@ohhwells/bridge 0.1.132-next.358 → 0.1.133

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -2727,7 +2727,7 @@ var AI_MOBILE_CSS = [
2727
2727
  // page's first section. Top only (bottom needs no nav clearance); ~96px approximates the
2728
2728
  // template nav's own height (measured ~94px) — there's no shared `--ohw-header-h` var to read
2729
2729
  // an exact figure from (no live measurement exists), so this is a safe approximation, not a
2730
- // pixel-exact fit. Horizontal spacing already comes from `data-ai-section-inner`.
2730
+ // pixel-exact fit. Horizontal spacing already comes from `data-ai-container`.
2731
2731
  '[data-ai-overlay-clearance] [data-ai-overlap-layer="overlay"]{padding-top:96px}',
2732
2732
  // A full-bleed carousel's height is pure arithmetic: it spans the whole window, so 16/9 turns
2733
2733
  // window width straight into height. Measured at 16/9 it came out ~90% of the viewport at EVERY
@@ -2743,10 +2743,8 @@ var AI_MOBILE_CSS = [
2743
2743
  "[data-ai-section]{overflow-x:hidden}",
2744
2744
  // `:not([data-ai-full-bleed])`: this `!important` gutter beat the inline `padding: 0` that a
2745
2745
  // full-bleed section's container sets, so a carousel/media hero that is edge-to-edge on desktop
2746
- // still got a 20px band of section background down both sides on a phone. The footer's own
2747
- // container keeps the unguarded rule below — `data-ai-full-bleed` can never appear on it.
2748
- "[data-ai-section-inner]:not([data-ai-full-bleed]){padding:0 20px !important}",
2749
- "[data-ai-container]{padding:0 20px !important}",
2746
+ // still got a 20px band of section background down both sides on a phone.
2747
+ "[data-ai-container]:not([data-ai-full-bleed]){padding:0 20px !important}",
2750
2748
  "[data-ai-row]{display:flex !important;flex-direction:column !important;align-items:stretch !important}",
2751
2749
  "[data-ai-cell]{width:100%;min-width:0}",
2752
2750
  // The rule above turns every row into a COLUMN flex container on phones, which silently breaks
@@ -2947,31 +2945,6 @@ function pricingCardEmphasis(featured, ctx, hasBg) {
2947
2945
  function textAttrs(ctx, path) {
2948
2946
  return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
2949
2947
  }
2950
- var AI_RESPONSIVE_CSS = [
2951
- "@media (max-width: 960px) {",
2952
- " [data-ai-responsive] [data-ai-grid] { grid-template-columns: repeat(2, 1fr) !important; }",
2953
- ' [data-ai-responsive] [data-ai-grid="1"] { grid-template-columns: 1fr !important; }',
2954
- "}",
2955
- "@media (max-width: 640px) {",
2956
- " [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
2957
- " [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
2958
- // Group containers flatten to a column on phones; span placements come along for free.
2959
- // `:not([data-ai-group="overlap"])` for the same reason as the twin pair in AI_MOBILE_CSS — see
2960
- // the comment there. This sheet's copy is the narrower selector, so without the exemption it
2961
- // flattens an `overlap` hero below 640px even though the other rule stands down: measured a 390px
2962
- // viewport with the heading/CTA in flow *under* the image, 219px of section background where the
2963
- // layered text used to be.
2964
- ' [data-ai-responsive] [data-ai-group]:not([data-ai-group="overlap"]) { display: flex !important; flex-direction: column !important; }',
2965
- ' [data-ai-responsive] [data-ai-group]:not([data-ai-group="overlap"]) > * { grid-column: auto !important; }',
2966
- // `:not([data-ai-full-bleed])` for the same reason as the twin rule in AI_MOBILE_CSS: this one
2967
- // is narrower (0,2,0 vs 0,1,0) and also `!important`, so without the guard it wins outright and
2968
- // a full-bleed hero gets its 20px side band back below 640px only — the one width where the
2969
- // other rule had already been taught to stand down.
2970
- " [data-ai-responsive] [data-ai-section-inner]:not([data-ai-full-bleed]) { padding-left: 20px !important; padding-right: 20px !important; }",
2971
- " [data-ai-responsive] { overflow-x: hidden; }",
2972
- " [data-ai-responsive] img { max-width: 100%; }",
2973
- "}"
2974
- ].join("\n");
2975
2948
  var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
2976
2949
  function MediaBox({
2977
2950
  refValue,
@@ -2992,9 +2965,9 @@ function MediaBox({
2992
2965
  const url = refValue ? ctx.resolveMedia(refValue) : null;
2993
2966
  const isIcon = /^(lucide|simple):/.test(refValue);
2994
2967
  const aspectRatio = aspect && /^\d+:\d+$/.test(aspect) ? aspect.replace(":", " / ") : void 0;
2995
- const editAttrs = ctx.keyFor && editPath ? {
2968
+ const editAttrs = ctx.keyFor && editPath && !isIcon ? {
2996
2969
  "data-ohw-key": ctx.keyFor(editPath),
2997
- ...isIcon ? { "data-ohw-editable": "icon" } : genericImageEdit ? { "data-ohw-editable": "image" } : {}
2970
+ ...genericImageEdit ? { "data-ohw-editable": "image" } : {}
2998
2971
  } : {};
2999
2972
  if (isIcon) {
3000
2973
  const Icon = refValue.startsWith("lucide:") ? lucideByName(refValue.slice(7)) : null;
@@ -3002,7 +2975,6 @@ function MediaBox({
3002
2975
  "span",
3003
2976
  {
3004
2977
  "data-ai-icon": refValue,
3005
- ...editAttrs,
3006
2978
  style: {
3007
2979
  display: "inline-flex",
3008
2980
  width: 48,
@@ -4187,18 +4159,25 @@ function FadeSlideshow({ node, ctx, path }) {
4187
4159
  (dir) => onInteract(stepViableSlide(index, failed, count, dir, loop)),
4188
4160
  [count, failed, index, loop, onInteract]
4189
4161
  );
4162
+ const prefetchRef = import_react.default.useRef(prefetch);
4163
+ import_react.default.useEffect(() => {
4164
+ prefetchRef.current = prefetch;
4165
+ });
4166
+ import_react.default.useEffect(() => {
4167
+ if (autoplay) hasInteractedRef.current = false;
4168
+ }, [autoplay]);
4190
4169
  import_react.default.useEffect(() => {
4191
4170
  if (!autoplay) return;
4192
4171
  const id = window.setInterval(() => {
4193
4172
  if (hasInteractedRef.current || hoveredRef.current) return;
4194
4173
  setIndex((i) => loop ? (i + 1) % count : Math.min(count - 1, i + 1));
4195
4174
  }, intervalMs);
4196
- const warmId = window.setTimeout(() => prefetch(1 % count), Math.min(1500, intervalMs / 2));
4175
+ const warmId = window.setTimeout(() => prefetchRef.current(1 % count), Math.min(1500, intervalMs / 2));
4197
4176
  return () => {
4198
4177
  window.clearInterval(id);
4199
4178
  window.clearTimeout(warmId);
4200
4179
  };
4201
- }, [autoplay, count, intervalMs, loop, prefetch]);
4180
+ }, [autoplay, count, intervalMs, loop]);
4202
4181
  const hasMovedRef = import_react.default.useRef(false);
4203
4182
  import_react.default.useEffect(() => {
4204
4183
  if (!hasMovedRef.current) {
@@ -4489,7 +4468,7 @@ function CollectionBlock({ node, ctx, path }) {
4489
4468
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
4490
4469
  "div",
4491
4470
  {
4492
- "data-ai-grid": String(itemsPerRow),
4471
+ "data-ai-grid": "",
4493
4472
  "data-ohw-pricing-collection": isPricing ? "" : void 0,
4494
4473
  style: {
4495
4474
  display: "grid",
@@ -4749,7 +4728,7 @@ function renderNode(node, ctx, path, ambientAlign) {
4749
4728
  },
4750
4729
  children: [
4751
4730
  i > 0 && ctx.heroOverlapFullBleed ? (
4752
- // The section's `data-ai-section-inner` gave up its max-width/gutter so the base
4731
+ // The section's `data-ai-container` gave up its max-width/gutter so the base
4753
4732
  // layer (this group's i===0 sibling) can span edge-to-edge — reintroduced here,
4754
4733
  // scoped to just the overlay text, so a heading/copy/CTA stack doesn't stretch
4755
4734
  // the full section width instead of reading at the usual content width.
@@ -5142,7 +5121,6 @@ function AiTreeRenderer({
5142
5121
  ...fillHeight ? { "data-ai-fill-height": "" } : {},
5143
5122
  ...needsOverlayClearance ? { "data-ai-overlay-clearance": "" } : {},
5144
5123
  ...bgAttrs,
5145
- "data-ai-responsive": "",
5146
5124
  style: {
5147
5125
  position: "relative",
5148
5126
  padding: `${padCss} 0`,
@@ -5156,13 +5134,12 @@ function AiTreeRenderer({
5156
5134
  ...fillHeight ? { display: "grid" } : {}
5157
5135
  },
5158
5136
  children: [
5159
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_RESPONSIVE_CSS }),
5160
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_MOBILE_CSS }),
5161
5137
  isOverlay && backgroundUrl && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { position: "absolute", inset: 0, background: `rgba(255,255,255,${overlayAlpha})` } }),
5138
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_MOBILE_CSS }),
5162
5139
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
5163
5140
  "div",
5164
5141
  {
5165
- "data-ai-section-inner": "",
5142
+ "data-ai-container": "",
5166
5143
  ...fullBleedMedia ? { "data-ai-full-bleed": "" } : {},
5167
5144
  style: {
5168
5145
  position: "relative",
@@ -5179,7 +5156,7 @@ function AiTreeRenderer({
5179
5156
  children: tree.rows.map((row, r2) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
5180
5157
  "div",
5181
5158
  {
5182
- "data-ai-columns": "",
5159
+ "data-ai-row": "",
5183
5160
  style: {
5184
5161
  display: "grid",
5185
5162
  gridTemplateColumns: "repeat(12, 1fr)",
@@ -5835,10 +5812,9 @@ function applyAiSectionsToDom(state, options) {
5835
5812
  if (existing && existing.serialized === serialized && existing.container.isConnected) {
5836
5813
  continue;
5837
5814
  }
5815
+ const isNewMount = !existing || !existing.container.isConnected;
5838
5816
  let container = existing?.container;
5839
- let isNewMount = false;
5840
5817
  if (!container || !container.isConnected) {
5841
- isNewMount = true;
5842
5818
  existing?.root.unmount();
5843
5819
  container?.remove();
5844
5820
  container = document.createElement("div");
@@ -13473,7 +13449,6 @@ function MediaOverlay({
13473
13449
  (prev) => prev && prev.fullWidth === width && prev.height === height ? prev : { fullWidth: width, height }
13474
13450
  );
13475
13451
  }, [isVideo]);
13476
- const replaceLabel = isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image";
13477
13452
  const replaceMode = buttonSize ? replaceButtonMode({ width: rect.width, height: rect.height }, buttonSize) : "none";
13478
13453
  const box = {
13479
13454
  position: "fixed",
@@ -13572,10 +13547,11 @@ function MediaOverlay({
13572
13547
  className: "flex items-center justify-center cursor-pointer",
13573
13548
  style: {
13574
13549
  ...box,
13575
- // Visual only. `pointer-events: auto` on this full-bleed rect covered the navbar
13576
- // (hero bg includes the absolute TopNav) and swallowed CTA press-drag. Text overlay
13577
- // and cueOnly also need clicks to fall through — Replace / video controls opt back in.
13578
- pointerEvents: "none",
13550
+ // When text overlays this media, let clicks fall THROUGH to the text underneath. In the
13551
+ // parent this needed a whole `ow:click-at` round-trip to re-hit-test inside the iframe;
13552
+ // in-document, pointer-events does it natively. The button below opts back in, so
13553
+ // Replace still works.
13554
+ pointerEvents: hover.hasTextOverlap || cueOnly ? "none" : "auto",
13579
13555
  // Selected: a firm component ring with no wash, so the image reads as chosen rather
13580
13556
  // than hovered. Hover keeps the existing tinted preview.
13581
13557
  boxShadow: selected ? "inset 0 0 0 2px var(--color-bridge-primary)" : "inset 0 0 0 1.5px var(--color-bridge-primary)",
@@ -13602,17 +13578,17 @@ function MediaOverlay({
13602
13578
  },
13603
13579
  children: [
13604
13580
  isVideo ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react5.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react5.ImageIcon, { size: 14 }),
13605
- replaceLabel
13581
+ isVideo ? "Replace video" : "Replace image"
13606
13582
  ]
13607
13583
  }
13608
13584
  ),
13609
- showChrome && replaceMode !== "none" && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
13585
+ replaceMode === "none" || cueOnly ? null : /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
13610
13586
  Button,
13611
13587
  {
13612
13588
  "data-ohw-media-overlay": "",
13613
13589
  variant: "outline",
13614
13590
  size: "sm",
13615
- "aria-label": replaceLabel,
13591
+ "aria-label": isVideo ? "Replace video" : "Replace image",
13616
13592
  className: "gap-1.5 cursor-pointer hover:bg-background",
13617
13593
  style: {
13618
13594
  ...OVERLAY_BUTTON_STYLE,
@@ -13635,7 +13611,7 @@ function MediaOverlay({
13635
13611
  },
13636
13612
  children: [
13637
13613
  isVideo ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react5.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react5.ImageIcon, { size: 14 }),
13638
- replaceMode === "full" ? replaceLabel : null
13614
+ replaceMode === "full" ? isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image" : null
13639
13615
  ]
13640
13616
  }
13641
13617
  )
@@ -19867,7 +19843,6 @@ function readLogoSizeState(content, placement) {
19867
19843
  function getLogoElement(el) {
19868
19844
  const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
19869
19845
  if (marked) return marked;
19870
- if (el.closest('[data-ohw-editable="icon"]')) return null;
19871
19846
  const root = el.closest("nav, [data-ohw-nav-root], footer");
19872
19847
  if (!root) return null;
19873
19848
  const anchor = el.closest("a");
@@ -23359,7 +23334,7 @@ function getNavigationSelectionParent(el) {
23359
23334
  if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
23360
23335
  return resolveFooterLinksContainerFrom(el);
23361
23336
  }
23362
- 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)) {
23337
+ if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
23363
23338
  return getNavigationRoot(el);
23364
23339
  }
23365
23340
  return null;
@@ -23581,6 +23556,7 @@ var ICONS = {
23581
23556
  insertUnorderedList: '<line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/>',
23582
23557
  insertOrderedList: '<line x1="10" y1="6" x2="21" y2="6"/><line x1="10" y1="12" x2="21" y2="12"/><line x1="10" y1="18" x2="21" y2="18"/><path d="M4 6h1v4"/><path d="M4 10h2"/><path d="M6 18H4c0-1 2-2 2-3s-1-1.5-2-1"/>'
23583
23558
  };
23559
+ var HEIGHT_SETTLE_DELAYS = [150, 400, 800];
23584
23560
  var SELECTION_CHROME_GAP2 = 4;
23585
23561
  var TOOLBAR_STROKE_GAP2 = 4;
23586
23562
  var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
@@ -24560,6 +24536,21 @@ function OhhwellsBridge() {
24560
24536
  const [isItemDragging, setIsItemDragging] = (0, import_react21.useState)(false);
24561
24537
  const [isFooterFrameSelection, setIsFooterFrameSelection] = (0, import_react21.useState)(false);
24562
24538
  isFooterFrameSelectionRef.current = isFooterFrameSelection;
24539
+ const [floatingPanel, setFloatingPanel] = (0, import_react21.useState)(null);
24540
+ const floatingPanelOpenRef = (0, import_react21.useRef)(false);
24541
+ floatingPanelOpenRef.current = floatingPanel !== null;
24542
+ const floatingPanelRef = (0, import_react21.useRef)(null);
24543
+ floatingPanelRef.current = floatingPanel;
24544
+ const [floatingPanelPos, setFloatingPanelPos] = (0, import_react21.useState)(null);
24545
+ const buttonCollectionDragRef = (0, import_react21.useRef)(null);
24546
+ const buttonDropInsertIndexRef = (0, import_react21.useRef)(null);
24547
+ const [buttonDropSlots, setButtonDropSlots] = (0, import_react21.useState)([]);
24548
+ const [activeButtonDropIndex, setActiveButtonDropIndex] = (0, import_react21.useState)(null);
24549
+ const buttonPointerDragRef = (0, import_react21.useRef)(null);
24550
+ const [buttonStyleTick, setButtonStyleTick] = (0, import_react21.useState)(0);
24551
+ const [logoSizeDraft, setLogoSizeDraft] = (0, import_react21.useState)(null);
24552
+ const [editorViewport, setEditorViewport] = (0, import_react21.useState)("desktop");
24553
+ const [parentScrollSnap, setParentScrollSnap] = (0, import_react21.useState)(null);
24563
24554
  const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = (0, import_react21.useState)(null);
24564
24555
  const [footerHeadingVisible, setFooterHeadingVisible] = (0, import_react21.useState)(null);
24565
24556
  const footerDragRef = (0, import_react21.useRef)(null);
@@ -24585,21 +24576,6 @@ function OhhwellsBridge() {
24585
24576
  const stylesRef = (0, import_react21.useRef)("");
24586
24577
  const appliedDrawerRef = (0, import_react21.useRef)(null);
24587
24578
  const pendingDeleteUndoRef = (0, import_react21.useRef)(null);
24588
- const [floatingPanel, setFloatingPanel] = (0, import_react21.useState)(null);
24589
- const floatingPanelOpenRef = (0, import_react21.useRef)(false);
24590
- const floatingPanelRef = (0, import_react21.useRef)(null);
24591
- floatingPanelRef.current = floatingPanel;
24592
- const setFloatingPanelRef = (0, import_react21.useRef)(setFloatingPanel);
24593
- const [floatingPanelPos, setFloatingPanelPos] = (0, import_react21.useState)(null);
24594
- const buttonCollectionDragRef = (0, import_react21.useRef)(null);
24595
- const buttonDropInsertIndexRef = (0, import_react21.useRef)(null);
24596
- const [buttonDropSlots, setButtonDropSlots] = (0, import_react21.useState)([]);
24597
- const [activeButtonDropIndex, setActiveButtonDropIndex] = (0, import_react21.useState)(null);
24598
- const buttonPointerDragRef = (0, import_react21.useRef)(null);
24599
- const [buttonStyleTick, setButtonStyleTick] = (0, import_react21.useState)(0);
24600
- const [logoSizeDraft, setLogoSizeDraft] = (0, import_react21.useState)(null);
24601
- const [editorViewport, setEditorViewport] = (0, import_react21.useState)("desktop");
24602
- const [parentScrollSnap, setParentScrollSnap] = (0, import_react21.useState)(null);
24603
24579
  const [sitePages, setSitePages] = (0, import_react21.useState)([]);
24604
24580
  const [sectionsByPath, setSectionsByPath] = (0, import_react21.useState)({});
24605
24581
  const sectionsPrefetchGenRef = (0, import_react21.useRef)(0);
@@ -24608,18 +24584,7 @@ function OhhwellsBridge() {
24608
24584
  const linkPopoverOpenRef = (0, import_react21.useRef)(false);
24609
24585
  const linkPopoverGraceUntilRef = (0, import_react21.useRef)(0);
24610
24586
  setLinkPopoverRef.current = setLinkPopover;
24611
- setFloatingPanelRef.current = setFloatingPanel;
24612
24587
  linkPopoverSessionRef.current = linkPopover;
24613
- floatingPanelOpenRef.current = Boolean(floatingPanel);
24614
- (0, import_react21.useEffect)(() => {
24615
- const syncViewport = () => {
24616
- const next = window.innerWidth <= 480 ? "mobile" : "desktop";
24617
- setEditorViewport((prev) => prev === next ? prev : next);
24618
- };
24619
- syncViewport();
24620
- window.addEventListener("resize", syncViewport);
24621
- return () => window.removeEventListener("resize", syncViewport);
24622
- }, []);
24623
24588
  (0, import_react21.useEffect)(() => {
24624
24589
  setSectionOrderPersistHandler((entries) => {
24625
24590
  const currentPath = window.location.pathname;
@@ -26298,7 +26263,6 @@ function OhhwellsBridge() {
26298
26263
  applyAiFooterFromContent(content);
26299
26264
  if (typeof content[STYLE_STORE_KEY] === "string") {
26300
26265
  stylesRef.current = content[STYLE_STORE_KEY];
26301
- document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
26302
26266
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
26303
26267
  }
26304
26268
  applyBrandChrome(content);
@@ -26308,12 +26272,12 @@ function OhhwellsBridge() {
26308
26272
  if (key === "__ohw_sections") continue;
26309
26273
  if (key === AI_SECTIONS_KEY) continue;
26310
26274
  if (key === AI_FOOTER_KEY) continue;
26311
- if (key === LOGO_PLACEHOLDER_KEY) continue;
26312
- if (LOGO_IMAGE_KEYS.includes(key)) continue;
26313
26275
  if (key === BRAND_KIT_KEY) continue;
26314
26276
  if (key === STYLE_STORE_KEY) continue;
26315
26277
  if (BRAND_CHROME_KEYS.has(key)) continue;
26278
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
26316
26279
  if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
26280
+ if (LOGO_IMAGE_KEYS.includes(key)) continue;
26317
26281
  if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
26318
26282
  continue;
26319
26283
  }
@@ -26527,18 +26491,17 @@ function OhhwellsBridge() {
26527
26491
  }
26528
26492
  applyAiFooterFromContent(content);
26529
26493
  if (typeof content[STYLE_STORE_KEY] === "string") {
26530
- document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
26531
26494
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
26532
26495
  }
26533
26496
  for (const [key, val] of Object.entries(content)) {
26534
26497
  if (key === "__ohw_sections") continue;
26535
26498
  if (key === AI_SECTIONS_KEY) continue;
26536
26499
  if (key === AI_FOOTER_KEY) continue;
26537
- if (key === LOGO_PLACEHOLDER_KEY) continue;
26538
- if (LOGO_IMAGE_KEYS.includes(key)) continue;
26539
26500
  if (key === BRAND_KIT_KEY) continue;
26540
26501
  if (key === STYLE_STORE_KEY) continue;
26541
26502
  if (BRAND_CHROME_KEYS.has(key)) continue;
26503
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
26504
+ if (LOGO_IMAGE_KEYS.includes(key)) continue;
26542
26505
  if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
26543
26506
  continue;
26544
26507
  }
@@ -26794,11 +26757,26 @@ function OhhwellsBridge() {
26794
26757
  const t2 = setTimeout(measure, 500);
26795
26758
  const ro = new ResizeObserver(schedule);
26796
26759
  ro.observe(document.body);
26760
+ let lastWidth = window.innerWidth;
26761
+ let resizeTimers = [];
26762
+ const clearResizeTimers = () => {
26763
+ resizeTimers.forEach(clearTimeout);
26764
+ resizeTimers = [];
26765
+ };
26766
+ const handleResize = () => {
26767
+ if (window.innerWidth === lastWidth) return;
26768
+ lastWidth = window.innerWidth;
26769
+ clearResizeTimers();
26770
+ resizeTimers = HEIGHT_SETTLE_DELAYS.map((delay) => setTimeout(measure, delay));
26771
+ };
26772
+ window.addEventListener("resize", handleResize);
26797
26773
  return () => {
26798
26774
  clearTimeout(t1);
26799
26775
  clearTimeout(t2);
26800
26776
  if (raf != null) cancelAnimationFrame(raf);
26801
26777
  ro.disconnect();
26778
+ clearResizeTimers();
26779
+ window.removeEventListener("resize", handleResize);
26802
26780
  };
26803
26781
  }, [pathname, isEditMode, postToParent2]);
26804
26782
  (0, import_react21.useEffect)(() => {
@@ -27093,13 +27071,6 @@ function OhhwellsBridge() {
27093
27071
  if (target.closest("[data-ohw-state-toggle]")) return;
27094
27072
  if (target.closest("[data-ohw-max-badge]")) return;
27095
27073
  if (isInsideLinkEditor(target)) return;
27096
- if (isInsideFloatingPanel(target)) return;
27097
- if (target.closest("[data-ohw-form-toolbar]")) return;
27098
- if (target.closest(
27099
- '[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
27100
- )) {
27101
- return;
27102
- }
27103
27074
  if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
27104
27075
  clearMediaSelectionRef.current();
27105
27076
  }
@@ -27120,6 +27091,13 @@ function OhhwellsBridge() {
27120
27091
  return;
27121
27092
  }
27122
27093
  }
27094
+ if (isInsideFloatingPanel(target)) return;
27095
+ if (target.closest("[data-ohw-form-toolbar]")) return;
27096
+ if (target.closest(
27097
+ '[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
27098
+ )) {
27099
+ return;
27100
+ }
27123
27101
  {
27124
27102
  const formEl = getFormElement(target);
27125
27103
  const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
@@ -27499,9 +27477,6 @@ function OhhwellsBridge() {
27499
27477
  setHoveredItemRect(null);
27500
27478
  hoveredNavContainerRef.current = null;
27501
27479
  setHoveredNavContainerRect(null);
27502
- siblingHintElRef.current = null;
27503
- setSiblingHintRect(null);
27504
- setSiblingHintRects([]);
27505
27480
  return;
27506
27481
  }
27507
27482
  {
@@ -27622,6 +27597,7 @@ function OhhwellsBridge() {
27622
27597
  hoveredNavContainerRef.current = null;
27623
27598
  setHoveredNavContainerRect(null);
27624
27599
  hoveredItemElRef.current = editable;
27600
+ setHoveredItemRect(isSelectedForHoverRef.current(editable) ? null : editable.getBoundingClientRect());
27625
27601
  }
27626
27602
  }
27627
27603
  }
@@ -28331,11 +28307,7 @@ function OhhwellsBridge() {
28331
28307
  };
28332
28308
  const handleMouseMove = (e) => {
28333
28309
  const { clientX, clientY } = e;
28334
- if (pointOwnedByFloatingPanel(clientX, clientY)) {
28335
- dismissImageHover();
28336
- clearImageHover();
28337
- return;
28338
- }
28310
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
28339
28311
  if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) {
28340
28312
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
28341
28313
  formHoverElRef.current = null;
@@ -28364,12 +28336,7 @@ function OhhwellsBridge() {
28364
28336
  setHoveredItemRect(null);
28365
28337
  hoveredNavContainerRef.current = null;
28366
28338
  setHoveredNavContainerRect(null);
28367
- siblingHintElRef.current = null;
28368
- setSiblingHintRect(null);
28369
- setSiblingHintRects([]);
28370
28339
  dismissImageHover();
28371
- clearImageHover();
28372
- setSectionGap(null);
28373
28340
  return;
28374
28341
  }
28375
28342
  if (probeSocialsRowAt(clientX, clientY)) return;
@@ -28381,11 +28348,7 @@ function OhhwellsBridge() {
28381
28348
  if (e.data?.type !== "ow:pointer-sync") return;
28382
28349
  const { clientX, clientY } = e.data;
28383
28350
  if (typeof clientX !== "number" || typeof clientY !== "number") return;
28384
- if (pointOwnedByFloatingPanel(clientX, clientY)) {
28385
- dismissImageHover();
28386
- clearImageHover();
28387
- return;
28388
- }
28351
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
28389
28352
  if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) return;
28390
28353
  if (probeSocialsRowAt(clientX, clientY)) return;
28391
28354
  probeSectionGapAt(clientX, clientY);
@@ -28737,7 +28700,6 @@ function OhhwellsBridge() {
28737
28700
  applyAiFooterFromContent(content);
28738
28701
  if (typeof content[STYLE_STORE_KEY] === "string") {
28739
28702
  stylesRef.current = content[STYLE_STORE_KEY];
28740
- document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
28741
28703
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
28742
28704
  }
28743
28705
  applyBrandChrome(content);
@@ -28751,12 +28713,12 @@ function OhhwellsBridge() {
28751
28713
  }
28752
28714
  if (key === AI_SECTIONS_KEY) continue;
28753
28715
  if (key === AI_FOOTER_KEY) continue;
28754
- if (key === LOGO_PLACEHOLDER_KEY) continue;
28755
- if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
28756
28716
  if (key === BRAND_KIT_KEY) continue;
28757
28717
  if (key === STYLE_STORE_KEY) continue;
28758
28718
  if (BRAND_CHROME_KEYS.has(key)) continue;
28719
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
28759
28720
  if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
28721
+ if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
28760
28722
  if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
28761
28723
  continue;
28762
28724
  }
@@ -29293,12 +29255,6 @@ function OhhwellsBridge() {
29293
29255
  closeLinkPopoverRef.current();
29294
29256
  return;
29295
29257
  }
29296
- if (floatingPanelOpenRef.current) {
29297
- setFloatingPanelRef.current(null);
29298
- deselectRef.current();
29299
- deactivateRef.current();
29300
- return;
29301
- }
29302
29258
  deselectRef.current();
29303
29259
  deactivateRef.current();
29304
29260
  clearMediaSelectionRef.current();
@@ -30061,10 +30017,10 @@ function OhhwellsBridge() {
30061
30017
  window.removeEventListener("message", handleDeleteSection);
30062
30018
  window.removeEventListener("message", handleDuplicateSection);
30063
30019
  window.removeEventListener("message", handleDeactivate);
30020
+ document.documentElement.removeAttribute("data-ohw-panel-dragging");
30064
30021
  window.removeEventListener("message", handleToastAction);
30065
30022
  window.removeEventListener("message", handleFormCount);
30066
30023
  window.removeEventListener("message", handleUiEscape);
30067
- document.documentElement.removeAttribute("data-ohw-panel-dragging");
30068
30024
  autoSaveTimers.current.forEach(clearTimeout);
30069
30025
  autoSaveTimers.current.clear();
30070
30026
  if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);