@ohhwells/bridge 0.1.41 → 0.1.42-next.81
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 +1737 -489
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +48 -3
- package/dist/index.d.ts +48 -3
- package/dist/index.js +1688 -443
- package/dist/index.js.map +1 -1
- package/dist/styles.css +42 -18
- 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
|
|
|
@@ -48,12 +48,13 @@ function useLinkHrefGuardian(...deps) {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
// src/ui/SchedulingWidget.tsx
|
|
51
|
-
import { useEffect, useId, useMemo, useRef, useState as useState2 } from "react";
|
|
51
|
+
import { useCallback, useEffect, useId, useMemo, useRef, useState as useState2 } from "react";
|
|
52
52
|
|
|
53
53
|
// src/ui/EmailCaptureModal.tsx
|
|
54
54
|
import { useState } from "react";
|
|
55
55
|
import { Dialog } from "radix-ui";
|
|
56
56
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
57
|
+
var isValidEmail = (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
|
|
57
58
|
function Spinner() {
|
|
58
59
|
return /* @__PURE__ */ jsxs(
|
|
59
60
|
"svg",
|
|
@@ -87,12 +88,17 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
|
|
|
87
88
|
const [error, setError] = useState(null);
|
|
88
89
|
const isBook = title === "Confirm your spot";
|
|
89
90
|
const handleSubmit = async () => {
|
|
90
|
-
|
|
91
|
+
const trimmed = email.trim();
|
|
92
|
+
if (!trimmed) return;
|
|
93
|
+
if (!isValidEmail(trimmed)) {
|
|
94
|
+
setError("Please enter a valid email address.");
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
91
97
|
setLoading(true);
|
|
92
98
|
setError(null);
|
|
93
99
|
try {
|
|
94
|
-
await onSubmit(
|
|
95
|
-
setSubmittedEmail(
|
|
100
|
+
await onSubmit(trimmed);
|
|
101
|
+
setSubmittedEmail(trimmed);
|
|
96
102
|
setSuccess(true);
|
|
97
103
|
} catch (e) {
|
|
98
104
|
setError(e instanceof Error ? e.message : "Something went wrong. Please try again.");
|
|
@@ -167,7 +173,10 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
|
|
|
167
173
|
{
|
|
168
174
|
type: "email",
|
|
169
175
|
value: email,
|
|
170
|
-
onChange: (e) =>
|
|
176
|
+
onChange: (e) => {
|
|
177
|
+
setEmail(e.target.value);
|
|
178
|
+
if (error) setError(null);
|
|
179
|
+
},
|
|
171
180
|
onKeyDown: handleKeyDown,
|
|
172
181
|
placeholder: "hello@gmail.com",
|
|
173
182
|
autoFocus: true,
|
|
@@ -224,12 +233,20 @@ function formatClassTime(cls) {
|
|
|
224
233
|
const em = endTotal % 60;
|
|
225
234
|
return `${h}:${cls.startTime.minutes}-${eh}:${String(em).padStart(2, "0")}`;
|
|
226
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
|
+
}
|
|
227
241
|
function getBookingsOnDate(cls, date) {
|
|
228
242
|
if (!cls.bookings?.length) return 0;
|
|
229
|
-
const
|
|
243
|
+
const target = new Date(date);
|
|
244
|
+
target.setHours(0, 0, 0, 0);
|
|
230
245
|
return cls.bookings.filter((b) => {
|
|
231
246
|
try {
|
|
232
|
-
|
|
247
|
+
const bookingDate = new Date(b.classDate);
|
|
248
|
+
bookingDate.setHours(0, 0, 0, 0);
|
|
249
|
+
return bookingDate.getTime() === target.getTime();
|
|
233
250
|
} catch {
|
|
234
251
|
return false;
|
|
235
252
|
}
|
|
@@ -494,7 +511,7 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
|
|
|
494
511
|
}
|
|
495
512
|
)
|
|
496
513
|
] }),
|
|
497
|
-
/* @__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: [
|
|
498
515
|
/* @__PURE__ */ jsxs2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: [
|
|
499
516
|
available,
|
|
500
517
|
"/",
|
|
@@ -506,9 +523,10 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
|
|
|
506
523
|
/* @__PURE__ */ jsxs2("div", { className: "flex flex-1 flex-col gap-2 min-w-0 sm:contents", children: [
|
|
507
524
|
/* @__PURE__ */ jsxs2("div", { className: "flex-1 flex flex-col gap-2 min-w-0", children: [
|
|
508
525
|
/* @__PURE__ */ jsx2("span", { className: "font-body text-base font-bold text-(--color-dark,#200C02) block truncate", children: cls.name }),
|
|
509
|
-
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 })
|
|
510
528
|
] }),
|
|
511
|
-
/* @__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: [
|
|
512
530
|
/* @__PURE__ */ jsxs2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: [
|
|
513
531
|
available,
|
|
514
532
|
"/",
|
|
@@ -533,7 +551,7 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
|
|
|
533
551
|
if (!cls.id) return;
|
|
534
552
|
onOpenModal?.(isFull ? "waitlist" : "book", cls.id, selectedDate);
|
|
535
553
|
},
|
|
536
|
-
children: isFull ? "Join Waitlist" :
|
|
554
|
+
children: isFull ? "Join Waitlist" : formatBookingLabel(cls)
|
|
537
555
|
}
|
|
538
556
|
)
|
|
539
557
|
] })
|
|
@@ -575,6 +593,17 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
575
593
|
const [isHovered, setIsHovered] = useState2(false);
|
|
576
594
|
const [modalState, setModalState] = useState2(null);
|
|
577
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
|
+
}, []);
|
|
578
607
|
const dates = useMemo(() => {
|
|
579
608
|
const today = /* @__PURE__ */ new Date();
|
|
580
609
|
today.setHours(0, 0, 0, 0);
|
|
@@ -594,6 +623,18 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
594
623
|
}
|
|
595
624
|
}
|
|
596
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]);
|
|
597
638
|
useEffect(() => {
|
|
598
639
|
if (typeof window === "undefined") return;
|
|
599
640
|
const isInEditor = window.self !== window.top;
|
|
@@ -655,7 +696,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
655
696
|
setLoading(false);
|
|
656
697
|
return;
|
|
657
698
|
}
|
|
658
|
-
;
|
|
699
|
+
liveScheduleIdRef.current = effectiveId;
|
|
659
700
|
(async () => {
|
|
660
701
|
try {
|
|
661
702
|
const res = await fetch(`${API_URL}/api/schedule/id/${effectiveId}`);
|
|
@@ -712,18 +753,14 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
712
753
|
const data = await res.json().catch(() => ({}));
|
|
713
754
|
throw new Error(data?.message ?? "Something went wrong. Please try again.");
|
|
714
755
|
}
|
|
756
|
+
await refetchLiveSchedule();
|
|
715
757
|
};
|
|
716
758
|
const handleReplaceSchedule = () => {
|
|
717
759
|
setIsHovered(false);
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
insertAfter
|
|
723
|
-
}, "*");
|
|
724
|
-
} else {
|
|
725
|
-
window.parent.postMessage({ type: "ow:scheduling-not-connected", insertAfter }, "*");
|
|
726
|
-
}
|
|
760
|
+
window.parent.postMessage(
|
|
761
|
+
{ type: "ow:scheduling-not-connected", insertAfter, currentScheduleId: schedule?.id },
|
|
762
|
+
"*"
|
|
763
|
+
);
|
|
727
764
|
};
|
|
728
765
|
if (!inEditor && !loading && !schedule) return null;
|
|
729
766
|
const sectionId = `scheduling-${insertAfter}`;
|
|
@@ -766,7 +803,19 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
766
803
|
),
|
|
767
804
|
/* @__PURE__ */ jsxs2("div", { className: "max-w-[1280px] mx-auto flex flex-col items-center gap-16", children: [
|
|
768
805
|
/* @__PURE__ */ jsxs2("div", { className: "flex flex-col items-center gap-4", children: [
|
|
769
|
-
/* @__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
|
+
),
|
|
770
819
|
schedule?.description && /* @__PURE__ */ jsx2("p", { className: "font-body text-body text-center m-0 text-(--color-accent,#A89B83)", children: schedule.description })
|
|
771
820
|
] }),
|
|
772
821
|
/* @__PURE__ */ jsxs2("div", { className: "w-full flex flex-col items-end gap-3", children: [
|
|
@@ -4444,7 +4493,7 @@ function getChromeStyle(state) {
|
|
|
4444
4493
|
case "dragging":
|
|
4445
4494
|
return {
|
|
4446
4495
|
border: `2px solid ${PRIMARY}`,
|
|
4447
|
-
boxShadow: DRAG_SHADOW
|
|
4496
|
+
boxShadow: `${FOCUS_RING}, ${DRAG_SHADOW}`
|
|
4448
4497
|
};
|
|
4449
4498
|
default:
|
|
4450
4499
|
return {};
|
|
@@ -4460,6 +4509,8 @@ function ItemInteractionLayer({
|
|
|
4460
4509
|
dragHandleLabel = "Reorder item",
|
|
4461
4510
|
onDragHandleDragStart,
|
|
4462
4511
|
onDragHandleDragEnd,
|
|
4512
|
+
onItemPointerDown,
|
|
4513
|
+
onItemClick,
|
|
4463
4514
|
chromeGap = 6,
|
|
4464
4515
|
className
|
|
4465
4516
|
}) {
|
|
@@ -4467,7 +4518,8 @@ function ItemInteractionLayer({
|
|
|
4467
4518
|
const isActive = state === "active-top" || state === "active-bottom";
|
|
4468
4519
|
const isDragging = state === "dragging";
|
|
4469
4520
|
const showToolbar = isActive && toolbar;
|
|
4470
|
-
const showDragHandle = isActive
|
|
4521
|
+
const showDragHandle = (isActive || isDragging) && showHandle;
|
|
4522
|
+
const itemDragEnabled = isActive && showHandle && !isDragging && !dragDisabled;
|
|
4471
4523
|
return /* @__PURE__ */ jsxs4(
|
|
4472
4524
|
"div",
|
|
4473
4525
|
{
|
|
@@ -4492,11 +4544,28 @@ function ItemInteractionLayer({
|
|
|
4492
4544
|
style: getChromeStyle(state)
|
|
4493
4545
|
}
|
|
4494
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
|
+
),
|
|
4495
4563
|
showDragHandle && /* @__PURE__ */ jsx9(
|
|
4496
4564
|
"div",
|
|
4497
4565
|
{
|
|
4498
4566
|
"data-ohw-drag-handle-container": "",
|
|
4499
|
-
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,
|
|
4500
4569
|
children: /* @__PURE__ */ jsx9(
|
|
4501
4570
|
DragHandle,
|
|
4502
4571
|
{
|
|
@@ -4719,15 +4788,12 @@ function MediaOverlay({
|
|
|
4719
4788
|
className: "flex items-center justify-center cursor-pointer",
|
|
4720
4789
|
style: {
|
|
4721
4790
|
...box,
|
|
4722
|
-
//
|
|
4723
|
-
//
|
|
4724
|
-
|
|
4725
|
-
// Replace still works.
|
|
4726
|
-
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",
|
|
4727
4794
|
boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
|
|
4728
4795
|
background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
|
|
4729
4796
|
},
|
|
4730
|
-
onClick: () => onReplace(hover.key),
|
|
4731
4797
|
children: /* @__PURE__ */ jsxs5(
|
|
4732
4798
|
Button,
|
|
4733
4799
|
{
|
|
@@ -4752,6 +4818,61 @@ function MediaOverlay({
|
|
|
4752
4818
|
] });
|
|
4753
4819
|
}
|
|
4754
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
|
+
|
|
4755
4876
|
// src/OhhwellsBridge.tsx
|
|
4756
4877
|
import { createPortal as createPortal2 } from "react-dom";
|
|
4757
4878
|
import { usePathname as usePathname2, useRouter as useRouter2, useSearchParams } from "next/navigation";
|
|
@@ -5038,22 +5159,22 @@ import { useEffect as useEffect6 } from "react";
|
|
|
5038
5159
|
import * as React7 from "react";
|
|
5039
5160
|
import { Dialog as DialogPrimitive } from "radix-ui";
|
|
5040
5161
|
import { X } from "lucide-react";
|
|
5041
|
-
import { jsx as
|
|
5162
|
+
import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
5042
5163
|
function Dialog2({
|
|
5043
5164
|
...props
|
|
5044
5165
|
}) {
|
|
5045
|
-
return /* @__PURE__ */
|
|
5166
|
+
return /* @__PURE__ */ jsx13(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
|
|
5046
5167
|
}
|
|
5047
5168
|
function DialogPortal({
|
|
5048
5169
|
...props
|
|
5049
5170
|
}) {
|
|
5050
|
-
return /* @__PURE__ */
|
|
5171
|
+
return /* @__PURE__ */ jsx13(DialogPrimitive.Portal, { ...props });
|
|
5051
5172
|
}
|
|
5052
5173
|
function DialogOverlay({
|
|
5053
5174
|
className,
|
|
5054
5175
|
...props
|
|
5055
5176
|
}) {
|
|
5056
|
-
return /* @__PURE__ */
|
|
5177
|
+
return /* @__PURE__ */ jsx13(
|
|
5057
5178
|
DialogPrimitive.Overlay,
|
|
5058
5179
|
{
|
|
5059
5180
|
"data-slot": "dialog-overlay",
|
|
@@ -5066,9 +5187,9 @@ function DialogOverlay({
|
|
|
5066
5187
|
var DialogContent = React7.forwardRef(
|
|
5067
5188
|
({ className, children, showCloseButton = true, container, ...props }, ref) => {
|
|
5068
5189
|
const positionMode = container ? "absolute" : "fixed";
|
|
5069
|
-
return /* @__PURE__ */
|
|
5070
|
-
/* @__PURE__ */
|
|
5071
|
-
/* @__PURE__ */
|
|
5190
|
+
return /* @__PURE__ */ jsxs7(DialogPortal, { container: container ?? void 0, children: [
|
|
5191
|
+
/* @__PURE__ */ jsx13(DialogOverlay, { className: cn(positionMode, "inset-0") }),
|
|
5192
|
+
/* @__PURE__ */ jsxs7(
|
|
5072
5193
|
DialogPrimitive.Content,
|
|
5073
5194
|
{
|
|
5074
5195
|
ref,
|
|
@@ -5084,13 +5205,13 @@ var DialogContent = React7.forwardRef(
|
|
|
5084
5205
|
...props,
|
|
5085
5206
|
children: [
|
|
5086
5207
|
children,
|
|
5087
|
-
showCloseButton ? /* @__PURE__ */
|
|
5208
|
+
showCloseButton ? /* @__PURE__ */ jsx13(
|
|
5088
5209
|
DialogPrimitive.Close,
|
|
5089
5210
|
{
|
|
5090
5211
|
type: "button",
|
|
5091
5212
|
className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
|
|
5092
5213
|
"aria-label": "Close",
|
|
5093
|
-
children: /* @__PURE__ */
|
|
5214
|
+
children: /* @__PURE__ */ jsx13(X, { size: 16, "aria-hidden": true })
|
|
5094
5215
|
}
|
|
5095
5216
|
) : null
|
|
5096
5217
|
]
|
|
@@ -5104,13 +5225,13 @@ function DialogHeader({
|
|
|
5104
5225
|
className,
|
|
5105
5226
|
...props
|
|
5106
5227
|
}) {
|
|
5107
|
-
return /* @__PURE__ */
|
|
5228
|
+
return /* @__PURE__ */ jsx13("div", { className: cn("flex flex-col gap-1.5", className), ...props });
|
|
5108
5229
|
}
|
|
5109
5230
|
function DialogFooter({
|
|
5110
5231
|
className,
|
|
5111
5232
|
...props
|
|
5112
5233
|
}) {
|
|
5113
|
-
return /* @__PURE__ */
|
|
5234
|
+
return /* @__PURE__ */ jsx13(
|
|
5114
5235
|
"div",
|
|
5115
5236
|
{
|
|
5116
5237
|
className: cn("flex items-center justify-end gap-2", className),
|
|
@@ -5118,7 +5239,7 @@ function DialogFooter({
|
|
|
5118
5239
|
}
|
|
5119
5240
|
);
|
|
5120
5241
|
}
|
|
5121
|
-
var DialogTitle = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
|
|
5242
|
+
var DialogTitle = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx13(
|
|
5122
5243
|
DialogPrimitive.Title,
|
|
5123
5244
|
{
|
|
5124
5245
|
ref,
|
|
@@ -5130,7 +5251,7 @@ var DialogTitle = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE
|
|
|
5130
5251
|
}
|
|
5131
5252
|
));
|
|
5132
5253
|
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
|
5133
|
-
var DialogDescription = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
|
|
5254
|
+
var DialogDescription = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx13(
|
|
5134
5255
|
DialogPrimitive.Description,
|
|
5135
5256
|
{
|
|
5136
5257
|
ref,
|
|
@@ -5146,19 +5267,19 @@ import { Info, X as X3 } from "lucide-react";
|
|
|
5146
5267
|
|
|
5147
5268
|
// src/ui/link-modal/DestinationBreadcrumb.tsx
|
|
5148
5269
|
import { ArrowRight, File, GalleryVertical } from "lucide-react";
|
|
5149
|
-
import { jsx as
|
|
5270
|
+
import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
5150
5271
|
function DestinationBreadcrumb({
|
|
5151
5272
|
pageTitle,
|
|
5152
5273
|
sectionLabel
|
|
5153
5274
|
}) {
|
|
5154
|
-
return /* @__PURE__ */
|
|
5155
|
-
/* @__PURE__ */
|
|
5156
|
-
/* @__PURE__ */
|
|
5157
|
-
/* @__PURE__ */
|
|
5158
|
-
/* @__PURE__ */
|
|
5159
|
-
/* @__PURE__ */
|
|
5275
|
+
return /* @__PURE__ */ jsxs8("div", { className: "flex w-full flex-col gap-2", children: [
|
|
5276
|
+
/* @__PURE__ */ jsx14("p", { className: "text-sm font-medium! text-foreground m-0", children: "Destination" }),
|
|
5277
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-3", children: [
|
|
5278
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
|
|
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 })
|
|
5160
5281
|
] }),
|
|
5161
|
-
/* @__PURE__ */
|
|
5282
|
+
/* @__PURE__ */ jsx14(
|
|
5162
5283
|
ArrowRight,
|
|
5163
5284
|
{
|
|
5164
5285
|
size: 16,
|
|
@@ -5166,8 +5287,8 @@ function DestinationBreadcrumb({
|
|
|
5166
5287
|
"aria-hidden": true
|
|
5167
5288
|
}
|
|
5168
5289
|
),
|
|
5169
|
-
/* @__PURE__ */
|
|
5170
|
-
/* @__PURE__ */
|
|
5290
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
|
|
5291
|
+
/* @__PURE__ */ jsx14(
|
|
5171
5292
|
GalleryVertical,
|
|
5172
5293
|
{
|
|
5173
5294
|
size: 16,
|
|
@@ -5175,7 +5296,7 @@ function DestinationBreadcrumb({
|
|
|
5175
5296
|
"aria-hidden": true
|
|
5176
5297
|
}
|
|
5177
5298
|
),
|
|
5178
|
-
/* @__PURE__ */
|
|
5299
|
+
/* @__PURE__ */ jsx14("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
|
|
5179
5300
|
] })
|
|
5180
5301
|
] })
|
|
5181
5302
|
] });
|
|
@@ -5183,22 +5304,22 @@ function DestinationBreadcrumb({
|
|
|
5183
5304
|
|
|
5184
5305
|
// src/ui/link-modal/SectionTreeItem.tsx
|
|
5185
5306
|
import { GalleryVertical as GalleryVertical2 } from "lucide-react";
|
|
5186
|
-
import { jsx as
|
|
5307
|
+
import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
5187
5308
|
function SectionTreeItem({
|
|
5188
5309
|
section,
|
|
5189
5310
|
onSelect,
|
|
5190
5311
|
selected
|
|
5191
5312
|
}) {
|
|
5192
5313
|
const interactive = Boolean(onSelect);
|
|
5193
|
-
return /* @__PURE__ */
|
|
5194
|
-
/* @__PURE__ */
|
|
5314
|
+
return /* @__PURE__ */ jsxs9("div", { className: "flex h-9 w-full items-end pl-3", children: [
|
|
5315
|
+
/* @__PURE__ */ jsx15(
|
|
5195
5316
|
"div",
|
|
5196
5317
|
{
|
|
5197
5318
|
className: "mr-[-1px] h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
|
|
5198
5319
|
"aria-hidden": true
|
|
5199
5320
|
}
|
|
5200
5321
|
),
|
|
5201
|
-
/* @__PURE__ */
|
|
5322
|
+
/* @__PURE__ */ jsxs9(
|
|
5202
5323
|
"div",
|
|
5203
5324
|
{
|
|
5204
5325
|
role: interactive ? "button" : void 0,
|
|
@@ -5216,7 +5337,7 @@ function SectionTreeItem({
|
|
|
5216
5337
|
interactive && selected && "border-primary"
|
|
5217
5338
|
),
|
|
5218
5339
|
children: [
|
|
5219
|
-
/* @__PURE__ */
|
|
5340
|
+
/* @__PURE__ */ jsx15(
|
|
5220
5341
|
GalleryVertical2,
|
|
5221
5342
|
{
|
|
5222
5343
|
size: 16,
|
|
@@ -5224,7 +5345,7 @@ function SectionTreeItem({
|
|
|
5224
5345
|
"aria-hidden": true
|
|
5225
5346
|
}
|
|
5226
5347
|
),
|
|
5227
|
-
/* @__PURE__ */
|
|
5348
|
+
/* @__PURE__ */ jsx15("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
|
|
5228
5349
|
]
|
|
5229
5350
|
}
|
|
5230
5351
|
)
|
|
@@ -5236,10 +5357,10 @@ import { useEffect as useEffect3, useId as useId2, useRef as useRef3, useState a
|
|
|
5236
5357
|
|
|
5237
5358
|
// src/ui/input.tsx
|
|
5238
5359
|
import * as React8 from "react";
|
|
5239
|
-
import { jsx as
|
|
5360
|
+
import { jsx as jsx16 } from "react/jsx-runtime";
|
|
5240
5361
|
var Input = React8.forwardRef(
|
|
5241
5362
|
({ className, type, ...props }, ref) => {
|
|
5242
|
-
return /* @__PURE__ */
|
|
5363
|
+
return /* @__PURE__ */ jsx16(
|
|
5243
5364
|
"input",
|
|
5244
5365
|
{
|
|
5245
5366
|
type,
|
|
@@ -5258,9 +5379,9 @@ Input.displayName = "Input";
|
|
|
5258
5379
|
|
|
5259
5380
|
// src/ui/label.tsx
|
|
5260
5381
|
import { Label as LabelPrimitive } from "radix-ui";
|
|
5261
|
-
import { jsx as
|
|
5382
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
5262
5383
|
function Label({ className, ...props }) {
|
|
5263
|
-
return /* @__PURE__ */
|
|
5384
|
+
return /* @__PURE__ */ jsx17(
|
|
5264
5385
|
LabelPrimitive.Root,
|
|
5265
5386
|
{
|
|
5266
5387
|
"data-slot": "label",
|
|
@@ -5272,11 +5393,11 @@ function Label({ className, ...props }) {
|
|
|
5272
5393
|
|
|
5273
5394
|
// src/ui/link-modal/UrlOrPageInput.tsx
|
|
5274
5395
|
import { ChevronDown, File as File2, X as X2 } from "lucide-react";
|
|
5275
|
-
import { jsx as
|
|
5396
|
+
import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
5276
5397
|
function FieldChevron({
|
|
5277
5398
|
onClick
|
|
5278
5399
|
}) {
|
|
5279
|
-
return /* @__PURE__ */
|
|
5400
|
+
return /* @__PURE__ */ jsx18(
|
|
5280
5401
|
"button",
|
|
5281
5402
|
{
|
|
5282
5403
|
type: "button",
|
|
@@ -5284,7 +5405,7 @@ function FieldChevron({
|
|
|
5284
5405
|
onClick,
|
|
5285
5406
|
"aria-label": "Open page list",
|
|
5286
5407
|
tabIndex: -1,
|
|
5287
|
-
children: /* @__PURE__ */
|
|
5408
|
+
children: /* @__PURE__ */ jsx18(ChevronDown, { size: 16 })
|
|
5288
5409
|
}
|
|
5289
5410
|
);
|
|
5290
5411
|
}
|
|
@@ -5345,11 +5466,11 @@ function UrlOrPageInput({
|
|
|
5345
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]",
|
|
5346
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"
|
|
5347
5468
|
);
|
|
5348
|
-
return /* @__PURE__ */
|
|
5349
|
-
/* @__PURE__ */
|
|
5350
|
-
/* @__PURE__ */
|
|
5351
|
-
/* @__PURE__ */
|
|
5352
|
-
selectedPage ? /* @__PURE__ */
|
|
5469
|
+
return /* @__PURE__ */ jsxs10("div", { className: "flex w-full flex-col gap-2 p-0", children: [
|
|
5470
|
+
/* @__PURE__ */ jsx18(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
|
|
5471
|
+
/* @__PURE__ */ jsxs10("div", { ref: rootRef, className: "relative w-full", children: [
|
|
5472
|
+
/* @__PURE__ */ jsxs10("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
|
|
5473
|
+
selectedPage ? /* @__PURE__ */ jsx18("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ jsx18(
|
|
5353
5474
|
File2,
|
|
5354
5475
|
{
|
|
5355
5476
|
size: 16,
|
|
@@ -5357,7 +5478,7 @@ function UrlOrPageInput({
|
|
|
5357
5478
|
"aria-hidden": true
|
|
5358
5479
|
}
|
|
5359
5480
|
) }) : null,
|
|
5360
|
-
readOnly ? /* @__PURE__ */
|
|
5481
|
+
readOnly ? /* @__PURE__ */ jsx18("span", { className: "min-w-0 flex-1 truncate text-sm leading-5 text-foreground", children: selectedPage?.title ?? value }) : /* @__PURE__ */ jsx18(
|
|
5361
5482
|
Input,
|
|
5362
5483
|
{
|
|
5363
5484
|
ref: inputRef,
|
|
@@ -5383,7 +5504,7 @@ function UrlOrPageInput({
|
|
|
5383
5504
|
)
|
|
5384
5505
|
}
|
|
5385
5506
|
),
|
|
5386
|
-
selectedPage && !readOnly ? /* @__PURE__ */
|
|
5507
|
+
selectedPage && !readOnly ? /* @__PURE__ */ jsx18(
|
|
5387
5508
|
"button",
|
|
5388
5509
|
{
|
|
5389
5510
|
type: "button",
|
|
@@ -5391,26 +5512,26 @@ function UrlOrPageInput({
|
|
|
5391
5512
|
onMouseDown: clearSelection,
|
|
5392
5513
|
"aria-label": "Clear selected page",
|
|
5393
5514
|
tabIndex: -1,
|
|
5394
|
-
children: /* @__PURE__ */
|
|
5515
|
+
children: /* @__PURE__ */ jsx18(X2, { size: 16, "aria-hidden": true })
|
|
5395
5516
|
}
|
|
5396
5517
|
) : null,
|
|
5397
|
-
!readOnly ? /* @__PURE__ */
|
|
5518
|
+
!readOnly ? /* @__PURE__ */ jsx18(FieldChevron, { onClick: toggleDropdown }) : null
|
|
5398
5519
|
] }),
|
|
5399
|
-
dropdownOpen && !readOnly && filteredPages.length > 0 ? /* @__PURE__ */
|
|
5520
|
+
dropdownOpen && !readOnly && filteredPages.length > 0 ? /* @__PURE__ */ jsx18(
|
|
5400
5521
|
"div",
|
|
5401
5522
|
{
|
|
5402
5523
|
"data-ohw-link-page-dropdown": "",
|
|
5403
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",
|
|
5404
5525
|
onMouseDown: (e) => e.preventDefault(),
|
|
5405
|
-
children: filteredPages.map((page) => /* @__PURE__ */
|
|
5526
|
+
children: filteredPages.map((page) => /* @__PURE__ */ jsxs10(
|
|
5406
5527
|
"button",
|
|
5407
5528
|
{
|
|
5408
5529
|
type: "button",
|
|
5409
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",
|
|
5410
5531
|
onClick: () => onPageSelect(page),
|
|
5411
5532
|
children: [
|
|
5412
|
-
/* @__PURE__ */
|
|
5413
|
-
/* @__PURE__ */
|
|
5533
|
+
/* @__PURE__ */ jsx18(File2, { size: 16, className: "shrink-0", "aria-hidden": true }),
|
|
5534
|
+
/* @__PURE__ */ jsx18("span", { className: "truncate", children: page.title })
|
|
5414
5535
|
]
|
|
5415
5536
|
},
|
|
5416
5537
|
page.path
|
|
@@ -5418,34 +5539,34 @@ function UrlOrPageInput({
|
|
|
5418
5539
|
}
|
|
5419
5540
|
) : null
|
|
5420
5541
|
] }),
|
|
5421
|
-
urlError ? /* @__PURE__ */
|
|
5542
|
+
urlError ? /* @__PURE__ */ jsx18("p", { className: "text-sm font-medium text-destructive", children: urlError }) : null
|
|
5422
5543
|
] });
|
|
5423
5544
|
}
|
|
5424
5545
|
|
|
5425
5546
|
// src/ui/link-modal/LinkEditorPanel.tsx
|
|
5426
|
-
import { Fragment as Fragment3, jsx as
|
|
5547
|
+
import { Fragment as Fragment3, jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
5427
5548
|
function LinkEditorPanel({ state, onClose }) {
|
|
5428
5549
|
const isCancel = state.secondaryLabel === "Cancel" || state.secondaryLabel === "Back to sections";
|
|
5429
|
-
return /* @__PURE__ */
|
|
5430
|
-
/* @__PURE__ */
|
|
5550
|
+
return /* @__PURE__ */ jsxs11(Fragment3, { children: [
|
|
5551
|
+
/* @__PURE__ */ jsx19(DialogClose, { asChild: true, children: /* @__PURE__ */ jsx19(
|
|
5431
5552
|
"button",
|
|
5432
5553
|
{
|
|
5433
5554
|
type: "button",
|
|
5434
5555
|
className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50 h-7",
|
|
5435
5556
|
"aria-label": "Close",
|
|
5436
5557
|
onClick: onClose,
|
|
5437
|
-
children: /* @__PURE__ */
|
|
5558
|
+
children: /* @__PURE__ */ jsx19(X3, { size: 16, "aria-hidden": true })
|
|
5438
5559
|
}
|
|
5439
5560
|
) }),
|
|
5440
|
-
/* @__PURE__ */
|
|
5441
|
-
/* @__PURE__ */
|
|
5442
|
-
state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */
|
|
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(
|
|
5443
5564
|
DestinationBreadcrumb,
|
|
5444
5565
|
{
|
|
5445
5566
|
pageTitle: state.selectedPage.title,
|
|
5446
5567
|
sectionLabel: state.selectedSection.label
|
|
5447
5568
|
}
|
|
5448
|
-
) : /* @__PURE__ */
|
|
5569
|
+
) : /* @__PURE__ */ jsx19(
|
|
5449
5570
|
UrlOrPageInput,
|
|
5450
5571
|
{
|
|
5451
5572
|
value: state.searchValue,
|
|
@@ -5458,8 +5579,8 @@ function LinkEditorPanel({ state, onClose }) {
|
|
|
5458
5579
|
urlError: state.urlError
|
|
5459
5580
|
}
|
|
5460
5581
|
),
|
|
5461
|
-
state.showChooseSection ? /* @__PURE__ */
|
|
5462
|
-
/* @__PURE__ */
|
|
5582
|
+
state.showChooseSection ? /* @__PURE__ */ jsxs11("div", { className: "flex flex-col justify-center gap-2", children: [
|
|
5583
|
+
/* @__PURE__ */ jsx19(
|
|
5463
5584
|
Button,
|
|
5464
5585
|
{
|
|
5465
5586
|
type: "button",
|
|
@@ -5470,15 +5591,15 @@ function LinkEditorPanel({ state, onClose }) {
|
|
|
5470
5591
|
children: "Choose a section"
|
|
5471
5592
|
}
|
|
5472
5593
|
),
|
|
5473
|
-
/* @__PURE__ */
|
|
5474
|
-
/* @__PURE__ */
|
|
5475
|
-
/* @__PURE__ */
|
|
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." })
|
|
5476
5597
|
] })
|
|
5477
5598
|
] }) : null,
|
|
5478
|
-
state.showSectionRow && state.selectedSection ? /* @__PURE__ */
|
|
5599
|
+
state.showSectionRow && state.selectedSection ? /* @__PURE__ */ jsx19(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
|
|
5479
5600
|
] }),
|
|
5480
|
-
/* @__PURE__ */
|
|
5481
|
-
/* @__PURE__ */
|
|
5601
|
+
/* @__PURE__ */ jsxs11(DialogFooter, { className: "w-full px-6 pb-6", children: [
|
|
5602
|
+
/* @__PURE__ */ jsx19(
|
|
5482
5603
|
Button,
|
|
5483
5604
|
{
|
|
5484
5605
|
type: "button",
|
|
@@ -5493,7 +5614,7 @@ function LinkEditorPanel({ state, onClose }) {
|
|
|
5493
5614
|
children: state.secondaryLabel
|
|
5494
5615
|
}
|
|
5495
5616
|
),
|
|
5496
|
-
/* @__PURE__ */
|
|
5617
|
+
/* @__PURE__ */ jsx19(
|
|
5497
5618
|
Button,
|
|
5498
5619
|
{
|
|
5499
5620
|
type: "button",
|
|
@@ -5512,11 +5633,11 @@ function LinkEditorPanel({ state, onClose }) {
|
|
|
5512
5633
|
}
|
|
5513
5634
|
|
|
5514
5635
|
// src/ui/link-modal/SectionPickerOverlay.tsx
|
|
5515
|
-
import { useCallback, useEffect as useEffect4, useMemo as useMemo2, useRef as useRef4, useState as useState4 } from "react";
|
|
5636
|
+
import { useCallback as useCallback2, useEffect as useEffect4, useMemo as useMemo2, useRef as useRef4, useState as useState4 } from "react";
|
|
5516
5637
|
import { createPortal } from "react-dom";
|
|
5517
5638
|
import { ArrowLeft, Check } from "lucide-react";
|
|
5518
5639
|
import { usePathname, useRouter } from "next/navigation";
|
|
5519
|
-
import { jsx as
|
|
5640
|
+
import { jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
5520
5641
|
var DIM_OVERLAY = "rgba(0, 0, 0, 0.45)";
|
|
5521
5642
|
function rectsEqual(a, b) {
|
|
5522
5643
|
if (a.size !== b.size) return false;
|
|
@@ -5643,7 +5764,7 @@ function SectionPickerOverlay({
|
|
|
5643
5764
|
);
|
|
5644
5765
|
sectionIdsRef.current = sectionIds;
|
|
5645
5766
|
const rects = useSectionRects(sectionIdsKey, isOnTargetPage);
|
|
5646
|
-
const applyHoverAt =
|
|
5767
|
+
const applyHoverAt = useCallback2(
|
|
5647
5768
|
(x, y, liveRects) => {
|
|
5648
5769
|
const ids = sectionIdsRef.current;
|
|
5649
5770
|
const map = liveRects ?? readSectionRects(ids);
|
|
@@ -5723,7 +5844,7 @@ function SectionPickerOverlay({
|
|
|
5723
5844
|
window.removeEventListener("message", onPointerSync);
|
|
5724
5845
|
};
|
|
5725
5846
|
}, [rects, applyHoverAt]);
|
|
5726
|
-
const handleSelect =
|
|
5847
|
+
const handleSelect = useCallback2(
|
|
5727
5848
|
(section) => {
|
|
5728
5849
|
if (selectedId) return;
|
|
5729
5850
|
setSelectedId(section.id);
|
|
@@ -5745,7 +5866,7 @@ function SectionPickerOverlay({
|
|
|
5745
5866
|
const portalRoot = typeof document !== "undefined" ? document.querySelector("[data-ohw-bridge-root]") ?? document.body : null;
|
|
5746
5867
|
if (!portalRoot) return null;
|
|
5747
5868
|
return createPortal(
|
|
5748
|
-
/* @__PURE__ */
|
|
5869
|
+
/* @__PURE__ */ jsxs12(
|
|
5749
5870
|
"div",
|
|
5750
5871
|
{
|
|
5751
5872
|
"data-ohw-section-picker": "",
|
|
@@ -5755,12 +5876,12 @@ function SectionPickerOverlay({
|
|
|
5755
5876
|
role: "dialog",
|
|
5756
5877
|
"aria-label": "Choose a section",
|
|
5757
5878
|
children: [
|
|
5758
|
-
/* @__PURE__ */
|
|
5879
|
+
/* @__PURE__ */ jsx20(
|
|
5759
5880
|
"div",
|
|
5760
5881
|
{
|
|
5761
5882
|
className: "pointer-events-auto fixed left-5 z-[2]",
|
|
5762
5883
|
style: { top: chromeClip.top + 20 },
|
|
5763
|
-
children: /* @__PURE__ */
|
|
5884
|
+
children: /* @__PURE__ */ jsxs12(
|
|
5764
5885
|
Button,
|
|
5765
5886
|
{
|
|
5766
5887
|
type: "button",
|
|
@@ -5769,14 +5890,14 @@ function SectionPickerOverlay({
|
|
|
5769
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",
|
|
5770
5891
|
onClick: onBack,
|
|
5771
5892
|
children: [
|
|
5772
|
-
/* @__PURE__ */
|
|
5893
|
+
/* @__PURE__ */ jsx20(ArrowLeft, { className: "size-4 shrink-0", "aria-hidden": true }),
|
|
5773
5894
|
"Back"
|
|
5774
5895
|
]
|
|
5775
5896
|
}
|
|
5776
5897
|
)
|
|
5777
5898
|
}
|
|
5778
5899
|
),
|
|
5779
|
-
/* @__PURE__ */
|
|
5900
|
+
/* @__PURE__ */ jsx20(
|
|
5780
5901
|
"div",
|
|
5781
5902
|
{
|
|
5782
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",
|
|
@@ -5789,7 +5910,7 @@ function SectionPickerOverlay({
|
|
|
5789
5910
|
children: "Click on section to select"
|
|
5790
5911
|
}
|
|
5791
5912
|
),
|
|
5792
|
-
!isOnTargetPage ? /* @__PURE__ */
|
|
5913
|
+
!isOnTargetPage ? /* @__PURE__ */ jsx20(
|
|
5793
5914
|
"div",
|
|
5794
5915
|
{
|
|
5795
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",
|
|
@@ -5797,14 +5918,14 @@ function SectionPickerOverlay({
|
|
|
5797
5918
|
children: "Loading page preview\u2026"
|
|
5798
5919
|
}
|
|
5799
5920
|
) : null,
|
|
5800
|
-
isOnTargetPage && liveSections.length === 0 ? /* @__PURE__ */
|
|
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,
|
|
5801
5922
|
isOnTargetPage ? liveSections.map((section) => {
|
|
5802
5923
|
const rect = rects.get(section.id);
|
|
5803
5924
|
if (!rect || rect.width <= 0 || rect.height <= 0) return null;
|
|
5804
5925
|
const isSelected = selectedId === section.id;
|
|
5805
5926
|
const isHovered = hoveredId === section.id;
|
|
5806
5927
|
const isLit = isSelected || isHovered;
|
|
5807
|
-
return /* @__PURE__ */
|
|
5928
|
+
return /* @__PURE__ */ jsxs12(
|
|
5808
5929
|
"button",
|
|
5809
5930
|
{
|
|
5810
5931
|
type: "button",
|
|
@@ -5819,7 +5940,7 @@ function SectionPickerOverlay({
|
|
|
5819
5940
|
"aria-label": `Select section ${section.label}`,
|
|
5820
5941
|
onClick: () => handleSelect(section),
|
|
5821
5942
|
children: [
|
|
5822
|
-
isLit ? /* @__PURE__ */
|
|
5943
|
+
isLit ? /* @__PURE__ */ jsx20(
|
|
5823
5944
|
"span",
|
|
5824
5945
|
{
|
|
5825
5946
|
className: "pointer-events-none absolute",
|
|
@@ -5832,13 +5953,13 @@ function SectionPickerOverlay({
|
|
|
5832
5953
|
"aria-hidden": true
|
|
5833
5954
|
}
|
|
5834
5955
|
) : null,
|
|
5835
|
-
isSelected ? /* @__PURE__ */
|
|
5956
|
+
isSelected ? /* @__PURE__ */ jsx20(
|
|
5836
5957
|
"span",
|
|
5837
5958
|
{
|
|
5838
5959
|
className: "absolute right-3 top-3 flex size-8 items-center justify-center rounded-full text-white",
|
|
5839
5960
|
style: { backgroundColor: "var(--ohw-primary, #0885fe)" },
|
|
5840
5961
|
"aria-hidden": true,
|
|
5841
|
-
children: /* @__PURE__ */
|
|
5962
|
+
children: /* @__PURE__ */ jsx20(Check, { className: "size-5" })
|
|
5842
5963
|
}
|
|
5843
5964
|
) : null
|
|
5844
5965
|
]
|
|
@@ -5854,7 +5975,7 @@ function SectionPickerOverlay({
|
|
|
5854
5975
|
}
|
|
5855
5976
|
|
|
5856
5977
|
// src/ui/link-modal/useLinkModalState.ts
|
|
5857
|
-
import { useCallback as
|
|
5978
|
+
import { useCallback as useCallback3, useEffect as useEffect5, useMemo as useMemo3, useState as useState5 } from "react";
|
|
5858
5979
|
function useLinkModalState({
|
|
5859
5980
|
open,
|
|
5860
5981
|
mode,
|
|
@@ -5873,7 +5994,7 @@ function useLinkModalState({
|
|
|
5873
5994
|
const [step, setStep] = useState5("input");
|
|
5874
5995
|
const [dropdownOpen, setDropdownOpen] = useState5(false);
|
|
5875
5996
|
const [urlError, setUrlError] = useState5("");
|
|
5876
|
-
const reset =
|
|
5997
|
+
const reset = useCallback3(() => {
|
|
5877
5998
|
setSearchValue("");
|
|
5878
5999
|
setSelectedPage(null);
|
|
5879
6000
|
setSelectedSection(null);
|
|
@@ -6018,7 +6139,7 @@ function useLinkModalState({
|
|
|
6018
6139
|
}
|
|
6019
6140
|
|
|
6020
6141
|
// src/ui/link-modal/LinkPopover.tsx
|
|
6021
|
-
import { Fragment as Fragment4, jsx as
|
|
6142
|
+
import { Fragment as Fragment4, jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
6022
6143
|
function postToParent(data) {
|
|
6023
6144
|
window.parent?.postMessage(data, "*");
|
|
6024
6145
|
}
|
|
@@ -6114,15 +6235,15 @@ function LinkPopover({
|
|
|
6114
6235
|
);
|
|
6115
6236
|
};
|
|
6116
6237
|
}, [open, sectionPickerActive]);
|
|
6117
|
-
return /* @__PURE__ */
|
|
6118
|
-
/* @__PURE__ */
|
|
6238
|
+
return /* @__PURE__ */ jsxs13(Fragment4, { children: [
|
|
6239
|
+
/* @__PURE__ */ jsx21(
|
|
6119
6240
|
Dialog2,
|
|
6120
6241
|
{
|
|
6121
6242
|
open: open && !sectionPickerActive,
|
|
6122
6243
|
onOpenChange: (next) => {
|
|
6123
6244
|
if (!next) onClose?.();
|
|
6124
6245
|
},
|
|
6125
|
-
children: /* @__PURE__ */
|
|
6246
|
+
children: /* @__PURE__ */ jsx21(
|
|
6126
6247
|
DialogContent,
|
|
6127
6248
|
{
|
|
6128
6249
|
ref: panelRef,
|
|
@@ -6132,12 +6253,12 @@ function LinkPopover({
|
|
|
6132
6253
|
"data-ohw-bridge": "",
|
|
6133
6254
|
showCloseButton: false,
|
|
6134
6255
|
className: "gap-0 p-0 w-full max-w-[448px] pointer-events-auto z-[2147483646] overflow-visible",
|
|
6135
|
-
children: /* @__PURE__ */
|
|
6256
|
+
children: /* @__PURE__ */ jsx21(LinkEditorPanel, { state, onClose })
|
|
6136
6257
|
}
|
|
6137
6258
|
)
|
|
6138
6259
|
}
|
|
6139
6260
|
),
|
|
6140
|
-
sectionPickerActive && state.selectedPage ? /* @__PURE__ */
|
|
6261
|
+
sectionPickerActive && state.selectedPage ? /* @__PURE__ */ jsx21(
|
|
6141
6262
|
SectionPickerOverlay,
|
|
6142
6263
|
{
|
|
6143
6264
|
pagePath: state.selectedPage.path,
|
|
@@ -6443,15 +6564,412 @@ function insertNavbarItem(href, label, afterAnchor = null) {
|
|
|
6443
6564
|
};
|
|
6444
6565
|
}
|
|
6445
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
|
+
|
|
6446
6964
|
// src/ui/navbar-container-chrome.tsx
|
|
6447
6965
|
import { Plus as Plus2 } from "lucide-react";
|
|
6448
|
-
import { jsx as
|
|
6966
|
+
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
6449
6967
|
function NavbarContainerChrome({
|
|
6450
6968
|
rect,
|
|
6451
6969
|
onAdd
|
|
6452
6970
|
}) {
|
|
6453
6971
|
const chromeGap = 6;
|
|
6454
|
-
return /* @__PURE__ */
|
|
6972
|
+
return /* @__PURE__ */ jsx22(
|
|
6455
6973
|
"div",
|
|
6456
6974
|
{
|
|
6457
6975
|
"data-ohw-navbar-container-chrome": "",
|
|
@@ -6463,7 +6981,7 @@ function NavbarContainerChrome({
|
|
|
6463
6981
|
width: rect.width + chromeGap * 2,
|
|
6464
6982
|
height: rect.height + chromeGap * 2
|
|
6465
6983
|
},
|
|
6466
|
-
children: /* @__PURE__ */
|
|
6984
|
+
children: /* @__PURE__ */ jsx22(
|
|
6467
6985
|
"button",
|
|
6468
6986
|
{
|
|
6469
6987
|
type: "button",
|
|
@@ -6480,15 +6998,57 @@ function NavbarContainerChrome({
|
|
|
6480
6998
|
e.stopPropagation();
|
|
6481
6999
|
onAdd();
|
|
6482
7000
|
},
|
|
6483
|
-
children: /* @__PURE__ */
|
|
7001
|
+
children: /* @__PURE__ */ jsx22(Plus2, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
|
|
6484
7002
|
}
|
|
6485
7003
|
)
|
|
6486
7004
|
}
|
|
6487
7005
|
);
|
|
6488
7006
|
}
|
|
6489
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
|
+
|
|
6490
7050
|
// src/ui/badge.tsx
|
|
6491
|
-
import { jsx as
|
|
7051
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
6492
7052
|
var badgeVariants = cva(
|
|
6493
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",
|
|
6494
7054
|
{
|
|
@@ -6506,12 +7066,12 @@ var badgeVariants = cva(
|
|
|
6506
7066
|
}
|
|
6507
7067
|
);
|
|
6508
7068
|
function Badge({ className, variant, ...props }) {
|
|
6509
|
-
return /* @__PURE__ */
|
|
7069
|
+
return /* @__PURE__ */ jsx24("div", { className: cn(badgeVariants({ variant }), className), ...props });
|
|
6510
7070
|
}
|
|
6511
7071
|
|
|
6512
7072
|
// src/OhhwellsBridge.tsx
|
|
6513
7073
|
import { Link as Link2 } from "lucide-react";
|
|
6514
|
-
import { Fragment as Fragment5, jsx as
|
|
7074
|
+
import { Fragment as Fragment5, jsx as jsx25, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
6515
7075
|
var PRIMARY2 = "#0885FE";
|
|
6516
7076
|
var IMAGE_FADE_MS = 300;
|
|
6517
7077
|
function runOpacityFade(el, onDone) {
|
|
@@ -6690,7 +7250,7 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
6690
7250
|
const root = createRoot(container);
|
|
6691
7251
|
flushSync(() => {
|
|
6692
7252
|
root.render(
|
|
6693
|
-
/* @__PURE__ */
|
|
7253
|
+
/* @__PURE__ */ jsx25(
|
|
6694
7254
|
SchedulingWidget,
|
|
6695
7255
|
{
|
|
6696
7256
|
notifyOnConnect,
|
|
@@ -6752,7 +7312,7 @@ function isDragHandleDisabled(el) {
|
|
|
6752
7312
|
return raw === "true" || raw === "";
|
|
6753
7313
|
});
|
|
6754
7314
|
}
|
|
6755
|
-
function collectEditableNodes() {
|
|
7315
|
+
function collectEditableNodes(extraContent) {
|
|
6756
7316
|
const nodes = Array.from(document.querySelectorAll("[data-ohw-editable]")).map((el) => {
|
|
6757
7317
|
if (el.dataset.ohwEditable === "image") {
|
|
6758
7318
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
@@ -6780,6 +7340,14 @@ function collectEditableNodes() {
|
|
|
6780
7340
|
if (!key) return;
|
|
6781
7341
|
nodes.push({ key, type: "link", text: getLinkHref2(el) });
|
|
6782
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
|
+
}
|
|
6783
7351
|
document.querySelectorAll('[data-ohw-editable="video"]').forEach((el) => {
|
|
6784
7352
|
const key = el.dataset.ohwKey ?? "";
|
|
6785
7353
|
const video = getVideoEl(el);
|
|
@@ -6787,13 +7355,10 @@ function collectEditableNodes() {
|
|
|
6787
7355
|
nodes.push({ key: `${key}${VIDEO_AUTOPLAY_SUFFIX}`, type: "video-setting", text: String(video.autoplay) });
|
|
6788
7356
|
nodes.push({ key: `${key}${VIDEO_MUTED_SUFFIX}`, type: "video-setting", text: String(video.muted) });
|
|
6789
7357
|
});
|
|
6790
|
-
const
|
|
6791
|
-
|
|
6792
|
-
|
|
6793
|
-
|
|
6794
|
-
seen.add(node.key);
|
|
6795
|
-
return true;
|
|
6796
|
-
});
|
|
7358
|
+
for (const key of listCarouselKeys()) {
|
|
7359
|
+
nodes.push({ key, type: "carousel", text: JSON.stringify(readCarouselValue(key)) });
|
|
7360
|
+
}
|
|
7361
|
+
return nodes;
|
|
6797
7362
|
}
|
|
6798
7363
|
function isMediaEditable(el) {
|
|
6799
7364
|
const t = el.dataset.ohwEditable;
|
|
@@ -6881,6 +7446,29 @@ function getHrefKeyFromElement(el) {
|
|
|
6881
7446
|
if (!key) return null;
|
|
6882
7447
|
return { anchor, key };
|
|
6883
7448
|
}
|
|
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
|
+
}
|
|
6884
7472
|
function isNavbarButton2(el) {
|
|
6885
7473
|
return Boolean(el.closest('[data-ohw-role="navbar-button"]'));
|
|
6886
7474
|
}
|
|
@@ -6943,7 +7531,7 @@ function isInferredFooterGroup(el) {
|
|
|
6943
7531
|
return Array.from(el.querySelectorAll(":scope > [data-ohw-href-key]")).some(isNavigationItem);
|
|
6944
7532
|
}
|
|
6945
7533
|
function isNavigationContainer(el) {
|
|
6946
|
-
return el.hasAttribute("data-ohw-nav-container") || isNavigationRoot(el) || isInferredFooterGroup(el);
|
|
7534
|
+
return el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-footer-col") || isNavigationRoot(el) || isInferredFooterGroup(el);
|
|
6947
7535
|
}
|
|
6948
7536
|
function isPointOverNavigation(x, y) {
|
|
6949
7537
|
const navRoot = document.querySelector("[data-ohw-nav-root]") ?? document.querySelector("nav");
|
|
@@ -7153,6 +7741,8 @@ var ICONS = {
|
|
|
7153
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"/>',
|
|
7154
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"/>'
|
|
7155
7743
|
};
|
|
7744
|
+
var TOOLBAR_PILL_PADDING = 2;
|
|
7745
|
+
var TOOLBAR_TOGGLE_GAP = 4;
|
|
7156
7746
|
var TOOLBAR_GROUPS = [
|
|
7157
7747
|
[
|
|
7158
7748
|
{ cmd: "bold", title: "Bold" },
|
|
@@ -7177,7 +7767,7 @@ function EditGlowChrome({
|
|
|
7177
7767
|
dragDisabled = false
|
|
7178
7768
|
}) {
|
|
7179
7769
|
const GAP = 6;
|
|
7180
|
-
return /* @__PURE__ */
|
|
7770
|
+
return /* @__PURE__ */ jsxs14(
|
|
7181
7771
|
"div",
|
|
7182
7772
|
{
|
|
7183
7773
|
ref: elRef,
|
|
@@ -7192,7 +7782,7 @@ function EditGlowChrome({
|
|
|
7192
7782
|
zIndex: 2147483646
|
|
7193
7783
|
},
|
|
7194
7784
|
children: [
|
|
7195
|
-
/* @__PURE__ */
|
|
7785
|
+
/* @__PURE__ */ jsx25(
|
|
7196
7786
|
"div",
|
|
7197
7787
|
{
|
|
7198
7788
|
style: {
|
|
@@ -7205,7 +7795,7 @@ function EditGlowChrome({
|
|
|
7205
7795
|
}
|
|
7206
7796
|
}
|
|
7207
7797
|
),
|
|
7208
|
-
reorderHrefKey && /* @__PURE__ */
|
|
7798
|
+
reorderHrefKey && /* @__PURE__ */ jsx25(
|
|
7209
7799
|
"div",
|
|
7210
7800
|
{
|
|
7211
7801
|
"data-ohw-drag-handle-container": "",
|
|
@@ -7217,7 +7807,7 @@ function EditGlowChrome({
|
|
|
7217
7807
|
transform: "translate(calc(-100% - 7px), -50%)",
|
|
7218
7808
|
pointerEvents: dragDisabled ? "none" : "auto"
|
|
7219
7809
|
},
|
|
7220
|
-
children: /* @__PURE__ */
|
|
7810
|
+
children: /* @__PURE__ */ jsx25(
|
|
7221
7811
|
DragHandle,
|
|
7222
7812
|
{
|
|
7223
7813
|
"aria-label": `Reorder ${reorderHrefKey}`,
|
|
@@ -7321,7 +7911,7 @@ function FloatingToolbar({
|
|
|
7321
7911
|
onEditLink
|
|
7322
7912
|
}) {
|
|
7323
7913
|
const { top, left, transform } = calcToolbarPos(rect, parentScroll, 330);
|
|
7324
|
-
return /* @__PURE__ */
|
|
7914
|
+
return /* @__PURE__ */ jsx25(
|
|
7325
7915
|
"div",
|
|
7326
7916
|
{
|
|
7327
7917
|
ref: elRef,
|
|
@@ -7331,14 +7921,23 @@ function FloatingToolbar({
|
|
|
7331
7921
|
left,
|
|
7332
7922
|
transform,
|
|
7333
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",
|
|
7334
7933
|
pointerEvents: "auto"
|
|
7335
7934
|
},
|
|
7336
|
-
children: /* @__PURE__ */
|
|
7337
|
-
TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */
|
|
7338
|
-
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, {}),
|
|
7339
7938
|
btns.map((btn) => {
|
|
7340
7939
|
const isActive = activeCommands.has(btn.cmd);
|
|
7341
|
-
return /* @__PURE__ */
|
|
7940
|
+
return /* @__PURE__ */ jsx25(
|
|
7342
7941
|
CustomToolbarButton,
|
|
7343
7942
|
{
|
|
7344
7943
|
title: btn.title,
|
|
@@ -7347,7 +7946,7 @@ function FloatingToolbar({
|
|
|
7347
7946
|
e.preventDefault();
|
|
7348
7947
|
onCommand(btn.cmd);
|
|
7349
7948
|
},
|
|
7350
|
-
children: /* @__PURE__ */
|
|
7949
|
+
children: /* @__PURE__ */ jsx25(
|
|
7351
7950
|
"svg",
|
|
7352
7951
|
{
|
|
7353
7952
|
width: "16",
|
|
@@ -7368,7 +7967,7 @@ function FloatingToolbar({
|
|
|
7368
7967
|
);
|
|
7369
7968
|
})
|
|
7370
7969
|
] }, gi)),
|
|
7371
|
-
showEditLink ? /* @__PURE__ */
|
|
7970
|
+
showEditLink ? /* @__PURE__ */ jsx25(
|
|
7372
7971
|
CustomToolbarButton,
|
|
7373
7972
|
{
|
|
7374
7973
|
type: "button",
|
|
@@ -7382,7 +7981,7 @@ function FloatingToolbar({
|
|
|
7382
7981
|
e.preventDefault();
|
|
7383
7982
|
e.stopPropagation();
|
|
7384
7983
|
},
|
|
7385
|
-
children: /* @__PURE__ */
|
|
7984
|
+
children: /* @__PURE__ */ jsx25(Link2, { className: "size-4 shrink-0", "aria-hidden": true })
|
|
7386
7985
|
}
|
|
7387
7986
|
) : null
|
|
7388
7987
|
] })
|
|
@@ -7399,7 +7998,7 @@ function StateToggle({
|
|
|
7399
7998
|
states,
|
|
7400
7999
|
onStateChange
|
|
7401
8000
|
}) {
|
|
7402
|
-
return /* @__PURE__ */
|
|
8001
|
+
return /* @__PURE__ */ jsx25(
|
|
7403
8002
|
ToggleGroup,
|
|
7404
8003
|
{
|
|
7405
8004
|
"data-ohw-state-toggle": "",
|
|
@@ -7413,7 +8012,7 @@ function StateToggle({
|
|
|
7413
8012
|
left: rect.right - 8,
|
|
7414
8013
|
transform: "translateX(-100%)"
|
|
7415
8014
|
},
|
|
7416
|
-
children: states.map((state) => /* @__PURE__ */
|
|
8015
|
+
children: states.map((state) => /* @__PURE__ */ jsx25(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
|
|
7417
8016
|
}
|
|
7418
8017
|
);
|
|
7419
8018
|
}
|
|
@@ -7440,8 +8039,8 @@ function OhhwellsBridge() {
|
|
|
7440
8039
|
const router = useRouter2();
|
|
7441
8040
|
const searchParams = useSearchParams();
|
|
7442
8041
|
const isEditMode = isEditSessionActive();
|
|
7443
|
-
const [bridgeRoot, setBridgeRoot] =
|
|
7444
|
-
|
|
8042
|
+
const [bridgeRoot, setBridgeRoot] = useState7(null);
|
|
8043
|
+
useEffect8(() => {
|
|
7445
8044
|
const figtreeFontId = "ohw-figtree-font";
|
|
7446
8045
|
if (!document.getElementById(figtreeFontId)) {
|
|
7447
8046
|
const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
|
|
@@ -7469,12 +8068,12 @@ function OhhwellsBridge() {
|
|
|
7469
8068
|
const subdomainFromQuery = searchParams.get("subdomain");
|
|
7470
8069
|
const subdomain = resolveSubdomain(subdomainFromQuery);
|
|
7471
8070
|
useLinkHrefGuardian(pathname, subdomain, isEditMode);
|
|
7472
|
-
const postToParent2 =
|
|
8071
|
+
const postToParent2 = useCallback4((data) => {
|
|
7473
8072
|
if (typeof window !== "undefined" && window.parent !== window) {
|
|
7474
8073
|
window.parent.postMessage(data, "*");
|
|
7475
8074
|
}
|
|
7476
8075
|
}, []);
|
|
7477
|
-
const [fetchState, setFetchState] =
|
|
8076
|
+
const [fetchState, setFetchState] = useState7("idle");
|
|
7478
8077
|
const autoSaveTimers = useRef5(/* @__PURE__ */ new Map());
|
|
7479
8078
|
const activeElRef = useRef5(null);
|
|
7480
8079
|
const selectedElRef = useRef5(null);
|
|
@@ -7482,8 +8081,8 @@ function OhhwellsBridge() {
|
|
|
7482
8081
|
const activeStateElRef = useRef5(null);
|
|
7483
8082
|
const parentScrollRef = useRef5(null);
|
|
7484
8083
|
const visibleViewportRef = useRef5(null);
|
|
7485
|
-
const [dialogPortalContainer, setDialogPortalContainer] =
|
|
7486
|
-
const attachVisibleViewport =
|
|
8084
|
+
const [dialogPortalContainer, setDialogPortalContainer] = useState7(null);
|
|
8085
|
+
const attachVisibleViewport = useCallback4((node) => {
|
|
7487
8086
|
visibleViewportRef.current = node;
|
|
7488
8087
|
setDialogPortalContainer(node);
|
|
7489
8088
|
if (node) applyVisibleViewport(node, parentScrollRef.current);
|
|
@@ -7493,8 +8092,10 @@ function OhhwellsBridge() {
|
|
|
7493
8092
|
const hoveredImageRef = useRef5(null);
|
|
7494
8093
|
const hoveredImageHasTextOverlapRef = useRef5(false);
|
|
7495
8094
|
const dragOverElRef = useRef5(null);
|
|
7496
|
-
const [mediaHover, setMediaHover] =
|
|
7497
|
-
const [
|
|
8095
|
+
const [mediaHover, setMediaHover] = useState7(null);
|
|
8096
|
+
const [carouselHover, setCarouselHover] = useState7(null);
|
|
8097
|
+
const [uploadingRects, setUploadingRects] = useState7({});
|
|
8098
|
+
const pendingUploadRectRef = useRef5(null);
|
|
7498
8099
|
const hoveredGapRef = useRef5(null);
|
|
7499
8100
|
const imageUnhoverTimerRef = useRef5(null);
|
|
7500
8101
|
const imageShowTimerRef = useRef5(null);
|
|
@@ -7519,30 +8120,38 @@ function OhhwellsBridge() {
|
|
|
7519
8120
|
postToParentRef.current = postToParent2;
|
|
7520
8121
|
const sectionsLoadedRef = useRef5(false);
|
|
7521
8122
|
const pendingScheduleConfigRequests = useRef5([]);
|
|
7522
|
-
const [toolbarRect, setToolbarRect] =
|
|
7523
|
-
const [toolbarVariant, setToolbarVariant] =
|
|
8123
|
+
const [toolbarRect, setToolbarRect] = useState7(null);
|
|
8124
|
+
const [toolbarVariant, setToolbarVariant] = useState7("none");
|
|
7524
8125
|
const toolbarVariantRef = useRef5("none");
|
|
7525
8126
|
toolbarVariantRef.current = toolbarVariant;
|
|
7526
|
-
const [reorderHrefKey, setReorderHrefKey] =
|
|
7527
|
-
const [reorderDragDisabled, setReorderDragDisabled] =
|
|
7528
|
-
const [toggleState, setToggleState] =
|
|
7529
|
-
const [maxBadge, setMaxBadge] =
|
|
7530
|
-
const [activeCommands, setActiveCommands] =
|
|
7531
|
-
const [sectionGap, setSectionGap] =
|
|
7532
|
-
const [toolbarShowEditLink, setToolbarShowEditLink] =
|
|
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);
|
|
7533
8134
|
const hoveredNavContainerRef = useRef5(null);
|
|
7534
|
-
const [hoveredNavContainerRect, setHoveredNavContainerRect] =
|
|
8135
|
+
const [hoveredNavContainerRect, setHoveredNavContainerRect] = useState7(null);
|
|
7535
8136
|
const hoveredItemElRef = useRef5(null);
|
|
7536
|
-
const [hoveredItemRect, setHoveredItemRect] =
|
|
8137
|
+
const [hoveredItemRect, setHoveredItemRect] = useState7(null);
|
|
7537
8138
|
const siblingHintElRef = useRef5(null);
|
|
7538
|
-
const [siblingHintRect, setSiblingHintRect] =
|
|
7539
|
-
const [
|
|
7540
|
-
const [
|
|
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);
|
|
7541
8150
|
const linkPopoverSessionRef = useRef5(null);
|
|
7542
8151
|
const addNavAfterAnchorRef = useRef5(null);
|
|
7543
8152
|
const editContentRef = useRef5({});
|
|
7544
|
-
const [sitePages, setSitePages] =
|
|
7545
|
-
const [sectionsByPath, setSectionsByPath] =
|
|
8153
|
+
const [sitePages, setSitePages] = useState7([]);
|
|
8154
|
+
const [sectionsByPath, setSectionsByPath] = useState7({});
|
|
7546
8155
|
const sectionsPrefetchGenRef = useRef5(0);
|
|
7547
8156
|
const setLinkPopoverRef = useRef5(setLinkPopover);
|
|
7548
8157
|
const linkPopoverPanelRef = useRef5(null);
|
|
@@ -7553,7 +8162,7 @@ function OhhwellsBridge() {
|
|
|
7553
8162
|
const bumpLinkPopoverGrace = () => {
|
|
7554
8163
|
linkPopoverGraceUntilRef.current = Date.now() + 350;
|
|
7555
8164
|
};
|
|
7556
|
-
const runSectionsPrefetch =
|
|
8165
|
+
const runSectionsPrefetch = useCallback4((pages) => {
|
|
7557
8166
|
if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
|
|
7558
8167
|
const gen = ++sectionsPrefetchGenRef.current;
|
|
7559
8168
|
const paths = pages.map((p) => p.path);
|
|
@@ -7574,8 +8183,12 @@ function OhhwellsBridge() {
|
|
|
7574
8183
|
}, [isEditMode, pathname]);
|
|
7575
8184
|
const runSectionsPrefetchRef = useRef5(runSectionsPrefetch);
|
|
7576
8185
|
runSectionsPrefetchRef.current = runSectionsPrefetch;
|
|
7577
|
-
|
|
7578
|
-
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", "");
|
|
7579
8192
|
if (hoveredImageRef.current) {
|
|
7580
8193
|
hoveredImageRef.current = null;
|
|
7581
8194
|
hoveredImageHasTextOverlapRef.current = false;
|
|
@@ -7602,14 +8215,10 @@ function OhhwellsBridge() {
|
|
|
7602
8215
|
document.addEventListener("touchmove", preventBackgroundScroll, scrollOpts);
|
|
7603
8216
|
postToParent2({ type: "ow:image-unhover" });
|
|
7604
8217
|
return () => {
|
|
7605
|
-
|
|
7606
|
-
html.style.overflow = prevHtmlOverflow;
|
|
7607
|
-
body.style.overflow = prevBodyOverflow;
|
|
7608
|
-
document.removeEventListener("wheel", preventBackgroundScroll, scrollOpts);
|
|
7609
|
-
document.removeEventListener("touchmove", preventBackgroundScroll, scrollOpts);
|
|
8218
|
+
document.documentElement.removeAttribute("data-ohw-link-popover-open");
|
|
7610
8219
|
};
|
|
7611
8220
|
}, [linkPopover, postToParent2]);
|
|
7612
|
-
|
|
8221
|
+
useEffect8(() => {
|
|
7613
8222
|
if (!isEditMode) return;
|
|
7614
8223
|
const useFixtures = shouldUseDevFixtures();
|
|
7615
8224
|
if (useFixtures) {
|
|
@@ -7633,14 +8242,14 @@ function OhhwellsBridge() {
|
|
|
7633
8242
|
if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
|
|
7634
8243
|
return () => window.removeEventListener("message", onSitePages);
|
|
7635
8244
|
}, [isEditMode, postToParent2]);
|
|
7636
|
-
|
|
8245
|
+
useEffect8(() => {
|
|
7637
8246
|
if (!isEditMode || shouldUseDevFixtures()) return;
|
|
7638
8247
|
void loadAllSectionsManifest().then((manifest) => {
|
|
7639
8248
|
if (Object.keys(manifest).length === 0) return;
|
|
7640
8249
|
setSectionsByPath((prev) => ({ ...manifest, ...prev }));
|
|
7641
8250
|
});
|
|
7642
8251
|
}, [isEditMode]);
|
|
7643
|
-
|
|
8252
|
+
useEffect8(() => {
|
|
7644
8253
|
const update = () => {
|
|
7645
8254
|
const el = activeElRef.current ?? selectedElRef.current;
|
|
7646
8255
|
if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
|
|
@@ -7664,10 +8273,10 @@ function OhhwellsBridge() {
|
|
|
7664
8273
|
vvp.removeEventListener("resize", update);
|
|
7665
8274
|
};
|
|
7666
8275
|
}, []);
|
|
7667
|
-
const refreshStateRules =
|
|
8276
|
+
const refreshStateRules = useCallback4(() => {
|
|
7668
8277
|
editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
|
|
7669
8278
|
}, []);
|
|
7670
|
-
const processConfigRequest =
|
|
8279
|
+
const processConfigRequest = useCallback4((insertAfterVal) => {
|
|
7671
8280
|
const tracker = getSectionsTracker();
|
|
7672
8281
|
let entries = [];
|
|
7673
8282
|
try {
|
|
@@ -7690,7 +8299,7 @@ function OhhwellsBridge() {
|
|
|
7690
8299
|
}
|
|
7691
8300
|
window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
|
|
7692
8301
|
}, [isEditMode]);
|
|
7693
|
-
const deactivate =
|
|
8302
|
+
const deactivate = useCallback4(() => {
|
|
7694
8303
|
const el = activeElRef.current;
|
|
7695
8304
|
if (!el) return;
|
|
7696
8305
|
const key = el.dataset.ohwKey;
|
|
@@ -7721,12 +8330,14 @@ function OhhwellsBridge() {
|
|
|
7721
8330
|
setToolbarShowEditLink(false);
|
|
7722
8331
|
postToParent2({ type: "ow:exit-edit" });
|
|
7723
8332
|
}, [postToParent2]);
|
|
7724
|
-
const deselect =
|
|
8333
|
+
const deselect = useCallback4(() => {
|
|
7725
8334
|
selectedElRef.current = null;
|
|
7726
8335
|
setReorderHrefKey(null);
|
|
7727
8336
|
setReorderDragDisabled(false);
|
|
8337
|
+
setIsFooterFrameSelection(false);
|
|
7728
8338
|
siblingHintElRef.current = null;
|
|
7729
8339
|
setSiblingHintRect(null);
|
|
8340
|
+
setSiblingHintRects([]);
|
|
7730
8341
|
setIsItemDragging(false);
|
|
7731
8342
|
hoveredNavContainerRef.current = null;
|
|
7732
8343
|
setHoveredNavContainerRect(null);
|
|
@@ -7735,7 +8346,7 @@ function OhhwellsBridge() {
|
|
|
7735
8346
|
setToolbarVariant("none");
|
|
7736
8347
|
}
|
|
7737
8348
|
}, []);
|
|
7738
|
-
const reselectNavigationItem =
|
|
8349
|
+
const reselectNavigationItem = useCallback4((navAnchor) => {
|
|
7739
8350
|
selectedElRef.current = navAnchor;
|
|
7740
8351
|
const { key, disabled } = getNavigationItemReorderState(navAnchor);
|
|
7741
8352
|
setReorderHrefKey(key);
|
|
@@ -7745,7 +8356,7 @@ function OhhwellsBridge() {
|
|
|
7745
8356
|
setToolbarShowEditLink(false);
|
|
7746
8357
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
7747
8358
|
}, []);
|
|
7748
|
-
const commitNavigationTextEdit =
|
|
8359
|
+
const commitNavigationTextEdit = useCallback4((navAnchor) => {
|
|
7749
8360
|
const el = activeElRef.current;
|
|
7750
8361
|
if (!el) return;
|
|
7751
8362
|
const key = el.dataset.ohwKey;
|
|
@@ -7771,7 +8382,7 @@ function OhhwellsBridge() {
|
|
|
7771
8382
|
postToParent2({ type: "ow:exit-edit" });
|
|
7772
8383
|
reselectNavigationItem(navAnchor);
|
|
7773
8384
|
}, [postToParent2, reselectNavigationItem]);
|
|
7774
|
-
const handleAddTopLevelNavItem =
|
|
8385
|
+
const handleAddTopLevelNavItem = useCallback4(() => {
|
|
7775
8386
|
const items = listNavbarItems();
|
|
7776
8387
|
addNavAfterAnchorRef.current = items[items.length - 1] ?? null;
|
|
7777
8388
|
deselectRef.current();
|
|
@@ -7783,90 +8394,387 @@ function OhhwellsBridge() {
|
|
|
7783
8394
|
intent: "add-nav"
|
|
7784
8395
|
});
|
|
7785
8396
|
}, []);
|
|
7786
|
-
const
|
|
7787
|
-
|
|
7788
|
-
|
|
7789
|
-
|
|
7790
|
-
|
|
7791
|
-
|
|
8397
|
+
const clearFooterDragVisuals = useCallback4(() => {
|
|
8398
|
+
footerDragRef.current = null;
|
|
8399
|
+
setSiblingHintRects([]);
|
|
8400
|
+
setFooterDropSlots([]);
|
|
8401
|
+
setActiveFooterDropIndex(null);
|
|
8402
|
+
setDraggedItemRect(null);
|
|
7792
8403
|
setIsItemDragging(false);
|
|
8404
|
+
unlockFooterDragInteraction();
|
|
7793
8405
|
}, []);
|
|
7794
|
-
|
|
7795
|
-
|
|
7796
|
-
|
|
7797
|
-
if (
|
|
7798
|
-
|
|
7799
|
-
|
|
7800
|
-
clearHrefKeyHover(anchor);
|
|
7801
|
-
hoveredNavContainerRef.current = null;
|
|
7802
|
-
setHoveredNavContainerRect(null);
|
|
7803
|
-
setHoveredItemRect(null);
|
|
7804
|
-
hoveredItemElRef.current = null;
|
|
7805
|
-
siblingHintElRef.current = null;
|
|
7806
|
-
setSiblingHintRect(null);
|
|
7807
|
-
setIsItemDragging(false);
|
|
7808
|
-
const { key, disabled } = getNavigationItemReorderState(anchor);
|
|
7809
|
-
setReorderHrefKey(key);
|
|
7810
|
-
setReorderDragDisabled(disabled);
|
|
7811
|
-
setToolbarVariant("link-action");
|
|
7812
|
-
setToolbarRect(anchor.getBoundingClientRect());
|
|
7813
|
-
setToolbarShowEditLink(false);
|
|
7814
|
-
setActiveCommands(/* @__PURE__ */ new Set());
|
|
7815
|
-
}, [deactivate]);
|
|
7816
|
-
const selectFrame = useCallback3((el) => {
|
|
7817
|
-
if (!isNavigationContainer(el)) return;
|
|
7818
|
-
if (activeElRef.current) deactivate();
|
|
7819
|
-
selectedElRef.current = el;
|
|
7820
|
-
clearHrefKeyHover(el);
|
|
7821
|
-
hoveredNavContainerRef.current = null;
|
|
7822
|
-
setHoveredNavContainerRect(null);
|
|
7823
|
-
setHoveredItemRect(null);
|
|
7824
|
-
hoveredItemElRef.current = null;
|
|
7825
|
-
siblingHintElRef.current = null;
|
|
7826
|
-
setSiblingHintRect(null);
|
|
7827
|
-
setIsItemDragging(false);
|
|
7828
|
-
setReorderHrefKey(null);
|
|
7829
|
-
setReorderDragDisabled(false);
|
|
7830
|
-
setToolbarVariant("select-frame");
|
|
7831
|
-
setToolbarRect(el.getBoundingClientRect());
|
|
7832
|
-
setToolbarShowEditLink(false);
|
|
7833
|
-
setActiveCommands(/* @__PURE__ */ new Set());
|
|
7834
|
-
}, [deactivate]);
|
|
7835
|
-
const activate = useCallback3((el, options) => {
|
|
7836
|
-
if (activeElRef.current === el) return;
|
|
7837
|
-
selectedElRef.current = null;
|
|
7838
|
-
deactivate();
|
|
7839
|
-
if (hoveredImageRef.current) {
|
|
7840
|
-
hoveredImageRef.current = null;
|
|
7841
|
-
setMediaHover(null);
|
|
7842
|
-
}
|
|
7843
|
-
setToolbarVariant("rich-text");
|
|
7844
|
-
siblingHintElRef.current = null;
|
|
7845
|
-
setSiblingHintRect(null);
|
|
7846
|
-
setIsItemDragging(false);
|
|
7847
|
-
el.setAttribute("contenteditable", "true");
|
|
7848
|
-
el.removeAttribute("data-ohw-hovered");
|
|
7849
|
-
el.closest("[data-ohw-href-key]")?.removeAttribute("data-ohw-hovered");
|
|
7850
|
-
activeElRef.current = el;
|
|
7851
|
-
originalContentRef.current = el.innerHTML;
|
|
7852
|
-
el.focus();
|
|
7853
|
-
if (options?.caretX !== void 0 && options?.caretY !== void 0) {
|
|
7854
|
-
placeCaretAtPoint(el, options.caretX, options.caretY);
|
|
8406
|
+
const refreshFooterDragVisuals = useCallback4((session, activeSlot, clientX, clientY) => {
|
|
8407
|
+
const dragged = session.draggedEl;
|
|
8408
|
+
setDraggedItemRect(dragged.getBoundingClientRect());
|
|
8409
|
+
if (typeof clientX === "number" && typeof clientY === "number") {
|
|
8410
|
+
session.lastClientX = clientX;
|
|
8411
|
+
session.lastClientY = clientY;
|
|
7855
8412
|
}
|
|
7856
|
-
|
|
7857
|
-
|
|
7858
|
-
|
|
7859
|
-
|
|
7860
|
-
|
|
7861
|
-
|
|
7862
|
-
|
|
7863
|
-
|
|
7864
|
-
|
|
8413
|
+
session.activeSlot = activeSlot;
|
|
8414
|
+
if (session.kind === "link") {
|
|
8415
|
+
const columns2 = listFooterColumns();
|
|
8416
|
+
const focusCols = /* @__PURE__ */ new Set([session.sourceColumnIndex]);
|
|
8417
|
+
if (activeSlot) focusCols.add(activeSlot.columnIndex);
|
|
8418
|
+
const siblingRects = [];
|
|
8419
|
+
columns2.forEach((col, i) => {
|
|
8420
|
+
if (!focusCols.has(i)) return;
|
|
8421
|
+
for (const link of listFooterLinksInColumn(col)) {
|
|
8422
|
+
if (link === dragged) continue;
|
|
8423
|
+
siblingRects.push(link.getBoundingClientRect());
|
|
8424
|
+
}
|
|
8425
|
+
});
|
|
8426
|
+
setSiblingHintRects(siblingRects);
|
|
8427
|
+
const slots2 = [];
|
|
8428
|
+
columns2.forEach((col, i) => {
|
|
8429
|
+
slots2.push(...buildLinkDropSlots(col, i));
|
|
8430
|
+
});
|
|
8431
|
+
setFooterDropSlots(slots2);
|
|
8432
|
+
const activeIdx2 = activeSlot ? slots2.findIndex((s) => s.columnIndex === activeSlot.columnIndex && s.insertIndex === activeSlot.insertIndex) : -1;
|
|
8433
|
+
setActiveFooterDropIndex(activeIdx2 >= 0 ? activeIdx2 : null);
|
|
8434
|
+
return;
|
|
8435
|
+
}
|
|
8436
|
+
const columns = listFooterColumns();
|
|
8437
|
+
setSiblingHintRects(columns.filter((col) => col !== dragged).map((col) => col.getBoundingClientRect()));
|
|
8438
|
+
const slots = buildColumnDropSlots();
|
|
8439
|
+
setFooterDropSlots(slots);
|
|
8440
|
+
const activeIdx = activeSlot ? slots.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
|
|
8441
|
+
setActiveFooterDropIndex(activeIdx >= 0 ? activeIdx : null);
|
|
8442
|
+
}, []);
|
|
8443
|
+
const refreshFooterDragVisualsRef = useRef5(refreshFooterDragVisuals);
|
|
8444
|
+
refreshFooterDragVisualsRef.current = refreshFooterDragVisuals;
|
|
8445
|
+
const commitFooterDragRef = useRef5(() => {
|
|
8446
|
+
});
|
|
8447
|
+
const beginFooterDragRef = useRef5(() => {
|
|
8448
|
+
});
|
|
8449
|
+
const beginFooterDrag = useCallback4(
|
|
8450
|
+
(session) => {
|
|
8451
|
+
const rect = session.draggedEl.getBoundingClientRect();
|
|
8452
|
+
session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
|
|
8453
|
+
session.lastClientY = session.lastClientY || rect.top + rect.height / 2;
|
|
8454
|
+
session.activeSlot = session.activeSlot ?? null;
|
|
8455
|
+
footerDragRef.current = session;
|
|
8456
|
+
setIsItemDragging(true);
|
|
8457
|
+
lockFooterDuringDrag();
|
|
8458
|
+
siblingHintElRef.current = null;
|
|
8459
|
+
setSiblingHintRect(null);
|
|
8460
|
+
if (session.wasSelected && selectedElRef.current === session.draggedEl) {
|
|
8461
|
+
setToolbarRect(rect);
|
|
8462
|
+
}
|
|
8463
|
+
const initialSlot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : hitTestColumnDropSlot(session.lastClientX, session.lastClientY);
|
|
8464
|
+
refreshFooterDragVisuals(session, initialSlot, session.lastClientX, session.lastClientY);
|
|
8465
|
+
},
|
|
8466
|
+
[refreshFooterDragVisuals]
|
|
8467
|
+
);
|
|
8468
|
+
beginFooterDragRef.current = beginFooterDrag;
|
|
8469
|
+
const commitFooterDrag = useCallback4(
|
|
8470
|
+
(clientX, clientY) => {
|
|
8471
|
+
const session = footerDragRef.current;
|
|
8472
|
+
if (!session) {
|
|
8473
|
+
clearFooterDragVisuals();
|
|
8474
|
+
return;
|
|
8475
|
+
}
|
|
8476
|
+
const x = typeof clientX === "number" && (clientX !== 0 || clientY !== 0) ? clientX : session.lastClientX;
|
|
8477
|
+
const y = typeof clientY === "number" && (clientX !== 0 || clientY !== 0) ? clientY : session.lastClientY;
|
|
8478
|
+
let nextOrder = null;
|
|
8479
|
+
const slot = session.activeSlot ?? (session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(x, y, session.hrefKey) : session.kind === "column" ? hitTestColumnDropSlot(x, y) : null);
|
|
8480
|
+
if (session.kind === "link" && session.hrefKey && slot) {
|
|
8481
|
+
nextOrder = planFooterLinkMove(session.hrefKey, slot.columnIndex, slot.insertIndex);
|
|
8482
|
+
} else if (session.kind === "column" && slot) {
|
|
8483
|
+
nextOrder = planFooterColumnMove(session.sourceColumnIndex, slot.insertIndex);
|
|
8484
|
+
}
|
|
8485
|
+
const wasSelected = session.wasSelected;
|
|
8486
|
+
const draggedEl = session.draggedEl;
|
|
8487
|
+
const hrefKey = session.hrefKey;
|
|
8488
|
+
let movedColumnIndex = null;
|
|
8489
|
+
if (session.kind === "column" && slot && nextOrder) {
|
|
8490
|
+
let adjusted = slot.insertIndex;
|
|
8491
|
+
if (session.sourceColumnIndex < slot.insertIndex) adjusted -= 1;
|
|
8492
|
+
movedColumnIndex = Math.max(0, Math.min(adjusted, nextOrder.length - 1));
|
|
8493
|
+
}
|
|
8494
|
+
clearFooterDragVisuals();
|
|
8495
|
+
const applySelectionAfterDrop = () => {
|
|
8496
|
+
if (!wasSelected) {
|
|
8497
|
+
deselectRef.current();
|
|
8498
|
+
return;
|
|
8499
|
+
}
|
|
8500
|
+
if (hrefKey) {
|
|
8501
|
+
const link = document.querySelector(
|
|
8502
|
+
`footer [data-ohw-href-key="${CSS.escape(hrefKey)}"]`
|
|
8503
|
+
);
|
|
8504
|
+
if (link && isNavigationItem(link)) {
|
|
8505
|
+
selectRef.current(link);
|
|
8506
|
+
return;
|
|
8507
|
+
}
|
|
8508
|
+
}
|
|
8509
|
+
if (movedColumnIndex !== null && nextOrder) {
|
|
8510
|
+
const colKeys = nextOrder[movedColumnIndex] ?? [];
|
|
8511
|
+
let column = null;
|
|
8512
|
+
for (const key of colKeys) {
|
|
8513
|
+
const link = document.querySelector(
|
|
8514
|
+
`footer [data-ohw-href-key="${CSS.escape(key)}"]`
|
|
8515
|
+
);
|
|
8516
|
+
if (link) {
|
|
8517
|
+
column = findFooterColumnForLink(link);
|
|
8518
|
+
if (column) break;
|
|
8519
|
+
}
|
|
8520
|
+
}
|
|
8521
|
+
if (!column) column = listFooterColumns()[movedColumnIndex] ?? null;
|
|
8522
|
+
if (column && isNavigationContainer(column)) {
|
|
8523
|
+
selectFrameRef.current(column);
|
|
8524
|
+
return;
|
|
8525
|
+
}
|
|
8526
|
+
}
|
|
8527
|
+
if (document.body.contains(draggedEl)) {
|
|
8528
|
+
if (isNavigationItem(draggedEl)) {
|
|
8529
|
+
selectRef.current(draggedEl);
|
|
8530
|
+
return;
|
|
8531
|
+
}
|
|
8532
|
+
if (isNavigationContainer(draggedEl)) {
|
|
8533
|
+
selectFrameRef.current(draggedEl);
|
|
8534
|
+
return;
|
|
8535
|
+
}
|
|
8536
|
+
}
|
|
8537
|
+
deselectRef.current();
|
|
8538
|
+
};
|
|
8539
|
+
if (!wasSelected) {
|
|
8540
|
+
deselectRef.current();
|
|
8541
|
+
}
|
|
8542
|
+
if (nextOrder) {
|
|
8543
|
+
const orderJson = JSON.stringify(nextOrder);
|
|
8544
|
+
editContentRef.current = {
|
|
8545
|
+
...editContentRef.current,
|
|
8546
|
+
[FOOTER_ORDER_KEY]: orderJson
|
|
8547
|
+
};
|
|
8548
|
+
applyFooterOrder(nextOrder);
|
|
8549
|
+
document.querySelectorAll("footer [data-ohw-href-key]").forEach(disableNativeHrefDrag);
|
|
8550
|
+
postToParentRef.current({
|
|
8551
|
+
type: "ow:change",
|
|
8552
|
+
nodes: [{ key: FOOTER_ORDER_KEY, text: orderJson }]
|
|
8553
|
+
});
|
|
8554
|
+
requestAnimationFrame(() => {
|
|
8555
|
+
if (editContentRef.current[FOOTER_ORDER_KEY] === orderJson) {
|
|
8556
|
+
applyFooterOrder(nextOrder);
|
|
8557
|
+
document.querySelectorAll("footer [data-ohw-href-key]").forEach(disableNativeHrefDrag);
|
|
8558
|
+
}
|
|
8559
|
+
requestAnimationFrame(applySelectionAfterDrop);
|
|
8560
|
+
});
|
|
8561
|
+
return;
|
|
8562
|
+
}
|
|
8563
|
+
applySelectionAfterDrop();
|
|
8564
|
+
},
|
|
8565
|
+
[clearFooterDragVisuals]
|
|
8566
|
+
);
|
|
8567
|
+
commitFooterDragRef.current = commitFooterDrag;
|
|
8568
|
+
const startFooterLinkDrag = useCallback4(
|
|
8569
|
+
(anchor, clientX, clientY, wasSelected) => {
|
|
8570
|
+
const hrefKey = anchor.getAttribute("data-ohw-href-key");
|
|
8571
|
+
if (!hrefKey || !isFooterHrefKey(hrefKey)) return false;
|
|
8572
|
+
const column = findFooterColumnForLink(anchor);
|
|
8573
|
+
const columns = listFooterColumns();
|
|
8574
|
+
beginFooterDrag({
|
|
8575
|
+
kind: "link",
|
|
8576
|
+
hrefKey,
|
|
8577
|
+
columnEl: column,
|
|
8578
|
+
sourceColumnIndex: column ? columns.indexOf(column) : 0,
|
|
8579
|
+
wasSelected,
|
|
8580
|
+
draggedEl: anchor,
|
|
8581
|
+
lastClientX: clientX,
|
|
8582
|
+
lastClientY: clientY,
|
|
8583
|
+
activeSlot: null
|
|
8584
|
+
});
|
|
8585
|
+
return true;
|
|
8586
|
+
},
|
|
8587
|
+
[beginFooterDrag]
|
|
8588
|
+
);
|
|
8589
|
+
const startFooterColumnDrag = useCallback4(
|
|
8590
|
+
(columnEl, clientX, clientY, wasSelected) => {
|
|
8591
|
+
const columns = listFooterColumns();
|
|
8592
|
+
const idx = columns.indexOf(columnEl);
|
|
8593
|
+
if (idx < 0) return false;
|
|
8594
|
+
beginFooterDrag({
|
|
8595
|
+
kind: "column",
|
|
8596
|
+
hrefKey: null,
|
|
8597
|
+
columnEl,
|
|
8598
|
+
sourceColumnIndex: idx,
|
|
8599
|
+
wasSelected,
|
|
8600
|
+
draggedEl: columnEl,
|
|
8601
|
+
lastClientX: clientX,
|
|
8602
|
+
lastClientY: clientY,
|
|
8603
|
+
activeSlot: null
|
|
8604
|
+
});
|
|
8605
|
+
return true;
|
|
8606
|
+
},
|
|
8607
|
+
[beginFooterDrag]
|
|
8608
|
+
);
|
|
8609
|
+
const handleItemDragStart = useCallback4(
|
|
8610
|
+
(e) => {
|
|
8611
|
+
const selected = selectedElRef.current;
|
|
8612
|
+
if (!selected) {
|
|
8613
|
+
setIsItemDragging(true);
|
|
8614
|
+
return;
|
|
8615
|
+
}
|
|
8616
|
+
const clientX = e?.clientX ?? selected.getBoundingClientRect().left + 8;
|
|
8617
|
+
const clientY = e?.clientY ?? selected.getBoundingClientRect().top + 8;
|
|
8618
|
+
if (startFooterLinkDrag(selected, clientX, clientY, true)) return;
|
|
8619
|
+
if (selected.hasAttribute("data-ohw-footer-col") || isInferredFooterGroup(selected) && selected.closest("footer")) {
|
|
8620
|
+
if (startFooterColumnDrag(selected, clientX, clientY, true)) return;
|
|
8621
|
+
}
|
|
8622
|
+
siblingHintElRef.current = null;
|
|
8623
|
+
setSiblingHintRect(null);
|
|
8624
|
+
setIsItemDragging(true);
|
|
8625
|
+
},
|
|
8626
|
+
[startFooterColumnDrag, startFooterLinkDrag]
|
|
8627
|
+
);
|
|
8628
|
+
const handleItemDragEnd = useCallback4(
|
|
8629
|
+
(e) => {
|
|
8630
|
+
if (footerDragRef.current) {
|
|
8631
|
+
const x = e?.clientX;
|
|
8632
|
+
const y = e?.clientY;
|
|
8633
|
+
if (typeof x === "number" && typeof y === "number" && (x !== 0 || y !== 0)) {
|
|
8634
|
+
commitFooterDrag(x, y);
|
|
8635
|
+
} else {
|
|
8636
|
+
commitFooterDrag();
|
|
8637
|
+
}
|
|
8638
|
+
return;
|
|
8639
|
+
}
|
|
8640
|
+
setIsItemDragging(false);
|
|
8641
|
+
},
|
|
8642
|
+
[commitFooterDrag]
|
|
8643
|
+
);
|
|
8644
|
+
const handleItemChromePointerDown = useCallback4((e) => {
|
|
8645
|
+
if (e.button !== 0) return;
|
|
8646
|
+
const selected = selectedElRef.current;
|
|
8647
|
+
if (!selected) return;
|
|
8648
|
+
armFooterPressDrag();
|
|
8649
|
+
const hrefKey = selected.getAttribute("data-ohw-href-key");
|
|
8650
|
+
if (hrefKey && isFooterHrefKey(hrefKey)) {
|
|
8651
|
+
footerPointerDragRef.current = {
|
|
8652
|
+
el: selected,
|
|
8653
|
+
kind: "link",
|
|
8654
|
+
startX: e.clientX,
|
|
8655
|
+
startY: e.clientY,
|
|
8656
|
+
pointerId: e.pointerId,
|
|
8657
|
+
wasSelected: true,
|
|
8658
|
+
started: false
|
|
8659
|
+
};
|
|
8660
|
+
return;
|
|
8661
|
+
}
|
|
8662
|
+
if (selected.hasAttribute("data-ohw-footer-col") || isInferredFooterGroup(selected) && selected.closest("footer")) {
|
|
8663
|
+
footerPointerDragRef.current = {
|
|
8664
|
+
el: selected,
|
|
8665
|
+
kind: "column",
|
|
8666
|
+
startX: e.clientX,
|
|
8667
|
+
startY: e.clientY,
|
|
8668
|
+
pointerId: e.pointerId,
|
|
8669
|
+
wasSelected: true,
|
|
8670
|
+
started: false
|
|
8671
|
+
};
|
|
7865
8672
|
}
|
|
7866
|
-
|
|
7867
|
-
|
|
7868
|
-
|
|
7869
|
-
|
|
8673
|
+
}, []);
|
|
8674
|
+
const handleItemChromeClick = useCallback4((clientX, clientY) => {
|
|
8675
|
+
if (suppressNextClickRef.current) {
|
|
8676
|
+
suppressNextClickRef.current = false;
|
|
8677
|
+
return;
|
|
8678
|
+
}
|
|
8679
|
+
const selected = selectedElRef.current;
|
|
8680
|
+
if (!selected || !isNavigationItem(selected)) return;
|
|
8681
|
+
const editable = selected.querySelector('[data-ohw-editable="text"]') ?? selected.querySelector("[data-ohw-editable]");
|
|
8682
|
+
if (!editable) return;
|
|
8683
|
+
activateRef.current(editable, { caretX: clientX, caretY: clientY });
|
|
8684
|
+
}, []);
|
|
8685
|
+
reselectNavigationItemRef.current = reselectNavigationItem;
|
|
8686
|
+
commitNavigationTextEditRef.current = commitNavigationTextEdit;
|
|
8687
|
+
const select = useCallback4(
|
|
8688
|
+
(anchor) => {
|
|
8689
|
+
if (!isNavigationItem(anchor)) return;
|
|
8690
|
+
if (activeElRef.current) deactivate();
|
|
8691
|
+
selectedElRef.current = anchor;
|
|
8692
|
+
clearHrefKeyHover(anchor);
|
|
8693
|
+
hoveredNavContainerRef.current = null;
|
|
8694
|
+
setHoveredNavContainerRect(null);
|
|
8695
|
+
setHoveredItemRect(null);
|
|
8696
|
+
hoveredItemElRef.current = null;
|
|
8697
|
+
siblingHintElRef.current = null;
|
|
8698
|
+
setSiblingHintRect(null);
|
|
8699
|
+
setSiblingHintRects([]);
|
|
8700
|
+
setIsItemDragging(false);
|
|
8701
|
+
const { key, disabled } = getNavigationItemReorderState(anchor);
|
|
8702
|
+
setReorderHrefKey(key);
|
|
8703
|
+
setReorderDragDisabled(disabled);
|
|
8704
|
+
setIsFooterFrameSelection(false);
|
|
8705
|
+
setToolbarVariant("link-action");
|
|
8706
|
+
setToolbarRect(anchor.getBoundingClientRect());
|
|
8707
|
+
setToolbarShowEditLink(false);
|
|
8708
|
+
setActiveCommands(/* @__PURE__ */ new Set());
|
|
8709
|
+
},
|
|
8710
|
+
[deactivate]
|
|
8711
|
+
);
|
|
8712
|
+
const selectFrame = useCallback4(
|
|
8713
|
+
(el) => {
|
|
8714
|
+
if (!isNavigationContainer(el)) return;
|
|
8715
|
+
if (activeElRef.current) deactivate();
|
|
8716
|
+
const isFooterColumn = el.hasAttribute("data-ohw-footer-col") || Boolean(el.closest("footer") && isInferredFooterGroup(el));
|
|
8717
|
+
selectedElRef.current = el;
|
|
8718
|
+
clearHrefKeyHover(el);
|
|
8719
|
+
hoveredNavContainerRef.current = null;
|
|
8720
|
+
setHoveredNavContainerRect(null);
|
|
8721
|
+
setHoveredItemRect(null);
|
|
8722
|
+
hoveredItemElRef.current = null;
|
|
8723
|
+
siblingHintElRef.current = null;
|
|
8724
|
+
setSiblingHintRect(null);
|
|
8725
|
+
setSiblingHintRects(
|
|
8726
|
+
isFooterColumn ? listFooterColumns().filter((column) => column !== el).map((column) => column.getBoundingClientRect()) : []
|
|
8727
|
+
);
|
|
8728
|
+
setIsItemDragging(false);
|
|
8729
|
+
setReorderHrefKey(null);
|
|
8730
|
+
setReorderDragDisabled(false);
|
|
8731
|
+
setIsFooterFrameSelection(isFooterColumn);
|
|
8732
|
+
setToolbarVariant("select-frame");
|
|
8733
|
+
setToolbarRect(el.getBoundingClientRect());
|
|
8734
|
+
setToolbarShowEditLink(false);
|
|
8735
|
+
setActiveCommands(/* @__PURE__ */ new Set());
|
|
8736
|
+
},
|
|
8737
|
+
[deactivate]
|
|
8738
|
+
);
|
|
8739
|
+
const activate = useCallback4(
|
|
8740
|
+
(el, options) => {
|
|
8741
|
+
if (activeElRef.current === el) return;
|
|
8742
|
+
selectedElRef.current = null;
|
|
8743
|
+
deactivate();
|
|
8744
|
+
if (hoveredImageRef.current) {
|
|
8745
|
+
hoveredImageRef.current = null;
|
|
8746
|
+
postToParentRef.current({ type: "ow:image-unhover" });
|
|
8747
|
+
}
|
|
8748
|
+
setToolbarVariant("rich-text");
|
|
8749
|
+
siblingHintElRef.current = null;
|
|
8750
|
+
setSiblingHintRect(null);
|
|
8751
|
+
setSiblingHintRects([]);
|
|
8752
|
+
setIsItemDragging(false);
|
|
8753
|
+
el.setAttribute("contenteditable", "true");
|
|
8754
|
+
el.removeAttribute("data-ohw-hovered");
|
|
8755
|
+
el.closest("[data-ohw-href-key]")?.removeAttribute("data-ohw-hovered");
|
|
8756
|
+
activeElRef.current = el;
|
|
8757
|
+
originalContentRef.current = el.innerHTML;
|
|
8758
|
+
el.focus();
|
|
8759
|
+
if (options?.caretX !== void 0 && options?.caretY !== void 0) {
|
|
8760
|
+
placeCaretAtPoint(el, options.caretX, options.caretY);
|
|
8761
|
+
}
|
|
8762
|
+
setToolbarShowEditLink(Boolean(getHrefKeyFromElement(el)));
|
|
8763
|
+
const navAnchor = getNavigationItemAnchor(el);
|
|
8764
|
+
if (navAnchor) {
|
|
8765
|
+
setReorderHrefKey(null);
|
|
8766
|
+
setReorderDragDisabled(false);
|
|
8767
|
+
} else {
|
|
8768
|
+
const { key: reorderKey, disabled: reorderDisabled } = getReorderHandleState(el);
|
|
8769
|
+
setReorderHrefKey(reorderKey);
|
|
8770
|
+
setReorderDragDisabled(reorderDisabled);
|
|
8771
|
+
}
|
|
8772
|
+
setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
|
|
8773
|
+
postToParent2({ type: "ow:enter-edit", key: el.dataset.ohwKey });
|
|
8774
|
+
requestAnimationFrame(() => refreshActiveCommandsRef.current());
|
|
8775
|
+
},
|
|
8776
|
+
[deactivate, postToParent2]
|
|
8777
|
+
);
|
|
7870
8778
|
activateRef.current = activate;
|
|
7871
8779
|
deactivateRef.current = deactivate;
|
|
7872
8780
|
selectRef.current = select;
|
|
@@ -7882,6 +8790,7 @@ function OhhwellsBridge() {
|
|
|
7882
8790
|
for (const [key, val] of Object.entries(content)) {
|
|
7883
8791
|
if (key === "__ohw_sections") continue;
|
|
7884
8792
|
if (applyVideoSettingNode(key, val)) continue;
|
|
8793
|
+
if (applyCarouselNode(key, val)) continue;
|
|
7885
8794
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
7886
8795
|
if (el.dataset.ohwEditable === "image") {
|
|
7887
8796
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
@@ -7913,6 +8822,7 @@ function OhhwellsBridge() {
|
|
|
7913
8822
|
applyLinkByKey(key, val);
|
|
7914
8823
|
}
|
|
7915
8824
|
reconcileNavbarItemsFromContent(content);
|
|
8825
|
+
reconcileFooterOrderFromContent(content);
|
|
7916
8826
|
enforceLinkHrefs();
|
|
7917
8827
|
initSectionsFromContent(content, true);
|
|
7918
8828
|
sectionsLoadedRef.current = true;
|
|
@@ -7941,7 +8851,7 @@ function OhhwellsBridge() {
|
|
|
7941
8851
|
cancelled = true;
|
|
7942
8852
|
};
|
|
7943
8853
|
}, [subdomain, isEditMode]);
|
|
7944
|
-
|
|
8854
|
+
useEffect8(() => {
|
|
7945
8855
|
if (!subdomain || isEditMode) return;
|
|
7946
8856
|
let debounceTimer = null;
|
|
7947
8857
|
let observer = null;
|
|
@@ -7954,6 +8864,7 @@ function OhhwellsBridge() {
|
|
|
7954
8864
|
for (const [key, val] of Object.entries(content)) {
|
|
7955
8865
|
if (key === "__ohw_sections") continue;
|
|
7956
8866
|
if (applyVideoSettingNode(key, val)) continue;
|
|
8867
|
+
if (applyCarouselNode(key, val)) continue;
|
|
7957
8868
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
7958
8869
|
if (el.dataset.ohwEditable === "image") {
|
|
7959
8870
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
@@ -7973,6 +8884,7 @@ function OhhwellsBridge() {
|
|
|
7973
8884
|
applyLinkByKey(key, val);
|
|
7974
8885
|
}
|
|
7975
8886
|
reconcileNavbarItemsFromContent(content);
|
|
8887
|
+
reconcileFooterOrderFromContent(content);
|
|
7976
8888
|
} finally {
|
|
7977
8889
|
observer?.observe(document.body, { childList: true, subtree: true });
|
|
7978
8890
|
}
|
|
@@ -7996,10 +8908,10 @@ function OhhwellsBridge() {
|
|
|
7996
8908
|
const visible = Boolean(subdomain) && fetchState !== "done";
|
|
7997
8909
|
el.style.display = visible ? "flex" : "none";
|
|
7998
8910
|
}, [subdomain, fetchState]);
|
|
7999
|
-
|
|
8911
|
+
useEffect8(() => {
|
|
8000
8912
|
postToParent2({ type: "ow:navigation", path: pathname });
|
|
8001
8913
|
}, [pathname, postToParent2]);
|
|
8002
|
-
|
|
8914
|
+
useEffect8(() => {
|
|
8003
8915
|
if (!isEditMode) return;
|
|
8004
8916
|
if (linkPopoverSessionRef.current?.intent === "add-nav") return;
|
|
8005
8917
|
if (document.querySelector("[data-ohw-section-picker]")) return;
|
|
@@ -8007,23 +8919,50 @@ function OhhwellsBridge() {
|
|
|
8007
8919
|
deselectRef.current();
|
|
8008
8920
|
deactivateRef.current();
|
|
8009
8921
|
}, [pathname, isEditMode]);
|
|
8010
|
-
|
|
8922
|
+
useEffect8(() => {
|
|
8011
8923
|
const contentForNav = () => {
|
|
8012
8924
|
if (isEditMode) return editContentRef.current;
|
|
8013
8925
|
if (!subdomain) return {};
|
|
8014
8926
|
return contentCache.get(subdomain) ?? {};
|
|
8015
8927
|
};
|
|
8016
|
-
|
|
8928
|
+
let applying = false;
|
|
8929
|
+
let rafId = null;
|
|
8930
|
+
const run = () => {
|
|
8931
|
+
if (footerDragRef.current || applying) return;
|
|
8932
|
+
applying = true;
|
|
8933
|
+
try {
|
|
8934
|
+
const content = contentForNav();
|
|
8935
|
+
reconcileNavbarItemsFromContent(content);
|
|
8936
|
+
reconcileFooterOrderFromContent(content);
|
|
8937
|
+
document.querySelectorAll("footer [data-ohw-href-key]").forEach((el) => {
|
|
8938
|
+
if (isFooterHrefKey(el.getAttribute("data-ohw-href-key"))) {
|
|
8939
|
+
disableNativeHrefDrag(el);
|
|
8940
|
+
}
|
|
8941
|
+
});
|
|
8942
|
+
} finally {
|
|
8943
|
+
applying = false;
|
|
8944
|
+
}
|
|
8945
|
+
};
|
|
8946
|
+
const scheduleRun = () => {
|
|
8947
|
+
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
8948
|
+
rafId = requestAnimationFrame(() => {
|
|
8949
|
+
rafId = null;
|
|
8950
|
+
run();
|
|
8951
|
+
});
|
|
8952
|
+
};
|
|
8017
8953
|
run();
|
|
8018
8954
|
const nav = document.querySelector("nav");
|
|
8019
|
-
|
|
8020
|
-
const observer = new MutationObserver(
|
|
8021
|
-
|
|
8022
|
-
});
|
|
8023
|
-
|
|
8024
|
-
return () =>
|
|
8955
|
+
const footer = document.querySelector("footer");
|
|
8956
|
+
const observer = new MutationObserver(scheduleRun);
|
|
8957
|
+
if (nav) observer.observe(nav, { childList: true, subtree: true });
|
|
8958
|
+
if (footer) observer.observe(footer, { childList: true, subtree: true });
|
|
8959
|
+
if (!nav && !footer) return;
|
|
8960
|
+
return () => {
|
|
8961
|
+
observer.disconnect();
|
|
8962
|
+
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
8963
|
+
};
|
|
8025
8964
|
}, [isEditMode, pathname, subdomain, fetchState]);
|
|
8026
|
-
|
|
8965
|
+
useEffect8(() => {
|
|
8027
8966
|
if (!isEditMode) return;
|
|
8028
8967
|
const measure = () => {
|
|
8029
8968
|
const h = document.body.scrollHeight;
|
|
@@ -8047,7 +8986,7 @@ function OhhwellsBridge() {
|
|
|
8047
8986
|
window.removeEventListener("resize", handleResize);
|
|
8048
8987
|
};
|
|
8049
8988
|
}, [pathname, isEditMode, postToParent2]);
|
|
8050
|
-
|
|
8989
|
+
useEffect8(() => {
|
|
8051
8990
|
if (!subdomainFromQuery || isEditMode) return;
|
|
8052
8991
|
const handleClick = (e) => {
|
|
8053
8992
|
const anchor = e.target.closest("a");
|
|
@@ -8063,7 +9002,7 @@ function OhhwellsBridge() {
|
|
|
8063
9002
|
document.addEventListener("click", handleClick, true);
|
|
8064
9003
|
return () => document.removeEventListener("click", handleClick, true);
|
|
8065
9004
|
}, [subdomainFromQuery, isEditMode, router]);
|
|
8066
|
-
|
|
9005
|
+
useEffect8(() => {
|
|
8067
9006
|
if (!isEditMode) {
|
|
8068
9007
|
editStylesRef.current?.base.remove();
|
|
8069
9008
|
editStylesRef.current?.forceHover.remove();
|
|
@@ -8086,6 +9025,32 @@ function OhhwellsBridge() {
|
|
|
8086
9025
|
[data-ohw-editable] {
|
|
8087
9026
|
display: block;
|
|
8088
9027
|
}
|
|
9028
|
+
/* Native <a> drag steals clicks \u2014 disable for edit links; reorder via press-to-drag / handle. */
|
|
9029
|
+
footer [data-ohw-href-key] {
|
|
9030
|
+
-webkit-user-drag: none !important;
|
|
9031
|
+
}
|
|
9032
|
+
footer [data-ohw-footer-col]:hover {
|
|
9033
|
+
outline: 1.5px dashed ${PRIMARY2} !important;
|
|
9034
|
+
outline-offset: 6px;
|
|
9035
|
+
border-radius: 8px;
|
|
9036
|
+
}
|
|
9037
|
+
html[data-ohw-link-popover-open] footer [data-ohw-footer-col]:hover {
|
|
9038
|
+
outline: none !important;
|
|
9039
|
+
}
|
|
9040
|
+
html[data-ohw-footer-press-drag] footer,
|
|
9041
|
+
html[data-ohw-footer-press-drag] footer * {
|
|
9042
|
+
user-select: none !important;
|
|
9043
|
+
-webkit-user-select: none !important;
|
|
9044
|
+
}
|
|
9045
|
+
html[data-ohw-item-dragging] footer,
|
|
9046
|
+
html[data-ohw-item-dragging] footer * {
|
|
9047
|
+
user-select: none !important;
|
|
9048
|
+
-webkit-user-select: none !important;
|
|
9049
|
+
pointer-events: none !important;
|
|
9050
|
+
}
|
|
9051
|
+
html[data-ohw-item-dragging] {
|
|
9052
|
+
cursor: grabbing !important;
|
|
9053
|
+
}
|
|
8089
9054
|
[data-ohw-editable]:not([contenteditable]):not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"]) { cursor: text !important; }
|
|
8090
9055
|
[data-ohw-editable="image"], [data-ohw-editable="image"] *,
|
|
8091
9056
|
[data-ohw-editable="video"], [data-ohw-editable="video"] *,
|
|
@@ -8130,12 +9095,39 @@ function OhhwellsBridge() {
|
|
|
8130
9095
|
}
|
|
8131
9096
|
refreshStateRules();
|
|
8132
9097
|
const handleClick = (e) => {
|
|
9098
|
+
if (suppressNextClickRef.current) {
|
|
9099
|
+
suppressNextClickRef.current = false;
|
|
9100
|
+
e.preventDefault();
|
|
9101
|
+
e.stopPropagation();
|
|
9102
|
+
return;
|
|
9103
|
+
}
|
|
8133
9104
|
const target = e.target;
|
|
8134
9105
|
if (target.closest("[data-ohw-toolbar]")) return;
|
|
8135
9106
|
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
8136
9107
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
8137
9108
|
if (isInsideLinkEditor(target)) return;
|
|
8138
9109
|
if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
|
|
9110
|
+
if (target.closest("[data-ohw-item-drag-surface]")) {
|
|
9111
|
+
e.preventDefault();
|
|
9112
|
+
e.stopPropagation();
|
|
9113
|
+
const selected = selectedElRef.current;
|
|
9114
|
+
if (selected && isNavigationItem(selected)) {
|
|
9115
|
+
const editable2 = selected.querySelector('[data-ohw-editable="text"]') ?? selected.querySelector("[data-ohw-editable]");
|
|
9116
|
+
if (editable2) {
|
|
9117
|
+
activateRef.current(editable2, {
|
|
9118
|
+
caretX: e.clientX,
|
|
9119
|
+
caretY: e.clientY
|
|
9120
|
+
});
|
|
9121
|
+
}
|
|
9122
|
+
} else if (selected?.hasAttribute("data-ohw-footer-col")) {
|
|
9123
|
+
const link = listFooterLinksInColumn(selected).find((el) => {
|
|
9124
|
+
const r2 = el.getBoundingClientRect();
|
|
9125
|
+
return e.clientX >= r2.left && e.clientX <= r2.right && e.clientY >= r2.top && e.clientY <= r2.bottom;
|
|
9126
|
+
});
|
|
9127
|
+
if (link) selectRef.current(link);
|
|
9128
|
+
}
|
|
9129
|
+
return;
|
|
9130
|
+
}
|
|
8139
9131
|
const navFromChrome = resolveNavContainerSelectionTarget(target, e.clientX, e.clientY);
|
|
8140
9132
|
if (navFromChrome) {
|
|
8141
9133
|
e.preventDefault();
|
|
@@ -8165,7 +9157,15 @@ function OhhwellsBridge() {
|
|
|
8165
9157
|
if (isMediaEditable(editable)) {
|
|
8166
9158
|
e.preventDefault();
|
|
8167
9159
|
e.stopPropagation();
|
|
8168
|
-
|
|
9160
|
+
const key = editable.dataset.ohwKey ?? "";
|
|
9161
|
+
const r2 = editable.getBoundingClientRect();
|
|
9162
|
+
if (key && r2.width > 1 && r2.height > 1) {
|
|
9163
|
+
pendingUploadRectRef.current = {
|
|
9164
|
+
key,
|
|
9165
|
+
rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height }
|
|
9166
|
+
};
|
|
9167
|
+
}
|
|
9168
|
+
postToParentRef.current({ type: "ow:image-pick", key, elementType: editable.dataset.ohwEditable ?? "image" });
|
|
8169
9169
|
return;
|
|
8170
9170
|
}
|
|
8171
9171
|
const hrefCtx = getHrefKeyFromElement(editable);
|
|
@@ -8190,10 +9190,26 @@ function OhhwellsBridge() {
|
|
|
8190
9190
|
if (hrefAnchor) {
|
|
8191
9191
|
e.preventDefault();
|
|
8192
9192
|
e.stopPropagation();
|
|
8193
|
-
if (selectedElRef.current === hrefAnchor)
|
|
9193
|
+
if (selectedElRef.current === hrefAnchor) {
|
|
9194
|
+
const textEditable = hrefAnchor.querySelector('[data-ohw-editable="text"]') ?? hrefAnchor.querySelector("[data-ohw-editable]");
|
|
9195
|
+
if (textEditable) {
|
|
9196
|
+
activateRef.current(textEditable, {
|
|
9197
|
+
caretX: e.clientX,
|
|
9198
|
+
caretY: e.clientY
|
|
9199
|
+
});
|
|
9200
|
+
}
|
|
9201
|
+
return;
|
|
9202
|
+
}
|
|
8194
9203
|
selectRef.current(hrefAnchor);
|
|
8195
9204
|
return;
|
|
8196
9205
|
}
|
|
9206
|
+
const footerColClick = target.closest("[data-ohw-footer-col]");
|
|
9207
|
+
if (footerColClick) {
|
|
9208
|
+
e.preventDefault();
|
|
9209
|
+
e.stopPropagation();
|
|
9210
|
+
selectFrameRef.current(footerColClick);
|
|
9211
|
+
return;
|
|
9212
|
+
}
|
|
8197
9213
|
const navContainerToSelect = resolveNavContainerSelectionTarget(target, e.clientX, e.clientY);
|
|
8198
9214
|
if (navContainerToSelect) {
|
|
8199
9215
|
e.preventDefault();
|
|
@@ -8260,6 +9276,13 @@ function OhhwellsBridge() {
|
|
|
8260
9276
|
const handleMouseOver = (e) => {
|
|
8261
9277
|
if (document.documentElement.hasAttribute("data-ohw-section-picking")) return;
|
|
8262
9278
|
const target = e.target;
|
|
9279
|
+
if (linkPopoverOpenRef.current) {
|
|
9280
|
+
hoveredItemElRef.current = null;
|
|
9281
|
+
setHoveredItemRect(null);
|
|
9282
|
+
hoveredNavContainerRef.current = null;
|
|
9283
|
+
setHoveredNavContainerRect(null);
|
|
9284
|
+
return;
|
|
9285
|
+
}
|
|
8263
9286
|
if (toolbarVariantRef.current !== "select-frame") {
|
|
8264
9287
|
const navContainer = target.closest("[data-ohw-nav-container]");
|
|
8265
9288
|
if (navContainer && !getNavigationItemAnchor(target)) {
|
|
@@ -8274,6 +9297,15 @@ function OhhwellsBridge() {
|
|
|
8274
9297
|
setHoveredNavContainerRect(null);
|
|
8275
9298
|
}
|
|
8276
9299
|
}
|
|
9300
|
+
const footerCol = target.closest("[data-ohw-footer-col]");
|
|
9301
|
+
if (footerCol) {
|
|
9302
|
+
hoveredNavContainerRef.current = null;
|
|
9303
|
+
setHoveredNavContainerRect(null);
|
|
9304
|
+
if (selectedElRef.current === footerCol) return;
|
|
9305
|
+
hoveredItemElRef.current = footerCol;
|
|
9306
|
+
setHoveredItemRect(footerCol.getBoundingClientRect());
|
|
9307
|
+
return;
|
|
9308
|
+
}
|
|
8277
9309
|
const navAnchor = getNavigationItemAnchor(target);
|
|
8278
9310
|
if (navAnchor) {
|
|
8279
9311
|
hoveredNavContainerRef.current = null;
|
|
@@ -8310,6 +9342,15 @@ function OhhwellsBridge() {
|
|
|
8310
9342
|
hoveredNavContainerRef.current = null;
|
|
8311
9343
|
setHoveredNavContainerRect(null);
|
|
8312
9344
|
}
|
|
9345
|
+
const footerCol = target.closest("[data-ohw-footer-col]");
|
|
9346
|
+
if (footerCol && hoveredItemElRef.current === footerCol) {
|
|
9347
|
+
const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
9348
|
+
if (related2?.closest("[data-ohw-drag-handle-container], [data-ohw-item-interaction]")) return;
|
|
9349
|
+
if (related2?.closest("[data-ohw-footer-col]") === footerCol) return;
|
|
9350
|
+
hoveredItemElRef.current = null;
|
|
9351
|
+
setHoveredItemRect(null);
|
|
9352
|
+
return;
|
|
9353
|
+
}
|
|
8313
9354
|
const navAnchor = getNavigationItemAnchor(target);
|
|
8314
9355
|
if (navAnchor) {
|
|
8315
9356
|
const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
@@ -8421,12 +9462,12 @@ function OhhwellsBridge() {
|
|
|
8421
9462
|
const stickyPad = 48;
|
|
8422
9463
|
const withinPad = x >= pr.left - stickyPad && x <= pr.left + pr.width + stickyPad && y >= pr.top - stickyPad && y <= pr.top + pr.height + stickyPad;
|
|
8423
9464
|
if (withinPad) {
|
|
8424
|
-
|
|
9465
|
+
const yieldToSmaller = smallest !== pinned && candidatePool.includes(smallest) && (() => {
|
|
8425
9466
|
const sr = getVisibleRect(smallest);
|
|
8426
|
-
const
|
|
8427
|
-
|
|
8428
|
-
}
|
|
8429
|
-
return pinned;
|
|
9467
|
+
const pr2 = getVisibleRect(pinned);
|
|
9468
|
+
return sr.width * sr.height < pr2.width * pr2.height;
|
|
9469
|
+
})();
|
|
9470
|
+
if (!yieldToSmaller) return pinned;
|
|
8430
9471
|
}
|
|
8431
9472
|
}
|
|
8432
9473
|
return smallest;
|
|
@@ -8438,6 +9479,7 @@ function OhhwellsBridge() {
|
|
|
8438
9479
|
resumeAnimTracks();
|
|
8439
9480
|
postToParentRef.current({ type: "ow:image-unhover" });
|
|
8440
9481
|
}
|
|
9482
|
+
clearImageHover();
|
|
8441
9483
|
};
|
|
8442
9484
|
const probeNavigationHoverAt = (x, y) => {
|
|
8443
9485
|
if (toolbarVariantRef.current === "select-frame") {
|
|
@@ -8540,7 +9582,7 @@ function OhhwellsBridge() {
|
|
|
8540
9582
|
return;
|
|
8541
9583
|
}
|
|
8542
9584
|
const topEl = document.elementFromPoint(x2, y2);
|
|
8543
|
-
if (topEl?.closest('[data-ohw-toolbar], [data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
|
|
9585
|
+
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]')) {
|
|
8544
9586
|
if (hoveredImageRef.current) {
|
|
8545
9587
|
hoveredImageRef.current = null;
|
|
8546
9588
|
resumeAnimTracks();
|
|
@@ -8747,6 +9789,14 @@ function OhhwellsBridge() {
|
|
|
8747
9789
|
probeHoverCardsAt(clientX, clientY);
|
|
8748
9790
|
};
|
|
8749
9791
|
const handleDragOver = (e) => {
|
|
9792
|
+
const footerSession = footerDragRef.current;
|
|
9793
|
+
if (footerSession) {
|
|
9794
|
+
e.preventDefault();
|
|
9795
|
+
if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
|
|
9796
|
+
const slot = footerSession.kind === "link" && footerSession.hrefKey ? hitTestLinkDropSlot(e.clientX, e.clientY, footerSession.hrefKey) : hitTestColumnDropSlot(e.clientX, e.clientY);
|
|
9797
|
+
refreshFooterDragVisualsRef.current(footerSession, slot, e.clientX, e.clientY);
|
|
9798
|
+
return;
|
|
9799
|
+
}
|
|
8750
9800
|
e.preventDefault();
|
|
8751
9801
|
const el = findImageAtPoint(e.clientX, e.clientY, false);
|
|
8752
9802
|
if (!el) {
|
|
@@ -8815,6 +9865,7 @@ function OhhwellsBridge() {
|
|
|
8815
9865
|
if (!entry || entry.fadingOut) return prev;
|
|
8816
9866
|
return { ...prev, [key]: { ...entry, fadingOut: true } };
|
|
8817
9867
|
});
|
|
9868
|
+
if (pendingUploadRectRef.current?.key === key) pendingUploadRectRef.current = null;
|
|
8818
9869
|
};
|
|
8819
9870
|
let found = false;
|
|
8820
9871
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -8929,6 +9980,7 @@ function OhhwellsBridge() {
|
|
|
8929
9980
|
continue;
|
|
8930
9981
|
}
|
|
8931
9982
|
if (applyVideoSettingNode(key, val)) continue;
|
|
9983
|
+
if (applyCarouselNode(key, val)) continue;
|
|
8932
9984
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
8933
9985
|
if (el.dataset.ohwEditable === "image") {
|
|
8934
9986
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
@@ -8953,6 +10005,7 @@ function OhhwellsBridge() {
|
|
|
8953
10005
|
}
|
|
8954
10006
|
editContentRef.current = { ...editContentRef.current, ...content };
|
|
8955
10007
|
reconcileNavbarItemsFromContent(editContentRef.current);
|
|
10008
|
+
reconcileFooterOrderFromContent(editContentRef.current);
|
|
8956
10009
|
enforceLinkHrefs();
|
|
8957
10010
|
postToParentRef.current({ type: "ow:hydrate-done" });
|
|
8958
10011
|
};
|
|
@@ -9066,6 +10119,17 @@ function OhhwellsBridge() {
|
|
|
9066
10119
|
if (siblingHintElRef.current) {
|
|
9067
10120
|
setSiblingHintRect(siblingHintElRef.current.getBoundingClientRect());
|
|
9068
10121
|
}
|
|
10122
|
+
const selected = selectedElRef.current;
|
|
10123
|
+
if (selected && !footerDragRef.current && (selected.hasAttribute("data-ohw-footer-col") || Boolean(selected.closest("footer") && isInferredFooterGroup(selected)))) {
|
|
10124
|
+
setSiblingHintRects(
|
|
10125
|
+
listFooterColumns().filter((column) => column !== selected).map((column) => column.getBoundingClientRect())
|
|
10126
|
+
);
|
|
10127
|
+
}
|
|
10128
|
+
if (footerDragRef.current) {
|
|
10129
|
+
const session = footerDragRef.current;
|
|
10130
|
+
const slot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : hitTestColumnDropSlot(session.lastClientX, session.lastClientY);
|
|
10131
|
+
refreshFooterDragVisualsRef.current(session, slot, session.lastClientX, session.lastClientY);
|
|
10132
|
+
}
|
|
9069
10133
|
if (hoveredImageRef.current) {
|
|
9070
10134
|
const el = hoveredImageRef.current;
|
|
9071
10135
|
const r2 = el.getBoundingClientRect();
|
|
@@ -9076,7 +10140,7 @@ function OhhwellsBridge() {
|
|
|
9076
10140
|
};
|
|
9077
10141
|
const handleSave = (e) => {
|
|
9078
10142
|
if (e.data?.type !== "ow:save") return;
|
|
9079
|
-
const nodes = collectEditableNodes();
|
|
10143
|
+
const nodes = collectEditableNodes(editContentRef.current);
|
|
9080
10144
|
const tracker = document.querySelector("[data-ohw-sections-tracker]");
|
|
9081
10145
|
if (tracker?.textContent) nodes.push({ key: "__ohw_sections", type: "sections", text: tracker.textContent });
|
|
9082
10146
|
postToParentRef.current({ type: "ow:save-result", nodes });
|
|
@@ -9161,28 +10225,49 @@ function OhhwellsBridge() {
|
|
|
9161
10225
|
const handleDocMouseLeave = () => {
|
|
9162
10226
|
hoveredImageRef.current = null;
|
|
9163
10227
|
setMediaHover(null);
|
|
10228
|
+
setCarouselHover(null);
|
|
9164
10229
|
document.querySelectorAll("[data-ohw-state-hovered]").forEach((el) => el.removeAttribute("data-ohw-state-hovered"));
|
|
9165
10230
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
9166
10231
|
activeStateElRef.current = null;
|
|
9167
10232
|
setToggleState(null);
|
|
9168
10233
|
};
|
|
10234
|
+
const resolveUploadRects = (key) => {
|
|
10235
|
+
const matches = Array.from(document.querySelectorAll(`[data-ohw-key="${key}"]`));
|
|
10236
|
+
const rects = matches.map((el) => {
|
|
10237
|
+
const r2 = el.getBoundingClientRect();
|
|
10238
|
+
return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
|
|
10239
|
+
}).filter((r2) => r2.width > 1 && r2.height > 1);
|
|
10240
|
+
if (rects.length > 0) return rects;
|
|
10241
|
+
const pending = pendingUploadRectRef.current;
|
|
10242
|
+
if (pending?.key === key && pending.rect.width > 1 && pending.rect.height > 1) {
|
|
10243
|
+
return [pending.rect];
|
|
10244
|
+
}
|
|
10245
|
+
const hovered = hoveredImageRef.current;
|
|
10246
|
+
if (hovered?.dataset.ohwKey === key) {
|
|
10247
|
+
const r2 = hovered.getBoundingClientRect();
|
|
10248
|
+
if (r2.width > 1 && r2.height > 1) {
|
|
10249
|
+
return [{ top: r2.top, left: r2.left, width: r2.width, height: r2.height }];
|
|
10250
|
+
}
|
|
10251
|
+
}
|
|
10252
|
+
return [];
|
|
10253
|
+
};
|
|
9169
10254
|
const handleImageUploading = (e) => {
|
|
9170
|
-
|
|
9171
|
-
|
|
10255
|
+
const type = e.data?.type;
|
|
10256
|
+
if (type !== "ow:image-uploading" && type !== "ow:anim-lock") return;
|
|
10257
|
+
const key = e.data.key;
|
|
10258
|
+
if (!key) return;
|
|
10259
|
+
const uploading = type === "ow:anim-lock" ? true : !!e.data.uploading;
|
|
9172
10260
|
setUploadingRects((prev) => {
|
|
9173
10261
|
if (!uploading) {
|
|
10262
|
+
if (pendingUploadRectRef.current?.key === key) pendingUploadRectRef.current = null;
|
|
9174
10263
|
if (!(key in prev)) return prev;
|
|
9175
10264
|
const next = { ...prev };
|
|
9176
10265
|
delete next[key];
|
|
9177
10266
|
return next;
|
|
9178
10267
|
}
|
|
9179
|
-
const
|
|
9180
|
-
if (
|
|
9181
|
-
|
|
9182
|
-
return {
|
|
9183
|
-
...prev,
|
|
9184
|
-
[key]: { rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height } }
|
|
9185
|
-
};
|
|
10268
|
+
const rects = resolveUploadRects(key);
|
|
10269
|
+
if (rects.length === 0) return prev;
|
|
10270
|
+
return { ...prev, [key]: { rects } };
|
|
9186
10271
|
});
|
|
9187
10272
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
9188
10273
|
const track = el.closest("[data-ohw-hover-pause]");
|
|
@@ -9200,6 +10285,48 @@ function OhhwellsBridge() {
|
|
|
9200
10285
|
if (e.data?.type !== "ow:canvas-height" || typeof e.data.height !== "number") return;
|
|
9201
10286
|
document.documentElement.style.setProperty("--ohw-canvas-h", `${e.data.height}px`);
|
|
9202
10287
|
};
|
|
10288
|
+
const handleCarouselChange = (e) => {
|
|
10289
|
+
if (e.data?.type !== "ow:carousel-change") return;
|
|
10290
|
+
const { key, images } = e.data;
|
|
10291
|
+
if (!key || !Array.isArray(images)) return;
|
|
10292
|
+
const text = JSON.stringify(images);
|
|
10293
|
+
applyCarouselValue(key, images);
|
|
10294
|
+
editContentRef.current = { ...editContentRef.current, [key]: text };
|
|
10295
|
+
postToParentRef.current({ type: "ow:change", nodes: [{ key, text }] });
|
|
10296
|
+
setCarouselHover(null);
|
|
10297
|
+
};
|
|
10298
|
+
const findCarouselAtPoint = (clientX, clientY) => {
|
|
10299
|
+
const containers = Array.from(document.querySelectorAll(`[${CAROUSEL_ATTR}]`));
|
|
10300
|
+
for (let i = containers.length - 1; i >= 0; i--) {
|
|
10301
|
+
const r2 = containers[i].getBoundingClientRect();
|
|
10302
|
+
if (clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom) {
|
|
10303
|
+
return containers[i];
|
|
10304
|
+
}
|
|
10305
|
+
}
|
|
10306
|
+
return null;
|
|
10307
|
+
};
|
|
10308
|
+
const isPointOverEditable = (scope, clientX, clientY) => {
|
|
10309
|
+
const editables = scope.querySelectorAll("[data-ohw-editable], [data-ohw-href-key]");
|
|
10310
|
+
for (const el of editables) {
|
|
10311
|
+
const r2 = el.getBoundingClientRect();
|
|
10312
|
+
if (clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom) return true;
|
|
10313
|
+
}
|
|
10314
|
+
return false;
|
|
10315
|
+
};
|
|
10316
|
+
const handleCarouselHover = (e) => {
|
|
10317
|
+
const container = findCarouselAtPoint(e.clientX, e.clientY);
|
|
10318
|
+
const scope = container?.closest("[data-ohw-section]") ?? container?.parentElement ?? null;
|
|
10319
|
+
if (!container || !scope || isPointOverEditable(scope, e.clientX, e.clientY)) {
|
|
10320
|
+
setCarouselHover((prev) => prev ? null : prev);
|
|
10321
|
+
return;
|
|
10322
|
+
}
|
|
10323
|
+
const key = container.getAttribute("data-ohw-key") ?? "";
|
|
10324
|
+
if (!key) return;
|
|
10325
|
+
const r2 = getVisibleRect(container);
|
|
10326
|
+
setCarouselHover(
|
|
10327
|
+
(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 } }
|
|
10328
|
+
);
|
|
10329
|
+
};
|
|
9203
10330
|
const applyToolbarPos = (rect) => {
|
|
9204
10331
|
const ps = parentScrollRef.current;
|
|
9205
10332
|
const approxW = 330;
|
|
@@ -9308,6 +10435,7 @@ function OhhwellsBridge() {
|
|
|
9308
10435
|
window.addEventListener("message", handleRemoveSchedulingSection);
|
|
9309
10436
|
window.addEventListener("message", handleImageUrl);
|
|
9310
10437
|
window.addEventListener("message", handleImageUploading);
|
|
10438
|
+
window.addEventListener("message", handleCarouselChange);
|
|
9311
10439
|
window.addEventListener("message", handleCanvasHeight);
|
|
9312
10440
|
window.addEventListener("message", handleParentScroll);
|
|
9313
10441
|
window.addEventListener("message", handlePointerSync);
|
|
@@ -9325,6 +10453,7 @@ function OhhwellsBridge() {
|
|
|
9325
10453
|
document.addEventListener("mouseover", handleMouseOver, true);
|
|
9326
10454
|
document.addEventListener("mouseout", handleMouseOut, true);
|
|
9327
10455
|
document.addEventListener("mousemove", handleMouseMove, true);
|
|
10456
|
+
document.addEventListener("mousemove", handleCarouselHover, true);
|
|
9328
10457
|
document.addEventListener("mouseleave", handleDocMouseLeave);
|
|
9329
10458
|
document.addEventListener("dragover", handleDragOver, true);
|
|
9330
10459
|
document.addEventListener("dragleave", handleDragLeave, true);
|
|
@@ -9340,6 +10469,7 @@ function OhhwellsBridge() {
|
|
|
9340
10469
|
document.removeEventListener("mouseover", handleMouseOver, true);
|
|
9341
10470
|
document.removeEventListener("mouseout", handleMouseOut, true);
|
|
9342
10471
|
document.removeEventListener("mousemove", handleMouseMove, true);
|
|
10472
|
+
document.removeEventListener("mousemove", handleCarouselHover, true);
|
|
9343
10473
|
document.removeEventListener("mouseleave", handleDocMouseLeave);
|
|
9344
10474
|
document.removeEventListener("dragover", handleDragOver, true);
|
|
9345
10475
|
document.removeEventListener("dragleave", handleDragLeave, true);
|
|
@@ -9355,6 +10485,7 @@ function OhhwellsBridge() {
|
|
|
9355
10485
|
window.removeEventListener("message", handleRemoveSchedulingSection);
|
|
9356
10486
|
window.removeEventListener("message", handleImageUrl);
|
|
9357
10487
|
window.removeEventListener("message", handleImageUploading);
|
|
10488
|
+
window.removeEventListener("message", handleCarouselChange);
|
|
9358
10489
|
window.removeEventListener("message", handleCanvasHeight);
|
|
9359
10490
|
window.removeEventListener("message", handleParentScroll);
|
|
9360
10491
|
window.removeEventListener("resize", handleViewportResize);
|
|
@@ -9369,7 +10500,158 @@ function OhhwellsBridge() {
|
|
|
9369
10500
|
if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
|
|
9370
10501
|
};
|
|
9371
10502
|
}, [isEditMode, refreshStateRules]);
|
|
9372
|
-
|
|
10503
|
+
useEffect8(() => {
|
|
10504
|
+
if (!isEditMode) return;
|
|
10505
|
+
const THRESHOLD = 10;
|
|
10506
|
+
const resolveWasSelected = (el) => {
|
|
10507
|
+
if (selectedElRef.current === el) return true;
|
|
10508
|
+
const activeAnchor = activeElRef.current ? getNavigationItemAnchor(activeElRef.current) : null;
|
|
10509
|
+
return activeAnchor === el;
|
|
10510
|
+
};
|
|
10511
|
+
const onPointerDown = (e) => {
|
|
10512
|
+
if (e.button !== 0) return;
|
|
10513
|
+
if (suppressNextClickRef.current && !footerDragRef.current && !footerPointerDragRef.current?.started) {
|
|
10514
|
+
suppressNextClickRef.current = false;
|
|
10515
|
+
}
|
|
10516
|
+
if (footerDragRef.current) return;
|
|
10517
|
+
const target = e.target;
|
|
10518
|
+
if (!target) return;
|
|
10519
|
+
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]')) {
|
|
10520
|
+
return;
|
|
10521
|
+
}
|
|
10522
|
+
if (target.closest("[data-ohw-item-drag-surface]")) return;
|
|
10523
|
+
const anchor = getNavigationItemAnchor(target);
|
|
10524
|
+
const hrefKey = anchor?.getAttribute("data-ohw-href-key") ?? null;
|
|
10525
|
+
if (anchor && isFooterHrefKey(hrefKey)) {
|
|
10526
|
+
armFooterPressDrag();
|
|
10527
|
+
footerPointerDragRef.current = {
|
|
10528
|
+
el: anchor,
|
|
10529
|
+
kind: "link",
|
|
10530
|
+
startX: e.clientX,
|
|
10531
|
+
startY: e.clientY,
|
|
10532
|
+
pointerId: e.pointerId,
|
|
10533
|
+
wasSelected: resolveWasSelected(anchor),
|
|
10534
|
+
started: false
|
|
10535
|
+
};
|
|
10536
|
+
return;
|
|
10537
|
+
}
|
|
10538
|
+
const col = target.closest("[data-ohw-footer-col]");
|
|
10539
|
+
if (col && !getNavigationItemAnchor(target)) {
|
|
10540
|
+
armFooterPressDrag();
|
|
10541
|
+
footerPointerDragRef.current = {
|
|
10542
|
+
el: col,
|
|
10543
|
+
kind: "column",
|
|
10544
|
+
startX: e.clientX,
|
|
10545
|
+
startY: e.clientY,
|
|
10546
|
+
pointerId: e.pointerId,
|
|
10547
|
+
wasSelected: resolveWasSelected(col),
|
|
10548
|
+
started: false
|
|
10549
|
+
};
|
|
10550
|
+
}
|
|
10551
|
+
};
|
|
10552
|
+
const onPointerMove = (e) => {
|
|
10553
|
+
const pending = footerPointerDragRef.current;
|
|
10554
|
+
if (!pending) return;
|
|
10555
|
+
if (pending.started) {
|
|
10556
|
+
e.preventDefault();
|
|
10557
|
+
clearTextSelection();
|
|
10558
|
+
const session = footerDragRef.current;
|
|
10559
|
+
if (!session) return;
|
|
10560
|
+
const slot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(e.clientX, e.clientY, session.hrefKey) : hitTestColumnDropSlot(e.clientX, e.clientY);
|
|
10561
|
+
refreshFooterDragVisualsRef.current(session, slot, e.clientX, e.clientY);
|
|
10562
|
+
return;
|
|
10563
|
+
}
|
|
10564
|
+
const dx = e.clientX - pending.startX;
|
|
10565
|
+
const dy = e.clientY - pending.startY;
|
|
10566
|
+
if (dx * dx + dy * dy < THRESHOLD * THRESHOLD) return;
|
|
10567
|
+
e.preventDefault();
|
|
10568
|
+
pending.started = true;
|
|
10569
|
+
clearTextSelection();
|
|
10570
|
+
try {
|
|
10571
|
+
document.body.setPointerCapture(pending.pointerId);
|
|
10572
|
+
} catch {
|
|
10573
|
+
}
|
|
10574
|
+
if (linkPopoverOpenRef.current) {
|
|
10575
|
+
setLinkPopoverRef.current(null);
|
|
10576
|
+
}
|
|
10577
|
+
if (activeElRef.current) {
|
|
10578
|
+
deactivateRef.current();
|
|
10579
|
+
}
|
|
10580
|
+
if (pending.kind === "link") {
|
|
10581
|
+
const key = pending.el.getAttribute("data-ohw-href-key");
|
|
10582
|
+
if (!key) return;
|
|
10583
|
+
const column = findFooterColumnForLink(pending.el);
|
|
10584
|
+
const columns2 = listFooterColumns();
|
|
10585
|
+
beginFooterDragRef.current({
|
|
10586
|
+
kind: "link",
|
|
10587
|
+
hrefKey: key,
|
|
10588
|
+
columnEl: column,
|
|
10589
|
+
sourceColumnIndex: column ? columns2.indexOf(column) : 0,
|
|
10590
|
+
wasSelected: pending.wasSelected,
|
|
10591
|
+
draggedEl: pending.el,
|
|
10592
|
+
lastClientX: e.clientX,
|
|
10593
|
+
lastClientY: e.clientY,
|
|
10594
|
+
activeSlot: null
|
|
10595
|
+
});
|
|
10596
|
+
return;
|
|
10597
|
+
}
|
|
10598
|
+
const columns = listFooterColumns();
|
|
10599
|
+
const idx = columns.indexOf(pending.el);
|
|
10600
|
+
if (idx < 0) return;
|
|
10601
|
+
beginFooterDragRef.current({
|
|
10602
|
+
kind: "column",
|
|
10603
|
+
hrefKey: null,
|
|
10604
|
+
columnEl: pending.el,
|
|
10605
|
+
sourceColumnIndex: idx,
|
|
10606
|
+
wasSelected: pending.wasSelected,
|
|
10607
|
+
draggedEl: pending.el,
|
|
10608
|
+
lastClientX: e.clientX,
|
|
10609
|
+
lastClientY: e.clientY,
|
|
10610
|
+
activeSlot: null
|
|
10611
|
+
});
|
|
10612
|
+
};
|
|
10613
|
+
const endPointerDrag = (e) => {
|
|
10614
|
+
const pending = footerPointerDragRef.current;
|
|
10615
|
+
footerPointerDragRef.current = null;
|
|
10616
|
+
try {
|
|
10617
|
+
if (document.body.hasPointerCapture(e.pointerId)) {
|
|
10618
|
+
document.body.releasePointerCapture(e.pointerId);
|
|
10619
|
+
}
|
|
10620
|
+
} catch {
|
|
10621
|
+
}
|
|
10622
|
+
if (!pending?.started) {
|
|
10623
|
+
unlockFooterDragInteraction();
|
|
10624
|
+
return;
|
|
10625
|
+
}
|
|
10626
|
+
suppressNextClickRef.current = true;
|
|
10627
|
+
commitFooterDragRef.current(e.clientX, e.clientY);
|
|
10628
|
+
};
|
|
10629
|
+
const blockSelectStart = (e) => {
|
|
10630
|
+
if (footerDragRef.current || footerPointerDragRef.current?.started || document.documentElement.hasAttribute("data-ohw-footer-press-drag")) {
|
|
10631
|
+
e.preventDefault();
|
|
10632
|
+
}
|
|
10633
|
+
};
|
|
10634
|
+
const onDragEnd = (_e) => {
|
|
10635
|
+
if (!footerDragRef.current) return;
|
|
10636
|
+
commitFooterDragRef.current();
|
|
10637
|
+
};
|
|
10638
|
+
document.addEventListener("pointerdown", onPointerDown, true);
|
|
10639
|
+
document.addEventListener("pointermove", onPointerMove, true);
|
|
10640
|
+
document.addEventListener("pointerup", endPointerDrag, true);
|
|
10641
|
+
document.addEventListener("pointercancel", endPointerDrag, true);
|
|
10642
|
+
document.addEventListener("selectstart", blockSelectStart, true);
|
|
10643
|
+
document.addEventListener("dragend", onDragEnd, true);
|
|
10644
|
+
return () => {
|
|
10645
|
+
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
10646
|
+
document.removeEventListener("pointermove", onPointerMove, true);
|
|
10647
|
+
document.removeEventListener("pointerup", endPointerDrag, true);
|
|
10648
|
+
document.removeEventListener("pointercancel", endPointerDrag, true);
|
|
10649
|
+
document.removeEventListener("selectstart", blockSelectStart, true);
|
|
10650
|
+
document.removeEventListener("dragend", onDragEnd, true);
|
|
10651
|
+
unlockFooterDragInteraction();
|
|
10652
|
+
};
|
|
10653
|
+
}, [isEditMode]);
|
|
10654
|
+
useEffect8(() => {
|
|
9373
10655
|
const handler = (e) => {
|
|
9374
10656
|
if (e.data?.type !== "ow:request-schedule-config") return;
|
|
9375
10657
|
const insertAfterVal = e.data.insertAfter;
|
|
@@ -9385,7 +10667,7 @@ function OhhwellsBridge() {
|
|
|
9385
10667
|
window.addEventListener("message", handler);
|
|
9386
10668
|
return () => window.removeEventListener("message", handler);
|
|
9387
10669
|
}, [processConfigRequest]);
|
|
9388
|
-
|
|
10670
|
+
useEffect8(() => {
|
|
9389
10671
|
if (!isEditMode) return;
|
|
9390
10672
|
document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
|
|
9391
10673
|
el.removeAttribute("data-ohw-active-state");
|
|
@@ -9406,7 +10688,13 @@ function OhhwellsBridge() {
|
|
|
9406
10688
|
const next = { ...prev, [pathKey]: sections };
|
|
9407
10689
|
return shouldUseDevFixtures() ? { ...DEV_SECTIONS_BY_PATH, ...next } : next;
|
|
9408
10690
|
});
|
|
9409
|
-
postToParent2({
|
|
10691
|
+
postToParent2({
|
|
10692
|
+
type: "ow:ready",
|
|
10693
|
+
version: "1",
|
|
10694
|
+
path: pathname,
|
|
10695
|
+
nodes: collectEditableNodes(editContentRef.current),
|
|
10696
|
+
sections
|
|
10697
|
+
});
|
|
9410
10698
|
postToParent2({ type: "ow:request-site-pages" });
|
|
9411
10699
|
}, 150);
|
|
9412
10700
|
return () => {
|
|
@@ -9414,19 +10702,19 @@ function OhhwellsBridge() {
|
|
|
9414
10702
|
clearTimeout(timer);
|
|
9415
10703
|
};
|
|
9416
10704
|
}, [pathname, isEditMode, refreshStateRules, postToParent2]);
|
|
9417
|
-
|
|
10705
|
+
useEffect8(() => {
|
|
9418
10706
|
scrollToHashSectionWhenReady();
|
|
9419
10707
|
const onHashChange = () => scrollToHashSectionWhenReady();
|
|
9420
10708
|
window.addEventListener("hashchange", onHashChange);
|
|
9421
10709
|
return () => window.removeEventListener("hashchange", onHashChange);
|
|
9422
10710
|
}, [pathname]);
|
|
9423
|
-
const handleCommand =
|
|
10711
|
+
const handleCommand = useCallback4((cmd) => {
|
|
9424
10712
|
document.execCommand(cmd, false);
|
|
9425
10713
|
activeElRef.current?.focus();
|
|
9426
10714
|
if (activeElRef.current) setToolbarRect(getEditMeasureEl(activeElRef.current).getBoundingClientRect());
|
|
9427
10715
|
refreshActiveCommandsRef.current();
|
|
9428
10716
|
}, []);
|
|
9429
|
-
const handleStateChange =
|
|
10717
|
+
const handleStateChange = useCallback4((state) => {
|
|
9430
10718
|
if (!activeStateElRef.current) return;
|
|
9431
10719
|
const el = activeStateElRef.current;
|
|
9432
10720
|
if (state === "Default") {
|
|
@@ -9439,11 +10727,11 @@ function OhhwellsBridge() {
|
|
|
9439
10727
|
}
|
|
9440
10728
|
setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
|
|
9441
10729
|
}, [deactivate]);
|
|
9442
|
-
const closeLinkPopover =
|
|
10730
|
+
const closeLinkPopover = useCallback4(() => {
|
|
9443
10731
|
addNavAfterAnchorRef.current = null;
|
|
9444
10732
|
setLinkPopover(null);
|
|
9445
10733
|
}, []);
|
|
9446
|
-
const openLinkPopoverForActive =
|
|
10734
|
+
const openLinkPopoverForActive = useCallback4(() => {
|
|
9447
10735
|
const hrefCtx = getHrefKeyFromElement(activeElRef.current);
|
|
9448
10736
|
if (!hrefCtx) return;
|
|
9449
10737
|
bumpLinkPopoverGrace();
|
|
@@ -9454,7 +10742,7 @@ function OhhwellsBridge() {
|
|
|
9454
10742
|
});
|
|
9455
10743
|
deactivate();
|
|
9456
10744
|
}, [deactivate]);
|
|
9457
|
-
const openLinkPopoverForSelected =
|
|
10745
|
+
const openLinkPopoverForSelected = useCallback4(() => {
|
|
9458
10746
|
const anchor = selectedElRef.current;
|
|
9459
10747
|
if (!anchor) return;
|
|
9460
10748
|
const key = anchor.getAttribute("data-ohw-href-key");
|
|
@@ -9467,7 +10755,7 @@ function OhhwellsBridge() {
|
|
|
9467
10755
|
});
|
|
9468
10756
|
deselect();
|
|
9469
10757
|
}, [deselect]);
|
|
9470
|
-
const handleLinkPopoverSubmit =
|
|
10758
|
+
const handleLinkPopoverSubmit = useCallback4(
|
|
9471
10759
|
(target) => {
|
|
9472
10760
|
const session = linkPopoverSessionRef.current;
|
|
9473
10761
|
if (!session) return;
|
|
@@ -9523,16 +10811,22 @@ function OhhwellsBridge() {
|
|
|
9523
10811
|
},
|
|
9524
10812
|
[postToParent2, sitePages, sectionsByPath]
|
|
9525
10813
|
);
|
|
9526
|
-
const
|
|
9527
|
-
const currentSections = sectionsByPath[pathname] ?? [];
|
|
9528
|
-
linkPopoverOpenRef.current = linkPopover !== null;
|
|
9529
|
-
const handleMediaReplace = useCallback3(
|
|
10814
|
+
const handleMediaReplace = useCallback4(
|
|
9530
10815
|
(key) => {
|
|
10816
|
+
if (mediaHover?.key === key) {
|
|
10817
|
+
pendingUploadRectRef.current = { key, rect: mediaHover.rect };
|
|
10818
|
+
}
|
|
9531
10819
|
postToParent2({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
|
|
9532
10820
|
},
|
|
9533
|
-
[postToParent2, mediaHover
|
|
10821
|
+
[postToParent2, mediaHover]
|
|
9534
10822
|
);
|
|
9535
|
-
const
|
|
10823
|
+
const handleEditCarousel = useCallback4(
|
|
10824
|
+
(key) => {
|
|
10825
|
+
postToParent2({ type: "ow:carousel-open", key, images: readCarouselValue(key) });
|
|
10826
|
+
},
|
|
10827
|
+
[postToParent2]
|
|
10828
|
+
);
|
|
10829
|
+
const handleMediaFadeOutComplete = useCallback4((key) => {
|
|
9536
10830
|
setUploadingRects((prev) => {
|
|
9537
10831
|
if (!(key in prev)) return prev;
|
|
9538
10832
|
const next = { ...prev };
|
|
@@ -9540,7 +10834,7 @@ function OhhwellsBridge() {
|
|
|
9540
10834
|
return next;
|
|
9541
10835
|
});
|
|
9542
10836
|
}, []);
|
|
9543
|
-
const handleVideoSettingsChange =
|
|
10837
|
+
const handleVideoSettingsChange = useCallback4(
|
|
9544
10838
|
(key, settings) => {
|
|
9545
10839
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
9546
10840
|
const video = getVideoEl(el);
|
|
@@ -9562,21 +10856,26 @@ function OhhwellsBridge() {
|
|
|
9562
10856
|
},
|
|
9563
10857
|
[postToParent2]
|
|
9564
10858
|
);
|
|
10859
|
+
const showEditLink = toolbarShowEditLink;
|
|
10860
|
+
const currentSections = sectionsByPath[pathname] ?? [];
|
|
10861
|
+
linkPopoverOpenRef.current = linkPopover !== null;
|
|
9565
10862
|
return bridgeRoot ? createPortal2(
|
|
9566
|
-
/* @__PURE__ */
|
|
9567
|
-
/* @__PURE__ */
|
|
9568
|
-
Object.entries(uploadingRects).
|
|
9569
|
-
|
|
9570
|
-
|
|
9571
|
-
|
|
9572
|
-
|
|
9573
|
-
|
|
9574
|
-
|
|
9575
|
-
|
|
9576
|
-
|
|
9577
|
-
|
|
9578
|
-
|
|
9579
|
-
|
|
10863
|
+
/* @__PURE__ */ jsxs14(Fragment5, { children: [
|
|
10864
|
+
/* @__PURE__ */ jsx25("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
|
|
10865
|
+
Object.entries(uploadingRects).flatMap(
|
|
10866
|
+
([key, { rects, fadingOut }]) => rects.map((rect, i) => /* @__PURE__ */ jsx25(
|
|
10867
|
+
MediaOverlay,
|
|
10868
|
+
{
|
|
10869
|
+
hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
|
|
10870
|
+
isUploading: true,
|
|
10871
|
+
fadingOut,
|
|
10872
|
+
onFadeOutComplete: handleMediaFadeOutComplete,
|
|
10873
|
+
onReplace: handleMediaReplace
|
|
10874
|
+
},
|
|
10875
|
+
`uploading-${key}-${i}`
|
|
10876
|
+
))
|
|
10877
|
+
),
|
|
10878
|
+
mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ jsx25(
|
|
9580
10879
|
MediaOverlay,
|
|
9581
10880
|
{
|
|
9582
10881
|
hover: mediaHover,
|
|
@@ -9585,62 +10884,33 @@ function OhhwellsBridge() {
|
|
|
9585
10884
|
onVideoSettingsChange: handleVideoSettingsChange
|
|
9586
10885
|
}
|
|
9587
10886
|
),
|
|
9588
|
-
|
|
9589
|
-
|
|
9590
|
-
|
|
9591
|
-
|
|
9592
|
-
|
|
9593
|
-
|
|
9594
|
-
onAdd: handleAddTopLevelNavItem
|
|
9595
|
-
}
|
|
9596
|
-
),
|
|
9597
|
-
hoveredItemRect && !hoveredNavContainerRect && !siblingHintRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx23(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
|
|
9598
|
-
toolbarRect && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ jsx23(
|
|
9599
|
-
ItemInteractionLayer,
|
|
10887
|
+
carouselHover && /* @__PURE__ */ jsx25(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
|
|
10888
|
+
siblingHintRect && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
|
|
10889
|
+
siblingHintRects.map((rect, i) => /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
|
|
10890
|
+
isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
|
|
10891
|
+
isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ jsx25(
|
|
10892
|
+
"div",
|
|
9600
10893
|
{
|
|
9601
|
-
|
|
9602
|
-
|
|
9603
|
-
|
|
9604
|
-
|
|
9605
|
-
|
|
9606
|
-
|
|
9607
|
-
|
|
9608
|
-
|
|
9609
|
-
|
|
9610
|
-
|
|
9611
|
-
|
|
9612
|
-
|
|
9613
|
-
|
|
9614
|
-
|
|
9615
|
-
|
|
9616
|
-
|
|
9617
|
-
|
|
9618
|
-
}
|
|
9619
|
-
),
|
|
9620
|
-
toolbarRect && toolbarVariant === "rich-text" && /* @__PURE__ */ jsxs13(Fragment5, { children: [
|
|
9621
|
-
/* @__PURE__ */ jsx23(
|
|
9622
|
-
EditGlowChrome,
|
|
9623
|
-
{
|
|
9624
|
-
rect: toolbarRect,
|
|
9625
|
-
elRef: glowElRef,
|
|
9626
|
-
reorderHrefKey,
|
|
9627
|
-
dragDisabled: reorderDragDisabled
|
|
9628
|
-
}
|
|
9629
|
-
),
|
|
9630
|
-
/* @__PURE__ */ jsx23(
|
|
9631
|
-
FloatingToolbar,
|
|
9632
|
-
{
|
|
9633
|
-
rect: toolbarRect,
|
|
9634
|
-
parentScroll: parentScrollRef.current,
|
|
9635
|
-
elRef: toolbarElRef,
|
|
9636
|
-
onCommand: handleCommand,
|
|
9637
|
-
activeCommands,
|
|
9638
|
-
showEditLink,
|
|
9639
|
-
onEditLink: openLinkPopoverForActive
|
|
9640
|
-
}
|
|
9641
|
-
)
|
|
10894
|
+
className: "pointer-events-none fixed z-2147483646",
|
|
10895
|
+
style: {
|
|
10896
|
+
left: slot.left,
|
|
10897
|
+
top: slot.top,
|
|
10898
|
+
width: slot.width,
|
|
10899
|
+
height: slot.height
|
|
10900
|
+
},
|
|
10901
|
+
children: /* @__PURE__ */ jsx25(DropIndicator, { direction: slot.direction, state: activeFooterDropIndex === i ? "dragActive" : "dragIdle", className: slot.direction === "horizontal" ? "!h-full !w-full" : "!h-full !w-full" })
|
|
10902
|
+
},
|
|
10903
|
+
`footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
|
|
10904
|
+
)),
|
|
10905
|
+
hoveredNavContainerRect && toolbarVariant !== "select-frame" && !linkPopover && !isItemDragging && !siblingHintRect && siblingHintRects.length === 0 && /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
|
|
10906
|
+
toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && /* @__PURE__ */ jsx25(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
|
|
10907
|
+
hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !siblingHintRect && siblingHintRects.length === 0 && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
|
|
10908
|
+
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 }),
|
|
10909
|
+
toolbarRect && toolbarVariant === "rich-text" && /* @__PURE__ */ jsxs14(Fragment5, { children: [
|
|
10910
|
+
/* @__PURE__ */ jsx25(EditGlowChrome, { rect: toolbarRect, elRef: glowElRef, reorderHrefKey, dragDisabled: reorderDragDisabled }),
|
|
10911
|
+
/* @__PURE__ */ jsx25(FloatingToolbar, { rect: toolbarRect, parentScroll: parentScrollRef.current, elRef: toolbarElRef, onCommand: handleCommand, activeCommands, showEditLink, onEditLink: openLinkPopoverForActive })
|
|
9642
10912
|
] }),
|
|
9643
|
-
maxBadge && /* @__PURE__ */
|
|
10913
|
+
maxBadge && /* @__PURE__ */ jsxs14(
|
|
9644
10914
|
"div",
|
|
9645
10915
|
{
|
|
9646
10916
|
"data-ohw-max-badge": "",
|
|
@@ -9666,57 +10936,29 @@ function OhhwellsBridge() {
|
|
|
9666
10936
|
]
|
|
9667
10937
|
}
|
|
9668
10938
|
),
|
|
9669
|
-
toggleState && !linkPopover && /* @__PURE__ */
|
|
9670
|
-
|
|
9671
|
-
{
|
|
9672
|
-
|
|
9673
|
-
|
|
9674
|
-
|
|
9675
|
-
|
|
9676
|
-
|
|
9677
|
-
|
|
9678
|
-
|
|
9679
|
-
|
|
9680
|
-
|
|
9681
|
-
|
|
9682
|
-
className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
|
|
9683
|
-
style: { top: sectionGap.y, transform: "translateY(-50%)" },
|
|
9684
|
-
children: [
|
|
9685
|
-
/* @__PURE__ */ jsx23("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
|
|
9686
|
-
/* @__PURE__ */ jsx23(
|
|
9687
|
-
Badge,
|
|
9688
|
-
{
|
|
9689
|
-
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",
|
|
9690
|
-
onClick: () => {
|
|
9691
|
-
window.parent.postMessage(
|
|
9692
|
-
{ type: "ow:add-section", insertAfter: sectionGap.insertAfter, insertBefore: sectionGap.insertBefore },
|
|
9693
|
-
"*"
|
|
9694
|
-
);
|
|
10939
|
+
toggleState && !linkPopover && /* @__PURE__ */ jsx25(StateToggle, { rect: toggleState.rect, activeState: toggleState.activeState, states: toggleState.states, onStateChange: handleStateChange }),
|
|
10940
|
+
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: [
|
|
10941
|
+
/* @__PURE__ */ jsx25("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
|
|
10942
|
+
/* @__PURE__ */ jsx25(
|
|
10943
|
+
Badge,
|
|
10944
|
+
{
|
|
10945
|
+
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",
|
|
10946
|
+
onClick: () => {
|
|
10947
|
+
window.parent.postMessage(
|
|
10948
|
+
{
|
|
10949
|
+
type: "ow:add-section",
|
|
10950
|
+
insertAfter: sectionGap.insertAfter,
|
|
10951
|
+
insertBefore: sectionGap.insertBefore
|
|
9695
10952
|
},
|
|
9696
|
-
|
|
9697
|
-
|
|
9698
|
-
|
|
9699
|
-
|
|
9700
|
-
|
|
9701
|
-
|
|
9702
|
-
|
|
9703
|
-
|
|
9704
|
-
|
|
9705
|
-
{
|
|
9706
|
-
panelRef: linkPopoverPanelRef,
|
|
9707
|
-
portalContainer: dialogPortalContainer,
|
|
9708
|
-
open: true,
|
|
9709
|
-
mode: linkPopover.mode ?? "edit",
|
|
9710
|
-
pages: sitePages,
|
|
9711
|
-
sections: currentSections,
|
|
9712
|
-
sectionsByPath,
|
|
9713
|
-
initialTarget: linkPopover.target,
|
|
9714
|
-
existingTargets: linkPopover.intent === "add-nav" ? getNavbarExistingTargets() : [],
|
|
9715
|
-
onClose: closeLinkPopover,
|
|
9716
|
-
onSubmit: handleLinkPopoverSubmit
|
|
9717
|
-
},
|
|
9718
|
-
linkPopover.key
|
|
9719
|
-
) : null
|
|
10953
|
+
"*"
|
|
10954
|
+
);
|
|
10955
|
+
},
|
|
10956
|
+
children: "Add Section"
|
|
10957
|
+
}
|
|
10958
|
+
),
|
|
10959
|
+
/* @__PURE__ */ jsx25("div", { className: "flex-1 bg-primary", style: { height: 3 } })
|
|
10960
|
+
] }),
|
|
10961
|
+
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
|
|
9720
10962
|
] }),
|
|
9721
10963
|
bridgeRoot
|
|
9722
10964
|
) : null;
|
|
@@ -9726,6 +10968,7 @@ export {
|
|
|
9726
10968
|
CustomToolbarButton,
|
|
9727
10969
|
CustomToolbarDivider,
|
|
9728
10970
|
DragHandle,
|
|
10971
|
+
DropIndicator,
|
|
9729
10972
|
ItemActionToolbar,
|
|
9730
10973
|
ItemInteractionLayer,
|
|
9731
10974
|
LinkEditorPanel,
|
|
@@ -9740,12 +10983,14 @@ export {
|
|
|
9740
10983
|
TooltipProvider,
|
|
9741
10984
|
TooltipTrigger,
|
|
9742
10985
|
buildTarget,
|
|
10986
|
+
dropIndicatorVariants,
|
|
9743
10987
|
filterAvailablePages,
|
|
9744
10988
|
getEditModeInitialState,
|
|
9745
10989
|
isEditSessionActive,
|
|
9746
10990
|
isValidUrl,
|
|
9747
10991
|
parseTarget,
|
|
9748
10992
|
toggleVariants,
|
|
10993
|
+
useOhwCarousel,
|
|
9749
10994
|
validateUrlInput
|
|
9750
10995
|
};
|
|
9751
10996
|
//# sourceMappingURL=index.js.map
|