@ohhwells/bridge 0.1.31 → 0.1.32

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
@@ -49,15 +49,54 @@ __export(index_exports, {
49
49
  module.exports = __toCommonJS(index_exports);
50
50
 
51
51
  // src/OhhwellsBridge.tsx
52
- var import_react5 = __toESM(require("react"), 1);
52
+ var import_react6 = __toESM(require("react"), 1);
53
53
  var import_client = require("react-dom/client");
54
54
  var import_react_dom = require("react-dom");
55
55
 
56
+ // src/linkHrefStore.ts
57
+ var linkHrefStore = /* @__PURE__ */ new Map();
58
+ function setStoredLinkHref(key, href) {
59
+ linkHrefStore.set(key, href);
60
+ }
61
+ function enforceLinkHrefs() {
62
+ document.querySelectorAll("[data-ohw-href-key]").forEach((el) => {
63
+ const key = el.getAttribute("data-ohw-href-key") ?? "";
64
+ if (!key) return;
65
+ const saved = linkHrefStore.get(key);
66
+ if (saved === void 0) return;
67
+ if (el.getAttribute("href") !== saved) el.setAttribute("href", saved);
68
+ });
69
+ }
70
+
71
+ // src/useLinkHrefGuardian.ts
72
+ var import_react = require("react");
73
+ function useLinkHrefGuardian(...deps) {
74
+ (0, import_react.useLayoutEffect)(() => {
75
+ let debounceTimer = null;
76
+ const scheduleEnforce = () => {
77
+ if (debounceTimer) clearTimeout(debounceTimer);
78
+ debounceTimer = setTimeout(enforceLinkHrefs, 50);
79
+ };
80
+ enforceLinkHrefs();
81
+ const observer = new MutationObserver(scheduleEnforce);
82
+ observer.observe(document.body, {
83
+ childList: true,
84
+ subtree: true,
85
+ attributes: true,
86
+ attributeFilter: ["href"]
87
+ });
88
+ return () => {
89
+ observer.disconnect();
90
+ if (debounceTimer) clearTimeout(debounceTimer);
91
+ };
92
+ }, deps);
93
+ }
94
+
56
95
  // src/ui/SchedulingWidget.tsx
57
- var import_react2 = require("react");
96
+ var import_react3 = require("react");
58
97
 
59
98
  // src/ui/EmailCaptureModal.tsx
60
- var import_react = require("react");
99
+ var import_react2 = require("react");
61
100
  var import_radix_ui = require("radix-ui");
62
101
  var import_jsx_runtime = require("react/jsx-runtime");
63
102
  function Spinner() {
@@ -86,11 +125,11 @@ function Spinner() {
86
125
  );
87
126
  }
88
127
  function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
89
- const [email, setEmail] = (0, import_react.useState)("");
90
- const [submittedEmail, setSubmittedEmail] = (0, import_react.useState)("");
91
- const [loading, setLoading] = (0, import_react.useState)(false);
92
- const [success, setSuccess] = (0, import_react.useState)(false);
93
- const [error, setError] = (0, import_react.useState)(null);
128
+ const [email, setEmail] = (0, import_react2.useState)("");
129
+ const [submittedEmail, setSubmittedEmail] = (0, import_react2.useState)("");
130
+ const [loading, setLoading] = (0, import_react2.useState)(false);
131
+ const [success, setSuccess] = (0, import_react2.useState)(false);
132
+ const [error, setError] = (0, import_react2.useState)(null);
94
133
  const isBook = title === "Confirm your spot";
95
134
  const handleSubmit = async () => {
96
135
  if (!email.trim()) return;
@@ -338,21 +377,21 @@ function LoadingSkeleton() {
338
377
  ] });
339
378
  }
340
379
  function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal }) {
341
- const todayMs = (0, import_react2.useMemo)(() => {
380
+ const todayMs = (0, import_react3.useMemo)(() => {
342
381
  const d = /* @__PURE__ */ new Date();
343
382
  d.setHours(0, 0, 0, 0);
344
383
  return d.getTime();
345
384
  }, []);
346
- const scrollRef = (0, import_react2.useRef)(null);
347
- const [canScrollLeft, setCanScrollLeft] = (0, import_react2.useState)(false);
348
- const [canScrollRight, setCanScrollRight] = (0, import_react2.useState)(false);
385
+ const scrollRef = (0, import_react3.useRef)(null);
386
+ const [canScrollLeft, setCanScrollLeft] = (0, import_react3.useState)(false);
387
+ const [canScrollRight, setCanScrollRight] = (0, import_react3.useState)(false);
349
388
  const updateScrollState = () => {
350
389
  const el = scrollRef.current;
351
390
  if (!el) return;
352
391
  setCanScrollLeft(el.scrollLeft > 0);
353
392
  setCanScrollRight(el.scrollLeft + el.clientWidth < el.scrollWidth - 1);
354
393
  };
355
- (0, import_react2.useEffect)(() => {
394
+ (0, import_react3.useEffect)(() => {
356
395
  const el = scrollRef.current;
357
396
  if (!el) return;
358
397
  updateScrollState();
@@ -367,9 +406,9 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
367
406
  const scroll = (dir) => {
368
407
  scrollRef.current?.scrollBy({ left: dir === "left" ? -216 : 216, behavior: "smooth" });
369
408
  };
370
- const isDragging = (0, import_react2.useRef)(false);
371
- const dragStartX = (0, import_react2.useRef)(0);
372
- const dragStartScrollLeft = (0, import_react2.useRef)(0);
409
+ const isDragging = (0, import_react3.useRef)(false);
410
+ const dragStartX = (0, import_react3.useRef)(0);
411
+ const dragStartScrollLeft = (0, import_react3.useRef)(0);
373
412
  const onDragStart = (e) => {
374
413
  if (!scrollRef.current) return;
375
414
  isDragging.current = true;
@@ -389,14 +428,14 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
389
428
  scrollRef.current.style.cursor = "grab";
390
429
  scrollRef.current.style.userSelect = "";
391
430
  };
392
- const datesWithClasses = (0, import_react2.useMemo)(
431
+ const datesWithClasses = (0, import_react3.useMemo)(
393
432
  () => new Set(dates.map(
394
433
  (d, i) => schedule.classes?.some((c) => classRunsOnDate(c, d, schedule.type)) ? i : -1
395
434
  ).filter((i) => i >= 0)),
396
435
  [dates, schedule]
397
436
  );
398
437
  const selectedDate = dates[selectedIdx];
399
- const selectedClasses = (0, import_react2.useMemo)(
438
+ const selectedClasses = (0, import_react3.useMemo)(
400
439
  () => (schedule.classes ?? []).filter((c) => selectedDate && classRunsOnDate(c, selectedDate, schedule.type)),
401
440
  [schedule, selectedDate]
402
441
  );
@@ -573,15 +612,15 @@ function CalendarFoldIcon() {
573
612
  );
574
613
  }
575
614
  function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAfter: insertAfterProp }) {
576
- const autoId = (0, import_react2.useId)();
615
+ const autoId = (0, import_react3.useId)();
577
616
  const insertAfter = insertAfterProp ?? autoId;
578
- const [schedule, setSchedule] = (0, import_react2.useState)(null);
579
- const [loading, setLoading] = (0, import_react2.useState)(true);
580
- const [inEditor, setInEditor] = (0, import_react2.useState)(false);
581
- const [isHovered, setIsHovered] = (0, import_react2.useState)(false);
582
- const [modalState, setModalState] = (0, import_react2.useState)(null);
583
- const switchScheduleIdRef = (0, import_react2.useRef)(null);
584
- const dates = (0, import_react2.useMemo)(() => {
617
+ const [schedule, setSchedule] = (0, import_react3.useState)(null);
618
+ const [loading, setLoading] = (0, import_react3.useState)(true);
619
+ const [inEditor, setInEditor] = (0, import_react3.useState)(false);
620
+ const [isHovered, setIsHovered] = (0, import_react3.useState)(false);
621
+ const [modalState, setModalState] = (0, import_react3.useState)(null);
622
+ const switchScheduleIdRef = (0, import_react3.useRef)(null);
623
+ const dates = (0, import_react3.useMemo)(() => {
585
624
  const today = /* @__PURE__ */ new Date();
586
625
  today.setHours(0, 0, 0, 0);
587
626
  return Array.from({ length: 14 }, (_, i) => {
@@ -590,8 +629,8 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
590
629
  return d;
591
630
  });
592
631
  }, []);
593
- const [selectedIdx, setSelectedIdx] = (0, import_react2.useState)(0);
594
- (0, import_react2.useEffect)(() => {
632
+ const [selectedIdx, setSelectedIdx] = (0, import_react3.useState)(0);
633
+ (0, import_react3.useEffect)(() => {
595
634
  if (!schedule?.classes) return;
596
635
  for (let i = 0; i < dates.length; i++) {
597
636
  if (schedule.classes.some((c) => classRunsOnDate(c, dates[i], schedule.type))) {
@@ -600,7 +639,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
600
639
  }
601
640
  }
602
641
  }, [schedule, dates]);
603
- (0, import_react2.useEffect)(() => {
642
+ (0, import_react3.useEffect)(() => {
604
643
  if (typeof window === "undefined") return;
605
644
  const isInEditor = window.self !== window.top;
606
645
  setInEditor(isInEditor);
@@ -4721,7 +4760,7 @@ function SectionPickerList({ sections, onSelect }) {
4721
4760
  }
4722
4761
 
4723
4762
  // src/ui/link-modal/UrlOrPageInput.tsx
4724
- var import_react3 = require("react");
4763
+ var import_react4 = require("react");
4725
4764
 
4726
4765
  // src/ui/input.tsx
4727
4766
  var React5 = __toESM(require("react"), 1);
@@ -4786,9 +4825,9 @@ function UrlOrPageInput({
4786
4825
  readOnly = false,
4787
4826
  urlError
4788
4827
  }) {
4789
- const inputId = (0, import_react3.useId)();
4790
- const inputRef = (0, import_react3.useRef)(null);
4791
- const [isFocused, setIsFocused] = (0, import_react3.useState)(false);
4828
+ const inputId = (0, import_react4.useId)();
4829
+ const inputRef = (0, import_react4.useRef)(null);
4830
+ const [isFocused, setIsFocused] = (0, import_react4.useState)(false);
4792
4831
  const openDropdown = () => {
4793
4832
  if (readOnly || filteredPages.length === 0) return;
4794
4833
  onDropdownOpenChange(true);
@@ -4873,7 +4912,7 @@ function UrlOrPageInput({
4873
4912
  }
4874
4913
 
4875
4914
  // src/ui/link-modal/useLinkModalState.ts
4876
- var import_react4 = require("react");
4915
+ var import_react5 = require("react");
4877
4916
  function useLinkModalState({
4878
4917
  open,
4879
4918
  mode,
@@ -4885,17 +4924,17 @@ function useLinkModalState({
4885
4924
  onClose,
4886
4925
  onSubmit
4887
4926
  }) {
4888
- const availablePages = (0, import_react4.useMemo)(
4927
+ const availablePages = (0, import_react5.useMemo)(
4889
4928
  () => mode === "create" ? filterAvailablePages(pages, existingTargets) : pages,
4890
4929
  [mode, pages, existingTargets]
4891
4930
  );
4892
- const [searchValue, setSearchValue] = (0, import_react4.useState)("");
4893
- const [selectedPage, setSelectedPage] = (0, import_react4.useState)(null);
4894
- const [selectedSection, setSelectedSection] = (0, import_react4.useState)(null);
4895
- const [step, setStep] = (0, import_react4.useState)("input");
4896
- const [dropdownOpen, setDropdownOpen] = (0, import_react4.useState)(false);
4897
- const [urlError, setUrlError] = (0, import_react4.useState)("");
4898
- const reset = (0, import_react4.useCallback)(() => {
4931
+ const [searchValue, setSearchValue] = (0, import_react5.useState)("");
4932
+ const [selectedPage, setSelectedPage] = (0, import_react5.useState)(null);
4933
+ const [selectedSection, setSelectedSection] = (0, import_react5.useState)(null);
4934
+ const [step, setStep] = (0, import_react5.useState)("input");
4935
+ const [dropdownOpen, setDropdownOpen] = (0, import_react5.useState)(false);
4936
+ const [urlError, setUrlError] = (0, import_react5.useState)("");
4937
+ const reset = (0, import_react5.useCallback)(() => {
4899
4938
  setSearchValue("");
4900
4939
  setSelectedPage(null);
4901
4940
  setSelectedSection(null);
@@ -4903,7 +4942,7 @@ function useLinkModalState({
4903
4942
  setDropdownOpen(false);
4904
4943
  setUrlError("");
4905
4944
  }, []);
4906
- (0, import_react4.useEffect)(() => {
4945
+ (0, import_react5.useEffect)(() => {
4907
4946
  if (!open) return;
4908
4947
  if (mode === "edit" && initialTarget) {
4909
4948
  const { pageRoute } = parseTarget(initialTarget);
@@ -4919,11 +4958,11 @@ function useLinkModalState({
4919
4958
  setDropdownOpen(false);
4920
4959
  setUrlError("");
4921
4960
  }, [open, mode, initialTarget, pages, sectionsByPath, reset]);
4922
- const filteredPages = (0, import_react4.useMemo)(() => {
4961
+ const filteredPages = (0, import_react5.useMemo)(() => {
4923
4962
  if (!searchValue.trim()) return availablePages;
4924
4963
  return availablePages.filter((p) => p.title.toLowerCase().startsWith(searchValue.toLowerCase()));
4925
4964
  }, [availablePages, searchValue]);
4926
- const activeSections = (0, import_react4.useMemo)(() => {
4965
+ const activeSections = (0, import_react5.useMemo)(() => {
4927
4966
  if (!selectedPage) return [];
4928
4967
  return getSectionsForPath(sectionsByPath, selectedPage.path);
4929
4968
  }, [selectedPage, sectionsByPath]);
@@ -4969,7 +5008,7 @@ function useLinkModalState({
4969
5008
  reset();
4970
5009
  onClose();
4971
5010
  };
4972
- const isValid = (0, import_react4.useMemo)(() => {
5011
+ const isValid = (0, import_react5.useMemo)(() => {
4973
5012
  if (urlError) return false;
4974
5013
  if (showBreadcrumb) return true;
4975
5014
  if (selectedPage) return true;
@@ -5502,10 +5541,11 @@ function applyLinkByKey(key, val) {
5502
5541
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
5503
5542
  if (el.dataset.ohwEditable === "link") applyLinkHref(el, val);
5504
5543
  });
5505
- document.querySelectorAll(`[data-ohw-href-key="${key}"]`).forEach((el) => {
5506
- applyLinkHref(el, val);
5507
- });
5508
- window.dispatchEvent(new CustomEvent("ohw:link-href", { detail: { key, href: val } }));
5544
+ const hrefAnchors = document.querySelectorAll(`[data-ohw-href-key="${key}"]`);
5545
+ if (hrefAnchors.length > 0) {
5546
+ setStoredLinkHref(key, val);
5547
+ hrefAnchors.forEach((el) => applyLinkHref(el, val));
5548
+ }
5509
5549
  }
5510
5550
  function isInsideLinkEditor(target) {
5511
5551
  return Boolean(
@@ -5899,7 +5939,7 @@ function FloatingToolbar({
5899
5939
  },
5900
5940
  onMouseDown: (e) => e.stopPropagation(),
5901
5941
  children: [
5902
- TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_react5.default.Fragment, { children: [
5942
+ TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_react6.default.Fragment, { children: [
5903
5943
  gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { display: "block", width: 1, height: 24, background: "#E7E5E4", flexShrink: 0 } }),
5904
5944
  btns.map((btn) => {
5905
5945
  const isActive = activeCommands.has(btn.cmd);
@@ -6039,8 +6079,8 @@ function OhhwellsBridge() {
6039
6079
  const router = (0, import_navigation.useRouter)();
6040
6080
  const searchParams = (0, import_navigation.useSearchParams)();
6041
6081
  const isEditMode = isEditSessionActive();
6042
- const [bridgeRoot, setBridgeRoot] = (0, import_react5.useState)(null);
6043
- (0, import_react5.useEffect)(() => {
6082
+ const [bridgeRoot, setBridgeRoot] = (0, import_react6.useState)(null);
6083
+ (0, import_react6.useEffect)(() => {
6044
6084
  const figtreeFontId = "ohw-figtree-font";
6045
6085
  if (!document.getElementById(figtreeFontId)) {
6046
6086
  const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
@@ -6064,69 +6104,70 @@ function OhhwellsBridge() {
6064
6104
  }, []);
6065
6105
  const subdomainFromQuery = searchParams.get("subdomain");
6066
6106
  const subdomain = resolveSubdomain(subdomainFromQuery);
6067
- const postToParent = (0, import_react5.useCallback)((data) => {
6107
+ useLinkHrefGuardian(pathname, subdomain, isEditMode);
6108
+ const postToParent = (0, import_react6.useCallback)((data) => {
6068
6109
  if (typeof window !== "undefined" && window.parent !== window) {
6069
6110
  window.parent.postMessage(data, "*");
6070
6111
  }
6071
6112
  }, []);
6072
- const [fetchState, setFetchState] = (0, import_react5.useState)("idle");
6073
- const autoSaveTimers = (0, import_react5.useRef)(/* @__PURE__ */ new Map());
6074
- const activeElRef = (0, import_react5.useRef)(null);
6075
- const selectedElRef = (0, import_react5.useRef)(null);
6076
- const originalContentRef = (0, import_react5.useRef)(null);
6077
- const activeStateElRef = (0, import_react5.useRef)(null);
6078
- const parentScrollRef = (0, import_react5.useRef)(null);
6079
- const visibleViewportRef = (0, import_react5.useRef)(null);
6080
- const [dialogPortalContainer, setDialogPortalContainer] = (0, import_react5.useState)(null);
6081
- const attachVisibleViewport = (0, import_react5.useCallback)((node) => {
6113
+ const [fetchState, setFetchState] = (0, import_react6.useState)("idle");
6114
+ const autoSaveTimers = (0, import_react6.useRef)(/* @__PURE__ */ new Map());
6115
+ const activeElRef = (0, import_react6.useRef)(null);
6116
+ const selectedElRef = (0, import_react6.useRef)(null);
6117
+ const originalContentRef = (0, import_react6.useRef)(null);
6118
+ const activeStateElRef = (0, import_react6.useRef)(null);
6119
+ const parentScrollRef = (0, import_react6.useRef)(null);
6120
+ const visibleViewportRef = (0, import_react6.useRef)(null);
6121
+ const [dialogPortalContainer, setDialogPortalContainer] = (0, import_react6.useState)(null);
6122
+ const attachVisibleViewport = (0, import_react6.useCallback)((node) => {
6082
6123
  visibleViewportRef.current = node;
6083
6124
  setDialogPortalContainer(node);
6084
6125
  if (node) applyVisibleViewport(node, parentScrollRef.current);
6085
6126
  }, []);
6086
- const toolbarElRef = (0, import_react5.useRef)(null);
6087
- const glowElRef = (0, import_react5.useRef)(null);
6088
- const hoveredImageRef = (0, import_react5.useRef)(null);
6089
- const hoveredImageHasTextOverlapRef = (0, import_react5.useRef)(false);
6090
- const hoveredGapRef = (0, import_react5.useRef)(null);
6091
- const imageUnhoverTimerRef = (0, import_react5.useRef)(null);
6092
- const imageShowTimerRef = (0, import_react5.useRef)(null);
6093
- const editStylesRef = (0, import_react5.useRef)(null);
6094
- const activateRef = (0, import_react5.useRef)(() => {
6127
+ const toolbarElRef = (0, import_react6.useRef)(null);
6128
+ const glowElRef = (0, import_react6.useRef)(null);
6129
+ const hoveredImageRef = (0, import_react6.useRef)(null);
6130
+ const hoveredImageHasTextOverlapRef = (0, import_react6.useRef)(false);
6131
+ const hoveredGapRef = (0, import_react6.useRef)(null);
6132
+ const imageUnhoverTimerRef = (0, import_react6.useRef)(null);
6133
+ const imageShowTimerRef = (0, import_react6.useRef)(null);
6134
+ const editStylesRef = (0, import_react6.useRef)(null);
6135
+ const activateRef = (0, import_react6.useRef)(() => {
6095
6136
  });
6096
- const deactivateRef = (0, import_react5.useRef)(() => {
6137
+ const deactivateRef = (0, import_react6.useRef)(() => {
6097
6138
  });
6098
- const selectRef = (0, import_react5.useRef)(() => {
6139
+ const selectRef = (0, import_react6.useRef)(() => {
6099
6140
  });
6100
- const deselectRef = (0, import_react5.useRef)(() => {
6141
+ const deselectRef = (0, import_react6.useRef)(() => {
6101
6142
  });
6102
- const refreshActiveCommandsRef = (0, import_react5.useRef)(() => {
6143
+ const refreshActiveCommandsRef = (0, import_react6.useRef)(() => {
6103
6144
  });
6104
- const postToParentRef = (0, import_react5.useRef)(postToParent);
6145
+ const postToParentRef = (0, import_react6.useRef)(postToParent);
6105
6146
  postToParentRef.current = postToParent;
6106
- const sectionsLoadedRef = (0, import_react5.useRef)(false);
6107
- const pendingScheduleConfigRequests = (0, import_react5.useRef)([]);
6108
- const [toolbarRect, setToolbarRect] = (0, import_react5.useState)(null);
6109
- const [toolbarVariant, setToolbarVariant] = (0, import_react5.useState)("none");
6110
- const toolbarVariantRef = (0, import_react5.useRef)("none");
6147
+ const sectionsLoadedRef = (0, import_react6.useRef)(false);
6148
+ const pendingScheduleConfigRequests = (0, import_react6.useRef)([]);
6149
+ const [toolbarRect, setToolbarRect] = (0, import_react6.useState)(null);
6150
+ const [toolbarVariant, setToolbarVariant] = (0, import_react6.useState)("none");
6151
+ const toolbarVariantRef = (0, import_react6.useRef)("none");
6111
6152
  toolbarVariantRef.current = toolbarVariant;
6112
- const [toggleState, setToggleState] = (0, import_react5.useState)(null);
6113
- const [maxBadge, setMaxBadge] = (0, import_react5.useState)(null);
6114
- const [activeCommands, setActiveCommands] = (0, import_react5.useState)(/* @__PURE__ */ new Set());
6115
- const [sectionGap, setSectionGap] = (0, import_react5.useState)(null);
6116
- const [toolbarShowEditLink, setToolbarShowEditLink] = (0, import_react5.useState)(false);
6117
- const [linkPopover, setLinkPopover] = (0, import_react5.useState)(null);
6118
- const [sitePages, setSitePages] = (0, import_react5.useState)([]);
6119
- const [sectionsByPath, setSectionsByPath] = (0, import_react5.useState)({});
6120
- const sectionsPrefetchGenRef = (0, import_react5.useRef)(0);
6121
- const setLinkPopoverRef = (0, import_react5.useRef)(setLinkPopover);
6122
- const linkPopoverPanelRef = (0, import_react5.useRef)(null);
6123
- const linkPopoverOpenRef = (0, import_react5.useRef)(false);
6124
- const linkPopoverGraceUntilRef = (0, import_react5.useRef)(0);
6153
+ const [toggleState, setToggleState] = (0, import_react6.useState)(null);
6154
+ const [maxBadge, setMaxBadge] = (0, import_react6.useState)(null);
6155
+ const [activeCommands, setActiveCommands] = (0, import_react6.useState)(/* @__PURE__ */ new Set());
6156
+ const [sectionGap, setSectionGap] = (0, import_react6.useState)(null);
6157
+ const [toolbarShowEditLink, setToolbarShowEditLink] = (0, import_react6.useState)(false);
6158
+ const [linkPopover, setLinkPopover] = (0, import_react6.useState)(null);
6159
+ const [sitePages, setSitePages] = (0, import_react6.useState)([]);
6160
+ const [sectionsByPath, setSectionsByPath] = (0, import_react6.useState)({});
6161
+ const sectionsPrefetchGenRef = (0, import_react6.useRef)(0);
6162
+ const setLinkPopoverRef = (0, import_react6.useRef)(setLinkPopover);
6163
+ const linkPopoverPanelRef = (0, import_react6.useRef)(null);
6164
+ const linkPopoverOpenRef = (0, import_react6.useRef)(false);
6165
+ const linkPopoverGraceUntilRef = (0, import_react6.useRef)(0);
6125
6166
  setLinkPopoverRef.current = setLinkPopover;
6126
6167
  const bumpLinkPopoverGrace = () => {
6127
6168
  linkPopoverGraceUntilRef.current = Date.now() + 350;
6128
6169
  };
6129
- const runSectionsPrefetch = (0, import_react5.useCallback)((pages) => {
6170
+ const runSectionsPrefetch = (0, import_react6.useCallback)((pages) => {
6130
6171
  if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
6131
6172
  const gen = ++sectionsPrefetchGenRef.current;
6132
6173
  const paths = pages.map((p) => p.path);
@@ -6145,9 +6186,9 @@ function OhhwellsBridge() {
6145
6186
  );
6146
6187
  });
6147
6188
  }, [isEditMode, pathname]);
6148
- const runSectionsPrefetchRef = (0, import_react5.useRef)(runSectionsPrefetch);
6189
+ const runSectionsPrefetchRef = (0, import_react6.useRef)(runSectionsPrefetch);
6149
6190
  runSectionsPrefetchRef.current = runSectionsPrefetch;
6150
- (0, import_react5.useEffect)(() => {
6191
+ (0, import_react6.useEffect)(() => {
6151
6192
  if (!linkPopover) return;
6152
6193
  if (hoveredImageRef.current) {
6153
6194
  hoveredImageRef.current = null;
@@ -6181,7 +6222,7 @@ function OhhwellsBridge() {
6181
6222
  document.removeEventListener("touchmove", preventBackgroundScroll, scrollOpts);
6182
6223
  };
6183
6224
  }, [linkPopover, postToParent]);
6184
- (0, import_react5.useEffect)(() => {
6225
+ (0, import_react6.useEffect)(() => {
6185
6226
  if (!isEditMode) return;
6186
6227
  const useFixtures = shouldUseDevFixtures();
6187
6228
  if (useFixtures) {
@@ -6205,14 +6246,14 @@ function OhhwellsBridge() {
6205
6246
  if (!useFixtures) postToParent({ type: "ow:request-site-pages" });
6206
6247
  return () => window.removeEventListener("message", onSitePages);
6207
6248
  }, [isEditMode, postToParent]);
6208
- (0, import_react5.useEffect)(() => {
6249
+ (0, import_react6.useEffect)(() => {
6209
6250
  if (!isEditMode || shouldUseDevFixtures()) return;
6210
6251
  void loadAllSectionsManifest().then((manifest) => {
6211
6252
  if (Object.keys(manifest).length === 0) return;
6212
6253
  setSectionsByPath((prev) => ({ ...manifest, ...prev }));
6213
6254
  });
6214
6255
  }, [isEditMode]);
6215
- (0, import_react5.useEffect)(() => {
6256
+ (0, import_react6.useEffect)(() => {
6216
6257
  const update = () => {
6217
6258
  const el = activeElRef.current ?? selectedElRef.current;
6218
6259
  if (el) setToolbarRect(el.getBoundingClientRect());
@@ -6236,10 +6277,10 @@ function OhhwellsBridge() {
6236
6277
  vvp.removeEventListener("resize", update);
6237
6278
  };
6238
6279
  }, []);
6239
- const refreshStateRules = (0, import_react5.useCallback)(() => {
6280
+ const refreshStateRules = (0, import_react6.useCallback)(() => {
6240
6281
  editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
6241
6282
  }, []);
6242
- const processConfigRequest = (0, import_react5.useCallback)((insertAfterVal) => {
6283
+ const processConfigRequest = (0, import_react6.useCallback)((insertAfterVal) => {
6243
6284
  const tracker = getSectionsTracker();
6244
6285
  let entries = [];
6245
6286
  try {
@@ -6262,7 +6303,7 @@ function OhhwellsBridge() {
6262
6303
  }
6263
6304
  window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
6264
6305
  }, [isEditMode]);
6265
- const deactivate = (0, import_react5.useCallback)(() => {
6306
+ const deactivate = (0, import_react6.useCallback)(() => {
6266
6307
  const el = activeElRef.current;
6267
6308
  if (!el) return;
6268
6309
  const key = el.dataset.ohwKey;
@@ -6291,14 +6332,14 @@ function OhhwellsBridge() {
6291
6332
  setToolbarShowEditLink(false);
6292
6333
  postToParent({ type: "ow:exit-edit" });
6293
6334
  }, [postToParent]);
6294
- const deselect = (0, import_react5.useCallback)(() => {
6335
+ const deselect = (0, import_react6.useCallback)(() => {
6295
6336
  selectedElRef.current = null;
6296
6337
  if (!activeElRef.current) {
6297
6338
  setToolbarRect(null);
6298
6339
  setToolbarVariant("none");
6299
6340
  }
6300
6341
  }, []);
6301
- const select = (0, import_react5.useCallback)((anchor) => {
6342
+ const select = (0, import_react6.useCallback)((anchor) => {
6302
6343
  if (!isNavbarButton(anchor)) return;
6303
6344
  if (activeElRef.current) deactivate();
6304
6345
  selectedElRef.current = anchor;
@@ -6308,7 +6349,7 @@ function OhhwellsBridge() {
6308
6349
  setToolbarShowEditLink(false);
6309
6350
  setActiveCommands(/* @__PURE__ */ new Set());
6310
6351
  }, [deactivate]);
6311
- const activate = (0, import_react5.useCallback)((el) => {
6352
+ const activate = (0, import_react6.useCallback)((el) => {
6312
6353
  if (activeElRef.current === el) return;
6313
6354
  selectedElRef.current = null;
6314
6355
  deactivate();
@@ -6331,7 +6372,7 @@ function OhhwellsBridge() {
6331
6372
  deactivateRef.current = deactivate;
6332
6373
  selectRef.current = select;
6333
6374
  deselectRef.current = deselect;
6334
- (0, import_react5.useLayoutEffect)(() => {
6375
+ (0, import_react6.useLayoutEffect)(() => {
6335
6376
  if (!subdomain || isEditMode) {
6336
6377
  setFetchState("done");
6337
6378
  return;
@@ -6361,6 +6402,7 @@ function OhhwellsBridge() {
6361
6402
  });
6362
6403
  applyLinkByKey(key, val);
6363
6404
  }
6405
+ enforceLinkHrefs();
6364
6406
  initSectionsFromContent(content, true);
6365
6407
  sectionsLoadedRef.current = true;
6366
6408
  pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
@@ -6388,7 +6430,7 @@ function OhhwellsBridge() {
6388
6430
  cancelled = true;
6389
6431
  };
6390
6432
  }, [subdomain, isEditMode, pathname]);
6391
- (0, import_react5.useEffect)(() => {
6433
+ (0, import_react6.useEffect)(() => {
6392
6434
  if (!subdomain || isEditMode) return;
6393
6435
  let debounceTimer = null;
6394
6436
  const applyFromCache = () => {
@@ -6412,6 +6454,7 @@ function OhhwellsBridge() {
6412
6454
  });
6413
6455
  applyLinkByKey(key, val);
6414
6456
  }
6457
+ enforceLinkHrefs();
6415
6458
  };
6416
6459
  const scheduleApply = () => {
6417
6460
  if (debounceTimer) clearTimeout(debounceTimer);
@@ -6425,22 +6468,22 @@ function OhhwellsBridge() {
6425
6468
  if (debounceTimer) clearTimeout(debounceTimer);
6426
6469
  };
6427
6470
  }, [subdomain, isEditMode, pathname]);
6428
- (0, import_react5.useLayoutEffect)(() => {
6471
+ (0, import_react6.useLayoutEffect)(() => {
6429
6472
  const el = document.getElementById("ohw-loader");
6430
6473
  if (!el) return;
6431
6474
  const visible = Boolean(subdomain) && fetchState !== "done";
6432
6475
  el.style.display = visible ? "flex" : "none";
6433
6476
  }, [subdomain, fetchState]);
6434
- (0, import_react5.useEffect)(() => {
6477
+ (0, import_react6.useEffect)(() => {
6435
6478
  postToParent({ type: "ow:navigation", path: pathname });
6436
6479
  }, [pathname, postToParent]);
6437
- (0, import_react5.useEffect)(() => {
6480
+ (0, import_react6.useEffect)(() => {
6438
6481
  if (!isEditMode) return;
6439
6482
  setLinkPopover(null);
6440
6483
  deselectRef.current();
6441
6484
  deactivateRef.current();
6442
6485
  }, [pathname, isEditMode]);
6443
- (0, import_react5.useEffect)(() => {
6486
+ (0, import_react6.useEffect)(() => {
6444
6487
  if (!isEditMode) return;
6445
6488
  const measure = () => {
6446
6489
  const h = document.body.scrollHeight;
@@ -6464,7 +6507,7 @@ function OhhwellsBridge() {
6464
6507
  window.removeEventListener("resize", handleResize);
6465
6508
  };
6466
6509
  }, [pathname, isEditMode, postToParent]);
6467
- (0, import_react5.useEffect)(() => {
6510
+ (0, import_react6.useEffect)(() => {
6468
6511
  if (!subdomainFromQuery || isEditMode) return;
6469
6512
  const handleClick = (e) => {
6470
6513
  const anchor = e.target.closest("a");
@@ -6480,7 +6523,7 @@ function OhhwellsBridge() {
6480
6523
  document.addEventListener("click", handleClick, true);
6481
6524
  return () => document.removeEventListener("click", handleClick, true);
6482
6525
  }, [subdomainFromQuery, isEditMode, router]);
6483
- (0, import_react5.useEffect)(() => {
6526
+ (0, import_react6.useEffect)(() => {
6484
6527
  if (!isEditMode) {
6485
6528
  editStylesRef.current?.base.remove();
6486
6529
  editStylesRef.current?.forceHover.remove();
@@ -7103,6 +7146,7 @@ function OhhwellsBridge() {
7103
7146
  sectionsLoadedRef.current = true;
7104
7147
  pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
7105
7148
  }
7149
+ enforceLinkHrefs();
7106
7150
  postToParentRef.current({ type: "ow:hydrate-done" });
7107
7151
  };
7108
7152
  window.addEventListener("message", handleHydrate);
@@ -7394,7 +7438,7 @@ function OhhwellsBridge() {
7394
7438
  if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
7395
7439
  };
7396
7440
  }, [isEditMode, refreshStateRules]);
7397
- (0, import_react5.useEffect)(() => {
7441
+ (0, import_react6.useEffect)(() => {
7398
7442
  const handler = (e) => {
7399
7443
  if (e.data?.type !== "ow:request-schedule-config") return;
7400
7444
  const insertAfterVal = e.data.insertAfter;
@@ -7410,7 +7454,7 @@ function OhhwellsBridge() {
7410
7454
  window.addEventListener("message", handler);
7411
7455
  return () => window.removeEventListener("message", handler);
7412
7456
  }, [processConfigRequest]);
7413
- (0, import_react5.useEffect)(() => {
7457
+ (0, import_react6.useEffect)(() => {
7414
7458
  if (!isEditMode) return;
7415
7459
  document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
7416
7460
  el.removeAttribute("data-ohw-active-state");
@@ -7439,19 +7483,19 @@ function OhhwellsBridge() {
7439
7483
  clearTimeout(timer);
7440
7484
  };
7441
7485
  }, [pathname, isEditMode, refreshStateRules, postToParent]);
7442
- (0, import_react5.useEffect)(() => {
7486
+ (0, import_react6.useEffect)(() => {
7443
7487
  scrollToHashSectionWhenReady();
7444
7488
  const onHashChange = () => scrollToHashSectionWhenReady();
7445
7489
  window.addEventListener("hashchange", onHashChange);
7446
7490
  return () => window.removeEventListener("hashchange", onHashChange);
7447
7491
  }, [pathname]);
7448
- const handleCommand = (0, import_react5.useCallback)((cmd) => {
7492
+ const handleCommand = (0, import_react6.useCallback)((cmd) => {
7449
7493
  document.execCommand(cmd, false);
7450
7494
  activeElRef.current?.focus();
7451
7495
  if (activeElRef.current) setToolbarRect(activeElRef.current.getBoundingClientRect());
7452
7496
  refreshActiveCommandsRef.current();
7453
7497
  }, []);
7454
- const handleStateChange = (0, import_react5.useCallback)((state) => {
7498
+ const handleStateChange = (0, import_react6.useCallback)((state) => {
7455
7499
  if (!activeStateElRef.current) return;
7456
7500
  const el = activeStateElRef.current;
7457
7501
  if (state === "Default") {
@@ -7464,8 +7508,8 @@ function OhhwellsBridge() {
7464
7508
  }
7465
7509
  setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
7466
7510
  }, [deactivate]);
7467
- const closeLinkPopover = (0, import_react5.useCallback)(() => setLinkPopover(null), []);
7468
- const openLinkPopoverForActive = (0, import_react5.useCallback)(() => {
7511
+ const closeLinkPopover = (0, import_react6.useCallback)(() => setLinkPopover(null), []);
7512
+ const openLinkPopoverForActive = (0, import_react6.useCallback)(() => {
7469
7513
  const hrefCtx = getHrefKeyFromElement(activeElRef.current);
7470
7514
  if (!hrefCtx) return;
7471
7515
  bumpLinkPopoverGrace();
@@ -7475,7 +7519,7 @@ function OhhwellsBridge() {
7475
7519
  });
7476
7520
  deactivate();
7477
7521
  }, [deactivate]);
7478
- const openLinkPopoverForSelected = (0, import_react5.useCallback)(() => {
7522
+ const openLinkPopoverForSelected = (0, import_react6.useCallback)(() => {
7479
7523
  const anchor = selectedElRef.current;
7480
7524
  if (!anchor) return;
7481
7525
  const key = anchor.getAttribute("data-ohw-href-key");
@@ -7487,7 +7531,7 @@ function OhhwellsBridge() {
7487
7531
  });
7488
7532
  deselect();
7489
7533
  }, [deselect]);
7490
- const handleLinkPopoverSubmit = (0, import_react5.useCallback)(
7534
+ const handleLinkPopoverSubmit = (0, import_react6.useCallback)(
7491
7535
  (target) => {
7492
7536
  if (!linkPopover) return;
7493
7537
  const { key } = linkPopover;