@ohhwells/bridge 0.1.34-next.40 → 0.1.34-next.44

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 useCallback2, useEffect as useEffect3, useLayoutEffect as useLayoutEffect2, useRef as useRef3, useState as useState5 } from "react";
4
+ import React8, { useCallback as useCallback3, 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,12 +45,13 @@ function useLinkHrefGuardian(...deps) {
45
45
  }
46
46
 
47
47
  // src/ui/SchedulingWidget.tsx
48
- import { useEffect, useId, useMemo, useRef, useState as useState2 } from "react";
48
+ import { useCallback, 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);
54
55
  function Spinner() {
55
56
  return /* @__PURE__ */ jsxs(
56
57
  "svg",
@@ -84,12 +85,17 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
84
85
  const [error, setError] = useState(null);
85
86
  const isBook = title === "Confirm your spot";
86
87
  const handleSubmit = async () => {
87
- if (!email.trim()) return;
88
+ const trimmed = email.trim();
89
+ if (!trimmed) return;
90
+ if (!isValidEmail(trimmed)) {
91
+ setError("Please enter a valid email address.");
92
+ return;
93
+ }
88
94
  setLoading(true);
89
95
  setError(null);
90
96
  try {
91
- await onSubmit(email.trim());
92
- setSubmittedEmail(email.trim());
97
+ await onSubmit(trimmed);
98
+ setSubmittedEmail(trimmed);
93
99
  setSuccess(true);
94
100
  } catch (e) {
95
101
  setError(e instanceof Error ? e.message : "Something went wrong. Please try again.");
@@ -164,7 +170,10 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
164
170
  {
165
171
  type: "email",
166
172
  value: email,
167
- onChange: (e) => setEmail(e.target.value),
173
+ onChange: (e) => {
174
+ setEmail(e.target.value);
175
+ if (error) setError(null);
176
+ },
168
177
  onKeyDown: handleKeyDown,
169
178
  placeholder: "hello@gmail.com",
170
179
  autoFocus: true,
@@ -580,6 +589,17 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
580
589
  const [isHovered, setIsHovered] = useState2(false);
581
590
  const [modalState, setModalState] = useState2(null);
582
591
  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
+ }, []);
583
603
  const dates = useMemo(() => {
584
604
  const today = /* @__PURE__ */ new Date();
585
605
  today.setHours(0, 0, 0, 0);
@@ -599,6 +619,18 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
599
619
  }
600
620
  }
601
621
  }, [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]);
602
634
  useEffect(() => {
603
635
  if (typeof window === "undefined") return;
604
636
  const isInEditor = window.self !== window.top;
@@ -660,7 +692,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
660
692
  setLoading(false);
661
693
  return;
662
694
  }
663
- ;
695
+ liveScheduleIdRef.current = effectiveId;
664
696
  (async () => {
665
697
  try {
666
698
  const res = await fetch(`${API_URL}/api/schedule/id/${effectiveId}`);
@@ -717,6 +749,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
717
749
  const data = await res.json().catch(() => ({}));
718
750
  throw new Error(data?.message ?? "Something went wrong. Please try again.");
719
751
  }
752
+ await refetchLiveSchedule();
720
753
  };
721
754
  const handleReplaceSchedule = () => {
722
755
  setIsHovered(false);
@@ -5209,7 +5242,7 @@ function UrlOrPageInput({
5209
5242
  }
5210
5243
 
5211
5244
  // src/ui/link-modal/useLinkModalState.ts
5212
- import { useCallback, useEffect as useEffect2, useMemo as useMemo2, useState as useState4 } from "react";
5245
+ import { useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo2, useState as useState4 } from "react";
5213
5246
  function useLinkModalState({
5214
5247
  open,
5215
5248
  mode,
@@ -5231,7 +5264,7 @@ function useLinkModalState({
5231
5264
  const [step, setStep] = useState4("input");
5232
5265
  const [dropdownOpen, setDropdownOpen] = useState4(false);
5233
5266
  const [urlError, setUrlError] = useState4("");
5234
- const reset = useCallback(() => {
5267
+ const reset = useCallback2(() => {
5235
5268
  setSearchValue("");
5236
5269
  setSelectedPage(null);
5237
5270
  setSelectedSection(null);
@@ -6365,7 +6398,7 @@ function OhhwellsBridge() {
6365
6398
  const subdomainFromQuery = searchParams.get("subdomain");
6366
6399
  const subdomain = resolveSubdomain(subdomainFromQuery);
6367
6400
  useLinkHrefGuardian(pathname, subdomain, isEditMode);
6368
- const postToParent = useCallback2((data) => {
6401
+ const postToParent = useCallback3((data) => {
6369
6402
  if (typeof window !== "undefined" && window.parent !== window) {
6370
6403
  window.parent.postMessage(data, "*");
6371
6404
  }
@@ -6379,7 +6412,7 @@ function OhhwellsBridge() {
6379
6412
  const parentScrollRef = useRef3(null);
6380
6413
  const visibleViewportRef = useRef3(null);
6381
6414
  const [dialogPortalContainer, setDialogPortalContainer] = useState5(null);
6382
- const attachVisibleViewport = useCallback2((node) => {
6415
+ const attachVisibleViewport = useCallback3((node) => {
6383
6416
  visibleViewportRef.current = node;
6384
6417
  setDialogPortalContainer(node);
6385
6418
  if (node) applyVisibleViewport(node, parentScrollRef.current);
@@ -6438,7 +6471,7 @@ function OhhwellsBridge() {
6438
6471
  const bumpLinkPopoverGrace = () => {
6439
6472
  linkPopoverGraceUntilRef.current = Date.now() + 350;
6440
6473
  };
6441
- const runSectionsPrefetch = useCallback2((pages) => {
6474
+ const runSectionsPrefetch = useCallback3((pages) => {
6442
6475
  if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
6443
6476
  const gen = ++sectionsPrefetchGenRef.current;
6444
6477
  const paths = pages.map((p) => p.path);
@@ -6548,10 +6581,10 @@ function OhhwellsBridge() {
6548
6581
  vvp.removeEventListener("resize", update);
6549
6582
  };
6550
6583
  }, []);
6551
- const refreshStateRules = useCallback2(() => {
6584
+ const refreshStateRules = useCallback3(() => {
6552
6585
  editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
6553
6586
  }, []);
6554
- const processConfigRequest = useCallback2((insertAfterVal) => {
6587
+ const processConfigRequest = useCallback3((insertAfterVal) => {
6555
6588
  const tracker = getSectionsTracker();
6556
6589
  let entries = [];
6557
6590
  try {
@@ -6574,7 +6607,7 @@ function OhhwellsBridge() {
6574
6607
  }
6575
6608
  window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
6576
6609
  }, [isEditMode]);
6577
- const deactivate = useCallback2(() => {
6610
+ const deactivate = useCallback3(() => {
6578
6611
  const el = activeElRef.current;
6579
6612
  if (!el) return;
6580
6613
  const key = el.dataset.ohwKey;
@@ -6605,7 +6638,7 @@ function OhhwellsBridge() {
6605
6638
  setToolbarShowEditLink(false);
6606
6639
  postToParent({ type: "ow:exit-edit" });
6607
6640
  }, [postToParent]);
6608
- const deselect = useCallback2(() => {
6641
+ const deselect = useCallback3(() => {
6609
6642
  selectedElRef.current = null;
6610
6643
  setReorderHrefKey(null);
6611
6644
  setReorderDragDisabled(false);
@@ -6617,7 +6650,7 @@ function OhhwellsBridge() {
6617
6650
  setToolbarVariant("none");
6618
6651
  }
6619
6652
  }, []);
6620
- const reselectNavigationItem = useCallback2((navAnchor) => {
6653
+ const reselectNavigationItem = useCallback3((navAnchor) => {
6621
6654
  selectedElRef.current = navAnchor;
6622
6655
  const { key, disabled } = getNavigationItemReorderState(navAnchor);
6623
6656
  setReorderHrefKey(key);
@@ -6627,7 +6660,7 @@ function OhhwellsBridge() {
6627
6660
  setToolbarShowEditLink(false);
6628
6661
  setActiveCommands(/* @__PURE__ */ new Set());
6629
6662
  }, []);
6630
- const commitNavigationTextEdit = useCallback2((navAnchor) => {
6663
+ const commitNavigationTextEdit = useCallback3((navAnchor) => {
6631
6664
  const el = activeElRef.current;
6632
6665
  if (!el) return;
6633
6666
  const key = el.dataset.ohwKey;
@@ -6653,24 +6686,24 @@ function OhhwellsBridge() {
6653
6686
  postToParent({ type: "ow:exit-edit" });
6654
6687
  reselectNavigationItem(navAnchor);
6655
6688
  }, [postToParent, reselectNavigationItem]);
6656
- const handleAddNavigationItem = useCallback2(() => {
6689
+ const handleAddNavigationItem = useCallback3(() => {
6657
6690
  const selected = selectedElRef.current;
6658
6691
  if (!selected) return;
6659
6692
  const target = getNavigationItemAddHintTarget(selected);
6660
6693
  siblingHintElRef.current = target;
6661
6694
  setSiblingHintRect(target.getBoundingClientRect());
6662
6695
  }, []);
6663
- const handleItemDragStart = useCallback2(() => {
6696
+ const handleItemDragStart = useCallback3(() => {
6664
6697
  siblingHintElRef.current = null;
6665
6698
  setSiblingHintRect(null);
6666
6699
  setIsItemDragging(true);
6667
6700
  }, []);
6668
- const handleItemDragEnd = useCallback2(() => {
6701
+ const handleItemDragEnd = useCallback3(() => {
6669
6702
  setIsItemDragging(false);
6670
6703
  }, []);
6671
6704
  reselectNavigationItemRef.current = reselectNavigationItem;
6672
6705
  commitNavigationTextEditRef.current = commitNavigationTextEdit;
6673
- const select = useCallback2((anchor) => {
6706
+ const select = useCallback3((anchor) => {
6674
6707
  if (!isNavigationItem(anchor)) return;
6675
6708
  if (activeElRef.current) deactivate();
6676
6709
  selectedElRef.current = anchor;
@@ -6688,7 +6721,7 @@ function OhhwellsBridge() {
6688
6721
  setToolbarShowEditLink(false);
6689
6722
  setActiveCommands(/* @__PURE__ */ new Set());
6690
6723
  }, [deactivate]);
6691
- const activate = useCallback2((el) => {
6724
+ const activate = useCallback3((el) => {
6692
6725
  if (activeElRef.current === el) return;
6693
6726
  selectedElRef.current = null;
6694
6727
  deactivate();
@@ -7967,13 +8000,13 @@ function OhhwellsBridge() {
7967
8000
  window.addEventListener("hashchange", onHashChange);
7968
8001
  return () => window.removeEventListener("hashchange", onHashChange);
7969
8002
  }, [pathname]);
7970
- const handleCommand = useCallback2((cmd) => {
8003
+ const handleCommand = useCallback3((cmd) => {
7971
8004
  document.execCommand(cmd, false);
7972
8005
  activeElRef.current?.focus();
7973
8006
  if (activeElRef.current) setToolbarRect(getEditMeasureEl(activeElRef.current).getBoundingClientRect());
7974
8007
  refreshActiveCommandsRef.current();
7975
8008
  }, []);
7976
- const handleStateChange = useCallback2((state) => {
8009
+ const handleStateChange = useCallback3((state) => {
7977
8010
  if (!activeStateElRef.current) return;
7978
8011
  const el = activeStateElRef.current;
7979
8012
  if (state === "Default") {
@@ -7986,8 +8019,8 @@ function OhhwellsBridge() {
7986
8019
  }
7987
8020
  setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
7988
8021
  }, [deactivate]);
7989
- const closeLinkPopover = useCallback2(() => setLinkPopover(null), []);
7990
- const openLinkPopoverForActive = useCallback2(() => {
8022
+ const closeLinkPopover = useCallback3(() => setLinkPopover(null), []);
8023
+ const openLinkPopoverForActive = useCallback3(() => {
7991
8024
  const hrefCtx = getHrefKeyFromElement(activeElRef.current);
7992
8025
  if (!hrefCtx) return;
7993
8026
  bumpLinkPopoverGrace();
@@ -7997,7 +8030,7 @@ function OhhwellsBridge() {
7997
8030
  });
7998
8031
  deactivate();
7999
8032
  }, [deactivate]);
8000
- const openLinkPopoverForSelected = useCallback2(() => {
8033
+ const openLinkPopoverForSelected = useCallback3(() => {
8001
8034
  const anchor = selectedElRef.current;
8002
8035
  if (!anchor) return;
8003
8036
  const key = anchor.getAttribute("data-ohw-href-key");
@@ -8009,7 +8042,7 @@ function OhhwellsBridge() {
8009
8042
  });
8010
8043
  deselect();
8011
8044
  }, [deselect]);
8012
- const handleLinkPopoverSubmit = useCallback2(
8045
+ const handleLinkPopoverSubmit = useCallback3(
8013
8046
  (target) => {
8014
8047
  if (!linkPopover) return;
8015
8048
  const { key } = linkPopover;