@ohhwells/bridge 0.1.24 → 0.1.26
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 +304 -327
- package/dist/index.cjs +1315 -271
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +65 -5
- package/dist/index.d.ts +65 -5
- package/dist/index.js +1305 -269
- package/dist/index.js.map +1 -1
- package/dist/styles.css +322 -2
- package/package.json +48 -48
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
// src/OhhwellsBridge.tsx
|
|
4
|
-
import
|
|
4
|
+
import React5, { useCallback as useCallback2, useEffect as useEffect4, useLayoutEffect, 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
|
|
|
8
8
|
// src/ui/SchedulingWidget.tsx
|
|
9
|
-
import { useEffect,
|
|
9
|
+
import { useEffect, useMemo, useRef, useState as useState2 } from "react";
|
|
10
10
|
|
|
11
11
|
// src/ui/EmailCaptureModal.tsx
|
|
12
12
|
import { useState } from "react";
|
|
@@ -164,6 +164,13 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
|
|
|
164
164
|
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
165
165
|
var API_URL = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
166
166
|
var DAY_ABBR = ["SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"];
|
|
167
|
+
function getApiDomain() {
|
|
168
|
+
const h = window.location.hostname;
|
|
169
|
+
for (const base of ["ohhwells.site", "theflowops-staging.com", "theflowops.com"]) {
|
|
170
|
+
if (h.endsWith(`.${base}`)) return h.slice(0, -(base.length + 1));
|
|
171
|
+
}
|
|
172
|
+
return h;
|
|
173
|
+
}
|
|
167
174
|
function classRunsOnDate(cls, date, type) {
|
|
168
175
|
if (type === "FIXED") {
|
|
169
176
|
const d = String(date.getDate()).padStart(2, "0");
|
|
@@ -209,10 +216,10 @@ function buildTimezoneLabel(tz) {
|
|
|
209
216
|
return tz;
|
|
210
217
|
}
|
|
211
218
|
}
|
|
212
|
-
function EmptyState({ inEditor
|
|
219
|
+
function EmptyState({ inEditor }) {
|
|
213
220
|
const handleAddSchedule = () => {
|
|
214
221
|
if (inEditor) {
|
|
215
|
-
window.parent.postMessage({ type: "ow:scheduling-not-connected"
|
|
222
|
+
window.parent.postMessage({ type: "ow:scheduling-not-connected" }, "*");
|
|
216
223
|
}
|
|
217
224
|
};
|
|
218
225
|
return /* @__PURE__ */ jsxs2("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: [
|
|
@@ -437,21 +444,18 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
|
|
|
437
444
|
const booked = getBookingsOnDate(cls, selectedDate);
|
|
438
445
|
const available = cls.maxParticipants - booked;
|
|
439
446
|
const isFull = available <= 0;
|
|
440
|
-
const isPrivate = cls.maxParticipants === 1;
|
|
441
447
|
return /* @__PURE__ */ jsxs2("div", { children: [
|
|
442
448
|
/* @__PURE__ */ jsxs2("div", { className: "flex gap-4 py-4 sm:items-center sm:gap-[60px] box-border", children: [
|
|
443
449
|
/* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-2 shrink-0 sm:contents", children: [
|
|
444
|
-
/* @__PURE__ */
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
)
|
|
454
|
-
] }),
|
|
450
|
+
/* @__PURE__ */ jsx2("div", { className: "sm:w-[120px] sm:shrink-0", children: /* @__PURE__ */ jsx2("span", { className: "font-body text-base font-bold text-(--color-dark,#200C02) block", children: formatClassTime(cls) }) }),
|
|
451
|
+
/* @__PURE__ */ jsx2(
|
|
452
|
+
"span",
|
|
453
|
+
{
|
|
454
|
+
className: "inline-flex items-center px-2 py-0.5 rounded-full border text-xs font-medium sm:hidden",
|
|
455
|
+
style: { borderColor: "#0885FE", color: "#0885FE" },
|
|
456
|
+
children: "GROUP"
|
|
457
|
+
}
|
|
458
|
+
),
|
|
455
459
|
/* @__PURE__ */ jsx2("div", { className: "sm:hidden flex flex-col gap-px", children: isFull ? /* @__PURE__ */ jsx2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
456
460
|
/* @__PURE__ */ jsxs2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: [
|
|
457
461
|
available,
|
|
@@ -524,9 +528,7 @@ function CalendarFoldIcon() {
|
|
|
524
528
|
}
|
|
525
529
|
);
|
|
526
530
|
}
|
|
527
|
-
function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAfter
|
|
528
|
-
const autoId = useId();
|
|
529
|
-
const insertAfter = insertAfterProp ?? autoId;
|
|
531
|
+
function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAfter }) {
|
|
530
532
|
const [schedule, setSchedule] = useState2(null);
|
|
531
533
|
const [loading, setLoading] = useState2(true);
|
|
532
534
|
const [inEditor, setInEditor] = useState2(false);
|
|
@@ -556,99 +558,88 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
556
558
|
if (typeof window === "undefined") return;
|
|
557
559
|
const isInEditor = window.self !== window.top;
|
|
558
560
|
setInEditor(isInEditor);
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
if (!initialized) {
|
|
566
|
-
initialized = true;
|
|
567
|
-
setLoading(false);
|
|
568
|
-
}
|
|
569
|
-
}, 5e3) : null;
|
|
570
|
-
const handler = (e) => {
|
|
571
|
-
if (e.data?.type === "ow:clear-scheduling-widget") {
|
|
572
|
-
if (!e.data.insertAfter || e.data.insertAfter !== insertAfter) return;
|
|
573
|
-
setSchedule(null);
|
|
574
|
-
setLoading(false);
|
|
575
|
-
return;
|
|
576
|
-
}
|
|
577
|
-
if (e.data?.type === "ow:switch-schedule") {
|
|
578
|
-
if (!e.data.insertAfter || e.data.insertAfter !== insertAfter) return;
|
|
579
|
-
switchScheduleIdRef.current = e.data.scheduleId ?? null;
|
|
580
|
-
initialized = false;
|
|
581
|
-
setLoading(true);
|
|
582
|
-
window.parent.postMessage({ type: "ow:request-user-schedules", insertAfter }, "*");
|
|
583
|
-
return;
|
|
584
|
-
}
|
|
585
|
-
if (e.data?.type !== "ow:user-schedules-response") return;
|
|
586
|
-
if (e.data.insertAfter && e.data.insertAfter !== insertAfter) return;
|
|
587
|
-
if (initialized && switchScheduleIdRef.current === null) return;
|
|
561
|
+
if (isInEditor) {
|
|
562
|
+
const startEmpty = initialScheduleId === null;
|
|
563
|
+
if (startEmpty) setLoading(false);
|
|
564
|
+
let initialized = startEmpty;
|
|
565
|
+
const timer = !startEmpty ? setTimeout(() => {
|
|
566
|
+
if (!initialized) {
|
|
588
567
|
initialized = true;
|
|
589
|
-
if (timer) clearTimeout(timer);
|
|
590
|
-
const schedules = e.data.schedules ?? [];
|
|
591
|
-
const isSwitching = switchScheduleIdRef.current !== null;
|
|
592
|
-
const target = isSwitching ? schedules.find((s) => s.id === switchScheduleIdRef.current) ?? schedules[0] ?? null : effectiveId ? schedules.find((s) => s.id === effectiveId) ?? schedules[0] ?? null : schedules[0] ?? null;
|
|
593
|
-
switchScheduleIdRef.current = null;
|
|
594
|
-
setSchedule(target);
|
|
595
568
|
setLoading(false);
|
|
596
|
-
if (notifyOnConnect && target && !isSwitching) {
|
|
597
|
-
window.parent.postMessage({
|
|
598
|
-
type: "ow:schedule-connected",
|
|
599
|
-
schedule: { id: target.id, name: target.name },
|
|
600
|
-
insertAfter
|
|
601
|
-
}, "*");
|
|
602
|
-
window.postMessage({ type: "ow:schedule-linked", scheduleId: target.id, insertAfter }, "*");
|
|
603
|
-
}
|
|
604
|
-
};
|
|
605
|
-
window.addEventListener("message", handler);
|
|
606
|
-
if (!startEmpty) window.parent.postMessage({ type: "ow:request-user-schedules", insertAfter }, "*");
|
|
607
|
-
return () => {
|
|
608
|
-
window.removeEventListener("message", handler);
|
|
609
|
-
if (timer) clearTimeout(timer);
|
|
610
|
-
};
|
|
611
|
-
}
|
|
612
|
-
if (!effectiveId) {
|
|
613
|
-
setLoading(false);
|
|
614
|
-
return;
|
|
615
|
-
}
|
|
616
|
-
;
|
|
617
|
-
(async () => {
|
|
618
|
-
try {
|
|
619
|
-
const res = await fetch(`${API_URL}/api/schedule/id/${effectiveId}`);
|
|
620
|
-
const data = await res.json();
|
|
621
|
-
setSchedule(data?.id ? data : null);
|
|
622
|
-
} catch {
|
|
623
569
|
}
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
let innerCleanup;
|
|
630
|
-
const timer = setTimeout(() => {
|
|
631
|
-
if (!done) {
|
|
632
|
-
done = true;
|
|
570
|
+
}, 5e3) : null;
|
|
571
|
+
const handler = (e) => {
|
|
572
|
+
if (e.data?.type === "ow:clear-scheduling-widget") {
|
|
573
|
+
if (!e.data.insertAfter || e.data.insertAfter !== insertAfter) return;
|
|
574
|
+
setSchedule(null);
|
|
633
575
|
setLoading(false);
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
if (e.data?.type === "ow:switch-schedule") {
|
|
579
|
+
if (!e.data.insertAfter || e.data.insertAfter !== insertAfter) return;
|
|
580
|
+
switchScheduleIdRef.current = e.data.scheduleId ?? null;
|
|
581
|
+
initialized = false;
|
|
582
|
+
setLoading(true);
|
|
583
|
+
window.parent.postMessage({ type: "ow:request-user-schedules", insertAfter }, "*");
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
if (e.data?.type !== "ow:user-schedules-response") return;
|
|
587
|
+
if (e.data.insertAfter && e.data.insertAfter !== insertAfter) return;
|
|
588
|
+
if (initialized && switchScheduleIdRef.current === null) return;
|
|
589
|
+
initialized = true;
|
|
590
|
+
if (timer) clearTimeout(timer);
|
|
591
|
+
const schedules = e.data.schedules ?? [];
|
|
592
|
+
const isSwitching = switchScheduleIdRef.current !== null;
|
|
593
|
+
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;
|
|
594
|
+
switchScheduleIdRef.current = null;
|
|
595
|
+
setSchedule(target);
|
|
596
|
+
setLoading(false);
|
|
597
|
+
if (notifyOnConnect && target && !isSwitching) {
|
|
598
|
+
window.parent.postMessage({
|
|
599
|
+
type: "ow:schedule-connected",
|
|
600
|
+
schedule: { id: target.id, name: target.name },
|
|
601
|
+
insertAfter
|
|
602
|
+
}, "*");
|
|
603
|
+
window.postMessage({ type: "ow:schedule-linked", scheduleId: target.id, insertAfter }, "*");
|
|
634
604
|
}
|
|
635
|
-
}, 2e3);
|
|
636
|
-
const configHandler = (e) => {
|
|
637
|
-
if (e.data?.type !== "ow:schedule-config" || e.data.insertAfter !== insertAfter || done) return;
|
|
638
|
-
done = true;
|
|
639
|
-
clearTimeout(timer);
|
|
640
|
-
window.removeEventListener("message", configHandler);
|
|
641
|
-
innerCleanup = loadWithId(e.data.scheduleId ?? null);
|
|
642
605
|
};
|
|
643
|
-
window.addEventListener("message",
|
|
644
|
-
window.postMessage({ type: "ow:request-
|
|
606
|
+
window.addEventListener("message", handler);
|
|
607
|
+
if (!startEmpty) window.parent.postMessage({ type: "ow:request-user-schedules", insertAfter }, "*");
|
|
645
608
|
return () => {
|
|
646
|
-
window.removeEventListener("message",
|
|
647
|
-
clearTimeout(timer);
|
|
648
|
-
innerCleanup?.();
|
|
609
|
+
window.removeEventListener("message", handler);
|
|
610
|
+
if (timer) clearTimeout(timer);
|
|
649
611
|
};
|
|
650
612
|
}
|
|
651
|
-
|
|
613
|
+
if (initialScheduleId === null) {
|
|
614
|
+
setLoading(false);
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
;
|
|
618
|
+
(async () => {
|
|
619
|
+
try {
|
|
620
|
+
if (initialScheduleId) {
|
|
621
|
+
const res = await fetch(`${API_URL}/api/schedule/id/${initialScheduleId}`);
|
|
622
|
+
const data = await res.json();
|
|
623
|
+
setSchedule(data?.id ? data : null);
|
|
624
|
+
} else {
|
|
625
|
+
const domain = getApiDomain();
|
|
626
|
+
const sitemapRes = await fetch(`${API_URL}/api/schedule/sitemap/${domain}`);
|
|
627
|
+
const slugs = await sitemapRes.json();
|
|
628
|
+
if (!Array.isArray(slugs) || !slugs.length) {
|
|
629
|
+
setLoading(false);
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
const { slug } = [...slugs].sort(
|
|
633
|
+
(a, b) => new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime()
|
|
634
|
+
)[0];
|
|
635
|
+
const res = await fetch(`${API_URL}/api/schedule/${domain}/${slug}`);
|
|
636
|
+
const data = await res.json();
|
|
637
|
+
setSchedule(data?.id ? data : null);
|
|
638
|
+
}
|
|
639
|
+
} catch {
|
|
640
|
+
}
|
|
641
|
+
setLoading(false);
|
|
642
|
+
})();
|
|
652
643
|
}, []);
|
|
653
644
|
const timezoneLabel = schedule?.timezone ? (() => {
|
|
654
645
|
try {
|
|
@@ -683,7 +674,6 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
683
674
|
window.parent.postMessage({ type: "ow:scheduling-not-connected", insertAfter }, "*");
|
|
684
675
|
}
|
|
685
676
|
};
|
|
686
|
-
if (!inEditor && !loading && !schedule) return null;
|
|
687
677
|
const sectionId = `scheduling-${insertAfter}`;
|
|
688
678
|
return /* @__PURE__ */ jsxs2(
|
|
689
679
|
"section",
|
|
@@ -729,7 +719,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
729
719
|
] }),
|
|
730
720
|
/* @__PURE__ */ jsxs2("div", { className: "w-full flex flex-col items-end gap-3", children: [
|
|
731
721
|
timezoneLabel && /* @__PURE__ */ jsx2("span", { className: "font-body text-sm font-normal text-(--color-accent,#A89B83)", children: timezoneLabel }),
|
|
732
|
-
/* @__PURE__ */ jsx2("div", { className: "w-full p-0 sm:p-10 box-border", children: loading ? /* @__PURE__ */ jsx2(LoadingSkeleton, {}) : !schedule ? /* @__PURE__ */ jsx2(EmptyState, { inEditor
|
|
722
|
+
/* @__PURE__ */ jsx2("div", { className: "w-full p-0 sm:p-10 box-border", children: loading ? /* @__PURE__ */ jsx2(LoadingSkeleton, {}) : !schedule ? /* @__PURE__ */ jsx2(EmptyState, { inEditor }) : /* @__PURE__ */ jsx2(
|
|
733
723
|
ScheduleView,
|
|
734
724
|
{
|
|
735
725
|
schedule,
|
|
@@ -4185,8 +4175,844 @@ function isEditSessionActive() {
|
|
|
4185
4175
|
return new URLSearchParams(q).get("mode") === "edit";
|
|
4186
4176
|
}
|
|
4187
4177
|
|
|
4188
|
-
// src/ui/
|
|
4178
|
+
// src/ui/link-modal/calcPopoverPos.ts
|
|
4179
|
+
function calcPopoverPos(rect, parentScroll, approxW = 483, approxH = 320) {
|
|
4180
|
+
const GAP = 8;
|
|
4181
|
+
const canvasTopInIframe = parentScroll != null ? parentScroll.headerH - parentScroll.iframeOffsetTop : 0;
|
|
4182
|
+
const visibleTop = rect.top - canvasTopInIframe;
|
|
4183
|
+
let top = rect.top - GAP;
|
|
4184
|
+
let transform = "translateX(-50%) translateY(-100%)";
|
|
4185
|
+
if (visibleTop < approxH + GAP) {
|
|
4186
|
+
top = rect.bottom + GAP;
|
|
4187
|
+
transform = "translateX(-50%)";
|
|
4188
|
+
}
|
|
4189
|
+
const rawLeft = rect.left + rect.width / 2;
|
|
4190
|
+
const left = Math.max(GAP + approxW / 2, Math.min(rawLeft, window.innerWidth - GAP - approxW / 2));
|
|
4191
|
+
return { top, left, transform };
|
|
4192
|
+
}
|
|
4193
|
+
|
|
4194
|
+
// src/ui/button.tsx
|
|
4195
|
+
import * as React3 from "react";
|
|
4196
|
+
import { Slot } from "radix-ui";
|
|
4189
4197
|
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
4198
|
+
var buttonVariants = cva(
|
|
4199
|
+
"inline-flex items-center justify-center gap-1 whitespace-nowrap rounded-md text-sm font-medium transition-colors outline-none disabled:pointer-events-none disabled:opacity-50 min-w-[80px] px-3 py-2",
|
|
4200
|
+
{
|
|
4201
|
+
variants: {
|
|
4202
|
+
variant: {
|
|
4203
|
+
default: "bg-primary text-primary-foreground hover:opacity-90",
|
|
4204
|
+
outline: "border border-border bg-background text-foreground shadow-sm hover:bg-muted/80",
|
|
4205
|
+
ghost: "min-w-0 px-3 py-2 text-foreground hover:bg-muted/50"
|
|
4206
|
+
},
|
|
4207
|
+
size: {
|
|
4208
|
+
default: "h-9",
|
|
4209
|
+
sm: "h-8 min-w-[64px] px-2 py-1.5 text-sm"
|
|
4210
|
+
}
|
|
4211
|
+
},
|
|
4212
|
+
defaultVariants: {
|
|
4213
|
+
variant: "default",
|
|
4214
|
+
size: "default"
|
|
4215
|
+
}
|
|
4216
|
+
}
|
|
4217
|
+
);
|
|
4218
|
+
var Button = React3.forwardRef(
|
|
4219
|
+
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
4220
|
+
const Comp = asChild ? Slot.Root : "button";
|
|
4221
|
+
return /* @__PURE__ */ jsx5(
|
|
4222
|
+
Comp,
|
|
4223
|
+
{
|
|
4224
|
+
ref,
|
|
4225
|
+
"data-slot": "button",
|
|
4226
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
4227
|
+
...props
|
|
4228
|
+
}
|
|
4229
|
+
);
|
|
4230
|
+
}
|
|
4231
|
+
);
|
|
4232
|
+
Button.displayName = "Button";
|
|
4233
|
+
|
|
4234
|
+
// src/ui/icons.tsx
|
|
4235
|
+
import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
4236
|
+
function IconX({ className, ...props }) {
|
|
4237
|
+
return /* @__PURE__ */ jsxs3("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
4238
|
+
/* @__PURE__ */ jsx6("path", { d: "M18 6 6 18" }),
|
|
4239
|
+
/* @__PURE__ */ jsx6("path", { d: "m6 6 12 12" })
|
|
4240
|
+
] });
|
|
4241
|
+
}
|
|
4242
|
+
function IconChevronDown({ className, ...props }) {
|
|
4243
|
+
return /* @__PURE__ */ jsx6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: /* @__PURE__ */ jsx6("path", { d: "m6 9 6 6 6-6" }) });
|
|
4244
|
+
}
|
|
4245
|
+
function IconFile({ className, ...props }) {
|
|
4246
|
+
return /* @__PURE__ */ jsxs3("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
4247
|
+
/* @__PURE__ */ jsx6("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
|
|
4248
|
+
/* @__PURE__ */ jsx6("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" })
|
|
4249
|
+
] });
|
|
4250
|
+
}
|
|
4251
|
+
function IconInfo({ className, ...props }) {
|
|
4252
|
+
return /* @__PURE__ */ jsxs3("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
4253
|
+
/* @__PURE__ */ jsx6("circle", { cx: "12", cy: "12", r: "10" }),
|
|
4254
|
+
/* @__PURE__ */ jsx6("path", { d: "M12 16v-4" }),
|
|
4255
|
+
/* @__PURE__ */ jsx6("path", { d: "M12 8h.01" })
|
|
4256
|
+
] });
|
|
4257
|
+
}
|
|
4258
|
+
function IconArrowRight({ className, ...props }) {
|
|
4259
|
+
return /* @__PURE__ */ jsxs3("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
4260
|
+
/* @__PURE__ */ jsx6("path", { d: "M5 12h14" }),
|
|
4261
|
+
/* @__PURE__ */ jsx6("path", { d: "m12 5 7 7-7 7" })
|
|
4262
|
+
] });
|
|
4263
|
+
}
|
|
4264
|
+
function IconSection({ className, ...props }) {
|
|
4265
|
+
return /* @__PURE__ */ jsxs3("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
4266
|
+
/* @__PURE__ */ jsx6("rect", { width: "18", height: "7", x: "3", y: "3", rx: "1" }),
|
|
4267
|
+
/* @__PURE__ */ jsx6("rect", { width: "9", height: "7", x: "3", y: "14", rx: "1" }),
|
|
4268
|
+
/* @__PURE__ */ jsx6("rect", { width: "5", height: "7", x: "16", y: "14", rx: "1" })
|
|
4269
|
+
] });
|
|
4270
|
+
}
|
|
4271
|
+
|
|
4272
|
+
// src/ui/link-modal/DestinationBreadcrumb.tsx
|
|
4273
|
+
import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
4274
|
+
function DestinationBreadcrumb({ pageTitle, sectionLabel }) {
|
|
4275
|
+
return /* @__PURE__ */ jsxs4("div", { className: "flex w-full flex-col gap-2", children: [
|
|
4276
|
+
/* @__PURE__ */ jsx7("p", { className: "text-sm font-medium text-foreground", children: "Destination" }),
|
|
4277
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-3", children: [
|
|
4278
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2", children: [
|
|
4279
|
+
/* @__PURE__ */ jsx7(IconFile, { className: "shrink-0 text-foreground", "aria-hidden": true }),
|
|
4280
|
+
/* @__PURE__ */ jsx7("span", { className: "text-sm font-medium leading-none text-foreground", children: pageTitle })
|
|
4281
|
+
] }),
|
|
4282
|
+
/* @__PURE__ */ jsx7(IconArrowRight, { className: "shrink-0 text-muted-foreground", "aria-hidden": true }),
|
|
4283
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
|
|
4284
|
+
/* @__PURE__ */ jsx7(IconSection, { className: "shrink-0 text-foreground", "aria-hidden": true }),
|
|
4285
|
+
/* @__PURE__ */ jsx7("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
|
|
4286
|
+
] })
|
|
4287
|
+
] })
|
|
4288
|
+
] });
|
|
4289
|
+
}
|
|
4290
|
+
|
|
4291
|
+
// src/ui/link-modal/SectionTreeItem.tsx
|
|
4292
|
+
import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
4293
|
+
function SectionTreeItem({ section, onSelect, selected }) {
|
|
4294
|
+
const interactive = Boolean(onSelect);
|
|
4295
|
+
return /* @__PURE__ */ jsxs5("div", { className: "flex h-9 w-full items-end pl-3", children: [
|
|
4296
|
+
/* @__PURE__ */ jsx8(
|
|
4297
|
+
"div",
|
|
4298
|
+
{
|
|
4299
|
+
className: "mr-[-1px] h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
|
|
4300
|
+
"aria-hidden": true
|
|
4301
|
+
}
|
|
4302
|
+
),
|
|
4303
|
+
/* @__PURE__ */ jsxs5(
|
|
4304
|
+
"div",
|
|
4305
|
+
{
|
|
4306
|
+
role: interactive ? "button" : void 0,
|
|
4307
|
+
tabIndex: interactive ? 0 : void 0,
|
|
4308
|
+
onClick: interactive ? () => onSelect?.(section) : void 0,
|
|
4309
|
+
onKeyDown: interactive ? (e) => {
|
|
4310
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
4311
|
+
e.preventDefault();
|
|
4312
|
+
onSelect?.(section);
|
|
4313
|
+
}
|
|
4314
|
+
} : void 0,
|
|
4315
|
+
className: cn(
|
|
4316
|
+
"flex h-9 min-w-0 flex-1 items-center gap-2 rounded-md border border-border bg-background p-3",
|
|
4317
|
+
interactive && "cursor-pointer hover:bg-muted/30",
|
|
4318
|
+
interactive && selected && "border-primary"
|
|
4319
|
+
),
|
|
4320
|
+
children: [
|
|
4321
|
+
/* @__PURE__ */ jsx8(IconSection, { className: "shrink-0 text-foreground", "aria-hidden": true }),
|
|
4322
|
+
/* @__PURE__ */ jsx8("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
|
|
4323
|
+
]
|
|
4324
|
+
}
|
|
4325
|
+
)
|
|
4326
|
+
] });
|
|
4327
|
+
}
|
|
4328
|
+
function SectionPickerList({ sections, onSelect }) {
|
|
4329
|
+
if (sections.length === 0) {
|
|
4330
|
+
return /* @__PURE__ */ jsx8("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." });
|
|
4331
|
+
}
|
|
4332
|
+
return /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-1", children: [
|
|
4333
|
+
/* @__PURE__ */ jsx8("p", { className: "text-sm text-muted-foreground", children: "Pick a section this link should scroll to." }),
|
|
4334
|
+
sections.map((section) => /* @__PURE__ */ jsx8(SectionTreeItem, { section, onSelect }, section.id))
|
|
4335
|
+
] });
|
|
4336
|
+
}
|
|
4337
|
+
|
|
4338
|
+
// src/ui/link-modal/UrlOrPageInput.tsx
|
|
4339
|
+
import { useEffect as useEffect2, useId, useRef as useRef2, useState as useState3 } from "react";
|
|
4340
|
+
|
|
4341
|
+
// src/ui/input.tsx
|
|
4342
|
+
import * as React4 from "react";
|
|
4343
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
4344
|
+
var Input = React4.forwardRef(
|
|
4345
|
+
({ className, type, ...props }, ref) => {
|
|
4346
|
+
return /* @__PURE__ */ jsx9(
|
|
4347
|
+
"input",
|
|
4348
|
+
{
|
|
4349
|
+
type,
|
|
4350
|
+
ref,
|
|
4351
|
+
"data-slot": "input",
|
|
4352
|
+
className: cn(
|
|
4353
|
+
"flex h-full w-full min-w-0 bg-transparent text-sm text-foreground outline-none placeholder:text-muted-foreground",
|
|
4354
|
+
className
|
|
4355
|
+
),
|
|
4356
|
+
...props
|
|
4357
|
+
}
|
|
4358
|
+
);
|
|
4359
|
+
}
|
|
4360
|
+
);
|
|
4361
|
+
Input.displayName = "Input";
|
|
4362
|
+
|
|
4363
|
+
// src/ui/label.tsx
|
|
4364
|
+
import { Label as LabelPrimitive } from "radix-ui";
|
|
4365
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
4366
|
+
function Label({ className, ...props }) {
|
|
4367
|
+
return /* @__PURE__ */ jsx10(
|
|
4368
|
+
LabelPrimitive.Root,
|
|
4369
|
+
{
|
|
4370
|
+
"data-slot": "label",
|
|
4371
|
+
className: cn("text-sm font-medium leading-5 text-foreground", className),
|
|
4372
|
+
...props
|
|
4373
|
+
}
|
|
4374
|
+
);
|
|
4375
|
+
}
|
|
4376
|
+
|
|
4377
|
+
// src/ui/popover.tsx
|
|
4378
|
+
import { Popover as PopoverPrimitive } from "radix-ui";
|
|
4379
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
4380
|
+
function Popover({ ...props }) {
|
|
4381
|
+
return /* @__PURE__ */ jsx11(PopoverPrimitive.Root, { "data-slot": "popover", ...props });
|
|
4382
|
+
}
|
|
4383
|
+
function PopoverTrigger({ ...props }) {
|
|
4384
|
+
return /* @__PURE__ */ jsx11(PopoverPrimitive.Trigger, { "data-slot": "popover-trigger", ...props });
|
|
4385
|
+
}
|
|
4386
|
+
function PopoverContent({
|
|
4387
|
+
className,
|
|
4388
|
+
align = "start",
|
|
4389
|
+
sideOffset = 6,
|
|
4390
|
+
...props
|
|
4391
|
+
}) {
|
|
4392
|
+
return /* @__PURE__ */ jsx11(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx11(
|
|
4393
|
+
PopoverPrimitive.Content,
|
|
4394
|
+
{
|
|
4395
|
+
"data-slot": "popover-content",
|
|
4396
|
+
align,
|
|
4397
|
+
sideOffset,
|
|
4398
|
+
className: cn(
|
|
4399
|
+
"z-[2147483647] w-[var(--radix-popover-trigger-width)] overflow-auto rounded-lg border border-border bg-popover py-1 shadow-lg outline-none",
|
|
4400
|
+
className
|
|
4401
|
+
),
|
|
4402
|
+
...props
|
|
4403
|
+
}
|
|
4404
|
+
) });
|
|
4405
|
+
}
|
|
4406
|
+
|
|
4407
|
+
// src/ui/link-modal/UrlOrPageInput.tsx
|
|
4408
|
+
import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
4409
|
+
function FieldChevron({ onClick }) {
|
|
4410
|
+
return /* @__PURE__ */ jsx12(
|
|
4411
|
+
"button",
|
|
4412
|
+
{
|
|
4413
|
+
type: "button",
|
|
4414
|
+
className: "flex shrink-0 items-center justify-end border-0 bg-transparent p-0 pl-4 text-muted-foreground outline-none",
|
|
4415
|
+
onClick,
|
|
4416
|
+
"aria-label": "Open page list",
|
|
4417
|
+
tabIndex: -1,
|
|
4418
|
+
children: /* @__PURE__ */ jsx12(IconChevronDown, {})
|
|
4419
|
+
}
|
|
4420
|
+
);
|
|
4421
|
+
}
|
|
4422
|
+
function UrlOrPageInput({
|
|
4423
|
+
value,
|
|
4424
|
+
selectedPage,
|
|
4425
|
+
placeholder = "Paste a URL or choose a page",
|
|
4426
|
+
dropdownOpen,
|
|
4427
|
+
onDropdownOpenChange,
|
|
4428
|
+
filteredPages,
|
|
4429
|
+
onInputChange,
|
|
4430
|
+
onPageSelect,
|
|
4431
|
+
readOnly = false,
|
|
4432
|
+
urlError
|
|
4433
|
+
}) {
|
|
4434
|
+
const inputId = useId();
|
|
4435
|
+
const inputRef = useRef2(null);
|
|
4436
|
+
const [isEditing, setIsEditing] = useState3(false);
|
|
4437
|
+
const [isFocused, setIsFocused] = useState3(false);
|
|
4438
|
+
const showFilledDisplay = Boolean(selectedPage) && !isEditing && !readOnly;
|
|
4439
|
+
useEffect2(() => {
|
|
4440
|
+
if (selectedPage) setIsEditing(false);
|
|
4441
|
+
}, [selectedPage]);
|
|
4442
|
+
const openDropdown = () => {
|
|
4443
|
+
if (readOnly || filteredPages.length === 0) return;
|
|
4444
|
+
onDropdownOpenChange(true);
|
|
4445
|
+
};
|
|
4446
|
+
const toggleDropdown = (e) => {
|
|
4447
|
+
e.stopPropagation();
|
|
4448
|
+
e.preventDefault();
|
|
4449
|
+
if (readOnly || filteredPages.length === 0) return;
|
|
4450
|
+
onDropdownOpenChange(!dropdownOpen);
|
|
4451
|
+
};
|
|
4452
|
+
const enterEditMode = () => {
|
|
4453
|
+
if (readOnly) return;
|
|
4454
|
+
setIsEditing(true);
|
|
4455
|
+
requestAnimationFrame(() => inputRef.current?.focus());
|
|
4456
|
+
};
|
|
4457
|
+
const fieldClassName = cn(
|
|
4458
|
+
"data-ohw-link-field flex h-10 w-full items-center overflow-hidden rounded-md border bg-background pl-3 pr-3 py-2 outline-none transition-[border-color,box-shadow]",
|
|
4459
|
+
urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
|
|
4460
|
+
);
|
|
4461
|
+
return /* @__PURE__ */ jsxs6("div", { className: "flex w-full flex-col gap-2 p-0", children: [
|
|
4462
|
+
/* @__PURE__ */ jsx12(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
|
|
4463
|
+
/* @__PURE__ */ jsxs6(Popover, { open: dropdownOpen && !readOnly, onOpenChange: onDropdownOpenChange, children: [
|
|
4464
|
+
/* @__PURE__ */ jsx12(PopoverTrigger, { asChild: true, children: showFilledDisplay ? /* @__PURE__ */ jsxs6(
|
|
4465
|
+
"button",
|
|
4466
|
+
{
|
|
4467
|
+
type: "button",
|
|
4468
|
+
"data-ohw-link-field": true,
|
|
4469
|
+
className: cn(fieldClassName, "m-0 cursor-pointer border-solid text-left"),
|
|
4470
|
+
onClick: openDropdown,
|
|
4471
|
+
onFocus: () => setIsFocused(true),
|
|
4472
|
+
onBlur: () => setIsFocused(false),
|
|
4473
|
+
onKeyDown: (e) => {
|
|
4474
|
+
if (e.key === "Backspace" || e.key === "Delete" || e.key.length === 1) {
|
|
4475
|
+
enterEditMode();
|
|
4476
|
+
}
|
|
4477
|
+
},
|
|
4478
|
+
children: [
|
|
4479
|
+
/* @__PURE__ */ jsx12("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ jsx12(IconFile, { className: "text-foreground", "aria-hidden": true }) }),
|
|
4480
|
+
/* @__PURE__ */ jsx12("span", { className: "min-w-0 flex-1 truncate text-sm font-normal text-foreground", children: selectedPage.title }),
|
|
4481
|
+
/* @__PURE__ */ jsx12(FieldChevron, { onClick: toggleDropdown })
|
|
4482
|
+
]
|
|
4483
|
+
}
|
|
4484
|
+
) : /* @__PURE__ */ jsxs6(
|
|
4485
|
+
"div",
|
|
4486
|
+
{
|
|
4487
|
+
"data-ohw-link-field": true,
|
|
4488
|
+
className: fieldClassName,
|
|
4489
|
+
onMouseDown: (e) => {
|
|
4490
|
+
if (readOnly) return;
|
|
4491
|
+
if (e.target === e.currentTarget) enterEditMode();
|
|
4492
|
+
},
|
|
4493
|
+
children: [
|
|
4494
|
+
selectedPage ? /* @__PURE__ */ jsx12("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ jsx12(IconFile, { className: "text-foreground", "aria-hidden": true }) }) : null,
|
|
4495
|
+
readOnly ? /* @__PURE__ */ jsx12("span", { className: "min-w-0 flex-1 truncate text-sm leading-5 text-foreground", children: selectedPage?.title ?? value }) : /* @__PURE__ */ jsx12(
|
|
4496
|
+
Input,
|
|
4497
|
+
{
|
|
4498
|
+
ref: inputRef,
|
|
4499
|
+
id: inputId,
|
|
4500
|
+
value,
|
|
4501
|
+
onChange: (e) => onInputChange(e.target.value),
|
|
4502
|
+
onFocus: () => {
|
|
4503
|
+
setIsFocused(true);
|
|
4504
|
+
setIsEditing(true);
|
|
4505
|
+
openDropdown();
|
|
4506
|
+
},
|
|
4507
|
+
onBlur: () => setIsFocused(false),
|
|
4508
|
+
placeholder,
|
|
4509
|
+
className: cn(
|
|
4510
|
+
"min-w-0 flex-1 truncate border-0 bg-transparent p-0 text-sm font-normal leading-5 shadow-none outline-none ring-0",
|
|
4511
|
+
value ? "text-foreground" : "text-muted-foreground placeholder:text-muted-foreground"
|
|
4512
|
+
)
|
|
4513
|
+
}
|
|
4514
|
+
),
|
|
4515
|
+
!readOnly ? /* @__PURE__ */ jsx12(FieldChevron, { onClick: toggleDropdown }) : null
|
|
4516
|
+
]
|
|
4517
|
+
}
|
|
4518
|
+
) }),
|
|
4519
|
+
/* @__PURE__ */ jsx12(PopoverContent, { "data-ohw-link-popover-root": "", onOpenAutoFocus: (e) => e.preventDefault(), children: filteredPages.map((page) => /* @__PURE__ */ jsxs6(
|
|
4520
|
+
"button",
|
|
4521
|
+
{
|
|
4522
|
+
type: "button",
|
|
4523
|
+
className: "flex h-9 w-full items-center gap-2 border-0 bg-transparent px-3 text-left text-sm leading-5 text-foreground outline-none hover:bg-muted",
|
|
4524
|
+
onClick: () => onPageSelect(page),
|
|
4525
|
+
children: [
|
|
4526
|
+
/* @__PURE__ */ jsx12(IconFile, { className: "shrink-0", "aria-hidden": true }),
|
|
4527
|
+
/* @__PURE__ */ jsx12("span", { className: "truncate", children: page.title })
|
|
4528
|
+
]
|
|
4529
|
+
},
|
|
4530
|
+
page.path
|
|
4531
|
+
)) })
|
|
4532
|
+
] }),
|
|
4533
|
+
urlError ? /* @__PURE__ */ jsx12("p", { className: "text-sm font-medium text-destructive", children: urlError }) : null
|
|
4534
|
+
] });
|
|
4535
|
+
}
|
|
4536
|
+
|
|
4537
|
+
// src/ui/link-modal/useLinkModalState.ts
|
|
4538
|
+
import { useCallback, useEffect as useEffect3, useMemo as useMemo2, useState as useState4 } from "react";
|
|
4539
|
+
|
|
4540
|
+
// src/ui/link-modal/linkModal.utils.ts
|
|
4541
|
+
function parseTarget(target) {
|
|
4542
|
+
if (!target) return { pageRoute: "", sectionId: null };
|
|
4543
|
+
const hashIndex = target.indexOf("#");
|
|
4544
|
+
if (hashIndex === -1) return { pageRoute: target, sectionId: null };
|
|
4545
|
+
return {
|
|
4546
|
+
pageRoute: target.slice(0, hashIndex),
|
|
4547
|
+
sectionId: target.slice(hashIndex + 1) || null
|
|
4548
|
+
};
|
|
4549
|
+
}
|
|
4550
|
+
function normalizePath(path) {
|
|
4551
|
+
const trimmed = path.trim();
|
|
4552
|
+
if (!trimmed) return "/";
|
|
4553
|
+
try {
|
|
4554
|
+
if (/^https?:\/\//i.test(trimmed)) {
|
|
4555
|
+
return new URL(trimmed).pathname || "/";
|
|
4556
|
+
}
|
|
4557
|
+
} catch {
|
|
4558
|
+
}
|
|
4559
|
+
const withSlash = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
|
|
4560
|
+
if (withSlash.length > 1 && withSlash.endsWith("/")) return withSlash.slice(0, -1);
|
|
4561
|
+
return withSlash;
|
|
4562
|
+
}
|
|
4563
|
+
function findPageByPath(pages, path) {
|
|
4564
|
+
const normalized = normalizePath(path);
|
|
4565
|
+
return pages.find((p) => normalizePath(p.path) === normalized);
|
|
4566
|
+
}
|
|
4567
|
+
function inferPageTitleFromPath(path) {
|
|
4568
|
+
const normalized = normalizePath(path);
|
|
4569
|
+
if (normalized === "/") return "Home";
|
|
4570
|
+
const segment = normalized.split("/").filter(Boolean).pop() ?? "";
|
|
4571
|
+
if (!segment) return "Home";
|
|
4572
|
+
return segment.split("-").filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
4573
|
+
}
|
|
4574
|
+
function isInternalPath(route) {
|
|
4575
|
+
const trimmed = route.trim();
|
|
4576
|
+
if (!trimmed) return false;
|
|
4577
|
+
if (/^https?:\/\//i.test(trimmed)) return false;
|
|
4578
|
+
if (trimmed.startsWith("/")) return true;
|
|
4579
|
+
if (trimmed.includes(" ") || trimmed.includes(".")) return false;
|
|
4580
|
+
return true;
|
|
4581
|
+
}
|
|
4582
|
+
function resolvePage(route, pages) {
|
|
4583
|
+
const found = findPageByPath(pages, route);
|
|
4584
|
+
if (found) return { path: found.path, title: found.title };
|
|
4585
|
+
return { path: normalizePath(route), title: inferPageTitleFromPath(route) };
|
|
4586
|
+
}
|
|
4587
|
+
function getSectionsForPath(sectionsByPath, pageRoute, fallback) {
|
|
4588
|
+
if (!sectionsByPath) return fallback;
|
|
4589
|
+
const normalized = normalizePath(pageRoute);
|
|
4590
|
+
return sectionsByPath[normalized] ?? sectionsByPath[pageRoute] ?? fallback;
|
|
4591
|
+
}
|
|
4592
|
+
function buildTarget(page, section) {
|
|
4593
|
+
if (section) return `${page.path}#${section.id}`;
|
|
4594
|
+
return page.path;
|
|
4595
|
+
}
|
|
4596
|
+
function isValidUrl(urlString) {
|
|
4597
|
+
try {
|
|
4598
|
+
const url = new URL(urlString);
|
|
4599
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return false;
|
|
4600
|
+
const hostname = url.hostname;
|
|
4601
|
+
if (!hostname || hostname.length === 0) return false;
|
|
4602
|
+
if (hostname.includes(" ")) return false;
|
|
4603
|
+
return hostname.includes(".") || hostname === "localhost";
|
|
4604
|
+
} catch {
|
|
4605
|
+
return false;
|
|
4606
|
+
}
|
|
4607
|
+
}
|
|
4608
|
+
function normalizeUrl(value) {
|
|
4609
|
+
const trimmed = value.trim();
|
|
4610
|
+
if (trimmed.startsWith("http://") || trimmed.startsWith("https://")) return trimmed;
|
|
4611
|
+
return `https://${trimmed}`;
|
|
4612
|
+
}
|
|
4613
|
+
function validateUrlInput(value, pages, allPages) {
|
|
4614
|
+
if (!value.trim()) return "";
|
|
4615
|
+
const filtered = pages.filter((p) => p.title.toLowerCase().startsWith(value.toLowerCase()));
|
|
4616
|
+
if (filtered.length > 0) return "";
|
|
4617
|
+
const matchingPage = allPages.find((p) => p.title.toLowerCase() === value.toLowerCase());
|
|
4618
|
+
if (matchingPage) return "";
|
|
4619
|
+
if (!isValidUrl(normalizeUrl(value))) {
|
|
4620
|
+
return "Please enter a valid URL (e.g., https://example.com)";
|
|
4621
|
+
}
|
|
4622
|
+
return "";
|
|
4623
|
+
}
|
|
4624
|
+
function getEditModeInitialState(target, pages, sections) {
|
|
4625
|
+
const empty = {
|
|
4626
|
+
searchValue: "",
|
|
4627
|
+
selectedPage: null,
|
|
4628
|
+
selectedSection: null,
|
|
4629
|
+
step: "input"
|
|
4630
|
+
};
|
|
4631
|
+
if (!target) return empty;
|
|
4632
|
+
if (isValidUrl(normalizeUrl(target))) {
|
|
4633
|
+
return { searchValue: target, selectedPage: null, selectedSection: null, step: "input" };
|
|
4634
|
+
}
|
|
4635
|
+
const { pageRoute, sectionId } = parseTarget(target);
|
|
4636
|
+
if (sectionId) {
|
|
4637
|
+
if (isInternalPath(pageRoute)) {
|
|
4638
|
+
const page = resolvePage(pageRoute, pages);
|
|
4639
|
+
const sec = sections.find((s) => s.id === sectionId);
|
|
4640
|
+
return {
|
|
4641
|
+
searchValue: page.title,
|
|
4642
|
+
selectedPage: page,
|
|
4643
|
+
selectedSection: sec ? { id: sec.id, label: sec.label } : null,
|
|
4644
|
+
step: "input"
|
|
4645
|
+
};
|
|
4646
|
+
}
|
|
4647
|
+
return { searchValue: pageRoute || target, selectedPage: null, selectedSection: null, step: "input" };
|
|
4648
|
+
}
|
|
4649
|
+
if (isInternalPath(pageRoute)) {
|
|
4650
|
+
const page = resolvePage(pageRoute, pages);
|
|
4651
|
+
return {
|
|
4652
|
+
searchValue: page.title,
|
|
4653
|
+
selectedPage: page,
|
|
4654
|
+
selectedSection: null,
|
|
4655
|
+
step: "input"
|
|
4656
|
+
};
|
|
4657
|
+
}
|
|
4658
|
+
return { searchValue: target, selectedPage: null, selectedSection: null, step: "input" };
|
|
4659
|
+
}
|
|
4660
|
+
function filterAvailablePages(pages, existingTargets) {
|
|
4661
|
+
const taken = new Set(existingTargets);
|
|
4662
|
+
return pages.filter((p) => !taken.has(p.path));
|
|
4663
|
+
}
|
|
4664
|
+
|
|
4665
|
+
// src/ui/link-modal/useLinkModalState.ts
|
|
4666
|
+
function useLinkModalState({
|
|
4667
|
+
open,
|
|
4668
|
+
mode,
|
|
4669
|
+
pages,
|
|
4670
|
+
sections,
|
|
4671
|
+
sectionsByPath,
|
|
4672
|
+
initialTarget,
|
|
4673
|
+
existingTargets,
|
|
4674
|
+
onClose,
|
|
4675
|
+
onSubmit
|
|
4676
|
+
}) {
|
|
4677
|
+
const availablePages = useMemo2(
|
|
4678
|
+
() => mode === "create" ? filterAvailablePages(pages, existingTargets) : pages,
|
|
4679
|
+
[mode, pages, existingTargets]
|
|
4680
|
+
);
|
|
4681
|
+
const [searchValue, setSearchValue] = useState4("");
|
|
4682
|
+
const [selectedPage, setSelectedPage] = useState4(null);
|
|
4683
|
+
const [selectedSection, setSelectedSection] = useState4(null);
|
|
4684
|
+
const [step, setStep] = useState4("input");
|
|
4685
|
+
const [dropdownOpen, setDropdownOpen] = useState4(false);
|
|
4686
|
+
const [urlError, setUrlError] = useState4("");
|
|
4687
|
+
const reset = useCallback(() => {
|
|
4688
|
+
setSearchValue("");
|
|
4689
|
+
setSelectedPage(null);
|
|
4690
|
+
setSelectedSection(null);
|
|
4691
|
+
setStep("input");
|
|
4692
|
+
setDropdownOpen(false);
|
|
4693
|
+
setUrlError("");
|
|
4694
|
+
}, []);
|
|
4695
|
+
useEffect3(() => {
|
|
4696
|
+
if (!open) return;
|
|
4697
|
+
if (mode === "edit" && initialTarget) {
|
|
4698
|
+
const { pageRoute } = parseTarget(initialTarget);
|
|
4699
|
+
const targetSections = getSectionsForPath(sectionsByPath, pageRoute, sections);
|
|
4700
|
+
const init = getEditModeInitialState(initialTarget, pages, targetSections);
|
|
4701
|
+
setSearchValue(init.searchValue);
|
|
4702
|
+
setSelectedPage(init.selectedPage);
|
|
4703
|
+
setSelectedSection(init.selectedSection);
|
|
4704
|
+
setStep(init.step);
|
|
4705
|
+
} else {
|
|
4706
|
+
reset();
|
|
4707
|
+
}
|
|
4708
|
+
setDropdownOpen(false);
|
|
4709
|
+
setUrlError("");
|
|
4710
|
+
}, [open, mode, initialTarget, pages, sections, sectionsByPath, reset]);
|
|
4711
|
+
const filteredPages = useMemo2(() => {
|
|
4712
|
+
if (!searchValue.trim()) return availablePages;
|
|
4713
|
+
return availablePages.filter((p) => p.title.toLowerCase().startsWith(searchValue.toLowerCase()));
|
|
4714
|
+
}, [availablePages, searchValue]);
|
|
4715
|
+
const activeSections = useMemo2(() => {
|
|
4716
|
+
if (selectedPage && sectionsByPath) {
|
|
4717
|
+
return getSectionsForPath(sectionsByPath, selectedPage.path, sections);
|
|
4718
|
+
}
|
|
4719
|
+
return sections;
|
|
4720
|
+
}, [selectedPage, sectionsByPath, sections]);
|
|
4721
|
+
const showBreadcrumb = step === "confirmed" && selectedPage && selectedSection;
|
|
4722
|
+
const showSectionPicker = step === "sectionPicker" && selectedPage;
|
|
4723
|
+
const showSectionRow = mode === "edit" && selectedPage && selectedSection && step === "input";
|
|
4724
|
+
const showChooseSection = step === "input" && selectedPage && !selectedSection && !showSectionRow;
|
|
4725
|
+
const handleInputChange = (value) => {
|
|
4726
|
+
setSearchValue(value);
|
|
4727
|
+
setSelectedPage(null);
|
|
4728
|
+
setSelectedSection(null);
|
|
4729
|
+
setStep("input");
|
|
4730
|
+
setUrlError("");
|
|
4731
|
+
const filtered = value.trim() ? availablePages.filter((p) => p.title.toLowerCase().startsWith(value.toLowerCase())) : availablePages;
|
|
4732
|
+
setDropdownOpen(filtered.length > 0);
|
|
4733
|
+
if (value.trim() && filtered.length === 0) {
|
|
4734
|
+
const error = validateUrlInput(value, availablePages, pages);
|
|
4735
|
+
if (error) setUrlError(error);
|
|
4736
|
+
}
|
|
4737
|
+
};
|
|
4738
|
+
const handlePageSelect = (page) => {
|
|
4739
|
+
setSelectedPage({ path: page.path, title: page.title });
|
|
4740
|
+
setSelectedSection(null);
|
|
4741
|
+
setSearchValue(page.title);
|
|
4742
|
+
setStep("input");
|
|
4743
|
+
setDropdownOpen(false);
|
|
4744
|
+
setUrlError("");
|
|
4745
|
+
};
|
|
4746
|
+
const handleChooseSection = () => {
|
|
4747
|
+
setStep("sectionPicker");
|
|
4748
|
+
};
|
|
4749
|
+
const handleSectionSelect = (section) => {
|
|
4750
|
+
setSelectedSection({ id: section.id, label: section.label });
|
|
4751
|
+
if (mode === "create") {
|
|
4752
|
+
setStep("confirmed");
|
|
4753
|
+
} else {
|
|
4754
|
+
setStep("input");
|
|
4755
|
+
}
|
|
4756
|
+
};
|
|
4757
|
+
const handleBackToSections = () => {
|
|
4758
|
+
setStep("sectionPicker");
|
|
4759
|
+
};
|
|
4760
|
+
const handleClose = () => {
|
|
4761
|
+
reset();
|
|
4762
|
+
onClose();
|
|
4763
|
+
};
|
|
4764
|
+
const isValid = useMemo2(() => {
|
|
4765
|
+
if (urlError) return false;
|
|
4766
|
+
if (showBreadcrumb) return true;
|
|
4767
|
+
if (selectedPage) return true;
|
|
4768
|
+
if (!searchValue.trim()) return false;
|
|
4769
|
+
return validateUrlInput(searchValue, availablePages, pages) === "";
|
|
4770
|
+
}, [urlError, showBreadcrumb, selectedPage, searchValue, availablePages, pages]);
|
|
4771
|
+
const handleSubmit = () => {
|
|
4772
|
+
if (selectedPage && selectedSection) {
|
|
4773
|
+
onSubmit(buildTarget(selectedPage, selectedSection));
|
|
4774
|
+
handleClose();
|
|
4775
|
+
return;
|
|
4776
|
+
}
|
|
4777
|
+
if (selectedPage) {
|
|
4778
|
+
onSubmit(buildTarget(selectedPage, null));
|
|
4779
|
+
handleClose();
|
|
4780
|
+
return;
|
|
4781
|
+
}
|
|
4782
|
+
if (!searchValue.trim()) return;
|
|
4783
|
+
const error = validateUrlInput(searchValue, availablePages, pages);
|
|
4784
|
+
if (error) {
|
|
4785
|
+
setUrlError(error);
|
|
4786
|
+
return;
|
|
4787
|
+
}
|
|
4788
|
+
const matchingPage = pages.find((p) => p.title.toLowerCase() === searchValue.toLowerCase());
|
|
4789
|
+
if (matchingPage) {
|
|
4790
|
+
onSubmit(matchingPage.path);
|
|
4791
|
+
handleClose();
|
|
4792
|
+
return;
|
|
4793
|
+
}
|
|
4794
|
+
onSubmit(normalizeUrl(searchValue));
|
|
4795
|
+
handleClose();
|
|
4796
|
+
};
|
|
4797
|
+
const submitLabel = mode === "edit" ? "Save" : "Create";
|
|
4798
|
+
const title = mode === "edit" ? "Edit navigation item" : "Create navigation item";
|
|
4799
|
+
const secondaryLabel = showBreadcrumb ? "Back to sections" : "Cancel";
|
|
4800
|
+
const handleSecondary = showBreadcrumb ? handleBackToSections : handleClose;
|
|
4801
|
+
return {
|
|
4802
|
+
title,
|
|
4803
|
+
submitLabel,
|
|
4804
|
+
secondaryLabel,
|
|
4805
|
+
searchValue,
|
|
4806
|
+
selectedPage,
|
|
4807
|
+
selectedSection,
|
|
4808
|
+
step,
|
|
4809
|
+
dropdownOpen,
|
|
4810
|
+
setDropdownOpen,
|
|
4811
|
+
urlError,
|
|
4812
|
+
filteredPages,
|
|
4813
|
+
showBreadcrumb,
|
|
4814
|
+
showSectionPicker,
|
|
4815
|
+
showChooseSection,
|
|
4816
|
+
showSectionRow,
|
|
4817
|
+
isValid,
|
|
4818
|
+
activeSections,
|
|
4819
|
+
handleInputChange,
|
|
4820
|
+
handlePageSelect,
|
|
4821
|
+
handleChooseSection,
|
|
4822
|
+
handleSectionSelect,
|
|
4823
|
+
handleBackToSections,
|
|
4824
|
+
handleClose,
|
|
4825
|
+
handleSecondary,
|
|
4826
|
+
handleSubmit
|
|
4827
|
+
};
|
|
4828
|
+
}
|
|
4829
|
+
|
|
4830
|
+
// src/ui/link-modal/LinkEditorPanel.tsx
|
|
4831
|
+
import { Fragment as Fragment2, jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
4832
|
+
function LinkEditorPanel({
|
|
4833
|
+
open = true,
|
|
4834
|
+
mode = "create",
|
|
4835
|
+
pages,
|
|
4836
|
+
sections = [],
|
|
4837
|
+
sectionsByPath,
|
|
4838
|
+
initialTarget,
|
|
4839
|
+
existingTargets = [],
|
|
4840
|
+
onClose,
|
|
4841
|
+
onSubmit
|
|
4842
|
+
}) {
|
|
4843
|
+
const state = useLinkModalState({
|
|
4844
|
+
open,
|
|
4845
|
+
mode,
|
|
4846
|
+
pages,
|
|
4847
|
+
sections,
|
|
4848
|
+
sectionsByPath,
|
|
4849
|
+
initialTarget,
|
|
4850
|
+
existingTargets,
|
|
4851
|
+
onClose,
|
|
4852
|
+
onSubmit
|
|
4853
|
+
});
|
|
4854
|
+
const isCancel = state.secondaryLabel === "Cancel";
|
|
4855
|
+
return /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
4856
|
+
/* @__PURE__ */ jsx13(
|
|
4857
|
+
"button",
|
|
4858
|
+
{
|
|
4859
|
+
type: "button",
|
|
4860
|
+
className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
|
|
4861
|
+
onClick: state.handleClose,
|
|
4862
|
+
"aria-label": "Close",
|
|
4863
|
+
children: /* @__PURE__ */ jsx13(IconX, { "aria-hidden": true })
|
|
4864
|
+
}
|
|
4865
|
+
),
|
|
4866
|
+
/* @__PURE__ */ jsx13("header", { className: "flex w-full flex-col gap-1.5 p-6 pr-12", children: /* @__PURE__ */ jsx13("h2", { className: "m-0 w-full break-words text-lg font-semibold leading-none tracking-tight text-card-foreground", children: state.title }) }),
|
|
4867
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
|
|
4868
|
+
state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ jsx13(
|
|
4869
|
+
DestinationBreadcrumb,
|
|
4870
|
+
{
|
|
4871
|
+
pageTitle: state.selectedPage.title,
|
|
4872
|
+
sectionLabel: state.selectedSection.label
|
|
4873
|
+
}
|
|
4874
|
+
) : /* @__PURE__ */ jsx13(
|
|
4875
|
+
UrlOrPageInput,
|
|
4876
|
+
{
|
|
4877
|
+
value: state.searchValue,
|
|
4878
|
+
selectedPage: state.selectedPage,
|
|
4879
|
+
dropdownOpen: state.dropdownOpen,
|
|
4880
|
+
onDropdownOpenChange: state.setDropdownOpen,
|
|
4881
|
+
filteredPages: state.filteredPages,
|
|
4882
|
+
onInputChange: state.handleInputChange,
|
|
4883
|
+
onPageSelect: state.handlePageSelect,
|
|
4884
|
+
urlError: state.urlError
|
|
4885
|
+
}
|
|
4886
|
+
),
|
|
4887
|
+
state.showChooseSection ? /* @__PURE__ */ jsxs7("div", { className: "flex flex-col justify-center gap-2", children: [
|
|
4888
|
+
/* @__PURE__ */ jsx13(Button, { type: "button", variant: "outline", className: "w-fit cursor-pointer", size: "sm", onClick: state.handleChooseSection, children: "Choose a section" }),
|
|
4889
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
|
|
4890
|
+
/* @__PURE__ */ jsx13(IconInfo, { className: "shrink-0", "aria-hidden": true }),
|
|
4891
|
+
/* @__PURE__ */ jsx13("span", { children: "Pick a section this link should scroll to." })
|
|
4892
|
+
] })
|
|
4893
|
+
] }) : null,
|
|
4894
|
+
state.showSectionPicker ? /* @__PURE__ */ jsx13(SectionPickerList, { sections: state.activeSections, onSelect: state.handleSectionSelect }) : null,
|
|
4895
|
+
state.showSectionRow && state.selectedSection ? /* @__PURE__ */ jsx13(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
|
|
4896
|
+
] }),
|
|
4897
|
+
/* @__PURE__ */ jsxs7("footer", { className: "flex w-full items-center justify-end gap-2 px-6 pb-6", children: [
|
|
4898
|
+
/* @__PURE__ */ jsx13(
|
|
4899
|
+
Button,
|
|
4900
|
+
{
|
|
4901
|
+
type: "button",
|
|
4902
|
+
variant: isCancel ? "outline" : "ghost",
|
|
4903
|
+
className: "leading-6 shadow-none cursor-pointer",
|
|
4904
|
+
style: isCancel ? {
|
|
4905
|
+
backgroundColor: "var(--ohw-background)",
|
|
4906
|
+
borderColor: "var(--ohw-border)",
|
|
4907
|
+
color: "var(--ohw-foreground)"
|
|
4908
|
+
} : void 0,
|
|
4909
|
+
onClick: state.handleSecondary,
|
|
4910
|
+
children: state.secondaryLabel
|
|
4911
|
+
}
|
|
4912
|
+
),
|
|
4913
|
+
/* @__PURE__ */ jsx13(
|
|
4914
|
+
Button,
|
|
4915
|
+
{
|
|
4916
|
+
type: "button",
|
|
4917
|
+
className: "border-0 leading-6 shadow-none hover:opacity-90 disabled:opacity-50 cursor-pointer",
|
|
4918
|
+
style: {
|
|
4919
|
+
backgroundColor: "var(--ohw-primary)",
|
|
4920
|
+
color: "var(--ohw-primary-foreground)"
|
|
4921
|
+
},
|
|
4922
|
+
disabled: !state.isValid,
|
|
4923
|
+
onClick: state.handleSubmit,
|
|
4924
|
+
children: state.submitLabel
|
|
4925
|
+
}
|
|
4926
|
+
)
|
|
4927
|
+
] })
|
|
4928
|
+
] });
|
|
4929
|
+
}
|
|
4930
|
+
|
|
4931
|
+
// src/ui/link-modal/LinkPopover.tsx
|
|
4932
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
4933
|
+
function LinkPopover({
|
|
4934
|
+
rect,
|
|
4935
|
+
parentScroll,
|
|
4936
|
+
panelRef,
|
|
4937
|
+
...editorProps
|
|
4938
|
+
}) {
|
|
4939
|
+
const { top, left, transform } = calcPopoverPos(rect, parentScroll);
|
|
4940
|
+
return /* @__PURE__ */ jsx14(
|
|
4941
|
+
"div",
|
|
4942
|
+
{
|
|
4943
|
+
ref: panelRef,
|
|
4944
|
+
"data-ohw-link-popover-root": "",
|
|
4945
|
+
"data-ohw-link-modal-root": "",
|
|
4946
|
+
"data-ohw-bridge": "",
|
|
4947
|
+
className: cn(
|
|
4948
|
+
"pointer-events-auto fixed z-[2147483647] flex w-[483px] max-w-[calc(100vw-16px)] flex-col overflow-hidden",
|
|
4949
|
+
"rounded-xl border border-border bg-background font-sans shadow-lg outline-none"
|
|
4950
|
+
),
|
|
4951
|
+
style: { top, left, transform },
|
|
4952
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
4953
|
+
children: /* @__PURE__ */ jsx14(LinkEditorPanel, { ...editorProps, open: true })
|
|
4954
|
+
}
|
|
4955
|
+
);
|
|
4956
|
+
}
|
|
4957
|
+
|
|
4958
|
+
// src/ui/link-modal/devFixtures.ts
|
|
4959
|
+
var DEV_SITE_PAGES = [
|
|
4960
|
+
{ path: "/", title: "Home" },
|
|
4961
|
+
{ path: "/about", title: "About" },
|
|
4962
|
+
{ path: "/classes", title: "Classes" },
|
|
4963
|
+
{ path: "/pricing", title: "Pricing" },
|
|
4964
|
+
{ path: "/studio", title: "Studio" },
|
|
4965
|
+
{ path: "/instructors", title: "Instructors" },
|
|
4966
|
+
{ path: "/contact", title: "Contact" }
|
|
4967
|
+
];
|
|
4968
|
+
var DEV_SECTIONS_BY_PATH = {
|
|
4969
|
+
"/": [
|
|
4970
|
+
{ id: "hero", label: "Hero" },
|
|
4971
|
+
{ id: "lagree-intro", label: "Lagree Intro" },
|
|
4972
|
+
{ id: "classes-strip", label: "Classes" },
|
|
4973
|
+
{ id: "feel-split", label: "Feel Split" },
|
|
4974
|
+
{ id: "founder-teaser", label: "Founder" },
|
|
4975
|
+
{ id: "plan-form", label: "Plan Form" },
|
|
4976
|
+
{ id: "testimonials", label: "Testimonials" },
|
|
4977
|
+
{ id: "wordmark", label: "Wordmark" }
|
|
4978
|
+
],
|
|
4979
|
+
"/about": [
|
|
4980
|
+
{ id: "manifesto", label: "Manifesto" },
|
|
4981
|
+
{ id: "story-letter", label: "Our Story" },
|
|
4982
|
+
{ id: "lagree-explainer", label: "Lagree Explainer" },
|
|
4983
|
+
{ id: "waitlist-cta", label: "Waitlist" },
|
|
4984
|
+
{ id: "personal-training", label: "Personal training" }
|
|
4985
|
+
],
|
|
4986
|
+
"/classes": [{ id: "class-library", label: "Class Library" }],
|
|
4987
|
+
"/pricing": [
|
|
4988
|
+
{ id: "benefits-marquee", label: "Benefits" },
|
|
4989
|
+
{ id: "monthly-memberships", label: "Memberships" },
|
|
4990
|
+
{ id: "package-matcher", label: "Packages" },
|
|
4991
|
+
{ id: "specialty-programs", label: "Specialty Programs" },
|
|
4992
|
+
{ id: "free-class-cta", label: "Free Class" }
|
|
4993
|
+
],
|
|
4994
|
+
"/studio": [
|
|
4995
|
+
{ id: "studio-intro", label: "Studio Intro" },
|
|
4996
|
+
{ id: "studio-features", label: "Studio Features" },
|
|
4997
|
+
{ id: "studio-gallery", label: "Studio Gallery" },
|
|
4998
|
+
{ id: "studio-visit", label: "Visit Studio" }
|
|
4999
|
+
],
|
|
5000
|
+
"/instructors": [{ id: "instructor-grid", label: "Instructors" }],
|
|
5001
|
+
"/contact": [
|
|
5002
|
+
{ id: "hello-hero", label: "Hello" },
|
|
5003
|
+
{ id: "contact-form", label: "Contact Form" },
|
|
5004
|
+
{ id: "faq", label: "FAQ" }
|
|
5005
|
+
]
|
|
5006
|
+
};
|
|
5007
|
+
function shouldUseDevFixtures() {
|
|
5008
|
+
if (typeof window === "undefined") return false;
|
|
5009
|
+
const raw = readPreservedSearch();
|
|
5010
|
+
const q = raw.startsWith("?") ? raw.slice(1) : raw;
|
|
5011
|
+
return new URLSearchParams(q).get("ohw-fixtures") === "1";
|
|
5012
|
+
}
|
|
5013
|
+
|
|
5014
|
+
// src/ui/badge.tsx
|
|
5015
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
4190
5016
|
var badgeVariants = cva(
|
|
4191
5017
|
"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",
|
|
4192
5018
|
{
|
|
@@ -4204,11 +5030,11 @@ var badgeVariants = cva(
|
|
|
4204
5030
|
}
|
|
4205
5031
|
);
|
|
4206
5032
|
function Badge({ className, variant, ...props }) {
|
|
4207
|
-
return /* @__PURE__ */
|
|
5033
|
+
return /* @__PURE__ */ jsx15("div", { className: cn(badgeVariants({ variant }), className), ...props });
|
|
4208
5034
|
}
|
|
4209
5035
|
|
|
4210
5036
|
// src/OhhwellsBridge.tsx
|
|
4211
|
-
import { Fragment as
|
|
5037
|
+
import { Fragment as Fragment3, jsx as jsx16, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
4212
5038
|
var PRIMARY = "#0885FE";
|
|
4213
5039
|
var IMAGE_FADE_MS = 300;
|
|
4214
5040
|
function runOpacityFade(el, onDone) {
|
|
@@ -4348,14 +5174,9 @@ function initSectionsFromContent(content, removeExisting = false) {
|
|
|
4348
5174
|
const inEditor = typeof window !== "undefined" && window.self !== window.top;
|
|
4349
5175
|
if (inEditor) getSectionsTracker().textContent = raw;
|
|
4350
5176
|
const pageEntries = getPageSchedulingEntries(raw);
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
requestAnimationFrame(() => retryMissingSchedulingMounts(pageEntries, notifyForEntry));
|
|
4355
|
-
setTimeout(() => retryMissingSchedulingMounts(pageEntries, notifyForEntry), 250);
|
|
4356
|
-
for (const entry of preExisting) {
|
|
4357
|
-
window.postMessage({ type: "ow:schedule-config", insertAfter: entry.insertAfter, scheduleId: entry.scheduleId ?? null }, "*");
|
|
4358
|
-
}
|
|
5177
|
+
mountSchedulingEntries(pageEntries, false);
|
|
5178
|
+
requestAnimationFrame(() => retryMissingSchedulingMounts(pageEntries, false));
|
|
5179
|
+
setTimeout(() => retryMissingSchedulingMounts(pageEntries, false), 250);
|
|
4359
5180
|
} catch {
|
|
4360
5181
|
}
|
|
4361
5182
|
}
|
|
@@ -4382,7 +5203,7 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
4382
5203
|
const root = createRoot(container);
|
|
4383
5204
|
flushSync(() => {
|
|
4384
5205
|
root.render(
|
|
4385
|
-
/* @__PURE__ */
|
|
5206
|
+
/* @__PURE__ */ jsx16(
|
|
4386
5207
|
SchedulingWidget,
|
|
4387
5208
|
{
|
|
4388
5209
|
notifyOnConnect,
|
|
@@ -4414,16 +5235,23 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
|
|
|
4414
5235
|
const pending = entries.filter((e) => e.type === "scheduling").sort((a, b) => schedulingMountDepth(a.insertAfter) - schedulingMountDepth(b.insertAfter));
|
|
4415
5236
|
for (let attempt = 0; attempt < pending.length + 1 && pending.length > 0; attempt++) {
|
|
4416
5237
|
for (let i = pending.length - 1; i >= 0; i--) {
|
|
4417
|
-
const
|
|
4418
|
-
|
|
4419
|
-
if (mountSchedulingWidget(entry.insertAfter, shouldNotify, entry.scheduleId)) {
|
|
5238
|
+
const { insertAfter, scheduleId } = pending[i];
|
|
5239
|
+
if (mountSchedulingWidget(insertAfter, notifyOnConnect, scheduleId)) {
|
|
4420
5240
|
pending.splice(i, 1);
|
|
4421
5241
|
}
|
|
4422
5242
|
}
|
|
4423
5243
|
}
|
|
4424
5244
|
}
|
|
5245
|
+
function getLinkHref(el) {
|
|
5246
|
+
const anchor = el instanceof HTMLAnchorElement ? el : el.querySelector("a");
|
|
5247
|
+
return anchor?.getAttribute("href") ?? "";
|
|
5248
|
+
}
|
|
5249
|
+
function applyLinkHref(el, val) {
|
|
5250
|
+
const anchor = el instanceof HTMLAnchorElement ? el : el.querySelector("a");
|
|
5251
|
+
if (anchor) anchor.setAttribute("href", val);
|
|
5252
|
+
}
|
|
4425
5253
|
function collectEditableNodes() {
|
|
4426
|
-
|
|
5254
|
+
const nodes = Array.from(document.querySelectorAll("[data-ohw-editable]")).map((el) => {
|
|
4427
5255
|
if (el.dataset.ohwEditable === "image") {
|
|
4428
5256
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
4429
5257
|
return { key: el.dataset.ohwKey ?? "", type: "image", text: img?.src ?? "" };
|
|
@@ -4433,12 +5261,52 @@ function collectEditableNodes() {
|
|
|
4433
5261
|
const url = raw.replace(/^url\(['"]?/, "").replace(/['"]?\)$/, "");
|
|
4434
5262
|
return { key: el.dataset.ohwKey ?? "", type: "bg-image", text: url };
|
|
4435
5263
|
}
|
|
5264
|
+
if (el.dataset.ohwEditable === "link") {
|
|
5265
|
+
return { key: el.dataset.ohwKey ?? "", type: "link", text: getLinkHref(el) };
|
|
5266
|
+
}
|
|
4436
5267
|
return {
|
|
4437
5268
|
key: el.dataset.ohwKey ?? "",
|
|
4438
5269
|
type: el.dataset.ohwEditable ?? "text",
|
|
4439
5270
|
text: el.dataset.ohwEditable === "plain" ? el.innerText ?? "" : el.innerHTML
|
|
4440
5271
|
};
|
|
4441
5272
|
});
|
|
5273
|
+
document.querySelectorAll("[data-ohw-href-key]").forEach((el) => {
|
|
5274
|
+
const key = el.getAttribute("data-ohw-href-key") ?? "";
|
|
5275
|
+
if (!key) return;
|
|
5276
|
+
nodes.push({ key, type: "link", text: getLinkHref(el) });
|
|
5277
|
+
});
|
|
5278
|
+
return nodes;
|
|
5279
|
+
}
|
|
5280
|
+
function applyLinkByKey(key, val) {
|
|
5281
|
+
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
5282
|
+
if (el.dataset.ohwEditable === "link") applyLinkHref(el, val);
|
|
5283
|
+
});
|
|
5284
|
+
document.querySelectorAll(`[data-ohw-href-key="${key}"]`).forEach((el) => {
|
|
5285
|
+
applyLinkHref(el, val);
|
|
5286
|
+
});
|
|
5287
|
+
}
|
|
5288
|
+
function isInsideLinkEditor(target) {
|
|
5289
|
+
return Boolean(
|
|
5290
|
+
target.closest("[data-ohw-link-popover-root]") || target.closest("[data-ohw-link-modal-root]") || target.closest('[data-slot="popover-content"]')
|
|
5291
|
+
);
|
|
5292
|
+
}
|
|
5293
|
+
function getHrefKeyFromElement(el) {
|
|
5294
|
+
if (!el) return null;
|
|
5295
|
+
const anchor = el.closest("[data-ohw-href-key]");
|
|
5296
|
+
if (!anchor) return null;
|
|
5297
|
+
const key = anchor.getAttribute("data-ohw-href-key");
|
|
5298
|
+
if (!key) return null;
|
|
5299
|
+
return { anchor, key };
|
|
5300
|
+
}
|
|
5301
|
+
function titleCaseSectionId(id) {
|
|
5302
|
+
return id.split("-").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
5303
|
+
}
|
|
5304
|
+
function collectSections() {
|
|
5305
|
+
return Array.from(document.querySelectorAll("[data-ohw-section]")).map((el) => {
|
|
5306
|
+
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
5307
|
+
const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
|
|
5308
|
+
return { id, label };
|
|
5309
|
+
});
|
|
4442
5310
|
}
|
|
4443
5311
|
var FORCE_PSEUDO_STATES = [
|
|
4444
5312
|
{ pseudo: ":hover", state: "hover" },
|
|
@@ -4579,7 +5447,7 @@ var TOOLBAR_GROUPS = [
|
|
|
4579
5447
|
];
|
|
4580
5448
|
function GlowFrame({ rect, elRef }) {
|
|
4581
5449
|
const GAP = 6;
|
|
4582
|
-
return /* @__PURE__ */
|
|
5450
|
+
return /* @__PURE__ */ jsx16(
|
|
4583
5451
|
"div",
|
|
4584
5452
|
{
|
|
4585
5453
|
ref: elRef,
|
|
@@ -4627,10 +5495,12 @@ function FloatingToolbar({
|
|
|
4627
5495
|
parentScroll,
|
|
4628
5496
|
elRef,
|
|
4629
5497
|
onCommand,
|
|
4630
|
-
activeCommands
|
|
5498
|
+
activeCommands,
|
|
5499
|
+
showEditLink,
|
|
5500
|
+
onEditLink
|
|
4631
5501
|
}) {
|
|
4632
5502
|
const { top, left, transform } = calcToolbarPos(rect, parentScroll);
|
|
4633
|
-
return /* @__PURE__ */
|
|
5503
|
+
return /* @__PURE__ */ jsxs8(
|
|
4634
5504
|
"div",
|
|
4635
5505
|
{
|
|
4636
5506
|
ref: elRef,
|
|
@@ -4653,56 +5523,97 @@ function FloatingToolbar({
|
|
|
4653
5523
|
pointerEvents: "auto",
|
|
4654
5524
|
whiteSpace: "nowrap"
|
|
4655
5525
|
},
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
5526
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
5527
|
+
children: [
|
|
5528
|
+
TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs8(React5.Fragment, { children: [
|
|
5529
|
+
gi > 0 && /* @__PURE__ */ jsx16("span", { style: { display: "block", width: 1, height: 24, background: "#E7E5E4", flexShrink: 0 } }),
|
|
5530
|
+
btns.map((btn) => {
|
|
5531
|
+
const isActive = activeCommands.has(btn.cmd);
|
|
5532
|
+
return /* @__PURE__ */ jsx16(
|
|
5533
|
+
"button",
|
|
5534
|
+
{
|
|
5535
|
+
title: btn.title,
|
|
5536
|
+
onMouseDown: (e) => {
|
|
5537
|
+
e.preventDefault();
|
|
5538
|
+
onCommand(btn.cmd);
|
|
5539
|
+
},
|
|
5540
|
+
onMouseEnter: (e) => {
|
|
5541
|
+
if (!isActive) e.currentTarget.style.background = "#F5F5F4";
|
|
5542
|
+
},
|
|
5543
|
+
onMouseLeave: (e) => {
|
|
5544
|
+
if (!isActive) e.currentTarget.style.background = "transparent";
|
|
5545
|
+
},
|
|
5546
|
+
style: {
|
|
5547
|
+
display: "flex",
|
|
5548
|
+
alignItems: "center",
|
|
5549
|
+
justifyContent: "center",
|
|
5550
|
+
border: "none",
|
|
5551
|
+
background: isActive ? PRIMARY : "transparent",
|
|
5552
|
+
borderRadius: 4,
|
|
5553
|
+
cursor: "pointer",
|
|
5554
|
+
color: isActive ? "#FFFFFF" : "#1C1917",
|
|
5555
|
+
flexShrink: 0,
|
|
5556
|
+
padding: 6
|
|
5557
|
+
},
|
|
5558
|
+
children: /* @__PURE__ */ jsx16(
|
|
5559
|
+
"svg",
|
|
5560
|
+
{
|
|
5561
|
+
width: "16",
|
|
5562
|
+
height: "16",
|
|
5563
|
+
viewBox: "0 0 24 24",
|
|
5564
|
+
fill: "none",
|
|
5565
|
+
stroke: isActive ? "#FFFFFF" : "#1C1917",
|
|
5566
|
+
strokeWidth: "2.5",
|
|
5567
|
+
strokeLinecap: "round",
|
|
5568
|
+
strokeLinejoin: "round",
|
|
5569
|
+
style: isActive && gi > 0 ? { filter: "drop-shadow(0 0 0.5px #fff)" } : void 0,
|
|
5570
|
+
dangerouslySetInnerHTML: { __html: ICONS[btn.cmd] }
|
|
5571
|
+
}
|
|
5572
|
+
)
|
|
4685
5573
|
},
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
5574
|
+
btn.cmd
|
|
5575
|
+
);
|
|
5576
|
+
})
|
|
5577
|
+
] }, gi)),
|
|
5578
|
+
showEditLink ? /* @__PURE__ */ jsx16(
|
|
5579
|
+
"button",
|
|
5580
|
+
{
|
|
5581
|
+
type: "button",
|
|
5582
|
+
title: "Edit link",
|
|
5583
|
+
onMouseDown: (e) => {
|
|
5584
|
+
e.preventDefault();
|
|
5585
|
+
e.stopPropagation();
|
|
5586
|
+
onEditLink?.();
|
|
5587
|
+
},
|
|
5588
|
+
onClick: (e) => {
|
|
5589
|
+
e.preventDefault();
|
|
5590
|
+
e.stopPropagation();
|
|
4701
5591
|
},
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
5592
|
+
onMouseEnter: (e) => {
|
|
5593
|
+
e.currentTarget.style.background = "#F5F5F4";
|
|
5594
|
+
},
|
|
5595
|
+
onMouseLeave: (e) => {
|
|
5596
|
+
e.currentTarget.style.background = "transparent";
|
|
5597
|
+
},
|
|
5598
|
+
style: {
|
|
5599
|
+
display: "flex",
|
|
5600
|
+
alignItems: "center",
|
|
5601
|
+
justifyContent: "center",
|
|
5602
|
+
border: "none",
|
|
5603
|
+
background: "transparent",
|
|
5604
|
+
borderRadius: 4,
|
|
5605
|
+
cursor: "pointer",
|
|
5606
|
+
color: "#1C1917",
|
|
5607
|
+
flexShrink: 0,
|
|
5608
|
+
padding: 6
|
|
5609
|
+
},
|
|
5610
|
+
children: /* @__PURE__ */ jsxs8("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
5611
|
+
/* @__PURE__ */ jsx16("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }),
|
|
5612
|
+
/* @__PURE__ */ jsx16("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })
|
|
5613
|
+
] })
|
|
5614
|
+
}
|
|
5615
|
+
) : null
|
|
5616
|
+
]
|
|
4706
5617
|
}
|
|
4707
5618
|
);
|
|
4708
5619
|
}
|
|
@@ -4716,7 +5627,7 @@ function StateToggle({
|
|
|
4716
5627
|
states,
|
|
4717
5628
|
onStateChange
|
|
4718
5629
|
}) {
|
|
4719
|
-
return /* @__PURE__ */
|
|
5630
|
+
return /* @__PURE__ */ jsx16(
|
|
4720
5631
|
ToggleGroup,
|
|
4721
5632
|
{
|
|
4722
5633
|
"data-ohw-state-toggle": "",
|
|
@@ -4730,7 +5641,7 @@ function StateToggle({
|
|
|
4730
5641
|
left: rect.right - 8,
|
|
4731
5642
|
transform: "translateX(-100%)"
|
|
4732
5643
|
},
|
|
4733
|
-
children: states.map((state) => /* @__PURE__ */
|
|
5644
|
+
children: states.map((state) => /* @__PURE__ */ jsx16(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
|
|
4734
5645
|
}
|
|
4735
5646
|
);
|
|
4736
5647
|
}
|
|
@@ -4757,8 +5668,8 @@ function OhhwellsBridge() {
|
|
|
4757
5668
|
const router = useRouter();
|
|
4758
5669
|
const searchParams = useSearchParams();
|
|
4759
5670
|
const isEditMode = isEditSessionActive();
|
|
4760
|
-
const [bridgeRoot, setBridgeRoot] =
|
|
4761
|
-
|
|
5671
|
+
const [bridgeRoot, setBridgeRoot] = useState5(null);
|
|
5672
|
+
useEffect4(() => {
|
|
4762
5673
|
const figtreeFontId = "ohw-figtree-font";
|
|
4763
5674
|
if (!document.getElementById(figtreeFontId)) {
|
|
4764
5675
|
const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
|
|
@@ -4782,41 +5693,83 @@ function OhhwellsBridge() {
|
|
|
4782
5693
|
}, []);
|
|
4783
5694
|
const subdomainFromQuery = searchParams.get("subdomain");
|
|
4784
5695
|
const subdomain = resolveSubdomain(subdomainFromQuery);
|
|
4785
|
-
const postToParent =
|
|
5696
|
+
const postToParent = useCallback2((data) => {
|
|
4786
5697
|
if (typeof window !== "undefined" && window.parent !== window) {
|
|
4787
5698
|
window.parent.postMessage(data, "*");
|
|
4788
5699
|
}
|
|
4789
5700
|
}, []);
|
|
4790
|
-
const [fetchState, setFetchState] =
|
|
4791
|
-
const autoSaveTimers =
|
|
4792
|
-
const activeElRef =
|
|
4793
|
-
const originalContentRef =
|
|
4794
|
-
const activeStateElRef =
|
|
4795
|
-
const parentScrollRef =
|
|
4796
|
-
const toolbarElRef =
|
|
4797
|
-
const glowElRef =
|
|
4798
|
-
const hoveredImageRef =
|
|
4799
|
-
const hoveredImageHasTextOverlapRef =
|
|
4800
|
-
const hoveredGapRef =
|
|
4801
|
-
const imageUnhoverTimerRef =
|
|
4802
|
-
const imageShowTimerRef =
|
|
4803
|
-
const editStylesRef =
|
|
4804
|
-
const activateRef =
|
|
5701
|
+
const [fetchState, setFetchState] = useState5("idle");
|
|
5702
|
+
const autoSaveTimers = useRef3(/* @__PURE__ */ new Map());
|
|
5703
|
+
const activeElRef = useRef3(null);
|
|
5704
|
+
const originalContentRef = useRef3(null);
|
|
5705
|
+
const activeStateElRef = useRef3(null);
|
|
5706
|
+
const parentScrollRef = useRef3(null);
|
|
5707
|
+
const toolbarElRef = useRef3(null);
|
|
5708
|
+
const glowElRef = useRef3(null);
|
|
5709
|
+
const hoveredImageRef = useRef3(null);
|
|
5710
|
+
const hoveredImageHasTextOverlapRef = useRef3(false);
|
|
5711
|
+
const hoveredGapRef = useRef3(null);
|
|
5712
|
+
const imageUnhoverTimerRef = useRef3(null);
|
|
5713
|
+
const imageShowTimerRef = useRef3(null);
|
|
5714
|
+
const editStylesRef = useRef3(null);
|
|
5715
|
+
const activateRef = useRef3(() => {
|
|
4805
5716
|
});
|
|
4806
|
-
const deactivateRef =
|
|
5717
|
+
const deactivateRef = useRef3(() => {
|
|
4807
5718
|
});
|
|
4808
|
-
const refreshActiveCommandsRef =
|
|
5719
|
+
const refreshActiveCommandsRef = useRef3(() => {
|
|
4809
5720
|
});
|
|
4810
|
-
const postToParentRef =
|
|
5721
|
+
const postToParentRef = useRef3(postToParent);
|
|
4811
5722
|
postToParentRef.current = postToParent;
|
|
4812
|
-
const
|
|
4813
|
-
const
|
|
4814
|
-
const [
|
|
4815
|
-
const [
|
|
4816
|
-
const [
|
|
4817
|
-
const [
|
|
4818
|
-
const [
|
|
4819
|
-
|
|
5723
|
+
const [toolbarRect, setToolbarRect] = useState5(null);
|
|
5724
|
+
const [toggleState, setToggleState] = useState5(null);
|
|
5725
|
+
const [maxBadge, setMaxBadge] = useState5(null);
|
|
5726
|
+
const [activeCommands, setActiveCommands] = useState5(/* @__PURE__ */ new Set());
|
|
5727
|
+
const [toolbarShowEditLink, setToolbarShowEditLink] = useState5(false);
|
|
5728
|
+
const [linkPopover, setLinkPopover] = useState5(null);
|
|
5729
|
+
const [sitePages, setSitePages] = useState5([]);
|
|
5730
|
+
const [sectionsByPath, setSectionsByPath] = useState5({});
|
|
5731
|
+
const setLinkPopoverRef = useRef3(setLinkPopover);
|
|
5732
|
+
const linkPopoverPanelRef = useRef3(null);
|
|
5733
|
+
const linkPopoverOpenRef = useRef3(false);
|
|
5734
|
+
const linkPopoverGraceUntilRef = useRef3(0);
|
|
5735
|
+
setLinkPopoverRef.current = setLinkPopover;
|
|
5736
|
+
const bumpLinkPopoverGrace = () => {
|
|
5737
|
+
linkPopoverGraceUntilRef.current = Date.now() + 350;
|
|
5738
|
+
};
|
|
5739
|
+
useEffect4(() => {
|
|
5740
|
+
if (!linkPopover) return;
|
|
5741
|
+
if (hoveredImageRef.current) {
|
|
5742
|
+
hoveredImageRef.current = null;
|
|
5743
|
+
hoveredImageHasTextOverlapRef.current = false;
|
|
5744
|
+
}
|
|
5745
|
+
postToParent({ type: "ow:image-unhover" });
|
|
5746
|
+
}, [linkPopover, postToParent]);
|
|
5747
|
+
useEffect4(() => {
|
|
5748
|
+
if (!isEditMode) return;
|
|
5749
|
+
const useFixtures = shouldUseDevFixtures();
|
|
5750
|
+
if (useFixtures) {
|
|
5751
|
+
setSitePages(DEV_SITE_PAGES);
|
|
5752
|
+
setSectionsByPath(DEV_SECTIONS_BY_PATH);
|
|
5753
|
+
if (process.env.NODE_ENV === "development") {
|
|
5754
|
+
console.info("[ohhwells-bridge] Dev fixtures loaded (ohw-fixtures=1)");
|
|
5755
|
+
}
|
|
5756
|
+
}
|
|
5757
|
+
const onSitePages = (e) => {
|
|
5758
|
+
if (e.data?.type !== "ow:site-pages" || !Array.isArray(e.data.pages)) return;
|
|
5759
|
+
if (useFixtures) return;
|
|
5760
|
+
setSitePages(
|
|
5761
|
+
e.data.pages.map((p) => ({
|
|
5762
|
+
path: p.path,
|
|
5763
|
+
title: p.title
|
|
5764
|
+
}))
|
|
5765
|
+
);
|
|
5766
|
+
};
|
|
5767
|
+
window.addEventListener("message", onSitePages);
|
|
5768
|
+
if (!useFixtures) postToParent({ type: "ow:request-site-pages" });
|
|
5769
|
+
return () => window.removeEventListener("message", onSitePages);
|
|
5770
|
+
}, [isEditMode, postToParent]);
|
|
5771
|
+
const [sectionGap, setSectionGap] = useState5(null);
|
|
5772
|
+
useEffect4(() => {
|
|
4820
5773
|
const update = () => {
|
|
4821
5774
|
const el = activeElRef.current;
|
|
4822
5775
|
if (el) setToolbarRect(el.getBoundingClientRect());
|
|
@@ -4840,33 +5793,10 @@ function OhhwellsBridge() {
|
|
|
4840
5793
|
vvp.removeEventListener("resize", update);
|
|
4841
5794
|
};
|
|
4842
5795
|
}, []);
|
|
4843
|
-
const refreshStateRules =
|
|
5796
|
+
const refreshStateRules = useCallback2(() => {
|
|
4844
5797
|
editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
|
|
4845
5798
|
}, []);
|
|
4846
|
-
const
|
|
4847
|
-
const tracker = getSectionsTracker();
|
|
4848
|
-
let entries = [];
|
|
4849
|
-
try {
|
|
4850
|
-
entries = JSON.parse(tracker.textContent || "[]");
|
|
4851
|
-
} catch {
|
|
4852
|
-
}
|
|
4853
|
-
const path = window.location.pathname;
|
|
4854
|
-
const entry = entries.find(
|
|
4855
|
-
(e) => e.type === "scheduling" && e.insertAfter === insertAfterVal && (!e.pagePath || e.pagePath === path)
|
|
4856
|
-
);
|
|
4857
|
-
if (entry) {
|
|
4858
|
-
window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: entry.scheduleId ?? null }, "*");
|
|
4859
|
-
return;
|
|
4860
|
-
}
|
|
4861
|
-
const newEntry = { type: "scheduling", insertAfter: insertAfterVal, pagePath: path };
|
|
4862
|
-
entries.push(newEntry);
|
|
4863
|
-
tracker.textContent = JSON.stringify(entries);
|
|
4864
|
-
if (isEditMode) {
|
|
4865
|
-
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent }] });
|
|
4866
|
-
}
|
|
4867
|
-
window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
|
|
4868
|
-
}, [isEditMode]);
|
|
4869
|
-
const deactivate = useCallback(() => {
|
|
5799
|
+
const deactivate = useCallback2(() => {
|
|
4870
5800
|
const el = activeElRef.current;
|
|
4871
5801
|
if (!el) return;
|
|
4872
5802
|
const key = el.dataset.ohwKey;
|
|
@@ -4889,9 +5819,10 @@ function OhhwellsBridge() {
|
|
|
4889
5819
|
setToolbarRect(null);
|
|
4890
5820
|
setMaxBadge(null);
|
|
4891
5821
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
5822
|
+
setToolbarShowEditLink(false);
|
|
4892
5823
|
postToParent({ type: "ow:exit-edit" });
|
|
4893
5824
|
}, [postToParent]);
|
|
4894
|
-
const activate =
|
|
5825
|
+
const activate = useCallback2((el) => {
|
|
4895
5826
|
if (activeElRef.current === el) return;
|
|
4896
5827
|
deactivate();
|
|
4897
5828
|
if (hoveredImageRef.current) {
|
|
@@ -4904,6 +5835,7 @@ function OhhwellsBridge() {
|
|
|
4904
5835
|
originalContentRef.current = el.innerHTML;
|
|
4905
5836
|
el.focus();
|
|
4906
5837
|
setToolbarRect(el.getBoundingClientRect());
|
|
5838
|
+
setToolbarShowEditLink(Boolean(getHrefKeyFromElement(el)));
|
|
4907
5839
|
postToParent({ type: "ow:enter-edit", key: el.dataset.ohwKey });
|
|
4908
5840
|
requestAnimationFrame(() => refreshActiveCommandsRef.current());
|
|
4909
5841
|
}, [deactivate, postToParent]);
|
|
@@ -4931,14 +5863,15 @@ function OhhwellsBridge() {
|
|
|
4931
5863
|
} else if (el.dataset.ohwEditable === "bg-image") {
|
|
4932
5864
|
const next = `url('${val}')`;
|
|
4933
5865
|
if (el.style.backgroundImage !== next) el.style.backgroundImage = next;
|
|
5866
|
+
} else if (el.dataset.ohwEditable === "link") {
|
|
5867
|
+
applyLinkHref(el, val);
|
|
4934
5868
|
} else if (el.innerHTML !== val) {
|
|
4935
5869
|
el.innerHTML = val;
|
|
4936
5870
|
}
|
|
4937
5871
|
});
|
|
5872
|
+
applyLinkByKey(key, val);
|
|
4938
5873
|
}
|
|
4939
5874
|
initSectionsFromContent(content, true);
|
|
4940
|
-
sectionsLoadedRef.current = true;
|
|
4941
|
-
pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
|
|
4942
5875
|
return imageLoads.length > 0 ? Promise.all(imageLoads).then(() => {
|
|
4943
5876
|
}) : Promise.resolve();
|
|
4944
5877
|
};
|
|
@@ -4963,7 +5896,7 @@ function OhhwellsBridge() {
|
|
|
4963
5896
|
cancelled = true;
|
|
4964
5897
|
};
|
|
4965
5898
|
}, [subdomain, isEditMode, pathname]);
|
|
4966
|
-
|
|
5899
|
+
useEffect4(() => {
|
|
4967
5900
|
if (!subdomain || isEditMode) return;
|
|
4968
5901
|
let debounceTimer = null;
|
|
4969
5902
|
const applyFromCache = () => {
|
|
@@ -4979,10 +5912,13 @@ function OhhwellsBridge() {
|
|
|
4979
5912
|
} else if (el.dataset.ohwEditable === "bg-image") {
|
|
4980
5913
|
const next = `url('${val}')`;
|
|
4981
5914
|
if (el.style.backgroundImage !== next) el.style.backgroundImage = next;
|
|
5915
|
+
} else if (el.dataset.ohwEditable === "link") {
|
|
5916
|
+
applyLinkHref(el, val);
|
|
4982
5917
|
} else if (el.innerHTML !== val) {
|
|
4983
5918
|
el.innerHTML = val;
|
|
4984
5919
|
}
|
|
4985
5920
|
});
|
|
5921
|
+
applyLinkByKey(key, val);
|
|
4986
5922
|
}
|
|
4987
5923
|
};
|
|
4988
5924
|
const scheduleApply = () => {
|
|
@@ -5003,10 +5939,10 @@ function OhhwellsBridge() {
|
|
|
5003
5939
|
const visible = Boolean(subdomain) && fetchState !== "done";
|
|
5004
5940
|
el.style.display = visible ? "flex" : "none";
|
|
5005
5941
|
}, [subdomain, fetchState]);
|
|
5006
|
-
|
|
5942
|
+
useEffect4(() => {
|
|
5007
5943
|
postToParent({ type: "ow:navigation", path: pathname });
|
|
5008
5944
|
}, [pathname, postToParent]);
|
|
5009
|
-
|
|
5945
|
+
useEffect4(() => {
|
|
5010
5946
|
if (!isEditMode) return;
|
|
5011
5947
|
const measure = () => {
|
|
5012
5948
|
const h = document.body.scrollHeight;
|
|
@@ -5030,7 +5966,7 @@ function OhhwellsBridge() {
|
|
|
5030
5966
|
window.removeEventListener("resize", handleResize);
|
|
5031
5967
|
};
|
|
5032
5968
|
}, [pathname, isEditMode, postToParent]);
|
|
5033
|
-
|
|
5969
|
+
useEffect4(() => {
|
|
5034
5970
|
if (!subdomainFromQuery || isEditMode) return;
|
|
5035
5971
|
const handleClick = (e) => {
|
|
5036
5972
|
const anchor = e.target.closest("a");
|
|
@@ -5046,7 +5982,7 @@ function OhhwellsBridge() {
|
|
|
5046
5982
|
document.addEventListener("click", handleClick, true);
|
|
5047
5983
|
return () => document.removeEventListener("click", handleClick, true);
|
|
5048
5984
|
}, [subdomainFromQuery, isEditMode, router]);
|
|
5049
|
-
|
|
5985
|
+
useEffect4(() => {
|
|
5050
5986
|
if (!isEditMode) {
|
|
5051
5987
|
editStylesRef.current?.base.remove();
|
|
5052
5988
|
editStylesRef.current?.forceHover.remove();
|
|
@@ -5072,6 +6008,7 @@ function OhhwellsBridge() {
|
|
|
5072
6008
|
[data-ohw-editable]:not([contenteditable]):not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]) { cursor: text !important; }
|
|
5073
6009
|
[data-ohw-editable="image"], [data-ohw-editable="image"] *,
|
|
5074
6010
|
[data-ohw-editable="bg-image"], [data-ohw-editable="bg-image"] * { cursor: pointer !important; }
|
|
6011
|
+
[data-ohw-editable="link"], [data-ohw-editable="link"] * { cursor: pointer !important; }
|
|
5075
6012
|
[data-ohw-hovered]:not([contenteditable]) {
|
|
5076
6013
|
outline: 2px dashed ${PRIMARY} !important;
|
|
5077
6014
|
outline-offset: 4px;
|
|
@@ -5109,8 +6046,21 @@ function OhhwellsBridge() {
|
|
|
5109
6046
|
if (target.closest("[data-ohw-toolbar]")) return;
|
|
5110
6047
|
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
5111
6048
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
6049
|
+
if (isInsideLinkEditor(target)) return;
|
|
5112
6050
|
const editable = target.closest("[data-ohw-editable]");
|
|
5113
6051
|
if (editable) {
|
|
6052
|
+
if (editable.dataset.ohwEditable === "link") {
|
|
6053
|
+
e.preventDefault();
|
|
6054
|
+
e.stopPropagation();
|
|
6055
|
+
deactivateRef.current();
|
|
6056
|
+
bumpLinkPopoverGrace();
|
|
6057
|
+
setLinkPopoverRef.current({
|
|
6058
|
+
key: editable.dataset.ohwKey ?? "",
|
|
6059
|
+
target: getLinkHref(editable),
|
|
6060
|
+
rect: editable.getBoundingClientRect()
|
|
6061
|
+
});
|
|
6062
|
+
return;
|
|
6063
|
+
}
|
|
5114
6064
|
if (editable.dataset.ohwEditable === "image" || editable.dataset.ohwEditable === "bg-image") {
|
|
5115
6065
|
e.preventDefault();
|
|
5116
6066
|
e.stopPropagation();
|
|
@@ -5131,6 +6081,15 @@ function OhhwellsBridge() {
|
|
|
5131
6081
|
}
|
|
5132
6082
|
const anchor = target.closest("a");
|
|
5133
6083
|
if (anchor) e.preventDefault();
|
|
6084
|
+
if (Date.now() < linkPopoverGraceUntilRef.current) return;
|
|
6085
|
+
if (linkPopoverOpenRef.current && activeElRef.current) {
|
|
6086
|
+
const hrefCtx = getHrefKeyFromElement(activeElRef.current);
|
|
6087
|
+
if (hrefCtx && (hrefCtx.anchor === target || hrefCtx.anchor.contains(target))) return;
|
|
6088
|
+
}
|
|
6089
|
+
if (linkPopoverOpenRef.current) {
|
|
6090
|
+
setLinkPopoverRef.current(null);
|
|
6091
|
+
return;
|
|
6092
|
+
}
|
|
5134
6093
|
deactivateRef.current();
|
|
5135
6094
|
};
|
|
5136
6095
|
const handleMouseOver = (e) => {
|
|
@@ -5237,6 +6196,15 @@ function OhhwellsBridge() {
|
|
|
5237
6196
|
return smallest;
|
|
5238
6197
|
};
|
|
5239
6198
|
const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
|
|
6199
|
+
if (linkPopoverOpenRef.current) {
|
|
6200
|
+
if (hoveredImageRef.current) {
|
|
6201
|
+
hoveredImageRef.current = null;
|
|
6202
|
+
hoveredImageHasTextOverlapRef.current = false;
|
|
6203
|
+
resumeAnimTracks();
|
|
6204
|
+
postToParentRef.current({ type: "ow:image-unhover" });
|
|
6205
|
+
}
|
|
6206
|
+
return;
|
|
6207
|
+
}
|
|
5240
6208
|
const toggleEl = document.querySelector("[data-ohw-state-toggle]");
|
|
5241
6209
|
if (toggleEl) {
|
|
5242
6210
|
const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
@@ -5262,6 +6230,15 @@ function OhhwellsBridge() {
|
|
|
5262
6230
|
}
|
|
5263
6231
|
return;
|
|
5264
6232
|
}
|
|
6233
|
+
if (topEl?.closest("[data-ohw-link-popover-root]") || topEl?.closest("[data-ohw-link-modal-root]")) {
|
|
6234
|
+
if (hoveredImageRef.current) {
|
|
6235
|
+
hoveredImageRef.current = null;
|
|
6236
|
+
hoveredImageHasTextOverlapRef.current = false;
|
|
6237
|
+
resumeAnimTracks();
|
|
6238
|
+
postToParentRef.current({ type: "ow:image-unhover" });
|
|
6239
|
+
}
|
|
6240
|
+
return;
|
|
6241
|
+
}
|
|
5265
6242
|
const isStateCardImage = !!imgEl.closest("[data-ohw-editable-state]");
|
|
5266
6243
|
const textEditable = Array.from(
|
|
5267
6244
|
document.querySelectorAll('[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"])')
|
|
@@ -5581,25 +6558,35 @@ function OhhwellsBridge() {
|
|
|
5581
6558
|
if (img) img.src = val;
|
|
5582
6559
|
} else if (el.dataset.ohwEditable === "bg-image") {
|
|
5583
6560
|
el.style.backgroundImage = `url('${val}')`;
|
|
6561
|
+
} else if (el.dataset.ohwEditable === "link") {
|
|
6562
|
+
applyLinkHref(el, val);
|
|
5584
6563
|
} else {
|
|
5585
6564
|
el.innerHTML = val;
|
|
5586
6565
|
}
|
|
5587
6566
|
});
|
|
6567
|
+
applyLinkByKey(key, val);
|
|
5588
6568
|
}
|
|
5589
6569
|
if (sectionsJson) {
|
|
5590
6570
|
initSectionsFromContent({ __ohw_sections: sectionsJson }, true);
|
|
5591
|
-
sectionsLoadedRef.current = true;
|
|
5592
|
-
pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
|
|
5593
6571
|
}
|
|
5594
6572
|
postToParentRef.current({ type: "ow:hydrate-done" });
|
|
5595
6573
|
};
|
|
5596
6574
|
window.addEventListener("message", handleHydrate);
|
|
5597
6575
|
const handleDeactivate = (e) => {
|
|
5598
6576
|
if (e.data?.type !== "ow:deactivate") return;
|
|
6577
|
+
if (Date.now() < linkPopoverGraceUntilRef.current) return;
|
|
6578
|
+
if (linkPopoverOpenRef.current) {
|
|
6579
|
+
setLinkPopoverRef.current(null);
|
|
6580
|
+
return;
|
|
6581
|
+
}
|
|
5599
6582
|
deactivateRef.current();
|
|
5600
6583
|
};
|
|
5601
6584
|
window.addEventListener("message", handleDeactivate);
|
|
5602
6585
|
const handleKeyDown = (e) => {
|
|
6586
|
+
if (e.key === "Escape" && linkPopoverOpenRef.current) {
|
|
6587
|
+
setLinkPopoverRef.current(null);
|
|
6588
|
+
return;
|
|
6589
|
+
}
|
|
5603
6590
|
if (e.key !== "Escape") return;
|
|
5604
6591
|
const el = activeElRef.current;
|
|
5605
6592
|
if (el && originalContentRef.current !== null) {
|
|
@@ -5853,23 +6840,7 @@ function OhhwellsBridge() {
|
|
|
5853
6840
|
if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
|
|
5854
6841
|
};
|
|
5855
6842
|
}, [isEditMode, refreshStateRules]);
|
|
5856
|
-
|
|
5857
|
-
const handler = (e) => {
|
|
5858
|
-
if (e.data?.type !== "ow:request-schedule-config") return;
|
|
5859
|
-
const insertAfterVal = e.data.insertAfter;
|
|
5860
|
-
if (!insertAfterVal) return;
|
|
5861
|
-
if (!sectionsLoadedRef.current) {
|
|
5862
|
-
if (!pendingScheduleConfigRequests.current.includes(insertAfterVal)) {
|
|
5863
|
-
pendingScheduleConfigRequests.current.push(insertAfterVal);
|
|
5864
|
-
}
|
|
5865
|
-
return;
|
|
5866
|
-
}
|
|
5867
|
-
processConfigRequest(insertAfterVal);
|
|
5868
|
-
};
|
|
5869
|
-
window.addEventListener("message", handler);
|
|
5870
|
-
return () => window.removeEventListener("message", handler);
|
|
5871
|
-
}, [processConfigRequest]);
|
|
5872
|
-
useEffect2(() => {
|
|
6843
|
+
useEffect4(() => {
|
|
5873
6844
|
if (!isEditMode) return;
|
|
5874
6845
|
document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
|
|
5875
6846
|
el.removeAttribute("data-ohw-active-state");
|
|
@@ -5884,20 +6855,26 @@ function OhhwellsBridge() {
|
|
|
5884
6855
|
const raf = requestAnimationFrame(() => refreshStateRules());
|
|
5885
6856
|
const timer = setTimeout(() => {
|
|
5886
6857
|
refreshStateRules();
|
|
5887
|
-
|
|
6858
|
+
const sections = collectSections();
|
|
6859
|
+
setSectionsByPath((prev) => {
|
|
6860
|
+
const next = { ...prev, [pathname]: sections };
|
|
6861
|
+
return shouldUseDevFixtures() ? { ...DEV_SECTIONS_BY_PATH, ...next } : next;
|
|
6862
|
+
});
|
|
6863
|
+
postToParent({ type: "ow:ready", version: "1", path: pathname, nodes: collectEditableNodes(), sections });
|
|
6864
|
+
postToParent({ type: "ow:request-site-pages" });
|
|
5888
6865
|
}, 150);
|
|
5889
6866
|
return () => {
|
|
5890
6867
|
cancelAnimationFrame(raf);
|
|
5891
6868
|
clearTimeout(timer);
|
|
5892
6869
|
};
|
|
5893
6870
|
}, [pathname, isEditMode, refreshStateRules, postToParent]);
|
|
5894
|
-
const handleCommand =
|
|
6871
|
+
const handleCommand = useCallback2((cmd) => {
|
|
5895
6872
|
document.execCommand(cmd, false);
|
|
5896
6873
|
activeElRef.current?.focus();
|
|
5897
6874
|
if (activeElRef.current) setToolbarRect(activeElRef.current.getBoundingClientRect());
|
|
5898
6875
|
refreshActiveCommandsRef.current();
|
|
5899
6876
|
}, []);
|
|
5900
|
-
const handleStateChange =
|
|
6877
|
+
const handleStateChange = useCallback2((state) => {
|
|
5901
6878
|
if (!activeStateElRef.current) return;
|
|
5902
6879
|
const el = activeStateElRef.current;
|
|
5903
6880
|
if (state === "Default") {
|
|
@@ -5910,13 +6887,48 @@ function OhhwellsBridge() {
|
|
|
5910
6887
|
}
|
|
5911
6888
|
setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
|
|
5912
6889
|
}, [deactivate]);
|
|
6890
|
+
const closeLinkPopover = useCallback2(() => setLinkPopover(null), []);
|
|
6891
|
+
const openLinkPopoverForActive = useCallback2(() => {
|
|
6892
|
+
const hrefCtx = getHrefKeyFromElement(activeElRef.current);
|
|
6893
|
+
if (!hrefCtx) return;
|
|
6894
|
+
bumpLinkPopoverGrace();
|
|
6895
|
+
setLinkPopover({
|
|
6896
|
+
key: hrefCtx.key,
|
|
6897
|
+
target: getLinkHref(hrefCtx.anchor),
|
|
6898
|
+
rect: hrefCtx.anchor.getBoundingClientRect()
|
|
6899
|
+
});
|
|
6900
|
+
}, []);
|
|
6901
|
+
const handleLinkPopoverSubmit = useCallback2(
|
|
6902
|
+
(target) => {
|
|
6903
|
+
if (!linkPopover) return;
|
|
6904
|
+
const { key } = linkPopover;
|
|
6905
|
+
applyLinkByKey(key, target);
|
|
6906
|
+
postToParent({ type: "ow:change", nodes: [{ key, text: target }] });
|
|
6907
|
+
setLinkPopover(null);
|
|
6908
|
+
},
|
|
6909
|
+
[linkPopover, postToParent]
|
|
6910
|
+
);
|
|
6911
|
+
const showEditLink = toolbarShowEditLink;
|
|
6912
|
+
const currentSections = sectionsByPath[pathname] ?? [];
|
|
6913
|
+
linkPopoverOpenRef.current = linkPopover !== null;
|
|
5913
6914
|
return bridgeRoot ? createPortal(
|
|
5914
|
-
/* @__PURE__ */
|
|
5915
|
-
toolbarRect && /* @__PURE__ */
|
|
5916
|
-
/* @__PURE__ */
|
|
5917
|
-
/* @__PURE__ */
|
|
6915
|
+
/* @__PURE__ */ jsxs8(Fragment3, { children: [
|
|
6916
|
+
toolbarRect && /* @__PURE__ */ jsxs8(Fragment3, { children: [
|
|
6917
|
+
/* @__PURE__ */ jsx16(GlowFrame, { rect: toolbarRect, elRef: glowElRef }),
|
|
6918
|
+
/* @__PURE__ */ jsx16(
|
|
6919
|
+
FloatingToolbar,
|
|
6920
|
+
{
|
|
6921
|
+
rect: toolbarRect,
|
|
6922
|
+
parentScroll: parentScrollRef.current,
|
|
6923
|
+
elRef: toolbarElRef,
|
|
6924
|
+
onCommand: handleCommand,
|
|
6925
|
+
activeCommands,
|
|
6926
|
+
showEditLink,
|
|
6927
|
+
onEditLink: openLinkPopoverForActive
|
|
6928
|
+
}
|
|
6929
|
+
)
|
|
5918
6930
|
] }),
|
|
5919
|
-
maxBadge && /* @__PURE__ */
|
|
6931
|
+
maxBadge && /* @__PURE__ */ jsxs8(
|
|
5920
6932
|
"div",
|
|
5921
6933
|
{
|
|
5922
6934
|
"data-ohw-max-badge": "",
|
|
@@ -5942,7 +6954,7 @@ function OhhwellsBridge() {
|
|
|
5942
6954
|
]
|
|
5943
6955
|
}
|
|
5944
6956
|
),
|
|
5945
|
-
toggleState && /* @__PURE__ */
|
|
6957
|
+
toggleState && /* @__PURE__ */ jsx16(
|
|
5946
6958
|
StateToggle,
|
|
5947
6959
|
{
|
|
5948
6960
|
rect: toggleState.rect,
|
|
@@ -5951,15 +6963,31 @@ function OhhwellsBridge() {
|
|
|
5951
6963
|
onStateChange: handleStateChange
|
|
5952
6964
|
}
|
|
5953
6965
|
),
|
|
5954
|
-
|
|
6966
|
+
linkPopover ? /* @__PURE__ */ jsx16(
|
|
6967
|
+
LinkPopover,
|
|
6968
|
+
{
|
|
6969
|
+
rect: linkPopover.rect,
|
|
6970
|
+
parentScroll: parentScrollRef.current,
|
|
6971
|
+
panelRef: linkPopoverPanelRef,
|
|
6972
|
+
open: true,
|
|
6973
|
+
mode: "edit",
|
|
6974
|
+
pages: sitePages,
|
|
6975
|
+
sections: currentSections,
|
|
6976
|
+
sectionsByPath,
|
|
6977
|
+
initialTarget: linkPopover.target,
|
|
6978
|
+
onClose: closeLinkPopover,
|
|
6979
|
+
onSubmit: handleLinkPopoverSubmit
|
|
6980
|
+
}
|
|
6981
|
+
) : null,
|
|
6982
|
+
sectionGap && /* @__PURE__ */ jsxs8(
|
|
5955
6983
|
"div",
|
|
5956
6984
|
{
|
|
5957
6985
|
"data-ohw-section-insert-line": "",
|
|
5958
6986
|
className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
|
|
5959
6987
|
style: { top: sectionGap.y, transform: "translateY(-50%)" },
|
|
5960
6988
|
children: [
|
|
5961
|
-
/* @__PURE__ */
|
|
5962
|
-
/* @__PURE__ */
|
|
6989
|
+
/* @__PURE__ */ jsx16("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
|
|
6990
|
+
/* @__PURE__ */ jsx16(
|
|
5963
6991
|
Badge,
|
|
5964
6992
|
{
|
|
5965
6993
|
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",
|
|
@@ -5972,7 +7000,7 @@ function OhhwellsBridge() {
|
|
|
5972
7000
|
children: "Add Section"
|
|
5973
7001
|
}
|
|
5974
7002
|
),
|
|
5975
|
-
/* @__PURE__ */
|
|
7003
|
+
/* @__PURE__ */ jsx16("div", { className: "flex-1 bg-primary", style: { height: 3 } })
|
|
5976
7004
|
]
|
|
5977
7005
|
}
|
|
5978
7006
|
)
|
|
@@ -5981,11 +7009,19 @@ function OhhwellsBridge() {
|
|
|
5981
7009
|
) : null;
|
|
5982
7010
|
}
|
|
5983
7011
|
export {
|
|
7012
|
+
LinkEditorPanel,
|
|
7013
|
+
LinkPopover,
|
|
5984
7014
|
OhhwellsBridge,
|
|
5985
7015
|
SchedulingWidget,
|
|
5986
7016
|
Toggle,
|
|
5987
7017
|
ToggleGroup,
|
|
5988
7018
|
ToggleGroupItem,
|
|
5989
|
-
|
|
7019
|
+
buildTarget,
|
|
7020
|
+
filterAvailablePages,
|
|
7021
|
+
getEditModeInitialState,
|
|
7022
|
+
isValidUrl,
|
|
7023
|
+
parseTarget,
|
|
7024
|
+
toggleVariants,
|
|
7025
|
+
validateUrlInput
|
|
5990
7026
|
};
|
|
5991
7027
|
//# sourceMappingURL=index.js.map
|