@ohhwells/bridge 0.1.36 → 0.1.38-next.56
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 +2114 -618
- 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 +2112 -616
- package/dist/index.js.map +1 -1
- package/dist/styles.css +156 -21
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -60,15 +60,18 @@ __export(index_exports, {
|
|
|
60
60
|
module.exports = __toCommonJS(index_exports);
|
|
61
61
|
|
|
62
62
|
// src/OhhwellsBridge.tsx
|
|
63
|
-
var
|
|
63
|
+
var import_react8 = __toESM(require("react"), 1);
|
|
64
64
|
var import_client = require("react-dom/client");
|
|
65
|
-
var
|
|
65
|
+
var import_react_dom2 = require("react-dom");
|
|
66
66
|
|
|
67
67
|
// src/linkHrefStore.ts
|
|
68
68
|
var linkHrefStore = /* @__PURE__ */ new Map();
|
|
69
69
|
function setStoredLinkHref(key, href) {
|
|
70
70
|
linkHrefStore.set(key, href);
|
|
71
71
|
}
|
|
72
|
+
function getStoredLinkHref(key) {
|
|
73
|
+
return linkHrefStore.get(key);
|
|
74
|
+
}
|
|
72
75
|
function enforceLinkHrefs() {
|
|
73
76
|
document.querySelectorAll("[data-ohw-href-key]").forEach((el) => {
|
|
74
77
|
const key = el.getAttribute("data-ohw-href-key") ?? "";
|
|
@@ -110,6 +113,7 @@ var import_react3 = require("react");
|
|
|
110
113
|
var import_react2 = require("react");
|
|
111
114
|
var import_radix_ui = require("radix-ui");
|
|
112
115
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
116
|
+
var isValidEmail = (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
|
|
113
117
|
function Spinner() {
|
|
114
118
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
115
119
|
"svg",
|
|
@@ -143,12 +147,17 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
|
|
|
143
147
|
const [error, setError] = (0, import_react2.useState)(null);
|
|
144
148
|
const isBook = title === "Confirm your spot";
|
|
145
149
|
const handleSubmit = async () => {
|
|
146
|
-
|
|
150
|
+
const trimmed = email.trim();
|
|
151
|
+
if (!trimmed) return;
|
|
152
|
+
if (!isValidEmail(trimmed)) {
|
|
153
|
+
setError("Please enter a valid email address.");
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
147
156
|
setLoading(true);
|
|
148
157
|
setError(null);
|
|
149
158
|
try {
|
|
150
|
-
await onSubmit(
|
|
151
|
-
setSubmittedEmail(
|
|
159
|
+
await onSubmit(trimmed);
|
|
160
|
+
setSubmittedEmail(trimmed);
|
|
152
161
|
setSuccess(true);
|
|
153
162
|
} catch (e) {
|
|
154
163
|
setError(e instanceof Error ? e.message : "Something went wrong. Please try again.");
|
|
@@ -223,7 +232,10 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
|
|
|
223
232
|
{
|
|
224
233
|
type: "email",
|
|
225
234
|
value: email,
|
|
226
|
-
onChange: (e) =>
|
|
235
|
+
onChange: (e) => {
|
|
236
|
+
setEmail(e.target.value);
|
|
237
|
+
if (error) setError(null);
|
|
238
|
+
},
|
|
227
239
|
onKeyDown: handleKeyDown,
|
|
228
240
|
placeholder: "hello@gmail.com",
|
|
229
241
|
autoFocus: true,
|
|
@@ -280,12 +292,20 @@ function formatClassTime(cls) {
|
|
|
280
292
|
const em = endTotal % 60;
|
|
281
293
|
return `${h}:${cls.startTime.minutes}-${eh}:${String(em).padStart(2, "0")}`;
|
|
282
294
|
}
|
|
295
|
+
function formatBookingLabel(cls) {
|
|
296
|
+
const price = cls.price;
|
|
297
|
+
const isFree = price === null || price === void 0 || `${price}` === "" || `${price}` === "0";
|
|
298
|
+
return isFree ? "Book for free" : `Book for ${cls.currency ?? ""} ${price}`.trim();
|
|
299
|
+
}
|
|
283
300
|
function getBookingsOnDate(cls, date) {
|
|
284
301
|
if (!cls.bookings?.length) return 0;
|
|
285
|
-
const
|
|
302
|
+
const target = new Date(date);
|
|
303
|
+
target.setHours(0, 0, 0, 0);
|
|
286
304
|
return cls.bookings.filter((b) => {
|
|
287
305
|
try {
|
|
288
|
-
|
|
306
|
+
const bookingDate = new Date(b.classDate);
|
|
307
|
+
bookingDate.setHours(0, 0, 0, 0);
|
|
308
|
+
return bookingDate.getTime() === target.getTime();
|
|
289
309
|
} catch {
|
|
290
310
|
return false;
|
|
291
311
|
}
|
|
@@ -589,7 +609,7 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
|
|
|
589
609
|
if (!cls.id) return;
|
|
590
610
|
onOpenModal?.(isFull ? "waitlist" : "book", cls.id, selectedDate);
|
|
591
611
|
},
|
|
592
|
-
children: isFull ? "Join Waitlist" :
|
|
612
|
+
children: isFull ? "Join Waitlist" : formatBookingLabel(cls)
|
|
593
613
|
}
|
|
594
614
|
)
|
|
595
615
|
] })
|
|
@@ -631,6 +651,17 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
631
651
|
const [isHovered, setIsHovered] = (0, import_react3.useState)(false);
|
|
632
652
|
const [modalState, setModalState] = (0, import_react3.useState)(null);
|
|
633
653
|
const switchScheduleIdRef = (0, import_react3.useRef)(null);
|
|
654
|
+
const liveScheduleIdRef = (0, import_react3.useRef)(null);
|
|
655
|
+
const refetchLiveSchedule = (0, import_react3.useCallback)(async () => {
|
|
656
|
+
const id = liveScheduleIdRef.current;
|
|
657
|
+
if (!id) return;
|
|
658
|
+
try {
|
|
659
|
+
const res = await fetch(`${API_URL}/api/schedule/id/${id}`);
|
|
660
|
+
const data = await res.json();
|
|
661
|
+
if (data?.id) setSchedule(data);
|
|
662
|
+
} catch {
|
|
663
|
+
}
|
|
664
|
+
}, []);
|
|
634
665
|
const dates = (0, import_react3.useMemo)(() => {
|
|
635
666
|
const today = /* @__PURE__ */ new Date();
|
|
636
667
|
today.setHours(0, 0, 0, 0);
|
|
@@ -650,6 +681,18 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
650
681
|
}
|
|
651
682
|
}
|
|
652
683
|
}, [schedule, dates]);
|
|
684
|
+
(0, import_react3.useEffect)(() => {
|
|
685
|
+
if (typeof window === "undefined") return;
|
|
686
|
+
const onVisible = () => {
|
|
687
|
+
if (!document.hidden) void refetchLiveSchedule();
|
|
688
|
+
};
|
|
689
|
+
window.addEventListener("focus", refetchLiveSchedule);
|
|
690
|
+
document.addEventListener("visibilitychange", onVisible);
|
|
691
|
+
return () => {
|
|
692
|
+
window.removeEventListener("focus", refetchLiveSchedule);
|
|
693
|
+
document.removeEventListener("visibilitychange", onVisible);
|
|
694
|
+
};
|
|
695
|
+
}, [refetchLiveSchedule]);
|
|
653
696
|
(0, import_react3.useEffect)(() => {
|
|
654
697
|
if (typeof window === "undefined") return;
|
|
655
698
|
const isInEditor = window.self !== window.top;
|
|
@@ -711,7 +754,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
711
754
|
setLoading(false);
|
|
712
755
|
return;
|
|
713
756
|
}
|
|
714
|
-
;
|
|
757
|
+
liveScheduleIdRef.current = effectiveId;
|
|
715
758
|
(async () => {
|
|
716
759
|
try {
|
|
717
760
|
const res = await fetch(`${API_URL}/api/schedule/id/${effectiveId}`);
|
|
@@ -768,18 +811,14 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
768
811
|
const data = await res.json().catch(() => ({}));
|
|
769
812
|
throw new Error(data?.message ?? "Something went wrong. Please try again.");
|
|
770
813
|
}
|
|
814
|
+
await refetchLiveSchedule();
|
|
771
815
|
};
|
|
772
816
|
const handleReplaceSchedule = () => {
|
|
773
817
|
setIsHovered(false);
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
insertAfter
|
|
779
|
-
}, "*");
|
|
780
|
-
} else {
|
|
781
|
-
window.parent.postMessage({ type: "ow:scheduling-not-connected", insertAfter }, "*");
|
|
782
|
-
}
|
|
818
|
+
window.parent.postMessage(
|
|
819
|
+
{ type: "ow:scheduling-not-connected", insertAfter, currentScheduleId: schedule?.id },
|
|
820
|
+
"*"
|
|
821
|
+
);
|
|
783
822
|
};
|
|
784
823
|
if (!inEditor && !loading && !schedule) return null;
|
|
785
824
|
const sectionId = `scheduling-${insertAfter}`;
|
|
@@ -822,7 +861,19 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
822
861
|
),
|
|
823
862
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "max-w-[1280px] mx-auto flex flex-col items-center gap-16", children: [
|
|
824
863
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col items-center gap-4", children: [
|
|
825
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
864
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
865
|
+
"h2",
|
|
866
|
+
{
|
|
867
|
+
className: "font-display text-center m-0 text-(--color-dark,#200C02)",
|
|
868
|
+
style: {
|
|
869
|
+
fontSize: "var(--fs-section-h2, clamp(40px, 4.4vw, 64px))",
|
|
870
|
+
fontWeight: "var(--font-weight-heading, 400)",
|
|
871
|
+
lineHeight: 1.05,
|
|
872
|
+
letterSpacing: "-0.02em"
|
|
873
|
+
},
|
|
874
|
+
children: schedule?.name ?? "Book an appointment"
|
|
875
|
+
}
|
|
876
|
+
),
|
|
826
877
|
schedule?.description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "font-body text-body text-center m-0 text-(--color-accent,#A89B83)", children: schedule.description })
|
|
827
878
|
] }),
|
|
828
879
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "w-full flex flex-col items-end gap-3", children: [
|
|
@@ -4408,6 +4459,7 @@ function ItemActionToolbar({
|
|
|
4408
4459
|
onEditLink,
|
|
4409
4460
|
onAddItem,
|
|
4410
4461
|
onMore,
|
|
4462
|
+
editLinkDisabled = false,
|
|
4411
4463
|
addItemDisabled = true,
|
|
4412
4464
|
moreDisabled = true,
|
|
4413
4465
|
tooltipSide = "bottom"
|
|
@@ -4416,10 +4468,12 @@ function ItemActionToolbar({
|
|
|
4416
4468
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
4417
4469
|
ToolbarActionTooltip,
|
|
4418
4470
|
{
|
|
4419
|
-
label: "
|
|
4471
|
+
label: "Edit link",
|
|
4420
4472
|
side: tooltipSide,
|
|
4473
|
+
disabled: editLinkDisabled,
|
|
4421
4474
|
buttonProps: {
|
|
4422
4475
|
onMouseDown: (e) => {
|
|
4476
|
+
if (editLinkDisabled) return;
|
|
4423
4477
|
e.preventDefault();
|
|
4424
4478
|
e.stopPropagation();
|
|
4425
4479
|
onEditLink?.();
|
|
@@ -4591,9 +4645,223 @@ function ItemInteractionLayer({
|
|
|
4591
4645
|
);
|
|
4592
4646
|
}
|
|
4593
4647
|
|
|
4648
|
+
// src/ui/MediaOverlay.tsx
|
|
4649
|
+
var React6 = __toESM(require("react"), 1);
|
|
4650
|
+
var import_lucide_react3 = require("lucide-react");
|
|
4651
|
+
|
|
4652
|
+
// src/ui/button.tsx
|
|
4653
|
+
var React5 = __toESM(require("react"), 1);
|
|
4654
|
+
var import_radix_ui4 = require("radix-ui");
|
|
4655
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
4656
|
+
var buttonVariants = cva(
|
|
4657
|
+
"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",
|
|
4658
|
+
{
|
|
4659
|
+
variants: {
|
|
4660
|
+
variant: {
|
|
4661
|
+
default: "bg-primary text-primary-foreground hover:opacity-90",
|
|
4662
|
+
outline: "border border-border bg-background text-foreground shadow-sm hover:bg-muted/80",
|
|
4663
|
+
ghost: "min-w-0 px-3 py-2 text-foreground hover:bg-muted/50"
|
|
4664
|
+
},
|
|
4665
|
+
size: {
|
|
4666
|
+
default: "h-9",
|
|
4667
|
+
sm: "h-8 min-w-[64px] px-2 py-1.5 text-sm"
|
|
4668
|
+
}
|
|
4669
|
+
},
|
|
4670
|
+
defaultVariants: {
|
|
4671
|
+
variant: "default",
|
|
4672
|
+
size: "default"
|
|
4673
|
+
}
|
|
4674
|
+
}
|
|
4675
|
+
);
|
|
4676
|
+
var Button = React5.forwardRef(
|
|
4677
|
+
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
4678
|
+
const Comp = asChild ? import_radix_ui4.Slot.Root : "button";
|
|
4679
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4680
|
+
Comp,
|
|
4681
|
+
{
|
|
4682
|
+
ref,
|
|
4683
|
+
"data-slot": "button",
|
|
4684
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
4685
|
+
...props
|
|
4686
|
+
}
|
|
4687
|
+
);
|
|
4688
|
+
}
|
|
4689
|
+
);
|
|
4690
|
+
Button.displayName = "Button";
|
|
4691
|
+
|
|
4692
|
+
// src/ui/MediaOverlay.tsx
|
|
4693
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
4694
|
+
var MEDIA_UPLOAD_FADE_MS = 300;
|
|
4695
|
+
var VIDEO_SETTINGS_BAR_INSET = 8;
|
|
4696
|
+
var OVERLAY_BUTTON_STYLE = {
|
|
4697
|
+
pointerEvents: "auto",
|
|
4698
|
+
fontFamily: "Inter, sans-serif",
|
|
4699
|
+
fontSize: 12,
|
|
4700
|
+
color: "#000"
|
|
4701
|
+
};
|
|
4702
|
+
var SKELETON_CSS = `
|
|
4703
|
+
@keyframes ohw-media-shimmer {
|
|
4704
|
+
0% { transform: translateX(-100%); }
|
|
4705
|
+
100% { transform: translateX(100%); }
|
|
4706
|
+
}
|
|
4707
|
+
[data-ohw-media-skeleton] {
|
|
4708
|
+
overflow: hidden;
|
|
4709
|
+
background-color: #d1d5db; /* tailwind gray-300 */
|
|
4710
|
+
}
|
|
4711
|
+
[data-ohw-media-skeleton]::after {
|
|
4712
|
+
content: "";
|
|
4713
|
+
position: absolute;
|
|
4714
|
+
inset: 0;
|
|
4715
|
+
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.6), transparent);
|
|
4716
|
+
animation: ohw-media-shimmer 1.4s infinite;
|
|
4717
|
+
}
|
|
4718
|
+
`;
|
|
4719
|
+
function MediaOverlay({
|
|
4720
|
+
hover,
|
|
4721
|
+
isUploading,
|
|
4722
|
+
fadingOut = false,
|
|
4723
|
+
onFadeOutComplete,
|
|
4724
|
+
onReplace,
|
|
4725
|
+
onVideoSettingsChange
|
|
4726
|
+
}) {
|
|
4727
|
+
const { rect } = hover;
|
|
4728
|
+
const skeletonRef = React6.useRef(null);
|
|
4729
|
+
const isVideo = hover.elementType === "video";
|
|
4730
|
+
const autoplay = hover.videoAutoplay ?? true;
|
|
4731
|
+
const muted = hover.videoMuted ?? true;
|
|
4732
|
+
const box = {
|
|
4733
|
+
position: "fixed",
|
|
4734
|
+
top: rect.top,
|
|
4735
|
+
left: rect.left,
|
|
4736
|
+
width: rect.width,
|
|
4737
|
+
height: rect.height,
|
|
4738
|
+
zIndex: 2147483646
|
|
4739
|
+
};
|
|
4740
|
+
React6.useEffect(() => {
|
|
4741
|
+
if (!isUploading || !fadingOut || !skeletonRef.current) return;
|
|
4742
|
+
const anim = skeletonRef.current.animate([{ opacity: 1 }, { opacity: 0 }], {
|
|
4743
|
+
duration: MEDIA_UPLOAD_FADE_MS,
|
|
4744
|
+
easing: "ease-out",
|
|
4745
|
+
fill: "forwards"
|
|
4746
|
+
});
|
|
4747
|
+
anim.finished.then(() => onFadeOutComplete?.(hover.key)).catch(() => onFadeOutComplete?.(hover.key));
|
|
4748
|
+
return () => anim.cancel();
|
|
4749
|
+
}, [isUploading, fadingOut, onFadeOutComplete, hover.key]);
|
|
4750
|
+
if (isUploading) {
|
|
4751
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
4752
|
+
"div",
|
|
4753
|
+
{
|
|
4754
|
+
ref: skeletonRef,
|
|
4755
|
+
"data-ohw-bridge": "",
|
|
4756
|
+
"data-ohw-media-overlay": "",
|
|
4757
|
+
"data-ohw-media-skeleton": "",
|
|
4758
|
+
"aria-hidden": true,
|
|
4759
|
+
style: { ...box, pointerEvents: "none" },
|
|
4760
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("style", { children: SKELETON_CSS })
|
|
4761
|
+
}
|
|
4762
|
+
);
|
|
4763
|
+
}
|
|
4764
|
+
const settingsBar = isVideo && !hover.isDragOver ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
4765
|
+
"div",
|
|
4766
|
+
{
|
|
4767
|
+
"data-ohw-bridge": "",
|
|
4768
|
+
"data-ohw-media-overlay": "",
|
|
4769
|
+
className: "flex items-center justify-center gap-1.5",
|
|
4770
|
+
style: {
|
|
4771
|
+
position: "fixed",
|
|
4772
|
+
top: rect.top + VIDEO_SETTINGS_BAR_INSET,
|
|
4773
|
+
left: rect.left,
|
|
4774
|
+
width: rect.width,
|
|
4775
|
+
zIndex: 2147483647,
|
|
4776
|
+
pointerEvents: "auto"
|
|
4777
|
+
},
|
|
4778
|
+
onClick: (e) => e.stopPropagation(),
|
|
4779
|
+
children: [
|
|
4780
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
4781
|
+
Button,
|
|
4782
|
+
{
|
|
4783
|
+
"data-ohw-media-overlay": "",
|
|
4784
|
+
variant: "outline",
|
|
4785
|
+
size: "sm",
|
|
4786
|
+
className: "cursor-pointer hover:bg-background",
|
|
4787
|
+
style: { ...OVERLAY_BUTTON_STYLE, minWidth: 0, padding: "0 8px" },
|
|
4788
|
+
"aria-label": autoplay ? "Disable autoplay" : "Enable autoplay",
|
|
4789
|
+
title: autoplay ? "Autoplay on \u2014 click to disable" : "Autoplay off \u2014 click to enable",
|
|
4790
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
4791
|
+
onClick: (e) => {
|
|
4792
|
+
e.stopPropagation();
|
|
4793
|
+
onVideoSettingsChange?.(hover.key, { autoplay: !autoplay });
|
|
4794
|
+
},
|
|
4795
|
+
children: autoplay ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react3.Pause, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react3.Play, { size: 14 })
|
|
4796
|
+
}
|
|
4797
|
+
),
|
|
4798
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
4799
|
+
Button,
|
|
4800
|
+
{
|
|
4801
|
+
"data-ohw-media-overlay": "",
|
|
4802
|
+
variant: "outline",
|
|
4803
|
+
size: "sm",
|
|
4804
|
+
className: "cursor-pointer hover:bg-background",
|
|
4805
|
+
style: { ...OVERLAY_BUTTON_STYLE, minWidth: 0, padding: "0 8px" },
|
|
4806
|
+
"aria-label": muted ? "Unmute video" : "Mute video",
|
|
4807
|
+
title: muted ? "Muted \u2014 click to unmute" : "Sound on \u2014 click to mute",
|
|
4808
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
4809
|
+
onClick: (e) => {
|
|
4810
|
+
e.stopPropagation();
|
|
4811
|
+
onVideoSettingsChange?.(hover.key, { muted: !muted });
|
|
4812
|
+
},
|
|
4813
|
+
children: muted ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react3.VolumeX, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react3.Volume2, { size: 14 })
|
|
4814
|
+
}
|
|
4815
|
+
)
|
|
4816
|
+
]
|
|
4817
|
+
}
|
|
4818
|
+
) : null;
|
|
4819
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
4820
|
+
settingsBar,
|
|
4821
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
4822
|
+
"div",
|
|
4823
|
+
{
|
|
4824
|
+
"data-ohw-bridge": "",
|
|
4825
|
+
"data-ohw-media-overlay": "",
|
|
4826
|
+
className: "flex items-center justify-center cursor-pointer",
|
|
4827
|
+
style: {
|
|
4828
|
+
...box,
|
|
4829
|
+
// When text overlays this media, let clicks fall THROUGH to the text underneath. In the
|
|
4830
|
+
// parent this needed a whole `ow:click-at` round-trip to re-hit-test inside the iframe;
|
|
4831
|
+
// in-document, pointer-events does it natively. The button below opts back in, so
|
|
4832
|
+
// Replace still works.
|
|
4833
|
+
pointerEvents: hover.hasTextOverlap ? "none" : "auto",
|
|
4834
|
+
boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
|
|
4835
|
+
background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
|
|
4836
|
+
},
|
|
4837
|
+
onClick: () => onReplace(hover.key),
|
|
4838
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
4839
|
+
Button,
|
|
4840
|
+
{
|
|
4841
|
+
"data-ohw-media-overlay": "",
|
|
4842
|
+
variant: "outline",
|
|
4843
|
+
size: "sm",
|
|
4844
|
+
className: "gap-1.5 cursor-pointer hover:bg-background",
|
|
4845
|
+
style: OVERLAY_BUTTON_STYLE,
|
|
4846
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
4847
|
+
onClick: (e) => {
|
|
4848
|
+
e.stopPropagation();
|
|
4849
|
+
onReplace(hover.key);
|
|
4850
|
+
},
|
|
4851
|
+
children: [
|
|
4852
|
+
isVideo ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react3.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react3.ImageIcon, { size: 14 }),
|
|
4853
|
+
isVideo ? "Replace video" : "Replace image"
|
|
4854
|
+
]
|
|
4855
|
+
}
|
|
4856
|
+
)
|
|
4857
|
+
}
|
|
4858
|
+
)
|
|
4859
|
+
] });
|
|
4860
|
+
}
|
|
4861
|
+
|
|
4594
4862
|
// src/OhhwellsBridge.tsx
|
|
4595
|
-
var
|
|
4596
|
-
var
|
|
4863
|
+
var import_react_dom3 = require("react-dom");
|
|
4864
|
+
var import_navigation2 = require("next/navigation");
|
|
4597
4865
|
|
|
4598
4866
|
// src/lib/session-search.ts
|
|
4599
4867
|
var STORAGE_KEY = "ohw-preserved-search";
|
|
@@ -4869,62 +5137,30 @@ function scrollToHashSectionWhenReady(behavior = "smooth") {
|
|
|
4869
5137
|
tick();
|
|
4870
5138
|
}
|
|
4871
5139
|
|
|
4872
|
-
// src/ui/
|
|
4873
|
-
var
|
|
4874
|
-
var import_radix_ui4 = require("radix-ui");
|
|
4875
|
-
|
|
4876
|
-
// src/ui/icons.tsx
|
|
4877
|
-
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
4878
|
-
function IconX({ className, ...props }) {
|
|
4879
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
4880
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M18 6 6 18" }),
|
|
4881
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "m6 6 12 12" })
|
|
4882
|
-
] });
|
|
4883
|
-
}
|
|
4884
|
-
function IconChevronDown({ className, ...props }) {
|
|
4885
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "m6 9 6 6 6-6" }) });
|
|
4886
|
-
}
|
|
4887
|
-
function IconFile({ className, ...props }) {
|
|
4888
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
4889
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
|
|
4890
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" })
|
|
4891
|
-
] });
|
|
4892
|
-
}
|
|
4893
|
-
function IconInfo({ className, ...props }) {
|
|
4894
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
4895
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
|
|
4896
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M12 16v-4" }),
|
|
4897
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M12 8h.01" })
|
|
4898
|
-
] });
|
|
4899
|
-
}
|
|
4900
|
-
function IconArrowRight({ className, ...props }) {
|
|
4901
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
4902
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M5 12h14" }),
|
|
4903
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "m12 5 7 7-7 7" })
|
|
4904
|
-
] });
|
|
4905
|
-
}
|
|
4906
|
-
function IconSection({ className, ...props }) {
|
|
4907
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
4908
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("rect", { width: "18", height: "7", x: "3", y: "3", rx: "1" }),
|
|
4909
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("rect", { width: "9", height: "7", x: "3", y: "14", rx: "1" }),
|
|
4910
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("rect", { width: "5", height: "7", x: "16", y: "14", rx: "1" })
|
|
4911
|
-
] });
|
|
4912
|
-
}
|
|
5140
|
+
// src/ui/link-modal/LinkPopover.tsx
|
|
5141
|
+
var import_react7 = require("react");
|
|
4913
5142
|
|
|
4914
5143
|
// src/ui/dialog.tsx
|
|
4915
|
-
var
|
|
4916
|
-
|
|
4917
|
-
|
|
5144
|
+
var React7 = __toESM(require("react"), 1);
|
|
5145
|
+
var import_radix_ui5 = require("radix-ui");
|
|
5146
|
+
var import_lucide_react4 = require("lucide-react");
|
|
5147
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
5148
|
+
function Dialog2({
|
|
5149
|
+
...props
|
|
5150
|
+
}) {
|
|
5151
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_radix_ui5.Dialog.Root, { "data-slot": "dialog", ...props });
|
|
4918
5152
|
}
|
|
4919
|
-
function DialogPortal({
|
|
4920
|
-
|
|
5153
|
+
function DialogPortal({
|
|
5154
|
+
...props
|
|
5155
|
+
}) {
|
|
5156
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_radix_ui5.Dialog.Portal, { ...props });
|
|
4921
5157
|
}
|
|
4922
5158
|
function DialogOverlay({
|
|
4923
5159
|
className,
|
|
4924
5160
|
...props
|
|
4925
5161
|
}) {
|
|
4926
|
-
return /* @__PURE__ */ (0,
|
|
4927
|
-
|
|
5162
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
5163
|
+
import_radix_ui5.Dialog.Overlay,
|
|
4928
5164
|
{
|
|
4929
5165
|
"data-slot": "dialog-overlay",
|
|
4930
5166
|
"data-ohw-link-modal-root": "",
|
|
@@ -4933,120 +5169,118 @@ function DialogOverlay({
|
|
|
4933
5169
|
}
|
|
4934
5170
|
);
|
|
4935
5171
|
}
|
|
4936
|
-
var DialogContent =
|
|
4937
|
-
|
|
4938
|
-
|
|
4939
|
-
/* @__PURE__ */ (0,
|
|
4940
|
-
|
|
4941
|
-
|
|
4942
|
-
|
|
4943
|
-
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
children
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
});
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
5172
|
+
var DialogContent = React7.forwardRef(
|
|
5173
|
+
({ className, children, showCloseButton = true, container, ...props }, ref) => {
|
|
5174
|
+
const positionMode = container ? "absolute" : "fixed";
|
|
5175
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(DialogPortal, { container: container ?? void 0, children: [
|
|
5176
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(DialogOverlay, { className: cn(positionMode, "inset-0") }),
|
|
5177
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
5178
|
+
import_radix_ui5.Dialog.Content,
|
|
5179
|
+
{
|
|
5180
|
+
ref,
|
|
5181
|
+
"data-slot": "dialog-content",
|
|
5182
|
+
className: cn(
|
|
5183
|
+
positionMode,
|
|
5184
|
+
"left-1/2 top-1/2 z-[2147483647] flex w-full max-w-[483px] -translate-x-1/2 -translate-y-1/2 flex-col overflow-visible",
|
|
5185
|
+
"rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
|
|
5186
|
+
container ? "max-h-[calc(100%-32px)] max-w-[calc(100%-16px)]" : "max-h-[calc(100vh-32px)] max-w-[calc(100vw-16px)]",
|
|
5187
|
+
className
|
|
5188
|
+
),
|
|
5189
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
5190
|
+
...props,
|
|
5191
|
+
children: [
|
|
5192
|
+
children,
|
|
5193
|
+
showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
5194
|
+
import_radix_ui5.Dialog.Close,
|
|
5195
|
+
{
|
|
5196
|
+
type: "button",
|
|
5197
|
+
className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
|
|
5198
|
+
"aria-label": "Close",
|
|
5199
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react4.X, { size: 16, "aria-hidden": true })
|
|
5200
|
+
}
|
|
5201
|
+
) : null
|
|
5202
|
+
]
|
|
5203
|
+
}
|
|
5204
|
+
)
|
|
5205
|
+
] });
|
|
5206
|
+
}
|
|
5207
|
+
);
|
|
5208
|
+
DialogContent.displayName = import_radix_ui5.Dialog.Content.displayName;
|
|
5209
|
+
function DialogHeader({
|
|
5210
|
+
className,
|
|
5211
|
+
...props
|
|
5212
|
+
}) {
|
|
5213
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: cn("flex flex-col gap-1.5", className), ...props });
|
|
4973
5214
|
}
|
|
4974
|
-
function DialogFooter({
|
|
4975
|
-
|
|
5215
|
+
function DialogFooter({
|
|
5216
|
+
className,
|
|
5217
|
+
...props
|
|
5218
|
+
}) {
|
|
5219
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
5220
|
+
"div",
|
|
5221
|
+
{
|
|
5222
|
+
className: cn("flex items-center justify-end gap-2", className),
|
|
5223
|
+
...props
|
|
5224
|
+
}
|
|
5225
|
+
);
|
|
4976
5226
|
}
|
|
4977
|
-
var DialogTitle =
|
|
4978
|
-
|
|
5227
|
+
var DialogTitle = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
5228
|
+
import_radix_ui5.Dialog.Title,
|
|
4979
5229
|
{
|
|
4980
5230
|
ref,
|
|
4981
|
-
className: cn(
|
|
5231
|
+
className: cn(
|
|
5232
|
+
"text-lg font-semibold leading-none tracking-tight text-card-foreground",
|
|
5233
|
+
className
|
|
5234
|
+
),
|
|
4982
5235
|
...props
|
|
4983
5236
|
}
|
|
4984
5237
|
));
|
|
4985
|
-
DialogTitle.displayName =
|
|
4986
|
-
var DialogDescription =
|
|
4987
|
-
|
|
5238
|
+
DialogTitle.displayName = import_radix_ui5.Dialog.Title.displayName;
|
|
5239
|
+
var DialogDescription = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
5240
|
+
import_radix_ui5.Dialog.Description,
|
|
4988
5241
|
{
|
|
4989
5242
|
ref,
|
|
4990
5243
|
className: cn("text-sm text-muted-foreground", className),
|
|
4991
5244
|
...props
|
|
4992
5245
|
}
|
|
4993
5246
|
));
|
|
4994
|
-
DialogDescription.displayName =
|
|
4995
|
-
var DialogClose =
|
|
5247
|
+
DialogDescription.displayName = import_radix_ui5.Dialog.Description.displayName;
|
|
5248
|
+
var DialogClose = import_radix_ui5.Dialog.Close;
|
|
4996
5249
|
|
|
4997
|
-
// src/ui/
|
|
4998
|
-
var
|
|
4999
|
-
var import_radix_ui5 = require("radix-ui");
|
|
5000
|
-
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
5001
|
-
var buttonVariants = cva(
|
|
5002
|
-
"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",
|
|
5003
|
-
{
|
|
5004
|
-
variants: {
|
|
5005
|
-
variant: {
|
|
5006
|
-
default: "bg-primary text-primary-foreground hover:opacity-90",
|
|
5007
|
-
outline: "border border-border bg-background text-foreground shadow-sm hover:bg-muted/80",
|
|
5008
|
-
ghost: "min-w-0 px-3 py-2 text-foreground hover:bg-muted/50"
|
|
5009
|
-
},
|
|
5010
|
-
size: {
|
|
5011
|
-
default: "h-9",
|
|
5012
|
-
sm: "h-8 min-w-[64px] px-2 py-1.5 text-sm"
|
|
5013
|
-
}
|
|
5014
|
-
},
|
|
5015
|
-
defaultVariants: {
|
|
5016
|
-
variant: "default",
|
|
5017
|
-
size: "default"
|
|
5018
|
-
}
|
|
5019
|
-
}
|
|
5020
|
-
);
|
|
5021
|
-
var Button = React6.forwardRef(
|
|
5022
|
-
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
5023
|
-
const Comp = asChild ? import_radix_ui5.Slot.Root : "button";
|
|
5024
|
-
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
5025
|
-
Comp,
|
|
5026
|
-
{
|
|
5027
|
-
ref,
|
|
5028
|
-
"data-slot": "button",
|
|
5029
|
-
className: cn(buttonVariants({ variant, size, className })),
|
|
5030
|
-
...props
|
|
5031
|
-
}
|
|
5032
|
-
);
|
|
5033
|
-
}
|
|
5034
|
-
);
|
|
5035
|
-
Button.displayName = "Button";
|
|
5250
|
+
// src/ui/link-modal/LinkEditorPanel.tsx
|
|
5251
|
+
var import_lucide_react8 = require("lucide-react");
|
|
5036
5252
|
|
|
5037
5253
|
// src/ui/link-modal/DestinationBreadcrumb.tsx
|
|
5254
|
+
var import_lucide_react5 = require("lucide-react");
|
|
5038
5255
|
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
5039
|
-
function DestinationBreadcrumb({
|
|
5256
|
+
function DestinationBreadcrumb({
|
|
5257
|
+
pageTitle,
|
|
5258
|
+
sectionLabel
|
|
5259
|
+
}) {
|
|
5040
5260
|
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex w-full flex-col gap-2", children: [
|
|
5041
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-sm font-medium text-foreground", children: "Destination" }),
|
|
5261
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-sm font-medium! text-foreground m-0", children: "Destination" }),
|
|
5042
5262
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-3", children: [
|
|
5043
5263
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
5044
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
5045
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-sm font-medium leading-none text-foreground", children: pageTitle })
|
|
5264
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react5.File, { size: 16, className: "shrink-0 text-foreground", "aria-hidden": true }),
|
|
5265
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-sm font-medium leading-none text-foreground!", children: pageTitle })
|
|
5046
5266
|
] }),
|
|
5047
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
5267
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
5268
|
+
import_lucide_react5.ArrowRight,
|
|
5269
|
+
{
|
|
5270
|
+
size: 16,
|
|
5271
|
+
className: "shrink-0 text-muted-foreground",
|
|
5272
|
+
"aria-hidden": true
|
|
5273
|
+
}
|
|
5274
|
+
),
|
|
5048
5275
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
|
|
5049
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
5276
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
5277
|
+
import_lucide_react5.GalleryVertical,
|
|
5278
|
+
{
|
|
5279
|
+
size: 16,
|
|
5280
|
+
className: "shrink-0 text-foreground",
|
|
5281
|
+
"aria-hidden": true
|
|
5282
|
+
}
|
|
5283
|
+
),
|
|
5050
5284
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
|
|
5051
5285
|
] })
|
|
5052
5286
|
] })
|
|
@@ -5054,8 +5288,13 @@ function DestinationBreadcrumb({ pageTitle, sectionLabel }) {
|
|
|
5054
5288
|
}
|
|
5055
5289
|
|
|
5056
5290
|
// src/ui/link-modal/SectionTreeItem.tsx
|
|
5291
|
+
var import_lucide_react6 = require("lucide-react");
|
|
5057
5292
|
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
5058
|
-
function SectionTreeItem({
|
|
5293
|
+
function SectionTreeItem({
|
|
5294
|
+
section,
|
|
5295
|
+
onSelect,
|
|
5296
|
+
selected
|
|
5297
|
+
}) {
|
|
5059
5298
|
const interactive = Boolean(onSelect);
|
|
5060
5299
|
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex h-9 w-full items-end pl-3", children: [
|
|
5061
5300
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
@@ -5083,30 +5322,28 @@ function SectionTreeItem({ section, onSelect, selected }) {
|
|
|
5083
5322
|
interactive && selected && "border-primary"
|
|
5084
5323
|
),
|
|
5085
5324
|
children: [
|
|
5086
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
5325
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
5326
|
+
import_lucide_react6.GalleryVertical,
|
|
5327
|
+
{
|
|
5328
|
+
size: 16,
|
|
5329
|
+
className: "shrink-0 text-foreground",
|
|
5330
|
+
"aria-hidden": true
|
|
5331
|
+
}
|
|
5332
|
+
),
|
|
5087
5333
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
|
|
5088
5334
|
]
|
|
5089
5335
|
}
|
|
5090
5336
|
)
|
|
5091
5337
|
] });
|
|
5092
5338
|
}
|
|
5093
|
-
function SectionPickerList({ sections, onSelect }) {
|
|
5094
|
-
if (sections.length === 0) {
|
|
5095
|
-
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." });
|
|
5096
|
-
}
|
|
5097
|
-
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col gap-1", children: [
|
|
5098
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-sm text-muted-foreground", children: "Pick a section this link should scroll to." }),
|
|
5099
|
-
sections.map((section) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SectionTreeItem, { section, onSelect }, section.id))
|
|
5100
|
-
] });
|
|
5101
|
-
}
|
|
5102
5339
|
|
|
5103
5340
|
// src/ui/link-modal/UrlOrPageInput.tsx
|
|
5104
5341
|
var import_react4 = require("react");
|
|
5105
5342
|
|
|
5106
5343
|
// src/ui/input.tsx
|
|
5107
|
-
var
|
|
5344
|
+
var React8 = __toESM(require("react"), 1);
|
|
5108
5345
|
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
5109
|
-
var Input =
|
|
5346
|
+
var Input = React8.forwardRef(
|
|
5110
5347
|
({ className, type, ...props }, ref) => {
|
|
5111
5348
|
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
5112
5349
|
"input",
|
|
@@ -5140,8 +5377,11 @@ function Label({ className, ...props }) {
|
|
|
5140
5377
|
}
|
|
5141
5378
|
|
|
5142
5379
|
// src/ui/link-modal/UrlOrPageInput.tsx
|
|
5380
|
+
var import_lucide_react7 = require("lucide-react");
|
|
5143
5381
|
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
5144
|
-
function FieldChevron({
|
|
5382
|
+
function FieldChevron({
|
|
5383
|
+
onClick
|
|
5384
|
+
}) {
|
|
5145
5385
|
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5146
5386
|
"button",
|
|
5147
5387
|
{
|
|
@@ -5150,7 +5390,7 @@ function FieldChevron({ onClick }) {
|
|
|
5150
5390
|
onClick,
|
|
5151
5391
|
"aria-label": "Open page list",
|
|
5152
5392
|
tabIndex: -1,
|
|
5153
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5393
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react7.ChevronDown, { size: 16 })
|
|
5154
5394
|
}
|
|
5155
5395
|
);
|
|
5156
5396
|
}
|
|
@@ -5168,7 +5408,29 @@ function UrlOrPageInput({
|
|
|
5168
5408
|
}) {
|
|
5169
5409
|
const inputId = (0, import_react4.useId)();
|
|
5170
5410
|
const inputRef = (0, import_react4.useRef)(null);
|
|
5411
|
+
const rootRef = (0, import_react4.useRef)(null);
|
|
5171
5412
|
const [isFocused, setIsFocused] = (0, import_react4.useState)(false);
|
|
5413
|
+
(0, import_react4.useEffect)(() => {
|
|
5414
|
+
if (!dropdownOpen) return;
|
|
5415
|
+
const isOutside = (e) => {
|
|
5416
|
+
const root = rootRef.current;
|
|
5417
|
+
if (!root) return true;
|
|
5418
|
+
const path = typeof e.composedPath === "function" ? e.composedPath() : [];
|
|
5419
|
+
if (path.includes(root)) return false;
|
|
5420
|
+
const target = e.target;
|
|
5421
|
+
return !(target instanceof Node && root.contains(target));
|
|
5422
|
+
};
|
|
5423
|
+
const closeIfOutside = (e) => {
|
|
5424
|
+
if (!isOutside(e)) return;
|
|
5425
|
+
onDropdownOpenChange(false);
|
|
5426
|
+
};
|
|
5427
|
+
document.addEventListener("pointerdown", closeIfOutside, true);
|
|
5428
|
+
document.addEventListener("mousedown", closeIfOutside, true);
|
|
5429
|
+
return () => {
|
|
5430
|
+
document.removeEventListener("pointerdown", closeIfOutside, true);
|
|
5431
|
+
document.removeEventListener("mousedown", closeIfOutside, true);
|
|
5432
|
+
};
|
|
5433
|
+
}, [dropdownOpen, onDropdownOpenChange]);
|
|
5172
5434
|
const openDropdown = () => {
|
|
5173
5435
|
if (readOnly || filteredPages.length === 0) return;
|
|
5174
5436
|
onDropdownOpenChange(true);
|
|
@@ -5191,9 +5453,16 @@ function UrlOrPageInput({
|
|
|
5191
5453
|
);
|
|
5192
5454
|
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex w-full flex-col gap-2 p-0", children: [
|
|
5193
5455
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
|
|
5194
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "relative w-full", children: [
|
|
5456
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { ref: rootRef, className: "relative w-full", children: [
|
|
5195
5457
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
|
|
5196
|
-
selectedPage ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5458
|
+
selectedPage ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5459
|
+
import_lucide_react7.File,
|
|
5460
|
+
{
|
|
5461
|
+
size: 16,
|
|
5462
|
+
className: "shrink-0 text-foreground",
|
|
5463
|
+
"aria-hidden": true
|
|
5464
|
+
}
|
|
5465
|
+
) }) : null,
|
|
5197
5466
|
readOnly ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "min-w-0 flex-1 truncate text-sm leading-5 text-foreground", children: selectedPage?.title ?? value }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5198
5467
|
Input,
|
|
5199
5468
|
{
|
|
@@ -5205,7 +5474,14 @@ function UrlOrPageInput({
|
|
|
5205
5474
|
setIsFocused(true);
|
|
5206
5475
|
if (!selectedPage) openDropdown();
|
|
5207
5476
|
},
|
|
5208
|
-
onBlur: () =>
|
|
5477
|
+
onBlur: () => {
|
|
5478
|
+
setIsFocused(false);
|
|
5479
|
+
requestAnimationFrame(() => {
|
|
5480
|
+
if (!rootRef.current?.contains(document.activeElement)) {
|
|
5481
|
+
onDropdownOpenChange(false);
|
|
5482
|
+
}
|
|
5483
|
+
});
|
|
5484
|
+
},
|
|
5209
5485
|
placeholder,
|
|
5210
5486
|
className: cn(
|
|
5211
5487
|
"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",
|
|
@@ -5221,7 +5497,7 @@ function UrlOrPageInput({
|
|
|
5221
5497
|
onMouseDown: clearSelection,
|
|
5222
5498
|
"aria-label": "Clear selected page",
|
|
5223
5499
|
tabIndex: -1,
|
|
5224
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5500
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react7.X, { size: 16, "aria-hidden": true })
|
|
5225
5501
|
}
|
|
5226
5502
|
) : null,
|
|
5227
5503
|
!readOnly ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(FieldChevron, { onClick: toggleDropdown }) : null
|
|
@@ -5230,7 +5506,7 @@ function UrlOrPageInput({
|
|
|
5230
5506
|
"div",
|
|
5231
5507
|
{
|
|
5232
5508
|
"data-ohw-link-page-dropdown": "",
|
|
5233
|
-
className: "absolute left-0 right-0
|
|
5509
|
+
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",
|
|
5234
5510
|
onMouseDown: (e) => e.preventDefault(),
|
|
5235
5511
|
children: filteredPages.map((page) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
5236
5512
|
"button",
|
|
@@ -5239,7 +5515,7 @@ function UrlOrPageInput({
|
|
|
5239
5515
|
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",
|
|
5240
5516
|
onClick: () => onPageSelect(page),
|
|
5241
5517
|
children: [
|
|
5242
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5518
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react7.File, { size: 16, className: "shrink-0", "aria-hidden": true }),
|
|
5243
5519
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "truncate", children: page.title })
|
|
5244
5520
|
]
|
|
5245
5521
|
},
|
|
@@ -5252,38 +5528,375 @@ function UrlOrPageInput({
|
|
|
5252
5528
|
] });
|
|
5253
5529
|
}
|
|
5254
5530
|
|
|
5255
|
-
// src/ui/link-modal/
|
|
5256
|
-
var
|
|
5257
|
-
function
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
|
|
5265
|
-
|
|
5266
|
-
|
|
5267
|
-
|
|
5268
|
-
|
|
5269
|
-
|
|
5270
|
-
|
|
5271
|
-
|
|
5272
|
-
|
|
5273
|
-
|
|
5274
|
-
|
|
5275
|
-
|
|
5276
|
-
|
|
5277
|
-
|
|
5278
|
-
|
|
5279
|
-
|
|
5280
|
-
|
|
5531
|
+
// src/ui/link-modal/LinkEditorPanel.tsx
|
|
5532
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
5533
|
+
function LinkEditorPanel({ state, onClose }) {
|
|
5534
|
+
const isCancel = state.secondaryLabel === "Cancel" || state.secondaryLabel === "Back to sections";
|
|
5535
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
|
|
5536
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DialogClose, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
5537
|
+
"button",
|
|
5538
|
+
{
|
|
5539
|
+
type: "button",
|
|
5540
|
+
className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50 h-7",
|
|
5541
|
+
"aria-label": "Close",
|
|
5542
|
+
onClick: onClose,
|
|
5543
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react8.X, { size: 16, "aria-hidden": true })
|
|
5544
|
+
}
|
|
5545
|
+
) }),
|
|
5546
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DialogHeader, { className: "w-full gap-1.5 p-6 pr-12", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DialogTitle, { className: "m-0 w-full break-words", children: state.title }) }),
|
|
5547
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
|
|
5548
|
+
state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
5549
|
+
DestinationBreadcrumb,
|
|
5550
|
+
{
|
|
5551
|
+
pageTitle: state.selectedPage.title,
|
|
5552
|
+
sectionLabel: state.selectedSection.label
|
|
5553
|
+
}
|
|
5554
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
5555
|
+
UrlOrPageInput,
|
|
5556
|
+
{
|
|
5557
|
+
value: state.searchValue,
|
|
5558
|
+
selectedPage: state.selectedPage,
|
|
5559
|
+
dropdownOpen: state.dropdownOpen,
|
|
5560
|
+
onDropdownOpenChange: state.setDropdownOpen,
|
|
5561
|
+
filteredPages: state.filteredPages,
|
|
5562
|
+
onInputChange: state.handleInputChange,
|
|
5563
|
+
onPageSelect: state.handlePageSelect,
|
|
5564
|
+
urlError: state.urlError
|
|
5565
|
+
}
|
|
5566
|
+
),
|
|
5567
|
+
state.showChooseSection ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex flex-col justify-center gap-2", children: [
|
|
5568
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
5569
|
+
Button,
|
|
5570
|
+
{
|
|
5571
|
+
type: "button",
|
|
5572
|
+
variant: "outline",
|
|
5573
|
+
className: "w-fit cursor-pointer",
|
|
5574
|
+
size: "sm",
|
|
5575
|
+
onClick: state.handleChooseSection,
|
|
5576
|
+
children: "Choose a section"
|
|
5577
|
+
}
|
|
5578
|
+
),
|
|
5579
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
|
|
5580
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react8.Info, { size: 16, className: "shrink-0", "aria-hidden": true }),
|
|
5581
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: "Pick a section this link should scroll to." })
|
|
5582
|
+
] })
|
|
5583
|
+
] }) : null,
|
|
5584
|
+
state.showSectionRow && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
|
|
5585
|
+
] }),
|
|
5586
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(DialogFooter, { className: "w-full px-6 pb-6", children: [
|
|
5587
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
5588
|
+
Button,
|
|
5589
|
+
{
|
|
5590
|
+
type: "button",
|
|
5591
|
+
variant: isCancel ? "outline" : "ghost",
|
|
5592
|
+
className: "leading-6 shadow-none cursor-pointer",
|
|
5593
|
+
style: isCancel ? {
|
|
5594
|
+
backgroundColor: "var(--ohw-background)",
|
|
5595
|
+
borderColor: "var(--ohw-border)",
|
|
5596
|
+
color: "var(--ohw-foreground)"
|
|
5597
|
+
} : void 0,
|
|
5598
|
+
onClick: state.handleSecondary,
|
|
5599
|
+
children: state.secondaryLabel
|
|
5600
|
+
}
|
|
5601
|
+
),
|
|
5602
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
5603
|
+
Button,
|
|
5604
|
+
{
|
|
5605
|
+
type: "button",
|
|
5606
|
+
className: "border-0 leading-6 shadow-none hover:opacity-90 disabled:opacity-50 cursor-pointer",
|
|
5607
|
+
style: {
|
|
5608
|
+
backgroundColor: "var(--ohw-primary)",
|
|
5609
|
+
color: "var(--ohw-primary-foreground)"
|
|
5610
|
+
},
|
|
5611
|
+
disabled: !state.isValid,
|
|
5612
|
+
onClick: state.handleSubmit,
|
|
5613
|
+
children: state.submitLabel
|
|
5614
|
+
}
|
|
5615
|
+
)
|
|
5616
|
+
] })
|
|
5617
|
+
] });
|
|
5618
|
+
}
|
|
5619
|
+
|
|
5620
|
+
// src/ui/link-modal/SectionPickerOverlay.tsx
|
|
5621
|
+
var import_react5 = require("react");
|
|
5622
|
+
var import_react_dom = require("react-dom");
|
|
5623
|
+
var import_lucide_react9 = require("lucide-react");
|
|
5624
|
+
var import_navigation = require("next/navigation");
|
|
5625
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
5626
|
+
var DIM_OVERLAY = "rgba(0, 0, 0, 0.45)";
|
|
5627
|
+
function rectsEqual(a, b) {
|
|
5628
|
+
if (a.size !== b.size) return false;
|
|
5629
|
+
for (const [id, rect] of a) {
|
|
5630
|
+
const other = b.get(id);
|
|
5631
|
+
if (!other || rect.top !== other.top || rect.left !== other.left || rect.width !== other.width || rect.height !== other.height) {
|
|
5632
|
+
return false;
|
|
5633
|
+
}
|
|
5634
|
+
}
|
|
5635
|
+
return true;
|
|
5636
|
+
}
|
|
5637
|
+
function useSectionRects(sectionIdsKey, enabled) {
|
|
5638
|
+
const [rects, setRects] = (0, import_react5.useState)(/* @__PURE__ */ new Map());
|
|
5639
|
+
const sectionIds = (0, import_react5.useMemo)(
|
|
5640
|
+
() => sectionIdsKey ? sectionIdsKey.split("\0") : [],
|
|
5641
|
+
[sectionIdsKey]
|
|
5642
|
+
);
|
|
5643
|
+
(0, import_react5.useEffect)(() => {
|
|
5644
|
+
if (!enabled || sectionIds.length === 0) {
|
|
5645
|
+
setRects((prev) => prev.size === 0 ? prev : /* @__PURE__ */ new Map());
|
|
5646
|
+
return;
|
|
5647
|
+
}
|
|
5648
|
+
const update = () => {
|
|
5649
|
+
const next = /* @__PURE__ */ new Map();
|
|
5650
|
+
for (const id of sectionIds) {
|
|
5651
|
+
const el = document.querySelector(
|
|
5652
|
+
`[data-ohw-section="${CSS.escape(id)}"]`
|
|
5653
|
+
);
|
|
5654
|
+
if (el) next.set(id, el.getBoundingClientRect());
|
|
5655
|
+
}
|
|
5656
|
+
setRects((prev) => rectsEqual(prev, next) ? prev : next);
|
|
5657
|
+
};
|
|
5658
|
+
update();
|
|
5659
|
+
const opts = { capture: true, passive: true };
|
|
5660
|
+
window.addEventListener("scroll", update, opts);
|
|
5661
|
+
window.addEventListener("resize", update);
|
|
5662
|
+
const vv = window.visualViewport;
|
|
5663
|
+
vv?.addEventListener("resize", update);
|
|
5664
|
+
vv?.addEventListener("scroll", update);
|
|
5665
|
+
const ro = new ResizeObserver(update);
|
|
5666
|
+
for (const id of sectionIds) {
|
|
5667
|
+
const el = document.querySelector(
|
|
5668
|
+
`[data-ohw-section="${CSS.escape(id)}"]`
|
|
5669
|
+
);
|
|
5670
|
+
if (el) ro.observe(el);
|
|
5671
|
+
}
|
|
5672
|
+
return () => {
|
|
5673
|
+
window.removeEventListener("scroll", update, opts);
|
|
5674
|
+
window.removeEventListener("resize", update);
|
|
5675
|
+
vv?.removeEventListener("resize", update);
|
|
5676
|
+
vv?.removeEventListener("scroll", update);
|
|
5677
|
+
ro.disconnect();
|
|
5678
|
+
};
|
|
5679
|
+
}, [sectionIds, enabled]);
|
|
5680
|
+
return rects;
|
|
5681
|
+
}
|
|
5682
|
+
function SectionPickerOverlay({
|
|
5683
|
+
pagePath,
|
|
5684
|
+
sections,
|
|
5685
|
+
onBack,
|
|
5686
|
+
onSelect
|
|
5687
|
+
}) {
|
|
5688
|
+
const router = (0, import_navigation.useRouter)();
|
|
5689
|
+
const pathname = (0, import_navigation.usePathname)();
|
|
5690
|
+
const [selectedId, setSelectedId] = (0, import_react5.useState)(null);
|
|
5691
|
+
const [hoveredId, setHoveredId] = (0, import_react5.useState)(null);
|
|
5692
|
+
const [chromeClip, setChromeClip] = (0, import_react5.useState)(
|
|
5693
|
+
() => ({
|
|
5694
|
+
top: 0,
|
|
5695
|
+
bottom: typeof window !== "undefined" ? window.innerHeight : 0
|
|
5696
|
+
})
|
|
5697
|
+
);
|
|
5698
|
+
const normalizedTarget = normalizePath(pagePath);
|
|
5699
|
+
const isOnTargetPage = normalizePath(pathname) === normalizedTarget;
|
|
5700
|
+
(0, import_react5.useEffect)(() => {
|
|
5701
|
+
if (isOnTargetPage) return;
|
|
5702
|
+
const search = readPreservedSearch();
|
|
5703
|
+
router.push(`${normalizedTarget}${search}`);
|
|
5704
|
+
}, [isOnTargetPage, normalizedTarget, router]);
|
|
5705
|
+
(0, import_react5.useEffect)(() => {
|
|
5706
|
+
document.documentElement.setAttribute("data-ohw-section-picking", "");
|
|
5707
|
+
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => {
|
|
5708
|
+
el.removeAttribute("data-ohw-hovered");
|
|
5709
|
+
});
|
|
5710
|
+
return () => {
|
|
5711
|
+
document.documentElement.removeAttribute("data-ohw-section-picking");
|
|
5712
|
+
};
|
|
5713
|
+
}, []);
|
|
5714
|
+
(0, import_react5.useEffect)(() => {
|
|
5715
|
+
const applyClip = (iframeOffsetTop, visibleCanvasTop, canvasH) => {
|
|
5716
|
+
const top = Math.max(0, visibleCanvasTop - iframeOffsetTop);
|
|
5717
|
+
const bottom = Math.min(
|
|
5718
|
+
window.innerHeight,
|
|
5719
|
+
visibleCanvasTop + canvasH - iframeOffsetTop
|
|
5720
|
+
);
|
|
5721
|
+
setChromeClip(
|
|
5722
|
+
(prev) => prev.top === top && prev.bottom === bottom ? prev : { top, bottom: Math.max(top, bottom) }
|
|
5723
|
+
);
|
|
5724
|
+
};
|
|
5725
|
+
const onParentScroll = (e) => {
|
|
5726
|
+
if (e.data?.type !== "ow:parent-scroll") return;
|
|
5727
|
+
const { iframeOffsetTop, headerH, canvasH } = e.data;
|
|
5728
|
+
applyClip(iframeOffsetTop, headerH, canvasH);
|
|
5729
|
+
};
|
|
5730
|
+
const onResize = () => {
|
|
5731
|
+
setChromeClip((prev) => {
|
|
5732
|
+
const bottom = Math.max(prev.top, window.innerHeight);
|
|
5733
|
+
return prev.bottom === bottom ? prev : { ...prev, bottom };
|
|
5734
|
+
});
|
|
5735
|
+
};
|
|
5736
|
+
window.addEventListener("message", onParentScroll);
|
|
5737
|
+
window.addEventListener("resize", onResize);
|
|
5738
|
+
return () => {
|
|
5739
|
+
window.removeEventListener("message", onParentScroll);
|
|
5740
|
+
window.removeEventListener("resize", onResize);
|
|
5741
|
+
};
|
|
5742
|
+
}, []);
|
|
5743
|
+
const liveSections = (0, import_react5.useMemo)(() => {
|
|
5744
|
+
if (!isOnTargetPage) return sections;
|
|
5745
|
+
const live = collectSectionsFromDom();
|
|
5746
|
+
if (live.length === 0) return sections;
|
|
5747
|
+
const labels = new Map(sections.map((s) => [s.id, s.label]));
|
|
5748
|
+
return live.map((s) => ({ id: s.id, label: labels.get(s.id) ?? s.label }));
|
|
5749
|
+
}, [isOnTargetPage, sections, pathname]);
|
|
5750
|
+
const sectionIdsKey = (0, import_react5.useMemo)(
|
|
5751
|
+
() => liveSections.map((s) => s.id).join("\0"),
|
|
5752
|
+
[liveSections]
|
|
5753
|
+
);
|
|
5754
|
+
const rects = useSectionRects(sectionIdsKey, isOnTargetPage);
|
|
5755
|
+
const handleSelect = (0, import_react5.useCallback)(
|
|
5756
|
+
(section) => {
|
|
5757
|
+
if (selectedId) return;
|
|
5758
|
+
setSelectedId(section.id);
|
|
5759
|
+
onSelect(section);
|
|
5760
|
+
},
|
|
5761
|
+
[selectedId, onSelect]
|
|
5762
|
+
);
|
|
5763
|
+
(0, import_react5.useEffect)(() => {
|
|
5764
|
+
const onKeyDown = (e) => {
|
|
5765
|
+
if (e.key === "Escape") {
|
|
5766
|
+
e.preventDefault();
|
|
5767
|
+
e.stopPropagation();
|
|
5768
|
+
onBack();
|
|
5769
|
+
}
|
|
5770
|
+
};
|
|
5771
|
+
window.addEventListener("keydown", onKeyDown, true);
|
|
5772
|
+
return () => window.removeEventListener("keydown", onKeyDown, true);
|
|
5773
|
+
}, [onBack]);
|
|
5774
|
+
const portalRoot = typeof document !== "undefined" ? document.querySelector("[data-ohw-bridge-root]") ?? document.body : null;
|
|
5775
|
+
if (!portalRoot) return null;
|
|
5776
|
+
return (0, import_react_dom.createPortal)(
|
|
5777
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
5778
|
+
"div",
|
|
5779
|
+
{
|
|
5780
|
+
"data-ohw-section-picker": "",
|
|
5781
|
+
"data-ohw-bridge": "",
|
|
5782
|
+
className: `pointer-events-none fixed inset-0 z-[2147483647] transition-opacity duration-200 ${"opacity-100"}`,
|
|
5783
|
+
"aria-modal": true,
|
|
5784
|
+
role: "dialog",
|
|
5785
|
+
"aria-label": "Choose a section",
|
|
5786
|
+
children: [
|
|
5787
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5788
|
+
"div",
|
|
5789
|
+
{
|
|
5790
|
+
className: "pointer-events-auto fixed left-5 z-[2]",
|
|
5791
|
+
style: { top: chromeClip.top + 20 },
|
|
5792
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
5793
|
+
Button,
|
|
5794
|
+
{
|
|
5795
|
+
type: "button",
|
|
5796
|
+
variant: "outline",
|
|
5797
|
+
size: "sm",
|
|
5798
|
+
className: "h-8 min-w-0 gap-1 border-border bg-background px-2 py-1.5 shadow-sm hover:bg-muted cursor-pointer",
|
|
5799
|
+
onClick: onBack,
|
|
5800
|
+
children: [
|
|
5801
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react9.ArrowLeft, { className: "size-4 shrink-0", "aria-hidden": true }),
|
|
5802
|
+
"Back"
|
|
5803
|
+
]
|
|
5804
|
+
}
|
|
5805
|
+
)
|
|
5806
|
+
}
|
|
5807
|
+
),
|
|
5808
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5809
|
+
"div",
|
|
5810
|
+
{
|
|
5811
|
+
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",
|
|
5812
|
+
style: {
|
|
5813
|
+
top: chromeClip.bottom - 20,
|
|
5814
|
+
transform: "translate(-50%, -100%)",
|
|
5815
|
+
backgroundColor: "var(--ohw-popover-foreground, #0c0a09)"
|
|
5816
|
+
},
|
|
5817
|
+
"data-ohw-section-picker-hint": "",
|
|
5818
|
+
children: "Click on section to select"
|
|
5819
|
+
}
|
|
5820
|
+
),
|
|
5821
|
+
!isOnTargetPage ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5822
|
+
"div",
|
|
5823
|
+
{
|
|
5824
|
+
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",
|
|
5825
|
+
style: { top: chromeClip.top + 64 },
|
|
5826
|
+
children: "Loading page preview\u2026"
|
|
5827
|
+
}
|
|
5828
|
+
) : null,
|
|
5829
|
+
isOnTargetPage && liveSections.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "pointer-events-auto fixed inset-0 z-[1] flex items-center justify-center bg-muted/40", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." }) }) : null,
|
|
5830
|
+
isOnTargetPage ? liveSections.map((section) => {
|
|
5831
|
+
const rect = rects.get(section.id);
|
|
5832
|
+
if (!rect || rect.width <= 0 || rect.height <= 0) return null;
|
|
5833
|
+
const isSelected = selectedId === section.id;
|
|
5834
|
+
const isLit = isSelected || hoveredId === section.id;
|
|
5835
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5836
|
+
"button",
|
|
5837
|
+
{
|
|
5838
|
+
type: "button",
|
|
5839
|
+
className: "pointer-events-auto fixed z-[1] cursor-pointer border-0 bg-transparent p-0 transition-[background-color] duration-150",
|
|
5840
|
+
style: {
|
|
5841
|
+
top: rect.top,
|
|
5842
|
+
left: rect.left,
|
|
5843
|
+
width: rect.width,
|
|
5844
|
+
height: rect.height,
|
|
5845
|
+
backgroundColor: isLit ? "transparent" : DIM_OVERLAY
|
|
5846
|
+
},
|
|
5847
|
+
"aria-label": `Select section ${section.label}`,
|
|
5848
|
+
onMouseEnter: () => setHoveredId(section.id),
|
|
5849
|
+
onMouseLeave: () => setHoveredId((prev) => prev === section.id ? null : prev),
|
|
5850
|
+
onClick: () => handleSelect(section),
|
|
5851
|
+
children: isSelected ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5852
|
+
"span",
|
|
5853
|
+
{
|
|
5854
|
+
className: "absolute right-3 top-3 flex size-8 items-center justify-center rounded-full text-white",
|
|
5855
|
+
style: { backgroundColor: "var(--ohw-primary, #0885fe)" },
|
|
5856
|
+
"aria-hidden": true,
|
|
5857
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react9.Check, { className: "size-5" })
|
|
5858
|
+
}
|
|
5859
|
+
) : null
|
|
5860
|
+
},
|
|
5861
|
+
section.id
|
|
5862
|
+
);
|
|
5863
|
+
}) : null
|
|
5864
|
+
]
|
|
5865
|
+
}
|
|
5866
|
+
),
|
|
5867
|
+
portalRoot
|
|
5868
|
+
);
|
|
5869
|
+
}
|
|
5870
|
+
|
|
5871
|
+
// src/ui/link-modal/useLinkModalState.ts
|
|
5872
|
+
var import_react6 = require("react");
|
|
5873
|
+
function useLinkModalState({
|
|
5874
|
+
open,
|
|
5875
|
+
mode,
|
|
5876
|
+
pages,
|
|
5877
|
+
sections: _sections,
|
|
5878
|
+
sectionsByPath,
|
|
5879
|
+
initialTarget,
|
|
5880
|
+
existingTargets: _existingTargets,
|
|
5881
|
+
onClose,
|
|
5882
|
+
onSubmit
|
|
5883
|
+
}) {
|
|
5884
|
+
const availablePages = (0, import_react6.useMemo)(() => pages, [pages]);
|
|
5885
|
+
const [searchValue, setSearchValue] = (0, import_react6.useState)("");
|
|
5886
|
+
const [selectedPage, setSelectedPage] = (0, import_react6.useState)(null);
|
|
5887
|
+
const [selectedSection, setSelectedSection] = (0, import_react6.useState)(null);
|
|
5888
|
+
const [step, setStep] = (0, import_react6.useState)("input");
|
|
5889
|
+
const [dropdownOpen, setDropdownOpen] = (0, import_react6.useState)(false);
|
|
5890
|
+
const [urlError, setUrlError] = (0, import_react6.useState)("");
|
|
5891
|
+
const reset = (0, import_react6.useCallback)(() => {
|
|
5892
|
+
setSearchValue("");
|
|
5893
|
+
setSelectedPage(null);
|
|
5281
5894
|
setSelectedSection(null);
|
|
5282
5895
|
setStep("input");
|
|
5283
5896
|
setDropdownOpen(false);
|
|
5284
5897
|
setUrlError("");
|
|
5285
5898
|
}, []);
|
|
5286
|
-
(0,
|
|
5899
|
+
(0, import_react6.useEffect)(() => {
|
|
5287
5900
|
if (!open) return;
|
|
5288
5901
|
if (mode === "edit" && initialTarget) {
|
|
5289
5902
|
const { pageRoute } = parseTarget(initialTarget);
|
|
@@ -5298,12 +5911,12 @@ function useLinkModalState({
|
|
|
5298
5911
|
}
|
|
5299
5912
|
setDropdownOpen(false);
|
|
5300
5913
|
setUrlError("");
|
|
5301
|
-
}, [open, mode, initialTarget,
|
|
5302
|
-
const filteredPages = (0,
|
|
5914
|
+
}, [open, mode, initialTarget, reset]);
|
|
5915
|
+
const filteredPages = (0, import_react6.useMemo)(() => {
|
|
5303
5916
|
if (!searchValue.trim()) return availablePages;
|
|
5304
5917
|
return availablePages.filter((p) => p.title.toLowerCase().startsWith(searchValue.toLowerCase()));
|
|
5305
5918
|
}, [availablePages, searchValue]);
|
|
5306
|
-
const activeSections = (0,
|
|
5919
|
+
const activeSections = (0, import_react6.useMemo)(() => {
|
|
5307
5920
|
if (!selectedPage) return [];
|
|
5308
5921
|
return getSectionsForPath(sectionsByPath, selectedPage.path);
|
|
5309
5922
|
}, [selectedPage, sectionsByPath]);
|
|
@@ -5345,11 +5958,14 @@ function useLinkModalState({
|
|
|
5345
5958
|
const handleBackToSections = () => {
|
|
5346
5959
|
setStep("sectionPicker");
|
|
5347
5960
|
};
|
|
5961
|
+
const handleSectionPickerBack = () => {
|
|
5962
|
+
setStep("input");
|
|
5963
|
+
};
|
|
5348
5964
|
const handleClose = () => {
|
|
5349
5965
|
reset();
|
|
5350
5966
|
onClose();
|
|
5351
5967
|
};
|
|
5352
|
-
const isValid = (0,
|
|
5968
|
+
const isValid = (0, import_react6.useMemo)(() => {
|
|
5353
5969
|
if (urlError) return false;
|
|
5354
5970
|
if (showBreadcrumb) return true;
|
|
5355
5971
|
if (selectedPage) return true;
|
|
@@ -5382,7 +5998,7 @@ function useLinkModalState({
|
|
|
5382
5998
|
onSubmit(normalizeUrl(searchValue));
|
|
5383
5999
|
handleClose();
|
|
5384
6000
|
};
|
|
5385
|
-
const submitLabel = mode === "edit" ? "Save" : "Create";
|
|
6001
|
+
const submitLabel = showBreadcrumb ? "Save" : mode === "edit" ? "Save" : "Create";
|
|
5386
6002
|
const title = mode === "edit" ? "Edit navigation item" : "Create navigation item";
|
|
5387
6003
|
const secondaryLabel = showBreadcrumb ? "Back to sections" : "Cancel";
|
|
5388
6004
|
const handleSecondary = showBreadcrumb ? handleBackToSections : handleClose;
|
|
@@ -5409,23 +6025,29 @@ function useLinkModalState({
|
|
|
5409
6025
|
handleChooseSection,
|
|
5410
6026
|
handleSectionSelect,
|
|
5411
6027
|
handleBackToSections,
|
|
6028
|
+
handleSectionPickerBack,
|
|
5412
6029
|
handleClose,
|
|
5413
6030
|
handleSecondary,
|
|
5414
6031
|
handleSubmit
|
|
5415
6032
|
};
|
|
5416
6033
|
}
|
|
5417
6034
|
|
|
5418
|
-
// src/ui/link-modal/
|
|
5419
|
-
var
|
|
5420
|
-
function
|
|
6035
|
+
// src/ui/link-modal/LinkPopover.tsx
|
|
6036
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
6037
|
+
function postToParent(data) {
|
|
6038
|
+
window.parent?.postMessage(data, "*");
|
|
6039
|
+
}
|
|
6040
|
+
function LinkPopover({
|
|
5421
6041
|
open = true,
|
|
6042
|
+
panelRef,
|
|
6043
|
+
portalContainer,
|
|
6044
|
+
onClose,
|
|
5422
6045
|
mode = "create",
|
|
5423
6046
|
pages,
|
|
5424
6047
|
sections = [],
|
|
5425
6048
|
sectionsByPath,
|
|
5426
6049
|
initialTarget,
|
|
5427
6050
|
existingTargets = [],
|
|
5428
|
-
onClose,
|
|
5429
6051
|
onSubmit
|
|
5430
6052
|
}) {
|
|
5431
6053
|
const state = useLinkModalState({
|
|
@@ -5439,115 +6061,100 @@ function LinkEditorPanel({
|
|
|
5439
6061
|
onClose,
|
|
5440
6062
|
onSubmit
|
|
5441
6063
|
});
|
|
5442
|
-
const
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
6064
|
+
const sectionPickerActive = state.showSectionPicker && Boolean(state.selectedPage);
|
|
6065
|
+
(0, import_react7.useEffect)(() => {
|
|
6066
|
+
if (!open) return;
|
|
6067
|
+
if (sectionPickerActive) {
|
|
6068
|
+
postToParent({ type: "ow:link-modal-lock", locked: false });
|
|
6069
|
+
postToParent({ type: "ow:section-picker", active: true });
|
|
6070
|
+
document.documentElement.style.overflow = "";
|
|
6071
|
+
document.body.style.overflow = "";
|
|
6072
|
+
return () => {
|
|
6073
|
+
postToParent({ type: "ow:section-picker", active: false });
|
|
6074
|
+
};
|
|
6075
|
+
}
|
|
6076
|
+
postToParent({ type: "ow:section-picker", active: false });
|
|
6077
|
+
postToParent({ type: "ow:link-modal-lock", locked: true });
|
|
6078
|
+
const html = document.documentElement;
|
|
6079
|
+
const body = document.body;
|
|
6080
|
+
const prevHtmlOverflow = html.style.overflow;
|
|
6081
|
+
const prevBodyOverflow = body.style.overflow;
|
|
6082
|
+
const prevHtmlOverscroll = html.style.overscrollBehavior;
|
|
6083
|
+
const prevBodyOverscroll = body.style.overscrollBehavior;
|
|
6084
|
+
html.style.overflow = "hidden";
|
|
6085
|
+
body.style.overflow = "hidden";
|
|
6086
|
+
html.style.overscrollBehavior = "none";
|
|
6087
|
+
body.style.overscrollBehavior = "none";
|
|
6088
|
+
const canScrollElement = (el, deltaY) => {
|
|
6089
|
+
const { overflowY } = getComputedStyle(el);
|
|
6090
|
+
if (overflowY !== "auto" && overflowY !== "scroll") return false;
|
|
6091
|
+
if (el.scrollHeight <= el.clientHeight + 1) return false;
|
|
6092
|
+
if (deltaY < 0) return el.scrollTop > 0;
|
|
6093
|
+
if (deltaY > 0) return el.scrollTop + el.clientHeight < el.scrollHeight - 1;
|
|
6094
|
+
return true;
|
|
6095
|
+
};
|
|
6096
|
+
const allowsInternalScroll = (e) => {
|
|
6097
|
+
const target = e.target;
|
|
6098
|
+
if (!(target instanceof Element)) return false;
|
|
6099
|
+
const scrollRoot = target.closest(
|
|
6100
|
+
"[data-ohw-link-page-dropdown], [data-ohw-allow-scroll]"
|
|
6101
|
+
);
|
|
6102
|
+
if (!scrollRoot) return false;
|
|
6103
|
+
const deltaY = e instanceof WheelEvent ? e.deltaY : 0;
|
|
6104
|
+
return canScrollElement(scrollRoot, deltaY);
|
|
6105
|
+
};
|
|
6106
|
+
const preventBackgroundScroll = (e) => {
|
|
6107
|
+
if (allowsInternalScroll(e)) return;
|
|
6108
|
+
e.preventDefault();
|
|
6109
|
+
};
|
|
6110
|
+
const scrollOpts = { passive: false, capture: true };
|
|
6111
|
+
document.addEventListener("wheel", preventBackgroundScroll, scrollOpts);
|
|
6112
|
+
document.addEventListener("touchmove", preventBackgroundScroll, scrollOpts);
|
|
6113
|
+
return () => {
|
|
6114
|
+
postToParent({ type: "ow:link-modal-lock", locked: false });
|
|
6115
|
+
html.style.overflow = prevHtmlOverflow;
|
|
6116
|
+
body.style.overflow = prevBodyOverflow;
|
|
6117
|
+
html.style.overscrollBehavior = prevHtmlOverscroll;
|
|
6118
|
+
body.style.overscrollBehavior = prevBodyOverscroll;
|
|
6119
|
+
document.removeEventListener("wheel", preventBackgroundScroll, scrollOpts);
|
|
6120
|
+
document.removeEventListener("touchmove", preventBackgroundScroll, scrollOpts);
|
|
6121
|
+
};
|
|
6122
|
+
}, [open, sectionPickerActive]);
|
|
6123
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
|
|
6124
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
6125
|
+
Dialog2,
|
|
5446
6126
|
{
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
6127
|
+
open: open && !sectionPickerActive,
|
|
6128
|
+
onOpenChange: (next) => {
|
|
6129
|
+
if (!next) onClose?.();
|
|
6130
|
+
},
|
|
6131
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
6132
|
+
DialogContent,
|
|
6133
|
+
{
|
|
6134
|
+
ref: panelRef,
|
|
6135
|
+
container: portalContainer,
|
|
6136
|
+
"data-ohw-link-popover-root": "",
|
|
6137
|
+
"data-ohw-link-modal-root": "",
|
|
6138
|
+
"data-ohw-bridge": "",
|
|
6139
|
+
showCloseButton: false,
|
|
6140
|
+
className: "gap-0 p-0 w-full md:w-md pointer-events-auto z-[2147483646] overflow-visible",
|
|
6141
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(LinkEditorPanel, { state, onClose })
|
|
6142
|
+
}
|
|
6143
|
+
)
|
|
5451
6144
|
}
|
|
5452
|
-
)
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
UrlOrPageInput,
|
|
5463
|
-
{
|
|
5464
|
-
value: state.searchValue,
|
|
5465
|
-
selectedPage: state.selectedPage,
|
|
5466
|
-
dropdownOpen: state.dropdownOpen,
|
|
5467
|
-
onDropdownOpenChange: state.setDropdownOpen,
|
|
5468
|
-
filteredPages: state.filteredPages,
|
|
5469
|
-
onInputChange: state.handleInputChange,
|
|
5470
|
-
onPageSelect: state.handlePageSelect,
|
|
5471
|
-
urlError: state.urlError
|
|
5472
|
-
}
|
|
5473
|
-
),
|
|
5474
|
-
state.showChooseSection ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex flex-col justify-center gap-2", children: [
|
|
5475
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { type: "button", variant: "outline", className: "w-fit cursor-pointer", size: "sm", onClick: state.handleChooseSection, children: "Choose a section" }),
|
|
5476
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
|
|
5477
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(IconInfo, { className: "shrink-0", "aria-hidden": true }),
|
|
5478
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: "Pick a section this link should scroll to." })
|
|
5479
|
-
] })
|
|
5480
|
-
] }) : null,
|
|
5481
|
-
state.showSectionPicker ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SectionPickerList, { sections: state.activeSections, onSelect: state.handleSectionSelect }) : null,
|
|
5482
|
-
state.showSectionRow && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
|
|
5483
|
-
] }),
|
|
5484
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(DialogFooter, { className: "w-full px-6 pb-6", children: [
|
|
5485
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
5486
|
-
Button,
|
|
5487
|
-
{
|
|
5488
|
-
type: "button",
|
|
5489
|
-
variant: isCancel ? "outline" : "ghost",
|
|
5490
|
-
className: "leading-6 shadow-none cursor-pointer",
|
|
5491
|
-
style: isCancel ? {
|
|
5492
|
-
backgroundColor: "var(--ohw-background)",
|
|
5493
|
-
borderColor: "var(--ohw-border)",
|
|
5494
|
-
color: "var(--ohw-foreground)"
|
|
5495
|
-
} : void 0,
|
|
5496
|
-
onClick: state.handleSecondary,
|
|
5497
|
-
children: state.secondaryLabel
|
|
5498
|
-
}
|
|
5499
|
-
),
|
|
5500
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
5501
|
-
Button,
|
|
5502
|
-
{
|
|
5503
|
-
type: "button",
|
|
5504
|
-
className: "border-0 leading-6 shadow-none hover:opacity-90 disabled:opacity-50 cursor-pointer",
|
|
5505
|
-
style: {
|
|
5506
|
-
backgroundColor: "var(--ohw-primary)",
|
|
5507
|
-
color: "var(--ohw-primary-foreground)"
|
|
5508
|
-
},
|
|
5509
|
-
disabled: !state.isValid,
|
|
5510
|
-
onClick: state.handleSubmit,
|
|
5511
|
-
children: state.submitLabel
|
|
5512
|
-
}
|
|
5513
|
-
)
|
|
5514
|
-
] })
|
|
6145
|
+
),
|
|
6146
|
+
sectionPickerActive && state.selectedPage ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
6147
|
+
SectionPickerOverlay,
|
|
6148
|
+
{
|
|
6149
|
+
pagePath: state.selectedPage.path,
|
|
6150
|
+
sections: state.activeSections,
|
|
6151
|
+
onBack: state.handleSectionPickerBack,
|
|
6152
|
+
onSelect: state.handleSectionSelect
|
|
6153
|
+
}
|
|
6154
|
+
) : null
|
|
5515
6155
|
] });
|
|
5516
6156
|
}
|
|
5517
6157
|
|
|
5518
|
-
// src/ui/link-modal/LinkPopover.tsx
|
|
5519
|
-
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
5520
|
-
function LinkPopover({
|
|
5521
|
-
open = true,
|
|
5522
|
-
panelRef,
|
|
5523
|
-
portalContainer,
|
|
5524
|
-
onClose,
|
|
5525
|
-
...editorProps
|
|
5526
|
-
}) {
|
|
5527
|
-
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5528
|
-
Dialog2,
|
|
5529
|
-
{
|
|
5530
|
-
open,
|
|
5531
|
-
onOpenChange: (next) => {
|
|
5532
|
-
if (!next) onClose?.();
|
|
5533
|
-
},
|
|
5534
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5535
|
-
DialogContent,
|
|
5536
|
-
{
|
|
5537
|
-
ref: panelRef,
|
|
5538
|
-
container: portalContainer,
|
|
5539
|
-
"data-ohw-link-popover-root": "",
|
|
5540
|
-
"data-ohw-link-modal-root": "",
|
|
5541
|
-
"data-ohw-bridge": "",
|
|
5542
|
-
showCloseButton: false,
|
|
5543
|
-
className: "gap-0 p-0 w-full md:w-md pointer-events-auto",
|
|
5544
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(LinkEditorPanel, { ...editorProps, open, onClose })
|
|
5545
|
-
}
|
|
5546
|
-
)
|
|
5547
|
-
}
|
|
5548
|
-
);
|
|
5549
|
-
}
|
|
5550
|
-
|
|
5551
6158
|
// src/ui/link-modal/devFixtures.ts
|
|
5552
6159
|
var DEV_SITE_PAGES = [
|
|
5553
6160
|
{ path: "/", title: "Home" },
|
|
@@ -5567,16 +6174,21 @@ var DEV_SECTIONS_BY_PATH = {
|
|
|
5567
6174
|
{ id: "founder-teaser", label: "Founder" },
|
|
5568
6175
|
{ id: "plan-form", label: "Plan Form" },
|
|
5569
6176
|
{ id: "testimonials", label: "Testimonials" },
|
|
5570
|
-
{ id: "wordmark", label: "Wordmark" }
|
|
6177
|
+
{ id: "wordmark", label: "Wordmark" },
|
|
6178
|
+
{ id: "footer", label: "Footer" }
|
|
5571
6179
|
],
|
|
5572
6180
|
"/about": [
|
|
5573
6181
|
{ id: "manifesto", label: "Manifesto" },
|
|
5574
6182
|
{ id: "story-letter", label: "Our Story" },
|
|
5575
6183
|
{ id: "lagree-explainer", label: "Lagree Explainer" },
|
|
5576
6184
|
{ id: "waitlist-cta", label: "Waitlist" },
|
|
5577
|
-
{ id: "personal-training", label: "Personal training" }
|
|
6185
|
+
{ id: "personal-training", label: "Personal training" },
|
|
6186
|
+
{ id: "footer", label: "Footer" }
|
|
6187
|
+
],
|
|
6188
|
+
"/classes": [
|
|
6189
|
+
{ id: "class-library", label: "Class Library" },
|
|
6190
|
+
{ id: "footer", label: "Footer" }
|
|
5578
6191
|
],
|
|
5579
|
-
"/classes": [{ id: "class-library", label: "Class Library" }],
|
|
5580
6192
|
"/pricing": [
|
|
5581
6193
|
{ id: "page-header", label: "Page Header" },
|
|
5582
6194
|
{ id: "free-class-cta", label: "Free Class" },
|
|
@@ -5584,19 +6196,25 @@ var DEV_SECTIONS_BY_PATH = {
|
|
|
5584
6196
|
{ id: "monthly-memberships", label: "Memberships" },
|
|
5585
6197
|
{ id: "specialty-programs", label: "Specialty Programs" },
|
|
5586
6198
|
{ id: "package-matcher", label: "Packages" },
|
|
5587
|
-
{ id: "wordmark", label: "Wordmark" }
|
|
6199
|
+
{ id: "wordmark", label: "Wordmark" },
|
|
6200
|
+
{ id: "footer", label: "Footer" }
|
|
5588
6201
|
],
|
|
5589
6202
|
"/studio": [
|
|
5590
6203
|
{ id: "studio-intro", label: "Studio Intro" },
|
|
5591
6204
|
{ id: "studio-features", label: "Studio Features" },
|
|
5592
6205
|
{ id: "studio-gallery", label: "Studio Gallery" },
|
|
5593
|
-
{ id: "studio-visit", label: "Visit Studio" }
|
|
6206
|
+
{ id: "studio-visit", label: "Visit Studio" },
|
|
6207
|
+
{ id: "footer", label: "Footer" }
|
|
6208
|
+
],
|
|
6209
|
+
"/instructors": [
|
|
6210
|
+
{ id: "instructor-grid", label: "Instructors" },
|
|
6211
|
+
{ id: "footer", label: "Footer" }
|
|
5594
6212
|
],
|
|
5595
|
-
"/instructors": [{ id: "instructor-grid", label: "Instructors" }],
|
|
5596
6213
|
"/contact": [
|
|
5597
6214
|
{ id: "hello-hero", label: "Hello" },
|
|
5598
6215
|
{ id: "contact-form", label: "Contact Form" },
|
|
5599
|
-
{ id: "faq", label: "FAQ" }
|
|
6216
|
+
{ id: "faq", label: "FAQ" },
|
|
6217
|
+
{ id: "footer", label: "Footer" }
|
|
5600
6218
|
]
|
|
5601
6219
|
};
|
|
5602
6220
|
function shouldUseDevFixtures() {
|
|
@@ -5606,8 +6224,277 @@ function shouldUseDevFixtures() {
|
|
|
5606
6224
|
return new URLSearchParams(q).get("ohw-fixtures") === "1";
|
|
5607
6225
|
}
|
|
5608
6226
|
|
|
6227
|
+
// src/lib/nav-items.ts
|
|
6228
|
+
var NAV_COUNT_KEY = "__ohw_nav_count";
|
|
6229
|
+
var NAV_ORDER_KEY = "__ohw_nav_order";
|
|
6230
|
+
function getLinkHref(el) {
|
|
6231
|
+
const key = el.getAttribute("data-ohw-href-key");
|
|
6232
|
+
if (key) {
|
|
6233
|
+
const stored = getStoredLinkHref(key);
|
|
6234
|
+
if (stored !== void 0) return stored;
|
|
6235
|
+
}
|
|
6236
|
+
return el.getAttribute("href") ?? "";
|
|
6237
|
+
}
|
|
6238
|
+
function isNavbarButton(el) {
|
|
6239
|
+
return el.hasAttribute("data-ohw-role") && el.getAttribute("data-ohw-role") === "navbar-button";
|
|
6240
|
+
}
|
|
6241
|
+
function isNavbarLinkItem(el) {
|
|
6242
|
+
if (!el.matches("[data-ohw-href-key]")) return false;
|
|
6243
|
+
if (isNavbarButton(el)) return false;
|
|
6244
|
+
if (!el.querySelector('[data-ohw-editable="text"]')) return false;
|
|
6245
|
+
return Boolean(el.closest("nav, [data-ohw-nav-container], [data-ohw-nav-drawer]"));
|
|
6246
|
+
}
|
|
6247
|
+
function getNavbarDesktopContainer() {
|
|
6248
|
+
return document.querySelector("[data-ohw-nav-container]");
|
|
6249
|
+
}
|
|
6250
|
+
function getNavbarDrawerContainer() {
|
|
6251
|
+
return document.querySelector("[data-ohw-nav-drawer]");
|
|
6252
|
+
}
|
|
6253
|
+
function listNavbarItems() {
|
|
6254
|
+
const desktop = getNavbarDesktopContainer();
|
|
6255
|
+
if (desktop) {
|
|
6256
|
+
return Array.from(desktop.querySelectorAll("[data-ohw-href-key]")).filter(isNavbarLinkItem);
|
|
6257
|
+
}
|
|
6258
|
+
const drawer = getNavbarDrawerContainer();
|
|
6259
|
+
if (drawer) {
|
|
6260
|
+
return Array.from(drawer.querySelectorAll("[data-ohw-href-key]")).filter(isNavbarLinkItem);
|
|
6261
|
+
}
|
|
6262
|
+
return Array.from(document.querySelectorAll("nav [data-ohw-href-key]")).filter(isNavbarLinkItem);
|
|
6263
|
+
}
|
|
6264
|
+
function parseNavIndexFromKey(key) {
|
|
6265
|
+
if (!key) return null;
|
|
6266
|
+
const match = key.match(/^nav-(\d+)-href$/);
|
|
6267
|
+
if (!match) return null;
|
|
6268
|
+
return parseInt(match[1], 10);
|
|
6269
|
+
}
|
|
6270
|
+
function getNavbarIndicesInDom() {
|
|
6271
|
+
const indices = /* @__PURE__ */ new Set();
|
|
6272
|
+
for (const item of listNavbarItems()) {
|
|
6273
|
+
const idx = parseNavIndexFromKey(item.getAttribute("data-ohw-href-key"));
|
|
6274
|
+
if (idx !== null) indices.add(idx);
|
|
6275
|
+
}
|
|
6276
|
+
return [...indices].sort((a, b) => a - b);
|
|
6277
|
+
}
|
|
6278
|
+
function getNextNavbarIndex() {
|
|
6279
|
+
const indices = getNavbarIndicesInDom();
|
|
6280
|
+
if (indices.length === 0) return 0;
|
|
6281
|
+
return Math.max(...indices) + 1;
|
|
6282
|
+
}
|
|
6283
|
+
function getNavbarExistingTargets() {
|
|
6284
|
+
return listNavbarItems().map((el) => getLinkHref(el)).filter(Boolean);
|
|
6285
|
+
}
|
|
6286
|
+
function getNavOrderFromDom() {
|
|
6287
|
+
return listNavbarItems().map((el) => el.getAttribute("data-ohw-href-key")).filter((key) => Boolean(key));
|
|
6288
|
+
}
|
|
6289
|
+
function parseNavOrder(content) {
|
|
6290
|
+
const raw = content[NAV_ORDER_KEY];
|
|
6291
|
+
if (!raw) return null;
|
|
6292
|
+
try {
|
|
6293
|
+
const parsed = JSON.parse(raw);
|
|
6294
|
+
if (!Array.isArray(parsed)) return null;
|
|
6295
|
+
return parsed.filter((key) => typeof key === "string" && key.length > 0);
|
|
6296
|
+
} catch {
|
|
6297
|
+
return null;
|
|
6298
|
+
}
|
|
6299
|
+
}
|
|
6300
|
+
function findCounterpartByHrefKey(hrefKey, root) {
|
|
6301
|
+
return root.querySelector(`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`);
|
|
6302
|
+
}
|
|
6303
|
+
function cloneNavLinkShell(template) {
|
|
6304
|
+
const anchor = document.createElement("a");
|
|
6305
|
+
if (template) {
|
|
6306
|
+
anchor.style.cssText = template.style.cssText;
|
|
6307
|
+
if (template.className) anchor.className = template.className;
|
|
6308
|
+
}
|
|
6309
|
+
anchor.style.cursor = "pointer";
|
|
6310
|
+
anchor.style.textDecoration = "none";
|
|
6311
|
+
return anchor;
|
|
6312
|
+
}
|
|
6313
|
+
function buildNavLink(index, href, label, template) {
|
|
6314
|
+
const anchor = cloneNavLinkShell(template);
|
|
6315
|
+
anchor.href = href;
|
|
6316
|
+
anchor.setAttribute("data-ohw-href-key", `nav-${index}-href`);
|
|
6317
|
+
const span = document.createElement("span");
|
|
6318
|
+
span.setAttribute("data-ohw-editable", "text");
|
|
6319
|
+
span.setAttribute("data-ohw-key", `nav-${index}-label`);
|
|
6320
|
+
span.textContent = label;
|
|
6321
|
+
anchor.appendChild(span);
|
|
6322
|
+
return anchor;
|
|
6323
|
+
}
|
|
6324
|
+
function insertNavLinkInContainer(container, anchor, afterHrefKey) {
|
|
6325
|
+
if (!afterHrefKey) {
|
|
6326
|
+
container.appendChild(anchor);
|
|
6327
|
+
return;
|
|
6328
|
+
}
|
|
6329
|
+
const afterEl = findCounterpartByHrefKey(afterHrefKey, container);
|
|
6330
|
+
if (afterEl?.parentElement === container) {
|
|
6331
|
+
afterEl.insertAdjacentElement("afterend", anchor);
|
|
6332
|
+
return;
|
|
6333
|
+
}
|
|
6334
|
+
container.appendChild(anchor);
|
|
6335
|
+
}
|
|
6336
|
+
function insertNavbarItemDom(index, href, label, afterAnchor) {
|
|
6337
|
+
const afterHrefKey = afterAnchor?.getAttribute("data-ohw-href-key") ?? null;
|
|
6338
|
+
const desktopItems = getNavbarDesktopContainer()?.querySelectorAll("[data-ohw-href-key]") ?? [];
|
|
6339
|
+
const drawerItems = getNavbarDrawerContainer()?.querySelectorAll("[data-ohw-href-key]") ?? [];
|
|
6340
|
+
const desktopTemplate = Array.from(desktopItems).find(isNavbarLinkItem) ?? null;
|
|
6341
|
+
const drawerTemplate = Array.from(drawerItems).find(isNavbarLinkItem) ?? null;
|
|
6342
|
+
let primary = null;
|
|
6343
|
+
const desktopContainer = getNavbarDesktopContainer();
|
|
6344
|
+
if (desktopContainer) {
|
|
6345
|
+
const desktopAnchor = buildNavLink(index, href, label, desktopTemplate);
|
|
6346
|
+
insertNavLinkInContainer(desktopContainer, desktopAnchor, afterHrefKey);
|
|
6347
|
+
primary = desktopAnchor;
|
|
6348
|
+
}
|
|
6349
|
+
const drawerContainer = getNavbarDrawerContainer();
|
|
6350
|
+
if (drawerContainer) {
|
|
6351
|
+
const drawerAnchor = buildNavLink(index, href, label, drawerTemplate);
|
|
6352
|
+
insertNavLinkInContainer(drawerContainer, drawerAnchor, afterHrefKey);
|
|
6353
|
+
if (!primary) primary = drawerAnchor;
|
|
6354
|
+
}
|
|
6355
|
+
if (!primary) {
|
|
6356
|
+
const fallback = buildNavLink(index, href, label, listNavbarItems()[0] ?? null);
|
|
6357
|
+
const nav = document.querySelector("nav");
|
|
6358
|
+
nav?.appendChild(fallback);
|
|
6359
|
+
primary = fallback;
|
|
6360
|
+
}
|
|
6361
|
+
return primary;
|
|
6362
|
+
}
|
|
6363
|
+
function applyNavOrderToContainer(container, order) {
|
|
6364
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6365
|
+
for (const hrefKey of order) {
|
|
6366
|
+
if (seen.has(hrefKey)) continue;
|
|
6367
|
+
seen.add(hrefKey);
|
|
6368
|
+
const el = findCounterpartByHrefKey(hrefKey, container);
|
|
6369
|
+
if (el) container.appendChild(el);
|
|
6370
|
+
}
|
|
6371
|
+
for (const el of container.querySelectorAll("[data-ohw-href-key]")) {
|
|
6372
|
+
if (!isNavbarLinkItem(el)) continue;
|
|
6373
|
+
const key = el.getAttribute("data-ohw-href-key");
|
|
6374
|
+
if (!key || seen.has(key)) continue;
|
|
6375
|
+
container.appendChild(el);
|
|
6376
|
+
}
|
|
6377
|
+
}
|
|
6378
|
+
function applyNavOrder(order) {
|
|
6379
|
+
const desktop = getNavbarDesktopContainer();
|
|
6380
|
+
if (desktop) applyNavOrderToContainer(desktop, order);
|
|
6381
|
+
const drawer = getNavbarDrawerContainer();
|
|
6382
|
+
if (drawer) applyNavOrderToContainer(drawer, order);
|
|
6383
|
+
}
|
|
6384
|
+
function collectNavbarIndicesFromContent(content) {
|
|
6385
|
+
const indices = /* @__PURE__ */ new Set();
|
|
6386
|
+
for (const key of Object.keys(content)) {
|
|
6387
|
+
const idx = parseNavIndexFromKey(key);
|
|
6388
|
+
if (idx !== null) indices.add(idx);
|
|
6389
|
+
}
|
|
6390
|
+
const countRaw = content[NAV_COUNT_KEY];
|
|
6391
|
+
if (countRaw) {
|
|
6392
|
+
const count = parseInt(countRaw, 10);
|
|
6393
|
+
if (Number.isFinite(count) && count > 0) {
|
|
6394
|
+
for (let i = 0; i < count; i++) indices.add(i);
|
|
6395
|
+
}
|
|
6396
|
+
}
|
|
6397
|
+
return [...indices].sort((a, b) => a - b);
|
|
6398
|
+
}
|
|
6399
|
+
function navbarIndexExistsInDom(index) {
|
|
6400
|
+
return document.querySelector(`[data-ohw-href-key="nav-${index}-href"]`) !== null;
|
|
6401
|
+
}
|
|
6402
|
+
function reconcileNavbarItemsFromContent(content) {
|
|
6403
|
+
const indices = collectNavbarIndicesFromContent(content);
|
|
6404
|
+
for (const index of indices) {
|
|
6405
|
+
if (navbarIndexExistsInDom(index)) continue;
|
|
6406
|
+
const href = content[`nav-${index}-href`];
|
|
6407
|
+
const label = content[`nav-${index}-label`];
|
|
6408
|
+
if (!href && !label) continue;
|
|
6409
|
+
insertNavbarItemDom(index, href ?? "/", label ?? "Untitled", null);
|
|
6410
|
+
}
|
|
6411
|
+
const order = parseNavOrder(content);
|
|
6412
|
+
if (order?.length) applyNavOrder(order);
|
|
6413
|
+
}
|
|
6414
|
+
function buildNavOrderAfterInsert(afterAnchor, newHrefKey) {
|
|
6415
|
+
const order = getNavOrderFromDom();
|
|
6416
|
+
if (!afterAnchor) {
|
|
6417
|
+
if (!order.includes(newHrefKey)) order.push(newHrefKey);
|
|
6418
|
+
return order;
|
|
6419
|
+
}
|
|
6420
|
+
const afterKey = afterAnchor.getAttribute("data-ohw-href-key");
|
|
6421
|
+
if (!afterKey) {
|
|
6422
|
+
if (!order.includes(newHrefKey)) order.push(newHrefKey);
|
|
6423
|
+
return order;
|
|
6424
|
+
}
|
|
6425
|
+
const withoutNew = order.filter((key) => key !== newHrefKey);
|
|
6426
|
+
const pos = withoutNew.indexOf(afterKey);
|
|
6427
|
+
if (pos >= 0) {
|
|
6428
|
+
withoutNew.splice(pos + 1, 0, newHrefKey);
|
|
6429
|
+
return withoutNew;
|
|
6430
|
+
}
|
|
6431
|
+
withoutNew.push(newHrefKey);
|
|
6432
|
+
return withoutNew;
|
|
6433
|
+
}
|
|
6434
|
+
function insertNavbarItem(href, label, afterAnchor = null) {
|
|
6435
|
+
const index = getNextNavbarIndex();
|
|
6436
|
+
const anchor = insertNavbarItemDom(index, href, label, afterAnchor);
|
|
6437
|
+
if (!anchor) throw new Error("Failed to insert navbar item");
|
|
6438
|
+
const hrefKey = `nav-${index}-href`;
|
|
6439
|
+
const order = buildNavOrderAfterInsert(afterAnchor, hrefKey);
|
|
6440
|
+
applyNavOrder(order);
|
|
6441
|
+
return {
|
|
6442
|
+
anchor,
|
|
6443
|
+
index,
|
|
6444
|
+
hrefKey,
|
|
6445
|
+
labelKey: `nav-${index}-label`,
|
|
6446
|
+
href,
|
|
6447
|
+
label,
|
|
6448
|
+
order
|
|
6449
|
+
};
|
|
6450
|
+
}
|
|
6451
|
+
|
|
6452
|
+
// src/ui/navbar-container-chrome.tsx
|
|
6453
|
+
var import_lucide_react10 = require("lucide-react");
|
|
6454
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
6455
|
+
function NavbarContainerChrome({
|
|
6456
|
+
rect,
|
|
6457
|
+
onAdd
|
|
6458
|
+
}) {
|
|
6459
|
+
const chromeGap = 6;
|
|
6460
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
6461
|
+
"div",
|
|
6462
|
+
{
|
|
6463
|
+
"data-ohw-navbar-container-chrome": "",
|
|
6464
|
+
"data-ohw-bridge": "",
|
|
6465
|
+
className: "pointer-events-none fixed z-[2147483647]",
|
|
6466
|
+
style: {
|
|
6467
|
+
top: rect.top - chromeGap,
|
|
6468
|
+
left: rect.left - chromeGap,
|
|
6469
|
+
width: rect.width + chromeGap * 2,
|
|
6470
|
+
height: rect.height + chromeGap * 2
|
|
6471
|
+
},
|
|
6472
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
6473
|
+
"button",
|
|
6474
|
+
{
|
|
6475
|
+
type: "button",
|
|
6476
|
+
"data-ohw-navbar-add-button": "",
|
|
6477
|
+
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",
|
|
6478
|
+
style: { top: "70%" },
|
|
6479
|
+
"aria-label": "Add item",
|
|
6480
|
+
onMouseDown: (e) => {
|
|
6481
|
+
e.preventDefault();
|
|
6482
|
+
e.stopPropagation();
|
|
6483
|
+
},
|
|
6484
|
+
onClick: (e) => {
|
|
6485
|
+
e.preventDefault();
|
|
6486
|
+
e.stopPropagation();
|
|
6487
|
+
onAdd();
|
|
6488
|
+
},
|
|
6489
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react10.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
|
|
6490
|
+
}
|
|
6491
|
+
)
|
|
6492
|
+
}
|
|
6493
|
+
);
|
|
6494
|
+
}
|
|
6495
|
+
|
|
5609
6496
|
// src/ui/badge.tsx
|
|
5610
|
-
var
|
|
6497
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
5611
6498
|
var badgeVariants = cva(
|
|
5612
6499
|
"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",
|
|
5613
6500
|
{
|
|
@@ -5625,12 +6512,12 @@ var badgeVariants = cva(
|
|
|
5625
6512
|
}
|
|
5626
6513
|
);
|
|
5627
6514
|
function Badge({ className, variant, ...props }) {
|
|
5628
|
-
return /* @__PURE__ */ (0,
|
|
6515
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: cn(badgeVariants({ variant }), className), ...props });
|
|
5629
6516
|
}
|
|
5630
6517
|
|
|
5631
6518
|
// src/OhhwellsBridge.tsx
|
|
5632
|
-
var
|
|
5633
|
-
var
|
|
6519
|
+
var import_lucide_react11 = require("lucide-react");
|
|
6520
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
5634
6521
|
var PRIMARY2 = "#0885FE";
|
|
5635
6522
|
var IMAGE_FADE_MS = 300;
|
|
5636
6523
|
function runOpacityFade(el, onDone) {
|
|
@@ -5657,6 +6544,11 @@ function fadeInImageElement(img, onReady) {
|
|
|
5657
6544
|
img.style.opacity = "";
|
|
5658
6545
|
});
|
|
5659
6546
|
}
|
|
6547
|
+
function applyEditableImageSrc(img, url) {
|
|
6548
|
+
img.removeAttribute("srcset");
|
|
6549
|
+
img.removeAttribute("sizes");
|
|
6550
|
+
img.src = url;
|
|
6551
|
+
}
|
|
5660
6552
|
function fadeInBgImage(el, url, onReady) {
|
|
5661
6553
|
const prevPos = el.style.position;
|
|
5662
6554
|
if (!prevPos || prevPos === "static") el.style.position = "relative";
|
|
@@ -5802,9 +6694,9 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
5802
6694
|
tail.insertAdjacentElement("afterend", container);
|
|
5803
6695
|
}
|
|
5804
6696
|
const root = (0, import_client.createRoot)(container);
|
|
5805
|
-
(0,
|
|
6697
|
+
(0, import_react_dom2.flushSync)(() => {
|
|
5806
6698
|
root.render(
|
|
5807
|
-
/* @__PURE__ */ (0,
|
|
6699
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
5808
6700
|
SchedulingWidget,
|
|
5809
6701
|
{
|
|
5810
6702
|
notifyOnConnect,
|
|
@@ -5844,7 +6736,7 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
|
|
|
5844
6736
|
}
|
|
5845
6737
|
}
|
|
5846
6738
|
}
|
|
5847
|
-
function
|
|
6739
|
+
function getLinkHref2(el) {
|
|
5848
6740
|
const anchor = el instanceof HTMLAnchorElement ? el : el.querySelector("a");
|
|
5849
6741
|
return anchor?.getAttribute("href") ?? "";
|
|
5850
6742
|
}
|
|
@@ -5877,8 +6769,11 @@ function collectEditableNodes() {
|
|
|
5877
6769
|
const url = raw.replace(/^url\(['"]?/, "").replace(/['"]?\)$/, "");
|
|
5878
6770
|
return { key: el.dataset.ohwKey ?? "", type: "bg-image", text: url };
|
|
5879
6771
|
}
|
|
6772
|
+
if (el.dataset.ohwEditable === "video") {
|
|
6773
|
+
return { key: el.dataset.ohwKey ?? "", type: "video", text: getVideoEl(el)?.src ?? "" };
|
|
6774
|
+
}
|
|
5880
6775
|
if (el.dataset.ohwEditable === "link") {
|
|
5881
|
-
return { key: el.dataset.ohwKey ?? "", type: "link", text:
|
|
6776
|
+
return { key: el.dataset.ohwKey ?? "", type: "link", text: getLinkHref2(el) };
|
|
5882
6777
|
}
|
|
5883
6778
|
return {
|
|
5884
6779
|
key: el.dataset.ohwKey ?? "",
|
|
@@ -5889,9 +6784,79 @@ function collectEditableNodes() {
|
|
|
5889
6784
|
document.querySelectorAll("[data-ohw-href-key]").forEach((el) => {
|
|
5890
6785
|
const key = el.getAttribute("data-ohw-href-key") ?? "";
|
|
5891
6786
|
if (!key) return;
|
|
5892
|
-
nodes.push({ key, type: "link", text:
|
|
6787
|
+
nodes.push({ key, type: "link", text: getLinkHref2(el) });
|
|
6788
|
+
});
|
|
6789
|
+
document.querySelectorAll('[data-ohw-editable="video"]').forEach((el) => {
|
|
6790
|
+
const key = el.dataset.ohwKey ?? "";
|
|
6791
|
+
const video = getVideoEl(el);
|
|
6792
|
+
if (!key || !video) return;
|
|
6793
|
+
nodes.push({ key: `${key}${VIDEO_AUTOPLAY_SUFFIX}`, type: "video-setting", text: String(video.autoplay) });
|
|
6794
|
+
nodes.push({ key: `${key}${VIDEO_MUTED_SUFFIX}`, type: "video-setting", text: String(video.muted) });
|
|
6795
|
+
});
|
|
6796
|
+
return nodes;
|
|
6797
|
+
}
|
|
6798
|
+
function isMediaEditable(el) {
|
|
6799
|
+
const t = el.dataset.ohwEditable;
|
|
6800
|
+
return t === "image" || t === "bg-image" || t === "video";
|
|
6801
|
+
}
|
|
6802
|
+
var MEDIA_SELECTOR = '[data-ohw-editable="image"], [data-ohw-editable="bg-image"], [data-ohw-editable="video"]';
|
|
6803
|
+
var NON_MEDIA_SELECTOR = '[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"])';
|
|
6804
|
+
function getVideoEl(el) {
|
|
6805
|
+
return el instanceof HTMLVideoElement ? el : el.querySelector("video");
|
|
6806
|
+
}
|
|
6807
|
+
var VIDEO_AUTOPLAY_SUFFIX = "__ohw_autoplay";
|
|
6808
|
+
var VIDEO_MUTED_SUFFIX = "__ohw_muted";
|
|
6809
|
+
function isBackgroundVideo(video) {
|
|
6810
|
+
return video.autoplay && video.muted;
|
|
6811
|
+
}
|
|
6812
|
+
function syncVideoPlayback(video) {
|
|
6813
|
+
const background = isBackgroundVideo(video);
|
|
6814
|
+
video.controls = !background;
|
|
6815
|
+
if (video.autoplay) void video.play().catch(() => {
|
|
6816
|
+
});
|
|
6817
|
+
else video.pause();
|
|
6818
|
+
}
|
|
6819
|
+
function lockVideoBox(video) {
|
|
6820
|
+
const { width, height } = video.getBoundingClientRect();
|
|
6821
|
+
if (width > 0 && height > 0 && !video.style.aspectRatio) {
|
|
6822
|
+
video.style.aspectRatio = `${width} / ${height}`;
|
|
6823
|
+
}
|
|
6824
|
+
if (getComputedStyle(video).objectFit === "fill") {
|
|
6825
|
+
video.style.objectFit = "contain";
|
|
6826
|
+
}
|
|
6827
|
+
const fit = video.style.objectFit || getComputedStyle(video).objectFit;
|
|
6828
|
+
const bg = getComputedStyle(video).backgroundColor;
|
|
6829
|
+
const isTransparent = bg === "rgba(0, 0, 0, 0)" || bg === "transparent" || !bg;
|
|
6830
|
+
if (fit === "contain" && isTransparent) {
|
|
6831
|
+
video.style.backgroundColor = "var(--color-dark, #000)";
|
|
6832
|
+
}
|
|
6833
|
+
}
|
|
6834
|
+
function applyVideoSrc(video, url) {
|
|
6835
|
+
const { autoplay, muted } = video;
|
|
6836
|
+
lockVideoBox(video);
|
|
6837
|
+
video.src = url;
|
|
6838
|
+
video.loop = true;
|
|
6839
|
+
video.playsInline = true;
|
|
6840
|
+
video.autoplay = autoplay;
|
|
6841
|
+
video.muted = muted;
|
|
6842
|
+
video.load();
|
|
6843
|
+
syncVideoPlayback(video);
|
|
6844
|
+
}
|
|
6845
|
+
function applyVideoSettingNode(key, val) {
|
|
6846
|
+
const isAutoplay = key.endsWith(VIDEO_AUTOPLAY_SUFFIX);
|
|
6847
|
+
const isMuted = key.endsWith(VIDEO_MUTED_SUFFIX);
|
|
6848
|
+
if (!isAutoplay && !isMuted) return false;
|
|
6849
|
+
const suffixLen = (isAutoplay ? VIDEO_AUTOPLAY_SUFFIX : VIDEO_MUTED_SUFFIX).length;
|
|
6850
|
+
const baseKey = key.slice(0, key.length - suffixLen);
|
|
6851
|
+
const on = val === "true";
|
|
6852
|
+
document.querySelectorAll(`[data-ohw-key="${baseKey}"]`).forEach((el) => {
|
|
6853
|
+
const video = getVideoEl(el);
|
|
6854
|
+
if (!video) return;
|
|
6855
|
+
if (isAutoplay) video.autoplay = on;
|
|
6856
|
+
else video.muted = on;
|
|
6857
|
+
syncVideoPlayback(video);
|
|
5893
6858
|
});
|
|
5894
|
-
return
|
|
6859
|
+
return true;
|
|
5895
6860
|
}
|
|
5896
6861
|
function applyLinkByKey(key, val) {
|
|
5897
6862
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -5905,7 +6870,7 @@ function applyLinkByKey(key, val) {
|
|
|
5905
6870
|
}
|
|
5906
6871
|
function isInsideLinkEditor(target) {
|
|
5907
6872
|
return Boolean(
|
|
5908
|
-
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"]')
|
|
6873
|
+
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"]')
|
|
5909
6874
|
);
|
|
5910
6875
|
}
|
|
5911
6876
|
function getHrefKeyFromElement(el) {
|
|
@@ -5916,7 +6881,7 @@ function getHrefKeyFromElement(el) {
|
|
|
5916
6881
|
if (!key) return null;
|
|
5917
6882
|
return { anchor, key };
|
|
5918
6883
|
}
|
|
5919
|
-
function
|
|
6884
|
+
function isNavbarButton2(el) {
|
|
5920
6885
|
return Boolean(el.closest('[data-ohw-role="navbar-button"]'));
|
|
5921
6886
|
}
|
|
5922
6887
|
function getNavigationItemAnchor(el) {
|
|
@@ -5928,19 +6893,8 @@ function getNavigationItemAnchor(el) {
|
|
|
5928
6893
|
function isNavigationItem(el) {
|
|
5929
6894
|
return getNavigationItemAnchor(el) !== null;
|
|
5930
6895
|
}
|
|
5931
|
-
function getNavigationItemAddHintTarget(anchor) {
|
|
5932
|
-
const items = listNavigationItems();
|
|
5933
|
-
const idx = items.indexOf(anchor);
|
|
5934
|
-
if (idx >= 0 && idx < items.length - 1) return items[idx + 1];
|
|
5935
|
-
return anchor;
|
|
5936
|
-
}
|
|
5937
|
-
function listNavigationItems() {
|
|
5938
|
-
return Array.from(
|
|
5939
|
-
document.querySelectorAll("nav [data-ohw-href-key], footer [data-ohw-href-key]")
|
|
5940
|
-
).filter((el) => isNavigationItem(el));
|
|
5941
|
-
}
|
|
5942
6896
|
function getNavigationItemReorderState(anchor) {
|
|
5943
|
-
if (
|
|
6897
|
+
if (isNavbarButton2(anchor)) return { key: null, disabled: false };
|
|
5944
6898
|
return getReorderHandleStateFromAnchor(anchor);
|
|
5945
6899
|
}
|
|
5946
6900
|
function getReorderHandleState(el) {
|
|
@@ -5962,6 +6916,120 @@ function clearHrefKeyHover(anchor) {
|
|
|
5962
6916
|
function isInsideNavigationItem(el) {
|
|
5963
6917
|
return getNavigationItemAnchor(el) !== null;
|
|
5964
6918
|
}
|
|
6919
|
+
function getNavigationRoot(el) {
|
|
6920
|
+
const explicit = el.closest("[data-ohw-nav-root]");
|
|
6921
|
+
if (explicit) return explicit;
|
|
6922
|
+
return el.closest("nav, footer, aside");
|
|
6923
|
+
}
|
|
6924
|
+
function findFooterItemGroup(item) {
|
|
6925
|
+
const footer = item.closest("footer");
|
|
6926
|
+
if (!footer) return null;
|
|
6927
|
+
let node = item.parentElement;
|
|
6928
|
+
while (node && node !== footer) {
|
|
6929
|
+
const hasDirectNavItems = Array.from(
|
|
6930
|
+
node.querySelectorAll(":scope > [data-ohw-href-key]")
|
|
6931
|
+
).some(isNavigationItem);
|
|
6932
|
+
if (hasDirectNavItems) return node;
|
|
6933
|
+
node = node.parentElement;
|
|
6934
|
+
}
|
|
6935
|
+
return null;
|
|
6936
|
+
}
|
|
6937
|
+
function isNavigationRoot(el) {
|
|
6938
|
+
return el.hasAttribute("data-ohw-nav-root") || el.matches("nav, footer, aside");
|
|
6939
|
+
}
|
|
6940
|
+
function isInferredFooterGroup(el) {
|
|
6941
|
+
const footer = el.closest("footer");
|
|
6942
|
+
if (!footer || el === footer) return false;
|
|
6943
|
+
return Array.from(el.querySelectorAll(":scope > [data-ohw-href-key]")).some(isNavigationItem);
|
|
6944
|
+
}
|
|
6945
|
+
function isNavigationContainer(el) {
|
|
6946
|
+
return el.hasAttribute("data-ohw-nav-container") || isNavigationRoot(el) || isInferredFooterGroup(el);
|
|
6947
|
+
}
|
|
6948
|
+
function isPointOverNavigation(x, y) {
|
|
6949
|
+
const navRoot = document.querySelector("[data-ohw-nav-root]") ?? document.querySelector("nav");
|
|
6950
|
+
if (!navRoot) return false;
|
|
6951
|
+
const r2 = navRoot.getBoundingClientRect();
|
|
6952
|
+
return x >= r2.left && x <= r2.right && y >= r2.top && y <= r2.bottom;
|
|
6953
|
+
}
|
|
6954
|
+
function isPointOverNavItem(container, x, y) {
|
|
6955
|
+
return Array.from(container.querySelectorAll("[data-ohw-href-key]")).some((el) => {
|
|
6956
|
+
if (!isNavigationItem(el) || isNavbarButton2(el)) return false;
|
|
6957
|
+
const itemRect = el.getBoundingClientRect();
|
|
6958
|
+
return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
|
|
6959
|
+
});
|
|
6960
|
+
}
|
|
6961
|
+
function resolveNavContainerSelectionTarget(target, clientX, clientY) {
|
|
6962
|
+
if (getNavigationItemAnchor(target)) return null;
|
|
6963
|
+
if (target.closest('[data-ohw-role="navbar-button"]')) return null;
|
|
6964
|
+
const plainLink = target.closest("a");
|
|
6965
|
+
if (plainLink && !plainLink.hasAttribute("data-ohw-href-key") && !plainLink.closest("[data-ohw-nav-container]")) {
|
|
6966
|
+
return null;
|
|
6967
|
+
}
|
|
6968
|
+
const fromClosest = target.closest("[data-ohw-nav-container]");
|
|
6969
|
+
if (fromClosest && !isPointOverNavItem(fromClosest, clientX, clientY)) {
|
|
6970
|
+
return fromClosest;
|
|
6971
|
+
}
|
|
6972
|
+
const navRoot = target.closest("[data-ohw-nav-root]");
|
|
6973
|
+
if (!navRoot) return null;
|
|
6974
|
+
const container = navRoot.querySelector("[data-ohw-nav-container]");
|
|
6975
|
+
if (!container || isPointOverNavItem(container, clientX, clientY)) return null;
|
|
6976
|
+
if (target === navRoot || target.hasAttribute("data-ohw-nav-root")) {
|
|
6977
|
+
return container;
|
|
6978
|
+
}
|
|
6979
|
+
return null;
|
|
6980
|
+
}
|
|
6981
|
+
function getNavigationSelectionParent(el) {
|
|
6982
|
+
if (isNavigationItem(el)) {
|
|
6983
|
+
const explicit = el.closest("[data-ohw-nav-container]");
|
|
6984
|
+
if (explicit) return explicit;
|
|
6985
|
+
const footerGroup = findFooterItemGroup(el);
|
|
6986
|
+
if (footerGroup) return footerGroup;
|
|
6987
|
+
return getNavigationRoot(el);
|
|
6988
|
+
}
|
|
6989
|
+
if (el.hasAttribute("data-ohw-nav-container") || isInferredFooterGroup(el)) {
|
|
6990
|
+
return getNavigationRoot(el);
|
|
6991
|
+
}
|
|
6992
|
+
return null;
|
|
6993
|
+
}
|
|
6994
|
+
function placeCaretAtPoint(el, x, y) {
|
|
6995
|
+
const selection = window.getSelection();
|
|
6996
|
+
if (!selection) return;
|
|
6997
|
+
if (typeof document.caretRangeFromPoint === "function") {
|
|
6998
|
+
const range = document.caretRangeFromPoint(x, y);
|
|
6999
|
+
if (range && el.contains(range.startContainer)) {
|
|
7000
|
+
selection.removeAllRanges();
|
|
7001
|
+
selection.addRange(range);
|
|
7002
|
+
return;
|
|
7003
|
+
}
|
|
7004
|
+
}
|
|
7005
|
+
const caretPositionFromPoint = document.caretPositionFromPoint;
|
|
7006
|
+
if (typeof caretPositionFromPoint === "function") {
|
|
7007
|
+
const position = caretPositionFromPoint(x, y);
|
|
7008
|
+
if (position && el.contains(position.offsetNode)) {
|
|
7009
|
+
const range = document.createRange();
|
|
7010
|
+
range.setStart(position.offsetNode, position.offset);
|
|
7011
|
+
range.collapse(true);
|
|
7012
|
+
selection.removeAllRanges();
|
|
7013
|
+
selection.addRange(range);
|
|
7014
|
+
}
|
|
7015
|
+
}
|
|
7016
|
+
}
|
|
7017
|
+
function selectAllTextInEditable(el) {
|
|
7018
|
+
const selection = window.getSelection();
|
|
7019
|
+
if (!selection) return;
|
|
7020
|
+
const range = document.createRange();
|
|
7021
|
+
range.selectNodeContents(el);
|
|
7022
|
+
selection.removeAllRanges();
|
|
7023
|
+
selection.addRange(range);
|
|
7024
|
+
}
|
|
7025
|
+
function getNavigationLabelEditable(target) {
|
|
7026
|
+
const editable = target.closest('[data-ohw-editable="text"]');
|
|
7027
|
+
if (!editable) return null;
|
|
7028
|
+
const hrefCtx = getHrefKeyFromElement(editable);
|
|
7029
|
+
const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
|
|
7030
|
+
if (!navAnchor) return null;
|
|
7031
|
+
return { editable, navAnchor };
|
|
7032
|
+
}
|
|
5965
7033
|
function collectSections() {
|
|
5966
7034
|
return collectSectionsFromDom();
|
|
5967
7035
|
}
|
|
@@ -6085,6 +7153,8 @@ var ICONS = {
|
|
|
6085
7153
|
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"/>',
|
|
6086
7154
|
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"/>'
|
|
6087
7155
|
};
|
|
7156
|
+
var TOOLBAR_PILL_PADDING = 2;
|
|
7157
|
+
var TOOLBAR_TOGGLE_GAP = 4;
|
|
6088
7158
|
var TOOLBAR_GROUPS = [
|
|
6089
7159
|
[
|
|
6090
7160
|
{ cmd: "bold", title: "Bold" },
|
|
@@ -6109,7 +7179,7 @@ function EditGlowChrome({
|
|
|
6109
7179
|
dragDisabled = false
|
|
6110
7180
|
}) {
|
|
6111
7181
|
const GAP = 6;
|
|
6112
|
-
return /* @__PURE__ */ (0,
|
|
7182
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
6113
7183
|
"div",
|
|
6114
7184
|
{
|
|
6115
7185
|
ref: elRef,
|
|
@@ -6124,7 +7194,7 @@ function EditGlowChrome({
|
|
|
6124
7194
|
zIndex: 2147483646
|
|
6125
7195
|
},
|
|
6126
7196
|
children: [
|
|
6127
|
-
/* @__PURE__ */ (0,
|
|
7197
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
6128
7198
|
"div",
|
|
6129
7199
|
{
|
|
6130
7200
|
style: {
|
|
@@ -6137,7 +7207,7 @@ function EditGlowChrome({
|
|
|
6137
7207
|
}
|
|
6138
7208
|
}
|
|
6139
7209
|
),
|
|
6140
|
-
reorderHrefKey && /* @__PURE__ */ (0,
|
|
7210
|
+
reorderHrefKey && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
6141
7211
|
"div",
|
|
6142
7212
|
{
|
|
6143
7213
|
"data-ohw-drag-handle-container": "",
|
|
@@ -6149,7 +7219,7 @@ function EditGlowChrome({
|
|
|
6149
7219
|
transform: "translate(calc(-100% - 7px), -50%)",
|
|
6150
7220
|
pointerEvents: dragDisabled ? "none" : "auto"
|
|
6151
7221
|
},
|
|
6152
|
-
children: /* @__PURE__ */ (0,
|
|
7222
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
6153
7223
|
DragHandle,
|
|
6154
7224
|
{
|
|
6155
7225
|
"aria-label": `Reorder ${reorderHrefKey}`,
|
|
@@ -6253,7 +7323,7 @@ function FloatingToolbar({
|
|
|
6253
7323
|
onEditLink
|
|
6254
7324
|
}) {
|
|
6255
7325
|
const { top, left, transform } = calcToolbarPos(rect, parentScroll, 330);
|
|
6256
|
-
return /* @__PURE__ */ (0,
|
|
7326
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
6257
7327
|
"div",
|
|
6258
7328
|
{
|
|
6259
7329
|
ref: elRef,
|
|
@@ -6263,14 +7333,23 @@ function FloatingToolbar({
|
|
|
6263
7333
|
left,
|
|
6264
7334
|
transform,
|
|
6265
7335
|
zIndex: 2147483647,
|
|
7336
|
+
background: "#fff",
|
|
7337
|
+
border: "1px solid #E7E5E4",
|
|
7338
|
+
borderRadius: 6,
|
|
7339
|
+
boxShadow: "0px 2px 4px -2px rgba(0,0,0,.1),0px 4px 6px -1px rgba(0,0,0,.1)",
|
|
7340
|
+
display: "flex",
|
|
7341
|
+
alignItems: "center",
|
|
7342
|
+
padding: TOOLBAR_PILL_PADDING,
|
|
7343
|
+
gap: TOOLBAR_TOGGLE_GAP,
|
|
7344
|
+
fontFamily: "sans-serif",
|
|
6266
7345
|
pointerEvents: "auto"
|
|
6267
7346
|
},
|
|
6268
|
-
children: /* @__PURE__ */ (0,
|
|
6269
|
-
TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0,
|
|
6270
|
-
gi > 0 && /* @__PURE__ */ (0,
|
|
7347
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(CustomToolbar, { children: [
|
|
7348
|
+
TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react8.default.Fragment, { children: [
|
|
7349
|
+
gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(CustomToolbarDivider, {}),
|
|
6271
7350
|
btns.map((btn) => {
|
|
6272
7351
|
const isActive = activeCommands.has(btn.cmd);
|
|
6273
|
-
return /* @__PURE__ */ (0,
|
|
7352
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
6274
7353
|
CustomToolbarButton,
|
|
6275
7354
|
{
|
|
6276
7355
|
title: btn.title,
|
|
@@ -6279,7 +7358,7 @@ function FloatingToolbar({
|
|
|
6279
7358
|
e.preventDefault();
|
|
6280
7359
|
onCommand(btn.cmd);
|
|
6281
7360
|
},
|
|
6282
|
-
children: /* @__PURE__ */ (0,
|
|
7361
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
6283
7362
|
"svg",
|
|
6284
7363
|
{
|
|
6285
7364
|
width: "16",
|
|
@@ -6300,7 +7379,7 @@ function FloatingToolbar({
|
|
|
6300
7379
|
);
|
|
6301
7380
|
})
|
|
6302
7381
|
] }, gi)),
|
|
6303
|
-
showEditLink ? /* @__PURE__ */ (0,
|
|
7382
|
+
showEditLink ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
6304
7383
|
CustomToolbarButton,
|
|
6305
7384
|
{
|
|
6306
7385
|
type: "button",
|
|
@@ -6314,7 +7393,7 @@ function FloatingToolbar({
|
|
|
6314
7393
|
e.preventDefault();
|
|
6315
7394
|
e.stopPropagation();
|
|
6316
7395
|
},
|
|
6317
|
-
children: /* @__PURE__ */ (0,
|
|
7396
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react11.Link, { className: "size-4 shrink-0", "aria-hidden": true })
|
|
6318
7397
|
}
|
|
6319
7398
|
) : null
|
|
6320
7399
|
] })
|
|
@@ -6331,7 +7410,7 @@ function StateToggle({
|
|
|
6331
7410
|
states,
|
|
6332
7411
|
onStateChange
|
|
6333
7412
|
}) {
|
|
6334
|
-
return /* @__PURE__ */ (0,
|
|
7413
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
6335
7414
|
ToggleGroup,
|
|
6336
7415
|
{
|
|
6337
7416
|
"data-ohw-state-toggle": "",
|
|
@@ -6345,7 +7424,7 @@ function StateToggle({
|
|
|
6345
7424
|
left: rect.right - 8,
|
|
6346
7425
|
transform: "translateX(-100%)"
|
|
6347
7426
|
},
|
|
6348
|
-
children: states.map((state) => /* @__PURE__ */ (0,
|
|
7427
|
+
children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
|
|
6349
7428
|
}
|
|
6350
7429
|
);
|
|
6351
7430
|
}
|
|
@@ -6368,12 +7447,12 @@ function resolveSubdomain(subdomainFromQuery) {
|
|
|
6368
7447
|
return "";
|
|
6369
7448
|
}
|
|
6370
7449
|
function OhhwellsBridge() {
|
|
6371
|
-
const pathname = (0,
|
|
6372
|
-
const router = (0,
|
|
6373
|
-
const searchParams = (0,
|
|
7450
|
+
const pathname = (0, import_navigation2.usePathname)();
|
|
7451
|
+
const router = (0, import_navigation2.useRouter)();
|
|
7452
|
+
const searchParams = (0, import_navigation2.useSearchParams)();
|
|
6374
7453
|
const isEditMode = isEditSessionActive();
|
|
6375
|
-
const [bridgeRoot, setBridgeRoot] = (0,
|
|
6376
|
-
(0,
|
|
7454
|
+
const [bridgeRoot, setBridgeRoot] = (0, import_react8.useState)(null);
|
|
7455
|
+
(0, import_react8.useEffect)(() => {
|
|
6377
7456
|
const figtreeFontId = "ohw-figtree-font";
|
|
6378
7457
|
if (!document.getElementById(figtreeFontId)) {
|
|
6379
7458
|
const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
|
|
@@ -6381,7 +7460,10 @@ function OhhwellsBridge() {
|
|
|
6381
7460
|
const stylesheet = Object.assign(document.createElement("link"), {
|
|
6382
7461
|
id: figtreeFontId,
|
|
6383
7462
|
rel: "stylesheet",
|
|
6384
|
-
|
|
7463
|
+
// Inter is loaded alongside Figtree for the media overlay's Replace button. The bridge
|
|
7464
|
+
// renders inside the customer's document, so it cannot assume any font is present — an
|
|
7465
|
+
// unloaded family would silently fall back to whatever the template happens to use.
|
|
7466
|
+
href: "https://fonts.googleapis.com/css2?family=Figtree:ital,wght@0,300..900;1,300..900&family=Inter:wght@400;500;600&display=swap"
|
|
6385
7467
|
});
|
|
6386
7468
|
document.head.append(preconnect1, preconnect2, stylesheet);
|
|
6387
7469
|
}
|
|
@@ -6398,80 +7480,91 @@ function OhhwellsBridge() {
|
|
|
6398
7480
|
const subdomainFromQuery = searchParams.get("subdomain");
|
|
6399
7481
|
const subdomain = resolveSubdomain(subdomainFromQuery);
|
|
6400
7482
|
useLinkHrefGuardian(pathname, subdomain, isEditMode);
|
|
6401
|
-
const
|
|
7483
|
+
const postToParent2 = (0, import_react8.useCallback)((data) => {
|
|
6402
7484
|
if (typeof window !== "undefined" && window.parent !== window) {
|
|
6403
7485
|
window.parent.postMessage(data, "*");
|
|
6404
7486
|
}
|
|
6405
7487
|
}, []);
|
|
6406
|
-
const [fetchState, setFetchState] = (0,
|
|
6407
|
-
const autoSaveTimers = (0,
|
|
6408
|
-
const activeElRef = (0,
|
|
6409
|
-
const selectedElRef = (0,
|
|
6410
|
-
const originalContentRef = (0,
|
|
6411
|
-
const activeStateElRef = (0,
|
|
6412
|
-
const parentScrollRef = (0,
|
|
6413
|
-
const visibleViewportRef = (0,
|
|
6414
|
-
const [dialogPortalContainer, setDialogPortalContainer] = (0,
|
|
6415
|
-
const attachVisibleViewport = (0,
|
|
7488
|
+
const [fetchState, setFetchState] = (0, import_react8.useState)("idle");
|
|
7489
|
+
const autoSaveTimers = (0, import_react8.useRef)(/* @__PURE__ */ new Map());
|
|
7490
|
+
const activeElRef = (0, import_react8.useRef)(null);
|
|
7491
|
+
const selectedElRef = (0, import_react8.useRef)(null);
|
|
7492
|
+
const originalContentRef = (0, import_react8.useRef)(null);
|
|
7493
|
+
const activeStateElRef = (0, import_react8.useRef)(null);
|
|
7494
|
+
const parentScrollRef = (0, import_react8.useRef)(null);
|
|
7495
|
+
const visibleViewportRef = (0, import_react8.useRef)(null);
|
|
7496
|
+
const [dialogPortalContainer, setDialogPortalContainer] = (0, import_react8.useState)(null);
|
|
7497
|
+
const attachVisibleViewport = (0, import_react8.useCallback)((node) => {
|
|
6416
7498
|
visibleViewportRef.current = node;
|
|
6417
7499
|
setDialogPortalContainer(node);
|
|
6418
7500
|
if (node) applyVisibleViewport(node, parentScrollRef.current);
|
|
6419
7501
|
}, []);
|
|
6420
|
-
const toolbarElRef = (0,
|
|
6421
|
-
const glowElRef = (0,
|
|
6422
|
-
const hoveredImageRef = (0,
|
|
6423
|
-
const hoveredImageHasTextOverlapRef = (0,
|
|
6424
|
-
const
|
|
6425
|
-
const
|
|
6426
|
-
const
|
|
6427
|
-
const
|
|
6428
|
-
const
|
|
7502
|
+
const toolbarElRef = (0, import_react8.useRef)(null);
|
|
7503
|
+
const glowElRef = (0, import_react8.useRef)(null);
|
|
7504
|
+
const hoveredImageRef = (0, import_react8.useRef)(null);
|
|
7505
|
+
const hoveredImageHasTextOverlapRef = (0, import_react8.useRef)(false);
|
|
7506
|
+
const dragOverElRef = (0, import_react8.useRef)(null);
|
|
7507
|
+
const [mediaHover, setMediaHover] = (0, import_react8.useState)(null);
|
|
7508
|
+
const [uploadingRects, setUploadingRects] = (0, import_react8.useState)({});
|
|
7509
|
+
const hoveredGapRef = (0, import_react8.useRef)(null);
|
|
7510
|
+
const imageUnhoverTimerRef = (0, import_react8.useRef)(null);
|
|
7511
|
+
const imageShowTimerRef = (0, import_react8.useRef)(null);
|
|
7512
|
+
const editStylesRef = (0, import_react8.useRef)(null);
|
|
7513
|
+
const activateRef = (0, import_react8.useRef)(() => {
|
|
7514
|
+
});
|
|
7515
|
+
const deactivateRef = (0, import_react8.useRef)(() => {
|
|
6429
7516
|
});
|
|
6430
|
-
const
|
|
7517
|
+
const selectRef = (0, import_react8.useRef)(() => {
|
|
6431
7518
|
});
|
|
6432
|
-
const
|
|
7519
|
+
const selectFrameRef = (0, import_react8.useRef)(() => {
|
|
6433
7520
|
});
|
|
6434
|
-
const deselectRef = (0,
|
|
7521
|
+
const deselectRef = (0, import_react8.useRef)(() => {
|
|
6435
7522
|
});
|
|
6436
|
-
const reselectNavigationItemRef = (0,
|
|
7523
|
+
const reselectNavigationItemRef = (0, import_react8.useRef)(() => {
|
|
6437
7524
|
});
|
|
6438
|
-
const commitNavigationTextEditRef = (0,
|
|
7525
|
+
const commitNavigationTextEditRef = (0, import_react8.useRef)(() => {
|
|
6439
7526
|
});
|
|
6440
|
-
const refreshActiveCommandsRef = (0,
|
|
7527
|
+
const refreshActiveCommandsRef = (0, import_react8.useRef)(() => {
|
|
6441
7528
|
});
|
|
6442
|
-
const postToParentRef = (0,
|
|
6443
|
-
postToParentRef.current =
|
|
6444
|
-
const sectionsLoadedRef = (0,
|
|
6445
|
-
const pendingScheduleConfigRequests = (0,
|
|
6446
|
-
const [toolbarRect, setToolbarRect] = (0,
|
|
6447
|
-
const [toolbarVariant, setToolbarVariant] = (0,
|
|
6448
|
-
const toolbarVariantRef = (0,
|
|
7529
|
+
const postToParentRef = (0, import_react8.useRef)(postToParent2);
|
|
7530
|
+
postToParentRef.current = postToParent2;
|
|
7531
|
+
const sectionsLoadedRef = (0, import_react8.useRef)(false);
|
|
7532
|
+
const pendingScheduleConfigRequests = (0, import_react8.useRef)([]);
|
|
7533
|
+
const [toolbarRect, setToolbarRect] = (0, import_react8.useState)(null);
|
|
7534
|
+
const [toolbarVariant, setToolbarVariant] = (0, import_react8.useState)("none");
|
|
7535
|
+
const toolbarVariantRef = (0, import_react8.useRef)("none");
|
|
6449
7536
|
toolbarVariantRef.current = toolbarVariant;
|
|
6450
|
-
const [reorderHrefKey, setReorderHrefKey] = (0,
|
|
6451
|
-
const [reorderDragDisabled, setReorderDragDisabled] = (0,
|
|
6452
|
-
const [toggleState, setToggleState] = (0,
|
|
6453
|
-
const [maxBadge, setMaxBadge] = (0,
|
|
6454
|
-
const [activeCommands, setActiveCommands] = (0,
|
|
6455
|
-
const [sectionGap, setSectionGap] = (0,
|
|
6456
|
-
const [toolbarShowEditLink, setToolbarShowEditLink] = (0,
|
|
6457
|
-
const
|
|
6458
|
-
const [
|
|
6459
|
-
const
|
|
6460
|
-
const [
|
|
6461
|
-
const
|
|
6462
|
-
const [
|
|
6463
|
-
const [
|
|
6464
|
-
const [
|
|
6465
|
-
const
|
|
6466
|
-
const
|
|
6467
|
-
const
|
|
6468
|
-
const
|
|
6469
|
-
const
|
|
7537
|
+
const [reorderHrefKey, setReorderHrefKey] = (0, import_react8.useState)(null);
|
|
7538
|
+
const [reorderDragDisabled, setReorderDragDisabled] = (0, import_react8.useState)(false);
|
|
7539
|
+
const [toggleState, setToggleState] = (0, import_react8.useState)(null);
|
|
7540
|
+
const [maxBadge, setMaxBadge] = (0, import_react8.useState)(null);
|
|
7541
|
+
const [activeCommands, setActiveCommands] = (0, import_react8.useState)(/* @__PURE__ */ new Set());
|
|
7542
|
+
const [sectionGap, setSectionGap] = (0, import_react8.useState)(null);
|
|
7543
|
+
const [toolbarShowEditLink, setToolbarShowEditLink] = (0, import_react8.useState)(false);
|
|
7544
|
+
const hoveredNavContainerRef = (0, import_react8.useRef)(null);
|
|
7545
|
+
const [hoveredNavContainerRect, setHoveredNavContainerRect] = (0, import_react8.useState)(null);
|
|
7546
|
+
const hoveredItemElRef = (0, import_react8.useRef)(null);
|
|
7547
|
+
const [hoveredItemRect, setHoveredItemRect] = (0, import_react8.useState)(null);
|
|
7548
|
+
const siblingHintElRef = (0, import_react8.useRef)(null);
|
|
7549
|
+
const [siblingHintRect, setSiblingHintRect] = (0, import_react8.useState)(null);
|
|
7550
|
+
const [isItemDragging, setIsItemDragging] = (0, import_react8.useState)(false);
|
|
7551
|
+
const [linkPopover, setLinkPopover] = (0, import_react8.useState)(null);
|
|
7552
|
+
const linkPopoverSessionRef = (0, import_react8.useRef)(null);
|
|
7553
|
+
const addNavAfterAnchorRef = (0, import_react8.useRef)(null);
|
|
7554
|
+
const editContentRef = (0, import_react8.useRef)({});
|
|
7555
|
+
const [sitePages, setSitePages] = (0, import_react8.useState)([]);
|
|
7556
|
+
const [sectionsByPath, setSectionsByPath] = (0, import_react8.useState)({});
|
|
7557
|
+
const sectionsPrefetchGenRef = (0, import_react8.useRef)(0);
|
|
7558
|
+
const setLinkPopoverRef = (0, import_react8.useRef)(setLinkPopover);
|
|
7559
|
+
const linkPopoverPanelRef = (0, import_react8.useRef)(null);
|
|
7560
|
+
const linkPopoverOpenRef = (0, import_react8.useRef)(false);
|
|
7561
|
+
const linkPopoverGraceUntilRef = (0, import_react8.useRef)(0);
|
|
6470
7562
|
setLinkPopoverRef.current = setLinkPopover;
|
|
7563
|
+
linkPopoverSessionRef.current = linkPopover;
|
|
6471
7564
|
const bumpLinkPopoverGrace = () => {
|
|
6472
7565
|
linkPopoverGraceUntilRef.current = Date.now() + 350;
|
|
6473
7566
|
};
|
|
6474
|
-
const runSectionsPrefetch = (0,
|
|
7567
|
+
const runSectionsPrefetch = (0, import_react8.useCallback)((pages) => {
|
|
6475
7568
|
if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
|
|
6476
7569
|
const gen = ++sectionsPrefetchGenRef.current;
|
|
6477
7570
|
const paths = pages.map((p) => p.path);
|
|
@@ -6490,9 +7583,9 @@ function OhhwellsBridge() {
|
|
|
6490
7583
|
);
|
|
6491
7584
|
});
|
|
6492
7585
|
}, [isEditMode, pathname]);
|
|
6493
|
-
const runSectionsPrefetchRef = (0,
|
|
7586
|
+
const runSectionsPrefetchRef = (0, import_react8.useRef)(runSectionsPrefetch);
|
|
6494
7587
|
runSectionsPrefetchRef.current = runSectionsPrefetch;
|
|
6495
|
-
(0,
|
|
7588
|
+
(0, import_react8.useEffect)(() => {
|
|
6496
7589
|
if (!linkPopover) return;
|
|
6497
7590
|
if (hoveredImageRef.current) {
|
|
6498
7591
|
hoveredImageRef.current = null;
|
|
@@ -6500,33 +7593,9 @@ function OhhwellsBridge() {
|
|
|
6500
7593
|
}
|
|
6501
7594
|
hoveredGapRef.current = null;
|
|
6502
7595
|
setSectionGap(null);
|
|
6503
|
-
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
const body = document.body;
|
|
6507
|
-
const prevHtmlOverflow = html.style.overflow;
|
|
6508
|
-
const prevBodyOverflow = body.style.overflow;
|
|
6509
|
-
html.style.overflow = "hidden";
|
|
6510
|
-
body.style.overflow = "hidden";
|
|
6511
|
-
const preventBackgroundScroll = (e) => {
|
|
6512
|
-
const target = e.target;
|
|
6513
|
-
if (target instanceof Element && target.closest('[data-ohw-link-modal-root], [data-slot="dialog-overlay"]')) {
|
|
6514
|
-
return;
|
|
6515
|
-
}
|
|
6516
|
-
e.preventDefault();
|
|
6517
|
-
};
|
|
6518
|
-
const scrollOpts = { passive: false, capture: true };
|
|
6519
|
-
document.addEventListener("wheel", preventBackgroundScroll, scrollOpts);
|
|
6520
|
-
document.addEventListener("touchmove", preventBackgroundScroll, scrollOpts);
|
|
6521
|
-
return () => {
|
|
6522
|
-
postToParent({ type: "ow:link-modal-lock", locked: false });
|
|
6523
|
-
html.style.overflow = prevHtmlOverflow;
|
|
6524
|
-
body.style.overflow = prevBodyOverflow;
|
|
6525
|
-
document.removeEventListener("wheel", preventBackgroundScroll, scrollOpts);
|
|
6526
|
-
document.removeEventListener("touchmove", preventBackgroundScroll, scrollOpts);
|
|
6527
|
-
};
|
|
6528
|
-
}, [linkPopover, postToParent]);
|
|
6529
|
-
(0, import_react6.useEffect)(() => {
|
|
7596
|
+
postToParent2({ type: "ow:image-unhover" });
|
|
7597
|
+
}, [linkPopover, postToParent2]);
|
|
7598
|
+
(0, import_react8.useEffect)(() => {
|
|
6530
7599
|
if (!isEditMode) return;
|
|
6531
7600
|
const useFixtures = shouldUseDevFixtures();
|
|
6532
7601
|
if (useFixtures) {
|
|
@@ -6547,17 +7616,17 @@ function OhhwellsBridge() {
|
|
|
6547
7616
|
runSectionsPrefetchRef.current(mapped);
|
|
6548
7617
|
};
|
|
6549
7618
|
window.addEventListener("message", onSitePages);
|
|
6550
|
-
if (!useFixtures)
|
|
7619
|
+
if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
|
|
6551
7620
|
return () => window.removeEventListener("message", onSitePages);
|
|
6552
|
-
}, [isEditMode,
|
|
6553
|
-
(0,
|
|
7621
|
+
}, [isEditMode, postToParent2]);
|
|
7622
|
+
(0, import_react8.useEffect)(() => {
|
|
6554
7623
|
if (!isEditMode || shouldUseDevFixtures()) return;
|
|
6555
7624
|
void loadAllSectionsManifest().then((manifest) => {
|
|
6556
7625
|
if (Object.keys(manifest).length === 0) return;
|
|
6557
7626
|
setSectionsByPath((prev) => ({ ...manifest, ...prev }));
|
|
6558
7627
|
});
|
|
6559
7628
|
}, [isEditMode]);
|
|
6560
|
-
(0,
|
|
7629
|
+
(0, import_react8.useEffect)(() => {
|
|
6561
7630
|
const update = () => {
|
|
6562
7631
|
const el = activeElRef.current ?? selectedElRef.current;
|
|
6563
7632
|
if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
|
|
@@ -6581,10 +7650,10 @@ function OhhwellsBridge() {
|
|
|
6581
7650
|
vvp.removeEventListener("resize", update);
|
|
6582
7651
|
};
|
|
6583
7652
|
}, []);
|
|
6584
|
-
const refreshStateRules = (0,
|
|
7653
|
+
const refreshStateRules = (0, import_react8.useCallback)(() => {
|
|
6585
7654
|
editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
|
|
6586
7655
|
}, []);
|
|
6587
|
-
const processConfigRequest = (0,
|
|
7656
|
+
const processConfigRequest = (0, import_react8.useCallback)((insertAfterVal) => {
|
|
6588
7657
|
const tracker = getSectionsTracker();
|
|
6589
7658
|
let entries = [];
|
|
6590
7659
|
try {
|
|
@@ -6607,7 +7676,7 @@ function OhhwellsBridge() {
|
|
|
6607
7676
|
}
|
|
6608
7677
|
window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
|
|
6609
7678
|
}, [isEditMode]);
|
|
6610
|
-
const deactivate = (0,
|
|
7679
|
+
const deactivate = (0, import_react8.useCallback)(() => {
|
|
6611
7680
|
const el = activeElRef.current;
|
|
6612
7681
|
if (!el) return;
|
|
6613
7682
|
const key = el.dataset.ohwKey;
|
|
@@ -6636,21 +7705,23 @@ function OhhwellsBridge() {
|
|
|
6636
7705
|
setMaxBadge(null);
|
|
6637
7706
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
6638
7707
|
setToolbarShowEditLink(false);
|
|
6639
|
-
|
|
6640
|
-
}, [
|
|
6641
|
-
const deselect = (0,
|
|
7708
|
+
postToParent2({ type: "ow:exit-edit" });
|
|
7709
|
+
}, [postToParent2]);
|
|
7710
|
+
const deselect = (0, import_react8.useCallback)(() => {
|
|
6642
7711
|
selectedElRef.current = null;
|
|
6643
7712
|
setReorderHrefKey(null);
|
|
6644
7713
|
setReorderDragDisabled(false);
|
|
6645
7714
|
siblingHintElRef.current = null;
|
|
6646
7715
|
setSiblingHintRect(null);
|
|
6647
7716
|
setIsItemDragging(false);
|
|
7717
|
+
hoveredNavContainerRef.current = null;
|
|
7718
|
+
setHoveredNavContainerRect(null);
|
|
6648
7719
|
if (!activeElRef.current) {
|
|
6649
7720
|
setToolbarRect(null);
|
|
6650
7721
|
setToolbarVariant("none");
|
|
6651
7722
|
}
|
|
6652
7723
|
}, []);
|
|
6653
|
-
const reselectNavigationItem = (0,
|
|
7724
|
+
const reselectNavigationItem = (0, import_react8.useCallback)((navAnchor) => {
|
|
6654
7725
|
selectedElRef.current = navAnchor;
|
|
6655
7726
|
const { key, disabled } = getNavigationItemReorderState(navAnchor);
|
|
6656
7727
|
setReorderHrefKey(key);
|
|
@@ -6660,7 +7731,7 @@ function OhhwellsBridge() {
|
|
|
6660
7731
|
setToolbarShowEditLink(false);
|
|
6661
7732
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
6662
7733
|
}, []);
|
|
6663
|
-
const commitNavigationTextEdit = (0,
|
|
7734
|
+
const commitNavigationTextEdit = (0, import_react8.useCallback)((navAnchor) => {
|
|
6664
7735
|
const el = activeElRef.current;
|
|
6665
7736
|
if (!el) return;
|
|
6666
7737
|
const key = el.dataset.ohwKey;
|
|
@@ -6673,9 +7744,9 @@ function OhhwellsBridge() {
|
|
|
6673
7744
|
const html = sanitizeHtml(el.innerHTML);
|
|
6674
7745
|
const original = originalContentRef.current ?? "";
|
|
6675
7746
|
if (html !== sanitizeHtml(original)) {
|
|
6676
|
-
|
|
7747
|
+
postToParent2({ type: "ow:change", nodes: [{ key, text: html }] });
|
|
6677
7748
|
const h = document.documentElement.scrollHeight;
|
|
6678
|
-
if (h > 50)
|
|
7749
|
+
if (h > 50) postToParent2({ type: "ow:height", height: h });
|
|
6679
7750
|
}
|
|
6680
7751
|
}
|
|
6681
7752
|
el.removeAttribute("contenteditable");
|
|
@@ -6683,31 +7754,38 @@ function OhhwellsBridge() {
|
|
|
6683
7754
|
setMaxBadge(null);
|
|
6684
7755
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
6685
7756
|
setToolbarShowEditLink(false);
|
|
6686
|
-
|
|
7757
|
+
postToParent2({ type: "ow:exit-edit" });
|
|
6687
7758
|
reselectNavigationItem(navAnchor);
|
|
6688
|
-
}, [
|
|
6689
|
-
const
|
|
6690
|
-
const
|
|
6691
|
-
|
|
6692
|
-
|
|
6693
|
-
|
|
6694
|
-
|
|
7759
|
+
}, [postToParent2, reselectNavigationItem]);
|
|
7760
|
+
const handleAddTopLevelNavItem = (0, import_react8.useCallback)(() => {
|
|
7761
|
+
const items = listNavbarItems();
|
|
7762
|
+
addNavAfterAnchorRef.current = items[items.length - 1] ?? null;
|
|
7763
|
+
deselectRef.current();
|
|
7764
|
+
deactivateRef.current();
|
|
7765
|
+
bumpLinkPopoverGrace();
|
|
7766
|
+
setLinkPopover({
|
|
7767
|
+
key: "__add-nav__",
|
|
7768
|
+
mode: "create",
|
|
7769
|
+
intent: "add-nav"
|
|
7770
|
+
});
|
|
6695
7771
|
}, []);
|
|
6696
|
-
const handleItemDragStart = (0,
|
|
7772
|
+
const handleItemDragStart = (0, import_react8.useCallback)(() => {
|
|
6697
7773
|
siblingHintElRef.current = null;
|
|
6698
7774
|
setSiblingHintRect(null);
|
|
6699
7775
|
setIsItemDragging(true);
|
|
6700
7776
|
}, []);
|
|
6701
|
-
const handleItemDragEnd = (0,
|
|
7777
|
+
const handleItemDragEnd = (0, import_react8.useCallback)(() => {
|
|
6702
7778
|
setIsItemDragging(false);
|
|
6703
7779
|
}, []);
|
|
6704
7780
|
reselectNavigationItemRef.current = reselectNavigationItem;
|
|
6705
7781
|
commitNavigationTextEditRef.current = commitNavigationTextEdit;
|
|
6706
|
-
const select = (0,
|
|
7782
|
+
const select = (0, import_react8.useCallback)((anchor) => {
|
|
6707
7783
|
if (!isNavigationItem(anchor)) return;
|
|
6708
7784
|
if (activeElRef.current) deactivate();
|
|
6709
7785
|
selectedElRef.current = anchor;
|
|
6710
7786
|
clearHrefKeyHover(anchor);
|
|
7787
|
+
hoveredNavContainerRef.current = null;
|
|
7788
|
+
setHoveredNavContainerRect(null);
|
|
6711
7789
|
setHoveredItemRect(null);
|
|
6712
7790
|
hoveredItemElRef.current = null;
|
|
6713
7791
|
siblingHintElRef.current = null;
|
|
@@ -6721,13 +7799,32 @@ function OhhwellsBridge() {
|
|
|
6721
7799
|
setToolbarShowEditLink(false);
|
|
6722
7800
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
6723
7801
|
}, [deactivate]);
|
|
6724
|
-
const
|
|
7802
|
+
const selectFrame = (0, import_react8.useCallback)((el) => {
|
|
7803
|
+
if (!isNavigationContainer(el)) return;
|
|
7804
|
+
if (activeElRef.current) deactivate();
|
|
7805
|
+
selectedElRef.current = el;
|
|
7806
|
+
clearHrefKeyHover(el);
|
|
7807
|
+
hoveredNavContainerRef.current = null;
|
|
7808
|
+
setHoveredNavContainerRect(null);
|
|
7809
|
+
setHoveredItemRect(null);
|
|
7810
|
+
hoveredItemElRef.current = null;
|
|
7811
|
+
siblingHintElRef.current = null;
|
|
7812
|
+
setSiblingHintRect(null);
|
|
7813
|
+
setIsItemDragging(false);
|
|
7814
|
+
setReorderHrefKey(null);
|
|
7815
|
+
setReorderDragDisabled(false);
|
|
7816
|
+
setToolbarVariant("select-frame");
|
|
7817
|
+
setToolbarRect(el.getBoundingClientRect());
|
|
7818
|
+
setToolbarShowEditLink(false);
|
|
7819
|
+
setActiveCommands(/* @__PURE__ */ new Set());
|
|
7820
|
+
}, [deactivate]);
|
|
7821
|
+
const activate = (0, import_react8.useCallback)((el, options) => {
|
|
6725
7822
|
if (activeElRef.current === el) return;
|
|
6726
7823
|
selectedElRef.current = null;
|
|
6727
7824
|
deactivate();
|
|
6728
7825
|
if (hoveredImageRef.current) {
|
|
6729
7826
|
hoveredImageRef.current = null;
|
|
6730
|
-
|
|
7827
|
+
setMediaHover(null);
|
|
6731
7828
|
}
|
|
6732
7829
|
setToolbarVariant("rich-text");
|
|
6733
7830
|
siblingHintElRef.current = null;
|
|
@@ -6739,6 +7836,9 @@ function OhhwellsBridge() {
|
|
|
6739
7836
|
activeElRef.current = el;
|
|
6740
7837
|
originalContentRef.current = el.innerHTML;
|
|
6741
7838
|
el.focus();
|
|
7839
|
+
if (options?.caretX !== void 0 && options?.caretY !== void 0) {
|
|
7840
|
+
placeCaretAtPoint(el, options.caretX, options.caretY);
|
|
7841
|
+
}
|
|
6742
7842
|
setToolbarShowEditLink(Boolean(getHrefKeyFromElement(el)));
|
|
6743
7843
|
const navAnchor = getNavigationItemAnchor(el);
|
|
6744
7844
|
if (navAnchor) {
|
|
@@ -6750,14 +7850,15 @@ function OhhwellsBridge() {
|
|
|
6750
7850
|
setReorderDragDisabled(reorderDisabled);
|
|
6751
7851
|
}
|
|
6752
7852
|
setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
|
|
6753
|
-
|
|
7853
|
+
postToParent2({ type: "ow:enter-edit", key: el.dataset.ohwKey });
|
|
6754
7854
|
requestAnimationFrame(() => refreshActiveCommandsRef.current());
|
|
6755
|
-
}, [deactivate,
|
|
7855
|
+
}, [deactivate, postToParent2]);
|
|
6756
7856
|
activateRef.current = activate;
|
|
6757
7857
|
deactivateRef.current = deactivate;
|
|
6758
7858
|
selectRef.current = select;
|
|
7859
|
+
selectFrameRef.current = selectFrame;
|
|
6759
7860
|
deselectRef.current = deselect;
|
|
6760
|
-
(0,
|
|
7861
|
+
(0, import_react8.useLayoutEffect)(() => {
|
|
6761
7862
|
if (!subdomain || isEditMode) {
|
|
6762
7863
|
setFetchState("done");
|
|
6763
7864
|
return;
|
|
@@ -6766,11 +7867,12 @@ function OhhwellsBridge() {
|
|
|
6766
7867
|
const imageLoads = [];
|
|
6767
7868
|
for (const [key, val] of Object.entries(content)) {
|
|
6768
7869
|
if (key === "__ohw_sections") continue;
|
|
7870
|
+
if (applyVideoSettingNode(key, val)) continue;
|
|
6769
7871
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
6770
7872
|
if (el.dataset.ohwEditable === "image") {
|
|
6771
7873
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
6772
7874
|
if (img && img.src !== val) {
|
|
6773
|
-
img
|
|
7875
|
+
applyEditableImageSrc(img, val);
|
|
6774
7876
|
imageLoads.push(new Promise((resolve) => {
|
|
6775
7877
|
img.onload = () => resolve();
|
|
6776
7878
|
img.onerror = () => resolve();
|
|
@@ -6779,6 +7881,15 @@ function OhhwellsBridge() {
|
|
|
6779
7881
|
} else if (el.dataset.ohwEditable === "bg-image") {
|
|
6780
7882
|
const next = `url('${val}')`;
|
|
6781
7883
|
if (el.style.backgroundImage !== next) el.style.backgroundImage = next;
|
|
7884
|
+
} else if (el.dataset.ohwEditable === "video") {
|
|
7885
|
+
const video = getVideoEl(el);
|
|
7886
|
+
if (video && video.src !== val) {
|
|
7887
|
+
applyVideoSrc(video, val);
|
|
7888
|
+
imageLoads.push(new Promise((resolve) => {
|
|
7889
|
+
video.onloadeddata = () => resolve();
|
|
7890
|
+
video.onerror = () => resolve();
|
|
7891
|
+
}));
|
|
7892
|
+
}
|
|
6782
7893
|
} else if (el.dataset.ohwEditable === "link") {
|
|
6783
7894
|
applyLinkHref(el, val);
|
|
6784
7895
|
} else if (el.innerHTML !== val) {
|
|
@@ -6787,6 +7898,7 @@ function OhhwellsBridge() {
|
|
|
6787
7898
|
});
|
|
6788
7899
|
applyLinkByKey(key, val);
|
|
6789
7900
|
}
|
|
7901
|
+
reconcileNavbarItemsFromContent(content);
|
|
6790
7902
|
enforceLinkHrefs();
|
|
6791
7903
|
initSectionsFromContent(content, true);
|
|
6792
7904
|
sectionsLoadedRef.current = true;
|
|
@@ -6815,7 +7927,7 @@ function OhhwellsBridge() {
|
|
|
6815
7927
|
cancelled = true;
|
|
6816
7928
|
};
|
|
6817
7929
|
}, [subdomain, isEditMode]);
|
|
6818
|
-
(0,
|
|
7930
|
+
(0, import_react8.useEffect)(() => {
|
|
6819
7931
|
if (!subdomain || isEditMode) return;
|
|
6820
7932
|
let debounceTimer = null;
|
|
6821
7933
|
let observer = null;
|
|
@@ -6827,13 +7939,17 @@ function OhhwellsBridge() {
|
|
|
6827
7939
|
try {
|
|
6828
7940
|
for (const [key, val] of Object.entries(content)) {
|
|
6829
7941
|
if (key === "__ohw_sections") continue;
|
|
7942
|
+
if (applyVideoSettingNode(key, val)) continue;
|
|
6830
7943
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
6831
7944
|
if (el.dataset.ohwEditable === "image") {
|
|
6832
7945
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
6833
|
-
if (img && img.src !== val) img
|
|
7946
|
+
if (img && img.src !== val) applyEditableImageSrc(img, val);
|
|
6834
7947
|
} else if (el.dataset.ohwEditable === "bg-image") {
|
|
6835
7948
|
const next = `url('${val}')`;
|
|
6836
7949
|
if (el.style.backgroundImage !== next) el.style.backgroundImage = next;
|
|
7950
|
+
} else if (el.dataset.ohwEditable === "video") {
|
|
7951
|
+
const video = getVideoEl(el);
|
|
7952
|
+
if (video && video.src !== val) applyVideoSrc(video, val);
|
|
6837
7953
|
} else if (el.dataset.ohwEditable === "link") {
|
|
6838
7954
|
applyLinkHref(el, val);
|
|
6839
7955
|
} else if (el.innerHTML !== val) {
|
|
@@ -6842,6 +7958,7 @@ function OhhwellsBridge() {
|
|
|
6842
7958
|
});
|
|
6843
7959
|
applyLinkByKey(key, val);
|
|
6844
7960
|
}
|
|
7961
|
+
reconcileNavbarItemsFromContent(content);
|
|
6845
7962
|
} finally {
|
|
6846
7963
|
observer?.observe(document.body, { childList: true, subtree: true });
|
|
6847
7964
|
}
|
|
@@ -6859,26 +7976,44 @@ function OhhwellsBridge() {
|
|
|
6859
7976
|
if (debounceTimer) clearTimeout(debounceTimer);
|
|
6860
7977
|
};
|
|
6861
7978
|
}, [subdomain, isEditMode, pathname]);
|
|
6862
|
-
(0,
|
|
7979
|
+
(0, import_react8.useLayoutEffect)(() => {
|
|
6863
7980
|
const el = document.getElementById("ohw-loader");
|
|
6864
7981
|
if (!el) return;
|
|
6865
7982
|
const visible = Boolean(subdomain) && fetchState !== "done";
|
|
6866
7983
|
el.style.display = visible ? "flex" : "none";
|
|
6867
7984
|
}, [subdomain, fetchState]);
|
|
6868
|
-
(0,
|
|
6869
|
-
|
|
6870
|
-
}, [pathname,
|
|
6871
|
-
(0,
|
|
7985
|
+
(0, import_react8.useEffect)(() => {
|
|
7986
|
+
postToParent2({ type: "ow:navigation", path: pathname });
|
|
7987
|
+
}, [pathname, postToParent2]);
|
|
7988
|
+
(0, import_react8.useEffect)(() => {
|
|
6872
7989
|
if (!isEditMode) return;
|
|
7990
|
+
if (linkPopoverSessionRef.current?.intent === "add-nav") return;
|
|
7991
|
+
if (document.querySelector("[data-ohw-section-picker]")) return;
|
|
6873
7992
|
setLinkPopover(null);
|
|
6874
7993
|
deselectRef.current();
|
|
6875
7994
|
deactivateRef.current();
|
|
6876
7995
|
}, [pathname, isEditMode]);
|
|
6877
|
-
(0,
|
|
7996
|
+
(0, import_react8.useEffect)(() => {
|
|
7997
|
+
const contentForNav = () => {
|
|
7998
|
+
if (isEditMode) return editContentRef.current;
|
|
7999
|
+
if (!subdomain) return {};
|
|
8000
|
+
return contentCache.get(subdomain) ?? {};
|
|
8001
|
+
};
|
|
8002
|
+
const run = () => reconcileNavbarItemsFromContent(contentForNav());
|
|
8003
|
+
run();
|
|
8004
|
+
const nav = document.querySelector("nav");
|
|
8005
|
+
if (!nav) return;
|
|
8006
|
+
const observer = new MutationObserver(() => {
|
|
8007
|
+
requestAnimationFrame(run);
|
|
8008
|
+
});
|
|
8009
|
+
observer.observe(nav, { childList: true, subtree: true });
|
|
8010
|
+
return () => observer.disconnect();
|
|
8011
|
+
}, [isEditMode, pathname, subdomain, fetchState]);
|
|
8012
|
+
(0, import_react8.useEffect)(() => {
|
|
6878
8013
|
if (!isEditMode) return;
|
|
6879
8014
|
const measure = () => {
|
|
6880
8015
|
const h = document.body.scrollHeight;
|
|
6881
|
-
if (h > 50)
|
|
8016
|
+
if (h > 50) postToParent2({ type: "ow:height", height: h });
|
|
6882
8017
|
};
|
|
6883
8018
|
const t1 = setTimeout(measure, 50);
|
|
6884
8019
|
const t2 = setTimeout(measure, 500);
|
|
@@ -6897,8 +8032,8 @@ function OhhwellsBridge() {
|
|
|
6897
8032
|
if (resizeTimer) clearTimeout(resizeTimer);
|
|
6898
8033
|
window.removeEventListener("resize", handleResize);
|
|
6899
8034
|
};
|
|
6900
|
-
}, [pathname, isEditMode,
|
|
6901
|
-
(0,
|
|
8035
|
+
}, [pathname, isEditMode, postToParent2]);
|
|
8036
|
+
(0, import_react8.useEffect)(() => {
|
|
6902
8037
|
if (!subdomainFromQuery || isEditMode) return;
|
|
6903
8038
|
const handleClick = (e) => {
|
|
6904
8039
|
const anchor = e.target.closest("a");
|
|
@@ -6914,7 +8049,7 @@ function OhhwellsBridge() {
|
|
|
6914
8049
|
document.addEventListener("click", handleClick, true);
|
|
6915
8050
|
return () => document.removeEventListener("click", handleClick, true);
|
|
6916
8051
|
}, [subdomainFromQuery, isEditMode, router]);
|
|
6917
|
-
(0,
|
|
8052
|
+
(0, import_react8.useEffect)(() => {
|
|
6918
8053
|
if (!isEditMode) {
|
|
6919
8054
|
editStylesRef.current?.base.remove();
|
|
6920
8055
|
editStylesRef.current?.forceHover.remove();
|
|
@@ -6937,8 +8072,9 @@ function OhhwellsBridge() {
|
|
|
6937
8072
|
[data-ohw-editable] {
|
|
6938
8073
|
display: block;
|
|
6939
8074
|
}
|
|
6940
|
-
[data-ohw-editable]:not([contenteditable]):not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]) { cursor: text !important; }
|
|
8075
|
+
[data-ohw-editable]:not([contenteditable]):not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"]) { cursor: text !important; }
|
|
6941
8076
|
[data-ohw-editable="image"], [data-ohw-editable="image"] *,
|
|
8077
|
+
[data-ohw-editable="video"], [data-ohw-editable="video"] *,
|
|
6942
8078
|
[data-ohw-editable="bg-image"], [data-ohw-editable="bg-image"] * { cursor: pointer !important; }
|
|
6943
8079
|
[data-ohw-editable="link"], [data-ohw-editable="link"] * { cursor: pointer !important; }
|
|
6944
8080
|
[data-ohw-hovered]:not([contenteditable]):not([data-ohw-href-key]) {
|
|
@@ -6987,6 +8123,13 @@ function OhhwellsBridge() {
|
|
|
6987
8123
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
6988
8124
|
if (isInsideLinkEditor(target)) return;
|
|
6989
8125
|
if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
|
|
8126
|
+
const navFromChrome = resolveNavContainerSelectionTarget(target, e.clientX, e.clientY);
|
|
8127
|
+
if (navFromChrome) {
|
|
8128
|
+
e.preventDefault();
|
|
8129
|
+
e.stopPropagation();
|
|
8130
|
+
selectFrameRef.current(navFromChrome);
|
|
8131
|
+
return;
|
|
8132
|
+
}
|
|
6990
8133
|
e.preventDefault();
|
|
6991
8134
|
e.stopPropagation();
|
|
6992
8135
|
return;
|
|
@@ -7001,14 +8144,15 @@ function OhhwellsBridge() {
|
|
|
7001
8144
|
bumpLinkPopoverGrace();
|
|
7002
8145
|
setLinkPopoverRef.current({
|
|
7003
8146
|
key: editable.dataset.ohwKey ?? "",
|
|
7004
|
-
|
|
8147
|
+
mode: "edit",
|
|
8148
|
+
target: getLinkHref2(editable)
|
|
7005
8149
|
});
|
|
7006
8150
|
return;
|
|
7007
8151
|
}
|
|
7008
|
-
if (editable
|
|
8152
|
+
if (isMediaEditable(editable)) {
|
|
7009
8153
|
e.preventDefault();
|
|
7010
8154
|
e.stopPropagation();
|
|
7011
|
-
postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "" });
|
|
8155
|
+
postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "", elementType: editable.dataset.ohwEditable ?? "image" });
|
|
7012
8156
|
return;
|
|
7013
8157
|
}
|
|
7014
8158
|
const hrefCtx = getHrefKeyFromElement(editable);
|
|
@@ -7017,7 +8161,8 @@ function OhhwellsBridge() {
|
|
|
7017
8161
|
e.preventDefault();
|
|
7018
8162
|
e.stopPropagation();
|
|
7019
8163
|
if (selectedElRef.current === navAnchor) {
|
|
7020
|
-
|
|
8164
|
+
if (e.detail >= 2) return;
|
|
8165
|
+
activateRef.current(editable, { caretX: e.clientX, caretY: e.clientY });
|
|
7021
8166
|
return;
|
|
7022
8167
|
}
|
|
7023
8168
|
selectRef.current(navAnchor);
|
|
@@ -7036,6 +8181,22 @@ function OhhwellsBridge() {
|
|
|
7036
8181
|
selectRef.current(hrefAnchor);
|
|
7037
8182
|
return;
|
|
7038
8183
|
}
|
|
8184
|
+
const navContainerToSelect = resolveNavContainerSelectionTarget(target, e.clientX, e.clientY);
|
|
8185
|
+
if (navContainerToSelect) {
|
|
8186
|
+
e.preventDefault();
|
|
8187
|
+
e.stopPropagation();
|
|
8188
|
+
selectFrameRef.current(navContainerToSelect);
|
|
8189
|
+
return;
|
|
8190
|
+
}
|
|
8191
|
+
const selectedContainer = selectedElRef.current;
|
|
8192
|
+
if (selectedContainer && isNavigationContainer(selectedContainer)) {
|
|
8193
|
+
const navItem = getNavigationItemAnchor(target);
|
|
8194
|
+
if (!navItem && (selectedContainer === target || selectedContainer.contains(target))) {
|
|
8195
|
+
e.preventDefault();
|
|
8196
|
+
e.stopPropagation();
|
|
8197
|
+
return;
|
|
8198
|
+
}
|
|
8199
|
+
}
|
|
7039
8200
|
if (activeElRef.current) {
|
|
7040
8201
|
const sel = window.getSelection();
|
|
7041
8202
|
if (sel && !sel.isCollapsed) {
|
|
@@ -7061,10 +8222,48 @@ function OhhwellsBridge() {
|
|
|
7061
8222
|
deselectRef.current();
|
|
7062
8223
|
deactivateRef.current();
|
|
7063
8224
|
};
|
|
8225
|
+
const handleDblClick = (e) => {
|
|
8226
|
+
const target = e.target;
|
|
8227
|
+
if (target.closest("[data-ohw-toolbar]")) return;
|
|
8228
|
+
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
8229
|
+
if (target.closest("[data-ohw-max-badge]")) return;
|
|
8230
|
+
if (isInsideLinkEditor(target)) return;
|
|
8231
|
+
if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
|
|
8232
|
+
return;
|
|
8233
|
+
}
|
|
8234
|
+
const navLabel = getNavigationLabelEditable(target);
|
|
8235
|
+
if (!navLabel) return;
|
|
8236
|
+
const { editable } = navLabel;
|
|
8237
|
+
e.preventDefault();
|
|
8238
|
+
e.stopPropagation();
|
|
8239
|
+
if (activeElRef.current !== editable) {
|
|
8240
|
+
activateRef.current(editable);
|
|
8241
|
+
}
|
|
8242
|
+
requestAnimationFrame(() => {
|
|
8243
|
+
selectAllTextInEditable(editable);
|
|
8244
|
+
refreshActiveCommandsRef.current();
|
|
8245
|
+
});
|
|
8246
|
+
};
|
|
7064
8247
|
const handleMouseOver = (e) => {
|
|
7065
8248
|
const target = e.target;
|
|
8249
|
+
if (toolbarVariantRef.current !== "select-frame") {
|
|
8250
|
+
const navContainer = target.closest("[data-ohw-nav-container]");
|
|
8251
|
+
if (navContainer && !getNavigationItemAnchor(target)) {
|
|
8252
|
+
hoveredNavContainerRef.current = navContainer;
|
|
8253
|
+
setHoveredNavContainerRect(navContainer.getBoundingClientRect());
|
|
8254
|
+
hoveredItemElRef.current = null;
|
|
8255
|
+
setHoveredItemRect(null);
|
|
8256
|
+
return;
|
|
8257
|
+
}
|
|
8258
|
+
if (!target.closest("[data-ohw-nav-container]")) {
|
|
8259
|
+
hoveredNavContainerRef.current = null;
|
|
8260
|
+
setHoveredNavContainerRect(null);
|
|
8261
|
+
}
|
|
8262
|
+
}
|
|
7066
8263
|
const navAnchor = getNavigationItemAnchor(target);
|
|
7067
8264
|
if (navAnchor) {
|
|
8265
|
+
hoveredNavContainerRef.current = null;
|
|
8266
|
+
setHoveredNavContainerRect(null);
|
|
7068
8267
|
const selected2 = selectedElRef.current;
|
|
7069
8268
|
if (selected2 === navAnchor || selected2?.contains(navAnchor)) return;
|
|
7070
8269
|
clearHrefKeyHover(navAnchor);
|
|
@@ -7076,7 +8275,7 @@ function OhhwellsBridge() {
|
|
|
7076
8275
|
if (!editable) return;
|
|
7077
8276
|
const selected = selectedElRef.current;
|
|
7078
8277
|
if (selected && (selected === editable || selected.contains(editable))) return;
|
|
7079
|
-
if (editable
|
|
8278
|
+
if (!isMediaEditable(editable) && !editable.hasAttribute("contenteditable")) {
|
|
7080
8279
|
const hoverTarget = editable.closest("[data-ohw-href-key]") ?? editable;
|
|
7081
8280
|
if (hoverTarget.hasAttribute("data-ohw-href-key")) {
|
|
7082
8281
|
clearHrefKeyHover(hoverTarget);
|
|
@@ -7089,6 +8288,14 @@ function OhhwellsBridge() {
|
|
|
7089
8288
|
};
|
|
7090
8289
|
const handleMouseOut = (e) => {
|
|
7091
8290
|
const target = e.target;
|
|
8291
|
+
if (target.closest("[data-ohw-nav-container]")) {
|
|
8292
|
+
const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
8293
|
+
if (related2?.closest("[data-ohw-nav-container], [data-ohw-navbar-container-chrome], [data-ohw-navbar-add-button]")) {
|
|
8294
|
+
return;
|
|
8295
|
+
}
|
|
8296
|
+
hoveredNavContainerRef.current = null;
|
|
8297
|
+
setHoveredNavContainerRect(null);
|
|
8298
|
+
}
|
|
7092
8299
|
const navAnchor = getNavigationItemAnchor(target);
|
|
7093
8300
|
if (navAnchor) {
|
|
7094
8301
|
const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
@@ -7104,7 +8311,7 @@ function OhhwellsBridge() {
|
|
|
7104
8311
|
if (!editable) return;
|
|
7105
8312
|
const related = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
7106
8313
|
if (related?.closest("[data-ohw-drag-handle-container], [data-ohw-item-interaction]")) return;
|
|
7107
|
-
if (editable
|
|
8314
|
+
if (!isMediaEditable(editable)) {
|
|
7108
8315
|
const hoverTarget = editable.closest("[data-ohw-href-key]") ?? editable;
|
|
7109
8316
|
if (hoverTarget.hasAttribute("data-ohw-href-key")) {
|
|
7110
8317
|
if (!related?.closest("[data-ohw-href-key]")) {
|
|
@@ -7150,23 +8357,26 @@ function OhhwellsBridge() {
|
|
|
7150
8357
|
}
|
|
7151
8358
|
return { top, left, width: Math.max(0, right - left), height: Math.max(0, bottom - top) };
|
|
7152
8359
|
};
|
|
7153
|
-
const
|
|
8360
|
+
const showImageHover = (imgEl, isDragOver = false, forceTextOverlap) => {
|
|
7154
8361
|
const r2 = getVisibleRect(imgEl);
|
|
7155
8362
|
const hasTextOverlap = forceTextOverlap ?? false;
|
|
7156
8363
|
hoveredImageHasTextOverlapRef.current = hasTextOverlap;
|
|
7157
|
-
|
|
7158
|
-
|
|
8364
|
+
const video = imgEl.dataset.ohwEditable === "video" ? getVideoEl(imgEl) : null;
|
|
8365
|
+
setMediaHover({
|
|
7159
8366
|
key: imgEl.dataset.ohwKey ?? "",
|
|
7160
8367
|
rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height },
|
|
8368
|
+
elementType: imgEl.dataset.ohwEditable ?? "image",
|
|
7161
8369
|
hasTextOverlap,
|
|
7162
|
-
|
|
8370
|
+
isDragOver,
|
|
8371
|
+
...video ? { videoAutoplay: video.autoplay, videoMuted: video.muted } : {}
|
|
7163
8372
|
});
|
|
7164
8373
|
const track = imgEl.closest("[data-ohw-hover-pause]");
|
|
7165
8374
|
if (track) track.setAttribute("data-ohw-hover-paused", "");
|
|
7166
8375
|
};
|
|
8376
|
+
const clearImageHover = () => setMediaHover(null);
|
|
7167
8377
|
const findImageAtPoint = (clientX, clientY, fromParentViewport) => {
|
|
7168
8378
|
const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
7169
|
-
const images = Array.from(document.querySelectorAll(
|
|
8379
|
+
const images = Array.from(document.querySelectorAll(MEDIA_SELECTOR));
|
|
7170
8380
|
const matches = [];
|
|
7171
8381
|
for (let i = images.length - 1; i >= 0; i--) {
|
|
7172
8382
|
const el = images[i];
|
|
@@ -7182,7 +8392,9 @@ function OhhwellsBridge() {
|
|
|
7182
8392
|
if (x >= r2.left && x <= r2.left + r2.width && y >= r2.top && y <= r2.top + r2.height) matches.push(el);
|
|
7183
8393
|
}
|
|
7184
8394
|
if (matches.length === 0) return null;
|
|
7185
|
-
const imageTypeMatches = matches.filter(
|
|
8395
|
+
const imageTypeMatches = matches.filter(
|
|
8396
|
+
(el) => el.dataset.ohwEditable === "image" || el.dataset.ohwEditable === "video"
|
|
8397
|
+
);
|
|
7186
8398
|
const candidatePool = imageTypeMatches.length > 0 ? imageTypeMatches : matches;
|
|
7187
8399
|
const smallest = candidatePool.reduce((best, el) => {
|
|
7188
8400
|
const br = getVisibleRect(best);
|
|
@@ -7205,47 +8417,91 @@ function OhhwellsBridge() {
|
|
|
7205
8417
|
}
|
|
7206
8418
|
return smallest;
|
|
7207
8419
|
};
|
|
8420
|
+
const dismissImageHover = () => {
|
|
8421
|
+
if (hoveredImageRef.current) {
|
|
8422
|
+
hoveredImageRef.current = null;
|
|
8423
|
+
hoveredImageHasTextOverlapRef.current = false;
|
|
8424
|
+
resumeAnimTracks();
|
|
8425
|
+
postToParentRef.current({ type: "ow:image-unhover" });
|
|
8426
|
+
}
|
|
8427
|
+
clearImageHover();
|
|
8428
|
+
};
|
|
8429
|
+
const probeNavigationHoverAt = (x, y) => {
|
|
8430
|
+
if (toolbarVariantRef.current === "select-frame") {
|
|
8431
|
+
hoveredNavContainerRef.current = null;
|
|
8432
|
+
setHoveredNavContainerRect(null);
|
|
8433
|
+
return;
|
|
8434
|
+
}
|
|
8435
|
+
const navContainer = document.querySelector("[data-ohw-nav-container]");
|
|
8436
|
+
if (!navContainer) {
|
|
8437
|
+
hoveredNavContainerRef.current = null;
|
|
8438
|
+
setHoveredNavContainerRect(null);
|
|
8439
|
+
return;
|
|
8440
|
+
}
|
|
8441
|
+
const containerRect = navContainer.getBoundingClientRect();
|
|
8442
|
+
const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
|
|
8443
|
+
if (!overContainer) {
|
|
8444
|
+
hoveredNavContainerRef.current = null;
|
|
8445
|
+
setHoveredNavContainerRect(null);
|
|
8446
|
+
return;
|
|
8447
|
+
}
|
|
8448
|
+
const navItemHit = Array.from(
|
|
8449
|
+
navContainer.querySelectorAll("[data-ohw-href-key]")
|
|
8450
|
+
).find((el) => {
|
|
8451
|
+
if (!isNavigationItem(el) || isNavbarButton2(el)) return false;
|
|
8452
|
+
const itemRect = el.getBoundingClientRect();
|
|
8453
|
+
return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
|
|
8454
|
+
});
|
|
8455
|
+
if (navItemHit) {
|
|
8456
|
+
hoveredNavContainerRef.current = null;
|
|
8457
|
+
setHoveredNavContainerRect(null);
|
|
8458
|
+
const selected = selectedElRef.current;
|
|
8459
|
+
if (selected !== navItemHit && !selected?.contains(navItemHit)) {
|
|
8460
|
+
clearHrefKeyHover(navItemHit);
|
|
8461
|
+
hoveredItemElRef.current = navItemHit;
|
|
8462
|
+
setHoveredItemRect(navItemHit.getBoundingClientRect());
|
|
8463
|
+
}
|
|
8464
|
+
return;
|
|
8465
|
+
}
|
|
8466
|
+
hoveredNavContainerRef.current = navContainer;
|
|
8467
|
+
setHoveredNavContainerRect(containerRect);
|
|
8468
|
+
hoveredItemElRef.current = null;
|
|
8469
|
+
setHoveredItemRect(null);
|
|
8470
|
+
};
|
|
7208
8471
|
const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
|
|
7209
8472
|
if (linkPopoverOpenRef.current) {
|
|
7210
|
-
|
|
7211
|
-
|
|
7212
|
-
|
|
7213
|
-
|
|
7214
|
-
|
|
7215
|
-
|
|
8473
|
+
dismissImageHover();
|
|
8474
|
+
return;
|
|
8475
|
+
}
|
|
8476
|
+
const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
8477
|
+
if (isPointOverNavigation(x, y)) {
|
|
8478
|
+
dismissImageHover();
|
|
8479
|
+
probeNavigationHoverAt(x, y);
|
|
7216
8480
|
return;
|
|
7217
8481
|
}
|
|
8482
|
+
hoveredNavContainerRef.current = null;
|
|
8483
|
+
setHoveredNavContainerRect(null);
|
|
7218
8484
|
const toggleEl = document.querySelector("[data-ohw-state-toggle]");
|
|
7219
8485
|
if (toggleEl) {
|
|
7220
|
-
const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
7221
8486
|
const tr = toggleEl.getBoundingClientRect();
|
|
7222
8487
|
if (x >= tr.left && x <= tr.right && y >= tr.top && y <= tr.bottom) {
|
|
7223
|
-
|
|
7224
|
-
hoveredImageRef.current = null;
|
|
7225
|
-
resumeAnimTracks();
|
|
7226
|
-
postToParentRef.current({ type: "ow:image-unhover" });
|
|
7227
|
-
}
|
|
8488
|
+
dismissImageHover();
|
|
7228
8489
|
return;
|
|
7229
8490
|
}
|
|
7230
8491
|
}
|
|
7231
|
-
|
|
7232
|
-
|
|
7233
|
-
|
|
7234
|
-
|
|
7235
|
-
resumeAnimTracks();
|
|
7236
|
-
postToParentRef.current({ type: "ow:image-unhover" });
|
|
7237
|
-
}
|
|
8492
|
+
const imgEl = findImageAtPoint(clientX, clientY, fromParentViewport);
|
|
8493
|
+
const activeEl = activeElRef.current;
|
|
8494
|
+
if (activeEl && (!imgEl || imgEl.contains(activeEl))) {
|
|
8495
|
+
dismissImageHover();
|
|
7238
8496
|
return;
|
|
7239
8497
|
}
|
|
7240
|
-
const imgEl = findImageAtPoint(clientX, clientY, fromParentViewport);
|
|
7241
8498
|
if (imgEl) {
|
|
7242
|
-
const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
7243
8499
|
const topEl = document.elementFromPoint(x, y);
|
|
7244
8500
|
if (topEl?.closest('[data-ohw-toolbar], [data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
|
|
7245
8501
|
if (hoveredImageRef.current) {
|
|
7246
8502
|
hoveredImageRef.current = null;
|
|
7247
8503
|
resumeAnimTracks();
|
|
7248
|
-
|
|
8504
|
+
clearImageHover();
|
|
7249
8505
|
}
|
|
7250
8506
|
return;
|
|
7251
8507
|
}
|
|
@@ -7254,13 +8510,13 @@ function OhhwellsBridge() {
|
|
|
7254
8510
|
hoveredImageRef.current = null;
|
|
7255
8511
|
hoveredImageHasTextOverlapRef.current = false;
|
|
7256
8512
|
resumeAnimTracks();
|
|
7257
|
-
|
|
8513
|
+
clearImageHover();
|
|
7258
8514
|
}
|
|
7259
8515
|
return;
|
|
7260
8516
|
}
|
|
7261
8517
|
const isStateCardImage = !!imgEl.closest("[data-ohw-editable-state]");
|
|
7262
8518
|
const textEditable = Array.from(
|
|
7263
|
-
document.querySelectorAll(
|
|
8519
|
+
document.querySelectorAll(NON_MEDIA_SELECTOR)
|
|
7264
8520
|
).find((el) => {
|
|
7265
8521
|
const er = el.getBoundingClientRect();
|
|
7266
8522
|
return x >= er.left && x <= er.right && y >= er.top && y <= er.bottom;
|
|
@@ -7279,14 +8535,14 @@ function OhhwellsBridge() {
|
|
|
7279
8535
|
hoveredImageRef.current = null;
|
|
7280
8536
|
hoveredImageHasTextOverlapRef.current = false;
|
|
7281
8537
|
resumeAnimTracks();
|
|
7282
|
-
|
|
8538
|
+
clearImageHover();
|
|
7283
8539
|
}
|
|
7284
8540
|
return;
|
|
7285
8541
|
}
|
|
7286
8542
|
if (isStateCardImage) {
|
|
7287
8543
|
if (imgEl !== hoveredImageRef.current || !hoveredImageHasTextOverlapRef.current) {
|
|
7288
8544
|
hoveredImageRef.current = imgEl;
|
|
7289
|
-
|
|
8545
|
+
showImageHover(imgEl, isDragOver, true);
|
|
7290
8546
|
}
|
|
7291
8547
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
7292
8548
|
if (textEditable && !isInsideNavigationItem(textEditable)) {
|
|
@@ -7298,7 +8554,7 @@ function OhhwellsBridge() {
|
|
|
7298
8554
|
hoveredImageRef.current = null;
|
|
7299
8555
|
hoveredImageHasTextOverlapRef.current = false;
|
|
7300
8556
|
resumeAnimTracks();
|
|
7301
|
-
|
|
8557
|
+
clearImageHover();
|
|
7302
8558
|
}
|
|
7303
8559
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
7304
8560
|
if (textEditable && !isInsideNavigationItem(textEditable)) {
|
|
@@ -7310,7 +8566,7 @@ function OhhwellsBridge() {
|
|
|
7310
8566
|
if (hoveredImageRef.current) {
|
|
7311
8567
|
hoveredImageRef.current = null;
|
|
7312
8568
|
resumeAnimTracks();
|
|
7313
|
-
|
|
8569
|
+
clearImageHover();
|
|
7314
8570
|
}
|
|
7315
8571
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
7316
8572
|
return;
|
|
@@ -7318,9 +8574,9 @@ function OhhwellsBridge() {
|
|
|
7318
8574
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
7319
8575
|
if (imgEl !== hoveredImageRef.current || hoveredImageHasTextOverlapRef.current) {
|
|
7320
8576
|
hoveredImageRef.current = imgEl;
|
|
7321
|
-
|
|
8577
|
+
showImageHover(imgEl, isDragOver);
|
|
7322
8578
|
} else if (isDragOver) {
|
|
7323
|
-
|
|
8579
|
+
showImageHover(imgEl, true);
|
|
7324
8580
|
}
|
|
7325
8581
|
} else {
|
|
7326
8582
|
const inIframeView = clientX >= 0 && clientY >= 0 && clientX <= window.innerWidth && clientY <= window.innerHeight;
|
|
@@ -7337,14 +8593,14 @@ function OhhwellsBridge() {
|
|
|
7337
8593
|
hoveredImageRef.current = null;
|
|
7338
8594
|
hoveredImageHasTextOverlapRef.current = false;
|
|
7339
8595
|
resumeAnimTracks();
|
|
7340
|
-
|
|
8596
|
+
clearImageHover();
|
|
7341
8597
|
}
|
|
7342
|
-
const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
8598
|
+
const { x: x2, y: y2 } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
7343
8599
|
const textEl = Array.from(
|
|
7344
|
-
document.querySelectorAll(
|
|
8600
|
+
document.querySelectorAll(NON_MEDIA_SELECTOR)
|
|
7345
8601
|
).find((el) => {
|
|
7346
8602
|
const er = el.getBoundingClientRect();
|
|
7347
|
-
return
|
|
8603
|
+
return x2 >= er.left && x2 <= er.right && y2 >= er.top && y2 <= er.bottom;
|
|
7348
8604
|
});
|
|
7349
8605
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
7350
8606
|
if (textEl && !textEl.hasAttribute("contenteditable")) {
|
|
@@ -7447,18 +8703,20 @@ function OhhwellsBridge() {
|
|
|
7447
8703
|
return;
|
|
7448
8704
|
}
|
|
7449
8705
|
e.dataTransfer.dropEffect = "copy";
|
|
7450
|
-
if (
|
|
8706
|
+
if (dragOverElRef.current !== el) {
|
|
8707
|
+
dragOverElRef.current = el;
|
|
7451
8708
|
hoveredImageRef.current = el;
|
|
7452
8709
|
const isStateCard = !!el.closest("[data-ohw-editable-state]");
|
|
7453
|
-
|
|
8710
|
+
showImageHover(el, true, isStateCard ? true : void 0);
|
|
7454
8711
|
}
|
|
7455
8712
|
};
|
|
7456
8713
|
const handleDragLeave = (e) => {
|
|
7457
8714
|
const imgEl = findImageAtPoint(e.clientX, e.clientY, false);
|
|
7458
8715
|
if (imgEl) return;
|
|
8716
|
+
dragOverElRef.current = null;
|
|
7459
8717
|
hoveredImageRef.current = null;
|
|
7460
8718
|
resumeAnimTracks();
|
|
7461
|
-
|
|
8719
|
+
clearImageHover();
|
|
7462
8720
|
};
|
|
7463
8721
|
const handleDrop = (e) => {
|
|
7464
8722
|
e.preventDefault();
|
|
@@ -7466,7 +8724,9 @@ function OhhwellsBridge() {
|
|
|
7466
8724
|
if (!el) return;
|
|
7467
8725
|
const file = e.dataTransfer?.files?.[0];
|
|
7468
8726
|
if (file) {
|
|
7469
|
-
|
|
8727
|
+
const wantsVideo = el.dataset.ohwEditable === "video";
|
|
8728
|
+
const accepted = wantsVideo ? file.type.startsWith("video/") : file.type.startsWith("image/");
|
|
8729
|
+
if (accepted) {
|
|
7470
8730
|
const key = el.dataset.ohwKey ?? "";
|
|
7471
8731
|
const { name, type: mimeType } = file;
|
|
7472
8732
|
const r2 = el.getBoundingClientRect();
|
|
@@ -7475,12 +8735,13 @@ function OhhwellsBridge() {
|
|
|
7475
8735
|
window.parent.postMessage({ type: "ow:image-drop", key, name, mimeType, buf, rect }, "*", [buf]);
|
|
7476
8736
|
});
|
|
7477
8737
|
} else {
|
|
7478
|
-
postToParentRef.current({ type: "ow:image-drop-invalid" });
|
|
8738
|
+
postToParentRef.current({ type: "ow:image-drop-invalid", expected: wantsVideo ? "video" : "image" });
|
|
7479
8739
|
}
|
|
7480
8740
|
}
|
|
8741
|
+
dragOverElRef.current = null;
|
|
7481
8742
|
hoveredImageRef.current = null;
|
|
7482
8743
|
resumeAnimTracks();
|
|
7483
|
-
|
|
8744
|
+
clearImageHover();
|
|
7484
8745
|
};
|
|
7485
8746
|
const handleImageUrl = (e) => {
|
|
7486
8747
|
if (e.data?.type !== "ow:image-url") return;
|
|
@@ -7498,7 +8759,11 @@ function OhhwellsBridge() {
|
|
|
7498
8759
|
}
|
|
7499
8760
|
});
|
|
7500
8761
|
hoveredImageRef.current = null;
|
|
7501
|
-
|
|
8762
|
+
setUploadingRects((prev) => {
|
|
8763
|
+
const entry = prev[key];
|
|
8764
|
+
if (!entry || entry.fadingOut) return prev;
|
|
8765
|
+
return { ...prev, [key]: { ...entry, fadingOut: true } };
|
|
8766
|
+
});
|
|
7502
8767
|
};
|
|
7503
8768
|
let found = false;
|
|
7504
8769
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -7528,11 +8793,24 @@ function OhhwellsBridge() {
|
|
|
7528
8793
|
};
|
|
7529
8794
|
img.onload = onReady;
|
|
7530
8795
|
img.onerror = onReady;
|
|
7531
|
-
img
|
|
8796
|
+
applyEditableImageSrc(img, url);
|
|
7532
8797
|
if (img.complete && img.naturalWidth > 0) {
|
|
7533
8798
|
requestAnimationFrame(() => onReady());
|
|
7534
8799
|
}
|
|
7535
8800
|
}
|
|
8801
|
+
} else if (el.dataset.ohwEditable === "video") {
|
|
8802
|
+
const video = getVideoEl(el);
|
|
8803
|
+
if (video) {
|
|
8804
|
+
found = true;
|
|
8805
|
+
const onReady = () => {
|
|
8806
|
+
video.onloadeddata = null;
|
|
8807
|
+
video.onerror = null;
|
|
8808
|
+
notify();
|
|
8809
|
+
};
|
|
8810
|
+
video.onloadeddata = onReady;
|
|
8811
|
+
video.onerror = onReady;
|
|
8812
|
+
applyVideoSrc(video, url);
|
|
8813
|
+
}
|
|
7536
8814
|
}
|
|
7537
8815
|
});
|
|
7538
8816
|
if (!found) notify();
|
|
@@ -7599,12 +8877,16 @@ function OhhwellsBridge() {
|
|
|
7599
8877
|
sectionsJson = val;
|
|
7600
8878
|
continue;
|
|
7601
8879
|
}
|
|
8880
|
+
if (applyVideoSettingNode(key, val)) continue;
|
|
7602
8881
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
7603
8882
|
if (el.dataset.ohwEditable === "image") {
|
|
7604
8883
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
7605
|
-
if (img) img
|
|
8884
|
+
if (img) applyEditableImageSrc(img, val);
|
|
7606
8885
|
} else if (el.dataset.ohwEditable === "bg-image") {
|
|
7607
8886
|
el.style.backgroundImage = `url('${val}')`;
|
|
8887
|
+
} else if (el.dataset.ohwEditable === "video") {
|
|
8888
|
+
const video = getVideoEl(el);
|
|
8889
|
+
if (video && video.src !== val) applyVideoSrc(video, val);
|
|
7608
8890
|
} else if (el.dataset.ohwEditable === "link") {
|
|
7609
8891
|
applyLinkHref(el, val);
|
|
7610
8892
|
} else {
|
|
@@ -7618,6 +8900,8 @@ function OhhwellsBridge() {
|
|
|
7618
8900
|
sectionsLoadedRef.current = true;
|
|
7619
8901
|
pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
|
|
7620
8902
|
}
|
|
8903
|
+
editContentRef.current = { ...editContentRef.current, ...content };
|
|
8904
|
+
reconcileNavbarItemsFromContent(editContentRef.current);
|
|
7621
8905
|
enforceLinkHrefs();
|
|
7622
8906
|
postToParentRef.current({ type: "ow:hydrate-done" });
|
|
7623
8907
|
};
|
|
@@ -7625,6 +8909,7 @@ function OhhwellsBridge() {
|
|
|
7625
8909
|
const handleDeactivate = (e) => {
|
|
7626
8910
|
if (e.data?.type !== "ow:deactivate") return;
|
|
7627
8911
|
if (Date.now() < linkPopoverGraceUntilRef.current) return;
|
|
8912
|
+
if (document.querySelector("[data-ohw-section-picker]")) return;
|
|
7628
8913
|
if (linkPopoverOpenRef.current) {
|
|
7629
8914
|
setLinkPopoverRef.current(null);
|
|
7630
8915
|
return;
|
|
@@ -7634,12 +8919,32 @@ function OhhwellsBridge() {
|
|
|
7634
8919
|
};
|
|
7635
8920
|
window.addEventListener("message", handleDeactivate);
|
|
7636
8921
|
const handleKeyDown = (e) => {
|
|
8922
|
+
if (e.key === "Escape" && document.querySelector("[data-ohw-section-picker]")) return;
|
|
8923
|
+
if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a" && activeElRef.current) {
|
|
8924
|
+
const navAnchor = getNavigationItemAnchor(activeElRef.current);
|
|
8925
|
+
if (navAnchor) {
|
|
8926
|
+
e.preventDefault();
|
|
8927
|
+
selectAllTextInEditable(activeElRef.current);
|
|
8928
|
+
refreshActiveCommandsRef.current();
|
|
8929
|
+
return;
|
|
8930
|
+
}
|
|
8931
|
+
}
|
|
7637
8932
|
if (e.key === "Escape" && linkPopoverOpenRef.current) {
|
|
7638
8933
|
setLinkPopoverRef.current(null);
|
|
7639
8934
|
return;
|
|
7640
8935
|
}
|
|
7641
8936
|
if (e.key === "Escape" && selectedElRef.current && !activeElRef.current) {
|
|
7642
|
-
|
|
8937
|
+
if (toolbarVariantRef.current === "select-frame") {
|
|
8938
|
+
deselectRef.current();
|
|
8939
|
+
return;
|
|
8940
|
+
}
|
|
8941
|
+
const parent = getNavigationSelectionParent(selectedElRef.current);
|
|
8942
|
+
if (parent) {
|
|
8943
|
+
e.preventDefault();
|
|
8944
|
+
selectFrameRef.current(parent);
|
|
8945
|
+
} else {
|
|
8946
|
+
deselectRef.current();
|
|
8947
|
+
}
|
|
7643
8948
|
return;
|
|
7644
8949
|
}
|
|
7645
8950
|
if (e.key === "Escape" && activeElRef.current) {
|
|
@@ -7697,18 +9002,18 @@ function OhhwellsBridge() {
|
|
|
7697
9002
|
if (hoveredItemElRef.current) {
|
|
7698
9003
|
setHoveredItemRect(hoveredItemElRef.current.getBoundingClientRect());
|
|
7699
9004
|
}
|
|
9005
|
+
if (hoveredNavContainerRef.current) {
|
|
9006
|
+
setHoveredNavContainerRect(hoveredNavContainerRef.current.getBoundingClientRect());
|
|
9007
|
+
}
|
|
7700
9008
|
if (siblingHintElRef.current) {
|
|
7701
9009
|
setSiblingHintRect(siblingHintElRef.current.getBoundingClientRect());
|
|
7702
9010
|
}
|
|
7703
9011
|
if (hoveredImageRef.current) {
|
|
7704
9012
|
const el = hoveredImageRef.current;
|
|
7705
9013
|
const r2 = el.getBoundingClientRect();
|
|
7706
|
-
|
|
7707
|
-
|
|
7708
|
-
|
|
7709
|
-
rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height },
|
|
7710
|
-
hasTextOverlap: hoveredImageHasTextOverlapRef.current
|
|
7711
|
-
});
|
|
9014
|
+
setMediaHover(
|
|
9015
|
+
(prev) => prev ? { ...prev, rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height } } : prev
|
|
9016
|
+
);
|
|
7712
9017
|
}
|
|
7713
9018
|
};
|
|
7714
9019
|
const handleSave = (e) => {
|
|
@@ -7797,19 +9102,39 @@ function OhhwellsBridge() {
|
|
|
7797
9102
|
refreshActiveCommandsRef.current = handleSelectionChange;
|
|
7798
9103
|
const handleDocMouseLeave = () => {
|
|
7799
9104
|
hoveredImageRef.current = null;
|
|
9105
|
+
setMediaHover(null);
|
|
7800
9106
|
document.querySelectorAll("[data-ohw-state-hovered]").forEach((el) => el.removeAttribute("data-ohw-state-hovered"));
|
|
7801
9107
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
7802
9108
|
activeStateElRef.current = null;
|
|
7803
9109
|
setToggleState(null);
|
|
7804
9110
|
};
|
|
7805
|
-
const
|
|
7806
|
-
if (e.data?.type !== "ow:
|
|
7807
|
-
const { key } = e.data;
|
|
9111
|
+
const handleImageUploading = (e) => {
|
|
9112
|
+
if (e.data?.type !== "ow:image-uploading") return;
|
|
9113
|
+
const { key, uploading } = e.data;
|
|
9114
|
+
setUploadingRects((prev) => {
|
|
9115
|
+
if (!uploading) {
|
|
9116
|
+
if (!(key in prev)) return prev;
|
|
9117
|
+
const next = { ...prev };
|
|
9118
|
+
delete next[key];
|
|
9119
|
+
return next;
|
|
9120
|
+
}
|
|
9121
|
+
const el = document.querySelector(`[data-ohw-key="${key}"]`);
|
|
9122
|
+
if (!el) return prev;
|
|
9123
|
+
const r2 = getVisibleRect(el);
|
|
9124
|
+
return {
|
|
9125
|
+
...prev,
|
|
9126
|
+
[key]: { rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height } }
|
|
9127
|
+
};
|
|
9128
|
+
});
|
|
7808
9129
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
7809
9130
|
const track = el.closest("[data-ohw-hover-pause]");
|
|
7810
|
-
if (track)
|
|
9131
|
+
if (!track) return;
|
|
9132
|
+
if (uploading) {
|
|
7811
9133
|
uploadLockedTracks.add(track);
|
|
7812
9134
|
track.setAttribute("data-ohw-hover-paused", "");
|
|
9135
|
+
} else {
|
|
9136
|
+
uploadLockedTracks.delete(track);
|
|
9137
|
+
track.removeAttribute("data-ohw-hover-paused");
|
|
7813
9138
|
}
|
|
7814
9139
|
});
|
|
7815
9140
|
};
|
|
@@ -7851,7 +9176,7 @@ function OhhwellsBridge() {
|
|
|
7851
9176
|
if (e.data?.type !== "ow:click-at") return;
|
|
7852
9177
|
const { clientX, clientY } = e.data;
|
|
7853
9178
|
const allImages = Array.from(
|
|
7854
|
-
document.querySelectorAll(
|
|
9179
|
+
document.querySelectorAll(MEDIA_SELECTOR)
|
|
7855
9180
|
).filter((el) => !!el.closest("[data-ohw-editable-state]"));
|
|
7856
9181
|
const stateCardImage = allImages.find((el) => {
|
|
7857
9182
|
const ownerCard = el.closest("[data-ohw-editable-state]");
|
|
@@ -7866,21 +9191,55 @@ function OhhwellsBridge() {
|
|
|
7866
9191
|
return clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom;
|
|
7867
9192
|
});
|
|
7868
9193
|
if (stateCardImage) {
|
|
7869
|
-
postToParentRef.current({ type: "ow:image-pick", key: stateCardImage.dataset.ohwKey ?? "" });
|
|
9194
|
+
postToParentRef.current({ type: "ow:image-pick", key: stateCardImage.dataset.ohwKey ?? "", elementType: stateCardImage.dataset.ohwEditable ?? "image" });
|
|
7870
9195
|
return;
|
|
7871
9196
|
}
|
|
7872
9197
|
const textEditable = Array.from(
|
|
7873
|
-
document.querySelectorAll(
|
|
7874
|
-
'[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"])'
|
|
7875
|
-
)
|
|
9198
|
+
document.querySelectorAll(NON_MEDIA_SELECTOR)
|
|
7876
9199
|
).find((el) => {
|
|
7877
9200
|
const r2 = el.getBoundingClientRect();
|
|
7878
9201
|
return clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom;
|
|
7879
9202
|
});
|
|
7880
9203
|
if (textEditable) {
|
|
7881
|
-
|
|
9204
|
+
const hrefCtx = getHrefKeyFromElement(textEditable);
|
|
9205
|
+
const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
|
|
9206
|
+
if (navAnchor) {
|
|
9207
|
+
if (selectedElRef.current === navAnchor) {
|
|
9208
|
+
activateRef.current(textEditable, { caretX: clientX, caretY: clientY });
|
|
9209
|
+
} else {
|
|
9210
|
+
selectRef.current(navAnchor);
|
|
9211
|
+
}
|
|
9212
|
+
return;
|
|
9213
|
+
}
|
|
9214
|
+
activateRef.current(textEditable, { caretX: clientX, caretY: clientY });
|
|
7882
9215
|
return;
|
|
7883
9216
|
}
|
|
9217
|
+
const navContainer = document.querySelector("[data-ohw-nav-container]");
|
|
9218
|
+
if (navContainer) {
|
|
9219
|
+
const r2 = navContainer.getBoundingClientRect();
|
|
9220
|
+
const pad = 8;
|
|
9221
|
+
const over = clientX >= r2.left - pad && clientX <= r2.right + pad && clientY >= r2.top - pad && clientY <= r2.bottom + pad;
|
|
9222
|
+
if (over && !isPointOverNavItem(navContainer, clientX, clientY)) {
|
|
9223
|
+
selectFrameRef.current(navContainer);
|
|
9224
|
+
return;
|
|
9225
|
+
}
|
|
9226
|
+
}
|
|
9227
|
+
const navRoot = document.querySelector("[data-ohw-nav-root]");
|
|
9228
|
+
if (navRoot && navContainer) {
|
|
9229
|
+
const rr = navRoot.getBoundingClientRect();
|
|
9230
|
+
if (clientX >= rr.left && clientX <= rr.right && clientY >= rr.top && clientY <= rr.bottom && !isPointOverNavItem(navContainer, clientX, clientY)) {
|
|
9231
|
+
const book = navRoot.querySelector('[data-ohw-role="navbar-button"]');
|
|
9232
|
+
if (book) {
|
|
9233
|
+
const br = book.getBoundingClientRect();
|
|
9234
|
+
if (clientX >= br.left && clientX <= br.right && clientY >= br.top && clientY <= br.bottom) {
|
|
9235
|
+
deactivateRef.current();
|
|
9236
|
+
return;
|
|
9237
|
+
}
|
|
9238
|
+
}
|
|
9239
|
+
selectFrameRef.current(navContainer);
|
|
9240
|
+
return;
|
|
9241
|
+
}
|
|
9242
|
+
}
|
|
7884
9243
|
deactivateRef.current();
|
|
7885
9244
|
};
|
|
7886
9245
|
window.addEventListener("message", handleSave);
|
|
@@ -7890,7 +9249,7 @@ function OhhwellsBridge() {
|
|
|
7890
9249
|
window.addEventListener("message", handleClearSchedulingWidget);
|
|
7891
9250
|
window.addEventListener("message", handleRemoveSchedulingSection);
|
|
7892
9251
|
window.addEventListener("message", handleImageUrl);
|
|
7893
|
-
window.addEventListener("message",
|
|
9252
|
+
window.addEventListener("message", handleImageUploading);
|
|
7894
9253
|
window.addEventListener("message", handleCanvasHeight);
|
|
7895
9254
|
window.addEventListener("message", handleParentScroll);
|
|
7896
9255
|
window.addEventListener("message", handlePointerSync);
|
|
@@ -7902,6 +9261,7 @@ function OhhwellsBridge() {
|
|
|
7902
9261
|
};
|
|
7903
9262
|
window.addEventListener("resize", handleViewportResize, { passive: true });
|
|
7904
9263
|
document.addEventListener("click", handleClick, true);
|
|
9264
|
+
document.addEventListener("dblclick", handleDblClick, true);
|
|
7905
9265
|
document.addEventListener("paste", handlePaste, true);
|
|
7906
9266
|
document.addEventListener("input", handleInput, true);
|
|
7907
9267
|
document.addEventListener("mouseover", handleMouseOver, true);
|
|
@@ -7916,6 +9276,7 @@ function OhhwellsBridge() {
|
|
|
7916
9276
|
window.addEventListener("scroll", handleScroll, true);
|
|
7917
9277
|
return () => {
|
|
7918
9278
|
document.removeEventListener("click", handleClick, true);
|
|
9279
|
+
document.removeEventListener("dblclick", handleDblClick, true);
|
|
7919
9280
|
document.removeEventListener("paste", handlePaste, true);
|
|
7920
9281
|
document.removeEventListener("input", handleInput, true);
|
|
7921
9282
|
document.removeEventListener("mouseover", handleMouseOver, true);
|
|
@@ -7935,7 +9296,7 @@ function OhhwellsBridge() {
|
|
|
7935
9296
|
window.removeEventListener("message", handleClearSchedulingWidget);
|
|
7936
9297
|
window.removeEventListener("message", handleRemoveSchedulingSection);
|
|
7937
9298
|
window.removeEventListener("message", handleImageUrl);
|
|
7938
|
-
window.removeEventListener("message",
|
|
9299
|
+
window.removeEventListener("message", handleImageUploading);
|
|
7939
9300
|
window.removeEventListener("message", handleCanvasHeight);
|
|
7940
9301
|
window.removeEventListener("message", handleParentScroll);
|
|
7941
9302
|
window.removeEventListener("resize", handleViewportResize);
|
|
@@ -7949,7 +9310,7 @@ function OhhwellsBridge() {
|
|
|
7949
9310
|
if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
|
|
7950
9311
|
};
|
|
7951
9312
|
}, [isEditMode, refreshStateRules]);
|
|
7952
|
-
(0,
|
|
9313
|
+
(0, import_react8.useEffect)(() => {
|
|
7953
9314
|
const handler = (e) => {
|
|
7954
9315
|
if (e.data?.type !== "ow:request-schedule-config") return;
|
|
7955
9316
|
const insertAfterVal = e.data.insertAfter;
|
|
@@ -7965,7 +9326,7 @@ function OhhwellsBridge() {
|
|
|
7965
9326
|
window.addEventListener("message", handler);
|
|
7966
9327
|
return () => window.removeEventListener("message", handler);
|
|
7967
9328
|
}, [processConfigRequest]);
|
|
7968
|
-
(0,
|
|
9329
|
+
(0, import_react8.useEffect)(() => {
|
|
7969
9330
|
if (!isEditMode) return;
|
|
7970
9331
|
document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
|
|
7971
9332
|
el.removeAttribute("data-ohw-active-state");
|
|
@@ -7986,27 +9347,27 @@ function OhhwellsBridge() {
|
|
|
7986
9347
|
const next = { ...prev, [pathKey]: sections };
|
|
7987
9348
|
return shouldUseDevFixtures() ? { ...DEV_SECTIONS_BY_PATH, ...next } : next;
|
|
7988
9349
|
});
|
|
7989
|
-
|
|
7990
|
-
|
|
9350
|
+
postToParent2({ type: "ow:ready", version: "1", path: pathname, nodes: collectEditableNodes(), sections });
|
|
9351
|
+
postToParent2({ type: "ow:request-site-pages" });
|
|
7991
9352
|
}, 150);
|
|
7992
9353
|
return () => {
|
|
7993
9354
|
cancelAnimationFrame(raf);
|
|
7994
9355
|
clearTimeout(timer);
|
|
7995
9356
|
};
|
|
7996
|
-
}, [pathname, isEditMode, refreshStateRules,
|
|
7997
|
-
(0,
|
|
9357
|
+
}, [pathname, isEditMode, refreshStateRules, postToParent2]);
|
|
9358
|
+
(0, import_react8.useEffect)(() => {
|
|
7998
9359
|
scrollToHashSectionWhenReady();
|
|
7999
9360
|
const onHashChange = () => scrollToHashSectionWhenReady();
|
|
8000
9361
|
window.addEventListener("hashchange", onHashChange);
|
|
8001
9362
|
return () => window.removeEventListener("hashchange", onHashChange);
|
|
8002
9363
|
}, [pathname]);
|
|
8003
|
-
const handleCommand = (0,
|
|
9364
|
+
const handleCommand = (0, import_react8.useCallback)((cmd) => {
|
|
8004
9365
|
document.execCommand(cmd, false);
|
|
8005
9366
|
activeElRef.current?.focus();
|
|
8006
9367
|
if (activeElRef.current) setToolbarRect(getEditMeasureEl(activeElRef.current).getBoundingClientRect());
|
|
8007
9368
|
refreshActiveCommandsRef.current();
|
|
8008
9369
|
}, []);
|
|
8009
|
-
const handleStateChange = (0,
|
|
9370
|
+
const handleStateChange = (0, import_react8.useCallback)((state) => {
|
|
8010
9371
|
if (!activeStateElRef.current) return;
|
|
8011
9372
|
const el = activeStateElRef.current;
|
|
8012
9373
|
if (state === "Default") {
|
|
@@ -8019,18 +9380,22 @@ function OhhwellsBridge() {
|
|
|
8019
9380
|
}
|
|
8020
9381
|
setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
|
|
8021
9382
|
}, [deactivate]);
|
|
8022
|
-
const closeLinkPopover = (0,
|
|
8023
|
-
|
|
9383
|
+
const closeLinkPopover = (0, import_react8.useCallback)(() => {
|
|
9384
|
+
addNavAfterAnchorRef.current = null;
|
|
9385
|
+
setLinkPopover(null);
|
|
9386
|
+
}, []);
|
|
9387
|
+
const openLinkPopoverForActive = (0, import_react8.useCallback)(() => {
|
|
8024
9388
|
const hrefCtx = getHrefKeyFromElement(activeElRef.current);
|
|
8025
9389
|
if (!hrefCtx) return;
|
|
8026
9390
|
bumpLinkPopoverGrace();
|
|
8027
9391
|
setLinkPopover({
|
|
8028
9392
|
key: hrefCtx.key,
|
|
8029
|
-
|
|
9393
|
+
mode: "edit",
|
|
9394
|
+
target: getLinkHref2(hrefCtx.anchor)
|
|
8030
9395
|
});
|
|
8031
9396
|
deactivate();
|
|
8032
9397
|
}, [deactivate]);
|
|
8033
|
-
const openLinkPopoverForSelected = (0,
|
|
9398
|
+
const openLinkPopoverForSelected = (0, import_react8.useCallback)(() => {
|
|
8034
9399
|
const anchor = selectedElRef.current;
|
|
8035
9400
|
if (!anchor) return;
|
|
8036
9401
|
const key = anchor.getAttribute("data-ohw-href-key");
|
|
@@ -8038,51 +9403,156 @@ function OhhwellsBridge() {
|
|
|
8038
9403
|
bumpLinkPopoverGrace();
|
|
8039
9404
|
setLinkPopover({
|
|
8040
9405
|
key,
|
|
8041
|
-
|
|
9406
|
+
mode: "edit",
|
|
9407
|
+
target: getLinkHref2(anchor)
|
|
8042
9408
|
});
|
|
8043
9409
|
deselect();
|
|
8044
9410
|
}, [deselect]);
|
|
8045
|
-
const handleLinkPopoverSubmit = (0,
|
|
9411
|
+
const handleLinkPopoverSubmit = (0, import_react8.useCallback)(
|
|
8046
9412
|
(target) => {
|
|
8047
|
-
|
|
8048
|
-
|
|
9413
|
+
const session = linkPopoverSessionRef.current;
|
|
9414
|
+
if (!session) return;
|
|
9415
|
+
if (session.intent === "add-nav") {
|
|
9416
|
+
const { pageRoute, sectionId } = parseTarget(target);
|
|
9417
|
+
const page = resolvePage(pageRoute, sitePages);
|
|
9418
|
+
const pageSections = getSectionsForPath(sectionsByPath, pageRoute);
|
|
9419
|
+
const section = sectionId ? pageSections.find((s) => s.id === sectionId) : void 0;
|
|
9420
|
+
const label = section?.label ?? page.title;
|
|
9421
|
+
const afterAnchor = addNavAfterAnchorRef.current;
|
|
9422
|
+
const { anchor, hrefKey, labelKey, index, order } = insertNavbarItem(target, label, afterAnchor);
|
|
9423
|
+
applyLinkByKey(hrefKey, target);
|
|
9424
|
+
document.querySelectorAll(`[data-ohw-key="${labelKey}"]`).forEach((el) => {
|
|
9425
|
+
el.textContent = label;
|
|
9426
|
+
});
|
|
9427
|
+
const navCount = String(index + 1);
|
|
9428
|
+
const orderJson = JSON.stringify(order);
|
|
9429
|
+
editContentRef.current = {
|
|
9430
|
+
...editContentRef.current,
|
|
9431
|
+
[hrefKey]: target,
|
|
9432
|
+
[labelKey]: label,
|
|
9433
|
+
[NAV_COUNT_KEY]: navCount,
|
|
9434
|
+
[NAV_ORDER_KEY]: orderJson
|
|
9435
|
+
};
|
|
9436
|
+
postToParent2({
|
|
9437
|
+
type: "ow:change",
|
|
9438
|
+
nodes: [
|
|
9439
|
+
{ key: hrefKey, text: target },
|
|
9440
|
+
{ key: labelKey, text: label },
|
|
9441
|
+
{ key: NAV_COUNT_KEY, text: navCount },
|
|
9442
|
+
{ key: NAV_ORDER_KEY, text: orderJson }
|
|
9443
|
+
]
|
|
9444
|
+
});
|
|
9445
|
+
addNavAfterAnchorRef.current = null;
|
|
9446
|
+
setLinkPopover(null);
|
|
9447
|
+
enforceLinkHrefs();
|
|
9448
|
+
requestAnimationFrame(() => {
|
|
9449
|
+
selectRef.current(anchor);
|
|
9450
|
+
});
|
|
9451
|
+
return;
|
|
9452
|
+
}
|
|
9453
|
+
const { key } = session;
|
|
8049
9454
|
applyLinkByKey(key, target);
|
|
8050
|
-
|
|
9455
|
+
postToParent2({ type: "ow:change", nodes: [{ key, text: target }] });
|
|
8051
9456
|
setLinkPopover(null);
|
|
8052
9457
|
},
|
|
8053
|
-
[
|
|
9458
|
+
[postToParent2, sitePages, sectionsByPath]
|
|
8054
9459
|
);
|
|
8055
9460
|
const showEditLink = toolbarShowEditLink;
|
|
8056
9461
|
const currentSections = sectionsByPath[pathname] ?? [];
|
|
8057
9462
|
linkPopoverOpenRef.current = linkPopover !== null;
|
|
8058
|
-
|
|
8059
|
-
|
|
8060
|
-
|
|
8061
|
-
|
|
8062
|
-
|
|
8063
|
-
|
|
9463
|
+
const handleMediaReplace = (0, import_react8.useCallback)(
|
|
9464
|
+
(key) => {
|
|
9465
|
+
postToParent2({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
|
|
9466
|
+
},
|
|
9467
|
+
[postToParent2, mediaHover?.elementType]
|
|
9468
|
+
);
|
|
9469
|
+
const handleMediaFadeOutComplete = (0, import_react8.useCallback)((key) => {
|
|
9470
|
+
setUploadingRects((prev) => {
|
|
9471
|
+
if (!(key in prev)) return prev;
|
|
9472
|
+
const next = { ...prev };
|
|
9473
|
+
delete next[key];
|
|
9474
|
+
return next;
|
|
9475
|
+
});
|
|
9476
|
+
}, []);
|
|
9477
|
+
const handleVideoSettingsChange = (0, import_react8.useCallback)(
|
|
9478
|
+
(key, settings) => {
|
|
9479
|
+
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
9480
|
+
const video = getVideoEl(el);
|
|
9481
|
+
if (!video) return;
|
|
9482
|
+
if (typeof settings.autoplay === "boolean") video.autoplay = settings.autoplay;
|
|
9483
|
+
if (typeof settings.muted === "boolean") video.muted = settings.muted;
|
|
9484
|
+
syncVideoPlayback(video);
|
|
9485
|
+
postToParent2({
|
|
9486
|
+
type: "ow:change",
|
|
9487
|
+
nodes: [
|
|
9488
|
+
{ key: `${key}${VIDEO_AUTOPLAY_SUFFIX}`, text: String(video.autoplay) },
|
|
9489
|
+
{ key: `${key}${VIDEO_MUTED_SUFFIX}`, text: String(video.muted) }
|
|
9490
|
+
]
|
|
9491
|
+
});
|
|
9492
|
+
setMediaHover(
|
|
9493
|
+
(prev) => prev && prev.key === key ? { ...prev, videoAutoplay: video.autoplay, videoMuted: video.muted } : prev
|
|
9494
|
+
);
|
|
9495
|
+
});
|
|
9496
|
+
},
|
|
9497
|
+
[postToParent2]
|
|
9498
|
+
);
|
|
9499
|
+
return bridgeRoot ? (0, import_react_dom3.createPortal)(
|
|
9500
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
|
|
9501
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
|
|
9502
|
+
Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
9503
|
+
MediaOverlay,
|
|
9504
|
+
{
|
|
9505
|
+
hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
|
|
9506
|
+
isUploading: true,
|
|
9507
|
+
fadingOut,
|
|
9508
|
+
onFadeOutComplete: handleMediaFadeOutComplete,
|
|
9509
|
+
onReplace: handleMediaReplace
|
|
9510
|
+
},
|
|
9511
|
+
`uploading-${key}`
|
|
9512
|
+
)),
|
|
9513
|
+
mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
9514
|
+
MediaOverlay,
|
|
9515
|
+
{
|
|
9516
|
+
hover: mediaHover,
|
|
9517
|
+
isUploading: false,
|
|
9518
|
+
onReplace: handleMediaReplace,
|
|
9519
|
+
onVideoSettingsChange: handleVideoSettingsChange
|
|
9520
|
+
}
|
|
9521
|
+
),
|
|
9522
|
+
siblingHintRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
|
|
9523
|
+
hoveredNavContainerRect && toolbarVariant !== "select-frame" && !linkPopover && !isItemDragging && !siblingHintRect && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
|
|
9524
|
+
toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
9525
|
+
NavbarContainerChrome,
|
|
9526
|
+
{
|
|
9527
|
+
rect: toolbarRect,
|
|
9528
|
+
onAdd: handleAddTopLevelNavItem
|
|
9529
|
+
}
|
|
9530
|
+
),
|
|
9531
|
+
hoveredItemRect && !hoveredNavContainerRect && !siblingHintRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
|
|
9532
|
+
toolbarRect && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
8064
9533
|
ItemInteractionLayer,
|
|
8065
9534
|
{
|
|
8066
9535
|
rect: toolbarRect,
|
|
8067
9536
|
elRef: glowElRef,
|
|
8068
9537
|
state: isItemDragging ? "dragging" : resolveItemInteractionState(toolbarRect, parentScrollRef.current),
|
|
8069
|
-
showHandle: Boolean(reorderHrefKey),
|
|
9538
|
+
showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey),
|
|
8070
9539
|
dragDisabled: reorderDragDisabled,
|
|
8071
9540
|
dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
|
|
8072
9541
|
onDragHandleDragStart: handleItemDragStart,
|
|
8073
9542
|
onDragHandleDragEnd: handleItemDragEnd,
|
|
8074
|
-
toolbar:
|
|
9543
|
+
toolbar: toolbarVariant === "link-action" && !isItemDragging ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
8075
9544
|
ItemActionToolbar,
|
|
8076
9545
|
{
|
|
8077
9546
|
onEditLink: openLinkPopoverForSelected,
|
|
8078
|
-
|
|
8079
|
-
|
|
9547
|
+
addItemDisabled: true,
|
|
9548
|
+
editLinkDisabled: false,
|
|
9549
|
+
moreDisabled: true
|
|
8080
9550
|
}
|
|
8081
|
-
)
|
|
9551
|
+
) : void 0
|
|
8082
9552
|
}
|
|
8083
9553
|
),
|
|
8084
|
-
toolbarRect && toolbarVariant === "rich-text" && /* @__PURE__ */ (0,
|
|
8085
|
-
/* @__PURE__ */ (0,
|
|
9554
|
+
toolbarRect && toolbarVariant === "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
|
|
9555
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
8086
9556
|
EditGlowChrome,
|
|
8087
9557
|
{
|
|
8088
9558
|
rect: toolbarRect,
|
|
@@ -8091,7 +9561,7 @@ function OhhwellsBridge() {
|
|
|
8091
9561
|
dragDisabled: reorderDragDisabled
|
|
8092
9562
|
}
|
|
8093
9563
|
),
|
|
8094
|
-
/* @__PURE__ */ (0,
|
|
9564
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
8095
9565
|
FloatingToolbar,
|
|
8096
9566
|
{
|
|
8097
9567
|
rect: toolbarRect,
|
|
@@ -8104,7 +9574,7 @@ function OhhwellsBridge() {
|
|
|
8104
9574
|
}
|
|
8105
9575
|
)
|
|
8106
9576
|
] }),
|
|
8107
|
-
maxBadge && /* @__PURE__ */ (0,
|
|
9577
|
+
maxBadge && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
8108
9578
|
"div",
|
|
8109
9579
|
{
|
|
8110
9580
|
"data-ohw-max-badge": "",
|
|
@@ -8130,7 +9600,7 @@ function OhhwellsBridge() {
|
|
|
8130
9600
|
]
|
|
8131
9601
|
}
|
|
8132
9602
|
),
|
|
8133
|
-
toggleState && /* @__PURE__ */ (0,
|
|
9603
|
+
toggleState && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
8134
9604
|
StateToggle,
|
|
8135
9605
|
{
|
|
8136
9606
|
rect: toggleState.rect,
|
|
@@ -8139,15 +9609,15 @@ function OhhwellsBridge() {
|
|
|
8139
9609
|
onStateChange: handleStateChange
|
|
8140
9610
|
}
|
|
8141
9611
|
),
|
|
8142
|
-
sectionGap && /* @__PURE__ */ (0,
|
|
9612
|
+
sectionGap && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
8143
9613
|
"div",
|
|
8144
9614
|
{
|
|
8145
9615
|
"data-ohw-section-insert-line": "",
|
|
8146
9616
|
className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
|
|
8147
9617
|
style: { top: sectionGap.y, transform: "translateY(-50%)" },
|
|
8148
9618
|
children: [
|
|
8149
|
-
/* @__PURE__ */ (0,
|
|
8150
|
-
/* @__PURE__ */ (0,
|
|
9619
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
|
|
9620
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
8151
9621
|
Badge,
|
|
8152
9622
|
{
|
|
8153
9623
|
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",
|
|
@@ -8160,26 +9630,52 @@ function OhhwellsBridge() {
|
|
|
8160
9630
|
children: "Add Section"
|
|
8161
9631
|
}
|
|
8162
9632
|
),
|
|
8163
|
-
/* @__PURE__ */ (0,
|
|
9633
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
|
|
8164
9634
|
]
|
|
8165
9635
|
}
|
|
8166
9636
|
),
|
|
8167
|
-
linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0,
|
|
9637
|
+
linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
8168
9638
|
LinkPopover,
|
|
8169
9639
|
{
|
|
8170
9640
|
panelRef: linkPopoverPanelRef,
|
|
8171
9641
|
portalContainer: dialogPortalContainer,
|
|
8172
9642
|
open: true,
|
|
8173
|
-
mode: "edit",
|
|
9643
|
+
mode: linkPopover.mode ?? "edit",
|
|
8174
9644
|
pages: sitePages,
|
|
8175
9645
|
sections: currentSections,
|
|
8176
9646
|
sectionsByPath,
|
|
8177
9647
|
initialTarget: linkPopover.target,
|
|
9648
|
+
existingTargets: linkPopover.intent === "add-nav" ? getNavbarExistingTargets() : [],
|
|
8178
9649
|
onClose: closeLinkPopover,
|
|
8179
9650
|
onSubmit: handleLinkPopoverSubmit
|
|
8180
9651
|
},
|
|
8181
|
-
|
|
8182
|
-
) : null
|
|
9652
|
+
linkPopover.key
|
|
9653
|
+
) : null,
|
|
9654
|
+
sectionGap && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
9655
|
+
"div",
|
|
9656
|
+
{
|
|
9657
|
+
"data-ohw-section-insert-line": "",
|
|
9658
|
+
className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
|
|
9659
|
+
style: { top: sectionGap.y, transform: "translateY(-50%)" },
|
|
9660
|
+
children: [
|
|
9661
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
|
|
9662
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
9663
|
+
Badge,
|
|
9664
|
+
{
|
|
9665
|
+
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",
|
|
9666
|
+
onClick: () => {
|
|
9667
|
+
window.parent.postMessage(
|
|
9668
|
+
{ type: "ow:add-section", insertAfter: sectionGap.insertAfter, insertBefore: sectionGap.insertBefore },
|
|
9669
|
+
"*"
|
|
9670
|
+
);
|
|
9671
|
+
},
|
|
9672
|
+
children: "Add Section"
|
|
9673
|
+
}
|
|
9674
|
+
),
|
|
9675
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
|
|
9676
|
+
]
|
|
9677
|
+
}
|
|
9678
|
+
)
|
|
8183
9679
|
] }),
|
|
8184
9680
|
bridgeRoot
|
|
8185
9681
|
) : null;
|