@ohhwells/bridge 0.1.100 → 0.1.101

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
@@ -7500,9 +7500,7 @@ function ItemActionToolbar({
7500
7500
  ToggleGroup,
7501
7501
  {
7502
7502
  value: dropdownOpen ? "open" : "closed",
7503
- onValueChange: (value) => {
7504
- if (value !== "open" && value !== "closed") return;
7505
- onDropdownOpenChange?.(value === "open");
7503
+ onValueChange: () => {
7506
7504
  },
7507
7505
  className: "h-7 gap-0.5 rounded-[calc(var(--radius,0.5rem)-2px)] bg-muted p-0.5",
7508
7506
  onMouseDown: (e) => {
@@ -7517,6 +7515,11 @@ function ItemActionToolbar({
7517
7515
  size: "sm",
7518
7516
  "aria-label": "Closed",
7519
7517
  className: "h-6 min-w-0 px-2 text-xs font-medium",
7518
+ onMouseDown: (e) => {
7519
+ e.preventDefault();
7520
+ e.stopPropagation();
7521
+ if (dropdownOpen !== false) onDropdownOpenChange?.(false);
7522
+ },
7520
7523
  children: "Closed"
7521
7524
  }
7522
7525
  ),
@@ -7527,6 +7530,11 @@ function ItemActionToolbar({
7527
7530
  size: "sm",
7528
7531
  "aria-label": "Open",
7529
7532
  className: "h-6 min-w-0 px-2 text-xs font-medium",
7533
+ onMouseDown: (e) => {
7534
+ e.preventDefault();
7535
+ e.stopPropagation();
7536
+ if (dropdownOpen !== true) onDropdownOpenChange?.(true);
7537
+ },
7530
7538
  children: "Open"
7531
7539
  }
7532
7540
  )
@@ -8552,7 +8560,7 @@ function FieldTypePicker({ onPick }) {
8552
8560
  "div",
8553
8561
  {
8554
8562
  "data-ohw-field-type-picker": "",
8555
- className: "pointer-events-auto grid w-[420px] grid-cols-3 gap-3 rounded-xl border border-border bg-background p-4 shadow-lg",
8563
+ className: "pointer-events-auto grid w-[280px] grid-cols-2 gap-2 rounded-xl border border-border bg-background p-3 shadow-lg",
8556
8564
  children: FIELD_TYPES.map((entry) => {
8557
8565
  const Icon = TYPE_ICONS[entry.type];
8558
8566
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
@@ -8560,7 +8568,7 @@ function FieldTypePicker({ onPick }) {
8560
8568
  {
8561
8569
  type: "button",
8562
8570
  onClick: () => onPick(entry.type),
8563
- 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",
8571
+ 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",
8564
8572
  children: [
8565
8573
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { size: 26, strokeWidth: 1.5, "aria-hidden": true }),
8566
8574
  entry.label
@@ -10913,6 +10921,32 @@ function getNavbarDesktopContainer() {
10913
10921
  function getNavbarDrawerContainer() {
10914
10922
  return document.querySelector("[data-ohw-nav-drawer]");
10915
10923
  }
10924
+ function isNavbarListContainerVisible(el) {
10925
+ if (el.hasAttribute("hidden")) return false;
10926
+ if (el.getClientRects().length === 0) return false;
10927
+ const style = window.getComputedStyle(el);
10928
+ return style.display !== "none" && style.visibility !== "hidden";
10929
+ }
10930
+ function getActiveNavbarListContainer(draggedEl) {
10931
+ const desktop = getNavbarDesktopContainer();
10932
+ const drawer = getNavbarDrawerContainer();
10933
+ if (draggedEl) {
10934
+ if (drawer?.contains(draggedEl)) return drawer;
10935
+ if (desktop?.contains(draggedEl)) return desktop;
10936
+ }
10937
+ if (desktop && isNavbarListContainerVisible(desktop)) return desktop;
10938
+ if (drawer && isNavbarListContainerVisible(drawer)) return drawer;
10939
+ return desktop ?? drawer;
10940
+ }
10941
+ function listActiveNavbarItems(draggedEl) {
10942
+ const container = getActiveNavbarListContainer(draggedEl);
10943
+ if (container) {
10944
+ return Array.from(container.querySelectorAll("[data-ohw-href-key]")).filter(
10945
+ isNavbarLinkItem
10946
+ );
10947
+ }
10948
+ return listNavbarItems();
10949
+ }
10916
10950
  function listNavbarItems() {
10917
10951
  const desktop = getNavbarDesktopContainer();
10918
10952
  if (desktop) {
@@ -12025,20 +12059,23 @@ function isEmptyLabelValue(value) {
12025
12059
  function applyStoredValues(item, content) {
12026
12060
  const hrefKey = socialHrefKey(item);
12027
12061
  const iconKey = socialIconKey(item);
12062
+ const baseKey = hrefKey?.replace(/-href$/, "");
12028
12063
  if (hrefKey && content[hrefKey] !== void 0) item.setAttribute("href", content[hrefKey]);
12029
- if (iconKey) {
12064
+ const glyphKey = iconKey ?? baseKey ?? null;
12065
+ const glyphStored = glyphKey ? content[glyphKey]?.trim() : void 0;
12066
+ if (glyphStored) {
12067
+ ensureIconSlot(item);
12030
12068
  const glyph = item.querySelector(ICON_SELECTOR);
12031
- if (glyph && content[iconKey]) {
12032
- applyIconMarkup(glyph, content[iconKey]);
12069
+ if (glyph) {
12070
+ applyIconMarkup(glyph, glyphStored);
12033
12071
  glyph.removeAttribute(SOCIALS_ICON_PLACEHOLDER_ATTR);
12034
12072
  }
12035
- const label = item.querySelector(`[${SOCIALS_LABEL_ATTR}]`);
12036
- label?.setAttribute("data-ohw-key", socialLabelKey(iconKey));
12037
- const stored = content[socialLabelKey(iconKey)];
12038
- if (label && stored !== void 0) {
12039
- const words = isEmptyLabelValue(stored) ? "" : stored;
12040
- if (label.innerHTML !== words) label.innerHTML = words;
12041
- }
12073
+ }
12074
+ const label = socialLabelElement(item);
12075
+ const labelKey = label?.getAttribute("data-ohw-key");
12076
+ if (label && labelKey && content[labelKey] !== void 0) {
12077
+ const words = isEmptyLabelValue(content[labelKey]) ? "" : content[labelKey];
12078
+ if (label.innerHTML !== words) label.innerHTML = words;
12042
12079
  }
12043
12080
  }
12044
12081
  function socialPlatformKey(iconKey) {
@@ -12127,6 +12164,9 @@ function insertSocialItem(row, after, content = {}, { placeholder = true, keys }
12127
12164
  if (placeholder) {
12128
12165
  const label = socialLabelElement(item);
12129
12166
  if (label) label.textContent = PLACEHOLDER_SOCIAL_LABEL;
12167
+ } else if (keys) {
12168
+ const label = socialLabelElement(item);
12169
+ if (label) label.textContent = "";
12130
12170
  }
12131
12171
  applySocialsDisplayToRow(row, display);
12132
12172
  return { item, hrefKey, iconKey, order: getSocialsOrderFromDom(row.ownerDocument) };
@@ -13983,8 +14023,8 @@ var lockFooterDuringDrag = lockItemDuringDrag;
13983
14023
  var unlockFooterDragInteraction = unlockItemDragInteraction;
13984
14024
 
13985
14025
  // src/lib/nav-dnd.ts
13986
- function listReorderableNavItems() {
13987
- return listNavbarItems().filter((el) => {
14026
+ function listReorderableNavItems(draggedEl) {
14027
+ return listActiveNavbarItems(draggedEl).filter((el) => {
13988
14028
  const key = el.getAttribute("data-ohw-href-key");
13989
14029
  return isNavbarHrefKey(key) && !isNestedNavChild(el);
13990
14030
  });
@@ -13999,8 +14039,8 @@ function resolveParentNavHrefKey(child) {
13999
14039
  const key = trigger?.getAttribute("data-ohw-href-key");
14000
14040
  return key && isNavbarHrefKey(key) ? key : null;
14001
14041
  }
14002
- function listNavChildren(parentHrefKey) {
14003
- const items = listNavbarItems();
14042
+ function listNavChildren(parentHrefKey, draggedEl) {
14043
+ const items = listActiveNavbarItems(draggedEl);
14004
14044
  const parent = items.find((el) => el.getAttribute("data-ohw-href-key") === parentHrefKey);
14005
14045
  if (!parent) return [];
14006
14046
  const group = parent.closest("[data-ohw-nav-group]");
@@ -14010,20 +14050,83 @@ function listNavChildren(parentHrefKey) {
14010
14050
  (el) => isNavbarHrefKey(el.getAttribute("data-ohw-href-key"))
14011
14051
  );
14012
14052
  }
14013
- function activeNavListContainer() {
14014
- const desktop = getNavbarDesktopContainer();
14015
- if (desktop && desktop.getClientRects().length > 0) {
14016
- const style = window.getComputedStyle(desktop);
14017
- if (style.display !== "none" && style.visibility !== "hidden") return desktop;
14053
+ function isVerticalNavLayout(items, draggedEl) {
14054
+ const visible = items.filter((el) => el.getClientRects().length > 0);
14055
+ if (visible.length >= 2) {
14056
+ const a = visible[0].getBoundingClientRect();
14057
+ const b = visible[1].getBoundingClientRect();
14058
+ const verticalGap = b.top - a.bottom;
14059
+ const horizontalGap = b.left - a.right;
14060
+ return verticalGap > horizontalGap;
14061
+ }
14062
+ const container = getActiveNavbarListContainer(draggedEl);
14063
+ if (!container) return false;
14064
+ const style = window.getComputedStyle(container);
14065
+ return style.flexDirection === "column" || style.flexDirection === "column-reverse";
14066
+ }
14067
+ function buildVerticalRootNavDropSlots(items, draggedEl) {
14068
+ const slots = [];
14069
+ const barThickness = 3;
14070
+ if (items.length === 0) {
14071
+ const container = getActiveNavbarListContainer(draggedEl);
14072
+ if (!container) return slots;
14073
+ const rect = container.getBoundingClientRect();
14074
+ slots.push({
14075
+ insertIndex: 0,
14076
+ parentId: null,
14077
+ left: rect.left,
14078
+ top: rect.top + rect.height / 2 - barThickness / 2,
14079
+ width: Math.max(rect.width, 40),
14080
+ height: barThickness,
14081
+ direction: "horizontal"
14082
+ });
14083
+ return slots;
14018
14084
  }
14019
- return getNavbarDrawerContainer();
14085
+ const edgeGap = (() => {
14086
+ if (items.length < 2) return 16;
14087
+ const a = items[0].getBoundingClientRect();
14088
+ const b = items[1].getBoundingClientRect();
14089
+ return Math.max(0, b.top - a.bottom);
14090
+ })();
14091
+ for (let i = 0; i <= items.length; i++) {
14092
+ let top;
14093
+ let width;
14094
+ let left;
14095
+ if (i === 0) {
14096
+ const first = items[0].getBoundingClientRect();
14097
+ top = first.top - edgeGap / 2 - barThickness / 2;
14098
+ left = first.left;
14099
+ width = first.width;
14100
+ } else if (i === items.length) {
14101
+ const last = items[items.length - 1].getBoundingClientRect();
14102
+ const lastGap = items.length >= 2 ? Math.max(0, last.top - items[items.length - 2].getBoundingClientRect().bottom) : edgeGap;
14103
+ top = last.bottom + lastGap / 2 - barThickness / 2;
14104
+ left = last.left;
14105
+ width = last.width;
14106
+ } else {
14107
+ const prev = items[i - 1].getBoundingClientRect();
14108
+ const next = items[i].getBoundingClientRect();
14109
+ top = (prev.bottom + next.top) / 2 - barThickness / 2;
14110
+ left = Math.min(prev.left, next.left);
14111
+ width = Math.max(prev.right, next.right) - left;
14112
+ }
14113
+ slots.push({
14114
+ insertIndex: i,
14115
+ parentId: null,
14116
+ left,
14117
+ top,
14118
+ width: Math.max(width, 40),
14119
+ height: barThickness,
14120
+ direction: "horizontal"
14121
+ });
14122
+ }
14123
+ return slots;
14020
14124
  }
14021
- function buildRootNavDropSlots() {
14022
- const items = listReorderableNavItems();
14125
+ function buildHorizontalRootNavDropSlots(items, draggedEl) {
14023
14126
  const slots = [];
14024
14127
  const barThickness = 3;
14025
14128
  if (items.length === 0) {
14026
- const container = activeNavListContainer();
14129
+ const container = getActiveNavbarListContainer(draggedEl);
14027
14130
  if (!container) return slots;
14028
14131
  const rect = container.getBoundingClientRect();
14029
14132
  slots.push({
@@ -14054,10 +14157,7 @@ function buildRootNavDropSlots() {
14054
14157
  height = first.height;
14055
14158
  } else if (i === items.length) {
14056
14159
  const last = items[items.length - 1].getBoundingClientRect();
14057
- const lastGap = items.length >= 2 ? Math.max(
14058
- 0,
14059
- last.left - items[items.length - 2].getBoundingClientRect().right
14060
- ) : edgeGap;
14160
+ const lastGap = items.length >= 2 ? Math.max(0, last.left - items[items.length - 2].getBoundingClientRect().right) : edgeGap;
14061
14161
  left = last.right + lastGap / 2 - barThickness / 2;
14062
14162
  top = last.top;
14063
14163
  height = last.height;
@@ -14080,8 +14180,15 @@ function buildRootNavDropSlots() {
14080
14180
  }
14081
14181
  return slots;
14082
14182
  }
14083
- function buildChildNavDropSlots(parentHrefKey) {
14084
- const children = listNavChildren(parentHrefKey);
14183
+ function buildRootNavDropSlots(draggedEl) {
14184
+ const items = listReorderableNavItems(draggedEl);
14185
+ if (isVerticalNavLayout(items, draggedEl)) {
14186
+ return buildVerticalRootNavDropSlots(items, draggedEl);
14187
+ }
14188
+ return buildHorizontalRootNavDropSlots(items, draggedEl);
14189
+ }
14190
+ function buildChildNavDropSlots(parentHrefKey, draggedEl) {
14191
+ const children = listNavChildren(parentHrefKey, draggedEl);
14085
14192
  const slots = [];
14086
14193
  const barThickness = 3;
14087
14194
  if (children.length === 0) return slots;
@@ -14102,10 +14209,7 @@ function buildChildNavDropSlots(parentHrefKey) {
14102
14209
  width = first.width;
14103
14210
  } else if (i === children.length) {
14104
14211
  const last = children[children.length - 1].getBoundingClientRect();
14105
- const lastGap = children.length >= 2 ? Math.max(
14106
- 0,
14107
- last.top - children[children.length - 2].getBoundingClientRect().bottom
14108
- ) : edgeGap;
14212
+ const lastGap = children.length >= 2 ? Math.max(0, last.top - children[children.length - 2].getBoundingClientRect().bottom) : edgeGap;
14109
14213
  top = last.bottom + lastGap / 2 - barThickness / 2;
14110
14214
  left = last.left;
14111
14215
  width = last.width;
@@ -14128,18 +14232,19 @@ function buildChildNavDropSlots(parentHrefKey) {
14128
14232
  }
14129
14233
  return slots;
14130
14234
  }
14131
- function buildAllNavDropSlots(draggedHrefKey) {
14132
- const dragged = listNavbarItems().find((el) => el.getAttribute("data-ohw-href-key") === draggedHrefKey);
14133
- if (!dragged) return buildRootNavDropSlots();
14235
+ function buildAllNavDropSlots(draggedHrefKey, draggedEl) {
14236
+ const activeItems = listActiveNavbarItems(draggedEl);
14237
+ 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);
14238
+ if (!dragged) return buildRootNavDropSlots(draggedEl);
14134
14239
  if (isNestedNavChild(dragged)) {
14135
14240
  const parentKey = resolveParentNavHrefKey(dragged);
14136
14241
  if (!parentKey) return [];
14137
- return buildChildNavDropSlots(parentKey);
14242
+ return buildChildNavDropSlots(parentKey, draggedEl);
14138
14243
  }
14139
- return buildRootNavDropSlots();
14244
+ return buildRootNavDropSlots(draggedEl);
14140
14245
  }
14141
- function hitTestNavDropSlot(clientX, clientY, draggedHrefKey) {
14142
- const slots = buildAllNavDropSlots(draggedHrefKey);
14246
+ function hitTestNavDropSlot(clientX, clientY, draggedHrefKey, draggedEl) {
14247
+ const slots = buildAllNavDropSlots(draggedHrefKey, draggedEl);
14143
14248
  let best = null;
14144
14249
  for (const slot of slots) {
14145
14250
  const cx2 = slot.left + slot.width / 2;
@@ -14190,6 +14295,12 @@ function useNavItemDrag({
14190
14295
  setIsItemDragging(false);
14191
14296
  if (keepOpenEl?.isConnected) {
14192
14297
  setNavGroupForceOpen(keepOpenEl, true);
14298
+ requestAnimationFrame(() => {
14299
+ if (keepOpenEl.isConnected) setNavGroupForceOpen(keepOpenEl, true);
14300
+ requestAnimationFrame(() => {
14301
+ if (keepOpenEl.isConnected) setNavGroupForceOpen(keepOpenEl, true);
14302
+ });
14303
+ });
14193
14304
  } else {
14194
14305
  setNavGroupForceOpen(null, false);
14195
14306
  }
@@ -14205,7 +14316,7 @@ function useNavItemDrag({
14205
14316
  }
14206
14317
  session.activeSlot = activeSlot;
14207
14318
  setSiblingHintRects([]);
14208
- const slots = buildAllNavDropSlots(session.hrefKey);
14319
+ const slots = buildAllNavDropSlots(session.hrefKey, session.draggedEl);
14209
14320
  setNavDropSlots(slots);
14210
14321
  const activeIdx = activeSlot ? slots.findIndex(
14211
14322
  (s) => s.parentId === activeSlot.parentId && s.insertIndex === activeSlot.insertIndex
@@ -14241,7 +14352,12 @@ function useNavItemDrag({
14241
14352
  if (session.wasSelected && selectedElRef.current === session.draggedEl) {
14242
14353
  setToolbarRect(rect);
14243
14354
  }
14244
- const initialSlot = hitTestNavDropSlot(session.lastClientX, session.lastClientY, session.hrefKey);
14355
+ const initialSlot = hitTestNavDropSlot(
14356
+ session.lastClientX,
14357
+ session.lastClientY,
14358
+ session.hrefKey,
14359
+ session.draggedEl
14360
+ );
14245
14361
  refreshNavDragVisuals(session, initialSlot, session.lastClientX, session.lastClientY);
14246
14362
  },
14247
14363
  [
@@ -14263,10 +14379,11 @@ function useNavItemDrag({
14263
14379
  }
14264
14380
  const x = typeof clientX === "number" && (clientX !== 0 || clientY !== 0) ? clientX : session.lastClientX;
14265
14381
  const y = typeof clientY === "number" && (clientX !== 0 || clientY !== 0) ? clientY : session.lastClientY;
14266
- const slot = session.activeSlot ?? hitTestNavDropSlot(x, y, session.hrefKey);
14382
+ const slot = session.activeSlot ?? hitTestNavDropSlot(x, y, session.hrefKey, session.draggedEl);
14267
14383
  const planned = slot != null ? planNavItemMove(session.hrefKey, slot.parentId, slot.insertIndex) : null;
14268
14384
  const wasSelected = session.wasSelected;
14269
14385
  const hrefKey = session.hrefKey;
14386
+ const keepDropdownOpen = Boolean(session.draggedEl.closest("[data-ohw-nav-children]"));
14270
14387
  const applySelectionAfterDrop = () => {
14271
14388
  if (!wasSelected) {
14272
14389
  deselectRef.current();
@@ -14300,6 +14417,14 @@ function useNavItemDrag({
14300
14417
  });
14301
14418
  applySelectionAfterDrop();
14302
14419
  clearNavDragVisuals();
14420
+ if (keepDropdownOpen) {
14421
+ requestAnimationFrame(() => {
14422
+ const desktop = document.querySelector("[data-ohw-nav-container]");
14423
+ const drawer = document.querySelector("[data-ohw-nav-drawer]");
14424
+ 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)}"]`);
14425
+ if (link) setNavGroupForceOpen(link, true);
14426
+ });
14427
+ }
14303
14428
  requestAnimationFrame(() => {
14304
14429
  if (editContentRef.current[NAV_ORDER_KEY] === planned.orderJson) {
14305
14430
  applyNavForest(planned.forest);
@@ -14339,7 +14464,7 @@ function useNavItemDrag({
14339
14464
  if (!session) return false;
14340
14465
  e.preventDefault();
14341
14466
  if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
14342
- const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey);
14467
+ const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey, session.draggedEl);
14343
14468
  refreshNavDragVisualsRef.current(session, slot, e.clientX, e.clientY);
14344
14469
  return true;
14345
14470
  },
@@ -14385,7 +14510,7 @@ function useNavItemDrag({
14385
14510
  clearTextSelection();
14386
14511
  const session = navDragRef.current;
14387
14512
  if (!session) return;
14388
- const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey);
14513
+ const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey, session.draggedEl);
14389
14514
  refreshNavDragVisualsRef.current(session, slot, e.clientX, e.clientY);
14390
14515
  return;
14391
14516
  }
@@ -14401,7 +14526,8 @@ function useNavItemDrag({
14401
14526
  } catch {
14402
14527
  }
14403
14528
  if (linkPopoverOpenRef.current) setLinkPopover(null);
14404
- if (activeElRef.current) deactivateRef.current();
14529
+ const isNestedDrag = Boolean(pending.el.closest("[data-ohw-nav-children]"));
14530
+ if (activeElRef.current && !isNestedDrag) deactivateRef.current();
14405
14531
  const key = pending.el.getAttribute("data-ohw-href-key");
14406
14532
  if (!key) return;
14407
14533
  beginNavDragRef.current({
@@ -14412,6 +14538,9 @@ function useNavItemDrag({
14412
14538
  lastClientY: e.clientY,
14413
14539
  activeSlot: null
14414
14540
  });
14541
+ if (activeElRef.current && isNestedDrag) {
14542
+ deactivateRef.current();
14543
+ }
14415
14544
  };
14416
14545
  const endPointerDrag = (e) => {
14417
14546
  const pending = navPointerDragRef.current;
@@ -14489,6 +14618,7 @@ function useNavItemDrag({
14489
14618
  );
14490
14619
  return {
14491
14620
  navDragRef,
14621
+ navPointerDragRef,
14492
14622
  navDropSlots,
14493
14623
  activeNavDropIndex,
14494
14624
  startNavLinkDrag,
@@ -15887,6 +16017,7 @@ function isNavDropdownPanelOpen(childrenRoot) {
15887
16017
  if (childrenRoot.closest("[data-ohw-nav-drawer]")) return true;
15888
16018
  const group = childrenRoot.closest("[data-ohw-nav-group]");
15889
16019
  if (group?.hasAttribute("data-ohw-nav-force-open")) return true;
16020
+ if (navDropdownsOpenOnClick()) return false;
15890
16021
  if (childrenRoot.clientHeight < 2 || childrenRoot.clientWidth < 2) return false;
15891
16022
  const style = window.getComputedStyle(childrenRoot);
15892
16023
  if (style.display === "none" || style.visibility === "hidden") return false;
@@ -15930,6 +16061,11 @@ function getNavigationItemAnchor(el) {
15930
16061
  function isNavigationItem2(el) {
15931
16062
  return getNavigationItemAnchor(el) !== null;
15932
16063
  }
16064
+ function isNavFooterScopedNavigationItem(el) {
16065
+ return Boolean(
16066
+ el.closest("nav, footer, [data-ohw-nav-container], [data-ohw-nav-drawer]")
16067
+ );
16068
+ }
15933
16069
  function socialWordsClicked(target, item) {
15934
16070
  const text = target.closest('[data-ohw-editable="text"], [data-ohw-editable="plain"]');
15935
16071
  return Boolean(text && item.contains(text));
@@ -16140,6 +16276,7 @@ function getNavigationSelectionParent(el) {
16140
16276
  }
16141
16277
  function collectNavigationItemSiblingHintRects(selected) {
16142
16278
  if (!isNavigationItem2(selected)) return [];
16279
+ if (!isNavFooterScopedNavigationItem(selected)) return [];
16143
16280
  const socialsRow = findSocialsRow(selected);
16144
16281
  if (socialsRow) {
16145
16282
  return listSocialItems(socialsRow).filter((item) => item !== selected).map((item) => item.getBoundingClientRect());
@@ -17311,6 +17448,7 @@ function OhhwellsBridge() {
17311
17448
  linkPopoverSessionRef.current = linkPopover;
17312
17449
  const {
17313
17450
  navDragRef,
17451
+ navPointerDragRef,
17314
17452
  navDropSlots,
17315
17453
  activeNavDropIndex,
17316
17454
  startNavLinkDrag,
@@ -17513,7 +17651,12 @@ function OhhwellsBridge() {
17513
17651
  if (owner) persistFieldsRef.current(owner);
17514
17652
  }
17515
17653
  activeElRef.current = null;
17516
- setNavGroupForceOpen(null, false);
17654
+ const preserveNavDropdown = Boolean(navPointerDragRef.current?.el?.closest("[data-ohw-nav-children]")) || Boolean(navDragRef.current?.draggedEl?.closest("[data-ohw-nav-children]")) || Boolean(
17655
+ selectedElRef.current?.closest("[data-ohw-nav-children]") && selectedElRef.current?.closest("[data-ohw-nav-group]")?.hasAttribute("data-ohw-nav-force-open")
17656
+ );
17657
+ if (!preserveNavDropdown) {
17658
+ setNavGroupForceOpen(null, false);
17659
+ }
17517
17660
  setReorderHrefKey(null);
17518
17661
  setReorderDragDisabled(false);
17519
17662
  if (!selectedElRef.current) {
@@ -17635,7 +17778,10 @@ function OhhwellsBridge() {
17635
17778
  setSelectedIsSocialsRow(false);
17636
17779
  const isDropdownTrigger = !isNestedNavChild(navAnchor) && (navItemHasDropdownChildren(navAnchor) || navItemOwnsDropdownPanel(navAnchor));
17637
17780
  if (isNestedNavChild(navAnchor)) {
17638
- setNavGroupForceOpen(navAnchor, true);
17781
+ const group = navAnchor.closest("[data-ohw-nav-group]");
17782
+ if (group?.hasAttribute("data-ohw-nav-force-open")) {
17783
+ setNavGroupForceOpen(navAnchor, true);
17784
+ }
17639
17785
  setNavDropdownPreviewOpen(null);
17640
17786
  } else if (isDropdownTrigger) {
17641
17787
  const group = navAnchor.closest("[data-ohw-nav-group]");
@@ -17717,6 +17863,10 @@ function OhhwellsBridge() {
17717
17863
  const handleNavDropdownOpenChange = (0, import_react17.useCallback)((open) => {
17718
17864
  const selected = selectedElRef.current;
17719
17865
  if (!selected || !isNavigationItem2(selected)) return;
17866
+ if (isNestedNavChild(selected)) return;
17867
+ const group = selected.closest("[data-ohw-nav-group]");
17868
+ const domOpen = Boolean(group?.hasAttribute("data-ohw-nav-force-open"));
17869
+ if (open === domOpen) return;
17720
17870
  setNavGroupForceOpen(selected, open);
17721
17871
  setNavDropdownPreviewOpen(open);
17722
17872
  requestAnimationFrame(() => {
@@ -18246,7 +18396,10 @@ function OhhwellsBridge() {
18246
18396
  clearHrefKeyHover(anchor);
18247
18397
  const isDropdownTrigger = !isNestedNavChild(anchor) && (navItemHasDropdownChildren(anchor) || navItemOwnsDropdownPanel(anchor));
18248
18398
  if (isNestedNavChild(anchor)) {
18249
- setNavGroupForceOpen(anchor, true);
18399
+ const group = anchor.closest("[data-ohw-nav-group]");
18400
+ if (group?.hasAttribute("data-ohw-nav-force-open")) {
18401
+ setNavGroupForceOpen(anchor, true);
18402
+ }
18250
18403
  setNavDropdownPreviewOpen(null);
18251
18404
  } else if (isDropdownTrigger) {
18252
18405
  setNavGroupForceOpen(null, false);
@@ -19088,28 +19241,19 @@ function OhhwellsBridge() {
19088
19241
  return;
19089
19242
  }
19090
19243
  const existing = editStylesRef.current;
19091
- let initialVh = window.innerHeight;
19092
- if (existing?.base.textContent) {
19093
- const match = existing.base.textContent.match(/\.min-h-screen[^{]*\{[^}]*min-height:\s*(\d+)px/);
19094
- if (match) initialVh = parseInt(match[1], 10);
19095
- }
19244
+ const canvasHeight = "var(--ohw-canvas-h, 852px)";
19096
19245
  const baseCss = `
19097
19246
  html { height: auto !important; }
19098
19247
  body { height: auto !important; min-height: 0 !important; overflow: hidden !important; }
19099
- .min-h-screen, .min-h-svh, .min-h-dvh { min-height: ${initialVh}px !important; }
19100
- .h-screen, .h-svh, .h-dvh { height: ${initialVh}px !important; }
19101
- [style*="100vh"] { min-height: ${initialVh}px !important; height: ${initialVh}px !important; }
19102
- [style*="100svh"] { min-height: ${initialVh}px !important; height: ${initialVh}px !important; }
19103
- [style*="100dvh"] { min-height: ${initialVh}px !important; height: ${initialVh}px !important; }
19104
- /* A section written as min-height: var(--ohw-canvas-h, 100svh) \u2014 the documented way to
19105
- build a full-viewport section that still grows for its own content \u2014 matches the three
19106
- rules above on substring alone, since the fallback text contains "100svh" too. Forcing
19107
- a literal height on top of that turns "at least one screen" into "exactly one screen",
19108
- so content taller than one screen (a long mobile hero, say) overflows a centered flex
19109
- column upward, under whatever sits above it. Only the min-height half belongs to it. */
19110
- [style*="min-height"][style*="100vh"],
19111
- [style*="min-height"][style*="100svh"],
19112
- [style*="min-height"][style*="100dvh"] { height: auto !important; }
19248
+ .min-h-screen, .min-h-svh, .min-h-dvh { min-height: ${canvasHeight} !important; }
19249
+ .h-screen, .h-svh, .h-dvh { height: ${canvasHeight} !important; }
19250
+ /* Literal inline viewport units only \u2014 skip R11 sections that already reference --ohw-canvas-h
19251
+ (their style attribute contains "100svh" only as a var() fallback string). */
19252
+ [style*="100vh"]:not([style*="--ohw-canvas-h"]) { min-height: ${canvasHeight} !important; height: ${canvasHeight} !important; }
19253
+ [style*="100svh"]:not([style*="--ohw-canvas-h"]) { min-height: ${canvasHeight} !important; height: ${canvasHeight} !important; }
19254
+ [style*="100dvh"]:not([style*="--ohw-canvas-h"]) { min-height: ${canvasHeight} !important; height: ${canvasHeight} !important; }
19255
+ /* R11: min-height via --ohw-canvas-h; height must grow with content taller than one screen. */
19256
+ [style*="min-height"][style*="--ohw-canvas-h"] { height: auto !important; }
19113
19257
  /* Emptied text keeps somewhere to click. A label typed down to nothing collapses to a
19114
19258
  couple of pixels, and getting back into it meant hunting for the caret with the mouse.
19115
19259
  Edit mode only \u2014 the published page shows nothing where there is nothing (OHH-736). */
@@ -19256,6 +19400,10 @@ function OhhwellsBridge() {
19256
19400
  outline-offset: 0 !important;
19257
19401
  box-shadow: none !important;
19258
19402
  }
19403
+ /* Open nav dropdown panels paint above AI section selection chrome (2147483000). */
19404
+ [data-ohw-nav-group][data-ohw-nav-force-open] > [data-ohw-nav-children] {
19405
+ z-index: 2147483100 !important;
19406
+ }
19259
19407
  /* Text edit wins over grab/default (must beat [data-ohw-can-drag] *). */
19260
19408
  [data-ohw-editing],
19261
19409
  [data-ohw-editing] *,
@@ -20594,7 +20742,11 @@ function OhhwellsBridge() {
20594
20742
  const slotFromItem = hrefKey ? findSocialByHrefKey(hrefKey)?.querySelector('[data-ohw-editable="icon"]') : null;
20595
20743
  const requestedIsIconSlot = Boolean(requestedIconKey) && Boolean(document.querySelector(`[data-ohw-key="${requestedIconKey}"][data-ohw-editable="icon"]`));
20596
20744
  const requestedIsFree = Boolean(requestedIconKey) && !document.querySelector(`[data-ohw-key="${requestedIconKey}"]`);
20597
- const iconKey = requestedIsIconSlot ? requestedIconKey : slotFromItem?.dataset.ohwKey ?? (requestedIsFree ? requestedIconKey : void 0);
20745
+ let iconKey = requestedIsIconSlot ? requestedIconKey : slotFromItem?.dataset.ohwKey ?? (requestedIsFree ? requestedIconKey : void 0);
20746
+ const item = hrefKey ? findSocialByHrefKey(hrefKey) : null;
20747
+ if (item && typeof iconMarkup === "string" && iconMarkup) {
20748
+ iconKey = ensureIconSlot(item) ?? iconKey;
20749
+ }
20598
20750
  if (iconKey && typeof iconMarkup === "string" && iconMarkup) {
20599
20751
  document.querySelectorAll(`[data-ohw-key="${iconKey}"][data-ohw-editable="icon"]`).forEach((el) => {
20600
20752
  applyIconMarkup(el, iconMarkup);
@@ -20604,7 +20756,7 @@ function OhhwellsBridge() {
20604
20756
  }
20605
20757
  if (iconKey && platformId) nodes.push({ key: socialPlatformKey(iconKey), text: platformId });
20606
20758
  if (iconKey && label) {
20607
- const labelKey = socialLabelKey(iconKey);
20759
+ const labelKey = (item ? socialLabelElement(item)?.getAttribute("data-ohw-key") : null) ?? socialLabelKey(iconKey);
20608
20760
  document.querySelectorAll(`[data-ohw-key="${labelKey}"]`).forEach((el) => {
20609
20761
  if (keepLabel && el.textContent?.trim()) return;
20610
20762
  el.textContent = label;
@@ -21423,7 +21575,12 @@ function OhhwellsBridge() {
21423
21575
  }
21424
21576
  if (navDragRef.current) {
21425
21577
  const session = navDragRef.current;
21426
- const slot = hitTestNavDropSlot(session.lastClientX, session.lastClientY, session.hrefKey);
21578
+ const slot = hitTestNavDropSlot(
21579
+ session.lastClientX,
21580
+ session.lastClientY,
21581
+ session.hrefKey,
21582
+ session.draggedEl
21583
+ );
21427
21584
  refreshNavDragVisualsRef.current(session, slot, session.lastClientX, session.lastClientY);
21428
21585
  }
21429
21586
  if (hoveredImageRef.current) {
@@ -21625,18 +21782,21 @@ function OhhwellsBridge() {
21625
21782
  }
21626
21783
  return null;
21627
21784
  };
21785
+ const isPointInRect = (el, clientX, clientY) => {
21786
+ const r2 = el.getBoundingClientRect();
21787
+ return clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom;
21788
+ };
21628
21789
  const isPointOverEditable = (scope, clientX, clientY) => {
21629
21790
  const editables = scope.querySelectorAll("[data-ohw-editable], [data-ohw-href-key]");
21630
21791
  for (const el of editables) {
21631
- const r2 = el.getBoundingClientRect();
21632
- if (clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom) return true;
21792
+ if (isPointInRect(el, clientX, clientY)) return true;
21633
21793
  }
21634
21794
  return false;
21635
21795
  };
21636
21796
  const handleCarouselHover = (e) => {
21637
21797
  const container = findCarouselAtPoint(e.clientX, e.clientY);
21638
21798
  const scope = container?.closest("[data-ohw-section]") ?? container?.parentElement ?? null;
21639
- if (!container || !scope || isPointOverEditable(scope, e.clientX, e.clientY)) {
21799
+ if (!container || !scope || isPointOverEditable(scope, e.clientX, e.clientY) || isPointOverNavigation(e.clientX, e.clientY) || isPointOverBridgeChrome(e.clientX, e.clientY)) {
21640
21800
  setCarouselHover((prev) => prev ? null : prev);
21641
21801
  return;
21642
21802
  }
@@ -22085,7 +22245,7 @@ function OhhwellsBridge() {
22085
22245
  postToParent2({
22086
22246
  type: "ow:ready",
22087
22247
  version: "1",
22088
- bridgeVersion: "0.1.99",
22248
+ bridgeVersion: "0.1.100",
22089
22249
  path: pathname,
22090
22250
  nodes: collectEditableNodes(editContentRef.current),
22091
22251
  sections