@ohhwells/bridge 0.1.66-next.192 → 0.1.66

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
  {
@@ -7681,9 +7254,6 @@ import { Check, X } from "lucide-react";
7681
7254
 
7682
7255
  // src/lib/sections.ts
7683
7256
  var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
7684
- function isChromeSection(el) {
7685
- return el.matches("header, nav, footer, aside");
7686
- }
7687
7257
  function titleCaseSectionId(id) {
7688
7258
  return id.split("-").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
7689
7259
  }
@@ -7694,8 +7264,6 @@ function parseSectionsFromRoot(root) {
7694
7264
  const id = el.getAttribute("data-ohw-section") ?? "";
7695
7265
  if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
7696
7266
  if (el.parentElement?.closest("[data-ohw-section]")) continue;
7697
- if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
7698
- continue;
7699
7267
  seen.add(id);
7700
7268
  const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
7701
7269
  sections.push({ id, label });
@@ -7713,12 +7281,8 @@ function parseSectionsFromHtml(html) {
7713
7281
 
7714
7282
  // src/ui/ai-section/AiSectionOverlay.tsx
7715
7283
  import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
7716
- function findSectionElement(instanceId) {
7717
- const escaped = CSS.escape(instanceId);
7718
- return document.querySelector(`[data-ohw-instance="${escaped}"]`) ?? document.querySelector(`[data-ohw-section="${escaped}"]:not([data-ohw-instance])`);
7719
- }
7720
- function readRect(instanceId) {
7721
- const el = findSectionElement(instanceId);
7284
+ function readRect(sectionId) {
7285
+ const el = document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`);
7722
7286
  if (!el) return null;
7723
7287
  const r2 = el.getBoundingClientRect();
7724
7288
  if (r2.width <= 0 || r2.height <= 0) return null;
@@ -7741,7 +7305,7 @@ function useLiveSectionRect(sectionId) {
7741
7305
  const opts = { capture: true, passive: true };
7742
7306
  window.addEventListener("scroll", update, opts);
7743
7307
  window.addEventListener("resize", update);
7744
- const el = findSectionElement(sectionId);
7308
+ const el = document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`);
7745
7309
  const ro = el ? new ResizeObserver(update) : null;
7746
7310
  if (el && ro) ro.observe(el);
7747
7311
  const interval = setInterval(update, 500);
@@ -7754,14 +7318,6 @@ function useLiveSectionRect(sectionId) {
7754
7318
  }, [sectionId]);
7755
7319
  return rect;
7756
7320
  }
7757
- function computeSectionBoundaryFlags(instanceId) {
7758
- const topLevel = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
7759
- (el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
7760
- );
7761
- const index = topLevel.findIndex((el) => (el.dataset.ohwInstance ?? el.dataset.ohwSection) === instanceId);
7762
- if (index === -1) return { isFirst: true, isLast: true };
7763
- return { isFirst: index === 0, isLast: index === topLevel.length - 1 };
7764
- }
7765
7321
  var PRIMARY2 = "#0885FE";
7766
7322
  function edgeAwareRadius(rect) {
7767
7323
  const container = window.innerWidth <= 480 ? 16 : 24;
@@ -7835,7 +7391,6 @@ function AiSectionOverlay({
7835
7391
  }) {
7836
7392
  const [selectedId, setSelectedId] = useState4(null);
7837
7393
  const [reviewId, setReviewId] = useState4(null);
7838
- const [reviewButtonsHidden, setReviewButtonsHidden] = useState4(false);
7839
7394
  const reviewIdRef = useRef4(null);
7840
7395
  reviewIdRef.current = reviewId;
7841
7396
  const selectedIdRef = useRef4(null);
@@ -7844,7 +7399,7 @@ function AiSectionOverlay({
7844
7399
  (el) => {
7845
7400
  postToParent2({
7846
7401
  type: "ow:section-selected",
7847
- sectionId: el ? el.dataset.ohwInstance ?? el.dataset.ohwSection ?? null : null,
7402
+ sectionId: el?.dataset.ohwSection ?? null,
7848
7403
  sectionLabel: el ? el.dataset.ohwSectionLabel ?? titleCaseSectionId(el.dataset.ohwSection ?? "") : null
7849
7404
  });
7850
7405
  },
@@ -7853,7 +7408,7 @@ function AiSectionOverlay({
7853
7408
  const selectFromElement = useCallback2(
7854
7409
  (el, options) => {
7855
7410
  const sectionEl = el?.closest("[data-ohw-section]") ?? null;
7856
- const id = sectionEl ? sectionEl.dataset.ohwInstance ?? sectionEl.dataset.ohwSection ?? null : null;
7411
+ const id = sectionEl?.dataset.ohwSection ?? null;
7857
7412
  if (id === selectedIdRef.current) return;
7858
7413
  setSelectedId(id);
7859
7414
  if (options?.report !== false) report(sectionEl);
@@ -7894,10 +7449,9 @@ function AiSectionOverlay({
7894
7449
  }
7895
7450
  const found = readRect(sectionId) != null;
7896
7451
  setReviewId(found ? sectionId : null);
7897
- setReviewButtonsHidden(e.data.hideButtons === true);
7898
7452
  postToParent2({ type: "ow:ai-review-started", sectionId, found });
7899
7453
  if (found) {
7900
- document.querySelector(`[data-ohw-instance="${CSS.escape(sectionId)}"]`)?.scrollIntoView({ behavior: "smooth", block: "nearest" });
7454
+ document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`)?.scrollIntoView({ behavior: "smooth", block: "nearest" });
7901
7455
  }
7902
7456
  }
7903
7457
  };
@@ -7916,7 +7470,7 @@ function AiSectionOverlay({
7916
7470
  return;
7917
7471
  }
7918
7472
  const sec = t.closest("[data-ohw-section]");
7919
- setHoveredId(sec ? sec.dataset.ohwInstance ?? sec.dataset.ohwSection ?? null : null);
7473
+ setHoveredId(sec?.dataset.ohwSection ?? null);
7920
7474
  };
7921
7475
  const onLeave = () => setHoveredId(null);
7922
7476
  document.addEventListener("mousemove", onMove, { passive: true });
@@ -7948,30 +7502,9 @@ function AiSectionOverlay({
7948
7502
  },
7949
7503
  [postToParent2]
7950
7504
  );
7951
- const activeSelectionId = reviewId ? null : selectedId;
7952
- const selectionRect = useLiveSectionRect(activeSelectionId);
7505
+ const selectionRect = useLiveSectionRect(reviewId ? null : selectedId);
7953
7506
  const reviewRect = useLiveSectionRect(reviewId);
7954
7507
  const hoverRect = useLiveSectionRect(reviewId || hoveredId === selectedId ? null : hoveredId);
7955
- useEffect4(() => {
7956
- const selectedEl = activeSelectionId ? findSectionElement(activeSelectionId) : null;
7957
- if (!activeSelectionId || !selectionRect || selectedEl && isChromeSection(selectedEl)) {
7958
- postToParent2({ type: "ow:section-rect", instanceId: null, rect: null });
7959
- return;
7960
- }
7961
- const { isFirst, isLast } = computeSectionBoundaryFlags(activeSelectionId);
7962
- postToParent2({
7963
- type: "ow:section-rect",
7964
- instanceId: activeSelectionId,
7965
- rect: {
7966
- top: selectionRect.top + window.scrollY,
7967
- left: selectionRect.left + window.scrollX,
7968
- width: selectionRect.width,
7969
- height: selectionRect.height
7970
- },
7971
- isFirst,
7972
- isLast
7973
- });
7974
- }, [activeSelectionId, selectionRect, postToParent2]);
7975
7508
  return /* @__PURE__ */ jsxs9(Fragment5, { children: [
7976
7509
  hoverRect && /* @__PURE__ */ jsx17(
7977
7510
  "div",
@@ -8022,16 +7555,13 @@ function AiSectionOverlay({
8022
7555
  border: `2px solid ${PRIMARY2}`,
8023
7556
  borderRadius: edgeAwareRadius(reviewRect),
8024
7557
  zIndex: 2147483200,
8025
- // The veil itself: swallows clicks so the section stays locked until decided. This
8026
- // stopPropagation only guards the bubble phase; the bridge's capture-phase click
8027
- // handlers additionally bail on `[data-ohw-ai-review]`, without which a click on
8028
- // Accept/Discard resolves to the media beneath and opens the file picker.
7558
+ // The veil itself: swallows clicks so the section stays locked until decided.
8029
7559
  background: "rgba(8, 133, 254, 0.04)",
8030
7560
  pointerEvents: "auto",
8031
7561
  cursor: "default"
8032
7562
  },
8033
7563
  onClick: (e) => e.stopPropagation(),
8034
- children: !reviewButtonsHidden && /* @__PURE__ */ jsxs9(
7564
+ children: /* @__PURE__ */ jsxs9(
8035
7565
  "div",
8036
7566
  {
8037
7567
  style: {
@@ -8056,58 +7586,6 @@ function AiSectionOverlay({
8056
7586
 
8057
7587
  // src/lib/section-instances.ts
8058
7588
  var SECTION_ORDER_KEY = "__ohw_section_order";
8059
- function topLevelSections() {
8060
- return Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
8061
- (el) => !el.parentElement?.closest("[data-ohw-section]") && !isChromeSection(el)
8062
- );
8063
- }
8064
- function instanceIdOf(el) {
8065
- return el.dataset.ohwInstance ?? el.dataset.ohwSection ?? "";
8066
- }
8067
- function planSectionMove(instanceId, targetIndex, currentPath) {
8068
- const sections = topLevelSections();
8069
- const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
8070
- if (index === -1) return null;
8071
- const dragged = sections[index];
8072
- const others = sections.filter((_, i) => i !== index);
8073
- const clamped = Math.max(0, Math.min(targetIndex, others.length));
8074
- const reordered = [...others.slice(0, clamped), dragged, ...others.slice(clamped)];
8075
- return reordered.map((el, order) => ({
8076
- instanceId: instanceIdOf(el),
8077
- type: el.getAttribute("data-ohw-section") ?? "",
8078
- order,
8079
- pagePath: currentPath
8080
- }));
8081
- }
8082
- function moveSectionInstance(instanceId, direction, currentPath) {
8083
- const sections = topLevelSections();
8084
- const index = sections.findIndex((el) => instanceIdOf(el) === instanceId);
8085
- if (index === -1) return null;
8086
- const siblingIndex = direction === "up" ? index - 1 : index + 1;
8087
- if (siblingIndex < 0 || siblingIndex >= sections.length) return null;
8088
- const entries = planSectionMove(instanceId, siblingIndex, currentPath);
8089
- if (!entries) return null;
8090
- applyPersistedOrder(entries);
8091
- return entries;
8092
- }
8093
- function applyPersistedOrder(entries) {
8094
- if (entries.length === 0) return;
8095
- const sections = topLevelSections();
8096
- if (sections.length === 0) return;
8097
- const orderIndex = new Map(entries.map((e) => [e.instanceId, e.order]));
8098
- const ordered = [...sections].sort((a, b) => {
8099
- const aOrder = orderIndex.get(instanceIdOf(a));
8100
- const bOrder = orderIndex.get(instanceIdOf(b));
8101
- if (aOrder === void 0 && bOrder === void 0) return 0;
8102
- if (aOrder === void 0) return 1;
8103
- if (bOrder === void 0) return -1;
8104
- return aOrder - bOrder;
8105
- });
8106
- const parent = sections[0].parentElement;
8107
- if (!parent) return;
8108
- const anchor = sections[sections.length - 1].nextSibling;
8109
- ordered.forEach((el) => parent.insertBefore(el, anchor));
8110
- }
8111
7589
  function getPageSectionOrderEntries(raw, currentPath) {
8112
7590
  if (!raw) return [];
8113
7591
  try {
@@ -8145,7 +7623,6 @@ function initSectionInstancesFromContent(content, currentPath) {
8145
7623
  rekeySectionSubtree(clone, entry.instanceId);
8146
7624
  original.insertAdjacentElement("afterend", clone);
8147
7625
  }
8148
- applyPersistedOrder(entries);
8149
7626
  }
8150
7627
 
8151
7628
  // src/OhhwellsBridge.tsx
@@ -12278,7 +11755,6 @@ function readLogoSizeState(content, placement) {
12278
11755
  function getLogoElement(el) {
12279
11756
  const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
12280
11757
  if (marked) return marked;
12281
- if (el.closest('[data-ohw-editable="icon"]')) return null;
12282
11758
  const root = el.closest("nav, [data-ohw-nav-root], footer");
12283
11759
  if (!root) return null;
12284
11760
  const anchor = el.closest("a");
@@ -12533,127 +12009,16 @@ function FloatingPanel({
12533
12009
  );
12534
12010
  }
12535
12011
 
12536
- // src/ui/logo-size-panel.tsx
12537
- import { ArrowUpRight, Link as Link2 } from "lucide-react";
12538
- import { jsx as jsx28, jsxs as jsxs18 } from "react/jsx-runtime";
12539
- function SizeSlider({
12540
- value,
12541
- onChange
12542
- }) {
12543
- const pct = (value - LOGO_SIZE_MIN) / (LOGO_SIZE_MAX - LOGO_SIZE_MIN) * 100;
12544
- return /* @__PURE__ */ jsxs18("div", { className: "flex w-full flex-col gap-3", children: [
12545
- /* @__PURE__ */ jsxs18("div", { className: "flex w-full items-center gap-2 text-sm font-medium leading-5", children: [
12546
- /* @__PURE__ */ jsx28("span", { className: "min-w-0 flex-1 text-foreground", children: "Size" }),
12547
- /* @__PURE__ */ jsxs18("span", { className: "shrink-0 whitespace-nowrap text-muted-foreground", children: [
12548
- value,
12549
- " px"
12550
- ] })
12551
- ] }),
12552
- /* @__PURE__ */ jsxs18("div", { className: "relative h-2 w-full rounded-full bg-primary-50", children: [
12553
- /* @__PURE__ */ jsx28(
12554
- "div",
12555
- {
12556
- className: "absolute inset-y-0 left-0 rounded-full bg-primary",
12557
- style: { width: `${pct}%` }
12558
- }
12559
- ),
12560
- /* @__PURE__ */ jsx28(
12561
- "input",
12562
- {
12563
- type: "range",
12564
- min: LOGO_SIZE_MIN,
12565
- max: LOGO_SIZE_MAX,
12566
- step: 1,
12567
- value,
12568
- "aria-label": "Logo size",
12569
- className: cn(
12570
- "absolute inset-0 h-full w-full cursor-pointer appearance-none bg-transparent",
12571
- "[&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:size-5",
12572
- "[&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border-2",
12573
- "[&::-webkit-slider-thumb]:border-primary [&::-webkit-slider-thumb]:bg-background",
12574
- "[&::-moz-range-thumb]:size-5 [&::-moz-range-thumb]:rounded-full",
12575
- "[&::-moz-range-thumb]:border-2 [&::-moz-range-thumb]:border-primary",
12576
- "[&::-moz-range-thumb]:bg-background"
12577
- ),
12578
- onChange: (e) => onChange(Number(e.target.value))
12579
- }
12580
- )
12581
- ] })
12582
- ] });
12583
- }
12584
- function LogoSizePanel({
12585
- viewport,
12586
- sizePx,
12587
- mobileFollowing = true,
12588
- onSizeChange,
12589
- onCustomizeMobile,
12590
- onResetMobile,
12591
- onUpdateEverywhere,
12592
- className
12593
- }) {
12594
- const showFollowing = viewport === "mobile" && mobileFollowing;
12595
- const showMobileSlider = viewport === "mobile" && !mobileFollowing;
12596
- const showDesktopSlider = viewport === "desktop";
12597
- return /* @__PURE__ */ jsxs18("div", { className: cn("flex w-full flex-col gap-4", className), children: [
12598
- showFollowing ? /* @__PURE__ */ jsxs18("div", { className: "flex w-full flex-col gap-2", children: [
12599
- /* @__PURE__ */ jsxs18("div", { className: "flex items-start gap-1", children: [
12600
- /* @__PURE__ */ jsx28(Link2, { size: 16, className: "mt-0.5 shrink-0 text-foreground", "aria-hidden": true }),
12601
- /* @__PURE__ */ jsx28("p", { className: "text-sm font-semibold leading-5 text-foreground", children: "Following desktop size" })
12602
- ] }),
12603
- /* @__PURE__ */ jsx28("p", { className: "text-sm leading-5 text-muted-foreground", children: "Mobile uses the desktop size until you customize it. Change the desktop size and it follows automatically." }),
12604
- /* @__PURE__ */ jsx28(
12605
- Button,
12606
- {
12607
- type: "button",
12608
- variant: "outline",
12609
- size: "sm",
12610
- className: "h-9 w-full min-w-0 cursor-pointer",
12611
- onClick: onCustomizeMobile,
12612
- children: "Customize for mobile"
12613
- }
12614
- )
12615
- ] }) : null,
12616
- showDesktopSlider || showMobileSlider ? /* @__PURE__ */ jsx28(SizeSlider, { value: sizePx, onChange: onSizeChange }) : null,
12617
- showMobileSlider ? /* @__PURE__ */ jsx28(
12618
- Button,
12619
- {
12620
- type: "button",
12621
- variant: "outline",
12622
- size: "sm",
12623
- className: "h-9 w-full min-w-0 cursor-pointer",
12624
- onClick: onResetMobile,
12625
- children: "Reset to desktop size"
12626
- }
12627
- ) : null,
12628
- /* @__PURE__ */ jsx28("div", { className: "h-px w-full bg-border", role: "separator" }),
12629
- /* @__PURE__ */ jsxs18(
12630
- Button,
12631
- {
12632
- type: "button",
12633
- variant: "outline",
12634
- size: "sm",
12635
- className: "h-9 w-full min-w-0 cursor-pointer gap-1",
12636
- onClick: onUpdateEverywhere,
12637
- children: [
12638
- "Update logo everywhere",
12639
- /* @__PURE__ */ jsx28(ArrowUpRight, { size: 16, "aria-hidden": true })
12640
- ]
12641
- }
12642
- ),
12643
- /* @__PURE__ */ jsx28("p", { className: "text-sm leading-5 text-muted-foreground", children: "Matches the right version to your background." })
12644
- ] });
12645
- }
12646
-
12647
12012
  // src/ui/socials-display-panel.tsx
12648
- import { jsx as jsx29, jsxs as jsxs19 } from "react/jsx-runtime";
12013
+ import { jsx as jsx28, jsxs as jsxs18 } from "react/jsx-runtime";
12649
12014
  function DisplaySwitch({
12650
12015
  label,
12651
12016
  checked,
12652
12017
  disabled,
12653
12018
  onChange
12654
12019
  }) {
12655
- return /* @__PURE__ */ jsxs19("div", { className: "flex w-full items-center gap-2", children: [
12656
- /* @__PURE__ */ jsx29(
12020
+ return /* @__PURE__ */ jsxs18("div", { className: "flex w-full items-center gap-2", children: [
12021
+ /* @__PURE__ */ jsx28(
12657
12022
  "span",
12658
12023
  {
12659
12024
  className: cn(
@@ -12663,7 +12028,7 @@ function DisplaySwitch({
12663
12028
  children: label
12664
12029
  }
12665
12030
  ),
12666
- /* @__PURE__ */ jsx29(
12031
+ /* @__PURE__ */ jsx28(
12667
12032
  "button",
12668
12033
  {
12669
12034
  type: "button",
@@ -12677,7 +12042,7 @@ function DisplaySwitch({
12677
12042
  checked ? "bg-primary" : "bg-primary-50",
12678
12043
  disabled ? "cursor-default opacity-50" : "cursor-pointer"
12679
12044
  ),
12680
- children: /* @__PURE__ */ jsx29(
12045
+ children: /* @__PURE__ */ jsx28(
12681
12046
  "span",
12682
12047
  {
12683
12048
  className: cn(
@@ -12691,8 +12056,8 @@ function DisplaySwitch({
12691
12056
  ] });
12692
12057
  }
12693
12058
  function SocialsDisplayPanel({ display, onChange, className }) {
12694
- return /* @__PURE__ */ jsxs19("div", { className: cn("flex w-full flex-col gap-3", className), children: [
12695
- /* @__PURE__ */ jsx29(
12059
+ return /* @__PURE__ */ jsxs18("div", { className: cn("flex w-full flex-col gap-3", className), children: [
12060
+ /* @__PURE__ */ jsx28(
12696
12061
  DisplaySwitch,
12697
12062
  {
12698
12063
  label: "Text",
@@ -12701,7 +12066,7 @@ function SocialsDisplayPanel({ display, onChange, className }) {
12701
12066
  onChange: (text) => onChange({ ...display, text })
12702
12067
  }
12703
12068
  ),
12704
- /* @__PURE__ */ jsx29(
12069
+ /* @__PURE__ */ jsx28(
12705
12070
  DisplaySwitch,
12706
12071
  {
12707
12072
  label: "Icon",
@@ -13260,414 +12625,87 @@ function useNavItemDrag({
13260
12625
  };
13261
12626
  }
13262
12627
 
13263
- // src/useSectionDrag.ts
13264
- import { useCallback as useCallback7, useEffect as useEffect11, useRef as useRef9, useState as useState10 } from "react";
12628
+ // src/ui/footer-container-chrome.tsx
12629
+ import { Plus as Plus2 } from "lucide-react";
12630
+ import { jsx as jsx29, jsxs as jsxs19 } from "react/jsx-runtime";
12631
+ function FooterContainerChrome({
12632
+ rect,
12633
+ onAdd,
12634
+ addDisabled = false
12635
+ }) {
12636
+ const chromeGap = 6;
12637
+ const buttonMargin = 7;
12638
+ return /* @__PURE__ */ jsx29(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsx29(
12639
+ "div",
12640
+ {
12641
+ "data-ohw-footer-container-chrome": "",
12642
+ "data-ohw-bridge": "",
12643
+ className: "pointer-events-none fixed z-[2147483647]",
12644
+ style: {
12645
+ top: rect.top - chromeGap,
12646
+ left: rect.left - chromeGap,
12647
+ width: rect.width + chromeGap * 2,
12648
+ height: rect.height + chromeGap * 2
12649
+ },
12650
+ children: /* @__PURE__ */ jsxs19(Tooltip, { children: [
12651
+ /* @__PURE__ */ jsx29(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx29(
12652
+ "button",
12653
+ {
12654
+ type: "button",
12655
+ "data-ohw-footer-add-button": "",
12656
+ disabled: addDisabled,
12657
+ 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",
12658
+ style: { top: chromeGap - buttonMargin },
12659
+ "aria-label": "Add item",
12660
+ onMouseDown: (e) => {
12661
+ e.preventDefault();
12662
+ e.stopPropagation();
12663
+ },
12664
+ onClick: (e) => {
12665
+ e.preventDefault();
12666
+ e.stopPropagation();
12667
+ if (addDisabled) return;
12668
+ onAdd();
12669
+ },
12670
+ children: /* @__PURE__ */ jsx29(Plus2, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
12671
+ }
12672
+ ) }),
12673
+ /* @__PURE__ */ jsx29(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
12674
+ ] })
12675
+ }
12676
+ ) });
12677
+ }
13265
12678
 
13266
- // src/lib/section-dnd.ts
13267
- function isFooterSection(el) {
13268
- return el.dataset.ohwSection === "footer";
12679
+ // src/lib/carousel.ts
12680
+ import { useEffect as useEffect11, useState as useState10 } from "react";
12681
+ var CAROUSEL_ATTR = "data-ohw-carousel";
12682
+ var CAROUSEL_VALUE_ATTR = "data-ohw-carousel-value";
12683
+ var CAROUSEL_SLIDE_ATTR = "data-ohw-carousel-slide";
12684
+ var CAROUSEL_EVENT = "ohw:carousel-change";
12685
+ function listCarouselKeys() {
12686
+ const keys = /* @__PURE__ */ new Set();
12687
+ document.querySelectorAll(`[${CAROUSEL_ATTR}]`).forEach((el) => {
12688
+ const key = el.getAttribute("data-ohw-key");
12689
+ if (key) keys.add(key);
12690
+ });
12691
+ return [...keys];
13269
12692
  }
13270
- function buildSectionDropSlots(draggedInstanceId) {
13271
- const sections = topLevelSections().filter(
13272
- (el) => instanceIdOf(el) !== draggedInstanceId && !isFooterSection(el)
12693
+ function containersForKey(key) {
12694
+ return Array.from(
12695
+ document.querySelectorAll(`[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`)
13273
12696
  );
13274
- const slots = [];
13275
- if (sections.length === 0) return slots;
13276
- const left = 0;
13277
- const width = document.documentElement.clientWidth;
13278
- for (let i = 0; i <= sections.length; i++) {
13279
- let y;
13280
- if (i === 0) {
13281
- y = sections[0].getBoundingClientRect().top;
13282
- } else if (i === sections.length) {
13283
- y = sections[sections.length - 1].getBoundingClientRect().bottom;
13284
- } else {
13285
- const prev = sections[i - 1].getBoundingClientRect();
13286
- const next = sections[i].getBoundingClientRect();
13287
- y = (prev.bottom + next.top) / 2;
13288
- }
13289
- slots.push({ insertIndex: i, y, left, width });
13290
- }
13291
- return slots;
13292
12697
  }
13293
- function hitTestSectionDropSlot(y, slots) {
13294
- let best = null;
13295
- for (const slot of slots) {
13296
- const dist = Math.abs(y - slot.y);
13297
- if (!best || dist < best.dist) best = { slot, dist };
13298
- }
13299
- return best?.slot ?? null;
13300
- }
13301
-
13302
- // src/useSectionDrag.ts
13303
- var PRESS_THRESHOLD = 10;
13304
- var EDGE_ZONE = 60;
13305
- var MAX_AUTO_SCROLL_SPEED = 18;
13306
- var SECTION_DRAG_EXCLUDED_SELECTOR = [
13307
- "[data-ohw-toolbar]",
13308
- "[data-ohw-edit-chrome]",
13309
- "[data-ohw-item-interaction]",
13310
- "[data-ohw-drag-handle-container]",
13311
- '[data-slot="drag-handle"]',
13312
- "[data-ohw-item-toolbar-anchor]",
13313
- "[data-ohw-item-drag-surface]",
13314
- "[data-ohw-more-menu]",
13315
- '[data-slot="dropdown-menu-content"]',
13316
- '[data-slot="dropdown-menu-item"]',
13317
- "[data-ohw-state-toggle]",
13318
- "[data-ohw-max-badge]",
13319
- "[data-ohw-floating-panel]",
13320
- "[data-ohw-section-picker]",
13321
- "[data-ohw-link-popover-root]",
13322
- "[data-ohw-link-modal-root]",
13323
- "[data-ohw-link-page-dropdown]",
13324
- '[data-slot="popover-content"]',
13325
- '[data-slot="dialog-content"]',
13326
- '[data-slot="dialog-overlay"]',
13327
- "[data-ohw-ai-review]",
13328
- "[data-ohw-editable]",
13329
- "[data-ohw-editable-state]",
13330
- "[contenteditable]",
13331
- "[data-ohw-href-key]",
13332
- "[data-ohw-footer-col]",
13333
- "[data-ohw-social-label]",
13334
- "a",
13335
- "button",
13336
- '[role="button"]',
13337
- '[data-ohw-role="navbar-button"]',
13338
- '[data-ohw-role="button"]',
13339
- "[data-ohw-carousel]",
13340
- "[data-ohw-carousel-value]",
13341
- "[data-ohw-carousel-slide]",
13342
- "[data-ohw-carousel-overlay]",
13343
- "[data-ohw-media-chrome]",
13344
- "[data-ohw-media-overlay]",
13345
- "[data-ohw-media-skeleton]"
13346
- ].join(", ");
13347
- function visibleClip(ps) {
13348
- if (!ps) return null;
13349
- const top = Math.max(0, ps.headerH - ps.iframeOffsetTop);
13350
- const bottom = Math.min(window.innerHeight, ps.headerH + ps.canvasH - ps.iframeOffsetTop);
13351
- return { top, bottom: Math.max(top, bottom) };
13352
- }
13353
- function useSectionDrag({
13354
- isEditMode,
13355
- editContentRef,
13356
- postToParentRef,
13357
- parentScrollRef,
13358
- navDragRef,
13359
- footerDragRef,
13360
- suppressNextClickRef,
13361
- suppressClickUntilRef
13362
- }) {
13363
- const sectionDragRef = useRef9(null);
13364
- const [sectionDropSlots, setSectionDropSlots] = useState10([]);
13365
- const [activeSectionDropIndex, setActiveSectionDropIndex] = useState10(null);
13366
- const [isSectionDragging, setIsSectionDragging] = useState10(false);
13367
- const sectionPointerDragRef = useRef9(null);
13368
- const autoScrollRafRef = useRef9(null);
13369
- const autoScrollDeltaRef = useRef9(0);
13370
- const stopAutoScroll = useCallback7(() => {
13371
- if (autoScrollRafRef.current != null) {
13372
- cancelAnimationFrame(autoScrollRafRef.current);
13373
- autoScrollRafRef.current = null;
13374
- }
13375
- autoScrollDeltaRef.current = 0;
13376
- }, []);
13377
- const tickAutoScroll = useCallback7(() => {
13378
- if (!sectionDragRef.current) {
13379
- stopAutoScroll();
13380
- return;
13381
- }
13382
- if (autoScrollDeltaRef.current !== 0) {
13383
- postToParentRef.current({ type: "ow:request-scroll", deltaY: autoScrollDeltaRef.current });
13384
- }
13385
- autoScrollRafRef.current = requestAnimationFrame(tickAutoScroll);
13386
- }, [postToParentRef, stopAutoScroll]);
13387
- const updateAutoScroll = useCallback7(
13388
- (clientY) => {
13389
- const clip = visibleClip(parentScrollRef.current);
13390
- let delta = 0;
13391
- if (clip) {
13392
- const distTop = clientY - clip.top;
13393
- const distBottom = clip.bottom - clientY;
13394
- if (distTop >= 0 && distTop < EDGE_ZONE) {
13395
- delta = -MAX_AUTO_SCROLL_SPEED * (1 - distTop / EDGE_ZONE);
13396
- } else if (distBottom >= 0 && distBottom < EDGE_ZONE) {
13397
- delta = MAX_AUTO_SCROLL_SPEED * (1 - distBottom / EDGE_ZONE);
13398
- }
13399
- }
13400
- autoScrollDeltaRef.current = delta;
13401
- if (delta !== 0 && autoScrollRafRef.current == null) {
13402
- autoScrollRafRef.current = requestAnimationFrame(tickAutoScroll);
13403
- } else if (delta === 0) {
13404
- stopAutoScroll();
13405
- }
13406
- },
13407
- [parentScrollRef, stopAutoScroll, tickAutoScroll]
13408
- );
13409
- const clearSectionDragVisuals = useCallback7(() => {
13410
- sectionDragRef.current?.draggedEl.removeAttribute("data-ohw-section-dragging");
13411
- sectionDragRef.current = null;
13412
- setSectionDropSlots([]);
13413
- setActiveSectionDropIndex(null);
13414
- setIsSectionDragging(false);
13415
- stopAutoScroll();
13416
- document.documentElement.removeAttribute("data-ohw-section-dragging-root");
13417
- unlockItemDragInteraction();
13418
- }, [stopAutoScroll]);
13419
- const refreshSectionDragVisuals = useCallback7(
13420
- (session, clientX, clientY) => {
13421
- session.lastClientX = clientX;
13422
- session.lastClientY = clientY;
13423
- const slots = buildSectionDropSlots(session.instanceId);
13424
- const activeSlot = hitTestSectionDropSlot(clientY, slots);
13425
- session.activeSlot = activeSlot;
13426
- setSectionDropSlots(slots);
13427
- const activeIdx = activeSlot ? slots.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
13428
- setActiveSectionDropIndex(activeIdx >= 0 ? activeIdx : null);
13429
- updateAutoScroll(clientY);
13430
- },
13431
- [updateAutoScroll]
13432
- );
13433
- const beginSectionDrag = useCallback7(
13434
- (session) => {
13435
- sectionDragRef.current = session;
13436
- setIsSectionDragging(true);
13437
- lockItemDuringDrag();
13438
- document.documentElement.setAttribute("data-ohw-section-dragging-root", "");
13439
- session.draggedEl.setAttribute("data-ohw-section-dragging", "");
13440
- refreshSectionDragVisuals(session, session.lastClientX, session.lastClientY);
13441
- },
13442
- [refreshSectionDragVisuals]
13443
- );
13444
- const commitSectionDrag = useCallback7(() => {
13445
- const session = sectionDragRef.current;
13446
- if (!session) {
13447
- clearSectionDragVisuals();
13448
- return;
13449
- }
13450
- const slot = session.activeSlot ?? hitTestSectionDropSlot(session.lastClientY, buildSectionDropSlots(session.instanceId));
13451
- const entries = slot ? planSectionMove(session.instanceId, slot.insertIndex, window.location.pathname) : null;
13452
- if (!entries) {
13453
- clearSectionDragVisuals();
13454
- return;
13455
- }
13456
- const orderJson = JSON.stringify(entries);
13457
- editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
13458
- postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
13459
- applyPersistedOrder(entries);
13460
- clearSectionDragVisuals();
13461
- requestAnimationFrame(() => {
13462
- if (editContentRef.current[SECTION_ORDER_KEY] === orderJson) {
13463
- applyPersistedOrder(entries);
13464
- }
13465
- requestAnimationFrame(() => {
13466
- window.dispatchEvent(new Event("resize"));
13467
- });
13468
- });
13469
- }, [clearSectionDragVisuals, editContentRef, postToParentRef]);
13470
- const startSectionPressDrag = useCallback7(
13471
- (el, clientX, clientY, pointerId) => {
13472
- if (navDragRef.current || footerDragRef.current || sectionDragRef.current) return false;
13473
- const instanceId = instanceIdOf(el);
13474
- if (!instanceId) return false;
13475
- sectionPointerDragRef.current = {
13476
- el,
13477
- instanceId,
13478
- startX: clientX,
13479
- startY: clientY,
13480
- pointerId,
13481
- started: false
13482
- };
13483
- return true;
13484
- },
13485
- [footerDragRef, navDragRef]
13486
- );
13487
- useEffect11(() => {
13488
- if (!isEditMode) return;
13489
- const onPointerDown = (e) => {
13490
- if (e.button !== 0) return;
13491
- if (navDragRef.current || footerDragRef.current || sectionDragRef.current) return;
13492
- if (sectionPointerDragRef.current) return;
13493
- const target = e.target;
13494
- if (!(target instanceof HTMLElement)) return;
13495
- if (target.closest(SECTION_DRAG_EXCLUDED_SELECTOR)) return;
13496
- const sectionEl = target.closest("[data-ohw-section]");
13497
- if (!sectionEl || isChromeSection(sectionEl) || sectionEl.dataset.ohwSection === "footer") return;
13498
- if (!topLevelSections().includes(sectionEl)) return;
13499
- startSectionPressDrag(sectionEl, e.clientX, e.clientY, e.pointerId);
13500
- };
13501
- const onPointerMove = (e) => {
13502
- const pending = sectionPointerDragRef.current;
13503
- if (!pending) return;
13504
- if (pending.started) {
13505
- e.preventDefault();
13506
- clearTextSelection();
13507
- const session = sectionDragRef.current;
13508
- if (!session) return;
13509
- refreshSectionDragVisuals(session, e.clientX, e.clientY);
13510
- return;
13511
- }
13512
- const dx = e.clientX - pending.startX;
13513
- const dy = e.clientY - pending.startY;
13514
- if (dx * dx + dy * dy < PRESS_THRESHOLD * PRESS_THRESHOLD) return;
13515
- e.preventDefault();
13516
- pending.started = true;
13517
- armItemPressDrag();
13518
- clearTextSelection();
13519
- try {
13520
- document.body.setPointerCapture(pending.pointerId);
13521
- } catch {
13522
- }
13523
- beginSectionDrag({
13524
- instanceId: pending.instanceId,
13525
- draggedEl: pending.el,
13526
- lastClientX: e.clientX,
13527
- lastClientY: e.clientY,
13528
- activeSlot: null
13529
- });
13530
- };
13531
- const endPointerDrag = (e) => {
13532
- const pending = sectionPointerDragRef.current;
13533
- sectionPointerDragRef.current = null;
13534
- try {
13535
- if (document.body.hasPointerCapture(e.pointerId)) {
13536
- document.body.releasePointerCapture(e.pointerId);
13537
- }
13538
- } catch {
13539
- }
13540
- if (!pending) return;
13541
- if (!pending.started) {
13542
- unlockItemDragInteraction();
13543
- return;
13544
- }
13545
- suppressNextClickRef.current = true;
13546
- suppressClickUntilRef.current = Date.now() + 500;
13547
- commitSectionDrag();
13548
- };
13549
- const onKeyDown = (e) => {
13550
- if (e.key !== "Escape") return;
13551
- if (!sectionDragRef.current && !sectionPointerDragRef.current) return;
13552
- sectionPointerDragRef.current = null;
13553
- clearSectionDragVisuals();
13554
- };
13555
- document.addEventListener("pointerdown", onPointerDown, true);
13556
- document.addEventListener("pointermove", onPointerMove, true);
13557
- document.addEventListener("pointerup", endPointerDrag, true);
13558
- document.addEventListener("pointercancel", endPointerDrag, true);
13559
- document.addEventListener("keydown", onKeyDown, true);
13560
- return () => {
13561
- document.removeEventListener("pointerdown", onPointerDown, true);
13562
- document.removeEventListener("pointermove", onPointerMove, true);
13563
- document.removeEventListener("pointerup", endPointerDrag, true);
13564
- document.removeEventListener("pointercancel", endPointerDrag, true);
13565
- document.removeEventListener("keydown", onKeyDown, true);
13566
- unlockItemDragInteraction();
13567
- stopAutoScroll();
13568
- };
13569
- }, [
13570
- beginSectionDrag,
13571
- clearSectionDragVisuals,
13572
- commitSectionDrag,
13573
- footerDragRef,
13574
- isEditMode,
13575
- navDragRef,
13576
- refreshSectionDragVisuals,
13577
- startSectionPressDrag,
13578
- stopAutoScroll,
13579
- suppressClickUntilRef,
13580
- suppressNextClickRef
13581
- ]);
13582
- return {
13583
- sectionDragRef,
13584
- sectionDropSlots,
13585
- activeSectionDropIndex,
13586
- isSectionDragging
13587
- };
13588
- }
13589
-
13590
- // src/ui/footer-container-chrome.tsx
13591
- import { Plus as Plus2 } from "lucide-react";
13592
- import { jsx as jsx30, jsxs as jsxs20 } from "react/jsx-runtime";
13593
- function FooterContainerChrome({
13594
- rect,
13595
- onAdd,
13596
- addDisabled = false
13597
- }) {
13598
- const chromeGap = 6;
13599
- const buttonMargin = 7;
13600
- return /* @__PURE__ */ jsx30(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsx30(
13601
- "div",
13602
- {
13603
- "data-ohw-footer-container-chrome": "",
13604
- "data-ohw-bridge": "",
13605
- className: "pointer-events-none fixed z-[2147483647]",
13606
- style: {
13607
- top: rect.top - chromeGap,
13608
- left: rect.left - chromeGap,
13609
- width: rect.width + chromeGap * 2,
13610
- height: rect.height + chromeGap * 2
13611
- },
13612
- children: /* @__PURE__ */ jsxs20(Tooltip, { children: [
13613
- /* @__PURE__ */ jsx30(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx30(
13614
- "button",
13615
- {
13616
- type: "button",
13617
- "data-ohw-footer-add-button": "",
13618
- disabled: addDisabled,
13619
- 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",
13620
- style: { top: chromeGap - buttonMargin },
13621
- "aria-label": "Add item",
13622
- onMouseDown: (e) => {
13623
- e.preventDefault();
13624
- e.stopPropagation();
13625
- },
13626
- onClick: (e) => {
13627
- e.preventDefault();
13628
- e.stopPropagation();
13629
- if (addDisabled) return;
13630
- onAdd();
13631
- },
13632
- children: /* @__PURE__ */ jsx30(Plus2, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
13633
- }
13634
- ) }),
13635
- /* @__PURE__ */ jsx30(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
13636
- ] })
13637
- }
13638
- ) });
13639
- }
13640
-
13641
- // src/lib/carousel.ts
13642
- import { useEffect as useEffect12, useState as useState11 } from "react";
13643
- var CAROUSEL_ATTR = "data-ohw-carousel";
13644
- var CAROUSEL_VALUE_ATTR = "data-ohw-carousel-value";
13645
- var CAROUSEL_SLIDE_ATTR = "data-ohw-carousel-slide";
13646
- var CAROUSEL_EVENT = "ohw:carousel-change";
13647
- function listCarouselKeys() {
13648
- const keys = /* @__PURE__ */ new Set();
13649
- document.querySelectorAll(`[${CAROUSEL_ATTR}]`).forEach((el) => {
13650
- const key = el.getAttribute("data-ohw-key");
13651
- if (key) keys.add(key);
13652
- });
13653
- return [...keys];
13654
- }
13655
- function containersForKey(key) {
13656
- return Array.from(
13657
- document.querySelectorAll(`[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`)
13658
- );
13659
- }
13660
- function isCarouselKey(key) {
13661
- return containersForKey(key).length > 0;
13662
- }
13663
- function parseSlides(raw) {
13664
- if (!raw) return [];
13665
- try {
13666
- const parsed = JSON.parse(raw);
13667
- if (!Array.isArray(parsed)) return [];
13668
- return parsed.filter((s) => Boolean(s) && typeof s === "object").map((s) => ({ src: String(s.src ?? ""), alt: String(s.alt ?? "") }));
13669
- } catch {
13670
- return [];
12698
+ function isCarouselKey(key) {
12699
+ return containersForKey(key).length > 0;
12700
+ }
12701
+ function parseSlides(raw) {
12702
+ if (!raw) return [];
12703
+ try {
12704
+ const parsed = JSON.parse(raw);
12705
+ if (!Array.isArray(parsed)) return [];
12706
+ return parsed.filter((s) => Boolean(s) && typeof s === "object").map((s) => ({ src: String(s.src ?? ""), alt: String(s.alt ?? "") }));
12707
+ } catch {
12708
+ return [];
13671
12709
  }
13672
12710
  }
13673
12711
  function readCarouselValue(key) {
@@ -13701,8 +12739,8 @@ function applyCarouselNode(key, val) {
13701
12739
  return true;
13702
12740
  }
13703
12741
  function useOhwCarousel(key, initial) {
13704
- const [images, setImages] = useState11(initial);
13705
- useEffect12(() => {
12742
+ const [images, setImages] = useState10(initial);
12743
+ useEffect11(() => {
13706
12744
  const el = document.querySelector(
13707
12745
  `[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`
13708
12746
  );
@@ -13780,7 +12818,7 @@ function collectEditableNodes(extraContent, root = document) {
13780
12818
  nodes.push({ key, type: "link", text: href });
13781
12819
  }
13782
12820
  if (extraContent) {
13783
- for (const key of [NAV_ORDER_KEY, FOOTER_ORDER_KEY, NAV_COUNT_KEY, SECTION_ORDER_KEY]) {
12821
+ for (const key of [NAV_ORDER_KEY, FOOTER_ORDER_KEY, NAV_COUNT_KEY]) {
13784
12822
  const text = extraContent[key];
13785
12823
  if (typeof text === "string" && text.length > 0) {
13786
12824
  nodes.push({ key, type: "meta", text });
@@ -13817,18 +12855,6 @@ function collectEditableNodes(extraContent, root = document) {
13817
12855
  }
13818
12856
  if (extraContent && !isScoped) {
13819
12857
  applyNavFooterDeleteOverrides(byKey, extraContent);
13820
- for (const key of LOGO_IMAGE_KEYS) {
13821
- if (!(key in extraContent)) continue;
13822
- byKey.set(key, { key, type: "image", text: extraContent[key] ?? "" });
13823
- }
13824
- for (const key of [LOGO_PLACEHOLDER_KEY, LOGO_ALT_KEY]) {
13825
- if (!(key in extraContent)) continue;
13826
- byKey.set(key, { key, type: "meta", text: extraContent[key] ?? "" });
13827
- }
13828
- for (const key of LOGO_SIZE_KEYS) {
13829
- if (!(key in extraContent)) continue;
13830
- byKey.set(key, { key, type: "meta", text: extraContent[key] ?? "" });
13831
- }
13832
12858
  }
13833
12859
  return Array.from(byKey.values());
13834
12860
  }
@@ -14095,13 +13121,13 @@ function deleteSelectedNavFooterItem(deps) {
14095
13121
 
14096
13122
  // src/ui/navbar-container-chrome.tsx
14097
13123
  import { Plus as Plus3 } from "lucide-react";
14098
- import { jsx as jsx31 } from "react/jsx-runtime";
13124
+ import { jsx as jsx30 } from "react/jsx-runtime";
14099
13125
  function NavbarContainerChrome({
14100
13126
  rect,
14101
13127
  onAdd
14102
13128
  }) {
14103
13129
  const chromeGap = 6;
14104
- return /* @__PURE__ */ jsx31(
13130
+ return /* @__PURE__ */ jsx30(
14105
13131
  "div",
14106
13132
  {
14107
13133
  "data-ohw-navbar-container-chrome": "",
@@ -14113,7 +13139,7 @@ function NavbarContainerChrome({
14113
13139
  width: rect.width + chromeGap * 2,
14114
13140
  height: rect.height + chromeGap * 2
14115
13141
  },
14116
- children: /* @__PURE__ */ jsx31(
13142
+ children: /* @__PURE__ */ jsx30(
14117
13143
  "button",
14118
13144
  {
14119
13145
  type: "button",
@@ -14130,7 +13156,7 @@ function NavbarContainerChrome({
14130
13156
  e.stopPropagation();
14131
13157
  onAdd();
14132
13158
  },
14133
- children: /* @__PURE__ */ jsx31(Plus3, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
13159
+ children: /* @__PURE__ */ jsx30(Plus3, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
14134
13160
  }
14135
13161
  )
14136
13162
  }
@@ -14139,7 +13165,7 @@ function NavbarContainerChrome({
14139
13165
 
14140
13166
  // src/ui/drop-indicator.tsx
14141
13167
  import * as React10 from "react";
14142
- import { jsx as jsx32 } from "react/jsx-runtime";
13168
+ import { jsx as jsx31 } from "react/jsx-runtime";
14143
13169
  var dropIndicatorVariants = cva(
14144
13170
  "ov-gap-line pointer-events-none shrink-0 transition-opacity duration-150",
14145
13171
  {
@@ -14163,7 +13189,7 @@ var dropIndicatorVariants = cva(
14163
13189
  );
14164
13190
  var DropIndicator = React10.forwardRef(
14165
13191
  ({ className, direction, state, ...props }, ref) => {
14166
- return /* @__PURE__ */ jsx32(
13192
+ return /* @__PURE__ */ jsx31(
14167
13193
  "div",
14168
13194
  {
14169
13195
  ref,
@@ -14180,7 +13206,7 @@ var DropIndicator = React10.forwardRef(
14180
13206
  DropIndicator.displayName = "DropIndicator";
14181
13207
 
14182
13208
  // src/ui/badge.tsx
14183
- import { jsx as jsx33 } from "react/jsx-runtime";
13209
+ import { jsx as jsx32 } from "react/jsx-runtime";
14184
13210
  var badgeVariants = cva(
14185
13211
  "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
14186
13212
  {
@@ -14198,12 +13224,12 @@ var badgeVariants = cva(
14198
13224
  }
14199
13225
  );
14200
13226
  function Badge({ className, variant, ...props }) {
14201
- return /* @__PURE__ */ jsx33("div", { className: cn(badgeVariants({ variant }), className), ...props });
13227
+ return /* @__PURE__ */ jsx32("div", { className: cn(badgeVariants({ variant }), className), ...props });
14202
13228
  }
14203
13229
 
14204
13230
  // src/OhhwellsBridge.tsx
14205
- import { Link as Link3, Plus as Plus4, Settings } from "lucide-react";
14206
- import { Fragment as Fragment8, jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
13231
+ import { Link as Link2, Plus as Plus4, Settings } from "lucide-react";
13232
+ import { Fragment as Fragment8, jsx as jsx33, jsxs as jsxs20 } from "react/jsx-runtime";
14207
13233
  var PRIMARY3 = "#0885FE";
14208
13234
  var IMAGE_FADE_MS = 300;
14209
13235
  function runOpacityFade(el, onDone) {
@@ -14297,10 +13323,21 @@ function parseSchedulingInsertAfter(insertAfter) {
14297
13323
  insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
14298
13324
  };
14299
13325
  }
14300
- function resolveEntryAnchor(entry) {
14301
- if (entry.anchorId !== void 0) return { anchorId: entry.anchorId, beforeId: entry.beforeId ?? null };
14302
- const parsed = parseSchedulingInsertAfter(entry.insertAfter);
14303
- return { anchorId: parsed.anchor, beforeId: parsed.insertBefore };
13326
+ function resolveSchedulingInsert(insertAfter, explicitInsertBefore) {
13327
+ const parsed = parseSchedulingInsertAfter(insertAfter);
13328
+ const insertBefore = explicitInsertBefore ?? parsed.insertBefore;
13329
+ const effectiveInsertAfter = insertBefore && parsed.insertBefore === null ? `${insertAfter}${INSERT_BEFORE_MARKER}${insertBefore}` : insertAfter;
13330
+ return { effectiveInsertAfter, insertBefore };
13331
+ }
13332
+ function getSchedulingMountPoint(insertAfter) {
13333
+ const { anchor } = parseSchedulingInsertAfter(insertAfter);
13334
+ let anchorEl = document.querySelector(`[data-ohw-section="${anchor}"]`);
13335
+ if (!anchorEl && anchor === "scheduling") {
13336
+ const widgets = Array.from(document.querySelectorAll('[data-ohw-section^="scheduling-"]'));
13337
+ anchorEl = widgets.at(-1) ?? null;
13338
+ }
13339
+ if (!anchorEl) return null;
13340
+ return anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
14304
13341
  }
14305
13342
  function schedulingMountDepth(insertAfter) {
14306
13343
  if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
@@ -14317,7 +13354,8 @@ function getPageSchedulingEntries(raw) {
14317
13354
  }
14318
13355
  }
14319
13356
  function isSchedulingWidgetMissing(entry) {
14320
- return !document.querySelector(`[data-ohw-section="${schedulingSectionId(entry.insertAfter)}"]`);
13357
+ const { effectiveInsertAfter } = resolveSchedulingInsert(entry.insertAfter);
13358
+ return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
14321
13359
  }
14322
13360
  function hasMissingSchedulingWidgets(entries) {
14323
13361
  return entries.some(isSchedulingWidgetMissing);
@@ -14347,17 +13385,16 @@ function initSectionsFromContent(content, removeExisting = false) {
14347
13385
  } catch {
14348
13386
  }
14349
13387
  }
14350
- function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, beforeId, existingWidgetId) {
14351
- const widgetId = existingWidgetId ?? (beforeId ? `${anchorId}${INSERT_BEFORE_MARKER}${beforeId}` : anchorId);
14352
- const sectionId = schedulingSectionId(widgetId);
13388
+ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId, explicitInsertBefore) {
13389
+ const { effectiveInsertAfter, insertBefore } = resolveSchedulingInsert(insertAfter, explicitInsertBefore);
13390
+ const sectionId = schedulingSectionId(effectiveInsertAfter);
14353
13391
  if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
14354
- const anchorEl = document.querySelector(`[data-ohw-section="${anchorId}"]`);
14355
- if (!anchorEl) return false;
14356
- const mountPoint = anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
13392
+ const mountPoint = getSchedulingMountPoint(effectiveInsertAfter);
13393
+ if (!mountPoint) return false;
14357
13394
  const container = document.createElement("div");
14358
13395
  container.dataset.ohwSectionContainer = "scheduling";
14359
- if (beforeId) {
14360
- const beforeAnchor = document.querySelector(`[data-ohw-section="${beforeId}"]`);
13396
+ if (insertBefore) {
13397
+ const beforeAnchor = document.querySelector(`[data-ohw-section="${insertBefore}"]`);
14361
13398
  const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
14362
13399
  if (!beforePoint) return false;
14363
13400
  beforePoint.insertAdjacentElement("beforebegin", container);
@@ -14368,25 +13405,19 @@ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, be
14368
13405
  }
14369
13406
  tail.insertAdjacentElement("afterend", container);
14370
13407
  }
14371
- try {
14372
- const root = createRoot2(container);
14373
- flushSync2(() => {
14374
- root.render(
14375
- /* @__PURE__ */ jsx34(
14376
- SchedulingWidget,
14377
- {
14378
- notifyOnConnect,
14379
- initialScheduleId: scheduleId,
14380
- insertAfter: widgetId
14381
- }
14382
- )
14383
- );
14384
- });
14385
- } catch (err) {
14386
- console.error("[ow:scheduling] render threw", err);
14387
- container.remove();
14388
- return false;
14389
- }
13408
+ const root = createRoot2(container);
13409
+ flushSync2(() => {
13410
+ root.render(
13411
+ /* @__PURE__ */ jsx33(
13412
+ SchedulingWidget,
13413
+ {
13414
+ notifyOnConnect,
13415
+ initialScheduleId: scheduleId,
13416
+ insertAfter: effectiveInsertAfter
13417
+ }
13418
+ )
13419
+ );
13420
+ });
14390
13421
  const tracker = getSectionsTracker();
14391
13422
  let sections = [];
14392
13423
  try {
@@ -14394,12 +13425,10 @@ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, be
14394
13425
  } catch {
14395
13426
  }
14396
13427
  const inEditor = typeof window !== "undefined" && window.self !== window.top;
14397
- if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === widgetId)) {
13428
+ if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === effectiveInsertAfter)) {
14398
13429
  sections.push({
14399
13430
  type: "scheduling",
14400
- insertAfter: widgetId,
14401
- anchorId,
14402
- beforeId: beforeId ?? null,
13431
+ insertAfter: effectiveInsertAfter,
14403
13432
  pagePath: window.location.pathname,
14404
13433
  ...scheduleId ? { scheduleId } : {}
14405
13434
  });
@@ -14413,8 +13442,7 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
14413
13442
  for (let i = pending.length - 1; i >= 0; i--) {
14414
13443
  const entry = pending[i];
14415
13444
  const shouldNotify = typeof notifyOnConnect === "function" ? notifyOnConnect(entry) : notifyOnConnect;
14416
- const { anchorId, beforeId } = resolveEntryAnchor(entry);
14417
- if (mountSchedulingWidget(anchorId, shouldNotify, entry.scheduleId ?? null, beforeId, entry.insertAfter)) {
13445
+ if (mountSchedulingWidget(entry.insertAfter, shouldNotify, entry.scheduleId)) {
14418
13446
  pending.splice(i, 1);
14419
13447
  }
14420
13448
  }
@@ -14562,13 +13590,6 @@ function isInsideLinkEditor(target) {
14562
13590
  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"]')
14563
13591
  );
14564
13592
  }
14565
- function isInsideFloatingPanel(target) {
14566
- return Boolean(target.closest("[data-ohw-floating-panel]"));
14567
- }
14568
- function isPointOverFloatingPanel(clientX, clientY) {
14569
- const el = document.elementFromPoint(clientX, clientY);
14570
- return Boolean(el instanceof Element && el.closest("[data-ohw-floating-panel]"));
14571
- }
14572
13593
  function getHrefKeyFromElement(el) {
14573
13594
  if (!el) return null;
14574
13595
  const anchor = el.closest("[data-ohw-href-key]");
@@ -14719,6 +13740,13 @@ function resolveFooterColumnSelectionTarget(target, clientX, clientY) {
14719
13740
  if (isPointOverNavItem(column, clientX, clientY)) return null;
14720
13741
  return column;
14721
13742
  }
13743
+ function isPointOverLogo(x, y) {
13744
+ for (const root of document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]')) {
13745
+ const r2 = root.getBoundingClientRect();
13746
+ if (r2.width > 0 && r2.height > 0 && x >= r2.left && x <= r2.right && y >= r2.top && y <= r2.bottom) return true;
13747
+ }
13748
+ return false;
13749
+ }
14722
13750
  function isPointOverNavigation(x, y) {
14723
13751
  const roots = /* @__PURE__ */ new Set();
14724
13752
  const navRoot = document.querySelector("[data-ohw-nav-root]") ?? document.querySelector("nav");
@@ -14807,7 +13835,7 @@ function getNavigationSelectionParent(el) {
14807
13835
  if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
14808
13836
  return getFooterLinksContainer();
14809
13837
  }
14810
- 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)) {
13838
+ if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
14811
13839
  return getNavigationRoot(el);
14812
13840
  }
14813
13841
  return null;
@@ -15053,7 +14081,7 @@ function EditGlowChrome({
15053
14081
  hideHandle = false
15054
14082
  }) {
15055
14083
  const GAP = SELECTION_CHROME_GAP2;
15056
- return /* @__PURE__ */ jsxs21(
14084
+ return /* @__PURE__ */ jsxs20(
15057
14085
  "div",
15058
14086
  {
15059
14087
  ref: elRef,
@@ -15068,7 +14096,7 @@ function EditGlowChrome({
15068
14096
  zIndex: 2147483646
15069
14097
  },
15070
14098
  children: [
15071
- /* @__PURE__ */ jsx34(
14099
+ /* @__PURE__ */ jsx33(
15072
14100
  "div",
15073
14101
  {
15074
14102
  style: {
@@ -15081,7 +14109,7 @@ function EditGlowChrome({
15081
14109
  }
15082
14110
  }
15083
14111
  ),
15084
- reorderHrefKey && !hideHandle && /* @__PURE__ */ jsx34(
14112
+ reorderHrefKey && !hideHandle && /* @__PURE__ */ jsx33(
15085
14113
  "div",
15086
14114
  {
15087
14115
  "data-ohw-drag-handle-container": "",
@@ -15093,7 +14121,7 @@ function EditGlowChrome({
15093
14121
  transform: "translate(calc(-100% - 7px), -50%)",
15094
14122
  pointerEvents: dragDisabled ? "none" : "auto"
15095
14123
  },
15096
- children: /* @__PURE__ */ jsx34(
14124
+ children: /* @__PURE__ */ jsx33(
15097
14125
  DragHandle,
15098
14126
  {
15099
14127
  "aria-label": `Reorder ${reorderHrefKey}`,
@@ -15303,7 +14331,7 @@ function FloatingToolbar({
15303
14331
  return () => ro.disconnect();
15304
14332
  }, [showEditLink, activeCommands]);
15305
14333
  const { top, left, transform } = calcToolbarPos(rect, parentScroll, measuredW);
15306
- return /* @__PURE__ */ jsx34(
14334
+ return /* @__PURE__ */ jsx33(
15307
14335
  "div",
15308
14336
  {
15309
14337
  ref: setRefs,
@@ -15315,12 +14343,12 @@ function FloatingToolbar({
15315
14343
  zIndex: 2147483647,
15316
14344
  pointerEvents: "auto"
15317
14345
  },
15318
- children: /* @__PURE__ */ jsxs21(CustomToolbar, { children: [
15319
- TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs21(React11.Fragment, { children: [
15320
- gi > 0 && /* @__PURE__ */ jsx34(CustomToolbarDivider, {}),
14346
+ children: /* @__PURE__ */ jsxs20(CustomToolbar, { children: [
14347
+ TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs20(React11.Fragment, { children: [
14348
+ gi > 0 && /* @__PURE__ */ jsx33(CustomToolbarDivider, {}),
15321
14349
  btns.map((btn) => {
15322
14350
  const isActive = activeCommands.has(btn.cmd);
15323
- return /* @__PURE__ */ jsx34(
14351
+ return /* @__PURE__ */ jsx33(
15324
14352
  CustomToolbarButton,
15325
14353
  {
15326
14354
  title: btn.title,
@@ -15329,7 +14357,7 @@ function FloatingToolbar({
15329
14357
  e.preventDefault();
15330
14358
  onCommand(btn.cmd);
15331
14359
  },
15332
- children: /* @__PURE__ */ jsx34(
14360
+ children: /* @__PURE__ */ jsx33(
15333
14361
  "svg",
15334
14362
  {
15335
14363
  width: "16",
@@ -15350,7 +14378,7 @@ function FloatingToolbar({
15350
14378
  );
15351
14379
  })
15352
14380
  ] }, gi)),
15353
- showEditLink ? /* @__PURE__ */ jsx34(
14381
+ showEditLink ? /* @__PURE__ */ jsx33(
15354
14382
  CustomToolbarButton,
15355
14383
  {
15356
14384
  type: "button",
@@ -15364,7 +14392,7 @@ function FloatingToolbar({
15364
14392
  e.preventDefault();
15365
14393
  e.stopPropagation();
15366
14394
  },
15367
- children: /* @__PURE__ */ jsx34(Link3, { className: "size-4 shrink-0", "aria-hidden": true })
14395
+ children: /* @__PURE__ */ jsx33(Link2, { className: "size-4 shrink-0", "aria-hidden": true })
15368
14396
  }
15369
14397
  ) : null
15370
14398
  ] })
@@ -15381,7 +14409,7 @@ function StateToggle({
15381
14409
  states,
15382
14410
  onStateChange
15383
14411
  }) {
15384
- return /* @__PURE__ */ jsx34(
14412
+ return /* @__PURE__ */ jsx33(
15385
14413
  ToggleGroup,
15386
14414
  {
15387
14415
  "data-ohw-state-toggle": "",
@@ -15395,50 +14423,11 @@ function StateToggle({
15395
14423
  left: rect.right - 8,
15396
14424
  transform: "translateX(-100%)"
15397
14425
  },
15398
- children: states.map((state) => /* @__PURE__ */ jsx34(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
14426
+ children: states.map((state) => /* @__PURE__ */ jsx33(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
15399
14427
  }
15400
14428
  );
15401
14429
  }
15402
14430
  var contentCache = /* @__PURE__ */ new Map();
15403
- var fetchedContentPaths = /* @__PURE__ */ new Set();
15404
- var OHW_LOADER_STYLE = {
15405
- position: "fixed",
15406
- inset: 0,
15407
- background: "#fff",
15408
- zIndex: 2147483646,
15409
- display: "flex",
15410
- alignItems: "center",
15411
- justifyContent: "center"
15412
- };
15413
- function OhwLoaderSpinner() {
15414
- return /* @__PURE__ */ jsxs21("svg", { width: "28", height: "28", viewBox: "0 0 28 28", fill: "none", "aria-hidden": true, children: [
15415
- /* @__PURE__ */ jsx34("circle", { cx: "14", cy: "14", r: "11", stroke: "#E7E5E4", strokeWidth: "3" }),
15416
- /* @__PURE__ */ jsx34(
15417
- "circle",
15418
- {
15419
- cx: "14",
15420
- cy: "14",
15421
- r: "11",
15422
- stroke: "#1C1917",
15423
- strokeWidth: "3",
15424
- strokeDasharray: "17 52",
15425
- strokeLinecap: "round",
15426
- children: /* @__PURE__ */ jsx34(
15427
- "animateTransform",
15428
- {
15429
- attributeName: "transform",
15430
- type: "rotate",
15431
- from: "0 14 14",
15432
- to: "360 14 14",
15433
- dur: "0.7s",
15434
- repeatCount: "indefinite"
15435
- }
15436
- )
15437
- }
15438
- )
15439
- ] });
15440
- }
15441
- 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){}})();`;
15442
14431
  function resolveSubdomain(subdomainFromQuery) {
15443
14432
  if (subdomainFromQuery) return subdomainFromQuery;
15444
14433
  if (typeof window !== "undefined") {
@@ -15461,8 +14450,8 @@ function OhhwellsBridge() {
15461
14450
  const router = useRouter3();
15462
14451
  const searchParams = useSearchParams();
15463
14452
  const isEditMode = isEditSessionActive();
15464
- const [bridgeRoot, setBridgeRoot] = useState12(null);
15465
- useEffect13(() => {
14453
+ const [bridgeRoot, setBridgeRoot] = useState11(null);
14454
+ useEffect12(() => {
15466
14455
  const figtreeFontId = "ohw-figtree-font";
15467
14456
  if (!document.getElementById(figtreeFontId)) {
15468
14457
  const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
@@ -15491,82 +14480,82 @@ function OhhwellsBridge() {
15491
14480
  const subdomain = resolveSubdomain(subdomainFromQuery);
15492
14481
  useLinkHrefGuardian(pathname, subdomain, isEditMode);
15493
14482
  useSavedLinkNavigation(isEditMode);
15494
- const postToParent2 = useCallback8((data) => {
14483
+ const postToParent2 = useCallback7((data) => {
15495
14484
  if (typeof window !== "undefined" && window.parent !== window) {
15496
14485
  window.parent.postMessage(data, "*");
15497
14486
  }
15498
14487
  }, []);
15499
- const [fetchState, setFetchState] = useState12("idle");
15500
- const autoSaveTimers = useRef10(/* @__PURE__ */ new Map());
15501
- const activeElRef = useRef10(null);
15502
- const pointerHeldRef = useRef10(false);
15503
- const selectedElRef = useRef10(null);
15504
- const selectedHrefKeyRef = useRef10(null);
15505
- const selectedFooterColAttrRef = useRef10(null);
15506
- const originalContentRef = useRef10(null);
15507
- const activeStateElRef = useRef10(null);
15508
- const parentScrollRef = useRef10(null);
15509
- const visibleViewportRef = useRef10(null);
15510
- const [dialogPortalContainer, setDialogPortalContainer] = useState12(null);
15511
- const attachVisibleViewport = useCallback8((node) => {
14488
+ const [fetchState, setFetchState] = useState11("idle");
14489
+ const autoSaveTimers = useRef9(/* @__PURE__ */ new Map());
14490
+ const activeElRef = useRef9(null);
14491
+ const pointerHeldRef = useRef9(false);
14492
+ const selectedElRef = useRef9(null);
14493
+ const selectedHrefKeyRef = useRef9(null);
14494
+ const selectedFooterColAttrRef = useRef9(null);
14495
+ const originalContentRef = useRef9(null);
14496
+ const activeStateElRef = useRef9(null);
14497
+ const parentScrollRef = useRef9(null);
14498
+ const visibleViewportRef = useRef9(null);
14499
+ const [dialogPortalContainer, setDialogPortalContainer] = useState11(null);
14500
+ const attachVisibleViewport = useCallback7((node) => {
15512
14501
  visibleViewportRef.current = node;
15513
14502
  setDialogPortalContainer(node);
15514
14503
  if (node) applyVisibleViewport(node, parentScrollRef.current);
15515
14504
  }, []);
15516
- const toolbarElRef = useRef10(null);
15517
- const glowElRef = useRef10(null);
15518
- const hoveredImageRef = useRef10(null);
15519
- const hoveredImageHasTextOverlapRef = useRef10(false);
15520
- const dragOverElRef = useRef10(null);
15521
- const [mediaHover, setMediaHover] = useState12(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(() => {
14505
+ const toolbarElRef = useRef9(null);
14506
+ const glowElRef = useRef9(null);
14507
+ const hoveredImageRef = useRef9(null);
14508
+ const hoveredImageHasTextOverlapRef = useRef9(false);
14509
+ const dragOverElRef = useRef9(null);
14510
+ const [mediaHover, setMediaHover] = useState11(null);
14511
+ const [carouselHover, setCarouselHover] = useState11(null);
14512
+ const [uploadingRects, setUploadingRects] = useState11({});
14513
+ const hoveredGapRef = useRef9(null);
14514
+ const imageUnhoverTimerRef = useRef9(null);
14515
+ const imageShowTimerRef = useRef9(null);
14516
+ const editStylesRef = useRef9(null);
14517
+ const activateRef = useRef9(() => {
15529
14518
  });
15530
- const deactivateRef = useRef10(() => {
14519
+ const deactivateRef = useRef9(() => {
15531
14520
  });
15532
- const selectRef = useRef10(() => {
14521
+ const selectRef = useRef9(() => {
15533
14522
  });
15534
- const selectFrameRef = useRef10(() => {
14523
+ const selectFrameRef = useRef9(() => {
15535
14524
  });
15536
- const selectLogoRef = useRef10(() => {
14525
+ const selectLogoRef = useRef9(() => {
15537
14526
  });
15538
- const openLogoSizePanelRef = useRef10(() => {
14527
+ const openLogoSizePanelRef = useRef9(() => {
15539
14528
  });
15540
- const deselectRef = useRef10(() => {
14529
+ const deselectRef = useRef9(() => {
15541
14530
  });
15542
- const closeFloatingPanelOnlyRef = useRef10(() => {
14531
+ const closeFloatingPanelOnlyRef = useRef9(() => {
15543
14532
  });
15544
- const reselectNavigationItemRef = useRef10(() => {
14533
+ const reselectNavigationItemRef = useRef9(() => {
15545
14534
  });
15546
- const commitNavigationTextEditRef = useRef10(() => {
14535
+ const commitNavigationTextEditRef = useRef9(() => {
15547
14536
  });
15548
- const handleDeleteSelectedRef = useRef10(() => false);
15549
- const runPendingDeleteUndoRef = useRef10(() => false);
15550
- const isFooterFrameSelectionRef = useRef10(false);
15551
- const refreshActiveCommandsRef = useRef10(() => {
14537
+ const handleDeleteSelectedRef = useRef9(() => false);
14538
+ const runPendingDeleteUndoRef = useRef9(() => false);
14539
+ const isFooterFrameSelectionRef = useRef9(false);
14540
+ const refreshActiveCommandsRef = useRef9(() => {
15552
14541
  });
15553
- const postToParentRef = useRef10(postToParent2);
14542
+ const postToParentRef = useRef9(postToParent2);
15554
14543
  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(() => {
14544
+ const aiSectionApiRef = useRef9(null);
14545
+ const sectionsLoadedRef = useRef9(false);
14546
+ const pendingScheduleConfigRequests = useRef9([]);
14547
+ const [toolbarRect, setToolbarRect] = useState11(null);
14548
+ const [formPickRect, setFormPickRect] = useState11(null);
14549
+ const formPickElRef = useRef9(null);
14550
+ const [formViewState, setFormViewStateUi] = useState11("default");
14551
+ const [formPickCount, setFormPickCount] = useState11(null);
14552
+ const [formHoverRect, setFormHoverRect] = useState11(null);
14553
+ const formHoverElRef = useRef9(null);
14554
+ const [fieldPickRect, setFieldPickRect] = useState11(null);
14555
+ const fieldPickElRef = useRef9(null);
14556
+ const [fieldPickState, setFieldPickState] = useState11(null);
14557
+ const [fieldTypePickerOpen, setFieldTypePickerOpen] = useState11(false);
14558
+ const clearFormPick = useCallback7(() => {
15570
14559
  const form = formPickElRef.current;
15571
14560
  const editing = fieldPickElRef.current;
15572
14561
  if (commitPlaceholderEdit(editing) && editing) {
@@ -15586,7 +14575,7 @@ function OhhwellsBridge() {
15586
14575
  formPickElRef.current = null;
15587
14576
  setFormPickRect(null);
15588
14577
  }, []);
15589
- const clearFieldPick = useCallback8(() => {
14578
+ const clearFieldPick = useCallback7(() => {
15590
14579
  const wrapper = fieldPickElRef.current;
15591
14580
  if (commitPlaceholderEdit(wrapper) && wrapper) {
15592
14581
  const form = wrapper.closest('[data-ohw-editable="form"]');
@@ -15596,9 +14585,9 @@ function OhhwellsBridge() {
15596
14585
  setFieldPickRect(null);
15597
14586
  setFieldPickState(null);
15598
14587
  }, []);
15599
- const persistFieldsRef = useRef10(() => {
14588
+ const persistFieldsRef = useRef9(() => {
15600
14589
  });
15601
- const persistFields = useCallback8(
14590
+ const persistFields = useCallback7(
15602
14591
  (form) => {
15603
14592
  const key = formKeyOf(form);
15604
14593
  if (!key) return;
@@ -15609,7 +14598,7 @@ function OhhwellsBridge() {
15609
14598
  []
15610
14599
  );
15611
14600
  persistFieldsRef.current = persistFields;
15612
- const selectField = useCallback8((wrapper) => {
14601
+ const selectField = useCallback7((wrapper) => {
15613
14602
  if (fieldPickElRef.current && fieldPickElRef.current !== wrapper) {
15614
14603
  commitPlaceholderEdit(fieldPickElRef.current);
15615
14604
  }
@@ -15622,7 +14611,7 @@ function OhhwellsBridge() {
15622
14611
  setFieldPickState({ type: fieldTypeOf(wrapper), required: isFieldRequired(wrapper) });
15623
14612
  setFieldTypePickerOpen(false);
15624
14613
  }, []);
15625
- const withSelectedField = useCallback8(
14614
+ const withSelectedField = useCallback7(
15626
14615
  (run) => {
15627
14616
  const wrapper = fieldPickElRef.current;
15628
14617
  const form = formPickElRef.current;
@@ -15635,28 +14624,28 @@ function OhhwellsBridge() {
15635
14624
  },
15636
14625
  [persistFields]
15637
14626
  );
15638
- const handleFieldTypeChange = useCallback8(
14627
+ const handleFieldTypeChange = useCallback7(
15639
14628
  (type) => withSelectedField((_form, wrapper) => {
15640
14629
  applyFieldType(wrapper, type);
15641
14630
  selectField(wrapper);
15642
14631
  }),
15643
14632
  [selectField, withSelectedField]
15644
14633
  );
15645
- const handleFieldRequiredToggle = useCallback8(
14634
+ const handleFieldRequiredToggle = useCallback7(
15646
14635
  () => withSelectedField((_form, wrapper) => {
15647
14636
  setFieldRequired(wrapper, !isFieldRequired(wrapper));
15648
14637
  selectField(wrapper);
15649
14638
  }),
15650
14639
  [selectField, withSelectedField]
15651
14640
  );
15652
- const handleFieldDuplicate = useCallback8(
14641
+ const handleFieldDuplicate = useCallback7(
15653
14642
  () => withSelectedField((form, wrapper) => {
15654
14643
  const copy = duplicateField(form, wrapper);
15655
14644
  selectField(copy);
15656
14645
  }),
15657
14646
  [selectField, withSelectedField]
15658
14647
  );
15659
- const handleFieldDelete = useCallback8(
14648
+ const handleFieldDelete = useCallback7(
15660
14649
  () => withSelectedField((_form, wrapper) => {
15661
14650
  removeField(wrapper);
15662
14651
  clearFieldPick();
@@ -15664,7 +14653,7 @@ function OhhwellsBridge() {
15664
14653
  }),
15665
14654
  [clearFieldPick, withSelectedField]
15666
14655
  );
15667
- const handleAddField = useCallback8(
14656
+ const handleAddField = useCallback7(
15668
14657
  (type) => {
15669
14658
  const form = formPickElRef.current;
15670
14659
  if (!form) return;
@@ -15680,8 +14669,8 @@ function OhhwellsBridge() {
15680
14669
  },
15681
14670
  [persistFields, selectField]
15682
14671
  );
15683
- const fieldDragRef = useRef10(null);
15684
- const buildFieldDropSlots = useCallback8((form, draggedKey) => {
14672
+ const fieldDragRef = useRef9(null);
14673
+ const buildFieldDropSlots = useCallback7((form, draggedKey) => {
15685
14674
  const others = listFieldWrappers(form).filter((el) => fieldKeyOf(el) !== draggedKey);
15686
14675
  const slots = others.map((el) => {
15687
14676
  const rect = el.getBoundingClientRect();
@@ -15694,7 +14683,7 @@ function OhhwellsBridge() {
15694
14683
  }
15695
14684
  return slots;
15696
14685
  }, []);
15697
- const handleFieldDragStart = useCallback8(() => {
14686
+ const handleFieldDragStart = useCallback7(() => {
15698
14687
  const wrapper = fieldPickElRef.current;
15699
14688
  const form = formPickElRef.current;
15700
14689
  if (!wrapper || !form) return;
@@ -15703,18 +14692,18 @@ function OhhwellsBridge() {
15703
14692
  setFieldDragging(true);
15704
14693
  setFieldDropSlots(buildFieldDropSlots(form, key));
15705
14694
  }, [buildFieldDropSlots]);
15706
- const handleFieldDragEnd = useCallback8(() => {
14695
+ const handleFieldDragEnd = useCallback7(() => {
15707
14696
  fieldDragRef.current = null;
15708
14697
  setFieldDropIndex(null);
15709
14698
  setFieldDropSlots([]);
15710
14699
  setFieldDragging(false);
15711
14700
  }, []);
15712
- const [fieldDropIndex, setFieldDropIndex] = useState12(null);
15713
- const [fieldDropSlots, setFieldDropSlots] = useState12([]);
15714
- const [fieldDragging, setFieldDragging] = useState12(false);
15715
- const clearFormPickRef = useRef10(clearFormPick);
14701
+ const [fieldDropIndex, setFieldDropIndex] = useState11(null);
14702
+ const [fieldDropSlots, setFieldDropSlots] = useState11([]);
14703
+ const [fieldDragging, setFieldDragging] = useState11(false);
14704
+ const clearFormPickRef = useRef9(clearFormPick);
15716
14705
  clearFormPickRef.current = clearFormPick;
15717
- useEffect13(() => {
14706
+ useEffect12(() => {
15718
14707
  const el = fieldPickElRef.current;
15719
14708
  if (!el || fieldPickRect === null) return;
15720
14709
  const observer = new ResizeObserver(() => {
@@ -15723,7 +14712,7 @@ function OhhwellsBridge() {
15723
14712
  observer.observe(el);
15724
14713
  return () => observer.disconnect();
15725
14714
  }, [fieldPickRect !== null, fieldPickState]);
15726
- useEffect13(() => {
14715
+ useEffect12(() => {
15727
14716
  const el = formPickElRef.current;
15728
14717
  if (!el || formPickRect === null) return;
15729
14718
  const observer = new ResizeObserver(() => {
@@ -15732,25 +14721,25 @@ function OhhwellsBridge() {
15732
14721
  observer.observe(el);
15733
14722
  return () => observer.disconnect();
15734
14723
  }, [formPickRect !== null, formViewState]);
15735
- const [toolbarVariant, setToolbarVariant] = useState12("none");
15736
- const toolbarVariantRef = useRef10("none");
14724
+ const [toolbarVariant, setToolbarVariant] = useState11("none");
14725
+ const toolbarVariantRef = useRef9("none");
15737
14726
  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(() => {
14727
+ const [selectedIsCta, setSelectedIsCta] = useState11(false);
14728
+ const [selectedIsSocial, setSelectedIsSocial] = useState11(false);
14729
+ const [selectedIsSocialsRow, setSelectedIsSocialsRow] = useState11(false);
14730
+ const [reorderHrefKey, setReorderHrefKey] = useState11(null);
14731
+ const [reorderDragDisabled, setReorderDragDisabled] = useState11(false);
14732
+ const [toggleState, setToggleState] = useState11(null);
14733
+ const [maxBadge, setMaxBadge] = useState11(null);
14734
+ const [activeCommands, setActiveCommands] = useState11(/* @__PURE__ */ new Set());
14735
+ const [sectionGap, setSectionGap] = useState11(null);
14736
+ const [toolbarShowEditLink, setToolbarShowEditLink] = useState11(false);
14737
+ const hoveredNavContainerRef = useRef9(null);
14738
+ const [hoveredNavContainerRect, setHoveredNavContainerRect] = useState11(null);
14739
+ const hoveredItemElRef = useRef9(null);
14740
+ const [hoveredItemRect, setHoveredItemRect] = useState11(null);
14741
+ const [hoveredTextRect, setHoveredTextRect] = useState11(null);
14742
+ useEffect12(() => {
15754
14743
  const sync = () => {
15755
14744
  const el = document.querySelector(
15756
14745
  '[data-ohw-hovered]:not([contenteditable]):not([data-ohw-href-key]):not([data-ohw-editable="form"] *)'
@@ -15771,56 +14760,43 @@ function OhhwellsBridge() {
15771
14760
  });
15772
14761
  return () => observer.disconnect();
15773
14762
  }, []);
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);
14763
+ const siblingHintElRef = useRef9(null);
14764
+ const [siblingHintRect, setSiblingHintRect] = useState11(null);
14765
+ const [siblingHintRects, setSiblingHintRects] = useState11([]);
14766
+ const [isItemDragging, setIsItemDragging] = useState11(false);
14767
+ const [isFooterFrameSelection, setIsFooterFrameSelection] = useState11(false);
15779
14768
  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);
14769
+ const [floatingPanel, setFloatingPanel] = useState11(null);
14770
+ const floatingPanelOpenRef = useRef9(false);
14771
+ floatingPanelOpenRef.current = floatingPanel !== null;
14772
+ const [floatingPanelPos, setFloatingPanelPos] = useState11(null);
14773
+ const [logoSizeDraft, setLogoSizeDraft] = useState11(null);
14774
+ const [editorViewport, setEditorViewport] = useState11("desktop");
14775
+ const [parentScrollSnap, setParentScrollSnap] = useState11(null);
14776
+ const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = useState11(null);
14777
+ const [footerHeadingVisible, setFooterHeadingVisible] = useState11(null);
14778
+ const footerDragRef = useRef9(null);
14779
+ const [footerDropSlots, setFooterDropSlots] = useState11([]);
14780
+ const [activeFooterDropIndex, setActiveFooterDropIndex] = useState11(null);
14781
+ const [draggedItemRect, setDraggedItemRect] = useState11(null);
14782
+ const footerPointerDragRef = useRef9(null);
14783
+ const suppressNextClickRef = useRef9(false);
14784
+ const suppressClickUntilRef = useRef9(0);
14785
+ const [linkPopover, setLinkPopover] = useState11(null);
14786
+ const linkPopoverSessionRef = useRef9(null);
14787
+ const addNavAfterAnchorRef = useRef9(null);
14788
+ const editContentRef = useRef9({});
14789
+ const aiSectionsRef = useRef9("");
14790
+ const pendingDeleteUndoRef = useRef9(null);
14791
+ const [sitePages, setSitePages] = useState11([]);
14792
+ const [sectionsByPath, setSectionsByPath] = useState11({});
14793
+ const sectionsPrefetchGenRef = useRef9(0);
14794
+ const setLinkPopoverRef = useRef9(setLinkPopover);
14795
+ const linkPopoverPanelRef = useRef9(null);
14796
+ const linkPopoverOpenRef = useRef9(false);
14797
+ const linkPopoverGraceUntilRef = useRef9(0);
15811
14798
  setLinkPopoverRef.current = setLinkPopover;
15812
- setFloatingPanelRef.current = setFloatingPanel;
15813
14799
  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
14800
  const {
15825
14801
  navDragRef,
15826
14802
  navDropSlots,
@@ -15853,20 +14829,10 @@ function OhhwellsBridge() {
15853
14829
  getNavigationItemAnchor,
15854
14830
  isDragHandleDisabled
15855
14831
  });
15856
- const { sectionDropSlots, activeSectionDropIndex, isSectionDragging } = useSectionDrag({
15857
- isEditMode,
15858
- editContentRef,
15859
- postToParentRef,
15860
- parentScrollRef,
15861
- navDragRef,
15862
- footerDragRef,
15863
- suppressNextClickRef,
15864
- suppressClickUntilRef
15865
- });
15866
14832
  const bumpLinkPopoverGrace = () => {
15867
14833
  linkPopoverGraceUntilRef.current = Date.now() + 350;
15868
14834
  };
15869
- const runSectionsPrefetch = useCallback8((pages) => {
14835
+ const runSectionsPrefetch = useCallback7((pages) => {
15870
14836
  if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
15871
14837
  const gen = ++sectionsPrefetchGenRef.current;
15872
14838
  const paths = pages.map((p) => p.path);
@@ -15885,9 +14851,9 @@ function OhhwellsBridge() {
15885
14851
  );
15886
14852
  });
15887
14853
  }, [isEditMode, pathname]);
15888
- const runSectionsPrefetchRef = useRef10(runSectionsPrefetch);
14854
+ const runSectionsPrefetchRef = useRef9(runSectionsPrefetch);
15889
14855
  runSectionsPrefetchRef.current = runSectionsPrefetch;
15890
- useEffect13(() => {
14856
+ useEffect12(() => {
15891
14857
  if (!linkPopover) {
15892
14858
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
15893
14859
  return;
@@ -15915,7 +14881,7 @@ function OhhwellsBridge() {
15915
14881
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
15916
14882
  };
15917
14883
  }, [linkPopover, postToParent2]);
15918
- useEffect13(() => {
14884
+ useEffect12(() => {
15919
14885
  if (!isEditMode) return;
15920
14886
  const useFixtures = shouldUseDevFixtures();
15921
14887
  if (useFixtures) {
@@ -15939,14 +14905,14 @@ function OhhwellsBridge() {
15939
14905
  if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
15940
14906
  return () => window.removeEventListener("message", onSitePages);
15941
14907
  }, [isEditMode, postToParent2]);
15942
- useEffect13(() => {
14908
+ useEffect12(() => {
15943
14909
  if (!isEditMode || shouldUseDevFixtures()) return;
15944
14910
  void loadAllSectionsManifest().then((manifest) => {
15945
14911
  if (Object.keys(manifest).length === 0) return;
15946
14912
  setSectionsByPath((prev) => ({ ...manifest, ...prev }));
15947
14913
  });
15948
14914
  }, [isEditMode]);
15949
- useEffect13(() => {
14915
+ useEffect12(() => {
15950
14916
  const update = () => {
15951
14917
  const el = activeElRef.current ?? selectedElRef.current;
15952
14918
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
@@ -15970,10 +14936,10 @@ function OhhwellsBridge() {
15970
14936
  vvp.removeEventListener("resize", update);
15971
14937
  };
15972
14938
  }, []);
15973
- const refreshStateRules = useCallback8(() => {
14939
+ const refreshStateRules = useCallback7(() => {
15974
14940
  editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
15975
14941
  }, []);
15976
- const processConfigRequest = useCallback8((insertAfterVal) => {
14942
+ const processConfigRequest = useCallback7((insertAfterVal) => {
15977
14943
  const tracker = getSectionsTracker();
15978
14944
  let entries = [];
15979
14945
  try {
@@ -15996,7 +14962,7 @@ function OhhwellsBridge() {
15996
14962
  }
15997
14963
  window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
15998
14964
  }, [isEditMode]);
15999
- const deactivate = useCallback8(() => {
14965
+ const deactivate = useCallback7(() => {
16000
14966
  const el = activeElRef.current;
16001
14967
  if (!el) return;
16002
14968
  const isFormBlock = el.dataset.ohwEditable === "form";
@@ -16037,12 +15003,12 @@ function OhhwellsBridge() {
16037
15003
  setToolbarShowEditLink(false);
16038
15004
  postToParent2({ type: "ow:exit-edit" });
16039
15005
  }, [postToParent2]);
16040
- const clearSelectedAttr = useCallback8(() => {
15006
+ const clearSelectedAttr = useCallback7(() => {
16041
15007
  document.querySelectorAll("[data-ohw-selected]").forEach((el) => {
16042
15008
  el.removeAttribute("data-ohw-selected");
16043
15009
  });
16044
15010
  }, []);
16045
- const deselect = useCallback8(() => {
15011
+ const deselect = useCallback7(() => {
16046
15012
  clearSelectedAttr();
16047
15013
  selectedElRef.current = null;
16048
15014
  selectedHrefKeyRef.current = null;
@@ -16071,11 +15037,11 @@ function OhhwellsBridge() {
16071
15037
  setToolbarVariant("none");
16072
15038
  }
16073
15039
  }, [clearSelectedAttr]);
16074
- const markSelected = useCallback8((el) => {
15040
+ const markSelected = useCallback7((el) => {
16075
15041
  clearSelectedAttr();
16076
15042
  el.setAttribute("data-ohw-selected", "");
16077
15043
  }, [clearSelectedAttr]);
16078
- const resolveHrefKeyElement = useCallback8((hrefKey) => {
15044
+ const resolveHrefKeyElement = useCallback7((hrefKey) => {
16079
15045
  if (isFooterHrefKey(hrefKey)) {
16080
15046
  return document.querySelector(
16081
15047
  `footer [data-ohw-href-key="${CSS.escape(hrefKey)}"]`
@@ -16090,7 +15056,7 @@ function OhhwellsBridge() {
16090
15056
  `[data-ohw-href-key="${CSS.escape(hrefKey)}"]`
16091
15057
  );
16092
15058
  }, []);
16093
- const resyncSelectedNavigationItem = useCallback8(() => {
15059
+ const resyncSelectedNavigationItem = useCallback7(() => {
16094
15060
  const hrefKey = selectedHrefKeyRef.current;
16095
15061
  if (hrefKey) {
16096
15062
  const link = resolveHrefKeyElement(hrefKey);
@@ -16128,7 +15094,7 @@ function OhhwellsBridge() {
16128
15094
  );
16129
15095
  }
16130
15096
  }, [resolveHrefKeyElement]);
16131
- const reselectNavigationItem = useCallback8((navAnchor) => {
15097
+ const reselectNavigationItem = useCallback7((navAnchor) => {
16132
15098
  selectedElRef.current = navAnchor;
16133
15099
  selectedHrefKeyRef.current = navAnchor.getAttribute("data-ohw-href-key");
16134
15100
  selectedFooterColAttrRef.current = null;
@@ -16159,7 +15125,7 @@ function OhhwellsBridge() {
16159
15125
  setToolbarShowEditLink(false);
16160
15126
  setActiveCommands(/* @__PURE__ */ new Set());
16161
15127
  }, [markSelected]);
16162
- const commitNavigationTextEdit = useCallback8((navAnchor) => {
15128
+ const commitNavigationTextEdit = useCallback7((navAnchor) => {
16163
15129
  const el = activeElRef.current;
16164
15130
  if (!el) return;
16165
15131
  const key = el.dataset.ohwKey;
@@ -16192,7 +15158,7 @@ function OhhwellsBridge() {
16192
15158
  postToParent2({ type: "ow:exit-edit" });
16193
15159
  reselectNavigationItem(navAnchor);
16194
15160
  }, [postToParent2, reselectNavigationItem]);
16195
- const handleAddTopLevelNavItem = useCallback8(() => {
15161
+ const handleAddTopLevelNavItem = useCallback7(() => {
16196
15162
  const items = listNavbarRootItems();
16197
15163
  addNavAfterAnchorRef.current = items[items.length - 1] ?? null;
16198
15164
  deselectRef.current();
@@ -16204,7 +15170,7 @@ function OhhwellsBridge() {
16204
15170
  intent: "add-nav"
16205
15171
  });
16206
15172
  }, []);
16207
- const maybeWarnNavLinkDropdownConflict = useCallback8(
15173
+ const maybeWarnNavLinkDropdownConflict = useCallback7(
16208
15174
  (anchor) => {
16209
15175
  if (!isNavbarHrefKey(anchor.getAttribute("data-ohw-href-key"))) return;
16210
15176
  if (!navDropdownsOpenOnClick()) return;
@@ -16217,7 +15183,7 @@ function OhhwellsBridge() {
16217
15183
  },
16218
15184
  [postToParent2]
16219
15185
  );
16220
- const handleNavDropdownOpenChange = useCallback8((open) => {
15186
+ const handleNavDropdownOpenChange = useCallback7((open) => {
16221
15187
  const selected = selectedElRef.current;
16222
15188
  if (!selected || !isNavigationItem2(selected)) return;
16223
15189
  setNavGroupForceOpen(selected, open);
@@ -16229,7 +15195,7 @@ function OhhwellsBridge() {
16229
15195
  }
16230
15196
  });
16231
15197
  }, []);
16232
- const handleFooterHeadingVisibleChange = useCallback8(
15198
+ const handleFooterHeadingVisibleChange = useCallback7(
16233
15199
  (visible) => {
16234
15200
  const selected = selectedElRef.current;
16235
15201
  if (!selected || !isFooterFrameSelectionRef.current) return;
@@ -16253,7 +15219,7 @@ function OhhwellsBridge() {
16253
15219
  },
16254
15220
  [postToParent2]
16255
15221
  );
16256
- const enterEditOnNewItem = useCallback8((anchor) => {
15222
+ const enterEditOnNewItem = useCallback7((anchor) => {
16257
15223
  const label = anchor.querySelector('[data-ohw-editable="text"]');
16258
15224
  if (!label) {
16259
15225
  selectRef.current(anchor);
@@ -16262,7 +15228,7 @@ function OhhwellsBridge() {
16262
15228
  setNavGroupForceOpen(anchor, true);
16263
15229
  activateRef.current(label);
16264
15230
  }, []);
16265
- const handleAddChildItem = useCallback8(() => {
15231
+ const handleAddChildItem = useCallback7(() => {
16266
15232
  const selected = selectedElRef.current;
16267
15233
  if (!selected) return;
16268
15234
  const socialsRow = isSocialsRow(selected) ? selected : findSocialsRow(selected);
@@ -16374,7 +15340,7 @@ function OhhwellsBridge() {
16374
15340
  enterEditOnNewItem(result.anchor);
16375
15341
  });
16376
15342
  }, [enterEditOnNewItem, isFooterFrameSelection, maybeWarnNavLinkDropdownConflict, postToParent2]);
16377
- const handleAddFooterColumn = useCallback8(() => {
15343
+ const handleAddFooterColumn = useCallback7(() => {
16378
15344
  if (!canAddFooterColumn()) {
16379
15345
  postToParent2({
16380
15346
  type: "ow:toast",
@@ -16395,7 +15361,7 @@ function OhhwellsBridge() {
16395
15361
  selectRef.current(result.firstLink);
16396
15362
  });
16397
15363
  }, [postToParent2]);
16398
- const clearFooterDragVisuals = useCallback8(() => {
15364
+ const clearFooterDragVisuals = useCallback7(() => {
16399
15365
  footerDragRef.current = null;
16400
15366
  setSiblingHintRects([]);
16401
15367
  setFooterDropSlots([]);
@@ -16404,7 +15370,7 @@ function OhhwellsBridge() {
16404
15370
  setIsItemDragging(false);
16405
15371
  unlockFooterDragInteraction();
16406
15372
  }, []);
16407
- const refreshFooterDragVisuals = useCallback8((session, activeSlot, clientX, clientY) => {
15373
+ const refreshFooterDragVisuals = useCallback7((session, activeSlot, clientX, clientY) => {
16408
15374
  const dragged = session.draggedEl;
16409
15375
  setDraggedItemRect(dragged.getBoundingClientRect());
16410
15376
  if (typeof clientX === "number" && typeof clientY === "number") {
@@ -16436,13 +15402,13 @@ function OhhwellsBridge() {
16436
15402
  const activeIdx = activeSlot ? slots.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
16437
15403
  setActiveFooterDropIndex(activeIdx >= 0 ? activeIdx : null);
16438
15404
  }, []);
16439
- const refreshFooterDragVisualsRef = useRef10(refreshFooterDragVisuals);
15405
+ const refreshFooterDragVisualsRef = useRef9(refreshFooterDragVisuals);
16440
15406
  refreshFooterDragVisualsRef.current = refreshFooterDragVisuals;
16441
- const commitFooterDragRef = useRef10(() => {
15407
+ const commitFooterDragRef = useRef9(() => {
16442
15408
  });
16443
- const beginFooterDragRef = useRef10(() => {
15409
+ const beginFooterDragRef = useRef9(() => {
16444
15410
  });
16445
- const beginFooterDrag = useCallback8(
15411
+ const beginFooterDrag = useCallback7(
16446
15412
  (session) => {
16447
15413
  const rect = session.draggedEl.getBoundingClientRect();
16448
15414
  session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
@@ -16462,7 +15428,7 @@ function OhhwellsBridge() {
16462
15428
  [refreshFooterDragVisuals]
16463
15429
  );
16464
15430
  beginFooterDragRef.current = beginFooterDrag;
16465
- const commitFooterDrag = useCallback8(
15431
+ const commitFooterDrag = useCallback7(
16466
15432
  (clientX, clientY) => {
16467
15433
  const session = footerDragRef.current;
16468
15434
  if (!session) {
@@ -16590,7 +15556,7 @@ function OhhwellsBridge() {
16590
15556
  [clearFooterDragVisuals, resolveHrefKeyElement, resyncSelectedNavigationItem]
16591
15557
  );
16592
15558
  commitFooterDragRef.current = commitFooterDrag;
16593
- const startFooterLinkDrag = useCallback8(
15559
+ const startFooterLinkDrag = useCallback7(
16594
15560
  (anchor, clientX, clientY, wasSelected) => {
16595
15561
  const hrefKey = anchor.getAttribute("data-ohw-href-key");
16596
15562
  if (!hrefKey) return false;
@@ -16626,7 +15592,7 @@ function OhhwellsBridge() {
16626
15592
  },
16627
15593
  [beginFooterDrag]
16628
15594
  );
16629
- const startFooterColumnDrag = useCallback8(
15595
+ const startFooterColumnDrag = useCallback7(
16630
15596
  (columnEl, clientX, clientY, wasSelected) => {
16631
15597
  const columns = listFooterColumns();
16632
15598
  const idx = columns.indexOf(columnEl);
@@ -16646,7 +15612,7 @@ function OhhwellsBridge() {
16646
15612
  },
16647
15613
  [beginFooterDrag]
16648
15614
  );
16649
- const handleItemDragStart = useCallback8(
15615
+ const handleItemDragStart = useCallback7(
16650
15616
  (e) => {
16651
15617
  const selected = selectedElRef.current;
16652
15618
  if (!selected) {
@@ -16666,7 +15632,7 @@ function OhhwellsBridge() {
16666
15632
  },
16667
15633
  [startFooterColumnDrag, startFooterLinkDrag, startNavLinkDrag]
16668
15634
  );
16669
- const handleItemDragEnd = useCallback8(
15635
+ const handleItemDragEnd = useCallback7(
16670
15636
  (e) => {
16671
15637
  if (footerDragRef.current) {
16672
15638
  const x = e?.clientX;
@@ -16692,7 +15658,7 @@ function OhhwellsBridge() {
16692
15658
  },
16693
15659
  [commitFooterDrag, commitNavDrag, navDragRef]
16694
15660
  );
16695
- const handleItemChromePointerDown = useCallback8((e) => {
15661
+ const handleItemChromePointerDown = useCallback7((e) => {
16696
15662
  if (e.button !== 0) return;
16697
15663
  const selected = selectedElRef.current;
16698
15664
  if (!selected) return;
@@ -16723,7 +15689,7 @@ function OhhwellsBridge() {
16723
15689
  }
16724
15690
  if (armNavPressFromChrome(selected, e.clientX, e.clientY, e.pointerId)) return;
16725
15691
  }, [armNavPressFromChrome]);
16726
- const handleItemChromeClick = useCallback8((clientX, clientY) => {
15692
+ const handleItemChromeClick = useCallback7((clientX, clientY) => {
16727
15693
  if (suppressNextClickRef.current || Date.now() < suppressClickUntilRef.current) {
16728
15694
  suppressNextClickRef.current = false;
16729
15695
  return;
@@ -16736,7 +15702,7 @@ function OhhwellsBridge() {
16736
15702
  }, []);
16737
15703
  reselectNavigationItemRef.current = reselectNavigationItem;
16738
15704
  commitNavigationTextEditRef.current = commitNavigationTextEdit;
16739
- const select = useCallback8((anchor) => {
15705
+ const select = useCallback7((anchor) => {
16740
15706
  if (!isNavigationItem2(anchor)) return;
16741
15707
  if (activeElRef.current) deactivate();
16742
15708
  aiSectionApiRef.current?.selectFromElement(anchor);
@@ -16779,7 +15745,7 @@ function OhhwellsBridge() {
16779
15745
  setFloatingPanel(null);
16780
15746
  setLogoSizeDraft(null);
16781
15747
  }, [deactivate, markSelected]);
16782
- const selectFrame = useCallback8((el) => {
15748
+ const selectFrame = useCallback7((el) => {
16783
15749
  if (!isNavigationContainer(el)) return;
16784
15750
  if (activeElRef.current) deactivate();
16785
15751
  aiSectionApiRef.current?.selectFromElement(el);
@@ -16830,7 +15796,7 @@ function OhhwellsBridge() {
16830
15796
  setFloatingPanel(null);
16831
15797
  setLogoSizeDraft(null);
16832
15798
  }, [deactivate, markSelected, postToParent2]);
16833
- const selectLogo = useCallback8(
15799
+ const selectLogo = useCallback7(
16834
15800
  (logoEl) => {
16835
15801
  if (activeElRef.current) deactivate();
16836
15802
  selectedElRef.current = logoEl;
@@ -16859,7 +15825,7 @@ function OhhwellsBridge() {
16859
15825
  },
16860
15826
  [deactivate, markSelected]
16861
15827
  );
16862
- const openLogoSizePanel = useCallback8((logoEl) => {
15828
+ const openLogoSizePanel = useCallback7((logoEl) => {
16863
15829
  const placement = getLogoPlacement(logoEl);
16864
15830
  const draft = readLogoSizeState(editContentRef.current, placement);
16865
15831
  setLogoSizeDraft(draft);
@@ -16872,7 +15838,7 @@ function OhhwellsBridge() {
16872
15838
  placement
16873
15839
  });
16874
15840
  }, []);
16875
- const openSocialsDisplayPanel = useCallback8((row) => {
15841
+ const openSocialsDisplayPanel = useCallback7((row) => {
16876
15842
  setParentScrollSnap(parentScrollRef.current);
16877
15843
  setFloatingPanel({
16878
15844
  key: "socials-display",
@@ -16882,7 +15848,7 @@ function OhhwellsBridge() {
16882
15848
  row
16883
15849
  });
16884
15850
  }, []);
16885
- const changeSocialsDisplay = useCallback8(
15851
+ const changeSocialsDisplay = useCallback7(
16886
15852
  (row, next) => {
16887
15853
  if (next.icon) {
16888
15854
  const missing = socialsMissingIcons(row);
@@ -16905,17 +15871,36 @@ function OhhwellsBridge() {
16905
15871
  },
16906
15872
  []
16907
15873
  );
16908
- const closeFloatingPanelOnly = useCallback8(() => {
15874
+ const closeFloatingPanelOnly = useCallback7(() => {
16909
15875
  setFloatingPanel(null);
16910
15876
  setLogoSizeDraft(null);
16911
15877
  }, []);
16912
15878
  closeFloatingPanelOnlyRef.current = closeFloatingPanelOnly;
16913
- const closeFloatingPanelAndDeselect = useCallback8(() => {
15879
+ const closeFloatingPanelAndDeselect = useCallback7(() => {
16914
15880
  setFloatingPanel(null);
16915
15881
  setLogoSizeDraft(null);
16916
15882
  deselectRef.current();
16917
15883
  }, []);
16918
- const persistLogoSizeDraft = useCallback8(
15884
+ useEffect12(() => {
15885
+ const session = floatingPanel && floatingPanel.kind === "logo-size" ? floatingPanel : null;
15886
+ if (!session || !logoSizeDraft) {
15887
+ postToParentRef.current({ type: "ow:logo-size-panel", open: false });
15888
+ return;
15889
+ }
15890
+ postToParentRef.current({
15891
+ type: "ow:logo-size-panel",
15892
+ open: true,
15893
+ title: session.title,
15894
+ context: session.context ?? "",
15895
+ placement: session.placement,
15896
+ viewport: editorViewport,
15897
+ mobileFollowing: logoSizeDraft.mobileFollowing,
15898
+ sizePx: editorViewport === "mobile" && !logoSizeDraft.mobileFollowing ? logoSizeDraft.mobilePx : logoSizeDraft.desktopPx,
15899
+ min: LOGO_SIZE_MIN,
15900
+ max: LOGO_SIZE_MAX
15901
+ });
15902
+ }, [floatingPanel, logoSizeDraft, editorViewport]);
15903
+ const persistLogoSizeDraft = useCallback7(
16919
15904
  (placement, draft) => {
16920
15905
  const desktopKey = LOGO_SIZE_DESKTOP_KEYS[placement];
16921
15906
  const mobileKey = LOGO_SIZE_MOBILE_KEYS[placement];
@@ -16955,7 +15940,7 @@ function OhhwellsBridge() {
16955
15940
  },
16956
15941
  [postToParent2]
16957
15942
  );
16958
- const activate = useCallback8((el, options) => {
15943
+ const activate = useCallback7((el, options) => {
16959
15944
  if (activeElRef.current === el) return;
16960
15945
  if (isIconEditable(el)) return;
16961
15946
  if (el.hasAttribute("data-ohw-social-label")) return;
@@ -17039,8 +16024,8 @@ function OhhwellsBridge() {
17039
16024
  openLogoSizePanelRef.current = openLogoSizePanel;
17040
16025
  deselectRef.current = deselect;
17041
16026
  closeFloatingPanelOnlyRef.current = closeFloatingPanelOnly;
17042
- const lastSiteWideScopeRef = useRef10(null);
17043
- useEffect13(() => {
16027
+ const lastSiteWideScopeRef = useRef9(null);
16028
+ useEffect12(() => {
17044
16029
  if (!isEditMode) {
17045
16030
  if (lastSiteWideScopeRef.current !== false) {
17046
16031
  lastSiteWideScopeRef.current = false;
@@ -17073,27 +16058,15 @@ function OhhwellsBridge() {
17073
16058
  }
17074
16059
  const applyContent = (content) => {
17075
16060
  const imageLoads = [];
17076
- if (typeof content[BRAND_KIT_KEY] === "string") {
17077
- brandKitRef.current = content[BRAND_KIT_KEY];
17078
- applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
17079
- }
17080
16061
  if (typeof content[AI_SECTIONS_KEY] === "string") {
17081
16062
  aiSectionsRef.current = content[AI_SECTIONS_KEY];
17082
16063
  applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
17083
16064
  }
17084
- if (typeof content[STYLE_STORE_KEY] === "string") {
17085
- stylesRef.current = content[STYLE_STORE_KEY];
17086
- applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
17087
- }
17088
- applyBrandChrome(content);
17089
16065
  for (const [key, val] of Object.entries(content)) {
17090
16066
  if (key === "__ohw_sections") continue;
17091
16067
  if (key === AI_SECTIONS_KEY) continue;
17092
16068
  if (key === LOGO_PLACEHOLDER_KEY) continue;
17093
16069
  if (LOGO_IMAGE_KEYS.includes(key)) continue;
17094
- if (key === BRAND_KIT_KEY) continue;
17095
- if (key === STYLE_STORE_KEY) continue;
17096
- if (BRAND_CHROME_KEYS.has(key)) continue;
17097
16070
  if (applyVideoSettingNode(key, val)) continue;
17098
16071
  if (applyCarouselNode(key, val)) continue;
17099
16072
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -17151,9 +16124,7 @@ function OhhwellsBridge() {
17151
16124
  let cancelled = false;
17152
16125
  setFetchState("loading");
17153
16126
  const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
17154
- const initialPath = pathname;
17155
- fetchedContentPaths.add(`${subdomain}::${initialPath}`);
17156
- fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(initialPath)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
16127
+ fetch(`${apiUrl}/api/public/sites/${subdomain}/content`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
17157
16128
  if (cancelled) return;
17158
16129
  const content = data?.content ?? {};
17159
16130
  contentCache.set(subdomain, content);
@@ -17166,7 +16137,7 @@ function OhhwellsBridge() {
17166
16137
  cancelled = true;
17167
16138
  };
17168
16139
  }, [subdomain, isEditMode]);
17169
- useEffect13(() => {
16140
+ useEffect12(() => {
17170
16141
  if (!isEditMode) return;
17171
16142
  const resolveIndex = (form, clientY) => {
17172
16143
  const wrappers = listFieldWrappers(form).filter((el) => fieldKeyOf(el) !== fieldDragRef.current?.key);
@@ -17207,7 +16178,7 @@ function OhhwellsBridge() {
17207
16178
  window.removeEventListener("drop", onDrop, true);
17208
16179
  };
17209
16180
  }, [buildFieldDropSlots, isEditMode, persistFields, selectField]);
17210
- useEffect13(() => {
16181
+ useEffect12(() => {
17211
16182
  if (!isEditMode) return;
17212
16183
  const mark = () => document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
17213
16184
  markFormFields(form);
@@ -17219,7 +16190,7 @@ function OhhwellsBridge() {
17219
16190
  });
17220
16191
  return () => observer.disconnect();
17221
16192
  }, [isEditMode, fetchState, pathname]);
17222
- useEffect13(() => {
16193
+ useEffect12(() => {
17223
16194
  if (!isEditMode) return;
17224
16195
  let saveTimer = null;
17225
16196
  const onInput = (e) => {
@@ -17241,14 +16212,14 @@ function OhhwellsBridge() {
17241
16212
  document.addEventListener("input", onInput, true);
17242
16213
  return () => document.removeEventListener("input", onInput, true);
17243
16214
  }, [isEditMode, persistFields]);
17244
- useEffect13(() => {
16215
+ useEffect12(() => {
17245
16216
  if (isEditMode || fetchState !== "done") return;
17246
16217
  const content = contentCache.get(subdomain) ?? {};
17247
16218
  document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
17248
16219
  reconcileFieldsFromContent(form, content);
17249
16220
  });
17250
16221
  }, [isEditMode, fetchState, subdomain]);
17251
- useEffect13(() => {
16222
+ useEffect12(() => {
17252
16223
  if (!isEditMode) return;
17253
16224
  const swallow = (e) => {
17254
16225
  const target = e.target;
@@ -17257,12 +16228,12 @@ function OhhwellsBridge() {
17257
16228
  document.addEventListener("submit", swallow, true);
17258
16229
  return () => document.removeEventListener("submit", swallow, true);
17259
16230
  }, [isEditMode]);
17260
- useEffect13(() => {
16231
+ useEffect12(() => {
17261
16232
  if (isEditMode || fetchState !== "done") return;
17262
16233
  const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
17263
16234
  bindPublishedForms(apiUrl, subdomain, contentCache.get(subdomain) ?? {});
17264
16235
  }, [isEditMode, fetchState, subdomain]);
17265
- useEffect13(() => {
16236
+ useEffect12(() => {
17266
16237
  if (!subdomain || isEditMode) return;
17267
16238
  let debounceTimer = null;
17268
16239
  let observer = null;
@@ -17273,21 +16244,10 @@ function OhhwellsBridge() {
17273
16244
  initSectionInstancesFromContent(content, window.location.pathname);
17274
16245
  observer?.disconnect();
17275
16246
  try {
17276
- applyBrandChrome(content);
17277
- if (typeof content[BRAND_KIT_KEY] === "string") {
17278
- applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
17279
- }
17280
- if (typeof content[STYLE_STORE_KEY] === "string") {
17281
- applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
17282
- }
17283
16247
  for (const [key, val] of Object.entries(content)) {
17284
16248
  if (key === "__ohw_sections") continue;
17285
16249
  if (key === LOGO_PLACEHOLDER_KEY) continue;
17286
16250
  if (LOGO_IMAGE_KEYS.includes(key)) continue;
17287
- if (key === BRAND_KIT_KEY) continue;
17288
- if (key === STYLE_STORE_KEY) continue;
17289
- if (key === STYLE_STORE_KEY) continue;
17290
- if (BRAND_CHROME_KEYS.has(key)) continue;
17291
16251
  if (applyVideoSettingNode(key, val)) continue;
17292
16252
  if (applyCarouselNode(key, val)) continue;
17293
16253
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -17330,17 +16290,6 @@ function OhhwellsBridge() {
17330
16290
  debounceTimer = setTimeout(applyFromCache, 150);
17331
16291
  };
17332
16292
  applyFromCache();
17333
- const pathCacheKey = `${subdomain}::${pathname}`;
17334
- if (!fetchedContentPaths.has(pathCacheKey)) {
17335
- fetchedContentPaths.add(pathCacheKey);
17336
- const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
17337
- fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(pathname)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
17338
- if (!data?.content) return;
17339
- contentCache.set(subdomain, data.content);
17340
- applyFromCache();
17341
- }).catch(() => {
17342
- });
17343
- }
17344
16293
  observer = new MutationObserver(scheduleApply);
17345
16294
  observer.observe(document.body, { childList: true, subtree: true });
17346
16295
  return () => {
@@ -17354,10 +16303,10 @@ function OhhwellsBridge() {
17354
16303
  const visible = Boolean(subdomain) && fetchState !== "done";
17355
16304
  el.style.display = visible ? "flex" : "none";
17356
16305
  }, [subdomain, fetchState]);
17357
- useEffect13(() => {
16306
+ useEffect12(() => {
17358
16307
  postToParent2({ type: "ow:navigation", path: pathname });
17359
16308
  }, [pathname, postToParent2]);
17360
- useEffect13(() => {
16309
+ useEffect12(() => {
17361
16310
  if (!isEditMode) return;
17362
16311
  if (linkPopoverSessionRef.current?.intent === "add-nav") return;
17363
16312
  if (document.querySelector("[data-ohw-section-picker]")) return;
@@ -17365,7 +16314,7 @@ function OhhwellsBridge() {
17365
16314
  deselectRef.current();
17366
16315
  deactivateRef.current();
17367
16316
  }, [pathname, isEditMode]);
17368
- useEffect13(() => {
16317
+ useEffect12(() => {
17369
16318
  const contentForNav = () => {
17370
16319
  if (isEditMode) return editContentRef.current;
17371
16320
  if (!subdomain) return {};
@@ -17432,36 +16381,31 @@ function OhhwellsBridge() {
17432
16381
  observer?.disconnect();
17433
16382
  };
17434
16383
  }, [isEditMode, pathname, subdomain, fetchState, resyncSelectedNavigationItem]);
17435
- useEffect13(() => {
16384
+ useEffect12(() => {
17436
16385
  if (!isEditMode) return;
17437
- let lastPosted = 0;
17438
16386
  const measure = () => {
17439
16387
  const h = document.body.scrollHeight;
17440
- if (h > 50 && Math.abs(h - lastPosted) > 1) {
17441
- lastPosted = h;
17442
- postToParent2({ type: "ow:height", height: h });
17443
- }
17444
- };
17445
- let raf = null;
17446
- const schedule = () => {
17447
- if (raf != null) return;
17448
- raf = requestAnimationFrame(() => {
17449
- raf = null;
17450
- measure();
17451
- });
16388
+ if (h > 50) postToParent2({ type: "ow:height", height: h });
17452
16389
  };
17453
16390
  const t1 = setTimeout(measure, 50);
17454
16391
  const t2 = setTimeout(measure, 500);
17455
- const ro = new ResizeObserver(schedule);
17456
- ro.observe(document.body);
16392
+ let lastWidth = window.innerWidth;
16393
+ let resizeTimer = null;
16394
+ const handleResize = () => {
16395
+ if (window.innerWidth === lastWidth) return;
16396
+ lastWidth = window.innerWidth;
16397
+ if (resizeTimer) clearTimeout(resizeTimer);
16398
+ resizeTimer = setTimeout(measure, 150);
16399
+ };
16400
+ window.addEventListener("resize", handleResize);
17457
16401
  return () => {
17458
16402
  clearTimeout(t1);
17459
16403
  clearTimeout(t2);
17460
- if (raf != null) cancelAnimationFrame(raf);
17461
- ro.disconnect();
16404
+ if (resizeTimer) clearTimeout(resizeTimer);
16405
+ window.removeEventListener("resize", handleResize);
17462
16406
  };
17463
16407
  }, [pathname, isEditMode, postToParent2]);
17464
- useEffect13(() => {
16408
+ useEffect12(() => {
17465
16409
  if (!subdomainFromQuery || isEditMode) return;
17466
16410
  const handleClick = (e) => {
17467
16411
  const anchor = e.target.closest("a");
@@ -17477,7 +16421,7 @@ function OhhwellsBridge() {
17477
16421
  document.addEventListener("click", handleClick, true);
17478
16422
  return () => document.removeEventListener("click", handleClick, true);
17479
16423
  }, [subdomainFromQuery, isEditMode, router]);
17480
- useEffect13(() => {
16424
+ useEffect12(() => {
17481
16425
  if (!isEditMode) {
17482
16426
  editStylesRef.current?.base.remove();
17483
16427
  editStylesRef.current?.forceHover.remove();
@@ -17639,12 +16583,10 @@ function OhhwellsBridge() {
17639
16583
  return;
17640
16584
  }
17641
16585
  const target = e.target;
17642
- if (target.closest("[data-ohw-ai-review]")) return;
17643
16586
  if (target.closest("[data-ohw-toolbar]")) return;
17644
16587
  if (target.closest("[data-ohw-state-toggle]")) return;
17645
16588
  if (target.closest("[data-ohw-max-badge]")) return;
17646
16589
  if (isInsideLinkEditor(target)) return;
17647
- if (isInsideFloatingPanel(target)) return;
17648
16590
  if (target.closest("[data-ohw-form-toolbar]")) return;
17649
16591
  if (target.closest(
17650
16592
  '[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
@@ -17918,12 +16860,10 @@ function OhhwellsBridge() {
17918
16860
  };
17919
16861
  const handleDblClick = (e) => {
17920
16862
  const target = e.target;
17921
- if (target.closest("[data-ohw-ai-review]")) return;
17922
16863
  if (target.closest("[data-ohw-toolbar]")) return;
17923
16864
  if (target.closest("[data-ohw-state-toggle]")) return;
17924
16865
  if (target.closest("[data-ohw-max-badge]")) return;
17925
16866
  if (isInsideLinkEditor(target)) return;
17926
- if (isInsideFloatingPanel(target)) return;
17927
16867
  if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
17928
16868
  return;
17929
16869
  }
@@ -17964,14 +16904,11 @@ function OhhwellsBridge() {
17964
16904
  setSiblingHintRects([]);
17965
16905
  return;
17966
16906
  }
17967
- if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || isInsideFloatingPanel(target) || isPointOverFloatingPanel(e.clientX, e.clientY)) {
16907
+ if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || target.closest("[data-ohw-floating-panel]")) {
17968
16908
  hoveredItemElRef.current = null;
17969
16909
  setHoveredItemRect(null);
17970
16910
  hoveredNavContainerRef.current = null;
17971
16911
  setHoveredNavContainerRect(null);
17972
- siblingHintElRef.current = null;
17973
- setSiblingHintRect(null);
17974
- setSiblingHintRects([]);
17975
16912
  return;
17976
16913
  }
17977
16914
  {
@@ -18080,6 +17017,7 @@ function OhhwellsBridge() {
18080
17017
  hoveredNavContainerRef.current = null;
18081
17018
  setHoveredNavContainerRect(null);
18082
17019
  hoveredItemElRef.current = editable;
17020
+ setHoveredItemRect(editable.getBoundingClientRect());
18083
17021
  }
18084
17022
  }
18085
17023
  }
@@ -18376,7 +17314,7 @@ function OhhwellsBridge() {
18376
17314
  }
18377
17315
  };
18378
17316
  const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
18379
- if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
17317
+ if (linkPopoverOpenRef.current) {
18380
17318
  if (hoveredImageRef.current) {
18381
17319
  hoveredImageRef.current = null;
18382
17320
  hoveredImageHasTextOverlapRef.current = false;
@@ -18392,6 +17330,11 @@ function OhhwellsBridge() {
18392
17330
  probeNavigationHoverAt(x, y);
18393
17331
  return;
18394
17332
  }
17333
+ if (isPointOverLogo(x, y)) {
17334
+ dismissImageHover();
17335
+ probeNavigationHoverAt(x, y);
17336
+ return;
17337
+ }
18395
17338
  const overMoreMenu = document.elementFromPoint(x, y)?.closest?.(
18396
17339
  '[data-ohw-more-menu], [data-slot="dropdown-menu-content"], [data-slot="dropdown-menu-item"]'
18397
17340
  );
@@ -18630,7 +17573,7 @@ function OhhwellsBridge() {
18630
17573
  }
18631
17574
  };
18632
17575
  const probeHoverCardsAt = (clientX, clientY, fromParentViewport = false) => {
18633
- if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY) || document.documentElement.hasAttribute("data-ohw-section-picking")) {
17576
+ if (linkPopoverOpenRef.current || document.documentElement.hasAttribute("data-ohw-section-picking")) {
18634
17577
  if (activeStateElRef.current) {
18635
17578
  activeStateElRef.current.removeAttribute("data-ohw-state-hovered");
18636
17579
  activeStateElRef.current = null;
@@ -18705,7 +17648,8 @@ function OhhwellsBridge() {
18705
17648
  };
18706
17649
  const handleMouseMove = (e) => {
18707
17650
  const { clientX, clientY } = e;
18708
- if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY) || isOverEditorChrome(clientX, clientY)) {
17651
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
17652
+ if (isOverEditorChrome(clientX, clientY)) {
18709
17653
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
18710
17654
  formHoverElRef.current = null;
18711
17655
  setFormHoverRect(null);
@@ -18713,12 +17657,6 @@ function OhhwellsBridge() {
18713
17657
  setHoveredItemRect(null);
18714
17658
  hoveredNavContainerRef.current = null;
18715
17659
  setHoveredNavContainerRect(null);
18716
- siblingHintElRef.current = null;
18717
- setSiblingHintRect(null);
18718
- setSiblingHintRects([]);
18719
- dismissImageHover();
18720
- clearImageHover();
18721
- setSectionGap(null);
18722
17660
  return;
18723
17661
  }
18724
17662
  probeSectionGapAt(clientX, clientY);
@@ -18729,11 +17667,7 @@ function OhhwellsBridge() {
18729
17667
  if (e.data?.type !== "ow:pointer-sync") return;
18730
17668
  const { clientX, clientY } = e.data;
18731
17669
  if (typeof clientX !== "number" || typeof clientY !== "number") return;
18732
- if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
18733
- dismissImageHover();
18734
- clearImageHover();
18735
- return;
18736
- }
17670
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
18737
17671
  probeSectionGapAt(clientX, clientY);
18738
17672
  probeImageAt(clientX, clientY);
18739
17673
  probeHoverCardsAt(clientX, clientY);
@@ -18979,19 +17913,10 @@ function OhhwellsBridge() {
18979
17913
  if (e.data?.type !== "ow:hydrate") return;
18980
17914
  const content = e.data.content;
18981
17915
  if (!content) return;
18982
- if (typeof content[BRAND_KIT_KEY] === "string") {
18983
- brandKitRef.current = content[BRAND_KIT_KEY];
18984
- applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
18985
- }
18986
17916
  if (typeof content[AI_SECTIONS_KEY] === "string") {
18987
17917
  aiSectionsRef.current = content[AI_SECTIONS_KEY];
18988
17918
  applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
18989
17919
  }
18990
- if (typeof content[STYLE_STORE_KEY] === "string") {
18991
- stylesRef.current = content[STYLE_STORE_KEY];
18992
- applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
18993
- }
18994
- applyBrandChrome(content);
18995
17920
  let sectionsJson = null;
18996
17921
  for (const [key, val] of Object.entries(content)) {
18997
17922
  if (key === "__ohw_sections") {
@@ -19001,9 +17926,6 @@ function OhhwellsBridge() {
19001
17926
  if (key === AI_SECTIONS_KEY) continue;
19002
17927
  if (key === LOGO_PLACEHOLDER_KEY) continue;
19003
17928
  if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
19004
- if (key === BRAND_KIT_KEY) continue;
19005
- if (key === STYLE_STORE_KEY) continue;
19006
- if (BRAND_CHROME_KEYS.has(key)) continue;
19007
17929
  if (applyVideoSettingNode(key, val)) continue;
19008
17930
  if (applyCarouselNode(key, val)) continue;
19009
17931
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -19105,10 +18027,7 @@ function OhhwellsBridge() {
19105
18027
  const payload = e.data.payload;
19106
18028
  if (!payload || typeof payload.id !== "string" || !isRenderableTree(payload.tree)) return;
19107
18029
  const previous = aiSectionsRef.current;
19108
- const nextState = applyTreeToState(parseAiSectionsState(previous), {
19109
- ...payload,
19110
- path: payload.path ?? window.location.pathname
19111
- });
18030
+ const nextState = applyTreeToState(parseAiSectionsState(previous), payload);
19112
18031
  const nextValue = serializeAiSectionsState(nextState);
19113
18032
  aiSectionsRef.current = nextValue;
19114
18033
  applyAiSectionsToDom(nextState);
@@ -19145,55 +18064,12 @@ function OhhwellsBridge() {
19145
18064
  const value = typeof e.data.value === "string" ? e.data.value : "";
19146
18065
  aiSectionsRef.current = value;
19147
18066
  applyAiSectionsToDom(parseAiSectionsState(value));
19148
- applyStylesToDom(parseStyleStore(stylesRef.current));
19149
18067
  const restoredHeight = document.documentElement.scrollHeight;
19150
18068
  if (restoredHeight > 50) postToParentRef.current({ type: "ow:height", height: restoredHeight });
19151
18069
  postToParentRef.current({ type: "ow:change", nodes: [{ key: AI_SECTIONS_KEY, text: value }] });
19152
18070
  postAiSectionsChanged();
19153
18071
  };
19154
18072
  window.addEventListener("message", handleAiSetSections);
19155
- const handleMoveSection = (e) => {
19156
- if (e.data?.type !== "ow:move-section") return;
19157
- const instanceId = typeof e.data.instanceId === "string" ? e.data.instanceId : "";
19158
- const direction = e.data.direction === "up" || e.data.direction === "down" ? e.data.direction : null;
19159
- if (!instanceId || !direction) return;
19160
- const entries = moveSectionInstance(instanceId, direction, window.location.pathname);
19161
- if (!entries) return;
19162
- const orderJson = JSON.stringify(entries);
19163
- editContentRef.current = { ...editContentRef.current, [SECTION_ORDER_KEY]: orderJson };
19164
- postToParentRef.current({ type: "ow:change", nodes: [{ key: SECTION_ORDER_KEY, text: orderJson }] });
19165
- window.dispatchEvent(new Event("resize"));
19166
- };
19167
- window.addEventListener("message", handleMoveSection);
19168
- const handleAiSetBrand = (e) => {
19169
- if (e.data?.type !== "ow:ai-set-brand") return;
19170
- const value = typeof e.data.value === "string" ? e.data.value : "";
19171
- const previous = brandKitRef.current;
19172
- brandKitRef.current = value;
19173
- applyBrandToDom(parseBrandKit(value));
19174
- if (aiSectionsRef.current) applyAiSectionsToDom(parseAiSectionsState(aiSectionsRef.current));
19175
- applyStylesToDom(parseStyleStore(stylesRef.current));
19176
- postToParentRef.current({ type: "ow:change", nodes: [{ key: BRAND_KIT_KEY, text: value }] });
19177
- postToParentRef.current({ type: "ow:ai-brand-applied", previous, value });
19178
- };
19179
- window.addEventListener("message", handleAiSetBrand);
19180
- const handleAiSetStyles = (e) => {
19181
- if (e.data?.type !== "ow:ai-set-styles") return;
19182
- const value = typeof e.data.value === "string" ? e.data.value : "";
19183
- const previous = stylesRef.current;
19184
- stylesRef.current = value;
19185
- applyStylesToDom(parseStyleStore(value));
19186
- postToParentRef.current({ type: "ow:change", nodes: [{ key: STYLE_STORE_KEY, text: value }] });
19187
- postToParentRef.current({ type: "ow:ai-styles-applied", previous, value });
19188
- };
19189
- window.addEventListener("message", handleAiSetStyles);
19190
- const handleGetBrand = (e) => {
19191
- if (e.data?.type !== "ow:get-brand") return;
19192
- const template = deriveTemplateBrand();
19193
- const value = brandKitRef.current || (template ? JSON.stringify(template) : "");
19194
- postToParentRef.current({ type: "ow:brand-value", value });
19195
- };
19196
- window.addEventListener("message", handleGetBrand);
19197
18073
  const handleDeactivate = (e) => {
19198
18074
  if (e.data?.type !== "ow:deactivate") return;
19199
18075
  if (Date.now() < linkPopoverGraceUntilRef.current) return;
@@ -19202,12 +18078,6 @@ function OhhwellsBridge() {
19202
18078
  closeLinkPopoverRef.current();
19203
18079
  return;
19204
18080
  }
19205
- if (floatingPanelOpenRef.current) {
19206
- setFloatingPanelRef.current(null);
19207
- deselectRef.current();
19208
- deactivateRef.current();
19209
- return;
19210
- }
19211
18081
  deselectRef.current();
19212
18082
  deactivateRef.current();
19213
18083
  };
@@ -19454,12 +18324,6 @@ function OhhwellsBridge() {
19454
18324
  if (aiSectionsRef.current) {
19455
18325
  nodes.push({ key: AI_SECTIONS_KEY, type: "sections", text: aiSectionsRef.current });
19456
18326
  }
19457
- if (stylesRef.current) {
19458
- nodes.push({ key: STYLE_STORE_KEY, type: "styles", text: stylesRef.current });
19459
- }
19460
- if (brandKitRef.current) {
19461
- nodes.push({ key: BRAND_KIT_KEY, type: "brand", text: brandKitRef.current });
19462
- }
19463
18327
  document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
19464
18328
  const formKey = formKeyOf(form);
19465
18329
  if (!formKey) return;
@@ -19477,12 +18341,8 @@ function OhhwellsBridge() {
19477
18341
  if (inserted) {
19478
18342
  const tracker = getSectionsTracker();
19479
18343
  postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
19480
- const reportHeight = () => {
19481
- const h = document.body.scrollHeight;
19482
- if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
19483
- };
19484
- reportHeight();
19485
- setTimeout(reportHeight, 500);
18344
+ const h = document.documentElement.scrollHeight;
18345
+ if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
19486
18346
  }
19487
18347
  };
19488
18348
  const handleSwitchSchedule = (e) => {
@@ -19869,10 +18729,6 @@ function OhhwellsBridge() {
19869
18729
  window.removeEventListener("message", handleAiApplyTree);
19870
18730
  window.removeEventListener("message", handleAiDeleteSection);
19871
18731
  window.removeEventListener("message", handleAiSetSections);
19872
- window.removeEventListener("message", handleMoveSection);
19873
- window.removeEventListener("message", handleAiSetBrand);
19874
- window.removeEventListener("message", handleAiSetStyles);
19875
- window.removeEventListener("message", handleGetBrand);
19876
18732
  window.removeEventListener("message", handleDeactivate);
19877
18733
  window.removeEventListener("message", handleToastAction);
19878
18734
  window.removeEventListener("message", handleFormCount);
@@ -19883,7 +18739,7 @@ function OhhwellsBridge() {
19883
18739
  if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
19884
18740
  };
19885
18741
  }, [isEditMode, refreshStateRules]);
19886
- useEffect13(() => {
18742
+ useEffect12(() => {
19887
18743
  if (!isEditMode) return;
19888
18744
  const THRESHOLD = 10;
19889
18745
  const resolveWasSelected = (el) => {
@@ -20039,7 +18895,7 @@ function OhhwellsBridge() {
20039
18895
  unlockFooterDragInteraction();
20040
18896
  };
20041
18897
  }, [isEditMode]);
20042
- useEffect13(() => {
18898
+ useEffect12(() => {
20043
18899
  const handler = (e) => {
20044
18900
  if (e.data?.type !== "ow:request-schedule-config") return;
20045
18901
  const insertAfterVal = e.data.insertAfter;
@@ -20055,7 +18911,7 @@ function OhhwellsBridge() {
20055
18911
  window.addEventListener("message", handler);
20056
18912
  return () => window.removeEventListener("message", handler);
20057
18913
  }, [processConfigRequest]);
20058
- useEffect13(() => {
18914
+ useEffect12(() => {
20059
18915
  if (!isEditMode) return;
20060
18916
  document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
20061
18917
  el.removeAttribute("data-ohw-active-state");
@@ -20079,7 +18935,7 @@ function OhhwellsBridge() {
20079
18935
  postToParent2({
20080
18936
  type: "ow:ready",
20081
18937
  version: "1",
20082
- bridgeVersion: "0.1.66",
18938
+ bridgeVersion: "0.1.65",
20083
18939
  path: pathname,
20084
18940
  nodes: collectEditableNodes(editContentRef.current),
20085
18941
  sections
@@ -20091,13 +18947,13 @@ function OhhwellsBridge() {
20091
18947
  clearTimeout(timer);
20092
18948
  };
20093
18949
  }, [pathname, isEditMode, refreshStateRules, postToParent2]);
20094
- useEffect13(() => {
18950
+ useEffect12(() => {
20095
18951
  scrollToHashSectionWhenReady();
20096
18952
  const onHashChange = () => scrollToHashSectionWhenReady();
20097
18953
  window.addEventListener("hashchange", onHashChange);
20098
18954
  return () => window.removeEventListener("hashchange", onHashChange);
20099
18955
  }, [pathname]);
20100
- const handleCommand = useCallback8((cmd) => {
18956
+ const handleCommand = useCallback7((cmd) => {
20101
18957
  const el = activeElRef.current;
20102
18958
  const selBefore = window.getSelection();
20103
18959
  let savedOffsets = null;
@@ -20133,7 +18989,45 @@ function OhhwellsBridge() {
20133
18989
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
20134
18990
  refreshActiveCommandsRef.current();
20135
18991
  }, []);
20136
- const handleStateChange = useCallback8((state) => {
18992
+ useEffect12(() => {
18993
+ const session = floatingPanel && floatingPanel.kind === "logo-size" ? floatingPanel : null;
18994
+ if (!session || !logoSizeDraft) return;
18995
+ const onPanelAction = (e) => {
18996
+ const type = e.data?.type;
18997
+ if (type === "ow:logo-size-close") {
18998
+ closeFloatingPanelAndDeselect();
18999
+ return;
19000
+ }
19001
+ if (type === "ow:logo-size-update-everywhere") {
19002
+ postToParentRef.current({ type: "ow:open-logo-settings", ...readLogoIdentityFromDom() });
19003
+ return;
19004
+ }
19005
+ if (type === "ow:logo-size-customize-mobile" || type === "ow:logo-size-reset-mobile") {
19006
+ const following = type === "ow:logo-size-reset-mobile";
19007
+ const next2 = {
19008
+ ...logoSizeDraft,
19009
+ mobileFollowing: following,
19010
+ mobilePx: logoSizeDraft.desktopPx
19011
+ };
19012
+ setLogoSizeDraft(next2);
19013
+ persistLogoSizeDraft(session.placement, next2);
19014
+ return;
19015
+ }
19016
+ if (type !== "ow:logo-size-set") return;
19017
+ const px = Number(e.data.px);
19018
+ if (!Number.isFinite(px)) return;
19019
+ const next = editorViewport === "mobile" ? { ...logoSizeDraft, mobilePx: px, mobileFollowing: false } : {
19020
+ ...logoSizeDraft,
19021
+ desktopPx: px,
19022
+ mobilePx: logoSizeDraft.mobileFollowing ? px : logoSizeDraft.mobilePx
19023
+ };
19024
+ setLogoSizeDraft(next);
19025
+ persistLogoSizeDraft(session.placement, next);
19026
+ };
19027
+ window.addEventListener("message", onPanelAction);
19028
+ return () => window.removeEventListener("message", onPanelAction);
19029
+ }, [floatingPanel, logoSizeDraft, editorViewport, persistLogoSizeDraft, closeFloatingPanelAndDeselect]);
19030
+ const handleStateChange = useCallback7((state) => {
20137
19031
  if (!activeStateElRef.current) return;
20138
19032
  const el = activeStateElRef.current;
20139
19033
  if (state === "Default") {
@@ -20146,7 +19040,7 @@ function OhhwellsBridge() {
20146
19040
  }
20147
19041
  setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
20148
19042
  }, [deactivate]);
20149
- const reselectAfterLinkPopover = useCallback8(
19043
+ const reselectAfterLinkPopover = useCallback7(
20150
19044
  (hrefKey) => {
20151
19045
  requestAnimationFrame(() => {
20152
19046
  const el = resolveHrefKeyElement(hrefKey);
@@ -20155,7 +19049,7 @@ function OhhwellsBridge() {
20155
19049
  },
20156
19050
  [resolveHrefKeyElement]
20157
19051
  );
20158
- const closeLinkPopover = useCallback8(() => {
19052
+ const closeLinkPopover = useCallback7(() => {
20159
19053
  const session = linkPopoverSessionRef.current;
20160
19054
  addNavAfterAnchorRef.current = null;
20161
19055
  setLinkPopover(null);
@@ -20163,9 +19057,9 @@ function OhhwellsBridge() {
20163
19057
  reselectAfterLinkPopover(session.key);
20164
19058
  }
20165
19059
  }, [reselectAfterLinkPopover]);
20166
- const closeLinkPopoverRef = useRef10(closeLinkPopover);
19060
+ const closeLinkPopoverRef = useRef9(closeLinkPopover);
20167
19061
  closeLinkPopoverRef.current = closeLinkPopover;
20168
- const openLinkPopoverForActive = useCallback8(() => {
19062
+ const openLinkPopoverForActive = useCallback7(() => {
20169
19063
  const hrefCtx = getHrefKeyFromElement(activeElRef.current);
20170
19064
  if (!hrefCtx) return;
20171
19065
  bumpLinkPopoverGrace();
@@ -20176,7 +19070,7 @@ function OhhwellsBridge() {
20176
19070
  });
20177
19071
  deactivate();
20178
19072
  }, [deactivate]);
20179
- const openLinkPopoverForSelected = useCallback8(() => {
19073
+ const openLinkPopoverForSelected = useCallback7(() => {
20180
19074
  const anchor = selectedElRef.current;
20181
19075
  if (!anchor) return;
20182
19076
  const key = anchor.getAttribute("data-ohw-href-key");
@@ -20193,7 +19087,7 @@ function OhhwellsBridge() {
20193
19087
  });
20194
19088
  deselect();
20195
19089
  }, [deselect]);
20196
- const handleSelectParent = useCallback8(() => {
19090
+ const handleSelectParent = useCallback7(() => {
20197
19091
  const selected = selectedElRef.current;
20198
19092
  if (!selected) return;
20199
19093
  if (toolbarVariantRef.current === "select-frame") {
@@ -20220,7 +19114,7 @@ function OhhwellsBridge() {
20220
19114
  }
20221
19115
  deselectRef.current();
20222
19116
  }, []);
20223
- const handleDuplicateSelected = useCallback8(() => {
19117
+ const handleDuplicateSelected = useCallback7(() => {
20224
19118
  const selected = selectedElRef.current;
20225
19119
  if (!selected || !isNavigationItem2(selected)) return;
20226
19120
  const hrefKey = selected.getAttribute("data-ohw-href-key");
@@ -20336,7 +19230,7 @@ function OhhwellsBridge() {
20336
19230
  });
20337
19231
  }
20338
19232
  }, [postToParent2]);
20339
- const runPendingDeleteUndo = useCallback8(() => {
19233
+ const runPendingDeleteUndo = useCallback7(() => {
20340
19234
  const pending = pendingDeleteUndoRef.current;
20341
19235
  if (!pending) return false;
20342
19236
  pendingDeleteUndoRef.current = null;
@@ -20344,7 +19238,7 @@ function OhhwellsBridge() {
20344
19238
  enforceLinkHrefs();
20345
19239
  return true;
20346
19240
  }, []);
20347
- const handleDeleteSelected = useCallback8(() => {
19241
+ const handleDeleteSelected = useCallback7(() => {
20348
19242
  const selected = selectedElRef.current;
20349
19243
  if (!selected) return false;
20350
19244
  return deleteSelectedNavFooterItem({
@@ -20365,7 +19259,7 @@ function OhhwellsBridge() {
20365
19259
  }, [postToParent2]);
20366
19260
  handleDeleteSelectedRef.current = handleDeleteSelected;
20367
19261
  runPendingDeleteUndoRef.current = runPendingDeleteUndo;
20368
- const handleLinkPopoverSubmit = useCallback8(
19262
+ const handleLinkPopoverSubmit = useCallback7(
20369
19263
  (target) => {
20370
19264
  const session = linkPopoverSessionRef.current;
20371
19265
  if (!session) return;
@@ -20431,19 +19325,19 @@ function OhhwellsBridge() {
20431
19325
  const showEditLink = toolbarShowEditLink;
20432
19326
  const currentSections = sectionsByPath[pathname] ?? [];
20433
19327
  linkPopoverOpenRef.current = linkPopover !== null;
20434
- const handleMediaReplace = useCallback8(
19328
+ const handleMediaReplace = useCallback7(
20435
19329
  (key) => {
20436
19330
  postToParent2({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
20437
19331
  },
20438
19332
  [postToParent2, mediaHover?.elementType]
20439
19333
  );
20440
- const handleEditCarousel = useCallback8(
19334
+ const handleEditCarousel = useCallback7(
20441
19335
  (key) => {
20442
19336
  postToParent2({ type: "ow:carousel-open", key, images: readCarouselValue(key) });
20443
19337
  },
20444
19338
  [postToParent2]
20445
19339
  );
20446
- const handleMediaFadeOutComplete = useCallback8((key) => {
19340
+ const handleMediaFadeOutComplete = useCallback7((key) => {
20447
19341
  setUploadingRects((prev) => {
20448
19342
  if (!(key in prev)) return prev;
20449
19343
  const next = { ...prev };
@@ -20451,7 +19345,7 @@ function OhhwellsBridge() {
20451
19345
  return next;
20452
19346
  });
20453
19347
  }, []);
20454
- const handleVideoSettingsChange = useCallback8(
19348
+ const handleVideoSettingsChange = useCallback7(
20455
19349
  (key, settings) => {
20456
19350
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
20457
19351
  const video = getVideoEl2(el);
@@ -20473,538 +19367,414 @@ function OhhwellsBridge() {
20473
19367
  },
20474
19368
  [postToParent2]
20475
19369
  );
20476
- return /* @__PURE__ */ jsxs21(Fragment8, { children: [
20477
- /* @__PURE__ */ jsx34("div", { id: "ohw-loader", suppressHydrationWarning: true, style: { ...OHW_LOADER_STYLE, display: "none" }, children: /* @__PURE__ */ jsx34(OhwLoaderSpinner, {}) }),
20478
- /* @__PURE__ */ jsx34("script", { suppressHydrationWarning: true, dangerouslySetInnerHTML: { __html: OHW_LOADER_PREHYDRATE_SCRIPT } }),
20479
- bridgeRoot ? createPortal2(
20480
- /* @__PURE__ */ jsxs21(Fragment8, { children: [
20481
- /* @__PURE__ */ jsx34("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
20482
- isEditMode && /* @__PURE__ */ jsx34(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
20483
- isSectionDragging && sectionDropSlots.map((slot, i) => /* @__PURE__ */ jsx34(
20484
- "div",
20485
- {
20486
- className: "pointer-events-none fixed z-2147483646",
20487
- style: { left: slot.left, top: slot.y, width: slot.width, height: 3, transform: "translateY(-50%)" },
20488
- children: /* @__PURE__ */ jsx34(
20489
- DropIndicator,
20490
- {
20491
- direction: "horizontal",
20492
- state: activeSectionDropIndex === i ? "dragActive" : "dragIdle",
20493
- className: "!h-full !w-full"
20494
- }
20495
- )
20496
- },
20497
- `section-drop-${slot.insertIndex}-${i}`
20498
- )),
20499
- Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ jsx34(
20500
- MediaOverlay,
20501
- {
20502
- hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
20503
- isUploading: true,
20504
- fadingOut,
20505
- onFadeOutComplete: handleMediaFadeOutComplete,
20506
- onReplace: handleMediaReplace
20507
- },
20508
- `uploading-${key}`
20509
- )),
20510
- mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ jsx34(
20511
- MediaOverlay,
20512
- {
20513
- hover: mediaHover,
20514
- isUploading: false,
20515
- onReplace: handleMediaReplace,
20516
- onVideoSettingsChange: handleVideoSettingsChange
20517
- }
20518
- ),
20519
- carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx34(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
20520
- siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ jsx34(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
20521
- siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ jsx34(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
20522
- isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ jsx34(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
20523
- isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ jsx34(
20524
- "div",
20525
- {
20526
- className: "pointer-events-none fixed z-2147483646",
20527
- style: {
20528
- left: slot.left,
20529
- top: slot.top,
20530
- width: slot.width,
20531
- height: slot.height
20532
- },
20533
- children: /* @__PURE__ */ jsx34(
20534
- DropIndicator,
20535
- {
20536
- direction: slot.direction,
20537
- state: activeFooterDropIndex === i ? "dragActive" : "dragIdle",
20538
- className: "!h-full !w-full"
20539
- }
20540
- )
19370
+ return bridgeRoot ? createPortal2(
19371
+ /* @__PURE__ */ jsxs20(Fragment8, { children: [
19372
+ /* @__PURE__ */ jsx33("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
19373
+ isEditMode && /* @__PURE__ */ jsx33(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
19374
+ Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ jsx33(
19375
+ MediaOverlay,
19376
+ {
19377
+ hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
19378
+ isUploading: true,
19379
+ fadingOut,
19380
+ onFadeOutComplete: handleMediaFadeOutComplete,
19381
+ onReplace: handleMediaReplace
19382
+ },
19383
+ `uploading-${key}`
19384
+ )),
19385
+ mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ jsx33(
19386
+ MediaOverlay,
19387
+ {
19388
+ hover: mediaHover,
19389
+ isUploading: false,
19390
+ onReplace: handleMediaReplace,
19391
+ onVideoSettingsChange: handleVideoSettingsChange
19392
+ }
19393
+ ),
19394
+ carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx33(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
19395
+ siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
19396
+ siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
19397
+ isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
19398
+ isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ jsx33(
19399
+ "div",
19400
+ {
19401
+ className: "pointer-events-none fixed z-2147483646",
19402
+ style: {
19403
+ left: slot.left,
19404
+ top: slot.top,
19405
+ width: slot.width,
19406
+ height: slot.height
20541
19407
  },
20542
- `footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
20543
- )),
20544
- isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ jsx34(
20545
- "div",
20546
- {
20547
- className: "pointer-events-none fixed z-2147483646",
20548
- style: {
20549
- left: slot.left,
20550
- top: slot.top,
20551
- width: slot.width,
20552
- height: slot.height
20553
- },
20554
- children: /* @__PURE__ */ jsx34(
20555
- DropIndicator,
20556
- {
20557
- direction: slot.direction,
20558
- state: activeNavDropIndex === i ? "dragActive" : "dragIdle",
20559
- className: "!h-full !w-full"
20560
- }
20561
- )
19408
+ children: /* @__PURE__ */ jsx33(
19409
+ DropIndicator,
19410
+ {
19411
+ direction: slot.direction,
19412
+ state: activeFooterDropIndex === i ? "dragActive" : "dragIdle",
19413
+ className: "!h-full !w-full"
19414
+ }
19415
+ )
19416
+ },
19417
+ `footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
19418
+ )),
19419
+ isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ jsx33(
19420
+ "div",
19421
+ {
19422
+ className: "pointer-events-none fixed z-2147483646",
19423
+ style: {
19424
+ left: slot.left,
19425
+ top: slot.top,
19426
+ width: slot.width,
19427
+ height: slot.height
20562
19428
  },
20563
- `nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
20564
- )),
20565
- hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx34(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
20566
- hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx34(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
20567
- hoveredTextRect && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ jsx34(ItemInteractionLayer, { rect: hoveredTextRect, state: "hover" }),
20568
- formPickRect && !isItemDragging && /* @__PURE__ */ jsx34(
20569
- ItemInteractionLayer,
20570
- {
20571
- rect: formPickRect,
20572
- state: "active-top",
20573
- itemDragSurface: false,
20574
- toolbarAlign: "left",
20575
- chromeGap: 24,
20576
- toolbar: fieldPickRect ? void 0 : /* @__PURE__ */ jsxs21(
20577
- "div",
20578
- {
20579
- "data-ohw-form-toolbar": "",
20580
- className: "pointer-events-auto flex items-center gap-0.5 whitespace-nowrap rounded-lg border border-border bg-background p-1 shadow-md",
20581
- children: [
20582
- /* @__PURE__ */ jsx34(
20583
- "button",
20584
- {
20585
- type: "button",
20586
- "aria-label": "Add field",
20587
- className: "flex h-7 w-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted/80",
20588
- onClick: () => setFieldTypePickerOpen((open) => !open),
20589
- "data-ohw-add-field": "",
20590
- children: /* @__PURE__ */ jsx34(Plus4, { size: 15, "aria-hidden": true })
20591
- }
20592
- ),
20593
- /* @__PURE__ */ jsx34("div", { className: "mx-0.5 h-5 w-px bg-border" }),
20594
- /* @__PURE__ */ jsxs21(
20595
- "button",
20596
- {
20597
- type: "button",
20598
- 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",
20599
- onClick: () => {
20600
- const form = formPickElRef.current;
20601
- if (!form) return;
20602
- postToParent2({
20603
- type: "ow:form-pick",
20604
- formKey: formKeyOf(form),
20605
- hasLongText: formHasLongText(form)
20606
- });
20607
- },
20608
- children: [
20609
- /* @__PURE__ */ jsx34(Settings, { size: 14, "aria-hidden": true }),
20610
- "Form settings",
20611
- formPickCount ? (
20612
- // Counter pill, per the design — not a text suffix.
20613
- /* @__PURE__ */ jsx34(
20614
- "span",
20615
- {
20616
- "data-ohw-form-count": "",
20617
- 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",
20618
- children: formPickCount
20619
- }
20620
- )
20621
- ) : null
20622
- ]
20623
- }
20624
- ),
20625
- /* @__PURE__ */ jsx34("div", { className: "mx-0.5 h-5 w-px bg-border" }),
20626
- /* @__PURE__ */ jsx34("div", { className: "flex items-center rounded-md bg-muted/70 p-0.5", children: ["default", "success"].map((state) => /* @__PURE__ */ jsx34(
20627
- "button",
20628
- {
20629
- type: "button",
20630
- "aria-pressed": formViewState === state,
20631
- 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"),
20632
- onClick: () => {
20633
- const form = formPickElRef.current;
20634
- const key = form ? formKeyOf(form) : null;
20635
- if (!form || !key) return;
20636
- const initial = successInitialFor(form, key, editContentRef.current);
20637
- setFormViewState(form, key, state, initial);
20638
- setFormViewStateUi(state);
20639
- setFormPickRect(form.getBoundingClientRect());
20640
- if (state === "success") {
20641
- const successEl = form.querySelector(`[${SUCCESS_TEXT_ATTR}]`);
20642
- if (successEl) requestAnimationFrame(() => activateRef.current(successEl));
20643
- } else {
20644
- deactivateRef.current();
20645
- }
20646
- },
20647
- children: state
19429
+ children: /* @__PURE__ */ jsx33(
19430
+ DropIndicator,
19431
+ {
19432
+ direction: slot.direction,
19433
+ state: activeNavDropIndex === i ? "dragActive" : "dragIdle",
19434
+ className: "!h-full !w-full"
19435
+ }
19436
+ )
19437
+ },
19438
+ `nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
19439
+ )),
19440
+ hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
19441
+ hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
19442
+ hoveredTextRect && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: hoveredTextRect, state: "hover" }),
19443
+ formPickRect && !isItemDragging && /* @__PURE__ */ jsx33(
19444
+ ItemInteractionLayer,
19445
+ {
19446
+ rect: formPickRect,
19447
+ state: "active-top",
19448
+ itemDragSurface: false,
19449
+ toolbarAlign: "left",
19450
+ chromeGap: 24,
19451
+ toolbar: fieldPickRect ? void 0 : /* @__PURE__ */ jsxs20(
19452
+ "div",
19453
+ {
19454
+ "data-ohw-form-toolbar": "",
19455
+ className: "pointer-events-auto flex items-center gap-0.5 whitespace-nowrap rounded-lg border border-border bg-background p-1 shadow-md",
19456
+ children: [
19457
+ /* @__PURE__ */ jsx33(
19458
+ "button",
19459
+ {
19460
+ type: "button",
19461
+ "aria-label": "Add field",
19462
+ className: "flex h-7 w-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted/80",
19463
+ onClick: () => setFieldTypePickerOpen((open) => !open),
19464
+ "data-ohw-add-field": "",
19465
+ children: /* @__PURE__ */ jsx33(Plus4, { size: 15, "aria-hidden": true })
19466
+ }
19467
+ ),
19468
+ /* @__PURE__ */ jsx33("div", { className: "mx-0.5 h-5 w-px bg-border" }),
19469
+ /* @__PURE__ */ jsxs20(
19470
+ "button",
19471
+ {
19472
+ type: "button",
19473
+ 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",
19474
+ onClick: () => {
19475
+ const form = formPickElRef.current;
19476
+ if (!form) return;
19477
+ postToParent2({
19478
+ type: "ow:form-pick",
19479
+ formKey: formKeyOf(form),
19480
+ hasLongText: formHasLongText(form)
19481
+ });
20648
19482
  },
20649
- state
20650
- )) })
20651
- ]
20652
- }
20653
- )
20654
- }
20655
- ),
20656
- formHoverRect && !isItemDragging && /* @__PURE__ */ jsx34(
20657
- ItemInteractionLayer,
20658
- {
20659
- rect: formHoverRect,
20660
- state: "hover",
20661
- chromeGap: formHoverElRef.current && getFieldWrapper(formHoverElRef.current) ? 8 : 24
20662
- }
20663
- ),
20664
- fieldPickRect && fieldPickState && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ jsx34(
20665
- ItemInteractionLayer,
20666
- {
20667
- rect: fieldPickRect,
20668
- state: fieldDragging ? "dragging" : "active-top",
20669
- itemDragSurface: false,
20670
- toolbarAlign: "left",
20671
- chromeGap: 10,
20672
- showHandle: true,
20673
- dragHandleLabel: "Reorder field",
20674
- onDragHandleDragStart: handleFieldDragStart,
20675
- onDragHandleDragEnd: handleFieldDragEnd,
20676
- toolbar: /* @__PURE__ */ jsx34(
20677
- FormFieldToolbar,
20678
- {
20679
- type: fieldPickState.type,
20680
- required: fieldPickState.required,
20681
- onTypeChange: handleFieldTypeChange,
20682
- onRequiredToggle: handleFieldRequiredToggle,
20683
- onDuplicate: handleFieldDuplicate,
20684
- onDelete: handleFieldDelete
20685
- }
20686
- )
20687
- }
20688
- ),
20689
- fieldDragging ? fieldDropSlots.map((slot, i) => /* @__PURE__ */ jsx34(
20690
- "div",
20691
- {
20692
- className: "pointer-events-none fixed z-[2147483644]",
20693
- style: { top: slot.top, left: slot.left, width: slot.width },
20694
- children: /* @__PURE__ */ jsx34(
20695
- DropIndicator,
20696
- {
20697
- direction: "horizontal",
20698
- state: fieldDropIndex === i ? "dragActive" : "dragIdle",
20699
- className: "!w-full"
20700
- }
20701
- )
20702
- },
20703
- `field-drop-${i}`
20704
- )) : null,
20705
- fieldTypePickerOpen && formPickRect && /* @__PURE__ */ jsx34(
20706
- "div",
20707
- {
20708
- className: "pointer-events-none fixed z-[2147483645]",
20709
- style: { top: formPickRect.top + 16, left: formPickRect.left + 24 },
20710
- children: /* @__PURE__ */ jsx34(FieldTypePicker, { onPick: handleAddField })
20711
- }
20712
- ),
20713
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ jsx34(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
20714
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ jsx34(
20715
- FooterContainerChrome,
20716
- {
20717
- rect: toolbarRect,
20718
- onAdd: handleAddFooterColumn,
20719
- addDisabled: !canAddFooterColumn()
20720
- }
20721
- ),
20722
- toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame" || toolbarVariant === "logo") && /* @__PURE__ */ jsx34(
20723
- ItemInteractionLayer,
20724
- {
20725
- rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
20726
- toolbarBelowRect: selectedElRef.current && isNavigationItem2(selectedElRef.current) ? getOpenNavDropdownPanelRect(selectedElRef.current) : null,
20727
- elRef: glowElRef,
20728
- state: isItemDragging ? "dragging" : selectedElRef.current && isNavigationItem2(selectedElRef.current) && getOpenNavDropdownPanelRect(selectedElRef.current) ? "active-bottom" : resolveItemInteractionState(toolbarRect, parentScrollRef.current),
20729
- showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey) || toolbarVariant === "select-frame" && isFooterFrameSelection,
20730
- dragDisabled: reorderDragDisabled,
20731
- dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
20732
- onDragHandleDragStart: handleItemDragStart,
20733
- onDragHandleDragEnd: handleItemDragEnd,
20734
- onItemPointerDown: toolbarVariant === "logo" ? void 0 : handleItemChromePointerDown,
20735
- onItemClick: toolbarVariant === "logo" ? void 0 : handleItemChromeClick,
20736
- itemDragSurface: toolbarVariant !== "logo" && !isFooterFrameSelection,
20737
- toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && (isFooterFrameSelection || selectedIsSocialsRow) && !isItemDragging ? /* @__PURE__ */ jsx34(
20738
- ItemActionToolbar,
20739
- {
20740
- onEditLink: openLinkPopoverForSelected,
20741
- onStyle: () => {
20742
- const row = selectedElRef.current;
20743
- if (!row) return;
20744
- if (floatingPanel?.kind === "socials-display") closeFloatingPanelOnly();
20745
- else openSocialsDisplayPanel(row);
20746
- },
20747
- showStyle: selectedIsSocialsRow,
20748
- styleActive: floatingPanel?.kind === "socials-display",
20749
- onAddItem: handleAddChildItem,
20750
- onSelectParent: handleSelectParent,
20751
- onDuplicate: handleDuplicateSelected,
20752
- onDelete: handleDeleteSelected,
20753
- addItemDisabled: isFooterFrameSelection && isFooterAddItemDisabled(selectedElRef.current) || selectedElRef.current !== null && (() => {
20754
- const row = isSocialsRow(selectedElRef.current) ? selectedElRef.current : findSocialsRow(selectedElRef.current);
20755
- return row ? !canAddSocialItem(row) : false;
20756
- })(),
20757
- editLinkDisabled: false,
20758
- moreDisabled: false,
20759
- duplicateDisabled: isFooterFrameSelection || selectedIsSocialsRow,
20760
- showEditLink: !isFooterFrameSelection && !selectedIsSocialsRow && navDropdownPreviewOpen === null,
20761
- showAddItem: isFooterFrameSelection || selectedIsSocialsRow || !selectedIsCta && Boolean(
20762
- selectedElRef.current && isNavbarHrefKey(selectedElRef.current.getAttribute("data-ohw-href-key")) && !isNestedNavChild(selectedElRef.current)
19483
+ children: [
19484
+ /* @__PURE__ */ jsx33(Settings, { size: 14, "aria-hidden": true }),
19485
+ "Form settings",
19486
+ formPickCount ? (
19487
+ // Counter pill, per the design — not a text suffix.
19488
+ /* @__PURE__ */ jsx33(
19489
+ "span",
19490
+ {
19491
+ "data-ohw-form-count": "",
19492
+ 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",
19493
+ children: formPickCount
19494
+ }
19495
+ )
19496
+ ) : null
19497
+ ]
19498
+ }
20763
19499
  ),
20764
- showMore: (!selectedIsCta || isFooterFrameSelection) && !selectedIsSocialsRow,
20765
- dropdownOpen: navDropdownPreviewOpen,
20766
- onDropdownOpenChange: handleNavDropdownOpenChange,
20767
- headingVisible: footerHeadingVisible,
20768
- onHeadingVisibleChange: handleFooterHeadingVisibleChange
20769
- }
20770
- ) : void 0
20771
- }
20772
- ),
20773
- toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ jsxs21(Fragment8, { children: [
20774
- /* @__PURE__ */ jsx34(
20775
- EditGlowChrome,
19500
+ /* @__PURE__ */ jsx33("div", { className: "mx-0.5 h-5 w-px bg-border" }),
19501
+ /* @__PURE__ */ jsx33("div", { className: "flex items-center rounded-md bg-muted/70 p-0.5", children: ["default", "success"].map((state) => /* @__PURE__ */ jsx33(
19502
+ "button",
19503
+ {
19504
+ type: "button",
19505
+ "aria-pressed": formViewState === state,
19506
+ 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"),
19507
+ onClick: () => {
19508
+ const form = formPickElRef.current;
19509
+ const key = form ? formKeyOf(form) : null;
19510
+ if (!form || !key) return;
19511
+ const initial = successInitialFor(form, key, editContentRef.current);
19512
+ setFormViewState(form, key, state, initial);
19513
+ setFormViewStateUi(state);
19514
+ setFormPickRect(form.getBoundingClientRect());
19515
+ if (state === "success") {
19516
+ const successEl = form.querySelector(`[${SUCCESS_TEXT_ATTR}]`);
19517
+ if (successEl) requestAnimationFrame(() => activateRef.current(successEl));
19518
+ } else {
19519
+ deactivateRef.current();
19520
+ }
19521
+ },
19522
+ children: state
19523
+ },
19524
+ state
19525
+ )) })
19526
+ ]
19527
+ }
19528
+ )
19529
+ }
19530
+ ),
19531
+ formHoverRect && !isItemDragging && /* @__PURE__ */ jsx33(
19532
+ ItemInteractionLayer,
19533
+ {
19534
+ rect: formHoverRect,
19535
+ state: "hover",
19536
+ chromeGap: formHoverElRef.current && getFieldWrapper(formHoverElRef.current) ? 8 : 24
19537
+ }
19538
+ ),
19539
+ fieldPickRect && fieldPickState && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ jsx33(
19540
+ ItemInteractionLayer,
19541
+ {
19542
+ rect: fieldPickRect,
19543
+ state: fieldDragging ? "dragging" : "active-top",
19544
+ itemDragSurface: false,
19545
+ toolbarAlign: "left",
19546
+ chromeGap: 10,
19547
+ showHandle: true,
19548
+ dragHandleLabel: "Reorder field",
19549
+ onDragHandleDragStart: handleFieldDragStart,
19550
+ onDragHandleDragEnd: handleFieldDragEnd,
19551
+ toolbar: /* @__PURE__ */ jsx33(
19552
+ FormFieldToolbar,
20776
19553
  {
20777
- rect: toolbarRect,
20778
- elRef: glowElRef,
20779
- reorderHrefKey,
20780
- dragDisabled: reorderDragDisabled,
20781
- hideHandle: isItemDragging
19554
+ type: fieldPickState.type,
19555
+ required: fieldPickState.required,
19556
+ onTypeChange: handleFieldTypeChange,
19557
+ onRequiredToggle: handleFieldRequiredToggle,
19558
+ onDuplicate: handleFieldDuplicate,
19559
+ onDelete: handleFieldDelete
20782
19560
  }
20783
- ),
20784
- /* @__PURE__ */ jsx34(
20785
- FloatingToolbar,
19561
+ )
19562
+ }
19563
+ ),
19564
+ fieldDragging ? fieldDropSlots.map((slot, i) => /* @__PURE__ */ jsx33(
19565
+ "div",
19566
+ {
19567
+ className: "pointer-events-none fixed z-[2147483644]",
19568
+ style: { top: slot.top, left: slot.left, width: slot.width },
19569
+ children: /* @__PURE__ */ jsx33(
19570
+ DropIndicator,
20786
19571
  {
20787
- rect: toolbarRect,
20788
- parentScroll: parentScrollRef.current,
20789
- elRef: toolbarElRef,
20790
- onCommand: handleCommand,
20791
- activeCommands,
20792
- showEditLink,
20793
- onEditLink: openLinkPopoverForActive
19572
+ direction: "horizontal",
19573
+ state: fieldDropIndex === i ? "dragActive" : "dragIdle",
19574
+ className: "!w-full"
20794
19575
  }
20795
19576
  )
20796
- ] }),
20797
- maxBadge && /* @__PURE__ */ jsxs21(
20798
- "div",
20799
- {
20800
- "data-ohw-max-badge": "",
20801
- style: {
20802
- position: "fixed",
20803
- top: maxBadge.rect.bottom + 4,
20804
- left: maxBadge.rect.right,
20805
- transform: "translateX(-100%)",
20806
- zIndex: 2147483647,
20807
- background: maxBadge.current > maxBadge.max ? "#FEF2F2" : "#F5F5F4",
20808
- color: maxBadge.current > maxBadge.max ? "#DC2626" : "#78716C",
20809
- border: `1px solid ${maxBadge.current > maxBadge.max ? "#FECACA" : "#E7E5E4"}`,
20810
- borderRadius: 4,
20811
- padding: "2px 6px",
20812
- fontSize: 11,
20813
- fontWeight: 500,
20814
- pointerEvents: "none"
20815
- },
20816
- children: [
20817
- maxBadge.current,
20818
- "/",
20819
- maxBadge.max
20820
- ]
20821
- }
20822
- ),
20823
- toggleState && !linkPopover && /* @__PURE__ */ jsx34(
20824
- StateToggle,
19577
+ },
19578
+ `field-drop-${i}`
19579
+ )) : null,
19580
+ fieldTypePickerOpen && formPickRect && /* @__PURE__ */ jsx33(
19581
+ "div",
19582
+ {
19583
+ className: "pointer-events-none fixed z-[2147483645]",
19584
+ style: { top: formPickRect.top + 16, left: formPickRect.left + 24 },
19585
+ children: /* @__PURE__ */ jsx33(FieldTypePicker, { onPick: handleAddField })
19586
+ }
19587
+ ),
19588
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ jsx33(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
19589
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ jsx33(
19590
+ FooterContainerChrome,
19591
+ {
19592
+ rect: toolbarRect,
19593
+ onAdd: handleAddFooterColumn,
19594
+ addDisabled: !canAddFooterColumn()
19595
+ }
19596
+ ),
19597
+ toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame" || toolbarVariant === "logo") && /* @__PURE__ */ jsx33(
19598
+ ItemInteractionLayer,
19599
+ {
19600
+ rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
19601
+ toolbarBelowRect: selectedElRef.current && isNavigationItem2(selectedElRef.current) ? getOpenNavDropdownPanelRect(selectedElRef.current) : null,
19602
+ elRef: glowElRef,
19603
+ state: isItemDragging ? "dragging" : selectedElRef.current && isNavigationItem2(selectedElRef.current) && getOpenNavDropdownPanelRect(selectedElRef.current) ? "active-bottom" : resolveItemInteractionState(toolbarRect, parentScrollRef.current),
19604
+ showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey) || toolbarVariant === "select-frame" && isFooterFrameSelection,
19605
+ dragDisabled: reorderDragDisabled,
19606
+ dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
19607
+ onDragHandleDragStart: handleItemDragStart,
19608
+ onDragHandleDragEnd: handleItemDragEnd,
19609
+ onItemPointerDown: toolbarVariant === "logo" ? void 0 : handleItemChromePointerDown,
19610
+ onItemClick: toolbarVariant === "logo" ? void 0 : handleItemChromeClick,
19611
+ itemDragSurface: toolbarVariant !== "logo" && !isFooterFrameSelection,
19612
+ toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && (isFooterFrameSelection || selectedIsSocialsRow) && !isItemDragging ? /* @__PURE__ */ jsx33(
19613
+ ItemActionToolbar,
19614
+ {
19615
+ onEditLink: openLinkPopoverForSelected,
19616
+ onStyle: () => {
19617
+ const row = selectedElRef.current;
19618
+ if (!row) return;
19619
+ if (floatingPanel?.kind === "socials-display") closeFloatingPanelOnly();
19620
+ else openSocialsDisplayPanel(row);
19621
+ },
19622
+ showStyle: selectedIsSocialsRow,
19623
+ styleActive: floatingPanel?.kind === "socials-display",
19624
+ onAddItem: handleAddChildItem,
19625
+ onSelectParent: handleSelectParent,
19626
+ onDuplicate: handleDuplicateSelected,
19627
+ onDelete: handleDeleteSelected,
19628
+ addItemDisabled: isFooterFrameSelection && isFooterAddItemDisabled(selectedElRef.current) || selectedElRef.current !== null && (() => {
19629
+ const row = isSocialsRow(selectedElRef.current) ? selectedElRef.current : findSocialsRow(selectedElRef.current);
19630
+ return row ? !canAddSocialItem(row) : false;
19631
+ })(),
19632
+ editLinkDisabled: false,
19633
+ moreDisabled: false,
19634
+ duplicateDisabled: isFooterFrameSelection || selectedIsSocialsRow,
19635
+ showEditLink: !isFooterFrameSelection && !selectedIsSocialsRow && navDropdownPreviewOpen === null,
19636
+ showAddItem: isFooterFrameSelection || selectedIsSocialsRow || !selectedIsCta && Boolean(
19637
+ selectedElRef.current && isNavbarHrefKey(selectedElRef.current.getAttribute("data-ohw-href-key")) && !isNestedNavChild(selectedElRef.current)
19638
+ ),
19639
+ showMore: (!selectedIsCta || isFooterFrameSelection) && !selectedIsSocialsRow,
19640
+ dropdownOpen: navDropdownPreviewOpen,
19641
+ onDropdownOpenChange: handleNavDropdownOpenChange,
19642
+ headingVisible: footerHeadingVisible,
19643
+ onHeadingVisibleChange: handleFooterHeadingVisibleChange
19644
+ }
19645
+ ) : void 0
19646
+ }
19647
+ ),
19648
+ toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ jsxs20(Fragment8, { children: [
19649
+ /* @__PURE__ */ jsx33(
19650
+ EditGlowChrome,
20825
19651
  {
20826
- rect: toggleState.rect,
20827
- activeState: toggleState.activeState,
20828
- states: toggleState.states,
20829
- onStateChange: handleStateChange
19652
+ rect: toolbarRect,
19653
+ elRef: glowElRef,
19654
+ reorderHrefKey,
19655
+ dragDisabled: reorderDragDisabled,
19656
+ hideHandle: isItemDragging
20830
19657
  }
20831
19658
  ),
20832
- sectionGap && !linkPopover && /* @__PURE__ */ jsxs21(
20833
- "div",
19659
+ /* @__PURE__ */ jsx33(
19660
+ FloatingToolbar,
20834
19661
  {
20835
- "data-ohw-section-insert-line": "",
20836
- className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
20837
- style: { top: sectionGap.y, transform: "translateY(-50%)" },
20838
- children: [
20839
- /* @__PURE__ */ jsx34("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
20840
- /* @__PURE__ */ jsx34(
20841
- Badge,
20842
- {
20843
- 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",
20844
- onClick: () => {
20845
- window.parent.postMessage(
20846
- {
20847
- type: "ow:add-section",
20848
- insertAfter: sectionGap.insertAfter,
20849
- insertBefore: sectionGap.insertBefore
20850
- },
20851
- "*"
20852
- );
20853
- },
20854
- children: "Add Section"
20855
- }
20856
- ),
20857
- /* @__PURE__ */ jsx34("div", { className: "flex-1 bg-primary", style: { height: 3 } })
20858
- ]
19662
+ rect: toolbarRect,
19663
+ parentScroll: parentScrollRef.current,
19664
+ elRef: toolbarElRef,
19665
+ onCommand: handleCommand,
19666
+ activeCommands,
19667
+ showEditLink,
19668
+ onEditLink: openLinkPopoverForActive
20859
19669
  }
20860
- ),
20861
- linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx34(
20862
- LinkPopover,
20863
- {
20864
- panelRef: linkPopoverPanelRef,
20865
- portalContainer: dialogPortalContainer,
20866
- open: true,
20867
- mode: linkPopover.mode ?? "edit",
20868
- pages: sitePages,
20869
- sections: currentSections,
20870
- sectionsByPath,
20871
- initialTarget: linkPopover.target,
20872
- existingTargets: linkPopover.intent === "add-nav" ? getNavbarExistingTargets() : [],
20873
- onClose: closeLinkPopover,
20874
- onSubmit: handleLinkPopoverSubmit
19670
+ )
19671
+ ] }),
19672
+ maxBadge && /* @__PURE__ */ jsxs20(
19673
+ "div",
19674
+ {
19675
+ "data-ohw-max-badge": "",
19676
+ style: {
19677
+ position: "fixed",
19678
+ top: maxBadge.rect.bottom + 4,
19679
+ left: maxBadge.rect.right,
19680
+ transform: "translateX(-100%)",
19681
+ zIndex: 2147483647,
19682
+ background: maxBadge.current > maxBadge.max ? "#FEF2F2" : "#F5F5F4",
19683
+ color: maxBadge.current > maxBadge.max ? "#DC2626" : "#78716C",
19684
+ border: `1px solid ${maxBadge.current > maxBadge.max ? "#FECACA" : "#E7E5E4"}`,
19685
+ borderRadius: 4,
19686
+ padding: "2px 6px",
19687
+ fontSize: 11,
19688
+ fontWeight: 500,
19689
+ pointerEvents: "none"
20875
19690
  },
20876
- linkPopover.key
20877
- ) : null,
20878
- floatingPanel && floatingPanel.kind === "socials-display" ? /* @__PURE__ */ jsx34(
20879
- FloatingPanel,
20880
- {
20881
- open: true,
20882
- title: floatingPanel.title,
20883
- context: floatingPanel.context,
20884
- position: floatingPanelPos,
20885
- onPositionChange: setFloatingPanelPos,
20886
- parentScroll: parentScrollSnap ?? parentScrollRef.current,
20887
- onClose: closeFloatingPanelOnly,
20888
- children: /* @__PURE__ */ jsx34(
20889
- SocialsDisplayPanel,
20890
- {
20891
- display: socialsDisplayFor(floatingPanel.row, editContentRef.current),
20892
- onChange: (next) => {
20893
- changeSocialsDisplay(floatingPanel.row, next);
20894
- setFloatingPanel({ ...floatingPanel });
20895
- }
20896
- }
20897
- )
20898
- }
20899
- ) : null,
20900
- floatingPanel && floatingPanel.kind === "logo-size" && logoSizeDraft ? /* @__PURE__ */ jsx34(
20901
- FloatingPanel,
20902
- {
20903
- open: true,
20904
- title: floatingPanel.title,
20905
- context: floatingPanel.context,
20906
- position: floatingPanelPos,
20907
- onPositionChange: setFloatingPanelPos,
20908
- parentScroll: parentScrollSnap ?? parentScrollRef.current,
20909
- onClose: closeFloatingPanelAndDeselect,
20910
- children: /* @__PURE__ */ jsx34(
20911
- LogoSizePanel,
19691
+ children: [
19692
+ maxBadge.current,
19693
+ "/",
19694
+ maxBadge.max
19695
+ ]
19696
+ }
19697
+ ),
19698
+ toggleState && !linkPopover && /* @__PURE__ */ jsx33(
19699
+ StateToggle,
19700
+ {
19701
+ rect: toggleState.rect,
19702
+ activeState: toggleState.activeState,
19703
+ states: toggleState.states,
19704
+ onStateChange: handleStateChange
19705
+ }
19706
+ ),
19707
+ sectionGap && !linkPopover && /* @__PURE__ */ jsxs20(
19708
+ "div",
19709
+ {
19710
+ "data-ohw-section-insert-line": "",
19711
+ className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
19712
+ style: { top: sectionGap.y, transform: "translateY(-50%)" },
19713
+ children: [
19714
+ /* @__PURE__ */ jsx33("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
19715
+ /* @__PURE__ */ jsx33(
19716
+ Badge,
20912
19717
  {
20913
- viewport: editorViewport,
20914
- sizePx: editorViewport === "mobile" && !logoSizeDraft.mobileFollowing ? logoSizeDraft.mobilePx : logoSizeDraft.desktopPx,
20915
- mobileFollowing: logoSizeDraft.mobileFollowing,
20916
- onSizeChange: (px) => {
20917
- const next = editorViewport === "mobile" ? { ...logoSizeDraft, mobilePx: px, mobileFollowing: false } : {
20918
- ...logoSizeDraft,
20919
- desktopPx: px,
20920
- mobilePx: logoSizeDraft.mobileFollowing ? px : logoSizeDraft.mobilePx
20921
- };
20922
- setLogoSizeDraft(next);
20923
- persistLogoSizeDraft(floatingPanel.placement, next);
20924
- },
20925
- onCustomizeMobile: () => {
20926
- const next = {
20927
- ...logoSizeDraft,
20928
- mobileFollowing: false,
20929
- mobilePx: logoSizeDraft.desktopPx
20930
- };
20931
- setLogoSizeDraft(next);
20932
- persistLogoSizeDraft(floatingPanel.placement, next);
20933
- },
20934
- onResetMobile: () => {
20935
- const next = {
20936
- ...logoSizeDraft,
20937
- mobileFollowing: true,
20938
- mobilePx: logoSizeDraft.desktopPx
20939
- };
20940
- setLogoSizeDraft(next);
20941
- persistLogoSizeDraft(floatingPanel.placement, next);
19718
+ 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",
19719
+ onClick: () => {
19720
+ window.parent.postMessage(
19721
+ {
19722
+ type: "ow:add-section",
19723
+ insertAfter: sectionGap.insertAfter,
19724
+ insertBefore: sectionGap.insertBefore
19725
+ },
19726
+ "*"
19727
+ );
20942
19728
  },
20943
- onUpdateEverywhere: () => {
20944
- const identity = readLogoIdentityFromDom();
20945
- postToParent2({ type: "ow:open-logo-settings", ...identity });
20946
- }
19729
+ children: "Add Section"
20947
19730
  }
20948
- )
20949
- }
20950
- ) : null
20951
- ] }),
20952
- bridgeRoot
20953
- ) : null
20954
- ] });
20955
- }
20956
-
20957
- // src/ui/EmptySection.tsx
20958
- import Link4 from "next/link";
20959
- import { Fragment as Fragment9, jsx as jsx35, jsxs as jsxs22 } from "react/jsx-runtime";
20960
- function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey }) {
20961
- return /* @__PURE__ */ jsxs22(Fragment9, { children: [
20962
- /* @__PURE__ */ jsx35(
20963
- "p",
20964
- {
20965
- style: {
20966
- fontFamily: "var(--brand-font-body)",
20967
- fontSize: "0.75rem",
20968
- fontWeight: 500,
20969
- letterSpacing: "0.15em",
20970
- textTransform: "uppercase",
20971
- color: "var(--brand-accent)",
20972
- marginBottom: "1.5rem"
20973
- },
20974
- children: /* @__PURE__ */ jsx35(Link4, { href: homeHref, style: { color: "inherit" }, children: /* @__PURE__ */ jsx35("span", { ...eyebrowKey ? { "data-ohw-editable": "text", "data-ohw-key": eyebrowKey } : {}, children: "Home" }) })
20975
- }
20976
- ),
20977
- /* @__PURE__ */ jsx35(
20978
- "h1",
20979
- {
20980
- style: {
20981
- fontFamily: "var(--brand-font-heading)",
20982
- fontSize: "clamp(2rem, 3.5vw, 2.75rem)",
20983
- lineHeight: 1.1,
20984
- letterSpacing: "-0.025em",
20985
- color: "var(--brand-text)",
20986
- marginBottom: "1rem"
20987
- },
20988
- ...titleKey ? { "data-ohw-editable": "text", "data-ohw-key": titleKey, "data-ohw-max-length": 80 } : {},
20989
- children: title
20990
- }
20991
- ),
20992
- /* @__PURE__ */ jsx35(
20993
- "p",
20994
- {
20995
- style: {
20996
- fontFamily: "var(--brand-font-body)",
20997
- fontSize: "1rem",
20998
- lineHeight: 1.7,
20999
- fontWeight: 300,
21000
- color: "var(--brand-text-muted)",
21001
- maxWidth: "340px"
19731
+ ),
19732
+ /* @__PURE__ */ jsx33("div", { className: "flex-1 bg-primary", style: { height: 3 } })
19733
+ ]
19734
+ }
19735
+ ),
19736
+ linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx33(
19737
+ LinkPopover,
19738
+ {
19739
+ panelRef: linkPopoverPanelRef,
19740
+ portalContainer: dialogPortalContainer,
19741
+ open: true,
19742
+ mode: linkPopover.mode ?? "edit",
19743
+ pages: sitePages,
19744
+ sections: currentSections,
19745
+ sectionsByPath,
19746
+ initialTarget: linkPopover.target,
19747
+ existingTargets: linkPopover.intent === "add-nav" ? getNavbarExistingTargets() : [],
19748
+ onClose: closeLinkPopover,
19749
+ onSubmit: handleLinkPopoverSubmit
21002
19750
  },
21003
- ...subtitleKey ? { "data-ohw-editable": "text", "data-ohw-key": subtitleKey, "data-ohw-max-length": 160 } : {},
21004
- children: "This page doesn't have any content yet."
21005
- }
21006
- )
21007
- ] });
19751
+ linkPopover.key
19752
+ ) : null,
19753
+ floatingPanel && floatingPanel.kind === "socials-display" ? /* @__PURE__ */ jsx33(
19754
+ FloatingPanel,
19755
+ {
19756
+ open: true,
19757
+ title: floatingPanel.title,
19758
+ context: floatingPanel.context,
19759
+ position: floatingPanelPos,
19760
+ onPositionChange: setFloatingPanelPos,
19761
+ parentScroll: parentScrollSnap ?? parentScrollRef.current,
19762
+ onClose: closeFloatingPanelOnly,
19763
+ children: /* @__PURE__ */ jsx33(
19764
+ SocialsDisplayPanel,
19765
+ {
19766
+ display: socialsDisplayFor(floatingPanel.row, editContentRef.current),
19767
+ onChange: (next) => {
19768
+ changeSocialsDisplay(floatingPanel.row, next);
19769
+ setFloatingPanel({ ...floatingPanel });
19770
+ }
19771
+ }
19772
+ )
19773
+ }
19774
+ ) : null
19775
+ ] }),
19776
+ bridgeRoot
19777
+ ) : null;
21008
19778
  }
21009
19779
  export {
21010
19780
  AI_DEFAULT_BRAND,
@@ -21022,7 +19792,6 @@ export {
21022
19792
  DropdownMenuItem,
21023
19793
  DropdownMenuSeparator,
21024
19794
  DropdownMenuTrigger,
21025
- EmptySection,
21026
19795
  ItemActionToolbar,
21027
19796
  ItemInteractionLayer,
21028
19797
  LinkEditorPanel,