@ohhwells/bridge 0.1.31-next.30 → 0.1.31-next.31

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
@@ -51,15 +51,54 @@ __export(index_exports, {
51
51
  module.exports = __toCommonJS(index_exports);
52
52
 
53
53
  // src/OhhwellsBridge.tsx
54
- var import_react5 = __toESM(require("react"), 1);
54
+ var import_react6 = __toESM(require("react"), 1);
55
55
  var import_client = require("react-dom/client");
56
56
  var import_react_dom = require("react-dom");
57
57
 
58
+ // src/linkHrefStore.ts
59
+ var linkHrefStore = /* @__PURE__ */ new Map();
60
+ function setStoredLinkHref(key, href) {
61
+ linkHrefStore.set(key, href);
62
+ }
63
+ function enforceLinkHrefs() {
64
+ document.querySelectorAll("[data-ohw-href-key]").forEach((el) => {
65
+ const key = el.getAttribute("data-ohw-href-key") ?? "";
66
+ if (!key) return;
67
+ const saved = linkHrefStore.get(key);
68
+ if (saved === void 0) return;
69
+ if (el.getAttribute("href") !== saved) el.setAttribute("href", saved);
70
+ });
71
+ }
72
+
73
+ // src/useLinkHrefGuardian.ts
74
+ var import_react = require("react");
75
+ function useLinkHrefGuardian(...deps) {
76
+ (0, import_react.useLayoutEffect)(() => {
77
+ let debounceTimer = null;
78
+ const scheduleEnforce = () => {
79
+ if (debounceTimer) clearTimeout(debounceTimer);
80
+ debounceTimer = setTimeout(enforceLinkHrefs, 50);
81
+ };
82
+ enforceLinkHrefs();
83
+ const observer = new MutationObserver(scheduleEnforce);
84
+ observer.observe(document.body, {
85
+ childList: true,
86
+ subtree: true,
87
+ attributes: true,
88
+ attributeFilter: ["href"]
89
+ });
90
+ return () => {
91
+ observer.disconnect();
92
+ if (debounceTimer) clearTimeout(debounceTimer);
93
+ };
94
+ }, deps);
95
+ }
96
+
58
97
  // src/ui/SchedulingWidget.tsx
59
- var import_react2 = require("react");
98
+ var import_react3 = require("react");
60
99
 
61
100
  // src/ui/EmailCaptureModal.tsx
62
- var import_react = require("react");
101
+ var import_react2 = require("react");
63
102
  var import_radix_ui = require("radix-ui");
64
103
  var import_jsx_runtime = require("react/jsx-runtime");
65
104
  function Spinner() {
@@ -88,11 +127,11 @@ function Spinner() {
88
127
  );
89
128
  }
90
129
  function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
91
- const [email, setEmail] = (0, import_react.useState)("");
92
- const [submittedEmail, setSubmittedEmail] = (0, import_react.useState)("");
93
- const [loading, setLoading] = (0, import_react.useState)(false);
94
- const [success, setSuccess] = (0, import_react.useState)(false);
95
- const [error, setError] = (0, import_react.useState)(null);
130
+ const [email, setEmail] = (0, import_react2.useState)("");
131
+ const [submittedEmail, setSubmittedEmail] = (0, import_react2.useState)("");
132
+ const [loading, setLoading] = (0, import_react2.useState)(false);
133
+ const [success, setSuccess] = (0, import_react2.useState)(false);
134
+ const [error, setError] = (0, import_react2.useState)(null);
96
135
  const isBook = title === "Confirm your spot";
97
136
  const handleSubmit = async () => {
98
137
  if (!email.trim()) return;
@@ -340,21 +379,21 @@ function LoadingSkeleton() {
340
379
  ] });
341
380
  }
342
381
  function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal }) {
343
- const todayMs = (0, import_react2.useMemo)(() => {
382
+ const todayMs = (0, import_react3.useMemo)(() => {
344
383
  const d = /* @__PURE__ */ new Date();
345
384
  d.setHours(0, 0, 0, 0);
346
385
  return d.getTime();
347
386
  }, []);
348
- const scrollRef = (0, import_react2.useRef)(null);
349
- const [canScrollLeft, setCanScrollLeft] = (0, import_react2.useState)(false);
350
- const [canScrollRight, setCanScrollRight] = (0, import_react2.useState)(false);
387
+ const scrollRef = (0, import_react3.useRef)(null);
388
+ const [canScrollLeft, setCanScrollLeft] = (0, import_react3.useState)(false);
389
+ const [canScrollRight, setCanScrollRight] = (0, import_react3.useState)(false);
351
390
  const updateScrollState = () => {
352
391
  const el = scrollRef.current;
353
392
  if (!el) return;
354
393
  setCanScrollLeft(el.scrollLeft > 0);
355
394
  setCanScrollRight(el.scrollLeft + el.clientWidth < el.scrollWidth - 1);
356
395
  };
357
- (0, import_react2.useEffect)(() => {
396
+ (0, import_react3.useEffect)(() => {
358
397
  const el = scrollRef.current;
359
398
  if (!el) return;
360
399
  updateScrollState();
@@ -369,9 +408,9 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
369
408
  const scroll = (dir) => {
370
409
  scrollRef.current?.scrollBy({ left: dir === "left" ? -216 : 216, behavior: "smooth" });
371
410
  };
372
- const isDragging = (0, import_react2.useRef)(false);
373
- const dragStartX = (0, import_react2.useRef)(0);
374
- const dragStartScrollLeft = (0, import_react2.useRef)(0);
411
+ const isDragging = (0, import_react3.useRef)(false);
412
+ const dragStartX = (0, import_react3.useRef)(0);
413
+ const dragStartScrollLeft = (0, import_react3.useRef)(0);
375
414
  const onDragStart = (e) => {
376
415
  if (!scrollRef.current) return;
377
416
  isDragging.current = true;
@@ -391,14 +430,14 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
391
430
  scrollRef.current.style.cursor = "grab";
392
431
  scrollRef.current.style.userSelect = "";
393
432
  };
394
- const datesWithClasses = (0, import_react2.useMemo)(
433
+ const datesWithClasses = (0, import_react3.useMemo)(
395
434
  () => new Set(dates.map(
396
435
  (d, i) => schedule.classes?.some((c) => classRunsOnDate(c, d, schedule.type)) ? i : -1
397
436
  ).filter((i) => i >= 0)),
398
437
  [dates, schedule]
399
438
  );
400
439
  const selectedDate = dates[selectedIdx];
401
- const selectedClasses = (0, import_react2.useMemo)(
440
+ const selectedClasses = (0, import_react3.useMemo)(
402
441
  () => (schedule.classes ?? []).filter((c) => selectedDate && classRunsOnDate(c, selectedDate, schedule.type)),
403
442
  [schedule, selectedDate]
404
443
  );
@@ -575,15 +614,15 @@ function CalendarFoldIcon() {
575
614
  );
576
615
  }
577
616
  function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAfter: insertAfterProp }) {
578
- const autoId = (0, import_react2.useId)();
617
+ const autoId = (0, import_react3.useId)();
579
618
  const insertAfter = insertAfterProp ?? autoId;
580
- const [schedule, setSchedule] = (0, import_react2.useState)(null);
581
- const [loading, setLoading] = (0, import_react2.useState)(true);
582
- const [inEditor, setInEditor] = (0, import_react2.useState)(false);
583
- const [isHovered, setIsHovered] = (0, import_react2.useState)(false);
584
- const [modalState, setModalState] = (0, import_react2.useState)(null);
585
- const switchScheduleIdRef = (0, import_react2.useRef)(null);
586
- const dates = (0, import_react2.useMemo)(() => {
619
+ const [schedule, setSchedule] = (0, import_react3.useState)(null);
620
+ const [loading, setLoading] = (0, import_react3.useState)(true);
621
+ const [inEditor, setInEditor] = (0, import_react3.useState)(false);
622
+ const [isHovered, setIsHovered] = (0, import_react3.useState)(false);
623
+ const [modalState, setModalState] = (0, import_react3.useState)(null);
624
+ const switchScheduleIdRef = (0, import_react3.useRef)(null);
625
+ const dates = (0, import_react3.useMemo)(() => {
587
626
  const today = /* @__PURE__ */ new Date();
588
627
  today.setHours(0, 0, 0, 0);
589
628
  return Array.from({ length: 14 }, (_, i) => {
@@ -592,8 +631,8 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
592
631
  return d;
593
632
  });
594
633
  }, []);
595
- const [selectedIdx, setSelectedIdx] = (0, import_react2.useState)(0);
596
- (0, import_react2.useEffect)(() => {
634
+ const [selectedIdx, setSelectedIdx] = (0, import_react3.useState)(0);
635
+ (0, import_react3.useEffect)(() => {
597
636
  if (!schedule?.classes) return;
598
637
  for (let i = 0; i < dates.length; i++) {
599
638
  if (schedule.classes.some((c) => classRunsOnDate(c, dates[i], schedule.type))) {
@@ -602,7 +641,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
602
641
  }
603
642
  }
604
643
  }, [schedule, dates]);
605
- (0, import_react2.useEffect)(() => {
644
+ (0, import_react3.useEffect)(() => {
606
645
  if (typeof window === "undefined") return;
607
646
  const isInEditor = window.self !== window.top;
608
647
  setInEditor(isInEditor);
@@ -4751,7 +4790,7 @@ function SectionPickerList({ sections, onSelect }) {
4751
4790
  }
4752
4791
 
4753
4792
  // src/ui/link-modal/UrlOrPageInput.tsx
4754
- var import_react3 = require("react");
4793
+ var import_react4 = require("react");
4755
4794
 
4756
4795
  // src/ui/input.tsx
4757
4796
  var React6 = __toESM(require("react"), 1);
@@ -4816,9 +4855,9 @@ function UrlOrPageInput({
4816
4855
  readOnly = false,
4817
4856
  urlError
4818
4857
  }) {
4819
- const inputId = (0, import_react3.useId)();
4820
- const inputRef = (0, import_react3.useRef)(null);
4821
- const [isFocused, setIsFocused] = (0, import_react3.useState)(false);
4858
+ const inputId = (0, import_react4.useId)();
4859
+ const inputRef = (0, import_react4.useRef)(null);
4860
+ const [isFocused, setIsFocused] = (0, import_react4.useState)(false);
4822
4861
  const openDropdown = () => {
4823
4862
  if (readOnly || filteredPages.length === 0) return;
4824
4863
  onDropdownOpenChange(true);
@@ -4903,7 +4942,7 @@ function UrlOrPageInput({
4903
4942
  }
4904
4943
 
4905
4944
  // src/ui/link-modal/useLinkModalState.ts
4906
- var import_react4 = require("react");
4945
+ var import_react5 = require("react");
4907
4946
  function useLinkModalState({
4908
4947
  open,
4909
4948
  mode,
@@ -4915,17 +4954,17 @@ function useLinkModalState({
4915
4954
  onClose,
4916
4955
  onSubmit
4917
4956
  }) {
4918
- const availablePages = (0, import_react4.useMemo)(
4957
+ const availablePages = (0, import_react5.useMemo)(
4919
4958
  () => mode === "create" ? filterAvailablePages(pages, existingTargets) : pages,
4920
4959
  [mode, pages, existingTargets]
4921
4960
  );
4922
- const [searchValue, setSearchValue] = (0, import_react4.useState)("");
4923
- const [selectedPage, setSelectedPage] = (0, import_react4.useState)(null);
4924
- const [selectedSection, setSelectedSection] = (0, import_react4.useState)(null);
4925
- const [step, setStep] = (0, import_react4.useState)("input");
4926
- const [dropdownOpen, setDropdownOpen] = (0, import_react4.useState)(false);
4927
- const [urlError, setUrlError] = (0, import_react4.useState)("");
4928
- const reset = (0, import_react4.useCallback)(() => {
4961
+ const [searchValue, setSearchValue] = (0, import_react5.useState)("");
4962
+ const [selectedPage, setSelectedPage] = (0, import_react5.useState)(null);
4963
+ const [selectedSection, setSelectedSection] = (0, import_react5.useState)(null);
4964
+ const [step, setStep] = (0, import_react5.useState)("input");
4965
+ const [dropdownOpen, setDropdownOpen] = (0, import_react5.useState)(false);
4966
+ const [urlError, setUrlError] = (0, import_react5.useState)("");
4967
+ const reset = (0, import_react5.useCallback)(() => {
4929
4968
  setSearchValue("");
4930
4969
  setSelectedPage(null);
4931
4970
  setSelectedSection(null);
@@ -4933,7 +4972,7 @@ function useLinkModalState({
4933
4972
  setDropdownOpen(false);
4934
4973
  setUrlError("");
4935
4974
  }, []);
4936
- (0, import_react4.useEffect)(() => {
4975
+ (0, import_react5.useEffect)(() => {
4937
4976
  if (!open) return;
4938
4977
  if (mode === "edit" && initialTarget) {
4939
4978
  const { pageRoute } = parseTarget(initialTarget);
@@ -4949,11 +4988,11 @@ function useLinkModalState({
4949
4988
  setDropdownOpen(false);
4950
4989
  setUrlError("");
4951
4990
  }, [open, mode, initialTarget, pages, sectionsByPath, reset]);
4952
- const filteredPages = (0, import_react4.useMemo)(() => {
4991
+ const filteredPages = (0, import_react5.useMemo)(() => {
4953
4992
  if (!searchValue.trim()) return availablePages;
4954
4993
  return availablePages.filter((p) => p.title.toLowerCase().startsWith(searchValue.toLowerCase()));
4955
4994
  }, [availablePages, searchValue]);
4956
- const activeSections = (0, import_react4.useMemo)(() => {
4995
+ const activeSections = (0, import_react5.useMemo)(() => {
4957
4996
  if (!selectedPage) return [];
4958
4997
  return getSectionsForPath(sectionsByPath, selectedPage.path);
4959
4998
  }, [selectedPage, sectionsByPath]);
@@ -4999,7 +5038,7 @@ function useLinkModalState({
4999
5038
  reset();
5000
5039
  onClose();
5001
5040
  };
5002
- const isValid = (0, import_react4.useMemo)(() => {
5041
+ const isValid = (0, import_react5.useMemo)(() => {
5003
5042
  if (urlError) return false;
5004
5043
  if (showBreadcrumb) return true;
5005
5044
  if (selectedPage) return true;
@@ -5546,10 +5585,11 @@ function applyLinkByKey(key, val) {
5546
5585
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
5547
5586
  if (el.dataset.ohwEditable === "link") applyLinkHref(el, val);
5548
5587
  });
5549
- document.querySelectorAll(`[data-ohw-href-key="${key}"]`).forEach((el) => {
5550
- applyLinkHref(el, val);
5551
- });
5552
- window.dispatchEvent(new CustomEvent("ohw:link-href", { detail: { key, href: val } }));
5588
+ const hrefAnchors = document.querySelectorAll(`[data-ohw-href-key="${key}"]`);
5589
+ if (hrefAnchors.length > 0) {
5590
+ setStoredLinkHref(key, val);
5591
+ hrefAnchors.forEach((el) => applyLinkHref(el, val));
5592
+ }
5553
5593
  }
5554
5594
  function isInsideLinkEditor(target) {
5555
5595
  return Boolean(
@@ -5993,7 +6033,7 @@ function FloatingToolbar({
5993
6033
  },
5994
6034
  onMouseDown: (e) => e.stopPropagation(),
5995
6035
  children: [
5996
- TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_react5.default.Fragment, { children: [
6036
+ TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_react6.default.Fragment, { children: [
5997
6037
  gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: { display: "block", width: 1, height: 24, background: "#E7E5E4", flexShrink: 0 } }),
5998
6038
  btns.map((btn) => {
5999
6039
  const isActive = activeCommands.has(btn.cmd);
@@ -6133,8 +6173,8 @@ function OhhwellsBridge() {
6133
6173
  const router = (0, import_navigation.useRouter)();
6134
6174
  const searchParams = (0, import_navigation.useSearchParams)();
6135
6175
  const isEditMode = isEditSessionActive();
6136
- const [bridgeRoot, setBridgeRoot] = (0, import_react5.useState)(null);
6137
- (0, import_react5.useEffect)(() => {
6176
+ const [bridgeRoot, setBridgeRoot] = (0, import_react6.useState)(null);
6177
+ (0, import_react6.useEffect)(() => {
6138
6178
  const figtreeFontId = "ohw-figtree-font";
6139
6179
  if (!document.getElementById(figtreeFontId)) {
6140
6180
  const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
@@ -6158,71 +6198,72 @@ function OhhwellsBridge() {
6158
6198
  }, []);
6159
6199
  const subdomainFromQuery = searchParams.get("subdomain");
6160
6200
  const subdomain = resolveSubdomain(subdomainFromQuery);
6161
- const postToParent = (0, import_react5.useCallback)((data) => {
6201
+ useLinkHrefGuardian(pathname, subdomain, isEditMode);
6202
+ const postToParent = (0, import_react6.useCallback)((data) => {
6162
6203
  if (typeof window !== "undefined" && window.parent !== window) {
6163
6204
  window.parent.postMessage(data, "*");
6164
6205
  }
6165
6206
  }, []);
6166
- const [fetchState, setFetchState] = (0, import_react5.useState)("idle");
6167
- const autoSaveTimers = (0, import_react5.useRef)(/* @__PURE__ */ new Map());
6168
- const activeElRef = (0, import_react5.useRef)(null);
6169
- const selectedElRef = (0, import_react5.useRef)(null);
6170
- const originalContentRef = (0, import_react5.useRef)(null);
6171
- const activeStateElRef = (0, import_react5.useRef)(null);
6172
- const parentScrollRef = (0, import_react5.useRef)(null);
6173
- const visibleViewportRef = (0, import_react5.useRef)(null);
6174
- const [dialogPortalContainer, setDialogPortalContainer] = (0, import_react5.useState)(null);
6175
- const attachVisibleViewport = (0, import_react5.useCallback)((node) => {
6207
+ const [fetchState, setFetchState] = (0, import_react6.useState)("idle");
6208
+ const autoSaveTimers = (0, import_react6.useRef)(/* @__PURE__ */ new Map());
6209
+ const activeElRef = (0, import_react6.useRef)(null);
6210
+ const selectedElRef = (0, import_react6.useRef)(null);
6211
+ const originalContentRef = (0, import_react6.useRef)(null);
6212
+ const activeStateElRef = (0, import_react6.useRef)(null);
6213
+ const parentScrollRef = (0, import_react6.useRef)(null);
6214
+ const visibleViewportRef = (0, import_react6.useRef)(null);
6215
+ const [dialogPortalContainer, setDialogPortalContainer] = (0, import_react6.useState)(null);
6216
+ const attachVisibleViewport = (0, import_react6.useCallback)((node) => {
6176
6217
  visibleViewportRef.current = node;
6177
6218
  setDialogPortalContainer(node);
6178
6219
  if (node) applyVisibleViewport(node, parentScrollRef.current);
6179
6220
  }, []);
6180
- const toolbarElRef = (0, import_react5.useRef)(null);
6181
- const glowElRef = (0, import_react5.useRef)(null);
6182
- const hoveredImageRef = (0, import_react5.useRef)(null);
6183
- const hoveredImageHasTextOverlapRef = (0, import_react5.useRef)(false);
6184
- const hoveredGapRef = (0, import_react5.useRef)(null);
6185
- const imageUnhoverTimerRef = (0, import_react5.useRef)(null);
6186
- const imageShowTimerRef = (0, import_react5.useRef)(null);
6187
- const editStylesRef = (0, import_react5.useRef)(null);
6188
- const activateRef = (0, import_react5.useRef)(() => {
6221
+ const toolbarElRef = (0, import_react6.useRef)(null);
6222
+ const glowElRef = (0, import_react6.useRef)(null);
6223
+ const hoveredImageRef = (0, import_react6.useRef)(null);
6224
+ const hoveredImageHasTextOverlapRef = (0, import_react6.useRef)(false);
6225
+ const hoveredGapRef = (0, import_react6.useRef)(null);
6226
+ const imageUnhoverTimerRef = (0, import_react6.useRef)(null);
6227
+ const imageShowTimerRef = (0, import_react6.useRef)(null);
6228
+ const editStylesRef = (0, import_react6.useRef)(null);
6229
+ const activateRef = (0, import_react6.useRef)(() => {
6189
6230
  });
6190
- const deactivateRef = (0, import_react5.useRef)(() => {
6231
+ const deactivateRef = (0, import_react6.useRef)(() => {
6191
6232
  });
6192
- const selectRef = (0, import_react5.useRef)(() => {
6233
+ const selectRef = (0, import_react6.useRef)(() => {
6193
6234
  });
6194
- const deselectRef = (0, import_react5.useRef)(() => {
6235
+ const deselectRef = (0, import_react6.useRef)(() => {
6195
6236
  });
6196
- const refreshActiveCommandsRef = (0, import_react5.useRef)(() => {
6237
+ const refreshActiveCommandsRef = (0, import_react6.useRef)(() => {
6197
6238
  });
6198
- const postToParentRef = (0, import_react5.useRef)(postToParent);
6239
+ const postToParentRef = (0, import_react6.useRef)(postToParent);
6199
6240
  postToParentRef.current = postToParent;
6200
- const sectionsLoadedRef = (0, import_react5.useRef)(false);
6201
- const pendingScheduleConfigRequests = (0, import_react5.useRef)([]);
6202
- const [toolbarRect, setToolbarRect] = (0, import_react5.useState)(null);
6203
- const [toolbarVariant, setToolbarVariant] = (0, import_react5.useState)("none");
6204
- const toolbarVariantRef = (0, import_react5.useRef)("none");
6241
+ const sectionsLoadedRef = (0, import_react6.useRef)(false);
6242
+ const pendingScheduleConfigRequests = (0, import_react6.useRef)([]);
6243
+ const [toolbarRect, setToolbarRect] = (0, import_react6.useState)(null);
6244
+ const [toolbarVariant, setToolbarVariant] = (0, import_react6.useState)("none");
6245
+ const toolbarVariantRef = (0, import_react6.useRef)("none");
6205
6246
  toolbarVariantRef.current = toolbarVariant;
6206
- const [reorderHrefKey, setReorderHrefKey] = (0, import_react5.useState)(null);
6207
- const [reorderDragDisabled, setReorderDragDisabled] = (0, import_react5.useState)(false);
6208
- const [toggleState, setToggleState] = (0, import_react5.useState)(null);
6209
- const [maxBadge, setMaxBadge] = (0, import_react5.useState)(null);
6210
- const [activeCommands, setActiveCommands] = (0, import_react5.useState)(/* @__PURE__ */ new Set());
6211
- const [sectionGap, setSectionGap] = (0, import_react5.useState)(null);
6212
- const [toolbarShowEditLink, setToolbarShowEditLink] = (0, import_react5.useState)(false);
6213
- const [linkPopover, setLinkPopover] = (0, import_react5.useState)(null);
6214
- const [sitePages, setSitePages] = (0, import_react5.useState)([]);
6215
- const [sectionsByPath, setSectionsByPath] = (0, import_react5.useState)({});
6216
- const sectionsPrefetchGenRef = (0, import_react5.useRef)(0);
6217
- const setLinkPopoverRef = (0, import_react5.useRef)(setLinkPopover);
6218
- const linkPopoverPanelRef = (0, import_react5.useRef)(null);
6219
- const linkPopoverOpenRef = (0, import_react5.useRef)(false);
6220
- const linkPopoverGraceUntilRef = (0, import_react5.useRef)(0);
6247
+ const [reorderHrefKey, setReorderHrefKey] = (0, import_react6.useState)(null);
6248
+ const [reorderDragDisabled, setReorderDragDisabled] = (0, import_react6.useState)(false);
6249
+ const [toggleState, setToggleState] = (0, import_react6.useState)(null);
6250
+ const [maxBadge, setMaxBadge] = (0, import_react6.useState)(null);
6251
+ const [activeCommands, setActiveCommands] = (0, import_react6.useState)(/* @__PURE__ */ new Set());
6252
+ const [sectionGap, setSectionGap] = (0, import_react6.useState)(null);
6253
+ const [toolbarShowEditLink, setToolbarShowEditLink] = (0, import_react6.useState)(false);
6254
+ const [linkPopover, setLinkPopover] = (0, import_react6.useState)(null);
6255
+ const [sitePages, setSitePages] = (0, import_react6.useState)([]);
6256
+ const [sectionsByPath, setSectionsByPath] = (0, import_react6.useState)({});
6257
+ const sectionsPrefetchGenRef = (0, import_react6.useRef)(0);
6258
+ const setLinkPopoverRef = (0, import_react6.useRef)(setLinkPopover);
6259
+ const linkPopoverPanelRef = (0, import_react6.useRef)(null);
6260
+ const linkPopoverOpenRef = (0, import_react6.useRef)(false);
6261
+ const linkPopoverGraceUntilRef = (0, import_react6.useRef)(0);
6221
6262
  setLinkPopoverRef.current = setLinkPopover;
6222
6263
  const bumpLinkPopoverGrace = () => {
6223
6264
  linkPopoverGraceUntilRef.current = Date.now() + 350;
6224
6265
  };
6225
- const runSectionsPrefetch = (0, import_react5.useCallback)((pages) => {
6266
+ const runSectionsPrefetch = (0, import_react6.useCallback)((pages) => {
6226
6267
  if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
6227
6268
  const gen = ++sectionsPrefetchGenRef.current;
6228
6269
  const paths = pages.map((p) => p.path);
@@ -6241,9 +6282,9 @@ function OhhwellsBridge() {
6241
6282
  );
6242
6283
  });
6243
6284
  }, [isEditMode, pathname]);
6244
- const runSectionsPrefetchRef = (0, import_react5.useRef)(runSectionsPrefetch);
6285
+ const runSectionsPrefetchRef = (0, import_react6.useRef)(runSectionsPrefetch);
6245
6286
  runSectionsPrefetchRef.current = runSectionsPrefetch;
6246
- (0, import_react5.useEffect)(() => {
6287
+ (0, import_react6.useEffect)(() => {
6247
6288
  if (!linkPopover) return;
6248
6289
  if (hoveredImageRef.current) {
6249
6290
  hoveredImageRef.current = null;
@@ -6277,7 +6318,7 @@ function OhhwellsBridge() {
6277
6318
  document.removeEventListener("touchmove", preventBackgroundScroll, scrollOpts);
6278
6319
  };
6279
6320
  }, [linkPopover, postToParent]);
6280
- (0, import_react5.useEffect)(() => {
6321
+ (0, import_react6.useEffect)(() => {
6281
6322
  if (!isEditMode) return;
6282
6323
  const useFixtures = shouldUseDevFixtures();
6283
6324
  if (useFixtures) {
@@ -6301,14 +6342,14 @@ function OhhwellsBridge() {
6301
6342
  if (!useFixtures) postToParent({ type: "ow:request-site-pages" });
6302
6343
  return () => window.removeEventListener("message", onSitePages);
6303
6344
  }, [isEditMode, postToParent]);
6304
- (0, import_react5.useEffect)(() => {
6345
+ (0, import_react6.useEffect)(() => {
6305
6346
  if (!isEditMode || shouldUseDevFixtures()) return;
6306
6347
  void loadAllSectionsManifest().then((manifest) => {
6307
6348
  if (Object.keys(manifest).length === 0) return;
6308
6349
  setSectionsByPath((prev) => ({ ...manifest, ...prev }));
6309
6350
  });
6310
6351
  }, [isEditMode]);
6311
- (0, import_react5.useEffect)(() => {
6352
+ (0, import_react6.useEffect)(() => {
6312
6353
  const update = () => {
6313
6354
  const el = activeElRef.current ?? selectedElRef.current;
6314
6355
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
@@ -6332,10 +6373,10 @@ function OhhwellsBridge() {
6332
6373
  vvp.removeEventListener("resize", update);
6333
6374
  };
6334
6375
  }, []);
6335
- const refreshStateRules = (0, import_react5.useCallback)(() => {
6376
+ const refreshStateRules = (0, import_react6.useCallback)(() => {
6336
6377
  editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
6337
6378
  }, []);
6338
- const processConfigRequest = (0, import_react5.useCallback)((insertAfterVal) => {
6379
+ const processConfigRequest = (0, import_react6.useCallback)((insertAfterVal) => {
6339
6380
  const tracker = getSectionsTracker();
6340
6381
  let entries = [];
6341
6382
  try {
@@ -6358,7 +6399,7 @@ function OhhwellsBridge() {
6358
6399
  }
6359
6400
  window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
6360
6401
  }, [isEditMode]);
6361
- const deactivate = (0, import_react5.useCallback)(() => {
6402
+ const deactivate = (0, import_react6.useCallback)(() => {
6362
6403
  const el = activeElRef.current;
6363
6404
  if (!el) return;
6364
6405
  const key = el.dataset.ohwKey;
@@ -6389,14 +6430,14 @@ function OhhwellsBridge() {
6389
6430
  setToolbarShowEditLink(false);
6390
6431
  postToParent({ type: "ow:exit-edit" });
6391
6432
  }, [postToParent]);
6392
- const deselect = (0, import_react5.useCallback)(() => {
6433
+ const deselect = (0, import_react6.useCallback)(() => {
6393
6434
  selectedElRef.current = null;
6394
6435
  if (!activeElRef.current) {
6395
6436
  setToolbarRect(null);
6396
6437
  setToolbarVariant("none");
6397
6438
  }
6398
6439
  }, []);
6399
- const select = (0, import_react5.useCallback)((anchor) => {
6440
+ const select = (0, import_react6.useCallback)((anchor) => {
6400
6441
  if (!isNavbarButton(anchor)) return;
6401
6442
  if (activeElRef.current) deactivate();
6402
6443
  selectedElRef.current = anchor;
@@ -6406,7 +6447,7 @@ function OhhwellsBridge() {
6406
6447
  setToolbarShowEditLink(false);
6407
6448
  setActiveCommands(/* @__PURE__ */ new Set());
6408
6449
  }, [deactivate]);
6409
- const activate = (0, import_react5.useCallback)((el) => {
6450
+ const activate = (0, import_react6.useCallback)((el) => {
6410
6451
  if (activeElRef.current === el) return;
6411
6452
  selectedElRef.current = null;
6412
6453
  deactivate();
@@ -6433,7 +6474,7 @@ function OhhwellsBridge() {
6433
6474
  deactivateRef.current = deactivate;
6434
6475
  selectRef.current = select;
6435
6476
  deselectRef.current = deselect;
6436
- (0, import_react5.useLayoutEffect)(() => {
6477
+ (0, import_react6.useLayoutEffect)(() => {
6437
6478
  if (!subdomain || isEditMode) {
6438
6479
  setFetchState("done");
6439
6480
  return;
@@ -6463,6 +6504,7 @@ function OhhwellsBridge() {
6463
6504
  });
6464
6505
  applyLinkByKey(key, val);
6465
6506
  }
6507
+ enforceLinkHrefs();
6466
6508
  initSectionsFromContent(content, true);
6467
6509
  sectionsLoadedRef.current = true;
6468
6510
  pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
@@ -6490,7 +6532,7 @@ function OhhwellsBridge() {
6490
6532
  cancelled = true;
6491
6533
  };
6492
6534
  }, [subdomain, isEditMode, pathname]);
6493
- (0, import_react5.useEffect)(() => {
6535
+ (0, import_react6.useEffect)(() => {
6494
6536
  if (!subdomain || isEditMode) return;
6495
6537
  let debounceTimer = null;
6496
6538
  const applyFromCache = () => {
@@ -6514,6 +6556,7 @@ function OhhwellsBridge() {
6514
6556
  });
6515
6557
  applyLinkByKey(key, val);
6516
6558
  }
6559
+ enforceLinkHrefs();
6517
6560
  };
6518
6561
  const scheduleApply = () => {
6519
6562
  if (debounceTimer) clearTimeout(debounceTimer);
@@ -6527,22 +6570,22 @@ function OhhwellsBridge() {
6527
6570
  if (debounceTimer) clearTimeout(debounceTimer);
6528
6571
  };
6529
6572
  }, [subdomain, isEditMode, pathname]);
6530
- (0, import_react5.useLayoutEffect)(() => {
6573
+ (0, import_react6.useLayoutEffect)(() => {
6531
6574
  const el = document.getElementById("ohw-loader");
6532
6575
  if (!el) return;
6533
6576
  const visible = Boolean(subdomain) && fetchState !== "done";
6534
6577
  el.style.display = visible ? "flex" : "none";
6535
6578
  }, [subdomain, fetchState]);
6536
- (0, import_react5.useEffect)(() => {
6579
+ (0, import_react6.useEffect)(() => {
6537
6580
  postToParent({ type: "ow:navigation", path: pathname });
6538
6581
  }, [pathname, postToParent]);
6539
- (0, import_react5.useEffect)(() => {
6582
+ (0, import_react6.useEffect)(() => {
6540
6583
  if (!isEditMode) return;
6541
6584
  setLinkPopover(null);
6542
6585
  deselectRef.current();
6543
6586
  deactivateRef.current();
6544
6587
  }, [pathname, isEditMode]);
6545
- (0, import_react5.useEffect)(() => {
6588
+ (0, import_react6.useEffect)(() => {
6546
6589
  if (!isEditMode) return;
6547
6590
  const measure = () => {
6548
6591
  const h = document.body.scrollHeight;
@@ -6566,7 +6609,7 @@ function OhhwellsBridge() {
6566
6609
  window.removeEventListener("resize", handleResize);
6567
6610
  };
6568
6611
  }, [pathname, isEditMode, postToParent]);
6569
- (0, import_react5.useEffect)(() => {
6612
+ (0, import_react6.useEffect)(() => {
6570
6613
  if (!subdomainFromQuery || isEditMode) return;
6571
6614
  const handleClick = (e) => {
6572
6615
  const anchor = e.target.closest("a");
@@ -6582,7 +6625,7 @@ function OhhwellsBridge() {
6582
6625
  document.addEventListener("click", handleClick, true);
6583
6626
  return () => document.removeEventListener("click", handleClick, true);
6584
6627
  }, [subdomainFromQuery, isEditMode, router]);
6585
- (0, import_react5.useEffect)(() => {
6628
+ (0, import_react6.useEffect)(() => {
6586
6629
  if (!isEditMode) {
6587
6630
  editStylesRef.current?.base.remove();
6588
6631
  editStylesRef.current?.forceHover.remove();
@@ -7223,6 +7266,7 @@ function OhhwellsBridge() {
7223
7266
  sectionsLoadedRef.current = true;
7224
7267
  pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
7225
7268
  }
7269
+ enforceLinkHrefs();
7226
7270
  postToParentRef.current({ type: "ow:hydrate-done" });
7227
7271
  };
7228
7272
  window.addEventListener("message", handleHydrate);
@@ -7514,7 +7558,7 @@ function OhhwellsBridge() {
7514
7558
  if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
7515
7559
  };
7516
7560
  }, [isEditMode, refreshStateRules]);
7517
- (0, import_react5.useEffect)(() => {
7561
+ (0, import_react6.useEffect)(() => {
7518
7562
  const handler = (e) => {
7519
7563
  if (e.data?.type !== "ow:request-schedule-config") return;
7520
7564
  const insertAfterVal = e.data.insertAfter;
@@ -7530,7 +7574,7 @@ function OhhwellsBridge() {
7530
7574
  window.addEventListener("message", handler);
7531
7575
  return () => window.removeEventListener("message", handler);
7532
7576
  }, [processConfigRequest]);
7533
- (0, import_react5.useEffect)(() => {
7577
+ (0, import_react6.useEffect)(() => {
7534
7578
  if (!isEditMode) return;
7535
7579
  document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
7536
7580
  el.removeAttribute("data-ohw-active-state");
@@ -7559,19 +7603,19 @@ function OhhwellsBridge() {
7559
7603
  clearTimeout(timer);
7560
7604
  };
7561
7605
  }, [pathname, isEditMode, refreshStateRules, postToParent]);
7562
- (0, import_react5.useEffect)(() => {
7606
+ (0, import_react6.useEffect)(() => {
7563
7607
  scrollToHashSectionWhenReady();
7564
7608
  const onHashChange = () => scrollToHashSectionWhenReady();
7565
7609
  window.addEventListener("hashchange", onHashChange);
7566
7610
  return () => window.removeEventListener("hashchange", onHashChange);
7567
7611
  }, [pathname]);
7568
- const handleCommand = (0, import_react5.useCallback)((cmd) => {
7612
+ const handleCommand = (0, import_react6.useCallback)((cmd) => {
7569
7613
  document.execCommand(cmd, false);
7570
7614
  activeElRef.current?.focus();
7571
7615
  if (activeElRef.current) setToolbarRect(getEditMeasureEl(activeElRef.current).getBoundingClientRect());
7572
7616
  refreshActiveCommandsRef.current();
7573
7617
  }, []);
7574
- const handleStateChange = (0, import_react5.useCallback)((state) => {
7618
+ const handleStateChange = (0, import_react6.useCallback)((state) => {
7575
7619
  if (!activeStateElRef.current) return;
7576
7620
  const el = activeStateElRef.current;
7577
7621
  if (state === "Default") {
@@ -7584,8 +7628,8 @@ function OhhwellsBridge() {
7584
7628
  }
7585
7629
  setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
7586
7630
  }, [deactivate]);
7587
- const closeLinkPopover = (0, import_react5.useCallback)(() => setLinkPopover(null), []);
7588
- const openLinkPopoverForActive = (0, import_react5.useCallback)(() => {
7631
+ const closeLinkPopover = (0, import_react6.useCallback)(() => setLinkPopover(null), []);
7632
+ const openLinkPopoverForActive = (0, import_react6.useCallback)(() => {
7589
7633
  const hrefCtx = getHrefKeyFromElement(activeElRef.current);
7590
7634
  if (!hrefCtx) return;
7591
7635
  bumpLinkPopoverGrace();
@@ -7595,7 +7639,7 @@ function OhhwellsBridge() {
7595
7639
  });
7596
7640
  deactivate();
7597
7641
  }, [deactivate]);
7598
- const openLinkPopoverForSelected = (0, import_react5.useCallback)(() => {
7642
+ const openLinkPopoverForSelected = (0, import_react6.useCallback)(() => {
7599
7643
  const anchor = selectedElRef.current;
7600
7644
  if (!anchor) return;
7601
7645
  const key = anchor.getAttribute("data-ohw-href-key");
@@ -7607,7 +7651,7 @@ function OhhwellsBridge() {
7607
7651
  });
7608
7652
  deselect();
7609
7653
  }, [deselect]);
7610
- const handleLinkPopoverSubmit = (0, import_react5.useCallback)(
7654
+ const handleLinkPopoverSubmit = (0, import_react6.useCallback)(
7611
7655
  (target) => {
7612
7656
  if (!linkPopover) return;
7613
7657
  const { key } = linkPopover;