@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.cjs
CHANGED
|
@@ -35,6 +35,7 @@ __export(index_exports, {
|
|
|
35
35
|
CustomToolbarButton: () => CustomToolbarButton,
|
|
36
36
|
CustomToolbarDivider: () => CustomToolbarDivider,
|
|
37
37
|
DragHandle: () => DragHandle,
|
|
38
|
+
DropIndicator: () => DropIndicator,
|
|
38
39
|
ItemActionToolbar: () => ItemActionToolbar,
|
|
39
40
|
ItemInteractionLayer: () => ItemInteractionLayer,
|
|
40
41
|
LinkEditorPanel: () => LinkEditorPanel,
|
|
@@ -49,6 +50,7 @@ __export(index_exports, {
|
|
|
49
50
|
TooltipProvider: () => TooltipProvider,
|
|
50
51
|
TooltipTrigger: () => TooltipTrigger,
|
|
51
52
|
buildTarget: () => buildTarget,
|
|
53
|
+
dropIndicatorVariants: () => dropIndicatorVariants,
|
|
52
54
|
filterAvailablePages: () => filterAvailablePages,
|
|
53
55
|
getEditModeInitialState: () => getEditModeInitialState,
|
|
54
56
|
isEditSessionActive: () => isEditSessionActive,
|
|
@@ -60,7 +62,7 @@ __export(index_exports, {
|
|
|
60
62
|
module.exports = __toCommonJS(index_exports);
|
|
61
63
|
|
|
62
64
|
// src/OhhwellsBridge.tsx
|
|
63
|
-
var
|
|
65
|
+
var import_react9 = __toESM(require("react"), 1);
|
|
64
66
|
var import_client = require("react-dom/client");
|
|
65
67
|
var import_react_dom2 = require("react-dom");
|
|
66
68
|
|
|
@@ -113,6 +115,7 @@ var import_react3 = require("react");
|
|
|
113
115
|
var import_react2 = require("react");
|
|
114
116
|
var import_radix_ui = require("radix-ui");
|
|
115
117
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
118
|
+
var isValidEmail = (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
|
|
116
119
|
function Spinner() {
|
|
117
120
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
118
121
|
"svg",
|
|
@@ -146,12 +149,17 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
|
|
|
146
149
|
const [error, setError] = (0, import_react2.useState)(null);
|
|
147
150
|
const isBook = title === "Confirm your spot";
|
|
148
151
|
const handleSubmit = async () => {
|
|
149
|
-
|
|
152
|
+
const trimmed = email.trim();
|
|
153
|
+
if (!trimmed) return;
|
|
154
|
+
if (!isValidEmail(trimmed)) {
|
|
155
|
+
setError("Please enter a valid email address.");
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
150
158
|
setLoading(true);
|
|
151
159
|
setError(null);
|
|
152
160
|
try {
|
|
153
|
-
await onSubmit(
|
|
154
|
-
setSubmittedEmail(
|
|
161
|
+
await onSubmit(trimmed);
|
|
162
|
+
setSubmittedEmail(trimmed);
|
|
155
163
|
setSuccess(true);
|
|
156
164
|
} catch (e) {
|
|
157
165
|
setError(e instanceof Error ? e.message : "Something went wrong. Please try again.");
|
|
@@ -226,7 +234,10 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
|
|
|
226
234
|
{
|
|
227
235
|
type: "email",
|
|
228
236
|
value: email,
|
|
229
|
-
onChange: (e) =>
|
|
237
|
+
onChange: (e) => {
|
|
238
|
+
setEmail(e.target.value);
|
|
239
|
+
if (error) setError(null);
|
|
240
|
+
},
|
|
230
241
|
onKeyDown: handleKeyDown,
|
|
231
242
|
placeholder: "hello@gmail.com",
|
|
232
243
|
autoFocus: true,
|
|
@@ -283,12 +294,20 @@ function formatClassTime(cls) {
|
|
|
283
294
|
const em = endTotal % 60;
|
|
284
295
|
return `${h}:${cls.startTime.minutes}-${eh}:${String(em).padStart(2, "0")}`;
|
|
285
296
|
}
|
|
297
|
+
function formatBookingLabel(cls) {
|
|
298
|
+
const price = cls.price;
|
|
299
|
+
const isFree = price === null || price === void 0 || `${price}` === "" || `${price}` === "0";
|
|
300
|
+
return isFree ? "Book for free" : `Book for ${cls.currency ?? ""} ${price}`.trim();
|
|
301
|
+
}
|
|
286
302
|
function getBookingsOnDate(cls, date) {
|
|
287
303
|
if (!cls.bookings?.length) return 0;
|
|
288
|
-
const
|
|
304
|
+
const target = new Date(date);
|
|
305
|
+
target.setHours(0, 0, 0, 0);
|
|
289
306
|
return cls.bookings.filter((b) => {
|
|
290
307
|
try {
|
|
291
|
-
|
|
308
|
+
const bookingDate = new Date(b.classDate);
|
|
309
|
+
bookingDate.setHours(0, 0, 0, 0);
|
|
310
|
+
return bookingDate.getTime() === target.getTime();
|
|
292
311
|
} catch {
|
|
293
312
|
return false;
|
|
294
313
|
}
|
|
@@ -553,7 +572,7 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
|
|
|
553
572
|
}
|
|
554
573
|
)
|
|
555
574
|
] }),
|
|
556
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "sm:hidden flex flex-col gap-px", children: isFull ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
575
|
+
cls.showAvailability !== false && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "sm:hidden flex flex-col gap-px", children: isFull ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
557
576
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: [
|
|
558
577
|
available,
|
|
559
578
|
"/",
|
|
@@ -565,9 +584,17 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
|
|
|
565
584
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-1 flex-col gap-2 min-w-0 sm:contents", children: [
|
|
566
585
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex-1 flex flex-col gap-2 min-w-0", children: [
|
|
567
586
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-base font-bold text-(--color-dark,#200C02) block truncate", children: cls.name }),
|
|
568
|
-
cls.hostName && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-base font-normal text-(--color-dark,#200C02) opacity-80 block truncate", children: cls.hostName })
|
|
587
|
+
cls.hostName && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-base font-normal text-(--color-dark,#200C02) opacity-80 block truncate", children: cls.hostName }),
|
|
588
|
+
cls.description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
589
|
+
"span",
|
|
590
|
+
{
|
|
591
|
+
className: "font-body text-base font-normal text-(--color-dark,#200C02) opacity-80 block",
|
|
592
|
+
style: { wordBreak: "break-word" },
|
|
593
|
+
children: cls.description
|
|
594
|
+
}
|
|
595
|
+
)
|
|
569
596
|
] }),
|
|
570
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "hidden sm:flex w-14 shrink-0 flex-col gap-px", children: isFull ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
597
|
+
cls.showAvailability !== false && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "hidden sm:flex w-14 shrink-0 flex-col gap-px", children: isFull ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
571
598
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: [
|
|
572
599
|
available,
|
|
573
600
|
"/",
|
|
@@ -592,7 +619,7 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
|
|
|
592
619
|
if (!cls.id) return;
|
|
593
620
|
onOpenModal?.(isFull ? "waitlist" : "book", cls.id, selectedDate);
|
|
594
621
|
},
|
|
595
|
-
children: isFull ? "Join Waitlist" :
|
|
622
|
+
children: isFull ? "Join Waitlist" : formatBookingLabel(cls)
|
|
596
623
|
}
|
|
597
624
|
)
|
|
598
625
|
] })
|
|
@@ -634,6 +661,17 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
634
661
|
const [isHovered, setIsHovered] = (0, import_react3.useState)(false);
|
|
635
662
|
const [modalState, setModalState] = (0, import_react3.useState)(null);
|
|
636
663
|
const switchScheduleIdRef = (0, import_react3.useRef)(null);
|
|
664
|
+
const liveScheduleIdRef = (0, import_react3.useRef)(null);
|
|
665
|
+
const refetchLiveSchedule = (0, import_react3.useCallback)(async () => {
|
|
666
|
+
const id = liveScheduleIdRef.current;
|
|
667
|
+
if (!id) return;
|
|
668
|
+
try {
|
|
669
|
+
const res = await fetch(`${API_URL}/api/schedule/id/${id}`);
|
|
670
|
+
const data = await res.json();
|
|
671
|
+
if (data?.id) setSchedule(data);
|
|
672
|
+
} catch {
|
|
673
|
+
}
|
|
674
|
+
}, []);
|
|
637
675
|
const dates = (0, import_react3.useMemo)(() => {
|
|
638
676
|
const today = /* @__PURE__ */ new Date();
|
|
639
677
|
today.setHours(0, 0, 0, 0);
|
|
@@ -653,6 +691,18 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
653
691
|
}
|
|
654
692
|
}
|
|
655
693
|
}, [schedule, dates]);
|
|
694
|
+
(0, import_react3.useEffect)(() => {
|
|
695
|
+
if (typeof window === "undefined") return;
|
|
696
|
+
const onVisible = () => {
|
|
697
|
+
if (!document.hidden) void refetchLiveSchedule();
|
|
698
|
+
};
|
|
699
|
+
window.addEventListener("focus", refetchLiveSchedule);
|
|
700
|
+
document.addEventListener("visibilitychange", onVisible);
|
|
701
|
+
return () => {
|
|
702
|
+
window.removeEventListener("focus", refetchLiveSchedule);
|
|
703
|
+
document.removeEventListener("visibilitychange", onVisible);
|
|
704
|
+
};
|
|
705
|
+
}, [refetchLiveSchedule]);
|
|
656
706
|
(0, import_react3.useEffect)(() => {
|
|
657
707
|
if (typeof window === "undefined") return;
|
|
658
708
|
const isInEditor = window.self !== window.top;
|
|
@@ -714,7 +764,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
714
764
|
setLoading(false);
|
|
715
765
|
return;
|
|
716
766
|
}
|
|
717
|
-
;
|
|
767
|
+
liveScheduleIdRef.current = effectiveId;
|
|
718
768
|
(async () => {
|
|
719
769
|
try {
|
|
720
770
|
const res = await fetch(`${API_URL}/api/schedule/id/${effectiveId}`);
|
|
@@ -771,18 +821,14 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
771
821
|
const data = await res.json().catch(() => ({}));
|
|
772
822
|
throw new Error(data?.message ?? "Something went wrong. Please try again.");
|
|
773
823
|
}
|
|
824
|
+
await refetchLiveSchedule();
|
|
774
825
|
};
|
|
775
826
|
const handleReplaceSchedule = () => {
|
|
776
827
|
setIsHovered(false);
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
insertAfter
|
|
782
|
-
}, "*");
|
|
783
|
-
} else {
|
|
784
|
-
window.parent.postMessage({ type: "ow:scheduling-not-connected", insertAfter }, "*");
|
|
785
|
-
}
|
|
828
|
+
window.parent.postMessage(
|
|
829
|
+
{ type: "ow:scheduling-not-connected", insertAfter, currentScheduleId: schedule?.id },
|
|
830
|
+
"*"
|
|
831
|
+
);
|
|
786
832
|
};
|
|
787
833
|
if (!inEditor && !loading && !schedule) return null;
|
|
788
834
|
const sectionId = `scheduling-${insertAfter}`;
|
|
@@ -825,7 +871,19 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
825
871
|
),
|
|
826
872
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "max-w-[1280px] mx-auto flex flex-col items-center gap-16", children: [
|
|
827
873
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col items-center gap-4", children: [
|
|
828
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
874
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
875
|
+
"h2",
|
|
876
|
+
{
|
|
877
|
+
className: "font-display text-center m-0 text-(--color-dark,#200C02)",
|
|
878
|
+
style: {
|
|
879
|
+
fontSize: "var(--fs-section-h2, clamp(40px, 4.4vw, 64px))",
|
|
880
|
+
fontWeight: "var(--font-weight-heading, 400)",
|
|
881
|
+
lineHeight: 1.05,
|
|
882
|
+
letterSpacing: "-0.02em"
|
|
883
|
+
},
|
|
884
|
+
children: schedule?.name ?? "Book an appointment"
|
|
885
|
+
}
|
|
886
|
+
),
|
|
829
887
|
schedule?.description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "font-body text-body text-center m-0 text-(--color-accent,#A89B83)", children: schedule.description })
|
|
830
888
|
] }),
|
|
831
889
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "w-full flex flex-col items-end gap-3", children: [
|
|
@@ -4301,7 +4359,8 @@ var CustomToolbar = React4.forwardRef(({ className, onMouseDown, ...props }, ref
|
|
|
4301
4359
|
ref,
|
|
4302
4360
|
"data-ohw-toolbar": "",
|
|
4303
4361
|
className: cn(
|
|
4304
|
-
|
|
4362
|
+
// Figma: bg background, radius 8, gap-1, p-0.5, shadow-md — no border
|
|
4363
|
+
"inline-flex h-8 items-center gap-1 rounded-[var(--radius,0.5rem)] bg-background p-0.5 font-sans whitespace-nowrap shadow-md",
|
|
4305
4364
|
className
|
|
4306
4365
|
),
|
|
4307
4366
|
onMouseDown: (e) => {
|
|
@@ -4329,8 +4388,8 @@ var CustomToolbarButton = React4.forwardRef(
|
|
|
4329
4388
|
ref,
|
|
4330
4389
|
type,
|
|
4331
4390
|
className: cn(
|
|
4332
|
-
"inline-flex shrink-0 items-center justify-center rounded
|
|
4333
|
-
active ? "bg-primary text-primary-foreground" : "bg-transparent
|
|
4391
|
+
"inline-flex size-7 shrink-0 items-center justify-center rounded-[calc(var(--radius,0.5rem)-2px)] text-foreground transition-colors",
|
|
4392
|
+
active ? "bg-primary text-primary-foreground" : "bg-transparent hover:bg-muted disabled:cursor-not-allowed disabled:text-muted-foreground disabled:opacity-60",
|
|
4334
4393
|
className
|
|
4335
4394
|
),
|
|
4336
4395
|
...props
|
|
@@ -4365,9 +4424,10 @@ var arrowClassBySide = {
|
|
|
4365
4424
|
};
|
|
4366
4425
|
function TooltipContent({
|
|
4367
4426
|
className,
|
|
4368
|
-
sideOffset =
|
|
4427
|
+
sideOffset = 9,
|
|
4369
4428
|
side = "bottom",
|
|
4370
4429
|
children,
|
|
4430
|
+
hideArrow,
|
|
4371
4431
|
...props
|
|
4372
4432
|
}) {
|
|
4373
4433
|
const resolvedSide = side ?? "bottom";
|
|
@@ -4378,12 +4438,13 @@ function TooltipContent({
|
|
|
4378
4438
|
side,
|
|
4379
4439
|
sideOffset,
|
|
4380
4440
|
className: cn(
|
|
4381
|
-
"relative z-[2147483647] w-fit max-w-xs rounded-md bg-foreground px-3 py-1.5 text-xs text-background
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
"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",
|
|
4441
|
+
"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",
|
|
4442
|
+
"origin-[var(--radix-tooltip-content-transform-origin)] animate-in fade-in-0 zoom-in-95",
|
|
4443
|
+
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
|
|
4385
4444
|
"data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2",
|
|
4386
4445
|
"data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2",
|
|
4446
|
+
!hideArrow && 'before:pointer-events-none before:absolute before:size-2 before:rotate-45 before:bg-foreground before:content-[""]',
|
|
4447
|
+
!hideArrow && arrowClassBySide[resolvedSide],
|
|
4387
4448
|
className
|
|
4388
4449
|
),
|
|
4389
4450
|
...props,
|
|
@@ -4404,7 +4465,7 @@ function ToolbarActionTooltip({
|
|
|
4404
4465
|
const button = /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CustomToolbarButton, { type: "button", "aria-label": label, disabled, ...buttonProps, children });
|
|
4405
4466
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Tooltip, { children: [
|
|
4406
4467
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "inline-flex", children: button }) : button }),
|
|
4407
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(TooltipContent, { side, children: label })
|
|
4468
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(TooltipContent, { side, sideOffset: 9, children: label })
|
|
4408
4469
|
] });
|
|
4409
4470
|
}
|
|
4410
4471
|
function ItemActionToolbar({
|
|
@@ -4414,6 +4475,8 @@ function ItemActionToolbar({
|
|
|
4414
4475
|
editLinkDisabled = false,
|
|
4415
4476
|
addItemDisabled = true,
|
|
4416
4477
|
moreDisabled = true,
|
|
4478
|
+
showAddItem = true,
|
|
4479
|
+
showMore = true,
|
|
4417
4480
|
tooltipSide = "bottom"
|
|
4418
4481
|
}) {
|
|
4419
4482
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(CustomToolbar, { children: [
|
|
@@ -4438,8 +4501,7 @@ function ItemActionToolbar({
|
|
|
4438
4501
|
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.Link, { className: "size-4 shrink-0", "aria-hidden": true })
|
|
4439
4502
|
}
|
|
4440
4503
|
),
|
|
4441
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
4442
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
4504
|
+
showAddItem ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
4443
4505
|
ToolbarActionTooltip,
|
|
4444
4506
|
{
|
|
4445
4507
|
label: "Add item",
|
|
@@ -4455,9 +4517,8 @@ function ItemActionToolbar({
|
|
|
4455
4517
|
},
|
|
4456
4518
|
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.Plus, { className: "size-4 shrink-0", "aria-hidden": true })
|
|
4457
4519
|
}
|
|
4458
|
-
),
|
|
4459
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
4460
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
4520
|
+
) : null,
|
|
4521
|
+
showMore ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
4461
4522
|
ToolbarActionTooltip,
|
|
4462
4523
|
{
|
|
4463
4524
|
label: "More",
|
|
@@ -4473,15 +4534,32 @@ function ItemActionToolbar({
|
|
|
4473
4534
|
},
|
|
4474
4535
|
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.MoreHorizontal, { className: "size-4 shrink-0", "aria-hidden": true })
|
|
4475
4536
|
}
|
|
4476
|
-
)
|
|
4537
|
+
) : null
|
|
4477
4538
|
] }) });
|
|
4478
4539
|
}
|
|
4479
4540
|
|
|
4480
4541
|
// src/ui/item-interaction-layer.tsx
|
|
4542
|
+
var React5 = __toESM(require("react"), 1);
|
|
4481
4543
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
4482
4544
|
var PRIMARY = "var(--ohw-primary, #0885FE)";
|
|
4483
|
-
var FOCUS_RING =
|
|
4545
|
+
var FOCUS_RING = `0 0 0 4px color-mix(in srgb, ${PRIMARY} 12%, transparent)`;
|
|
4484
4546
|
var DRAG_SHADOW = "0px 4px 6px -1px rgba(0, 0, 0, 0.1), 0px 2px 4px -2px rgba(0, 0, 0, 0.1)";
|
|
4547
|
+
var TOOLBAR_EDGE_MARGIN = 4;
|
|
4548
|
+
var SELECTION_CHROME_GAP = 4;
|
|
4549
|
+
var TOOLBAR_STROKE_GAP = 4;
|
|
4550
|
+
function getChromeZIndex(state) {
|
|
4551
|
+
switch (state) {
|
|
4552
|
+
case "active-top":
|
|
4553
|
+
case "active-bottom":
|
|
4554
|
+
case "dragging":
|
|
4555
|
+
return 2147483644;
|
|
4556
|
+
case "hover":
|
|
4557
|
+
case "sibling-hint":
|
|
4558
|
+
return 2147483643;
|
|
4559
|
+
default:
|
|
4560
|
+
return 2147483642;
|
|
4561
|
+
}
|
|
4562
|
+
}
|
|
4485
4563
|
function getChromeStyle(state) {
|
|
4486
4564
|
switch (state) {
|
|
4487
4565
|
case "hover":
|
|
@@ -4503,12 +4581,65 @@ function getChromeStyle(state) {
|
|
|
4503
4581
|
case "dragging":
|
|
4504
4582
|
return {
|
|
4505
4583
|
border: `2px solid ${PRIMARY}`,
|
|
4506
|
-
boxShadow: DRAG_SHADOW
|
|
4584
|
+
boxShadow: `${FOCUS_RING}, ${DRAG_SHADOW}`
|
|
4507
4585
|
};
|
|
4508
4586
|
default:
|
|
4509
4587
|
return {};
|
|
4510
4588
|
}
|
|
4511
4589
|
}
|
|
4590
|
+
function ClampedToolbarSlot({
|
|
4591
|
+
placement,
|
|
4592
|
+
children
|
|
4593
|
+
}) {
|
|
4594
|
+
const slotRef = React5.useRef(null);
|
|
4595
|
+
React5.useLayoutEffect(() => {
|
|
4596
|
+
const slot = slotRef.current;
|
|
4597
|
+
if (!slot) return;
|
|
4598
|
+
const clamp = () => {
|
|
4599
|
+
const toolbar = slot.firstElementChild;
|
|
4600
|
+
if (!toolbar) return;
|
|
4601
|
+
const w = toolbar.offsetWidth;
|
|
4602
|
+
if (w <= 0) return;
|
|
4603
|
+
const parent = slot.offsetParent;
|
|
4604
|
+
if (!parent) return;
|
|
4605
|
+
const parentRect = parent.getBoundingClientRect();
|
|
4606
|
+
const centerX = parentRect.left + parentRect.width / 2;
|
|
4607
|
+
const half = w / 2;
|
|
4608
|
+
const clampedCenter = Math.max(
|
|
4609
|
+
TOOLBAR_EDGE_MARGIN + half,
|
|
4610
|
+
Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN - half)
|
|
4611
|
+
);
|
|
4612
|
+
const offsetX = clampedCenter - centerX;
|
|
4613
|
+
slot.style.transform = `translateX(calc(-50% + ${offsetX}px))`;
|
|
4614
|
+
};
|
|
4615
|
+
clamp();
|
|
4616
|
+
const ro = new ResizeObserver(clamp);
|
|
4617
|
+
ro.observe(slot);
|
|
4618
|
+
if (slot.firstElementChild) ro.observe(slot.firstElementChild);
|
|
4619
|
+
window.addEventListener("resize", clamp);
|
|
4620
|
+
return () => {
|
|
4621
|
+
ro.disconnect();
|
|
4622
|
+
window.removeEventListener("resize", clamp);
|
|
4623
|
+
};
|
|
4624
|
+
}, [placement, children]);
|
|
4625
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4626
|
+
"div",
|
|
4627
|
+
{
|
|
4628
|
+
ref: slotRef,
|
|
4629
|
+
className: cn(
|
|
4630
|
+
"pointer-events-auto absolute left-1/2",
|
|
4631
|
+
placement === "top" ? "bottom-full" : "top-full"
|
|
4632
|
+
),
|
|
4633
|
+
style: {
|
|
4634
|
+
marginBottom: placement === "top" ? TOOLBAR_STROKE_GAP : void 0,
|
|
4635
|
+
marginTop: placement === "bottom" ? TOOLBAR_STROKE_GAP : void 0,
|
|
4636
|
+
transform: "translateX(-50%)"
|
|
4637
|
+
},
|
|
4638
|
+
"data-ohw-item-toolbar-anchor": placement,
|
|
4639
|
+
children
|
|
4640
|
+
}
|
|
4641
|
+
);
|
|
4642
|
+
}
|
|
4512
4643
|
function ItemInteractionLayer({
|
|
4513
4644
|
rect,
|
|
4514
4645
|
state,
|
|
@@ -4519,14 +4650,18 @@ function ItemInteractionLayer({
|
|
|
4519
4650
|
dragHandleLabel = "Reorder item",
|
|
4520
4651
|
onDragHandleDragStart,
|
|
4521
4652
|
onDragHandleDragEnd,
|
|
4522
|
-
|
|
4653
|
+
onItemPointerDown,
|
|
4654
|
+
onItemClick,
|
|
4655
|
+
itemDragSurface = true,
|
|
4656
|
+
chromeGap = SELECTION_CHROME_GAP,
|
|
4523
4657
|
className
|
|
4524
4658
|
}) {
|
|
4525
4659
|
if (state === "default") return null;
|
|
4526
4660
|
const isActive = state === "active-top" || state === "active-bottom";
|
|
4527
4661
|
const isDragging = state === "dragging";
|
|
4528
4662
|
const showToolbar = isActive && toolbar;
|
|
4529
|
-
const showDragHandle = isActive
|
|
4663
|
+
const showDragHandle = (isActive || isDragging) && showHandle;
|
|
4664
|
+
const itemDragEnabled = itemDragSurface && isActive && showHandle && !isDragging && !dragDisabled;
|
|
4530
4665
|
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
4531
4666
|
"div",
|
|
4532
4667
|
{
|
|
@@ -4540,7 +4675,7 @@ function ItemInteractionLayer({
|
|
|
4540
4675
|
left: rect.left - chromeGap,
|
|
4541
4676
|
width: rect.width + chromeGap * 2,
|
|
4542
4677
|
height: rect.height + chromeGap * 2,
|
|
4543
|
-
zIndex:
|
|
4678
|
+
zIndex: getChromeZIndex(state)
|
|
4544
4679
|
},
|
|
4545
4680
|
children: [
|
|
4546
4681
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
@@ -4551,11 +4686,29 @@ function ItemInteractionLayer({
|
|
|
4551
4686
|
style: getChromeStyle(state)
|
|
4552
4687
|
}
|
|
4553
4688
|
),
|
|
4689
|
+
itemDragEnabled && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4690
|
+
"div",
|
|
4691
|
+
{
|
|
4692
|
+
"data-ohw-item-drag-surface": "",
|
|
4693
|
+
className: "pointer-events-auto absolute inset-0 cursor-text rounded-lg",
|
|
4694
|
+
onPointerDown: (e) => {
|
|
4695
|
+
if (e.button !== 0) return;
|
|
4696
|
+
onItemPointerDown?.(e);
|
|
4697
|
+
},
|
|
4698
|
+
onClick: (e) => {
|
|
4699
|
+
e.preventDefault();
|
|
4700
|
+
e.stopPropagation();
|
|
4701
|
+
onItemClick?.(e.clientX, e.clientY);
|
|
4702
|
+
}
|
|
4703
|
+
}
|
|
4704
|
+
),
|
|
4554
4705
|
showDragHandle && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4555
4706
|
"div",
|
|
4556
4707
|
{
|
|
4557
4708
|
"data-ohw-drag-handle-container": "",
|
|
4558
|
-
className: "pointer-events-auto absolute left-0 top-1/2 -translate-x-[calc(100%+7px)] -translate-y-1/2",
|
|
4709
|
+
className: "pointer-events-auto absolute left-0 top-1/2 z-10 -translate-x-[calc(100%+7px)] -translate-y-1/2",
|
|
4710
|
+
style: isDragging ? { opacity: 0 } : void 0,
|
|
4711
|
+
"aria-hidden": isDragging || void 0,
|
|
4559
4712
|
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4560
4713
|
DragHandle,
|
|
4561
4714
|
{
|
|
@@ -4567,7 +4720,17 @@ function ItemInteractionLayer({
|
|
|
4567
4720
|
e.preventDefault();
|
|
4568
4721
|
return;
|
|
4569
4722
|
}
|
|
4570
|
-
|
|
4723
|
+
const blank = document.createElement("canvas");
|
|
4724
|
+
blank.width = 1;
|
|
4725
|
+
blank.height = 1;
|
|
4726
|
+
blank.style.cssText = "position:fixed;left:-9999px;top:-9999px;width:1px;height:1px;pointer-events:none";
|
|
4727
|
+
document.body.appendChild(blank);
|
|
4728
|
+
try {
|
|
4729
|
+
e.dataTransfer.setDragImage(blank, 0, 0);
|
|
4730
|
+
} finally {
|
|
4731
|
+
requestAnimationFrame(() => blank.remove());
|
|
4732
|
+
}
|
|
4733
|
+
e.dataTransfer.setData("text/plain", dragHandleLabel);
|
|
4571
4734
|
e.dataTransfer.effectAllowed = "move";
|
|
4572
4735
|
onDragHandleDragStart?.(e);
|
|
4573
4736
|
},
|
|
@@ -4576,33 +4739,19 @@ function ItemInteractionLayer({
|
|
|
4576
4739
|
)
|
|
4577
4740
|
}
|
|
4578
4741
|
),
|
|
4579
|
-
showToolbar && state === "active-top" && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4580
|
-
|
|
4581
|
-
{
|
|
4582
|
-
className: "pointer-events-auto absolute bottom-full left-1/2 mb-2 -translate-x-1/2",
|
|
4583
|
-
"data-ohw-item-toolbar-anchor": "top",
|
|
4584
|
-
children: toolbar
|
|
4585
|
-
}
|
|
4586
|
-
),
|
|
4587
|
-
showToolbar && state === "active-bottom" && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4588
|
-
"div",
|
|
4589
|
-
{
|
|
4590
|
-
className: "pointer-events-auto absolute left-1/2 top-full mt-2 -translate-x-1/2",
|
|
4591
|
-
"data-ohw-item-toolbar-anchor": "bottom",
|
|
4592
|
-
children: toolbar
|
|
4593
|
-
}
|
|
4594
|
-
)
|
|
4742
|
+
showToolbar && state === "active-top" && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ClampedToolbarSlot, { placement: "top", children: toolbar }),
|
|
4743
|
+
showToolbar && state === "active-bottom" && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ClampedToolbarSlot, { placement: "bottom", children: toolbar })
|
|
4595
4744
|
]
|
|
4596
4745
|
}
|
|
4597
4746
|
);
|
|
4598
4747
|
}
|
|
4599
4748
|
|
|
4600
4749
|
// src/ui/MediaOverlay.tsx
|
|
4601
|
-
var
|
|
4750
|
+
var React7 = __toESM(require("react"), 1);
|
|
4602
4751
|
var import_lucide_react3 = require("lucide-react");
|
|
4603
4752
|
|
|
4604
4753
|
// src/ui/button.tsx
|
|
4605
|
-
var
|
|
4754
|
+
var React6 = __toESM(require("react"), 1);
|
|
4606
4755
|
var import_radix_ui4 = require("radix-ui");
|
|
4607
4756
|
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
4608
4757
|
var buttonVariants = cva(
|
|
@@ -4625,7 +4774,7 @@ var buttonVariants = cva(
|
|
|
4625
4774
|
}
|
|
4626
4775
|
}
|
|
4627
4776
|
);
|
|
4628
|
-
var Button =
|
|
4777
|
+
var Button = React6.forwardRef(
|
|
4629
4778
|
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
4630
4779
|
const Comp = asChild ? import_radix_ui4.Slot.Root : "button";
|
|
4631
4780
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
@@ -4677,7 +4826,7 @@ function MediaOverlay({
|
|
|
4677
4826
|
onVideoSettingsChange
|
|
4678
4827
|
}) {
|
|
4679
4828
|
const { rect } = hover;
|
|
4680
|
-
const skeletonRef =
|
|
4829
|
+
const skeletonRef = React7.useRef(null);
|
|
4681
4830
|
const isVideo = hover.elementType === "video";
|
|
4682
4831
|
const autoplay = hover.videoAutoplay ?? true;
|
|
4683
4832
|
const muted = hover.videoMuted ?? true;
|
|
@@ -4689,7 +4838,7 @@ function MediaOverlay({
|
|
|
4689
4838
|
height: rect.height,
|
|
4690
4839
|
zIndex: 2147483646
|
|
4691
4840
|
};
|
|
4692
|
-
|
|
4841
|
+
React7.useEffect(() => {
|
|
4693
4842
|
if (!isUploading || !fadingOut || !skeletonRef.current) return;
|
|
4694
4843
|
const anim = skeletonRef.current.animate([{ opacity: 1 }, { opacity: 0 }], {
|
|
4695
4844
|
duration: MEDIA_UPLOAD_FADE_MS,
|
|
@@ -5094,7 +5243,7 @@ function scrollToHashSectionWhenReady(behavior = "smooth") {
|
|
|
5094
5243
|
var import_react7 = require("react");
|
|
5095
5244
|
|
|
5096
5245
|
// src/ui/dialog.tsx
|
|
5097
|
-
var
|
|
5246
|
+
var React8 = __toESM(require("react"), 1);
|
|
5098
5247
|
var import_radix_ui5 = require("radix-ui");
|
|
5099
5248
|
var import_lucide_react4 = require("lucide-react");
|
|
5100
5249
|
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
@@ -5122,7 +5271,7 @@ function DialogOverlay({
|
|
|
5122
5271
|
}
|
|
5123
5272
|
);
|
|
5124
5273
|
}
|
|
5125
|
-
var DialogContent =
|
|
5274
|
+
var DialogContent = React8.forwardRef(
|
|
5126
5275
|
({ className, children, showCloseButton = true, container, ...props }, ref) => {
|
|
5127
5276
|
const positionMode = container ? "absolute" : "fixed";
|
|
5128
5277
|
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(DialogPortal, { container: container ?? void 0, children: [
|
|
@@ -5177,7 +5326,7 @@ function DialogFooter({
|
|
|
5177
5326
|
}
|
|
5178
5327
|
);
|
|
5179
5328
|
}
|
|
5180
|
-
var DialogTitle =
|
|
5329
|
+
var DialogTitle = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
5181
5330
|
import_radix_ui5.Dialog.Title,
|
|
5182
5331
|
{
|
|
5183
5332
|
ref,
|
|
@@ -5189,7 +5338,7 @@ var DialogTitle = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE
|
|
|
5189
5338
|
}
|
|
5190
5339
|
));
|
|
5191
5340
|
DialogTitle.displayName = import_radix_ui5.Dialog.Title.displayName;
|
|
5192
|
-
var DialogDescription =
|
|
5341
|
+
var DialogDescription = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
5193
5342
|
import_radix_ui5.Dialog.Description,
|
|
5194
5343
|
{
|
|
5195
5344
|
ref,
|
|
@@ -5294,9 +5443,9 @@ function SectionTreeItem({
|
|
|
5294
5443
|
var import_react4 = require("react");
|
|
5295
5444
|
|
|
5296
5445
|
// src/ui/input.tsx
|
|
5297
|
-
var
|
|
5446
|
+
var React9 = __toESM(require("react"), 1);
|
|
5298
5447
|
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
5299
|
-
var Input =
|
|
5448
|
+
var Input = React9.forwardRef(
|
|
5300
5449
|
({ className, type, ...props }, ref) => {
|
|
5301
5450
|
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
5302
5451
|
"input",
|
|
@@ -5851,8 +6000,8 @@ function SectionPickerOverlay({
|
|
|
5851
6000
|
!isOnTargetPage ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5852
6001
|
"div",
|
|
5853
6002
|
{
|
|
5854
|
-
className: "pointer-events-none fixed left-1/2 z-[1] -translate-x-1/2 rounded-md
|
|
5855
|
-
style: { top: chromeClip.top + 64 },
|
|
6003
|
+
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",
|
|
6004
|
+
style: { top: chromeClip.top + 64, backgroundColor: "var(--ohw-background, #ffffff)" },
|
|
5856
6005
|
children: "Loading page preview\u2026"
|
|
5857
6006
|
}
|
|
5858
6007
|
) : null,
|
|
@@ -6277,9 +6426,155 @@ function shouldUseDevFixtures() {
|
|
|
6277
6426
|
return new URLSearchParams(q).get("ohw-fixtures") === "1";
|
|
6278
6427
|
}
|
|
6279
6428
|
|
|
6429
|
+
// src/lib/nav-tree.ts
|
|
6430
|
+
var MAX_LEVEL = { nav: 1 };
|
|
6431
|
+
var ROOT = null;
|
|
6432
|
+
function cloneForest(nodes) {
|
|
6433
|
+
return nodes.map((n) => ({ id: n.id, children: cloneForest(n.children) }));
|
|
6434
|
+
}
|
|
6435
|
+
function findNode(nodes, id, parentId = ROOT) {
|
|
6436
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
6437
|
+
const node = nodes[i];
|
|
6438
|
+
if (node.id === id) return { node, parentId, index: i, siblings: nodes };
|
|
6439
|
+
const nested = findNode(node.children, id, node.id);
|
|
6440
|
+
if (nested) return nested;
|
|
6441
|
+
}
|
|
6442
|
+
return null;
|
|
6443
|
+
}
|
|
6444
|
+
function getChildrenOf(nodes, parentId) {
|
|
6445
|
+
if (parentId === ROOT) return nodes;
|
|
6446
|
+
const found = findNode(nodes, parentId);
|
|
6447
|
+
return found ? found.node.children : null;
|
|
6448
|
+
}
|
|
6449
|
+
function isDescendant(nodes, ancestorId, maybeDescendantId) {
|
|
6450
|
+
const found = findNode(nodes, ancestorId);
|
|
6451
|
+
if (!found) return false;
|
|
6452
|
+
return findNode(found.node.children, maybeDescendantId) !== null;
|
|
6453
|
+
}
|
|
6454
|
+
function levelOf(nodes, id) {
|
|
6455
|
+
const loc = findNode(nodes, id);
|
|
6456
|
+
if (!loc) return -1;
|
|
6457
|
+
if (loc.parentId === ROOT) return 0;
|
|
6458
|
+
return 1 + Math.max(0, levelOf(nodes, loc.parentId));
|
|
6459
|
+
}
|
|
6460
|
+
function insertedLevel(nodes, parentId) {
|
|
6461
|
+
if (parentId === ROOT) return 0;
|
|
6462
|
+
const parentLevel = levelOf(nodes, parentId);
|
|
6463
|
+
if (parentLevel < 0) return -1;
|
|
6464
|
+
return parentLevel + 1;
|
|
6465
|
+
}
|
|
6466
|
+
function takeNode(nodes, id) {
|
|
6467
|
+
const forest = cloneForest(nodes);
|
|
6468
|
+
const loc = findNode(forest, id);
|
|
6469
|
+
if (!loc) return null;
|
|
6470
|
+
const [taken] = loc.siblings.splice(loc.index, 1);
|
|
6471
|
+
if (!taken) return null;
|
|
6472
|
+
return { forest, taken };
|
|
6473
|
+
}
|
|
6474
|
+
function insertInto(forest, node, parentId, index) {
|
|
6475
|
+
const siblings = getChildrenOf(forest, parentId);
|
|
6476
|
+
if (!siblings) return false;
|
|
6477
|
+
const clamped = Math.max(0, Math.min(index, siblings.length));
|
|
6478
|
+
siblings.splice(clamped, 0, node);
|
|
6479
|
+
return true;
|
|
6480
|
+
}
|
|
6481
|
+
function normalize(nodes) {
|
|
6482
|
+
const walk = (list) => list.map((n) => {
|
|
6483
|
+
const children = walk(n.children);
|
|
6484
|
+
return { id: n.id, children };
|
|
6485
|
+
});
|
|
6486
|
+
return walk(nodes);
|
|
6487
|
+
}
|
|
6488
|
+
function moveNode(model, draggedId, target) {
|
|
6489
|
+
const { parentId, index: targetIndex } = target;
|
|
6490
|
+
if (parentId === draggedId) return null;
|
|
6491
|
+
if (parentId !== ROOT && isDescendant(model, draggedId, parentId)) return null;
|
|
6492
|
+
const nextLevel = insertedLevel(model, parentId);
|
|
6493
|
+
if (nextLevel < 0 || nextLevel > MAX_LEVEL.nav) return null;
|
|
6494
|
+
const draggedLoc = findNode(model, draggedId);
|
|
6495
|
+
if (!draggedLoc) return null;
|
|
6496
|
+
if (parentId !== ROOT && draggedLoc.node.children.length > 0) return null;
|
|
6497
|
+
const taken = takeNode(model, draggedId);
|
|
6498
|
+
if (!taken) return null;
|
|
6499
|
+
let insertIndex = targetIndex;
|
|
6500
|
+
if (draggedLoc.parentId === parentId && draggedLoc.index < targetIndex) {
|
|
6501
|
+
insertIndex -= 1;
|
|
6502
|
+
}
|
|
6503
|
+
if (!insertInto(taken.forest, taken.taken, parentId, insertIndex)) return null;
|
|
6504
|
+
const next = normalize(taken.forest);
|
|
6505
|
+
if (forestsEqual(model, next)) return null;
|
|
6506
|
+
return next;
|
|
6507
|
+
}
|
|
6508
|
+
function forestsEqual(a, b) {
|
|
6509
|
+
if (a.length !== b.length) return false;
|
|
6510
|
+
for (let i = 0; i < a.length; i++) {
|
|
6511
|
+
const left = a[i];
|
|
6512
|
+
const right = b[i];
|
|
6513
|
+
if (left.id !== right.id) return false;
|
|
6514
|
+
if (!forestsEqual(left.children, right.children)) return false;
|
|
6515
|
+
}
|
|
6516
|
+
return true;
|
|
6517
|
+
}
|
|
6518
|
+
function forestFromFlatOrder(order) {
|
|
6519
|
+
return order.map((id) => ({ id, children: [] }));
|
|
6520
|
+
}
|
|
6521
|
+
function serializeNavOrder(nodes) {
|
|
6522
|
+
const hasNesting = nodes.some((n) => n.children.length > 0);
|
|
6523
|
+
if (!hasNesting) {
|
|
6524
|
+
return JSON.stringify(nodes.map((n) => n.id));
|
|
6525
|
+
}
|
|
6526
|
+
return JSON.stringify(nodes);
|
|
6527
|
+
}
|
|
6528
|
+
function parseNavOrderJson(raw) {
|
|
6529
|
+
if (!raw) return null;
|
|
6530
|
+
try {
|
|
6531
|
+
const parsed = JSON.parse(raw);
|
|
6532
|
+
if (!Array.isArray(parsed)) return null;
|
|
6533
|
+
if (parsed.every((x) => typeof x === "string")) {
|
|
6534
|
+
return forestFromFlatOrder(parsed.filter((x) => typeof x === "string" && x.length > 0));
|
|
6535
|
+
}
|
|
6536
|
+
return parseNavNodeList(parsed);
|
|
6537
|
+
} catch {
|
|
6538
|
+
return null;
|
|
6539
|
+
}
|
|
6540
|
+
}
|
|
6541
|
+
function parseNavNodeList(raw) {
|
|
6542
|
+
const out = [];
|
|
6543
|
+
for (const item of raw) {
|
|
6544
|
+
if (typeof item === "string" && item.length > 0) {
|
|
6545
|
+
out.push({ id: item, children: [] });
|
|
6546
|
+
continue;
|
|
6547
|
+
}
|
|
6548
|
+
if (!item || typeof item !== "object") return null;
|
|
6549
|
+
const rec = item;
|
|
6550
|
+
if (typeof rec.id !== "string" || !rec.id) return null;
|
|
6551
|
+
const children = Array.isArray(rec.children) ? parseNavNodeList(rec.children) : [];
|
|
6552
|
+
if (!children) return null;
|
|
6553
|
+
out.push({ id: rec.id, children });
|
|
6554
|
+
}
|
|
6555
|
+
return out;
|
|
6556
|
+
}
|
|
6557
|
+
function flattenNavOrder(nodes) {
|
|
6558
|
+
const out = [];
|
|
6559
|
+
const walk = (list) => {
|
|
6560
|
+
for (const n of list) {
|
|
6561
|
+
out.push(n.id);
|
|
6562
|
+
walk(n.children);
|
|
6563
|
+
}
|
|
6564
|
+
};
|
|
6565
|
+
walk(nodes);
|
|
6566
|
+
return out;
|
|
6567
|
+
}
|
|
6568
|
+
|
|
6280
6569
|
// src/lib/nav-items.ts
|
|
6281
6570
|
var NAV_COUNT_KEY = "__ohw_nav_count";
|
|
6282
6571
|
var NAV_ORDER_KEY = "__ohw_nav_order";
|
|
6572
|
+
var NAV_HREF_RE = /^nav-(\d+)-href$/;
|
|
6573
|
+
function isNavbarHrefKey(key) {
|
|
6574
|
+
if (!key) return false;
|
|
6575
|
+
if (key === "nav-book-href") return false;
|
|
6576
|
+
return NAV_HREF_RE.test(key);
|
|
6577
|
+
}
|
|
6283
6578
|
function getLinkHref(el) {
|
|
6284
6579
|
const key = el.getAttribute("data-ohw-href-key");
|
|
6285
6580
|
if (key) {
|
|
@@ -6316,7 +6611,7 @@ function listNavbarItems() {
|
|
|
6316
6611
|
}
|
|
6317
6612
|
function parseNavIndexFromKey(key) {
|
|
6318
6613
|
if (!key) return null;
|
|
6319
|
-
const match = key.match(
|
|
6614
|
+
const match = key.match(NAV_HREF_RE);
|
|
6320
6615
|
if (!match) return null;
|
|
6321
6616
|
return parseInt(match[1], 10);
|
|
6322
6617
|
}
|
|
@@ -6339,17 +6634,6 @@ function getNavbarExistingTargets() {
|
|
|
6339
6634
|
function getNavOrderFromDom() {
|
|
6340
6635
|
return listNavbarItems().map((el) => el.getAttribute("data-ohw-href-key")).filter((key) => Boolean(key));
|
|
6341
6636
|
}
|
|
6342
|
-
function parseNavOrder(content) {
|
|
6343
|
-
const raw = content[NAV_ORDER_KEY];
|
|
6344
|
-
if (!raw) return null;
|
|
6345
|
-
try {
|
|
6346
|
-
const parsed = JSON.parse(raw);
|
|
6347
|
-
if (!Array.isArray(parsed)) return null;
|
|
6348
|
-
return parsed.filter((key) => typeof key === "string" && key.length > 0);
|
|
6349
|
-
} catch {
|
|
6350
|
-
return null;
|
|
6351
|
-
}
|
|
6352
|
-
}
|
|
6353
6637
|
function findCounterpartByHrefKey(hrefKey, root) {
|
|
6354
6638
|
return root.querySelector(`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`);
|
|
6355
6639
|
}
|
|
@@ -6413,19 +6697,47 @@ function insertNavbarItemDom(index, href, label, afterAnchor) {
|
|
|
6413
6697
|
}
|
|
6414
6698
|
return primary;
|
|
6415
6699
|
}
|
|
6700
|
+
function navOrderKeysEqual(a, b) {
|
|
6701
|
+
if (a.length !== b.length) return false;
|
|
6702
|
+
for (let i = 0; i < a.length; i++) {
|
|
6703
|
+
if (a[i] !== b[i]) return false;
|
|
6704
|
+
}
|
|
6705
|
+
return true;
|
|
6706
|
+
}
|
|
6707
|
+
function getNavbarLinkKeysInContainer(container) {
|
|
6708
|
+
return Array.from(container.querySelectorAll("[data-ohw-href-key]")).filter(isNavbarLinkItem).map((el) => el.getAttribute("data-ohw-href-key")).filter((key) => Boolean(key));
|
|
6709
|
+
}
|
|
6416
6710
|
function applyNavOrderToContainer(container, order) {
|
|
6711
|
+
const desired = order.filter((key, i) => order.indexOf(key) === i);
|
|
6712
|
+
const current = getNavbarLinkKeysInContainer(container);
|
|
6713
|
+
const extras = current.filter((key) => !desired.includes(key));
|
|
6714
|
+
const expected = [...desired.filter((key) => current.includes(key)), ...extras];
|
|
6715
|
+
const orderedEls = [];
|
|
6716
|
+
if (navOrderKeysEqual(current, expected)) return;
|
|
6717
|
+
if (current.length === expected.length && current.every((key, i) => key === expected[i])) {
|
|
6718
|
+
return;
|
|
6719
|
+
}
|
|
6720
|
+
const lastCurrentLinkEl = current.length > 0 ? findCounterpartByHrefKey(current[current.length - 1], container) : null;
|
|
6721
|
+
const anchor = lastCurrentLinkEl?.parentElement === container ? lastCurrentLinkEl.nextElementSibling : null;
|
|
6417
6722
|
const seen = /* @__PURE__ */ new Set();
|
|
6418
|
-
for (const hrefKey of
|
|
6723
|
+
for (const hrefKey of desired) {
|
|
6419
6724
|
if (seen.has(hrefKey)) continue;
|
|
6420
6725
|
seen.add(hrefKey);
|
|
6421
6726
|
const el = findCounterpartByHrefKey(hrefKey, container);
|
|
6422
|
-
if (el)
|
|
6727
|
+
if (el && isNavbarLinkItem(el)) orderedEls.push(el);
|
|
6423
6728
|
}
|
|
6424
6729
|
for (const el of container.querySelectorAll("[data-ohw-href-key]")) {
|
|
6425
6730
|
if (!isNavbarLinkItem(el)) continue;
|
|
6426
6731
|
const key = el.getAttribute("data-ohw-href-key");
|
|
6427
6732
|
if (!key || seen.has(key)) continue;
|
|
6428
|
-
|
|
6733
|
+
orderedEls.push(el);
|
|
6734
|
+
}
|
|
6735
|
+
for (const el of orderedEls) {
|
|
6736
|
+
if (anchor) {
|
|
6737
|
+
if (el.nextSibling !== anchor) container.insertBefore(el, anchor);
|
|
6738
|
+
} else if (container.lastElementChild !== el) {
|
|
6739
|
+
container.appendChild(el);
|
|
6740
|
+
}
|
|
6429
6741
|
}
|
|
6430
6742
|
}
|
|
6431
6743
|
function applyNavOrder(order) {
|
|
@@ -6434,6 +6746,75 @@ function applyNavOrder(order) {
|
|
|
6434
6746
|
const drawer = getNavbarDrawerContainer();
|
|
6435
6747
|
if (drawer) applyNavOrderToContainer(drawer, order);
|
|
6436
6748
|
}
|
|
6749
|
+
function applyChildrenOrder(parentHrefKey, childKeys, root) {
|
|
6750
|
+
const parent = findCounterpartByHrefKey(parentHrefKey, root);
|
|
6751
|
+
if (!parent) return;
|
|
6752
|
+
const group = parent.closest("[data-ohw-nav-group]");
|
|
6753
|
+
const childrenRoot = group?.querySelector(":scope > [data-ohw-nav-children]");
|
|
6754
|
+
if (!childrenRoot) return;
|
|
6755
|
+
const current = Array.from(childrenRoot.querySelectorAll(":scope > [data-ohw-href-key]")).map((el) => el.getAttribute("data-ohw-href-key")).filter((key) => Boolean(key));
|
|
6756
|
+
if (navOrderKeysEqual(current, childKeys)) return;
|
|
6757
|
+
for (const key of childKeys) {
|
|
6758
|
+
const el = findCounterpartByHrefKey(key, root);
|
|
6759
|
+
if (!el) continue;
|
|
6760
|
+
if (childrenRoot.lastElementChild !== el) {
|
|
6761
|
+
childrenRoot.appendChild(el);
|
|
6762
|
+
}
|
|
6763
|
+
}
|
|
6764
|
+
}
|
|
6765
|
+
function applyNavForest(forest) {
|
|
6766
|
+
if (forestsEqual(forest, getNavForestFromDom())) return;
|
|
6767
|
+
const rootKeys = forest.map((n) => n.id);
|
|
6768
|
+
applyNavOrder(rootKeys);
|
|
6769
|
+
const desktop = getNavbarDesktopContainer();
|
|
6770
|
+
const drawer = getNavbarDrawerContainer();
|
|
6771
|
+
for (const node of forest) {
|
|
6772
|
+
if (node.children.length === 0) continue;
|
|
6773
|
+
const childKeys = node.children.map((c) => c.id);
|
|
6774
|
+
if (desktop) applyChildrenOrder(node.id, childKeys, desktop);
|
|
6775
|
+
if (drawer) applyChildrenOrder(node.id, childKeys, drawer);
|
|
6776
|
+
}
|
|
6777
|
+
}
|
|
6778
|
+
function getNavForestFromDom() {
|
|
6779
|
+
const items = listNavbarItems();
|
|
6780
|
+
const nestedChildKeys = /* @__PURE__ */ new Set();
|
|
6781
|
+
const roots = [];
|
|
6782
|
+
for (const item of items) {
|
|
6783
|
+
const key = item.getAttribute("data-ohw-href-key");
|
|
6784
|
+
if (!key || !isNavbarHrefKey(key)) continue;
|
|
6785
|
+
if (item.closest("[data-ohw-nav-children]")) continue;
|
|
6786
|
+
const group = item.closest("[data-ohw-nav-group]");
|
|
6787
|
+
const childrenRoot = group?.querySelector(":scope > [data-ohw-nav-children]");
|
|
6788
|
+
const children = [];
|
|
6789
|
+
if (childrenRoot) {
|
|
6790
|
+
for (const child of childrenRoot.querySelectorAll(":scope > [data-ohw-href-key]")) {
|
|
6791
|
+
if (!isNavbarLinkItem(child)) continue;
|
|
6792
|
+
const childKey = child.getAttribute("data-ohw-href-key");
|
|
6793
|
+
if (!childKey || !isNavbarHrefKey(childKey)) continue;
|
|
6794
|
+
nestedChildKeys.add(childKey);
|
|
6795
|
+
children.push({ id: childKey, children: [] });
|
|
6796
|
+
}
|
|
6797
|
+
}
|
|
6798
|
+
roots.push({ id: key, children });
|
|
6799
|
+
}
|
|
6800
|
+
if (roots.length === 0) {
|
|
6801
|
+
return forestFromFlatOrder(
|
|
6802
|
+
getNavOrderFromDom().filter((k) => isNavbarHrefKey(k) && !nestedChildKeys.has(k))
|
|
6803
|
+
);
|
|
6804
|
+
}
|
|
6805
|
+
return roots;
|
|
6806
|
+
}
|
|
6807
|
+
function planNavItemMove(hrefKey, parentId, insertIndex) {
|
|
6808
|
+
const model = getNavForestFromDom();
|
|
6809
|
+
const next = moveNode(model, hrefKey, { parentId, index: insertIndex });
|
|
6810
|
+
if (!next) return null;
|
|
6811
|
+
if (forestsEqual(model, next)) return null;
|
|
6812
|
+
return {
|
|
6813
|
+
forest: next,
|
|
6814
|
+
orderJson: serializeNavOrder(next),
|
|
6815
|
+
flatOrder: flattenNavOrder(next)
|
|
6816
|
+
};
|
|
6817
|
+
}
|
|
6437
6818
|
function collectNavbarIndicesFromContent(content) {
|
|
6438
6819
|
const indices = /* @__PURE__ */ new Set();
|
|
6439
6820
|
for (const key of Object.keys(content)) {
|
|
@@ -6461,8 +6842,10 @@ function reconcileNavbarItemsFromContent(content) {
|
|
|
6461
6842
|
if (!href && !label) continue;
|
|
6462
6843
|
insertNavbarItemDom(index, href ?? "/", label ?? "Untitled", null);
|
|
6463
6844
|
}
|
|
6464
|
-
const
|
|
6465
|
-
if (
|
|
6845
|
+
const orderForest = parseNavOrderJson(content[NAV_ORDER_KEY]);
|
|
6846
|
+
if (orderForest?.length) {
|
|
6847
|
+
applyNavForest(orderForest);
|
|
6848
|
+
}
|
|
6466
6849
|
}
|
|
6467
6850
|
function buildNavOrderAfterInsert(afterAnchor, newHrefKey) {
|
|
6468
6851
|
const order = getNavOrderFromDom();
|
|
@@ -6502,111 +6885,1018 @@ function insertNavbarItem(href, label, afterAnchor = null) {
|
|
|
6502
6885
|
};
|
|
6503
6886
|
}
|
|
6504
6887
|
|
|
6505
|
-
// src/
|
|
6506
|
-
var
|
|
6507
|
-
var
|
|
6508
|
-
function
|
|
6509
|
-
|
|
6510
|
-
|
|
6511
|
-
|
|
6512
|
-
|
|
6513
|
-
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
6514
|
-
"div",
|
|
6515
|
-
{
|
|
6516
|
-
"data-ohw-navbar-container-chrome": "",
|
|
6517
|
-
"data-ohw-bridge": "",
|
|
6518
|
-
className: "pointer-events-none fixed z-[2147483647]",
|
|
6519
|
-
style: {
|
|
6520
|
-
top: rect.top - chromeGap,
|
|
6521
|
-
left: rect.left - chromeGap,
|
|
6522
|
-
width: rect.width + chromeGap * 2,
|
|
6523
|
-
height: rect.height + chromeGap * 2
|
|
6524
|
-
},
|
|
6525
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
6526
|
-
"button",
|
|
6527
|
-
{
|
|
6528
|
-
type: "button",
|
|
6529
|
-
"data-ohw-navbar-add-button": "",
|
|
6530
|
-
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",
|
|
6531
|
-
style: { top: "70%" },
|
|
6532
|
-
"aria-label": "Add item",
|
|
6533
|
-
onMouseDown: (e) => {
|
|
6534
|
-
e.preventDefault();
|
|
6535
|
-
e.stopPropagation();
|
|
6536
|
-
},
|
|
6537
|
-
onClick: (e) => {
|
|
6538
|
-
e.preventDefault();
|
|
6539
|
-
e.stopPropagation();
|
|
6540
|
-
onAdd();
|
|
6541
|
-
},
|
|
6542
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react10.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
|
|
6543
|
-
}
|
|
6544
|
-
)
|
|
6545
|
-
}
|
|
6546
|
-
);
|
|
6888
|
+
// src/lib/footer-items.ts
|
|
6889
|
+
var FOOTER_ORDER_KEY = "__ohw_footer_order";
|
|
6890
|
+
var FOOTER_HREF_RE = /^footer-(\d+)-(\d+)-href$/;
|
|
6891
|
+
function parseFooterHrefKey(key) {
|
|
6892
|
+
if (!key) return null;
|
|
6893
|
+
const match = key.match(FOOTER_HREF_RE);
|
|
6894
|
+
if (!match) return null;
|
|
6895
|
+
return { col: parseInt(match[1], 10), item: parseInt(match[2], 10) };
|
|
6547
6896
|
}
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
6551
|
-
var badgeVariants = cva(
|
|
6552
|
-
"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",
|
|
6553
|
-
{
|
|
6554
|
-
variants: {
|
|
6555
|
-
variant: {
|
|
6556
|
-
default: "border-transparent bg-primary text-primary-foreground",
|
|
6557
|
-
secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
6558
|
-
destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
|
6559
|
-
outline: "text-foreground"
|
|
6560
|
-
}
|
|
6561
|
-
},
|
|
6562
|
-
defaultVariants: {
|
|
6563
|
-
variant: "default"
|
|
6564
|
-
}
|
|
6565
|
-
}
|
|
6566
|
-
);
|
|
6567
|
-
function Badge({ className, variant, ...props }) {
|
|
6568
|
-
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: cn(badgeVariants({ variant }), className), ...props });
|
|
6897
|
+
function isFooterHrefKey(key) {
|
|
6898
|
+
return parseFooterHrefKey(key) !== null;
|
|
6569
6899
|
}
|
|
6570
|
-
|
|
6571
|
-
|
|
6572
|
-
var import_lucide_react11 = require("lucide-react");
|
|
6573
|
-
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
6574
|
-
var PRIMARY2 = "#0885FE";
|
|
6575
|
-
var IMAGE_FADE_MS = 300;
|
|
6576
|
-
function runOpacityFade(el, onDone) {
|
|
6577
|
-
const anim = el.animate([{ opacity: 0 }, { opacity: 1 }], {
|
|
6578
|
-
duration: IMAGE_FADE_MS,
|
|
6579
|
-
easing: "ease",
|
|
6580
|
-
fill: "forwards"
|
|
6581
|
-
});
|
|
6582
|
-
let finished = false;
|
|
6583
|
-
const finish = () => {
|
|
6584
|
-
if (finished) return;
|
|
6585
|
-
finished = true;
|
|
6586
|
-
anim.cancel();
|
|
6587
|
-
el.style.opacity = "";
|
|
6588
|
-
onDone();
|
|
6589
|
-
};
|
|
6590
|
-
anim.finished.then(finish).catch(finish);
|
|
6591
|
-
window.setTimeout(finish, IMAGE_FADE_MS + 100);
|
|
6900
|
+
function getFooterRoot() {
|
|
6901
|
+
return document.querySelector('footer[data-ohw-section="footer"], footer');
|
|
6592
6902
|
}
|
|
6593
|
-
function
|
|
6594
|
-
|
|
6595
|
-
|
|
6596
|
-
|
|
6597
|
-
|
|
6903
|
+
function getFooterLinksContainer() {
|
|
6904
|
+
return document.querySelector("[data-ohw-footer-links]") ?? document.querySelector(".rb-footer-links");
|
|
6905
|
+
}
|
|
6906
|
+
function isFooterLinkAnchor(el) {
|
|
6907
|
+
if (!el.matches("[data-ohw-href-key]")) return false;
|
|
6908
|
+
if (!isFooterHrefKey(el.getAttribute("data-ohw-href-key"))) return false;
|
|
6909
|
+
return Boolean(el.querySelector('[data-ohw-editable="text"]'));
|
|
6910
|
+
}
|
|
6911
|
+
function listFooterColumns() {
|
|
6912
|
+
const root = getFooterLinksContainer() ?? getFooterRoot()?.querySelector(".rb-footer-links") ?? null;
|
|
6913
|
+
if (!root) return [];
|
|
6914
|
+
const explicit = Array.from(root.querySelectorAll(":scope > [data-ohw-footer-col]"));
|
|
6915
|
+
if (explicit.length > 0) return explicit;
|
|
6916
|
+
return Array.from(root.children).filter((el) => {
|
|
6917
|
+
if (!(el instanceof HTMLElement)) return false;
|
|
6918
|
+
return Array.from(el.querySelectorAll(":scope > [data-ohw-href-key]")).some(
|
|
6919
|
+
isFooterLinkAnchor
|
|
6920
|
+
);
|
|
6598
6921
|
});
|
|
6599
6922
|
}
|
|
6600
|
-
function
|
|
6601
|
-
|
|
6602
|
-
|
|
6603
|
-
|
|
6923
|
+
function listFooterLinksInColumn(column) {
|
|
6924
|
+
return Array.from(column.querySelectorAll(":scope > [data-ohw-href-key]")).filter(
|
|
6925
|
+
isFooterLinkAnchor
|
|
6926
|
+
);
|
|
6604
6927
|
}
|
|
6605
|
-
function
|
|
6606
|
-
const
|
|
6607
|
-
|
|
6608
|
-
|
|
6609
|
-
|
|
6928
|
+
function findFooterColumnForLink(anchor) {
|
|
6929
|
+
const columns = listFooterColumns();
|
|
6930
|
+
return columns.find((col) => col.contains(anchor)) ?? null;
|
|
6931
|
+
}
|
|
6932
|
+
function getFooterOrderFromDom() {
|
|
6933
|
+
return listFooterColumns().map(
|
|
6934
|
+
(col) => listFooterLinksInColumn(col).map((el) => el.getAttribute("data-ohw-href-key")).filter((key) => Boolean(key))
|
|
6935
|
+
);
|
|
6936
|
+
}
|
|
6937
|
+
function findFooterLinkByKey(hrefKey) {
|
|
6938
|
+
return document.querySelector(
|
|
6939
|
+
`footer [data-ohw-href-key="${CSS.escape(hrefKey)}"]`
|
|
6940
|
+
);
|
|
6941
|
+
}
|
|
6942
|
+
function syncFooterColumnIndices(columns) {
|
|
6943
|
+
columns.forEach((col, index) => {
|
|
6944
|
+
const next = String(index);
|
|
6945
|
+
if (col.getAttribute("data-ohw-footer-col") !== next) {
|
|
6946
|
+
col.setAttribute("data-ohw-footer-col", next);
|
|
6947
|
+
}
|
|
6948
|
+
});
|
|
6949
|
+
}
|
|
6950
|
+
function appendChildIfNeeded(parent, child) {
|
|
6951
|
+
if (parent.lastElementChild !== child) {
|
|
6952
|
+
parent.appendChild(child);
|
|
6953
|
+
}
|
|
6954
|
+
}
|
|
6955
|
+
function applyFooterOrder(order) {
|
|
6956
|
+
const container = getFooterLinksContainer();
|
|
6957
|
+
if (!container) return;
|
|
6958
|
+
const columns = listFooterColumns();
|
|
6959
|
+
if (columns.length === 0) return;
|
|
6960
|
+
const currentOrder = getFooterOrderFromDom();
|
|
6961
|
+
if (ordersEqual(order, currentOrder)) {
|
|
6962
|
+
syncFooterColumnIndices(columns);
|
|
6963
|
+
return;
|
|
6964
|
+
}
|
|
6965
|
+
const used = /* @__PURE__ */ new Set();
|
|
6966
|
+
const orderedCols = [];
|
|
6967
|
+
for (const colOrder of order) {
|
|
6968
|
+
let matched = null;
|
|
6969
|
+
for (const hrefKey of colOrder) {
|
|
6970
|
+
const link = findFooterLinkByKey(hrefKey);
|
|
6971
|
+
if (!link) continue;
|
|
6972
|
+
const owner = findFooterColumnForLink(link);
|
|
6973
|
+
if (owner && !used.has(owner)) {
|
|
6974
|
+
matched = owner;
|
|
6975
|
+
break;
|
|
6976
|
+
}
|
|
6977
|
+
}
|
|
6978
|
+
if (!matched) {
|
|
6979
|
+
matched = columns.find((col) => !used.has(col)) ?? null;
|
|
6980
|
+
}
|
|
6981
|
+
if (matched) {
|
|
6982
|
+
used.add(matched);
|
|
6983
|
+
orderedCols.push(matched);
|
|
6984
|
+
}
|
|
6985
|
+
}
|
|
6986
|
+
for (const col of columns) {
|
|
6987
|
+
if (!used.has(col)) orderedCols.push(col);
|
|
6988
|
+
}
|
|
6989
|
+
for (const col of orderedCols) {
|
|
6990
|
+
appendChildIfNeeded(container, col);
|
|
6991
|
+
}
|
|
6992
|
+
const freshColumns = listFooterColumns();
|
|
6993
|
+
syncFooterColumnIndices(freshColumns);
|
|
6994
|
+
for (let c = 0; c < order.length; c++) {
|
|
6995
|
+
const col = freshColumns[c];
|
|
6996
|
+
if (!col) continue;
|
|
6997
|
+
const colOrder = order[c];
|
|
6998
|
+
for (const hrefKey of colOrder) {
|
|
6999
|
+
const el = findFooterLinkByKey(hrefKey);
|
|
7000
|
+
if (!el) continue;
|
|
7001
|
+
if (el.parentElement !== col || col.lastElementChild !== el) {
|
|
7002
|
+
col.appendChild(el);
|
|
7003
|
+
}
|
|
7004
|
+
}
|
|
7005
|
+
}
|
|
7006
|
+
}
|
|
7007
|
+
function ordersEqual(a, b) {
|
|
7008
|
+
if (a.length !== b.length) return false;
|
|
7009
|
+
for (let i = 0; i < a.length; i++) {
|
|
7010
|
+
const left = a[i];
|
|
7011
|
+
const right = b[i];
|
|
7012
|
+
if (left.length !== right.length) return false;
|
|
7013
|
+
for (let j = 0; j < left.length; j++) {
|
|
7014
|
+
if (left[j] !== right[j]) return false;
|
|
7015
|
+
}
|
|
7016
|
+
}
|
|
7017
|
+
return true;
|
|
7018
|
+
}
|
|
7019
|
+
function planFooterLinkMove(hrefKey, targetColIndex, insertIndex) {
|
|
7020
|
+
const order = getFooterOrderFromDom();
|
|
7021
|
+
if (targetColIndex < 0 || targetColIndex >= order.length) return null;
|
|
7022
|
+
let fromCol = -1;
|
|
7023
|
+
let fromIdx = -1;
|
|
7024
|
+
for (let c = 0; c < order.length; c++) {
|
|
7025
|
+
const idx = order[c].indexOf(hrefKey);
|
|
7026
|
+
if (idx >= 0) {
|
|
7027
|
+
fromCol = c;
|
|
7028
|
+
fromIdx = idx;
|
|
7029
|
+
break;
|
|
7030
|
+
}
|
|
7031
|
+
}
|
|
7032
|
+
if (fromCol < 0) return null;
|
|
7033
|
+
const next = order.map((col) => [...col]);
|
|
7034
|
+
next[fromCol].splice(fromIdx, 1);
|
|
7035
|
+
let adjusted = insertIndex;
|
|
7036
|
+
if (fromCol === targetColIndex && fromIdx < insertIndex) adjusted -= 1;
|
|
7037
|
+
adjusted = Math.max(0, Math.min(adjusted, next[targetColIndex].length));
|
|
7038
|
+
next[targetColIndex].splice(adjusted, 0, hrefKey);
|
|
7039
|
+
if (ordersEqual(next, order)) return null;
|
|
7040
|
+
return next;
|
|
7041
|
+
}
|
|
7042
|
+
function planFooterColumnMove(fromIndex, toIndex) {
|
|
7043
|
+
const order = getFooterOrderFromDom();
|
|
7044
|
+
const columns = listFooterColumns();
|
|
7045
|
+
if (fromIndex < 0 || fromIndex >= columns.length || toIndex < 0 || toIndex > columns.length) {
|
|
7046
|
+
return null;
|
|
7047
|
+
}
|
|
7048
|
+
if (toIndex === fromIndex || toIndex === fromIndex + 1) return null;
|
|
7049
|
+
const nextOrder = order.map((col) => [...col]);
|
|
7050
|
+
const [movedOrder] = nextOrder.splice(fromIndex, 1);
|
|
7051
|
+
if (!movedOrder) return null;
|
|
7052
|
+
let adjusted = toIndex;
|
|
7053
|
+
if (fromIndex < toIndex) adjusted -= 1;
|
|
7054
|
+
adjusted = Math.max(0, Math.min(adjusted, nextOrder.length));
|
|
7055
|
+
nextOrder.splice(adjusted, 0, movedOrder);
|
|
7056
|
+
if (ordersEqual(nextOrder, order)) return null;
|
|
7057
|
+
return nextOrder;
|
|
7058
|
+
}
|
|
7059
|
+
function parseFooterOrder(content) {
|
|
7060
|
+
const raw = content[FOOTER_ORDER_KEY];
|
|
7061
|
+
if (!raw) return null;
|
|
7062
|
+
try {
|
|
7063
|
+
const parsed = JSON.parse(raw);
|
|
7064
|
+
if (!Array.isArray(parsed)) return null;
|
|
7065
|
+
return parsed.filter((col) => Array.isArray(col)).map((col) => col.filter((key) => typeof key === "string" && key.length > 0));
|
|
7066
|
+
} catch {
|
|
7067
|
+
return null;
|
|
7068
|
+
}
|
|
7069
|
+
}
|
|
7070
|
+
function reconcileFooterOrderFromContent(content) {
|
|
7071
|
+
const order = parseFooterOrder(content);
|
|
7072
|
+
if (!order?.length) return;
|
|
7073
|
+
const current = getFooterOrderFromDom();
|
|
7074
|
+
if (ordersEqual(order, current)) {
|
|
7075
|
+
syncFooterColumnIndices(listFooterColumns());
|
|
7076
|
+
return;
|
|
7077
|
+
}
|
|
7078
|
+
applyFooterOrder(order);
|
|
7079
|
+
}
|
|
7080
|
+
function isRowLayoutColumn(links) {
|
|
7081
|
+
if (links.length < 2) return false;
|
|
7082
|
+
const firstTop = links[0].getBoundingClientRect().top;
|
|
7083
|
+
return links.every((link) => Math.abs(link.getBoundingClientRect().top - firstTop) < 4);
|
|
7084
|
+
}
|
|
7085
|
+
function buildLinkDropSlots(column, columnIndex) {
|
|
7086
|
+
const links = listFooterLinksInColumn(column);
|
|
7087
|
+
const colRect = column.getBoundingClientRect();
|
|
7088
|
+
const slots = [];
|
|
7089
|
+
const barThickness = 3;
|
|
7090
|
+
if (links.length === 0) {
|
|
7091
|
+
slots.push({
|
|
7092
|
+
insertIndex: 0,
|
|
7093
|
+
columnIndex,
|
|
7094
|
+
left: colRect.left,
|
|
7095
|
+
top: colRect.top + colRect.height / 2 - barThickness / 2,
|
|
7096
|
+
width: colRect.width,
|
|
7097
|
+
height: barThickness,
|
|
7098
|
+
direction: "horizontal"
|
|
7099
|
+
});
|
|
7100
|
+
return slots;
|
|
7101
|
+
}
|
|
7102
|
+
if (isRowLayoutColumn(links)) {
|
|
7103
|
+
for (let i = 0; i <= links.length; i++) {
|
|
7104
|
+
let left;
|
|
7105
|
+
if (i === 0) {
|
|
7106
|
+
left = links[0].getBoundingClientRect().left - barThickness / 2;
|
|
7107
|
+
} else if (i === links.length) {
|
|
7108
|
+
const last = links[links.length - 1].getBoundingClientRect();
|
|
7109
|
+
left = last.right - barThickness / 2;
|
|
7110
|
+
} else {
|
|
7111
|
+
const prev = links[i - 1].getBoundingClientRect();
|
|
7112
|
+
const next = links[i].getBoundingClientRect();
|
|
7113
|
+
left = (prev.right + next.left) / 2 - barThickness / 2;
|
|
7114
|
+
}
|
|
7115
|
+
const heightRef = i === 0 ? links[0].getBoundingClientRect() : i === links.length ? links[links.length - 1].getBoundingClientRect() : links[i].getBoundingClientRect();
|
|
7116
|
+
slots.push({
|
|
7117
|
+
insertIndex: i,
|
|
7118
|
+
columnIndex,
|
|
7119
|
+
left,
|
|
7120
|
+
top: heightRef.top,
|
|
7121
|
+
width: barThickness,
|
|
7122
|
+
height: Math.max(heightRef.height, colRect.height * 0.8),
|
|
7123
|
+
direction: "vertical"
|
|
7124
|
+
});
|
|
7125
|
+
}
|
|
7126
|
+
return slots;
|
|
7127
|
+
}
|
|
7128
|
+
for (let i = 0; i <= links.length; i++) {
|
|
7129
|
+
let top;
|
|
7130
|
+
if (i === 0) {
|
|
7131
|
+
top = links[0].getBoundingClientRect().top - barThickness / 2;
|
|
7132
|
+
} else if (i === links.length) {
|
|
7133
|
+
const last = links[links.length - 1].getBoundingClientRect();
|
|
7134
|
+
top = last.bottom - barThickness / 2;
|
|
7135
|
+
} else {
|
|
7136
|
+
const prev = links[i - 1].getBoundingClientRect();
|
|
7137
|
+
const next = links[i].getBoundingClientRect();
|
|
7138
|
+
top = (prev.bottom + next.top) / 2 - barThickness / 2;
|
|
7139
|
+
}
|
|
7140
|
+
const widthRef = i === 0 ? links[0].getBoundingClientRect() : i === links.length ? links[links.length - 1].getBoundingClientRect() : links[i].getBoundingClientRect();
|
|
7141
|
+
slots.push({
|
|
7142
|
+
insertIndex: i,
|
|
7143
|
+
columnIndex,
|
|
7144
|
+
left: widthRef.left,
|
|
7145
|
+
top,
|
|
7146
|
+
width: Math.max(widthRef.width, colRect.width * 0.8),
|
|
7147
|
+
height: barThickness,
|
|
7148
|
+
direction: "horizontal"
|
|
7149
|
+
});
|
|
7150
|
+
}
|
|
7151
|
+
return slots;
|
|
7152
|
+
}
|
|
7153
|
+
function buildColumnDropSlots() {
|
|
7154
|
+
const columns = listFooterColumns();
|
|
7155
|
+
const slots = [];
|
|
7156
|
+
const barThickness = 3;
|
|
7157
|
+
if (columns.length === 0) return slots;
|
|
7158
|
+
for (let i = 0; i <= columns.length; i++) {
|
|
7159
|
+
let left;
|
|
7160
|
+
let height;
|
|
7161
|
+
let top;
|
|
7162
|
+
if (i === 0) {
|
|
7163
|
+
const first = columns[0].getBoundingClientRect();
|
|
7164
|
+
left = first.left - barThickness / 2;
|
|
7165
|
+
top = first.top;
|
|
7166
|
+
height = first.height;
|
|
7167
|
+
} else if (i === columns.length) {
|
|
7168
|
+
const last = columns[columns.length - 1].getBoundingClientRect();
|
|
7169
|
+
left = last.right - barThickness / 2;
|
|
7170
|
+
top = last.top;
|
|
7171
|
+
height = last.height;
|
|
7172
|
+
} else {
|
|
7173
|
+
const prev = columns[i - 1].getBoundingClientRect();
|
|
7174
|
+
const next = columns[i].getBoundingClientRect();
|
|
7175
|
+
left = (prev.right + next.left) / 2 - barThickness / 2;
|
|
7176
|
+
top = Math.min(prev.top, next.top);
|
|
7177
|
+
height = Math.max(prev.bottom, next.bottom) - top;
|
|
7178
|
+
}
|
|
7179
|
+
slots.push({
|
|
7180
|
+
insertIndex: i,
|
|
7181
|
+
columnIndex: i,
|
|
7182
|
+
left,
|
|
7183
|
+
top,
|
|
7184
|
+
width: barThickness,
|
|
7185
|
+
height: Math.max(height, 24),
|
|
7186
|
+
direction: "vertical"
|
|
7187
|
+
});
|
|
7188
|
+
}
|
|
7189
|
+
return slots;
|
|
7190
|
+
}
|
|
7191
|
+
function hitTestLinkDropSlot(clientX, clientY, draggedHrefKey) {
|
|
7192
|
+
const columns = listFooterColumns();
|
|
7193
|
+
let best = null;
|
|
7194
|
+
for (let c = 0; c < columns.length; c++) {
|
|
7195
|
+
const col = columns[c];
|
|
7196
|
+
const colRect = col.getBoundingClientRect();
|
|
7197
|
+
const inColX = clientX >= colRect.left - 24 && clientX <= colRect.right + 24;
|
|
7198
|
+
if (!inColX) continue;
|
|
7199
|
+
const slots = buildLinkDropSlots(col, c).filter((slot) => {
|
|
7200
|
+
const links = listFooterLinksInColumn(col);
|
|
7201
|
+
const fromIdx = links.findIndex(
|
|
7202
|
+
(el) => el.getAttribute("data-ohw-href-key") === draggedHrefKey
|
|
7203
|
+
);
|
|
7204
|
+
if (fromIdx < 0) return true;
|
|
7205
|
+
if (c === findColumnIndexForKey(draggedHrefKey) && (slot.insertIndex === fromIdx || slot.insertIndex === fromIdx + 1)) {
|
|
7206
|
+
return true;
|
|
7207
|
+
}
|
|
7208
|
+
return true;
|
|
7209
|
+
});
|
|
7210
|
+
for (const slot of slots) {
|
|
7211
|
+
const dist = slot.direction === "vertical" ? Math.abs(clientX - (slot.left + slot.width / 2)) : Math.abs(clientY - (slot.top + slot.height / 2));
|
|
7212
|
+
if (!best || dist < best.dist) best = { slot, dist };
|
|
7213
|
+
}
|
|
7214
|
+
}
|
|
7215
|
+
return best?.slot ?? null;
|
|
7216
|
+
}
|
|
7217
|
+
function findColumnIndexForKey(hrefKey) {
|
|
7218
|
+
const order = getFooterOrderFromDom();
|
|
7219
|
+
for (let c = 0; c < order.length; c++) {
|
|
7220
|
+
if (order[c].includes(hrefKey)) return c;
|
|
7221
|
+
}
|
|
7222
|
+
return -1;
|
|
7223
|
+
}
|
|
7224
|
+
function hitTestColumnDropSlot(clientX, _clientY) {
|
|
7225
|
+
const slots = buildColumnDropSlots();
|
|
7226
|
+
let best = null;
|
|
7227
|
+
for (const slot of slots) {
|
|
7228
|
+
const cx2 = slot.left + slot.width / 2;
|
|
7229
|
+
const dist = Math.abs(clientX - cx2);
|
|
7230
|
+
if (!best || dist < best.dist) best = { slot, dist };
|
|
7231
|
+
}
|
|
7232
|
+
return best?.slot ?? null;
|
|
7233
|
+
}
|
|
7234
|
+
|
|
7235
|
+
// src/lib/item-drag-interaction.ts
|
|
7236
|
+
function disableNativeHrefDrag(el) {
|
|
7237
|
+
if (el.draggable) el.draggable = false;
|
|
7238
|
+
if (el.getAttribute("draggable") !== "false") {
|
|
7239
|
+
el.setAttribute("draggable", "false");
|
|
7240
|
+
}
|
|
7241
|
+
}
|
|
7242
|
+
function clearTextSelection() {
|
|
7243
|
+
const sel = window.getSelection();
|
|
7244
|
+
if (sel && !sel.isCollapsed) sel.removeAllRanges();
|
|
7245
|
+
}
|
|
7246
|
+
function armItemPressDrag() {
|
|
7247
|
+
document.documentElement.setAttribute("data-ohw-footer-press-drag", "");
|
|
7248
|
+
}
|
|
7249
|
+
function lockItemDuringDrag() {
|
|
7250
|
+
document.documentElement.removeAttribute("data-ohw-footer-press-drag");
|
|
7251
|
+
document.documentElement.setAttribute("data-ohw-item-dragging", "");
|
|
7252
|
+
clearTextSelection();
|
|
7253
|
+
}
|
|
7254
|
+
function unlockItemDragInteraction() {
|
|
7255
|
+
document.documentElement.removeAttribute("data-ohw-footer-press-drag");
|
|
7256
|
+
document.documentElement.removeAttribute("data-ohw-item-dragging");
|
|
7257
|
+
clearTextSelection();
|
|
7258
|
+
}
|
|
7259
|
+
var armFooterPressDrag = armItemPressDrag;
|
|
7260
|
+
var lockFooterDuringDrag = lockItemDuringDrag;
|
|
7261
|
+
var unlockFooterDragInteraction = unlockItemDragInteraction;
|
|
7262
|
+
|
|
7263
|
+
// src/lib/nav-dnd.ts
|
|
7264
|
+
function listReorderableNavItems() {
|
|
7265
|
+
return listNavbarItems().filter((el) => {
|
|
7266
|
+
const key = el.getAttribute("data-ohw-href-key");
|
|
7267
|
+
return isNavbarHrefKey(key) && !el.closest("[data-ohw-nav-children]");
|
|
7268
|
+
});
|
|
7269
|
+
}
|
|
7270
|
+
function listNavChildren(parentHrefKey) {
|
|
7271
|
+
const items = listNavbarItems();
|
|
7272
|
+
const parent = items.find((el) => el.getAttribute("data-ohw-href-key") === parentHrefKey);
|
|
7273
|
+
if (!parent) return [];
|
|
7274
|
+
const group = parent.closest("[data-ohw-nav-group]");
|
|
7275
|
+
const childrenRoot = group?.querySelector(":scope > [data-ohw-nav-children]");
|
|
7276
|
+
if (!childrenRoot) return [];
|
|
7277
|
+
return Array.from(childrenRoot.querySelectorAll(":scope > [data-ohw-href-key]")).filter(
|
|
7278
|
+
(el) => isNavbarHrefKey(el.getAttribute("data-ohw-href-key"))
|
|
7279
|
+
);
|
|
7280
|
+
}
|
|
7281
|
+
function activeNavListContainer() {
|
|
7282
|
+
const desktop = getNavbarDesktopContainer();
|
|
7283
|
+
if (desktop && desktop.getClientRects().length > 0) {
|
|
7284
|
+
const style = window.getComputedStyle(desktop);
|
|
7285
|
+
if (style.display !== "none" && style.visibility !== "hidden") return desktop;
|
|
7286
|
+
}
|
|
7287
|
+
return getNavbarDrawerContainer();
|
|
7288
|
+
}
|
|
7289
|
+
function buildRootNavDropSlots() {
|
|
7290
|
+
const items = listReorderableNavItems();
|
|
7291
|
+
const slots = [];
|
|
7292
|
+
const barThickness = 3;
|
|
7293
|
+
if (items.length === 0) {
|
|
7294
|
+
const container = activeNavListContainer();
|
|
7295
|
+
if (!container) return slots;
|
|
7296
|
+
const rect = container.getBoundingClientRect();
|
|
7297
|
+
slots.push({
|
|
7298
|
+
insertIndex: 0,
|
|
7299
|
+
parentId: null,
|
|
7300
|
+
left: rect.left + rect.width / 2 - barThickness / 2,
|
|
7301
|
+
top: rect.top,
|
|
7302
|
+
width: barThickness,
|
|
7303
|
+
height: Math.max(rect.height, 24),
|
|
7304
|
+
direction: "vertical"
|
|
7305
|
+
});
|
|
7306
|
+
return slots;
|
|
7307
|
+
}
|
|
7308
|
+
for (let i = 0; i <= items.length; i++) {
|
|
7309
|
+
let left;
|
|
7310
|
+
let top;
|
|
7311
|
+
let height;
|
|
7312
|
+
if (i === 0) {
|
|
7313
|
+
const first = items[0].getBoundingClientRect();
|
|
7314
|
+
left = first.left - barThickness / 2;
|
|
7315
|
+
top = first.top;
|
|
7316
|
+
height = first.height;
|
|
7317
|
+
} else if (i === items.length) {
|
|
7318
|
+
const last = items[items.length - 1].getBoundingClientRect();
|
|
7319
|
+
left = last.right - barThickness / 2;
|
|
7320
|
+
top = last.top;
|
|
7321
|
+
height = last.height;
|
|
7322
|
+
} else {
|
|
7323
|
+
const prev = items[i - 1].getBoundingClientRect();
|
|
7324
|
+
const next = items[i].getBoundingClientRect();
|
|
7325
|
+
left = (prev.right + next.left) / 2 - barThickness / 2;
|
|
7326
|
+
top = Math.min(prev.top, next.top);
|
|
7327
|
+
height = Math.max(prev.bottom, next.bottom) - top;
|
|
7328
|
+
}
|
|
7329
|
+
slots.push({
|
|
7330
|
+
insertIndex: i,
|
|
7331
|
+
parentId: null,
|
|
7332
|
+
left,
|
|
7333
|
+
top,
|
|
7334
|
+
width: barThickness,
|
|
7335
|
+
height: Math.max(height, 24),
|
|
7336
|
+
direction: "vertical"
|
|
7337
|
+
});
|
|
7338
|
+
}
|
|
7339
|
+
return slots;
|
|
7340
|
+
}
|
|
7341
|
+
function buildChildNavDropSlots(parentHrefKey) {
|
|
7342
|
+
const children = listNavChildren(parentHrefKey);
|
|
7343
|
+
const slots = [];
|
|
7344
|
+
const barThickness = 3;
|
|
7345
|
+
if (children.length === 0) return slots;
|
|
7346
|
+
for (let i = 0; i <= children.length; i++) {
|
|
7347
|
+
let top;
|
|
7348
|
+
let width;
|
|
7349
|
+
let left;
|
|
7350
|
+
if (i === 0) {
|
|
7351
|
+
const first = children[0].getBoundingClientRect();
|
|
7352
|
+
top = first.top - barThickness / 2;
|
|
7353
|
+
left = first.left;
|
|
7354
|
+
width = first.width;
|
|
7355
|
+
} else if (i === children.length) {
|
|
7356
|
+
const last = children[children.length - 1].getBoundingClientRect();
|
|
7357
|
+
top = last.bottom - barThickness / 2;
|
|
7358
|
+
left = last.left;
|
|
7359
|
+
width = last.width;
|
|
7360
|
+
} else {
|
|
7361
|
+
const prev = children[i - 1].getBoundingClientRect();
|
|
7362
|
+
const next = children[i].getBoundingClientRect();
|
|
7363
|
+
top = (prev.bottom + next.top) / 2 - barThickness / 2;
|
|
7364
|
+
left = Math.min(prev.left, next.left);
|
|
7365
|
+
width = Math.max(prev.right, next.right) - left;
|
|
7366
|
+
}
|
|
7367
|
+
slots.push({
|
|
7368
|
+
insertIndex: i,
|
|
7369
|
+
parentId: parentHrefKey,
|
|
7370
|
+
left,
|
|
7371
|
+
top,
|
|
7372
|
+
width: Math.max(width, 40),
|
|
7373
|
+
height: barThickness,
|
|
7374
|
+
direction: "horizontal"
|
|
7375
|
+
});
|
|
7376
|
+
}
|
|
7377
|
+
return slots;
|
|
7378
|
+
}
|
|
7379
|
+
function buildAllNavDropSlots(draggedHrefKey) {
|
|
7380
|
+
const slots = [...buildRootNavDropSlots()];
|
|
7381
|
+
for (const item of listReorderableNavItems()) {
|
|
7382
|
+
const key = item.getAttribute("data-ohw-href-key");
|
|
7383
|
+
if (!key || key === draggedHrefKey) continue;
|
|
7384
|
+
const group = item.closest("[data-ohw-nav-group]");
|
|
7385
|
+
if (!group?.querySelector(":scope > [data-ohw-nav-children]")) continue;
|
|
7386
|
+
slots.push(...buildChildNavDropSlots(key));
|
|
7387
|
+
}
|
|
7388
|
+
const dragged = listNavbarItems().find((el) => el.getAttribute("data-ohw-href-key") === draggedHrefKey);
|
|
7389
|
+
const parentGroup = dragged?.closest("[data-ohw-nav-children]")?.closest("[data-ohw-nav-group]");
|
|
7390
|
+
const parentTrigger = parentGroup?.querySelector(":scope > [data-ohw-href-key]");
|
|
7391
|
+
const parentKey = parentTrigger?.getAttribute("data-ohw-href-key");
|
|
7392
|
+
if (parentKey && isNavbarHrefKey(parentKey)) {
|
|
7393
|
+
const existing = slots.some((s) => s.parentId === parentKey);
|
|
7394
|
+
if (!existing) slots.push(...buildChildNavDropSlots(parentKey));
|
|
7395
|
+
}
|
|
7396
|
+
return slots;
|
|
7397
|
+
}
|
|
7398
|
+
function hitTestNavDropSlot(clientX, clientY, draggedHrefKey) {
|
|
7399
|
+
const slots = buildAllNavDropSlots(draggedHrefKey);
|
|
7400
|
+
let best = null;
|
|
7401
|
+
for (const slot of slots) {
|
|
7402
|
+
const cx2 = slot.left + slot.width / 2;
|
|
7403
|
+
const cy = slot.top + slot.height / 2;
|
|
7404
|
+
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;
|
|
7405
|
+
if (!best || dist < best.dist) best = { slot, dist };
|
|
7406
|
+
}
|
|
7407
|
+
return best?.slot ?? null;
|
|
7408
|
+
}
|
|
7409
|
+
function siblingRectsForNavDrag(draggedEl, activeParentId) {
|
|
7410
|
+
if (activeParentId) {
|
|
7411
|
+
return listNavChildren(activeParentId).filter((el) => el !== draggedEl).map((el) => el.getBoundingClientRect());
|
|
7412
|
+
}
|
|
7413
|
+
return listReorderableNavItems().filter((el) => el !== draggedEl).map((el) => el.getBoundingClientRect());
|
|
7414
|
+
}
|
|
7415
|
+
|
|
7416
|
+
// src/useNavItemDrag.ts
|
|
7417
|
+
var import_react8 = require("react");
|
|
7418
|
+
function useNavItemDrag({
|
|
7419
|
+
isEditMode,
|
|
7420
|
+
editContentRef,
|
|
7421
|
+
selectedElRef,
|
|
7422
|
+
activeElRef,
|
|
7423
|
+
footerDragRef,
|
|
7424
|
+
suppressNextClickRef,
|
|
7425
|
+
suppressClickUntilRef,
|
|
7426
|
+
siblingHintElRef,
|
|
7427
|
+
postToParentRef,
|
|
7428
|
+
deselectRef,
|
|
7429
|
+
selectRef,
|
|
7430
|
+
deactivateRef,
|
|
7431
|
+
setLinkPopover,
|
|
7432
|
+
linkPopoverOpenRef,
|
|
7433
|
+
setIsItemDragging,
|
|
7434
|
+
setDraggedItemRect,
|
|
7435
|
+
setSiblingHintRect,
|
|
7436
|
+
setSiblingHintRects,
|
|
7437
|
+
setToolbarRect,
|
|
7438
|
+
getNavigationItemAnchor: getNavigationItemAnchor2,
|
|
7439
|
+
isDragHandleDisabled: isDragHandleDisabled2,
|
|
7440
|
+
isNavbarButton: isNavbarButton3
|
|
7441
|
+
}) {
|
|
7442
|
+
const navDragRef = (0, import_react8.useRef)(null);
|
|
7443
|
+
const [navDropSlots, setNavDropSlots] = (0, import_react8.useState)([]);
|
|
7444
|
+
const [activeNavDropIndex, setActiveNavDropIndex] = (0, import_react8.useState)(null);
|
|
7445
|
+
const navPointerDragRef = (0, import_react8.useRef)(null);
|
|
7446
|
+
const clearNavDragVisuals = (0, import_react8.useCallback)(() => {
|
|
7447
|
+
navDragRef.current = null;
|
|
7448
|
+
setNavDropSlots([]);
|
|
7449
|
+
setActiveNavDropIndex(null);
|
|
7450
|
+
setDraggedItemRect(null);
|
|
7451
|
+
setSiblingHintRects([]);
|
|
7452
|
+
setIsItemDragging(false);
|
|
7453
|
+
unlockItemDragInteraction();
|
|
7454
|
+
}, [setDraggedItemRect, setIsItemDragging, setSiblingHintRects]);
|
|
7455
|
+
const refreshNavDragVisuals = (0, import_react8.useCallback)(
|
|
7456
|
+
(session, activeSlot, clientX, clientY) => {
|
|
7457
|
+
setDraggedItemRect(session.draggedEl.getBoundingClientRect());
|
|
7458
|
+
if (typeof clientX === "number" && typeof clientY === "number") {
|
|
7459
|
+
session.lastClientX = clientX;
|
|
7460
|
+
session.lastClientY = clientY;
|
|
7461
|
+
}
|
|
7462
|
+
session.activeSlot = activeSlot;
|
|
7463
|
+
const parentId = activeSlot?.parentId ?? null;
|
|
7464
|
+
setSiblingHintRects(siblingRectsForNavDrag(session.draggedEl, parentId));
|
|
7465
|
+
const slots = buildAllNavDropSlots(session.hrefKey);
|
|
7466
|
+
setNavDropSlots(slots);
|
|
7467
|
+
const activeIdx = activeSlot ? slots.findIndex(
|
|
7468
|
+
(s) => s.parentId === activeSlot.parentId && s.insertIndex === activeSlot.insertIndex
|
|
7469
|
+
) : -1;
|
|
7470
|
+
setActiveNavDropIndex(activeIdx >= 0 ? activeIdx : null);
|
|
7471
|
+
},
|
|
7472
|
+
[setDraggedItemRect, setSiblingHintRects]
|
|
7473
|
+
);
|
|
7474
|
+
const refreshNavDragVisualsRef = (0, import_react8.useRef)(refreshNavDragVisuals);
|
|
7475
|
+
refreshNavDragVisualsRef.current = refreshNavDragVisuals;
|
|
7476
|
+
const commitNavDragRef = (0, import_react8.useRef)(() => {
|
|
7477
|
+
});
|
|
7478
|
+
const beginNavDragRef = (0, import_react8.useRef)(() => {
|
|
7479
|
+
});
|
|
7480
|
+
const beginNavDrag = (0, import_react8.useCallback)(
|
|
7481
|
+
(session) => {
|
|
7482
|
+
const rect = session.draggedEl.getBoundingClientRect();
|
|
7483
|
+
session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
|
|
7484
|
+
session.lastClientY = session.lastClientY || rect.top + rect.height / 2;
|
|
7485
|
+
session.activeSlot = session.activeSlot ?? null;
|
|
7486
|
+
navDragRef.current = session;
|
|
7487
|
+
setIsItemDragging(true);
|
|
7488
|
+
lockItemDuringDrag();
|
|
7489
|
+
siblingHintElRef.current = null;
|
|
7490
|
+
setSiblingHintRect(null);
|
|
7491
|
+
if (session.wasSelected && selectedElRef.current === session.draggedEl) {
|
|
7492
|
+
setToolbarRect(rect);
|
|
7493
|
+
}
|
|
7494
|
+
const initialSlot = hitTestNavDropSlot(session.lastClientX, session.lastClientY, session.hrefKey);
|
|
7495
|
+
refreshNavDragVisuals(session, initialSlot, session.lastClientX, session.lastClientY);
|
|
7496
|
+
},
|
|
7497
|
+
[
|
|
7498
|
+
refreshNavDragVisuals,
|
|
7499
|
+
selectedElRef,
|
|
7500
|
+
setIsItemDragging,
|
|
7501
|
+
setSiblingHintRect,
|
|
7502
|
+
setToolbarRect,
|
|
7503
|
+
siblingHintElRef
|
|
7504
|
+
]
|
|
7505
|
+
);
|
|
7506
|
+
beginNavDragRef.current = beginNavDrag;
|
|
7507
|
+
const commitNavDrag = (0, import_react8.useCallback)(
|
|
7508
|
+
(clientX, clientY) => {
|
|
7509
|
+
const session = navDragRef.current;
|
|
7510
|
+
if (!session) {
|
|
7511
|
+
clearNavDragVisuals();
|
|
7512
|
+
return;
|
|
7513
|
+
}
|
|
7514
|
+
const x = typeof clientX === "number" && (clientX !== 0 || clientY !== 0) ? clientX : session.lastClientX;
|
|
7515
|
+
const y = typeof clientY === "number" && (clientX !== 0 || clientY !== 0) ? clientY : session.lastClientY;
|
|
7516
|
+
const slot = session.activeSlot ?? hitTestNavDropSlot(x, y, session.hrefKey);
|
|
7517
|
+
const planned = slot != null ? planNavItemMove(session.hrefKey, slot.parentId, slot.insertIndex) : null;
|
|
7518
|
+
const wasSelected = session.wasSelected;
|
|
7519
|
+
const hrefKey = session.hrefKey;
|
|
7520
|
+
const applySelectionAfterDrop = () => {
|
|
7521
|
+
if (!wasSelected) {
|
|
7522
|
+
deselectRef.current();
|
|
7523
|
+
return;
|
|
7524
|
+
}
|
|
7525
|
+
const desktop = document.querySelector("[data-ohw-nav-container]");
|
|
7526
|
+
const drawer = document.querySelector("[data-ohw-nav-drawer]");
|
|
7527
|
+
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)}"]`);
|
|
7528
|
+
if (link) {
|
|
7529
|
+
selectRef.current(link);
|
|
7530
|
+
return;
|
|
7531
|
+
}
|
|
7532
|
+
deselectRef.current();
|
|
7533
|
+
};
|
|
7534
|
+
if (planned) {
|
|
7535
|
+
editContentRef.current = {
|
|
7536
|
+
...editContentRef.current,
|
|
7537
|
+
[NAV_ORDER_KEY]: planned.orderJson
|
|
7538
|
+
};
|
|
7539
|
+
applyNavForest(planned.forest);
|
|
7540
|
+
document.querySelectorAll(
|
|
7541
|
+
"nav [data-ohw-href-key], [data-ohw-nav-container] [data-ohw-href-key], [data-ohw-nav-drawer] [data-ohw-href-key]"
|
|
7542
|
+
).forEach((el) => {
|
|
7543
|
+
if (isNavbarHrefKey(el.getAttribute("data-ohw-href-key"))) {
|
|
7544
|
+
disableNativeHrefDrag(el);
|
|
7545
|
+
}
|
|
7546
|
+
});
|
|
7547
|
+
postToParentRef.current({
|
|
7548
|
+
type: "ow:change",
|
|
7549
|
+
nodes: [{ key: NAV_ORDER_KEY, text: planned.orderJson }]
|
|
7550
|
+
});
|
|
7551
|
+
applySelectionAfterDrop();
|
|
7552
|
+
clearNavDragVisuals();
|
|
7553
|
+
requestAnimationFrame(() => {
|
|
7554
|
+
if (editContentRef.current[NAV_ORDER_KEY] === planned.orderJson) {
|
|
7555
|
+
applyNavForest(planned.forest);
|
|
7556
|
+
}
|
|
7557
|
+
applySelectionAfterDrop();
|
|
7558
|
+
requestAnimationFrame(applySelectionAfterDrop);
|
|
7559
|
+
});
|
|
7560
|
+
return;
|
|
7561
|
+
}
|
|
7562
|
+
applySelectionAfterDrop();
|
|
7563
|
+
clearNavDragVisuals();
|
|
7564
|
+
},
|
|
7565
|
+
[clearNavDragVisuals, deselectRef, editContentRef, postToParentRef, selectRef]
|
|
7566
|
+
);
|
|
7567
|
+
commitNavDragRef.current = commitNavDrag;
|
|
7568
|
+
const startNavLinkDrag = (0, import_react8.useCallback)(
|
|
7569
|
+
(anchor, clientX, clientY, wasSelected) => {
|
|
7570
|
+
if (footerDragRef.current) return false;
|
|
7571
|
+
const hrefKey = anchor.getAttribute("data-ohw-href-key");
|
|
7572
|
+
if (!hrefKey || !isNavbarHrefKey(hrefKey)) return false;
|
|
7573
|
+
if (isNavbarButton3(anchor) || isDragHandleDisabled2(anchor)) return false;
|
|
7574
|
+
beginNavDrag({
|
|
7575
|
+
hrefKey,
|
|
7576
|
+
wasSelected,
|
|
7577
|
+
draggedEl: anchor,
|
|
7578
|
+
lastClientX: clientX,
|
|
7579
|
+
lastClientY: clientY,
|
|
7580
|
+
activeSlot: null
|
|
7581
|
+
});
|
|
7582
|
+
return true;
|
|
7583
|
+
},
|
|
7584
|
+
[beginNavDrag, footerDragRef, isDragHandleDisabled2, isNavbarButton3]
|
|
7585
|
+
);
|
|
7586
|
+
const onNavDragOver = (0, import_react8.useCallback)(
|
|
7587
|
+
(e) => {
|
|
7588
|
+
const session = navDragRef.current;
|
|
7589
|
+
if (!session) return false;
|
|
7590
|
+
e.preventDefault();
|
|
7591
|
+
if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
|
|
7592
|
+
const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey);
|
|
7593
|
+
refreshNavDragVisualsRef.current(session, slot, e.clientX, e.clientY);
|
|
7594
|
+
return true;
|
|
7595
|
+
},
|
|
7596
|
+
[]
|
|
7597
|
+
);
|
|
7598
|
+
(0, import_react8.useEffect)(() => {
|
|
7599
|
+
if (!isEditMode) return;
|
|
7600
|
+
const THRESHOLD = 10;
|
|
7601
|
+
const resolveWasSelected = (el) => {
|
|
7602
|
+
if (selectedElRef.current === el) return true;
|
|
7603
|
+
const activeAnchor = activeElRef.current ? getNavigationItemAnchor2(activeElRef.current) : null;
|
|
7604
|
+
return activeAnchor === el;
|
|
7605
|
+
};
|
|
7606
|
+
const onPointerDown = (e) => {
|
|
7607
|
+
if (e.button !== 0) return;
|
|
7608
|
+
if (navDragRef.current || footerDragRef.current) return;
|
|
7609
|
+
const target = e.target;
|
|
7610
|
+
if (!target) return;
|
|
7611
|
+
if (target.closest(
|
|
7612
|
+
'[data-ohw-drag-handle-container], [data-slot="drag-handle"], [data-ohw-toolbar], [data-ohw-item-toolbar-anchor], [data-ohw-link-popover-root]'
|
|
7613
|
+
)) {
|
|
7614
|
+
return;
|
|
7615
|
+
}
|
|
7616
|
+
if (target.closest("[data-ohw-item-drag-surface]")) return;
|
|
7617
|
+
const anchor = getNavigationItemAnchor2(target);
|
|
7618
|
+
const hrefKey = anchor?.getAttribute("data-ohw-href-key") ?? null;
|
|
7619
|
+
if (!anchor || !isNavbarHrefKey(hrefKey)) return;
|
|
7620
|
+
if (isNavbarButton3(anchor) || isDragHandleDisabled2(anchor)) return;
|
|
7621
|
+
navPointerDragRef.current = {
|
|
7622
|
+
el: anchor,
|
|
7623
|
+
startX: e.clientX,
|
|
7624
|
+
startY: e.clientY,
|
|
7625
|
+
pointerId: e.pointerId,
|
|
7626
|
+
wasSelected: resolveWasSelected(anchor),
|
|
7627
|
+
started: false
|
|
7628
|
+
};
|
|
7629
|
+
};
|
|
7630
|
+
const onPointerMove = (e) => {
|
|
7631
|
+
const pending = navPointerDragRef.current;
|
|
7632
|
+
if (!pending) return;
|
|
7633
|
+
if (pending.started) {
|
|
7634
|
+
e.preventDefault();
|
|
7635
|
+
clearTextSelection();
|
|
7636
|
+
const session = navDragRef.current;
|
|
7637
|
+
if (!session) return;
|
|
7638
|
+
const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey);
|
|
7639
|
+
refreshNavDragVisualsRef.current(session, slot, e.clientX, e.clientY);
|
|
7640
|
+
return;
|
|
7641
|
+
}
|
|
7642
|
+
const dx = e.clientX - pending.startX;
|
|
7643
|
+
const dy = e.clientY - pending.startY;
|
|
7644
|
+
if (dx * dx + dy * dy < THRESHOLD * THRESHOLD) return;
|
|
7645
|
+
e.preventDefault();
|
|
7646
|
+
pending.started = true;
|
|
7647
|
+
armItemPressDrag();
|
|
7648
|
+
clearTextSelection();
|
|
7649
|
+
try {
|
|
7650
|
+
document.body.setPointerCapture(pending.pointerId);
|
|
7651
|
+
} catch {
|
|
7652
|
+
}
|
|
7653
|
+
if (linkPopoverOpenRef.current) setLinkPopover(null);
|
|
7654
|
+
if (activeElRef.current) deactivateRef.current();
|
|
7655
|
+
const key = pending.el.getAttribute("data-ohw-href-key");
|
|
7656
|
+
if (!key) return;
|
|
7657
|
+
beginNavDragRef.current({
|
|
7658
|
+
hrefKey: key,
|
|
7659
|
+
wasSelected: pending.wasSelected,
|
|
7660
|
+
draggedEl: pending.el,
|
|
7661
|
+
lastClientX: e.clientX,
|
|
7662
|
+
lastClientY: e.clientY,
|
|
7663
|
+
activeSlot: null
|
|
7664
|
+
});
|
|
7665
|
+
};
|
|
7666
|
+
const endPointerDrag = (e) => {
|
|
7667
|
+
const pending = navPointerDragRef.current;
|
|
7668
|
+
navPointerDragRef.current = null;
|
|
7669
|
+
try {
|
|
7670
|
+
if (document.body.hasPointerCapture(e.pointerId)) {
|
|
7671
|
+
document.body.releasePointerCapture(e.pointerId);
|
|
7672
|
+
}
|
|
7673
|
+
} catch {
|
|
7674
|
+
}
|
|
7675
|
+
if (!pending) return;
|
|
7676
|
+
if (!pending.started) {
|
|
7677
|
+
unlockItemDragInteraction();
|
|
7678
|
+
return;
|
|
7679
|
+
}
|
|
7680
|
+
suppressNextClickRef.current = true;
|
|
7681
|
+
suppressClickUntilRef.current = Date.now() + 500;
|
|
7682
|
+
commitNavDragRef.current(e.clientX, e.clientY);
|
|
7683
|
+
};
|
|
7684
|
+
const blockSelectStart = (e) => {
|
|
7685
|
+
if (navDragRef.current || navPointerDragRef.current?.started || document.documentElement.hasAttribute("data-ohw-footer-press-drag")) {
|
|
7686
|
+
e.preventDefault();
|
|
7687
|
+
}
|
|
7688
|
+
};
|
|
7689
|
+
const onDragEnd = () => {
|
|
7690
|
+
if (!navDragRef.current) return;
|
|
7691
|
+
suppressNextClickRef.current = true;
|
|
7692
|
+
suppressClickUntilRef.current = Date.now() + 500;
|
|
7693
|
+
commitNavDragRef.current();
|
|
7694
|
+
};
|
|
7695
|
+
document.addEventListener("pointerdown", onPointerDown, true);
|
|
7696
|
+
document.addEventListener("pointermove", onPointerMove, true);
|
|
7697
|
+
document.addEventListener("pointerup", endPointerDrag, true);
|
|
7698
|
+
document.addEventListener("pointercancel", endPointerDrag, true);
|
|
7699
|
+
document.addEventListener("selectstart", blockSelectStart, true);
|
|
7700
|
+
document.addEventListener("dragend", onDragEnd, true);
|
|
7701
|
+
return () => {
|
|
7702
|
+
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
7703
|
+
document.removeEventListener("pointermove", onPointerMove, true);
|
|
7704
|
+
document.removeEventListener("pointerup", endPointerDrag, true);
|
|
7705
|
+
document.removeEventListener("pointercancel", endPointerDrag, true);
|
|
7706
|
+
document.removeEventListener("selectstart", blockSelectStart, true);
|
|
7707
|
+
document.removeEventListener("dragend", onDragEnd, true);
|
|
7708
|
+
unlockItemDragInteraction();
|
|
7709
|
+
};
|
|
7710
|
+
}, [
|
|
7711
|
+
activeElRef,
|
|
7712
|
+
deactivateRef,
|
|
7713
|
+
footerDragRef,
|
|
7714
|
+
getNavigationItemAnchor2,
|
|
7715
|
+
isDragHandleDisabled2,
|
|
7716
|
+
isEditMode,
|
|
7717
|
+
isNavbarButton3,
|
|
7718
|
+
linkPopoverOpenRef,
|
|
7719
|
+
selectedElRef,
|
|
7720
|
+
setLinkPopover,
|
|
7721
|
+
suppressNextClickRef
|
|
7722
|
+
]);
|
|
7723
|
+
const armNavPressFromChrome = (0, import_react8.useCallback)(
|
|
7724
|
+
(selected, clientX, clientY, pointerId) => {
|
|
7725
|
+
const hrefKey = selected.getAttribute("data-ohw-href-key");
|
|
7726
|
+
if (!hrefKey || !isNavbarHrefKey(hrefKey)) return false;
|
|
7727
|
+
if (isNavbarButton3(selected) || isDragHandleDisabled2(selected)) return false;
|
|
7728
|
+
navPointerDragRef.current = {
|
|
7729
|
+
el: selected,
|
|
7730
|
+
startX: clientX,
|
|
7731
|
+
startY: clientY,
|
|
7732
|
+
pointerId,
|
|
7733
|
+
wasSelected: true,
|
|
7734
|
+
started: false
|
|
7735
|
+
};
|
|
7736
|
+
return true;
|
|
7737
|
+
},
|
|
7738
|
+
[isDragHandleDisabled2, isNavbarButton3]
|
|
7739
|
+
);
|
|
7740
|
+
return {
|
|
7741
|
+
navDragRef,
|
|
7742
|
+
navDropSlots,
|
|
7743
|
+
activeNavDropIndex,
|
|
7744
|
+
startNavLinkDrag,
|
|
7745
|
+
commitNavDrag,
|
|
7746
|
+
onNavDragOver,
|
|
7747
|
+
armNavPressFromChrome,
|
|
7748
|
+
clearNavDragVisuals,
|
|
7749
|
+
refreshNavDragVisualsRef
|
|
7750
|
+
};
|
|
7751
|
+
}
|
|
7752
|
+
|
|
7753
|
+
// src/ui/navbar-container-chrome.tsx
|
|
7754
|
+
var import_lucide_react10 = require("lucide-react");
|
|
7755
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
7756
|
+
function NavbarContainerChrome({
|
|
7757
|
+
rect,
|
|
7758
|
+
onAdd
|
|
7759
|
+
}) {
|
|
7760
|
+
const chromeGap = 6;
|
|
7761
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
7762
|
+
"div",
|
|
7763
|
+
{
|
|
7764
|
+
"data-ohw-navbar-container-chrome": "",
|
|
7765
|
+
"data-ohw-bridge": "",
|
|
7766
|
+
className: "pointer-events-none fixed z-[2147483647]",
|
|
7767
|
+
style: {
|
|
7768
|
+
top: rect.top - chromeGap,
|
|
7769
|
+
left: rect.left - chromeGap,
|
|
7770
|
+
width: rect.width + chromeGap * 2,
|
|
7771
|
+
height: rect.height + chromeGap * 2
|
|
7772
|
+
},
|
|
7773
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
7774
|
+
"button",
|
|
7775
|
+
{
|
|
7776
|
+
type: "button",
|
|
7777
|
+
"data-ohw-navbar-add-button": "",
|
|
7778
|
+
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",
|
|
7779
|
+
style: { top: "70%" },
|
|
7780
|
+
"aria-label": "Add item",
|
|
7781
|
+
onMouseDown: (e) => {
|
|
7782
|
+
e.preventDefault();
|
|
7783
|
+
e.stopPropagation();
|
|
7784
|
+
},
|
|
7785
|
+
onClick: (e) => {
|
|
7786
|
+
e.preventDefault();
|
|
7787
|
+
e.stopPropagation();
|
|
7788
|
+
onAdd();
|
|
7789
|
+
},
|
|
7790
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react10.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
|
|
7791
|
+
}
|
|
7792
|
+
)
|
|
7793
|
+
}
|
|
7794
|
+
);
|
|
7795
|
+
}
|
|
7796
|
+
|
|
7797
|
+
// src/ui/drop-indicator.tsx
|
|
7798
|
+
var React10 = __toESM(require("react"), 1);
|
|
7799
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
7800
|
+
var dropIndicatorVariants = cva(
|
|
7801
|
+
"ov-gap-line pointer-events-none shrink-0 transition-opacity duration-150",
|
|
7802
|
+
{
|
|
7803
|
+
variants: {
|
|
7804
|
+
direction: {
|
|
7805
|
+
vertical: "h-6 w-[3px]",
|
|
7806
|
+
horizontal: "h-[3px] w-[200px]"
|
|
7807
|
+
},
|
|
7808
|
+
state: {
|
|
7809
|
+
default: "opacity-0",
|
|
7810
|
+
hover: "opacity-100",
|
|
7811
|
+
dragIdle: "opacity-40",
|
|
7812
|
+
dragActive: "opacity-100"
|
|
7813
|
+
}
|
|
7814
|
+
},
|
|
7815
|
+
defaultVariants: {
|
|
7816
|
+
direction: "vertical",
|
|
7817
|
+
state: "default"
|
|
7818
|
+
}
|
|
7819
|
+
}
|
|
7820
|
+
);
|
|
7821
|
+
var DropIndicator = React10.forwardRef(
|
|
7822
|
+
({ className, direction, state, ...props }, ref) => {
|
|
7823
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
7824
|
+
"div",
|
|
7825
|
+
{
|
|
7826
|
+
ref,
|
|
7827
|
+
"data-slot": "drop-indicator",
|
|
7828
|
+
"data-direction": direction ?? "vertical",
|
|
7829
|
+
"data-state": state ?? "default",
|
|
7830
|
+
"aria-hidden": "true",
|
|
7831
|
+
className: cn(dropIndicatorVariants({ direction, state }), className),
|
|
7832
|
+
...props
|
|
7833
|
+
}
|
|
7834
|
+
);
|
|
7835
|
+
}
|
|
7836
|
+
);
|
|
7837
|
+
DropIndicator.displayName = "DropIndicator";
|
|
7838
|
+
|
|
7839
|
+
// src/ui/badge.tsx
|
|
7840
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
7841
|
+
var badgeVariants = cva(
|
|
7842
|
+
"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",
|
|
7843
|
+
{
|
|
7844
|
+
variants: {
|
|
7845
|
+
variant: {
|
|
7846
|
+
default: "border-transparent bg-primary text-primary-foreground",
|
|
7847
|
+
secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
7848
|
+
destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
|
7849
|
+
outline: "text-foreground"
|
|
7850
|
+
}
|
|
7851
|
+
},
|
|
7852
|
+
defaultVariants: {
|
|
7853
|
+
variant: "default"
|
|
7854
|
+
}
|
|
7855
|
+
}
|
|
7856
|
+
);
|
|
7857
|
+
function Badge({ className, variant, ...props }) {
|
|
7858
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: cn(badgeVariants({ variant }), className), ...props });
|
|
7859
|
+
}
|
|
7860
|
+
|
|
7861
|
+
// src/OhhwellsBridge.tsx
|
|
7862
|
+
var import_lucide_react11 = require("lucide-react");
|
|
7863
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
7864
|
+
var PRIMARY2 = "#0885FE";
|
|
7865
|
+
var IMAGE_FADE_MS = 300;
|
|
7866
|
+
function runOpacityFade(el, onDone) {
|
|
7867
|
+
const anim = el.animate([{ opacity: 0 }, { opacity: 1 }], {
|
|
7868
|
+
duration: IMAGE_FADE_MS,
|
|
7869
|
+
easing: "ease",
|
|
7870
|
+
fill: "forwards"
|
|
7871
|
+
});
|
|
7872
|
+
let finished = false;
|
|
7873
|
+
const finish = () => {
|
|
7874
|
+
if (finished) return;
|
|
7875
|
+
finished = true;
|
|
7876
|
+
anim.cancel();
|
|
7877
|
+
el.style.opacity = "";
|
|
7878
|
+
onDone();
|
|
7879
|
+
};
|
|
7880
|
+
anim.finished.then(finish).catch(finish);
|
|
7881
|
+
window.setTimeout(finish, IMAGE_FADE_MS + 100);
|
|
7882
|
+
}
|
|
7883
|
+
function fadeInImageElement(img, onReady) {
|
|
7884
|
+
onReady();
|
|
7885
|
+
img.style.opacity = "0";
|
|
7886
|
+
runOpacityFade(img, () => {
|
|
7887
|
+
img.style.opacity = "";
|
|
7888
|
+
});
|
|
7889
|
+
}
|
|
7890
|
+
function applyEditableImageSrc(img, url) {
|
|
7891
|
+
img.removeAttribute("srcset");
|
|
7892
|
+
img.removeAttribute("sizes");
|
|
7893
|
+
img.src = url;
|
|
7894
|
+
}
|
|
7895
|
+
function fadeInBgImage(el, url, onReady) {
|
|
7896
|
+
const prevPos = el.style.position;
|
|
7897
|
+
if (!prevPos || prevPos === "static") el.style.position = "relative";
|
|
7898
|
+
const layer = document.createElement("div");
|
|
7899
|
+
layer.setAttribute("data-ohw-bg-fade-layer", "");
|
|
6610
7900
|
Object.assign(layer.style, {
|
|
6611
7901
|
position: "absolute",
|
|
6612
7902
|
inset: "0",
|
|
@@ -6749,7 +8039,7 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
6749
8039
|
const root = (0, import_client.createRoot)(container);
|
|
6750
8040
|
(0, import_react_dom2.flushSync)(() => {
|
|
6751
8041
|
root.render(
|
|
6752
|
-
/* @__PURE__ */ (0,
|
|
8042
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
6753
8043
|
SchedulingWidget,
|
|
6754
8044
|
{
|
|
6755
8045
|
notifyOnConnect,
|
|
@@ -6811,7 +8101,20 @@ function isDragHandleDisabled(el) {
|
|
|
6811
8101
|
return raw === "true" || raw === "";
|
|
6812
8102
|
});
|
|
6813
8103
|
}
|
|
6814
|
-
function
|
|
8104
|
+
function canDragNavigationItem(anchor) {
|
|
8105
|
+
const { key, disabled } = getNavigationItemReorderState(anchor);
|
|
8106
|
+
return Boolean(key) && !disabled;
|
|
8107
|
+
}
|
|
8108
|
+
function syncNavigationDragCursorAttrs() {
|
|
8109
|
+
document.querySelectorAll("nav [data-ohw-href-key], footer [data-ohw-href-key]").forEach((el) => {
|
|
8110
|
+
if (!isNavigationItem(el) || !canDragNavigationItem(el)) {
|
|
8111
|
+
el.removeAttribute("data-ohw-can-drag");
|
|
8112
|
+
return;
|
|
8113
|
+
}
|
|
8114
|
+
el.setAttribute("data-ohw-can-drag", "");
|
|
8115
|
+
});
|
|
8116
|
+
}
|
|
8117
|
+
function collectEditableNodes(extraContent) {
|
|
6815
8118
|
const nodes = Array.from(document.querySelectorAll("[data-ohw-editable]")).map((el) => {
|
|
6816
8119
|
if (el.dataset.ohwEditable === "image") {
|
|
6817
8120
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
@@ -6839,6 +8142,14 @@ function collectEditableNodes() {
|
|
|
6839
8142
|
if (!key) return;
|
|
6840
8143
|
nodes.push({ key, type: "link", text: getLinkHref2(el) });
|
|
6841
8144
|
});
|
|
8145
|
+
if (extraContent) {
|
|
8146
|
+
for (const key of [NAV_ORDER_KEY, FOOTER_ORDER_KEY, NAV_COUNT_KEY]) {
|
|
8147
|
+
const text = extraContent[key];
|
|
8148
|
+
if (typeof text === "string" && text.length > 0) {
|
|
8149
|
+
nodes.push({ key, type: "meta", text });
|
|
8150
|
+
}
|
|
8151
|
+
}
|
|
8152
|
+
}
|
|
6842
8153
|
document.querySelectorAll('[data-ohw-editable="video"]').forEach((el) => {
|
|
6843
8154
|
const key = el.dataset.ohwKey ?? "";
|
|
6844
8155
|
const video = getVideoEl(el);
|
|
@@ -6952,6 +8263,11 @@ function getNavigationItemAnchor(el) {
|
|
|
6952
8263
|
function isNavigationItem(el) {
|
|
6953
8264
|
return getNavigationItemAnchor(el) !== null;
|
|
6954
8265
|
}
|
|
8266
|
+
function listNavigationItems() {
|
|
8267
|
+
return Array.from(
|
|
8268
|
+
document.querySelectorAll("nav [data-ohw-href-key], footer [data-ohw-href-key]")
|
|
8269
|
+
).filter((el) => isNavigationItem(el));
|
|
8270
|
+
}
|
|
6955
8271
|
function getNavigationItemReorderState(anchor) {
|
|
6956
8272
|
if (isNavbarButton2(anchor)) return { key: null, disabled: false };
|
|
6957
8273
|
return getReorderHandleStateFromAnchor(anchor);
|
|
@@ -6980,18 +8296,20 @@ function getNavigationRoot(el) {
|
|
|
6980
8296
|
if (explicit) return explicit;
|
|
6981
8297
|
return el.closest("nav, footer, aside");
|
|
6982
8298
|
}
|
|
8299
|
+
function countFooterNavItems(el) {
|
|
8300
|
+
return Array.from(el.querySelectorAll("[data-ohw-href-key]")).filter(isNavigationItem).length;
|
|
8301
|
+
}
|
|
6983
8302
|
function findFooterItemGroup(item) {
|
|
8303
|
+
const explicit = item.closest("[data-ohw-footer-col], [data-ohw-footer-column]");
|
|
8304
|
+
if (explicit) return explicit;
|
|
6984
8305
|
const footer = item.closest("footer");
|
|
6985
8306
|
if (!footer) return null;
|
|
6986
8307
|
let node = item.parentElement;
|
|
6987
8308
|
while (node && node !== footer) {
|
|
6988
|
-
|
|
6989
|
-
node.querySelectorAll(":scope > [data-ohw-href-key]")
|
|
6990
|
-
).some(isNavigationItem);
|
|
6991
|
-
if (hasDirectNavItems) return node;
|
|
8309
|
+
if (countFooterNavItems(node) >= 2) return node;
|
|
6992
8310
|
node = node.parentElement;
|
|
6993
8311
|
}
|
|
6994
|
-
return
|
|
8312
|
+
return footer;
|
|
6995
8313
|
}
|
|
6996
8314
|
function isNavigationRoot(el) {
|
|
6997
8315
|
return el.hasAttribute("data-ohw-nav-root") || el.matches("nav, footer, aside");
|
|
@@ -6999,16 +8317,49 @@ function isNavigationRoot(el) {
|
|
|
6999
8317
|
function isInferredFooterGroup(el) {
|
|
7000
8318
|
const footer = el.closest("footer");
|
|
7001
8319
|
if (!footer || el === footer) return false;
|
|
7002
|
-
|
|
8320
|
+
if (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column")) return true;
|
|
8321
|
+
return countFooterNavItems(el) >= 2;
|
|
7003
8322
|
}
|
|
7004
8323
|
function isNavigationContainer(el) {
|
|
7005
|
-
return el.hasAttribute("data-ohw-nav-container") || isNavigationRoot(el) || isInferredFooterGroup(el);
|
|
8324
|
+
return el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isNavigationRoot(el) || isInferredFooterGroup(el);
|
|
8325
|
+
}
|
|
8326
|
+
function isNavbarLinksContainer(el) {
|
|
8327
|
+
return el.hasAttribute("data-ohw-nav-container");
|
|
8328
|
+
}
|
|
8329
|
+
function getFooterColumn(el) {
|
|
8330
|
+
return el.closest("[data-ohw-footer-col], [data-ohw-footer-column]");
|
|
8331
|
+
}
|
|
8332
|
+
function resolveFooterColumnSelectionTarget(target, clientX, clientY) {
|
|
8333
|
+
if (getNavigationItemAnchor(target)) return null;
|
|
8334
|
+
const column = getFooterColumn(target);
|
|
8335
|
+
if (!column) return null;
|
|
8336
|
+
if (isPointOverNavItem(column, clientX, clientY)) return null;
|
|
8337
|
+
return column;
|
|
7006
8338
|
}
|
|
7007
8339
|
function isPointOverNavigation(x, y) {
|
|
8340
|
+
const roots = /* @__PURE__ */ new Set();
|
|
7008
8341
|
const navRoot = document.querySelector("[data-ohw-nav-root]") ?? document.querySelector("nav");
|
|
7009
|
-
if (
|
|
7010
|
-
const
|
|
7011
|
-
|
|
8342
|
+
if (navRoot) roots.add(navRoot);
|
|
8343
|
+
const footer = document.querySelector("footer");
|
|
8344
|
+
if (footer) roots.add(footer);
|
|
8345
|
+
for (const root of roots) {
|
|
8346
|
+
const r2 = root.getBoundingClientRect();
|
|
8347
|
+
if (x >= r2.left && x <= r2.right && y >= r2.top && y <= r2.bottom) return true;
|
|
8348
|
+
}
|
|
8349
|
+
return false;
|
|
8350
|
+
}
|
|
8351
|
+
function findHoveredNavOrFooterContainer(x, y) {
|
|
8352
|
+
const candidates = [
|
|
8353
|
+
...document.querySelectorAll("[data-ohw-nav-container]"),
|
|
8354
|
+
...listFooterColumns()
|
|
8355
|
+
];
|
|
8356
|
+
for (const container of candidates) {
|
|
8357
|
+
const r2 = container.getBoundingClientRect();
|
|
8358
|
+
if (x < r2.left || x > r2.right || y < r2.top || y > r2.bottom) continue;
|
|
8359
|
+
if (isPointOverNavItem(container, x, y)) continue;
|
|
8360
|
+
return container;
|
|
8361
|
+
}
|
|
8362
|
+
return null;
|
|
7012
8363
|
}
|
|
7013
8364
|
function isPointOverNavItem(container, x, y) {
|
|
7014
8365
|
return Array.from(container.querySelectorAll("[data-ohw-href-key]")).some((el) => {
|
|
@@ -7041,38 +8392,81 @@ function getNavigationSelectionParent(el) {
|
|
|
7041
8392
|
if (isNavigationItem(el)) {
|
|
7042
8393
|
const explicit = el.closest("[data-ohw-nav-container]");
|
|
7043
8394
|
if (explicit) return explicit;
|
|
8395
|
+
const footerColumn = getFooterColumn(el);
|
|
8396
|
+
if (footerColumn) return footerColumn;
|
|
7044
8397
|
const footerGroup = findFooterItemGroup(el);
|
|
7045
8398
|
if (footerGroup) return footerGroup;
|
|
7046
8399
|
return getNavigationRoot(el);
|
|
7047
8400
|
}
|
|
7048
|
-
if (el.hasAttribute("data-ohw-nav-container") || isInferredFooterGroup(el)) {
|
|
8401
|
+
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup(el)) {
|
|
7049
8402
|
return getNavigationRoot(el);
|
|
7050
8403
|
}
|
|
7051
8404
|
return null;
|
|
7052
8405
|
}
|
|
8406
|
+
function collectNavigationItemSiblingHintRects(selected) {
|
|
8407
|
+
if (!isNavigationItem(selected)) return [];
|
|
8408
|
+
const footerColumn = getFooterColumn(selected);
|
|
8409
|
+
if (footerColumn) {
|
|
8410
|
+
return listFooterLinksInColumn(footerColumn).filter((link) => link !== selected).map((link) => link.getBoundingClientRect());
|
|
8411
|
+
}
|
|
8412
|
+
const navContainer = selected.closest("[data-ohw-nav-container], [data-ohw-nav-drawer]");
|
|
8413
|
+
if (navContainer) {
|
|
8414
|
+
return Array.from(navContainer.querySelectorAll("[data-ohw-href-key]")).filter((el) => isNavigationItem(el) && el !== selected).map((el) => el.getBoundingClientRect());
|
|
8415
|
+
}
|
|
8416
|
+
return listNavigationItems().filter((el) => el !== selected).map((el) => el.getBoundingClientRect());
|
|
8417
|
+
}
|
|
7053
8418
|
function placeCaretAtPoint(el, x, y) {
|
|
7054
8419
|
const selection = window.getSelection();
|
|
7055
8420
|
if (!selection) return;
|
|
7056
|
-
|
|
7057
|
-
|
|
7058
|
-
|
|
7059
|
-
|
|
7060
|
-
|
|
7061
|
-
|
|
8421
|
+
const overlays = Array.from(
|
|
8422
|
+
document.querySelectorAll(
|
|
8423
|
+
"[data-ohw-item-drag-surface], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-ohw-item-toolbar-anchor]"
|
|
8424
|
+
)
|
|
8425
|
+
);
|
|
8426
|
+
const prevPointerEvents = overlays.map((node) => node.style.pointerEvents);
|
|
8427
|
+
for (const node of overlays) node.style.pointerEvents = "none";
|
|
8428
|
+
try {
|
|
8429
|
+
if (typeof document.caretRangeFromPoint === "function") {
|
|
8430
|
+
const range = document.caretRangeFromPoint(x, y);
|
|
8431
|
+
if (range && el.contains(range.startContainer)) {
|
|
8432
|
+
selection.removeAllRanges();
|
|
8433
|
+
selection.addRange(range);
|
|
8434
|
+
return;
|
|
8435
|
+
}
|
|
7062
8436
|
}
|
|
7063
|
-
|
|
7064
|
-
|
|
7065
|
-
|
|
7066
|
-
|
|
7067
|
-
|
|
7068
|
-
|
|
7069
|
-
|
|
7070
|
-
|
|
7071
|
-
|
|
7072
|
-
|
|
8437
|
+
const caretPositionFromPoint = document.caretPositionFromPoint;
|
|
8438
|
+
if (typeof caretPositionFromPoint === "function") {
|
|
8439
|
+
const position = caretPositionFromPoint(x, y);
|
|
8440
|
+
if (position && el.contains(position.offsetNode)) {
|
|
8441
|
+
const range = document.createRange();
|
|
8442
|
+
range.setStart(position.offsetNode, position.offset);
|
|
8443
|
+
range.collapse(true);
|
|
8444
|
+
selection.removeAllRanges();
|
|
8445
|
+
selection.addRange(range);
|
|
8446
|
+
}
|
|
7073
8447
|
}
|
|
8448
|
+
} finally {
|
|
8449
|
+
overlays.forEach((node, i) => {
|
|
8450
|
+
node.style.pointerEvents = prevPointerEvents[i] ?? "";
|
|
8451
|
+
});
|
|
7074
8452
|
}
|
|
7075
8453
|
}
|
|
8454
|
+
function selectAllTextInEditable(el) {
|
|
8455
|
+
const selection = window.getSelection();
|
|
8456
|
+
if (!selection) return;
|
|
8457
|
+
const range = document.createRange();
|
|
8458
|
+
range.selectNodeContents(el);
|
|
8459
|
+
selection.removeAllRanges();
|
|
8460
|
+
selection.addRange(range);
|
|
8461
|
+
}
|
|
8462
|
+
function getNavigationLabelEditable(target) {
|
|
8463
|
+
const editable = target.closest('[data-ohw-editable="text"]');
|
|
8464
|
+
if (!editable) return null;
|
|
8465
|
+
const hrefCtx = getHrefKeyFromElement(editable);
|
|
8466
|
+
const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
|
|
8467
|
+
if (!navAnchor) return null;
|
|
8468
|
+
return { editable, navAnchor };
|
|
8469
|
+
}
|
|
7076
8470
|
function collectSections() {
|
|
7077
8471
|
return collectSectionsFromDom();
|
|
7078
8472
|
}
|
|
@@ -7196,6 +8590,9 @@ var ICONS = {
|
|
|
7196
8590
|
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"/>',
|
|
7197
8591
|
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"/>'
|
|
7198
8592
|
};
|
|
8593
|
+
var SELECTION_CHROME_GAP2 = 4;
|
|
8594
|
+
var TOOLBAR_STROKE_GAP2 = 4;
|
|
8595
|
+
var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
|
|
7199
8596
|
var TOOLBAR_GROUPS = [
|
|
7200
8597
|
[
|
|
7201
8598
|
{ cmd: "bold", title: "Bold" },
|
|
@@ -7217,10 +8614,11 @@ function EditGlowChrome({
|
|
|
7217
8614
|
rect,
|
|
7218
8615
|
elRef,
|
|
7219
8616
|
reorderHrefKey,
|
|
7220
|
-
dragDisabled = false
|
|
8617
|
+
dragDisabled = false,
|
|
8618
|
+
hideHandle = false
|
|
7221
8619
|
}) {
|
|
7222
|
-
const GAP =
|
|
7223
|
-
return /* @__PURE__ */ (0,
|
|
8620
|
+
const GAP = SELECTION_CHROME_GAP2;
|
|
8621
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
7224
8622
|
"div",
|
|
7225
8623
|
{
|
|
7226
8624
|
ref: elRef,
|
|
@@ -7235,7 +8633,7 @@ function EditGlowChrome({
|
|
|
7235
8633
|
zIndex: 2147483646
|
|
7236
8634
|
},
|
|
7237
8635
|
children: [
|
|
7238
|
-
/* @__PURE__ */ (0,
|
|
8636
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
7239
8637
|
"div",
|
|
7240
8638
|
{
|
|
7241
8639
|
style: {
|
|
@@ -7243,12 +8641,12 @@ function EditGlowChrome({
|
|
|
7243
8641
|
inset: 0,
|
|
7244
8642
|
border: "2px solid var(--ohw-primary, #0885FE)",
|
|
7245
8643
|
borderRadius: 8,
|
|
7246
|
-
boxShadow: "0 0 0 4px
|
|
8644
|
+
boxShadow: "0 0 0 4px color-mix(in srgb, var(--ohw-primary, #0885FE) 12%, transparent)",
|
|
7247
8645
|
pointerEvents: "none"
|
|
7248
8646
|
}
|
|
7249
8647
|
}
|
|
7250
8648
|
),
|
|
7251
|
-
reorderHrefKey && /* @__PURE__ */ (0,
|
|
8649
|
+
reorderHrefKey && !hideHandle && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
7252
8650
|
"div",
|
|
7253
8651
|
{
|
|
7254
8652
|
"data-ohw-drag-handle-container": "",
|
|
@@ -7260,7 +8658,7 @@ function EditGlowChrome({
|
|
|
7260
8658
|
transform: "translate(calc(-100% - 7px), -50%)",
|
|
7261
8659
|
pointerEvents: dragDisabled ? "none" : "auto"
|
|
7262
8660
|
},
|
|
7263
|
-
children: /* @__PURE__ */ (0,
|
|
8661
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
7264
8662
|
DragHandle,
|
|
7265
8663
|
{
|
|
7266
8664
|
"aria-label": `Reorder ${reorderHrefKey}`,
|
|
@@ -7291,6 +8689,7 @@ function applyVisibleViewport(el, parentScroll) {
|
|
|
7291
8689
|
el.style.top = `${top}px`;
|
|
7292
8690
|
el.style.height = `${height}px`;
|
|
7293
8691
|
}
|
|
8692
|
+
var TOOLBAR_EDGE_MARGIN2 = 4;
|
|
7294
8693
|
function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
|
|
7295
8694
|
const isAbove = transform.includes("translateY(-100%)");
|
|
7296
8695
|
let visualTop = isAbove ? top - approxH : top;
|
|
@@ -7314,10 +8713,16 @@ function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
|
|
|
7314
8713
|
const pinnedTop = Math.min(maxBottom - approxH, Math.max(minTop, clip.top + gap));
|
|
7315
8714
|
return { top: pinnedTop + approxH, transform: "translateX(-50%) translateY(-100%)" };
|
|
7316
8715
|
}
|
|
7317
|
-
function
|
|
7318
|
-
const
|
|
8716
|
+
function clampToolbarLeft(centerX, toolbarWidth) {
|
|
8717
|
+
const half = toolbarWidth / 2;
|
|
8718
|
+
return Math.max(
|
|
8719
|
+
TOOLBAR_EDGE_MARGIN2 + half,
|
|
8720
|
+
Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN2 - half)
|
|
8721
|
+
);
|
|
8722
|
+
}
|
|
8723
|
+
function calcToolbarPos(rect, parentScroll, toolbarW = 306) {
|
|
8724
|
+
const GAP = TOOLBAR_OFFSET_FROM_ELEMENT;
|
|
7319
8725
|
const APPROX_H = 32;
|
|
7320
|
-
const APPROX_W = approxW;
|
|
7321
8726
|
const clip = getIframeVisibleClip(parentScroll);
|
|
7322
8727
|
const clipTop = clip?.top ?? 0;
|
|
7323
8728
|
const canvasTopInIframe = parentScroll != null ? parentScroll.headerH - parentScroll.iframeOffsetTop : 0;
|
|
@@ -7347,7 +8752,7 @@ function calcToolbarPos(rect, parentScroll, approxW = 306) {
|
|
|
7347
8752
|
transform = clamped.transform;
|
|
7348
8753
|
}
|
|
7349
8754
|
const rawLeft = rect.left + rect.width / 2;
|
|
7350
|
-
const left =
|
|
8755
|
+
const left = clampToolbarLeft(rawLeft, toolbarW);
|
|
7351
8756
|
return { top, left, transform };
|
|
7352
8757
|
}
|
|
7353
8758
|
function resolveItemInteractionState(rect, parentScroll) {
|
|
@@ -7363,11 +8768,37 @@ function FloatingToolbar({
|
|
|
7363
8768
|
showEditLink,
|
|
7364
8769
|
onEditLink
|
|
7365
8770
|
}) {
|
|
7366
|
-
const
|
|
7367
|
-
|
|
8771
|
+
const localRef = import_react9.default.useRef(null);
|
|
8772
|
+
const [measuredW, setMeasuredW] = import_react9.default.useState(330);
|
|
8773
|
+
const setRefs = import_react9.default.useCallback(
|
|
8774
|
+
(node) => {
|
|
8775
|
+
localRef.current = node;
|
|
8776
|
+
if (typeof elRef === "function") elRef(node);
|
|
8777
|
+
else if (elRef) elRef.current = node;
|
|
8778
|
+
if (node) {
|
|
8779
|
+
const w = node.offsetWidth;
|
|
8780
|
+
if (w > 0) setMeasuredW(w);
|
|
8781
|
+
}
|
|
8782
|
+
},
|
|
8783
|
+
[elRef]
|
|
8784
|
+
);
|
|
8785
|
+
import_react9.default.useLayoutEffect(() => {
|
|
8786
|
+
const node = localRef.current;
|
|
8787
|
+
if (!node) return;
|
|
8788
|
+
const update = () => {
|
|
8789
|
+
const w = node.offsetWidth;
|
|
8790
|
+
if (w > 0) setMeasuredW(w);
|
|
8791
|
+
};
|
|
8792
|
+
update();
|
|
8793
|
+
const ro = new ResizeObserver(update);
|
|
8794
|
+
ro.observe(node);
|
|
8795
|
+
return () => ro.disconnect();
|
|
8796
|
+
}, [showEditLink, activeCommands]);
|
|
8797
|
+
const { top, left, transform } = calcToolbarPos(rect, parentScroll, measuredW);
|
|
8798
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
7368
8799
|
"div",
|
|
7369
8800
|
{
|
|
7370
|
-
ref:
|
|
8801
|
+
ref: setRefs,
|
|
7371
8802
|
style: {
|
|
7372
8803
|
position: "fixed",
|
|
7373
8804
|
top,
|
|
@@ -7376,12 +8807,12 @@ function FloatingToolbar({
|
|
|
7376
8807
|
zIndex: 2147483647,
|
|
7377
8808
|
pointerEvents: "auto"
|
|
7378
8809
|
},
|
|
7379
|
-
children: /* @__PURE__ */ (0,
|
|
7380
|
-
TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0,
|
|
7381
|
-
gi > 0 && /* @__PURE__ */ (0,
|
|
8810
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(CustomToolbar, { children: [
|
|
8811
|
+
TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react9.default.Fragment, { children: [
|
|
8812
|
+
gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(CustomToolbarDivider, {}),
|
|
7382
8813
|
btns.map((btn) => {
|
|
7383
8814
|
const isActive = activeCommands.has(btn.cmd);
|
|
7384
|
-
return /* @__PURE__ */ (0,
|
|
8815
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
7385
8816
|
CustomToolbarButton,
|
|
7386
8817
|
{
|
|
7387
8818
|
title: btn.title,
|
|
@@ -7390,7 +8821,7 @@ function FloatingToolbar({
|
|
|
7390
8821
|
e.preventDefault();
|
|
7391
8822
|
onCommand(btn.cmd);
|
|
7392
8823
|
},
|
|
7393
|
-
children: /* @__PURE__ */ (0,
|
|
8824
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
7394
8825
|
"svg",
|
|
7395
8826
|
{
|
|
7396
8827
|
width: "16",
|
|
@@ -7411,7 +8842,7 @@ function FloatingToolbar({
|
|
|
7411
8842
|
);
|
|
7412
8843
|
})
|
|
7413
8844
|
] }, gi)),
|
|
7414
|
-
showEditLink ? /* @__PURE__ */ (0,
|
|
8845
|
+
showEditLink ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
7415
8846
|
CustomToolbarButton,
|
|
7416
8847
|
{
|
|
7417
8848
|
type: "button",
|
|
@@ -7425,7 +8856,7 @@ function FloatingToolbar({
|
|
|
7425
8856
|
e.preventDefault();
|
|
7426
8857
|
e.stopPropagation();
|
|
7427
8858
|
},
|
|
7428
|
-
children: /* @__PURE__ */ (0,
|
|
8859
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react11.Link, { className: "size-4 shrink-0", "aria-hidden": true })
|
|
7429
8860
|
}
|
|
7430
8861
|
) : null
|
|
7431
8862
|
] })
|
|
@@ -7442,7 +8873,7 @@ function StateToggle({
|
|
|
7442
8873
|
states,
|
|
7443
8874
|
onStateChange
|
|
7444
8875
|
}) {
|
|
7445
|
-
return /* @__PURE__ */ (0,
|
|
8876
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
7446
8877
|
ToggleGroup,
|
|
7447
8878
|
{
|
|
7448
8879
|
"data-ohw-state-toggle": "",
|
|
@@ -7456,7 +8887,7 @@ function StateToggle({
|
|
|
7456
8887
|
left: rect.right - 8,
|
|
7457
8888
|
transform: "translateX(-100%)"
|
|
7458
8889
|
},
|
|
7459
|
-
children: states.map((state) => /* @__PURE__ */ (0,
|
|
8890
|
+
children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
|
|
7460
8891
|
}
|
|
7461
8892
|
);
|
|
7462
8893
|
}
|
|
@@ -7483,8 +8914,8 @@ function OhhwellsBridge() {
|
|
|
7483
8914
|
const router = (0, import_navigation2.useRouter)();
|
|
7484
8915
|
const searchParams = (0, import_navigation2.useSearchParams)();
|
|
7485
8916
|
const isEditMode = isEditSessionActive();
|
|
7486
|
-
const [bridgeRoot, setBridgeRoot] = (0,
|
|
7487
|
-
(0,
|
|
8917
|
+
const [bridgeRoot, setBridgeRoot] = (0, import_react9.useState)(null);
|
|
8918
|
+
(0, import_react9.useEffect)(() => {
|
|
7488
8919
|
const figtreeFontId = "ohw-figtree-font";
|
|
7489
8920
|
if (!document.getElementById(figtreeFontId)) {
|
|
7490
8921
|
const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
|
|
@@ -7512,91 +8943,137 @@ function OhhwellsBridge() {
|
|
|
7512
8943
|
const subdomainFromQuery = searchParams.get("subdomain");
|
|
7513
8944
|
const subdomain = resolveSubdomain(subdomainFromQuery);
|
|
7514
8945
|
useLinkHrefGuardian(pathname, subdomain, isEditMode);
|
|
7515
|
-
const postToParent2 = (0,
|
|
8946
|
+
const postToParent2 = (0, import_react9.useCallback)((data) => {
|
|
7516
8947
|
if (typeof window !== "undefined" && window.parent !== window) {
|
|
7517
8948
|
window.parent.postMessage(data, "*");
|
|
7518
8949
|
}
|
|
7519
8950
|
}, []);
|
|
7520
|
-
const [fetchState, setFetchState] = (0,
|
|
7521
|
-
const autoSaveTimers = (0,
|
|
7522
|
-
const activeElRef = (0,
|
|
7523
|
-
const
|
|
7524
|
-
const
|
|
7525
|
-
const
|
|
7526
|
-
const
|
|
7527
|
-
const
|
|
7528
|
-
const
|
|
7529
|
-
const
|
|
8951
|
+
const [fetchState, setFetchState] = (0, import_react9.useState)("idle");
|
|
8952
|
+
const autoSaveTimers = (0, import_react9.useRef)(/* @__PURE__ */ new Map());
|
|
8953
|
+
const activeElRef = (0, import_react9.useRef)(null);
|
|
8954
|
+
const pointerHeldRef = (0, import_react9.useRef)(false);
|
|
8955
|
+
const selectedElRef = (0, import_react9.useRef)(null);
|
|
8956
|
+
const selectedHrefKeyRef = (0, import_react9.useRef)(null);
|
|
8957
|
+
const selectedFooterColAttrRef = (0, import_react9.useRef)(null);
|
|
8958
|
+
const originalContentRef = (0, import_react9.useRef)(null);
|
|
8959
|
+
const activeStateElRef = (0, import_react9.useRef)(null);
|
|
8960
|
+
const parentScrollRef = (0, import_react9.useRef)(null);
|
|
8961
|
+
const visibleViewportRef = (0, import_react9.useRef)(null);
|
|
8962
|
+
const [dialogPortalContainer, setDialogPortalContainer] = (0, import_react9.useState)(null);
|
|
8963
|
+
const attachVisibleViewport = (0, import_react9.useCallback)((node) => {
|
|
7530
8964
|
visibleViewportRef.current = node;
|
|
7531
8965
|
setDialogPortalContainer(node);
|
|
7532
8966
|
if (node) applyVisibleViewport(node, parentScrollRef.current);
|
|
7533
8967
|
}, []);
|
|
7534
|
-
const toolbarElRef = (0,
|
|
7535
|
-
const glowElRef = (0,
|
|
7536
|
-
const hoveredImageRef = (0,
|
|
7537
|
-
const hoveredImageHasTextOverlapRef = (0,
|
|
7538
|
-
const dragOverElRef = (0,
|
|
7539
|
-
const [mediaHover, setMediaHover] = (0,
|
|
7540
|
-
const [uploadingRects, setUploadingRects] = (0,
|
|
7541
|
-
const hoveredGapRef = (0,
|
|
7542
|
-
const imageUnhoverTimerRef = (0,
|
|
7543
|
-
const imageShowTimerRef = (0,
|
|
7544
|
-
const editStylesRef = (0,
|
|
7545
|
-
const activateRef = (0,
|
|
8968
|
+
const toolbarElRef = (0, import_react9.useRef)(null);
|
|
8969
|
+
const glowElRef = (0, import_react9.useRef)(null);
|
|
8970
|
+
const hoveredImageRef = (0, import_react9.useRef)(null);
|
|
8971
|
+
const hoveredImageHasTextOverlapRef = (0, import_react9.useRef)(false);
|
|
8972
|
+
const dragOverElRef = (0, import_react9.useRef)(null);
|
|
8973
|
+
const [mediaHover, setMediaHover] = (0, import_react9.useState)(null);
|
|
8974
|
+
const [uploadingRects, setUploadingRects] = (0, import_react9.useState)({});
|
|
8975
|
+
const hoveredGapRef = (0, import_react9.useRef)(null);
|
|
8976
|
+
const imageUnhoverTimerRef = (0, import_react9.useRef)(null);
|
|
8977
|
+
const imageShowTimerRef = (0, import_react9.useRef)(null);
|
|
8978
|
+
const editStylesRef = (0, import_react9.useRef)(null);
|
|
8979
|
+
const activateRef = (0, import_react9.useRef)(() => {
|
|
7546
8980
|
});
|
|
7547
|
-
const deactivateRef = (0,
|
|
8981
|
+
const deactivateRef = (0, import_react9.useRef)(() => {
|
|
7548
8982
|
});
|
|
7549
|
-
const selectRef = (0,
|
|
8983
|
+
const selectRef = (0, import_react9.useRef)(() => {
|
|
7550
8984
|
});
|
|
7551
|
-
const selectFrameRef = (0,
|
|
8985
|
+
const selectFrameRef = (0, import_react9.useRef)(() => {
|
|
7552
8986
|
});
|
|
7553
|
-
const deselectRef = (0,
|
|
8987
|
+
const deselectRef = (0, import_react9.useRef)(() => {
|
|
7554
8988
|
});
|
|
7555
|
-
const reselectNavigationItemRef = (0,
|
|
8989
|
+
const reselectNavigationItemRef = (0, import_react9.useRef)(() => {
|
|
7556
8990
|
});
|
|
7557
|
-
const commitNavigationTextEditRef = (0,
|
|
8991
|
+
const commitNavigationTextEditRef = (0, import_react9.useRef)(() => {
|
|
7558
8992
|
});
|
|
7559
|
-
const refreshActiveCommandsRef = (0,
|
|
8993
|
+
const refreshActiveCommandsRef = (0, import_react9.useRef)(() => {
|
|
7560
8994
|
});
|
|
7561
|
-
const postToParentRef = (0,
|
|
8995
|
+
const postToParentRef = (0, import_react9.useRef)(postToParent2);
|
|
7562
8996
|
postToParentRef.current = postToParent2;
|
|
7563
|
-
const sectionsLoadedRef = (0,
|
|
7564
|
-
const pendingScheduleConfigRequests = (0,
|
|
7565
|
-
const [toolbarRect, setToolbarRect] = (0,
|
|
7566
|
-
const [toolbarVariant, setToolbarVariant] = (0,
|
|
7567
|
-
const toolbarVariantRef = (0,
|
|
8997
|
+
const sectionsLoadedRef = (0, import_react9.useRef)(false);
|
|
8998
|
+
const pendingScheduleConfigRequests = (0, import_react9.useRef)([]);
|
|
8999
|
+
const [toolbarRect, setToolbarRect] = (0, import_react9.useState)(null);
|
|
9000
|
+
const [toolbarVariant, setToolbarVariant] = (0, import_react9.useState)("none");
|
|
9001
|
+
const toolbarVariantRef = (0, import_react9.useRef)("none");
|
|
7568
9002
|
toolbarVariantRef.current = toolbarVariant;
|
|
7569
|
-
const [
|
|
7570
|
-
const [
|
|
7571
|
-
const [
|
|
7572
|
-
const [
|
|
7573
|
-
const [
|
|
7574
|
-
const [
|
|
7575
|
-
const [
|
|
7576
|
-
const
|
|
7577
|
-
const
|
|
7578
|
-
const
|
|
7579
|
-
const
|
|
7580
|
-
const
|
|
7581
|
-
const
|
|
7582
|
-
const [
|
|
7583
|
-
const [
|
|
7584
|
-
const
|
|
7585
|
-
const
|
|
7586
|
-
const
|
|
7587
|
-
const [
|
|
7588
|
-
const [
|
|
7589
|
-
const
|
|
7590
|
-
const
|
|
7591
|
-
const
|
|
7592
|
-
const
|
|
7593
|
-
const
|
|
9003
|
+
const [selectedIsCta, setSelectedIsCta] = (0, import_react9.useState)(false);
|
|
9004
|
+
const [reorderHrefKey, setReorderHrefKey] = (0, import_react9.useState)(null);
|
|
9005
|
+
const [reorderDragDisabled, setReorderDragDisabled] = (0, import_react9.useState)(false);
|
|
9006
|
+
const [toggleState, setToggleState] = (0, import_react9.useState)(null);
|
|
9007
|
+
const [maxBadge, setMaxBadge] = (0, import_react9.useState)(null);
|
|
9008
|
+
const [activeCommands, setActiveCommands] = (0, import_react9.useState)(/* @__PURE__ */ new Set());
|
|
9009
|
+
const [sectionGap, setSectionGap] = (0, import_react9.useState)(null);
|
|
9010
|
+
const [toolbarShowEditLink, setToolbarShowEditLink] = (0, import_react9.useState)(false);
|
|
9011
|
+
const hoveredNavContainerRef = (0, import_react9.useRef)(null);
|
|
9012
|
+
const [hoveredNavContainerRect, setHoveredNavContainerRect] = (0, import_react9.useState)(null);
|
|
9013
|
+
const hoveredItemElRef = (0, import_react9.useRef)(null);
|
|
9014
|
+
const [hoveredItemRect, setHoveredItemRect] = (0, import_react9.useState)(null);
|
|
9015
|
+
const siblingHintElRef = (0, import_react9.useRef)(null);
|
|
9016
|
+
const [siblingHintRect, setSiblingHintRect] = (0, import_react9.useState)(null);
|
|
9017
|
+
const [siblingHintRects, setSiblingHintRects] = (0, import_react9.useState)([]);
|
|
9018
|
+
const [isItemDragging, setIsItemDragging] = (0, import_react9.useState)(false);
|
|
9019
|
+
const [isFooterFrameSelection, setIsFooterFrameSelection] = (0, import_react9.useState)(false);
|
|
9020
|
+
const footerDragRef = (0, import_react9.useRef)(null);
|
|
9021
|
+
const [footerDropSlots, setFooterDropSlots] = (0, import_react9.useState)([]);
|
|
9022
|
+
const [activeFooterDropIndex, setActiveFooterDropIndex] = (0, import_react9.useState)(null);
|
|
9023
|
+
const [draggedItemRect, setDraggedItemRect] = (0, import_react9.useState)(null);
|
|
9024
|
+
const footerPointerDragRef = (0, import_react9.useRef)(null);
|
|
9025
|
+
const suppressNextClickRef = (0, import_react9.useRef)(false);
|
|
9026
|
+
const suppressClickUntilRef = (0, import_react9.useRef)(0);
|
|
9027
|
+
const [linkPopover, setLinkPopover] = (0, import_react9.useState)(null);
|
|
9028
|
+
const linkPopoverSessionRef = (0, import_react9.useRef)(null);
|
|
9029
|
+
const addNavAfterAnchorRef = (0, import_react9.useRef)(null);
|
|
9030
|
+
const editContentRef = (0, import_react9.useRef)({});
|
|
9031
|
+
const [sitePages, setSitePages] = (0, import_react9.useState)([]);
|
|
9032
|
+
const [sectionsByPath, setSectionsByPath] = (0, import_react9.useState)({});
|
|
9033
|
+
const sectionsPrefetchGenRef = (0, import_react9.useRef)(0);
|
|
9034
|
+
const setLinkPopoverRef = (0, import_react9.useRef)(setLinkPopover);
|
|
9035
|
+
const linkPopoverPanelRef = (0, import_react9.useRef)(null);
|
|
9036
|
+
const linkPopoverOpenRef = (0, import_react9.useRef)(false);
|
|
9037
|
+
const linkPopoverGraceUntilRef = (0, import_react9.useRef)(0);
|
|
7594
9038
|
setLinkPopoverRef.current = setLinkPopover;
|
|
7595
9039
|
linkPopoverSessionRef.current = linkPopover;
|
|
9040
|
+
const {
|
|
9041
|
+
navDragRef,
|
|
9042
|
+
navDropSlots,
|
|
9043
|
+
activeNavDropIndex,
|
|
9044
|
+
startNavLinkDrag,
|
|
9045
|
+
commitNavDrag,
|
|
9046
|
+
onNavDragOver,
|
|
9047
|
+
armNavPressFromChrome,
|
|
9048
|
+
refreshNavDragVisualsRef
|
|
9049
|
+
} = useNavItemDrag({
|
|
9050
|
+
isEditMode,
|
|
9051
|
+
editContentRef,
|
|
9052
|
+
selectedElRef,
|
|
9053
|
+
activeElRef,
|
|
9054
|
+
footerDragRef,
|
|
9055
|
+
suppressNextClickRef,
|
|
9056
|
+
suppressClickUntilRef,
|
|
9057
|
+
siblingHintElRef,
|
|
9058
|
+
postToParentRef,
|
|
9059
|
+
deselectRef,
|
|
9060
|
+
selectRef,
|
|
9061
|
+
deactivateRef,
|
|
9062
|
+
setLinkPopover: () => setLinkPopover(null),
|
|
9063
|
+
linkPopoverOpenRef,
|
|
9064
|
+
setIsItemDragging,
|
|
9065
|
+
setDraggedItemRect,
|
|
9066
|
+
setSiblingHintRect,
|
|
9067
|
+
setSiblingHintRects,
|
|
9068
|
+
setToolbarRect,
|
|
9069
|
+
getNavigationItemAnchor,
|
|
9070
|
+
isDragHandleDisabled,
|
|
9071
|
+
isNavbarButton: isNavbarButton2
|
|
9072
|
+
});
|
|
7596
9073
|
const bumpLinkPopoverGrace = () => {
|
|
7597
9074
|
linkPopoverGraceUntilRef.current = Date.now() + 350;
|
|
7598
9075
|
};
|
|
7599
|
-
const runSectionsPrefetch = (0,
|
|
9076
|
+
const runSectionsPrefetch = (0, import_react9.useCallback)((pages) => {
|
|
7600
9077
|
if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
|
|
7601
9078
|
const gen = ++sectionsPrefetchGenRef.current;
|
|
7602
9079
|
const paths = pages.map((p) => p.path);
|
|
@@ -7615,10 +9092,24 @@ function OhhwellsBridge() {
|
|
|
7615
9092
|
);
|
|
7616
9093
|
});
|
|
7617
9094
|
}, [isEditMode, pathname]);
|
|
7618
|
-
const runSectionsPrefetchRef = (0,
|
|
9095
|
+
const runSectionsPrefetchRef = (0, import_react9.useRef)(runSectionsPrefetch);
|
|
7619
9096
|
runSectionsPrefetchRef.current = runSectionsPrefetch;
|
|
7620
|
-
(0,
|
|
7621
|
-
if (!linkPopover)
|
|
9097
|
+
(0, import_react9.useEffect)(() => {
|
|
9098
|
+
if (!linkPopover) {
|
|
9099
|
+
document.documentElement.removeAttribute("data-ohw-link-popover-open");
|
|
9100
|
+
return;
|
|
9101
|
+
}
|
|
9102
|
+
document.documentElement.setAttribute("data-ohw-link-popover-open", "");
|
|
9103
|
+
hoveredItemElRef.current = null;
|
|
9104
|
+
setHoveredItemRect(null);
|
|
9105
|
+
hoveredNavContainerRef.current = null;
|
|
9106
|
+
setHoveredNavContainerRect(null);
|
|
9107
|
+
siblingHintElRef.current = null;
|
|
9108
|
+
setSiblingHintRect(null);
|
|
9109
|
+
setSiblingHintRects([]);
|
|
9110
|
+
if (selectedElRef.current || toolbarVariantRef.current !== "none") {
|
|
9111
|
+
deselectRef.current();
|
|
9112
|
+
}
|
|
7622
9113
|
if (hoveredImageRef.current) {
|
|
7623
9114
|
hoveredImageRef.current = null;
|
|
7624
9115
|
hoveredImageHasTextOverlapRef.current = false;
|
|
@@ -7652,7 +9143,7 @@ function OhhwellsBridge() {
|
|
|
7652
9143
|
document.removeEventListener("touchmove", preventBackgroundScroll, scrollOpts);
|
|
7653
9144
|
};
|
|
7654
9145
|
}, [linkPopover, postToParent2]);
|
|
7655
|
-
(0,
|
|
9146
|
+
(0, import_react9.useEffect)(() => {
|
|
7656
9147
|
if (!isEditMode) return;
|
|
7657
9148
|
const useFixtures = shouldUseDevFixtures();
|
|
7658
9149
|
if (useFixtures) {
|
|
@@ -7676,14 +9167,14 @@ function OhhwellsBridge() {
|
|
|
7676
9167
|
if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
|
|
7677
9168
|
return () => window.removeEventListener("message", onSitePages);
|
|
7678
9169
|
}, [isEditMode, postToParent2]);
|
|
7679
|
-
(0,
|
|
9170
|
+
(0, import_react9.useEffect)(() => {
|
|
7680
9171
|
if (!isEditMode || shouldUseDevFixtures()) return;
|
|
7681
9172
|
void loadAllSectionsManifest().then((manifest) => {
|
|
7682
9173
|
if (Object.keys(manifest).length === 0) return;
|
|
7683
9174
|
setSectionsByPath((prev) => ({ ...manifest, ...prev }));
|
|
7684
9175
|
});
|
|
7685
9176
|
}, [isEditMode]);
|
|
7686
|
-
(0,
|
|
9177
|
+
(0, import_react9.useEffect)(() => {
|
|
7687
9178
|
const update = () => {
|
|
7688
9179
|
const el = activeElRef.current ?? selectedElRef.current;
|
|
7689
9180
|
if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
|
|
@@ -7707,10 +9198,10 @@ function OhhwellsBridge() {
|
|
|
7707
9198
|
vvp.removeEventListener("resize", update);
|
|
7708
9199
|
};
|
|
7709
9200
|
}, []);
|
|
7710
|
-
const refreshStateRules = (0,
|
|
9201
|
+
const refreshStateRules = (0, import_react9.useCallback)(() => {
|
|
7711
9202
|
editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
|
|
7712
9203
|
}, []);
|
|
7713
|
-
const processConfigRequest = (0,
|
|
9204
|
+
const processConfigRequest = (0, import_react9.useCallback)((insertAfterVal) => {
|
|
7714
9205
|
const tracker = getSectionsTracker();
|
|
7715
9206
|
let entries = [];
|
|
7716
9207
|
try {
|
|
@@ -7733,7 +9224,7 @@ function OhhwellsBridge() {
|
|
|
7733
9224
|
}
|
|
7734
9225
|
window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
|
|
7735
9226
|
}, [isEditMode]);
|
|
7736
|
-
const deactivate = (0,
|
|
9227
|
+
const deactivate = (0, import_react9.useCallback)(() => {
|
|
7737
9228
|
const el = activeElRef.current;
|
|
7738
9229
|
if (!el) return;
|
|
7739
9230
|
const key = el.dataset.ohwKey;
|
|
@@ -7752,6 +9243,7 @@ function OhhwellsBridge() {
|
|
|
7752
9243
|
}
|
|
7753
9244
|
}
|
|
7754
9245
|
el.removeAttribute("contenteditable");
|
|
9246
|
+
el.removeAttribute("data-ohw-editing");
|
|
7755
9247
|
activeElRef.current = null;
|
|
7756
9248
|
setReorderHrefKey(null);
|
|
7757
9249
|
setReorderDragDisabled(false);
|
|
@@ -7764,12 +9256,23 @@ function OhhwellsBridge() {
|
|
|
7764
9256
|
setToolbarShowEditLink(false);
|
|
7765
9257
|
postToParent2({ type: "ow:exit-edit" });
|
|
7766
9258
|
}, [postToParent2]);
|
|
7767
|
-
const
|
|
9259
|
+
const clearSelectedAttr = (0, import_react9.useCallback)(() => {
|
|
9260
|
+
document.querySelectorAll("[data-ohw-selected]").forEach((el) => {
|
|
9261
|
+
el.removeAttribute("data-ohw-selected");
|
|
9262
|
+
});
|
|
9263
|
+
}, []);
|
|
9264
|
+
const deselect = (0, import_react9.useCallback)(() => {
|
|
9265
|
+
clearSelectedAttr();
|
|
7768
9266
|
selectedElRef.current = null;
|
|
9267
|
+
selectedHrefKeyRef.current = null;
|
|
9268
|
+
selectedFooterColAttrRef.current = null;
|
|
9269
|
+
setSelectedIsCta(false);
|
|
7769
9270
|
setReorderHrefKey(null);
|
|
7770
9271
|
setReorderDragDisabled(false);
|
|
9272
|
+
setIsFooterFrameSelection(false);
|
|
7771
9273
|
siblingHintElRef.current = null;
|
|
7772
9274
|
setSiblingHintRect(null);
|
|
9275
|
+
setSiblingHintRects([]);
|
|
7773
9276
|
setIsItemDragging(false);
|
|
7774
9277
|
hoveredNavContainerRef.current = null;
|
|
7775
9278
|
setHoveredNavContainerRect(null);
|
|
@@ -7777,18 +9280,70 @@ function OhhwellsBridge() {
|
|
|
7777
9280
|
setToolbarRect(null);
|
|
7778
9281
|
setToolbarVariant("none");
|
|
7779
9282
|
}
|
|
9283
|
+
}, [clearSelectedAttr]);
|
|
9284
|
+
const markSelected = (0, import_react9.useCallback)((el) => {
|
|
9285
|
+
clearSelectedAttr();
|
|
9286
|
+
el.setAttribute("data-ohw-selected", "");
|
|
9287
|
+
}, [clearSelectedAttr]);
|
|
9288
|
+
const resolveHrefKeyElement = (0, import_react9.useCallback)((hrefKey) => {
|
|
9289
|
+
if (isFooterHrefKey(hrefKey)) {
|
|
9290
|
+
return document.querySelector(
|
|
9291
|
+
`footer [data-ohw-href-key="${CSS.escape(hrefKey)}"]`
|
|
9292
|
+
);
|
|
9293
|
+
}
|
|
9294
|
+
if (isNavbarHrefKey(hrefKey)) {
|
|
9295
|
+
const desktop = document.querySelector("[data-ohw-nav-container]");
|
|
9296
|
+
const drawer = document.querySelector("[data-ohw-nav-drawer]");
|
|
9297
|
+
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)}"]`);
|
|
9298
|
+
}
|
|
9299
|
+
return document.querySelector(
|
|
9300
|
+
`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`
|
|
9301
|
+
);
|
|
7780
9302
|
}, []);
|
|
7781
|
-
const
|
|
9303
|
+
const resyncSelectedNavigationItem = (0, import_react9.useCallback)(() => {
|
|
9304
|
+
const hrefKey = selectedHrefKeyRef.current;
|
|
9305
|
+
if (hrefKey) {
|
|
9306
|
+
const link = resolveHrefKeyElement(hrefKey);
|
|
9307
|
+
if (!link || !isNavigationItem(link)) return;
|
|
9308
|
+
selectedElRef.current = link;
|
|
9309
|
+
const { key, disabled } = getNavigationItemReorderState(link);
|
|
9310
|
+
setReorderHrefKey(key);
|
|
9311
|
+
setReorderDragDisabled(disabled);
|
|
9312
|
+
setIsFooterFrameSelection(false);
|
|
9313
|
+
setToolbarVariant("link-action");
|
|
9314
|
+
setToolbarRect(link.getBoundingClientRect());
|
|
9315
|
+
setSiblingHintRects(collectNavigationItemSiblingHintRects(link));
|
|
9316
|
+
return;
|
|
9317
|
+
}
|
|
9318
|
+
const colAttr = selectedFooterColAttrRef.current;
|
|
9319
|
+
if (colAttr != null) {
|
|
9320
|
+
const column = document.querySelector(`[data-ohw-footer-col="${CSS.escape(colAttr)}"]`) ?? listFooterColumns()[Number(colAttr)] ?? null;
|
|
9321
|
+
if (!column || !isNavigationContainer(column)) return;
|
|
9322
|
+
selectedElRef.current = column;
|
|
9323
|
+
setIsFooterFrameSelection(true);
|
|
9324
|
+
setToolbarVariant("select-frame");
|
|
9325
|
+
setToolbarRect(column.getBoundingClientRect());
|
|
9326
|
+
setSiblingHintRects(
|
|
9327
|
+
listFooterColumns().filter((c) => c !== column).map((c) => c.getBoundingClientRect())
|
|
9328
|
+
);
|
|
9329
|
+
}
|
|
9330
|
+
}, [resolveHrefKeyElement]);
|
|
9331
|
+
const reselectNavigationItem = (0, import_react9.useCallback)((navAnchor) => {
|
|
7782
9332
|
selectedElRef.current = navAnchor;
|
|
9333
|
+
selectedHrefKeyRef.current = navAnchor.getAttribute("data-ohw-href-key");
|
|
9334
|
+
selectedFooterColAttrRef.current = null;
|
|
9335
|
+
markSelected(navAnchor);
|
|
9336
|
+
setSelectedIsCta(isNavbarButton2(navAnchor));
|
|
7783
9337
|
const { key, disabled } = getNavigationItemReorderState(navAnchor);
|
|
7784
9338
|
setReorderHrefKey(key);
|
|
7785
9339
|
setReorderDragDisabled(disabled);
|
|
7786
9340
|
setToolbarVariant("link-action");
|
|
7787
9341
|
setToolbarRect(navAnchor.getBoundingClientRect());
|
|
9342
|
+
setSiblingHintRects(collectNavigationItemSiblingHintRects(navAnchor));
|
|
7788
9343
|
setToolbarShowEditLink(false);
|
|
7789
9344
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
7790
|
-
}, []);
|
|
7791
|
-
const commitNavigationTextEdit = (0,
|
|
9345
|
+
}, [markSelected]);
|
|
9346
|
+
const commitNavigationTextEdit = (0, import_react9.useCallback)((navAnchor) => {
|
|
7792
9347
|
const el = activeElRef.current;
|
|
7793
9348
|
if (!el) return;
|
|
7794
9349
|
const key = el.dataset.ohwKey;
|
|
@@ -7807,6 +9362,7 @@ function OhhwellsBridge() {
|
|
|
7807
9362
|
}
|
|
7808
9363
|
}
|
|
7809
9364
|
el.removeAttribute("contenteditable");
|
|
9365
|
+
el.removeAttribute("data-ohw-editing");
|
|
7810
9366
|
activeElRef.current = null;
|
|
7811
9367
|
setMaxBadge(null);
|
|
7812
9368
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
@@ -7814,7 +9370,7 @@ function OhhwellsBridge() {
|
|
|
7814
9370
|
postToParent2({ type: "ow:exit-edit" });
|
|
7815
9371
|
reselectNavigationItem(navAnchor);
|
|
7816
9372
|
}, [postToParent2, reselectNavigationItem]);
|
|
7817
|
-
const handleAddTopLevelNavItem = (0,
|
|
9373
|
+
const handleAddTopLevelNavItem = (0, import_react9.useCallback)(() => {
|
|
7818
9374
|
const items = listNavbarItems();
|
|
7819
9375
|
addNavAfterAnchorRef.current = items[items.length - 1] ?? null;
|
|
7820
9376
|
deselectRef.current();
|
|
@@ -7826,20 +9382,321 @@ function OhhwellsBridge() {
|
|
|
7826
9382
|
intent: "add-nav"
|
|
7827
9383
|
});
|
|
7828
9384
|
}, []);
|
|
7829
|
-
const
|
|
7830
|
-
|
|
7831
|
-
|
|
7832
|
-
|
|
7833
|
-
|
|
7834
|
-
|
|
9385
|
+
const clearFooterDragVisuals = (0, import_react9.useCallback)(() => {
|
|
9386
|
+
footerDragRef.current = null;
|
|
9387
|
+
setSiblingHintRects([]);
|
|
9388
|
+
setFooterDropSlots([]);
|
|
9389
|
+
setActiveFooterDropIndex(null);
|
|
9390
|
+
setDraggedItemRect(null);
|
|
7835
9391
|
setIsItemDragging(false);
|
|
9392
|
+
unlockFooterDragInteraction();
|
|
9393
|
+
}, []);
|
|
9394
|
+
const refreshFooterDragVisuals = (0, import_react9.useCallback)((session, activeSlot, clientX, clientY) => {
|
|
9395
|
+
const dragged = session.draggedEl;
|
|
9396
|
+
setDraggedItemRect(dragged.getBoundingClientRect());
|
|
9397
|
+
if (typeof clientX === "number" && typeof clientY === "number") {
|
|
9398
|
+
session.lastClientX = clientX;
|
|
9399
|
+
session.lastClientY = clientY;
|
|
9400
|
+
}
|
|
9401
|
+
session.activeSlot = activeSlot;
|
|
9402
|
+
if (session.kind === "link") {
|
|
9403
|
+
const columns2 = listFooterColumns();
|
|
9404
|
+
const focusCols = /* @__PURE__ */ new Set([session.sourceColumnIndex]);
|
|
9405
|
+
if (activeSlot) focusCols.add(activeSlot.columnIndex);
|
|
9406
|
+
const siblingRects = [];
|
|
9407
|
+
columns2.forEach((col, i) => {
|
|
9408
|
+
if (!focusCols.has(i)) return;
|
|
9409
|
+
for (const link of listFooterLinksInColumn(col)) {
|
|
9410
|
+
if (link === dragged) continue;
|
|
9411
|
+
siblingRects.push(link.getBoundingClientRect());
|
|
9412
|
+
}
|
|
9413
|
+
});
|
|
9414
|
+
setSiblingHintRects(siblingRects);
|
|
9415
|
+
const slots2 = [];
|
|
9416
|
+
columns2.forEach((col, i) => {
|
|
9417
|
+
slots2.push(...buildLinkDropSlots(col, i));
|
|
9418
|
+
});
|
|
9419
|
+
setFooterDropSlots(slots2);
|
|
9420
|
+
const activeIdx2 = activeSlot ? slots2.findIndex((s) => s.columnIndex === activeSlot.columnIndex && s.insertIndex === activeSlot.insertIndex) : -1;
|
|
9421
|
+
setActiveFooterDropIndex(activeIdx2 >= 0 ? activeIdx2 : null);
|
|
9422
|
+
return;
|
|
9423
|
+
}
|
|
9424
|
+
const columns = listFooterColumns();
|
|
9425
|
+
setSiblingHintRects(columns.filter((col) => col !== dragged).map((col) => col.getBoundingClientRect()));
|
|
9426
|
+
const slots = buildColumnDropSlots();
|
|
9427
|
+
setFooterDropSlots(slots);
|
|
9428
|
+
const activeIdx = activeSlot ? slots.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
|
|
9429
|
+
setActiveFooterDropIndex(activeIdx >= 0 ? activeIdx : null);
|
|
9430
|
+
}, []);
|
|
9431
|
+
const refreshFooterDragVisualsRef = (0, import_react9.useRef)(refreshFooterDragVisuals);
|
|
9432
|
+
refreshFooterDragVisualsRef.current = refreshFooterDragVisuals;
|
|
9433
|
+
const commitFooterDragRef = (0, import_react9.useRef)(() => {
|
|
9434
|
+
});
|
|
9435
|
+
const beginFooterDragRef = (0, import_react9.useRef)(() => {
|
|
9436
|
+
});
|
|
9437
|
+
const beginFooterDrag = (0, import_react9.useCallback)(
|
|
9438
|
+
(session) => {
|
|
9439
|
+
const rect = session.draggedEl.getBoundingClientRect();
|
|
9440
|
+
session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
|
|
9441
|
+
session.lastClientY = session.lastClientY || rect.top + rect.height / 2;
|
|
9442
|
+
session.activeSlot = session.activeSlot ?? null;
|
|
9443
|
+
footerDragRef.current = session;
|
|
9444
|
+
setIsItemDragging(true);
|
|
9445
|
+
lockFooterDuringDrag();
|
|
9446
|
+
siblingHintElRef.current = null;
|
|
9447
|
+
setSiblingHintRect(null);
|
|
9448
|
+
if (session.wasSelected && selectedElRef.current === session.draggedEl) {
|
|
9449
|
+
setToolbarRect(rect);
|
|
9450
|
+
}
|
|
9451
|
+
const initialSlot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : hitTestColumnDropSlot(session.lastClientX, session.lastClientY);
|
|
9452
|
+
refreshFooterDragVisuals(session, initialSlot, session.lastClientX, session.lastClientY);
|
|
9453
|
+
},
|
|
9454
|
+
[refreshFooterDragVisuals]
|
|
9455
|
+
);
|
|
9456
|
+
beginFooterDragRef.current = beginFooterDrag;
|
|
9457
|
+
const commitFooterDrag = (0, import_react9.useCallback)(
|
|
9458
|
+
(clientX, clientY) => {
|
|
9459
|
+
const session = footerDragRef.current;
|
|
9460
|
+
if (!session) {
|
|
9461
|
+
clearFooterDragVisuals();
|
|
9462
|
+
return;
|
|
9463
|
+
}
|
|
9464
|
+
const x = typeof clientX === "number" && (clientX !== 0 || clientY !== 0) ? clientX : session.lastClientX;
|
|
9465
|
+
const y = typeof clientY === "number" && (clientX !== 0 || clientY !== 0) ? clientY : session.lastClientY;
|
|
9466
|
+
let nextOrder = null;
|
|
9467
|
+
const slot = session.activeSlot ?? (session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(x, y, session.hrefKey) : session.kind === "column" ? hitTestColumnDropSlot(x, y) : null);
|
|
9468
|
+
if (session.kind === "link" && session.hrefKey && slot) {
|
|
9469
|
+
nextOrder = planFooterLinkMove(session.hrefKey, slot.columnIndex, slot.insertIndex);
|
|
9470
|
+
} else if (session.kind === "column" && slot) {
|
|
9471
|
+
nextOrder = planFooterColumnMove(session.sourceColumnIndex, slot.insertIndex);
|
|
9472
|
+
}
|
|
9473
|
+
const wasSelected = session.wasSelected;
|
|
9474
|
+
const draggedEl = session.draggedEl;
|
|
9475
|
+
const hrefKey = session.hrefKey;
|
|
9476
|
+
let movedColumnIndex = null;
|
|
9477
|
+
if (session.kind === "column" && slot && nextOrder) {
|
|
9478
|
+
let adjusted = slot.insertIndex;
|
|
9479
|
+
if (session.sourceColumnIndex < slot.insertIndex) adjusted -= 1;
|
|
9480
|
+
movedColumnIndex = Math.max(0, Math.min(adjusted, nextOrder.length - 1));
|
|
9481
|
+
}
|
|
9482
|
+
const applySelectionAfterDrop = () => {
|
|
9483
|
+
if (!wasSelected) {
|
|
9484
|
+
deselectRef.current();
|
|
9485
|
+
return;
|
|
9486
|
+
}
|
|
9487
|
+
if (hrefKey) {
|
|
9488
|
+
selectedHrefKeyRef.current = hrefKey;
|
|
9489
|
+
selectedFooterColAttrRef.current = null;
|
|
9490
|
+
const link = resolveHrefKeyElement(hrefKey);
|
|
9491
|
+
if (link && isNavigationItem(link)) {
|
|
9492
|
+
selectRef.current(link);
|
|
9493
|
+
return;
|
|
9494
|
+
}
|
|
9495
|
+
}
|
|
9496
|
+
if (movedColumnIndex !== null && nextOrder) {
|
|
9497
|
+
const colKeys = nextOrder[movedColumnIndex] ?? [];
|
|
9498
|
+
let column = null;
|
|
9499
|
+
for (const key of colKeys) {
|
|
9500
|
+
const link = document.querySelector(
|
|
9501
|
+
`footer [data-ohw-href-key="${CSS.escape(key)}"]`
|
|
9502
|
+
);
|
|
9503
|
+
if (link) {
|
|
9504
|
+
column = findFooterColumnForLink(link);
|
|
9505
|
+
if (column) break;
|
|
9506
|
+
}
|
|
9507
|
+
}
|
|
9508
|
+
if (!column) column = listFooterColumns()[movedColumnIndex] ?? null;
|
|
9509
|
+
if (column && isNavigationContainer(column)) {
|
|
9510
|
+
selectFrameRef.current(column);
|
|
9511
|
+
return;
|
|
9512
|
+
}
|
|
9513
|
+
}
|
|
9514
|
+
if (document.body.contains(draggedEl)) {
|
|
9515
|
+
if (isNavigationItem(draggedEl)) {
|
|
9516
|
+
selectRef.current(draggedEl);
|
|
9517
|
+
return;
|
|
9518
|
+
}
|
|
9519
|
+
if (isNavigationContainer(draggedEl)) {
|
|
9520
|
+
selectFrameRef.current(draggedEl);
|
|
9521
|
+
return;
|
|
9522
|
+
}
|
|
9523
|
+
}
|
|
9524
|
+
deselectRef.current();
|
|
9525
|
+
};
|
|
9526
|
+
if (nextOrder) {
|
|
9527
|
+
const orderJson = JSON.stringify(nextOrder);
|
|
9528
|
+
editContentRef.current = {
|
|
9529
|
+
...editContentRef.current,
|
|
9530
|
+
[FOOTER_ORDER_KEY]: orderJson
|
|
9531
|
+
};
|
|
9532
|
+
applyFooterOrder(nextOrder);
|
|
9533
|
+
document.querySelectorAll("footer [data-ohw-href-key]").forEach(disableNativeHrefDrag);
|
|
9534
|
+
postToParentRef.current({
|
|
9535
|
+
type: "ow:change",
|
|
9536
|
+
nodes: [{ key: FOOTER_ORDER_KEY, text: orderJson }]
|
|
9537
|
+
});
|
|
9538
|
+
applySelectionAfterDrop();
|
|
9539
|
+
clearFooterDragVisuals();
|
|
9540
|
+
requestAnimationFrame(() => {
|
|
9541
|
+
if (editContentRef.current[FOOTER_ORDER_KEY] === orderJson) {
|
|
9542
|
+
applyFooterOrder(nextOrder);
|
|
9543
|
+
document.querySelectorAll("footer [data-ohw-href-key]").forEach(disableNativeHrefDrag);
|
|
9544
|
+
}
|
|
9545
|
+
applySelectionAfterDrop();
|
|
9546
|
+
requestAnimationFrame(() => {
|
|
9547
|
+
if (editContentRef.current[FOOTER_ORDER_KEY] === orderJson) {
|
|
9548
|
+
applyFooterOrder(nextOrder);
|
|
9549
|
+
}
|
|
9550
|
+
resyncSelectedNavigationItem();
|
|
9551
|
+
});
|
|
9552
|
+
});
|
|
9553
|
+
return;
|
|
9554
|
+
}
|
|
9555
|
+
applySelectionAfterDrop();
|
|
9556
|
+
clearFooterDragVisuals();
|
|
9557
|
+
},
|
|
9558
|
+
[clearFooterDragVisuals, resolveHrefKeyElement, resyncSelectedNavigationItem]
|
|
9559
|
+
);
|
|
9560
|
+
commitFooterDragRef.current = commitFooterDrag;
|
|
9561
|
+
const startFooterLinkDrag = (0, import_react9.useCallback)(
|
|
9562
|
+
(anchor, clientX, clientY, wasSelected) => {
|
|
9563
|
+
const hrefKey = anchor.getAttribute("data-ohw-href-key");
|
|
9564
|
+
if (!hrefKey || !isFooterHrefKey(hrefKey)) return false;
|
|
9565
|
+
const column = findFooterColumnForLink(anchor);
|
|
9566
|
+
const columns = listFooterColumns();
|
|
9567
|
+
beginFooterDrag({
|
|
9568
|
+
kind: "link",
|
|
9569
|
+
hrefKey,
|
|
9570
|
+
columnEl: column,
|
|
9571
|
+
sourceColumnIndex: column ? columns.indexOf(column) : 0,
|
|
9572
|
+
wasSelected,
|
|
9573
|
+
draggedEl: anchor,
|
|
9574
|
+
lastClientX: clientX,
|
|
9575
|
+
lastClientY: clientY,
|
|
9576
|
+
activeSlot: null
|
|
9577
|
+
});
|
|
9578
|
+
return true;
|
|
9579
|
+
},
|
|
9580
|
+
[beginFooterDrag]
|
|
9581
|
+
);
|
|
9582
|
+
const startFooterColumnDrag = (0, import_react9.useCallback)(
|
|
9583
|
+
(columnEl, clientX, clientY, wasSelected) => {
|
|
9584
|
+
const columns = listFooterColumns();
|
|
9585
|
+
const idx = columns.indexOf(columnEl);
|
|
9586
|
+
if (idx < 0) return false;
|
|
9587
|
+
beginFooterDrag({
|
|
9588
|
+
kind: "column",
|
|
9589
|
+
hrefKey: null,
|
|
9590
|
+
columnEl,
|
|
9591
|
+
sourceColumnIndex: idx,
|
|
9592
|
+
wasSelected,
|
|
9593
|
+
draggedEl: columnEl,
|
|
9594
|
+
lastClientX: clientX,
|
|
9595
|
+
lastClientY: clientY,
|
|
9596
|
+
activeSlot: null
|
|
9597
|
+
});
|
|
9598
|
+
return true;
|
|
9599
|
+
},
|
|
9600
|
+
[beginFooterDrag]
|
|
9601
|
+
);
|
|
9602
|
+
const handleItemDragStart = (0, import_react9.useCallback)(
|
|
9603
|
+
(e) => {
|
|
9604
|
+
const selected = selectedElRef.current;
|
|
9605
|
+
if (!selected) {
|
|
9606
|
+
setIsItemDragging(true);
|
|
9607
|
+
return;
|
|
9608
|
+
}
|
|
9609
|
+
const clientX = e?.clientX ?? selected.getBoundingClientRect().left + 8;
|
|
9610
|
+
const clientY = e?.clientY ?? selected.getBoundingClientRect().top + 8;
|
|
9611
|
+
if (startFooterLinkDrag(selected, clientX, clientY, true)) return;
|
|
9612
|
+
if (selected.hasAttribute("data-ohw-footer-col") || isInferredFooterGroup(selected) && selected.closest("footer")) {
|
|
9613
|
+
if (startFooterColumnDrag(selected, clientX, clientY, true)) return;
|
|
9614
|
+
}
|
|
9615
|
+
if (startNavLinkDrag(selected, clientX, clientY, true)) return;
|
|
9616
|
+
siblingHintElRef.current = null;
|
|
9617
|
+
setSiblingHintRect(null);
|
|
9618
|
+
setIsItemDragging(true);
|
|
9619
|
+
},
|
|
9620
|
+
[startFooterColumnDrag, startFooterLinkDrag, startNavLinkDrag]
|
|
9621
|
+
);
|
|
9622
|
+
const handleItemDragEnd = (0, import_react9.useCallback)(
|
|
9623
|
+
(e) => {
|
|
9624
|
+
if (footerDragRef.current) {
|
|
9625
|
+
const x = e?.clientX;
|
|
9626
|
+
const y = e?.clientY;
|
|
9627
|
+
if (typeof x === "number" && typeof y === "number" && (x !== 0 || y !== 0)) {
|
|
9628
|
+
commitFooterDrag(x, y);
|
|
9629
|
+
} else {
|
|
9630
|
+
commitFooterDrag();
|
|
9631
|
+
}
|
|
9632
|
+
return;
|
|
9633
|
+
}
|
|
9634
|
+
if (navDragRef.current) {
|
|
9635
|
+
const x = e?.clientX;
|
|
9636
|
+
const y = e?.clientY;
|
|
9637
|
+
if (typeof x === "number" && typeof y === "number" && (x !== 0 || y !== 0)) {
|
|
9638
|
+
commitNavDrag(x, y);
|
|
9639
|
+
} else {
|
|
9640
|
+
commitNavDrag();
|
|
9641
|
+
}
|
|
9642
|
+
return;
|
|
9643
|
+
}
|
|
9644
|
+
setIsItemDragging(false);
|
|
9645
|
+
},
|
|
9646
|
+
[commitFooterDrag, commitNavDrag, navDragRef]
|
|
9647
|
+
);
|
|
9648
|
+
const handleItemChromePointerDown = (0, import_react9.useCallback)((e) => {
|
|
9649
|
+
if (e.button !== 0) return;
|
|
9650
|
+
const selected = selectedElRef.current;
|
|
9651
|
+
if (!selected) return;
|
|
9652
|
+
const hrefKey = selected.getAttribute("data-ohw-href-key");
|
|
9653
|
+
if (hrefKey && isFooterHrefKey(hrefKey)) {
|
|
9654
|
+
footerPointerDragRef.current = {
|
|
9655
|
+
el: selected,
|
|
9656
|
+
kind: "link",
|
|
9657
|
+
startX: e.clientX,
|
|
9658
|
+
startY: e.clientY,
|
|
9659
|
+
pointerId: e.pointerId,
|
|
9660
|
+
wasSelected: true,
|
|
9661
|
+
started: false
|
|
9662
|
+
};
|
|
9663
|
+
return;
|
|
9664
|
+
}
|
|
9665
|
+
if (selected.hasAttribute("data-ohw-footer-col") || isInferredFooterGroup(selected) && selected.closest("footer")) {
|
|
9666
|
+
footerPointerDragRef.current = {
|
|
9667
|
+
el: selected,
|
|
9668
|
+
kind: "column",
|
|
9669
|
+
startX: e.clientX,
|
|
9670
|
+
startY: e.clientY,
|
|
9671
|
+
pointerId: e.pointerId,
|
|
9672
|
+
wasSelected: true,
|
|
9673
|
+
started: false
|
|
9674
|
+
};
|
|
9675
|
+
return;
|
|
9676
|
+
}
|
|
9677
|
+
if (armNavPressFromChrome(selected, e.clientX, e.clientY, e.pointerId)) return;
|
|
9678
|
+
}, [armNavPressFromChrome]);
|
|
9679
|
+
const handleItemChromeClick = (0, import_react9.useCallback)((clientX, clientY) => {
|
|
9680
|
+
if (suppressNextClickRef.current || Date.now() < suppressClickUntilRef.current) {
|
|
9681
|
+
suppressNextClickRef.current = false;
|
|
9682
|
+
return;
|
|
9683
|
+
}
|
|
9684
|
+
const selected = selectedElRef.current;
|
|
9685
|
+
if (!selected || !isNavigationItem(selected)) return;
|
|
9686
|
+
const editable = selected.querySelector('[data-ohw-editable="text"]') ?? selected.querySelector("[data-ohw-editable]");
|
|
9687
|
+
if (!editable) return;
|
|
9688
|
+
activateRef.current(editable, { caretX: clientX, caretY: clientY });
|
|
7836
9689
|
}, []);
|
|
7837
9690
|
reselectNavigationItemRef.current = reselectNavigationItem;
|
|
7838
9691
|
commitNavigationTextEditRef.current = commitNavigationTextEdit;
|
|
7839
|
-
const select = (0,
|
|
9692
|
+
const select = (0, import_react9.useCallback)((anchor) => {
|
|
7840
9693
|
if (!isNavigationItem(anchor)) return;
|
|
7841
9694
|
if (activeElRef.current) deactivate();
|
|
7842
9695
|
selectedElRef.current = anchor;
|
|
9696
|
+
selectedHrefKeyRef.current = anchor.getAttribute("data-ohw-href-key");
|
|
9697
|
+
selectedFooterColAttrRef.current = null;
|
|
9698
|
+
markSelected(anchor);
|
|
9699
|
+
setSelectedIsCta(isNavbarButton2(anchor));
|
|
7843
9700
|
clearHrefKeyHover(anchor);
|
|
7844
9701
|
hoveredNavContainerRef.current = null;
|
|
7845
9702
|
setHoveredNavContainerRect(null);
|
|
@@ -7847,19 +9704,26 @@ function OhhwellsBridge() {
|
|
|
7847
9704
|
hoveredItemElRef.current = null;
|
|
7848
9705
|
siblingHintElRef.current = null;
|
|
7849
9706
|
setSiblingHintRect(null);
|
|
9707
|
+
setSiblingHintRects(collectNavigationItemSiblingHintRects(anchor));
|
|
7850
9708
|
setIsItemDragging(false);
|
|
7851
9709
|
const { key, disabled } = getNavigationItemReorderState(anchor);
|
|
7852
9710
|
setReorderHrefKey(key);
|
|
7853
9711
|
setReorderDragDisabled(disabled);
|
|
9712
|
+
setIsFooterFrameSelection(false);
|
|
7854
9713
|
setToolbarVariant("link-action");
|
|
7855
9714
|
setToolbarRect(anchor.getBoundingClientRect());
|
|
7856
9715
|
setToolbarShowEditLink(false);
|
|
7857
9716
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
7858
|
-
}, [deactivate]);
|
|
7859
|
-
const selectFrame = (0,
|
|
9717
|
+
}, [deactivate, markSelected]);
|
|
9718
|
+
const selectFrame = (0, import_react9.useCallback)((el) => {
|
|
7860
9719
|
if (!isNavigationContainer(el)) return;
|
|
7861
9720
|
if (activeElRef.current) deactivate();
|
|
9721
|
+
const isFooterColumn = el.hasAttribute("data-ohw-footer-col") || Boolean(el.closest("footer") && isInferredFooterGroup(el));
|
|
7862
9722
|
selectedElRef.current = el;
|
|
9723
|
+
selectedHrefKeyRef.current = null;
|
|
9724
|
+
selectedFooterColAttrRef.current = isFooterColumn ? el.getAttribute("data-ohw-footer-col") ?? String(listFooterColumns().indexOf(el)) : null;
|
|
9725
|
+
markSelected(el);
|
|
9726
|
+
setSelectedIsCta(false);
|
|
7863
9727
|
clearHrefKeyHover(el);
|
|
7864
9728
|
hoveredNavContainerRef.current = null;
|
|
7865
9729
|
setHoveredNavContainerRect(null);
|
|
@@ -7867,17 +9731,25 @@ function OhhwellsBridge() {
|
|
|
7867
9731
|
hoveredItemElRef.current = null;
|
|
7868
9732
|
siblingHintElRef.current = null;
|
|
7869
9733
|
setSiblingHintRect(null);
|
|
9734
|
+
setSiblingHintRects(
|
|
9735
|
+
isFooterColumn ? listFooterColumns().filter((column) => column !== el).map((column) => column.getBoundingClientRect()) : []
|
|
9736
|
+
);
|
|
7870
9737
|
setIsItemDragging(false);
|
|
7871
9738
|
setReorderHrefKey(null);
|
|
7872
9739
|
setReorderDragDisabled(false);
|
|
9740
|
+
setIsFooterFrameSelection(isFooterColumn);
|
|
7873
9741
|
setToolbarVariant("select-frame");
|
|
7874
9742
|
setToolbarRect(el.getBoundingClientRect());
|
|
7875
9743
|
setToolbarShowEditLink(false);
|
|
7876
9744
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
7877
|
-
}, [deactivate]);
|
|
7878
|
-
const activate = (0,
|
|
9745
|
+
}, [deactivate, markSelected]);
|
|
9746
|
+
const activate = (0, import_react9.useCallback)((el, options) => {
|
|
7879
9747
|
if (activeElRef.current === el) return;
|
|
9748
|
+
clearSelectedAttr();
|
|
7880
9749
|
selectedElRef.current = null;
|
|
9750
|
+
selectedHrefKeyRef.current = null;
|
|
9751
|
+
selectedFooterColAttrRef.current = null;
|
|
9752
|
+
setSelectedIsCta(false);
|
|
7881
9753
|
deactivate();
|
|
7882
9754
|
if (hoveredImageRef.current) {
|
|
7883
9755
|
hoveredImageRef.current = null;
|
|
@@ -7887,14 +9759,34 @@ function OhhwellsBridge() {
|
|
|
7887
9759
|
siblingHintElRef.current = null;
|
|
7888
9760
|
setSiblingHintRect(null);
|
|
7889
9761
|
setIsItemDragging(false);
|
|
9762
|
+
const preActivationSelection = window.getSelection();
|
|
9763
|
+
const preservedRange = preActivationSelection && preActivationSelection.rangeCount > 0 && !preActivationSelection.isCollapsed && el.contains(preActivationSelection.getRangeAt(0).commonAncestorContainer) ? preActivationSelection.getRangeAt(0).cloneRange() : null;
|
|
7890
9764
|
el.setAttribute("contenteditable", "true");
|
|
9765
|
+
el.setAttribute("data-ohw-editing", "");
|
|
7891
9766
|
el.removeAttribute("data-ohw-hovered");
|
|
7892
9767
|
el.closest("[data-ohw-href-key]")?.removeAttribute("data-ohw-hovered");
|
|
7893
9768
|
activeElRef.current = el;
|
|
7894
9769
|
originalContentRef.current = el.innerHTML;
|
|
7895
|
-
el.focus();
|
|
7896
|
-
if (
|
|
7897
|
-
|
|
9770
|
+
el.focus({ preventScroll: true });
|
|
9771
|
+
if (preservedRange) {
|
|
9772
|
+
const selection = window.getSelection();
|
|
9773
|
+
selection?.removeAllRanges();
|
|
9774
|
+
selection?.addRange(preservedRange);
|
|
9775
|
+
} else if (options?.caretX !== void 0 && options?.caretY !== void 0) {
|
|
9776
|
+
const { caretX, caretY } = options;
|
|
9777
|
+
placeCaretAtPoint(el, caretX, caretY);
|
|
9778
|
+
requestAnimationFrame(() => {
|
|
9779
|
+
if (activeElRef.current === el) placeCaretAtPoint(el, caretX, caretY);
|
|
9780
|
+
});
|
|
9781
|
+
} else {
|
|
9782
|
+
const selection = window.getSelection();
|
|
9783
|
+
if (selection && selection.rangeCount === 0) {
|
|
9784
|
+
const range = document.createRange();
|
|
9785
|
+
range.selectNodeContents(el);
|
|
9786
|
+
range.collapse(false);
|
|
9787
|
+
selection.removeAllRanges();
|
|
9788
|
+
selection.addRange(range);
|
|
9789
|
+
}
|
|
7898
9790
|
}
|
|
7899
9791
|
setToolbarShowEditLink(Boolean(getHrefKeyFromElement(el)));
|
|
7900
9792
|
const navAnchor = getNavigationItemAnchor(el);
|
|
@@ -7909,13 +9801,13 @@ function OhhwellsBridge() {
|
|
|
7909
9801
|
setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
|
|
7910
9802
|
postToParent2({ type: "ow:enter-edit", key: el.dataset.ohwKey });
|
|
7911
9803
|
requestAnimationFrame(() => refreshActiveCommandsRef.current());
|
|
7912
|
-
}, [deactivate, postToParent2]);
|
|
9804
|
+
}, [clearSelectedAttr, deactivate, postToParent2]);
|
|
7913
9805
|
activateRef.current = activate;
|
|
7914
9806
|
deactivateRef.current = deactivate;
|
|
7915
9807
|
selectRef.current = select;
|
|
7916
9808
|
selectFrameRef.current = selectFrame;
|
|
7917
9809
|
deselectRef.current = deselect;
|
|
7918
|
-
(0,
|
|
9810
|
+
(0, import_react9.useLayoutEffect)(() => {
|
|
7919
9811
|
if (!subdomain || isEditMode) {
|
|
7920
9812
|
setFetchState("done");
|
|
7921
9813
|
return;
|
|
@@ -7956,6 +9848,7 @@ function OhhwellsBridge() {
|
|
|
7956
9848
|
applyLinkByKey(key, val);
|
|
7957
9849
|
}
|
|
7958
9850
|
reconcileNavbarItemsFromContent(content);
|
|
9851
|
+
reconcileFooterOrderFromContent(content);
|
|
7959
9852
|
enforceLinkHrefs();
|
|
7960
9853
|
initSectionsFromContent(content, true);
|
|
7961
9854
|
sectionsLoadedRef.current = true;
|
|
@@ -7984,7 +9877,7 @@ function OhhwellsBridge() {
|
|
|
7984
9877
|
cancelled = true;
|
|
7985
9878
|
};
|
|
7986
9879
|
}, [subdomain, isEditMode]);
|
|
7987
|
-
(0,
|
|
9880
|
+
(0, import_react9.useEffect)(() => {
|
|
7988
9881
|
if (!subdomain || isEditMode) return;
|
|
7989
9882
|
let debounceTimer = null;
|
|
7990
9883
|
let observer = null;
|
|
@@ -8016,6 +9909,7 @@ function OhhwellsBridge() {
|
|
|
8016
9909
|
applyLinkByKey(key, val);
|
|
8017
9910
|
}
|
|
8018
9911
|
reconcileNavbarItemsFromContent(content);
|
|
9912
|
+
reconcileFooterOrderFromContent(content);
|
|
8019
9913
|
} finally {
|
|
8020
9914
|
observer?.observe(document.body, { childList: true, subtree: true });
|
|
8021
9915
|
}
|
|
@@ -8033,16 +9927,16 @@ function OhhwellsBridge() {
|
|
|
8033
9927
|
if (debounceTimer) clearTimeout(debounceTimer);
|
|
8034
9928
|
};
|
|
8035
9929
|
}, [subdomain, isEditMode, pathname]);
|
|
8036
|
-
(0,
|
|
9930
|
+
(0, import_react9.useLayoutEffect)(() => {
|
|
8037
9931
|
const el = document.getElementById("ohw-loader");
|
|
8038
9932
|
if (!el) return;
|
|
8039
9933
|
const visible = Boolean(subdomain) && fetchState !== "done";
|
|
8040
9934
|
el.style.display = visible ? "flex" : "none";
|
|
8041
9935
|
}, [subdomain, fetchState]);
|
|
8042
|
-
(0,
|
|
9936
|
+
(0, import_react9.useEffect)(() => {
|
|
8043
9937
|
postToParent2({ type: "ow:navigation", path: pathname });
|
|
8044
9938
|
}, [pathname, postToParent2]);
|
|
8045
|
-
(0,
|
|
9939
|
+
(0, import_react9.useEffect)(() => {
|
|
8046
9940
|
if (!isEditMode) return;
|
|
8047
9941
|
if (linkPopoverSessionRef.current?.intent === "add-nav") return;
|
|
8048
9942
|
if (document.querySelector("[data-ohw-section-picker]")) return;
|
|
@@ -8050,23 +9944,72 @@ function OhhwellsBridge() {
|
|
|
8050
9944
|
deselectRef.current();
|
|
8051
9945
|
deactivateRef.current();
|
|
8052
9946
|
}, [pathname, isEditMode]);
|
|
8053
|
-
(0,
|
|
9947
|
+
(0, import_react9.useEffect)(() => {
|
|
8054
9948
|
const contentForNav = () => {
|
|
8055
9949
|
if (isEditMode) return editContentRef.current;
|
|
8056
9950
|
if (!subdomain) return {};
|
|
8057
9951
|
return contentCache.get(subdomain) ?? {};
|
|
8058
9952
|
};
|
|
8059
|
-
const
|
|
9953
|
+
const observeRoots = () => [document.querySelector("nav"), document.querySelector("footer")].filter(
|
|
9954
|
+
(el) => Boolean(el)
|
|
9955
|
+
);
|
|
9956
|
+
const roots = observeRoots();
|
|
9957
|
+
if (roots.length === 0) {
|
|
9958
|
+
reconcileNavbarItemsFromContent(contentForNav());
|
|
9959
|
+
reconcileFooterOrderFromContent(contentForNav());
|
|
9960
|
+
if (isEditMode) syncNavigationDragCursorAttrs();
|
|
9961
|
+
return;
|
|
9962
|
+
}
|
|
9963
|
+
let rafId = null;
|
|
9964
|
+
let applying = false;
|
|
9965
|
+
let observer = null;
|
|
9966
|
+
const attach = () => {
|
|
9967
|
+
for (const root of observeRoots()) {
|
|
9968
|
+
observer?.observe(root, { childList: true, subtree: true });
|
|
9969
|
+
}
|
|
9970
|
+
};
|
|
9971
|
+
const run = () => {
|
|
9972
|
+
if (footerDragRef.current || navDragRef.current || applying) return;
|
|
9973
|
+
applying = true;
|
|
9974
|
+
observer?.disconnect();
|
|
9975
|
+
try {
|
|
9976
|
+
const content = contentForNav();
|
|
9977
|
+
reconcileNavbarItemsFromContent(content);
|
|
9978
|
+
reconcileFooterOrderFromContent(content);
|
|
9979
|
+
document.querySelectorAll("footer [data-ohw-href-key]").forEach((el) => {
|
|
9980
|
+
if (isFooterHrefKey(el.getAttribute("data-ohw-href-key"))) {
|
|
9981
|
+
disableNativeHrefDrag(el);
|
|
9982
|
+
}
|
|
9983
|
+
});
|
|
9984
|
+
document.querySelectorAll(
|
|
9985
|
+
"nav [data-ohw-href-key], [data-ohw-nav-container] [data-ohw-href-key], [data-ohw-nav-drawer] [data-ohw-href-key]"
|
|
9986
|
+
).forEach((el) => {
|
|
9987
|
+
if (isNavbarHrefKey(el.getAttribute("data-ohw-href-key"))) {
|
|
9988
|
+
disableNativeHrefDrag(el);
|
|
9989
|
+
}
|
|
9990
|
+
});
|
|
9991
|
+
resyncSelectedNavigationItem();
|
|
9992
|
+
if (isEditMode) syncNavigationDragCursorAttrs();
|
|
9993
|
+
} finally {
|
|
9994
|
+
applying = false;
|
|
9995
|
+
attach();
|
|
9996
|
+
}
|
|
9997
|
+
};
|
|
9998
|
+
const schedule = () => {
|
|
9999
|
+
if (applying || rafId != null) return;
|
|
10000
|
+
rafId = requestAnimationFrame(() => {
|
|
10001
|
+
rafId = null;
|
|
10002
|
+
run();
|
|
10003
|
+
});
|
|
10004
|
+
};
|
|
10005
|
+
observer = new MutationObserver(schedule);
|
|
8060
10006
|
run();
|
|
8061
|
-
|
|
8062
|
-
|
|
8063
|
-
|
|
8064
|
-
|
|
8065
|
-
|
|
8066
|
-
|
|
8067
|
-
return () => observer.disconnect();
|
|
8068
|
-
}, [isEditMode, pathname, subdomain, fetchState]);
|
|
8069
|
-
(0, import_react8.useEffect)(() => {
|
|
10007
|
+
return () => {
|
|
10008
|
+
if (rafId != null) cancelAnimationFrame(rafId);
|
|
10009
|
+
observer?.disconnect();
|
|
10010
|
+
};
|
|
10011
|
+
}, [isEditMode, pathname, subdomain, fetchState, resyncSelectedNavigationItem]);
|
|
10012
|
+
(0, import_react9.useEffect)(() => {
|
|
8070
10013
|
if (!isEditMode) return;
|
|
8071
10014
|
const measure = () => {
|
|
8072
10015
|
const h = document.body.scrollHeight;
|
|
@@ -8090,7 +10033,7 @@ function OhhwellsBridge() {
|
|
|
8090
10033
|
window.removeEventListener("resize", handleResize);
|
|
8091
10034
|
};
|
|
8092
10035
|
}, [pathname, isEditMode, postToParent2]);
|
|
8093
|
-
(0,
|
|
10036
|
+
(0, import_react9.useEffect)(() => {
|
|
8094
10037
|
if (!subdomainFromQuery || isEditMode) return;
|
|
8095
10038
|
const handleClick = (e) => {
|
|
8096
10039
|
const anchor = e.target.closest("a");
|
|
@@ -8106,19 +10049,24 @@ function OhhwellsBridge() {
|
|
|
8106
10049
|
document.addEventListener("click", handleClick, true);
|
|
8107
10050
|
return () => document.removeEventListener("click", handleClick, true);
|
|
8108
10051
|
}, [subdomainFromQuery, isEditMode, router]);
|
|
8109
|
-
(0,
|
|
10052
|
+
(0, import_react9.useEffect)(() => {
|
|
8110
10053
|
if (!isEditMode) {
|
|
8111
10054
|
editStylesRef.current?.base.remove();
|
|
8112
10055
|
editStylesRef.current?.forceHover.remove();
|
|
8113
10056
|
editStylesRef.current?.stateViews.remove();
|
|
8114
10057
|
editStylesRef.current = null;
|
|
10058
|
+
document.querySelectorAll("[data-ohw-can-drag]").forEach((el) => {
|
|
10059
|
+
el.removeAttribute("data-ohw-can-drag");
|
|
10060
|
+
});
|
|
8115
10061
|
return;
|
|
8116
10062
|
}
|
|
8117
|
-
|
|
8118
|
-
|
|
8119
|
-
|
|
8120
|
-
base.
|
|
8121
|
-
|
|
10063
|
+
const existing = editStylesRef.current;
|
|
10064
|
+
let initialVh = window.innerHeight;
|
|
10065
|
+
if (existing?.base.textContent) {
|
|
10066
|
+
const match = existing.base.textContent.match(/\.min-h-screen[^{]*\{[^}]*min-height:\s*(\d+)px/);
|
|
10067
|
+
if (match) initialVh = parseInt(match[1], 10);
|
|
10068
|
+
}
|
|
10069
|
+
const baseCss = `
|
|
8122
10070
|
html { height: auto !important; }
|
|
8123
10071
|
body { height: auto !important; min-height: 0 !important; overflow: hidden !important; }
|
|
8124
10072
|
.min-h-screen, .min-h-svh, .min-h-dvh { min-height: ${initialVh}px !important; }
|
|
@@ -8129,7 +10077,25 @@ function OhhwellsBridge() {
|
|
|
8129
10077
|
[data-ohw-editable] {
|
|
8130
10078
|
display: block;
|
|
8131
10079
|
}
|
|
8132
|
-
|
|
10080
|
+
/* Body text (no item-action toolbar) \u2014 first click enters text edit \u2192 I-beam.
|
|
10081
|
+
Exclude select-first nav/footer labels so grab/default on [data-ohw-href-key] can win. */
|
|
10082
|
+
[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] *)) {
|
|
10083
|
+
cursor: text !important;
|
|
10084
|
+
}
|
|
10085
|
+
/* Select-first items: default arrow; grab only when drag-start is allowed (data-ohw-can-drag). */
|
|
10086
|
+
[data-ohw-href-key]:not([data-ohw-selected]),
|
|
10087
|
+
[data-ohw-href-key]:not([data-ohw-selected]) * {
|
|
10088
|
+
cursor: default !important;
|
|
10089
|
+
}
|
|
10090
|
+
[data-ohw-href-key][data-ohw-can-drag]:not([data-ohw-selected]),
|
|
10091
|
+
[data-ohw-href-key][data-ohw-can-drag]:not([data-ohw-selected]) * {
|
|
10092
|
+
cursor: grab !important;
|
|
10093
|
+
}
|
|
10094
|
+
/* Selected (action-toolbar) \u2014 next click enters text edit at caret. */
|
|
10095
|
+
[data-ohw-href-key][data-ohw-selected],
|
|
10096
|
+
[data-ohw-href-key][data-ohw-selected] * {
|
|
10097
|
+
cursor: text !important;
|
|
10098
|
+
}
|
|
8133
10099
|
[data-ohw-editable="image"], [data-ohw-editable="image"] *,
|
|
8134
10100
|
[data-ohw-editable="video"], [data-ohw-editable="video"] *,
|
|
8135
10101
|
[data-ohw-editable="bg-image"], [data-ohw-editable="bg-image"] * { cursor: pointer !important; }
|
|
@@ -8145,9 +10111,32 @@ function OhhwellsBridge() {
|
|
|
8145
10111
|
outline: none !important;
|
|
8146
10112
|
outline-offset: 0 !important;
|
|
8147
10113
|
}
|
|
8148
|
-
|
|
10114
|
+
/* Editor chrome owns selection \u2014 suppress native focus rings on nav/footer items. */
|
|
10115
|
+
nav [data-ohw-href-key]:focus,
|
|
10116
|
+
nav [data-ohw-href-key]:focus-visible,
|
|
10117
|
+
nav [data-ohw-href-key]:focus-within,
|
|
10118
|
+
footer [data-ohw-href-key]:focus,
|
|
10119
|
+
footer [data-ohw-href-key]:focus-visible,
|
|
10120
|
+
footer [data-ohw-href-key]:focus-within,
|
|
10121
|
+
nav [data-ohw-href-key] [data-ohw-editable]:focus,
|
|
10122
|
+
nav [data-ohw-href-key] [data-ohw-editable]:focus-visible,
|
|
10123
|
+
footer [data-ohw-href-key] [data-ohw-editable]:focus,
|
|
10124
|
+
footer [data-ohw-href-key] [data-ohw-editable]:focus-visible {
|
|
10125
|
+
outline: none !important;
|
|
10126
|
+
outline-offset: 0 !important;
|
|
10127
|
+
box-shadow: none !important;
|
|
10128
|
+
}
|
|
10129
|
+
/* Text edit wins over grab/default (must beat [data-ohw-can-drag] *). */
|
|
10130
|
+
[data-ohw-editing],
|
|
10131
|
+
[data-ohw-editing] *,
|
|
10132
|
+
[data-ohw-editable][contenteditable],
|
|
10133
|
+
[data-ohw-editable][contenteditable] *,
|
|
10134
|
+
nav [data-ohw-href-key] [data-ohw-editable][contenteditable],
|
|
10135
|
+
nav [data-ohw-href-key] [data-ohw-editable][contenteditable] *,
|
|
10136
|
+
footer [data-ohw-href-key] [data-ohw-editable][contenteditable],
|
|
10137
|
+
footer [data-ohw-href-key] [data-ohw-editable][contenteditable] * {
|
|
8149
10138
|
outline: none !important;
|
|
8150
|
-
caret-color: ${PRIMARY2};
|
|
10139
|
+
caret-color: ${PRIMARY2} !important;
|
|
8151
10140
|
cursor: text !important;
|
|
8152
10141
|
}
|
|
8153
10142
|
[data-ohw-editable][contenteditable]::selection,
|
|
@@ -8156,6 +10145,9 @@ function OhhwellsBridge() {
|
|
|
8156
10145
|
[data-ohw-editable-state][data-ohw-active-state] [data-ohw-editable] { pointer-events: auto !important; }
|
|
8157
10146
|
[data-ohw-editable-state][data-ohw-active-state][data-ohw-editable] { pointer-events: auto !important; }
|
|
8158
10147
|
`;
|
|
10148
|
+
if (!existing) {
|
|
10149
|
+
const base = document.createElement("style");
|
|
10150
|
+
base.setAttribute("data-ohw-edit-style", "");
|
|
8159
10151
|
const forceHover = document.createElement("style");
|
|
8160
10152
|
forceHover.setAttribute("data-ohw-active-state-style", "");
|
|
8161
10153
|
const stateViews = document.createElement("style");
|
|
@@ -8171,14 +10163,43 @@ function OhhwellsBridge() {
|
|
|
8171
10163
|
document.head.appendChild(stateViews);
|
|
8172
10164
|
editStylesRef.current = { base, forceHover, stateViews };
|
|
8173
10165
|
}
|
|
10166
|
+
editStylesRef.current.base.textContent = baseCss;
|
|
10167
|
+
syncNavigationDragCursorAttrs();
|
|
8174
10168
|
refreshStateRules();
|
|
8175
10169
|
const handleClick = (e) => {
|
|
10170
|
+
if (suppressNextClickRef.current || Date.now() < suppressClickUntilRef.current) {
|
|
10171
|
+
suppressNextClickRef.current = false;
|
|
10172
|
+
e.preventDefault();
|
|
10173
|
+
e.stopPropagation();
|
|
10174
|
+
return;
|
|
10175
|
+
}
|
|
8176
10176
|
const target = e.target;
|
|
8177
10177
|
if (target.closest("[data-ohw-toolbar]")) return;
|
|
8178
10178
|
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
8179
10179
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
8180
10180
|
if (isInsideLinkEditor(target)) return;
|
|
8181
10181
|
if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
|
|
10182
|
+
if (target.closest("[data-ohw-item-drag-surface]")) {
|
|
10183
|
+
e.preventDefault();
|
|
10184
|
+
e.stopPropagation();
|
|
10185
|
+
const selected = selectedElRef.current;
|
|
10186
|
+
if (selected && isNavigationItem(selected)) {
|
|
10187
|
+
const editable2 = selected.querySelector('[data-ohw-editable="text"]') ?? selected.querySelector("[data-ohw-editable]");
|
|
10188
|
+
if (editable2) {
|
|
10189
|
+
activateRef.current(editable2, {
|
|
10190
|
+
caretX: e.clientX,
|
|
10191
|
+
caretY: e.clientY
|
|
10192
|
+
});
|
|
10193
|
+
}
|
|
10194
|
+
} else if (selected?.hasAttribute("data-ohw-footer-col")) {
|
|
10195
|
+
const link = listFooterLinksInColumn(selected).find((el) => {
|
|
10196
|
+
const r2 = el.getBoundingClientRect();
|
|
10197
|
+
return e.clientX >= r2.left && e.clientX <= r2.right && e.clientY >= r2.top && e.clientY <= r2.bottom;
|
|
10198
|
+
});
|
|
10199
|
+
if (link) selectRef.current(link);
|
|
10200
|
+
}
|
|
10201
|
+
return;
|
|
10202
|
+
}
|
|
8182
10203
|
const navFromChrome = resolveNavContainerSelectionTarget(target, e.clientX, e.clientY);
|
|
8183
10204
|
if (navFromChrome) {
|
|
8184
10205
|
e.preventDefault();
|
|
@@ -8186,10 +10207,45 @@ function OhhwellsBridge() {
|
|
|
8186
10207
|
selectFrameRef.current(navFromChrome);
|
|
8187
10208
|
return;
|
|
8188
10209
|
}
|
|
10210
|
+
const footerFromChrome = resolveFooterColumnSelectionTarget(target, e.clientX, e.clientY);
|
|
10211
|
+
if (footerFromChrome) {
|
|
10212
|
+
e.preventDefault();
|
|
10213
|
+
e.stopPropagation();
|
|
10214
|
+
selectFrameRef.current(footerFromChrome);
|
|
10215
|
+
return;
|
|
10216
|
+
}
|
|
8189
10217
|
e.preventDefault();
|
|
8190
10218
|
e.stopPropagation();
|
|
8191
10219
|
return;
|
|
8192
10220
|
}
|
|
10221
|
+
if (activeElRef.current) {
|
|
10222
|
+
const active = activeElRef.current;
|
|
10223
|
+
const inActive = active === target || active.contains(target);
|
|
10224
|
+
const navAnchor = getNavigationItemAnchor(active);
|
|
10225
|
+
const inActiveNav = Boolean(
|
|
10226
|
+
navAnchor && (navAnchor === target || navAnchor.contains(target))
|
|
10227
|
+
);
|
|
10228
|
+
if (inActive || inActiveNav) {
|
|
10229
|
+
e.preventDefault();
|
|
10230
|
+
e.stopPropagation();
|
|
10231
|
+
const selection = window.getSelection();
|
|
10232
|
+
const hasRangeSelection = Boolean(selection && !selection.isCollapsed);
|
|
10233
|
+
console.log(
|
|
10234
|
+
"[OHW DEBUG handleClick] already-active branch",
|
|
10235
|
+
"detail=",
|
|
10236
|
+
e.detail,
|
|
10237
|
+
"hasRangeSelection=",
|
|
10238
|
+
hasRangeSelection,
|
|
10239
|
+
"willPlaceCaret=",
|
|
10240
|
+
e.detail < 2 && !hasRangeSelection
|
|
10241
|
+
);
|
|
10242
|
+
if (e.detail < 2 && !hasRangeSelection) {
|
|
10243
|
+
placeCaretAtPoint(active, e.clientX, e.clientY);
|
|
10244
|
+
refreshActiveCommandsRef.current();
|
|
10245
|
+
}
|
|
10246
|
+
return;
|
|
10247
|
+
}
|
|
10248
|
+
}
|
|
8193
10249
|
const editable = target.closest("[data-ohw-editable]");
|
|
8194
10250
|
if (editable) {
|
|
8195
10251
|
if (editable.dataset.ohwEditable === "link") {
|
|
@@ -8217,6 +10273,7 @@ function OhhwellsBridge() {
|
|
|
8217
10273
|
e.preventDefault();
|
|
8218
10274
|
e.stopPropagation();
|
|
8219
10275
|
if (selectedElRef.current === navAnchor) {
|
|
10276
|
+
if (e.detail >= 2) return;
|
|
8220
10277
|
activateRef.current(editable, { caretX: e.clientX, caretY: e.clientY });
|
|
8221
10278
|
return;
|
|
8222
10279
|
}
|
|
@@ -8225,6 +10282,15 @@ function OhhwellsBridge() {
|
|
|
8225
10282
|
}
|
|
8226
10283
|
e.preventDefault();
|
|
8227
10284
|
e.stopPropagation();
|
|
10285
|
+
console.log(
|
|
10286
|
+
"[OHW DEBUG handleClick] first-activation branch",
|
|
10287
|
+
"detail=",
|
|
10288
|
+
e.detail,
|
|
10289
|
+
"selectionAtClick=",
|
|
10290
|
+
JSON.stringify(window.getSelection()?.toString() ?? ""),
|
|
10291
|
+
"collapsedAtClick=",
|
|
10292
|
+
window.getSelection()?.isCollapsed
|
|
10293
|
+
);
|
|
8228
10294
|
activateRef.current(editable);
|
|
8229
10295
|
return;
|
|
8230
10296
|
}
|
|
@@ -8232,10 +10298,26 @@ function OhhwellsBridge() {
|
|
|
8232
10298
|
if (hrefAnchor) {
|
|
8233
10299
|
e.preventDefault();
|
|
8234
10300
|
e.stopPropagation();
|
|
8235
|
-
if (selectedElRef.current === hrefAnchor)
|
|
10301
|
+
if (selectedElRef.current === hrefAnchor) {
|
|
10302
|
+
const textEditable = hrefAnchor.querySelector('[data-ohw-editable="text"]') ?? hrefAnchor.querySelector("[data-ohw-editable]");
|
|
10303
|
+
if (textEditable) {
|
|
10304
|
+
activateRef.current(textEditable, {
|
|
10305
|
+
caretX: e.clientX,
|
|
10306
|
+
caretY: e.clientY
|
|
10307
|
+
});
|
|
10308
|
+
}
|
|
10309
|
+
return;
|
|
10310
|
+
}
|
|
8236
10311
|
selectRef.current(hrefAnchor);
|
|
8237
10312
|
return;
|
|
8238
10313
|
}
|
|
10314
|
+
const footerColClick = target.closest("[data-ohw-footer-col]");
|
|
10315
|
+
if (footerColClick) {
|
|
10316
|
+
e.preventDefault();
|
|
10317
|
+
e.stopPropagation();
|
|
10318
|
+
selectFrameRef.current(footerColClick);
|
|
10319
|
+
return;
|
|
10320
|
+
}
|
|
8239
10321
|
const navContainerToSelect = resolveNavContainerSelectionTarget(target, e.clientX, e.clientY);
|
|
8240
10322
|
if (navContainerToSelect) {
|
|
8241
10323
|
e.preventDefault();
|
|
@@ -8243,6 +10325,13 @@ function OhhwellsBridge() {
|
|
|
8243
10325
|
selectFrameRef.current(navContainerToSelect);
|
|
8244
10326
|
return;
|
|
8245
10327
|
}
|
|
10328
|
+
const footerColumnToSelect = resolveFooterColumnSelectionTarget(target, e.clientX, e.clientY);
|
|
10329
|
+
if (footerColumnToSelect) {
|
|
10330
|
+
e.preventDefault();
|
|
10331
|
+
e.stopPropagation();
|
|
10332
|
+
selectFrameRef.current(footerColumnToSelect);
|
|
10333
|
+
return;
|
|
10334
|
+
}
|
|
8246
10335
|
const selectedContainer = selectedElRef.current;
|
|
8247
10336
|
if (selectedContainer && isNavigationContainer(selectedContainer)) {
|
|
8248
10337
|
const navItem = getNavigationItemAnchor(target);
|
|
@@ -8277,9 +10366,38 @@ function OhhwellsBridge() {
|
|
|
8277
10366
|
deselectRef.current();
|
|
8278
10367
|
deactivateRef.current();
|
|
8279
10368
|
};
|
|
10369
|
+
const handleDblClick = (e) => {
|
|
10370
|
+
const target = e.target;
|
|
10371
|
+
if (target.closest("[data-ohw-toolbar]")) return;
|
|
10372
|
+
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
10373
|
+
if (target.closest("[data-ohw-max-badge]")) return;
|
|
10374
|
+
if (isInsideLinkEditor(target)) return;
|
|
10375
|
+
if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
|
|
10376
|
+
return;
|
|
10377
|
+
}
|
|
10378
|
+
const navLabel = getNavigationLabelEditable(target);
|
|
10379
|
+
if (!navLabel) return;
|
|
10380
|
+
const { editable } = navLabel;
|
|
10381
|
+
e.preventDefault();
|
|
10382
|
+
e.stopPropagation();
|
|
10383
|
+
if (activeElRef.current !== editable) {
|
|
10384
|
+
activateRef.current(editable);
|
|
10385
|
+
}
|
|
10386
|
+
requestAnimationFrame(() => {
|
|
10387
|
+
selectAllTextInEditable(editable);
|
|
10388
|
+
refreshActiveCommandsRef.current();
|
|
10389
|
+
});
|
|
10390
|
+
};
|
|
8280
10391
|
const handleMouseOver = (e) => {
|
|
8281
10392
|
if (document.documentElement.hasAttribute("data-ohw-section-picking")) return;
|
|
8282
10393
|
const target = e.target;
|
|
10394
|
+
if (linkPopoverOpenRef.current) {
|
|
10395
|
+
hoveredItemElRef.current = null;
|
|
10396
|
+
setHoveredItemRect(null);
|
|
10397
|
+
hoveredNavContainerRef.current = null;
|
|
10398
|
+
setHoveredNavContainerRect(null);
|
|
10399
|
+
return;
|
|
10400
|
+
}
|
|
8283
10401
|
if (toolbarVariantRef.current !== "select-frame") {
|
|
8284
10402
|
const navContainer = target.closest("[data-ohw-nav-container]");
|
|
8285
10403
|
if (navContainer && !getNavigationItemAnchor(target)) {
|
|
@@ -8299,12 +10417,21 @@ function OhhwellsBridge() {
|
|
|
8299
10417
|
hoveredNavContainerRef.current = null;
|
|
8300
10418
|
setHoveredNavContainerRect(null);
|
|
8301
10419
|
const selected2 = selectedElRef.current;
|
|
8302
|
-
if (selected2 === navAnchor
|
|
10420
|
+
if (selected2 === navAnchor) return;
|
|
8303
10421
|
clearHrefKeyHover(navAnchor);
|
|
8304
10422
|
hoveredItemElRef.current = navAnchor;
|
|
8305
10423
|
setHoveredItemRect(navAnchor.getBoundingClientRect());
|
|
8306
10424
|
return;
|
|
8307
10425
|
}
|
|
10426
|
+
const footerCol = target.closest("[data-ohw-footer-col]") ?? target.closest("[data-ohw-footer-column]");
|
|
10427
|
+
if (footerCol) {
|
|
10428
|
+
hoveredNavContainerRef.current = null;
|
|
10429
|
+
setHoveredNavContainerRect(null);
|
|
10430
|
+
if (selectedElRef.current === footerCol) return;
|
|
10431
|
+
hoveredItemElRef.current = footerCol;
|
|
10432
|
+
setHoveredItemRect(footerCol.getBoundingClientRect());
|
|
10433
|
+
return;
|
|
10434
|
+
}
|
|
8308
10435
|
const editable = target.closest("[data-ohw-editable]");
|
|
8309
10436
|
if (!editable) return;
|
|
8310
10437
|
const selected = selectedElRef.current;
|
|
@@ -8322,14 +10449,25 @@ function OhhwellsBridge() {
|
|
|
8322
10449
|
};
|
|
8323
10450
|
const handleMouseOut = (e) => {
|
|
8324
10451
|
const target = e.target;
|
|
8325
|
-
if (target.closest("[data-ohw-nav-container]")) {
|
|
10452
|
+
if (target.closest("[data-ohw-nav-container], [data-ohw-footer-col], [data-ohw-footer-column]")) {
|
|
8326
10453
|
const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
8327
|
-
if (related2?.closest("[data-ohw-nav-container], [data-ohw-navbar-container-chrome], [data-ohw-navbar-add-button]")) {
|
|
10454
|
+
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]")) {
|
|
8328
10455
|
return;
|
|
8329
10456
|
}
|
|
8330
10457
|
hoveredNavContainerRef.current = null;
|
|
8331
10458
|
setHoveredNavContainerRect(null);
|
|
8332
10459
|
}
|
|
10460
|
+
const footerCol = target.closest("[data-ohw-footer-col]") ?? target.closest("[data-ohw-footer-column]");
|
|
10461
|
+
if (footerCol && hoveredItemElRef.current === footerCol) {
|
|
10462
|
+
const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
10463
|
+
if (related2?.closest("[data-ohw-drag-handle-container], [data-ohw-item-interaction]")) return;
|
|
10464
|
+
if (related2?.closest("[data-ohw-footer-col], [data-ohw-footer-column]") === footerCol) {
|
|
10465
|
+
return;
|
|
10466
|
+
}
|
|
10467
|
+
hoveredItemElRef.current = null;
|
|
10468
|
+
setHoveredItemRect(null);
|
|
10469
|
+
return;
|
|
10470
|
+
}
|
|
8333
10471
|
const navAnchor = getNavigationItemAnchor(target);
|
|
8334
10472
|
if (navAnchor) {
|
|
8335
10473
|
const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
@@ -8463,43 +10601,75 @@ function OhhwellsBridge() {
|
|
|
8463
10601
|
if (toolbarVariantRef.current === "select-frame") {
|
|
8464
10602
|
hoveredNavContainerRef.current = null;
|
|
8465
10603
|
setHoveredNavContainerRect(null);
|
|
8466
|
-
return;
|
|
8467
10604
|
}
|
|
8468
|
-
const
|
|
8469
|
-
|
|
8470
|
-
|
|
8471
|
-
|
|
8472
|
-
|
|
10605
|
+
const navContainers = Array.from(
|
|
10606
|
+
document.querySelectorAll("[data-ohw-nav-container]")
|
|
10607
|
+
);
|
|
10608
|
+
const footerColumns = listFooterColumns();
|
|
10609
|
+
for (const container of [...navContainers, ...footerColumns]) {
|
|
10610
|
+
const containerRect = container.getBoundingClientRect();
|
|
10611
|
+
const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
|
|
10612
|
+
if (!overContainer) continue;
|
|
10613
|
+
const navItemHit = Array.from(
|
|
10614
|
+
container.querySelectorAll("[data-ohw-href-key]")
|
|
10615
|
+
).find((el) => {
|
|
10616
|
+
if (!isNavigationItem(el) || isNavbarButton2(el)) return false;
|
|
10617
|
+
const itemRect = el.getBoundingClientRect();
|
|
10618
|
+
return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
|
|
10619
|
+
});
|
|
10620
|
+
if (navItemHit) {
|
|
10621
|
+
hoveredNavContainerRef.current = null;
|
|
10622
|
+
setHoveredNavContainerRect(null);
|
|
10623
|
+
const selected = selectedElRef.current;
|
|
10624
|
+
if (selected !== navItemHit) {
|
|
10625
|
+
clearHrefKeyHover(navItemHit);
|
|
10626
|
+
hoveredItemElRef.current = navItemHit;
|
|
10627
|
+
setHoveredItemRect(navItemHit.getBoundingClientRect());
|
|
10628
|
+
} else if (hoveredItemElRef.current === navItemHit) {
|
|
10629
|
+
hoveredItemElRef.current = null;
|
|
10630
|
+
setHoveredItemRect(null);
|
|
10631
|
+
}
|
|
10632
|
+
return;
|
|
10633
|
+
}
|
|
8473
10634
|
}
|
|
8474
|
-
|
|
8475
|
-
|
|
8476
|
-
|
|
10635
|
+
if (toolbarVariantRef.current !== "select-frame") {
|
|
10636
|
+
for (const container of navContainers) {
|
|
10637
|
+
const containerRect = container.getBoundingClientRect();
|
|
10638
|
+
const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
|
|
10639
|
+
if (!overContainer) continue;
|
|
10640
|
+
if (isPointOverNavItem(container, x, y)) continue;
|
|
10641
|
+
hoveredNavContainerRef.current = container;
|
|
10642
|
+
setHoveredNavContainerRect(container.getBoundingClientRect());
|
|
10643
|
+
hoveredItemElRef.current = null;
|
|
10644
|
+
setHoveredItemRect(null);
|
|
10645
|
+
return;
|
|
10646
|
+
}
|
|
8477
10647
|
hoveredNavContainerRef.current = null;
|
|
8478
10648
|
setHoveredNavContainerRect(null);
|
|
8479
|
-
|
|
8480
|
-
}
|
|
8481
|
-
const navItemHit = Array.from(
|
|
8482
|
-
navContainer.querySelectorAll("[data-ohw-href-key]")
|
|
8483
|
-
).find((el) => {
|
|
8484
|
-
if (!isNavigationItem(el) || isNavbarButton2(el)) return false;
|
|
8485
|
-
const itemRect = el.getBoundingClientRect();
|
|
8486
|
-
return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
|
|
8487
|
-
});
|
|
8488
|
-
if (navItemHit) {
|
|
10649
|
+
} else {
|
|
8489
10650
|
hoveredNavContainerRef.current = null;
|
|
8490
10651
|
setHoveredNavContainerRect(null);
|
|
8491
|
-
|
|
8492
|
-
|
|
8493
|
-
|
|
8494
|
-
|
|
8495
|
-
|
|
10652
|
+
}
|
|
10653
|
+
for (const column of footerColumns) {
|
|
10654
|
+
const containerRect = column.getBoundingClientRect();
|
|
10655
|
+
const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
|
|
10656
|
+
if (!overContainer) continue;
|
|
10657
|
+
if (isPointOverNavItem(column, x, y)) continue;
|
|
10658
|
+
if (selectedElRef.current === column) {
|
|
10659
|
+
if (hoveredItemElRef.current === column) {
|
|
10660
|
+
hoveredItemElRef.current = null;
|
|
10661
|
+
setHoveredItemRect(null);
|
|
10662
|
+
}
|
|
10663
|
+
return;
|
|
8496
10664
|
}
|
|
10665
|
+
hoveredItemElRef.current = column;
|
|
10666
|
+
setHoveredItemRect(column.getBoundingClientRect());
|
|
8497
10667
|
return;
|
|
8498
10668
|
}
|
|
8499
|
-
|
|
8500
|
-
|
|
8501
|
-
|
|
8502
|
-
|
|
10669
|
+
if (hoveredItemElRef.current?.hasAttribute("data-ohw-footer-col") || hoveredItemElRef.current?.hasAttribute("data-ohw-footer-column")) {
|
|
10670
|
+
hoveredItemElRef.current = null;
|
|
10671
|
+
setHoveredItemRect(null);
|
|
10672
|
+
}
|
|
8503
10673
|
};
|
|
8504
10674
|
const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
|
|
8505
10675
|
if (linkPopoverOpenRef.current) {
|
|
@@ -8520,6 +10690,10 @@ function OhhwellsBridge() {
|
|
|
8520
10690
|
}
|
|
8521
10691
|
hoveredNavContainerRef.current = null;
|
|
8522
10692
|
setHoveredNavContainerRect(null);
|
|
10693
|
+
if (hoveredItemElRef.current?.hasAttribute("data-ohw-footer-col") || hoveredItemElRef.current?.hasAttribute("data-ohw-footer-column")) {
|
|
10694
|
+
hoveredItemElRef.current = null;
|
|
10695
|
+
setHoveredItemRect(null);
|
|
10696
|
+
}
|
|
8523
10697
|
const toggleEl = document.querySelector("[data-ohw-state-toggle]");
|
|
8524
10698
|
if (toggleEl) {
|
|
8525
10699
|
const tr = toggleEl.getBoundingClientRect();
|
|
@@ -8767,6 +10941,15 @@ function OhhwellsBridge() {
|
|
|
8767
10941
|
probeHoverCardsAt(clientX, clientY);
|
|
8768
10942
|
};
|
|
8769
10943
|
const handleDragOver = (e) => {
|
|
10944
|
+
const footerSession = footerDragRef.current;
|
|
10945
|
+
if (footerSession) {
|
|
10946
|
+
e.preventDefault();
|
|
10947
|
+
if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
|
|
10948
|
+
const slot = footerSession.kind === "link" && footerSession.hrefKey ? hitTestLinkDropSlot(e.clientX, e.clientY, footerSession.hrefKey) : hitTestColumnDropSlot(e.clientX, e.clientY);
|
|
10949
|
+
refreshFooterDragVisualsRef.current(footerSession, slot, e.clientX, e.clientY);
|
|
10950
|
+
return;
|
|
10951
|
+
}
|
|
10952
|
+
if (onNavDragOver(e)) return;
|
|
8770
10953
|
e.preventDefault();
|
|
8771
10954
|
const el = findImageAtPoint(e.clientX, e.clientY, false);
|
|
8772
10955
|
if (!el) {
|
|
@@ -8929,8 +11112,8 @@ function OhhwellsBridge() {
|
|
|
8929
11112
|
if (sibling !== el) sibling.innerHTML = html;
|
|
8930
11113
|
});
|
|
8931
11114
|
const timers = autoSaveTimers.current;
|
|
8932
|
-
const
|
|
8933
|
-
if (
|
|
11115
|
+
const existing2 = timers.get(key);
|
|
11116
|
+
if (existing2) clearTimeout(existing2);
|
|
8934
11117
|
timers.set(key, setTimeout(() => {
|
|
8935
11118
|
timers.delete(key);
|
|
8936
11119
|
postToParentRef.current({ type: "ow:change", nodes: [{ key, text: html }] });
|
|
@@ -8973,6 +11156,7 @@ function OhhwellsBridge() {
|
|
|
8973
11156
|
}
|
|
8974
11157
|
editContentRef.current = { ...editContentRef.current, ...content };
|
|
8975
11158
|
reconcileNavbarItemsFromContent(editContentRef.current);
|
|
11159
|
+
syncNavigationDragCursorAttrs();
|
|
8976
11160
|
enforceLinkHrefs();
|
|
8977
11161
|
postToParentRef.current({ type: "ow:hydrate-done" });
|
|
8978
11162
|
};
|
|
@@ -8993,11 +11177,62 @@ function OhhwellsBridge() {
|
|
|
8993
11177
|
if (e.data?.type !== "ui:escape") return;
|
|
8994
11178
|
if (linkPopoverOpenRef.current) {
|
|
8995
11179
|
setLinkPopoverRef.current(null);
|
|
11180
|
+
return;
|
|
11181
|
+
}
|
|
11182
|
+
if (activeElRef.current) {
|
|
11183
|
+
const hrefCtx = getHrefKeyFromElement(activeElRef.current);
|
|
11184
|
+
const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
|
|
11185
|
+
if (navAnchor) {
|
|
11186
|
+
const el = activeElRef.current;
|
|
11187
|
+
if (originalContentRef.current !== null) {
|
|
11188
|
+
el.innerHTML = originalContentRef.current;
|
|
11189
|
+
}
|
|
11190
|
+
el.removeAttribute("contenteditable");
|
|
11191
|
+
el.removeAttribute("data-ohw-editing");
|
|
11192
|
+
activeElRef.current = null;
|
|
11193
|
+
setMaxBadge(null);
|
|
11194
|
+
setActiveCommands(/* @__PURE__ */ new Set());
|
|
11195
|
+
setToolbarShowEditLink(false);
|
|
11196
|
+
postToParentRef.current({ type: "ow:exit-edit" });
|
|
11197
|
+
reselectNavigationItemRef.current(navAnchor);
|
|
11198
|
+
return;
|
|
11199
|
+
}
|
|
11200
|
+
if (originalContentRef.current !== null) {
|
|
11201
|
+
activeElRef.current.innerHTML = originalContentRef.current;
|
|
11202
|
+
const key = activeElRef.current.dataset.ohwKey;
|
|
11203
|
+
if (key) {
|
|
11204
|
+
postToParentRef.current({ type: "ow:change", nodes: [{ key, text: originalContentRef.current }] });
|
|
11205
|
+
}
|
|
11206
|
+
}
|
|
11207
|
+
deselectRef.current();
|
|
11208
|
+
deactivateRef.current();
|
|
11209
|
+
return;
|
|
11210
|
+
}
|
|
11211
|
+
if (selectedElRef.current) {
|
|
11212
|
+
if (toolbarVariantRef.current === "select-frame") {
|
|
11213
|
+
deselectRef.current();
|
|
11214
|
+
return;
|
|
11215
|
+
}
|
|
11216
|
+
const parent = getNavigationSelectionParent(selectedElRef.current);
|
|
11217
|
+
if (parent && isNavigationContainer(parent)) {
|
|
11218
|
+
selectFrameRef.current(parent);
|
|
11219
|
+
} else {
|
|
11220
|
+
deselectRef.current();
|
|
11221
|
+
}
|
|
8996
11222
|
}
|
|
8997
11223
|
};
|
|
8998
11224
|
window.addEventListener("message", handleUiEscape);
|
|
8999
11225
|
const handleKeyDown = (e) => {
|
|
9000
11226
|
if (e.key === "Escape" && document.querySelector("[data-ohw-section-picker]")) return;
|
|
11227
|
+
if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a" && activeElRef.current) {
|
|
11228
|
+
const navAnchor = getNavigationItemAnchor(activeElRef.current);
|
|
11229
|
+
if (navAnchor) {
|
|
11230
|
+
e.preventDefault();
|
|
11231
|
+
selectAllTextInEditable(activeElRef.current);
|
|
11232
|
+
refreshActiveCommandsRef.current();
|
|
11233
|
+
return;
|
|
11234
|
+
}
|
|
11235
|
+
}
|
|
9001
11236
|
if (e.key === "Escape" && linkPopoverOpenRef.current) {
|
|
9002
11237
|
setLinkPopoverRef.current(null);
|
|
9003
11238
|
return;
|
|
@@ -9008,7 +11243,7 @@ function OhhwellsBridge() {
|
|
|
9008
11243
|
return;
|
|
9009
11244
|
}
|
|
9010
11245
|
const parent = getNavigationSelectionParent(selectedElRef.current);
|
|
9011
|
-
if (parent) {
|
|
11246
|
+
if (parent && isNavigationContainer(parent)) {
|
|
9012
11247
|
e.preventDefault();
|
|
9013
11248
|
selectFrameRef.current(parent);
|
|
9014
11249
|
} else {
|
|
@@ -9026,6 +11261,7 @@ function OhhwellsBridge() {
|
|
|
9026
11261
|
el2.innerHTML = originalContentRef.current;
|
|
9027
11262
|
}
|
|
9028
11263
|
el2.removeAttribute("contenteditable");
|
|
11264
|
+
el2.removeAttribute("data-ohw-editing");
|
|
9029
11265
|
activeElRef.current = null;
|
|
9030
11266
|
setMaxBadge(null);
|
|
9031
11267
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
@@ -9077,6 +11313,26 @@ function OhhwellsBridge() {
|
|
|
9077
11313
|
if (siblingHintElRef.current) {
|
|
9078
11314
|
setSiblingHintRect(siblingHintElRef.current.getBoundingClientRect());
|
|
9079
11315
|
}
|
|
11316
|
+
const selected = selectedElRef.current;
|
|
11317
|
+
if (selected && !footerDragRef.current && !navDragRef.current) {
|
|
11318
|
+
if (selected.hasAttribute("data-ohw-footer-col") || Boolean(selected.closest("footer") && isInferredFooterGroup(selected))) {
|
|
11319
|
+
setSiblingHintRects(
|
|
11320
|
+
listFooterColumns().filter((column) => column !== selected).map((column) => column.getBoundingClientRect())
|
|
11321
|
+
);
|
|
11322
|
+
} else if (isNavigationItem(selected)) {
|
|
11323
|
+
setSiblingHintRects(collectNavigationItemSiblingHintRects(selected));
|
|
11324
|
+
}
|
|
11325
|
+
}
|
|
11326
|
+
if (footerDragRef.current) {
|
|
11327
|
+
const session = footerDragRef.current;
|
|
11328
|
+
const slot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : hitTestColumnDropSlot(session.lastClientX, session.lastClientY);
|
|
11329
|
+
refreshFooterDragVisualsRef.current(session, slot, session.lastClientX, session.lastClientY);
|
|
11330
|
+
}
|
|
11331
|
+
if (navDragRef.current) {
|
|
11332
|
+
const session = navDragRef.current;
|
|
11333
|
+
const slot = hitTestNavDropSlot(session.lastClientX, session.lastClientY, session.hrefKey);
|
|
11334
|
+
refreshNavDragVisualsRef.current(session, slot, session.lastClientX, session.lastClientY);
|
|
11335
|
+
}
|
|
9080
11336
|
if (hoveredImageRef.current) {
|
|
9081
11337
|
const el = hoveredImageRef.current;
|
|
9082
11338
|
const r2 = el.getBoundingClientRect();
|
|
@@ -9087,7 +11343,7 @@ function OhhwellsBridge() {
|
|
|
9087
11343
|
};
|
|
9088
11344
|
const handleSave = (e) => {
|
|
9089
11345
|
if (e.data?.type !== "ow:save") return;
|
|
9090
|
-
const nodes = collectEditableNodes();
|
|
11346
|
+
const nodes = collectEditableNodes(editContentRef.current);
|
|
9091
11347
|
const tracker = document.querySelector("[data-ohw-sections-tracker]");
|
|
9092
11348
|
if (tracker?.textContent) nodes.push({ key: "__ohw_sections", type: "sections", text: tracker.textContent });
|
|
9093
11349
|
postToParentRef.current({ type: "ow:save-result", nodes });
|
|
@@ -9145,30 +11401,83 @@ function OhhwellsBridge() {
|
|
|
9145
11401
|
const h = document.documentElement.scrollHeight;
|
|
9146
11402
|
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
9147
11403
|
};
|
|
9148
|
-
|
|
9149
|
-
|
|
11404
|
+
let selectionChangeRaf = null;
|
|
11405
|
+
const runSelectionChange = () => {
|
|
11406
|
+
selectionChangeRaf = null;
|
|
11407
|
+
const activeRoot = activeElRef.current;
|
|
11408
|
+
if (!activeRoot) return;
|
|
9150
11409
|
const next = /* @__PURE__ */ new Set();
|
|
9151
|
-
|
|
9152
|
-
|
|
9153
|
-
|
|
9154
|
-
|
|
11410
|
+
const sel = window.getSelection();
|
|
11411
|
+
let startNode = null;
|
|
11412
|
+
if (sel && sel.rangeCount > 0) {
|
|
11413
|
+
const range = sel.getRangeAt(0);
|
|
11414
|
+
startNode = range.startContainer;
|
|
11415
|
+
if (startNode.nodeType === Node.ELEMENT_NODE) {
|
|
11416
|
+
const el = startNode;
|
|
11417
|
+
startNode = el.childNodes[range.startOffset] ?? el.childNodes[range.startOffset - 1] ?? el;
|
|
9155
11418
|
}
|
|
9156
11419
|
}
|
|
9157
|
-
const
|
|
9158
|
-
|
|
9159
|
-
|
|
9160
|
-
const
|
|
9161
|
-
|
|
9162
|
-
|
|
9163
|
-
|
|
9164
|
-
|
|
9165
|
-
|
|
9166
|
-
|
|
11420
|
+
const startEl = startNode ? startNode.nodeType === Node.TEXT_NODE ? startNode.parentElement : startNode : null;
|
|
11421
|
+
if (startEl) {
|
|
11422
|
+
const cs = getComputedStyle(startEl);
|
|
11423
|
+
const weight = parseInt(cs.fontWeight, 10);
|
|
11424
|
+
let hasBold = cs.fontWeight === "bold" || !Number.isNaN(weight) && weight >= 600;
|
|
11425
|
+
let hasItalic = cs.fontStyle === "italic" || cs.fontStyle === "oblique";
|
|
11426
|
+
let hasUnderline = false;
|
|
11427
|
+
let hasStrike = false;
|
|
11428
|
+
let hasUl = false;
|
|
11429
|
+
let hasOl = false;
|
|
11430
|
+
for (let el = startEl; el; el = el.parentElement) {
|
|
11431
|
+
if (el.tagName === "B" || el.tagName === "STRONG") hasBold = true;
|
|
11432
|
+
if (el.tagName === "I" || el.tagName === "EM") hasItalic = true;
|
|
11433
|
+
const decoration = getComputedStyle(el).textDecorationLine;
|
|
11434
|
+
if (decoration.includes("underline") || el.tagName === "U" || el.tagName === "INS") hasUnderline = true;
|
|
11435
|
+
if (decoration.includes("line-through") || el.tagName === "S" || el.tagName === "STRIKE" || el.tagName === "DEL") hasStrike = true;
|
|
11436
|
+
if (el.tagName === "UL") hasUl = true;
|
|
11437
|
+
if (el.tagName === "OL") hasOl = true;
|
|
11438
|
+
if (el === activeRoot) break;
|
|
9167
11439
|
}
|
|
11440
|
+
if (hasBold) next.add("bold");
|
|
11441
|
+
if (hasItalic) next.add("italic");
|
|
11442
|
+
if (hasUnderline) next.add("underline");
|
|
11443
|
+
if (hasStrike) next.add("strikeThrough");
|
|
11444
|
+
if (hasUl) next.add("insertUnorderedList");
|
|
11445
|
+
if (hasOl) next.add("insertOrderedList");
|
|
11446
|
+
const block = startEl.closest("div, p, h1, h2, h3, h4, h5, h6, li, td, th") ?? startEl;
|
|
11447
|
+
const align = getComputedStyle(block).textAlign;
|
|
11448
|
+
if (align === "center") next.add("justifyCenter");
|
|
11449
|
+
else if (align === "right" || align === "end") next.add("justifyRight");
|
|
11450
|
+
else next.add("justifyLeft");
|
|
9168
11451
|
}
|
|
9169
|
-
setActiveCommands(
|
|
11452
|
+
setActiveCommands((prev) => {
|
|
11453
|
+
if (prev.size === next.size) {
|
|
11454
|
+
let same = true;
|
|
11455
|
+
for (const cmd of prev) {
|
|
11456
|
+
if (!next.has(cmd)) {
|
|
11457
|
+
same = false;
|
|
11458
|
+
break;
|
|
11459
|
+
}
|
|
11460
|
+
}
|
|
11461
|
+
if (same) return prev;
|
|
11462
|
+
}
|
|
11463
|
+
return next;
|
|
11464
|
+
});
|
|
11465
|
+
};
|
|
11466
|
+
const handleSelectionChange = () => {
|
|
11467
|
+
if (pointerHeldRef.current) return;
|
|
11468
|
+
if (selectionChangeRaf !== null) return;
|
|
11469
|
+
selectionChangeRaf = requestAnimationFrame(runSelectionChange);
|
|
11470
|
+
};
|
|
11471
|
+
const markPointerHeld = (e) => {
|
|
11472
|
+
if (e.button !== 0) return;
|
|
11473
|
+
pointerHeldRef.current = true;
|
|
9170
11474
|
};
|
|
9171
|
-
|
|
11475
|
+
const markPointerReleased = () => {
|
|
11476
|
+
if (!pointerHeldRef.current) return;
|
|
11477
|
+
pointerHeldRef.current = false;
|
|
11478
|
+
handleSelectionChange();
|
|
11479
|
+
};
|
|
11480
|
+
refreshActiveCommandsRef.current = runSelectionChange;
|
|
9172
11481
|
const handleDocMouseLeave = () => {
|
|
9173
11482
|
hoveredImageRef.current = null;
|
|
9174
11483
|
setMediaHover(null);
|
|
@@ -9213,15 +11522,15 @@ function OhhwellsBridge() {
|
|
|
9213
11522
|
};
|
|
9214
11523
|
const applyToolbarPos = (rect) => {
|
|
9215
11524
|
const ps = parentScrollRef.current;
|
|
9216
|
-
const
|
|
11525
|
+
const measuredW = toolbarElRef.current?.offsetWidth || 330;
|
|
9217
11526
|
if (toolbarElRef.current) {
|
|
9218
|
-
const { top, left, transform } = calcToolbarPos(rect, ps,
|
|
11527
|
+
const { top, left, transform } = calcToolbarPos(rect, ps, measuredW);
|
|
9219
11528
|
toolbarElRef.current.style.top = `${top}px`;
|
|
9220
11529
|
toolbarElRef.current.style.left = `${left}px`;
|
|
9221
11530
|
toolbarElRef.current.style.transform = transform;
|
|
9222
11531
|
}
|
|
9223
11532
|
if (glowElRef.current) {
|
|
9224
|
-
const GAP =
|
|
11533
|
+
const GAP = SELECTION_CHROME_GAP2;
|
|
9225
11534
|
glowElRef.current.style.top = `${rect.top - GAP}px`;
|
|
9226
11535
|
glowElRef.current.style.left = `${rect.left - GAP}px`;
|
|
9227
11536
|
glowElRef.current.style.width = `${rect.width + GAP * 2}px`;
|
|
@@ -9309,6 +11618,11 @@ function OhhwellsBridge() {
|
|
|
9309
11618
|
return;
|
|
9310
11619
|
}
|
|
9311
11620
|
}
|
|
11621
|
+
const footerColumn = findHoveredNavOrFooterContainer(clientX, clientY);
|
|
11622
|
+
if (footerColumn?.hasAttribute("data-ohw-footer-col") || footerColumn?.hasAttribute("data-ohw-footer-column")) {
|
|
11623
|
+
selectFrameRef.current(footerColumn);
|
|
11624
|
+
return;
|
|
11625
|
+
}
|
|
9312
11626
|
deactivateRef.current();
|
|
9313
11627
|
};
|
|
9314
11628
|
window.addEventListener("message", handleSave);
|
|
@@ -9330,6 +11644,7 @@ function OhhwellsBridge() {
|
|
|
9330
11644
|
};
|
|
9331
11645
|
window.addEventListener("resize", handleViewportResize, { passive: true });
|
|
9332
11646
|
document.addEventListener("click", handleClick, true);
|
|
11647
|
+
document.addEventListener("dblclick", handleDblClick, true);
|
|
9333
11648
|
document.addEventListener("paste", handlePaste, true);
|
|
9334
11649
|
document.addEventListener("input", handleInput, true);
|
|
9335
11650
|
document.addEventListener("mouseover", handleMouseOver, true);
|
|
@@ -9344,6 +11659,7 @@ function OhhwellsBridge() {
|
|
|
9344
11659
|
window.addEventListener("scroll", handleScroll, true);
|
|
9345
11660
|
return () => {
|
|
9346
11661
|
document.removeEventListener("click", handleClick, true);
|
|
11662
|
+
document.removeEventListener("dblclick", handleDblClick, true);
|
|
9347
11663
|
document.removeEventListener("paste", handlePaste, true);
|
|
9348
11664
|
document.removeEventListener("input", handleInput, true);
|
|
9349
11665
|
document.removeEventListener("mouseover", handleMouseOver, true);
|
|
@@ -9378,7 +11694,177 @@ function OhhwellsBridge() {
|
|
|
9378
11694
|
if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
|
|
9379
11695
|
};
|
|
9380
11696
|
}, [isEditMode, refreshStateRules]);
|
|
9381
|
-
(0,
|
|
11697
|
+
(0, import_react9.useEffect)(() => {
|
|
11698
|
+
if (!isEditMode) return;
|
|
11699
|
+
const THRESHOLD = 10;
|
|
11700
|
+
const resolveWasSelected = (el) => {
|
|
11701
|
+
if (selectedElRef.current === el) return true;
|
|
11702
|
+
const activeAnchor = activeElRef.current ? getNavigationItemAnchor(activeElRef.current) : null;
|
|
11703
|
+
return activeAnchor === el;
|
|
11704
|
+
};
|
|
11705
|
+
const onPointerDown = (e) => {
|
|
11706
|
+
if (e.button !== 0) return;
|
|
11707
|
+
if (suppressNextClickRef.current && Date.now() >= suppressClickUntilRef.current && !footerDragRef.current && !footerPointerDragRef.current?.started) {
|
|
11708
|
+
suppressNextClickRef.current = false;
|
|
11709
|
+
}
|
|
11710
|
+
if (footerDragRef.current) return;
|
|
11711
|
+
const target = e.target;
|
|
11712
|
+
if (!target) return;
|
|
11713
|
+
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]')) {
|
|
11714
|
+
return;
|
|
11715
|
+
}
|
|
11716
|
+
if (target.closest("[data-ohw-item-drag-surface]")) return;
|
|
11717
|
+
const anchor = getNavigationItemAnchor(target);
|
|
11718
|
+
const hrefKey = anchor?.getAttribute("data-ohw-href-key") ?? null;
|
|
11719
|
+
if (anchor && isFooterHrefKey(hrefKey)) {
|
|
11720
|
+
footerPointerDragRef.current = {
|
|
11721
|
+
el: anchor,
|
|
11722
|
+
kind: "link",
|
|
11723
|
+
startX: e.clientX,
|
|
11724
|
+
startY: e.clientY,
|
|
11725
|
+
pointerId: e.pointerId,
|
|
11726
|
+
wasSelected: resolveWasSelected(anchor),
|
|
11727
|
+
started: false
|
|
11728
|
+
};
|
|
11729
|
+
return;
|
|
11730
|
+
}
|
|
11731
|
+
const col = target.closest("[data-ohw-footer-col]");
|
|
11732
|
+
if (col && !getNavigationItemAnchor(target)) {
|
|
11733
|
+
footerPointerDragRef.current = {
|
|
11734
|
+
el: col,
|
|
11735
|
+
kind: "column",
|
|
11736
|
+
startX: e.clientX,
|
|
11737
|
+
startY: e.clientY,
|
|
11738
|
+
pointerId: e.pointerId,
|
|
11739
|
+
wasSelected: resolveWasSelected(col),
|
|
11740
|
+
started: false
|
|
11741
|
+
};
|
|
11742
|
+
}
|
|
11743
|
+
};
|
|
11744
|
+
const onPointerMove = (e) => {
|
|
11745
|
+
const pending = footerPointerDragRef.current;
|
|
11746
|
+
if (!pending) return;
|
|
11747
|
+
if (pending.started) {
|
|
11748
|
+
e.preventDefault();
|
|
11749
|
+
clearTextSelection();
|
|
11750
|
+
const session = footerDragRef.current;
|
|
11751
|
+
if (!session) return;
|
|
11752
|
+
const slot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(e.clientX, e.clientY, session.hrefKey) : hitTestColumnDropSlot(e.clientX, e.clientY);
|
|
11753
|
+
refreshFooterDragVisualsRef.current(session, slot, e.clientX, e.clientY);
|
|
11754
|
+
return;
|
|
11755
|
+
}
|
|
11756
|
+
const dx = e.clientX - pending.startX;
|
|
11757
|
+
const dy = e.clientY - pending.startY;
|
|
11758
|
+
if (dx * dx + dy * dy < THRESHOLD * THRESHOLD) return;
|
|
11759
|
+
e.preventDefault();
|
|
11760
|
+
pending.started = true;
|
|
11761
|
+
armFooterPressDrag();
|
|
11762
|
+
clearTextSelection();
|
|
11763
|
+
try {
|
|
11764
|
+
document.body.setPointerCapture(pending.pointerId);
|
|
11765
|
+
} catch {
|
|
11766
|
+
}
|
|
11767
|
+
if (linkPopoverOpenRef.current) {
|
|
11768
|
+
setLinkPopoverRef.current(null);
|
|
11769
|
+
}
|
|
11770
|
+
if (activeElRef.current) {
|
|
11771
|
+
deactivateRef.current();
|
|
11772
|
+
}
|
|
11773
|
+
if (pending.kind === "link") {
|
|
11774
|
+
const key = pending.el.getAttribute("data-ohw-href-key");
|
|
11775
|
+
if (!key) return;
|
|
11776
|
+
const column = findFooterColumnForLink(pending.el);
|
|
11777
|
+
const columns2 = listFooterColumns();
|
|
11778
|
+
beginFooterDragRef.current({
|
|
11779
|
+
kind: "link",
|
|
11780
|
+
hrefKey: key,
|
|
11781
|
+
columnEl: column,
|
|
11782
|
+
sourceColumnIndex: column ? columns2.indexOf(column) : 0,
|
|
11783
|
+
wasSelected: pending.wasSelected,
|
|
11784
|
+
draggedEl: pending.el,
|
|
11785
|
+
lastClientX: e.clientX,
|
|
11786
|
+
lastClientY: e.clientY,
|
|
11787
|
+
activeSlot: null
|
|
11788
|
+
});
|
|
11789
|
+
return;
|
|
11790
|
+
}
|
|
11791
|
+
const columns = listFooterColumns();
|
|
11792
|
+
const idx = columns.indexOf(pending.el);
|
|
11793
|
+
if (idx < 0) return;
|
|
11794
|
+
beginFooterDragRef.current({
|
|
11795
|
+
kind: "column",
|
|
11796
|
+
hrefKey: null,
|
|
11797
|
+
columnEl: pending.el,
|
|
11798
|
+
sourceColumnIndex: idx,
|
|
11799
|
+
wasSelected: pending.wasSelected,
|
|
11800
|
+
draggedEl: pending.el,
|
|
11801
|
+
lastClientX: e.clientX,
|
|
11802
|
+
lastClientY: e.clientY,
|
|
11803
|
+
activeSlot: null
|
|
11804
|
+
});
|
|
11805
|
+
};
|
|
11806
|
+
const endPointerDrag = (e) => {
|
|
11807
|
+
const pending = footerPointerDragRef.current;
|
|
11808
|
+
footerPointerDragRef.current = null;
|
|
11809
|
+
try {
|
|
11810
|
+
if (document.body.hasPointerCapture(e.pointerId)) {
|
|
11811
|
+
document.body.releasePointerCapture(e.pointerId);
|
|
11812
|
+
}
|
|
11813
|
+
} catch {
|
|
11814
|
+
}
|
|
11815
|
+
if (!pending) return;
|
|
11816
|
+
if (!pending.started) {
|
|
11817
|
+
unlockFooterDragInteraction();
|
|
11818
|
+
return;
|
|
11819
|
+
}
|
|
11820
|
+
suppressNextClickRef.current = true;
|
|
11821
|
+
suppressClickUntilRef.current = Date.now() + 500;
|
|
11822
|
+
commitFooterDragRef.current(e.clientX, e.clientY);
|
|
11823
|
+
};
|
|
11824
|
+
const blockSelectStart = (e) => {
|
|
11825
|
+
if (footerDragRef.current || footerPointerDragRef.current?.started || document.documentElement.hasAttribute("data-ohw-footer-press-drag")) {
|
|
11826
|
+
e.preventDefault();
|
|
11827
|
+
}
|
|
11828
|
+
};
|
|
11829
|
+
const onDragEnd = (_e) => {
|
|
11830
|
+
if (!footerDragRef.current) return;
|
|
11831
|
+
suppressNextClickRef.current = true;
|
|
11832
|
+
suppressClickUntilRef.current = Date.now() + 500;
|
|
11833
|
+
commitFooterDragRef.current();
|
|
11834
|
+
};
|
|
11835
|
+
document.addEventListener("pointerdown", onPointerDown, true);
|
|
11836
|
+
document.addEventListener("pointermove", onPointerMove, true);
|
|
11837
|
+
document.addEventListener("pointerup", endPointerDrag, true);
|
|
11838
|
+
document.addEventListener("pointercancel", endPointerDrag, true);
|
|
11839
|
+
document.addEventListener("selectstart", blockSelectStart, true);
|
|
11840
|
+
document.addEventListener("dragend", onDragEnd, true);
|
|
11841
|
+
return () => {
|
|
11842
|
+
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
11843
|
+
document.removeEventListener("pointermove", onPointerMove, true);
|
|
11844
|
+
document.removeEventListener("pointerup", endPointerDrag, true);
|
|
11845
|
+
document.removeEventListener("pointercancel", endPointerDrag, true);
|
|
11846
|
+
document.removeEventListener("selectstart", blockSelectStart, true);
|
|
11847
|
+
document.removeEventListener("dragend", onDragEnd, true);
|
|
11848
|
+
unlockFooterDragInteraction();
|
|
11849
|
+
};
|
|
11850
|
+
}, [isEditMode]);
|
|
11851
|
+
(0, import_react9.useEffect)(() => {
|
|
11852
|
+
if (!isEditMode) return;
|
|
11853
|
+
const debugSelectionChange = () => {
|
|
11854
|
+
const sel = window.getSelection();
|
|
11855
|
+
console.log(
|
|
11856
|
+
"[OHW DEBUG selectionchange]",
|
|
11857
|
+
JSON.stringify(sel?.toString() ?? ""),
|
|
11858
|
+
"collapsed=",
|
|
11859
|
+
sel?.isCollapsed,
|
|
11860
|
+
"anchorNode=",
|
|
11861
|
+
sel?.anchorNode,
|
|
11862
|
+
"activeEl=",
|
|
11863
|
+
activeElRef.current
|
|
11864
|
+
);
|
|
11865
|
+
};
|
|
11866
|
+
}, [isEditMode]);
|
|
11867
|
+
(0, import_react9.useEffect)(() => {
|
|
9382
11868
|
const handler = (e) => {
|
|
9383
11869
|
if (e.data?.type !== "ow:request-schedule-config") return;
|
|
9384
11870
|
const insertAfterVal = e.data.insertAfter;
|
|
@@ -9394,7 +11880,7 @@ function OhhwellsBridge() {
|
|
|
9394
11880
|
window.addEventListener("message", handler);
|
|
9395
11881
|
return () => window.removeEventListener("message", handler);
|
|
9396
11882
|
}, [processConfigRequest]);
|
|
9397
|
-
(0,
|
|
11883
|
+
(0, import_react9.useEffect)(() => {
|
|
9398
11884
|
if (!isEditMode) return;
|
|
9399
11885
|
document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
|
|
9400
11886
|
el.removeAttribute("data-ohw-active-state");
|
|
@@ -9415,7 +11901,13 @@ function OhhwellsBridge() {
|
|
|
9415
11901
|
const next = { ...prev, [pathKey]: sections };
|
|
9416
11902
|
return shouldUseDevFixtures() ? { ...DEV_SECTIONS_BY_PATH, ...next } : next;
|
|
9417
11903
|
});
|
|
9418
|
-
postToParent2({
|
|
11904
|
+
postToParent2({
|
|
11905
|
+
type: "ow:ready",
|
|
11906
|
+
version: "1",
|
|
11907
|
+
path: pathname,
|
|
11908
|
+
nodes: collectEditableNodes(editContentRef.current),
|
|
11909
|
+
sections
|
|
11910
|
+
});
|
|
9419
11911
|
postToParent2({ type: "ow:request-site-pages" });
|
|
9420
11912
|
}, 150);
|
|
9421
11913
|
return () => {
|
|
@@ -9423,19 +11915,20 @@ function OhhwellsBridge() {
|
|
|
9423
11915
|
clearTimeout(timer);
|
|
9424
11916
|
};
|
|
9425
11917
|
}, [pathname, isEditMode, refreshStateRules, postToParent2]);
|
|
9426
|
-
(0,
|
|
11918
|
+
(0, import_react9.useEffect)(() => {
|
|
9427
11919
|
scrollToHashSectionWhenReady();
|
|
9428
11920
|
const onHashChange = () => scrollToHashSectionWhenReady();
|
|
9429
11921
|
window.addEventListener("hashchange", onHashChange);
|
|
9430
11922
|
return () => window.removeEventListener("hashchange", onHashChange);
|
|
9431
11923
|
}, [pathname]);
|
|
9432
|
-
const handleCommand = (0,
|
|
11924
|
+
const handleCommand = (0, import_react9.useCallback)((cmd) => {
|
|
11925
|
+
document.execCommand("styleWithCSS", false, true);
|
|
9433
11926
|
document.execCommand(cmd, false);
|
|
9434
11927
|
activeElRef.current?.focus();
|
|
9435
11928
|
if (activeElRef.current) setToolbarRect(getEditMeasureEl(activeElRef.current).getBoundingClientRect());
|
|
9436
11929
|
refreshActiveCommandsRef.current();
|
|
9437
11930
|
}, []);
|
|
9438
|
-
const handleStateChange = (0,
|
|
11931
|
+
const handleStateChange = (0, import_react9.useCallback)((state) => {
|
|
9439
11932
|
if (!activeStateElRef.current) return;
|
|
9440
11933
|
const el = activeStateElRef.current;
|
|
9441
11934
|
if (state === "Default") {
|
|
@@ -9448,11 +11941,11 @@ function OhhwellsBridge() {
|
|
|
9448
11941
|
}
|
|
9449
11942
|
setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
|
|
9450
11943
|
}, [deactivate]);
|
|
9451
|
-
const closeLinkPopover = (0,
|
|
11944
|
+
const closeLinkPopover = (0, import_react9.useCallback)(() => {
|
|
9452
11945
|
addNavAfterAnchorRef.current = null;
|
|
9453
11946
|
setLinkPopover(null);
|
|
9454
11947
|
}, []);
|
|
9455
|
-
const openLinkPopoverForActive = (0,
|
|
11948
|
+
const openLinkPopoverForActive = (0, import_react9.useCallback)(() => {
|
|
9456
11949
|
const hrefCtx = getHrefKeyFromElement(activeElRef.current);
|
|
9457
11950
|
if (!hrefCtx) return;
|
|
9458
11951
|
bumpLinkPopoverGrace();
|
|
@@ -9463,7 +11956,7 @@ function OhhwellsBridge() {
|
|
|
9463
11956
|
});
|
|
9464
11957
|
deactivate();
|
|
9465
11958
|
}, [deactivate]);
|
|
9466
|
-
const openLinkPopoverForSelected = (0,
|
|
11959
|
+
const openLinkPopoverForSelected = (0, import_react9.useCallback)(() => {
|
|
9467
11960
|
const anchor = selectedElRef.current;
|
|
9468
11961
|
if (!anchor) return;
|
|
9469
11962
|
const key = anchor.getAttribute("data-ohw-href-key");
|
|
@@ -9476,7 +11969,7 @@ function OhhwellsBridge() {
|
|
|
9476
11969
|
});
|
|
9477
11970
|
deselect();
|
|
9478
11971
|
}, [deselect]);
|
|
9479
|
-
const handleLinkPopoverSubmit = (0,
|
|
11972
|
+
const handleLinkPopoverSubmit = (0, import_react9.useCallback)(
|
|
9480
11973
|
(target) => {
|
|
9481
11974
|
const session = linkPopoverSessionRef.current;
|
|
9482
11975
|
if (!session) return;
|
|
@@ -9535,13 +12028,13 @@ function OhhwellsBridge() {
|
|
|
9535
12028
|
const showEditLink = toolbarShowEditLink;
|
|
9536
12029
|
const currentSections = sectionsByPath[pathname] ?? [];
|
|
9537
12030
|
linkPopoverOpenRef.current = linkPopover !== null;
|
|
9538
|
-
const handleMediaReplace = (0,
|
|
12031
|
+
const handleMediaReplace = (0, import_react9.useCallback)(
|
|
9539
12032
|
(key) => {
|
|
9540
12033
|
postToParent2({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
|
|
9541
12034
|
},
|
|
9542
12035
|
[postToParent2, mediaHover?.elementType]
|
|
9543
12036
|
);
|
|
9544
|
-
const handleMediaFadeOutComplete = (0,
|
|
12037
|
+
const handleMediaFadeOutComplete = (0, import_react9.useCallback)((key) => {
|
|
9545
12038
|
setUploadingRects((prev) => {
|
|
9546
12039
|
if (!(key in prev)) return prev;
|
|
9547
12040
|
const next = { ...prev };
|
|
@@ -9549,7 +12042,7 @@ function OhhwellsBridge() {
|
|
|
9549
12042
|
return next;
|
|
9550
12043
|
});
|
|
9551
12044
|
}, []);
|
|
9552
|
-
const handleVideoSettingsChange = (0,
|
|
12045
|
+
const handleVideoSettingsChange = (0, import_react9.useCallback)(
|
|
9553
12046
|
(key, settings) => {
|
|
9554
12047
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
9555
12048
|
const video = getVideoEl(el);
|
|
@@ -9572,9 +12065,9 @@ function OhhwellsBridge() {
|
|
|
9572
12065
|
[postToParent2]
|
|
9573
12066
|
);
|
|
9574
12067
|
return bridgeRoot ? (0, import_react_dom3.createPortal)(
|
|
9575
|
-
/* @__PURE__ */ (0,
|
|
9576
|
-
/* @__PURE__ */ (0,
|
|
9577
|
-
Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0,
|
|
12068
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
|
|
12069
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
|
|
12070
|
+
Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
9578
12071
|
MediaOverlay,
|
|
9579
12072
|
{
|
|
9580
12073
|
hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
|
|
@@ -9585,7 +12078,7 @@ function OhhwellsBridge() {
|
|
|
9585
12078
|
},
|
|
9586
12079
|
`uploading-${key}`
|
|
9587
12080
|
)),
|
|
9588
|
-
mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ (0,
|
|
12081
|
+
mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
9589
12082
|
MediaOverlay,
|
|
9590
12083
|
{
|
|
9591
12084
|
hover: mediaHover,
|
|
@@ -9594,49 +12087,93 @@ function OhhwellsBridge() {
|
|
|
9594
12087
|
onVideoSettingsChange: handleVideoSettingsChange
|
|
9595
12088
|
}
|
|
9596
12089
|
),
|
|
9597
|
-
siblingHintRect && !isItemDragging && /* @__PURE__ */ (0,
|
|
9598
|
-
|
|
9599
|
-
|
|
9600
|
-
|
|
12090
|
+
siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
|
|
12091
|
+
siblingHintRects.length > 0 && !linkPopover && siblingHintRects.map((rect, i) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
|
|
12092
|
+
isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
|
|
12093
|
+
isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
12094
|
+
"div",
|
|
9601
12095
|
{
|
|
9602
|
-
|
|
9603
|
-
|
|
9604
|
-
|
|
9605
|
-
|
|
9606
|
-
|
|
9607
|
-
|
|
12096
|
+
className: "pointer-events-none fixed z-2147483646",
|
|
12097
|
+
style: {
|
|
12098
|
+
left: slot.left,
|
|
12099
|
+
top: slot.top,
|
|
12100
|
+
width: slot.width,
|
|
12101
|
+
height: slot.height
|
|
12102
|
+
},
|
|
12103
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
12104
|
+
DropIndicator,
|
|
12105
|
+
{
|
|
12106
|
+
direction: slot.direction,
|
|
12107
|
+
state: activeFooterDropIndex === i ? "dragActive" : "dragIdle",
|
|
12108
|
+
className: "!h-full !w-full"
|
|
12109
|
+
}
|
|
12110
|
+
)
|
|
12111
|
+
},
|
|
12112
|
+
`footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
|
|
12113
|
+
)),
|
|
12114
|
+
isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
12115
|
+
"div",
|
|
12116
|
+
{
|
|
12117
|
+
className: "pointer-events-none fixed z-2147483646",
|
|
12118
|
+
style: {
|
|
12119
|
+
left: slot.left,
|
|
12120
|
+
top: slot.top,
|
|
12121
|
+
width: slot.width,
|
|
12122
|
+
height: slot.height
|
|
12123
|
+
},
|
|
12124
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
12125
|
+
DropIndicator,
|
|
12126
|
+
{
|
|
12127
|
+
direction: slot.direction,
|
|
12128
|
+
state: activeNavDropIndex === i ? "dragActive" : "dragIdle",
|
|
12129
|
+
className: "!h-full !w-full"
|
|
12130
|
+
}
|
|
12131
|
+
)
|
|
12132
|
+
},
|
|
12133
|
+
`nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
|
|
12134
|
+
)),
|
|
12135
|
+
hoveredNavContainerRect && toolbarVariant !== "select-frame" && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
|
|
12136
|
+
hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
|
|
12137
|
+
toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
|
|
12138
|
+
toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
9608
12139
|
ItemInteractionLayer,
|
|
9609
12140
|
{
|
|
9610
|
-
rect: toolbarRect,
|
|
12141
|
+
rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
|
|
9611
12142
|
elRef: glowElRef,
|
|
9612
12143
|
state: isItemDragging ? "dragging" : resolveItemInteractionState(toolbarRect, parentScrollRef.current),
|
|
9613
|
-
showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey),
|
|
12144
|
+
showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey) || toolbarVariant === "select-frame" && isFooterFrameSelection,
|
|
9614
12145
|
dragDisabled: reorderDragDisabled,
|
|
9615
12146
|
dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
|
|
9616
12147
|
onDragHandleDragStart: handleItemDragStart,
|
|
9617
12148
|
onDragHandleDragEnd: handleItemDragEnd,
|
|
9618
|
-
|
|
12149
|
+
onItemPointerDown: handleItemChromePointerDown,
|
|
12150
|
+
onItemClick: handleItemChromeClick,
|
|
12151
|
+
itemDragSurface: !isFooterFrameSelection,
|
|
12152
|
+
toolbar: toolbarVariant === "link-action" && !isItemDragging ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
9619
12153
|
ItemActionToolbar,
|
|
9620
12154
|
{
|
|
9621
12155
|
onEditLink: openLinkPopoverForSelected,
|
|
9622
12156
|
addItemDisabled: true,
|
|
9623
12157
|
editLinkDisabled: false,
|
|
9624
|
-
moreDisabled: true
|
|
12158
|
+
moreDisabled: true,
|
|
12159
|
+
showAddItem: !selectedIsCta,
|
|
12160
|
+
showMore: !selectedIsCta
|
|
9625
12161
|
}
|
|
9626
12162
|
) : void 0
|
|
9627
12163
|
}
|
|
9628
12164
|
),
|
|
9629
|
-
toolbarRect && toolbarVariant === "rich-text" && /* @__PURE__ */ (0,
|
|
9630
|
-
/* @__PURE__ */ (0,
|
|
12165
|
+
toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
|
|
12166
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
9631
12167
|
EditGlowChrome,
|
|
9632
12168
|
{
|
|
9633
12169
|
rect: toolbarRect,
|
|
9634
12170
|
elRef: glowElRef,
|
|
9635
12171
|
reorderHrefKey,
|
|
9636
|
-
dragDisabled: reorderDragDisabled
|
|
12172
|
+
dragDisabled: reorderDragDisabled,
|
|
12173
|
+
hideHandle: isItemDragging
|
|
9637
12174
|
}
|
|
9638
12175
|
),
|
|
9639
|
-
/* @__PURE__ */ (0,
|
|
12176
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
9640
12177
|
FloatingToolbar,
|
|
9641
12178
|
{
|
|
9642
12179
|
rect: toolbarRect,
|
|
@@ -9649,7 +12186,7 @@ function OhhwellsBridge() {
|
|
|
9649
12186
|
}
|
|
9650
12187
|
)
|
|
9651
12188
|
] }),
|
|
9652
|
-
maxBadge && /* @__PURE__ */ (0,
|
|
12189
|
+
maxBadge && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
9653
12190
|
"div",
|
|
9654
12191
|
{
|
|
9655
12192
|
"data-ohw-max-badge": "",
|
|
@@ -9675,7 +12212,7 @@ function OhhwellsBridge() {
|
|
|
9675
12212
|
]
|
|
9676
12213
|
}
|
|
9677
12214
|
),
|
|
9678
|
-
toggleState && !linkPopover && /* @__PURE__ */ (0,
|
|
12215
|
+
toggleState && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
9679
12216
|
StateToggle,
|
|
9680
12217
|
{
|
|
9681
12218
|
rect: toggleState.rect,
|
|
@@ -9684,32 +12221,36 @@ function OhhwellsBridge() {
|
|
|
9684
12221
|
onStateChange: handleStateChange
|
|
9685
12222
|
}
|
|
9686
12223
|
),
|
|
9687
|
-
sectionGap && !linkPopover && /* @__PURE__ */ (0,
|
|
12224
|
+
sectionGap && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
9688
12225
|
"div",
|
|
9689
12226
|
{
|
|
9690
12227
|
"data-ohw-section-insert-line": "",
|
|
9691
12228
|
className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
|
|
9692
12229
|
style: { top: sectionGap.y, transform: "translateY(-50%)" },
|
|
9693
12230
|
children: [
|
|
9694
|
-
/* @__PURE__ */ (0,
|
|
9695
|
-
/* @__PURE__ */ (0,
|
|
12231
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
|
|
12232
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
9696
12233
|
Badge,
|
|
9697
12234
|
{
|
|
9698
12235
|
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",
|
|
9699
12236
|
onClick: () => {
|
|
9700
12237
|
window.parent.postMessage(
|
|
9701
|
-
{
|
|
12238
|
+
{
|
|
12239
|
+
type: "ow:add-section",
|
|
12240
|
+
insertAfter: sectionGap.insertAfter,
|
|
12241
|
+
insertBefore: sectionGap.insertBefore
|
|
12242
|
+
},
|
|
9702
12243
|
"*"
|
|
9703
12244
|
);
|
|
9704
12245
|
},
|
|
9705
12246
|
children: "Add Section"
|
|
9706
12247
|
}
|
|
9707
12248
|
),
|
|
9708
|
-
/* @__PURE__ */ (0,
|
|
12249
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
|
|
9709
12250
|
]
|
|
9710
12251
|
}
|
|
9711
12252
|
),
|
|
9712
|
-
linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0,
|
|
12253
|
+
linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
9713
12254
|
LinkPopover,
|
|
9714
12255
|
{
|
|
9715
12256
|
panelRef: linkPopoverPanelRef,
|
|
@@ -9736,6 +12277,7 @@ function OhhwellsBridge() {
|
|
|
9736
12277
|
CustomToolbarButton,
|
|
9737
12278
|
CustomToolbarDivider,
|
|
9738
12279
|
DragHandle,
|
|
12280
|
+
DropIndicator,
|
|
9739
12281
|
ItemActionToolbar,
|
|
9740
12282
|
ItemInteractionLayer,
|
|
9741
12283
|
LinkEditorPanel,
|
|
@@ -9750,6 +12292,7 @@ function OhhwellsBridge() {
|
|
|
9750
12292
|
TooltipProvider,
|
|
9751
12293
|
TooltipTrigger,
|
|
9752
12294
|
buildTarget,
|
|
12295
|
+
dropIndicatorVariants,
|
|
9753
12296
|
filterAvailablePages,
|
|
9754
12297
|
getEditModeInitialState,
|
|
9755
12298
|
isEditSessionActive,
|