@ohhwells/bridge 0.1.52 → 0.1.53

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  // src/OhhwellsBridge.tsx
4
- import React10, { useCallback as useCallback5, useEffect as useEffect9, useLayoutEffect as useLayoutEffect3, useRef as useRef7, useState as useState9 } from "react";
4
+ import React10, { useCallback as useCallback5, useEffect as useEffect10, useLayoutEffect as useLayoutEffect3, useRef as useRef7, useState as useState9 } from "react";
5
5
  import { createRoot } from "react-dom/client";
6
6
  import { flushSync } from "react-dom";
7
7
 
@@ -16,6 +16,9 @@ function getStoredLinkHref(key) {
16
16
  function clearStoredLinkHref(key) {
17
17
  linkHrefStore.delete(key);
18
18
  }
19
+ function listStoredLinkHrefs() {
20
+ return Array.from(linkHrefStore.entries());
21
+ }
19
22
  function enforceLinkHrefs() {
20
23
  document.querySelectorAll("[data-ohw-href-key]").forEach((el) => {
21
24
  const key = el.getAttribute("data-ohw-href-key") ?? "";
@@ -50,8 +53,40 @@ function useLinkHrefGuardian(...deps) {
50
53
  }, deps);
51
54
  }
52
55
 
56
+ // src/useSavedLinkNavigation.ts
57
+ import { useEffect } from "react";
58
+ import { useRouter } from "next/navigation";
59
+ function isRouterHref(href) {
60
+ return href.startsWith("/") || href.startsWith("#");
61
+ }
62
+ function shouldLetBrowserHandle(e, anchor) {
63
+ return e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || anchor.hasAttribute("download") || anchor.target !== "" && anchor.target !== "_self";
64
+ }
65
+ function useSavedLinkNavigation(isEditMode) {
66
+ const router = useRouter();
67
+ useEffect(() => {
68
+ if (isEditMode) return;
69
+ const onClick = (e) => {
70
+ const anchor = e.target?.closest(
71
+ "a[data-ohw-href-key]"
72
+ );
73
+ if (!anchor || shouldLetBrowserHandle(e, anchor)) return;
74
+ const key = anchor.getAttribute("data-ohw-href-key");
75
+ if (!key || getStoredLinkHref(key) === void 0) return;
76
+ const href = anchor.getAttribute("href");
77
+ if (!href) return;
78
+ e.preventDefault();
79
+ e.stopPropagation();
80
+ if (isRouterHref(href)) router.push(href);
81
+ else window.location.assign(href);
82
+ };
83
+ document.addEventListener("click", onClick, true);
84
+ return () => document.removeEventListener("click", onClick, true);
85
+ }, [isEditMode, router]);
86
+ }
87
+
53
88
  // src/ui/SchedulingWidget.tsx
54
- import { useCallback, useEffect, useId, useMemo, useRef, useState as useState2 } from "react";
89
+ import { useCallback, useEffect as useEffect2, useId, useMemo, useRef, useState as useState2 } from "react";
55
90
 
56
91
  // src/ui/EmailCaptureModal.tsx
57
92
  import { useState } from "react";
@@ -366,7 +401,7 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
366
401
  setCanScrollLeft(el.scrollLeft > 0);
367
402
  setCanScrollRight(el.scrollLeft + el.clientWidth < el.scrollWidth - 1);
368
403
  };
369
- useEffect(() => {
404
+ useEffect2(() => {
370
405
  const el = scrollRef.current;
371
406
  if (!el) return;
372
407
  updateScrollState();
@@ -624,7 +659,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
624
659
  });
625
660
  }, []);
626
661
  const [selectedIdx, setSelectedIdx] = useState2(0);
627
- useEffect(() => {
662
+ useEffect2(() => {
628
663
  if (!schedule?.classes) return;
629
664
  for (let i = 0; i < dates.length; i++) {
630
665
  if (schedule.classes.some((c) => classRunsOnDate(c, dates[i], schedule.type))) {
@@ -633,7 +668,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
633
668
  }
634
669
  }
635
670
  }, [schedule, dates]);
636
- useEffect(() => {
671
+ useEffect2(() => {
637
672
  if (typeof window === "undefined") return;
638
673
  const onVisible = () => {
639
674
  if (!document.hidden) void refetchLiveSchedule();
@@ -645,7 +680,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
645
680
  document.removeEventListener("visibilitychange", onVisible);
646
681
  };
647
682
  }, [refetchLiveSchedule]);
648
- useEffect(() => {
683
+ useEffect2(() => {
649
684
  if (typeof window === "undefined") return;
650
685
  const isInEditor = window.self !== window.top;
651
686
  setInEditor(isInEditor);
@@ -5240,7 +5275,43 @@ function CarouselOverlay({
5240
5275
 
5241
5276
  // src/OhhwellsBridge.tsx
5242
5277
  import { createPortal as createPortal2 } from "react-dom";
5243
- import { usePathname as usePathname2, useRouter as useRouter2, useSearchParams } from "next/navigation";
5278
+ import { usePathname as usePathname2, useRouter as useRouter3, useSearchParams } from "next/navigation";
5279
+
5280
+ // src/lib/cta-button.ts
5281
+ function isCtaButton(el) {
5282
+ return Boolean(
5283
+ el.closest('[data-ohw-role="navbar-button"], [data-ohw-role="button"]')
5284
+ );
5285
+ }
5286
+ var CTA_BUTTON_SELECTOR = '[data-ohw-role="navbar-button"], [data-ohw-role="button"]';
5287
+
5288
+ // src/lib/media-overlay-guards.ts
5289
+ var BRIDGE_CHROME_SELECTOR = [
5290
+ "[data-ohw-toolbar]",
5291
+ "[data-ohw-item-toolbar-anchor]",
5292
+ "[data-ohw-drag-handle-container]",
5293
+ '[data-slot="drag-handle"]',
5294
+ "[data-ohw-more-menu]",
5295
+ '[data-slot="dropdown-menu-content"]'
5296
+ ].join(", ");
5297
+ function containsPoint(el, x, y) {
5298
+ const r2 = el.getBoundingClientRect();
5299
+ if (r2.width <= 0 || r2.height <= 0) return false;
5300
+ return x >= r2.left && x <= r2.right && y >= r2.top && y <= r2.bottom;
5301
+ }
5302
+ function isPointOverBridgeChrome(x, y) {
5303
+ for (const el of document.querySelectorAll(BRIDGE_CHROME_SELECTOR)) {
5304
+ if (containsPoint(el, x, y)) return true;
5305
+ }
5306
+ return false;
5307
+ }
5308
+ function findCtaButtonAtPoint(x, y, media) {
5309
+ const hits = Array.from(
5310
+ document.querySelectorAll(CTA_BUTTON_SELECTOR)
5311
+ ).filter((el) => containsPoint(el, x, y) && !(media && el.contains(media)));
5312
+ if (hits.length === 0) return null;
5313
+ return hits.reduce((best, el) => best.contains(el) ? el : best);
5314
+ }
5244
5315
 
5245
5316
  // src/lib/session-search.ts
5246
5317
  var STORAGE_KEY = "ohw-preserved-search";
@@ -5518,7 +5589,7 @@ function scrollToHashSectionWhenReady(behavior = "smooth") {
5518
5589
  }
5519
5590
 
5520
5591
  // src/ui/link-modal/LinkPopover.tsx
5521
- import { useEffect as useEffect6 } from "react";
5592
+ import { useEffect as useEffect7 } from "react";
5522
5593
 
5523
5594
  // src/ui/dialog.tsx
5524
5595
  import * as React7 from "react";
@@ -5718,7 +5789,7 @@ function SectionTreeItem({
5718
5789
  }
5719
5790
 
5720
5791
  // src/ui/link-modal/UrlOrPageInput.tsx
5721
- import { useEffect as useEffect3, useId as useId2, useRef as useRef4, useState as useState4 } from "react";
5792
+ import { useEffect as useEffect4, useId as useId2, useRef as useRef4, useState as useState4 } from "react";
5722
5793
 
5723
5794
  // src/ui/input.tsx
5724
5795
  import * as React8 from "react";
@@ -5790,7 +5861,7 @@ function UrlOrPageInput({
5790
5861
  const inputRef = useRef4(null);
5791
5862
  const rootRef = useRef4(null);
5792
5863
  const [isFocused, setIsFocused] = useState4(false);
5793
- useEffect3(() => {
5864
+ useEffect4(() => {
5794
5865
  if (!dropdownOpen) return;
5795
5866
  const isOutside = (e) => {
5796
5867
  const root = rootRef.current;
@@ -5998,10 +6069,10 @@ function LinkEditorPanel({ state, onClose }) {
5998
6069
  }
5999
6070
 
6000
6071
  // src/ui/link-modal/SectionPickerOverlay.tsx
6001
- import { useCallback as useCallback2, useEffect as useEffect4, useMemo as useMemo2, useRef as useRef5, useState as useState5 } from "react";
6072
+ import { useCallback as useCallback2, useEffect as useEffect5, useMemo as useMemo2, useRef as useRef5, useState as useState5 } from "react";
6002
6073
  import { createPortal } from "react-dom";
6003
6074
  import { ArrowLeft, Check } from "lucide-react";
6004
- import { usePathname, useRouter } from "next/navigation";
6075
+ import { usePathname, useRouter as useRouter2 } from "next/navigation";
6005
6076
  import { jsx as jsx21, jsxs as jsxs12 } from "react/jsx-runtime";
6006
6077
  var DIM_OVERLAY = "rgba(0, 0, 0, 0.45)";
6007
6078
  function rectsEqual(a, b) {
@@ -6040,7 +6111,7 @@ function useSectionRects(sectionIdsKey, enabled) {
6040
6111
  () => sectionIdsKey ? sectionIdsKey.split("\0") : [],
6041
6112
  [sectionIdsKey]
6042
6113
  );
6043
- useEffect4(() => {
6114
+ useEffect5(() => {
6044
6115
  if (!enabled || sectionIds.length === 0) {
6045
6116
  setRects((prev) => prev.size === 0 ? prev : /* @__PURE__ */ new Map());
6046
6117
  return;
@@ -6079,7 +6150,7 @@ function SectionPickerOverlay({
6079
6150
  onBack,
6080
6151
  onSelect
6081
6152
  }) {
6082
- const router = useRouter();
6153
+ const router = useRouter2();
6083
6154
  const pathname = usePathname();
6084
6155
  const [selectedId, setSelectedId] = useState5(null);
6085
6156
  const [hoveredId, setHoveredId] = useState5(null);
@@ -6095,12 +6166,12 @@ function SectionPickerOverlay({
6095
6166
  );
6096
6167
  const normalizedTarget = normalizePath(pagePath);
6097
6168
  const isOnTargetPage = normalizePath(pathname) === normalizedTarget;
6098
- useEffect4(() => {
6169
+ useEffect5(() => {
6099
6170
  if (isOnTargetPage) return;
6100
6171
  const search = readPreservedSearch();
6101
6172
  router.push(`${normalizedTarget}${search}`);
6102
6173
  }, [isOnTargetPage, normalizedTarget, router]);
6103
- useEffect4(() => {
6174
+ useEffect5(() => {
6104
6175
  document.documentElement.setAttribute("data-ohw-section-picking", "");
6105
6176
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => {
6106
6177
  el.removeAttribute("data-ohw-hovered");
@@ -6138,7 +6209,7 @@ function SectionPickerOverlay({
6138
6209
  },
6139
6210
  []
6140
6211
  );
6141
- useEffect4(() => {
6212
+ useEffect5(() => {
6142
6213
  const applyClip = (iframeOffsetTop, visibleCanvasTop, canvasH) => {
6143
6214
  const top = Math.max(0, visibleCanvasTop - iframeOffsetTop);
6144
6215
  const bottom = Math.min(
@@ -6180,12 +6251,12 @@ function SectionPickerOverlay({
6180
6251
  window.removeEventListener("resize", onResize);
6181
6252
  };
6182
6253
  }, [applyHoverAt]);
6183
- useEffect4(() => {
6254
+ useEffect5(() => {
6184
6255
  const ptr = pointerRef.current;
6185
6256
  if (!ptr) return;
6186
6257
  applyHoverAt(ptr.x, ptr.y, rects);
6187
6258
  }, [rects, applyHoverAt]);
6188
- useEffect4(() => {
6259
+ useEffect5(() => {
6189
6260
  const rememberPointer = (clientX, clientY) => {
6190
6261
  pointerRef.current = { x: clientX, y: clientY };
6191
6262
  const top = iframeOffsetTopRef.current;
@@ -6217,7 +6288,7 @@ function SectionPickerOverlay({
6217
6288
  },
6218
6289
  [selectedId, onSelect]
6219
6290
  );
6220
- useEffect4(() => {
6291
+ useEffect5(() => {
6221
6292
  const onKeyDown = (e) => {
6222
6293
  if (e.key === "Escape") {
6223
6294
  e.preventDefault();
@@ -6340,7 +6411,7 @@ function SectionPickerOverlay({
6340
6411
  }
6341
6412
 
6342
6413
  // src/ui/link-modal/useLinkModalState.ts
6343
- import { useCallback as useCallback3, useEffect as useEffect5, useMemo as useMemo3, useState as useState6 } from "react";
6414
+ import { useCallback as useCallback3, useEffect as useEffect6, useMemo as useMemo3, useState as useState6 } from "react";
6344
6415
  function useLinkModalState({
6345
6416
  open,
6346
6417
  mode,
@@ -6367,7 +6438,7 @@ function useLinkModalState({
6367
6438
  setDropdownOpen(false);
6368
6439
  setUrlError("");
6369
6440
  }, []);
6370
- useEffect5(() => {
6441
+ useEffect6(() => {
6371
6442
  if (!open) return;
6372
6443
  if (mode === "edit" && initialTarget) {
6373
6444
  const { pageRoute } = parseTarget(initialTarget);
@@ -6533,7 +6604,7 @@ function LinkPopover({
6533
6604
  onSubmit
6534
6605
  });
6535
6606
  const sectionPickerActive = state.showSectionPicker && Boolean(state.selectedPage);
6536
- useEffect6(() => {
6607
+ useEffect7(() => {
6537
6608
  if (!open) return;
6538
6609
  if (sectionPickerActive) {
6539
6610
  postToParent({ type: "ui:unlock" });
@@ -6861,12 +6932,9 @@ function getLinkHref(el) {
6861
6932
  }
6862
6933
  return el.getAttribute("href") ?? "";
6863
6934
  }
6864
- function isNavbarButton(el) {
6865
- return el.hasAttribute("data-ohw-role") && el.getAttribute("data-ohw-role") === "navbar-button";
6866
- }
6867
6935
  function isNavbarLinkItem(el) {
6868
6936
  if (!el.matches("[data-ohw-href-key]")) return false;
6869
- if (isNavbarButton(el)) return false;
6937
+ if (isCtaButton(el)) return false;
6870
6938
  if (!el.querySelector('[data-ohw-editable="text"]')) return false;
6871
6939
  return Boolean(el.closest("nav, [data-ohw-nav-container], [data-ohw-nav-drawer]"));
6872
6940
  }
@@ -6947,7 +7015,7 @@ function buildNavLink(index, href, label, template) {
6947
7015
  }
6948
7016
  function insertNavLinkInContainer(container, anchor, afterHrefKey) {
6949
7017
  if (!afterHrefKey) {
6950
- const cta = container.querySelector('[data-ohw-role="navbar-button"]');
7018
+ const cta = container.querySelector(CTA_BUTTON_SELECTOR);
6951
7019
  if (cta && cta.parentElement === container) {
6952
7020
  container.insertBefore(anchor, cta);
6953
7021
  return;
@@ -8828,7 +8896,7 @@ function hitTestNavDropSlot(clientX, clientY, draggedHrefKey) {
8828
8896
  }
8829
8897
 
8830
8898
  // src/useNavItemDrag.ts
8831
- import { useCallback as useCallback4, useEffect as useEffect7, useRef as useRef6, useState as useState7 } from "react";
8899
+ import { useCallback as useCallback4, useEffect as useEffect8, useRef as useRef6, useState as useState7 } from "react";
8832
8900
  function useNavItemDrag({
8833
8901
  isEditMode,
8834
8902
  editContentRef,
@@ -8850,8 +8918,7 @@ function useNavItemDrag({
8850
8918
  setSiblingHintRects,
8851
8919
  setToolbarRect,
8852
8920
  getNavigationItemAnchor: getNavigationItemAnchor2,
8853
- isDragHandleDisabled: isDragHandleDisabled2,
8854
- isNavbarButton: isNavbarButton3
8921
+ isDragHandleDisabled: isDragHandleDisabled2
8855
8922
  }) {
8856
8923
  const navDragRef = useRef6(null);
8857
8924
  const [navDropSlots, setNavDropSlots] = useState7([]);
@@ -8998,7 +9065,7 @@ function useNavItemDrag({
8998
9065
  if (footerDragRef.current) return false;
8999
9066
  const hrefKey = anchor.getAttribute("data-ohw-href-key");
9000
9067
  if (!hrefKey || !isNavbarHrefKey(hrefKey)) return false;
9001
- if (isNavbarButton3(anchor) || isDragHandleDisabled2(anchor)) return false;
9068
+ if (isCtaButton(anchor) || isDragHandleDisabled2(anchor)) return false;
9002
9069
  beginNavDrag({
9003
9070
  hrefKey,
9004
9071
  wasSelected,
@@ -9009,7 +9076,7 @@ function useNavItemDrag({
9009
9076
  });
9010
9077
  return true;
9011
9078
  },
9012
- [beginNavDrag, footerDragRef, isDragHandleDisabled2, isNavbarButton3]
9079
+ [beginNavDrag, footerDragRef, isDragHandleDisabled2, isCtaButton]
9013
9080
  );
9014
9081
  const onNavDragOver = useCallback4(
9015
9082
  (e) => {
@@ -9023,7 +9090,7 @@ function useNavItemDrag({
9023
9090
  },
9024
9091
  []
9025
9092
  );
9026
- useEffect7(() => {
9093
+ useEffect8(() => {
9027
9094
  if (!isEditMode) return;
9028
9095
  const THRESHOLD = 10;
9029
9096
  const resolveWasSelected = (el) => {
@@ -9045,7 +9112,7 @@ function useNavItemDrag({
9045
9112
  const anchor = getNavigationItemAnchor2(target);
9046
9113
  const hrefKey = anchor?.getAttribute("data-ohw-href-key") ?? null;
9047
9114
  if (!anchor || !isNavbarHrefKey(hrefKey)) return;
9048
- if (isNavbarButton3(anchor) || isDragHandleDisabled2(anchor)) return;
9115
+ if (isCtaButton(anchor) || isDragHandleDisabled2(anchor)) return;
9049
9116
  navPointerDragRef.current = {
9050
9117
  el: anchor,
9051
9118
  startX: e.clientX,
@@ -9142,7 +9209,7 @@ function useNavItemDrag({
9142
9209
  getNavigationItemAnchor2,
9143
9210
  isDragHandleDisabled2,
9144
9211
  isEditMode,
9145
- isNavbarButton3,
9212
+ isCtaButton,
9146
9213
  linkPopoverOpenRef,
9147
9214
  selectedElRef,
9148
9215
  setLinkPopover,
@@ -9152,7 +9219,7 @@ function useNavItemDrag({
9152
9219
  (selected, clientX, clientY, pointerId) => {
9153
9220
  const hrefKey = selected.getAttribute("data-ohw-href-key");
9154
9221
  if (!hrefKey || !isNavbarHrefKey(hrefKey)) return false;
9155
- if (isNavbarButton3(selected) || isDragHandleDisabled2(selected)) return false;
9222
+ if (isCtaButton(selected) || isDragHandleDisabled2(selected)) return false;
9156
9223
  navPointerDragRef.current = {
9157
9224
  el: selected,
9158
9225
  startX: clientX,
@@ -9163,7 +9230,7 @@ function useNavItemDrag({
9163
9230
  };
9164
9231
  return true;
9165
9232
  },
9166
- [isDragHandleDisabled2, isNavbarButton3]
9233
+ [isDragHandleDisabled2, isCtaButton]
9167
9234
  );
9168
9235
  return {
9169
9236
  navDragRef,
@@ -9230,7 +9297,7 @@ function FooterContainerChrome({
9230
9297
  }
9231
9298
 
9232
9299
  // src/lib/carousel.ts
9233
- import { useEffect as useEffect8, useState as useState8 } from "react";
9300
+ import { useEffect as useEffect9, useState as useState8 } from "react";
9234
9301
  var CAROUSEL_ATTR = "data-ohw-carousel";
9235
9302
  var CAROUSEL_VALUE_ATTR = "data-ohw-carousel-value";
9236
9303
  var CAROUSEL_SLIDE_ATTR = "data-ohw-carousel-slide";
@@ -9293,7 +9360,7 @@ function applyCarouselNode(key, val) {
9293
9360
  }
9294
9361
  function useOhwCarousel(key, initial) {
9295
9362
  const [images, setImages] = useState8(initial);
9296
- useEffect8(() => {
9363
+ useEffect9(() => {
9297
9364
  const el = document.querySelector(
9298
9365
  `[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`
9299
9366
  );
@@ -9358,6 +9425,9 @@ function collectEditableNodes(extraContent) {
9358
9425
  if (!key) return;
9359
9426
  nodes.push({ key, type: "link", text: getLinkHref3(el) });
9360
9427
  });
9428
+ for (const [key, href] of listStoredLinkHrefs()) {
9429
+ nodes.push({ key, type: "link", text: href });
9430
+ }
9361
9431
  if (extraContent) {
9362
9432
  for (const key of [NAV_ORDER_KEY, FOOTER_ORDER_KEY, NAV_COUNT_KEY]) {
9363
9433
  const text = extraContent[key];
@@ -10086,9 +10156,6 @@ function getHrefKeyFromElement(el) {
10086
10156
  if (!key) return null;
10087
10157
  return { anchor, key };
10088
10158
  }
10089
- function isNavbarButton2(el) {
10090
- return Boolean(el.closest('[data-ohw-role="navbar-button"]'));
10091
- }
10092
10159
  function isNavDropdownPanelOpen(childrenRoot) {
10093
10160
  if (childrenRoot.closest("[data-ohw-nav-drawer]")) return true;
10094
10161
  const group = childrenRoot.closest("[data-ohw-nav-group]");
@@ -10141,7 +10208,7 @@ function listNavigationItems() {
10141
10208
  ).filter((el) => isNavigationItem2(el));
10142
10209
  }
10143
10210
  function getNavigationItemReorderState(anchor) {
10144
- if (isNavbarButton2(anchor)) return { key: null, disabled: false };
10211
+ if (isCtaButton(anchor)) return { key: null, disabled: false };
10145
10212
  return getReorderHandleStateFromAnchor(anchor);
10146
10213
  }
10147
10214
  function getReorderHandleState(el) {
@@ -10243,7 +10310,7 @@ function findHoveredNavOrFooterContainer(x, y) {
10243
10310
  }
10244
10311
  function isPointOverNavItem(container, x, y) {
10245
10312
  return Array.from(container.querySelectorAll("[data-ohw-href-key]")).some((el) => {
10246
- if (!isNavigationItem2(el) || isNavbarButton2(el)) return false;
10313
+ if (!isNavigationItem2(el) || isCtaButton(el)) return false;
10247
10314
  if (!isNavItemPointerTarget(el)) return false;
10248
10315
  const itemRect = el.getBoundingClientRect();
10249
10316
  return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
@@ -10257,7 +10324,7 @@ function isPointOverFooterColumn(x, y) {
10257
10324
  }
10258
10325
  function resolveNavContainerSelectionTarget(target, clientX, clientY) {
10259
10326
  if (getNavigationItemAnchor(target)) return null;
10260
- if (target.closest('[data-ohw-role="navbar-button"]')) return null;
10327
+ if (target.closest(CTA_BUTTON_SELECTOR)) return null;
10261
10328
  const plainLink = target.closest("a");
10262
10329
  if (plainLink && !plainLink.hasAttribute("data-ohw-href-key") && !plainLink.closest("[data-ohw-nav-container]")) {
10263
10330
  return null;
@@ -10899,11 +10966,11 @@ function resolveSubdomain(subdomainFromQuery) {
10899
10966
  }
10900
10967
  function OhhwellsBridge() {
10901
10968
  const pathname = usePathname2();
10902
- const router = useRouter2();
10969
+ const router = useRouter3();
10903
10970
  const searchParams = useSearchParams();
10904
10971
  const isEditMode = isEditSessionActive();
10905
10972
  const [bridgeRoot, setBridgeRoot] = useState9(null);
10906
- useEffect9(() => {
10973
+ useEffect10(() => {
10907
10974
  const figtreeFontId = "ohw-figtree-font";
10908
10975
  if (!document.getElementById(figtreeFontId)) {
10909
10976
  const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
@@ -10931,6 +10998,7 @@ function OhhwellsBridge() {
10931
10998
  const subdomainFromQuery = searchParams.get("subdomain");
10932
10999
  const subdomain = resolveSubdomain(subdomainFromQuery);
10933
11000
  useLinkHrefGuardian(pathname, subdomain, isEditMode);
11001
+ useSavedLinkNavigation(isEditMode);
10934
11002
  const postToParent2 = useCallback5((data) => {
10935
11003
  if (typeof window !== "undefined" && window.parent !== window) {
10936
11004
  window.parent.postMessage(data, "*");
@@ -11063,8 +11131,7 @@ function OhhwellsBridge() {
11063
11131
  setSiblingHintRects,
11064
11132
  setToolbarRect,
11065
11133
  getNavigationItemAnchor,
11066
- isDragHandleDisabled,
11067
- isNavbarButton: isNavbarButton2
11134
+ isDragHandleDisabled
11068
11135
  });
11069
11136
  const bumpLinkPopoverGrace = () => {
11070
11137
  linkPopoverGraceUntilRef.current = Date.now() + 350;
@@ -11090,7 +11157,7 @@ function OhhwellsBridge() {
11090
11157
  }, [isEditMode, pathname]);
11091
11158
  const runSectionsPrefetchRef = useRef7(runSectionsPrefetch);
11092
11159
  runSectionsPrefetchRef.current = runSectionsPrefetch;
11093
- useEffect9(() => {
11160
+ useEffect10(() => {
11094
11161
  if (!linkPopover) {
11095
11162
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
11096
11163
  return;
@@ -11118,7 +11185,7 @@ function OhhwellsBridge() {
11118
11185
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
11119
11186
  };
11120
11187
  }, [linkPopover, postToParent2]);
11121
- useEffect9(() => {
11188
+ useEffect10(() => {
11122
11189
  if (!isEditMode) return;
11123
11190
  const useFixtures = shouldUseDevFixtures();
11124
11191
  if (useFixtures) {
@@ -11142,14 +11209,14 @@ function OhhwellsBridge() {
11142
11209
  if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
11143
11210
  return () => window.removeEventListener("message", onSitePages);
11144
11211
  }, [isEditMode, postToParent2]);
11145
- useEffect9(() => {
11212
+ useEffect10(() => {
11146
11213
  if (!isEditMode || shouldUseDevFixtures()) return;
11147
11214
  void loadAllSectionsManifest().then((manifest) => {
11148
11215
  if (Object.keys(manifest).length === 0) return;
11149
11216
  setSectionsByPath((prev) => ({ ...manifest, ...prev }));
11150
11217
  });
11151
11218
  }, [isEditMode]);
11152
- useEffect9(() => {
11219
+ useEffect10(() => {
11153
11220
  const update = () => {
11154
11221
  const el = activeElRef.current ?? selectedElRef.current;
11155
11222
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
@@ -11322,7 +11389,7 @@ function OhhwellsBridge() {
11322
11389
  selectedHrefKeyRef.current = navAnchor.getAttribute("data-ohw-href-key");
11323
11390
  selectedFooterColAttrRef.current = null;
11324
11391
  markSelected(navAnchor);
11325
- setSelectedIsCta(isNavbarButton2(navAnchor));
11392
+ setSelectedIsCta(isCtaButton(navAnchor));
11326
11393
  const isDropdownTrigger = !isNestedNavChild(navAnchor) && (navItemHasDropdownChildren(navAnchor) || navItemOwnsDropdownPanel(navAnchor));
11327
11394
  if (isNestedNavChild(navAnchor)) {
11328
11395
  setNavGroupForceOpen(navAnchor, true);
@@ -11842,7 +11909,7 @@ function OhhwellsBridge() {
11842
11909
  selectedHrefKeyRef.current = anchor.getAttribute("data-ohw-href-key");
11843
11910
  selectedFooterColAttrRef.current = null;
11844
11911
  markSelected(anchor);
11845
- setSelectedIsCta(isNavbarButton2(anchor));
11912
+ setSelectedIsCta(isCtaButton(anchor));
11846
11913
  clearHrefKeyHover(anchor);
11847
11914
  const isDropdownTrigger = !isNestedNavChild(anchor) && (navItemHasDropdownChildren(anchor) || navItemOwnsDropdownPanel(anchor));
11848
11915
  if (isNestedNavChild(anchor)) {
@@ -12059,7 +12126,7 @@ function OhhwellsBridge() {
12059
12126
  cancelled = true;
12060
12127
  };
12061
12128
  }, [subdomain, isEditMode]);
12062
- useEffect9(() => {
12129
+ useEffect10(() => {
12063
12130
  if (!subdomain || isEditMode) return;
12064
12131
  let debounceTimer = null;
12065
12132
  let observer = null;
@@ -12116,10 +12183,10 @@ function OhhwellsBridge() {
12116
12183
  const visible = Boolean(subdomain) && fetchState !== "done";
12117
12184
  el.style.display = visible ? "flex" : "none";
12118
12185
  }, [subdomain, fetchState]);
12119
- useEffect9(() => {
12186
+ useEffect10(() => {
12120
12187
  postToParent2({ type: "ow:navigation", path: pathname });
12121
12188
  }, [pathname, postToParent2]);
12122
- useEffect9(() => {
12189
+ useEffect10(() => {
12123
12190
  if (!isEditMode) return;
12124
12191
  if (linkPopoverSessionRef.current?.intent === "add-nav") return;
12125
12192
  if (document.querySelector("[data-ohw-section-picker]")) return;
@@ -12127,7 +12194,7 @@ function OhhwellsBridge() {
12127
12194
  deselectRef.current();
12128
12195
  deactivateRef.current();
12129
12196
  }, [pathname, isEditMode]);
12130
- useEffect9(() => {
12197
+ useEffect10(() => {
12131
12198
  const contentForNav = () => {
12132
12199
  if (isEditMode) return editContentRef.current;
12133
12200
  if (!subdomain) return {};
@@ -12192,7 +12259,7 @@ function OhhwellsBridge() {
12192
12259
  observer?.disconnect();
12193
12260
  };
12194
12261
  }, [isEditMode, pathname, subdomain, fetchState, resyncSelectedNavigationItem]);
12195
- useEffect9(() => {
12262
+ useEffect10(() => {
12196
12263
  if (!isEditMode) return;
12197
12264
  const measure = () => {
12198
12265
  const h = document.body.scrollHeight;
@@ -12216,7 +12283,7 @@ function OhhwellsBridge() {
12216
12283
  window.removeEventListener("resize", handleResize);
12217
12284
  };
12218
12285
  }, [pathname, isEditMode, postToParent2]);
12219
- useEffect9(() => {
12286
+ useEffect10(() => {
12220
12287
  if (!subdomainFromQuery || isEditMode) return;
12221
12288
  const handleClick = (e) => {
12222
12289
  const anchor = e.target.closest("a");
@@ -12232,7 +12299,7 @@ function OhhwellsBridge() {
12232
12299
  document.addEventListener("click", handleClick, true);
12233
12300
  return () => document.removeEventListener("click", handleClick, true);
12234
12301
  }, [subdomainFromQuery, isEditMode, router]);
12235
- useEffect9(() => {
12302
+ useEffect10(() => {
12236
12303
  if (!isEditMode) {
12237
12304
  editStylesRef.current?.base.remove();
12238
12305
  editStylesRef.current?.forceHover.remove();
@@ -12818,7 +12885,7 @@ function OhhwellsBridge() {
12818
12885
  const navItemHit = Array.from(
12819
12886
  container.querySelectorAll("[data-ohw-href-key]")
12820
12887
  ).filter((el) => {
12821
- if (!isNavigationItem2(el) || isNavbarButton2(el)) return false;
12888
+ if (!isNavigationItem2(el) || isCtaButton(el)) return false;
12822
12889
  if (!isNavItemPointerTarget(el)) return false;
12823
12890
  const itemRect = el.getBoundingClientRect();
12824
12891
  return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
@@ -12960,6 +13027,22 @@ function OhhwellsBridge() {
12960
13027
  }
12961
13028
  return;
12962
13029
  }
13030
+ if (!isDragOver && isPointOverBridgeChrome(x2, y2)) {
13031
+ dismissImageHover();
13032
+ return;
13033
+ }
13034
+ const ctaHit = isDragOver ? null : findCtaButtonAtPoint(x2, y2, imgEl);
13035
+ if (ctaHit) {
13036
+ dismissImageHover();
13037
+ document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
13038
+ const selected = selectedElRef.current;
13039
+ if (selected !== ctaHit && !selected?.contains(ctaHit)) {
13040
+ clearHrefKeyHover(ctaHit);
13041
+ hoveredItemElRef.current = ctaHit;
13042
+ setHoveredItemRect(ctaHit.getBoundingClientRect());
13043
+ }
13044
+ return;
13045
+ }
12963
13046
  const topEl = document.elementFromPoint(x2, y2);
12964
13047
  if (topEl?.closest('[data-ohw-toolbar], [data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"], [data-ohw-more-menu], [data-slot="dropdown-menu-content"], [data-slot="dropdown-menu-item"]')) {
12965
13048
  if (hoveredImageRef.current) {
@@ -13083,7 +13166,7 @@ function OhhwellsBridge() {
13083
13166
  const navLinkHit = Array.from(
13084
13167
  document.querySelectorAll("nav [data-ohw-href-key], footer [data-ohw-href-key]")
13085
13168
  ).find((el) => {
13086
- if (!isNavigationItem2(el) || isNavbarButton2(el)) return false;
13169
+ if (!isNavigationItem2(el) || isCtaButton(el)) return false;
13087
13170
  if (!isNavItemPointerTarget(el)) return false;
13088
13171
  const er = el.getBoundingClientRect();
13089
13172
  return x2 >= er.left && x2 <= er.right && y2 >= er.top && y2 <= er.bottom;
@@ -13902,7 +13985,7 @@ function OhhwellsBridge() {
13902
13985
  if (navRoot && navContainer) {
13903
13986
  const rr = navRoot.getBoundingClientRect();
13904
13987
  if (clientX >= rr.left && clientX <= rr.right && clientY >= rr.top && clientY <= rr.bottom && !isPointOverNavItem(navContainer, clientX, clientY)) {
13905
- const book = navRoot.querySelector('[data-ohw-role="navbar-button"]');
13988
+ const book = navRoot.querySelector(CTA_BUTTON_SELECTOR);
13906
13989
  if (book) {
13907
13990
  const br = book.getBoundingClientRect();
13908
13991
  if (clientX >= br.left && clientX <= br.right && clientY >= br.top && clientY <= br.bottom) {
@@ -13995,7 +14078,7 @@ function OhhwellsBridge() {
13995
14078
  if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
13996
14079
  };
13997
14080
  }, [isEditMode, refreshStateRules]);
13998
- useEffect9(() => {
14081
+ useEffect10(() => {
13999
14082
  if (!isEditMode) return;
14000
14083
  const THRESHOLD = 10;
14001
14084
  const resolveWasSelected = (el) => {
@@ -14149,7 +14232,7 @@ function OhhwellsBridge() {
14149
14232
  unlockFooterDragInteraction();
14150
14233
  };
14151
14234
  }, [isEditMode]);
14152
- useEffect9(() => {
14235
+ useEffect10(() => {
14153
14236
  const handler = (e) => {
14154
14237
  if (e.data?.type !== "ow:request-schedule-config") return;
14155
14238
  const insertAfterVal = e.data.insertAfter;
@@ -14165,7 +14248,7 @@ function OhhwellsBridge() {
14165
14248
  window.addEventListener("message", handler);
14166
14249
  return () => window.removeEventListener("message", handler);
14167
14250
  }, [processConfigRequest]);
14168
- useEffect9(() => {
14251
+ useEffect10(() => {
14169
14252
  if (!isEditMode) return;
14170
14253
  document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
14171
14254
  el.removeAttribute("data-ohw-active-state");
@@ -14200,7 +14283,7 @@ function OhhwellsBridge() {
14200
14283
  clearTimeout(timer);
14201
14284
  };
14202
14285
  }, [pathname, isEditMode, refreshStateRules, postToParent2]);
14203
- useEffect9(() => {
14286
+ useEffect10(() => {
14204
14287
  scrollToHashSectionWhenReady();
14205
14288
  const onHashChange = () => scrollToHashSectionWhenReady();
14206
14289
  window.addEventListener("hashchange", onHashChange);
@@ -14494,6 +14577,7 @@ function OhhwellsBridge() {
14494
14577
  return;
14495
14578
  }
14496
14579
  const { key } = session;
14580
+ setStoredLinkHref(key, target);
14497
14581
  applyLinkByKey(key, target);
14498
14582
  editContentRef.current = { ...editContentRef.current, [key]: target };
14499
14583
  postToParent2({ type: "ow:change", nodes: [{ key, text: target }] });