@ohhwells/bridge 0.1.139-next.376 → 0.1.140

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
@@ -5204,21 +5204,19 @@ function findIndexSegment(keys) {
5204
5204
  if (len < 2 || tokenLists.some((t) => t.length !== len)) return null;
5205
5205
  let position = -1;
5206
5206
  for (let p = 0; p < len; p++) {
5207
- const values2 = tokenLists.map((t) => t[p]);
5208
- const allSame = values2.every((v) => v === values2[0]);
5207
+ const values = tokenLists.map((t) => t[p]);
5208
+ const allSame = values.every((v) => v === values[0]);
5209
5209
  if (allSame) continue;
5210
- if (position !== -1) return null;
5210
+ const allNumeric = values.every((v) => /^\d+$/.test(v));
5211
+ if (!allNumeric || position !== -1) return null;
5211
5212
  position = p;
5212
5213
  }
5213
5214
  if (position === -1) return null;
5214
- const values = tokenLists.map((t) => t[position]);
5215
- const numericCount = values.filter((v) => /^\d+$/.test(v)).length;
5216
- if (numericCount !== 0 && numericCount !== values.length) return null;
5217
- if (numericCount === 0 && position === len - 1) return null;
5218
5215
  const group = tokenLists[0].slice(0, position).join("-");
5219
5216
  if (!group) return null;
5220
- if (new Set(values).size !== values.length) return null;
5221
- return numericCount === values.length ? { position, group } : { position, group, slug: true };
5217
+ const indices = tokenLists.map((t) => parseInt(t[position], 10));
5218
+ if (new Set(indices).size !== indices.length) return null;
5219
+ return { position, group };
5222
5220
  }
5223
5221
  function singleIndexSegment(key) {
5224
5222
  const tokens = baseKey(key).split("-");
@@ -5264,19 +5262,7 @@ function detectItemGroups(sectionEl) {
5264
5262
  list.push(m);
5265
5263
  byShape.set(shape, list);
5266
5264
  }
5267
- const shaped = Array.from(byShape.values());
5268
- clusters.push(...shaped.filter((c) => c.length >= 2));
5269
- const singles = shaped.filter((c) => c.length === 1).map((c) => c[0]);
5270
- const bySlugShape = /* @__PURE__ */ new Map();
5271
- for (const m of singles) {
5272
- const primary = primaryKey(keyedDescendants(m));
5273
- const tokens = baseKey(primary ?? "").split("-");
5274
- const slugShape = `${tokens.length}|${tokens[0]}|${tokens[tokens.length - 1]}`;
5275
- const list = bySlugShape.get(slugShape) ?? [];
5276
- list.push(m);
5277
- bySlugShape.set(slugShape, list);
5278
- }
5279
- clusters.push(...Array.from(bySlugShape.values()));
5265
+ clusters.push(...Array.from(byShape.values()));
5280
5266
  }
5281
5267
  for (const members of clusters) {
5282
5268
  const keyedPerMember = members.map((m) => keyedDescendants(m));
@@ -5287,28 +5273,11 @@ function detectItemGroups(sectionEl) {
5287
5273
  const dedupeKey = `${segment.group}`;
5288
5274
  if (seenParents.has(dedupeKey)) continue;
5289
5275
  seenParents.add(dedupeKey);
5290
- let items;
5291
- if (segment.slug) {
5292
- const tokens = members.map((_, i) => baseKey(primaries[i]).split("-")[segment.position]);
5293
- let nextOriginal = 1;
5294
- const indices = tokens.map((t) => {
5295
- const cloneMatch = t.match(/^x(\d+)$/);
5296
- return cloneMatch ? parseInt(cloneMatch[1], 10) : nextOriginal++;
5297
- });
5298
- if (new Set(indices).size !== indices.length) continue;
5299
- items = members.map((el, i) => ({
5300
- el,
5301
- index: indices[i],
5302
- keyed: keyedPerMember[i],
5303
- slugToken: tokens[i]
5304
- }));
5305
- } else {
5306
- items = members.map((el, i) => ({
5307
- el,
5308
- index: indexFromKey(primaries[i], segment.position),
5309
- keyed: keyedPerMember[i]
5310
- }));
5311
- }
5276
+ const items = members.map((el, i) => ({
5277
+ el,
5278
+ index: indexFromKey(primaries[i], segment.position),
5279
+ keyed: keyedPerMember[i]
5280
+ }));
5312
5281
  groups.push({ group: segment.group, parent, nested: false, items });
5313
5282
  }
5314
5283
  }
@@ -5432,18 +5401,6 @@ function rekeyItemClone(clone, source, sibling, group, newIndex) {
5432
5401
  const delta = newIndex - source.index;
5433
5402
  const cloneKeyed = keyedDescendants(clone);
5434
5403
  const pairs = [];
5435
- if (source.slugToken) {
5436
- source.keyed.forEach((src, i) => {
5437
- const target = cloneKeyed[i];
5438
- if (!target || target.attr !== src.attr) return;
5439
- const tokens = baseKey(src.key).split("-");
5440
- if (!tokens.includes(source.slugToken)) return;
5441
- const next = tokens.map((t) => t === source.slugToken ? `x${newIndex}` : t).join("-") + keySuffix(src.key);
5442
- target.el.setAttribute(src.attr, next);
5443
- pairs.push({ from: src.key, to: next });
5444
- });
5445
- return pairs;
5446
- }
5447
5404
  source.keyed.forEach((src, i) => {
5448
5405
  const target = cloneKeyed[i];
5449
5406
  if (!target || target.attr !== src.attr) return;
@@ -5487,12 +5444,7 @@ function syncGroup(detected, state) {
5487
5444
  clone.setAttribute(ITEM_ATTR, `${detected.group}:${entry.index}`);
5488
5445
  rekeyItemClone(clone, source, sibling, detected.group, entry.index);
5489
5446
  source.el.insertAdjacentElement("afterend", clone);
5490
- byIndex.set(entry.index, {
5491
- el: clone,
5492
- index: entry.index,
5493
- keyed: keyedDescendants(clone),
5494
- ...source.slugToken ? { slugToken: `x${entry.index}` } : {}
5495
- });
5447
+ byIndex.set(entry.index, { el: clone, index: entry.index, keyed: keyedDescendants(clone) });
5496
5448
  }
5497
5449
  const listed = state.items.map((e) => byIndex.get(e.index)?.el).filter((el) => !!el);
5498
5450
  let prev = null;
@@ -5594,16 +5546,9 @@ function applyItemOps(store, ops, currentContent) {
5594
5546
  const nodes = [];
5595
5547
  const added = [];
5596
5548
  let elements = syncGroup(detected, state);
5597
- const sluggy = detected.items.some((item) => item.slugToken);
5598
- const slugTokenOf = (index) => detected.items.find((item) => item.index === index)?.slugToken ?? (sluggy ? `x${index}` : void 0);
5599
5549
  for (const add of ops.add ?? []) {
5600
5550
  const sourceEl = elements.get(add.cloneOf);
5601
- const source = sourceEl ? {
5602
- el: sourceEl,
5603
- index: add.cloneOf,
5604
- keyed: keyedDescendants(sourceEl),
5605
- ...slugTokenOf(add.cloneOf) ? { slugToken: slugTokenOf(add.cloneOf) } : {}
5606
- } : void 0;
5551
+ const source = sourceEl ? { el: sourceEl, index: add.cloneOf, keyed: keyedDescendants(sourceEl) } : void 0;
5607
5552
  if (!source) continue;
5608
5553
  const newIndex = Math.max(...state.items.map((e) => e.index), ...detected.items.map((i) => i.index)) + 1;
5609
5554
  const sibling = detected.items.find((item) => item.index !== add.cloneOf && !item.el.hasAttribute(ITEM_CLONE_ATTR)) ?? null;
@@ -5630,12 +5575,7 @@ function applyItemOps(store, ops, currentContent) {
5630
5575
  if (anchor) anchor.insertAdjacentElement("afterend", clone);
5631
5576
  else source.el.insertAdjacentElement("afterend", clone);
5632
5577
  elements.set(newIndex, clone);
5633
- detected.items.push({
5634
- el: clone,
5635
- index: newIndex,
5636
- keyed: cloneKeyed,
5637
- ...sluggy ? { slugToken: `x${newIndex}` } : {}
5638
- });
5578
+ detected.items.push({ el: clone, index: newIndex, keyed: cloneKeyed });
5639
5579
  added.push(newIndex);
5640
5580
  elements = syncGroup(detected, state);
5641
5581
  }
@@ -6078,25 +6018,16 @@ function foldAlignIntoTrees(state, store) {
6078
6018
  nextTrees.set(id, fresh);
6079
6019
  return fresh;
6080
6020
  };
6081
- const stripChildAligns = (node) => node.children ? {
6082
- ...node,
6083
- children: node.children.map((child) => {
6084
- const { align: _dropped, ...rest } = child;
6085
- return stripChildAligns(rest);
6086
- })
6087
- } : node;
6088
6021
  const nodes = {};
6089
6022
  for (const [key, override] of Object.entries(store.nodes)) {
6090
6023
  const match = override.align !== void 0 && key.startsWith(AI_SLOT_KEY_PREFIX) ? key.match(/^ai\.(.+?)\.r(\d+)\.b(\d+)(?:\.|$)/) : null;
6091
6024
  const tree = match ? treeFor(match[1]) : void 0;
6092
- const row = match && tree ? tree.rows[Number(match[2])] : void 0;
6093
- const blockIdx = match ? Number(match[3]) : -1;
6094
- const block = row?.blocks[blockIdx];
6095
- if (!row || !block) {
6025
+ const block = match && tree ? tree.rows[Number(match[2])]?.blocks[Number(match[3])] : void 0;
6026
+ if (!block) {
6096
6027
  nodes[key] = override;
6097
6028
  continue;
6098
6029
  }
6099
- row.blocks[blockIdx] = { ...stripChildAligns(block), align: override.align };
6030
+ block.align = override.align;
6100
6031
  const rest = { ...override };
6101
6032
  delete rest.align;
6102
6033
  if (Object.keys(rest).length > 0) nodes[key] = rest;
@@ -6109,7 +6040,7 @@ function foldAlignIntoTrees(state, store) {
6109
6040
  continue;
6110
6041
  }
6111
6042
  for (const row of tree.rows) {
6112
- row.blocks = row.blocks.map((block) => ({ ...stripChildAligns(block), align: override.align }));
6043
+ for (const block of row.blocks) block.align = override.align;
6113
6044
  }
6114
6045
  const rest = { ...override };
6115
6046
  delete rest.align;
@@ -7270,7 +7201,6 @@ var blockAlignStyle = (blockAlign) => blockAlign ? {
7270
7201
  alignItems: blockAlign === "left" ? "flex-start" : blockAlign === "right" ? "flex-end" : "center",
7271
7202
  textAlign: blockAlign
7272
7203
  } : {};
7273
- var fullBleedBlock = (block) => block.type === "carousel" || block.type === "group" && str(block.slots?.layout) === "overlap";
7274
7204
  var featureLines = (value) => value.split(/\n|<br\s*\/?>/i).map((line) => line.trim()).filter(Boolean);
7275
7205
  var AI_MOBILE_CSS = [
7276
7206
  // Unscoped (applies at every viewport, not just mobile): re-enables pointer-events for the
@@ -7315,7 +7245,7 @@ var AI_MOBILE_CSS = [
7315
7245
  // page's first section. Top only (bottom needs no nav clearance); ~96px approximates the
7316
7246
  // template nav's own height (measured ~94px) — there's no shared `--ohw-header-h` var to read
7317
7247
  // an exact figure from (no live measurement exists), so this is a safe approximation, not a
7318
- // pixel-exact fit. Horizontal spacing already comes from `data-ai-section-inner`.
7248
+ // pixel-exact fit. Horizontal spacing already comes from `data-ai-container`.
7319
7249
  '[data-ai-overlay-clearance] [data-ai-overlap-layer="overlay"]{padding-top:96px}',
7320
7250
  // A full-bleed carousel's height is pure arithmetic: it spans the whole window, so 16/9 turns
7321
7251
  // window width straight into height. Measured at 16/9 it came out ~90% of the viewport at EVERY
@@ -7331,10 +7261,8 @@ var AI_MOBILE_CSS = [
7331
7261
  "[data-ai-section]{overflow-x:hidden}",
7332
7262
  // `:not([data-ai-full-bleed])`: this `!important` gutter beat the inline `padding: 0` that a
7333
7263
  // full-bleed section's container sets, so a carousel/media hero that is edge-to-edge on desktop
7334
- // still got a 20px band of section background down both sides on a phone. The footer's own
7335
- // container keeps the unguarded rule below — `data-ai-full-bleed` can never appear on it.
7336
- "[data-ai-section-inner]:not([data-ai-full-bleed]){padding:0 20px !important}",
7337
- "[data-ai-container]{padding:0 20px !important}",
7264
+ // still got a 20px band of section background down both sides on a phone.
7265
+ "[data-ai-container]:not([data-ai-full-bleed]){padding:0 20px !important}",
7338
7266
  "[data-ai-row]{display:flex !important;flex-direction:column !important;align-items:stretch !important}",
7339
7267
  "[data-ai-cell]{width:100%;min-width:0}",
7340
7268
  // The rule above turns every row into a COLUMN flex container on phones, which silently breaks
@@ -7539,31 +7467,6 @@ function pricingCardEmphasis(featured, ctx, hasBg) {
7539
7467
  function textAttrs(ctx, path) {
7540
7468
  return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
7541
7469
  }
7542
- var AI_RESPONSIVE_CSS = [
7543
- "@media (max-width: 960px) {",
7544
- " [data-ai-responsive] [data-ai-grid] { grid-template-columns: repeat(2, 1fr) !important; }",
7545
- ' [data-ai-responsive] [data-ai-grid="1"] { grid-template-columns: 1fr !important; }',
7546
- "}",
7547
- "@media (max-width: 640px) {",
7548
- " [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
7549
- " [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
7550
- // Group containers flatten to a column on phones; span placements come along for free.
7551
- // `:not([data-ai-group="overlap"])` for the same reason as the twin pair in AI_MOBILE_CSS — see
7552
- // the comment there. This sheet's copy is the narrower selector, so without the exemption it
7553
- // flattens an `overlap` hero below 640px even though the other rule stands down: measured a 390px
7554
- // viewport with the heading/CTA in flow *under* the image, 219px of section background where the
7555
- // layered text used to be.
7556
- ' [data-ai-responsive] [data-ai-group]:not([data-ai-group="overlap"]) { display: flex !important; flex-direction: column !important; }',
7557
- ' [data-ai-responsive] [data-ai-group]:not([data-ai-group="overlap"]) > * { grid-column: auto !important; }',
7558
- // `:not([data-ai-full-bleed])` for the same reason as the twin rule in AI_MOBILE_CSS: this one
7559
- // is narrower (0,2,0 vs 0,1,0) and also `!important`, so without the guard it wins outright and
7560
- // a full-bleed hero gets its 20px side band back below 640px only — the one width where the
7561
- // other rule had already been taught to stand down.
7562
- " [data-ai-responsive] [data-ai-section-inner]:not([data-ai-full-bleed]) { padding-left: 20px !important; padding-right: 20px !important; }",
7563
- " [data-ai-responsive] { overflow-x: hidden; }",
7564
- " [data-ai-responsive] img { max-width: 100%; }",
7565
- "}"
7566
- ].join("\n");
7567
7470
  var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
7568
7471
  function MediaBox({
7569
7472
  refValue,
@@ -7584,9 +7487,9 @@ function MediaBox({
7584
7487
  const url = refValue ? ctx.resolveMedia(refValue) : null;
7585
7488
  const isIcon = /^(lucide|simple):/.test(refValue);
7586
7489
  const aspectRatio = aspect && /^\d+:\d+$/.test(aspect) ? aspect.replace(":", " / ") : void 0;
7587
- const editAttrs = ctx.keyFor && editPath ? {
7490
+ const editAttrs = ctx.keyFor && editPath && !isIcon ? {
7588
7491
  "data-ohw-key": ctx.keyFor(editPath),
7589
- ...isIcon ? { "data-ohw-editable": "icon" } : genericImageEdit ? { "data-ohw-editable": "image" } : {}
7492
+ ...genericImageEdit ? { "data-ohw-editable": "image" } : {}
7590
7493
  } : {};
7591
7494
  if (isIcon) {
7592
7495
  const Icon = refValue.startsWith("lucide:") ? lucideByName(refValue.slice(7)) : null;
@@ -7594,7 +7497,6 @@ function MediaBox({
7594
7497
  "span",
7595
7498
  {
7596
7499
  "data-ai-icon": refValue,
7597
- ...editAttrs,
7598
7500
  style: {
7599
7501
  display: "inline-flex",
7600
7502
  width: 48,
@@ -9100,7 +9002,7 @@ function CollectionBlock({ node, ctx, path }) {
9100
9002
  return /* @__PURE__ */ jsx(
9101
9003
  "div",
9102
9004
  {
9103
- "data-ai-grid": String(itemsPerRow),
9005
+ "data-ai-grid": "",
9104
9006
  "data-ohw-pricing-collection": isPricing ? "" : void 0,
9105
9007
  style: {
9106
9008
  display: "grid",
@@ -9360,12 +9262,12 @@ function renderNode(node, ctx, path, ambientAlign) {
9360
9262
  },
9361
9263
  children: [
9362
9264
  i > 0 && ctx.heroOverlapFullBleed ? (
9363
- // The section's `data-ai-section-inner` gave up its max-width/gutter so the base
9265
+ // The section's `data-ai-container` gave up its max-width/gutter so the base
9364
9266
  // layer (this group's i===0 sibling) can span edge-to-edge — reintroduced here,
9365
9267
  // scoped to just the overlay text, so a heading/copy/CTA stack doesn't stretch
9366
9268
  // the full section width instead of reading at the usual content width.
9367
- /* @__PURE__ */ jsx("div", { style: { maxWidth: AI_TREE_TOKENS.sectionMaxWidth, margin: "0 auto", padding: "0 40px", width: "100%", boxSizing: "border-box" }, children: renderNode(child, ctx, `${path}.c${i}`, child.align ?? node.align ?? "center") })
9368
- ) : renderNode(child, ctx, `${path}.c${i}`, i > 0 ? child.align ?? node.align ?? "center" : void 0),
9269
+ /* @__PURE__ */ jsx("div", { style: { maxWidth: AI_TREE_TOKENS.sectionMaxWidth, margin: "0 auto", padding: "0 40px", width: "100%", boxSizing: "border-box" }, children: renderNode(child, ctx, `${path}.c${i}`, child.align ?? "center") })
9270
+ ) : renderNode(child, ctx, `${path}.c${i}`, i > 0 ? child.align ?? "center" : void 0),
9369
9271
  i === 0 && needsBaseScrim && /* @__PURE__ */ jsx(
9370
9272
  "div",
9371
9273
  {
@@ -9398,7 +9300,7 @@ function renderNode(node, ctx, path, ambientAlign) {
9398
9300
  // child otherwise stretches full-width (unchanged pre-existing behaviour).
9399
9301
  ...blockAlignStyle(child.align ?? ambientAlign)
9400
9302
  },
9401
- children: renderNode(child, ctx, `${path}.c${i}`, node.align ?? ambientAlign)
9303
+ children: renderNode(child, ctx, `${path}.c${i}`, ambientAlign)
9402
9304
  },
9403
9305
  i
9404
9306
  ));
@@ -9428,20 +9330,8 @@ function renderNode(node, ctx, path, ambientAlign) {
9428
9330
  }
9429
9331
  case "button":
9430
9332
  return /* @__PURE__ */ jsx(ButtonEl, { slots, ctx, path });
9431
- case "button-row": {
9432
- const rowAlign = node.align ?? ambientAlign;
9433
- return /* @__PURE__ */ jsx(
9434
- "div",
9435
- {
9436
- style: {
9437
- display: "flex",
9438
- gap: AI_TREE_TOKENS.spacing6,
9439
- justifyContent: rowAlign === "left" ? "flex-start" : rowAlign === "right" ? "flex-end" : "center"
9440
- },
9441
- children: (node.children ?? []).map((child, i) => /* @__PURE__ */ jsx(ButtonEl, { slots: child.slots ?? {}, ctx, path: `${path}.c${i}` }, i))
9442
- }
9443
- );
9444
- }
9333
+ case "button-row":
9334
+ return /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: AI_TREE_TOKENS.spacing6, justifyContent: "center" }, children: (node.children ?? []).map((child, i) => /* @__PURE__ */ jsx(ButtonEl, { slots: child.slots ?? {}, ctx, path: `${path}.c${i}` }, i)) });
9445
9335
  case "media":
9446
9336
  return /* @__PURE__ */ jsx(
9447
9337
  MediaBox,
@@ -9765,7 +9655,6 @@ function AiTreeRenderer({
9765
9655
  ...fillHeight ? { "data-ai-fill-height": "" } : {},
9766
9656
  ...needsOverlayClearance ? { "data-ai-overlay-clearance": "" } : {},
9767
9657
  ...bgAttrs,
9768
- "data-ai-responsive": "",
9769
9658
  style: {
9770
9659
  position: "relative",
9771
9660
  padding: `${padCss} 0`,
@@ -9779,13 +9668,12 @@ function AiTreeRenderer({
9779
9668
  ...fillHeight ? { display: "grid" } : {}
9780
9669
  },
9781
9670
  children: [
9782
- /* @__PURE__ */ jsx("style", { children: AI_RESPONSIVE_CSS }),
9783
- /* @__PURE__ */ jsx("style", { children: AI_MOBILE_CSS }),
9784
9671
  isOverlay && backgroundUrl && /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, background: `rgba(255,255,255,${overlayAlpha})` } }),
9672
+ /* @__PURE__ */ jsx("style", { children: AI_MOBILE_CSS }),
9785
9673
  /* @__PURE__ */ jsx(
9786
9674
  "div",
9787
9675
  {
9788
- "data-ai-section-inner": "",
9676
+ "data-ai-container": "",
9789
9677
  ...fullBleedMedia ? { "data-ai-full-bleed": "" } : {},
9790
9678
  style: {
9791
9679
  position: "relative",
@@ -9802,7 +9690,7 @@ function AiTreeRenderer({
9802
9690
  children: tree.rows.map((row, r2) => /* @__PURE__ */ jsx(
9803
9691
  "div",
9804
9692
  {
9805
- "data-ai-columns": "",
9693
+ "data-ai-row": "",
9806
9694
  style: {
9807
9695
  display: "grid",
9808
9696
  gridTemplateColumns: "repeat(12, 1fr)",
@@ -9822,7 +9710,7 @@ function AiTreeRenderer({
9822
9710
  // its own horizontal `align`, which takes priority for that block.
9823
9711
  ...fillHeight ? { display: "grid" } : {},
9824
9712
  // Horizontal placement of the block's content within its column.
9825
- ...fullBleedBlock(block) ? {} : cellAlignStyle(block.align),
9713
+ ...cellAlignStyle(block.align),
9826
9714
  // space-between: each column becomes a flex column whose content spreads over
9827
9715
  // the full row height instead of clumping at the top.
9828
9716
  ...distributed === "space-between" ? { display: "flex", flexDirection: "column", justifyContent: "space-between" } : {}
@@ -10458,10 +10346,9 @@ function applyAiSectionsToDom(state, options) {
10458
10346
  if (existing && existing.serialized === serialized && existing.container.isConnected) {
10459
10347
  continue;
10460
10348
  }
10349
+ const isNewMount = !existing || !existing.container.isConnected;
10461
10350
  let container = existing?.container;
10462
- let isNewMount = false;
10463
10351
  if (!container || !container.isConnected) {
10464
- isNewMount = true;
10465
10352
  existing?.root.unmount();
10466
10353
  container?.remove();
10467
10354
  container = document.createElement("div");
@@ -16903,7 +16790,6 @@ function MediaOverlay({
16903
16790
  (prev) => prev && prev.fullWidth === width && prev.height === height ? prev : { fullWidth: width, height }
16904
16791
  );
16905
16792
  }, [isVideo]);
16906
- const replaceLabel = isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image";
16907
16793
  const replaceMode = buttonSize ? replaceButtonMode({ width: rect.width, height: rect.height }, buttonSize) : "none";
16908
16794
  const box = {
16909
16795
  position: "fixed",
@@ -17002,10 +16888,11 @@ function MediaOverlay({
17002
16888
  className: "flex items-center justify-center cursor-pointer",
17003
16889
  style: {
17004
16890
  ...box,
17005
- // Visual only. `pointer-events: auto` on this full-bleed rect covered the navbar
17006
- // (hero bg includes the absolute TopNav) and swallowed CTA press-drag. Text overlay
17007
- // and cueOnly also need clicks to fall through — Replace / video controls opt back in.
17008
- pointerEvents: "none",
16891
+ // When text overlays this media, let clicks fall THROUGH to the text underneath. In the
16892
+ // parent this needed a whole `ow:click-at` round-trip to re-hit-test inside the iframe;
16893
+ // in-document, pointer-events does it natively. The button below opts back in, so
16894
+ // Replace still works.
16895
+ pointerEvents: hover.hasTextOverlap || cueOnly ? "none" : "auto",
17009
16896
  // Selected: a firm component ring with no wash, so the image reads as chosen rather
17010
16897
  // than hovered. Hover keeps the existing tinted preview.
17011
16898
  boxShadow: selected ? "inset 0 0 0 2px var(--color-bridge-primary)" : "inset 0 0 0 1.5px var(--color-bridge-primary)",
@@ -17032,17 +16919,17 @@ function MediaOverlay({
17032
16919
  },
17033
16920
  children: [
17034
16921
  isVideo ? /* @__PURE__ */ jsx16(Film, { size: 14 }) : /* @__PURE__ */ jsx16(ImageIcon, { size: 14 }),
17035
- replaceLabel
16922
+ isVideo ? "Replace video" : "Replace image"
17036
16923
  ]
17037
16924
  }
17038
16925
  ),
17039
- showChrome && replaceMode !== "none" && /* @__PURE__ */ jsxs7(
16926
+ replaceMode === "none" || cueOnly ? null : /* @__PURE__ */ jsxs7(
17040
16927
  Button,
17041
16928
  {
17042
16929
  "data-ohw-media-overlay": "",
17043
16930
  variant: "outline",
17044
16931
  size: "sm",
17045
- "aria-label": replaceLabel,
16932
+ "aria-label": isVideo ? "Replace video" : "Replace image",
17046
16933
  className: "gap-1.5 cursor-pointer hover:bg-background",
17047
16934
  style: {
17048
16935
  ...OVERLAY_BUTTON_STYLE,
@@ -17065,7 +16952,7 @@ function MediaOverlay({
17065
16952
  },
17066
16953
  children: [
17067
16954
  isVideo ? /* @__PURE__ */ jsx16(Film, { size: 14 }) : /* @__PURE__ */ jsx16(ImageIcon, { size: 14 }),
17068
- replaceMode === "full" ? replaceLabel : null
16955
+ replaceMode === "full" ? isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image" : null
17069
16956
  ]
17070
16957
  }
17071
16958
  )
@@ -18457,23 +18344,10 @@ function setPricingCardStyle(tree, index, style) {
18457
18344
  });
18458
18345
  }
18459
18346
  function setPricingCardFeaturedTag(tree, index, on) {
18460
- return withPricingCollection(tree, (collection) => {
18461
- const children = collection.children;
18462
- if (index < 0 || index >= children.length) return false;
18463
- if (on) {
18464
- children.forEach((card, i) => {
18465
- if (i === index) return;
18466
- const prev2 = featuredOf(card);
18467
- if (prev2.enabled !== true || badgeOf(prev2).length === 0) return;
18468
- card.slots = card.slots ?? {};
18469
- card.slots.featured = composeFeatured(pricingCardStyleOf(prev2), false, badgeOf(prev2));
18470
- });
18471
- }
18472
- const target = children[index];
18473
- target.slots = target.slots ?? {};
18347
+ return withPricingCard(tree, index, (target) => {
18474
18348
  const prev = featuredOf(target);
18475
- target.slots.featured = composeFeatured(pricingCardStyleOf(prev), on, badgeOf(prev));
18476
- return true;
18349
+ const style = pricingCardStyleOf(prev);
18350
+ target.slots.featured = composeFeatured(style, on, badgeOf(prev));
18477
18351
  });
18478
18352
  }
18479
18353
  function pricingCardStyleOf(featured) {
@@ -18723,40 +18597,25 @@ function ToolbarSeparator() {
18723
18597
  }
18724
18598
  function CardStyleMenu({
18725
18599
  value,
18726
- onChange,
18727
- disabled = false
18600
+ onChange
18728
18601
  }) {
18729
18602
  const current = PRICING_CARD_STYLES.find((s) => s.value === value) ?? PRICING_CARD_STYLES[0];
18730
- const trigger = /* @__PURE__ */ jsxs11(
18731
- "button",
18732
- {
18733
- type: "button",
18734
- "aria-label": "Card style",
18735
- disabled,
18736
- className: cn(
18737
- "inline-flex h-8 min-w-[110px] items-center gap-[7px] rounded-[6px] bg-transparent px-2 text-[13px] font-medium text-foreground transition-colors hover:bg-muted data-[state=open]:bg-muted",
18738
- disabled && "cursor-not-allowed opacity-40 hover:bg-transparent"
18739
- ),
18740
- children: [
18741
- /* @__PURE__ */ jsx20(StyleSwatch, { style: current.value }),
18742
- /* @__PURE__ */ jsx20("span", { className: "flex-1 text-left", children: current.label }),
18743
- /* @__PURE__ */ jsx20(ChevronDown3, { size: 16, style: { pointerEvents: "none" } })
18744
- ]
18745
- }
18746
- );
18747
- if (disabled) {
18748
- return /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
18749
- /* @__PURE__ */ jsx20("span", { className: "text-xs text-muted-foreground opacity-50", children: "Card style" }),
18750
- /* @__PURE__ */ jsxs11(Tooltip, { children: [
18751
- /* @__PURE__ */ jsx20(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx20("span", { className: "inline-flex", children: trigger }) }),
18752
- /* @__PURE__ */ jsx20(TooltipContent, { side: "bottom", sideOffset: 8, children: "Mark as featured to edit card style" })
18753
- ] })
18754
- ] });
18755
- }
18756
18603
  return /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
18757
18604
  /* @__PURE__ */ jsx20("span", { className: "text-xs text-muted-foreground", children: "Card style" }),
18758
18605
  /* @__PURE__ */ jsxs11(DropdownMenu, { modal: false, children: [
18759
- /* @__PURE__ */ jsx20(DropdownMenuTrigger, { asChild: true, children: trigger }),
18606
+ /* @__PURE__ */ jsx20(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs11(
18607
+ "button",
18608
+ {
18609
+ type: "button",
18610
+ "aria-label": "Card style",
18611
+ className: "inline-flex h-8 min-w-[110px] items-center gap-[7px] rounded-[6px] bg-transparent px-2 text-[13px] font-medium text-foreground transition-colors hover:bg-muted data-[state=open]:bg-muted",
18612
+ children: [
18613
+ /* @__PURE__ */ jsx20(StyleSwatch, { style: current.value }),
18614
+ /* @__PURE__ */ jsx20("span", { className: "flex-1 text-left", children: current.label }),
18615
+ /* @__PURE__ */ jsx20(ChevronDown3, { size: 16, style: { pointerEvents: "none" } })
18616
+ ]
18617
+ }
18618
+ ) }),
18760
18619
  /* @__PURE__ */ jsx20(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[152px] min-w-[152px] p-1", children: PRICING_CARD_STYLES.map((style) => {
18761
18620
  const selected = style.value === value;
18762
18621
  return /* @__PURE__ */ jsxs11(
@@ -18820,35 +18679,23 @@ function PricingCardToolbar({
18820
18679
  mobile ? "flex-wrap justify-center" : "flex-nowrap"
18821
18680
  ),
18822
18681
  children: [
18682
+ /* @__PURE__ */ jsx20(CardStyleMenu, { value: style, onChange: onSetStyle }),
18823
18683
  /* @__PURE__ */ jsxs11(Tooltip, { children: [
18824
18684
  /* @__PURE__ */ jsx20(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx20(
18825
18685
  CustomToolbarButton,
18826
18686
  {
18827
18687
  type: "button",
18828
- "aria-label": featuredTag ? "Unmark as featured" : "Mark as featured",
18688
+ "aria-label": featuredTag ? "Remove featured tag" : "Add featured tag",
18829
18689
  "aria-pressed": featuredTag,
18690
+ active: featuredTag,
18830
18691
  onClick: () => onSetFeaturedTag(!featuredTag),
18831
- className: "group size-8",
18832
- children: /* @__PURE__ */ jsx20(
18833
- Star2,
18834
- {
18835
- size: 16,
18836
- fill: "currentColor",
18837
- strokeWidth: 0,
18838
- className: cn(
18839
- "transition-colors",
18840
- featuredTag ? "text-[#f59e0b] group-hover:text-[#d97706]" : "text-[#d6d3d1] group-hover:text-[#fbbf24]"
18841
- ),
18842
- style: { pointerEvents: "none" }
18843
- }
18844
- )
18692
+ className: "size-8",
18693
+ children: /* @__PURE__ */ jsx20(Star2, { size: 16, fill: featuredTag ? "currentColor" : "none", style: { pointerEvents: "none" } })
18845
18694
  }
18846
18695
  ) }),
18847
- /* @__PURE__ */ jsx20(TooltipContent, { side: "bottom", sideOffset: 8, children: featuredTag ? "Unmark featured" : "Mark as featured" })
18696
+ /* @__PURE__ */ jsx20(TooltipContent, { side: "bottom", sideOffset: 8, children: featuredTag ? "Remove featured tag" : "Add featured tag" })
18848
18697
  ] }),
18849
18698
  /* @__PURE__ */ jsx20(ToolbarSeparator, {}),
18850
- /* @__PURE__ */ jsx20(CardStyleMenu, { value: style, onChange: onSetStyle, disabled: !featuredTag }),
18851
- /* @__PURE__ */ jsx20(ToolbarSeparator, {}),
18852
18699
  /* @__PURE__ */ jsx20(ToolbarAction, { label: "Add button", onClick: onAddButton, disabled: buttonCount >= 2, children: /* @__PURE__ */ jsx20(ButtonGlyph, {}) }),
18853
18700
  /* @__PURE__ */ jsx20(ToolbarAction, { label: "Remove button", onClick: onRemoveButton, disabled: buttonCount === 0, children: /* @__PURE__ */ jsxs11("span", { className: "relative inline-flex", children: [
18854
18701
  /* @__PURE__ */ jsx20(ButtonGlyph, {}),
@@ -18991,12 +18838,7 @@ function AiPricingCardOverlay({
18991
18838
  index: active.index,
18992
18839
  pending,
18993
18840
  error,
18994
- onAddTier: () => {
18995
- const newIndex = pricingCardCount(activeEntry.tree);
18996
- void runMutation(active.sectionId, addPricingTier).then((applied) => {
18997
- if (applied) setActive({ sectionId: active.sectionId, index: newIndex });
18998
- });
18999
- },
18841
+ onAddTier: () => runMutation(active.sectionId, addPricingTier),
19000
18842
  onRemoveTier: () => {
19001
18843
  void runMutation(active.sectionId, (tree) => removePricingTier(tree, active.index)).then(
19002
18844
  (applied) => {
@@ -21545,7 +21387,6 @@ function shouldUseDevFixtures() {
21545
21387
  function getLogoElement(el) {
21546
21388
  const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
21547
21389
  if (marked) return marked;
21548
- if (el.closest('[data-ohw-editable="icon"]')) return null;
21549
21390
  const root = el.closest("nav, [data-ohw-nav-root], footer");
21550
21391
  if (!root) return null;
21551
21392
  const anchor = el.closest("a");
@@ -24115,7 +23956,7 @@ function getNavigationSelectionParent(el) {
24115
23956
  if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
24116
23957
  return resolveFooterLinksContainerFrom(el);
24117
23958
  }
24118
- 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)) {
23959
+ if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
24119
23960
  return getNavigationRoot(el);
24120
23961
  }
24121
23962
  return null;
@@ -24337,6 +24178,7 @@ var ICONS = {
24337
24178
  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"/>',
24338
24179
  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"/>'
24339
24180
  };
24181
+ var HEIGHT_SETTLE_DELAYS = [150, 400, 800];
24340
24182
  var SELECTION_CHROME_GAP2 = 4;
24341
24183
  var TOOLBAR_STROKE_GAP2 = 4;
24342
24184
  var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
@@ -25316,6 +25158,21 @@ function OhhwellsBridge() {
25316
25158
  const [isItemDragging, setIsItemDragging] = useState18(false);
25317
25159
  const [isFooterFrameSelection, setIsFooterFrameSelection] = useState18(false);
25318
25160
  isFooterFrameSelectionRef.current = isFooterFrameSelection;
25161
+ const [floatingPanel, setFloatingPanel] = useState18(null);
25162
+ const floatingPanelOpenRef = useRef14(false);
25163
+ floatingPanelOpenRef.current = floatingPanel !== null;
25164
+ const floatingPanelRef = useRef14(null);
25165
+ floatingPanelRef.current = floatingPanel;
25166
+ const [floatingPanelPos, setFloatingPanelPos] = useState18(null);
25167
+ const buttonCollectionDragRef = useRef14(null);
25168
+ const buttonDropInsertIndexRef = useRef14(null);
25169
+ const [buttonDropSlots, setButtonDropSlots] = useState18([]);
25170
+ const [activeButtonDropIndex, setActiveButtonDropIndex] = useState18(null);
25171
+ const buttonPointerDragRef = useRef14(null);
25172
+ const [buttonStyleTick, setButtonStyleTick] = useState18(0);
25173
+ const [logoSizeDraft, setLogoSizeDraft] = useState18(null);
25174
+ const [editorViewport, setEditorViewport] = useState18("desktop");
25175
+ const [parentScrollSnap, setParentScrollSnap] = useState18(null);
25319
25176
  const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = useState18(null);
25320
25177
  const [footerHeadingVisible, setFooterHeadingVisible] = useState18(null);
25321
25178
  const footerDragRef = useRef14(null);
@@ -25341,21 +25198,6 @@ function OhhwellsBridge() {
25341
25198
  const stylesRef = useRef14("");
25342
25199
  const appliedDrawerRef = useRef14(null);
25343
25200
  const pendingDeleteUndoRef = useRef14(null);
25344
- const [floatingPanel, setFloatingPanel] = useState18(null);
25345
- const floatingPanelOpenRef = useRef14(false);
25346
- const floatingPanelRef = useRef14(null);
25347
- floatingPanelRef.current = floatingPanel;
25348
- const setFloatingPanelRef = useRef14(setFloatingPanel);
25349
- const [floatingPanelPos, setFloatingPanelPos] = useState18(null);
25350
- const buttonCollectionDragRef = useRef14(null);
25351
- const buttonDropInsertIndexRef = useRef14(null);
25352
- const [buttonDropSlots, setButtonDropSlots] = useState18([]);
25353
- const [activeButtonDropIndex, setActiveButtonDropIndex] = useState18(null);
25354
- const buttonPointerDragRef = useRef14(null);
25355
- const [buttonStyleTick, setButtonStyleTick] = useState18(0);
25356
- const [logoSizeDraft, setLogoSizeDraft] = useState18(null);
25357
- const [editorViewport, setEditorViewport] = useState18("desktop");
25358
- const [parentScrollSnap, setParentScrollSnap] = useState18(null);
25359
25201
  const [sitePages, setSitePages] = useState18([]);
25360
25202
  const [sectionsByPath, setSectionsByPath] = useState18({});
25361
25203
  const sectionsPrefetchGenRef = useRef14(0);
@@ -25364,18 +25206,7 @@ function OhhwellsBridge() {
25364
25206
  const linkPopoverOpenRef = useRef14(false);
25365
25207
  const linkPopoverGraceUntilRef = useRef14(0);
25366
25208
  setLinkPopoverRef.current = setLinkPopover;
25367
- setFloatingPanelRef.current = setFloatingPanel;
25368
25209
  linkPopoverSessionRef.current = linkPopover;
25369
- floatingPanelOpenRef.current = Boolean(floatingPanel);
25370
- useEffect17(() => {
25371
- const syncViewport = () => {
25372
- const next = window.innerWidth <= 480 ? "mobile" : "desktop";
25373
- setEditorViewport((prev) => prev === next ? prev : next);
25374
- };
25375
- syncViewport();
25376
- window.addEventListener("resize", syncViewport);
25377
- return () => window.removeEventListener("resize", syncViewport);
25378
- }, []);
25379
25210
  useEffect17(() => {
25380
25211
  setSectionOrderPersistHandler((entries) => {
25381
25212
  const currentPath = window.location.pathname;
@@ -27054,7 +26885,6 @@ function OhhwellsBridge() {
27054
26885
  applyAiFooterFromContent(content);
27055
26886
  if (typeof content[STYLE_STORE_KEY] === "string") {
27056
26887
  stylesRef.current = content[STYLE_STORE_KEY];
27057
- document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
27058
26888
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
27059
26889
  }
27060
26890
  applyBrandChrome(content);
@@ -27065,12 +26895,12 @@ function OhhwellsBridge() {
27065
26895
  if (key === "__ohw_sections") continue;
27066
26896
  if (key === AI_SECTIONS_KEY) continue;
27067
26897
  if (key === AI_FOOTER_KEY) continue;
27068
- if (key === LOGO_PLACEHOLDER_KEY) continue;
27069
- if (LOGO_IMAGE_KEYS.includes(key)) continue;
27070
26898
  if (key === BRAND_KIT_KEY) continue;
27071
26899
  if (key === STYLE_STORE_KEY) continue;
27072
26900
  if (BRAND_CHROME_KEYS.has(key)) continue;
26901
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
27073
26902
  if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
26903
+ if (LOGO_IMAGE_KEYS.includes(key)) continue;
27074
26904
  if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
27075
26905
  continue;
27076
26906
  }
@@ -27285,18 +27115,17 @@ function OhhwellsBridge() {
27285
27115
  }
27286
27116
  applyAiFooterFromContent(content);
27287
27117
  if (typeof content[STYLE_STORE_KEY] === "string") {
27288
- document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
27289
27118
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
27290
27119
  }
27291
27120
  for (const [key, val] of Object.entries(content)) {
27292
27121
  if (key === "__ohw_sections") continue;
27293
27122
  if (key === AI_SECTIONS_KEY) continue;
27294
27123
  if (key === AI_FOOTER_KEY) continue;
27295
- if (key === LOGO_PLACEHOLDER_KEY) continue;
27296
- if (LOGO_IMAGE_KEYS.includes(key)) continue;
27297
27124
  if (key === BRAND_KIT_KEY) continue;
27298
27125
  if (key === STYLE_STORE_KEY) continue;
27299
27126
  if (BRAND_CHROME_KEYS.has(key)) continue;
27127
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
27128
+ if (LOGO_IMAGE_KEYS.includes(key)) continue;
27300
27129
  if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
27301
27130
  continue;
27302
27131
  }
@@ -27553,11 +27382,26 @@ function OhhwellsBridge() {
27553
27382
  const t2 = setTimeout(measure, 500);
27554
27383
  const ro = new ResizeObserver(schedule);
27555
27384
  ro.observe(document.body);
27385
+ let lastWidth = window.innerWidth;
27386
+ let resizeTimers = [];
27387
+ const clearResizeTimers = () => {
27388
+ resizeTimers.forEach(clearTimeout);
27389
+ resizeTimers = [];
27390
+ };
27391
+ const handleResize = () => {
27392
+ if (window.innerWidth === lastWidth) return;
27393
+ lastWidth = window.innerWidth;
27394
+ clearResizeTimers();
27395
+ resizeTimers = HEIGHT_SETTLE_DELAYS.map((delay) => setTimeout(measure, delay));
27396
+ };
27397
+ window.addEventListener("resize", handleResize);
27556
27398
  return () => {
27557
27399
  clearTimeout(t1);
27558
27400
  clearTimeout(t2);
27559
27401
  if (raf != null) cancelAnimationFrame(raf);
27560
27402
  ro.disconnect();
27403
+ clearResizeTimers();
27404
+ window.removeEventListener("resize", handleResize);
27561
27405
  };
27562
27406
  }, [pathname, isEditMode, postToParent2]);
27563
27407
  useEffect17(() => {
@@ -27852,13 +27696,6 @@ function OhhwellsBridge() {
27852
27696
  if (target.closest("[data-ohw-state-toggle]")) return;
27853
27697
  if (target.closest("[data-ohw-max-badge]")) return;
27854
27698
  if (isInsideLinkEditor(target)) return;
27855
- if (isInsideFloatingPanel(target)) return;
27856
- if (target.closest("[data-ohw-form-toolbar]")) return;
27857
- if (target.closest(
27858
- '[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
27859
- )) {
27860
- return;
27861
- }
27862
27699
  if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
27863
27700
  clearMediaSelectionRef.current();
27864
27701
  }
@@ -27879,6 +27716,13 @@ function OhhwellsBridge() {
27879
27716
  return;
27880
27717
  }
27881
27718
  }
27719
+ if (isInsideFloatingPanel(target)) return;
27720
+ if (target.closest("[data-ohw-form-toolbar]")) return;
27721
+ if (target.closest(
27722
+ '[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
27723
+ )) {
27724
+ return;
27725
+ }
27882
27726
  {
27883
27727
  const formEl = getFormElement(target);
27884
27728
  const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
@@ -28258,9 +28102,6 @@ function OhhwellsBridge() {
28258
28102
  setHoveredItemRect(null);
28259
28103
  hoveredNavContainerRef.current = null;
28260
28104
  setHoveredNavContainerRect(null);
28261
- siblingHintElRef.current = null;
28262
- setSiblingHintRect(null);
28263
- setSiblingHintRects([]);
28264
28105
  return;
28265
28106
  }
28266
28107
  {
@@ -28381,6 +28222,7 @@ function OhhwellsBridge() {
28381
28222
  hoveredNavContainerRef.current = null;
28382
28223
  setHoveredNavContainerRect(null);
28383
28224
  hoveredItemElRef.current = editable;
28225
+ setHoveredItemRect(isSelectedForHoverRef.current(editable) ? null : editable.getBoundingClientRect());
28384
28226
  }
28385
28227
  }
28386
28228
  }
@@ -29090,11 +28932,7 @@ function OhhwellsBridge() {
29090
28932
  };
29091
28933
  const handleMouseMove = (e) => {
29092
28934
  const { clientX, clientY } = e;
29093
- if (pointOwnedByFloatingPanel(clientX, clientY)) {
29094
- dismissImageHover();
29095
- clearImageHover();
29096
- return;
29097
- }
28935
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
29098
28936
  if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) {
29099
28937
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
29100
28938
  formHoverElRef.current = null;
@@ -29123,12 +28961,7 @@ function OhhwellsBridge() {
29123
28961
  setHoveredItemRect(null);
29124
28962
  hoveredNavContainerRef.current = null;
29125
28963
  setHoveredNavContainerRect(null);
29126
- siblingHintElRef.current = null;
29127
- setSiblingHintRect(null);
29128
- setSiblingHintRects([]);
29129
28964
  dismissImageHover();
29130
- clearImageHover();
29131
- setSectionGap(null);
29132
28965
  return;
29133
28966
  }
29134
28967
  if (probeSocialsRowAt(clientX, clientY)) return;
@@ -29140,11 +28973,7 @@ function OhhwellsBridge() {
29140
28973
  if (e.data?.type !== "ow:pointer-sync") return;
29141
28974
  const { clientX, clientY } = e.data;
29142
28975
  if (typeof clientX !== "number" || typeof clientY !== "number") return;
29143
- if (pointOwnedByFloatingPanel(clientX, clientY)) {
29144
- dismissImageHover();
29145
- clearImageHover();
29146
- return;
29147
- }
28976
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
29148
28977
  if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) return;
29149
28978
  if (probeSocialsRowAt(clientX, clientY)) return;
29150
28979
  probeSectionGapAt(clientX, clientY);
@@ -29496,7 +29325,6 @@ function OhhwellsBridge() {
29496
29325
  applyAiFooterFromContent(content);
29497
29326
  if (typeof content[STYLE_STORE_KEY] === "string") {
29498
29327
  stylesRef.current = content[STYLE_STORE_KEY];
29499
- document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
29500
29328
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
29501
29329
  }
29502
29330
  applyBrandChrome(content);
@@ -29511,12 +29339,12 @@ function OhhwellsBridge() {
29511
29339
  }
29512
29340
  if (key === AI_SECTIONS_KEY) continue;
29513
29341
  if (key === AI_FOOTER_KEY) continue;
29514
- if (key === LOGO_PLACEHOLDER_KEY) continue;
29515
- if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
29516
29342
  if (key === BRAND_KIT_KEY) continue;
29517
29343
  if (key === STYLE_STORE_KEY) continue;
29518
29344
  if (BRAND_CHROME_KEYS.has(key)) continue;
29345
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
29519
29346
  if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
29347
+ if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
29520
29348
  if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
29521
29349
  continue;
29522
29350
  }
@@ -30054,12 +29882,6 @@ function OhhwellsBridge() {
30054
29882
  closeLinkPopoverRef.current();
30055
29883
  return;
30056
29884
  }
30057
- if (floatingPanelOpenRef.current) {
30058
- setFloatingPanelRef.current(null);
30059
- deselectRef.current();
30060
- deactivateRef.current();
30061
- return;
30062
- }
30063
29885
  deselectRef.current();
30064
29886
  deactivateRef.current();
30065
29887
  clearMediaSelectionRef.current();
@@ -30429,10 +30251,9 @@ function OhhwellsBridge() {
30429
30251
  if (e.data?.type !== "ow:collect-section") return;
30430
30252
  const sectionId = e.data.sectionId;
30431
30253
  if (typeof sectionId !== "string" || !sectionId) return;
30432
- const foundEl = document.querySelector(
30254
+ const sectionEl = document.querySelector(
30433
30255
  `[data-ohw-section="${CSS.escape(sectionId)}"]`
30434
30256
  );
30435
- const sectionEl = foundEl && !foundEl.hasAttribute("data-ohw-ai-template-hidden") && !foundEl.hasAttribute("data-ohw-ai-removed") && !foundEl.hasAttribute("data-ohw-ai-replaced-by") ? foundEl : null;
30436
30257
  const nodes = sectionEl ? collectEditableNodes(void 0, sectionEl).filter(
30437
30258
  (n) => n.key && !n.key.startsWith("__ohw_") && !["meta", "sections", "video-setting"].includes(n.type)
30438
30259
  ).map((n) => ({ ...n, text: n.text ?? "", type: normalizeAiNodeType(n.type) })) : [];
@@ -30874,10 +30695,10 @@ function OhhwellsBridge() {
30874
30695
  window.removeEventListener("message", handleDeleteSection);
30875
30696
  window.removeEventListener("message", handleDuplicateSection);
30876
30697
  window.removeEventListener("message", handleDeactivate);
30698
+ document.documentElement.removeAttribute("data-ohw-panel-dragging");
30877
30699
  window.removeEventListener("message", handleToastAction);
30878
30700
  window.removeEventListener("message", handleFormCount);
30879
30701
  window.removeEventListener("message", handleUiEscape);
30880
- document.documentElement.removeAttribute("data-ohw-panel-dragging");
30881
30702
  autoSaveTimers.current.forEach(clearTimeout);
30882
30703
  autoSaveTimers.current.clear();
30883
30704
  if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
@@ -32386,7 +32207,6 @@ export {
32386
32207
  dropIndicatorVariants,
32387
32208
  ensureFooterTree,
32388
32209
  filterAvailablePages,
32389
- foldAlignIntoTrees,
32390
32210
  getEditModeInitialState,
32391
32211
  insertFooterHours,
32392
32212
  isEditSessionActive,
@@ -32395,7 +32215,6 @@ export {
32395
32215
  isValidUrl,
32396
32216
  nextViableSlide,
32397
32217
  parseAiFooterState,
32398
- parseAiSectionsState,
32399
32218
  parseTarget,
32400
32219
  removeFooterBlock,
32401
32220
  resolveFooterCopyright,