@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/README.md +0 -12
- package/dist/index.cjs +21 -105
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +45 -129
- package/dist/index.js.map +1 -1
- package/dist/styles.css +18 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -318,18 +318,6 @@ npm run build
|
|
|
318
318
|
npm publish --access public
|
|
319
319
|
```
|
|
320
320
|
|
|
321
|
-
### Staging → rebound-template auto-bump
|
|
322
|
-
|
|
323
|
-
When `staging` publishes successfully, the bridge workflow dispatches a `bridge-published` event to `TheFlowOps-Eng/rebound-template`. That repo’s `bump-bridge.yml` workflow checks out `staging`, runs `npm install @ohhwells/bridge@<version> --save-exact`, and pushes the lockfile bump.
|
|
324
|
-
|
|
325
|
-
**One-time setup** (in `ohhwells-bridge` GitHub repo → Settings → Secrets):
|
|
326
|
-
|
|
327
|
-
| Secret | Value |
|
|
328
|
-
|--------|--------|
|
|
329
|
-
| `REBOUND_TEMPLATE_DISPATCH_TOKEN` | Fine-grained or classic PAT with `repo` access to `rebound-template` (needs permission to trigger `repository_dispatch`) |
|
|
330
|
-
|
|
331
|
-
The published staging version looks like `0.1.31-next.42` and is tagged `next` on npm.
|
|
332
|
-
|
|
333
321
|
---
|
|
334
322
|
|
|
335
323
|
## Link dialog (Canvas Editor)
|
package/dist/index.cjs
CHANGED
|
@@ -110,7 +110,6 @@ var import_react3 = require("react");
|
|
|
110
110
|
var import_react2 = require("react");
|
|
111
111
|
var import_radix_ui = require("radix-ui");
|
|
112
112
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
113
|
-
var isValidEmail = (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
|
|
114
113
|
function Spinner() {
|
|
115
114
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
116
115
|
"svg",
|
|
@@ -144,17 +143,12 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
|
|
|
144
143
|
const [error, setError] = (0, import_react2.useState)(null);
|
|
145
144
|
const isBook = title === "Confirm your spot";
|
|
146
145
|
const handleSubmit = async () => {
|
|
147
|
-
|
|
148
|
-
if (!trimmed) return;
|
|
149
|
-
if (!isValidEmail(trimmed)) {
|
|
150
|
-
setError("Please enter a valid email address.");
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
146
|
+
if (!email.trim()) return;
|
|
153
147
|
setLoading(true);
|
|
154
148
|
setError(null);
|
|
155
149
|
try {
|
|
156
|
-
await onSubmit(
|
|
157
|
-
setSubmittedEmail(
|
|
150
|
+
await onSubmit(email.trim());
|
|
151
|
+
setSubmittedEmail(email.trim());
|
|
158
152
|
setSuccess(true);
|
|
159
153
|
} catch (e) {
|
|
160
154
|
setError(e instanceof Error ? e.message : "Something went wrong. Please try again.");
|
|
@@ -229,10 +223,7 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
|
|
|
229
223
|
{
|
|
230
224
|
type: "email",
|
|
231
225
|
value: email,
|
|
232
|
-
onChange: (e) =>
|
|
233
|
-
setEmail(e.target.value);
|
|
234
|
-
if (error) setError(null);
|
|
235
|
-
},
|
|
226
|
+
onChange: (e) => setEmail(e.target.value),
|
|
236
227
|
onKeyDown: handleKeyDown,
|
|
237
228
|
placeholder: "hello@gmail.com",
|
|
238
229
|
autoFocus: true,
|
|
@@ -289,20 +280,12 @@ function formatClassTime(cls) {
|
|
|
289
280
|
const em = endTotal % 60;
|
|
290
281
|
return `${h}:${cls.startTime.minutes}-${eh}:${String(em).padStart(2, "0")}`;
|
|
291
282
|
}
|
|
292
|
-
function formatBookingLabel(cls) {
|
|
293
|
-
const price = cls.price;
|
|
294
|
-
const isFree = price === null || price === void 0 || `${price}` === "" || `${price}` === "0";
|
|
295
|
-
return isFree ? "Book for free" : `Book for ${cls.currency ?? ""} ${price}`.trim();
|
|
296
|
-
}
|
|
297
283
|
function getBookingsOnDate(cls, date) {
|
|
298
284
|
if (!cls.bookings?.length) return 0;
|
|
299
|
-
const
|
|
300
|
-
target.setHours(0, 0, 0, 0);
|
|
285
|
+
const ds = date.toISOString().split("T")[0];
|
|
301
286
|
return cls.bookings.filter((b) => {
|
|
302
287
|
try {
|
|
303
|
-
|
|
304
|
-
bookingDate.setHours(0, 0, 0, 0);
|
|
305
|
-
return bookingDate.getTime() === target.getTime();
|
|
288
|
+
return new Date(b.classDate).toISOString().split("T")[0] === ds;
|
|
306
289
|
} catch {
|
|
307
290
|
return false;
|
|
308
291
|
}
|
|
@@ -606,7 +589,7 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
|
|
|
606
589
|
if (!cls.id) return;
|
|
607
590
|
onOpenModal?.(isFull ? "waitlist" : "book", cls.id, selectedDate);
|
|
608
591
|
},
|
|
609
|
-
children: isFull ? "Join Waitlist" :
|
|
592
|
+
children: isFull ? "Join Waitlist" : "Book Now"
|
|
610
593
|
}
|
|
611
594
|
)
|
|
612
595
|
] })
|
|
@@ -648,17 +631,6 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
648
631
|
const [isHovered, setIsHovered] = (0, import_react3.useState)(false);
|
|
649
632
|
const [modalState, setModalState] = (0, import_react3.useState)(null);
|
|
650
633
|
const switchScheduleIdRef = (0, import_react3.useRef)(null);
|
|
651
|
-
const liveScheduleIdRef = (0, import_react3.useRef)(null);
|
|
652
|
-
const refetchLiveSchedule = (0, import_react3.useCallback)(async () => {
|
|
653
|
-
const id = liveScheduleIdRef.current;
|
|
654
|
-
if (!id) return;
|
|
655
|
-
try {
|
|
656
|
-
const res = await fetch(`${API_URL}/api/schedule/id/${id}`);
|
|
657
|
-
const data = await res.json();
|
|
658
|
-
if (data?.id) setSchedule(data);
|
|
659
|
-
} catch {
|
|
660
|
-
}
|
|
661
|
-
}, []);
|
|
662
634
|
const dates = (0, import_react3.useMemo)(() => {
|
|
663
635
|
const today = /* @__PURE__ */ new Date();
|
|
664
636
|
today.setHours(0, 0, 0, 0);
|
|
@@ -678,18 +650,6 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
678
650
|
}
|
|
679
651
|
}
|
|
680
652
|
}, [schedule, dates]);
|
|
681
|
-
(0, import_react3.useEffect)(() => {
|
|
682
|
-
if (typeof window === "undefined") return;
|
|
683
|
-
const onVisible = () => {
|
|
684
|
-
if (!document.hidden) void refetchLiveSchedule();
|
|
685
|
-
};
|
|
686
|
-
window.addEventListener("focus", refetchLiveSchedule);
|
|
687
|
-
document.addEventListener("visibilitychange", onVisible);
|
|
688
|
-
return () => {
|
|
689
|
-
window.removeEventListener("focus", refetchLiveSchedule);
|
|
690
|
-
document.removeEventListener("visibilitychange", onVisible);
|
|
691
|
-
};
|
|
692
|
-
}, [refetchLiveSchedule]);
|
|
693
653
|
(0, import_react3.useEffect)(() => {
|
|
694
654
|
if (typeof window === "undefined") return;
|
|
695
655
|
const isInEditor = window.self !== window.top;
|
|
@@ -751,7 +711,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
751
711
|
setLoading(false);
|
|
752
712
|
return;
|
|
753
713
|
}
|
|
754
|
-
|
|
714
|
+
;
|
|
755
715
|
(async () => {
|
|
756
716
|
try {
|
|
757
717
|
const res = await fetch(`${API_URL}/api/schedule/id/${effectiveId}`);
|
|
@@ -808,14 +768,18 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
808
768
|
const data = await res.json().catch(() => ({}));
|
|
809
769
|
throw new Error(data?.message ?? "Something went wrong. Please try again.");
|
|
810
770
|
}
|
|
811
|
-
await refetchLiveSchedule();
|
|
812
771
|
};
|
|
813
772
|
const handleReplaceSchedule = () => {
|
|
814
773
|
setIsHovered(false);
|
|
815
|
-
|
|
816
|
-
{
|
|
817
|
-
|
|
818
|
-
|
|
774
|
+
if (schedule) {
|
|
775
|
+
window.parent.postMessage({
|
|
776
|
+
type: "ow:schedule-connected",
|
|
777
|
+
schedule: { id: schedule.id, name: schedule.name },
|
|
778
|
+
insertAfter
|
|
779
|
+
}, "*");
|
|
780
|
+
} else {
|
|
781
|
+
window.parent.postMessage({ type: "ow:scheduling-not-connected", insertAfter }, "*");
|
|
782
|
+
}
|
|
819
783
|
};
|
|
820
784
|
if (!inEditor && !loading && !schedule) return null;
|
|
821
785
|
const sectionId = `scheduling-${insertAfter}`;
|
|
@@ -858,19 +822,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
858
822
|
),
|
|
859
823
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "max-w-[1280px] mx-auto flex flex-col items-center gap-16", children: [
|
|
860
824
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col items-center gap-4", children: [
|
|
861
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
862
|
-
"h2",
|
|
863
|
-
{
|
|
864
|
-
className: "font-display text-center m-0 text-(--color-dark,#200C02)",
|
|
865
|
-
style: {
|
|
866
|
-
fontSize: "var(--fs-section-h2, clamp(40px, 4.4vw, 64px))",
|
|
867
|
-
fontWeight: "var(--font-weight-heading, 400)",
|
|
868
|
-
lineHeight: 1.05,
|
|
869
|
-
letterSpacing: "-0.02em"
|
|
870
|
-
},
|
|
871
|
-
children: schedule?.name ?? "Book an appointment"
|
|
872
|
-
}
|
|
873
|
-
),
|
|
825
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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" }),
|
|
874
826
|
schedule?.description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "font-body text-body text-center m-0 text-(--color-accent,#A89B83)", children: schedule.description })
|
|
875
827
|
] }),
|
|
876
828
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "w-full flex flex-col items-end gap-3", children: [
|
|
@@ -6133,8 +6085,6 @@ var ICONS = {
|
|
|
6133
6085
|
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"/>',
|
|
6134
6086
|
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"/>'
|
|
6135
6087
|
};
|
|
6136
|
-
var TOOLBAR_PILL_PADDING = 2;
|
|
6137
|
-
var TOOLBAR_TOGGLE_GAP = 4;
|
|
6138
6088
|
var TOOLBAR_GROUPS = [
|
|
6139
6089
|
[
|
|
6140
6090
|
{ cmd: "bold", title: "Bold" },
|
|
@@ -6253,9 +6203,9 @@ function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
|
|
|
6253
6203
|
const pinnedTop = Math.min(maxBottom - approxH, Math.max(minTop, clip.top + gap));
|
|
6254
6204
|
return { top: pinnedTop + approxH, transform: "translateX(-50%) translateY(-100%)" };
|
|
6255
6205
|
}
|
|
6256
|
-
function calcToolbarPos(rect, parentScroll, approxW =
|
|
6206
|
+
function calcToolbarPos(rect, parentScroll, approxW = 330) {
|
|
6257
6207
|
const GAP = 8;
|
|
6258
|
-
const APPROX_H =
|
|
6208
|
+
const APPROX_H = 36;
|
|
6259
6209
|
const APPROX_W = approxW;
|
|
6260
6210
|
const clip = getIframeVisibleClip(parentScroll);
|
|
6261
6211
|
const clipTop = clip?.top ?? 0;
|
|
@@ -6313,15 +6263,6 @@ function FloatingToolbar({
|
|
|
6313
6263
|
left,
|
|
6314
6264
|
transform,
|
|
6315
6265
|
zIndex: 2147483647,
|
|
6316
|
-
background: "#fff",
|
|
6317
|
-
border: "1px solid #E7E5E4",
|
|
6318
|
-
borderRadius: 6,
|
|
6319
|
-
boxShadow: "0px 2px 4px -2px rgba(0,0,0,.1),0px 4px 6px -1px rgba(0,0,0,.1)",
|
|
6320
|
-
display: "flex",
|
|
6321
|
-
alignItems: "center",
|
|
6322
|
-
padding: TOOLBAR_PILL_PADDING,
|
|
6323
|
-
gap: TOOLBAR_TOGGLE_GAP,
|
|
6324
|
-
fontFamily: "sans-serif",
|
|
6325
6266
|
pointerEvents: "auto"
|
|
6326
6267
|
},
|
|
6327
6268
|
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(CustomToolbar, { children: [
|
|
@@ -8238,32 +8179,7 @@ function OhhwellsBridge() {
|
|
|
8238
8179
|
onSubmit: handleLinkPopoverSubmit
|
|
8239
8180
|
},
|
|
8240
8181
|
`${linkPopover.key}-${pathname}`
|
|
8241
|
-
) : null
|
|
8242
|
-
sectionGap && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
8243
|
-
"div",
|
|
8244
|
-
{
|
|
8245
|
-
"data-ohw-section-insert-line": "",
|
|
8246
|
-
className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
|
|
8247
|
-
style: { top: sectionGap.y, transform: "translateY(-50%)" },
|
|
8248
|
-
children: [
|
|
8249
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
|
|
8250
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
8251
|
-
Badge,
|
|
8252
|
-
{
|
|
8253
|
-
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",
|
|
8254
|
-
onClick: () => {
|
|
8255
|
-
window.parent.postMessage(
|
|
8256
|
-
{ type: "ow:add-section", insertAfter: sectionGap.insertAfter, insertBefore: sectionGap.insertBefore },
|
|
8257
|
-
"*"
|
|
8258
|
-
);
|
|
8259
|
-
},
|
|
8260
|
-
children: "Add Section"
|
|
8261
|
-
}
|
|
8262
|
-
),
|
|
8263
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
|
|
8264
|
-
]
|
|
8265
|
-
}
|
|
8266
|
-
)
|
|
8182
|
+
) : null
|
|
8267
8183
|
] }),
|
|
8268
8184
|
bridgeRoot
|
|
8269
8185
|
) : null;
|