@ohhwells/bridge 0.1.134-next.362 → 0.1.135

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
@@ -2740,7 +2740,7 @@ var AI_MOBILE_CSS = [
2740
2740
  // page's first section. Top only (bottom needs no nav clearance); ~96px approximates the
2741
2741
  // template nav's own height (measured ~94px) — there's no shared `--ohw-header-h` var to read
2742
2742
  // an exact figure from (no live measurement exists), so this is a safe approximation, not a
2743
- // pixel-exact fit. Horizontal spacing already comes from `data-ai-section-inner`.
2743
+ // pixel-exact fit. Horizontal spacing already comes from `data-ai-container`.
2744
2744
  '[data-ai-overlay-clearance] [data-ai-overlap-layer="overlay"]{padding-top:96px}',
2745
2745
  // A full-bleed carousel's height is pure arithmetic: it spans the whole window, so 16/9 turns
2746
2746
  // window width straight into height. Measured at 16/9 it came out ~90% of the viewport at EVERY
@@ -2756,10 +2756,8 @@ var AI_MOBILE_CSS = [
2756
2756
  "[data-ai-section]{overflow-x:hidden}",
2757
2757
  // `:not([data-ai-full-bleed])`: this `!important` gutter beat the inline `padding: 0` that a
2758
2758
  // full-bleed section's container sets, so a carousel/media hero that is edge-to-edge on desktop
2759
- // still got a 20px band of section background down both sides on a phone. The footer's own
2760
- // container keeps the unguarded rule below — `data-ai-full-bleed` can never appear on it.
2761
- "[data-ai-section-inner]:not([data-ai-full-bleed]){padding:0 20px !important}",
2762
- "[data-ai-container]{padding:0 20px !important}",
2759
+ // still got a 20px band of section background down both sides on a phone.
2760
+ "[data-ai-container]:not([data-ai-full-bleed]){padding:0 20px !important}",
2763
2761
  "[data-ai-row]{display:flex !important;flex-direction:column !important;align-items:stretch !important}",
2764
2762
  "[data-ai-cell]{width:100%;min-width:0}",
2765
2763
  // The rule above turns every row into a COLUMN flex container on phones, which silently breaks
@@ -2960,31 +2958,6 @@ function pricingCardEmphasis(featured, ctx, hasBg) {
2960
2958
  function textAttrs(ctx, path) {
2961
2959
  return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
2962
2960
  }
2963
- var AI_RESPONSIVE_CSS = [
2964
- "@media (max-width: 960px) {",
2965
- " [data-ai-responsive] [data-ai-grid] { grid-template-columns: repeat(2, 1fr) !important; }",
2966
- ' [data-ai-responsive] [data-ai-grid="1"] { grid-template-columns: 1fr !important; }',
2967
- "}",
2968
- "@media (max-width: 640px) {",
2969
- " [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
2970
- " [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
2971
- // Group containers flatten to a column on phones; span placements come along for free.
2972
- // `:not([data-ai-group="overlap"])` for the same reason as the twin pair in AI_MOBILE_CSS — see
2973
- // the comment there. This sheet's copy is the narrower selector, so without the exemption it
2974
- // flattens an `overlap` hero below 640px even though the other rule stands down: measured a 390px
2975
- // viewport with the heading/CTA in flow *under* the image, 219px of section background where the
2976
- // layered text used to be.
2977
- ' [data-ai-responsive] [data-ai-group]:not([data-ai-group="overlap"]) { display: flex !important; flex-direction: column !important; }',
2978
- ' [data-ai-responsive] [data-ai-group]:not([data-ai-group="overlap"]) > * { grid-column: auto !important; }',
2979
- // `:not([data-ai-full-bleed])` for the same reason as the twin rule in AI_MOBILE_CSS: this one
2980
- // is narrower (0,2,0 vs 0,1,0) and also `!important`, so without the guard it wins outright and
2981
- // a full-bleed hero gets its 20px side band back below 640px only — the one width where the
2982
- // other rule had already been taught to stand down.
2983
- " [data-ai-responsive] [data-ai-section-inner]:not([data-ai-full-bleed]) { padding-left: 20px !important; padding-right: 20px !important; }",
2984
- " [data-ai-responsive] { overflow-x: hidden; }",
2985
- " [data-ai-responsive] img { max-width: 100%; }",
2986
- "}"
2987
- ].join("\n");
2988
2961
  var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
2989
2962
  function MediaBox({
2990
2963
  refValue,
@@ -3005,9 +2978,9 @@ function MediaBox({
3005
2978
  const url = refValue ? ctx.resolveMedia(refValue) : null;
3006
2979
  const isIcon = /^(lucide|simple):/.test(refValue);
3007
2980
  const aspectRatio = aspect && /^\d+:\d+$/.test(aspect) ? aspect.replace(":", " / ") : void 0;
3008
- const editAttrs = ctx.keyFor && editPath ? {
2981
+ const editAttrs = ctx.keyFor && editPath && !isIcon ? {
3009
2982
  "data-ohw-key": ctx.keyFor(editPath),
3010
- ...isIcon ? { "data-ohw-editable": "icon" } : genericImageEdit ? { "data-ohw-editable": "image" } : {}
2983
+ ...genericImageEdit ? { "data-ohw-editable": "image" } : {}
3011
2984
  } : {};
3012
2985
  if (isIcon) {
3013
2986
  const Icon = refValue.startsWith("lucide:") ? lucideByName(refValue.slice(7)) : null;
@@ -3015,7 +2988,6 @@ function MediaBox({
3015
2988
  "span",
3016
2989
  {
3017
2990
  "data-ai-icon": refValue,
3018
- ...editAttrs,
3019
2991
  style: {
3020
2992
  display: "inline-flex",
3021
2993
  width: 48,
@@ -4509,7 +4481,7 @@ function CollectionBlock({ node, ctx, path }) {
4509
4481
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
4510
4482
  "div",
4511
4483
  {
4512
- "data-ai-grid": String(itemsPerRow),
4484
+ "data-ai-grid": "",
4513
4485
  "data-ohw-pricing-collection": isPricing ? "" : void 0,
4514
4486
  style: {
4515
4487
  display: "grid",
@@ -4769,7 +4741,7 @@ function renderNode(node, ctx, path, ambientAlign) {
4769
4741
  },
4770
4742
  children: [
4771
4743
  i > 0 && ctx.heroOverlapFullBleed ? (
4772
- // The section's `data-ai-section-inner` gave up its max-width/gutter so the base
4744
+ // The section's `data-ai-container` gave up its max-width/gutter so the base
4773
4745
  // layer (this group's i===0 sibling) can span edge-to-edge — reintroduced here,
4774
4746
  // scoped to just the overlay text, so a heading/copy/CTA stack doesn't stretch
4775
4747
  // the full section width instead of reading at the usual content width.
@@ -5162,7 +5134,6 @@ function AiTreeRenderer({
5162
5134
  ...fillHeight ? { "data-ai-fill-height": "" } : {},
5163
5135
  ...needsOverlayClearance ? { "data-ai-overlay-clearance": "" } : {},
5164
5136
  ...bgAttrs,
5165
- "data-ai-responsive": "",
5166
5137
  style: {
5167
5138
  position: "relative",
5168
5139
  padding: `${padCss} 0`,
@@ -5176,13 +5147,12 @@ function AiTreeRenderer({
5176
5147
  ...fillHeight ? { display: "grid" } : {}
5177
5148
  },
5178
5149
  children: [
5179
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_RESPONSIVE_CSS }),
5180
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_MOBILE_CSS }),
5181
5150
  isOverlay && backgroundUrl && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { position: "absolute", inset: 0, background: `rgba(255,255,255,${overlayAlpha})` } }),
5151
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_MOBILE_CSS }),
5182
5152
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
5183
5153
  "div",
5184
5154
  {
5185
- "data-ai-section-inner": "",
5155
+ "data-ai-container": "",
5186
5156
  ...fullBleedMedia ? { "data-ai-full-bleed": "" } : {},
5187
5157
  style: {
5188
5158
  position: "relative",
@@ -5199,7 +5169,7 @@ function AiTreeRenderer({
5199
5169
  children: tree.rows.map((row, r2) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
5200
5170
  "div",
5201
5171
  {
5202
- "data-ai-columns": "",
5172
+ "data-ai-row": "",
5203
5173
  style: {
5204
5174
  display: "grid",
5205
5175
  gridTemplateColumns: "repeat(12, 1fr)",
@@ -5855,10 +5825,9 @@ function applyAiSectionsToDom(state, options) {
5855
5825
  if (existing && existing.serialized === serialized && existing.container.isConnected) {
5856
5826
  continue;
5857
5827
  }
5828
+ const isNewMount = !existing || !existing.container.isConnected;
5858
5829
  let container = existing?.container;
5859
- let isNewMount = false;
5860
5830
  if (!container || !container.isConnected) {
5861
- isNewMount = true;
5862
5831
  existing?.root.unmount();
5863
5832
  container?.remove();
5864
5833
  container = document.createElement("div");
@@ -13493,7 +13462,6 @@ function MediaOverlay({
13493
13462
  (prev) => prev && prev.fullWidth === width && prev.height === height ? prev : { fullWidth: width, height }
13494
13463
  );
13495
13464
  }, [isVideo]);
13496
- const replaceLabel = isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image";
13497
13465
  const replaceMode = buttonSize ? replaceButtonMode({ width: rect.width, height: rect.height }, buttonSize) : "none";
13498
13466
  const box = {
13499
13467
  position: "fixed",
@@ -13592,10 +13560,11 @@ function MediaOverlay({
13592
13560
  className: "flex items-center justify-center cursor-pointer",
13593
13561
  style: {
13594
13562
  ...box,
13595
- // Visual only. `pointer-events: auto` on this full-bleed rect covered the navbar
13596
- // (hero bg includes the absolute TopNav) and swallowed CTA press-drag. Text overlay
13597
- // and cueOnly also need clicks to fall through — Replace / video controls opt back in.
13598
- pointerEvents: "none",
13563
+ // When text overlays this media, let clicks fall THROUGH to the text underneath. In the
13564
+ // parent this needed a whole `ow:click-at` round-trip to re-hit-test inside the iframe;
13565
+ // in-document, pointer-events does it natively. The button below opts back in, so
13566
+ // Replace still works.
13567
+ pointerEvents: hover.hasTextOverlap || cueOnly ? "none" : "auto",
13599
13568
  // Selected: a firm component ring with no wash, so the image reads as chosen rather
13600
13569
  // than hovered. Hover keeps the existing tinted preview.
13601
13570
  boxShadow: selected ? "inset 0 0 0 2px var(--color-bridge-primary)" : "inset 0 0 0 1.5px var(--color-bridge-primary)",
@@ -13622,17 +13591,17 @@ function MediaOverlay({
13622
13591
  },
13623
13592
  children: [
13624
13593
  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 }),
13625
- replaceLabel
13594
+ isVideo ? "Replace video" : "Replace image"
13626
13595
  ]
13627
13596
  }
13628
13597
  ),
13629
- showChrome && replaceMode !== "none" && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
13598
+ replaceMode === "none" || cueOnly ? null : /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
13630
13599
  Button,
13631
13600
  {
13632
13601
  "data-ohw-media-overlay": "",
13633
13602
  variant: "outline",
13634
13603
  size: "sm",
13635
- "aria-label": replaceLabel,
13604
+ "aria-label": isVideo ? "Replace video" : "Replace image",
13636
13605
  className: "gap-1.5 cursor-pointer hover:bg-background",
13637
13606
  style: {
13638
13607
  ...OVERLAY_BUTTON_STYLE,
@@ -13655,7 +13624,7 @@ function MediaOverlay({
13655
13624
  },
13656
13625
  children: [
13657
13626
  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 }),
13658
- replaceMode === "full" ? replaceLabel : null
13627
+ replaceMode === "full" ? isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image" : null
13659
13628
  ]
13660
13629
  }
13661
13630
  )
@@ -19887,7 +19856,6 @@ function readLogoSizeState(content, placement) {
19887
19856
  function getLogoElement(el) {
19888
19857
  const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
19889
19858
  if (marked) return marked;
19890
- if (el.closest('[data-ohw-editable="icon"]')) return null;
19891
19859
  const root = el.closest("nav, [data-ohw-nav-root], footer");
19892
19860
  if (!root) return null;
19893
19861
  const anchor = el.closest("a");
@@ -23379,7 +23347,7 @@ function getNavigationSelectionParent(el) {
23379
23347
  if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
23380
23348
  return resolveFooterLinksContainerFrom(el);
23381
23349
  }
23382
- 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)) {
23350
+ if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
23383
23351
  return getNavigationRoot(el);
23384
23352
  }
23385
23353
  return null;
@@ -23601,6 +23569,7 @@ var ICONS = {
23601
23569
  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"/>',
23602
23570
  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"/>'
23603
23571
  };
23572
+ var HEIGHT_SETTLE_DELAYS = [150, 400, 800];
23604
23573
  var SELECTION_CHROME_GAP2 = 4;
23605
23574
  var TOOLBAR_STROKE_GAP2 = 4;
23606
23575
  var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
@@ -24580,6 +24549,21 @@ function OhhwellsBridge() {
24580
24549
  const [isItemDragging, setIsItemDragging] = (0, import_react21.useState)(false);
24581
24550
  const [isFooterFrameSelection, setIsFooterFrameSelection] = (0, import_react21.useState)(false);
24582
24551
  isFooterFrameSelectionRef.current = isFooterFrameSelection;
24552
+ const [floatingPanel, setFloatingPanel] = (0, import_react21.useState)(null);
24553
+ const floatingPanelOpenRef = (0, import_react21.useRef)(false);
24554
+ floatingPanelOpenRef.current = floatingPanel !== null;
24555
+ const floatingPanelRef = (0, import_react21.useRef)(null);
24556
+ floatingPanelRef.current = floatingPanel;
24557
+ const [floatingPanelPos, setFloatingPanelPos] = (0, import_react21.useState)(null);
24558
+ const buttonCollectionDragRef = (0, import_react21.useRef)(null);
24559
+ const buttonDropInsertIndexRef = (0, import_react21.useRef)(null);
24560
+ const [buttonDropSlots, setButtonDropSlots] = (0, import_react21.useState)([]);
24561
+ const [activeButtonDropIndex, setActiveButtonDropIndex] = (0, import_react21.useState)(null);
24562
+ const buttonPointerDragRef = (0, import_react21.useRef)(null);
24563
+ const [buttonStyleTick, setButtonStyleTick] = (0, import_react21.useState)(0);
24564
+ const [logoSizeDraft, setLogoSizeDraft] = (0, import_react21.useState)(null);
24565
+ const [editorViewport, setEditorViewport] = (0, import_react21.useState)("desktop");
24566
+ const [parentScrollSnap, setParentScrollSnap] = (0, import_react21.useState)(null);
24583
24567
  const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = (0, import_react21.useState)(null);
24584
24568
  const [footerHeadingVisible, setFooterHeadingVisible] = (0, import_react21.useState)(null);
24585
24569
  const footerDragRef = (0, import_react21.useRef)(null);
@@ -24605,21 +24589,6 @@ function OhhwellsBridge() {
24605
24589
  const stylesRef = (0, import_react21.useRef)("");
24606
24590
  const appliedDrawerRef = (0, import_react21.useRef)(null);
24607
24591
  const pendingDeleteUndoRef = (0, import_react21.useRef)(null);
24608
- const [floatingPanel, setFloatingPanel] = (0, import_react21.useState)(null);
24609
- const floatingPanelOpenRef = (0, import_react21.useRef)(false);
24610
- const floatingPanelRef = (0, import_react21.useRef)(null);
24611
- floatingPanelRef.current = floatingPanel;
24612
- const setFloatingPanelRef = (0, import_react21.useRef)(setFloatingPanel);
24613
- const [floatingPanelPos, setFloatingPanelPos] = (0, import_react21.useState)(null);
24614
- const buttonCollectionDragRef = (0, import_react21.useRef)(null);
24615
- const buttonDropInsertIndexRef = (0, import_react21.useRef)(null);
24616
- const [buttonDropSlots, setButtonDropSlots] = (0, import_react21.useState)([]);
24617
- const [activeButtonDropIndex, setActiveButtonDropIndex] = (0, import_react21.useState)(null);
24618
- const buttonPointerDragRef = (0, import_react21.useRef)(null);
24619
- const [buttonStyleTick, setButtonStyleTick] = (0, import_react21.useState)(0);
24620
- const [logoSizeDraft, setLogoSizeDraft] = (0, import_react21.useState)(null);
24621
- const [editorViewport, setEditorViewport] = (0, import_react21.useState)("desktop");
24622
- const [parentScrollSnap, setParentScrollSnap] = (0, import_react21.useState)(null);
24623
24592
  const [sitePages, setSitePages] = (0, import_react21.useState)([]);
24624
24593
  const [sectionsByPath, setSectionsByPath] = (0, import_react21.useState)({});
24625
24594
  const sectionsPrefetchGenRef = (0, import_react21.useRef)(0);
@@ -24628,18 +24597,7 @@ function OhhwellsBridge() {
24628
24597
  const linkPopoverOpenRef = (0, import_react21.useRef)(false);
24629
24598
  const linkPopoverGraceUntilRef = (0, import_react21.useRef)(0);
24630
24599
  setLinkPopoverRef.current = setLinkPopover;
24631
- setFloatingPanelRef.current = setFloatingPanel;
24632
24600
  linkPopoverSessionRef.current = linkPopover;
24633
- floatingPanelOpenRef.current = Boolean(floatingPanel);
24634
- (0, import_react21.useEffect)(() => {
24635
- const syncViewport = () => {
24636
- const next = window.innerWidth <= 480 ? "mobile" : "desktop";
24637
- setEditorViewport((prev) => prev === next ? prev : next);
24638
- };
24639
- syncViewport();
24640
- window.addEventListener("resize", syncViewport);
24641
- return () => window.removeEventListener("resize", syncViewport);
24642
- }, []);
24643
24601
  (0, import_react21.useEffect)(() => {
24644
24602
  setSectionOrderPersistHandler((entries) => {
24645
24603
  const currentPath = window.location.pathname;
@@ -26318,7 +26276,6 @@ function OhhwellsBridge() {
26318
26276
  applyAiFooterFromContent(content);
26319
26277
  if (typeof content[STYLE_STORE_KEY] === "string") {
26320
26278
  stylesRef.current = content[STYLE_STORE_KEY];
26321
- document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
26322
26279
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
26323
26280
  }
26324
26281
  applyBrandChrome(content);
@@ -26328,12 +26285,12 @@ function OhhwellsBridge() {
26328
26285
  if (key === "__ohw_sections") continue;
26329
26286
  if (key === AI_SECTIONS_KEY) continue;
26330
26287
  if (key === AI_FOOTER_KEY) continue;
26331
- if (key === LOGO_PLACEHOLDER_KEY) continue;
26332
- if (LOGO_IMAGE_KEYS.includes(key)) continue;
26333
26288
  if (key === BRAND_KIT_KEY) continue;
26334
26289
  if (key === STYLE_STORE_KEY) continue;
26335
26290
  if (BRAND_CHROME_KEYS.has(key)) continue;
26291
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
26336
26292
  if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
26293
+ if (LOGO_IMAGE_KEYS.includes(key)) continue;
26337
26294
  if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
26338
26295
  continue;
26339
26296
  }
@@ -26547,18 +26504,17 @@ function OhhwellsBridge() {
26547
26504
  }
26548
26505
  applyAiFooterFromContent(content);
26549
26506
  if (typeof content[STYLE_STORE_KEY] === "string") {
26550
- document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
26551
26507
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
26552
26508
  }
26553
26509
  for (const [key, val] of Object.entries(content)) {
26554
26510
  if (key === "__ohw_sections") continue;
26555
26511
  if (key === AI_SECTIONS_KEY) continue;
26556
26512
  if (key === AI_FOOTER_KEY) continue;
26557
- if (key === LOGO_PLACEHOLDER_KEY) continue;
26558
- if (LOGO_IMAGE_KEYS.includes(key)) continue;
26559
26513
  if (key === BRAND_KIT_KEY) continue;
26560
26514
  if (key === STYLE_STORE_KEY) continue;
26561
26515
  if (BRAND_CHROME_KEYS.has(key)) continue;
26516
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
26517
+ if (LOGO_IMAGE_KEYS.includes(key)) continue;
26562
26518
  if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
26563
26519
  continue;
26564
26520
  }
@@ -26814,11 +26770,26 @@ function OhhwellsBridge() {
26814
26770
  const t2 = setTimeout(measure, 500);
26815
26771
  const ro = new ResizeObserver(schedule);
26816
26772
  ro.observe(document.body);
26773
+ let lastWidth = window.innerWidth;
26774
+ let resizeTimers = [];
26775
+ const clearResizeTimers = () => {
26776
+ resizeTimers.forEach(clearTimeout);
26777
+ resizeTimers = [];
26778
+ };
26779
+ const handleResize = () => {
26780
+ if (window.innerWidth === lastWidth) return;
26781
+ lastWidth = window.innerWidth;
26782
+ clearResizeTimers();
26783
+ resizeTimers = HEIGHT_SETTLE_DELAYS.map((delay) => setTimeout(measure, delay));
26784
+ };
26785
+ window.addEventListener("resize", handleResize);
26817
26786
  return () => {
26818
26787
  clearTimeout(t1);
26819
26788
  clearTimeout(t2);
26820
26789
  if (raf != null) cancelAnimationFrame(raf);
26821
26790
  ro.disconnect();
26791
+ clearResizeTimers();
26792
+ window.removeEventListener("resize", handleResize);
26822
26793
  };
26823
26794
  }, [pathname, isEditMode, postToParent2]);
26824
26795
  (0, import_react21.useEffect)(() => {
@@ -27113,13 +27084,6 @@ function OhhwellsBridge() {
27113
27084
  if (target.closest("[data-ohw-state-toggle]")) return;
27114
27085
  if (target.closest("[data-ohw-max-badge]")) return;
27115
27086
  if (isInsideLinkEditor(target)) return;
27116
- if (isInsideFloatingPanel(target)) return;
27117
- if (target.closest("[data-ohw-form-toolbar]")) return;
27118
- if (target.closest(
27119
- '[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
27120
- )) {
27121
- return;
27122
- }
27123
27087
  if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
27124
27088
  clearMediaSelectionRef.current();
27125
27089
  }
@@ -27140,6 +27104,13 @@ function OhhwellsBridge() {
27140
27104
  return;
27141
27105
  }
27142
27106
  }
27107
+ if (isInsideFloatingPanel(target)) return;
27108
+ if (target.closest("[data-ohw-form-toolbar]")) return;
27109
+ if (target.closest(
27110
+ '[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
27111
+ )) {
27112
+ return;
27113
+ }
27143
27114
  {
27144
27115
  const formEl = getFormElement(target);
27145
27116
  const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
@@ -27519,9 +27490,6 @@ function OhhwellsBridge() {
27519
27490
  setHoveredItemRect(null);
27520
27491
  hoveredNavContainerRef.current = null;
27521
27492
  setHoveredNavContainerRect(null);
27522
- siblingHintElRef.current = null;
27523
- setSiblingHintRect(null);
27524
- setSiblingHintRects([]);
27525
27493
  return;
27526
27494
  }
27527
27495
  {
@@ -27642,6 +27610,7 @@ function OhhwellsBridge() {
27642
27610
  hoveredNavContainerRef.current = null;
27643
27611
  setHoveredNavContainerRect(null);
27644
27612
  hoveredItemElRef.current = editable;
27613
+ setHoveredItemRect(isSelectedForHoverRef.current(editable) ? null : editable.getBoundingClientRect());
27645
27614
  }
27646
27615
  }
27647
27616
  }
@@ -28351,11 +28320,7 @@ function OhhwellsBridge() {
28351
28320
  };
28352
28321
  const handleMouseMove = (e) => {
28353
28322
  const { clientX, clientY } = e;
28354
- if (pointOwnedByFloatingPanel(clientX, clientY)) {
28355
- dismissImageHover();
28356
- clearImageHover();
28357
- return;
28358
- }
28323
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
28359
28324
  if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) {
28360
28325
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
28361
28326
  formHoverElRef.current = null;
@@ -28384,12 +28349,7 @@ function OhhwellsBridge() {
28384
28349
  setHoveredItemRect(null);
28385
28350
  hoveredNavContainerRef.current = null;
28386
28351
  setHoveredNavContainerRect(null);
28387
- siblingHintElRef.current = null;
28388
- setSiblingHintRect(null);
28389
- setSiblingHintRects([]);
28390
28352
  dismissImageHover();
28391
- clearImageHover();
28392
- setSectionGap(null);
28393
28353
  return;
28394
28354
  }
28395
28355
  if (probeSocialsRowAt(clientX, clientY)) return;
@@ -28401,11 +28361,7 @@ function OhhwellsBridge() {
28401
28361
  if (e.data?.type !== "ow:pointer-sync") return;
28402
28362
  const { clientX, clientY } = e.data;
28403
28363
  if (typeof clientX !== "number" || typeof clientY !== "number") return;
28404
- if (pointOwnedByFloatingPanel(clientX, clientY)) {
28405
- dismissImageHover();
28406
- clearImageHover();
28407
- return;
28408
- }
28364
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
28409
28365
  if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) return;
28410
28366
  if (probeSocialsRowAt(clientX, clientY)) return;
28411
28367
  probeSectionGapAt(clientX, clientY);
@@ -28757,7 +28713,6 @@ function OhhwellsBridge() {
28757
28713
  applyAiFooterFromContent(content);
28758
28714
  if (typeof content[STYLE_STORE_KEY] === "string") {
28759
28715
  stylesRef.current = content[STYLE_STORE_KEY];
28760
- document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
28761
28716
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
28762
28717
  }
28763
28718
  applyBrandChrome(content);
@@ -28771,12 +28726,12 @@ function OhhwellsBridge() {
28771
28726
  }
28772
28727
  if (key === AI_SECTIONS_KEY) continue;
28773
28728
  if (key === AI_FOOTER_KEY) continue;
28774
- if (key === LOGO_PLACEHOLDER_KEY) continue;
28775
- if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
28776
28729
  if (key === BRAND_KIT_KEY) continue;
28777
28730
  if (key === STYLE_STORE_KEY) continue;
28778
28731
  if (BRAND_CHROME_KEYS.has(key)) continue;
28732
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
28779
28733
  if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
28734
+ if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
28780
28735
  if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
28781
28736
  continue;
28782
28737
  }
@@ -29313,12 +29268,6 @@ function OhhwellsBridge() {
29313
29268
  closeLinkPopoverRef.current();
29314
29269
  return;
29315
29270
  }
29316
- if (floatingPanelOpenRef.current) {
29317
- setFloatingPanelRef.current(null);
29318
- deselectRef.current();
29319
- deactivateRef.current();
29320
- return;
29321
- }
29322
29271
  deselectRef.current();
29323
29272
  deactivateRef.current();
29324
29273
  clearMediaSelectionRef.current();
@@ -30081,10 +30030,10 @@ function OhhwellsBridge() {
30081
30030
  window.removeEventListener("message", handleDeleteSection);
30082
30031
  window.removeEventListener("message", handleDuplicateSection);
30083
30032
  window.removeEventListener("message", handleDeactivate);
30033
+ document.documentElement.removeAttribute("data-ohw-panel-dragging");
30084
30034
  window.removeEventListener("message", handleToastAction);
30085
30035
  window.removeEventListener("message", handleFormCount);
30086
30036
  window.removeEventListener("message", handleUiEscape);
30087
- document.documentElement.removeAttribute("data-ohw-panel-dragging");
30088
30037
  autoSaveTimers.current.forEach(clearTimeout);
30089
30038
  autoSaveTimers.current.clear();
30090
30039
  if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);