@ohhwells/bridge 0.1.18 → 0.1.19

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.js CHANGED
@@ -1,10 +1,428 @@
1
1
  "use client";
2
2
 
3
3
  // src/OhhwellsBridge.tsx
4
- import React2, { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
4
+ import React3, { useCallback, useEffect as useEffect2, useLayoutEffect, useRef, useState as useState2 } from "react";
5
+ import { createRoot } from "react-dom/client";
6
+
7
+ // src/ui/SchedulingWidget.tsx
8
+ import React, { useEffect, useMemo, useState } from "react";
9
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
10
+ var API_URL = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
11
+ var DAY_ABBR = ["SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"];
12
+ function getApiDomain() {
13
+ const h = window.location.hostname;
14
+ for (const base of ["ohhwells.site", "theflowops-staging.com", "theflowops.com"]) {
15
+ if (h.endsWith(`.${base}`)) return h.slice(0, -(base.length + 1));
16
+ }
17
+ return h;
18
+ }
19
+ function classRunsOnDate(cls, date, type) {
20
+ if (type === "FIXED") {
21
+ const d = String(date.getDate()).padStart(2, "0");
22
+ const m = String(date.getMonth() + 1).padStart(2, "0");
23
+ return cls.fixedDates?.some((fd) => fd.date === `${d}-${m}-${date.getFullYear()}`) ?? false;
24
+ }
25
+ return cls.weekdays?.some((w) => w.weekday === date.getDay()) ?? false;
26
+ }
27
+ function formatClassTime(cls) {
28
+ let h = parseInt(cls.startTime.hour, 10);
29
+ const m = parseInt(cls.startTime.minutes, 10);
30
+ if (cls.startTime.time === "PM" && h !== 12) h += 12;
31
+ if (cls.startTime.time === "AM" && h === 12) h = 0;
32
+ const endTotal = h * 60 + m + cls.duration;
33
+ const eh = Math.floor(endTotal / 60) % 24;
34
+ const em = endTotal % 60;
35
+ return `${h}:${cls.startTime.minutes}-${eh}:${String(em).padStart(2, "0")}`;
36
+ }
37
+ function getBookingsOnDate(cls, date) {
38
+ if (!cls.bookings?.length) return 0;
39
+ const ds = date.toISOString().split("T")[0];
40
+ return cls.bookings.filter((b) => {
41
+ try {
42
+ return new Date(b.classDate).toISOString().split("T")[0] === ds;
43
+ } catch {
44
+ return false;
45
+ }
46
+ }).length;
47
+ }
48
+ function buildTimezoneLabel(tz) {
49
+ try {
50
+ const now = /* @__PURE__ */ new Date();
51
+ const timeStr = new Intl.DateTimeFormat("en-US", {
52
+ hour: "2-digit",
53
+ minute: "2-digit",
54
+ hour12: false,
55
+ timeZone: tz
56
+ }).format(now);
57
+ const offsetPart = new Intl.DateTimeFormat("en-US", { timeZoneName: "short", timeZone: tz }).formatToParts(now).find((p) => p.type === "timeZoneName")?.value ?? "";
58
+ const city = tz.split("/").pop()?.replace(/_/g, " ") ?? tz;
59
+ return `${timeStr} (${offsetPart}) ${city} time`;
60
+ } catch {
61
+ return tz;
62
+ }
63
+ }
64
+ function EmptyState({ inEditor }) {
65
+ const handleAddSchedule = () => {
66
+ if (inEditor) {
67
+ window.parent.postMessage({ type: "ow:scheduling-not-connected" }, "*");
68
+ }
69
+ };
70
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center gap-6 p-12 bg-[#FAFAF9] border-2 border-dashed border-[#E7E5E4] rounded-[10px] h-[264px] w-full box-border", children: [
71
+ /* @__PURE__ */ jsx("div", { className: "w-10 h-10 bg-[#F5F5F4] rounded-[10px] flex items-center justify-center shrink-0", children: /* @__PURE__ */ jsxs(
72
+ "svg",
73
+ {
74
+ width: "20",
75
+ height: "20",
76
+ viewBox: "0 0 24 24",
77
+ fill: "none",
78
+ stroke: "var(--color-accent, #A89B83)",
79
+ strokeWidth: "1.5",
80
+ strokeLinecap: "round",
81
+ strokeLinejoin: "round",
82
+ children: [
83
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2" }),
84
+ /* @__PURE__ */ jsx("line", { x1: "16", y1: "2", x2: "16", y2: "6" }),
85
+ /* @__PURE__ */ jsx("line", { x1: "8", y1: "2", x2: "8", y2: "6" }),
86
+ /* @__PURE__ */ jsx("line", { x1: "3", y1: "10", x2: "21", y2: "10" }),
87
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "14", x2: "12", y2: "18" }),
88
+ /* @__PURE__ */ jsx("line", { x1: "10", y1: "16", x2: "14", y2: "16" })
89
+ ]
90
+ }
91
+ ) }),
92
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2", children: [
93
+ /* @__PURE__ */ jsx("p", { className: "font-body text-lg font-medium text-center text-[#0A0A0A] m-0", children: "No schedule yet" }),
94
+ /* @__PURE__ */ jsx("p", { className: "font-body text-base font-normal text-center text-(--color-accent,#A89B83) m-0", children: "Add a scheduling widget to get instant bookings." })
95
+ ] }),
96
+ /* @__PURE__ */ jsx(
97
+ "button",
98
+ {
99
+ onClick: handleAddSchedule,
100
+ className: "h-9 px-2 py-1.5 flex items-center justify-center bg-white border border-[#E7E5E4] rounded-md font-body text-sm font-medium text-(--color-dark,#200C02) cursor-pointer",
101
+ children: "Add Schedule"
102
+ }
103
+ )
104
+ ] });
105
+ }
106
+ function LoadingSkeleton() {
107
+ const shimmer = {
108
+ background: "linear-gradient(90deg,#f0f0f0 25%,#e8e8e8 50%,#f0f0f0 75%)",
109
+ backgroundSize: "200% 100%",
110
+ animation: "ohw-shimmer 1.5s infinite"
111
+ };
112
+ return /* @__PURE__ */ jsxs("div", { className: "w-full flex flex-col gap-10", children: [
113
+ /* @__PURE__ */ jsx("style", { children: `@keyframes ohw-shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}` }),
114
+ /* @__PURE__ */ jsx("div", { className: "flex h-[70px] items-stretch", children: Array.from({ length: 7 }).map((_, i) => /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col justify-between items-center px-1", children: [
115
+ /* @__PURE__ */ jsx("div", { style: { ...shimmer, width: "32px", height: "14px", borderRadius: "4px" } }),
116
+ /* @__PURE__ */ jsx("div", { style: { ...shimmer, width: "40px", height: "40px", borderRadius: "50%" } })
117
+ ] }, i)) }),
118
+ [0, 1, 2].map((i) => /* @__PURE__ */ jsxs("div", { children: [
119
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-[60px] py-4", children: [
120
+ /* @__PURE__ */ jsx("div", { style: { ...shimmer, width: "120px", height: "16px", borderRadius: "4px", flexShrink: 0 } }),
121
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col gap-2", children: [
122
+ /* @__PURE__ */ jsx("div", { style: { ...shimmer, width: "55%", height: "16px", borderRadius: "4px" } }),
123
+ /* @__PURE__ */ jsx("div", { style: { ...shimmer, width: "38%", height: "14px", borderRadius: "4px" } })
124
+ ] }),
125
+ /* @__PURE__ */ jsx("div", { style: { ...shimmer, width: "56px", height: "32px", borderRadius: "4px", flexShrink: 0 } }),
126
+ /* @__PURE__ */ jsx("div", { style: { ...shimmer, width: "200px", height: "44px", borderRadius: "8px", flexShrink: 0 } })
127
+ ] }),
128
+ i < 2 && /* @__PURE__ */ jsx("div", { className: "h-px bg-black/20" })
129
+ ] }, i))
130
+ ] });
131
+ }
132
+ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate }) {
133
+ const todayMs = useMemo(() => {
134
+ const d = /* @__PURE__ */ new Date();
135
+ d.setHours(0, 0, 0, 0);
136
+ return d.getTime();
137
+ }, []);
138
+ const datesWithClasses = useMemo(
139
+ () => new Set(dates.map(
140
+ (d, i) => schedule.classes?.some((c) => classRunsOnDate(c, d, schedule.type)) ? i : -1
141
+ ).filter((i) => i >= 0)),
142
+ [dates, schedule]
143
+ );
144
+ const selectedDate = dates[selectedIdx];
145
+ const selectedClasses = useMemo(
146
+ () => (schedule.classes ?? []).filter((c) => selectedDate && classRunsOnDate(c, selectedDate, schedule.type)),
147
+ [schedule, selectedDate]
148
+ );
149
+ return /* @__PURE__ */ jsxs("div", { className: "w-full flex flex-col gap-10", children: [
150
+ /* @__PURE__ */ jsx("div", { className: "overflow-x-auto w-full", children: /* @__PURE__ */ jsx("div", { className: "flex min-w-max", children: dates.map((date, i) => {
151
+ const isToday = date.getTime() === todayMs;
152
+ const isSelected = i === selectedIdx;
153
+ const clickable = datesWithClasses.has(i);
154
+ const label = isToday ? "TODAY" : DAY_ABBR[date.getDay()];
155
+ return /* @__PURE__ */ jsxs(
156
+ "div",
157
+ {
158
+ onClick: () => clickable && onSelectDate(i),
159
+ className: `flex-none w-[72px] h-[70px] flex flex-col justify-between items-center ${clickable ? "cursor-pointer opacity-100" : "cursor-default opacity-50"}`,
160
+ children: [
161
+ /* @__PURE__ */ jsx("span", { className: "font-body text-base font-normal text-center text-(--color-dark,#200C02)", children: label }),
162
+ /* @__PURE__ */ jsx(
163
+ "div",
164
+ {
165
+ className: "w-10 h-10 rounded-full flex items-center justify-center",
166
+ style: { background: isSelected ? "var(--color-primary, #3D312B)" : "transparent" },
167
+ children: /* @__PURE__ */ jsx(
168
+ "span",
169
+ {
170
+ className: "font-body text-xl font-bold text-center tracking-display-tight",
171
+ style: { color: isSelected ? "var(--color-light, #FEFFF0)" : "var(--color-dark, #200C02)" },
172
+ children: date.getDate()
173
+ }
174
+ )
175
+ }
176
+ )
177
+ ]
178
+ },
179
+ i
180
+ );
181
+ }) }) }),
182
+ selectedClasses.length === 0 ? /* @__PURE__ */ jsx("p", { className: "font-body text-base text-(--color-accent,#A89B83) text-center py-8 m-0", children: "No classes scheduled for this day." }) : /* @__PURE__ */ jsx("div", { className: "flex flex-col", children: selectedClasses.map((cls, i) => {
183
+ const booked = getBookingsOnDate(cls, selectedDate);
184
+ const available = cls.maxParticipants - booked;
185
+ const isFull = available <= 0;
186
+ return /* @__PURE__ */ jsxs("div", { children: [
187
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-[60px] py-4 box-border", children: [
188
+ /* @__PURE__ */ jsx("div", { className: "w-[120px] shrink-0", children: /* @__PURE__ */ jsx("span", { className: "font-body text-base font-bold text-(--color-dark,#200C02) block", children: formatClassTime(cls) }) }),
189
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col gap-3 min-w-0", children: [
190
+ /* @__PURE__ */ jsx("span", { className: "font-body text-base font-bold text-(--color-dark,#200C02) block truncate", children: cls.name }),
191
+ cls.hostName && /* @__PURE__ */ jsx("span", { className: "font-body text-base font-normal text-(--color-dark,#200C02) opacity-80 block truncate", children: cls.hostName })
192
+ ] }),
193
+ /* @__PURE__ */ jsx("div", { className: "w-14 shrink-0 flex flex-col gap-px", children: isFull ? /* @__PURE__ */ jsx("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
194
+ /* @__PURE__ */ jsxs("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: [
195
+ available,
196
+ "/",
197
+ cls.maxParticipants
198
+ ] }),
199
+ /* @__PURE__ */ jsx("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "available" })
200
+ ] }) }),
201
+ /* @__PURE__ */ jsx(
202
+ "button",
203
+ {
204
+ className: "shrink-0 w-[200px] px-5 py-[10px] flex items-center justify-center rounded-lg font-body text-base font-bold cursor-pointer box-border",
205
+ style: isFull ? {
206
+ background: "transparent",
207
+ border: "1px solid var(--color-dark, #200C02)",
208
+ color: "var(--color-dark, #200C02)"
209
+ } : {
210
+ background: "var(--color-primary, #3D312B)",
211
+ border: "none",
212
+ color: "var(--color-light, #FEFFF0)"
213
+ },
214
+ children: isFull ? "Join Waitlist" : "Book Now"
215
+ }
216
+ )
217
+ ] }),
218
+ i < selectedClasses.length - 1 && /* @__PURE__ */ jsx("div", { className: "h-px bg-black/20" })
219
+ ] }, cls.id ?? i);
220
+ }) })
221
+ ] });
222
+ }
223
+ function CalendarFoldIcon() {
224
+ return /* @__PURE__ */ jsxs(
225
+ "svg",
226
+ {
227
+ width: "16",
228
+ height: "16",
229
+ viewBox: "0 0 24 24",
230
+ fill: "none",
231
+ stroke: "currentColor",
232
+ strokeWidth: "2",
233
+ strokeLinecap: "round",
234
+ strokeLinejoin: "round",
235
+ style: { flexShrink: 0 },
236
+ children: [
237
+ /* @__PURE__ */ jsx("path", { d: "M8 2v4" }),
238
+ /* @__PURE__ */ jsx("path", { d: "M16 2v4" }),
239
+ /* @__PURE__ */ jsx("path", { d: "M21 17V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h11Z" }),
240
+ /* @__PURE__ */ jsx("path", { d: "M3 10h18" }),
241
+ /* @__PURE__ */ jsx("path", { d: "M15 22v-4a2 2 0 0 1 2-2h4" })
242
+ ]
243
+ }
244
+ );
245
+ }
246
+ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId }) {
247
+ const [schedule, setSchedule] = useState(null);
248
+ const [loading, setLoading] = useState(true);
249
+ const [inEditor, setInEditor] = useState(false);
250
+ const [isHovered, setIsHovered] = useState(false);
251
+ const switchScheduleIdRef = React.useRef(null);
252
+ const dates = useMemo(() => {
253
+ const today = /* @__PURE__ */ new Date();
254
+ today.setHours(0, 0, 0, 0);
255
+ return Array.from({ length: 14 }, (_, i) => {
256
+ const d = new Date(today);
257
+ d.setDate(today.getDate() + i);
258
+ return d;
259
+ });
260
+ }, []);
261
+ const [selectedIdx, setSelectedIdx] = useState(0);
262
+ useEffect(() => {
263
+ if (!schedule?.classes) return;
264
+ for (let i = 0; i < dates.length; i++) {
265
+ if (schedule.classes.some((c) => classRunsOnDate(c, dates[i], schedule.type))) {
266
+ setSelectedIdx(i);
267
+ return;
268
+ }
269
+ }
270
+ }, [schedule, dates]);
271
+ useEffect(() => {
272
+ if (typeof window === "undefined") return;
273
+ const isInEditor = window.self !== window.top;
274
+ setInEditor(isInEditor);
275
+ if (isInEditor) {
276
+ const startEmpty = initialScheduleId === null;
277
+ if (startEmpty) setLoading(false);
278
+ let initialized = startEmpty;
279
+ const timer = !startEmpty ? setTimeout(() => {
280
+ if (!initialized) {
281
+ initialized = true;
282
+ setLoading(false);
283
+ }
284
+ }, 5e3) : null;
285
+ const handler = (e) => {
286
+ if (e.data?.type === "ow:clear-scheduling-widget") {
287
+ setSchedule(null);
288
+ setLoading(false);
289
+ return;
290
+ }
291
+ if (e.data?.type === "ow:switch-schedule") {
292
+ switchScheduleIdRef.current = e.data.scheduleId ?? null;
293
+ initialized = false;
294
+ setLoading(true);
295
+ window.parent.postMessage({ type: "ow:request-user-schedules" }, "*");
296
+ return;
297
+ }
298
+ if (e.data?.type !== "ow:user-schedules-response") return;
299
+ if (initialized && switchScheduleIdRef.current === null) return;
300
+ initialized = true;
301
+ if (timer) clearTimeout(timer);
302
+ const schedules = e.data.schedules ?? [];
303
+ const isSwitching = switchScheduleIdRef.current !== null;
304
+ const target = isSwitching ? schedules.find((s) => s.id === switchScheduleIdRef.current) ?? schedules[0] ?? null : initialScheduleId ? schedules.find((s) => s.id === initialScheduleId) ?? schedules[0] ?? null : schedules[0] ?? null;
305
+ switchScheduleIdRef.current = null;
306
+ setSchedule(target);
307
+ setLoading(false);
308
+ if (notifyOnConnect && target && !isSwitching) {
309
+ window.parent.postMessage({ type: "ow:schedule-connected", schedule: { id: target.id, name: target.name } }, "*");
310
+ }
311
+ };
312
+ window.addEventListener("message", handler);
313
+ if (!startEmpty) window.parent.postMessage({ type: "ow:request-user-schedules" }, "*");
314
+ return () => {
315
+ window.removeEventListener("message", handler);
316
+ if (timer) clearTimeout(timer);
317
+ };
318
+ }
319
+ if (initialScheduleId === null) {
320
+ setLoading(false);
321
+ return;
322
+ }
323
+ ;
324
+ (async () => {
325
+ try {
326
+ if (initialScheduleId) {
327
+ const res = await fetch(`${API_URL}/api/schedule/id/${initialScheduleId}`);
328
+ const data = await res.json();
329
+ setSchedule(data?.id ? data : null);
330
+ } else {
331
+ const domain = getApiDomain();
332
+ const sitemapRes = await fetch(`${API_URL}/api/schedule/sitemap/${domain}`);
333
+ const slugs = await sitemapRes.json();
334
+ if (!Array.isArray(slugs) || !slugs.length) {
335
+ setLoading(false);
336
+ return;
337
+ }
338
+ const { slug } = [...slugs].sort(
339
+ (a, b) => new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime()
340
+ )[0];
341
+ const res = await fetch(`${API_URL}/api/schedule/${domain}/${slug}`);
342
+ const data = await res.json();
343
+ setSchedule(data?.id ? data : null);
344
+ }
345
+ } catch {
346
+ }
347
+ setLoading(false);
348
+ })();
349
+ }, []);
350
+ const timezoneLabel = schedule?.timezone ? (() => {
351
+ try {
352
+ return buildTimezoneLabel(schedule.timezone);
353
+ } catch {
354
+ return void 0;
355
+ }
356
+ })() : void 0;
357
+ const handleReplaceSchedule = () => {
358
+ setIsHovered(false);
359
+ if (schedule) {
360
+ window.parent.postMessage({ type: "ow:schedule-connected", schedule: { id: schedule.id, name: schedule.name } }, "*");
361
+ } else {
362
+ window.parent.postMessage({ type: "ow:scheduling-not-connected" }, "*");
363
+ }
364
+ };
365
+ return /* @__PURE__ */ jsxs(
366
+ "section",
367
+ {
368
+ "data-ohw-section": "scheduling",
369
+ className: "w-full box-border py-20 px-16 font-body bg-(--color-light,#FEFFF0) relative",
370
+ onMouseEnter: () => inEditor && setIsHovered(true),
371
+ onMouseLeave: () => setIsHovered(false),
372
+ children: [
373
+ inEditor && isHovered && !!schedule && /* @__PURE__ */ jsxs(
374
+ "div",
375
+ {
376
+ className: "absolute inset-0 z-10 pointer-events-auto cursor-pointer",
377
+ onClick: handleReplaceSchedule,
378
+ children: [
379
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0", style: { background: "#0885FE", opacity: 0.18 } }),
380
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0", style: { boxShadow: "inset 0 0 0 1.5px #0885FE" } }),
381
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxs(
382
+ "div",
383
+ {
384
+ className: "bg-white border border-[#E7E5E4] rounded-md px-3 py-1.5 flex items-center gap-1.5",
385
+ style: {
386
+ fontSize: 14,
387
+ lineHeight: "24px",
388
+ fontFamily: "'Figtree', system-ui, sans-serif",
389
+ fontWeight: 500,
390
+ color: "#0C0A09"
391
+ },
392
+ children: [
393
+ /* @__PURE__ */ jsx(CalendarFoldIcon, {}),
394
+ "Replace schedule"
395
+ ]
396
+ }
397
+ ) })
398
+ ]
399
+ }
400
+ ),
401
+ /* @__PURE__ */ jsxs("div", { className: "max-w-[1280px] mx-auto flex flex-col items-center gap-16", children: [
402
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-4", children: [
403
+ /* @__PURE__ */ jsx("h2", { className: "font-display text-5xl font-bold text-center m-0 text-(--color-dark,#200C02)", children: schedule?.name ?? "Book an appointment" }),
404
+ schedule?.description && /* @__PURE__ */ jsx("p", { className: "font-body text-body text-center m-0 text-(--color-accent,#A89B83)", children: schedule.description })
405
+ ] }),
406
+ /* @__PURE__ */ jsxs("div", { className: "w-full flex flex-col items-end gap-3", children: [
407
+ timezoneLabel && /* @__PURE__ */ jsx("span", { className: "font-body text-sm font-normal text-(--color-accent,#A89B83)", children: timezoneLabel }),
408
+ /* @__PURE__ */ jsx("div", { className: "w-full p-10 box-border", children: loading ? /* @__PURE__ */ jsx(LoadingSkeleton, {}) : !schedule ? /* @__PURE__ */ jsx(EmptyState, { inEditor }) : /* @__PURE__ */ jsx(
409
+ ScheduleView,
410
+ {
411
+ schedule,
412
+ dates,
413
+ selectedIdx,
414
+ onSelectDate: setSelectedIdx
415
+ }
416
+ ) })
417
+ ] })
418
+ ] })
419
+ ]
420
+ }
421
+ );
422
+ }
5
423
 
6
424
  // src/ui/toggle-group.tsx
7
- import * as React from "react";
425
+ import * as React2 from "react";
8
426
 
9
427
  // node_modules/clsx/dist/clsx.mjs
10
428
  function r(e) {
@@ -3324,7 +3742,7 @@ var cva = (base, config) => (props) => {
3324
3742
 
3325
3743
  // src/ui/toggle.tsx
3326
3744
  import { Toggle as TogglePrimitive } from "radix-ui";
3327
- import { jsx } from "react/jsx-runtime";
3745
+ import { jsx as jsx2 } from "react/jsx-runtime";
3328
3746
  var toggleVariants = cva(
3329
3747
  "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none hover:bg-muted hover:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
3330
3748
  {
@@ -3351,7 +3769,7 @@ function Toggle({
3351
3769
  size,
3352
3770
  ...props
3353
3771
  }) {
3354
- return /* @__PURE__ */ jsx(
3772
+ return /* @__PURE__ */ jsx2(
3355
3773
  TogglePrimitive.Root,
3356
3774
  {
3357
3775
  "data-slot": "toggle",
@@ -3362,8 +3780,8 @@ function Toggle({
3362
3780
  }
3363
3781
 
3364
3782
  // src/ui/toggle-group.tsx
3365
- import { jsx as jsx2 } from "react/jsx-runtime";
3366
- var ToggleGroupContext = React.createContext({
3783
+ import { jsx as jsx3 } from "react/jsx-runtime";
3784
+ var ToggleGroupContext = React2.createContext({
3367
3785
  value: "",
3368
3786
  onValueChange: () => {
3369
3787
  }
@@ -3375,13 +3793,13 @@ function ToggleGroup({
3375
3793
  children,
3376
3794
  ...props
3377
3795
  }) {
3378
- return /* @__PURE__ */ jsx2(
3796
+ return /* @__PURE__ */ jsx3(
3379
3797
  "div",
3380
3798
  {
3381
3799
  role: "group",
3382
3800
  className: cn("flex items-center gap-1 p-1 bg-muted rounded-md", className),
3383
3801
  ...props,
3384
- children: /* @__PURE__ */ jsx2(ToggleGroupContext.Provider, { value: { value, onValueChange }, children })
3802
+ children: /* @__PURE__ */ jsx3(ToggleGroupContext.Provider, { value: { value, onValueChange }, children })
3385
3803
  }
3386
3804
  );
3387
3805
  }
@@ -3391,8 +3809,8 @@ function ToggleGroupItem({
3391
3809
  children,
3392
3810
  ...props
3393
3811
  }) {
3394
- const { value: groupValue, onValueChange } = React.useContext(ToggleGroupContext);
3395
- return /* @__PURE__ */ jsx2(
3812
+ const { value: groupValue, onValueChange } = React2.useContext(ToggleGroupContext);
3813
+ return /* @__PURE__ */ jsx3(
3396
3814
  Toggle,
3397
3815
  {
3398
3816
  pressed: groupValue === value,
@@ -3434,7 +3852,7 @@ function isEditSessionActive() {
3434
3852
  }
3435
3853
 
3436
3854
  // src/ui/badge.tsx
3437
- import { jsx as jsx3 } from "react/jsx-runtime";
3855
+ import { jsx as jsx4 } from "react/jsx-runtime";
3438
3856
  var badgeVariants = cva(
3439
3857
  "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
3440
3858
  {
@@ -3452,11 +3870,11 @@ var badgeVariants = cva(
3452
3870
  }
3453
3871
  );
3454
3872
  function Badge({ className, variant, ...props }) {
3455
- return /* @__PURE__ */ jsx3("div", { className: cn(badgeVariants({ variant }), className), ...props });
3873
+ return /* @__PURE__ */ jsx4("div", { className: cn(badgeVariants({ variant }), className), ...props });
3456
3874
  }
3457
3875
 
3458
3876
  // src/OhhwellsBridge.tsx
3459
- import { Fragment, jsx as jsx4, jsxs } from "react/jsx-runtime";
3877
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
3460
3878
  var PRIMARY = "#0885FE";
3461
3879
  var IMAGE_FADE_MS = 300;
3462
3880
  function runOpacityFade(el, onDone) {
@@ -3507,6 +3925,41 @@ function fadeInBgImage(el, url, onReady) {
3507
3925
  if (!prevPos || prevPos === "static") el.style.position = prevPos;
3508
3926
  });
3509
3927
  }
3928
+ function getSectionsTracker() {
3929
+ let el = document.querySelector("[data-ohw-sections-tracker]");
3930
+ if (!el) {
3931
+ el = document.createElement("div");
3932
+ el.setAttribute("data-ohw-sections-tracker", "");
3933
+ el.style.display = "none";
3934
+ document.body.appendChild(el);
3935
+ }
3936
+ return el;
3937
+ }
3938
+ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId) {
3939
+ const anchor = document.querySelector(`[data-ohw-section="${insertAfter}"]`);
3940
+ if (!anchor) return false;
3941
+ if (anchor.nextElementSibling?.dataset.ohwSectionContainer) return false;
3942
+ const container = document.createElement("div");
3943
+ container.dataset.ohwSectionContainer = "scheduling";
3944
+ anchor.insertAdjacentElement("afterend", container);
3945
+ createRoot(container).render(/* @__PURE__ */ jsx5(SchedulingWidget, { notifyOnConnect, initialScheduleId: scheduleId }));
3946
+ const tracker = getSectionsTracker();
3947
+ let sections = [];
3948
+ try {
3949
+ sections = JSON.parse(tracker.textContent || "[]");
3950
+ } catch {
3951
+ }
3952
+ if (!sections.find((s) => s.type === "scheduling" && s.insertAfter === insertAfter)) {
3953
+ sections.push({
3954
+ type: "scheduling",
3955
+ insertAfter,
3956
+ pagePath: window.location.pathname,
3957
+ ...scheduleId ? { scheduleId } : {}
3958
+ });
3959
+ tracker.textContent = JSON.stringify(sections);
3960
+ }
3961
+ return true;
3962
+ }
3510
3963
  function collectEditableNodes() {
3511
3964
  return Array.from(document.querySelectorAll("[data-ohw-editable]")).map((el) => {
3512
3965
  if (el.dataset.ohwEditable === "image") {
@@ -3664,7 +4117,7 @@ var TOOLBAR_GROUPS = [
3664
4117
  ];
3665
4118
  function GlowFrame({ rect, elRef }) {
3666
4119
  const GAP = 6;
3667
- return /* @__PURE__ */ jsx4(
4120
+ return /* @__PURE__ */ jsx5(
3668
4121
  "div",
3669
4122
  {
3670
4123
  ref: elRef,
@@ -3715,7 +4168,7 @@ function FloatingToolbar({
3715
4168
  activeCommands
3716
4169
  }) {
3717
4170
  const { top, left, transform } = calcToolbarPos(rect, parentScroll);
3718
- return /* @__PURE__ */ jsx4(
4171
+ return /* @__PURE__ */ jsx5(
3719
4172
  "div",
3720
4173
  {
3721
4174
  ref: elRef,
@@ -3738,11 +4191,11 @@ function FloatingToolbar({
3738
4191
  pointerEvents: "auto",
3739
4192
  whiteSpace: "nowrap"
3740
4193
  },
3741
- children: TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs(React2.Fragment, { children: [
3742
- gi > 0 && /* @__PURE__ */ jsx4("span", { style: { display: "block", width: 1, height: 24, background: "#E7E5E4", flexShrink: 0 } }),
4194
+ children: TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs2(React3.Fragment, { children: [
4195
+ gi > 0 && /* @__PURE__ */ jsx5("span", { style: { display: "block", width: 1, height: 24, background: "#E7E5E4", flexShrink: 0 } }),
3743
4196
  btns.map((btn) => {
3744
4197
  const isActive = activeCommands.has(btn.cmd);
3745
- return /* @__PURE__ */ jsx4(
4198
+ return /* @__PURE__ */ jsx5(
3746
4199
  "button",
3747
4200
  {
3748
4201
  title: btn.title,
@@ -3768,7 +4221,7 @@ function FloatingToolbar({
3768
4221
  flexShrink: 0,
3769
4222
  padding: 6
3770
4223
  },
3771
- children: /* @__PURE__ */ jsx4(
4224
+ children: /* @__PURE__ */ jsx5(
3772
4225
  "svg",
3773
4226
  {
3774
4227
  width: "16",
@@ -3801,7 +4254,7 @@ function StateToggle({
3801
4254
  states,
3802
4255
  onStateChange
3803
4256
  }) {
3804
- return /* @__PURE__ */ jsx4(
4257
+ return /* @__PURE__ */ jsx5(
3805
4258
  ToggleGroup,
3806
4259
  {
3807
4260
  "data-ohw-state-toggle": "",
@@ -3815,7 +4268,7 @@ function StateToggle({
3815
4268
  left: rect.right - 8,
3816
4269
  transform: "translateX(-100%)"
3817
4270
  },
3818
- children: states.map((state) => /* @__PURE__ */ jsx4(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
4271
+ children: states.map((state) => /* @__PURE__ */ jsx5(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
3819
4272
  }
3820
4273
  );
3821
4274
  }
@@ -3825,8 +4278,8 @@ function OhhwellsBridge() {
3825
4278
  const router = useRouter();
3826
4279
  const searchParams = useSearchParams();
3827
4280
  const isEditMode = isEditSessionActive();
3828
- const [bridgeRoot, setBridgeRoot] = useState(null);
3829
- useEffect(() => {
4281
+ const [bridgeRoot, setBridgeRoot] = useState2(null);
4282
+ useEffect2(() => {
3830
4283
  const figtreeFontId = "ohw-figtree-font";
3831
4284
  if (!document.getElementById(figtreeFontId)) {
3832
4285
  const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
@@ -3859,7 +4312,7 @@ function OhhwellsBridge() {
3859
4312
  window.parent.postMessage(data, "*");
3860
4313
  }
3861
4314
  }, []);
3862
- const [fetchState, setFetchState] = useState("idle");
4315
+ const [fetchState, setFetchState] = useState2("idle");
3863
4316
  const autoSaveTimers = useRef(/* @__PURE__ */ new Map());
3864
4317
  const activeElRef = useRef(null);
3865
4318
  const originalContentRef = useRef(null);
@@ -3881,12 +4334,12 @@ function OhhwellsBridge() {
3881
4334
  });
3882
4335
  const postToParentRef = useRef(postToParent);
3883
4336
  postToParentRef.current = postToParent;
3884
- const [toolbarRect, setToolbarRect] = useState(null);
3885
- const [toggleState, setToggleState] = useState(null);
3886
- const [maxBadge, setMaxBadge] = useState(null);
3887
- const [activeCommands, setActiveCommands] = useState(/* @__PURE__ */ new Set());
3888
- const [sectionGap, setSectionGap] = useState(null);
3889
- useEffect(() => {
4337
+ const [toolbarRect, setToolbarRect] = useState2(null);
4338
+ const [toggleState, setToggleState] = useState2(null);
4339
+ const [maxBadge, setMaxBadge] = useState2(null);
4340
+ const [activeCommands, setActiveCommands] = useState2(/* @__PURE__ */ new Set());
4341
+ const [sectionGap, setSectionGap] = useState2(null);
4342
+ useEffect2(() => {
3890
4343
  const update = () => {
3891
4344
  const el = activeElRef.current;
3892
4345
  if (el) setToolbarRect(el.getBoundingClientRect());
@@ -3963,7 +4416,20 @@ function OhhwellsBridge() {
3963
4416
  }
3964
4417
  const applyContent = (content) => {
3965
4418
  const imageLoads = [];
4419
+ document.querySelectorAll("[data-ohw-section-container]").forEach((el) => el.remove());
4420
+ if (content["__ohw_sections"]) {
4421
+ try {
4422
+ const entries = JSON.parse(content["__ohw_sections"]);
4423
+ const currentPath = window.location.pathname;
4424
+ entries.forEach(({ type, insertAfter, scheduleId, pagePath }) => {
4425
+ if (pagePath && pagePath !== currentPath) return;
4426
+ if (type === "scheduling") mountSchedulingWidget(insertAfter, false, scheduleId);
4427
+ });
4428
+ } catch {
4429
+ }
4430
+ }
3966
4431
  for (const [key, val] of Object.entries(content)) {
4432
+ if (key === "__ohw_sections") continue;
3967
4433
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
3968
4434
  if (el.dataset.ohwEditable === "image") {
3969
4435
  const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
@@ -4006,12 +4472,24 @@ function OhhwellsBridge() {
4006
4472
  cancelled = true;
4007
4473
  };
4008
4474
  }, [subdomain, isEditMode, pathname]);
4009
- useEffect(() => {
4475
+ useEffect2(() => {
4010
4476
  if (!subdomain || isEditMode) return;
4011
4477
  const applyFromCache = () => {
4012
4478
  const content = contentCache.get(subdomain);
4013
4479
  if (!content) return;
4480
+ if (content["__ohw_sections"]) {
4481
+ try {
4482
+ const entries = JSON.parse(content["__ohw_sections"]);
4483
+ const currentPath = window.location.pathname;
4484
+ entries.forEach(({ type, insertAfter, scheduleId, pagePath }) => {
4485
+ if (pagePath && pagePath !== currentPath) return;
4486
+ if (type === "scheduling") mountSchedulingWidget(insertAfter, false, scheduleId);
4487
+ });
4488
+ } catch {
4489
+ }
4490
+ }
4014
4491
  for (const [key, val] of Object.entries(content)) {
4492
+ if (key === "__ohw_sections") continue;
4015
4493
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
4016
4494
  if (el.dataset.ohwEditable === "image") {
4017
4495
  const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
@@ -4036,10 +4514,10 @@ function OhhwellsBridge() {
4036
4514
  const visible = Boolean(subdomain) && fetchState !== "done";
4037
4515
  el.style.display = visible ? "flex" : "none";
4038
4516
  }, [subdomain, fetchState]);
4039
- useEffect(() => {
4517
+ useEffect2(() => {
4040
4518
  postToParent({ type: "ow:navigation", path: pathname });
4041
4519
  }, [pathname, postToParent]);
4042
- useEffect(() => {
4520
+ useEffect2(() => {
4043
4521
  if (!isEditMode) return;
4044
4522
  const measure = () => {
4045
4523
  const h = document.body.scrollHeight;
@@ -4063,7 +4541,7 @@ function OhhwellsBridge() {
4063
4541
  window.removeEventListener("resize", handleResize);
4064
4542
  };
4065
4543
  }, [pathname, isEditMode, postToParent]);
4066
- useEffect(() => {
4544
+ useEffect2(() => {
4067
4545
  if (!subdomainFromQuery || isEditMode) return;
4068
4546
  const handleClick = (e) => {
4069
4547
  const anchor = e.target.closest("a");
@@ -4079,7 +4557,7 @@ function OhhwellsBridge() {
4079
4557
  document.addEventListener("click", handleClick, true);
4080
4558
  return () => document.removeEventListener("click", handleClick, true);
4081
4559
  }, [subdomainFromQuery, isEditMode, router]);
4082
- useEffect(() => {
4560
+ useEffect2(() => {
4083
4561
  if (!isEditMode) {
4084
4562
  editStylesRef.current?.base.remove();
4085
4563
  editStylesRef.current?.forceHover.remove();
@@ -4339,6 +4817,15 @@ function OhhwellsBridge() {
4339
4817
  textEditable.setAttribute("data-ohw-hovered", "");
4340
4818
  return;
4341
4819
  }
4820
+ if (hoveredGapRef.current) {
4821
+ if (hoveredImageRef.current) {
4822
+ hoveredImageRef.current = null;
4823
+ resumeAnimTracks();
4824
+ postToParentRef.current({ type: "ow:image-unhover" });
4825
+ }
4826
+ document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
4827
+ return;
4828
+ }
4342
4829
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
4343
4830
  if (imgEl !== hoveredImageRef.current || hoveredImageHasTextOverlapRef.current) {
4344
4831
  hoveredImageRef.current = imgEl;
@@ -4427,17 +4914,17 @@ function OhhwellsBridge() {
4427
4914
  };
4428
4915
  const handleMouseMove = (e) => {
4429
4916
  const { clientX, clientY } = e;
4917
+ probeSectionGapAt(clientX, clientY);
4430
4918
  probeImageAt(clientX, clientY);
4431
4919
  probeHoverCardsAt(clientX, clientY);
4432
- probeSectionGapAt(clientX, clientY);
4433
4920
  };
4434
4921
  const handlePointerSync = (e) => {
4435
4922
  if (e.data?.type !== "ow:pointer-sync") return;
4436
4923
  const { clientX, clientY } = e.data;
4437
4924
  if (typeof clientX !== "number" || typeof clientY !== "number") return;
4925
+ probeSectionGapAt(clientX, clientY);
4438
4926
  probeImageAt(clientX, clientY);
4439
4927
  probeHoverCardsAt(clientX, clientY);
4440
- probeSectionGapAt(clientX, clientY);
4441
4928
  };
4442
4929
  const handleDragOver = (e) => {
4443
4930
  e.preventDefault();
@@ -4594,6 +5081,18 @@ function OhhwellsBridge() {
4594
5081
  const content = e.data.content;
4595
5082
  if (!content) return;
4596
5083
  for (const [key, val] of Object.entries(content)) {
5084
+ if (key === "__ohw_sections") {
5085
+ try {
5086
+ const entries = JSON.parse(val);
5087
+ const tracker = getSectionsTracker();
5088
+ tracker.textContent = val;
5089
+ entries.forEach(({ type, insertAfter, scheduleId }) => {
5090
+ if (type === "scheduling") mountSchedulingWidget(insertAfter, false, scheduleId);
5091
+ });
5092
+ } catch {
5093
+ }
5094
+ continue;
5095
+ }
4597
5096
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
4598
5097
  if (el.dataset.ohwEditable === "image") {
4599
5098
  const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
@@ -4648,7 +5147,71 @@ function OhhwellsBridge() {
4648
5147
  };
4649
5148
  const handleSave = (e) => {
4650
5149
  if (e.data?.type !== "ow:save") return;
4651
- postToParentRef.current({ type: "ow:save-result", nodes: collectEditableNodes() });
5150
+ const nodes = collectEditableNodes();
5151
+ const tracker = document.querySelector("[data-ohw-sections-tracker]");
5152
+ if (tracker?.textContent) nodes.push({ key: "__ohw_sections", type: "sections", text: tracker.textContent });
5153
+ postToParentRef.current({ type: "ow:save-result", nodes });
5154
+ };
5155
+ const handleInsertSection = (e) => {
5156
+ if (e.data?.type !== "ow:insert-section") return;
5157
+ const { widgetType, insertAfter } = e.data;
5158
+ if (widgetType !== "scheduling") return;
5159
+ const inserted = mountSchedulingWidget(insertAfter, true);
5160
+ if (inserted) {
5161
+ const tracker = getSectionsTracker();
5162
+ postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
5163
+ const h = document.documentElement.scrollHeight;
5164
+ if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
5165
+ }
5166
+ };
5167
+ const handleSwitchSchedule = (e) => {
5168
+ if (e.data?.type !== "ow:switch-schedule") return;
5169
+ const scheduleId = e.data.scheduleId;
5170
+ if (!scheduleId) return;
5171
+ const tracker = getSectionsTracker();
5172
+ let sections = [];
5173
+ try {
5174
+ sections = JSON.parse(tracker.textContent || "[]");
5175
+ } catch {
5176
+ }
5177
+ const currentPath = window.location.pathname;
5178
+ const updated = sections.map(
5179
+ (s) => s.type === "scheduling" && s.pagePath === currentPath ? { ...s, scheduleId } : s
5180
+ );
5181
+ tracker.textContent = JSON.stringify(updated);
5182
+ postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent }] });
5183
+ };
5184
+ const handleClearSchedulingWidget = (e) => {
5185
+ if (e.data?.type !== "ow:clear-scheduling-widget") return;
5186
+ const tracker = getSectionsTracker();
5187
+ let sections = [];
5188
+ try {
5189
+ sections = JSON.parse(tracker.textContent || "[]");
5190
+ } catch {
5191
+ }
5192
+ const currentPath = window.location.pathname;
5193
+ const updated = sections.map(
5194
+ (s) => s.type === "scheduling" && s.pagePath === currentPath ? { ...s, scheduleId: null } : s
5195
+ );
5196
+ tracker.textContent = JSON.stringify(updated);
5197
+ postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent }] });
5198
+ };
5199
+ const handleRemoveSchedulingSection = (e) => {
5200
+ if (e.data?.type !== "ow:remove-scheduling-section") return;
5201
+ const els = document.querySelectorAll('[data-ohw-section="scheduling"]');
5202
+ els.forEach((el) => el.parentElement?.removeChild(el));
5203
+ const tracker = getSectionsTracker();
5204
+ let sections = [];
5205
+ try {
5206
+ sections = JSON.parse(tracker.textContent || "[]");
5207
+ } catch {
5208
+ }
5209
+ const currentPath = window.location.pathname;
5210
+ const updated = sections.filter((s) => !(s.type === "scheduling" && s.pagePath === currentPath));
5211
+ tracker.textContent = JSON.stringify(updated);
5212
+ postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent }] });
5213
+ const h = document.documentElement.scrollHeight;
5214
+ if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
4652
5215
  };
4653
5216
  const handleSelectionChange = () => {
4654
5217
  if (!activeElRef.current) return;
@@ -4753,6 +5316,10 @@ function OhhwellsBridge() {
4753
5316
  deactivateRef.current();
4754
5317
  };
4755
5318
  window.addEventListener("message", handleSave);
5319
+ window.addEventListener("message", handleInsertSection);
5320
+ window.addEventListener("message", handleSwitchSchedule);
5321
+ window.addEventListener("message", handleClearSchedulingWidget);
5322
+ window.addEventListener("message", handleRemoveSchedulingSection);
4756
5323
  window.addEventListener("message", handleImageUrl);
4757
5324
  window.addEventListener("message", handleAnimLock);
4758
5325
  window.addEventListener("message", handleCanvasHeight);
@@ -4787,6 +5354,10 @@ function OhhwellsBridge() {
4787
5354
  document.removeEventListener("selectionchange", handleSelectionChange);
4788
5355
  window.removeEventListener("scroll", handleScroll, true);
4789
5356
  window.removeEventListener("message", handleSave);
5357
+ window.removeEventListener("message", handleInsertSection);
5358
+ window.removeEventListener("message", handleSwitchSchedule);
5359
+ window.removeEventListener("message", handleClearSchedulingWidget);
5360
+ window.removeEventListener("message", handleRemoveSchedulingSection);
4790
5361
  window.removeEventListener("message", handleImageUrl);
4791
5362
  window.removeEventListener("message", handleAnimLock);
4792
5363
  window.removeEventListener("message", handleCanvasHeight);
@@ -4801,7 +5372,7 @@ function OhhwellsBridge() {
4801
5372
  if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
4802
5373
  };
4803
5374
  }, [isEditMode, refreshStateRules]);
4804
- useEffect(() => {
5375
+ useEffect2(() => {
4805
5376
  if (!isEditMode) return;
4806
5377
  document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
4807
5378
  el.removeAttribute("data-ohw-active-state");
@@ -4843,12 +5414,12 @@ function OhhwellsBridge() {
4843
5414
  setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
4844
5415
  }, [deactivate]);
4845
5416
  return bridgeRoot ? createPortal(
4846
- /* @__PURE__ */ jsxs(Fragment, { children: [
4847
- toolbarRect && /* @__PURE__ */ jsxs(Fragment, { children: [
4848
- /* @__PURE__ */ jsx4(GlowFrame, { rect: toolbarRect, elRef: glowElRef }),
4849
- /* @__PURE__ */ jsx4(FloatingToolbar, { rect: toolbarRect, parentScroll: parentScrollRef.current, elRef: toolbarElRef, onCommand: handleCommand, activeCommands })
5417
+ /* @__PURE__ */ jsxs2(Fragment2, { children: [
5418
+ toolbarRect && /* @__PURE__ */ jsxs2(Fragment2, { children: [
5419
+ /* @__PURE__ */ jsx5(GlowFrame, { rect: toolbarRect, elRef: glowElRef }),
5420
+ /* @__PURE__ */ jsx5(FloatingToolbar, { rect: toolbarRect, parentScroll: parentScrollRef.current, elRef: toolbarElRef, onCommand: handleCommand, activeCommands })
4850
5421
  ] }),
4851
- maxBadge && /* @__PURE__ */ jsxs(
5422
+ maxBadge && /* @__PURE__ */ jsxs2(
4852
5423
  "div",
4853
5424
  {
4854
5425
  "data-ohw-max-badge": "",
@@ -4874,7 +5445,7 @@ function OhhwellsBridge() {
4874
5445
  ]
4875
5446
  }
4876
5447
  ),
4877
- toggleState && /* @__PURE__ */ jsx4(
5448
+ toggleState && /* @__PURE__ */ jsx5(
4878
5449
  StateToggle,
4879
5450
  {
4880
5451
  rect: toggleState.rect,
@@ -4883,15 +5454,15 @@ function OhhwellsBridge() {
4883
5454
  onStateChange: handleStateChange
4884
5455
  }
4885
5456
  ),
4886
- sectionGap && /* @__PURE__ */ jsxs(
5457
+ sectionGap && /* @__PURE__ */ jsxs2(
4887
5458
  "div",
4888
5459
  {
4889
5460
  "data-ohw-section-insert-line": "",
4890
5461
  className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
4891
5462
  style: { top: sectionGap.y, transform: "translateY(-50%)" },
4892
5463
  children: [
4893
- /* @__PURE__ */ jsx4("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
4894
- /* @__PURE__ */ jsx4(
5464
+ /* @__PURE__ */ jsx5("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
5465
+ /* @__PURE__ */ jsx5(
4895
5466
  Badge,
4896
5467
  {
4897
5468
  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",
@@ -4904,7 +5475,7 @@ function OhhwellsBridge() {
4904
5475
  children: "Add Section"
4905
5476
  }
4906
5477
  ),
4907
- /* @__PURE__ */ jsx4("div", { className: "flex-1 bg-primary", style: { height: 3 } })
5478
+ /* @__PURE__ */ jsx5("div", { className: "flex-1 bg-primary", style: { height: 3 } })
4908
5479
  ]
4909
5480
  }
4910
5481
  )
@@ -4914,6 +5485,7 @@ function OhhwellsBridge() {
4914
5485
  }
4915
5486
  export {
4916
5487
  OhhwellsBridge,
5488
+ SchedulingWidget,
4917
5489
  Toggle,
4918
5490
  ToggleGroup,
4919
5491
  ToggleGroupItem,