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