@ohhwells/bridge 0.1.92-next.267 → 0.1.92-next.272

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
@@ -2642,6 +2642,10 @@ var REPLACED_ATTR = "data-ohw-ai-replaced-by";
2642
2642
  var REMOVED_ATTR2 = "data-ohw-ai-removed";
2643
2643
  var TEMPLATE_HIDDEN_ATTR = "data-ohw-ai-template-hidden";
2644
2644
  var CHROME_SECTION_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
2645
+ function isChromeSection2(el) {
2646
+ if (CHROME_SECTION_IDS.has(el.getAttribute("data-ohw-section") ?? "")) return true;
2647
+ return el.tagName === "HEADER" || el.tagName === "FOOTER";
2648
+ }
2645
2649
  function readRootVar(name) {
2646
2650
  if (typeof document === "undefined") return "";
2647
2651
  return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
@@ -2693,7 +2697,10 @@ function deriveTemplateButtonStyle() {
2693
2697
  ].map((v) => v || "0px");
2694
2698
  const radius = corners.every((v) => v === corners[0]) ? corners[0] : corners.join(" ");
2695
2699
  const px = (v) => parseFloat(v) || 0;
2696
- const padY = Math.max(px(cs.paddingTop), px(cs.paddingBottom));
2700
+ const lineHeight = px(cs.lineHeight) || px(cs.fontSize) * 1.2;
2701
+ const contentH = btn.getBoundingClientRect().height - px(cs.borderTopWidth) - px(cs.borderBottomWidth);
2702
+ const impliedY = Math.round(Math.max(0, (contentH - lineHeight) / 2));
2703
+ const padY = Math.max(px(cs.paddingTop), px(cs.paddingBottom), impliedY);
2697
2704
  const padX = Math.max(px(cs.paddingLeft), px(cs.paddingRight));
2698
2705
  return {
2699
2706
  radius: radius || "10px",
@@ -2719,6 +2726,19 @@ function findPlacementAnchor(id, exclude) {
2719
2726
  for (const el of document.querySelectorAll(`[data-ohw-section="${CSS.escape(id)}"]`)) {
2720
2727
  if (el === exclude) continue;
2721
2728
  if (el.parentElement?.closest("[data-ohw-section]")) continue;
2729
+ if (isChromeSection2(el)) return null;
2730
+ return el;
2731
+ }
2732
+ return null;
2733
+ }
2734
+ function findFooterSection() {
2735
+ const byId = findTemplateSection("footer");
2736
+ if (byId) return byId;
2737
+ for (const el of Array.from(
2738
+ document.querySelectorAll("footer[data-ohw-section]")
2739
+ ).reverse()) {
2740
+ if (el.hasAttribute(CONTAINER_ATTR)) continue;
2741
+ if (el.parentElement?.closest("[data-ohw-section]")) continue;
2722
2742
  return el;
2723
2743
  }
2724
2744
  return null;
@@ -2745,7 +2765,7 @@ function placeContainer(container, entry) {
2745
2765
  return;
2746
2766
  }
2747
2767
  }
2748
- const footer = findTemplateSection("footer");
2768
+ const footer = findFooterSection();
2749
2769
  if (footer) {
2750
2770
  footer.insertAdjacentElement("beforebegin", container);
2751
2771
  } else {
@@ -2780,7 +2800,7 @@ function syncTemplateHidden(state, pageHasSections) {
2780
2800
  if (!hide) return;
2781
2801
  for (const el of Array.from(document.querySelectorAll("[data-ohw-section]"))) {
2782
2802
  if (el.hasAttribute(CONTAINER_ATTR)) continue;
2783
- if (CHROME_SECTION_IDS.has(el.getAttribute("data-ohw-section") ?? "")) continue;
2803
+ if (isChromeSection2(el)) continue;
2784
2804
  if (el.parentElement?.closest("[data-ohw-section]")) continue;
2785
2805
  if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(REMOVED_ATTR2)) continue;
2786
2806
  el.style.display = "none";
@@ -7486,9 +7506,7 @@ function ItemActionToolbar({
7486
7506
  ToggleGroup,
7487
7507
  {
7488
7508
  value: dropdownOpen ? "open" : "closed",
7489
- onValueChange: (value) => {
7490
- if (value !== "open" && value !== "closed") return;
7491
- onDropdownOpenChange?.(value === "open");
7509
+ onValueChange: () => {
7492
7510
  },
7493
7511
  className: "h-7 gap-0.5 rounded-[calc(var(--radius,0.5rem)-2px)] bg-muted p-0.5",
7494
7512
  onMouseDown: (e) => {
@@ -7503,6 +7521,11 @@ function ItemActionToolbar({
7503
7521
  size: "sm",
7504
7522
  "aria-label": "Closed",
7505
7523
  className: "h-6 min-w-0 px-2 text-xs font-medium",
7524
+ onMouseDown: (e) => {
7525
+ e.preventDefault();
7526
+ e.stopPropagation();
7527
+ if (dropdownOpen !== false) onDropdownOpenChange?.(false);
7528
+ },
7506
7529
  children: "Closed"
7507
7530
  }
7508
7531
  ),
@@ -7513,6 +7536,11 @@ function ItemActionToolbar({
7513
7536
  size: "sm",
7514
7537
  "aria-label": "Open",
7515
7538
  className: "h-6 min-w-0 px-2 text-xs font-medium",
7539
+ onMouseDown: (e) => {
7540
+ e.preventDefault();
7541
+ e.stopPropagation();
7542
+ if (dropdownOpen !== true) onDropdownOpenChange?.(true);
7543
+ },
7516
7544
  children: "Open"
7517
7545
  }
7518
7546
  )
@@ -8538,7 +8566,7 @@ function FieldTypePicker({ onPick }) {
8538
8566
  "div",
8539
8567
  {
8540
8568
  "data-ohw-field-type-picker": "",
8541
- className: "pointer-events-auto grid w-[420px] grid-cols-3 gap-3 rounded-xl border border-border bg-background p-4 shadow-lg",
8569
+ className: "pointer-events-auto grid w-[280px] grid-cols-2 gap-2 rounded-xl border border-border bg-background p-3 shadow-lg",
8542
8570
  children: FIELD_TYPES.map((entry) => {
8543
8571
  const Icon = TYPE_ICONS[entry.type];
8544
8572
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
@@ -8546,7 +8574,7 @@ function FieldTypePicker({ onPick }) {
8546
8574
  {
8547
8575
  type: "button",
8548
8576
  onClick: () => onPick(entry.type),
8549
- className: "flex h-[104px] flex-col items-center justify-center gap-3 rounded-xl border border-border text-[15px] font-medium text-foreground transition-colors hover:border-primary hover:bg-primary/5",
8577
+ className: "flex h-[76px] flex-col items-center justify-center gap-2 rounded-xl border border-border text-[15px] font-medium text-foreground transition-colors hover:border-primary hover:bg-primary/5",
8550
8578
  children: [
8551
8579
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { size: 26, strokeWidth: 1.5, "aria-hidden": true }),
8552
8580
  entry.label
@@ -10900,6 +10928,32 @@ function getNavbarDesktopContainer() {
10900
10928
  function getNavbarDrawerContainer() {
10901
10929
  return document.querySelector("[data-ohw-nav-drawer]");
10902
10930
  }
10931
+ function isNavbarListContainerVisible(el) {
10932
+ if (el.hasAttribute("hidden")) return false;
10933
+ if (el.getClientRects().length === 0) return false;
10934
+ const style = window.getComputedStyle(el);
10935
+ return style.display !== "none" && style.visibility !== "hidden";
10936
+ }
10937
+ function getActiveNavbarListContainer(draggedEl) {
10938
+ const desktop = getNavbarDesktopContainer();
10939
+ const drawer = getNavbarDrawerContainer();
10940
+ if (draggedEl) {
10941
+ if (drawer?.contains(draggedEl)) return drawer;
10942
+ if (desktop?.contains(draggedEl)) return desktop;
10943
+ }
10944
+ if (desktop && isNavbarListContainerVisible(desktop)) return desktop;
10945
+ if (drawer && isNavbarListContainerVisible(drawer)) return drawer;
10946
+ return desktop ?? drawer;
10947
+ }
10948
+ function listActiveNavbarItems(draggedEl) {
10949
+ const container = getActiveNavbarListContainer(draggedEl);
10950
+ if (container) {
10951
+ return Array.from(container.querySelectorAll("[data-ohw-href-key]")).filter(
10952
+ isNavbarLinkItem
10953
+ );
10954
+ }
10955
+ return listNavbarItems();
10956
+ }
10903
10957
  function listNavbarItems() {
10904
10958
  const desktop = getNavbarDesktopContainer();
10905
10959
  if (desktop) {
@@ -12012,20 +12066,23 @@ function isEmptyLabelValue(value) {
12012
12066
  function applyStoredValues(item, content) {
12013
12067
  const hrefKey = socialHrefKey(item);
12014
12068
  const iconKey = socialIconKey(item);
12069
+ const baseKey = hrefKey?.replace(/-href$/, "");
12015
12070
  if (hrefKey && content[hrefKey] !== void 0) item.setAttribute("href", content[hrefKey]);
12016
- if (iconKey) {
12071
+ const glyphKey = iconKey ?? baseKey ?? null;
12072
+ const glyphStored = glyphKey ? content[glyphKey]?.trim() : void 0;
12073
+ if (glyphStored) {
12074
+ ensureIconSlot(item);
12017
12075
  const glyph = item.querySelector(ICON_SELECTOR);
12018
- if (glyph && content[iconKey]) {
12019
- applyIconMarkup(glyph, content[iconKey]);
12076
+ if (glyph) {
12077
+ applyIconMarkup(glyph, glyphStored);
12020
12078
  glyph.removeAttribute(SOCIALS_ICON_PLACEHOLDER_ATTR);
12021
12079
  }
12022
- const label = item.querySelector(`[${SOCIALS_LABEL_ATTR}]`);
12023
- label?.setAttribute("data-ohw-key", socialLabelKey(iconKey));
12024
- const stored = content[socialLabelKey(iconKey)];
12025
- if (label && stored !== void 0) {
12026
- const words = isEmptyLabelValue(stored) ? "" : stored;
12027
- if (label.innerHTML !== words) label.innerHTML = words;
12028
- }
12080
+ }
12081
+ const label = socialLabelElement(item);
12082
+ const labelKey = label?.getAttribute("data-ohw-key");
12083
+ if (label && labelKey && content[labelKey] !== void 0) {
12084
+ const words = isEmptyLabelValue(content[labelKey]) ? "" : content[labelKey];
12085
+ if (label.innerHTML !== words) label.innerHTML = words;
12029
12086
  }
12030
12087
  }
12031
12088
  function socialPlatformKey(iconKey) {
@@ -12114,6 +12171,9 @@ function insertSocialItem(row, after, content = {}, { placeholder = true, keys }
12114
12171
  if (placeholder) {
12115
12172
  const label = socialLabelElement(item);
12116
12173
  if (label) label.textContent = PLACEHOLDER_SOCIAL_LABEL;
12174
+ } else if (keys) {
12175
+ const label = socialLabelElement(item);
12176
+ if (label) label.textContent = "";
12117
12177
  }
12118
12178
  applySocialsDisplayToRow(row, display);
12119
12179
  return { item, hrefKey, iconKey, order: getSocialsOrderFromDom(row.ownerDocument) };
@@ -13971,8 +14031,8 @@ var lockFooterDuringDrag = lockItemDuringDrag;
13971
14031
  var unlockFooterDragInteraction = unlockItemDragInteraction;
13972
14032
 
13973
14033
  // src/lib/nav-dnd.ts
13974
- function listReorderableNavItems() {
13975
- return listNavbarItems().filter((el) => {
14034
+ function listReorderableNavItems(draggedEl) {
14035
+ return listActiveNavbarItems(draggedEl).filter((el) => {
13976
14036
  const key = el.getAttribute("data-ohw-href-key");
13977
14037
  return isNavbarHrefKey(key) && !isNestedNavChild(el);
13978
14038
  });
@@ -13987,8 +14047,8 @@ function resolveParentNavHrefKey(child) {
13987
14047
  const key = trigger?.getAttribute("data-ohw-href-key");
13988
14048
  return key && isNavbarHrefKey(key) ? key : null;
13989
14049
  }
13990
- function listNavChildren(parentHrefKey) {
13991
- const items = listNavbarItems();
14050
+ function listNavChildren(parentHrefKey, draggedEl) {
14051
+ const items = listActiveNavbarItems(draggedEl);
13992
14052
  const parent = items.find((el) => el.getAttribute("data-ohw-href-key") === parentHrefKey);
13993
14053
  if (!parent) return [];
13994
14054
  const group = parent.closest("[data-ohw-nav-group]");
@@ -13998,20 +14058,83 @@ function listNavChildren(parentHrefKey) {
13998
14058
  (el) => isNavbarHrefKey(el.getAttribute("data-ohw-href-key"))
13999
14059
  );
14000
14060
  }
14001
- function activeNavListContainer() {
14002
- const desktop = getNavbarDesktopContainer();
14003
- if (desktop && desktop.getClientRects().length > 0) {
14004
- const style = window.getComputedStyle(desktop);
14005
- if (style.display !== "none" && style.visibility !== "hidden") return desktop;
14061
+ function isVerticalNavLayout(items, draggedEl) {
14062
+ const visible = items.filter((el) => el.getClientRects().length > 0);
14063
+ if (visible.length >= 2) {
14064
+ const a = visible[0].getBoundingClientRect();
14065
+ const b = visible[1].getBoundingClientRect();
14066
+ const verticalGap = b.top - a.bottom;
14067
+ const horizontalGap = b.left - a.right;
14068
+ return verticalGap > horizontalGap;
14069
+ }
14070
+ const container = getActiveNavbarListContainer(draggedEl);
14071
+ if (!container) return false;
14072
+ const style = window.getComputedStyle(container);
14073
+ return style.flexDirection === "column" || style.flexDirection === "column-reverse";
14074
+ }
14075
+ function buildVerticalRootNavDropSlots(items, draggedEl) {
14076
+ const slots = [];
14077
+ const barThickness = 3;
14078
+ if (items.length === 0) {
14079
+ const container = getActiveNavbarListContainer(draggedEl);
14080
+ if (!container) return slots;
14081
+ const rect = container.getBoundingClientRect();
14082
+ slots.push({
14083
+ insertIndex: 0,
14084
+ parentId: null,
14085
+ left: rect.left,
14086
+ top: rect.top + rect.height / 2 - barThickness / 2,
14087
+ width: Math.max(rect.width, 40),
14088
+ height: barThickness,
14089
+ direction: "horizontal"
14090
+ });
14091
+ return slots;
14006
14092
  }
14007
- return getNavbarDrawerContainer();
14093
+ const edgeGap = (() => {
14094
+ if (items.length < 2) return 16;
14095
+ const a = items[0].getBoundingClientRect();
14096
+ const b = items[1].getBoundingClientRect();
14097
+ return Math.max(0, b.top - a.bottom);
14098
+ })();
14099
+ for (let i = 0; i <= items.length; i++) {
14100
+ let top;
14101
+ let width;
14102
+ let left;
14103
+ if (i === 0) {
14104
+ const first = items[0].getBoundingClientRect();
14105
+ top = first.top - edgeGap / 2 - barThickness / 2;
14106
+ left = first.left;
14107
+ width = first.width;
14108
+ } else if (i === items.length) {
14109
+ const last = items[items.length - 1].getBoundingClientRect();
14110
+ const lastGap = items.length >= 2 ? Math.max(0, last.top - items[items.length - 2].getBoundingClientRect().bottom) : edgeGap;
14111
+ top = last.bottom + lastGap / 2 - barThickness / 2;
14112
+ left = last.left;
14113
+ width = last.width;
14114
+ } else {
14115
+ const prev = items[i - 1].getBoundingClientRect();
14116
+ const next = items[i].getBoundingClientRect();
14117
+ top = (prev.bottom + next.top) / 2 - barThickness / 2;
14118
+ left = Math.min(prev.left, next.left);
14119
+ width = Math.max(prev.right, next.right) - left;
14120
+ }
14121
+ slots.push({
14122
+ insertIndex: i,
14123
+ parentId: null,
14124
+ left,
14125
+ top,
14126
+ width: Math.max(width, 40),
14127
+ height: barThickness,
14128
+ direction: "horizontal"
14129
+ });
14130
+ }
14131
+ return slots;
14008
14132
  }
14009
- function buildRootNavDropSlots() {
14010
- const items = listReorderableNavItems();
14133
+ function buildHorizontalRootNavDropSlots(items, draggedEl) {
14011
14134
  const slots = [];
14012
14135
  const barThickness = 3;
14013
14136
  if (items.length === 0) {
14014
- const container = activeNavListContainer();
14137
+ const container = getActiveNavbarListContainer(draggedEl);
14015
14138
  if (!container) return slots;
14016
14139
  const rect = container.getBoundingClientRect();
14017
14140
  slots.push({
@@ -14042,10 +14165,7 @@ function buildRootNavDropSlots() {
14042
14165
  height = first.height;
14043
14166
  } else if (i === items.length) {
14044
14167
  const last = items[items.length - 1].getBoundingClientRect();
14045
- const lastGap = items.length >= 2 ? Math.max(
14046
- 0,
14047
- last.left - items[items.length - 2].getBoundingClientRect().right
14048
- ) : edgeGap;
14168
+ const lastGap = items.length >= 2 ? Math.max(0, last.left - items[items.length - 2].getBoundingClientRect().right) : edgeGap;
14049
14169
  left = last.right + lastGap / 2 - barThickness / 2;
14050
14170
  top = last.top;
14051
14171
  height = last.height;
@@ -14068,8 +14188,15 @@ function buildRootNavDropSlots() {
14068
14188
  }
14069
14189
  return slots;
14070
14190
  }
14071
- function buildChildNavDropSlots(parentHrefKey) {
14072
- const children = listNavChildren(parentHrefKey);
14191
+ function buildRootNavDropSlots(draggedEl) {
14192
+ const items = listReorderableNavItems(draggedEl);
14193
+ if (isVerticalNavLayout(items, draggedEl)) {
14194
+ return buildVerticalRootNavDropSlots(items, draggedEl);
14195
+ }
14196
+ return buildHorizontalRootNavDropSlots(items, draggedEl);
14197
+ }
14198
+ function buildChildNavDropSlots(parentHrefKey, draggedEl) {
14199
+ const children = listNavChildren(parentHrefKey, draggedEl);
14073
14200
  const slots = [];
14074
14201
  const barThickness = 3;
14075
14202
  if (children.length === 0) return slots;
@@ -14090,10 +14217,7 @@ function buildChildNavDropSlots(parentHrefKey) {
14090
14217
  width = first.width;
14091
14218
  } else if (i === children.length) {
14092
14219
  const last = children[children.length - 1].getBoundingClientRect();
14093
- const lastGap = children.length >= 2 ? Math.max(
14094
- 0,
14095
- last.top - children[children.length - 2].getBoundingClientRect().bottom
14096
- ) : edgeGap;
14220
+ const lastGap = children.length >= 2 ? Math.max(0, last.top - children[children.length - 2].getBoundingClientRect().bottom) : edgeGap;
14097
14221
  top = last.bottom + lastGap / 2 - barThickness / 2;
14098
14222
  left = last.left;
14099
14223
  width = last.width;
@@ -14116,18 +14240,19 @@ function buildChildNavDropSlots(parentHrefKey) {
14116
14240
  }
14117
14241
  return slots;
14118
14242
  }
14119
- function buildAllNavDropSlots(draggedHrefKey) {
14120
- const dragged = listNavbarItems().find((el) => el.getAttribute("data-ohw-href-key") === draggedHrefKey);
14121
- if (!dragged) return buildRootNavDropSlots();
14243
+ function buildAllNavDropSlots(draggedHrefKey, draggedEl) {
14244
+ const activeItems = listActiveNavbarItems(draggedEl);
14245
+ const dragged = (draggedEl && activeItems.includes(draggedEl) ? draggedEl : null) ?? activeItems.find((el) => el.getAttribute("data-ohw-href-key") === draggedHrefKey) ?? listNavbarItems().find((el) => el.getAttribute("data-ohw-href-key") === draggedHrefKey);
14246
+ if (!dragged) return buildRootNavDropSlots(draggedEl);
14122
14247
  if (isNestedNavChild(dragged)) {
14123
14248
  const parentKey = resolveParentNavHrefKey(dragged);
14124
14249
  if (!parentKey) return [];
14125
- return buildChildNavDropSlots(parentKey);
14250
+ return buildChildNavDropSlots(parentKey, draggedEl);
14126
14251
  }
14127
- return buildRootNavDropSlots();
14252
+ return buildRootNavDropSlots(draggedEl);
14128
14253
  }
14129
- function hitTestNavDropSlot(clientX, clientY, draggedHrefKey) {
14130
- const slots = buildAllNavDropSlots(draggedHrefKey);
14254
+ function hitTestNavDropSlot(clientX, clientY, draggedHrefKey, draggedEl) {
14255
+ const slots = buildAllNavDropSlots(draggedHrefKey, draggedEl);
14131
14256
  let best = null;
14132
14257
  for (const slot of slots) {
14133
14258
  const cx2 = slot.left + slot.width / 2;
@@ -14178,6 +14303,12 @@ function useNavItemDrag({
14178
14303
  setIsItemDragging(false);
14179
14304
  if (keepOpenEl?.isConnected) {
14180
14305
  setNavGroupForceOpen(keepOpenEl, true);
14306
+ requestAnimationFrame(() => {
14307
+ if (keepOpenEl.isConnected) setNavGroupForceOpen(keepOpenEl, true);
14308
+ requestAnimationFrame(() => {
14309
+ if (keepOpenEl.isConnected) setNavGroupForceOpen(keepOpenEl, true);
14310
+ });
14311
+ });
14181
14312
  } else {
14182
14313
  setNavGroupForceOpen(null, false);
14183
14314
  }
@@ -14193,7 +14324,7 @@ function useNavItemDrag({
14193
14324
  }
14194
14325
  session.activeSlot = activeSlot;
14195
14326
  setSiblingHintRects([]);
14196
- const slots = buildAllNavDropSlots(session.hrefKey);
14327
+ const slots = buildAllNavDropSlots(session.hrefKey, session.draggedEl);
14197
14328
  setNavDropSlots(slots);
14198
14329
  const activeIdx = activeSlot ? slots.findIndex(
14199
14330
  (s) => s.parentId === activeSlot.parentId && s.insertIndex === activeSlot.insertIndex
@@ -14229,7 +14360,12 @@ function useNavItemDrag({
14229
14360
  if (session.wasSelected && selectedElRef.current === session.draggedEl) {
14230
14361
  setToolbarRect(rect);
14231
14362
  }
14232
- const initialSlot = hitTestNavDropSlot(session.lastClientX, session.lastClientY, session.hrefKey);
14363
+ const initialSlot = hitTestNavDropSlot(
14364
+ session.lastClientX,
14365
+ session.lastClientY,
14366
+ session.hrefKey,
14367
+ session.draggedEl
14368
+ );
14233
14369
  refreshNavDragVisuals(session, initialSlot, session.lastClientX, session.lastClientY);
14234
14370
  },
14235
14371
  [
@@ -14251,10 +14387,11 @@ function useNavItemDrag({
14251
14387
  }
14252
14388
  const x = typeof clientX === "number" && (clientX !== 0 || clientY !== 0) ? clientX : session.lastClientX;
14253
14389
  const y = typeof clientY === "number" && (clientX !== 0 || clientY !== 0) ? clientY : session.lastClientY;
14254
- const slot = session.activeSlot ?? hitTestNavDropSlot(x, y, session.hrefKey);
14390
+ const slot = session.activeSlot ?? hitTestNavDropSlot(x, y, session.hrefKey, session.draggedEl);
14255
14391
  const planned = slot != null ? planNavItemMove(session.hrefKey, slot.parentId, slot.insertIndex) : null;
14256
14392
  const wasSelected = session.wasSelected;
14257
14393
  const hrefKey = session.hrefKey;
14394
+ const keepDropdownOpen = Boolean(session.draggedEl.closest("[data-ohw-nav-children]"));
14258
14395
  const applySelectionAfterDrop = () => {
14259
14396
  if (!wasSelected) {
14260
14397
  deselectRef.current();
@@ -14288,6 +14425,14 @@ function useNavItemDrag({
14288
14425
  });
14289
14426
  applySelectionAfterDrop();
14290
14427
  clearNavDragVisuals();
14428
+ if (keepDropdownOpen) {
14429
+ requestAnimationFrame(() => {
14430
+ const desktop = document.querySelector("[data-ohw-nav-container]");
14431
+ const drawer = document.querySelector("[data-ohw-nav-drawer]");
14432
+ const link = desktop?.querySelector(`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`) ?? drawer?.querySelector(`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`) ?? document.querySelector(`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`);
14433
+ if (link) setNavGroupForceOpen(link, true);
14434
+ });
14435
+ }
14291
14436
  requestAnimationFrame(() => {
14292
14437
  if (editContentRef.current[NAV_ORDER_KEY] === planned.orderJson) {
14293
14438
  applyNavForest(planned.forest);
@@ -14327,7 +14472,7 @@ function useNavItemDrag({
14327
14472
  if (!session) return false;
14328
14473
  e.preventDefault();
14329
14474
  if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
14330
- const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey);
14475
+ const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey, session.draggedEl);
14331
14476
  refreshNavDragVisualsRef.current(session, slot, e.clientX, e.clientY);
14332
14477
  return true;
14333
14478
  },
@@ -14373,7 +14518,7 @@ function useNavItemDrag({
14373
14518
  clearTextSelection();
14374
14519
  const session = navDragRef.current;
14375
14520
  if (!session) return;
14376
- const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey);
14521
+ const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey, session.draggedEl);
14377
14522
  refreshNavDragVisualsRef.current(session, slot, e.clientX, e.clientY);
14378
14523
  return;
14379
14524
  }
@@ -14389,7 +14534,8 @@ function useNavItemDrag({
14389
14534
  } catch {
14390
14535
  }
14391
14536
  if (linkPopoverOpenRef.current) setLinkPopover(null);
14392
- if (activeElRef.current) deactivateRef.current();
14537
+ const isNestedDrag = Boolean(pending.el.closest("[data-ohw-nav-children]"));
14538
+ if (activeElRef.current && !isNestedDrag) deactivateRef.current();
14393
14539
  const key = pending.el.getAttribute("data-ohw-href-key");
14394
14540
  if (!key) return;
14395
14541
  beginNavDragRef.current({
@@ -14400,6 +14546,9 @@ function useNavItemDrag({
14400
14546
  lastClientY: e.clientY,
14401
14547
  activeSlot: null
14402
14548
  });
14549
+ if (activeElRef.current && isNestedDrag) {
14550
+ deactivateRef.current();
14551
+ }
14403
14552
  };
14404
14553
  const endPointerDrag = (e) => {
14405
14554
  const pending = navPointerDragRef.current;
@@ -14477,6 +14626,7 @@ function useNavItemDrag({
14477
14626
  );
14478
14627
  return {
14479
14628
  navDragRef,
14629
+ navPointerDragRef,
14480
14630
  navDropSlots,
14481
14631
  activeNavDropIndex,
14482
14632
  startNavLinkDrag,
@@ -15873,6 +16023,7 @@ function isNavDropdownPanelOpen(childrenRoot) {
15873
16023
  if (childrenRoot.closest("[data-ohw-nav-drawer]")) return true;
15874
16024
  const group = childrenRoot.closest("[data-ohw-nav-group]");
15875
16025
  if (group?.hasAttribute("data-ohw-nav-force-open")) return true;
16026
+ if (navDropdownsOpenOnClick()) return false;
15876
16027
  if (childrenRoot.clientHeight < 2 || childrenRoot.clientWidth < 2) return false;
15877
16028
  const style = window.getComputedStyle(childrenRoot);
15878
16029
  if (style.display === "none" || style.visibility === "hidden") return false;
@@ -15916,6 +16067,11 @@ function getNavigationItemAnchor(el) {
15916
16067
  function isNavigationItem2(el) {
15917
16068
  return getNavigationItemAnchor(el) !== null;
15918
16069
  }
16070
+ function isNavFooterScopedNavigationItem(el) {
16071
+ return Boolean(
16072
+ el.closest("nav, footer, [data-ohw-nav-container], [data-ohw-nav-drawer]")
16073
+ );
16074
+ }
15919
16075
  function socialWordsClicked(target, item) {
15920
16076
  const text = target.closest('[data-ohw-editable="text"], [data-ohw-editable="plain"]');
15921
16077
  return Boolean(text && item.contains(text));
@@ -16126,6 +16282,7 @@ function getNavigationSelectionParent(el) {
16126
16282
  }
16127
16283
  function collectNavigationItemSiblingHintRects(selected) {
16128
16284
  if (!isNavigationItem2(selected)) return [];
16285
+ if (!isNavFooterScopedNavigationItem(selected)) return [];
16129
16286
  const socialsRow = findSocialsRow(selected);
16130
16287
  if (socialsRow) {
16131
16288
  return listSocialItems(socialsRow).filter((item) => item !== selected).map((item) => item.getBoundingClientRect());
@@ -17289,6 +17446,7 @@ function OhhwellsBridge() {
17289
17446
  }, []);
17290
17447
  const {
17291
17448
  navDragRef,
17449
+ navPointerDragRef,
17292
17450
  navDropSlots,
17293
17451
  activeNavDropIndex,
17294
17452
  startNavLinkDrag,
@@ -17491,7 +17649,12 @@ function OhhwellsBridge() {
17491
17649
  if (owner) persistFieldsRef.current(owner);
17492
17650
  }
17493
17651
  activeElRef.current = null;
17494
- setNavGroupForceOpen(null, false);
17652
+ const preserveNavDropdown = Boolean(navPointerDragRef.current?.el?.closest("[data-ohw-nav-children]")) || Boolean(navDragRef.current?.draggedEl?.closest("[data-ohw-nav-children]")) || Boolean(
17653
+ selectedElRef.current?.closest("[data-ohw-nav-children]") && selectedElRef.current?.closest("[data-ohw-nav-group]")?.hasAttribute("data-ohw-nav-force-open")
17654
+ );
17655
+ if (!preserveNavDropdown) {
17656
+ setNavGroupForceOpen(null, false);
17657
+ }
17495
17658
  setReorderHrefKey(null);
17496
17659
  setReorderDragDisabled(false);
17497
17660
  if (!selectedElRef.current) {
@@ -17613,7 +17776,10 @@ function OhhwellsBridge() {
17613
17776
  setSelectedIsSocialsRow(false);
17614
17777
  const isDropdownTrigger = !isNestedNavChild(navAnchor) && (navItemHasDropdownChildren(navAnchor) || navItemOwnsDropdownPanel(navAnchor));
17615
17778
  if (isNestedNavChild(navAnchor)) {
17616
- setNavGroupForceOpen(navAnchor, true);
17779
+ const group = navAnchor.closest("[data-ohw-nav-group]");
17780
+ if (group?.hasAttribute("data-ohw-nav-force-open")) {
17781
+ setNavGroupForceOpen(navAnchor, true);
17782
+ }
17617
17783
  setNavDropdownPreviewOpen(null);
17618
17784
  } else if (isDropdownTrigger) {
17619
17785
  const group = navAnchor.closest("[data-ohw-nav-group]");
@@ -17695,6 +17861,10 @@ function OhhwellsBridge() {
17695
17861
  const handleNavDropdownOpenChange = (0, import_react17.useCallback)((open) => {
17696
17862
  const selected = selectedElRef.current;
17697
17863
  if (!selected || !isNavigationItem2(selected)) return;
17864
+ if (isNestedNavChild(selected)) return;
17865
+ const group = selected.closest("[data-ohw-nav-group]");
17866
+ const domOpen = Boolean(group?.hasAttribute("data-ohw-nav-force-open"));
17867
+ if (open === domOpen) return;
17698
17868
  setNavGroupForceOpen(selected, open);
17699
17869
  setNavDropdownPreviewOpen(open);
17700
17870
  requestAnimationFrame(() => {
@@ -18224,7 +18394,10 @@ function OhhwellsBridge() {
18224
18394
  clearHrefKeyHover(anchor);
18225
18395
  const isDropdownTrigger = !isNestedNavChild(anchor) && (navItemHasDropdownChildren(anchor) || navItemOwnsDropdownPanel(anchor));
18226
18396
  if (isNestedNavChild(anchor)) {
18227
- setNavGroupForceOpen(anchor, true);
18397
+ const group = anchor.closest("[data-ohw-nav-group]");
18398
+ if (group?.hasAttribute("data-ohw-nav-force-open")) {
18399
+ setNavGroupForceOpen(anchor, true);
18400
+ }
18228
18401
  setNavDropdownPreviewOpen(null);
18229
18402
  } else if (isDropdownTrigger) {
18230
18403
  setNavGroupForceOpen(null, false);
@@ -19050,28 +19223,19 @@ function OhhwellsBridge() {
19050
19223
  return;
19051
19224
  }
19052
19225
  const existing = editStylesRef.current;
19053
- let initialVh = window.innerHeight;
19054
- if (existing?.base.textContent) {
19055
- const match = existing.base.textContent.match(/\.min-h-screen[^{]*\{[^}]*min-height:\s*(\d+)px/);
19056
- if (match) initialVh = parseInt(match[1], 10);
19057
- }
19226
+ const canvasHeight = "var(--ohw-canvas-h, 852px)";
19058
19227
  const baseCss = `
19059
19228
  html { height: auto !important; }
19060
19229
  body { height: auto !important; min-height: 0 !important; overflow: hidden !important; }
19061
- .min-h-screen, .min-h-svh, .min-h-dvh { min-height: ${initialVh}px !important; }
19062
- .h-screen, .h-svh, .h-dvh { height: ${initialVh}px !important; }
19063
- [style*="100vh"] { min-height: ${initialVh}px !important; height: ${initialVh}px !important; }
19064
- [style*="100svh"] { min-height: ${initialVh}px !important; height: ${initialVh}px !important; }
19065
- [style*="100dvh"] { min-height: ${initialVh}px !important; height: ${initialVh}px !important; }
19066
- /* A section written as min-height: var(--ohw-canvas-h, 100svh) \u2014 the documented way to
19067
- build a full-viewport section that still grows for its own content \u2014 matches the three
19068
- rules above on substring alone, since the fallback text contains "100svh" too. Forcing
19069
- a literal height on top of that turns "at least one screen" into "exactly one screen",
19070
- so content taller than one screen (a long mobile hero, say) overflows a centered flex
19071
- column upward, under whatever sits above it. Only the min-height half belongs to it. */
19072
- [style*="min-height"][style*="100vh"],
19073
- [style*="min-height"][style*="100svh"],
19074
- [style*="min-height"][style*="100dvh"] { height: auto !important; }
19230
+ .min-h-screen, .min-h-svh, .min-h-dvh { min-height: ${canvasHeight} !important; }
19231
+ .h-screen, .h-svh, .h-dvh { height: ${canvasHeight} !important; }
19232
+ /* Literal inline viewport units only \u2014 skip R11 sections that already reference --ohw-canvas-h
19233
+ (their style attribute contains "100svh" only as a var() fallback string). */
19234
+ [style*="100vh"]:not([style*="--ohw-canvas-h"]) { min-height: ${canvasHeight} !important; height: ${canvasHeight} !important; }
19235
+ [style*="100svh"]:not([style*="--ohw-canvas-h"]) { min-height: ${canvasHeight} !important; height: ${canvasHeight} !important; }
19236
+ [style*="100dvh"]:not([style*="--ohw-canvas-h"]) { min-height: ${canvasHeight} !important; height: ${canvasHeight} !important; }
19237
+ /* R11: min-height via --ohw-canvas-h; height must grow with content taller than one screen. */
19238
+ [style*="min-height"][style*="--ohw-canvas-h"] { height: auto !important; }
19075
19239
  /* Emptied text keeps somewhere to click. A label typed down to nothing collapses to a
19076
19240
  couple of pixels, and getting back into it meant hunting for the caret with the mouse.
19077
19241
  Edit mode only \u2014 the published page shows nothing where there is nothing (OHH-736). */
@@ -19218,6 +19382,10 @@ function OhhwellsBridge() {
19218
19382
  outline-offset: 0 !important;
19219
19383
  box-shadow: none !important;
19220
19384
  }
19385
+ /* Open nav dropdown panels paint above AI section selection chrome (2147483000). */
19386
+ [data-ohw-nav-group][data-ohw-nav-force-open] > [data-ohw-nav-children] {
19387
+ z-index: 2147483100 !important;
19388
+ }
19221
19389
  /* Text edit wins over grab/default (must beat [data-ohw-can-drag] *). */
19222
19390
  [data-ohw-editing],
19223
19391
  [data-ohw-editing] *,
@@ -20555,7 +20723,11 @@ function OhhwellsBridge() {
20555
20723
  const slotFromItem = hrefKey ? findSocialByHrefKey(hrefKey)?.querySelector('[data-ohw-editable="icon"]') : null;
20556
20724
  const requestedIsIconSlot = Boolean(requestedIconKey) && Boolean(document.querySelector(`[data-ohw-key="${requestedIconKey}"][data-ohw-editable="icon"]`));
20557
20725
  const requestedIsFree = Boolean(requestedIconKey) && !document.querySelector(`[data-ohw-key="${requestedIconKey}"]`);
20558
- const iconKey = requestedIsIconSlot ? requestedIconKey : slotFromItem?.dataset.ohwKey ?? (requestedIsFree ? requestedIconKey : void 0);
20726
+ let iconKey = requestedIsIconSlot ? requestedIconKey : slotFromItem?.dataset.ohwKey ?? (requestedIsFree ? requestedIconKey : void 0);
20727
+ const item = hrefKey ? findSocialByHrefKey(hrefKey) : null;
20728
+ if (item && typeof iconMarkup === "string" && iconMarkup) {
20729
+ iconKey = ensureIconSlot(item) ?? iconKey;
20730
+ }
20559
20731
  if (iconKey && typeof iconMarkup === "string" && iconMarkup) {
20560
20732
  document.querySelectorAll(`[data-ohw-key="${iconKey}"][data-ohw-editable="icon"]`).forEach((el) => {
20561
20733
  applyIconMarkup(el, iconMarkup);
@@ -20565,7 +20737,7 @@ function OhhwellsBridge() {
20565
20737
  }
20566
20738
  if (iconKey && platformId) nodes.push({ key: socialPlatformKey(iconKey), text: platformId });
20567
20739
  if (iconKey && label) {
20568
- const labelKey = socialLabelKey(iconKey);
20740
+ const labelKey = (item ? socialLabelElement(item)?.getAttribute("data-ohw-key") : null) ?? socialLabelKey(iconKey);
20569
20741
  document.querySelectorAll(`[data-ohw-key="${labelKey}"]`).forEach((el) => {
20570
20742
  if (keepLabel && el.textContent?.trim()) return;
20571
20743
  el.textContent = label;
@@ -20836,6 +21008,9 @@ function OhhwellsBridge() {
20836
21008
  if (reapNodes.length > 0) postToParentRef.current({ type: "ow:change", nodes: reapNodes });
20837
21009
  const hydratedHeight = document.body.scrollHeight;
20838
21010
  if (hydratedHeight > 50) postToParentRef.current({ type: "ow:height", height: hydratedHeight });
21011
+ if (parseAiSectionsState(aiSectionsRef.current).sections.length > 0) {
21012
+ postAiSectionsChanged();
21013
+ }
20839
21014
  postToParentRef.current({ type: "ow:hydrate-done" });
20840
21015
  };
20841
21016
  const handleUpdateLogoIdentity = (e) => {
@@ -21388,7 +21563,12 @@ function OhhwellsBridge() {
21388
21563
  }
21389
21564
  if (navDragRef.current) {
21390
21565
  const session = navDragRef.current;
21391
- const slot = hitTestNavDropSlot(session.lastClientX, session.lastClientY, session.hrefKey);
21566
+ const slot = hitTestNavDropSlot(
21567
+ session.lastClientX,
21568
+ session.lastClientY,
21569
+ session.hrefKey,
21570
+ session.draggedEl
21571
+ );
21392
21572
  refreshNavDragVisualsRef.current(session, slot, session.lastClientX, session.lastClientY);
21393
21573
  }
21394
21574
  if (hoveredImageRef.current) {
@@ -21594,18 +21774,21 @@ function OhhwellsBridge() {
21594
21774
  }
21595
21775
  return null;
21596
21776
  };
21777
+ const isPointInRect = (el, clientX, clientY) => {
21778
+ const r2 = el.getBoundingClientRect();
21779
+ return clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom;
21780
+ };
21597
21781
  const isPointOverEditable = (scope, clientX, clientY) => {
21598
21782
  const editables = scope.querySelectorAll("[data-ohw-editable], [data-ohw-href-key]");
21599
21783
  for (const el of editables) {
21600
- const r2 = el.getBoundingClientRect();
21601
- if (clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom) return true;
21784
+ if (isPointInRect(el, clientX, clientY)) return true;
21602
21785
  }
21603
21786
  return false;
21604
21787
  };
21605
21788
  const handleCarouselHover = (e) => {
21606
21789
  const container = findCarouselAtPoint(e.clientX, e.clientY);
21607
21790
  const scope = container?.closest("[data-ohw-section]") ?? container?.parentElement ?? null;
21608
- if (!container || !scope || isPointOverEditable(scope, e.clientX, e.clientY)) {
21791
+ if (!container || !scope || isPointOverEditable(scope, e.clientX, e.clientY) || isPointOverNavigation(e.clientX, e.clientY) || isPointOverBridgeChrome(e.clientX, e.clientY)) {
21609
21792
  setCarouselHover((prev) => prev ? null : prev);
21610
21793
  return;
21611
21794
  }