@ohhwells/bridge 0.1.40 → 0.1.42-next.100
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 +3003 -460
- 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 +3010 -469
- 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,1019 @@ 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
|
+
document.documentElement.removeAttribute("data-ohw-footer-press-drag");
|
|
7195
|
+
document.documentElement.removeAttribute("data-ohw-item-dragging");
|
|
7196
|
+
clearTextSelection();
|
|
7197
|
+
}
|
|
7198
|
+
var armFooterPressDrag = armItemPressDrag;
|
|
7199
|
+
var lockFooterDuringDrag = lockItemDuringDrag;
|
|
7200
|
+
var unlockFooterDragInteraction = unlockItemDragInteraction;
|
|
7201
|
+
|
|
7202
|
+
// src/lib/nav-dnd.ts
|
|
7203
|
+
function listReorderableNavItems() {
|
|
7204
|
+
return listNavbarItems().filter((el) => {
|
|
7205
|
+
const key = el.getAttribute("data-ohw-href-key");
|
|
7206
|
+
return isNavbarHrefKey(key) && !el.closest("[data-ohw-nav-children]");
|
|
7207
|
+
});
|
|
7208
|
+
}
|
|
7209
|
+
function listNavChildren(parentHrefKey) {
|
|
7210
|
+
const items = listNavbarItems();
|
|
7211
|
+
const parent = items.find((el) => el.getAttribute("data-ohw-href-key") === parentHrefKey);
|
|
7212
|
+
if (!parent) return [];
|
|
7213
|
+
const group = parent.closest("[data-ohw-nav-group]");
|
|
7214
|
+
const childrenRoot = group?.querySelector(":scope > [data-ohw-nav-children]");
|
|
7215
|
+
if (!childrenRoot) return [];
|
|
7216
|
+
return Array.from(childrenRoot.querySelectorAll(":scope > [data-ohw-href-key]")).filter(
|
|
7217
|
+
(el) => isNavbarHrefKey(el.getAttribute("data-ohw-href-key"))
|
|
7218
|
+
);
|
|
7219
|
+
}
|
|
7220
|
+
function activeNavListContainer() {
|
|
7221
|
+
const desktop = getNavbarDesktopContainer();
|
|
7222
|
+
if (desktop && desktop.getClientRects().length > 0) {
|
|
7223
|
+
const style = window.getComputedStyle(desktop);
|
|
7224
|
+
if (style.display !== "none" && style.visibility !== "hidden") return desktop;
|
|
7225
|
+
}
|
|
7226
|
+
return getNavbarDrawerContainer();
|
|
7227
|
+
}
|
|
7228
|
+
function buildRootNavDropSlots() {
|
|
7229
|
+
const items = listReorderableNavItems();
|
|
7230
|
+
const slots = [];
|
|
7231
|
+
const barThickness = 3;
|
|
7232
|
+
if (items.length === 0) {
|
|
7233
|
+
const container = activeNavListContainer();
|
|
7234
|
+
if (!container) return slots;
|
|
7235
|
+
const rect = container.getBoundingClientRect();
|
|
7236
|
+
slots.push({
|
|
7237
|
+
insertIndex: 0,
|
|
7238
|
+
parentId: null,
|
|
7239
|
+
left: rect.left + rect.width / 2 - barThickness / 2,
|
|
7240
|
+
top: rect.top,
|
|
7241
|
+
width: barThickness,
|
|
7242
|
+
height: Math.max(rect.height, 24),
|
|
7243
|
+
direction: "vertical"
|
|
7244
|
+
});
|
|
7245
|
+
return slots;
|
|
7246
|
+
}
|
|
7247
|
+
for (let i = 0; i <= items.length; i++) {
|
|
7248
|
+
let left;
|
|
7249
|
+
let top;
|
|
7250
|
+
let height;
|
|
7251
|
+
if (i === 0) {
|
|
7252
|
+
const first = items[0].getBoundingClientRect();
|
|
7253
|
+
left = first.left - barThickness / 2;
|
|
7254
|
+
top = first.top;
|
|
7255
|
+
height = first.height;
|
|
7256
|
+
} else if (i === items.length) {
|
|
7257
|
+
const last = items[items.length - 1].getBoundingClientRect();
|
|
7258
|
+
left = last.right - barThickness / 2;
|
|
7259
|
+
top = last.top;
|
|
7260
|
+
height = last.height;
|
|
7261
|
+
} else {
|
|
7262
|
+
const prev = items[i - 1].getBoundingClientRect();
|
|
7263
|
+
const next = items[i].getBoundingClientRect();
|
|
7264
|
+
left = (prev.right + next.left) / 2 - barThickness / 2;
|
|
7265
|
+
top = Math.min(prev.top, next.top);
|
|
7266
|
+
height = Math.max(prev.bottom, next.bottom) - top;
|
|
7267
|
+
}
|
|
7268
|
+
slots.push({
|
|
7269
|
+
insertIndex: i,
|
|
7270
|
+
parentId: null,
|
|
7271
|
+
left,
|
|
7272
|
+
top,
|
|
7273
|
+
width: barThickness,
|
|
7274
|
+
height: Math.max(height, 24),
|
|
7275
|
+
direction: "vertical"
|
|
7276
|
+
});
|
|
7277
|
+
}
|
|
7278
|
+
return slots;
|
|
7279
|
+
}
|
|
7280
|
+
function buildChildNavDropSlots(parentHrefKey) {
|
|
7281
|
+
const children = listNavChildren(parentHrefKey);
|
|
7282
|
+
const slots = [];
|
|
7283
|
+
const barThickness = 3;
|
|
7284
|
+
if (children.length === 0) return slots;
|
|
7285
|
+
for (let i = 0; i <= children.length; i++) {
|
|
7286
|
+
let top;
|
|
7287
|
+
let width;
|
|
7288
|
+
let left;
|
|
7289
|
+
if (i === 0) {
|
|
7290
|
+
const first = children[0].getBoundingClientRect();
|
|
7291
|
+
top = first.top - barThickness / 2;
|
|
7292
|
+
left = first.left;
|
|
7293
|
+
width = first.width;
|
|
7294
|
+
} else if (i === children.length) {
|
|
7295
|
+
const last = children[children.length - 1].getBoundingClientRect();
|
|
7296
|
+
top = last.bottom - barThickness / 2;
|
|
7297
|
+
left = last.left;
|
|
7298
|
+
width = last.width;
|
|
7299
|
+
} else {
|
|
7300
|
+
const prev = children[i - 1].getBoundingClientRect();
|
|
7301
|
+
const next = children[i].getBoundingClientRect();
|
|
7302
|
+
top = (prev.bottom + next.top) / 2 - barThickness / 2;
|
|
7303
|
+
left = Math.min(prev.left, next.left);
|
|
7304
|
+
width = Math.max(prev.right, next.right) - left;
|
|
7305
|
+
}
|
|
7306
|
+
slots.push({
|
|
7307
|
+
insertIndex: i,
|
|
7308
|
+
parentId: parentHrefKey,
|
|
7309
|
+
left,
|
|
7310
|
+
top,
|
|
7311
|
+
width: Math.max(width, 40),
|
|
7312
|
+
height: barThickness,
|
|
7313
|
+
direction: "horizontal"
|
|
7314
|
+
});
|
|
7315
|
+
}
|
|
7316
|
+
return slots;
|
|
7317
|
+
}
|
|
7318
|
+
function buildAllNavDropSlots(draggedHrefKey) {
|
|
7319
|
+
const slots = [...buildRootNavDropSlots()];
|
|
7320
|
+
for (const item of listReorderableNavItems()) {
|
|
7321
|
+
const key = item.getAttribute("data-ohw-href-key");
|
|
7322
|
+
if (!key || key === draggedHrefKey) continue;
|
|
7323
|
+
const group = item.closest("[data-ohw-nav-group]");
|
|
7324
|
+
if (!group?.querySelector(":scope > [data-ohw-nav-children]")) continue;
|
|
7325
|
+
slots.push(...buildChildNavDropSlots(key));
|
|
7326
|
+
}
|
|
7327
|
+
const dragged = listNavbarItems().find((el) => el.getAttribute("data-ohw-href-key") === draggedHrefKey);
|
|
7328
|
+
const parentGroup = dragged?.closest("[data-ohw-nav-children]")?.closest("[data-ohw-nav-group]");
|
|
7329
|
+
const parentTrigger = parentGroup?.querySelector(":scope > [data-ohw-href-key]");
|
|
7330
|
+
const parentKey = parentTrigger?.getAttribute("data-ohw-href-key");
|
|
7331
|
+
if (parentKey && isNavbarHrefKey(parentKey)) {
|
|
7332
|
+
const existing = slots.some((s) => s.parentId === parentKey);
|
|
7333
|
+
if (!existing) slots.push(...buildChildNavDropSlots(parentKey));
|
|
7334
|
+
}
|
|
7335
|
+
return slots;
|
|
7336
|
+
}
|
|
7337
|
+
function hitTestNavDropSlot(clientX, clientY, draggedHrefKey) {
|
|
7338
|
+
const slots = buildAllNavDropSlots(draggedHrefKey);
|
|
7339
|
+
let best = null;
|
|
7340
|
+
for (const slot of slots) {
|
|
7341
|
+
const cx2 = slot.left + slot.width / 2;
|
|
7342
|
+
const cy = slot.top + slot.height / 2;
|
|
7343
|
+
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;
|
|
7344
|
+
if (!best || dist < best.dist) best = { slot, dist };
|
|
7345
|
+
}
|
|
7346
|
+
return best?.slot ?? null;
|
|
7347
|
+
}
|
|
7348
|
+
function siblingRectsForNavDrag(draggedEl, activeParentId) {
|
|
7349
|
+
if (activeParentId) {
|
|
7350
|
+
return listNavChildren(activeParentId).filter((el) => el !== draggedEl).map((el) => el.getBoundingClientRect());
|
|
7351
|
+
}
|
|
7352
|
+
return listReorderableNavItems().filter((el) => el !== draggedEl).map((el) => el.getBoundingClientRect());
|
|
7353
|
+
}
|
|
7354
|
+
|
|
7355
|
+
// src/useNavItemDrag.ts
|
|
7356
|
+
import { useCallback as useCallback4, useEffect as useEffect7, useRef as useRef6, useState as useState6 } from "react";
|
|
7357
|
+
function useNavItemDrag({
|
|
7358
|
+
isEditMode,
|
|
7359
|
+
editContentRef,
|
|
7360
|
+
selectedElRef,
|
|
7361
|
+
activeElRef,
|
|
7362
|
+
footerDragRef,
|
|
7363
|
+
suppressNextClickRef,
|
|
7364
|
+
suppressClickUntilRef,
|
|
7365
|
+
siblingHintElRef,
|
|
7366
|
+
postToParentRef,
|
|
7367
|
+
deselectRef,
|
|
7368
|
+
selectRef,
|
|
7369
|
+
deactivateRef,
|
|
7370
|
+
setLinkPopover,
|
|
7371
|
+
linkPopoverOpenRef,
|
|
7372
|
+
setIsItemDragging,
|
|
7373
|
+
setDraggedItemRect,
|
|
7374
|
+
setSiblingHintRect,
|
|
7375
|
+
setSiblingHintRects,
|
|
7376
|
+
setToolbarRect,
|
|
7377
|
+
getNavigationItemAnchor: getNavigationItemAnchor2,
|
|
7378
|
+
isDragHandleDisabled: isDragHandleDisabled2,
|
|
7379
|
+
isNavbarButton: isNavbarButton3
|
|
7380
|
+
}) {
|
|
7381
|
+
const navDragRef = useRef6(null);
|
|
7382
|
+
const [navDropSlots, setNavDropSlots] = useState6([]);
|
|
7383
|
+
const [activeNavDropIndex, setActiveNavDropIndex] = useState6(null);
|
|
7384
|
+
const navPointerDragRef = useRef6(null);
|
|
7385
|
+
const clearNavDragVisuals = useCallback4(() => {
|
|
7386
|
+
navDragRef.current = null;
|
|
7387
|
+
setNavDropSlots([]);
|
|
7388
|
+
setActiveNavDropIndex(null);
|
|
7389
|
+
setDraggedItemRect(null);
|
|
7390
|
+
setSiblingHintRects([]);
|
|
7391
|
+
setIsItemDragging(false);
|
|
7392
|
+
unlockItemDragInteraction();
|
|
7393
|
+
}, [setDraggedItemRect, setIsItemDragging, setSiblingHintRects]);
|
|
7394
|
+
const refreshNavDragVisuals = useCallback4(
|
|
7395
|
+
(session, activeSlot, clientX, clientY) => {
|
|
7396
|
+
setDraggedItemRect(session.draggedEl.getBoundingClientRect());
|
|
7397
|
+
if (typeof clientX === "number" && typeof clientY === "number") {
|
|
7398
|
+
session.lastClientX = clientX;
|
|
7399
|
+
session.lastClientY = clientY;
|
|
7400
|
+
}
|
|
7401
|
+
session.activeSlot = activeSlot;
|
|
7402
|
+
const parentId = activeSlot?.parentId ?? null;
|
|
7403
|
+
setSiblingHintRects(siblingRectsForNavDrag(session.draggedEl, parentId));
|
|
7404
|
+
const slots = buildAllNavDropSlots(session.hrefKey);
|
|
7405
|
+
setNavDropSlots(slots);
|
|
7406
|
+
const activeIdx = activeSlot ? slots.findIndex(
|
|
7407
|
+
(s) => s.parentId === activeSlot.parentId && s.insertIndex === activeSlot.insertIndex
|
|
7408
|
+
) : -1;
|
|
7409
|
+
setActiveNavDropIndex(activeIdx >= 0 ? activeIdx : null);
|
|
7410
|
+
},
|
|
7411
|
+
[setDraggedItemRect, setSiblingHintRects]
|
|
7412
|
+
);
|
|
7413
|
+
const refreshNavDragVisualsRef = useRef6(refreshNavDragVisuals);
|
|
7414
|
+
refreshNavDragVisualsRef.current = refreshNavDragVisuals;
|
|
7415
|
+
const commitNavDragRef = useRef6(() => {
|
|
7416
|
+
});
|
|
7417
|
+
const beginNavDragRef = useRef6(() => {
|
|
7418
|
+
});
|
|
7419
|
+
const beginNavDrag = useCallback4(
|
|
7420
|
+
(session) => {
|
|
7421
|
+
const rect = session.draggedEl.getBoundingClientRect();
|
|
7422
|
+
session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
|
|
7423
|
+
session.lastClientY = session.lastClientY || rect.top + rect.height / 2;
|
|
7424
|
+
session.activeSlot = session.activeSlot ?? null;
|
|
7425
|
+
navDragRef.current = session;
|
|
7426
|
+
setIsItemDragging(true);
|
|
7427
|
+
lockItemDuringDrag();
|
|
7428
|
+
siblingHintElRef.current = null;
|
|
7429
|
+
setSiblingHintRect(null);
|
|
7430
|
+
if (session.wasSelected && selectedElRef.current === session.draggedEl) {
|
|
7431
|
+
setToolbarRect(rect);
|
|
7432
|
+
}
|
|
7433
|
+
const initialSlot = hitTestNavDropSlot(session.lastClientX, session.lastClientY, session.hrefKey);
|
|
7434
|
+
refreshNavDragVisuals(session, initialSlot, session.lastClientX, session.lastClientY);
|
|
7435
|
+
},
|
|
7436
|
+
[
|
|
7437
|
+
refreshNavDragVisuals,
|
|
7438
|
+
selectedElRef,
|
|
7439
|
+
setIsItemDragging,
|
|
7440
|
+
setSiblingHintRect,
|
|
7441
|
+
setToolbarRect,
|
|
7442
|
+
siblingHintElRef
|
|
7443
|
+
]
|
|
7444
|
+
);
|
|
7445
|
+
beginNavDragRef.current = beginNavDrag;
|
|
7446
|
+
const commitNavDrag = useCallback4(
|
|
7447
|
+
(clientX, clientY) => {
|
|
7448
|
+
const session = navDragRef.current;
|
|
7449
|
+
if (!session) {
|
|
7450
|
+
clearNavDragVisuals();
|
|
7451
|
+
return;
|
|
7452
|
+
}
|
|
7453
|
+
const x = typeof clientX === "number" && (clientX !== 0 || clientY !== 0) ? clientX : session.lastClientX;
|
|
7454
|
+
const y = typeof clientY === "number" && (clientX !== 0 || clientY !== 0) ? clientY : session.lastClientY;
|
|
7455
|
+
const slot = session.activeSlot ?? hitTestNavDropSlot(x, y, session.hrefKey);
|
|
7456
|
+
const planned = slot != null ? planNavItemMove(session.hrefKey, slot.parentId, slot.insertIndex) : null;
|
|
7457
|
+
const wasSelected = session.wasSelected;
|
|
7458
|
+
const hrefKey = session.hrefKey;
|
|
7459
|
+
const applySelectionAfterDrop = () => {
|
|
7460
|
+
if (!wasSelected) {
|
|
7461
|
+
deselectRef.current();
|
|
7462
|
+
return;
|
|
7463
|
+
}
|
|
7464
|
+
const desktop = document.querySelector("[data-ohw-nav-container]");
|
|
7465
|
+
const drawer = document.querySelector("[data-ohw-nav-drawer]");
|
|
7466
|
+
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)}"]`);
|
|
7467
|
+
if (link) {
|
|
7468
|
+
selectRef.current(link);
|
|
7469
|
+
return;
|
|
7470
|
+
}
|
|
7471
|
+
deselectRef.current();
|
|
7472
|
+
};
|
|
7473
|
+
if (planned) {
|
|
7474
|
+
editContentRef.current = {
|
|
7475
|
+
...editContentRef.current,
|
|
7476
|
+
[NAV_ORDER_KEY]: planned.orderJson
|
|
7477
|
+
};
|
|
7478
|
+
applyNavForest(planned.forest);
|
|
7479
|
+
document.querySelectorAll(
|
|
7480
|
+
"nav [data-ohw-href-key], [data-ohw-nav-container] [data-ohw-href-key], [data-ohw-nav-drawer] [data-ohw-href-key]"
|
|
7481
|
+
).forEach((el) => {
|
|
7482
|
+
if (isNavbarHrefKey(el.getAttribute("data-ohw-href-key"))) {
|
|
7483
|
+
disableNativeHrefDrag(el);
|
|
7484
|
+
}
|
|
7485
|
+
});
|
|
7486
|
+
postToParentRef.current({
|
|
7487
|
+
type: "ow:change",
|
|
7488
|
+
nodes: [{ key: NAV_ORDER_KEY, text: planned.orderJson }]
|
|
7489
|
+
});
|
|
7490
|
+
applySelectionAfterDrop();
|
|
7491
|
+
clearNavDragVisuals();
|
|
7492
|
+
requestAnimationFrame(() => {
|
|
7493
|
+
if (editContentRef.current[NAV_ORDER_KEY] === planned.orderJson) {
|
|
7494
|
+
applyNavForest(planned.forest);
|
|
7495
|
+
}
|
|
7496
|
+
applySelectionAfterDrop();
|
|
7497
|
+
requestAnimationFrame(applySelectionAfterDrop);
|
|
7498
|
+
});
|
|
7499
|
+
return;
|
|
7500
|
+
}
|
|
7501
|
+
applySelectionAfterDrop();
|
|
7502
|
+
clearNavDragVisuals();
|
|
7503
|
+
},
|
|
7504
|
+
[clearNavDragVisuals, deselectRef, editContentRef, postToParentRef, selectRef]
|
|
7505
|
+
);
|
|
7506
|
+
commitNavDragRef.current = commitNavDrag;
|
|
7507
|
+
const startNavLinkDrag = useCallback4(
|
|
7508
|
+
(anchor, clientX, clientY, wasSelected) => {
|
|
7509
|
+
if (footerDragRef.current) return false;
|
|
7510
|
+
const hrefKey = anchor.getAttribute("data-ohw-href-key");
|
|
7511
|
+
if (!hrefKey || !isNavbarHrefKey(hrefKey)) return false;
|
|
7512
|
+
if (isNavbarButton3(anchor) || isDragHandleDisabled2(anchor)) return false;
|
|
7513
|
+
beginNavDrag({
|
|
7514
|
+
hrefKey,
|
|
7515
|
+
wasSelected,
|
|
7516
|
+
draggedEl: anchor,
|
|
7517
|
+
lastClientX: clientX,
|
|
7518
|
+
lastClientY: clientY,
|
|
7519
|
+
activeSlot: null
|
|
7520
|
+
});
|
|
7521
|
+
return true;
|
|
7522
|
+
},
|
|
7523
|
+
[beginNavDrag, footerDragRef, isDragHandleDisabled2, isNavbarButton3]
|
|
7524
|
+
);
|
|
7525
|
+
const onNavDragOver = useCallback4(
|
|
7526
|
+
(e) => {
|
|
7527
|
+
const session = navDragRef.current;
|
|
7528
|
+
if (!session) return false;
|
|
7529
|
+
e.preventDefault();
|
|
7530
|
+
if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
|
|
7531
|
+
const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey);
|
|
7532
|
+
refreshNavDragVisualsRef.current(session, slot, e.clientX, e.clientY);
|
|
7533
|
+
return true;
|
|
7534
|
+
},
|
|
7535
|
+
[]
|
|
7536
|
+
);
|
|
7537
|
+
useEffect7(() => {
|
|
7538
|
+
if (!isEditMode) return;
|
|
7539
|
+
const THRESHOLD = 10;
|
|
7540
|
+
const resolveWasSelected = (el) => {
|
|
7541
|
+
if (selectedElRef.current === el) return true;
|
|
7542
|
+
const activeAnchor = activeElRef.current ? getNavigationItemAnchor2(activeElRef.current) : null;
|
|
7543
|
+
return activeAnchor === el;
|
|
7544
|
+
};
|
|
7545
|
+
const onPointerDown = (e) => {
|
|
7546
|
+
if (e.button !== 0) return;
|
|
7547
|
+
if (navDragRef.current || footerDragRef.current) return;
|
|
7548
|
+
const target = e.target;
|
|
7549
|
+
if (!target) return;
|
|
7550
|
+
if (target.closest(
|
|
7551
|
+
'[data-ohw-drag-handle-container], [data-slot="drag-handle"], [data-ohw-toolbar], [data-ohw-item-toolbar-anchor], [data-ohw-link-popover-root]'
|
|
7552
|
+
)) {
|
|
7553
|
+
return;
|
|
7554
|
+
}
|
|
7555
|
+
if (target.closest("[data-ohw-item-drag-surface]")) return;
|
|
7556
|
+
const anchor = getNavigationItemAnchor2(target);
|
|
7557
|
+
const hrefKey = anchor?.getAttribute("data-ohw-href-key") ?? null;
|
|
7558
|
+
if (!anchor || !isNavbarHrefKey(hrefKey)) return;
|
|
7559
|
+
if (isNavbarButton3(anchor) || isDragHandleDisabled2(anchor)) return;
|
|
7560
|
+
navPointerDragRef.current = {
|
|
7561
|
+
el: anchor,
|
|
7562
|
+
startX: e.clientX,
|
|
7563
|
+
startY: e.clientY,
|
|
7564
|
+
pointerId: e.pointerId,
|
|
7565
|
+
wasSelected: resolveWasSelected(anchor),
|
|
7566
|
+
started: false
|
|
7567
|
+
};
|
|
7568
|
+
};
|
|
7569
|
+
const onPointerMove = (e) => {
|
|
7570
|
+
const pending = navPointerDragRef.current;
|
|
7571
|
+
if (!pending) return;
|
|
7572
|
+
if (pending.started) {
|
|
7573
|
+
e.preventDefault();
|
|
7574
|
+
clearTextSelection();
|
|
7575
|
+
const session = navDragRef.current;
|
|
7576
|
+
if (!session) return;
|
|
7577
|
+
const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey);
|
|
7578
|
+
refreshNavDragVisualsRef.current(session, slot, e.clientX, e.clientY);
|
|
7579
|
+
return;
|
|
7580
|
+
}
|
|
7581
|
+
const dx = e.clientX - pending.startX;
|
|
7582
|
+
const dy = e.clientY - pending.startY;
|
|
7583
|
+
if (dx * dx + dy * dy < THRESHOLD * THRESHOLD) return;
|
|
7584
|
+
e.preventDefault();
|
|
7585
|
+
pending.started = true;
|
|
7586
|
+
armItemPressDrag();
|
|
7587
|
+
clearTextSelection();
|
|
7588
|
+
try {
|
|
7589
|
+
document.body.setPointerCapture(pending.pointerId);
|
|
7590
|
+
} catch {
|
|
7591
|
+
}
|
|
7592
|
+
if (linkPopoverOpenRef.current) setLinkPopover(null);
|
|
7593
|
+
if (activeElRef.current) deactivateRef.current();
|
|
7594
|
+
const key = pending.el.getAttribute("data-ohw-href-key");
|
|
7595
|
+
if (!key) return;
|
|
7596
|
+
beginNavDragRef.current({
|
|
7597
|
+
hrefKey: key,
|
|
7598
|
+
wasSelected: pending.wasSelected,
|
|
7599
|
+
draggedEl: pending.el,
|
|
7600
|
+
lastClientX: e.clientX,
|
|
7601
|
+
lastClientY: e.clientY,
|
|
7602
|
+
activeSlot: null
|
|
7603
|
+
});
|
|
7604
|
+
};
|
|
7605
|
+
const endPointerDrag = (e) => {
|
|
7606
|
+
const pending = navPointerDragRef.current;
|
|
7607
|
+
navPointerDragRef.current = null;
|
|
7608
|
+
try {
|
|
7609
|
+
if (document.body.hasPointerCapture(e.pointerId)) {
|
|
7610
|
+
document.body.releasePointerCapture(e.pointerId);
|
|
7611
|
+
}
|
|
7612
|
+
} catch {
|
|
7613
|
+
}
|
|
7614
|
+
if (!pending) return;
|
|
7615
|
+
if (!pending.started) {
|
|
7616
|
+
unlockItemDragInteraction();
|
|
7617
|
+
return;
|
|
7618
|
+
}
|
|
7619
|
+
suppressNextClickRef.current = true;
|
|
7620
|
+
suppressClickUntilRef.current = Date.now() + 500;
|
|
7621
|
+
commitNavDragRef.current(e.clientX, e.clientY);
|
|
7622
|
+
};
|
|
7623
|
+
const blockSelectStart = (e) => {
|
|
7624
|
+
if (navDragRef.current || navPointerDragRef.current?.started || document.documentElement.hasAttribute("data-ohw-footer-press-drag")) {
|
|
7625
|
+
e.preventDefault();
|
|
7626
|
+
}
|
|
7627
|
+
};
|
|
7628
|
+
const onDragEnd = () => {
|
|
7629
|
+
if (!navDragRef.current) return;
|
|
7630
|
+
suppressNextClickRef.current = true;
|
|
7631
|
+
suppressClickUntilRef.current = Date.now() + 500;
|
|
7632
|
+
commitNavDragRef.current();
|
|
7633
|
+
};
|
|
7634
|
+
document.addEventListener("pointerdown", onPointerDown, true);
|
|
7635
|
+
document.addEventListener("pointermove", onPointerMove, true);
|
|
7636
|
+
document.addEventListener("pointerup", endPointerDrag, true);
|
|
7637
|
+
document.addEventListener("pointercancel", endPointerDrag, true);
|
|
7638
|
+
document.addEventListener("selectstart", blockSelectStart, true);
|
|
7639
|
+
document.addEventListener("dragend", onDragEnd, true);
|
|
7640
|
+
return () => {
|
|
7641
|
+
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
7642
|
+
document.removeEventListener("pointermove", onPointerMove, true);
|
|
7643
|
+
document.removeEventListener("pointerup", endPointerDrag, true);
|
|
7644
|
+
document.removeEventListener("pointercancel", endPointerDrag, true);
|
|
7645
|
+
document.removeEventListener("selectstart", blockSelectStart, true);
|
|
7646
|
+
document.removeEventListener("dragend", onDragEnd, true);
|
|
7647
|
+
unlockItemDragInteraction();
|
|
7648
|
+
};
|
|
7649
|
+
}, [
|
|
7650
|
+
activeElRef,
|
|
7651
|
+
deactivateRef,
|
|
7652
|
+
footerDragRef,
|
|
7653
|
+
getNavigationItemAnchor2,
|
|
7654
|
+
isDragHandleDisabled2,
|
|
7655
|
+
isEditMode,
|
|
7656
|
+
isNavbarButton3,
|
|
7657
|
+
linkPopoverOpenRef,
|
|
7658
|
+
selectedElRef,
|
|
7659
|
+
setLinkPopover,
|
|
7660
|
+
suppressNextClickRef
|
|
7661
|
+
]);
|
|
7662
|
+
const armNavPressFromChrome = useCallback4(
|
|
7663
|
+
(selected, clientX, clientY, pointerId) => {
|
|
7664
|
+
const hrefKey = selected.getAttribute("data-ohw-href-key");
|
|
7665
|
+
if (!hrefKey || !isNavbarHrefKey(hrefKey)) return false;
|
|
7666
|
+
if (isNavbarButton3(selected) || isDragHandleDisabled2(selected)) return false;
|
|
7667
|
+
navPointerDragRef.current = {
|
|
7668
|
+
el: selected,
|
|
7669
|
+
startX: clientX,
|
|
7670
|
+
startY: clientY,
|
|
7671
|
+
pointerId,
|
|
7672
|
+
wasSelected: true,
|
|
7673
|
+
started: false
|
|
7674
|
+
};
|
|
7675
|
+
return true;
|
|
7676
|
+
},
|
|
7677
|
+
[isDragHandleDisabled2, isNavbarButton3]
|
|
7678
|
+
);
|
|
7679
|
+
return {
|
|
7680
|
+
navDragRef,
|
|
7681
|
+
navDropSlots,
|
|
7682
|
+
activeNavDropIndex,
|
|
7683
|
+
startNavLinkDrag,
|
|
7684
|
+
commitNavDrag,
|
|
7685
|
+
onNavDragOver,
|
|
7686
|
+
armNavPressFromChrome,
|
|
7687
|
+
clearNavDragVisuals,
|
|
7688
|
+
refreshNavDragVisualsRef
|
|
7689
|
+
};
|
|
7690
|
+
}
|
|
7691
|
+
|
|
7692
|
+
// src/ui/navbar-container-chrome.tsx
|
|
7693
|
+
import { Plus as Plus2 } from "lucide-react";
|
|
7694
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
7695
|
+
function NavbarContainerChrome({
|
|
7696
|
+
rect,
|
|
7697
|
+
onAdd
|
|
7698
|
+
}) {
|
|
7699
|
+
const chromeGap = 6;
|
|
7700
|
+
return /* @__PURE__ */ jsx21(
|
|
7701
|
+
"div",
|
|
7702
|
+
{
|
|
7703
|
+
"data-ohw-navbar-container-chrome": "",
|
|
7704
|
+
"data-ohw-bridge": "",
|
|
7705
|
+
className: "pointer-events-none fixed z-[2147483647]",
|
|
7706
|
+
style: {
|
|
7707
|
+
top: rect.top - chromeGap,
|
|
7708
|
+
left: rect.left - chromeGap,
|
|
7709
|
+
width: rect.width + chromeGap * 2,
|
|
7710
|
+
height: rect.height + chromeGap * 2
|
|
7711
|
+
},
|
|
7712
|
+
children: /* @__PURE__ */ jsx21(
|
|
7713
|
+
"button",
|
|
7714
|
+
{
|
|
7715
|
+
type: "button",
|
|
7716
|
+
"data-ohw-navbar-add-button": "",
|
|
7717
|
+
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",
|
|
7718
|
+
style: { top: "70%" },
|
|
7719
|
+
"aria-label": "Add item",
|
|
7720
|
+
onMouseDown: (e) => {
|
|
7721
|
+
e.preventDefault();
|
|
7722
|
+
e.stopPropagation();
|
|
7723
|
+
},
|
|
7724
|
+
onClick: (e) => {
|
|
7725
|
+
e.preventDefault();
|
|
7726
|
+
e.stopPropagation();
|
|
7727
|
+
onAdd();
|
|
7728
|
+
},
|
|
7729
|
+
children: /* @__PURE__ */ jsx21(Plus2, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
|
|
7730
|
+
}
|
|
7731
|
+
)
|
|
7732
|
+
}
|
|
7733
|
+
);
|
|
7734
|
+
}
|
|
7735
|
+
|
|
7736
|
+
// src/ui/drop-indicator.tsx
|
|
7737
|
+
import * as React10 from "react";
|
|
7738
|
+
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
7739
|
+
var dropIndicatorVariants = cva(
|
|
7740
|
+
"ov-gap-line pointer-events-none shrink-0 transition-opacity duration-150",
|
|
7741
|
+
{
|
|
7742
|
+
variants: {
|
|
7743
|
+
direction: {
|
|
7744
|
+
vertical: "h-6 w-[3px]",
|
|
7745
|
+
horizontal: "h-[3px] w-[200px]"
|
|
7746
|
+
},
|
|
7747
|
+
state: {
|
|
7748
|
+
default: "opacity-0",
|
|
7749
|
+
hover: "opacity-100",
|
|
7750
|
+
dragIdle: "opacity-40",
|
|
7751
|
+
dragActive: "opacity-100"
|
|
7752
|
+
}
|
|
7753
|
+
},
|
|
7754
|
+
defaultVariants: {
|
|
7755
|
+
direction: "vertical",
|
|
7756
|
+
state: "default"
|
|
7757
|
+
}
|
|
7758
|
+
}
|
|
7759
|
+
);
|
|
7760
|
+
var DropIndicator = React10.forwardRef(
|
|
7761
|
+
({ className, direction, state, ...props }, ref) => {
|
|
7762
|
+
return /* @__PURE__ */ jsx22(
|
|
7763
|
+
"div",
|
|
7764
|
+
{
|
|
7765
|
+
ref,
|
|
7766
|
+
"data-slot": "drop-indicator",
|
|
7767
|
+
"data-direction": direction ?? "vertical",
|
|
7768
|
+
"data-state": state ?? "default",
|
|
7769
|
+
"aria-hidden": "true",
|
|
7770
|
+
className: cn(dropIndicatorVariants({ direction, state }), className),
|
|
7771
|
+
...props
|
|
7772
|
+
}
|
|
7773
|
+
);
|
|
7774
|
+
}
|
|
7775
|
+
);
|
|
7776
|
+
DropIndicator.displayName = "DropIndicator";
|
|
7777
|
+
|
|
7778
|
+
// src/ui/badge.tsx
|
|
7779
|
+
import { jsx as jsx23 } from "react/jsx-runtime";
|
|
7780
|
+
var badgeVariants = cva(
|
|
7781
|
+
"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",
|
|
7782
|
+
{
|
|
7783
|
+
variants: {
|
|
7784
|
+
variant: {
|
|
7785
|
+
default: "border-transparent bg-primary text-primary-foreground",
|
|
7786
|
+
secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
7787
|
+
destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
|
7788
|
+
outline: "text-foreground"
|
|
7789
|
+
}
|
|
7790
|
+
},
|
|
7791
|
+
defaultVariants: {
|
|
7792
|
+
variant: "default"
|
|
7793
|
+
}
|
|
7794
|
+
}
|
|
7795
|
+
);
|
|
7796
|
+
function Badge({ className, variant, ...props }) {
|
|
7797
|
+
return /* @__PURE__ */ jsx23("div", { className: cn(badgeVariants({ variant }), className), ...props });
|
|
7798
|
+
}
|
|
7799
|
+
|
|
7800
|
+
// src/OhhwellsBridge.tsx
|
|
7801
|
+
import { Link as Link2 } from "lucide-react";
|
|
7802
|
+
import { Fragment as Fragment5, jsx as jsx24, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
7803
|
+
var PRIMARY2 = "#0885FE";
|
|
7804
|
+
var IMAGE_FADE_MS = 300;
|
|
7805
|
+
function runOpacityFade(el, onDone) {
|
|
7806
|
+
const anim = el.animate([{ opacity: 0 }, { opacity: 1 }], {
|
|
7807
|
+
duration: IMAGE_FADE_MS,
|
|
7808
|
+
easing: "ease",
|
|
7809
|
+
fill: "forwards"
|
|
7810
|
+
});
|
|
7811
|
+
let finished = false;
|
|
7812
|
+
const finish = () => {
|
|
7813
|
+
if (finished) return;
|
|
7814
|
+
finished = true;
|
|
7815
|
+
anim.cancel();
|
|
7816
|
+
el.style.opacity = "";
|
|
7817
|
+
onDone();
|
|
7818
|
+
};
|
|
7819
|
+
anim.finished.then(finish).catch(finish);
|
|
7820
|
+
window.setTimeout(finish, IMAGE_FADE_MS + 100);
|
|
7821
|
+
}
|
|
7822
|
+
function fadeInImageElement(img, onReady) {
|
|
7823
|
+
onReady();
|
|
7824
|
+
img.style.opacity = "0";
|
|
7825
|
+
runOpacityFade(img, () => {
|
|
7826
|
+
img.style.opacity = "";
|
|
7827
|
+
});
|
|
7828
|
+
}
|
|
7829
|
+
function applyEditableImageSrc(img, url) {
|
|
7830
|
+
img.removeAttribute("srcset");
|
|
7831
|
+
img.removeAttribute("sizes");
|
|
7832
|
+
img.src = url;
|
|
7833
|
+
}
|
|
7834
|
+
function fadeInBgImage(el, url, onReady) {
|
|
7835
|
+
const prevPos = el.style.position;
|
|
7836
|
+
if (!prevPos || prevPos === "static") el.style.position = "relative";
|
|
7837
|
+
const layer = document.createElement("div");
|
|
7838
|
+
layer.setAttribute("data-ohw-bg-fade-layer", "");
|
|
7839
|
+
Object.assign(layer.style, {
|
|
6552
7840
|
position: "absolute",
|
|
6553
7841
|
inset: "0",
|
|
6554
7842
|
zIndex: "0",
|
|
@@ -6690,7 +7978,7 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
6690
7978
|
const root = createRoot(container);
|
|
6691
7979
|
flushSync(() => {
|
|
6692
7980
|
root.render(
|
|
6693
|
-
/* @__PURE__ */
|
|
7981
|
+
/* @__PURE__ */ jsx24(
|
|
6694
7982
|
SchedulingWidget,
|
|
6695
7983
|
{
|
|
6696
7984
|
notifyOnConnect,
|
|
@@ -6752,7 +8040,20 @@ function isDragHandleDisabled(el) {
|
|
|
6752
8040
|
return raw === "true" || raw === "";
|
|
6753
8041
|
});
|
|
6754
8042
|
}
|
|
6755
|
-
function
|
|
8043
|
+
function canDragNavigationItem(anchor) {
|
|
8044
|
+
const { key, disabled } = getNavigationItemReorderState(anchor);
|
|
8045
|
+
return Boolean(key) && !disabled;
|
|
8046
|
+
}
|
|
8047
|
+
function syncNavigationDragCursorAttrs() {
|
|
8048
|
+
document.querySelectorAll("nav [data-ohw-href-key], footer [data-ohw-href-key]").forEach((el) => {
|
|
8049
|
+
if (!isNavigationItem(el) || !canDragNavigationItem(el)) {
|
|
8050
|
+
el.removeAttribute("data-ohw-can-drag");
|
|
8051
|
+
return;
|
|
8052
|
+
}
|
|
8053
|
+
el.setAttribute("data-ohw-can-drag", "");
|
|
8054
|
+
});
|
|
8055
|
+
}
|
|
8056
|
+
function collectEditableNodes(extraContent) {
|
|
6756
8057
|
const nodes = Array.from(document.querySelectorAll("[data-ohw-editable]")).map((el) => {
|
|
6757
8058
|
if (el.dataset.ohwEditable === "image") {
|
|
6758
8059
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
@@ -6780,6 +8081,14 @@ function collectEditableNodes() {
|
|
|
6780
8081
|
if (!key) return;
|
|
6781
8082
|
nodes.push({ key, type: "link", text: getLinkHref2(el) });
|
|
6782
8083
|
});
|
|
8084
|
+
if (extraContent) {
|
|
8085
|
+
for (const key of [NAV_ORDER_KEY, FOOTER_ORDER_KEY, NAV_COUNT_KEY]) {
|
|
8086
|
+
const text = extraContent[key];
|
|
8087
|
+
if (typeof text === "string" && text.length > 0) {
|
|
8088
|
+
nodes.push({ key, type: "meta", text });
|
|
8089
|
+
}
|
|
8090
|
+
}
|
|
8091
|
+
}
|
|
6783
8092
|
document.querySelectorAll('[data-ohw-editable="video"]').forEach((el) => {
|
|
6784
8093
|
const key = el.dataset.ohwKey ?? "";
|
|
6785
8094
|
const video = getVideoEl(el);
|
|
@@ -6893,6 +8202,11 @@ function getNavigationItemAnchor(el) {
|
|
|
6893
8202
|
function isNavigationItem(el) {
|
|
6894
8203
|
return getNavigationItemAnchor(el) !== null;
|
|
6895
8204
|
}
|
|
8205
|
+
function listNavigationItems() {
|
|
8206
|
+
return Array.from(
|
|
8207
|
+
document.querySelectorAll("nav [data-ohw-href-key], footer [data-ohw-href-key]")
|
|
8208
|
+
).filter((el) => isNavigationItem(el));
|
|
8209
|
+
}
|
|
6896
8210
|
function getNavigationItemReorderState(anchor) {
|
|
6897
8211
|
if (isNavbarButton2(anchor)) return { key: null, disabled: false };
|
|
6898
8212
|
return getReorderHandleStateFromAnchor(anchor);
|
|
@@ -6921,18 +8235,20 @@ function getNavigationRoot(el) {
|
|
|
6921
8235
|
if (explicit) return explicit;
|
|
6922
8236
|
return el.closest("nav, footer, aside");
|
|
6923
8237
|
}
|
|
8238
|
+
function countFooterNavItems(el) {
|
|
8239
|
+
return Array.from(el.querySelectorAll("[data-ohw-href-key]")).filter(isNavigationItem).length;
|
|
8240
|
+
}
|
|
6924
8241
|
function findFooterItemGroup(item) {
|
|
8242
|
+
const explicit = item.closest("[data-ohw-footer-col], [data-ohw-footer-column]");
|
|
8243
|
+
if (explicit) return explicit;
|
|
6925
8244
|
const footer = item.closest("footer");
|
|
6926
8245
|
if (!footer) return null;
|
|
6927
8246
|
let node = item.parentElement;
|
|
6928
8247
|
while (node && node !== footer) {
|
|
6929
|
-
|
|
6930
|
-
node.querySelectorAll(":scope > [data-ohw-href-key]")
|
|
6931
|
-
).some(isNavigationItem);
|
|
6932
|
-
if (hasDirectNavItems) return node;
|
|
8248
|
+
if (countFooterNavItems(node) >= 2) return node;
|
|
6933
8249
|
node = node.parentElement;
|
|
6934
8250
|
}
|
|
6935
|
-
return
|
|
8251
|
+
return footer;
|
|
6936
8252
|
}
|
|
6937
8253
|
function isNavigationRoot(el) {
|
|
6938
8254
|
return el.hasAttribute("data-ohw-nav-root") || el.matches("nav, footer, aside");
|
|
@@ -6940,16 +8256,49 @@ function isNavigationRoot(el) {
|
|
|
6940
8256
|
function isInferredFooterGroup(el) {
|
|
6941
8257
|
const footer = el.closest("footer");
|
|
6942
8258
|
if (!footer || el === footer) return false;
|
|
6943
|
-
|
|
8259
|
+
if (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column")) return true;
|
|
8260
|
+
return countFooterNavItems(el) >= 2;
|
|
6944
8261
|
}
|
|
6945
8262
|
function isNavigationContainer(el) {
|
|
6946
|
-
return el.hasAttribute("data-ohw-nav-container") || isNavigationRoot(el) || isInferredFooterGroup(el);
|
|
8263
|
+
return el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isNavigationRoot(el) || isInferredFooterGroup(el);
|
|
8264
|
+
}
|
|
8265
|
+
function isNavbarLinksContainer(el) {
|
|
8266
|
+
return el.hasAttribute("data-ohw-nav-container");
|
|
8267
|
+
}
|
|
8268
|
+
function getFooterColumn(el) {
|
|
8269
|
+
return el.closest("[data-ohw-footer-col], [data-ohw-footer-column]");
|
|
8270
|
+
}
|
|
8271
|
+
function resolveFooterColumnSelectionTarget(target, clientX, clientY) {
|
|
8272
|
+
if (getNavigationItemAnchor(target)) return null;
|
|
8273
|
+
const column = getFooterColumn(target);
|
|
8274
|
+
if (!column) return null;
|
|
8275
|
+
if (isPointOverNavItem(column, clientX, clientY)) return null;
|
|
8276
|
+
return column;
|
|
6947
8277
|
}
|
|
6948
8278
|
function isPointOverNavigation(x, y) {
|
|
8279
|
+
const roots = /* @__PURE__ */ new Set();
|
|
6949
8280
|
const navRoot = document.querySelector("[data-ohw-nav-root]") ?? document.querySelector("nav");
|
|
6950
|
-
if (
|
|
6951
|
-
const
|
|
6952
|
-
|
|
8281
|
+
if (navRoot) roots.add(navRoot);
|
|
8282
|
+
const footer = document.querySelector("footer");
|
|
8283
|
+
if (footer) roots.add(footer);
|
|
8284
|
+
for (const root of roots) {
|
|
8285
|
+
const r2 = root.getBoundingClientRect();
|
|
8286
|
+
if (x >= r2.left && x <= r2.right && y >= r2.top && y <= r2.bottom) return true;
|
|
8287
|
+
}
|
|
8288
|
+
return false;
|
|
8289
|
+
}
|
|
8290
|
+
function findHoveredNavOrFooterContainer(x, y) {
|
|
8291
|
+
const candidates = [
|
|
8292
|
+
...document.querySelectorAll("[data-ohw-nav-container]"),
|
|
8293
|
+
...listFooterColumns()
|
|
8294
|
+
];
|
|
8295
|
+
for (const container of candidates) {
|
|
8296
|
+
const r2 = container.getBoundingClientRect();
|
|
8297
|
+
if (x < r2.left || x > r2.right || y < r2.top || y > r2.bottom) continue;
|
|
8298
|
+
if (isPointOverNavItem(container, x, y)) continue;
|
|
8299
|
+
return container;
|
|
8300
|
+
}
|
|
8301
|
+
return null;
|
|
6953
8302
|
}
|
|
6954
8303
|
function isPointOverNavItem(container, x, y) {
|
|
6955
8304
|
return Array.from(container.querySelectorAll("[data-ohw-href-key]")).some((el) => {
|
|
@@ -6982,38 +8331,81 @@ function getNavigationSelectionParent(el) {
|
|
|
6982
8331
|
if (isNavigationItem(el)) {
|
|
6983
8332
|
const explicit = el.closest("[data-ohw-nav-container]");
|
|
6984
8333
|
if (explicit) return explicit;
|
|
8334
|
+
const footerColumn = getFooterColumn(el);
|
|
8335
|
+
if (footerColumn) return footerColumn;
|
|
6985
8336
|
const footerGroup = findFooterItemGroup(el);
|
|
6986
8337
|
if (footerGroup) return footerGroup;
|
|
6987
8338
|
return getNavigationRoot(el);
|
|
6988
8339
|
}
|
|
6989
|
-
if (el.hasAttribute("data-ohw-nav-container") || isInferredFooterGroup(el)) {
|
|
8340
|
+
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup(el)) {
|
|
6990
8341
|
return getNavigationRoot(el);
|
|
6991
8342
|
}
|
|
6992
8343
|
return null;
|
|
6993
8344
|
}
|
|
8345
|
+
function collectNavigationItemSiblingHintRects(selected) {
|
|
8346
|
+
if (!isNavigationItem(selected)) return [];
|
|
8347
|
+
const footerColumn = getFooterColumn(selected);
|
|
8348
|
+
if (footerColumn) {
|
|
8349
|
+
return listFooterLinksInColumn(footerColumn).filter((link) => link !== selected).map((link) => link.getBoundingClientRect());
|
|
8350
|
+
}
|
|
8351
|
+
const navContainer = selected.closest("[data-ohw-nav-container], [data-ohw-nav-drawer]");
|
|
8352
|
+
if (navContainer) {
|
|
8353
|
+
return Array.from(navContainer.querySelectorAll("[data-ohw-href-key]")).filter((el) => isNavigationItem(el) && el !== selected).map((el) => el.getBoundingClientRect());
|
|
8354
|
+
}
|
|
8355
|
+
return listNavigationItems().filter((el) => el !== selected).map((el) => el.getBoundingClientRect());
|
|
8356
|
+
}
|
|
6994
8357
|
function placeCaretAtPoint(el, x, y) {
|
|
6995
8358
|
const selection = window.getSelection();
|
|
6996
8359
|
if (!selection) return;
|
|
6997
|
-
|
|
6998
|
-
|
|
6999
|
-
|
|
7000
|
-
|
|
7001
|
-
|
|
7002
|
-
|
|
8360
|
+
const overlays = Array.from(
|
|
8361
|
+
document.querySelectorAll(
|
|
8362
|
+
"[data-ohw-item-drag-surface], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-ohw-item-toolbar-anchor]"
|
|
8363
|
+
)
|
|
8364
|
+
);
|
|
8365
|
+
const prevPointerEvents = overlays.map((node) => node.style.pointerEvents);
|
|
8366
|
+
for (const node of overlays) node.style.pointerEvents = "none";
|
|
8367
|
+
try {
|
|
8368
|
+
if (typeof document.caretRangeFromPoint === "function") {
|
|
8369
|
+
const range = document.caretRangeFromPoint(x, y);
|
|
8370
|
+
if (range && el.contains(range.startContainer)) {
|
|
8371
|
+
selection.removeAllRanges();
|
|
8372
|
+
selection.addRange(range);
|
|
8373
|
+
return;
|
|
8374
|
+
}
|
|
7003
8375
|
}
|
|
7004
|
-
|
|
7005
|
-
|
|
7006
|
-
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
8376
|
+
const caretPositionFromPoint = document.caretPositionFromPoint;
|
|
8377
|
+
if (typeof caretPositionFromPoint === "function") {
|
|
8378
|
+
const position = caretPositionFromPoint(x, y);
|
|
8379
|
+
if (position && el.contains(position.offsetNode)) {
|
|
8380
|
+
const range = document.createRange();
|
|
8381
|
+
range.setStart(position.offsetNode, position.offset);
|
|
8382
|
+
range.collapse(true);
|
|
8383
|
+
selection.removeAllRanges();
|
|
8384
|
+
selection.addRange(range);
|
|
8385
|
+
}
|
|
7014
8386
|
}
|
|
8387
|
+
} finally {
|
|
8388
|
+
overlays.forEach((node, i) => {
|
|
8389
|
+
node.style.pointerEvents = prevPointerEvents[i] ?? "";
|
|
8390
|
+
});
|
|
7015
8391
|
}
|
|
7016
8392
|
}
|
|
8393
|
+
function selectAllTextInEditable(el) {
|
|
8394
|
+
const selection = window.getSelection();
|
|
8395
|
+
if (!selection) return;
|
|
8396
|
+
const range = document.createRange();
|
|
8397
|
+
range.selectNodeContents(el);
|
|
8398
|
+
selection.removeAllRanges();
|
|
8399
|
+
selection.addRange(range);
|
|
8400
|
+
}
|
|
8401
|
+
function getNavigationLabelEditable(target) {
|
|
8402
|
+
const editable = target.closest('[data-ohw-editable="text"]');
|
|
8403
|
+
if (!editable) return null;
|
|
8404
|
+
const hrefCtx = getHrefKeyFromElement(editable);
|
|
8405
|
+
const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
|
|
8406
|
+
if (!navAnchor) return null;
|
|
8407
|
+
return { editable, navAnchor };
|
|
8408
|
+
}
|
|
7017
8409
|
function collectSections() {
|
|
7018
8410
|
return collectSectionsFromDom();
|
|
7019
8411
|
}
|
|
@@ -7137,6 +8529,9 @@ var ICONS = {
|
|
|
7137
8529
|
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"/>',
|
|
7138
8530
|
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"/>'
|
|
7139
8531
|
};
|
|
8532
|
+
var SELECTION_CHROME_GAP2 = 4;
|
|
8533
|
+
var TOOLBAR_STROKE_GAP2 = 4;
|
|
8534
|
+
var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
|
|
7140
8535
|
var TOOLBAR_GROUPS = [
|
|
7141
8536
|
[
|
|
7142
8537
|
{ cmd: "bold", title: "Bold" },
|
|
@@ -7158,9 +8553,10 @@ function EditGlowChrome({
|
|
|
7158
8553
|
rect,
|
|
7159
8554
|
elRef,
|
|
7160
8555
|
reorderHrefKey,
|
|
7161
|
-
dragDisabled = false
|
|
8556
|
+
dragDisabled = false,
|
|
8557
|
+
hideHandle = false
|
|
7162
8558
|
}) {
|
|
7163
|
-
const GAP =
|
|
8559
|
+
const GAP = SELECTION_CHROME_GAP2;
|
|
7164
8560
|
return /* @__PURE__ */ jsxs13(
|
|
7165
8561
|
"div",
|
|
7166
8562
|
{
|
|
@@ -7176,7 +8572,7 @@ function EditGlowChrome({
|
|
|
7176
8572
|
zIndex: 2147483646
|
|
7177
8573
|
},
|
|
7178
8574
|
children: [
|
|
7179
|
-
/* @__PURE__ */
|
|
8575
|
+
/* @__PURE__ */ jsx24(
|
|
7180
8576
|
"div",
|
|
7181
8577
|
{
|
|
7182
8578
|
style: {
|
|
@@ -7184,12 +8580,12 @@ function EditGlowChrome({
|
|
|
7184
8580
|
inset: 0,
|
|
7185
8581
|
border: "2px solid var(--ohw-primary, #0885FE)",
|
|
7186
8582
|
borderRadius: 8,
|
|
7187
|
-
boxShadow: "0 0 0 4px
|
|
8583
|
+
boxShadow: "0 0 0 4px color-mix(in srgb, var(--ohw-primary, #0885FE) 12%, transparent)",
|
|
7188
8584
|
pointerEvents: "none"
|
|
7189
8585
|
}
|
|
7190
8586
|
}
|
|
7191
8587
|
),
|
|
7192
|
-
reorderHrefKey && /* @__PURE__ */
|
|
8588
|
+
reorderHrefKey && !hideHandle && /* @__PURE__ */ jsx24(
|
|
7193
8589
|
"div",
|
|
7194
8590
|
{
|
|
7195
8591
|
"data-ohw-drag-handle-container": "",
|
|
@@ -7201,7 +8597,7 @@ function EditGlowChrome({
|
|
|
7201
8597
|
transform: "translate(calc(-100% - 7px), -50%)",
|
|
7202
8598
|
pointerEvents: dragDisabled ? "none" : "auto"
|
|
7203
8599
|
},
|
|
7204
|
-
children: /* @__PURE__ */
|
|
8600
|
+
children: /* @__PURE__ */ jsx24(
|
|
7205
8601
|
DragHandle,
|
|
7206
8602
|
{
|
|
7207
8603
|
"aria-label": `Reorder ${reorderHrefKey}`,
|
|
@@ -7232,6 +8628,7 @@ function applyVisibleViewport(el, parentScroll) {
|
|
|
7232
8628
|
el.style.top = `${top}px`;
|
|
7233
8629
|
el.style.height = `${height}px`;
|
|
7234
8630
|
}
|
|
8631
|
+
var TOOLBAR_EDGE_MARGIN2 = 4;
|
|
7235
8632
|
function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
|
|
7236
8633
|
const isAbove = transform.includes("translateY(-100%)");
|
|
7237
8634
|
let visualTop = isAbove ? top - approxH : top;
|
|
@@ -7255,10 +8652,16 @@ function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
|
|
|
7255
8652
|
const pinnedTop = Math.min(maxBottom - approxH, Math.max(minTop, clip.top + gap));
|
|
7256
8653
|
return { top: pinnedTop + approxH, transform: "translateX(-50%) translateY(-100%)" };
|
|
7257
8654
|
}
|
|
7258
|
-
function
|
|
7259
|
-
const
|
|
8655
|
+
function clampToolbarLeft(centerX, toolbarWidth) {
|
|
8656
|
+
const half = toolbarWidth / 2;
|
|
8657
|
+
return Math.max(
|
|
8658
|
+
TOOLBAR_EDGE_MARGIN2 + half,
|
|
8659
|
+
Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN2 - half)
|
|
8660
|
+
);
|
|
8661
|
+
}
|
|
8662
|
+
function calcToolbarPos(rect, parentScroll, toolbarW = 306) {
|
|
8663
|
+
const GAP = TOOLBAR_OFFSET_FROM_ELEMENT;
|
|
7260
8664
|
const APPROX_H = 32;
|
|
7261
|
-
const APPROX_W = approxW;
|
|
7262
8665
|
const clip = getIframeVisibleClip(parentScroll);
|
|
7263
8666
|
const clipTop = clip?.top ?? 0;
|
|
7264
8667
|
const canvasTopInIframe = parentScroll != null ? parentScroll.headerH - parentScroll.iframeOffsetTop : 0;
|
|
@@ -7288,7 +8691,7 @@ function calcToolbarPos(rect, parentScroll, approxW = 306) {
|
|
|
7288
8691
|
transform = clamped.transform;
|
|
7289
8692
|
}
|
|
7290
8693
|
const rawLeft = rect.left + rect.width / 2;
|
|
7291
|
-
const left =
|
|
8694
|
+
const left = clampToolbarLeft(rawLeft, toolbarW);
|
|
7292
8695
|
return { top, left, transform };
|
|
7293
8696
|
}
|
|
7294
8697
|
function resolveItemInteractionState(rect, parentScroll) {
|
|
@@ -7304,11 +8707,37 @@ function FloatingToolbar({
|
|
|
7304
8707
|
showEditLink,
|
|
7305
8708
|
onEditLink
|
|
7306
8709
|
}) {
|
|
7307
|
-
const
|
|
7308
|
-
|
|
8710
|
+
const localRef = React11.useRef(null);
|
|
8711
|
+
const [measuredW, setMeasuredW] = React11.useState(330);
|
|
8712
|
+
const setRefs = React11.useCallback(
|
|
8713
|
+
(node) => {
|
|
8714
|
+
localRef.current = node;
|
|
8715
|
+
if (typeof elRef === "function") elRef(node);
|
|
8716
|
+
else if (elRef) elRef.current = node;
|
|
8717
|
+
if (node) {
|
|
8718
|
+
const w = node.offsetWidth;
|
|
8719
|
+
if (w > 0) setMeasuredW(w);
|
|
8720
|
+
}
|
|
8721
|
+
},
|
|
8722
|
+
[elRef]
|
|
8723
|
+
);
|
|
8724
|
+
React11.useLayoutEffect(() => {
|
|
8725
|
+
const node = localRef.current;
|
|
8726
|
+
if (!node) return;
|
|
8727
|
+
const update = () => {
|
|
8728
|
+
const w = node.offsetWidth;
|
|
8729
|
+
if (w > 0) setMeasuredW(w);
|
|
8730
|
+
};
|
|
8731
|
+
update();
|
|
8732
|
+
const ro = new ResizeObserver(update);
|
|
8733
|
+
ro.observe(node);
|
|
8734
|
+
return () => ro.disconnect();
|
|
8735
|
+
}, [showEditLink, activeCommands]);
|
|
8736
|
+
const { top, left, transform } = calcToolbarPos(rect, parentScroll, measuredW);
|
|
8737
|
+
return /* @__PURE__ */ jsx24(
|
|
7309
8738
|
"div",
|
|
7310
8739
|
{
|
|
7311
|
-
ref:
|
|
8740
|
+
ref: setRefs,
|
|
7312
8741
|
style: {
|
|
7313
8742
|
position: "fixed",
|
|
7314
8743
|
top,
|
|
@@ -7318,11 +8747,11 @@ function FloatingToolbar({
|
|
|
7318
8747
|
pointerEvents: "auto"
|
|
7319
8748
|
},
|
|
7320
8749
|
children: /* @__PURE__ */ jsxs13(CustomToolbar, { children: [
|
|
7321
|
-
TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs13(
|
|
7322
|
-
gi > 0 && /* @__PURE__ */
|
|
8750
|
+
TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs13(React11.Fragment, { children: [
|
|
8751
|
+
gi > 0 && /* @__PURE__ */ jsx24(CustomToolbarDivider, {}),
|
|
7323
8752
|
btns.map((btn) => {
|
|
7324
8753
|
const isActive = activeCommands.has(btn.cmd);
|
|
7325
|
-
return /* @__PURE__ */
|
|
8754
|
+
return /* @__PURE__ */ jsx24(
|
|
7326
8755
|
CustomToolbarButton,
|
|
7327
8756
|
{
|
|
7328
8757
|
title: btn.title,
|
|
@@ -7331,7 +8760,7 @@ function FloatingToolbar({
|
|
|
7331
8760
|
e.preventDefault();
|
|
7332
8761
|
onCommand(btn.cmd);
|
|
7333
8762
|
},
|
|
7334
|
-
children: /* @__PURE__ */
|
|
8763
|
+
children: /* @__PURE__ */ jsx24(
|
|
7335
8764
|
"svg",
|
|
7336
8765
|
{
|
|
7337
8766
|
width: "16",
|
|
@@ -7352,7 +8781,7 @@ function FloatingToolbar({
|
|
|
7352
8781
|
);
|
|
7353
8782
|
})
|
|
7354
8783
|
] }, gi)),
|
|
7355
|
-
showEditLink ? /* @__PURE__ */
|
|
8784
|
+
showEditLink ? /* @__PURE__ */ jsx24(
|
|
7356
8785
|
CustomToolbarButton,
|
|
7357
8786
|
{
|
|
7358
8787
|
type: "button",
|
|
@@ -7366,7 +8795,7 @@ function FloatingToolbar({
|
|
|
7366
8795
|
e.preventDefault();
|
|
7367
8796
|
e.stopPropagation();
|
|
7368
8797
|
},
|
|
7369
|
-
children: /* @__PURE__ */
|
|
8798
|
+
children: /* @__PURE__ */ jsx24(Link2, { className: "size-4 shrink-0", "aria-hidden": true })
|
|
7370
8799
|
}
|
|
7371
8800
|
) : null
|
|
7372
8801
|
] })
|
|
@@ -7383,7 +8812,7 @@ function StateToggle({
|
|
|
7383
8812
|
states,
|
|
7384
8813
|
onStateChange
|
|
7385
8814
|
}) {
|
|
7386
|
-
return /* @__PURE__ */
|
|
8815
|
+
return /* @__PURE__ */ jsx24(
|
|
7387
8816
|
ToggleGroup,
|
|
7388
8817
|
{
|
|
7389
8818
|
"data-ohw-state-toggle": "",
|
|
@@ -7397,7 +8826,7 @@ function StateToggle({
|
|
|
7397
8826
|
left: rect.right - 8,
|
|
7398
8827
|
transform: "translateX(-100%)"
|
|
7399
8828
|
},
|
|
7400
|
-
children: states.map((state) => /* @__PURE__ */
|
|
8829
|
+
children: states.map((state) => /* @__PURE__ */ jsx24(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
|
|
7401
8830
|
}
|
|
7402
8831
|
);
|
|
7403
8832
|
}
|
|
@@ -7424,8 +8853,8 @@ function OhhwellsBridge() {
|
|
|
7424
8853
|
const router = useRouter2();
|
|
7425
8854
|
const searchParams = useSearchParams();
|
|
7426
8855
|
const isEditMode = isEditSessionActive();
|
|
7427
|
-
const [bridgeRoot, setBridgeRoot] =
|
|
7428
|
-
|
|
8856
|
+
const [bridgeRoot, setBridgeRoot] = useState7(null);
|
|
8857
|
+
useEffect8(() => {
|
|
7429
8858
|
const figtreeFontId = "ohw-figtree-font";
|
|
7430
8859
|
if (!document.getElementById(figtreeFontId)) {
|
|
7431
8860
|
const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
|
|
@@ -7453,91 +8882,137 @@ function OhhwellsBridge() {
|
|
|
7453
8882
|
const subdomainFromQuery = searchParams.get("subdomain");
|
|
7454
8883
|
const subdomain = resolveSubdomain(subdomainFromQuery);
|
|
7455
8884
|
useLinkHrefGuardian(pathname, subdomain, isEditMode);
|
|
7456
|
-
const postToParent2 =
|
|
8885
|
+
const postToParent2 = useCallback5((data) => {
|
|
7457
8886
|
if (typeof window !== "undefined" && window.parent !== window) {
|
|
7458
8887
|
window.parent.postMessage(data, "*");
|
|
7459
8888
|
}
|
|
7460
8889
|
}, []);
|
|
7461
|
-
const [fetchState, setFetchState] =
|
|
7462
|
-
const autoSaveTimers =
|
|
7463
|
-
const activeElRef =
|
|
7464
|
-
const
|
|
7465
|
-
const
|
|
7466
|
-
const
|
|
7467
|
-
const
|
|
7468
|
-
const
|
|
7469
|
-
const
|
|
7470
|
-
const
|
|
8890
|
+
const [fetchState, setFetchState] = useState7("idle");
|
|
8891
|
+
const autoSaveTimers = useRef7(/* @__PURE__ */ new Map());
|
|
8892
|
+
const activeElRef = useRef7(null);
|
|
8893
|
+
const pointerHeldRef = useRef7(false);
|
|
8894
|
+
const selectedElRef = useRef7(null);
|
|
8895
|
+
const selectedHrefKeyRef = useRef7(null);
|
|
8896
|
+
const selectedFooterColAttrRef = useRef7(null);
|
|
8897
|
+
const originalContentRef = useRef7(null);
|
|
8898
|
+
const activeStateElRef = useRef7(null);
|
|
8899
|
+
const parentScrollRef = useRef7(null);
|
|
8900
|
+
const visibleViewportRef = useRef7(null);
|
|
8901
|
+
const [dialogPortalContainer, setDialogPortalContainer] = useState7(null);
|
|
8902
|
+
const attachVisibleViewport = useCallback5((node) => {
|
|
7471
8903
|
visibleViewportRef.current = node;
|
|
7472
8904
|
setDialogPortalContainer(node);
|
|
7473
8905
|
if (node) applyVisibleViewport(node, parentScrollRef.current);
|
|
7474
8906
|
}, []);
|
|
7475
|
-
const toolbarElRef =
|
|
7476
|
-
const glowElRef =
|
|
7477
|
-
const hoveredImageRef =
|
|
7478
|
-
const hoveredImageHasTextOverlapRef =
|
|
7479
|
-
const dragOverElRef =
|
|
7480
|
-
const [mediaHover, setMediaHover] =
|
|
7481
|
-
const [uploadingRects, setUploadingRects] =
|
|
7482
|
-
const hoveredGapRef =
|
|
7483
|
-
const imageUnhoverTimerRef =
|
|
7484
|
-
const imageShowTimerRef =
|
|
7485
|
-
const editStylesRef =
|
|
7486
|
-
const activateRef =
|
|
8907
|
+
const toolbarElRef = useRef7(null);
|
|
8908
|
+
const glowElRef = useRef7(null);
|
|
8909
|
+
const hoveredImageRef = useRef7(null);
|
|
8910
|
+
const hoveredImageHasTextOverlapRef = useRef7(false);
|
|
8911
|
+
const dragOverElRef = useRef7(null);
|
|
8912
|
+
const [mediaHover, setMediaHover] = useState7(null);
|
|
8913
|
+
const [uploadingRects, setUploadingRects] = useState7({});
|
|
8914
|
+
const hoveredGapRef = useRef7(null);
|
|
8915
|
+
const imageUnhoverTimerRef = useRef7(null);
|
|
8916
|
+
const imageShowTimerRef = useRef7(null);
|
|
8917
|
+
const editStylesRef = useRef7(null);
|
|
8918
|
+
const activateRef = useRef7(() => {
|
|
7487
8919
|
});
|
|
7488
|
-
const deactivateRef =
|
|
8920
|
+
const deactivateRef = useRef7(() => {
|
|
7489
8921
|
});
|
|
7490
|
-
const selectRef =
|
|
8922
|
+
const selectRef = useRef7(() => {
|
|
7491
8923
|
});
|
|
7492
|
-
const selectFrameRef =
|
|
8924
|
+
const selectFrameRef = useRef7(() => {
|
|
7493
8925
|
});
|
|
7494
|
-
const deselectRef =
|
|
8926
|
+
const deselectRef = useRef7(() => {
|
|
7495
8927
|
});
|
|
7496
|
-
const reselectNavigationItemRef =
|
|
8928
|
+
const reselectNavigationItemRef = useRef7(() => {
|
|
7497
8929
|
});
|
|
7498
|
-
const commitNavigationTextEditRef =
|
|
8930
|
+
const commitNavigationTextEditRef = useRef7(() => {
|
|
7499
8931
|
});
|
|
7500
|
-
const refreshActiveCommandsRef =
|
|
8932
|
+
const refreshActiveCommandsRef = useRef7(() => {
|
|
7501
8933
|
});
|
|
7502
|
-
const postToParentRef =
|
|
8934
|
+
const postToParentRef = useRef7(postToParent2);
|
|
7503
8935
|
postToParentRef.current = postToParent2;
|
|
7504
|
-
const sectionsLoadedRef =
|
|
7505
|
-
const pendingScheduleConfigRequests =
|
|
7506
|
-
const [toolbarRect, setToolbarRect] =
|
|
7507
|
-
const [toolbarVariant, setToolbarVariant] =
|
|
7508
|
-
const toolbarVariantRef =
|
|
8936
|
+
const sectionsLoadedRef = useRef7(false);
|
|
8937
|
+
const pendingScheduleConfigRequests = useRef7([]);
|
|
8938
|
+
const [toolbarRect, setToolbarRect] = useState7(null);
|
|
8939
|
+
const [toolbarVariant, setToolbarVariant] = useState7("none");
|
|
8940
|
+
const toolbarVariantRef = useRef7("none");
|
|
7509
8941
|
toolbarVariantRef.current = toolbarVariant;
|
|
7510
|
-
const [
|
|
7511
|
-
const [
|
|
7512
|
-
const [
|
|
7513
|
-
const [
|
|
7514
|
-
const [
|
|
7515
|
-
const [
|
|
7516
|
-
const [
|
|
7517
|
-
const
|
|
7518
|
-
const
|
|
7519
|
-
const
|
|
7520
|
-
const
|
|
7521
|
-
const
|
|
7522
|
-
const
|
|
7523
|
-
const [
|
|
7524
|
-
const [
|
|
7525
|
-
const
|
|
7526
|
-
const
|
|
7527
|
-
const
|
|
7528
|
-
const [
|
|
7529
|
-
const [
|
|
7530
|
-
const
|
|
7531
|
-
const
|
|
7532
|
-
const
|
|
7533
|
-
const
|
|
7534
|
-
const
|
|
8942
|
+
const [selectedIsCta, setSelectedIsCta] = useState7(false);
|
|
8943
|
+
const [reorderHrefKey, setReorderHrefKey] = useState7(null);
|
|
8944
|
+
const [reorderDragDisabled, setReorderDragDisabled] = useState7(false);
|
|
8945
|
+
const [toggleState, setToggleState] = useState7(null);
|
|
8946
|
+
const [maxBadge, setMaxBadge] = useState7(null);
|
|
8947
|
+
const [activeCommands, setActiveCommands] = useState7(/* @__PURE__ */ new Set());
|
|
8948
|
+
const [sectionGap, setSectionGap] = useState7(null);
|
|
8949
|
+
const [toolbarShowEditLink, setToolbarShowEditLink] = useState7(false);
|
|
8950
|
+
const hoveredNavContainerRef = useRef7(null);
|
|
8951
|
+
const [hoveredNavContainerRect, setHoveredNavContainerRect] = useState7(null);
|
|
8952
|
+
const hoveredItemElRef = useRef7(null);
|
|
8953
|
+
const [hoveredItemRect, setHoveredItemRect] = useState7(null);
|
|
8954
|
+
const siblingHintElRef = useRef7(null);
|
|
8955
|
+
const [siblingHintRect, setSiblingHintRect] = useState7(null);
|
|
8956
|
+
const [siblingHintRects, setSiblingHintRects] = useState7([]);
|
|
8957
|
+
const [isItemDragging, setIsItemDragging] = useState7(false);
|
|
8958
|
+
const [isFooterFrameSelection, setIsFooterFrameSelection] = useState7(false);
|
|
8959
|
+
const footerDragRef = useRef7(null);
|
|
8960
|
+
const [footerDropSlots, setFooterDropSlots] = useState7([]);
|
|
8961
|
+
const [activeFooterDropIndex, setActiveFooterDropIndex] = useState7(null);
|
|
8962
|
+
const [draggedItemRect, setDraggedItemRect] = useState7(null);
|
|
8963
|
+
const footerPointerDragRef = useRef7(null);
|
|
8964
|
+
const suppressNextClickRef = useRef7(false);
|
|
8965
|
+
const suppressClickUntilRef = useRef7(0);
|
|
8966
|
+
const [linkPopover, setLinkPopover] = useState7(null);
|
|
8967
|
+
const linkPopoverSessionRef = useRef7(null);
|
|
8968
|
+
const addNavAfterAnchorRef = useRef7(null);
|
|
8969
|
+
const editContentRef = useRef7({});
|
|
8970
|
+
const [sitePages, setSitePages] = useState7([]);
|
|
8971
|
+
const [sectionsByPath, setSectionsByPath] = useState7({});
|
|
8972
|
+
const sectionsPrefetchGenRef = useRef7(0);
|
|
8973
|
+
const setLinkPopoverRef = useRef7(setLinkPopover);
|
|
8974
|
+
const linkPopoverPanelRef = useRef7(null);
|
|
8975
|
+
const linkPopoverOpenRef = useRef7(false);
|
|
8976
|
+
const linkPopoverGraceUntilRef = useRef7(0);
|
|
7535
8977
|
setLinkPopoverRef.current = setLinkPopover;
|
|
7536
8978
|
linkPopoverSessionRef.current = linkPopover;
|
|
8979
|
+
const {
|
|
8980
|
+
navDragRef,
|
|
8981
|
+
navDropSlots,
|
|
8982
|
+
activeNavDropIndex,
|
|
8983
|
+
startNavLinkDrag,
|
|
8984
|
+
commitNavDrag,
|
|
8985
|
+
onNavDragOver,
|
|
8986
|
+
armNavPressFromChrome,
|
|
8987
|
+
refreshNavDragVisualsRef
|
|
8988
|
+
} = useNavItemDrag({
|
|
8989
|
+
isEditMode,
|
|
8990
|
+
editContentRef,
|
|
8991
|
+
selectedElRef,
|
|
8992
|
+
activeElRef,
|
|
8993
|
+
footerDragRef,
|
|
8994
|
+
suppressNextClickRef,
|
|
8995
|
+
suppressClickUntilRef,
|
|
8996
|
+
siblingHintElRef,
|
|
8997
|
+
postToParentRef,
|
|
8998
|
+
deselectRef,
|
|
8999
|
+
selectRef,
|
|
9000
|
+
deactivateRef,
|
|
9001
|
+
setLinkPopover: () => setLinkPopover(null),
|
|
9002
|
+
linkPopoverOpenRef,
|
|
9003
|
+
setIsItemDragging,
|
|
9004
|
+
setDraggedItemRect,
|
|
9005
|
+
setSiblingHintRect,
|
|
9006
|
+
setSiblingHintRects,
|
|
9007
|
+
setToolbarRect,
|
|
9008
|
+
getNavigationItemAnchor,
|
|
9009
|
+
isDragHandleDisabled,
|
|
9010
|
+
isNavbarButton: isNavbarButton2
|
|
9011
|
+
});
|
|
7537
9012
|
const bumpLinkPopoverGrace = () => {
|
|
7538
9013
|
linkPopoverGraceUntilRef.current = Date.now() + 350;
|
|
7539
9014
|
};
|
|
7540
|
-
const runSectionsPrefetch =
|
|
9015
|
+
const runSectionsPrefetch = useCallback5((pages) => {
|
|
7541
9016
|
if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
|
|
7542
9017
|
const gen = ++sectionsPrefetchGenRef.current;
|
|
7543
9018
|
const paths = pages.map((p) => p.path);
|
|
@@ -7556,10 +9031,24 @@ function OhhwellsBridge() {
|
|
|
7556
9031
|
);
|
|
7557
9032
|
});
|
|
7558
9033
|
}, [isEditMode, pathname]);
|
|
7559
|
-
const runSectionsPrefetchRef =
|
|
9034
|
+
const runSectionsPrefetchRef = useRef7(runSectionsPrefetch);
|
|
7560
9035
|
runSectionsPrefetchRef.current = runSectionsPrefetch;
|
|
7561
|
-
|
|
7562
|
-
if (!linkPopover)
|
|
9036
|
+
useEffect8(() => {
|
|
9037
|
+
if (!linkPopover) {
|
|
9038
|
+
document.documentElement.removeAttribute("data-ohw-link-popover-open");
|
|
9039
|
+
return;
|
|
9040
|
+
}
|
|
9041
|
+
document.documentElement.setAttribute("data-ohw-link-popover-open", "");
|
|
9042
|
+
hoveredItemElRef.current = null;
|
|
9043
|
+
setHoveredItemRect(null);
|
|
9044
|
+
hoveredNavContainerRef.current = null;
|
|
9045
|
+
setHoveredNavContainerRect(null);
|
|
9046
|
+
siblingHintElRef.current = null;
|
|
9047
|
+
setSiblingHintRect(null);
|
|
9048
|
+
setSiblingHintRects([]);
|
|
9049
|
+
if (selectedElRef.current || toolbarVariantRef.current !== "none") {
|
|
9050
|
+
deselectRef.current();
|
|
9051
|
+
}
|
|
7563
9052
|
if (hoveredImageRef.current) {
|
|
7564
9053
|
hoveredImageRef.current = null;
|
|
7565
9054
|
hoveredImageHasTextOverlapRef.current = false;
|
|
@@ -7593,7 +9082,7 @@ function OhhwellsBridge() {
|
|
|
7593
9082
|
document.removeEventListener("touchmove", preventBackgroundScroll, scrollOpts);
|
|
7594
9083
|
};
|
|
7595
9084
|
}, [linkPopover, postToParent2]);
|
|
7596
|
-
|
|
9085
|
+
useEffect8(() => {
|
|
7597
9086
|
if (!isEditMode) return;
|
|
7598
9087
|
const useFixtures = shouldUseDevFixtures();
|
|
7599
9088
|
if (useFixtures) {
|
|
@@ -7617,14 +9106,14 @@ function OhhwellsBridge() {
|
|
|
7617
9106
|
if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
|
|
7618
9107
|
return () => window.removeEventListener("message", onSitePages);
|
|
7619
9108
|
}, [isEditMode, postToParent2]);
|
|
7620
|
-
|
|
9109
|
+
useEffect8(() => {
|
|
7621
9110
|
if (!isEditMode || shouldUseDevFixtures()) return;
|
|
7622
9111
|
void loadAllSectionsManifest().then((manifest) => {
|
|
7623
9112
|
if (Object.keys(manifest).length === 0) return;
|
|
7624
9113
|
setSectionsByPath((prev) => ({ ...manifest, ...prev }));
|
|
7625
9114
|
});
|
|
7626
9115
|
}, [isEditMode]);
|
|
7627
|
-
|
|
9116
|
+
useEffect8(() => {
|
|
7628
9117
|
const update = () => {
|
|
7629
9118
|
const el = activeElRef.current ?? selectedElRef.current;
|
|
7630
9119
|
if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
|
|
@@ -7648,10 +9137,10 @@ function OhhwellsBridge() {
|
|
|
7648
9137
|
vvp.removeEventListener("resize", update);
|
|
7649
9138
|
};
|
|
7650
9139
|
}, []);
|
|
7651
|
-
const refreshStateRules =
|
|
9140
|
+
const refreshStateRules = useCallback5(() => {
|
|
7652
9141
|
editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
|
|
7653
9142
|
}, []);
|
|
7654
|
-
const processConfigRequest =
|
|
9143
|
+
const processConfigRequest = useCallback5((insertAfterVal) => {
|
|
7655
9144
|
const tracker = getSectionsTracker();
|
|
7656
9145
|
let entries = [];
|
|
7657
9146
|
try {
|
|
@@ -7674,7 +9163,7 @@ function OhhwellsBridge() {
|
|
|
7674
9163
|
}
|
|
7675
9164
|
window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
|
|
7676
9165
|
}, [isEditMode]);
|
|
7677
|
-
const deactivate =
|
|
9166
|
+
const deactivate = useCallback5(() => {
|
|
7678
9167
|
const el = activeElRef.current;
|
|
7679
9168
|
if (!el) return;
|
|
7680
9169
|
const key = el.dataset.ohwKey;
|
|
@@ -7693,6 +9182,7 @@ function OhhwellsBridge() {
|
|
|
7693
9182
|
}
|
|
7694
9183
|
}
|
|
7695
9184
|
el.removeAttribute("contenteditable");
|
|
9185
|
+
el.removeAttribute("data-ohw-editing");
|
|
7696
9186
|
activeElRef.current = null;
|
|
7697
9187
|
setReorderHrefKey(null);
|
|
7698
9188
|
setReorderDragDisabled(false);
|
|
@@ -7705,12 +9195,23 @@ function OhhwellsBridge() {
|
|
|
7705
9195
|
setToolbarShowEditLink(false);
|
|
7706
9196
|
postToParent2({ type: "ow:exit-edit" });
|
|
7707
9197
|
}, [postToParent2]);
|
|
7708
|
-
const
|
|
9198
|
+
const clearSelectedAttr = useCallback5(() => {
|
|
9199
|
+
document.querySelectorAll("[data-ohw-selected]").forEach((el) => {
|
|
9200
|
+
el.removeAttribute("data-ohw-selected");
|
|
9201
|
+
});
|
|
9202
|
+
}, []);
|
|
9203
|
+
const deselect = useCallback5(() => {
|
|
9204
|
+
clearSelectedAttr();
|
|
7709
9205
|
selectedElRef.current = null;
|
|
9206
|
+
selectedHrefKeyRef.current = null;
|
|
9207
|
+
selectedFooterColAttrRef.current = null;
|
|
9208
|
+
setSelectedIsCta(false);
|
|
7710
9209
|
setReorderHrefKey(null);
|
|
7711
9210
|
setReorderDragDisabled(false);
|
|
9211
|
+
setIsFooterFrameSelection(false);
|
|
7712
9212
|
siblingHintElRef.current = null;
|
|
7713
9213
|
setSiblingHintRect(null);
|
|
9214
|
+
setSiblingHintRects([]);
|
|
7714
9215
|
setIsItemDragging(false);
|
|
7715
9216
|
hoveredNavContainerRef.current = null;
|
|
7716
9217
|
setHoveredNavContainerRect(null);
|
|
@@ -7718,18 +9219,70 @@ function OhhwellsBridge() {
|
|
|
7718
9219
|
setToolbarRect(null);
|
|
7719
9220
|
setToolbarVariant("none");
|
|
7720
9221
|
}
|
|
9222
|
+
}, [clearSelectedAttr]);
|
|
9223
|
+
const markSelected = useCallback5((el) => {
|
|
9224
|
+
clearSelectedAttr();
|
|
9225
|
+
el.setAttribute("data-ohw-selected", "");
|
|
9226
|
+
}, [clearSelectedAttr]);
|
|
9227
|
+
const resolveHrefKeyElement = useCallback5((hrefKey) => {
|
|
9228
|
+
if (isFooterHrefKey(hrefKey)) {
|
|
9229
|
+
return document.querySelector(
|
|
9230
|
+
`footer [data-ohw-href-key="${CSS.escape(hrefKey)}"]`
|
|
9231
|
+
);
|
|
9232
|
+
}
|
|
9233
|
+
if (isNavbarHrefKey(hrefKey)) {
|
|
9234
|
+
const desktop = document.querySelector("[data-ohw-nav-container]");
|
|
9235
|
+
const drawer = document.querySelector("[data-ohw-nav-drawer]");
|
|
9236
|
+
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)}"]`);
|
|
9237
|
+
}
|
|
9238
|
+
return document.querySelector(
|
|
9239
|
+
`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`
|
|
9240
|
+
);
|
|
7721
9241
|
}, []);
|
|
7722
|
-
const
|
|
9242
|
+
const resyncSelectedNavigationItem = useCallback5(() => {
|
|
9243
|
+
const hrefKey = selectedHrefKeyRef.current;
|
|
9244
|
+
if (hrefKey) {
|
|
9245
|
+
const link = resolveHrefKeyElement(hrefKey);
|
|
9246
|
+
if (!link || !isNavigationItem(link)) return;
|
|
9247
|
+
selectedElRef.current = link;
|
|
9248
|
+
const { key, disabled } = getNavigationItemReorderState(link);
|
|
9249
|
+
setReorderHrefKey(key);
|
|
9250
|
+
setReorderDragDisabled(disabled);
|
|
9251
|
+
setIsFooterFrameSelection(false);
|
|
9252
|
+
setToolbarVariant("link-action");
|
|
9253
|
+
setToolbarRect(link.getBoundingClientRect());
|
|
9254
|
+
setSiblingHintRects(collectNavigationItemSiblingHintRects(link));
|
|
9255
|
+
return;
|
|
9256
|
+
}
|
|
9257
|
+
const colAttr = selectedFooterColAttrRef.current;
|
|
9258
|
+
if (colAttr != null) {
|
|
9259
|
+
const column = document.querySelector(`[data-ohw-footer-col="${CSS.escape(colAttr)}"]`) ?? listFooterColumns()[Number(colAttr)] ?? null;
|
|
9260
|
+
if (!column || !isNavigationContainer(column)) return;
|
|
9261
|
+
selectedElRef.current = column;
|
|
9262
|
+
setIsFooterFrameSelection(true);
|
|
9263
|
+
setToolbarVariant("select-frame");
|
|
9264
|
+
setToolbarRect(column.getBoundingClientRect());
|
|
9265
|
+
setSiblingHintRects(
|
|
9266
|
+
listFooterColumns().filter((c) => c !== column).map((c) => c.getBoundingClientRect())
|
|
9267
|
+
);
|
|
9268
|
+
}
|
|
9269
|
+
}, [resolveHrefKeyElement]);
|
|
9270
|
+
const reselectNavigationItem = useCallback5((navAnchor) => {
|
|
7723
9271
|
selectedElRef.current = navAnchor;
|
|
9272
|
+
selectedHrefKeyRef.current = navAnchor.getAttribute("data-ohw-href-key");
|
|
9273
|
+
selectedFooterColAttrRef.current = null;
|
|
9274
|
+
markSelected(navAnchor);
|
|
9275
|
+
setSelectedIsCta(isNavbarButton2(navAnchor));
|
|
7724
9276
|
const { key, disabled } = getNavigationItemReorderState(navAnchor);
|
|
7725
9277
|
setReorderHrefKey(key);
|
|
7726
9278
|
setReorderDragDisabled(disabled);
|
|
7727
9279
|
setToolbarVariant("link-action");
|
|
7728
9280
|
setToolbarRect(navAnchor.getBoundingClientRect());
|
|
9281
|
+
setSiblingHintRects(collectNavigationItemSiblingHintRects(navAnchor));
|
|
7729
9282
|
setToolbarShowEditLink(false);
|
|
7730
9283
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
7731
|
-
}, []);
|
|
7732
|
-
const commitNavigationTextEdit =
|
|
9284
|
+
}, [markSelected]);
|
|
9285
|
+
const commitNavigationTextEdit = useCallback5((navAnchor) => {
|
|
7733
9286
|
const el = activeElRef.current;
|
|
7734
9287
|
if (!el) return;
|
|
7735
9288
|
const key = el.dataset.ohwKey;
|
|
@@ -7748,6 +9301,7 @@ function OhhwellsBridge() {
|
|
|
7748
9301
|
}
|
|
7749
9302
|
}
|
|
7750
9303
|
el.removeAttribute("contenteditable");
|
|
9304
|
+
el.removeAttribute("data-ohw-editing");
|
|
7751
9305
|
activeElRef.current = null;
|
|
7752
9306
|
setMaxBadge(null);
|
|
7753
9307
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
@@ -7755,7 +9309,7 @@ function OhhwellsBridge() {
|
|
|
7755
9309
|
postToParent2({ type: "ow:exit-edit" });
|
|
7756
9310
|
reselectNavigationItem(navAnchor);
|
|
7757
9311
|
}, [postToParent2, reselectNavigationItem]);
|
|
7758
|
-
const handleAddTopLevelNavItem =
|
|
9312
|
+
const handleAddTopLevelNavItem = useCallback5(() => {
|
|
7759
9313
|
const items = listNavbarItems();
|
|
7760
9314
|
addNavAfterAnchorRef.current = items[items.length - 1] ?? null;
|
|
7761
9315
|
deselectRef.current();
|
|
@@ -7767,20 +9321,321 @@ function OhhwellsBridge() {
|
|
|
7767
9321
|
intent: "add-nav"
|
|
7768
9322
|
});
|
|
7769
9323
|
}, []);
|
|
7770
|
-
const
|
|
7771
|
-
|
|
7772
|
-
|
|
7773
|
-
|
|
7774
|
-
|
|
7775
|
-
|
|
9324
|
+
const clearFooterDragVisuals = useCallback5(() => {
|
|
9325
|
+
footerDragRef.current = null;
|
|
9326
|
+
setSiblingHintRects([]);
|
|
9327
|
+
setFooterDropSlots([]);
|
|
9328
|
+
setActiveFooterDropIndex(null);
|
|
9329
|
+
setDraggedItemRect(null);
|
|
7776
9330
|
setIsItemDragging(false);
|
|
9331
|
+
unlockFooterDragInteraction();
|
|
9332
|
+
}, []);
|
|
9333
|
+
const refreshFooterDragVisuals = useCallback5((session, activeSlot, clientX, clientY) => {
|
|
9334
|
+
const dragged = session.draggedEl;
|
|
9335
|
+
setDraggedItemRect(dragged.getBoundingClientRect());
|
|
9336
|
+
if (typeof clientX === "number" && typeof clientY === "number") {
|
|
9337
|
+
session.lastClientX = clientX;
|
|
9338
|
+
session.lastClientY = clientY;
|
|
9339
|
+
}
|
|
9340
|
+
session.activeSlot = activeSlot;
|
|
9341
|
+
if (session.kind === "link") {
|
|
9342
|
+
const columns2 = listFooterColumns();
|
|
9343
|
+
const focusCols = /* @__PURE__ */ new Set([session.sourceColumnIndex]);
|
|
9344
|
+
if (activeSlot) focusCols.add(activeSlot.columnIndex);
|
|
9345
|
+
const siblingRects = [];
|
|
9346
|
+
columns2.forEach((col, i) => {
|
|
9347
|
+
if (!focusCols.has(i)) return;
|
|
9348
|
+
for (const link of listFooterLinksInColumn(col)) {
|
|
9349
|
+
if (link === dragged) continue;
|
|
9350
|
+
siblingRects.push(link.getBoundingClientRect());
|
|
9351
|
+
}
|
|
9352
|
+
});
|
|
9353
|
+
setSiblingHintRects(siblingRects);
|
|
9354
|
+
const slots2 = [];
|
|
9355
|
+
columns2.forEach((col, i) => {
|
|
9356
|
+
slots2.push(...buildLinkDropSlots(col, i));
|
|
9357
|
+
});
|
|
9358
|
+
setFooterDropSlots(slots2);
|
|
9359
|
+
const activeIdx2 = activeSlot ? slots2.findIndex((s) => s.columnIndex === activeSlot.columnIndex && s.insertIndex === activeSlot.insertIndex) : -1;
|
|
9360
|
+
setActiveFooterDropIndex(activeIdx2 >= 0 ? activeIdx2 : null);
|
|
9361
|
+
return;
|
|
9362
|
+
}
|
|
9363
|
+
const columns = listFooterColumns();
|
|
9364
|
+
setSiblingHintRects(columns.filter((col) => col !== dragged).map((col) => col.getBoundingClientRect()));
|
|
9365
|
+
const slots = buildColumnDropSlots();
|
|
9366
|
+
setFooterDropSlots(slots);
|
|
9367
|
+
const activeIdx = activeSlot ? slots.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
|
|
9368
|
+
setActiveFooterDropIndex(activeIdx >= 0 ? activeIdx : null);
|
|
9369
|
+
}, []);
|
|
9370
|
+
const refreshFooterDragVisualsRef = useRef7(refreshFooterDragVisuals);
|
|
9371
|
+
refreshFooterDragVisualsRef.current = refreshFooterDragVisuals;
|
|
9372
|
+
const commitFooterDragRef = useRef7(() => {
|
|
9373
|
+
});
|
|
9374
|
+
const beginFooterDragRef = useRef7(() => {
|
|
9375
|
+
});
|
|
9376
|
+
const beginFooterDrag = useCallback5(
|
|
9377
|
+
(session) => {
|
|
9378
|
+
const rect = session.draggedEl.getBoundingClientRect();
|
|
9379
|
+
session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
|
|
9380
|
+
session.lastClientY = session.lastClientY || rect.top + rect.height / 2;
|
|
9381
|
+
session.activeSlot = session.activeSlot ?? null;
|
|
9382
|
+
footerDragRef.current = session;
|
|
9383
|
+
setIsItemDragging(true);
|
|
9384
|
+
lockFooterDuringDrag();
|
|
9385
|
+
siblingHintElRef.current = null;
|
|
9386
|
+
setSiblingHintRect(null);
|
|
9387
|
+
if (session.wasSelected && selectedElRef.current === session.draggedEl) {
|
|
9388
|
+
setToolbarRect(rect);
|
|
9389
|
+
}
|
|
9390
|
+
const initialSlot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : hitTestColumnDropSlot(session.lastClientX, session.lastClientY);
|
|
9391
|
+
refreshFooterDragVisuals(session, initialSlot, session.lastClientX, session.lastClientY);
|
|
9392
|
+
},
|
|
9393
|
+
[refreshFooterDragVisuals]
|
|
9394
|
+
);
|
|
9395
|
+
beginFooterDragRef.current = beginFooterDrag;
|
|
9396
|
+
const commitFooterDrag = useCallback5(
|
|
9397
|
+
(clientX, clientY) => {
|
|
9398
|
+
const session = footerDragRef.current;
|
|
9399
|
+
if (!session) {
|
|
9400
|
+
clearFooterDragVisuals();
|
|
9401
|
+
return;
|
|
9402
|
+
}
|
|
9403
|
+
const x = typeof clientX === "number" && (clientX !== 0 || clientY !== 0) ? clientX : session.lastClientX;
|
|
9404
|
+
const y = typeof clientY === "number" && (clientX !== 0 || clientY !== 0) ? clientY : session.lastClientY;
|
|
9405
|
+
let nextOrder = null;
|
|
9406
|
+
const slot = session.activeSlot ?? (session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(x, y, session.hrefKey) : session.kind === "column" ? hitTestColumnDropSlot(x, y) : null);
|
|
9407
|
+
if (session.kind === "link" && session.hrefKey && slot) {
|
|
9408
|
+
nextOrder = planFooterLinkMove(session.hrefKey, slot.columnIndex, slot.insertIndex);
|
|
9409
|
+
} else if (session.kind === "column" && slot) {
|
|
9410
|
+
nextOrder = planFooterColumnMove(session.sourceColumnIndex, slot.insertIndex);
|
|
9411
|
+
}
|
|
9412
|
+
const wasSelected = session.wasSelected;
|
|
9413
|
+
const draggedEl = session.draggedEl;
|
|
9414
|
+
const hrefKey = session.hrefKey;
|
|
9415
|
+
let movedColumnIndex = null;
|
|
9416
|
+
if (session.kind === "column" && slot && nextOrder) {
|
|
9417
|
+
let adjusted = slot.insertIndex;
|
|
9418
|
+
if (session.sourceColumnIndex < slot.insertIndex) adjusted -= 1;
|
|
9419
|
+
movedColumnIndex = Math.max(0, Math.min(adjusted, nextOrder.length - 1));
|
|
9420
|
+
}
|
|
9421
|
+
const applySelectionAfterDrop = () => {
|
|
9422
|
+
if (!wasSelected) {
|
|
9423
|
+
deselectRef.current();
|
|
9424
|
+
return;
|
|
9425
|
+
}
|
|
9426
|
+
if (hrefKey) {
|
|
9427
|
+
selectedHrefKeyRef.current = hrefKey;
|
|
9428
|
+
selectedFooterColAttrRef.current = null;
|
|
9429
|
+
const link = resolveHrefKeyElement(hrefKey);
|
|
9430
|
+
if (link && isNavigationItem(link)) {
|
|
9431
|
+
selectRef.current(link);
|
|
9432
|
+
return;
|
|
9433
|
+
}
|
|
9434
|
+
}
|
|
9435
|
+
if (movedColumnIndex !== null && nextOrder) {
|
|
9436
|
+
const colKeys = nextOrder[movedColumnIndex] ?? [];
|
|
9437
|
+
let column = null;
|
|
9438
|
+
for (const key of colKeys) {
|
|
9439
|
+
const link = document.querySelector(
|
|
9440
|
+
`footer [data-ohw-href-key="${CSS.escape(key)}"]`
|
|
9441
|
+
);
|
|
9442
|
+
if (link) {
|
|
9443
|
+
column = findFooterColumnForLink(link);
|
|
9444
|
+
if (column) break;
|
|
9445
|
+
}
|
|
9446
|
+
}
|
|
9447
|
+
if (!column) column = listFooterColumns()[movedColumnIndex] ?? null;
|
|
9448
|
+
if (column && isNavigationContainer(column)) {
|
|
9449
|
+
selectFrameRef.current(column);
|
|
9450
|
+
return;
|
|
9451
|
+
}
|
|
9452
|
+
}
|
|
9453
|
+
if (document.body.contains(draggedEl)) {
|
|
9454
|
+
if (isNavigationItem(draggedEl)) {
|
|
9455
|
+
selectRef.current(draggedEl);
|
|
9456
|
+
return;
|
|
9457
|
+
}
|
|
9458
|
+
if (isNavigationContainer(draggedEl)) {
|
|
9459
|
+
selectFrameRef.current(draggedEl);
|
|
9460
|
+
return;
|
|
9461
|
+
}
|
|
9462
|
+
}
|
|
9463
|
+
deselectRef.current();
|
|
9464
|
+
};
|
|
9465
|
+
if (nextOrder) {
|
|
9466
|
+
const orderJson = JSON.stringify(nextOrder);
|
|
9467
|
+
editContentRef.current = {
|
|
9468
|
+
...editContentRef.current,
|
|
9469
|
+
[FOOTER_ORDER_KEY]: orderJson
|
|
9470
|
+
};
|
|
9471
|
+
applyFooterOrder(nextOrder);
|
|
9472
|
+
document.querySelectorAll("footer [data-ohw-href-key]").forEach(disableNativeHrefDrag);
|
|
9473
|
+
postToParentRef.current({
|
|
9474
|
+
type: "ow:change",
|
|
9475
|
+
nodes: [{ key: FOOTER_ORDER_KEY, text: orderJson }]
|
|
9476
|
+
});
|
|
9477
|
+
applySelectionAfterDrop();
|
|
9478
|
+
clearFooterDragVisuals();
|
|
9479
|
+
requestAnimationFrame(() => {
|
|
9480
|
+
if (editContentRef.current[FOOTER_ORDER_KEY] === orderJson) {
|
|
9481
|
+
applyFooterOrder(nextOrder);
|
|
9482
|
+
document.querySelectorAll("footer [data-ohw-href-key]").forEach(disableNativeHrefDrag);
|
|
9483
|
+
}
|
|
9484
|
+
applySelectionAfterDrop();
|
|
9485
|
+
requestAnimationFrame(() => {
|
|
9486
|
+
if (editContentRef.current[FOOTER_ORDER_KEY] === orderJson) {
|
|
9487
|
+
applyFooterOrder(nextOrder);
|
|
9488
|
+
}
|
|
9489
|
+
resyncSelectedNavigationItem();
|
|
9490
|
+
});
|
|
9491
|
+
});
|
|
9492
|
+
return;
|
|
9493
|
+
}
|
|
9494
|
+
applySelectionAfterDrop();
|
|
9495
|
+
clearFooterDragVisuals();
|
|
9496
|
+
},
|
|
9497
|
+
[clearFooterDragVisuals, resolveHrefKeyElement, resyncSelectedNavigationItem]
|
|
9498
|
+
);
|
|
9499
|
+
commitFooterDragRef.current = commitFooterDrag;
|
|
9500
|
+
const startFooterLinkDrag = useCallback5(
|
|
9501
|
+
(anchor, clientX, clientY, wasSelected) => {
|
|
9502
|
+
const hrefKey = anchor.getAttribute("data-ohw-href-key");
|
|
9503
|
+
if (!hrefKey || !isFooterHrefKey(hrefKey)) return false;
|
|
9504
|
+
const column = findFooterColumnForLink(anchor);
|
|
9505
|
+
const columns = listFooterColumns();
|
|
9506
|
+
beginFooterDrag({
|
|
9507
|
+
kind: "link",
|
|
9508
|
+
hrefKey,
|
|
9509
|
+
columnEl: column,
|
|
9510
|
+
sourceColumnIndex: column ? columns.indexOf(column) : 0,
|
|
9511
|
+
wasSelected,
|
|
9512
|
+
draggedEl: anchor,
|
|
9513
|
+
lastClientX: clientX,
|
|
9514
|
+
lastClientY: clientY,
|
|
9515
|
+
activeSlot: null
|
|
9516
|
+
});
|
|
9517
|
+
return true;
|
|
9518
|
+
},
|
|
9519
|
+
[beginFooterDrag]
|
|
9520
|
+
);
|
|
9521
|
+
const startFooterColumnDrag = useCallback5(
|
|
9522
|
+
(columnEl, clientX, clientY, wasSelected) => {
|
|
9523
|
+
const columns = listFooterColumns();
|
|
9524
|
+
const idx = columns.indexOf(columnEl);
|
|
9525
|
+
if (idx < 0) return false;
|
|
9526
|
+
beginFooterDrag({
|
|
9527
|
+
kind: "column",
|
|
9528
|
+
hrefKey: null,
|
|
9529
|
+
columnEl,
|
|
9530
|
+
sourceColumnIndex: idx,
|
|
9531
|
+
wasSelected,
|
|
9532
|
+
draggedEl: columnEl,
|
|
9533
|
+
lastClientX: clientX,
|
|
9534
|
+
lastClientY: clientY,
|
|
9535
|
+
activeSlot: null
|
|
9536
|
+
});
|
|
9537
|
+
return true;
|
|
9538
|
+
},
|
|
9539
|
+
[beginFooterDrag]
|
|
9540
|
+
);
|
|
9541
|
+
const handleItemDragStart = useCallback5(
|
|
9542
|
+
(e) => {
|
|
9543
|
+
const selected = selectedElRef.current;
|
|
9544
|
+
if (!selected) {
|
|
9545
|
+
setIsItemDragging(true);
|
|
9546
|
+
return;
|
|
9547
|
+
}
|
|
9548
|
+
const clientX = e?.clientX ?? selected.getBoundingClientRect().left + 8;
|
|
9549
|
+
const clientY = e?.clientY ?? selected.getBoundingClientRect().top + 8;
|
|
9550
|
+
if (startFooterLinkDrag(selected, clientX, clientY, true)) return;
|
|
9551
|
+
if (selected.hasAttribute("data-ohw-footer-col") || isInferredFooterGroup(selected) && selected.closest("footer")) {
|
|
9552
|
+
if (startFooterColumnDrag(selected, clientX, clientY, true)) return;
|
|
9553
|
+
}
|
|
9554
|
+
if (startNavLinkDrag(selected, clientX, clientY, true)) return;
|
|
9555
|
+
siblingHintElRef.current = null;
|
|
9556
|
+
setSiblingHintRect(null);
|
|
9557
|
+
setIsItemDragging(true);
|
|
9558
|
+
},
|
|
9559
|
+
[startFooterColumnDrag, startFooterLinkDrag, startNavLinkDrag]
|
|
9560
|
+
);
|
|
9561
|
+
const handleItemDragEnd = useCallback5(
|
|
9562
|
+
(e) => {
|
|
9563
|
+
if (footerDragRef.current) {
|
|
9564
|
+
const x = e?.clientX;
|
|
9565
|
+
const y = e?.clientY;
|
|
9566
|
+
if (typeof x === "number" && typeof y === "number" && (x !== 0 || y !== 0)) {
|
|
9567
|
+
commitFooterDrag(x, y);
|
|
9568
|
+
} else {
|
|
9569
|
+
commitFooterDrag();
|
|
9570
|
+
}
|
|
9571
|
+
return;
|
|
9572
|
+
}
|
|
9573
|
+
if (navDragRef.current) {
|
|
9574
|
+
const x = e?.clientX;
|
|
9575
|
+
const y = e?.clientY;
|
|
9576
|
+
if (typeof x === "number" && typeof y === "number" && (x !== 0 || y !== 0)) {
|
|
9577
|
+
commitNavDrag(x, y);
|
|
9578
|
+
} else {
|
|
9579
|
+
commitNavDrag();
|
|
9580
|
+
}
|
|
9581
|
+
return;
|
|
9582
|
+
}
|
|
9583
|
+
setIsItemDragging(false);
|
|
9584
|
+
},
|
|
9585
|
+
[commitFooterDrag, commitNavDrag, navDragRef]
|
|
9586
|
+
);
|
|
9587
|
+
const handleItemChromePointerDown = useCallback5((e) => {
|
|
9588
|
+
if (e.button !== 0) return;
|
|
9589
|
+
const selected = selectedElRef.current;
|
|
9590
|
+
if (!selected) return;
|
|
9591
|
+
const hrefKey = selected.getAttribute("data-ohw-href-key");
|
|
9592
|
+
if (hrefKey && isFooterHrefKey(hrefKey)) {
|
|
9593
|
+
footerPointerDragRef.current = {
|
|
9594
|
+
el: selected,
|
|
9595
|
+
kind: "link",
|
|
9596
|
+
startX: e.clientX,
|
|
9597
|
+
startY: e.clientY,
|
|
9598
|
+
pointerId: e.pointerId,
|
|
9599
|
+
wasSelected: true,
|
|
9600
|
+
started: false
|
|
9601
|
+
};
|
|
9602
|
+
return;
|
|
9603
|
+
}
|
|
9604
|
+
if (selected.hasAttribute("data-ohw-footer-col") || isInferredFooterGroup(selected) && selected.closest("footer")) {
|
|
9605
|
+
footerPointerDragRef.current = {
|
|
9606
|
+
el: selected,
|
|
9607
|
+
kind: "column",
|
|
9608
|
+
startX: e.clientX,
|
|
9609
|
+
startY: e.clientY,
|
|
9610
|
+
pointerId: e.pointerId,
|
|
9611
|
+
wasSelected: true,
|
|
9612
|
+
started: false
|
|
9613
|
+
};
|
|
9614
|
+
return;
|
|
9615
|
+
}
|
|
9616
|
+
if (armNavPressFromChrome(selected, e.clientX, e.clientY, e.pointerId)) return;
|
|
9617
|
+
}, [armNavPressFromChrome]);
|
|
9618
|
+
const handleItemChromeClick = useCallback5((clientX, clientY) => {
|
|
9619
|
+
if (suppressNextClickRef.current || Date.now() < suppressClickUntilRef.current) {
|
|
9620
|
+
suppressNextClickRef.current = false;
|
|
9621
|
+
return;
|
|
9622
|
+
}
|
|
9623
|
+
const selected = selectedElRef.current;
|
|
9624
|
+
if (!selected || !isNavigationItem(selected)) return;
|
|
9625
|
+
const editable = selected.querySelector('[data-ohw-editable="text"]') ?? selected.querySelector("[data-ohw-editable]");
|
|
9626
|
+
if (!editable) return;
|
|
9627
|
+
activateRef.current(editable, { caretX: clientX, caretY: clientY });
|
|
7777
9628
|
}, []);
|
|
7778
9629
|
reselectNavigationItemRef.current = reselectNavigationItem;
|
|
7779
9630
|
commitNavigationTextEditRef.current = commitNavigationTextEdit;
|
|
7780
|
-
const select =
|
|
9631
|
+
const select = useCallback5((anchor) => {
|
|
7781
9632
|
if (!isNavigationItem(anchor)) return;
|
|
7782
9633
|
if (activeElRef.current) deactivate();
|
|
7783
9634
|
selectedElRef.current = anchor;
|
|
9635
|
+
selectedHrefKeyRef.current = anchor.getAttribute("data-ohw-href-key");
|
|
9636
|
+
selectedFooterColAttrRef.current = null;
|
|
9637
|
+
markSelected(anchor);
|
|
9638
|
+
setSelectedIsCta(isNavbarButton2(anchor));
|
|
7784
9639
|
clearHrefKeyHover(anchor);
|
|
7785
9640
|
hoveredNavContainerRef.current = null;
|
|
7786
9641
|
setHoveredNavContainerRect(null);
|
|
@@ -7788,19 +9643,26 @@ function OhhwellsBridge() {
|
|
|
7788
9643
|
hoveredItemElRef.current = null;
|
|
7789
9644
|
siblingHintElRef.current = null;
|
|
7790
9645
|
setSiblingHintRect(null);
|
|
9646
|
+
setSiblingHintRects(collectNavigationItemSiblingHintRects(anchor));
|
|
7791
9647
|
setIsItemDragging(false);
|
|
7792
9648
|
const { key, disabled } = getNavigationItemReorderState(anchor);
|
|
7793
9649
|
setReorderHrefKey(key);
|
|
7794
9650
|
setReorderDragDisabled(disabled);
|
|
9651
|
+
setIsFooterFrameSelection(false);
|
|
7795
9652
|
setToolbarVariant("link-action");
|
|
7796
9653
|
setToolbarRect(anchor.getBoundingClientRect());
|
|
7797
9654
|
setToolbarShowEditLink(false);
|
|
7798
9655
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
7799
|
-
}, [deactivate]);
|
|
7800
|
-
const selectFrame =
|
|
9656
|
+
}, [deactivate, markSelected]);
|
|
9657
|
+
const selectFrame = useCallback5((el) => {
|
|
7801
9658
|
if (!isNavigationContainer(el)) return;
|
|
7802
9659
|
if (activeElRef.current) deactivate();
|
|
9660
|
+
const isFooterColumn = el.hasAttribute("data-ohw-footer-col") || Boolean(el.closest("footer") && isInferredFooterGroup(el));
|
|
7803
9661
|
selectedElRef.current = el;
|
|
9662
|
+
selectedHrefKeyRef.current = null;
|
|
9663
|
+
selectedFooterColAttrRef.current = isFooterColumn ? el.getAttribute("data-ohw-footer-col") ?? String(listFooterColumns().indexOf(el)) : null;
|
|
9664
|
+
markSelected(el);
|
|
9665
|
+
setSelectedIsCta(false);
|
|
7804
9666
|
clearHrefKeyHover(el);
|
|
7805
9667
|
hoveredNavContainerRef.current = null;
|
|
7806
9668
|
setHoveredNavContainerRect(null);
|
|
@@ -7808,17 +9670,25 @@ function OhhwellsBridge() {
|
|
|
7808
9670
|
hoveredItemElRef.current = null;
|
|
7809
9671
|
siblingHintElRef.current = null;
|
|
7810
9672
|
setSiblingHintRect(null);
|
|
9673
|
+
setSiblingHintRects(
|
|
9674
|
+
isFooterColumn ? listFooterColumns().filter((column) => column !== el).map((column) => column.getBoundingClientRect()) : []
|
|
9675
|
+
);
|
|
7811
9676
|
setIsItemDragging(false);
|
|
7812
9677
|
setReorderHrefKey(null);
|
|
7813
9678
|
setReorderDragDisabled(false);
|
|
9679
|
+
setIsFooterFrameSelection(isFooterColumn);
|
|
7814
9680
|
setToolbarVariant("select-frame");
|
|
7815
9681
|
setToolbarRect(el.getBoundingClientRect());
|
|
7816
9682
|
setToolbarShowEditLink(false);
|
|
7817
9683
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
7818
|
-
}, [deactivate]);
|
|
7819
|
-
const activate =
|
|
9684
|
+
}, [deactivate, markSelected]);
|
|
9685
|
+
const activate = useCallback5((el, options) => {
|
|
7820
9686
|
if (activeElRef.current === el) return;
|
|
9687
|
+
clearSelectedAttr();
|
|
7821
9688
|
selectedElRef.current = null;
|
|
9689
|
+
selectedHrefKeyRef.current = null;
|
|
9690
|
+
selectedFooterColAttrRef.current = null;
|
|
9691
|
+
setSelectedIsCta(false);
|
|
7822
9692
|
deactivate();
|
|
7823
9693
|
if (hoveredImageRef.current) {
|
|
7824
9694
|
hoveredImageRef.current = null;
|
|
@@ -7828,14 +9698,34 @@ function OhhwellsBridge() {
|
|
|
7828
9698
|
siblingHintElRef.current = null;
|
|
7829
9699
|
setSiblingHintRect(null);
|
|
7830
9700
|
setIsItemDragging(false);
|
|
9701
|
+
const preActivationSelection = window.getSelection();
|
|
9702
|
+
const preservedRange = preActivationSelection && preActivationSelection.rangeCount > 0 && !preActivationSelection.isCollapsed && el.contains(preActivationSelection.getRangeAt(0).commonAncestorContainer) ? preActivationSelection.getRangeAt(0).cloneRange() : null;
|
|
7831
9703
|
el.setAttribute("contenteditable", "true");
|
|
9704
|
+
el.setAttribute("data-ohw-editing", "");
|
|
7832
9705
|
el.removeAttribute("data-ohw-hovered");
|
|
7833
9706
|
el.closest("[data-ohw-href-key]")?.removeAttribute("data-ohw-hovered");
|
|
7834
9707
|
activeElRef.current = el;
|
|
7835
9708
|
originalContentRef.current = el.innerHTML;
|
|
7836
|
-
el.focus();
|
|
7837
|
-
if (
|
|
7838
|
-
|
|
9709
|
+
el.focus({ preventScroll: true });
|
|
9710
|
+
if (preservedRange) {
|
|
9711
|
+
const selection = window.getSelection();
|
|
9712
|
+
selection?.removeAllRanges();
|
|
9713
|
+
selection?.addRange(preservedRange);
|
|
9714
|
+
} else if (options?.caretX !== void 0 && options?.caretY !== void 0) {
|
|
9715
|
+
const { caretX, caretY } = options;
|
|
9716
|
+
placeCaretAtPoint(el, caretX, caretY);
|
|
9717
|
+
requestAnimationFrame(() => {
|
|
9718
|
+
if (activeElRef.current === el) placeCaretAtPoint(el, caretX, caretY);
|
|
9719
|
+
});
|
|
9720
|
+
} else {
|
|
9721
|
+
const selection = window.getSelection();
|
|
9722
|
+
if (selection && selection.rangeCount === 0) {
|
|
9723
|
+
const range = document.createRange();
|
|
9724
|
+
range.selectNodeContents(el);
|
|
9725
|
+
range.collapse(false);
|
|
9726
|
+
selection.removeAllRanges();
|
|
9727
|
+
selection.addRange(range);
|
|
9728
|
+
}
|
|
7839
9729
|
}
|
|
7840
9730
|
setToolbarShowEditLink(Boolean(getHrefKeyFromElement(el)));
|
|
7841
9731
|
const navAnchor = getNavigationItemAnchor(el);
|
|
@@ -7850,13 +9740,13 @@ function OhhwellsBridge() {
|
|
|
7850
9740
|
setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
|
|
7851
9741
|
postToParent2({ type: "ow:enter-edit", key: el.dataset.ohwKey });
|
|
7852
9742
|
requestAnimationFrame(() => refreshActiveCommandsRef.current());
|
|
7853
|
-
}, [deactivate, postToParent2]);
|
|
9743
|
+
}, [clearSelectedAttr, deactivate, postToParent2]);
|
|
7854
9744
|
activateRef.current = activate;
|
|
7855
9745
|
deactivateRef.current = deactivate;
|
|
7856
9746
|
selectRef.current = select;
|
|
7857
9747
|
selectFrameRef.current = selectFrame;
|
|
7858
9748
|
deselectRef.current = deselect;
|
|
7859
|
-
|
|
9749
|
+
useLayoutEffect3(() => {
|
|
7860
9750
|
if (!subdomain || isEditMode) {
|
|
7861
9751
|
setFetchState("done");
|
|
7862
9752
|
return;
|
|
@@ -7897,6 +9787,7 @@ function OhhwellsBridge() {
|
|
|
7897
9787
|
applyLinkByKey(key, val);
|
|
7898
9788
|
}
|
|
7899
9789
|
reconcileNavbarItemsFromContent(content);
|
|
9790
|
+
reconcileFooterOrderFromContent(content);
|
|
7900
9791
|
enforceLinkHrefs();
|
|
7901
9792
|
initSectionsFromContent(content, true);
|
|
7902
9793
|
sectionsLoadedRef.current = true;
|
|
@@ -7925,7 +9816,7 @@ function OhhwellsBridge() {
|
|
|
7925
9816
|
cancelled = true;
|
|
7926
9817
|
};
|
|
7927
9818
|
}, [subdomain, isEditMode]);
|
|
7928
|
-
|
|
9819
|
+
useEffect8(() => {
|
|
7929
9820
|
if (!subdomain || isEditMode) return;
|
|
7930
9821
|
let debounceTimer = null;
|
|
7931
9822
|
let observer = null;
|
|
@@ -7957,6 +9848,7 @@ function OhhwellsBridge() {
|
|
|
7957
9848
|
applyLinkByKey(key, val);
|
|
7958
9849
|
}
|
|
7959
9850
|
reconcileNavbarItemsFromContent(content);
|
|
9851
|
+
reconcileFooterOrderFromContent(content);
|
|
7960
9852
|
} finally {
|
|
7961
9853
|
observer?.observe(document.body, { childList: true, subtree: true });
|
|
7962
9854
|
}
|
|
@@ -7974,16 +9866,16 @@ function OhhwellsBridge() {
|
|
|
7974
9866
|
if (debounceTimer) clearTimeout(debounceTimer);
|
|
7975
9867
|
};
|
|
7976
9868
|
}, [subdomain, isEditMode, pathname]);
|
|
7977
|
-
|
|
9869
|
+
useLayoutEffect3(() => {
|
|
7978
9870
|
const el = document.getElementById("ohw-loader");
|
|
7979
9871
|
if (!el) return;
|
|
7980
9872
|
const visible = Boolean(subdomain) && fetchState !== "done";
|
|
7981
9873
|
el.style.display = visible ? "flex" : "none";
|
|
7982
9874
|
}, [subdomain, fetchState]);
|
|
7983
|
-
|
|
9875
|
+
useEffect8(() => {
|
|
7984
9876
|
postToParent2({ type: "ow:navigation", path: pathname });
|
|
7985
9877
|
}, [pathname, postToParent2]);
|
|
7986
|
-
|
|
9878
|
+
useEffect8(() => {
|
|
7987
9879
|
if (!isEditMode) return;
|
|
7988
9880
|
if (linkPopoverSessionRef.current?.intent === "add-nav") return;
|
|
7989
9881
|
if (document.querySelector("[data-ohw-section-picker]")) return;
|
|
@@ -7991,23 +9883,72 @@ function OhhwellsBridge() {
|
|
|
7991
9883
|
deselectRef.current();
|
|
7992
9884
|
deactivateRef.current();
|
|
7993
9885
|
}, [pathname, isEditMode]);
|
|
7994
|
-
|
|
9886
|
+
useEffect8(() => {
|
|
7995
9887
|
const contentForNav = () => {
|
|
7996
9888
|
if (isEditMode) return editContentRef.current;
|
|
7997
9889
|
if (!subdomain) return {};
|
|
7998
9890
|
return contentCache.get(subdomain) ?? {};
|
|
7999
9891
|
};
|
|
8000
|
-
const
|
|
9892
|
+
const observeRoots = () => [document.querySelector("nav"), document.querySelector("footer")].filter(
|
|
9893
|
+
(el) => Boolean(el)
|
|
9894
|
+
);
|
|
9895
|
+
const roots = observeRoots();
|
|
9896
|
+
if (roots.length === 0) {
|
|
9897
|
+
reconcileNavbarItemsFromContent(contentForNav());
|
|
9898
|
+
reconcileFooterOrderFromContent(contentForNav());
|
|
9899
|
+
if (isEditMode) syncNavigationDragCursorAttrs();
|
|
9900
|
+
return;
|
|
9901
|
+
}
|
|
9902
|
+
let rafId = null;
|
|
9903
|
+
let applying = false;
|
|
9904
|
+
let observer = null;
|
|
9905
|
+
const attach = () => {
|
|
9906
|
+
for (const root of observeRoots()) {
|
|
9907
|
+
observer?.observe(root, { childList: true, subtree: true });
|
|
9908
|
+
}
|
|
9909
|
+
};
|
|
9910
|
+
const run = () => {
|
|
9911
|
+
if (footerDragRef.current || navDragRef.current || applying) return;
|
|
9912
|
+
applying = true;
|
|
9913
|
+
observer?.disconnect();
|
|
9914
|
+
try {
|
|
9915
|
+
const content = contentForNav();
|
|
9916
|
+
reconcileNavbarItemsFromContent(content);
|
|
9917
|
+
reconcileFooterOrderFromContent(content);
|
|
9918
|
+
document.querySelectorAll("footer [data-ohw-href-key]").forEach((el) => {
|
|
9919
|
+
if (isFooterHrefKey(el.getAttribute("data-ohw-href-key"))) {
|
|
9920
|
+
disableNativeHrefDrag(el);
|
|
9921
|
+
}
|
|
9922
|
+
});
|
|
9923
|
+
document.querySelectorAll(
|
|
9924
|
+
"nav [data-ohw-href-key], [data-ohw-nav-container] [data-ohw-href-key], [data-ohw-nav-drawer] [data-ohw-href-key]"
|
|
9925
|
+
).forEach((el) => {
|
|
9926
|
+
if (isNavbarHrefKey(el.getAttribute("data-ohw-href-key"))) {
|
|
9927
|
+
disableNativeHrefDrag(el);
|
|
9928
|
+
}
|
|
9929
|
+
});
|
|
9930
|
+
resyncSelectedNavigationItem();
|
|
9931
|
+
if (isEditMode) syncNavigationDragCursorAttrs();
|
|
9932
|
+
} finally {
|
|
9933
|
+
applying = false;
|
|
9934
|
+
attach();
|
|
9935
|
+
}
|
|
9936
|
+
};
|
|
9937
|
+
const schedule = () => {
|
|
9938
|
+
if (applying || rafId != null) return;
|
|
9939
|
+
rafId = requestAnimationFrame(() => {
|
|
9940
|
+
rafId = null;
|
|
9941
|
+
run();
|
|
9942
|
+
});
|
|
9943
|
+
};
|
|
9944
|
+
observer = new MutationObserver(schedule);
|
|
8001
9945
|
run();
|
|
8002
|
-
|
|
8003
|
-
|
|
8004
|
-
|
|
8005
|
-
|
|
8006
|
-
|
|
8007
|
-
|
|
8008
|
-
return () => observer.disconnect();
|
|
8009
|
-
}, [isEditMode, pathname, subdomain, fetchState]);
|
|
8010
|
-
useEffect7(() => {
|
|
9946
|
+
return () => {
|
|
9947
|
+
if (rafId != null) cancelAnimationFrame(rafId);
|
|
9948
|
+
observer?.disconnect();
|
|
9949
|
+
};
|
|
9950
|
+
}, [isEditMode, pathname, subdomain, fetchState, resyncSelectedNavigationItem]);
|
|
9951
|
+
useEffect8(() => {
|
|
8011
9952
|
if (!isEditMode) return;
|
|
8012
9953
|
const measure = () => {
|
|
8013
9954
|
const h = document.body.scrollHeight;
|
|
@@ -8031,7 +9972,7 @@ function OhhwellsBridge() {
|
|
|
8031
9972
|
window.removeEventListener("resize", handleResize);
|
|
8032
9973
|
};
|
|
8033
9974
|
}, [pathname, isEditMode, postToParent2]);
|
|
8034
|
-
|
|
9975
|
+
useEffect8(() => {
|
|
8035
9976
|
if (!subdomainFromQuery || isEditMode) return;
|
|
8036
9977
|
const handleClick = (e) => {
|
|
8037
9978
|
const anchor = e.target.closest("a");
|
|
@@ -8047,19 +9988,24 @@ function OhhwellsBridge() {
|
|
|
8047
9988
|
document.addEventListener("click", handleClick, true);
|
|
8048
9989
|
return () => document.removeEventListener("click", handleClick, true);
|
|
8049
9990
|
}, [subdomainFromQuery, isEditMode, router]);
|
|
8050
|
-
|
|
9991
|
+
useEffect8(() => {
|
|
8051
9992
|
if (!isEditMode) {
|
|
8052
9993
|
editStylesRef.current?.base.remove();
|
|
8053
9994
|
editStylesRef.current?.forceHover.remove();
|
|
8054
9995
|
editStylesRef.current?.stateViews.remove();
|
|
8055
9996
|
editStylesRef.current = null;
|
|
9997
|
+
document.querySelectorAll("[data-ohw-can-drag]").forEach((el) => {
|
|
9998
|
+
el.removeAttribute("data-ohw-can-drag");
|
|
9999
|
+
});
|
|
8056
10000
|
return;
|
|
8057
10001
|
}
|
|
8058
|
-
|
|
8059
|
-
|
|
8060
|
-
|
|
8061
|
-
base.
|
|
8062
|
-
|
|
10002
|
+
const existing = editStylesRef.current;
|
|
10003
|
+
let initialVh = window.innerHeight;
|
|
10004
|
+
if (existing?.base.textContent) {
|
|
10005
|
+
const match = existing.base.textContent.match(/\.min-h-screen[^{]*\{[^}]*min-height:\s*(\d+)px/);
|
|
10006
|
+
if (match) initialVh = parseInt(match[1], 10);
|
|
10007
|
+
}
|
|
10008
|
+
const baseCss = `
|
|
8063
10009
|
html { height: auto !important; }
|
|
8064
10010
|
body { height: auto !important; min-height: 0 !important; overflow: hidden !important; }
|
|
8065
10011
|
.min-h-screen, .min-h-svh, .min-h-dvh { min-height: ${initialVh}px !important; }
|
|
@@ -8070,7 +10016,25 @@ function OhhwellsBridge() {
|
|
|
8070
10016
|
[data-ohw-editable] {
|
|
8071
10017
|
display: block;
|
|
8072
10018
|
}
|
|
8073
|
-
|
|
10019
|
+
/* Body text (no item-action toolbar) \u2014 first click enters text edit \u2192 I-beam.
|
|
10020
|
+
Exclude select-first nav/footer labels so grab/default on [data-ohw-href-key] can win. */
|
|
10021
|
+
[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] *)) {
|
|
10022
|
+
cursor: text !important;
|
|
10023
|
+
}
|
|
10024
|
+
/* Select-first items: default arrow; grab only when drag-start is allowed (data-ohw-can-drag). */
|
|
10025
|
+
[data-ohw-href-key]:not([data-ohw-selected]),
|
|
10026
|
+
[data-ohw-href-key]:not([data-ohw-selected]) * {
|
|
10027
|
+
cursor: default !important;
|
|
10028
|
+
}
|
|
10029
|
+
[data-ohw-href-key][data-ohw-can-drag]:not([data-ohw-selected]),
|
|
10030
|
+
[data-ohw-href-key][data-ohw-can-drag]:not([data-ohw-selected]) * {
|
|
10031
|
+
cursor: grab !important;
|
|
10032
|
+
}
|
|
10033
|
+
/* Selected (action-toolbar) \u2014 next click enters text edit at caret. */
|
|
10034
|
+
[data-ohw-href-key][data-ohw-selected],
|
|
10035
|
+
[data-ohw-href-key][data-ohw-selected] * {
|
|
10036
|
+
cursor: text !important;
|
|
10037
|
+
}
|
|
8074
10038
|
[data-ohw-editable="image"], [data-ohw-editable="image"] *,
|
|
8075
10039
|
[data-ohw-editable="video"], [data-ohw-editable="video"] *,
|
|
8076
10040
|
[data-ohw-editable="bg-image"], [data-ohw-editable="bg-image"] * { cursor: pointer !important; }
|
|
@@ -8086,9 +10050,32 @@ function OhhwellsBridge() {
|
|
|
8086
10050
|
outline: none !important;
|
|
8087
10051
|
outline-offset: 0 !important;
|
|
8088
10052
|
}
|
|
8089
|
-
|
|
10053
|
+
/* Editor chrome owns selection \u2014 suppress native focus rings on nav/footer items. */
|
|
10054
|
+
nav [data-ohw-href-key]:focus,
|
|
10055
|
+
nav [data-ohw-href-key]:focus-visible,
|
|
10056
|
+
nav [data-ohw-href-key]:focus-within,
|
|
10057
|
+
footer [data-ohw-href-key]:focus,
|
|
10058
|
+
footer [data-ohw-href-key]:focus-visible,
|
|
10059
|
+
footer [data-ohw-href-key]:focus-within,
|
|
10060
|
+
nav [data-ohw-href-key] [data-ohw-editable]:focus,
|
|
10061
|
+
nav [data-ohw-href-key] [data-ohw-editable]:focus-visible,
|
|
10062
|
+
footer [data-ohw-href-key] [data-ohw-editable]:focus,
|
|
10063
|
+
footer [data-ohw-href-key] [data-ohw-editable]:focus-visible {
|
|
10064
|
+
outline: none !important;
|
|
10065
|
+
outline-offset: 0 !important;
|
|
10066
|
+
box-shadow: none !important;
|
|
10067
|
+
}
|
|
10068
|
+
/* Text edit wins over grab/default (must beat [data-ohw-can-drag] *). */
|
|
10069
|
+
[data-ohw-editing],
|
|
10070
|
+
[data-ohw-editing] *,
|
|
10071
|
+
[data-ohw-editable][contenteditable],
|
|
10072
|
+
[data-ohw-editable][contenteditable] *,
|
|
10073
|
+
nav [data-ohw-href-key] [data-ohw-editable][contenteditable],
|
|
10074
|
+
nav [data-ohw-href-key] [data-ohw-editable][contenteditable] *,
|
|
10075
|
+
footer [data-ohw-href-key] [data-ohw-editable][contenteditable],
|
|
10076
|
+
footer [data-ohw-href-key] [data-ohw-editable][contenteditable] * {
|
|
8090
10077
|
outline: none !important;
|
|
8091
|
-
caret-color: ${PRIMARY2};
|
|
10078
|
+
caret-color: ${PRIMARY2} !important;
|
|
8092
10079
|
cursor: text !important;
|
|
8093
10080
|
}
|
|
8094
10081
|
[data-ohw-editable][contenteditable]::selection,
|
|
@@ -8097,6 +10084,9 @@ function OhhwellsBridge() {
|
|
|
8097
10084
|
[data-ohw-editable-state][data-ohw-active-state] [data-ohw-editable] { pointer-events: auto !important; }
|
|
8098
10085
|
[data-ohw-editable-state][data-ohw-active-state][data-ohw-editable] { pointer-events: auto !important; }
|
|
8099
10086
|
`;
|
|
10087
|
+
if (!existing) {
|
|
10088
|
+
const base = document.createElement("style");
|
|
10089
|
+
base.setAttribute("data-ohw-edit-style", "");
|
|
8100
10090
|
const forceHover = document.createElement("style");
|
|
8101
10091
|
forceHover.setAttribute("data-ohw-active-state-style", "");
|
|
8102
10092
|
const stateViews = document.createElement("style");
|
|
@@ -8112,14 +10102,43 @@ function OhhwellsBridge() {
|
|
|
8112
10102
|
document.head.appendChild(stateViews);
|
|
8113
10103
|
editStylesRef.current = { base, forceHover, stateViews };
|
|
8114
10104
|
}
|
|
10105
|
+
editStylesRef.current.base.textContent = baseCss;
|
|
10106
|
+
syncNavigationDragCursorAttrs();
|
|
8115
10107
|
refreshStateRules();
|
|
8116
10108
|
const handleClick = (e) => {
|
|
10109
|
+
if (suppressNextClickRef.current || Date.now() < suppressClickUntilRef.current) {
|
|
10110
|
+
suppressNextClickRef.current = false;
|
|
10111
|
+
e.preventDefault();
|
|
10112
|
+
e.stopPropagation();
|
|
10113
|
+
return;
|
|
10114
|
+
}
|
|
8117
10115
|
const target = e.target;
|
|
8118
10116
|
if (target.closest("[data-ohw-toolbar]")) return;
|
|
8119
10117
|
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
8120
10118
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
8121
10119
|
if (isInsideLinkEditor(target)) return;
|
|
8122
10120
|
if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
|
|
10121
|
+
if (target.closest("[data-ohw-item-drag-surface]")) {
|
|
10122
|
+
e.preventDefault();
|
|
10123
|
+
e.stopPropagation();
|
|
10124
|
+
const selected = selectedElRef.current;
|
|
10125
|
+
if (selected && isNavigationItem(selected)) {
|
|
10126
|
+
const editable2 = selected.querySelector('[data-ohw-editable="text"]') ?? selected.querySelector("[data-ohw-editable]");
|
|
10127
|
+
if (editable2) {
|
|
10128
|
+
activateRef.current(editable2, {
|
|
10129
|
+
caretX: e.clientX,
|
|
10130
|
+
caretY: e.clientY
|
|
10131
|
+
});
|
|
10132
|
+
}
|
|
10133
|
+
} else if (selected?.hasAttribute("data-ohw-footer-col")) {
|
|
10134
|
+
const link = listFooterLinksInColumn(selected).find((el) => {
|
|
10135
|
+
const r2 = el.getBoundingClientRect();
|
|
10136
|
+
return e.clientX >= r2.left && e.clientX <= r2.right && e.clientY >= r2.top && e.clientY <= r2.bottom;
|
|
10137
|
+
});
|
|
10138
|
+
if (link) selectRef.current(link);
|
|
10139
|
+
}
|
|
10140
|
+
return;
|
|
10141
|
+
}
|
|
8123
10142
|
const navFromChrome = resolveNavContainerSelectionTarget(target, e.clientX, e.clientY);
|
|
8124
10143
|
if (navFromChrome) {
|
|
8125
10144
|
e.preventDefault();
|
|
@@ -8127,10 +10146,45 @@ function OhhwellsBridge() {
|
|
|
8127
10146
|
selectFrameRef.current(navFromChrome);
|
|
8128
10147
|
return;
|
|
8129
10148
|
}
|
|
10149
|
+
const footerFromChrome = resolveFooterColumnSelectionTarget(target, e.clientX, e.clientY);
|
|
10150
|
+
if (footerFromChrome) {
|
|
10151
|
+
e.preventDefault();
|
|
10152
|
+
e.stopPropagation();
|
|
10153
|
+
selectFrameRef.current(footerFromChrome);
|
|
10154
|
+
return;
|
|
10155
|
+
}
|
|
8130
10156
|
e.preventDefault();
|
|
8131
10157
|
e.stopPropagation();
|
|
8132
10158
|
return;
|
|
8133
10159
|
}
|
|
10160
|
+
if (activeElRef.current) {
|
|
10161
|
+
const active = activeElRef.current;
|
|
10162
|
+
const inActive = active === target || active.contains(target);
|
|
10163
|
+
const navAnchor = getNavigationItemAnchor(active);
|
|
10164
|
+
const inActiveNav = Boolean(
|
|
10165
|
+
navAnchor && (navAnchor === target || navAnchor.contains(target))
|
|
10166
|
+
);
|
|
10167
|
+
if (inActive || inActiveNav) {
|
|
10168
|
+
e.preventDefault();
|
|
10169
|
+
e.stopPropagation();
|
|
10170
|
+
const selection = window.getSelection();
|
|
10171
|
+
const hasRangeSelection = Boolean(selection && !selection.isCollapsed);
|
|
10172
|
+
console.log(
|
|
10173
|
+
"[OHW DEBUG handleClick] already-active branch",
|
|
10174
|
+
"detail=",
|
|
10175
|
+
e.detail,
|
|
10176
|
+
"hasRangeSelection=",
|
|
10177
|
+
hasRangeSelection,
|
|
10178
|
+
"willPlaceCaret=",
|
|
10179
|
+
e.detail < 2 && !hasRangeSelection
|
|
10180
|
+
);
|
|
10181
|
+
if (e.detail < 2 && !hasRangeSelection) {
|
|
10182
|
+
placeCaretAtPoint(active, e.clientX, e.clientY);
|
|
10183
|
+
refreshActiveCommandsRef.current();
|
|
10184
|
+
}
|
|
10185
|
+
return;
|
|
10186
|
+
}
|
|
10187
|
+
}
|
|
8134
10188
|
const editable = target.closest("[data-ohw-editable]");
|
|
8135
10189
|
if (editable) {
|
|
8136
10190
|
if (editable.dataset.ohwEditable === "link") {
|
|
@@ -8158,6 +10212,7 @@ function OhhwellsBridge() {
|
|
|
8158
10212
|
e.preventDefault();
|
|
8159
10213
|
e.stopPropagation();
|
|
8160
10214
|
if (selectedElRef.current === navAnchor) {
|
|
10215
|
+
if (e.detail >= 2) return;
|
|
8161
10216
|
activateRef.current(editable, { caretX: e.clientX, caretY: e.clientY });
|
|
8162
10217
|
return;
|
|
8163
10218
|
}
|
|
@@ -8166,6 +10221,15 @@ function OhhwellsBridge() {
|
|
|
8166
10221
|
}
|
|
8167
10222
|
e.preventDefault();
|
|
8168
10223
|
e.stopPropagation();
|
|
10224
|
+
console.log(
|
|
10225
|
+
"[OHW DEBUG handleClick] first-activation branch",
|
|
10226
|
+
"detail=",
|
|
10227
|
+
e.detail,
|
|
10228
|
+
"selectionAtClick=",
|
|
10229
|
+
JSON.stringify(window.getSelection()?.toString() ?? ""),
|
|
10230
|
+
"collapsedAtClick=",
|
|
10231
|
+
window.getSelection()?.isCollapsed
|
|
10232
|
+
);
|
|
8169
10233
|
activateRef.current(editable);
|
|
8170
10234
|
return;
|
|
8171
10235
|
}
|
|
@@ -8173,10 +10237,26 @@ function OhhwellsBridge() {
|
|
|
8173
10237
|
if (hrefAnchor) {
|
|
8174
10238
|
e.preventDefault();
|
|
8175
10239
|
e.stopPropagation();
|
|
8176
|
-
if (selectedElRef.current === hrefAnchor)
|
|
10240
|
+
if (selectedElRef.current === hrefAnchor) {
|
|
10241
|
+
const textEditable = hrefAnchor.querySelector('[data-ohw-editable="text"]') ?? hrefAnchor.querySelector("[data-ohw-editable]");
|
|
10242
|
+
if (textEditable) {
|
|
10243
|
+
activateRef.current(textEditable, {
|
|
10244
|
+
caretX: e.clientX,
|
|
10245
|
+
caretY: e.clientY
|
|
10246
|
+
});
|
|
10247
|
+
}
|
|
10248
|
+
return;
|
|
10249
|
+
}
|
|
8177
10250
|
selectRef.current(hrefAnchor);
|
|
8178
10251
|
return;
|
|
8179
10252
|
}
|
|
10253
|
+
const footerColClick = target.closest("[data-ohw-footer-col]");
|
|
10254
|
+
if (footerColClick) {
|
|
10255
|
+
e.preventDefault();
|
|
10256
|
+
e.stopPropagation();
|
|
10257
|
+
selectFrameRef.current(footerColClick);
|
|
10258
|
+
return;
|
|
10259
|
+
}
|
|
8180
10260
|
const navContainerToSelect = resolveNavContainerSelectionTarget(target, e.clientX, e.clientY);
|
|
8181
10261
|
if (navContainerToSelect) {
|
|
8182
10262
|
e.preventDefault();
|
|
@@ -8184,6 +10264,13 @@ function OhhwellsBridge() {
|
|
|
8184
10264
|
selectFrameRef.current(navContainerToSelect);
|
|
8185
10265
|
return;
|
|
8186
10266
|
}
|
|
10267
|
+
const footerColumnToSelect = resolveFooterColumnSelectionTarget(target, e.clientX, e.clientY);
|
|
10268
|
+
if (footerColumnToSelect) {
|
|
10269
|
+
e.preventDefault();
|
|
10270
|
+
e.stopPropagation();
|
|
10271
|
+
selectFrameRef.current(footerColumnToSelect);
|
|
10272
|
+
return;
|
|
10273
|
+
}
|
|
8187
10274
|
const selectedContainer = selectedElRef.current;
|
|
8188
10275
|
if (selectedContainer && isNavigationContainer(selectedContainer)) {
|
|
8189
10276
|
const navItem = getNavigationItemAnchor(target);
|
|
@@ -8218,9 +10305,38 @@ function OhhwellsBridge() {
|
|
|
8218
10305
|
deselectRef.current();
|
|
8219
10306
|
deactivateRef.current();
|
|
8220
10307
|
};
|
|
10308
|
+
const handleDblClick = (e) => {
|
|
10309
|
+
const target = e.target;
|
|
10310
|
+
if (target.closest("[data-ohw-toolbar]")) return;
|
|
10311
|
+
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
10312
|
+
if (target.closest("[data-ohw-max-badge]")) return;
|
|
10313
|
+
if (isInsideLinkEditor(target)) return;
|
|
10314
|
+
if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
|
|
10315
|
+
return;
|
|
10316
|
+
}
|
|
10317
|
+
const navLabel = getNavigationLabelEditable(target);
|
|
10318
|
+
if (!navLabel) return;
|
|
10319
|
+
const { editable } = navLabel;
|
|
10320
|
+
e.preventDefault();
|
|
10321
|
+
e.stopPropagation();
|
|
10322
|
+
if (activeElRef.current !== editable) {
|
|
10323
|
+
activateRef.current(editable);
|
|
10324
|
+
}
|
|
10325
|
+
requestAnimationFrame(() => {
|
|
10326
|
+
selectAllTextInEditable(editable);
|
|
10327
|
+
refreshActiveCommandsRef.current();
|
|
10328
|
+
});
|
|
10329
|
+
};
|
|
8221
10330
|
const handleMouseOver = (e) => {
|
|
8222
10331
|
if (document.documentElement.hasAttribute("data-ohw-section-picking")) return;
|
|
8223
10332
|
const target = e.target;
|
|
10333
|
+
if (linkPopoverOpenRef.current) {
|
|
10334
|
+
hoveredItemElRef.current = null;
|
|
10335
|
+
setHoveredItemRect(null);
|
|
10336
|
+
hoveredNavContainerRef.current = null;
|
|
10337
|
+
setHoveredNavContainerRect(null);
|
|
10338
|
+
return;
|
|
10339
|
+
}
|
|
8224
10340
|
if (toolbarVariantRef.current !== "select-frame") {
|
|
8225
10341
|
const navContainer = target.closest("[data-ohw-nav-container]");
|
|
8226
10342
|
if (navContainer && !getNavigationItemAnchor(target)) {
|
|
@@ -8240,12 +10356,21 @@ function OhhwellsBridge() {
|
|
|
8240
10356
|
hoveredNavContainerRef.current = null;
|
|
8241
10357
|
setHoveredNavContainerRect(null);
|
|
8242
10358
|
const selected2 = selectedElRef.current;
|
|
8243
|
-
if (selected2 === navAnchor
|
|
10359
|
+
if (selected2 === navAnchor) return;
|
|
8244
10360
|
clearHrefKeyHover(navAnchor);
|
|
8245
10361
|
hoveredItemElRef.current = navAnchor;
|
|
8246
10362
|
setHoveredItemRect(navAnchor.getBoundingClientRect());
|
|
8247
10363
|
return;
|
|
8248
10364
|
}
|
|
10365
|
+
const footerCol = target.closest("[data-ohw-footer-col]") ?? target.closest("[data-ohw-footer-column]");
|
|
10366
|
+
if (footerCol) {
|
|
10367
|
+
hoveredNavContainerRef.current = null;
|
|
10368
|
+
setHoveredNavContainerRect(null);
|
|
10369
|
+
if (selectedElRef.current === footerCol) return;
|
|
10370
|
+
hoveredItemElRef.current = footerCol;
|
|
10371
|
+
setHoveredItemRect(footerCol.getBoundingClientRect());
|
|
10372
|
+
return;
|
|
10373
|
+
}
|
|
8249
10374
|
const editable = target.closest("[data-ohw-editable]");
|
|
8250
10375
|
if (!editable) return;
|
|
8251
10376
|
const selected = selectedElRef.current;
|
|
@@ -8263,14 +10388,25 @@ function OhhwellsBridge() {
|
|
|
8263
10388
|
};
|
|
8264
10389
|
const handleMouseOut = (e) => {
|
|
8265
10390
|
const target = e.target;
|
|
8266
|
-
if (target.closest("[data-ohw-nav-container]")) {
|
|
10391
|
+
if (target.closest("[data-ohw-nav-container], [data-ohw-footer-col], [data-ohw-footer-column]")) {
|
|
8267
10392
|
const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
8268
|
-
if (related2?.closest("[data-ohw-nav-container], [data-ohw-navbar-container-chrome], [data-ohw-navbar-add-button]")) {
|
|
10393
|
+
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]")) {
|
|
8269
10394
|
return;
|
|
8270
10395
|
}
|
|
8271
10396
|
hoveredNavContainerRef.current = null;
|
|
8272
10397
|
setHoveredNavContainerRect(null);
|
|
8273
10398
|
}
|
|
10399
|
+
const footerCol = target.closest("[data-ohw-footer-col]") ?? target.closest("[data-ohw-footer-column]");
|
|
10400
|
+
if (footerCol && hoveredItemElRef.current === footerCol) {
|
|
10401
|
+
const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
10402
|
+
if (related2?.closest("[data-ohw-drag-handle-container], [data-ohw-item-interaction]")) return;
|
|
10403
|
+
if (related2?.closest("[data-ohw-footer-col], [data-ohw-footer-column]") === footerCol) {
|
|
10404
|
+
return;
|
|
10405
|
+
}
|
|
10406
|
+
hoveredItemElRef.current = null;
|
|
10407
|
+
setHoveredItemRect(null);
|
|
10408
|
+
return;
|
|
10409
|
+
}
|
|
8274
10410
|
const navAnchor = getNavigationItemAnchor(target);
|
|
8275
10411
|
if (navAnchor) {
|
|
8276
10412
|
const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
@@ -8404,43 +10540,75 @@ function OhhwellsBridge() {
|
|
|
8404
10540
|
if (toolbarVariantRef.current === "select-frame") {
|
|
8405
10541
|
hoveredNavContainerRef.current = null;
|
|
8406
10542
|
setHoveredNavContainerRect(null);
|
|
8407
|
-
return;
|
|
8408
10543
|
}
|
|
8409
|
-
const
|
|
8410
|
-
|
|
8411
|
-
|
|
8412
|
-
|
|
8413
|
-
|
|
10544
|
+
const navContainers = Array.from(
|
|
10545
|
+
document.querySelectorAll("[data-ohw-nav-container]")
|
|
10546
|
+
);
|
|
10547
|
+
const footerColumns = listFooterColumns();
|
|
10548
|
+
for (const container of [...navContainers, ...footerColumns]) {
|
|
10549
|
+
const containerRect = container.getBoundingClientRect();
|
|
10550
|
+
const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
|
|
10551
|
+
if (!overContainer) continue;
|
|
10552
|
+
const navItemHit = Array.from(
|
|
10553
|
+
container.querySelectorAll("[data-ohw-href-key]")
|
|
10554
|
+
).find((el) => {
|
|
10555
|
+
if (!isNavigationItem(el) || isNavbarButton2(el)) return false;
|
|
10556
|
+
const itemRect = el.getBoundingClientRect();
|
|
10557
|
+
return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
|
|
10558
|
+
});
|
|
10559
|
+
if (navItemHit) {
|
|
10560
|
+
hoveredNavContainerRef.current = null;
|
|
10561
|
+
setHoveredNavContainerRect(null);
|
|
10562
|
+
const selected = selectedElRef.current;
|
|
10563
|
+
if (selected !== navItemHit) {
|
|
10564
|
+
clearHrefKeyHover(navItemHit);
|
|
10565
|
+
hoveredItemElRef.current = navItemHit;
|
|
10566
|
+
setHoveredItemRect(navItemHit.getBoundingClientRect());
|
|
10567
|
+
} else if (hoveredItemElRef.current === navItemHit) {
|
|
10568
|
+
hoveredItemElRef.current = null;
|
|
10569
|
+
setHoveredItemRect(null);
|
|
10570
|
+
}
|
|
10571
|
+
return;
|
|
10572
|
+
}
|
|
8414
10573
|
}
|
|
8415
|
-
|
|
8416
|
-
|
|
8417
|
-
|
|
10574
|
+
if (toolbarVariantRef.current !== "select-frame") {
|
|
10575
|
+
for (const container of navContainers) {
|
|
10576
|
+
const containerRect = container.getBoundingClientRect();
|
|
10577
|
+
const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
|
|
10578
|
+
if (!overContainer) continue;
|
|
10579
|
+
if (isPointOverNavItem(container, x, y)) continue;
|
|
10580
|
+
hoveredNavContainerRef.current = container;
|
|
10581
|
+
setHoveredNavContainerRect(container.getBoundingClientRect());
|
|
10582
|
+
hoveredItemElRef.current = null;
|
|
10583
|
+
setHoveredItemRect(null);
|
|
10584
|
+
return;
|
|
10585
|
+
}
|
|
8418
10586
|
hoveredNavContainerRef.current = null;
|
|
8419
10587
|
setHoveredNavContainerRect(null);
|
|
8420
|
-
|
|
8421
|
-
}
|
|
8422
|
-
const navItemHit = Array.from(
|
|
8423
|
-
navContainer.querySelectorAll("[data-ohw-href-key]")
|
|
8424
|
-
).find((el) => {
|
|
8425
|
-
if (!isNavigationItem(el) || isNavbarButton2(el)) return false;
|
|
8426
|
-
const itemRect = el.getBoundingClientRect();
|
|
8427
|
-
return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
|
|
8428
|
-
});
|
|
8429
|
-
if (navItemHit) {
|
|
10588
|
+
} else {
|
|
8430
10589
|
hoveredNavContainerRef.current = null;
|
|
8431
10590
|
setHoveredNavContainerRect(null);
|
|
8432
|
-
|
|
8433
|
-
|
|
8434
|
-
|
|
8435
|
-
|
|
8436
|
-
|
|
10591
|
+
}
|
|
10592
|
+
for (const column of footerColumns) {
|
|
10593
|
+
const containerRect = column.getBoundingClientRect();
|
|
10594
|
+
const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
|
|
10595
|
+
if (!overContainer) continue;
|
|
10596
|
+
if (isPointOverNavItem(column, x, y)) continue;
|
|
10597
|
+
if (selectedElRef.current === column) {
|
|
10598
|
+
if (hoveredItemElRef.current === column) {
|
|
10599
|
+
hoveredItemElRef.current = null;
|
|
10600
|
+
setHoveredItemRect(null);
|
|
10601
|
+
}
|
|
10602
|
+
return;
|
|
8437
10603
|
}
|
|
10604
|
+
hoveredItemElRef.current = column;
|
|
10605
|
+
setHoveredItemRect(column.getBoundingClientRect());
|
|
8438
10606
|
return;
|
|
8439
10607
|
}
|
|
8440
|
-
|
|
8441
|
-
|
|
8442
|
-
|
|
8443
|
-
|
|
10608
|
+
if (hoveredItemElRef.current?.hasAttribute("data-ohw-footer-col") || hoveredItemElRef.current?.hasAttribute("data-ohw-footer-column")) {
|
|
10609
|
+
hoveredItemElRef.current = null;
|
|
10610
|
+
setHoveredItemRect(null);
|
|
10611
|
+
}
|
|
8444
10612
|
};
|
|
8445
10613
|
const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
|
|
8446
10614
|
if (linkPopoverOpenRef.current) {
|
|
@@ -8461,6 +10629,10 @@ function OhhwellsBridge() {
|
|
|
8461
10629
|
}
|
|
8462
10630
|
hoveredNavContainerRef.current = null;
|
|
8463
10631
|
setHoveredNavContainerRect(null);
|
|
10632
|
+
if (hoveredItemElRef.current?.hasAttribute("data-ohw-footer-col") || hoveredItemElRef.current?.hasAttribute("data-ohw-footer-column")) {
|
|
10633
|
+
hoveredItemElRef.current = null;
|
|
10634
|
+
setHoveredItemRect(null);
|
|
10635
|
+
}
|
|
8464
10636
|
const toggleEl = document.querySelector("[data-ohw-state-toggle]");
|
|
8465
10637
|
if (toggleEl) {
|
|
8466
10638
|
const tr = toggleEl.getBoundingClientRect();
|
|
@@ -8708,6 +10880,15 @@ function OhhwellsBridge() {
|
|
|
8708
10880
|
probeHoverCardsAt(clientX, clientY);
|
|
8709
10881
|
};
|
|
8710
10882
|
const handleDragOver = (e) => {
|
|
10883
|
+
const footerSession = footerDragRef.current;
|
|
10884
|
+
if (footerSession) {
|
|
10885
|
+
e.preventDefault();
|
|
10886
|
+
if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
|
|
10887
|
+
const slot = footerSession.kind === "link" && footerSession.hrefKey ? hitTestLinkDropSlot(e.clientX, e.clientY, footerSession.hrefKey) : hitTestColumnDropSlot(e.clientX, e.clientY);
|
|
10888
|
+
refreshFooterDragVisualsRef.current(footerSession, slot, e.clientX, e.clientY);
|
|
10889
|
+
return;
|
|
10890
|
+
}
|
|
10891
|
+
if (onNavDragOver(e)) return;
|
|
8711
10892
|
e.preventDefault();
|
|
8712
10893
|
const el = findImageAtPoint(e.clientX, e.clientY, false);
|
|
8713
10894
|
if (!el) {
|
|
@@ -8870,8 +11051,8 @@ function OhhwellsBridge() {
|
|
|
8870
11051
|
if (sibling !== el) sibling.innerHTML = html;
|
|
8871
11052
|
});
|
|
8872
11053
|
const timers = autoSaveTimers.current;
|
|
8873
|
-
const
|
|
8874
|
-
if (
|
|
11054
|
+
const existing2 = timers.get(key);
|
|
11055
|
+
if (existing2) clearTimeout(existing2);
|
|
8875
11056
|
timers.set(key, setTimeout(() => {
|
|
8876
11057
|
timers.delete(key);
|
|
8877
11058
|
postToParentRef.current({ type: "ow:change", nodes: [{ key, text: html }] });
|
|
@@ -8914,6 +11095,7 @@ function OhhwellsBridge() {
|
|
|
8914
11095
|
}
|
|
8915
11096
|
editContentRef.current = { ...editContentRef.current, ...content };
|
|
8916
11097
|
reconcileNavbarItemsFromContent(editContentRef.current);
|
|
11098
|
+
syncNavigationDragCursorAttrs();
|
|
8917
11099
|
enforceLinkHrefs();
|
|
8918
11100
|
postToParentRef.current({ type: "ow:hydrate-done" });
|
|
8919
11101
|
};
|
|
@@ -8934,11 +11116,62 @@ function OhhwellsBridge() {
|
|
|
8934
11116
|
if (e.data?.type !== "ui:escape") return;
|
|
8935
11117
|
if (linkPopoverOpenRef.current) {
|
|
8936
11118
|
setLinkPopoverRef.current(null);
|
|
11119
|
+
return;
|
|
11120
|
+
}
|
|
11121
|
+
if (activeElRef.current) {
|
|
11122
|
+
const hrefCtx = getHrefKeyFromElement(activeElRef.current);
|
|
11123
|
+
const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
|
|
11124
|
+
if (navAnchor) {
|
|
11125
|
+
const el = activeElRef.current;
|
|
11126
|
+
if (originalContentRef.current !== null) {
|
|
11127
|
+
el.innerHTML = originalContentRef.current;
|
|
11128
|
+
}
|
|
11129
|
+
el.removeAttribute("contenteditable");
|
|
11130
|
+
el.removeAttribute("data-ohw-editing");
|
|
11131
|
+
activeElRef.current = null;
|
|
11132
|
+
setMaxBadge(null);
|
|
11133
|
+
setActiveCommands(/* @__PURE__ */ new Set());
|
|
11134
|
+
setToolbarShowEditLink(false);
|
|
11135
|
+
postToParentRef.current({ type: "ow:exit-edit" });
|
|
11136
|
+
reselectNavigationItemRef.current(navAnchor);
|
|
11137
|
+
return;
|
|
11138
|
+
}
|
|
11139
|
+
if (originalContentRef.current !== null) {
|
|
11140
|
+
activeElRef.current.innerHTML = originalContentRef.current;
|
|
11141
|
+
const key = activeElRef.current.dataset.ohwKey;
|
|
11142
|
+
if (key) {
|
|
11143
|
+
postToParentRef.current({ type: "ow:change", nodes: [{ key, text: originalContentRef.current }] });
|
|
11144
|
+
}
|
|
11145
|
+
}
|
|
11146
|
+
deselectRef.current();
|
|
11147
|
+
deactivateRef.current();
|
|
11148
|
+
return;
|
|
11149
|
+
}
|
|
11150
|
+
if (selectedElRef.current) {
|
|
11151
|
+
if (toolbarVariantRef.current === "select-frame") {
|
|
11152
|
+
deselectRef.current();
|
|
11153
|
+
return;
|
|
11154
|
+
}
|
|
11155
|
+
const parent = getNavigationSelectionParent(selectedElRef.current);
|
|
11156
|
+
if (parent && isNavigationContainer(parent)) {
|
|
11157
|
+
selectFrameRef.current(parent);
|
|
11158
|
+
} else {
|
|
11159
|
+
deselectRef.current();
|
|
11160
|
+
}
|
|
8937
11161
|
}
|
|
8938
11162
|
};
|
|
8939
11163
|
window.addEventListener("message", handleUiEscape);
|
|
8940
11164
|
const handleKeyDown = (e) => {
|
|
8941
11165
|
if (e.key === "Escape" && document.querySelector("[data-ohw-section-picker]")) return;
|
|
11166
|
+
if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a" && activeElRef.current) {
|
|
11167
|
+
const navAnchor = getNavigationItemAnchor(activeElRef.current);
|
|
11168
|
+
if (navAnchor) {
|
|
11169
|
+
e.preventDefault();
|
|
11170
|
+
selectAllTextInEditable(activeElRef.current);
|
|
11171
|
+
refreshActiveCommandsRef.current();
|
|
11172
|
+
return;
|
|
11173
|
+
}
|
|
11174
|
+
}
|
|
8942
11175
|
if (e.key === "Escape" && linkPopoverOpenRef.current) {
|
|
8943
11176
|
setLinkPopoverRef.current(null);
|
|
8944
11177
|
return;
|
|
@@ -8949,7 +11182,7 @@ function OhhwellsBridge() {
|
|
|
8949
11182
|
return;
|
|
8950
11183
|
}
|
|
8951
11184
|
const parent = getNavigationSelectionParent(selectedElRef.current);
|
|
8952
|
-
if (parent) {
|
|
11185
|
+
if (parent && isNavigationContainer(parent)) {
|
|
8953
11186
|
e.preventDefault();
|
|
8954
11187
|
selectFrameRef.current(parent);
|
|
8955
11188
|
} else {
|
|
@@ -8967,6 +11200,7 @@ function OhhwellsBridge() {
|
|
|
8967
11200
|
el2.innerHTML = originalContentRef.current;
|
|
8968
11201
|
}
|
|
8969
11202
|
el2.removeAttribute("contenteditable");
|
|
11203
|
+
el2.removeAttribute("data-ohw-editing");
|
|
8970
11204
|
activeElRef.current = null;
|
|
8971
11205
|
setMaxBadge(null);
|
|
8972
11206
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
@@ -9018,6 +11252,26 @@ function OhhwellsBridge() {
|
|
|
9018
11252
|
if (siblingHintElRef.current) {
|
|
9019
11253
|
setSiblingHintRect(siblingHintElRef.current.getBoundingClientRect());
|
|
9020
11254
|
}
|
|
11255
|
+
const selected = selectedElRef.current;
|
|
11256
|
+
if (selected && !footerDragRef.current && !navDragRef.current) {
|
|
11257
|
+
if (selected.hasAttribute("data-ohw-footer-col") || Boolean(selected.closest("footer") && isInferredFooterGroup(selected))) {
|
|
11258
|
+
setSiblingHintRects(
|
|
11259
|
+
listFooterColumns().filter((column) => column !== selected).map((column) => column.getBoundingClientRect())
|
|
11260
|
+
);
|
|
11261
|
+
} else if (isNavigationItem(selected)) {
|
|
11262
|
+
setSiblingHintRects(collectNavigationItemSiblingHintRects(selected));
|
|
11263
|
+
}
|
|
11264
|
+
}
|
|
11265
|
+
if (footerDragRef.current) {
|
|
11266
|
+
const session = footerDragRef.current;
|
|
11267
|
+
const slot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : hitTestColumnDropSlot(session.lastClientX, session.lastClientY);
|
|
11268
|
+
refreshFooterDragVisualsRef.current(session, slot, session.lastClientX, session.lastClientY);
|
|
11269
|
+
}
|
|
11270
|
+
if (navDragRef.current) {
|
|
11271
|
+
const session = navDragRef.current;
|
|
11272
|
+
const slot = hitTestNavDropSlot(session.lastClientX, session.lastClientY, session.hrefKey);
|
|
11273
|
+
refreshNavDragVisualsRef.current(session, slot, session.lastClientX, session.lastClientY);
|
|
11274
|
+
}
|
|
9021
11275
|
if (hoveredImageRef.current) {
|
|
9022
11276
|
const el = hoveredImageRef.current;
|
|
9023
11277
|
const r2 = el.getBoundingClientRect();
|
|
@@ -9028,7 +11282,7 @@ function OhhwellsBridge() {
|
|
|
9028
11282
|
};
|
|
9029
11283
|
const handleSave = (e) => {
|
|
9030
11284
|
if (e.data?.type !== "ow:save") return;
|
|
9031
|
-
const nodes = collectEditableNodes();
|
|
11285
|
+
const nodes = collectEditableNodes(editContentRef.current);
|
|
9032
11286
|
const tracker = document.querySelector("[data-ohw-sections-tracker]");
|
|
9033
11287
|
if (tracker?.textContent) nodes.push({ key: "__ohw_sections", type: "sections", text: tracker.textContent });
|
|
9034
11288
|
postToParentRef.current({ type: "ow:save-result", nodes });
|
|
@@ -9086,30 +11340,83 @@ function OhhwellsBridge() {
|
|
|
9086
11340
|
const h = document.documentElement.scrollHeight;
|
|
9087
11341
|
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
9088
11342
|
};
|
|
9089
|
-
|
|
9090
|
-
|
|
11343
|
+
let selectionChangeRaf = null;
|
|
11344
|
+
const runSelectionChange = () => {
|
|
11345
|
+
selectionChangeRaf = null;
|
|
11346
|
+
const activeRoot = activeElRef.current;
|
|
11347
|
+
if (!activeRoot) return;
|
|
9091
11348
|
const next = /* @__PURE__ */ new Set();
|
|
9092
|
-
|
|
9093
|
-
|
|
9094
|
-
|
|
9095
|
-
|
|
11349
|
+
const sel = window.getSelection();
|
|
11350
|
+
let startNode = null;
|
|
11351
|
+
if (sel && sel.rangeCount > 0) {
|
|
11352
|
+
const range = sel.getRangeAt(0);
|
|
11353
|
+
startNode = range.startContainer;
|
|
11354
|
+
if (startNode.nodeType === Node.ELEMENT_NODE) {
|
|
11355
|
+
const el = startNode;
|
|
11356
|
+
startNode = el.childNodes[range.startOffset] ?? el.childNodes[range.startOffset - 1] ?? el;
|
|
9096
11357
|
}
|
|
9097
11358
|
}
|
|
9098
|
-
const
|
|
9099
|
-
|
|
9100
|
-
|
|
9101
|
-
const
|
|
9102
|
-
|
|
9103
|
-
|
|
9104
|
-
|
|
9105
|
-
|
|
9106
|
-
|
|
9107
|
-
|
|
11359
|
+
const startEl = startNode ? startNode.nodeType === Node.TEXT_NODE ? startNode.parentElement : startNode : null;
|
|
11360
|
+
if (startEl) {
|
|
11361
|
+
const cs = getComputedStyle(startEl);
|
|
11362
|
+
const weight = parseInt(cs.fontWeight, 10);
|
|
11363
|
+
let hasBold = cs.fontWeight === "bold" || !Number.isNaN(weight) && weight >= 600;
|
|
11364
|
+
let hasItalic = cs.fontStyle === "italic" || cs.fontStyle === "oblique";
|
|
11365
|
+
let hasUnderline = false;
|
|
11366
|
+
let hasStrike = false;
|
|
11367
|
+
let hasUl = false;
|
|
11368
|
+
let hasOl = false;
|
|
11369
|
+
for (let el = startEl; el; el = el.parentElement) {
|
|
11370
|
+
if (el.tagName === "B" || el.tagName === "STRONG") hasBold = true;
|
|
11371
|
+
if (el.tagName === "I" || el.tagName === "EM") hasItalic = true;
|
|
11372
|
+
const decoration = getComputedStyle(el).textDecorationLine;
|
|
11373
|
+
if (decoration.includes("underline") || el.tagName === "U" || el.tagName === "INS") hasUnderline = true;
|
|
11374
|
+
if (decoration.includes("line-through") || el.tagName === "S" || el.tagName === "STRIKE" || el.tagName === "DEL") hasStrike = true;
|
|
11375
|
+
if (el.tagName === "UL") hasUl = true;
|
|
11376
|
+
if (el.tagName === "OL") hasOl = true;
|
|
11377
|
+
if (el === activeRoot) break;
|
|
9108
11378
|
}
|
|
11379
|
+
if (hasBold) next.add("bold");
|
|
11380
|
+
if (hasItalic) next.add("italic");
|
|
11381
|
+
if (hasUnderline) next.add("underline");
|
|
11382
|
+
if (hasStrike) next.add("strikeThrough");
|
|
11383
|
+
if (hasUl) next.add("insertUnorderedList");
|
|
11384
|
+
if (hasOl) next.add("insertOrderedList");
|
|
11385
|
+
const block = startEl.closest("div, p, h1, h2, h3, h4, h5, h6, li, td, th") ?? startEl;
|
|
11386
|
+
const align = getComputedStyle(block).textAlign;
|
|
11387
|
+
if (align === "center") next.add("justifyCenter");
|
|
11388
|
+
else if (align === "right" || align === "end") next.add("justifyRight");
|
|
11389
|
+
else next.add("justifyLeft");
|
|
9109
11390
|
}
|
|
9110
|
-
setActiveCommands(
|
|
11391
|
+
setActiveCommands((prev) => {
|
|
11392
|
+
if (prev.size === next.size) {
|
|
11393
|
+
let same = true;
|
|
11394
|
+
for (const cmd of prev) {
|
|
11395
|
+
if (!next.has(cmd)) {
|
|
11396
|
+
same = false;
|
|
11397
|
+
break;
|
|
11398
|
+
}
|
|
11399
|
+
}
|
|
11400
|
+
if (same) return prev;
|
|
11401
|
+
}
|
|
11402
|
+
return next;
|
|
11403
|
+
});
|
|
11404
|
+
};
|
|
11405
|
+
const handleSelectionChange = () => {
|
|
11406
|
+
if (pointerHeldRef.current) return;
|
|
11407
|
+
if (selectionChangeRaf !== null) return;
|
|
11408
|
+
selectionChangeRaf = requestAnimationFrame(runSelectionChange);
|
|
11409
|
+
};
|
|
11410
|
+
const markPointerHeld = (e) => {
|
|
11411
|
+
if (e.button !== 0) return;
|
|
11412
|
+
pointerHeldRef.current = true;
|
|
9111
11413
|
};
|
|
9112
|
-
|
|
11414
|
+
const markPointerReleased = () => {
|
|
11415
|
+
if (!pointerHeldRef.current) return;
|
|
11416
|
+
pointerHeldRef.current = false;
|
|
11417
|
+
handleSelectionChange();
|
|
11418
|
+
};
|
|
11419
|
+
refreshActiveCommandsRef.current = runSelectionChange;
|
|
9113
11420
|
const handleDocMouseLeave = () => {
|
|
9114
11421
|
hoveredImageRef.current = null;
|
|
9115
11422
|
setMediaHover(null);
|
|
@@ -9154,15 +11461,15 @@ function OhhwellsBridge() {
|
|
|
9154
11461
|
};
|
|
9155
11462
|
const applyToolbarPos = (rect) => {
|
|
9156
11463
|
const ps = parentScrollRef.current;
|
|
9157
|
-
const
|
|
11464
|
+
const measuredW = toolbarElRef.current?.offsetWidth || 330;
|
|
9158
11465
|
if (toolbarElRef.current) {
|
|
9159
|
-
const { top, left, transform } = calcToolbarPos(rect, ps,
|
|
11466
|
+
const { top, left, transform } = calcToolbarPos(rect, ps, measuredW);
|
|
9160
11467
|
toolbarElRef.current.style.top = `${top}px`;
|
|
9161
11468
|
toolbarElRef.current.style.left = `${left}px`;
|
|
9162
11469
|
toolbarElRef.current.style.transform = transform;
|
|
9163
11470
|
}
|
|
9164
11471
|
if (glowElRef.current) {
|
|
9165
|
-
const GAP =
|
|
11472
|
+
const GAP = SELECTION_CHROME_GAP2;
|
|
9166
11473
|
glowElRef.current.style.top = `${rect.top - GAP}px`;
|
|
9167
11474
|
glowElRef.current.style.left = `${rect.left - GAP}px`;
|
|
9168
11475
|
glowElRef.current.style.width = `${rect.width + GAP * 2}px`;
|
|
@@ -9250,6 +11557,11 @@ function OhhwellsBridge() {
|
|
|
9250
11557
|
return;
|
|
9251
11558
|
}
|
|
9252
11559
|
}
|
|
11560
|
+
const footerColumn = findHoveredNavOrFooterContainer(clientX, clientY);
|
|
11561
|
+
if (footerColumn?.hasAttribute("data-ohw-footer-col") || footerColumn?.hasAttribute("data-ohw-footer-column")) {
|
|
11562
|
+
selectFrameRef.current(footerColumn);
|
|
11563
|
+
return;
|
|
11564
|
+
}
|
|
9253
11565
|
deactivateRef.current();
|
|
9254
11566
|
};
|
|
9255
11567
|
window.addEventListener("message", handleSave);
|
|
@@ -9271,6 +11583,7 @@ function OhhwellsBridge() {
|
|
|
9271
11583
|
};
|
|
9272
11584
|
window.addEventListener("resize", handleViewportResize, { passive: true });
|
|
9273
11585
|
document.addEventListener("click", handleClick, true);
|
|
11586
|
+
document.addEventListener("dblclick", handleDblClick, true);
|
|
9274
11587
|
document.addEventListener("paste", handlePaste, true);
|
|
9275
11588
|
document.addEventListener("input", handleInput, true);
|
|
9276
11589
|
document.addEventListener("mouseover", handleMouseOver, true);
|
|
@@ -9285,6 +11598,7 @@ function OhhwellsBridge() {
|
|
|
9285
11598
|
window.addEventListener("scroll", handleScroll, true);
|
|
9286
11599
|
return () => {
|
|
9287
11600
|
document.removeEventListener("click", handleClick, true);
|
|
11601
|
+
document.removeEventListener("dblclick", handleDblClick, true);
|
|
9288
11602
|
document.removeEventListener("paste", handlePaste, true);
|
|
9289
11603
|
document.removeEventListener("input", handleInput, true);
|
|
9290
11604
|
document.removeEventListener("mouseover", handleMouseOver, true);
|
|
@@ -9319,7 +11633,177 @@ function OhhwellsBridge() {
|
|
|
9319
11633
|
if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
|
|
9320
11634
|
};
|
|
9321
11635
|
}, [isEditMode, refreshStateRules]);
|
|
9322
|
-
|
|
11636
|
+
useEffect8(() => {
|
|
11637
|
+
if (!isEditMode) return;
|
|
11638
|
+
const THRESHOLD = 10;
|
|
11639
|
+
const resolveWasSelected = (el) => {
|
|
11640
|
+
if (selectedElRef.current === el) return true;
|
|
11641
|
+
const activeAnchor = activeElRef.current ? getNavigationItemAnchor(activeElRef.current) : null;
|
|
11642
|
+
return activeAnchor === el;
|
|
11643
|
+
};
|
|
11644
|
+
const onPointerDown = (e) => {
|
|
11645
|
+
if (e.button !== 0) return;
|
|
11646
|
+
if (suppressNextClickRef.current && Date.now() >= suppressClickUntilRef.current && !footerDragRef.current && !footerPointerDragRef.current?.started) {
|
|
11647
|
+
suppressNextClickRef.current = false;
|
|
11648
|
+
}
|
|
11649
|
+
if (footerDragRef.current) return;
|
|
11650
|
+
const target = e.target;
|
|
11651
|
+
if (!target) return;
|
|
11652
|
+
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]')) {
|
|
11653
|
+
return;
|
|
11654
|
+
}
|
|
11655
|
+
if (target.closest("[data-ohw-item-drag-surface]")) return;
|
|
11656
|
+
const anchor = getNavigationItemAnchor(target);
|
|
11657
|
+
const hrefKey = anchor?.getAttribute("data-ohw-href-key") ?? null;
|
|
11658
|
+
if (anchor && isFooterHrefKey(hrefKey)) {
|
|
11659
|
+
footerPointerDragRef.current = {
|
|
11660
|
+
el: anchor,
|
|
11661
|
+
kind: "link",
|
|
11662
|
+
startX: e.clientX,
|
|
11663
|
+
startY: e.clientY,
|
|
11664
|
+
pointerId: e.pointerId,
|
|
11665
|
+
wasSelected: resolveWasSelected(anchor),
|
|
11666
|
+
started: false
|
|
11667
|
+
};
|
|
11668
|
+
return;
|
|
11669
|
+
}
|
|
11670
|
+
const col = target.closest("[data-ohw-footer-col]");
|
|
11671
|
+
if (col && !getNavigationItemAnchor(target)) {
|
|
11672
|
+
footerPointerDragRef.current = {
|
|
11673
|
+
el: col,
|
|
11674
|
+
kind: "column",
|
|
11675
|
+
startX: e.clientX,
|
|
11676
|
+
startY: e.clientY,
|
|
11677
|
+
pointerId: e.pointerId,
|
|
11678
|
+
wasSelected: resolveWasSelected(col),
|
|
11679
|
+
started: false
|
|
11680
|
+
};
|
|
11681
|
+
}
|
|
11682
|
+
};
|
|
11683
|
+
const onPointerMove = (e) => {
|
|
11684
|
+
const pending = footerPointerDragRef.current;
|
|
11685
|
+
if (!pending) return;
|
|
11686
|
+
if (pending.started) {
|
|
11687
|
+
e.preventDefault();
|
|
11688
|
+
clearTextSelection();
|
|
11689
|
+
const session = footerDragRef.current;
|
|
11690
|
+
if (!session) return;
|
|
11691
|
+
const slot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(e.clientX, e.clientY, session.hrefKey) : hitTestColumnDropSlot(e.clientX, e.clientY);
|
|
11692
|
+
refreshFooterDragVisualsRef.current(session, slot, e.clientX, e.clientY);
|
|
11693
|
+
return;
|
|
11694
|
+
}
|
|
11695
|
+
const dx = e.clientX - pending.startX;
|
|
11696
|
+
const dy = e.clientY - pending.startY;
|
|
11697
|
+
if (dx * dx + dy * dy < THRESHOLD * THRESHOLD) return;
|
|
11698
|
+
e.preventDefault();
|
|
11699
|
+
pending.started = true;
|
|
11700
|
+
armFooterPressDrag();
|
|
11701
|
+
clearTextSelection();
|
|
11702
|
+
try {
|
|
11703
|
+
document.body.setPointerCapture(pending.pointerId);
|
|
11704
|
+
} catch {
|
|
11705
|
+
}
|
|
11706
|
+
if (linkPopoverOpenRef.current) {
|
|
11707
|
+
setLinkPopoverRef.current(null);
|
|
11708
|
+
}
|
|
11709
|
+
if (activeElRef.current) {
|
|
11710
|
+
deactivateRef.current();
|
|
11711
|
+
}
|
|
11712
|
+
if (pending.kind === "link") {
|
|
11713
|
+
const key = pending.el.getAttribute("data-ohw-href-key");
|
|
11714
|
+
if (!key) return;
|
|
11715
|
+
const column = findFooterColumnForLink(pending.el);
|
|
11716
|
+
const columns2 = listFooterColumns();
|
|
11717
|
+
beginFooterDragRef.current({
|
|
11718
|
+
kind: "link",
|
|
11719
|
+
hrefKey: key,
|
|
11720
|
+
columnEl: column,
|
|
11721
|
+
sourceColumnIndex: column ? columns2.indexOf(column) : 0,
|
|
11722
|
+
wasSelected: pending.wasSelected,
|
|
11723
|
+
draggedEl: pending.el,
|
|
11724
|
+
lastClientX: e.clientX,
|
|
11725
|
+
lastClientY: e.clientY,
|
|
11726
|
+
activeSlot: null
|
|
11727
|
+
});
|
|
11728
|
+
return;
|
|
11729
|
+
}
|
|
11730
|
+
const columns = listFooterColumns();
|
|
11731
|
+
const idx = columns.indexOf(pending.el);
|
|
11732
|
+
if (idx < 0) return;
|
|
11733
|
+
beginFooterDragRef.current({
|
|
11734
|
+
kind: "column",
|
|
11735
|
+
hrefKey: null,
|
|
11736
|
+
columnEl: pending.el,
|
|
11737
|
+
sourceColumnIndex: idx,
|
|
11738
|
+
wasSelected: pending.wasSelected,
|
|
11739
|
+
draggedEl: pending.el,
|
|
11740
|
+
lastClientX: e.clientX,
|
|
11741
|
+
lastClientY: e.clientY,
|
|
11742
|
+
activeSlot: null
|
|
11743
|
+
});
|
|
11744
|
+
};
|
|
11745
|
+
const endPointerDrag = (e) => {
|
|
11746
|
+
const pending = footerPointerDragRef.current;
|
|
11747
|
+
footerPointerDragRef.current = null;
|
|
11748
|
+
try {
|
|
11749
|
+
if (document.body.hasPointerCapture(e.pointerId)) {
|
|
11750
|
+
document.body.releasePointerCapture(e.pointerId);
|
|
11751
|
+
}
|
|
11752
|
+
} catch {
|
|
11753
|
+
}
|
|
11754
|
+
if (!pending) return;
|
|
11755
|
+
if (!pending.started) {
|
|
11756
|
+
unlockFooterDragInteraction();
|
|
11757
|
+
return;
|
|
11758
|
+
}
|
|
11759
|
+
suppressNextClickRef.current = true;
|
|
11760
|
+
suppressClickUntilRef.current = Date.now() + 500;
|
|
11761
|
+
commitFooterDragRef.current(e.clientX, e.clientY);
|
|
11762
|
+
};
|
|
11763
|
+
const blockSelectStart = (e) => {
|
|
11764
|
+
if (footerDragRef.current || footerPointerDragRef.current?.started || document.documentElement.hasAttribute("data-ohw-footer-press-drag")) {
|
|
11765
|
+
e.preventDefault();
|
|
11766
|
+
}
|
|
11767
|
+
};
|
|
11768
|
+
const onDragEnd = (_e) => {
|
|
11769
|
+
if (!footerDragRef.current) return;
|
|
11770
|
+
suppressNextClickRef.current = true;
|
|
11771
|
+
suppressClickUntilRef.current = Date.now() + 500;
|
|
11772
|
+
commitFooterDragRef.current();
|
|
11773
|
+
};
|
|
11774
|
+
document.addEventListener("pointerdown", onPointerDown, true);
|
|
11775
|
+
document.addEventListener("pointermove", onPointerMove, true);
|
|
11776
|
+
document.addEventListener("pointerup", endPointerDrag, true);
|
|
11777
|
+
document.addEventListener("pointercancel", endPointerDrag, true);
|
|
11778
|
+
document.addEventListener("selectstart", blockSelectStart, true);
|
|
11779
|
+
document.addEventListener("dragend", onDragEnd, true);
|
|
11780
|
+
return () => {
|
|
11781
|
+
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
11782
|
+
document.removeEventListener("pointermove", onPointerMove, true);
|
|
11783
|
+
document.removeEventListener("pointerup", endPointerDrag, true);
|
|
11784
|
+
document.removeEventListener("pointercancel", endPointerDrag, true);
|
|
11785
|
+
document.removeEventListener("selectstart", blockSelectStart, true);
|
|
11786
|
+
document.removeEventListener("dragend", onDragEnd, true);
|
|
11787
|
+
unlockFooterDragInteraction();
|
|
11788
|
+
};
|
|
11789
|
+
}, [isEditMode]);
|
|
11790
|
+
useEffect8(() => {
|
|
11791
|
+
if (!isEditMode) return;
|
|
11792
|
+
const debugSelectionChange = () => {
|
|
11793
|
+
const sel = window.getSelection();
|
|
11794
|
+
console.log(
|
|
11795
|
+
"[OHW DEBUG selectionchange]",
|
|
11796
|
+
JSON.stringify(sel?.toString() ?? ""),
|
|
11797
|
+
"collapsed=",
|
|
11798
|
+
sel?.isCollapsed,
|
|
11799
|
+
"anchorNode=",
|
|
11800
|
+
sel?.anchorNode,
|
|
11801
|
+
"activeEl=",
|
|
11802
|
+
activeElRef.current
|
|
11803
|
+
);
|
|
11804
|
+
};
|
|
11805
|
+
}, [isEditMode]);
|
|
11806
|
+
useEffect8(() => {
|
|
9323
11807
|
const handler = (e) => {
|
|
9324
11808
|
if (e.data?.type !== "ow:request-schedule-config") return;
|
|
9325
11809
|
const insertAfterVal = e.data.insertAfter;
|
|
@@ -9335,7 +11819,7 @@ function OhhwellsBridge() {
|
|
|
9335
11819
|
window.addEventListener("message", handler);
|
|
9336
11820
|
return () => window.removeEventListener("message", handler);
|
|
9337
11821
|
}, [processConfigRequest]);
|
|
9338
|
-
|
|
11822
|
+
useEffect8(() => {
|
|
9339
11823
|
if (!isEditMode) return;
|
|
9340
11824
|
document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
|
|
9341
11825
|
el.removeAttribute("data-ohw-active-state");
|
|
@@ -9356,7 +11840,13 @@ function OhhwellsBridge() {
|
|
|
9356
11840
|
const next = { ...prev, [pathKey]: sections };
|
|
9357
11841
|
return shouldUseDevFixtures() ? { ...DEV_SECTIONS_BY_PATH, ...next } : next;
|
|
9358
11842
|
});
|
|
9359
|
-
postToParent2({
|
|
11843
|
+
postToParent2({
|
|
11844
|
+
type: "ow:ready",
|
|
11845
|
+
version: "1",
|
|
11846
|
+
path: pathname,
|
|
11847
|
+
nodes: collectEditableNodes(editContentRef.current),
|
|
11848
|
+
sections
|
|
11849
|
+
});
|
|
9360
11850
|
postToParent2({ type: "ow:request-site-pages" });
|
|
9361
11851
|
}, 150);
|
|
9362
11852
|
return () => {
|
|
@@ -9364,19 +11854,20 @@ function OhhwellsBridge() {
|
|
|
9364
11854
|
clearTimeout(timer);
|
|
9365
11855
|
};
|
|
9366
11856
|
}, [pathname, isEditMode, refreshStateRules, postToParent2]);
|
|
9367
|
-
|
|
11857
|
+
useEffect8(() => {
|
|
9368
11858
|
scrollToHashSectionWhenReady();
|
|
9369
11859
|
const onHashChange = () => scrollToHashSectionWhenReady();
|
|
9370
11860
|
window.addEventListener("hashchange", onHashChange);
|
|
9371
11861
|
return () => window.removeEventListener("hashchange", onHashChange);
|
|
9372
11862
|
}, [pathname]);
|
|
9373
|
-
const handleCommand =
|
|
11863
|
+
const handleCommand = useCallback5((cmd) => {
|
|
11864
|
+
document.execCommand("styleWithCSS", false, true);
|
|
9374
11865
|
document.execCommand(cmd, false);
|
|
9375
11866
|
activeElRef.current?.focus();
|
|
9376
11867
|
if (activeElRef.current) setToolbarRect(getEditMeasureEl(activeElRef.current).getBoundingClientRect());
|
|
9377
11868
|
refreshActiveCommandsRef.current();
|
|
9378
11869
|
}, []);
|
|
9379
|
-
const handleStateChange =
|
|
11870
|
+
const handleStateChange = useCallback5((state) => {
|
|
9380
11871
|
if (!activeStateElRef.current) return;
|
|
9381
11872
|
const el = activeStateElRef.current;
|
|
9382
11873
|
if (state === "Default") {
|
|
@@ -9389,11 +11880,11 @@ function OhhwellsBridge() {
|
|
|
9389
11880
|
}
|
|
9390
11881
|
setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
|
|
9391
11882
|
}, [deactivate]);
|
|
9392
|
-
const closeLinkPopover =
|
|
11883
|
+
const closeLinkPopover = useCallback5(() => {
|
|
9393
11884
|
addNavAfterAnchorRef.current = null;
|
|
9394
11885
|
setLinkPopover(null);
|
|
9395
11886
|
}, []);
|
|
9396
|
-
const openLinkPopoverForActive =
|
|
11887
|
+
const openLinkPopoverForActive = useCallback5(() => {
|
|
9397
11888
|
const hrefCtx = getHrefKeyFromElement(activeElRef.current);
|
|
9398
11889
|
if (!hrefCtx) return;
|
|
9399
11890
|
bumpLinkPopoverGrace();
|
|
@@ -9404,7 +11895,7 @@ function OhhwellsBridge() {
|
|
|
9404
11895
|
});
|
|
9405
11896
|
deactivate();
|
|
9406
11897
|
}, [deactivate]);
|
|
9407
|
-
const openLinkPopoverForSelected =
|
|
11898
|
+
const openLinkPopoverForSelected = useCallback5(() => {
|
|
9408
11899
|
const anchor = selectedElRef.current;
|
|
9409
11900
|
if (!anchor) return;
|
|
9410
11901
|
const key = anchor.getAttribute("data-ohw-href-key");
|
|
@@ -9417,7 +11908,7 @@ function OhhwellsBridge() {
|
|
|
9417
11908
|
});
|
|
9418
11909
|
deselect();
|
|
9419
11910
|
}, [deselect]);
|
|
9420
|
-
const handleLinkPopoverSubmit =
|
|
11911
|
+
const handleLinkPopoverSubmit = useCallback5(
|
|
9421
11912
|
(target) => {
|
|
9422
11913
|
const session = linkPopoverSessionRef.current;
|
|
9423
11914
|
if (!session) return;
|
|
@@ -9476,13 +11967,13 @@ function OhhwellsBridge() {
|
|
|
9476
11967
|
const showEditLink = toolbarShowEditLink;
|
|
9477
11968
|
const currentSections = sectionsByPath[pathname] ?? [];
|
|
9478
11969
|
linkPopoverOpenRef.current = linkPopover !== null;
|
|
9479
|
-
const handleMediaReplace =
|
|
11970
|
+
const handleMediaReplace = useCallback5(
|
|
9480
11971
|
(key) => {
|
|
9481
11972
|
postToParent2({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
|
|
9482
11973
|
},
|
|
9483
11974
|
[postToParent2, mediaHover?.elementType]
|
|
9484
11975
|
);
|
|
9485
|
-
const handleMediaFadeOutComplete =
|
|
11976
|
+
const handleMediaFadeOutComplete = useCallback5((key) => {
|
|
9486
11977
|
setUploadingRects((prev) => {
|
|
9487
11978
|
if (!(key in prev)) return prev;
|
|
9488
11979
|
const next = { ...prev };
|
|
@@ -9490,7 +11981,7 @@ function OhhwellsBridge() {
|
|
|
9490
11981
|
return next;
|
|
9491
11982
|
});
|
|
9492
11983
|
}, []);
|
|
9493
|
-
const handleVideoSettingsChange =
|
|
11984
|
+
const handleVideoSettingsChange = useCallback5(
|
|
9494
11985
|
(key, settings) => {
|
|
9495
11986
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
9496
11987
|
const video = getVideoEl(el);
|
|
@@ -9514,8 +12005,8 @@ function OhhwellsBridge() {
|
|
|
9514
12005
|
);
|
|
9515
12006
|
return bridgeRoot ? createPortal2(
|
|
9516
12007
|
/* @__PURE__ */ jsxs13(Fragment5, { children: [
|
|
9517
|
-
/* @__PURE__ */
|
|
9518
|
-
Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */
|
|
12008
|
+
/* @__PURE__ */ jsx24("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
|
|
12009
|
+
Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ jsx24(
|
|
9519
12010
|
MediaOverlay,
|
|
9520
12011
|
{
|
|
9521
12012
|
hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
|
|
@@ -9526,7 +12017,7 @@ function OhhwellsBridge() {
|
|
|
9526
12017
|
},
|
|
9527
12018
|
`uploading-${key}`
|
|
9528
12019
|
)),
|
|
9529
|
-
mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */
|
|
12020
|
+
mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ jsx24(
|
|
9530
12021
|
MediaOverlay,
|
|
9531
12022
|
{
|
|
9532
12023
|
hover: mediaHover,
|
|
@@ -9535,49 +12026,93 @@ function OhhwellsBridge() {
|
|
|
9535
12026
|
onVideoSettingsChange: handleVideoSettingsChange
|
|
9536
12027
|
}
|
|
9537
12028
|
),
|
|
9538
|
-
siblingHintRect && !isItemDragging && /* @__PURE__ */
|
|
9539
|
-
|
|
9540
|
-
|
|
9541
|
-
|
|
12029
|
+
siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ jsx24(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
|
|
12030
|
+
siblingHintRects.length > 0 && !linkPopover && siblingHintRects.map((rect, i) => /* @__PURE__ */ jsx24(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
|
|
12031
|
+
isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ jsx24(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
|
|
12032
|
+
isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ jsx24(
|
|
12033
|
+
"div",
|
|
9542
12034
|
{
|
|
9543
|
-
|
|
9544
|
-
|
|
9545
|
-
|
|
9546
|
-
|
|
9547
|
-
|
|
9548
|
-
|
|
12035
|
+
className: "pointer-events-none fixed z-2147483646",
|
|
12036
|
+
style: {
|
|
12037
|
+
left: slot.left,
|
|
12038
|
+
top: slot.top,
|
|
12039
|
+
width: slot.width,
|
|
12040
|
+
height: slot.height
|
|
12041
|
+
},
|
|
12042
|
+
children: /* @__PURE__ */ jsx24(
|
|
12043
|
+
DropIndicator,
|
|
12044
|
+
{
|
|
12045
|
+
direction: slot.direction,
|
|
12046
|
+
state: activeFooterDropIndex === i ? "dragActive" : "dragIdle",
|
|
12047
|
+
className: "!h-full !w-full"
|
|
12048
|
+
}
|
|
12049
|
+
)
|
|
12050
|
+
},
|
|
12051
|
+
`footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
|
|
12052
|
+
)),
|
|
12053
|
+
isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ jsx24(
|
|
12054
|
+
"div",
|
|
12055
|
+
{
|
|
12056
|
+
className: "pointer-events-none fixed z-2147483646",
|
|
12057
|
+
style: {
|
|
12058
|
+
left: slot.left,
|
|
12059
|
+
top: slot.top,
|
|
12060
|
+
width: slot.width,
|
|
12061
|
+
height: slot.height
|
|
12062
|
+
},
|
|
12063
|
+
children: /* @__PURE__ */ jsx24(
|
|
12064
|
+
DropIndicator,
|
|
12065
|
+
{
|
|
12066
|
+
direction: slot.direction,
|
|
12067
|
+
state: activeNavDropIndex === i ? "dragActive" : "dragIdle",
|
|
12068
|
+
className: "!h-full !w-full"
|
|
12069
|
+
}
|
|
12070
|
+
)
|
|
12071
|
+
},
|
|
12072
|
+
`nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
|
|
12073
|
+
)),
|
|
12074
|
+
hoveredNavContainerRect && toolbarVariant !== "select-frame" && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx24(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
|
|
12075
|
+
hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx24(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
|
|
12076
|
+
toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer(selectedElRef.current) && /* @__PURE__ */ jsx24(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
|
|
12077
|
+
toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ jsx24(
|
|
9549
12078
|
ItemInteractionLayer,
|
|
9550
12079
|
{
|
|
9551
|
-
rect: toolbarRect,
|
|
12080
|
+
rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
|
|
9552
12081
|
elRef: glowElRef,
|
|
9553
12082
|
state: isItemDragging ? "dragging" : resolveItemInteractionState(toolbarRect, parentScrollRef.current),
|
|
9554
|
-
showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey),
|
|
12083
|
+
showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey) || toolbarVariant === "select-frame" && isFooterFrameSelection,
|
|
9555
12084
|
dragDisabled: reorderDragDisabled,
|
|
9556
12085
|
dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
|
|
9557
12086
|
onDragHandleDragStart: handleItemDragStart,
|
|
9558
12087
|
onDragHandleDragEnd: handleItemDragEnd,
|
|
9559
|
-
|
|
12088
|
+
onItemPointerDown: handleItemChromePointerDown,
|
|
12089
|
+
onItemClick: handleItemChromeClick,
|
|
12090
|
+
itemDragSurface: !isFooterFrameSelection,
|
|
12091
|
+
toolbar: toolbarVariant === "link-action" && !isItemDragging ? /* @__PURE__ */ jsx24(
|
|
9560
12092
|
ItemActionToolbar,
|
|
9561
12093
|
{
|
|
9562
12094
|
onEditLink: openLinkPopoverForSelected,
|
|
9563
12095
|
addItemDisabled: true,
|
|
9564
12096
|
editLinkDisabled: false,
|
|
9565
|
-
moreDisabled: true
|
|
12097
|
+
moreDisabled: true,
|
|
12098
|
+
showAddItem: !selectedIsCta,
|
|
12099
|
+
showMore: !selectedIsCta
|
|
9566
12100
|
}
|
|
9567
12101
|
) : void 0
|
|
9568
12102
|
}
|
|
9569
12103
|
),
|
|
9570
|
-
toolbarRect && toolbarVariant === "rich-text" && /* @__PURE__ */ jsxs13(Fragment5, { children: [
|
|
9571
|
-
/* @__PURE__ */
|
|
12104
|
+
toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ jsxs13(Fragment5, { children: [
|
|
12105
|
+
/* @__PURE__ */ jsx24(
|
|
9572
12106
|
EditGlowChrome,
|
|
9573
12107
|
{
|
|
9574
12108
|
rect: toolbarRect,
|
|
9575
12109
|
elRef: glowElRef,
|
|
9576
12110
|
reorderHrefKey,
|
|
9577
|
-
dragDisabled: reorderDragDisabled
|
|
12111
|
+
dragDisabled: reorderDragDisabled,
|
|
12112
|
+
hideHandle: isItemDragging
|
|
9578
12113
|
}
|
|
9579
12114
|
),
|
|
9580
|
-
/* @__PURE__ */
|
|
12115
|
+
/* @__PURE__ */ jsx24(
|
|
9581
12116
|
FloatingToolbar,
|
|
9582
12117
|
{
|
|
9583
12118
|
rect: toolbarRect,
|
|
@@ -9616,7 +12151,7 @@ function OhhwellsBridge() {
|
|
|
9616
12151
|
]
|
|
9617
12152
|
}
|
|
9618
12153
|
),
|
|
9619
|
-
toggleState && !linkPopover && /* @__PURE__ */
|
|
12154
|
+
toggleState && !linkPopover && /* @__PURE__ */ jsx24(
|
|
9620
12155
|
StateToggle,
|
|
9621
12156
|
{
|
|
9622
12157
|
rect: toggleState.rect,
|
|
@@ -9632,25 +12167,29 @@ function OhhwellsBridge() {
|
|
|
9632
12167
|
className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
|
|
9633
12168
|
style: { top: sectionGap.y, transform: "translateY(-50%)" },
|
|
9634
12169
|
children: [
|
|
9635
|
-
/* @__PURE__ */
|
|
9636
|
-
/* @__PURE__ */
|
|
12170
|
+
/* @__PURE__ */ jsx24("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
|
|
12171
|
+
/* @__PURE__ */ jsx24(
|
|
9637
12172
|
Badge,
|
|
9638
12173
|
{
|
|
9639
12174
|
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",
|
|
9640
12175
|
onClick: () => {
|
|
9641
12176
|
window.parent.postMessage(
|
|
9642
|
-
{
|
|
12177
|
+
{
|
|
12178
|
+
type: "ow:add-section",
|
|
12179
|
+
insertAfter: sectionGap.insertAfter,
|
|
12180
|
+
insertBefore: sectionGap.insertBefore
|
|
12181
|
+
},
|
|
9643
12182
|
"*"
|
|
9644
12183
|
);
|
|
9645
12184
|
},
|
|
9646
12185
|
children: "Add Section"
|
|
9647
12186
|
}
|
|
9648
12187
|
),
|
|
9649
|
-
/* @__PURE__ */
|
|
12188
|
+
/* @__PURE__ */ jsx24("div", { className: "flex-1 bg-primary", style: { height: 3 } })
|
|
9650
12189
|
]
|
|
9651
12190
|
}
|
|
9652
12191
|
),
|
|
9653
|
-
linkPopover && dialogPortalContainer ? /* @__PURE__ */
|
|
12192
|
+
linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx24(
|
|
9654
12193
|
LinkPopover,
|
|
9655
12194
|
{
|
|
9656
12195
|
panelRef: linkPopoverPanelRef,
|
|
@@ -9676,6 +12215,7 @@ export {
|
|
|
9676
12215
|
CustomToolbarButton,
|
|
9677
12216
|
CustomToolbarDivider,
|
|
9678
12217
|
DragHandle,
|
|
12218
|
+
DropIndicator,
|
|
9679
12219
|
ItemActionToolbar,
|
|
9680
12220
|
ItemInteractionLayer,
|
|
9681
12221
|
LinkEditorPanel,
|
|
@@ -9690,6 +12230,7 @@ export {
|
|
|
9690
12230
|
TooltipProvider,
|
|
9691
12231
|
TooltipTrigger,
|
|
9692
12232
|
buildTarget,
|
|
12233
|
+
dropIndicatorVariants,
|
|
9693
12234
|
filterAvailablePages,
|
|
9694
12235
|
getEditModeInitialState,
|
|
9695
12236
|
isEditSessionActive,
|