@ohhwells/bridge 0.1.34-next.44 → 0.1.35

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.d.cts CHANGED
@@ -109,7 +109,7 @@ type ItemInteractionLayerProps = {
109
109
  rect: DOMRect;
110
110
  state: ItemInteractionState;
111
111
  elRef?: React.Ref<HTMLDivElement>;
112
- /** Slotted Custom/Toolbar instance (item-action or other fill). */
112
+ /** Slotted Custom/Toolbar instance (item-action or other fill). */
113
113
  toolbar?: React.ReactNode;
114
114
  showHandle?: boolean;
115
115
  dragDisabled?: boolean;
package/dist/index.d.ts CHANGED
@@ -109,7 +109,7 @@ type ItemInteractionLayerProps = {
109
109
  rect: DOMRect;
110
110
  state: ItemInteractionState;
111
111
  elRef?: React.Ref<HTMLDivElement>;
112
- /** Slotted Custom/Toolbar instance (item-action or other fill). */
112
+ /** Slotted Custom/Toolbar instance (item-action or other fill). */
113
113
  toolbar?: React.ReactNode;
114
114
  showHandle?: boolean;
115
115
  dragDisabled?: boolean;
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  // src/OhhwellsBridge.tsx
4
- import React8, { useCallback as useCallback3, useEffect as useEffect3, useLayoutEffect as useLayoutEffect2, useRef as useRef3, useState as useState5 } from "react";
4
+ import React8, { useCallback as useCallback2, useEffect as useEffect3, useLayoutEffect as useLayoutEffect2, useRef as useRef3, useState as useState5 } from "react";
5
5
  import { createRoot } from "react-dom/client";
6
6
  import { flushSync } from "react-dom";
7
7
 
@@ -45,13 +45,12 @@ function useLinkHrefGuardian(...deps) {
45
45
  }
46
46
 
47
47
  // src/ui/SchedulingWidget.tsx
48
- import { useCallback, useEffect, useId, useMemo, useRef, useState as useState2 } from "react";
48
+ import { useEffect, useId, useMemo, useRef, useState as useState2 } from "react";
49
49
 
50
50
  // src/ui/EmailCaptureModal.tsx
51
51
  import { useState } from "react";
52
52
  import { Dialog } from "radix-ui";
53
53
  import { jsx, jsxs } from "react/jsx-runtime";
54
- var isValidEmail = (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
55
54
  function Spinner() {
56
55
  return /* @__PURE__ */ jsxs(
57
56
  "svg",
@@ -85,17 +84,12 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
85
84
  const [error, setError] = useState(null);
86
85
  const isBook = title === "Confirm your spot";
87
86
  const handleSubmit = async () => {
88
- const trimmed = email.trim();
89
- if (!trimmed) return;
90
- if (!isValidEmail(trimmed)) {
91
- setError("Please enter a valid email address.");
92
- return;
93
- }
87
+ if (!email.trim()) return;
94
88
  setLoading(true);
95
89
  setError(null);
96
90
  try {
97
- await onSubmit(trimmed);
98
- setSubmittedEmail(trimmed);
91
+ await onSubmit(email.trim());
92
+ setSubmittedEmail(email.trim());
99
93
  setSuccess(true);
100
94
  } catch (e) {
101
95
  setError(e instanceof Error ? e.message : "Something went wrong. Please try again.");
@@ -170,10 +164,7 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
170
164
  {
171
165
  type: "email",
172
166
  value: email,
173
- onChange: (e) => {
174
- setEmail(e.target.value);
175
- if (error) setError(null);
176
- },
167
+ onChange: (e) => setEmail(e.target.value),
177
168
  onKeyDown: handleKeyDown,
178
169
  placeholder: "hello@gmail.com",
179
170
  autoFocus: true,
@@ -230,20 +221,12 @@ function formatClassTime(cls) {
230
221
  const em = endTotal % 60;
231
222
  return `${h}:${cls.startTime.minutes}-${eh}:${String(em).padStart(2, "0")}`;
232
223
  }
233
- function formatBookingLabel(cls) {
234
- const price = cls.price;
235
- const isFree = price === null || price === void 0 || `${price}` === "" || `${price}` === "0";
236
- return isFree ? "Book for free" : `Book for ${cls.currency ?? ""} ${price}`.trim();
237
- }
238
224
  function getBookingsOnDate(cls, date) {
239
225
  if (!cls.bookings?.length) return 0;
240
- const target = new Date(date);
241
- target.setHours(0, 0, 0, 0);
226
+ const ds = date.toISOString().split("T")[0];
242
227
  return cls.bookings.filter((b) => {
243
228
  try {
244
- const bookingDate = new Date(b.classDate);
245
- bookingDate.setHours(0, 0, 0, 0);
246
- return bookingDate.getTime() === target.getTime();
229
+ return new Date(b.classDate).toISOString().split("T")[0] === ds;
247
230
  } catch {
248
231
  return false;
249
232
  }
@@ -547,7 +530,7 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
547
530
  if (!cls.id) return;
548
531
  onOpenModal?.(isFull ? "waitlist" : "book", cls.id, selectedDate);
549
532
  },
550
- children: isFull ? "Join Waitlist" : formatBookingLabel(cls)
533
+ children: isFull ? "Join Waitlist" : "Book Now"
551
534
  }
552
535
  )
553
536
  ] })
@@ -589,17 +572,6 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
589
572
  const [isHovered, setIsHovered] = useState2(false);
590
573
  const [modalState, setModalState] = useState2(null);
591
574
  const switchScheduleIdRef = useRef(null);
592
- const liveScheduleIdRef = useRef(null);
593
- const refetchLiveSchedule = useCallback(async () => {
594
- const id = liveScheduleIdRef.current;
595
- if (!id) return;
596
- try {
597
- const res = await fetch(`${API_URL}/api/schedule/id/${id}`);
598
- const data = await res.json();
599
- if (data?.id) setSchedule(data);
600
- } catch {
601
- }
602
- }, []);
603
575
  const dates = useMemo(() => {
604
576
  const today = /* @__PURE__ */ new Date();
605
577
  today.setHours(0, 0, 0, 0);
@@ -619,18 +591,6 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
619
591
  }
620
592
  }
621
593
  }, [schedule, dates]);
622
- useEffect(() => {
623
- if (typeof window === "undefined") return;
624
- const onVisible = () => {
625
- if (!document.hidden) void refetchLiveSchedule();
626
- };
627
- window.addEventListener("focus", refetchLiveSchedule);
628
- document.addEventListener("visibilitychange", onVisible);
629
- return () => {
630
- window.removeEventListener("focus", refetchLiveSchedule);
631
- document.removeEventListener("visibilitychange", onVisible);
632
- };
633
- }, [refetchLiveSchedule]);
634
594
  useEffect(() => {
635
595
  if (typeof window === "undefined") return;
636
596
  const isInEditor = window.self !== window.top;
@@ -692,7 +652,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
692
652
  setLoading(false);
693
653
  return;
694
654
  }
695
- liveScheduleIdRef.current = effectiveId;
655
+ ;
696
656
  (async () => {
697
657
  try {
698
658
  const res = await fetch(`${API_URL}/api/schedule/id/${effectiveId}`);
@@ -749,14 +709,18 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
749
709
  const data = await res.json().catch(() => ({}));
750
710
  throw new Error(data?.message ?? "Something went wrong. Please try again.");
751
711
  }
752
- await refetchLiveSchedule();
753
712
  };
754
713
  const handleReplaceSchedule = () => {
755
714
  setIsHovered(false);
756
- window.parent.postMessage(
757
- { type: "ow:scheduling-not-connected", insertAfter, currentScheduleId: schedule?.id },
758
- "*"
759
- );
715
+ if (schedule) {
716
+ window.parent.postMessage({
717
+ type: "ow:schedule-connected",
718
+ schedule: { id: schedule.id, name: schedule.name },
719
+ insertAfter
720
+ }, "*");
721
+ } else {
722
+ window.parent.postMessage({ type: "ow:scheduling-not-connected", insertAfter }, "*");
723
+ }
760
724
  };
761
725
  if (!inEditor && !loading && !schedule) return null;
762
726
  const sectionId = `scheduling-${insertAfter}`;
@@ -799,19 +763,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
799
763
  ),
800
764
  /* @__PURE__ */ jsxs2("div", { className: "max-w-[1280px] mx-auto flex flex-col items-center gap-16", children: [
801
765
  /* @__PURE__ */ jsxs2("div", { className: "flex flex-col items-center gap-4", children: [
802
- /* @__PURE__ */ jsx2(
803
- "h2",
804
- {
805
- className: "font-display text-center m-0 text-(--color-dark,#200C02)",
806
- style: {
807
- fontSize: "var(--fs-section-h2, clamp(40px, 4.4vw, 64px))",
808
- fontWeight: "var(--font-weight-heading, 400)",
809
- lineHeight: 1.05,
810
- letterSpacing: "-0.02em"
811
- },
812
- children: schedule?.name ?? "Book an appointment"
813
- }
814
- ),
766
+ /* @__PURE__ */ jsx2("h2", { className: "font-display text-4xl sm:text-5xl font-bold text-center m-0 text-(--color-dark,#200C02)", children: schedule?.name ?? "Book an appointment" }),
815
767
  schedule?.description && /* @__PURE__ */ jsx2("p", { className: "font-body text-body text-center m-0 text-(--color-accent,#A89B83)", children: schedule.description })
816
768
  ] }),
817
769
  /* @__PURE__ */ jsxs2("div", { className: "w-full flex flex-col items-end gap-3", children: [
@@ -5242,7 +5194,7 @@ function UrlOrPageInput({
5242
5194
  }
5243
5195
 
5244
5196
  // src/ui/link-modal/useLinkModalState.ts
5245
- import { useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo2, useState as useState4 } from "react";
5197
+ import { useCallback, useEffect as useEffect2, useMemo as useMemo2, useState as useState4 } from "react";
5246
5198
  function useLinkModalState({
5247
5199
  open,
5248
5200
  mode,
@@ -5264,7 +5216,7 @@ function useLinkModalState({
5264
5216
  const [step, setStep] = useState4("input");
5265
5217
  const [dropdownOpen, setDropdownOpen] = useState4(false);
5266
5218
  const [urlError, setUrlError] = useState4("");
5267
- const reset = useCallback2(() => {
5219
+ const reset = useCallback(() => {
5268
5220
  setSearchValue("");
5269
5221
  setSelectedPage(null);
5270
5222
  setSelectedSection(null);
@@ -6074,8 +6026,6 @@ var ICONS = {
6074
6026
  insertUnorderedList: '<line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/>',
6075
6027
  insertOrderedList: '<line x1="10" y1="6" x2="21" y2="6"/><line x1="10" y1="12" x2="21" y2="12"/><line x1="10" y1="18" x2="21" y2="18"/><path d="M4 6h1v4"/><path d="M4 10h2"/><path d="M6 18H4c0-1 2-2 2-3s-1-1.5-2-1"/>'
6076
6028
  };
6077
- var TOOLBAR_PILL_PADDING = 2;
6078
- var TOOLBAR_TOGGLE_GAP = 4;
6079
6029
  var TOOLBAR_GROUPS = [
6080
6030
  [
6081
6031
  { cmd: "bold", title: "Bold" },
@@ -6194,9 +6144,9 @@ function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
6194
6144
  const pinnedTop = Math.min(maxBottom - approxH, Math.max(minTop, clip.top + gap));
6195
6145
  return { top: pinnedTop + approxH, transform: "translateX(-50%) translateY(-100%)" };
6196
6146
  }
6197
- function calcToolbarPos(rect, parentScroll, approxW = 306) {
6147
+ function calcToolbarPos(rect, parentScroll, approxW = 330) {
6198
6148
  const GAP = 8;
6199
- const APPROX_H = 32;
6149
+ const APPROX_H = 36;
6200
6150
  const APPROX_W = approxW;
6201
6151
  const clip = getIframeVisibleClip(parentScroll);
6202
6152
  const clipTop = clip?.top ?? 0;
@@ -6254,15 +6204,6 @@ function FloatingToolbar({
6254
6204
  left,
6255
6205
  transform,
6256
6206
  zIndex: 2147483647,
6257
- background: "#fff",
6258
- border: "1px solid #E7E5E4",
6259
- borderRadius: 6,
6260
- boxShadow: "0px 2px 4px -2px rgba(0,0,0,.1),0px 4px 6px -1px rgba(0,0,0,.1)",
6261
- display: "flex",
6262
- alignItems: "center",
6263
- padding: TOOLBAR_PILL_PADDING,
6264
- gap: TOOLBAR_TOGGLE_GAP,
6265
- fontFamily: "sans-serif",
6266
6207
  pointerEvents: "auto"
6267
6208
  },
6268
6209
  children: /* @__PURE__ */ jsxs11(CustomToolbar, { children: [
@@ -6398,7 +6339,7 @@ function OhhwellsBridge() {
6398
6339
  const subdomainFromQuery = searchParams.get("subdomain");
6399
6340
  const subdomain = resolveSubdomain(subdomainFromQuery);
6400
6341
  useLinkHrefGuardian(pathname, subdomain, isEditMode);
6401
- const postToParent = useCallback3((data) => {
6342
+ const postToParent = useCallback2((data) => {
6402
6343
  if (typeof window !== "undefined" && window.parent !== window) {
6403
6344
  window.parent.postMessage(data, "*");
6404
6345
  }
@@ -6412,7 +6353,7 @@ function OhhwellsBridge() {
6412
6353
  const parentScrollRef = useRef3(null);
6413
6354
  const visibleViewportRef = useRef3(null);
6414
6355
  const [dialogPortalContainer, setDialogPortalContainer] = useState5(null);
6415
- const attachVisibleViewport = useCallback3((node) => {
6356
+ const attachVisibleViewport = useCallback2((node) => {
6416
6357
  visibleViewportRef.current = node;
6417
6358
  setDialogPortalContainer(node);
6418
6359
  if (node) applyVisibleViewport(node, parentScrollRef.current);
@@ -6471,7 +6412,7 @@ function OhhwellsBridge() {
6471
6412
  const bumpLinkPopoverGrace = () => {
6472
6413
  linkPopoverGraceUntilRef.current = Date.now() + 350;
6473
6414
  };
6474
- const runSectionsPrefetch = useCallback3((pages) => {
6415
+ const runSectionsPrefetch = useCallback2((pages) => {
6475
6416
  if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
6476
6417
  const gen = ++sectionsPrefetchGenRef.current;
6477
6418
  const paths = pages.map((p) => p.path);
@@ -6581,10 +6522,10 @@ function OhhwellsBridge() {
6581
6522
  vvp.removeEventListener("resize", update);
6582
6523
  };
6583
6524
  }, []);
6584
- const refreshStateRules = useCallback3(() => {
6525
+ const refreshStateRules = useCallback2(() => {
6585
6526
  editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
6586
6527
  }, []);
6587
- const processConfigRequest = useCallback3((insertAfterVal) => {
6528
+ const processConfigRequest = useCallback2((insertAfterVal) => {
6588
6529
  const tracker = getSectionsTracker();
6589
6530
  let entries = [];
6590
6531
  try {
@@ -6607,7 +6548,7 @@ function OhhwellsBridge() {
6607
6548
  }
6608
6549
  window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
6609
6550
  }, [isEditMode]);
6610
- const deactivate = useCallback3(() => {
6551
+ const deactivate = useCallback2(() => {
6611
6552
  const el = activeElRef.current;
6612
6553
  if (!el) return;
6613
6554
  const key = el.dataset.ohwKey;
@@ -6638,7 +6579,7 @@ function OhhwellsBridge() {
6638
6579
  setToolbarShowEditLink(false);
6639
6580
  postToParent({ type: "ow:exit-edit" });
6640
6581
  }, [postToParent]);
6641
- const deselect = useCallback3(() => {
6582
+ const deselect = useCallback2(() => {
6642
6583
  selectedElRef.current = null;
6643
6584
  setReorderHrefKey(null);
6644
6585
  setReorderDragDisabled(false);
@@ -6650,7 +6591,7 @@ function OhhwellsBridge() {
6650
6591
  setToolbarVariant("none");
6651
6592
  }
6652
6593
  }, []);
6653
- const reselectNavigationItem = useCallback3((navAnchor) => {
6594
+ const reselectNavigationItem = useCallback2((navAnchor) => {
6654
6595
  selectedElRef.current = navAnchor;
6655
6596
  const { key, disabled } = getNavigationItemReorderState(navAnchor);
6656
6597
  setReorderHrefKey(key);
@@ -6660,7 +6601,7 @@ function OhhwellsBridge() {
6660
6601
  setToolbarShowEditLink(false);
6661
6602
  setActiveCommands(/* @__PURE__ */ new Set());
6662
6603
  }, []);
6663
- const commitNavigationTextEdit = useCallback3((navAnchor) => {
6604
+ const commitNavigationTextEdit = useCallback2((navAnchor) => {
6664
6605
  const el = activeElRef.current;
6665
6606
  if (!el) return;
6666
6607
  const key = el.dataset.ohwKey;
@@ -6686,24 +6627,24 @@ function OhhwellsBridge() {
6686
6627
  postToParent({ type: "ow:exit-edit" });
6687
6628
  reselectNavigationItem(navAnchor);
6688
6629
  }, [postToParent, reselectNavigationItem]);
6689
- const handleAddNavigationItem = useCallback3(() => {
6630
+ const handleAddNavigationItem = useCallback2(() => {
6690
6631
  const selected = selectedElRef.current;
6691
6632
  if (!selected) return;
6692
6633
  const target = getNavigationItemAddHintTarget(selected);
6693
6634
  siblingHintElRef.current = target;
6694
6635
  setSiblingHintRect(target.getBoundingClientRect());
6695
6636
  }, []);
6696
- const handleItemDragStart = useCallback3(() => {
6637
+ const handleItemDragStart = useCallback2(() => {
6697
6638
  siblingHintElRef.current = null;
6698
6639
  setSiblingHintRect(null);
6699
6640
  setIsItemDragging(true);
6700
6641
  }, []);
6701
- const handleItemDragEnd = useCallback3(() => {
6642
+ const handleItemDragEnd = useCallback2(() => {
6702
6643
  setIsItemDragging(false);
6703
6644
  }, []);
6704
6645
  reselectNavigationItemRef.current = reselectNavigationItem;
6705
6646
  commitNavigationTextEditRef.current = commitNavigationTextEdit;
6706
- const select = useCallback3((anchor) => {
6647
+ const select = useCallback2((anchor) => {
6707
6648
  if (!isNavigationItem(anchor)) return;
6708
6649
  if (activeElRef.current) deactivate();
6709
6650
  selectedElRef.current = anchor;
@@ -6721,7 +6662,7 @@ function OhhwellsBridge() {
6721
6662
  setToolbarShowEditLink(false);
6722
6663
  setActiveCommands(/* @__PURE__ */ new Set());
6723
6664
  }, [deactivate]);
6724
- const activate = useCallback3((el) => {
6665
+ const activate = useCallback2((el) => {
6725
6666
  if (activeElRef.current === el) return;
6726
6667
  selectedElRef.current = null;
6727
6668
  deactivate();
@@ -8000,13 +7941,13 @@ function OhhwellsBridge() {
8000
7941
  window.addEventListener("hashchange", onHashChange);
8001
7942
  return () => window.removeEventListener("hashchange", onHashChange);
8002
7943
  }, [pathname]);
8003
- const handleCommand = useCallback3((cmd) => {
7944
+ const handleCommand = useCallback2((cmd) => {
8004
7945
  document.execCommand(cmd, false);
8005
7946
  activeElRef.current?.focus();
8006
7947
  if (activeElRef.current) setToolbarRect(getEditMeasureEl(activeElRef.current).getBoundingClientRect());
8007
7948
  refreshActiveCommandsRef.current();
8008
7949
  }, []);
8009
- const handleStateChange = useCallback3((state) => {
7950
+ const handleStateChange = useCallback2((state) => {
8010
7951
  if (!activeStateElRef.current) return;
8011
7952
  const el = activeStateElRef.current;
8012
7953
  if (state === "Default") {
@@ -8019,8 +7960,8 @@ function OhhwellsBridge() {
8019
7960
  }
8020
7961
  setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
8021
7962
  }, [deactivate]);
8022
- const closeLinkPopover = useCallback3(() => setLinkPopover(null), []);
8023
- const openLinkPopoverForActive = useCallback3(() => {
7963
+ const closeLinkPopover = useCallback2(() => setLinkPopover(null), []);
7964
+ const openLinkPopoverForActive = useCallback2(() => {
8024
7965
  const hrefCtx = getHrefKeyFromElement(activeElRef.current);
8025
7966
  if (!hrefCtx) return;
8026
7967
  bumpLinkPopoverGrace();
@@ -8030,7 +7971,7 @@ function OhhwellsBridge() {
8030
7971
  });
8031
7972
  deactivate();
8032
7973
  }, [deactivate]);
8033
- const openLinkPopoverForSelected = useCallback3(() => {
7974
+ const openLinkPopoverForSelected = useCallback2(() => {
8034
7975
  const anchor = selectedElRef.current;
8035
7976
  if (!anchor) return;
8036
7977
  const key = anchor.getAttribute("data-ohw-href-key");
@@ -8042,7 +7983,7 @@ function OhhwellsBridge() {
8042
7983
  });
8043
7984
  deselect();
8044
7985
  }, [deselect]);
8045
- const handleLinkPopoverSubmit = useCallback3(
7986
+ const handleLinkPopoverSubmit = useCallback2(
8046
7987
  (target) => {
8047
7988
  if (!linkPopover) return;
8048
7989
  const { key } = linkPopover;
@@ -8179,32 +8120,7 @@ function OhhwellsBridge() {
8179
8120
  onSubmit: handleLinkPopoverSubmit
8180
8121
  },
8181
8122
  `${linkPopover.key}-${pathname}`
8182
- ) : null,
8183
- sectionGap && /* @__PURE__ */ jsxs11(
8184
- "div",
8185
- {
8186
- "data-ohw-section-insert-line": "",
8187
- className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
8188
- style: { top: sectionGap.y, transform: "translateY(-50%)" },
8189
- children: [
8190
- /* @__PURE__ */ jsx21("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
8191
- /* @__PURE__ */ jsx21(
8192
- Badge,
8193
- {
8194
- className: "px-8 py-1 bg-primary hover:bg-primary text-primary-foreground text-xs font-medium shrink-0 rounded-full cursor-pointer pointer-events-auto",
8195
- onClick: () => {
8196
- window.parent.postMessage(
8197
- { type: "ow:add-section", insertAfter: sectionGap.insertAfter, insertBefore: sectionGap.insertBefore },
8198
- "*"
8199
- );
8200
- },
8201
- children: "Add Section"
8202
- }
8203
- ),
8204
- /* @__PURE__ */ jsx21("div", { className: "flex-1 bg-primary", style: { height: 3 } })
8205
- ]
8206
- }
8207
- )
8123
+ ) : null
8208
8124
  ] }),
8209
8125
  bridgeRoot
8210
8126
  ) : null;