@ohhwells/bridge 0.1.38 → 0.1.39-next.75
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 +13 -1
- package/dist/index.cjs +3114 -686
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +98 -6
- package/dist/index.d.ts +98 -6
- package/dist/index.js +3099 -674
- package/dist/index.js.map +1 -1
- package/dist/styles.css +169 -34
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
// src/OhhwellsBridge.tsx
|
|
4
|
-
import
|
|
4
|
+
import React10, { useCallback as useCallback4, useEffect as useEffect8, useLayoutEffect as useLayoutEffect2, useRef as useRef5, useState as useState7 } from "react";
|
|
5
5
|
import { createRoot } from "react-dom/client";
|
|
6
6
|
import { flushSync } from "react-dom";
|
|
7
7
|
|
|
@@ -10,6 +10,9 @@ var linkHrefStore = /* @__PURE__ */ new Map();
|
|
|
10
10
|
function setStoredLinkHref(key, href) {
|
|
11
11
|
linkHrefStore.set(key, href);
|
|
12
12
|
}
|
|
13
|
+
function getStoredLinkHref(key) {
|
|
14
|
+
return linkHrefStore.get(key);
|
|
15
|
+
}
|
|
13
16
|
function enforceLinkHrefs() {
|
|
14
17
|
document.querySelectorAll("[data-ohw-href-key]").forEach((el) => {
|
|
15
18
|
const key = el.getAttribute("data-ohw-href-key") ?? "";
|
|
@@ -45,12 +48,13 @@ function useLinkHrefGuardian(...deps) {
|
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
// src/ui/SchedulingWidget.tsx
|
|
48
|
-
import { useEffect, useId, useMemo, useRef, useState as useState2 } from "react";
|
|
51
|
+
import { useCallback, useEffect, useId, useMemo, useRef, useState as useState2 } from "react";
|
|
49
52
|
|
|
50
53
|
// src/ui/EmailCaptureModal.tsx
|
|
51
54
|
import { useState } from "react";
|
|
52
55
|
import { Dialog } from "radix-ui";
|
|
53
56
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
57
|
+
var isValidEmail = (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
|
|
54
58
|
function Spinner() {
|
|
55
59
|
return /* @__PURE__ */ jsxs(
|
|
56
60
|
"svg",
|
|
@@ -84,12 +88,17 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
|
|
|
84
88
|
const [error, setError] = useState(null);
|
|
85
89
|
const isBook = title === "Confirm your spot";
|
|
86
90
|
const handleSubmit = async () => {
|
|
87
|
-
|
|
91
|
+
const trimmed = email.trim();
|
|
92
|
+
if (!trimmed) return;
|
|
93
|
+
if (!isValidEmail(trimmed)) {
|
|
94
|
+
setError("Please enter a valid email address.");
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
88
97
|
setLoading(true);
|
|
89
98
|
setError(null);
|
|
90
99
|
try {
|
|
91
|
-
await onSubmit(
|
|
92
|
-
setSubmittedEmail(
|
|
100
|
+
await onSubmit(trimmed);
|
|
101
|
+
setSubmittedEmail(trimmed);
|
|
93
102
|
setSuccess(true);
|
|
94
103
|
} catch (e) {
|
|
95
104
|
setError(e instanceof Error ? e.message : "Something went wrong. Please try again.");
|
|
@@ -164,7 +173,10 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
|
|
|
164
173
|
{
|
|
165
174
|
type: "email",
|
|
166
175
|
value: email,
|
|
167
|
-
onChange: (e) =>
|
|
176
|
+
onChange: (e) => {
|
|
177
|
+
setEmail(e.target.value);
|
|
178
|
+
if (error) setError(null);
|
|
179
|
+
},
|
|
168
180
|
onKeyDown: handleKeyDown,
|
|
169
181
|
placeholder: "hello@gmail.com",
|
|
170
182
|
autoFocus: true,
|
|
@@ -221,12 +233,20 @@ function formatClassTime(cls) {
|
|
|
221
233
|
const em = endTotal % 60;
|
|
222
234
|
return `${h}:${cls.startTime.minutes}-${eh}:${String(em).padStart(2, "0")}`;
|
|
223
235
|
}
|
|
236
|
+
function formatBookingLabel(cls) {
|
|
237
|
+
const price = cls.price;
|
|
238
|
+
const isFree = price === null || price === void 0 || `${price}` === "" || `${price}` === "0";
|
|
239
|
+
return isFree ? "Book for free" : `Book for ${cls.currency ?? ""} ${price}`.trim();
|
|
240
|
+
}
|
|
224
241
|
function getBookingsOnDate(cls, date) {
|
|
225
242
|
if (!cls.bookings?.length) return 0;
|
|
226
|
-
const
|
|
243
|
+
const target = new Date(date);
|
|
244
|
+
target.setHours(0, 0, 0, 0);
|
|
227
245
|
return cls.bookings.filter((b) => {
|
|
228
246
|
try {
|
|
229
|
-
|
|
247
|
+
const bookingDate = new Date(b.classDate);
|
|
248
|
+
bookingDate.setHours(0, 0, 0, 0);
|
|
249
|
+
return bookingDate.getTime() === target.getTime();
|
|
230
250
|
} catch {
|
|
231
251
|
return false;
|
|
232
252
|
}
|
|
@@ -491,7 +511,7 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
|
|
|
491
511
|
}
|
|
492
512
|
)
|
|
493
513
|
] }),
|
|
494
|
-
/* @__PURE__ */ jsx2("div", { className: "sm:hidden flex flex-col gap-px", children: isFull ? /* @__PURE__ */ jsx2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
514
|
+
cls.showAvailability !== false && /* @__PURE__ */ jsx2("div", { className: "sm:hidden flex flex-col gap-px", children: isFull ? /* @__PURE__ */ jsx2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
495
515
|
/* @__PURE__ */ jsxs2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: [
|
|
496
516
|
available,
|
|
497
517
|
"/",
|
|
@@ -503,9 +523,10 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
|
|
|
503
523
|
/* @__PURE__ */ jsxs2("div", { className: "flex flex-1 flex-col gap-2 min-w-0 sm:contents", children: [
|
|
504
524
|
/* @__PURE__ */ jsxs2("div", { className: "flex-1 flex flex-col gap-2 min-w-0", children: [
|
|
505
525
|
/* @__PURE__ */ jsx2("span", { className: "font-body text-base font-bold text-(--color-dark,#200C02) block truncate", children: cls.name }),
|
|
506
|
-
cls.hostName && /* @__PURE__ */ jsx2("span", { className: "font-body text-base font-normal text-(--color-dark,#200C02) opacity-80 block truncate", children: cls.hostName })
|
|
526
|
+
cls.hostName && /* @__PURE__ */ jsx2("span", { className: "font-body text-base font-normal text-(--color-dark,#200C02) opacity-80 block truncate", children: cls.hostName }),
|
|
527
|
+
cls.description && /* @__PURE__ */ jsx2("span", { className: "font-body text-sm font-normal text-(--color-dark,#200C02) opacity-70 block truncate", children: cls.description })
|
|
507
528
|
] }),
|
|
508
|
-
/* @__PURE__ */ jsx2("div", { className: "hidden sm:flex w-14 shrink-0 flex-col gap-px", children: isFull ? /* @__PURE__ */ jsx2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
529
|
+
cls.showAvailability !== false && /* @__PURE__ */ jsx2("div", { className: "hidden sm:flex w-14 shrink-0 flex-col gap-px", children: isFull ? /* @__PURE__ */ jsx2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
509
530
|
/* @__PURE__ */ jsxs2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: [
|
|
510
531
|
available,
|
|
511
532
|
"/",
|
|
@@ -530,7 +551,7 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
|
|
|
530
551
|
if (!cls.id) return;
|
|
531
552
|
onOpenModal?.(isFull ? "waitlist" : "book", cls.id, selectedDate);
|
|
532
553
|
},
|
|
533
|
-
children: isFull ? "Join Waitlist" :
|
|
554
|
+
children: isFull ? "Join Waitlist" : formatBookingLabel(cls)
|
|
534
555
|
}
|
|
535
556
|
)
|
|
536
557
|
] })
|
|
@@ -572,6 +593,17 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
572
593
|
const [isHovered, setIsHovered] = useState2(false);
|
|
573
594
|
const [modalState, setModalState] = useState2(null);
|
|
574
595
|
const switchScheduleIdRef = useRef(null);
|
|
596
|
+
const liveScheduleIdRef = useRef(null);
|
|
597
|
+
const refetchLiveSchedule = useCallback(async () => {
|
|
598
|
+
const id = liveScheduleIdRef.current;
|
|
599
|
+
if (!id) return;
|
|
600
|
+
try {
|
|
601
|
+
const res = await fetch(`${API_URL}/api/schedule/id/${id}`);
|
|
602
|
+
const data = await res.json();
|
|
603
|
+
if (data?.id) setSchedule(data);
|
|
604
|
+
} catch {
|
|
605
|
+
}
|
|
606
|
+
}, []);
|
|
575
607
|
const dates = useMemo(() => {
|
|
576
608
|
const today = /* @__PURE__ */ new Date();
|
|
577
609
|
today.setHours(0, 0, 0, 0);
|
|
@@ -591,6 +623,18 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
591
623
|
}
|
|
592
624
|
}
|
|
593
625
|
}, [schedule, dates]);
|
|
626
|
+
useEffect(() => {
|
|
627
|
+
if (typeof window === "undefined") return;
|
|
628
|
+
const onVisible = () => {
|
|
629
|
+
if (!document.hidden) void refetchLiveSchedule();
|
|
630
|
+
};
|
|
631
|
+
window.addEventListener("focus", refetchLiveSchedule);
|
|
632
|
+
document.addEventListener("visibilitychange", onVisible);
|
|
633
|
+
return () => {
|
|
634
|
+
window.removeEventListener("focus", refetchLiveSchedule);
|
|
635
|
+
document.removeEventListener("visibilitychange", onVisible);
|
|
636
|
+
};
|
|
637
|
+
}, [refetchLiveSchedule]);
|
|
594
638
|
useEffect(() => {
|
|
595
639
|
if (typeof window === "undefined") return;
|
|
596
640
|
const isInEditor = window.self !== window.top;
|
|
@@ -652,7 +696,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
652
696
|
setLoading(false);
|
|
653
697
|
return;
|
|
654
698
|
}
|
|
655
|
-
;
|
|
699
|
+
liveScheduleIdRef.current = effectiveId;
|
|
656
700
|
(async () => {
|
|
657
701
|
try {
|
|
658
702
|
const res = await fetch(`${API_URL}/api/schedule/id/${effectiveId}`);
|
|
@@ -709,18 +753,14 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
709
753
|
const data = await res.json().catch(() => ({}));
|
|
710
754
|
throw new Error(data?.message ?? "Something went wrong. Please try again.");
|
|
711
755
|
}
|
|
756
|
+
await refetchLiveSchedule();
|
|
712
757
|
};
|
|
713
758
|
const handleReplaceSchedule = () => {
|
|
714
759
|
setIsHovered(false);
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
insertAfter
|
|
720
|
-
}, "*");
|
|
721
|
-
} else {
|
|
722
|
-
window.parent.postMessage({ type: "ow:scheduling-not-connected", insertAfter }, "*");
|
|
723
|
-
}
|
|
760
|
+
window.parent.postMessage(
|
|
761
|
+
{ type: "ow:scheduling-not-connected", insertAfter, currentScheduleId: schedule?.id },
|
|
762
|
+
"*"
|
|
763
|
+
);
|
|
724
764
|
};
|
|
725
765
|
if (!inEditor && !loading && !schedule) return null;
|
|
726
766
|
const sectionId = `scheduling-${insertAfter}`;
|
|
@@ -763,7 +803,19 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
763
803
|
),
|
|
764
804
|
/* @__PURE__ */ jsxs2("div", { className: "max-w-[1280px] mx-auto flex flex-col items-center gap-16", children: [
|
|
765
805
|
/* @__PURE__ */ jsxs2("div", { className: "flex flex-col items-center gap-4", children: [
|
|
766
|
-
/* @__PURE__ */ jsx2(
|
|
806
|
+
/* @__PURE__ */ jsx2(
|
|
807
|
+
"h2",
|
|
808
|
+
{
|
|
809
|
+
className: "font-display text-center m-0 text-(--color-dark,#200C02)",
|
|
810
|
+
style: {
|
|
811
|
+
fontSize: "var(--fs-section-h2, clamp(40px, 4.4vw, 64px))",
|
|
812
|
+
fontWeight: "var(--font-weight-heading, 400)",
|
|
813
|
+
lineHeight: 1.05,
|
|
814
|
+
letterSpacing: "-0.02em"
|
|
815
|
+
},
|
|
816
|
+
children: schedule?.name ?? "Book an appointment"
|
|
817
|
+
}
|
|
818
|
+
),
|
|
767
819
|
schedule?.description && /* @__PURE__ */ jsx2("p", { className: "font-body text-body text-center m-0 text-(--color-accent,#A89B83)", children: schedule.description })
|
|
768
820
|
] }),
|
|
769
821
|
/* @__PURE__ */ jsxs2("div", { className: "w-full flex flex-col items-end gap-3", children: [
|
|
@@ -4349,6 +4401,7 @@ function ItemActionToolbar({
|
|
|
4349
4401
|
onEditLink,
|
|
4350
4402
|
onAddItem,
|
|
4351
4403
|
onMore,
|
|
4404
|
+
editLinkDisabled = false,
|
|
4352
4405
|
addItemDisabled = true,
|
|
4353
4406
|
moreDisabled = true,
|
|
4354
4407
|
tooltipSide = "bottom"
|
|
@@ -4357,10 +4410,12 @@ function ItemActionToolbar({
|
|
|
4357
4410
|
/* @__PURE__ */ jsx8(
|
|
4358
4411
|
ToolbarActionTooltip,
|
|
4359
4412
|
{
|
|
4360
|
-
label: "
|
|
4413
|
+
label: "Edit link",
|
|
4361
4414
|
side: tooltipSide,
|
|
4415
|
+
disabled: editLinkDisabled,
|
|
4362
4416
|
buttonProps: {
|
|
4363
4417
|
onMouseDown: (e) => {
|
|
4418
|
+
if (editLinkDisabled) return;
|
|
4364
4419
|
e.preventDefault();
|
|
4365
4420
|
e.stopPropagation();
|
|
4366
4421
|
onEditLink?.();
|
|
@@ -4438,7 +4493,7 @@ function getChromeStyle(state) {
|
|
|
4438
4493
|
case "dragging":
|
|
4439
4494
|
return {
|
|
4440
4495
|
border: `2px solid ${PRIMARY}`,
|
|
4441
|
-
boxShadow: DRAG_SHADOW
|
|
4496
|
+
boxShadow: `${FOCUS_RING}, ${DRAG_SHADOW}`
|
|
4442
4497
|
};
|
|
4443
4498
|
default:
|
|
4444
4499
|
return {};
|
|
@@ -4454,6 +4509,8 @@ function ItemInteractionLayer({
|
|
|
4454
4509
|
dragHandleLabel = "Reorder item",
|
|
4455
4510
|
onDragHandleDragStart,
|
|
4456
4511
|
onDragHandleDragEnd,
|
|
4512
|
+
onItemPointerDown,
|
|
4513
|
+
onItemClick,
|
|
4457
4514
|
chromeGap = 6,
|
|
4458
4515
|
className
|
|
4459
4516
|
}) {
|
|
@@ -4461,7 +4518,8 @@ function ItemInteractionLayer({
|
|
|
4461
4518
|
const isActive = state === "active-top" || state === "active-bottom";
|
|
4462
4519
|
const isDragging = state === "dragging";
|
|
4463
4520
|
const showToolbar = isActive && toolbar;
|
|
4464
|
-
const showDragHandle = isActive
|
|
4521
|
+
const showDragHandle = (isActive || isDragging) && showHandle;
|
|
4522
|
+
const itemDragEnabled = isActive && showHandle && !isDragging && !dragDisabled;
|
|
4465
4523
|
return /* @__PURE__ */ jsxs4(
|
|
4466
4524
|
"div",
|
|
4467
4525
|
{
|
|
@@ -4486,11 +4544,28 @@ function ItemInteractionLayer({
|
|
|
4486
4544
|
style: getChromeStyle(state)
|
|
4487
4545
|
}
|
|
4488
4546
|
),
|
|
4547
|
+
itemDragEnabled && /* @__PURE__ */ jsx9(
|
|
4548
|
+
"div",
|
|
4549
|
+
{
|
|
4550
|
+
"data-ohw-item-drag-surface": "",
|
|
4551
|
+
className: "pointer-events-auto absolute inset-0 cursor-grab rounded-lg active:cursor-grabbing",
|
|
4552
|
+
onPointerDown: (e) => {
|
|
4553
|
+
if (e.button !== 0) return;
|
|
4554
|
+
onItemPointerDown?.(e);
|
|
4555
|
+
},
|
|
4556
|
+
onClick: (e) => {
|
|
4557
|
+
e.preventDefault();
|
|
4558
|
+
e.stopPropagation();
|
|
4559
|
+
onItemClick?.(e.clientX, e.clientY);
|
|
4560
|
+
}
|
|
4561
|
+
}
|
|
4562
|
+
),
|
|
4489
4563
|
showDragHandle && /* @__PURE__ */ jsx9(
|
|
4490
4564
|
"div",
|
|
4491
4565
|
{
|
|
4492
4566
|
"data-ohw-drag-handle-container": "",
|
|
4493
|
-
className: "pointer-events-auto absolute left-0 top-1/2 -translate-x-[calc(100%+7px)] -translate-y-1/2",
|
|
4567
|
+
className: "pointer-events-auto absolute left-0 top-1/2 z-10 -translate-x-[calc(100%+7px)] -translate-y-1/2",
|
|
4568
|
+
style: isDragging ? { visibility: "hidden" } : void 0,
|
|
4494
4569
|
children: /* @__PURE__ */ jsx9(
|
|
4495
4570
|
DragHandle,
|
|
4496
4571
|
{
|
|
@@ -4713,15 +4788,12 @@ function MediaOverlay({
|
|
|
4713
4788
|
className: "flex items-center justify-center cursor-pointer",
|
|
4714
4789
|
style: {
|
|
4715
4790
|
...box,
|
|
4716
|
-
//
|
|
4717
|
-
//
|
|
4718
|
-
|
|
4719
|
-
// Replace still works.
|
|
4720
|
-
pointerEvents: hover.hasTextOverlap ? "none" : "auto",
|
|
4791
|
+
// Keep the full-size visual overlay click-through so carousel controls and editable
|
|
4792
|
+
// content underneath remain interactive. The Replace button opts back in below.
|
|
4793
|
+
pointerEvents: "none",
|
|
4721
4794
|
boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
|
|
4722
4795
|
background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
|
|
4723
4796
|
},
|
|
4724
|
-
onClick: () => onReplace(hover.key),
|
|
4725
4797
|
children: /* @__PURE__ */ jsxs5(
|
|
4726
4798
|
Button,
|
|
4727
4799
|
{
|
|
@@ -4746,9 +4818,64 @@ function MediaOverlay({
|
|
|
4746
4818
|
] });
|
|
4747
4819
|
}
|
|
4748
4820
|
|
|
4821
|
+
// src/ui/CarouselOverlay.tsx
|
|
4822
|
+
import { GalleryHorizontal } from "lucide-react";
|
|
4823
|
+
import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
4824
|
+
var OVERLAY_BUTTON_STYLE2 = {
|
|
4825
|
+
pointerEvents: "auto",
|
|
4826
|
+
fontFamily: "Inter, sans-serif",
|
|
4827
|
+
fontSize: 12,
|
|
4828
|
+
color: "#000"
|
|
4829
|
+
};
|
|
4830
|
+
function CarouselOverlay({
|
|
4831
|
+
hover,
|
|
4832
|
+
onEdit
|
|
4833
|
+
}) {
|
|
4834
|
+
const { rect } = hover;
|
|
4835
|
+
return /* @__PURE__ */ jsx12(
|
|
4836
|
+
"div",
|
|
4837
|
+
{
|
|
4838
|
+
"data-ohw-bridge": "",
|
|
4839
|
+
"data-ohw-carousel-overlay": "",
|
|
4840
|
+
className: "flex cursor-pointer items-center justify-center",
|
|
4841
|
+
style: {
|
|
4842
|
+
position: "fixed",
|
|
4843
|
+
top: rect.top,
|
|
4844
|
+
left: rect.left,
|
|
4845
|
+
width: rect.width,
|
|
4846
|
+
height: rect.height,
|
|
4847
|
+
zIndex: 2147483646,
|
|
4848
|
+
pointerEvents: "auto",
|
|
4849
|
+
boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
|
|
4850
|
+
background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
|
|
4851
|
+
},
|
|
4852
|
+
onClick: () => onEdit(hover.key),
|
|
4853
|
+
children: /* @__PURE__ */ jsxs6(
|
|
4854
|
+
Button,
|
|
4855
|
+
{
|
|
4856
|
+
"data-ohw-carousel-overlay": "",
|
|
4857
|
+
variant: "outline",
|
|
4858
|
+
size: "sm",
|
|
4859
|
+
className: "cursor-pointer gap-1.5 hover:bg-background",
|
|
4860
|
+
style: OVERLAY_BUTTON_STYLE2,
|
|
4861
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
4862
|
+
onClick: (e) => {
|
|
4863
|
+
e.stopPropagation();
|
|
4864
|
+
onEdit(hover.key);
|
|
4865
|
+
},
|
|
4866
|
+
children: [
|
|
4867
|
+
/* @__PURE__ */ jsx12(GalleryHorizontal, { size: 14 }),
|
|
4868
|
+
"Edit gallery"
|
|
4869
|
+
]
|
|
4870
|
+
}
|
|
4871
|
+
)
|
|
4872
|
+
}
|
|
4873
|
+
);
|
|
4874
|
+
}
|
|
4875
|
+
|
|
4749
4876
|
// src/OhhwellsBridge.tsx
|
|
4750
|
-
import { createPortal } from "react-dom";
|
|
4751
|
-
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
|
4877
|
+
import { createPortal as createPortal2 } from "react-dom";
|
|
4878
|
+
import { usePathname as usePathname2, useRouter as useRouter2, useSearchParams } from "next/navigation";
|
|
4752
4879
|
|
|
4753
4880
|
// src/lib/session-search.ts
|
|
4754
4881
|
var STORAGE_KEY = "ohw-preserved-search";
|
|
@@ -4778,6 +4905,7 @@ function parseSectionsFromRoot(root) {
|
|
|
4778
4905
|
for (const el of root.querySelectorAll("[data-ohw-section]")) {
|
|
4779
4906
|
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
4780
4907
|
if (!id || seen.has(id)) continue;
|
|
4908
|
+
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
4781
4909
|
seen.add(id);
|
|
4782
4910
|
const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
|
|
4783
4911
|
sections.push({ id, label });
|
|
@@ -5024,54 +5152,22 @@ function scrollToHashSectionWhenReady(behavior = "smooth") {
|
|
|
5024
5152
|
tick();
|
|
5025
5153
|
}
|
|
5026
5154
|
|
|
5155
|
+
// src/ui/link-modal/LinkPopover.tsx
|
|
5156
|
+
import { useEffect as useEffect6 } from "react";
|
|
5157
|
+
|
|
5027
5158
|
// src/ui/dialog.tsx
|
|
5028
5159
|
import * as React7 from "react";
|
|
5029
5160
|
import { Dialog as DialogPrimitive } from "radix-ui";
|
|
5030
|
-
|
|
5031
|
-
// src/ui/icons.tsx
|
|
5032
|
-
import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
5033
|
-
function IconX({ className, ...props }) {
|
|
5034
|
-
return /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
5035
|
-
/* @__PURE__ */ jsx12("path", { d: "M18 6 6 18" }),
|
|
5036
|
-
/* @__PURE__ */ jsx12("path", { d: "m6 6 12 12" })
|
|
5037
|
-
] });
|
|
5038
|
-
}
|
|
5039
|
-
function IconChevronDown({ className, ...props }) {
|
|
5040
|
-
return /* @__PURE__ */ jsx12("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: /* @__PURE__ */ jsx12("path", { d: "m6 9 6 6 6-6" }) });
|
|
5041
|
-
}
|
|
5042
|
-
function IconFile({ className, ...props }) {
|
|
5043
|
-
return /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
5044
|
-
/* @__PURE__ */ jsx12("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
|
|
5045
|
-
/* @__PURE__ */ jsx12("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" })
|
|
5046
|
-
] });
|
|
5047
|
-
}
|
|
5048
|
-
function IconInfo({ className, ...props }) {
|
|
5049
|
-
return /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
5050
|
-
/* @__PURE__ */ jsx12("circle", { cx: "12", cy: "12", r: "10" }),
|
|
5051
|
-
/* @__PURE__ */ jsx12("path", { d: "M12 16v-4" }),
|
|
5052
|
-
/* @__PURE__ */ jsx12("path", { d: "M12 8h.01" })
|
|
5053
|
-
] });
|
|
5054
|
-
}
|
|
5055
|
-
function IconArrowRight({ className, ...props }) {
|
|
5056
|
-
return /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
5057
|
-
/* @__PURE__ */ jsx12("path", { d: "M5 12h14" }),
|
|
5058
|
-
/* @__PURE__ */ jsx12("path", { d: "m12 5 7 7-7 7" })
|
|
5059
|
-
] });
|
|
5060
|
-
}
|
|
5061
|
-
function IconSection({ className, ...props }) {
|
|
5062
|
-
return /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
5063
|
-
/* @__PURE__ */ jsx12("rect", { width: "18", height: "7", x: "3", y: "3", rx: "1" }),
|
|
5064
|
-
/* @__PURE__ */ jsx12("rect", { width: "9", height: "7", x: "3", y: "14", rx: "1" }),
|
|
5065
|
-
/* @__PURE__ */ jsx12("rect", { width: "5", height: "7", x: "16", y: "14", rx: "1" })
|
|
5066
|
-
] });
|
|
5067
|
-
}
|
|
5068
|
-
|
|
5069
|
-
// src/ui/dialog.tsx
|
|
5161
|
+
import { X } from "lucide-react";
|
|
5070
5162
|
import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
5071
|
-
function Dialog2({
|
|
5163
|
+
function Dialog2({
|
|
5164
|
+
...props
|
|
5165
|
+
}) {
|
|
5072
5166
|
return /* @__PURE__ */ jsx13(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
|
|
5073
5167
|
}
|
|
5074
|
-
function DialogPortal({
|
|
5168
|
+
function DialogPortal({
|
|
5169
|
+
...props
|
|
5170
|
+
}) {
|
|
5075
5171
|
return /* @__PURE__ */ jsx13(DialogPrimitive.Portal, { ...props });
|
|
5076
5172
|
}
|
|
5077
5173
|
function DialogOverlay({
|
|
@@ -5088,52 +5184,69 @@ function DialogOverlay({
|
|
|
5088
5184
|
}
|
|
5089
5185
|
);
|
|
5090
5186
|
}
|
|
5091
|
-
var DialogContent = React7.forwardRef(
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
/* @__PURE__ */
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
children
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
|
|
5118
|
-
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
|
|
5123
|
-
|
|
5124
|
-
});
|
|
5187
|
+
var DialogContent = React7.forwardRef(
|
|
5188
|
+
({ className, children, showCloseButton = true, container, ...props }, ref) => {
|
|
5189
|
+
const positionMode = container ? "absolute" : "fixed";
|
|
5190
|
+
return /* @__PURE__ */ jsxs7(DialogPortal, { container: container ?? void 0, children: [
|
|
5191
|
+
/* @__PURE__ */ jsx13(DialogOverlay, { className: cn(positionMode, "inset-0") }),
|
|
5192
|
+
/* @__PURE__ */ jsxs7(
|
|
5193
|
+
DialogPrimitive.Content,
|
|
5194
|
+
{
|
|
5195
|
+
ref,
|
|
5196
|
+
"data-slot": "dialog-content",
|
|
5197
|
+
className: cn(
|
|
5198
|
+
positionMode,
|
|
5199
|
+
"left-1/2 top-1/2 z-[2147483647] flex w-full max-w-[448px] -translate-x-1/2 -translate-y-1/2 flex-col overflow-visible",
|
|
5200
|
+
"rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
|
|
5201
|
+
container ? "max-h-[calc(100%-32px)]" : "max-h-[calc(100vh-32px)]",
|
|
5202
|
+
className
|
|
5203
|
+
),
|
|
5204
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
5205
|
+
...props,
|
|
5206
|
+
children: [
|
|
5207
|
+
children,
|
|
5208
|
+
showCloseButton ? /* @__PURE__ */ jsx13(
|
|
5209
|
+
DialogPrimitive.Close,
|
|
5210
|
+
{
|
|
5211
|
+
type: "button",
|
|
5212
|
+
className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
|
|
5213
|
+
"aria-label": "Close",
|
|
5214
|
+
children: /* @__PURE__ */ jsx13(X, { size: 16, "aria-hidden": true })
|
|
5215
|
+
}
|
|
5216
|
+
) : null
|
|
5217
|
+
]
|
|
5218
|
+
}
|
|
5219
|
+
)
|
|
5220
|
+
] });
|
|
5221
|
+
}
|
|
5222
|
+
);
|
|
5125
5223
|
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
|
5126
|
-
function DialogHeader({
|
|
5224
|
+
function DialogHeader({
|
|
5225
|
+
className,
|
|
5226
|
+
...props
|
|
5227
|
+
}) {
|
|
5127
5228
|
return /* @__PURE__ */ jsx13("div", { className: cn("flex flex-col gap-1.5", className), ...props });
|
|
5128
5229
|
}
|
|
5129
|
-
function DialogFooter({
|
|
5130
|
-
|
|
5230
|
+
function DialogFooter({
|
|
5231
|
+
className,
|
|
5232
|
+
...props
|
|
5233
|
+
}) {
|
|
5234
|
+
return /* @__PURE__ */ jsx13(
|
|
5235
|
+
"div",
|
|
5236
|
+
{
|
|
5237
|
+
className: cn("flex items-center justify-end gap-2", className),
|
|
5238
|
+
...props
|
|
5239
|
+
}
|
|
5240
|
+
);
|
|
5131
5241
|
}
|
|
5132
5242
|
var DialogTitle = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx13(
|
|
5133
5243
|
DialogPrimitive.Title,
|
|
5134
5244
|
{
|
|
5135
5245
|
ref,
|
|
5136
|
-
className: cn(
|
|
5246
|
+
className: cn(
|
|
5247
|
+
"text-lg font-semibold leading-none tracking-tight text-card-foreground",
|
|
5248
|
+
className
|
|
5249
|
+
),
|
|
5137
5250
|
...props
|
|
5138
5251
|
}
|
|
5139
5252
|
));
|
|
@@ -5149,19 +5262,40 @@ var DialogDescription = React7.forwardRef(({ className, ...props }, ref) => /* @
|
|
|
5149
5262
|
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
|
5150
5263
|
var DialogClose = DialogPrimitive.Close;
|
|
5151
5264
|
|
|
5265
|
+
// src/ui/link-modal/LinkEditorPanel.tsx
|
|
5266
|
+
import { Info, X as X3 } from "lucide-react";
|
|
5267
|
+
|
|
5152
5268
|
// src/ui/link-modal/DestinationBreadcrumb.tsx
|
|
5269
|
+
import { ArrowRight, File, GalleryVertical } from "lucide-react";
|
|
5153
5270
|
import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
5154
|
-
function DestinationBreadcrumb({
|
|
5271
|
+
function DestinationBreadcrumb({
|
|
5272
|
+
pageTitle,
|
|
5273
|
+
sectionLabel
|
|
5274
|
+
}) {
|
|
5155
5275
|
return /* @__PURE__ */ jsxs8("div", { className: "flex w-full flex-col gap-2", children: [
|
|
5156
|
-
/* @__PURE__ */ jsx14("p", { className: "text-sm font-medium text-foreground", children: "Destination" }),
|
|
5276
|
+
/* @__PURE__ */ jsx14("p", { className: "text-sm font-medium! text-foreground m-0", children: "Destination" }),
|
|
5157
5277
|
/* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-3", children: [
|
|
5158
5278
|
/* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
|
|
5159
|
-
/* @__PURE__ */ jsx14(
|
|
5160
|
-
/* @__PURE__ */ jsx14("span", { className: "text-sm font-medium leading-none text-foreground", children: pageTitle })
|
|
5279
|
+
/* @__PURE__ */ jsx14(File, { size: 16, className: "shrink-0 text-foreground", "aria-hidden": true }),
|
|
5280
|
+
/* @__PURE__ */ jsx14("span", { className: "text-sm font-medium leading-none text-foreground!", children: pageTitle })
|
|
5161
5281
|
] }),
|
|
5162
|
-
/* @__PURE__ */ jsx14(
|
|
5282
|
+
/* @__PURE__ */ jsx14(
|
|
5283
|
+
ArrowRight,
|
|
5284
|
+
{
|
|
5285
|
+
size: 16,
|
|
5286
|
+
className: "shrink-0 text-muted-foreground",
|
|
5287
|
+
"aria-hidden": true
|
|
5288
|
+
}
|
|
5289
|
+
),
|
|
5163
5290
|
/* @__PURE__ */ jsxs8("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
|
|
5164
|
-
/* @__PURE__ */ jsx14(
|
|
5291
|
+
/* @__PURE__ */ jsx14(
|
|
5292
|
+
GalleryVertical,
|
|
5293
|
+
{
|
|
5294
|
+
size: 16,
|
|
5295
|
+
className: "shrink-0 text-foreground",
|
|
5296
|
+
"aria-hidden": true
|
|
5297
|
+
}
|
|
5298
|
+
),
|
|
5165
5299
|
/* @__PURE__ */ jsx14("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
|
|
5166
5300
|
] })
|
|
5167
5301
|
] })
|
|
@@ -5169,8 +5303,13 @@ function DestinationBreadcrumb({ pageTitle, sectionLabel }) {
|
|
|
5169
5303
|
}
|
|
5170
5304
|
|
|
5171
5305
|
// src/ui/link-modal/SectionTreeItem.tsx
|
|
5306
|
+
import { GalleryVertical as GalleryVertical2 } from "lucide-react";
|
|
5172
5307
|
import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
5173
|
-
function SectionTreeItem({
|
|
5308
|
+
function SectionTreeItem({
|
|
5309
|
+
section,
|
|
5310
|
+
onSelect,
|
|
5311
|
+
selected
|
|
5312
|
+
}) {
|
|
5174
5313
|
const interactive = Boolean(onSelect);
|
|
5175
5314
|
return /* @__PURE__ */ jsxs9("div", { className: "flex h-9 w-full items-end pl-3", children: [
|
|
5176
5315
|
/* @__PURE__ */ jsx15(
|
|
@@ -5198,25 +5337,23 @@ function SectionTreeItem({ section, onSelect, selected }) {
|
|
|
5198
5337
|
interactive && selected && "border-primary"
|
|
5199
5338
|
),
|
|
5200
5339
|
children: [
|
|
5201
|
-
/* @__PURE__ */ jsx15(
|
|
5340
|
+
/* @__PURE__ */ jsx15(
|
|
5341
|
+
GalleryVertical2,
|
|
5342
|
+
{
|
|
5343
|
+
size: 16,
|
|
5344
|
+
className: "shrink-0 text-foreground",
|
|
5345
|
+
"aria-hidden": true
|
|
5346
|
+
}
|
|
5347
|
+
),
|
|
5202
5348
|
/* @__PURE__ */ jsx15("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
|
|
5203
5349
|
]
|
|
5204
5350
|
}
|
|
5205
5351
|
)
|
|
5206
5352
|
] });
|
|
5207
5353
|
}
|
|
5208
|
-
function SectionPickerList({ sections, onSelect }) {
|
|
5209
|
-
if (sections.length === 0) {
|
|
5210
|
-
return /* @__PURE__ */ jsx15("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." });
|
|
5211
|
-
}
|
|
5212
|
-
return /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-1", children: [
|
|
5213
|
-
/* @__PURE__ */ jsx15("p", { className: "text-sm text-muted-foreground", children: "Pick a section this link should scroll to." }),
|
|
5214
|
-
sections.map((section) => /* @__PURE__ */ jsx15(SectionTreeItem, { section, onSelect }, section.id))
|
|
5215
|
-
] });
|
|
5216
|
-
}
|
|
5217
5354
|
|
|
5218
5355
|
// src/ui/link-modal/UrlOrPageInput.tsx
|
|
5219
|
-
import { useId as useId2, useRef as useRef3, useState as useState3 } from "react";
|
|
5356
|
+
import { useEffect as useEffect3, useId as useId2, useRef as useRef3, useState as useState3 } from "react";
|
|
5220
5357
|
|
|
5221
5358
|
// src/ui/input.tsx
|
|
5222
5359
|
import * as React8 from "react";
|
|
@@ -5255,8 +5392,11 @@ function Label({ className, ...props }) {
|
|
|
5255
5392
|
}
|
|
5256
5393
|
|
|
5257
5394
|
// src/ui/link-modal/UrlOrPageInput.tsx
|
|
5395
|
+
import { ChevronDown, File as File2, X as X2 } from "lucide-react";
|
|
5258
5396
|
import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
5259
|
-
function FieldChevron({
|
|
5397
|
+
function FieldChevron({
|
|
5398
|
+
onClick
|
|
5399
|
+
}) {
|
|
5260
5400
|
return /* @__PURE__ */ jsx18(
|
|
5261
5401
|
"button",
|
|
5262
5402
|
{
|
|
@@ -5265,7 +5405,7 @@ function FieldChevron({ onClick }) {
|
|
|
5265
5405
|
onClick,
|
|
5266
5406
|
"aria-label": "Open page list",
|
|
5267
5407
|
tabIndex: -1,
|
|
5268
|
-
children: /* @__PURE__ */ jsx18(
|
|
5408
|
+
children: /* @__PURE__ */ jsx18(ChevronDown, { size: 16 })
|
|
5269
5409
|
}
|
|
5270
5410
|
);
|
|
5271
5411
|
}
|
|
@@ -5283,7 +5423,29 @@ function UrlOrPageInput({
|
|
|
5283
5423
|
}) {
|
|
5284
5424
|
const inputId = useId2();
|
|
5285
5425
|
const inputRef = useRef3(null);
|
|
5426
|
+
const rootRef = useRef3(null);
|
|
5286
5427
|
const [isFocused, setIsFocused] = useState3(false);
|
|
5428
|
+
useEffect3(() => {
|
|
5429
|
+
if (!dropdownOpen) return;
|
|
5430
|
+
const isOutside = (e) => {
|
|
5431
|
+
const root = rootRef.current;
|
|
5432
|
+
if (!root) return true;
|
|
5433
|
+
const path = typeof e.composedPath === "function" ? e.composedPath() : [];
|
|
5434
|
+
if (path.includes(root)) return false;
|
|
5435
|
+
const target = e.target;
|
|
5436
|
+
return !(target instanceof Node && root.contains(target));
|
|
5437
|
+
};
|
|
5438
|
+
const closeIfOutside = (e) => {
|
|
5439
|
+
if (!isOutside(e)) return;
|
|
5440
|
+
onDropdownOpenChange(false);
|
|
5441
|
+
};
|
|
5442
|
+
document.addEventListener("pointerdown", closeIfOutside, true);
|
|
5443
|
+
document.addEventListener("mousedown", closeIfOutside, true);
|
|
5444
|
+
return () => {
|
|
5445
|
+
document.removeEventListener("pointerdown", closeIfOutside, true);
|
|
5446
|
+
document.removeEventListener("mousedown", closeIfOutside, true);
|
|
5447
|
+
};
|
|
5448
|
+
}, [dropdownOpen, onDropdownOpenChange]);
|
|
5287
5449
|
const openDropdown = () => {
|
|
5288
5450
|
if (readOnly || filteredPages.length === 0) return;
|
|
5289
5451
|
onDropdownOpenChange(true);
|
|
@@ -5301,14 +5463,21 @@ function UrlOrPageInput({
|
|
|
5301
5463
|
requestAnimationFrame(() => inputRef.current?.focus());
|
|
5302
5464
|
};
|
|
5303
5465
|
const fieldClassName = cn(
|
|
5304
|
-
"data-ohw-link-field flex h-
|
|
5466
|
+
"data-ohw-link-field flex h-[36px] w-full items-center overflow-hidden rounded-md border bg-background pl-3 pr-3 py-2 outline-none transition-[border-color,box-shadow]",
|
|
5305
5467
|
urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
|
|
5306
5468
|
);
|
|
5307
5469
|
return /* @__PURE__ */ jsxs10("div", { className: "flex w-full flex-col gap-2 p-0", children: [
|
|
5308
5470
|
/* @__PURE__ */ jsx18(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
|
|
5309
|
-
/* @__PURE__ */ jsxs10("div", { className: "relative w-full", children: [
|
|
5471
|
+
/* @__PURE__ */ jsxs10("div", { ref: rootRef, className: "relative w-full", children: [
|
|
5310
5472
|
/* @__PURE__ */ jsxs10("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
|
|
5311
|
-
selectedPage ? /* @__PURE__ */ jsx18("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ jsx18(
|
|
5473
|
+
selectedPage ? /* @__PURE__ */ jsx18("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ jsx18(
|
|
5474
|
+
File2,
|
|
5475
|
+
{
|
|
5476
|
+
size: 16,
|
|
5477
|
+
className: "shrink-0 text-foreground",
|
|
5478
|
+
"aria-hidden": true
|
|
5479
|
+
}
|
|
5480
|
+
) }) : null,
|
|
5312
5481
|
readOnly ? /* @__PURE__ */ jsx18("span", { className: "min-w-0 flex-1 truncate text-sm leading-5 text-foreground", children: selectedPage?.title ?? value }) : /* @__PURE__ */ jsx18(
|
|
5313
5482
|
Input,
|
|
5314
5483
|
{
|
|
@@ -5320,7 +5489,14 @@ function UrlOrPageInput({
|
|
|
5320
5489
|
setIsFocused(true);
|
|
5321
5490
|
if (!selectedPage) openDropdown();
|
|
5322
5491
|
},
|
|
5323
|
-
onBlur: () =>
|
|
5492
|
+
onBlur: () => {
|
|
5493
|
+
setIsFocused(false);
|
|
5494
|
+
requestAnimationFrame(() => {
|
|
5495
|
+
if (!rootRef.current?.contains(document.activeElement)) {
|
|
5496
|
+
onDropdownOpenChange(false);
|
|
5497
|
+
}
|
|
5498
|
+
});
|
|
5499
|
+
},
|
|
5324
5500
|
placeholder,
|
|
5325
5501
|
className: cn(
|
|
5326
5502
|
"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",
|
|
@@ -5336,7 +5512,7 @@ function UrlOrPageInput({
|
|
|
5336
5512
|
onMouseDown: clearSelection,
|
|
5337
5513
|
"aria-label": "Clear selected page",
|
|
5338
5514
|
tabIndex: -1,
|
|
5339
|
-
children: /* @__PURE__ */ jsx18(
|
|
5515
|
+
children: /* @__PURE__ */ jsx18(X2, { size: 16, "aria-hidden": true })
|
|
5340
5516
|
}
|
|
5341
5517
|
) : null,
|
|
5342
5518
|
!readOnly ? /* @__PURE__ */ jsx18(FieldChevron, { onClick: toggleDropdown }) : null
|
|
@@ -5345,7 +5521,7 @@ function UrlOrPageInput({
|
|
|
5345
5521
|
"div",
|
|
5346
5522
|
{
|
|
5347
5523
|
"data-ohw-link-page-dropdown": "",
|
|
5348
|
-
className: "absolute left-0 right-0
|
|
5524
|
+
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",
|
|
5349
5525
|
onMouseDown: (e) => e.preventDefault(),
|
|
5350
5526
|
children: filteredPages.map((page) => /* @__PURE__ */ jsxs10(
|
|
5351
5527
|
"button",
|
|
@@ -5354,7 +5530,7 @@ function UrlOrPageInput({
|
|
|
5354
5530
|
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",
|
|
5355
5531
|
onClick: () => onPageSelect(page),
|
|
5356
5532
|
children: [
|
|
5357
|
-
/* @__PURE__ */ jsx18(
|
|
5533
|
+
/* @__PURE__ */ jsx18(File2, { size: 16, className: "shrink-0", "aria-hidden": true }),
|
|
5358
5534
|
/* @__PURE__ */ jsx18("span", { className: "truncate", children: page.title })
|
|
5359
5535
|
]
|
|
5360
5536
|
},
|
|
@@ -5367,38 +5543,466 @@ function UrlOrPageInput({
|
|
|
5367
5543
|
] });
|
|
5368
5544
|
}
|
|
5369
5545
|
|
|
5370
|
-
// src/ui/link-modal/
|
|
5371
|
-
import {
|
|
5372
|
-
function
|
|
5373
|
-
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
})
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5546
|
+
// src/ui/link-modal/LinkEditorPanel.tsx
|
|
5547
|
+
import { Fragment as Fragment3, jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
5548
|
+
function LinkEditorPanel({ state, onClose }) {
|
|
5549
|
+
const isCancel = state.secondaryLabel === "Cancel" || state.secondaryLabel === "Back to sections";
|
|
5550
|
+
return /* @__PURE__ */ jsxs11(Fragment3, { children: [
|
|
5551
|
+
/* @__PURE__ */ jsx19(DialogClose, { asChild: true, children: /* @__PURE__ */ jsx19(
|
|
5552
|
+
"button",
|
|
5553
|
+
{
|
|
5554
|
+
type: "button",
|
|
5555
|
+
className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50 h-7",
|
|
5556
|
+
"aria-label": "Close",
|
|
5557
|
+
onClick: onClose,
|
|
5558
|
+
children: /* @__PURE__ */ jsx19(X3, { size: 16, "aria-hidden": true })
|
|
5559
|
+
}
|
|
5560
|
+
) }),
|
|
5561
|
+
/* @__PURE__ */ jsx19(DialogHeader, { className: "w-full gap-1.5 p-6 pr-12", children: /* @__PURE__ */ jsx19(DialogTitle, { className: "m-0 w-full break-words", children: state.title }) }),
|
|
5562
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
|
|
5563
|
+
state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ jsx19(
|
|
5564
|
+
DestinationBreadcrumb,
|
|
5565
|
+
{
|
|
5566
|
+
pageTitle: state.selectedPage.title,
|
|
5567
|
+
sectionLabel: state.selectedSection.label
|
|
5568
|
+
}
|
|
5569
|
+
) : /* @__PURE__ */ jsx19(
|
|
5570
|
+
UrlOrPageInput,
|
|
5571
|
+
{
|
|
5572
|
+
value: state.searchValue,
|
|
5573
|
+
selectedPage: state.selectedPage,
|
|
5574
|
+
dropdownOpen: state.dropdownOpen,
|
|
5575
|
+
onDropdownOpenChange: state.setDropdownOpen,
|
|
5576
|
+
filteredPages: state.filteredPages,
|
|
5577
|
+
onInputChange: state.handleInputChange,
|
|
5578
|
+
onPageSelect: state.handlePageSelect,
|
|
5579
|
+
urlError: state.urlError
|
|
5580
|
+
}
|
|
5581
|
+
),
|
|
5582
|
+
state.showChooseSection ? /* @__PURE__ */ jsxs11("div", { className: "flex flex-col justify-center gap-2", children: [
|
|
5583
|
+
/* @__PURE__ */ jsx19(
|
|
5584
|
+
Button,
|
|
5585
|
+
{
|
|
5586
|
+
type: "button",
|
|
5587
|
+
variant: "outline",
|
|
5588
|
+
className: "w-fit cursor-pointer",
|
|
5589
|
+
size: "sm",
|
|
5590
|
+
onClick: state.handleChooseSection,
|
|
5591
|
+
children: "Choose a section"
|
|
5592
|
+
}
|
|
5593
|
+
),
|
|
5594
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
|
|
5595
|
+
/* @__PURE__ */ jsx19(Info, { size: 16, className: "shrink-0", "aria-hidden": true }),
|
|
5596
|
+
/* @__PURE__ */ jsx19("span", { children: "Pick a section this link should scroll to." })
|
|
5597
|
+
] })
|
|
5598
|
+
] }) : null,
|
|
5599
|
+
state.showSectionRow && state.selectedSection ? /* @__PURE__ */ jsx19(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
|
|
5600
|
+
] }),
|
|
5601
|
+
/* @__PURE__ */ jsxs11(DialogFooter, { className: "w-full px-6 pb-6", children: [
|
|
5602
|
+
/* @__PURE__ */ jsx19(
|
|
5603
|
+
Button,
|
|
5604
|
+
{
|
|
5605
|
+
type: "button",
|
|
5606
|
+
variant: isCancel ? "outline" : "ghost",
|
|
5607
|
+
className: "leading-6 shadow-none cursor-pointer",
|
|
5608
|
+
style: isCancel ? {
|
|
5609
|
+
backgroundColor: "var(--ohw-background)",
|
|
5610
|
+
borderColor: "var(--ohw-border)",
|
|
5611
|
+
color: "var(--ohw-foreground)"
|
|
5612
|
+
} : void 0,
|
|
5613
|
+
onClick: state.handleSecondary,
|
|
5614
|
+
children: state.secondaryLabel
|
|
5615
|
+
}
|
|
5616
|
+
),
|
|
5617
|
+
/* @__PURE__ */ jsx19(
|
|
5618
|
+
Button,
|
|
5619
|
+
{
|
|
5620
|
+
type: "button",
|
|
5621
|
+
className: "border-0 leading-6 shadow-none hover:opacity-90 disabled:opacity-50 cursor-pointer",
|
|
5622
|
+
style: {
|
|
5623
|
+
backgroundColor: "var(--ohw-primary)",
|
|
5624
|
+
color: "var(--ohw-primary-foreground)"
|
|
5625
|
+
},
|
|
5626
|
+
disabled: !state.isValid,
|
|
5627
|
+
onClick: state.handleSubmit,
|
|
5628
|
+
children: state.submitLabel
|
|
5629
|
+
}
|
|
5630
|
+
)
|
|
5631
|
+
] })
|
|
5632
|
+
] });
|
|
5633
|
+
}
|
|
5634
|
+
|
|
5635
|
+
// src/ui/link-modal/SectionPickerOverlay.tsx
|
|
5636
|
+
import { useCallback as useCallback2, useEffect as useEffect4, useMemo as useMemo2, useRef as useRef4, useState as useState4 } from "react";
|
|
5637
|
+
import { createPortal } from "react-dom";
|
|
5638
|
+
import { ArrowLeft, Check } from "lucide-react";
|
|
5639
|
+
import { usePathname, useRouter } from "next/navigation";
|
|
5640
|
+
import { jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
5641
|
+
var DIM_OVERLAY = "rgba(0, 0, 0, 0.45)";
|
|
5642
|
+
function rectsEqual(a, b) {
|
|
5643
|
+
if (a.size !== b.size) return false;
|
|
5644
|
+
for (const [id, rect] of a) {
|
|
5645
|
+
const other = b.get(id);
|
|
5646
|
+
if (!other || rect.top !== other.top || rect.left !== other.left || rect.width !== other.width || rect.height !== other.height) {
|
|
5647
|
+
return false;
|
|
5648
|
+
}
|
|
5649
|
+
}
|
|
5650
|
+
return true;
|
|
5651
|
+
}
|
|
5652
|
+
function readSectionRects(sectionIds) {
|
|
5653
|
+
const next = /* @__PURE__ */ new Map();
|
|
5654
|
+
for (const id of sectionIds) {
|
|
5655
|
+
const el = document.querySelector(
|
|
5656
|
+
`[data-ohw-section="${CSS.escape(id)}"]`
|
|
5657
|
+
);
|
|
5658
|
+
if (el) next.set(id, el.getBoundingClientRect());
|
|
5659
|
+
}
|
|
5660
|
+
return next;
|
|
5661
|
+
}
|
|
5662
|
+
function hitTestSectionId(x, y, sectionIds, rects) {
|
|
5663
|
+
for (const id of sectionIds) {
|
|
5664
|
+
const rect = rects.get(id);
|
|
5665
|
+
if (!rect || rect.width <= 0 || rect.height <= 0) continue;
|
|
5666
|
+
if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) {
|
|
5667
|
+
return id;
|
|
5668
|
+
}
|
|
5669
|
+
}
|
|
5670
|
+
return null;
|
|
5671
|
+
}
|
|
5672
|
+
function useSectionRects(sectionIdsKey, enabled) {
|
|
5673
|
+
const [rects, setRects] = useState4(/* @__PURE__ */ new Map());
|
|
5674
|
+
const sectionIds = useMemo2(
|
|
5675
|
+
() => sectionIdsKey ? sectionIdsKey.split("\0") : [],
|
|
5676
|
+
[sectionIdsKey]
|
|
5386
5677
|
);
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5678
|
+
useEffect4(() => {
|
|
5679
|
+
if (!enabled || sectionIds.length === 0) {
|
|
5680
|
+
setRects((prev) => prev.size === 0 ? prev : /* @__PURE__ */ new Map());
|
|
5681
|
+
return;
|
|
5682
|
+
}
|
|
5683
|
+
const update = () => {
|
|
5684
|
+
const next = readSectionRects(sectionIds);
|
|
5685
|
+
setRects((prev) => rectsEqual(prev, next) ? prev : next);
|
|
5686
|
+
};
|
|
5687
|
+
update();
|
|
5688
|
+
const opts = { capture: true, passive: true };
|
|
5689
|
+
window.addEventListener("scroll", update, opts);
|
|
5690
|
+
window.addEventListener("resize", update);
|
|
5691
|
+
const vv = window.visualViewport;
|
|
5692
|
+
vv?.addEventListener("resize", update);
|
|
5693
|
+
vv?.addEventListener("scroll", update);
|
|
5694
|
+
const ro = new ResizeObserver(update);
|
|
5695
|
+
for (const id of sectionIds) {
|
|
5696
|
+
const el = document.querySelector(
|
|
5697
|
+
`[data-ohw-section="${CSS.escape(id)}"]`
|
|
5698
|
+
);
|
|
5699
|
+
if (el) ro.observe(el);
|
|
5700
|
+
}
|
|
5701
|
+
return () => {
|
|
5702
|
+
window.removeEventListener("scroll", update, opts);
|
|
5703
|
+
window.removeEventListener("resize", update);
|
|
5704
|
+
vv?.removeEventListener("resize", update);
|
|
5705
|
+
vv?.removeEventListener("scroll", update);
|
|
5706
|
+
ro.disconnect();
|
|
5707
|
+
};
|
|
5708
|
+
}, [sectionIds, enabled]);
|
|
5709
|
+
return rects;
|
|
5710
|
+
}
|
|
5711
|
+
function SectionPickerOverlay({
|
|
5712
|
+
pagePath,
|
|
5713
|
+
sections,
|
|
5714
|
+
onBack,
|
|
5715
|
+
onSelect
|
|
5716
|
+
}) {
|
|
5717
|
+
const router = useRouter();
|
|
5718
|
+
const pathname = usePathname();
|
|
5719
|
+
const [selectedId, setSelectedId] = useState4(null);
|
|
5720
|
+
const [hoveredId, setHoveredId] = useState4(null);
|
|
5721
|
+
const pointerRef = useRef4(null);
|
|
5722
|
+
const pointerScreenRef = useRef4(null);
|
|
5723
|
+
const iframeOffsetTopRef = useRef4(null);
|
|
5724
|
+
const sectionIdsRef = useRef4([]);
|
|
5725
|
+
const [chromeClip, setChromeClip] = useState4(
|
|
5726
|
+
() => ({
|
|
5727
|
+
top: 0,
|
|
5728
|
+
bottom: typeof window !== "undefined" ? window.innerHeight : 0
|
|
5729
|
+
})
|
|
5730
|
+
);
|
|
5731
|
+
const normalizedTarget = normalizePath(pagePath);
|
|
5732
|
+
const isOnTargetPage = normalizePath(pathname) === normalizedTarget;
|
|
5733
|
+
useEffect4(() => {
|
|
5734
|
+
if (isOnTargetPage) return;
|
|
5735
|
+
const search = readPreservedSearch();
|
|
5736
|
+
router.push(`${normalizedTarget}${search}`);
|
|
5737
|
+
}, [isOnTargetPage, normalizedTarget, router]);
|
|
5738
|
+
useEffect4(() => {
|
|
5739
|
+
document.documentElement.setAttribute("data-ohw-section-picking", "");
|
|
5740
|
+
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => {
|
|
5741
|
+
el.removeAttribute("data-ohw-hovered");
|
|
5742
|
+
});
|
|
5743
|
+
document.querySelectorAll("[data-ohw-state-hovered]").forEach((el) => {
|
|
5744
|
+
el.removeAttribute("data-ohw-state-hovered");
|
|
5745
|
+
});
|
|
5746
|
+
return () => {
|
|
5747
|
+
document.documentElement.removeAttribute("data-ohw-section-picking");
|
|
5748
|
+
};
|
|
5749
|
+
}, []);
|
|
5750
|
+
const liveSections = useMemo2(() => {
|
|
5751
|
+
if (!isOnTargetPage) return sections;
|
|
5752
|
+
const live = collectSectionsFromDom();
|
|
5753
|
+
if (live.length === 0) return sections;
|
|
5754
|
+
const labels = new Map(sections.map((s) => [s.id, s.label]));
|
|
5755
|
+
return live.map((s) => ({ id: s.id, label: labels.get(s.id) ?? s.label }));
|
|
5756
|
+
}, [isOnTargetPage, sections, pathname]);
|
|
5757
|
+
const sectionIdsKey = useMemo2(
|
|
5758
|
+
() => liveSections.map((s) => s.id).join("\0"),
|
|
5759
|
+
[liveSections]
|
|
5760
|
+
);
|
|
5761
|
+
const sectionIds = useMemo2(
|
|
5762
|
+
() => liveSections.map((s) => s.id),
|
|
5763
|
+
[liveSections]
|
|
5764
|
+
);
|
|
5765
|
+
sectionIdsRef.current = sectionIds;
|
|
5766
|
+
const rects = useSectionRects(sectionIdsKey, isOnTargetPage);
|
|
5767
|
+
const applyHoverAt = useCallback2(
|
|
5768
|
+
(x, y, liveRects) => {
|
|
5769
|
+
const ids = sectionIdsRef.current;
|
|
5770
|
+
const map = liveRects ?? readSectionRects(ids);
|
|
5771
|
+
const next = hitTestSectionId(x, y, ids, map);
|
|
5772
|
+
setHoveredId((prev) => prev === next ? prev : next);
|
|
5773
|
+
},
|
|
5774
|
+
[]
|
|
5775
|
+
);
|
|
5776
|
+
useEffect4(() => {
|
|
5777
|
+
const applyClip = (iframeOffsetTop, visibleCanvasTop, canvasH) => {
|
|
5778
|
+
const top = Math.max(0, visibleCanvasTop - iframeOffsetTop);
|
|
5779
|
+
const bottom = Math.min(
|
|
5780
|
+
window.innerHeight,
|
|
5781
|
+
visibleCanvasTop + canvasH - iframeOffsetTop
|
|
5782
|
+
);
|
|
5783
|
+
setChromeClip(
|
|
5784
|
+
(prev) => prev.top === top && prev.bottom === bottom ? prev : { top, bottom: Math.max(top, bottom) }
|
|
5785
|
+
);
|
|
5786
|
+
};
|
|
5787
|
+
const onParentScroll = (e) => {
|
|
5788
|
+
if (e.data?.type !== "ow:parent-scroll") return;
|
|
5789
|
+
const { iframeOffsetTop, headerH, canvasH } = e.data;
|
|
5790
|
+
applyClip(iframeOffsetTop, headerH, canvasH);
|
|
5791
|
+
iframeOffsetTopRef.current = iframeOffsetTop;
|
|
5792
|
+
if (!pointerScreenRef.current && pointerRef.current) {
|
|
5793
|
+
pointerScreenRef.current = {
|
|
5794
|
+
x: pointerRef.current.x,
|
|
5795
|
+
y: pointerRef.current.y + iframeOffsetTop
|
|
5796
|
+
};
|
|
5797
|
+
}
|
|
5798
|
+
const screen = pointerScreenRef.current;
|
|
5799
|
+
if (screen) {
|
|
5800
|
+
const next = { x: screen.x, y: screen.y - iframeOffsetTop };
|
|
5801
|
+
pointerRef.current = next;
|
|
5802
|
+
applyHoverAt(next.x, next.y);
|
|
5803
|
+
}
|
|
5804
|
+
};
|
|
5805
|
+
const onResize = () => {
|
|
5806
|
+
setChromeClip((prev) => {
|
|
5807
|
+
const bottom = Math.max(prev.top, window.innerHeight);
|
|
5808
|
+
return prev.bottom === bottom ? prev : { ...prev, bottom };
|
|
5809
|
+
});
|
|
5810
|
+
};
|
|
5811
|
+
window.addEventListener("message", onParentScroll);
|
|
5812
|
+
window.addEventListener("resize", onResize);
|
|
5813
|
+
return () => {
|
|
5814
|
+
window.removeEventListener("message", onParentScroll);
|
|
5815
|
+
window.removeEventListener("resize", onResize);
|
|
5816
|
+
};
|
|
5817
|
+
}, [applyHoverAt]);
|
|
5818
|
+
useEffect4(() => {
|
|
5819
|
+
const ptr = pointerRef.current;
|
|
5820
|
+
if (!ptr) return;
|
|
5821
|
+
applyHoverAt(ptr.x, ptr.y, rects);
|
|
5822
|
+
}, [rects, applyHoverAt]);
|
|
5823
|
+
useEffect4(() => {
|
|
5824
|
+
const rememberPointer = (clientX, clientY) => {
|
|
5825
|
+
pointerRef.current = { x: clientX, y: clientY };
|
|
5826
|
+
const top = iframeOffsetTopRef.current;
|
|
5827
|
+
if (top != null) {
|
|
5828
|
+
pointerScreenRef.current = { x: clientX, y: clientY + top };
|
|
5829
|
+
}
|
|
5830
|
+
applyHoverAt(clientX, clientY, rects);
|
|
5831
|
+
};
|
|
5832
|
+
const onPointerMove = (e) => {
|
|
5833
|
+
rememberPointer(e.clientX, e.clientY);
|
|
5834
|
+
};
|
|
5835
|
+
const onPointerSync = (e) => {
|
|
5836
|
+
if (e.data?.type !== "ow:pointer-sync") return;
|
|
5837
|
+
const { clientX, clientY } = e.data;
|
|
5838
|
+
rememberPointer(clientX, clientY);
|
|
5839
|
+
};
|
|
5840
|
+
window.addEventListener("pointermove", onPointerMove, { passive: true });
|
|
5841
|
+
window.addEventListener("message", onPointerSync);
|
|
5842
|
+
return () => {
|
|
5843
|
+
window.removeEventListener("pointermove", onPointerMove);
|
|
5844
|
+
window.removeEventListener("message", onPointerSync);
|
|
5845
|
+
};
|
|
5846
|
+
}, [rects, applyHoverAt]);
|
|
5847
|
+
const handleSelect = useCallback2(
|
|
5848
|
+
(section) => {
|
|
5849
|
+
if (selectedId) return;
|
|
5850
|
+
setSelectedId(section.id);
|
|
5851
|
+
onSelect(section);
|
|
5852
|
+
},
|
|
5853
|
+
[selectedId, onSelect]
|
|
5854
|
+
);
|
|
5855
|
+
useEffect4(() => {
|
|
5856
|
+
const onKeyDown = (e) => {
|
|
5857
|
+
if (e.key === "Escape") {
|
|
5858
|
+
e.preventDefault();
|
|
5859
|
+
e.stopPropagation();
|
|
5860
|
+
onBack();
|
|
5861
|
+
}
|
|
5862
|
+
};
|
|
5863
|
+
window.addEventListener("keydown", onKeyDown, true);
|
|
5864
|
+
return () => window.removeEventListener("keydown", onKeyDown, true);
|
|
5865
|
+
}, [onBack]);
|
|
5866
|
+
const portalRoot = typeof document !== "undefined" ? document.querySelector("[data-ohw-bridge-root]") ?? document.body : null;
|
|
5867
|
+
if (!portalRoot) return null;
|
|
5868
|
+
return createPortal(
|
|
5869
|
+
/* @__PURE__ */ jsxs12(
|
|
5870
|
+
"div",
|
|
5871
|
+
{
|
|
5872
|
+
"data-ohw-section-picker": "",
|
|
5873
|
+
"data-ohw-bridge": "",
|
|
5874
|
+
className: `pointer-events-none fixed inset-0 z-[2147483647] transition-opacity duration-200 ${"opacity-100"}`,
|
|
5875
|
+
"aria-modal": true,
|
|
5876
|
+
role: "dialog",
|
|
5877
|
+
"aria-label": "Choose a section",
|
|
5878
|
+
children: [
|
|
5879
|
+
/* @__PURE__ */ jsx20(
|
|
5880
|
+
"div",
|
|
5881
|
+
{
|
|
5882
|
+
className: "pointer-events-auto fixed left-5 z-[2]",
|
|
5883
|
+
style: { top: chromeClip.top + 20 },
|
|
5884
|
+
children: /* @__PURE__ */ jsxs12(
|
|
5885
|
+
Button,
|
|
5886
|
+
{
|
|
5887
|
+
type: "button",
|
|
5888
|
+
variant: "outline",
|
|
5889
|
+
size: "sm",
|
|
5890
|
+
className: "h-8 min-w-0 gap-1 border-border bg-background px-2 py-1.5 shadow-sm hover:bg-muted cursor-pointer",
|
|
5891
|
+
onClick: onBack,
|
|
5892
|
+
children: [
|
|
5893
|
+
/* @__PURE__ */ jsx20(ArrowLeft, { className: "size-4 shrink-0", "aria-hidden": true }),
|
|
5894
|
+
"Back"
|
|
5895
|
+
]
|
|
5896
|
+
}
|
|
5897
|
+
)
|
|
5898
|
+
}
|
|
5899
|
+
),
|
|
5900
|
+
/* @__PURE__ */ jsx20(
|
|
5901
|
+
"div",
|
|
5902
|
+
{
|
|
5903
|
+
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",
|
|
5904
|
+
style: {
|
|
5905
|
+
top: chromeClip.bottom - 20,
|
|
5906
|
+
transform: "translate(-50%, -100%)",
|
|
5907
|
+
backgroundColor: "var(--ohw-popover-foreground, #0c0a09)"
|
|
5908
|
+
},
|
|
5909
|
+
"data-ohw-section-picker-hint": "",
|
|
5910
|
+
children: "Click on section to select"
|
|
5911
|
+
}
|
|
5912
|
+
),
|
|
5913
|
+
!isOnTargetPage ? /* @__PURE__ */ jsx20(
|
|
5914
|
+
"div",
|
|
5915
|
+
{
|
|
5916
|
+
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",
|
|
5917
|
+
style: { top: chromeClip.top + 64 },
|
|
5918
|
+
children: "Loading page preview\u2026"
|
|
5919
|
+
}
|
|
5920
|
+
) : null,
|
|
5921
|
+
isOnTargetPage && liveSections.length === 0 ? /* @__PURE__ */ jsx20("div", { className: "pointer-events-auto fixed inset-0 z-[1] flex items-center justify-center bg-muted/40", children: /* @__PURE__ */ jsx20("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." }) }) : null,
|
|
5922
|
+
isOnTargetPage ? liveSections.map((section) => {
|
|
5923
|
+
const rect = rects.get(section.id);
|
|
5924
|
+
if (!rect || rect.width <= 0 || rect.height <= 0) return null;
|
|
5925
|
+
const isSelected = selectedId === section.id;
|
|
5926
|
+
const isHovered = hoveredId === section.id;
|
|
5927
|
+
const isLit = isSelected || isHovered;
|
|
5928
|
+
return /* @__PURE__ */ jsxs12(
|
|
5929
|
+
"button",
|
|
5930
|
+
{
|
|
5931
|
+
type: "button",
|
|
5932
|
+
className: "pointer-events-auto fixed z-[1] cursor-pointer border-0 bg-transparent p-0 transition-[background-color] duration-150",
|
|
5933
|
+
style: {
|
|
5934
|
+
top: rect.top,
|
|
5935
|
+
left: rect.left,
|
|
5936
|
+
width: rect.width,
|
|
5937
|
+
height: rect.height,
|
|
5938
|
+
backgroundColor: isLit ? "transparent" : DIM_OVERLAY
|
|
5939
|
+
},
|
|
5940
|
+
"aria-label": `Select section ${section.label}`,
|
|
5941
|
+
onClick: () => handleSelect(section),
|
|
5942
|
+
children: [
|
|
5943
|
+
isLit ? /* @__PURE__ */ jsx20(
|
|
5944
|
+
"span",
|
|
5945
|
+
{
|
|
5946
|
+
className: "pointer-events-none absolute",
|
|
5947
|
+
style: {
|
|
5948
|
+
inset: 4,
|
|
5949
|
+
borderRadius: "var(--radius, 6px)",
|
|
5950
|
+
border: "1.5px dashed var(--primary, #0885FE)",
|
|
5951
|
+
boxSizing: "border-box"
|
|
5952
|
+
},
|
|
5953
|
+
"aria-hidden": true
|
|
5954
|
+
}
|
|
5955
|
+
) : null,
|
|
5956
|
+
isSelected ? /* @__PURE__ */ jsx20(
|
|
5957
|
+
"span",
|
|
5958
|
+
{
|
|
5959
|
+
className: "absolute right-3 top-3 flex size-8 items-center justify-center rounded-full text-white",
|
|
5960
|
+
style: { backgroundColor: "var(--ohw-primary, #0885fe)" },
|
|
5961
|
+
"aria-hidden": true,
|
|
5962
|
+
children: /* @__PURE__ */ jsx20(Check, { className: "size-5" })
|
|
5963
|
+
}
|
|
5964
|
+
) : null
|
|
5965
|
+
]
|
|
5966
|
+
},
|
|
5967
|
+
section.id
|
|
5968
|
+
);
|
|
5969
|
+
}) : null
|
|
5970
|
+
]
|
|
5971
|
+
}
|
|
5972
|
+
),
|
|
5973
|
+
portalRoot
|
|
5974
|
+
);
|
|
5975
|
+
}
|
|
5976
|
+
|
|
5977
|
+
// src/ui/link-modal/useLinkModalState.ts
|
|
5978
|
+
import { useCallback as useCallback3, useEffect as useEffect5, useMemo as useMemo3, useState as useState5 } from "react";
|
|
5979
|
+
function useLinkModalState({
|
|
5980
|
+
open,
|
|
5981
|
+
mode,
|
|
5982
|
+
pages,
|
|
5983
|
+
sections: _sections,
|
|
5984
|
+
sectionsByPath,
|
|
5985
|
+
initialTarget,
|
|
5986
|
+
existingTargets: _existingTargets,
|
|
5987
|
+
onClose,
|
|
5988
|
+
onSubmit
|
|
5989
|
+
}) {
|
|
5990
|
+
const availablePages = useMemo3(() => pages, [pages]);
|
|
5991
|
+
const [searchValue, setSearchValue] = useState5("");
|
|
5992
|
+
const [selectedPage, setSelectedPage] = useState5(null);
|
|
5993
|
+
const [selectedSection, setSelectedSection] = useState5(null);
|
|
5994
|
+
const [step, setStep] = useState5("input");
|
|
5995
|
+
const [dropdownOpen, setDropdownOpen] = useState5(false);
|
|
5996
|
+
const [urlError, setUrlError] = useState5("");
|
|
5997
|
+
const reset = useCallback3(() => {
|
|
5998
|
+
setSearchValue("");
|
|
5999
|
+
setSelectedPage(null);
|
|
6000
|
+
setSelectedSection(null);
|
|
5397
6001
|
setStep("input");
|
|
5398
6002
|
setDropdownOpen(false);
|
|
5399
6003
|
setUrlError("");
|
|
5400
6004
|
}, []);
|
|
5401
|
-
|
|
6005
|
+
useEffect5(() => {
|
|
5402
6006
|
if (!open) return;
|
|
5403
6007
|
if (mode === "edit" && initialTarget) {
|
|
5404
6008
|
const { pageRoute } = parseTarget(initialTarget);
|
|
@@ -5413,12 +6017,12 @@ function useLinkModalState({
|
|
|
5413
6017
|
}
|
|
5414
6018
|
setDropdownOpen(false);
|
|
5415
6019
|
setUrlError("");
|
|
5416
|
-
}, [open, mode, initialTarget,
|
|
5417
|
-
const filteredPages =
|
|
6020
|
+
}, [open, mode, initialTarget, reset]);
|
|
6021
|
+
const filteredPages = useMemo3(() => {
|
|
5418
6022
|
if (!searchValue.trim()) return availablePages;
|
|
5419
6023
|
return availablePages.filter((p) => p.title.toLowerCase().startsWith(searchValue.toLowerCase()));
|
|
5420
6024
|
}, [availablePages, searchValue]);
|
|
5421
|
-
const activeSections =
|
|
6025
|
+
const activeSections = useMemo3(() => {
|
|
5422
6026
|
if (!selectedPage) return [];
|
|
5423
6027
|
return getSectionsForPath(sectionsByPath, selectedPage.path);
|
|
5424
6028
|
}, [selectedPage, sectionsByPath]);
|
|
@@ -5460,11 +6064,14 @@ function useLinkModalState({
|
|
|
5460
6064
|
const handleBackToSections = () => {
|
|
5461
6065
|
setStep("sectionPicker");
|
|
5462
6066
|
};
|
|
6067
|
+
const handleSectionPickerBack = () => {
|
|
6068
|
+
setStep("input");
|
|
6069
|
+
};
|
|
5463
6070
|
const handleClose = () => {
|
|
5464
6071
|
reset();
|
|
5465
6072
|
onClose();
|
|
5466
6073
|
};
|
|
5467
|
-
const isValid =
|
|
6074
|
+
const isValid = useMemo3(() => {
|
|
5468
6075
|
if (urlError) return false;
|
|
5469
6076
|
if (showBreadcrumb) return true;
|
|
5470
6077
|
if (selectedPage) return true;
|
|
@@ -5497,7 +6104,7 @@ function useLinkModalState({
|
|
|
5497
6104
|
onSubmit(normalizeUrl(searchValue));
|
|
5498
6105
|
handleClose();
|
|
5499
6106
|
};
|
|
5500
|
-
const submitLabel = mode === "edit" ? "Save" : "Create";
|
|
6107
|
+
const submitLabel = showBreadcrumb ? "Save" : mode === "edit" ? "Save" : "Create";
|
|
5501
6108
|
const title = mode === "edit" ? "Edit navigation item" : "Create navigation item";
|
|
5502
6109
|
const secondaryLabel = showBreadcrumb ? "Back to sections" : "Cancel";
|
|
5503
6110
|
const handleSecondary = showBreadcrumb ? handleBackToSections : handleClose;
|
|
@@ -5524,23 +6131,29 @@ function useLinkModalState({
|
|
|
5524
6131
|
handleChooseSection,
|
|
5525
6132
|
handleSectionSelect,
|
|
5526
6133
|
handleBackToSections,
|
|
6134
|
+
handleSectionPickerBack,
|
|
5527
6135
|
handleClose,
|
|
5528
6136
|
handleSecondary,
|
|
5529
6137
|
handleSubmit
|
|
5530
6138
|
};
|
|
5531
6139
|
}
|
|
5532
6140
|
|
|
5533
|
-
// src/ui/link-modal/
|
|
5534
|
-
import { Fragment as
|
|
5535
|
-
function
|
|
6141
|
+
// src/ui/link-modal/LinkPopover.tsx
|
|
6142
|
+
import { Fragment as Fragment4, jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
6143
|
+
function postToParent(data) {
|
|
6144
|
+
window.parent?.postMessage(data, "*");
|
|
6145
|
+
}
|
|
6146
|
+
function LinkPopover({
|
|
5536
6147
|
open = true,
|
|
6148
|
+
panelRef,
|
|
6149
|
+
portalContainer,
|
|
6150
|
+
onClose,
|
|
5537
6151
|
mode = "create",
|
|
5538
6152
|
pages,
|
|
5539
6153
|
sections = [],
|
|
5540
6154
|
sectionsByPath,
|
|
5541
6155
|
initialTarget,
|
|
5542
6156
|
existingTargets = [],
|
|
5543
|
-
onClose,
|
|
5544
6157
|
onSubmit
|
|
5545
6158
|
}) {
|
|
5546
6159
|
const state = useLinkModalState({
|
|
@@ -5554,115 +6167,109 @@ function LinkEditorPanel({
|
|
|
5554
6167
|
onClose,
|
|
5555
6168
|
onSubmit
|
|
5556
6169
|
});
|
|
5557
|
-
const
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
|
|
6170
|
+
const sectionPickerActive = state.showSectionPicker && Boolean(state.selectedPage);
|
|
6171
|
+
useEffect6(() => {
|
|
6172
|
+
if (!open) return;
|
|
6173
|
+
if (sectionPickerActive) {
|
|
6174
|
+
postToParent({ type: "ui:unlock" });
|
|
6175
|
+
postToParent({ type: "ow:section-picker", active: true });
|
|
6176
|
+
document.documentElement.style.overflow = "";
|
|
6177
|
+
document.body.style.overflow = "";
|
|
6178
|
+
return () => {
|
|
6179
|
+
postToParent({ type: "ow:section-picker", active: false });
|
|
6180
|
+
};
|
|
6181
|
+
}
|
|
6182
|
+
postToParent({ type: "ow:section-picker", active: false });
|
|
6183
|
+
postToParent({ type: "ui:lock" });
|
|
6184
|
+
const html = document.documentElement;
|
|
6185
|
+
const body = document.body;
|
|
6186
|
+
const prevHtmlOverflow = html.style.overflow;
|
|
6187
|
+
const prevBodyOverflow = body.style.overflow;
|
|
6188
|
+
const prevHtmlOverscroll = html.style.overscrollBehavior;
|
|
6189
|
+
const prevBodyOverscroll = body.style.overscrollBehavior;
|
|
6190
|
+
html.style.overflow = "hidden";
|
|
6191
|
+
body.style.overflow = "hidden";
|
|
6192
|
+
html.style.overscrollBehavior = "none";
|
|
6193
|
+
body.style.overscrollBehavior = "none";
|
|
6194
|
+
const canScrollElement = (el, deltaY) => {
|
|
6195
|
+
const { overflowY } = getComputedStyle(el);
|
|
6196
|
+
if (overflowY !== "auto" && overflowY !== "scroll") return false;
|
|
6197
|
+
if (el.scrollHeight <= el.clientHeight + 1) return false;
|
|
6198
|
+
if (deltaY < 0) return el.scrollTop > 0;
|
|
6199
|
+
if (deltaY > 0)
|
|
6200
|
+
return el.scrollTop + el.clientHeight < el.scrollHeight - 1;
|
|
6201
|
+
return true;
|
|
6202
|
+
};
|
|
6203
|
+
const allowsInternalScroll = (e) => {
|
|
6204
|
+
const target = e.target;
|
|
6205
|
+
if (!(target instanceof Element)) return false;
|
|
6206
|
+
const scrollRoot = target.closest(
|
|
6207
|
+
"[data-ohw-link-page-dropdown], [data-ohw-allow-scroll]"
|
|
6208
|
+
);
|
|
6209
|
+
if (!scrollRoot) return false;
|
|
6210
|
+
const deltaY = e instanceof WheelEvent ? e.deltaY : 0;
|
|
6211
|
+
return canScrollElement(scrollRoot, deltaY);
|
|
6212
|
+
};
|
|
6213
|
+
const preventBackgroundScroll = (e) => {
|
|
6214
|
+
if (allowsInternalScroll(e)) return;
|
|
6215
|
+
e.preventDefault();
|
|
6216
|
+
};
|
|
6217
|
+
const scrollOpts = { passive: false, capture: true };
|
|
6218
|
+
document.addEventListener("wheel", preventBackgroundScroll, scrollOpts);
|
|
6219
|
+
document.addEventListener("touchmove", preventBackgroundScroll, scrollOpts);
|
|
6220
|
+
return () => {
|
|
6221
|
+
postToParent({ type: "ui:unlock" });
|
|
6222
|
+
html.style.overflow = prevHtmlOverflow;
|
|
6223
|
+
body.style.overflow = prevBodyOverflow;
|
|
6224
|
+
html.style.overscrollBehavior = prevHtmlOverscroll;
|
|
6225
|
+
body.style.overscrollBehavior = prevBodyOverscroll;
|
|
6226
|
+
document.removeEventListener(
|
|
6227
|
+
"wheel",
|
|
6228
|
+
preventBackgroundScroll,
|
|
6229
|
+
scrollOpts
|
|
6230
|
+
);
|
|
6231
|
+
document.removeEventListener(
|
|
6232
|
+
"touchmove",
|
|
6233
|
+
preventBackgroundScroll,
|
|
6234
|
+
scrollOpts
|
|
6235
|
+
);
|
|
6236
|
+
};
|
|
6237
|
+
}, [open, sectionPickerActive]);
|
|
6238
|
+
return /* @__PURE__ */ jsxs13(Fragment4, { children: [
|
|
6239
|
+
/* @__PURE__ */ jsx21(
|
|
6240
|
+
Dialog2,
|
|
5561
6241
|
{
|
|
5562
|
-
|
|
5563
|
-
|
|
5564
|
-
|
|
5565
|
-
|
|
6242
|
+
open: open && !sectionPickerActive,
|
|
6243
|
+
onOpenChange: (next) => {
|
|
6244
|
+
if (!next) onClose?.();
|
|
6245
|
+
},
|
|
6246
|
+
children: /* @__PURE__ */ jsx21(
|
|
6247
|
+
DialogContent,
|
|
6248
|
+
{
|
|
6249
|
+
ref: panelRef,
|
|
6250
|
+
container: portalContainer,
|
|
6251
|
+
"data-ohw-link-popover-root": "",
|
|
6252
|
+
"data-ohw-link-modal-root": "",
|
|
6253
|
+
"data-ohw-bridge": "",
|
|
6254
|
+
showCloseButton: false,
|
|
6255
|
+
className: "gap-0 p-0 w-full max-w-[448px] pointer-events-auto z-[2147483646] overflow-visible",
|
|
6256
|
+
children: /* @__PURE__ */ jsx21(LinkEditorPanel, { state, onClose })
|
|
6257
|
+
}
|
|
6258
|
+
)
|
|
5566
6259
|
}
|
|
5567
|
-
)
|
|
5568
|
-
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
UrlOrPageInput,
|
|
5578
|
-
{
|
|
5579
|
-
value: state.searchValue,
|
|
5580
|
-
selectedPage: state.selectedPage,
|
|
5581
|
-
dropdownOpen: state.dropdownOpen,
|
|
5582
|
-
onDropdownOpenChange: state.setDropdownOpen,
|
|
5583
|
-
filteredPages: state.filteredPages,
|
|
5584
|
-
onInputChange: state.handleInputChange,
|
|
5585
|
-
onPageSelect: state.handlePageSelect,
|
|
5586
|
-
urlError: state.urlError
|
|
5587
|
-
}
|
|
5588
|
-
),
|
|
5589
|
-
state.showChooseSection ? /* @__PURE__ */ jsxs11("div", { className: "flex flex-col justify-center gap-2", children: [
|
|
5590
|
-
/* @__PURE__ */ jsx19(Button, { type: "button", variant: "outline", className: "w-fit cursor-pointer", size: "sm", onClick: state.handleChooseSection, children: "Choose a section" }),
|
|
5591
|
-
/* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
|
|
5592
|
-
/* @__PURE__ */ jsx19(IconInfo, { className: "shrink-0", "aria-hidden": true }),
|
|
5593
|
-
/* @__PURE__ */ jsx19("span", { children: "Pick a section this link should scroll to." })
|
|
5594
|
-
] })
|
|
5595
|
-
] }) : null,
|
|
5596
|
-
state.showSectionPicker ? /* @__PURE__ */ jsx19(SectionPickerList, { sections: state.activeSections, onSelect: state.handleSectionSelect }) : null,
|
|
5597
|
-
state.showSectionRow && state.selectedSection ? /* @__PURE__ */ jsx19(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
|
|
5598
|
-
] }),
|
|
5599
|
-
/* @__PURE__ */ jsxs11(DialogFooter, { className: "w-full px-6 pb-6", children: [
|
|
5600
|
-
/* @__PURE__ */ jsx19(
|
|
5601
|
-
Button,
|
|
5602
|
-
{
|
|
5603
|
-
type: "button",
|
|
5604
|
-
variant: isCancel ? "outline" : "ghost",
|
|
5605
|
-
className: "leading-6 shadow-none cursor-pointer",
|
|
5606
|
-
style: isCancel ? {
|
|
5607
|
-
backgroundColor: "var(--ohw-background)",
|
|
5608
|
-
borderColor: "var(--ohw-border)",
|
|
5609
|
-
color: "var(--ohw-foreground)"
|
|
5610
|
-
} : void 0,
|
|
5611
|
-
onClick: state.handleSecondary,
|
|
5612
|
-
children: state.secondaryLabel
|
|
5613
|
-
}
|
|
5614
|
-
),
|
|
5615
|
-
/* @__PURE__ */ jsx19(
|
|
5616
|
-
Button,
|
|
5617
|
-
{
|
|
5618
|
-
type: "button",
|
|
5619
|
-
className: "border-0 leading-6 shadow-none hover:opacity-90 disabled:opacity-50 cursor-pointer",
|
|
5620
|
-
style: {
|
|
5621
|
-
backgroundColor: "var(--ohw-primary)",
|
|
5622
|
-
color: "var(--ohw-primary-foreground)"
|
|
5623
|
-
},
|
|
5624
|
-
disabled: !state.isValid,
|
|
5625
|
-
onClick: state.handleSubmit,
|
|
5626
|
-
children: state.submitLabel
|
|
5627
|
-
}
|
|
5628
|
-
)
|
|
5629
|
-
] })
|
|
6260
|
+
),
|
|
6261
|
+
sectionPickerActive && state.selectedPage ? /* @__PURE__ */ jsx21(
|
|
6262
|
+
SectionPickerOverlay,
|
|
6263
|
+
{
|
|
6264
|
+
pagePath: state.selectedPage.path,
|
|
6265
|
+
sections: state.activeSections,
|
|
6266
|
+
onBack: state.handleSectionPickerBack,
|
|
6267
|
+
onSelect: state.handleSectionSelect
|
|
6268
|
+
}
|
|
6269
|
+
) : null
|
|
5630
6270
|
] });
|
|
5631
6271
|
}
|
|
5632
6272
|
|
|
5633
|
-
// src/ui/link-modal/LinkPopover.tsx
|
|
5634
|
-
import { jsx as jsx20 } from "react/jsx-runtime";
|
|
5635
|
-
function LinkPopover({
|
|
5636
|
-
open = true,
|
|
5637
|
-
panelRef,
|
|
5638
|
-
portalContainer,
|
|
5639
|
-
onClose,
|
|
5640
|
-
...editorProps
|
|
5641
|
-
}) {
|
|
5642
|
-
return /* @__PURE__ */ jsx20(
|
|
5643
|
-
Dialog2,
|
|
5644
|
-
{
|
|
5645
|
-
open,
|
|
5646
|
-
onOpenChange: (next) => {
|
|
5647
|
-
if (!next) onClose?.();
|
|
5648
|
-
},
|
|
5649
|
-
children: /* @__PURE__ */ jsx20(
|
|
5650
|
-
DialogContent,
|
|
5651
|
-
{
|
|
5652
|
-
ref: panelRef,
|
|
5653
|
-
container: portalContainer,
|
|
5654
|
-
"data-ohw-link-popover-root": "",
|
|
5655
|
-
"data-ohw-link-modal-root": "",
|
|
5656
|
-
"data-ohw-bridge": "",
|
|
5657
|
-
showCloseButton: false,
|
|
5658
|
-
className: "gap-0 p-0 w-full md:w-md pointer-events-auto",
|
|
5659
|
-
children: /* @__PURE__ */ jsx20(LinkEditorPanel, { ...editorProps, open, onClose })
|
|
5660
|
-
}
|
|
5661
|
-
)
|
|
5662
|
-
}
|
|
5663
|
-
);
|
|
5664
|
-
}
|
|
5665
|
-
|
|
5666
6273
|
// src/ui/link-modal/devFixtures.ts
|
|
5667
6274
|
var DEV_SITE_PAGES = [
|
|
5668
6275
|
{ path: "/", title: "Home" },
|
|
@@ -5682,16 +6289,21 @@ var DEV_SECTIONS_BY_PATH = {
|
|
|
5682
6289
|
{ id: "founder-teaser", label: "Founder" },
|
|
5683
6290
|
{ id: "plan-form", label: "Plan Form" },
|
|
5684
6291
|
{ id: "testimonials", label: "Testimonials" },
|
|
5685
|
-
{ id: "wordmark", label: "Wordmark" }
|
|
6292
|
+
{ id: "wordmark", label: "Wordmark" },
|
|
6293
|
+
{ id: "footer", label: "Footer" }
|
|
5686
6294
|
],
|
|
5687
6295
|
"/about": [
|
|
5688
6296
|
{ id: "manifesto", label: "Manifesto" },
|
|
5689
6297
|
{ id: "story-letter", label: "Our Story" },
|
|
5690
6298
|
{ id: "lagree-explainer", label: "Lagree Explainer" },
|
|
5691
6299
|
{ id: "waitlist-cta", label: "Waitlist" },
|
|
5692
|
-
{ id: "personal-training", label: "Personal training" }
|
|
6300
|
+
{ id: "personal-training", label: "Personal training" },
|
|
6301
|
+
{ id: "footer", label: "Footer" }
|
|
6302
|
+
],
|
|
6303
|
+
"/classes": [
|
|
6304
|
+
{ id: "class-library", label: "Class Library" },
|
|
6305
|
+
{ id: "footer", label: "Footer" }
|
|
5693
6306
|
],
|
|
5694
|
-
"/classes": [{ id: "class-library", label: "Class Library" }],
|
|
5695
6307
|
"/pricing": [
|
|
5696
6308
|
{ id: "page-header", label: "Page Header" },
|
|
5697
6309
|
{ id: "free-class-cta", label: "Free Class" },
|
|
@@ -5699,19 +6311,25 @@ var DEV_SECTIONS_BY_PATH = {
|
|
|
5699
6311
|
{ id: "monthly-memberships", label: "Memberships" },
|
|
5700
6312
|
{ id: "specialty-programs", label: "Specialty Programs" },
|
|
5701
6313
|
{ id: "package-matcher", label: "Packages" },
|
|
5702
|
-
{ id: "wordmark", label: "Wordmark" }
|
|
6314
|
+
{ id: "wordmark", label: "Wordmark" },
|
|
6315
|
+
{ id: "footer", label: "Footer" }
|
|
5703
6316
|
],
|
|
5704
6317
|
"/studio": [
|
|
5705
6318
|
{ id: "studio-intro", label: "Studio Intro" },
|
|
5706
6319
|
{ id: "studio-features", label: "Studio Features" },
|
|
5707
6320
|
{ id: "studio-gallery", label: "Studio Gallery" },
|
|
5708
|
-
{ id: "studio-visit", label: "Visit Studio" }
|
|
6321
|
+
{ id: "studio-visit", label: "Visit Studio" },
|
|
6322
|
+
{ id: "footer", label: "Footer" }
|
|
6323
|
+
],
|
|
6324
|
+
"/instructors": [
|
|
6325
|
+
{ id: "instructor-grid", label: "Instructors" },
|
|
6326
|
+
{ id: "footer", label: "Footer" }
|
|
5709
6327
|
],
|
|
5710
|
-
"/instructors": [{ id: "instructor-grid", label: "Instructors" }],
|
|
5711
6328
|
"/contact": [
|
|
5712
6329
|
{ id: "hello-hero", label: "Hello" },
|
|
5713
6330
|
{ id: "contact-form", label: "Contact Form" },
|
|
5714
|
-
{ id: "faq", label: "FAQ" }
|
|
6331
|
+
{ id: "faq", label: "FAQ" },
|
|
6332
|
+
{ id: "footer", label: "Footer" }
|
|
5715
6333
|
]
|
|
5716
6334
|
};
|
|
5717
6335
|
function shouldUseDevFixtures() {
|
|
@@ -5721,8 +6339,716 @@ function shouldUseDevFixtures() {
|
|
|
5721
6339
|
return new URLSearchParams(q).get("ohw-fixtures") === "1";
|
|
5722
6340
|
}
|
|
5723
6341
|
|
|
6342
|
+
// src/lib/nav-items.ts
|
|
6343
|
+
var NAV_COUNT_KEY = "__ohw_nav_count";
|
|
6344
|
+
var NAV_ORDER_KEY = "__ohw_nav_order";
|
|
6345
|
+
function getLinkHref(el) {
|
|
6346
|
+
const key = el.getAttribute("data-ohw-href-key");
|
|
6347
|
+
if (key) {
|
|
6348
|
+
const stored = getStoredLinkHref(key);
|
|
6349
|
+
if (stored !== void 0) return stored;
|
|
6350
|
+
}
|
|
6351
|
+
return el.getAttribute("href") ?? "";
|
|
6352
|
+
}
|
|
6353
|
+
function isNavbarButton(el) {
|
|
6354
|
+
return el.hasAttribute("data-ohw-role") && el.getAttribute("data-ohw-role") === "navbar-button";
|
|
6355
|
+
}
|
|
6356
|
+
function isNavbarLinkItem(el) {
|
|
6357
|
+
if (!el.matches("[data-ohw-href-key]")) return false;
|
|
6358
|
+
if (isNavbarButton(el)) return false;
|
|
6359
|
+
if (!el.querySelector('[data-ohw-editable="text"]')) return false;
|
|
6360
|
+
return Boolean(el.closest("nav, [data-ohw-nav-container], [data-ohw-nav-drawer]"));
|
|
6361
|
+
}
|
|
6362
|
+
function getNavbarDesktopContainer() {
|
|
6363
|
+
return document.querySelector("[data-ohw-nav-container]");
|
|
6364
|
+
}
|
|
6365
|
+
function getNavbarDrawerContainer() {
|
|
6366
|
+
return document.querySelector("[data-ohw-nav-drawer]");
|
|
6367
|
+
}
|
|
6368
|
+
function listNavbarItems() {
|
|
6369
|
+
const desktop = getNavbarDesktopContainer();
|
|
6370
|
+
if (desktop) {
|
|
6371
|
+
return Array.from(desktop.querySelectorAll("[data-ohw-href-key]")).filter(isNavbarLinkItem);
|
|
6372
|
+
}
|
|
6373
|
+
const drawer = getNavbarDrawerContainer();
|
|
6374
|
+
if (drawer) {
|
|
6375
|
+
return Array.from(drawer.querySelectorAll("[data-ohw-href-key]")).filter(isNavbarLinkItem);
|
|
6376
|
+
}
|
|
6377
|
+
return Array.from(document.querySelectorAll("nav [data-ohw-href-key]")).filter(isNavbarLinkItem);
|
|
6378
|
+
}
|
|
6379
|
+
function parseNavIndexFromKey(key) {
|
|
6380
|
+
if (!key) return null;
|
|
6381
|
+
const match = key.match(/^nav-(\d+)-href$/);
|
|
6382
|
+
if (!match) return null;
|
|
6383
|
+
return parseInt(match[1], 10);
|
|
6384
|
+
}
|
|
6385
|
+
function getNavbarIndicesInDom() {
|
|
6386
|
+
const indices = /* @__PURE__ */ new Set();
|
|
6387
|
+
for (const item of listNavbarItems()) {
|
|
6388
|
+
const idx = parseNavIndexFromKey(item.getAttribute("data-ohw-href-key"));
|
|
6389
|
+
if (idx !== null) indices.add(idx);
|
|
6390
|
+
}
|
|
6391
|
+
return [...indices].sort((a, b) => a - b);
|
|
6392
|
+
}
|
|
6393
|
+
function getNextNavbarIndex() {
|
|
6394
|
+
const indices = getNavbarIndicesInDom();
|
|
6395
|
+
if (indices.length === 0) return 0;
|
|
6396
|
+
return Math.max(...indices) + 1;
|
|
6397
|
+
}
|
|
6398
|
+
function getNavbarExistingTargets() {
|
|
6399
|
+
return listNavbarItems().map((el) => getLinkHref(el)).filter(Boolean);
|
|
6400
|
+
}
|
|
6401
|
+
function getNavOrderFromDom() {
|
|
6402
|
+
return listNavbarItems().map((el) => el.getAttribute("data-ohw-href-key")).filter((key) => Boolean(key));
|
|
6403
|
+
}
|
|
6404
|
+
function parseNavOrder(content) {
|
|
6405
|
+
const raw = content[NAV_ORDER_KEY];
|
|
6406
|
+
if (!raw) return null;
|
|
6407
|
+
try {
|
|
6408
|
+
const parsed = JSON.parse(raw);
|
|
6409
|
+
if (!Array.isArray(parsed)) return null;
|
|
6410
|
+
return parsed.filter((key) => typeof key === "string" && key.length > 0);
|
|
6411
|
+
} catch {
|
|
6412
|
+
return null;
|
|
6413
|
+
}
|
|
6414
|
+
}
|
|
6415
|
+
function findCounterpartByHrefKey(hrefKey, root) {
|
|
6416
|
+
return root.querySelector(`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`);
|
|
6417
|
+
}
|
|
6418
|
+
function cloneNavLinkShell(template) {
|
|
6419
|
+
const anchor = document.createElement("a");
|
|
6420
|
+
if (template) {
|
|
6421
|
+
anchor.style.cssText = template.style.cssText;
|
|
6422
|
+
if (template.className) anchor.className = template.className;
|
|
6423
|
+
}
|
|
6424
|
+
anchor.style.cursor = "pointer";
|
|
6425
|
+
anchor.style.textDecoration = "none";
|
|
6426
|
+
return anchor;
|
|
6427
|
+
}
|
|
6428
|
+
function buildNavLink(index, href, label, template) {
|
|
6429
|
+
const anchor = cloneNavLinkShell(template);
|
|
6430
|
+
anchor.href = href;
|
|
6431
|
+
anchor.setAttribute("data-ohw-href-key", `nav-${index}-href`);
|
|
6432
|
+
const span = document.createElement("span");
|
|
6433
|
+
span.setAttribute("data-ohw-editable", "text");
|
|
6434
|
+
span.setAttribute("data-ohw-key", `nav-${index}-label`);
|
|
6435
|
+
span.textContent = label;
|
|
6436
|
+
anchor.appendChild(span);
|
|
6437
|
+
return anchor;
|
|
6438
|
+
}
|
|
6439
|
+
function insertNavLinkInContainer(container, anchor, afterHrefKey) {
|
|
6440
|
+
if (!afterHrefKey) {
|
|
6441
|
+
container.appendChild(anchor);
|
|
6442
|
+
return;
|
|
6443
|
+
}
|
|
6444
|
+
const afterEl = findCounterpartByHrefKey(afterHrefKey, container);
|
|
6445
|
+
if (afterEl?.parentElement === container) {
|
|
6446
|
+
afterEl.insertAdjacentElement("afterend", anchor);
|
|
6447
|
+
return;
|
|
6448
|
+
}
|
|
6449
|
+
container.appendChild(anchor);
|
|
6450
|
+
}
|
|
6451
|
+
function insertNavbarItemDom(index, href, label, afterAnchor) {
|
|
6452
|
+
const afterHrefKey = afterAnchor?.getAttribute("data-ohw-href-key") ?? null;
|
|
6453
|
+
const desktopItems = getNavbarDesktopContainer()?.querySelectorAll("[data-ohw-href-key]") ?? [];
|
|
6454
|
+
const drawerItems = getNavbarDrawerContainer()?.querySelectorAll("[data-ohw-href-key]") ?? [];
|
|
6455
|
+
const desktopTemplate = Array.from(desktopItems).find(isNavbarLinkItem) ?? null;
|
|
6456
|
+
const drawerTemplate = Array.from(drawerItems).find(isNavbarLinkItem) ?? null;
|
|
6457
|
+
let primary = null;
|
|
6458
|
+
const desktopContainer = getNavbarDesktopContainer();
|
|
6459
|
+
if (desktopContainer) {
|
|
6460
|
+
const desktopAnchor = buildNavLink(index, href, label, desktopTemplate);
|
|
6461
|
+
insertNavLinkInContainer(desktopContainer, desktopAnchor, afterHrefKey);
|
|
6462
|
+
primary = desktopAnchor;
|
|
6463
|
+
}
|
|
6464
|
+
const drawerContainer = getNavbarDrawerContainer();
|
|
6465
|
+
if (drawerContainer) {
|
|
6466
|
+
const drawerAnchor = buildNavLink(index, href, label, drawerTemplate);
|
|
6467
|
+
insertNavLinkInContainer(drawerContainer, drawerAnchor, afterHrefKey);
|
|
6468
|
+
if (!primary) primary = drawerAnchor;
|
|
6469
|
+
}
|
|
6470
|
+
if (!primary) {
|
|
6471
|
+
const fallback = buildNavLink(index, href, label, listNavbarItems()[0] ?? null);
|
|
6472
|
+
const nav = document.querySelector("nav");
|
|
6473
|
+
nav?.appendChild(fallback);
|
|
6474
|
+
primary = fallback;
|
|
6475
|
+
}
|
|
6476
|
+
return primary;
|
|
6477
|
+
}
|
|
6478
|
+
function applyNavOrderToContainer(container, order) {
|
|
6479
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6480
|
+
for (const hrefKey of order) {
|
|
6481
|
+
if (seen.has(hrefKey)) continue;
|
|
6482
|
+
seen.add(hrefKey);
|
|
6483
|
+
const el = findCounterpartByHrefKey(hrefKey, container);
|
|
6484
|
+
if (el) container.appendChild(el);
|
|
6485
|
+
}
|
|
6486
|
+
for (const el of container.querySelectorAll("[data-ohw-href-key]")) {
|
|
6487
|
+
if (!isNavbarLinkItem(el)) continue;
|
|
6488
|
+
const key = el.getAttribute("data-ohw-href-key");
|
|
6489
|
+
if (!key || seen.has(key)) continue;
|
|
6490
|
+
container.appendChild(el);
|
|
6491
|
+
}
|
|
6492
|
+
}
|
|
6493
|
+
function applyNavOrder(order) {
|
|
6494
|
+
const desktop = getNavbarDesktopContainer();
|
|
6495
|
+
if (desktop) applyNavOrderToContainer(desktop, order);
|
|
6496
|
+
const drawer = getNavbarDrawerContainer();
|
|
6497
|
+
if (drawer) applyNavOrderToContainer(drawer, order);
|
|
6498
|
+
}
|
|
6499
|
+
function collectNavbarIndicesFromContent(content) {
|
|
6500
|
+
const indices = /* @__PURE__ */ new Set();
|
|
6501
|
+
for (const key of Object.keys(content)) {
|
|
6502
|
+
const idx = parseNavIndexFromKey(key);
|
|
6503
|
+
if (idx !== null) indices.add(idx);
|
|
6504
|
+
}
|
|
6505
|
+
const countRaw = content[NAV_COUNT_KEY];
|
|
6506
|
+
if (countRaw) {
|
|
6507
|
+
const count = parseInt(countRaw, 10);
|
|
6508
|
+
if (Number.isFinite(count) && count > 0) {
|
|
6509
|
+
for (let i = 0; i < count; i++) indices.add(i);
|
|
6510
|
+
}
|
|
6511
|
+
}
|
|
6512
|
+
return [...indices].sort((a, b) => a - b);
|
|
6513
|
+
}
|
|
6514
|
+
function navbarIndexExistsInDom(index) {
|
|
6515
|
+
return document.querySelector(`[data-ohw-href-key="nav-${index}-href"]`) !== null;
|
|
6516
|
+
}
|
|
6517
|
+
function reconcileNavbarItemsFromContent(content) {
|
|
6518
|
+
const indices = collectNavbarIndicesFromContent(content);
|
|
6519
|
+
for (const index of indices) {
|
|
6520
|
+
if (navbarIndexExistsInDom(index)) continue;
|
|
6521
|
+
const href = content[`nav-${index}-href`];
|
|
6522
|
+
const label = content[`nav-${index}-label`];
|
|
6523
|
+
if (!href && !label) continue;
|
|
6524
|
+
insertNavbarItemDom(index, href ?? "/", label ?? "Untitled", null);
|
|
6525
|
+
}
|
|
6526
|
+
const order = parseNavOrder(content);
|
|
6527
|
+
if (order?.length) applyNavOrder(order);
|
|
6528
|
+
}
|
|
6529
|
+
function buildNavOrderAfterInsert(afterAnchor, newHrefKey) {
|
|
6530
|
+
const order = getNavOrderFromDom();
|
|
6531
|
+
if (!afterAnchor) {
|
|
6532
|
+
if (!order.includes(newHrefKey)) order.push(newHrefKey);
|
|
6533
|
+
return order;
|
|
6534
|
+
}
|
|
6535
|
+
const afterKey = afterAnchor.getAttribute("data-ohw-href-key");
|
|
6536
|
+
if (!afterKey) {
|
|
6537
|
+
if (!order.includes(newHrefKey)) order.push(newHrefKey);
|
|
6538
|
+
return order;
|
|
6539
|
+
}
|
|
6540
|
+
const withoutNew = order.filter((key) => key !== newHrefKey);
|
|
6541
|
+
const pos = withoutNew.indexOf(afterKey);
|
|
6542
|
+
if (pos >= 0) {
|
|
6543
|
+
withoutNew.splice(pos + 1, 0, newHrefKey);
|
|
6544
|
+
return withoutNew;
|
|
6545
|
+
}
|
|
6546
|
+
withoutNew.push(newHrefKey);
|
|
6547
|
+
return withoutNew;
|
|
6548
|
+
}
|
|
6549
|
+
function insertNavbarItem(href, label, afterAnchor = null) {
|
|
6550
|
+
const index = getNextNavbarIndex();
|
|
6551
|
+
const anchor = insertNavbarItemDom(index, href, label, afterAnchor);
|
|
6552
|
+
if (!anchor) throw new Error("Failed to insert navbar item");
|
|
6553
|
+
const hrefKey = `nav-${index}-href`;
|
|
6554
|
+
const order = buildNavOrderAfterInsert(afterAnchor, hrefKey);
|
|
6555
|
+
applyNavOrder(order);
|
|
6556
|
+
return {
|
|
6557
|
+
anchor,
|
|
6558
|
+
index,
|
|
6559
|
+
hrefKey,
|
|
6560
|
+
labelKey: `nav-${index}-label`,
|
|
6561
|
+
href,
|
|
6562
|
+
label,
|
|
6563
|
+
order
|
|
6564
|
+
};
|
|
6565
|
+
}
|
|
6566
|
+
|
|
6567
|
+
// src/lib/footer-items.ts
|
|
6568
|
+
var FOOTER_ORDER_KEY = "__ohw_footer_order";
|
|
6569
|
+
var FOOTER_HREF_RE = /^footer-(\d+)-(\d+)-href$/;
|
|
6570
|
+
function parseFooterHrefKey(key) {
|
|
6571
|
+
if (!key) return null;
|
|
6572
|
+
const match = key.match(FOOTER_HREF_RE);
|
|
6573
|
+
if (!match) return null;
|
|
6574
|
+
return { col: parseInt(match[1], 10), item: parseInt(match[2], 10) };
|
|
6575
|
+
}
|
|
6576
|
+
function isFooterHrefKey(key) {
|
|
6577
|
+
return parseFooterHrefKey(key) !== null;
|
|
6578
|
+
}
|
|
6579
|
+
function getFooterRoot() {
|
|
6580
|
+
return document.querySelector('footer[data-ohw-section="footer"], footer');
|
|
6581
|
+
}
|
|
6582
|
+
function getFooterLinksContainer() {
|
|
6583
|
+
return document.querySelector("[data-ohw-footer-links]") ?? document.querySelector(".rb-footer-links");
|
|
6584
|
+
}
|
|
6585
|
+
function isFooterLinkAnchor(el) {
|
|
6586
|
+
if (!el.matches("[data-ohw-href-key]")) return false;
|
|
6587
|
+
if (!isFooterHrefKey(el.getAttribute("data-ohw-href-key"))) return false;
|
|
6588
|
+
return Boolean(el.querySelector('[data-ohw-editable="text"]'));
|
|
6589
|
+
}
|
|
6590
|
+
function listFooterColumns() {
|
|
6591
|
+
const root = getFooterLinksContainer() ?? getFooterRoot()?.querySelector(".rb-footer-links") ?? null;
|
|
6592
|
+
if (!root) return [];
|
|
6593
|
+
const explicit = Array.from(root.querySelectorAll(":scope > [data-ohw-footer-col]"));
|
|
6594
|
+
if (explicit.length > 0) return explicit;
|
|
6595
|
+
return Array.from(root.children).filter((el) => {
|
|
6596
|
+
if (!(el instanceof HTMLElement)) return false;
|
|
6597
|
+
return Array.from(el.querySelectorAll(":scope > [data-ohw-href-key]")).some(
|
|
6598
|
+
isFooterLinkAnchor
|
|
6599
|
+
);
|
|
6600
|
+
});
|
|
6601
|
+
}
|
|
6602
|
+
function listFooterLinksInColumn(column) {
|
|
6603
|
+
return Array.from(column.querySelectorAll(":scope > [data-ohw-href-key]")).filter(
|
|
6604
|
+
isFooterLinkAnchor
|
|
6605
|
+
);
|
|
6606
|
+
}
|
|
6607
|
+
function findFooterColumnForLink(anchor) {
|
|
6608
|
+
const columns = listFooterColumns();
|
|
6609
|
+
return columns.find((col) => col.contains(anchor)) ?? null;
|
|
6610
|
+
}
|
|
6611
|
+
function getFooterOrderFromDom() {
|
|
6612
|
+
return listFooterColumns().map(
|
|
6613
|
+
(col) => listFooterLinksInColumn(col).map((el) => el.getAttribute("data-ohw-href-key")).filter((key) => Boolean(key))
|
|
6614
|
+
);
|
|
6615
|
+
}
|
|
6616
|
+
function findFooterLinkByKey(hrefKey) {
|
|
6617
|
+
return document.querySelector(
|
|
6618
|
+
`footer [data-ohw-href-key="${CSS.escape(hrefKey)}"]`
|
|
6619
|
+
);
|
|
6620
|
+
}
|
|
6621
|
+
function syncFooterColumnIndices(columns) {
|
|
6622
|
+
columns.forEach((col, index) => {
|
|
6623
|
+
const next = String(index);
|
|
6624
|
+
if (col.getAttribute("data-ohw-footer-col") !== next) {
|
|
6625
|
+
col.setAttribute("data-ohw-footer-col", next);
|
|
6626
|
+
}
|
|
6627
|
+
});
|
|
6628
|
+
}
|
|
6629
|
+
function appendChildIfNeeded(parent, child) {
|
|
6630
|
+
if (parent.lastElementChild !== child) {
|
|
6631
|
+
parent.appendChild(child);
|
|
6632
|
+
}
|
|
6633
|
+
}
|
|
6634
|
+
function insertLinkBeforeNext(col, el, nextEl) {
|
|
6635
|
+
if (nextEl) {
|
|
6636
|
+
if (el.nextElementSibling !== nextEl) {
|
|
6637
|
+
col.insertBefore(el, nextEl);
|
|
6638
|
+
}
|
|
6639
|
+
return;
|
|
6640
|
+
}
|
|
6641
|
+
if (col.lastElementChild !== el) {
|
|
6642
|
+
col.appendChild(el);
|
|
6643
|
+
}
|
|
6644
|
+
}
|
|
6645
|
+
function applyFooterOrder(order) {
|
|
6646
|
+
const container = getFooterLinksContainer();
|
|
6647
|
+
if (!container) return;
|
|
6648
|
+
const columns = listFooterColumns();
|
|
6649
|
+
if (columns.length === 0) return;
|
|
6650
|
+
const currentOrder = getFooterOrderFromDom();
|
|
6651
|
+
if (ordersEqual(order, currentOrder)) {
|
|
6652
|
+
syncFooterColumnIndices(columns);
|
|
6653
|
+
return;
|
|
6654
|
+
}
|
|
6655
|
+
const colCount = Math.max(columns.length, order.length);
|
|
6656
|
+
const working = columns.slice(0, colCount);
|
|
6657
|
+
for (let i = 0; i < order.length && i < working.length; i++) {
|
|
6658
|
+
appendChildIfNeeded(container, working[i]);
|
|
6659
|
+
}
|
|
6660
|
+
for (let i = order.length; i < working.length; i++) {
|
|
6661
|
+
appendChildIfNeeded(container, working[i]);
|
|
6662
|
+
}
|
|
6663
|
+
const freshColumns = listFooterColumns();
|
|
6664
|
+
syncFooterColumnIndices(freshColumns);
|
|
6665
|
+
for (let c = 0; c < order.length; c++) {
|
|
6666
|
+
const col = freshColumns[c];
|
|
6667
|
+
if (!col) continue;
|
|
6668
|
+
const colOrder = order[c];
|
|
6669
|
+
for (let j = 0; j < colOrder.length; j++) {
|
|
6670
|
+
const hrefKey = colOrder[j];
|
|
6671
|
+
const el = findFooterLinkByKey(hrefKey);
|
|
6672
|
+
if (!el) continue;
|
|
6673
|
+
if (el.parentElement !== col) {
|
|
6674
|
+
col.appendChild(el);
|
|
6675
|
+
}
|
|
6676
|
+
const nextKey = colOrder[j + 1];
|
|
6677
|
+
const nextEl = nextKey ? findFooterLinkByKey(nextKey) : null;
|
|
6678
|
+
insertLinkBeforeNext(col, el, nextEl?.parentElement === col ? nextEl : null);
|
|
6679
|
+
}
|
|
6680
|
+
}
|
|
6681
|
+
}
|
|
6682
|
+
function ordersEqual(a, b) {
|
|
6683
|
+
if (a.length !== b.length) return false;
|
|
6684
|
+
for (let i = 0; i < a.length; i++) {
|
|
6685
|
+
const left = a[i];
|
|
6686
|
+
const right = b[i];
|
|
6687
|
+
if (left.length !== right.length) return false;
|
|
6688
|
+
for (let j = 0; j < left.length; j++) {
|
|
6689
|
+
if (left[j] !== right[j]) return false;
|
|
6690
|
+
}
|
|
6691
|
+
}
|
|
6692
|
+
return true;
|
|
6693
|
+
}
|
|
6694
|
+
function planFooterLinkMove(hrefKey, targetColIndex, insertIndex) {
|
|
6695
|
+
const order = getFooterOrderFromDom();
|
|
6696
|
+
if (targetColIndex < 0 || targetColIndex >= order.length) return null;
|
|
6697
|
+
let fromCol = -1;
|
|
6698
|
+
let fromIdx = -1;
|
|
6699
|
+
for (let c = 0; c < order.length; c++) {
|
|
6700
|
+
const idx = order[c].indexOf(hrefKey);
|
|
6701
|
+
if (idx >= 0) {
|
|
6702
|
+
fromCol = c;
|
|
6703
|
+
fromIdx = idx;
|
|
6704
|
+
break;
|
|
6705
|
+
}
|
|
6706
|
+
}
|
|
6707
|
+
if (fromCol < 0) return null;
|
|
6708
|
+
const next = order.map((col) => [...col]);
|
|
6709
|
+
next[fromCol].splice(fromIdx, 1);
|
|
6710
|
+
let adjusted = insertIndex;
|
|
6711
|
+
if (fromCol === targetColIndex && fromIdx < insertIndex) adjusted -= 1;
|
|
6712
|
+
adjusted = Math.max(0, Math.min(adjusted, next[targetColIndex].length));
|
|
6713
|
+
next[targetColIndex].splice(adjusted, 0, hrefKey);
|
|
6714
|
+
if (ordersEqual(next, order)) return null;
|
|
6715
|
+
return next;
|
|
6716
|
+
}
|
|
6717
|
+
function planFooterColumnMove(fromIndex, toIndex) {
|
|
6718
|
+
const order = getFooterOrderFromDom();
|
|
6719
|
+
const columns = listFooterColumns();
|
|
6720
|
+
if (fromIndex < 0 || fromIndex >= columns.length || toIndex < 0 || toIndex > columns.length) {
|
|
6721
|
+
return null;
|
|
6722
|
+
}
|
|
6723
|
+
if (toIndex === fromIndex || toIndex === fromIndex + 1) return null;
|
|
6724
|
+
const nextOrder = order.map((col) => [...col]);
|
|
6725
|
+
const [movedOrder] = nextOrder.splice(fromIndex, 1);
|
|
6726
|
+
if (!movedOrder) return null;
|
|
6727
|
+
let adjusted = toIndex;
|
|
6728
|
+
if (fromIndex < toIndex) adjusted -= 1;
|
|
6729
|
+
adjusted = Math.max(0, Math.min(adjusted, nextOrder.length));
|
|
6730
|
+
nextOrder.splice(adjusted, 0, movedOrder);
|
|
6731
|
+
if (ordersEqual(nextOrder, order)) return null;
|
|
6732
|
+
return nextOrder;
|
|
6733
|
+
}
|
|
6734
|
+
function parseFooterOrder(content) {
|
|
6735
|
+
const raw = content[FOOTER_ORDER_KEY];
|
|
6736
|
+
if (!raw) return null;
|
|
6737
|
+
try {
|
|
6738
|
+
const parsed = JSON.parse(raw);
|
|
6739
|
+
if (!Array.isArray(parsed)) return null;
|
|
6740
|
+
return parsed.filter((col) => Array.isArray(col)).map((col) => col.filter((key) => typeof key === "string" && key.length > 0));
|
|
6741
|
+
} catch {
|
|
6742
|
+
return null;
|
|
6743
|
+
}
|
|
6744
|
+
}
|
|
6745
|
+
function reconcileFooterOrderFromContent(content) {
|
|
6746
|
+
const order = parseFooterOrder(content);
|
|
6747
|
+
if (!order?.length) return;
|
|
6748
|
+
const current = getFooterOrderFromDom();
|
|
6749
|
+
if (ordersEqual(order, current)) {
|
|
6750
|
+
syncFooterColumnIndices(listFooterColumns());
|
|
6751
|
+
return;
|
|
6752
|
+
}
|
|
6753
|
+
applyFooterOrder(order);
|
|
6754
|
+
}
|
|
6755
|
+
function buildLinkDropSlots(column, columnIndex) {
|
|
6756
|
+
const links = listFooterLinksInColumn(column);
|
|
6757
|
+
const colRect = column.getBoundingClientRect();
|
|
6758
|
+
const slots = [];
|
|
6759
|
+
const barThickness = 3;
|
|
6760
|
+
if (links.length === 0) {
|
|
6761
|
+
slots.push({
|
|
6762
|
+
insertIndex: 0,
|
|
6763
|
+
columnIndex,
|
|
6764
|
+
left: colRect.left,
|
|
6765
|
+
top: colRect.top + colRect.height / 2 - barThickness / 2,
|
|
6766
|
+
width: colRect.width,
|
|
6767
|
+
height: barThickness,
|
|
6768
|
+
direction: "horizontal"
|
|
6769
|
+
});
|
|
6770
|
+
return slots;
|
|
6771
|
+
}
|
|
6772
|
+
for (let i = 0; i <= links.length; i++) {
|
|
6773
|
+
let top;
|
|
6774
|
+
if (i === 0) {
|
|
6775
|
+
top = links[0].getBoundingClientRect().top - barThickness / 2;
|
|
6776
|
+
} else if (i === links.length) {
|
|
6777
|
+
const last = links[links.length - 1].getBoundingClientRect();
|
|
6778
|
+
top = last.bottom - barThickness / 2;
|
|
6779
|
+
} else {
|
|
6780
|
+
const prev = links[i - 1].getBoundingClientRect();
|
|
6781
|
+
const next = links[i].getBoundingClientRect();
|
|
6782
|
+
top = (prev.bottom + next.top) / 2 - barThickness / 2;
|
|
6783
|
+
}
|
|
6784
|
+
const widthRef = i === 0 ? links[0].getBoundingClientRect() : i === links.length ? links[links.length - 1].getBoundingClientRect() : links[i].getBoundingClientRect();
|
|
6785
|
+
slots.push({
|
|
6786
|
+
insertIndex: i,
|
|
6787
|
+
columnIndex,
|
|
6788
|
+
left: widthRef.left,
|
|
6789
|
+
top,
|
|
6790
|
+
width: Math.max(widthRef.width, colRect.width * 0.8),
|
|
6791
|
+
height: barThickness,
|
|
6792
|
+
direction: "horizontal"
|
|
6793
|
+
});
|
|
6794
|
+
}
|
|
6795
|
+
return slots;
|
|
6796
|
+
}
|
|
6797
|
+
function buildColumnDropSlots() {
|
|
6798
|
+
const columns = listFooterColumns();
|
|
6799
|
+
const slots = [];
|
|
6800
|
+
const barThickness = 3;
|
|
6801
|
+
if (columns.length === 0) return slots;
|
|
6802
|
+
for (let i = 0; i <= columns.length; i++) {
|
|
6803
|
+
let left;
|
|
6804
|
+
let height;
|
|
6805
|
+
let top;
|
|
6806
|
+
if (i === 0) {
|
|
6807
|
+
const first = columns[0].getBoundingClientRect();
|
|
6808
|
+
left = first.left - barThickness / 2;
|
|
6809
|
+
top = first.top;
|
|
6810
|
+
height = first.height;
|
|
6811
|
+
} else if (i === columns.length) {
|
|
6812
|
+
const last = columns[columns.length - 1].getBoundingClientRect();
|
|
6813
|
+
left = last.right - barThickness / 2;
|
|
6814
|
+
top = last.top;
|
|
6815
|
+
height = last.height;
|
|
6816
|
+
} else {
|
|
6817
|
+
const prev = columns[i - 1].getBoundingClientRect();
|
|
6818
|
+
const next = columns[i].getBoundingClientRect();
|
|
6819
|
+
left = (prev.right + next.left) / 2 - barThickness / 2;
|
|
6820
|
+
top = Math.min(prev.top, next.top);
|
|
6821
|
+
height = Math.max(prev.bottom, next.bottom) - top;
|
|
6822
|
+
}
|
|
6823
|
+
slots.push({
|
|
6824
|
+
insertIndex: i,
|
|
6825
|
+
columnIndex: i,
|
|
6826
|
+
left,
|
|
6827
|
+
top,
|
|
6828
|
+
width: barThickness,
|
|
6829
|
+
height: Math.max(height, 24),
|
|
6830
|
+
direction: "vertical"
|
|
6831
|
+
});
|
|
6832
|
+
}
|
|
6833
|
+
return slots;
|
|
6834
|
+
}
|
|
6835
|
+
function hitTestLinkDropSlot(clientX, clientY, draggedHrefKey) {
|
|
6836
|
+
const columns = listFooterColumns();
|
|
6837
|
+
let best = null;
|
|
6838
|
+
for (let c = 0; c < columns.length; c++) {
|
|
6839
|
+
const col = columns[c];
|
|
6840
|
+
const colRect = col.getBoundingClientRect();
|
|
6841
|
+
const inColX = clientX >= colRect.left - 24 && clientX <= colRect.right + 24;
|
|
6842
|
+
if (!inColX) continue;
|
|
6843
|
+
const slots = buildLinkDropSlots(col, c).filter((slot) => {
|
|
6844
|
+
const links = listFooterLinksInColumn(col);
|
|
6845
|
+
const fromIdx = links.findIndex(
|
|
6846
|
+
(el) => el.getAttribute("data-ohw-href-key") === draggedHrefKey
|
|
6847
|
+
);
|
|
6848
|
+
if (fromIdx < 0) return true;
|
|
6849
|
+
if (c === findColumnIndexForKey(draggedHrefKey) && (slot.insertIndex === fromIdx || slot.insertIndex === fromIdx + 1)) {
|
|
6850
|
+
return true;
|
|
6851
|
+
}
|
|
6852
|
+
return true;
|
|
6853
|
+
});
|
|
6854
|
+
for (const slot of slots) {
|
|
6855
|
+
const cy = slot.top + slot.height / 2;
|
|
6856
|
+
const dist = Math.abs(clientY - cy) + (inColX ? 0 : 1e3);
|
|
6857
|
+
if (!best || dist < best.dist) best = { slot, dist };
|
|
6858
|
+
}
|
|
6859
|
+
}
|
|
6860
|
+
return best?.slot ?? null;
|
|
6861
|
+
}
|
|
6862
|
+
function findColumnIndexForKey(hrefKey) {
|
|
6863
|
+
const order = getFooterOrderFromDom();
|
|
6864
|
+
for (let c = 0; c < order.length; c++) {
|
|
6865
|
+
if (order[c].includes(hrefKey)) return c;
|
|
6866
|
+
}
|
|
6867
|
+
return -1;
|
|
6868
|
+
}
|
|
6869
|
+
function hitTestColumnDropSlot(clientX, _clientY) {
|
|
6870
|
+
const slots = buildColumnDropSlots();
|
|
6871
|
+
let best = null;
|
|
6872
|
+
for (const slot of slots) {
|
|
6873
|
+
const cx2 = slot.left + slot.width / 2;
|
|
6874
|
+
const dist = Math.abs(clientX - cx2);
|
|
6875
|
+
if (!best || dist < best.dist) best = { slot, dist };
|
|
6876
|
+
}
|
|
6877
|
+
return best?.slot ?? null;
|
|
6878
|
+
}
|
|
6879
|
+
|
|
6880
|
+
// src/lib/carousel.ts
|
|
6881
|
+
import { useEffect as useEffect7, useState as useState6 } from "react";
|
|
6882
|
+
var CAROUSEL_ATTR = "data-ohw-carousel";
|
|
6883
|
+
var CAROUSEL_VALUE_ATTR = "data-ohw-carousel-value";
|
|
6884
|
+
var CAROUSEL_SLIDE_ATTR = "data-ohw-carousel-slide";
|
|
6885
|
+
var CAROUSEL_EVENT = "ohw:carousel-change";
|
|
6886
|
+
function listCarouselKeys() {
|
|
6887
|
+
const keys = /* @__PURE__ */ new Set();
|
|
6888
|
+
document.querySelectorAll(`[${CAROUSEL_ATTR}]`).forEach((el) => {
|
|
6889
|
+
const key = el.getAttribute("data-ohw-key");
|
|
6890
|
+
if (key) keys.add(key);
|
|
6891
|
+
});
|
|
6892
|
+
return [...keys];
|
|
6893
|
+
}
|
|
6894
|
+
function containersForKey(key) {
|
|
6895
|
+
return Array.from(
|
|
6896
|
+
document.querySelectorAll(`[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`)
|
|
6897
|
+
);
|
|
6898
|
+
}
|
|
6899
|
+
function isCarouselKey(key) {
|
|
6900
|
+
return containersForKey(key).length > 0;
|
|
6901
|
+
}
|
|
6902
|
+
function parseSlides(raw) {
|
|
6903
|
+
if (!raw) return [];
|
|
6904
|
+
try {
|
|
6905
|
+
const parsed = JSON.parse(raw);
|
|
6906
|
+
if (!Array.isArray(parsed)) return [];
|
|
6907
|
+
return parsed.filter((s) => Boolean(s) && typeof s === "object").map((s) => ({ src: String(s.src ?? ""), alt: String(s.alt ?? "") }));
|
|
6908
|
+
} catch {
|
|
6909
|
+
return [];
|
|
6910
|
+
}
|
|
6911
|
+
}
|
|
6912
|
+
function readCarouselValue(key) {
|
|
6913
|
+
const container = containersForKey(key)[0];
|
|
6914
|
+
if (!container) return [];
|
|
6915
|
+
const fromAttr = parseSlides(container.getAttribute(CAROUSEL_VALUE_ATTR));
|
|
6916
|
+
if (fromAttr.length > 0) return fromAttr;
|
|
6917
|
+
return Array.from(container.querySelectorAll(`[${CAROUSEL_SLIDE_ATTR}]`)).filter((slide) => slide.closest(`[${CAROUSEL_ATTR}]`) === container).sort((a, b) => slideIndex(a) - slideIndex(b)).map((slide) => {
|
|
6918
|
+
const img = slide instanceof HTMLImageElement ? slide : slide.querySelector("img");
|
|
6919
|
+
return { src: img?.src ?? "", alt: img?.alt ?? "" };
|
|
6920
|
+
});
|
|
6921
|
+
}
|
|
6922
|
+
function slideIndex(el) {
|
|
6923
|
+
const raw = el.getAttribute(CAROUSEL_SLIDE_ATTR);
|
|
6924
|
+
const n = raw ? parseInt(raw, 10) : NaN;
|
|
6925
|
+
return Number.isFinite(n) ? n : 0;
|
|
6926
|
+
}
|
|
6927
|
+
function applyCarouselValue(key, slides) {
|
|
6928
|
+
const value = JSON.stringify(slides);
|
|
6929
|
+
for (const container of containersForKey(key)) {
|
|
6930
|
+
if (container.getAttribute(CAROUSEL_VALUE_ATTR) === value) continue;
|
|
6931
|
+
container.setAttribute(CAROUSEL_VALUE_ATTR, value);
|
|
6932
|
+
container.dispatchEvent(
|
|
6933
|
+
new CustomEvent(CAROUSEL_EVENT, { detail: { images: slides } })
|
|
6934
|
+
);
|
|
6935
|
+
}
|
|
6936
|
+
}
|
|
6937
|
+
function applyCarouselNode(key, val) {
|
|
6938
|
+
if (!isCarouselKey(key)) return false;
|
|
6939
|
+
applyCarouselValue(key, parseSlides(val));
|
|
6940
|
+
return true;
|
|
6941
|
+
}
|
|
6942
|
+
function useOhwCarousel(key, initial) {
|
|
6943
|
+
const [images, setImages] = useState6(initial);
|
|
6944
|
+
useEffect7(() => {
|
|
6945
|
+
const el = document.querySelector(
|
|
6946
|
+
`[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`
|
|
6947
|
+
);
|
|
6948
|
+
if (!el) return;
|
|
6949
|
+
const onChange = (e) => {
|
|
6950
|
+
const detail = e.detail;
|
|
6951
|
+
if (Array.isArray(detail?.images)) setImages(detail.images);
|
|
6952
|
+
};
|
|
6953
|
+
el.addEventListener(CAROUSEL_EVENT, onChange);
|
|
6954
|
+
return () => el.removeEventListener(CAROUSEL_EVENT, onChange);
|
|
6955
|
+
}, [key]);
|
|
6956
|
+
const bind = {
|
|
6957
|
+
[CAROUSEL_ATTR]: "",
|
|
6958
|
+
"data-ohw-key": key,
|
|
6959
|
+
[CAROUSEL_VALUE_ATTR]: JSON.stringify(images)
|
|
6960
|
+
};
|
|
6961
|
+
return { images, setImages, bind };
|
|
6962
|
+
}
|
|
6963
|
+
|
|
6964
|
+
// src/ui/navbar-container-chrome.tsx
|
|
6965
|
+
import { Plus as Plus2 } from "lucide-react";
|
|
6966
|
+
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
6967
|
+
function NavbarContainerChrome({
|
|
6968
|
+
rect,
|
|
6969
|
+
onAdd
|
|
6970
|
+
}) {
|
|
6971
|
+
const chromeGap = 6;
|
|
6972
|
+
return /* @__PURE__ */ jsx22(
|
|
6973
|
+
"div",
|
|
6974
|
+
{
|
|
6975
|
+
"data-ohw-navbar-container-chrome": "",
|
|
6976
|
+
"data-ohw-bridge": "",
|
|
6977
|
+
className: "pointer-events-none fixed z-[2147483647]",
|
|
6978
|
+
style: {
|
|
6979
|
+
top: rect.top - chromeGap,
|
|
6980
|
+
left: rect.left - chromeGap,
|
|
6981
|
+
width: rect.width + chromeGap * 2,
|
|
6982
|
+
height: rect.height + chromeGap * 2
|
|
6983
|
+
},
|
|
6984
|
+
children: /* @__PURE__ */ jsx22(
|
|
6985
|
+
"button",
|
|
6986
|
+
{
|
|
6987
|
+
type: "button",
|
|
6988
|
+
"data-ohw-navbar-add-button": "",
|
|
6989
|
+
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",
|
|
6990
|
+
style: { top: "70%" },
|
|
6991
|
+
"aria-label": "Add item",
|
|
6992
|
+
onMouseDown: (e) => {
|
|
6993
|
+
e.preventDefault();
|
|
6994
|
+
e.stopPropagation();
|
|
6995
|
+
},
|
|
6996
|
+
onClick: (e) => {
|
|
6997
|
+
e.preventDefault();
|
|
6998
|
+
e.stopPropagation();
|
|
6999
|
+
onAdd();
|
|
7000
|
+
},
|
|
7001
|
+
children: /* @__PURE__ */ jsx22(Plus2, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
|
|
7002
|
+
}
|
|
7003
|
+
)
|
|
7004
|
+
}
|
|
7005
|
+
);
|
|
7006
|
+
}
|
|
7007
|
+
|
|
7008
|
+
// src/ui/drop-indicator.tsx
|
|
7009
|
+
import * as React9 from "react";
|
|
7010
|
+
import { jsx as jsx23 } from "react/jsx-runtime";
|
|
7011
|
+
var dropIndicatorVariants = cva(
|
|
7012
|
+
"ov-gap-line pointer-events-none shrink-0 transition-opacity duration-150",
|
|
7013
|
+
{
|
|
7014
|
+
variants: {
|
|
7015
|
+
direction: {
|
|
7016
|
+
vertical: "h-6 w-[3px]",
|
|
7017
|
+
horizontal: "h-[3px] w-[200px]"
|
|
7018
|
+
},
|
|
7019
|
+
state: {
|
|
7020
|
+
default: "opacity-0",
|
|
7021
|
+
hover: "opacity-100",
|
|
7022
|
+
dragIdle: "opacity-40",
|
|
7023
|
+
dragActive: "opacity-100"
|
|
7024
|
+
}
|
|
7025
|
+
},
|
|
7026
|
+
defaultVariants: {
|
|
7027
|
+
direction: "vertical",
|
|
7028
|
+
state: "default"
|
|
7029
|
+
}
|
|
7030
|
+
}
|
|
7031
|
+
);
|
|
7032
|
+
var DropIndicator = React9.forwardRef(
|
|
7033
|
+
({ className, direction, state, ...props }, ref) => {
|
|
7034
|
+
return /* @__PURE__ */ jsx23(
|
|
7035
|
+
"div",
|
|
7036
|
+
{
|
|
7037
|
+
ref,
|
|
7038
|
+
"data-slot": "drop-indicator",
|
|
7039
|
+
"data-direction": direction ?? "vertical",
|
|
7040
|
+
"data-state": state ?? "default",
|
|
7041
|
+
"aria-hidden": "true",
|
|
7042
|
+
className: cn(dropIndicatorVariants({ direction, state }), className),
|
|
7043
|
+
...props
|
|
7044
|
+
}
|
|
7045
|
+
);
|
|
7046
|
+
}
|
|
7047
|
+
);
|
|
7048
|
+
DropIndicator.displayName = "DropIndicator";
|
|
7049
|
+
|
|
5724
7050
|
// src/ui/badge.tsx
|
|
5725
|
-
import { jsx as
|
|
7051
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
5726
7052
|
var badgeVariants = cva(
|
|
5727
7053
|
"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",
|
|
5728
7054
|
{
|
|
@@ -5740,12 +7066,12 @@ var badgeVariants = cva(
|
|
|
5740
7066
|
}
|
|
5741
7067
|
);
|
|
5742
7068
|
function Badge({ className, variant, ...props }) {
|
|
5743
|
-
return /* @__PURE__ */
|
|
7069
|
+
return /* @__PURE__ */ jsx24("div", { className: cn(badgeVariants({ variant }), className), ...props });
|
|
5744
7070
|
}
|
|
5745
7071
|
|
|
5746
7072
|
// src/OhhwellsBridge.tsx
|
|
5747
7073
|
import { Link as Link2 } from "lucide-react";
|
|
5748
|
-
import { Fragment as
|
|
7074
|
+
import { Fragment as Fragment5, jsx as jsx25, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
5749
7075
|
var PRIMARY2 = "#0885FE";
|
|
5750
7076
|
var IMAGE_FADE_MS = 300;
|
|
5751
7077
|
function runOpacityFade(el, onDone) {
|
|
@@ -5924,7 +7250,7 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
5924
7250
|
const root = createRoot(container);
|
|
5925
7251
|
flushSync(() => {
|
|
5926
7252
|
root.render(
|
|
5927
|
-
/* @__PURE__ */
|
|
7253
|
+
/* @__PURE__ */ jsx25(
|
|
5928
7254
|
SchedulingWidget,
|
|
5929
7255
|
{
|
|
5930
7256
|
notifyOnConnect,
|
|
@@ -5964,7 +7290,7 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
|
|
|
5964
7290
|
}
|
|
5965
7291
|
}
|
|
5966
7292
|
}
|
|
5967
|
-
function
|
|
7293
|
+
function getLinkHref2(el) {
|
|
5968
7294
|
const anchor = el instanceof HTMLAnchorElement ? el : el.querySelector("a");
|
|
5969
7295
|
return anchor?.getAttribute("href") ?? "";
|
|
5970
7296
|
}
|
|
@@ -5986,7 +7312,7 @@ function isDragHandleDisabled(el) {
|
|
|
5986
7312
|
return raw === "true" || raw === "";
|
|
5987
7313
|
});
|
|
5988
7314
|
}
|
|
5989
|
-
function collectEditableNodes() {
|
|
7315
|
+
function collectEditableNodes(extraContent) {
|
|
5990
7316
|
const nodes = Array.from(document.querySelectorAll("[data-ohw-editable]")).map((el) => {
|
|
5991
7317
|
if (el.dataset.ohwEditable === "image") {
|
|
5992
7318
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
@@ -6001,7 +7327,7 @@ function collectEditableNodes() {
|
|
|
6001
7327
|
return { key: el.dataset.ohwKey ?? "", type: "video", text: getVideoEl(el)?.src ?? "" };
|
|
6002
7328
|
}
|
|
6003
7329
|
if (el.dataset.ohwEditable === "link") {
|
|
6004
|
-
return { key: el.dataset.ohwKey ?? "", type: "link", text:
|
|
7330
|
+
return { key: el.dataset.ohwKey ?? "", type: "link", text: getLinkHref2(el) };
|
|
6005
7331
|
}
|
|
6006
7332
|
return {
|
|
6007
7333
|
key: el.dataset.ohwKey ?? "",
|
|
@@ -6012,8 +7338,16 @@ function collectEditableNodes() {
|
|
|
6012
7338
|
document.querySelectorAll("[data-ohw-href-key]").forEach((el) => {
|
|
6013
7339
|
const key = el.getAttribute("data-ohw-href-key") ?? "";
|
|
6014
7340
|
if (!key) return;
|
|
6015
|
-
nodes.push({ key, type: "link", text:
|
|
7341
|
+
nodes.push({ key, type: "link", text: getLinkHref2(el) });
|
|
6016
7342
|
});
|
|
7343
|
+
if (extraContent) {
|
|
7344
|
+
for (const key of [NAV_ORDER_KEY, FOOTER_ORDER_KEY, NAV_COUNT_KEY]) {
|
|
7345
|
+
const text = extraContent[key];
|
|
7346
|
+
if (typeof text === "string" && text.length > 0) {
|
|
7347
|
+
nodes.push({ key, type: "meta", text });
|
|
7348
|
+
}
|
|
7349
|
+
}
|
|
7350
|
+
}
|
|
6017
7351
|
document.querySelectorAll('[data-ohw-editable="video"]').forEach((el) => {
|
|
6018
7352
|
const key = el.dataset.ohwKey ?? "";
|
|
6019
7353
|
const video = getVideoEl(el);
|
|
@@ -6021,6 +7355,9 @@ function collectEditableNodes() {
|
|
|
6021
7355
|
nodes.push({ key: `${key}${VIDEO_AUTOPLAY_SUFFIX}`, type: "video-setting", text: String(video.autoplay) });
|
|
6022
7356
|
nodes.push({ key: `${key}${VIDEO_MUTED_SUFFIX}`, type: "video-setting", text: String(video.muted) });
|
|
6023
7357
|
});
|
|
7358
|
+
for (const key of listCarouselKeys()) {
|
|
7359
|
+
nodes.push({ key, type: "carousel", text: JSON.stringify(readCarouselValue(key)) });
|
|
7360
|
+
}
|
|
6024
7361
|
return nodes;
|
|
6025
7362
|
}
|
|
6026
7363
|
function isMediaEditable(el) {
|
|
@@ -6098,7 +7435,7 @@ function applyLinkByKey(key, val) {
|
|
|
6098
7435
|
}
|
|
6099
7436
|
function isInsideLinkEditor(target) {
|
|
6100
7437
|
return Boolean(
|
|
6101
|
-
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"]')
|
|
7438
|
+
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"]')
|
|
6102
7439
|
);
|
|
6103
7440
|
}
|
|
6104
7441
|
function getHrefKeyFromElement(el) {
|
|
@@ -6109,7 +7446,30 @@ function getHrefKeyFromElement(el) {
|
|
|
6109
7446
|
if (!key) return null;
|
|
6110
7447
|
return { anchor, key };
|
|
6111
7448
|
}
|
|
6112
|
-
function
|
|
7449
|
+
function disableNativeHrefDrag(el) {
|
|
7450
|
+
if (el.draggable) el.draggable = false;
|
|
7451
|
+
if (el.getAttribute("draggable") !== "false") {
|
|
7452
|
+
el.setAttribute("draggable", "false");
|
|
7453
|
+
}
|
|
7454
|
+
}
|
|
7455
|
+
function clearTextSelection() {
|
|
7456
|
+
const sel = window.getSelection();
|
|
7457
|
+
if (sel && !sel.isCollapsed) sel.removeAllRanges();
|
|
7458
|
+
}
|
|
7459
|
+
function armFooterPressDrag() {
|
|
7460
|
+
document.documentElement.setAttribute("data-ohw-footer-press-drag", "");
|
|
7461
|
+
}
|
|
7462
|
+
function lockFooterDuringDrag() {
|
|
7463
|
+
document.documentElement.removeAttribute("data-ohw-footer-press-drag");
|
|
7464
|
+
document.documentElement.setAttribute("data-ohw-item-dragging", "");
|
|
7465
|
+
clearTextSelection();
|
|
7466
|
+
}
|
|
7467
|
+
function unlockFooterDragInteraction() {
|
|
7468
|
+
document.documentElement.removeAttribute("data-ohw-footer-press-drag");
|
|
7469
|
+
document.documentElement.removeAttribute("data-ohw-item-dragging");
|
|
7470
|
+
clearTextSelection();
|
|
7471
|
+
}
|
|
7472
|
+
function isNavbarButton2(el) {
|
|
6113
7473
|
return Boolean(el.closest('[data-ohw-role="navbar-button"]'));
|
|
6114
7474
|
}
|
|
6115
7475
|
function getNavigationItemAnchor(el) {
|
|
@@ -6121,19 +7481,8 @@ function getNavigationItemAnchor(el) {
|
|
|
6121
7481
|
function isNavigationItem(el) {
|
|
6122
7482
|
return getNavigationItemAnchor(el) !== null;
|
|
6123
7483
|
}
|
|
6124
|
-
function getNavigationItemAddHintTarget(anchor) {
|
|
6125
|
-
const items = listNavigationItems();
|
|
6126
|
-
const idx = items.indexOf(anchor);
|
|
6127
|
-
if (idx >= 0 && idx < items.length - 1) return items[idx + 1];
|
|
6128
|
-
return anchor;
|
|
6129
|
-
}
|
|
6130
|
-
function listNavigationItems() {
|
|
6131
|
-
return Array.from(
|
|
6132
|
-
document.querySelectorAll("nav [data-ohw-href-key], footer [data-ohw-href-key]")
|
|
6133
|
-
).filter((el) => isNavigationItem(el));
|
|
6134
|
-
}
|
|
6135
7484
|
function getNavigationItemReorderState(anchor) {
|
|
6136
|
-
if (
|
|
7485
|
+
if (isNavbarButton2(anchor)) return { key: null, disabled: false };
|
|
6137
7486
|
return getReorderHandleStateFromAnchor(anchor);
|
|
6138
7487
|
}
|
|
6139
7488
|
function getReorderHandleState(el) {
|
|
@@ -6155,6 +7504,120 @@ function clearHrefKeyHover(anchor) {
|
|
|
6155
7504
|
function isInsideNavigationItem(el) {
|
|
6156
7505
|
return getNavigationItemAnchor(el) !== null;
|
|
6157
7506
|
}
|
|
7507
|
+
function getNavigationRoot(el) {
|
|
7508
|
+
const explicit = el.closest("[data-ohw-nav-root]");
|
|
7509
|
+
if (explicit) return explicit;
|
|
7510
|
+
return el.closest("nav, footer, aside");
|
|
7511
|
+
}
|
|
7512
|
+
function findFooterItemGroup(item) {
|
|
7513
|
+
const footer = item.closest("footer");
|
|
7514
|
+
if (!footer) return null;
|
|
7515
|
+
let node = item.parentElement;
|
|
7516
|
+
while (node && node !== footer) {
|
|
7517
|
+
const hasDirectNavItems = Array.from(
|
|
7518
|
+
node.querySelectorAll(":scope > [data-ohw-href-key]")
|
|
7519
|
+
).some(isNavigationItem);
|
|
7520
|
+
if (hasDirectNavItems) return node;
|
|
7521
|
+
node = node.parentElement;
|
|
7522
|
+
}
|
|
7523
|
+
return null;
|
|
7524
|
+
}
|
|
7525
|
+
function isNavigationRoot(el) {
|
|
7526
|
+
return el.hasAttribute("data-ohw-nav-root") || el.matches("nav, footer, aside");
|
|
7527
|
+
}
|
|
7528
|
+
function isInferredFooterGroup(el) {
|
|
7529
|
+
const footer = el.closest("footer");
|
|
7530
|
+
if (!footer || el === footer) return false;
|
|
7531
|
+
return Array.from(el.querySelectorAll(":scope > [data-ohw-href-key]")).some(isNavigationItem);
|
|
7532
|
+
}
|
|
7533
|
+
function isNavigationContainer(el) {
|
|
7534
|
+
return el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-footer-col") || isNavigationRoot(el) || isInferredFooterGroup(el);
|
|
7535
|
+
}
|
|
7536
|
+
function isPointOverNavigation(x, y) {
|
|
7537
|
+
const navRoot = document.querySelector("[data-ohw-nav-root]") ?? document.querySelector("nav");
|
|
7538
|
+
if (!navRoot) return false;
|
|
7539
|
+
const r2 = navRoot.getBoundingClientRect();
|
|
7540
|
+
return x >= r2.left && x <= r2.right && y >= r2.top && y <= r2.bottom;
|
|
7541
|
+
}
|
|
7542
|
+
function isPointOverNavItem(container, x, y) {
|
|
7543
|
+
return Array.from(container.querySelectorAll("[data-ohw-href-key]")).some((el) => {
|
|
7544
|
+
if (!isNavigationItem(el) || isNavbarButton2(el)) return false;
|
|
7545
|
+
const itemRect = el.getBoundingClientRect();
|
|
7546
|
+
return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
|
|
7547
|
+
});
|
|
7548
|
+
}
|
|
7549
|
+
function resolveNavContainerSelectionTarget(target, clientX, clientY) {
|
|
7550
|
+
if (getNavigationItemAnchor(target)) return null;
|
|
7551
|
+
if (target.closest('[data-ohw-role="navbar-button"]')) return null;
|
|
7552
|
+
const plainLink = target.closest("a");
|
|
7553
|
+
if (plainLink && !plainLink.hasAttribute("data-ohw-href-key") && !plainLink.closest("[data-ohw-nav-container]")) {
|
|
7554
|
+
return null;
|
|
7555
|
+
}
|
|
7556
|
+
const fromClosest = target.closest("[data-ohw-nav-container]");
|
|
7557
|
+
if (fromClosest && !isPointOverNavItem(fromClosest, clientX, clientY)) {
|
|
7558
|
+
return fromClosest;
|
|
7559
|
+
}
|
|
7560
|
+
const navRoot = target.closest("[data-ohw-nav-root]");
|
|
7561
|
+
if (!navRoot) return null;
|
|
7562
|
+
const container = navRoot.querySelector("[data-ohw-nav-container]");
|
|
7563
|
+
if (!container || isPointOverNavItem(container, clientX, clientY)) return null;
|
|
7564
|
+
if (target === navRoot || target.hasAttribute("data-ohw-nav-root")) {
|
|
7565
|
+
return container;
|
|
7566
|
+
}
|
|
7567
|
+
return null;
|
|
7568
|
+
}
|
|
7569
|
+
function getNavigationSelectionParent(el) {
|
|
7570
|
+
if (isNavigationItem(el)) {
|
|
7571
|
+
const explicit = el.closest("[data-ohw-nav-container]");
|
|
7572
|
+
if (explicit) return explicit;
|
|
7573
|
+
const footerGroup = findFooterItemGroup(el);
|
|
7574
|
+
if (footerGroup) return footerGroup;
|
|
7575
|
+
return getNavigationRoot(el);
|
|
7576
|
+
}
|
|
7577
|
+
if (el.hasAttribute("data-ohw-nav-container") || isInferredFooterGroup(el)) {
|
|
7578
|
+
return getNavigationRoot(el);
|
|
7579
|
+
}
|
|
7580
|
+
return null;
|
|
7581
|
+
}
|
|
7582
|
+
function placeCaretAtPoint(el, x, y) {
|
|
7583
|
+
const selection = window.getSelection();
|
|
7584
|
+
if (!selection) return;
|
|
7585
|
+
if (typeof document.caretRangeFromPoint === "function") {
|
|
7586
|
+
const range = document.caretRangeFromPoint(x, y);
|
|
7587
|
+
if (range && el.contains(range.startContainer)) {
|
|
7588
|
+
selection.removeAllRanges();
|
|
7589
|
+
selection.addRange(range);
|
|
7590
|
+
return;
|
|
7591
|
+
}
|
|
7592
|
+
}
|
|
7593
|
+
const caretPositionFromPoint = document.caretPositionFromPoint;
|
|
7594
|
+
if (typeof caretPositionFromPoint === "function") {
|
|
7595
|
+
const position = caretPositionFromPoint(x, y);
|
|
7596
|
+
if (position && el.contains(position.offsetNode)) {
|
|
7597
|
+
const range = document.createRange();
|
|
7598
|
+
range.setStart(position.offsetNode, position.offset);
|
|
7599
|
+
range.collapse(true);
|
|
7600
|
+
selection.removeAllRanges();
|
|
7601
|
+
selection.addRange(range);
|
|
7602
|
+
}
|
|
7603
|
+
}
|
|
7604
|
+
}
|
|
7605
|
+
function selectAllTextInEditable(el) {
|
|
7606
|
+
const selection = window.getSelection();
|
|
7607
|
+
if (!selection) return;
|
|
7608
|
+
const range = document.createRange();
|
|
7609
|
+
range.selectNodeContents(el);
|
|
7610
|
+
selection.removeAllRanges();
|
|
7611
|
+
selection.addRange(range);
|
|
7612
|
+
}
|
|
7613
|
+
function getNavigationLabelEditable(target) {
|
|
7614
|
+
const editable = target.closest('[data-ohw-editable="text"]');
|
|
7615
|
+
if (!editable) return null;
|
|
7616
|
+
const hrefCtx = getHrefKeyFromElement(editable);
|
|
7617
|
+
const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
|
|
7618
|
+
if (!navAnchor) return null;
|
|
7619
|
+
return { editable, navAnchor };
|
|
7620
|
+
}
|
|
6158
7621
|
function collectSections() {
|
|
6159
7622
|
return collectSectionsFromDom();
|
|
6160
7623
|
}
|
|
@@ -6278,6 +7741,8 @@ var ICONS = {
|
|
|
6278
7741
|
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"/>',
|
|
6279
7742
|
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"/>'
|
|
6280
7743
|
};
|
|
7744
|
+
var TOOLBAR_PILL_PADDING = 2;
|
|
7745
|
+
var TOOLBAR_TOGGLE_GAP = 4;
|
|
6281
7746
|
var TOOLBAR_GROUPS = [
|
|
6282
7747
|
[
|
|
6283
7748
|
{ cmd: "bold", title: "Bold" },
|
|
@@ -6302,7 +7767,7 @@ function EditGlowChrome({
|
|
|
6302
7767
|
dragDisabled = false
|
|
6303
7768
|
}) {
|
|
6304
7769
|
const GAP = 6;
|
|
6305
|
-
return /* @__PURE__ */
|
|
7770
|
+
return /* @__PURE__ */ jsxs14(
|
|
6306
7771
|
"div",
|
|
6307
7772
|
{
|
|
6308
7773
|
ref: elRef,
|
|
@@ -6317,7 +7782,7 @@ function EditGlowChrome({
|
|
|
6317
7782
|
zIndex: 2147483646
|
|
6318
7783
|
},
|
|
6319
7784
|
children: [
|
|
6320
|
-
/* @__PURE__ */
|
|
7785
|
+
/* @__PURE__ */ jsx25(
|
|
6321
7786
|
"div",
|
|
6322
7787
|
{
|
|
6323
7788
|
style: {
|
|
@@ -6330,7 +7795,7 @@ function EditGlowChrome({
|
|
|
6330
7795
|
}
|
|
6331
7796
|
}
|
|
6332
7797
|
),
|
|
6333
|
-
reorderHrefKey && /* @__PURE__ */
|
|
7798
|
+
reorderHrefKey && /* @__PURE__ */ jsx25(
|
|
6334
7799
|
"div",
|
|
6335
7800
|
{
|
|
6336
7801
|
"data-ohw-drag-handle-container": "",
|
|
@@ -6342,7 +7807,7 @@ function EditGlowChrome({
|
|
|
6342
7807
|
transform: "translate(calc(-100% - 7px), -50%)",
|
|
6343
7808
|
pointerEvents: dragDisabled ? "none" : "auto"
|
|
6344
7809
|
},
|
|
6345
|
-
children: /* @__PURE__ */
|
|
7810
|
+
children: /* @__PURE__ */ jsx25(
|
|
6346
7811
|
DragHandle,
|
|
6347
7812
|
{
|
|
6348
7813
|
"aria-label": `Reorder ${reorderHrefKey}`,
|
|
@@ -6446,7 +7911,7 @@ function FloatingToolbar({
|
|
|
6446
7911
|
onEditLink
|
|
6447
7912
|
}) {
|
|
6448
7913
|
const { top, left, transform } = calcToolbarPos(rect, parentScroll, 330);
|
|
6449
|
-
return /* @__PURE__ */
|
|
7914
|
+
return /* @__PURE__ */ jsx25(
|
|
6450
7915
|
"div",
|
|
6451
7916
|
{
|
|
6452
7917
|
ref: elRef,
|
|
@@ -6456,14 +7921,23 @@ function FloatingToolbar({
|
|
|
6456
7921
|
left,
|
|
6457
7922
|
transform,
|
|
6458
7923
|
zIndex: 2147483647,
|
|
7924
|
+
background: "#fff",
|
|
7925
|
+
border: "1px solid #E7E5E4",
|
|
7926
|
+
borderRadius: 6,
|
|
7927
|
+
boxShadow: "0px 2px 4px -2px rgba(0,0,0,.1),0px 4px 6px -1px rgba(0,0,0,.1)",
|
|
7928
|
+
display: "flex",
|
|
7929
|
+
alignItems: "center",
|
|
7930
|
+
padding: TOOLBAR_PILL_PADDING,
|
|
7931
|
+
gap: TOOLBAR_TOGGLE_GAP,
|
|
7932
|
+
fontFamily: "sans-serif",
|
|
6459
7933
|
pointerEvents: "auto"
|
|
6460
7934
|
},
|
|
6461
|
-
children: /* @__PURE__ */
|
|
6462
|
-
TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */
|
|
6463
|
-
gi > 0 && /* @__PURE__ */
|
|
7935
|
+
children: /* @__PURE__ */ jsxs14(CustomToolbar, { children: [
|
|
7936
|
+
TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs14(React10.Fragment, { children: [
|
|
7937
|
+
gi > 0 && /* @__PURE__ */ jsx25(CustomToolbarDivider, {}),
|
|
6464
7938
|
btns.map((btn) => {
|
|
6465
7939
|
const isActive = activeCommands.has(btn.cmd);
|
|
6466
|
-
return /* @__PURE__ */
|
|
7940
|
+
return /* @__PURE__ */ jsx25(
|
|
6467
7941
|
CustomToolbarButton,
|
|
6468
7942
|
{
|
|
6469
7943
|
title: btn.title,
|
|
@@ -6472,7 +7946,7 @@ function FloatingToolbar({
|
|
|
6472
7946
|
e.preventDefault();
|
|
6473
7947
|
onCommand(btn.cmd);
|
|
6474
7948
|
},
|
|
6475
|
-
children: /* @__PURE__ */
|
|
7949
|
+
children: /* @__PURE__ */ jsx25(
|
|
6476
7950
|
"svg",
|
|
6477
7951
|
{
|
|
6478
7952
|
width: "16",
|
|
@@ -6493,7 +7967,7 @@ function FloatingToolbar({
|
|
|
6493
7967
|
);
|
|
6494
7968
|
})
|
|
6495
7969
|
] }, gi)),
|
|
6496
|
-
showEditLink ? /* @__PURE__ */
|
|
7970
|
+
showEditLink ? /* @__PURE__ */ jsx25(
|
|
6497
7971
|
CustomToolbarButton,
|
|
6498
7972
|
{
|
|
6499
7973
|
type: "button",
|
|
@@ -6507,7 +7981,7 @@ function FloatingToolbar({
|
|
|
6507
7981
|
e.preventDefault();
|
|
6508
7982
|
e.stopPropagation();
|
|
6509
7983
|
},
|
|
6510
|
-
children: /* @__PURE__ */
|
|
7984
|
+
children: /* @__PURE__ */ jsx25(Link2, { className: "size-4 shrink-0", "aria-hidden": true })
|
|
6511
7985
|
}
|
|
6512
7986
|
) : null
|
|
6513
7987
|
] })
|
|
@@ -6524,7 +7998,7 @@ function StateToggle({
|
|
|
6524
7998
|
states,
|
|
6525
7999
|
onStateChange
|
|
6526
8000
|
}) {
|
|
6527
|
-
return /* @__PURE__ */
|
|
8001
|
+
return /* @__PURE__ */ jsx25(
|
|
6528
8002
|
ToggleGroup,
|
|
6529
8003
|
{
|
|
6530
8004
|
"data-ohw-state-toggle": "",
|
|
@@ -6538,7 +8012,7 @@ function StateToggle({
|
|
|
6538
8012
|
left: rect.right - 8,
|
|
6539
8013
|
transform: "translateX(-100%)"
|
|
6540
8014
|
},
|
|
6541
|
-
children: states.map((state) => /* @__PURE__ */
|
|
8015
|
+
children: states.map((state) => /* @__PURE__ */ jsx25(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
|
|
6542
8016
|
}
|
|
6543
8017
|
);
|
|
6544
8018
|
}
|
|
@@ -6561,12 +8035,12 @@ function resolveSubdomain(subdomainFromQuery) {
|
|
|
6561
8035
|
return "";
|
|
6562
8036
|
}
|
|
6563
8037
|
function OhhwellsBridge() {
|
|
6564
|
-
const pathname =
|
|
6565
|
-
const router =
|
|
8038
|
+
const pathname = usePathname2();
|
|
8039
|
+
const router = useRouter2();
|
|
6566
8040
|
const searchParams = useSearchParams();
|
|
6567
8041
|
const isEditMode = isEditSessionActive();
|
|
6568
|
-
const [bridgeRoot, setBridgeRoot] =
|
|
6569
|
-
|
|
8042
|
+
const [bridgeRoot, setBridgeRoot] = useState7(null);
|
|
8043
|
+
useEffect8(() => {
|
|
6570
8044
|
const figtreeFontId = "ohw-figtree-font";
|
|
6571
8045
|
if (!document.getElementById(figtreeFontId)) {
|
|
6572
8046
|
const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
|
|
@@ -6594,83 +8068,101 @@ function OhhwellsBridge() {
|
|
|
6594
8068
|
const subdomainFromQuery = searchParams.get("subdomain");
|
|
6595
8069
|
const subdomain = resolveSubdomain(subdomainFromQuery);
|
|
6596
8070
|
useLinkHrefGuardian(pathname, subdomain, isEditMode);
|
|
6597
|
-
const
|
|
8071
|
+
const postToParent2 = useCallback4((data) => {
|
|
6598
8072
|
if (typeof window !== "undefined" && window.parent !== window) {
|
|
6599
8073
|
window.parent.postMessage(data, "*");
|
|
6600
8074
|
}
|
|
6601
8075
|
}, []);
|
|
6602
|
-
const [fetchState, setFetchState] =
|
|
6603
|
-
const autoSaveTimers =
|
|
6604
|
-
const activeElRef =
|
|
6605
|
-
const selectedElRef =
|
|
6606
|
-
const originalContentRef =
|
|
6607
|
-
const activeStateElRef =
|
|
6608
|
-
const parentScrollRef =
|
|
6609
|
-
const visibleViewportRef =
|
|
6610
|
-
const [dialogPortalContainer, setDialogPortalContainer] =
|
|
6611
|
-
const attachVisibleViewport =
|
|
8076
|
+
const [fetchState, setFetchState] = useState7("idle");
|
|
8077
|
+
const autoSaveTimers = useRef5(/* @__PURE__ */ new Map());
|
|
8078
|
+
const activeElRef = useRef5(null);
|
|
8079
|
+
const selectedElRef = useRef5(null);
|
|
8080
|
+
const originalContentRef = useRef5(null);
|
|
8081
|
+
const activeStateElRef = useRef5(null);
|
|
8082
|
+
const parentScrollRef = useRef5(null);
|
|
8083
|
+
const visibleViewportRef = useRef5(null);
|
|
8084
|
+
const [dialogPortalContainer, setDialogPortalContainer] = useState7(null);
|
|
8085
|
+
const attachVisibleViewport = useCallback4((node) => {
|
|
6612
8086
|
visibleViewportRef.current = node;
|
|
6613
8087
|
setDialogPortalContainer(node);
|
|
6614
8088
|
if (node) applyVisibleViewport(node, parentScrollRef.current);
|
|
6615
8089
|
}, []);
|
|
6616
|
-
const toolbarElRef =
|
|
6617
|
-
const glowElRef =
|
|
6618
|
-
const hoveredImageRef =
|
|
6619
|
-
const hoveredImageHasTextOverlapRef =
|
|
6620
|
-
const dragOverElRef =
|
|
6621
|
-
const [mediaHover, setMediaHover] =
|
|
6622
|
-
const [
|
|
6623
|
-
const
|
|
6624
|
-
const
|
|
6625
|
-
const
|
|
6626
|
-
const
|
|
6627
|
-
const
|
|
8090
|
+
const toolbarElRef = useRef5(null);
|
|
8091
|
+
const glowElRef = useRef5(null);
|
|
8092
|
+
const hoveredImageRef = useRef5(null);
|
|
8093
|
+
const hoveredImageHasTextOverlapRef = useRef5(false);
|
|
8094
|
+
const dragOverElRef = useRef5(null);
|
|
8095
|
+
const [mediaHover, setMediaHover] = useState7(null);
|
|
8096
|
+
const [carouselHover, setCarouselHover] = useState7(null);
|
|
8097
|
+
const [uploadingRects, setUploadingRects] = useState7({});
|
|
8098
|
+
const pendingUploadRectRef = useRef5(null);
|
|
8099
|
+
const hoveredGapRef = useRef5(null);
|
|
8100
|
+
const imageUnhoverTimerRef = useRef5(null);
|
|
8101
|
+
const imageShowTimerRef = useRef5(null);
|
|
8102
|
+
const editStylesRef = useRef5(null);
|
|
8103
|
+
const activateRef = useRef5(() => {
|
|
8104
|
+
});
|
|
8105
|
+
const deactivateRef = useRef5(() => {
|
|
6628
8106
|
});
|
|
6629
|
-
const
|
|
8107
|
+
const selectRef = useRef5(() => {
|
|
6630
8108
|
});
|
|
6631
|
-
const
|
|
8109
|
+
const selectFrameRef = useRef5(() => {
|
|
6632
8110
|
});
|
|
6633
|
-
const deselectRef =
|
|
8111
|
+
const deselectRef = useRef5(() => {
|
|
6634
8112
|
});
|
|
6635
|
-
const reselectNavigationItemRef =
|
|
8113
|
+
const reselectNavigationItemRef = useRef5(() => {
|
|
6636
8114
|
});
|
|
6637
|
-
const commitNavigationTextEditRef =
|
|
8115
|
+
const commitNavigationTextEditRef = useRef5(() => {
|
|
6638
8116
|
});
|
|
6639
|
-
const refreshActiveCommandsRef =
|
|
8117
|
+
const refreshActiveCommandsRef = useRef5(() => {
|
|
6640
8118
|
});
|
|
6641
|
-
const postToParentRef =
|
|
6642
|
-
postToParentRef.current =
|
|
6643
|
-
const sectionsLoadedRef =
|
|
6644
|
-
const pendingScheduleConfigRequests =
|
|
6645
|
-
const [toolbarRect, setToolbarRect] =
|
|
6646
|
-
const [toolbarVariant, setToolbarVariant] =
|
|
6647
|
-
const toolbarVariantRef =
|
|
8119
|
+
const postToParentRef = useRef5(postToParent2);
|
|
8120
|
+
postToParentRef.current = postToParent2;
|
|
8121
|
+
const sectionsLoadedRef = useRef5(false);
|
|
8122
|
+
const pendingScheduleConfigRequests = useRef5([]);
|
|
8123
|
+
const [toolbarRect, setToolbarRect] = useState7(null);
|
|
8124
|
+
const [toolbarVariant, setToolbarVariant] = useState7("none");
|
|
8125
|
+
const toolbarVariantRef = useRef5("none");
|
|
6648
8126
|
toolbarVariantRef.current = toolbarVariant;
|
|
6649
|
-
const [reorderHrefKey, setReorderHrefKey] =
|
|
6650
|
-
const [reorderDragDisabled, setReorderDragDisabled] =
|
|
6651
|
-
const [toggleState, setToggleState] =
|
|
6652
|
-
const [maxBadge, setMaxBadge] =
|
|
6653
|
-
const [activeCommands, setActiveCommands] =
|
|
6654
|
-
const [sectionGap, setSectionGap] =
|
|
6655
|
-
const [toolbarShowEditLink, setToolbarShowEditLink] =
|
|
6656
|
-
const
|
|
6657
|
-
const [
|
|
6658
|
-
const
|
|
6659
|
-
const [
|
|
6660
|
-
const
|
|
6661
|
-
const [
|
|
6662
|
-
const [
|
|
6663
|
-
const [
|
|
6664
|
-
const
|
|
6665
|
-
const
|
|
6666
|
-
const
|
|
6667
|
-
const
|
|
6668
|
-
const
|
|
8127
|
+
const [reorderHrefKey, setReorderHrefKey] = useState7(null);
|
|
8128
|
+
const [reorderDragDisabled, setReorderDragDisabled] = useState7(false);
|
|
8129
|
+
const [toggleState, setToggleState] = useState7(null);
|
|
8130
|
+
const [maxBadge, setMaxBadge] = useState7(null);
|
|
8131
|
+
const [activeCommands, setActiveCommands] = useState7(/* @__PURE__ */ new Set());
|
|
8132
|
+
const [sectionGap, setSectionGap] = useState7(null);
|
|
8133
|
+
const [toolbarShowEditLink, setToolbarShowEditLink] = useState7(false);
|
|
8134
|
+
const hoveredNavContainerRef = useRef5(null);
|
|
8135
|
+
const [hoveredNavContainerRect, setHoveredNavContainerRect] = useState7(null);
|
|
8136
|
+
const hoveredItemElRef = useRef5(null);
|
|
8137
|
+
const [hoveredItemRect, setHoveredItemRect] = useState7(null);
|
|
8138
|
+
const siblingHintElRef = useRef5(null);
|
|
8139
|
+
const [siblingHintRect, setSiblingHintRect] = useState7(null);
|
|
8140
|
+
const [siblingHintRects, setSiblingHintRects] = useState7([]);
|
|
8141
|
+
const [isItemDragging, setIsItemDragging] = useState7(false);
|
|
8142
|
+
const [isFooterFrameSelection, setIsFooterFrameSelection] = useState7(false);
|
|
8143
|
+
const footerDragRef = useRef5(null);
|
|
8144
|
+
const [footerDropSlots, setFooterDropSlots] = useState7([]);
|
|
8145
|
+
const [activeFooterDropIndex, setActiveFooterDropIndex] = useState7(null);
|
|
8146
|
+
const [draggedItemRect, setDraggedItemRect] = useState7(null);
|
|
8147
|
+
const footerPointerDragRef = useRef5(null);
|
|
8148
|
+
const suppressNextClickRef = useRef5(false);
|
|
8149
|
+
const [linkPopover, setLinkPopover] = useState7(null);
|
|
8150
|
+
const linkPopoverSessionRef = useRef5(null);
|
|
8151
|
+
const addNavAfterAnchorRef = useRef5(null);
|
|
8152
|
+
const editContentRef = useRef5({});
|
|
8153
|
+
const [sitePages, setSitePages] = useState7([]);
|
|
8154
|
+
const [sectionsByPath, setSectionsByPath] = useState7({});
|
|
8155
|
+
const sectionsPrefetchGenRef = useRef5(0);
|
|
8156
|
+
const setLinkPopoverRef = useRef5(setLinkPopover);
|
|
8157
|
+
const linkPopoverPanelRef = useRef5(null);
|
|
8158
|
+
const linkPopoverOpenRef = useRef5(false);
|
|
8159
|
+
const linkPopoverGraceUntilRef = useRef5(0);
|
|
6669
8160
|
setLinkPopoverRef.current = setLinkPopover;
|
|
8161
|
+
linkPopoverSessionRef.current = linkPopover;
|
|
6670
8162
|
const bumpLinkPopoverGrace = () => {
|
|
6671
8163
|
linkPopoverGraceUntilRef.current = Date.now() + 350;
|
|
6672
8164
|
};
|
|
6673
|
-
const runSectionsPrefetch =
|
|
8165
|
+
const runSectionsPrefetch = useCallback4((pages) => {
|
|
6674
8166
|
if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
|
|
6675
8167
|
const gen = ++sectionsPrefetchGenRef.current;
|
|
6676
8168
|
const paths = pages.map((p) => p.path);
|
|
@@ -6689,43 +8181,33 @@ function OhhwellsBridge() {
|
|
|
6689
8181
|
);
|
|
6690
8182
|
});
|
|
6691
8183
|
}, [isEditMode, pathname]);
|
|
6692
|
-
const runSectionsPrefetchRef =
|
|
8184
|
+
const runSectionsPrefetchRef = useRef5(runSectionsPrefetch);
|
|
6693
8185
|
runSectionsPrefetchRef.current = runSectionsPrefetch;
|
|
6694
|
-
|
|
6695
|
-
if (!linkPopover)
|
|
8186
|
+
useEffect8(() => {
|
|
8187
|
+
if (!linkPopover) {
|
|
8188
|
+
document.documentElement.removeAttribute("data-ohw-link-popover-open");
|
|
8189
|
+
return;
|
|
8190
|
+
}
|
|
8191
|
+
document.documentElement.setAttribute("data-ohw-link-popover-open", "");
|
|
6696
8192
|
if (hoveredImageRef.current) {
|
|
6697
8193
|
hoveredImageRef.current = null;
|
|
6698
8194
|
hoveredImageHasTextOverlapRef.current = false;
|
|
6699
8195
|
}
|
|
6700
8196
|
hoveredGapRef.current = null;
|
|
6701
8197
|
setSectionGap(null);
|
|
6702
|
-
|
|
6703
|
-
|
|
6704
|
-
|
|
6705
|
-
|
|
6706
|
-
|
|
6707
|
-
|
|
6708
|
-
|
|
6709
|
-
|
|
6710
|
-
const preventBackgroundScroll = (e) => {
|
|
6711
|
-
const target = e.target;
|
|
6712
|
-
if (target instanceof Element && target.closest('[data-ohw-link-modal-root], [data-slot="dialog-overlay"]')) {
|
|
6713
|
-
return;
|
|
6714
|
-
}
|
|
6715
|
-
e.preventDefault();
|
|
6716
|
-
};
|
|
6717
|
-
const scrollOpts = { passive: false, capture: true };
|
|
6718
|
-
document.addEventListener("wheel", preventBackgroundScroll, scrollOpts);
|
|
6719
|
-
document.addEventListener("touchmove", preventBackgroundScroll, scrollOpts);
|
|
8198
|
+
hoveredItemElRef.current = null;
|
|
8199
|
+
setHoveredItemRect(null);
|
|
8200
|
+
hoveredNavContainerRef.current = null;
|
|
8201
|
+
setHoveredNavContainerRect(null);
|
|
8202
|
+
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => {
|
|
8203
|
+
el.removeAttribute("data-ohw-hovered");
|
|
8204
|
+
});
|
|
8205
|
+
postToParent2({ type: "ow:image-unhover" });
|
|
6720
8206
|
return () => {
|
|
6721
|
-
|
|
6722
|
-
html.style.overflow = prevHtmlOverflow;
|
|
6723
|
-
body.style.overflow = prevBodyOverflow;
|
|
6724
|
-
document.removeEventListener("wheel", preventBackgroundScroll, scrollOpts);
|
|
6725
|
-
document.removeEventListener("touchmove", preventBackgroundScroll, scrollOpts);
|
|
8207
|
+
document.documentElement.removeAttribute("data-ohw-link-popover-open");
|
|
6726
8208
|
};
|
|
6727
|
-
}, [linkPopover,
|
|
6728
|
-
|
|
8209
|
+
}, [linkPopover, postToParent2]);
|
|
8210
|
+
useEffect8(() => {
|
|
6729
8211
|
if (!isEditMode) return;
|
|
6730
8212
|
const useFixtures = shouldUseDevFixtures();
|
|
6731
8213
|
if (useFixtures) {
|
|
@@ -6746,17 +8228,17 @@ function OhhwellsBridge() {
|
|
|
6746
8228
|
runSectionsPrefetchRef.current(mapped);
|
|
6747
8229
|
};
|
|
6748
8230
|
window.addEventListener("message", onSitePages);
|
|
6749
|
-
if (!useFixtures)
|
|
8231
|
+
if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
|
|
6750
8232
|
return () => window.removeEventListener("message", onSitePages);
|
|
6751
|
-
}, [isEditMode,
|
|
6752
|
-
|
|
8233
|
+
}, [isEditMode, postToParent2]);
|
|
8234
|
+
useEffect8(() => {
|
|
6753
8235
|
if (!isEditMode || shouldUseDevFixtures()) return;
|
|
6754
8236
|
void loadAllSectionsManifest().then((manifest) => {
|
|
6755
8237
|
if (Object.keys(manifest).length === 0) return;
|
|
6756
8238
|
setSectionsByPath((prev) => ({ ...manifest, ...prev }));
|
|
6757
8239
|
});
|
|
6758
8240
|
}, [isEditMode]);
|
|
6759
|
-
|
|
8241
|
+
useEffect8(() => {
|
|
6760
8242
|
const update = () => {
|
|
6761
8243
|
const el = activeElRef.current ?? selectedElRef.current;
|
|
6762
8244
|
if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
|
|
@@ -6780,10 +8262,10 @@ function OhhwellsBridge() {
|
|
|
6780
8262
|
vvp.removeEventListener("resize", update);
|
|
6781
8263
|
};
|
|
6782
8264
|
}, []);
|
|
6783
|
-
const refreshStateRules =
|
|
8265
|
+
const refreshStateRules = useCallback4(() => {
|
|
6784
8266
|
editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
|
|
6785
8267
|
}, []);
|
|
6786
|
-
const processConfigRequest =
|
|
8268
|
+
const processConfigRequest = useCallback4((insertAfterVal) => {
|
|
6787
8269
|
const tracker = getSectionsTracker();
|
|
6788
8270
|
let entries = [];
|
|
6789
8271
|
try {
|
|
@@ -6806,7 +8288,7 @@ function OhhwellsBridge() {
|
|
|
6806
8288
|
}
|
|
6807
8289
|
window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
|
|
6808
8290
|
}, [isEditMode]);
|
|
6809
|
-
const deactivate =
|
|
8291
|
+
const deactivate = useCallback4(() => {
|
|
6810
8292
|
const el = activeElRef.current;
|
|
6811
8293
|
if (!el) return;
|
|
6812
8294
|
const key = el.dataset.ohwKey;
|
|
@@ -6835,21 +8317,25 @@ function OhhwellsBridge() {
|
|
|
6835
8317
|
setMaxBadge(null);
|
|
6836
8318
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
6837
8319
|
setToolbarShowEditLink(false);
|
|
6838
|
-
|
|
6839
|
-
}, [
|
|
6840
|
-
const deselect =
|
|
8320
|
+
postToParent2({ type: "ow:exit-edit" });
|
|
8321
|
+
}, [postToParent2]);
|
|
8322
|
+
const deselect = useCallback4(() => {
|
|
6841
8323
|
selectedElRef.current = null;
|
|
6842
8324
|
setReorderHrefKey(null);
|
|
6843
8325
|
setReorderDragDisabled(false);
|
|
8326
|
+
setIsFooterFrameSelection(false);
|
|
6844
8327
|
siblingHintElRef.current = null;
|
|
6845
8328
|
setSiblingHintRect(null);
|
|
8329
|
+
setSiblingHintRects([]);
|
|
6846
8330
|
setIsItemDragging(false);
|
|
8331
|
+
hoveredNavContainerRef.current = null;
|
|
8332
|
+
setHoveredNavContainerRect(null);
|
|
6847
8333
|
if (!activeElRef.current) {
|
|
6848
8334
|
setToolbarRect(null);
|
|
6849
8335
|
setToolbarVariant("none");
|
|
6850
8336
|
}
|
|
6851
8337
|
}, []);
|
|
6852
|
-
const reselectNavigationItem =
|
|
8338
|
+
const reselectNavigationItem = useCallback4((navAnchor) => {
|
|
6853
8339
|
selectedElRef.current = navAnchor;
|
|
6854
8340
|
const { key, disabled } = getNavigationItemReorderState(navAnchor);
|
|
6855
8341
|
setReorderHrefKey(key);
|
|
@@ -6859,7 +8345,7 @@ function OhhwellsBridge() {
|
|
|
6859
8345
|
setToolbarShowEditLink(false);
|
|
6860
8346
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
6861
8347
|
}, []);
|
|
6862
|
-
const commitNavigationTextEdit =
|
|
8348
|
+
const commitNavigationTextEdit = useCallback4((navAnchor) => {
|
|
6863
8349
|
const el = activeElRef.current;
|
|
6864
8350
|
if (!el) return;
|
|
6865
8351
|
const key = el.dataset.ohwKey;
|
|
@@ -6872,9 +8358,9 @@ function OhhwellsBridge() {
|
|
|
6872
8358
|
const html = sanitizeHtml(el.innerHTML);
|
|
6873
8359
|
const original = originalContentRef.current ?? "";
|
|
6874
8360
|
if (html !== sanitizeHtml(original)) {
|
|
6875
|
-
|
|
8361
|
+
postToParent2({ type: "ow:change", nodes: [{ key, text: html }] });
|
|
6876
8362
|
const h = document.documentElement.scrollHeight;
|
|
6877
|
-
if (h > 50)
|
|
8363
|
+
if (h > 50) postToParent2({ type: "ow:height", height: h });
|
|
6878
8364
|
}
|
|
6879
8365
|
}
|
|
6880
8366
|
el.removeAttribute("contenteditable");
|
|
@@ -6882,79 +8368,406 @@ function OhhwellsBridge() {
|
|
|
6882
8368
|
setMaxBadge(null);
|
|
6883
8369
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
6884
8370
|
setToolbarShowEditLink(false);
|
|
6885
|
-
|
|
8371
|
+
postToParent2({ type: "ow:exit-edit" });
|
|
6886
8372
|
reselectNavigationItem(navAnchor);
|
|
6887
|
-
}, [
|
|
6888
|
-
const
|
|
8373
|
+
}, [postToParent2, reselectNavigationItem]);
|
|
8374
|
+
const handleAddTopLevelNavItem = useCallback4(() => {
|
|
8375
|
+
const items = listNavbarItems();
|
|
8376
|
+
addNavAfterAnchorRef.current = items[items.length - 1] ?? null;
|
|
8377
|
+
deselectRef.current();
|
|
8378
|
+
deactivateRef.current();
|
|
8379
|
+
bumpLinkPopoverGrace();
|
|
8380
|
+
setLinkPopover({
|
|
8381
|
+
key: "__add-nav__",
|
|
8382
|
+
mode: "create",
|
|
8383
|
+
intent: "add-nav"
|
|
8384
|
+
});
|
|
8385
|
+
}, []);
|
|
8386
|
+
const clearFooterDragVisuals = useCallback4(() => {
|
|
8387
|
+
footerDragRef.current = null;
|
|
8388
|
+
setSiblingHintRects([]);
|
|
8389
|
+
setFooterDropSlots([]);
|
|
8390
|
+
setActiveFooterDropIndex(null);
|
|
8391
|
+
setDraggedItemRect(null);
|
|
8392
|
+
setIsItemDragging(false);
|
|
8393
|
+
unlockFooterDragInteraction();
|
|
8394
|
+
}, []);
|
|
8395
|
+
const refreshFooterDragVisuals = useCallback4((session, activeSlot, clientX, clientY) => {
|
|
8396
|
+
const dragged = session.draggedEl;
|
|
8397
|
+
setDraggedItemRect(dragged.getBoundingClientRect());
|
|
8398
|
+
if (typeof clientX === "number" && typeof clientY === "number") {
|
|
8399
|
+
session.lastClientX = clientX;
|
|
8400
|
+
session.lastClientY = clientY;
|
|
8401
|
+
}
|
|
8402
|
+
session.activeSlot = activeSlot;
|
|
8403
|
+
if (session.kind === "link") {
|
|
8404
|
+
const columns2 = listFooterColumns();
|
|
8405
|
+
const focusCols = /* @__PURE__ */ new Set([session.sourceColumnIndex]);
|
|
8406
|
+
if (activeSlot) focusCols.add(activeSlot.columnIndex);
|
|
8407
|
+
const siblingRects = [];
|
|
8408
|
+
columns2.forEach((col, i) => {
|
|
8409
|
+
if (!focusCols.has(i)) return;
|
|
8410
|
+
for (const link of listFooterLinksInColumn(col)) {
|
|
8411
|
+
if (link === dragged) continue;
|
|
8412
|
+
siblingRects.push(link.getBoundingClientRect());
|
|
8413
|
+
}
|
|
8414
|
+
});
|
|
8415
|
+
setSiblingHintRects(siblingRects);
|
|
8416
|
+
const slots2 = [];
|
|
8417
|
+
columns2.forEach((col, i) => {
|
|
8418
|
+
slots2.push(...buildLinkDropSlots(col, i));
|
|
8419
|
+
});
|
|
8420
|
+
setFooterDropSlots(slots2);
|
|
8421
|
+
const activeIdx2 = activeSlot ? slots2.findIndex((s) => s.columnIndex === activeSlot.columnIndex && s.insertIndex === activeSlot.insertIndex) : -1;
|
|
8422
|
+
setActiveFooterDropIndex(activeIdx2 >= 0 ? activeIdx2 : null);
|
|
8423
|
+
return;
|
|
8424
|
+
}
|
|
8425
|
+
const columns = listFooterColumns();
|
|
8426
|
+
setSiblingHintRects(columns.filter((col) => col !== dragged).map((col) => col.getBoundingClientRect()));
|
|
8427
|
+
const slots = buildColumnDropSlots();
|
|
8428
|
+
setFooterDropSlots(slots);
|
|
8429
|
+
const activeIdx = activeSlot ? slots.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
|
|
8430
|
+
setActiveFooterDropIndex(activeIdx >= 0 ? activeIdx : null);
|
|
8431
|
+
}, []);
|
|
8432
|
+
const refreshFooterDragVisualsRef = useRef5(refreshFooterDragVisuals);
|
|
8433
|
+
refreshFooterDragVisualsRef.current = refreshFooterDragVisuals;
|
|
8434
|
+
const commitFooterDragRef = useRef5(() => {
|
|
8435
|
+
});
|
|
8436
|
+
const beginFooterDragRef = useRef5(() => {
|
|
8437
|
+
});
|
|
8438
|
+
const beginFooterDrag = useCallback4(
|
|
8439
|
+
(session) => {
|
|
8440
|
+
const rect = session.draggedEl.getBoundingClientRect();
|
|
8441
|
+
session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
|
|
8442
|
+
session.lastClientY = session.lastClientY || rect.top + rect.height / 2;
|
|
8443
|
+
session.activeSlot = session.activeSlot ?? null;
|
|
8444
|
+
footerDragRef.current = session;
|
|
8445
|
+
setIsItemDragging(true);
|
|
8446
|
+
lockFooterDuringDrag();
|
|
8447
|
+
siblingHintElRef.current = null;
|
|
8448
|
+
setSiblingHintRect(null);
|
|
8449
|
+
if (session.wasSelected && selectedElRef.current === session.draggedEl) {
|
|
8450
|
+
setToolbarRect(rect);
|
|
8451
|
+
}
|
|
8452
|
+
const initialSlot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : hitTestColumnDropSlot(session.lastClientX, session.lastClientY);
|
|
8453
|
+
refreshFooterDragVisuals(session, initialSlot, session.lastClientX, session.lastClientY);
|
|
8454
|
+
},
|
|
8455
|
+
[refreshFooterDragVisuals]
|
|
8456
|
+
);
|
|
8457
|
+
beginFooterDragRef.current = beginFooterDrag;
|
|
8458
|
+
const commitFooterDrag = useCallback4(
|
|
8459
|
+
(clientX, clientY) => {
|
|
8460
|
+
const session = footerDragRef.current;
|
|
8461
|
+
if (!session) {
|
|
8462
|
+
clearFooterDragVisuals();
|
|
8463
|
+
return;
|
|
8464
|
+
}
|
|
8465
|
+
const x = typeof clientX === "number" && (clientX !== 0 || clientY !== 0) ? clientX : session.lastClientX;
|
|
8466
|
+
const y = typeof clientY === "number" && (clientX !== 0 || clientY !== 0) ? clientY : session.lastClientY;
|
|
8467
|
+
let nextOrder = null;
|
|
8468
|
+
const slot = session.activeSlot ?? (session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(x, y, session.hrefKey) : session.kind === "column" ? hitTestColumnDropSlot(x, y) : null);
|
|
8469
|
+
if (session.kind === "link" && session.hrefKey && slot) {
|
|
8470
|
+
nextOrder = planFooterLinkMove(session.hrefKey, slot.columnIndex, slot.insertIndex);
|
|
8471
|
+
} else if (session.kind === "column" && slot) {
|
|
8472
|
+
nextOrder = planFooterColumnMove(session.sourceColumnIndex, slot.insertIndex);
|
|
8473
|
+
}
|
|
8474
|
+
const wasSelected = session.wasSelected;
|
|
8475
|
+
const draggedEl = session.draggedEl;
|
|
8476
|
+
const hrefKey = session.hrefKey;
|
|
8477
|
+
let movedColumnIndex = null;
|
|
8478
|
+
if (session.kind === "column" && slot && nextOrder) {
|
|
8479
|
+
let adjusted = slot.insertIndex;
|
|
8480
|
+
if (session.sourceColumnIndex < slot.insertIndex) adjusted -= 1;
|
|
8481
|
+
movedColumnIndex = Math.max(0, Math.min(adjusted, nextOrder.length - 1));
|
|
8482
|
+
}
|
|
8483
|
+
clearFooterDragVisuals();
|
|
8484
|
+
const applySelectionAfterDrop = () => {
|
|
8485
|
+
if (!wasSelected) {
|
|
8486
|
+
deselectRef.current();
|
|
8487
|
+
return;
|
|
8488
|
+
}
|
|
8489
|
+
if (hrefKey) {
|
|
8490
|
+
const link = document.querySelector(
|
|
8491
|
+
`footer [data-ohw-href-key="${CSS.escape(hrefKey)}"]`
|
|
8492
|
+
);
|
|
8493
|
+
if (link && isNavigationItem(link)) {
|
|
8494
|
+
selectRef.current(link);
|
|
8495
|
+
return;
|
|
8496
|
+
}
|
|
8497
|
+
}
|
|
8498
|
+
if (movedColumnIndex !== null && nextOrder) {
|
|
8499
|
+
const colKeys = nextOrder[movedColumnIndex] ?? [];
|
|
8500
|
+
let column = null;
|
|
8501
|
+
for (const key of colKeys) {
|
|
8502
|
+
const link = document.querySelector(
|
|
8503
|
+
`footer [data-ohw-href-key="${CSS.escape(key)}"]`
|
|
8504
|
+
);
|
|
8505
|
+
if (link) {
|
|
8506
|
+
column = findFooterColumnForLink(link);
|
|
8507
|
+
if (column) break;
|
|
8508
|
+
}
|
|
8509
|
+
}
|
|
8510
|
+
if (!column) column = listFooterColumns()[movedColumnIndex] ?? null;
|
|
8511
|
+
if (column && isNavigationContainer(column)) {
|
|
8512
|
+
selectFrameRef.current(column);
|
|
8513
|
+
return;
|
|
8514
|
+
}
|
|
8515
|
+
}
|
|
8516
|
+
if (document.body.contains(draggedEl)) {
|
|
8517
|
+
if (isNavigationItem(draggedEl)) {
|
|
8518
|
+
selectRef.current(draggedEl);
|
|
8519
|
+
return;
|
|
8520
|
+
}
|
|
8521
|
+
if (isNavigationContainer(draggedEl)) {
|
|
8522
|
+
selectFrameRef.current(draggedEl);
|
|
8523
|
+
return;
|
|
8524
|
+
}
|
|
8525
|
+
}
|
|
8526
|
+
deselectRef.current();
|
|
8527
|
+
};
|
|
8528
|
+
if (!wasSelected) {
|
|
8529
|
+
deselectRef.current();
|
|
8530
|
+
}
|
|
8531
|
+
if (nextOrder) {
|
|
8532
|
+
const orderJson = JSON.stringify(nextOrder);
|
|
8533
|
+
editContentRef.current = {
|
|
8534
|
+
...editContentRef.current,
|
|
8535
|
+
[FOOTER_ORDER_KEY]: orderJson
|
|
8536
|
+
};
|
|
8537
|
+
applyFooterOrder(nextOrder);
|
|
8538
|
+
document.querySelectorAll("footer [data-ohw-href-key]").forEach(disableNativeHrefDrag);
|
|
8539
|
+
postToParentRef.current({
|
|
8540
|
+
type: "ow:change",
|
|
8541
|
+
nodes: [{ key: FOOTER_ORDER_KEY, text: orderJson }]
|
|
8542
|
+
});
|
|
8543
|
+
requestAnimationFrame(() => {
|
|
8544
|
+
if (editContentRef.current[FOOTER_ORDER_KEY] === orderJson) {
|
|
8545
|
+
applyFooterOrder(nextOrder);
|
|
8546
|
+
document.querySelectorAll("footer [data-ohw-href-key]").forEach(disableNativeHrefDrag);
|
|
8547
|
+
}
|
|
8548
|
+
requestAnimationFrame(applySelectionAfterDrop);
|
|
8549
|
+
});
|
|
8550
|
+
return;
|
|
8551
|
+
}
|
|
8552
|
+
applySelectionAfterDrop();
|
|
8553
|
+
},
|
|
8554
|
+
[clearFooterDragVisuals]
|
|
8555
|
+
);
|
|
8556
|
+
commitFooterDragRef.current = commitFooterDrag;
|
|
8557
|
+
const startFooterLinkDrag = useCallback4(
|
|
8558
|
+
(anchor, clientX, clientY, wasSelected) => {
|
|
8559
|
+
const hrefKey = anchor.getAttribute("data-ohw-href-key");
|
|
8560
|
+
if (!hrefKey || !isFooterHrefKey(hrefKey)) return false;
|
|
8561
|
+
const column = findFooterColumnForLink(anchor);
|
|
8562
|
+
const columns = listFooterColumns();
|
|
8563
|
+
beginFooterDrag({
|
|
8564
|
+
kind: "link",
|
|
8565
|
+
hrefKey,
|
|
8566
|
+
columnEl: column,
|
|
8567
|
+
sourceColumnIndex: column ? columns.indexOf(column) : 0,
|
|
8568
|
+
wasSelected,
|
|
8569
|
+
draggedEl: anchor,
|
|
8570
|
+
lastClientX: clientX,
|
|
8571
|
+
lastClientY: clientY,
|
|
8572
|
+
activeSlot: null
|
|
8573
|
+
});
|
|
8574
|
+
return true;
|
|
8575
|
+
},
|
|
8576
|
+
[beginFooterDrag]
|
|
8577
|
+
);
|
|
8578
|
+
const startFooterColumnDrag = useCallback4(
|
|
8579
|
+
(columnEl, clientX, clientY, wasSelected) => {
|
|
8580
|
+
const columns = listFooterColumns();
|
|
8581
|
+
const idx = columns.indexOf(columnEl);
|
|
8582
|
+
if (idx < 0) return false;
|
|
8583
|
+
beginFooterDrag({
|
|
8584
|
+
kind: "column",
|
|
8585
|
+
hrefKey: null,
|
|
8586
|
+
columnEl,
|
|
8587
|
+
sourceColumnIndex: idx,
|
|
8588
|
+
wasSelected,
|
|
8589
|
+
draggedEl: columnEl,
|
|
8590
|
+
lastClientX: clientX,
|
|
8591
|
+
lastClientY: clientY,
|
|
8592
|
+
activeSlot: null
|
|
8593
|
+
});
|
|
8594
|
+
return true;
|
|
8595
|
+
},
|
|
8596
|
+
[beginFooterDrag]
|
|
8597
|
+
);
|
|
8598
|
+
const handleItemDragStart = useCallback4(
|
|
8599
|
+
(e) => {
|
|
8600
|
+
const selected = selectedElRef.current;
|
|
8601
|
+
if (!selected) {
|
|
8602
|
+
setIsItemDragging(true);
|
|
8603
|
+
return;
|
|
8604
|
+
}
|
|
8605
|
+
const clientX = e?.clientX ?? selected.getBoundingClientRect().left + 8;
|
|
8606
|
+
const clientY = e?.clientY ?? selected.getBoundingClientRect().top + 8;
|
|
8607
|
+
if (startFooterLinkDrag(selected, clientX, clientY, true)) return;
|
|
8608
|
+
if (selected.hasAttribute("data-ohw-footer-col") || isInferredFooterGroup(selected) && selected.closest("footer")) {
|
|
8609
|
+
if (startFooterColumnDrag(selected, clientX, clientY, true)) return;
|
|
8610
|
+
}
|
|
8611
|
+
siblingHintElRef.current = null;
|
|
8612
|
+
setSiblingHintRect(null);
|
|
8613
|
+
setIsItemDragging(true);
|
|
8614
|
+
},
|
|
8615
|
+
[startFooterColumnDrag, startFooterLinkDrag]
|
|
8616
|
+
);
|
|
8617
|
+
const handleItemDragEnd = useCallback4(
|
|
8618
|
+
(e) => {
|
|
8619
|
+
if (footerDragRef.current) {
|
|
8620
|
+
const x = e?.clientX;
|
|
8621
|
+
const y = e?.clientY;
|
|
8622
|
+
if (typeof x === "number" && typeof y === "number" && (x !== 0 || y !== 0)) {
|
|
8623
|
+
commitFooterDrag(x, y);
|
|
8624
|
+
} else {
|
|
8625
|
+
commitFooterDrag();
|
|
8626
|
+
}
|
|
8627
|
+
return;
|
|
8628
|
+
}
|
|
8629
|
+
setIsItemDragging(false);
|
|
8630
|
+
},
|
|
8631
|
+
[commitFooterDrag]
|
|
8632
|
+
);
|
|
8633
|
+
const handleItemChromePointerDown = useCallback4((e) => {
|
|
8634
|
+
if (e.button !== 0) return;
|
|
6889
8635
|
const selected = selectedElRef.current;
|
|
6890
8636
|
if (!selected) return;
|
|
6891
|
-
|
|
6892
|
-
|
|
6893
|
-
|
|
6894
|
-
|
|
6895
|
-
|
|
6896
|
-
|
|
6897
|
-
|
|
6898
|
-
|
|
8637
|
+
armFooterPressDrag();
|
|
8638
|
+
const hrefKey = selected.getAttribute("data-ohw-href-key");
|
|
8639
|
+
if (hrefKey && isFooterHrefKey(hrefKey)) {
|
|
8640
|
+
footerPointerDragRef.current = {
|
|
8641
|
+
el: selected,
|
|
8642
|
+
kind: "link",
|
|
8643
|
+
startX: e.clientX,
|
|
8644
|
+
startY: e.clientY,
|
|
8645
|
+
pointerId: e.pointerId,
|
|
8646
|
+
wasSelected: true,
|
|
8647
|
+
started: false
|
|
8648
|
+
};
|
|
8649
|
+
return;
|
|
8650
|
+
}
|
|
8651
|
+
if (selected.hasAttribute("data-ohw-footer-col") || isInferredFooterGroup(selected) && selected.closest("footer")) {
|
|
8652
|
+
footerPointerDragRef.current = {
|
|
8653
|
+
el: selected,
|
|
8654
|
+
kind: "column",
|
|
8655
|
+
startX: e.clientX,
|
|
8656
|
+
startY: e.clientY,
|
|
8657
|
+
pointerId: e.pointerId,
|
|
8658
|
+
wasSelected: true,
|
|
8659
|
+
started: false
|
|
8660
|
+
};
|
|
8661
|
+
}
|
|
6899
8662
|
}, []);
|
|
6900
|
-
const
|
|
6901
|
-
|
|
8663
|
+
const handleItemChromeClick = useCallback4((clientX, clientY) => {
|
|
8664
|
+
if (suppressNextClickRef.current) {
|
|
8665
|
+
suppressNextClickRef.current = false;
|
|
8666
|
+
return;
|
|
8667
|
+
}
|
|
8668
|
+
const selected = selectedElRef.current;
|
|
8669
|
+
if (!selected || !isNavigationItem(selected)) return;
|
|
8670
|
+
const editable = selected.querySelector('[data-ohw-editable="text"]') ?? selected.querySelector("[data-ohw-editable]");
|
|
8671
|
+
if (!editable) return;
|
|
8672
|
+
activateRef.current(editable, { caretX: clientX, caretY: clientY });
|
|
6902
8673
|
}, []);
|
|
6903
8674
|
reselectNavigationItemRef.current = reselectNavigationItem;
|
|
6904
8675
|
commitNavigationTextEditRef.current = commitNavigationTextEdit;
|
|
6905
|
-
const select =
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
6910
|
-
|
|
6911
|
-
|
|
6912
|
-
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
|
|
6917
|
-
|
|
6918
|
-
|
|
6919
|
-
|
|
6920
|
-
|
|
6921
|
-
|
|
6922
|
-
|
|
6923
|
-
|
|
6924
|
-
|
|
6925
|
-
|
|
6926
|
-
|
|
6927
|
-
|
|
6928
|
-
|
|
6929
|
-
|
|
6930
|
-
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
|
|
6934
|
-
|
|
6935
|
-
|
|
6936
|
-
|
|
6937
|
-
|
|
6938
|
-
|
|
6939
|
-
|
|
6940
|
-
|
|
6941
|
-
|
|
6942
|
-
|
|
6943
|
-
|
|
8676
|
+
const select = useCallback4(
|
|
8677
|
+
(anchor) => {
|
|
8678
|
+
if (!isNavigationItem(anchor)) return;
|
|
8679
|
+
if (activeElRef.current) deactivate();
|
|
8680
|
+
selectedElRef.current = anchor;
|
|
8681
|
+
clearHrefKeyHover(anchor);
|
|
8682
|
+
hoveredNavContainerRef.current = null;
|
|
8683
|
+
setHoveredNavContainerRect(null);
|
|
8684
|
+
setHoveredItemRect(null);
|
|
8685
|
+
hoveredItemElRef.current = null;
|
|
8686
|
+
siblingHintElRef.current = null;
|
|
8687
|
+
setSiblingHintRect(null);
|
|
8688
|
+
setSiblingHintRects([]);
|
|
8689
|
+
setIsItemDragging(false);
|
|
8690
|
+
const { key, disabled } = getNavigationItemReorderState(anchor);
|
|
8691
|
+
setReorderHrefKey(key);
|
|
8692
|
+
setReorderDragDisabled(disabled);
|
|
8693
|
+
setIsFooterFrameSelection(false);
|
|
8694
|
+
setToolbarVariant("link-action");
|
|
8695
|
+
setToolbarRect(anchor.getBoundingClientRect());
|
|
8696
|
+
setToolbarShowEditLink(false);
|
|
8697
|
+
setActiveCommands(/* @__PURE__ */ new Set());
|
|
8698
|
+
},
|
|
8699
|
+
[deactivate]
|
|
8700
|
+
);
|
|
8701
|
+
const selectFrame = useCallback4(
|
|
8702
|
+
(el) => {
|
|
8703
|
+
if (!isNavigationContainer(el)) return;
|
|
8704
|
+
if (activeElRef.current) deactivate();
|
|
8705
|
+
const isFooterColumn = el.hasAttribute("data-ohw-footer-col") || Boolean(el.closest("footer") && isInferredFooterGroup(el));
|
|
8706
|
+
selectedElRef.current = el;
|
|
8707
|
+
clearHrefKeyHover(el);
|
|
8708
|
+
hoveredNavContainerRef.current = null;
|
|
8709
|
+
setHoveredNavContainerRect(null);
|
|
8710
|
+
setHoveredItemRect(null);
|
|
8711
|
+
hoveredItemElRef.current = null;
|
|
8712
|
+
siblingHintElRef.current = null;
|
|
8713
|
+
setSiblingHintRect(null);
|
|
8714
|
+
setSiblingHintRects(
|
|
8715
|
+
isFooterColumn ? listFooterColumns().filter((column) => column !== el).map((column) => column.getBoundingClientRect()) : []
|
|
8716
|
+
);
|
|
8717
|
+
setIsItemDragging(false);
|
|
6944
8718
|
setReorderHrefKey(null);
|
|
6945
8719
|
setReorderDragDisabled(false);
|
|
6946
|
-
|
|
6947
|
-
|
|
6948
|
-
|
|
6949
|
-
|
|
6950
|
-
|
|
6951
|
-
|
|
6952
|
-
|
|
6953
|
-
|
|
6954
|
-
|
|
8720
|
+
setIsFooterFrameSelection(isFooterColumn);
|
|
8721
|
+
setToolbarVariant("select-frame");
|
|
8722
|
+
setToolbarRect(el.getBoundingClientRect());
|
|
8723
|
+
setToolbarShowEditLink(false);
|
|
8724
|
+
setActiveCommands(/* @__PURE__ */ new Set());
|
|
8725
|
+
},
|
|
8726
|
+
[deactivate]
|
|
8727
|
+
);
|
|
8728
|
+
const activate = useCallback4(
|
|
8729
|
+
(el, options) => {
|
|
8730
|
+
if (activeElRef.current === el) return;
|
|
8731
|
+
selectedElRef.current = null;
|
|
8732
|
+
deactivate();
|
|
8733
|
+
if (hoveredImageRef.current) {
|
|
8734
|
+
hoveredImageRef.current = null;
|
|
8735
|
+
postToParentRef.current({ type: "ow:image-unhover" });
|
|
8736
|
+
}
|
|
8737
|
+
setToolbarVariant("rich-text");
|
|
8738
|
+
siblingHintElRef.current = null;
|
|
8739
|
+
setSiblingHintRect(null);
|
|
8740
|
+
setSiblingHintRects([]);
|
|
8741
|
+
setIsItemDragging(false);
|
|
8742
|
+
el.setAttribute("contenteditable", "true");
|
|
8743
|
+
el.removeAttribute("data-ohw-hovered");
|
|
8744
|
+
el.closest("[data-ohw-href-key]")?.removeAttribute("data-ohw-hovered");
|
|
8745
|
+
activeElRef.current = el;
|
|
8746
|
+
originalContentRef.current = el.innerHTML;
|
|
8747
|
+
el.focus();
|
|
8748
|
+
if (options?.caretX !== void 0 && options?.caretY !== void 0) {
|
|
8749
|
+
placeCaretAtPoint(el, options.caretX, options.caretY);
|
|
8750
|
+
}
|
|
8751
|
+
setToolbarShowEditLink(Boolean(getHrefKeyFromElement(el)));
|
|
8752
|
+
const navAnchor = getNavigationItemAnchor(el);
|
|
8753
|
+
if (navAnchor) {
|
|
8754
|
+
setReorderHrefKey(null);
|
|
8755
|
+
setReorderDragDisabled(false);
|
|
8756
|
+
} else {
|
|
8757
|
+
const { key: reorderKey, disabled: reorderDisabled } = getReorderHandleState(el);
|
|
8758
|
+
setReorderHrefKey(reorderKey);
|
|
8759
|
+
setReorderDragDisabled(reorderDisabled);
|
|
8760
|
+
}
|
|
8761
|
+
setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
|
|
8762
|
+
postToParent2({ type: "ow:enter-edit", key: el.dataset.ohwKey });
|
|
8763
|
+
requestAnimationFrame(() => refreshActiveCommandsRef.current());
|
|
8764
|
+
},
|
|
8765
|
+
[deactivate, postToParent2]
|
|
8766
|
+
);
|
|
6955
8767
|
activateRef.current = activate;
|
|
6956
8768
|
deactivateRef.current = deactivate;
|
|
6957
8769
|
selectRef.current = select;
|
|
8770
|
+
selectFrameRef.current = selectFrame;
|
|
6958
8771
|
deselectRef.current = deselect;
|
|
6959
8772
|
useLayoutEffect2(() => {
|
|
6960
8773
|
if (!subdomain || isEditMode) {
|
|
@@ -6966,6 +8779,7 @@ function OhhwellsBridge() {
|
|
|
6966
8779
|
for (const [key, val] of Object.entries(content)) {
|
|
6967
8780
|
if (key === "__ohw_sections") continue;
|
|
6968
8781
|
if (applyVideoSettingNode(key, val)) continue;
|
|
8782
|
+
if (applyCarouselNode(key, val)) continue;
|
|
6969
8783
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
6970
8784
|
if (el.dataset.ohwEditable === "image") {
|
|
6971
8785
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
@@ -6996,6 +8810,8 @@ function OhhwellsBridge() {
|
|
|
6996
8810
|
});
|
|
6997
8811
|
applyLinkByKey(key, val);
|
|
6998
8812
|
}
|
|
8813
|
+
reconcileNavbarItemsFromContent(content);
|
|
8814
|
+
reconcileFooterOrderFromContent(content);
|
|
6999
8815
|
enforceLinkHrefs();
|
|
7000
8816
|
initSectionsFromContent(content, true);
|
|
7001
8817
|
sectionsLoadedRef.current = true;
|
|
@@ -7024,7 +8840,7 @@ function OhhwellsBridge() {
|
|
|
7024
8840
|
cancelled = true;
|
|
7025
8841
|
};
|
|
7026
8842
|
}, [subdomain, isEditMode]);
|
|
7027
|
-
|
|
8843
|
+
useEffect8(() => {
|
|
7028
8844
|
if (!subdomain || isEditMode) return;
|
|
7029
8845
|
let debounceTimer = null;
|
|
7030
8846
|
let observer = null;
|
|
@@ -7037,6 +8853,7 @@ function OhhwellsBridge() {
|
|
|
7037
8853
|
for (const [key, val] of Object.entries(content)) {
|
|
7038
8854
|
if (key === "__ohw_sections") continue;
|
|
7039
8855
|
if (applyVideoSettingNode(key, val)) continue;
|
|
8856
|
+
if (applyCarouselNode(key, val)) continue;
|
|
7040
8857
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
7041
8858
|
if (el.dataset.ohwEditable === "image") {
|
|
7042
8859
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
@@ -7055,6 +8872,8 @@ function OhhwellsBridge() {
|
|
|
7055
8872
|
});
|
|
7056
8873
|
applyLinkByKey(key, val);
|
|
7057
8874
|
}
|
|
8875
|
+
reconcileNavbarItemsFromContent(content);
|
|
8876
|
+
reconcileFooterOrderFromContent(content);
|
|
7058
8877
|
} finally {
|
|
7059
8878
|
observer?.observe(document.body, { childList: true, subtree: true });
|
|
7060
8879
|
}
|
|
@@ -7078,20 +8897,65 @@ function OhhwellsBridge() {
|
|
|
7078
8897
|
const visible = Boolean(subdomain) && fetchState !== "done";
|
|
7079
8898
|
el.style.display = visible ? "flex" : "none";
|
|
7080
8899
|
}, [subdomain, fetchState]);
|
|
7081
|
-
|
|
7082
|
-
|
|
7083
|
-
}, [pathname,
|
|
7084
|
-
|
|
8900
|
+
useEffect8(() => {
|
|
8901
|
+
postToParent2({ type: "ow:navigation", path: pathname });
|
|
8902
|
+
}, [pathname, postToParent2]);
|
|
8903
|
+
useEffect8(() => {
|
|
7085
8904
|
if (!isEditMode) return;
|
|
8905
|
+
if (linkPopoverSessionRef.current?.intent === "add-nav") return;
|
|
8906
|
+
if (document.querySelector("[data-ohw-section-picker]")) return;
|
|
7086
8907
|
setLinkPopover(null);
|
|
7087
8908
|
deselectRef.current();
|
|
7088
8909
|
deactivateRef.current();
|
|
7089
8910
|
}, [pathname, isEditMode]);
|
|
7090
|
-
|
|
8911
|
+
useEffect8(() => {
|
|
8912
|
+
const contentForNav = () => {
|
|
8913
|
+
if (isEditMode) return editContentRef.current;
|
|
8914
|
+
if (!subdomain) return {};
|
|
8915
|
+
return contentCache.get(subdomain) ?? {};
|
|
8916
|
+
};
|
|
8917
|
+
let applying = false;
|
|
8918
|
+
let rafId = null;
|
|
8919
|
+
const run = () => {
|
|
8920
|
+
if (footerDragRef.current || applying) return;
|
|
8921
|
+
applying = true;
|
|
8922
|
+
try {
|
|
8923
|
+
const content = contentForNav();
|
|
8924
|
+
reconcileNavbarItemsFromContent(content);
|
|
8925
|
+
reconcileFooterOrderFromContent(content);
|
|
8926
|
+
document.querySelectorAll("footer [data-ohw-href-key]").forEach((el) => {
|
|
8927
|
+
if (isFooterHrefKey(el.getAttribute("data-ohw-href-key"))) {
|
|
8928
|
+
disableNativeHrefDrag(el);
|
|
8929
|
+
}
|
|
8930
|
+
});
|
|
8931
|
+
} finally {
|
|
8932
|
+
applying = false;
|
|
8933
|
+
}
|
|
8934
|
+
};
|
|
8935
|
+
const scheduleRun = () => {
|
|
8936
|
+
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
8937
|
+
rafId = requestAnimationFrame(() => {
|
|
8938
|
+
rafId = null;
|
|
8939
|
+
run();
|
|
8940
|
+
});
|
|
8941
|
+
};
|
|
8942
|
+
run();
|
|
8943
|
+
const nav = document.querySelector("nav");
|
|
8944
|
+
const footer = document.querySelector("footer");
|
|
8945
|
+
const observer = new MutationObserver(scheduleRun);
|
|
8946
|
+
if (nav) observer.observe(nav, { childList: true, subtree: true });
|
|
8947
|
+
if (footer) observer.observe(footer, { childList: true, subtree: true });
|
|
8948
|
+
if (!nav && !footer) return;
|
|
8949
|
+
return () => {
|
|
8950
|
+
observer.disconnect();
|
|
8951
|
+
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
8952
|
+
};
|
|
8953
|
+
}, [isEditMode, pathname, subdomain, fetchState]);
|
|
8954
|
+
useEffect8(() => {
|
|
7091
8955
|
if (!isEditMode) return;
|
|
7092
8956
|
const measure = () => {
|
|
7093
8957
|
const h = document.body.scrollHeight;
|
|
7094
|
-
if (h > 50)
|
|
8958
|
+
if (h > 50) postToParent2({ type: "ow:height", height: h });
|
|
7095
8959
|
};
|
|
7096
8960
|
const t1 = setTimeout(measure, 50);
|
|
7097
8961
|
const t2 = setTimeout(measure, 500);
|
|
@@ -7110,8 +8974,8 @@ function OhhwellsBridge() {
|
|
|
7110
8974
|
if (resizeTimer) clearTimeout(resizeTimer);
|
|
7111
8975
|
window.removeEventListener("resize", handleResize);
|
|
7112
8976
|
};
|
|
7113
|
-
}, [pathname, isEditMode,
|
|
7114
|
-
|
|
8977
|
+
}, [pathname, isEditMode, postToParent2]);
|
|
8978
|
+
useEffect8(() => {
|
|
7115
8979
|
if (!subdomainFromQuery || isEditMode) return;
|
|
7116
8980
|
const handleClick = (e) => {
|
|
7117
8981
|
const anchor = e.target.closest("a");
|
|
@@ -7127,7 +8991,7 @@ function OhhwellsBridge() {
|
|
|
7127
8991
|
document.addEventListener("click", handleClick, true);
|
|
7128
8992
|
return () => document.removeEventListener("click", handleClick, true);
|
|
7129
8993
|
}, [subdomainFromQuery, isEditMode, router]);
|
|
7130
|
-
|
|
8994
|
+
useEffect8(() => {
|
|
7131
8995
|
if (!isEditMode) {
|
|
7132
8996
|
editStylesRef.current?.base.remove();
|
|
7133
8997
|
editStylesRef.current?.forceHover.remove();
|
|
@@ -7150,6 +9014,32 @@ function OhhwellsBridge() {
|
|
|
7150
9014
|
[data-ohw-editable] {
|
|
7151
9015
|
display: block;
|
|
7152
9016
|
}
|
|
9017
|
+
/* Native <a> drag steals clicks \u2014 disable for edit links; reorder via press-to-drag / handle. */
|
|
9018
|
+
footer [data-ohw-href-key] {
|
|
9019
|
+
-webkit-user-drag: none !important;
|
|
9020
|
+
}
|
|
9021
|
+
footer [data-ohw-footer-col]:hover {
|
|
9022
|
+
outline: 1.5px dashed ${PRIMARY2} !important;
|
|
9023
|
+
outline-offset: 6px;
|
|
9024
|
+
border-radius: 8px;
|
|
9025
|
+
}
|
|
9026
|
+
html[data-ohw-link-popover-open] footer [data-ohw-footer-col]:hover {
|
|
9027
|
+
outline: none !important;
|
|
9028
|
+
}
|
|
9029
|
+
html[data-ohw-footer-press-drag] footer,
|
|
9030
|
+
html[data-ohw-footer-press-drag] footer * {
|
|
9031
|
+
user-select: none !important;
|
|
9032
|
+
-webkit-user-select: none !important;
|
|
9033
|
+
}
|
|
9034
|
+
html[data-ohw-item-dragging] footer,
|
|
9035
|
+
html[data-ohw-item-dragging] footer * {
|
|
9036
|
+
user-select: none !important;
|
|
9037
|
+
-webkit-user-select: none !important;
|
|
9038
|
+
pointer-events: none !important;
|
|
9039
|
+
}
|
|
9040
|
+
html[data-ohw-item-dragging] {
|
|
9041
|
+
cursor: grabbing !important;
|
|
9042
|
+
}
|
|
7153
9043
|
[data-ohw-editable]:not([contenteditable]):not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"]) { cursor: text !important; }
|
|
7154
9044
|
[data-ohw-editable="image"], [data-ohw-editable="image"] *,
|
|
7155
9045
|
[data-ohw-editable="video"], [data-ohw-editable="video"] *,
|
|
@@ -7195,12 +9085,46 @@ function OhhwellsBridge() {
|
|
|
7195
9085
|
}
|
|
7196
9086
|
refreshStateRules();
|
|
7197
9087
|
const handleClick = (e) => {
|
|
9088
|
+
if (suppressNextClickRef.current) {
|
|
9089
|
+
suppressNextClickRef.current = false;
|
|
9090
|
+
e.preventDefault();
|
|
9091
|
+
e.stopPropagation();
|
|
9092
|
+
return;
|
|
9093
|
+
}
|
|
7198
9094
|
const target = e.target;
|
|
7199
9095
|
if (target.closest("[data-ohw-toolbar]")) return;
|
|
7200
9096
|
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
7201
9097
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
7202
9098
|
if (isInsideLinkEditor(target)) return;
|
|
7203
9099
|
if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
|
|
9100
|
+
if (target.closest("[data-ohw-item-drag-surface]")) {
|
|
9101
|
+
e.preventDefault();
|
|
9102
|
+
e.stopPropagation();
|
|
9103
|
+
const selected = selectedElRef.current;
|
|
9104
|
+
if (selected && isNavigationItem(selected)) {
|
|
9105
|
+
const editable2 = selected.querySelector('[data-ohw-editable="text"]') ?? selected.querySelector("[data-ohw-editable]");
|
|
9106
|
+
if (editable2) {
|
|
9107
|
+
activateRef.current(editable2, {
|
|
9108
|
+
caretX: e.clientX,
|
|
9109
|
+
caretY: e.clientY
|
|
9110
|
+
});
|
|
9111
|
+
}
|
|
9112
|
+
} else if (selected?.hasAttribute("data-ohw-footer-col")) {
|
|
9113
|
+
const link = listFooterLinksInColumn(selected).find((el) => {
|
|
9114
|
+
const r2 = el.getBoundingClientRect();
|
|
9115
|
+
return e.clientX >= r2.left && e.clientX <= r2.right && e.clientY >= r2.top && e.clientY <= r2.bottom;
|
|
9116
|
+
});
|
|
9117
|
+
if (link) selectRef.current(link);
|
|
9118
|
+
}
|
|
9119
|
+
return;
|
|
9120
|
+
}
|
|
9121
|
+
const navFromChrome = resolveNavContainerSelectionTarget(target, e.clientX, e.clientY);
|
|
9122
|
+
if (navFromChrome) {
|
|
9123
|
+
e.preventDefault();
|
|
9124
|
+
e.stopPropagation();
|
|
9125
|
+
selectFrameRef.current(navFromChrome);
|
|
9126
|
+
return;
|
|
9127
|
+
}
|
|
7204
9128
|
e.preventDefault();
|
|
7205
9129
|
e.stopPropagation();
|
|
7206
9130
|
return;
|
|
@@ -7215,14 +9139,23 @@ function OhhwellsBridge() {
|
|
|
7215
9139
|
bumpLinkPopoverGrace();
|
|
7216
9140
|
setLinkPopoverRef.current({
|
|
7217
9141
|
key: editable.dataset.ohwKey ?? "",
|
|
7218
|
-
|
|
9142
|
+
mode: "edit",
|
|
9143
|
+
target: getLinkHref2(editable)
|
|
7219
9144
|
});
|
|
7220
9145
|
return;
|
|
7221
9146
|
}
|
|
7222
9147
|
if (isMediaEditable(editable)) {
|
|
7223
9148
|
e.preventDefault();
|
|
7224
9149
|
e.stopPropagation();
|
|
7225
|
-
|
|
9150
|
+
const key = editable.dataset.ohwKey ?? "";
|
|
9151
|
+
const r2 = editable.getBoundingClientRect();
|
|
9152
|
+
if (key && r2.width > 1 && r2.height > 1) {
|
|
9153
|
+
pendingUploadRectRef.current = {
|
|
9154
|
+
key,
|
|
9155
|
+
rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height }
|
|
9156
|
+
};
|
|
9157
|
+
}
|
|
9158
|
+
postToParentRef.current({ type: "ow:image-pick", key, elementType: editable.dataset.ohwEditable ?? "image" });
|
|
7226
9159
|
return;
|
|
7227
9160
|
}
|
|
7228
9161
|
const hrefCtx = getHrefKeyFromElement(editable);
|
|
@@ -7231,7 +9164,8 @@ function OhhwellsBridge() {
|
|
|
7231
9164
|
e.preventDefault();
|
|
7232
9165
|
e.stopPropagation();
|
|
7233
9166
|
if (selectedElRef.current === navAnchor) {
|
|
7234
|
-
|
|
9167
|
+
if (e.detail >= 2) return;
|
|
9168
|
+
activateRef.current(editable, { caretX: e.clientX, caretY: e.clientY });
|
|
7235
9169
|
return;
|
|
7236
9170
|
}
|
|
7237
9171
|
selectRef.current(navAnchor);
|
|
@@ -7246,10 +9180,42 @@ function OhhwellsBridge() {
|
|
|
7246
9180
|
if (hrefAnchor) {
|
|
7247
9181
|
e.preventDefault();
|
|
7248
9182
|
e.stopPropagation();
|
|
7249
|
-
if (selectedElRef.current === hrefAnchor)
|
|
9183
|
+
if (selectedElRef.current === hrefAnchor) {
|
|
9184
|
+
const textEditable = hrefAnchor.querySelector('[data-ohw-editable="text"]') ?? hrefAnchor.querySelector("[data-ohw-editable]");
|
|
9185
|
+
if (textEditable) {
|
|
9186
|
+
activateRef.current(textEditable, {
|
|
9187
|
+
caretX: e.clientX,
|
|
9188
|
+
caretY: e.clientY
|
|
9189
|
+
});
|
|
9190
|
+
}
|
|
9191
|
+
return;
|
|
9192
|
+
}
|
|
7250
9193
|
selectRef.current(hrefAnchor);
|
|
7251
9194
|
return;
|
|
7252
9195
|
}
|
|
9196
|
+
const footerColClick = target.closest("[data-ohw-footer-col]");
|
|
9197
|
+
if (footerColClick) {
|
|
9198
|
+
e.preventDefault();
|
|
9199
|
+
e.stopPropagation();
|
|
9200
|
+
selectFrameRef.current(footerColClick);
|
|
9201
|
+
return;
|
|
9202
|
+
}
|
|
9203
|
+
const navContainerToSelect = resolveNavContainerSelectionTarget(target, e.clientX, e.clientY);
|
|
9204
|
+
if (navContainerToSelect) {
|
|
9205
|
+
e.preventDefault();
|
|
9206
|
+
e.stopPropagation();
|
|
9207
|
+
selectFrameRef.current(navContainerToSelect);
|
|
9208
|
+
return;
|
|
9209
|
+
}
|
|
9210
|
+
const selectedContainer = selectedElRef.current;
|
|
9211
|
+
if (selectedContainer && isNavigationContainer(selectedContainer)) {
|
|
9212
|
+
const navItem = getNavigationItemAnchor(target);
|
|
9213
|
+
if (!navItem && (selectedContainer === target || selectedContainer.contains(target))) {
|
|
9214
|
+
e.preventDefault();
|
|
9215
|
+
e.stopPropagation();
|
|
9216
|
+
return;
|
|
9217
|
+
}
|
|
9218
|
+
}
|
|
7253
9219
|
if (activeElRef.current) {
|
|
7254
9220
|
const sel = window.getSelection();
|
|
7255
9221
|
if (sel && !sel.isCollapsed) {
|
|
@@ -7275,10 +9241,65 @@ function OhhwellsBridge() {
|
|
|
7275
9241
|
deselectRef.current();
|
|
7276
9242
|
deactivateRef.current();
|
|
7277
9243
|
};
|
|
9244
|
+
const handleDblClick = (e) => {
|
|
9245
|
+
const target = e.target;
|
|
9246
|
+
if (target.closest("[data-ohw-toolbar]")) return;
|
|
9247
|
+
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
9248
|
+
if (target.closest("[data-ohw-max-badge]")) return;
|
|
9249
|
+
if (isInsideLinkEditor(target)) return;
|
|
9250
|
+
if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
|
|
9251
|
+
return;
|
|
9252
|
+
}
|
|
9253
|
+
const navLabel = getNavigationLabelEditable(target);
|
|
9254
|
+
if (!navLabel) return;
|
|
9255
|
+
const { editable } = navLabel;
|
|
9256
|
+
e.preventDefault();
|
|
9257
|
+
e.stopPropagation();
|
|
9258
|
+
if (activeElRef.current !== editable) {
|
|
9259
|
+
activateRef.current(editable);
|
|
9260
|
+
}
|
|
9261
|
+
requestAnimationFrame(() => {
|
|
9262
|
+
selectAllTextInEditable(editable);
|
|
9263
|
+
refreshActiveCommandsRef.current();
|
|
9264
|
+
});
|
|
9265
|
+
};
|
|
7278
9266
|
const handleMouseOver = (e) => {
|
|
9267
|
+
if (document.documentElement.hasAttribute("data-ohw-section-picking")) return;
|
|
7279
9268
|
const target = e.target;
|
|
9269
|
+
if (linkPopoverOpenRef.current) {
|
|
9270
|
+
hoveredItemElRef.current = null;
|
|
9271
|
+
setHoveredItemRect(null);
|
|
9272
|
+
hoveredNavContainerRef.current = null;
|
|
9273
|
+
setHoveredNavContainerRect(null);
|
|
9274
|
+
return;
|
|
9275
|
+
}
|
|
9276
|
+
if (toolbarVariantRef.current !== "select-frame") {
|
|
9277
|
+
const navContainer = target.closest("[data-ohw-nav-container]");
|
|
9278
|
+
if (navContainer && !getNavigationItemAnchor(target)) {
|
|
9279
|
+
hoveredNavContainerRef.current = navContainer;
|
|
9280
|
+
setHoveredNavContainerRect(navContainer.getBoundingClientRect());
|
|
9281
|
+
hoveredItemElRef.current = null;
|
|
9282
|
+
setHoveredItemRect(null);
|
|
9283
|
+
return;
|
|
9284
|
+
}
|
|
9285
|
+
if (!target.closest("[data-ohw-nav-container]")) {
|
|
9286
|
+
hoveredNavContainerRef.current = null;
|
|
9287
|
+
setHoveredNavContainerRect(null);
|
|
9288
|
+
}
|
|
9289
|
+
}
|
|
9290
|
+
const footerCol = target.closest("[data-ohw-footer-col]");
|
|
9291
|
+
if (footerCol) {
|
|
9292
|
+
hoveredNavContainerRef.current = null;
|
|
9293
|
+
setHoveredNavContainerRect(null);
|
|
9294
|
+
if (selectedElRef.current === footerCol) return;
|
|
9295
|
+
hoveredItemElRef.current = footerCol;
|
|
9296
|
+
setHoveredItemRect(footerCol.getBoundingClientRect());
|
|
9297
|
+
return;
|
|
9298
|
+
}
|
|
7280
9299
|
const navAnchor = getNavigationItemAnchor(target);
|
|
7281
9300
|
if (navAnchor) {
|
|
9301
|
+
hoveredNavContainerRef.current = null;
|
|
9302
|
+
setHoveredNavContainerRect(null);
|
|
7282
9303
|
const selected2 = selectedElRef.current;
|
|
7283
9304
|
if (selected2 === navAnchor || selected2?.contains(navAnchor)) return;
|
|
7284
9305
|
clearHrefKeyHover(navAnchor);
|
|
@@ -7303,6 +9324,23 @@ function OhhwellsBridge() {
|
|
|
7303
9324
|
};
|
|
7304
9325
|
const handleMouseOut = (e) => {
|
|
7305
9326
|
const target = e.target;
|
|
9327
|
+
if (target.closest("[data-ohw-nav-container]")) {
|
|
9328
|
+
const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
9329
|
+
if (related2?.closest("[data-ohw-nav-container], [data-ohw-navbar-container-chrome], [data-ohw-navbar-add-button]")) {
|
|
9330
|
+
return;
|
|
9331
|
+
}
|
|
9332
|
+
hoveredNavContainerRef.current = null;
|
|
9333
|
+
setHoveredNavContainerRect(null);
|
|
9334
|
+
}
|
|
9335
|
+
const footerCol = target.closest("[data-ohw-footer-col]");
|
|
9336
|
+
if (footerCol && hoveredItemElRef.current === footerCol) {
|
|
9337
|
+
const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
9338
|
+
if (related2?.closest("[data-ohw-drag-handle-container], [data-ohw-item-interaction]")) return;
|
|
9339
|
+
if (related2?.closest("[data-ohw-footer-col]") === footerCol) return;
|
|
9340
|
+
hoveredItemElRef.current = null;
|
|
9341
|
+
setHoveredItemRect(null);
|
|
9342
|
+
return;
|
|
9343
|
+
}
|
|
7306
9344
|
const navAnchor = getNavigationItemAnchor(target);
|
|
7307
9345
|
if (navAnchor) {
|
|
7308
9346
|
const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
@@ -7424,44 +9462,87 @@ function OhhwellsBridge() {
|
|
|
7424
9462
|
}
|
|
7425
9463
|
return smallest;
|
|
7426
9464
|
};
|
|
9465
|
+
const dismissImageHover = () => {
|
|
9466
|
+
if (hoveredImageRef.current) {
|
|
9467
|
+
hoveredImageRef.current = null;
|
|
9468
|
+
hoveredImageHasTextOverlapRef.current = false;
|
|
9469
|
+
resumeAnimTracks();
|
|
9470
|
+
postToParentRef.current({ type: "ow:image-unhover" });
|
|
9471
|
+
}
|
|
9472
|
+
clearImageHover();
|
|
9473
|
+
};
|
|
9474
|
+
const probeNavigationHoverAt = (x, y) => {
|
|
9475
|
+
if (toolbarVariantRef.current === "select-frame") {
|
|
9476
|
+
hoveredNavContainerRef.current = null;
|
|
9477
|
+
setHoveredNavContainerRect(null);
|
|
9478
|
+
return;
|
|
9479
|
+
}
|
|
9480
|
+
const navContainer = document.querySelector("[data-ohw-nav-container]");
|
|
9481
|
+
if (!navContainer) {
|
|
9482
|
+
hoveredNavContainerRef.current = null;
|
|
9483
|
+
setHoveredNavContainerRect(null);
|
|
9484
|
+
return;
|
|
9485
|
+
}
|
|
9486
|
+
const containerRect = navContainer.getBoundingClientRect();
|
|
9487
|
+
const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
|
|
9488
|
+
if (!overContainer) {
|
|
9489
|
+
hoveredNavContainerRef.current = null;
|
|
9490
|
+
setHoveredNavContainerRect(null);
|
|
9491
|
+
return;
|
|
9492
|
+
}
|
|
9493
|
+
const navItemHit = Array.from(
|
|
9494
|
+
navContainer.querySelectorAll("[data-ohw-href-key]")
|
|
9495
|
+
).find((el) => {
|
|
9496
|
+
if (!isNavigationItem(el) || isNavbarButton2(el)) return false;
|
|
9497
|
+
const itemRect = el.getBoundingClientRect();
|
|
9498
|
+
return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
|
|
9499
|
+
});
|
|
9500
|
+
if (navItemHit) {
|
|
9501
|
+
hoveredNavContainerRef.current = null;
|
|
9502
|
+
setHoveredNavContainerRect(null);
|
|
9503
|
+
const selected = selectedElRef.current;
|
|
9504
|
+
if (selected !== navItemHit && !selected?.contains(navItemHit)) {
|
|
9505
|
+
clearHrefKeyHover(navItemHit);
|
|
9506
|
+
hoveredItemElRef.current = navItemHit;
|
|
9507
|
+
setHoveredItemRect(navItemHit.getBoundingClientRect());
|
|
9508
|
+
}
|
|
9509
|
+
return;
|
|
9510
|
+
}
|
|
9511
|
+
hoveredNavContainerRef.current = navContainer;
|
|
9512
|
+
setHoveredNavContainerRect(containerRect);
|
|
9513
|
+
hoveredItemElRef.current = null;
|
|
9514
|
+
setHoveredItemRect(null);
|
|
9515
|
+
};
|
|
7427
9516
|
const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
|
|
7428
9517
|
if (linkPopoverOpenRef.current) {
|
|
7429
|
-
|
|
7430
|
-
|
|
7431
|
-
|
|
7432
|
-
|
|
7433
|
-
|
|
7434
|
-
|
|
9518
|
+
dismissImageHover();
|
|
9519
|
+
return;
|
|
9520
|
+
}
|
|
9521
|
+
const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
9522
|
+
if (isPointOverNavigation(x, y)) {
|
|
9523
|
+
dismissImageHover();
|
|
9524
|
+
probeNavigationHoverAt(x, y);
|
|
7435
9525
|
return;
|
|
7436
9526
|
}
|
|
9527
|
+
hoveredNavContainerRef.current = null;
|
|
9528
|
+
setHoveredNavContainerRect(null);
|
|
7437
9529
|
const toggleEl = document.querySelector("[data-ohw-state-toggle]");
|
|
7438
9530
|
if (toggleEl) {
|
|
7439
|
-
const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
7440
9531
|
const tr = toggleEl.getBoundingClientRect();
|
|
7441
9532
|
if (x >= tr.left && x <= tr.right && y >= tr.top && y <= tr.bottom) {
|
|
7442
|
-
|
|
7443
|
-
hoveredImageRef.current = null;
|
|
7444
|
-
resumeAnimTracks();
|
|
7445
|
-
clearImageHover();
|
|
7446
|
-
}
|
|
9533
|
+
dismissImageHover();
|
|
7447
9534
|
return;
|
|
7448
9535
|
}
|
|
7449
9536
|
}
|
|
7450
9537
|
const imgEl = findImageAtPoint(clientX, clientY, fromParentViewport);
|
|
7451
9538
|
const activeEl = activeElRef.current;
|
|
7452
9539
|
if (activeEl && (!imgEl || imgEl.contains(activeEl))) {
|
|
7453
|
-
|
|
7454
|
-
hoveredImageRef.current = null;
|
|
7455
|
-
hoveredImageHasTextOverlapRef.current = false;
|
|
7456
|
-
resumeAnimTracks();
|
|
7457
|
-
clearImageHover();
|
|
7458
|
-
}
|
|
9540
|
+
dismissImageHover();
|
|
7459
9541
|
return;
|
|
7460
9542
|
}
|
|
7461
9543
|
if (imgEl) {
|
|
7462
|
-
const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
7463
9544
|
const topEl = document.elementFromPoint(x, y);
|
|
7464
|
-
if (topEl?.closest('[data-ohw-toolbar], [data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
|
|
9545
|
+
if (topEl?.closest('[data-ohw-toolbar], [data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"], [data-ohw-media-chrome]')) {
|
|
7465
9546
|
if (hoveredImageRef.current) {
|
|
7466
9547
|
hoveredImageRef.current = null;
|
|
7467
9548
|
resumeAnimTracks();
|
|
@@ -7559,12 +9640,12 @@ function OhhwellsBridge() {
|
|
|
7559
9640
|
resumeAnimTracks();
|
|
7560
9641
|
clearImageHover();
|
|
7561
9642
|
}
|
|
7562
|
-
const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
9643
|
+
const { x: x2, y: y2 } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
7563
9644
|
const textEl = Array.from(
|
|
7564
9645
|
document.querySelectorAll(NON_MEDIA_SELECTOR)
|
|
7565
9646
|
).find((el) => {
|
|
7566
9647
|
const er = el.getBoundingClientRect();
|
|
7567
|
-
return
|
|
9648
|
+
return x2 >= er.left && x2 <= er.right && y2 >= er.top && y2 <= er.bottom;
|
|
7568
9649
|
});
|
|
7569
9650
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
7570
9651
|
if (textEl && !textEl.hasAttribute("contenteditable")) {
|
|
@@ -7588,6 +9669,14 @@ function OhhwellsBridge() {
|
|
|
7588
9669
|
}
|
|
7589
9670
|
};
|
|
7590
9671
|
const probeHoverCardsAt = (clientX, clientY, fromParentViewport = false) => {
|
|
9672
|
+
if (linkPopoverOpenRef.current || document.documentElement.hasAttribute("data-ohw-section-picking")) {
|
|
9673
|
+
if (activeStateElRef.current) {
|
|
9674
|
+
activeStateElRef.current.removeAttribute("data-ohw-state-hovered");
|
|
9675
|
+
activeStateElRef.current = null;
|
|
9676
|
+
setToggleState(null);
|
|
9677
|
+
}
|
|
9678
|
+
return;
|
|
9679
|
+
}
|
|
7591
9680
|
const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
7592
9681
|
const toggleEl = document.querySelector("[data-ohw-state-toggle]");
|
|
7593
9682
|
if (toggleEl) {
|
|
@@ -7660,6 +9749,14 @@ function OhhwellsBridge() {
|
|
|
7660
9749
|
probeHoverCardsAt(clientX, clientY);
|
|
7661
9750
|
};
|
|
7662
9751
|
const handleDragOver = (e) => {
|
|
9752
|
+
const footerSession = footerDragRef.current;
|
|
9753
|
+
if (footerSession) {
|
|
9754
|
+
e.preventDefault();
|
|
9755
|
+
if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
|
|
9756
|
+
const slot = footerSession.kind === "link" && footerSession.hrefKey ? hitTestLinkDropSlot(e.clientX, e.clientY, footerSession.hrefKey) : hitTestColumnDropSlot(e.clientX, e.clientY);
|
|
9757
|
+
refreshFooterDragVisualsRef.current(footerSession, slot, e.clientX, e.clientY);
|
|
9758
|
+
return;
|
|
9759
|
+
}
|
|
7663
9760
|
e.preventDefault();
|
|
7664
9761
|
const el = findImageAtPoint(e.clientX, e.clientY, false);
|
|
7665
9762
|
if (!el) {
|
|
@@ -7728,6 +9825,7 @@ function OhhwellsBridge() {
|
|
|
7728
9825
|
if (!entry || entry.fadingOut) return prev;
|
|
7729
9826
|
return { ...prev, [key]: { ...entry, fadingOut: true } };
|
|
7730
9827
|
});
|
|
9828
|
+
if (pendingUploadRectRef.current?.key === key) pendingUploadRectRef.current = null;
|
|
7731
9829
|
};
|
|
7732
9830
|
let found = false;
|
|
7733
9831
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -7842,6 +9940,7 @@ function OhhwellsBridge() {
|
|
|
7842
9940
|
continue;
|
|
7843
9941
|
}
|
|
7844
9942
|
if (applyVideoSettingNode(key, val)) continue;
|
|
9943
|
+
if (applyCarouselNode(key, val)) continue;
|
|
7845
9944
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
7846
9945
|
if (el.dataset.ohwEditable === "image") {
|
|
7847
9946
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
@@ -7864,6 +9963,9 @@ function OhhwellsBridge() {
|
|
|
7864
9963
|
sectionsLoadedRef.current = true;
|
|
7865
9964
|
pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
|
|
7866
9965
|
}
|
|
9966
|
+
editContentRef.current = { ...editContentRef.current, ...content };
|
|
9967
|
+
reconcileNavbarItemsFromContent(editContentRef.current);
|
|
9968
|
+
reconcileFooterOrderFromContent(editContentRef.current);
|
|
7867
9969
|
enforceLinkHrefs();
|
|
7868
9970
|
postToParentRef.current({ type: "ow:hydrate-done" });
|
|
7869
9971
|
};
|
|
@@ -7871,6 +9973,7 @@ function OhhwellsBridge() {
|
|
|
7871
9973
|
const handleDeactivate = (e) => {
|
|
7872
9974
|
if (e.data?.type !== "ow:deactivate") return;
|
|
7873
9975
|
if (Date.now() < linkPopoverGraceUntilRef.current) return;
|
|
9976
|
+
if (document.querySelector("[data-ohw-section-picker]")) return;
|
|
7874
9977
|
if (linkPopoverOpenRef.current) {
|
|
7875
9978
|
setLinkPopoverRef.current(null);
|
|
7876
9979
|
return;
|
|
@@ -7879,13 +9982,40 @@ function OhhwellsBridge() {
|
|
|
7879
9982
|
deactivateRef.current();
|
|
7880
9983
|
};
|
|
7881
9984
|
window.addEventListener("message", handleDeactivate);
|
|
9985
|
+
const handleUiEscape = (e) => {
|
|
9986
|
+
if (e.data?.type !== "ui:escape") return;
|
|
9987
|
+
if (linkPopoverOpenRef.current) {
|
|
9988
|
+
setLinkPopoverRef.current(null);
|
|
9989
|
+
}
|
|
9990
|
+
};
|
|
9991
|
+
window.addEventListener("message", handleUiEscape);
|
|
7882
9992
|
const handleKeyDown = (e) => {
|
|
9993
|
+
if (e.key === "Escape" && document.querySelector("[data-ohw-section-picker]")) return;
|
|
9994
|
+
if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a" && activeElRef.current) {
|
|
9995
|
+
const navAnchor = getNavigationItemAnchor(activeElRef.current);
|
|
9996
|
+
if (navAnchor) {
|
|
9997
|
+
e.preventDefault();
|
|
9998
|
+
selectAllTextInEditable(activeElRef.current);
|
|
9999
|
+
refreshActiveCommandsRef.current();
|
|
10000
|
+
return;
|
|
10001
|
+
}
|
|
10002
|
+
}
|
|
7883
10003
|
if (e.key === "Escape" && linkPopoverOpenRef.current) {
|
|
7884
10004
|
setLinkPopoverRef.current(null);
|
|
7885
10005
|
return;
|
|
7886
10006
|
}
|
|
7887
10007
|
if (e.key === "Escape" && selectedElRef.current && !activeElRef.current) {
|
|
7888
|
-
|
|
10008
|
+
if (toolbarVariantRef.current === "select-frame") {
|
|
10009
|
+
deselectRef.current();
|
|
10010
|
+
return;
|
|
10011
|
+
}
|
|
10012
|
+
const parent = getNavigationSelectionParent(selectedElRef.current);
|
|
10013
|
+
if (parent) {
|
|
10014
|
+
e.preventDefault();
|
|
10015
|
+
selectFrameRef.current(parent);
|
|
10016
|
+
} else {
|
|
10017
|
+
deselectRef.current();
|
|
10018
|
+
}
|
|
7889
10019
|
return;
|
|
7890
10020
|
}
|
|
7891
10021
|
if (e.key === "Escape" && activeElRef.current) {
|
|
@@ -7943,9 +10073,23 @@ function OhhwellsBridge() {
|
|
|
7943
10073
|
if (hoveredItemElRef.current) {
|
|
7944
10074
|
setHoveredItemRect(hoveredItemElRef.current.getBoundingClientRect());
|
|
7945
10075
|
}
|
|
10076
|
+
if (hoveredNavContainerRef.current) {
|
|
10077
|
+
setHoveredNavContainerRect(hoveredNavContainerRef.current.getBoundingClientRect());
|
|
10078
|
+
}
|
|
7946
10079
|
if (siblingHintElRef.current) {
|
|
7947
10080
|
setSiblingHintRect(siblingHintElRef.current.getBoundingClientRect());
|
|
7948
10081
|
}
|
|
10082
|
+
const selected = selectedElRef.current;
|
|
10083
|
+
if (selected && !footerDragRef.current && (selected.hasAttribute("data-ohw-footer-col") || Boolean(selected.closest("footer") && isInferredFooterGroup(selected)))) {
|
|
10084
|
+
setSiblingHintRects(
|
|
10085
|
+
listFooterColumns().filter((column) => column !== selected).map((column) => column.getBoundingClientRect())
|
|
10086
|
+
);
|
|
10087
|
+
}
|
|
10088
|
+
if (footerDragRef.current) {
|
|
10089
|
+
const session = footerDragRef.current;
|
|
10090
|
+
const slot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : hitTestColumnDropSlot(session.lastClientX, session.lastClientY);
|
|
10091
|
+
refreshFooterDragVisualsRef.current(session, slot, session.lastClientX, session.lastClientY);
|
|
10092
|
+
}
|
|
7949
10093
|
if (hoveredImageRef.current) {
|
|
7950
10094
|
const el = hoveredImageRef.current;
|
|
7951
10095
|
const r2 = el.getBoundingClientRect();
|
|
@@ -7956,7 +10100,7 @@ function OhhwellsBridge() {
|
|
|
7956
10100
|
};
|
|
7957
10101
|
const handleSave = (e) => {
|
|
7958
10102
|
if (e.data?.type !== "ow:save") return;
|
|
7959
|
-
const nodes = collectEditableNodes();
|
|
10103
|
+
const nodes = collectEditableNodes(editContentRef.current);
|
|
7960
10104
|
const tracker = document.querySelector("[data-ohw-sections-tracker]");
|
|
7961
10105
|
if (tracker?.textContent) nodes.push({ key: "__ohw_sections", type: "sections", text: tracker.textContent });
|
|
7962
10106
|
postToParentRef.current({ type: "ow:save-result", nodes });
|
|
@@ -8041,28 +10185,49 @@ function OhhwellsBridge() {
|
|
|
8041
10185
|
const handleDocMouseLeave = () => {
|
|
8042
10186
|
hoveredImageRef.current = null;
|
|
8043
10187
|
setMediaHover(null);
|
|
10188
|
+
setCarouselHover(null);
|
|
8044
10189
|
document.querySelectorAll("[data-ohw-state-hovered]").forEach((el) => el.removeAttribute("data-ohw-state-hovered"));
|
|
8045
10190
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
8046
10191
|
activeStateElRef.current = null;
|
|
8047
10192
|
setToggleState(null);
|
|
8048
10193
|
};
|
|
10194
|
+
const resolveUploadRects = (key) => {
|
|
10195
|
+
const matches = Array.from(document.querySelectorAll(`[data-ohw-key="${key}"]`));
|
|
10196
|
+
const rects = matches.map((el) => {
|
|
10197
|
+
const r2 = el.getBoundingClientRect();
|
|
10198
|
+
return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
|
|
10199
|
+
}).filter((r2) => r2.width > 1 && r2.height > 1);
|
|
10200
|
+
if (rects.length > 0) return rects;
|
|
10201
|
+
const pending = pendingUploadRectRef.current;
|
|
10202
|
+
if (pending?.key === key && pending.rect.width > 1 && pending.rect.height > 1) {
|
|
10203
|
+
return [pending.rect];
|
|
10204
|
+
}
|
|
10205
|
+
const hovered = hoveredImageRef.current;
|
|
10206
|
+
if (hovered?.dataset.ohwKey === key) {
|
|
10207
|
+
const r2 = hovered.getBoundingClientRect();
|
|
10208
|
+
if (r2.width > 1 && r2.height > 1) {
|
|
10209
|
+
return [{ top: r2.top, left: r2.left, width: r2.width, height: r2.height }];
|
|
10210
|
+
}
|
|
10211
|
+
}
|
|
10212
|
+
return [];
|
|
10213
|
+
};
|
|
8049
10214
|
const handleImageUploading = (e) => {
|
|
8050
|
-
|
|
8051
|
-
|
|
10215
|
+
const type = e.data?.type;
|
|
10216
|
+
if (type !== "ow:image-uploading" && type !== "ow:anim-lock") return;
|
|
10217
|
+
const key = e.data.key;
|
|
10218
|
+
if (!key) return;
|
|
10219
|
+
const uploading = type === "ow:anim-lock" ? true : !!e.data.uploading;
|
|
8052
10220
|
setUploadingRects((prev) => {
|
|
8053
10221
|
if (!uploading) {
|
|
10222
|
+
if (pendingUploadRectRef.current?.key === key) pendingUploadRectRef.current = null;
|
|
8054
10223
|
if (!(key in prev)) return prev;
|
|
8055
10224
|
const next = { ...prev };
|
|
8056
10225
|
delete next[key];
|
|
8057
10226
|
return next;
|
|
8058
10227
|
}
|
|
8059
|
-
const
|
|
8060
|
-
if (
|
|
8061
|
-
|
|
8062
|
-
return {
|
|
8063
|
-
...prev,
|
|
8064
|
-
[key]: { rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height } }
|
|
8065
|
-
};
|
|
10228
|
+
const rects = resolveUploadRects(key);
|
|
10229
|
+
if (rects.length === 0) return prev;
|
|
10230
|
+
return { ...prev, [key]: { rects } };
|
|
8066
10231
|
});
|
|
8067
10232
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
8068
10233
|
const track = el.closest("[data-ohw-hover-pause]");
|
|
@@ -8080,6 +10245,48 @@ function OhhwellsBridge() {
|
|
|
8080
10245
|
if (e.data?.type !== "ow:canvas-height" || typeof e.data.height !== "number") return;
|
|
8081
10246
|
document.documentElement.style.setProperty("--ohw-canvas-h", `${e.data.height}px`);
|
|
8082
10247
|
};
|
|
10248
|
+
const handleCarouselChange = (e) => {
|
|
10249
|
+
if (e.data?.type !== "ow:carousel-change") return;
|
|
10250
|
+
const { key, images } = e.data;
|
|
10251
|
+
if (!key || !Array.isArray(images)) return;
|
|
10252
|
+
const text = JSON.stringify(images);
|
|
10253
|
+
applyCarouselValue(key, images);
|
|
10254
|
+
editContentRef.current = { ...editContentRef.current, [key]: text };
|
|
10255
|
+
postToParentRef.current({ type: "ow:change", nodes: [{ key, text }] });
|
|
10256
|
+
setCarouselHover(null);
|
|
10257
|
+
};
|
|
10258
|
+
const findCarouselAtPoint = (clientX, clientY) => {
|
|
10259
|
+
const containers = Array.from(document.querySelectorAll(`[${CAROUSEL_ATTR}]`));
|
|
10260
|
+
for (let i = containers.length - 1; i >= 0; i--) {
|
|
10261
|
+
const r2 = containers[i].getBoundingClientRect();
|
|
10262
|
+
if (clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom) {
|
|
10263
|
+
return containers[i];
|
|
10264
|
+
}
|
|
10265
|
+
}
|
|
10266
|
+
return null;
|
|
10267
|
+
};
|
|
10268
|
+
const isPointOverEditable = (scope, clientX, clientY) => {
|
|
10269
|
+
const editables = scope.querySelectorAll("[data-ohw-editable], [data-ohw-href-key]");
|
|
10270
|
+
for (const el of editables) {
|
|
10271
|
+
const r2 = el.getBoundingClientRect();
|
|
10272
|
+
if (clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom) return true;
|
|
10273
|
+
}
|
|
10274
|
+
return false;
|
|
10275
|
+
};
|
|
10276
|
+
const handleCarouselHover = (e) => {
|
|
10277
|
+
const container = findCarouselAtPoint(e.clientX, e.clientY);
|
|
10278
|
+
const scope = container?.closest("[data-ohw-section]") ?? container?.parentElement ?? null;
|
|
10279
|
+
if (!container || !scope || isPointOverEditable(scope, e.clientX, e.clientY)) {
|
|
10280
|
+
setCarouselHover((prev) => prev ? null : prev);
|
|
10281
|
+
return;
|
|
10282
|
+
}
|
|
10283
|
+
const key = container.getAttribute("data-ohw-key") ?? "";
|
|
10284
|
+
if (!key) return;
|
|
10285
|
+
const r2 = getVisibleRect(container);
|
|
10286
|
+
setCarouselHover(
|
|
10287
|
+
(prev) => prev && prev.key === key && prev.rect.top === r2.top && prev.rect.left === r2.left && prev.rect.width === r2.width && prev.rect.height === r2.height ? prev : { key, rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height } }
|
|
10288
|
+
);
|
|
10289
|
+
};
|
|
8083
10290
|
const applyToolbarPos = (rect) => {
|
|
8084
10291
|
const ps = parentScrollRef.current;
|
|
8085
10292
|
const approxW = 330;
|
|
@@ -8139,9 +10346,45 @@ function OhhwellsBridge() {
|
|
|
8139
10346
|
return clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom;
|
|
8140
10347
|
});
|
|
8141
10348
|
if (textEditable) {
|
|
8142
|
-
|
|
10349
|
+
const hrefCtx = getHrefKeyFromElement(textEditable);
|
|
10350
|
+
const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
|
|
10351
|
+
if (navAnchor) {
|
|
10352
|
+
if (selectedElRef.current === navAnchor) {
|
|
10353
|
+
activateRef.current(textEditable, { caretX: clientX, caretY: clientY });
|
|
10354
|
+
} else {
|
|
10355
|
+
selectRef.current(navAnchor);
|
|
10356
|
+
}
|
|
10357
|
+
return;
|
|
10358
|
+
}
|
|
10359
|
+
activateRef.current(textEditable, { caretX: clientX, caretY: clientY });
|
|
8143
10360
|
return;
|
|
8144
10361
|
}
|
|
10362
|
+
const navContainer = document.querySelector("[data-ohw-nav-container]");
|
|
10363
|
+
if (navContainer) {
|
|
10364
|
+
const r2 = navContainer.getBoundingClientRect();
|
|
10365
|
+
const pad = 8;
|
|
10366
|
+
const over = clientX >= r2.left - pad && clientX <= r2.right + pad && clientY >= r2.top - pad && clientY <= r2.bottom + pad;
|
|
10367
|
+
if (over && !isPointOverNavItem(navContainer, clientX, clientY)) {
|
|
10368
|
+
selectFrameRef.current(navContainer);
|
|
10369
|
+
return;
|
|
10370
|
+
}
|
|
10371
|
+
}
|
|
10372
|
+
const navRoot = document.querySelector("[data-ohw-nav-root]");
|
|
10373
|
+
if (navRoot && navContainer) {
|
|
10374
|
+
const rr = navRoot.getBoundingClientRect();
|
|
10375
|
+
if (clientX >= rr.left && clientX <= rr.right && clientY >= rr.top && clientY <= rr.bottom && !isPointOverNavItem(navContainer, clientX, clientY)) {
|
|
10376
|
+
const book = navRoot.querySelector('[data-ohw-role="navbar-button"]');
|
|
10377
|
+
if (book) {
|
|
10378
|
+
const br = book.getBoundingClientRect();
|
|
10379
|
+
if (clientX >= br.left && clientX <= br.right && clientY >= br.top && clientY <= br.bottom) {
|
|
10380
|
+
deactivateRef.current();
|
|
10381
|
+
return;
|
|
10382
|
+
}
|
|
10383
|
+
}
|
|
10384
|
+
selectFrameRef.current(navContainer);
|
|
10385
|
+
return;
|
|
10386
|
+
}
|
|
10387
|
+
}
|
|
8145
10388
|
deactivateRef.current();
|
|
8146
10389
|
};
|
|
8147
10390
|
window.addEventListener("message", handleSave);
|
|
@@ -8152,6 +10395,7 @@ function OhhwellsBridge() {
|
|
|
8152
10395
|
window.addEventListener("message", handleRemoveSchedulingSection);
|
|
8153
10396
|
window.addEventListener("message", handleImageUrl);
|
|
8154
10397
|
window.addEventListener("message", handleImageUploading);
|
|
10398
|
+
window.addEventListener("message", handleCarouselChange);
|
|
8155
10399
|
window.addEventListener("message", handleCanvasHeight);
|
|
8156
10400
|
window.addEventListener("message", handleParentScroll);
|
|
8157
10401
|
window.addEventListener("message", handlePointerSync);
|
|
@@ -8163,11 +10407,13 @@ function OhhwellsBridge() {
|
|
|
8163
10407
|
};
|
|
8164
10408
|
window.addEventListener("resize", handleViewportResize, { passive: true });
|
|
8165
10409
|
document.addEventListener("click", handleClick, true);
|
|
10410
|
+
document.addEventListener("dblclick", handleDblClick, true);
|
|
8166
10411
|
document.addEventListener("paste", handlePaste, true);
|
|
8167
10412
|
document.addEventListener("input", handleInput, true);
|
|
8168
10413
|
document.addEventListener("mouseover", handleMouseOver, true);
|
|
8169
10414
|
document.addEventListener("mouseout", handleMouseOut, true);
|
|
8170
10415
|
document.addEventListener("mousemove", handleMouseMove, true);
|
|
10416
|
+
document.addEventListener("mousemove", handleCarouselHover, true);
|
|
8171
10417
|
document.addEventListener("mouseleave", handleDocMouseLeave);
|
|
8172
10418
|
document.addEventListener("dragover", handleDragOver, true);
|
|
8173
10419
|
document.addEventListener("dragleave", handleDragLeave, true);
|
|
@@ -8177,11 +10423,13 @@ function OhhwellsBridge() {
|
|
|
8177
10423
|
window.addEventListener("scroll", handleScroll, true);
|
|
8178
10424
|
return () => {
|
|
8179
10425
|
document.removeEventListener("click", handleClick, true);
|
|
10426
|
+
document.removeEventListener("dblclick", handleDblClick, true);
|
|
8180
10427
|
document.removeEventListener("paste", handlePaste, true);
|
|
8181
10428
|
document.removeEventListener("input", handleInput, true);
|
|
8182
10429
|
document.removeEventListener("mouseover", handleMouseOver, true);
|
|
8183
10430
|
document.removeEventListener("mouseout", handleMouseOut, true);
|
|
8184
10431
|
document.removeEventListener("mousemove", handleMouseMove, true);
|
|
10432
|
+
document.removeEventListener("mousemove", handleCarouselHover, true);
|
|
8185
10433
|
document.removeEventListener("mouseleave", handleDocMouseLeave);
|
|
8186
10434
|
document.removeEventListener("dragover", handleDragOver, true);
|
|
8187
10435
|
document.removeEventListener("dragleave", handleDragLeave, true);
|
|
@@ -8197,6 +10445,7 @@ function OhhwellsBridge() {
|
|
|
8197
10445
|
window.removeEventListener("message", handleRemoveSchedulingSection);
|
|
8198
10446
|
window.removeEventListener("message", handleImageUrl);
|
|
8199
10447
|
window.removeEventListener("message", handleImageUploading);
|
|
10448
|
+
window.removeEventListener("message", handleCarouselChange);
|
|
8200
10449
|
window.removeEventListener("message", handleCanvasHeight);
|
|
8201
10450
|
window.removeEventListener("message", handleParentScroll);
|
|
8202
10451
|
window.removeEventListener("resize", handleViewportResize);
|
|
@@ -8204,13 +10453,165 @@ function OhhwellsBridge() {
|
|
|
8204
10453
|
window.removeEventListener("message", handleClickAt);
|
|
8205
10454
|
window.removeEventListener("message", handleHydrate);
|
|
8206
10455
|
window.removeEventListener("message", handleDeactivate);
|
|
10456
|
+
window.removeEventListener("message", handleUiEscape);
|
|
8207
10457
|
autoSaveTimers.current.forEach(clearTimeout);
|
|
8208
10458
|
autoSaveTimers.current.clear();
|
|
8209
10459
|
if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
|
|
8210
10460
|
if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
|
|
8211
10461
|
};
|
|
8212
10462
|
}, [isEditMode, refreshStateRules]);
|
|
8213
|
-
|
|
10463
|
+
useEffect8(() => {
|
|
10464
|
+
if (!isEditMode) return;
|
|
10465
|
+
const THRESHOLD = 10;
|
|
10466
|
+
const resolveWasSelected = (el) => {
|
|
10467
|
+
if (selectedElRef.current === el) return true;
|
|
10468
|
+
const activeAnchor = activeElRef.current ? getNavigationItemAnchor(activeElRef.current) : null;
|
|
10469
|
+
return activeAnchor === el;
|
|
10470
|
+
};
|
|
10471
|
+
const onPointerDown = (e) => {
|
|
10472
|
+
if (e.button !== 0) return;
|
|
10473
|
+
if (suppressNextClickRef.current && !footerDragRef.current && !footerPointerDragRef.current?.started) {
|
|
10474
|
+
suppressNextClickRef.current = false;
|
|
10475
|
+
}
|
|
10476
|
+
if (footerDragRef.current) return;
|
|
10477
|
+
const target = e.target;
|
|
10478
|
+
if (!target) return;
|
|
10479
|
+
if (target.closest('[data-ohw-drag-handle-container], [data-slot="drag-handle"], [data-ohw-toolbar], [data-ohw-item-toolbar-anchor], [data-ohw-link-popover-root]')) {
|
|
10480
|
+
return;
|
|
10481
|
+
}
|
|
10482
|
+
if (target.closest("[data-ohw-item-drag-surface]")) return;
|
|
10483
|
+
const anchor = getNavigationItemAnchor(target);
|
|
10484
|
+
const hrefKey = anchor?.getAttribute("data-ohw-href-key") ?? null;
|
|
10485
|
+
if (anchor && isFooterHrefKey(hrefKey)) {
|
|
10486
|
+
armFooterPressDrag();
|
|
10487
|
+
footerPointerDragRef.current = {
|
|
10488
|
+
el: anchor,
|
|
10489
|
+
kind: "link",
|
|
10490
|
+
startX: e.clientX,
|
|
10491
|
+
startY: e.clientY,
|
|
10492
|
+
pointerId: e.pointerId,
|
|
10493
|
+
wasSelected: resolveWasSelected(anchor),
|
|
10494
|
+
started: false
|
|
10495
|
+
};
|
|
10496
|
+
return;
|
|
10497
|
+
}
|
|
10498
|
+
const col = target.closest("[data-ohw-footer-col]");
|
|
10499
|
+
if (col && !getNavigationItemAnchor(target)) {
|
|
10500
|
+
armFooterPressDrag();
|
|
10501
|
+
footerPointerDragRef.current = {
|
|
10502
|
+
el: col,
|
|
10503
|
+
kind: "column",
|
|
10504
|
+
startX: e.clientX,
|
|
10505
|
+
startY: e.clientY,
|
|
10506
|
+
pointerId: e.pointerId,
|
|
10507
|
+
wasSelected: resolveWasSelected(col),
|
|
10508
|
+
started: false
|
|
10509
|
+
};
|
|
10510
|
+
}
|
|
10511
|
+
};
|
|
10512
|
+
const onPointerMove = (e) => {
|
|
10513
|
+
const pending = footerPointerDragRef.current;
|
|
10514
|
+
if (!pending) return;
|
|
10515
|
+
if (pending.started) {
|
|
10516
|
+
e.preventDefault();
|
|
10517
|
+
clearTextSelection();
|
|
10518
|
+
const session = footerDragRef.current;
|
|
10519
|
+
if (!session) return;
|
|
10520
|
+
const slot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(e.clientX, e.clientY, session.hrefKey) : hitTestColumnDropSlot(e.clientX, e.clientY);
|
|
10521
|
+
refreshFooterDragVisualsRef.current(session, slot, e.clientX, e.clientY);
|
|
10522
|
+
return;
|
|
10523
|
+
}
|
|
10524
|
+
const dx = e.clientX - pending.startX;
|
|
10525
|
+
const dy = e.clientY - pending.startY;
|
|
10526
|
+
if (dx * dx + dy * dy < THRESHOLD * THRESHOLD) return;
|
|
10527
|
+
e.preventDefault();
|
|
10528
|
+
pending.started = true;
|
|
10529
|
+
clearTextSelection();
|
|
10530
|
+
try {
|
|
10531
|
+
document.body.setPointerCapture(pending.pointerId);
|
|
10532
|
+
} catch {
|
|
10533
|
+
}
|
|
10534
|
+
if (linkPopoverOpenRef.current) {
|
|
10535
|
+
setLinkPopoverRef.current(null);
|
|
10536
|
+
}
|
|
10537
|
+
if (activeElRef.current) {
|
|
10538
|
+
deactivateRef.current();
|
|
10539
|
+
}
|
|
10540
|
+
if (pending.kind === "link") {
|
|
10541
|
+
const key = pending.el.getAttribute("data-ohw-href-key");
|
|
10542
|
+
if (!key) return;
|
|
10543
|
+
const column = findFooterColumnForLink(pending.el);
|
|
10544
|
+
const columns2 = listFooterColumns();
|
|
10545
|
+
beginFooterDragRef.current({
|
|
10546
|
+
kind: "link",
|
|
10547
|
+
hrefKey: key,
|
|
10548
|
+
columnEl: column,
|
|
10549
|
+
sourceColumnIndex: column ? columns2.indexOf(column) : 0,
|
|
10550
|
+
wasSelected: pending.wasSelected,
|
|
10551
|
+
draggedEl: pending.el,
|
|
10552
|
+
lastClientX: e.clientX,
|
|
10553
|
+
lastClientY: e.clientY,
|
|
10554
|
+
activeSlot: null
|
|
10555
|
+
});
|
|
10556
|
+
return;
|
|
10557
|
+
}
|
|
10558
|
+
const columns = listFooterColumns();
|
|
10559
|
+
const idx = columns.indexOf(pending.el);
|
|
10560
|
+
if (idx < 0) return;
|
|
10561
|
+
beginFooterDragRef.current({
|
|
10562
|
+
kind: "column",
|
|
10563
|
+
hrefKey: null,
|
|
10564
|
+
columnEl: pending.el,
|
|
10565
|
+
sourceColumnIndex: idx,
|
|
10566
|
+
wasSelected: pending.wasSelected,
|
|
10567
|
+
draggedEl: pending.el,
|
|
10568
|
+
lastClientX: e.clientX,
|
|
10569
|
+
lastClientY: e.clientY,
|
|
10570
|
+
activeSlot: null
|
|
10571
|
+
});
|
|
10572
|
+
};
|
|
10573
|
+
const endPointerDrag = (e) => {
|
|
10574
|
+
const pending = footerPointerDragRef.current;
|
|
10575
|
+
footerPointerDragRef.current = null;
|
|
10576
|
+
try {
|
|
10577
|
+
if (document.body.hasPointerCapture(e.pointerId)) {
|
|
10578
|
+
document.body.releasePointerCapture(e.pointerId);
|
|
10579
|
+
}
|
|
10580
|
+
} catch {
|
|
10581
|
+
}
|
|
10582
|
+
if (!pending?.started) {
|
|
10583
|
+
unlockFooterDragInteraction();
|
|
10584
|
+
return;
|
|
10585
|
+
}
|
|
10586
|
+
suppressNextClickRef.current = true;
|
|
10587
|
+
commitFooterDragRef.current(e.clientX, e.clientY);
|
|
10588
|
+
};
|
|
10589
|
+
const blockSelectStart = (e) => {
|
|
10590
|
+
if (footerDragRef.current || footerPointerDragRef.current?.started || document.documentElement.hasAttribute("data-ohw-footer-press-drag")) {
|
|
10591
|
+
e.preventDefault();
|
|
10592
|
+
}
|
|
10593
|
+
};
|
|
10594
|
+
const onDragEnd = (_e) => {
|
|
10595
|
+
if (!footerDragRef.current) return;
|
|
10596
|
+
commitFooterDragRef.current();
|
|
10597
|
+
};
|
|
10598
|
+
document.addEventListener("pointerdown", onPointerDown, true);
|
|
10599
|
+
document.addEventListener("pointermove", onPointerMove, true);
|
|
10600
|
+
document.addEventListener("pointerup", endPointerDrag, true);
|
|
10601
|
+
document.addEventListener("pointercancel", endPointerDrag, true);
|
|
10602
|
+
document.addEventListener("selectstart", blockSelectStart, true);
|
|
10603
|
+
document.addEventListener("dragend", onDragEnd, true);
|
|
10604
|
+
return () => {
|
|
10605
|
+
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
10606
|
+
document.removeEventListener("pointermove", onPointerMove, true);
|
|
10607
|
+
document.removeEventListener("pointerup", endPointerDrag, true);
|
|
10608
|
+
document.removeEventListener("pointercancel", endPointerDrag, true);
|
|
10609
|
+
document.removeEventListener("selectstart", blockSelectStart, true);
|
|
10610
|
+
document.removeEventListener("dragend", onDragEnd, true);
|
|
10611
|
+
unlockFooterDragInteraction();
|
|
10612
|
+
};
|
|
10613
|
+
}, [isEditMode]);
|
|
10614
|
+
useEffect8(() => {
|
|
8214
10615
|
const handler = (e) => {
|
|
8215
10616
|
if (e.data?.type !== "ow:request-schedule-config") return;
|
|
8216
10617
|
const insertAfterVal = e.data.insertAfter;
|
|
@@ -8226,7 +10627,7 @@ function OhhwellsBridge() {
|
|
|
8226
10627
|
window.addEventListener("message", handler);
|
|
8227
10628
|
return () => window.removeEventListener("message", handler);
|
|
8228
10629
|
}, [processConfigRequest]);
|
|
8229
|
-
|
|
10630
|
+
useEffect8(() => {
|
|
8230
10631
|
if (!isEditMode) return;
|
|
8231
10632
|
document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
|
|
8232
10633
|
el.removeAttribute("data-ohw-active-state");
|
|
@@ -8247,27 +10648,33 @@ function OhhwellsBridge() {
|
|
|
8247
10648
|
const next = { ...prev, [pathKey]: sections };
|
|
8248
10649
|
return shouldUseDevFixtures() ? { ...DEV_SECTIONS_BY_PATH, ...next } : next;
|
|
8249
10650
|
});
|
|
8250
|
-
|
|
8251
|
-
|
|
10651
|
+
postToParent2({
|
|
10652
|
+
type: "ow:ready",
|
|
10653
|
+
version: "1",
|
|
10654
|
+
path: pathname,
|
|
10655
|
+
nodes: collectEditableNodes(editContentRef.current),
|
|
10656
|
+
sections
|
|
10657
|
+
});
|
|
10658
|
+
postToParent2({ type: "ow:request-site-pages" });
|
|
8252
10659
|
}, 150);
|
|
8253
10660
|
return () => {
|
|
8254
10661
|
cancelAnimationFrame(raf);
|
|
8255
10662
|
clearTimeout(timer);
|
|
8256
10663
|
};
|
|
8257
|
-
}, [pathname, isEditMode, refreshStateRules,
|
|
8258
|
-
|
|
10664
|
+
}, [pathname, isEditMode, refreshStateRules, postToParent2]);
|
|
10665
|
+
useEffect8(() => {
|
|
8259
10666
|
scrollToHashSectionWhenReady();
|
|
8260
10667
|
const onHashChange = () => scrollToHashSectionWhenReady();
|
|
8261
10668
|
window.addEventListener("hashchange", onHashChange);
|
|
8262
10669
|
return () => window.removeEventListener("hashchange", onHashChange);
|
|
8263
10670
|
}, [pathname]);
|
|
8264
|
-
const handleCommand =
|
|
10671
|
+
const handleCommand = useCallback4((cmd) => {
|
|
8265
10672
|
document.execCommand(cmd, false);
|
|
8266
10673
|
activeElRef.current?.focus();
|
|
8267
10674
|
if (activeElRef.current) setToolbarRect(getEditMeasureEl(activeElRef.current).getBoundingClientRect());
|
|
8268
10675
|
refreshActiveCommandsRef.current();
|
|
8269
10676
|
}, []);
|
|
8270
|
-
const handleStateChange =
|
|
10677
|
+
const handleStateChange = useCallback4((state) => {
|
|
8271
10678
|
if (!activeStateElRef.current) return;
|
|
8272
10679
|
const el = activeStateElRef.current;
|
|
8273
10680
|
if (state === "Default") {
|
|
@@ -8280,18 +10687,22 @@ function OhhwellsBridge() {
|
|
|
8280
10687
|
}
|
|
8281
10688
|
setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
|
|
8282
10689
|
}, [deactivate]);
|
|
8283
|
-
const closeLinkPopover =
|
|
8284
|
-
|
|
10690
|
+
const closeLinkPopover = useCallback4(() => {
|
|
10691
|
+
addNavAfterAnchorRef.current = null;
|
|
10692
|
+
setLinkPopover(null);
|
|
10693
|
+
}, []);
|
|
10694
|
+
const openLinkPopoverForActive = useCallback4(() => {
|
|
8285
10695
|
const hrefCtx = getHrefKeyFromElement(activeElRef.current);
|
|
8286
10696
|
if (!hrefCtx) return;
|
|
8287
10697
|
bumpLinkPopoverGrace();
|
|
8288
10698
|
setLinkPopover({
|
|
8289
10699
|
key: hrefCtx.key,
|
|
8290
|
-
|
|
10700
|
+
mode: "edit",
|
|
10701
|
+
target: getLinkHref2(hrefCtx.anchor)
|
|
8291
10702
|
});
|
|
8292
10703
|
deactivate();
|
|
8293
10704
|
}, [deactivate]);
|
|
8294
|
-
const openLinkPopoverForSelected =
|
|
10705
|
+
const openLinkPopoverForSelected = useCallback4(() => {
|
|
8295
10706
|
const anchor = selectedElRef.current;
|
|
8296
10707
|
if (!anchor) return;
|
|
8297
10708
|
const key = anchor.getAttribute("data-ohw-href-key");
|
|
@@ -8299,30 +10710,83 @@ function OhhwellsBridge() {
|
|
|
8299
10710
|
bumpLinkPopoverGrace();
|
|
8300
10711
|
setLinkPopover({
|
|
8301
10712
|
key,
|
|
8302
|
-
|
|
10713
|
+
mode: "edit",
|
|
10714
|
+
target: getLinkHref2(anchor)
|
|
8303
10715
|
});
|
|
8304
10716
|
deselect();
|
|
8305
10717
|
}, [deselect]);
|
|
8306
|
-
const handleLinkPopoverSubmit =
|
|
10718
|
+
const handleLinkPopoverSubmit = useCallback4(
|
|
8307
10719
|
(target) => {
|
|
8308
|
-
|
|
8309
|
-
|
|
10720
|
+
const session = linkPopoverSessionRef.current;
|
|
10721
|
+
if (!session) return;
|
|
10722
|
+
if (session.intent === "add-nav") {
|
|
10723
|
+
const trimmed = target.trim();
|
|
10724
|
+
let href = trimmed;
|
|
10725
|
+
let label = "Untitled";
|
|
10726
|
+
if (trimmed) {
|
|
10727
|
+
const { pageRoute, sectionId } = parseTarget(trimmed);
|
|
10728
|
+
const page = resolvePage(pageRoute, sitePages);
|
|
10729
|
+
const pageSections = getSectionsForPath(sectionsByPath, pageRoute);
|
|
10730
|
+
const section = sectionId ? pageSections.find((s) => s.id === sectionId) : void 0;
|
|
10731
|
+
label = section?.label ?? page.title;
|
|
10732
|
+
href = trimmed;
|
|
10733
|
+
}
|
|
10734
|
+
const afterAnchor = addNavAfterAnchorRef.current;
|
|
10735
|
+
const { anchor, hrefKey, labelKey, index, order } = insertNavbarItem(href, label, afterAnchor);
|
|
10736
|
+
applyLinkByKey(hrefKey, href);
|
|
10737
|
+
document.querySelectorAll(`[data-ohw-key="${labelKey}"]`).forEach((el) => {
|
|
10738
|
+
el.textContent = label;
|
|
10739
|
+
});
|
|
10740
|
+
const navCount = String(index + 1);
|
|
10741
|
+
const orderJson = JSON.stringify(order);
|
|
10742
|
+
editContentRef.current = {
|
|
10743
|
+
...editContentRef.current,
|
|
10744
|
+
[hrefKey]: href,
|
|
10745
|
+
[labelKey]: label,
|
|
10746
|
+
[NAV_COUNT_KEY]: navCount,
|
|
10747
|
+
[NAV_ORDER_KEY]: orderJson
|
|
10748
|
+
};
|
|
10749
|
+
postToParent2({
|
|
10750
|
+
type: "ow:change",
|
|
10751
|
+
nodes: [
|
|
10752
|
+
{ key: hrefKey, text: href },
|
|
10753
|
+
{ key: labelKey, text: label },
|
|
10754
|
+
{ key: NAV_COUNT_KEY, text: navCount },
|
|
10755
|
+
{ key: NAV_ORDER_KEY, text: orderJson }
|
|
10756
|
+
]
|
|
10757
|
+
});
|
|
10758
|
+
postToParent2({ type: "ow:toast", title: "Link added", toastType: "success" });
|
|
10759
|
+
addNavAfterAnchorRef.current = null;
|
|
10760
|
+
setLinkPopover(null);
|
|
10761
|
+
enforceLinkHrefs();
|
|
10762
|
+
requestAnimationFrame(() => {
|
|
10763
|
+
selectRef.current(anchor);
|
|
10764
|
+
});
|
|
10765
|
+
return;
|
|
10766
|
+
}
|
|
10767
|
+
const { key } = session;
|
|
8310
10768
|
applyLinkByKey(key, target);
|
|
8311
|
-
|
|
10769
|
+
postToParent2({ type: "ow:change", nodes: [{ key, text: target }] });
|
|
8312
10770
|
setLinkPopover(null);
|
|
8313
10771
|
},
|
|
8314
|
-
[
|
|
10772
|
+
[postToParent2, sitePages, sectionsByPath]
|
|
8315
10773
|
);
|
|
8316
|
-
const
|
|
8317
|
-
|
|
8318
|
-
|
|
8319
|
-
|
|
10774
|
+
const handleMediaReplace = useCallback4(
|
|
10775
|
+
(key) => {
|
|
10776
|
+
if (mediaHover?.key === key) {
|
|
10777
|
+
pendingUploadRectRef.current = { key, rect: mediaHover.rect };
|
|
10778
|
+
}
|
|
10779
|
+
postToParent2({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
|
|
10780
|
+
},
|
|
10781
|
+
[postToParent2, mediaHover]
|
|
10782
|
+
);
|
|
10783
|
+
const handleEditCarousel = useCallback4(
|
|
8320
10784
|
(key) => {
|
|
8321
|
-
|
|
10785
|
+
postToParent2({ type: "ow:carousel-open", key, images: readCarouselValue(key) });
|
|
8322
10786
|
},
|
|
8323
|
-
[
|
|
10787
|
+
[postToParent2]
|
|
8324
10788
|
);
|
|
8325
|
-
const handleMediaFadeOutComplete =
|
|
10789
|
+
const handleMediaFadeOutComplete = useCallback4((key) => {
|
|
8326
10790
|
setUploadingRects((prev) => {
|
|
8327
10791
|
if (!(key in prev)) return prev;
|
|
8328
10792
|
const next = { ...prev };
|
|
@@ -8330,7 +10794,7 @@ function OhhwellsBridge() {
|
|
|
8330
10794
|
return next;
|
|
8331
10795
|
});
|
|
8332
10796
|
}, []);
|
|
8333
|
-
const handleVideoSettingsChange =
|
|
10797
|
+
const handleVideoSettingsChange = useCallback4(
|
|
8334
10798
|
(key, settings) => {
|
|
8335
10799
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
8336
10800
|
const video = getVideoEl(el);
|
|
@@ -8338,7 +10802,7 @@ function OhhwellsBridge() {
|
|
|
8338
10802
|
if (typeof settings.autoplay === "boolean") video.autoplay = settings.autoplay;
|
|
8339
10803
|
if (typeof settings.muted === "boolean") video.muted = settings.muted;
|
|
8340
10804
|
syncVideoPlayback(video);
|
|
8341
|
-
|
|
10805
|
+
postToParent2({
|
|
8342
10806
|
type: "ow:change",
|
|
8343
10807
|
nodes: [
|
|
8344
10808
|
{ key: `${key}${VIDEO_AUTOPLAY_SUFFIX}`, text: String(video.autoplay) },
|
|
@@ -8350,23 +10814,28 @@ function OhhwellsBridge() {
|
|
|
8350
10814
|
);
|
|
8351
10815
|
});
|
|
8352
10816
|
},
|
|
8353
|
-
[
|
|
10817
|
+
[postToParent2]
|
|
8354
10818
|
);
|
|
8355
|
-
|
|
8356
|
-
|
|
8357
|
-
|
|
8358
|
-
|
|
8359
|
-
|
|
8360
|
-
|
|
8361
|
-
|
|
8362
|
-
|
|
8363
|
-
|
|
8364
|
-
|
|
8365
|
-
|
|
8366
|
-
|
|
8367
|
-
|
|
8368
|
-
|
|
8369
|
-
|
|
10819
|
+
const showEditLink = toolbarShowEditLink;
|
|
10820
|
+
const currentSections = sectionsByPath[pathname] ?? [];
|
|
10821
|
+
linkPopoverOpenRef.current = linkPopover !== null;
|
|
10822
|
+
return bridgeRoot ? createPortal2(
|
|
10823
|
+
/* @__PURE__ */ jsxs14(Fragment5, { children: [
|
|
10824
|
+
/* @__PURE__ */ jsx25("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
|
|
10825
|
+
Object.entries(uploadingRects).flatMap(
|
|
10826
|
+
([key, { rects, fadingOut }]) => rects.map((rect, i) => /* @__PURE__ */ jsx25(
|
|
10827
|
+
MediaOverlay,
|
|
10828
|
+
{
|
|
10829
|
+
hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
|
|
10830
|
+
isUploading: true,
|
|
10831
|
+
fadingOut,
|
|
10832
|
+
onFadeOutComplete: handleMediaFadeOutComplete,
|
|
10833
|
+
onReplace: handleMediaReplace
|
|
10834
|
+
},
|
|
10835
|
+
`uploading-${key}-${i}`
|
|
10836
|
+
))
|
|
10837
|
+
),
|
|
10838
|
+
mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ jsx25(
|
|
8370
10839
|
MediaOverlay,
|
|
8371
10840
|
{
|
|
8372
10841
|
hover: mediaHover,
|
|
@@ -8375,53 +10844,33 @@ function OhhwellsBridge() {
|
|
|
8375
10844
|
onVideoSettingsChange: handleVideoSettingsChange
|
|
8376
10845
|
}
|
|
8377
10846
|
),
|
|
8378
|
-
|
|
8379
|
-
|
|
8380
|
-
|
|
8381
|
-
|
|
10847
|
+
carouselHover && /* @__PURE__ */ jsx25(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
|
|
10848
|
+
siblingHintRect && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
|
|
10849
|
+
siblingHintRects.map((rect, i) => /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
|
|
10850
|
+
isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
|
|
10851
|
+
isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ jsx25(
|
|
10852
|
+
"div",
|
|
8382
10853
|
{
|
|
8383
|
-
|
|
8384
|
-
|
|
8385
|
-
|
|
8386
|
-
|
|
8387
|
-
|
|
8388
|
-
|
|
8389
|
-
|
|
8390
|
-
|
|
8391
|
-
|
|
8392
|
-
|
|
8393
|
-
|
|
8394
|
-
|
|
8395
|
-
|
|
8396
|
-
|
|
8397
|
-
|
|
8398
|
-
|
|
8399
|
-
}
|
|
8400
|
-
|
|
8401
|
-
toolbarRect && toolbarVariant === "rich-text" && /* @__PURE__ */ jsxs12(Fragment4, { children: [
|
|
8402
|
-
/* @__PURE__ */ jsx22(
|
|
8403
|
-
EditGlowChrome,
|
|
8404
|
-
{
|
|
8405
|
-
rect: toolbarRect,
|
|
8406
|
-
elRef: glowElRef,
|
|
8407
|
-
reorderHrefKey,
|
|
8408
|
-
dragDisabled: reorderDragDisabled
|
|
8409
|
-
}
|
|
8410
|
-
),
|
|
8411
|
-
/* @__PURE__ */ jsx22(
|
|
8412
|
-
FloatingToolbar,
|
|
8413
|
-
{
|
|
8414
|
-
rect: toolbarRect,
|
|
8415
|
-
parentScroll: parentScrollRef.current,
|
|
8416
|
-
elRef: toolbarElRef,
|
|
8417
|
-
onCommand: handleCommand,
|
|
8418
|
-
activeCommands,
|
|
8419
|
-
showEditLink,
|
|
8420
|
-
onEditLink: openLinkPopoverForActive
|
|
8421
|
-
}
|
|
8422
|
-
)
|
|
10854
|
+
className: "pointer-events-none fixed z-2147483646",
|
|
10855
|
+
style: {
|
|
10856
|
+
left: slot.left,
|
|
10857
|
+
top: slot.top,
|
|
10858
|
+
width: slot.width,
|
|
10859
|
+
height: slot.height
|
|
10860
|
+
},
|
|
10861
|
+
children: /* @__PURE__ */ jsx25(DropIndicator, { direction: slot.direction, state: activeFooterDropIndex === i ? "dragActive" : "dragIdle", className: slot.direction === "horizontal" ? "!h-full !w-full" : "!h-full !w-full" })
|
|
10862
|
+
},
|
|
10863
|
+
`footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
|
|
10864
|
+
)),
|
|
10865
|
+
hoveredNavContainerRect && toolbarVariant !== "select-frame" && !linkPopover && !isItemDragging && !siblingHintRect && siblingHintRects.length === 0 && /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
|
|
10866
|
+
toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && /* @__PURE__ */ jsx25(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
|
|
10867
|
+
hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !siblingHintRect && siblingHintRects.length === 0 && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
|
|
10868
|
+
toolbarRect && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect: isItemDragging && draggedItemRect && footerDragRef.current?.wasSelected ? draggedItemRect : toolbarRect, elRef: glowElRef, state: isItemDragging ? "dragging" : resolveItemInteractionState(toolbarRect, parentScrollRef.current), showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey) || toolbarVariant === "select-frame" && isFooterFrameSelection, dragDisabled: reorderDragDisabled, dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item", onDragHandleDragStart: handleItemDragStart, onDragHandleDragEnd: handleItemDragEnd, onItemPointerDown: handleItemChromePointerDown, onItemClick: handleItemChromeClick, toolbar: toolbarVariant === "link-action" && !isItemDragging ? /* @__PURE__ */ jsx25(ItemActionToolbar, { onEditLink: openLinkPopoverForSelected, addItemDisabled: true, editLinkDisabled: false, moreDisabled: true }) : void 0 }),
|
|
10869
|
+
toolbarRect && toolbarVariant === "rich-text" && /* @__PURE__ */ jsxs14(Fragment5, { children: [
|
|
10870
|
+
/* @__PURE__ */ jsx25(EditGlowChrome, { rect: toolbarRect, elRef: glowElRef, reorderHrefKey, dragDisabled: reorderDragDisabled }),
|
|
10871
|
+
/* @__PURE__ */ jsx25(FloatingToolbar, { rect: toolbarRect, parentScroll: parentScrollRef.current, elRef: toolbarElRef, onCommand: handleCommand, activeCommands, showEditLink, onEditLink: openLinkPopoverForActive })
|
|
8423
10872
|
] }),
|
|
8424
|
-
maxBadge && /* @__PURE__ */
|
|
10873
|
+
maxBadge && /* @__PURE__ */ jsxs14(
|
|
8425
10874
|
"div",
|
|
8426
10875
|
{
|
|
8427
10876
|
"data-ohw-max-badge": "",
|
|
@@ -8447,56 +10896,29 @@ function OhhwellsBridge() {
|
|
|
8447
10896
|
]
|
|
8448
10897
|
}
|
|
8449
10898
|
),
|
|
8450
|
-
toggleState && /* @__PURE__ */
|
|
8451
|
-
|
|
8452
|
-
{
|
|
8453
|
-
|
|
8454
|
-
|
|
8455
|
-
|
|
8456
|
-
|
|
8457
|
-
|
|
8458
|
-
|
|
8459
|
-
|
|
8460
|
-
|
|
8461
|
-
|
|
8462
|
-
|
|
8463
|
-
className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
|
|
8464
|
-
style: { top: sectionGap.y, transform: "translateY(-50%)" },
|
|
8465
|
-
children: [
|
|
8466
|
-
/* @__PURE__ */ jsx22("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
|
|
8467
|
-
/* @__PURE__ */ jsx22(
|
|
8468
|
-
Badge,
|
|
8469
|
-
{
|
|
8470
|
-
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",
|
|
8471
|
-
onClick: () => {
|
|
8472
|
-
window.parent.postMessage(
|
|
8473
|
-
{ type: "ow:add-section", insertAfter: sectionGap.insertAfter, insertBefore: sectionGap.insertBefore },
|
|
8474
|
-
"*"
|
|
8475
|
-
);
|
|
10899
|
+
toggleState && !linkPopover && /* @__PURE__ */ jsx25(StateToggle, { rect: toggleState.rect, activeState: toggleState.activeState, states: toggleState.states, onStateChange: handleStateChange }),
|
|
10900
|
+
sectionGap && !linkPopover && /* @__PURE__ */ jsxs14("div", { "data-ohw-section-insert-line": "", className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none", style: { top: sectionGap.y, transform: "translateY(-50%)" }, children: [
|
|
10901
|
+
/* @__PURE__ */ jsx25("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
|
|
10902
|
+
/* @__PURE__ */ jsx25(
|
|
10903
|
+
Badge,
|
|
10904
|
+
{
|
|
10905
|
+
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",
|
|
10906
|
+
onClick: () => {
|
|
10907
|
+
window.parent.postMessage(
|
|
10908
|
+
{
|
|
10909
|
+
type: "ow:add-section",
|
|
10910
|
+
insertAfter: sectionGap.insertAfter,
|
|
10911
|
+
insertBefore: sectionGap.insertBefore
|
|
8476
10912
|
},
|
|
8477
|
-
|
|
8478
|
-
|
|
8479
|
-
|
|
8480
|
-
|
|
8481
|
-
|
|
8482
|
-
|
|
8483
|
-
|
|
8484
|
-
|
|
8485
|
-
|
|
8486
|
-
{
|
|
8487
|
-
panelRef: linkPopoverPanelRef,
|
|
8488
|
-
portalContainer: dialogPortalContainer,
|
|
8489
|
-
open: true,
|
|
8490
|
-
mode: "edit",
|
|
8491
|
-
pages: sitePages,
|
|
8492
|
-
sections: currentSections,
|
|
8493
|
-
sectionsByPath,
|
|
8494
|
-
initialTarget: linkPopover.target,
|
|
8495
|
-
onClose: closeLinkPopover,
|
|
8496
|
-
onSubmit: handleLinkPopoverSubmit
|
|
8497
|
-
},
|
|
8498
|
-
`${linkPopover.key}-${pathname}`
|
|
8499
|
-
) : null
|
|
10913
|
+
"*"
|
|
10914
|
+
);
|
|
10915
|
+
},
|
|
10916
|
+
children: "Add Section"
|
|
10917
|
+
}
|
|
10918
|
+
),
|
|
10919
|
+
/* @__PURE__ */ jsx25("div", { className: "flex-1 bg-primary", style: { height: 3 } })
|
|
10920
|
+
] }),
|
|
10921
|
+
linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx25(LinkPopover, { panelRef: linkPopoverPanelRef, portalContainer: dialogPortalContainer, open: true, mode: linkPopover.mode ?? "edit", pages: sitePages, sections: currentSections, sectionsByPath, initialTarget: linkPopover.target, existingTargets: linkPopover.intent === "add-nav" ? getNavbarExistingTargets() : [], onClose: closeLinkPopover, onSubmit: handleLinkPopoverSubmit }, linkPopover.key) : null
|
|
8500
10922
|
] }),
|
|
8501
10923
|
bridgeRoot
|
|
8502
10924
|
) : null;
|
|
@@ -8506,6 +10928,7 @@ export {
|
|
|
8506
10928
|
CustomToolbarButton,
|
|
8507
10929
|
CustomToolbarDivider,
|
|
8508
10930
|
DragHandle,
|
|
10931
|
+
DropIndicator,
|
|
8509
10932
|
ItemActionToolbar,
|
|
8510
10933
|
ItemInteractionLayer,
|
|
8511
10934
|
LinkEditorPanel,
|
|
@@ -8520,12 +10943,14 @@ export {
|
|
|
8520
10943
|
TooltipProvider,
|
|
8521
10944
|
TooltipTrigger,
|
|
8522
10945
|
buildTarget,
|
|
10946
|
+
dropIndicatorVariants,
|
|
8523
10947
|
filterAvailablePages,
|
|
8524
10948
|
getEditModeInitialState,
|
|
8525
10949
|
isEditSessionActive,
|
|
8526
10950
|
isValidUrl,
|
|
8527
10951
|
parseTarget,
|
|
8528
10952
|
toggleVariants,
|
|
10953
|
+
useOhwCarousel,
|
|
8529
10954
|
validateUrlInput
|
|
8530
10955
|
};
|
|
8531
10956
|
//# sourceMappingURL=index.js.map
|