@ohhwells/bridge 0.1.44 → 0.1.46-next.109
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/dist/index.cjs +3007 -492
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -3
- package/dist/index.d.ts +12 -3
- package/dist/index.js +3046 -531
- package/dist/index.js.map +1 -1
- package/dist/styles.css +131 -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 React11, { useCallback as useCallback5, useEffect as useEffect8, useLayoutEffect as useLayoutEffect3, useRef as useRef7, useState as useState7 } from "react";
|
|
5
5
|
import { createRoot } from "react-dom/client";
|
|
6
6
|
import { flushSync } from "react-dom";
|
|
7
7
|
|
|
@@ -48,12 +48,13 @@ function useLinkHrefGuardian(...deps) {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
// src/ui/SchedulingWidget.tsx
|
|
51
|
-
import { useEffect, useId, useMemo, useRef, useState as useState2 } from "react";
|
|
51
|
+
import { useCallback, useEffect, useId, useMemo, useRef, useState as useState2 } from "react";
|
|
52
52
|
|
|
53
53
|
// src/ui/EmailCaptureModal.tsx
|
|
54
54
|
import { useState } from "react";
|
|
55
55
|
import { Dialog } from "radix-ui";
|
|
56
56
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
57
|
+
var isValidEmail = (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
|
|
57
58
|
function Spinner() {
|
|
58
59
|
return /* @__PURE__ */ jsxs(
|
|
59
60
|
"svg",
|
|
@@ -87,12 +88,17 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
|
|
|
87
88
|
const [error, setError] = useState(null);
|
|
88
89
|
const isBook = title === "Confirm your spot";
|
|
89
90
|
const handleSubmit = async () => {
|
|
90
|
-
|
|
91
|
+
const trimmed = email.trim();
|
|
92
|
+
if (!trimmed) return;
|
|
93
|
+
if (!isValidEmail(trimmed)) {
|
|
94
|
+
setError("Please enter a valid email address.");
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
91
97
|
setLoading(true);
|
|
92
98
|
setError(null);
|
|
93
99
|
try {
|
|
94
|
-
await onSubmit(
|
|
95
|
-
setSubmittedEmail(
|
|
100
|
+
await onSubmit(trimmed);
|
|
101
|
+
setSubmittedEmail(trimmed);
|
|
96
102
|
setSuccess(true);
|
|
97
103
|
} catch (e) {
|
|
98
104
|
setError(e instanceof Error ? e.message : "Something went wrong. Please try again.");
|
|
@@ -167,7 +173,10 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
|
|
|
167
173
|
{
|
|
168
174
|
type: "email",
|
|
169
175
|
value: email,
|
|
170
|
-
onChange: (e) =>
|
|
176
|
+
onChange: (e) => {
|
|
177
|
+
setEmail(e.target.value);
|
|
178
|
+
if (error) setError(null);
|
|
179
|
+
},
|
|
171
180
|
onKeyDown: handleKeyDown,
|
|
172
181
|
placeholder: "hello@gmail.com",
|
|
173
182
|
autoFocus: true,
|
|
@@ -224,12 +233,20 @@ function formatClassTime(cls) {
|
|
|
224
233
|
const em = endTotal % 60;
|
|
225
234
|
return `${h}:${cls.startTime.minutes}-${eh}:${String(em).padStart(2, "0")}`;
|
|
226
235
|
}
|
|
236
|
+
function formatBookingLabel(cls) {
|
|
237
|
+
const price = cls.price;
|
|
238
|
+
const isFree = price === null || price === void 0 || `${price}` === "" || `${price}` === "0";
|
|
239
|
+
return isFree ? "Book for free" : `Book for ${cls.currency ?? ""} ${price}`.trim();
|
|
240
|
+
}
|
|
227
241
|
function getBookingsOnDate(cls, date) {
|
|
228
242
|
if (!cls.bookings?.length) return 0;
|
|
229
|
-
const
|
|
243
|
+
const target = new Date(date);
|
|
244
|
+
target.setHours(0, 0, 0, 0);
|
|
230
245
|
return cls.bookings.filter((b) => {
|
|
231
246
|
try {
|
|
232
|
-
|
|
247
|
+
const bookingDate = new Date(b.classDate);
|
|
248
|
+
bookingDate.setHours(0, 0, 0, 0);
|
|
249
|
+
return bookingDate.getTime() === target.getTime();
|
|
233
250
|
} catch {
|
|
234
251
|
return false;
|
|
235
252
|
}
|
|
@@ -494,7 +511,7 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
|
|
|
494
511
|
}
|
|
495
512
|
)
|
|
496
513
|
] }),
|
|
497
|
-
/* @__PURE__ */ jsx2("div", { className: "sm:hidden flex flex-col gap-px", children: isFull ? /* @__PURE__ */ jsx2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
514
|
+
cls.showAvailability !== false && /* @__PURE__ */ jsx2("div", { className: "sm:hidden flex flex-col gap-px", children: isFull ? /* @__PURE__ */ jsx2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
498
515
|
/* @__PURE__ */ jsxs2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: [
|
|
499
516
|
available,
|
|
500
517
|
"/",
|
|
@@ -506,9 +523,17 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
|
|
|
506
523
|
/* @__PURE__ */ jsxs2("div", { className: "flex flex-1 flex-col gap-2 min-w-0 sm:contents", children: [
|
|
507
524
|
/* @__PURE__ */ jsxs2("div", { className: "flex-1 flex flex-col gap-2 min-w-0", children: [
|
|
508
525
|
/* @__PURE__ */ jsx2("span", { className: "font-body text-base font-bold text-(--color-dark,#200C02) block truncate", children: cls.name }),
|
|
509
|
-
cls.hostName && /* @__PURE__ */ jsx2("span", { className: "font-body text-base font-normal text-(--color-dark,#200C02) opacity-80 block truncate", children: cls.hostName })
|
|
526
|
+
cls.hostName && /* @__PURE__ */ jsx2("span", { className: "font-body text-base font-normal text-(--color-dark,#200C02) opacity-80 block truncate", children: cls.hostName }),
|
|
527
|
+
cls.description && /* @__PURE__ */ jsx2(
|
|
528
|
+
"span",
|
|
529
|
+
{
|
|
530
|
+
className: "font-body text-base font-normal text-(--color-dark,#200C02) opacity-80 block",
|
|
531
|
+
style: { wordBreak: "break-word" },
|
|
532
|
+
children: cls.description
|
|
533
|
+
}
|
|
534
|
+
)
|
|
510
535
|
] }),
|
|
511
|
-
/* @__PURE__ */ jsx2("div", { className: "hidden sm:flex w-14 shrink-0 flex-col gap-px", children: isFull ? /* @__PURE__ */ jsx2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
536
|
+
cls.showAvailability !== false && /* @__PURE__ */ jsx2("div", { className: "hidden sm:flex w-14 shrink-0 flex-col gap-px", children: isFull ? /* @__PURE__ */ jsx2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
512
537
|
/* @__PURE__ */ jsxs2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: [
|
|
513
538
|
available,
|
|
514
539
|
"/",
|
|
@@ -533,7 +558,7 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
|
|
|
533
558
|
if (!cls.id) return;
|
|
534
559
|
onOpenModal?.(isFull ? "waitlist" : "book", cls.id, selectedDate);
|
|
535
560
|
},
|
|
536
|
-
children: isFull ? "Join Waitlist" :
|
|
561
|
+
children: isFull ? "Join Waitlist" : formatBookingLabel(cls)
|
|
537
562
|
}
|
|
538
563
|
)
|
|
539
564
|
] })
|
|
@@ -575,6 +600,17 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
575
600
|
const [isHovered, setIsHovered] = useState2(false);
|
|
576
601
|
const [modalState, setModalState] = useState2(null);
|
|
577
602
|
const switchScheduleIdRef = useRef(null);
|
|
603
|
+
const liveScheduleIdRef = useRef(null);
|
|
604
|
+
const refetchLiveSchedule = useCallback(async () => {
|
|
605
|
+
const id = liveScheduleIdRef.current;
|
|
606
|
+
if (!id) return;
|
|
607
|
+
try {
|
|
608
|
+
const res = await fetch(`${API_URL}/api/schedule/id/${id}`);
|
|
609
|
+
const data = await res.json();
|
|
610
|
+
if (data?.id) setSchedule(data);
|
|
611
|
+
} catch {
|
|
612
|
+
}
|
|
613
|
+
}, []);
|
|
578
614
|
const dates = useMemo(() => {
|
|
579
615
|
const today = /* @__PURE__ */ new Date();
|
|
580
616
|
today.setHours(0, 0, 0, 0);
|
|
@@ -594,6 +630,18 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
594
630
|
}
|
|
595
631
|
}
|
|
596
632
|
}, [schedule, dates]);
|
|
633
|
+
useEffect(() => {
|
|
634
|
+
if (typeof window === "undefined") return;
|
|
635
|
+
const onVisible = () => {
|
|
636
|
+
if (!document.hidden) void refetchLiveSchedule();
|
|
637
|
+
};
|
|
638
|
+
window.addEventListener("focus", refetchLiveSchedule);
|
|
639
|
+
document.addEventListener("visibilitychange", onVisible);
|
|
640
|
+
return () => {
|
|
641
|
+
window.removeEventListener("focus", refetchLiveSchedule);
|
|
642
|
+
document.removeEventListener("visibilitychange", onVisible);
|
|
643
|
+
};
|
|
644
|
+
}, [refetchLiveSchedule]);
|
|
597
645
|
useEffect(() => {
|
|
598
646
|
if (typeof window === "undefined") return;
|
|
599
647
|
const isInEditor = window.self !== window.top;
|
|
@@ -655,7 +703,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
655
703
|
setLoading(false);
|
|
656
704
|
return;
|
|
657
705
|
}
|
|
658
|
-
;
|
|
706
|
+
liveScheduleIdRef.current = effectiveId;
|
|
659
707
|
(async () => {
|
|
660
708
|
try {
|
|
661
709
|
const res = await fetch(`${API_URL}/api/schedule/id/${effectiveId}`);
|
|
@@ -712,18 +760,14 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
712
760
|
const data = await res.json().catch(() => ({}));
|
|
713
761
|
throw new Error(data?.message ?? "Something went wrong. Please try again.");
|
|
714
762
|
}
|
|
763
|
+
await refetchLiveSchedule();
|
|
715
764
|
};
|
|
716
765
|
const handleReplaceSchedule = () => {
|
|
717
766
|
setIsHovered(false);
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
insertAfter
|
|
723
|
-
}, "*");
|
|
724
|
-
} else {
|
|
725
|
-
window.parent.postMessage({ type: "ow:scheduling-not-connected", insertAfter }, "*");
|
|
726
|
-
}
|
|
767
|
+
window.parent.postMessage(
|
|
768
|
+
{ type: "ow:scheduling-not-connected", insertAfter, currentScheduleId: schedule?.id },
|
|
769
|
+
"*"
|
|
770
|
+
);
|
|
727
771
|
};
|
|
728
772
|
if (!inEditor && !loading && !schedule) return null;
|
|
729
773
|
const sectionId = `scheduling-${insertAfter}`;
|
|
@@ -766,7 +810,19 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
766
810
|
),
|
|
767
811
|
/* @__PURE__ */ jsxs2("div", { className: "max-w-[1280px] mx-auto flex flex-col items-center gap-16", children: [
|
|
768
812
|
/* @__PURE__ */ jsxs2("div", { className: "flex flex-col items-center gap-4", children: [
|
|
769
|
-
/* @__PURE__ */ jsx2(
|
|
813
|
+
/* @__PURE__ */ jsx2(
|
|
814
|
+
"h2",
|
|
815
|
+
{
|
|
816
|
+
className: "font-display text-center m-0 text-(--color-dark,#200C02)",
|
|
817
|
+
style: {
|
|
818
|
+
fontSize: "var(--fs-section-h2, clamp(40px, 4.4vw, 64px))",
|
|
819
|
+
fontWeight: "var(--font-weight-heading, 400)",
|
|
820
|
+
lineHeight: 1.05,
|
|
821
|
+
letterSpacing: "-0.02em"
|
|
822
|
+
},
|
|
823
|
+
children: schedule?.name ?? "Book an appointment"
|
|
824
|
+
}
|
|
825
|
+
),
|
|
770
826
|
schedule?.description && /* @__PURE__ */ jsx2("p", { className: "font-body text-body text-center m-0 text-(--color-accent,#A89B83)", children: schedule.description })
|
|
771
827
|
] }),
|
|
772
828
|
/* @__PURE__ */ jsxs2("div", { className: "w-full flex flex-col items-end gap-3", children: [
|
|
@@ -4286,7 +4342,7 @@ import { Link, MoreHorizontal, Plus } from "lucide-react";
|
|
|
4286
4342
|
|
|
4287
4343
|
// src/ui/tooltip.tsx
|
|
4288
4344
|
import { Tooltip as TooltipPrimitive } from "radix-ui";
|
|
4289
|
-
import { jsx as jsx7
|
|
4345
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
4290
4346
|
function TooltipProvider({
|
|
4291
4347
|
delayDuration = 0,
|
|
4292
4348
|
...props
|
|
@@ -4299,39 +4355,45 @@ function Tooltip({ ...props }) {
|
|
|
4299
4355
|
function TooltipTrigger({ ...props }) {
|
|
4300
4356
|
return /* @__PURE__ */ jsx7(TooltipPrimitive.Trigger, { "data-slot": "tooltip-trigger", ...props });
|
|
4301
4357
|
}
|
|
4358
|
+
var arrowClassBySide = {
|
|
4359
|
+
top: "before:bottom-0 before:left-1/2 before:-translate-x-1/2 before:translate-y-1/2",
|
|
4360
|
+
bottom: "before:top-0 before:left-1/2 before:-translate-x-1/2 before:-translate-y-1/2",
|
|
4361
|
+
left: "before:right-0 before:top-1/2 before:-translate-y-1/2 before:translate-x-1/2",
|
|
4362
|
+
right: "before:left-0 before:top-1/2 before:-translate-y-1/2 before:-translate-x-1/2"
|
|
4363
|
+
};
|
|
4302
4364
|
function TooltipContent({
|
|
4303
4365
|
className,
|
|
4304
|
-
sideOffset =
|
|
4366
|
+
sideOffset = 9,
|
|
4305
4367
|
side = "bottom",
|
|
4306
4368
|
children,
|
|
4307
4369
|
hideArrow,
|
|
4308
4370
|
...props
|
|
4309
4371
|
}) {
|
|
4310
|
-
|
|
4372
|
+
const resolvedSide = side ?? "bottom";
|
|
4373
|
+
return /* @__PURE__ */ jsx7(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsx7(
|
|
4311
4374
|
TooltipPrimitive.Content,
|
|
4312
4375
|
{
|
|
4313
4376
|
"data-slot": "tooltip-content",
|
|
4314
4377
|
side,
|
|
4315
4378
|
sideOffset,
|
|
4316
4379
|
className: cn(
|
|
4317
|
-
"z-[2147483647] inline-flex w-fit max-w-xs items-center rounded-md bg-foreground px-3 py-1.5 text-xs text-background",
|
|
4380
|
+
"relative z-[2147483647] inline-flex w-fit max-w-xs items-center rounded-md bg-foreground px-3 py-1.5 text-xs text-background",
|
|
4318
4381
|
"origin-[var(--radix-tooltip-content-transform-origin)] animate-in fade-in-0 zoom-in-95",
|
|
4319
4382
|
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
|
|
4320
4383
|
"data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2",
|
|
4321
4384
|
"data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2",
|
|
4385
|
+
!hideArrow && 'before:pointer-events-none before:absolute before:size-2 before:rotate-45 before:bg-foreground before:content-[""]',
|
|
4386
|
+
!hideArrow && arrowClassBySide[resolvedSide],
|
|
4322
4387
|
className
|
|
4323
4388
|
),
|
|
4324
4389
|
...props,
|
|
4325
|
-
children
|
|
4326
|
-
children,
|
|
4327
|
-
!hideArrow && /* @__PURE__ */ jsx7(TooltipPrimitive.Arrow, { className: "z-[2147483647] size-2.5 translate-y-[calc(-50%-2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground" })
|
|
4328
|
-
]
|
|
4390
|
+
children
|
|
4329
4391
|
}
|
|
4330
4392
|
) });
|
|
4331
4393
|
}
|
|
4332
4394
|
|
|
4333
4395
|
// src/ui/item-action-toolbar.tsx
|
|
4334
|
-
import { jsx as jsx8, jsxs as
|
|
4396
|
+
import { jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
4335
4397
|
function ToolbarActionTooltip({
|
|
4336
4398
|
label,
|
|
4337
4399
|
side = "bottom",
|
|
@@ -4340,9 +4402,9 @@ function ToolbarActionTooltip({
|
|
|
4340
4402
|
children
|
|
4341
4403
|
}) {
|
|
4342
4404
|
const button = /* @__PURE__ */ jsx8(CustomToolbarButton, { type: "button", "aria-label": label, disabled, ...buttonProps, children });
|
|
4343
|
-
return /* @__PURE__ */
|
|
4405
|
+
return /* @__PURE__ */ jsxs3(Tooltip, { children: [
|
|
4344
4406
|
/* @__PURE__ */ jsx8(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ jsx8("span", { className: "inline-flex", children: button }) : button }),
|
|
4345
|
-
/* @__PURE__ */ jsx8(TooltipContent, { side, sideOffset:
|
|
4407
|
+
/* @__PURE__ */ jsx8(TooltipContent, { side, sideOffset: 9, children: label })
|
|
4346
4408
|
] });
|
|
4347
4409
|
}
|
|
4348
4410
|
function ItemActionToolbar({
|
|
@@ -4356,7 +4418,7 @@ function ItemActionToolbar({
|
|
|
4356
4418
|
showMore = true,
|
|
4357
4419
|
tooltipSide = "bottom"
|
|
4358
4420
|
}) {
|
|
4359
|
-
return /* @__PURE__ */ jsx8(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */
|
|
4421
|
+
return /* @__PURE__ */ jsx8(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs3(CustomToolbar, { children: [
|
|
4360
4422
|
/* @__PURE__ */ jsx8(
|
|
4361
4423
|
ToolbarActionTooltip,
|
|
4362
4424
|
{
|
|
@@ -4417,13 +4479,26 @@ function ItemActionToolbar({
|
|
|
4417
4479
|
|
|
4418
4480
|
// src/ui/item-interaction-layer.tsx
|
|
4419
4481
|
import * as React5 from "react";
|
|
4420
|
-
import { jsx as jsx9, jsxs as
|
|
4482
|
+
import { jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
4421
4483
|
var PRIMARY = "var(--ohw-primary, #0885FE)";
|
|
4422
4484
|
var FOCUS_RING = `0 0 0 4px color-mix(in srgb, ${PRIMARY} 12%, transparent)`;
|
|
4423
4485
|
var DRAG_SHADOW = "0px 4px 6px -1px rgba(0, 0, 0, 0.1), 0px 2px 4px -2px rgba(0, 0, 0, 0.1)";
|
|
4424
4486
|
var TOOLBAR_EDGE_MARGIN = 4;
|
|
4425
4487
|
var SELECTION_CHROME_GAP = 4;
|
|
4426
4488
|
var TOOLBAR_STROKE_GAP = 4;
|
|
4489
|
+
function getChromeZIndex(state) {
|
|
4490
|
+
switch (state) {
|
|
4491
|
+
case "active-top":
|
|
4492
|
+
case "active-bottom":
|
|
4493
|
+
case "dragging":
|
|
4494
|
+
return 2147483644;
|
|
4495
|
+
case "hover":
|
|
4496
|
+
case "sibling-hint":
|
|
4497
|
+
return 2147483643;
|
|
4498
|
+
default:
|
|
4499
|
+
return 2147483642;
|
|
4500
|
+
}
|
|
4501
|
+
}
|
|
4427
4502
|
function getChromeStyle(state) {
|
|
4428
4503
|
switch (state) {
|
|
4429
4504
|
case "hover":
|
|
@@ -4445,7 +4520,7 @@ function getChromeStyle(state) {
|
|
|
4445
4520
|
case "dragging":
|
|
4446
4521
|
return {
|
|
4447
4522
|
border: `2px solid ${PRIMARY}`,
|
|
4448
|
-
boxShadow: DRAG_SHADOW
|
|
4523
|
+
boxShadow: `${FOCUS_RING}, ${DRAG_SHADOW}`
|
|
4449
4524
|
};
|
|
4450
4525
|
default:
|
|
4451
4526
|
return {};
|
|
@@ -4514,6 +4589,9 @@ function ItemInteractionLayer({
|
|
|
4514
4589
|
dragHandleLabel = "Reorder item",
|
|
4515
4590
|
onDragHandleDragStart,
|
|
4516
4591
|
onDragHandleDragEnd,
|
|
4592
|
+
onItemPointerDown,
|
|
4593
|
+
onItemClick,
|
|
4594
|
+
itemDragSurface = true,
|
|
4517
4595
|
chromeGap = SELECTION_CHROME_GAP,
|
|
4518
4596
|
className
|
|
4519
4597
|
}) {
|
|
@@ -4521,8 +4599,9 @@ function ItemInteractionLayer({
|
|
|
4521
4599
|
const isActive = state === "active-top" || state === "active-bottom";
|
|
4522
4600
|
const isDragging = state === "dragging";
|
|
4523
4601
|
const showToolbar = isActive && toolbar;
|
|
4524
|
-
const showDragHandle = isActive
|
|
4525
|
-
|
|
4602
|
+
const showDragHandle = (isActive || isDragging) && showHandle;
|
|
4603
|
+
const itemDragEnabled = itemDragSurface && isActive && showHandle && !isDragging && !dragDisabled;
|
|
4604
|
+
return /* @__PURE__ */ jsxs4(
|
|
4526
4605
|
"div",
|
|
4527
4606
|
{
|
|
4528
4607
|
ref: elRef,
|
|
@@ -4535,7 +4614,7 @@ function ItemInteractionLayer({
|
|
|
4535
4614
|
left: rect.left - chromeGap,
|
|
4536
4615
|
width: rect.width + chromeGap * 2,
|
|
4537
4616
|
height: rect.height + chromeGap * 2,
|
|
4538
|
-
zIndex:
|
|
4617
|
+
zIndex: getChromeZIndex(state)
|
|
4539
4618
|
},
|
|
4540
4619
|
children: [
|
|
4541
4620
|
/* @__PURE__ */ jsx9(
|
|
@@ -4546,11 +4625,29 @@ function ItemInteractionLayer({
|
|
|
4546
4625
|
style: getChromeStyle(state)
|
|
4547
4626
|
}
|
|
4548
4627
|
),
|
|
4628
|
+
itemDragEnabled && /* @__PURE__ */ jsx9(
|
|
4629
|
+
"div",
|
|
4630
|
+
{
|
|
4631
|
+
"data-ohw-item-drag-surface": "",
|
|
4632
|
+
className: "pointer-events-auto absolute inset-0 cursor-text rounded-lg",
|
|
4633
|
+
onPointerDown: (e) => {
|
|
4634
|
+
if (e.button !== 0) return;
|
|
4635
|
+
onItemPointerDown?.(e);
|
|
4636
|
+
},
|
|
4637
|
+
onClick: (e) => {
|
|
4638
|
+
e.preventDefault();
|
|
4639
|
+
e.stopPropagation();
|
|
4640
|
+
onItemClick?.(e.clientX, e.clientY);
|
|
4641
|
+
}
|
|
4642
|
+
}
|
|
4643
|
+
),
|
|
4549
4644
|
showDragHandle && /* @__PURE__ */ jsx9(
|
|
4550
4645
|
"div",
|
|
4551
4646
|
{
|
|
4552
4647
|
"data-ohw-drag-handle-container": "",
|
|
4553
|
-
className: "pointer-events-auto absolute left-0 top-1/2 -translate-x-[calc(100%+7px)] -translate-y-1/2",
|
|
4648
|
+
className: "pointer-events-auto absolute left-0 top-1/2 z-10 -translate-x-[calc(100%+7px)] -translate-y-1/2",
|
|
4649
|
+
style: isDragging ? { opacity: 0 } : void 0,
|
|
4650
|
+
"aria-hidden": isDragging || void 0,
|
|
4554
4651
|
children: /* @__PURE__ */ jsx9(
|
|
4555
4652
|
DragHandle,
|
|
4556
4653
|
{
|
|
@@ -4562,7 +4659,17 @@ function ItemInteractionLayer({
|
|
|
4562
4659
|
e.preventDefault();
|
|
4563
4660
|
return;
|
|
4564
4661
|
}
|
|
4565
|
-
|
|
4662
|
+
const blank = document.createElement("canvas");
|
|
4663
|
+
blank.width = 1;
|
|
4664
|
+
blank.height = 1;
|
|
4665
|
+
blank.style.cssText = "position:fixed;left:-9999px;top:-9999px;width:1px;height:1px;pointer-events:none";
|
|
4666
|
+
document.body.appendChild(blank);
|
|
4667
|
+
try {
|
|
4668
|
+
e.dataTransfer.setDragImage(blank, 0, 0);
|
|
4669
|
+
} finally {
|
|
4670
|
+
requestAnimationFrame(() => blank.remove());
|
|
4671
|
+
}
|
|
4672
|
+
e.dataTransfer.setData("text/plain", dragHandleLabel);
|
|
4566
4673
|
e.dataTransfer.effectAllowed = "move";
|
|
4567
4674
|
onDragHandleDragStart?.(e);
|
|
4568
4675
|
},
|
|
@@ -4623,7 +4730,7 @@ var Button = React6.forwardRef(
|
|
|
4623
4730
|
Button.displayName = "Button";
|
|
4624
4731
|
|
|
4625
4732
|
// src/ui/MediaOverlay.tsx
|
|
4626
|
-
import { Fragment as Fragment2, jsx as jsx11, jsxs as
|
|
4733
|
+
import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
4627
4734
|
var MEDIA_UPLOAD_FADE_MS = 300;
|
|
4628
4735
|
var VIDEO_SETTINGS_BAR_INSET = 8;
|
|
4629
4736
|
var OVERLAY_BUTTON_STYLE = {
|
|
@@ -4694,7 +4801,7 @@ function MediaOverlay({
|
|
|
4694
4801
|
}
|
|
4695
4802
|
);
|
|
4696
4803
|
}
|
|
4697
|
-
const settingsBar = isVideo && !hover.isDragOver ? /* @__PURE__ */
|
|
4804
|
+
const settingsBar = isVideo && !hover.isDragOver ? /* @__PURE__ */ jsxs5(
|
|
4698
4805
|
"div",
|
|
4699
4806
|
{
|
|
4700
4807
|
"data-ohw-bridge": "",
|
|
@@ -4749,7 +4856,7 @@ function MediaOverlay({
|
|
|
4749
4856
|
]
|
|
4750
4857
|
}
|
|
4751
4858
|
) : null;
|
|
4752
|
-
return /* @__PURE__ */
|
|
4859
|
+
return /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
4753
4860
|
settingsBar,
|
|
4754
4861
|
/* @__PURE__ */ jsx11(
|
|
4755
4862
|
"div",
|
|
@@ -4768,14 +4875,18 @@ function MediaOverlay({
|
|
|
4768
4875
|
background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
|
|
4769
4876
|
},
|
|
4770
4877
|
onClick: () => onReplace(hover.key),
|
|
4771
|
-
children: /* @__PURE__ */
|
|
4878
|
+
children: /* @__PURE__ */ jsxs5(
|
|
4772
4879
|
Button,
|
|
4773
4880
|
{
|
|
4774
4881
|
"data-ohw-media-overlay": "",
|
|
4775
4882
|
variant: "outline",
|
|
4776
4883
|
size: "sm",
|
|
4777
4884
|
className: "gap-1.5 cursor-pointer hover:bg-background",
|
|
4778
|
-
style:
|
|
4885
|
+
style: {
|
|
4886
|
+
...OVERLAY_BUTTON_STYLE,
|
|
4887
|
+
// Don't let Replace steal clicks when text (e.g. nav) sits on top of this media.
|
|
4888
|
+
pointerEvents: hover.hasTextOverlap ? "none" : "auto"
|
|
4889
|
+
},
|
|
4779
4890
|
onMouseDown: (e) => e.preventDefault(),
|
|
4780
4891
|
onClick: (e) => {
|
|
4781
4892
|
e.stopPropagation();
|
|
@@ -5078,7 +5189,7 @@ import { useEffect as useEffect6 } from "react";
|
|
|
5078
5189
|
import * as React8 from "react";
|
|
5079
5190
|
import { Dialog as DialogPrimitive } from "radix-ui";
|
|
5080
5191
|
import { X } from "lucide-react";
|
|
5081
|
-
import { jsx as jsx12, jsxs as
|
|
5192
|
+
import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
5082
5193
|
function Dialog2({
|
|
5083
5194
|
...props
|
|
5084
5195
|
}) {
|
|
@@ -5106,9 +5217,9 @@ function DialogOverlay({
|
|
|
5106
5217
|
var DialogContent = React8.forwardRef(
|
|
5107
5218
|
({ className, children, showCloseButton = true, container, ...props }, ref) => {
|
|
5108
5219
|
const positionMode = container ? "absolute" : "fixed";
|
|
5109
|
-
return /* @__PURE__ */
|
|
5220
|
+
return /* @__PURE__ */ jsxs6(DialogPortal, { container: container ?? void 0, children: [
|
|
5110
5221
|
/* @__PURE__ */ jsx12(DialogOverlay, { className: cn(positionMode, "inset-0") }),
|
|
5111
|
-
/* @__PURE__ */
|
|
5222
|
+
/* @__PURE__ */ jsxs6(
|
|
5112
5223
|
DialogPrimitive.Content,
|
|
5113
5224
|
{
|
|
5114
5225
|
ref,
|
|
@@ -5186,15 +5297,15 @@ import { Info, X as X3 } from "lucide-react";
|
|
|
5186
5297
|
|
|
5187
5298
|
// src/ui/link-modal/DestinationBreadcrumb.tsx
|
|
5188
5299
|
import { ArrowRight, File, GalleryVertical } from "lucide-react";
|
|
5189
|
-
import { jsx as jsx13, jsxs as
|
|
5300
|
+
import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
5190
5301
|
function DestinationBreadcrumb({
|
|
5191
5302
|
pageTitle,
|
|
5192
5303
|
sectionLabel
|
|
5193
5304
|
}) {
|
|
5194
|
-
return /* @__PURE__ */
|
|
5305
|
+
return /* @__PURE__ */ jsxs7("div", { className: "flex w-full flex-col gap-2", children: [
|
|
5195
5306
|
/* @__PURE__ */ jsx13("p", { className: "text-sm font-medium! text-foreground m-0", children: "Destination" }),
|
|
5196
|
-
/* @__PURE__ */
|
|
5197
|
-
/* @__PURE__ */
|
|
5307
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-3", children: [
|
|
5308
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2", children: [
|
|
5198
5309
|
/* @__PURE__ */ jsx13(File, { size: 16, className: "shrink-0 text-foreground", "aria-hidden": true }),
|
|
5199
5310
|
/* @__PURE__ */ jsx13("span", { className: "text-sm font-medium leading-none text-foreground!", children: pageTitle })
|
|
5200
5311
|
] }),
|
|
@@ -5206,7 +5317,7 @@ function DestinationBreadcrumb({
|
|
|
5206
5317
|
"aria-hidden": true
|
|
5207
5318
|
}
|
|
5208
5319
|
),
|
|
5209
|
-
/* @__PURE__ */
|
|
5320
|
+
/* @__PURE__ */ jsxs7("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
|
|
5210
5321
|
/* @__PURE__ */ jsx13(
|
|
5211
5322
|
GalleryVertical,
|
|
5212
5323
|
{
|
|
@@ -5223,14 +5334,14 @@ function DestinationBreadcrumb({
|
|
|
5223
5334
|
|
|
5224
5335
|
// src/ui/link-modal/SectionTreeItem.tsx
|
|
5225
5336
|
import { GalleryVertical as GalleryVertical2 } from "lucide-react";
|
|
5226
|
-
import { jsx as jsx14, jsxs as
|
|
5337
|
+
import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
5227
5338
|
function SectionTreeItem({
|
|
5228
5339
|
section,
|
|
5229
5340
|
onSelect,
|
|
5230
5341
|
selected
|
|
5231
5342
|
}) {
|
|
5232
5343
|
const interactive = Boolean(onSelect);
|
|
5233
|
-
return /* @__PURE__ */
|
|
5344
|
+
return /* @__PURE__ */ jsxs8("div", { className: "flex h-9 w-full items-end pl-3", children: [
|
|
5234
5345
|
/* @__PURE__ */ jsx14(
|
|
5235
5346
|
"div",
|
|
5236
5347
|
{
|
|
@@ -5238,7 +5349,7 @@ function SectionTreeItem({
|
|
|
5238
5349
|
"aria-hidden": true
|
|
5239
5350
|
}
|
|
5240
5351
|
),
|
|
5241
|
-
/* @__PURE__ */
|
|
5352
|
+
/* @__PURE__ */ jsxs8(
|
|
5242
5353
|
"div",
|
|
5243
5354
|
{
|
|
5244
5355
|
role: interactive ? "button" : void 0,
|
|
@@ -5312,7 +5423,7 @@ function Label({ className, ...props }) {
|
|
|
5312
5423
|
|
|
5313
5424
|
// src/ui/link-modal/UrlOrPageInput.tsx
|
|
5314
5425
|
import { ChevronDown, File as File2, X as X2 } from "lucide-react";
|
|
5315
|
-
import { jsx as jsx17, jsxs as
|
|
5426
|
+
import { jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
5316
5427
|
function FieldChevron({
|
|
5317
5428
|
onClick
|
|
5318
5429
|
}) {
|
|
@@ -5385,10 +5496,10 @@ function UrlOrPageInput({
|
|
|
5385
5496
|
"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]",
|
|
5386
5497
|
urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
|
|
5387
5498
|
);
|
|
5388
|
-
return /* @__PURE__ */
|
|
5499
|
+
return /* @__PURE__ */ jsxs9("div", { className: "flex w-full flex-col gap-2 p-0", children: [
|
|
5389
5500
|
/* @__PURE__ */ jsx17(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
|
|
5390
|
-
/* @__PURE__ */
|
|
5391
|
-
/* @__PURE__ */
|
|
5501
|
+
/* @__PURE__ */ jsxs9("div", { ref: rootRef, className: "relative w-full", children: [
|
|
5502
|
+
/* @__PURE__ */ jsxs9("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
|
|
5392
5503
|
selectedPage ? /* @__PURE__ */ jsx17("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ jsx17(
|
|
5393
5504
|
File2,
|
|
5394
5505
|
{
|
|
@@ -5442,7 +5553,7 @@ function UrlOrPageInput({
|
|
|
5442
5553
|
"data-ohw-link-page-dropdown": "",
|
|
5443
5554
|
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",
|
|
5444
5555
|
onMouseDown: (e) => e.preventDefault(),
|
|
5445
|
-
children: filteredPages.map((page) => /* @__PURE__ */
|
|
5556
|
+
children: filteredPages.map((page) => /* @__PURE__ */ jsxs9(
|
|
5446
5557
|
"button",
|
|
5447
5558
|
{
|
|
5448
5559
|
type: "button",
|
|
@@ -5463,10 +5574,10 @@ function UrlOrPageInput({
|
|
|
5463
5574
|
}
|
|
5464
5575
|
|
|
5465
5576
|
// src/ui/link-modal/LinkEditorPanel.tsx
|
|
5466
|
-
import { Fragment as Fragment3, jsx as jsx18, jsxs as
|
|
5577
|
+
import { Fragment as Fragment3, jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
5467
5578
|
function LinkEditorPanel({ state, onClose }) {
|
|
5468
5579
|
const isCancel = state.secondaryLabel === "Cancel" || state.secondaryLabel === "Back to sections";
|
|
5469
|
-
return /* @__PURE__ */
|
|
5580
|
+
return /* @__PURE__ */ jsxs10(Fragment3, { children: [
|
|
5470
5581
|
/* @__PURE__ */ jsx18(DialogClose, { asChild: true, children: /* @__PURE__ */ jsx18(
|
|
5471
5582
|
"button",
|
|
5472
5583
|
{
|
|
@@ -5478,7 +5589,7 @@ function LinkEditorPanel({ state, onClose }) {
|
|
|
5478
5589
|
}
|
|
5479
5590
|
) }),
|
|
5480
5591
|
/* @__PURE__ */ jsx18(DialogHeader, { className: "w-full gap-1.5 p-6 pr-12", children: /* @__PURE__ */ jsx18(DialogTitle, { className: "m-0 w-full break-words", children: state.title }) }),
|
|
5481
|
-
/* @__PURE__ */
|
|
5592
|
+
/* @__PURE__ */ jsxs10("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
|
|
5482
5593
|
state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ jsx18(
|
|
5483
5594
|
DestinationBreadcrumb,
|
|
5484
5595
|
{
|
|
@@ -5498,7 +5609,7 @@ function LinkEditorPanel({ state, onClose }) {
|
|
|
5498
5609
|
urlError: state.urlError
|
|
5499
5610
|
}
|
|
5500
5611
|
),
|
|
5501
|
-
state.showChooseSection ? /* @__PURE__ */
|
|
5612
|
+
state.showChooseSection ? /* @__PURE__ */ jsxs10("div", { className: "flex flex-col justify-center gap-2", children: [
|
|
5502
5613
|
/* @__PURE__ */ jsx18(
|
|
5503
5614
|
Button,
|
|
5504
5615
|
{
|
|
@@ -5510,14 +5621,14 @@ function LinkEditorPanel({ state, onClose }) {
|
|
|
5510
5621
|
children: "Choose a section"
|
|
5511
5622
|
}
|
|
5512
5623
|
),
|
|
5513
|
-
/* @__PURE__ */
|
|
5624
|
+
/* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
|
|
5514
5625
|
/* @__PURE__ */ jsx18(Info, { size: 16, className: "shrink-0", "aria-hidden": true }),
|
|
5515
5626
|
/* @__PURE__ */ jsx18("span", { children: "Pick a section this link should scroll to." })
|
|
5516
5627
|
] })
|
|
5517
5628
|
] }) : null,
|
|
5518
5629
|
state.showSectionRow && state.selectedSection ? /* @__PURE__ */ jsx18(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
|
|
5519
5630
|
] }),
|
|
5520
|
-
/* @__PURE__ */
|
|
5631
|
+
/* @__PURE__ */ jsxs10(DialogFooter, { className: "w-full px-6 pb-6", children: [
|
|
5521
5632
|
/* @__PURE__ */ jsx18(
|
|
5522
5633
|
Button,
|
|
5523
5634
|
{
|
|
@@ -5552,11 +5663,11 @@ function LinkEditorPanel({ state, onClose }) {
|
|
|
5552
5663
|
}
|
|
5553
5664
|
|
|
5554
5665
|
// src/ui/link-modal/SectionPickerOverlay.tsx
|
|
5555
|
-
import { useCallback, useEffect as useEffect4, useMemo as useMemo2, useRef as useRef5, useState as useState4 } from "react";
|
|
5666
|
+
import { useCallback as useCallback2, useEffect as useEffect4, useMemo as useMemo2, useRef as useRef5, useState as useState4 } from "react";
|
|
5556
5667
|
import { createPortal } from "react-dom";
|
|
5557
5668
|
import { ArrowLeft, Check } from "lucide-react";
|
|
5558
5669
|
import { usePathname, useRouter } from "next/navigation";
|
|
5559
|
-
import { jsx as jsx19, jsxs as
|
|
5670
|
+
import { jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
5560
5671
|
var DIM_OVERLAY = "rgba(0, 0, 0, 0.45)";
|
|
5561
5672
|
function rectsEqual(a, b) {
|
|
5562
5673
|
if (a.size !== b.size) return false;
|
|
@@ -5683,7 +5794,7 @@ function SectionPickerOverlay({
|
|
|
5683
5794
|
);
|
|
5684
5795
|
sectionIdsRef.current = sectionIds;
|
|
5685
5796
|
const rects = useSectionRects(sectionIdsKey, isOnTargetPage);
|
|
5686
|
-
const applyHoverAt =
|
|
5797
|
+
const applyHoverAt = useCallback2(
|
|
5687
5798
|
(x, y, liveRects) => {
|
|
5688
5799
|
const ids = sectionIdsRef.current;
|
|
5689
5800
|
const map = liveRects ?? readSectionRects(ids);
|
|
@@ -5763,7 +5874,7 @@ function SectionPickerOverlay({
|
|
|
5763
5874
|
window.removeEventListener("message", onPointerSync);
|
|
5764
5875
|
};
|
|
5765
5876
|
}, [rects, applyHoverAt]);
|
|
5766
|
-
const handleSelect =
|
|
5877
|
+
const handleSelect = useCallback2(
|
|
5767
5878
|
(section) => {
|
|
5768
5879
|
if (selectedId) return;
|
|
5769
5880
|
setSelectedId(section.id);
|
|
@@ -5785,7 +5896,7 @@ function SectionPickerOverlay({
|
|
|
5785
5896
|
const portalRoot = typeof document !== "undefined" ? document.querySelector("[data-ohw-bridge-root]") ?? document.body : null;
|
|
5786
5897
|
if (!portalRoot) return null;
|
|
5787
5898
|
return createPortal(
|
|
5788
|
-
/* @__PURE__ */
|
|
5899
|
+
/* @__PURE__ */ jsxs11(
|
|
5789
5900
|
"div",
|
|
5790
5901
|
{
|
|
5791
5902
|
"data-ohw-section-picker": "",
|
|
@@ -5800,7 +5911,7 @@ function SectionPickerOverlay({
|
|
|
5800
5911
|
{
|
|
5801
5912
|
className: "pointer-events-auto fixed left-5 z-[2]",
|
|
5802
5913
|
style: { top: chromeClip.top + 20 },
|
|
5803
|
-
children: /* @__PURE__ */
|
|
5914
|
+
children: /* @__PURE__ */ jsxs11(
|
|
5804
5915
|
Button,
|
|
5805
5916
|
{
|
|
5806
5917
|
type: "button",
|
|
@@ -5844,7 +5955,7 @@ function SectionPickerOverlay({
|
|
|
5844
5955
|
const isSelected = selectedId === section.id;
|
|
5845
5956
|
const isHovered = hoveredId === section.id;
|
|
5846
5957
|
const isLit = isSelected || isHovered;
|
|
5847
|
-
return /* @__PURE__ */
|
|
5958
|
+
return /* @__PURE__ */ jsxs11(
|
|
5848
5959
|
"button",
|
|
5849
5960
|
{
|
|
5850
5961
|
type: "button",
|
|
@@ -5894,7 +6005,7 @@ function SectionPickerOverlay({
|
|
|
5894
6005
|
}
|
|
5895
6006
|
|
|
5896
6007
|
// src/ui/link-modal/useLinkModalState.ts
|
|
5897
|
-
import { useCallback as
|
|
6008
|
+
import { useCallback as useCallback3, useEffect as useEffect5, useMemo as useMemo3, useState as useState5 } from "react";
|
|
5898
6009
|
function useLinkModalState({
|
|
5899
6010
|
open,
|
|
5900
6011
|
mode,
|
|
@@ -5913,7 +6024,7 @@ function useLinkModalState({
|
|
|
5913
6024
|
const [step, setStep] = useState5("input");
|
|
5914
6025
|
const [dropdownOpen, setDropdownOpen] = useState5(false);
|
|
5915
6026
|
const [urlError, setUrlError] = useState5("");
|
|
5916
|
-
const reset =
|
|
6027
|
+
const reset = useCallback3(() => {
|
|
5917
6028
|
setSearchValue("");
|
|
5918
6029
|
setSelectedPage(null);
|
|
5919
6030
|
setSelectedSection(null);
|
|
@@ -6058,7 +6169,7 @@ function useLinkModalState({
|
|
|
6058
6169
|
}
|
|
6059
6170
|
|
|
6060
6171
|
// src/ui/link-modal/LinkPopover.tsx
|
|
6061
|
-
import { Fragment as Fragment4, jsx as jsx20, jsxs as
|
|
6172
|
+
import { Fragment as Fragment4, jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
6062
6173
|
function postToParent(data) {
|
|
6063
6174
|
window.parent?.postMessage(data, "*");
|
|
6064
6175
|
}
|
|
@@ -6154,7 +6265,7 @@ function LinkPopover({
|
|
|
6154
6265
|
);
|
|
6155
6266
|
};
|
|
6156
6267
|
}, [open, sectionPickerActive]);
|
|
6157
|
-
return /* @__PURE__ */
|
|
6268
|
+
return /* @__PURE__ */ jsxs12(Fragment4, { children: [
|
|
6158
6269
|
/* @__PURE__ */ jsx20(
|
|
6159
6270
|
Dialog2,
|
|
6160
6271
|
{
|
|
@@ -6258,9 +6369,155 @@ function shouldUseDevFixtures() {
|
|
|
6258
6369
|
return new URLSearchParams(q).get("ohw-fixtures") === "1";
|
|
6259
6370
|
}
|
|
6260
6371
|
|
|
6372
|
+
// src/lib/nav-tree.ts
|
|
6373
|
+
var MAX_LEVEL = { nav: 1 };
|
|
6374
|
+
var ROOT = null;
|
|
6375
|
+
function cloneForest(nodes) {
|
|
6376
|
+
return nodes.map((n) => ({ id: n.id, children: cloneForest(n.children) }));
|
|
6377
|
+
}
|
|
6378
|
+
function findNode(nodes, id, parentId = ROOT) {
|
|
6379
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
6380
|
+
const node = nodes[i];
|
|
6381
|
+
if (node.id === id) return { node, parentId, index: i, siblings: nodes };
|
|
6382
|
+
const nested = findNode(node.children, id, node.id);
|
|
6383
|
+
if (nested) return nested;
|
|
6384
|
+
}
|
|
6385
|
+
return null;
|
|
6386
|
+
}
|
|
6387
|
+
function getChildrenOf(nodes, parentId) {
|
|
6388
|
+
if (parentId === ROOT) return nodes;
|
|
6389
|
+
const found = findNode(nodes, parentId);
|
|
6390
|
+
return found ? found.node.children : null;
|
|
6391
|
+
}
|
|
6392
|
+
function isDescendant(nodes, ancestorId, maybeDescendantId) {
|
|
6393
|
+
const found = findNode(nodes, ancestorId);
|
|
6394
|
+
if (!found) return false;
|
|
6395
|
+
return findNode(found.node.children, maybeDescendantId) !== null;
|
|
6396
|
+
}
|
|
6397
|
+
function levelOf(nodes, id) {
|
|
6398
|
+
const loc = findNode(nodes, id);
|
|
6399
|
+
if (!loc) return -1;
|
|
6400
|
+
if (loc.parentId === ROOT) return 0;
|
|
6401
|
+
return 1 + Math.max(0, levelOf(nodes, loc.parentId));
|
|
6402
|
+
}
|
|
6403
|
+
function insertedLevel(nodes, parentId) {
|
|
6404
|
+
if (parentId === ROOT) return 0;
|
|
6405
|
+
const parentLevel = levelOf(nodes, parentId);
|
|
6406
|
+
if (parentLevel < 0) return -1;
|
|
6407
|
+
return parentLevel + 1;
|
|
6408
|
+
}
|
|
6409
|
+
function takeNode(nodes, id) {
|
|
6410
|
+
const forest = cloneForest(nodes);
|
|
6411
|
+
const loc = findNode(forest, id);
|
|
6412
|
+
if (!loc) return null;
|
|
6413
|
+
const [taken] = loc.siblings.splice(loc.index, 1);
|
|
6414
|
+
if (!taken) return null;
|
|
6415
|
+
return { forest, taken };
|
|
6416
|
+
}
|
|
6417
|
+
function insertInto(forest, node, parentId, index) {
|
|
6418
|
+
const siblings = getChildrenOf(forest, parentId);
|
|
6419
|
+
if (!siblings) return false;
|
|
6420
|
+
const clamped = Math.max(0, Math.min(index, siblings.length));
|
|
6421
|
+
siblings.splice(clamped, 0, node);
|
|
6422
|
+
return true;
|
|
6423
|
+
}
|
|
6424
|
+
function normalize(nodes) {
|
|
6425
|
+
const walk = (list) => list.map((n) => {
|
|
6426
|
+
const children = walk(n.children);
|
|
6427
|
+
return { id: n.id, children };
|
|
6428
|
+
});
|
|
6429
|
+
return walk(nodes);
|
|
6430
|
+
}
|
|
6431
|
+
function moveNode(model, draggedId, target) {
|
|
6432
|
+
const { parentId, index: targetIndex } = target;
|
|
6433
|
+
if (parentId === draggedId) return null;
|
|
6434
|
+
if (parentId !== ROOT && isDescendant(model, draggedId, parentId)) return null;
|
|
6435
|
+
const nextLevel = insertedLevel(model, parentId);
|
|
6436
|
+
if (nextLevel < 0 || nextLevel > MAX_LEVEL.nav) return null;
|
|
6437
|
+
const draggedLoc = findNode(model, draggedId);
|
|
6438
|
+
if (!draggedLoc) return null;
|
|
6439
|
+
if (parentId !== ROOT && draggedLoc.node.children.length > 0) return null;
|
|
6440
|
+
const taken = takeNode(model, draggedId);
|
|
6441
|
+
if (!taken) return null;
|
|
6442
|
+
let insertIndex = targetIndex;
|
|
6443
|
+
if (draggedLoc.parentId === parentId && draggedLoc.index < targetIndex) {
|
|
6444
|
+
insertIndex -= 1;
|
|
6445
|
+
}
|
|
6446
|
+
if (!insertInto(taken.forest, taken.taken, parentId, insertIndex)) return null;
|
|
6447
|
+
const next = normalize(taken.forest);
|
|
6448
|
+
if (forestsEqual(model, next)) return null;
|
|
6449
|
+
return next;
|
|
6450
|
+
}
|
|
6451
|
+
function forestsEqual(a, b) {
|
|
6452
|
+
if (a.length !== b.length) return false;
|
|
6453
|
+
for (let i = 0; i < a.length; i++) {
|
|
6454
|
+
const left = a[i];
|
|
6455
|
+
const right = b[i];
|
|
6456
|
+
if (left.id !== right.id) return false;
|
|
6457
|
+
if (!forestsEqual(left.children, right.children)) return false;
|
|
6458
|
+
}
|
|
6459
|
+
return true;
|
|
6460
|
+
}
|
|
6461
|
+
function forestFromFlatOrder(order) {
|
|
6462
|
+
return order.map((id) => ({ id, children: [] }));
|
|
6463
|
+
}
|
|
6464
|
+
function serializeNavOrder(nodes) {
|
|
6465
|
+
const hasNesting = nodes.some((n) => n.children.length > 0);
|
|
6466
|
+
if (!hasNesting) {
|
|
6467
|
+
return JSON.stringify(nodes.map((n) => n.id));
|
|
6468
|
+
}
|
|
6469
|
+
return JSON.stringify(nodes);
|
|
6470
|
+
}
|
|
6471
|
+
function parseNavOrderJson(raw) {
|
|
6472
|
+
if (!raw) return null;
|
|
6473
|
+
try {
|
|
6474
|
+
const parsed = JSON.parse(raw);
|
|
6475
|
+
if (!Array.isArray(parsed)) return null;
|
|
6476
|
+
if (parsed.every((x) => typeof x === "string")) {
|
|
6477
|
+
return forestFromFlatOrder(parsed.filter((x) => typeof x === "string" && x.length > 0));
|
|
6478
|
+
}
|
|
6479
|
+
return parseNavNodeList(parsed);
|
|
6480
|
+
} catch {
|
|
6481
|
+
return null;
|
|
6482
|
+
}
|
|
6483
|
+
}
|
|
6484
|
+
function parseNavNodeList(raw) {
|
|
6485
|
+
const out = [];
|
|
6486
|
+
for (const item of raw) {
|
|
6487
|
+
if (typeof item === "string" && item.length > 0) {
|
|
6488
|
+
out.push({ id: item, children: [] });
|
|
6489
|
+
continue;
|
|
6490
|
+
}
|
|
6491
|
+
if (!item || typeof item !== "object") return null;
|
|
6492
|
+
const rec = item;
|
|
6493
|
+
if (typeof rec.id !== "string" || !rec.id) return null;
|
|
6494
|
+
const children = Array.isArray(rec.children) ? parseNavNodeList(rec.children) : [];
|
|
6495
|
+
if (!children) return null;
|
|
6496
|
+
out.push({ id: rec.id, children });
|
|
6497
|
+
}
|
|
6498
|
+
return out;
|
|
6499
|
+
}
|
|
6500
|
+
function flattenNavOrder(nodes) {
|
|
6501
|
+
const out = [];
|
|
6502
|
+
const walk = (list) => {
|
|
6503
|
+
for (const n of list) {
|
|
6504
|
+
out.push(n.id);
|
|
6505
|
+
walk(n.children);
|
|
6506
|
+
}
|
|
6507
|
+
};
|
|
6508
|
+
walk(nodes);
|
|
6509
|
+
return out;
|
|
6510
|
+
}
|
|
6511
|
+
|
|
6261
6512
|
// src/lib/nav-items.ts
|
|
6262
6513
|
var NAV_COUNT_KEY = "__ohw_nav_count";
|
|
6263
6514
|
var NAV_ORDER_KEY = "__ohw_nav_order";
|
|
6515
|
+
var NAV_HREF_RE = /^nav-(\d+)-href$/;
|
|
6516
|
+
function isNavbarHrefKey(key) {
|
|
6517
|
+
if (!key) return false;
|
|
6518
|
+
if (key === "nav-book-href") return false;
|
|
6519
|
+
return NAV_HREF_RE.test(key);
|
|
6520
|
+
}
|
|
6264
6521
|
function getLinkHref(el) {
|
|
6265
6522
|
const key = el.getAttribute("data-ohw-href-key");
|
|
6266
6523
|
if (key) {
|
|
@@ -6297,7 +6554,7 @@ function listNavbarItems() {
|
|
|
6297
6554
|
}
|
|
6298
6555
|
function parseNavIndexFromKey(key) {
|
|
6299
6556
|
if (!key) return null;
|
|
6300
|
-
const match = key.match(
|
|
6557
|
+
const match = key.match(NAV_HREF_RE);
|
|
6301
6558
|
if (!match) return null;
|
|
6302
6559
|
return parseInt(match[1], 10);
|
|
6303
6560
|
}
|
|
@@ -6320,17 +6577,6 @@ function getNavbarExistingTargets() {
|
|
|
6320
6577
|
function getNavOrderFromDom() {
|
|
6321
6578
|
return listNavbarItems().map((el) => el.getAttribute("data-ohw-href-key")).filter((key) => Boolean(key));
|
|
6322
6579
|
}
|
|
6323
|
-
function parseNavOrder(content) {
|
|
6324
|
-
const raw = content[NAV_ORDER_KEY];
|
|
6325
|
-
if (!raw) return null;
|
|
6326
|
-
try {
|
|
6327
|
-
const parsed = JSON.parse(raw);
|
|
6328
|
-
if (!Array.isArray(parsed)) return null;
|
|
6329
|
-
return parsed.filter((key) => typeof key === "string" && key.length > 0);
|
|
6330
|
-
} catch {
|
|
6331
|
-
return null;
|
|
6332
|
-
}
|
|
6333
|
-
}
|
|
6334
6580
|
function findCounterpartByHrefKey(hrefKey, root) {
|
|
6335
6581
|
return root.querySelector(`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`);
|
|
6336
6582
|
}
|
|
@@ -6394,6 +6640,13 @@ function insertNavbarItemDom(index, href, label, afterAnchor) {
|
|
|
6394
6640
|
}
|
|
6395
6641
|
return primary;
|
|
6396
6642
|
}
|
|
6643
|
+
function navOrderKeysEqual(a, b) {
|
|
6644
|
+
if (a.length !== b.length) return false;
|
|
6645
|
+
for (let i = 0; i < a.length; i++) {
|
|
6646
|
+
if (a[i] !== b[i]) return false;
|
|
6647
|
+
}
|
|
6648
|
+
return true;
|
|
6649
|
+
}
|
|
6397
6650
|
function getNavbarLinkKeysInContainer(container) {
|
|
6398
6651
|
return Array.from(container.querySelectorAll("[data-ohw-href-key]")).filter(isNavbarLinkItem).map((el) => el.getAttribute("data-ohw-href-key")).filter((key) => Boolean(key));
|
|
6399
6652
|
}
|
|
@@ -6402,21 +6655,32 @@ function applyNavOrderToContainer(container, order) {
|
|
|
6402
6655
|
const current = getNavbarLinkKeysInContainer(container);
|
|
6403
6656
|
const extras = current.filter((key) => !desired.includes(key));
|
|
6404
6657
|
const expected = [...desired.filter((key) => current.includes(key)), ...extras];
|
|
6658
|
+
const orderedEls = [];
|
|
6659
|
+
if (navOrderKeysEqual(current, expected)) return;
|
|
6405
6660
|
if (current.length === expected.length && current.every((key, i) => key === expected[i])) {
|
|
6406
6661
|
return;
|
|
6407
6662
|
}
|
|
6663
|
+
const lastCurrentLinkEl = current.length > 0 ? findCounterpartByHrefKey(current[current.length - 1], container) : null;
|
|
6664
|
+
const anchor = lastCurrentLinkEl?.parentElement === container ? lastCurrentLinkEl.nextElementSibling : null;
|
|
6408
6665
|
const seen = /* @__PURE__ */ new Set();
|
|
6409
6666
|
for (const hrefKey of desired) {
|
|
6410
6667
|
if (seen.has(hrefKey)) continue;
|
|
6411
6668
|
seen.add(hrefKey);
|
|
6412
6669
|
const el = findCounterpartByHrefKey(hrefKey, container);
|
|
6413
|
-
if (el)
|
|
6670
|
+
if (el && isNavbarLinkItem(el)) orderedEls.push(el);
|
|
6414
6671
|
}
|
|
6415
6672
|
for (const el of container.querySelectorAll("[data-ohw-href-key]")) {
|
|
6416
6673
|
if (!isNavbarLinkItem(el)) continue;
|
|
6417
6674
|
const key = el.getAttribute("data-ohw-href-key");
|
|
6418
6675
|
if (!key || seen.has(key)) continue;
|
|
6419
|
-
|
|
6676
|
+
orderedEls.push(el);
|
|
6677
|
+
}
|
|
6678
|
+
for (const el of orderedEls) {
|
|
6679
|
+
if (anchor) {
|
|
6680
|
+
if (el.nextSibling !== anchor) container.insertBefore(el, anchor);
|
|
6681
|
+
} else if (container.lastElementChild !== el) {
|
|
6682
|
+
container.appendChild(el);
|
|
6683
|
+
}
|
|
6420
6684
|
}
|
|
6421
6685
|
}
|
|
6422
6686
|
function applyNavOrder(order) {
|
|
@@ -6425,6 +6689,75 @@ function applyNavOrder(order) {
|
|
|
6425
6689
|
const drawer = getNavbarDrawerContainer();
|
|
6426
6690
|
if (drawer) applyNavOrderToContainer(drawer, order);
|
|
6427
6691
|
}
|
|
6692
|
+
function applyChildrenOrder(parentHrefKey, childKeys, root) {
|
|
6693
|
+
const parent = findCounterpartByHrefKey(parentHrefKey, root);
|
|
6694
|
+
if (!parent) return;
|
|
6695
|
+
const group = parent.closest("[data-ohw-nav-group]");
|
|
6696
|
+
const childrenRoot = group?.querySelector(":scope > [data-ohw-nav-children]");
|
|
6697
|
+
if (!childrenRoot) return;
|
|
6698
|
+
const current = Array.from(childrenRoot.querySelectorAll(":scope > [data-ohw-href-key]")).map((el) => el.getAttribute("data-ohw-href-key")).filter((key) => Boolean(key));
|
|
6699
|
+
if (navOrderKeysEqual(current, childKeys)) return;
|
|
6700
|
+
for (const key of childKeys) {
|
|
6701
|
+
const el = findCounterpartByHrefKey(key, root);
|
|
6702
|
+
if (!el) continue;
|
|
6703
|
+
if (childrenRoot.lastElementChild !== el) {
|
|
6704
|
+
childrenRoot.appendChild(el);
|
|
6705
|
+
}
|
|
6706
|
+
}
|
|
6707
|
+
}
|
|
6708
|
+
function applyNavForest(forest) {
|
|
6709
|
+
if (forestsEqual(forest, getNavForestFromDom())) return;
|
|
6710
|
+
const rootKeys = forest.map((n) => n.id);
|
|
6711
|
+
applyNavOrder(rootKeys);
|
|
6712
|
+
const desktop = getNavbarDesktopContainer();
|
|
6713
|
+
const drawer = getNavbarDrawerContainer();
|
|
6714
|
+
for (const node of forest) {
|
|
6715
|
+
if (node.children.length === 0) continue;
|
|
6716
|
+
const childKeys = node.children.map((c) => c.id);
|
|
6717
|
+
if (desktop) applyChildrenOrder(node.id, childKeys, desktop);
|
|
6718
|
+
if (drawer) applyChildrenOrder(node.id, childKeys, drawer);
|
|
6719
|
+
}
|
|
6720
|
+
}
|
|
6721
|
+
function getNavForestFromDom() {
|
|
6722
|
+
const items = listNavbarItems();
|
|
6723
|
+
const nestedChildKeys = /* @__PURE__ */ new Set();
|
|
6724
|
+
const roots = [];
|
|
6725
|
+
for (const item of items) {
|
|
6726
|
+
const key = item.getAttribute("data-ohw-href-key");
|
|
6727
|
+
if (!key || !isNavbarHrefKey(key)) continue;
|
|
6728
|
+
if (item.closest("[data-ohw-nav-children]")) continue;
|
|
6729
|
+
const group = item.closest("[data-ohw-nav-group]");
|
|
6730
|
+
const childrenRoot = group?.querySelector(":scope > [data-ohw-nav-children]");
|
|
6731
|
+
const children = [];
|
|
6732
|
+
if (childrenRoot) {
|
|
6733
|
+
for (const child of childrenRoot.querySelectorAll(":scope > [data-ohw-href-key]")) {
|
|
6734
|
+
if (!isNavbarLinkItem(child)) continue;
|
|
6735
|
+
const childKey = child.getAttribute("data-ohw-href-key");
|
|
6736
|
+
if (!childKey || !isNavbarHrefKey(childKey)) continue;
|
|
6737
|
+
nestedChildKeys.add(childKey);
|
|
6738
|
+
children.push({ id: childKey, children: [] });
|
|
6739
|
+
}
|
|
6740
|
+
}
|
|
6741
|
+
roots.push({ id: key, children });
|
|
6742
|
+
}
|
|
6743
|
+
if (roots.length === 0) {
|
|
6744
|
+
return forestFromFlatOrder(
|
|
6745
|
+
getNavOrderFromDom().filter((k) => isNavbarHrefKey(k) && !nestedChildKeys.has(k))
|
|
6746
|
+
);
|
|
6747
|
+
}
|
|
6748
|
+
return roots;
|
|
6749
|
+
}
|
|
6750
|
+
function planNavItemMove(hrefKey, parentId, insertIndex) {
|
|
6751
|
+
const model = getNavForestFromDom();
|
|
6752
|
+
const next = moveNode(model, hrefKey, { parentId, index: insertIndex });
|
|
6753
|
+
if (!next) return null;
|
|
6754
|
+
if (forestsEqual(model, next)) return null;
|
|
6755
|
+
return {
|
|
6756
|
+
forest: next,
|
|
6757
|
+
orderJson: serializeNavOrder(next),
|
|
6758
|
+
flatOrder: flattenNavOrder(next)
|
|
6759
|
+
};
|
|
6760
|
+
}
|
|
6428
6761
|
function collectNavbarIndicesFromContent(content) {
|
|
6429
6762
|
const indices = /* @__PURE__ */ new Set();
|
|
6430
6763
|
for (const key of Object.keys(content)) {
|
|
@@ -6452,8 +6785,10 @@ function reconcileNavbarItemsFromContent(content) {
|
|
|
6452
6785
|
if (!href && !label) continue;
|
|
6453
6786
|
insertNavbarItemDom(index, href ?? "/", label ?? "Untitled", null);
|
|
6454
6787
|
}
|
|
6455
|
-
const
|
|
6456
|
-
if (
|
|
6788
|
+
const orderForest = parseNavOrderJson(content[NAV_ORDER_KEY]);
|
|
6789
|
+
if (orderForest?.length) {
|
|
6790
|
+
applyNavForest(orderForest);
|
|
6791
|
+
}
|
|
6457
6792
|
}
|
|
6458
6793
|
function buildNavOrderAfterInsert(afterAnchor, newHrefKey) {
|
|
6459
6794
|
const order = getNavOrderFromDom();
|
|
@@ -6493,149 +6828,1347 @@ function insertNavbarItem(href, label, afterAnchor = null) {
|
|
|
6493
6828
|
};
|
|
6494
6829
|
}
|
|
6495
6830
|
|
|
6496
|
-
// src/
|
|
6497
|
-
|
|
6498
|
-
|
|
6499
|
-
function
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
|
|
6503
|
-
|
|
6504
|
-
return /* @__PURE__ */ jsx21(
|
|
6505
|
-
"div",
|
|
6506
|
-
{
|
|
6507
|
-
"data-ohw-navbar-container-chrome": "",
|
|
6508
|
-
"data-ohw-bridge": "",
|
|
6509
|
-
className: "pointer-events-none fixed z-[2147483647]",
|
|
6510
|
-
style: {
|
|
6511
|
-
top: rect.top - chromeGap,
|
|
6512
|
-
left: rect.left - chromeGap,
|
|
6513
|
-
width: rect.width + chromeGap * 2,
|
|
6514
|
-
height: rect.height + chromeGap * 2
|
|
6515
|
-
},
|
|
6516
|
-
children: /* @__PURE__ */ jsx21(
|
|
6517
|
-
"button",
|
|
6518
|
-
{
|
|
6519
|
-
type: "button",
|
|
6520
|
-
"data-ohw-navbar-add-button": "",
|
|
6521
|
-
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",
|
|
6522
|
-
style: { top: "70%" },
|
|
6523
|
-
"aria-label": "Add item",
|
|
6524
|
-
onMouseDown: (e) => {
|
|
6525
|
-
e.preventDefault();
|
|
6526
|
-
e.stopPropagation();
|
|
6527
|
-
},
|
|
6528
|
-
onClick: (e) => {
|
|
6529
|
-
e.preventDefault();
|
|
6530
|
-
e.stopPropagation();
|
|
6531
|
-
onAdd();
|
|
6532
|
-
},
|
|
6533
|
-
children: /* @__PURE__ */ jsx21(Plus2, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
|
|
6534
|
-
}
|
|
6535
|
-
)
|
|
6536
|
-
}
|
|
6537
|
-
);
|
|
6831
|
+
// src/lib/footer-items.ts
|
|
6832
|
+
var FOOTER_ORDER_KEY = "__ohw_footer_order";
|
|
6833
|
+
var FOOTER_HREF_RE = /^footer-(\d+)-(\d+)-href$/;
|
|
6834
|
+
function parseFooterHrefKey(key) {
|
|
6835
|
+
if (!key) return null;
|
|
6836
|
+
const match = key.match(FOOTER_HREF_RE);
|
|
6837
|
+
if (!match) return null;
|
|
6838
|
+
return { col: parseInt(match[1], 10), item: parseInt(match[2], 10) };
|
|
6538
6839
|
}
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
6542
|
-
var badgeVariants = cva(
|
|
6543
|
-
"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",
|
|
6544
|
-
{
|
|
6545
|
-
variants: {
|
|
6546
|
-
variant: {
|
|
6547
|
-
default: "border-transparent bg-primary text-primary-foreground",
|
|
6548
|
-
secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
6549
|
-
destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
|
6550
|
-
outline: "text-foreground"
|
|
6551
|
-
}
|
|
6552
|
-
},
|
|
6553
|
-
defaultVariants: {
|
|
6554
|
-
variant: "default"
|
|
6555
|
-
}
|
|
6556
|
-
}
|
|
6557
|
-
);
|
|
6558
|
-
function Badge({ className, variant, ...props }) {
|
|
6559
|
-
return /* @__PURE__ */ jsx22("div", { className: cn(badgeVariants({ variant }), className), ...props });
|
|
6840
|
+
function isFooterHrefKey(key) {
|
|
6841
|
+
return parseFooterHrefKey(key) !== null;
|
|
6560
6842
|
}
|
|
6561
|
-
|
|
6562
|
-
|
|
6563
|
-
import { Link as Link2 } from "lucide-react";
|
|
6564
|
-
import { Fragment as Fragment5, jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
6565
|
-
var PRIMARY2 = "#0885FE";
|
|
6566
|
-
var IMAGE_FADE_MS = 300;
|
|
6567
|
-
function runOpacityFade(el, onDone) {
|
|
6568
|
-
const anim = el.animate([{ opacity: 0 }, { opacity: 1 }], {
|
|
6569
|
-
duration: IMAGE_FADE_MS,
|
|
6570
|
-
easing: "ease",
|
|
6571
|
-
fill: "forwards"
|
|
6572
|
-
});
|
|
6573
|
-
let finished = false;
|
|
6574
|
-
const finish = () => {
|
|
6575
|
-
if (finished) return;
|
|
6576
|
-
finished = true;
|
|
6577
|
-
anim.cancel();
|
|
6578
|
-
el.style.opacity = "";
|
|
6579
|
-
onDone();
|
|
6580
|
-
};
|
|
6581
|
-
anim.finished.then(finish).catch(finish);
|
|
6582
|
-
window.setTimeout(finish, IMAGE_FADE_MS + 100);
|
|
6843
|
+
function getFooterRoot() {
|
|
6844
|
+
return document.querySelector('footer[data-ohw-section="footer"], footer');
|
|
6583
6845
|
}
|
|
6584
|
-
function
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
|
|
6846
|
+
function getFooterLinksContainer() {
|
|
6847
|
+
return document.querySelector("[data-ohw-footer-links]") ?? document.querySelector(".rb-footer-links");
|
|
6848
|
+
}
|
|
6849
|
+
function isFooterLinkAnchor(el) {
|
|
6850
|
+
if (!el.matches("[data-ohw-href-key]")) return false;
|
|
6851
|
+
if (!isFooterHrefKey(el.getAttribute("data-ohw-href-key"))) return false;
|
|
6852
|
+
return Boolean(el.querySelector('[data-ohw-editable="text"]'));
|
|
6853
|
+
}
|
|
6854
|
+
function listFooterColumns() {
|
|
6855
|
+
const root = getFooterLinksContainer() ?? getFooterRoot()?.querySelector(".rb-footer-links") ?? null;
|
|
6856
|
+
if (!root) return [];
|
|
6857
|
+
const explicit = Array.from(root.querySelectorAll(":scope > [data-ohw-footer-col]"));
|
|
6858
|
+
if (explicit.length > 0) return explicit;
|
|
6859
|
+
return Array.from(root.children).filter((el) => {
|
|
6860
|
+
if (!(el instanceof HTMLElement)) return false;
|
|
6861
|
+
return Array.from(el.querySelectorAll(":scope > [data-ohw-href-key]")).some(
|
|
6862
|
+
isFooterLinkAnchor
|
|
6863
|
+
);
|
|
6589
6864
|
});
|
|
6590
6865
|
}
|
|
6591
|
-
function
|
|
6592
|
-
|
|
6593
|
-
|
|
6594
|
-
|
|
6866
|
+
function listFooterLinksInColumn(column) {
|
|
6867
|
+
return Array.from(column.querySelectorAll(":scope > [data-ohw-href-key]")).filter(
|
|
6868
|
+
isFooterLinkAnchor
|
|
6869
|
+
);
|
|
6595
6870
|
}
|
|
6596
|
-
function
|
|
6597
|
-
const
|
|
6598
|
-
|
|
6599
|
-
|
|
6600
|
-
|
|
6601
|
-
|
|
6602
|
-
|
|
6603
|
-
|
|
6604
|
-
|
|
6605
|
-
|
|
6606
|
-
|
|
6607
|
-
|
|
6608
|
-
|
|
6609
|
-
|
|
6610
|
-
|
|
6611
|
-
|
|
6612
|
-
|
|
6613
|
-
|
|
6614
|
-
|
|
6615
|
-
|
|
6616
|
-
layer.remove();
|
|
6617
|
-
if (!prevPos || prevPos === "static") el.style.position = prevPos;
|
|
6871
|
+
function findFooterColumnForLink(anchor) {
|
|
6872
|
+
const columns = listFooterColumns();
|
|
6873
|
+
return columns.find((col) => col.contains(anchor)) ?? null;
|
|
6874
|
+
}
|
|
6875
|
+
function getFooterOrderFromDom() {
|
|
6876
|
+
return listFooterColumns().map(
|
|
6877
|
+
(col) => listFooterLinksInColumn(col).map((el) => el.getAttribute("data-ohw-href-key")).filter((key) => Boolean(key))
|
|
6878
|
+
);
|
|
6879
|
+
}
|
|
6880
|
+
function findFooterLinkByKey(hrefKey) {
|
|
6881
|
+
return document.querySelector(
|
|
6882
|
+
`footer [data-ohw-href-key="${CSS.escape(hrefKey)}"]`
|
|
6883
|
+
);
|
|
6884
|
+
}
|
|
6885
|
+
function syncFooterColumnIndices(columns) {
|
|
6886
|
+
columns.forEach((col, index) => {
|
|
6887
|
+
const next = String(index);
|
|
6888
|
+
if (col.getAttribute("data-ohw-footer-col") !== next) {
|
|
6889
|
+
col.setAttribute("data-ohw-footer-col", next);
|
|
6890
|
+
}
|
|
6618
6891
|
});
|
|
6619
6892
|
}
|
|
6620
|
-
function
|
|
6621
|
-
|
|
6622
|
-
|
|
6623
|
-
el = document.createElement("div");
|
|
6624
|
-
el.setAttribute("data-ohw-sections-tracker", "");
|
|
6625
|
-
el.style.display = "none";
|
|
6626
|
-
document.body.appendChild(el);
|
|
6893
|
+
function appendChildIfNeeded(parent, child) {
|
|
6894
|
+
if (parent.lastElementChild !== child) {
|
|
6895
|
+
parent.appendChild(child);
|
|
6627
6896
|
}
|
|
6628
|
-
return el;
|
|
6629
6897
|
}
|
|
6630
|
-
function
|
|
6631
|
-
const
|
|
6632
|
-
|
|
6633
|
-
|
|
6634
|
-
|
|
6635
|
-
|
|
6898
|
+
function applyFooterOrder(order) {
|
|
6899
|
+
const container = getFooterLinksContainer();
|
|
6900
|
+
if (!container) return;
|
|
6901
|
+
const columns = listFooterColumns();
|
|
6902
|
+
if (columns.length === 0) return;
|
|
6903
|
+
const currentOrder = getFooterOrderFromDom();
|
|
6904
|
+
if (ordersEqual(order, currentOrder)) {
|
|
6905
|
+
syncFooterColumnIndices(columns);
|
|
6906
|
+
return;
|
|
6636
6907
|
}
|
|
6637
|
-
const
|
|
6638
|
-
const
|
|
6908
|
+
const used = /* @__PURE__ */ new Set();
|
|
6909
|
+
const orderedCols = [];
|
|
6910
|
+
for (const colOrder of order) {
|
|
6911
|
+
let matched = null;
|
|
6912
|
+
for (const hrefKey of colOrder) {
|
|
6913
|
+
const link = findFooterLinkByKey(hrefKey);
|
|
6914
|
+
if (!link) continue;
|
|
6915
|
+
const owner = findFooterColumnForLink(link);
|
|
6916
|
+
if (owner && !used.has(owner)) {
|
|
6917
|
+
matched = owner;
|
|
6918
|
+
break;
|
|
6919
|
+
}
|
|
6920
|
+
}
|
|
6921
|
+
if (!matched) {
|
|
6922
|
+
matched = columns.find((col) => !used.has(col)) ?? null;
|
|
6923
|
+
}
|
|
6924
|
+
if (matched) {
|
|
6925
|
+
used.add(matched);
|
|
6926
|
+
orderedCols.push(matched);
|
|
6927
|
+
}
|
|
6928
|
+
}
|
|
6929
|
+
for (const col of columns) {
|
|
6930
|
+
if (!used.has(col)) orderedCols.push(col);
|
|
6931
|
+
}
|
|
6932
|
+
for (const col of orderedCols) {
|
|
6933
|
+
appendChildIfNeeded(container, col);
|
|
6934
|
+
}
|
|
6935
|
+
const freshColumns = listFooterColumns();
|
|
6936
|
+
syncFooterColumnIndices(freshColumns);
|
|
6937
|
+
for (let c = 0; c < order.length; c++) {
|
|
6938
|
+
const col = freshColumns[c];
|
|
6939
|
+
if (!col) continue;
|
|
6940
|
+
const colOrder = order[c];
|
|
6941
|
+
for (const hrefKey of colOrder) {
|
|
6942
|
+
const el = findFooterLinkByKey(hrefKey);
|
|
6943
|
+
if (!el) continue;
|
|
6944
|
+
if (el.parentElement !== col || col.lastElementChild !== el) {
|
|
6945
|
+
col.appendChild(el);
|
|
6946
|
+
}
|
|
6947
|
+
}
|
|
6948
|
+
}
|
|
6949
|
+
}
|
|
6950
|
+
function ordersEqual(a, b) {
|
|
6951
|
+
if (a.length !== b.length) return false;
|
|
6952
|
+
for (let i = 0; i < a.length; i++) {
|
|
6953
|
+
const left = a[i];
|
|
6954
|
+
const right = b[i];
|
|
6955
|
+
if (left.length !== right.length) return false;
|
|
6956
|
+
for (let j = 0; j < left.length; j++) {
|
|
6957
|
+
if (left[j] !== right[j]) return false;
|
|
6958
|
+
}
|
|
6959
|
+
}
|
|
6960
|
+
return true;
|
|
6961
|
+
}
|
|
6962
|
+
function planFooterLinkMove(hrefKey, targetColIndex, insertIndex) {
|
|
6963
|
+
const order = getFooterOrderFromDom();
|
|
6964
|
+
if (targetColIndex < 0 || targetColIndex >= order.length) return null;
|
|
6965
|
+
let fromCol = -1;
|
|
6966
|
+
let fromIdx = -1;
|
|
6967
|
+
for (let c = 0; c < order.length; c++) {
|
|
6968
|
+
const idx = order[c].indexOf(hrefKey);
|
|
6969
|
+
if (idx >= 0) {
|
|
6970
|
+
fromCol = c;
|
|
6971
|
+
fromIdx = idx;
|
|
6972
|
+
break;
|
|
6973
|
+
}
|
|
6974
|
+
}
|
|
6975
|
+
if (fromCol < 0) return null;
|
|
6976
|
+
const next = order.map((col) => [...col]);
|
|
6977
|
+
next[fromCol].splice(fromIdx, 1);
|
|
6978
|
+
let adjusted = insertIndex;
|
|
6979
|
+
if (fromCol === targetColIndex && fromIdx < insertIndex) adjusted -= 1;
|
|
6980
|
+
adjusted = Math.max(0, Math.min(adjusted, next[targetColIndex].length));
|
|
6981
|
+
next[targetColIndex].splice(adjusted, 0, hrefKey);
|
|
6982
|
+
if (ordersEqual(next, order)) return null;
|
|
6983
|
+
return next;
|
|
6984
|
+
}
|
|
6985
|
+
function planFooterColumnMove(fromIndex, toIndex) {
|
|
6986
|
+
const order = getFooterOrderFromDom();
|
|
6987
|
+
const columns = listFooterColumns();
|
|
6988
|
+
if (fromIndex < 0 || fromIndex >= columns.length || toIndex < 0 || toIndex > columns.length) {
|
|
6989
|
+
return null;
|
|
6990
|
+
}
|
|
6991
|
+
if (toIndex === fromIndex || toIndex === fromIndex + 1) return null;
|
|
6992
|
+
const nextOrder = order.map((col) => [...col]);
|
|
6993
|
+
const [movedOrder] = nextOrder.splice(fromIndex, 1);
|
|
6994
|
+
if (!movedOrder) return null;
|
|
6995
|
+
let adjusted = toIndex;
|
|
6996
|
+
if (fromIndex < toIndex) adjusted -= 1;
|
|
6997
|
+
adjusted = Math.max(0, Math.min(adjusted, nextOrder.length));
|
|
6998
|
+
nextOrder.splice(adjusted, 0, movedOrder);
|
|
6999
|
+
if (ordersEqual(nextOrder, order)) return null;
|
|
7000
|
+
return nextOrder;
|
|
7001
|
+
}
|
|
7002
|
+
function parseFooterOrder(content) {
|
|
7003
|
+
const raw = content[FOOTER_ORDER_KEY];
|
|
7004
|
+
if (!raw) return null;
|
|
7005
|
+
try {
|
|
7006
|
+
const parsed = JSON.parse(raw);
|
|
7007
|
+
if (!Array.isArray(parsed)) return null;
|
|
7008
|
+
return parsed.filter((col) => Array.isArray(col)).map((col) => col.filter((key) => typeof key === "string" && key.length > 0));
|
|
7009
|
+
} catch {
|
|
7010
|
+
return null;
|
|
7011
|
+
}
|
|
7012
|
+
}
|
|
7013
|
+
var FOOTER_HEADING_RE = /^footer-(\d+)-heading$/;
|
|
7014
|
+
var FOOTER_LABEL_RE = /^footer-(\d+)-(\d+)-label$/;
|
|
7015
|
+
var DEFAULT_FOOTER_COLUMN_HEADING = "New";
|
|
7016
|
+
var DEFAULT_FOOTER_COLUMN_LINK_LABEL = "New link";
|
|
7017
|
+
var DEFAULT_FOOTER_COLUMN_LINK_HREF = "";
|
|
7018
|
+
function isFooterLinksContainer(el) {
|
|
7019
|
+
return el.hasAttribute("data-ohw-footer-links") || el.classList.contains("rb-footer-links");
|
|
7020
|
+
}
|
|
7021
|
+
function getFooterColumnIndicesInDom() {
|
|
7022
|
+
const indices = /* @__PURE__ */ new Set();
|
|
7023
|
+
for (const col of listFooterColumns()) {
|
|
7024
|
+
const attr = col.getAttribute("data-ohw-footer-col");
|
|
7025
|
+
if (attr != null) {
|
|
7026
|
+
const n = parseInt(attr, 10);
|
|
7027
|
+
if (Number.isFinite(n)) indices.add(n);
|
|
7028
|
+
}
|
|
7029
|
+
for (const link of listFooterLinksInColumn(col)) {
|
|
7030
|
+
const parsed = parseFooterHrefKey(link.getAttribute("data-ohw-href-key"));
|
|
7031
|
+
if (parsed) indices.add(parsed.col);
|
|
7032
|
+
}
|
|
7033
|
+
const heading = col.querySelector('[data-ohw-key^="footer-"][data-ohw-key$="-heading"]');
|
|
7034
|
+
const headingKey = heading?.getAttribute("data-ohw-key");
|
|
7035
|
+
if (headingKey) {
|
|
7036
|
+
const match = headingKey.match(FOOTER_HEADING_RE);
|
|
7037
|
+
if (match) indices.add(parseInt(match[1], 10));
|
|
7038
|
+
}
|
|
7039
|
+
}
|
|
7040
|
+
return [...indices].sort((a, b) => a - b);
|
|
7041
|
+
}
|
|
7042
|
+
function getNextFooterColumnIndex() {
|
|
7043
|
+
const indices = getFooterColumnIndicesInDom();
|
|
7044
|
+
if (indices.length === 0) return 0;
|
|
7045
|
+
return Math.max(...indices) + 1;
|
|
7046
|
+
}
|
|
7047
|
+
function cloneFooterLinkShell(template) {
|
|
7048
|
+
const anchor = document.createElement("a");
|
|
7049
|
+
if (template) {
|
|
7050
|
+
anchor.style.cssText = template.style.cssText;
|
|
7051
|
+
if (template.className) anchor.className = template.className;
|
|
7052
|
+
}
|
|
7053
|
+
anchor.style.cursor = "pointer";
|
|
7054
|
+
anchor.style.textDecoration = "none";
|
|
7055
|
+
return anchor;
|
|
7056
|
+
}
|
|
7057
|
+
function buildFooterHeading(colIndex, text) {
|
|
7058
|
+
const heading = document.createElement("p");
|
|
7059
|
+
heading.setAttribute("data-ohw-editable", "text");
|
|
7060
|
+
heading.setAttribute("data-ohw-key", `footer-${colIndex}-heading`);
|
|
7061
|
+
heading.textContent = text;
|
|
7062
|
+
heading.style.cssText = [
|
|
7063
|
+
"color: var(--espresso, #3d312b)",
|
|
7064
|
+
"font-size: 14px",
|
|
7065
|
+
"font-weight: 800",
|
|
7066
|
+
"opacity: 0.82",
|
|
7067
|
+
"margin: 0 0 6px",
|
|
7068
|
+
"padding: 0",
|
|
7069
|
+
"line-height: 1.2"
|
|
7070
|
+
].join(";");
|
|
7071
|
+
return heading;
|
|
7072
|
+
}
|
|
7073
|
+
function buildFooterLink(colIndex, itemIndex, href, label, template) {
|
|
7074
|
+
const anchor = cloneFooterLinkShell(template);
|
|
7075
|
+
anchor.setAttribute("href", href);
|
|
7076
|
+
anchor.setAttribute("data-ohw-href-key", `footer-${colIndex}-${itemIndex}-href`);
|
|
7077
|
+
const span = document.createElement("span");
|
|
7078
|
+
span.setAttribute("data-ohw-editable", "text");
|
|
7079
|
+
span.setAttribute("data-ohw-key", `footer-${colIndex}-${itemIndex}-label`);
|
|
7080
|
+
span.textContent = label;
|
|
7081
|
+
anchor.appendChild(span);
|
|
7082
|
+
return anchor;
|
|
7083
|
+
}
|
|
7084
|
+
function footerColumnExistsInDom(colIndex) {
|
|
7085
|
+
return document.querySelector(`[data-ohw-footer-col="${colIndex}"]`) !== null || document.querySelector(`[data-ohw-href-key^="footer-${colIndex}-"]`) !== null || document.querySelector(`[data-ohw-key="footer-${colIndex}-heading"]`) !== null;
|
|
7086
|
+
}
|
|
7087
|
+
function getFooterLinkTemplate() {
|
|
7088
|
+
for (const col of listFooterColumns()) {
|
|
7089
|
+
const link = listFooterLinksInColumn(col)[0];
|
|
7090
|
+
if (link) return link;
|
|
7091
|
+
}
|
|
7092
|
+
return null;
|
|
7093
|
+
}
|
|
7094
|
+
function getFooterColumnTemplate() {
|
|
7095
|
+
return listFooterColumns()[0] ?? null;
|
|
7096
|
+
}
|
|
7097
|
+
function insertFooterColumnDom(colIndex, heading, items) {
|
|
7098
|
+
const container = getFooterLinksContainer();
|
|
7099
|
+
if (!container) return null;
|
|
7100
|
+
const colTemplate = getFooterColumnTemplate();
|
|
7101
|
+
const linkTemplate = getFooterLinkTemplate();
|
|
7102
|
+
const column = document.createElement("div");
|
|
7103
|
+
if (colTemplate?.className) column.className = colTemplate.className;
|
|
7104
|
+
else column.className = "rb-footer-link-col";
|
|
7105
|
+
column.setAttribute("data-ohw-footer-col", String(colIndex));
|
|
7106
|
+
if (colTemplate) {
|
|
7107
|
+
const gap = getComputedStyle(colTemplate).gap;
|
|
7108
|
+
if (gap && gap !== "normal") column.style.gap = gap;
|
|
7109
|
+
column.style.display = getComputedStyle(colTemplate).display || "flex";
|
|
7110
|
+
column.style.flexDirection = "column";
|
|
7111
|
+
}
|
|
7112
|
+
column.appendChild(buildFooterHeading(colIndex, heading));
|
|
7113
|
+
let firstLink = null;
|
|
7114
|
+
items.forEach((item, itemIndex) => {
|
|
7115
|
+
const link = buildFooterLink(colIndex, itemIndex, item.href, item.label, linkTemplate);
|
|
7116
|
+
column.appendChild(link);
|
|
7117
|
+
if (!firstLink) firstLink = link;
|
|
7118
|
+
});
|
|
7119
|
+
container.appendChild(column);
|
|
7120
|
+
return { column, firstLink };
|
|
7121
|
+
}
|
|
7122
|
+
function insertFooterColumn(heading = DEFAULT_FOOTER_COLUMN_HEADING, linkLabel = DEFAULT_FOOTER_COLUMN_LINK_LABEL, linkHref = DEFAULT_FOOTER_COLUMN_LINK_HREF) {
|
|
7123
|
+
const colIndex = getNextFooterColumnIndex();
|
|
7124
|
+
const inserted = insertFooterColumnDom(colIndex, heading, [{ href: linkHref, label: linkLabel }]);
|
|
7125
|
+
if (!inserted?.firstLink) throw new Error("Failed to insert footer column");
|
|
7126
|
+
syncFooterColumnIndices(listFooterColumns());
|
|
7127
|
+
return {
|
|
7128
|
+
column: inserted.column,
|
|
7129
|
+
firstLink: inserted.firstLink,
|
|
7130
|
+
colIndex,
|
|
7131
|
+
headingKey: `footer-${colIndex}-heading`,
|
|
7132
|
+
hrefKey: `footer-${colIndex}-0-href`,
|
|
7133
|
+
labelKey: `footer-${colIndex}-0-label`,
|
|
7134
|
+
heading,
|
|
7135
|
+
label: linkLabel,
|
|
7136
|
+
href: linkHref,
|
|
7137
|
+
order: getFooterOrderFromDom()
|
|
7138
|
+
};
|
|
7139
|
+
}
|
|
7140
|
+
function collectFooterColumnIndicesFromContent(content) {
|
|
7141
|
+
const indices = /* @__PURE__ */ new Set();
|
|
7142
|
+
for (const key of Object.keys(content)) {
|
|
7143
|
+
const href = parseFooterHrefKey(key);
|
|
7144
|
+
if (href) indices.add(href.col);
|
|
7145
|
+
const heading = key.match(FOOTER_HEADING_RE);
|
|
7146
|
+
if (heading) indices.add(parseInt(heading[1], 10));
|
|
7147
|
+
const label = key.match(FOOTER_LABEL_RE);
|
|
7148
|
+
if (label) indices.add(parseInt(label[1], 10));
|
|
7149
|
+
}
|
|
7150
|
+
const order = parseFooterOrder(content);
|
|
7151
|
+
if (order) {
|
|
7152
|
+
for (const col of order) {
|
|
7153
|
+
for (const hrefKey of col) {
|
|
7154
|
+
const parsed = parseFooterHrefKey(hrefKey);
|
|
7155
|
+
if (parsed) indices.add(parsed.col);
|
|
7156
|
+
}
|
|
7157
|
+
}
|
|
7158
|
+
}
|
|
7159
|
+
return [...indices].sort((a, b) => a - b);
|
|
7160
|
+
}
|
|
7161
|
+
function collectFooterItemsForColumn(content, colIndex) {
|
|
7162
|
+
const itemIndices = /* @__PURE__ */ new Set();
|
|
7163
|
+
for (const key of Object.keys(content)) {
|
|
7164
|
+
const href = parseFooterHrefKey(key);
|
|
7165
|
+
if (href?.col === colIndex) itemIndices.add(href.item);
|
|
7166
|
+
const label = key.match(FOOTER_LABEL_RE);
|
|
7167
|
+
if (label && parseInt(label[1], 10) === colIndex) {
|
|
7168
|
+
itemIndices.add(parseInt(label[2], 10));
|
|
7169
|
+
}
|
|
7170
|
+
}
|
|
7171
|
+
const sorted = [...itemIndices].sort((a, b) => a - b);
|
|
7172
|
+
if (sorted.length === 0) {
|
|
7173
|
+
return [
|
|
7174
|
+
{
|
|
7175
|
+
href: content[`footer-${colIndex}-0-href`] ?? DEFAULT_FOOTER_COLUMN_LINK_HREF,
|
|
7176
|
+
label: content[`footer-${colIndex}-0-label`] ?? DEFAULT_FOOTER_COLUMN_LINK_LABEL
|
|
7177
|
+
}
|
|
7178
|
+
];
|
|
7179
|
+
}
|
|
7180
|
+
return sorted.map((itemIndex) => ({
|
|
7181
|
+
href: content[`footer-${colIndex}-${itemIndex}-href`] ?? DEFAULT_FOOTER_COLUMN_LINK_HREF,
|
|
7182
|
+
label: content[`footer-${colIndex}-${itemIndex}-label`] ?? DEFAULT_FOOTER_COLUMN_LINK_LABEL
|
|
7183
|
+
}));
|
|
7184
|
+
}
|
|
7185
|
+
function reconcileFooterColumnsFromContent(content) {
|
|
7186
|
+
const indices = collectFooterColumnIndicesFromContent(content);
|
|
7187
|
+
for (const colIndex of indices) {
|
|
7188
|
+
if (footerColumnExistsInDom(colIndex)) continue;
|
|
7189
|
+
const heading = content[`footer-${colIndex}-heading`] ?? DEFAULT_FOOTER_COLUMN_HEADING;
|
|
7190
|
+
const items = collectFooterItemsForColumn(content, colIndex);
|
|
7191
|
+
const hasPayload = Boolean(content[`footer-${colIndex}-heading`]) || items.some(
|
|
7192
|
+
(_, i) => content[`footer-${colIndex}-${i}-href`] !== void 0 || content[`footer-${colIndex}-${i}-label`] !== void 0
|
|
7193
|
+
) || (parseFooterOrder(content)?.some(
|
|
7194
|
+
(col) => col.some((k) => parseFooterHrefKey(k)?.col === colIndex)
|
|
7195
|
+
) ?? false);
|
|
7196
|
+
if (!hasPayload) continue;
|
|
7197
|
+
insertFooterColumnDom(colIndex, heading, items);
|
|
7198
|
+
}
|
|
7199
|
+
}
|
|
7200
|
+
function reconcileFooterOrderFromContent(content) {
|
|
7201
|
+
reconcileFooterColumnsFromContent(content);
|
|
7202
|
+
const order = parseFooterOrder(content);
|
|
7203
|
+
if (!order?.length) return;
|
|
7204
|
+
const current = getFooterOrderFromDom();
|
|
7205
|
+
if (ordersEqual(order, current)) {
|
|
7206
|
+
syncFooterColumnIndices(listFooterColumns());
|
|
7207
|
+
return;
|
|
7208
|
+
}
|
|
7209
|
+
applyFooterOrder(order);
|
|
7210
|
+
}
|
|
7211
|
+
function resolveFooterLinksContainerSelectionTarget(target, clientX, clientY, isPointOverItem) {
|
|
7212
|
+
const container = getFooterLinksContainer();
|
|
7213
|
+
if (!container) return null;
|
|
7214
|
+
const inContainer = target === container || container.contains(target) && Boolean(target.closest("[data-ohw-footer-links], .rb-footer-links"));
|
|
7215
|
+
if (!inContainer && target !== container) {
|
|
7216
|
+
const r2 = container.getBoundingClientRect();
|
|
7217
|
+
const over = clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom;
|
|
7218
|
+
if (!over) return null;
|
|
7219
|
+
}
|
|
7220
|
+
if (isPointOverItem(container, clientX, clientY)) return null;
|
|
7221
|
+
const column = target.closest("[data-ohw-footer-col], [data-ohw-footer-column]") ?? null;
|
|
7222
|
+
if (column && container.contains(column)) {
|
|
7223
|
+
if (target === column || column.contains(target)) return null;
|
|
7224
|
+
}
|
|
7225
|
+
if (target === container || container.contains(target) || inContainer) {
|
|
7226
|
+
if (target === container || isFooterLinksContainer(target)) return container;
|
|
7227
|
+
if (!column) return container;
|
|
7228
|
+
}
|
|
7229
|
+
return null;
|
|
7230
|
+
}
|
|
7231
|
+
function isRowLayoutColumn(links) {
|
|
7232
|
+
if (links.length < 2) return false;
|
|
7233
|
+
const firstTop = links[0].getBoundingClientRect().top;
|
|
7234
|
+
return links.every((link) => Math.abs(link.getBoundingClientRect().top - firstTop) < 4);
|
|
7235
|
+
}
|
|
7236
|
+
function buildLinkDropSlots(column, columnIndex) {
|
|
7237
|
+
const links = listFooterLinksInColumn(column);
|
|
7238
|
+
const colRect = column.getBoundingClientRect();
|
|
7239
|
+
const slots = [];
|
|
7240
|
+
const barThickness = 3;
|
|
7241
|
+
if (links.length === 0) {
|
|
7242
|
+
slots.push({
|
|
7243
|
+
insertIndex: 0,
|
|
7244
|
+
columnIndex,
|
|
7245
|
+
left: colRect.left,
|
|
7246
|
+
top: colRect.top + colRect.height / 2 - barThickness / 2,
|
|
7247
|
+
width: colRect.width,
|
|
7248
|
+
height: barThickness,
|
|
7249
|
+
direction: "horizontal"
|
|
7250
|
+
});
|
|
7251
|
+
return slots;
|
|
7252
|
+
}
|
|
7253
|
+
if (isRowLayoutColumn(links)) {
|
|
7254
|
+
for (let i = 0; i <= links.length; i++) {
|
|
7255
|
+
let left;
|
|
7256
|
+
if (i === 0) {
|
|
7257
|
+
left = links[0].getBoundingClientRect().left - barThickness / 2;
|
|
7258
|
+
} else if (i === links.length) {
|
|
7259
|
+
const last = links[links.length - 1].getBoundingClientRect();
|
|
7260
|
+
left = last.right - barThickness / 2;
|
|
7261
|
+
} else {
|
|
7262
|
+
const prev = links[i - 1].getBoundingClientRect();
|
|
7263
|
+
const next = links[i].getBoundingClientRect();
|
|
7264
|
+
left = (prev.right + next.left) / 2 - barThickness / 2;
|
|
7265
|
+
}
|
|
7266
|
+
const heightRef = i === 0 ? links[0].getBoundingClientRect() : i === links.length ? links[links.length - 1].getBoundingClientRect() : links[i].getBoundingClientRect();
|
|
7267
|
+
slots.push({
|
|
7268
|
+
insertIndex: i,
|
|
7269
|
+
columnIndex,
|
|
7270
|
+
left,
|
|
7271
|
+
top: heightRef.top,
|
|
7272
|
+
width: barThickness,
|
|
7273
|
+
height: Math.max(heightRef.height, colRect.height * 0.8),
|
|
7274
|
+
direction: "vertical"
|
|
7275
|
+
});
|
|
7276
|
+
}
|
|
7277
|
+
return slots;
|
|
7278
|
+
}
|
|
7279
|
+
for (let i = 0; i <= links.length; i++) {
|
|
7280
|
+
let top;
|
|
7281
|
+
if (i === 0) {
|
|
7282
|
+
top = links[0].getBoundingClientRect().top - barThickness / 2;
|
|
7283
|
+
} else if (i === links.length) {
|
|
7284
|
+
const last = links[links.length - 1].getBoundingClientRect();
|
|
7285
|
+
top = last.bottom - barThickness / 2;
|
|
7286
|
+
} else {
|
|
7287
|
+
const prev = links[i - 1].getBoundingClientRect();
|
|
7288
|
+
const next = links[i].getBoundingClientRect();
|
|
7289
|
+
top = (prev.bottom + next.top) / 2 - barThickness / 2;
|
|
7290
|
+
}
|
|
7291
|
+
const widthRef = i === 0 ? links[0].getBoundingClientRect() : i === links.length ? links[links.length - 1].getBoundingClientRect() : links[i].getBoundingClientRect();
|
|
7292
|
+
slots.push({
|
|
7293
|
+
insertIndex: i,
|
|
7294
|
+
columnIndex,
|
|
7295
|
+
left: widthRef.left,
|
|
7296
|
+
top,
|
|
7297
|
+
width: Math.max(widthRef.width, colRect.width * 0.8),
|
|
7298
|
+
height: barThickness,
|
|
7299
|
+
direction: "horizontal"
|
|
7300
|
+
});
|
|
7301
|
+
}
|
|
7302
|
+
return slots;
|
|
7303
|
+
}
|
|
7304
|
+
function buildColumnDropSlots() {
|
|
7305
|
+
const columns = listFooterColumns();
|
|
7306
|
+
const slots = [];
|
|
7307
|
+
const barThickness = 3;
|
|
7308
|
+
if (columns.length === 0) return slots;
|
|
7309
|
+
for (let i = 0; i <= columns.length; i++) {
|
|
7310
|
+
let left;
|
|
7311
|
+
let height;
|
|
7312
|
+
let top;
|
|
7313
|
+
if (i === 0) {
|
|
7314
|
+
const first = columns[0].getBoundingClientRect();
|
|
7315
|
+
left = first.left - barThickness / 2;
|
|
7316
|
+
top = first.top;
|
|
7317
|
+
height = first.height;
|
|
7318
|
+
} else if (i === columns.length) {
|
|
7319
|
+
const last = columns[columns.length - 1].getBoundingClientRect();
|
|
7320
|
+
left = last.right - barThickness / 2;
|
|
7321
|
+
top = last.top;
|
|
7322
|
+
height = last.height;
|
|
7323
|
+
} else {
|
|
7324
|
+
const prev = columns[i - 1].getBoundingClientRect();
|
|
7325
|
+
const next = columns[i].getBoundingClientRect();
|
|
7326
|
+
left = (prev.right + next.left) / 2 - barThickness / 2;
|
|
7327
|
+
top = Math.min(prev.top, next.top);
|
|
7328
|
+
height = Math.max(prev.bottom, next.bottom) - top;
|
|
7329
|
+
}
|
|
7330
|
+
slots.push({
|
|
7331
|
+
insertIndex: i,
|
|
7332
|
+
columnIndex: i,
|
|
7333
|
+
left,
|
|
7334
|
+
top,
|
|
7335
|
+
width: barThickness,
|
|
7336
|
+
height: Math.max(height, 24),
|
|
7337
|
+
direction: "vertical"
|
|
7338
|
+
});
|
|
7339
|
+
}
|
|
7340
|
+
return slots;
|
|
7341
|
+
}
|
|
7342
|
+
function hitTestLinkDropSlot(clientX, clientY, draggedHrefKey) {
|
|
7343
|
+
const columns = listFooterColumns();
|
|
7344
|
+
let best = null;
|
|
7345
|
+
for (let c = 0; c < columns.length; c++) {
|
|
7346
|
+
const col = columns[c];
|
|
7347
|
+
const colRect = col.getBoundingClientRect();
|
|
7348
|
+
const inColX = clientX >= colRect.left - 24 && clientX <= colRect.right + 24;
|
|
7349
|
+
if (!inColX) continue;
|
|
7350
|
+
const slots = buildLinkDropSlots(col, c).filter((slot) => {
|
|
7351
|
+
const links = listFooterLinksInColumn(col);
|
|
7352
|
+
const fromIdx = links.findIndex(
|
|
7353
|
+
(el) => el.getAttribute("data-ohw-href-key") === draggedHrefKey
|
|
7354
|
+
);
|
|
7355
|
+
if (fromIdx < 0) return true;
|
|
7356
|
+
if (c === findColumnIndexForKey(draggedHrefKey) && (slot.insertIndex === fromIdx || slot.insertIndex === fromIdx + 1)) {
|
|
7357
|
+
return true;
|
|
7358
|
+
}
|
|
7359
|
+
return true;
|
|
7360
|
+
});
|
|
7361
|
+
for (const slot of slots) {
|
|
7362
|
+
const dist = slot.direction === "vertical" ? Math.abs(clientX - (slot.left + slot.width / 2)) : Math.abs(clientY - (slot.top + slot.height / 2));
|
|
7363
|
+
if (!best || dist < best.dist) best = { slot, dist };
|
|
7364
|
+
}
|
|
7365
|
+
}
|
|
7366
|
+
return best?.slot ?? null;
|
|
7367
|
+
}
|
|
7368
|
+
function findColumnIndexForKey(hrefKey) {
|
|
7369
|
+
const order = getFooterOrderFromDom();
|
|
7370
|
+
for (let c = 0; c < order.length; c++) {
|
|
7371
|
+
if (order[c].includes(hrefKey)) return c;
|
|
7372
|
+
}
|
|
7373
|
+
return -1;
|
|
7374
|
+
}
|
|
7375
|
+
function hitTestColumnDropSlot(clientX, _clientY) {
|
|
7376
|
+
const slots = buildColumnDropSlots();
|
|
7377
|
+
let best = null;
|
|
7378
|
+
for (const slot of slots) {
|
|
7379
|
+
const cx2 = slot.left + slot.width / 2;
|
|
7380
|
+
const dist = Math.abs(clientX - cx2);
|
|
7381
|
+
if (!best || dist < best.dist) best = { slot, dist };
|
|
7382
|
+
}
|
|
7383
|
+
return best?.slot ?? null;
|
|
7384
|
+
}
|
|
7385
|
+
|
|
7386
|
+
// src/lib/add-footer-column.ts
|
|
7387
|
+
function buildFooterColumnEditContentPatch(result) {
|
|
7388
|
+
return {
|
|
7389
|
+
[result.headingKey]: result.heading,
|
|
7390
|
+
[result.hrefKey]: result.href,
|
|
7391
|
+
[result.labelKey]: result.label,
|
|
7392
|
+
[FOOTER_ORDER_KEY]: JSON.stringify(result.order)
|
|
7393
|
+
};
|
|
7394
|
+
}
|
|
7395
|
+
function addFooterColumnWithPersist({
|
|
7396
|
+
postToParent: postToParent2
|
|
7397
|
+
}) {
|
|
7398
|
+
const result = insertFooterColumn();
|
|
7399
|
+
const patch = buildFooterColumnEditContentPatch(result);
|
|
7400
|
+
setStoredLinkHref(result.hrefKey, result.href);
|
|
7401
|
+
postToParent2({
|
|
7402
|
+
type: "ow:change",
|
|
7403
|
+
nodes: Object.entries(patch).map(([key, text]) => ({ key, text }))
|
|
7404
|
+
});
|
|
7405
|
+
postToParent2({ type: "ow:toast", title: "Item added", toastType: "success" });
|
|
7406
|
+
enforceLinkHrefs();
|
|
7407
|
+
return result;
|
|
7408
|
+
}
|
|
7409
|
+
|
|
7410
|
+
// src/lib/item-drag-interaction.ts
|
|
7411
|
+
function disableNativeHrefDrag(el) {
|
|
7412
|
+
if (el.draggable) el.draggable = false;
|
|
7413
|
+
if (el.getAttribute("draggable") !== "false") {
|
|
7414
|
+
el.setAttribute("draggable", "false");
|
|
7415
|
+
}
|
|
7416
|
+
}
|
|
7417
|
+
function clearTextSelection() {
|
|
7418
|
+
const sel = window.getSelection();
|
|
7419
|
+
if (sel && !sel.isCollapsed) sel.removeAllRanges();
|
|
7420
|
+
}
|
|
7421
|
+
function armItemPressDrag() {
|
|
7422
|
+
document.documentElement.setAttribute("data-ohw-footer-press-drag", "");
|
|
7423
|
+
}
|
|
7424
|
+
function lockItemDuringDrag() {
|
|
7425
|
+
document.documentElement.removeAttribute("data-ohw-footer-press-drag");
|
|
7426
|
+
document.documentElement.setAttribute("data-ohw-item-dragging", "");
|
|
7427
|
+
clearTextSelection();
|
|
7428
|
+
}
|
|
7429
|
+
function unlockItemDragInteraction() {
|
|
7430
|
+
const wasDragging = document.documentElement.hasAttribute("data-ohw-item-dragging");
|
|
7431
|
+
document.documentElement.removeAttribute("data-ohw-footer-press-drag");
|
|
7432
|
+
document.documentElement.removeAttribute("data-ohw-item-dragging");
|
|
7433
|
+
if (wasDragging) clearTextSelection();
|
|
7434
|
+
}
|
|
7435
|
+
var armFooterPressDrag = armItemPressDrag;
|
|
7436
|
+
var lockFooterDuringDrag = lockItemDuringDrag;
|
|
7437
|
+
var unlockFooterDragInteraction = unlockItemDragInteraction;
|
|
7438
|
+
|
|
7439
|
+
// src/lib/nav-dnd.ts
|
|
7440
|
+
function listReorderableNavItems() {
|
|
7441
|
+
return listNavbarItems().filter((el) => {
|
|
7442
|
+
const key = el.getAttribute("data-ohw-href-key");
|
|
7443
|
+
return isNavbarHrefKey(key) && !el.closest("[data-ohw-nav-children]");
|
|
7444
|
+
});
|
|
7445
|
+
}
|
|
7446
|
+
function listNavChildren(parentHrefKey) {
|
|
7447
|
+
const items = listNavbarItems();
|
|
7448
|
+
const parent = items.find((el) => el.getAttribute("data-ohw-href-key") === parentHrefKey);
|
|
7449
|
+
if (!parent) return [];
|
|
7450
|
+
const group = parent.closest("[data-ohw-nav-group]");
|
|
7451
|
+
const childrenRoot = group?.querySelector(":scope > [data-ohw-nav-children]");
|
|
7452
|
+
if (!childrenRoot) return [];
|
|
7453
|
+
return Array.from(childrenRoot.querySelectorAll(":scope > [data-ohw-href-key]")).filter(
|
|
7454
|
+
(el) => isNavbarHrefKey(el.getAttribute("data-ohw-href-key"))
|
|
7455
|
+
);
|
|
7456
|
+
}
|
|
7457
|
+
function activeNavListContainer() {
|
|
7458
|
+
const desktop = getNavbarDesktopContainer();
|
|
7459
|
+
if (desktop && desktop.getClientRects().length > 0) {
|
|
7460
|
+
const style = window.getComputedStyle(desktop);
|
|
7461
|
+
if (style.display !== "none" && style.visibility !== "hidden") return desktop;
|
|
7462
|
+
}
|
|
7463
|
+
return getNavbarDrawerContainer();
|
|
7464
|
+
}
|
|
7465
|
+
function buildRootNavDropSlots() {
|
|
7466
|
+
const items = listReorderableNavItems();
|
|
7467
|
+
const slots = [];
|
|
7468
|
+
const barThickness = 3;
|
|
7469
|
+
if (items.length === 0) {
|
|
7470
|
+
const container = activeNavListContainer();
|
|
7471
|
+
if (!container) return slots;
|
|
7472
|
+
const rect = container.getBoundingClientRect();
|
|
7473
|
+
slots.push({
|
|
7474
|
+
insertIndex: 0,
|
|
7475
|
+
parentId: null,
|
|
7476
|
+
left: rect.left + rect.width / 2 - barThickness / 2,
|
|
7477
|
+
top: rect.top,
|
|
7478
|
+
width: barThickness,
|
|
7479
|
+
height: Math.max(rect.height, 24),
|
|
7480
|
+
direction: "vertical"
|
|
7481
|
+
});
|
|
7482
|
+
return slots;
|
|
7483
|
+
}
|
|
7484
|
+
const edgeGap = (() => {
|
|
7485
|
+
if (items.length < 2) return 32;
|
|
7486
|
+
const a = items[0].getBoundingClientRect();
|
|
7487
|
+
const b = items[1].getBoundingClientRect();
|
|
7488
|
+
return Math.max(0, b.left - a.right);
|
|
7489
|
+
})();
|
|
7490
|
+
for (let i = 0; i <= items.length; i++) {
|
|
7491
|
+
let left;
|
|
7492
|
+
let top;
|
|
7493
|
+
let height;
|
|
7494
|
+
if (i === 0) {
|
|
7495
|
+
const first = items[0].getBoundingClientRect();
|
|
7496
|
+
left = first.left - edgeGap / 2 - barThickness / 2;
|
|
7497
|
+
top = first.top;
|
|
7498
|
+
height = first.height;
|
|
7499
|
+
} else if (i === items.length) {
|
|
7500
|
+
const last = items[items.length - 1].getBoundingClientRect();
|
|
7501
|
+
const lastGap = items.length >= 2 ? Math.max(
|
|
7502
|
+
0,
|
|
7503
|
+
last.left - items[items.length - 2].getBoundingClientRect().right
|
|
7504
|
+
) : edgeGap;
|
|
7505
|
+
left = last.right + lastGap / 2 - barThickness / 2;
|
|
7506
|
+
top = last.top;
|
|
7507
|
+
height = last.height;
|
|
7508
|
+
} else {
|
|
7509
|
+
const prev = items[i - 1].getBoundingClientRect();
|
|
7510
|
+
const next = items[i].getBoundingClientRect();
|
|
7511
|
+
left = (prev.right + next.left) / 2 - barThickness / 2;
|
|
7512
|
+
top = Math.min(prev.top, next.top);
|
|
7513
|
+
height = Math.max(prev.bottom, next.bottom) - top;
|
|
7514
|
+
}
|
|
7515
|
+
slots.push({
|
|
7516
|
+
insertIndex: i,
|
|
7517
|
+
parentId: null,
|
|
7518
|
+
left,
|
|
7519
|
+
top,
|
|
7520
|
+
width: barThickness,
|
|
7521
|
+
height: Math.max(height, 24),
|
|
7522
|
+
direction: "vertical"
|
|
7523
|
+
});
|
|
7524
|
+
}
|
|
7525
|
+
return slots;
|
|
7526
|
+
}
|
|
7527
|
+
function buildChildNavDropSlots(parentHrefKey) {
|
|
7528
|
+
const children = listNavChildren(parentHrefKey);
|
|
7529
|
+
const slots = [];
|
|
7530
|
+
const barThickness = 3;
|
|
7531
|
+
if (children.length === 0) return slots;
|
|
7532
|
+
const edgeGap = (() => {
|
|
7533
|
+
if (children.length < 2) return 16;
|
|
7534
|
+
const a = children[0].getBoundingClientRect();
|
|
7535
|
+
const b = children[1].getBoundingClientRect();
|
|
7536
|
+
return Math.max(0, b.top - a.bottom);
|
|
7537
|
+
})();
|
|
7538
|
+
for (let i = 0; i <= children.length; i++) {
|
|
7539
|
+
let top;
|
|
7540
|
+
let width;
|
|
7541
|
+
let left;
|
|
7542
|
+
if (i === 0) {
|
|
7543
|
+
const first = children[0].getBoundingClientRect();
|
|
7544
|
+
top = first.top - edgeGap / 2 - barThickness / 2;
|
|
7545
|
+
left = first.left;
|
|
7546
|
+
width = first.width;
|
|
7547
|
+
} else if (i === children.length) {
|
|
7548
|
+
const last = children[children.length - 1].getBoundingClientRect();
|
|
7549
|
+
const lastGap = children.length >= 2 ? Math.max(
|
|
7550
|
+
0,
|
|
7551
|
+
last.top - children[children.length - 2].getBoundingClientRect().bottom
|
|
7552
|
+
) : edgeGap;
|
|
7553
|
+
top = last.bottom + lastGap / 2 - barThickness / 2;
|
|
7554
|
+
left = last.left;
|
|
7555
|
+
width = last.width;
|
|
7556
|
+
} else {
|
|
7557
|
+
const prev = children[i - 1].getBoundingClientRect();
|
|
7558
|
+
const next = children[i].getBoundingClientRect();
|
|
7559
|
+
top = (prev.bottom + next.top) / 2 - barThickness / 2;
|
|
7560
|
+
left = Math.min(prev.left, next.left);
|
|
7561
|
+
width = Math.max(prev.right, next.right) - left;
|
|
7562
|
+
}
|
|
7563
|
+
slots.push({
|
|
7564
|
+
insertIndex: i,
|
|
7565
|
+
parentId: parentHrefKey,
|
|
7566
|
+
left,
|
|
7567
|
+
top,
|
|
7568
|
+
width: Math.max(width, 40),
|
|
7569
|
+
height: barThickness,
|
|
7570
|
+
direction: "horizontal"
|
|
7571
|
+
});
|
|
7572
|
+
}
|
|
7573
|
+
return slots;
|
|
7574
|
+
}
|
|
7575
|
+
function buildAllNavDropSlots(draggedHrefKey) {
|
|
7576
|
+
const slots = [...buildRootNavDropSlots()];
|
|
7577
|
+
for (const item of listReorderableNavItems()) {
|
|
7578
|
+
const key = item.getAttribute("data-ohw-href-key");
|
|
7579
|
+
if (!key || key === draggedHrefKey) continue;
|
|
7580
|
+
const group = item.closest("[data-ohw-nav-group]");
|
|
7581
|
+
if (!group?.querySelector(":scope > [data-ohw-nav-children]")) continue;
|
|
7582
|
+
slots.push(...buildChildNavDropSlots(key));
|
|
7583
|
+
}
|
|
7584
|
+
const dragged = listNavbarItems().find((el) => el.getAttribute("data-ohw-href-key") === draggedHrefKey);
|
|
7585
|
+
const parentGroup = dragged?.closest("[data-ohw-nav-children]")?.closest("[data-ohw-nav-group]");
|
|
7586
|
+
const parentTrigger = parentGroup?.querySelector(":scope > [data-ohw-href-key]");
|
|
7587
|
+
const parentKey = parentTrigger?.getAttribute("data-ohw-href-key");
|
|
7588
|
+
if (parentKey && isNavbarHrefKey(parentKey)) {
|
|
7589
|
+
const existing = slots.some((s) => s.parentId === parentKey);
|
|
7590
|
+
if (!existing) slots.push(...buildChildNavDropSlots(parentKey));
|
|
7591
|
+
}
|
|
7592
|
+
return slots;
|
|
7593
|
+
}
|
|
7594
|
+
function hitTestNavDropSlot(clientX, clientY, draggedHrefKey) {
|
|
7595
|
+
const slots = buildAllNavDropSlots(draggedHrefKey);
|
|
7596
|
+
let best = null;
|
|
7597
|
+
for (const slot of slots) {
|
|
7598
|
+
const cx2 = slot.left + slot.width / 2;
|
|
7599
|
+
const cy = slot.top + slot.height / 2;
|
|
7600
|
+
const dist = slot.direction === "vertical" ? Math.abs(clientX - cx2) + Math.abs(clientY - cy) * 0.25 : Math.abs(clientY - cy) + Math.abs(clientX - cx2) * 0.25;
|
|
7601
|
+
if (!best || dist < best.dist) best = { slot, dist };
|
|
7602
|
+
}
|
|
7603
|
+
return best?.slot ?? null;
|
|
7604
|
+
}
|
|
7605
|
+
|
|
7606
|
+
// src/useNavItemDrag.ts
|
|
7607
|
+
import { useCallback as useCallback4, useEffect as useEffect7, useRef as useRef6, useState as useState6 } from "react";
|
|
7608
|
+
function useNavItemDrag({
|
|
7609
|
+
isEditMode,
|
|
7610
|
+
editContentRef,
|
|
7611
|
+
selectedElRef,
|
|
7612
|
+
activeElRef,
|
|
7613
|
+
footerDragRef,
|
|
7614
|
+
suppressNextClickRef,
|
|
7615
|
+
suppressClickUntilRef,
|
|
7616
|
+
siblingHintElRef,
|
|
7617
|
+
postToParentRef,
|
|
7618
|
+
deselectRef,
|
|
7619
|
+
selectRef,
|
|
7620
|
+
deactivateRef,
|
|
7621
|
+
setLinkPopover,
|
|
7622
|
+
linkPopoverOpenRef,
|
|
7623
|
+
setIsItemDragging,
|
|
7624
|
+
setDraggedItemRect,
|
|
7625
|
+
setSiblingHintRect,
|
|
7626
|
+
setSiblingHintRects,
|
|
7627
|
+
setToolbarRect,
|
|
7628
|
+
getNavigationItemAnchor: getNavigationItemAnchor2,
|
|
7629
|
+
isDragHandleDisabled: isDragHandleDisabled2,
|
|
7630
|
+
isNavbarButton: isNavbarButton3
|
|
7631
|
+
}) {
|
|
7632
|
+
const navDragRef = useRef6(null);
|
|
7633
|
+
const [navDropSlots, setNavDropSlots] = useState6([]);
|
|
7634
|
+
const [activeNavDropIndex, setActiveNavDropIndex] = useState6(null);
|
|
7635
|
+
const navPointerDragRef = useRef6(null);
|
|
7636
|
+
const clearNavDragVisuals = useCallback4(() => {
|
|
7637
|
+
navDragRef.current = null;
|
|
7638
|
+
setNavDropSlots([]);
|
|
7639
|
+
setActiveNavDropIndex(null);
|
|
7640
|
+
setDraggedItemRect(null);
|
|
7641
|
+
setSiblingHintRects([]);
|
|
7642
|
+
setIsItemDragging(false);
|
|
7643
|
+
unlockItemDragInteraction();
|
|
7644
|
+
}, [setDraggedItemRect, setIsItemDragging, setSiblingHintRects]);
|
|
7645
|
+
const refreshNavDragVisuals = useCallback4(
|
|
7646
|
+
(session, activeSlot, clientX, clientY) => {
|
|
7647
|
+
setDraggedItemRect(session.draggedEl.getBoundingClientRect());
|
|
7648
|
+
if (typeof clientX === "number" && typeof clientY === "number") {
|
|
7649
|
+
session.lastClientX = clientX;
|
|
7650
|
+
session.lastClientY = clientY;
|
|
7651
|
+
}
|
|
7652
|
+
session.activeSlot = activeSlot;
|
|
7653
|
+
setSiblingHintRects([]);
|
|
7654
|
+
const slots = buildAllNavDropSlots(session.hrefKey);
|
|
7655
|
+
setNavDropSlots(slots);
|
|
7656
|
+
const activeIdx = activeSlot ? slots.findIndex(
|
|
7657
|
+
(s) => s.parentId === activeSlot.parentId && s.insertIndex === activeSlot.insertIndex
|
|
7658
|
+
) : -1;
|
|
7659
|
+
setActiveNavDropIndex(activeIdx >= 0 ? activeIdx : null);
|
|
7660
|
+
},
|
|
7661
|
+
[setDraggedItemRect, setSiblingHintRects]
|
|
7662
|
+
);
|
|
7663
|
+
const refreshNavDragVisualsRef = useRef6(refreshNavDragVisuals);
|
|
7664
|
+
refreshNavDragVisualsRef.current = refreshNavDragVisuals;
|
|
7665
|
+
const commitNavDragRef = useRef6(() => {
|
|
7666
|
+
});
|
|
7667
|
+
const beginNavDragRef = useRef6(() => {
|
|
7668
|
+
});
|
|
7669
|
+
const beginNavDrag = useCallback4(
|
|
7670
|
+
(session) => {
|
|
7671
|
+
const rect = session.draggedEl.getBoundingClientRect();
|
|
7672
|
+
session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
|
|
7673
|
+
session.lastClientY = session.lastClientY || rect.top + rect.height / 2;
|
|
7674
|
+
session.activeSlot = session.activeSlot ?? null;
|
|
7675
|
+
navDragRef.current = session;
|
|
7676
|
+
setIsItemDragging(true);
|
|
7677
|
+
lockItemDuringDrag();
|
|
7678
|
+
siblingHintElRef.current = null;
|
|
7679
|
+
setSiblingHintRect(null);
|
|
7680
|
+
if (session.wasSelected && selectedElRef.current === session.draggedEl) {
|
|
7681
|
+
setToolbarRect(rect);
|
|
7682
|
+
}
|
|
7683
|
+
const initialSlot = hitTestNavDropSlot(session.lastClientX, session.lastClientY, session.hrefKey);
|
|
7684
|
+
refreshNavDragVisuals(session, initialSlot, session.lastClientX, session.lastClientY);
|
|
7685
|
+
},
|
|
7686
|
+
[
|
|
7687
|
+
refreshNavDragVisuals,
|
|
7688
|
+
selectedElRef,
|
|
7689
|
+
setIsItemDragging,
|
|
7690
|
+
setSiblingHintRect,
|
|
7691
|
+
setToolbarRect,
|
|
7692
|
+
siblingHintElRef
|
|
7693
|
+
]
|
|
7694
|
+
);
|
|
7695
|
+
beginNavDragRef.current = beginNavDrag;
|
|
7696
|
+
const commitNavDrag = useCallback4(
|
|
7697
|
+
(clientX, clientY) => {
|
|
7698
|
+
const session = navDragRef.current;
|
|
7699
|
+
if (!session) {
|
|
7700
|
+
clearNavDragVisuals();
|
|
7701
|
+
return;
|
|
7702
|
+
}
|
|
7703
|
+
const x = typeof clientX === "number" && (clientX !== 0 || clientY !== 0) ? clientX : session.lastClientX;
|
|
7704
|
+
const y = typeof clientY === "number" && (clientX !== 0 || clientY !== 0) ? clientY : session.lastClientY;
|
|
7705
|
+
const slot = session.activeSlot ?? hitTestNavDropSlot(x, y, session.hrefKey);
|
|
7706
|
+
const planned = slot != null ? planNavItemMove(session.hrefKey, slot.parentId, slot.insertIndex) : null;
|
|
7707
|
+
const wasSelected = session.wasSelected;
|
|
7708
|
+
const hrefKey = session.hrefKey;
|
|
7709
|
+
const applySelectionAfterDrop = () => {
|
|
7710
|
+
if (!wasSelected) {
|
|
7711
|
+
deselectRef.current();
|
|
7712
|
+
return;
|
|
7713
|
+
}
|
|
7714
|
+
const desktop = document.querySelector("[data-ohw-nav-container]");
|
|
7715
|
+
const drawer = document.querySelector("[data-ohw-nav-drawer]");
|
|
7716
|
+
const link = desktop?.querySelector(`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`) ?? drawer?.querySelector(`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`) ?? document.querySelector(`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`);
|
|
7717
|
+
if (link) {
|
|
7718
|
+
selectRef.current(link);
|
|
7719
|
+
return;
|
|
7720
|
+
}
|
|
7721
|
+
deselectRef.current();
|
|
7722
|
+
};
|
|
7723
|
+
if (planned) {
|
|
7724
|
+
editContentRef.current = {
|
|
7725
|
+
...editContentRef.current,
|
|
7726
|
+
[NAV_ORDER_KEY]: planned.orderJson
|
|
7727
|
+
};
|
|
7728
|
+
applyNavForest(planned.forest);
|
|
7729
|
+
document.querySelectorAll(
|
|
7730
|
+
"nav [data-ohw-href-key], [data-ohw-nav-container] [data-ohw-href-key], [data-ohw-nav-drawer] [data-ohw-href-key]"
|
|
7731
|
+
).forEach((el) => {
|
|
7732
|
+
if (isNavbarHrefKey(el.getAttribute("data-ohw-href-key"))) {
|
|
7733
|
+
disableNativeHrefDrag(el);
|
|
7734
|
+
}
|
|
7735
|
+
});
|
|
7736
|
+
postToParentRef.current({
|
|
7737
|
+
type: "ow:change",
|
|
7738
|
+
nodes: [{ key: NAV_ORDER_KEY, text: planned.orderJson }]
|
|
7739
|
+
});
|
|
7740
|
+
applySelectionAfterDrop();
|
|
7741
|
+
clearNavDragVisuals();
|
|
7742
|
+
requestAnimationFrame(() => {
|
|
7743
|
+
if (editContentRef.current[NAV_ORDER_KEY] === planned.orderJson) {
|
|
7744
|
+
applyNavForest(planned.forest);
|
|
7745
|
+
}
|
|
7746
|
+
applySelectionAfterDrop();
|
|
7747
|
+
requestAnimationFrame(applySelectionAfterDrop);
|
|
7748
|
+
});
|
|
7749
|
+
return;
|
|
7750
|
+
}
|
|
7751
|
+
applySelectionAfterDrop();
|
|
7752
|
+
clearNavDragVisuals();
|
|
7753
|
+
},
|
|
7754
|
+
[clearNavDragVisuals, deselectRef, editContentRef, postToParentRef, selectRef]
|
|
7755
|
+
);
|
|
7756
|
+
commitNavDragRef.current = commitNavDrag;
|
|
7757
|
+
const startNavLinkDrag = useCallback4(
|
|
7758
|
+
(anchor, clientX, clientY, wasSelected) => {
|
|
7759
|
+
if (footerDragRef.current) return false;
|
|
7760
|
+
const hrefKey = anchor.getAttribute("data-ohw-href-key");
|
|
7761
|
+
if (!hrefKey || !isNavbarHrefKey(hrefKey)) return false;
|
|
7762
|
+
if (isNavbarButton3(anchor) || isDragHandleDisabled2(anchor)) return false;
|
|
7763
|
+
beginNavDrag({
|
|
7764
|
+
hrefKey,
|
|
7765
|
+
wasSelected,
|
|
7766
|
+
draggedEl: anchor,
|
|
7767
|
+
lastClientX: clientX,
|
|
7768
|
+
lastClientY: clientY,
|
|
7769
|
+
activeSlot: null
|
|
7770
|
+
});
|
|
7771
|
+
return true;
|
|
7772
|
+
},
|
|
7773
|
+
[beginNavDrag, footerDragRef, isDragHandleDisabled2, isNavbarButton3]
|
|
7774
|
+
);
|
|
7775
|
+
const onNavDragOver = useCallback4(
|
|
7776
|
+
(e) => {
|
|
7777
|
+
const session = navDragRef.current;
|
|
7778
|
+
if (!session) return false;
|
|
7779
|
+
e.preventDefault();
|
|
7780
|
+
if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
|
|
7781
|
+
const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey);
|
|
7782
|
+
refreshNavDragVisualsRef.current(session, slot, e.clientX, e.clientY);
|
|
7783
|
+
return true;
|
|
7784
|
+
},
|
|
7785
|
+
[]
|
|
7786
|
+
);
|
|
7787
|
+
useEffect7(() => {
|
|
7788
|
+
if (!isEditMode) return;
|
|
7789
|
+
const THRESHOLD = 10;
|
|
7790
|
+
const resolveWasSelected = (el) => {
|
|
7791
|
+
if (selectedElRef.current === el) return true;
|
|
7792
|
+
const activeAnchor = activeElRef.current ? getNavigationItemAnchor2(activeElRef.current) : null;
|
|
7793
|
+
return activeAnchor === el;
|
|
7794
|
+
};
|
|
7795
|
+
const onPointerDown = (e) => {
|
|
7796
|
+
if (e.button !== 0) return;
|
|
7797
|
+
if (navDragRef.current || footerDragRef.current) return;
|
|
7798
|
+
const target = e.target;
|
|
7799
|
+
if (!target) return;
|
|
7800
|
+
if (target.closest(
|
|
7801
|
+
'[data-ohw-drag-handle-container], [data-slot="drag-handle"], [data-ohw-toolbar], [data-ohw-item-toolbar-anchor], [data-ohw-link-popover-root]'
|
|
7802
|
+
)) {
|
|
7803
|
+
return;
|
|
7804
|
+
}
|
|
7805
|
+
if (target.closest("[data-ohw-item-drag-surface]")) return;
|
|
7806
|
+
const anchor = getNavigationItemAnchor2(target);
|
|
7807
|
+
const hrefKey = anchor?.getAttribute("data-ohw-href-key") ?? null;
|
|
7808
|
+
if (!anchor || !isNavbarHrefKey(hrefKey)) return;
|
|
7809
|
+
if (isNavbarButton3(anchor) || isDragHandleDisabled2(anchor)) return;
|
|
7810
|
+
navPointerDragRef.current = {
|
|
7811
|
+
el: anchor,
|
|
7812
|
+
startX: e.clientX,
|
|
7813
|
+
startY: e.clientY,
|
|
7814
|
+
pointerId: e.pointerId,
|
|
7815
|
+
wasSelected: resolveWasSelected(anchor),
|
|
7816
|
+
started: false
|
|
7817
|
+
};
|
|
7818
|
+
};
|
|
7819
|
+
const onPointerMove = (e) => {
|
|
7820
|
+
const pending = navPointerDragRef.current;
|
|
7821
|
+
if (!pending) return;
|
|
7822
|
+
if (pending.started) {
|
|
7823
|
+
e.preventDefault();
|
|
7824
|
+
clearTextSelection();
|
|
7825
|
+
const session = navDragRef.current;
|
|
7826
|
+
if (!session) return;
|
|
7827
|
+
const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey);
|
|
7828
|
+
refreshNavDragVisualsRef.current(session, slot, e.clientX, e.clientY);
|
|
7829
|
+
return;
|
|
7830
|
+
}
|
|
7831
|
+
const dx = e.clientX - pending.startX;
|
|
7832
|
+
const dy = e.clientY - pending.startY;
|
|
7833
|
+
if (dx * dx + dy * dy < THRESHOLD * THRESHOLD) return;
|
|
7834
|
+
e.preventDefault();
|
|
7835
|
+
pending.started = true;
|
|
7836
|
+
armItemPressDrag();
|
|
7837
|
+
clearTextSelection();
|
|
7838
|
+
try {
|
|
7839
|
+
document.body.setPointerCapture(pending.pointerId);
|
|
7840
|
+
} catch {
|
|
7841
|
+
}
|
|
7842
|
+
if (linkPopoverOpenRef.current) setLinkPopover(null);
|
|
7843
|
+
if (activeElRef.current) deactivateRef.current();
|
|
7844
|
+
const key = pending.el.getAttribute("data-ohw-href-key");
|
|
7845
|
+
if (!key) return;
|
|
7846
|
+
beginNavDragRef.current({
|
|
7847
|
+
hrefKey: key,
|
|
7848
|
+
wasSelected: pending.wasSelected,
|
|
7849
|
+
draggedEl: pending.el,
|
|
7850
|
+
lastClientX: e.clientX,
|
|
7851
|
+
lastClientY: e.clientY,
|
|
7852
|
+
activeSlot: null
|
|
7853
|
+
});
|
|
7854
|
+
};
|
|
7855
|
+
const endPointerDrag = (e) => {
|
|
7856
|
+
const pending = navPointerDragRef.current;
|
|
7857
|
+
navPointerDragRef.current = null;
|
|
7858
|
+
try {
|
|
7859
|
+
if (document.body.hasPointerCapture(e.pointerId)) {
|
|
7860
|
+
document.body.releasePointerCapture(e.pointerId);
|
|
7861
|
+
}
|
|
7862
|
+
} catch {
|
|
7863
|
+
}
|
|
7864
|
+
if (!pending) return;
|
|
7865
|
+
if (!pending.started) {
|
|
7866
|
+
unlockItemDragInteraction();
|
|
7867
|
+
return;
|
|
7868
|
+
}
|
|
7869
|
+
suppressNextClickRef.current = true;
|
|
7870
|
+
suppressClickUntilRef.current = Date.now() + 500;
|
|
7871
|
+
commitNavDragRef.current(e.clientX, e.clientY);
|
|
7872
|
+
};
|
|
7873
|
+
const blockSelectStart = (e) => {
|
|
7874
|
+
if (navDragRef.current || navPointerDragRef.current?.started || document.documentElement.hasAttribute("data-ohw-footer-press-drag")) {
|
|
7875
|
+
e.preventDefault();
|
|
7876
|
+
}
|
|
7877
|
+
};
|
|
7878
|
+
const onDragEnd = () => {
|
|
7879
|
+
if (!navDragRef.current) return;
|
|
7880
|
+
suppressNextClickRef.current = true;
|
|
7881
|
+
suppressClickUntilRef.current = Date.now() + 500;
|
|
7882
|
+
commitNavDragRef.current();
|
|
7883
|
+
};
|
|
7884
|
+
document.addEventListener("pointerdown", onPointerDown, true);
|
|
7885
|
+
document.addEventListener("pointermove", onPointerMove, true);
|
|
7886
|
+
document.addEventListener("pointerup", endPointerDrag, true);
|
|
7887
|
+
document.addEventListener("pointercancel", endPointerDrag, true);
|
|
7888
|
+
document.addEventListener("selectstart", blockSelectStart, true);
|
|
7889
|
+
document.addEventListener("dragend", onDragEnd, true);
|
|
7890
|
+
return () => {
|
|
7891
|
+
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
7892
|
+
document.removeEventListener("pointermove", onPointerMove, true);
|
|
7893
|
+
document.removeEventListener("pointerup", endPointerDrag, true);
|
|
7894
|
+
document.removeEventListener("pointercancel", endPointerDrag, true);
|
|
7895
|
+
document.removeEventListener("selectstart", blockSelectStart, true);
|
|
7896
|
+
document.removeEventListener("dragend", onDragEnd, true);
|
|
7897
|
+
unlockItemDragInteraction();
|
|
7898
|
+
};
|
|
7899
|
+
}, [
|
|
7900
|
+
activeElRef,
|
|
7901
|
+
deactivateRef,
|
|
7902
|
+
footerDragRef,
|
|
7903
|
+
getNavigationItemAnchor2,
|
|
7904
|
+
isDragHandleDisabled2,
|
|
7905
|
+
isEditMode,
|
|
7906
|
+
isNavbarButton3,
|
|
7907
|
+
linkPopoverOpenRef,
|
|
7908
|
+
selectedElRef,
|
|
7909
|
+
setLinkPopover,
|
|
7910
|
+
suppressNextClickRef
|
|
7911
|
+
]);
|
|
7912
|
+
const armNavPressFromChrome = useCallback4(
|
|
7913
|
+
(selected, clientX, clientY, pointerId) => {
|
|
7914
|
+
const hrefKey = selected.getAttribute("data-ohw-href-key");
|
|
7915
|
+
if (!hrefKey || !isNavbarHrefKey(hrefKey)) return false;
|
|
7916
|
+
if (isNavbarButton3(selected) || isDragHandleDisabled2(selected)) return false;
|
|
7917
|
+
navPointerDragRef.current = {
|
|
7918
|
+
el: selected,
|
|
7919
|
+
startX: clientX,
|
|
7920
|
+
startY: clientY,
|
|
7921
|
+
pointerId,
|
|
7922
|
+
wasSelected: true,
|
|
7923
|
+
started: false
|
|
7924
|
+
};
|
|
7925
|
+
return true;
|
|
7926
|
+
},
|
|
7927
|
+
[isDragHandleDisabled2, isNavbarButton3]
|
|
7928
|
+
);
|
|
7929
|
+
return {
|
|
7930
|
+
navDragRef,
|
|
7931
|
+
navDropSlots,
|
|
7932
|
+
activeNavDropIndex,
|
|
7933
|
+
startNavLinkDrag,
|
|
7934
|
+
commitNavDrag,
|
|
7935
|
+
onNavDragOver,
|
|
7936
|
+
armNavPressFromChrome,
|
|
7937
|
+
clearNavDragVisuals,
|
|
7938
|
+
refreshNavDragVisualsRef
|
|
7939
|
+
};
|
|
7940
|
+
}
|
|
7941
|
+
|
|
7942
|
+
// src/ui/footer-container-chrome.tsx
|
|
7943
|
+
import { Plus as Plus2 } from "lucide-react";
|
|
7944
|
+
import { jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
7945
|
+
function FooterContainerChrome({ rect, onAdd }) {
|
|
7946
|
+
const chromeGap = 6;
|
|
7947
|
+
const buttonMargin = 7;
|
|
7948
|
+
return /* @__PURE__ */ jsx21(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsx21(
|
|
7949
|
+
"div",
|
|
7950
|
+
{
|
|
7951
|
+
"data-ohw-footer-container-chrome": "",
|
|
7952
|
+
"data-ohw-bridge": "",
|
|
7953
|
+
className: "pointer-events-none fixed z-[2147483647]",
|
|
7954
|
+
style: {
|
|
7955
|
+
top: rect.top - chromeGap,
|
|
7956
|
+
left: rect.left - chromeGap,
|
|
7957
|
+
width: rect.width + chromeGap * 2,
|
|
7958
|
+
height: rect.height + chromeGap * 2
|
|
7959
|
+
},
|
|
7960
|
+
children: /* @__PURE__ */ jsxs13(Tooltip, { children: [
|
|
7961
|
+
/* @__PURE__ */ jsx21(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx21(
|
|
7962
|
+
"button",
|
|
7963
|
+
{
|
|
7964
|
+
type: "button",
|
|
7965
|
+
"data-ohw-footer-add-button": "",
|
|
7966
|
+
className: "pointer-events-auto absolute left-1/2 flex size-7 -translate-x-1/2 -translate-y-full items-center justify-center rounded-[10px] border border-border bg-background p-0.5 shadow-sm transition-colors hover:bg-muted/80",
|
|
7967
|
+
style: { top: chromeGap - buttonMargin },
|
|
7968
|
+
"aria-label": "Add item",
|
|
7969
|
+
onMouseDown: (e) => {
|
|
7970
|
+
e.preventDefault();
|
|
7971
|
+
e.stopPropagation();
|
|
7972
|
+
},
|
|
7973
|
+
onClick: (e) => {
|
|
7974
|
+
e.preventDefault();
|
|
7975
|
+
e.stopPropagation();
|
|
7976
|
+
onAdd();
|
|
7977
|
+
},
|
|
7978
|
+
children: /* @__PURE__ */ jsx21(Plus2, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
|
|
7979
|
+
}
|
|
7980
|
+
) }),
|
|
7981
|
+
/* @__PURE__ */ jsx21(TooltipContent, { side: "bottom", sideOffset: 9, children: "Add item" })
|
|
7982
|
+
] })
|
|
7983
|
+
}
|
|
7984
|
+
) });
|
|
7985
|
+
}
|
|
7986
|
+
|
|
7987
|
+
// src/ui/navbar-container-chrome.tsx
|
|
7988
|
+
import { Plus as Plus3 } from "lucide-react";
|
|
7989
|
+
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
7990
|
+
function NavbarContainerChrome({
|
|
7991
|
+
rect,
|
|
7992
|
+
onAdd
|
|
7993
|
+
}) {
|
|
7994
|
+
const chromeGap = 6;
|
|
7995
|
+
return /* @__PURE__ */ jsx22(
|
|
7996
|
+
"div",
|
|
7997
|
+
{
|
|
7998
|
+
"data-ohw-navbar-container-chrome": "",
|
|
7999
|
+
"data-ohw-bridge": "",
|
|
8000
|
+
className: "pointer-events-none fixed z-[2147483647]",
|
|
8001
|
+
style: {
|
|
8002
|
+
top: rect.top - chromeGap,
|
|
8003
|
+
left: rect.left - chromeGap,
|
|
8004
|
+
width: rect.width + chromeGap * 2,
|
|
8005
|
+
height: rect.height + chromeGap * 2
|
|
8006
|
+
},
|
|
8007
|
+
children: /* @__PURE__ */ jsx22(
|
|
8008
|
+
"button",
|
|
8009
|
+
{
|
|
8010
|
+
type: "button",
|
|
8011
|
+
"data-ohw-navbar-add-button": "",
|
|
8012
|
+
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",
|
|
8013
|
+
style: { top: "70%" },
|
|
8014
|
+
"aria-label": "Add item",
|
|
8015
|
+
onMouseDown: (e) => {
|
|
8016
|
+
e.preventDefault();
|
|
8017
|
+
e.stopPropagation();
|
|
8018
|
+
},
|
|
8019
|
+
onClick: (e) => {
|
|
8020
|
+
e.preventDefault();
|
|
8021
|
+
e.stopPropagation();
|
|
8022
|
+
onAdd();
|
|
8023
|
+
},
|
|
8024
|
+
children: /* @__PURE__ */ jsx22(Plus3, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
|
|
8025
|
+
}
|
|
8026
|
+
)
|
|
8027
|
+
}
|
|
8028
|
+
);
|
|
8029
|
+
}
|
|
8030
|
+
|
|
8031
|
+
// src/ui/drop-indicator.tsx
|
|
8032
|
+
import * as React10 from "react";
|
|
8033
|
+
import { jsx as jsx23 } from "react/jsx-runtime";
|
|
8034
|
+
var dropIndicatorVariants = cva(
|
|
8035
|
+
"ov-gap-line pointer-events-none shrink-0 transition-opacity duration-150",
|
|
8036
|
+
{
|
|
8037
|
+
variants: {
|
|
8038
|
+
direction: {
|
|
8039
|
+
vertical: "h-6 w-[3px]",
|
|
8040
|
+
horizontal: "h-[3px] w-[200px]"
|
|
8041
|
+
},
|
|
8042
|
+
state: {
|
|
8043
|
+
default: "opacity-0",
|
|
8044
|
+
hover: "opacity-100",
|
|
8045
|
+
dragIdle: "opacity-40",
|
|
8046
|
+
dragActive: "opacity-100"
|
|
8047
|
+
}
|
|
8048
|
+
},
|
|
8049
|
+
defaultVariants: {
|
|
8050
|
+
direction: "vertical",
|
|
8051
|
+
state: "default"
|
|
8052
|
+
}
|
|
8053
|
+
}
|
|
8054
|
+
);
|
|
8055
|
+
var DropIndicator = React10.forwardRef(
|
|
8056
|
+
({ className, direction, state, ...props }, ref) => {
|
|
8057
|
+
return /* @__PURE__ */ jsx23(
|
|
8058
|
+
"div",
|
|
8059
|
+
{
|
|
8060
|
+
ref,
|
|
8061
|
+
"data-slot": "drop-indicator",
|
|
8062
|
+
"data-direction": direction ?? "vertical",
|
|
8063
|
+
"data-state": state ?? "default",
|
|
8064
|
+
"aria-hidden": "true",
|
|
8065
|
+
className: cn(dropIndicatorVariants({ direction, state }), className),
|
|
8066
|
+
...props
|
|
8067
|
+
}
|
|
8068
|
+
);
|
|
8069
|
+
}
|
|
8070
|
+
);
|
|
8071
|
+
DropIndicator.displayName = "DropIndicator";
|
|
8072
|
+
|
|
8073
|
+
// src/ui/badge.tsx
|
|
8074
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
8075
|
+
var badgeVariants = cva(
|
|
8076
|
+
"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",
|
|
8077
|
+
{
|
|
8078
|
+
variants: {
|
|
8079
|
+
variant: {
|
|
8080
|
+
default: "border-transparent bg-primary text-primary-foreground",
|
|
8081
|
+
secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
8082
|
+
destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
|
8083
|
+
outline: "text-foreground"
|
|
8084
|
+
}
|
|
8085
|
+
},
|
|
8086
|
+
defaultVariants: {
|
|
8087
|
+
variant: "default"
|
|
8088
|
+
}
|
|
8089
|
+
}
|
|
8090
|
+
);
|
|
8091
|
+
function Badge({ className, variant, ...props }) {
|
|
8092
|
+
return /* @__PURE__ */ jsx24("div", { className: cn(badgeVariants({ variant }), className), ...props });
|
|
8093
|
+
}
|
|
8094
|
+
|
|
8095
|
+
// src/OhhwellsBridge.tsx
|
|
8096
|
+
import { Link as Link2 } from "lucide-react";
|
|
8097
|
+
import { Fragment as Fragment5, jsx as jsx25, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
8098
|
+
var PRIMARY2 = "#0885FE";
|
|
8099
|
+
var IMAGE_FADE_MS = 300;
|
|
8100
|
+
function runOpacityFade(el, onDone) {
|
|
8101
|
+
const anim = el.animate([{ opacity: 0 }, { opacity: 1 }], {
|
|
8102
|
+
duration: IMAGE_FADE_MS,
|
|
8103
|
+
easing: "ease",
|
|
8104
|
+
fill: "forwards"
|
|
8105
|
+
});
|
|
8106
|
+
let finished = false;
|
|
8107
|
+
const finish = () => {
|
|
8108
|
+
if (finished) return;
|
|
8109
|
+
finished = true;
|
|
8110
|
+
anim.cancel();
|
|
8111
|
+
el.style.opacity = "";
|
|
8112
|
+
onDone();
|
|
8113
|
+
};
|
|
8114
|
+
anim.finished.then(finish).catch(finish);
|
|
8115
|
+
window.setTimeout(finish, IMAGE_FADE_MS + 100);
|
|
8116
|
+
}
|
|
8117
|
+
function fadeInImageElement(img, onReady) {
|
|
8118
|
+
onReady();
|
|
8119
|
+
img.style.opacity = "0";
|
|
8120
|
+
runOpacityFade(img, () => {
|
|
8121
|
+
img.style.opacity = "";
|
|
8122
|
+
});
|
|
8123
|
+
}
|
|
8124
|
+
function applyEditableImageSrc(img, url) {
|
|
8125
|
+
img.removeAttribute("srcset");
|
|
8126
|
+
img.removeAttribute("sizes");
|
|
8127
|
+
img.src = url;
|
|
8128
|
+
}
|
|
8129
|
+
function fadeInBgImage(el, url, onReady) {
|
|
8130
|
+
const prevPos = el.style.position;
|
|
8131
|
+
if (!prevPos || prevPos === "static") el.style.position = "relative";
|
|
8132
|
+
const layer = document.createElement("div");
|
|
8133
|
+
layer.setAttribute("data-ohw-bg-fade-layer", "");
|
|
8134
|
+
Object.assign(layer.style, {
|
|
8135
|
+
position: "absolute",
|
|
8136
|
+
inset: "0",
|
|
8137
|
+
zIndex: "0",
|
|
8138
|
+
backgroundImage: `url('${url}')`,
|
|
8139
|
+
backgroundSize: "cover",
|
|
8140
|
+
backgroundPosition: "center",
|
|
8141
|
+
backgroundRepeat: "no-repeat",
|
|
8142
|
+
opacity: "0",
|
|
8143
|
+
pointerEvents: "none"
|
|
8144
|
+
});
|
|
8145
|
+
el.prepend(layer);
|
|
8146
|
+
onReady();
|
|
8147
|
+
runOpacityFade(layer, () => {
|
|
8148
|
+
el.style.backgroundImage = `url('${url}')`;
|
|
8149
|
+
layer.remove();
|
|
8150
|
+
if (!prevPos || prevPos === "static") el.style.position = prevPos;
|
|
8151
|
+
});
|
|
8152
|
+
}
|
|
8153
|
+
function getSectionsTracker() {
|
|
8154
|
+
let el = document.querySelector("[data-ohw-sections-tracker]");
|
|
8155
|
+
if (!el) {
|
|
8156
|
+
el = document.createElement("div");
|
|
8157
|
+
el.setAttribute("data-ohw-sections-tracker", "");
|
|
8158
|
+
el.style.display = "none";
|
|
8159
|
+
document.body.appendChild(el);
|
|
8160
|
+
}
|
|
8161
|
+
return el;
|
|
8162
|
+
}
|
|
8163
|
+
function updateSectionScheduleId(insertAfter, scheduleId) {
|
|
8164
|
+
const tracker = getSectionsTracker();
|
|
8165
|
+
let sections = [];
|
|
8166
|
+
try {
|
|
8167
|
+
sections = JSON.parse(tracker.textContent || "[]");
|
|
8168
|
+
} catch {
|
|
8169
|
+
}
|
|
8170
|
+
const currentPath = window.location.pathname;
|
|
8171
|
+
const updated = sections.map((s) => {
|
|
6639
8172
|
if (s.type !== "scheduling" || s.insertAfter !== insertAfter) return s;
|
|
6640
8173
|
if (s.pagePath && s.pagePath !== currentPath) return s;
|
|
6641
8174
|
return { ...s, scheduleId };
|
|
@@ -6740,7 +8273,7 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
6740
8273
|
const root = createRoot(container);
|
|
6741
8274
|
flushSync(() => {
|
|
6742
8275
|
root.render(
|
|
6743
|
-
/* @__PURE__ */
|
|
8276
|
+
/* @__PURE__ */ jsx25(
|
|
6744
8277
|
SchedulingWidget,
|
|
6745
8278
|
{
|
|
6746
8279
|
notifyOnConnect,
|
|
@@ -6815,7 +8348,7 @@ function syncNavigationDragCursorAttrs() {
|
|
|
6815
8348
|
el.setAttribute("data-ohw-can-drag", "");
|
|
6816
8349
|
});
|
|
6817
8350
|
}
|
|
6818
|
-
function collectEditableNodes() {
|
|
8351
|
+
function collectEditableNodes(extraContent) {
|
|
6819
8352
|
const nodes = Array.from(document.querySelectorAll("[data-ohw-editable]")).map((el) => {
|
|
6820
8353
|
if (el.dataset.ohwEditable === "image") {
|
|
6821
8354
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
@@ -6843,6 +8376,14 @@ function collectEditableNodes() {
|
|
|
6843
8376
|
if (!key) return;
|
|
6844
8377
|
nodes.push({ key, type: "link", text: getLinkHref2(el) });
|
|
6845
8378
|
});
|
|
8379
|
+
if (extraContent) {
|
|
8380
|
+
for (const key of [NAV_ORDER_KEY, FOOTER_ORDER_KEY, NAV_COUNT_KEY]) {
|
|
8381
|
+
const text = extraContent[key];
|
|
8382
|
+
if (typeof text === "string" && text.length > 0) {
|
|
8383
|
+
nodes.push({ key, type: "meta", text });
|
|
8384
|
+
}
|
|
8385
|
+
}
|
|
8386
|
+
}
|
|
6846
8387
|
document.querySelectorAll('[data-ohw-editable="video"]').forEach((el) => {
|
|
6847
8388
|
const key = el.dataset.ohwKey ?? "";
|
|
6848
8389
|
const video = getVideoEl(el);
|
|
@@ -6933,7 +8474,7 @@ function applyLinkByKey(key, val) {
|
|
|
6933
8474
|
}
|
|
6934
8475
|
function isInsideLinkEditor(target) {
|
|
6935
8476
|
return Boolean(
|
|
6936
|
-
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"]')
|
|
8477
|
+
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-ohw-footer-container-chrome]") || target.closest("[data-ohw-footer-add-button]") || target.closest('[data-slot="popover-content"]') || target.closest('[data-slot="dialog-content"]') || target.closest('[data-slot="dialog-overlay"]')
|
|
6937
8478
|
);
|
|
6938
8479
|
}
|
|
6939
8480
|
function getHrefKeyFromElement(el) {
|
|
@@ -6956,6 +8497,11 @@ function getNavigationItemAnchor(el) {
|
|
|
6956
8497
|
function isNavigationItem(el) {
|
|
6957
8498
|
return getNavigationItemAnchor(el) !== null;
|
|
6958
8499
|
}
|
|
8500
|
+
function listNavigationItems() {
|
|
8501
|
+
return Array.from(
|
|
8502
|
+
document.querySelectorAll("nav [data-ohw-href-key], footer [data-ohw-href-key]")
|
|
8503
|
+
).filter((el) => isNavigationItem(el));
|
|
8504
|
+
}
|
|
6959
8505
|
function getNavigationItemReorderState(anchor) {
|
|
6960
8506
|
if (isNavbarButton2(anchor)) return { key: null, disabled: false };
|
|
6961
8507
|
return getReorderHandleStateFromAnchor(anchor);
|
|
@@ -6988,7 +8534,7 @@ function countFooterNavItems(el) {
|
|
|
6988
8534
|
return Array.from(el.querySelectorAll("[data-ohw-href-key]")).filter(isNavigationItem).length;
|
|
6989
8535
|
}
|
|
6990
8536
|
function findFooterItemGroup(item) {
|
|
6991
|
-
const explicit = item.closest("[data-ohw-footer-column]");
|
|
8537
|
+
const explicit = item.closest("[data-ohw-footer-col], [data-ohw-footer-column]");
|
|
6992
8538
|
if (explicit) return explicit;
|
|
6993
8539
|
const footer = item.closest("footer");
|
|
6994
8540
|
if (!footer) return null;
|
|
@@ -7005,17 +8551,17 @@ function isNavigationRoot(el) {
|
|
|
7005
8551
|
function isInferredFooterGroup(el) {
|
|
7006
8552
|
const footer = el.closest("footer");
|
|
7007
8553
|
if (!footer || el === footer) return false;
|
|
7008
|
-
if (el.hasAttribute("data-ohw-footer-column")) return true;
|
|
8554
|
+
if (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column")) return true;
|
|
7009
8555
|
return countFooterNavItems(el) >= 2;
|
|
7010
8556
|
}
|
|
7011
8557
|
function isNavigationContainer(el) {
|
|
7012
|
-
return el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-footer-column") || isNavigationRoot(el) || isInferredFooterGroup(el);
|
|
8558
|
+
return el.hasAttribute("data-ohw-nav-container") || isFooterLinksContainer(el) || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isNavigationRoot(el) || isInferredFooterGroup(el);
|
|
7013
8559
|
}
|
|
7014
8560
|
function isNavbarLinksContainer(el) {
|
|
7015
8561
|
return el.hasAttribute("data-ohw-nav-container");
|
|
7016
8562
|
}
|
|
7017
8563
|
function getFooterColumn(el) {
|
|
7018
|
-
return el.closest("[data-ohw-footer-column]");
|
|
8564
|
+
return el.closest("[data-ohw-footer-col], [data-ohw-footer-column]");
|
|
7019
8565
|
}
|
|
7020
8566
|
function resolveFooterColumnSelectionTarget(target, clientX, clientY) {
|
|
7021
8567
|
if (getNavigationItemAnchor(target)) return null;
|
|
@@ -7028,6 +8574,9 @@ function isPointOverNavigation(x, y) {
|
|
|
7028
8574
|
const roots = /* @__PURE__ */ new Set();
|
|
7029
8575
|
const navRoot = document.querySelector("[data-ohw-nav-root]") ?? document.querySelector("nav");
|
|
7030
8576
|
if (navRoot) roots.add(navRoot);
|
|
8577
|
+
document.querySelectorAll("[data-ohw-nav-drawer], [data-ohw-nav-container]").forEach((el) => {
|
|
8578
|
+
roots.add(el);
|
|
8579
|
+
});
|
|
7031
8580
|
const footer = document.querySelector("footer");
|
|
7032
8581
|
if (footer) roots.add(footer);
|
|
7033
8582
|
for (const root of roots) {
|
|
@@ -7039,7 +8588,7 @@ function isPointOverNavigation(x, y) {
|
|
|
7039
8588
|
function findHoveredNavOrFooterContainer(x, y) {
|
|
7040
8589
|
const candidates = [
|
|
7041
8590
|
...document.querySelectorAll("[data-ohw-nav-container]"),
|
|
7042
|
-
...
|
|
8591
|
+
...listFooterColumns()
|
|
7043
8592
|
];
|
|
7044
8593
|
for (const container of candidates) {
|
|
7045
8594
|
const r2 = container.getBoundingClientRect();
|
|
@@ -7056,6 +8605,12 @@ function isPointOverNavItem(container, x, y) {
|
|
|
7056
8605
|
return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
|
|
7057
8606
|
});
|
|
7058
8607
|
}
|
|
8608
|
+
function isPointOverFooterColumn(x, y) {
|
|
8609
|
+
return listFooterColumns().some((col) => {
|
|
8610
|
+
const r2 = col.getBoundingClientRect();
|
|
8611
|
+
return x >= r2.left && x <= r2.right && y >= r2.top && y <= r2.bottom;
|
|
8612
|
+
});
|
|
8613
|
+
}
|
|
7059
8614
|
function resolveNavContainerSelectionTarget(target, clientX, clientY) {
|
|
7060
8615
|
if (getNavigationItemAnchor(target)) return null;
|
|
7061
8616
|
if (target.closest('[data-ohw-role="navbar-button"]')) return null;
|
|
@@ -7086,32 +8641,60 @@ function getNavigationSelectionParent(el) {
|
|
|
7086
8641
|
if (footerGroup) return footerGroup;
|
|
7087
8642
|
return getNavigationRoot(el);
|
|
7088
8643
|
}
|
|
7089
|
-
if (el.hasAttribute("data-ohw-
|
|
8644
|
+
if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup(el))) {
|
|
8645
|
+
return getFooterLinksContainer();
|
|
8646
|
+
}
|
|
8647
|
+
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isFooterLinksContainer(el) || isInferredFooterGroup(el)) {
|
|
7090
8648
|
return getNavigationRoot(el);
|
|
7091
8649
|
}
|
|
7092
8650
|
return null;
|
|
7093
8651
|
}
|
|
8652
|
+
function collectNavigationItemSiblingHintRects(selected) {
|
|
8653
|
+
if (!isNavigationItem(selected)) return [];
|
|
8654
|
+
const footerColumn = getFooterColumn(selected);
|
|
8655
|
+
if (footerColumn) {
|
|
8656
|
+
return listFooterLinksInColumn(footerColumn).filter((link) => link !== selected).map((link) => link.getBoundingClientRect());
|
|
8657
|
+
}
|
|
8658
|
+
const navContainer = selected.closest("[data-ohw-nav-container], [data-ohw-nav-drawer]");
|
|
8659
|
+
if (navContainer) {
|
|
8660
|
+
return Array.from(navContainer.querySelectorAll("[data-ohw-href-key]")).filter((el) => isNavigationItem(el) && el !== selected).map((el) => el.getBoundingClientRect());
|
|
8661
|
+
}
|
|
8662
|
+
return listNavigationItems().filter((el) => el !== selected).map((el) => el.getBoundingClientRect());
|
|
8663
|
+
}
|
|
7094
8664
|
function placeCaretAtPoint(el, x, y) {
|
|
7095
8665
|
const selection = window.getSelection();
|
|
7096
8666
|
if (!selection) return;
|
|
7097
|
-
|
|
7098
|
-
|
|
7099
|
-
|
|
7100
|
-
|
|
7101
|
-
|
|
7102
|
-
|
|
8667
|
+
const overlays = Array.from(
|
|
8668
|
+
document.querySelectorAll(
|
|
8669
|
+
"[data-ohw-item-drag-surface], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-ohw-item-toolbar-anchor]"
|
|
8670
|
+
)
|
|
8671
|
+
);
|
|
8672
|
+
const prevPointerEvents = overlays.map((node) => node.style.pointerEvents);
|
|
8673
|
+
for (const node of overlays) node.style.pointerEvents = "none";
|
|
8674
|
+
try {
|
|
8675
|
+
if (typeof document.caretRangeFromPoint === "function") {
|
|
8676
|
+
const range = document.caretRangeFromPoint(x, y);
|
|
8677
|
+
if (range && el.contains(range.startContainer)) {
|
|
8678
|
+
selection.removeAllRanges();
|
|
8679
|
+
selection.addRange(range);
|
|
8680
|
+
return;
|
|
8681
|
+
}
|
|
7103
8682
|
}
|
|
7104
|
-
|
|
7105
|
-
|
|
7106
|
-
|
|
7107
|
-
|
|
7108
|
-
|
|
7109
|
-
|
|
7110
|
-
|
|
7111
|
-
|
|
7112
|
-
|
|
7113
|
-
|
|
8683
|
+
const caretPositionFromPoint = document.caretPositionFromPoint;
|
|
8684
|
+
if (typeof caretPositionFromPoint === "function") {
|
|
8685
|
+
const position = caretPositionFromPoint(x, y);
|
|
8686
|
+
if (position && el.contains(position.offsetNode)) {
|
|
8687
|
+
const range = document.createRange();
|
|
8688
|
+
range.setStart(position.offsetNode, position.offset);
|
|
8689
|
+
range.collapse(true);
|
|
8690
|
+
selection.removeAllRanges();
|
|
8691
|
+
selection.addRange(range);
|
|
8692
|
+
}
|
|
7114
8693
|
}
|
|
8694
|
+
} finally {
|
|
8695
|
+
overlays.forEach((node, i) => {
|
|
8696
|
+
node.style.pointerEvents = prevPointerEvents[i] ?? "";
|
|
8697
|
+
});
|
|
7115
8698
|
}
|
|
7116
8699
|
}
|
|
7117
8700
|
function selectAllTextInEditable(el) {
|
|
@@ -7232,9 +8815,16 @@ function sanitizeHtml(html) {
|
|
|
7232
8815
|
if (!SAFE_TAGS.has(el.tagName)) {
|
|
7233
8816
|
parent.replaceChild(document.createTextNode(el.textContent ?? ""), el);
|
|
7234
8817
|
} else {
|
|
7235
|
-
const
|
|
8818
|
+
const htmlEl = el;
|
|
8819
|
+
const textAlign = htmlEl.style?.textAlign || el.getAttribute("align") || "";
|
|
8820
|
+
const fontWeight = htmlEl.style?.fontWeight || "";
|
|
8821
|
+
const fontStyle = htmlEl.style?.fontStyle || "";
|
|
8822
|
+
const textDecorationLine = htmlEl.style?.textDecorationLine || htmlEl.style?.textDecoration || "";
|
|
7236
8823
|
for (const attr of Array.from(el.attributes)) el.removeAttribute(attr.name);
|
|
7237
|
-
if (textAlign)
|
|
8824
|
+
if (textAlign) htmlEl.style.textAlign = textAlign;
|
|
8825
|
+
if (fontWeight) htmlEl.style.fontWeight = fontWeight;
|
|
8826
|
+
if (fontStyle) htmlEl.style.fontStyle = fontStyle;
|
|
8827
|
+
if (textDecorationLine) htmlEl.style.textDecorationLine = textDecorationLine;
|
|
7238
8828
|
walk(el);
|
|
7239
8829
|
}
|
|
7240
8830
|
}
|
|
@@ -7277,7 +8867,8 @@ function EditGlowChrome({
|
|
|
7277
8867
|
rect,
|
|
7278
8868
|
elRef,
|
|
7279
8869
|
reorderHrefKey,
|
|
7280
|
-
dragDisabled = false
|
|
8870
|
+
dragDisabled = false,
|
|
8871
|
+
hideHandle = false
|
|
7281
8872
|
}) {
|
|
7282
8873
|
const GAP = SELECTION_CHROME_GAP2;
|
|
7283
8874
|
return /* @__PURE__ */ jsxs14(
|
|
@@ -7295,7 +8886,7 @@ function EditGlowChrome({
|
|
|
7295
8886
|
zIndex: 2147483646
|
|
7296
8887
|
},
|
|
7297
8888
|
children: [
|
|
7298
|
-
/* @__PURE__ */
|
|
8889
|
+
/* @__PURE__ */ jsx25(
|
|
7299
8890
|
"div",
|
|
7300
8891
|
{
|
|
7301
8892
|
style: {
|
|
@@ -7308,7 +8899,7 @@ function EditGlowChrome({
|
|
|
7308
8899
|
}
|
|
7309
8900
|
}
|
|
7310
8901
|
),
|
|
7311
|
-
reorderHrefKey && /* @__PURE__ */
|
|
8902
|
+
reorderHrefKey && !hideHandle && /* @__PURE__ */ jsx25(
|
|
7312
8903
|
"div",
|
|
7313
8904
|
{
|
|
7314
8905
|
"data-ohw-drag-handle-container": "",
|
|
@@ -7320,7 +8911,7 @@ function EditGlowChrome({
|
|
|
7320
8911
|
transform: "translate(calc(-100% - 7px), -50%)",
|
|
7321
8912
|
pointerEvents: dragDisabled ? "none" : "auto"
|
|
7322
8913
|
},
|
|
7323
|
-
children: /* @__PURE__ */
|
|
8914
|
+
children: /* @__PURE__ */ jsx25(
|
|
7324
8915
|
DragHandle,
|
|
7325
8916
|
{
|
|
7326
8917
|
"aria-label": `Reorder ${reorderHrefKey}`,
|
|
@@ -7421,6 +9012,79 @@ function resolveItemInteractionState(rect, parentScroll) {
|
|
|
7421
9012
|
const { transform } = calcToolbarPos(rect, parentScroll, 120);
|
|
7422
9013
|
return transform.includes("translateY(-100%)") ? "active-top" : "active-bottom";
|
|
7423
9014
|
}
|
|
9015
|
+
function resolveSelectionStartElement(sel) {
|
|
9016
|
+
if (!sel || sel.rangeCount === 0) return null;
|
|
9017
|
+
const range = sel.getRangeAt(0);
|
|
9018
|
+
let startNode = range.startContainer;
|
|
9019
|
+
if (startNode.nodeType === Node.ELEMENT_NODE) {
|
|
9020
|
+
const el = startNode;
|
|
9021
|
+
startNode = el.childNodes[range.startOffset] ?? el.childNodes[range.startOffset - 1] ?? el;
|
|
9022
|
+
}
|
|
9023
|
+
return startNode.nodeType === Node.TEXT_NODE ? startNode.parentElement : startNode;
|
|
9024
|
+
}
|
|
9025
|
+
function detectActiveFormats(startEl, activeRoot) {
|
|
9026
|
+
const formats = /* @__PURE__ */ new Set();
|
|
9027
|
+
const cs = getComputedStyle(startEl);
|
|
9028
|
+
const weight = parseInt(cs.fontWeight, 10);
|
|
9029
|
+
let hasBold = cs.fontWeight === "bold" || !Number.isNaN(weight) && weight >= 600;
|
|
9030
|
+
let hasItalic = cs.fontStyle === "italic" || cs.fontStyle === "oblique";
|
|
9031
|
+
let hasUnderline = false;
|
|
9032
|
+
let hasStrike = false;
|
|
9033
|
+
let hasUl = false;
|
|
9034
|
+
let hasOl = false;
|
|
9035
|
+
for (let el = startEl; el; el = el.parentElement) {
|
|
9036
|
+
if (el.tagName === "B" || el.tagName === "STRONG") hasBold = true;
|
|
9037
|
+
if (el.tagName === "I" || el.tagName === "EM") hasItalic = true;
|
|
9038
|
+
const decoration = getComputedStyle(el).textDecorationLine;
|
|
9039
|
+
if (decoration.includes("underline") || el.tagName === "U" || el.tagName === "INS") hasUnderline = true;
|
|
9040
|
+
if (decoration.includes("line-through") || el.tagName === "S" || el.tagName === "STRIKE" || el.tagName === "DEL") hasStrike = true;
|
|
9041
|
+
if (el.tagName === "UL") hasUl = true;
|
|
9042
|
+
if (el.tagName === "OL") hasOl = true;
|
|
9043
|
+
if (el === activeRoot) break;
|
|
9044
|
+
}
|
|
9045
|
+
if (hasBold) formats.add("bold");
|
|
9046
|
+
if (hasItalic) formats.add("italic");
|
|
9047
|
+
if (hasUnderline) formats.add("underline");
|
|
9048
|
+
if (hasStrike) formats.add("strikeThrough");
|
|
9049
|
+
if (hasUl) formats.add("insertUnorderedList");
|
|
9050
|
+
if (hasOl) formats.add("insertOrderedList");
|
|
9051
|
+
const block = startEl.closest("div, p, h1, h2, h3, h4, h5, h6, li, td, th") ?? startEl;
|
|
9052
|
+
const align = getComputedStyle(block).textAlign;
|
|
9053
|
+
if (align === "center") formats.add("justifyCenter");
|
|
9054
|
+
else if (align === "right" || align === "end") formats.add("justifyRight");
|
|
9055
|
+
else formats.add("justifyLeft");
|
|
9056
|
+
return formats;
|
|
9057
|
+
}
|
|
9058
|
+
function setsEqual(a, b) {
|
|
9059
|
+
if (a.size !== b.size) return false;
|
|
9060
|
+
for (const item of a) {
|
|
9061
|
+
if (!b.has(item)) return false;
|
|
9062
|
+
}
|
|
9063
|
+
return true;
|
|
9064
|
+
}
|
|
9065
|
+
function textOffsetInRoot(root, node, offset) {
|
|
9066
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
|
|
9067
|
+
let total = 0;
|
|
9068
|
+
let current;
|
|
9069
|
+
while (current = walker.nextNode()) {
|
|
9070
|
+
if (current === node) return total + offset;
|
|
9071
|
+
total += (current.textContent ?? "").length;
|
|
9072
|
+
}
|
|
9073
|
+
return total;
|
|
9074
|
+
}
|
|
9075
|
+
function pointAtTextOffset(root, targetOffset) {
|
|
9076
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
|
|
9077
|
+
let total = 0;
|
|
9078
|
+
let current;
|
|
9079
|
+
let last = null;
|
|
9080
|
+
while (current = walker.nextNode()) {
|
|
9081
|
+
const len = (current.textContent ?? "").length;
|
|
9082
|
+
if (total + len >= targetOffset) return { node: current, offset: targetOffset - total };
|
|
9083
|
+
total += len;
|
|
9084
|
+
last = current;
|
|
9085
|
+
}
|
|
9086
|
+
return last ? { node: last, offset: (last.textContent ?? "").length } : null;
|
|
9087
|
+
}
|
|
7424
9088
|
function FloatingToolbar({
|
|
7425
9089
|
rect,
|
|
7426
9090
|
parentScroll,
|
|
@@ -7430,9 +9094,9 @@ function FloatingToolbar({
|
|
|
7430
9094
|
showEditLink,
|
|
7431
9095
|
onEditLink
|
|
7432
9096
|
}) {
|
|
7433
|
-
const localRef =
|
|
7434
|
-
const [measuredW, setMeasuredW] =
|
|
7435
|
-
const setRefs =
|
|
9097
|
+
const localRef = React11.useRef(null);
|
|
9098
|
+
const [measuredW, setMeasuredW] = React11.useState(330);
|
|
9099
|
+
const setRefs = React11.useCallback(
|
|
7436
9100
|
(node) => {
|
|
7437
9101
|
localRef.current = node;
|
|
7438
9102
|
if (typeof elRef === "function") elRef(node);
|
|
@@ -7444,7 +9108,7 @@ function FloatingToolbar({
|
|
|
7444
9108
|
},
|
|
7445
9109
|
[elRef]
|
|
7446
9110
|
);
|
|
7447
|
-
|
|
9111
|
+
React11.useLayoutEffect(() => {
|
|
7448
9112
|
const node = localRef.current;
|
|
7449
9113
|
if (!node) return;
|
|
7450
9114
|
const update = () => {
|
|
@@ -7457,7 +9121,7 @@ function FloatingToolbar({
|
|
|
7457
9121
|
return () => ro.disconnect();
|
|
7458
9122
|
}, [showEditLink, activeCommands]);
|
|
7459
9123
|
const { top, left, transform } = calcToolbarPos(rect, parentScroll, measuredW);
|
|
7460
|
-
return /* @__PURE__ */
|
|
9124
|
+
return /* @__PURE__ */ jsx25(
|
|
7461
9125
|
"div",
|
|
7462
9126
|
{
|
|
7463
9127
|
ref: setRefs,
|
|
@@ -7470,11 +9134,11 @@ function FloatingToolbar({
|
|
|
7470
9134
|
pointerEvents: "auto"
|
|
7471
9135
|
},
|
|
7472
9136
|
children: /* @__PURE__ */ jsxs14(CustomToolbar, { children: [
|
|
7473
|
-
TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs14(
|
|
7474
|
-
gi > 0 && /* @__PURE__ */
|
|
9137
|
+
TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs14(React11.Fragment, { children: [
|
|
9138
|
+
gi > 0 && /* @__PURE__ */ jsx25(CustomToolbarDivider, {}),
|
|
7475
9139
|
btns.map((btn) => {
|
|
7476
9140
|
const isActive = activeCommands.has(btn.cmd);
|
|
7477
|
-
return /* @__PURE__ */
|
|
9141
|
+
return /* @__PURE__ */ jsx25(
|
|
7478
9142
|
CustomToolbarButton,
|
|
7479
9143
|
{
|
|
7480
9144
|
title: btn.title,
|
|
@@ -7483,7 +9147,7 @@ function FloatingToolbar({
|
|
|
7483
9147
|
e.preventDefault();
|
|
7484
9148
|
onCommand(btn.cmd);
|
|
7485
9149
|
},
|
|
7486
|
-
children: /* @__PURE__ */
|
|
9150
|
+
children: /* @__PURE__ */ jsx25(
|
|
7487
9151
|
"svg",
|
|
7488
9152
|
{
|
|
7489
9153
|
width: "16",
|
|
@@ -7504,7 +9168,7 @@ function FloatingToolbar({
|
|
|
7504
9168
|
);
|
|
7505
9169
|
})
|
|
7506
9170
|
] }, gi)),
|
|
7507
|
-
showEditLink ? /* @__PURE__ */
|
|
9171
|
+
showEditLink ? /* @__PURE__ */ jsx25(
|
|
7508
9172
|
CustomToolbarButton,
|
|
7509
9173
|
{
|
|
7510
9174
|
type: "button",
|
|
@@ -7518,7 +9182,7 @@ function FloatingToolbar({
|
|
|
7518
9182
|
e.preventDefault();
|
|
7519
9183
|
e.stopPropagation();
|
|
7520
9184
|
},
|
|
7521
|
-
children: /* @__PURE__ */
|
|
9185
|
+
children: /* @__PURE__ */ jsx25(Link2, { className: "size-4 shrink-0", "aria-hidden": true })
|
|
7522
9186
|
}
|
|
7523
9187
|
) : null
|
|
7524
9188
|
] })
|
|
@@ -7535,7 +9199,7 @@ function StateToggle({
|
|
|
7535
9199
|
states,
|
|
7536
9200
|
onStateChange
|
|
7537
9201
|
}) {
|
|
7538
|
-
return /* @__PURE__ */
|
|
9202
|
+
return /* @__PURE__ */ jsx25(
|
|
7539
9203
|
ToggleGroup,
|
|
7540
9204
|
{
|
|
7541
9205
|
"data-ohw-state-toggle": "",
|
|
@@ -7549,7 +9213,7 @@ function StateToggle({
|
|
|
7549
9213
|
left: rect.right - 8,
|
|
7550
9214
|
transform: "translateX(-100%)"
|
|
7551
9215
|
},
|
|
7552
|
-
children: states.map((state) => /* @__PURE__ */
|
|
9216
|
+
children: states.map((state) => /* @__PURE__ */ jsx25(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
|
|
7553
9217
|
}
|
|
7554
9218
|
);
|
|
7555
9219
|
}
|
|
@@ -7576,8 +9240,8 @@ function OhhwellsBridge() {
|
|
|
7576
9240
|
const router = useRouter2();
|
|
7577
9241
|
const searchParams = useSearchParams();
|
|
7578
9242
|
const isEditMode = isEditSessionActive();
|
|
7579
|
-
const [bridgeRoot, setBridgeRoot] =
|
|
7580
|
-
|
|
9243
|
+
const [bridgeRoot, setBridgeRoot] = useState7(null);
|
|
9244
|
+
useEffect8(() => {
|
|
7581
9245
|
const figtreeFontId = "ohw-figtree-font";
|
|
7582
9246
|
if (!document.getElementById(figtreeFontId)) {
|
|
7583
9247
|
const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
|
|
@@ -7605,92 +9269,137 @@ function OhhwellsBridge() {
|
|
|
7605
9269
|
const subdomainFromQuery = searchParams.get("subdomain");
|
|
7606
9270
|
const subdomain = resolveSubdomain(subdomainFromQuery);
|
|
7607
9271
|
useLinkHrefGuardian(pathname, subdomain, isEditMode);
|
|
7608
|
-
const postToParent2 =
|
|
9272
|
+
const postToParent2 = useCallback5((data) => {
|
|
7609
9273
|
if (typeof window !== "undefined" && window.parent !== window) {
|
|
7610
9274
|
window.parent.postMessage(data, "*");
|
|
7611
9275
|
}
|
|
7612
9276
|
}, []);
|
|
7613
|
-
const [fetchState, setFetchState] =
|
|
7614
|
-
const autoSaveTimers =
|
|
7615
|
-
const activeElRef =
|
|
7616
|
-
const
|
|
7617
|
-
const
|
|
7618
|
-
const
|
|
7619
|
-
const
|
|
7620
|
-
const
|
|
7621
|
-
const
|
|
7622
|
-
const
|
|
9277
|
+
const [fetchState, setFetchState] = useState7("idle");
|
|
9278
|
+
const autoSaveTimers = useRef7(/* @__PURE__ */ new Map());
|
|
9279
|
+
const activeElRef = useRef7(null);
|
|
9280
|
+
const pointerHeldRef = useRef7(false);
|
|
9281
|
+
const selectedElRef = useRef7(null);
|
|
9282
|
+
const selectedHrefKeyRef = useRef7(null);
|
|
9283
|
+
const selectedFooterColAttrRef = useRef7(null);
|
|
9284
|
+
const originalContentRef = useRef7(null);
|
|
9285
|
+
const activeStateElRef = useRef7(null);
|
|
9286
|
+
const parentScrollRef = useRef7(null);
|
|
9287
|
+
const visibleViewportRef = useRef7(null);
|
|
9288
|
+
const [dialogPortalContainer, setDialogPortalContainer] = useState7(null);
|
|
9289
|
+
const attachVisibleViewport = useCallback5((node) => {
|
|
7623
9290
|
visibleViewportRef.current = node;
|
|
7624
9291
|
setDialogPortalContainer(node);
|
|
7625
9292
|
if (node) applyVisibleViewport(node, parentScrollRef.current);
|
|
7626
9293
|
}, []);
|
|
7627
|
-
const toolbarElRef =
|
|
7628
|
-
const glowElRef =
|
|
7629
|
-
const hoveredImageRef =
|
|
7630
|
-
const hoveredImageHasTextOverlapRef =
|
|
7631
|
-
const dragOverElRef =
|
|
7632
|
-
const [mediaHover, setMediaHover] =
|
|
7633
|
-
const [uploadingRects, setUploadingRects] =
|
|
7634
|
-
const hoveredGapRef =
|
|
7635
|
-
const imageUnhoverTimerRef =
|
|
7636
|
-
const imageShowTimerRef =
|
|
7637
|
-
const editStylesRef =
|
|
7638
|
-
const activateRef =
|
|
9294
|
+
const toolbarElRef = useRef7(null);
|
|
9295
|
+
const glowElRef = useRef7(null);
|
|
9296
|
+
const hoveredImageRef = useRef7(null);
|
|
9297
|
+
const hoveredImageHasTextOverlapRef = useRef7(false);
|
|
9298
|
+
const dragOverElRef = useRef7(null);
|
|
9299
|
+
const [mediaHover, setMediaHover] = useState7(null);
|
|
9300
|
+
const [uploadingRects, setUploadingRects] = useState7({});
|
|
9301
|
+
const hoveredGapRef = useRef7(null);
|
|
9302
|
+
const imageUnhoverTimerRef = useRef7(null);
|
|
9303
|
+
const imageShowTimerRef = useRef7(null);
|
|
9304
|
+
const editStylesRef = useRef7(null);
|
|
9305
|
+
const activateRef = useRef7(() => {
|
|
7639
9306
|
});
|
|
7640
|
-
const deactivateRef =
|
|
9307
|
+
const deactivateRef = useRef7(() => {
|
|
7641
9308
|
});
|
|
7642
|
-
const selectRef =
|
|
9309
|
+
const selectRef = useRef7(() => {
|
|
7643
9310
|
});
|
|
7644
|
-
const selectFrameRef =
|
|
9311
|
+
const selectFrameRef = useRef7(() => {
|
|
7645
9312
|
});
|
|
7646
|
-
const deselectRef =
|
|
9313
|
+
const deselectRef = useRef7(() => {
|
|
7647
9314
|
});
|
|
7648
|
-
const reselectNavigationItemRef =
|
|
9315
|
+
const reselectNavigationItemRef = useRef7(() => {
|
|
7649
9316
|
});
|
|
7650
|
-
const commitNavigationTextEditRef =
|
|
9317
|
+
const commitNavigationTextEditRef = useRef7(() => {
|
|
7651
9318
|
});
|
|
7652
|
-
const refreshActiveCommandsRef =
|
|
9319
|
+
const refreshActiveCommandsRef = useRef7(() => {
|
|
7653
9320
|
});
|
|
7654
|
-
const postToParentRef =
|
|
9321
|
+
const postToParentRef = useRef7(postToParent2);
|
|
7655
9322
|
postToParentRef.current = postToParent2;
|
|
7656
|
-
const sectionsLoadedRef =
|
|
7657
|
-
const pendingScheduleConfigRequests =
|
|
7658
|
-
const [toolbarRect, setToolbarRect] =
|
|
7659
|
-
const [toolbarVariant, setToolbarVariant] =
|
|
7660
|
-
const toolbarVariantRef =
|
|
9323
|
+
const sectionsLoadedRef = useRef7(false);
|
|
9324
|
+
const pendingScheduleConfigRequests = useRef7([]);
|
|
9325
|
+
const [toolbarRect, setToolbarRect] = useState7(null);
|
|
9326
|
+
const [toolbarVariant, setToolbarVariant] = useState7("none");
|
|
9327
|
+
const toolbarVariantRef = useRef7("none");
|
|
7661
9328
|
toolbarVariantRef.current = toolbarVariant;
|
|
7662
|
-
const [selectedIsCta, setSelectedIsCta] =
|
|
7663
|
-
const [reorderHrefKey, setReorderHrefKey] =
|
|
7664
|
-
const [reorderDragDisabled, setReorderDragDisabled] =
|
|
7665
|
-
const [toggleState, setToggleState] =
|
|
7666
|
-
const [maxBadge, setMaxBadge] =
|
|
7667
|
-
const [activeCommands, setActiveCommands] =
|
|
7668
|
-
const [sectionGap, setSectionGap] =
|
|
7669
|
-
const [toolbarShowEditLink, setToolbarShowEditLink] =
|
|
7670
|
-
const hoveredNavContainerRef =
|
|
7671
|
-
const [hoveredNavContainerRect, setHoveredNavContainerRect] =
|
|
7672
|
-
const hoveredItemElRef =
|
|
7673
|
-
const [hoveredItemRect, setHoveredItemRect] =
|
|
7674
|
-
const siblingHintElRef =
|
|
7675
|
-
const [siblingHintRect, setSiblingHintRect] =
|
|
7676
|
-
const [
|
|
7677
|
-
const [
|
|
7678
|
-
const
|
|
7679
|
-
const
|
|
7680
|
-
const
|
|
7681
|
-
const [
|
|
7682
|
-
const [
|
|
7683
|
-
const
|
|
7684
|
-
const
|
|
7685
|
-
const
|
|
7686
|
-
const
|
|
7687
|
-
const
|
|
9329
|
+
const [selectedIsCta, setSelectedIsCta] = useState7(false);
|
|
9330
|
+
const [reorderHrefKey, setReorderHrefKey] = useState7(null);
|
|
9331
|
+
const [reorderDragDisabled, setReorderDragDisabled] = useState7(false);
|
|
9332
|
+
const [toggleState, setToggleState] = useState7(null);
|
|
9333
|
+
const [maxBadge, setMaxBadge] = useState7(null);
|
|
9334
|
+
const [activeCommands, setActiveCommands] = useState7(/* @__PURE__ */ new Set());
|
|
9335
|
+
const [sectionGap, setSectionGap] = useState7(null);
|
|
9336
|
+
const [toolbarShowEditLink, setToolbarShowEditLink] = useState7(false);
|
|
9337
|
+
const hoveredNavContainerRef = useRef7(null);
|
|
9338
|
+
const [hoveredNavContainerRect, setHoveredNavContainerRect] = useState7(null);
|
|
9339
|
+
const hoveredItemElRef = useRef7(null);
|
|
9340
|
+
const [hoveredItemRect, setHoveredItemRect] = useState7(null);
|
|
9341
|
+
const siblingHintElRef = useRef7(null);
|
|
9342
|
+
const [siblingHintRect, setSiblingHintRect] = useState7(null);
|
|
9343
|
+
const [siblingHintRects, setSiblingHintRects] = useState7([]);
|
|
9344
|
+
const [isItemDragging, setIsItemDragging] = useState7(false);
|
|
9345
|
+
const [isFooterFrameSelection, setIsFooterFrameSelection] = useState7(false);
|
|
9346
|
+
const footerDragRef = useRef7(null);
|
|
9347
|
+
const [footerDropSlots, setFooterDropSlots] = useState7([]);
|
|
9348
|
+
const [activeFooterDropIndex, setActiveFooterDropIndex] = useState7(null);
|
|
9349
|
+
const [draggedItemRect, setDraggedItemRect] = useState7(null);
|
|
9350
|
+
const footerPointerDragRef = useRef7(null);
|
|
9351
|
+
const suppressNextClickRef = useRef7(false);
|
|
9352
|
+
const suppressClickUntilRef = useRef7(0);
|
|
9353
|
+
const [linkPopover, setLinkPopover] = useState7(null);
|
|
9354
|
+
const linkPopoverSessionRef = useRef7(null);
|
|
9355
|
+
const addNavAfterAnchorRef = useRef7(null);
|
|
9356
|
+
const editContentRef = useRef7({});
|
|
9357
|
+
const [sitePages, setSitePages] = useState7([]);
|
|
9358
|
+
const [sectionsByPath, setSectionsByPath] = useState7({});
|
|
9359
|
+
const sectionsPrefetchGenRef = useRef7(0);
|
|
9360
|
+
const setLinkPopoverRef = useRef7(setLinkPopover);
|
|
9361
|
+
const linkPopoverPanelRef = useRef7(null);
|
|
9362
|
+
const linkPopoverOpenRef = useRef7(false);
|
|
9363
|
+
const linkPopoverGraceUntilRef = useRef7(0);
|
|
7688
9364
|
setLinkPopoverRef.current = setLinkPopover;
|
|
7689
9365
|
linkPopoverSessionRef.current = linkPopover;
|
|
9366
|
+
const {
|
|
9367
|
+
navDragRef,
|
|
9368
|
+
navDropSlots,
|
|
9369
|
+
activeNavDropIndex,
|
|
9370
|
+
startNavLinkDrag,
|
|
9371
|
+
commitNavDrag,
|
|
9372
|
+
onNavDragOver,
|
|
9373
|
+
armNavPressFromChrome,
|
|
9374
|
+
refreshNavDragVisualsRef
|
|
9375
|
+
} = useNavItemDrag({
|
|
9376
|
+
isEditMode,
|
|
9377
|
+
editContentRef,
|
|
9378
|
+
selectedElRef,
|
|
9379
|
+
activeElRef,
|
|
9380
|
+
footerDragRef,
|
|
9381
|
+
suppressNextClickRef,
|
|
9382
|
+
suppressClickUntilRef,
|
|
9383
|
+
siblingHintElRef,
|
|
9384
|
+
postToParentRef,
|
|
9385
|
+
deselectRef,
|
|
9386
|
+
selectRef,
|
|
9387
|
+
deactivateRef,
|
|
9388
|
+
setLinkPopover: () => setLinkPopover(null),
|
|
9389
|
+
linkPopoverOpenRef,
|
|
9390
|
+
setIsItemDragging,
|
|
9391
|
+
setDraggedItemRect,
|
|
9392
|
+
setSiblingHintRect,
|
|
9393
|
+
setSiblingHintRects,
|
|
9394
|
+
setToolbarRect,
|
|
9395
|
+
getNavigationItemAnchor,
|
|
9396
|
+
isDragHandleDisabled,
|
|
9397
|
+
isNavbarButton: isNavbarButton2
|
|
9398
|
+
});
|
|
7690
9399
|
const bumpLinkPopoverGrace = () => {
|
|
7691
9400
|
linkPopoverGraceUntilRef.current = Date.now() + 350;
|
|
7692
9401
|
};
|
|
7693
|
-
const runSectionsPrefetch =
|
|
9402
|
+
const runSectionsPrefetch = useCallback5((pages) => {
|
|
7694
9403
|
if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
|
|
7695
9404
|
const gen = ++sectionsPrefetchGenRef.current;
|
|
7696
9405
|
const paths = pages.map((p) => p.path);
|
|
@@ -7709,10 +9418,24 @@ function OhhwellsBridge() {
|
|
|
7709
9418
|
);
|
|
7710
9419
|
});
|
|
7711
9420
|
}, [isEditMode, pathname]);
|
|
7712
|
-
const runSectionsPrefetchRef =
|
|
9421
|
+
const runSectionsPrefetchRef = useRef7(runSectionsPrefetch);
|
|
7713
9422
|
runSectionsPrefetchRef.current = runSectionsPrefetch;
|
|
7714
|
-
|
|
7715
|
-
if (!linkPopover)
|
|
9423
|
+
useEffect8(() => {
|
|
9424
|
+
if (!linkPopover) {
|
|
9425
|
+
document.documentElement.removeAttribute("data-ohw-link-popover-open");
|
|
9426
|
+
return;
|
|
9427
|
+
}
|
|
9428
|
+
document.documentElement.setAttribute("data-ohw-link-popover-open", "");
|
|
9429
|
+
hoveredItemElRef.current = null;
|
|
9430
|
+
setHoveredItemRect(null);
|
|
9431
|
+
hoveredNavContainerRef.current = null;
|
|
9432
|
+
setHoveredNavContainerRect(null);
|
|
9433
|
+
siblingHintElRef.current = null;
|
|
9434
|
+
setSiblingHintRect(null);
|
|
9435
|
+
setSiblingHintRects([]);
|
|
9436
|
+
if (selectedElRef.current || toolbarVariantRef.current !== "none") {
|
|
9437
|
+
deselectRef.current();
|
|
9438
|
+
}
|
|
7716
9439
|
if (hoveredImageRef.current) {
|
|
7717
9440
|
hoveredImageRef.current = null;
|
|
7718
9441
|
hoveredImageHasTextOverlapRef.current = false;
|
|
@@ -7739,6 +9462,7 @@ function OhhwellsBridge() {
|
|
|
7739
9462
|
document.addEventListener("touchmove", preventBackgroundScroll, scrollOpts);
|
|
7740
9463
|
postToParent2({ type: "ow:image-unhover" });
|
|
7741
9464
|
return () => {
|
|
9465
|
+
document.documentElement.removeAttribute("data-ohw-link-popover-open");
|
|
7742
9466
|
postToParent2({ type: "ow:link-modal-lock", locked: false });
|
|
7743
9467
|
html.style.overflow = prevHtmlOverflow;
|
|
7744
9468
|
body.style.overflow = prevBodyOverflow;
|
|
@@ -7746,7 +9470,7 @@ function OhhwellsBridge() {
|
|
|
7746
9470
|
document.removeEventListener("touchmove", preventBackgroundScroll, scrollOpts);
|
|
7747
9471
|
};
|
|
7748
9472
|
}, [linkPopover, postToParent2]);
|
|
7749
|
-
|
|
9473
|
+
useEffect8(() => {
|
|
7750
9474
|
if (!isEditMode) return;
|
|
7751
9475
|
const useFixtures = shouldUseDevFixtures();
|
|
7752
9476
|
if (useFixtures) {
|
|
@@ -7770,14 +9494,14 @@ function OhhwellsBridge() {
|
|
|
7770
9494
|
if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
|
|
7771
9495
|
return () => window.removeEventListener("message", onSitePages);
|
|
7772
9496
|
}, [isEditMode, postToParent2]);
|
|
7773
|
-
|
|
9497
|
+
useEffect8(() => {
|
|
7774
9498
|
if (!isEditMode || shouldUseDevFixtures()) return;
|
|
7775
9499
|
void loadAllSectionsManifest().then((manifest) => {
|
|
7776
9500
|
if (Object.keys(manifest).length === 0) return;
|
|
7777
9501
|
setSectionsByPath((prev) => ({ ...manifest, ...prev }));
|
|
7778
9502
|
});
|
|
7779
9503
|
}, [isEditMode]);
|
|
7780
|
-
|
|
9504
|
+
useEffect8(() => {
|
|
7781
9505
|
const update = () => {
|
|
7782
9506
|
const el = activeElRef.current ?? selectedElRef.current;
|
|
7783
9507
|
if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
|
|
@@ -7801,10 +9525,10 @@ function OhhwellsBridge() {
|
|
|
7801
9525
|
vvp.removeEventListener("resize", update);
|
|
7802
9526
|
};
|
|
7803
9527
|
}, []);
|
|
7804
|
-
const refreshStateRules =
|
|
9528
|
+
const refreshStateRules = useCallback5(() => {
|
|
7805
9529
|
editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
|
|
7806
9530
|
}, []);
|
|
7807
|
-
const processConfigRequest =
|
|
9531
|
+
const processConfigRequest = useCallback5((insertAfterVal) => {
|
|
7808
9532
|
const tracker = getSectionsTracker();
|
|
7809
9533
|
let entries = [];
|
|
7810
9534
|
try {
|
|
@@ -7827,7 +9551,7 @@ function OhhwellsBridge() {
|
|
|
7827
9551
|
}
|
|
7828
9552
|
window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
|
|
7829
9553
|
}, [isEditMode]);
|
|
7830
|
-
const deactivate =
|
|
9554
|
+
const deactivate = useCallback5(() => {
|
|
7831
9555
|
const el = activeElRef.current;
|
|
7832
9556
|
if (!el) return;
|
|
7833
9557
|
const key = el.dataset.ohwKey;
|
|
@@ -7859,19 +9583,23 @@ function OhhwellsBridge() {
|
|
|
7859
9583
|
setToolbarShowEditLink(false);
|
|
7860
9584
|
postToParent2({ type: "ow:exit-edit" });
|
|
7861
9585
|
}, [postToParent2]);
|
|
7862
|
-
const clearSelectedAttr =
|
|
9586
|
+
const clearSelectedAttr = useCallback5(() => {
|
|
7863
9587
|
document.querySelectorAll("[data-ohw-selected]").forEach((el) => {
|
|
7864
9588
|
el.removeAttribute("data-ohw-selected");
|
|
7865
9589
|
});
|
|
7866
9590
|
}, []);
|
|
7867
|
-
const deselect =
|
|
9591
|
+
const deselect = useCallback5(() => {
|
|
7868
9592
|
clearSelectedAttr();
|
|
7869
9593
|
selectedElRef.current = null;
|
|
9594
|
+
selectedHrefKeyRef.current = null;
|
|
9595
|
+
selectedFooterColAttrRef.current = null;
|
|
7870
9596
|
setSelectedIsCta(false);
|
|
7871
9597
|
setReorderHrefKey(null);
|
|
7872
9598
|
setReorderDragDisabled(false);
|
|
9599
|
+
setIsFooterFrameSelection(false);
|
|
7873
9600
|
siblingHintElRef.current = null;
|
|
7874
9601
|
setSiblingHintRect(null);
|
|
9602
|
+
setSiblingHintRects([]);
|
|
7875
9603
|
setIsItemDragging(false);
|
|
7876
9604
|
hoveredNavContainerRef.current = null;
|
|
7877
9605
|
setHoveredNavContainerRect(null);
|
|
@@ -7880,12 +9608,57 @@ function OhhwellsBridge() {
|
|
|
7880
9608
|
setToolbarVariant("none");
|
|
7881
9609
|
}
|
|
7882
9610
|
}, [clearSelectedAttr]);
|
|
7883
|
-
const markSelected =
|
|
9611
|
+
const markSelected = useCallback5((el) => {
|
|
7884
9612
|
clearSelectedAttr();
|
|
7885
9613
|
el.setAttribute("data-ohw-selected", "");
|
|
7886
9614
|
}, [clearSelectedAttr]);
|
|
7887
|
-
const
|
|
9615
|
+
const resolveHrefKeyElement = useCallback5((hrefKey) => {
|
|
9616
|
+
if (isFooterHrefKey(hrefKey)) {
|
|
9617
|
+
return document.querySelector(
|
|
9618
|
+
`footer [data-ohw-href-key="${CSS.escape(hrefKey)}"]`
|
|
9619
|
+
);
|
|
9620
|
+
}
|
|
9621
|
+
if (isNavbarHrefKey(hrefKey)) {
|
|
9622
|
+
const desktop = document.querySelector("[data-ohw-nav-container]");
|
|
9623
|
+
const drawer = document.querySelector("[data-ohw-nav-drawer]");
|
|
9624
|
+
return desktop?.querySelector(`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`) ?? drawer?.querySelector(`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`) ?? document.querySelector(`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`);
|
|
9625
|
+
}
|
|
9626
|
+
return document.querySelector(
|
|
9627
|
+
`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`
|
|
9628
|
+
);
|
|
9629
|
+
}, []);
|
|
9630
|
+
const resyncSelectedNavigationItem = useCallback5(() => {
|
|
9631
|
+
const hrefKey = selectedHrefKeyRef.current;
|
|
9632
|
+
if (hrefKey) {
|
|
9633
|
+
const link = resolveHrefKeyElement(hrefKey);
|
|
9634
|
+
if (!link || !isNavigationItem(link)) return;
|
|
9635
|
+
selectedElRef.current = link;
|
|
9636
|
+
const { key, disabled } = getNavigationItemReorderState(link);
|
|
9637
|
+
setReorderHrefKey(key);
|
|
9638
|
+
setReorderDragDisabled(disabled);
|
|
9639
|
+
setIsFooterFrameSelection(false);
|
|
9640
|
+
setToolbarVariant("link-action");
|
|
9641
|
+
setToolbarRect(link.getBoundingClientRect());
|
|
9642
|
+
setSiblingHintRects(collectNavigationItemSiblingHintRects(link));
|
|
9643
|
+
return;
|
|
9644
|
+
}
|
|
9645
|
+
const colAttr = selectedFooterColAttrRef.current;
|
|
9646
|
+
if (colAttr != null) {
|
|
9647
|
+
const column = document.querySelector(`[data-ohw-footer-col="${CSS.escape(colAttr)}"]`) ?? listFooterColumns()[Number(colAttr)] ?? null;
|
|
9648
|
+
if (!column || !isNavigationContainer(column)) return;
|
|
9649
|
+
selectedElRef.current = column;
|
|
9650
|
+
setIsFooterFrameSelection(true);
|
|
9651
|
+
setToolbarVariant("select-frame");
|
|
9652
|
+
setToolbarRect(column.getBoundingClientRect());
|
|
9653
|
+
setSiblingHintRects(
|
|
9654
|
+
listFooterColumns().filter((c) => c !== column).map((c) => c.getBoundingClientRect())
|
|
9655
|
+
);
|
|
9656
|
+
}
|
|
9657
|
+
}, [resolveHrefKeyElement]);
|
|
9658
|
+
const reselectNavigationItem = useCallback5((navAnchor) => {
|
|
7888
9659
|
selectedElRef.current = navAnchor;
|
|
9660
|
+
selectedHrefKeyRef.current = navAnchor.getAttribute("data-ohw-href-key");
|
|
9661
|
+
selectedFooterColAttrRef.current = null;
|
|
7889
9662
|
markSelected(navAnchor);
|
|
7890
9663
|
setSelectedIsCta(isNavbarButton2(navAnchor));
|
|
7891
9664
|
const { key, disabled } = getNavigationItemReorderState(navAnchor);
|
|
@@ -7893,10 +9666,11 @@ function OhhwellsBridge() {
|
|
|
7893
9666
|
setReorderDragDisabled(disabled);
|
|
7894
9667
|
setToolbarVariant("link-action");
|
|
7895
9668
|
setToolbarRect(navAnchor.getBoundingClientRect());
|
|
9669
|
+
setSiblingHintRects(collectNavigationItemSiblingHintRects(navAnchor));
|
|
7896
9670
|
setToolbarShowEditLink(false);
|
|
7897
9671
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
7898
9672
|
}, [markSelected]);
|
|
7899
|
-
const commitNavigationTextEdit =
|
|
9673
|
+
const commitNavigationTextEdit = useCallback5((navAnchor) => {
|
|
7900
9674
|
const el = activeElRef.current;
|
|
7901
9675
|
if (!el) return;
|
|
7902
9676
|
const key = el.dataset.ohwKey;
|
|
@@ -7923,7 +9697,7 @@ function OhhwellsBridge() {
|
|
|
7923
9697
|
postToParent2({ type: "ow:exit-edit" });
|
|
7924
9698
|
reselectNavigationItem(navAnchor);
|
|
7925
9699
|
}, [postToParent2, reselectNavigationItem]);
|
|
7926
|
-
const handleAddTopLevelNavItem =
|
|
9700
|
+
const handleAddTopLevelNavItem = useCallback5(() => {
|
|
7927
9701
|
const items = listNavbarItems();
|
|
7928
9702
|
addNavAfterAnchorRef.current = items[items.length - 1] ?? null;
|
|
7929
9703
|
deselectRef.current();
|
|
@@ -7935,20 +9709,319 @@ function OhhwellsBridge() {
|
|
|
7935
9709
|
intent: "add-nav"
|
|
7936
9710
|
});
|
|
7937
9711
|
}, []);
|
|
7938
|
-
const
|
|
7939
|
-
|
|
7940
|
-
|
|
7941
|
-
|
|
7942
|
-
|
|
7943
|
-
|
|
9712
|
+
const handleAddFooterColumn = useCallback5(() => {
|
|
9713
|
+
deselectRef.current();
|
|
9714
|
+
deactivateRef.current();
|
|
9715
|
+
const result = addFooterColumnWithPersist({ postToParent: postToParent2 });
|
|
9716
|
+
editContentRef.current = {
|
|
9717
|
+
...editContentRef.current,
|
|
9718
|
+
...buildFooterColumnEditContentPatch(result)
|
|
9719
|
+
};
|
|
9720
|
+
requestAnimationFrame(() => {
|
|
9721
|
+
selectRef.current(result.firstLink);
|
|
9722
|
+
});
|
|
9723
|
+
}, [postToParent2]);
|
|
9724
|
+
const clearFooterDragVisuals = useCallback5(() => {
|
|
9725
|
+
footerDragRef.current = null;
|
|
9726
|
+
setSiblingHintRects([]);
|
|
9727
|
+
setFooterDropSlots([]);
|
|
9728
|
+
setActiveFooterDropIndex(null);
|
|
9729
|
+
setDraggedItemRect(null);
|
|
7944
9730
|
setIsItemDragging(false);
|
|
9731
|
+
unlockFooterDragInteraction();
|
|
9732
|
+
}, []);
|
|
9733
|
+
const refreshFooterDragVisuals = useCallback5((session, activeSlot, clientX, clientY) => {
|
|
9734
|
+
const dragged = session.draggedEl;
|
|
9735
|
+
setDraggedItemRect(dragged.getBoundingClientRect());
|
|
9736
|
+
if (typeof clientX === "number" && typeof clientY === "number") {
|
|
9737
|
+
session.lastClientX = clientX;
|
|
9738
|
+
session.lastClientY = clientY;
|
|
9739
|
+
}
|
|
9740
|
+
session.activeSlot = activeSlot;
|
|
9741
|
+
setSiblingHintRects([]);
|
|
9742
|
+
if (session.kind === "link") {
|
|
9743
|
+
const columns = listFooterColumns();
|
|
9744
|
+
const slots2 = [];
|
|
9745
|
+
columns.forEach((col, i) => {
|
|
9746
|
+
slots2.push(...buildLinkDropSlots(col, i));
|
|
9747
|
+
});
|
|
9748
|
+
setFooterDropSlots(slots2);
|
|
9749
|
+
const activeIdx2 = activeSlot ? slots2.findIndex((s) => s.columnIndex === activeSlot.columnIndex && s.insertIndex === activeSlot.insertIndex) : -1;
|
|
9750
|
+
setActiveFooterDropIndex(activeIdx2 >= 0 ? activeIdx2 : null);
|
|
9751
|
+
return;
|
|
9752
|
+
}
|
|
9753
|
+
const slots = buildColumnDropSlots();
|
|
9754
|
+
setFooterDropSlots(slots);
|
|
9755
|
+
const activeIdx = activeSlot ? slots.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
|
|
9756
|
+
setActiveFooterDropIndex(activeIdx >= 0 ? activeIdx : null);
|
|
9757
|
+
}, []);
|
|
9758
|
+
const refreshFooterDragVisualsRef = useRef7(refreshFooterDragVisuals);
|
|
9759
|
+
refreshFooterDragVisualsRef.current = refreshFooterDragVisuals;
|
|
9760
|
+
const commitFooterDragRef = useRef7(() => {
|
|
9761
|
+
});
|
|
9762
|
+
const beginFooterDragRef = useRef7(() => {
|
|
9763
|
+
});
|
|
9764
|
+
const beginFooterDrag = useCallback5(
|
|
9765
|
+
(session) => {
|
|
9766
|
+
const rect = session.draggedEl.getBoundingClientRect();
|
|
9767
|
+
session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
|
|
9768
|
+
session.lastClientY = session.lastClientY || rect.top + rect.height / 2;
|
|
9769
|
+
session.activeSlot = session.activeSlot ?? null;
|
|
9770
|
+
footerDragRef.current = session;
|
|
9771
|
+
setIsItemDragging(true);
|
|
9772
|
+
lockFooterDuringDrag();
|
|
9773
|
+
siblingHintElRef.current = null;
|
|
9774
|
+
setSiblingHintRect(null);
|
|
9775
|
+
if (session.wasSelected && selectedElRef.current === session.draggedEl) {
|
|
9776
|
+
setToolbarRect(rect);
|
|
9777
|
+
}
|
|
9778
|
+
const initialSlot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : hitTestColumnDropSlot(session.lastClientX, session.lastClientY);
|
|
9779
|
+
refreshFooterDragVisuals(session, initialSlot, session.lastClientX, session.lastClientY);
|
|
9780
|
+
},
|
|
9781
|
+
[refreshFooterDragVisuals]
|
|
9782
|
+
);
|
|
9783
|
+
beginFooterDragRef.current = beginFooterDrag;
|
|
9784
|
+
const commitFooterDrag = useCallback5(
|
|
9785
|
+
(clientX, clientY) => {
|
|
9786
|
+
const session = footerDragRef.current;
|
|
9787
|
+
if (!session) {
|
|
9788
|
+
clearFooterDragVisuals();
|
|
9789
|
+
return;
|
|
9790
|
+
}
|
|
9791
|
+
const x = typeof clientX === "number" && (clientX !== 0 || clientY !== 0) ? clientX : session.lastClientX;
|
|
9792
|
+
const y = typeof clientY === "number" && (clientX !== 0 || clientY !== 0) ? clientY : session.lastClientY;
|
|
9793
|
+
let nextOrder = null;
|
|
9794
|
+
const slot = session.activeSlot ?? (session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(x, y, session.hrefKey) : session.kind === "column" ? hitTestColumnDropSlot(x, y) : null);
|
|
9795
|
+
if (session.kind === "link" && session.hrefKey && slot) {
|
|
9796
|
+
nextOrder = planFooterLinkMove(session.hrefKey, slot.columnIndex, slot.insertIndex);
|
|
9797
|
+
} else if (session.kind === "column" && slot) {
|
|
9798
|
+
nextOrder = planFooterColumnMove(session.sourceColumnIndex, slot.insertIndex);
|
|
9799
|
+
}
|
|
9800
|
+
const wasSelected = session.wasSelected;
|
|
9801
|
+
const draggedEl = session.draggedEl;
|
|
9802
|
+
const hrefKey = session.hrefKey;
|
|
9803
|
+
let movedColumnIndex = null;
|
|
9804
|
+
if (session.kind === "column" && slot && nextOrder) {
|
|
9805
|
+
let adjusted = slot.insertIndex;
|
|
9806
|
+
if (session.sourceColumnIndex < slot.insertIndex) adjusted -= 1;
|
|
9807
|
+
movedColumnIndex = Math.max(0, Math.min(adjusted, nextOrder.length - 1));
|
|
9808
|
+
}
|
|
9809
|
+
const applySelectionAfterDrop = () => {
|
|
9810
|
+
if (!wasSelected) {
|
|
9811
|
+
deselectRef.current();
|
|
9812
|
+
return;
|
|
9813
|
+
}
|
|
9814
|
+
if (hrefKey) {
|
|
9815
|
+
selectedHrefKeyRef.current = hrefKey;
|
|
9816
|
+
selectedFooterColAttrRef.current = null;
|
|
9817
|
+
const link = resolveHrefKeyElement(hrefKey);
|
|
9818
|
+
if (link && isNavigationItem(link)) {
|
|
9819
|
+
selectRef.current(link);
|
|
9820
|
+
return;
|
|
9821
|
+
}
|
|
9822
|
+
}
|
|
9823
|
+
if (movedColumnIndex !== null && nextOrder) {
|
|
9824
|
+
const colKeys = nextOrder[movedColumnIndex] ?? [];
|
|
9825
|
+
let column = null;
|
|
9826
|
+
for (const key of colKeys) {
|
|
9827
|
+
const link = document.querySelector(
|
|
9828
|
+
`footer [data-ohw-href-key="${CSS.escape(key)}"]`
|
|
9829
|
+
);
|
|
9830
|
+
if (link) {
|
|
9831
|
+
column = findFooterColumnForLink(link);
|
|
9832
|
+
if (column) break;
|
|
9833
|
+
}
|
|
9834
|
+
}
|
|
9835
|
+
if (!column) column = listFooterColumns()[movedColumnIndex] ?? null;
|
|
9836
|
+
if (column && isNavigationContainer(column)) {
|
|
9837
|
+
selectFrameRef.current(column);
|
|
9838
|
+
return;
|
|
9839
|
+
}
|
|
9840
|
+
}
|
|
9841
|
+
if (document.body.contains(draggedEl)) {
|
|
9842
|
+
if (isNavigationItem(draggedEl)) {
|
|
9843
|
+
selectRef.current(draggedEl);
|
|
9844
|
+
return;
|
|
9845
|
+
}
|
|
9846
|
+
if (isNavigationContainer(draggedEl)) {
|
|
9847
|
+
selectFrameRef.current(draggedEl);
|
|
9848
|
+
return;
|
|
9849
|
+
}
|
|
9850
|
+
}
|
|
9851
|
+
deselectRef.current();
|
|
9852
|
+
};
|
|
9853
|
+
if (nextOrder) {
|
|
9854
|
+
const orderJson = JSON.stringify(nextOrder);
|
|
9855
|
+
editContentRef.current = {
|
|
9856
|
+
...editContentRef.current,
|
|
9857
|
+
[FOOTER_ORDER_KEY]: orderJson
|
|
9858
|
+
};
|
|
9859
|
+
applyFooterOrder(nextOrder);
|
|
9860
|
+
document.querySelectorAll("footer [data-ohw-href-key]").forEach(disableNativeHrefDrag);
|
|
9861
|
+
postToParentRef.current({
|
|
9862
|
+
type: "ow:change",
|
|
9863
|
+
nodes: [{ key: FOOTER_ORDER_KEY, text: orderJson }]
|
|
9864
|
+
});
|
|
9865
|
+
applySelectionAfterDrop();
|
|
9866
|
+
clearFooterDragVisuals();
|
|
9867
|
+
requestAnimationFrame(() => {
|
|
9868
|
+
if (editContentRef.current[FOOTER_ORDER_KEY] === orderJson) {
|
|
9869
|
+
applyFooterOrder(nextOrder);
|
|
9870
|
+
document.querySelectorAll("footer [data-ohw-href-key]").forEach(disableNativeHrefDrag);
|
|
9871
|
+
}
|
|
9872
|
+
applySelectionAfterDrop();
|
|
9873
|
+
requestAnimationFrame(() => {
|
|
9874
|
+
if (editContentRef.current[FOOTER_ORDER_KEY] === orderJson) {
|
|
9875
|
+
applyFooterOrder(nextOrder);
|
|
9876
|
+
}
|
|
9877
|
+
resyncSelectedNavigationItem();
|
|
9878
|
+
});
|
|
9879
|
+
});
|
|
9880
|
+
return;
|
|
9881
|
+
}
|
|
9882
|
+
applySelectionAfterDrop();
|
|
9883
|
+
clearFooterDragVisuals();
|
|
9884
|
+
},
|
|
9885
|
+
[clearFooterDragVisuals, resolveHrefKeyElement, resyncSelectedNavigationItem]
|
|
9886
|
+
);
|
|
9887
|
+
commitFooterDragRef.current = commitFooterDrag;
|
|
9888
|
+
const startFooterLinkDrag = useCallback5(
|
|
9889
|
+
(anchor, clientX, clientY, wasSelected) => {
|
|
9890
|
+
const hrefKey = anchor.getAttribute("data-ohw-href-key");
|
|
9891
|
+
if (!hrefKey || !isFooterHrefKey(hrefKey)) return false;
|
|
9892
|
+
const column = findFooterColumnForLink(anchor);
|
|
9893
|
+
const columns = listFooterColumns();
|
|
9894
|
+
beginFooterDrag({
|
|
9895
|
+
kind: "link",
|
|
9896
|
+
hrefKey,
|
|
9897
|
+
columnEl: column,
|
|
9898
|
+
sourceColumnIndex: column ? columns.indexOf(column) : 0,
|
|
9899
|
+
wasSelected,
|
|
9900
|
+
draggedEl: anchor,
|
|
9901
|
+
lastClientX: clientX,
|
|
9902
|
+
lastClientY: clientY,
|
|
9903
|
+
activeSlot: null
|
|
9904
|
+
});
|
|
9905
|
+
return true;
|
|
9906
|
+
},
|
|
9907
|
+
[beginFooterDrag]
|
|
9908
|
+
);
|
|
9909
|
+
const startFooterColumnDrag = useCallback5(
|
|
9910
|
+
(columnEl, clientX, clientY, wasSelected) => {
|
|
9911
|
+
const columns = listFooterColumns();
|
|
9912
|
+
const idx = columns.indexOf(columnEl);
|
|
9913
|
+
if (idx < 0) return false;
|
|
9914
|
+
beginFooterDrag({
|
|
9915
|
+
kind: "column",
|
|
9916
|
+
hrefKey: null,
|
|
9917
|
+
columnEl,
|
|
9918
|
+
sourceColumnIndex: idx,
|
|
9919
|
+
wasSelected,
|
|
9920
|
+
draggedEl: columnEl,
|
|
9921
|
+
lastClientX: clientX,
|
|
9922
|
+
lastClientY: clientY,
|
|
9923
|
+
activeSlot: null
|
|
9924
|
+
});
|
|
9925
|
+
return true;
|
|
9926
|
+
},
|
|
9927
|
+
[beginFooterDrag]
|
|
9928
|
+
);
|
|
9929
|
+
const handleItemDragStart = useCallback5(
|
|
9930
|
+
(e) => {
|
|
9931
|
+
const selected = selectedElRef.current;
|
|
9932
|
+
if (!selected) {
|
|
9933
|
+
setIsItemDragging(true);
|
|
9934
|
+
return;
|
|
9935
|
+
}
|
|
9936
|
+
const clientX = e?.clientX ?? selected.getBoundingClientRect().left + 8;
|
|
9937
|
+
const clientY = e?.clientY ?? selected.getBoundingClientRect().top + 8;
|
|
9938
|
+
if (startFooterLinkDrag(selected, clientX, clientY, true)) return;
|
|
9939
|
+
if (selected.hasAttribute("data-ohw-footer-col") || isInferredFooterGroup(selected) && selected.closest("footer")) {
|
|
9940
|
+
if (startFooterColumnDrag(selected, clientX, clientY, true)) return;
|
|
9941
|
+
}
|
|
9942
|
+
if (startNavLinkDrag(selected, clientX, clientY, true)) return;
|
|
9943
|
+
siblingHintElRef.current = null;
|
|
9944
|
+
setSiblingHintRect(null);
|
|
9945
|
+
setIsItemDragging(true);
|
|
9946
|
+
},
|
|
9947
|
+
[startFooterColumnDrag, startFooterLinkDrag, startNavLinkDrag]
|
|
9948
|
+
);
|
|
9949
|
+
const handleItemDragEnd = useCallback5(
|
|
9950
|
+
(e) => {
|
|
9951
|
+
if (footerDragRef.current) {
|
|
9952
|
+
const x = e?.clientX;
|
|
9953
|
+
const y = e?.clientY;
|
|
9954
|
+
if (typeof x === "number" && typeof y === "number" && (x !== 0 || y !== 0)) {
|
|
9955
|
+
commitFooterDrag(x, y);
|
|
9956
|
+
} else {
|
|
9957
|
+
commitFooterDrag();
|
|
9958
|
+
}
|
|
9959
|
+
return;
|
|
9960
|
+
}
|
|
9961
|
+
if (navDragRef.current) {
|
|
9962
|
+
const x = e?.clientX;
|
|
9963
|
+
const y = e?.clientY;
|
|
9964
|
+
if (typeof x === "number" && typeof y === "number" && (x !== 0 || y !== 0)) {
|
|
9965
|
+
commitNavDrag(x, y);
|
|
9966
|
+
} else {
|
|
9967
|
+
commitNavDrag();
|
|
9968
|
+
}
|
|
9969
|
+
return;
|
|
9970
|
+
}
|
|
9971
|
+
setIsItemDragging(false);
|
|
9972
|
+
},
|
|
9973
|
+
[commitFooterDrag, commitNavDrag, navDragRef]
|
|
9974
|
+
);
|
|
9975
|
+
const handleItemChromePointerDown = useCallback5((e) => {
|
|
9976
|
+
if (e.button !== 0) return;
|
|
9977
|
+
const selected = selectedElRef.current;
|
|
9978
|
+
if (!selected) return;
|
|
9979
|
+
const hrefKey = selected.getAttribute("data-ohw-href-key");
|
|
9980
|
+
if (hrefKey && isFooterHrefKey(hrefKey)) {
|
|
9981
|
+
footerPointerDragRef.current = {
|
|
9982
|
+
el: selected,
|
|
9983
|
+
kind: "link",
|
|
9984
|
+
startX: e.clientX,
|
|
9985
|
+
startY: e.clientY,
|
|
9986
|
+
pointerId: e.pointerId,
|
|
9987
|
+
wasSelected: true,
|
|
9988
|
+
started: false
|
|
9989
|
+
};
|
|
9990
|
+
return;
|
|
9991
|
+
}
|
|
9992
|
+
if (selected.hasAttribute("data-ohw-footer-col") || isInferredFooterGroup(selected) && selected.closest("footer")) {
|
|
9993
|
+
footerPointerDragRef.current = {
|
|
9994
|
+
el: selected,
|
|
9995
|
+
kind: "column",
|
|
9996
|
+
startX: e.clientX,
|
|
9997
|
+
startY: e.clientY,
|
|
9998
|
+
pointerId: e.pointerId,
|
|
9999
|
+
wasSelected: true,
|
|
10000
|
+
started: false
|
|
10001
|
+
};
|
|
10002
|
+
return;
|
|
10003
|
+
}
|
|
10004
|
+
if (armNavPressFromChrome(selected, e.clientX, e.clientY, e.pointerId)) return;
|
|
10005
|
+
}, [armNavPressFromChrome]);
|
|
10006
|
+
const handleItemChromeClick = useCallback5((clientX, clientY) => {
|
|
10007
|
+
if (suppressNextClickRef.current || Date.now() < suppressClickUntilRef.current) {
|
|
10008
|
+
suppressNextClickRef.current = false;
|
|
10009
|
+
return;
|
|
10010
|
+
}
|
|
10011
|
+
const selected = selectedElRef.current;
|
|
10012
|
+
if (!selected || !isNavigationItem(selected)) return;
|
|
10013
|
+
const editable = selected.querySelector('[data-ohw-editable="text"]') ?? selected.querySelector("[data-ohw-editable]");
|
|
10014
|
+
if (!editable) return;
|
|
10015
|
+
activateRef.current(editable, { caretX: clientX, caretY: clientY });
|
|
7945
10016
|
}, []);
|
|
7946
10017
|
reselectNavigationItemRef.current = reselectNavigationItem;
|
|
7947
10018
|
commitNavigationTextEditRef.current = commitNavigationTextEdit;
|
|
7948
|
-
const select =
|
|
10019
|
+
const select = useCallback5((anchor) => {
|
|
7949
10020
|
if (!isNavigationItem(anchor)) return;
|
|
7950
10021
|
if (activeElRef.current) deactivate();
|
|
7951
10022
|
selectedElRef.current = anchor;
|
|
10023
|
+
selectedHrefKeyRef.current = anchor.getAttribute("data-ohw-href-key");
|
|
10024
|
+
selectedFooterColAttrRef.current = null;
|
|
7952
10025
|
markSelected(anchor);
|
|
7953
10026
|
setSelectedIsCta(isNavbarButton2(anchor));
|
|
7954
10027
|
clearHrefKeyHover(anchor);
|
|
@@ -7958,19 +10031,24 @@ function OhhwellsBridge() {
|
|
|
7958
10031
|
hoveredItemElRef.current = null;
|
|
7959
10032
|
siblingHintElRef.current = null;
|
|
7960
10033
|
setSiblingHintRect(null);
|
|
10034
|
+
setSiblingHintRects(collectNavigationItemSiblingHintRects(anchor));
|
|
7961
10035
|
setIsItemDragging(false);
|
|
7962
10036
|
const { key, disabled } = getNavigationItemReorderState(anchor);
|
|
7963
10037
|
setReorderHrefKey(key);
|
|
7964
10038
|
setReorderDragDisabled(disabled);
|
|
10039
|
+
setIsFooterFrameSelection(false);
|
|
7965
10040
|
setToolbarVariant("link-action");
|
|
7966
10041
|
setToolbarRect(anchor.getBoundingClientRect());
|
|
7967
10042
|
setToolbarShowEditLink(false);
|
|
7968
10043
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
7969
10044
|
}, [deactivate, markSelected]);
|
|
7970
|
-
const selectFrame =
|
|
10045
|
+
const selectFrame = useCallback5((el) => {
|
|
7971
10046
|
if (!isNavigationContainer(el)) return;
|
|
7972
10047
|
if (activeElRef.current) deactivate();
|
|
10048
|
+
const isFooterColumn = !isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || Boolean(el.closest("footer") && isInferredFooterGroup(el)));
|
|
7973
10049
|
selectedElRef.current = el;
|
|
10050
|
+
selectedHrefKeyRef.current = null;
|
|
10051
|
+
selectedFooterColAttrRef.current = isFooterColumn ? el.getAttribute("data-ohw-footer-col") ?? String(listFooterColumns().indexOf(el)) : null;
|
|
7974
10052
|
markSelected(el);
|
|
7975
10053
|
setSelectedIsCta(false);
|
|
7976
10054
|
clearHrefKeyHover(el);
|
|
@@ -7980,18 +10058,24 @@ function OhhwellsBridge() {
|
|
|
7980
10058
|
hoveredItemElRef.current = null;
|
|
7981
10059
|
siblingHintElRef.current = null;
|
|
7982
10060
|
setSiblingHintRect(null);
|
|
10061
|
+
setSiblingHintRects(
|
|
10062
|
+
isFooterColumn ? listFooterColumns().filter((column) => column !== el).map((column) => column.getBoundingClientRect()) : []
|
|
10063
|
+
);
|
|
7983
10064
|
setIsItemDragging(false);
|
|
7984
10065
|
setReorderHrefKey(null);
|
|
7985
10066
|
setReorderDragDisabled(false);
|
|
10067
|
+
setIsFooterFrameSelection(isFooterColumn);
|
|
7986
10068
|
setToolbarVariant("select-frame");
|
|
7987
10069
|
setToolbarRect(el.getBoundingClientRect());
|
|
7988
10070
|
setToolbarShowEditLink(false);
|
|
7989
10071
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
7990
10072
|
}, [deactivate, markSelected]);
|
|
7991
|
-
const activate =
|
|
10073
|
+
const activate = useCallback5((el, options) => {
|
|
7992
10074
|
if (activeElRef.current === el) return;
|
|
7993
10075
|
clearSelectedAttr();
|
|
7994
10076
|
selectedElRef.current = null;
|
|
10077
|
+
selectedHrefKeyRef.current = null;
|
|
10078
|
+
selectedFooterColAttrRef.current = null;
|
|
7995
10079
|
setSelectedIsCta(false);
|
|
7996
10080
|
deactivate();
|
|
7997
10081
|
if (hoveredImageRef.current) {
|
|
@@ -8001,7 +10085,10 @@ function OhhwellsBridge() {
|
|
|
8001
10085
|
setToolbarVariant("rich-text");
|
|
8002
10086
|
siblingHintElRef.current = null;
|
|
8003
10087
|
setSiblingHintRect(null);
|
|
10088
|
+
setSiblingHintRects([]);
|
|
8004
10089
|
setIsItemDragging(false);
|
|
10090
|
+
const preActivationSelection = window.getSelection();
|
|
10091
|
+
const preservedRange = preActivationSelection && preActivationSelection.rangeCount > 0 && !preActivationSelection.isCollapsed && el.contains(preActivationSelection.getRangeAt(0).commonAncestorContainer) ? preActivationSelection.getRangeAt(0).cloneRange() : null;
|
|
8005
10092
|
el.setAttribute("contenteditable", "true");
|
|
8006
10093
|
el.setAttribute("data-ohw-editing", "");
|
|
8007
10094
|
el.removeAttribute("data-ohw-hovered");
|
|
@@ -8009,8 +10096,16 @@ function OhhwellsBridge() {
|
|
|
8009
10096
|
activeElRef.current = el;
|
|
8010
10097
|
originalContentRef.current = el.innerHTML;
|
|
8011
10098
|
el.focus({ preventScroll: true });
|
|
8012
|
-
if (
|
|
8013
|
-
|
|
10099
|
+
if (preservedRange) {
|
|
10100
|
+
const selection = window.getSelection();
|
|
10101
|
+
selection?.removeAllRanges();
|
|
10102
|
+
selection?.addRange(preservedRange);
|
|
10103
|
+
} else if (options?.caretX !== void 0 && options?.caretY !== void 0) {
|
|
10104
|
+
const { caretX, caretY } = options;
|
|
10105
|
+
placeCaretAtPoint(el, caretX, caretY);
|
|
10106
|
+
requestAnimationFrame(() => {
|
|
10107
|
+
if (activeElRef.current === el) placeCaretAtPoint(el, caretX, caretY);
|
|
10108
|
+
});
|
|
8014
10109
|
} else {
|
|
8015
10110
|
const selection = window.getSelection();
|
|
8016
10111
|
if (selection && selection.rangeCount === 0) {
|
|
@@ -8081,6 +10176,7 @@ function OhhwellsBridge() {
|
|
|
8081
10176
|
applyLinkByKey(key, val);
|
|
8082
10177
|
}
|
|
8083
10178
|
reconcileNavbarItemsFromContent(content);
|
|
10179
|
+
reconcileFooterOrderFromContent(content);
|
|
8084
10180
|
enforceLinkHrefs();
|
|
8085
10181
|
initSectionsFromContent(content, true);
|
|
8086
10182
|
sectionsLoadedRef.current = true;
|
|
@@ -8109,7 +10205,7 @@ function OhhwellsBridge() {
|
|
|
8109
10205
|
cancelled = true;
|
|
8110
10206
|
};
|
|
8111
10207
|
}, [subdomain, isEditMode]);
|
|
8112
|
-
|
|
10208
|
+
useEffect8(() => {
|
|
8113
10209
|
if (!subdomain || isEditMode) return;
|
|
8114
10210
|
let debounceTimer = null;
|
|
8115
10211
|
let observer = null;
|
|
@@ -8141,6 +10237,7 @@ function OhhwellsBridge() {
|
|
|
8141
10237
|
applyLinkByKey(key, val);
|
|
8142
10238
|
}
|
|
8143
10239
|
reconcileNavbarItemsFromContent(content);
|
|
10240
|
+
reconcileFooterOrderFromContent(content);
|
|
8144
10241
|
} finally {
|
|
8145
10242
|
observer?.observe(document.body, { childList: true, subtree: true });
|
|
8146
10243
|
}
|
|
@@ -8164,10 +10261,10 @@ function OhhwellsBridge() {
|
|
|
8164
10261
|
const visible = Boolean(subdomain) && fetchState !== "done";
|
|
8165
10262
|
el.style.display = visible ? "flex" : "none";
|
|
8166
10263
|
}, [subdomain, fetchState]);
|
|
8167
|
-
|
|
10264
|
+
useEffect8(() => {
|
|
8168
10265
|
postToParent2({ type: "ow:navigation", path: pathname });
|
|
8169
10266
|
}, [pathname, postToParent2]);
|
|
8170
|
-
|
|
10267
|
+
useEffect8(() => {
|
|
8171
10268
|
if (!isEditMode) return;
|
|
8172
10269
|
if (linkPopoverSessionRef.current?.intent === "add-nav") return;
|
|
8173
10270
|
if (document.querySelector("[data-ohw-section-picker]")) return;
|
|
@@ -8175,7 +10272,7 @@ function OhhwellsBridge() {
|
|
|
8175
10272
|
deselectRef.current();
|
|
8176
10273
|
deactivateRef.current();
|
|
8177
10274
|
}, [pathname, isEditMode]);
|
|
8178
|
-
|
|
10275
|
+
useEffect8(() => {
|
|
8179
10276
|
const contentForNav = () => {
|
|
8180
10277
|
if (isEditMode) return editContentRef.current;
|
|
8181
10278
|
if (!subdomain) return {};
|
|
@@ -8187,6 +10284,7 @@ function OhhwellsBridge() {
|
|
|
8187
10284
|
const roots = observeRoots();
|
|
8188
10285
|
if (roots.length === 0) {
|
|
8189
10286
|
reconcileNavbarItemsFromContent(contentForNav());
|
|
10287
|
+
reconcileFooterOrderFromContent(contentForNav());
|
|
8190
10288
|
if (isEditMode) syncNavigationDragCursorAttrs();
|
|
8191
10289
|
return;
|
|
8192
10290
|
}
|
|
@@ -8199,11 +10297,26 @@ function OhhwellsBridge() {
|
|
|
8199
10297
|
}
|
|
8200
10298
|
};
|
|
8201
10299
|
const run = () => {
|
|
8202
|
-
if (applying) return;
|
|
10300
|
+
if (footerDragRef.current || navDragRef.current || applying) return;
|
|
8203
10301
|
applying = true;
|
|
8204
10302
|
observer?.disconnect();
|
|
8205
10303
|
try {
|
|
8206
|
-
|
|
10304
|
+
const content = contentForNav();
|
|
10305
|
+
reconcileNavbarItemsFromContent(content);
|
|
10306
|
+
reconcileFooterOrderFromContent(content);
|
|
10307
|
+
document.querySelectorAll("footer [data-ohw-href-key]").forEach((el) => {
|
|
10308
|
+
if (isFooterHrefKey(el.getAttribute("data-ohw-href-key"))) {
|
|
10309
|
+
disableNativeHrefDrag(el);
|
|
10310
|
+
}
|
|
10311
|
+
});
|
|
10312
|
+
document.querySelectorAll(
|
|
10313
|
+
"nav [data-ohw-href-key], [data-ohw-nav-container] [data-ohw-href-key], [data-ohw-nav-drawer] [data-ohw-href-key]"
|
|
10314
|
+
).forEach((el) => {
|
|
10315
|
+
if (isNavbarHrefKey(el.getAttribute("data-ohw-href-key"))) {
|
|
10316
|
+
disableNativeHrefDrag(el);
|
|
10317
|
+
}
|
|
10318
|
+
});
|
|
10319
|
+
resyncSelectedNavigationItem();
|
|
8207
10320
|
if (isEditMode) syncNavigationDragCursorAttrs();
|
|
8208
10321
|
} finally {
|
|
8209
10322
|
applying = false;
|
|
@@ -8223,8 +10336,8 @@ function OhhwellsBridge() {
|
|
|
8223
10336
|
if (rafId != null) cancelAnimationFrame(rafId);
|
|
8224
10337
|
observer?.disconnect();
|
|
8225
10338
|
};
|
|
8226
|
-
}, [isEditMode, pathname, subdomain, fetchState]);
|
|
8227
|
-
|
|
10339
|
+
}, [isEditMode, pathname, subdomain, fetchState, resyncSelectedNavigationItem]);
|
|
10340
|
+
useEffect8(() => {
|
|
8228
10341
|
if (!isEditMode) return;
|
|
8229
10342
|
const measure = () => {
|
|
8230
10343
|
const h = document.body.scrollHeight;
|
|
@@ -8248,7 +10361,7 @@ function OhhwellsBridge() {
|
|
|
8248
10361
|
window.removeEventListener("resize", handleResize);
|
|
8249
10362
|
};
|
|
8250
10363
|
}, [pathname, isEditMode, postToParent2]);
|
|
8251
|
-
|
|
10364
|
+
useEffect8(() => {
|
|
8252
10365
|
if (!subdomainFromQuery || isEditMode) return;
|
|
8253
10366
|
const handleClick = (e) => {
|
|
8254
10367
|
const anchor = e.target.closest("a");
|
|
@@ -8264,7 +10377,7 @@ function OhhwellsBridge() {
|
|
|
8264
10377
|
document.addEventListener("click", handleClick, true);
|
|
8265
10378
|
return () => document.removeEventListener("click", handleClick, true);
|
|
8266
10379
|
}, [subdomainFromQuery, isEditMode, router]);
|
|
8267
|
-
|
|
10380
|
+
useEffect8(() => {
|
|
8268
10381
|
if (!isEditMode) {
|
|
8269
10382
|
editStylesRef.current?.base.remove();
|
|
8270
10383
|
editStylesRef.current?.forceHover.remove();
|
|
@@ -8326,6 +10439,21 @@ function OhhwellsBridge() {
|
|
|
8326
10439
|
outline: none !important;
|
|
8327
10440
|
outline-offset: 0 !important;
|
|
8328
10441
|
}
|
|
10442
|
+
/* Editor chrome owns selection \u2014 suppress native focus rings on nav/footer items. */
|
|
10443
|
+
nav [data-ohw-href-key]:focus,
|
|
10444
|
+
nav [data-ohw-href-key]:focus-visible,
|
|
10445
|
+
nav [data-ohw-href-key]:focus-within,
|
|
10446
|
+
footer [data-ohw-href-key]:focus,
|
|
10447
|
+
footer [data-ohw-href-key]:focus-visible,
|
|
10448
|
+
footer [data-ohw-href-key]:focus-within,
|
|
10449
|
+
nav [data-ohw-href-key] [data-ohw-editable]:focus,
|
|
10450
|
+
nav [data-ohw-href-key] [data-ohw-editable]:focus-visible,
|
|
10451
|
+
footer [data-ohw-href-key] [data-ohw-editable]:focus,
|
|
10452
|
+
footer [data-ohw-href-key] [data-ohw-editable]:focus-visible {
|
|
10453
|
+
outline: none !important;
|
|
10454
|
+
outline-offset: 0 !important;
|
|
10455
|
+
box-shadow: none !important;
|
|
10456
|
+
}
|
|
8329
10457
|
/* Text edit wins over grab/default (must beat [data-ohw-can-drag] *). */
|
|
8330
10458
|
[data-ohw-editing],
|
|
8331
10459
|
[data-ohw-editing] *,
|
|
@@ -8367,12 +10495,39 @@ function OhhwellsBridge() {
|
|
|
8367
10495
|
syncNavigationDragCursorAttrs();
|
|
8368
10496
|
refreshStateRules();
|
|
8369
10497
|
const handleClick = (e) => {
|
|
10498
|
+
if (suppressNextClickRef.current || Date.now() < suppressClickUntilRef.current) {
|
|
10499
|
+
suppressNextClickRef.current = false;
|
|
10500
|
+
e.preventDefault();
|
|
10501
|
+
e.stopPropagation();
|
|
10502
|
+
return;
|
|
10503
|
+
}
|
|
8370
10504
|
const target = e.target;
|
|
8371
10505
|
if (target.closest("[data-ohw-toolbar]")) return;
|
|
8372
10506
|
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
8373
10507
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
8374
10508
|
if (isInsideLinkEditor(target)) return;
|
|
8375
10509
|
if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
|
|
10510
|
+
if (target.closest("[data-ohw-item-drag-surface]")) {
|
|
10511
|
+
e.preventDefault();
|
|
10512
|
+
e.stopPropagation();
|
|
10513
|
+
const selected = selectedElRef.current;
|
|
10514
|
+
if (selected && isNavigationItem(selected)) {
|
|
10515
|
+
const editable2 = selected.querySelector('[data-ohw-editable="text"]') ?? selected.querySelector("[data-ohw-editable]");
|
|
10516
|
+
if (editable2) {
|
|
10517
|
+
activateRef.current(editable2, {
|
|
10518
|
+
caretX: e.clientX,
|
|
10519
|
+
caretY: e.clientY
|
|
10520
|
+
});
|
|
10521
|
+
}
|
|
10522
|
+
} else if (selected?.hasAttribute("data-ohw-footer-col")) {
|
|
10523
|
+
const link = listFooterLinksInColumn(selected).find((el) => {
|
|
10524
|
+
const r2 = el.getBoundingClientRect();
|
|
10525
|
+
return e.clientX >= r2.left && e.clientX <= r2.right && e.clientY >= r2.top && e.clientY <= r2.bottom;
|
|
10526
|
+
});
|
|
10527
|
+
if (link) selectRef.current(link);
|
|
10528
|
+
}
|
|
10529
|
+
return;
|
|
10530
|
+
}
|
|
8376
10531
|
const navFromChrome = resolveNavContainerSelectionTarget(target, e.clientX, e.clientY);
|
|
8377
10532
|
if (navFromChrome) {
|
|
8378
10533
|
e.preventDefault();
|
|
@@ -8401,7 +10556,9 @@ function OhhwellsBridge() {
|
|
|
8401
10556
|
if (inActive || inActiveNav) {
|
|
8402
10557
|
e.preventDefault();
|
|
8403
10558
|
e.stopPropagation();
|
|
8404
|
-
|
|
10559
|
+
const selection = window.getSelection();
|
|
10560
|
+
const hasRangeSelection = Boolean(selection && !selection.isCollapsed);
|
|
10561
|
+
if (e.detail < 2 && !hasRangeSelection) {
|
|
8405
10562
|
placeCaretAtPoint(active, e.clientX, e.clientY);
|
|
8406
10563
|
refreshActiveCommandsRef.current();
|
|
8407
10564
|
}
|
|
@@ -8444,17 +10601,45 @@ function OhhwellsBridge() {
|
|
|
8444
10601
|
}
|
|
8445
10602
|
e.preventDefault();
|
|
8446
10603
|
e.stopPropagation();
|
|
8447
|
-
activateRef.current(editable);
|
|
10604
|
+
activateRef.current(editable, { caretX: e.clientX, caretY: e.clientY });
|
|
8448
10605
|
return;
|
|
8449
10606
|
}
|
|
8450
10607
|
const hrefAnchor = getNavigationItemAnchor(target);
|
|
8451
10608
|
if (hrefAnchor) {
|
|
8452
10609
|
e.preventDefault();
|
|
8453
10610
|
e.stopPropagation();
|
|
8454
|
-
if (selectedElRef.current === hrefAnchor)
|
|
10611
|
+
if (selectedElRef.current === hrefAnchor) {
|
|
10612
|
+
const textEditable = hrefAnchor.querySelector('[data-ohw-editable="text"]') ?? hrefAnchor.querySelector("[data-ohw-editable]");
|
|
10613
|
+
if (textEditable) {
|
|
10614
|
+
activateRef.current(textEditable, {
|
|
10615
|
+
caretX: e.clientX,
|
|
10616
|
+
caretY: e.clientY
|
|
10617
|
+
});
|
|
10618
|
+
}
|
|
10619
|
+
return;
|
|
10620
|
+
}
|
|
8455
10621
|
selectRef.current(hrefAnchor);
|
|
8456
10622
|
return;
|
|
8457
10623
|
}
|
|
10624
|
+
const footerColClick = target.closest("[data-ohw-footer-col]");
|
|
10625
|
+
if (footerColClick) {
|
|
10626
|
+
e.preventDefault();
|
|
10627
|
+
e.stopPropagation();
|
|
10628
|
+
selectFrameRef.current(footerColClick);
|
|
10629
|
+
return;
|
|
10630
|
+
}
|
|
10631
|
+
const footerLinksToSelect = resolveFooterLinksContainerSelectionTarget(
|
|
10632
|
+
target,
|
|
10633
|
+
e.clientX,
|
|
10634
|
+
e.clientY,
|
|
10635
|
+
isPointOverNavItem
|
|
10636
|
+
);
|
|
10637
|
+
if (footerLinksToSelect) {
|
|
10638
|
+
e.preventDefault();
|
|
10639
|
+
e.stopPropagation();
|
|
10640
|
+
selectFrameRef.current(footerLinksToSelect);
|
|
10641
|
+
return;
|
|
10642
|
+
}
|
|
8458
10643
|
const navContainerToSelect = resolveNavContainerSelectionTarget(target, e.clientX, e.clientY);
|
|
8459
10644
|
if (navContainerToSelect) {
|
|
8460
10645
|
e.preventDefault();
|
|
@@ -8513,8 +10698,8 @@ function OhhwellsBridge() {
|
|
|
8513
10698
|
return;
|
|
8514
10699
|
}
|
|
8515
10700
|
const navLabel = getNavigationLabelEditable(target);
|
|
8516
|
-
|
|
8517
|
-
|
|
10701
|
+
const editable = navLabel?.editable ?? target.closest('[data-ohw-editable="text"], [data-ohw-editable="plain"]');
|
|
10702
|
+
if (!editable || isMediaEditable(editable) || editable.dataset.ohwEditable === "link") return;
|
|
8518
10703
|
e.preventDefault();
|
|
8519
10704
|
e.stopPropagation();
|
|
8520
10705
|
if (activeElRef.current !== editable) {
|
|
@@ -8528,16 +10713,45 @@ function OhhwellsBridge() {
|
|
|
8528
10713
|
const handleMouseOver = (e) => {
|
|
8529
10714
|
if (document.documentElement.hasAttribute("data-ohw-section-picking")) return;
|
|
8530
10715
|
const target = e.target;
|
|
8531
|
-
if (
|
|
8532
|
-
|
|
8533
|
-
|
|
8534
|
-
|
|
8535
|
-
|
|
8536
|
-
|
|
8537
|
-
|
|
8538
|
-
|
|
10716
|
+
if (linkPopoverOpenRef.current) {
|
|
10717
|
+
hoveredItemElRef.current = null;
|
|
10718
|
+
setHoveredItemRect(null);
|
|
10719
|
+
hoveredNavContainerRef.current = null;
|
|
10720
|
+
setHoveredNavContainerRect(null);
|
|
10721
|
+
return;
|
|
10722
|
+
}
|
|
10723
|
+
{
|
|
10724
|
+
const selected2 = selectedElRef.current;
|
|
10725
|
+
const selectedIsFooterColumn = Boolean(selected2) && !isFooterLinksContainer(selected2) && (selected2.hasAttribute("data-ohw-footer-col") || selected2.hasAttribute("data-ohw-footer-column") || Boolean(selected2.closest("footer") && isInferredFooterGroup(selected2)));
|
|
10726
|
+
const allowNavContainerHover = toolbarVariantRef.current !== "select-frame";
|
|
10727
|
+
const allowFooterLinksHover = toolbarVariantRef.current !== "select-frame" || selectedIsFooterColumn;
|
|
10728
|
+
if (allowNavContainerHover) {
|
|
10729
|
+
const navContainer = target.closest("[data-ohw-nav-container]");
|
|
10730
|
+
if (navContainer && !getNavigationItemAnchor(target)) {
|
|
10731
|
+
hoveredNavContainerRef.current = navContainer;
|
|
10732
|
+
setHoveredNavContainerRect(navContainer.getBoundingClientRect());
|
|
10733
|
+
hoveredItemElRef.current = null;
|
|
10734
|
+
setHoveredItemRect(null);
|
|
10735
|
+
return;
|
|
10736
|
+
}
|
|
8539
10737
|
}
|
|
8540
|
-
if (
|
|
10738
|
+
if (allowFooterLinksHover) {
|
|
10739
|
+
const navContainer = target.closest("[data-ohw-nav-container]");
|
|
10740
|
+
if (!navContainer) {
|
|
10741
|
+
const footerLinks = target.closest("[data-ohw-footer-links], .rb-footer-links") ?? null;
|
|
10742
|
+
if (footerLinks && selected2 !== footerLinks && !getNavigationItemAnchor(target) && !target.closest("[data-ohw-footer-col], [data-ohw-footer-column]")) {
|
|
10743
|
+
hoveredNavContainerRef.current = footerLinks;
|
|
10744
|
+
setHoveredNavContainerRect(footerLinks.getBoundingClientRect());
|
|
10745
|
+
hoveredItemElRef.current = null;
|
|
10746
|
+
setHoveredItemRect(null);
|
|
10747
|
+
return;
|
|
10748
|
+
}
|
|
10749
|
+
if (!footerLinks) {
|
|
10750
|
+
hoveredNavContainerRef.current = null;
|
|
10751
|
+
setHoveredNavContainerRect(null);
|
|
10752
|
+
}
|
|
10753
|
+
}
|
|
10754
|
+
} else if (toolbarVariantRef.current === "select-frame") {
|
|
8541
10755
|
hoveredNavContainerRef.current = null;
|
|
8542
10756
|
setHoveredNavContainerRect(null);
|
|
8543
10757
|
}
|
|
@@ -8547,12 +10761,21 @@ function OhhwellsBridge() {
|
|
|
8547
10761
|
hoveredNavContainerRef.current = null;
|
|
8548
10762
|
setHoveredNavContainerRect(null);
|
|
8549
10763
|
const selected2 = selectedElRef.current;
|
|
8550
|
-
if (selected2 === navAnchor
|
|
10764
|
+
if (selected2 === navAnchor) return;
|
|
8551
10765
|
clearHrefKeyHover(navAnchor);
|
|
8552
10766
|
hoveredItemElRef.current = navAnchor;
|
|
8553
10767
|
setHoveredItemRect(navAnchor.getBoundingClientRect());
|
|
8554
10768
|
return;
|
|
8555
10769
|
}
|
|
10770
|
+
const footerCol = target.closest("[data-ohw-footer-col]") ?? target.closest("[data-ohw-footer-column]");
|
|
10771
|
+
if (footerCol) {
|
|
10772
|
+
hoveredNavContainerRef.current = null;
|
|
10773
|
+
setHoveredNavContainerRect(null);
|
|
10774
|
+
if (selectedElRef.current === footerCol) return;
|
|
10775
|
+
hoveredItemElRef.current = footerCol;
|
|
10776
|
+
setHoveredItemRect(footerCol.getBoundingClientRect());
|
|
10777
|
+
return;
|
|
10778
|
+
}
|
|
8556
10779
|
const editable = target.closest("[data-ohw-editable]");
|
|
8557
10780
|
if (!editable) return;
|
|
8558
10781
|
const selected = selectedElRef.current;
|
|
@@ -8570,14 +10793,25 @@ function OhhwellsBridge() {
|
|
|
8570
10793
|
};
|
|
8571
10794
|
const handleMouseOut = (e) => {
|
|
8572
10795
|
const target = e.target;
|
|
8573
|
-
if (target.closest("[data-ohw-nav-container], [data-ohw-footer-column]")) {
|
|
10796
|
+
if (target.closest("[data-ohw-nav-container], [data-ohw-footer-col], [data-ohw-footer-column], [data-ohw-footer-links], .rb-footer-links")) {
|
|
8574
10797
|
const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
8575
|
-
if (related2?.closest("[data-ohw-nav-container], [data-ohw-footer-column], [data-ohw-navbar-container-chrome], [data-ohw-navbar-add-button]")) {
|
|
10798
|
+
if (related2?.closest("[data-ohw-nav-container], [data-ohw-footer-col], [data-ohw-footer-column], [data-ohw-footer-links], .rb-footer-links, [data-ohw-navbar-container-chrome], [data-ohw-navbar-add-button], [data-ohw-footer-container-chrome], [data-ohw-footer-add-button]")) {
|
|
8576
10799
|
return;
|
|
8577
10800
|
}
|
|
8578
10801
|
hoveredNavContainerRef.current = null;
|
|
8579
10802
|
setHoveredNavContainerRect(null);
|
|
8580
10803
|
}
|
|
10804
|
+
const footerCol = target.closest("[data-ohw-footer-col]") ?? target.closest("[data-ohw-footer-column]");
|
|
10805
|
+
if (footerCol && hoveredItemElRef.current === footerCol) {
|
|
10806
|
+
const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
10807
|
+
if (related2?.closest("[data-ohw-drag-handle-container], [data-ohw-item-interaction]")) return;
|
|
10808
|
+
if (related2?.closest("[data-ohw-footer-col], [data-ohw-footer-column]") === footerCol) {
|
|
10809
|
+
return;
|
|
10810
|
+
}
|
|
10811
|
+
hoveredItemElRef.current = null;
|
|
10812
|
+
setHoveredItemRect(null);
|
|
10813
|
+
return;
|
|
10814
|
+
}
|
|
8581
10815
|
const navAnchor = getNavigationItemAnchor(target);
|
|
8582
10816
|
if (navAnchor) {
|
|
8583
10817
|
const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
@@ -8656,6 +10890,15 @@ function OhhwellsBridge() {
|
|
|
8656
10890
|
if (track) track.setAttribute("data-ohw-hover-paused", "");
|
|
8657
10891
|
};
|
|
8658
10892
|
const clearImageHover = () => setMediaHover(null);
|
|
10893
|
+
const dismissImageHover = () => {
|
|
10894
|
+
if (hoveredImageRef.current) {
|
|
10895
|
+
hoveredImageRef.current = null;
|
|
10896
|
+
hoveredImageHasTextOverlapRef.current = false;
|
|
10897
|
+
resumeAnimTracks();
|
|
10898
|
+
postToParentRef.current({ type: "ow:image-unhover" });
|
|
10899
|
+
}
|
|
10900
|
+
clearImageHover();
|
|
10901
|
+
};
|
|
8659
10902
|
const findImageAtPoint = (clientX, clientY, fromParentViewport) => {
|
|
8660
10903
|
const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
8661
10904
|
const images = Array.from(document.querySelectorAll(MEDIA_SELECTOR));
|
|
@@ -8699,26 +10942,21 @@ function OhhwellsBridge() {
|
|
|
8699
10942
|
}
|
|
8700
10943
|
return smallest;
|
|
8701
10944
|
};
|
|
8702
|
-
const dismissImageHover = () => {
|
|
8703
|
-
if (hoveredImageRef.current) {
|
|
8704
|
-
hoveredImageRef.current = null;
|
|
8705
|
-
hoveredImageHasTextOverlapRef.current = false;
|
|
8706
|
-
resumeAnimTracks();
|
|
8707
|
-
postToParentRef.current({ type: "ow:image-unhover" });
|
|
8708
|
-
}
|
|
8709
|
-
};
|
|
8710
10945
|
const probeNavigationHoverAt = (x, y) => {
|
|
8711
|
-
|
|
10946
|
+
const selected = selectedElRef.current;
|
|
10947
|
+
const selectedIsFooterColumn = Boolean(selected) && !isFooterLinksContainer(selected) && (selected.hasAttribute("data-ohw-footer-col") || selected.hasAttribute("data-ohw-footer-column") || Boolean(selected.closest("footer") && isInferredFooterGroup(selected)));
|
|
10948
|
+
const selectedIsFooterLinks = Boolean(selected && isFooterLinksContainer(selected));
|
|
10949
|
+
const allowNavContainerHover = toolbarVariantRef.current !== "select-frame";
|
|
10950
|
+
const allowFooterLinksHover = (toolbarVariantRef.current !== "select-frame" || selectedIsFooterColumn) && !selectedIsFooterLinks;
|
|
10951
|
+
if (toolbarVariantRef.current === "select-frame" && !allowFooterLinksHover) {
|
|
8712
10952
|
hoveredNavContainerRef.current = null;
|
|
8713
10953
|
setHoveredNavContainerRect(null);
|
|
8714
|
-
return;
|
|
8715
10954
|
}
|
|
8716
|
-
const
|
|
8717
|
-
|
|
8718
|
-
|
|
8719
|
-
|
|
8720
|
-
|
|
8721
|
-
for (const container of frameContainers) {
|
|
10955
|
+
const navContainers = Array.from(
|
|
10956
|
+
document.querySelectorAll("[data-ohw-nav-container]")
|
|
10957
|
+
);
|
|
10958
|
+
const footerColumns = listFooterColumns();
|
|
10959
|
+
for (const container of [...navContainers, ...footerColumns]) {
|
|
8722
10960
|
const containerRect = container.getBoundingClientRect();
|
|
8723
10961
|
const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
|
|
8724
10962
|
if (!overContainer) continue;
|
|
@@ -8732,26 +10970,66 @@ function OhhwellsBridge() {
|
|
|
8732
10970
|
if (navItemHit) {
|
|
8733
10971
|
hoveredNavContainerRef.current = null;
|
|
8734
10972
|
setHoveredNavContainerRect(null);
|
|
8735
|
-
|
|
8736
|
-
if (selected !== navItemHit && !selected?.contains(navItemHit)) {
|
|
10973
|
+
if (selected !== navItemHit) {
|
|
8737
10974
|
clearHrefKeyHover(navItemHit);
|
|
8738
10975
|
hoveredItemElRef.current = navItemHit;
|
|
8739
10976
|
setHoveredItemRect(navItemHit.getBoundingClientRect());
|
|
10977
|
+
} else if (hoveredItemElRef.current === navItemHit) {
|
|
10978
|
+
hoveredItemElRef.current = null;
|
|
10979
|
+
setHoveredItemRect(null);
|
|
8740
10980
|
}
|
|
8741
10981
|
return;
|
|
8742
10982
|
}
|
|
8743
|
-
overFrame = container;
|
|
8744
|
-
break;
|
|
8745
10983
|
}
|
|
8746
|
-
if (
|
|
8747
|
-
|
|
8748
|
-
|
|
10984
|
+
if (allowNavContainerHover) {
|
|
10985
|
+
for (const container of navContainers) {
|
|
10986
|
+
const containerRect = container.getBoundingClientRect();
|
|
10987
|
+
const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
|
|
10988
|
+
if (!overContainer) continue;
|
|
10989
|
+
if (isPointOverNavItem(container, x, y)) continue;
|
|
10990
|
+
hoveredNavContainerRef.current = container;
|
|
10991
|
+
setHoveredNavContainerRect(container.getBoundingClientRect());
|
|
10992
|
+
hoveredItemElRef.current = null;
|
|
10993
|
+
setHoveredItemRect(null);
|
|
10994
|
+
return;
|
|
10995
|
+
}
|
|
10996
|
+
}
|
|
10997
|
+
if (allowFooterLinksHover) {
|
|
10998
|
+
const footerLinks = getFooterLinksContainer();
|
|
10999
|
+
if (footerLinks) {
|
|
11000
|
+
const containerRect = footerLinks.getBoundingClientRect();
|
|
11001
|
+
const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
|
|
11002
|
+
if (overContainer && !isPointOverNavItem(footerLinks, x, y) && !isPointOverFooterColumn(x, y)) {
|
|
11003
|
+
hoveredNavContainerRef.current = footerLinks;
|
|
11004
|
+
setHoveredNavContainerRect(footerLinks.getBoundingClientRect());
|
|
11005
|
+
hoveredItemElRef.current = null;
|
|
11006
|
+
setHoveredItemRect(null);
|
|
11007
|
+
return;
|
|
11008
|
+
}
|
|
11009
|
+
}
|
|
11010
|
+
}
|
|
11011
|
+
hoveredNavContainerRef.current = null;
|
|
11012
|
+
setHoveredNavContainerRect(null);
|
|
11013
|
+
for (const column of footerColumns) {
|
|
11014
|
+
const containerRect = column.getBoundingClientRect();
|
|
11015
|
+
const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
|
|
11016
|
+
if (!overContainer) continue;
|
|
11017
|
+
if (isPointOverNavItem(column, x, y)) continue;
|
|
11018
|
+
if (selectedElRef.current === column) {
|
|
11019
|
+
if (hoveredItemElRef.current === column) {
|
|
11020
|
+
hoveredItemElRef.current = null;
|
|
11021
|
+
setHoveredItemRect(null);
|
|
11022
|
+
}
|
|
11023
|
+
return;
|
|
11024
|
+
}
|
|
11025
|
+
hoveredItemElRef.current = column;
|
|
11026
|
+
setHoveredItemRect(column.getBoundingClientRect());
|
|
8749
11027
|
return;
|
|
8750
11028
|
}
|
|
8751
|
-
|
|
8752
|
-
|
|
8753
|
-
|
|
8754
|
-
|
|
11029
|
+
if (hoveredItemElRef.current?.hasAttribute("data-ohw-footer-col") || hoveredItemElRef.current?.hasAttribute("data-ohw-footer-column")) {
|
|
11030
|
+
hoveredItemElRef.current = null;
|
|
11031
|
+
setHoveredItemRect(null);
|
|
11032
|
+
}
|
|
8755
11033
|
};
|
|
8756
11034
|
const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
|
|
8757
11035
|
if (linkPopoverOpenRef.current) {
|
|
@@ -8772,6 +11050,10 @@ function OhhwellsBridge() {
|
|
|
8772
11050
|
}
|
|
8773
11051
|
hoveredNavContainerRef.current = null;
|
|
8774
11052
|
setHoveredNavContainerRect(null);
|
|
11053
|
+
if (hoveredItemElRef.current?.hasAttribute("data-ohw-footer-col") || hoveredItemElRef.current?.hasAttribute("data-ohw-footer-column")) {
|
|
11054
|
+
hoveredItemElRef.current = null;
|
|
11055
|
+
setHoveredItemRect(null);
|
|
11056
|
+
}
|
|
8775
11057
|
const toggleEl = document.querySelector("[data-ohw-state-toggle]");
|
|
8776
11058
|
if (toggleEl) {
|
|
8777
11059
|
const tr = toggleEl.getBoundingClientRect();
|
|
@@ -9019,6 +11301,15 @@ function OhhwellsBridge() {
|
|
|
9019
11301
|
probeHoverCardsAt(clientX, clientY);
|
|
9020
11302
|
};
|
|
9021
11303
|
const handleDragOver = (e) => {
|
|
11304
|
+
const footerSession = footerDragRef.current;
|
|
11305
|
+
if (footerSession) {
|
|
11306
|
+
e.preventDefault();
|
|
11307
|
+
if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
|
|
11308
|
+
const slot = footerSession.kind === "link" && footerSession.hrefKey ? hitTestLinkDropSlot(e.clientX, e.clientY, footerSession.hrefKey) : hitTestColumnDropSlot(e.clientX, e.clientY);
|
|
11309
|
+
refreshFooterDragVisualsRef.current(footerSession, slot, e.clientX, e.clientY);
|
|
11310
|
+
return;
|
|
11311
|
+
}
|
|
11312
|
+
if (onNavDragOver(e)) return;
|
|
9022
11313
|
e.preventDefault();
|
|
9023
11314
|
const el = findImageAtPoint(e.clientX, e.clientY, false);
|
|
9024
11315
|
if (!el) {
|
|
@@ -9225,6 +11516,7 @@ function OhhwellsBridge() {
|
|
|
9225
11516
|
}
|
|
9226
11517
|
editContentRef.current = { ...editContentRef.current, ...content };
|
|
9227
11518
|
reconcileNavbarItemsFromContent(editContentRef.current);
|
|
11519
|
+
reconcileFooterOrderFromContent(editContentRef.current);
|
|
9228
11520
|
syncNavigationDragCursorAttrs();
|
|
9229
11521
|
enforceLinkHrefs();
|
|
9230
11522
|
postToParentRef.current({ type: "ow:hydrate-done" });
|
|
@@ -9279,6 +11571,11 @@ function OhhwellsBridge() {
|
|
|
9279
11571
|
}
|
|
9280
11572
|
if (selectedElRef.current) {
|
|
9281
11573
|
if (toolbarVariantRef.current === "select-frame") {
|
|
11574
|
+
const parent2 = getNavigationSelectionParent(selectedElRef.current);
|
|
11575
|
+
if (parent2 && isNavigationContainer(parent2) && isFooterLinksContainer(parent2) && !isFooterLinksContainer(selectedElRef.current)) {
|
|
11576
|
+
selectFrameRef.current(parent2);
|
|
11577
|
+
return;
|
|
11578
|
+
}
|
|
9282
11579
|
deselectRef.current();
|
|
9283
11580
|
return;
|
|
9284
11581
|
}
|
|
@@ -9294,13 +11591,10 @@ function OhhwellsBridge() {
|
|
|
9294
11591
|
const handleKeyDown = (e) => {
|
|
9295
11592
|
if (e.key === "Escape" && document.querySelector("[data-ohw-section-picker]")) return;
|
|
9296
11593
|
if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a" && activeElRef.current) {
|
|
9297
|
-
|
|
9298
|
-
|
|
9299
|
-
|
|
9300
|
-
|
|
9301
|
-
refreshActiveCommandsRef.current();
|
|
9302
|
-
return;
|
|
9303
|
-
}
|
|
11594
|
+
e.preventDefault();
|
|
11595
|
+
selectAllTextInEditable(activeElRef.current);
|
|
11596
|
+
refreshActiveCommandsRef.current();
|
|
11597
|
+
return;
|
|
9304
11598
|
}
|
|
9305
11599
|
if (e.key === "Escape" && linkPopoverOpenRef.current) {
|
|
9306
11600
|
setLinkPopoverRef.current(null);
|
|
@@ -9308,6 +11602,12 @@ function OhhwellsBridge() {
|
|
|
9308
11602
|
}
|
|
9309
11603
|
if (e.key === "Escape" && selectedElRef.current && !activeElRef.current) {
|
|
9310
11604
|
if (toolbarVariantRef.current === "select-frame") {
|
|
11605
|
+
const parent2 = getNavigationSelectionParent(selectedElRef.current);
|
|
11606
|
+
if (parent2 && isNavigationContainer(parent2) && isFooterLinksContainer(parent2) && !isFooterLinksContainer(selectedElRef.current)) {
|
|
11607
|
+
e.preventDefault();
|
|
11608
|
+
selectFrameRef.current(parent2);
|
|
11609
|
+
return;
|
|
11610
|
+
}
|
|
9311
11611
|
deselectRef.current();
|
|
9312
11612
|
return;
|
|
9313
11613
|
}
|
|
@@ -9382,6 +11682,26 @@ function OhhwellsBridge() {
|
|
|
9382
11682
|
if (siblingHintElRef.current) {
|
|
9383
11683
|
setSiblingHintRect(siblingHintElRef.current.getBoundingClientRect());
|
|
9384
11684
|
}
|
|
11685
|
+
const selected = selectedElRef.current;
|
|
11686
|
+
if (selected && !footerDragRef.current && !navDragRef.current) {
|
|
11687
|
+
if (selected.hasAttribute("data-ohw-footer-col") || Boolean(selected.closest("footer") && isInferredFooterGroup(selected))) {
|
|
11688
|
+
setSiblingHintRects(
|
|
11689
|
+
listFooterColumns().filter((column) => column !== selected).map((column) => column.getBoundingClientRect())
|
|
11690
|
+
);
|
|
11691
|
+
} else if (isNavigationItem(selected)) {
|
|
11692
|
+
setSiblingHintRects(collectNavigationItemSiblingHintRects(selected));
|
|
11693
|
+
}
|
|
11694
|
+
}
|
|
11695
|
+
if (footerDragRef.current) {
|
|
11696
|
+
const session = footerDragRef.current;
|
|
11697
|
+
const slot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : hitTestColumnDropSlot(session.lastClientX, session.lastClientY);
|
|
11698
|
+
refreshFooterDragVisualsRef.current(session, slot, session.lastClientX, session.lastClientY);
|
|
11699
|
+
}
|
|
11700
|
+
if (navDragRef.current) {
|
|
11701
|
+
const session = navDragRef.current;
|
|
11702
|
+
const slot = hitTestNavDropSlot(session.lastClientX, session.lastClientY, session.hrefKey);
|
|
11703
|
+
refreshNavDragVisualsRef.current(session, slot, session.lastClientX, session.lastClientY);
|
|
11704
|
+
}
|
|
9385
11705
|
if (hoveredImageRef.current) {
|
|
9386
11706
|
const el = hoveredImageRef.current;
|
|
9387
11707
|
const r2 = el.getBoundingClientRect();
|
|
@@ -9392,7 +11712,7 @@ function OhhwellsBridge() {
|
|
|
9392
11712
|
};
|
|
9393
11713
|
const handleSave = (e) => {
|
|
9394
11714
|
if (e.data?.type !== "ow:save") return;
|
|
9395
|
-
const nodes = collectEditableNodes();
|
|
11715
|
+
const nodes = collectEditableNodes(editContentRef.current);
|
|
9396
11716
|
const tracker = document.querySelector("[data-ohw-sections-tracker]");
|
|
9397
11717
|
if (tracker?.textContent) nodes.push({ key: "__ohw_sections", type: "sections", text: tracker.textContent });
|
|
9398
11718
|
postToParentRef.current({ type: "ow:save-result", nodes });
|
|
@@ -9450,30 +11770,30 @@ function OhhwellsBridge() {
|
|
|
9450
11770
|
const h = document.documentElement.scrollHeight;
|
|
9451
11771
|
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
9452
11772
|
};
|
|
11773
|
+
let selectionChangeRaf = null;
|
|
11774
|
+
const runSelectionChange = () => {
|
|
11775
|
+
selectionChangeRaf = null;
|
|
11776
|
+
const activeRoot = activeElRef.current;
|
|
11777
|
+
if (!activeRoot) return;
|
|
11778
|
+
const startEl = resolveSelectionStartElement(window.getSelection());
|
|
11779
|
+
const next = startEl ? detectActiveFormats(startEl, activeRoot) : /* @__PURE__ */ new Set();
|
|
11780
|
+
setActiveCommands((prev) => setsEqual(prev, next) ? prev : next);
|
|
11781
|
+
};
|
|
9453
11782
|
const handleSelectionChange = () => {
|
|
9454
|
-
if (
|
|
9455
|
-
|
|
9456
|
-
|
|
9457
|
-
|
|
9458
|
-
|
|
9459
|
-
|
|
9460
|
-
|
|
9461
|
-
|
|
9462
|
-
|
|
9463
|
-
|
|
9464
|
-
|
|
9465
|
-
|
|
9466
|
-
const block = el?.closest("div, p, h1, h2, h3, h4, h5, h6, li, td, th") ?? el;
|
|
9467
|
-
if (block) {
|
|
9468
|
-
const align = getComputedStyle(block).textAlign;
|
|
9469
|
-
if (align === "center") next.add("justifyCenter");
|
|
9470
|
-
else if (align === "right" || align === "end") next.add("justifyRight");
|
|
9471
|
-
else next.add("justifyLeft");
|
|
9472
|
-
}
|
|
9473
|
-
}
|
|
9474
|
-
setActiveCommands(next);
|
|
11783
|
+
if (pointerHeldRef.current) return;
|
|
11784
|
+
if (selectionChangeRaf !== null) return;
|
|
11785
|
+
selectionChangeRaf = requestAnimationFrame(runSelectionChange);
|
|
11786
|
+
};
|
|
11787
|
+
const markPointerHeld = (e) => {
|
|
11788
|
+
if (e.button !== 0) return;
|
|
11789
|
+
pointerHeldRef.current = true;
|
|
11790
|
+
};
|
|
11791
|
+
const markPointerReleased = () => {
|
|
11792
|
+
if (!pointerHeldRef.current) return;
|
|
11793
|
+
pointerHeldRef.current = false;
|
|
11794
|
+
handleSelectionChange();
|
|
9475
11795
|
};
|
|
9476
|
-
refreshActiveCommandsRef.current =
|
|
11796
|
+
refreshActiveCommandsRef.current = runSelectionChange;
|
|
9477
11797
|
const handleDocMouseLeave = () => {
|
|
9478
11798
|
hoveredImageRef.current = null;
|
|
9479
11799
|
setMediaHover(null);
|
|
@@ -9615,7 +11935,7 @@ function OhhwellsBridge() {
|
|
|
9615
11935
|
}
|
|
9616
11936
|
}
|
|
9617
11937
|
const footerColumn = findHoveredNavOrFooterContainer(clientX, clientY);
|
|
9618
|
-
if (footerColumn?.hasAttribute("data-ohw-footer-column")) {
|
|
11938
|
+
if (footerColumn?.hasAttribute("data-ohw-footer-col") || footerColumn?.hasAttribute("data-ohw-footer-column")) {
|
|
9619
11939
|
selectFrameRef.current(footerColumn);
|
|
9620
11940
|
return;
|
|
9621
11941
|
}
|
|
@@ -9690,7 +12010,161 @@ function OhhwellsBridge() {
|
|
|
9690
12010
|
if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
|
|
9691
12011
|
};
|
|
9692
12012
|
}, [isEditMode, refreshStateRules]);
|
|
9693
|
-
|
|
12013
|
+
useEffect8(() => {
|
|
12014
|
+
if (!isEditMode) return;
|
|
12015
|
+
const THRESHOLD = 10;
|
|
12016
|
+
const resolveWasSelected = (el) => {
|
|
12017
|
+
if (selectedElRef.current === el) return true;
|
|
12018
|
+
const activeAnchor = activeElRef.current ? getNavigationItemAnchor(activeElRef.current) : null;
|
|
12019
|
+
return activeAnchor === el;
|
|
12020
|
+
};
|
|
12021
|
+
const onPointerDown = (e) => {
|
|
12022
|
+
if (e.button !== 0) return;
|
|
12023
|
+
if (suppressNextClickRef.current && Date.now() >= suppressClickUntilRef.current && !footerDragRef.current && !footerPointerDragRef.current?.started) {
|
|
12024
|
+
suppressNextClickRef.current = false;
|
|
12025
|
+
}
|
|
12026
|
+
if (footerDragRef.current) return;
|
|
12027
|
+
const target = e.target;
|
|
12028
|
+
if (!target) return;
|
|
12029
|
+
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]')) {
|
|
12030
|
+
return;
|
|
12031
|
+
}
|
|
12032
|
+
if (target.closest("[data-ohw-item-drag-surface]")) return;
|
|
12033
|
+
const anchor = getNavigationItemAnchor(target);
|
|
12034
|
+
const hrefKey = anchor?.getAttribute("data-ohw-href-key") ?? null;
|
|
12035
|
+
if (anchor && isFooterHrefKey(hrefKey)) {
|
|
12036
|
+
footerPointerDragRef.current = {
|
|
12037
|
+
el: anchor,
|
|
12038
|
+
kind: "link",
|
|
12039
|
+
startX: e.clientX,
|
|
12040
|
+
startY: e.clientY,
|
|
12041
|
+
pointerId: e.pointerId,
|
|
12042
|
+
wasSelected: resolveWasSelected(anchor),
|
|
12043
|
+
started: false
|
|
12044
|
+
};
|
|
12045
|
+
return;
|
|
12046
|
+
}
|
|
12047
|
+
const col = target.closest("[data-ohw-footer-col]");
|
|
12048
|
+
if (col && !getNavigationItemAnchor(target)) {
|
|
12049
|
+
footerPointerDragRef.current = {
|
|
12050
|
+
el: col,
|
|
12051
|
+
kind: "column",
|
|
12052
|
+
startX: e.clientX,
|
|
12053
|
+
startY: e.clientY,
|
|
12054
|
+
pointerId: e.pointerId,
|
|
12055
|
+
wasSelected: resolveWasSelected(col),
|
|
12056
|
+
started: false
|
|
12057
|
+
};
|
|
12058
|
+
}
|
|
12059
|
+
};
|
|
12060
|
+
const onPointerMove = (e) => {
|
|
12061
|
+
const pending = footerPointerDragRef.current;
|
|
12062
|
+
if (!pending) return;
|
|
12063
|
+
if (pending.started) {
|
|
12064
|
+
e.preventDefault();
|
|
12065
|
+
clearTextSelection();
|
|
12066
|
+
const session = footerDragRef.current;
|
|
12067
|
+
if (!session) return;
|
|
12068
|
+
const slot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(e.clientX, e.clientY, session.hrefKey) : hitTestColumnDropSlot(e.clientX, e.clientY);
|
|
12069
|
+
refreshFooterDragVisualsRef.current(session, slot, e.clientX, e.clientY);
|
|
12070
|
+
return;
|
|
12071
|
+
}
|
|
12072
|
+
const dx = e.clientX - pending.startX;
|
|
12073
|
+
const dy = e.clientY - pending.startY;
|
|
12074
|
+
if (dx * dx + dy * dy < THRESHOLD * THRESHOLD) return;
|
|
12075
|
+
e.preventDefault();
|
|
12076
|
+
pending.started = true;
|
|
12077
|
+
armFooterPressDrag();
|
|
12078
|
+
clearTextSelection();
|
|
12079
|
+
try {
|
|
12080
|
+
document.body.setPointerCapture(pending.pointerId);
|
|
12081
|
+
} catch {
|
|
12082
|
+
}
|
|
12083
|
+
if (linkPopoverOpenRef.current) {
|
|
12084
|
+
setLinkPopoverRef.current(null);
|
|
12085
|
+
}
|
|
12086
|
+
if (activeElRef.current) {
|
|
12087
|
+
deactivateRef.current();
|
|
12088
|
+
}
|
|
12089
|
+
if (pending.kind === "link") {
|
|
12090
|
+
const key = pending.el.getAttribute("data-ohw-href-key");
|
|
12091
|
+
if (!key) return;
|
|
12092
|
+
const column = findFooterColumnForLink(pending.el);
|
|
12093
|
+
const columns2 = listFooterColumns();
|
|
12094
|
+
beginFooterDragRef.current({
|
|
12095
|
+
kind: "link",
|
|
12096
|
+
hrefKey: key,
|
|
12097
|
+
columnEl: column,
|
|
12098
|
+
sourceColumnIndex: column ? columns2.indexOf(column) : 0,
|
|
12099
|
+
wasSelected: pending.wasSelected,
|
|
12100
|
+
draggedEl: pending.el,
|
|
12101
|
+
lastClientX: e.clientX,
|
|
12102
|
+
lastClientY: e.clientY,
|
|
12103
|
+
activeSlot: null
|
|
12104
|
+
});
|
|
12105
|
+
return;
|
|
12106
|
+
}
|
|
12107
|
+
const columns = listFooterColumns();
|
|
12108
|
+
const idx = columns.indexOf(pending.el);
|
|
12109
|
+
if (idx < 0) return;
|
|
12110
|
+
beginFooterDragRef.current({
|
|
12111
|
+
kind: "column",
|
|
12112
|
+
hrefKey: null,
|
|
12113
|
+
columnEl: pending.el,
|
|
12114
|
+
sourceColumnIndex: idx,
|
|
12115
|
+
wasSelected: pending.wasSelected,
|
|
12116
|
+
draggedEl: pending.el,
|
|
12117
|
+
lastClientX: e.clientX,
|
|
12118
|
+
lastClientY: e.clientY,
|
|
12119
|
+
activeSlot: null
|
|
12120
|
+
});
|
|
12121
|
+
};
|
|
12122
|
+
const endPointerDrag = (e) => {
|
|
12123
|
+
const pending = footerPointerDragRef.current;
|
|
12124
|
+
footerPointerDragRef.current = null;
|
|
12125
|
+
try {
|
|
12126
|
+
if (document.body.hasPointerCapture(e.pointerId)) {
|
|
12127
|
+
document.body.releasePointerCapture(e.pointerId);
|
|
12128
|
+
}
|
|
12129
|
+
} catch {
|
|
12130
|
+
}
|
|
12131
|
+
if (!pending) return;
|
|
12132
|
+
if (!pending.started) {
|
|
12133
|
+
unlockFooterDragInteraction();
|
|
12134
|
+
return;
|
|
12135
|
+
}
|
|
12136
|
+
suppressNextClickRef.current = true;
|
|
12137
|
+
suppressClickUntilRef.current = Date.now() + 500;
|
|
12138
|
+
commitFooterDragRef.current(e.clientX, e.clientY);
|
|
12139
|
+
};
|
|
12140
|
+
const blockSelectStart = (e) => {
|
|
12141
|
+
if (footerDragRef.current || footerPointerDragRef.current?.started || document.documentElement.hasAttribute("data-ohw-footer-press-drag")) {
|
|
12142
|
+
e.preventDefault();
|
|
12143
|
+
}
|
|
12144
|
+
};
|
|
12145
|
+
const onDragEnd = (_e) => {
|
|
12146
|
+
if (!footerDragRef.current) return;
|
|
12147
|
+
suppressNextClickRef.current = true;
|
|
12148
|
+
suppressClickUntilRef.current = Date.now() + 500;
|
|
12149
|
+
commitFooterDragRef.current();
|
|
12150
|
+
};
|
|
12151
|
+
document.addEventListener("pointerdown", onPointerDown, true);
|
|
12152
|
+
document.addEventListener("pointermove", onPointerMove, true);
|
|
12153
|
+
document.addEventListener("pointerup", endPointerDrag, true);
|
|
12154
|
+
document.addEventListener("pointercancel", endPointerDrag, true);
|
|
12155
|
+
document.addEventListener("selectstart", blockSelectStart, true);
|
|
12156
|
+
document.addEventListener("dragend", onDragEnd, true);
|
|
12157
|
+
return () => {
|
|
12158
|
+
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
12159
|
+
document.removeEventListener("pointermove", onPointerMove, true);
|
|
12160
|
+
document.removeEventListener("pointerup", endPointerDrag, true);
|
|
12161
|
+
document.removeEventListener("pointercancel", endPointerDrag, true);
|
|
12162
|
+
document.removeEventListener("selectstart", blockSelectStart, true);
|
|
12163
|
+
document.removeEventListener("dragend", onDragEnd, true);
|
|
12164
|
+
unlockFooterDragInteraction();
|
|
12165
|
+
};
|
|
12166
|
+
}, [isEditMode]);
|
|
12167
|
+
useEffect8(() => {
|
|
9694
12168
|
const handler = (e) => {
|
|
9695
12169
|
if (e.data?.type !== "ow:request-schedule-config") return;
|
|
9696
12170
|
const insertAfterVal = e.data.insertAfter;
|
|
@@ -9706,7 +12180,7 @@ function OhhwellsBridge() {
|
|
|
9706
12180
|
window.addEventListener("message", handler);
|
|
9707
12181
|
return () => window.removeEventListener("message", handler);
|
|
9708
12182
|
}, [processConfigRequest]);
|
|
9709
|
-
|
|
12183
|
+
useEffect8(() => {
|
|
9710
12184
|
if (!isEditMode) return;
|
|
9711
12185
|
document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
|
|
9712
12186
|
el.removeAttribute("data-ohw-active-state");
|
|
@@ -9727,7 +12201,13 @@ function OhhwellsBridge() {
|
|
|
9727
12201
|
const next = { ...prev, [pathKey]: sections };
|
|
9728
12202
|
return shouldUseDevFixtures() ? { ...DEV_SECTIONS_BY_PATH, ...next } : next;
|
|
9729
12203
|
});
|
|
9730
|
-
postToParent2({
|
|
12204
|
+
postToParent2({
|
|
12205
|
+
type: "ow:ready",
|
|
12206
|
+
version: "1",
|
|
12207
|
+
path: pathname,
|
|
12208
|
+
nodes: collectEditableNodes(editContentRef.current),
|
|
12209
|
+
sections
|
|
12210
|
+
});
|
|
9731
12211
|
postToParent2({ type: "ow:request-site-pages" });
|
|
9732
12212
|
}, 150);
|
|
9733
12213
|
return () => {
|
|
@@ -9735,19 +12215,49 @@ function OhhwellsBridge() {
|
|
|
9735
12215
|
clearTimeout(timer);
|
|
9736
12216
|
};
|
|
9737
12217
|
}, [pathname, isEditMode, refreshStateRules, postToParent2]);
|
|
9738
|
-
|
|
12218
|
+
useEffect8(() => {
|
|
9739
12219
|
scrollToHashSectionWhenReady();
|
|
9740
12220
|
const onHashChange = () => scrollToHashSectionWhenReady();
|
|
9741
12221
|
window.addEventListener("hashchange", onHashChange);
|
|
9742
12222
|
return () => window.removeEventListener("hashchange", onHashChange);
|
|
9743
12223
|
}, [pathname]);
|
|
9744
|
-
const handleCommand =
|
|
12224
|
+
const handleCommand = useCallback5((cmd) => {
|
|
12225
|
+
const el = activeElRef.current;
|
|
12226
|
+
const selBefore = window.getSelection();
|
|
12227
|
+
let savedOffsets = null;
|
|
12228
|
+
if (el && selBefore && selBefore.rangeCount > 0 && !selBefore.isCollapsed) {
|
|
12229
|
+
const r2 = selBefore.getRangeAt(0);
|
|
12230
|
+
if (el.contains(r2.commonAncestorContainer)) {
|
|
12231
|
+
savedOffsets = {
|
|
12232
|
+
start: textOffsetInRoot(el, r2.startContainer, r2.startOffset),
|
|
12233
|
+
end: textOffsetInRoot(el, r2.endContainer, r2.endOffset)
|
|
12234
|
+
};
|
|
12235
|
+
}
|
|
12236
|
+
}
|
|
12237
|
+
document.execCommand("styleWithCSS", false, true);
|
|
9745
12238
|
document.execCommand(cmd, false);
|
|
9746
|
-
|
|
9747
|
-
|
|
12239
|
+
if (el && document.activeElement !== el) {
|
|
12240
|
+
el.focus();
|
|
12241
|
+
}
|
|
12242
|
+
const selAfter = window.getSelection();
|
|
12243
|
+
if (el && savedOffsets && selAfter?.isCollapsed) {
|
|
12244
|
+
const start = pointAtTextOffset(el, savedOffsets.start);
|
|
12245
|
+
const end = pointAtTextOffset(el, savedOffsets.end);
|
|
12246
|
+
if (start && end) {
|
|
12247
|
+
try {
|
|
12248
|
+
const range = document.createRange();
|
|
12249
|
+
range.setStart(start.node, start.offset);
|
|
12250
|
+
range.setEnd(end.node, end.offset);
|
|
12251
|
+
selAfter.removeAllRanges();
|
|
12252
|
+
selAfter.addRange(range);
|
|
12253
|
+
} catch {
|
|
12254
|
+
}
|
|
12255
|
+
}
|
|
12256
|
+
}
|
|
12257
|
+
if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
|
|
9748
12258
|
refreshActiveCommandsRef.current();
|
|
9749
12259
|
}, []);
|
|
9750
|
-
const handleStateChange =
|
|
12260
|
+
const handleStateChange = useCallback5((state) => {
|
|
9751
12261
|
if (!activeStateElRef.current) return;
|
|
9752
12262
|
const el = activeStateElRef.current;
|
|
9753
12263
|
if (state === "Default") {
|
|
@@ -9760,11 +12270,11 @@ function OhhwellsBridge() {
|
|
|
9760
12270
|
}
|
|
9761
12271
|
setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
|
|
9762
12272
|
}, [deactivate]);
|
|
9763
|
-
const closeLinkPopover =
|
|
12273
|
+
const closeLinkPopover = useCallback5(() => {
|
|
9764
12274
|
addNavAfterAnchorRef.current = null;
|
|
9765
12275
|
setLinkPopover(null);
|
|
9766
12276
|
}, []);
|
|
9767
|
-
const openLinkPopoverForActive =
|
|
12277
|
+
const openLinkPopoverForActive = useCallback5(() => {
|
|
9768
12278
|
const hrefCtx = getHrefKeyFromElement(activeElRef.current);
|
|
9769
12279
|
if (!hrefCtx) return;
|
|
9770
12280
|
bumpLinkPopoverGrace();
|
|
@@ -9775,7 +12285,7 @@ function OhhwellsBridge() {
|
|
|
9775
12285
|
});
|
|
9776
12286
|
deactivate();
|
|
9777
12287
|
}, [deactivate]);
|
|
9778
|
-
const openLinkPopoverForSelected =
|
|
12288
|
+
const openLinkPopoverForSelected = useCallback5(() => {
|
|
9779
12289
|
const anchor = selectedElRef.current;
|
|
9780
12290
|
if (!anchor) return;
|
|
9781
12291
|
const key = anchor.getAttribute("data-ohw-href-key");
|
|
@@ -9788,7 +12298,7 @@ function OhhwellsBridge() {
|
|
|
9788
12298
|
});
|
|
9789
12299
|
deselect();
|
|
9790
12300
|
}, [deselect]);
|
|
9791
|
-
const handleLinkPopoverSubmit =
|
|
12301
|
+
const handleLinkPopoverSubmit = useCallback5(
|
|
9792
12302
|
(target) => {
|
|
9793
12303
|
const session = linkPopoverSessionRef.current;
|
|
9794
12304
|
if (!session) return;
|
|
@@ -9847,13 +12357,13 @@ function OhhwellsBridge() {
|
|
|
9847
12357
|
const showEditLink = toolbarShowEditLink;
|
|
9848
12358
|
const currentSections = sectionsByPath[pathname] ?? [];
|
|
9849
12359
|
linkPopoverOpenRef.current = linkPopover !== null;
|
|
9850
|
-
const handleMediaReplace =
|
|
12360
|
+
const handleMediaReplace = useCallback5(
|
|
9851
12361
|
(key) => {
|
|
9852
12362
|
postToParent2({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
|
|
9853
12363
|
},
|
|
9854
12364
|
[postToParent2, mediaHover?.elementType]
|
|
9855
12365
|
);
|
|
9856
|
-
const handleMediaFadeOutComplete =
|
|
12366
|
+
const handleMediaFadeOutComplete = useCallback5((key) => {
|
|
9857
12367
|
setUploadingRects((prev) => {
|
|
9858
12368
|
if (!(key in prev)) return prev;
|
|
9859
12369
|
const next = { ...prev };
|
|
@@ -9861,7 +12371,7 @@ function OhhwellsBridge() {
|
|
|
9861
12371
|
return next;
|
|
9862
12372
|
});
|
|
9863
12373
|
}, []);
|
|
9864
|
-
const handleVideoSettingsChange =
|
|
12374
|
+
const handleVideoSettingsChange = useCallback5(
|
|
9865
12375
|
(key, settings) => {
|
|
9866
12376
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
9867
12377
|
const video = getVideoEl(el);
|
|
@@ -9885,8 +12395,8 @@ function OhhwellsBridge() {
|
|
|
9885
12395
|
);
|
|
9886
12396
|
return bridgeRoot ? createPortal2(
|
|
9887
12397
|
/* @__PURE__ */ jsxs14(Fragment5, { children: [
|
|
9888
|
-
/* @__PURE__ */
|
|
9889
|
-
Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */
|
|
12398
|
+
/* @__PURE__ */ jsx25("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
|
|
12399
|
+
Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ jsx25(
|
|
9890
12400
|
MediaOverlay,
|
|
9891
12401
|
{
|
|
9892
12402
|
hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
|
|
@@ -9897,7 +12407,7 @@ function OhhwellsBridge() {
|
|
|
9897
12407
|
},
|
|
9898
12408
|
`uploading-${key}`
|
|
9899
12409
|
)),
|
|
9900
|
-
mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */
|
|
12410
|
+
mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ jsx25(
|
|
9901
12411
|
MediaOverlay,
|
|
9902
12412
|
{
|
|
9903
12413
|
hover: mediaHover,
|
|
@@ -9906,28 +12416,70 @@ function OhhwellsBridge() {
|
|
|
9906
12416
|
onVideoSettingsChange: handleVideoSettingsChange
|
|
9907
12417
|
}
|
|
9908
12418
|
),
|
|
9909
|
-
siblingHintRect && !isItemDragging && /* @__PURE__ */
|
|
9910
|
-
|
|
9911
|
-
|
|
9912
|
-
|
|
12419
|
+
siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
|
|
12420
|
+
siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
|
|
12421
|
+
isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
|
|
12422
|
+
isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ jsx25(
|
|
12423
|
+
"div",
|
|
9913
12424
|
{
|
|
9914
|
-
|
|
9915
|
-
|
|
9916
|
-
|
|
9917
|
-
|
|
9918
|
-
|
|
9919
|
-
|
|
12425
|
+
className: "pointer-events-none fixed z-2147483646",
|
|
12426
|
+
style: {
|
|
12427
|
+
left: slot.left,
|
|
12428
|
+
top: slot.top,
|
|
12429
|
+
width: slot.width,
|
|
12430
|
+
height: slot.height
|
|
12431
|
+
},
|
|
12432
|
+
children: /* @__PURE__ */ jsx25(
|
|
12433
|
+
DropIndicator,
|
|
12434
|
+
{
|
|
12435
|
+
direction: slot.direction,
|
|
12436
|
+
state: activeFooterDropIndex === i ? "dragActive" : "dragIdle",
|
|
12437
|
+
className: "!h-full !w-full"
|
|
12438
|
+
}
|
|
12439
|
+
)
|
|
12440
|
+
},
|
|
12441
|
+
`footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
|
|
12442
|
+
)),
|
|
12443
|
+
isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ jsx25(
|
|
12444
|
+
"div",
|
|
12445
|
+
{
|
|
12446
|
+
className: "pointer-events-none fixed z-2147483646",
|
|
12447
|
+
style: {
|
|
12448
|
+
left: slot.left,
|
|
12449
|
+
top: slot.top,
|
|
12450
|
+
width: slot.width,
|
|
12451
|
+
height: slot.height
|
|
12452
|
+
},
|
|
12453
|
+
children: /* @__PURE__ */ jsx25(
|
|
12454
|
+
DropIndicator,
|
|
12455
|
+
{
|
|
12456
|
+
direction: slot.direction,
|
|
12457
|
+
state: activeNavDropIndex === i ? "dragActive" : "dragIdle",
|
|
12458
|
+
className: "!h-full !w-full"
|
|
12459
|
+
}
|
|
12460
|
+
)
|
|
12461
|
+
},
|
|
12462
|
+
`nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
|
|
12463
|
+
)),
|
|
12464
|
+
hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
|
|
12465
|
+
hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
|
|
12466
|
+
toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer(selectedElRef.current) && /* @__PURE__ */ jsx25(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
|
|
12467
|
+
toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ jsx25(FooterContainerChrome, { rect: toolbarRect, onAdd: handleAddFooterColumn }),
|
|
12468
|
+
toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ jsx25(
|
|
9920
12469
|
ItemInteractionLayer,
|
|
9921
12470
|
{
|
|
9922
|
-
rect: toolbarRect,
|
|
12471
|
+
rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
|
|
9923
12472
|
elRef: glowElRef,
|
|
9924
12473
|
state: isItemDragging ? "dragging" : resolveItemInteractionState(toolbarRect, parentScrollRef.current),
|
|
9925
|
-
showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey),
|
|
12474
|
+
showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey) || toolbarVariant === "select-frame" && isFooterFrameSelection,
|
|
9926
12475
|
dragDisabled: reorderDragDisabled,
|
|
9927
12476
|
dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
|
|
9928
12477
|
onDragHandleDragStart: handleItemDragStart,
|
|
9929
12478
|
onDragHandleDragEnd: handleItemDragEnd,
|
|
9930
|
-
|
|
12479
|
+
onItemPointerDown: handleItemChromePointerDown,
|
|
12480
|
+
onItemClick: handleItemChromeClick,
|
|
12481
|
+
itemDragSurface: !isFooterFrameSelection,
|
|
12482
|
+
toolbar: toolbarVariant === "link-action" && !isItemDragging ? /* @__PURE__ */ jsx25(
|
|
9931
12483
|
ItemActionToolbar,
|
|
9932
12484
|
{
|
|
9933
12485
|
onEditLink: openLinkPopoverForSelected,
|
|
@@ -9940,17 +12492,18 @@ function OhhwellsBridge() {
|
|
|
9940
12492
|
) : void 0
|
|
9941
12493
|
}
|
|
9942
12494
|
),
|
|
9943
|
-
toolbarRect && toolbarVariant === "rich-text" && /* @__PURE__ */ jsxs14(Fragment5, { children: [
|
|
9944
|
-
/* @__PURE__ */
|
|
12495
|
+
toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ jsxs14(Fragment5, { children: [
|
|
12496
|
+
/* @__PURE__ */ jsx25(
|
|
9945
12497
|
EditGlowChrome,
|
|
9946
12498
|
{
|
|
9947
12499
|
rect: toolbarRect,
|
|
9948
12500
|
elRef: glowElRef,
|
|
9949
12501
|
reorderHrefKey,
|
|
9950
|
-
dragDisabled: reorderDragDisabled
|
|
12502
|
+
dragDisabled: reorderDragDisabled,
|
|
12503
|
+
hideHandle: isItemDragging
|
|
9951
12504
|
}
|
|
9952
12505
|
),
|
|
9953
|
-
/* @__PURE__ */
|
|
12506
|
+
/* @__PURE__ */ jsx25(
|
|
9954
12507
|
FloatingToolbar,
|
|
9955
12508
|
{
|
|
9956
12509
|
rect: toolbarRect,
|
|
@@ -9989,7 +12542,7 @@ function OhhwellsBridge() {
|
|
|
9989
12542
|
]
|
|
9990
12543
|
}
|
|
9991
12544
|
),
|
|
9992
|
-
toggleState && !linkPopover && /* @__PURE__ */
|
|
12545
|
+
toggleState && !linkPopover && /* @__PURE__ */ jsx25(
|
|
9993
12546
|
StateToggle,
|
|
9994
12547
|
{
|
|
9995
12548
|
rect: toggleState.rect,
|
|
@@ -10005,25 +12558,29 @@ function OhhwellsBridge() {
|
|
|
10005
12558
|
className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
|
|
10006
12559
|
style: { top: sectionGap.y, transform: "translateY(-50%)" },
|
|
10007
12560
|
children: [
|
|
10008
|
-
/* @__PURE__ */
|
|
10009
|
-
/* @__PURE__ */
|
|
12561
|
+
/* @__PURE__ */ jsx25("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
|
|
12562
|
+
/* @__PURE__ */ jsx25(
|
|
10010
12563
|
Badge,
|
|
10011
12564
|
{
|
|
10012
12565
|
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",
|
|
10013
12566
|
onClick: () => {
|
|
10014
12567
|
window.parent.postMessage(
|
|
10015
|
-
{
|
|
12568
|
+
{
|
|
12569
|
+
type: "ow:add-section",
|
|
12570
|
+
insertAfter: sectionGap.insertAfter,
|
|
12571
|
+
insertBefore: sectionGap.insertBefore
|
|
12572
|
+
},
|
|
10016
12573
|
"*"
|
|
10017
12574
|
);
|
|
10018
12575
|
},
|
|
10019
12576
|
children: "Add Section"
|
|
10020
12577
|
}
|
|
10021
12578
|
),
|
|
10022
|
-
/* @__PURE__ */
|
|
12579
|
+
/* @__PURE__ */ jsx25("div", { className: "flex-1 bg-primary", style: { height: 3 } })
|
|
10023
12580
|
]
|
|
10024
12581
|
}
|
|
10025
12582
|
),
|
|
10026
|
-
linkPopover && dialogPortalContainer ? /* @__PURE__ */
|
|
12583
|
+
linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx25(
|
|
10027
12584
|
LinkPopover,
|
|
10028
12585
|
{
|
|
10029
12586
|
panelRef: linkPopoverPanelRef,
|
|
@@ -10044,48 +12601,6 @@ function OhhwellsBridge() {
|
|
|
10044
12601
|
bridgeRoot
|
|
10045
12602
|
) : null;
|
|
10046
12603
|
}
|
|
10047
|
-
|
|
10048
|
-
// src/ui/drop-indicator.tsx
|
|
10049
|
-
import * as React11 from "react";
|
|
10050
|
-
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
10051
|
-
var dropIndicatorVariants = cva(
|
|
10052
|
-
"ov-gap-line pointer-events-none shrink-0 transition-opacity duration-150",
|
|
10053
|
-
{
|
|
10054
|
-
variants: {
|
|
10055
|
-
direction: {
|
|
10056
|
-
vertical: "h-6 w-[3px]",
|
|
10057
|
-
horizontal: "h-[3px] w-[200px]"
|
|
10058
|
-
},
|
|
10059
|
-
state: {
|
|
10060
|
-
default: "opacity-0",
|
|
10061
|
-
hover: "opacity-100",
|
|
10062
|
-
dragIdle: "opacity-40",
|
|
10063
|
-
dragActive: "opacity-100"
|
|
10064
|
-
}
|
|
10065
|
-
},
|
|
10066
|
-
defaultVariants: {
|
|
10067
|
-
direction: "vertical",
|
|
10068
|
-
state: "default"
|
|
10069
|
-
}
|
|
10070
|
-
}
|
|
10071
|
-
);
|
|
10072
|
-
var DropIndicator = React11.forwardRef(
|
|
10073
|
-
({ className, direction, state, ...props }, ref) => {
|
|
10074
|
-
return /* @__PURE__ */ jsx24(
|
|
10075
|
-
"div",
|
|
10076
|
-
{
|
|
10077
|
-
ref,
|
|
10078
|
-
"data-slot": "drop-indicator",
|
|
10079
|
-
"data-direction": direction ?? "vertical",
|
|
10080
|
-
"data-state": state ?? "default",
|
|
10081
|
-
"aria-hidden": "true",
|
|
10082
|
-
className: cn(dropIndicatorVariants({ direction, state }), className),
|
|
10083
|
-
...props
|
|
10084
|
-
}
|
|
10085
|
-
);
|
|
10086
|
-
}
|
|
10087
|
-
);
|
|
10088
|
-
DropIndicator.displayName = "DropIndicator";
|
|
10089
12604
|
export {
|
|
10090
12605
|
CustomToolbar,
|
|
10091
12606
|
CustomToolbarButton,
|