@ohhwells/bridge 0.1.68-next.203 → 0.1.68

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  // src/OhhwellsBridge.tsx
4
- import React11, { useCallback as useCallback8, useEffect as useEffect13, useLayoutEffect as useLayoutEffect4, useRef as useRef10, useState as useState12 } from "react";
4
+ import React11, { useCallback as useCallback7, useEffect as useEffect12, useLayoutEffect as useLayoutEffect4, useRef as useRef9, useState as useState11 } from "react";
5
5
  import { createRoot as createRoot2 } from "react-dom/client";
6
6
  import { flushSync as flushSync2 } from "react-dom";
7
7
 
@@ -83,12 +83,7 @@ function parseAiSectionsState(raw) {
83
83
  media: entry.media && typeof entry.media === "object" ? entry.media : {}
84
84
  }));
85
85
  const removed = Array.isArray(parsed.removed) ? parsed.removed.filter((id) => typeof id === "string" && id.length > 0) : [];
86
- return {
87
- v: 1,
88
- sections,
89
- ...removed.length ? { removed } : {},
90
- ...parsed.hideTemplate === true ? { hideTemplate: true } : {}
91
- };
86
+ return { v: 1, sections, ...removed.length ? { removed } : {} };
92
87
  } catch {
93
88
  return EMPTY_AI_SECTIONS;
94
89
  }
@@ -101,7 +96,6 @@ function applyTreeToState(state, payload) {
101
96
  const entry = {
102
97
  id: payload.id,
103
98
  label: payload.label ?? "Generated section",
104
- ...typeof payload.path === "string" && payload.path ? { path: payload.path } : {},
105
99
  afterSection: payload.mode === "insert" && !insertBefore ? payload.targetSectionId ?? null : null,
106
100
  ...insertBefore && payload.targetSectionId ? { beforeSection: payload.targetSectionId } : {},
107
101
  ...payload.mode === "replace" && payload.targetSectionId ? { replaces: payload.targetSectionId } : {},
@@ -124,317 +118,6 @@ function deleteSectionFromState(state, sectionId) {
124
118
  return { ...state, v: 1, sections: state.sections, removed: [...removed, sectionId] };
125
119
  }
126
120
 
127
- // src/lib/brand-chrome.ts
128
- var BRAND_NAME_KEY = "__ohw_brand_name";
129
- var BRAND_TITLE_KEY = "__ohw_site_title";
130
- var BRAND_FAVICON_LETTER_KEY = "__ohw_favicon_letter";
131
- var BRAND_CHROME_KEYS = /* @__PURE__ */ new Set([
132
- BRAND_NAME_KEY,
133
- BRAND_TITLE_KEY,
134
- BRAND_FAVICON_LETTER_KEY
135
- ]);
136
- function upsertMeta(selector, attr, token, value) {
137
- let el = document.head.querySelector(selector);
138
- if (!el) {
139
- el = document.createElement("meta");
140
- el.setAttribute(attr, token);
141
- document.head.appendChild(el);
142
- }
143
- if (el.getAttribute("content") !== value) el.setAttribute("content", value);
144
- }
145
- function escapeXml(value) {
146
- return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
147
- }
148
- function applyLetterFavicon(letter) {
149
- const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect width="64" height="64" rx="12" fill="#111827"/><text x="32" y="46" font-family="system-ui,-apple-system,Segoe UI,sans-serif" font-size="40" font-weight="700" text-anchor="middle" fill="#ffffff">${escapeXml(letter)}</text></svg>`;
150
- const href = `data:image/svg+xml,${encodeURIComponent(svg)}`;
151
- let link = document.head.querySelector('link[rel="icon"]');
152
- if (!link) {
153
- link = document.createElement("link");
154
- link.rel = "icon";
155
- document.head.appendChild(link);
156
- }
157
- link.type = "image/svg+xml";
158
- if (link.href !== href) link.href = href;
159
- }
160
- function applyBrandChrome(content) {
161
- const name = content[BRAND_NAME_KEY];
162
- if (typeof name === "string" && name.length > 0) {
163
- document.querySelectorAll("[data-ohw-wordmark]").forEach((el) => {
164
- if (el.textContent !== name) el.textContent = name;
165
- if (el.getAttribute("title") !== name) el.setAttribute("title", name);
166
- });
167
- }
168
- const title = content[BRAND_TITLE_KEY];
169
- if (typeof title === "string" && title.length > 0) {
170
- if (document.title !== title) document.title = title;
171
- upsertMeta('meta[property="og:title"]', "property", "og:title", title);
172
- upsertMeta('meta[name="twitter:title"]', "name", "twitter:title", title);
173
- }
174
- const letter = content[BRAND_FAVICON_LETTER_KEY];
175
- if (typeof letter === "string" && letter.length > 0) {
176
- applyLetterFavicon(letter);
177
- }
178
- }
179
-
180
- // src/lib/brand-kit.ts
181
- var BRAND_KIT_KEY = "__ohw_brand";
182
- var BRAND_VAR_PREFIX = "--ohw-brand-";
183
- var BRAND_VAR_NAMES = ["primary", "accent", "light", "dark", "surface", "border", "muted"].map(
184
- (role) => `${BRAND_VAR_PREFIX}${role}`
185
- );
186
- var FONT_VARS = {
187
- heading: ["--font-heading", "--font-display", "--brand-font-heading"],
188
- body: ["--font-body", "--brand-font-body"]
189
- };
190
- var BRAND_FONT_LINK_ID = "ohw-brand-fonts";
191
- function brandColorVars(kit) {
192
- const { dark, primary, accent, light } = kit.palette;
193
- const mix = (a, aPct, b) => `color-mix(in srgb, ${a} ${aPct}%, ${b})`;
194
- return {
195
- [`${BRAND_VAR_PREFIX}primary`]: primary,
196
- [`${BRAND_VAR_PREFIX}accent`]: accent,
197
- [`${BRAND_VAR_PREFIX}light`]: light,
198
- [`${BRAND_VAR_PREFIX}dark`]: dark,
199
- [`${BRAND_VAR_PREFIX}surface`]: mix(light, 95, dark),
200
- [`${BRAND_VAR_PREFIX}border`]: mix(light, 85, dark),
201
- [`${BRAND_VAR_PREFIX}muted`]: mix(dark, 62, light)
202
- };
203
- }
204
- function parseBrandKit(raw) {
205
- if (!raw) return null;
206
- try {
207
- const parsed = JSON.parse(raw);
208
- const p = parsed?.palette;
209
- const f = parsed?.fonts;
210
- if (!p || !f || typeof p.dark !== "string" || typeof p.primary !== "string" || typeof p.accent !== "string" || typeof p.light !== "string" || typeof f.heading !== "string" || typeof f.body !== "string") {
211
- return null;
212
- }
213
- return {
214
- palette: { dark: p.dark, primary: p.primary, accent: p.accent, light: p.light },
215
- fonts: { heading: f.heading, body: f.body }
216
- };
217
- } catch {
218
- return null;
219
- }
220
- }
221
- function familyOf(stack) {
222
- const first = stack.split(",")[0]?.trim() ?? "";
223
- return first.replace(/^['"]|['"]$/g, "");
224
- }
225
- function loadBrandFonts(families) {
226
- const unique = [...new Set(families.map((f) => f.trim()).filter(Boolean))];
227
- if (unique.length === 0) return;
228
- const spec = unique.map((f) => `${f.replace(/ /g, "+")}:400,500,600,700`).join("|");
229
- const href = `https://fonts.googleapis.com/css?family=${spec}&display=swap`;
230
- let link = document.getElementById(BRAND_FONT_LINK_ID);
231
- if (!link) {
232
- link = document.createElement("link");
233
- link.id = BRAND_FONT_LINK_ID;
234
- link.rel = "stylesheet";
235
- document.head.appendChild(link);
236
- }
237
- if (link.href !== href) link.href = href;
238
- }
239
- function applyBrandToDom(kit) {
240
- const root = document.documentElement;
241
- if (!kit) {
242
- for (const name of BRAND_VAR_NAMES) root.style.removeProperty(name);
243
- for (const name of [...FONT_VARS.heading, ...FONT_VARS.body]) root.style.removeProperty(name);
244
- document.getElementById(BRAND_FONT_LINK_ID)?.remove();
245
- return;
246
- }
247
- for (const [name, value] of Object.entries(brandColorVars(kit))) root.style.setProperty(name, value);
248
- for (const name of FONT_VARS.heading) root.style.setProperty(name, kit.fonts.heading);
249
- for (const name of FONT_VARS.body) root.style.setProperty(name, kit.fonts.body);
250
- loadBrandFonts([familyOf(kit.fonts.heading), familyOf(kit.fonts.body)]);
251
- }
252
-
253
- // src/lib/section-styles.ts
254
- var STYLE_STORE_KEY = "__ohw_styles";
255
- var STYLE_SHEET_ID = "ohw-section-styles";
256
- function parseStyleStore(raw) {
257
- if (!raw) return null;
258
- try {
259
- const parsed = JSON.parse(raw);
260
- if (parsed?.v !== 1) return null;
261
- return {
262
- v: 1,
263
- sections: typeof parsed.sections === "object" && parsed.sections ? parsed.sections : {},
264
- nodes: typeof parsed.nodes === "object" && parsed.nodes ? parsed.nodes : {}
265
- };
266
- } catch {
267
- return null;
268
- }
269
- }
270
- var BG_VALUES = {
271
- surface: "color-mix(in srgb, var(--ohw-brand-light, var(--color-light, #ECECEB)) 94%, var(--ohw-brand-dark, var(--color-dark, #0C0A09)))",
272
- accent: "var(--ohw-brand-primary, var(--color-primary, #0078E5))",
273
- "accent-soft": "color-mix(in srgb, var(--ohw-brand-primary, var(--color-primary, #0078E5)) 12%, var(--ohw-brand-light, var(--color-light, #FFFFFF)))"
274
- };
275
- var HEADLINE_SIZES = { md: 24, lg: 32, xl: 40, display: 56 };
276
- function styleSheetCss() {
277
- const rules = [];
278
- for (const [tone, value] of Object.entries(BG_VALUES)) {
279
- rules.push(`[data-ohw-style-bg="${tone}"] { background: ${value} !important; }`);
280
- }
281
- rules.push(
282
- `[data-ohw-style-bg="accent"] { color: var(--ohw-brand-light, var(--color-light, #FFFFFF)) !important; }`
283
- );
284
- rules.push(
285
- `[data-ohw-style-distribution="space-between"] { display: flex !important; flex-direction: column; justify-content: space-between; }`,
286
- `[data-ohw-style-distribution="center"] { display: flex !important; flex-direction: column; justify-content: center; }`
287
- );
288
- for (const [scale, size] of Object.entries(HEADLINE_SIZES)) {
289
- rules.push(
290
- `[data-ohw-style-headline="${scale}"] :is(h1, h2, h3) { font-size: ${size}px !important; line-height: 1.15 !important; }`
291
- );
292
- }
293
- rules.push(
294
- `[data-ohw-style-aspect="fill-height"] img { height: 100% !important; aspect-ratio: auto !important; object-fit: cover; }`
295
- );
296
- for (const aspect of ["1:1", "4:5", "3:4", "3:2", "16:9", "2:1", "3:1"]) {
297
- rules.push(
298
- `[data-ohw-style-aspect="${aspect.replace(":", "-")}"] img { aspect-ratio: ${aspect.replace(":", " / ")} !important; height: auto !important; object-fit: cover; }`
299
- );
300
- }
301
- const pad = { tight: 40, balanced: 64, airy: 96 };
302
- for (const [spacing, px] of Object.entries(pad)) {
303
- rules.push(
304
- `[data-ohw-style-spacing="${spacing}"] { padding-top: ${px}px !important; padding-bottom: ${px}px !important; }`
305
- );
306
- }
307
- return rules.join("\n");
308
- }
309
- var STYLE_FONT_LINK_ID = "ohw-style-fonts";
310
- function loadStyleFonts(families) {
311
- const unique = [...new Set(families.map((f) => f.trim()).filter(Boolean))];
312
- const existing = document.getElementById(STYLE_FONT_LINK_ID);
313
- if (unique.length === 0) {
314
- existing?.remove();
315
- return;
316
- }
317
- const spec = unique.map((f) => `${f.replace(/ /g, "+")}:400,500,600,700`).join("|");
318
- const href = `https://fonts.googleapis.com/css?family=${spec}&display=swap`;
319
- let link = existing;
320
- if (!link) {
321
- link = document.createElement("link");
322
- link.id = STYLE_FONT_LINK_ID;
323
- link.rel = "stylesheet";
324
- document.head.appendChild(link);
325
- }
326
- if (link.href !== href) link.href = href;
327
- }
328
- var SECTION_ATTRS = {
329
- sectionBackground: "data-ohw-style-bg",
330
- textDistribution: "data-ohw-style-distribution",
331
- headlineScale: "data-ohw-style-headline",
332
- imageAspect: "data-ohw-style-aspect",
333
- spacing: "data-ohw-style-spacing"
334
- };
335
- var NODE_WROTE_ATTR = "data-ohw-style-node";
336
- var NODE_PROPS = ["color", "font-family", "font-size", "background"];
337
- function saveInline(el, prop) {
338
- const attr = `data-ohw-style-prev-${prop}`;
339
- if (!el.hasAttribute(attr)) el.setAttribute(attr, el.style.getPropertyValue(prop));
340
- }
341
- function restoreInline(el, prop) {
342
- const attr = `data-ohw-style-prev-${prop}`;
343
- if (!el.hasAttribute(attr)) return;
344
- const prev = el.getAttribute(attr) ?? "";
345
- if (prev) el.style.setProperty(prop, prev);
346
- else el.style.removeProperty(prop);
347
- el.removeAttribute(attr);
348
- }
349
- function ensureStyleSheet() {
350
- let el = document.getElementById(STYLE_SHEET_ID);
351
- if (!el) {
352
- el = document.createElement("style");
353
- el.id = STYLE_SHEET_ID;
354
- document.head.appendChild(el);
355
- }
356
- const css = styleSheetCss();
357
- if (el.textContent !== css) el.textContent = css;
358
- }
359
- function clearSectionAttrs(root) {
360
- for (const attr of Object.values(SECTION_ATTRS)) {
361
- for (const el of Array.from(root.querySelectorAll(`[${attr}]`))) el.removeAttribute(attr);
362
- }
363
- for (const el of Array.from(root.querySelectorAll("[data-ohw-style-bgcolor]"))) {
364
- restoreInline(el, "background");
365
- el.removeAttribute("data-ohw-style-bgcolor");
366
- }
367
- }
368
- function clearNodeProps(root) {
369
- for (const el of Array.from(root.querySelectorAll(`[${NODE_WROTE_ATTR}]`))) {
370
- const h = el;
371
- for (const prop of NODE_PROPS) restoreInline(h, prop);
372
- h.removeAttribute(NODE_WROTE_ATTR);
373
- }
374
- }
375
- function buttonSurfaceOf(el) {
376
- return el.closest("a, button") ?? el;
377
- }
378
- function applyStylesToDom(store) {
379
- ensureStyleSheet();
380
- clearSectionAttrs(document);
381
- clearNodeProps(document);
382
- loadStyleFonts(
383
- store ? Object.values(store.nodes).flatMap((n) => n.fontFamily ? [n.fontFamily] : []) : []
384
- );
385
- if (!store) return;
386
- for (const [sectionId, override] of Object.entries(store.sections)) {
387
- const sections = document.querySelectorAll(
388
- `[data-ohw-section="${CSS.escape(sectionId)}"]`
389
- );
390
- for (const section of Array.from(sections)) {
391
- for (const [prop, attr] of Object.entries(SECTION_ATTRS)) {
392
- const value = override[prop];
393
- if (value === void 0) continue;
394
- if (prop === "sectionBackground" && override.sectionBackgroundColor !== void 0) continue;
395
- section.setAttribute(attr, String(value).replace(":", "-"));
396
- }
397
- if (override.sectionBackgroundColor !== void 0) {
398
- saveInline(section, "background");
399
- section.style.setProperty("background", override.sectionBackgroundColor, "important");
400
- section.setAttribute("data-ohw-style-bgcolor", "");
401
- }
402
- }
403
- }
404
- for (const [key, override] of Object.entries(store.nodes)) {
405
- const nodes = document.querySelectorAll(`[data-ohw-key="${CSS.escape(key)}"]`);
406
- for (const el of Array.from(nodes)) {
407
- if (override.color !== void 0) {
408
- saveInline(el, "color");
409
- el.style.setProperty("color", override.color, "important");
410
- el.setAttribute(NODE_WROTE_ATTR, "");
411
- }
412
- if (override.fontFamily !== void 0) {
413
- saveInline(el, "font-family");
414
- el.style.setProperty("font-family", `'${override.fontFamily}'`, "important");
415
- el.setAttribute(NODE_WROTE_ATTR, "");
416
- }
417
- if (override.fontSize !== void 0) {
418
- saveInline(el, "font-size");
419
- el.style.setProperty("font-size", `${override.fontSize}px`, "important");
420
- el.setAttribute(NODE_WROTE_ATTR, "");
421
- }
422
- if (override.buttonBackground !== void 0 || override.buttonText !== void 0) {
423
- const surface = buttonSurfaceOf(el);
424
- if (override.buttonBackground !== void 0) {
425
- saveInline(surface, "background");
426
- surface.style.setProperty("background", override.buttonBackground, "important");
427
- }
428
- if (override.buttonText !== void 0) {
429
- saveInline(surface, "color");
430
- surface.style.setProperty("color", override.buttonText, "important");
431
- }
432
- surface.setAttribute(NODE_WROTE_ATTR, "");
433
- }
434
- }
435
- }
436
- }
437
-
438
121
  // src/ui/ai-tree/aiSectionsManager.tsx
439
122
  import { flushSync } from "react-dom";
440
123
  import { createRoot } from "react-dom/client";
@@ -449,8 +132,7 @@ function lucideByName(name) {
449
132
  }
450
133
  var typeStyle = (spec, font) => ({
451
134
  fontFamily: font,
452
- // Headings shrink with the viewport (reaching full size around ~900px wide); body copy stays put.
453
- fontSize: spec.size >= 24 ? `clamp(${Math.max(18, Math.round(spec.size * 0.6))}px, ${(spec.size / 9).toFixed(2)}vw, ${spec.size}px)` : spec.size,
135
+ fontSize: spec.size,
454
136
  lineHeight: spec.line,
455
137
  fontWeight: spec.weight
456
138
  });
@@ -465,36 +147,6 @@ var FEATURE_LINE_CSS = [
465
147
  `background-color:currentColor;-webkit-mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px;`,
466
148
  `mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px}`
467
149
  ].join("");
468
- function hexLuminance(color) {
469
- const m = /^#([0-9a-f]{6})$/i.exec(color.trim());
470
- if (!m) return null;
471
- const [r2, g, b] = [0, 2, 4].map((i) => {
472
- const c = parseInt(m[1].slice(i, i + 2), 16) / 255;
473
- return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
474
- });
475
- return 0.2126 * r2 + 0.7152 * g + 0.0722 * b;
476
- }
477
- function hexContrast(a, b) {
478
- const la = hexLuminance(a);
479
- const lb = hexLuminance(b);
480
- if (la === null || lb === null) return null;
481
- const [hi, lo] = la > lb ? [la, lb] : [lb, la];
482
- return (hi + 0.05) / (lo + 0.05);
483
- }
484
- function accentBandContext(brand) {
485
- const p = brand.palette;
486
- const lightWins = (hexContrast(p.light, p.primary) ?? 99) >= (hexContrast(p.dark, p.primary) ?? 0);
487
- if (lightWins) {
488
- return {
489
- brand: { ...brand, palette: { dark: p.light, primary: p.light, accent: p.light, light: p.primary } },
490
- buttonLabel: p.primary
491
- };
492
- }
493
- return {
494
- brand: { ...brand, palette: { dark: p.dark, primary: p.dark, accent: p.dark, light: p.light } },
495
- buttonLabel: p.light
496
- };
497
- }
498
150
  function textAttrs(ctx, path) {
499
151
  return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
500
152
  }
@@ -507,8 +159,6 @@ var AI_RESPONSIVE_CSS = [
507
159
  " [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
508
160
  " [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
509
161
  " [data-ai-responsive] [data-ai-section-inner] { padding-left: 20px !important; padding-right: 20px !important; }",
510
- " [data-ai-responsive] { overflow-x: hidden; }",
511
- " [data-ai-responsive] img { max-width: 100%; }",
512
162
  "}"
513
163
  ].join("\n");
514
164
  var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
@@ -586,7 +236,7 @@ function ButtonEl({
586
236
  }) {
587
237
  const secondary = slots.variant === "secondary";
588
238
  const href = str(slots.href);
589
- const linkAttrs = ctx.keyFor && path ? { "data-ohw-href-key": ctx.keyFor(`${path}.href`), "data-ohw-role": "button" } : {};
239
+ const linkAttrs = ctx.keyFor && path ? { "data-ohw-href-key": ctx.keyFor(`${path}.href`) } : {};
590
240
  return /* @__PURE__ */ jsx(
591
241
  "a",
592
242
  {
@@ -602,7 +252,7 @@ function ButtonEl({
602
252
  textDecoration: "none",
603
253
  cursor: "pointer",
604
254
  ...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body),
605
- ...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : { background: ctx.brand.palette.primary, color: ctx.buttonLabel ?? AI_TREE_TOKENS.textPrimaryForeground }
255
+ ...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : { background: ctx.brand.palette.primary, color: AI_TREE_TOKENS.textPrimaryForeground }
606
256
  },
607
257
  children: /* @__PURE__ */ jsx("span", { ...path ? textAttrs(ctx, `${path}.label`) : {}, children: str(slots.label) })
608
258
  }
@@ -1504,14 +1154,11 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1504
1154
  return null;
1505
1155
  }
1506
1156
  const resolvedBrand = brand ?? AI_DEFAULT_BRAND;
1507
- const band = (tree.settings ?? {}).sectionBackground === "accent" ? accentBandContext(resolvedBrand) : null;
1508
- const blockBrand = band?.brand ?? resolvedBrand;
1509
1157
  const ctx = {
1510
- brand: blockBrand,
1158
+ brand: resolvedBrand,
1511
1159
  resolveMedia: resolveMedia ?? (() => null),
1512
- cardSurface: blockBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${blockBrand.palette.light} 90%, ${blockBrand.palette.dark})`,
1513
- keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null,
1514
- ...band ? { buttonLabel: band.buttonLabel } : {}
1160
+ cardSurface: resolvedBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${resolvedBrand.palette.light} 90%, ${resolvedBrand.palette.dark})`,
1161
+ keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null
1515
1162
  };
1516
1163
  const settings = tree.settings ?? {};
1517
1164
  const pad = AI_TREE_TOKENS.sectionPadding[settings.spacing ?? "balanced"];
@@ -1519,20 +1166,6 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1519
1166
  const overlayAlpha = { low: 0.25, medium: 0.45, high: 0.65 }[settings.overlayIntensity ?? "medium"];
1520
1167
  const backgroundUrl = isOverlay && settings.backgroundMedia ? ctx.resolveMedia(settings.backgroundMedia) : null;
1521
1168
  const bgAttrs = ctx.keyFor && isOverlay && settings.backgroundMedia ? { "data-ohw-key": ctx.keyFor("settings.backgroundMedia"), "data-ohw-editable": "bg-image" } : {};
1522
- const toneBackground = (() => {
1523
- const { dark, primary, light } = resolvedBrand.palette;
1524
- switch (settings.sectionBackground) {
1525
- case "surface":
1526
- return `color-mix(in srgb, ${light} 94%, ${dark})`;
1527
- case "accent":
1528
- return primary;
1529
- case "accent-soft":
1530
- return `color-mix(in srgb, ${primary} 12%, ${light})`;
1531
- default:
1532
- return void 0;
1533
- }
1534
- })();
1535
- const distributed = !isOverlay && settings.textDistribution;
1536
1169
  return /* @__PURE__ */ jsxs(
1537
1170
  "section",
1538
1171
  {
@@ -1542,11 +1175,10 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1542
1175
  style: {
1543
1176
  position: "relative",
1544
1177
  padding: `${pad}px 0`,
1545
- background: toneBackground ?? (isOverlay && !backgroundUrl ? "#DBEAFE" : void 0),
1178
+ background: isOverlay && !backgroundUrl ? "#DBEAFE" : void 0,
1546
1179
  backgroundImage: backgroundUrl ? `url(${backgroundUrl})` : void 0,
1547
1180
  backgroundSize: "cover",
1548
- backgroundPosition: "center",
1549
- color: settings.sectionBackground === "accent" ? blockBrand.palette.dark : void 0
1181
+ backgroundPosition: "center"
1550
1182
  },
1551
1183
  children: [
1552
1184
  /* @__PURE__ */ jsx("style", { children: AI_RESPONSIVE_CSS }),
@@ -1570,24 +1202,10 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1570
1202
  display: "grid",
1571
1203
  gridTemplateColumns: "repeat(12, 1fr)",
1572
1204
  gap: AI_TREE_TOKENS.spacing6,
1573
- alignItems: distributed === "space-between" ? "stretch" : (distributed ?? settings.verticalPosition) === "top" ? "start" : "center",
1205
+ alignItems: settings.verticalPosition === "top" ? "start" : "center",
1574
1206
  marginTop: r2 > 0 ? AI_TREE_TOKENS.spacing8 : 0
1575
1207
  },
1576
- children: (row.blocks ?? []).map((block, b) => /* @__PURE__ */ jsx(
1577
- "div",
1578
- {
1579
- "data-ai-cell": "",
1580
- style: {
1581
- gridColumn: `span ${Math.min(12, Math.max(1, block.span))}`,
1582
- minWidth: 0,
1583
- // space-between: each column becomes a flex column whose content spreads over
1584
- // the full row height instead of clumping at the top.
1585
- ...distributed === "space-between" ? { display: "flex", flexDirection: "column", justifyContent: "space-between" } : {}
1586
- },
1587
- children: renderNode(block, ctx, `r${r2}.b${b}`)
1588
- },
1589
- b
1590
- ))
1208
+ children: (row.blocks ?? []).map((block, b) => /* @__PURE__ */ jsx("div", { style: { gridColumn: `span ${Math.min(12, Math.max(1, block.span))}`, minWidth: 0 }, children: renderNode(block, ctx, `r${r2}.b${b}`) }, b))
1591
1209
  },
1592
1210
  r2
1593
1211
  ))
@@ -1603,36 +1221,17 @@ import { jsx as jsx2 } from "react/jsx-runtime";
1603
1221
  var CONTAINER_ATTR = "data-ohw-ai-generated";
1604
1222
  var REPLACED_ATTR = "data-ohw-ai-replaced-by";
1605
1223
  var REMOVED_ATTR = "data-ohw-ai-removed";
1606
- var TEMPLATE_HIDDEN_ATTR = "data-ohw-ai-template-hidden";
1607
- var CHROME_SECTION_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
1608
- function readRootVar(name) {
1609
- if (typeof document === "undefined") return "";
1610
- return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
1611
- }
1612
- function deriveBrandOverride() {
1613
- const dark = readRootVar("--ohw-brand-dark");
1614
- const primary = readRootVar("--ohw-brand-primary");
1615
- const light = readRootVar("--ohw-brand-light");
1616
- if (!dark || !primary || !light) return null;
1617
- const accent = readRootVar("--ohw-brand-accent");
1618
- const heading = readRootVar("--font-heading") || readRootVar("--font-display");
1619
- const body = readRootVar("--font-body");
1620
- return {
1621
- palette: { dark, primary, accent: accent || dark, light },
1622
- fonts: {
1623
- heading: heading || AI_DEFAULT_BRAND.fonts.heading,
1624
- body: body || AI_DEFAULT_BRAND.fonts.body
1625
- }
1626
- };
1627
- }
1628
1224
  function deriveTemplateBrand() {
1629
- const dark = readRootVar("--color-dark");
1630
- const primary = readRootVar("--color-primary");
1631
- const light = readRootVar("--color-light");
1225
+ if (typeof document === "undefined") return null;
1226
+ const cs = getComputedStyle(document.documentElement);
1227
+ const read = (name) => cs.getPropertyValue(name).trim();
1228
+ const dark = read("--color-dark");
1229
+ const primary = read("--color-primary");
1230
+ const light = read("--color-light");
1632
1231
  if (!dark || !primary || !light) return null;
1633
- const accent = readRootVar("--color-accent");
1634
- const heading = readRootVar("--font-heading") || readRootVar("--font-display");
1635
- const body = readRootVar("--font-body");
1232
+ const accent = read("--color-accent");
1233
+ const heading = read("--font-heading") || read("--font-display");
1234
+ const body = read("--font-body");
1636
1235
  return {
1637
1236
  palette: { dark, primary, accent: accent || dark, light },
1638
1237
  fonts: {
@@ -1704,24 +1303,6 @@ function syncRemovedSections(state) {
1704
1303
  }
1705
1304
  }
1706
1305
  }
1707
- function syncTemplateHidden(state, pageHasSections) {
1708
- const hide = state.hideTemplate === true && pageHasSections;
1709
- for (const el of Array.from(document.querySelectorAll(`[${TEMPLATE_HIDDEN_ATTR}]`))) {
1710
- if (!hide) {
1711
- el.style.removeProperty("display");
1712
- el.removeAttribute(TEMPLATE_HIDDEN_ATTR);
1713
- }
1714
- }
1715
- if (!hide) return;
1716
- for (const el of Array.from(document.querySelectorAll("[data-ohw-section]"))) {
1717
- if (el.hasAttribute(CONTAINER_ATTR)) continue;
1718
- if (CHROME_SECTION_IDS.has(el.getAttribute("data-ohw-section") ?? "")) continue;
1719
- if (el.parentElement?.closest("[data-ohw-section]")) continue;
1720
- if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(REMOVED_ATTR)) continue;
1721
- el.style.display = "none";
1722
- el.setAttribute(TEMPLATE_HIDDEN_ATTR, "");
1723
- }
1724
- }
1725
1306
  function syncReplacedOriginals(state) {
1726
1307
  for (const el of document.querySelectorAll(`[${REPLACED_ATTR}]`)) {
1727
1308
  const byId = el.getAttribute(REPLACED_ATTR) ?? "";
@@ -1742,12 +1323,8 @@ function syncReplacedOriginals(state) {
1742
1323
  }
1743
1324
  function applyAiSectionsToDom(state, options) {
1744
1325
  if (typeof document === "undefined") return;
1745
- const brandOverride = deriveBrandOverride();
1746
1326
  const templateBrand = deriveTemplateBrand();
1747
- const brandKey = brandOverride ? JSON.stringify(brandOverride) : "";
1748
- const pagePath = window.location.pathname;
1749
- const pageSections = state.sections.filter((entry) => !entry.path || entry.path === pagePath);
1750
- const activeIds = new Set(pageSections.map((entry) => entry.id));
1327
+ const activeIds = new Set(state.sections.map((entry) => entry.id));
1751
1328
  for (const [id, section] of mounted) {
1752
1329
  if (!activeIds.has(id)) {
1753
1330
  section.root.unmount();
@@ -1755,8 +1332,8 @@ function applyAiSectionsToDom(state, options) {
1755
1332
  mounted.delete(id);
1756
1333
  }
1757
1334
  }
1758
- for (const entry of pageSections) {
1759
- const serialized = JSON.stringify(entry) + brandKey;
1335
+ for (const entry of state.sections) {
1336
+ const serialized = JSON.stringify(entry);
1760
1337
  const existing = mounted.get(entry.id);
1761
1338
  if (existing && existing.serialized === serialized && existing.container.isConnected) {
1762
1339
  continue;
@@ -1770,7 +1347,6 @@ function applyAiSectionsToDom(state, options) {
1770
1347
  mounted.delete(entry.id);
1771
1348
  }
1772
1349
  container.setAttribute("data-ohw-section", entry.id);
1773
- container.setAttribute("data-ohw-instance", entry.id);
1774
1350
  container.setAttribute("data-ohw-section-label", entry.label);
1775
1351
  placeContainer(container, entry);
1776
1352
  const root = mounted.get(entry.id)?.root ?? createRoot(container);
@@ -1781,7 +1357,7 @@ function applyAiSectionsToDom(state, options) {
1781
1357
  AiTreeRenderer,
1782
1358
  {
1783
1359
  tree: entry.tree,
1784
- brand: brandOverride ?? entry.brand ?? options?.brand ?? templateBrand ?? void 0,
1360
+ brand: entry.brand ?? options?.brand ?? templateBrand ?? void 0,
1785
1361
  resolveMedia,
1786
1362
  editKeyPrefix: `ai.${entry.id}`
1787
1363
  }
@@ -1792,7 +1368,6 @@ function applyAiSectionsToDom(state, options) {
1792
1368
  }
1793
1369
  syncReplacedOriginals(state);
1794
1370
  syncRemovedSections(state);
1795
- syncTemplateHidden(state, pageSections.length > 0);
1796
1371
  }
1797
1372
 
1798
1373
  // src/useLinkHrefGuardian.ts
@@ -2399,7 +1974,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
2399
1974
  const autoId = useId();
2400
1975
  const insertAfter = insertAfterProp ?? autoId;
2401
1976
  const [schedule, setSchedule] = useState2(null);
2402
- const [loading, setLoading] = useState2(initialScheduleId !== null);
1977
+ const [loading, setLoading] = useState2(true);
2403
1978
  const [inEditor, setInEditor] = useState2(false);
2404
1979
  const [isHovered, setIsHovered] = useState2(false);
2405
1980
  const [modalState, setModalState] = useState2(null);
@@ -2573,10 +2148,8 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
2573
2148
  "*"
2574
2149
  );
2575
2150
  };
2151
+ if (!inEditor && !loading && !schedule) return null;
2576
2152
  const sectionId = `scheduling-${insertAfter}`;
2577
- if (!inEditor && !loading && !schedule) {
2578
- return /* @__PURE__ */ jsx4("section", { "data-ohw-section": sectionId, "data-ohw-scheduling-anchor": insertAfter, style: { display: "none" } });
2579
- }
2580
2153
  return /* @__PURE__ */ jsxs3(
2581
2154
  "section",
2582
2155
  {
@@ -7484,17 +7057,13 @@ function MediaOverlay({
7484
7057
  hover,
7485
7058
  isUploading,
7486
7059
  fadingOut = false,
7487
- selected = false,
7488
- hovered = false,
7489
7060
  onFadeOutComplete,
7490
7061
  onReplace,
7491
- onSelect,
7492
7062
  onVideoSettingsChange
7493
7063
  }) {
7494
7064
  const { rect } = hover;
7495
7065
  const skeletonRef = React7.useRef(null);
7496
7066
  const isVideo = hover.elementType === "video";
7497
- const showChrome = !selected || hovered;
7498
7067
  const autoplay = hover.videoAutoplay ?? true;
7499
7068
  const muted = hover.videoMuted ?? true;
7500
7069
  const box = {
@@ -7529,7 +7098,7 @@ function MediaOverlay({
7529
7098
  }
7530
7099
  );
7531
7100
  }
7532
- const settingsBar = isVideo && !hover.isDragOver && showChrome ? /* @__PURE__ */ jsxs7(
7101
+ const settingsBar = isVideo && !hover.isDragOver ? /* @__PURE__ */ jsxs7(
7533
7102
  "div",
7534
7103
  {
7535
7104
  "data-ohw-bridge": "",
@@ -7599,13 +7168,11 @@ function MediaOverlay({
7599
7168
  // in-document, pointer-events does it natively. The button below opts back in, so
7600
7169
  // Replace still works.
7601
7170
  pointerEvents: hover.hasTextOverlap ? "none" : "auto",
7602
- // Selected: a firm component ring with no wash, so the image reads as chosen rather
7603
- // than hovered. Hover keeps the existing tinted preview.
7604
- boxShadow: selected ? "inset 0 0 0 2px var(--color-primary)" : "inset 0 0 0 1.5px var(--color-primary)",
7605
- background: selected ? "transparent" : "color-mix(in srgb, var(--color-primary) 20%, transparent)"
7171
+ boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
7172
+ background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
7606
7173
  },
7607
- onClick: () => onSelect && !selected ? onSelect(hover.key) : onReplace(hover.key),
7608
- children: showChrome && /* @__PURE__ */ jsxs7(
7174
+ onClick: () => onReplace(hover.key),
7175
+ children: /* @__PURE__ */ jsxs7(
7609
7176
  Button,
7610
7177
  {
7611
7178
  "data-ohw-media-overlay": "",
@@ -7694,9 +7261,6 @@ import { Check, X } from "lucide-react";
7694
7261
 
7695
7262
  // src/lib/sections.ts
7696
7263
  var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
7697
- function isChromeSection(el) {
7698
- return el.matches("header, nav, footer, aside");
7699
- }
7700
7264
  function titleCaseSectionId(id) {
7701
7265
  return id.split("-").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
7702
7266
  }
@@ -7707,8 +7271,6 @@ function parseSectionsFromRoot(root) {
7707
7271
  const id = el.getAttribute("data-ohw-section") ?? "";
7708
7272
  if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
7709
7273
  if (el.parentElement?.closest("[data-ohw-section]")) continue;
7710
- if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
7711
- continue;
7712
7274
  seen.add(id);
7713
7275
  const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
7714
7276
  sections.push({ id, label });
@@ -7726,12 +7288,8 @@ function parseSectionsFromHtml(html) {
7726
7288
 
7727
7289
  // src/ui/ai-section/AiSectionOverlay.tsx
7728
7290
  import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
7729
- function findSectionElement(instanceId) {
7730
- const escaped = CSS.escape(instanceId);
7731
- return document.querySelector(`[data-ohw-instance="${escaped}"]`) ?? document.querySelector(`[data-ohw-section="${escaped}"]:not([data-ohw-instance])`);
7732
- }
7733
- function readRect(instanceId) {
7734
- const el = findSectionElement(instanceId);
7291
+ function readRect(sectionId) {
7292
+ const el = document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`);
7735
7293
  if (!el) return null;
7736
7294
  const r2 = el.getBoundingClientRect();
7737
7295
  if (r2.width <= 0 || r2.height <= 0) return null;
@@ -7754,7 +7312,7 @@ function useLiveSectionRect(sectionId) {
7754
7312
  const opts = { capture: true, passive: true };
7755
7313
  window.addEventListener("scroll", update, opts);
7756
7314
  window.addEventListener("resize", update);
7757
- const el = findSectionElement(sectionId);
7315
+ const el = document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`);
7758
7316
  const ro = el ? new ResizeObserver(update) : null;
7759
7317
  if (el && ro) ro.observe(el);
7760
7318
  const interval = setInterval(update, 500);
@@ -7767,14 +7325,6 @@ function useLiveSectionRect(sectionId) {
7767
7325
  }, [sectionId]);
7768
7326
  return rect;
7769
7327
  }
7770
- function computeSectionBoundaryFlags(instanceId) {
7771
- const topLevel = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
7772
- (el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
7773
- );
7774
- const index = topLevel.findIndex((el) => (el.dataset.ohwInstance ?? el.dataset.ohwSection) === instanceId);
7775
- if (index === -1) return { isFirst: true, isLast: true };
7776
- return { isFirst: index === 0, isLast: index === topLevel.length - 1 };
7777
- }
7778
7328
  var PRIMARY2 = "#0885FE";
7779
7329
  function edgeAwareRadius(rect) {
7780
7330
  const container = window.innerWidth <= 480 ? 16 : 24;
@@ -7848,7 +7398,6 @@ function AiSectionOverlay({
7848
7398
  }) {
7849
7399
  const [selectedId, setSelectedId] = useState4(null);
7850
7400
  const [reviewId, setReviewId] = useState4(null);
7851
- const [reviewButtonsHidden, setReviewButtonsHidden] = useState4(false);
7852
7401
  const reviewIdRef = useRef4(null);
7853
7402
  reviewIdRef.current = reviewId;
7854
7403
  const selectedIdRef = useRef4(null);
@@ -7857,7 +7406,7 @@ function AiSectionOverlay({
7857
7406
  (el) => {
7858
7407
  postToParent2({
7859
7408
  type: "ow:section-selected",
7860
- sectionId: el ? el.dataset.ohwInstance ?? el.dataset.ohwSection ?? null : null,
7409
+ sectionId: el?.dataset.ohwSection ?? null,
7861
7410
  sectionLabel: el ? el.dataset.ohwSectionLabel ?? titleCaseSectionId(el.dataset.ohwSection ?? "") : null
7862
7411
  });
7863
7412
  },
@@ -7866,7 +7415,7 @@ function AiSectionOverlay({
7866
7415
  const selectFromElement = useCallback2(
7867
7416
  (el, options) => {
7868
7417
  const sectionEl = el?.closest("[data-ohw-section]") ?? null;
7869
- const id = sectionEl ? sectionEl.dataset.ohwInstance ?? sectionEl.dataset.ohwSection ?? null : null;
7418
+ const id = sectionEl?.dataset.ohwSection ?? null;
7870
7419
  if (id === selectedIdRef.current) return;
7871
7420
  setSelectedId(id);
7872
7421
  if (options?.report !== false) report(sectionEl);
@@ -7907,10 +7456,9 @@ function AiSectionOverlay({
7907
7456
  }
7908
7457
  const found = readRect(sectionId) != null;
7909
7458
  setReviewId(found ? sectionId : null);
7910
- setReviewButtonsHidden(e.data.hideButtons === true);
7911
7459
  postToParent2({ type: "ow:ai-review-started", sectionId, found });
7912
7460
  if (found) {
7913
- document.querySelector(`[data-ohw-instance="${CSS.escape(sectionId)}"]`)?.scrollIntoView({ behavior: "smooth", block: "nearest" });
7461
+ document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`)?.scrollIntoView({ behavior: "smooth", block: "nearest" });
7914
7462
  }
7915
7463
  }
7916
7464
  };
@@ -7929,7 +7477,7 @@ function AiSectionOverlay({
7929
7477
  return;
7930
7478
  }
7931
7479
  const sec = t.closest("[data-ohw-section]");
7932
- setHoveredId(sec ? sec.dataset.ohwInstance ?? sec.dataset.ohwSection ?? null : null);
7480
+ setHoveredId(sec?.dataset.ohwSection ?? null);
7933
7481
  };
7934
7482
  const onLeave = () => setHoveredId(null);
7935
7483
  document.addEventListener("mousemove", onMove, { passive: true });
@@ -7961,30 +7509,9 @@ function AiSectionOverlay({
7961
7509
  },
7962
7510
  [postToParent2]
7963
7511
  );
7964
- const activeSelectionId = reviewId ? null : selectedId;
7965
- const selectionRect = useLiveSectionRect(activeSelectionId);
7512
+ const selectionRect = useLiveSectionRect(reviewId ? null : selectedId);
7966
7513
  const reviewRect = useLiveSectionRect(reviewId);
7967
7514
  const hoverRect = useLiveSectionRect(reviewId || hoveredId === selectedId ? null : hoveredId);
7968
- useEffect4(() => {
7969
- const selectedEl = activeSelectionId ? findSectionElement(activeSelectionId) : null;
7970
- if (!activeSelectionId || !selectionRect || selectedEl && isChromeSection(selectedEl)) {
7971
- postToParent2({ type: "ow:section-rect", instanceId: null, rect: null });
7972
- return;
7973
- }
7974
- const { isFirst, isLast } = computeSectionBoundaryFlags(activeSelectionId);
7975
- postToParent2({
7976
- type: "ow:section-rect",
7977
- instanceId: activeSelectionId,
7978
- rect: {
7979
- top: selectionRect.top + window.scrollY,
7980
- left: selectionRect.left + window.scrollX,
7981
- width: selectionRect.width,
7982
- height: selectionRect.height
7983
- },
7984
- isFirst,
7985
- isLast
7986
- });
7987
- }, [activeSelectionId, selectionRect, postToParent2]);
7988
7515
  return /* @__PURE__ */ jsxs9(Fragment5, { children: [
7989
7516
  hoverRect && /* @__PURE__ */ jsx17(
7990
7517
  "div",
@@ -8035,16 +7562,13 @@ function AiSectionOverlay({
8035
7562
  border: `2px solid ${PRIMARY2}`,
8036
7563
  borderRadius: edgeAwareRadius(reviewRect),
8037
7564
  zIndex: 2147483200,
8038
- // The veil itself: swallows clicks so the section stays locked until decided. This
8039
- // stopPropagation only guards the bubble phase; the bridge's capture-phase click
8040
- // handlers additionally bail on `[data-ohw-ai-review]`, without which a click on
8041
- // Accept/Discard resolves to the media beneath and opens the file picker.
7565
+ // The veil itself: swallows clicks so the section stays locked until decided.
8042
7566
  background: "rgba(8, 133, 254, 0.04)",
8043
7567
  pointerEvents: "auto",
8044
7568
  cursor: "default"
8045
7569
  },
8046
7570
  onClick: (e) => e.stopPropagation(),
8047
- children: !reviewButtonsHidden && /* @__PURE__ */ jsxs9(
7571
+ children: /* @__PURE__ */ jsxs9(
8048
7572
  "div",
8049
7573
  {
8050
7574
  style: {
@@ -8069,58 +7593,6 @@ function AiSectionOverlay({
8069
7593
 
8070
7594
  // src/lib/section-instances.ts
8071
7595
  var SECTION_ORDER_KEY = "__ohw_section_order";
8072
- function topLevelSections() {
8073
- return Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
8074
- (el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
8075
- );
8076
- }
8077
- function instanceIdOf(el) {
8078
- return el.dataset.ohwInstance ?? el.dataset.ohwSection ?? "";
8079
- }
8080
- function planSectionMove(instanceId, targetIndex, currentPath) {
8081
- const sections = topLevelSections();
8082
- const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
8083
- if (index === -1) return null;
8084
- const dragged = sections[index];
8085
- const others = sections.filter((_, i) => i !== index);
8086
- const clamped = Math.max(0, Math.min(targetIndex, others.length));
8087
- const reordered = [...others.slice(0, clamped), dragged, ...others.slice(clamped)];
8088
- return reordered.map((el, order) => ({
8089
- instanceId: instanceIdOf(el),
8090
- type: el.getAttribute("data-ohw-section") ?? "",
8091
- order,
8092
- pagePath: currentPath
8093
- }));
8094
- }
8095
- function moveSectionInstance(instanceId, direction, currentPath) {
8096
- const sections = topLevelSections();
8097
- const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
8098
- if (index === -1) return null;
8099
- const siblingIndex = direction === "up" ? index - 1 : index + 1;
8100
- if (siblingIndex < 0 || siblingIndex >= sections.length) return null;
8101
- const entries = planSectionMove(instanceId, siblingIndex, currentPath);
8102
- if (!entries) return null;
8103
- applyPersistedOrder(entries);
8104
- return entries;
8105
- }
8106
- function applyPersistedOrder(entries) {
8107
- if (entries.length === 0) return;
8108
- const sections = topLevelSections();
8109
- if (sections.length === 0) return;
8110
- const orderIndex = new Map(entries.map((e) => [e.instanceId, e.order]));
8111
- const ordered = [...sections].sort((a, b) => {
8112
- const aOrder = orderIndex.get(instanceIdOf(a));
8113
- const bOrder = orderIndex.get(instanceIdOf(b));
8114
- if (aOrder === void 0 && bOrder === void 0) return 0;
8115
- if (aOrder === void 0) return 1;
8116
- if (bOrder === void 0) return -1;
8117
- return aOrder - bOrder;
8118
- });
8119
- const parent = sections[0].parentElement;
8120
- if (!parent) return;
8121
- const anchor = sections[sections.length - 1].nextSibling;
8122
- ordered.forEach((el) => parent.insertBefore(el, anchor));
8123
- }
8124
7596
  function getPageSectionOrderEntries(raw, currentPath) {
8125
7597
  if (!raw) return [];
8126
7598
  try {
@@ -8158,7 +7630,6 @@ function initSectionInstancesFromContent(content, currentPath) {
8158
7630
  rekeySectionSubtree(clone, entry.instanceId);
8159
7631
  original.insertAdjacentElement("afterend", clone);
8160
7632
  }
8161
- applyPersistedOrder(entries);
8162
7633
  }
8163
7634
 
8164
7635
  // src/OhhwellsBridge.tsx
@@ -10783,8 +10254,7 @@ function findSocialsRow(el) {
10783
10254
  }
10784
10255
  function isSocialsRow(el) {
10785
10256
  const anchors = Array.from(el.querySelectorAll("a"));
10786
- if (!anchors.length || !anchors.some((anchor) => isSocialItem(anchor))) return false;
10787
- return findSocialsRow(anchors[0]) === el;
10257
+ return anchors.length > 0 && anchors.every((anchor) => isSocialItem(anchor));
10788
10258
  }
10789
10259
  var MAX_SOCIAL_ITEMS_PER_ROW = 7;
10790
10260
  function canAddSocialItem(row) {
@@ -10822,7 +10292,6 @@ function markSocialsRows(root = document) {
10822
10292
  });
10823
10293
  listSocialsRows(root).forEach((row) => {
10824
10294
  row.setAttribute(SOCIALS_ROW_ATTR, "");
10825
- allowRowToWrap(row);
10826
10295
  const items = listSocialItems(row);
10827
10296
  const firstUnit = items[0] ? socialRowUnit(items[0], row) : null;
10828
10297
  if (firstUnit) rowTemplates.set(rowKeyOf(row), firstUnit.outerHTML);
@@ -11117,29 +10586,7 @@ function applySocialsDisplayToRow(row, display) {
11117
10586
  const icon = item.querySelector(ICON_SELECTOR);
11118
10587
  if (label) label.style.display = display.text ? "" : "none";
11119
10588
  if (icon) icon.style.display = display.icon ? "" : "none";
11120
- layOutIconAndLabel(item, Boolean(display.text && display.icon));
11121
10589
  });
11122
- allowRowToWrap(row);
11123
- }
11124
- function layOutIconAndLabel(item, on) {
11125
- const hasBoth = Boolean(item.querySelector(ICON_SELECTOR)) && Boolean(socialLabelElement(item));
11126
- if (!hasBoth) {
11127
- item.style.display = "";
11128
- item.style.alignItems = "";
11129
- item.style.gap = "";
11130
- item.style.whiteSpace = "";
11131
- item.style.flex = "";
11132
- return;
11133
- }
11134
- item.style.display = on ? "inline-flex" : "";
11135
- item.style.alignItems = on ? "center" : "";
11136
- item.style.gap = on ? "8px" : "";
11137
- item.style.whiteSpace = on ? "nowrap" : "";
11138
- item.style.flex = on ? "0 0 auto" : "";
11139
- }
11140
- function allowRowToWrap(row) {
11141
- const display = row.ownerDocument.defaultView?.getComputedStyle(row).display ?? "";
11142
- if (display === "flex" || display === "inline-flex") row.style.flexWrap = "wrap";
11143
10590
  }
11144
10591
  function applySocialsDisplayFromContent(content, root = document) {
11145
10592
  const stored = parseSocialsDisplay(content[SOCIALS_DISPLAY_KEY]);
@@ -12027,12 +11474,17 @@ function deleteFooterColumn(column) {
12027
11474
  }
12028
11475
 
12029
11476
  // src/lib/logo-identity.ts
12030
- var LOGO_TEXT_KEYS = ["nav-logo-text", "footer-logo-text", "logo-text"];
12031
- var LOGO_IMAGE_KEYS = ["nav-logo-image", "footer-logo", "footer-logo-image"];
11477
+ var LOGO_TEXT_KEYS = ["nav-logo-text", "footer-logo-text", "logo-text", "nav-logo", "logo"];
11478
+ var LOGO_IMAGE_KEYS = [
11479
+ "nav-logo-image",
11480
+ "footer-logo",
11481
+ "footer-logo-image",
11482
+ "logo-image",
11483
+ "footer-logo-img"
11484
+ ];
12032
11485
  var LOGO_HREF_KEYS = ["nav-logo-href", "footer-logo-href", "logo-href"];
12033
11486
  var LOGO_PLACEHOLDER_KEY = "logo-is-placeholder";
12034
11487
  var LOGO_ALT_KEY = "logo-alt";
12035
- var LOGO_IMAGE_URL_KEY = "nav-logo-image";
12036
11488
  var PLACEHOLDER_BUSINESS_NAME = "Business name";
12037
11489
  function resolveLogoDisplayText(text) {
12038
11490
  const trimmed = (text ?? "").trim();
@@ -12052,6 +11504,21 @@ function ensureLogoHrefKey(root) {
12052
11504
  if (root.hasAttribute("data-ohw-href-key")) return;
12053
11505
  root.setAttribute("data-ohw-href-key", isFooterLogoRoot(root) ? "footer-logo-href" : "nav-logo-href");
12054
11506
  }
11507
+ function logoTextElement(root) {
11508
+ const SELECTOR = '[data-ohw-editable="plain"], [data-ohw-editable="text"]';
11509
+ if (root.matches(SELECTOR)) return root;
11510
+ const marked = root.querySelector(SELECTOR);
11511
+ if (marked) return marked;
11512
+ const hasOwnText = Array.from(root.childNodes).some(
11513
+ (node) => node.nodeType === Node.TEXT_NODE && node.textContent?.trim()
11514
+ );
11515
+ return hasOwnText ? root : null;
11516
+ }
11517
+ function logoRootImage(root) {
11518
+ const img = root.querySelector("img");
11519
+ const src = img?.getAttribute("src")?.trim() ?? "";
11520
+ return img && src && img.style.display !== "none" ? img : null;
11521
+ }
12055
11522
  function applyLogoIdentity(text, isPlaceholder) {
12056
11523
  const display = resolveLogoDisplayText(text);
12057
11524
  const placeholder = isPlaceholder || !text.trim() || display === PLACEHOLDER_BUSINESS_NAME;
@@ -12069,6 +11536,9 @@ function applyLogoIdentity(text, isPlaceholder) {
12069
11536
  document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]').forEach((el) => {
12070
11537
  if (placeholder) el.setAttribute("data-ohw-placeholder", "");
12071
11538
  else el.removeAttribute("data-ohw-placeholder");
11539
+ if (logoRootImage(el)) return;
11540
+ const textEl = logoTextElement(el);
11541
+ if (textEl && textEl.textContent !== display) textEl.textContent = display;
12072
11542
  });
12073
11543
  return display;
12074
11544
  }
@@ -12079,7 +11549,7 @@ function applyLogoImage(url, alt) {
12079
11549
  const imageKey = imageKeyForRoot(root);
12080
11550
  const textKey = textKeyForRoot(root);
12081
11551
  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");
12082
- let textEl = root.querySelector(`[data-ohw-key="${textKey}"]`) ?? root.querySelector('[data-ohw-key="logo-text"]');
11552
+ let textEl = root.querySelector(`[data-ohw-key="${textKey}"]`) ?? root.querySelector('[data-ohw-key="logo-text"]') ?? logoTextElement(root);
12083
11553
  if (url) {
12084
11554
  if (!img) {
12085
11555
  img = document.createElement("img");
@@ -12101,7 +11571,11 @@ function applyLogoImage(url, alt) {
12101
11571
  img.src = url;
12102
11572
  img.alt = displayAlt;
12103
11573
  img.style.display = "block";
12104
- if (textEl) textEl.style.display = "none";
11574
+ if (textEl === root) {
11575
+ Array.from(root.childNodes).filter((node) => node.nodeType === Node.TEXT_NODE).forEach((node) => node.remove());
11576
+ } else if (textEl) {
11577
+ textEl.style.display = "none";
11578
+ }
12105
11579
  root.removeAttribute("data-ohw-placeholder");
12106
11580
  return;
12107
11581
  }
@@ -12150,6 +11624,13 @@ function readLogoIdentityFromDom() {
12150
11624
  }
12151
11625
  let text = PLACEHOLDER_BUSINESS_NAME;
12152
11626
  let isPlaceholder = true;
11627
+ const rootWithText = Array.from(
11628
+ document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]')
11629
+ ).find((root) => logoTextElement(root)?.textContent?.trim());
11630
+ if (rootWithText) {
11631
+ text = logoTextElement(rootWithText).textContent.trim();
11632
+ isPlaceholder = rootWithText.hasAttribute("data-ohw-placeholder") || text === PLACEHOLDER_BUSINESS_NAME;
11633
+ }
12153
11634
  for (const key of LOGO_TEXT_KEYS) {
12154
11635
  const el = document.querySelector(`[data-ohw-key="${key}"]`);
12155
11636
  if (el?.textContent?.trim()) {
@@ -12180,7 +11661,7 @@ function applyLogoFromContent(content) {
12180
11661
  if (!hasLogoIdentity) return false;
12181
11662
  const logoText = content[LOGO_TEXT_KEYS[0]] ?? content[LOGO_TEXT_KEYS[1]] ?? readLogoIdentityFromDom().text;
12182
11663
  const logoAlt = content[LOGO_ALT_KEY] ?? logoText;
12183
- const rawLogoImage = content[LOGO_IMAGE_URL_KEY] ?? content["footer-logo"] ?? content["footer-logo-image"] ?? null;
11664
+ const rawLogoImage = LOGO_IMAGE_KEYS.map((key) => content[key]).find((value) => typeof value === "string" && value.trim()) ?? null;
12184
11665
  const logoImageUrl = typeof rawLogoImage === "string" && rawLogoImage.trim() ? rawLogoImage.trim() : null;
12185
11666
  const imageExplicitlyCleared = LOGO_IMAGE_KEYS.some((key) => key in content) && !logoImageUrl;
12186
11667
  const logoIsPlaceholder = LOGO_PLACEHOLDER_KEY in content ? content[LOGO_PLACEHOLDER_KEY] !== "false" : !logoImageUrl && (!logoText.trim() || logoText === PLACEHOLDER_BUSINESS_NAME);
@@ -12315,7 +11796,6 @@ function readLogoSizeState(content, placement) {
12315
11796
  function getLogoElement(el) {
12316
11797
  const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
12317
11798
  if (marked) return marked;
12318
- if (el.closest('[data-ohw-editable="icon"]')) return null;
12319
11799
  const root = el.closest("nav, [data-ohw-nav-root], footer");
12320
11800
  if (!root) return null;
12321
11801
  const anchor = el.closest("a");
@@ -13195,449 +12675,122 @@ function useNavItemDrag({
13195
12675
  };
13196
12676
  }
13197
12677
 
13198
- // src/useSectionDrag.ts
13199
- import { useCallback as useCallback7, useEffect as useEffect11, useRef as useRef9, useState as useState10 } from "react";
12678
+ // src/ui/footer-container-chrome.tsx
12679
+ import { Plus as Plus2 } from "lucide-react";
12680
+ import { jsx as jsx29, jsxs as jsxs19 } from "react/jsx-runtime";
12681
+ function FooterContainerChrome({
12682
+ rect,
12683
+ onAdd,
12684
+ addDisabled = false
12685
+ }) {
12686
+ const chromeGap = 6;
12687
+ const buttonMargin = 7;
12688
+ return /* @__PURE__ */ jsx29(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsx29(
12689
+ "div",
12690
+ {
12691
+ "data-ohw-footer-container-chrome": "",
12692
+ "data-ohw-bridge": "",
12693
+ className: "pointer-events-none fixed z-[2147483647]",
12694
+ style: {
12695
+ top: rect.top - chromeGap,
12696
+ left: rect.left - chromeGap,
12697
+ width: rect.width + chromeGap * 2,
12698
+ height: rect.height + chromeGap * 2
12699
+ },
12700
+ children: /* @__PURE__ */ jsxs19(Tooltip, { children: [
12701
+ /* @__PURE__ */ jsx29(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx29(
12702
+ "button",
12703
+ {
12704
+ type: "button",
12705
+ "data-ohw-footer-add-button": "",
12706
+ disabled: addDisabled,
12707
+ 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",
12708
+ style: { top: chromeGap - buttonMargin },
12709
+ "aria-label": "Add item",
12710
+ onMouseDown: (e) => {
12711
+ e.preventDefault();
12712
+ e.stopPropagation();
12713
+ },
12714
+ onClick: (e) => {
12715
+ e.preventDefault();
12716
+ e.stopPropagation();
12717
+ if (addDisabled) return;
12718
+ onAdd();
12719
+ },
12720
+ children: /* @__PURE__ */ jsx29(Plus2, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
12721
+ }
12722
+ ) }),
12723
+ /* @__PURE__ */ jsx29(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
12724
+ ] })
12725
+ }
12726
+ ) });
12727
+ }
13200
12728
 
13201
- // src/lib/section-dnd.ts
13202
- function isFooterSection(el) {
13203
- return el.dataset.ohwSection === "footer";
12729
+ // src/lib/carousel.ts
12730
+ import { useEffect as useEffect11, useState as useState10 } from "react";
12731
+ var CAROUSEL_ATTR = "data-ohw-carousel";
12732
+ var CAROUSEL_VALUE_ATTR = "data-ohw-carousel-value";
12733
+ var CAROUSEL_SLIDE_ATTR = "data-ohw-carousel-slide";
12734
+ var CAROUSEL_EVENT = "ohw:carousel-change";
12735
+ function listCarouselKeys() {
12736
+ const keys = /* @__PURE__ */ new Set();
12737
+ document.querySelectorAll(`[${CAROUSEL_ATTR}]`).forEach((el) => {
12738
+ const key = el.getAttribute("data-ohw-key");
12739
+ if (key) keys.add(key);
12740
+ });
12741
+ return [...keys];
13204
12742
  }
13205
- function buildSectionDropSlots(draggedInstanceId) {
13206
- const sections = topLevelSections().filter(
13207
- (el) => instanceIdOf(el) !== draggedInstanceId && !isFooterSection(el)
12743
+ function containersForKey(key) {
12744
+ return Array.from(
12745
+ document.querySelectorAll(`[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`)
13208
12746
  );
13209
- const slots = [];
13210
- if (sections.length === 0) return slots;
13211
- const left = 0;
13212
- const width = document.documentElement.clientWidth;
13213
- for (let i = 0; i <= sections.length; i++) {
13214
- let y;
13215
- if (i === 0) {
13216
- y = sections[0].getBoundingClientRect().top;
13217
- } else if (i === sections.length) {
13218
- y = sections[sections.length - 1].getBoundingClientRect().bottom;
13219
- } else {
13220
- const prev = sections[i - 1].getBoundingClientRect();
13221
- const next = sections[i].getBoundingClientRect();
13222
- y = (prev.bottom + next.top) / 2;
13223
- }
13224
- slots.push({ insertIndex: i, y, left, width });
12747
+ }
12748
+ function isCarouselKey(key) {
12749
+ return containersForKey(key).length > 0;
12750
+ }
12751
+ function parseSlides(raw) {
12752
+ if (!raw) return [];
12753
+ try {
12754
+ const parsed = JSON.parse(raw);
12755
+ if (!Array.isArray(parsed)) return [];
12756
+ return parsed.filter((s) => Boolean(s) && typeof s === "object").map((s) => ({ src: String(s.src ?? ""), alt: String(s.alt ?? "") }));
12757
+ } catch {
12758
+ return [];
13225
12759
  }
13226
- return slots;
13227
12760
  }
13228
- function hitTestSectionDropSlot(y, slots) {
13229
- let best = null;
13230
- for (const slot of slots) {
13231
- const dist = Math.abs(y - slot.y);
13232
- if (!best || dist < best.dist) best = { slot, dist };
12761
+ function readCarouselValue(key) {
12762
+ const container = containersForKey(key)[0];
12763
+ if (!container) return [];
12764
+ const fromAttr = parseSlides(container.getAttribute(CAROUSEL_VALUE_ATTR));
12765
+ if (fromAttr.length > 0) return fromAttr;
12766
+ return Array.from(container.querySelectorAll(`[${CAROUSEL_SLIDE_ATTR}]`)).filter((slide) => slide.closest(`[${CAROUSEL_ATTR}]`) === container).sort((a, b) => slideIndex(a) - slideIndex(b)).map((slide) => {
12767
+ const img = slide instanceof HTMLImageElement ? slide : slide.querySelector("img");
12768
+ return { src: img?.src ?? "", alt: img?.alt ?? "" };
12769
+ });
12770
+ }
12771
+ function slideIndex(el) {
12772
+ const raw = el.getAttribute(CAROUSEL_SLIDE_ATTR);
12773
+ const n = raw ? parseInt(raw, 10) : NaN;
12774
+ return Number.isFinite(n) ? n : 0;
12775
+ }
12776
+ function applyCarouselValue(key, slides) {
12777
+ const value = JSON.stringify(slides);
12778
+ for (const container of containersForKey(key)) {
12779
+ if (container.getAttribute(CAROUSEL_VALUE_ATTR) === value) continue;
12780
+ container.setAttribute(CAROUSEL_VALUE_ATTR, value);
12781
+ container.dispatchEvent(
12782
+ new CustomEvent(CAROUSEL_EVENT, { detail: { images: slides } })
12783
+ );
13233
12784
  }
13234
- return best?.slot ?? null;
13235
12785
  }
13236
-
13237
- // src/useSectionDrag.ts
13238
- var PRESS_THRESHOLD = 10;
13239
- var EDGE_ZONE = 60;
13240
- var MAX_AUTO_SCROLL_SPEED = 18;
13241
- var SECTION_DRAG_EXCLUDED_SELECTOR = [
13242
- "[data-ohw-toolbar]",
13243
- "[data-ohw-edit-chrome]",
13244
- "[data-ohw-item-interaction]",
13245
- "[data-ohw-drag-handle-container]",
13246
- '[data-slot="drag-handle"]',
13247
- "[data-ohw-item-toolbar-anchor]",
13248
- "[data-ohw-item-drag-surface]",
13249
- "[data-ohw-more-menu]",
13250
- '[data-slot="dropdown-menu-content"]',
13251
- '[data-slot="dropdown-menu-item"]',
13252
- "[data-ohw-state-toggle]",
13253
- "[data-ohw-max-badge]",
13254
- "[data-ohw-floating-panel]",
13255
- "[data-ohw-section-picker]",
13256
- "[data-ohw-link-popover-root]",
13257
- "[data-ohw-link-modal-root]",
13258
- "[data-ohw-link-page-dropdown]",
13259
- '[data-slot="popover-content"]',
13260
- '[data-slot="dialog-content"]',
13261
- '[data-slot="dialog-overlay"]',
13262
- "[data-ohw-ai-review]",
13263
- "[data-ohw-editable]",
13264
- "[data-ohw-editable-state]",
13265
- "[contenteditable]",
13266
- "[data-ohw-href-key]",
13267
- "[data-ohw-footer-col]",
13268
- "[data-ohw-social-label]",
13269
- "a",
13270
- "button",
13271
- '[role="button"]',
13272
- '[data-ohw-role="navbar-button"]',
13273
- '[data-ohw-role="button"]',
13274
- "[data-ohw-carousel]",
13275
- "[data-ohw-carousel-value]",
13276
- "[data-ohw-carousel-slide]",
13277
- "[data-ohw-carousel-overlay]",
13278
- "[data-ohw-media-chrome]",
13279
- "[data-ohw-media-overlay]",
13280
- "[data-ohw-media-skeleton]"
13281
- ].join(", ");
13282
- function visibleClip(ps) {
13283
- if (!ps) return null;
13284
- const top = Math.max(0, ps.headerH - ps.iframeOffsetTop);
13285
- const bottom = Math.min(window.innerHeight, ps.headerH + ps.canvasH - ps.iframeOffsetTop);
13286
- return { top, bottom: Math.max(top, bottom) };
13287
- }
13288
- function useSectionDrag({
13289
- isEditMode,
13290
- editContentRef,
13291
- postToParentRef,
13292
- parentScrollRef,
13293
- navDragRef,
13294
- footerDragRef,
13295
- suppressNextClickRef,
13296
- suppressClickUntilRef
13297
- }) {
13298
- const sectionDragRef = useRef9(null);
13299
- const [sectionDropSlots, setSectionDropSlots] = useState10([]);
13300
- const [activeSectionDropIndex, setActiveSectionDropIndex] = useState10(null);
13301
- const [isSectionDragging, setIsSectionDragging] = useState10(false);
13302
- const sectionPointerDragRef = useRef9(null);
13303
- const autoScrollRafRef = useRef9(null);
13304
- const autoScrollDeltaRef = useRef9(0);
13305
- const stopAutoScroll = useCallback7(() => {
13306
- if (autoScrollRafRef.current != null) {
13307
- cancelAnimationFrame(autoScrollRafRef.current);
13308
- autoScrollRafRef.current = null;
13309
- }
13310
- autoScrollDeltaRef.current = 0;
13311
- }, []);
13312
- const tickAutoScroll = useCallback7(() => {
13313
- if (!sectionDragRef.current) {
13314
- stopAutoScroll();
13315
- return;
13316
- }
13317
- if (autoScrollDeltaRef.current !== 0) {
13318
- postToParentRef.current({ type: "ow:request-scroll", deltaY: autoScrollDeltaRef.current });
13319
- }
13320
- autoScrollRafRef.current = requestAnimationFrame(tickAutoScroll);
13321
- }, [postToParentRef, stopAutoScroll]);
13322
- const updateAutoScroll = useCallback7(
13323
- (clientY) => {
13324
- const clip = visibleClip(parentScrollRef.current);
13325
- let delta = 0;
13326
- if (clip) {
13327
- const distTop = clientY - clip.top;
13328
- const distBottom = clip.bottom - clientY;
13329
- if (distTop >= 0 && distTop < EDGE_ZONE) {
13330
- delta = -MAX_AUTO_SCROLL_SPEED * (1 - distTop / EDGE_ZONE);
13331
- } else if (distBottom >= 0 && distBottom < EDGE_ZONE) {
13332
- delta = MAX_AUTO_SCROLL_SPEED * (1 - distBottom / EDGE_ZONE);
13333
- }
13334
- }
13335
- autoScrollDeltaRef.current = delta;
13336
- if (delta !== 0 && autoScrollRafRef.current == null) {
13337
- autoScrollRafRef.current = requestAnimationFrame(tickAutoScroll);
13338
- } else if (delta === 0) {
13339
- stopAutoScroll();
13340
- }
13341
- },
13342
- [parentScrollRef, stopAutoScroll, tickAutoScroll]
13343
- );
13344
- const clearSectionDragVisuals = useCallback7(() => {
13345
- sectionDragRef.current?.draggedEl.removeAttribute("data-ohw-section-dragging");
13346
- sectionDragRef.current = null;
13347
- setSectionDropSlots([]);
13348
- setActiveSectionDropIndex(null);
13349
- setIsSectionDragging(false);
13350
- stopAutoScroll();
13351
- document.documentElement.removeAttribute("data-ohw-section-dragging-root");
13352
- unlockItemDragInteraction();
13353
- }, [stopAutoScroll]);
13354
- const refreshSectionDragVisuals = useCallback7(
13355
- (session, clientX, clientY) => {
13356
- session.lastClientX = clientX;
13357
- session.lastClientY = clientY;
13358
- const slots = buildSectionDropSlots(session.instanceId);
13359
- const activeSlot = hitTestSectionDropSlot(clientY, slots);
13360
- session.activeSlot = activeSlot;
13361
- setSectionDropSlots(slots);
13362
- const activeIdx = activeSlot ? slots.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
13363
- setActiveSectionDropIndex(activeIdx >= 0 ? activeIdx : null);
13364
- updateAutoScroll(clientY);
13365
- },
13366
- [updateAutoScroll]
13367
- );
13368
- const beginSectionDrag = useCallback7(
13369
- (session) => {
13370
- sectionDragRef.current = session;
13371
- setIsSectionDragging(true);
13372
- lockItemDuringDrag();
13373
- document.documentElement.setAttribute("data-ohw-section-dragging-root", "");
13374
- session.draggedEl.setAttribute("data-ohw-section-dragging", "");
13375
- refreshSectionDragVisuals(session, session.lastClientX, session.lastClientY);
13376
- },
13377
- [refreshSectionDragVisuals]
13378
- );
13379
- const commitSectionDrag = useCallback7(() => {
13380
- const session = sectionDragRef.current;
13381
- if (!session) {
13382
- clearSectionDragVisuals();
13383
- return;
13384
- }
13385
- const slot = session.activeSlot ?? hitTestSectionDropSlot(session.lastClientY, buildSectionDropSlots(session.instanceId));
13386
- const entries = slot ? planSectionMove(session.instanceId, slot.insertIndex, window.location.pathname) : null;
13387
- if (!entries) {
13388
- clearSectionDragVisuals();
13389
- return;
13390
- }
13391
- const orderJson = JSON.stringify(entries);
13392
- editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
13393
- postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
13394
- applyPersistedOrder(entries);
13395
- clearSectionDragVisuals();
13396
- requestAnimationFrame(() => {
13397
- if (editContentRef.current[SECTION_ORDER_KEY] === orderJson) {
13398
- applyPersistedOrder(entries);
13399
- }
13400
- requestAnimationFrame(() => {
13401
- window.dispatchEvent(new Event("resize"));
13402
- });
13403
- });
13404
- }, [clearSectionDragVisuals, editContentRef, postToParentRef]);
13405
- const startSectionPressDrag = useCallback7(
13406
- (el, clientX, clientY, pointerId) => {
13407
- if (navDragRef.current || footerDragRef.current || sectionDragRef.current) return false;
13408
- const instanceId = instanceIdOf(el);
13409
- if (!instanceId) return false;
13410
- sectionPointerDragRef.current = {
13411
- el,
13412
- instanceId,
13413
- startX: clientX,
13414
- startY: clientY,
13415
- pointerId,
13416
- started: false
13417
- };
13418
- return true;
13419
- },
13420
- [footerDragRef, navDragRef]
13421
- );
13422
- useEffect11(() => {
13423
- if (!isEditMode) return;
13424
- const onPointerDown = (e) => {
13425
- if (e.button !== 0) return;
13426
- if (navDragRef.current || footerDragRef.current || sectionDragRef.current) return;
13427
- if (sectionPointerDragRef.current) return;
13428
- const target = e.target;
13429
- if (!(target instanceof HTMLElement)) return;
13430
- if (target.closest(SECTION_DRAG_EXCLUDED_SELECTOR)) return;
13431
- const sectionEl = target.closest("[data-ohw-section]");
13432
- if (!sectionEl || isChromeSection(sectionEl) || sectionEl.dataset.ohwSection === "footer") return;
13433
- if (!topLevelSections().includes(sectionEl)) return;
13434
- startSectionPressDrag(sectionEl, e.clientX, e.clientY, e.pointerId);
13435
- };
13436
- const onPointerMove = (e) => {
13437
- const pending = sectionPointerDragRef.current;
13438
- if (!pending) return;
13439
- if (pending.started) {
13440
- e.preventDefault();
13441
- clearTextSelection();
13442
- const session = sectionDragRef.current;
13443
- if (!session) return;
13444
- refreshSectionDragVisuals(session, e.clientX, e.clientY);
13445
- return;
13446
- }
13447
- const dx = e.clientX - pending.startX;
13448
- const dy = e.clientY - pending.startY;
13449
- if (dx * dx + dy * dy < PRESS_THRESHOLD * PRESS_THRESHOLD) return;
13450
- e.preventDefault();
13451
- pending.started = true;
13452
- armItemPressDrag();
13453
- clearTextSelection();
13454
- try {
13455
- document.body.setPointerCapture(pending.pointerId);
13456
- } catch {
13457
- }
13458
- beginSectionDrag({
13459
- instanceId: pending.instanceId,
13460
- draggedEl: pending.el,
13461
- lastClientX: e.clientX,
13462
- lastClientY: e.clientY,
13463
- activeSlot: null
13464
- });
13465
- };
13466
- const endPointerDrag = (e) => {
13467
- const pending = sectionPointerDragRef.current;
13468
- sectionPointerDragRef.current = null;
13469
- try {
13470
- if (document.body.hasPointerCapture(e.pointerId)) {
13471
- document.body.releasePointerCapture(e.pointerId);
13472
- }
13473
- } catch {
13474
- }
13475
- if (!pending) return;
13476
- if (!pending.started) {
13477
- unlockItemDragInteraction();
13478
- return;
13479
- }
13480
- suppressNextClickRef.current = true;
13481
- suppressClickUntilRef.current = Date.now() + 500;
13482
- commitSectionDrag();
13483
- };
13484
- const onKeyDown = (e) => {
13485
- if (e.key !== "Escape") return;
13486
- if (!sectionDragRef.current && !sectionPointerDragRef.current) return;
13487
- sectionPointerDragRef.current = null;
13488
- clearSectionDragVisuals();
13489
- };
13490
- document.addEventListener("pointerdown", onPointerDown, true);
13491
- document.addEventListener("pointermove", onPointerMove, true);
13492
- document.addEventListener("pointerup", endPointerDrag, true);
13493
- document.addEventListener("pointercancel", endPointerDrag, true);
13494
- document.addEventListener("keydown", onKeyDown, true);
13495
- return () => {
13496
- document.removeEventListener("pointerdown", onPointerDown, true);
13497
- document.removeEventListener("pointermove", onPointerMove, true);
13498
- document.removeEventListener("pointerup", endPointerDrag, true);
13499
- document.removeEventListener("pointercancel", endPointerDrag, true);
13500
- document.removeEventListener("keydown", onKeyDown, true);
13501
- unlockItemDragInteraction();
13502
- stopAutoScroll();
13503
- };
13504
- }, [
13505
- beginSectionDrag,
13506
- clearSectionDragVisuals,
13507
- commitSectionDrag,
13508
- footerDragRef,
13509
- isEditMode,
13510
- navDragRef,
13511
- refreshSectionDragVisuals,
13512
- startSectionPressDrag,
13513
- stopAutoScroll,
13514
- suppressClickUntilRef,
13515
- suppressNextClickRef
13516
- ]);
13517
- return {
13518
- sectionDragRef,
13519
- sectionDropSlots,
13520
- activeSectionDropIndex,
13521
- isSectionDragging
13522
- };
13523
- }
13524
-
13525
- // src/ui/footer-container-chrome.tsx
13526
- import { Plus as Plus2 } from "lucide-react";
13527
- import { jsx as jsx29, jsxs as jsxs19 } from "react/jsx-runtime";
13528
- function FooterContainerChrome({
13529
- rect,
13530
- onAdd,
13531
- addDisabled = false
13532
- }) {
13533
- const chromeGap = 6;
13534
- const buttonMargin = 7;
13535
- return /* @__PURE__ */ jsx29(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsx29(
13536
- "div",
13537
- {
13538
- "data-ohw-footer-container-chrome": "",
13539
- "data-ohw-bridge": "",
13540
- className: "pointer-events-none fixed z-[2147483647]",
13541
- style: {
13542
- top: rect.top - chromeGap,
13543
- left: rect.left - chromeGap,
13544
- width: rect.width + chromeGap * 2,
13545
- height: rect.height + chromeGap * 2
13546
- },
13547
- children: /* @__PURE__ */ jsxs19(Tooltip, { children: [
13548
- /* @__PURE__ */ jsx29(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx29(
13549
- "button",
13550
- {
13551
- type: "button",
13552
- "data-ohw-footer-add-button": "",
13553
- disabled: addDisabled,
13554
- 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",
13555
- style: { top: chromeGap - buttonMargin },
13556
- "aria-label": "Add item",
13557
- onMouseDown: (e) => {
13558
- e.preventDefault();
13559
- e.stopPropagation();
13560
- },
13561
- onClick: (e) => {
13562
- e.preventDefault();
13563
- e.stopPropagation();
13564
- if (addDisabled) return;
13565
- onAdd();
13566
- },
13567
- children: /* @__PURE__ */ jsx29(Plus2, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
13568
- }
13569
- ) }),
13570
- /* @__PURE__ */ jsx29(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
13571
- ] })
13572
- }
13573
- ) });
13574
- }
13575
-
13576
- // src/lib/carousel.ts
13577
- import { useEffect as useEffect12, useState as useState11 } from "react";
13578
- var CAROUSEL_ATTR = "data-ohw-carousel";
13579
- var CAROUSEL_VALUE_ATTR = "data-ohw-carousel-value";
13580
- var CAROUSEL_SLIDE_ATTR = "data-ohw-carousel-slide";
13581
- var CAROUSEL_EVENT = "ohw:carousel-change";
13582
- function listCarouselKeys() {
13583
- const keys = /* @__PURE__ */ new Set();
13584
- document.querySelectorAll(`[${CAROUSEL_ATTR}]`).forEach((el) => {
13585
- const key = el.getAttribute("data-ohw-key");
13586
- if (key) keys.add(key);
13587
- });
13588
- return [...keys];
13589
- }
13590
- function containersForKey(key) {
13591
- return Array.from(
13592
- document.querySelectorAll(`[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`)
13593
- );
13594
- }
13595
- function isCarouselKey(key) {
13596
- return containersForKey(key).length > 0;
13597
- }
13598
- function parseSlides(raw) {
13599
- if (!raw) return [];
13600
- try {
13601
- const parsed = JSON.parse(raw);
13602
- if (!Array.isArray(parsed)) return [];
13603
- return parsed.filter((s) => Boolean(s) && typeof s === "object").map((s) => ({ src: String(s.src ?? ""), alt: String(s.alt ?? "") }));
13604
- } catch {
13605
- return [];
13606
- }
13607
- }
13608
- function readCarouselValue(key) {
13609
- const container = containersForKey(key)[0];
13610
- if (!container) return [];
13611
- const fromAttr = parseSlides(container.getAttribute(CAROUSEL_VALUE_ATTR));
13612
- if (fromAttr.length > 0) return fromAttr;
13613
- return Array.from(container.querySelectorAll(`[${CAROUSEL_SLIDE_ATTR}]`)).filter((slide) => slide.closest(`[${CAROUSEL_ATTR}]`) === container).sort((a, b) => slideIndex(a) - slideIndex(b)).map((slide) => {
13614
- const img = slide instanceof HTMLImageElement ? slide : slide.querySelector("img");
13615
- return { src: img?.src ?? "", alt: img?.alt ?? "" };
13616
- });
13617
- }
13618
- function slideIndex(el) {
13619
- const raw = el.getAttribute(CAROUSEL_SLIDE_ATTR);
13620
- const n = raw ? parseInt(raw, 10) : NaN;
13621
- return Number.isFinite(n) ? n : 0;
13622
- }
13623
- function applyCarouselValue(key, slides) {
13624
- const value = JSON.stringify(slides);
13625
- for (const container of containersForKey(key)) {
13626
- if (container.getAttribute(CAROUSEL_VALUE_ATTR) === value) continue;
13627
- container.setAttribute(CAROUSEL_VALUE_ATTR, value);
13628
- container.dispatchEvent(
13629
- new CustomEvent(CAROUSEL_EVENT, { detail: { images: slides } })
13630
- );
13631
- }
13632
- }
13633
- function applyCarouselNode(key, val) {
13634
- if (!isCarouselKey(key)) return false;
13635
- applyCarouselValue(key, parseSlides(val));
13636
- return true;
12786
+ function applyCarouselNode(key, val) {
12787
+ if (!isCarouselKey(key)) return false;
12788
+ applyCarouselValue(key, parseSlides(val));
12789
+ return true;
13637
12790
  }
13638
12791
  function useOhwCarousel(key, initial) {
13639
- const [images, setImages] = useState11(initial);
13640
- useEffect12(() => {
12792
+ const [images, setImages] = useState10(initial);
12793
+ useEffect11(() => {
13641
12794
  const el = document.querySelector(
13642
12795
  `[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`
13643
12796
  );
@@ -13715,7 +12868,7 @@ function collectEditableNodes(extraContent, root = document) {
13715
12868
  nodes.push({ key, type: "link", text: href });
13716
12869
  }
13717
12870
  if (extraContent) {
13718
- for (const key of [NAV_ORDER_KEY, FOOTER_ORDER_KEY, NAV_COUNT_KEY, SECTION_ORDER_KEY]) {
12871
+ for (const key of [NAV_ORDER_KEY, FOOTER_ORDER_KEY, NAV_COUNT_KEY]) {
13719
12872
  const text = extraContent[key];
13720
12873
  if (typeof text === "string" && text.length > 0) {
13721
12874
  nodes.push({ key, type: "meta", text });
@@ -13752,18 +12905,6 @@ function collectEditableNodes(extraContent, root = document) {
13752
12905
  }
13753
12906
  if (extraContent && !isScoped) {
13754
12907
  applyNavFooterDeleteOverrides(byKey, extraContent);
13755
- for (const key of LOGO_IMAGE_KEYS) {
13756
- if (!(key in extraContent)) continue;
13757
- byKey.set(key, { key, type: "image", text: extraContent[key] ?? "" });
13758
- }
13759
- for (const key of [LOGO_PLACEHOLDER_KEY, LOGO_ALT_KEY]) {
13760
- if (!(key in extraContent)) continue;
13761
- byKey.set(key, { key, type: "meta", text: extraContent[key] ?? "" });
13762
- }
13763
- for (const key of LOGO_SIZE_KEYS) {
13764
- if (!(key in extraContent)) continue;
13765
- byKey.set(key, { key, type: "meta", text: extraContent[key] ?? "" });
13766
- }
13767
12908
  }
13768
12909
  return Array.from(byKey.values());
13769
12910
  }
@@ -14168,7 +13309,6 @@ function fadeInImageElement(img, onReady) {
14168
13309
  function applyEditableImageSrc(img, url) {
14169
13310
  img.removeAttribute("srcset");
14170
13311
  img.removeAttribute("sizes");
14171
- if (img.loading === "lazy") img.loading = "eager";
14172
13312
  img.src = url;
14173
13313
  }
14174
13314
  function fadeInBgImage(el, url, onReady) {
@@ -14233,10 +13373,21 @@ function parseSchedulingInsertAfter(insertAfter) {
14233
13373
  insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
14234
13374
  };
14235
13375
  }
14236
- function resolveEntryAnchor(entry) {
14237
- if (entry.anchorId !== void 0) return { anchorId: entry.anchorId, beforeId: entry.beforeId ?? null };
14238
- const parsed = parseSchedulingInsertAfter(entry.insertAfter);
14239
- return { anchorId: parsed.anchor, beforeId: parsed.insertBefore };
13376
+ function resolveSchedulingInsert(insertAfter, explicitInsertBefore) {
13377
+ const parsed = parseSchedulingInsertAfter(insertAfter);
13378
+ const insertBefore = explicitInsertBefore ?? parsed.insertBefore;
13379
+ const effectiveInsertAfter = insertBefore && parsed.insertBefore === null ? `${insertAfter}${INSERT_BEFORE_MARKER}${insertBefore}` : insertAfter;
13380
+ return { effectiveInsertAfter, insertBefore };
13381
+ }
13382
+ function getSchedulingMountPoint(insertAfter) {
13383
+ const { anchor } = parseSchedulingInsertAfter(insertAfter);
13384
+ let anchorEl = document.querySelector(`[data-ohw-section="${anchor}"]`);
13385
+ if (!anchorEl && anchor === "scheduling") {
13386
+ const widgets = Array.from(document.querySelectorAll('[data-ohw-section^="scheduling-"]'));
13387
+ anchorEl = widgets.at(-1) ?? null;
13388
+ }
13389
+ if (!anchorEl) return null;
13390
+ return anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
14240
13391
  }
14241
13392
  function schedulingMountDepth(insertAfter) {
14242
13393
  if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
@@ -14253,7 +13404,8 @@ function getPageSchedulingEntries(raw) {
14253
13404
  }
14254
13405
  }
14255
13406
  function isSchedulingWidgetMissing(entry) {
14256
- return !document.querySelector(`[data-ohw-section="${schedulingSectionId(entry.insertAfter)}"]`);
13407
+ const { effectiveInsertAfter } = resolveSchedulingInsert(entry.insertAfter);
13408
+ return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
14257
13409
  }
14258
13410
  function hasMissingSchedulingWidgets(entries) {
14259
13411
  return entries.some(isSchedulingWidgetMissing);
@@ -14283,17 +13435,16 @@ function initSectionsFromContent(content, removeExisting = false) {
14283
13435
  } catch {
14284
13436
  }
14285
13437
  }
14286
- function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, beforeId, existingWidgetId) {
14287
- const widgetId = existingWidgetId ?? (beforeId ? `${anchorId}${INSERT_BEFORE_MARKER}${beforeId}` : anchorId);
14288
- const sectionId = schedulingSectionId(widgetId);
13438
+ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId, explicitInsertBefore) {
13439
+ const { effectiveInsertAfter, insertBefore } = resolveSchedulingInsert(insertAfter, explicitInsertBefore);
13440
+ const sectionId = schedulingSectionId(effectiveInsertAfter);
14289
13441
  if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
14290
- const anchorEl = document.querySelector(`[data-ohw-section="${anchorId}"]`);
14291
- if (!anchorEl) return false;
14292
- const mountPoint = anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
13442
+ const mountPoint = getSchedulingMountPoint(effectiveInsertAfter);
13443
+ if (!mountPoint) return false;
14293
13444
  const container = document.createElement("div");
14294
13445
  container.dataset.ohwSectionContainer = "scheduling";
14295
- if (beforeId) {
14296
- const beforeAnchor = document.querySelector(`[data-ohw-section="${beforeId}"]`);
13446
+ if (insertBefore) {
13447
+ const beforeAnchor = document.querySelector(`[data-ohw-section="${insertBefore}"]`);
14297
13448
  const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
14298
13449
  if (!beforePoint) return false;
14299
13450
  beforePoint.insertAdjacentElement("beforebegin", container);
@@ -14304,25 +13455,19 @@ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, be
14304
13455
  }
14305
13456
  tail.insertAdjacentElement("afterend", container);
14306
13457
  }
14307
- try {
14308
- const root = createRoot2(container);
14309
- flushSync2(() => {
14310
- root.render(
14311
- /* @__PURE__ */ jsx33(
14312
- SchedulingWidget,
14313
- {
14314
- notifyOnConnect,
14315
- initialScheduleId: scheduleId,
14316
- insertAfter: widgetId
14317
- }
14318
- )
14319
- );
14320
- });
14321
- } catch (err) {
14322
- console.error("[ow:scheduling] render threw", err);
14323
- container.remove();
14324
- return false;
14325
- }
13458
+ const root = createRoot2(container);
13459
+ flushSync2(() => {
13460
+ root.render(
13461
+ /* @__PURE__ */ jsx33(
13462
+ SchedulingWidget,
13463
+ {
13464
+ notifyOnConnect,
13465
+ initialScheduleId: scheduleId,
13466
+ insertAfter: effectiveInsertAfter
13467
+ }
13468
+ )
13469
+ );
13470
+ });
14326
13471
  const tracker = getSectionsTracker();
14327
13472
  let sections = [];
14328
13473
  try {
@@ -14330,12 +13475,10 @@ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, be
14330
13475
  } catch {
14331
13476
  }
14332
13477
  const inEditor = typeof window !== "undefined" && window.self !== window.top;
14333
- if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === widgetId)) {
13478
+ if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === effectiveInsertAfter)) {
14334
13479
  sections.push({
14335
13480
  type: "scheduling",
14336
- insertAfter: widgetId,
14337
- anchorId,
14338
- beforeId: beforeId ?? null,
13481
+ insertAfter: effectiveInsertAfter,
14339
13482
  pagePath: window.location.pathname,
14340
13483
  ...scheduleId ? { scheduleId } : {}
14341
13484
  });
@@ -14349,8 +13492,7 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
14349
13492
  for (let i = pending.length - 1; i >= 0; i--) {
14350
13493
  const entry = pending[i];
14351
13494
  const shouldNotify = typeof notifyOnConnect === "function" ? notifyOnConnect(entry) : notifyOnConnect;
14352
- const { anchorId, beforeId } = resolveEntryAnchor(entry);
14353
- if (mountSchedulingWidget(anchorId, shouldNotify, entry.scheduleId ?? null, beforeId, entry.insertAfter)) {
13495
+ if (mountSchedulingWidget(entry.insertAfter, shouldNotify, entry.scheduleId)) {
14354
13496
  pending.splice(i, 1);
14355
13497
  }
14356
13498
  }
@@ -14498,13 +13640,6 @@ function isInsideLinkEditor(target) {
14498
13640
  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"]')
14499
13641
  );
14500
13642
  }
14501
- function isInsideFloatingPanel(target) {
14502
- return Boolean(target.closest("[data-ohw-floating-panel]"));
14503
- }
14504
- function isPointOverFloatingPanel(clientX, clientY) {
14505
- const el = document.elementFromPoint(clientX, clientY);
14506
- return Boolean(el instanceof Element && el.closest("[data-ohw-floating-panel]"));
14507
- }
14508
13643
  function getHrefKeyFromElement(el) {
14509
13644
  if (!el) return null;
14510
13645
  const anchor = el.closest("[data-ohw-href-key]");
@@ -14655,6 +13790,13 @@ function resolveFooterColumnSelectionTarget(target, clientX, clientY) {
14655
13790
  if (isPointOverNavItem(column, clientX, clientY)) return null;
14656
13791
  return column;
14657
13792
  }
13793
+ function isPointOverLogo(x, y) {
13794
+ for (const root of document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]')) {
13795
+ const r2 = root.getBoundingClientRect();
13796
+ if (r2.width > 0 && r2.height > 0 && x >= r2.left && x <= r2.right && y >= r2.top && y <= r2.bottom) return true;
13797
+ }
13798
+ return false;
13799
+ }
14658
13800
  function isPointOverNavigation(x, y) {
14659
13801
  const roots = /* @__PURE__ */ new Set();
14660
13802
  const navRoot = document.querySelector("[data-ohw-nav-root]") ?? document.querySelector("nav");
@@ -14743,7 +13885,7 @@ function getNavigationSelectionParent(el) {
14743
13885
  if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
14744
13886
  return getFooterLinksContainer();
14745
13887
  }
14746
- 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)) {
13888
+ if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
14747
13889
  return getNavigationRoot(el);
14748
13890
  }
14749
13891
  return null;
@@ -15336,45 +14478,6 @@ function StateToggle({
15336
14478
  );
15337
14479
  }
15338
14480
  var contentCache = /* @__PURE__ */ new Map();
15339
- var fetchedContentPaths = /* @__PURE__ */ new Set();
15340
- var OHW_LOADER_STYLE = {
15341
- position: "fixed",
15342
- inset: 0,
15343
- background: "#fff",
15344
- zIndex: 2147483646,
15345
- display: "flex",
15346
- alignItems: "center",
15347
- justifyContent: "center"
15348
- };
15349
- function OhwLoaderSpinner() {
15350
- return /* @__PURE__ */ jsxs20("svg", { width: "28", height: "28", viewBox: "0 0 28 28", fill: "none", "aria-hidden": true, children: [
15351
- /* @__PURE__ */ jsx33("circle", { cx: "14", cy: "14", r: "11", stroke: "#E7E5E4", strokeWidth: "3" }),
15352
- /* @__PURE__ */ jsx33(
15353
- "circle",
15354
- {
15355
- cx: "14",
15356
- cy: "14",
15357
- r: "11",
15358
- stroke: "#1C1917",
15359
- strokeWidth: "3",
15360
- strokeDasharray: "17 52",
15361
- strokeLinecap: "round",
15362
- children: /* @__PURE__ */ jsx33(
15363
- "animateTransform",
15364
- {
15365
- attributeName: "transform",
15366
- type: "rotate",
15367
- from: "0 14 14",
15368
- to: "360 14 14",
15369
- dur: "0.7s",
15370
- repeatCount: "indefinite"
15371
- }
15372
- )
15373
- }
15374
- )
15375
- ] });
15376
- }
15377
- 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){}})();`;
15378
14481
  function resolveSubdomain(subdomainFromQuery) {
15379
14482
  if (subdomainFromQuery) return subdomainFromQuery;
15380
14483
  if (typeof window !== "undefined") {
@@ -15397,8 +14500,8 @@ function OhhwellsBridge() {
15397
14500
  const router = useRouter3();
15398
14501
  const searchParams = useSearchParams();
15399
14502
  const isEditMode = isEditSessionActive();
15400
- const [bridgeRoot, setBridgeRoot] = useState12(null);
15401
- useEffect13(() => {
14503
+ const [bridgeRoot, setBridgeRoot] = useState11(null);
14504
+ useEffect12(() => {
15402
14505
  const figtreeFontId = "ohw-figtree-font";
15403
14506
  if (!document.getElementById(figtreeFontId)) {
15404
14507
  const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
@@ -15427,146 +14530,82 @@ function OhhwellsBridge() {
15427
14530
  const subdomain = resolveSubdomain(subdomainFromQuery);
15428
14531
  useLinkHrefGuardian(pathname, subdomain, isEditMode);
15429
14532
  useSavedLinkNavigation(isEditMode);
15430
- const postToParent2 = useCallback8((data) => {
14533
+ const postToParent2 = useCallback7((data) => {
15431
14534
  if (typeof window !== "undefined" && window.parent !== window) {
15432
14535
  window.parent.postMessage(data, "*");
15433
14536
  }
15434
14537
  }, []);
15435
- const [fetchState, setFetchState] = useState12("idle");
15436
- const autoSaveTimers = useRef10(/* @__PURE__ */ new Map());
15437
- const activeElRef = useRef10(null);
15438
- const pointerHeldRef = useRef10(false);
15439
- const selectedElRef = useRef10(null);
15440
- const selectedHrefKeyRef = useRef10(null);
15441
- const selectedFooterColAttrRef = useRef10(null);
15442
- const originalContentRef = useRef10(null);
15443
- const activeStateElRef = useRef10(null);
15444
- const parentScrollRef = useRef10(null);
15445
- const visibleViewportRef = useRef10(null);
15446
- const [dialogPortalContainer, setDialogPortalContainer] = useState12(null);
15447
- const attachVisibleViewport = useCallback8((node) => {
14538
+ const [fetchState, setFetchState] = useState11("idle");
14539
+ const autoSaveTimers = useRef9(/* @__PURE__ */ new Map());
14540
+ const activeElRef = useRef9(null);
14541
+ const pointerHeldRef = useRef9(false);
14542
+ const selectedElRef = useRef9(null);
14543
+ const selectedHrefKeyRef = useRef9(null);
14544
+ const selectedFooterColAttrRef = useRef9(null);
14545
+ const originalContentRef = useRef9(null);
14546
+ const activeStateElRef = useRef9(null);
14547
+ const parentScrollRef = useRef9(null);
14548
+ const visibleViewportRef = useRef9(null);
14549
+ const [dialogPortalContainer, setDialogPortalContainer] = useState11(null);
14550
+ const attachVisibleViewport = useCallback7((node) => {
15448
14551
  visibleViewportRef.current = node;
15449
14552
  setDialogPortalContainer(node);
15450
14553
  if (node) applyVisibleViewport(node, parentScrollRef.current);
15451
14554
  }, []);
15452
- const toolbarElRef = useRef10(null);
15453
- const glowElRef = useRef10(null);
15454
- const hoveredImageRef = useRef10(null);
15455
- const hoveredImageHasTextOverlapRef = useRef10(false);
15456
- const dragOverElRef = useRef10(null);
15457
- const [mediaHover, setMediaHover] = useState12(null);
15458
- const [selectedMedia, setSelectedMedia] = useState12(null);
15459
- const selectedMediaElRef = useRef10(null);
15460
- const clearMediaSelection = useCallback8(() => {
15461
- const prev = selectedMediaElRef.current;
15462
- selectedMediaElRef.current = null;
15463
- setSelectedMedia(null);
15464
- const sectionEl = prev?.closest("[data-ohw-section]") ?? null;
15465
- if (sectionEl) {
15466
- postToParentRef.current({
15467
- type: "ow:section-selected",
15468
- sectionId: sectionEl.dataset.ohwSection ?? null,
15469
- sectionLabel: sectionEl.dataset.ohwSectionLabel ?? titleCaseSectionId(sectionEl.dataset.ohwSection ?? ""),
15470
- key: null
15471
- });
15472
- }
15473
- }, []);
15474
- const clearMediaSelectionRef = useRef10(clearMediaSelection);
15475
- clearMediaSelectionRef.current = clearMediaSelection;
15476
- const selectMediaElement = useCallback8((el) => {
15477
- const r2 = el.getBoundingClientRect();
15478
- const video = el.dataset.ohwEditable === "video" ? el.querySelector("video") : null;
15479
- selectedMediaElRef.current = el;
15480
- setSelectedMedia({
15481
- key: el.dataset.ohwKey ?? "",
15482
- rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height },
15483
- elementType: el.dataset.ohwEditable ?? "image",
15484
- hasTextOverlap: false,
15485
- isDragOver: false,
15486
- ...video ? { videoAutoplay: video.autoplay, videoMuted: video.muted } : {}
15487
- });
15488
- const sectionEl = el.closest("[data-ohw-section]");
15489
- aiSectionApiRef.current?.selectFromElement(el, { report: false });
15490
- postToParentRef.current({
15491
- type: "ow:section-selected",
15492
- sectionId: sectionEl?.dataset.ohwSection ?? null,
15493
- sectionLabel: sectionEl ? sectionEl.dataset.ohwSectionLabel ?? titleCaseSectionId(sectionEl.dataset.ohwSection ?? "") : null,
15494
- key: el.dataset.ohwKey ?? null,
15495
- // Display name for the pill — the raw key prettifies into fragments ("Img"); the
15496
- // bridge knows what the node IS, so it names it.
15497
- keyLabel: el.dataset.ohwEditable === "video" ? "Video" : "Image"
15498
- });
15499
- }, []);
15500
- const selectMediaElementRef = useRef10(selectMediaElement);
15501
- selectMediaElementRef.current = selectMediaElement;
15502
- useEffect13(() => {
15503
- if (!selectedMedia) return;
15504
- const update = () => {
15505
- const el = selectedMediaElRef.current;
15506
- if (!el || !el.isConnected) {
15507
- clearMediaSelection();
15508
- return;
15509
- }
15510
- const r2 = el.getBoundingClientRect();
15511
- setSelectedMedia(
15512
- (prev) => prev ? { ...prev, rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height } } : prev
15513
- );
15514
- };
15515
- window.addEventListener("scroll", update, true);
15516
- window.addEventListener("resize", update);
15517
- return () => {
15518
- window.removeEventListener("scroll", update, true);
15519
- window.removeEventListener("resize", update);
15520
- };
15521
- }, [selectedMedia !== null]);
15522
- const [carouselHover, setCarouselHover] = useState12(null);
15523
- const [uploadingRects, setUploadingRects] = useState12({});
15524
- const hoveredGapRef = useRef10(null);
15525
- const imageUnhoverTimerRef = useRef10(null);
15526
- const imageShowTimerRef = useRef10(null);
15527
- const editStylesRef = useRef10(null);
15528
- const activateRef = useRef10(() => {
14555
+ const toolbarElRef = useRef9(null);
14556
+ const glowElRef = useRef9(null);
14557
+ const hoveredImageRef = useRef9(null);
14558
+ const hoveredImageHasTextOverlapRef = useRef9(false);
14559
+ const dragOverElRef = useRef9(null);
14560
+ const [mediaHover, setMediaHover] = useState11(null);
14561
+ const [carouselHover, setCarouselHover] = useState11(null);
14562
+ const [uploadingRects, setUploadingRects] = useState11({});
14563
+ const hoveredGapRef = useRef9(null);
14564
+ const imageUnhoverTimerRef = useRef9(null);
14565
+ const imageShowTimerRef = useRef9(null);
14566
+ const editStylesRef = useRef9(null);
14567
+ const activateRef = useRef9(() => {
15529
14568
  });
15530
- const deactivateRef = useRef10(() => {
14569
+ const deactivateRef = useRef9(() => {
15531
14570
  });
15532
- const selectRef = useRef10(() => {
14571
+ const selectRef = useRef9(() => {
15533
14572
  });
15534
- const selectFrameRef = useRef10(() => {
14573
+ const selectFrameRef = useRef9(() => {
15535
14574
  });
15536
- const selectLogoRef = useRef10(() => {
14575
+ const selectLogoRef = useRef9(() => {
15537
14576
  });
15538
- const openLogoSizePanelRef = useRef10(() => {
14577
+ const openLogoSizePanelRef = useRef9(() => {
15539
14578
  });
15540
- const deselectRef = useRef10(() => {
14579
+ const deselectRef = useRef9(() => {
15541
14580
  });
15542
- const closeFloatingPanelOnlyRef = useRef10(() => {
14581
+ const closeFloatingPanelOnlyRef = useRef9(() => {
15543
14582
  });
15544
- const reselectNavigationItemRef = useRef10(() => {
14583
+ const reselectNavigationItemRef = useRef9(() => {
15545
14584
  });
15546
- const commitNavigationTextEditRef = useRef10(() => {
14585
+ const commitNavigationTextEditRef = useRef9(() => {
15547
14586
  });
15548
- const handleDeleteSelectedRef = useRef10(() => false);
15549
- const runPendingDeleteUndoRef = useRef10(() => false);
15550
- const isFooterFrameSelectionRef = useRef10(false);
15551
- const refreshActiveCommandsRef = useRef10(() => {
14587
+ const handleDeleteSelectedRef = useRef9(() => false);
14588
+ const runPendingDeleteUndoRef = useRef9(() => false);
14589
+ const isFooterFrameSelectionRef = useRef9(false);
14590
+ const refreshActiveCommandsRef = useRef9(() => {
15552
14591
  });
15553
- const postToParentRef = useRef10(postToParent2);
14592
+ const postToParentRef = useRef9(postToParent2);
15554
14593
  postToParentRef.current = postToParent2;
15555
- const aiSectionApiRef = useRef10(null);
15556
- const sectionsLoadedRef = useRef10(false);
15557
- const pendingScheduleConfigRequests = useRef10([]);
15558
- const [toolbarRect, setToolbarRect] = useState12(null);
15559
- const [formPickRect, setFormPickRect] = useState12(null);
15560
- const formPickElRef = useRef10(null);
15561
- const [formViewState, setFormViewStateUi] = useState12("default");
15562
- const [formPickCount, setFormPickCount] = useState12(null);
15563
- const [formHoverRect, setFormHoverRect] = useState12(null);
15564
- const formHoverElRef = useRef10(null);
15565
- const [fieldPickRect, setFieldPickRect] = useState12(null);
15566
- const fieldPickElRef = useRef10(null);
15567
- const [fieldPickState, setFieldPickState] = useState12(null);
15568
- const [fieldTypePickerOpen, setFieldTypePickerOpen] = useState12(false);
15569
- const clearFormPick = useCallback8(() => {
14594
+ const aiSectionApiRef = useRef9(null);
14595
+ const sectionsLoadedRef = useRef9(false);
14596
+ const pendingScheduleConfigRequests = useRef9([]);
14597
+ const [toolbarRect, setToolbarRect] = useState11(null);
14598
+ const [formPickRect, setFormPickRect] = useState11(null);
14599
+ const formPickElRef = useRef9(null);
14600
+ const [formViewState, setFormViewStateUi] = useState11("default");
14601
+ const [formPickCount, setFormPickCount] = useState11(null);
14602
+ const [formHoverRect, setFormHoverRect] = useState11(null);
14603
+ const formHoverElRef = useRef9(null);
14604
+ const [fieldPickRect, setFieldPickRect] = useState11(null);
14605
+ const fieldPickElRef = useRef9(null);
14606
+ const [fieldPickState, setFieldPickState] = useState11(null);
14607
+ const [fieldTypePickerOpen, setFieldTypePickerOpen] = useState11(false);
14608
+ const clearFormPick = useCallback7(() => {
15570
14609
  const form = formPickElRef.current;
15571
14610
  const editing = fieldPickElRef.current;
15572
14611
  if (commitPlaceholderEdit(editing) && editing) {
@@ -15586,7 +14625,7 @@ function OhhwellsBridge() {
15586
14625
  formPickElRef.current = null;
15587
14626
  setFormPickRect(null);
15588
14627
  }, []);
15589
- const clearFieldPick = useCallback8(() => {
14628
+ const clearFieldPick = useCallback7(() => {
15590
14629
  const wrapper = fieldPickElRef.current;
15591
14630
  if (commitPlaceholderEdit(wrapper) && wrapper) {
15592
14631
  const form = wrapper.closest('[data-ohw-editable="form"]');
@@ -15596,9 +14635,9 @@ function OhhwellsBridge() {
15596
14635
  setFieldPickRect(null);
15597
14636
  setFieldPickState(null);
15598
14637
  }, []);
15599
- const persistFieldsRef = useRef10(() => {
14638
+ const persistFieldsRef = useRef9(() => {
15600
14639
  });
15601
- const persistFields = useCallback8(
14640
+ const persistFields = useCallback7(
15602
14641
  (form) => {
15603
14642
  const key = formKeyOf(form);
15604
14643
  if (!key) return;
@@ -15609,7 +14648,7 @@ function OhhwellsBridge() {
15609
14648
  []
15610
14649
  );
15611
14650
  persistFieldsRef.current = persistFields;
15612
- const selectField = useCallback8((wrapper) => {
14651
+ const selectField = useCallback7((wrapper) => {
15613
14652
  if (fieldPickElRef.current && fieldPickElRef.current !== wrapper) {
15614
14653
  commitPlaceholderEdit(fieldPickElRef.current);
15615
14654
  }
@@ -15622,7 +14661,7 @@ function OhhwellsBridge() {
15622
14661
  setFieldPickState({ type: fieldTypeOf(wrapper), required: isFieldRequired(wrapper) });
15623
14662
  setFieldTypePickerOpen(false);
15624
14663
  }, []);
15625
- const withSelectedField = useCallback8(
14664
+ const withSelectedField = useCallback7(
15626
14665
  (run) => {
15627
14666
  const wrapper = fieldPickElRef.current;
15628
14667
  const form = formPickElRef.current;
@@ -15635,28 +14674,28 @@ function OhhwellsBridge() {
15635
14674
  },
15636
14675
  [persistFields]
15637
14676
  );
15638
- const handleFieldTypeChange = useCallback8(
14677
+ const handleFieldTypeChange = useCallback7(
15639
14678
  (type) => withSelectedField((_form, wrapper) => {
15640
14679
  applyFieldType(wrapper, type);
15641
14680
  selectField(wrapper);
15642
14681
  }),
15643
14682
  [selectField, withSelectedField]
15644
14683
  );
15645
- const handleFieldRequiredToggle = useCallback8(
14684
+ const handleFieldRequiredToggle = useCallback7(
15646
14685
  () => withSelectedField((_form, wrapper) => {
15647
14686
  setFieldRequired(wrapper, !isFieldRequired(wrapper));
15648
14687
  selectField(wrapper);
15649
14688
  }),
15650
14689
  [selectField, withSelectedField]
15651
14690
  );
15652
- const handleFieldDuplicate = useCallback8(
14691
+ const handleFieldDuplicate = useCallback7(
15653
14692
  () => withSelectedField((form, wrapper) => {
15654
14693
  const copy = duplicateField(form, wrapper);
15655
14694
  selectField(copy);
15656
14695
  }),
15657
14696
  [selectField, withSelectedField]
15658
14697
  );
15659
- const handleFieldDelete = useCallback8(
14698
+ const handleFieldDelete = useCallback7(
15660
14699
  () => withSelectedField((_form, wrapper) => {
15661
14700
  removeField(wrapper);
15662
14701
  clearFieldPick();
@@ -15664,7 +14703,7 @@ function OhhwellsBridge() {
15664
14703
  }),
15665
14704
  [clearFieldPick, withSelectedField]
15666
14705
  );
15667
- const handleAddField = useCallback8(
14706
+ const handleAddField = useCallback7(
15668
14707
  (type) => {
15669
14708
  const form = formPickElRef.current;
15670
14709
  if (!form) return;
@@ -15680,8 +14719,8 @@ function OhhwellsBridge() {
15680
14719
  },
15681
14720
  [persistFields, selectField]
15682
14721
  );
15683
- const fieldDragRef = useRef10(null);
15684
- const buildFieldDropSlots = useCallback8((form, draggedKey) => {
14722
+ const fieldDragRef = useRef9(null);
14723
+ const buildFieldDropSlots = useCallback7((form, draggedKey) => {
15685
14724
  const others = listFieldWrappers(form).filter((el) => fieldKeyOf(el) !== draggedKey);
15686
14725
  const slots = others.map((el) => {
15687
14726
  const rect = el.getBoundingClientRect();
@@ -15694,7 +14733,7 @@ function OhhwellsBridge() {
15694
14733
  }
15695
14734
  return slots;
15696
14735
  }, []);
15697
- const handleFieldDragStart = useCallback8(() => {
14736
+ const handleFieldDragStart = useCallback7(() => {
15698
14737
  const wrapper = fieldPickElRef.current;
15699
14738
  const form = formPickElRef.current;
15700
14739
  if (!wrapper || !form) return;
@@ -15703,18 +14742,18 @@ function OhhwellsBridge() {
15703
14742
  setFieldDragging(true);
15704
14743
  setFieldDropSlots(buildFieldDropSlots(form, key));
15705
14744
  }, [buildFieldDropSlots]);
15706
- const handleFieldDragEnd = useCallback8(() => {
14745
+ const handleFieldDragEnd = useCallback7(() => {
15707
14746
  fieldDragRef.current = null;
15708
14747
  setFieldDropIndex(null);
15709
14748
  setFieldDropSlots([]);
15710
14749
  setFieldDragging(false);
15711
14750
  }, []);
15712
- const [fieldDropIndex, setFieldDropIndex] = useState12(null);
15713
- const [fieldDropSlots, setFieldDropSlots] = useState12([]);
15714
- const [fieldDragging, setFieldDragging] = useState12(false);
15715
- const clearFormPickRef = useRef10(clearFormPick);
14751
+ const [fieldDropIndex, setFieldDropIndex] = useState11(null);
14752
+ const [fieldDropSlots, setFieldDropSlots] = useState11([]);
14753
+ const [fieldDragging, setFieldDragging] = useState11(false);
14754
+ const clearFormPickRef = useRef9(clearFormPick);
15716
14755
  clearFormPickRef.current = clearFormPick;
15717
- useEffect13(() => {
14756
+ useEffect12(() => {
15718
14757
  const el = fieldPickElRef.current;
15719
14758
  if (!el || fieldPickRect === null) return;
15720
14759
  const observer = new ResizeObserver(() => {
@@ -15723,7 +14762,7 @@ function OhhwellsBridge() {
15723
14762
  observer.observe(el);
15724
14763
  return () => observer.disconnect();
15725
14764
  }, [fieldPickRect !== null, fieldPickState]);
15726
- useEffect13(() => {
14765
+ useEffect12(() => {
15727
14766
  const el = formPickElRef.current;
15728
14767
  if (!el || formPickRect === null) return;
15729
14768
  const observer = new ResizeObserver(() => {
@@ -15732,25 +14771,25 @@ function OhhwellsBridge() {
15732
14771
  observer.observe(el);
15733
14772
  return () => observer.disconnect();
15734
14773
  }, [formPickRect !== null, formViewState]);
15735
- const [toolbarVariant, setToolbarVariant] = useState12("none");
15736
- const toolbarVariantRef = useRef10("none");
14774
+ const [toolbarVariant, setToolbarVariant] = useState11("none");
14775
+ const toolbarVariantRef = useRef9("none");
15737
14776
  toolbarVariantRef.current = toolbarVariant;
15738
- const [selectedIsCta, setSelectedIsCta] = useState12(false);
15739
- const [selectedIsSocial, setSelectedIsSocial] = useState12(false);
15740
- const [selectedIsSocialsRow, setSelectedIsSocialsRow] = useState12(false);
15741
- const [reorderHrefKey, setReorderHrefKey] = useState12(null);
15742
- const [reorderDragDisabled, setReorderDragDisabled] = useState12(false);
15743
- const [toggleState, setToggleState] = useState12(null);
15744
- const [maxBadge, setMaxBadge] = useState12(null);
15745
- const [activeCommands, setActiveCommands] = useState12(/* @__PURE__ */ new Set());
15746
- const [sectionGap, setSectionGap] = useState12(null);
15747
- const [toolbarShowEditLink, setToolbarShowEditLink] = useState12(false);
15748
- const hoveredNavContainerRef = useRef10(null);
15749
- const [hoveredNavContainerRect, setHoveredNavContainerRect] = useState12(null);
15750
- const hoveredItemElRef = useRef10(null);
15751
- const [hoveredItemRect, setHoveredItemRect] = useState12(null);
15752
- const [hoveredTextRect, setHoveredTextRect] = useState12(null);
15753
- useEffect13(() => {
14777
+ const [selectedIsCta, setSelectedIsCta] = useState11(false);
14778
+ const [selectedIsSocial, setSelectedIsSocial] = useState11(false);
14779
+ const [selectedIsSocialsRow, setSelectedIsSocialsRow] = useState11(false);
14780
+ const [reorderHrefKey, setReorderHrefKey] = useState11(null);
14781
+ const [reorderDragDisabled, setReorderDragDisabled] = useState11(false);
14782
+ const [toggleState, setToggleState] = useState11(null);
14783
+ const [maxBadge, setMaxBadge] = useState11(null);
14784
+ const [activeCommands, setActiveCommands] = useState11(/* @__PURE__ */ new Set());
14785
+ const [sectionGap, setSectionGap] = useState11(null);
14786
+ const [toolbarShowEditLink, setToolbarShowEditLink] = useState11(false);
14787
+ const hoveredNavContainerRef = useRef9(null);
14788
+ const [hoveredNavContainerRect, setHoveredNavContainerRect] = useState11(null);
14789
+ const hoveredItemElRef = useRef9(null);
14790
+ const [hoveredItemRect, setHoveredItemRect] = useState11(null);
14791
+ const [hoveredTextRect, setHoveredTextRect] = useState11(null);
14792
+ useEffect12(() => {
15754
14793
  const sync = () => {
15755
14794
  const el = document.querySelector(
15756
14795
  '[data-ohw-hovered]:not([contenteditable]):not([data-ohw-href-key]):not([data-ohw-editable="form"] *)'
@@ -15771,56 +14810,43 @@ function OhhwellsBridge() {
15771
14810
  });
15772
14811
  return () => observer.disconnect();
15773
14812
  }, []);
15774
- const siblingHintElRef = useRef10(null);
15775
- const [siblingHintRect, setSiblingHintRect] = useState12(null);
15776
- const [siblingHintRects, setSiblingHintRects] = useState12([]);
15777
- const [isItemDragging, setIsItemDragging] = useState12(false);
15778
- const [isFooterFrameSelection, setIsFooterFrameSelection] = useState12(false);
14813
+ const siblingHintElRef = useRef9(null);
14814
+ const [siblingHintRect, setSiblingHintRect] = useState11(null);
14815
+ const [siblingHintRects, setSiblingHintRects] = useState11([]);
14816
+ const [isItemDragging, setIsItemDragging] = useState11(false);
14817
+ const [isFooterFrameSelection, setIsFooterFrameSelection] = useState11(false);
15779
14818
  isFooterFrameSelectionRef.current = isFooterFrameSelection;
15780
- const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = useState12(null);
15781
- const [footerHeadingVisible, setFooterHeadingVisible] = useState12(null);
15782
- const footerDragRef = useRef10(null);
15783
- const [footerDropSlots, setFooterDropSlots] = useState12([]);
15784
- const [activeFooterDropIndex, setActiveFooterDropIndex] = useState12(null);
15785
- const [draggedItemRect, setDraggedItemRect] = useState12(null);
15786
- const footerPointerDragRef = useRef10(null);
15787
- const suppressNextClickRef = useRef10(false);
15788
- const suppressClickUntilRef = useRef10(0);
15789
- const [linkPopover, setLinkPopover] = useState12(null);
15790
- const linkPopoverSessionRef = useRef10(null);
15791
- const addNavAfterAnchorRef = useRef10(null);
15792
- const editContentRef = useRef10({});
15793
- const aiSectionsRef = useRef10("");
15794
- const brandKitRef = useRef10("");
15795
- const stylesRef = useRef10("");
15796
- const pendingDeleteUndoRef = useRef10(null);
15797
- const [floatingPanel, setFloatingPanel] = useState12(null);
15798
- const floatingPanelOpenRef = useRef10(false);
15799
- const setFloatingPanelRef = useRef10(setFloatingPanel);
15800
- const [floatingPanelPos, setFloatingPanelPos] = useState12(null);
15801
- const [logoSizeDraft, setLogoSizeDraft] = useState12(null);
15802
- const [editorViewport, setEditorViewport] = useState12("desktop");
15803
- const [parentScrollSnap, setParentScrollSnap] = useState12(null);
15804
- const [sitePages, setSitePages] = useState12([]);
15805
- const [sectionsByPath, setSectionsByPath] = useState12({});
15806
- const sectionsPrefetchGenRef = useRef10(0);
15807
- const setLinkPopoverRef = useRef10(setLinkPopover);
15808
- const linkPopoverPanelRef = useRef10(null);
15809
- const linkPopoverOpenRef = useRef10(false);
15810
- const linkPopoverGraceUntilRef = useRef10(0);
14819
+ const [floatingPanel, setFloatingPanel] = useState11(null);
14820
+ const floatingPanelOpenRef = useRef9(false);
14821
+ floatingPanelOpenRef.current = floatingPanel !== null;
14822
+ const [floatingPanelPos, setFloatingPanelPos] = useState11(null);
14823
+ const [logoSizeDraft, setLogoSizeDraft] = useState11(null);
14824
+ const [editorViewport, setEditorViewport] = useState11("desktop");
14825
+ const [parentScrollSnap, setParentScrollSnap] = useState11(null);
14826
+ const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = useState11(null);
14827
+ const [footerHeadingVisible, setFooterHeadingVisible] = useState11(null);
14828
+ const footerDragRef = useRef9(null);
14829
+ const [footerDropSlots, setFooterDropSlots] = useState11([]);
14830
+ const [activeFooterDropIndex, setActiveFooterDropIndex] = useState11(null);
14831
+ const [draggedItemRect, setDraggedItemRect] = useState11(null);
14832
+ const footerPointerDragRef = useRef9(null);
14833
+ const suppressNextClickRef = useRef9(false);
14834
+ const suppressClickUntilRef = useRef9(0);
14835
+ const [linkPopover, setLinkPopover] = useState11(null);
14836
+ const linkPopoverSessionRef = useRef9(null);
14837
+ const addNavAfterAnchorRef = useRef9(null);
14838
+ const editContentRef = useRef9({});
14839
+ const aiSectionsRef = useRef9("");
14840
+ const pendingDeleteUndoRef = useRef9(null);
14841
+ const [sitePages, setSitePages] = useState11([]);
14842
+ const [sectionsByPath, setSectionsByPath] = useState11({});
14843
+ const sectionsPrefetchGenRef = useRef9(0);
14844
+ const setLinkPopoverRef = useRef9(setLinkPopover);
14845
+ const linkPopoverPanelRef = useRef9(null);
14846
+ const linkPopoverOpenRef = useRef9(false);
14847
+ const linkPopoverGraceUntilRef = useRef9(0);
15811
14848
  setLinkPopoverRef.current = setLinkPopover;
15812
- setFloatingPanelRef.current = setFloatingPanel;
15813
14849
  linkPopoverSessionRef.current = linkPopover;
15814
- floatingPanelOpenRef.current = Boolean(floatingPanel);
15815
- useEffect13(() => {
15816
- const syncViewport = () => {
15817
- const next = window.innerWidth <= 480 ? "mobile" : "desktop";
15818
- setEditorViewport((prev) => prev === next ? prev : next);
15819
- };
15820
- syncViewport();
15821
- window.addEventListener("resize", syncViewport);
15822
- return () => window.removeEventListener("resize", syncViewport);
15823
- }, []);
15824
14850
  const {
15825
14851
  navDragRef,
15826
14852
  navDropSlots,
@@ -15853,20 +14879,10 @@ function OhhwellsBridge() {
15853
14879
  getNavigationItemAnchor,
15854
14880
  isDragHandleDisabled
15855
14881
  });
15856
- const { sectionDropSlots, activeSectionDropIndex, isSectionDragging } = useSectionDrag({
15857
- isEditMode,
15858
- editContentRef,
15859
- postToParentRef,
15860
- parentScrollRef,
15861
- navDragRef,
15862
- footerDragRef,
15863
- suppressNextClickRef,
15864
- suppressClickUntilRef
15865
- });
15866
14882
  const bumpLinkPopoverGrace = () => {
15867
14883
  linkPopoverGraceUntilRef.current = Date.now() + 350;
15868
14884
  };
15869
- const runSectionsPrefetch = useCallback8((pages) => {
14885
+ const runSectionsPrefetch = useCallback7((pages) => {
15870
14886
  if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
15871
14887
  const gen = ++sectionsPrefetchGenRef.current;
15872
14888
  const paths = pages.map((p) => p.path);
@@ -15885,9 +14901,9 @@ function OhhwellsBridge() {
15885
14901
  );
15886
14902
  });
15887
14903
  }, [isEditMode, pathname]);
15888
- const runSectionsPrefetchRef = useRef10(runSectionsPrefetch);
14904
+ const runSectionsPrefetchRef = useRef9(runSectionsPrefetch);
15889
14905
  runSectionsPrefetchRef.current = runSectionsPrefetch;
15890
- useEffect13(() => {
14906
+ useEffect12(() => {
15891
14907
  if (!linkPopover) {
15892
14908
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
15893
14909
  return;
@@ -15915,7 +14931,7 @@ function OhhwellsBridge() {
15915
14931
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
15916
14932
  };
15917
14933
  }, [linkPopover, postToParent2]);
15918
- useEffect13(() => {
14934
+ useEffect12(() => {
15919
14935
  if (!isEditMode) return;
15920
14936
  const useFixtures = shouldUseDevFixtures();
15921
14937
  if (useFixtures) {
@@ -15939,14 +14955,14 @@ function OhhwellsBridge() {
15939
14955
  if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
15940
14956
  return () => window.removeEventListener("message", onSitePages);
15941
14957
  }, [isEditMode, postToParent2]);
15942
- useEffect13(() => {
14958
+ useEffect12(() => {
15943
14959
  if (!isEditMode || shouldUseDevFixtures()) return;
15944
14960
  void loadAllSectionsManifest().then((manifest) => {
15945
14961
  if (Object.keys(manifest).length === 0) return;
15946
14962
  setSectionsByPath((prev) => ({ ...manifest, ...prev }));
15947
14963
  });
15948
14964
  }, [isEditMode]);
15949
- useEffect13(() => {
14965
+ useEffect12(() => {
15950
14966
  const update = () => {
15951
14967
  const el = activeElRef.current ?? selectedElRef.current;
15952
14968
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
@@ -15970,10 +14986,10 @@ function OhhwellsBridge() {
15970
14986
  vvp.removeEventListener("resize", update);
15971
14987
  };
15972
14988
  }, []);
15973
- const refreshStateRules = useCallback8(() => {
14989
+ const refreshStateRules = useCallback7(() => {
15974
14990
  editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
15975
14991
  }, []);
15976
- const processConfigRequest = useCallback8((insertAfterVal) => {
14992
+ const processConfigRequest = useCallback7((insertAfterVal) => {
15977
14993
  const tracker = getSectionsTracker();
15978
14994
  let entries = [];
15979
14995
  try {
@@ -15996,7 +15012,7 @@ function OhhwellsBridge() {
15996
15012
  }
15997
15013
  window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
15998
15014
  }, [isEditMode]);
15999
- const deactivate = useCallback8(() => {
15015
+ const deactivate = useCallback7(() => {
16000
15016
  const el = activeElRef.current;
16001
15017
  if (!el) return;
16002
15018
  const isFormBlock = el.dataset.ohwEditable === "form";
@@ -16037,12 +15053,12 @@ function OhhwellsBridge() {
16037
15053
  setToolbarShowEditLink(false);
16038
15054
  postToParent2({ type: "ow:exit-edit" });
16039
15055
  }, [postToParent2]);
16040
- const clearSelectedAttr = useCallback8(() => {
15056
+ const clearSelectedAttr = useCallback7(() => {
16041
15057
  document.querySelectorAll("[data-ohw-selected]").forEach((el) => {
16042
15058
  el.removeAttribute("data-ohw-selected");
16043
15059
  });
16044
15060
  }, []);
16045
- const deselect = useCallback8(() => {
15061
+ const deselect = useCallback7(() => {
16046
15062
  clearSelectedAttr();
16047
15063
  selectedElRef.current = null;
16048
15064
  selectedHrefKeyRef.current = null;
@@ -16071,12 +15087,11 @@ function OhhwellsBridge() {
16071
15087
  setToolbarVariant("none");
16072
15088
  }
16073
15089
  }, [clearSelectedAttr]);
16074
- const markSelected = useCallback8((el) => {
15090
+ const markSelected = useCallback7((el) => {
16075
15091
  clearSelectedAttr();
16076
- el.removeAttribute("data-ohw-hovered");
16077
15092
  el.setAttribute("data-ohw-selected", "");
16078
15093
  }, [clearSelectedAttr]);
16079
- const resolveHrefKeyElement = useCallback8((hrefKey) => {
15094
+ const resolveHrefKeyElement = useCallback7((hrefKey) => {
16080
15095
  if (isFooterHrefKey(hrefKey)) {
16081
15096
  return document.querySelector(
16082
15097
  `footer [data-ohw-href-key="${CSS.escape(hrefKey)}"]`
@@ -16091,7 +15106,7 @@ function OhhwellsBridge() {
16091
15106
  `[data-ohw-href-key="${CSS.escape(hrefKey)}"]`
16092
15107
  );
16093
15108
  }, []);
16094
- const resyncSelectedNavigationItem = useCallback8(() => {
15109
+ const resyncSelectedNavigationItem = useCallback7(() => {
16095
15110
  const hrefKey = selectedHrefKeyRef.current;
16096
15111
  if (hrefKey) {
16097
15112
  const link = resolveHrefKeyElement(hrefKey);
@@ -16129,7 +15144,7 @@ function OhhwellsBridge() {
16129
15144
  );
16130
15145
  }
16131
15146
  }, [resolveHrefKeyElement]);
16132
- const reselectNavigationItem = useCallback8((navAnchor) => {
15147
+ const reselectNavigationItem = useCallback7((navAnchor) => {
16133
15148
  selectedElRef.current = navAnchor;
16134
15149
  selectedHrefKeyRef.current = navAnchor.getAttribute("data-ohw-href-key");
16135
15150
  selectedFooterColAttrRef.current = null;
@@ -16160,7 +15175,7 @@ function OhhwellsBridge() {
16160
15175
  setToolbarShowEditLink(false);
16161
15176
  setActiveCommands(/* @__PURE__ */ new Set());
16162
15177
  }, [markSelected]);
16163
- const commitNavigationTextEdit = useCallback8((navAnchor) => {
15178
+ const commitNavigationTextEdit = useCallback7((navAnchor) => {
16164
15179
  const el = activeElRef.current;
16165
15180
  if (!el) return;
16166
15181
  const key = el.dataset.ohwKey;
@@ -16193,7 +15208,7 @@ function OhhwellsBridge() {
16193
15208
  postToParent2({ type: "ow:exit-edit" });
16194
15209
  reselectNavigationItem(navAnchor);
16195
15210
  }, [postToParent2, reselectNavigationItem]);
16196
- const handleAddTopLevelNavItem = useCallback8(() => {
15211
+ const handleAddTopLevelNavItem = useCallback7(() => {
16197
15212
  const items = listNavbarRootItems();
16198
15213
  addNavAfterAnchorRef.current = items[items.length - 1] ?? null;
16199
15214
  deselectRef.current();
@@ -16205,7 +15220,7 @@ function OhhwellsBridge() {
16205
15220
  intent: "add-nav"
16206
15221
  });
16207
15222
  }, []);
16208
- const maybeWarnNavLinkDropdownConflict = useCallback8(
15223
+ const maybeWarnNavLinkDropdownConflict = useCallback7(
16209
15224
  (anchor) => {
16210
15225
  if (!isNavbarHrefKey(anchor.getAttribute("data-ohw-href-key"))) return;
16211
15226
  if (!navDropdownsOpenOnClick()) return;
@@ -16218,7 +15233,7 @@ function OhhwellsBridge() {
16218
15233
  },
16219
15234
  [postToParent2]
16220
15235
  );
16221
- const handleNavDropdownOpenChange = useCallback8((open) => {
15236
+ const handleNavDropdownOpenChange = useCallback7((open) => {
16222
15237
  const selected = selectedElRef.current;
16223
15238
  if (!selected || !isNavigationItem2(selected)) return;
16224
15239
  setNavGroupForceOpen(selected, open);
@@ -16230,7 +15245,7 @@ function OhhwellsBridge() {
16230
15245
  }
16231
15246
  });
16232
15247
  }, []);
16233
- const handleFooterHeadingVisibleChange = useCallback8(
15248
+ const handleFooterHeadingVisibleChange = useCallback7(
16234
15249
  (visible) => {
16235
15250
  const selected = selectedElRef.current;
16236
15251
  if (!selected || !isFooterFrameSelectionRef.current) return;
@@ -16254,7 +15269,7 @@ function OhhwellsBridge() {
16254
15269
  },
16255
15270
  [postToParent2]
16256
15271
  );
16257
- const enterEditOnNewItem = useCallback8((anchor) => {
15272
+ const enterEditOnNewItem = useCallback7((anchor) => {
16258
15273
  const label = anchor.querySelector('[data-ohw-editable="text"]');
16259
15274
  if (!label) {
16260
15275
  selectRef.current(anchor);
@@ -16263,7 +15278,7 @@ function OhhwellsBridge() {
16263
15278
  setNavGroupForceOpen(anchor, true);
16264
15279
  activateRef.current(label);
16265
15280
  }, []);
16266
- const handleAddChildItem = useCallback8(() => {
15281
+ const handleAddChildItem = useCallback7(() => {
16267
15282
  const selected = selectedElRef.current;
16268
15283
  if (!selected) return;
16269
15284
  const socialsRow = isSocialsRow(selected) ? selected : findSocialsRow(selected);
@@ -16375,7 +15390,7 @@ function OhhwellsBridge() {
16375
15390
  enterEditOnNewItem(result.anchor);
16376
15391
  });
16377
15392
  }, [enterEditOnNewItem, isFooterFrameSelection, maybeWarnNavLinkDropdownConflict, postToParent2]);
16378
- const handleAddFooterColumn = useCallback8(() => {
15393
+ const handleAddFooterColumn = useCallback7(() => {
16379
15394
  if (!canAddFooterColumn()) {
16380
15395
  postToParent2({
16381
15396
  type: "ow:toast",
@@ -16396,7 +15411,7 @@ function OhhwellsBridge() {
16396
15411
  selectRef.current(result.firstLink);
16397
15412
  });
16398
15413
  }, [postToParent2]);
16399
- const clearFooterDragVisuals = useCallback8(() => {
15414
+ const clearFooterDragVisuals = useCallback7(() => {
16400
15415
  footerDragRef.current = null;
16401
15416
  setSiblingHintRects([]);
16402
15417
  setFooterDropSlots([]);
@@ -16405,7 +15420,7 @@ function OhhwellsBridge() {
16405
15420
  setIsItemDragging(false);
16406
15421
  unlockFooterDragInteraction();
16407
15422
  }, []);
16408
- const refreshFooterDragVisuals = useCallback8((session, activeSlot, clientX, clientY) => {
15423
+ const refreshFooterDragVisuals = useCallback7((session, activeSlot, clientX, clientY) => {
16409
15424
  const dragged = session.draggedEl;
16410
15425
  setDraggedItemRect(dragged.getBoundingClientRect());
16411
15426
  if (typeof clientX === "number" && typeof clientY === "number") {
@@ -16437,13 +15452,13 @@ function OhhwellsBridge() {
16437
15452
  const activeIdx = activeSlot ? slots.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
16438
15453
  setActiveFooterDropIndex(activeIdx >= 0 ? activeIdx : null);
16439
15454
  }, []);
16440
- const refreshFooterDragVisualsRef = useRef10(refreshFooterDragVisuals);
15455
+ const refreshFooterDragVisualsRef = useRef9(refreshFooterDragVisuals);
16441
15456
  refreshFooterDragVisualsRef.current = refreshFooterDragVisuals;
16442
- const commitFooterDragRef = useRef10(() => {
15457
+ const commitFooterDragRef = useRef9(() => {
16443
15458
  });
16444
- const beginFooterDragRef = useRef10(() => {
15459
+ const beginFooterDragRef = useRef9(() => {
16445
15460
  });
16446
- const beginFooterDrag = useCallback8(
15461
+ const beginFooterDrag = useCallback7(
16447
15462
  (session) => {
16448
15463
  const rect = session.draggedEl.getBoundingClientRect();
16449
15464
  session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
@@ -16463,7 +15478,7 @@ function OhhwellsBridge() {
16463
15478
  [refreshFooterDragVisuals]
16464
15479
  );
16465
15480
  beginFooterDragRef.current = beginFooterDrag;
16466
- const commitFooterDrag = useCallback8(
15481
+ const commitFooterDrag = useCallback7(
16467
15482
  (clientX, clientY) => {
16468
15483
  const session = footerDragRef.current;
16469
15484
  if (!session) {
@@ -16591,7 +15606,7 @@ function OhhwellsBridge() {
16591
15606
  [clearFooterDragVisuals, resolveHrefKeyElement, resyncSelectedNavigationItem]
16592
15607
  );
16593
15608
  commitFooterDragRef.current = commitFooterDrag;
16594
- const startFooterLinkDrag = useCallback8(
15609
+ const startFooterLinkDrag = useCallback7(
16595
15610
  (anchor, clientX, clientY, wasSelected) => {
16596
15611
  const hrefKey = anchor.getAttribute("data-ohw-href-key");
16597
15612
  if (!hrefKey) return false;
@@ -16627,7 +15642,7 @@ function OhhwellsBridge() {
16627
15642
  },
16628
15643
  [beginFooterDrag]
16629
15644
  );
16630
- const startFooterColumnDrag = useCallback8(
15645
+ const startFooterColumnDrag = useCallback7(
16631
15646
  (columnEl, clientX, clientY, wasSelected) => {
16632
15647
  const columns = listFooterColumns();
16633
15648
  const idx = columns.indexOf(columnEl);
@@ -16647,7 +15662,7 @@ function OhhwellsBridge() {
16647
15662
  },
16648
15663
  [beginFooterDrag]
16649
15664
  );
16650
- const handleItemDragStart = useCallback8(
15665
+ const handleItemDragStart = useCallback7(
16651
15666
  (e) => {
16652
15667
  const selected = selectedElRef.current;
16653
15668
  if (!selected) {
@@ -16667,7 +15682,7 @@ function OhhwellsBridge() {
16667
15682
  },
16668
15683
  [startFooterColumnDrag, startFooterLinkDrag, startNavLinkDrag]
16669
15684
  );
16670
- const handleItemDragEnd = useCallback8(
15685
+ const handleItemDragEnd = useCallback7(
16671
15686
  (e) => {
16672
15687
  if (footerDragRef.current) {
16673
15688
  const x = e?.clientX;
@@ -16693,7 +15708,7 @@ function OhhwellsBridge() {
16693
15708
  },
16694
15709
  [commitFooterDrag, commitNavDrag, navDragRef]
16695
15710
  );
16696
- const handleItemChromePointerDown = useCallback8((e) => {
15711
+ const handleItemChromePointerDown = useCallback7((e) => {
16697
15712
  if (e.button !== 0) return;
16698
15713
  const selected = selectedElRef.current;
16699
15714
  if (!selected) return;
@@ -16724,7 +15739,7 @@ function OhhwellsBridge() {
16724
15739
  }
16725
15740
  if (armNavPressFromChrome(selected, e.clientX, e.clientY, e.pointerId)) return;
16726
15741
  }, [armNavPressFromChrome]);
16727
- const handleItemChromeClick = useCallback8((clientX, clientY) => {
15742
+ const handleItemChromeClick = useCallback7((clientX, clientY) => {
16728
15743
  if (suppressNextClickRef.current || Date.now() < suppressClickUntilRef.current) {
16729
15744
  suppressNextClickRef.current = false;
16730
15745
  return;
@@ -16737,7 +15752,7 @@ function OhhwellsBridge() {
16737
15752
  }, []);
16738
15753
  reselectNavigationItemRef.current = reselectNavigationItem;
16739
15754
  commitNavigationTextEditRef.current = commitNavigationTextEdit;
16740
- const select = useCallback8((anchor) => {
15755
+ const select = useCallback7((anchor) => {
16741
15756
  if (!isNavigationItem2(anchor)) return;
16742
15757
  if (activeElRef.current) deactivate();
16743
15758
  aiSectionApiRef.current?.selectFromElement(anchor);
@@ -16780,7 +15795,7 @@ function OhhwellsBridge() {
16780
15795
  setFloatingPanel(null);
16781
15796
  setLogoSizeDraft(null);
16782
15797
  }, [deactivate, markSelected]);
16783
- const selectFrame = useCallback8((el) => {
15798
+ const selectFrame = useCallback7((el) => {
16784
15799
  if (!isNavigationContainer(el)) return;
16785
15800
  if (activeElRef.current) deactivate();
16786
15801
  aiSectionApiRef.current?.selectFromElement(el);
@@ -16831,7 +15846,7 @@ function OhhwellsBridge() {
16831
15846
  setFloatingPanel(null);
16832
15847
  setLogoSizeDraft(null);
16833
15848
  }, [deactivate, markSelected, postToParent2]);
16834
- const selectLogo = useCallback8(
15849
+ const selectLogo = useCallback7(
16835
15850
  (logoEl) => {
16836
15851
  if (activeElRef.current) deactivate();
16837
15852
  selectedElRef.current = logoEl;
@@ -16860,7 +15875,7 @@ function OhhwellsBridge() {
16860
15875
  },
16861
15876
  [deactivate, markSelected]
16862
15877
  );
16863
- const openLogoSizePanel = useCallback8((logoEl) => {
15878
+ const openLogoSizePanel = useCallback7((logoEl) => {
16864
15879
  const placement = getLogoPlacement(logoEl);
16865
15880
  const draft = readLogoSizeState(editContentRef.current, placement);
16866
15881
  setLogoSizeDraft(draft);
@@ -16873,7 +15888,7 @@ function OhhwellsBridge() {
16873
15888
  placement
16874
15889
  });
16875
15890
  }, []);
16876
- const openSocialsDisplayPanel = useCallback8((row) => {
15891
+ const openSocialsDisplayPanel = useCallback7((row) => {
16877
15892
  setParentScrollSnap(parentScrollRef.current);
16878
15893
  setFloatingPanel({
16879
15894
  key: "socials-display",
@@ -16883,7 +15898,7 @@ function OhhwellsBridge() {
16883
15898
  row
16884
15899
  });
16885
15900
  }, []);
16886
- const changeSocialsDisplay = useCallback8(
15901
+ const changeSocialsDisplay = useCallback7(
16887
15902
  (row, next) => {
16888
15903
  if (next.icon) {
16889
15904
  const missing = socialsMissingIcons(row);
@@ -16906,17 +15921,17 @@ function OhhwellsBridge() {
16906
15921
  },
16907
15922
  []
16908
15923
  );
16909
- const closeFloatingPanelOnly = useCallback8(() => {
15924
+ const closeFloatingPanelOnly = useCallback7(() => {
16910
15925
  setFloatingPanel(null);
16911
15926
  setLogoSizeDraft(null);
16912
15927
  }, []);
16913
15928
  closeFloatingPanelOnlyRef.current = closeFloatingPanelOnly;
16914
- const closeFloatingPanelAndDeselect = useCallback8(() => {
15929
+ const closeFloatingPanelAndDeselect = useCallback7(() => {
16915
15930
  setFloatingPanel(null);
16916
15931
  setLogoSizeDraft(null);
16917
15932
  deselectRef.current();
16918
15933
  }, []);
16919
- useEffect13(() => {
15934
+ useEffect12(() => {
16920
15935
  const session = floatingPanel && floatingPanel.kind === "logo-size" ? floatingPanel : null;
16921
15936
  if (!session || !logoSizeDraft) {
16922
15937
  postToParentRef.current({ type: "ow:logo-size-panel", open: false });
@@ -16935,7 +15950,7 @@ function OhhwellsBridge() {
16935
15950
  max: LOGO_SIZE_MAX
16936
15951
  });
16937
15952
  }, [floatingPanel, logoSizeDraft, editorViewport]);
16938
- const persistLogoSizeDraft = useCallback8(
15953
+ const persistLogoSizeDraft = useCallback7(
16939
15954
  (placement, draft) => {
16940
15955
  const desktopKey = LOGO_SIZE_DESKTOP_KEYS[placement];
16941
15956
  const mobileKey = LOGO_SIZE_MOBILE_KEYS[placement];
@@ -16975,7 +15990,7 @@ function OhhwellsBridge() {
16975
15990
  },
16976
15991
  [postToParent2]
16977
15992
  );
16978
- const activate = useCallback8((el, options) => {
15993
+ const activate = useCallback7((el, options) => {
16979
15994
  if (activeElRef.current === el) return;
16980
15995
  if (isIconEditable(el)) return;
16981
15996
  if (el.hasAttribute("data-ohw-social-label")) return;
@@ -17059,8 +16074,8 @@ function OhhwellsBridge() {
17059
16074
  openLogoSizePanelRef.current = openLogoSizePanel;
17060
16075
  deselectRef.current = deselect;
17061
16076
  closeFloatingPanelOnlyRef.current = closeFloatingPanelOnly;
17062
- const lastSiteWideScopeRef = useRef10(null);
17063
- useEffect13(() => {
16077
+ const lastSiteWideScopeRef = useRef9(null);
16078
+ useEffect12(() => {
17064
16079
  if (!isEditMode) {
17065
16080
  if (lastSiteWideScopeRef.current !== false) {
17066
16081
  lastSiteWideScopeRef.current = false;
@@ -17093,27 +16108,15 @@ function OhhwellsBridge() {
17093
16108
  }
17094
16109
  const applyContent = (content) => {
17095
16110
  const imageLoads = [];
17096
- if (typeof content[BRAND_KIT_KEY] === "string") {
17097
- brandKitRef.current = content[BRAND_KIT_KEY];
17098
- applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
17099
- }
17100
16111
  if (typeof content[AI_SECTIONS_KEY] === "string") {
17101
16112
  aiSectionsRef.current = content[AI_SECTIONS_KEY];
17102
16113
  applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
17103
16114
  }
17104
- if (typeof content[STYLE_STORE_KEY] === "string") {
17105
- stylesRef.current = content[STYLE_STORE_KEY];
17106
- applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
17107
- }
17108
- applyBrandChrome(content);
17109
16115
  for (const [key, val] of Object.entries(content)) {
17110
16116
  if (key === "__ohw_sections") continue;
17111
16117
  if (key === AI_SECTIONS_KEY) continue;
17112
16118
  if (key === LOGO_PLACEHOLDER_KEY) continue;
17113
16119
  if (LOGO_IMAGE_KEYS.includes(key)) continue;
17114
- if (key === BRAND_KIT_KEY) continue;
17115
- if (key === STYLE_STORE_KEY) continue;
17116
- if (BRAND_CHROME_KEYS.has(key)) continue;
17117
16120
  if (applyVideoSettingNode(key, val)) continue;
17118
16121
  if (applyCarouselNode(key, val)) continue;
17119
16122
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -17171,9 +16174,7 @@ function OhhwellsBridge() {
17171
16174
  let cancelled = false;
17172
16175
  setFetchState("loading");
17173
16176
  const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
17174
- const initialPath = pathname;
17175
- fetchedContentPaths.add(`${subdomain}::${initialPath}`);
17176
- fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(initialPath)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
16177
+ fetch(`${apiUrl}/api/public/sites/${subdomain}/content`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
17177
16178
  if (cancelled) return;
17178
16179
  const content = data?.content ?? {};
17179
16180
  contentCache.set(subdomain, content);
@@ -17186,7 +16187,7 @@ function OhhwellsBridge() {
17186
16187
  cancelled = true;
17187
16188
  };
17188
16189
  }, [subdomain, isEditMode]);
17189
- useEffect13(() => {
16190
+ useEffect12(() => {
17190
16191
  if (!isEditMode) return;
17191
16192
  const resolveIndex = (form, clientY) => {
17192
16193
  const wrappers = listFieldWrappers(form).filter((el) => fieldKeyOf(el) !== fieldDragRef.current?.key);
@@ -17227,7 +16228,7 @@ function OhhwellsBridge() {
17227
16228
  window.removeEventListener("drop", onDrop, true);
17228
16229
  };
17229
16230
  }, [buildFieldDropSlots, isEditMode, persistFields, selectField]);
17230
- useEffect13(() => {
16231
+ useEffect12(() => {
17231
16232
  if (!isEditMode) return;
17232
16233
  const mark = () => document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
17233
16234
  markFormFields(form);
@@ -17239,7 +16240,7 @@ function OhhwellsBridge() {
17239
16240
  });
17240
16241
  return () => observer.disconnect();
17241
16242
  }, [isEditMode, fetchState, pathname]);
17242
- useEffect13(() => {
16243
+ useEffect12(() => {
17243
16244
  if (!isEditMode) return;
17244
16245
  let saveTimer = null;
17245
16246
  const onInput = (e) => {
@@ -17261,14 +16262,14 @@ function OhhwellsBridge() {
17261
16262
  document.addEventListener("input", onInput, true);
17262
16263
  return () => document.removeEventListener("input", onInput, true);
17263
16264
  }, [isEditMode, persistFields]);
17264
- useEffect13(() => {
16265
+ useEffect12(() => {
17265
16266
  if (isEditMode || fetchState !== "done") return;
17266
16267
  const content = contentCache.get(subdomain) ?? {};
17267
16268
  document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
17268
16269
  reconcileFieldsFromContent(form, content);
17269
16270
  });
17270
16271
  }, [isEditMode, fetchState, subdomain]);
17271
- useEffect13(() => {
16272
+ useEffect12(() => {
17272
16273
  if (!isEditMode) return;
17273
16274
  const swallow = (e) => {
17274
16275
  const target = e.target;
@@ -17277,12 +16278,12 @@ function OhhwellsBridge() {
17277
16278
  document.addEventListener("submit", swallow, true);
17278
16279
  return () => document.removeEventListener("submit", swallow, true);
17279
16280
  }, [isEditMode]);
17280
- useEffect13(() => {
16281
+ useEffect12(() => {
17281
16282
  if (isEditMode || fetchState !== "done") return;
17282
16283
  const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
17283
16284
  bindPublishedForms(apiUrl, subdomain, contentCache.get(subdomain) ?? {});
17284
16285
  }, [isEditMode, fetchState, subdomain]);
17285
- useEffect13(() => {
16286
+ useEffect12(() => {
17286
16287
  if (!subdomain || isEditMode) return;
17287
16288
  let debounceTimer = null;
17288
16289
  let observer = null;
@@ -17293,21 +16294,10 @@ function OhhwellsBridge() {
17293
16294
  initSectionInstancesFromContent(content, window.location.pathname);
17294
16295
  observer?.disconnect();
17295
16296
  try {
17296
- applyBrandChrome(content);
17297
- if (typeof content[BRAND_KIT_KEY] === "string") {
17298
- applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
17299
- }
17300
- if (typeof content[STYLE_STORE_KEY] === "string") {
17301
- applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
17302
- }
17303
16297
  for (const [key, val] of Object.entries(content)) {
17304
16298
  if (key === "__ohw_sections") continue;
17305
16299
  if (key === LOGO_PLACEHOLDER_KEY) continue;
17306
16300
  if (LOGO_IMAGE_KEYS.includes(key)) continue;
17307
- if (key === BRAND_KIT_KEY) continue;
17308
- if (key === STYLE_STORE_KEY) continue;
17309
- if (key === STYLE_STORE_KEY) continue;
17310
- if (BRAND_CHROME_KEYS.has(key)) continue;
17311
16301
  if (applyVideoSettingNode(key, val)) continue;
17312
16302
  if (applyCarouselNode(key, val)) continue;
17313
16303
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -17350,17 +16340,6 @@ function OhhwellsBridge() {
17350
16340
  debounceTimer = setTimeout(applyFromCache, 150);
17351
16341
  };
17352
16342
  applyFromCache();
17353
- const pathCacheKey = `${subdomain}::${pathname}`;
17354
- if (!fetchedContentPaths.has(pathCacheKey)) {
17355
- fetchedContentPaths.add(pathCacheKey);
17356
- const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
17357
- fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(pathname)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
17358
- if (!data?.content) return;
17359
- contentCache.set(subdomain, data.content);
17360
- applyFromCache();
17361
- }).catch(() => {
17362
- });
17363
- }
17364
16343
  observer = new MutationObserver(scheduleApply);
17365
16344
  observer.observe(document.body, { childList: true, subtree: true });
17366
16345
  return () => {
@@ -17374,10 +16353,10 @@ function OhhwellsBridge() {
17374
16353
  const visible = Boolean(subdomain) && fetchState !== "done";
17375
16354
  el.style.display = visible ? "flex" : "none";
17376
16355
  }, [subdomain, fetchState]);
17377
- useEffect13(() => {
16356
+ useEffect12(() => {
17378
16357
  postToParent2({ type: "ow:navigation", path: pathname });
17379
16358
  }, [pathname, postToParent2]);
17380
- useEffect13(() => {
16359
+ useEffect12(() => {
17381
16360
  if (!isEditMode) return;
17382
16361
  if (linkPopoverSessionRef.current?.intent === "add-nav") return;
17383
16362
  if (document.querySelector("[data-ohw-section-picker]")) return;
@@ -17385,7 +16364,7 @@ function OhhwellsBridge() {
17385
16364
  deselectRef.current();
17386
16365
  deactivateRef.current();
17387
16366
  }, [pathname, isEditMode]);
17388
- useEffect13(() => {
16367
+ useEffect12(() => {
17389
16368
  const contentForNav = () => {
17390
16369
  if (isEditMode) return editContentRef.current;
17391
16370
  if (!subdomain) return {};
@@ -17452,36 +16431,31 @@ function OhhwellsBridge() {
17452
16431
  observer?.disconnect();
17453
16432
  };
17454
16433
  }, [isEditMode, pathname, subdomain, fetchState, resyncSelectedNavigationItem]);
17455
- useEffect13(() => {
16434
+ useEffect12(() => {
17456
16435
  if (!isEditMode) return;
17457
- let lastPosted = 0;
17458
16436
  const measure = () => {
17459
16437
  const h = document.body.scrollHeight;
17460
- if (h > 50 && Math.abs(h - lastPosted) > 1) {
17461
- lastPosted = h;
17462
- postToParent2({ type: "ow:height", height: h });
17463
- }
17464
- };
17465
- let raf = null;
17466
- const schedule = () => {
17467
- if (raf != null) return;
17468
- raf = requestAnimationFrame(() => {
17469
- raf = null;
17470
- measure();
17471
- });
16438
+ if (h > 50) postToParent2({ type: "ow:height", height: h });
17472
16439
  };
17473
16440
  const t1 = setTimeout(measure, 50);
17474
16441
  const t2 = setTimeout(measure, 500);
17475
- const ro = new ResizeObserver(schedule);
17476
- ro.observe(document.body);
16442
+ let lastWidth = window.innerWidth;
16443
+ let resizeTimer = null;
16444
+ const handleResize = () => {
16445
+ if (window.innerWidth === lastWidth) return;
16446
+ lastWidth = window.innerWidth;
16447
+ if (resizeTimer) clearTimeout(resizeTimer);
16448
+ resizeTimer = setTimeout(measure, 150);
16449
+ };
16450
+ window.addEventListener("resize", handleResize);
17477
16451
  return () => {
17478
16452
  clearTimeout(t1);
17479
16453
  clearTimeout(t2);
17480
- if (raf != null) cancelAnimationFrame(raf);
17481
- ro.disconnect();
16454
+ if (resizeTimer) clearTimeout(resizeTimer);
16455
+ window.removeEventListener("resize", handleResize);
17482
16456
  };
17483
16457
  }, [pathname, isEditMode, postToParent2]);
17484
- useEffect13(() => {
16458
+ useEffect12(() => {
17485
16459
  if (!subdomainFromQuery || isEditMode) return;
17486
16460
  const handleClick = (e) => {
17487
16461
  const anchor = e.target.closest("a");
@@ -17497,7 +16471,7 @@ function OhhwellsBridge() {
17497
16471
  document.addEventListener("click", handleClick, true);
17498
16472
  return () => document.removeEventListener("click", handleClick, true);
17499
16473
  }, [subdomainFromQuery, isEditMode, router]);
17500
- useEffect13(() => {
16474
+ useEffect12(() => {
17501
16475
  if (!isEditMode) {
17502
16476
  editStylesRef.current?.base.remove();
17503
16477
  editStylesRef.current?.forceHover.remove();
@@ -17659,21 +16633,16 @@ function OhhwellsBridge() {
17659
16633
  return;
17660
16634
  }
17661
16635
  const target = e.target;
17662
- if (target.closest("[data-ohw-ai-review]")) return;
17663
16636
  if (target.closest("[data-ohw-toolbar]")) return;
17664
16637
  if (target.closest("[data-ohw-state-toggle]")) return;
17665
16638
  if (target.closest("[data-ohw-max-badge]")) return;
17666
16639
  if (isInsideLinkEditor(target)) return;
17667
- if (isInsideFloatingPanel(target)) return;
17668
16640
  if (target.closest("[data-ohw-form-toolbar]")) return;
17669
16641
  if (target.closest(
17670
16642
  '[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
17671
16643
  )) {
17672
16644
  return;
17673
16645
  }
17674
- if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
17675
- clearMediaSelectionRef.current();
17676
- }
17677
16646
  {
17678
16647
  const formEl = getFormElement(target);
17679
16648
  const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
@@ -17821,11 +16790,8 @@ function OhhwellsBridge() {
17821
16790
  if (isMediaEditable(editable) && !buttonOnMedia) {
17822
16791
  e.preventDefault();
17823
16792
  e.stopPropagation();
17824
- if (selectedMediaElRef.current === editable) {
17825
- postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "", elementType: editable.dataset.ohwEditable ?? "image" });
17826
- } else {
17827
- selectMediaElementRef.current(editable);
17828
- }
16793
+ aiSectionApiRef.current?.selectFromElement(editable);
16794
+ postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "", elementType: editable.dataset.ohwEditable ?? "image" });
17829
16795
  return;
17830
16796
  }
17831
16797
  const hrefLookupTarget = buttonOnMedia ? clickedButton : editable;
@@ -17944,12 +16910,10 @@ function OhhwellsBridge() {
17944
16910
  };
17945
16911
  const handleDblClick = (e) => {
17946
16912
  const target = e.target;
17947
- if (target.closest("[data-ohw-ai-review]")) return;
17948
16913
  if (target.closest("[data-ohw-toolbar]")) return;
17949
16914
  if (target.closest("[data-ohw-state-toggle]")) return;
17950
16915
  if (target.closest("[data-ohw-max-badge]")) return;
17951
16916
  if (isInsideLinkEditor(target)) return;
17952
- if (isInsideFloatingPanel(target)) return;
17953
16917
  if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
17954
16918
  return;
17955
16919
  }
@@ -17990,14 +16954,11 @@ function OhhwellsBridge() {
17990
16954
  setSiblingHintRects([]);
17991
16955
  return;
17992
16956
  }
17993
- if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || isInsideFloatingPanel(target) || isPointOverFloatingPanel(e.clientX, e.clientY)) {
16957
+ if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || target.closest("[data-ohw-floating-panel]")) {
17994
16958
  hoveredItemElRef.current = null;
17995
16959
  setHoveredItemRect(null);
17996
16960
  hoveredNavContainerRef.current = null;
17997
16961
  setHoveredNavContainerRect(null);
17998
- siblingHintElRef.current = null;
17999
- setSiblingHintRect(null);
18000
- setSiblingHintRects([]);
18001
16962
  return;
18002
16963
  }
18003
16964
  {
@@ -18015,16 +16976,6 @@ function OhhwellsBridge() {
18015
16976
  return;
18016
16977
  }
18017
16978
  }
18018
- if (allowNavContainerHover) {
18019
- const socialsRow = isSocialsRow(target) ? target : null;
18020
- if (socialsRow && !getSocialItem(target) && selected2 !== socialsRow) {
18021
- hoveredNavContainerRef.current = socialsRow;
18022
- setHoveredNavContainerRect(socialsRow.getBoundingClientRect());
18023
- hoveredItemElRef.current = null;
18024
- setHoveredItemRect(null);
18025
- return;
18026
- }
18027
- }
18028
16979
  if (allowFooterLinksHover) {
18029
16980
  const navContainer = target.closest("[data-ohw-nav-container]");
18030
16981
  if (!navContainer) {
@@ -18110,12 +17061,13 @@ function OhhwellsBridge() {
18110
17061
  clearHrefKeyHover(hoverTarget);
18111
17062
  hoveredItemElRef.current = hoverTarget;
18112
17063
  setHoveredItemRect(hoverTarget.getBoundingClientRect());
18113
- } else if (!isInsideNavigationItem(editable) && hoverTarget !== selectedElRef.current) {
17064
+ } else if (!isInsideNavigationItem(editable)) {
18114
17065
  hoverTarget.setAttribute("data-ohw-hovered", "");
18115
17066
  if (editable.closest("footer") || editable.closest('[data-ohw-section="footer"]')) {
18116
17067
  hoveredNavContainerRef.current = null;
18117
17068
  setHoveredNavContainerRect(null);
18118
17069
  hoveredItemElRef.current = editable;
17070
+ setHoveredItemRect(editable.getBoundingClientRect());
18119
17071
  }
18120
17072
  }
18121
17073
  }
@@ -18412,7 +17364,7 @@ function OhhwellsBridge() {
18412
17364
  }
18413
17365
  };
18414
17366
  const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
18415
- if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
17367
+ if (linkPopoverOpenRef.current) {
18416
17368
  if (hoveredImageRef.current) {
18417
17369
  hoveredImageRef.current = null;
18418
17370
  hoveredImageHasTextOverlapRef.current = false;
@@ -18428,6 +17380,11 @@ function OhhwellsBridge() {
18428
17380
  probeNavigationHoverAt(x, y);
18429
17381
  return;
18430
17382
  }
17383
+ if (isPointOverLogo(x, y)) {
17384
+ dismissImageHover();
17385
+ probeNavigationHoverAt(x, y);
17386
+ return;
17387
+ }
18431
17388
  const overMoreMenu = document.elementFromPoint(x, y)?.closest?.(
18432
17389
  '[data-ohw-more-menu], [data-slot="dropdown-menu-content"], [data-slot="dropdown-menu-item"]'
18433
17390
  );
@@ -18666,7 +17623,7 @@ function OhhwellsBridge() {
18666
17623
  }
18667
17624
  };
18668
17625
  const probeHoverCardsAt = (clientX, clientY, fromParentViewport = false) => {
18669
- if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY) || document.documentElement.hasAttribute("data-ohw-section-picking")) {
17626
+ if (linkPopoverOpenRef.current || document.documentElement.hasAttribute("data-ohw-section-picking")) {
18670
17627
  if (activeStateElRef.current) {
18671
17628
  activeStateElRef.current.removeAttribute("data-ohw-state-hovered");
18672
17629
  activeStateElRef.current = null;
@@ -18703,35 +17660,6 @@ function OhhwellsBridge() {
18703
17660
  }
18704
17661
  }
18705
17662
  };
18706
- const probeSocialsRowAt = (clientX, clientY, fromParentViewport = false) => {
18707
- const wasSocialsRow = Boolean(hoveredNavContainerRef.current?.hasAttribute(SOCIALS_ROW_ATTR));
18708
- const clear = () => {
18709
- if (!wasSocialsRow) return false;
18710
- hoveredNavContainerRef.current = null;
18711
- setHoveredNavContainerRect(null);
18712
- return false;
18713
- };
18714
- if (linkPopoverOpenRef.current || toolbarVariantRef.current === "select-frame") return clear();
18715
- const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
18716
- const SLACK = 6;
18717
- for (const row of Array.from(document.querySelectorAll(`[${SOCIALS_ROW_ATTR}]`))) {
18718
- const rect = row.getBoundingClientRect();
18719
- const inside = x >= rect.left - SLACK && x <= rect.right + SLACK && y >= rect.top - SLACK && y <= rect.bottom + SLACK;
18720
- if (!inside) continue;
18721
- if (selectedElRef.current === row) return clear();
18722
- const overItem = listSocialItems(row).some((item) => {
18723
- const box = item.getBoundingClientRect();
18724
- return x >= box.left && x <= box.right && y >= box.top && y <= box.bottom;
18725
- });
18726
- if (overItem) return clear();
18727
- hoveredNavContainerRef.current = row;
18728
- setHoveredNavContainerRect(rect);
18729
- hoveredItemElRef.current = null;
18730
- setHoveredItemRect(null);
18731
- return true;
18732
- }
18733
- return clear();
18734
- };
18735
17663
  const probeSectionGapAt = (clientX, clientY, fromParentViewport = false) => {
18736
17664
  if (linkPopoverOpenRef.current) {
18737
17665
  if (hoveredGapRef.current) {
@@ -18741,9 +17669,7 @@ function OhhwellsBridge() {
18741
17669
  return;
18742
17670
  }
18743
17671
  const { y } = toProbeCoords(clientX, clientY, fromParentViewport);
18744
- const sections = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
18745
- (el) => !el.hasAttribute("data-ohw-ai-template-hidden") && !el.hasAttribute("data-ohw-ai-removed") && !el.hasAttribute("data-ohw-ai-replaced-by") && el.getBoundingClientRect().height > 0
18746
- ).sort((a, b) => a.getBoundingClientRect().top - b.getBoundingClientRect().top);
17672
+ const sections = Array.from(document.querySelectorAll("[data-ohw-section]")).sort((a, b) => a.getBoundingClientRect().top - b.getBoundingClientRect().top);
18747
17673
  const ZONE = 20;
18748
17674
  for (let i = 0; i < sections.length; i++) {
18749
17675
  const a = sections[i];
@@ -18772,7 +17698,8 @@ function OhhwellsBridge() {
18772
17698
  };
18773
17699
  const handleMouseMove = (e) => {
18774
17700
  const { clientX, clientY } = e;
18775
- if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY) || isOverEditorChrome(clientX, clientY)) {
17701
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
17702
+ if (isOverEditorChrome(clientX, clientY)) {
18776
17703
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
18777
17704
  formHoverElRef.current = null;
18778
17705
  setFormHoverRect(null);
@@ -18780,15 +17707,8 @@ function OhhwellsBridge() {
18780
17707
  setHoveredItemRect(null);
18781
17708
  hoveredNavContainerRef.current = null;
18782
17709
  setHoveredNavContainerRect(null);
18783
- siblingHintElRef.current = null;
18784
- setSiblingHintRect(null);
18785
- setSiblingHintRects([]);
18786
- dismissImageHover();
18787
- clearImageHover();
18788
- setSectionGap(null);
18789
17710
  return;
18790
17711
  }
18791
- if (probeSocialsRowAt(clientX, clientY)) return;
18792
17712
  probeSectionGapAt(clientX, clientY);
18793
17713
  probeImageAt(clientX, clientY);
18794
17714
  probeHoverCardsAt(clientX, clientY);
@@ -18797,12 +17717,7 @@ function OhhwellsBridge() {
18797
17717
  if (e.data?.type !== "ow:pointer-sync") return;
18798
17718
  const { clientX, clientY } = e.data;
18799
17719
  if (typeof clientX !== "number" || typeof clientY !== "number") return;
18800
- if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
18801
- dismissImageHover();
18802
- clearImageHover();
18803
- return;
18804
- }
18805
- if (probeSocialsRowAt(clientX, clientY)) return;
17720
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
18806
17721
  probeSectionGapAt(clientX, clientY);
18807
17722
  probeImageAt(clientX, clientY);
18808
17723
  probeHoverCardsAt(clientX, clientY);
@@ -19048,19 +17963,10 @@ function OhhwellsBridge() {
19048
17963
  if (e.data?.type !== "ow:hydrate") return;
19049
17964
  const content = e.data.content;
19050
17965
  if (!content) return;
19051
- if (typeof content[BRAND_KIT_KEY] === "string") {
19052
- brandKitRef.current = content[BRAND_KIT_KEY];
19053
- applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
19054
- }
19055
17966
  if (typeof content[AI_SECTIONS_KEY] === "string") {
19056
17967
  aiSectionsRef.current = content[AI_SECTIONS_KEY];
19057
17968
  applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
19058
17969
  }
19059
- if (typeof content[STYLE_STORE_KEY] === "string") {
19060
- stylesRef.current = content[STYLE_STORE_KEY];
19061
- applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
19062
- }
19063
- applyBrandChrome(content);
19064
17970
  let sectionsJson = null;
19065
17971
  for (const [key, val] of Object.entries(content)) {
19066
17972
  if (key === "__ohw_sections") {
@@ -19070,9 +17976,6 @@ function OhhwellsBridge() {
19070
17976
  if (key === AI_SECTIONS_KEY) continue;
19071
17977
  if (key === LOGO_PLACEHOLDER_KEY) continue;
19072
17978
  if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
19073
- if (key === BRAND_KIT_KEY) continue;
19074
- if (key === STYLE_STORE_KEY) continue;
19075
- if (BRAND_CHROME_KEYS.has(key)) continue;
19076
17979
  if (applyVideoSettingNode(key, val)) continue;
19077
17980
  if (applyCarouselNode(key, val)) continue;
19078
17981
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -19169,21 +18072,12 @@ function OhhwellsBridge() {
19169
18072
  nodes: collectEditableNodes(editContentRef.current)
19170
18073
  });
19171
18074
  };
19172
- const clearInteractionChrome = () => {
19173
- deactivateRef.current();
19174
- deselectRef.current();
19175
- clearMediaSelectionRef.current();
19176
- };
19177
18075
  const handleAiApplyTree = (e) => {
19178
18076
  if (e.data?.type !== "ow:ai-apply-tree") return;
19179
18077
  const payload = e.data.payload;
19180
18078
  if (!payload || typeof payload.id !== "string" || !isRenderableTree(payload.tree)) return;
19181
- clearInteractionChrome();
19182
18079
  const previous = aiSectionsRef.current;
19183
- const nextState = applyTreeToState(parseAiSectionsState(previous), {
19184
- ...payload,
19185
- path: payload.path ?? window.location.pathname
19186
- });
18080
+ const nextState = applyTreeToState(parseAiSectionsState(previous), payload);
19187
18081
  const nextValue = serializeAiSectionsState(nextState);
19188
18082
  aiSectionsRef.current = nextValue;
19189
18083
  applyAiSectionsToDom(nextState);
@@ -19203,7 +18097,6 @@ function OhhwellsBridge() {
19203
18097
  if (!sectionId || sectionId === "navbar" || sectionId === "footer") return;
19204
18098
  const exists = document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`);
19205
18099
  if (!exists) return;
19206
- clearInteractionChrome();
19207
18100
  const previous = aiSectionsRef.current;
19208
18101
  const nextState = deleteSectionFromState(parseAiSectionsState(previous), sectionId);
19209
18102
  const nextValue = serializeAiSectionsState(nextState);
@@ -19219,58 +18112,14 @@ function OhhwellsBridge() {
19219
18112
  const handleAiSetSections = (e) => {
19220
18113
  if (e.data?.type !== "ow:ai-set-sections") return;
19221
18114
  const value = typeof e.data.value === "string" ? e.data.value : "";
19222
- clearInteractionChrome();
19223
18115
  aiSectionsRef.current = value;
19224
18116
  applyAiSectionsToDom(parseAiSectionsState(value));
19225
- applyStylesToDom(parseStyleStore(stylesRef.current));
19226
18117
  const restoredHeight = document.documentElement.scrollHeight;
19227
18118
  if (restoredHeight > 50) postToParentRef.current({ type: "ow:height", height: restoredHeight });
19228
18119
  postToParentRef.current({ type: "ow:change", nodes: [{ key: AI_SECTIONS_KEY, text: value }] });
19229
18120
  postAiSectionsChanged();
19230
18121
  };
19231
18122
  window.addEventListener("message", handleAiSetSections);
19232
- const handleMoveSection = (e) => {
19233
- if (e.data?.type !== "ow:move-section") return;
19234
- const instanceId = typeof e.data.instanceId === "string" ? e.data.instanceId : "";
19235
- const direction = e.data.direction === "up" || e.data.direction === "down" ? e.data.direction : null;
19236
- if (!instanceId || !direction) return;
19237
- const entries = moveSectionInstance(instanceId, direction, window.location.pathname);
19238
- if (!entries) return;
19239
- const orderJson = JSON.stringify(entries);
19240
- editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
19241
- postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
19242
- window.dispatchEvent(new Event("resize"));
19243
- };
19244
- window.addEventListener("message", handleMoveSection);
19245
- const handleAiSetBrand = (e) => {
19246
- if (e.data?.type !== "ow:ai-set-brand") return;
19247
- const value = typeof e.data.value === "string" ? e.data.value : "";
19248
- const previous = brandKitRef.current;
19249
- brandKitRef.current = value;
19250
- applyBrandToDom(parseBrandKit(value));
19251
- if (aiSectionsRef.current) applyAiSectionsToDom(parseAiSectionsState(aiSectionsRef.current));
19252
- applyStylesToDom(parseStyleStore(stylesRef.current));
19253
- postToParentRef.current({ type: "ow:change", nodes: [{ key: BRAND_KIT_KEY, text: value }] });
19254
- postToParentRef.current({ type: "ow:ai-brand-applied", previous, value });
19255
- };
19256
- window.addEventListener("message", handleAiSetBrand);
19257
- const handleAiSetStyles = (e) => {
19258
- if (e.data?.type !== "ow:ai-set-styles") return;
19259
- const value = typeof e.data.value === "string" ? e.data.value : "";
19260
- const previous = stylesRef.current;
19261
- stylesRef.current = value;
19262
- applyStylesToDom(parseStyleStore(value));
19263
- postToParentRef.current({ type: "ow:change", nodes: [{ key: STYLE_STORE_KEY, text: value }] });
19264
- postToParentRef.current({ type: "ow:ai-styles-applied", previous, value });
19265
- };
19266
- window.addEventListener("message", handleAiSetStyles);
19267
- const handleGetBrand = (e) => {
19268
- if (e.data?.type !== "ow:get-brand") return;
19269
- const template = deriveTemplateBrand();
19270
- const value = brandKitRef.current || (template ? JSON.stringify(template) : "");
19271
- postToParentRef.current({ type: "ow:brand-value", value });
19272
- };
19273
- window.addEventListener("message", handleGetBrand);
19274
18123
  const handlePanelDragging = (e) => {
19275
18124
  if (e.data?.type !== "ow:panel-dragging") return;
19276
18125
  if (e.data.dragging) document.documentElement.setAttribute("data-ohw-panel-dragging", "");
@@ -19286,12 +18135,6 @@ function OhhwellsBridge() {
19286
18135
  closeLinkPopoverRef.current();
19287
18136
  return;
19288
18137
  }
19289
- if (floatingPanelOpenRef.current) {
19290
- setFloatingPanelRef.current(null);
19291
- deselectRef.current();
19292
- deactivateRef.current();
19293
- return;
19294
- }
19295
18138
  deselectRef.current();
19296
18139
  deactivateRef.current();
19297
18140
  };
@@ -19379,10 +18222,6 @@ function OhhwellsBridge() {
19379
18222
  const handleKeyDown = (e) => {
19380
18223
  if (e.key === "Escape" && document.querySelector("[data-ohw-section-picker]")) return;
19381
18224
  if (e.key === "Escape" && document.querySelector("[data-ohw-more-menu]")) return;
19382
- if (e.key === "Escape" && selectedMediaElRef.current) {
19383
- clearMediaSelectionRef.current();
19384
- return;
19385
- }
19386
18225
  if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a" && activeElRef.current) {
19387
18226
  e.preventDefault();
19388
18227
  selectAllTextInEditable(activeElRef.current);
@@ -19542,12 +18381,6 @@ function OhhwellsBridge() {
19542
18381
  if (aiSectionsRef.current) {
19543
18382
  nodes.push({ key: AI_SECTIONS_KEY, type: "sections", text: aiSectionsRef.current });
19544
18383
  }
19545
- if (stylesRef.current) {
19546
- nodes.push({ key: STYLE_STORE_KEY, type: "styles", text: stylesRef.current });
19547
- }
19548
- if (brandKitRef.current) {
19549
- nodes.push({ key: BRAND_KIT_KEY, type: "brand", text: brandKitRef.current });
19550
- }
19551
18384
  document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
19552
18385
  const formKey = formKeyOf(form);
19553
18386
  if (!formKey) return;
@@ -19565,12 +18398,8 @@ function OhhwellsBridge() {
19565
18398
  if (inserted) {
19566
18399
  const tracker = getSectionsTracker();
19567
18400
  postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
19568
- const reportHeight = () => {
19569
- const h = document.body.scrollHeight;
19570
- if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
19571
- };
19572
- reportHeight();
19573
- setTimeout(reportHeight, 500);
18401
+ const h = document.documentElement.scrollHeight;
18402
+ if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
19574
18403
  }
19575
18404
  };
19576
18405
  const handleSwitchSchedule = (e) => {
@@ -19957,23 +18786,19 @@ function OhhwellsBridge() {
19957
18786
  window.removeEventListener("message", handleAiApplyTree);
19958
18787
  window.removeEventListener("message", handleAiDeleteSection);
19959
18788
  window.removeEventListener("message", handleAiSetSections);
19960
- window.removeEventListener("message", handleMoveSection);
19961
- window.removeEventListener("message", handleAiSetBrand);
19962
- window.removeEventListener("message", handleAiSetStyles);
19963
- window.removeEventListener("message", handleGetBrand);
19964
18789
  window.removeEventListener("message", handlePanelDragging);
19965
18790
  window.removeEventListener("message", handleDeactivate);
18791
+ document.documentElement.removeAttribute("data-ohw-panel-dragging");
19966
18792
  window.removeEventListener("message", handleToastAction);
19967
18793
  window.removeEventListener("message", handleFormCount);
19968
18794
  window.removeEventListener("message", handleUiEscape);
19969
- document.documentElement.removeAttribute("data-ohw-panel-dragging");
19970
18795
  autoSaveTimers.current.forEach(clearTimeout);
19971
18796
  autoSaveTimers.current.clear();
19972
18797
  if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
19973
18798
  if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
19974
18799
  };
19975
18800
  }, [isEditMode, refreshStateRules]);
19976
- useEffect13(() => {
18801
+ useEffect12(() => {
19977
18802
  if (!isEditMode) return;
19978
18803
  const THRESHOLD = 10;
19979
18804
  const resolveWasSelected = (el) => {
@@ -20129,7 +18954,7 @@ function OhhwellsBridge() {
20129
18954
  unlockFooterDragInteraction();
20130
18955
  };
20131
18956
  }, [isEditMode]);
20132
- useEffect13(() => {
18957
+ useEffect12(() => {
20133
18958
  const handler = (e) => {
20134
18959
  if (e.data?.type !== "ow:request-schedule-config") return;
20135
18960
  const insertAfterVal = e.data.insertAfter;
@@ -20145,7 +18970,7 @@ function OhhwellsBridge() {
20145
18970
  window.addEventListener("message", handler);
20146
18971
  return () => window.removeEventListener("message", handler);
20147
18972
  }, [processConfigRequest]);
20148
- useEffect13(() => {
18973
+ useEffect12(() => {
20149
18974
  if (!isEditMode) return;
20150
18975
  document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
20151
18976
  el.removeAttribute("data-ohw-active-state");
@@ -20169,7 +18994,7 @@ function OhhwellsBridge() {
20169
18994
  postToParent2({
20170
18995
  type: "ow:ready",
20171
18996
  version: "1",
20172
- bridgeVersion: "0.1.68",
18997
+ bridgeVersion: "0.1.67",
20173
18998
  path: pathname,
20174
18999
  nodes: collectEditableNodes(editContentRef.current),
20175
19000
  sections
@@ -20181,13 +19006,13 @@ function OhhwellsBridge() {
20181
19006
  clearTimeout(timer);
20182
19007
  };
20183
19008
  }, [pathname, isEditMode, refreshStateRules, postToParent2]);
20184
- useEffect13(() => {
19009
+ useEffect12(() => {
20185
19010
  scrollToHashSectionWhenReady();
20186
19011
  const onHashChange = () => scrollToHashSectionWhenReady();
20187
19012
  window.addEventListener("hashchange", onHashChange);
20188
19013
  return () => window.removeEventListener("hashchange", onHashChange);
20189
19014
  }, [pathname]);
20190
- const handleCommand = useCallback8((cmd) => {
19015
+ const handleCommand = useCallback7((cmd) => {
20191
19016
  const el = activeElRef.current;
20192
19017
  const selBefore = window.getSelection();
20193
19018
  let savedOffsets = null;
@@ -20223,7 +19048,7 @@ function OhhwellsBridge() {
20223
19048
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
20224
19049
  refreshActiveCommandsRef.current();
20225
19050
  }, []);
20226
- useEffect13(() => {
19051
+ useEffect12(() => {
20227
19052
  const session = floatingPanel && floatingPanel.kind === "logo-size" ? floatingPanel : null;
20228
19053
  if (!session || !logoSizeDraft) return;
20229
19054
  const onPanelAction = (e) => {
@@ -20261,7 +19086,7 @@ function OhhwellsBridge() {
20261
19086
  window.addEventListener("message", onPanelAction);
20262
19087
  return () => window.removeEventListener("message", onPanelAction);
20263
19088
  }, [floatingPanel, logoSizeDraft, editorViewport, persistLogoSizeDraft, closeFloatingPanelAndDeselect]);
20264
- const handleStateChange = useCallback8((state) => {
19089
+ const handleStateChange = useCallback7((state) => {
20265
19090
  if (!activeStateElRef.current) return;
20266
19091
  const el = activeStateElRef.current;
20267
19092
  if (state === "Default") {
@@ -20274,7 +19099,7 @@ function OhhwellsBridge() {
20274
19099
  }
20275
19100
  setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
20276
19101
  }, [deactivate]);
20277
- const reselectAfterLinkPopover = useCallback8(
19102
+ const reselectAfterLinkPopover = useCallback7(
20278
19103
  (hrefKey) => {
20279
19104
  requestAnimationFrame(() => {
20280
19105
  const el = resolveHrefKeyElement(hrefKey);
@@ -20283,7 +19108,7 @@ function OhhwellsBridge() {
20283
19108
  },
20284
19109
  [resolveHrefKeyElement]
20285
19110
  );
20286
- const closeLinkPopover = useCallback8(() => {
19111
+ const closeLinkPopover = useCallback7(() => {
20287
19112
  const session = linkPopoverSessionRef.current;
20288
19113
  addNavAfterAnchorRef.current = null;
20289
19114
  setLinkPopover(null);
@@ -20291,9 +19116,9 @@ function OhhwellsBridge() {
20291
19116
  reselectAfterLinkPopover(session.key);
20292
19117
  }
20293
19118
  }, [reselectAfterLinkPopover]);
20294
- const closeLinkPopoverRef = useRef10(closeLinkPopover);
19119
+ const closeLinkPopoverRef = useRef9(closeLinkPopover);
20295
19120
  closeLinkPopoverRef.current = closeLinkPopover;
20296
- const openLinkPopoverForActive = useCallback8(() => {
19121
+ const openLinkPopoverForActive = useCallback7(() => {
20297
19122
  const hrefCtx = getHrefKeyFromElement(activeElRef.current);
20298
19123
  if (!hrefCtx) return;
20299
19124
  bumpLinkPopoverGrace();
@@ -20304,7 +19129,7 @@ function OhhwellsBridge() {
20304
19129
  });
20305
19130
  deactivate();
20306
19131
  }, [deactivate]);
20307
- const openLinkPopoverForSelected = useCallback8(() => {
19132
+ const openLinkPopoverForSelected = useCallback7(() => {
20308
19133
  const anchor = selectedElRef.current;
20309
19134
  if (!anchor) return;
20310
19135
  const key = anchor.getAttribute("data-ohw-href-key");
@@ -20321,7 +19146,7 @@ function OhhwellsBridge() {
20321
19146
  });
20322
19147
  deselect();
20323
19148
  }, [deselect]);
20324
- const handleSelectParent = useCallback8(() => {
19149
+ const handleSelectParent = useCallback7(() => {
20325
19150
  const selected = selectedElRef.current;
20326
19151
  if (!selected) return;
20327
19152
  if (toolbarVariantRef.current === "select-frame") {
@@ -20348,7 +19173,7 @@ function OhhwellsBridge() {
20348
19173
  }
20349
19174
  deselectRef.current();
20350
19175
  }, []);
20351
- const handleDuplicateSelected = useCallback8(() => {
19176
+ const handleDuplicateSelected = useCallback7(() => {
20352
19177
  const selected = selectedElRef.current;
20353
19178
  if (!selected || !isNavigationItem2(selected)) return;
20354
19179
  const hrefKey = selected.getAttribute("data-ohw-href-key");
@@ -20464,7 +19289,7 @@ function OhhwellsBridge() {
20464
19289
  });
20465
19290
  }
20466
19291
  }, [postToParent2]);
20467
- const runPendingDeleteUndo = useCallback8(() => {
19292
+ const runPendingDeleteUndo = useCallback7(() => {
20468
19293
  const pending = pendingDeleteUndoRef.current;
20469
19294
  if (!pending) return false;
20470
19295
  pendingDeleteUndoRef.current = null;
@@ -20472,7 +19297,7 @@ function OhhwellsBridge() {
20472
19297
  enforceLinkHrefs();
20473
19298
  return true;
20474
19299
  }, []);
20475
- const handleDeleteSelected = useCallback8(() => {
19300
+ const handleDeleteSelected = useCallback7(() => {
20476
19301
  const selected = selectedElRef.current;
20477
19302
  if (!selected) return false;
20478
19303
  return deleteSelectedNavFooterItem({
@@ -20493,7 +19318,7 @@ function OhhwellsBridge() {
20493
19318
  }, [postToParent2]);
20494
19319
  handleDeleteSelectedRef.current = handleDeleteSelected;
20495
19320
  runPendingDeleteUndoRef.current = runPendingDeleteUndo;
20496
- const handleLinkPopoverSubmit = useCallback8(
19321
+ const handleLinkPopoverSubmit = useCallback7(
20497
19322
  (target) => {
20498
19323
  const session = linkPopoverSessionRef.current;
20499
19324
  if (!session) return;
@@ -20559,30 +19384,19 @@ function OhhwellsBridge() {
20559
19384
  const showEditLink = toolbarShowEditLink;
20560
19385
  const currentSections = sectionsByPath[pathname] ?? [];
20561
19386
  linkPopoverOpenRef.current = linkPopover !== null;
20562
- const handleMediaSelect = useCallback8((key) => {
20563
- const el = hoveredImageRef.current?.dataset.ohwKey === key ? hoveredImageRef.current : Array.from(document.querySelectorAll(MEDIA_SELECTOR)).find(
20564
- (m) => (m.dataset.ohwKey ?? "") === key
20565
- ) ?? null;
20566
- if (!el) return;
20567
- selectMediaElementRef.current(el);
20568
- }, []);
20569
- const handleMediaReplace = useCallback8(
19387
+ const handleMediaReplace = useCallback7(
20570
19388
  (key) => {
20571
- postToParent2({
20572
- type: "ow:image-pick",
20573
- key,
20574
- elementType: mediaHover?.elementType ?? selectedMedia?.elementType ?? "image"
20575
- });
19389
+ postToParent2({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
20576
19390
  },
20577
- [postToParent2, mediaHover?.elementType, selectedMedia?.elementType]
19391
+ [postToParent2, mediaHover?.elementType]
20578
19392
  );
20579
- const handleEditCarousel = useCallback8(
19393
+ const handleEditCarousel = useCallback7(
20580
19394
  (key) => {
20581
19395
  postToParent2({ type: "ow:carousel-open", key, images: readCarouselValue(key) });
20582
19396
  },
20583
19397
  [postToParent2]
20584
19398
  );
20585
- const handleMediaFadeOutComplete = useCallback8((key) => {
19399
+ const handleMediaFadeOutComplete = useCallback7((key) => {
20586
19400
  setUploadingRects((prev) => {
20587
19401
  if (!(key in prev)) return prev;
20588
19402
  const next = { ...prev };
@@ -20590,7 +19404,7 @@ function OhhwellsBridge() {
20590
19404
  return next;
20591
19405
  });
20592
19406
  }, []);
20593
- const handleVideoSettingsChange = useCallback8(
19407
+ const handleVideoSettingsChange = useCallback7(
20594
19408
  (key, settings) => {
20595
19409
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
20596
19410
  const video = getVideoEl2(el);
@@ -20612,506 +19426,420 @@ function OhhwellsBridge() {
20612
19426
  },
20613
19427
  [postToParent2]
20614
19428
  );
20615
- return /* @__PURE__ */ jsxs20(Fragment8, { children: [
20616
- /* @__PURE__ */ jsx33("div", { id: "ohw-loader", suppressHydrationWarning: true, style: { ...OHW_LOADER_STYLE, display: "none" }, children: /* @__PURE__ */ jsx33(OhwLoaderSpinner, {}) }),
20617
- /* @__PURE__ */ jsx33("script", { suppressHydrationWarning: true, dangerouslySetInnerHTML: { __html: OHW_LOADER_PREHYDRATE_SCRIPT } }),
20618
- bridgeRoot ? createPortal2(
20619
- /* @__PURE__ */ jsxs20(Fragment8, { children: [
20620
- /* @__PURE__ */ jsx33("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
20621
- isEditMode && /* @__PURE__ */ jsx33(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
20622
- isSectionDragging && sectionDropSlots.map((slot, i) => /* @__PURE__ */ jsx33(
20623
- "div",
20624
- {
20625
- className: "pointer-events-none fixed z-2147483646",
20626
- style: { left: slot.left, top: slot.y, width: slot.width, height: 3, transform: "translateY(-50%)" },
20627
- children: /* @__PURE__ */ jsx33(
20628
- DropIndicator,
20629
- {
20630
- direction: "horizontal",
20631
- state: activeSectionDropIndex === i ? "dragActive" : "dragIdle",
20632
- className: "!h-full !w-full"
20633
- }
20634
- )
20635
- },
20636
- `section-drop-${slot.insertIndex}-${i}`
20637
- )),
20638
- Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ jsx33(
20639
- MediaOverlay,
20640
- {
20641
- hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
20642
- isUploading: true,
20643
- fadingOut,
20644
- onFadeOutComplete: handleMediaFadeOutComplete,
20645
- onReplace: handleMediaReplace
20646
- },
20647
- `uploading-${key}`
20648
- )),
20649
- mediaHover && !(mediaHover.key in uploadingRects) && mediaHover.key !== selectedMedia?.key && /* @__PURE__ */ jsx33(
20650
- MediaOverlay,
20651
- {
20652
- hover: mediaHover,
20653
- isUploading: false,
20654
- onReplace: handleMediaReplace,
20655
- onSelect: handleMediaSelect,
20656
- onVideoSettingsChange: handleVideoSettingsChange
20657
- }
20658
- ),
20659
- selectedMedia && !(selectedMedia.key in uploadingRects) && !linkPopover && /* @__PURE__ */ jsx33(
20660
- MediaOverlay,
20661
- {
20662
- hover: selectedMedia,
20663
- selected: true,
20664
- hovered: mediaHover?.key === selectedMedia.key,
20665
- isUploading: false,
20666
- onReplace: handleMediaReplace,
20667
- onSelect: handleMediaSelect,
20668
- onVideoSettingsChange: handleVideoSettingsChange
20669
- }
20670
- ),
20671
- carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx33(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
20672
- siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
20673
- siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
20674
- isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
20675
- isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ jsx33(
20676
- "div",
20677
- {
20678
- className: "pointer-events-none fixed z-2147483646",
20679
- style: {
20680
- left: slot.left,
20681
- top: slot.top,
20682
- width: slot.width,
20683
- height: slot.height
20684
- },
20685
- children: /* @__PURE__ */ jsx33(
20686
- DropIndicator,
20687
- {
20688
- direction: slot.direction,
20689
- state: activeFooterDropIndex === i ? "dragActive" : "dragIdle",
20690
- className: "!h-full !w-full"
20691
- }
20692
- )
20693
- },
20694
- `footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
20695
- )),
20696
- isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ jsx33(
20697
- "div",
20698
- {
20699
- className: "pointer-events-none fixed z-2147483646",
20700
- style: {
20701
- left: slot.left,
20702
- top: slot.top,
20703
- width: slot.width,
20704
- height: slot.height
20705
- },
20706
- children: /* @__PURE__ */ jsx33(
20707
- DropIndicator,
20708
- {
20709
- direction: slot.direction,
20710
- state: activeNavDropIndex === i ? "dragActive" : "dragIdle",
20711
- className: "!h-full !w-full"
20712
- }
20713
- )
19429
+ return bridgeRoot ? createPortal2(
19430
+ /* @__PURE__ */ jsxs20(Fragment8, { children: [
19431
+ /* @__PURE__ */ jsx33("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
19432
+ isEditMode && /* @__PURE__ */ jsx33(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
19433
+ Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ jsx33(
19434
+ MediaOverlay,
19435
+ {
19436
+ hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
19437
+ isUploading: true,
19438
+ fadingOut,
19439
+ onFadeOutComplete: handleMediaFadeOutComplete,
19440
+ onReplace: handleMediaReplace
19441
+ },
19442
+ `uploading-${key}`
19443
+ )),
19444
+ mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ jsx33(
19445
+ MediaOverlay,
19446
+ {
19447
+ hover: mediaHover,
19448
+ isUploading: false,
19449
+ onReplace: handleMediaReplace,
19450
+ onVideoSettingsChange: handleVideoSettingsChange
19451
+ }
19452
+ ),
19453
+ carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx33(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
19454
+ siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
19455
+ siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
19456
+ isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
19457
+ isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ jsx33(
19458
+ "div",
19459
+ {
19460
+ className: "pointer-events-none fixed z-2147483646",
19461
+ style: {
19462
+ left: slot.left,
19463
+ top: slot.top,
19464
+ width: slot.width,
19465
+ height: slot.height
20714
19466
  },
20715
- `nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
20716
- )),
20717
- hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
20718
- hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
20719
- hoveredTextRect && !hoveredNavContainerRect && !hoveredItemRect && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: hoveredTextRect, state: "hover" }),
20720
- formPickRect && !isItemDragging && /* @__PURE__ */ jsx33(
20721
- ItemInteractionLayer,
20722
- {
20723
- rect: formPickRect,
20724
- state: "active-top",
20725
- itemDragSurface: false,
20726
- toolbarAlign: "left",
20727
- chromeGap: 24,
20728
- toolbar: fieldPickRect ? void 0 : /* @__PURE__ */ jsxs20(
20729
- "div",
20730
- {
20731
- "data-ohw-form-toolbar": "",
20732
- className: "pointer-events-auto flex items-center gap-0.5 whitespace-nowrap rounded-lg border border-border bg-background p-1 shadow-md",
20733
- children: [
20734
- /* @__PURE__ */ jsx33(
20735
- "button",
20736
- {
20737
- type: "button",
20738
- "aria-label": "Add field",
20739
- className: "flex h-7 w-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted/80",
20740
- onClick: () => setFieldTypePickerOpen((open) => !open),
20741
- "data-ohw-add-field": "",
20742
- children: /* @__PURE__ */ jsx33(Plus4, { size: 15, "aria-hidden": true })
20743
- }
20744
- ),
20745
- /* @__PURE__ */ jsx33("div", { className: "mx-0.5 h-5 w-px bg-border" }),
20746
- /* @__PURE__ */ jsxs20(
20747
- "button",
20748
- {
20749
- type: "button",
20750
- 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",
20751
- onClick: () => {
20752
- const form = formPickElRef.current;
20753
- if (!form) return;
20754
- postToParent2({
20755
- type: "ow:form-pick",
20756
- formKey: formKeyOf(form),
20757
- hasLongText: formHasLongText(form)
20758
- });
20759
- },
20760
- children: [
20761
- /* @__PURE__ */ jsx33(Settings, { size: 14, "aria-hidden": true }),
20762
- "Form settings",
20763
- formPickCount ? (
20764
- // Counter pill, per the design — not a text suffix.
20765
- /* @__PURE__ */ jsx33(
20766
- "span",
20767
- {
20768
- "data-ohw-form-count": "",
20769
- 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",
20770
- children: formPickCount
20771
- }
20772
- )
20773
- ) : null
20774
- ]
20775
- }
20776
- ),
20777
- /* @__PURE__ */ jsx33("div", { className: "mx-0.5 h-5 w-px bg-border" }),
20778
- /* @__PURE__ */ jsx33("div", { className: "flex items-center rounded-md bg-muted/70 p-0.5", children: ["default", "success"].map((state) => /* @__PURE__ */ jsx33(
20779
- "button",
20780
- {
20781
- type: "button",
20782
- "aria-pressed": formViewState === state,
20783
- 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"),
20784
- onClick: () => {
20785
- const form = formPickElRef.current;
20786
- const key = form ? formKeyOf(form) : null;
20787
- if (!form || !key) return;
20788
- const initial = successInitialFor(form, key, editContentRef.current);
20789
- setFormViewState(form, key, state, initial);
20790
- setFormViewStateUi(state);
20791
- setFormPickRect(form.getBoundingClientRect());
20792
- if (state === "success") {
20793
- const successEl = form.querySelector(`[${SUCCESS_TEXT_ATTR}]`);
20794
- if (successEl) requestAnimationFrame(() => activateRef.current(successEl));
20795
- } else {
20796
- deactivateRef.current();
20797
- }
20798
- },
20799
- children: state
20800
- },
20801
- state
20802
- )) })
20803
- ]
20804
- }
20805
- )
20806
- }
20807
- ),
20808
- formHoverRect && !isItemDragging && /* @__PURE__ */ jsx33(
20809
- ItemInteractionLayer,
20810
- {
20811
- rect: formHoverRect,
20812
- state: "hover",
20813
- chromeGap: formHoverElRef.current && getFieldWrapper(formHoverElRef.current) ? 8 : 24
20814
- }
20815
- ),
20816
- fieldPickRect && fieldPickState && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ jsx33(
20817
- ItemInteractionLayer,
20818
- {
20819
- rect: fieldPickRect,
20820
- state: fieldDragging ? "dragging" : "active-top",
20821
- itemDragSurface: false,
20822
- toolbarAlign: "left",
20823
- chromeGap: 10,
20824
- showHandle: true,
20825
- dragHandleLabel: "Reorder field",
20826
- onDragHandleDragStart: handleFieldDragStart,
20827
- onDragHandleDragEnd: handleFieldDragEnd,
20828
- toolbar: /* @__PURE__ */ jsx33(
20829
- FormFieldToolbar,
20830
- {
20831
- type: fieldPickState.type,
20832
- required: fieldPickState.required,
20833
- onTypeChange: handleFieldTypeChange,
20834
- onRequiredToggle: handleFieldRequiredToggle,
20835
- onDuplicate: handleFieldDuplicate,
20836
- onDelete: handleFieldDelete
20837
- }
20838
- )
20839
- }
20840
- ),
20841
- fieldDragging ? fieldDropSlots.map((slot, i) => /* @__PURE__ */ jsx33(
20842
- "div",
20843
- {
20844
- className: "pointer-events-none fixed z-[2147483644]",
20845
- style: { top: slot.top, left: slot.left, width: slot.width },
20846
- children: /* @__PURE__ */ jsx33(
20847
- DropIndicator,
20848
- {
20849
- direction: "horizontal",
20850
- state: fieldDropIndex === i ? "dragActive" : "dragIdle",
20851
- className: "!w-full"
20852
- }
20853
- )
19467
+ children: /* @__PURE__ */ jsx33(
19468
+ DropIndicator,
19469
+ {
19470
+ direction: slot.direction,
19471
+ state: activeFooterDropIndex === i ? "dragActive" : "dragIdle",
19472
+ className: "!h-full !w-full"
19473
+ }
19474
+ )
19475
+ },
19476
+ `footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
19477
+ )),
19478
+ isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ jsx33(
19479
+ "div",
19480
+ {
19481
+ className: "pointer-events-none fixed z-2147483646",
19482
+ style: {
19483
+ left: slot.left,
19484
+ top: slot.top,
19485
+ width: slot.width,
19486
+ height: slot.height
20854
19487
  },
20855
- `field-drop-${i}`
20856
- )) : null,
20857
- fieldTypePickerOpen && formPickRect ? (() => {
20858
- const toolbar = document.querySelector("[data-ohw-form-toolbar]")?.getBoundingClientRect();
20859
- return /* @__PURE__ */ jsx33(
20860
- "div",
19488
+ children: /* @__PURE__ */ jsx33(
19489
+ DropIndicator,
20861
19490
  {
20862
- className: "pointer-events-none fixed z-[2147483645]",
20863
- style: {
20864
- top: toolbar ? toolbar.bottom + 6 : formPickRect.top + 16,
20865
- left: toolbar ? toolbar.left : formPickRect.left + 24
20866
- },
20867
- children: /* @__PURE__ */ jsx33(FieldTypePicker, { onPick: handleAddField })
19491
+ direction: slot.direction,
19492
+ state: activeNavDropIndex === i ? "dragActive" : "dragIdle",
19493
+ className: "!h-full !w-full"
20868
19494
  }
20869
- );
20870
- })() : null,
20871
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ jsx33(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
20872
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ jsx33(
20873
- FooterContainerChrome,
20874
- {
20875
- rect: toolbarRect,
20876
- onAdd: handleAddFooterColumn,
20877
- addDisabled: !canAddFooterColumn()
20878
- }
20879
- ),
20880
- toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame" || toolbarVariant === "logo") && /* @__PURE__ */ jsx33(
20881
- ItemInteractionLayer,
20882
- {
20883
- rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
20884
- toolbarBelowRect: selectedElRef.current && isNavigationItem2(selectedElRef.current) ? getOpenNavDropdownPanelRect(selectedElRef.current) : null,
20885
- elRef: glowElRef,
20886
- state: isItemDragging ? "dragging" : selectedElRef.current && isNavigationItem2(selectedElRef.current) && getOpenNavDropdownPanelRect(selectedElRef.current) ? "active-bottom" : resolveItemInteractionState(toolbarRect, parentScrollRef.current),
20887
- showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey) || toolbarVariant === "select-frame" && isFooterFrameSelection,
20888
- dragDisabled: reorderDragDisabled,
20889
- dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
20890
- onDragHandleDragStart: handleItemDragStart,
20891
- onDragHandleDragEnd: handleItemDragEnd,
20892
- onItemPointerDown: toolbarVariant === "logo" ? void 0 : handleItemChromePointerDown,
20893
- onItemClick: toolbarVariant === "logo" ? void 0 : handleItemChromeClick,
20894
- itemDragSurface: toolbarVariant !== "logo" && !isFooterFrameSelection,
20895
- toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && (isFooterFrameSelection || selectedIsSocialsRow) && !isItemDragging ? /* @__PURE__ */ jsx33(
20896
- ItemActionToolbar,
20897
- {
20898
- onEditLink: openLinkPopoverForSelected,
20899
- onStyle: () => {
20900
- const row = selectedElRef.current;
20901
- if (!row) return;
20902
- if (floatingPanel?.kind === "socials-display") closeFloatingPanelOnly();
20903
- else openSocialsDisplayPanel(row);
20904
- },
20905
- showStyle: selectedIsSocialsRow,
20906
- styleActive: floatingPanel?.kind === "socials-display",
20907
- onAddItem: handleAddChildItem,
20908
- onSelectParent: handleSelectParent,
20909
- onDuplicate: handleDuplicateSelected,
20910
- onDelete: handleDeleteSelected,
20911
- addItemDisabled: isFooterFrameSelection && isFooterAddItemDisabled(selectedElRef.current) || selectedElRef.current !== null && (() => {
20912
- const row = isSocialsRow(selectedElRef.current) ? selectedElRef.current : findSocialsRow(selectedElRef.current);
20913
- return row ? !canAddSocialItem(row) : false;
20914
- })(),
20915
- editLinkDisabled: false,
20916
- moreDisabled: false,
20917
- duplicateDisabled: isFooterFrameSelection || selectedIsSocialsRow,
20918
- showEditLink: !isFooterFrameSelection && !selectedIsSocialsRow && navDropdownPreviewOpen === null,
20919
- showAddItem: isFooterFrameSelection || selectedIsSocialsRow || !selectedIsCta && Boolean(
20920
- selectedElRef.current && isNavbarHrefKey(selectedElRef.current.getAttribute("data-ohw-href-key")) && !isNestedNavChild(selectedElRef.current)
19495
+ )
19496
+ },
19497
+ `nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
19498
+ )),
19499
+ hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
19500
+ hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
19501
+ hoveredTextRect && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: hoveredTextRect, state: "hover" }),
19502
+ formPickRect && !isItemDragging && /* @__PURE__ */ jsx33(
19503
+ ItemInteractionLayer,
19504
+ {
19505
+ rect: formPickRect,
19506
+ state: "active-top",
19507
+ itemDragSurface: false,
19508
+ toolbarAlign: "left",
19509
+ chromeGap: 24,
19510
+ toolbar: fieldPickRect ? void 0 : /* @__PURE__ */ jsxs20(
19511
+ "div",
19512
+ {
19513
+ "data-ohw-form-toolbar": "",
19514
+ className: "pointer-events-auto flex items-center gap-0.5 whitespace-nowrap rounded-lg border border-border bg-background p-1 shadow-md",
19515
+ children: [
19516
+ /* @__PURE__ */ jsx33(
19517
+ "button",
19518
+ {
19519
+ type: "button",
19520
+ "aria-label": "Add field",
19521
+ className: "flex h-7 w-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted/80",
19522
+ onClick: () => setFieldTypePickerOpen((open) => !open),
19523
+ "data-ohw-add-field": "",
19524
+ children: /* @__PURE__ */ jsx33(Plus4, { size: 15, "aria-hidden": true })
19525
+ }
20921
19526
  ),
20922
- showMore: (!selectedIsCta || isFooterFrameSelection) && !selectedIsSocialsRow,
20923
- dropdownOpen: navDropdownPreviewOpen,
20924
- onDropdownOpenChange: handleNavDropdownOpenChange,
20925
- headingVisible: footerHeadingVisible,
20926
- onHeadingVisibleChange: handleFooterHeadingVisibleChange
20927
- }
20928
- ) : void 0
20929
- }
20930
- ),
20931
- toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ jsxs20(Fragment8, { children: [
20932
- /* @__PURE__ */ jsx33(
20933
- EditGlowChrome,
19527
+ /* @__PURE__ */ jsx33("div", { className: "mx-0.5 h-5 w-px bg-border" }),
19528
+ /* @__PURE__ */ jsxs20(
19529
+ "button",
19530
+ {
19531
+ type: "button",
19532
+ 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",
19533
+ onClick: () => {
19534
+ const form = formPickElRef.current;
19535
+ if (!form) return;
19536
+ postToParent2({
19537
+ type: "ow:form-pick",
19538
+ formKey: formKeyOf(form),
19539
+ hasLongText: formHasLongText(form)
19540
+ });
19541
+ },
19542
+ children: [
19543
+ /* @__PURE__ */ jsx33(Settings, { size: 14, "aria-hidden": true }),
19544
+ "Form settings",
19545
+ formPickCount ? (
19546
+ // Counter pill, per the design — not a text suffix.
19547
+ /* @__PURE__ */ jsx33(
19548
+ "span",
19549
+ {
19550
+ "data-ohw-form-count": "",
19551
+ 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",
19552
+ children: formPickCount
19553
+ }
19554
+ )
19555
+ ) : null
19556
+ ]
19557
+ }
19558
+ ),
19559
+ /* @__PURE__ */ jsx33("div", { className: "mx-0.5 h-5 w-px bg-border" }),
19560
+ /* @__PURE__ */ jsx33("div", { className: "flex items-center rounded-md bg-muted/70 p-0.5", children: ["default", "success"].map((state) => /* @__PURE__ */ jsx33(
19561
+ "button",
19562
+ {
19563
+ type: "button",
19564
+ "aria-pressed": formViewState === state,
19565
+ 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"),
19566
+ onClick: () => {
19567
+ const form = formPickElRef.current;
19568
+ const key = form ? formKeyOf(form) : null;
19569
+ if (!form || !key) return;
19570
+ const initial = successInitialFor(form, key, editContentRef.current);
19571
+ setFormViewState(form, key, state, initial);
19572
+ setFormViewStateUi(state);
19573
+ setFormPickRect(form.getBoundingClientRect());
19574
+ if (state === "success") {
19575
+ const successEl = form.querySelector(`[${SUCCESS_TEXT_ATTR}]`);
19576
+ if (successEl) requestAnimationFrame(() => activateRef.current(successEl));
19577
+ } else {
19578
+ deactivateRef.current();
19579
+ }
19580
+ },
19581
+ children: state
19582
+ },
19583
+ state
19584
+ )) })
19585
+ ]
19586
+ }
19587
+ )
19588
+ }
19589
+ ),
19590
+ formHoverRect && !isItemDragging && /* @__PURE__ */ jsx33(
19591
+ ItemInteractionLayer,
19592
+ {
19593
+ rect: formHoverRect,
19594
+ state: "hover",
19595
+ chromeGap: formHoverElRef.current && getFieldWrapper(formHoverElRef.current) ? 8 : 24
19596
+ }
19597
+ ),
19598
+ fieldPickRect && fieldPickState && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ jsx33(
19599
+ ItemInteractionLayer,
19600
+ {
19601
+ rect: fieldPickRect,
19602
+ state: fieldDragging ? "dragging" : "active-top",
19603
+ itemDragSurface: false,
19604
+ toolbarAlign: "left",
19605
+ chromeGap: 10,
19606
+ showHandle: true,
19607
+ dragHandleLabel: "Reorder field",
19608
+ onDragHandleDragStart: handleFieldDragStart,
19609
+ onDragHandleDragEnd: handleFieldDragEnd,
19610
+ toolbar: /* @__PURE__ */ jsx33(
19611
+ FormFieldToolbar,
20934
19612
  {
20935
- rect: toolbarRect,
20936
- elRef: glowElRef,
20937
- reorderHrefKey,
20938
- dragDisabled: reorderDragDisabled,
20939
- hideHandle: isItemDragging
19613
+ type: fieldPickState.type,
19614
+ required: fieldPickState.required,
19615
+ onTypeChange: handleFieldTypeChange,
19616
+ onRequiredToggle: handleFieldRequiredToggle,
19617
+ onDuplicate: handleFieldDuplicate,
19618
+ onDelete: handleFieldDelete
20940
19619
  }
20941
- ),
20942
- /* @__PURE__ */ jsx33(
20943
- FloatingToolbar,
19620
+ )
19621
+ }
19622
+ ),
19623
+ fieldDragging ? fieldDropSlots.map((slot, i) => /* @__PURE__ */ jsx33(
19624
+ "div",
19625
+ {
19626
+ className: "pointer-events-none fixed z-[2147483644]",
19627
+ style: { top: slot.top, left: slot.left, width: slot.width },
19628
+ children: /* @__PURE__ */ jsx33(
19629
+ DropIndicator,
20944
19630
  {
20945
- rect: toolbarRect,
20946
- parentScroll: parentScrollRef.current,
20947
- elRef: toolbarElRef,
20948
- onCommand: handleCommand,
20949
- activeCommands,
20950
- showEditLink,
20951
- onEditLink: openLinkPopoverForActive
19631
+ direction: "horizontal",
19632
+ state: fieldDropIndex === i ? "dragActive" : "dragIdle",
19633
+ className: "!w-full"
20952
19634
  }
20953
19635
  )
20954
- ] }),
20955
- maxBadge && /* @__PURE__ */ jsxs20(
19636
+ },
19637
+ `field-drop-${i}`
19638
+ )) : null,
19639
+ fieldTypePickerOpen && formPickRect ? (() => {
19640
+ const toolbar = document.querySelector("[data-ohw-form-toolbar]")?.getBoundingClientRect();
19641
+ return /* @__PURE__ */ jsx33(
20956
19642
  "div",
20957
19643
  {
20958
- "data-ohw-max-badge": "",
19644
+ className: "pointer-events-none fixed z-[2147483645]",
20959
19645
  style: {
20960
- position: "fixed",
20961
- top: maxBadge.rect.bottom + 4,
20962
- left: maxBadge.rect.right,
20963
- transform: "translateX(-100%)",
20964
- zIndex: 2147483647,
20965
- background: maxBadge.current > maxBadge.max ? "#FEF2F2" : "#F5F5F4",
20966
- color: maxBadge.current > maxBadge.max ? "#DC2626" : "#78716C",
20967
- border: `1px solid ${maxBadge.current > maxBadge.max ? "#FECACA" : "#E7E5E4"}`,
20968
- borderRadius: 4,
20969
- padding: "2px 6px",
20970
- fontSize: 11,
20971
- fontWeight: 500,
20972
- pointerEvents: "none"
19646
+ top: toolbar ? toolbar.bottom + 6 : formPickRect.top + 16,
19647
+ left: toolbar ? toolbar.left : formPickRect.left + 24
20973
19648
  },
20974
- children: [
20975
- maxBadge.current,
20976
- "/",
20977
- maxBadge.max
20978
- ]
19649
+ children: /* @__PURE__ */ jsx33(FieldTypePicker, { onPick: handleAddField })
20979
19650
  }
20980
- ),
20981
- toggleState && !linkPopover && /* @__PURE__ */ jsx33(
20982
- StateToggle,
19651
+ );
19652
+ })() : null,
19653
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ jsx33(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
19654
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ jsx33(
19655
+ FooterContainerChrome,
19656
+ {
19657
+ rect: toolbarRect,
19658
+ onAdd: handleAddFooterColumn,
19659
+ addDisabled: !canAddFooterColumn()
19660
+ }
19661
+ ),
19662
+ toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame" || toolbarVariant === "logo") && /* @__PURE__ */ jsx33(
19663
+ ItemInteractionLayer,
19664
+ {
19665
+ rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
19666
+ toolbarBelowRect: selectedElRef.current && isNavigationItem2(selectedElRef.current) ? getOpenNavDropdownPanelRect(selectedElRef.current) : null,
19667
+ elRef: glowElRef,
19668
+ state: isItemDragging ? "dragging" : selectedElRef.current && isNavigationItem2(selectedElRef.current) && getOpenNavDropdownPanelRect(selectedElRef.current) ? "active-bottom" : resolveItemInteractionState(toolbarRect, parentScrollRef.current),
19669
+ showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey) || toolbarVariant === "select-frame" && isFooterFrameSelection,
19670
+ dragDisabled: reorderDragDisabled,
19671
+ dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
19672
+ onDragHandleDragStart: handleItemDragStart,
19673
+ onDragHandleDragEnd: handleItemDragEnd,
19674
+ onItemPointerDown: toolbarVariant === "logo" ? void 0 : handleItemChromePointerDown,
19675
+ onItemClick: toolbarVariant === "logo" ? void 0 : handleItemChromeClick,
19676
+ itemDragSurface: toolbarVariant !== "logo" && !isFooterFrameSelection,
19677
+ toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && (isFooterFrameSelection || selectedIsSocialsRow) && !isItemDragging ? /* @__PURE__ */ jsx33(
19678
+ ItemActionToolbar,
19679
+ {
19680
+ onEditLink: openLinkPopoverForSelected,
19681
+ onStyle: () => {
19682
+ const row = selectedElRef.current;
19683
+ if (!row) return;
19684
+ if (floatingPanel?.kind === "socials-display") closeFloatingPanelOnly();
19685
+ else openSocialsDisplayPanel(row);
19686
+ },
19687
+ showStyle: selectedIsSocialsRow,
19688
+ styleActive: floatingPanel?.kind === "socials-display",
19689
+ onAddItem: handleAddChildItem,
19690
+ onSelectParent: handleSelectParent,
19691
+ onDuplicate: handleDuplicateSelected,
19692
+ onDelete: handleDeleteSelected,
19693
+ addItemDisabled: isFooterFrameSelection && isFooterAddItemDisabled(selectedElRef.current) || selectedElRef.current !== null && (() => {
19694
+ const row = isSocialsRow(selectedElRef.current) ? selectedElRef.current : findSocialsRow(selectedElRef.current);
19695
+ return row ? !canAddSocialItem(row) : false;
19696
+ })(),
19697
+ editLinkDisabled: false,
19698
+ moreDisabled: false,
19699
+ duplicateDisabled: isFooterFrameSelection || selectedIsSocialsRow,
19700
+ showEditLink: !isFooterFrameSelection && !selectedIsSocialsRow && navDropdownPreviewOpen === null,
19701
+ showAddItem: isFooterFrameSelection || selectedIsSocialsRow || !selectedIsCta && Boolean(
19702
+ selectedElRef.current && isNavbarHrefKey(selectedElRef.current.getAttribute("data-ohw-href-key")) && !isNestedNavChild(selectedElRef.current)
19703
+ ),
19704
+ showMore: (!selectedIsCta || isFooterFrameSelection) && !selectedIsSocialsRow,
19705
+ dropdownOpen: navDropdownPreviewOpen,
19706
+ onDropdownOpenChange: handleNavDropdownOpenChange,
19707
+ headingVisible: footerHeadingVisible,
19708
+ onHeadingVisibleChange: handleFooterHeadingVisibleChange
19709
+ }
19710
+ ) : void 0
19711
+ }
19712
+ ),
19713
+ toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ jsxs20(Fragment8, { children: [
19714
+ /* @__PURE__ */ jsx33(
19715
+ EditGlowChrome,
20983
19716
  {
20984
- rect: toggleState.rect,
20985
- activeState: toggleState.activeState,
20986
- states: toggleState.states,
20987
- onStateChange: handleStateChange
19717
+ rect: toolbarRect,
19718
+ elRef: glowElRef,
19719
+ reorderHrefKey,
19720
+ dragDisabled: reorderDragDisabled,
19721
+ hideHandle: isItemDragging
20988
19722
  }
20989
19723
  ),
20990
- sectionGap && !linkPopover && /* @__PURE__ */ jsxs20(
20991
- "div",
19724
+ /* @__PURE__ */ jsx33(
19725
+ FloatingToolbar,
20992
19726
  {
20993
- "data-ohw-section-insert-line": "",
20994
- className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
20995
- style: { top: sectionGap.y, transform: "translateY(-50%)" },
20996
- children: [
20997
- /* @__PURE__ */ jsx33("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
20998
- /* @__PURE__ */ jsx33(
20999
- Badge,
21000
- {
21001
- 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",
21002
- onClick: () => {
21003
- window.parent.postMessage(
21004
- {
21005
- type: "ow:add-section",
21006
- insertAfter: sectionGap.insertAfter,
21007
- insertBefore: sectionGap.insertBefore
21008
- },
21009
- "*"
21010
- );
21011
- },
21012
- children: "Add Section"
21013
- }
21014
- ),
21015
- /* @__PURE__ */ jsx33("div", { className: "flex-1 bg-primary", style: { height: 3 } })
21016
- ]
19727
+ rect: toolbarRect,
19728
+ parentScroll: parentScrollRef.current,
19729
+ elRef: toolbarElRef,
19730
+ onCommand: handleCommand,
19731
+ activeCommands,
19732
+ showEditLink,
19733
+ onEditLink: openLinkPopoverForActive
21017
19734
  }
21018
- ),
21019
- linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx33(
21020
- LinkPopover,
21021
- {
21022
- panelRef: linkPopoverPanelRef,
21023
- portalContainer: dialogPortalContainer,
21024
- open: true,
21025
- mode: linkPopover.mode ?? "edit",
21026
- pages: sitePages,
21027
- sections: currentSections,
21028
- sectionsByPath,
21029
- initialTarget: linkPopover.target,
21030
- existingTargets: linkPopover.intent === "add-nav" ? getNavbarExistingTargets() : [],
21031
- onClose: closeLinkPopover,
21032
- onSubmit: handleLinkPopoverSubmit
19735
+ )
19736
+ ] }),
19737
+ maxBadge && /* @__PURE__ */ jsxs20(
19738
+ "div",
19739
+ {
19740
+ "data-ohw-max-badge": "",
19741
+ style: {
19742
+ position: "fixed",
19743
+ top: maxBadge.rect.bottom + 4,
19744
+ left: maxBadge.rect.right,
19745
+ transform: "translateX(-100%)",
19746
+ zIndex: 2147483647,
19747
+ background: maxBadge.current > maxBadge.max ? "#FEF2F2" : "#F5F5F4",
19748
+ color: maxBadge.current > maxBadge.max ? "#DC2626" : "#78716C",
19749
+ border: `1px solid ${maxBadge.current > maxBadge.max ? "#FECACA" : "#E7E5E4"}`,
19750
+ borderRadius: 4,
19751
+ padding: "2px 6px",
19752
+ fontSize: 11,
19753
+ fontWeight: 500,
19754
+ pointerEvents: "none"
21033
19755
  },
21034
- linkPopover.key
21035
- ) : null,
21036
- floatingPanel && floatingPanel.kind === "socials-display" ? /* @__PURE__ */ jsx33(
21037
- FloatingPanel,
21038
- {
21039
- open: true,
21040
- title: floatingPanel.title,
21041
- context: floatingPanel.context,
21042
- position: floatingPanelPos,
21043
- onPositionChange: setFloatingPanelPos,
21044
- parentScroll: parentScrollSnap ?? parentScrollRef.current,
21045
- onClose: closeFloatingPanelOnly,
21046
- children: /* @__PURE__ */ jsx33(
21047
- SocialsDisplayPanel,
19756
+ children: [
19757
+ maxBadge.current,
19758
+ "/",
19759
+ maxBadge.max
19760
+ ]
19761
+ }
19762
+ ),
19763
+ toggleState && !linkPopover && /* @__PURE__ */ jsx33(
19764
+ StateToggle,
19765
+ {
19766
+ rect: toggleState.rect,
19767
+ activeState: toggleState.activeState,
19768
+ states: toggleState.states,
19769
+ onStateChange: handleStateChange
19770
+ }
19771
+ ),
19772
+ sectionGap && !linkPopover && /* @__PURE__ */ jsxs20(
19773
+ "div",
19774
+ {
19775
+ "data-ohw-section-insert-line": "",
19776
+ className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
19777
+ style: { top: sectionGap.y, transform: "translateY(-50%)" },
19778
+ children: [
19779
+ /* @__PURE__ */ jsx33("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
19780
+ /* @__PURE__ */ jsx33(
19781
+ Badge,
21048
19782
  {
21049
- display: socialsDisplayFor(floatingPanel.row, editContentRef.current),
21050
- onChange: (next) => {
21051
- changeSocialsDisplay(floatingPanel.row, next);
21052
- setFloatingPanel({ ...floatingPanel });
21053
- }
19783
+ 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",
19784
+ onClick: () => {
19785
+ window.parent.postMessage(
19786
+ {
19787
+ type: "ow:add-section",
19788
+ insertAfter: sectionGap.insertAfter,
19789
+ insertBefore: sectionGap.insertBefore
19790
+ },
19791
+ "*"
19792
+ );
19793
+ },
19794
+ children: "Add Section"
21054
19795
  }
21055
- )
21056
- }
21057
- ) : null
21058
- ] }),
21059
- bridgeRoot
21060
- ) : null
21061
- ] });
21062
- }
21063
-
21064
- // src/ui/EmptySection.tsx
21065
- import Link3 from "next/link";
21066
- import { Fragment as Fragment9, jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
21067
- function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey }) {
21068
- return /* @__PURE__ */ jsxs21(Fragment9, { children: [
21069
- /* @__PURE__ */ jsx34(
21070
- "p",
21071
- {
21072
- style: {
21073
- fontFamily: "var(--brand-font-body)",
21074
- fontSize: "0.75rem",
21075
- fontWeight: 500,
21076
- letterSpacing: "0.15em",
21077
- textTransform: "uppercase",
21078
- color: "var(--brand-accent)",
21079
- marginBottom: "1.5rem"
21080
- },
21081
- children: /* @__PURE__ */ jsx34(Link3, { href: homeHref, style: { color: "inherit" }, children: /* @__PURE__ */ jsx34("span", { ...eyebrowKey ? { "data-ohw-editable": "text", "data-ohw-key": eyebrowKey } : {}, children: "Home" }) })
21082
- }
21083
- ),
21084
- /* @__PURE__ */ jsx34(
21085
- "h1",
21086
- {
21087
- style: {
21088
- fontFamily: "var(--brand-font-heading)",
21089
- fontSize: "clamp(2rem, 3.5vw, 2.75rem)",
21090
- lineHeight: 1.1,
21091
- letterSpacing: "-0.025em",
21092
- color: "var(--brand-text)",
21093
- marginBottom: "1rem"
21094
- },
21095
- ...titleKey ? { "data-ohw-editable": "text", "data-ohw-key": titleKey, "data-ohw-max-length": 80 } : {},
21096
- children: title
21097
- }
21098
- ),
21099
- /* @__PURE__ */ jsx34(
21100
- "p",
21101
- {
21102
- style: {
21103
- fontFamily: "var(--brand-font-body)",
21104
- fontSize: "1rem",
21105
- lineHeight: 1.7,
21106
- fontWeight: 300,
21107
- color: "var(--brand-text-muted)",
21108
- maxWidth: "340px"
19796
+ ),
19797
+ /* @__PURE__ */ jsx33("div", { className: "flex-1 bg-primary", style: { height: 3 } })
19798
+ ]
19799
+ }
19800
+ ),
19801
+ linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx33(
19802
+ LinkPopover,
19803
+ {
19804
+ panelRef: linkPopoverPanelRef,
19805
+ portalContainer: dialogPortalContainer,
19806
+ open: true,
19807
+ mode: linkPopover.mode ?? "edit",
19808
+ pages: sitePages,
19809
+ sections: currentSections,
19810
+ sectionsByPath,
19811
+ initialTarget: linkPopover.target,
19812
+ existingTargets: linkPopover.intent === "add-nav" ? getNavbarExistingTargets() : [],
19813
+ onClose: closeLinkPopover,
19814
+ onSubmit: handleLinkPopoverSubmit
21109
19815
  },
21110
- ...subtitleKey ? { "data-ohw-editable": "text", "data-ohw-key": subtitleKey, "data-ohw-max-length": 160 } : {},
21111
- children: "This page doesn't have any content yet."
21112
- }
21113
- )
21114
- ] });
19816
+ linkPopover.key
19817
+ ) : null,
19818
+ floatingPanel && floatingPanel.kind === "socials-display" ? /* @__PURE__ */ jsx33(
19819
+ FloatingPanel,
19820
+ {
19821
+ open: true,
19822
+ title: floatingPanel.title,
19823
+ context: floatingPanel.context,
19824
+ position: floatingPanelPos,
19825
+ onPositionChange: setFloatingPanelPos,
19826
+ parentScroll: parentScrollSnap ?? parentScrollRef.current,
19827
+ onClose: closeFloatingPanelOnly,
19828
+ children: /* @__PURE__ */ jsx33(
19829
+ SocialsDisplayPanel,
19830
+ {
19831
+ display: socialsDisplayFor(floatingPanel.row, editContentRef.current),
19832
+ onChange: (next) => {
19833
+ changeSocialsDisplay(floatingPanel.row, next);
19834
+ setFloatingPanel({ ...floatingPanel });
19835
+ }
19836
+ }
19837
+ )
19838
+ }
19839
+ ) : null
19840
+ ] }),
19841
+ bridgeRoot
19842
+ ) : null;
21115
19843
  }
21116
19844
  export {
21117
19845
  AI_DEFAULT_BRAND,
@@ -21129,7 +19857,6 @@ export {
21129
19857
  DropdownMenuItem,
21130
19858
  DropdownMenuSeparator,
21131
19859
  DropdownMenuTrigger,
21132
- EmptySection,
21133
19860
  ItemActionToolbar,
21134
19861
  ItemInteractionLayer,
21135
19862
  LinkEditorPanel,