@ohhwells/bridge 0.1.37 → 0.1.38-next.57
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 +12 -0
- package/dist/index.cjs +2191 -615
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +51 -4
- package/dist/index.d.ts +51 -4
- package/dist/index.js +2189 -613
- package/dist/index.js.map +1 -1
- package/dist/styles.css +160 -34
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
// src/OhhwellsBridge.tsx
|
|
4
|
-
import
|
|
4
|
+
import React9, { useCallback as useCallback4, useEffect as useEffect7, useLayoutEffect as useLayoutEffect2, useRef as useRef5, useState as useState6 } from "react";
|
|
5
5
|
import { createRoot } from "react-dom/client";
|
|
6
6
|
import { flushSync } from "react-dom";
|
|
7
7
|
|
|
@@ -10,6 +10,9 @@ var linkHrefStore = /* @__PURE__ */ new Map();
|
|
|
10
10
|
function setStoredLinkHref(key, href) {
|
|
11
11
|
linkHrefStore.set(key, href);
|
|
12
12
|
}
|
|
13
|
+
function getStoredLinkHref(key) {
|
|
14
|
+
return linkHrefStore.get(key);
|
|
15
|
+
}
|
|
13
16
|
function enforceLinkHrefs() {
|
|
14
17
|
document.querySelectorAll("[data-ohw-href-key]").forEach((el) => {
|
|
15
18
|
const key = el.getAttribute("data-ohw-href-key") ?? "";
|
|
@@ -45,12 +48,13 @@ function useLinkHrefGuardian(...deps) {
|
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
// src/ui/SchedulingWidget.tsx
|
|
48
|
-
import { useEffect, useId, useMemo, useRef, useState as useState2 } from "react";
|
|
51
|
+
import { useCallback, useEffect, useId, useMemo, useRef, useState as useState2 } from "react";
|
|
49
52
|
|
|
50
53
|
// src/ui/EmailCaptureModal.tsx
|
|
51
54
|
import { useState } from "react";
|
|
52
55
|
import { Dialog } from "radix-ui";
|
|
53
56
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
57
|
+
var isValidEmail = (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
|
|
54
58
|
function Spinner() {
|
|
55
59
|
return /* @__PURE__ */ jsxs(
|
|
56
60
|
"svg",
|
|
@@ -84,12 +88,17 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
|
|
|
84
88
|
const [error, setError] = useState(null);
|
|
85
89
|
const isBook = title === "Confirm your spot";
|
|
86
90
|
const handleSubmit = async () => {
|
|
87
|
-
|
|
91
|
+
const trimmed = email.trim();
|
|
92
|
+
if (!trimmed) return;
|
|
93
|
+
if (!isValidEmail(trimmed)) {
|
|
94
|
+
setError("Please enter a valid email address.");
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
88
97
|
setLoading(true);
|
|
89
98
|
setError(null);
|
|
90
99
|
try {
|
|
91
|
-
await onSubmit(
|
|
92
|
-
setSubmittedEmail(
|
|
100
|
+
await onSubmit(trimmed);
|
|
101
|
+
setSubmittedEmail(trimmed);
|
|
93
102
|
setSuccess(true);
|
|
94
103
|
} catch (e) {
|
|
95
104
|
setError(e instanceof Error ? e.message : "Something went wrong. Please try again.");
|
|
@@ -164,7 +173,10 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
|
|
|
164
173
|
{
|
|
165
174
|
type: "email",
|
|
166
175
|
value: email,
|
|
167
|
-
onChange: (e) =>
|
|
176
|
+
onChange: (e) => {
|
|
177
|
+
setEmail(e.target.value);
|
|
178
|
+
if (error) setError(null);
|
|
179
|
+
},
|
|
168
180
|
onKeyDown: handleKeyDown,
|
|
169
181
|
placeholder: "hello@gmail.com",
|
|
170
182
|
autoFocus: true,
|
|
@@ -221,12 +233,20 @@ function formatClassTime(cls) {
|
|
|
221
233
|
const em = endTotal % 60;
|
|
222
234
|
return `${h}:${cls.startTime.minutes}-${eh}:${String(em).padStart(2, "0")}`;
|
|
223
235
|
}
|
|
236
|
+
function formatBookingLabel(cls) {
|
|
237
|
+
const price = cls.price;
|
|
238
|
+
const isFree = price === null || price === void 0 || `${price}` === "" || `${price}` === "0";
|
|
239
|
+
return isFree ? "Book for free" : `Book for ${cls.currency ?? ""} ${price}`.trim();
|
|
240
|
+
}
|
|
224
241
|
function getBookingsOnDate(cls, date) {
|
|
225
242
|
if (!cls.bookings?.length) return 0;
|
|
226
|
-
const
|
|
243
|
+
const target = new Date(date);
|
|
244
|
+
target.setHours(0, 0, 0, 0);
|
|
227
245
|
return cls.bookings.filter((b) => {
|
|
228
246
|
try {
|
|
229
|
-
|
|
247
|
+
const bookingDate = new Date(b.classDate);
|
|
248
|
+
bookingDate.setHours(0, 0, 0, 0);
|
|
249
|
+
return bookingDate.getTime() === target.getTime();
|
|
230
250
|
} catch {
|
|
231
251
|
return false;
|
|
232
252
|
}
|
|
@@ -530,7 +550,7 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
|
|
|
530
550
|
if (!cls.id) return;
|
|
531
551
|
onOpenModal?.(isFull ? "waitlist" : "book", cls.id, selectedDate);
|
|
532
552
|
},
|
|
533
|
-
children: isFull ? "Join Waitlist" :
|
|
553
|
+
children: isFull ? "Join Waitlist" : formatBookingLabel(cls)
|
|
534
554
|
}
|
|
535
555
|
)
|
|
536
556
|
] })
|
|
@@ -572,6 +592,17 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
572
592
|
const [isHovered, setIsHovered] = useState2(false);
|
|
573
593
|
const [modalState, setModalState] = useState2(null);
|
|
574
594
|
const switchScheduleIdRef = useRef(null);
|
|
595
|
+
const liveScheduleIdRef = useRef(null);
|
|
596
|
+
const refetchLiveSchedule = useCallback(async () => {
|
|
597
|
+
const id = liveScheduleIdRef.current;
|
|
598
|
+
if (!id) return;
|
|
599
|
+
try {
|
|
600
|
+
const res = await fetch(`${API_URL}/api/schedule/id/${id}`);
|
|
601
|
+
const data = await res.json();
|
|
602
|
+
if (data?.id) setSchedule(data);
|
|
603
|
+
} catch {
|
|
604
|
+
}
|
|
605
|
+
}, []);
|
|
575
606
|
const dates = useMemo(() => {
|
|
576
607
|
const today = /* @__PURE__ */ new Date();
|
|
577
608
|
today.setHours(0, 0, 0, 0);
|
|
@@ -591,6 +622,18 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
591
622
|
}
|
|
592
623
|
}
|
|
593
624
|
}, [schedule, dates]);
|
|
625
|
+
useEffect(() => {
|
|
626
|
+
if (typeof window === "undefined") return;
|
|
627
|
+
const onVisible = () => {
|
|
628
|
+
if (!document.hidden) void refetchLiveSchedule();
|
|
629
|
+
};
|
|
630
|
+
window.addEventListener("focus", refetchLiveSchedule);
|
|
631
|
+
document.addEventListener("visibilitychange", onVisible);
|
|
632
|
+
return () => {
|
|
633
|
+
window.removeEventListener("focus", refetchLiveSchedule);
|
|
634
|
+
document.removeEventListener("visibilitychange", onVisible);
|
|
635
|
+
};
|
|
636
|
+
}, [refetchLiveSchedule]);
|
|
594
637
|
useEffect(() => {
|
|
595
638
|
if (typeof window === "undefined") return;
|
|
596
639
|
const isInEditor = window.self !== window.top;
|
|
@@ -652,7 +695,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
652
695
|
setLoading(false);
|
|
653
696
|
return;
|
|
654
697
|
}
|
|
655
|
-
;
|
|
698
|
+
liveScheduleIdRef.current = effectiveId;
|
|
656
699
|
(async () => {
|
|
657
700
|
try {
|
|
658
701
|
const res = await fetch(`${API_URL}/api/schedule/id/${effectiveId}`);
|
|
@@ -709,18 +752,14 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
709
752
|
const data = await res.json().catch(() => ({}));
|
|
710
753
|
throw new Error(data?.message ?? "Something went wrong. Please try again.");
|
|
711
754
|
}
|
|
755
|
+
await refetchLiveSchedule();
|
|
712
756
|
};
|
|
713
757
|
const handleReplaceSchedule = () => {
|
|
714
758
|
setIsHovered(false);
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
insertAfter
|
|
720
|
-
}, "*");
|
|
721
|
-
} else {
|
|
722
|
-
window.parent.postMessage({ type: "ow:scheduling-not-connected", insertAfter }, "*");
|
|
723
|
-
}
|
|
759
|
+
window.parent.postMessage(
|
|
760
|
+
{ type: "ow:scheduling-not-connected", insertAfter, currentScheduleId: schedule?.id },
|
|
761
|
+
"*"
|
|
762
|
+
);
|
|
724
763
|
};
|
|
725
764
|
if (!inEditor && !loading && !schedule) return null;
|
|
726
765
|
const sectionId = `scheduling-${insertAfter}`;
|
|
@@ -763,7 +802,19 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
763
802
|
),
|
|
764
803
|
/* @__PURE__ */ jsxs2("div", { className: "max-w-[1280px] mx-auto flex flex-col items-center gap-16", children: [
|
|
765
804
|
/* @__PURE__ */ jsxs2("div", { className: "flex flex-col items-center gap-4", children: [
|
|
766
|
-
/* @__PURE__ */ jsx2(
|
|
805
|
+
/* @__PURE__ */ jsx2(
|
|
806
|
+
"h2",
|
|
807
|
+
{
|
|
808
|
+
className: "font-display text-center m-0 text-(--color-dark,#200C02)",
|
|
809
|
+
style: {
|
|
810
|
+
fontSize: "var(--fs-section-h2, clamp(40px, 4.4vw, 64px))",
|
|
811
|
+
fontWeight: "var(--font-weight-heading, 400)",
|
|
812
|
+
lineHeight: 1.05,
|
|
813
|
+
letterSpacing: "-0.02em"
|
|
814
|
+
},
|
|
815
|
+
children: schedule?.name ?? "Book an appointment"
|
|
816
|
+
}
|
|
817
|
+
),
|
|
767
818
|
schedule?.description && /* @__PURE__ */ jsx2("p", { className: "font-body text-body text-center m-0 text-(--color-accent,#A89B83)", children: schedule.description })
|
|
768
819
|
] }),
|
|
769
820
|
/* @__PURE__ */ jsxs2("div", { className: "w-full flex flex-col items-end gap-3", children: [
|
|
@@ -4349,6 +4400,7 @@ function ItemActionToolbar({
|
|
|
4349
4400
|
onEditLink,
|
|
4350
4401
|
onAddItem,
|
|
4351
4402
|
onMore,
|
|
4403
|
+
editLinkDisabled = false,
|
|
4352
4404
|
addItemDisabled = true,
|
|
4353
4405
|
moreDisabled = true,
|
|
4354
4406
|
tooltipSide = "bottom"
|
|
@@ -4357,10 +4409,12 @@ function ItemActionToolbar({
|
|
|
4357
4409
|
/* @__PURE__ */ jsx8(
|
|
4358
4410
|
ToolbarActionTooltip,
|
|
4359
4411
|
{
|
|
4360
|
-
label: "
|
|
4412
|
+
label: "Edit link",
|
|
4361
4413
|
side: tooltipSide,
|
|
4414
|
+
disabled: editLinkDisabled,
|
|
4362
4415
|
buttonProps: {
|
|
4363
4416
|
onMouseDown: (e) => {
|
|
4417
|
+
if (editLinkDisabled) return;
|
|
4364
4418
|
e.preventDefault();
|
|
4365
4419
|
e.stopPropagation();
|
|
4366
4420
|
onEditLink?.();
|
|
@@ -4532,9 +4586,223 @@ function ItemInteractionLayer({
|
|
|
4532
4586
|
);
|
|
4533
4587
|
}
|
|
4534
4588
|
|
|
4589
|
+
// src/ui/MediaOverlay.tsx
|
|
4590
|
+
import * as React6 from "react";
|
|
4591
|
+
import { Film, ImageIcon, Pause, Play, Volume2, VolumeX } from "lucide-react";
|
|
4592
|
+
|
|
4593
|
+
// src/ui/button.tsx
|
|
4594
|
+
import * as React5 from "react";
|
|
4595
|
+
import { Slot } from "radix-ui";
|
|
4596
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
4597
|
+
var buttonVariants = cva(
|
|
4598
|
+
"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",
|
|
4599
|
+
{
|
|
4600
|
+
variants: {
|
|
4601
|
+
variant: {
|
|
4602
|
+
default: "bg-primary text-primary-foreground hover:opacity-90",
|
|
4603
|
+
outline: "border border-border bg-background text-foreground shadow-sm hover:bg-muted/80",
|
|
4604
|
+
ghost: "min-w-0 px-3 py-2 text-foreground hover:bg-muted/50"
|
|
4605
|
+
},
|
|
4606
|
+
size: {
|
|
4607
|
+
default: "h-9",
|
|
4608
|
+
sm: "h-8 min-w-[64px] px-2 py-1.5 text-sm"
|
|
4609
|
+
}
|
|
4610
|
+
},
|
|
4611
|
+
defaultVariants: {
|
|
4612
|
+
variant: "default",
|
|
4613
|
+
size: "default"
|
|
4614
|
+
}
|
|
4615
|
+
}
|
|
4616
|
+
);
|
|
4617
|
+
var Button = React5.forwardRef(
|
|
4618
|
+
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
4619
|
+
const Comp = asChild ? Slot.Root : "button";
|
|
4620
|
+
return /* @__PURE__ */ jsx10(
|
|
4621
|
+
Comp,
|
|
4622
|
+
{
|
|
4623
|
+
ref,
|
|
4624
|
+
"data-slot": "button",
|
|
4625
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
4626
|
+
...props
|
|
4627
|
+
}
|
|
4628
|
+
);
|
|
4629
|
+
}
|
|
4630
|
+
);
|
|
4631
|
+
Button.displayName = "Button";
|
|
4632
|
+
|
|
4633
|
+
// src/ui/MediaOverlay.tsx
|
|
4634
|
+
import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
4635
|
+
var MEDIA_UPLOAD_FADE_MS = 300;
|
|
4636
|
+
var VIDEO_SETTINGS_BAR_INSET = 8;
|
|
4637
|
+
var OVERLAY_BUTTON_STYLE = {
|
|
4638
|
+
pointerEvents: "auto",
|
|
4639
|
+
fontFamily: "Inter, sans-serif",
|
|
4640
|
+
fontSize: 12,
|
|
4641
|
+
color: "#000"
|
|
4642
|
+
};
|
|
4643
|
+
var SKELETON_CSS = `
|
|
4644
|
+
@keyframes ohw-media-shimmer {
|
|
4645
|
+
0% { transform: translateX(-100%); }
|
|
4646
|
+
100% { transform: translateX(100%); }
|
|
4647
|
+
}
|
|
4648
|
+
[data-ohw-media-skeleton] {
|
|
4649
|
+
overflow: hidden;
|
|
4650
|
+
background-color: #d1d5db; /* tailwind gray-300 */
|
|
4651
|
+
}
|
|
4652
|
+
[data-ohw-media-skeleton]::after {
|
|
4653
|
+
content: "";
|
|
4654
|
+
position: absolute;
|
|
4655
|
+
inset: 0;
|
|
4656
|
+
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.6), transparent);
|
|
4657
|
+
animation: ohw-media-shimmer 1.4s infinite;
|
|
4658
|
+
}
|
|
4659
|
+
`;
|
|
4660
|
+
function MediaOverlay({
|
|
4661
|
+
hover,
|
|
4662
|
+
isUploading,
|
|
4663
|
+
fadingOut = false,
|
|
4664
|
+
onFadeOutComplete,
|
|
4665
|
+
onReplace,
|
|
4666
|
+
onVideoSettingsChange
|
|
4667
|
+
}) {
|
|
4668
|
+
const { rect } = hover;
|
|
4669
|
+
const skeletonRef = React6.useRef(null);
|
|
4670
|
+
const isVideo = hover.elementType === "video";
|
|
4671
|
+
const autoplay = hover.videoAutoplay ?? true;
|
|
4672
|
+
const muted = hover.videoMuted ?? true;
|
|
4673
|
+
const box = {
|
|
4674
|
+
position: "fixed",
|
|
4675
|
+
top: rect.top,
|
|
4676
|
+
left: rect.left,
|
|
4677
|
+
width: rect.width,
|
|
4678
|
+
height: rect.height,
|
|
4679
|
+
zIndex: 2147483646
|
|
4680
|
+
};
|
|
4681
|
+
React6.useEffect(() => {
|
|
4682
|
+
if (!isUploading || !fadingOut || !skeletonRef.current) return;
|
|
4683
|
+
const anim = skeletonRef.current.animate([{ opacity: 1 }, { opacity: 0 }], {
|
|
4684
|
+
duration: MEDIA_UPLOAD_FADE_MS,
|
|
4685
|
+
easing: "ease-out",
|
|
4686
|
+
fill: "forwards"
|
|
4687
|
+
});
|
|
4688
|
+
anim.finished.then(() => onFadeOutComplete?.(hover.key)).catch(() => onFadeOutComplete?.(hover.key));
|
|
4689
|
+
return () => anim.cancel();
|
|
4690
|
+
}, [isUploading, fadingOut, onFadeOutComplete, hover.key]);
|
|
4691
|
+
if (isUploading) {
|
|
4692
|
+
return /* @__PURE__ */ jsx11(
|
|
4693
|
+
"div",
|
|
4694
|
+
{
|
|
4695
|
+
ref: skeletonRef,
|
|
4696
|
+
"data-ohw-bridge": "",
|
|
4697
|
+
"data-ohw-media-overlay": "",
|
|
4698
|
+
"data-ohw-media-skeleton": "",
|
|
4699
|
+
"aria-hidden": true,
|
|
4700
|
+
style: { ...box, pointerEvents: "none" },
|
|
4701
|
+
children: /* @__PURE__ */ jsx11("style", { children: SKELETON_CSS })
|
|
4702
|
+
}
|
|
4703
|
+
);
|
|
4704
|
+
}
|
|
4705
|
+
const settingsBar = isVideo && !hover.isDragOver ? /* @__PURE__ */ jsxs5(
|
|
4706
|
+
"div",
|
|
4707
|
+
{
|
|
4708
|
+
"data-ohw-bridge": "",
|
|
4709
|
+
"data-ohw-media-overlay": "",
|
|
4710
|
+
className: "flex items-center justify-center gap-1.5",
|
|
4711
|
+
style: {
|
|
4712
|
+
position: "fixed",
|
|
4713
|
+
top: rect.top + VIDEO_SETTINGS_BAR_INSET,
|
|
4714
|
+
left: rect.left,
|
|
4715
|
+
width: rect.width,
|
|
4716
|
+
zIndex: 2147483647,
|
|
4717
|
+
pointerEvents: "auto"
|
|
4718
|
+
},
|
|
4719
|
+
onClick: (e) => e.stopPropagation(),
|
|
4720
|
+
children: [
|
|
4721
|
+
/* @__PURE__ */ jsx11(
|
|
4722
|
+
Button,
|
|
4723
|
+
{
|
|
4724
|
+
"data-ohw-media-overlay": "",
|
|
4725
|
+
variant: "outline",
|
|
4726
|
+
size: "sm",
|
|
4727
|
+
className: "cursor-pointer hover:bg-background",
|
|
4728
|
+
style: { ...OVERLAY_BUTTON_STYLE, minWidth: 0, padding: "0 8px" },
|
|
4729
|
+
"aria-label": autoplay ? "Disable autoplay" : "Enable autoplay",
|
|
4730
|
+
title: autoplay ? "Autoplay on \u2014 click to disable" : "Autoplay off \u2014 click to enable",
|
|
4731
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
4732
|
+
onClick: (e) => {
|
|
4733
|
+
e.stopPropagation();
|
|
4734
|
+
onVideoSettingsChange?.(hover.key, { autoplay: !autoplay });
|
|
4735
|
+
},
|
|
4736
|
+
children: autoplay ? /* @__PURE__ */ jsx11(Pause, { size: 14 }) : /* @__PURE__ */ jsx11(Play, { size: 14 })
|
|
4737
|
+
}
|
|
4738
|
+
),
|
|
4739
|
+
/* @__PURE__ */ jsx11(
|
|
4740
|
+
Button,
|
|
4741
|
+
{
|
|
4742
|
+
"data-ohw-media-overlay": "",
|
|
4743
|
+
variant: "outline",
|
|
4744
|
+
size: "sm",
|
|
4745
|
+
className: "cursor-pointer hover:bg-background",
|
|
4746
|
+
style: { ...OVERLAY_BUTTON_STYLE, minWidth: 0, padding: "0 8px" },
|
|
4747
|
+
"aria-label": muted ? "Unmute video" : "Mute video",
|
|
4748
|
+
title: muted ? "Muted \u2014 click to unmute" : "Sound on \u2014 click to mute",
|
|
4749
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
4750
|
+
onClick: (e) => {
|
|
4751
|
+
e.stopPropagation();
|
|
4752
|
+
onVideoSettingsChange?.(hover.key, { muted: !muted });
|
|
4753
|
+
},
|
|
4754
|
+
children: muted ? /* @__PURE__ */ jsx11(VolumeX, { size: 14 }) : /* @__PURE__ */ jsx11(Volume2, { size: 14 })
|
|
4755
|
+
}
|
|
4756
|
+
)
|
|
4757
|
+
]
|
|
4758
|
+
}
|
|
4759
|
+
) : null;
|
|
4760
|
+
return /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
4761
|
+
settingsBar,
|
|
4762
|
+
/* @__PURE__ */ jsx11(
|
|
4763
|
+
"div",
|
|
4764
|
+
{
|
|
4765
|
+
"data-ohw-bridge": "",
|
|
4766
|
+
"data-ohw-media-overlay": "",
|
|
4767
|
+
className: "flex items-center justify-center cursor-pointer",
|
|
4768
|
+
style: {
|
|
4769
|
+
...box,
|
|
4770
|
+
// When text overlays this media, let clicks fall THROUGH to the text underneath. In the
|
|
4771
|
+
// parent this needed a whole `ow:click-at` round-trip to re-hit-test inside the iframe;
|
|
4772
|
+
// in-document, pointer-events does it natively. The button below opts back in, so
|
|
4773
|
+
// Replace still works.
|
|
4774
|
+
pointerEvents: hover.hasTextOverlap ? "none" : "auto",
|
|
4775
|
+
boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
|
|
4776
|
+
background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
|
|
4777
|
+
},
|
|
4778
|
+
onClick: () => onReplace(hover.key),
|
|
4779
|
+
children: /* @__PURE__ */ jsxs5(
|
|
4780
|
+
Button,
|
|
4781
|
+
{
|
|
4782
|
+
"data-ohw-media-overlay": "",
|
|
4783
|
+
variant: "outline",
|
|
4784
|
+
size: "sm",
|
|
4785
|
+
className: "gap-1.5 cursor-pointer hover:bg-background",
|
|
4786
|
+
style: OVERLAY_BUTTON_STYLE,
|
|
4787
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
4788
|
+
onClick: (e) => {
|
|
4789
|
+
e.stopPropagation();
|
|
4790
|
+
onReplace(hover.key);
|
|
4791
|
+
},
|
|
4792
|
+
children: [
|
|
4793
|
+
isVideo ? /* @__PURE__ */ jsx11(Film, { size: 14 }) : /* @__PURE__ */ jsx11(ImageIcon, { size: 14 }),
|
|
4794
|
+
isVideo ? "Replace video" : "Replace image"
|
|
4795
|
+
]
|
|
4796
|
+
}
|
|
4797
|
+
)
|
|
4798
|
+
}
|
|
4799
|
+
)
|
|
4800
|
+
] });
|
|
4801
|
+
}
|
|
4802
|
+
|
|
4535
4803
|
// src/OhhwellsBridge.tsx
|
|
4536
|
-
import { createPortal } from "react-dom";
|
|
4537
|
-
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
|
4804
|
+
import { createPortal as createPortal2 } from "react-dom";
|
|
4805
|
+
import { usePathname as usePathname2, useRouter as useRouter2, useSearchParams } from "next/navigation";
|
|
4538
4806
|
|
|
4539
4807
|
// src/lib/session-search.ts
|
|
4540
4808
|
var STORAGE_KEY = "ohw-preserved-search";
|
|
@@ -4810,61 +5078,29 @@ function scrollToHashSectionWhenReady(behavior = "smooth") {
|
|
|
4810
5078
|
tick();
|
|
4811
5079
|
}
|
|
4812
5080
|
|
|
4813
|
-
// src/ui/
|
|
4814
|
-
import
|
|
4815
|
-
import { Dialog as DialogPrimitive } from "radix-ui";
|
|
4816
|
-
|
|
4817
|
-
// src/ui/icons.tsx
|
|
4818
|
-
import { jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
4819
|
-
function IconX({ className, ...props }) {
|
|
4820
|
-
return /* @__PURE__ */ jsxs5("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
4821
|
-
/* @__PURE__ */ jsx10("path", { d: "M18 6 6 18" }),
|
|
4822
|
-
/* @__PURE__ */ jsx10("path", { d: "m6 6 12 12" })
|
|
4823
|
-
] });
|
|
4824
|
-
}
|
|
4825
|
-
function IconChevronDown({ className, ...props }) {
|
|
4826
|
-
return /* @__PURE__ */ jsx10("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: /* @__PURE__ */ jsx10("path", { d: "m6 9 6 6 6-6" }) });
|
|
4827
|
-
}
|
|
4828
|
-
function IconFile({ className, ...props }) {
|
|
4829
|
-
return /* @__PURE__ */ jsxs5("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
4830
|
-
/* @__PURE__ */ jsx10("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
|
|
4831
|
-
/* @__PURE__ */ jsx10("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" })
|
|
4832
|
-
] });
|
|
4833
|
-
}
|
|
4834
|
-
function IconInfo({ className, ...props }) {
|
|
4835
|
-
return /* @__PURE__ */ jsxs5("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
4836
|
-
/* @__PURE__ */ jsx10("circle", { cx: "12", cy: "12", r: "10" }),
|
|
4837
|
-
/* @__PURE__ */ jsx10("path", { d: "M12 16v-4" }),
|
|
4838
|
-
/* @__PURE__ */ jsx10("path", { d: "M12 8h.01" })
|
|
4839
|
-
] });
|
|
4840
|
-
}
|
|
4841
|
-
function IconArrowRight({ className, ...props }) {
|
|
4842
|
-
return /* @__PURE__ */ jsxs5("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
4843
|
-
/* @__PURE__ */ jsx10("path", { d: "M5 12h14" }),
|
|
4844
|
-
/* @__PURE__ */ jsx10("path", { d: "m12 5 7 7-7 7" })
|
|
4845
|
-
] });
|
|
4846
|
-
}
|
|
4847
|
-
function IconSection({ className, ...props }) {
|
|
4848
|
-
return /* @__PURE__ */ jsxs5("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
4849
|
-
/* @__PURE__ */ jsx10("rect", { width: "18", height: "7", x: "3", y: "3", rx: "1" }),
|
|
4850
|
-
/* @__PURE__ */ jsx10("rect", { width: "9", height: "7", x: "3", y: "14", rx: "1" }),
|
|
4851
|
-
/* @__PURE__ */ jsx10("rect", { width: "5", height: "7", x: "16", y: "14", rx: "1" })
|
|
4852
|
-
] });
|
|
4853
|
-
}
|
|
5081
|
+
// src/ui/link-modal/LinkPopover.tsx
|
|
5082
|
+
import { useEffect as useEffect6 } from "react";
|
|
4854
5083
|
|
|
4855
5084
|
// src/ui/dialog.tsx
|
|
4856
|
-
import
|
|
4857
|
-
|
|
4858
|
-
|
|
5085
|
+
import * as React7 from "react";
|
|
5086
|
+
import { Dialog as DialogPrimitive } from "radix-ui";
|
|
5087
|
+
import { X } from "lucide-react";
|
|
5088
|
+
import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
5089
|
+
function Dialog2({
|
|
5090
|
+
...props
|
|
5091
|
+
}) {
|
|
5092
|
+
return /* @__PURE__ */ jsx12(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
|
|
4859
5093
|
}
|
|
4860
|
-
function DialogPortal({
|
|
4861
|
-
|
|
5094
|
+
function DialogPortal({
|
|
5095
|
+
...props
|
|
5096
|
+
}) {
|
|
5097
|
+
return /* @__PURE__ */ jsx12(DialogPrimitive.Portal, { ...props });
|
|
4862
5098
|
}
|
|
4863
5099
|
function DialogOverlay({
|
|
4864
5100
|
className,
|
|
4865
5101
|
...props
|
|
4866
5102
|
}) {
|
|
4867
|
-
return /* @__PURE__ */
|
|
5103
|
+
return /* @__PURE__ */ jsx12(
|
|
4868
5104
|
DialogPrimitive.Overlay,
|
|
4869
5105
|
{
|
|
4870
5106
|
"data-slot": "dialog-overlay",
|
|
@@ -4874,57 +5110,74 @@ function DialogOverlay({
|
|
|
4874
5110
|
}
|
|
4875
5111
|
);
|
|
4876
5112
|
}
|
|
4877
|
-
var DialogContent =
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
/* @__PURE__ */
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
|
|
4896
|
-
children
|
|
4897
|
-
|
|
4898
|
-
|
|
4899
|
-
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
|
|
4910
|
-
});
|
|
5113
|
+
var DialogContent = React7.forwardRef(
|
|
5114
|
+
({ className, children, showCloseButton = true, container, ...props }, ref) => {
|
|
5115
|
+
const positionMode = container ? "absolute" : "fixed";
|
|
5116
|
+
return /* @__PURE__ */ jsxs6(DialogPortal, { container: container ?? void 0, children: [
|
|
5117
|
+
/* @__PURE__ */ jsx12(DialogOverlay, { className: cn(positionMode, "inset-0") }),
|
|
5118
|
+
/* @__PURE__ */ jsxs6(
|
|
5119
|
+
DialogPrimitive.Content,
|
|
5120
|
+
{
|
|
5121
|
+
ref,
|
|
5122
|
+
"data-slot": "dialog-content",
|
|
5123
|
+
className: cn(
|
|
5124
|
+
positionMode,
|
|
5125
|
+
"left-1/2 top-1/2 z-[2147483647] flex w-full max-w-[448px] -translate-x-1/2 -translate-y-1/2 flex-col overflow-visible",
|
|
5126
|
+
"rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
|
|
5127
|
+
container ? "max-h-[calc(100%-32px)]" : "max-h-[calc(100vh-32px)]",
|
|
5128
|
+
className
|
|
5129
|
+
),
|
|
5130
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
5131
|
+
...props,
|
|
5132
|
+
children: [
|
|
5133
|
+
children,
|
|
5134
|
+
showCloseButton ? /* @__PURE__ */ jsx12(
|
|
5135
|
+
DialogPrimitive.Close,
|
|
5136
|
+
{
|
|
5137
|
+
type: "button",
|
|
5138
|
+
className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
|
|
5139
|
+
"aria-label": "Close",
|
|
5140
|
+
children: /* @__PURE__ */ jsx12(X, { size: 16, "aria-hidden": true })
|
|
5141
|
+
}
|
|
5142
|
+
) : null
|
|
5143
|
+
]
|
|
5144
|
+
}
|
|
5145
|
+
)
|
|
5146
|
+
] });
|
|
5147
|
+
}
|
|
5148
|
+
);
|
|
4911
5149
|
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
|
4912
|
-
function DialogHeader({
|
|
4913
|
-
|
|
5150
|
+
function DialogHeader({
|
|
5151
|
+
className,
|
|
5152
|
+
...props
|
|
5153
|
+
}) {
|
|
5154
|
+
return /* @__PURE__ */ jsx12("div", { className: cn("flex flex-col gap-1.5", className), ...props });
|
|
4914
5155
|
}
|
|
4915
|
-
function DialogFooter({
|
|
4916
|
-
|
|
5156
|
+
function DialogFooter({
|
|
5157
|
+
className,
|
|
5158
|
+
...props
|
|
5159
|
+
}) {
|
|
5160
|
+
return /* @__PURE__ */ jsx12(
|
|
5161
|
+
"div",
|
|
5162
|
+
{
|
|
5163
|
+
className: cn("flex items-center justify-end gap-2", className),
|
|
5164
|
+
...props
|
|
5165
|
+
}
|
|
5166
|
+
);
|
|
4917
5167
|
}
|
|
4918
|
-
var DialogTitle =
|
|
5168
|
+
var DialogTitle = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx12(
|
|
4919
5169
|
DialogPrimitive.Title,
|
|
4920
5170
|
{
|
|
4921
5171
|
ref,
|
|
4922
|
-
className: cn(
|
|
5172
|
+
className: cn(
|
|
5173
|
+
"text-lg font-semibold leading-none tracking-tight text-card-foreground",
|
|
5174
|
+
className
|
|
5175
|
+
),
|
|
4923
5176
|
...props
|
|
4924
5177
|
}
|
|
4925
5178
|
));
|
|
4926
5179
|
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
|
4927
|
-
var DialogDescription =
|
|
5180
|
+
var DialogDescription = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx12(
|
|
4928
5181
|
DialogPrimitive.Description,
|
|
4929
5182
|
{
|
|
4930
5183
|
ref,
|
|
@@ -4935,59 +5188,40 @@ var DialogDescription = React5.forwardRef(({ className, ...props }, ref) => /* @
|
|
|
4935
5188
|
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
|
4936
5189
|
var DialogClose = DialogPrimitive.Close;
|
|
4937
5190
|
|
|
4938
|
-
// src/ui/
|
|
4939
|
-
import
|
|
4940
|
-
import { Slot } from "radix-ui";
|
|
4941
|
-
import { jsx as jsx12 } from "react/jsx-runtime";
|
|
4942
|
-
var buttonVariants = cva(
|
|
4943
|
-
"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",
|
|
4944
|
-
{
|
|
4945
|
-
variants: {
|
|
4946
|
-
variant: {
|
|
4947
|
-
default: "bg-primary text-primary-foreground hover:opacity-90",
|
|
4948
|
-
outline: "border border-border bg-background text-foreground shadow-sm hover:bg-muted/80",
|
|
4949
|
-
ghost: "min-w-0 px-3 py-2 text-foreground hover:bg-muted/50"
|
|
4950
|
-
},
|
|
4951
|
-
size: {
|
|
4952
|
-
default: "h-9",
|
|
4953
|
-
sm: "h-8 min-w-[64px] px-2 py-1.5 text-sm"
|
|
4954
|
-
}
|
|
4955
|
-
},
|
|
4956
|
-
defaultVariants: {
|
|
4957
|
-
variant: "default",
|
|
4958
|
-
size: "default"
|
|
4959
|
-
}
|
|
4960
|
-
}
|
|
4961
|
-
);
|
|
4962
|
-
var Button = React6.forwardRef(
|
|
4963
|
-
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
4964
|
-
const Comp = asChild ? Slot.Root : "button";
|
|
4965
|
-
return /* @__PURE__ */ jsx12(
|
|
4966
|
-
Comp,
|
|
4967
|
-
{
|
|
4968
|
-
ref,
|
|
4969
|
-
"data-slot": "button",
|
|
4970
|
-
className: cn(buttonVariants({ variant, size, className })),
|
|
4971
|
-
...props
|
|
4972
|
-
}
|
|
4973
|
-
);
|
|
4974
|
-
}
|
|
4975
|
-
);
|
|
4976
|
-
Button.displayName = "Button";
|
|
5191
|
+
// src/ui/link-modal/LinkEditorPanel.tsx
|
|
5192
|
+
import { Info, X as X3 } from "lucide-react";
|
|
4977
5193
|
|
|
4978
5194
|
// src/ui/link-modal/DestinationBreadcrumb.tsx
|
|
5195
|
+
import { ArrowRight, File, GalleryVertical } from "lucide-react";
|
|
4979
5196
|
import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
4980
|
-
function DestinationBreadcrumb({
|
|
5197
|
+
function DestinationBreadcrumb({
|
|
5198
|
+
pageTitle,
|
|
5199
|
+
sectionLabel
|
|
5200
|
+
}) {
|
|
4981
5201
|
return /* @__PURE__ */ jsxs7("div", { className: "flex w-full flex-col gap-2", children: [
|
|
4982
|
-
/* @__PURE__ */ jsx13("p", { className: "text-sm font-medium text-foreground", children: "Destination" }),
|
|
5202
|
+
/* @__PURE__ */ jsx13("p", { className: "text-sm font-medium! text-foreground m-0", children: "Destination" }),
|
|
4983
5203
|
/* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-3", children: [
|
|
4984
5204
|
/* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2", children: [
|
|
4985
|
-
/* @__PURE__ */ jsx13(
|
|
4986
|
-
/* @__PURE__ */ jsx13("span", { className: "text-sm font-medium leading-none text-foreground", children: pageTitle })
|
|
5205
|
+
/* @__PURE__ */ jsx13(File, { size: 16, className: "shrink-0 text-foreground", "aria-hidden": true }),
|
|
5206
|
+
/* @__PURE__ */ jsx13("span", { className: "text-sm font-medium leading-none text-foreground!", children: pageTitle })
|
|
4987
5207
|
] }),
|
|
4988
|
-
/* @__PURE__ */ jsx13(
|
|
5208
|
+
/* @__PURE__ */ jsx13(
|
|
5209
|
+
ArrowRight,
|
|
5210
|
+
{
|
|
5211
|
+
size: 16,
|
|
5212
|
+
className: "shrink-0 text-muted-foreground",
|
|
5213
|
+
"aria-hidden": true
|
|
5214
|
+
}
|
|
5215
|
+
),
|
|
4989
5216
|
/* @__PURE__ */ jsxs7("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
|
|
4990
|
-
/* @__PURE__ */ jsx13(
|
|
5217
|
+
/* @__PURE__ */ jsx13(
|
|
5218
|
+
GalleryVertical,
|
|
5219
|
+
{
|
|
5220
|
+
size: 16,
|
|
5221
|
+
className: "shrink-0 text-foreground",
|
|
5222
|
+
"aria-hidden": true
|
|
5223
|
+
}
|
|
5224
|
+
),
|
|
4991
5225
|
/* @__PURE__ */ jsx13("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
|
|
4992
5226
|
] })
|
|
4993
5227
|
] })
|
|
@@ -4995,8 +5229,13 @@ function DestinationBreadcrumb({ pageTitle, sectionLabel }) {
|
|
|
4995
5229
|
}
|
|
4996
5230
|
|
|
4997
5231
|
// src/ui/link-modal/SectionTreeItem.tsx
|
|
5232
|
+
import { GalleryVertical as GalleryVertical2 } from "lucide-react";
|
|
4998
5233
|
import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
4999
|
-
function SectionTreeItem({
|
|
5234
|
+
function SectionTreeItem({
|
|
5235
|
+
section,
|
|
5236
|
+
onSelect,
|
|
5237
|
+
selected
|
|
5238
|
+
}) {
|
|
5000
5239
|
const interactive = Boolean(onSelect);
|
|
5001
5240
|
return /* @__PURE__ */ jsxs8("div", { className: "flex h-9 w-full items-end pl-3", children: [
|
|
5002
5241
|
/* @__PURE__ */ jsx14(
|
|
@@ -5024,30 +5263,28 @@ function SectionTreeItem({ section, onSelect, selected }) {
|
|
|
5024
5263
|
interactive && selected && "border-primary"
|
|
5025
5264
|
),
|
|
5026
5265
|
children: [
|
|
5027
|
-
/* @__PURE__ */ jsx14(
|
|
5266
|
+
/* @__PURE__ */ jsx14(
|
|
5267
|
+
GalleryVertical2,
|
|
5268
|
+
{
|
|
5269
|
+
size: 16,
|
|
5270
|
+
className: "shrink-0 text-foreground",
|
|
5271
|
+
"aria-hidden": true
|
|
5272
|
+
}
|
|
5273
|
+
),
|
|
5028
5274
|
/* @__PURE__ */ jsx14("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
|
|
5029
5275
|
]
|
|
5030
5276
|
}
|
|
5031
5277
|
)
|
|
5032
5278
|
] });
|
|
5033
5279
|
}
|
|
5034
|
-
function SectionPickerList({ sections, onSelect }) {
|
|
5035
|
-
if (sections.length === 0) {
|
|
5036
|
-
return /* @__PURE__ */ jsx14("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." });
|
|
5037
|
-
}
|
|
5038
|
-
return /* @__PURE__ */ jsxs8("div", { className: "flex flex-col gap-1", children: [
|
|
5039
|
-
/* @__PURE__ */ jsx14("p", { className: "text-sm text-muted-foreground", children: "Pick a section this link should scroll to." }),
|
|
5040
|
-
sections.map((section) => /* @__PURE__ */ jsx14(SectionTreeItem, { section, onSelect }, section.id))
|
|
5041
|
-
] });
|
|
5042
|
-
}
|
|
5043
5280
|
|
|
5044
5281
|
// src/ui/link-modal/UrlOrPageInput.tsx
|
|
5045
|
-
import { useId as useId2, useRef as
|
|
5282
|
+
import { useEffect as useEffect3, useId as useId2, useRef as useRef3, useState as useState3 } from "react";
|
|
5046
5283
|
|
|
5047
5284
|
// src/ui/input.tsx
|
|
5048
|
-
import * as
|
|
5285
|
+
import * as React8 from "react";
|
|
5049
5286
|
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
5050
|
-
var Input =
|
|
5287
|
+
var Input = React8.forwardRef(
|
|
5051
5288
|
({ className, type, ...props }, ref) => {
|
|
5052
5289
|
return /* @__PURE__ */ jsx15(
|
|
5053
5290
|
"input",
|
|
@@ -5081,8 +5318,11 @@ function Label({ className, ...props }) {
|
|
|
5081
5318
|
}
|
|
5082
5319
|
|
|
5083
5320
|
// src/ui/link-modal/UrlOrPageInput.tsx
|
|
5321
|
+
import { ChevronDown, File as File2, X as X2 } from "lucide-react";
|
|
5084
5322
|
import { jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
5085
|
-
function FieldChevron({
|
|
5323
|
+
function FieldChevron({
|
|
5324
|
+
onClick
|
|
5325
|
+
}) {
|
|
5086
5326
|
return /* @__PURE__ */ jsx17(
|
|
5087
5327
|
"button",
|
|
5088
5328
|
{
|
|
@@ -5091,7 +5331,7 @@ function FieldChevron({ onClick }) {
|
|
|
5091
5331
|
onClick,
|
|
5092
5332
|
"aria-label": "Open page list",
|
|
5093
5333
|
tabIndex: -1,
|
|
5094
|
-
children: /* @__PURE__ */ jsx17(
|
|
5334
|
+
children: /* @__PURE__ */ jsx17(ChevronDown, { size: 16 })
|
|
5095
5335
|
}
|
|
5096
5336
|
);
|
|
5097
5337
|
}
|
|
@@ -5108,8 +5348,30 @@ function UrlOrPageInput({
|
|
|
5108
5348
|
urlError
|
|
5109
5349
|
}) {
|
|
5110
5350
|
const inputId = useId2();
|
|
5111
|
-
const inputRef =
|
|
5351
|
+
const inputRef = useRef3(null);
|
|
5352
|
+
const rootRef = useRef3(null);
|
|
5112
5353
|
const [isFocused, setIsFocused] = useState3(false);
|
|
5354
|
+
useEffect3(() => {
|
|
5355
|
+
if (!dropdownOpen) return;
|
|
5356
|
+
const isOutside = (e) => {
|
|
5357
|
+
const root = rootRef.current;
|
|
5358
|
+
if (!root) return true;
|
|
5359
|
+
const path = typeof e.composedPath === "function" ? e.composedPath() : [];
|
|
5360
|
+
if (path.includes(root)) return false;
|
|
5361
|
+
const target = e.target;
|
|
5362
|
+
return !(target instanceof Node && root.contains(target));
|
|
5363
|
+
};
|
|
5364
|
+
const closeIfOutside = (e) => {
|
|
5365
|
+
if (!isOutside(e)) return;
|
|
5366
|
+
onDropdownOpenChange(false);
|
|
5367
|
+
};
|
|
5368
|
+
document.addEventListener("pointerdown", closeIfOutside, true);
|
|
5369
|
+
document.addEventListener("mousedown", closeIfOutside, true);
|
|
5370
|
+
return () => {
|
|
5371
|
+
document.removeEventListener("pointerdown", closeIfOutside, true);
|
|
5372
|
+
document.removeEventListener("mousedown", closeIfOutside, true);
|
|
5373
|
+
};
|
|
5374
|
+
}, [dropdownOpen, onDropdownOpenChange]);
|
|
5113
5375
|
const openDropdown = () => {
|
|
5114
5376
|
if (readOnly || filteredPages.length === 0) return;
|
|
5115
5377
|
onDropdownOpenChange(true);
|
|
@@ -5127,14 +5389,21 @@ function UrlOrPageInput({
|
|
|
5127
5389
|
requestAnimationFrame(() => inputRef.current?.focus());
|
|
5128
5390
|
};
|
|
5129
5391
|
const fieldClassName = cn(
|
|
5130
|
-
"data-ohw-link-field flex h-
|
|
5392
|
+
"data-ohw-link-field flex h-[36px] w-full items-center overflow-hidden rounded-md border bg-background pl-3 pr-3 py-2 outline-none transition-[border-color,box-shadow]",
|
|
5131
5393
|
urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
|
|
5132
5394
|
);
|
|
5133
5395
|
return /* @__PURE__ */ jsxs9("div", { className: "flex w-full flex-col gap-2 p-0", children: [
|
|
5134
5396
|
/* @__PURE__ */ jsx17(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
|
|
5135
|
-
/* @__PURE__ */ jsxs9("div", { className: "relative w-full", children: [
|
|
5397
|
+
/* @__PURE__ */ jsxs9("div", { ref: rootRef, className: "relative w-full", children: [
|
|
5136
5398
|
/* @__PURE__ */ jsxs9("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
|
|
5137
|
-
selectedPage ? /* @__PURE__ */ jsx17("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ jsx17(
|
|
5399
|
+
selectedPage ? /* @__PURE__ */ jsx17("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ jsx17(
|
|
5400
|
+
File2,
|
|
5401
|
+
{
|
|
5402
|
+
size: 16,
|
|
5403
|
+
className: "shrink-0 text-foreground",
|
|
5404
|
+
"aria-hidden": true
|
|
5405
|
+
}
|
|
5406
|
+
) }) : null,
|
|
5138
5407
|
readOnly ? /* @__PURE__ */ jsx17("span", { className: "min-w-0 flex-1 truncate text-sm leading-5 text-foreground", children: selectedPage?.title ?? value }) : /* @__PURE__ */ jsx17(
|
|
5139
5408
|
Input,
|
|
5140
5409
|
{
|
|
@@ -5146,7 +5415,14 @@ function UrlOrPageInput({
|
|
|
5146
5415
|
setIsFocused(true);
|
|
5147
5416
|
if (!selectedPage) openDropdown();
|
|
5148
5417
|
},
|
|
5149
|
-
onBlur: () =>
|
|
5418
|
+
onBlur: () => {
|
|
5419
|
+
setIsFocused(false);
|
|
5420
|
+
requestAnimationFrame(() => {
|
|
5421
|
+
if (!rootRef.current?.contains(document.activeElement)) {
|
|
5422
|
+
onDropdownOpenChange(false);
|
|
5423
|
+
}
|
|
5424
|
+
});
|
|
5425
|
+
},
|
|
5150
5426
|
placeholder,
|
|
5151
5427
|
className: cn(
|
|
5152
5428
|
"min-w-0 flex-1 truncate border-0 bg-transparent p-0 text-sm font-normal leading-5 shadow-none outline-none ring-0 caret-foreground",
|
|
@@ -5162,7 +5438,7 @@ function UrlOrPageInput({
|
|
|
5162
5438
|
onMouseDown: clearSelection,
|
|
5163
5439
|
"aria-label": "Clear selected page",
|
|
5164
5440
|
tabIndex: -1,
|
|
5165
|
-
children: /* @__PURE__ */ jsx17(
|
|
5441
|
+
children: /* @__PURE__ */ jsx17(X2, { size: 16, "aria-hidden": true })
|
|
5166
5442
|
}
|
|
5167
5443
|
) : null,
|
|
5168
5444
|
!readOnly ? /* @__PURE__ */ jsx17(FieldChevron, { onClick: toggleDropdown }) : null
|
|
@@ -5171,7 +5447,7 @@ function UrlOrPageInput({
|
|
|
5171
5447
|
"div",
|
|
5172
5448
|
{
|
|
5173
5449
|
"data-ohw-link-page-dropdown": "",
|
|
5174
|
-
className: "absolute left-0 right-0
|
|
5450
|
+
className: "absolute left-0 right-0 top-[calc(100%+4px)] z-50 max-h-48 overflow-auto rounded-lg border border-border bg-popover py-1 shadow-lg",
|
|
5175
5451
|
onMouseDown: (e) => e.preventDefault(),
|
|
5176
5452
|
children: filteredPages.map((page) => /* @__PURE__ */ jsxs9(
|
|
5177
5453
|
"button",
|
|
@@ -5180,7 +5456,7 @@ function UrlOrPageInput({
|
|
|
5180
5456
|
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",
|
|
5181
5457
|
onClick: () => onPageSelect(page),
|
|
5182
5458
|
children: [
|
|
5183
|
-
/* @__PURE__ */ jsx17(
|
|
5459
|
+
/* @__PURE__ */ jsx17(File2, { size: 16, className: "shrink-0", "aria-hidden": true }),
|
|
5184
5460
|
/* @__PURE__ */ jsx17("span", { className: "truncate", children: page.title })
|
|
5185
5461
|
]
|
|
5186
5462
|
},
|
|
@@ -5193,41 +5469,447 @@ function UrlOrPageInput({
|
|
|
5193
5469
|
] });
|
|
5194
5470
|
}
|
|
5195
5471
|
|
|
5196
|
-
// src/ui/link-modal/
|
|
5197
|
-
import {
|
|
5198
|
-
function
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
|
|
5207
|
-
|
|
5208
|
-
})
|
|
5209
|
-
|
|
5210
|
-
|
|
5211
|
-
|
|
5212
|
-
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
|
|
5217
|
-
|
|
5218
|
-
|
|
5219
|
-
|
|
5220
|
-
|
|
5221
|
-
|
|
5222
|
-
|
|
5223
|
-
|
|
5224
|
-
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
|
|
5472
|
+
// src/ui/link-modal/LinkEditorPanel.tsx
|
|
5473
|
+
import { Fragment as Fragment3, jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
5474
|
+
function LinkEditorPanel({ state, onClose }) {
|
|
5475
|
+
const isCancel = state.secondaryLabel === "Cancel" || state.secondaryLabel === "Back to sections";
|
|
5476
|
+
return /* @__PURE__ */ jsxs10(Fragment3, { children: [
|
|
5477
|
+
/* @__PURE__ */ jsx18(DialogClose, { asChild: true, children: /* @__PURE__ */ jsx18(
|
|
5478
|
+
"button",
|
|
5479
|
+
{
|
|
5480
|
+
type: "button",
|
|
5481
|
+
className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50 h-7",
|
|
5482
|
+
"aria-label": "Close",
|
|
5483
|
+
onClick: onClose,
|
|
5484
|
+
children: /* @__PURE__ */ jsx18(X3, { size: 16, "aria-hidden": true })
|
|
5485
|
+
}
|
|
5486
|
+
) }),
|
|
5487
|
+
/* @__PURE__ */ jsx18(DialogHeader, { className: "w-full gap-1.5 p-6 pr-12", children: /* @__PURE__ */ jsx18(DialogTitle, { className: "m-0 w-full break-words", children: state.title }) }),
|
|
5488
|
+
/* @__PURE__ */ jsxs10("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
|
|
5489
|
+
state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ jsx18(
|
|
5490
|
+
DestinationBreadcrumb,
|
|
5491
|
+
{
|
|
5492
|
+
pageTitle: state.selectedPage.title,
|
|
5493
|
+
sectionLabel: state.selectedSection.label
|
|
5494
|
+
}
|
|
5495
|
+
) : /* @__PURE__ */ jsx18(
|
|
5496
|
+
UrlOrPageInput,
|
|
5497
|
+
{
|
|
5498
|
+
value: state.searchValue,
|
|
5499
|
+
selectedPage: state.selectedPage,
|
|
5500
|
+
dropdownOpen: state.dropdownOpen,
|
|
5501
|
+
onDropdownOpenChange: state.setDropdownOpen,
|
|
5502
|
+
filteredPages: state.filteredPages,
|
|
5503
|
+
onInputChange: state.handleInputChange,
|
|
5504
|
+
onPageSelect: state.handlePageSelect,
|
|
5505
|
+
urlError: state.urlError
|
|
5506
|
+
}
|
|
5507
|
+
),
|
|
5508
|
+
state.showChooseSection ? /* @__PURE__ */ jsxs10("div", { className: "flex flex-col justify-center gap-2", children: [
|
|
5509
|
+
/* @__PURE__ */ jsx18(
|
|
5510
|
+
Button,
|
|
5511
|
+
{
|
|
5512
|
+
type: "button",
|
|
5513
|
+
variant: "outline",
|
|
5514
|
+
className: "w-fit cursor-pointer",
|
|
5515
|
+
size: "sm",
|
|
5516
|
+
onClick: state.handleChooseSection,
|
|
5517
|
+
children: "Choose a section"
|
|
5518
|
+
}
|
|
5519
|
+
),
|
|
5520
|
+
/* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
|
|
5521
|
+
/* @__PURE__ */ jsx18(Info, { size: 16, className: "shrink-0", "aria-hidden": true }),
|
|
5522
|
+
/* @__PURE__ */ jsx18("span", { children: "Pick a section this link should scroll to." })
|
|
5523
|
+
] })
|
|
5524
|
+
] }) : null,
|
|
5525
|
+
state.showSectionRow && state.selectedSection ? /* @__PURE__ */ jsx18(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
|
|
5526
|
+
] }),
|
|
5527
|
+
/* @__PURE__ */ jsxs10(DialogFooter, { className: "w-full px-6 pb-6", children: [
|
|
5528
|
+
/* @__PURE__ */ jsx18(
|
|
5529
|
+
Button,
|
|
5530
|
+
{
|
|
5531
|
+
type: "button",
|
|
5532
|
+
variant: isCancel ? "outline" : "ghost",
|
|
5533
|
+
className: "leading-6 shadow-none cursor-pointer",
|
|
5534
|
+
style: isCancel ? {
|
|
5535
|
+
backgroundColor: "var(--ohw-background)",
|
|
5536
|
+
borderColor: "var(--ohw-border)",
|
|
5537
|
+
color: "var(--ohw-foreground)"
|
|
5538
|
+
} : void 0,
|
|
5539
|
+
onClick: state.handleSecondary,
|
|
5540
|
+
children: state.secondaryLabel
|
|
5541
|
+
}
|
|
5542
|
+
),
|
|
5543
|
+
/* @__PURE__ */ jsx18(
|
|
5544
|
+
Button,
|
|
5545
|
+
{
|
|
5546
|
+
type: "button",
|
|
5547
|
+
className: "border-0 leading-6 shadow-none hover:opacity-90 disabled:opacity-50 cursor-pointer",
|
|
5548
|
+
style: {
|
|
5549
|
+
backgroundColor: "var(--ohw-primary)",
|
|
5550
|
+
color: "var(--ohw-primary-foreground)"
|
|
5551
|
+
},
|
|
5552
|
+
disabled: !state.isValid,
|
|
5553
|
+
onClick: state.handleSubmit,
|
|
5554
|
+
children: state.submitLabel
|
|
5555
|
+
}
|
|
5556
|
+
)
|
|
5557
|
+
] })
|
|
5558
|
+
] });
|
|
5559
|
+
}
|
|
5560
|
+
|
|
5561
|
+
// src/ui/link-modal/SectionPickerOverlay.tsx
|
|
5562
|
+
import { useCallback as useCallback2, useEffect as useEffect4, useMemo as useMemo2, useRef as useRef4, useState as useState4 } from "react";
|
|
5563
|
+
import { createPortal } from "react-dom";
|
|
5564
|
+
import { ArrowLeft, Check } from "lucide-react";
|
|
5565
|
+
import { usePathname, useRouter } from "next/navigation";
|
|
5566
|
+
import { jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
5567
|
+
var DIM_OVERLAY = "rgba(0, 0, 0, 0.45)";
|
|
5568
|
+
function rectsEqual(a, b) {
|
|
5569
|
+
if (a.size !== b.size) return false;
|
|
5570
|
+
for (const [id, rect] of a) {
|
|
5571
|
+
const other = b.get(id);
|
|
5572
|
+
if (!other || rect.top !== other.top || rect.left !== other.left || rect.width !== other.width || rect.height !== other.height) {
|
|
5573
|
+
return false;
|
|
5574
|
+
}
|
|
5575
|
+
}
|
|
5576
|
+
return true;
|
|
5577
|
+
}
|
|
5578
|
+
function readSectionRects(sectionIds) {
|
|
5579
|
+
const next = /* @__PURE__ */ new Map();
|
|
5580
|
+
for (const id of sectionIds) {
|
|
5581
|
+
const el = document.querySelector(
|
|
5582
|
+
`[data-ohw-section="${CSS.escape(id)}"]`
|
|
5583
|
+
);
|
|
5584
|
+
if (el) next.set(id, el.getBoundingClientRect());
|
|
5585
|
+
}
|
|
5586
|
+
return next;
|
|
5587
|
+
}
|
|
5588
|
+
function hitTestSectionId(x, y, sectionIds, rects) {
|
|
5589
|
+
for (const id of sectionIds) {
|
|
5590
|
+
const rect = rects.get(id);
|
|
5591
|
+
if (!rect || rect.width <= 0 || rect.height <= 0) continue;
|
|
5592
|
+
if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) {
|
|
5593
|
+
return id;
|
|
5594
|
+
}
|
|
5595
|
+
}
|
|
5596
|
+
return null;
|
|
5597
|
+
}
|
|
5598
|
+
function useSectionRects(sectionIdsKey, enabled) {
|
|
5599
|
+
const [rects, setRects] = useState4(/* @__PURE__ */ new Map());
|
|
5600
|
+
const sectionIds = useMemo2(
|
|
5601
|
+
() => sectionIdsKey ? sectionIdsKey.split("\0") : [],
|
|
5602
|
+
[sectionIdsKey]
|
|
5603
|
+
);
|
|
5604
|
+
useEffect4(() => {
|
|
5605
|
+
if (!enabled || sectionIds.length === 0) {
|
|
5606
|
+
setRects((prev) => prev.size === 0 ? prev : /* @__PURE__ */ new Map());
|
|
5607
|
+
return;
|
|
5608
|
+
}
|
|
5609
|
+
const update = () => {
|
|
5610
|
+
const next = readSectionRects(sectionIds);
|
|
5611
|
+
setRects((prev) => rectsEqual(prev, next) ? prev : next);
|
|
5612
|
+
};
|
|
5613
|
+
update();
|
|
5614
|
+
const opts = { capture: true, passive: true };
|
|
5615
|
+
window.addEventListener("scroll", update, opts);
|
|
5616
|
+
window.addEventListener("resize", update);
|
|
5617
|
+
const vv = window.visualViewport;
|
|
5618
|
+
vv?.addEventListener("resize", update);
|
|
5619
|
+
vv?.addEventListener("scroll", update);
|
|
5620
|
+
const ro = new ResizeObserver(update);
|
|
5621
|
+
for (const id of sectionIds) {
|
|
5622
|
+
const el = document.querySelector(
|
|
5623
|
+
`[data-ohw-section="${CSS.escape(id)}"]`
|
|
5624
|
+
);
|
|
5625
|
+
if (el) ro.observe(el);
|
|
5626
|
+
}
|
|
5627
|
+
return () => {
|
|
5628
|
+
window.removeEventListener("scroll", update, opts);
|
|
5629
|
+
window.removeEventListener("resize", update);
|
|
5630
|
+
vv?.removeEventListener("resize", update);
|
|
5631
|
+
vv?.removeEventListener("scroll", update);
|
|
5632
|
+
ro.disconnect();
|
|
5633
|
+
};
|
|
5634
|
+
}, [sectionIds, enabled]);
|
|
5635
|
+
return rects;
|
|
5636
|
+
}
|
|
5637
|
+
function SectionPickerOverlay({
|
|
5638
|
+
pagePath,
|
|
5639
|
+
sections,
|
|
5640
|
+
onBack,
|
|
5641
|
+
onSelect
|
|
5642
|
+
}) {
|
|
5643
|
+
const router = useRouter();
|
|
5644
|
+
const pathname = usePathname();
|
|
5645
|
+
const [selectedId, setSelectedId] = useState4(null);
|
|
5646
|
+
const [hoveredId, setHoveredId] = useState4(null);
|
|
5647
|
+
const pointerRef = useRef4(null);
|
|
5648
|
+
const pointerScreenRef = useRef4(null);
|
|
5649
|
+
const iframeOffsetTopRef = useRef4(null);
|
|
5650
|
+
const sectionIdsRef = useRef4([]);
|
|
5651
|
+
const [chromeClip, setChromeClip] = useState4(
|
|
5652
|
+
() => ({
|
|
5653
|
+
top: 0,
|
|
5654
|
+
bottom: typeof window !== "undefined" ? window.innerHeight : 0
|
|
5655
|
+
})
|
|
5656
|
+
);
|
|
5657
|
+
const normalizedTarget = normalizePath(pagePath);
|
|
5658
|
+
const isOnTargetPage = normalizePath(pathname) === normalizedTarget;
|
|
5659
|
+
useEffect4(() => {
|
|
5660
|
+
if (isOnTargetPage) return;
|
|
5661
|
+
const search = readPreservedSearch();
|
|
5662
|
+
router.push(`${normalizedTarget}${search}`);
|
|
5663
|
+
}, [isOnTargetPage, normalizedTarget, router]);
|
|
5664
|
+
useEffect4(() => {
|
|
5665
|
+
document.documentElement.setAttribute("data-ohw-section-picking", "");
|
|
5666
|
+
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => {
|
|
5667
|
+
el.removeAttribute("data-ohw-hovered");
|
|
5668
|
+
});
|
|
5669
|
+
return () => {
|
|
5670
|
+
document.documentElement.removeAttribute("data-ohw-section-picking");
|
|
5671
|
+
};
|
|
5672
|
+
}, []);
|
|
5673
|
+
const liveSections = useMemo2(() => {
|
|
5674
|
+
if (!isOnTargetPage) return sections;
|
|
5675
|
+
const live = collectSectionsFromDom();
|
|
5676
|
+
if (live.length === 0) return sections;
|
|
5677
|
+
const labels = new Map(sections.map((s) => [s.id, s.label]));
|
|
5678
|
+
return live.map((s) => ({ id: s.id, label: labels.get(s.id) ?? s.label }));
|
|
5679
|
+
}, [isOnTargetPage, sections, pathname]);
|
|
5680
|
+
const sectionIdsKey = useMemo2(
|
|
5681
|
+
() => liveSections.map((s) => s.id).join("\0"),
|
|
5682
|
+
[liveSections]
|
|
5683
|
+
);
|
|
5684
|
+
const sectionIds = useMemo2(
|
|
5685
|
+
() => liveSections.map((s) => s.id),
|
|
5686
|
+
[liveSections]
|
|
5687
|
+
);
|
|
5688
|
+
sectionIdsRef.current = sectionIds;
|
|
5689
|
+
const rects = useSectionRects(sectionIdsKey, isOnTargetPage);
|
|
5690
|
+
const applyHoverAt = useCallback2((x, y, liveRects) => {
|
|
5691
|
+
const ids = sectionIdsRef.current;
|
|
5692
|
+
const map = liveRects ?? readSectionRects(ids);
|
|
5693
|
+
const next = hitTestSectionId(x, y, ids, map);
|
|
5694
|
+
setHoveredId((prev) => prev === next ? prev : next);
|
|
5695
|
+
}, []);
|
|
5696
|
+
useEffect4(() => {
|
|
5697
|
+
const applyClip = (iframeOffsetTop, visibleCanvasTop, canvasH) => {
|
|
5698
|
+
const top = Math.max(0, visibleCanvasTop - iframeOffsetTop);
|
|
5699
|
+
const bottom = Math.min(
|
|
5700
|
+
window.innerHeight,
|
|
5701
|
+
visibleCanvasTop + canvasH - iframeOffsetTop
|
|
5702
|
+
);
|
|
5703
|
+
setChromeClip(
|
|
5704
|
+
(prev) => prev.top === top && prev.bottom === bottom ? prev : { top, bottom: Math.max(top, bottom) }
|
|
5705
|
+
);
|
|
5706
|
+
};
|
|
5707
|
+
const onParentScroll = (e) => {
|
|
5708
|
+
if (e.data?.type !== "ow:parent-scroll") return;
|
|
5709
|
+
const { iframeOffsetTop, headerH, canvasH } = e.data;
|
|
5710
|
+
applyClip(iframeOffsetTop, headerH, canvasH);
|
|
5711
|
+
iframeOffsetTopRef.current = iframeOffsetTop;
|
|
5712
|
+
if (!pointerScreenRef.current && pointerRef.current) {
|
|
5713
|
+
pointerScreenRef.current = {
|
|
5714
|
+
x: pointerRef.current.x,
|
|
5715
|
+
y: pointerRef.current.y + iframeOffsetTop
|
|
5716
|
+
};
|
|
5717
|
+
}
|
|
5718
|
+
const screen = pointerScreenRef.current;
|
|
5719
|
+
if (screen) {
|
|
5720
|
+
const next = { x: screen.x, y: screen.y - iframeOffsetTop };
|
|
5721
|
+
pointerRef.current = next;
|
|
5722
|
+
applyHoverAt(next.x, next.y);
|
|
5723
|
+
}
|
|
5724
|
+
};
|
|
5725
|
+
const onResize = () => {
|
|
5726
|
+
setChromeClip((prev) => {
|
|
5727
|
+
const bottom = Math.max(prev.top, window.innerHeight);
|
|
5728
|
+
return prev.bottom === bottom ? prev : { ...prev, bottom };
|
|
5729
|
+
});
|
|
5730
|
+
};
|
|
5731
|
+
window.addEventListener("message", onParentScroll);
|
|
5732
|
+
window.addEventListener("resize", onResize);
|
|
5733
|
+
return () => {
|
|
5734
|
+
window.removeEventListener("message", onParentScroll);
|
|
5735
|
+
window.removeEventListener("resize", onResize);
|
|
5736
|
+
};
|
|
5737
|
+
}, [applyHoverAt]);
|
|
5738
|
+
useEffect4(() => {
|
|
5739
|
+
const ptr = pointerRef.current;
|
|
5740
|
+
if (!ptr) return;
|
|
5741
|
+
applyHoverAt(ptr.x, ptr.y, rects);
|
|
5742
|
+
}, [rects, applyHoverAt]);
|
|
5743
|
+
useEffect4(() => {
|
|
5744
|
+
const rememberPointer = (clientX, clientY) => {
|
|
5745
|
+
pointerRef.current = { x: clientX, y: clientY };
|
|
5746
|
+
const top = iframeOffsetTopRef.current;
|
|
5747
|
+
if (top != null) {
|
|
5748
|
+
pointerScreenRef.current = { x: clientX, y: clientY + top };
|
|
5749
|
+
}
|
|
5750
|
+
applyHoverAt(clientX, clientY, rects);
|
|
5751
|
+
};
|
|
5752
|
+
const onPointerMove = (e) => {
|
|
5753
|
+
rememberPointer(e.clientX, e.clientY);
|
|
5754
|
+
};
|
|
5755
|
+
const onPointerSync = (e) => {
|
|
5756
|
+
if (e.data?.type !== "ow:pointer-sync") return;
|
|
5757
|
+
const { clientX, clientY } = e.data;
|
|
5758
|
+
rememberPointer(clientX, clientY);
|
|
5759
|
+
};
|
|
5760
|
+
window.addEventListener("pointermove", onPointerMove, { passive: true });
|
|
5761
|
+
window.addEventListener("message", onPointerSync);
|
|
5762
|
+
return () => {
|
|
5763
|
+
window.removeEventListener("pointermove", onPointerMove);
|
|
5764
|
+
window.removeEventListener("message", onPointerSync);
|
|
5765
|
+
};
|
|
5766
|
+
}, [rects, applyHoverAt]);
|
|
5767
|
+
const handleSelect = useCallback2(
|
|
5768
|
+
(section) => {
|
|
5769
|
+
if (selectedId) return;
|
|
5770
|
+
setSelectedId(section.id);
|
|
5771
|
+
onSelect(section);
|
|
5772
|
+
},
|
|
5773
|
+
[selectedId, onSelect]
|
|
5774
|
+
);
|
|
5775
|
+
useEffect4(() => {
|
|
5776
|
+
const onKeyDown = (e) => {
|
|
5777
|
+
if (e.key === "Escape") {
|
|
5778
|
+
e.preventDefault();
|
|
5779
|
+
e.stopPropagation();
|
|
5780
|
+
onBack();
|
|
5781
|
+
}
|
|
5782
|
+
};
|
|
5783
|
+
window.addEventListener("keydown", onKeyDown, true);
|
|
5784
|
+
return () => window.removeEventListener("keydown", onKeyDown, true);
|
|
5785
|
+
}, [onBack]);
|
|
5786
|
+
const portalRoot = typeof document !== "undefined" ? document.querySelector("[data-ohw-bridge-root]") ?? document.body : null;
|
|
5787
|
+
if (!portalRoot) return null;
|
|
5788
|
+
return createPortal(
|
|
5789
|
+
/* @__PURE__ */ jsxs11(
|
|
5790
|
+
"div",
|
|
5791
|
+
{
|
|
5792
|
+
"data-ohw-section-picker": "",
|
|
5793
|
+
"data-ohw-bridge": "",
|
|
5794
|
+
className: `pointer-events-none fixed inset-0 z-[2147483647] transition-opacity duration-200 ${"opacity-100"}`,
|
|
5795
|
+
"aria-modal": true,
|
|
5796
|
+
role: "dialog",
|
|
5797
|
+
"aria-label": "Choose a section",
|
|
5798
|
+
children: [
|
|
5799
|
+
/* @__PURE__ */ jsx19(
|
|
5800
|
+
"div",
|
|
5801
|
+
{
|
|
5802
|
+
className: "pointer-events-auto fixed left-5 z-[2]",
|
|
5803
|
+
style: { top: chromeClip.top + 20 },
|
|
5804
|
+
children: /* @__PURE__ */ jsxs11(
|
|
5805
|
+
Button,
|
|
5806
|
+
{
|
|
5807
|
+
type: "button",
|
|
5808
|
+
variant: "outline",
|
|
5809
|
+
size: "sm",
|
|
5810
|
+
className: "h-8 min-w-0 gap-1 border-border bg-background px-2 py-1.5 shadow-sm hover:bg-muted cursor-pointer",
|
|
5811
|
+
onClick: onBack,
|
|
5812
|
+
children: [
|
|
5813
|
+
/* @__PURE__ */ jsx19(ArrowLeft, { className: "size-4 shrink-0", "aria-hidden": true }),
|
|
5814
|
+
"Back"
|
|
5815
|
+
]
|
|
5816
|
+
}
|
|
5817
|
+
)
|
|
5818
|
+
}
|
|
5819
|
+
),
|
|
5820
|
+
/* @__PURE__ */ jsx19(
|
|
5821
|
+
"div",
|
|
5822
|
+
{
|
|
5823
|
+
className: "pointer-events-none fixed left-1/2 z-[2] rounded-lg px-4 py-3 text-xs leading-4 tracking-[0.18px] text-white shadow-md",
|
|
5824
|
+
style: {
|
|
5825
|
+
top: chromeClip.bottom - 20,
|
|
5826
|
+
transform: "translate(-50%, -100%)",
|
|
5827
|
+
backgroundColor: "var(--ohw-popover-foreground, #0c0a09)"
|
|
5828
|
+
},
|
|
5829
|
+
"data-ohw-section-picker-hint": "",
|
|
5830
|
+
children: "Click on section to select"
|
|
5831
|
+
}
|
|
5832
|
+
),
|
|
5833
|
+
!isOnTargetPage ? /* @__PURE__ */ jsx19(
|
|
5834
|
+
"div",
|
|
5835
|
+
{
|
|
5836
|
+
className: "pointer-events-none fixed left-1/2 z-[1] -translate-x-1/2 rounded-md bg-background/90 px-3 py-2 text-sm text-muted-foreground shadow-sm",
|
|
5837
|
+
style: { top: chromeClip.top + 64 },
|
|
5838
|
+
children: "Loading page preview\u2026"
|
|
5839
|
+
}
|
|
5840
|
+
) : null,
|
|
5841
|
+
isOnTargetPage && liveSections.length === 0 ? /* @__PURE__ */ jsx19("div", { className: "pointer-events-auto fixed inset-0 z-[1] flex items-center justify-center bg-muted/40", children: /* @__PURE__ */ jsx19("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." }) }) : null,
|
|
5842
|
+
isOnTargetPage ? liveSections.map((section) => {
|
|
5843
|
+
const rect = rects.get(section.id);
|
|
5844
|
+
if (!rect || rect.width <= 0 || rect.height <= 0) return null;
|
|
5845
|
+
const isSelected = selectedId === section.id;
|
|
5846
|
+
const isLit = isSelected || hoveredId === section.id;
|
|
5847
|
+
return /* @__PURE__ */ jsx19(
|
|
5848
|
+
"button",
|
|
5849
|
+
{
|
|
5850
|
+
type: "button",
|
|
5851
|
+
className: "pointer-events-auto fixed z-[1] cursor-pointer border-0 bg-transparent p-0 transition-[background-color] duration-150",
|
|
5852
|
+
style: {
|
|
5853
|
+
top: rect.top,
|
|
5854
|
+
left: rect.left,
|
|
5855
|
+
width: rect.width,
|
|
5856
|
+
height: rect.height,
|
|
5857
|
+
backgroundColor: isLit ? "transparent" : DIM_OVERLAY
|
|
5858
|
+
},
|
|
5859
|
+
"aria-label": `Select section ${section.label}`,
|
|
5860
|
+
onClick: () => handleSelect(section),
|
|
5861
|
+
children: isSelected ? /* @__PURE__ */ jsx19(
|
|
5862
|
+
"span",
|
|
5863
|
+
{
|
|
5864
|
+
className: "absolute right-3 top-3 flex size-8 items-center justify-center rounded-full text-white",
|
|
5865
|
+
style: { backgroundColor: "var(--ohw-primary, #0885fe)" },
|
|
5866
|
+
"aria-hidden": true,
|
|
5867
|
+
children: /* @__PURE__ */ jsx19(Check, { className: "size-5" })
|
|
5868
|
+
}
|
|
5869
|
+
) : null
|
|
5870
|
+
},
|
|
5871
|
+
section.id
|
|
5872
|
+
);
|
|
5873
|
+
}) : null
|
|
5874
|
+
]
|
|
5875
|
+
}
|
|
5876
|
+
),
|
|
5877
|
+
portalRoot
|
|
5878
|
+
);
|
|
5879
|
+
}
|
|
5880
|
+
|
|
5881
|
+
// src/ui/link-modal/useLinkModalState.ts
|
|
5882
|
+
import { useCallback as useCallback3, useEffect as useEffect5, useMemo as useMemo3, useState as useState5 } from "react";
|
|
5883
|
+
function useLinkModalState({
|
|
5884
|
+
open,
|
|
5885
|
+
mode,
|
|
5886
|
+
pages,
|
|
5887
|
+
sections: _sections,
|
|
5888
|
+
sectionsByPath,
|
|
5889
|
+
initialTarget,
|
|
5890
|
+
existingTargets: _existingTargets,
|
|
5891
|
+
onClose,
|
|
5892
|
+
onSubmit
|
|
5893
|
+
}) {
|
|
5894
|
+
const availablePages = useMemo3(() => pages, [pages]);
|
|
5895
|
+
const [searchValue, setSearchValue] = useState5("");
|
|
5896
|
+
const [selectedPage, setSelectedPage] = useState5(null);
|
|
5897
|
+
const [selectedSection, setSelectedSection] = useState5(null);
|
|
5898
|
+
const [step, setStep] = useState5("input");
|
|
5899
|
+
const [dropdownOpen, setDropdownOpen] = useState5(false);
|
|
5900
|
+
const [urlError, setUrlError] = useState5("");
|
|
5901
|
+
const reset = useCallback3(() => {
|
|
5902
|
+
setSearchValue("");
|
|
5903
|
+
setSelectedPage(null);
|
|
5904
|
+
setSelectedSection(null);
|
|
5905
|
+
setStep("input");
|
|
5906
|
+
setDropdownOpen(false);
|
|
5907
|
+
setUrlError("");
|
|
5908
|
+
}, []);
|
|
5909
|
+
useEffect5(() => {
|
|
5910
|
+
if (!open) return;
|
|
5911
|
+
if (mode === "edit" && initialTarget) {
|
|
5912
|
+
const { pageRoute } = parseTarget(initialTarget);
|
|
5231
5913
|
const targetSections = getSectionsForPath(sectionsByPath, pageRoute);
|
|
5232
5914
|
const init = getEditModeInitialState(initialTarget, pages, targetSections);
|
|
5233
5915
|
setSearchValue(init.searchValue);
|
|
@@ -5239,12 +5921,12 @@ function useLinkModalState({
|
|
|
5239
5921
|
}
|
|
5240
5922
|
setDropdownOpen(false);
|
|
5241
5923
|
setUrlError("");
|
|
5242
|
-
}, [open, mode, initialTarget,
|
|
5243
|
-
const filteredPages =
|
|
5924
|
+
}, [open, mode, initialTarget, reset]);
|
|
5925
|
+
const filteredPages = useMemo3(() => {
|
|
5244
5926
|
if (!searchValue.trim()) return availablePages;
|
|
5245
5927
|
return availablePages.filter((p) => p.title.toLowerCase().startsWith(searchValue.toLowerCase()));
|
|
5246
5928
|
}, [availablePages, searchValue]);
|
|
5247
|
-
const activeSections =
|
|
5929
|
+
const activeSections = useMemo3(() => {
|
|
5248
5930
|
if (!selectedPage) return [];
|
|
5249
5931
|
return getSectionsForPath(sectionsByPath, selectedPage.path);
|
|
5250
5932
|
}, [selectedPage, sectionsByPath]);
|
|
@@ -5286,11 +5968,14 @@ function useLinkModalState({
|
|
|
5286
5968
|
const handleBackToSections = () => {
|
|
5287
5969
|
setStep("sectionPicker");
|
|
5288
5970
|
};
|
|
5971
|
+
const handleSectionPickerBack = () => {
|
|
5972
|
+
setStep("input");
|
|
5973
|
+
};
|
|
5289
5974
|
const handleClose = () => {
|
|
5290
5975
|
reset();
|
|
5291
5976
|
onClose();
|
|
5292
5977
|
};
|
|
5293
|
-
const isValid =
|
|
5978
|
+
const isValid = useMemo3(() => {
|
|
5294
5979
|
if (urlError) return false;
|
|
5295
5980
|
if (showBreadcrumb) return true;
|
|
5296
5981
|
if (selectedPage) return true;
|
|
@@ -5323,7 +6008,7 @@ function useLinkModalState({
|
|
|
5323
6008
|
onSubmit(normalizeUrl(searchValue));
|
|
5324
6009
|
handleClose();
|
|
5325
6010
|
};
|
|
5326
|
-
const submitLabel = mode === "edit" ? "Save" : "Create";
|
|
6011
|
+
const submitLabel = showBreadcrumb ? "Save" : mode === "edit" ? "Save" : "Create";
|
|
5327
6012
|
const title = mode === "edit" ? "Edit navigation item" : "Create navigation item";
|
|
5328
6013
|
const secondaryLabel = showBreadcrumb ? "Back to sections" : "Cancel";
|
|
5329
6014
|
const handleSecondary = showBreadcrumb ? handleBackToSections : handleClose;
|
|
@@ -5350,23 +6035,29 @@ function useLinkModalState({
|
|
|
5350
6035
|
handleChooseSection,
|
|
5351
6036
|
handleSectionSelect,
|
|
5352
6037
|
handleBackToSections,
|
|
6038
|
+
handleSectionPickerBack,
|
|
5353
6039
|
handleClose,
|
|
5354
6040
|
handleSecondary,
|
|
5355
6041
|
handleSubmit
|
|
5356
6042
|
};
|
|
5357
6043
|
}
|
|
5358
6044
|
|
|
5359
|
-
// src/ui/link-modal/
|
|
5360
|
-
import { Fragment as
|
|
5361
|
-
function
|
|
6045
|
+
// src/ui/link-modal/LinkPopover.tsx
|
|
6046
|
+
import { Fragment as Fragment4, jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
6047
|
+
function postToParent(data) {
|
|
6048
|
+
window.parent?.postMessage(data, "*");
|
|
6049
|
+
}
|
|
6050
|
+
function LinkPopover({
|
|
5362
6051
|
open = true,
|
|
6052
|
+
panelRef,
|
|
6053
|
+
portalContainer,
|
|
6054
|
+
onClose,
|
|
5363
6055
|
mode = "create",
|
|
5364
6056
|
pages,
|
|
5365
6057
|
sections = [],
|
|
5366
6058
|
sectionsByPath,
|
|
5367
6059
|
initialTarget,
|
|
5368
6060
|
existingTargets = [],
|
|
5369
|
-
onClose,
|
|
5370
6061
|
onSubmit
|
|
5371
6062
|
}) {
|
|
5372
6063
|
const state = useLinkModalState({
|
|
@@ -5380,115 +6071,109 @@ function LinkEditorPanel({
|
|
|
5380
6071
|
onClose,
|
|
5381
6072
|
onSubmit
|
|
5382
6073
|
});
|
|
5383
|
-
const
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
6074
|
+
const sectionPickerActive = state.showSectionPicker && Boolean(state.selectedPage);
|
|
6075
|
+
useEffect6(() => {
|
|
6076
|
+
if (!open) return;
|
|
6077
|
+
if (sectionPickerActive) {
|
|
6078
|
+
postToParent({ type: "ow:link-modal-lock", locked: false });
|
|
6079
|
+
postToParent({ type: "ow:section-picker", active: true });
|
|
6080
|
+
document.documentElement.style.overflow = "";
|
|
6081
|
+
document.body.style.overflow = "";
|
|
6082
|
+
return () => {
|
|
6083
|
+
postToParent({ type: "ow:section-picker", active: false });
|
|
6084
|
+
};
|
|
6085
|
+
}
|
|
6086
|
+
postToParent({ type: "ow:section-picker", active: false });
|
|
6087
|
+
postToParent({ type: "ow:link-modal-lock", locked: true });
|
|
6088
|
+
const html = document.documentElement;
|
|
6089
|
+
const body = document.body;
|
|
6090
|
+
const prevHtmlOverflow = html.style.overflow;
|
|
6091
|
+
const prevBodyOverflow = body.style.overflow;
|
|
6092
|
+
const prevHtmlOverscroll = html.style.overscrollBehavior;
|
|
6093
|
+
const prevBodyOverscroll = body.style.overscrollBehavior;
|
|
6094
|
+
html.style.overflow = "hidden";
|
|
6095
|
+
body.style.overflow = "hidden";
|
|
6096
|
+
html.style.overscrollBehavior = "none";
|
|
6097
|
+
body.style.overscrollBehavior = "none";
|
|
6098
|
+
const canScrollElement = (el, deltaY) => {
|
|
6099
|
+
const { overflowY } = getComputedStyle(el);
|
|
6100
|
+
if (overflowY !== "auto" && overflowY !== "scroll") return false;
|
|
6101
|
+
if (el.scrollHeight <= el.clientHeight + 1) return false;
|
|
6102
|
+
if (deltaY < 0) return el.scrollTop > 0;
|
|
6103
|
+
if (deltaY > 0)
|
|
6104
|
+
return el.scrollTop + el.clientHeight < el.scrollHeight - 1;
|
|
6105
|
+
return true;
|
|
6106
|
+
};
|
|
6107
|
+
const allowsInternalScroll = (e) => {
|
|
6108
|
+
const target = e.target;
|
|
6109
|
+
if (!(target instanceof Element)) return false;
|
|
6110
|
+
const scrollRoot = target.closest(
|
|
6111
|
+
"[data-ohw-link-page-dropdown], [data-ohw-allow-scroll]"
|
|
6112
|
+
);
|
|
6113
|
+
if (!scrollRoot) return false;
|
|
6114
|
+
const deltaY = e instanceof WheelEvent ? e.deltaY : 0;
|
|
6115
|
+
return canScrollElement(scrollRoot, deltaY);
|
|
6116
|
+
};
|
|
6117
|
+
const preventBackgroundScroll = (e) => {
|
|
6118
|
+
if (allowsInternalScroll(e)) return;
|
|
6119
|
+
e.preventDefault();
|
|
6120
|
+
};
|
|
6121
|
+
const scrollOpts = { passive: false, capture: true };
|
|
6122
|
+
document.addEventListener("wheel", preventBackgroundScroll, scrollOpts);
|
|
6123
|
+
document.addEventListener("touchmove", preventBackgroundScroll, scrollOpts);
|
|
6124
|
+
return () => {
|
|
6125
|
+
postToParent({ type: "ow:link-modal-lock", locked: false });
|
|
6126
|
+
html.style.overflow = prevHtmlOverflow;
|
|
6127
|
+
body.style.overflow = prevBodyOverflow;
|
|
6128
|
+
html.style.overscrollBehavior = prevHtmlOverscroll;
|
|
6129
|
+
body.style.overscrollBehavior = prevBodyOverscroll;
|
|
6130
|
+
document.removeEventListener(
|
|
6131
|
+
"wheel",
|
|
6132
|
+
preventBackgroundScroll,
|
|
6133
|
+
scrollOpts
|
|
6134
|
+
);
|
|
6135
|
+
document.removeEventListener(
|
|
6136
|
+
"touchmove",
|
|
6137
|
+
preventBackgroundScroll,
|
|
6138
|
+
scrollOpts
|
|
6139
|
+
);
|
|
6140
|
+
};
|
|
6141
|
+
}, [open, sectionPickerActive]);
|
|
6142
|
+
return /* @__PURE__ */ jsxs12(Fragment4, { children: [
|
|
6143
|
+
/* @__PURE__ */ jsx20(
|
|
6144
|
+
Dialog2,
|
|
5387
6145
|
{
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
6146
|
+
open: open && !sectionPickerActive,
|
|
6147
|
+
onOpenChange: (next) => {
|
|
6148
|
+
if (!next) onClose?.();
|
|
6149
|
+
},
|
|
6150
|
+
children: /* @__PURE__ */ jsx20(
|
|
6151
|
+
DialogContent,
|
|
6152
|
+
{
|
|
6153
|
+
ref: panelRef,
|
|
6154
|
+
container: portalContainer,
|
|
6155
|
+
"data-ohw-link-popover-root": "",
|
|
6156
|
+
"data-ohw-link-modal-root": "",
|
|
6157
|
+
"data-ohw-bridge": "",
|
|
6158
|
+
showCloseButton: false,
|
|
6159
|
+
className: "gap-0 p-0 w-full max-w-[448px] pointer-events-auto z-[2147483646] overflow-visible",
|
|
6160
|
+
children: /* @__PURE__ */ jsx20(LinkEditorPanel, { state, onClose })
|
|
6161
|
+
}
|
|
6162
|
+
)
|
|
5392
6163
|
}
|
|
5393
|
-
)
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
UrlOrPageInput,
|
|
5404
|
-
{
|
|
5405
|
-
value: state.searchValue,
|
|
5406
|
-
selectedPage: state.selectedPage,
|
|
5407
|
-
dropdownOpen: state.dropdownOpen,
|
|
5408
|
-
onDropdownOpenChange: state.setDropdownOpen,
|
|
5409
|
-
filteredPages: state.filteredPages,
|
|
5410
|
-
onInputChange: state.handleInputChange,
|
|
5411
|
-
onPageSelect: state.handlePageSelect,
|
|
5412
|
-
urlError: state.urlError
|
|
5413
|
-
}
|
|
5414
|
-
),
|
|
5415
|
-
state.showChooseSection ? /* @__PURE__ */ jsxs10("div", { className: "flex flex-col justify-center gap-2", children: [
|
|
5416
|
-
/* @__PURE__ */ jsx18(Button, { type: "button", variant: "outline", className: "w-fit cursor-pointer", size: "sm", onClick: state.handleChooseSection, children: "Choose a section" }),
|
|
5417
|
-
/* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
|
|
5418
|
-
/* @__PURE__ */ jsx18(IconInfo, { className: "shrink-0", "aria-hidden": true }),
|
|
5419
|
-
/* @__PURE__ */ jsx18("span", { children: "Pick a section this link should scroll to." })
|
|
5420
|
-
] })
|
|
5421
|
-
] }) : null,
|
|
5422
|
-
state.showSectionPicker ? /* @__PURE__ */ jsx18(SectionPickerList, { sections: state.activeSections, onSelect: state.handleSectionSelect }) : null,
|
|
5423
|
-
state.showSectionRow && state.selectedSection ? /* @__PURE__ */ jsx18(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
|
|
5424
|
-
] }),
|
|
5425
|
-
/* @__PURE__ */ jsxs10(DialogFooter, { className: "w-full px-6 pb-6", children: [
|
|
5426
|
-
/* @__PURE__ */ jsx18(
|
|
5427
|
-
Button,
|
|
5428
|
-
{
|
|
5429
|
-
type: "button",
|
|
5430
|
-
variant: isCancel ? "outline" : "ghost",
|
|
5431
|
-
className: "leading-6 shadow-none cursor-pointer",
|
|
5432
|
-
style: isCancel ? {
|
|
5433
|
-
backgroundColor: "var(--ohw-background)",
|
|
5434
|
-
borderColor: "var(--ohw-border)",
|
|
5435
|
-
color: "var(--ohw-foreground)"
|
|
5436
|
-
} : void 0,
|
|
5437
|
-
onClick: state.handleSecondary,
|
|
5438
|
-
children: state.secondaryLabel
|
|
5439
|
-
}
|
|
5440
|
-
),
|
|
5441
|
-
/* @__PURE__ */ jsx18(
|
|
5442
|
-
Button,
|
|
5443
|
-
{
|
|
5444
|
-
type: "button",
|
|
5445
|
-
className: "border-0 leading-6 shadow-none hover:opacity-90 disabled:opacity-50 cursor-pointer",
|
|
5446
|
-
style: {
|
|
5447
|
-
backgroundColor: "var(--ohw-primary)",
|
|
5448
|
-
color: "var(--ohw-primary-foreground)"
|
|
5449
|
-
},
|
|
5450
|
-
disabled: !state.isValid,
|
|
5451
|
-
onClick: state.handleSubmit,
|
|
5452
|
-
children: state.submitLabel
|
|
5453
|
-
}
|
|
5454
|
-
)
|
|
5455
|
-
] })
|
|
6164
|
+
),
|
|
6165
|
+
sectionPickerActive && state.selectedPage ? /* @__PURE__ */ jsx20(
|
|
6166
|
+
SectionPickerOverlay,
|
|
6167
|
+
{
|
|
6168
|
+
pagePath: state.selectedPage.path,
|
|
6169
|
+
sections: state.activeSections,
|
|
6170
|
+
onBack: state.handleSectionPickerBack,
|
|
6171
|
+
onSelect: state.handleSectionSelect
|
|
6172
|
+
}
|
|
6173
|
+
) : null
|
|
5456
6174
|
] });
|
|
5457
6175
|
}
|
|
5458
6176
|
|
|
5459
|
-
// src/ui/link-modal/LinkPopover.tsx
|
|
5460
|
-
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
5461
|
-
function LinkPopover({
|
|
5462
|
-
open = true,
|
|
5463
|
-
panelRef,
|
|
5464
|
-
portalContainer,
|
|
5465
|
-
onClose,
|
|
5466
|
-
...editorProps
|
|
5467
|
-
}) {
|
|
5468
|
-
return /* @__PURE__ */ jsx19(
|
|
5469
|
-
Dialog2,
|
|
5470
|
-
{
|
|
5471
|
-
open,
|
|
5472
|
-
onOpenChange: (next) => {
|
|
5473
|
-
if (!next) onClose?.();
|
|
5474
|
-
},
|
|
5475
|
-
children: /* @__PURE__ */ jsx19(
|
|
5476
|
-
DialogContent,
|
|
5477
|
-
{
|
|
5478
|
-
ref: panelRef,
|
|
5479
|
-
container: portalContainer,
|
|
5480
|
-
"data-ohw-link-popover-root": "",
|
|
5481
|
-
"data-ohw-link-modal-root": "",
|
|
5482
|
-
"data-ohw-bridge": "",
|
|
5483
|
-
showCloseButton: false,
|
|
5484
|
-
className: "gap-0 p-0 w-full md:w-md pointer-events-auto",
|
|
5485
|
-
children: /* @__PURE__ */ jsx19(LinkEditorPanel, { ...editorProps, open, onClose })
|
|
5486
|
-
}
|
|
5487
|
-
)
|
|
5488
|
-
}
|
|
5489
|
-
);
|
|
5490
|
-
}
|
|
5491
|
-
|
|
5492
6177
|
// src/ui/link-modal/devFixtures.ts
|
|
5493
6178
|
var DEV_SITE_PAGES = [
|
|
5494
6179
|
{ path: "/", title: "Home" },
|
|
@@ -5508,16 +6193,21 @@ var DEV_SECTIONS_BY_PATH = {
|
|
|
5508
6193
|
{ id: "founder-teaser", label: "Founder" },
|
|
5509
6194
|
{ id: "plan-form", label: "Plan Form" },
|
|
5510
6195
|
{ id: "testimonials", label: "Testimonials" },
|
|
5511
|
-
{ id: "wordmark", label: "Wordmark" }
|
|
6196
|
+
{ id: "wordmark", label: "Wordmark" },
|
|
6197
|
+
{ id: "footer", label: "Footer" }
|
|
5512
6198
|
],
|
|
5513
6199
|
"/about": [
|
|
5514
6200
|
{ id: "manifesto", label: "Manifesto" },
|
|
5515
6201
|
{ id: "story-letter", label: "Our Story" },
|
|
5516
6202
|
{ id: "lagree-explainer", label: "Lagree Explainer" },
|
|
5517
6203
|
{ id: "waitlist-cta", label: "Waitlist" },
|
|
5518
|
-
{ id: "personal-training", label: "Personal training" }
|
|
6204
|
+
{ id: "personal-training", label: "Personal training" },
|
|
6205
|
+
{ id: "footer", label: "Footer" }
|
|
6206
|
+
],
|
|
6207
|
+
"/classes": [
|
|
6208
|
+
{ id: "class-library", label: "Class Library" },
|
|
6209
|
+
{ id: "footer", label: "Footer" }
|
|
5519
6210
|
],
|
|
5520
|
-
"/classes": [{ id: "class-library", label: "Class Library" }],
|
|
5521
6211
|
"/pricing": [
|
|
5522
6212
|
{ id: "page-header", label: "Page Header" },
|
|
5523
6213
|
{ id: "free-class-cta", label: "Free Class" },
|
|
@@ -5525,19 +6215,25 @@ var DEV_SECTIONS_BY_PATH = {
|
|
|
5525
6215
|
{ id: "monthly-memberships", label: "Memberships" },
|
|
5526
6216
|
{ id: "specialty-programs", label: "Specialty Programs" },
|
|
5527
6217
|
{ id: "package-matcher", label: "Packages" },
|
|
5528
|
-
{ id: "wordmark", label: "Wordmark" }
|
|
6218
|
+
{ id: "wordmark", label: "Wordmark" },
|
|
6219
|
+
{ id: "footer", label: "Footer" }
|
|
5529
6220
|
],
|
|
5530
6221
|
"/studio": [
|
|
5531
6222
|
{ id: "studio-intro", label: "Studio Intro" },
|
|
5532
6223
|
{ id: "studio-features", label: "Studio Features" },
|
|
5533
6224
|
{ id: "studio-gallery", label: "Studio Gallery" },
|
|
5534
|
-
{ id: "studio-visit", label: "Visit Studio" }
|
|
6225
|
+
{ id: "studio-visit", label: "Visit Studio" },
|
|
6226
|
+
{ id: "footer", label: "Footer" }
|
|
6227
|
+
],
|
|
6228
|
+
"/instructors": [
|
|
6229
|
+
{ id: "instructor-grid", label: "Instructors" },
|
|
6230
|
+
{ id: "footer", label: "Footer" }
|
|
5535
6231
|
],
|
|
5536
|
-
"/instructors": [{ id: "instructor-grid", label: "Instructors" }],
|
|
5537
6232
|
"/contact": [
|
|
5538
6233
|
{ id: "hello-hero", label: "Hello" },
|
|
5539
6234
|
{ id: "contact-form", label: "Contact Form" },
|
|
5540
|
-
{ id: "faq", label: "FAQ" }
|
|
6235
|
+
{ id: "faq", label: "FAQ" },
|
|
6236
|
+
{ id: "footer", label: "Footer" }
|
|
5541
6237
|
]
|
|
5542
6238
|
};
|
|
5543
6239
|
function shouldUseDevFixtures() {
|
|
@@ -5547,8 +6243,277 @@ function shouldUseDevFixtures() {
|
|
|
5547
6243
|
return new URLSearchParams(q).get("ohw-fixtures") === "1";
|
|
5548
6244
|
}
|
|
5549
6245
|
|
|
6246
|
+
// src/lib/nav-items.ts
|
|
6247
|
+
var NAV_COUNT_KEY = "__ohw_nav_count";
|
|
6248
|
+
var NAV_ORDER_KEY = "__ohw_nav_order";
|
|
6249
|
+
function getLinkHref(el) {
|
|
6250
|
+
const key = el.getAttribute("data-ohw-href-key");
|
|
6251
|
+
if (key) {
|
|
6252
|
+
const stored = getStoredLinkHref(key);
|
|
6253
|
+
if (stored !== void 0) return stored;
|
|
6254
|
+
}
|
|
6255
|
+
return el.getAttribute("href") ?? "";
|
|
6256
|
+
}
|
|
6257
|
+
function isNavbarButton(el) {
|
|
6258
|
+
return el.hasAttribute("data-ohw-role") && el.getAttribute("data-ohw-role") === "navbar-button";
|
|
6259
|
+
}
|
|
6260
|
+
function isNavbarLinkItem(el) {
|
|
6261
|
+
if (!el.matches("[data-ohw-href-key]")) return false;
|
|
6262
|
+
if (isNavbarButton(el)) return false;
|
|
6263
|
+
if (!el.querySelector('[data-ohw-editable="text"]')) return false;
|
|
6264
|
+
return Boolean(el.closest("nav, [data-ohw-nav-container], [data-ohw-nav-drawer]"));
|
|
6265
|
+
}
|
|
6266
|
+
function getNavbarDesktopContainer() {
|
|
6267
|
+
return document.querySelector("[data-ohw-nav-container]");
|
|
6268
|
+
}
|
|
6269
|
+
function getNavbarDrawerContainer() {
|
|
6270
|
+
return document.querySelector("[data-ohw-nav-drawer]");
|
|
6271
|
+
}
|
|
6272
|
+
function listNavbarItems() {
|
|
6273
|
+
const desktop = getNavbarDesktopContainer();
|
|
6274
|
+
if (desktop) {
|
|
6275
|
+
return Array.from(desktop.querySelectorAll("[data-ohw-href-key]")).filter(isNavbarLinkItem);
|
|
6276
|
+
}
|
|
6277
|
+
const drawer = getNavbarDrawerContainer();
|
|
6278
|
+
if (drawer) {
|
|
6279
|
+
return Array.from(drawer.querySelectorAll("[data-ohw-href-key]")).filter(isNavbarLinkItem);
|
|
6280
|
+
}
|
|
6281
|
+
return Array.from(document.querySelectorAll("nav [data-ohw-href-key]")).filter(isNavbarLinkItem);
|
|
6282
|
+
}
|
|
6283
|
+
function parseNavIndexFromKey(key) {
|
|
6284
|
+
if (!key) return null;
|
|
6285
|
+
const match = key.match(/^nav-(\d+)-href$/);
|
|
6286
|
+
if (!match) return null;
|
|
6287
|
+
return parseInt(match[1], 10);
|
|
6288
|
+
}
|
|
6289
|
+
function getNavbarIndicesInDom() {
|
|
6290
|
+
const indices = /* @__PURE__ */ new Set();
|
|
6291
|
+
for (const item of listNavbarItems()) {
|
|
6292
|
+
const idx = parseNavIndexFromKey(item.getAttribute("data-ohw-href-key"));
|
|
6293
|
+
if (idx !== null) indices.add(idx);
|
|
6294
|
+
}
|
|
6295
|
+
return [...indices].sort((a, b) => a - b);
|
|
6296
|
+
}
|
|
6297
|
+
function getNextNavbarIndex() {
|
|
6298
|
+
const indices = getNavbarIndicesInDom();
|
|
6299
|
+
if (indices.length === 0) return 0;
|
|
6300
|
+
return Math.max(...indices) + 1;
|
|
6301
|
+
}
|
|
6302
|
+
function getNavbarExistingTargets() {
|
|
6303
|
+
return listNavbarItems().map((el) => getLinkHref(el)).filter(Boolean);
|
|
6304
|
+
}
|
|
6305
|
+
function getNavOrderFromDom() {
|
|
6306
|
+
return listNavbarItems().map((el) => el.getAttribute("data-ohw-href-key")).filter((key) => Boolean(key));
|
|
6307
|
+
}
|
|
6308
|
+
function parseNavOrder(content) {
|
|
6309
|
+
const raw = content[NAV_ORDER_KEY];
|
|
6310
|
+
if (!raw) return null;
|
|
6311
|
+
try {
|
|
6312
|
+
const parsed = JSON.parse(raw);
|
|
6313
|
+
if (!Array.isArray(parsed)) return null;
|
|
6314
|
+
return parsed.filter((key) => typeof key === "string" && key.length > 0);
|
|
6315
|
+
} catch {
|
|
6316
|
+
return null;
|
|
6317
|
+
}
|
|
6318
|
+
}
|
|
6319
|
+
function findCounterpartByHrefKey(hrefKey, root) {
|
|
6320
|
+
return root.querySelector(`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`);
|
|
6321
|
+
}
|
|
6322
|
+
function cloneNavLinkShell(template) {
|
|
6323
|
+
const anchor = document.createElement("a");
|
|
6324
|
+
if (template) {
|
|
6325
|
+
anchor.style.cssText = template.style.cssText;
|
|
6326
|
+
if (template.className) anchor.className = template.className;
|
|
6327
|
+
}
|
|
6328
|
+
anchor.style.cursor = "pointer";
|
|
6329
|
+
anchor.style.textDecoration = "none";
|
|
6330
|
+
return anchor;
|
|
6331
|
+
}
|
|
6332
|
+
function buildNavLink(index, href, label, template) {
|
|
6333
|
+
const anchor = cloneNavLinkShell(template);
|
|
6334
|
+
anchor.href = href;
|
|
6335
|
+
anchor.setAttribute("data-ohw-href-key", `nav-${index}-href`);
|
|
6336
|
+
const span = document.createElement("span");
|
|
6337
|
+
span.setAttribute("data-ohw-editable", "text");
|
|
6338
|
+
span.setAttribute("data-ohw-key", `nav-${index}-label`);
|
|
6339
|
+
span.textContent = label;
|
|
6340
|
+
anchor.appendChild(span);
|
|
6341
|
+
return anchor;
|
|
6342
|
+
}
|
|
6343
|
+
function insertNavLinkInContainer(container, anchor, afterHrefKey) {
|
|
6344
|
+
if (!afterHrefKey) {
|
|
6345
|
+
container.appendChild(anchor);
|
|
6346
|
+
return;
|
|
6347
|
+
}
|
|
6348
|
+
const afterEl = findCounterpartByHrefKey(afterHrefKey, container);
|
|
6349
|
+
if (afterEl?.parentElement === container) {
|
|
6350
|
+
afterEl.insertAdjacentElement("afterend", anchor);
|
|
6351
|
+
return;
|
|
6352
|
+
}
|
|
6353
|
+
container.appendChild(anchor);
|
|
6354
|
+
}
|
|
6355
|
+
function insertNavbarItemDom(index, href, label, afterAnchor) {
|
|
6356
|
+
const afterHrefKey = afterAnchor?.getAttribute("data-ohw-href-key") ?? null;
|
|
6357
|
+
const desktopItems = getNavbarDesktopContainer()?.querySelectorAll("[data-ohw-href-key]") ?? [];
|
|
6358
|
+
const drawerItems = getNavbarDrawerContainer()?.querySelectorAll("[data-ohw-href-key]") ?? [];
|
|
6359
|
+
const desktopTemplate = Array.from(desktopItems).find(isNavbarLinkItem) ?? null;
|
|
6360
|
+
const drawerTemplate = Array.from(drawerItems).find(isNavbarLinkItem) ?? null;
|
|
6361
|
+
let primary = null;
|
|
6362
|
+
const desktopContainer = getNavbarDesktopContainer();
|
|
6363
|
+
if (desktopContainer) {
|
|
6364
|
+
const desktopAnchor = buildNavLink(index, href, label, desktopTemplate);
|
|
6365
|
+
insertNavLinkInContainer(desktopContainer, desktopAnchor, afterHrefKey);
|
|
6366
|
+
primary = desktopAnchor;
|
|
6367
|
+
}
|
|
6368
|
+
const drawerContainer = getNavbarDrawerContainer();
|
|
6369
|
+
if (drawerContainer) {
|
|
6370
|
+
const drawerAnchor = buildNavLink(index, href, label, drawerTemplate);
|
|
6371
|
+
insertNavLinkInContainer(drawerContainer, drawerAnchor, afterHrefKey);
|
|
6372
|
+
if (!primary) primary = drawerAnchor;
|
|
6373
|
+
}
|
|
6374
|
+
if (!primary) {
|
|
6375
|
+
const fallback = buildNavLink(index, href, label, listNavbarItems()[0] ?? null);
|
|
6376
|
+
const nav = document.querySelector("nav");
|
|
6377
|
+
nav?.appendChild(fallback);
|
|
6378
|
+
primary = fallback;
|
|
6379
|
+
}
|
|
6380
|
+
return primary;
|
|
6381
|
+
}
|
|
6382
|
+
function applyNavOrderToContainer(container, order) {
|
|
6383
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6384
|
+
for (const hrefKey of order) {
|
|
6385
|
+
if (seen.has(hrefKey)) continue;
|
|
6386
|
+
seen.add(hrefKey);
|
|
6387
|
+
const el = findCounterpartByHrefKey(hrefKey, container);
|
|
6388
|
+
if (el) container.appendChild(el);
|
|
6389
|
+
}
|
|
6390
|
+
for (const el of container.querySelectorAll("[data-ohw-href-key]")) {
|
|
6391
|
+
if (!isNavbarLinkItem(el)) continue;
|
|
6392
|
+
const key = el.getAttribute("data-ohw-href-key");
|
|
6393
|
+
if (!key || seen.has(key)) continue;
|
|
6394
|
+
container.appendChild(el);
|
|
6395
|
+
}
|
|
6396
|
+
}
|
|
6397
|
+
function applyNavOrder(order) {
|
|
6398
|
+
const desktop = getNavbarDesktopContainer();
|
|
6399
|
+
if (desktop) applyNavOrderToContainer(desktop, order);
|
|
6400
|
+
const drawer = getNavbarDrawerContainer();
|
|
6401
|
+
if (drawer) applyNavOrderToContainer(drawer, order);
|
|
6402
|
+
}
|
|
6403
|
+
function collectNavbarIndicesFromContent(content) {
|
|
6404
|
+
const indices = /* @__PURE__ */ new Set();
|
|
6405
|
+
for (const key of Object.keys(content)) {
|
|
6406
|
+
const idx = parseNavIndexFromKey(key);
|
|
6407
|
+
if (idx !== null) indices.add(idx);
|
|
6408
|
+
}
|
|
6409
|
+
const countRaw = content[NAV_COUNT_KEY];
|
|
6410
|
+
if (countRaw) {
|
|
6411
|
+
const count = parseInt(countRaw, 10);
|
|
6412
|
+
if (Number.isFinite(count) && count > 0) {
|
|
6413
|
+
for (let i = 0; i < count; i++) indices.add(i);
|
|
6414
|
+
}
|
|
6415
|
+
}
|
|
6416
|
+
return [...indices].sort((a, b) => a - b);
|
|
6417
|
+
}
|
|
6418
|
+
function navbarIndexExistsInDom(index) {
|
|
6419
|
+
return document.querySelector(`[data-ohw-href-key="nav-${index}-href"]`) !== null;
|
|
6420
|
+
}
|
|
6421
|
+
function reconcileNavbarItemsFromContent(content) {
|
|
6422
|
+
const indices = collectNavbarIndicesFromContent(content);
|
|
6423
|
+
for (const index of indices) {
|
|
6424
|
+
if (navbarIndexExistsInDom(index)) continue;
|
|
6425
|
+
const href = content[`nav-${index}-href`];
|
|
6426
|
+
const label = content[`nav-${index}-label`];
|
|
6427
|
+
if (!href && !label) continue;
|
|
6428
|
+
insertNavbarItemDom(index, href ?? "/", label ?? "Untitled", null);
|
|
6429
|
+
}
|
|
6430
|
+
const order = parseNavOrder(content);
|
|
6431
|
+
if (order?.length) applyNavOrder(order);
|
|
6432
|
+
}
|
|
6433
|
+
function buildNavOrderAfterInsert(afterAnchor, newHrefKey) {
|
|
6434
|
+
const order = getNavOrderFromDom();
|
|
6435
|
+
if (!afterAnchor) {
|
|
6436
|
+
if (!order.includes(newHrefKey)) order.push(newHrefKey);
|
|
6437
|
+
return order;
|
|
6438
|
+
}
|
|
6439
|
+
const afterKey = afterAnchor.getAttribute("data-ohw-href-key");
|
|
6440
|
+
if (!afterKey) {
|
|
6441
|
+
if (!order.includes(newHrefKey)) order.push(newHrefKey);
|
|
6442
|
+
return order;
|
|
6443
|
+
}
|
|
6444
|
+
const withoutNew = order.filter((key) => key !== newHrefKey);
|
|
6445
|
+
const pos = withoutNew.indexOf(afterKey);
|
|
6446
|
+
if (pos >= 0) {
|
|
6447
|
+
withoutNew.splice(pos + 1, 0, newHrefKey);
|
|
6448
|
+
return withoutNew;
|
|
6449
|
+
}
|
|
6450
|
+
withoutNew.push(newHrefKey);
|
|
6451
|
+
return withoutNew;
|
|
6452
|
+
}
|
|
6453
|
+
function insertNavbarItem(href, label, afterAnchor = null) {
|
|
6454
|
+
const index = getNextNavbarIndex();
|
|
6455
|
+
const anchor = insertNavbarItemDom(index, href, label, afterAnchor);
|
|
6456
|
+
if (!anchor) throw new Error("Failed to insert navbar item");
|
|
6457
|
+
const hrefKey = `nav-${index}-href`;
|
|
6458
|
+
const order = buildNavOrderAfterInsert(afterAnchor, hrefKey);
|
|
6459
|
+
applyNavOrder(order);
|
|
6460
|
+
return {
|
|
6461
|
+
anchor,
|
|
6462
|
+
index,
|
|
6463
|
+
hrefKey,
|
|
6464
|
+
labelKey: `nav-${index}-label`,
|
|
6465
|
+
href,
|
|
6466
|
+
label,
|
|
6467
|
+
order
|
|
6468
|
+
};
|
|
6469
|
+
}
|
|
6470
|
+
|
|
6471
|
+
// src/ui/navbar-container-chrome.tsx
|
|
6472
|
+
import { Plus as Plus2 } from "lucide-react";
|
|
6473
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
6474
|
+
function NavbarContainerChrome({
|
|
6475
|
+
rect,
|
|
6476
|
+
onAdd
|
|
6477
|
+
}) {
|
|
6478
|
+
const chromeGap = 6;
|
|
6479
|
+
return /* @__PURE__ */ jsx21(
|
|
6480
|
+
"div",
|
|
6481
|
+
{
|
|
6482
|
+
"data-ohw-navbar-container-chrome": "",
|
|
6483
|
+
"data-ohw-bridge": "",
|
|
6484
|
+
className: "pointer-events-none fixed z-[2147483647]",
|
|
6485
|
+
style: {
|
|
6486
|
+
top: rect.top - chromeGap,
|
|
6487
|
+
left: rect.left - chromeGap,
|
|
6488
|
+
width: rect.width + chromeGap * 2,
|
|
6489
|
+
height: rect.height + chromeGap * 2
|
|
6490
|
+
},
|
|
6491
|
+
children: /* @__PURE__ */ jsx21(
|
|
6492
|
+
"button",
|
|
6493
|
+
{
|
|
6494
|
+
type: "button",
|
|
6495
|
+
"data-ohw-navbar-add-button": "",
|
|
6496
|
+
className: "pointer-events-auto absolute left-1/2 flex p-0.5 rounded-[10px] size-7 -translate-x-1/2 translate-y-1/2 items-center justify-center border border-border bg-background shadow-sm transition-colors hover:bg-muted/80",
|
|
6497
|
+
style: { top: "70%" },
|
|
6498
|
+
"aria-label": "Add item",
|
|
6499
|
+
onMouseDown: (e) => {
|
|
6500
|
+
e.preventDefault();
|
|
6501
|
+
e.stopPropagation();
|
|
6502
|
+
},
|
|
6503
|
+
onClick: (e) => {
|
|
6504
|
+
e.preventDefault();
|
|
6505
|
+
e.stopPropagation();
|
|
6506
|
+
onAdd();
|
|
6507
|
+
},
|
|
6508
|
+
children: /* @__PURE__ */ jsx21(Plus2, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
|
|
6509
|
+
}
|
|
6510
|
+
)
|
|
6511
|
+
}
|
|
6512
|
+
);
|
|
6513
|
+
}
|
|
6514
|
+
|
|
5550
6515
|
// src/ui/badge.tsx
|
|
5551
|
-
import { jsx as
|
|
6516
|
+
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
5552
6517
|
var badgeVariants = cva(
|
|
5553
6518
|
"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",
|
|
5554
6519
|
{
|
|
@@ -5566,12 +6531,12 @@ var badgeVariants = cva(
|
|
|
5566
6531
|
}
|
|
5567
6532
|
);
|
|
5568
6533
|
function Badge({ className, variant, ...props }) {
|
|
5569
|
-
return /* @__PURE__ */
|
|
6534
|
+
return /* @__PURE__ */ jsx22("div", { className: cn(badgeVariants({ variant }), className), ...props });
|
|
5570
6535
|
}
|
|
5571
6536
|
|
|
5572
6537
|
// src/OhhwellsBridge.tsx
|
|
5573
6538
|
import { Link as Link2 } from "lucide-react";
|
|
5574
|
-
import { Fragment as
|
|
6539
|
+
import { Fragment as Fragment5, jsx as jsx23, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
5575
6540
|
var PRIMARY2 = "#0885FE";
|
|
5576
6541
|
var IMAGE_FADE_MS = 300;
|
|
5577
6542
|
function runOpacityFade(el, onDone) {
|
|
@@ -5750,7 +6715,7 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
5750
6715
|
const root = createRoot(container);
|
|
5751
6716
|
flushSync(() => {
|
|
5752
6717
|
root.render(
|
|
5753
|
-
/* @__PURE__ */
|
|
6718
|
+
/* @__PURE__ */ jsx23(
|
|
5754
6719
|
SchedulingWidget,
|
|
5755
6720
|
{
|
|
5756
6721
|
notifyOnConnect,
|
|
@@ -5790,7 +6755,7 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
|
|
|
5790
6755
|
}
|
|
5791
6756
|
}
|
|
5792
6757
|
}
|
|
5793
|
-
function
|
|
6758
|
+
function getLinkHref2(el) {
|
|
5794
6759
|
const anchor = el instanceof HTMLAnchorElement ? el : el.querySelector("a");
|
|
5795
6760
|
return anchor?.getAttribute("href") ?? "";
|
|
5796
6761
|
}
|
|
@@ -5823,8 +6788,11 @@ function collectEditableNodes() {
|
|
|
5823
6788
|
const url = raw.replace(/^url\(['"]?/, "").replace(/['"]?\)$/, "");
|
|
5824
6789
|
return { key: el.dataset.ohwKey ?? "", type: "bg-image", text: url };
|
|
5825
6790
|
}
|
|
6791
|
+
if (el.dataset.ohwEditable === "video") {
|
|
6792
|
+
return { key: el.dataset.ohwKey ?? "", type: "video", text: getVideoEl(el)?.src ?? "" };
|
|
6793
|
+
}
|
|
5826
6794
|
if (el.dataset.ohwEditable === "link") {
|
|
5827
|
-
return { key: el.dataset.ohwKey ?? "", type: "link", text:
|
|
6795
|
+
return { key: el.dataset.ohwKey ?? "", type: "link", text: getLinkHref2(el) };
|
|
5828
6796
|
}
|
|
5829
6797
|
return {
|
|
5830
6798
|
key: el.dataset.ohwKey ?? "",
|
|
@@ -5835,9 +6803,79 @@ function collectEditableNodes() {
|
|
|
5835
6803
|
document.querySelectorAll("[data-ohw-href-key]").forEach((el) => {
|
|
5836
6804
|
const key = el.getAttribute("data-ohw-href-key") ?? "";
|
|
5837
6805
|
if (!key) return;
|
|
5838
|
-
nodes.push({ key, type: "link", text:
|
|
6806
|
+
nodes.push({ key, type: "link", text: getLinkHref2(el) });
|
|
6807
|
+
});
|
|
6808
|
+
document.querySelectorAll('[data-ohw-editable="video"]').forEach((el) => {
|
|
6809
|
+
const key = el.dataset.ohwKey ?? "";
|
|
6810
|
+
const video = getVideoEl(el);
|
|
6811
|
+
if (!key || !video) return;
|
|
6812
|
+
nodes.push({ key: `${key}${VIDEO_AUTOPLAY_SUFFIX}`, type: "video-setting", text: String(video.autoplay) });
|
|
6813
|
+
nodes.push({ key: `${key}${VIDEO_MUTED_SUFFIX}`, type: "video-setting", text: String(video.muted) });
|
|
6814
|
+
});
|
|
6815
|
+
return nodes;
|
|
6816
|
+
}
|
|
6817
|
+
function isMediaEditable(el) {
|
|
6818
|
+
const t = el.dataset.ohwEditable;
|
|
6819
|
+
return t === "image" || t === "bg-image" || t === "video";
|
|
6820
|
+
}
|
|
6821
|
+
var MEDIA_SELECTOR = '[data-ohw-editable="image"], [data-ohw-editable="bg-image"], [data-ohw-editable="video"]';
|
|
6822
|
+
var NON_MEDIA_SELECTOR = '[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"])';
|
|
6823
|
+
function getVideoEl(el) {
|
|
6824
|
+
return el instanceof HTMLVideoElement ? el : el.querySelector("video");
|
|
6825
|
+
}
|
|
6826
|
+
var VIDEO_AUTOPLAY_SUFFIX = "__ohw_autoplay";
|
|
6827
|
+
var VIDEO_MUTED_SUFFIX = "__ohw_muted";
|
|
6828
|
+
function isBackgroundVideo(video) {
|
|
6829
|
+
return video.autoplay && video.muted;
|
|
6830
|
+
}
|
|
6831
|
+
function syncVideoPlayback(video) {
|
|
6832
|
+
const background = isBackgroundVideo(video);
|
|
6833
|
+
video.controls = !background;
|
|
6834
|
+
if (video.autoplay) void video.play().catch(() => {
|
|
6835
|
+
});
|
|
6836
|
+
else video.pause();
|
|
6837
|
+
}
|
|
6838
|
+
function lockVideoBox(video) {
|
|
6839
|
+
const { width, height } = video.getBoundingClientRect();
|
|
6840
|
+
if (width > 0 && height > 0 && !video.style.aspectRatio) {
|
|
6841
|
+
video.style.aspectRatio = `${width} / ${height}`;
|
|
6842
|
+
}
|
|
6843
|
+
if (getComputedStyle(video).objectFit === "fill") {
|
|
6844
|
+
video.style.objectFit = "contain";
|
|
6845
|
+
}
|
|
6846
|
+
const fit = video.style.objectFit || getComputedStyle(video).objectFit;
|
|
6847
|
+
const bg = getComputedStyle(video).backgroundColor;
|
|
6848
|
+
const isTransparent = bg === "rgba(0, 0, 0, 0)" || bg === "transparent" || !bg;
|
|
6849
|
+
if (fit === "contain" && isTransparent) {
|
|
6850
|
+
video.style.backgroundColor = "var(--color-dark, #000)";
|
|
6851
|
+
}
|
|
6852
|
+
}
|
|
6853
|
+
function applyVideoSrc(video, url) {
|
|
6854
|
+
const { autoplay, muted } = video;
|
|
6855
|
+
lockVideoBox(video);
|
|
6856
|
+
video.src = url;
|
|
6857
|
+
video.loop = true;
|
|
6858
|
+
video.playsInline = true;
|
|
6859
|
+
video.autoplay = autoplay;
|
|
6860
|
+
video.muted = muted;
|
|
6861
|
+
video.load();
|
|
6862
|
+
syncVideoPlayback(video);
|
|
6863
|
+
}
|
|
6864
|
+
function applyVideoSettingNode(key, val) {
|
|
6865
|
+
const isAutoplay = key.endsWith(VIDEO_AUTOPLAY_SUFFIX);
|
|
6866
|
+
const isMuted = key.endsWith(VIDEO_MUTED_SUFFIX);
|
|
6867
|
+
if (!isAutoplay && !isMuted) return false;
|
|
6868
|
+
const suffixLen = (isAutoplay ? VIDEO_AUTOPLAY_SUFFIX : VIDEO_MUTED_SUFFIX).length;
|
|
6869
|
+
const baseKey = key.slice(0, key.length - suffixLen);
|
|
6870
|
+
const on = val === "true";
|
|
6871
|
+
document.querySelectorAll(`[data-ohw-key="${baseKey}"]`).forEach((el) => {
|
|
6872
|
+
const video = getVideoEl(el);
|
|
6873
|
+
if (!video) return;
|
|
6874
|
+
if (isAutoplay) video.autoplay = on;
|
|
6875
|
+
else video.muted = on;
|
|
6876
|
+
syncVideoPlayback(video);
|
|
5839
6877
|
});
|
|
5840
|
-
return
|
|
6878
|
+
return true;
|
|
5841
6879
|
}
|
|
5842
6880
|
function applyLinkByKey(key, val) {
|
|
5843
6881
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -5851,7 +6889,7 @@ function applyLinkByKey(key, val) {
|
|
|
5851
6889
|
}
|
|
5852
6890
|
function isInsideLinkEditor(target) {
|
|
5853
6891
|
return Boolean(
|
|
5854
|
-
target.closest("[data-ohw-link-popover-root]") || target.closest("[data-ohw-link-modal-root]") || target.closest("[data-ohw-link-page-dropdown]") || target.closest('[data-slot="popover-content"]') || target.closest('[data-slot="dialog-content"]') || target.closest('[data-slot="dialog-overlay"]')
|
|
6892
|
+
target.closest("[data-ohw-link-popover-root]") || target.closest("[data-ohw-link-modal-root]") || target.closest("[data-ohw-link-page-dropdown]") || target.closest("[data-ohw-section-picker]") || target.closest("[data-ohw-navbar-container-chrome]") || target.closest("[data-ohw-navbar-add-button]") || target.closest('[data-slot="popover-content"]') || target.closest('[data-slot="dialog-content"]') || target.closest('[data-slot="dialog-overlay"]')
|
|
5855
6893
|
);
|
|
5856
6894
|
}
|
|
5857
6895
|
function getHrefKeyFromElement(el) {
|
|
@@ -5862,7 +6900,7 @@ function getHrefKeyFromElement(el) {
|
|
|
5862
6900
|
if (!key) return null;
|
|
5863
6901
|
return { anchor, key };
|
|
5864
6902
|
}
|
|
5865
|
-
function
|
|
6903
|
+
function isNavbarButton2(el) {
|
|
5866
6904
|
return Boolean(el.closest('[data-ohw-role="navbar-button"]'));
|
|
5867
6905
|
}
|
|
5868
6906
|
function getNavigationItemAnchor(el) {
|
|
@@ -5874,19 +6912,8 @@ function getNavigationItemAnchor(el) {
|
|
|
5874
6912
|
function isNavigationItem(el) {
|
|
5875
6913
|
return getNavigationItemAnchor(el) !== null;
|
|
5876
6914
|
}
|
|
5877
|
-
function getNavigationItemAddHintTarget(anchor) {
|
|
5878
|
-
const items = listNavigationItems();
|
|
5879
|
-
const idx = items.indexOf(anchor);
|
|
5880
|
-
if (idx >= 0 && idx < items.length - 1) return items[idx + 1];
|
|
5881
|
-
return anchor;
|
|
5882
|
-
}
|
|
5883
|
-
function listNavigationItems() {
|
|
5884
|
-
return Array.from(
|
|
5885
|
-
document.querySelectorAll("nav [data-ohw-href-key], footer [data-ohw-href-key]")
|
|
5886
|
-
).filter((el) => isNavigationItem(el));
|
|
5887
|
-
}
|
|
5888
6915
|
function getNavigationItemReorderState(anchor) {
|
|
5889
|
-
if (
|
|
6916
|
+
if (isNavbarButton2(anchor)) return { key: null, disabled: false };
|
|
5890
6917
|
return getReorderHandleStateFromAnchor(anchor);
|
|
5891
6918
|
}
|
|
5892
6919
|
function getReorderHandleState(el) {
|
|
@@ -5908,6 +6935,120 @@ function clearHrefKeyHover(anchor) {
|
|
|
5908
6935
|
function isInsideNavigationItem(el) {
|
|
5909
6936
|
return getNavigationItemAnchor(el) !== null;
|
|
5910
6937
|
}
|
|
6938
|
+
function getNavigationRoot(el) {
|
|
6939
|
+
const explicit = el.closest("[data-ohw-nav-root]");
|
|
6940
|
+
if (explicit) return explicit;
|
|
6941
|
+
return el.closest("nav, footer, aside");
|
|
6942
|
+
}
|
|
6943
|
+
function findFooterItemGroup(item) {
|
|
6944
|
+
const footer = item.closest("footer");
|
|
6945
|
+
if (!footer) return null;
|
|
6946
|
+
let node = item.parentElement;
|
|
6947
|
+
while (node && node !== footer) {
|
|
6948
|
+
const hasDirectNavItems = Array.from(
|
|
6949
|
+
node.querySelectorAll(":scope > [data-ohw-href-key]")
|
|
6950
|
+
).some(isNavigationItem);
|
|
6951
|
+
if (hasDirectNavItems) return node;
|
|
6952
|
+
node = node.parentElement;
|
|
6953
|
+
}
|
|
6954
|
+
return null;
|
|
6955
|
+
}
|
|
6956
|
+
function isNavigationRoot(el) {
|
|
6957
|
+
return el.hasAttribute("data-ohw-nav-root") || el.matches("nav, footer, aside");
|
|
6958
|
+
}
|
|
6959
|
+
function isInferredFooterGroup(el) {
|
|
6960
|
+
const footer = el.closest("footer");
|
|
6961
|
+
if (!footer || el === footer) return false;
|
|
6962
|
+
return Array.from(el.querySelectorAll(":scope > [data-ohw-href-key]")).some(isNavigationItem);
|
|
6963
|
+
}
|
|
6964
|
+
function isNavigationContainer(el) {
|
|
6965
|
+
return el.hasAttribute("data-ohw-nav-container") || isNavigationRoot(el) || isInferredFooterGroup(el);
|
|
6966
|
+
}
|
|
6967
|
+
function isPointOverNavigation(x, y) {
|
|
6968
|
+
const navRoot = document.querySelector("[data-ohw-nav-root]") ?? document.querySelector("nav");
|
|
6969
|
+
if (!navRoot) return false;
|
|
6970
|
+
const r2 = navRoot.getBoundingClientRect();
|
|
6971
|
+
return x >= r2.left && x <= r2.right && y >= r2.top && y <= r2.bottom;
|
|
6972
|
+
}
|
|
6973
|
+
function isPointOverNavItem(container, x, y) {
|
|
6974
|
+
return Array.from(container.querySelectorAll("[data-ohw-href-key]")).some((el) => {
|
|
6975
|
+
if (!isNavigationItem(el) || isNavbarButton2(el)) return false;
|
|
6976
|
+
const itemRect = el.getBoundingClientRect();
|
|
6977
|
+
return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
|
|
6978
|
+
});
|
|
6979
|
+
}
|
|
6980
|
+
function resolveNavContainerSelectionTarget(target, clientX, clientY) {
|
|
6981
|
+
if (getNavigationItemAnchor(target)) return null;
|
|
6982
|
+
if (target.closest('[data-ohw-role="navbar-button"]')) return null;
|
|
6983
|
+
const plainLink = target.closest("a");
|
|
6984
|
+
if (plainLink && !plainLink.hasAttribute("data-ohw-href-key") && !plainLink.closest("[data-ohw-nav-container]")) {
|
|
6985
|
+
return null;
|
|
6986
|
+
}
|
|
6987
|
+
const fromClosest = target.closest("[data-ohw-nav-container]");
|
|
6988
|
+
if (fromClosest && !isPointOverNavItem(fromClosest, clientX, clientY)) {
|
|
6989
|
+
return fromClosest;
|
|
6990
|
+
}
|
|
6991
|
+
const navRoot = target.closest("[data-ohw-nav-root]");
|
|
6992
|
+
if (!navRoot) return null;
|
|
6993
|
+
const container = navRoot.querySelector("[data-ohw-nav-container]");
|
|
6994
|
+
if (!container || isPointOverNavItem(container, clientX, clientY)) return null;
|
|
6995
|
+
if (target === navRoot || target.hasAttribute("data-ohw-nav-root")) {
|
|
6996
|
+
return container;
|
|
6997
|
+
}
|
|
6998
|
+
return null;
|
|
6999
|
+
}
|
|
7000
|
+
function getNavigationSelectionParent(el) {
|
|
7001
|
+
if (isNavigationItem(el)) {
|
|
7002
|
+
const explicit = el.closest("[data-ohw-nav-container]");
|
|
7003
|
+
if (explicit) return explicit;
|
|
7004
|
+
const footerGroup = findFooterItemGroup(el);
|
|
7005
|
+
if (footerGroup) return footerGroup;
|
|
7006
|
+
return getNavigationRoot(el);
|
|
7007
|
+
}
|
|
7008
|
+
if (el.hasAttribute("data-ohw-nav-container") || isInferredFooterGroup(el)) {
|
|
7009
|
+
return getNavigationRoot(el);
|
|
7010
|
+
}
|
|
7011
|
+
return null;
|
|
7012
|
+
}
|
|
7013
|
+
function placeCaretAtPoint(el, x, y) {
|
|
7014
|
+
const selection = window.getSelection();
|
|
7015
|
+
if (!selection) return;
|
|
7016
|
+
if (typeof document.caretRangeFromPoint === "function") {
|
|
7017
|
+
const range = document.caretRangeFromPoint(x, y);
|
|
7018
|
+
if (range && el.contains(range.startContainer)) {
|
|
7019
|
+
selection.removeAllRanges();
|
|
7020
|
+
selection.addRange(range);
|
|
7021
|
+
return;
|
|
7022
|
+
}
|
|
7023
|
+
}
|
|
7024
|
+
const caretPositionFromPoint = document.caretPositionFromPoint;
|
|
7025
|
+
if (typeof caretPositionFromPoint === "function") {
|
|
7026
|
+
const position = caretPositionFromPoint(x, y);
|
|
7027
|
+
if (position && el.contains(position.offsetNode)) {
|
|
7028
|
+
const range = document.createRange();
|
|
7029
|
+
range.setStart(position.offsetNode, position.offset);
|
|
7030
|
+
range.collapse(true);
|
|
7031
|
+
selection.removeAllRanges();
|
|
7032
|
+
selection.addRange(range);
|
|
7033
|
+
}
|
|
7034
|
+
}
|
|
7035
|
+
}
|
|
7036
|
+
function selectAllTextInEditable(el) {
|
|
7037
|
+
const selection = window.getSelection();
|
|
7038
|
+
if (!selection) return;
|
|
7039
|
+
const range = document.createRange();
|
|
7040
|
+
range.selectNodeContents(el);
|
|
7041
|
+
selection.removeAllRanges();
|
|
7042
|
+
selection.addRange(range);
|
|
7043
|
+
}
|
|
7044
|
+
function getNavigationLabelEditable(target) {
|
|
7045
|
+
const editable = target.closest('[data-ohw-editable="text"]');
|
|
7046
|
+
if (!editable) return null;
|
|
7047
|
+
const hrefCtx = getHrefKeyFromElement(editable);
|
|
7048
|
+
const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
|
|
7049
|
+
if (!navAnchor) return null;
|
|
7050
|
+
return { editable, navAnchor };
|
|
7051
|
+
}
|
|
5911
7052
|
function collectSections() {
|
|
5912
7053
|
return collectSectionsFromDom();
|
|
5913
7054
|
}
|
|
@@ -6031,6 +7172,8 @@ var ICONS = {
|
|
|
6031
7172
|
insertUnorderedList: '<line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/>',
|
|
6032
7173
|
insertOrderedList: '<line x1="10" y1="6" x2="21" y2="6"/><line x1="10" y1="12" x2="21" y2="12"/><line x1="10" y1="18" x2="21" y2="18"/><path d="M4 6h1v4"/><path d="M4 10h2"/><path d="M6 18H4c0-1 2-2 2-3s-1-1.5-2-1"/>'
|
|
6033
7174
|
};
|
|
7175
|
+
var TOOLBAR_PILL_PADDING = 2;
|
|
7176
|
+
var TOOLBAR_TOGGLE_GAP = 4;
|
|
6034
7177
|
var TOOLBAR_GROUPS = [
|
|
6035
7178
|
[
|
|
6036
7179
|
{ cmd: "bold", title: "Bold" },
|
|
@@ -6055,7 +7198,7 @@ function EditGlowChrome({
|
|
|
6055
7198
|
dragDisabled = false
|
|
6056
7199
|
}) {
|
|
6057
7200
|
const GAP = 6;
|
|
6058
|
-
return /* @__PURE__ */
|
|
7201
|
+
return /* @__PURE__ */ jsxs13(
|
|
6059
7202
|
"div",
|
|
6060
7203
|
{
|
|
6061
7204
|
ref: elRef,
|
|
@@ -6070,7 +7213,7 @@ function EditGlowChrome({
|
|
|
6070
7213
|
zIndex: 2147483646
|
|
6071
7214
|
},
|
|
6072
7215
|
children: [
|
|
6073
|
-
/* @__PURE__ */
|
|
7216
|
+
/* @__PURE__ */ jsx23(
|
|
6074
7217
|
"div",
|
|
6075
7218
|
{
|
|
6076
7219
|
style: {
|
|
@@ -6083,7 +7226,7 @@ function EditGlowChrome({
|
|
|
6083
7226
|
}
|
|
6084
7227
|
}
|
|
6085
7228
|
),
|
|
6086
|
-
reorderHrefKey && /* @__PURE__ */
|
|
7229
|
+
reorderHrefKey && /* @__PURE__ */ jsx23(
|
|
6087
7230
|
"div",
|
|
6088
7231
|
{
|
|
6089
7232
|
"data-ohw-drag-handle-container": "",
|
|
@@ -6095,7 +7238,7 @@ function EditGlowChrome({
|
|
|
6095
7238
|
transform: "translate(calc(-100% - 7px), -50%)",
|
|
6096
7239
|
pointerEvents: dragDisabled ? "none" : "auto"
|
|
6097
7240
|
},
|
|
6098
|
-
children: /* @__PURE__ */
|
|
7241
|
+
children: /* @__PURE__ */ jsx23(
|
|
6099
7242
|
DragHandle,
|
|
6100
7243
|
{
|
|
6101
7244
|
"aria-label": `Reorder ${reorderHrefKey}`,
|
|
@@ -6199,7 +7342,7 @@ function FloatingToolbar({
|
|
|
6199
7342
|
onEditLink
|
|
6200
7343
|
}) {
|
|
6201
7344
|
const { top, left, transform } = calcToolbarPos(rect, parentScroll, 330);
|
|
6202
|
-
return /* @__PURE__ */
|
|
7345
|
+
return /* @__PURE__ */ jsx23(
|
|
6203
7346
|
"div",
|
|
6204
7347
|
{
|
|
6205
7348
|
ref: elRef,
|
|
@@ -6209,14 +7352,23 @@ function FloatingToolbar({
|
|
|
6209
7352
|
left,
|
|
6210
7353
|
transform,
|
|
6211
7354
|
zIndex: 2147483647,
|
|
7355
|
+
background: "#fff",
|
|
7356
|
+
border: "1px solid #E7E5E4",
|
|
7357
|
+
borderRadius: 6,
|
|
7358
|
+
boxShadow: "0px 2px 4px -2px rgba(0,0,0,.1),0px 4px 6px -1px rgba(0,0,0,.1)",
|
|
7359
|
+
display: "flex",
|
|
7360
|
+
alignItems: "center",
|
|
7361
|
+
padding: TOOLBAR_PILL_PADDING,
|
|
7362
|
+
gap: TOOLBAR_TOGGLE_GAP,
|
|
7363
|
+
fontFamily: "sans-serif",
|
|
6212
7364
|
pointerEvents: "auto"
|
|
6213
7365
|
},
|
|
6214
|
-
children: /* @__PURE__ */
|
|
6215
|
-
TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */
|
|
6216
|
-
gi > 0 && /* @__PURE__ */
|
|
7366
|
+
children: /* @__PURE__ */ jsxs13(CustomToolbar, { children: [
|
|
7367
|
+
TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs13(React9.Fragment, { children: [
|
|
7368
|
+
gi > 0 && /* @__PURE__ */ jsx23(CustomToolbarDivider, {}),
|
|
6217
7369
|
btns.map((btn) => {
|
|
6218
7370
|
const isActive = activeCommands.has(btn.cmd);
|
|
6219
|
-
return /* @__PURE__ */
|
|
7371
|
+
return /* @__PURE__ */ jsx23(
|
|
6220
7372
|
CustomToolbarButton,
|
|
6221
7373
|
{
|
|
6222
7374
|
title: btn.title,
|
|
@@ -6225,7 +7377,7 @@ function FloatingToolbar({
|
|
|
6225
7377
|
e.preventDefault();
|
|
6226
7378
|
onCommand(btn.cmd);
|
|
6227
7379
|
},
|
|
6228
|
-
children: /* @__PURE__ */
|
|
7380
|
+
children: /* @__PURE__ */ jsx23(
|
|
6229
7381
|
"svg",
|
|
6230
7382
|
{
|
|
6231
7383
|
width: "16",
|
|
@@ -6246,7 +7398,7 @@ function FloatingToolbar({
|
|
|
6246
7398
|
);
|
|
6247
7399
|
})
|
|
6248
7400
|
] }, gi)),
|
|
6249
|
-
showEditLink ? /* @__PURE__ */
|
|
7401
|
+
showEditLink ? /* @__PURE__ */ jsx23(
|
|
6250
7402
|
CustomToolbarButton,
|
|
6251
7403
|
{
|
|
6252
7404
|
type: "button",
|
|
@@ -6260,7 +7412,7 @@ function FloatingToolbar({
|
|
|
6260
7412
|
e.preventDefault();
|
|
6261
7413
|
e.stopPropagation();
|
|
6262
7414
|
},
|
|
6263
|
-
children: /* @__PURE__ */
|
|
7415
|
+
children: /* @__PURE__ */ jsx23(Link2, { className: "size-4 shrink-0", "aria-hidden": true })
|
|
6264
7416
|
}
|
|
6265
7417
|
) : null
|
|
6266
7418
|
] })
|
|
@@ -6277,7 +7429,7 @@ function StateToggle({
|
|
|
6277
7429
|
states,
|
|
6278
7430
|
onStateChange
|
|
6279
7431
|
}) {
|
|
6280
|
-
return /* @__PURE__ */
|
|
7432
|
+
return /* @__PURE__ */ jsx23(
|
|
6281
7433
|
ToggleGroup,
|
|
6282
7434
|
{
|
|
6283
7435
|
"data-ohw-state-toggle": "",
|
|
@@ -6291,7 +7443,7 @@ function StateToggle({
|
|
|
6291
7443
|
left: rect.right - 8,
|
|
6292
7444
|
transform: "translateX(-100%)"
|
|
6293
7445
|
},
|
|
6294
|
-
children: states.map((state) => /* @__PURE__ */
|
|
7446
|
+
children: states.map((state) => /* @__PURE__ */ jsx23(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
|
|
6295
7447
|
}
|
|
6296
7448
|
);
|
|
6297
7449
|
}
|
|
@@ -6314,12 +7466,12 @@ function resolveSubdomain(subdomainFromQuery) {
|
|
|
6314
7466
|
return "";
|
|
6315
7467
|
}
|
|
6316
7468
|
function OhhwellsBridge() {
|
|
6317
|
-
const pathname =
|
|
6318
|
-
const router =
|
|
7469
|
+
const pathname = usePathname2();
|
|
7470
|
+
const router = useRouter2();
|
|
6319
7471
|
const searchParams = useSearchParams();
|
|
6320
7472
|
const isEditMode = isEditSessionActive();
|
|
6321
|
-
const [bridgeRoot, setBridgeRoot] =
|
|
6322
|
-
|
|
7473
|
+
const [bridgeRoot, setBridgeRoot] = useState6(null);
|
|
7474
|
+
useEffect7(() => {
|
|
6323
7475
|
const figtreeFontId = "ohw-figtree-font";
|
|
6324
7476
|
if (!document.getElementById(figtreeFontId)) {
|
|
6325
7477
|
const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
|
|
@@ -6327,7 +7479,10 @@ function OhhwellsBridge() {
|
|
|
6327
7479
|
const stylesheet = Object.assign(document.createElement("link"), {
|
|
6328
7480
|
id: figtreeFontId,
|
|
6329
7481
|
rel: "stylesheet",
|
|
6330
|
-
|
|
7482
|
+
// Inter is loaded alongside Figtree for the media overlay's Replace button. The bridge
|
|
7483
|
+
// renders inside the customer's document, so it cannot assume any font is present — an
|
|
7484
|
+
// unloaded family would silently fall back to whatever the template happens to use.
|
|
7485
|
+
href: "https://fonts.googleapis.com/css2?family=Figtree:ital,wght@0,300..900;1,300..900&family=Inter:wght@400;500;600&display=swap"
|
|
6331
7486
|
});
|
|
6332
7487
|
document.head.append(preconnect1, preconnect2, stylesheet);
|
|
6333
7488
|
}
|
|
@@ -6344,80 +7499,91 @@ function OhhwellsBridge() {
|
|
|
6344
7499
|
const subdomainFromQuery = searchParams.get("subdomain");
|
|
6345
7500
|
const subdomain = resolveSubdomain(subdomainFromQuery);
|
|
6346
7501
|
useLinkHrefGuardian(pathname, subdomain, isEditMode);
|
|
6347
|
-
const
|
|
7502
|
+
const postToParent2 = useCallback4((data) => {
|
|
6348
7503
|
if (typeof window !== "undefined" && window.parent !== window) {
|
|
6349
7504
|
window.parent.postMessage(data, "*");
|
|
6350
7505
|
}
|
|
6351
7506
|
}, []);
|
|
6352
|
-
const [fetchState, setFetchState] =
|
|
6353
|
-
const autoSaveTimers =
|
|
6354
|
-
const activeElRef =
|
|
6355
|
-
const selectedElRef =
|
|
6356
|
-
const originalContentRef =
|
|
6357
|
-
const activeStateElRef =
|
|
6358
|
-
const parentScrollRef =
|
|
6359
|
-
const visibleViewportRef =
|
|
6360
|
-
const [dialogPortalContainer, setDialogPortalContainer] =
|
|
6361
|
-
const attachVisibleViewport =
|
|
7507
|
+
const [fetchState, setFetchState] = useState6("idle");
|
|
7508
|
+
const autoSaveTimers = useRef5(/* @__PURE__ */ new Map());
|
|
7509
|
+
const activeElRef = useRef5(null);
|
|
7510
|
+
const selectedElRef = useRef5(null);
|
|
7511
|
+
const originalContentRef = useRef5(null);
|
|
7512
|
+
const activeStateElRef = useRef5(null);
|
|
7513
|
+
const parentScrollRef = useRef5(null);
|
|
7514
|
+
const visibleViewportRef = useRef5(null);
|
|
7515
|
+
const [dialogPortalContainer, setDialogPortalContainer] = useState6(null);
|
|
7516
|
+
const attachVisibleViewport = useCallback4((node) => {
|
|
6362
7517
|
visibleViewportRef.current = node;
|
|
6363
7518
|
setDialogPortalContainer(node);
|
|
6364
7519
|
if (node) applyVisibleViewport(node, parentScrollRef.current);
|
|
6365
7520
|
}, []);
|
|
6366
|
-
const toolbarElRef =
|
|
6367
|
-
const glowElRef =
|
|
6368
|
-
const hoveredImageRef =
|
|
6369
|
-
const hoveredImageHasTextOverlapRef =
|
|
6370
|
-
const
|
|
6371
|
-
const
|
|
6372
|
-
const
|
|
6373
|
-
const
|
|
6374
|
-
const
|
|
7521
|
+
const toolbarElRef = useRef5(null);
|
|
7522
|
+
const glowElRef = useRef5(null);
|
|
7523
|
+
const hoveredImageRef = useRef5(null);
|
|
7524
|
+
const hoveredImageHasTextOverlapRef = useRef5(false);
|
|
7525
|
+
const dragOverElRef = useRef5(null);
|
|
7526
|
+
const [mediaHover, setMediaHover] = useState6(null);
|
|
7527
|
+
const [uploadingRects, setUploadingRects] = useState6({});
|
|
7528
|
+
const hoveredGapRef = useRef5(null);
|
|
7529
|
+
const imageUnhoverTimerRef = useRef5(null);
|
|
7530
|
+
const imageShowTimerRef = useRef5(null);
|
|
7531
|
+
const editStylesRef = useRef5(null);
|
|
7532
|
+
const activateRef = useRef5(() => {
|
|
6375
7533
|
});
|
|
6376
|
-
const deactivateRef =
|
|
7534
|
+
const deactivateRef = useRef5(() => {
|
|
6377
7535
|
});
|
|
6378
|
-
const selectRef =
|
|
7536
|
+
const selectRef = useRef5(() => {
|
|
6379
7537
|
});
|
|
6380
|
-
const
|
|
7538
|
+
const selectFrameRef = useRef5(() => {
|
|
6381
7539
|
});
|
|
6382
|
-
const
|
|
7540
|
+
const deselectRef = useRef5(() => {
|
|
6383
7541
|
});
|
|
6384
|
-
const
|
|
7542
|
+
const reselectNavigationItemRef = useRef5(() => {
|
|
6385
7543
|
});
|
|
6386
|
-
const
|
|
7544
|
+
const commitNavigationTextEditRef = useRef5(() => {
|
|
6387
7545
|
});
|
|
6388
|
-
const
|
|
6389
|
-
|
|
6390
|
-
const
|
|
6391
|
-
|
|
6392
|
-
const
|
|
6393
|
-
const
|
|
6394
|
-
const
|
|
7546
|
+
const refreshActiveCommandsRef = useRef5(() => {
|
|
7547
|
+
});
|
|
7548
|
+
const postToParentRef = useRef5(postToParent2);
|
|
7549
|
+
postToParentRef.current = postToParent2;
|
|
7550
|
+
const sectionsLoadedRef = useRef5(false);
|
|
7551
|
+
const pendingScheduleConfigRequests = useRef5([]);
|
|
7552
|
+
const [toolbarRect, setToolbarRect] = useState6(null);
|
|
7553
|
+
const [toolbarVariant, setToolbarVariant] = useState6("none");
|
|
7554
|
+
const toolbarVariantRef = useRef5("none");
|
|
6395
7555
|
toolbarVariantRef.current = toolbarVariant;
|
|
6396
|
-
const [reorderHrefKey, setReorderHrefKey] =
|
|
6397
|
-
const [reorderDragDisabled, setReorderDragDisabled] =
|
|
6398
|
-
const [toggleState, setToggleState] =
|
|
6399
|
-
const [maxBadge, setMaxBadge] =
|
|
6400
|
-
const [activeCommands, setActiveCommands] =
|
|
6401
|
-
const [sectionGap, setSectionGap] =
|
|
6402
|
-
const [toolbarShowEditLink, setToolbarShowEditLink] =
|
|
6403
|
-
const
|
|
6404
|
-
const [
|
|
6405
|
-
const
|
|
6406
|
-
const [
|
|
6407
|
-
const
|
|
6408
|
-
const [
|
|
6409
|
-
const [
|
|
6410
|
-
const [
|
|
6411
|
-
const
|
|
6412
|
-
const
|
|
6413
|
-
const
|
|
6414
|
-
const
|
|
6415
|
-
const
|
|
7556
|
+
const [reorderHrefKey, setReorderHrefKey] = useState6(null);
|
|
7557
|
+
const [reorderDragDisabled, setReorderDragDisabled] = useState6(false);
|
|
7558
|
+
const [toggleState, setToggleState] = useState6(null);
|
|
7559
|
+
const [maxBadge, setMaxBadge] = useState6(null);
|
|
7560
|
+
const [activeCommands, setActiveCommands] = useState6(/* @__PURE__ */ new Set());
|
|
7561
|
+
const [sectionGap, setSectionGap] = useState6(null);
|
|
7562
|
+
const [toolbarShowEditLink, setToolbarShowEditLink] = useState6(false);
|
|
7563
|
+
const hoveredNavContainerRef = useRef5(null);
|
|
7564
|
+
const [hoveredNavContainerRect, setHoveredNavContainerRect] = useState6(null);
|
|
7565
|
+
const hoveredItemElRef = useRef5(null);
|
|
7566
|
+
const [hoveredItemRect, setHoveredItemRect] = useState6(null);
|
|
7567
|
+
const siblingHintElRef = useRef5(null);
|
|
7568
|
+
const [siblingHintRect, setSiblingHintRect] = useState6(null);
|
|
7569
|
+
const [isItemDragging, setIsItemDragging] = useState6(false);
|
|
7570
|
+
const [linkPopover, setLinkPopover] = useState6(null);
|
|
7571
|
+
const linkPopoverSessionRef = useRef5(null);
|
|
7572
|
+
const addNavAfterAnchorRef = useRef5(null);
|
|
7573
|
+
const editContentRef = useRef5({});
|
|
7574
|
+
const [sitePages, setSitePages] = useState6([]);
|
|
7575
|
+
const [sectionsByPath, setSectionsByPath] = useState6({});
|
|
7576
|
+
const sectionsPrefetchGenRef = useRef5(0);
|
|
7577
|
+
const setLinkPopoverRef = useRef5(setLinkPopover);
|
|
7578
|
+
const linkPopoverPanelRef = useRef5(null);
|
|
7579
|
+
const linkPopoverOpenRef = useRef5(false);
|
|
7580
|
+
const linkPopoverGraceUntilRef = useRef5(0);
|
|
6416
7581
|
setLinkPopoverRef.current = setLinkPopover;
|
|
7582
|
+
linkPopoverSessionRef.current = linkPopover;
|
|
6417
7583
|
const bumpLinkPopoverGrace = () => {
|
|
6418
7584
|
linkPopoverGraceUntilRef.current = Date.now() + 350;
|
|
6419
7585
|
};
|
|
6420
|
-
const runSectionsPrefetch =
|
|
7586
|
+
const runSectionsPrefetch = useCallback4((pages) => {
|
|
6421
7587
|
if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
|
|
6422
7588
|
const gen = ++sectionsPrefetchGenRef.current;
|
|
6423
7589
|
const paths = pages.map((p) => p.path);
|
|
@@ -6436,9 +7602,9 @@ function OhhwellsBridge() {
|
|
|
6436
7602
|
);
|
|
6437
7603
|
});
|
|
6438
7604
|
}, [isEditMode, pathname]);
|
|
6439
|
-
const runSectionsPrefetchRef =
|
|
7605
|
+
const runSectionsPrefetchRef = useRef5(runSectionsPrefetch);
|
|
6440
7606
|
runSectionsPrefetchRef.current = runSectionsPrefetch;
|
|
6441
|
-
|
|
7607
|
+
useEffect7(() => {
|
|
6442
7608
|
if (!linkPopover) return;
|
|
6443
7609
|
if (hoveredImageRef.current) {
|
|
6444
7610
|
hoveredImageRef.current = null;
|
|
@@ -6446,33 +7612,9 @@ function OhhwellsBridge() {
|
|
|
6446
7612
|
}
|
|
6447
7613
|
hoveredGapRef.current = null;
|
|
6448
7614
|
setSectionGap(null);
|
|
6449
|
-
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
const body = document.body;
|
|
6453
|
-
const prevHtmlOverflow = html.style.overflow;
|
|
6454
|
-
const prevBodyOverflow = body.style.overflow;
|
|
6455
|
-
html.style.overflow = "hidden";
|
|
6456
|
-
body.style.overflow = "hidden";
|
|
6457
|
-
const preventBackgroundScroll = (e) => {
|
|
6458
|
-
const target = e.target;
|
|
6459
|
-
if (target instanceof Element && target.closest('[data-ohw-link-modal-root], [data-slot="dialog-overlay"]')) {
|
|
6460
|
-
return;
|
|
6461
|
-
}
|
|
6462
|
-
e.preventDefault();
|
|
6463
|
-
};
|
|
6464
|
-
const scrollOpts = { passive: false, capture: true };
|
|
6465
|
-
document.addEventListener("wheel", preventBackgroundScroll, scrollOpts);
|
|
6466
|
-
document.addEventListener("touchmove", preventBackgroundScroll, scrollOpts);
|
|
6467
|
-
return () => {
|
|
6468
|
-
postToParent({ type: "ow:link-modal-lock", locked: false });
|
|
6469
|
-
html.style.overflow = prevHtmlOverflow;
|
|
6470
|
-
body.style.overflow = prevBodyOverflow;
|
|
6471
|
-
document.removeEventListener("wheel", preventBackgroundScroll, scrollOpts);
|
|
6472
|
-
document.removeEventListener("touchmove", preventBackgroundScroll, scrollOpts);
|
|
6473
|
-
};
|
|
6474
|
-
}, [linkPopover, postToParent]);
|
|
6475
|
-
useEffect3(() => {
|
|
7615
|
+
postToParent2({ type: "ow:image-unhover" });
|
|
7616
|
+
}, [linkPopover, postToParent2]);
|
|
7617
|
+
useEffect7(() => {
|
|
6476
7618
|
if (!isEditMode) return;
|
|
6477
7619
|
const useFixtures = shouldUseDevFixtures();
|
|
6478
7620
|
if (useFixtures) {
|
|
@@ -6493,17 +7635,17 @@ function OhhwellsBridge() {
|
|
|
6493
7635
|
runSectionsPrefetchRef.current(mapped);
|
|
6494
7636
|
};
|
|
6495
7637
|
window.addEventListener("message", onSitePages);
|
|
6496
|
-
if (!useFixtures)
|
|
7638
|
+
if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
|
|
6497
7639
|
return () => window.removeEventListener("message", onSitePages);
|
|
6498
|
-
}, [isEditMode,
|
|
6499
|
-
|
|
7640
|
+
}, [isEditMode, postToParent2]);
|
|
7641
|
+
useEffect7(() => {
|
|
6500
7642
|
if (!isEditMode || shouldUseDevFixtures()) return;
|
|
6501
7643
|
void loadAllSectionsManifest().then((manifest) => {
|
|
6502
7644
|
if (Object.keys(manifest).length === 0) return;
|
|
6503
7645
|
setSectionsByPath((prev) => ({ ...manifest, ...prev }));
|
|
6504
7646
|
});
|
|
6505
7647
|
}, [isEditMode]);
|
|
6506
|
-
|
|
7648
|
+
useEffect7(() => {
|
|
6507
7649
|
const update = () => {
|
|
6508
7650
|
const el = activeElRef.current ?? selectedElRef.current;
|
|
6509
7651
|
if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
|
|
@@ -6527,10 +7669,10 @@ function OhhwellsBridge() {
|
|
|
6527
7669
|
vvp.removeEventListener("resize", update);
|
|
6528
7670
|
};
|
|
6529
7671
|
}, []);
|
|
6530
|
-
const refreshStateRules =
|
|
7672
|
+
const refreshStateRules = useCallback4(() => {
|
|
6531
7673
|
editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
|
|
6532
7674
|
}, []);
|
|
6533
|
-
const processConfigRequest =
|
|
7675
|
+
const processConfigRequest = useCallback4((insertAfterVal) => {
|
|
6534
7676
|
const tracker = getSectionsTracker();
|
|
6535
7677
|
let entries = [];
|
|
6536
7678
|
try {
|
|
@@ -6553,7 +7695,7 @@ function OhhwellsBridge() {
|
|
|
6553
7695
|
}
|
|
6554
7696
|
window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
|
|
6555
7697
|
}, [isEditMode]);
|
|
6556
|
-
const deactivate =
|
|
7698
|
+
const deactivate = useCallback4(() => {
|
|
6557
7699
|
const el = activeElRef.current;
|
|
6558
7700
|
if (!el) return;
|
|
6559
7701
|
const key = el.dataset.ohwKey;
|
|
@@ -6582,21 +7724,23 @@ function OhhwellsBridge() {
|
|
|
6582
7724
|
setMaxBadge(null);
|
|
6583
7725
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
6584
7726
|
setToolbarShowEditLink(false);
|
|
6585
|
-
|
|
6586
|
-
}, [
|
|
6587
|
-
const deselect =
|
|
7727
|
+
postToParent2({ type: "ow:exit-edit" });
|
|
7728
|
+
}, [postToParent2]);
|
|
7729
|
+
const deselect = useCallback4(() => {
|
|
6588
7730
|
selectedElRef.current = null;
|
|
6589
7731
|
setReorderHrefKey(null);
|
|
6590
7732
|
setReorderDragDisabled(false);
|
|
6591
7733
|
siblingHintElRef.current = null;
|
|
6592
7734
|
setSiblingHintRect(null);
|
|
6593
7735
|
setIsItemDragging(false);
|
|
7736
|
+
hoveredNavContainerRef.current = null;
|
|
7737
|
+
setHoveredNavContainerRect(null);
|
|
6594
7738
|
if (!activeElRef.current) {
|
|
6595
7739
|
setToolbarRect(null);
|
|
6596
7740
|
setToolbarVariant("none");
|
|
6597
7741
|
}
|
|
6598
7742
|
}, []);
|
|
6599
|
-
const reselectNavigationItem =
|
|
7743
|
+
const reselectNavigationItem = useCallback4((navAnchor) => {
|
|
6600
7744
|
selectedElRef.current = navAnchor;
|
|
6601
7745
|
const { key, disabled } = getNavigationItemReorderState(navAnchor);
|
|
6602
7746
|
setReorderHrefKey(key);
|
|
@@ -6606,7 +7750,7 @@ function OhhwellsBridge() {
|
|
|
6606
7750
|
setToolbarShowEditLink(false);
|
|
6607
7751
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
6608
7752
|
}, []);
|
|
6609
|
-
const commitNavigationTextEdit =
|
|
7753
|
+
const commitNavigationTextEdit = useCallback4((navAnchor) => {
|
|
6610
7754
|
const el = activeElRef.current;
|
|
6611
7755
|
if (!el) return;
|
|
6612
7756
|
const key = el.dataset.ohwKey;
|
|
@@ -6619,9 +7763,9 @@ function OhhwellsBridge() {
|
|
|
6619
7763
|
const html = sanitizeHtml(el.innerHTML);
|
|
6620
7764
|
const original = originalContentRef.current ?? "";
|
|
6621
7765
|
if (html !== sanitizeHtml(original)) {
|
|
6622
|
-
|
|
7766
|
+
postToParent2({ type: "ow:change", nodes: [{ key, text: html }] });
|
|
6623
7767
|
const h = document.documentElement.scrollHeight;
|
|
6624
|
-
if (h > 50)
|
|
7768
|
+
if (h > 50) postToParent2({ type: "ow:height", height: h });
|
|
6625
7769
|
}
|
|
6626
7770
|
}
|
|
6627
7771
|
el.removeAttribute("contenteditable");
|
|
@@ -6629,31 +7773,38 @@ function OhhwellsBridge() {
|
|
|
6629
7773
|
setMaxBadge(null);
|
|
6630
7774
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
6631
7775
|
setToolbarShowEditLink(false);
|
|
6632
|
-
|
|
7776
|
+
postToParent2({ type: "ow:exit-edit" });
|
|
6633
7777
|
reselectNavigationItem(navAnchor);
|
|
6634
|
-
}, [
|
|
6635
|
-
const
|
|
6636
|
-
const
|
|
6637
|
-
|
|
6638
|
-
|
|
6639
|
-
|
|
6640
|
-
|
|
7778
|
+
}, [postToParent2, reselectNavigationItem]);
|
|
7779
|
+
const handleAddTopLevelNavItem = useCallback4(() => {
|
|
7780
|
+
const items = listNavbarItems();
|
|
7781
|
+
addNavAfterAnchorRef.current = items[items.length - 1] ?? null;
|
|
7782
|
+
deselectRef.current();
|
|
7783
|
+
deactivateRef.current();
|
|
7784
|
+
bumpLinkPopoverGrace();
|
|
7785
|
+
setLinkPopover({
|
|
7786
|
+
key: "__add-nav__",
|
|
7787
|
+
mode: "create",
|
|
7788
|
+
intent: "add-nav"
|
|
7789
|
+
});
|
|
6641
7790
|
}, []);
|
|
6642
|
-
const handleItemDragStart =
|
|
7791
|
+
const handleItemDragStart = useCallback4(() => {
|
|
6643
7792
|
siblingHintElRef.current = null;
|
|
6644
7793
|
setSiblingHintRect(null);
|
|
6645
7794
|
setIsItemDragging(true);
|
|
6646
7795
|
}, []);
|
|
6647
|
-
const handleItemDragEnd =
|
|
7796
|
+
const handleItemDragEnd = useCallback4(() => {
|
|
6648
7797
|
setIsItemDragging(false);
|
|
6649
7798
|
}, []);
|
|
6650
7799
|
reselectNavigationItemRef.current = reselectNavigationItem;
|
|
6651
7800
|
commitNavigationTextEditRef.current = commitNavigationTextEdit;
|
|
6652
|
-
const select =
|
|
7801
|
+
const select = useCallback4((anchor) => {
|
|
6653
7802
|
if (!isNavigationItem(anchor)) return;
|
|
6654
7803
|
if (activeElRef.current) deactivate();
|
|
6655
7804
|
selectedElRef.current = anchor;
|
|
6656
7805
|
clearHrefKeyHover(anchor);
|
|
7806
|
+
hoveredNavContainerRef.current = null;
|
|
7807
|
+
setHoveredNavContainerRect(null);
|
|
6657
7808
|
setHoveredItemRect(null);
|
|
6658
7809
|
hoveredItemElRef.current = null;
|
|
6659
7810
|
siblingHintElRef.current = null;
|
|
@@ -6667,13 +7818,32 @@ function OhhwellsBridge() {
|
|
|
6667
7818
|
setToolbarShowEditLink(false);
|
|
6668
7819
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
6669
7820
|
}, [deactivate]);
|
|
6670
|
-
const
|
|
7821
|
+
const selectFrame = useCallback4((el) => {
|
|
7822
|
+
if (!isNavigationContainer(el)) return;
|
|
7823
|
+
if (activeElRef.current) deactivate();
|
|
7824
|
+
selectedElRef.current = el;
|
|
7825
|
+
clearHrefKeyHover(el);
|
|
7826
|
+
hoveredNavContainerRef.current = null;
|
|
7827
|
+
setHoveredNavContainerRect(null);
|
|
7828
|
+
setHoveredItemRect(null);
|
|
7829
|
+
hoveredItemElRef.current = null;
|
|
7830
|
+
siblingHintElRef.current = null;
|
|
7831
|
+
setSiblingHintRect(null);
|
|
7832
|
+
setIsItemDragging(false);
|
|
7833
|
+
setReorderHrefKey(null);
|
|
7834
|
+
setReorderDragDisabled(false);
|
|
7835
|
+
setToolbarVariant("select-frame");
|
|
7836
|
+
setToolbarRect(el.getBoundingClientRect());
|
|
7837
|
+
setToolbarShowEditLink(false);
|
|
7838
|
+
setActiveCommands(/* @__PURE__ */ new Set());
|
|
7839
|
+
}, [deactivate]);
|
|
7840
|
+
const activate = useCallback4((el, options) => {
|
|
6671
7841
|
if (activeElRef.current === el) return;
|
|
6672
7842
|
selectedElRef.current = null;
|
|
6673
7843
|
deactivate();
|
|
6674
7844
|
if (hoveredImageRef.current) {
|
|
6675
7845
|
hoveredImageRef.current = null;
|
|
6676
|
-
|
|
7846
|
+
setMediaHover(null);
|
|
6677
7847
|
}
|
|
6678
7848
|
setToolbarVariant("rich-text");
|
|
6679
7849
|
siblingHintElRef.current = null;
|
|
@@ -6685,6 +7855,9 @@ function OhhwellsBridge() {
|
|
|
6685
7855
|
activeElRef.current = el;
|
|
6686
7856
|
originalContentRef.current = el.innerHTML;
|
|
6687
7857
|
el.focus();
|
|
7858
|
+
if (options?.caretX !== void 0 && options?.caretY !== void 0) {
|
|
7859
|
+
placeCaretAtPoint(el, options.caretX, options.caretY);
|
|
7860
|
+
}
|
|
6688
7861
|
setToolbarShowEditLink(Boolean(getHrefKeyFromElement(el)));
|
|
6689
7862
|
const navAnchor = getNavigationItemAnchor(el);
|
|
6690
7863
|
if (navAnchor) {
|
|
@@ -6696,12 +7869,13 @@ function OhhwellsBridge() {
|
|
|
6696
7869
|
setReorderDragDisabled(reorderDisabled);
|
|
6697
7870
|
}
|
|
6698
7871
|
setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
|
|
6699
|
-
|
|
7872
|
+
postToParent2({ type: "ow:enter-edit", key: el.dataset.ohwKey });
|
|
6700
7873
|
requestAnimationFrame(() => refreshActiveCommandsRef.current());
|
|
6701
|
-
}, [deactivate,
|
|
7874
|
+
}, [deactivate, postToParent2]);
|
|
6702
7875
|
activateRef.current = activate;
|
|
6703
7876
|
deactivateRef.current = deactivate;
|
|
6704
7877
|
selectRef.current = select;
|
|
7878
|
+
selectFrameRef.current = selectFrame;
|
|
6705
7879
|
deselectRef.current = deselect;
|
|
6706
7880
|
useLayoutEffect2(() => {
|
|
6707
7881
|
if (!subdomain || isEditMode) {
|
|
@@ -6712,6 +7886,7 @@ function OhhwellsBridge() {
|
|
|
6712
7886
|
const imageLoads = [];
|
|
6713
7887
|
for (const [key, val] of Object.entries(content)) {
|
|
6714
7888
|
if (key === "__ohw_sections") continue;
|
|
7889
|
+
if (applyVideoSettingNode(key, val)) continue;
|
|
6715
7890
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
6716
7891
|
if (el.dataset.ohwEditable === "image") {
|
|
6717
7892
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
@@ -6725,6 +7900,15 @@ function OhhwellsBridge() {
|
|
|
6725
7900
|
} else if (el.dataset.ohwEditable === "bg-image") {
|
|
6726
7901
|
const next = `url('${val}')`;
|
|
6727
7902
|
if (el.style.backgroundImage !== next) el.style.backgroundImage = next;
|
|
7903
|
+
} else if (el.dataset.ohwEditable === "video") {
|
|
7904
|
+
const video = getVideoEl(el);
|
|
7905
|
+
if (video && video.src !== val) {
|
|
7906
|
+
applyVideoSrc(video, val);
|
|
7907
|
+
imageLoads.push(new Promise((resolve) => {
|
|
7908
|
+
video.onloadeddata = () => resolve();
|
|
7909
|
+
video.onerror = () => resolve();
|
|
7910
|
+
}));
|
|
7911
|
+
}
|
|
6728
7912
|
} else if (el.dataset.ohwEditable === "link") {
|
|
6729
7913
|
applyLinkHref(el, val);
|
|
6730
7914
|
} else if (el.innerHTML !== val) {
|
|
@@ -6733,6 +7917,7 @@ function OhhwellsBridge() {
|
|
|
6733
7917
|
});
|
|
6734
7918
|
applyLinkByKey(key, val);
|
|
6735
7919
|
}
|
|
7920
|
+
reconcileNavbarItemsFromContent(content);
|
|
6736
7921
|
enforceLinkHrefs();
|
|
6737
7922
|
initSectionsFromContent(content, true);
|
|
6738
7923
|
sectionsLoadedRef.current = true;
|
|
@@ -6761,7 +7946,7 @@ function OhhwellsBridge() {
|
|
|
6761
7946
|
cancelled = true;
|
|
6762
7947
|
};
|
|
6763
7948
|
}, [subdomain, isEditMode]);
|
|
6764
|
-
|
|
7949
|
+
useEffect7(() => {
|
|
6765
7950
|
if (!subdomain || isEditMode) return;
|
|
6766
7951
|
let debounceTimer = null;
|
|
6767
7952
|
let observer = null;
|
|
@@ -6773,6 +7958,7 @@ function OhhwellsBridge() {
|
|
|
6773
7958
|
try {
|
|
6774
7959
|
for (const [key, val] of Object.entries(content)) {
|
|
6775
7960
|
if (key === "__ohw_sections") continue;
|
|
7961
|
+
if (applyVideoSettingNode(key, val)) continue;
|
|
6776
7962
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
6777
7963
|
if (el.dataset.ohwEditable === "image") {
|
|
6778
7964
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
@@ -6780,6 +7966,9 @@ function OhhwellsBridge() {
|
|
|
6780
7966
|
} else if (el.dataset.ohwEditable === "bg-image") {
|
|
6781
7967
|
const next = `url('${val}')`;
|
|
6782
7968
|
if (el.style.backgroundImage !== next) el.style.backgroundImage = next;
|
|
7969
|
+
} else if (el.dataset.ohwEditable === "video") {
|
|
7970
|
+
const video = getVideoEl(el);
|
|
7971
|
+
if (video && video.src !== val) applyVideoSrc(video, val);
|
|
6783
7972
|
} else if (el.dataset.ohwEditable === "link") {
|
|
6784
7973
|
applyLinkHref(el, val);
|
|
6785
7974
|
} else if (el.innerHTML !== val) {
|
|
@@ -6788,6 +7977,7 @@ function OhhwellsBridge() {
|
|
|
6788
7977
|
});
|
|
6789
7978
|
applyLinkByKey(key, val);
|
|
6790
7979
|
}
|
|
7980
|
+
reconcileNavbarItemsFromContent(content);
|
|
6791
7981
|
} finally {
|
|
6792
7982
|
observer?.observe(document.body, { childList: true, subtree: true });
|
|
6793
7983
|
}
|
|
@@ -6811,20 +8001,38 @@ function OhhwellsBridge() {
|
|
|
6811
8001
|
const visible = Boolean(subdomain) && fetchState !== "done";
|
|
6812
8002
|
el.style.display = visible ? "flex" : "none";
|
|
6813
8003
|
}, [subdomain, fetchState]);
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
}, [pathname,
|
|
6817
|
-
|
|
8004
|
+
useEffect7(() => {
|
|
8005
|
+
postToParent2({ type: "ow:navigation", path: pathname });
|
|
8006
|
+
}, [pathname, postToParent2]);
|
|
8007
|
+
useEffect7(() => {
|
|
6818
8008
|
if (!isEditMode) return;
|
|
8009
|
+
if (linkPopoverSessionRef.current?.intent === "add-nav") return;
|
|
8010
|
+
if (document.querySelector("[data-ohw-section-picker]")) return;
|
|
6819
8011
|
setLinkPopover(null);
|
|
6820
8012
|
deselectRef.current();
|
|
6821
8013
|
deactivateRef.current();
|
|
6822
8014
|
}, [pathname, isEditMode]);
|
|
6823
|
-
|
|
8015
|
+
useEffect7(() => {
|
|
8016
|
+
const contentForNav = () => {
|
|
8017
|
+
if (isEditMode) return editContentRef.current;
|
|
8018
|
+
if (!subdomain) return {};
|
|
8019
|
+
return contentCache.get(subdomain) ?? {};
|
|
8020
|
+
};
|
|
8021
|
+
const run = () => reconcileNavbarItemsFromContent(contentForNav());
|
|
8022
|
+
run();
|
|
8023
|
+
const nav = document.querySelector("nav");
|
|
8024
|
+
if (!nav) return;
|
|
8025
|
+
const observer = new MutationObserver(() => {
|
|
8026
|
+
requestAnimationFrame(run);
|
|
8027
|
+
});
|
|
8028
|
+
observer.observe(nav, { childList: true, subtree: true });
|
|
8029
|
+
return () => observer.disconnect();
|
|
8030
|
+
}, [isEditMode, pathname, subdomain, fetchState]);
|
|
8031
|
+
useEffect7(() => {
|
|
6824
8032
|
if (!isEditMode) return;
|
|
6825
8033
|
const measure = () => {
|
|
6826
8034
|
const h = document.body.scrollHeight;
|
|
6827
|
-
if (h > 50)
|
|
8035
|
+
if (h > 50) postToParent2({ type: "ow:height", height: h });
|
|
6828
8036
|
};
|
|
6829
8037
|
const t1 = setTimeout(measure, 50);
|
|
6830
8038
|
const t2 = setTimeout(measure, 500);
|
|
@@ -6843,8 +8051,8 @@ function OhhwellsBridge() {
|
|
|
6843
8051
|
if (resizeTimer) clearTimeout(resizeTimer);
|
|
6844
8052
|
window.removeEventListener("resize", handleResize);
|
|
6845
8053
|
};
|
|
6846
|
-
}, [pathname, isEditMode,
|
|
6847
|
-
|
|
8054
|
+
}, [pathname, isEditMode, postToParent2]);
|
|
8055
|
+
useEffect7(() => {
|
|
6848
8056
|
if (!subdomainFromQuery || isEditMode) return;
|
|
6849
8057
|
const handleClick = (e) => {
|
|
6850
8058
|
const anchor = e.target.closest("a");
|
|
@@ -6860,7 +8068,7 @@ function OhhwellsBridge() {
|
|
|
6860
8068
|
document.addEventListener("click", handleClick, true);
|
|
6861
8069
|
return () => document.removeEventListener("click", handleClick, true);
|
|
6862
8070
|
}, [subdomainFromQuery, isEditMode, router]);
|
|
6863
|
-
|
|
8071
|
+
useEffect7(() => {
|
|
6864
8072
|
if (!isEditMode) {
|
|
6865
8073
|
editStylesRef.current?.base.remove();
|
|
6866
8074
|
editStylesRef.current?.forceHover.remove();
|
|
@@ -6883,8 +8091,9 @@ function OhhwellsBridge() {
|
|
|
6883
8091
|
[data-ohw-editable] {
|
|
6884
8092
|
display: block;
|
|
6885
8093
|
}
|
|
6886
|
-
[data-ohw-editable]:not([contenteditable]):not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]) { cursor: text !important; }
|
|
8094
|
+
[data-ohw-editable]:not([contenteditable]):not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"]) { cursor: text !important; }
|
|
6887
8095
|
[data-ohw-editable="image"], [data-ohw-editable="image"] *,
|
|
8096
|
+
[data-ohw-editable="video"], [data-ohw-editable="video"] *,
|
|
6888
8097
|
[data-ohw-editable="bg-image"], [data-ohw-editable="bg-image"] * { cursor: pointer !important; }
|
|
6889
8098
|
[data-ohw-editable="link"], [data-ohw-editable="link"] * { cursor: pointer !important; }
|
|
6890
8099
|
[data-ohw-hovered]:not([contenteditable]):not([data-ohw-href-key]) {
|
|
@@ -6933,6 +8142,13 @@ function OhhwellsBridge() {
|
|
|
6933
8142
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
6934
8143
|
if (isInsideLinkEditor(target)) return;
|
|
6935
8144
|
if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
|
|
8145
|
+
const navFromChrome = resolveNavContainerSelectionTarget(target, e.clientX, e.clientY);
|
|
8146
|
+
if (navFromChrome) {
|
|
8147
|
+
e.preventDefault();
|
|
8148
|
+
e.stopPropagation();
|
|
8149
|
+
selectFrameRef.current(navFromChrome);
|
|
8150
|
+
return;
|
|
8151
|
+
}
|
|
6936
8152
|
e.preventDefault();
|
|
6937
8153
|
e.stopPropagation();
|
|
6938
8154
|
return;
|
|
@@ -6947,14 +8163,15 @@ function OhhwellsBridge() {
|
|
|
6947
8163
|
bumpLinkPopoverGrace();
|
|
6948
8164
|
setLinkPopoverRef.current({
|
|
6949
8165
|
key: editable.dataset.ohwKey ?? "",
|
|
6950
|
-
|
|
8166
|
+
mode: "edit",
|
|
8167
|
+
target: getLinkHref2(editable)
|
|
6951
8168
|
});
|
|
6952
8169
|
return;
|
|
6953
8170
|
}
|
|
6954
|
-
if (editable
|
|
8171
|
+
if (isMediaEditable(editable)) {
|
|
6955
8172
|
e.preventDefault();
|
|
6956
8173
|
e.stopPropagation();
|
|
6957
|
-
postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "" });
|
|
8174
|
+
postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "", elementType: editable.dataset.ohwEditable ?? "image" });
|
|
6958
8175
|
return;
|
|
6959
8176
|
}
|
|
6960
8177
|
const hrefCtx = getHrefKeyFromElement(editable);
|
|
@@ -6963,7 +8180,8 @@ function OhhwellsBridge() {
|
|
|
6963
8180
|
e.preventDefault();
|
|
6964
8181
|
e.stopPropagation();
|
|
6965
8182
|
if (selectedElRef.current === navAnchor) {
|
|
6966
|
-
|
|
8183
|
+
if (e.detail >= 2) return;
|
|
8184
|
+
activateRef.current(editable, { caretX: e.clientX, caretY: e.clientY });
|
|
6967
8185
|
return;
|
|
6968
8186
|
}
|
|
6969
8187
|
selectRef.current(navAnchor);
|
|
@@ -6982,6 +8200,22 @@ function OhhwellsBridge() {
|
|
|
6982
8200
|
selectRef.current(hrefAnchor);
|
|
6983
8201
|
return;
|
|
6984
8202
|
}
|
|
8203
|
+
const navContainerToSelect = resolveNavContainerSelectionTarget(target, e.clientX, e.clientY);
|
|
8204
|
+
if (navContainerToSelect) {
|
|
8205
|
+
e.preventDefault();
|
|
8206
|
+
e.stopPropagation();
|
|
8207
|
+
selectFrameRef.current(navContainerToSelect);
|
|
8208
|
+
return;
|
|
8209
|
+
}
|
|
8210
|
+
const selectedContainer = selectedElRef.current;
|
|
8211
|
+
if (selectedContainer && isNavigationContainer(selectedContainer)) {
|
|
8212
|
+
const navItem = getNavigationItemAnchor(target);
|
|
8213
|
+
if (!navItem && (selectedContainer === target || selectedContainer.contains(target))) {
|
|
8214
|
+
e.preventDefault();
|
|
8215
|
+
e.stopPropagation();
|
|
8216
|
+
return;
|
|
8217
|
+
}
|
|
8218
|
+
}
|
|
6985
8219
|
if (activeElRef.current) {
|
|
6986
8220
|
const sel = window.getSelection();
|
|
6987
8221
|
if (sel && !sel.isCollapsed) {
|
|
@@ -7007,10 +8241,48 @@ function OhhwellsBridge() {
|
|
|
7007
8241
|
deselectRef.current();
|
|
7008
8242
|
deactivateRef.current();
|
|
7009
8243
|
};
|
|
8244
|
+
const handleDblClick = (e) => {
|
|
8245
|
+
const target = e.target;
|
|
8246
|
+
if (target.closest("[data-ohw-toolbar]")) return;
|
|
8247
|
+
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
8248
|
+
if (target.closest("[data-ohw-max-badge]")) return;
|
|
8249
|
+
if (isInsideLinkEditor(target)) return;
|
|
8250
|
+
if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
|
|
8251
|
+
return;
|
|
8252
|
+
}
|
|
8253
|
+
const navLabel = getNavigationLabelEditable(target);
|
|
8254
|
+
if (!navLabel) return;
|
|
8255
|
+
const { editable } = navLabel;
|
|
8256
|
+
e.preventDefault();
|
|
8257
|
+
e.stopPropagation();
|
|
8258
|
+
if (activeElRef.current !== editable) {
|
|
8259
|
+
activateRef.current(editable);
|
|
8260
|
+
}
|
|
8261
|
+
requestAnimationFrame(() => {
|
|
8262
|
+
selectAllTextInEditable(editable);
|
|
8263
|
+
refreshActiveCommandsRef.current();
|
|
8264
|
+
});
|
|
8265
|
+
};
|
|
7010
8266
|
const handleMouseOver = (e) => {
|
|
7011
8267
|
const target = e.target;
|
|
8268
|
+
if (toolbarVariantRef.current !== "select-frame") {
|
|
8269
|
+
const navContainer = target.closest("[data-ohw-nav-container]");
|
|
8270
|
+
if (navContainer && !getNavigationItemAnchor(target)) {
|
|
8271
|
+
hoveredNavContainerRef.current = navContainer;
|
|
8272
|
+
setHoveredNavContainerRect(navContainer.getBoundingClientRect());
|
|
8273
|
+
hoveredItemElRef.current = null;
|
|
8274
|
+
setHoveredItemRect(null);
|
|
8275
|
+
return;
|
|
8276
|
+
}
|
|
8277
|
+
if (!target.closest("[data-ohw-nav-container]")) {
|
|
8278
|
+
hoveredNavContainerRef.current = null;
|
|
8279
|
+
setHoveredNavContainerRect(null);
|
|
8280
|
+
}
|
|
8281
|
+
}
|
|
7012
8282
|
const navAnchor = getNavigationItemAnchor(target);
|
|
7013
8283
|
if (navAnchor) {
|
|
8284
|
+
hoveredNavContainerRef.current = null;
|
|
8285
|
+
setHoveredNavContainerRect(null);
|
|
7014
8286
|
const selected2 = selectedElRef.current;
|
|
7015
8287
|
if (selected2 === navAnchor || selected2?.contains(navAnchor)) return;
|
|
7016
8288
|
clearHrefKeyHover(navAnchor);
|
|
@@ -7022,7 +8294,7 @@ function OhhwellsBridge() {
|
|
|
7022
8294
|
if (!editable) return;
|
|
7023
8295
|
const selected = selectedElRef.current;
|
|
7024
8296
|
if (selected && (selected === editable || selected.contains(editable))) return;
|
|
7025
|
-
if (editable
|
|
8297
|
+
if (!isMediaEditable(editable) && !editable.hasAttribute("contenteditable")) {
|
|
7026
8298
|
const hoverTarget = editable.closest("[data-ohw-href-key]") ?? editable;
|
|
7027
8299
|
if (hoverTarget.hasAttribute("data-ohw-href-key")) {
|
|
7028
8300
|
clearHrefKeyHover(hoverTarget);
|
|
@@ -7035,6 +8307,14 @@ function OhhwellsBridge() {
|
|
|
7035
8307
|
};
|
|
7036
8308
|
const handleMouseOut = (e) => {
|
|
7037
8309
|
const target = e.target;
|
|
8310
|
+
if (target.closest("[data-ohw-nav-container]")) {
|
|
8311
|
+
const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
8312
|
+
if (related2?.closest("[data-ohw-nav-container], [data-ohw-navbar-container-chrome], [data-ohw-navbar-add-button]")) {
|
|
8313
|
+
return;
|
|
8314
|
+
}
|
|
8315
|
+
hoveredNavContainerRef.current = null;
|
|
8316
|
+
setHoveredNavContainerRect(null);
|
|
8317
|
+
}
|
|
7038
8318
|
const navAnchor = getNavigationItemAnchor(target);
|
|
7039
8319
|
if (navAnchor) {
|
|
7040
8320
|
const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
@@ -7050,7 +8330,7 @@ function OhhwellsBridge() {
|
|
|
7050
8330
|
if (!editable) return;
|
|
7051
8331
|
const related = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
7052
8332
|
if (related?.closest("[data-ohw-drag-handle-container], [data-ohw-item-interaction]")) return;
|
|
7053
|
-
if (editable
|
|
8333
|
+
if (!isMediaEditable(editable)) {
|
|
7054
8334
|
const hoverTarget = editable.closest("[data-ohw-href-key]") ?? editable;
|
|
7055
8335
|
if (hoverTarget.hasAttribute("data-ohw-href-key")) {
|
|
7056
8336
|
if (!related?.closest("[data-ohw-href-key]")) {
|
|
@@ -7096,23 +8376,26 @@ function OhhwellsBridge() {
|
|
|
7096
8376
|
}
|
|
7097
8377
|
return { top, left, width: Math.max(0, right - left), height: Math.max(0, bottom - top) };
|
|
7098
8378
|
};
|
|
7099
|
-
const
|
|
8379
|
+
const showImageHover = (imgEl, isDragOver = false, forceTextOverlap) => {
|
|
7100
8380
|
const r2 = getVisibleRect(imgEl);
|
|
7101
8381
|
const hasTextOverlap = forceTextOverlap ?? false;
|
|
7102
8382
|
hoveredImageHasTextOverlapRef.current = hasTextOverlap;
|
|
7103
|
-
|
|
7104
|
-
|
|
8383
|
+
const video = imgEl.dataset.ohwEditable === "video" ? getVideoEl(imgEl) : null;
|
|
8384
|
+
setMediaHover({
|
|
7105
8385
|
key: imgEl.dataset.ohwKey ?? "",
|
|
7106
8386
|
rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height },
|
|
8387
|
+
elementType: imgEl.dataset.ohwEditable ?? "image",
|
|
7107
8388
|
hasTextOverlap,
|
|
7108
|
-
|
|
8389
|
+
isDragOver,
|
|
8390
|
+
...video ? { videoAutoplay: video.autoplay, videoMuted: video.muted } : {}
|
|
7109
8391
|
});
|
|
7110
8392
|
const track = imgEl.closest("[data-ohw-hover-pause]");
|
|
7111
8393
|
if (track) track.setAttribute("data-ohw-hover-paused", "");
|
|
7112
8394
|
};
|
|
8395
|
+
const clearImageHover = () => setMediaHover(null);
|
|
7113
8396
|
const findImageAtPoint = (clientX, clientY, fromParentViewport) => {
|
|
7114
8397
|
const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
7115
|
-
const images = Array.from(document.querySelectorAll(
|
|
8398
|
+
const images = Array.from(document.querySelectorAll(MEDIA_SELECTOR));
|
|
7116
8399
|
const matches = [];
|
|
7117
8400
|
for (let i = images.length - 1; i >= 0; i--) {
|
|
7118
8401
|
const el = images[i];
|
|
@@ -7128,7 +8411,9 @@ function OhhwellsBridge() {
|
|
|
7128
8411
|
if (x >= r2.left && x <= r2.left + r2.width && y >= r2.top && y <= r2.top + r2.height) matches.push(el);
|
|
7129
8412
|
}
|
|
7130
8413
|
if (matches.length === 0) return null;
|
|
7131
|
-
const imageTypeMatches = matches.filter(
|
|
8414
|
+
const imageTypeMatches = matches.filter(
|
|
8415
|
+
(el) => el.dataset.ohwEditable === "image" || el.dataset.ohwEditable === "video"
|
|
8416
|
+
);
|
|
7132
8417
|
const candidatePool = imageTypeMatches.length > 0 ? imageTypeMatches : matches;
|
|
7133
8418
|
const smallest = candidatePool.reduce((best, el) => {
|
|
7134
8419
|
const br = getVisibleRect(best);
|
|
@@ -7151,47 +8436,91 @@ function OhhwellsBridge() {
|
|
|
7151
8436
|
}
|
|
7152
8437
|
return smallest;
|
|
7153
8438
|
};
|
|
8439
|
+
const dismissImageHover = () => {
|
|
8440
|
+
if (hoveredImageRef.current) {
|
|
8441
|
+
hoveredImageRef.current = null;
|
|
8442
|
+
hoveredImageHasTextOverlapRef.current = false;
|
|
8443
|
+
resumeAnimTracks();
|
|
8444
|
+
postToParentRef.current({ type: "ow:image-unhover" });
|
|
8445
|
+
}
|
|
8446
|
+
clearImageHover();
|
|
8447
|
+
};
|
|
8448
|
+
const probeNavigationHoverAt = (x, y) => {
|
|
8449
|
+
if (toolbarVariantRef.current === "select-frame") {
|
|
8450
|
+
hoveredNavContainerRef.current = null;
|
|
8451
|
+
setHoveredNavContainerRect(null);
|
|
8452
|
+
return;
|
|
8453
|
+
}
|
|
8454
|
+
const navContainer = document.querySelector("[data-ohw-nav-container]");
|
|
8455
|
+
if (!navContainer) {
|
|
8456
|
+
hoveredNavContainerRef.current = null;
|
|
8457
|
+
setHoveredNavContainerRect(null);
|
|
8458
|
+
return;
|
|
8459
|
+
}
|
|
8460
|
+
const containerRect = navContainer.getBoundingClientRect();
|
|
8461
|
+
const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
|
|
8462
|
+
if (!overContainer) {
|
|
8463
|
+
hoveredNavContainerRef.current = null;
|
|
8464
|
+
setHoveredNavContainerRect(null);
|
|
8465
|
+
return;
|
|
8466
|
+
}
|
|
8467
|
+
const navItemHit = Array.from(
|
|
8468
|
+
navContainer.querySelectorAll("[data-ohw-href-key]")
|
|
8469
|
+
).find((el) => {
|
|
8470
|
+
if (!isNavigationItem(el) || isNavbarButton2(el)) return false;
|
|
8471
|
+
const itemRect = el.getBoundingClientRect();
|
|
8472
|
+
return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
|
|
8473
|
+
});
|
|
8474
|
+
if (navItemHit) {
|
|
8475
|
+
hoveredNavContainerRef.current = null;
|
|
8476
|
+
setHoveredNavContainerRect(null);
|
|
8477
|
+
const selected = selectedElRef.current;
|
|
8478
|
+
if (selected !== navItemHit && !selected?.contains(navItemHit)) {
|
|
8479
|
+
clearHrefKeyHover(navItemHit);
|
|
8480
|
+
hoveredItemElRef.current = navItemHit;
|
|
8481
|
+
setHoveredItemRect(navItemHit.getBoundingClientRect());
|
|
8482
|
+
}
|
|
8483
|
+
return;
|
|
8484
|
+
}
|
|
8485
|
+
hoveredNavContainerRef.current = navContainer;
|
|
8486
|
+
setHoveredNavContainerRect(containerRect);
|
|
8487
|
+
hoveredItemElRef.current = null;
|
|
8488
|
+
setHoveredItemRect(null);
|
|
8489
|
+
};
|
|
7154
8490
|
const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
|
|
7155
8491
|
if (linkPopoverOpenRef.current) {
|
|
7156
|
-
|
|
7157
|
-
hoveredImageRef.current = null;
|
|
7158
|
-
hoveredImageHasTextOverlapRef.current = false;
|
|
7159
|
-
resumeAnimTracks();
|
|
7160
|
-
postToParentRef.current({ type: "ow:image-unhover" });
|
|
7161
|
-
}
|
|
8492
|
+
dismissImageHover();
|
|
7162
8493
|
return;
|
|
7163
8494
|
}
|
|
8495
|
+
const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
8496
|
+
if (isPointOverNavigation(x, y)) {
|
|
8497
|
+
dismissImageHover();
|
|
8498
|
+
probeNavigationHoverAt(x, y);
|
|
8499
|
+
return;
|
|
8500
|
+
}
|
|
8501
|
+
hoveredNavContainerRef.current = null;
|
|
8502
|
+
setHoveredNavContainerRect(null);
|
|
7164
8503
|
const toggleEl = document.querySelector("[data-ohw-state-toggle]");
|
|
7165
8504
|
if (toggleEl) {
|
|
7166
|
-
const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
7167
8505
|
const tr = toggleEl.getBoundingClientRect();
|
|
7168
8506
|
if (x >= tr.left && x <= tr.right && y >= tr.top && y <= tr.bottom) {
|
|
7169
|
-
|
|
7170
|
-
hoveredImageRef.current = null;
|
|
7171
|
-
resumeAnimTracks();
|
|
7172
|
-
postToParentRef.current({ type: "ow:image-unhover" });
|
|
7173
|
-
}
|
|
8507
|
+
dismissImageHover();
|
|
7174
8508
|
return;
|
|
7175
8509
|
}
|
|
7176
8510
|
}
|
|
7177
|
-
|
|
7178
|
-
|
|
7179
|
-
|
|
7180
|
-
|
|
7181
|
-
resumeAnimTracks();
|
|
7182
|
-
postToParentRef.current({ type: "ow:image-unhover" });
|
|
7183
|
-
}
|
|
8511
|
+
const imgEl = findImageAtPoint(clientX, clientY, fromParentViewport);
|
|
8512
|
+
const activeEl = activeElRef.current;
|
|
8513
|
+
if (activeEl && (!imgEl || imgEl.contains(activeEl))) {
|
|
8514
|
+
dismissImageHover();
|
|
7184
8515
|
return;
|
|
7185
8516
|
}
|
|
7186
|
-
const imgEl = findImageAtPoint(clientX, clientY, fromParentViewport);
|
|
7187
8517
|
if (imgEl) {
|
|
7188
|
-
const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
7189
8518
|
const topEl = document.elementFromPoint(x, y);
|
|
7190
8519
|
if (topEl?.closest('[data-ohw-toolbar], [data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
|
|
7191
8520
|
if (hoveredImageRef.current) {
|
|
7192
8521
|
hoveredImageRef.current = null;
|
|
7193
8522
|
resumeAnimTracks();
|
|
7194
|
-
|
|
8523
|
+
clearImageHover();
|
|
7195
8524
|
}
|
|
7196
8525
|
return;
|
|
7197
8526
|
}
|
|
@@ -7200,13 +8529,13 @@ function OhhwellsBridge() {
|
|
|
7200
8529
|
hoveredImageRef.current = null;
|
|
7201
8530
|
hoveredImageHasTextOverlapRef.current = false;
|
|
7202
8531
|
resumeAnimTracks();
|
|
7203
|
-
|
|
8532
|
+
clearImageHover();
|
|
7204
8533
|
}
|
|
7205
8534
|
return;
|
|
7206
8535
|
}
|
|
7207
8536
|
const isStateCardImage = !!imgEl.closest("[data-ohw-editable-state]");
|
|
7208
8537
|
const textEditable = Array.from(
|
|
7209
|
-
document.querySelectorAll(
|
|
8538
|
+
document.querySelectorAll(NON_MEDIA_SELECTOR)
|
|
7210
8539
|
).find((el) => {
|
|
7211
8540
|
const er = el.getBoundingClientRect();
|
|
7212
8541
|
return x >= er.left && x <= er.right && y >= er.top && y <= er.bottom;
|
|
@@ -7225,14 +8554,14 @@ function OhhwellsBridge() {
|
|
|
7225
8554
|
hoveredImageRef.current = null;
|
|
7226
8555
|
hoveredImageHasTextOverlapRef.current = false;
|
|
7227
8556
|
resumeAnimTracks();
|
|
7228
|
-
|
|
8557
|
+
clearImageHover();
|
|
7229
8558
|
}
|
|
7230
8559
|
return;
|
|
7231
8560
|
}
|
|
7232
8561
|
if (isStateCardImage) {
|
|
7233
8562
|
if (imgEl !== hoveredImageRef.current || !hoveredImageHasTextOverlapRef.current) {
|
|
7234
8563
|
hoveredImageRef.current = imgEl;
|
|
7235
|
-
|
|
8564
|
+
showImageHover(imgEl, isDragOver, true);
|
|
7236
8565
|
}
|
|
7237
8566
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
7238
8567
|
if (textEditable && !isInsideNavigationItem(textEditable)) {
|
|
@@ -7244,7 +8573,7 @@ function OhhwellsBridge() {
|
|
|
7244
8573
|
hoveredImageRef.current = null;
|
|
7245
8574
|
hoveredImageHasTextOverlapRef.current = false;
|
|
7246
8575
|
resumeAnimTracks();
|
|
7247
|
-
|
|
8576
|
+
clearImageHover();
|
|
7248
8577
|
}
|
|
7249
8578
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
7250
8579
|
if (textEditable && !isInsideNavigationItem(textEditable)) {
|
|
@@ -7256,7 +8585,7 @@ function OhhwellsBridge() {
|
|
|
7256
8585
|
if (hoveredImageRef.current) {
|
|
7257
8586
|
hoveredImageRef.current = null;
|
|
7258
8587
|
resumeAnimTracks();
|
|
7259
|
-
|
|
8588
|
+
clearImageHover();
|
|
7260
8589
|
}
|
|
7261
8590
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
7262
8591
|
return;
|
|
@@ -7264,9 +8593,9 @@ function OhhwellsBridge() {
|
|
|
7264
8593
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
7265
8594
|
if (imgEl !== hoveredImageRef.current || hoveredImageHasTextOverlapRef.current) {
|
|
7266
8595
|
hoveredImageRef.current = imgEl;
|
|
7267
|
-
|
|
8596
|
+
showImageHover(imgEl, isDragOver);
|
|
7268
8597
|
} else if (isDragOver) {
|
|
7269
|
-
|
|
8598
|
+
showImageHover(imgEl, true);
|
|
7270
8599
|
}
|
|
7271
8600
|
} else {
|
|
7272
8601
|
const inIframeView = clientX >= 0 && clientY >= 0 && clientX <= window.innerWidth && clientY <= window.innerHeight;
|
|
@@ -7283,14 +8612,14 @@ function OhhwellsBridge() {
|
|
|
7283
8612
|
hoveredImageRef.current = null;
|
|
7284
8613
|
hoveredImageHasTextOverlapRef.current = false;
|
|
7285
8614
|
resumeAnimTracks();
|
|
7286
|
-
|
|
8615
|
+
clearImageHover();
|
|
7287
8616
|
}
|
|
7288
|
-
const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
8617
|
+
const { x: x2, y: y2 } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
7289
8618
|
const textEl = Array.from(
|
|
7290
|
-
document.querySelectorAll(
|
|
8619
|
+
document.querySelectorAll(NON_MEDIA_SELECTOR)
|
|
7291
8620
|
).find((el) => {
|
|
7292
8621
|
const er = el.getBoundingClientRect();
|
|
7293
|
-
return
|
|
8622
|
+
return x2 >= er.left && x2 <= er.right && y2 >= er.top && y2 <= er.bottom;
|
|
7294
8623
|
});
|
|
7295
8624
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
7296
8625
|
if (textEl && !textEl.hasAttribute("contenteditable")) {
|
|
@@ -7393,18 +8722,20 @@ function OhhwellsBridge() {
|
|
|
7393
8722
|
return;
|
|
7394
8723
|
}
|
|
7395
8724
|
e.dataTransfer.dropEffect = "copy";
|
|
7396
|
-
if (
|
|
8725
|
+
if (dragOverElRef.current !== el) {
|
|
8726
|
+
dragOverElRef.current = el;
|
|
7397
8727
|
hoveredImageRef.current = el;
|
|
7398
8728
|
const isStateCard = !!el.closest("[data-ohw-editable-state]");
|
|
7399
|
-
|
|
8729
|
+
showImageHover(el, true, isStateCard ? true : void 0);
|
|
7400
8730
|
}
|
|
7401
8731
|
};
|
|
7402
8732
|
const handleDragLeave = (e) => {
|
|
7403
8733
|
const imgEl = findImageAtPoint(e.clientX, e.clientY, false);
|
|
7404
8734
|
if (imgEl) return;
|
|
8735
|
+
dragOverElRef.current = null;
|
|
7405
8736
|
hoveredImageRef.current = null;
|
|
7406
8737
|
resumeAnimTracks();
|
|
7407
|
-
|
|
8738
|
+
clearImageHover();
|
|
7408
8739
|
};
|
|
7409
8740
|
const handleDrop = (e) => {
|
|
7410
8741
|
e.preventDefault();
|
|
@@ -7412,7 +8743,9 @@ function OhhwellsBridge() {
|
|
|
7412
8743
|
if (!el) return;
|
|
7413
8744
|
const file = e.dataTransfer?.files?.[0];
|
|
7414
8745
|
if (file) {
|
|
7415
|
-
|
|
8746
|
+
const wantsVideo = el.dataset.ohwEditable === "video";
|
|
8747
|
+
const accepted = wantsVideo ? file.type.startsWith("video/") : file.type.startsWith("image/");
|
|
8748
|
+
if (accepted) {
|
|
7416
8749
|
const key = el.dataset.ohwKey ?? "";
|
|
7417
8750
|
const { name, type: mimeType } = file;
|
|
7418
8751
|
const r2 = el.getBoundingClientRect();
|
|
@@ -7421,12 +8754,13 @@ function OhhwellsBridge() {
|
|
|
7421
8754
|
window.parent.postMessage({ type: "ow:image-drop", key, name, mimeType, buf, rect }, "*", [buf]);
|
|
7422
8755
|
});
|
|
7423
8756
|
} else {
|
|
7424
|
-
postToParentRef.current({ type: "ow:image-drop-invalid" });
|
|
8757
|
+
postToParentRef.current({ type: "ow:image-drop-invalid", expected: wantsVideo ? "video" : "image" });
|
|
7425
8758
|
}
|
|
7426
8759
|
}
|
|
8760
|
+
dragOverElRef.current = null;
|
|
7427
8761
|
hoveredImageRef.current = null;
|
|
7428
8762
|
resumeAnimTracks();
|
|
7429
|
-
|
|
8763
|
+
clearImageHover();
|
|
7430
8764
|
};
|
|
7431
8765
|
const handleImageUrl = (e) => {
|
|
7432
8766
|
if (e.data?.type !== "ow:image-url") return;
|
|
@@ -7444,7 +8778,11 @@ function OhhwellsBridge() {
|
|
|
7444
8778
|
}
|
|
7445
8779
|
});
|
|
7446
8780
|
hoveredImageRef.current = null;
|
|
7447
|
-
|
|
8781
|
+
setUploadingRects((prev) => {
|
|
8782
|
+
const entry = prev[key];
|
|
8783
|
+
if (!entry || entry.fadingOut) return prev;
|
|
8784
|
+
return { ...prev, [key]: { ...entry, fadingOut: true } };
|
|
8785
|
+
});
|
|
7448
8786
|
};
|
|
7449
8787
|
let found = false;
|
|
7450
8788
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -7479,6 +8817,19 @@ function OhhwellsBridge() {
|
|
|
7479
8817
|
requestAnimationFrame(() => onReady());
|
|
7480
8818
|
}
|
|
7481
8819
|
}
|
|
8820
|
+
} else if (el.dataset.ohwEditable === "video") {
|
|
8821
|
+
const video = getVideoEl(el);
|
|
8822
|
+
if (video) {
|
|
8823
|
+
found = true;
|
|
8824
|
+
const onReady = () => {
|
|
8825
|
+
video.onloadeddata = null;
|
|
8826
|
+
video.onerror = null;
|
|
8827
|
+
notify();
|
|
8828
|
+
};
|
|
8829
|
+
video.onloadeddata = onReady;
|
|
8830
|
+
video.onerror = onReady;
|
|
8831
|
+
applyVideoSrc(video, url);
|
|
8832
|
+
}
|
|
7482
8833
|
}
|
|
7483
8834
|
});
|
|
7484
8835
|
if (!found) notify();
|
|
@@ -7545,12 +8896,16 @@ function OhhwellsBridge() {
|
|
|
7545
8896
|
sectionsJson = val;
|
|
7546
8897
|
continue;
|
|
7547
8898
|
}
|
|
8899
|
+
if (applyVideoSettingNode(key, val)) continue;
|
|
7548
8900
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
7549
8901
|
if (el.dataset.ohwEditable === "image") {
|
|
7550
8902
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
7551
8903
|
if (img) applyEditableImageSrc(img, val);
|
|
7552
8904
|
} else if (el.dataset.ohwEditable === "bg-image") {
|
|
7553
8905
|
el.style.backgroundImage = `url('${val}')`;
|
|
8906
|
+
} else if (el.dataset.ohwEditable === "video") {
|
|
8907
|
+
const video = getVideoEl(el);
|
|
8908
|
+
if (video && video.src !== val) applyVideoSrc(video, val);
|
|
7554
8909
|
} else if (el.dataset.ohwEditable === "link") {
|
|
7555
8910
|
applyLinkHref(el, val);
|
|
7556
8911
|
} else {
|
|
@@ -7564,6 +8919,8 @@ function OhhwellsBridge() {
|
|
|
7564
8919
|
sectionsLoadedRef.current = true;
|
|
7565
8920
|
pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
|
|
7566
8921
|
}
|
|
8922
|
+
editContentRef.current = { ...editContentRef.current, ...content };
|
|
8923
|
+
reconcileNavbarItemsFromContent(editContentRef.current);
|
|
7567
8924
|
enforceLinkHrefs();
|
|
7568
8925
|
postToParentRef.current({ type: "ow:hydrate-done" });
|
|
7569
8926
|
};
|
|
@@ -7571,6 +8928,7 @@ function OhhwellsBridge() {
|
|
|
7571
8928
|
const handleDeactivate = (e) => {
|
|
7572
8929
|
if (e.data?.type !== "ow:deactivate") return;
|
|
7573
8930
|
if (Date.now() < linkPopoverGraceUntilRef.current) return;
|
|
8931
|
+
if (document.querySelector("[data-ohw-section-picker]")) return;
|
|
7574
8932
|
if (linkPopoverOpenRef.current) {
|
|
7575
8933
|
setLinkPopoverRef.current(null);
|
|
7576
8934
|
return;
|
|
@@ -7580,12 +8938,32 @@ function OhhwellsBridge() {
|
|
|
7580
8938
|
};
|
|
7581
8939
|
window.addEventListener("message", handleDeactivate);
|
|
7582
8940
|
const handleKeyDown = (e) => {
|
|
8941
|
+
if (e.key === "Escape" && document.querySelector("[data-ohw-section-picker]")) return;
|
|
8942
|
+
if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a" && activeElRef.current) {
|
|
8943
|
+
const navAnchor = getNavigationItemAnchor(activeElRef.current);
|
|
8944
|
+
if (navAnchor) {
|
|
8945
|
+
e.preventDefault();
|
|
8946
|
+
selectAllTextInEditable(activeElRef.current);
|
|
8947
|
+
refreshActiveCommandsRef.current();
|
|
8948
|
+
return;
|
|
8949
|
+
}
|
|
8950
|
+
}
|
|
7583
8951
|
if (e.key === "Escape" && linkPopoverOpenRef.current) {
|
|
7584
8952
|
setLinkPopoverRef.current(null);
|
|
7585
8953
|
return;
|
|
7586
8954
|
}
|
|
7587
8955
|
if (e.key === "Escape" && selectedElRef.current && !activeElRef.current) {
|
|
7588
|
-
|
|
8956
|
+
if (toolbarVariantRef.current === "select-frame") {
|
|
8957
|
+
deselectRef.current();
|
|
8958
|
+
return;
|
|
8959
|
+
}
|
|
8960
|
+
const parent = getNavigationSelectionParent(selectedElRef.current);
|
|
8961
|
+
if (parent) {
|
|
8962
|
+
e.preventDefault();
|
|
8963
|
+
selectFrameRef.current(parent);
|
|
8964
|
+
} else {
|
|
8965
|
+
deselectRef.current();
|
|
8966
|
+
}
|
|
7589
8967
|
return;
|
|
7590
8968
|
}
|
|
7591
8969
|
if (e.key === "Escape" && activeElRef.current) {
|
|
@@ -7643,18 +9021,18 @@ function OhhwellsBridge() {
|
|
|
7643
9021
|
if (hoveredItemElRef.current) {
|
|
7644
9022
|
setHoveredItemRect(hoveredItemElRef.current.getBoundingClientRect());
|
|
7645
9023
|
}
|
|
9024
|
+
if (hoveredNavContainerRef.current) {
|
|
9025
|
+
setHoveredNavContainerRect(hoveredNavContainerRef.current.getBoundingClientRect());
|
|
9026
|
+
}
|
|
7646
9027
|
if (siblingHintElRef.current) {
|
|
7647
9028
|
setSiblingHintRect(siblingHintElRef.current.getBoundingClientRect());
|
|
7648
9029
|
}
|
|
7649
9030
|
if (hoveredImageRef.current) {
|
|
7650
9031
|
const el = hoveredImageRef.current;
|
|
7651
9032
|
const r2 = el.getBoundingClientRect();
|
|
7652
|
-
|
|
7653
|
-
|
|
7654
|
-
|
|
7655
|
-
rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height },
|
|
7656
|
-
hasTextOverlap: hoveredImageHasTextOverlapRef.current
|
|
7657
|
-
});
|
|
9033
|
+
setMediaHover(
|
|
9034
|
+
(prev) => prev ? { ...prev, rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height } } : prev
|
|
9035
|
+
);
|
|
7658
9036
|
}
|
|
7659
9037
|
};
|
|
7660
9038
|
const handleSave = (e) => {
|
|
@@ -7743,19 +9121,39 @@ function OhhwellsBridge() {
|
|
|
7743
9121
|
refreshActiveCommandsRef.current = handleSelectionChange;
|
|
7744
9122
|
const handleDocMouseLeave = () => {
|
|
7745
9123
|
hoveredImageRef.current = null;
|
|
9124
|
+
setMediaHover(null);
|
|
7746
9125
|
document.querySelectorAll("[data-ohw-state-hovered]").forEach((el) => el.removeAttribute("data-ohw-state-hovered"));
|
|
7747
9126
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
7748
9127
|
activeStateElRef.current = null;
|
|
7749
9128
|
setToggleState(null);
|
|
7750
9129
|
};
|
|
7751
|
-
const
|
|
7752
|
-
if (e.data?.type !== "ow:
|
|
7753
|
-
const { key } = e.data;
|
|
9130
|
+
const handleImageUploading = (e) => {
|
|
9131
|
+
if (e.data?.type !== "ow:image-uploading") return;
|
|
9132
|
+
const { key, uploading } = e.data;
|
|
9133
|
+
setUploadingRects((prev) => {
|
|
9134
|
+
if (!uploading) {
|
|
9135
|
+
if (!(key in prev)) return prev;
|
|
9136
|
+
const next = { ...prev };
|
|
9137
|
+
delete next[key];
|
|
9138
|
+
return next;
|
|
9139
|
+
}
|
|
9140
|
+
const el = document.querySelector(`[data-ohw-key="${key}"]`);
|
|
9141
|
+
if (!el) return prev;
|
|
9142
|
+
const r2 = getVisibleRect(el);
|
|
9143
|
+
return {
|
|
9144
|
+
...prev,
|
|
9145
|
+
[key]: { rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height } }
|
|
9146
|
+
};
|
|
9147
|
+
});
|
|
7754
9148
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
7755
9149
|
const track = el.closest("[data-ohw-hover-pause]");
|
|
7756
|
-
if (track)
|
|
9150
|
+
if (!track) return;
|
|
9151
|
+
if (uploading) {
|
|
7757
9152
|
uploadLockedTracks.add(track);
|
|
7758
9153
|
track.setAttribute("data-ohw-hover-paused", "");
|
|
9154
|
+
} else {
|
|
9155
|
+
uploadLockedTracks.delete(track);
|
|
9156
|
+
track.removeAttribute("data-ohw-hover-paused");
|
|
7759
9157
|
}
|
|
7760
9158
|
});
|
|
7761
9159
|
};
|
|
@@ -7797,7 +9195,7 @@ function OhhwellsBridge() {
|
|
|
7797
9195
|
if (e.data?.type !== "ow:click-at") return;
|
|
7798
9196
|
const { clientX, clientY } = e.data;
|
|
7799
9197
|
const allImages = Array.from(
|
|
7800
|
-
document.querySelectorAll(
|
|
9198
|
+
document.querySelectorAll(MEDIA_SELECTOR)
|
|
7801
9199
|
).filter((el) => !!el.closest("[data-ohw-editable-state]"));
|
|
7802
9200
|
const stateCardImage = allImages.find((el) => {
|
|
7803
9201
|
const ownerCard = el.closest("[data-ohw-editable-state]");
|
|
@@ -7812,21 +9210,55 @@ function OhhwellsBridge() {
|
|
|
7812
9210
|
return clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom;
|
|
7813
9211
|
});
|
|
7814
9212
|
if (stateCardImage) {
|
|
7815
|
-
postToParentRef.current({ type: "ow:image-pick", key: stateCardImage.dataset.ohwKey ?? "" });
|
|
9213
|
+
postToParentRef.current({ type: "ow:image-pick", key: stateCardImage.dataset.ohwKey ?? "", elementType: stateCardImage.dataset.ohwEditable ?? "image" });
|
|
7816
9214
|
return;
|
|
7817
9215
|
}
|
|
7818
9216
|
const textEditable = Array.from(
|
|
7819
|
-
document.querySelectorAll(
|
|
7820
|
-
'[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"])'
|
|
7821
|
-
)
|
|
9217
|
+
document.querySelectorAll(NON_MEDIA_SELECTOR)
|
|
7822
9218
|
).find((el) => {
|
|
7823
9219
|
const r2 = el.getBoundingClientRect();
|
|
7824
9220
|
return clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom;
|
|
7825
9221
|
});
|
|
7826
9222
|
if (textEditable) {
|
|
7827
|
-
|
|
9223
|
+
const hrefCtx = getHrefKeyFromElement(textEditable);
|
|
9224
|
+
const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
|
|
9225
|
+
if (navAnchor) {
|
|
9226
|
+
if (selectedElRef.current === navAnchor) {
|
|
9227
|
+
activateRef.current(textEditable, { caretX: clientX, caretY: clientY });
|
|
9228
|
+
} else {
|
|
9229
|
+
selectRef.current(navAnchor);
|
|
9230
|
+
}
|
|
9231
|
+
return;
|
|
9232
|
+
}
|
|
9233
|
+
activateRef.current(textEditable, { caretX: clientX, caretY: clientY });
|
|
7828
9234
|
return;
|
|
7829
9235
|
}
|
|
9236
|
+
const navContainer = document.querySelector("[data-ohw-nav-container]");
|
|
9237
|
+
if (navContainer) {
|
|
9238
|
+
const r2 = navContainer.getBoundingClientRect();
|
|
9239
|
+
const pad = 8;
|
|
9240
|
+
const over = clientX >= r2.left - pad && clientX <= r2.right + pad && clientY >= r2.top - pad && clientY <= r2.bottom + pad;
|
|
9241
|
+
if (over && !isPointOverNavItem(navContainer, clientX, clientY)) {
|
|
9242
|
+
selectFrameRef.current(navContainer);
|
|
9243
|
+
return;
|
|
9244
|
+
}
|
|
9245
|
+
}
|
|
9246
|
+
const navRoot = document.querySelector("[data-ohw-nav-root]");
|
|
9247
|
+
if (navRoot && navContainer) {
|
|
9248
|
+
const rr = navRoot.getBoundingClientRect();
|
|
9249
|
+
if (clientX >= rr.left && clientX <= rr.right && clientY >= rr.top && clientY <= rr.bottom && !isPointOverNavItem(navContainer, clientX, clientY)) {
|
|
9250
|
+
const book = navRoot.querySelector('[data-ohw-role="navbar-button"]');
|
|
9251
|
+
if (book) {
|
|
9252
|
+
const br = book.getBoundingClientRect();
|
|
9253
|
+
if (clientX >= br.left && clientX <= br.right && clientY >= br.top && clientY <= br.bottom) {
|
|
9254
|
+
deactivateRef.current();
|
|
9255
|
+
return;
|
|
9256
|
+
}
|
|
9257
|
+
}
|
|
9258
|
+
selectFrameRef.current(navContainer);
|
|
9259
|
+
return;
|
|
9260
|
+
}
|
|
9261
|
+
}
|
|
7830
9262
|
deactivateRef.current();
|
|
7831
9263
|
};
|
|
7832
9264
|
window.addEventListener("message", handleSave);
|
|
@@ -7836,7 +9268,7 @@ function OhhwellsBridge() {
|
|
|
7836
9268
|
window.addEventListener("message", handleClearSchedulingWidget);
|
|
7837
9269
|
window.addEventListener("message", handleRemoveSchedulingSection);
|
|
7838
9270
|
window.addEventListener("message", handleImageUrl);
|
|
7839
|
-
window.addEventListener("message",
|
|
9271
|
+
window.addEventListener("message", handleImageUploading);
|
|
7840
9272
|
window.addEventListener("message", handleCanvasHeight);
|
|
7841
9273
|
window.addEventListener("message", handleParentScroll);
|
|
7842
9274
|
window.addEventListener("message", handlePointerSync);
|
|
@@ -7848,6 +9280,7 @@ function OhhwellsBridge() {
|
|
|
7848
9280
|
};
|
|
7849
9281
|
window.addEventListener("resize", handleViewportResize, { passive: true });
|
|
7850
9282
|
document.addEventListener("click", handleClick, true);
|
|
9283
|
+
document.addEventListener("dblclick", handleDblClick, true);
|
|
7851
9284
|
document.addEventListener("paste", handlePaste, true);
|
|
7852
9285
|
document.addEventListener("input", handleInput, true);
|
|
7853
9286
|
document.addEventListener("mouseover", handleMouseOver, true);
|
|
@@ -7862,6 +9295,7 @@ function OhhwellsBridge() {
|
|
|
7862
9295
|
window.addEventListener("scroll", handleScroll, true);
|
|
7863
9296
|
return () => {
|
|
7864
9297
|
document.removeEventListener("click", handleClick, true);
|
|
9298
|
+
document.removeEventListener("dblclick", handleDblClick, true);
|
|
7865
9299
|
document.removeEventListener("paste", handlePaste, true);
|
|
7866
9300
|
document.removeEventListener("input", handleInput, true);
|
|
7867
9301
|
document.removeEventListener("mouseover", handleMouseOver, true);
|
|
@@ -7881,7 +9315,7 @@ function OhhwellsBridge() {
|
|
|
7881
9315
|
window.removeEventListener("message", handleClearSchedulingWidget);
|
|
7882
9316
|
window.removeEventListener("message", handleRemoveSchedulingSection);
|
|
7883
9317
|
window.removeEventListener("message", handleImageUrl);
|
|
7884
|
-
window.removeEventListener("message",
|
|
9318
|
+
window.removeEventListener("message", handleImageUploading);
|
|
7885
9319
|
window.removeEventListener("message", handleCanvasHeight);
|
|
7886
9320
|
window.removeEventListener("message", handleParentScroll);
|
|
7887
9321
|
window.removeEventListener("resize", handleViewportResize);
|
|
@@ -7895,7 +9329,7 @@ function OhhwellsBridge() {
|
|
|
7895
9329
|
if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
|
|
7896
9330
|
};
|
|
7897
9331
|
}, [isEditMode, refreshStateRules]);
|
|
7898
|
-
|
|
9332
|
+
useEffect7(() => {
|
|
7899
9333
|
const handler = (e) => {
|
|
7900
9334
|
if (e.data?.type !== "ow:request-schedule-config") return;
|
|
7901
9335
|
const insertAfterVal = e.data.insertAfter;
|
|
@@ -7911,7 +9345,7 @@ function OhhwellsBridge() {
|
|
|
7911
9345
|
window.addEventListener("message", handler);
|
|
7912
9346
|
return () => window.removeEventListener("message", handler);
|
|
7913
9347
|
}, [processConfigRequest]);
|
|
7914
|
-
|
|
9348
|
+
useEffect7(() => {
|
|
7915
9349
|
if (!isEditMode) return;
|
|
7916
9350
|
document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
|
|
7917
9351
|
el.removeAttribute("data-ohw-active-state");
|
|
@@ -7932,27 +9366,27 @@ function OhhwellsBridge() {
|
|
|
7932
9366
|
const next = { ...prev, [pathKey]: sections };
|
|
7933
9367
|
return shouldUseDevFixtures() ? { ...DEV_SECTIONS_BY_PATH, ...next } : next;
|
|
7934
9368
|
});
|
|
7935
|
-
|
|
7936
|
-
|
|
9369
|
+
postToParent2({ type: "ow:ready", version: "1", path: pathname, nodes: collectEditableNodes(), sections });
|
|
9370
|
+
postToParent2({ type: "ow:request-site-pages" });
|
|
7937
9371
|
}, 150);
|
|
7938
9372
|
return () => {
|
|
7939
9373
|
cancelAnimationFrame(raf);
|
|
7940
9374
|
clearTimeout(timer);
|
|
7941
9375
|
};
|
|
7942
|
-
}, [pathname, isEditMode, refreshStateRules,
|
|
7943
|
-
|
|
9376
|
+
}, [pathname, isEditMode, refreshStateRules, postToParent2]);
|
|
9377
|
+
useEffect7(() => {
|
|
7944
9378
|
scrollToHashSectionWhenReady();
|
|
7945
9379
|
const onHashChange = () => scrollToHashSectionWhenReady();
|
|
7946
9380
|
window.addEventListener("hashchange", onHashChange);
|
|
7947
9381
|
return () => window.removeEventListener("hashchange", onHashChange);
|
|
7948
9382
|
}, [pathname]);
|
|
7949
|
-
const handleCommand =
|
|
9383
|
+
const handleCommand = useCallback4((cmd) => {
|
|
7950
9384
|
document.execCommand(cmd, false);
|
|
7951
9385
|
activeElRef.current?.focus();
|
|
7952
9386
|
if (activeElRef.current) setToolbarRect(getEditMeasureEl(activeElRef.current).getBoundingClientRect());
|
|
7953
9387
|
refreshActiveCommandsRef.current();
|
|
7954
9388
|
}, []);
|
|
7955
|
-
const handleStateChange =
|
|
9389
|
+
const handleStateChange = useCallback4((state) => {
|
|
7956
9390
|
if (!activeStateElRef.current) return;
|
|
7957
9391
|
const el = activeStateElRef.current;
|
|
7958
9392
|
if (state === "Default") {
|
|
@@ -7965,18 +9399,22 @@ function OhhwellsBridge() {
|
|
|
7965
9399
|
}
|
|
7966
9400
|
setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
|
|
7967
9401
|
}, [deactivate]);
|
|
7968
|
-
const closeLinkPopover =
|
|
7969
|
-
|
|
9402
|
+
const closeLinkPopover = useCallback4(() => {
|
|
9403
|
+
addNavAfterAnchorRef.current = null;
|
|
9404
|
+
setLinkPopover(null);
|
|
9405
|
+
}, []);
|
|
9406
|
+
const openLinkPopoverForActive = useCallback4(() => {
|
|
7970
9407
|
const hrefCtx = getHrefKeyFromElement(activeElRef.current);
|
|
7971
9408
|
if (!hrefCtx) return;
|
|
7972
9409
|
bumpLinkPopoverGrace();
|
|
7973
9410
|
setLinkPopover({
|
|
7974
9411
|
key: hrefCtx.key,
|
|
7975
|
-
|
|
9412
|
+
mode: "edit",
|
|
9413
|
+
target: getLinkHref2(hrefCtx.anchor)
|
|
7976
9414
|
});
|
|
7977
9415
|
deactivate();
|
|
7978
9416
|
}, [deactivate]);
|
|
7979
|
-
const openLinkPopoverForSelected =
|
|
9417
|
+
const openLinkPopoverForSelected = useCallback4(() => {
|
|
7980
9418
|
const anchor = selectedElRef.current;
|
|
7981
9419
|
if (!anchor) return;
|
|
7982
9420
|
const key = anchor.getAttribute("data-ohw-href-key");
|
|
@@ -7984,51 +9422,163 @@ function OhhwellsBridge() {
|
|
|
7984
9422
|
bumpLinkPopoverGrace();
|
|
7985
9423
|
setLinkPopover({
|
|
7986
9424
|
key,
|
|
7987
|
-
|
|
9425
|
+
mode: "edit",
|
|
9426
|
+
target: getLinkHref2(anchor)
|
|
7988
9427
|
});
|
|
7989
9428
|
deselect();
|
|
7990
9429
|
}, [deselect]);
|
|
7991
|
-
const handleLinkPopoverSubmit =
|
|
9430
|
+
const handleLinkPopoverSubmit = useCallback4(
|
|
7992
9431
|
(target) => {
|
|
7993
|
-
|
|
7994
|
-
|
|
9432
|
+
const session = linkPopoverSessionRef.current;
|
|
9433
|
+
if (!session) return;
|
|
9434
|
+
if (session.intent === "add-nav") {
|
|
9435
|
+
const trimmed = target.trim();
|
|
9436
|
+
let href = trimmed;
|
|
9437
|
+
let label = "Untitled";
|
|
9438
|
+
if (trimmed) {
|
|
9439
|
+
const { pageRoute, sectionId } = parseTarget(trimmed);
|
|
9440
|
+
const page = resolvePage(pageRoute, sitePages);
|
|
9441
|
+
const pageSections = getSectionsForPath(sectionsByPath, pageRoute);
|
|
9442
|
+
const section = sectionId ? pageSections.find((s) => s.id === sectionId) : void 0;
|
|
9443
|
+
label = section?.label ?? page.title;
|
|
9444
|
+
href = trimmed;
|
|
9445
|
+
}
|
|
9446
|
+
const afterAnchor = addNavAfterAnchorRef.current;
|
|
9447
|
+
const { anchor, hrefKey, labelKey, index, order } = insertNavbarItem(href, label, afterAnchor);
|
|
9448
|
+
applyLinkByKey(hrefKey, href);
|
|
9449
|
+
document.querySelectorAll(`[data-ohw-key="${labelKey}"]`).forEach((el) => {
|
|
9450
|
+
el.textContent = label;
|
|
9451
|
+
});
|
|
9452
|
+
const navCount = String(index + 1);
|
|
9453
|
+
const orderJson = JSON.stringify(order);
|
|
9454
|
+
editContentRef.current = {
|
|
9455
|
+
...editContentRef.current,
|
|
9456
|
+
[hrefKey]: href,
|
|
9457
|
+
[labelKey]: label,
|
|
9458
|
+
[NAV_COUNT_KEY]: navCount,
|
|
9459
|
+
[NAV_ORDER_KEY]: orderJson
|
|
9460
|
+
};
|
|
9461
|
+
postToParent2({
|
|
9462
|
+
type: "ow:change",
|
|
9463
|
+
nodes: [
|
|
9464
|
+
{ key: hrefKey, text: href },
|
|
9465
|
+
{ key: labelKey, text: label },
|
|
9466
|
+
{ key: NAV_COUNT_KEY, text: navCount },
|
|
9467
|
+
{ key: NAV_ORDER_KEY, text: orderJson }
|
|
9468
|
+
]
|
|
9469
|
+
});
|
|
9470
|
+
postToParent2({ type: "ow:toast", title: "Link added", toastType: "success" });
|
|
9471
|
+
addNavAfterAnchorRef.current = null;
|
|
9472
|
+
setLinkPopover(null);
|
|
9473
|
+
enforceLinkHrefs();
|
|
9474
|
+
requestAnimationFrame(() => {
|
|
9475
|
+
selectRef.current(anchor);
|
|
9476
|
+
});
|
|
9477
|
+
return;
|
|
9478
|
+
}
|
|
9479
|
+
const { key } = session;
|
|
7995
9480
|
applyLinkByKey(key, target);
|
|
7996
|
-
|
|
9481
|
+
postToParent2({ type: "ow:change", nodes: [{ key, text: target }] });
|
|
7997
9482
|
setLinkPopover(null);
|
|
7998
9483
|
},
|
|
7999
|
-
[
|
|
9484
|
+
[postToParent2, sitePages, sectionsByPath]
|
|
8000
9485
|
);
|
|
8001
9486
|
const showEditLink = toolbarShowEditLink;
|
|
8002
9487
|
const currentSections = sectionsByPath[pathname] ?? [];
|
|
8003
9488
|
linkPopoverOpenRef.current = linkPopover !== null;
|
|
8004
|
-
|
|
8005
|
-
|
|
8006
|
-
|
|
8007
|
-
|
|
8008
|
-
|
|
8009
|
-
|
|
9489
|
+
const handleMediaReplace = useCallback4(
|
|
9490
|
+
(key) => {
|
|
9491
|
+
postToParent2({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
|
|
9492
|
+
},
|
|
9493
|
+
[postToParent2, mediaHover?.elementType]
|
|
9494
|
+
);
|
|
9495
|
+
const handleMediaFadeOutComplete = useCallback4((key) => {
|
|
9496
|
+
setUploadingRects((prev) => {
|
|
9497
|
+
if (!(key in prev)) return prev;
|
|
9498
|
+
const next = { ...prev };
|
|
9499
|
+
delete next[key];
|
|
9500
|
+
return next;
|
|
9501
|
+
});
|
|
9502
|
+
}, []);
|
|
9503
|
+
const handleVideoSettingsChange = useCallback4(
|
|
9504
|
+
(key, settings) => {
|
|
9505
|
+
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
9506
|
+
const video = getVideoEl(el);
|
|
9507
|
+
if (!video) return;
|
|
9508
|
+
if (typeof settings.autoplay === "boolean") video.autoplay = settings.autoplay;
|
|
9509
|
+
if (typeof settings.muted === "boolean") video.muted = settings.muted;
|
|
9510
|
+
syncVideoPlayback(video);
|
|
9511
|
+
postToParent2({
|
|
9512
|
+
type: "ow:change",
|
|
9513
|
+
nodes: [
|
|
9514
|
+
{ key: `${key}${VIDEO_AUTOPLAY_SUFFIX}`, text: String(video.autoplay) },
|
|
9515
|
+
{ key: `${key}${VIDEO_MUTED_SUFFIX}`, text: String(video.muted) }
|
|
9516
|
+
]
|
|
9517
|
+
});
|
|
9518
|
+
setMediaHover(
|
|
9519
|
+
(prev) => prev && prev.key === key ? { ...prev, videoAutoplay: video.autoplay, videoMuted: video.muted } : prev
|
|
9520
|
+
);
|
|
9521
|
+
});
|
|
9522
|
+
},
|
|
9523
|
+
[postToParent2]
|
|
9524
|
+
);
|
|
9525
|
+
return bridgeRoot ? createPortal2(
|
|
9526
|
+
/* @__PURE__ */ jsxs13(Fragment5, { children: [
|
|
9527
|
+
/* @__PURE__ */ jsx23("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
|
|
9528
|
+
Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ jsx23(
|
|
9529
|
+
MediaOverlay,
|
|
9530
|
+
{
|
|
9531
|
+
hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
|
|
9532
|
+
isUploading: true,
|
|
9533
|
+
fadingOut,
|
|
9534
|
+
onFadeOutComplete: handleMediaFadeOutComplete,
|
|
9535
|
+
onReplace: handleMediaReplace
|
|
9536
|
+
},
|
|
9537
|
+
`uploading-${key}`
|
|
9538
|
+
)),
|
|
9539
|
+
mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ jsx23(
|
|
9540
|
+
MediaOverlay,
|
|
9541
|
+
{
|
|
9542
|
+
hover: mediaHover,
|
|
9543
|
+
isUploading: false,
|
|
9544
|
+
onReplace: handleMediaReplace,
|
|
9545
|
+
onVideoSettingsChange: handleVideoSettingsChange
|
|
9546
|
+
}
|
|
9547
|
+
),
|
|
9548
|
+
siblingHintRect && !isItemDragging && /* @__PURE__ */ jsx23(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
|
|
9549
|
+
hoveredNavContainerRect && toolbarVariant !== "select-frame" && !linkPopover && !isItemDragging && !siblingHintRect && /* @__PURE__ */ jsx23(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
|
|
9550
|
+
toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx23(
|
|
9551
|
+
NavbarContainerChrome,
|
|
9552
|
+
{
|
|
9553
|
+
rect: toolbarRect,
|
|
9554
|
+
onAdd: handleAddTopLevelNavItem
|
|
9555
|
+
}
|
|
9556
|
+
),
|
|
9557
|
+
hoveredItemRect && !hoveredNavContainerRect && !siblingHintRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx23(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
|
|
9558
|
+
toolbarRect && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ jsx23(
|
|
8010
9559
|
ItemInteractionLayer,
|
|
8011
9560
|
{
|
|
8012
9561
|
rect: toolbarRect,
|
|
8013
9562
|
elRef: glowElRef,
|
|
8014
9563
|
state: isItemDragging ? "dragging" : resolveItemInteractionState(toolbarRect, parentScrollRef.current),
|
|
8015
|
-
showHandle: Boolean(reorderHrefKey),
|
|
9564
|
+
showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey),
|
|
8016
9565
|
dragDisabled: reorderDragDisabled,
|
|
8017
9566
|
dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
|
|
8018
9567
|
onDragHandleDragStart: handleItemDragStart,
|
|
8019
9568
|
onDragHandleDragEnd: handleItemDragEnd,
|
|
8020
|
-
toolbar:
|
|
9569
|
+
toolbar: toolbarVariant === "link-action" && !isItemDragging ? /* @__PURE__ */ jsx23(
|
|
8021
9570
|
ItemActionToolbar,
|
|
8022
9571
|
{
|
|
8023
9572
|
onEditLink: openLinkPopoverForSelected,
|
|
8024
|
-
|
|
8025
|
-
|
|
9573
|
+
addItemDisabled: true,
|
|
9574
|
+
editLinkDisabled: false,
|
|
9575
|
+
moreDisabled: true
|
|
8026
9576
|
}
|
|
8027
|
-
)
|
|
9577
|
+
) : void 0
|
|
8028
9578
|
}
|
|
8029
9579
|
),
|
|
8030
|
-
toolbarRect && toolbarVariant === "rich-text" && /* @__PURE__ */
|
|
8031
|
-
/* @__PURE__ */
|
|
9580
|
+
toolbarRect && toolbarVariant === "rich-text" && /* @__PURE__ */ jsxs13(Fragment5, { children: [
|
|
9581
|
+
/* @__PURE__ */ jsx23(
|
|
8032
9582
|
EditGlowChrome,
|
|
8033
9583
|
{
|
|
8034
9584
|
rect: toolbarRect,
|
|
@@ -8037,7 +9587,7 @@ function OhhwellsBridge() {
|
|
|
8037
9587
|
dragDisabled: reorderDragDisabled
|
|
8038
9588
|
}
|
|
8039
9589
|
),
|
|
8040
|
-
/* @__PURE__ */
|
|
9590
|
+
/* @__PURE__ */ jsx23(
|
|
8041
9591
|
FloatingToolbar,
|
|
8042
9592
|
{
|
|
8043
9593
|
rect: toolbarRect,
|
|
@@ -8050,7 +9600,7 @@ function OhhwellsBridge() {
|
|
|
8050
9600
|
}
|
|
8051
9601
|
)
|
|
8052
9602
|
] }),
|
|
8053
|
-
maxBadge && /* @__PURE__ */
|
|
9603
|
+
maxBadge && /* @__PURE__ */ jsxs13(
|
|
8054
9604
|
"div",
|
|
8055
9605
|
{
|
|
8056
9606
|
"data-ohw-max-badge": "",
|
|
@@ -8076,7 +9626,7 @@ function OhhwellsBridge() {
|
|
|
8076
9626
|
]
|
|
8077
9627
|
}
|
|
8078
9628
|
),
|
|
8079
|
-
toggleState && /* @__PURE__ */
|
|
9629
|
+
toggleState && !linkPopover && /* @__PURE__ */ jsx23(
|
|
8080
9630
|
StateToggle,
|
|
8081
9631
|
{
|
|
8082
9632
|
rect: toggleState.rect,
|
|
@@ -8085,15 +9635,15 @@ function OhhwellsBridge() {
|
|
|
8085
9635
|
onStateChange: handleStateChange
|
|
8086
9636
|
}
|
|
8087
9637
|
),
|
|
8088
|
-
sectionGap && /* @__PURE__ */
|
|
9638
|
+
sectionGap && !linkPopover && /* @__PURE__ */ jsxs13(
|
|
8089
9639
|
"div",
|
|
8090
9640
|
{
|
|
8091
9641
|
"data-ohw-section-insert-line": "",
|
|
8092
9642
|
className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
|
|
8093
9643
|
style: { top: sectionGap.y, transform: "translateY(-50%)" },
|
|
8094
9644
|
children: [
|
|
8095
|
-
/* @__PURE__ */
|
|
8096
|
-
/* @__PURE__ */
|
|
9645
|
+
/* @__PURE__ */ jsx23("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
|
|
9646
|
+
/* @__PURE__ */ jsx23(
|
|
8097
9647
|
Badge,
|
|
8098
9648
|
{
|
|
8099
9649
|
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",
|
|
@@ -8106,26 +9656,52 @@ function OhhwellsBridge() {
|
|
|
8106
9656
|
children: "Add Section"
|
|
8107
9657
|
}
|
|
8108
9658
|
),
|
|
8109
|
-
/* @__PURE__ */
|
|
9659
|
+
/* @__PURE__ */ jsx23("div", { className: "flex-1 bg-primary", style: { height: 3 } })
|
|
8110
9660
|
]
|
|
8111
9661
|
}
|
|
8112
9662
|
),
|
|
8113
|
-
linkPopover && dialogPortalContainer ? /* @__PURE__ */
|
|
9663
|
+
linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx23(
|
|
8114
9664
|
LinkPopover,
|
|
8115
9665
|
{
|
|
8116
9666
|
panelRef: linkPopoverPanelRef,
|
|
8117
9667
|
portalContainer: dialogPortalContainer,
|
|
8118
9668
|
open: true,
|
|
8119
|
-
mode: "edit",
|
|
9669
|
+
mode: linkPopover.mode ?? "edit",
|
|
8120
9670
|
pages: sitePages,
|
|
8121
9671
|
sections: currentSections,
|
|
8122
9672
|
sectionsByPath,
|
|
8123
9673
|
initialTarget: linkPopover.target,
|
|
9674
|
+
existingTargets: linkPopover.intent === "add-nav" ? getNavbarExistingTargets() : [],
|
|
8124
9675
|
onClose: closeLinkPopover,
|
|
8125
9676
|
onSubmit: handleLinkPopoverSubmit
|
|
8126
9677
|
},
|
|
8127
|
-
|
|
8128
|
-
) : null
|
|
9678
|
+
linkPopover.key
|
|
9679
|
+
) : null,
|
|
9680
|
+
sectionGap && /* @__PURE__ */ jsxs13(
|
|
9681
|
+
"div",
|
|
9682
|
+
{
|
|
9683
|
+
"data-ohw-section-insert-line": "",
|
|
9684
|
+
className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
|
|
9685
|
+
style: { top: sectionGap.y, transform: "translateY(-50%)" },
|
|
9686
|
+
children: [
|
|
9687
|
+
/* @__PURE__ */ jsx23("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
|
|
9688
|
+
/* @__PURE__ */ jsx23(
|
|
9689
|
+
Badge,
|
|
9690
|
+
{
|
|
9691
|
+
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",
|
|
9692
|
+
onClick: () => {
|
|
9693
|
+
window.parent.postMessage(
|
|
9694
|
+
{ type: "ow:add-section", insertAfter: sectionGap.insertAfter, insertBefore: sectionGap.insertBefore },
|
|
9695
|
+
"*"
|
|
9696
|
+
);
|
|
9697
|
+
},
|
|
9698
|
+
children: "Add Section"
|
|
9699
|
+
}
|
|
9700
|
+
),
|
|
9701
|
+
/* @__PURE__ */ jsx23("div", { className: "flex-1 bg-primary", style: { height: 3 } })
|
|
9702
|
+
]
|
|
9703
|
+
}
|
|
9704
|
+
)
|
|
8129
9705
|
] }),
|
|
8130
9706
|
bridgeRoot
|
|
8131
9707
|
) : null;
|