@ohhwells/bridge 0.1.117-next.315 → 0.1.117-next.317

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
@@ -8510,7 +8510,7 @@ function ItemInteractionLayer({
8510
8510
  const isDragging = state === "dragging";
8511
8511
  const showToolbar = isActive && toolbar;
8512
8512
  const showDragHandle = (isActive || isDragging) && showHandle;
8513
- const itemDragEnabled = itemDragSurface && isActive && showHandle && !isDragging && !dragDisabled;
8513
+ const itemDragEnabled = itemDragSurface && isActive && !isDragging && !dragDisabled && Boolean(showHandle || onItemPointerDown);
8514
8514
  const useDetachedBelowToolbar = Boolean(showToolbar && state === "active-bottom" && toolbarBelowRect);
8515
8515
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
8516
8516
  "div",
@@ -9456,11 +9456,10 @@ function MediaOverlay({
9456
9456
  className: "flex items-center justify-center cursor-pointer",
9457
9457
  style: {
9458
9458
  ...box,
9459
- // When text overlays this media, let clicks fall THROUGH to the text underneath. In the
9460
- // parent this needed a whole `ow:click-at` round-trip to re-hit-test inside the iframe;
9461
- // in-document, pointer-events does it natively. The button below opts back in, so
9462
- // Replace still works.
9463
- pointerEvents: hover.hasTextOverlap || cueOnly ? "none" : "auto",
9459
+ // Visual only. `pointer-events: auto` on this full-bleed rect covered the navbar
9460
+ // (hero bg includes the absolute TopNav) and swallowed CTA press-drag. Text overlay
9461
+ // and cueOnly also need clicks to fall through — Replace / video controls opt back in.
9462
+ pointerEvents: "none",
9464
9463
  // Selected: a firm component ring with no wash, so the image reads as chosen rather
9465
9464
  // than hovered. Hover keeps the existing tinted preview.
9466
9465
  boxShadow: selected ? "inset 0 0 0 2px var(--color-bridge-primary)" : "inset 0 0 0 1.5px var(--color-bridge-primary)",
@@ -11124,6 +11123,13 @@ function findButtonAtPoint(x, y, media) {
11124
11123
  if (hits.length === 0) return null;
11125
11124
  return hits.reduce((best, el) => best.contains(el) ? el : best);
11126
11125
  }
11126
+ function findNavbarCtaAtPoint(x, y) {
11127
+ const hits = Array.from(
11128
+ document.querySelectorAll('[data-ohw-role="navbar-button"]')
11129
+ ).filter((el) => containsPoint(el, x, y) && !el.closest("[data-ohw-bridge]"));
11130
+ if (hits.length === 0) return null;
11131
+ return hits.reduce((best, el) => best.contains(el) ? el : best);
11132
+ }
11127
11133
 
11128
11134
  // src/lib/session-search.ts
11129
11135
  var STORAGE_KEY = "ohw-preserved-search";
@@ -16675,7 +16681,7 @@ function ButtonStylePanel({
16675
16681
  const label = previewLabel.trim() || "Book Now";
16676
16682
  return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex w-full flex-col gap-5", children: [
16677
16683
  /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("section", { className: "flex w-full flex-col gap-2.5", children: [
16678
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("h3", { className: "text-xs font-semibold uppercase leading-4 tracking-[0.6px] text-stone-500", children: "Variants" }),
16684
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("h3", { className: "text-xs font-semibold uppercase leading-4 tracking-[0.6px] text-stone-500 font-sans", children: "Variants" }),
16679
16685
  /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "flex w-full flex-col gap-2.5", children: BUTTON_VARIANT_IDS.map((id) => {
16680
16686
  const chrome = variants[id];
16681
16687
  const selected = id === variant;
@@ -16739,7 +16745,7 @@ function ButtonStylePanel({
16739
16745
  }) })
16740
16746
  ] }),
16741
16747
  /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("section", { className: "flex w-full flex-col gap-2.5", children: [
16742
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("h3", { className: "text-xs font-semibold uppercase leading-4 tracking-[0.6px] text-stone-500", children: "Size" }),
16748
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("h3", { className: "text-xs font-semibold uppercase leading-4 tracking-[0.6px] text-stone-500 font-sans", children: "Size" }),
16743
16749
  /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
16744
16750
  "div",
16745
16751
  {
@@ -17127,6 +17133,137 @@ function reorderButtonInCollection(button, clientX) {
17127
17133
  if (!placed) collection.append(button);
17128
17134
  return listCollectionMembers(collection);
17129
17135
  }
17136
+ function listVisibleCollectionButtons(collection) {
17137
+ return Array.from(collection.querySelectorAll(CTA_BUTTON_SELECTOR)).filter((el) => {
17138
+ if (!buttonId(el)) return false;
17139
+ return el.getClientRects().length > 0;
17140
+ });
17141
+ }
17142
+ function isVerticalButtonLayout(items, collection) {
17143
+ if (items.length >= 2) {
17144
+ const a = items[0].getBoundingClientRect();
17145
+ const b = items[1].getBoundingClientRect();
17146
+ return b.top - a.bottom > b.left - a.right;
17147
+ }
17148
+ const style = window.getComputedStyle(collection);
17149
+ return style.flexDirection === "column" || style.flexDirection === "column-reverse";
17150
+ }
17151
+ function buildButtonCollectionDropSlots(collection) {
17152
+ const items = listVisibleCollectionButtons(collection);
17153
+ const barThickness = 3;
17154
+ const slots = [];
17155
+ if (items.length === 0) {
17156
+ const rect = collection.getBoundingClientRect();
17157
+ slots.push({
17158
+ insertIndex: 0,
17159
+ left: rect.left + rect.width / 2 - barThickness / 2,
17160
+ top: rect.top,
17161
+ width: barThickness,
17162
+ height: Math.max(rect.height, 24),
17163
+ direction: "vertical"
17164
+ });
17165
+ return slots;
17166
+ }
17167
+ if (isVerticalButtonLayout(items, collection)) {
17168
+ const edgeGap2 = items.length >= 2 ? Math.max(0, items[1].getBoundingClientRect().top - items[0].getBoundingClientRect().bottom) : 16;
17169
+ for (let i = 0; i <= items.length; i++) {
17170
+ let top;
17171
+ let left;
17172
+ let width;
17173
+ if (i === 0) {
17174
+ const first = items[0].getBoundingClientRect();
17175
+ top = first.top - edgeGap2 / 2 - barThickness / 2;
17176
+ left = first.left;
17177
+ width = first.width;
17178
+ } else if (i === items.length) {
17179
+ const last = items[items.length - 1].getBoundingClientRect();
17180
+ const lastGap = items.length >= 2 ? Math.max(0, last.top - items[items.length - 2].getBoundingClientRect().bottom) : edgeGap2;
17181
+ top = last.bottom + lastGap / 2 - barThickness / 2;
17182
+ left = last.left;
17183
+ width = last.width;
17184
+ } else {
17185
+ const prev = items[i - 1].getBoundingClientRect();
17186
+ const next = items[i].getBoundingClientRect();
17187
+ top = (prev.bottom + next.top) / 2 - barThickness / 2;
17188
+ left = Math.min(prev.left, next.left);
17189
+ width = Math.max(prev.right, next.right) - left;
17190
+ }
17191
+ slots.push({
17192
+ insertIndex: i,
17193
+ left,
17194
+ top,
17195
+ width: Math.max(width, 40),
17196
+ height: barThickness,
17197
+ direction: "horizontal"
17198
+ });
17199
+ }
17200
+ return slots;
17201
+ }
17202
+ const edgeGap = items.length >= 2 ? Math.max(0, items[1].getBoundingClientRect().left - items[0].getBoundingClientRect().right) : 12;
17203
+ for (let i = 0; i <= items.length; i++) {
17204
+ let left;
17205
+ let top;
17206
+ let height;
17207
+ if (i === 0) {
17208
+ const first = items[0].getBoundingClientRect();
17209
+ left = first.left - edgeGap / 2 - barThickness / 2;
17210
+ top = first.top;
17211
+ height = first.height;
17212
+ } else if (i === items.length) {
17213
+ const last = items[items.length - 1].getBoundingClientRect();
17214
+ const lastGap = items.length >= 2 ? Math.max(0, last.left - items[items.length - 2].getBoundingClientRect().right) : edgeGap;
17215
+ left = last.right + lastGap / 2 - barThickness / 2;
17216
+ top = last.top;
17217
+ height = last.height;
17218
+ } else {
17219
+ const prev = items[i - 1].getBoundingClientRect();
17220
+ const next = items[i].getBoundingClientRect();
17221
+ left = (prev.right + next.left) / 2 - barThickness / 2;
17222
+ top = Math.min(prev.top, next.top);
17223
+ height = Math.max(prev.bottom, next.bottom) - top;
17224
+ }
17225
+ slots.push({
17226
+ insertIndex: i,
17227
+ left,
17228
+ top,
17229
+ width: barThickness,
17230
+ height: Math.max(height, 24),
17231
+ direction: "vertical"
17232
+ });
17233
+ }
17234
+ return slots;
17235
+ }
17236
+ function hitTestButtonCollectionDropSlot(collection, clientX, clientY) {
17237
+ const slots = buildButtonCollectionDropSlots(collection);
17238
+ let best = null;
17239
+ for (const slot of slots) {
17240
+ const cx2 = slot.left + slot.width / 2;
17241
+ const cy = slot.top + slot.height / 2;
17242
+ const dist = slot.direction === "vertical" ? Math.abs(clientX - cx2) + Math.abs(clientY - cy) * 0.25 : Math.abs(clientY - cy) + Math.abs(clientX - cx2) * 0.25;
17243
+ if (!best || dist < best.dist) best = { slot, dist };
17244
+ }
17245
+ return best?.slot ?? null;
17246
+ }
17247
+ function insertButtonAtCollectionIndex(button, insertIndex) {
17248
+ const collection = buttonCollectionOf(button);
17249
+ if (!collection) return null;
17250
+ const items = listVisibleCollectionButtons(collection);
17251
+ const from = items.indexOf(button);
17252
+ if (from < 0) return null;
17253
+ const others = items.filter((el) => el !== button);
17254
+ let index = insertIndex;
17255
+ if (from < insertIndex) index -= 1;
17256
+ if (index <= 0) {
17257
+ const first = others[0];
17258
+ if (first) first.before(button);
17259
+ else collection.append(button);
17260
+ } else if (index >= others.length) {
17261
+ collection.append(button);
17262
+ } else {
17263
+ others[index].before(button);
17264
+ }
17265
+ return listCollectionMembers(collection);
17266
+ }
17130
17267
  function persistCollectionOrder(collection, content) {
17131
17268
  const id = collection.getAttribute(COLLECTION_ATTR);
17132
17269
  if (!id) return null;
@@ -17223,8 +17360,34 @@ function restoreSnapshot(doc, snapshot, content) {
17223
17360
  setButtonDragAttr(el);
17224
17361
  return el;
17225
17362
  }
17363
+ function navbarCtasInScope(el) {
17364
+ const scope = el.closest("nav, [data-ohw-nav-root], [data-ohw-nav-drawer]") ?? el.parentElement;
17365
+ if (!scope) return [];
17366
+ return Array.from(scope.querySelectorAll(CTA_BUTTON_SELECTOR)).filter(
17367
+ (button) => isNavbarCta(button) && buttonId(button)
17368
+ );
17369
+ }
17370
+ function ensureNavbarButtonCollection(button, content) {
17371
+ const existing = buttonCollectionOf(button);
17372
+ if (existing) return existing;
17373
+ if (!isNavbarCta(button) || !buttonId(button)) return null;
17374
+ const parent = button.parentElement;
17375
+ if (!parent) return null;
17376
+ const siblings = navbarCtasInScope(button).filter((el) => el.parentElement === parent);
17377
+ if (siblings.length < 2) return null;
17378
+ const id = nextCollectionId(content, button.ownerDocument);
17379
+ const collection = createCollection(button.ownerDocument, id, collectionGap(button, tokensFromButton(button)));
17380
+ siblings[0].before(collection);
17381
+ for (const member of siblings) {
17382
+ collection.append(member);
17383
+ setButtonDragAttr(member);
17384
+ }
17385
+ return collection;
17386
+ }
17226
17387
  function collectionDragEnabled(el) {
17227
- return Boolean(isNavbarCta(el) && buttonCollectionOf(el) && buttonId(el));
17388
+ if (!isNavbarCta(el) || !buttonId(el)) return false;
17389
+ if (buttonCollectionOf(el)) return true;
17390
+ return navbarCtasInScope(el).length >= 2;
17228
17391
  }
17229
17392
 
17230
17393
  // src/lib/item-drag-interaction.ts
@@ -17656,7 +17819,7 @@ function useNavItemDrag({
17656
17819
  document.querySelectorAll(
17657
17820
  "nav [data-ohw-href-key], [data-ohw-nav-container] [data-ohw-href-key], [data-ohw-nav-drawer] [data-ohw-href-key]"
17658
17821
  ).forEach((el) => {
17659
- if (isNavbarHrefKey(el.getAttribute("data-ohw-href-key"))) {
17822
+ if (isNavbarHrefKey(el.getAttribute("data-ohw-href-key")) || isCtaButton(el)) {
17660
17823
  disableNativeHrefDrag(el);
17661
17824
  }
17662
17825
  });
@@ -19523,6 +19686,12 @@ function isPointOverNavigation(x, y) {
19523
19686
  const r2 = panel.getBoundingClientRect();
19524
19687
  if (x >= r2.left && x <= r2.right && y >= r2.top && y <= r2.bottom) return true;
19525
19688
  }
19689
+ for (const el of document.querySelectorAll('[data-ohw-role="navbar-button"]')) {
19690
+ const r2 = el.getBoundingClientRect();
19691
+ if (r2.width > 0 && r2.height > 0 && x >= r2.left && x <= r2.right && y >= r2.top && y <= r2.bottom) {
19692
+ return true;
19693
+ }
19694
+ }
19526
19695
  return false;
19527
19696
  }
19528
19697
  function findHoveredNavOrFooterContainer(x, y) {
@@ -20827,6 +20996,10 @@ function OhhwellsBridge() {
20827
20996
  const setFloatingPanelRef = (0, import_react19.useRef)(setFloatingPanel);
20828
20997
  const [floatingPanelPos, setFloatingPanelPos] = (0, import_react19.useState)(null);
20829
20998
  const buttonCollectionDragRef = (0, import_react19.useRef)(null);
20999
+ const buttonDropInsertIndexRef = (0, import_react19.useRef)(null);
21000
+ const [buttonDropSlots, setButtonDropSlots] = (0, import_react19.useState)([]);
21001
+ const [activeButtonDropIndex, setActiveButtonDropIndex] = (0, import_react19.useState)(null);
21002
+ const buttonPointerDragRef = (0, import_react19.useRef)(null);
20830
21003
  const [buttonStyleTick, setButtonStyleTick] = (0, import_react19.useState)(0);
20831
21004
  const [logoSizeDraft, setLogoSizeDraft] = (0, import_react19.useState)(null);
20832
21005
  const [editorViewport, setEditorViewport] = (0, import_react19.useState)("desktop");
@@ -21717,6 +21890,47 @@ function OhhwellsBridge() {
21717
21890
  },
21718
21891
  [beginFooterDrag]
21719
21892
  );
21893
+ const persistButtonCollectionDrag = (0, import_react19.useCallback)(
21894
+ (button, clientX) => {
21895
+ const insertIndex = buttonDropInsertIndexRef.current;
21896
+ if (insertIndex != null) insertButtonAtCollectionIndex(button, insertIndex);
21897
+ else if (typeof clientX === "number" && clientX !== 0) reorderButtonInCollection(button, clientX);
21898
+ buttonDropInsertIndexRef.current = null;
21899
+ const collection = buttonCollectionOf(button);
21900
+ if (collection) {
21901
+ const persisted = persistCollectionOrder(collection, editContentRef.current);
21902
+ if (persisted) {
21903
+ editContentRef.current = persisted.content;
21904
+ postToParent2({ type: "ow:change", nodes: persisted.nodes });
21905
+ }
21906
+ }
21907
+ buttonCollectionDragRef.current = null;
21908
+ buttonPointerDragRef.current = null;
21909
+ setButtonDropSlots([]);
21910
+ setActiveButtonDropIndex(null);
21911
+ setIsItemDragging(false);
21912
+ unlockFooterDragInteraction();
21913
+ if (button.isConnected) setToolbarRect(button.getBoundingClientRect());
21914
+ },
21915
+ [postToParent2]
21916
+ );
21917
+ const refreshButtonDragVisuals = (0, import_react19.useCallback)((button, clientX, clientY) => {
21918
+ const collection = buttonCollectionOf(button);
21919
+ if (!collection) {
21920
+ setButtonDropSlots([]);
21921
+ setActiveButtonDropIndex(null);
21922
+ buttonDropInsertIndexRef.current = null;
21923
+ return;
21924
+ }
21925
+ const slots = buildButtonCollectionDropSlots(collection);
21926
+ const active = hitTestButtonCollectionDropSlot(collection, clientX, clientY);
21927
+ setButtonDropSlots(slots);
21928
+ const idx = active ? slots.findIndex((slot) => slot.insertIndex === active.insertIndex) : -1;
21929
+ setActiveButtonDropIndex(idx >= 0 ? idx : null);
21930
+ buttonDropInsertIndexRef.current = active?.insertIndex ?? null;
21931
+ setDraggedItemRect(button.getBoundingClientRect());
21932
+ if (selectedElRef.current === button) setToolbarRect(button.getBoundingClientRect());
21933
+ }, []);
21720
21934
  const handleItemDragStart = (0, import_react19.useCallback)(
21721
21935
  (e) => {
21722
21936
  const selected = selectedElRef.current;
@@ -21728,11 +21942,13 @@ function OhhwellsBridge() {
21728
21942
  const clientY = e?.clientY ?? selected.getBoundingClientRect().top + 8;
21729
21943
  if (isCtaButton(selected) && collectionDragEnabled(selected)) {
21730
21944
  buttonCollectionDragRef.current = selected;
21945
+ setMediaHover(null);
21731
21946
  if (e?.dataTransfer) {
21732
21947
  e.dataTransfer.effectAllowed = "move";
21733
21948
  e.dataTransfer.setData("text/plain", buttonId(selected) ?? "button");
21734
21949
  }
21735
21950
  setIsItemDragging(true);
21951
+ refreshButtonDragVisuals(selected, clientX, clientY);
21736
21952
  return;
21737
21953
  }
21738
21954
  if (startFooterLinkDrag(selected, clientX, clientY, true)) return;
@@ -21744,25 +21960,13 @@ function OhhwellsBridge() {
21744
21960
  setSiblingHintRect(null);
21745
21961
  setIsItemDragging(true);
21746
21962
  },
21747
- [startFooterColumnDrag, startFooterLinkDrag, startNavLinkDrag]
21963
+ [startFooterColumnDrag, startFooterLinkDrag, startNavLinkDrag, refreshButtonDragVisuals]
21748
21964
  );
21749
21965
  const handleItemDragEnd = (0, import_react19.useCallback)(
21750
21966
  (e) => {
21751
21967
  const collectionButton = buttonCollectionDragRef.current;
21752
21968
  if (collectionButton) {
21753
- const x = e?.clientX;
21754
- if (typeof x === "number" && x !== 0) reorderButtonInCollection(collectionButton, x);
21755
- const collection = buttonCollectionOf(collectionButton);
21756
- if (collection) {
21757
- const persisted = persistCollectionOrder(collection, editContentRef.current);
21758
- if (persisted) {
21759
- editContentRef.current = persisted.content;
21760
- postToParent2({ type: "ow:change", nodes: persisted.nodes });
21761
- }
21762
- }
21763
- buttonCollectionDragRef.current = null;
21764
- setIsItemDragging(false);
21765
- if (collectionButton.isConnected) setToolbarRect(collectionButton.getBoundingClientRect());
21969
+ persistButtonCollectionDrag(collectionButton, e?.clientX);
21766
21970
  return;
21767
21971
  }
21768
21972
  if (footerDragRef.current) {
@@ -21787,12 +21991,22 @@ function OhhwellsBridge() {
21787
21991
  }
21788
21992
  setIsItemDragging(false);
21789
21993
  },
21790
- [commitFooterDrag, commitNavDrag, navDragRef, postToParent2]
21994
+ [commitFooterDrag, commitNavDrag, navDragRef, persistButtonCollectionDrag]
21791
21995
  );
21792
21996
  const handleItemChromePointerDown = (0, import_react19.useCallback)((e) => {
21793
21997
  if (e.button !== 0) return;
21794
21998
  const selected = selectedElRef.current;
21795
21999
  if (!selected) return;
22000
+ if (isCtaButton(selected) && collectionDragEnabled(selected)) {
22001
+ buttonPointerDragRef.current = {
22002
+ el: selected,
22003
+ startX: e.clientX,
22004
+ startY: e.clientY,
22005
+ pointerId: e.pointerId,
22006
+ started: false
22007
+ };
22008
+ return;
22009
+ }
21796
22010
  const hrefKey = selected.getAttribute("data-ohw-href-key");
21797
22011
  if (hrefKey && isFooterHrefKey(hrefKey)) {
21798
22012
  footerPointerDragRef.current = {
@@ -22054,7 +22268,7 @@ function OhhwellsBridge() {
22054
22268
  if (!dragged) return;
22055
22269
  e.preventDefault();
22056
22270
  if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
22057
- reorderButtonInCollection(dragged, e.clientX);
22271
+ refreshButtonDragVisuals(dragged, e.clientX, e.clientY);
22058
22272
  };
22059
22273
  const onDrop = (e) => {
22060
22274
  if (!buttonCollectionDragRef.current) return;
@@ -22066,7 +22280,7 @@ function OhhwellsBridge() {
22066
22280
  document.removeEventListener("dragover", onDragOver);
22067
22281
  document.removeEventListener("drop", onDrop);
22068
22282
  };
22069
- }, []);
22283
+ }, [refreshButtonDragVisuals]);
22070
22284
  const isEditModeRef = (0, import_react19.useRef)(false);
22071
22285
  const requestMissingSocialIconsRef = (0, import_react19.useRef)(() => {
22072
22286
  });
@@ -22720,9 +22934,9 @@ function OhhwellsBridge() {
22720
22934
  }
22721
22935
  });
22722
22936
  document.querySelectorAll(
22723
- "nav [data-ohw-href-key], [data-ohw-nav-container] [data-ohw-href-key], [data-ohw-nav-drawer] [data-ohw-href-key]"
22937
+ 'nav [data-ohw-href-key], [data-ohw-nav-container] [data-ohw-href-key], [data-ohw-nav-drawer] [data-ohw-href-key], [data-ohw-role="navbar-button"]'
22724
22938
  ).forEach((el) => {
22725
- if (isNavbarHrefKey(el.getAttribute("data-ohw-href-key"))) {
22939
+ if (isNavbarHrefKey(el.getAttribute("data-ohw-href-key")) || isCtaButton(el)) {
22726
22940
  disableNativeHrefDrag(el);
22727
22941
  }
22728
22942
  });
@@ -23847,6 +24061,20 @@ function OhhwellsBridge() {
23847
24061
  }
23848
24062
  return;
23849
24063
  }
24064
+ const navbarCtaHit = findNavbarCtaAtPoint(x, y);
24065
+ if (navbarCtaHit) {
24066
+ hoveredNavContainerRef.current = null;
24067
+ setHoveredNavContainerRect(null);
24068
+ if (selected !== navbarCtaHit && !selected?.contains(navbarCtaHit)) {
24069
+ clearHrefKeyHover(navbarCtaHit);
24070
+ hoveredItemElRef.current = navbarCtaHit;
24071
+ setHoveredItemRect(navbarCtaHit.getBoundingClientRect());
24072
+ } else if (hoveredItemElRef.current === navbarCtaHit) {
24073
+ hoveredItemElRef.current = null;
24074
+ setHoveredItemRect(null);
24075
+ }
24076
+ return;
24077
+ }
23850
24078
  const navContainers = Array.from(
23851
24079
  document.querySelectorAll("[data-ohw-nav-container]")
23852
24080
  );
@@ -23949,6 +24177,24 @@ function OhhwellsBridge() {
23949
24177
  return;
23950
24178
  }
23951
24179
  const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
24180
+ if (!isDragOver) {
24181
+ const buttonHit = findButtonAtPoint(x, y);
24182
+ if (buttonHit) {
24183
+ dismissImageHover();
24184
+ if (findNavbarCtaAtPoint(x, y)) {
24185
+ probeNavigationHoverAt(x, y);
24186
+ return;
24187
+ }
24188
+ document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
24189
+ const selected = selectedElRef.current;
24190
+ if (selected !== buttonHit && !selected?.contains(buttonHit)) {
24191
+ clearHrefKeyHover(buttonHit);
24192
+ hoveredItemElRef.current = buttonHit;
24193
+ setHoveredItemRect(buttonHit.getBoundingClientRect());
24194
+ }
24195
+ return;
24196
+ }
24197
+ }
23952
24198
  if (isPointOverNavigation(x, y)) {
23953
24199
  dismissImageHover();
23954
24200
  probeNavigationHoverAt(x, y);
@@ -24383,6 +24629,11 @@ function OhhwellsBridge() {
24383
24629
  return;
24384
24630
  }
24385
24631
  if (onNavDragOver(e)) return;
24632
+ if (buttonCollectionDragRef.current) {
24633
+ e.preventDefault();
24634
+ if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
24635
+ return;
24636
+ }
24386
24637
  e.preventDefault();
24387
24638
  const el = findImageAtPoint(e.clientX, e.clientY, false);
24388
24639
  if (!el) {
@@ -24407,6 +24658,7 @@ function OhhwellsBridge() {
24407
24658
  };
24408
24659
  const handleDrop = (e) => {
24409
24660
  e.preventDefault();
24661
+ if (buttonCollectionDragRef.current || navDragRef.current || footerDragRef.current) return;
24410
24662
  const el = findImageAtPoint(e.clientX, e.clientY, false);
24411
24663
  if (!el) return;
24412
24664
  const file = e.dataTransfer?.files?.[0];
@@ -26064,6 +26316,97 @@ function OhhwellsBridge() {
26064
26316
  unlockFooterDragInteraction();
26065
26317
  };
26066
26318
  }, [isEditMode]);
26319
+ (0, import_react19.useEffect)(() => {
26320
+ if (!isEditMode) return;
26321
+ const THRESHOLD = 10;
26322
+ const onPointerDown = (e) => {
26323
+ if (e.button !== 0) return;
26324
+ if (buttonCollectionDragRef.current || navDragRef.current || footerDragRef.current) return;
26325
+ if (buttonPointerDragRef.current) return;
26326
+ const target = e.target;
26327
+ if (!target) return;
26328
+ if (target.closest(
26329
+ '[data-ohw-drag-handle-container], [data-slot="drag-handle"], [data-ohw-toolbar], [data-ohw-item-toolbar-anchor], [data-ohw-link-popover-root], [data-ohw-floating-panel]'
26330
+ )) {
26331
+ return;
26332
+ }
26333
+ const fromTarget = target.closest('[data-ohw-role="navbar-button"]');
26334
+ const anchor = (fromTarget && !fromTarget.closest("[data-ohw-bridge]") ? fromTarget : null) ?? findNavbarCtaAtPoint(e.clientX, e.clientY);
26335
+ if (!anchor || !collectionDragEnabled(anchor)) return;
26336
+ disableNativeHrefDrag(anchor);
26337
+ setMediaHover(null);
26338
+ buttonPointerDragRef.current = {
26339
+ el: anchor,
26340
+ startX: e.clientX,
26341
+ startY: e.clientY,
26342
+ pointerId: e.pointerId,
26343
+ started: false
26344
+ };
26345
+ };
26346
+ const onPointerMove = (e) => {
26347
+ const pending = buttonPointerDragRef.current;
26348
+ if (!pending) return;
26349
+ if (pending.started) {
26350
+ e.preventDefault();
26351
+ clearTextSelection();
26352
+ const dragged = buttonCollectionDragRef.current;
26353
+ if (!dragged) return;
26354
+ refreshButtonDragVisuals(dragged, e.clientX, e.clientY);
26355
+ return;
26356
+ }
26357
+ const dx = e.clientX - pending.startX;
26358
+ const dy = e.clientY - pending.startY;
26359
+ if (dx * dx + dy * dy < THRESHOLD * THRESHOLD) return;
26360
+ e.preventDefault();
26361
+ pending.started = true;
26362
+ armFooterPressDrag();
26363
+ clearTextSelection();
26364
+ try {
26365
+ document.body.setPointerCapture(pending.pointerId);
26366
+ } catch {
26367
+ }
26368
+ if (linkPopoverOpenRef.current) setLinkPopoverRef.current(null);
26369
+ if (activeElRef.current) deactivateRef.current();
26370
+ ensureNavbarButtonCollection(pending.el, editContentRef.current);
26371
+ buttonCollectionDragRef.current = pending.el;
26372
+ lockFooterDuringDrag();
26373
+ setIsItemDragging(true);
26374
+ refreshButtonDragVisuals(pending.el, e.clientX, e.clientY);
26375
+ };
26376
+ const endPointerDrag = (e) => {
26377
+ const pending = buttonPointerDragRef.current;
26378
+ buttonPointerDragRef.current = null;
26379
+ try {
26380
+ if (document.body.hasPointerCapture(e.pointerId)) {
26381
+ document.body.releasePointerCapture(e.pointerId);
26382
+ }
26383
+ } catch {
26384
+ }
26385
+ if (!pending) return;
26386
+ if (!pending.started) {
26387
+ unlockFooterDragInteraction();
26388
+ return;
26389
+ }
26390
+ suppressNextClickRef.current = true;
26391
+ suppressClickUntilRef.current = Date.now() + 500;
26392
+ persistButtonCollectionDrag(pending.el, e.clientX);
26393
+ };
26394
+ const blockSelectStart = (e) => {
26395
+ if (buttonCollectionDragRef.current || buttonPointerDragRef.current?.started) e.preventDefault();
26396
+ };
26397
+ document.addEventListener("pointerdown", onPointerDown, true);
26398
+ document.addEventListener("pointermove", onPointerMove, true);
26399
+ document.addEventListener("pointerup", endPointerDrag, true);
26400
+ document.addEventListener("pointercancel", endPointerDrag, true);
26401
+ document.addEventListener("selectstart", blockSelectStart, true);
26402
+ return () => {
26403
+ document.removeEventListener("pointerdown", onPointerDown, true);
26404
+ document.removeEventListener("pointermove", onPointerMove, true);
26405
+ document.removeEventListener("pointerup", endPointerDrag, true);
26406
+ document.removeEventListener("pointercancel", endPointerDrag, true);
26407
+ document.removeEventListener("selectstart", blockSelectStart, true);
26408
+ };
26409
+ }, [isEditMode, persistButtonCollectionDrag, refreshButtonDragVisuals]);
26067
26410
  (0, import_react19.useEffect)(() => {
26068
26411
  const handler = (e) => {
26069
26412
  if (e.data?.type !== "ow:request-schedule-config") return;
@@ -26717,7 +27060,7 @@ function OhhwellsBridge() {
26717
27060
  ),
26718
27061
  siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
26719
27062
  siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
26720
- isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
27063
+ isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && selectedElRef.current !== buttonCollectionDragRef.current && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
26721
27064
  isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
26722
27065
  "div",
26723
27066
  {
@@ -26760,6 +27103,27 @@ function OhhwellsBridge() {
26760
27103
  },
26761
27104
  `nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
26762
27105
  )),
27106
+ isItemDragging && buttonDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
27107
+ "div",
27108
+ {
27109
+ className: "pointer-events-none fixed z-2147483646",
27110
+ style: {
27111
+ left: slot.left,
27112
+ top: slot.top,
27113
+ width: slot.width,
27114
+ height: slot.height
27115
+ },
27116
+ children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
27117
+ DropIndicator,
27118
+ {
27119
+ direction: slot.direction,
27120
+ state: activeButtonDropIndex === i ? "dragActive" : "dragIdle",
27121
+ className: "!h-full !w-full"
27122
+ }
27123
+ )
27124
+ },
27125
+ `button-drop-${slot.direction}-${slot.insertIndex}-${i}`
27126
+ )),
26763
27127
  hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
26764
27128
  hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
26765
27129
  hoveredTextRect && !hoveredNavContainerRect && !hoveredItemRect && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ItemInteractionLayer, { rect: hoveredTextRect, state: "hover" }),
@@ -26928,7 +27292,7 @@ function OhhwellsBridge() {
26928
27292
  toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame" || toolbarVariant === "logo") && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
26929
27293
  ItemInteractionLayer,
26930
27294
  {
26931
- rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
27295
+ rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected || selectedElRef.current === buttonCollectionDragRef.current) ? draggedItemRect : toolbarRect,
26932
27296
  toolbarBelowRect: selectedElRef.current && isNavigationItem2(selectedElRef.current) ? getOpenNavDropdownPanelRect(selectedElRef.current) : null,
26933
27297
  toolbarBelowEl: selectedElRef.current && isNavigationItem2(selectedElRef.current) ? getOpenNavDropdownPanel(selectedElRef.current) : null,
26934
27298
  elRef: glowElRef,