@ohhwells/bridge 0.1.41 → 0.1.42-next.101
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 +2984 -468
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +51 -5
- package/dist/index.d.ts +51 -5
- package/dist/index.js +2991 -477
- package/dist/index.js.map +1 -1
- package/dist/styles.css +88 -73
- 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: [
|
|
@@ -4242,7 +4298,8 @@ var CustomToolbar = React4.forwardRef(({ className, onMouseDown, ...props }, ref
|
|
|
4242
4298
|
ref,
|
|
4243
4299
|
"data-ohw-toolbar": "",
|
|
4244
4300
|
className: cn(
|
|
4245
|
-
|
|
4301
|
+
// Figma: bg background, radius 8, gap-1, p-0.5, shadow-md — no border
|
|
4302
|
+
"inline-flex h-8 items-center gap-1 rounded-[var(--radius,0.5rem)] bg-background p-0.5 font-sans whitespace-nowrap shadow-md",
|
|
4246
4303
|
className
|
|
4247
4304
|
),
|
|
4248
4305
|
onMouseDown: (e) => {
|
|
@@ -4270,8 +4327,8 @@ var CustomToolbarButton = React4.forwardRef(
|
|
|
4270
4327
|
ref,
|
|
4271
4328
|
type,
|
|
4272
4329
|
className: cn(
|
|
4273
|
-
"inline-flex shrink-0 items-center justify-center rounded
|
|
4274
|
-
active ? "bg-primary text-primary-foreground" : "bg-transparent
|
|
4330
|
+
"inline-flex size-7 shrink-0 items-center justify-center rounded-[calc(var(--radius,0.5rem)-2px)] text-foreground transition-colors",
|
|
4331
|
+
active ? "bg-primary text-primary-foreground" : "bg-transparent hover:bg-muted disabled:cursor-not-allowed disabled:text-muted-foreground disabled:opacity-60",
|
|
4275
4332
|
className
|
|
4276
4333
|
),
|
|
4277
4334
|
...props
|
|
@@ -4306,9 +4363,10 @@ var arrowClassBySide = {
|
|
|
4306
4363
|
};
|
|
4307
4364
|
function TooltipContent({
|
|
4308
4365
|
className,
|
|
4309
|
-
sideOffset =
|
|
4366
|
+
sideOffset = 9,
|
|
4310
4367
|
side = "bottom",
|
|
4311
4368
|
children,
|
|
4369
|
+
hideArrow,
|
|
4312
4370
|
...props
|
|
4313
4371
|
}) {
|
|
4314
4372
|
const resolvedSide = side ?? "bottom";
|
|
@@ -4319,12 +4377,13 @@ function TooltipContent({
|
|
|
4319
4377
|
side,
|
|
4320
4378
|
sideOffset,
|
|
4321
4379
|
className: cn(
|
|
4322
|
-
"relative z-[2147483647] w-fit max-w-xs rounded-md bg-foreground px-3 py-1.5 text-xs text-background
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
"animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
|
|
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",
|
|
4381
|
+
"origin-[var(--radix-tooltip-content-transform-origin)] animate-in fade-in-0 zoom-in-95",
|
|
4382
|
+
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
|
|
4326
4383
|
"data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2",
|
|
4327
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],
|
|
4328
4387
|
className
|
|
4329
4388
|
),
|
|
4330
4389
|
...props,
|
|
@@ -4345,7 +4404,7 @@ function ToolbarActionTooltip({
|
|
|
4345
4404
|
const button = /* @__PURE__ */ jsx8(CustomToolbarButton, { type: "button", "aria-label": label, disabled, ...buttonProps, children });
|
|
4346
4405
|
return /* @__PURE__ */ jsxs3(Tooltip, { children: [
|
|
4347
4406
|
/* @__PURE__ */ jsx8(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ jsx8("span", { className: "inline-flex", children: button }) : button }),
|
|
4348
|
-
/* @__PURE__ */ jsx8(TooltipContent, { side, children: label })
|
|
4407
|
+
/* @__PURE__ */ jsx8(TooltipContent, { side, sideOffset: 9, children: label })
|
|
4349
4408
|
] });
|
|
4350
4409
|
}
|
|
4351
4410
|
function ItemActionToolbar({
|
|
@@ -4355,6 +4414,8 @@ function ItemActionToolbar({
|
|
|
4355
4414
|
editLinkDisabled = false,
|
|
4356
4415
|
addItemDisabled = true,
|
|
4357
4416
|
moreDisabled = true,
|
|
4417
|
+
showAddItem = true,
|
|
4418
|
+
showMore = true,
|
|
4358
4419
|
tooltipSide = "bottom"
|
|
4359
4420
|
}) {
|
|
4360
4421
|
return /* @__PURE__ */ jsx8(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs3(CustomToolbar, { children: [
|
|
@@ -4379,8 +4440,7 @@ function ItemActionToolbar({
|
|
|
4379
4440
|
children: /* @__PURE__ */ jsx8(Link, { className: "size-4 shrink-0", "aria-hidden": true })
|
|
4380
4441
|
}
|
|
4381
4442
|
),
|
|
4382
|
-
/* @__PURE__ */ jsx8(
|
|
4383
|
-
/* @__PURE__ */ jsx8(
|
|
4443
|
+
showAddItem ? /* @__PURE__ */ jsx8(
|
|
4384
4444
|
ToolbarActionTooltip,
|
|
4385
4445
|
{
|
|
4386
4446
|
label: "Add item",
|
|
@@ -4396,9 +4456,8 @@ function ItemActionToolbar({
|
|
|
4396
4456
|
},
|
|
4397
4457
|
children: /* @__PURE__ */ jsx8(Plus, { className: "size-4 shrink-0", "aria-hidden": true })
|
|
4398
4458
|
}
|
|
4399
|
-
),
|
|
4400
|
-
/* @__PURE__ */ jsx8(
|
|
4401
|
-
/* @__PURE__ */ jsx8(
|
|
4459
|
+
) : null,
|
|
4460
|
+
showMore ? /* @__PURE__ */ jsx8(
|
|
4402
4461
|
ToolbarActionTooltip,
|
|
4403
4462
|
{
|
|
4404
4463
|
label: "More",
|
|
@@ -4414,15 +4473,32 @@ function ItemActionToolbar({
|
|
|
4414
4473
|
},
|
|
4415
4474
|
children: /* @__PURE__ */ jsx8(MoreHorizontal, { className: "size-4 shrink-0", "aria-hidden": true })
|
|
4416
4475
|
}
|
|
4417
|
-
)
|
|
4476
|
+
) : null
|
|
4418
4477
|
] }) });
|
|
4419
4478
|
}
|
|
4420
4479
|
|
|
4421
4480
|
// src/ui/item-interaction-layer.tsx
|
|
4481
|
+
import * as React5 from "react";
|
|
4422
4482
|
import { jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
4423
4483
|
var PRIMARY = "var(--ohw-primary, #0885FE)";
|
|
4424
|
-
var FOCUS_RING =
|
|
4484
|
+
var FOCUS_RING = `0 0 0 4px color-mix(in srgb, ${PRIMARY} 12%, transparent)`;
|
|
4425
4485
|
var DRAG_SHADOW = "0px 4px 6px -1px rgba(0, 0, 0, 0.1), 0px 2px 4px -2px rgba(0, 0, 0, 0.1)";
|
|
4486
|
+
var TOOLBAR_EDGE_MARGIN = 4;
|
|
4487
|
+
var SELECTION_CHROME_GAP = 4;
|
|
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
|
+
}
|
|
4426
4502
|
function getChromeStyle(state) {
|
|
4427
4503
|
switch (state) {
|
|
4428
4504
|
case "hover":
|
|
@@ -4444,12 +4520,65 @@ function getChromeStyle(state) {
|
|
|
4444
4520
|
case "dragging":
|
|
4445
4521
|
return {
|
|
4446
4522
|
border: `2px solid ${PRIMARY}`,
|
|
4447
|
-
boxShadow: DRAG_SHADOW
|
|
4523
|
+
boxShadow: `${FOCUS_RING}, ${DRAG_SHADOW}`
|
|
4448
4524
|
};
|
|
4449
4525
|
default:
|
|
4450
4526
|
return {};
|
|
4451
4527
|
}
|
|
4452
4528
|
}
|
|
4529
|
+
function ClampedToolbarSlot({
|
|
4530
|
+
placement,
|
|
4531
|
+
children
|
|
4532
|
+
}) {
|
|
4533
|
+
const slotRef = React5.useRef(null);
|
|
4534
|
+
React5.useLayoutEffect(() => {
|
|
4535
|
+
const slot = slotRef.current;
|
|
4536
|
+
if (!slot) return;
|
|
4537
|
+
const clamp = () => {
|
|
4538
|
+
const toolbar = slot.firstElementChild;
|
|
4539
|
+
if (!toolbar) return;
|
|
4540
|
+
const w = toolbar.offsetWidth;
|
|
4541
|
+
if (w <= 0) return;
|
|
4542
|
+
const parent = slot.offsetParent;
|
|
4543
|
+
if (!parent) return;
|
|
4544
|
+
const parentRect = parent.getBoundingClientRect();
|
|
4545
|
+
const centerX = parentRect.left + parentRect.width / 2;
|
|
4546
|
+
const half = w / 2;
|
|
4547
|
+
const clampedCenter = Math.max(
|
|
4548
|
+
TOOLBAR_EDGE_MARGIN + half,
|
|
4549
|
+
Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN - half)
|
|
4550
|
+
);
|
|
4551
|
+
const offsetX = clampedCenter - centerX;
|
|
4552
|
+
slot.style.transform = `translateX(calc(-50% + ${offsetX}px))`;
|
|
4553
|
+
};
|
|
4554
|
+
clamp();
|
|
4555
|
+
const ro = new ResizeObserver(clamp);
|
|
4556
|
+
ro.observe(slot);
|
|
4557
|
+
if (slot.firstElementChild) ro.observe(slot.firstElementChild);
|
|
4558
|
+
window.addEventListener("resize", clamp);
|
|
4559
|
+
return () => {
|
|
4560
|
+
ro.disconnect();
|
|
4561
|
+
window.removeEventListener("resize", clamp);
|
|
4562
|
+
};
|
|
4563
|
+
}, [placement, children]);
|
|
4564
|
+
return /* @__PURE__ */ jsx9(
|
|
4565
|
+
"div",
|
|
4566
|
+
{
|
|
4567
|
+
ref: slotRef,
|
|
4568
|
+
className: cn(
|
|
4569
|
+
"pointer-events-auto absolute left-1/2",
|
|
4570
|
+
placement === "top" ? "bottom-full" : "top-full"
|
|
4571
|
+
),
|
|
4572
|
+
style: {
|
|
4573
|
+
marginBottom: placement === "top" ? TOOLBAR_STROKE_GAP : void 0,
|
|
4574
|
+
marginTop: placement === "bottom" ? TOOLBAR_STROKE_GAP : void 0,
|
|
4575
|
+
transform: "translateX(-50%)"
|
|
4576
|
+
},
|
|
4577
|
+
"data-ohw-item-toolbar-anchor": placement,
|
|
4578
|
+
children
|
|
4579
|
+
}
|
|
4580
|
+
);
|
|
4581
|
+
}
|
|
4453
4582
|
function ItemInteractionLayer({
|
|
4454
4583
|
rect,
|
|
4455
4584
|
state,
|
|
@@ -4460,14 +4589,18 @@ function ItemInteractionLayer({
|
|
|
4460
4589
|
dragHandleLabel = "Reorder item",
|
|
4461
4590
|
onDragHandleDragStart,
|
|
4462
4591
|
onDragHandleDragEnd,
|
|
4463
|
-
|
|
4592
|
+
onItemPointerDown,
|
|
4593
|
+
onItemClick,
|
|
4594
|
+
itemDragSurface = true,
|
|
4595
|
+
chromeGap = SELECTION_CHROME_GAP,
|
|
4464
4596
|
className
|
|
4465
4597
|
}) {
|
|
4466
4598
|
if (state === "default") return null;
|
|
4467
4599
|
const isActive = state === "active-top" || state === "active-bottom";
|
|
4468
4600
|
const isDragging = state === "dragging";
|
|
4469
4601
|
const showToolbar = isActive && toolbar;
|
|
4470
|
-
const showDragHandle = isActive
|
|
4602
|
+
const showDragHandle = (isActive || isDragging) && showHandle;
|
|
4603
|
+
const itemDragEnabled = itemDragSurface && isActive && showHandle && !isDragging && !dragDisabled;
|
|
4471
4604
|
return /* @__PURE__ */ jsxs4(
|
|
4472
4605
|
"div",
|
|
4473
4606
|
{
|
|
@@ -4481,7 +4614,7 @@ function ItemInteractionLayer({
|
|
|
4481
4614
|
left: rect.left - chromeGap,
|
|
4482
4615
|
width: rect.width + chromeGap * 2,
|
|
4483
4616
|
height: rect.height + chromeGap * 2,
|
|
4484
|
-
zIndex:
|
|
4617
|
+
zIndex: getChromeZIndex(state)
|
|
4485
4618
|
},
|
|
4486
4619
|
children: [
|
|
4487
4620
|
/* @__PURE__ */ jsx9(
|
|
@@ -4492,11 +4625,29 @@ function ItemInteractionLayer({
|
|
|
4492
4625
|
style: getChromeStyle(state)
|
|
4493
4626
|
}
|
|
4494
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
|
+
),
|
|
4495
4644
|
showDragHandle && /* @__PURE__ */ jsx9(
|
|
4496
4645
|
"div",
|
|
4497
4646
|
{
|
|
4498
4647
|
"data-ohw-drag-handle-container": "",
|
|
4499
|
-
className: "pointer-events-auto absolute left-0 top-1/2 -translate-x-[calc(100%+7px)] -translate-y-1/2",
|
|
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,
|
|
4500
4651
|
children: /* @__PURE__ */ jsx9(
|
|
4501
4652
|
DragHandle,
|
|
4502
4653
|
{
|
|
@@ -4508,7 +4659,17 @@ function ItemInteractionLayer({
|
|
|
4508
4659
|
e.preventDefault();
|
|
4509
4660
|
return;
|
|
4510
4661
|
}
|
|
4511
|
-
|
|
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);
|
|
4512
4673
|
e.dataTransfer.effectAllowed = "move";
|
|
4513
4674
|
onDragHandleDragStart?.(e);
|
|
4514
4675
|
},
|
|
@@ -4517,33 +4678,19 @@ function ItemInteractionLayer({
|
|
|
4517
4678
|
)
|
|
4518
4679
|
}
|
|
4519
4680
|
),
|
|
4520
|
-
showToolbar && state === "active-top" && /* @__PURE__ */ jsx9(
|
|
4521
|
-
|
|
4522
|
-
{
|
|
4523
|
-
className: "pointer-events-auto absolute bottom-full left-1/2 mb-2 -translate-x-1/2",
|
|
4524
|
-
"data-ohw-item-toolbar-anchor": "top",
|
|
4525
|
-
children: toolbar
|
|
4526
|
-
}
|
|
4527
|
-
),
|
|
4528
|
-
showToolbar && state === "active-bottom" && /* @__PURE__ */ jsx9(
|
|
4529
|
-
"div",
|
|
4530
|
-
{
|
|
4531
|
-
className: "pointer-events-auto absolute left-1/2 top-full mt-2 -translate-x-1/2",
|
|
4532
|
-
"data-ohw-item-toolbar-anchor": "bottom",
|
|
4533
|
-
children: toolbar
|
|
4534
|
-
}
|
|
4535
|
-
)
|
|
4681
|
+
showToolbar && state === "active-top" && /* @__PURE__ */ jsx9(ClampedToolbarSlot, { placement: "top", children: toolbar }),
|
|
4682
|
+
showToolbar && state === "active-bottom" && /* @__PURE__ */ jsx9(ClampedToolbarSlot, { placement: "bottom", children: toolbar })
|
|
4536
4683
|
]
|
|
4537
4684
|
}
|
|
4538
4685
|
);
|
|
4539
4686
|
}
|
|
4540
4687
|
|
|
4541
4688
|
// src/ui/MediaOverlay.tsx
|
|
4542
|
-
import * as
|
|
4689
|
+
import * as React7 from "react";
|
|
4543
4690
|
import { Film, ImageIcon, Pause, Play, Volume2, VolumeX } from "lucide-react";
|
|
4544
4691
|
|
|
4545
4692
|
// src/ui/button.tsx
|
|
4546
|
-
import * as
|
|
4693
|
+
import * as React6 from "react";
|
|
4547
4694
|
import { Slot } from "radix-ui";
|
|
4548
4695
|
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
4549
4696
|
var buttonVariants = cva(
|
|
@@ -4566,7 +4713,7 @@ var buttonVariants = cva(
|
|
|
4566
4713
|
}
|
|
4567
4714
|
}
|
|
4568
4715
|
);
|
|
4569
|
-
var Button =
|
|
4716
|
+
var Button = React6.forwardRef(
|
|
4570
4717
|
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
4571
4718
|
const Comp = asChild ? Slot.Root : "button";
|
|
4572
4719
|
return /* @__PURE__ */ jsx10(
|
|
@@ -4618,7 +4765,7 @@ function MediaOverlay({
|
|
|
4618
4765
|
onVideoSettingsChange
|
|
4619
4766
|
}) {
|
|
4620
4767
|
const { rect } = hover;
|
|
4621
|
-
const skeletonRef =
|
|
4768
|
+
const skeletonRef = React7.useRef(null);
|
|
4622
4769
|
const isVideo = hover.elementType === "video";
|
|
4623
4770
|
const autoplay = hover.videoAutoplay ?? true;
|
|
4624
4771
|
const muted = hover.videoMuted ?? true;
|
|
@@ -4630,7 +4777,7 @@ function MediaOverlay({
|
|
|
4630
4777
|
height: rect.height,
|
|
4631
4778
|
zIndex: 2147483646
|
|
4632
4779
|
};
|
|
4633
|
-
|
|
4780
|
+
React7.useEffect(() => {
|
|
4634
4781
|
if (!isUploading || !fadingOut || !skeletonRef.current) return;
|
|
4635
4782
|
const anim = skeletonRef.current.animate([{ opacity: 1 }, { opacity: 0 }], {
|
|
4636
4783
|
duration: MEDIA_UPLOAD_FADE_MS,
|
|
@@ -5035,7 +5182,7 @@ function scrollToHashSectionWhenReady(behavior = "smooth") {
|
|
|
5035
5182
|
import { useEffect as useEffect6 } from "react";
|
|
5036
5183
|
|
|
5037
5184
|
// src/ui/dialog.tsx
|
|
5038
|
-
import * as
|
|
5185
|
+
import * as React8 from "react";
|
|
5039
5186
|
import { Dialog as DialogPrimitive } from "radix-ui";
|
|
5040
5187
|
import { X } from "lucide-react";
|
|
5041
5188
|
import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
@@ -5063,7 +5210,7 @@ function DialogOverlay({
|
|
|
5063
5210
|
}
|
|
5064
5211
|
);
|
|
5065
5212
|
}
|
|
5066
|
-
var DialogContent =
|
|
5213
|
+
var DialogContent = React8.forwardRef(
|
|
5067
5214
|
({ className, children, showCloseButton = true, container, ...props }, ref) => {
|
|
5068
5215
|
const positionMode = container ? "absolute" : "fixed";
|
|
5069
5216
|
return /* @__PURE__ */ jsxs6(DialogPortal, { container: container ?? void 0, children: [
|
|
@@ -5118,7 +5265,7 @@ function DialogFooter({
|
|
|
5118
5265
|
}
|
|
5119
5266
|
);
|
|
5120
5267
|
}
|
|
5121
|
-
var DialogTitle =
|
|
5268
|
+
var DialogTitle = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx12(
|
|
5122
5269
|
DialogPrimitive.Title,
|
|
5123
5270
|
{
|
|
5124
5271
|
ref,
|
|
@@ -5130,7 +5277,7 @@ var DialogTitle = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE
|
|
|
5130
5277
|
}
|
|
5131
5278
|
));
|
|
5132
5279
|
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
|
5133
|
-
var DialogDescription =
|
|
5280
|
+
var DialogDescription = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx12(
|
|
5134
5281
|
DialogPrimitive.Description,
|
|
5135
5282
|
{
|
|
5136
5283
|
ref,
|
|
@@ -5232,12 +5379,12 @@ function SectionTreeItem({
|
|
|
5232
5379
|
}
|
|
5233
5380
|
|
|
5234
5381
|
// src/ui/link-modal/UrlOrPageInput.tsx
|
|
5235
|
-
import { useEffect as useEffect3, useId as useId2, useRef as
|
|
5382
|
+
import { useEffect as useEffect3, useId as useId2, useRef as useRef4, useState as useState3 } from "react";
|
|
5236
5383
|
|
|
5237
5384
|
// src/ui/input.tsx
|
|
5238
|
-
import * as
|
|
5385
|
+
import * as React9 from "react";
|
|
5239
5386
|
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
5240
|
-
var Input =
|
|
5387
|
+
var Input = React9.forwardRef(
|
|
5241
5388
|
({ className, type, ...props }, ref) => {
|
|
5242
5389
|
return /* @__PURE__ */ jsx15(
|
|
5243
5390
|
"input",
|
|
@@ -5301,8 +5448,8 @@ function UrlOrPageInput({
|
|
|
5301
5448
|
urlError
|
|
5302
5449
|
}) {
|
|
5303
5450
|
const inputId = useId2();
|
|
5304
|
-
const inputRef =
|
|
5305
|
-
const rootRef =
|
|
5451
|
+
const inputRef = useRef4(null);
|
|
5452
|
+
const rootRef = useRef4(null);
|
|
5306
5453
|
const [isFocused, setIsFocused] = useState3(false);
|
|
5307
5454
|
useEffect3(() => {
|
|
5308
5455
|
if (!dropdownOpen) return;
|
|
@@ -5512,7 +5659,7 @@ function LinkEditorPanel({ state, onClose }) {
|
|
|
5512
5659
|
}
|
|
5513
5660
|
|
|
5514
5661
|
// src/ui/link-modal/SectionPickerOverlay.tsx
|
|
5515
|
-
import { useCallback, useEffect as useEffect4, useMemo as useMemo2, useRef as
|
|
5662
|
+
import { useCallback as useCallback2, useEffect as useEffect4, useMemo as useMemo2, useRef as useRef5, useState as useState4 } from "react";
|
|
5516
5663
|
import { createPortal } from "react-dom";
|
|
5517
5664
|
import { ArrowLeft, Check } from "lucide-react";
|
|
5518
5665
|
import { usePathname, useRouter } from "next/navigation";
|
|
@@ -5597,10 +5744,10 @@ function SectionPickerOverlay({
|
|
|
5597
5744
|
const pathname = usePathname();
|
|
5598
5745
|
const [selectedId, setSelectedId] = useState4(null);
|
|
5599
5746
|
const [hoveredId, setHoveredId] = useState4(null);
|
|
5600
|
-
const pointerRef =
|
|
5601
|
-
const pointerScreenRef =
|
|
5602
|
-
const iframeOffsetTopRef =
|
|
5603
|
-
const sectionIdsRef =
|
|
5747
|
+
const pointerRef = useRef5(null);
|
|
5748
|
+
const pointerScreenRef = useRef5(null);
|
|
5749
|
+
const iframeOffsetTopRef = useRef5(null);
|
|
5750
|
+
const sectionIdsRef = useRef5([]);
|
|
5604
5751
|
const [chromeClip, setChromeClip] = useState4(
|
|
5605
5752
|
() => ({
|
|
5606
5753
|
top: 0,
|
|
@@ -5643,7 +5790,7 @@ function SectionPickerOverlay({
|
|
|
5643
5790
|
);
|
|
5644
5791
|
sectionIdsRef.current = sectionIds;
|
|
5645
5792
|
const rects = useSectionRects(sectionIdsKey, isOnTargetPage);
|
|
5646
|
-
const applyHoverAt =
|
|
5793
|
+
const applyHoverAt = useCallback2(
|
|
5647
5794
|
(x, y, liveRects) => {
|
|
5648
5795
|
const ids = sectionIdsRef.current;
|
|
5649
5796
|
const map = liveRects ?? readSectionRects(ids);
|
|
@@ -5723,7 +5870,7 @@ function SectionPickerOverlay({
|
|
|
5723
5870
|
window.removeEventListener("message", onPointerSync);
|
|
5724
5871
|
};
|
|
5725
5872
|
}, [rects, applyHoverAt]);
|
|
5726
|
-
const handleSelect =
|
|
5873
|
+
const handleSelect = useCallback2(
|
|
5727
5874
|
(section) => {
|
|
5728
5875
|
if (selectedId) return;
|
|
5729
5876
|
setSelectedId(section.id);
|
|
@@ -5792,8 +5939,8 @@ function SectionPickerOverlay({
|
|
|
5792
5939
|
!isOnTargetPage ? /* @__PURE__ */ jsx19(
|
|
5793
5940
|
"div",
|
|
5794
5941
|
{
|
|
5795
|
-
className: "pointer-events-none fixed left-1/2 z-[1] -translate-x-1/2 rounded-md
|
|
5796
|
-
style: { top: chromeClip.top + 64 },
|
|
5942
|
+
className: "pointer-events-none fixed left-1/2 z-[1] -translate-x-1/2 rounded-md px-3 py-2 text-sm text-muted-foreground shadow-sm",
|
|
5943
|
+
style: { top: chromeClip.top + 64, backgroundColor: "var(--ohw-background, #ffffff)" },
|
|
5797
5944
|
children: "Loading page preview\u2026"
|
|
5798
5945
|
}
|
|
5799
5946
|
) : null,
|
|
@@ -5854,7 +6001,7 @@ function SectionPickerOverlay({
|
|
|
5854
6001
|
}
|
|
5855
6002
|
|
|
5856
6003
|
// src/ui/link-modal/useLinkModalState.ts
|
|
5857
|
-
import { useCallback as
|
|
6004
|
+
import { useCallback as useCallback3, useEffect as useEffect5, useMemo as useMemo3, useState as useState5 } from "react";
|
|
5858
6005
|
function useLinkModalState({
|
|
5859
6006
|
open,
|
|
5860
6007
|
mode,
|
|
@@ -5873,7 +6020,7 @@ function useLinkModalState({
|
|
|
5873
6020
|
const [step, setStep] = useState5("input");
|
|
5874
6021
|
const [dropdownOpen, setDropdownOpen] = useState5(false);
|
|
5875
6022
|
const [urlError, setUrlError] = useState5("");
|
|
5876
|
-
const reset =
|
|
6023
|
+
const reset = useCallback3(() => {
|
|
5877
6024
|
setSearchValue("");
|
|
5878
6025
|
setSelectedPage(null);
|
|
5879
6026
|
setSelectedSection(null);
|
|
@@ -6218,9 +6365,155 @@ function shouldUseDevFixtures() {
|
|
|
6218
6365
|
return new URLSearchParams(q).get("ohw-fixtures") === "1";
|
|
6219
6366
|
}
|
|
6220
6367
|
|
|
6368
|
+
// src/lib/nav-tree.ts
|
|
6369
|
+
var MAX_LEVEL = { nav: 1 };
|
|
6370
|
+
var ROOT = null;
|
|
6371
|
+
function cloneForest(nodes) {
|
|
6372
|
+
return nodes.map((n) => ({ id: n.id, children: cloneForest(n.children) }));
|
|
6373
|
+
}
|
|
6374
|
+
function findNode(nodes, id, parentId = ROOT) {
|
|
6375
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
6376
|
+
const node = nodes[i];
|
|
6377
|
+
if (node.id === id) return { node, parentId, index: i, siblings: nodes };
|
|
6378
|
+
const nested = findNode(node.children, id, node.id);
|
|
6379
|
+
if (nested) return nested;
|
|
6380
|
+
}
|
|
6381
|
+
return null;
|
|
6382
|
+
}
|
|
6383
|
+
function getChildrenOf(nodes, parentId) {
|
|
6384
|
+
if (parentId === ROOT) return nodes;
|
|
6385
|
+
const found = findNode(nodes, parentId);
|
|
6386
|
+
return found ? found.node.children : null;
|
|
6387
|
+
}
|
|
6388
|
+
function isDescendant(nodes, ancestorId, maybeDescendantId) {
|
|
6389
|
+
const found = findNode(nodes, ancestorId);
|
|
6390
|
+
if (!found) return false;
|
|
6391
|
+
return findNode(found.node.children, maybeDescendantId) !== null;
|
|
6392
|
+
}
|
|
6393
|
+
function levelOf(nodes, id) {
|
|
6394
|
+
const loc = findNode(nodes, id);
|
|
6395
|
+
if (!loc) return -1;
|
|
6396
|
+
if (loc.parentId === ROOT) return 0;
|
|
6397
|
+
return 1 + Math.max(0, levelOf(nodes, loc.parentId));
|
|
6398
|
+
}
|
|
6399
|
+
function insertedLevel(nodes, parentId) {
|
|
6400
|
+
if (parentId === ROOT) return 0;
|
|
6401
|
+
const parentLevel = levelOf(nodes, parentId);
|
|
6402
|
+
if (parentLevel < 0) return -1;
|
|
6403
|
+
return parentLevel + 1;
|
|
6404
|
+
}
|
|
6405
|
+
function takeNode(nodes, id) {
|
|
6406
|
+
const forest = cloneForest(nodes);
|
|
6407
|
+
const loc = findNode(forest, id);
|
|
6408
|
+
if (!loc) return null;
|
|
6409
|
+
const [taken] = loc.siblings.splice(loc.index, 1);
|
|
6410
|
+
if (!taken) return null;
|
|
6411
|
+
return { forest, taken };
|
|
6412
|
+
}
|
|
6413
|
+
function insertInto(forest, node, parentId, index) {
|
|
6414
|
+
const siblings = getChildrenOf(forest, parentId);
|
|
6415
|
+
if (!siblings) return false;
|
|
6416
|
+
const clamped = Math.max(0, Math.min(index, siblings.length));
|
|
6417
|
+
siblings.splice(clamped, 0, node);
|
|
6418
|
+
return true;
|
|
6419
|
+
}
|
|
6420
|
+
function normalize(nodes) {
|
|
6421
|
+
const walk = (list) => list.map((n) => {
|
|
6422
|
+
const children = walk(n.children);
|
|
6423
|
+
return { id: n.id, children };
|
|
6424
|
+
});
|
|
6425
|
+
return walk(nodes);
|
|
6426
|
+
}
|
|
6427
|
+
function moveNode(model, draggedId, target) {
|
|
6428
|
+
const { parentId, index: targetIndex } = target;
|
|
6429
|
+
if (parentId === draggedId) return null;
|
|
6430
|
+
if (parentId !== ROOT && isDescendant(model, draggedId, parentId)) return null;
|
|
6431
|
+
const nextLevel = insertedLevel(model, parentId);
|
|
6432
|
+
if (nextLevel < 0 || nextLevel > MAX_LEVEL.nav) return null;
|
|
6433
|
+
const draggedLoc = findNode(model, draggedId);
|
|
6434
|
+
if (!draggedLoc) return null;
|
|
6435
|
+
if (parentId !== ROOT && draggedLoc.node.children.length > 0) return null;
|
|
6436
|
+
const taken = takeNode(model, draggedId);
|
|
6437
|
+
if (!taken) return null;
|
|
6438
|
+
let insertIndex = targetIndex;
|
|
6439
|
+
if (draggedLoc.parentId === parentId && draggedLoc.index < targetIndex) {
|
|
6440
|
+
insertIndex -= 1;
|
|
6441
|
+
}
|
|
6442
|
+
if (!insertInto(taken.forest, taken.taken, parentId, insertIndex)) return null;
|
|
6443
|
+
const next = normalize(taken.forest);
|
|
6444
|
+
if (forestsEqual(model, next)) return null;
|
|
6445
|
+
return next;
|
|
6446
|
+
}
|
|
6447
|
+
function forestsEqual(a, b) {
|
|
6448
|
+
if (a.length !== b.length) return false;
|
|
6449
|
+
for (let i = 0; i < a.length; i++) {
|
|
6450
|
+
const left = a[i];
|
|
6451
|
+
const right = b[i];
|
|
6452
|
+
if (left.id !== right.id) return false;
|
|
6453
|
+
if (!forestsEqual(left.children, right.children)) return false;
|
|
6454
|
+
}
|
|
6455
|
+
return true;
|
|
6456
|
+
}
|
|
6457
|
+
function forestFromFlatOrder(order) {
|
|
6458
|
+
return order.map((id) => ({ id, children: [] }));
|
|
6459
|
+
}
|
|
6460
|
+
function serializeNavOrder(nodes) {
|
|
6461
|
+
const hasNesting = nodes.some((n) => n.children.length > 0);
|
|
6462
|
+
if (!hasNesting) {
|
|
6463
|
+
return JSON.stringify(nodes.map((n) => n.id));
|
|
6464
|
+
}
|
|
6465
|
+
return JSON.stringify(nodes);
|
|
6466
|
+
}
|
|
6467
|
+
function parseNavOrderJson(raw) {
|
|
6468
|
+
if (!raw) return null;
|
|
6469
|
+
try {
|
|
6470
|
+
const parsed = JSON.parse(raw);
|
|
6471
|
+
if (!Array.isArray(parsed)) return null;
|
|
6472
|
+
if (parsed.every((x) => typeof x === "string")) {
|
|
6473
|
+
return forestFromFlatOrder(parsed.filter((x) => typeof x === "string" && x.length > 0));
|
|
6474
|
+
}
|
|
6475
|
+
return parseNavNodeList(parsed);
|
|
6476
|
+
} catch {
|
|
6477
|
+
return null;
|
|
6478
|
+
}
|
|
6479
|
+
}
|
|
6480
|
+
function parseNavNodeList(raw) {
|
|
6481
|
+
const out = [];
|
|
6482
|
+
for (const item of raw) {
|
|
6483
|
+
if (typeof item === "string" && item.length > 0) {
|
|
6484
|
+
out.push({ id: item, children: [] });
|
|
6485
|
+
continue;
|
|
6486
|
+
}
|
|
6487
|
+
if (!item || typeof item !== "object") return null;
|
|
6488
|
+
const rec = item;
|
|
6489
|
+
if (typeof rec.id !== "string" || !rec.id) return null;
|
|
6490
|
+
const children = Array.isArray(rec.children) ? parseNavNodeList(rec.children) : [];
|
|
6491
|
+
if (!children) return null;
|
|
6492
|
+
out.push({ id: rec.id, children });
|
|
6493
|
+
}
|
|
6494
|
+
return out;
|
|
6495
|
+
}
|
|
6496
|
+
function flattenNavOrder(nodes) {
|
|
6497
|
+
const out = [];
|
|
6498
|
+
const walk = (list) => {
|
|
6499
|
+
for (const n of list) {
|
|
6500
|
+
out.push(n.id);
|
|
6501
|
+
walk(n.children);
|
|
6502
|
+
}
|
|
6503
|
+
};
|
|
6504
|
+
walk(nodes);
|
|
6505
|
+
return out;
|
|
6506
|
+
}
|
|
6507
|
+
|
|
6221
6508
|
// src/lib/nav-items.ts
|
|
6222
6509
|
var NAV_COUNT_KEY = "__ohw_nav_count";
|
|
6223
6510
|
var NAV_ORDER_KEY = "__ohw_nav_order";
|
|
6511
|
+
var NAV_HREF_RE = /^nav-(\d+)-href$/;
|
|
6512
|
+
function isNavbarHrefKey(key) {
|
|
6513
|
+
if (!key) return false;
|
|
6514
|
+
if (key === "nav-book-href") return false;
|
|
6515
|
+
return NAV_HREF_RE.test(key);
|
|
6516
|
+
}
|
|
6224
6517
|
function getLinkHref(el) {
|
|
6225
6518
|
const key = el.getAttribute("data-ohw-href-key");
|
|
6226
6519
|
if (key) {
|
|
@@ -6257,7 +6550,7 @@ function listNavbarItems() {
|
|
|
6257
6550
|
}
|
|
6258
6551
|
function parseNavIndexFromKey(key) {
|
|
6259
6552
|
if (!key) return null;
|
|
6260
|
-
const match = key.match(
|
|
6553
|
+
const match = key.match(NAV_HREF_RE);
|
|
6261
6554
|
if (!match) return null;
|
|
6262
6555
|
return parseInt(match[1], 10);
|
|
6263
6556
|
}
|
|
@@ -6280,17 +6573,6 @@ function getNavbarExistingTargets() {
|
|
|
6280
6573
|
function getNavOrderFromDom() {
|
|
6281
6574
|
return listNavbarItems().map((el) => el.getAttribute("data-ohw-href-key")).filter((key) => Boolean(key));
|
|
6282
6575
|
}
|
|
6283
|
-
function parseNavOrder(content) {
|
|
6284
|
-
const raw = content[NAV_ORDER_KEY];
|
|
6285
|
-
if (!raw) return null;
|
|
6286
|
-
try {
|
|
6287
|
-
const parsed = JSON.parse(raw);
|
|
6288
|
-
if (!Array.isArray(parsed)) return null;
|
|
6289
|
-
return parsed.filter((key) => typeof key === "string" && key.length > 0);
|
|
6290
|
-
} catch {
|
|
6291
|
-
return null;
|
|
6292
|
-
}
|
|
6293
|
-
}
|
|
6294
6576
|
function findCounterpartByHrefKey(hrefKey, root) {
|
|
6295
6577
|
return root.querySelector(`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`);
|
|
6296
6578
|
}
|
|
@@ -6354,19 +6636,47 @@ function insertNavbarItemDom(index, href, label, afterAnchor) {
|
|
|
6354
6636
|
}
|
|
6355
6637
|
return primary;
|
|
6356
6638
|
}
|
|
6639
|
+
function navOrderKeysEqual(a, b) {
|
|
6640
|
+
if (a.length !== b.length) return false;
|
|
6641
|
+
for (let i = 0; i < a.length; i++) {
|
|
6642
|
+
if (a[i] !== b[i]) return false;
|
|
6643
|
+
}
|
|
6644
|
+
return true;
|
|
6645
|
+
}
|
|
6646
|
+
function getNavbarLinkKeysInContainer(container) {
|
|
6647
|
+
return Array.from(container.querySelectorAll("[data-ohw-href-key]")).filter(isNavbarLinkItem).map((el) => el.getAttribute("data-ohw-href-key")).filter((key) => Boolean(key));
|
|
6648
|
+
}
|
|
6357
6649
|
function applyNavOrderToContainer(container, order) {
|
|
6650
|
+
const desired = order.filter((key, i) => order.indexOf(key) === i);
|
|
6651
|
+
const current = getNavbarLinkKeysInContainer(container);
|
|
6652
|
+
const extras = current.filter((key) => !desired.includes(key));
|
|
6653
|
+
const expected = [...desired.filter((key) => current.includes(key)), ...extras];
|
|
6654
|
+
const orderedEls = [];
|
|
6655
|
+
if (navOrderKeysEqual(current, expected)) return;
|
|
6656
|
+
if (current.length === expected.length && current.every((key, i) => key === expected[i])) {
|
|
6657
|
+
return;
|
|
6658
|
+
}
|
|
6659
|
+
const lastCurrentLinkEl = current.length > 0 ? findCounterpartByHrefKey(current[current.length - 1], container) : null;
|
|
6660
|
+
const anchor = lastCurrentLinkEl?.parentElement === container ? lastCurrentLinkEl.nextElementSibling : null;
|
|
6358
6661
|
const seen = /* @__PURE__ */ new Set();
|
|
6359
|
-
for (const hrefKey of
|
|
6662
|
+
for (const hrefKey of desired) {
|
|
6360
6663
|
if (seen.has(hrefKey)) continue;
|
|
6361
6664
|
seen.add(hrefKey);
|
|
6362
6665
|
const el = findCounterpartByHrefKey(hrefKey, container);
|
|
6363
|
-
if (el)
|
|
6666
|
+
if (el && isNavbarLinkItem(el)) orderedEls.push(el);
|
|
6364
6667
|
}
|
|
6365
6668
|
for (const el of container.querySelectorAll("[data-ohw-href-key]")) {
|
|
6366
6669
|
if (!isNavbarLinkItem(el)) continue;
|
|
6367
6670
|
const key = el.getAttribute("data-ohw-href-key");
|
|
6368
6671
|
if (!key || seen.has(key)) continue;
|
|
6369
|
-
|
|
6672
|
+
orderedEls.push(el);
|
|
6673
|
+
}
|
|
6674
|
+
for (const el of orderedEls) {
|
|
6675
|
+
if (anchor) {
|
|
6676
|
+
if (el.nextSibling !== anchor) container.insertBefore(el, anchor);
|
|
6677
|
+
} else if (container.lastElementChild !== el) {
|
|
6678
|
+
container.appendChild(el);
|
|
6679
|
+
}
|
|
6370
6680
|
}
|
|
6371
6681
|
}
|
|
6372
6682
|
function applyNavOrder(order) {
|
|
@@ -6375,6 +6685,75 @@ function applyNavOrder(order) {
|
|
|
6375
6685
|
const drawer = getNavbarDrawerContainer();
|
|
6376
6686
|
if (drawer) applyNavOrderToContainer(drawer, order);
|
|
6377
6687
|
}
|
|
6688
|
+
function applyChildrenOrder(parentHrefKey, childKeys, root) {
|
|
6689
|
+
const parent = findCounterpartByHrefKey(parentHrefKey, root);
|
|
6690
|
+
if (!parent) return;
|
|
6691
|
+
const group = parent.closest("[data-ohw-nav-group]");
|
|
6692
|
+
const childrenRoot = group?.querySelector(":scope > [data-ohw-nav-children]");
|
|
6693
|
+
if (!childrenRoot) return;
|
|
6694
|
+
const current = Array.from(childrenRoot.querySelectorAll(":scope > [data-ohw-href-key]")).map((el) => el.getAttribute("data-ohw-href-key")).filter((key) => Boolean(key));
|
|
6695
|
+
if (navOrderKeysEqual(current, childKeys)) return;
|
|
6696
|
+
for (const key of childKeys) {
|
|
6697
|
+
const el = findCounterpartByHrefKey(key, root);
|
|
6698
|
+
if (!el) continue;
|
|
6699
|
+
if (childrenRoot.lastElementChild !== el) {
|
|
6700
|
+
childrenRoot.appendChild(el);
|
|
6701
|
+
}
|
|
6702
|
+
}
|
|
6703
|
+
}
|
|
6704
|
+
function applyNavForest(forest) {
|
|
6705
|
+
if (forestsEqual(forest, getNavForestFromDom())) return;
|
|
6706
|
+
const rootKeys = forest.map((n) => n.id);
|
|
6707
|
+
applyNavOrder(rootKeys);
|
|
6708
|
+
const desktop = getNavbarDesktopContainer();
|
|
6709
|
+
const drawer = getNavbarDrawerContainer();
|
|
6710
|
+
for (const node of forest) {
|
|
6711
|
+
if (node.children.length === 0) continue;
|
|
6712
|
+
const childKeys = node.children.map((c) => c.id);
|
|
6713
|
+
if (desktop) applyChildrenOrder(node.id, childKeys, desktop);
|
|
6714
|
+
if (drawer) applyChildrenOrder(node.id, childKeys, drawer);
|
|
6715
|
+
}
|
|
6716
|
+
}
|
|
6717
|
+
function getNavForestFromDom() {
|
|
6718
|
+
const items = listNavbarItems();
|
|
6719
|
+
const nestedChildKeys = /* @__PURE__ */ new Set();
|
|
6720
|
+
const roots = [];
|
|
6721
|
+
for (const item of items) {
|
|
6722
|
+
const key = item.getAttribute("data-ohw-href-key");
|
|
6723
|
+
if (!key || !isNavbarHrefKey(key)) continue;
|
|
6724
|
+
if (item.closest("[data-ohw-nav-children]")) continue;
|
|
6725
|
+
const group = item.closest("[data-ohw-nav-group]");
|
|
6726
|
+
const childrenRoot = group?.querySelector(":scope > [data-ohw-nav-children]");
|
|
6727
|
+
const children = [];
|
|
6728
|
+
if (childrenRoot) {
|
|
6729
|
+
for (const child of childrenRoot.querySelectorAll(":scope > [data-ohw-href-key]")) {
|
|
6730
|
+
if (!isNavbarLinkItem(child)) continue;
|
|
6731
|
+
const childKey = child.getAttribute("data-ohw-href-key");
|
|
6732
|
+
if (!childKey || !isNavbarHrefKey(childKey)) continue;
|
|
6733
|
+
nestedChildKeys.add(childKey);
|
|
6734
|
+
children.push({ id: childKey, children: [] });
|
|
6735
|
+
}
|
|
6736
|
+
}
|
|
6737
|
+
roots.push({ id: key, children });
|
|
6738
|
+
}
|
|
6739
|
+
if (roots.length === 0) {
|
|
6740
|
+
return forestFromFlatOrder(
|
|
6741
|
+
getNavOrderFromDom().filter((k) => isNavbarHrefKey(k) && !nestedChildKeys.has(k))
|
|
6742
|
+
);
|
|
6743
|
+
}
|
|
6744
|
+
return roots;
|
|
6745
|
+
}
|
|
6746
|
+
function planNavItemMove(hrefKey, parentId, insertIndex) {
|
|
6747
|
+
const model = getNavForestFromDom();
|
|
6748
|
+
const next = moveNode(model, hrefKey, { parentId, index: insertIndex });
|
|
6749
|
+
if (!next) return null;
|
|
6750
|
+
if (forestsEqual(model, next)) return null;
|
|
6751
|
+
return {
|
|
6752
|
+
forest: next,
|
|
6753
|
+
orderJson: serializeNavOrder(next),
|
|
6754
|
+
flatOrder: flattenNavOrder(next)
|
|
6755
|
+
};
|
|
6756
|
+
}
|
|
6378
6757
|
function collectNavbarIndicesFromContent(content) {
|
|
6379
6758
|
const indices = /* @__PURE__ */ new Set();
|
|
6380
6759
|
for (const key of Object.keys(content)) {
|
|
@@ -6402,8 +6781,10 @@ function reconcileNavbarItemsFromContent(content) {
|
|
|
6402
6781
|
if (!href && !label) continue;
|
|
6403
6782
|
insertNavbarItemDom(index, href ?? "/", label ?? "Untitled", null);
|
|
6404
6783
|
}
|
|
6405
|
-
const
|
|
6406
|
-
if (
|
|
6784
|
+
const orderForest = parseNavOrderJson(content[NAV_ORDER_KEY]);
|
|
6785
|
+
if (orderForest?.length) {
|
|
6786
|
+
applyNavForest(orderForest);
|
|
6787
|
+
}
|
|
6407
6788
|
}
|
|
6408
6789
|
function buildNavOrderAfterInsert(afterAnchor, newHrefKey) {
|
|
6409
6790
|
const order = getNavOrderFromDom();
|
|
@@ -6443,112 +6824,1020 @@ function insertNavbarItem(href, label, afterAnchor = null) {
|
|
|
6443
6824
|
};
|
|
6444
6825
|
}
|
|
6445
6826
|
|
|
6446
|
-
// src/
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
function
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
return /* @__PURE__ */ jsx21(
|
|
6455
|
-
"div",
|
|
6456
|
-
{
|
|
6457
|
-
"data-ohw-navbar-container-chrome": "",
|
|
6458
|
-
"data-ohw-bridge": "",
|
|
6459
|
-
className: "pointer-events-none fixed z-[2147483647]",
|
|
6460
|
-
style: {
|
|
6461
|
-
top: rect.top - chromeGap,
|
|
6462
|
-
left: rect.left - chromeGap,
|
|
6463
|
-
width: rect.width + chromeGap * 2,
|
|
6464
|
-
height: rect.height + chromeGap * 2
|
|
6465
|
-
},
|
|
6466
|
-
children: /* @__PURE__ */ jsx21(
|
|
6467
|
-
"button",
|
|
6468
|
-
{
|
|
6469
|
-
type: "button",
|
|
6470
|
-
"data-ohw-navbar-add-button": "",
|
|
6471
|
-
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",
|
|
6472
|
-
style: { top: "70%" },
|
|
6473
|
-
"aria-label": "Add item",
|
|
6474
|
-
onMouseDown: (e) => {
|
|
6475
|
-
e.preventDefault();
|
|
6476
|
-
e.stopPropagation();
|
|
6477
|
-
},
|
|
6478
|
-
onClick: (e) => {
|
|
6479
|
-
e.preventDefault();
|
|
6480
|
-
e.stopPropagation();
|
|
6481
|
-
onAdd();
|
|
6482
|
-
},
|
|
6483
|
-
children: /* @__PURE__ */ jsx21(Plus2, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
|
|
6484
|
-
}
|
|
6485
|
-
)
|
|
6486
|
-
}
|
|
6487
|
-
);
|
|
6827
|
+
// src/lib/footer-items.ts
|
|
6828
|
+
var FOOTER_ORDER_KEY = "__ohw_footer_order";
|
|
6829
|
+
var FOOTER_HREF_RE = /^footer-(\d+)-(\d+)-href$/;
|
|
6830
|
+
function parseFooterHrefKey(key) {
|
|
6831
|
+
if (!key) return null;
|
|
6832
|
+
const match = key.match(FOOTER_HREF_RE);
|
|
6833
|
+
if (!match) return null;
|
|
6834
|
+
return { col: parseInt(match[1], 10), item: parseInt(match[2], 10) };
|
|
6488
6835
|
}
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
6492
|
-
var badgeVariants = cva(
|
|
6493
|
-
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
|
6494
|
-
{
|
|
6495
|
-
variants: {
|
|
6496
|
-
variant: {
|
|
6497
|
-
default: "border-transparent bg-primary text-primary-foreground",
|
|
6498
|
-
secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
6499
|
-
destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
|
6500
|
-
outline: "text-foreground"
|
|
6501
|
-
}
|
|
6502
|
-
},
|
|
6503
|
-
defaultVariants: {
|
|
6504
|
-
variant: "default"
|
|
6505
|
-
}
|
|
6506
|
-
}
|
|
6507
|
-
);
|
|
6508
|
-
function Badge({ className, variant, ...props }) {
|
|
6509
|
-
return /* @__PURE__ */ jsx22("div", { className: cn(badgeVariants({ variant }), className), ...props });
|
|
6836
|
+
function isFooterHrefKey(key) {
|
|
6837
|
+
return parseFooterHrefKey(key) !== null;
|
|
6510
6838
|
}
|
|
6511
|
-
|
|
6512
|
-
|
|
6513
|
-
import { Link as Link2 } from "lucide-react";
|
|
6514
|
-
import { Fragment as Fragment5, jsx as jsx23, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
6515
|
-
var PRIMARY2 = "#0885FE";
|
|
6516
|
-
var IMAGE_FADE_MS = 300;
|
|
6517
|
-
function runOpacityFade(el, onDone) {
|
|
6518
|
-
const anim = el.animate([{ opacity: 0 }, { opacity: 1 }], {
|
|
6519
|
-
duration: IMAGE_FADE_MS,
|
|
6520
|
-
easing: "ease",
|
|
6521
|
-
fill: "forwards"
|
|
6522
|
-
});
|
|
6523
|
-
let finished = false;
|
|
6524
|
-
const finish = () => {
|
|
6525
|
-
if (finished) return;
|
|
6526
|
-
finished = true;
|
|
6527
|
-
anim.cancel();
|
|
6528
|
-
el.style.opacity = "";
|
|
6529
|
-
onDone();
|
|
6530
|
-
};
|
|
6531
|
-
anim.finished.then(finish).catch(finish);
|
|
6532
|
-
window.setTimeout(finish, IMAGE_FADE_MS + 100);
|
|
6839
|
+
function getFooterRoot() {
|
|
6840
|
+
return document.querySelector('footer[data-ohw-section="footer"], footer');
|
|
6533
6841
|
}
|
|
6534
|
-
function
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
|
|
6538
|
-
|
|
6842
|
+
function getFooterLinksContainer() {
|
|
6843
|
+
return document.querySelector("[data-ohw-footer-links]") ?? document.querySelector(".rb-footer-links");
|
|
6844
|
+
}
|
|
6845
|
+
function isFooterLinkAnchor(el) {
|
|
6846
|
+
if (!el.matches("[data-ohw-href-key]")) return false;
|
|
6847
|
+
if (!isFooterHrefKey(el.getAttribute("data-ohw-href-key"))) return false;
|
|
6848
|
+
return Boolean(el.querySelector('[data-ohw-editable="text"]'));
|
|
6849
|
+
}
|
|
6850
|
+
function listFooterColumns() {
|
|
6851
|
+
const root = getFooterLinksContainer() ?? getFooterRoot()?.querySelector(".rb-footer-links") ?? null;
|
|
6852
|
+
if (!root) return [];
|
|
6853
|
+
const explicit = Array.from(root.querySelectorAll(":scope > [data-ohw-footer-col]"));
|
|
6854
|
+
if (explicit.length > 0) return explicit;
|
|
6855
|
+
return Array.from(root.children).filter((el) => {
|
|
6856
|
+
if (!(el instanceof HTMLElement)) return false;
|
|
6857
|
+
return Array.from(el.querySelectorAll(":scope > [data-ohw-href-key]")).some(
|
|
6858
|
+
isFooterLinkAnchor
|
|
6859
|
+
);
|
|
6539
6860
|
});
|
|
6540
6861
|
}
|
|
6541
|
-
function
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
|
|
6862
|
+
function listFooterLinksInColumn(column) {
|
|
6863
|
+
return Array.from(column.querySelectorAll(":scope > [data-ohw-href-key]")).filter(
|
|
6864
|
+
isFooterLinkAnchor
|
|
6865
|
+
);
|
|
6545
6866
|
}
|
|
6546
|
-
function
|
|
6547
|
-
const
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
|
|
6551
|
-
|
|
6867
|
+
function findFooterColumnForLink(anchor) {
|
|
6868
|
+
const columns = listFooterColumns();
|
|
6869
|
+
return columns.find((col) => col.contains(anchor)) ?? null;
|
|
6870
|
+
}
|
|
6871
|
+
function getFooterOrderFromDom() {
|
|
6872
|
+
return listFooterColumns().map(
|
|
6873
|
+
(col) => listFooterLinksInColumn(col).map((el) => el.getAttribute("data-ohw-href-key")).filter((key) => Boolean(key))
|
|
6874
|
+
);
|
|
6875
|
+
}
|
|
6876
|
+
function findFooterLinkByKey(hrefKey) {
|
|
6877
|
+
return document.querySelector(
|
|
6878
|
+
`footer [data-ohw-href-key="${CSS.escape(hrefKey)}"]`
|
|
6879
|
+
);
|
|
6880
|
+
}
|
|
6881
|
+
function syncFooterColumnIndices(columns) {
|
|
6882
|
+
columns.forEach((col, index) => {
|
|
6883
|
+
const next = String(index);
|
|
6884
|
+
if (col.getAttribute("data-ohw-footer-col") !== next) {
|
|
6885
|
+
col.setAttribute("data-ohw-footer-col", next);
|
|
6886
|
+
}
|
|
6887
|
+
});
|
|
6888
|
+
}
|
|
6889
|
+
function appendChildIfNeeded(parent, child) {
|
|
6890
|
+
if (parent.lastElementChild !== child) {
|
|
6891
|
+
parent.appendChild(child);
|
|
6892
|
+
}
|
|
6893
|
+
}
|
|
6894
|
+
function applyFooterOrder(order) {
|
|
6895
|
+
const container = getFooterLinksContainer();
|
|
6896
|
+
if (!container) return;
|
|
6897
|
+
const columns = listFooterColumns();
|
|
6898
|
+
if (columns.length === 0) return;
|
|
6899
|
+
const currentOrder = getFooterOrderFromDom();
|
|
6900
|
+
if (ordersEqual(order, currentOrder)) {
|
|
6901
|
+
syncFooterColumnIndices(columns);
|
|
6902
|
+
return;
|
|
6903
|
+
}
|
|
6904
|
+
const used = /* @__PURE__ */ new Set();
|
|
6905
|
+
const orderedCols = [];
|
|
6906
|
+
for (const colOrder of order) {
|
|
6907
|
+
let matched = null;
|
|
6908
|
+
for (const hrefKey of colOrder) {
|
|
6909
|
+
const link = findFooterLinkByKey(hrefKey);
|
|
6910
|
+
if (!link) continue;
|
|
6911
|
+
const owner = findFooterColumnForLink(link);
|
|
6912
|
+
if (owner && !used.has(owner)) {
|
|
6913
|
+
matched = owner;
|
|
6914
|
+
break;
|
|
6915
|
+
}
|
|
6916
|
+
}
|
|
6917
|
+
if (!matched) {
|
|
6918
|
+
matched = columns.find((col) => !used.has(col)) ?? null;
|
|
6919
|
+
}
|
|
6920
|
+
if (matched) {
|
|
6921
|
+
used.add(matched);
|
|
6922
|
+
orderedCols.push(matched);
|
|
6923
|
+
}
|
|
6924
|
+
}
|
|
6925
|
+
for (const col of columns) {
|
|
6926
|
+
if (!used.has(col)) orderedCols.push(col);
|
|
6927
|
+
}
|
|
6928
|
+
for (const col of orderedCols) {
|
|
6929
|
+
appendChildIfNeeded(container, col);
|
|
6930
|
+
}
|
|
6931
|
+
const freshColumns = listFooterColumns();
|
|
6932
|
+
syncFooterColumnIndices(freshColumns);
|
|
6933
|
+
for (let c = 0; c < order.length; c++) {
|
|
6934
|
+
const col = freshColumns[c];
|
|
6935
|
+
if (!col) continue;
|
|
6936
|
+
const colOrder = order[c];
|
|
6937
|
+
for (const hrefKey of colOrder) {
|
|
6938
|
+
const el = findFooterLinkByKey(hrefKey);
|
|
6939
|
+
if (!el) continue;
|
|
6940
|
+
if (el.parentElement !== col || col.lastElementChild !== el) {
|
|
6941
|
+
col.appendChild(el);
|
|
6942
|
+
}
|
|
6943
|
+
}
|
|
6944
|
+
}
|
|
6945
|
+
}
|
|
6946
|
+
function ordersEqual(a, b) {
|
|
6947
|
+
if (a.length !== b.length) return false;
|
|
6948
|
+
for (let i = 0; i < a.length; i++) {
|
|
6949
|
+
const left = a[i];
|
|
6950
|
+
const right = b[i];
|
|
6951
|
+
if (left.length !== right.length) return false;
|
|
6952
|
+
for (let j = 0; j < left.length; j++) {
|
|
6953
|
+
if (left[j] !== right[j]) return false;
|
|
6954
|
+
}
|
|
6955
|
+
}
|
|
6956
|
+
return true;
|
|
6957
|
+
}
|
|
6958
|
+
function planFooterLinkMove(hrefKey, targetColIndex, insertIndex) {
|
|
6959
|
+
const order = getFooterOrderFromDom();
|
|
6960
|
+
if (targetColIndex < 0 || targetColIndex >= order.length) return null;
|
|
6961
|
+
let fromCol = -1;
|
|
6962
|
+
let fromIdx = -1;
|
|
6963
|
+
for (let c = 0; c < order.length; c++) {
|
|
6964
|
+
const idx = order[c].indexOf(hrefKey);
|
|
6965
|
+
if (idx >= 0) {
|
|
6966
|
+
fromCol = c;
|
|
6967
|
+
fromIdx = idx;
|
|
6968
|
+
break;
|
|
6969
|
+
}
|
|
6970
|
+
}
|
|
6971
|
+
if (fromCol < 0) return null;
|
|
6972
|
+
const next = order.map((col) => [...col]);
|
|
6973
|
+
next[fromCol].splice(fromIdx, 1);
|
|
6974
|
+
let adjusted = insertIndex;
|
|
6975
|
+
if (fromCol === targetColIndex && fromIdx < insertIndex) adjusted -= 1;
|
|
6976
|
+
adjusted = Math.max(0, Math.min(adjusted, next[targetColIndex].length));
|
|
6977
|
+
next[targetColIndex].splice(adjusted, 0, hrefKey);
|
|
6978
|
+
if (ordersEqual(next, order)) return null;
|
|
6979
|
+
return next;
|
|
6980
|
+
}
|
|
6981
|
+
function planFooterColumnMove(fromIndex, toIndex) {
|
|
6982
|
+
const order = getFooterOrderFromDom();
|
|
6983
|
+
const columns = listFooterColumns();
|
|
6984
|
+
if (fromIndex < 0 || fromIndex >= columns.length || toIndex < 0 || toIndex > columns.length) {
|
|
6985
|
+
return null;
|
|
6986
|
+
}
|
|
6987
|
+
if (toIndex === fromIndex || toIndex === fromIndex + 1) return null;
|
|
6988
|
+
const nextOrder = order.map((col) => [...col]);
|
|
6989
|
+
const [movedOrder] = nextOrder.splice(fromIndex, 1);
|
|
6990
|
+
if (!movedOrder) return null;
|
|
6991
|
+
let adjusted = toIndex;
|
|
6992
|
+
if (fromIndex < toIndex) adjusted -= 1;
|
|
6993
|
+
adjusted = Math.max(0, Math.min(adjusted, nextOrder.length));
|
|
6994
|
+
nextOrder.splice(adjusted, 0, movedOrder);
|
|
6995
|
+
if (ordersEqual(nextOrder, order)) return null;
|
|
6996
|
+
return nextOrder;
|
|
6997
|
+
}
|
|
6998
|
+
function parseFooterOrder(content) {
|
|
6999
|
+
const raw = content[FOOTER_ORDER_KEY];
|
|
7000
|
+
if (!raw) return null;
|
|
7001
|
+
try {
|
|
7002
|
+
const parsed = JSON.parse(raw);
|
|
7003
|
+
if (!Array.isArray(parsed)) return null;
|
|
7004
|
+
return parsed.filter((col) => Array.isArray(col)).map((col) => col.filter((key) => typeof key === "string" && key.length > 0));
|
|
7005
|
+
} catch {
|
|
7006
|
+
return null;
|
|
7007
|
+
}
|
|
7008
|
+
}
|
|
7009
|
+
function reconcileFooterOrderFromContent(content) {
|
|
7010
|
+
const order = parseFooterOrder(content);
|
|
7011
|
+
if (!order?.length) return;
|
|
7012
|
+
const current = getFooterOrderFromDom();
|
|
7013
|
+
if (ordersEqual(order, current)) {
|
|
7014
|
+
syncFooterColumnIndices(listFooterColumns());
|
|
7015
|
+
return;
|
|
7016
|
+
}
|
|
7017
|
+
applyFooterOrder(order);
|
|
7018
|
+
}
|
|
7019
|
+
function isRowLayoutColumn(links) {
|
|
7020
|
+
if (links.length < 2) return false;
|
|
7021
|
+
const firstTop = links[0].getBoundingClientRect().top;
|
|
7022
|
+
return links.every((link) => Math.abs(link.getBoundingClientRect().top - firstTop) < 4);
|
|
7023
|
+
}
|
|
7024
|
+
function buildLinkDropSlots(column, columnIndex) {
|
|
7025
|
+
const links = listFooterLinksInColumn(column);
|
|
7026
|
+
const colRect = column.getBoundingClientRect();
|
|
7027
|
+
const slots = [];
|
|
7028
|
+
const barThickness = 3;
|
|
7029
|
+
if (links.length === 0) {
|
|
7030
|
+
slots.push({
|
|
7031
|
+
insertIndex: 0,
|
|
7032
|
+
columnIndex,
|
|
7033
|
+
left: colRect.left,
|
|
7034
|
+
top: colRect.top + colRect.height / 2 - barThickness / 2,
|
|
7035
|
+
width: colRect.width,
|
|
7036
|
+
height: barThickness,
|
|
7037
|
+
direction: "horizontal"
|
|
7038
|
+
});
|
|
7039
|
+
return slots;
|
|
7040
|
+
}
|
|
7041
|
+
if (isRowLayoutColumn(links)) {
|
|
7042
|
+
for (let i = 0; i <= links.length; i++) {
|
|
7043
|
+
let left;
|
|
7044
|
+
if (i === 0) {
|
|
7045
|
+
left = links[0].getBoundingClientRect().left - barThickness / 2;
|
|
7046
|
+
} else if (i === links.length) {
|
|
7047
|
+
const last = links[links.length - 1].getBoundingClientRect();
|
|
7048
|
+
left = last.right - barThickness / 2;
|
|
7049
|
+
} else {
|
|
7050
|
+
const prev = links[i - 1].getBoundingClientRect();
|
|
7051
|
+
const next = links[i].getBoundingClientRect();
|
|
7052
|
+
left = (prev.right + next.left) / 2 - barThickness / 2;
|
|
7053
|
+
}
|
|
7054
|
+
const heightRef = i === 0 ? links[0].getBoundingClientRect() : i === links.length ? links[links.length - 1].getBoundingClientRect() : links[i].getBoundingClientRect();
|
|
7055
|
+
slots.push({
|
|
7056
|
+
insertIndex: i,
|
|
7057
|
+
columnIndex,
|
|
7058
|
+
left,
|
|
7059
|
+
top: heightRef.top,
|
|
7060
|
+
width: barThickness,
|
|
7061
|
+
height: Math.max(heightRef.height, colRect.height * 0.8),
|
|
7062
|
+
direction: "vertical"
|
|
7063
|
+
});
|
|
7064
|
+
}
|
|
7065
|
+
return slots;
|
|
7066
|
+
}
|
|
7067
|
+
for (let i = 0; i <= links.length; i++) {
|
|
7068
|
+
let top;
|
|
7069
|
+
if (i === 0) {
|
|
7070
|
+
top = links[0].getBoundingClientRect().top - barThickness / 2;
|
|
7071
|
+
} else if (i === links.length) {
|
|
7072
|
+
const last = links[links.length - 1].getBoundingClientRect();
|
|
7073
|
+
top = last.bottom - barThickness / 2;
|
|
7074
|
+
} else {
|
|
7075
|
+
const prev = links[i - 1].getBoundingClientRect();
|
|
7076
|
+
const next = links[i].getBoundingClientRect();
|
|
7077
|
+
top = (prev.bottom + next.top) / 2 - barThickness / 2;
|
|
7078
|
+
}
|
|
7079
|
+
const widthRef = i === 0 ? links[0].getBoundingClientRect() : i === links.length ? links[links.length - 1].getBoundingClientRect() : links[i].getBoundingClientRect();
|
|
7080
|
+
slots.push({
|
|
7081
|
+
insertIndex: i,
|
|
7082
|
+
columnIndex,
|
|
7083
|
+
left: widthRef.left,
|
|
7084
|
+
top,
|
|
7085
|
+
width: Math.max(widthRef.width, colRect.width * 0.8),
|
|
7086
|
+
height: barThickness,
|
|
7087
|
+
direction: "horizontal"
|
|
7088
|
+
});
|
|
7089
|
+
}
|
|
7090
|
+
return slots;
|
|
7091
|
+
}
|
|
7092
|
+
function buildColumnDropSlots() {
|
|
7093
|
+
const columns = listFooterColumns();
|
|
7094
|
+
const slots = [];
|
|
7095
|
+
const barThickness = 3;
|
|
7096
|
+
if (columns.length === 0) return slots;
|
|
7097
|
+
for (let i = 0; i <= columns.length; i++) {
|
|
7098
|
+
let left;
|
|
7099
|
+
let height;
|
|
7100
|
+
let top;
|
|
7101
|
+
if (i === 0) {
|
|
7102
|
+
const first = columns[0].getBoundingClientRect();
|
|
7103
|
+
left = first.left - barThickness / 2;
|
|
7104
|
+
top = first.top;
|
|
7105
|
+
height = first.height;
|
|
7106
|
+
} else if (i === columns.length) {
|
|
7107
|
+
const last = columns[columns.length - 1].getBoundingClientRect();
|
|
7108
|
+
left = last.right - barThickness / 2;
|
|
7109
|
+
top = last.top;
|
|
7110
|
+
height = last.height;
|
|
7111
|
+
} else {
|
|
7112
|
+
const prev = columns[i - 1].getBoundingClientRect();
|
|
7113
|
+
const next = columns[i].getBoundingClientRect();
|
|
7114
|
+
left = (prev.right + next.left) / 2 - barThickness / 2;
|
|
7115
|
+
top = Math.min(prev.top, next.top);
|
|
7116
|
+
height = Math.max(prev.bottom, next.bottom) - top;
|
|
7117
|
+
}
|
|
7118
|
+
slots.push({
|
|
7119
|
+
insertIndex: i,
|
|
7120
|
+
columnIndex: i,
|
|
7121
|
+
left,
|
|
7122
|
+
top,
|
|
7123
|
+
width: barThickness,
|
|
7124
|
+
height: Math.max(height, 24),
|
|
7125
|
+
direction: "vertical"
|
|
7126
|
+
});
|
|
7127
|
+
}
|
|
7128
|
+
return slots;
|
|
7129
|
+
}
|
|
7130
|
+
function hitTestLinkDropSlot(clientX, clientY, draggedHrefKey) {
|
|
7131
|
+
const columns = listFooterColumns();
|
|
7132
|
+
let best = null;
|
|
7133
|
+
for (let c = 0; c < columns.length; c++) {
|
|
7134
|
+
const col = columns[c];
|
|
7135
|
+
const colRect = col.getBoundingClientRect();
|
|
7136
|
+
const inColX = clientX >= colRect.left - 24 && clientX <= colRect.right + 24;
|
|
7137
|
+
if (!inColX) continue;
|
|
7138
|
+
const slots = buildLinkDropSlots(col, c).filter((slot) => {
|
|
7139
|
+
const links = listFooterLinksInColumn(col);
|
|
7140
|
+
const fromIdx = links.findIndex(
|
|
7141
|
+
(el) => el.getAttribute("data-ohw-href-key") === draggedHrefKey
|
|
7142
|
+
);
|
|
7143
|
+
if (fromIdx < 0) return true;
|
|
7144
|
+
if (c === findColumnIndexForKey(draggedHrefKey) && (slot.insertIndex === fromIdx || slot.insertIndex === fromIdx + 1)) {
|
|
7145
|
+
return true;
|
|
7146
|
+
}
|
|
7147
|
+
return true;
|
|
7148
|
+
});
|
|
7149
|
+
for (const slot of slots) {
|
|
7150
|
+
const dist = slot.direction === "vertical" ? Math.abs(clientX - (slot.left + slot.width / 2)) : Math.abs(clientY - (slot.top + slot.height / 2));
|
|
7151
|
+
if (!best || dist < best.dist) best = { slot, dist };
|
|
7152
|
+
}
|
|
7153
|
+
}
|
|
7154
|
+
return best?.slot ?? null;
|
|
7155
|
+
}
|
|
7156
|
+
function findColumnIndexForKey(hrefKey) {
|
|
7157
|
+
const order = getFooterOrderFromDom();
|
|
7158
|
+
for (let c = 0; c < order.length; c++) {
|
|
7159
|
+
if (order[c].includes(hrefKey)) return c;
|
|
7160
|
+
}
|
|
7161
|
+
return -1;
|
|
7162
|
+
}
|
|
7163
|
+
function hitTestColumnDropSlot(clientX, _clientY) {
|
|
7164
|
+
const slots = buildColumnDropSlots();
|
|
7165
|
+
let best = null;
|
|
7166
|
+
for (const slot of slots) {
|
|
7167
|
+
const cx2 = slot.left + slot.width / 2;
|
|
7168
|
+
const dist = Math.abs(clientX - cx2);
|
|
7169
|
+
if (!best || dist < best.dist) best = { slot, dist };
|
|
7170
|
+
}
|
|
7171
|
+
return best?.slot ?? null;
|
|
7172
|
+
}
|
|
7173
|
+
|
|
7174
|
+
// src/lib/item-drag-interaction.ts
|
|
7175
|
+
function disableNativeHrefDrag(el) {
|
|
7176
|
+
if (el.draggable) el.draggable = false;
|
|
7177
|
+
if (el.getAttribute("draggable") !== "false") {
|
|
7178
|
+
el.setAttribute("draggable", "false");
|
|
7179
|
+
}
|
|
7180
|
+
}
|
|
7181
|
+
function clearTextSelection() {
|
|
7182
|
+
const sel = window.getSelection();
|
|
7183
|
+
if (sel && !sel.isCollapsed) sel.removeAllRanges();
|
|
7184
|
+
}
|
|
7185
|
+
function armItemPressDrag() {
|
|
7186
|
+
document.documentElement.setAttribute("data-ohw-footer-press-drag", "");
|
|
7187
|
+
}
|
|
7188
|
+
function lockItemDuringDrag() {
|
|
7189
|
+
document.documentElement.removeAttribute("data-ohw-footer-press-drag");
|
|
7190
|
+
document.documentElement.setAttribute("data-ohw-item-dragging", "");
|
|
7191
|
+
clearTextSelection();
|
|
7192
|
+
}
|
|
7193
|
+
function unlockItemDragInteraction() {
|
|
7194
|
+
const wasDragging = document.documentElement.hasAttribute("data-ohw-item-dragging");
|
|
7195
|
+
document.documentElement.removeAttribute("data-ohw-footer-press-drag");
|
|
7196
|
+
document.documentElement.removeAttribute("data-ohw-item-dragging");
|
|
7197
|
+
if (wasDragging) clearTextSelection();
|
|
7198
|
+
}
|
|
7199
|
+
var armFooterPressDrag = armItemPressDrag;
|
|
7200
|
+
var lockFooterDuringDrag = lockItemDuringDrag;
|
|
7201
|
+
var unlockFooterDragInteraction = unlockItemDragInteraction;
|
|
7202
|
+
|
|
7203
|
+
// src/lib/nav-dnd.ts
|
|
7204
|
+
function listReorderableNavItems() {
|
|
7205
|
+
return listNavbarItems().filter((el) => {
|
|
7206
|
+
const key = el.getAttribute("data-ohw-href-key");
|
|
7207
|
+
return isNavbarHrefKey(key) && !el.closest("[data-ohw-nav-children]");
|
|
7208
|
+
});
|
|
7209
|
+
}
|
|
7210
|
+
function listNavChildren(parentHrefKey) {
|
|
7211
|
+
const items = listNavbarItems();
|
|
7212
|
+
const parent = items.find((el) => el.getAttribute("data-ohw-href-key") === parentHrefKey);
|
|
7213
|
+
if (!parent) return [];
|
|
7214
|
+
const group = parent.closest("[data-ohw-nav-group]");
|
|
7215
|
+
const childrenRoot = group?.querySelector(":scope > [data-ohw-nav-children]");
|
|
7216
|
+
if (!childrenRoot) return [];
|
|
7217
|
+
return Array.from(childrenRoot.querySelectorAll(":scope > [data-ohw-href-key]")).filter(
|
|
7218
|
+
(el) => isNavbarHrefKey(el.getAttribute("data-ohw-href-key"))
|
|
7219
|
+
);
|
|
7220
|
+
}
|
|
7221
|
+
function activeNavListContainer() {
|
|
7222
|
+
const desktop = getNavbarDesktopContainer();
|
|
7223
|
+
if (desktop && desktop.getClientRects().length > 0) {
|
|
7224
|
+
const style = window.getComputedStyle(desktop);
|
|
7225
|
+
if (style.display !== "none" && style.visibility !== "hidden") return desktop;
|
|
7226
|
+
}
|
|
7227
|
+
return getNavbarDrawerContainer();
|
|
7228
|
+
}
|
|
7229
|
+
function buildRootNavDropSlots() {
|
|
7230
|
+
const items = listReorderableNavItems();
|
|
7231
|
+
const slots = [];
|
|
7232
|
+
const barThickness = 3;
|
|
7233
|
+
if (items.length === 0) {
|
|
7234
|
+
const container = activeNavListContainer();
|
|
7235
|
+
if (!container) return slots;
|
|
7236
|
+
const rect = container.getBoundingClientRect();
|
|
7237
|
+
slots.push({
|
|
7238
|
+
insertIndex: 0,
|
|
7239
|
+
parentId: null,
|
|
7240
|
+
left: rect.left + rect.width / 2 - barThickness / 2,
|
|
7241
|
+
top: rect.top,
|
|
7242
|
+
width: barThickness,
|
|
7243
|
+
height: Math.max(rect.height, 24),
|
|
7244
|
+
direction: "vertical"
|
|
7245
|
+
});
|
|
7246
|
+
return slots;
|
|
7247
|
+
}
|
|
7248
|
+
for (let i = 0; i <= items.length; i++) {
|
|
7249
|
+
let left;
|
|
7250
|
+
let top;
|
|
7251
|
+
let height;
|
|
7252
|
+
if (i === 0) {
|
|
7253
|
+
const first = items[0].getBoundingClientRect();
|
|
7254
|
+
left = first.left - barThickness / 2;
|
|
7255
|
+
top = first.top;
|
|
7256
|
+
height = first.height;
|
|
7257
|
+
} else if (i === items.length) {
|
|
7258
|
+
const last = items[items.length - 1].getBoundingClientRect();
|
|
7259
|
+
left = last.right - barThickness / 2;
|
|
7260
|
+
top = last.top;
|
|
7261
|
+
height = last.height;
|
|
7262
|
+
} else {
|
|
7263
|
+
const prev = items[i - 1].getBoundingClientRect();
|
|
7264
|
+
const next = items[i].getBoundingClientRect();
|
|
7265
|
+
left = (prev.right + next.left) / 2 - barThickness / 2;
|
|
7266
|
+
top = Math.min(prev.top, next.top);
|
|
7267
|
+
height = Math.max(prev.bottom, next.bottom) - top;
|
|
7268
|
+
}
|
|
7269
|
+
slots.push({
|
|
7270
|
+
insertIndex: i,
|
|
7271
|
+
parentId: null,
|
|
7272
|
+
left,
|
|
7273
|
+
top,
|
|
7274
|
+
width: barThickness,
|
|
7275
|
+
height: Math.max(height, 24),
|
|
7276
|
+
direction: "vertical"
|
|
7277
|
+
});
|
|
7278
|
+
}
|
|
7279
|
+
return slots;
|
|
7280
|
+
}
|
|
7281
|
+
function buildChildNavDropSlots(parentHrefKey) {
|
|
7282
|
+
const children = listNavChildren(parentHrefKey);
|
|
7283
|
+
const slots = [];
|
|
7284
|
+
const barThickness = 3;
|
|
7285
|
+
if (children.length === 0) return slots;
|
|
7286
|
+
for (let i = 0; i <= children.length; i++) {
|
|
7287
|
+
let top;
|
|
7288
|
+
let width;
|
|
7289
|
+
let left;
|
|
7290
|
+
if (i === 0) {
|
|
7291
|
+
const first = children[0].getBoundingClientRect();
|
|
7292
|
+
top = first.top - barThickness / 2;
|
|
7293
|
+
left = first.left;
|
|
7294
|
+
width = first.width;
|
|
7295
|
+
} else if (i === children.length) {
|
|
7296
|
+
const last = children[children.length - 1].getBoundingClientRect();
|
|
7297
|
+
top = last.bottom - barThickness / 2;
|
|
7298
|
+
left = last.left;
|
|
7299
|
+
width = last.width;
|
|
7300
|
+
} else {
|
|
7301
|
+
const prev = children[i - 1].getBoundingClientRect();
|
|
7302
|
+
const next = children[i].getBoundingClientRect();
|
|
7303
|
+
top = (prev.bottom + next.top) / 2 - barThickness / 2;
|
|
7304
|
+
left = Math.min(prev.left, next.left);
|
|
7305
|
+
width = Math.max(prev.right, next.right) - left;
|
|
7306
|
+
}
|
|
7307
|
+
slots.push({
|
|
7308
|
+
insertIndex: i,
|
|
7309
|
+
parentId: parentHrefKey,
|
|
7310
|
+
left,
|
|
7311
|
+
top,
|
|
7312
|
+
width: Math.max(width, 40),
|
|
7313
|
+
height: barThickness,
|
|
7314
|
+
direction: "horizontal"
|
|
7315
|
+
});
|
|
7316
|
+
}
|
|
7317
|
+
return slots;
|
|
7318
|
+
}
|
|
7319
|
+
function buildAllNavDropSlots(draggedHrefKey) {
|
|
7320
|
+
const slots = [...buildRootNavDropSlots()];
|
|
7321
|
+
for (const item of listReorderableNavItems()) {
|
|
7322
|
+
const key = item.getAttribute("data-ohw-href-key");
|
|
7323
|
+
if (!key || key === draggedHrefKey) continue;
|
|
7324
|
+
const group = item.closest("[data-ohw-nav-group]");
|
|
7325
|
+
if (!group?.querySelector(":scope > [data-ohw-nav-children]")) continue;
|
|
7326
|
+
slots.push(...buildChildNavDropSlots(key));
|
|
7327
|
+
}
|
|
7328
|
+
const dragged = listNavbarItems().find((el) => el.getAttribute("data-ohw-href-key") === draggedHrefKey);
|
|
7329
|
+
const parentGroup = dragged?.closest("[data-ohw-nav-children]")?.closest("[data-ohw-nav-group]");
|
|
7330
|
+
const parentTrigger = parentGroup?.querySelector(":scope > [data-ohw-href-key]");
|
|
7331
|
+
const parentKey = parentTrigger?.getAttribute("data-ohw-href-key");
|
|
7332
|
+
if (parentKey && isNavbarHrefKey(parentKey)) {
|
|
7333
|
+
const existing = slots.some((s) => s.parentId === parentKey);
|
|
7334
|
+
if (!existing) slots.push(...buildChildNavDropSlots(parentKey));
|
|
7335
|
+
}
|
|
7336
|
+
return slots;
|
|
7337
|
+
}
|
|
7338
|
+
function hitTestNavDropSlot(clientX, clientY, draggedHrefKey) {
|
|
7339
|
+
const slots = buildAllNavDropSlots(draggedHrefKey);
|
|
7340
|
+
let best = null;
|
|
7341
|
+
for (const slot of slots) {
|
|
7342
|
+
const cx2 = slot.left + slot.width / 2;
|
|
7343
|
+
const cy = slot.top + slot.height / 2;
|
|
7344
|
+
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;
|
|
7345
|
+
if (!best || dist < best.dist) best = { slot, dist };
|
|
7346
|
+
}
|
|
7347
|
+
return best?.slot ?? null;
|
|
7348
|
+
}
|
|
7349
|
+
function siblingRectsForNavDrag(draggedEl, activeParentId) {
|
|
7350
|
+
if (activeParentId) {
|
|
7351
|
+
return listNavChildren(activeParentId).filter((el) => el !== draggedEl).map((el) => el.getBoundingClientRect());
|
|
7352
|
+
}
|
|
7353
|
+
return listReorderableNavItems().filter((el) => el !== draggedEl).map((el) => el.getBoundingClientRect());
|
|
7354
|
+
}
|
|
7355
|
+
|
|
7356
|
+
// src/useNavItemDrag.ts
|
|
7357
|
+
import { useCallback as useCallback4, useEffect as useEffect7, useRef as useRef6, useState as useState6 } from "react";
|
|
7358
|
+
function useNavItemDrag({
|
|
7359
|
+
isEditMode,
|
|
7360
|
+
editContentRef,
|
|
7361
|
+
selectedElRef,
|
|
7362
|
+
activeElRef,
|
|
7363
|
+
footerDragRef,
|
|
7364
|
+
suppressNextClickRef,
|
|
7365
|
+
suppressClickUntilRef,
|
|
7366
|
+
siblingHintElRef,
|
|
7367
|
+
postToParentRef,
|
|
7368
|
+
deselectRef,
|
|
7369
|
+
selectRef,
|
|
7370
|
+
deactivateRef,
|
|
7371
|
+
setLinkPopover,
|
|
7372
|
+
linkPopoverOpenRef,
|
|
7373
|
+
setIsItemDragging,
|
|
7374
|
+
setDraggedItemRect,
|
|
7375
|
+
setSiblingHintRect,
|
|
7376
|
+
setSiblingHintRects,
|
|
7377
|
+
setToolbarRect,
|
|
7378
|
+
getNavigationItemAnchor: getNavigationItemAnchor2,
|
|
7379
|
+
isDragHandleDisabled: isDragHandleDisabled2,
|
|
7380
|
+
isNavbarButton: isNavbarButton3
|
|
7381
|
+
}) {
|
|
7382
|
+
const navDragRef = useRef6(null);
|
|
7383
|
+
const [navDropSlots, setNavDropSlots] = useState6([]);
|
|
7384
|
+
const [activeNavDropIndex, setActiveNavDropIndex] = useState6(null);
|
|
7385
|
+
const navPointerDragRef = useRef6(null);
|
|
7386
|
+
const clearNavDragVisuals = useCallback4(() => {
|
|
7387
|
+
navDragRef.current = null;
|
|
7388
|
+
setNavDropSlots([]);
|
|
7389
|
+
setActiveNavDropIndex(null);
|
|
7390
|
+
setDraggedItemRect(null);
|
|
7391
|
+
setSiblingHintRects([]);
|
|
7392
|
+
setIsItemDragging(false);
|
|
7393
|
+
unlockItemDragInteraction();
|
|
7394
|
+
}, [setDraggedItemRect, setIsItemDragging, setSiblingHintRects]);
|
|
7395
|
+
const refreshNavDragVisuals = useCallback4(
|
|
7396
|
+
(session, activeSlot, clientX, clientY) => {
|
|
7397
|
+
setDraggedItemRect(session.draggedEl.getBoundingClientRect());
|
|
7398
|
+
if (typeof clientX === "number" && typeof clientY === "number") {
|
|
7399
|
+
session.lastClientX = clientX;
|
|
7400
|
+
session.lastClientY = clientY;
|
|
7401
|
+
}
|
|
7402
|
+
session.activeSlot = activeSlot;
|
|
7403
|
+
const parentId = activeSlot?.parentId ?? null;
|
|
7404
|
+
setSiblingHintRects(siblingRectsForNavDrag(session.draggedEl, parentId));
|
|
7405
|
+
const slots = buildAllNavDropSlots(session.hrefKey);
|
|
7406
|
+
setNavDropSlots(slots);
|
|
7407
|
+
const activeIdx = activeSlot ? slots.findIndex(
|
|
7408
|
+
(s) => s.parentId === activeSlot.parentId && s.insertIndex === activeSlot.insertIndex
|
|
7409
|
+
) : -1;
|
|
7410
|
+
setActiveNavDropIndex(activeIdx >= 0 ? activeIdx : null);
|
|
7411
|
+
},
|
|
7412
|
+
[setDraggedItemRect, setSiblingHintRects]
|
|
7413
|
+
);
|
|
7414
|
+
const refreshNavDragVisualsRef = useRef6(refreshNavDragVisuals);
|
|
7415
|
+
refreshNavDragVisualsRef.current = refreshNavDragVisuals;
|
|
7416
|
+
const commitNavDragRef = useRef6(() => {
|
|
7417
|
+
});
|
|
7418
|
+
const beginNavDragRef = useRef6(() => {
|
|
7419
|
+
});
|
|
7420
|
+
const beginNavDrag = useCallback4(
|
|
7421
|
+
(session) => {
|
|
7422
|
+
const rect = session.draggedEl.getBoundingClientRect();
|
|
7423
|
+
session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
|
|
7424
|
+
session.lastClientY = session.lastClientY || rect.top + rect.height / 2;
|
|
7425
|
+
session.activeSlot = session.activeSlot ?? null;
|
|
7426
|
+
navDragRef.current = session;
|
|
7427
|
+
setIsItemDragging(true);
|
|
7428
|
+
lockItemDuringDrag();
|
|
7429
|
+
siblingHintElRef.current = null;
|
|
7430
|
+
setSiblingHintRect(null);
|
|
7431
|
+
if (session.wasSelected && selectedElRef.current === session.draggedEl) {
|
|
7432
|
+
setToolbarRect(rect);
|
|
7433
|
+
}
|
|
7434
|
+
const initialSlot = hitTestNavDropSlot(session.lastClientX, session.lastClientY, session.hrefKey);
|
|
7435
|
+
refreshNavDragVisuals(session, initialSlot, session.lastClientX, session.lastClientY);
|
|
7436
|
+
},
|
|
7437
|
+
[
|
|
7438
|
+
refreshNavDragVisuals,
|
|
7439
|
+
selectedElRef,
|
|
7440
|
+
setIsItemDragging,
|
|
7441
|
+
setSiblingHintRect,
|
|
7442
|
+
setToolbarRect,
|
|
7443
|
+
siblingHintElRef
|
|
7444
|
+
]
|
|
7445
|
+
);
|
|
7446
|
+
beginNavDragRef.current = beginNavDrag;
|
|
7447
|
+
const commitNavDrag = useCallback4(
|
|
7448
|
+
(clientX, clientY) => {
|
|
7449
|
+
const session = navDragRef.current;
|
|
7450
|
+
if (!session) {
|
|
7451
|
+
clearNavDragVisuals();
|
|
7452
|
+
return;
|
|
7453
|
+
}
|
|
7454
|
+
const x = typeof clientX === "number" && (clientX !== 0 || clientY !== 0) ? clientX : session.lastClientX;
|
|
7455
|
+
const y = typeof clientY === "number" && (clientX !== 0 || clientY !== 0) ? clientY : session.lastClientY;
|
|
7456
|
+
const slot = session.activeSlot ?? hitTestNavDropSlot(x, y, session.hrefKey);
|
|
7457
|
+
const planned = slot != null ? planNavItemMove(session.hrefKey, slot.parentId, slot.insertIndex) : null;
|
|
7458
|
+
const wasSelected = session.wasSelected;
|
|
7459
|
+
const hrefKey = session.hrefKey;
|
|
7460
|
+
const applySelectionAfterDrop = () => {
|
|
7461
|
+
if (!wasSelected) {
|
|
7462
|
+
deselectRef.current();
|
|
7463
|
+
return;
|
|
7464
|
+
}
|
|
7465
|
+
const desktop = document.querySelector("[data-ohw-nav-container]");
|
|
7466
|
+
const drawer = document.querySelector("[data-ohw-nav-drawer]");
|
|
7467
|
+
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)}"]`);
|
|
7468
|
+
if (link) {
|
|
7469
|
+
selectRef.current(link);
|
|
7470
|
+
return;
|
|
7471
|
+
}
|
|
7472
|
+
deselectRef.current();
|
|
7473
|
+
};
|
|
7474
|
+
if (planned) {
|
|
7475
|
+
editContentRef.current = {
|
|
7476
|
+
...editContentRef.current,
|
|
7477
|
+
[NAV_ORDER_KEY]: planned.orderJson
|
|
7478
|
+
};
|
|
7479
|
+
applyNavForest(planned.forest);
|
|
7480
|
+
document.querySelectorAll(
|
|
7481
|
+
"nav [data-ohw-href-key], [data-ohw-nav-container] [data-ohw-href-key], [data-ohw-nav-drawer] [data-ohw-href-key]"
|
|
7482
|
+
).forEach((el) => {
|
|
7483
|
+
if (isNavbarHrefKey(el.getAttribute("data-ohw-href-key"))) {
|
|
7484
|
+
disableNativeHrefDrag(el);
|
|
7485
|
+
}
|
|
7486
|
+
});
|
|
7487
|
+
postToParentRef.current({
|
|
7488
|
+
type: "ow:change",
|
|
7489
|
+
nodes: [{ key: NAV_ORDER_KEY, text: planned.orderJson }]
|
|
7490
|
+
});
|
|
7491
|
+
applySelectionAfterDrop();
|
|
7492
|
+
clearNavDragVisuals();
|
|
7493
|
+
requestAnimationFrame(() => {
|
|
7494
|
+
if (editContentRef.current[NAV_ORDER_KEY] === planned.orderJson) {
|
|
7495
|
+
applyNavForest(planned.forest);
|
|
7496
|
+
}
|
|
7497
|
+
applySelectionAfterDrop();
|
|
7498
|
+
requestAnimationFrame(applySelectionAfterDrop);
|
|
7499
|
+
});
|
|
7500
|
+
return;
|
|
7501
|
+
}
|
|
7502
|
+
applySelectionAfterDrop();
|
|
7503
|
+
clearNavDragVisuals();
|
|
7504
|
+
},
|
|
7505
|
+
[clearNavDragVisuals, deselectRef, editContentRef, postToParentRef, selectRef]
|
|
7506
|
+
);
|
|
7507
|
+
commitNavDragRef.current = commitNavDrag;
|
|
7508
|
+
const startNavLinkDrag = useCallback4(
|
|
7509
|
+
(anchor, clientX, clientY, wasSelected) => {
|
|
7510
|
+
if (footerDragRef.current) return false;
|
|
7511
|
+
const hrefKey = anchor.getAttribute("data-ohw-href-key");
|
|
7512
|
+
if (!hrefKey || !isNavbarHrefKey(hrefKey)) return false;
|
|
7513
|
+
if (isNavbarButton3(anchor) || isDragHandleDisabled2(anchor)) return false;
|
|
7514
|
+
beginNavDrag({
|
|
7515
|
+
hrefKey,
|
|
7516
|
+
wasSelected,
|
|
7517
|
+
draggedEl: anchor,
|
|
7518
|
+
lastClientX: clientX,
|
|
7519
|
+
lastClientY: clientY,
|
|
7520
|
+
activeSlot: null
|
|
7521
|
+
});
|
|
7522
|
+
return true;
|
|
7523
|
+
},
|
|
7524
|
+
[beginNavDrag, footerDragRef, isDragHandleDisabled2, isNavbarButton3]
|
|
7525
|
+
);
|
|
7526
|
+
const onNavDragOver = useCallback4(
|
|
7527
|
+
(e) => {
|
|
7528
|
+
const session = navDragRef.current;
|
|
7529
|
+
if (!session) return false;
|
|
7530
|
+
e.preventDefault();
|
|
7531
|
+
if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
|
|
7532
|
+
const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey);
|
|
7533
|
+
refreshNavDragVisualsRef.current(session, slot, e.clientX, e.clientY);
|
|
7534
|
+
return true;
|
|
7535
|
+
},
|
|
7536
|
+
[]
|
|
7537
|
+
);
|
|
7538
|
+
useEffect7(() => {
|
|
7539
|
+
if (!isEditMode) return;
|
|
7540
|
+
const THRESHOLD = 10;
|
|
7541
|
+
const resolveWasSelected = (el) => {
|
|
7542
|
+
if (selectedElRef.current === el) return true;
|
|
7543
|
+
const activeAnchor = activeElRef.current ? getNavigationItemAnchor2(activeElRef.current) : null;
|
|
7544
|
+
return activeAnchor === el;
|
|
7545
|
+
};
|
|
7546
|
+
const onPointerDown = (e) => {
|
|
7547
|
+
if (e.button !== 0) return;
|
|
7548
|
+
if (navDragRef.current || footerDragRef.current) return;
|
|
7549
|
+
const target = e.target;
|
|
7550
|
+
if (!target) return;
|
|
7551
|
+
if (target.closest(
|
|
7552
|
+
'[data-ohw-drag-handle-container], [data-slot="drag-handle"], [data-ohw-toolbar], [data-ohw-item-toolbar-anchor], [data-ohw-link-popover-root]'
|
|
7553
|
+
)) {
|
|
7554
|
+
return;
|
|
7555
|
+
}
|
|
7556
|
+
if (target.closest("[data-ohw-item-drag-surface]")) return;
|
|
7557
|
+
const anchor = getNavigationItemAnchor2(target);
|
|
7558
|
+
const hrefKey = anchor?.getAttribute("data-ohw-href-key") ?? null;
|
|
7559
|
+
if (!anchor || !isNavbarHrefKey(hrefKey)) return;
|
|
7560
|
+
if (isNavbarButton3(anchor) || isDragHandleDisabled2(anchor)) return;
|
|
7561
|
+
navPointerDragRef.current = {
|
|
7562
|
+
el: anchor,
|
|
7563
|
+
startX: e.clientX,
|
|
7564
|
+
startY: e.clientY,
|
|
7565
|
+
pointerId: e.pointerId,
|
|
7566
|
+
wasSelected: resolveWasSelected(anchor),
|
|
7567
|
+
started: false
|
|
7568
|
+
};
|
|
7569
|
+
};
|
|
7570
|
+
const onPointerMove = (e) => {
|
|
7571
|
+
const pending = navPointerDragRef.current;
|
|
7572
|
+
if (!pending) return;
|
|
7573
|
+
if (pending.started) {
|
|
7574
|
+
e.preventDefault();
|
|
7575
|
+
clearTextSelection();
|
|
7576
|
+
const session = navDragRef.current;
|
|
7577
|
+
if (!session) return;
|
|
7578
|
+
const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey);
|
|
7579
|
+
refreshNavDragVisualsRef.current(session, slot, e.clientX, e.clientY);
|
|
7580
|
+
return;
|
|
7581
|
+
}
|
|
7582
|
+
const dx = e.clientX - pending.startX;
|
|
7583
|
+
const dy = e.clientY - pending.startY;
|
|
7584
|
+
if (dx * dx + dy * dy < THRESHOLD * THRESHOLD) return;
|
|
7585
|
+
e.preventDefault();
|
|
7586
|
+
pending.started = true;
|
|
7587
|
+
armItemPressDrag();
|
|
7588
|
+
clearTextSelection();
|
|
7589
|
+
try {
|
|
7590
|
+
document.body.setPointerCapture(pending.pointerId);
|
|
7591
|
+
} catch {
|
|
7592
|
+
}
|
|
7593
|
+
if (linkPopoverOpenRef.current) setLinkPopover(null);
|
|
7594
|
+
if (activeElRef.current) deactivateRef.current();
|
|
7595
|
+
const key = pending.el.getAttribute("data-ohw-href-key");
|
|
7596
|
+
if (!key) return;
|
|
7597
|
+
beginNavDragRef.current({
|
|
7598
|
+
hrefKey: key,
|
|
7599
|
+
wasSelected: pending.wasSelected,
|
|
7600
|
+
draggedEl: pending.el,
|
|
7601
|
+
lastClientX: e.clientX,
|
|
7602
|
+
lastClientY: e.clientY,
|
|
7603
|
+
activeSlot: null
|
|
7604
|
+
});
|
|
7605
|
+
};
|
|
7606
|
+
const endPointerDrag = (e) => {
|
|
7607
|
+
const pending = navPointerDragRef.current;
|
|
7608
|
+
navPointerDragRef.current = null;
|
|
7609
|
+
try {
|
|
7610
|
+
if (document.body.hasPointerCapture(e.pointerId)) {
|
|
7611
|
+
document.body.releasePointerCapture(e.pointerId);
|
|
7612
|
+
}
|
|
7613
|
+
} catch {
|
|
7614
|
+
}
|
|
7615
|
+
if (!pending) return;
|
|
7616
|
+
if (!pending.started) {
|
|
7617
|
+
unlockItemDragInteraction();
|
|
7618
|
+
return;
|
|
7619
|
+
}
|
|
7620
|
+
suppressNextClickRef.current = true;
|
|
7621
|
+
suppressClickUntilRef.current = Date.now() + 500;
|
|
7622
|
+
commitNavDragRef.current(e.clientX, e.clientY);
|
|
7623
|
+
};
|
|
7624
|
+
const blockSelectStart = (e) => {
|
|
7625
|
+
if (navDragRef.current || navPointerDragRef.current?.started || document.documentElement.hasAttribute("data-ohw-footer-press-drag")) {
|
|
7626
|
+
e.preventDefault();
|
|
7627
|
+
}
|
|
7628
|
+
};
|
|
7629
|
+
const onDragEnd = () => {
|
|
7630
|
+
if (!navDragRef.current) return;
|
|
7631
|
+
suppressNextClickRef.current = true;
|
|
7632
|
+
suppressClickUntilRef.current = Date.now() + 500;
|
|
7633
|
+
commitNavDragRef.current();
|
|
7634
|
+
};
|
|
7635
|
+
document.addEventListener("pointerdown", onPointerDown, true);
|
|
7636
|
+
document.addEventListener("pointermove", onPointerMove, true);
|
|
7637
|
+
document.addEventListener("pointerup", endPointerDrag, true);
|
|
7638
|
+
document.addEventListener("pointercancel", endPointerDrag, true);
|
|
7639
|
+
document.addEventListener("selectstart", blockSelectStart, true);
|
|
7640
|
+
document.addEventListener("dragend", onDragEnd, true);
|
|
7641
|
+
return () => {
|
|
7642
|
+
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
7643
|
+
document.removeEventListener("pointermove", onPointerMove, true);
|
|
7644
|
+
document.removeEventListener("pointerup", endPointerDrag, true);
|
|
7645
|
+
document.removeEventListener("pointercancel", endPointerDrag, true);
|
|
7646
|
+
document.removeEventListener("selectstart", blockSelectStart, true);
|
|
7647
|
+
document.removeEventListener("dragend", onDragEnd, true);
|
|
7648
|
+
unlockItemDragInteraction();
|
|
7649
|
+
};
|
|
7650
|
+
}, [
|
|
7651
|
+
activeElRef,
|
|
7652
|
+
deactivateRef,
|
|
7653
|
+
footerDragRef,
|
|
7654
|
+
getNavigationItemAnchor2,
|
|
7655
|
+
isDragHandleDisabled2,
|
|
7656
|
+
isEditMode,
|
|
7657
|
+
isNavbarButton3,
|
|
7658
|
+
linkPopoverOpenRef,
|
|
7659
|
+
selectedElRef,
|
|
7660
|
+
setLinkPopover,
|
|
7661
|
+
suppressNextClickRef
|
|
7662
|
+
]);
|
|
7663
|
+
const armNavPressFromChrome = useCallback4(
|
|
7664
|
+
(selected, clientX, clientY, pointerId) => {
|
|
7665
|
+
const hrefKey = selected.getAttribute("data-ohw-href-key");
|
|
7666
|
+
if (!hrefKey || !isNavbarHrefKey(hrefKey)) return false;
|
|
7667
|
+
if (isNavbarButton3(selected) || isDragHandleDisabled2(selected)) return false;
|
|
7668
|
+
navPointerDragRef.current = {
|
|
7669
|
+
el: selected,
|
|
7670
|
+
startX: clientX,
|
|
7671
|
+
startY: clientY,
|
|
7672
|
+
pointerId,
|
|
7673
|
+
wasSelected: true,
|
|
7674
|
+
started: false
|
|
7675
|
+
};
|
|
7676
|
+
return true;
|
|
7677
|
+
},
|
|
7678
|
+
[isDragHandleDisabled2, isNavbarButton3]
|
|
7679
|
+
);
|
|
7680
|
+
return {
|
|
7681
|
+
navDragRef,
|
|
7682
|
+
navDropSlots,
|
|
7683
|
+
activeNavDropIndex,
|
|
7684
|
+
startNavLinkDrag,
|
|
7685
|
+
commitNavDrag,
|
|
7686
|
+
onNavDragOver,
|
|
7687
|
+
armNavPressFromChrome,
|
|
7688
|
+
clearNavDragVisuals,
|
|
7689
|
+
refreshNavDragVisualsRef
|
|
7690
|
+
};
|
|
7691
|
+
}
|
|
7692
|
+
|
|
7693
|
+
// src/ui/navbar-container-chrome.tsx
|
|
7694
|
+
import { Plus as Plus2 } from "lucide-react";
|
|
7695
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
7696
|
+
function NavbarContainerChrome({
|
|
7697
|
+
rect,
|
|
7698
|
+
onAdd
|
|
7699
|
+
}) {
|
|
7700
|
+
const chromeGap = 6;
|
|
7701
|
+
return /* @__PURE__ */ jsx21(
|
|
7702
|
+
"div",
|
|
7703
|
+
{
|
|
7704
|
+
"data-ohw-navbar-container-chrome": "",
|
|
7705
|
+
"data-ohw-bridge": "",
|
|
7706
|
+
className: "pointer-events-none fixed z-[2147483647]",
|
|
7707
|
+
style: {
|
|
7708
|
+
top: rect.top - chromeGap,
|
|
7709
|
+
left: rect.left - chromeGap,
|
|
7710
|
+
width: rect.width + chromeGap * 2,
|
|
7711
|
+
height: rect.height + chromeGap * 2
|
|
7712
|
+
},
|
|
7713
|
+
children: /* @__PURE__ */ jsx21(
|
|
7714
|
+
"button",
|
|
7715
|
+
{
|
|
7716
|
+
type: "button",
|
|
7717
|
+
"data-ohw-navbar-add-button": "",
|
|
7718
|
+
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",
|
|
7719
|
+
style: { top: "70%" },
|
|
7720
|
+
"aria-label": "Add item",
|
|
7721
|
+
onMouseDown: (e) => {
|
|
7722
|
+
e.preventDefault();
|
|
7723
|
+
e.stopPropagation();
|
|
7724
|
+
},
|
|
7725
|
+
onClick: (e) => {
|
|
7726
|
+
e.preventDefault();
|
|
7727
|
+
e.stopPropagation();
|
|
7728
|
+
onAdd();
|
|
7729
|
+
},
|
|
7730
|
+
children: /* @__PURE__ */ jsx21(Plus2, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
|
|
7731
|
+
}
|
|
7732
|
+
)
|
|
7733
|
+
}
|
|
7734
|
+
);
|
|
7735
|
+
}
|
|
7736
|
+
|
|
7737
|
+
// src/ui/drop-indicator.tsx
|
|
7738
|
+
import * as React10 from "react";
|
|
7739
|
+
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
7740
|
+
var dropIndicatorVariants = cva(
|
|
7741
|
+
"ov-gap-line pointer-events-none shrink-0 transition-opacity duration-150",
|
|
7742
|
+
{
|
|
7743
|
+
variants: {
|
|
7744
|
+
direction: {
|
|
7745
|
+
vertical: "h-6 w-[3px]",
|
|
7746
|
+
horizontal: "h-[3px] w-[200px]"
|
|
7747
|
+
},
|
|
7748
|
+
state: {
|
|
7749
|
+
default: "opacity-0",
|
|
7750
|
+
hover: "opacity-100",
|
|
7751
|
+
dragIdle: "opacity-40",
|
|
7752
|
+
dragActive: "opacity-100"
|
|
7753
|
+
}
|
|
7754
|
+
},
|
|
7755
|
+
defaultVariants: {
|
|
7756
|
+
direction: "vertical",
|
|
7757
|
+
state: "default"
|
|
7758
|
+
}
|
|
7759
|
+
}
|
|
7760
|
+
);
|
|
7761
|
+
var DropIndicator = React10.forwardRef(
|
|
7762
|
+
({ className, direction, state, ...props }, ref) => {
|
|
7763
|
+
return /* @__PURE__ */ jsx22(
|
|
7764
|
+
"div",
|
|
7765
|
+
{
|
|
7766
|
+
ref,
|
|
7767
|
+
"data-slot": "drop-indicator",
|
|
7768
|
+
"data-direction": direction ?? "vertical",
|
|
7769
|
+
"data-state": state ?? "default",
|
|
7770
|
+
"aria-hidden": "true",
|
|
7771
|
+
className: cn(dropIndicatorVariants({ direction, state }), className),
|
|
7772
|
+
...props
|
|
7773
|
+
}
|
|
7774
|
+
);
|
|
7775
|
+
}
|
|
7776
|
+
);
|
|
7777
|
+
DropIndicator.displayName = "DropIndicator";
|
|
7778
|
+
|
|
7779
|
+
// src/ui/badge.tsx
|
|
7780
|
+
import { jsx as jsx23 } from "react/jsx-runtime";
|
|
7781
|
+
var badgeVariants = cva(
|
|
7782
|
+
"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",
|
|
7783
|
+
{
|
|
7784
|
+
variants: {
|
|
7785
|
+
variant: {
|
|
7786
|
+
default: "border-transparent bg-primary text-primary-foreground",
|
|
7787
|
+
secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
7788
|
+
destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
|
7789
|
+
outline: "text-foreground"
|
|
7790
|
+
}
|
|
7791
|
+
},
|
|
7792
|
+
defaultVariants: {
|
|
7793
|
+
variant: "default"
|
|
7794
|
+
}
|
|
7795
|
+
}
|
|
7796
|
+
);
|
|
7797
|
+
function Badge({ className, variant, ...props }) {
|
|
7798
|
+
return /* @__PURE__ */ jsx23("div", { className: cn(badgeVariants({ variant }), className), ...props });
|
|
7799
|
+
}
|
|
7800
|
+
|
|
7801
|
+
// src/OhhwellsBridge.tsx
|
|
7802
|
+
import { Link as Link2 } from "lucide-react";
|
|
7803
|
+
import { Fragment as Fragment5, jsx as jsx24, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
7804
|
+
var PRIMARY2 = "#0885FE";
|
|
7805
|
+
var IMAGE_FADE_MS = 300;
|
|
7806
|
+
function runOpacityFade(el, onDone) {
|
|
7807
|
+
const anim = el.animate([{ opacity: 0 }, { opacity: 1 }], {
|
|
7808
|
+
duration: IMAGE_FADE_MS,
|
|
7809
|
+
easing: "ease",
|
|
7810
|
+
fill: "forwards"
|
|
7811
|
+
});
|
|
7812
|
+
let finished = false;
|
|
7813
|
+
const finish = () => {
|
|
7814
|
+
if (finished) return;
|
|
7815
|
+
finished = true;
|
|
7816
|
+
anim.cancel();
|
|
7817
|
+
el.style.opacity = "";
|
|
7818
|
+
onDone();
|
|
7819
|
+
};
|
|
7820
|
+
anim.finished.then(finish).catch(finish);
|
|
7821
|
+
window.setTimeout(finish, IMAGE_FADE_MS + 100);
|
|
7822
|
+
}
|
|
7823
|
+
function fadeInImageElement(img, onReady) {
|
|
7824
|
+
onReady();
|
|
7825
|
+
img.style.opacity = "0";
|
|
7826
|
+
runOpacityFade(img, () => {
|
|
7827
|
+
img.style.opacity = "";
|
|
7828
|
+
});
|
|
7829
|
+
}
|
|
7830
|
+
function applyEditableImageSrc(img, url) {
|
|
7831
|
+
img.removeAttribute("srcset");
|
|
7832
|
+
img.removeAttribute("sizes");
|
|
7833
|
+
img.src = url;
|
|
7834
|
+
}
|
|
7835
|
+
function fadeInBgImage(el, url, onReady) {
|
|
7836
|
+
const prevPos = el.style.position;
|
|
7837
|
+
if (!prevPos || prevPos === "static") el.style.position = "relative";
|
|
7838
|
+
const layer = document.createElement("div");
|
|
7839
|
+
layer.setAttribute("data-ohw-bg-fade-layer", "");
|
|
7840
|
+
Object.assign(layer.style, {
|
|
6552
7841
|
position: "absolute",
|
|
6553
7842
|
inset: "0",
|
|
6554
7843
|
zIndex: "0",
|
|
@@ -6690,7 +7979,7 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
6690
7979
|
const root = createRoot(container);
|
|
6691
7980
|
flushSync(() => {
|
|
6692
7981
|
root.render(
|
|
6693
|
-
/* @__PURE__ */
|
|
7982
|
+
/* @__PURE__ */ jsx24(
|
|
6694
7983
|
SchedulingWidget,
|
|
6695
7984
|
{
|
|
6696
7985
|
notifyOnConnect,
|
|
@@ -6752,7 +8041,20 @@ function isDragHandleDisabled(el) {
|
|
|
6752
8041
|
return raw === "true" || raw === "";
|
|
6753
8042
|
});
|
|
6754
8043
|
}
|
|
6755
|
-
function
|
|
8044
|
+
function canDragNavigationItem(anchor) {
|
|
8045
|
+
const { key, disabled } = getNavigationItemReorderState(anchor);
|
|
8046
|
+
return Boolean(key) && !disabled;
|
|
8047
|
+
}
|
|
8048
|
+
function syncNavigationDragCursorAttrs() {
|
|
8049
|
+
document.querySelectorAll("nav [data-ohw-href-key], footer [data-ohw-href-key]").forEach((el) => {
|
|
8050
|
+
if (!isNavigationItem(el) || !canDragNavigationItem(el)) {
|
|
8051
|
+
el.removeAttribute("data-ohw-can-drag");
|
|
8052
|
+
return;
|
|
8053
|
+
}
|
|
8054
|
+
el.setAttribute("data-ohw-can-drag", "");
|
|
8055
|
+
});
|
|
8056
|
+
}
|
|
8057
|
+
function collectEditableNodes(extraContent) {
|
|
6756
8058
|
const nodes = Array.from(document.querySelectorAll("[data-ohw-editable]")).map((el) => {
|
|
6757
8059
|
if (el.dataset.ohwEditable === "image") {
|
|
6758
8060
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
@@ -6780,6 +8082,14 @@ function collectEditableNodes() {
|
|
|
6780
8082
|
if (!key) return;
|
|
6781
8083
|
nodes.push({ key, type: "link", text: getLinkHref2(el) });
|
|
6782
8084
|
});
|
|
8085
|
+
if (extraContent) {
|
|
8086
|
+
for (const key of [NAV_ORDER_KEY, FOOTER_ORDER_KEY, NAV_COUNT_KEY]) {
|
|
8087
|
+
const text = extraContent[key];
|
|
8088
|
+
if (typeof text === "string" && text.length > 0) {
|
|
8089
|
+
nodes.push({ key, type: "meta", text });
|
|
8090
|
+
}
|
|
8091
|
+
}
|
|
8092
|
+
}
|
|
6783
8093
|
document.querySelectorAll('[data-ohw-editable="video"]').forEach((el) => {
|
|
6784
8094
|
const key = el.dataset.ohwKey ?? "";
|
|
6785
8095
|
const video = getVideoEl(el);
|
|
@@ -6893,6 +8203,11 @@ function getNavigationItemAnchor(el) {
|
|
|
6893
8203
|
function isNavigationItem(el) {
|
|
6894
8204
|
return getNavigationItemAnchor(el) !== null;
|
|
6895
8205
|
}
|
|
8206
|
+
function listNavigationItems() {
|
|
8207
|
+
return Array.from(
|
|
8208
|
+
document.querySelectorAll("nav [data-ohw-href-key], footer [data-ohw-href-key]")
|
|
8209
|
+
).filter((el) => isNavigationItem(el));
|
|
8210
|
+
}
|
|
6896
8211
|
function getNavigationItemReorderState(anchor) {
|
|
6897
8212
|
if (isNavbarButton2(anchor)) return { key: null, disabled: false };
|
|
6898
8213
|
return getReorderHandleStateFromAnchor(anchor);
|
|
@@ -6921,18 +8236,20 @@ function getNavigationRoot(el) {
|
|
|
6921
8236
|
if (explicit) return explicit;
|
|
6922
8237
|
return el.closest("nav, footer, aside");
|
|
6923
8238
|
}
|
|
8239
|
+
function countFooterNavItems(el) {
|
|
8240
|
+
return Array.from(el.querySelectorAll("[data-ohw-href-key]")).filter(isNavigationItem).length;
|
|
8241
|
+
}
|
|
6924
8242
|
function findFooterItemGroup(item) {
|
|
8243
|
+
const explicit = item.closest("[data-ohw-footer-col], [data-ohw-footer-column]");
|
|
8244
|
+
if (explicit) return explicit;
|
|
6925
8245
|
const footer = item.closest("footer");
|
|
6926
8246
|
if (!footer) return null;
|
|
6927
8247
|
let node = item.parentElement;
|
|
6928
8248
|
while (node && node !== footer) {
|
|
6929
|
-
|
|
6930
|
-
node.querySelectorAll(":scope > [data-ohw-href-key]")
|
|
6931
|
-
).some(isNavigationItem);
|
|
6932
|
-
if (hasDirectNavItems) return node;
|
|
8249
|
+
if (countFooterNavItems(node) >= 2) return node;
|
|
6933
8250
|
node = node.parentElement;
|
|
6934
8251
|
}
|
|
6935
|
-
return
|
|
8252
|
+
return footer;
|
|
6936
8253
|
}
|
|
6937
8254
|
function isNavigationRoot(el) {
|
|
6938
8255
|
return el.hasAttribute("data-ohw-nav-root") || el.matches("nav, footer, aside");
|
|
@@ -6940,16 +8257,49 @@ function isNavigationRoot(el) {
|
|
|
6940
8257
|
function isInferredFooterGroup(el) {
|
|
6941
8258
|
const footer = el.closest("footer");
|
|
6942
8259
|
if (!footer || el === footer) return false;
|
|
6943
|
-
|
|
8260
|
+
if (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column")) return true;
|
|
8261
|
+
return countFooterNavItems(el) >= 2;
|
|
6944
8262
|
}
|
|
6945
8263
|
function isNavigationContainer(el) {
|
|
6946
|
-
return el.hasAttribute("data-ohw-nav-container") || isNavigationRoot(el) || isInferredFooterGroup(el);
|
|
8264
|
+
return el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isNavigationRoot(el) || isInferredFooterGroup(el);
|
|
8265
|
+
}
|
|
8266
|
+
function isNavbarLinksContainer(el) {
|
|
8267
|
+
return el.hasAttribute("data-ohw-nav-container");
|
|
8268
|
+
}
|
|
8269
|
+
function getFooterColumn(el) {
|
|
8270
|
+
return el.closest("[data-ohw-footer-col], [data-ohw-footer-column]");
|
|
8271
|
+
}
|
|
8272
|
+
function resolveFooterColumnSelectionTarget(target, clientX, clientY) {
|
|
8273
|
+
if (getNavigationItemAnchor(target)) return null;
|
|
8274
|
+
const column = getFooterColumn(target);
|
|
8275
|
+
if (!column) return null;
|
|
8276
|
+
if (isPointOverNavItem(column, clientX, clientY)) return null;
|
|
8277
|
+
return column;
|
|
6947
8278
|
}
|
|
6948
8279
|
function isPointOverNavigation(x, y) {
|
|
8280
|
+
const roots = /* @__PURE__ */ new Set();
|
|
6949
8281
|
const navRoot = document.querySelector("[data-ohw-nav-root]") ?? document.querySelector("nav");
|
|
6950
|
-
if (
|
|
6951
|
-
const
|
|
6952
|
-
|
|
8282
|
+
if (navRoot) roots.add(navRoot);
|
|
8283
|
+
const footer = document.querySelector("footer");
|
|
8284
|
+
if (footer) roots.add(footer);
|
|
8285
|
+
for (const root of roots) {
|
|
8286
|
+
const r2 = root.getBoundingClientRect();
|
|
8287
|
+
if (x >= r2.left && x <= r2.right && y >= r2.top && y <= r2.bottom) return true;
|
|
8288
|
+
}
|
|
8289
|
+
return false;
|
|
8290
|
+
}
|
|
8291
|
+
function findHoveredNavOrFooterContainer(x, y) {
|
|
8292
|
+
const candidates = [
|
|
8293
|
+
...document.querySelectorAll("[data-ohw-nav-container]"),
|
|
8294
|
+
...listFooterColumns()
|
|
8295
|
+
];
|
|
8296
|
+
for (const container of candidates) {
|
|
8297
|
+
const r2 = container.getBoundingClientRect();
|
|
8298
|
+
if (x < r2.left || x > r2.right || y < r2.top || y > r2.bottom) continue;
|
|
8299
|
+
if (isPointOverNavItem(container, x, y)) continue;
|
|
8300
|
+
return container;
|
|
8301
|
+
}
|
|
8302
|
+
return null;
|
|
6953
8303
|
}
|
|
6954
8304
|
function isPointOverNavItem(container, x, y) {
|
|
6955
8305
|
return Array.from(container.querySelectorAll("[data-ohw-href-key]")).some((el) => {
|
|
@@ -6982,36 +8332,63 @@ function getNavigationSelectionParent(el) {
|
|
|
6982
8332
|
if (isNavigationItem(el)) {
|
|
6983
8333
|
const explicit = el.closest("[data-ohw-nav-container]");
|
|
6984
8334
|
if (explicit) return explicit;
|
|
8335
|
+
const footerColumn = getFooterColumn(el);
|
|
8336
|
+
if (footerColumn) return footerColumn;
|
|
6985
8337
|
const footerGroup = findFooterItemGroup(el);
|
|
6986
8338
|
if (footerGroup) return footerGroup;
|
|
6987
8339
|
return getNavigationRoot(el);
|
|
6988
8340
|
}
|
|
6989
|
-
if (el.hasAttribute("data-ohw-nav-container") || isInferredFooterGroup(el)) {
|
|
8341
|
+
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup(el)) {
|
|
6990
8342
|
return getNavigationRoot(el);
|
|
6991
8343
|
}
|
|
6992
8344
|
return null;
|
|
6993
8345
|
}
|
|
8346
|
+
function collectNavigationItemSiblingHintRects(selected) {
|
|
8347
|
+
if (!isNavigationItem(selected)) return [];
|
|
8348
|
+
const footerColumn = getFooterColumn(selected);
|
|
8349
|
+
if (footerColumn) {
|
|
8350
|
+
return listFooterLinksInColumn(footerColumn).filter((link) => link !== selected).map((link) => link.getBoundingClientRect());
|
|
8351
|
+
}
|
|
8352
|
+
const navContainer = selected.closest("[data-ohw-nav-container], [data-ohw-nav-drawer]");
|
|
8353
|
+
if (navContainer) {
|
|
8354
|
+
return Array.from(navContainer.querySelectorAll("[data-ohw-href-key]")).filter((el) => isNavigationItem(el) && el !== selected).map((el) => el.getBoundingClientRect());
|
|
8355
|
+
}
|
|
8356
|
+
return listNavigationItems().filter((el) => el !== selected).map((el) => el.getBoundingClientRect());
|
|
8357
|
+
}
|
|
6994
8358
|
function placeCaretAtPoint(el, x, y) {
|
|
6995
8359
|
const selection = window.getSelection();
|
|
6996
8360
|
if (!selection) return;
|
|
6997
|
-
|
|
6998
|
-
|
|
6999
|
-
|
|
7000
|
-
|
|
7001
|
-
|
|
7002
|
-
|
|
8361
|
+
const overlays = Array.from(
|
|
8362
|
+
document.querySelectorAll(
|
|
8363
|
+
"[data-ohw-item-drag-surface], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-ohw-item-toolbar-anchor]"
|
|
8364
|
+
)
|
|
8365
|
+
);
|
|
8366
|
+
const prevPointerEvents = overlays.map((node) => node.style.pointerEvents);
|
|
8367
|
+
for (const node of overlays) node.style.pointerEvents = "none";
|
|
8368
|
+
try {
|
|
8369
|
+
if (typeof document.caretRangeFromPoint === "function") {
|
|
8370
|
+
const range = document.caretRangeFromPoint(x, y);
|
|
8371
|
+
if (range && el.contains(range.startContainer)) {
|
|
8372
|
+
selection.removeAllRanges();
|
|
8373
|
+
selection.addRange(range);
|
|
8374
|
+
return;
|
|
8375
|
+
}
|
|
7003
8376
|
}
|
|
7004
|
-
|
|
7005
|
-
|
|
7006
|
-
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
8377
|
+
const caretPositionFromPoint = document.caretPositionFromPoint;
|
|
8378
|
+
if (typeof caretPositionFromPoint === "function") {
|
|
8379
|
+
const position = caretPositionFromPoint(x, y);
|
|
8380
|
+
if (position && el.contains(position.offsetNode)) {
|
|
8381
|
+
const range = document.createRange();
|
|
8382
|
+
range.setStart(position.offsetNode, position.offset);
|
|
8383
|
+
range.collapse(true);
|
|
8384
|
+
selection.removeAllRanges();
|
|
8385
|
+
selection.addRange(range);
|
|
8386
|
+
}
|
|
7014
8387
|
}
|
|
8388
|
+
} finally {
|
|
8389
|
+
overlays.forEach((node, i) => {
|
|
8390
|
+
node.style.pointerEvents = prevPointerEvents[i] ?? "";
|
|
8391
|
+
});
|
|
7015
8392
|
}
|
|
7016
8393
|
}
|
|
7017
8394
|
function selectAllTextInEditable(el) {
|
|
@@ -7132,9 +8509,16 @@ function sanitizeHtml(html) {
|
|
|
7132
8509
|
if (!SAFE_TAGS.has(el.tagName)) {
|
|
7133
8510
|
parent.replaceChild(document.createTextNode(el.textContent ?? ""), el);
|
|
7134
8511
|
} else {
|
|
7135
|
-
const
|
|
8512
|
+
const htmlEl = el;
|
|
8513
|
+
const textAlign = htmlEl.style?.textAlign || el.getAttribute("align") || "";
|
|
8514
|
+
const fontWeight = htmlEl.style?.fontWeight || "";
|
|
8515
|
+
const fontStyle = htmlEl.style?.fontStyle || "";
|
|
8516
|
+
const textDecorationLine = htmlEl.style?.textDecorationLine || htmlEl.style?.textDecoration || "";
|
|
7136
8517
|
for (const attr of Array.from(el.attributes)) el.removeAttribute(attr.name);
|
|
7137
|
-
if (textAlign)
|
|
8518
|
+
if (textAlign) htmlEl.style.textAlign = textAlign;
|
|
8519
|
+
if (fontWeight) htmlEl.style.fontWeight = fontWeight;
|
|
8520
|
+
if (fontStyle) htmlEl.style.fontStyle = fontStyle;
|
|
8521
|
+
if (textDecorationLine) htmlEl.style.textDecorationLine = textDecorationLine;
|
|
7138
8522
|
walk(el);
|
|
7139
8523
|
}
|
|
7140
8524
|
}
|
|
@@ -7153,6 +8537,9 @@ var ICONS = {
|
|
|
7153
8537
|
insertUnorderedList: '<line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/>',
|
|
7154
8538
|
insertOrderedList: '<line x1="10" y1="6" x2="21" y2="6"/><line x1="10" y1="12" x2="21" y2="12"/><line x1="10" y1="18" x2="21" y2="18"/><path d="M4 6h1v4"/><path d="M4 10h2"/><path d="M6 18H4c0-1 2-2 2-3s-1-1.5-2-1"/>'
|
|
7155
8539
|
};
|
|
8540
|
+
var SELECTION_CHROME_GAP2 = 4;
|
|
8541
|
+
var TOOLBAR_STROKE_GAP2 = 4;
|
|
8542
|
+
var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
|
|
7156
8543
|
var TOOLBAR_GROUPS = [
|
|
7157
8544
|
[
|
|
7158
8545
|
{ cmd: "bold", title: "Bold" },
|
|
@@ -7174,9 +8561,10 @@ function EditGlowChrome({
|
|
|
7174
8561
|
rect,
|
|
7175
8562
|
elRef,
|
|
7176
8563
|
reorderHrefKey,
|
|
7177
|
-
dragDisabled = false
|
|
8564
|
+
dragDisabled = false,
|
|
8565
|
+
hideHandle = false
|
|
7178
8566
|
}) {
|
|
7179
|
-
const GAP =
|
|
8567
|
+
const GAP = SELECTION_CHROME_GAP2;
|
|
7180
8568
|
return /* @__PURE__ */ jsxs13(
|
|
7181
8569
|
"div",
|
|
7182
8570
|
{
|
|
@@ -7192,7 +8580,7 @@ function EditGlowChrome({
|
|
|
7192
8580
|
zIndex: 2147483646
|
|
7193
8581
|
},
|
|
7194
8582
|
children: [
|
|
7195
|
-
/* @__PURE__ */
|
|
8583
|
+
/* @__PURE__ */ jsx24(
|
|
7196
8584
|
"div",
|
|
7197
8585
|
{
|
|
7198
8586
|
style: {
|
|
@@ -7200,12 +8588,12 @@ function EditGlowChrome({
|
|
|
7200
8588
|
inset: 0,
|
|
7201
8589
|
border: "2px solid var(--ohw-primary, #0885FE)",
|
|
7202
8590
|
borderRadius: 8,
|
|
7203
|
-
boxShadow: "0 0 0 4px
|
|
8591
|
+
boxShadow: "0 0 0 4px color-mix(in srgb, var(--ohw-primary, #0885FE) 12%, transparent)",
|
|
7204
8592
|
pointerEvents: "none"
|
|
7205
8593
|
}
|
|
7206
8594
|
}
|
|
7207
8595
|
),
|
|
7208
|
-
reorderHrefKey && /* @__PURE__ */
|
|
8596
|
+
reorderHrefKey && !hideHandle && /* @__PURE__ */ jsx24(
|
|
7209
8597
|
"div",
|
|
7210
8598
|
{
|
|
7211
8599
|
"data-ohw-drag-handle-container": "",
|
|
@@ -7217,7 +8605,7 @@ function EditGlowChrome({
|
|
|
7217
8605
|
transform: "translate(calc(-100% - 7px), -50%)",
|
|
7218
8606
|
pointerEvents: dragDisabled ? "none" : "auto"
|
|
7219
8607
|
},
|
|
7220
|
-
children: /* @__PURE__ */
|
|
8608
|
+
children: /* @__PURE__ */ jsx24(
|
|
7221
8609
|
DragHandle,
|
|
7222
8610
|
{
|
|
7223
8611
|
"aria-label": `Reorder ${reorderHrefKey}`,
|
|
@@ -7248,6 +8636,7 @@ function applyVisibleViewport(el, parentScroll) {
|
|
|
7248
8636
|
el.style.top = `${top}px`;
|
|
7249
8637
|
el.style.height = `${height}px`;
|
|
7250
8638
|
}
|
|
8639
|
+
var TOOLBAR_EDGE_MARGIN2 = 4;
|
|
7251
8640
|
function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
|
|
7252
8641
|
const isAbove = transform.includes("translateY(-100%)");
|
|
7253
8642
|
let visualTop = isAbove ? top - approxH : top;
|
|
@@ -7271,10 +8660,16 @@ function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
|
|
|
7271
8660
|
const pinnedTop = Math.min(maxBottom - approxH, Math.max(minTop, clip.top + gap));
|
|
7272
8661
|
return { top: pinnedTop + approxH, transform: "translateX(-50%) translateY(-100%)" };
|
|
7273
8662
|
}
|
|
7274
|
-
function
|
|
7275
|
-
const
|
|
8663
|
+
function clampToolbarLeft(centerX, toolbarWidth) {
|
|
8664
|
+
const half = toolbarWidth / 2;
|
|
8665
|
+
return Math.max(
|
|
8666
|
+
TOOLBAR_EDGE_MARGIN2 + half,
|
|
8667
|
+
Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN2 - half)
|
|
8668
|
+
);
|
|
8669
|
+
}
|
|
8670
|
+
function calcToolbarPos(rect, parentScroll, toolbarW = 306) {
|
|
8671
|
+
const GAP = TOOLBAR_OFFSET_FROM_ELEMENT;
|
|
7276
8672
|
const APPROX_H = 32;
|
|
7277
|
-
const APPROX_W = approxW;
|
|
7278
8673
|
const clip = getIframeVisibleClip(parentScroll);
|
|
7279
8674
|
const clipTop = clip?.top ?? 0;
|
|
7280
8675
|
const canvasTopInIframe = parentScroll != null ? parentScroll.headerH - parentScroll.iframeOffsetTop : 0;
|
|
@@ -7304,13 +8699,86 @@ function calcToolbarPos(rect, parentScroll, approxW = 306) {
|
|
|
7304
8699
|
transform = clamped.transform;
|
|
7305
8700
|
}
|
|
7306
8701
|
const rawLeft = rect.left + rect.width / 2;
|
|
7307
|
-
const left =
|
|
8702
|
+
const left = clampToolbarLeft(rawLeft, toolbarW);
|
|
7308
8703
|
return { top, left, transform };
|
|
7309
8704
|
}
|
|
7310
8705
|
function resolveItemInteractionState(rect, parentScroll) {
|
|
7311
8706
|
const { transform } = calcToolbarPos(rect, parentScroll, 120);
|
|
7312
8707
|
return transform.includes("translateY(-100%)") ? "active-top" : "active-bottom";
|
|
7313
8708
|
}
|
|
8709
|
+
function resolveSelectionStartElement(sel) {
|
|
8710
|
+
if (!sel || sel.rangeCount === 0) return null;
|
|
8711
|
+
const range = sel.getRangeAt(0);
|
|
8712
|
+
let startNode = range.startContainer;
|
|
8713
|
+
if (startNode.nodeType === Node.ELEMENT_NODE) {
|
|
8714
|
+
const el = startNode;
|
|
8715
|
+
startNode = el.childNodes[range.startOffset] ?? el.childNodes[range.startOffset - 1] ?? el;
|
|
8716
|
+
}
|
|
8717
|
+
return startNode.nodeType === Node.TEXT_NODE ? startNode.parentElement : startNode;
|
|
8718
|
+
}
|
|
8719
|
+
function detectActiveFormats(startEl, activeRoot) {
|
|
8720
|
+
const formats = /* @__PURE__ */ new Set();
|
|
8721
|
+
const cs = getComputedStyle(startEl);
|
|
8722
|
+
const weight = parseInt(cs.fontWeight, 10);
|
|
8723
|
+
let hasBold = cs.fontWeight === "bold" || !Number.isNaN(weight) && weight >= 600;
|
|
8724
|
+
let hasItalic = cs.fontStyle === "italic" || cs.fontStyle === "oblique";
|
|
8725
|
+
let hasUnderline = false;
|
|
8726
|
+
let hasStrike = false;
|
|
8727
|
+
let hasUl = false;
|
|
8728
|
+
let hasOl = false;
|
|
8729
|
+
for (let el = startEl; el; el = el.parentElement) {
|
|
8730
|
+
if (el.tagName === "B" || el.tagName === "STRONG") hasBold = true;
|
|
8731
|
+
if (el.tagName === "I" || el.tagName === "EM") hasItalic = true;
|
|
8732
|
+
const decoration = getComputedStyle(el).textDecorationLine;
|
|
8733
|
+
if (decoration.includes("underline") || el.tagName === "U" || el.tagName === "INS") hasUnderline = true;
|
|
8734
|
+
if (decoration.includes("line-through") || el.tagName === "S" || el.tagName === "STRIKE" || el.tagName === "DEL") hasStrike = true;
|
|
8735
|
+
if (el.tagName === "UL") hasUl = true;
|
|
8736
|
+
if (el.tagName === "OL") hasOl = true;
|
|
8737
|
+
if (el === activeRoot) break;
|
|
8738
|
+
}
|
|
8739
|
+
if (hasBold) formats.add("bold");
|
|
8740
|
+
if (hasItalic) formats.add("italic");
|
|
8741
|
+
if (hasUnderline) formats.add("underline");
|
|
8742
|
+
if (hasStrike) formats.add("strikeThrough");
|
|
8743
|
+
if (hasUl) formats.add("insertUnorderedList");
|
|
8744
|
+
if (hasOl) formats.add("insertOrderedList");
|
|
8745
|
+
const block = startEl.closest("div, p, h1, h2, h3, h4, h5, h6, li, td, th") ?? startEl;
|
|
8746
|
+
const align = getComputedStyle(block).textAlign;
|
|
8747
|
+
if (align === "center") formats.add("justifyCenter");
|
|
8748
|
+
else if (align === "right" || align === "end") formats.add("justifyRight");
|
|
8749
|
+
else formats.add("justifyLeft");
|
|
8750
|
+
return formats;
|
|
8751
|
+
}
|
|
8752
|
+
function setsEqual(a, b) {
|
|
8753
|
+
if (a.size !== b.size) return false;
|
|
8754
|
+
for (const item of a) {
|
|
8755
|
+
if (!b.has(item)) return false;
|
|
8756
|
+
}
|
|
8757
|
+
return true;
|
|
8758
|
+
}
|
|
8759
|
+
function textOffsetInRoot(root, node, offset) {
|
|
8760
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
|
|
8761
|
+
let total = 0;
|
|
8762
|
+
let current;
|
|
8763
|
+
while (current = walker.nextNode()) {
|
|
8764
|
+
if (current === node) return total + offset;
|
|
8765
|
+
total += (current.textContent ?? "").length;
|
|
8766
|
+
}
|
|
8767
|
+
return total;
|
|
8768
|
+
}
|
|
8769
|
+
function pointAtTextOffset(root, targetOffset) {
|
|
8770
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
|
|
8771
|
+
let total = 0;
|
|
8772
|
+
let current;
|
|
8773
|
+
let last = null;
|
|
8774
|
+
while (current = walker.nextNode()) {
|
|
8775
|
+
const len = (current.textContent ?? "").length;
|
|
8776
|
+
if (total + len >= targetOffset) return { node: current, offset: targetOffset - total };
|
|
8777
|
+
total += len;
|
|
8778
|
+
last = current;
|
|
8779
|
+
}
|
|
8780
|
+
return last ? { node: last, offset: (last.textContent ?? "").length } : null;
|
|
8781
|
+
}
|
|
7314
8782
|
function FloatingToolbar({
|
|
7315
8783
|
rect,
|
|
7316
8784
|
parentScroll,
|
|
@@ -7320,11 +8788,37 @@ function FloatingToolbar({
|
|
|
7320
8788
|
showEditLink,
|
|
7321
8789
|
onEditLink
|
|
7322
8790
|
}) {
|
|
7323
|
-
const
|
|
7324
|
-
|
|
8791
|
+
const localRef = React11.useRef(null);
|
|
8792
|
+
const [measuredW, setMeasuredW] = React11.useState(330);
|
|
8793
|
+
const setRefs = React11.useCallback(
|
|
8794
|
+
(node) => {
|
|
8795
|
+
localRef.current = node;
|
|
8796
|
+
if (typeof elRef === "function") elRef(node);
|
|
8797
|
+
else if (elRef) elRef.current = node;
|
|
8798
|
+
if (node) {
|
|
8799
|
+
const w = node.offsetWidth;
|
|
8800
|
+
if (w > 0) setMeasuredW(w);
|
|
8801
|
+
}
|
|
8802
|
+
},
|
|
8803
|
+
[elRef]
|
|
8804
|
+
);
|
|
8805
|
+
React11.useLayoutEffect(() => {
|
|
8806
|
+
const node = localRef.current;
|
|
8807
|
+
if (!node) return;
|
|
8808
|
+
const update = () => {
|
|
8809
|
+
const w = node.offsetWidth;
|
|
8810
|
+
if (w > 0) setMeasuredW(w);
|
|
8811
|
+
};
|
|
8812
|
+
update();
|
|
8813
|
+
const ro = new ResizeObserver(update);
|
|
8814
|
+
ro.observe(node);
|
|
8815
|
+
return () => ro.disconnect();
|
|
8816
|
+
}, [showEditLink, activeCommands]);
|
|
8817
|
+
const { top, left, transform } = calcToolbarPos(rect, parentScroll, measuredW);
|
|
8818
|
+
return /* @__PURE__ */ jsx24(
|
|
7325
8819
|
"div",
|
|
7326
8820
|
{
|
|
7327
|
-
ref:
|
|
8821
|
+
ref: setRefs,
|
|
7328
8822
|
style: {
|
|
7329
8823
|
position: "fixed",
|
|
7330
8824
|
top,
|
|
@@ -7334,11 +8828,11 @@ function FloatingToolbar({
|
|
|
7334
8828
|
pointerEvents: "auto"
|
|
7335
8829
|
},
|
|
7336
8830
|
children: /* @__PURE__ */ jsxs13(CustomToolbar, { children: [
|
|
7337
|
-
TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs13(
|
|
7338
|
-
gi > 0 && /* @__PURE__ */
|
|
8831
|
+
TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs13(React11.Fragment, { children: [
|
|
8832
|
+
gi > 0 && /* @__PURE__ */ jsx24(CustomToolbarDivider, {}),
|
|
7339
8833
|
btns.map((btn) => {
|
|
7340
8834
|
const isActive = activeCommands.has(btn.cmd);
|
|
7341
|
-
return /* @__PURE__ */
|
|
8835
|
+
return /* @__PURE__ */ jsx24(
|
|
7342
8836
|
CustomToolbarButton,
|
|
7343
8837
|
{
|
|
7344
8838
|
title: btn.title,
|
|
@@ -7347,7 +8841,7 @@ function FloatingToolbar({
|
|
|
7347
8841
|
e.preventDefault();
|
|
7348
8842
|
onCommand(btn.cmd);
|
|
7349
8843
|
},
|
|
7350
|
-
children: /* @__PURE__ */
|
|
8844
|
+
children: /* @__PURE__ */ jsx24(
|
|
7351
8845
|
"svg",
|
|
7352
8846
|
{
|
|
7353
8847
|
width: "16",
|
|
@@ -7368,7 +8862,7 @@ function FloatingToolbar({
|
|
|
7368
8862
|
);
|
|
7369
8863
|
})
|
|
7370
8864
|
] }, gi)),
|
|
7371
|
-
showEditLink ? /* @__PURE__ */
|
|
8865
|
+
showEditLink ? /* @__PURE__ */ jsx24(
|
|
7372
8866
|
CustomToolbarButton,
|
|
7373
8867
|
{
|
|
7374
8868
|
type: "button",
|
|
@@ -7382,7 +8876,7 @@ function FloatingToolbar({
|
|
|
7382
8876
|
e.preventDefault();
|
|
7383
8877
|
e.stopPropagation();
|
|
7384
8878
|
},
|
|
7385
|
-
children: /* @__PURE__ */
|
|
8879
|
+
children: /* @__PURE__ */ jsx24(Link2, { className: "size-4 shrink-0", "aria-hidden": true })
|
|
7386
8880
|
}
|
|
7387
8881
|
) : null
|
|
7388
8882
|
] })
|
|
@@ -7399,7 +8893,7 @@ function StateToggle({
|
|
|
7399
8893
|
states,
|
|
7400
8894
|
onStateChange
|
|
7401
8895
|
}) {
|
|
7402
|
-
return /* @__PURE__ */
|
|
8896
|
+
return /* @__PURE__ */ jsx24(
|
|
7403
8897
|
ToggleGroup,
|
|
7404
8898
|
{
|
|
7405
8899
|
"data-ohw-state-toggle": "",
|
|
@@ -7413,7 +8907,7 @@ function StateToggle({
|
|
|
7413
8907
|
left: rect.right - 8,
|
|
7414
8908
|
transform: "translateX(-100%)"
|
|
7415
8909
|
},
|
|
7416
|
-
children: states.map((state) => /* @__PURE__ */
|
|
8910
|
+
children: states.map((state) => /* @__PURE__ */ jsx24(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
|
|
7417
8911
|
}
|
|
7418
8912
|
);
|
|
7419
8913
|
}
|
|
@@ -7440,8 +8934,8 @@ function OhhwellsBridge() {
|
|
|
7440
8934
|
const router = useRouter2();
|
|
7441
8935
|
const searchParams = useSearchParams();
|
|
7442
8936
|
const isEditMode = isEditSessionActive();
|
|
7443
|
-
const [bridgeRoot, setBridgeRoot] =
|
|
7444
|
-
|
|
8937
|
+
const [bridgeRoot, setBridgeRoot] = useState7(null);
|
|
8938
|
+
useEffect8(() => {
|
|
7445
8939
|
const figtreeFontId = "ohw-figtree-font";
|
|
7446
8940
|
if (!document.getElementById(figtreeFontId)) {
|
|
7447
8941
|
const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
|
|
@@ -7469,91 +8963,137 @@ function OhhwellsBridge() {
|
|
|
7469
8963
|
const subdomainFromQuery = searchParams.get("subdomain");
|
|
7470
8964
|
const subdomain = resolveSubdomain(subdomainFromQuery);
|
|
7471
8965
|
useLinkHrefGuardian(pathname, subdomain, isEditMode);
|
|
7472
|
-
const postToParent2 =
|
|
8966
|
+
const postToParent2 = useCallback5((data) => {
|
|
7473
8967
|
if (typeof window !== "undefined" && window.parent !== window) {
|
|
7474
8968
|
window.parent.postMessage(data, "*");
|
|
7475
8969
|
}
|
|
7476
8970
|
}, []);
|
|
7477
|
-
const [fetchState, setFetchState] =
|
|
7478
|
-
const autoSaveTimers =
|
|
7479
|
-
const activeElRef =
|
|
7480
|
-
const
|
|
7481
|
-
const
|
|
7482
|
-
const
|
|
7483
|
-
const
|
|
7484
|
-
const
|
|
7485
|
-
const
|
|
7486
|
-
const
|
|
8971
|
+
const [fetchState, setFetchState] = useState7("idle");
|
|
8972
|
+
const autoSaveTimers = useRef7(/* @__PURE__ */ new Map());
|
|
8973
|
+
const activeElRef = useRef7(null);
|
|
8974
|
+
const pointerHeldRef = useRef7(false);
|
|
8975
|
+
const selectedElRef = useRef7(null);
|
|
8976
|
+
const selectedHrefKeyRef = useRef7(null);
|
|
8977
|
+
const selectedFooterColAttrRef = useRef7(null);
|
|
8978
|
+
const originalContentRef = useRef7(null);
|
|
8979
|
+
const activeStateElRef = useRef7(null);
|
|
8980
|
+
const parentScrollRef = useRef7(null);
|
|
8981
|
+
const visibleViewportRef = useRef7(null);
|
|
8982
|
+
const [dialogPortalContainer, setDialogPortalContainer] = useState7(null);
|
|
8983
|
+
const attachVisibleViewport = useCallback5((node) => {
|
|
7487
8984
|
visibleViewportRef.current = node;
|
|
7488
8985
|
setDialogPortalContainer(node);
|
|
7489
8986
|
if (node) applyVisibleViewport(node, parentScrollRef.current);
|
|
7490
8987
|
}, []);
|
|
7491
|
-
const toolbarElRef =
|
|
7492
|
-
const glowElRef =
|
|
7493
|
-
const hoveredImageRef =
|
|
7494
|
-
const hoveredImageHasTextOverlapRef =
|
|
7495
|
-
const dragOverElRef =
|
|
7496
|
-
const [mediaHover, setMediaHover] =
|
|
7497
|
-
const [uploadingRects, setUploadingRects] =
|
|
7498
|
-
const hoveredGapRef =
|
|
7499
|
-
const imageUnhoverTimerRef =
|
|
7500
|
-
const imageShowTimerRef =
|
|
7501
|
-
const editStylesRef =
|
|
7502
|
-
const activateRef =
|
|
8988
|
+
const toolbarElRef = useRef7(null);
|
|
8989
|
+
const glowElRef = useRef7(null);
|
|
8990
|
+
const hoveredImageRef = useRef7(null);
|
|
8991
|
+
const hoveredImageHasTextOverlapRef = useRef7(false);
|
|
8992
|
+
const dragOverElRef = useRef7(null);
|
|
8993
|
+
const [mediaHover, setMediaHover] = useState7(null);
|
|
8994
|
+
const [uploadingRects, setUploadingRects] = useState7({});
|
|
8995
|
+
const hoveredGapRef = useRef7(null);
|
|
8996
|
+
const imageUnhoverTimerRef = useRef7(null);
|
|
8997
|
+
const imageShowTimerRef = useRef7(null);
|
|
8998
|
+
const editStylesRef = useRef7(null);
|
|
8999
|
+
const activateRef = useRef7(() => {
|
|
7503
9000
|
});
|
|
7504
|
-
const deactivateRef =
|
|
9001
|
+
const deactivateRef = useRef7(() => {
|
|
7505
9002
|
});
|
|
7506
|
-
const selectRef =
|
|
9003
|
+
const selectRef = useRef7(() => {
|
|
7507
9004
|
});
|
|
7508
|
-
const selectFrameRef =
|
|
9005
|
+
const selectFrameRef = useRef7(() => {
|
|
7509
9006
|
});
|
|
7510
|
-
const deselectRef =
|
|
9007
|
+
const deselectRef = useRef7(() => {
|
|
7511
9008
|
});
|
|
7512
|
-
const reselectNavigationItemRef =
|
|
9009
|
+
const reselectNavigationItemRef = useRef7(() => {
|
|
7513
9010
|
});
|
|
7514
|
-
const commitNavigationTextEditRef =
|
|
9011
|
+
const commitNavigationTextEditRef = useRef7(() => {
|
|
7515
9012
|
});
|
|
7516
|
-
const refreshActiveCommandsRef =
|
|
9013
|
+
const refreshActiveCommandsRef = useRef7(() => {
|
|
7517
9014
|
});
|
|
7518
|
-
const postToParentRef =
|
|
9015
|
+
const postToParentRef = useRef7(postToParent2);
|
|
7519
9016
|
postToParentRef.current = postToParent2;
|
|
7520
|
-
const sectionsLoadedRef =
|
|
7521
|
-
const pendingScheduleConfigRequests =
|
|
7522
|
-
const [toolbarRect, setToolbarRect] =
|
|
7523
|
-
const [toolbarVariant, setToolbarVariant] =
|
|
7524
|
-
const toolbarVariantRef =
|
|
9017
|
+
const sectionsLoadedRef = useRef7(false);
|
|
9018
|
+
const pendingScheduleConfigRequests = useRef7([]);
|
|
9019
|
+
const [toolbarRect, setToolbarRect] = useState7(null);
|
|
9020
|
+
const [toolbarVariant, setToolbarVariant] = useState7("none");
|
|
9021
|
+
const toolbarVariantRef = useRef7("none");
|
|
7525
9022
|
toolbarVariantRef.current = toolbarVariant;
|
|
7526
|
-
const [
|
|
7527
|
-
const [
|
|
7528
|
-
const [
|
|
7529
|
-
const [
|
|
7530
|
-
const [
|
|
7531
|
-
const [
|
|
7532
|
-
const [
|
|
7533
|
-
const
|
|
7534
|
-
const
|
|
7535
|
-
const
|
|
7536
|
-
const
|
|
7537
|
-
const
|
|
7538
|
-
const
|
|
7539
|
-
const [
|
|
7540
|
-
const [
|
|
7541
|
-
const
|
|
7542
|
-
const
|
|
7543
|
-
const
|
|
7544
|
-
const [
|
|
7545
|
-
const [
|
|
7546
|
-
const
|
|
7547
|
-
const
|
|
7548
|
-
const
|
|
7549
|
-
const
|
|
7550
|
-
const
|
|
9023
|
+
const [selectedIsCta, setSelectedIsCta] = useState7(false);
|
|
9024
|
+
const [reorderHrefKey, setReorderHrefKey] = useState7(null);
|
|
9025
|
+
const [reorderDragDisabled, setReorderDragDisabled] = useState7(false);
|
|
9026
|
+
const [toggleState, setToggleState] = useState7(null);
|
|
9027
|
+
const [maxBadge, setMaxBadge] = useState7(null);
|
|
9028
|
+
const [activeCommands, setActiveCommands] = useState7(/* @__PURE__ */ new Set());
|
|
9029
|
+
const [sectionGap, setSectionGap] = useState7(null);
|
|
9030
|
+
const [toolbarShowEditLink, setToolbarShowEditLink] = useState7(false);
|
|
9031
|
+
const hoveredNavContainerRef = useRef7(null);
|
|
9032
|
+
const [hoveredNavContainerRect, setHoveredNavContainerRect] = useState7(null);
|
|
9033
|
+
const hoveredItemElRef = useRef7(null);
|
|
9034
|
+
const [hoveredItemRect, setHoveredItemRect] = useState7(null);
|
|
9035
|
+
const siblingHintElRef = useRef7(null);
|
|
9036
|
+
const [siblingHintRect, setSiblingHintRect] = useState7(null);
|
|
9037
|
+
const [siblingHintRects, setSiblingHintRects] = useState7([]);
|
|
9038
|
+
const [isItemDragging, setIsItemDragging] = useState7(false);
|
|
9039
|
+
const [isFooterFrameSelection, setIsFooterFrameSelection] = useState7(false);
|
|
9040
|
+
const footerDragRef = useRef7(null);
|
|
9041
|
+
const [footerDropSlots, setFooterDropSlots] = useState7([]);
|
|
9042
|
+
const [activeFooterDropIndex, setActiveFooterDropIndex] = useState7(null);
|
|
9043
|
+
const [draggedItemRect, setDraggedItemRect] = useState7(null);
|
|
9044
|
+
const footerPointerDragRef = useRef7(null);
|
|
9045
|
+
const suppressNextClickRef = useRef7(false);
|
|
9046
|
+
const suppressClickUntilRef = useRef7(0);
|
|
9047
|
+
const [linkPopover, setLinkPopover] = useState7(null);
|
|
9048
|
+
const linkPopoverSessionRef = useRef7(null);
|
|
9049
|
+
const addNavAfterAnchorRef = useRef7(null);
|
|
9050
|
+
const editContentRef = useRef7({});
|
|
9051
|
+
const [sitePages, setSitePages] = useState7([]);
|
|
9052
|
+
const [sectionsByPath, setSectionsByPath] = useState7({});
|
|
9053
|
+
const sectionsPrefetchGenRef = useRef7(0);
|
|
9054
|
+
const setLinkPopoverRef = useRef7(setLinkPopover);
|
|
9055
|
+
const linkPopoverPanelRef = useRef7(null);
|
|
9056
|
+
const linkPopoverOpenRef = useRef7(false);
|
|
9057
|
+
const linkPopoverGraceUntilRef = useRef7(0);
|
|
7551
9058
|
setLinkPopoverRef.current = setLinkPopover;
|
|
7552
9059
|
linkPopoverSessionRef.current = linkPopover;
|
|
9060
|
+
const {
|
|
9061
|
+
navDragRef,
|
|
9062
|
+
navDropSlots,
|
|
9063
|
+
activeNavDropIndex,
|
|
9064
|
+
startNavLinkDrag,
|
|
9065
|
+
commitNavDrag,
|
|
9066
|
+
onNavDragOver,
|
|
9067
|
+
armNavPressFromChrome,
|
|
9068
|
+
refreshNavDragVisualsRef
|
|
9069
|
+
} = useNavItemDrag({
|
|
9070
|
+
isEditMode,
|
|
9071
|
+
editContentRef,
|
|
9072
|
+
selectedElRef,
|
|
9073
|
+
activeElRef,
|
|
9074
|
+
footerDragRef,
|
|
9075
|
+
suppressNextClickRef,
|
|
9076
|
+
suppressClickUntilRef,
|
|
9077
|
+
siblingHintElRef,
|
|
9078
|
+
postToParentRef,
|
|
9079
|
+
deselectRef,
|
|
9080
|
+
selectRef,
|
|
9081
|
+
deactivateRef,
|
|
9082
|
+
setLinkPopover: () => setLinkPopover(null),
|
|
9083
|
+
linkPopoverOpenRef,
|
|
9084
|
+
setIsItemDragging,
|
|
9085
|
+
setDraggedItemRect,
|
|
9086
|
+
setSiblingHintRect,
|
|
9087
|
+
setSiblingHintRects,
|
|
9088
|
+
setToolbarRect,
|
|
9089
|
+
getNavigationItemAnchor,
|
|
9090
|
+
isDragHandleDisabled,
|
|
9091
|
+
isNavbarButton: isNavbarButton2
|
|
9092
|
+
});
|
|
7553
9093
|
const bumpLinkPopoverGrace = () => {
|
|
7554
9094
|
linkPopoverGraceUntilRef.current = Date.now() + 350;
|
|
7555
9095
|
};
|
|
7556
|
-
const runSectionsPrefetch =
|
|
9096
|
+
const runSectionsPrefetch = useCallback5((pages) => {
|
|
7557
9097
|
if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
|
|
7558
9098
|
const gen = ++sectionsPrefetchGenRef.current;
|
|
7559
9099
|
const paths = pages.map((p) => p.path);
|
|
@@ -7572,10 +9112,24 @@ function OhhwellsBridge() {
|
|
|
7572
9112
|
);
|
|
7573
9113
|
});
|
|
7574
9114
|
}, [isEditMode, pathname]);
|
|
7575
|
-
const runSectionsPrefetchRef =
|
|
9115
|
+
const runSectionsPrefetchRef = useRef7(runSectionsPrefetch);
|
|
7576
9116
|
runSectionsPrefetchRef.current = runSectionsPrefetch;
|
|
7577
|
-
|
|
7578
|
-
if (!linkPopover)
|
|
9117
|
+
useEffect8(() => {
|
|
9118
|
+
if (!linkPopover) {
|
|
9119
|
+
document.documentElement.removeAttribute("data-ohw-link-popover-open");
|
|
9120
|
+
return;
|
|
9121
|
+
}
|
|
9122
|
+
document.documentElement.setAttribute("data-ohw-link-popover-open", "");
|
|
9123
|
+
hoveredItemElRef.current = null;
|
|
9124
|
+
setHoveredItemRect(null);
|
|
9125
|
+
hoveredNavContainerRef.current = null;
|
|
9126
|
+
setHoveredNavContainerRect(null);
|
|
9127
|
+
siblingHintElRef.current = null;
|
|
9128
|
+
setSiblingHintRect(null);
|
|
9129
|
+
setSiblingHintRects([]);
|
|
9130
|
+
if (selectedElRef.current || toolbarVariantRef.current !== "none") {
|
|
9131
|
+
deselectRef.current();
|
|
9132
|
+
}
|
|
7579
9133
|
if (hoveredImageRef.current) {
|
|
7580
9134
|
hoveredImageRef.current = null;
|
|
7581
9135
|
hoveredImageHasTextOverlapRef.current = false;
|
|
@@ -7609,7 +9163,7 @@ function OhhwellsBridge() {
|
|
|
7609
9163
|
document.removeEventListener("touchmove", preventBackgroundScroll, scrollOpts);
|
|
7610
9164
|
};
|
|
7611
9165
|
}, [linkPopover, postToParent2]);
|
|
7612
|
-
|
|
9166
|
+
useEffect8(() => {
|
|
7613
9167
|
if (!isEditMode) return;
|
|
7614
9168
|
const useFixtures = shouldUseDevFixtures();
|
|
7615
9169
|
if (useFixtures) {
|
|
@@ -7633,14 +9187,14 @@ function OhhwellsBridge() {
|
|
|
7633
9187
|
if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
|
|
7634
9188
|
return () => window.removeEventListener("message", onSitePages);
|
|
7635
9189
|
}, [isEditMode, postToParent2]);
|
|
7636
|
-
|
|
9190
|
+
useEffect8(() => {
|
|
7637
9191
|
if (!isEditMode || shouldUseDevFixtures()) return;
|
|
7638
9192
|
void loadAllSectionsManifest().then((manifest) => {
|
|
7639
9193
|
if (Object.keys(manifest).length === 0) return;
|
|
7640
9194
|
setSectionsByPath((prev) => ({ ...manifest, ...prev }));
|
|
7641
9195
|
});
|
|
7642
9196
|
}, [isEditMode]);
|
|
7643
|
-
|
|
9197
|
+
useEffect8(() => {
|
|
7644
9198
|
const update = () => {
|
|
7645
9199
|
const el = activeElRef.current ?? selectedElRef.current;
|
|
7646
9200
|
if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
|
|
@@ -7664,10 +9218,10 @@ function OhhwellsBridge() {
|
|
|
7664
9218
|
vvp.removeEventListener("resize", update);
|
|
7665
9219
|
};
|
|
7666
9220
|
}, []);
|
|
7667
|
-
const refreshStateRules =
|
|
9221
|
+
const refreshStateRules = useCallback5(() => {
|
|
7668
9222
|
editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
|
|
7669
9223
|
}, []);
|
|
7670
|
-
const processConfigRequest =
|
|
9224
|
+
const processConfigRequest = useCallback5((insertAfterVal) => {
|
|
7671
9225
|
const tracker = getSectionsTracker();
|
|
7672
9226
|
let entries = [];
|
|
7673
9227
|
try {
|
|
@@ -7690,7 +9244,7 @@ function OhhwellsBridge() {
|
|
|
7690
9244
|
}
|
|
7691
9245
|
window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
|
|
7692
9246
|
}, [isEditMode]);
|
|
7693
|
-
const deactivate =
|
|
9247
|
+
const deactivate = useCallback5(() => {
|
|
7694
9248
|
const el = activeElRef.current;
|
|
7695
9249
|
if (!el) return;
|
|
7696
9250
|
const key = el.dataset.ohwKey;
|
|
@@ -7709,6 +9263,7 @@ function OhhwellsBridge() {
|
|
|
7709
9263
|
}
|
|
7710
9264
|
}
|
|
7711
9265
|
el.removeAttribute("contenteditable");
|
|
9266
|
+
el.removeAttribute("data-ohw-editing");
|
|
7712
9267
|
activeElRef.current = null;
|
|
7713
9268
|
setReorderHrefKey(null);
|
|
7714
9269
|
setReorderDragDisabled(false);
|
|
@@ -7721,12 +9276,23 @@ function OhhwellsBridge() {
|
|
|
7721
9276
|
setToolbarShowEditLink(false);
|
|
7722
9277
|
postToParent2({ type: "ow:exit-edit" });
|
|
7723
9278
|
}, [postToParent2]);
|
|
7724
|
-
const
|
|
9279
|
+
const clearSelectedAttr = useCallback5(() => {
|
|
9280
|
+
document.querySelectorAll("[data-ohw-selected]").forEach((el) => {
|
|
9281
|
+
el.removeAttribute("data-ohw-selected");
|
|
9282
|
+
});
|
|
9283
|
+
}, []);
|
|
9284
|
+
const deselect = useCallback5(() => {
|
|
9285
|
+
clearSelectedAttr();
|
|
7725
9286
|
selectedElRef.current = null;
|
|
9287
|
+
selectedHrefKeyRef.current = null;
|
|
9288
|
+
selectedFooterColAttrRef.current = null;
|
|
9289
|
+
setSelectedIsCta(false);
|
|
7726
9290
|
setReorderHrefKey(null);
|
|
7727
9291
|
setReorderDragDisabled(false);
|
|
9292
|
+
setIsFooterFrameSelection(false);
|
|
7728
9293
|
siblingHintElRef.current = null;
|
|
7729
9294
|
setSiblingHintRect(null);
|
|
9295
|
+
setSiblingHintRects([]);
|
|
7730
9296
|
setIsItemDragging(false);
|
|
7731
9297
|
hoveredNavContainerRef.current = null;
|
|
7732
9298
|
setHoveredNavContainerRect(null);
|
|
@@ -7734,18 +9300,70 @@ function OhhwellsBridge() {
|
|
|
7734
9300
|
setToolbarRect(null);
|
|
7735
9301
|
setToolbarVariant("none");
|
|
7736
9302
|
}
|
|
9303
|
+
}, [clearSelectedAttr]);
|
|
9304
|
+
const markSelected = useCallback5((el) => {
|
|
9305
|
+
clearSelectedAttr();
|
|
9306
|
+
el.setAttribute("data-ohw-selected", "");
|
|
9307
|
+
}, [clearSelectedAttr]);
|
|
9308
|
+
const resolveHrefKeyElement = useCallback5((hrefKey) => {
|
|
9309
|
+
if (isFooterHrefKey(hrefKey)) {
|
|
9310
|
+
return document.querySelector(
|
|
9311
|
+
`footer [data-ohw-href-key="${CSS.escape(hrefKey)}"]`
|
|
9312
|
+
);
|
|
9313
|
+
}
|
|
9314
|
+
if (isNavbarHrefKey(hrefKey)) {
|
|
9315
|
+
const desktop = document.querySelector("[data-ohw-nav-container]");
|
|
9316
|
+
const drawer = document.querySelector("[data-ohw-nav-drawer]");
|
|
9317
|
+
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)}"]`);
|
|
9318
|
+
}
|
|
9319
|
+
return document.querySelector(
|
|
9320
|
+
`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`
|
|
9321
|
+
);
|
|
7737
9322
|
}, []);
|
|
7738
|
-
const
|
|
9323
|
+
const resyncSelectedNavigationItem = useCallback5(() => {
|
|
9324
|
+
const hrefKey = selectedHrefKeyRef.current;
|
|
9325
|
+
if (hrefKey) {
|
|
9326
|
+
const link = resolveHrefKeyElement(hrefKey);
|
|
9327
|
+
if (!link || !isNavigationItem(link)) return;
|
|
9328
|
+
selectedElRef.current = link;
|
|
9329
|
+
const { key, disabled } = getNavigationItemReorderState(link);
|
|
9330
|
+
setReorderHrefKey(key);
|
|
9331
|
+
setReorderDragDisabled(disabled);
|
|
9332
|
+
setIsFooterFrameSelection(false);
|
|
9333
|
+
setToolbarVariant("link-action");
|
|
9334
|
+
setToolbarRect(link.getBoundingClientRect());
|
|
9335
|
+
setSiblingHintRects(collectNavigationItemSiblingHintRects(link));
|
|
9336
|
+
return;
|
|
9337
|
+
}
|
|
9338
|
+
const colAttr = selectedFooterColAttrRef.current;
|
|
9339
|
+
if (colAttr != null) {
|
|
9340
|
+
const column = document.querySelector(`[data-ohw-footer-col="${CSS.escape(colAttr)}"]`) ?? listFooterColumns()[Number(colAttr)] ?? null;
|
|
9341
|
+
if (!column || !isNavigationContainer(column)) return;
|
|
9342
|
+
selectedElRef.current = column;
|
|
9343
|
+
setIsFooterFrameSelection(true);
|
|
9344
|
+
setToolbarVariant("select-frame");
|
|
9345
|
+
setToolbarRect(column.getBoundingClientRect());
|
|
9346
|
+
setSiblingHintRects(
|
|
9347
|
+
listFooterColumns().filter((c) => c !== column).map((c) => c.getBoundingClientRect())
|
|
9348
|
+
);
|
|
9349
|
+
}
|
|
9350
|
+
}, [resolveHrefKeyElement]);
|
|
9351
|
+
const reselectNavigationItem = useCallback5((navAnchor) => {
|
|
7739
9352
|
selectedElRef.current = navAnchor;
|
|
9353
|
+
selectedHrefKeyRef.current = navAnchor.getAttribute("data-ohw-href-key");
|
|
9354
|
+
selectedFooterColAttrRef.current = null;
|
|
9355
|
+
markSelected(navAnchor);
|
|
9356
|
+
setSelectedIsCta(isNavbarButton2(navAnchor));
|
|
7740
9357
|
const { key, disabled } = getNavigationItemReorderState(navAnchor);
|
|
7741
9358
|
setReorderHrefKey(key);
|
|
7742
9359
|
setReorderDragDisabled(disabled);
|
|
7743
9360
|
setToolbarVariant("link-action");
|
|
7744
9361
|
setToolbarRect(navAnchor.getBoundingClientRect());
|
|
9362
|
+
setSiblingHintRects(collectNavigationItemSiblingHintRects(navAnchor));
|
|
7745
9363
|
setToolbarShowEditLink(false);
|
|
7746
9364
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
7747
|
-
}, []);
|
|
7748
|
-
const commitNavigationTextEdit =
|
|
9365
|
+
}, [markSelected]);
|
|
9366
|
+
const commitNavigationTextEdit = useCallback5((navAnchor) => {
|
|
7749
9367
|
const el = activeElRef.current;
|
|
7750
9368
|
if (!el) return;
|
|
7751
9369
|
const key = el.dataset.ohwKey;
|
|
@@ -7764,6 +9382,7 @@ function OhhwellsBridge() {
|
|
|
7764
9382
|
}
|
|
7765
9383
|
}
|
|
7766
9384
|
el.removeAttribute("contenteditable");
|
|
9385
|
+
el.removeAttribute("data-ohw-editing");
|
|
7767
9386
|
activeElRef.current = null;
|
|
7768
9387
|
setMaxBadge(null);
|
|
7769
9388
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
@@ -7771,7 +9390,7 @@ function OhhwellsBridge() {
|
|
|
7771
9390
|
postToParent2({ type: "ow:exit-edit" });
|
|
7772
9391
|
reselectNavigationItem(navAnchor);
|
|
7773
9392
|
}, [postToParent2, reselectNavigationItem]);
|
|
7774
|
-
const handleAddTopLevelNavItem =
|
|
9393
|
+
const handleAddTopLevelNavItem = useCallback5(() => {
|
|
7775
9394
|
const items = listNavbarItems();
|
|
7776
9395
|
addNavAfterAnchorRef.current = items[items.length - 1] ?? null;
|
|
7777
9396
|
deselectRef.current();
|
|
@@ -7783,20 +9402,321 @@ function OhhwellsBridge() {
|
|
|
7783
9402
|
intent: "add-nav"
|
|
7784
9403
|
});
|
|
7785
9404
|
}, []);
|
|
7786
|
-
const
|
|
7787
|
-
|
|
7788
|
-
|
|
7789
|
-
|
|
7790
|
-
|
|
7791
|
-
|
|
9405
|
+
const clearFooterDragVisuals = useCallback5(() => {
|
|
9406
|
+
footerDragRef.current = null;
|
|
9407
|
+
setSiblingHintRects([]);
|
|
9408
|
+
setFooterDropSlots([]);
|
|
9409
|
+
setActiveFooterDropIndex(null);
|
|
9410
|
+
setDraggedItemRect(null);
|
|
7792
9411
|
setIsItemDragging(false);
|
|
9412
|
+
unlockFooterDragInteraction();
|
|
9413
|
+
}, []);
|
|
9414
|
+
const refreshFooterDragVisuals = useCallback5((session, activeSlot, clientX, clientY) => {
|
|
9415
|
+
const dragged = session.draggedEl;
|
|
9416
|
+
setDraggedItemRect(dragged.getBoundingClientRect());
|
|
9417
|
+
if (typeof clientX === "number" && typeof clientY === "number") {
|
|
9418
|
+
session.lastClientX = clientX;
|
|
9419
|
+
session.lastClientY = clientY;
|
|
9420
|
+
}
|
|
9421
|
+
session.activeSlot = activeSlot;
|
|
9422
|
+
if (session.kind === "link") {
|
|
9423
|
+
const columns2 = listFooterColumns();
|
|
9424
|
+
const focusCols = /* @__PURE__ */ new Set([session.sourceColumnIndex]);
|
|
9425
|
+
if (activeSlot) focusCols.add(activeSlot.columnIndex);
|
|
9426
|
+
const siblingRects = [];
|
|
9427
|
+
columns2.forEach((col, i) => {
|
|
9428
|
+
if (!focusCols.has(i)) return;
|
|
9429
|
+
for (const link of listFooterLinksInColumn(col)) {
|
|
9430
|
+
if (link === dragged) continue;
|
|
9431
|
+
siblingRects.push(link.getBoundingClientRect());
|
|
9432
|
+
}
|
|
9433
|
+
});
|
|
9434
|
+
setSiblingHintRects(siblingRects);
|
|
9435
|
+
const slots2 = [];
|
|
9436
|
+
columns2.forEach((col, i) => {
|
|
9437
|
+
slots2.push(...buildLinkDropSlots(col, i));
|
|
9438
|
+
});
|
|
9439
|
+
setFooterDropSlots(slots2);
|
|
9440
|
+
const activeIdx2 = activeSlot ? slots2.findIndex((s) => s.columnIndex === activeSlot.columnIndex && s.insertIndex === activeSlot.insertIndex) : -1;
|
|
9441
|
+
setActiveFooterDropIndex(activeIdx2 >= 0 ? activeIdx2 : null);
|
|
9442
|
+
return;
|
|
9443
|
+
}
|
|
9444
|
+
const columns = listFooterColumns();
|
|
9445
|
+
setSiblingHintRects(columns.filter((col) => col !== dragged).map((col) => col.getBoundingClientRect()));
|
|
9446
|
+
const slots = buildColumnDropSlots();
|
|
9447
|
+
setFooterDropSlots(slots);
|
|
9448
|
+
const activeIdx = activeSlot ? slots.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
|
|
9449
|
+
setActiveFooterDropIndex(activeIdx >= 0 ? activeIdx : null);
|
|
9450
|
+
}, []);
|
|
9451
|
+
const refreshFooterDragVisualsRef = useRef7(refreshFooterDragVisuals);
|
|
9452
|
+
refreshFooterDragVisualsRef.current = refreshFooterDragVisuals;
|
|
9453
|
+
const commitFooterDragRef = useRef7(() => {
|
|
9454
|
+
});
|
|
9455
|
+
const beginFooterDragRef = useRef7(() => {
|
|
9456
|
+
});
|
|
9457
|
+
const beginFooterDrag = useCallback5(
|
|
9458
|
+
(session) => {
|
|
9459
|
+
const rect = session.draggedEl.getBoundingClientRect();
|
|
9460
|
+
session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
|
|
9461
|
+
session.lastClientY = session.lastClientY || rect.top + rect.height / 2;
|
|
9462
|
+
session.activeSlot = session.activeSlot ?? null;
|
|
9463
|
+
footerDragRef.current = session;
|
|
9464
|
+
setIsItemDragging(true);
|
|
9465
|
+
lockFooterDuringDrag();
|
|
9466
|
+
siblingHintElRef.current = null;
|
|
9467
|
+
setSiblingHintRect(null);
|
|
9468
|
+
if (session.wasSelected && selectedElRef.current === session.draggedEl) {
|
|
9469
|
+
setToolbarRect(rect);
|
|
9470
|
+
}
|
|
9471
|
+
const initialSlot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : hitTestColumnDropSlot(session.lastClientX, session.lastClientY);
|
|
9472
|
+
refreshFooterDragVisuals(session, initialSlot, session.lastClientX, session.lastClientY);
|
|
9473
|
+
},
|
|
9474
|
+
[refreshFooterDragVisuals]
|
|
9475
|
+
);
|
|
9476
|
+
beginFooterDragRef.current = beginFooterDrag;
|
|
9477
|
+
const commitFooterDrag = useCallback5(
|
|
9478
|
+
(clientX, clientY) => {
|
|
9479
|
+
const session = footerDragRef.current;
|
|
9480
|
+
if (!session) {
|
|
9481
|
+
clearFooterDragVisuals();
|
|
9482
|
+
return;
|
|
9483
|
+
}
|
|
9484
|
+
const x = typeof clientX === "number" && (clientX !== 0 || clientY !== 0) ? clientX : session.lastClientX;
|
|
9485
|
+
const y = typeof clientY === "number" && (clientX !== 0 || clientY !== 0) ? clientY : session.lastClientY;
|
|
9486
|
+
let nextOrder = null;
|
|
9487
|
+
const slot = session.activeSlot ?? (session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(x, y, session.hrefKey) : session.kind === "column" ? hitTestColumnDropSlot(x, y) : null);
|
|
9488
|
+
if (session.kind === "link" && session.hrefKey && slot) {
|
|
9489
|
+
nextOrder = planFooterLinkMove(session.hrefKey, slot.columnIndex, slot.insertIndex);
|
|
9490
|
+
} else if (session.kind === "column" && slot) {
|
|
9491
|
+
nextOrder = planFooterColumnMove(session.sourceColumnIndex, slot.insertIndex);
|
|
9492
|
+
}
|
|
9493
|
+
const wasSelected = session.wasSelected;
|
|
9494
|
+
const draggedEl = session.draggedEl;
|
|
9495
|
+
const hrefKey = session.hrefKey;
|
|
9496
|
+
let movedColumnIndex = null;
|
|
9497
|
+
if (session.kind === "column" && slot && nextOrder) {
|
|
9498
|
+
let adjusted = slot.insertIndex;
|
|
9499
|
+
if (session.sourceColumnIndex < slot.insertIndex) adjusted -= 1;
|
|
9500
|
+
movedColumnIndex = Math.max(0, Math.min(adjusted, nextOrder.length - 1));
|
|
9501
|
+
}
|
|
9502
|
+
const applySelectionAfterDrop = () => {
|
|
9503
|
+
if (!wasSelected) {
|
|
9504
|
+
deselectRef.current();
|
|
9505
|
+
return;
|
|
9506
|
+
}
|
|
9507
|
+
if (hrefKey) {
|
|
9508
|
+
selectedHrefKeyRef.current = hrefKey;
|
|
9509
|
+
selectedFooterColAttrRef.current = null;
|
|
9510
|
+
const link = resolveHrefKeyElement(hrefKey);
|
|
9511
|
+
if (link && isNavigationItem(link)) {
|
|
9512
|
+
selectRef.current(link);
|
|
9513
|
+
return;
|
|
9514
|
+
}
|
|
9515
|
+
}
|
|
9516
|
+
if (movedColumnIndex !== null && nextOrder) {
|
|
9517
|
+
const colKeys = nextOrder[movedColumnIndex] ?? [];
|
|
9518
|
+
let column = null;
|
|
9519
|
+
for (const key of colKeys) {
|
|
9520
|
+
const link = document.querySelector(
|
|
9521
|
+
`footer [data-ohw-href-key="${CSS.escape(key)}"]`
|
|
9522
|
+
);
|
|
9523
|
+
if (link) {
|
|
9524
|
+
column = findFooterColumnForLink(link);
|
|
9525
|
+
if (column) break;
|
|
9526
|
+
}
|
|
9527
|
+
}
|
|
9528
|
+
if (!column) column = listFooterColumns()[movedColumnIndex] ?? null;
|
|
9529
|
+
if (column && isNavigationContainer(column)) {
|
|
9530
|
+
selectFrameRef.current(column);
|
|
9531
|
+
return;
|
|
9532
|
+
}
|
|
9533
|
+
}
|
|
9534
|
+
if (document.body.contains(draggedEl)) {
|
|
9535
|
+
if (isNavigationItem(draggedEl)) {
|
|
9536
|
+
selectRef.current(draggedEl);
|
|
9537
|
+
return;
|
|
9538
|
+
}
|
|
9539
|
+
if (isNavigationContainer(draggedEl)) {
|
|
9540
|
+
selectFrameRef.current(draggedEl);
|
|
9541
|
+
return;
|
|
9542
|
+
}
|
|
9543
|
+
}
|
|
9544
|
+
deselectRef.current();
|
|
9545
|
+
};
|
|
9546
|
+
if (nextOrder) {
|
|
9547
|
+
const orderJson = JSON.stringify(nextOrder);
|
|
9548
|
+
editContentRef.current = {
|
|
9549
|
+
...editContentRef.current,
|
|
9550
|
+
[FOOTER_ORDER_KEY]: orderJson
|
|
9551
|
+
};
|
|
9552
|
+
applyFooterOrder(nextOrder);
|
|
9553
|
+
document.querySelectorAll("footer [data-ohw-href-key]").forEach(disableNativeHrefDrag);
|
|
9554
|
+
postToParentRef.current({
|
|
9555
|
+
type: "ow:change",
|
|
9556
|
+
nodes: [{ key: FOOTER_ORDER_KEY, text: orderJson }]
|
|
9557
|
+
});
|
|
9558
|
+
applySelectionAfterDrop();
|
|
9559
|
+
clearFooterDragVisuals();
|
|
9560
|
+
requestAnimationFrame(() => {
|
|
9561
|
+
if (editContentRef.current[FOOTER_ORDER_KEY] === orderJson) {
|
|
9562
|
+
applyFooterOrder(nextOrder);
|
|
9563
|
+
document.querySelectorAll("footer [data-ohw-href-key]").forEach(disableNativeHrefDrag);
|
|
9564
|
+
}
|
|
9565
|
+
applySelectionAfterDrop();
|
|
9566
|
+
requestAnimationFrame(() => {
|
|
9567
|
+
if (editContentRef.current[FOOTER_ORDER_KEY] === orderJson) {
|
|
9568
|
+
applyFooterOrder(nextOrder);
|
|
9569
|
+
}
|
|
9570
|
+
resyncSelectedNavigationItem();
|
|
9571
|
+
});
|
|
9572
|
+
});
|
|
9573
|
+
return;
|
|
9574
|
+
}
|
|
9575
|
+
applySelectionAfterDrop();
|
|
9576
|
+
clearFooterDragVisuals();
|
|
9577
|
+
},
|
|
9578
|
+
[clearFooterDragVisuals, resolveHrefKeyElement, resyncSelectedNavigationItem]
|
|
9579
|
+
);
|
|
9580
|
+
commitFooterDragRef.current = commitFooterDrag;
|
|
9581
|
+
const startFooterLinkDrag = useCallback5(
|
|
9582
|
+
(anchor, clientX, clientY, wasSelected) => {
|
|
9583
|
+
const hrefKey = anchor.getAttribute("data-ohw-href-key");
|
|
9584
|
+
if (!hrefKey || !isFooterHrefKey(hrefKey)) return false;
|
|
9585
|
+
const column = findFooterColumnForLink(anchor);
|
|
9586
|
+
const columns = listFooterColumns();
|
|
9587
|
+
beginFooterDrag({
|
|
9588
|
+
kind: "link",
|
|
9589
|
+
hrefKey,
|
|
9590
|
+
columnEl: column,
|
|
9591
|
+
sourceColumnIndex: column ? columns.indexOf(column) : 0,
|
|
9592
|
+
wasSelected,
|
|
9593
|
+
draggedEl: anchor,
|
|
9594
|
+
lastClientX: clientX,
|
|
9595
|
+
lastClientY: clientY,
|
|
9596
|
+
activeSlot: null
|
|
9597
|
+
});
|
|
9598
|
+
return true;
|
|
9599
|
+
},
|
|
9600
|
+
[beginFooterDrag]
|
|
9601
|
+
);
|
|
9602
|
+
const startFooterColumnDrag = useCallback5(
|
|
9603
|
+
(columnEl, clientX, clientY, wasSelected) => {
|
|
9604
|
+
const columns = listFooterColumns();
|
|
9605
|
+
const idx = columns.indexOf(columnEl);
|
|
9606
|
+
if (idx < 0) return false;
|
|
9607
|
+
beginFooterDrag({
|
|
9608
|
+
kind: "column",
|
|
9609
|
+
hrefKey: null,
|
|
9610
|
+
columnEl,
|
|
9611
|
+
sourceColumnIndex: idx,
|
|
9612
|
+
wasSelected,
|
|
9613
|
+
draggedEl: columnEl,
|
|
9614
|
+
lastClientX: clientX,
|
|
9615
|
+
lastClientY: clientY,
|
|
9616
|
+
activeSlot: null
|
|
9617
|
+
});
|
|
9618
|
+
return true;
|
|
9619
|
+
},
|
|
9620
|
+
[beginFooterDrag]
|
|
9621
|
+
);
|
|
9622
|
+
const handleItemDragStart = useCallback5(
|
|
9623
|
+
(e) => {
|
|
9624
|
+
const selected = selectedElRef.current;
|
|
9625
|
+
if (!selected) {
|
|
9626
|
+
setIsItemDragging(true);
|
|
9627
|
+
return;
|
|
9628
|
+
}
|
|
9629
|
+
const clientX = e?.clientX ?? selected.getBoundingClientRect().left + 8;
|
|
9630
|
+
const clientY = e?.clientY ?? selected.getBoundingClientRect().top + 8;
|
|
9631
|
+
if (startFooterLinkDrag(selected, clientX, clientY, true)) return;
|
|
9632
|
+
if (selected.hasAttribute("data-ohw-footer-col") || isInferredFooterGroup(selected) && selected.closest("footer")) {
|
|
9633
|
+
if (startFooterColumnDrag(selected, clientX, clientY, true)) return;
|
|
9634
|
+
}
|
|
9635
|
+
if (startNavLinkDrag(selected, clientX, clientY, true)) return;
|
|
9636
|
+
siblingHintElRef.current = null;
|
|
9637
|
+
setSiblingHintRect(null);
|
|
9638
|
+
setIsItemDragging(true);
|
|
9639
|
+
},
|
|
9640
|
+
[startFooterColumnDrag, startFooterLinkDrag, startNavLinkDrag]
|
|
9641
|
+
);
|
|
9642
|
+
const handleItemDragEnd = useCallback5(
|
|
9643
|
+
(e) => {
|
|
9644
|
+
if (footerDragRef.current) {
|
|
9645
|
+
const x = e?.clientX;
|
|
9646
|
+
const y = e?.clientY;
|
|
9647
|
+
if (typeof x === "number" && typeof y === "number" && (x !== 0 || y !== 0)) {
|
|
9648
|
+
commitFooterDrag(x, y);
|
|
9649
|
+
} else {
|
|
9650
|
+
commitFooterDrag();
|
|
9651
|
+
}
|
|
9652
|
+
return;
|
|
9653
|
+
}
|
|
9654
|
+
if (navDragRef.current) {
|
|
9655
|
+
const x = e?.clientX;
|
|
9656
|
+
const y = e?.clientY;
|
|
9657
|
+
if (typeof x === "number" && typeof y === "number" && (x !== 0 || y !== 0)) {
|
|
9658
|
+
commitNavDrag(x, y);
|
|
9659
|
+
} else {
|
|
9660
|
+
commitNavDrag();
|
|
9661
|
+
}
|
|
9662
|
+
return;
|
|
9663
|
+
}
|
|
9664
|
+
setIsItemDragging(false);
|
|
9665
|
+
},
|
|
9666
|
+
[commitFooterDrag, commitNavDrag, navDragRef]
|
|
9667
|
+
);
|
|
9668
|
+
const handleItemChromePointerDown = useCallback5((e) => {
|
|
9669
|
+
if (e.button !== 0) return;
|
|
9670
|
+
const selected = selectedElRef.current;
|
|
9671
|
+
if (!selected) return;
|
|
9672
|
+
const hrefKey = selected.getAttribute("data-ohw-href-key");
|
|
9673
|
+
if (hrefKey && isFooterHrefKey(hrefKey)) {
|
|
9674
|
+
footerPointerDragRef.current = {
|
|
9675
|
+
el: selected,
|
|
9676
|
+
kind: "link",
|
|
9677
|
+
startX: e.clientX,
|
|
9678
|
+
startY: e.clientY,
|
|
9679
|
+
pointerId: e.pointerId,
|
|
9680
|
+
wasSelected: true,
|
|
9681
|
+
started: false
|
|
9682
|
+
};
|
|
9683
|
+
return;
|
|
9684
|
+
}
|
|
9685
|
+
if (selected.hasAttribute("data-ohw-footer-col") || isInferredFooterGroup(selected) && selected.closest("footer")) {
|
|
9686
|
+
footerPointerDragRef.current = {
|
|
9687
|
+
el: selected,
|
|
9688
|
+
kind: "column",
|
|
9689
|
+
startX: e.clientX,
|
|
9690
|
+
startY: e.clientY,
|
|
9691
|
+
pointerId: e.pointerId,
|
|
9692
|
+
wasSelected: true,
|
|
9693
|
+
started: false
|
|
9694
|
+
};
|
|
9695
|
+
return;
|
|
9696
|
+
}
|
|
9697
|
+
if (armNavPressFromChrome(selected, e.clientX, e.clientY, e.pointerId)) return;
|
|
9698
|
+
}, [armNavPressFromChrome]);
|
|
9699
|
+
const handleItemChromeClick = useCallback5((clientX, clientY) => {
|
|
9700
|
+
if (suppressNextClickRef.current || Date.now() < suppressClickUntilRef.current) {
|
|
9701
|
+
suppressNextClickRef.current = false;
|
|
9702
|
+
return;
|
|
9703
|
+
}
|
|
9704
|
+
const selected = selectedElRef.current;
|
|
9705
|
+
if (!selected || !isNavigationItem(selected)) return;
|
|
9706
|
+
const editable = selected.querySelector('[data-ohw-editable="text"]') ?? selected.querySelector("[data-ohw-editable]");
|
|
9707
|
+
if (!editable) return;
|
|
9708
|
+
activateRef.current(editable, { caretX: clientX, caretY: clientY });
|
|
7793
9709
|
}, []);
|
|
7794
9710
|
reselectNavigationItemRef.current = reselectNavigationItem;
|
|
7795
9711
|
commitNavigationTextEditRef.current = commitNavigationTextEdit;
|
|
7796
|
-
const select =
|
|
9712
|
+
const select = useCallback5((anchor) => {
|
|
7797
9713
|
if (!isNavigationItem(anchor)) return;
|
|
7798
9714
|
if (activeElRef.current) deactivate();
|
|
7799
9715
|
selectedElRef.current = anchor;
|
|
9716
|
+
selectedHrefKeyRef.current = anchor.getAttribute("data-ohw-href-key");
|
|
9717
|
+
selectedFooterColAttrRef.current = null;
|
|
9718
|
+
markSelected(anchor);
|
|
9719
|
+
setSelectedIsCta(isNavbarButton2(anchor));
|
|
7800
9720
|
clearHrefKeyHover(anchor);
|
|
7801
9721
|
hoveredNavContainerRef.current = null;
|
|
7802
9722
|
setHoveredNavContainerRect(null);
|
|
@@ -7804,19 +9724,26 @@ function OhhwellsBridge() {
|
|
|
7804
9724
|
hoveredItemElRef.current = null;
|
|
7805
9725
|
siblingHintElRef.current = null;
|
|
7806
9726
|
setSiblingHintRect(null);
|
|
9727
|
+
setSiblingHintRects(collectNavigationItemSiblingHintRects(anchor));
|
|
7807
9728
|
setIsItemDragging(false);
|
|
7808
9729
|
const { key, disabled } = getNavigationItemReorderState(anchor);
|
|
7809
9730
|
setReorderHrefKey(key);
|
|
7810
9731
|
setReorderDragDisabled(disabled);
|
|
9732
|
+
setIsFooterFrameSelection(false);
|
|
7811
9733
|
setToolbarVariant("link-action");
|
|
7812
9734
|
setToolbarRect(anchor.getBoundingClientRect());
|
|
7813
9735
|
setToolbarShowEditLink(false);
|
|
7814
9736
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
7815
|
-
}, [deactivate]);
|
|
7816
|
-
const selectFrame =
|
|
9737
|
+
}, [deactivate, markSelected]);
|
|
9738
|
+
const selectFrame = useCallback5((el) => {
|
|
7817
9739
|
if (!isNavigationContainer(el)) return;
|
|
7818
9740
|
if (activeElRef.current) deactivate();
|
|
9741
|
+
const isFooterColumn = el.hasAttribute("data-ohw-footer-col") || Boolean(el.closest("footer") && isInferredFooterGroup(el));
|
|
7819
9742
|
selectedElRef.current = el;
|
|
9743
|
+
selectedHrefKeyRef.current = null;
|
|
9744
|
+
selectedFooterColAttrRef.current = isFooterColumn ? el.getAttribute("data-ohw-footer-col") ?? String(listFooterColumns().indexOf(el)) : null;
|
|
9745
|
+
markSelected(el);
|
|
9746
|
+
setSelectedIsCta(false);
|
|
7820
9747
|
clearHrefKeyHover(el);
|
|
7821
9748
|
hoveredNavContainerRef.current = null;
|
|
7822
9749
|
setHoveredNavContainerRect(null);
|
|
@@ -7824,17 +9751,25 @@ function OhhwellsBridge() {
|
|
|
7824
9751
|
hoveredItemElRef.current = null;
|
|
7825
9752
|
siblingHintElRef.current = null;
|
|
7826
9753
|
setSiblingHintRect(null);
|
|
9754
|
+
setSiblingHintRects(
|
|
9755
|
+
isFooterColumn ? listFooterColumns().filter((column) => column !== el).map((column) => column.getBoundingClientRect()) : []
|
|
9756
|
+
);
|
|
7827
9757
|
setIsItemDragging(false);
|
|
7828
9758
|
setReorderHrefKey(null);
|
|
7829
9759
|
setReorderDragDisabled(false);
|
|
9760
|
+
setIsFooterFrameSelection(isFooterColumn);
|
|
7830
9761
|
setToolbarVariant("select-frame");
|
|
7831
9762
|
setToolbarRect(el.getBoundingClientRect());
|
|
7832
9763
|
setToolbarShowEditLink(false);
|
|
7833
9764
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
7834
|
-
}, [deactivate]);
|
|
7835
|
-
const activate =
|
|
9765
|
+
}, [deactivate, markSelected]);
|
|
9766
|
+
const activate = useCallback5((el, options) => {
|
|
7836
9767
|
if (activeElRef.current === el) return;
|
|
9768
|
+
clearSelectedAttr();
|
|
7837
9769
|
selectedElRef.current = null;
|
|
9770
|
+
selectedHrefKeyRef.current = null;
|
|
9771
|
+
selectedFooterColAttrRef.current = null;
|
|
9772
|
+
setSelectedIsCta(false);
|
|
7838
9773
|
deactivate();
|
|
7839
9774
|
if (hoveredImageRef.current) {
|
|
7840
9775
|
hoveredImageRef.current = null;
|
|
@@ -7844,14 +9779,34 @@ function OhhwellsBridge() {
|
|
|
7844
9779
|
siblingHintElRef.current = null;
|
|
7845
9780
|
setSiblingHintRect(null);
|
|
7846
9781
|
setIsItemDragging(false);
|
|
9782
|
+
const preActivationSelection = window.getSelection();
|
|
9783
|
+
const preservedRange = preActivationSelection && preActivationSelection.rangeCount > 0 && !preActivationSelection.isCollapsed && el.contains(preActivationSelection.getRangeAt(0).commonAncestorContainer) ? preActivationSelection.getRangeAt(0).cloneRange() : null;
|
|
7847
9784
|
el.setAttribute("contenteditable", "true");
|
|
9785
|
+
el.setAttribute("data-ohw-editing", "");
|
|
7848
9786
|
el.removeAttribute("data-ohw-hovered");
|
|
7849
9787
|
el.closest("[data-ohw-href-key]")?.removeAttribute("data-ohw-hovered");
|
|
7850
9788
|
activeElRef.current = el;
|
|
7851
9789
|
originalContentRef.current = el.innerHTML;
|
|
7852
|
-
el.focus();
|
|
7853
|
-
if (
|
|
7854
|
-
|
|
9790
|
+
el.focus({ preventScroll: true });
|
|
9791
|
+
if (preservedRange) {
|
|
9792
|
+
const selection = window.getSelection();
|
|
9793
|
+
selection?.removeAllRanges();
|
|
9794
|
+
selection?.addRange(preservedRange);
|
|
9795
|
+
} else if (options?.caretX !== void 0 && options?.caretY !== void 0) {
|
|
9796
|
+
const { caretX, caretY } = options;
|
|
9797
|
+
placeCaretAtPoint(el, caretX, caretY);
|
|
9798
|
+
requestAnimationFrame(() => {
|
|
9799
|
+
if (activeElRef.current === el) placeCaretAtPoint(el, caretX, caretY);
|
|
9800
|
+
});
|
|
9801
|
+
} else {
|
|
9802
|
+
const selection = window.getSelection();
|
|
9803
|
+
if (selection && selection.rangeCount === 0) {
|
|
9804
|
+
const range = document.createRange();
|
|
9805
|
+
range.selectNodeContents(el);
|
|
9806
|
+
range.collapse(false);
|
|
9807
|
+
selection.removeAllRanges();
|
|
9808
|
+
selection.addRange(range);
|
|
9809
|
+
}
|
|
7855
9810
|
}
|
|
7856
9811
|
setToolbarShowEditLink(Boolean(getHrefKeyFromElement(el)));
|
|
7857
9812
|
const navAnchor = getNavigationItemAnchor(el);
|
|
@@ -7866,13 +9821,13 @@ function OhhwellsBridge() {
|
|
|
7866
9821
|
setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
|
|
7867
9822
|
postToParent2({ type: "ow:enter-edit", key: el.dataset.ohwKey });
|
|
7868
9823
|
requestAnimationFrame(() => refreshActiveCommandsRef.current());
|
|
7869
|
-
}, [deactivate, postToParent2]);
|
|
9824
|
+
}, [clearSelectedAttr, deactivate, postToParent2]);
|
|
7870
9825
|
activateRef.current = activate;
|
|
7871
9826
|
deactivateRef.current = deactivate;
|
|
7872
9827
|
selectRef.current = select;
|
|
7873
9828
|
selectFrameRef.current = selectFrame;
|
|
7874
9829
|
deselectRef.current = deselect;
|
|
7875
|
-
|
|
9830
|
+
useLayoutEffect3(() => {
|
|
7876
9831
|
if (!subdomain || isEditMode) {
|
|
7877
9832
|
setFetchState("done");
|
|
7878
9833
|
return;
|
|
@@ -7913,6 +9868,7 @@ function OhhwellsBridge() {
|
|
|
7913
9868
|
applyLinkByKey(key, val);
|
|
7914
9869
|
}
|
|
7915
9870
|
reconcileNavbarItemsFromContent(content);
|
|
9871
|
+
reconcileFooterOrderFromContent(content);
|
|
7916
9872
|
enforceLinkHrefs();
|
|
7917
9873
|
initSectionsFromContent(content, true);
|
|
7918
9874
|
sectionsLoadedRef.current = true;
|
|
@@ -7941,7 +9897,7 @@ function OhhwellsBridge() {
|
|
|
7941
9897
|
cancelled = true;
|
|
7942
9898
|
};
|
|
7943
9899
|
}, [subdomain, isEditMode]);
|
|
7944
|
-
|
|
9900
|
+
useEffect8(() => {
|
|
7945
9901
|
if (!subdomain || isEditMode) return;
|
|
7946
9902
|
let debounceTimer = null;
|
|
7947
9903
|
let observer = null;
|
|
@@ -7973,6 +9929,7 @@ function OhhwellsBridge() {
|
|
|
7973
9929
|
applyLinkByKey(key, val);
|
|
7974
9930
|
}
|
|
7975
9931
|
reconcileNavbarItemsFromContent(content);
|
|
9932
|
+
reconcileFooterOrderFromContent(content);
|
|
7976
9933
|
} finally {
|
|
7977
9934
|
observer?.observe(document.body, { childList: true, subtree: true });
|
|
7978
9935
|
}
|
|
@@ -7990,16 +9947,16 @@ function OhhwellsBridge() {
|
|
|
7990
9947
|
if (debounceTimer) clearTimeout(debounceTimer);
|
|
7991
9948
|
};
|
|
7992
9949
|
}, [subdomain, isEditMode, pathname]);
|
|
7993
|
-
|
|
9950
|
+
useLayoutEffect3(() => {
|
|
7994
9951
|
const el = document.getElementById("ohw-loader");
|
|
7995
9952
|
if (!el) return;
|
|
7996
9953
|
const visible = Boolean(subdomain) && fetchState !== "done";
|
|
7997
9954
|
el.style.display = visible ? "flex" : "none";
|
|
7998
9955
|
}, [subdomain, fetchState]);
|
|
7999
|
-
|
|
9956
|
+
useEffect8(() => {
|
|
8000
9957
|
postToParent2({ type: "ow:navigation", path: pathname });
|
|
8001
9958
|
}, [pathname, postToParent2]);
|
|
8002
|
-
|
|
9959
|
+
useEffect8(() => {
|
|
8003
9960
|
if (!isEditMode) return;
|
|
8004
9961
|
if (linkPopoverSessionRef.current?.intent === "add-nav") return;
|
|
8005
9962
|
if (document.querySelector("[data-ohw-section-picker]")) return;
|
|
@@ -8007,23 +9964,72 @@ function OhhwellsBridge() {
|
|
|
8007
9964
|
deselectRef.current();
|
|
8008
9965
|
deactivateRef.current();
|
|
8009
9966
|
}, [pathname, isEditMode]);
|
|
8010
|
-
|
|
9967
|
+
useEffect8(() => {
|
|
8011
9968
|
const contentForNav = () => {
|
|
8012
9969
|
if (isEditMode) return editContentRef.current;
|
|
8013
9970
|
if (!subdomain) return {};
|
|
8014
9971
|
return contentCache.get(subdomain) ?? {};
|
|
8015
9972
|
};
|
|
8016
|
-
const
|
|
9973
|
+
const observeRoots = () => [document.querySelector("nav"), document.querySelector("footer")].filter(
|
|
9974
|
+
(el) => Boolean(el)
|
|
9975
|
+
);
|
|
9976
|
+
const roots = observeRoots();
|
|
9977
|
+
if (roots.length === 0) {
|
|
9978
|
+
reconcileNavbarItemsFromContent(contentForNav());
|
|
9979
|
+
reconcileFooterOrderFromContent(contentForNav());
|
|
9980
|
+
if (isEditMode) syncNavigationDragCursorAttrs();
|
|
9981
|
+
return;
|
|
9982
|
+
}
|
|
9983
|
+
let rafId = null;
|
|
9984
|
+
let applying = false;
|
|
9985
|
+
let observer = null;
|
|
9986
|
+
const attach = () => {
|
|
9987
|
+
for (const root of observeRoots()) {
|
|
9988
|
+
observer?.observe(root, { childList: true, subtree: true });
|
|
9989
|
+
}
|
|
9990
|
+
};
|
|
9991
|
+
const run = () => {
|
|
9992
|
+
if (footerDragRef.current || navDragRef.current || applying) return;
|
|
9993
|
+
applying = true;
|
|
9994
|
+
observer?.disconnect();
|
|
9995
|
+
try {
|
|
9996
|
+
const content = contentForNav();
|
|
9997
|
+
reconcileNavbarItemsFromContent(content);
|
|
9998
|
+
reconcileFooterOrderFromContent(content);
|
|
9999
|
+
document.querySelectorAll("footer [data-ohw-href-key]").forEach((el) => {
|
|
10000
|
+
if (isFooterHrefKey(el.getAttribute("data-ohw-href-key"))) {
|
|
10001
|
+
disableNativeHrefDrag(el);
|
|
10002
|
+
}
|
|
10003
|
+
});
|
|
10004
|
+
document.querySelectorAll(
|
|
10005
|
+
"nav [data-ohw-href-key], [data-ohw-nav-container] [data-ohw-href-key], [data-ohw-nav-drawer] [data-ohw-href-key]"
|
|
10006
|
+
).forEach((el) => {
|
|
10007
|
+
if (isNavbarHrefKey(el.getAttribute("data-ohw-href-key"))) {
|
|
10008
|
+
disableNativeHrefDrag(el);
|
|
10009
|
+
}
|
|
10010
|
+
});
|
|
10011
|
+
resyncSelectedNavigationItem();
|
|
10012
|
+
if (isEditMode) syncNavigationDragCursorAttrs();
|
|
10013
|
+
} finally {
|
|
10014
|
+
applying = false;
|
|
10015
|
+
attach();
|
|
10016
|
+
}
|
|
10017
|
+
};
|
|
10018
|
+
const schedule = () => {
|
|
10019
|
+
if (applying || rafId != null) return;
|
|
10020
|
+
rafId = requestAnimationFrame(() => {
|
|
10021
|
+
rafId = null;
|
|
10022
|
+
run();
|
|
10023
|
+
});
|
|
10024
|
+
};
|
|
10025
|
+
observer = new MutationObserver(schedule);
|
|
8017
10026
|
run();
|
|
8018
|
-
|
|
8019
|
-
|
|
8020
|
-
|
|
8021
|
-
|
|
8022
|
-
|
|
8023
|
-
|
|
8024
|
-
return () => observer.disconnect();
|
|
8025
|
-
}, [isEditMode, pathname, subdomain, fetchState]);
|
|
8026
|
-
useEffect7(() => {
|
|
10027
|
+
return () => {
|
|
10028
|
+
if (rafId != null) cancelAnimationFrame(rafId);
|
|
10029
|
+
observer?.disconnect();
|
|
10030
|
+
};
|
|
10031
|
+
}, [isEditMode, pathname, subdomain, fetchState, resyncSelectedNavigationItem]);
|
|
10032
|
+
useEffect8(() => {
|
|
8027
10033
|
if (!isEditMode) return;
|
|
8028
10034
|
const measure = () => {
|
|
8029
10035
|
const h = document.body.scrollHeight;
|
|
@@ -8047,7 +10053,7 @@ function OhhwellsBridge() {
|
|
|
8047
10053
|
window.removeEventListener("resize", handleResize);
|
|
8048
10054
|
};
|
|
8049
10055
|
}, [pathname, isEditMode, postToParent2]);
|
|
8050
|
-
|
|
10056
|
+
useEffect8(() => {
|
|
8051
10057
|
if (!subdomainFromQuery || isEditMode) return;
|
|
8052
10058
|
const handleClick = (e) => {
|
|
8053
10059
|
const anchor = e.target.closest("a");
|
|
@@ -8063,19 +10069,24 @@ function OhhwellsBridge() {
|
|
|
8063
10069
|
document.addEventListener("click", handleClick, true);
|
|
8064
10070
|
return () => document.removeEventListener("click", handleClick, true);
|
|
8065
10071
|
}, [subdomainFromQuery, isEditMode, router]);
|
|
8066
|
-
|
|
10072
|
+
useEffect8(() => {
|
|
8067
10073
|
if (!isEditMode) {
|
|
8068
10074
|
editStylesRef.current?.base.remove();
|
|
8069
10075
|
editStylesRef.current?.forceHover.remove();
|
|
8070
10076
|
editStylesRef.current?.stateViews.remove();
|
|
8071
10077
|
editStylesRef.current = null;
|
|
10078
|
+
document.querySelectorAll("[data-ohw-can-drag]").forEach((el) => {
|
|
10079
|
+
el.removeAttribute("data-ohw-can-drag");
|
|
10080
|
+
});
|
|
8072
10081
|
return;
|
|
8073
10082
|
}
|
|
8074
|
-
|
|
8075
|
-
|
|
8076
|
-
|
|
8077
|
-
base.
|
|
8078
|
-
|
|
10083
|
+
const existing = editStylesRef.current;
|
|
10084
|
+
let initialVh = window.innerHeight;
|
|
10085
|
+
if (existing?.base.textContent) {
|
|
10086
|
+
const match = existing.base.textContent.match(/\.min-h-screen[^{]*\{[^}]*min-height:\s*(\d+)px/);
|
|
10087
|
+
if (match) initialVh = parseInt(match[1], 10);
|
|
10088
|
+
}
|
|
10089
|
+
const baseCss = `
|
|
8079
10090
|
html { height: auto !important; }
|
|
8080
10091
|
body { height: auto !important; min-height: 0 !important; overflow: hidden !important; }
|
|
8081
10092
|
.min-h-screen, .min-h-svh, .min-h-dvh { min-height: ${initialVh}px !important; }
|
|
@@ -8086,7 +10097,25 @@ function OhhwellsBridge() {
|
|
|
8086
10097
|
[data-ohw-editable] {
|
|
8087
10098
|
display: block;
|
|
8088
10099
|
}
|
|
8089
|
-
|
|
10100
|
+
/* Body text (no item-action toolbar) \u2014 first click enters text edit \u2192 I-beam.
|
|
10101
|
+
Exclude select-first nav/footer labels so grab/default on [data-ohw-href-key] can win. */
|
|
10102
|
+
[data-ohw-editable]:not([contenteditable]):not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"]):not([data-ohw-editable="link"]):not(:is([data-ohw-href-key] *)) {
|
|
10103
|
+
cursor: text !important;
|
|
10104
|
+
}
|
|
10105
|
+
/* Select-first items: default arrow; grab only when drag-start is allowed (data-ohw-can-drag). */
|
|
10106
|
+
[data-ohw-href-key]:not([data-ohw-selected]),
|
|
10107
|
+
[data-ohw-href-key]:not([data-ohw-selected]) * {
|
|
10108
|
+
cursor: default !important;
|
|
10109
|
+
}
|
|
10110
|
+
[data-ohw-href-key][data-ohw-can-drag]:not([data-ohw-selected]),
|
|
10111
|
+
[data-ohw-href-key][data-ohw-can-drag]:not([data-ohw-selected]) * {
|
|
10112
|
+
cursor: grab !important;
|
|
10113
|
+
}
|
|
10114
|
+
/* Selected (action-toolbar) \u2014 next click enters text edit at caret. */
|
|
10115
|
+
[data-ohw-href-key][data-ohw-selected],
|
|
10116
|
+
[data-ohw-href-key][data-ohw-selected] * {
|
|
10117
|
+
cursor: text !important;
|
|
10118
|
+
}
|
|
8090
10119
|
[data-ohw-editable="image"], [data-ohw-editable="image"] *,
|
|
8091
10120
|
[data-ohw-editable="video"], [data-ohw-editable="video"] *,
|
|
8092
10121
|
[data-ohw-editable="bg-image"], [data-ohw-editable="bg-image"] * { cursor: pointer !important; }
|
|
@@ -8102,9 +10131,32 @@ function OhhwellsBridge() {
|
|
|
8102
10131
|
outline: none !important;
|
|
8103
10132
|
outline-offset: 0 !important;
|
|
8104
10133
|
}
|
|
8105
|
-
|
|
10134
|
+
/* Editor chrome owns selection \u2014 suppress native focus rings on nav/footer items. */
|
|
10135
|
+
nav [data-ohw-href-key]:focus,
|
|
10136
|
+
nav [data-ohw-href-key]:focus-visible,
|
|
10137
|
+
nav [data-ohw-href-key]:focus-within,
|
|
10138
|
+
footer [data-ohw-href-key]:focus,
|
|
10139
|
+
footer [data-ohw-href-key]:focus-visible,
|
|
10140
|
+
footer [data-ohw-href-key]:focus-within,
|
|
10141
|
+
nav [data-ohw-href-key] [data-ohw-editable]:focus,
|
|
10142
|
+
nav [data-ohw-href-key] [data-ohw-editable]:focus-visible,
|
|
10143
|
+
footer [data-ohw-href-key] [data-ohw-editable]:focus,
|
|
10144
|
+
footer [data-ohw-href-key] [data-ohw-editable]:focus-visible {
|
|
10145
|
+
outline: none !important;
|
|
10146
|
+
outline-offset: 0 !important;
|
|
10147
|
+
box-shadow: none !important;
|
|
10148
|
+
}
|
|
10149
|
+
/* Text edit wins over grab/default (must beat [data-ohw-can-drag] *). */
|
|
10150
|
+
[data-ohw-editing],
|
|
10151
|
+
[data-ohw-editing] *,
|
|
10152
|
+
[data-ohw-editable][contenteditable],
|
|
10153
|
+
[data-ohw-editable][contenteditable] *,
|
|
10154
|
+
nav [data-ohw-href-key] [data-ohw-editable][contenteditable],
|
|
10155
|
+
nav [data-ohw-href-key] [data-ohw-editable][contenteditable] *,
|
|
10156
|
+
footer [data-ohw-href-key] [data-ohw-editable][contenteditable],
|
|
10157
|
+
footer [data-ohw-href-key] [data-ohw-editable][contenteditable] * {
|
|
8106
10158
|
outline: none !important;
|
|
8107
|
-
caret-color: ${PRIMARY2};
|
|
10159
|
+
caret-color: ${PRIMARY2} !important;
|
|
8108
10160
|
cursor: text !important;
|
|
8109
10161
|
}
|
|
8110
10162
|
[data-ohw-editable][contenteditable]::selection,
|
|
@@ -8113,6 +10165,9 @@ function OhhwellsBridge() {
|
|
|
8113
10165
|
[data-ohw-editable-state][data-ohw-active-state] [data-ohw-editable] { pointer-events: auto !important; }
|
|
8114
10166
|
[data-ohw-editable-state][data-ohw-active-state][data-ohw-editable] { pointer-events: auto !important; }
|
|
8115
10167
|
`;
|
|
10168
|
+
if (!existing) {
|
|
10169
|
+
const base = document.createElement("style");
|
|
10170
|
+
base.setAttribute("data-ohw-edit-style", "");
|
|
8116
10171
|
const forceHover = document.createElement("style");
|
|
8117
10172
|
forceHover.setAttribute("data-ohw-active-state-style", "");
|
|
8118
10173
|
const stateViews = document.createElement("style");
|
|
@@ -8128,14 +10183,43 @@ function OhhwellsBridge() {
|
|
|
8128
10183
|
document.head.appendChild(stateViews);
|
|
8129
10184
|
editStylesRef.current = { base, forceHover, stateViews };
|
|
8130
10185
|
}
|
|
10186
|
+
editStylesRef.current.base.textContent = baseCss;
|
|
10187
|
+
syncNavigationDragCursorAttrs();
|
|
8131
10188
|
refreshStateRules();
|
|
8132
10189
|
const handleClick = (e) => {
|
|
10190
|
+
if (suppressNextClickRef.current || Date.now() < suppressClickUntilRef.current) {
|
|
10191
|
+
suppressNextClickRef.current = false;
|
|
10192
|
+
e.preventDefault();
|
|
10193
|
+
e.stopPropagation();
|
|
10194
|
+
return;
|
|
10195
|
+
}
|
|
8133
10196
|
const target = e.target;
|
|
8134
10197
|
if (target.closest("[data-ohw-toolbar]")) return;
|
|
8135
10198
|
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
8136
10199
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
8137
10200
|
if (isInsideLinkEditor(target)) return;
|
|
8138
10201
|
if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
|
|
10202
|
+
if (target.closest("[data-ohw-item-drag-surface]")) {
|
|
10203
|
+
e.preventDefault();
|
|
10204
|
+
e.stopPropagation();
|
|
10205
|
+
const selected = selectedElRef.current;
|
|
10206
|
+
if (selected && isNavigationItem(selected)) {
|
|
10207
|
+
const editable2 = selected.querySelector('[data-ohw-editable="text"]') ?? selected.querySelector("[data-ohw-editable]");
|
|
10208
|
+
if (editable2) {
|
|
10209
|
+
activateRef.current(editable2, {
|
|
10210
|
+
caretX: e.clientX,
|
|
10211
|
+
caretY: e.clientY
|
|
10212
|
+
});
|
|
10213
|
+
}
|
|
10214
|
+
} else if (selected?.hasAttribute("data-ohw-footer-col")) {
|
|
10215
|
+
const link = listFooterLinksInColumn(selected).find((el) => {
|
|
10216
|
+
const r2 = el.getBoundingClientRect();
|
|
10217
|
+
return e.clientX >= r2.left && e.clientX <= r2.right && e.clientY >= r2.top && e.clientY <= r2.bottom;
|
|
10218
|
+
});
|
|
10219
|
+
if (link) selectRef.current(link);
|
|
10220
|
+
}
|
|
10221
|
+
return;
|
|
10222
|
+
}
|
|
8139
10223
|
const navFromChrome = resolveNavContainerSelectionTarget(target, e.clientX, e.clientY);
|
|
8140
10224
|
if (navFromChrome) {
|
|
8141
10225
|
e.preventDefault();
|
|
@@ -8143,10 +10227,36 @@ function OhhwellsBridge() {
|
|
|
8143
10227
|
selectFrameRef.current(navFromChrome);
|
|
8144
10228
|
return;
|
|
8145
10229
|
}
|
|
10230
|
+
const footerFromChrome = resolveFooterColumnSelectionTarget(target, e.clientX, e.clientY);
|
|
10231
|
+
if (footerFromChrome) {
|
|
10232
|
+
e.preventDefault();
|
|
10233
|
+
e.stopPropagation();
|
|
10234
|
+
selectFrameRef.current(footerFromChrome);
|
|
10235
|
+
return;
|
|
10236
|
+
}
|
|
8146
10237
|
e.preventDefault();
|
|
8147
10238
|
e.stopPropagation();
|
|
8148
10239
|
return;
|
|
8149
10240
|
}
|
|
10241
|
+
if (activeElRef.current) {
|
|
10242
|
+
const active = activeElRef.current;
|
|
10243
|
+
const inActive = active === target || active.contains(target);
|
|
10244
|
+
const navAnchor = getNavigationItemAnchor(active);
|
|
10245
|
+
const inActiveNav = Boolean(
|
|
10246
|
+
navAnchor && (navAnchor === target || navAnchor.contains(target))
|
|
10247
|
+
);
|
|
10248
|
+
if (inActive || inActiveNav) {
|
|
10249
|
+
e.preventDefault();
|
|
10250
|
+
e.stopPropagation();
|
|
10251
|
+
const selection = window.getSelection();
|
|
10252
|
+
const hasRangeSelection = Boolean(selection && !selection.isCollapsed);
|
|
10253
|
+
if (e.detail < 2 && !hasRangeSelection) {
|
|
10254
|
+
placeCaretAtPoint(active, e.clientX, e.clientY);
|
|
10255
|
+
refreshActiveCommandsRef.current();
|
|
10256
|
+
}
|
|
10257
|
+
return;
|
|
10258
|
+
}
|
|
10259
|
+
}
|
|
8150
10260
|
const editable = target.closest("[data-ohw-editable]");
|
|
8151
10261
|
if (editable) {
|
|
8152
10262
|
if (editable.dataset.ohwEditable === "link") {
|
|
@@ -8190,10 +10300,26 @@ function OhhwellsBridge() {
|
|
|
8190
10300
|
if (hrefAnchor) {
|
|
8191
10301
|
e.preventDefault();
|
|
8192
10302
|
e.stopPropagation();
|
|
8193
|
-
if (selectedElRef.current === hrefAnchor)
|
|
10303
|
+
if (selectedElRef.current === hrefAnchor) {
|
|
10304
|
+
const textEditable = hrefAnchor.querySelector('[data-ohw-editable="text"]') ?? hrefAnchor.querySelector("[data-ohw-editable]");
|
|
10305
|
+
if (textEditable) {
|
|
10306
|
+
activateRef.current(textEditable, {
|
|
10307
|
+
caretX: e.clientX,
|
|
10308
|
+
caretY: e.clientY
|
|
10309
|
+
});
|
|
10310
|
+
}
|
|
10311
|
+
return;
|
|
10312
|
+
}
|
|
8194
10313
|
selectRef.current(hrefAnchor);
|
|
8195
10314
|
return;
|
|
8196
10315
|
}
|
|
10316
|
+
const footerColClick = target.closest("[data-ohw-footer-col]");
|
|
10317
|
+
if (footerColClick) {
|
|
10318
|
+
e.preventDefault();
|
|
10319
|
+
e.stopPropagation();
|
|
10320
|
+
selectFrameRef.current(footerColClick);
|
|
10321
|
+
return;
|
|
10322
|
+
}
|
|
8197
10323
|
const navContainerToSelect = resolveNavContainerSelectionTarget(target, e.clientX, e.clientY);
|
|
8198
10324
|
if (navContainerToSelect) {
|
|
8199
10325
|
e.preventDefault();
|
|
@@ -8201,6 +10327,13 @@ function OhhwellsBridge() {
|
|
|
8201
10327
|
selectFrameRef.current(navContainerToSelect);
|
|
8202
10328
|
return;
|
|
8203
10329
|
}
|
|
10330
|
+
const footerColumnToSelect = resolveFooterColumnSelectionTarget(target, e.clientX, e.clientY);
|
|
10331
|
+
if (footerColumnToSelect) {
|
|
10332
|
+
e.preventDefault();
|
|
10333
|
+
e.stopPropagation();
|
|
10334
|
+
selectFrameRef.current(footerColumnToSelect);
|
|
10335
|
+
return;
|
|
10336
|
+
}
|
|
8204
10337
|
const selectedContainer = selectedElRef.current;
|
|
8205
10338
|
if (selectedContainer && isNavigationContainer(selectedContainer)) {
|
|
8206
10339
|
const navItem = getNavigationItemAnchor(target);
|
|
@@ -8260,6 +10393,13 @@ function OhhwellsBridge() {
|
|
|
8260
10393
|
const handleMouseOver = (e) => {
|
|
8261
10394
|
if (document.documentElement.hasAttribute("data-ohw-section-picking")) return;
|
|
8262
10395
|
const target = e.target;
|
|
10396
|
+
if (linkPopoverOpenRef.current) {
|
|
10397
|
+
hoveredItemElRef.current = null;
|
|
10398
|
+
setHoveredItemRect(null);
|
|
10399
|
+
hoveredNavContainerRef.current = null;
|
|
10400
|
+
setHoveredNavContainerRect(null);
|
|
10401
|
+
return;
|
|
10402
|
+
}
|
|
8263
10403
|
if (toolbarVariantRef.current !== "select-frame") {
|
|
8264
10404
|
const navContainer = target.closest("[data-ohw-nav-container]");
|
|
8265
10405
|
if (navContainer && !getNavigationItemAnchor(target)) {
|
|
@@ -8279,12 +10419,21 @@ function OhhwellsBridge() {
|
|
|
8279
10419
|
hoveredNavContainerRef.current = null;
|
|
8280
10420
|
setHoveredNavContainerRect(null);
|
|
8281
10421
|
const selected2 = selectedElRef.current;
|
|
8282
|
-
if (selected2 === navAnchor
|
|
10422
|
+
if (selected2 === navAnchor) return;
|
|
8283
10423
|
clearHrefKeyHover(navAnchor);
|
|
8284
10424
|
hoveredItemElRef.current = navAnchor;
|
|
8285
10425
|
setHoveredItemRect(navAnchor.getBoundingClientRect());
|
|
8286
10426
|
return;
|
|
8287
10427
|
}
|
|
10428
|
+
const footerCol = target.closest("[data-ohw-footer-col]") ?? target.closest("[data-ohw-footer-column]");
|
|
10429
|
+
if (footerCol) {
|
|
10430
|
+
hoveredNavContainerRef.current = null;
|
|
10431
|
+
setHoveredNavContainerRect(null);
|
|
10432
|
+
if (selectedElRef.current === footerCol) return;
|
|
10433
|
+
hoveredItemElRef.current = footerCol;
|
|
10434
|
+
setHoveredItemRect(footerCol.getBoundingClientRect());
|
|
10435
|
+
return;
|
|
10436
|
+
}
|
|
8288
10437
|
const editable = target.closest("[data-ohw-editable]");
|
|
8289
10438
|
if (!editable) return;
|
|
8290
10439
|
const selected = selectedElRef.current;
|
|
@@ -8302,14 +10451,25 @@ function OhhwellsBridge() {
|
|
|
8302
10451
|
};
|
|
8303
10452
|
const handleMouseOut = (e) => {
|
|
8304
10453
|
const target = e.target;
|
|
8305
|
-
if (target.closest("[data-ohw-nav-container]")) {
|
|
10454
|
+
if (target.closest("[data-ohw-nav-container], [data-ohw-footer-col], [data-ohw-footer-column]")) {
|
|
8306
10455
|
const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
8307
|
-
if (related2?.closest("[data-ohw-nav-container], [data-ohw-navbar-container-chrome], [data-ohw-navbar-add-button]")) {
|
|
10456
|
+
if (related2?.closest("[data-ohw-nav-container], [data-ohw-footer-col], [data-ohw-footer-column], [data-ohw-navbar-container-chrome], [data-ohw-navbar-add-button]")) {
|
|
8308
10457
|
return;
|
|
8309
10458
|
}
|
|
8310
10459
|
hoveredNavContainerRef.current = null;
|
|
8311
10460
|
setHoveredNavContainerRect(null);
|
|
8312
10461
|
}
|
|
10462
|
+
const footerCol = target.closest("[data-ohw-footer-col]") ?? target.closest("[data-ohw-footer-column]");
|
|
10463
|
+
if (footerCol && hoveredItemElRef.current === footerCol) {
|
|
10464
|
+
const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
10465
|
+
if (related2?.closest("[data-ohw-drag-handle-container], [data-ohw-item-interaction]")) return;
|
|
10466
|
+
if (related2?.closest("[data-ohw-footer-col], [data-ohw-footer-column]") === footerCol) {
|
|
10467
|
+
return;
|
|
10468
|
+
}
|
|
10469
|
+
hoveredItemElRef.current = null;
|
|
10470
|
+
setHoveredItemRect(null);
|
|
10471
|
+
return;
|
|
10472
|
+
}
|
|
8313
10473
|
const navAnchor = getNavigationItemAnchor(target);
|
|
8314
10474
|
if (navAnchor) {
|
|
8315
10475
|
const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
@@ -8443,43 +10603,75 @@ function OhhwellsBridge() {
|
|
|
8443
10603
|
if (toolbarVariantRef.current === "select-frame") {
|
|
8444
10604
|
hoveredNavContainerRef.current = null;
|
|
8445
10605
|
setHoveredNavContainerRect(null);
|
|
8446
|
-
return;
|
|
8447
10606
|
}
|
|
8448
|
-
const
|
|
8449
|
-
|
|
8450
|
-
|
|
8451
|
-
|
|
8452
|
-
|
|
10607
|
+
const navContainers = Array.from(
|
|
10608
|
+
document.querySelectorAll("[data-ohw-nav-container]")
|
|
10609
|
+
);
|
|
10610
|
+
const footerColumns = listFooterColumns();
|
|
10611
|
+
for (const container of [...navContainers, ...footerColumns]) {
|
|
10612
|
+
const containerRect = container.getBoundingClientRect();
|
|
10613
|
+
const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
|
|
10614
|
+
if (!overContainer) continue;
|
|
10615
|
+
const navItemHit = Array.from(
|
|
10616
|
+
container.querySelectorAll("[data-ohw-href-key]")
|
|
10617
|
+
).find((el) => {
|
|
10618
|
+
if (!isNavigationItem(el) || isNavbarButton2(el)) return false;
|
|
10619
|
+
const itemRect = el.getBoundingClientRect();
|
|
10620
|
+
return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
|
|
10621
|
+
});
|
|
10622
|
+
if (navItemHit) {
|
|
10623
|
+
hoveredNavContainerRef.current = null;
|
|
10624
|
+
setHoveredNavContainerRect(null);
|
|
10625
|
+
const selected = selectedElRef.current;
|
|
10626
|
+
if (selected !== navItemHit) {
|
|
10627
|
+
clearHrefKeyHover(navItemHit);
|
|
10628
|
+
hoveredItemElRef.current = navItemHit;
|
|
10629
|
+
setHoveredItemRect(navItemHit.getBoundingClientRect());
|
|
10630
|
+
} else if (hoveredItemElRef.current === navItemHit) {
|
|
10631
|
+
hoveredItemElRef.current = null;
|
|
10632
|
+
setHoveredItemRect(null);
|
|
10633
|
+
}
|
|
10634
|
+
return;
|
|
10635
|
+
}
|
|
8453
10636
|
}
|
|
8454
|
-
|
|
8455
|
-
|
|
8456
|
-
|
|
10637
|
+
if (toolbarVariantRef.current !== "select-frame") {
|
|
10638
|
+
for (const container of navContainers) {
|
|
10639
|
+
const containerRect = container.getBoundingClientRect();
|
|
10640
|
+
const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
|
|
10641
|
+
if (!overContainer) continue;
|
|
10642
|
+
if (isPointOverNavItem(container, x, y)) continue;
|
|
10643
|
+
hoveredNavContainerRef.current = container;
|
|
10644
|
+
setHoveredNavContainerRect(container.getBoundingClientRect());
|
|
10645
|
+
hoveredItemElRef.current = null;
|
|
10646
|
+
setHoveredItemRect(null);
|
|
10647
|
+
return;
|
|
10648
|
+
}
|
|
8457
10649
|
hoveredNavContainerRef.current = null;
|
|
8458
10650
|
setHoveredNavContainerRect(null);
|
|
8459
|
-
|
|
8460
|
-
}
|
|
8461
|
-
const navItemHit = Array.from(
|
|
8462
|
-
navContainer.querySelectorAll("[data-ohw-href-key]")
|
|
8463
|
-
).find((el) => {
|
|
8464
|
-
if (!isNavigationItem(el) || isNavbarButton2(el)) return false;
|
|
8465
|
-
const itemRect = el.getBoundingClientRect();
|
|
8466
|
-
return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
|
|
8467
|
-
});
|
|
8468
|
-
if (navItemHit) {
|
|
10651
|
+
} else {
|
|
8469
10652
|
hoveredNavContainerRef.current = null;
|
|
8470
10653
|
setHoveredNavContainerRect(null);
|
|
8471
|
-
|
|
8472
|
-
|
|
8473
|
-
|
|
8474
|
-
|
|
8475
|
-
|
|
10654
|
+
}
|
|
10655
|
+
for (const column of footerColumns) {
|
|
10656
|
+
const containerRect = column.getBoundingClientRect();
|
|
10657
|
+
const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
|
|
10658
|
+
if (!overContainer) continue;
|
|
10659
|
+
if (isPointOverNavItem(column, x, y)) continue;
|
|
10660
|
+
if (selectedElRef.current === column) {
|
|
10661
|
+
if (hoveredItemElRef.current === column) {
|
|
10662
|
+
hoveredItemElRef.current = null;
|
|
10663
|
+
setHoveredItemRect(null);
|
|
10664
|
+
}
|
|
10665
|
+
return;
|
|
8476
10666
|
}
|
|
10667
|
+
hoveredItemElRef.current = column;
|
|
10668
|
+
setHoveredItemRect(column.getBoundingClientRect());
|
|
8477
10669
|
return;
|
|
8478
10670
|
}
|
|
8479
|
-
|
|
8480
|
-
|
|
8481
|
-
|
|
8482
|
-
|
|
10671
|
+
if (hoveredItemElRef.current?.hasAttribute("data-ohw-footer-col") || hoveredItemElRef.current?.hasAttribute("data-ohw-footer-column")) {
|
|
10672
|
+
hoveredItemElRef.current = null;
|
|
10673
|
+
setHoveredItemRect(null);
|
|
10674
|
+
}
|
|
8483
10675
|
};
|
|
8484
10676
|
const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
|
|
8485
10677
|
if (linkPopoverOpenRef.current) {
|
|
@@ -8500,6 +10692,10 @@ function OhhwellsBridge() {
|
|
|
8500
10692
|
}
|
|
8501
10693
|
hoveredNavContainerRef.current = null;
|
|
8502
10694
|
setHoveredNavContainerRect(null);
|
|
10695
|
+
if (hoveredItemElRef.current?.hasAttribute("data-ohw-footer-col") || hoveredItemElRef.current?.hasAttribute("data-ohw-footer-column")) {
|
|
10696
|
+
hoveredItemElRef.current = null;
|
|
10697
|
+
setHoveredItemRect(null);
|
|
10698
|
+
}
|
|
8503
10699
|
const toggleEl = document.querySelector("[data-ohw-state-toggle]");
|
|
8504
10700
|
if (toggleEl) {
|
|
8505
10701
|
const tr = toggleEl.getBoundingClientRect();
|
|
@@ -8747,6 +10943,15 @@ function OhhwellsBridge() {
|
|
|
8747
10943
|
probeHoverCardsAt(clientX, clientY);
|
|
8748
10944
|
};
|
|
8749
10945
|
const handleDragOver = (e) => {
|
|
10946
|
+
const footerSession = footerDragRef.current;
|
|
10947
|
+
if (footerSession) {
|
|
10948
|
+
e.preventDefault();
|
|
10949
|
+
if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
|
|
10950
|
+
const slot = footerSession.kind === "link" && footerSession.hrefKey ? hitTestLinkDropSlot(e.clientX, e.clientY, footerSession.hrefKey) : hitTestColumnDropSlot(e.clientX, e.clientY);
|
|
10951
|
+
refreshFooterDragVisualsRef.current(footerSession, slot, e.clientX, e.clientY);
|
|
10952
|
+
return;
|
|
10953
|
+
}
|
|
10954
|
+
if (onNavDragOver(e)) return;
|
|
8750
10955
|
e.preventDefault();
|
|
8751
10956
|
const el = findImageAtPoint(e.clientX, e.clientY, false);
|
|
8752
10957
|
if (!el) {
|
|
@@ -8909,8 +11114,8 @@ function OhhwellsBridge() {
|
|
|
8909
11114
|
if (sibling !== el) sibling.innerHTML = html;
|
|
8910
11115
|
});
|
|
8911
11116
|
const timers = autoSaveTimers.current;
|
|
8912
|
-
const
|
|
8913
|
-
if (
|
|
11117
|
+
const existing2 = timers.get(key);
|
|
11118
|
+
if (existing2) clearTimeout(existing2);
|
|
8914
11119
|
timers.set(key, setTimeout(() => {
|
|
8915
11120
|
timers.delete(key);
|
|
8916
11121
|
postToParentRef.current({ type: "ow:change", nodes: [{ key, text: html }] });
|
|
@@ -8953,6 +11158,7 @@ function OhhwellsBridge() {
|
|
|
8953
11158
|
}
|
|
8954
11159
|
editContentRef.current = { ...editContentRef.current, ...content };
|
|
8955
11160
|
reconcileNavbarItemsFromContent(editContentRef.current);
|
|
11161
|
+
syncNavigationDragCursorAttrs();
|
|
8956
11162
|
enforceLinkHrefs();
|
|
8957
11163
|
postToParentRef.current({ type: "ow:hydrate-done" });
|
|
8958
11164
|
};
|
|
@@ -8973,6 +11179,48 @@ function OhhwellsBridge() {
|
|
|
8973
11179
|
if (e.data?.type !== "ui:escape") return;
|
|
8974
11180
|
if (linkPopoverOpenRef.current) {
|
|
8975
11181
|
setLinkPopoverRef.current(null);
|
|
11182
|
+
return;
|
|
11183
|
+
}
|
|
11184
|
+
if (activeElRef.current) {
|
|
11185
|
+
const hrefCtx = getHrefKeyFromElement(activeElRef.current);
|
|
11186
|
+
const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
|
|
11187
|
+
if (navAnchor) {
|
|
11188
|
+
const el = activeElRef.current;
|
|
11189
|
+
if (originalContentRef.current !== null) {
|
|
11190
|
+
el.innerHTML = originalContentRef.current;
|
|
11191
|
+
}
|
|
11192
|
+
el.removeAttribute("contenteditable");
|
|
11193
|
+
el.removeAttribute("data-ohw-editing");
|
|
11194
|
+
activeElRef.current = null;
|
|
11195
|
+
setMaxBadge(null);
|
|
11196
|
+
setActiveCommands(/* @__PURE__ */ new Set());
|
|
11197
|
+
setToolbarShowEditLink(false);
|
|
11198
|
+
postToParentRef.current({ type: "ow:exit-edit" });
|
|
11199
|
+
reselectNavigationItemRef.current(navAnchor);
|
|
11200
|
+
return;
|
|
11201
|
+
}
|
|
11202
|
+
if (originalContentRef.current !== null) {
|
|
11203
|
+
activeElRef.current.innerHTML = originalContentRef.current;
|
|
11204
|
+
const key = activeElRef.current.dataset.ohwKey;
|
|
11205
|
+
if (key) {
|
|
11206
|
+
postToParentRef.current({ type: "ow:change", nodes: [{ key, text: originalContentRef.current }] });
|
|
11207
|
+
}
|
|
11208
|
+
}
|
|
11209
|
+
deselectRef.current();
|
|
11210
|
+
deactivateRef.current();
|
|
11211
|
+
return;
|
|
11212
|
+
}
|
|
11213
|
+
if (selectedElRef.current) {
|
|
11214
|
+
if (toolbarVariantRef.current === "select-frame") {
|
|
11215
|
+
deselectRef.current();
|
|
11216
|
+
return;
|
|
11217
|
+
}
|
|
11218
|
+
const parent = getNavigationSelectionParent(selectedElRef.current);
|
|
11219
|
+
if (parent && isNavigationContainer(parent)) {
|
|
11220
|
+
selectFrameRef.current(parent);
|
|
11221
|
+
} else {
|
|
11222
|
+
deselectRef.current();
|
|
11223
|
+
}
|
|
8976
11224
|
}
|
|
8977
11225
|
};
|
|
8978
11226
|
window.addEventListener("message", handleUiEscape);
|
|
@@ -8997,7 +11245,7 @@ function OhhwellsBridge() {
|
|
|
8997
11245
|
return;
|
|
8998
11246
|
}
|
|
8999
11247
|
const parent = getNavigationSelectionParent(selectedElRef.current);
|
|
9000
|
-
if (parent) {
|
|
11248
|
+
if (parent && isNavigationContainer(parent)) {
|
|
9001
11249
|
e.preventDefault();
|
|
9002
11250
|
selectFrameRef.current(parent);
|
|
9003
11251
|
} else {
|
|
@@ -9015,6 +11263,7 @@ function OhhwellsBridge() {
|
|
|
9015
11263
|
el2.innerHTML = originalContentRef.current;
|
|
9016
11264
|
}
|
|
9017
11265
|
el2.removeAttribute("contenteditable");
|
|
11266
|
+
el2.removeAttribute("data-ohw-editing");
|
|
9018
11267
|
activeElRef.current = null;
|
|
9019
11268
|
setMaxBadge(null);
|
|
9020
11269
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
@@ -9066,6 +11315,26 @@ function OhhwellsBridge() {
|
|
|
9066
11315
|
if (siblingHintElRef.current) {
|
|
9067
11316
|
setSiblingHintRect(siblingHintElRef.current.getBoundingClientRect());
|
|
9068
11317
|
}
|
|
11318
|
+
const selected = selectedElRef.current;
|
|
11319
|
+
if (selected && !footerDragRef.current && !navDragRef.current) {
|
|
11320
|
+
if (selected.hasAttribute("data-ohw-footer-col") || Boolean(selected.closest("footer") && isInferredFooterGroup(selected))) {
|
|
11321
|
+
setSiblingHintRects(
|
|
11322
|
+
listFooterColumns().filter((column) => column !== selected).map((column) => column.getBoundingClientRect())
|
|
11323
|
+
);
|
|
11324
|
+
} else if (isNavigationItem(selected)) {
|
|
11325
|
+
setSiblingHintRects(collectNavigationItemSiblingHintRects(selected));
|
|
11326
|
+
}
|
|
11327
|
+
}
|
|
11328
|
+
if (footerDragRef.current) {
|
|
11329
|
+
const session = footerDragRef.current;
|
|
11330
|
+
const slot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : hitTestColumnDropSlot(session.lastClientX, session.lastClientY);
|
|
11331
|
+
refreshFooterDragVisualsRef.current(session, slot, session.lastClientX, session.lastClientY);
|
|
11332
|
+
}
|
|
11333
|
+
if (navDragRef.current) {
|
|
11334
|
+
const session = navDragRef.current;
|
|
11335
|
+
const slot = hitTestNavDropSlot(session.lastClientX, session.lastClientY, session.hrefKey);
|
|
11336
|
+
refreshNavDragVisualsRef.current(session, slot, session.lastClientX, session.lastClientY);
|
|
11337
|
+
}
|
|
9069
11338
|
if (hoveredImageRef.current) {
|
|
9070
11339
|
const el = hoveredImageRef.current;
|
|
9071
11340
|
const r2 = el.getBoundingClientRect();
|
|
@@ -9076,7 +11345,7 @@ function OhhwellsBridge() {
|
|
|
9076
11345
|
};
|
|
9077
11346
|
const handleSave = (e) => {
|
|
9078
11347
|
if (e.data?.type !== "ow:save") return;
|
|
9079
|
-
const nodes = collectEditableNodes();
|
|
11348
|
+
const nodes = collectEditableNodes(editContentRef.current);
|
|
9080
11349
|
const tracker = document.querySelector("[data-ohw-sections-tracker]");
|
|
9081
11350
|
if (tracker?.textContent) nodes.push({ key: "__ohw_sections", type: "sections", text: tracker.textContent });
|
|
9082
11351
|
postToParentRef.current({ type: "ow:save-result", nodes });
|
|
@@ -9134,30 +11403,30 @@ function OhhwellsBridge() {
|
|
|
9134
11403
|
const h = document.documentElement.scrollHeight;
|
|
9135
11404
|
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
9136
11405
|
};
|
|
11406
|
+
let selectionChangeRaf = null;
|
|
11407
|
+
const runSelectionChange = () => {
|
|
11408
|
+
selectionChangeRaf = null;
|
|
11409
|
+
const activeRoot = activeElRef.current;
|
|
11410
|
+
if (!activeRoot) return;
|
|
11411
|
+
const startEl = resolveSelectionStartElement(window.getSelection());
|
|
11412
|
+
const next = startEl ? detectActiveFormats(startEl, activeRoot) : /* @__PURE__ */ new Set();
|
|
11413
|
+
setActiveCommands((prev) => setsEqual(prev, next) ? prev : next);
|
|
11414
|
+
};
|
|
9137
11415
|
const handleSelectionChange = () => {
|
|
9138
|
-
if (
|
|
9139
|
-
|
|
9140
|
-
|
|
9141
|
-
|
|
9142
|
-
|
|
9143
|
-
|
|
9144
|
-
|
|
9145
|
-
}
|
|
9146
|
-
const sel = window.getSelection();
|
|
9147
|
-
const anchor = sel?.anchorNode;
|
|
9148
|
-
if (anchor) {
|
|
9149
|
-
const el = anchor.nodeType === Node.TEXT_NODE ? anchor.parentElement : anchor;
|
|
9150
|
-
const block = el?.closest("div, p, h1, h2, h3, h4, h5, h6, li, td, th") ?? el;
|
|
9151
|
-
if (block) {
|
|
9152
|
-
const align = getComputedStyle(block).textAlign;
|
|
9153
|
-
if (align === "center") next.add("justifyCenter");
|
|
9154
|
-
else if (align === "right" || align === "end") next.add("justifyRight");
|
|
9155
|
-
else next.add("justifyLeft");
|
|
9156
|
-
}
|
|
9157
|
-
}
|
|
9158
|
-
setActiveCommands(next);
|
|
11416
|
+
if (pointerHeldRef.current) return;
|
|
11417
|
+
if (selectionChangeRaf !== null) return;
|
|
11418
|
+
selectionChangeRaf = requestAnimationFrame(runSelectionChange);
|
|
11419
|
+
};
|
|
11420
|
+
const markPointerHeld = (e) => {
|
|
11421
|
+
if (e.button !== 0) return;
|
|
11422
|
+
pointerHeldRef.current = true;
|
|
9159
11423
|
};
|
|
9160
|
-
|
|
11424
|
+
const markPointerReleased = () => {
|
|
11425
|
+
if (!pointerHeldRef.current) return;
|
|
11426
|
+
pointerHeldRef.current = false;
|
|
11427
|
+
handleSelectionChange();
|
|
11428
|
+
};
|
|
11429
|
+
refreshActiveCommandsRef.current = runSelectionChange;
|
|
9161
11430
|
const handleDocMouseLeave = () => {
|
|
9162
11431
|
hoveredImageRef.current = null;
|
|
9163
11432
|
setMediaHover(null);
|
|
@@ -9202,15 +11471,15 @@ function OhhwellsBridge() {
|
|
|
9202
11471
|
};
|
|
9203
11472
|
const applyToolbarPos = (rect) => {
|
|
9204
11473
|
const ps = parentScrollRef.current;
|
|
9205
|
-
const
|
|
11474
|
+
const measuredW = toolbarElRef.current?.offsetWidth || 330;
|
|
9206
11475
|
if (toolbarElRef.current) {
|
|
9207
|
-
const { top, left, transform } = calcToolbarPos(rect, ps,
|
|
11476
|
+
const { top, left, transform } = calcToolbarPos(rect, ps, measuredW);
|
|
9208
11477
|
toolbarElRef.current.style.top = `${top}px`;
|
|
9209
11478
|
toolbarElRef.current.style.left = `${left}px`;
|
|
9210
11479
|
toolbarElRef.current.style.transform = transform;
|
|
9211
11480
|
}
|
|
9212
11481
|
if (glowElRef.current) {
|
|
9213
|
-
const GAP =
|
|
11482
|
+
const GAP = SELECTION_CHROME_GAP2;
|
|
9214
11483
|
glowElRef.current.style.top = `${rect.top - GAP}px`;
|
|
9215
11484
|
glowElRef.current.style.left = `${rect.left - GAP}px`;
|
|
9216
11485
|
glowElRef.current.style.width = `${rect.width + GAP * 2}px`;
|
|
@@ -9298,6 +11567,11 @@ function OhhwellsBridge() {
|
|
|
9298
11567
|
return;
|
|
9299
11568
|
}
|
|
9300
11569
|
}
|
|
11570
|
+
const footerColumn = findHoveredNavOrFooterContainer(clientX, clientY);
|
|
11571
|
+
if (footerColumn?.hasAttribute("data-ohw-footer-col") || footerColumn?.hasAttribute("data-ohw-footer-column")) {
|
|
11572
|
+
selectFrameRef.current(footerColumn);
|
|
11573
|
+
return;
|
|
11574
|
+
}
|
|
9301
11575
|
deactivateRef.current();
|
|
9302
11576
|
};
|
|
9303
11577
|
window.addEventListener("message", handleSave);
|
|
@@ -9369,7 +11643,161 @@ function OhhwellsBridge() {
|
|
|
9369
11643
|
if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
|
|
9370
11644
|
};
|
|
9371
11645
|
}, [isEditMode, refreshStateRules]);
|
|
9372
|
-
|
|
11646
|
+
useEffect8(() => {
|
|
11647
|
+
if (!isEditMode) return;
|
|
11648
|
+
const THRESHOLD = 10;
|
|
11649
|
+
const resolveWasSelected = (el) => {
|
|
11650
|
+
if (selectedElRef.current === el) return true;
|
|
11651
|
+
const activeAnchor = activeElRef.current ? getNavigationItemAnchor(activeElRef.current) : null;
|
|
11652
|
+
return activeAnchor === el;
|
|
11653
|
+
};
|
|
11654
|
+
const onPointerDown = (e) => {
|
|
11655
|
+
if (e.button !== 0) return;
|
|
11656
|
+
if (suppressNextClickRef.current && Date.now() >= suppressClickUntilRef.current && !footerDragRef.current && !footerPointerDragRef.current?.started) {
|
|
11657
|
+
suppressNextClickRef.current = false;
|
|
11658
|
+
}
|
|
11659
|
+
if (footerDragRef.current) return;
|
|
11660
|
+
const target = e.target;
|
|
11661
|
+
if (!target) return;
|
|
11662
|
+
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]')) {
|
|
11663
|
+
return;
|
|
11664
|
+
}
|
|
11665
|
+
if (target.closest("[data-ohw-item-drag-surface]")) return;
|
|
11666
|
+
const anchor = getNavigationItemAnchor(target);
|
|
11667
|
+
const hrefKey = anchor?.getAttribute("data-ohw-href-key") ?? null;
|
|
11668
|
+
if (anchor && isFooterHrefKey(hrefKey)) {
|
|
11669
|
+
footerPointerDragRef.current = {
|
|
11670
|
+
el: anchor,
|
|
11671
|
+
kind: "link",
|
|
11672
|
+
startX: e.clientX,
|
|
11673
|
+
startY: e.clientY,
|
|
11674
|
+
pointerId: e.pointerId,
|
|
11675
|
+
wasSelected: resolveWasSelected(anchor),
|
|
11676
|
+
started: false
|
|
11677
|
+
};
|
|
11678
|
+
return;
|
|
11679
|
+
}
|
|
11680
|
+
const col = target.closest("[data-ohw-footer-col]");
|
|
11681
|
+
if (col && !getNavigationItemAnchor(target)) {
|
|
11682
|
+
footerPointerDragRef.current = {
|
|
11683
|
+
el: col,
|
|
11684
|
+
kind: "column",
|
|
11685
|
+
startX: e.clientX,
|
|
11686
|
+
startY: e.clientY,
|
|
11687
|
+
pointerId: e.pointerId,
|
|
11688
|
+
wasSelected: resolveWasSelected(col),
|
|
11689
|
+
started: false
|
|
11690
|
+
};
|
|
11691
|
+
}
|
|
11692
|
+
};
|
|
11693
|
+
const onPointerMove = (e) => {
|
|
11694
|
+
const pending = footerPointerDragRef.current;
|
|
11695
|
+
if (!pending) return;
|
|
11696
|
+
if (pending.started) {
|
|
11697
|
+
e.preventDefault();
|
|
11698
|
+
clearTextSelection();
|
|
11699
|
+
const session = footerDragRef.current;
|
|
11700
|
+
if (!session) return;
|
|
11701
|
+
const slot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(e.clientX, e.clientY, session.hrefKey) : hitTestColumnDropSlot(e.clientX, e.clientY);
|
|
11702
|
+
refreshFooterDragVisualsRef.current(session, slot, e.clientX, e.clientY);
|
|
11703
|
+
return;
|
|
11704
|
+
}
|
|
11705
|
+
const dx = e.clientX - pending.startX;
|
|
11706
|
+
const dy = e.clientY - pending.startY;
|
|
11707
|
+
if (dx * dx + dy * dy < THRESHOLD * THRESHOLD) return;
|
|
11708
|
+
e.preventDefault();
|
|
11709
|
+
pending.started = true;
|
|
11710
|
+
armFooterPressDrag();
|
|
11711
|
+
clearTextSelection();
|
|
11712
|
+
try {
|
|
11713
|
+
document.body.setPointerCapture(pending.pointerId);
|
|
11714
|
+
} catch {
|
|
11715
|
+
}
|
|
11716
|
+
if (linkPopoverOpenRef.current) {
|
|
11717
|
+
setLinkPopoverRef.current(null);
|
|
11718
|
+
}
|
|
11719
|
+
if (activeElRef.current) {
|
|
11720
|
+
deactivateRef.current();
|
|
11721
|
+
}
|
|
11722
|
+
if (pending.kind === "link") {
|
|
11723
|
+
const key = pending.el.getAttribute("data-ohw-href-key");
|
|
11724
|
+
if (!key) return;
|
|
11725
|
+
const column = findFooterColumnForLink(pending.el);
|
|
11726
|
+
const columns2 = listFooterColumns();
|
|
11727
|
+
beginFooterDragRef.current({
|
|
11728
|
+
kind: "link",
|
|
11729
|
+
hrefKey: key,
|
|
11730
|
+
columnEl: column,
|
|
11731
|
+
sourceColumnIndex: column ? columns2.indexOf(column) : 0,
|
|
11732
|
+
wasSelected: pending.wasSelected,
|
|
11733
|
+
draggedEl: pending.el,
|
|
11734
|
+
lastClientX: e.clientX,
|
|
11735
|
+
lastClientY: e.clientY,
|
|
11736
|
+
activeSlot: null
|
|
11737
|
+
});
|
|
11738
|
+
return;
|
|
11739
|
+
}
|
|
11740
|
+
const columns = listFooterColumns();
|
|
11741
|
+
const idx = columns.indexOf(pending.el);
|
|
11742
|
+
if (idx < 0) return;
|
|
11743
|
+
beginFooterDragRef.current({
|
|
11744
|
+
kind: "column",
|
|
11745
|
+
hrefKey: null,
|
|
11746
|
+
columnEl: pending.el,
|
|
11747
|
+
sourceColumnIndex: idx,
|
|
11748
|
+
wasSelected: pending.wasSelected,
|
|
11749
|
+
draggedEl: pending.el,
|
|
11750
|
+
lastClientX: e.clientX,
|
|
11751
|
+
lastClientY: e.clientY,
|
|
11752
|
+
activeSlot: null
|
|
11753
|
+
});
|
|
11754
|
+
};
|
|
11755
|
+
const endPointerDrag = (e) => {
|
|
11756
|
+
const pending = footerPointerDragRef.current;
|
|
11757
|
+
footerPointerDragRef.current = null;
|
|
11758
|
+
try {
|
|
11759
|
+
if (document.body.hasPointerCapture(e.pointerId)) {
|
|
11760
|
+
document.body.releasePointerCapture(e.pointerId);
|
|
11761
|
+
}
|
|
11762
|
+
} catch {
|
|
11763
|
+
}
|
|
11764
|
+
if (!pending) return;
|
|
11765
|
+
if (!pending.started) {
|
|
11766
|
+
unlockFooterDragInteraction();
|
|
11767
|
+
return;
|
|
11768
|
+
}
|
|
11769
|
+
suppressNextClickRef.current = true;
|
|
11770
|
+
suppressClickUntilRef.current = Date.now() + 500;
|
|
11771
|
+
commitFooterDragRef.current(e.clientX, e.clientY);
|
|
11772
|
+
};
|
|
11773
|
+
const blockSelectStart = (e) => {
|
|
11774
|
+
if (footerDragRef.current || footerPointerDragRef.current?.started || document.documentElement.hasAttribute("data-ohw-footer-press-drag")) {
|
|
11775
|
+
e.preventDefault();
|
|
11776
|
+
}
|
|
11777
|
+
};
|
|
11778
|
+
const onDragEnd = (_e) => {
|
|
11779
|
+
if (!footerDragRef.current) return;
|
|
11780
|
+
suppressNextClickRef.current = true;
|
|
11781
|
+
suppressClickUntilRef.current = Date.now() + 500;
|
|
11782
|
+
commitFooterDragRef.current();
|
|
11783
|
+
};
|
|
11784
|
+
document.addEventListener("pointerdown", onPointerDown, true);
|
|
11785
|
+
document.addEventListener("pointermove", onPointerMove, true);
|
|
11786
|
+
document.addEventListener("pointerup", endPointerDrag, true);
|
|
11787
|
+
document.addEventListener("pointercancel", endPointerDrag, true);
|
|
11788
|
+
document.addEventListener("selectstart", blockSelectStart, true);
|
|
11789
|
+
document.addEventListener("dragend", onDragEnd, true);
|
|
11790
|
+
return () => {
|
|
11791
|
+
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
11792
|
+
document.removeEventListener("pointermove", onPointerMove, true);
|
|
11793
|
+
document.removeEventListener("pointerup", endPointerDrag, true);
|
|
11794
|
+
document.removeEventListener("pointercancel", endPointerDrag, true);
|
|
11795
|
+
document.removeEventListener("selectstart", blockSelectStart, true);
|
|
11796
|
+
document.removeEventListener("dragend", onDragEnd, true);
|
|
11797
|
+
unlockFooterDragInteraction();
|
|
11798
|
+
};
|
|
11799
|
+
}, [isEditMode]);
|
|
11800
|
+
useEffect8(() => {
|
|
9373
11801
|
const handler = (e) => {
|
|
9374
11802
|
if (e.data?.type !== "ow:request-schedule-config") return;
|
|
9375
11803
|
const insertAfterVal = e.data.insertAfter;
|
|
@@ -9385,7 +11813,7 @@ function OhhwellsBridge() {
|
|
|
9385
11813
|
window.addEventListener("message", handler);
|
|
9386
11814
|
return () => window.removeEventListener("message", handler);
|
|
9387
11815
|
}, [processConfigRequest]);
|
|
9388
|
-
|
|
11816
|
+
useEffect8(() => {
|
|
9389
11817
|
if (!isEditMode) return;
|
|
9390
11818
|
document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
|
|
9391
11819
|
el.removeAttribute("data-ohw-active-state");
|
|
@@ -9406,7 +11834,13 @@ function OhhwellsBridge() {
|
|
|
9406
11834
|
const next = { ...prev, [pathKey]: sections };
|
|
9407
11835
|
return shouldUseDevFixtures() ? { ...DEV_SECTIONS_BY_PATH, ...next } : next;
|
|
9408
11836
|
});
|
|
9409
|
-
postToParent2({
|
|
11837
|
+
postToParent2({
|
|
11838
|
+
type: "ow:ready",
|
|
11839
|
+
version: "1",
|
|
11840
|
+
path: pathname,
|
|
11841
|
+
nodes: collectEditableNodes(editContentRef.current),
|
|
11842
|
+
sections
|
|
11843
|
+
});
|
|
9410
11844
|
postToParent2({ type: "ow:request-site-pages" });
|
|
9411
11845
|
}, 150);
|
|
9412
11846
|
return () => {
|
|
@@ -9414,19 +11848,49 @@ function OhhwellsBridge() {
|
|
|
9414
11848
|
clearTimeout(timer);
|
|
9415
11849
|
};
|
|
9416
11850
|
}, [pathname, isEditMode, refreshStateRules, postToParent2]);
|
|
9417
|
-
|
|
11851
|
+
useEffect8(() => {
|
|
9418
11852
|
scrollToHashSectionWhenReady();
|
|
9419
11853
|
const onHashChange = () => scrollToHashSectionWhenReady();
|
|
9420
11854
|
window.addEventListener("hashchange", onHashChange);
|
|
9421
11855
|
return () => window.removeEventListener("hashchange", onHashChange);
|
|
9422
11856
|
}, [pathname]);
|
|
9423
|
-
const handleCommand =
|
|
11857
|
+
const handleCommand = useCallback5((cmd) => {
|
|
11858
|
+
const el = activeElRef.current;
|
|
11859
|
+
const selBefore = window.getSelection();
|
|
11860
|
+
let savedOffsets = null;
|
|
11861
|
+
if (el && selBefore && selBefore.rangeCount > 0 && !selBefore.isCollapsed) {
|
|
11862
|
+
const r2 = selBefore.getRangeAt(0);
|
|
11863
|
+
if (el.contains(r2.commonAncestorContainer)) {
|
|
11864
|
+
savedOffsets = {
|
|
11865
|
+
start: textOffsetInRoot(el, r2.startContainer, r2.startOffset),
|
|
11866
|
+
end: textOffsetInRoot(el, r2.endContainer, r2.endOffset)
|
|
11867
|
+
};
|
|
11868
|
+
}
|
|
11869
|
+
}
|
|
11870
|
+
document.execCommand("styleWithCSS", false, true);
|
|
9424
11871
|
document.execCommand(cmd, false);
|
|
9425
|
-
|
|
9426
|
-
|
|
11872
|
+
if (el && document.activeElement !== el) {
|
|
11873
|
+
el.focus();
|
|
11874
|
+
}
|
|
11875
|
+
const selAfter = window.getSelection();
|
|
11876
|
+
if (el && savedOffsets && selAfter?.isCollapsed) {
|
|
11877
|
+
const start = pointAtTextOffset(el, savedOffsets.start);
|
|
11878
|
+
const end = pointAtTextOffset(el, savedOffsets.end);
|
|
11879
|
+
if (start && end) {
|
|
11880
|
+
try {
|
|
11881
|
+
const range = document.createRange();
|
|
11882
|
+
range.setStart(start.node, start.offset);
|
|
11883
|
+
range.setEnd(end.node, end.offset);
|
|
11884
|
+
selAfter.removeAllRanges();
|
|
11885
|
+
selAfter.addRange(range);
|
|
11886
|
+
} catch {
|
|
11887
|
+
}
|
|
11888
|
+
}
|
|
11889
|
+
}
|
|
11890
|
+
if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
|
|
9427
11891
|
refreshActiveCommandsRef.current();
|
|
9428
11892
|
}, []);
|
|
9429
|
-
const handleStateChange =
|
|
11893
|
+
const handleStateChange = useCallback5((state) => {
|
|
9430
11894
|
if (!activeStateElRef.current) return;
|
|
9431
11895
|
const el = activeStateElRef.current;
|
|
9432
11896
|
if (state === "Default") {
|
|
@@ -9439,11 +11903,11 @@ function OhhwellsBridge() {
|
|
|
9439
11903
|
}
|
|
9440
11904
|
setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
|
|
9441
11905
|
}, [deactivate]);
|
|
9442
|
-
const closeLinkPopover =
|
|
11906
|
+
const closeLinkPopover = useCallback5(() => {
|
|
9443
11907
|
addNavAfterAnchorRef.current = null;
|
|
9444
11908
|
setLinkPopover(null);
|
|
9445
11909
|
}, []);
|
|
9446
|
-
const openLinkPopoverForActive =
|
|
11910
|
+
const openLinkPopoverForActive = useCallback5(() => {
|
|
9447
11911
|
const hrefCtx = getHrefKeyFromElement(activeElRef.current);
|
|
9448
11912
|
if (!hrefCtx) return;
|
|
9449
11913
|
bumpLinkPopoverGrace();
|
|
@@ -9454,7 +11918,7 @@ function OhhwellsBridge() {
|
|
|
9454
11918
|
});
|
|
9455
11919
|
deactivate();
|
|
9456
11920
|
}, [deactivate]);
|
|
9457
|
-
const openLinkPopoverForSelected =
|
|
11921
|
+
const openLinkPopoverForSelected = useCallback5(() => {
|
|
9458
11922
|
const anchor = selectedElRef.current;
|
|
9459
11923
|
if (!anchor) return;
|
|
9460
11924
|
const key = anchor.getAttribute("data-ohw-href-key");
|
|
@@ -9467,7 +11931,7 @@ function OhhwellsBridge() {
|
|
|
9467
11931
|
});
|
|
9468
11932
|
deselect();
|
|
9469
11933
|
}, [deselect]);
|
|
9470
|
-
const handleLinkPopoverSubmit =
|
|
11934
|
+
const handleLinkPopoverSubmit = useCallback5(
|
|
9471
11935
|
(target) => {
|
|
9472
11936
|
const session = linkPopoverSessionRef.current;
|
|
9473
11937
|
if (!session) return;
|
|
@@ -9526,13 +11990,13 @@ function OhhwellsBridge() {
|
|
|
9526
11990
|
const showEditLink = toolbarShowEditLink;
|
|
9527
11991
|
const currentSections = sectionsByPath[pathname] ?? [];
|
|
9528
11992
|
linkPopoverOpenRef.current = linkPopover !== null;
|
|
9529
|
-
const handleMediaReplace =
|
|
11993
|
+
const handleMediaReplace = useCallback5(
|
|
9530
11994
|
(key) => {
|
|
9531
11995
|
postToParent2({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
|
|
9532
11996
|
},
|
|
9533
11997
|
[postToParent2, mediaHover?.elementType]
|
|
9534
11998
|
);
|
|
9535
|
-
const handleMediaFadeOutComplete =
|
|
11999
|
+
const handleMediaFadeOutComplete = useCallback5((key) => {
|
|
9536
12000
|
setUploadingRects((prev) => {
|
|
9537
12001
|
if (!(key in prev)) return prev;
|
|
9538
12002
|
const next = { ...prev };
|
|
@@ -9540,7 +12004,7 @@ function OhhwellsBridge() {
|
|
|
9540
12004
|
return next;
|
|
9541
12005
|
});
|
|
9542
12006
|
}, []);
|
|
9543
|
-
const handleVideoSettingsChange =
|
|
12007
|
+
const handleVideoSettingsChange = useCallback5(
|
|
9544
12008
|
(key, settings) => {
|
|
9545
12009
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
9546
12010
|
const video = getVideoEl(el);
|
|
@@ -9564,8 +12028,8 @@ function OhhwellsBridge() {
|
|
|
9564
12028
|
);
|
|
9565
12029
|
return bridgeRoot ? createPortal2(
|
|
9566
12030
|
/* @__PURE__ */ jsxs13(Fragment5, { children: [
|
|
9567
|
-
/* @__PURE__ */
|
|
9568
|
-
Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */
|
|
12031
|
+
/* @__PURE__ */ jsx24("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
|
|
12032
|
+
Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ jsx24(
|
|
9569
12033
|
MediaOverlay,
|
|
9570
12034
|
{
|
|
9571
12035
|
hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
|
|
@@ -9576,7 +12040,7 @@ function OhhwellsBridge() {
|
|
|
9576
12040
|
},
|
|
9577
12041
|
`uploading-${key}`
|
|
9578
12042
|
)),
|
|
9579
|
-
mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */
|
|
12043
|
+
mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ jsx24(
|
|
9580
12044
|
MediaOverlay,
|
|
9581
12045
|
{
|
|
9582
12046
|
hover: mediaHover,
|
|
@@ -9585,49 +12049,93 @@ function OhhwellsBridge() {
|
|
|
9585
12049
|
onVideoSettingsChange: handleVideoSettingsChange
|
|
9586
12050
|
}
|
|
9587
12051
|
),
|
|
9588
|
-
siblingHintRect && !isItemDragging && /* @__PURE__ */
|
|
9589
|
-
|
|
9590
|
-
|
|
9591
|
-
|
|
12052
|
+
siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ jsx24(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
|
|
12053
|
+
siblingHintRects.length > 0 && !linkPopover && siblingHintRects.map((rect, i) => /* @__PURE__ */ jsx24(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
|
|
12054
|
+
isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ jsx24(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
|
|
12055
|
+
isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ jsx24(
|
|
12056
|
+
"div",
|
|
9592
12057
|
{
|
|
9593
|
-
|
|
9594
|
-
|
|
9595
|
-
|
|
9596
|
-
|
|
9597
|
-
|
|
9598
|
-
|
|
12058
|
+
className: "pointer-events-none fixed z-2147483646",
|
|
12059
|
+
style: {
|
|
12060
|
+
left: slot.left,
|
|
12061
|
+
top: slot.top,
|
|
12062
|
+
width: slot.width,
|
|
12063
|
+
height: slot.height
|
|
12064
|
+
},
|
|
12065
|
+
children: /* @__PURE__ */ jsx24(
|
|
12066
|
+
DropIndicator,
|
|
12067
|
+
{
|
|
12068
|
+
direction: slot.direction,
|
|
12069
|
+
state: activeFooterDropIndex === i ? "dragActive" : "dragIdle",
|
|
12070
|
+
className: "!h-full !w-full"
|
|
12071
|
+
}
|
|
12072
|
+
)
|
|
12073
|
+
},
|
|
12074
|
+
`footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
|
|
12075
|
+
)),
|
|
12076
|
+
isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ jsx24(
|
|
12077
|
+
"div",
|
|
12078
|
+
{
|
|
12079
|
+
className: "pointer-events-none fixed z-2147483646",
|
|
12080
|
+
style: {
|
|
12081
|
+
left: slot.left,
|
|
12082
|
+
top: slot.top,
|
|
12083
|
+
width: slot.width,
|
|
12084
|
+
height: slot.height
|
|
12085
|
+
},
|
|
12086
|
+
children: /* @__PURE__ */ jsx24(
|
|
12087
|
+
DropIndicator,
|
|
12088
|
+
{
|
|
12089
|
+
direction: slot.direction,
|
|
12090
|
+
state: activeNavDropIndex === i ? "dragActive" : "dragIdle",
|
|
12091
|
+
className: "!h-full !w-full"
|
|
12092
|
+
}
|
|
12093
|
+
)
|
|
12094
|
+
},
|
|
12095
|
+
`nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
|
|
12096
|
+
)),
|
|
12097
|
+
hoveredNavContainerRect && toolbarVariant !== "select-frame" && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx24(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
|
|
12098
|
+
hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx24(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
|
|
12099
|
+
toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer(selectedElRef.current) && /* @__PURE__ */ jsx24(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
|
|
12100
|
+
toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ jsx24(
|
|
9599
12101
|
ItemInteractionLayer,
|
|
9600
12102
|
{
|
|
9601
|
-
rect: toolbarRect,
|
|
12103
|
+
rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
|
|
9602
12104
|
elRef: glowElRef,
|
|
9603
12105
|
state: isItemDragging ? "dragging" : resolveItemInteractionState(toolbarRect, parentScrollRef.current),
|
|
9604
|
-
showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey),
|
|
12106
|
+
showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey) || toolbarVariant === "select-frame" && isFooterFrameSelection,
|
|
9605
12107
|
dragDisabled: reorderDragDisabled,
|
|
9606
12108
|
dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
|
|
9607
12109
|
onDragHandleDragStart: handleItemDragStart,
|
|
9608
12110
|
onDragHandleDragEnd: handleItemDragEnd,
|
|
9609
|
-
|
|
12111
|
+
onItemPointerDown: handleItemChromePointerDown,
|
|
12112
|
+
onItemClick: handleItemChromeClick,
|
|
12113
|
+
itemDragSurface: !isFooterFrameSelection,
|
|
12114
|
+
toolbar: toolbarVariant === "link-action" && !isItemDragging ? /* @__PURE__ */ jsx24(
|
|
9610
12115
|
ItemActionToolbar,
|
|
9611
12116
|
{
|
|
9612
12117
|
onEditLink: openLinkPopoverForSelected,
|
|
9613
12118
|
addItemDisabled: true,
|
|
9614
12119
|
editLinkDisabled: false,
|
|
9615
|
-
moreDisabled: true
|
|
12120
|
+
moreDisabled: true,
|
|
12121
|
+
showAddItem: !selectedIsCta,
|
|
12122
|
+
showMore: !selectedIsCta
|
|
9616
12123
|
}
|
|
9617
12124
|
) : void 0
|
|
9618
12125
|
}
|
|
9619
12126
|
),
|
|
9620
|
-
toolbarRect && toolbarVariant === "rich-text" && /* @__PURE__ */ jsxs13(Fragment5, { children: [
|
|
9621
|
-
/* @__PURE__ */
|
|
12127
|
+
toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ jsxs13(Fragment5, { children: [
|
|
12128
|
+
/* @__PURE__ */ jsx24(
|
|
9622
12129
|
EditGlowChrome,
|
|
9623
12130
|
{
|
|
9624
12131
|
rect: toolbarRect,
|
|
9625
12132
|
elRef: glowElRef,
|
|
9626
12133
|
reorderHrefKey,
|
|
9627
|
-
dragDisabled: reorderDragDisabled
|
|
12134
|
+
dragDisabled: reorderDragDisabled,
|
|
12135
|
+
hideHandle: isItemDragging
|
|
9628
12136
|
}
|
|
9629
12137
|
),
|
|
9630
|
-
/* @__PURE__ */
|
|
12138
|
+
/* @__PURE__ */ jsx24(
|
|
9631
12139
|
FloatingToolbar,
|
|
9632
12140
|
{
|
|
9633
12141
|
rect: toolbarRect,
|
|
@@ -9666,7 +12174,7 @@ function OhhwellsBridge() {
|
|
|
9666
12174
|
]
|
|
9667
12175
|
}
|
|
9668
12176
|
),
|
|
9669
|
-
toggleState && !linkPopover && /* @__PURE__ */
|
|
12177
|
+
toggleState && !linkPopover && /* @__PURE__ */ jsx24(
|
|
9670
12178
|
StateToggle,
|
|
9671
12179
|
{
|
|
9672
12180
|
rect: toggleState.rect,
|
|
@@ -9682,25 +12190,29 @@ function OhhwellsBridge() {
|
|
|
9682
12190
|
className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
|
|
9683
12191
|
style: { top: sectionGap.y, transform: "translateY(-50%)" },
|
|
9684
12192
|
children: [
|
|
9685
|
-
/* @__PURE__ */
|
|
9686
|
-
/* @__PURE__ */
|
|
12193
|
+
/* @__PURE__ */ jsx24("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
|
|
12194
|
+
/* @__PURE__ */ jsx24(
|
|
9687
12195
|
Badge,
|
|
9688
12196
|
{
|
|
9689
12197
|
className: "px-8 py-1 bg-primary hover:bg-primary text-primary-foreground text-xs font-medium shrink-0 rounded-full cursor-pointer pointer-events-auto",
|
|
9690
12198
|
onClick: () => {
|
|
9691
12199
|
window.parent.postMessage(
|
|
9692
|
-
{
|
|
12200
|
+
{
|
|
12201
|
+
type: "ow:add-section",
|
|
12202
|
+
insertAfter: sectionGap.insertAfter,
|
|
12203
|
+
insertBefore: sectionGap.insertBefore
|
|
12204
|
+
},
|
|
9693
12205
|
"*"
|
|
9694
12206
|
);
|
|
9695
12207
|
},
|
|
9696
12208
|
children: "Add Section"
|
|
9697
12209
|
}
|
|
9698
12210
|
),
|
|
9699
|
-
/* @__PURE__ */
|
|
12211
|
+
/* @__PURE__ */ jsx24("div", { className: "flex-1 bg-primary", style: { height: 3 } })
|
|
9700
12212
|
]
|
|
9701
12213
|
}
|
|
9702
12214
|
),
|
|
9703
|
-
linkPopover && dialogPortalContainer ? /* @__PURE__ */
|
|
12215
|
+
linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx24(
|
|
9704
12216
|
LinkPopover,
|
|
9705
12217
|
{
|
|
9706
12218
|
panelRef: linkPopoverPanelRef,
|
|
@@ -9726,6 +12238,7 @@ export {
|
|
|
9726
12238
|
CustomToolbarButton,
|
|
9727
12239
|
CustomToolbarDivider,
|
|
9728
12240
|
DragHandle,
|
|
12241
|
+
DropIndicator,
|
|
9729
12242
|
ItemActionToolbar,
|
|
9730
12243
|
ItemInteractionLayer,
|
|
9731
12244
|
LinkEditorPanel,
|
|
@@ -9740,6 +12253,7 @@ export {
|
|
|
9740
12253
|
TooltipProvider,
|
|
9741
12254
|
TooltipTrigger,
|
|
9742
12255
|
buildTarget,
|
|
12256
|
+
dropIndicatorVariants,
|
|
9743
12257
|
filterAvailablePages,
|
|
9744
12258
|
getEditModeInitialState,
|
|
9745
12259
|
isEditSessionActive,
|