@ohhwells/bridge 0.1.41 → 0.1.42-next.101
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/dist/index.cjs +2984 -468
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +51 -5
- package/dist/index.d.ts +51 -5
- package/dist/index.js +2991 -477
- package/dist/index.js.map +1 -1
- package/dist/styles.css +88 -73
- package/package.json +1 -1
package/dist/index.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,1019 @@ 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
|
+
const wasDragging = document.documentElement.hasAttribute("data-ohw-item-dragging");
|
|
7256
|
+
document.documentElement.removeAttribute("data-ohw-footer-press-drag");
|
|
7257
|
+
document.documentElement.removeAttribute("data-ohw-item-dragging");
|
|
7258
|
+
if (wasDragging) clearTextSelection();
|
|
7259
|
+
}
|
|
7260
|
+
var armFooterPressDrag = armItemPressDrag;
|
|
7261
|
+
var lockFooterDuringDrag = lockItemDuringDrag;
|
|
7262
|
+
var unlockFooterDragInteraction = unlockItemDragInteraction;
|
|
7263
|
+
|
|
7264
|
+
// src/lib/nav-dnd.ts
|
|
7265
|
+
function listReorderableNavItems() {
|
|
7266
|
+
return listNavbarItems().filter((el) => {
|
|
7267
|
+
const key = el.getAttribute("data-ohw-href-key");
|
|
7268
|
+
return isNavbarHrefKey(key) && !el.closest("[data-ohw-nav-children]");
|
|
7269
|
+
});
|
|
7270
|
+
}
|
|
7271
|
+
function listNavChildren(parentHrefKey) {
|
|
7272
|
+
const items = listNavbarItems();
|
|
7273
|
+
const parent = items.find((el) => el.getAttribute("data-ohw-href-key") === parentHrefKey);
|
|
7274
|
+
if (!parent) return [];
|
|
7275
|
+
const group = parent.closest("[data-ohw-nav-group]");
|
|
7276
|
+
const childrenRoot = group?.querySelector(":scope > [data-ohw-nav-children]");
|
|
7277
|
+
if (!childrenRoot) return [];
|
|
7278
|
+
return Array.from(childrenRoot.querySelectorAll(":scope > [data-ohw-href-key]")).filter(
|
|
7279
|
+
(el) => isNavbarHrefKey(el.getAttribute("data-ohw-href-key"))
|
|
7280
|
+
);
|
|
7281
|
+
}
|
|
7282
|
+
function activeNavListContainer() {
|
|
7283
|
+
const desktop = getNavbarDesktopContainer();
|
|
7284
|
+
if (desktop && desktop.getClientRects().length > 0) {
|
|
7285
|
+
const style = window.getComputedStyle(desktop);
|
|
7286
|
+
if (style.display !== "none" && style.visibility !== "hidden") return desktop;
|
|
7287
|
+
}
|
|
7288
|
+
return getNavbarDrawerContainer();
|
|
7289
|
+
}
|
|
7290
|
+
function buildRootNavDropSlots() {
|
|
7291
|
+
const items = listReorderableNavItems();
|
|
7292
|
+
const slots = [];
|
|
7293
|
+
const barThickness = 3;
|
|
7294
|
+
if (items.length === 0) {
|
|
7295
|
+
const container = activeNavListContainer();
|
|
7296
|
+
if (!container) return slots;
|
|
7297
|
+
const rect = container.getBoundingClientRect();
|
|
7298
|
+
slots.push({
|
|
7299
|
+
insertIndex: 0,
|
|
7300
|
+
parentId: null,
|
|
7301
|
+
left: rect.left + rect.width / 2 - barThickness / 2,
|
|
7302
|
+
top: rect.top,
|
|
7303
|
+
width: barThickness,
|
|
7304
|
+
height: Math.max(rect.height, 24),
|
|
7305
|
+
direction: "vertical"
|
|
7306
|
+
});
|
|
7307
|
+
return slots;
|
|
7308
|
+
}
|
|
7309
|
+
for (let i = 0; i <= items.length; i++) {
|
|
7310
|
+
let left;
|
|
7311
|
+
let top;
|
|
7312
|
+
let height;
|
|
7313
|
+
if (i === 0) {
|
|
7314
|
+
const first = items[0].getBoundingClientRect();
|
|
7315
|
+
left = first.left - barThickness / 2;
|
|
7316
|
+
top = first.top;
|
|
7317
|
+
height = first.height;
|
|
7318
|
+
} else if (i === items.length) {
|
|
7319
|
+
const last = items[items.length - 1].getBoundingClientRect();
|
|
7320
|
+
left = last.right - barThickness / 2;
|
|
7321
|
+
top = last.top;
|
|
7322
|
+
height = last.height;
|
|
7323
|
+
} else {
|
|
7324
|
+
const prev = items[i - 1].getBoundingClientRect();
|
|
7325
|
+
const next = items[i].getBoundingClientRect();
|
|
7326
|
+
left = (prev.right + next.left) / 2 - barThickness / 2;
|
|
7327
|
+
top = Math.min(prev.top, next.top);
|
|
7328
|
+
height = Math.max(prev.bottom, next.bottom) - top;
|
|
7329
|
+
}
|
|
7330
|
+
slots.push({
|
|
7331
|
+
insertIndex: i,
|
|
7332
|
+
parentId: null,
|
|
7333
|
+
left,
|
|
7334
|
+
top,
|
|
7335
|
+
width: barThickness,
|
|
7336
|
+
height: Math.max(height, 24),
|
|
7337
|
+
direction: "vertical"
|
|
7338
|
+
});
|
|
7339
|
+
}
|
|
7340
|
+
return slots;
|
|
7341
|
+
}
|
|
7342
|
+
function buildChildNavDropSlots(parentHrefKey) {
|
|
7343
|
+
const children = listNavChildren(parentHrefKey);
|
|
7344
|
+
const slots = [];
|
|
7345
|
+
const barThickness = 3;
|
|
7346
|
+
if (children.length === 0) return slots;
|
|
7347
|
+
for (let i = 0; i <= children.length; i++) {
|
|
7348
|
+
let top;
|
|
7349
|
+
let width;
|
|
7350
|
+
let left;
|
|
7351
|
+
if (i === 0) {
|
|
7352
|
+
const first = children[0].getBoundingClientRect();
|
|
7353
|
+
top = first.top - barThickness / 2;
|
|
7354
|
+
left = first.left;
|
|
7355
|
+
width = first.width;
|
|
7356
|
+
} else if (i === children.length) {
|
|
7357
|
+
const last = children[children.length - 1].getBoundingClientRect();
|
|
7358
|
+
top = last.bottom - barThickness / 2;
|
|
7359
|
+
left = last.left;
|
|
7360
|
+
width = last.width;
|
|
7361
|
+
} else {
|
|
7362
|
+
const prev = children[i - 1].getBoundingClientRect();
|
|
7363
|
+
const next = children[i].getBoundingClientRect();
|
|
7364
|
+
top = (prev.bottom + next.top) / 2 - barThickness / 2;
|
|
7365
|
+
left = Math.min(prev.left, next.left);
|
|
7366
|
+
width = Math.max(prev.right, next.right) - left;
|
|
7367
|
+
}
|
|
7368
|
+
slots.push({
|
|
7369
|
+
insertIndex: i,
|
|
7370
|
+
parentId: parentHrefKey,
|
|
7371
|
+
left,
|
|
7372
|
+
top,
|
|
7373
|
+
width: Math.max(width, 40),
|
|
7374
|
+
height: barThickness,
|
|
7375
|
+
direction: "horizontal"
|
|
7376
|
+
});
|
|
7377
|
+
}
|
|
7378
|
+
return slots;
|
|
7379
|
+
}
|
|
7380
|
+
function buildAllNavDropSlots(draggedHrefKey) {
|
|
7381
|
+
const slots = [...buildRootNavDropSlots()];
|
|
7382
|
+
for (const item of listReorderableNavItems()) {
|
|
7383
|
+
const key = item.getAttribute("data-ohw-href-key");
|
|
7384
|
+
if (!key || key === draggedHrefKey) continue;
|
|
7385
|
+
const group = item.closest("[data-ohw-nav-group]");
|
|
7386
|
+
if (!group?.querySelector(":scope > [data-ohw-nav-children]")) continue;
|
|
7387
|
+
slots.push(...buildChildNavDropSlots(key));
|
|
7388
|
+
}
|
|
7389
|
+
const dragged = listNavbarItems().find((el) => el.getAttribute("data-ohw-href-key") === draggedHrefKey);
|
|
7390
|
+
const parentGroup = dragged?.closest("[data-ohw-nav-children]")?.closest("[data-ohw-nav-group]");
|
|
7391
|
+
const parentTrigger = parentGroup?.querySelector(":scope > [data-ohw-href-key]");
|
|
7392
|
+
const parentKey = parentTrigger?.getAttribute("data-ohw-href-key");
|
|
7393
|
+
if (parentKey && isNavbarHrefKey(parentKey)) {
|
|
7394
|
+
const existing = slots.some((s) => s.parentId === parentKey);
|
|
7395
|
+
if (!existing) slots.push(...buildChildNavDropSlots(parentKey));
|
|
7396
|
+
}
|
|
7397
|
+
return slots;
|
|
7398
|
+
}
|
|
7399
|
+
function hitTestNavDropSlot(clientX, clientY, draggedHrefKey) {
|
|
7400
|
+
const slots = buildAllNavDropSlots(draggedHrefKey);
|
|
7401
|
+
let best = null;
|
|
7402
|
+
for (const slot of slots) {
|
|
7403
|
+
const cx2 = slot.left + slot.width / 2;
|
|
7404
|
+
const cy = slot.top + slot.height / 2;
|
|
7405
|
+
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;
|
|
7406
|
+
if (!best || dist < best.dist) best = { slot, dist };
|
|
7407
|
+
}
|
|
7408
|
+
return best?.slot ?? null;
|
|
7409
|
+
}
|
|
7410
|
+
function siblingRectsForNavDrag(draggedEl, activeParentId) {
|
|
7411
|
+
if (activeParentId) {
|
|
7412
|
+
return listNavChildren(activeParentId).filter((el) => el !== draggedEl).map((el) => el.getBoundingClientRect());
|
|
7413
|
+
}
|
|
7414
|
+
return listReorderableNavItems().filter((el) => el !== draggedEl).map((el) => el.getBoundingClientRect());
|
|
7415
|
+
}
|
|
7416
|
+
|
|
7417
|
+
// src/useNavItemDrag.ts
|
|
7418
|
+
var import_react8 = require("react");
|
|
7419
|
+
function useNavItemDrag({
|
|
7420
|
+
isEditMode,
|
|
7421
|
+
editContentRef,
|
|
7422
|
+
selectedElRef,
|
|
7423
|
+
activeElRef,
|
|
7424
|
+
footerDragRef,
|
|
7425
|
+
suppressNextClickRef,
|
|
7426
|
+
suppressClickUntilRef,
|
|
7427
|
+
siblingHintElRef,
|
|
7428
|
+
postToParentRef,
|
|
7429
|
+
deselectRef,
|
|
7430
|
+
selectRef,
|
|
7431
|
+
deactivateRef,
|
|
7432
|
+
setLinkPopover,
|
|
7433
|
+
linkPopoverOpenRef,
|
|
7434
|
+
setIsItemDragging,
|
|
7435
|
+
setDraggedItemRect,
|
|
7436
|
+
setSiblingHintRect,
|
|
7437
|
+
setSiblingHintRects,
|
|
7438
|
+
setToolbarRect,
|
|
7439
|
+
getNavigationItemAnchor: getNavigationItemAnchor2,
|
|
7440
|
+
isDragHandleDisabled: isDragHandleDisabled2,
|
|
7441
|
+
isNavbarButton: isNavbarButton3
|
|
7442
|
+
}) {
|
|
7443
|
+
const navDragRef = (0, import_react8.useRef)(null);
|
|
7444
|
+
const [navDropSlots, setNavDropSlots] = (0, import_react8.useState)([]);
|
|
7445
|
+
const [activeNavDropIndex, setActiveNavDropIndex] = (0, import_react8.useState)(null);
|
|
7446
|
+
const navPointerDragRef = (0, import_react8.useRef)(null);
|
|
7447
|
+
const clearNavDragVisuals = (0, import_react8.useCallback)(() => {
|
|
7448
|
+
navDragRef.current = null;
|
|
7449
|
+
setNavDropSlots([]);
|
|
7450
|
+
setActiveNavDropIndex(null);
|
|
7451
|
+
setDraggedItemRect(null);
|
|
7452
|
+
setSiblingHintRects([]);
|
|
7453
|
+
setIsItemDragging(false);
|
|
7454
|
+
unlockItemDragInteraction();
|
|
7455
|
+
}, [setDraggedItemRect, setIsItemDragging, setSiblingHintRects]);
|
|
7456
|
+
const refreshNavDragVisuals = (0, import_react8.useCallback)(
|
|
7457
|
+
(session, activeSlot, clientX, clientY) => {
|
|
7458
|
+
setDraggedItemRect(session.draggedEl.getBoundingClientRect());
|
|
7459
|
+
if (typeof clientX === "number" && typeof clientY === "number") {
|
|
7460
|
+
session.lastClientX = clientX;
|
|
7461
|
+
session.lastClientY = clientY;
|
|
7462
|
+
}
|
|
7463
|
+
session.activeSlot = activeSlot;
|
|
7464
|
+
const parentId = activeSlot?.parentId ?? null;
|
|
7465
|
+
setSiblingHintRects(siblingRectsForNavDrag(session.draggedEl, parentId));
|
|
7466
|
+
const slots = buildAllNavDropSlots(session.hrefKey);
|
|
7467
|
+
setNavDropSlots(slots);
|
|
7468
|
+
const activeIdx = activeSlot ? slots.findIndex(
|
|
7469
|
+
(s) => s.parentId === activeSlot.parentId && s.insertIndex === activeSlot.insertIndex
|
|
7470
|
+
) : -1;
|
|
7471
|
+
setActiveNavDropIndex(activeIdx >= 0 ? activeIdx : null);
|
|
7472
|
+
},
|
|
7473
|
+
[setDraggedItemRect, setSiblingHintRects]
|
|
7474
|
+
);
|
|
7475
|
+
const refreshNavDragVisualsRef = (0, import_react8.useRef)(refreshNavDragVisuals);
|
|
7476
|
+
refreshNavDragVisualsRef.current = refreshNavDragVisuals;
|
|
7477
|
+
const commitNavDragRef = (0, import_react8.useRef)(() => {
|
|
7478
|
+
});
|
|
7479
|
+
const beginNavDragRef = (0, import_react8.useRef)(() => {
|
|
7480
|
+
});
|
|
7481
|
+
const beginNavDrag = (0, import_react8.useCallback)(
|
|
7482
|
+
(session) => {
|
|
7483
|
+
const rect = session.draggedEl.getBoundingClientRect();
|
|
7484
|
+
session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
|
|
7485
|
+
session.lastClientY = session.lastClientY || rect.top + rect.height / 2;
|
|
7486
|
+
session.activeSlot = session.activeSlot ?? null;
|
|
7487
|
+
navDragRef.current = session;
|
|
7488
|
+
setIsItemDragging(true);
|
|
7489
|
+
lockItemDuringDrag();
|
|
7490
|
+
siblingHintElRef.current = null;
|
|
7491
|
+
setSiblingHintRect(null);
|
|
7492
|
+
if (session.wasSelected && selectedElRef.current === session.draggedEl) {
|
|
7493
|
+
setToolbarRect(rect);
|
|
7494
|
+
}
|
|
7495
|
+
const initialSlot = hitTestNavDropSlot(session.lastClientX, session.lastClientY, session.hrefKey);
|
|
7496
|
+
refreshNavDragVisuals(session, initialSlot, session.lastClientX, session.lastClientY);
|
|
7497
|
+
},
|
|
7498
|
+
[
|
|
7499
|
+
refreshNavDragVisuals,
|
|
7500
|
+
selectedElRef,
|
|
7501
|
+
setIsItemDragging,
|
|
7502
|
+
setSiblingHintRect,
|
|
7503
|
+
setToolbarRect,
|
|
7504
|
+
siblingHintElRef
|
|
7505
|
+
]
|
|
7506
|
+
);
|
|
7507
|
+
beginNavDragRef.current = beginNavDrag;
|
|
7508
|
+
const commitNavDrag = (0, import_react8.useCallback)(
|
|
7509
|
+
(clientX, clientY) => {
|
|
7510
|
+
const session = navDragRef.current;
|
|
7511
|
+
if (!session) {
|
|
7512
|
+
clearNavDragVisuals();
|
|
7513
|
+
return;
|
|
7514
|
+
}
|
|
7515
|
+
const x = typeof clientX === "number" && (clientX !== 0 || clientY !== 0) ? clientX : session.lastClientX;
|
|
7516
|
+
const y = typeof clientY === "number" && (clientX !== 0 || clientY !== 0) ? clientY : session.lastClientY;
|
|
7517
|
+
const slot = session.activeSlot ?? hitTestNavDropSlot(x, y, session.hrefKey);
|
|
7518
|
+
const planned = slot != null ? planNavItemMove(session.hrefKey, slot.parentId, slot.insertIndex) : null;
|
|
7519
|
+
const wasSelected = session.wasSelected;
|
|
7520
|
+
const hrefKey = session.hrefKey;
|
|
7521
|
+
const applySelectionAfterDrop = () => {
|
|
7522
|
+
if (!wasSelected) {
|
|
7523
|
+
deselectRef.current();
|
|
7524
|
+
return;
|
|
7525
|
+
}
|
|
7526
|
+
const desktop = document.querySelector("[data-ohw-nav-container]");
|
|
7527
|
+
const drawer = document.querySelector("[data-ohw-nav-drawer]");
|
|
7528
|
+
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)}"]`);
|
|
7529
|
+
if (link) {
|
|
7530
|
+
selectRef.current(link);
|
|
7531
|
+
return;
|
|
7532
|
+
}
|
|
7533
|
+
deselectRef.current();
|
|
7534
|
+
};
|
|
7535
|
+
if (planned) {
|
|
7536
|
+
editContentRef.current = {
|
|
7537
|
+
...editContentRef.current,
|
|
7538
|
+
[NAV_ORDER_KEY]: planned.orderJson
|
|
7539
|
+
};
|
|
7540
|
+
applyNavForest(planned.forest);
|
|
7541
|
+
document.querySelectorAll(
|
|
7542
|
+
"nav [data-ohw-href-key], [data-ohw-nav-container] [data-ohw-href-key], [data-ohw-nav-drawer] [data-ohw-href-key]"
|
|
7543
|
+
).forEach((el) => {
|
|
7544
|
+
if (isNavbarHrefKey(el.getAttribute("data-ohw-href-key"))) {
|
|
7545
|
+
disableNativeHrefDrag(el);
|
|
7546
|
+
}
|
|
7547
|
+
});
|
|
7548
|
+
postToParentRef.current({
|
|
7549
|
+
type: "ow:change",
|
|
7550
|
+
nodes: [{ key: NAV_ORDER_KEY, text: planned.orderJson }]
|
|
7551
|
+
});
|
|
7552
|
+
applySelectionAfterDrop();
|
|
7553
|
+
clearNavDragVisuals();
|
|
7554
|
+
requestAnimationFrame(() => {
|
|
7555
|
+
if (editContentRef.current[NAV_ORDER_KEY] === planned.orderJson) {
|
|
7556
|
+
applyNavForest(planned.forest);
|
|
7557
|
+
}
|
|
7558
|
+
applySelectionAfterDrop();
|
|
7559
|
+
requestAnimationFrame(applySelectionAfterDrop);
|
|
7560
|
+
});
|
|
7561
|
+
return;
|
|
7562
|
+
}
|
|
7563
|
+
applySelectionAfterDrop();
|
|
7564
|
+
clearNavDragVisuals();
|
|
7565
|
+
},
|
|
7566
|
+
[clearNavDragVisuals, deselectRef, editContentRef, postToParentRef, selectRef]
|
|
7567
|
+
);
|
|
7568
|
+
commitNavDragRef.current = commitNavDrag;
|
|
7569
|
+
const startNavLinkDrag = (0, import_react8.useCallback)(
|
|
7570
|
+
(anchor, clientX, clientY, wasSelected) => {
|
|
7571
|
+
if (footerDragRef.current) return false;
|
|
7572
|
+
const hrefKey = anchor.getAttribute("data-ohw-href-key");
|
|
7573
|
+
if (!hrefKey || !isNavbarHrefKey(hrefKey)) return false;
|
|
7574
|
+
if (isNavbarButton3(anchor) || isDragHandleDisabled2(anchor)) return false;
|
|
7575
|
+
beginNavDrag({
|
|
7576
|
+
hrefKey,
|
|
7577
|
+
wasSelected,
|
|
7578
|
+
draggedEl: anchor,
|
|
7579
|
+
lastClientX: clientX,
|
|
7580
|
+
lastClientY: clientY,
|
|
7581
|
+
activeSlot: null
|
|
7582
|
+
});
|
|
7583
|
+
return true;
|
|
7584
|
+
},
|
|
7585
|
+
[beginNavDrag, footerDragRef, isDragHandleDisabled2, isNavbarButton3]
|
|
7586
|
+
);
|
|
7587
|
+
const onNavDragOver = (0, import_react8.useCallback)(
|
|
7588
|
+
(e) => {
|
|
7589
|
+
const session = navDragRef.current;
|
|
7590
|
+
if (!session) return false;
|
|
7591
|
+
e.preventDefault();
|
|
7592
|
+
if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
|
|
7593
|
+
const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey);
|
|
7594
|
+
refreshNavDragVisualsRef.current(session, slot, e.clientX, e.clientY);
|
|
7595
|
+
return true;
|
|
7596
|
+
},
|
|
7597
|
+
[]
|
|
7598
|
+
);
|
|
7599
|
+
(0, import_react8.useEffect)(() => {
|
|
7600
|
+
if (!isEditMode) return;
|
|
7601
|
+
const THRESHOLD = 10;
|
|
7602
|
+
const resolveWasSelected = (el) => {
|
|
7603
|
+
if (selectedElRef.current === el) return true;
|
|
7604
|
+
const activeAnchor = activeElRef.current ? getNavigationItemAnchor2(activeElRef.current) : null;
|
|
7605
|
+
return activeAnchor === el;
|
|
7606
|
+
};
|
|
7607
|
+
const onPointerDown = (e) => {
|
|
7608
|
+
if (e.button !== 0) return;
|
|
7609
|
+
if (navDragRef.current || footerDragRef.current) return;
|
|
7610
|
+
const target = e.target;
|
|
7611
|
+
if (!target) return;
|
|
7612
|
+
if (target.closest(
|
|
7613
|
+
'[data-ohw-drag-handle-container], [data-slot="drag-handle"], [data-ohw-toolbar], [data-ohw-item-toolbar-anchor], [data-ohw-link-popover-root]'
|
|
7614
|
+
)) {
|
|
7615
|
+
return;
|
|
7616
|
+
}
|
|
7617
|
+
if (target.closest("[data-ohw-item-drag-surface]")) return;
|
|
7618
|
+
const anchor = getNavigationItemAnchor2(target);
|
|
7619
|
+
const hrefKey = anchor?.getAttribute("data-ohw-href-key") ?? null;
|
|
7620
|
+
if (!anchor || !isNavbarHrefKey(hrefKey)) return;
|
|
7621
|
+
if (isNavbarButton3(anchor) || isDragHandleDisabled2(anchor)) return;
|
|
7622
|
+
navPointerDragRef.current = {
|
|
7623
|
+
el: anchor,
|
|
7624
|
+
startX: e.clientX,
|
|
7625
|
+
startY: e.clientY,
|
|
7626
|
+
pointerId: e.pointerId,
|
|
7627
|
+
wasSelected: resolveWasSelected(anchor),
|
|
7628
|
+
started: false
|
|
7629
|
+
};
|
|
7630
|
+
};
|
|
7631
|
+
const onPointerMove = (e) => {
|
|
7632
|
+
const pending = navPointerDragRef.current;
|
|
7633
|
+
if (!pending) return;
|
|
7634
|
+
if (pending.started) {
|
|
7635
|
+
e.preventDefault();
|
|
7636
|
+
clearTextSelection();
|
|
7637
|
+
const session = navDragRef.current;
|
|
7638
|
+
if (!session) return;
|
|
7639
|
+
const slot = hitTestNavDropSlot(e.clientX, e.clientY, session.hrefKey);
|
|
7640
|
+
refreshNavDragVisualsRef.current(session, slot, e.clientX, e.clientY);
|
|
7641
|
+
return;
|
|
7642
|
+
}
|
|
7643
|
+
const dx = e.clientX - pending.startX;
|
|
7644
|
+
const dy = e.clientY - pending.startY;
|
|
7645
|
+
if (dx * dx + dy * dy < THRESHOLD * THRESHOLD) return;
|
|
7646
|
+
e.preventDefault();
|
|
7647
|
+
pending.started = true;
|
|
7648
|
+
armItemPressDrag();
|
|
7649
|
+
clearTextSelection();
|
|
7650
|
+
try {
|
|
7651
|
+
document.body.setPointerCapture(pending.pointerId);
|
|
7652
|
+
} catch {
|
|
7653
|
+
}
|
|
7654
|
+
if (linkPopoverOpenRef.current) setLinkPopover(null);
|
|
7655
|
+
if (activeElRef.current) deactivateRef.current();
|
|
7656
|
+
const key = pending.el.getAttribute("data-ohw-href-key");
|
|
7657
|
+
if (!key) return;
|
|
7658
|
+
beginNavDragRef.current({
|
|
7659
|
+
hrefKey: key,
|
|
7660
|
+
wasSelected: pending.wasSelected,
|
|
7661
|
+
draggedEl: pending.el,
|
|
7662
|
+
lastClientX: e.clientX,
|
|
7663
|
+
lastClientY: e.clientY,
|
|
7664
|
+
activeSlot: null
|
|
7665
|
+
});
|
|
7666
|
+
};
|
|
7667
|
+
const endPointerDrag = (e) => {
|
|
7668
|
+
const pending = navPointerDragRef.current;
|
|
7669
|
+
navPointerDragRef.current = null;
|
|
7670
|
+
try {
|
|
7671
|
+
if (document.body.hasPointerCapture(e.pointerId)) {
|
|
7672
|
+
document.body.releasePointerCapture(e.pointerId);
|
|
7673
|
+
}
|
|
7674
|
+
} catch {
|
|
7675
|
+
}
|
|
7676
|
+
if (!pending) return;
|
|
7677
|
+
if (!pending.started) {
|
|
7678
|
+
unlockItemDragInteraction();
|
|
7679
|
+
return;
|
|
7680
|
+
}
|
|
7681
|
+
suppressNextClickRef.current = true;
|
|
7682
|
+
suppressClickUntilRef.current = Date.now() + 500;
|
|
7683
|
+
commitNavDragRef.current(e.clientX, e.clientY);
|
|
7684
|
+
};
|
|
7685
|
+
const blockSelectStart = (e) => {
|
|
7686
|
+
if (navDragRef.current || navPointerDragRef.current?.started || document.documentElement.hasAttribute("data-ohw-footer-press-drag")) {
|
|
7687
|
+
e.preventDefault();
|
|
7688
|
+
}
|
|
7689
|
+
};
|
|
7690
|
+
const onDragEnd = () => {
|
|
7691
|
+
if (!navDragRef.current) return;
|
|
7692
|
+
suppressNextClickRef.current = true;
|
|
7693
|
+
suppressClickUntilRef.current = Date.now() + 500;
|
|
7694
|
+
commitNavDragRef.current();
|
|
7695
|
+
};
|
|
7696
|
+
document.addEventListener("pointerdown", onPointerDown, true);
|
|
7697
|
+
document.addEventListener("pointermove", onPointerMove, true);
|
|
7698
|
+
document.addEventListener("pointerup", endPointerDrag, true);
|
|
7699
|
+
document.addEventListener("pointercancel", endPointerDrag, true);
|
|
7700
|
+
document.addEventListener("selectstart", blockSelectStart, true);
|
|
7701
|
+
document.addEventListener("dragend", onDragEnd, true);
|
|
7702
|
+
return () => {
|
|
7703
|
+
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
7704
|
+
document.removeEventListener("pointermove", onPointerMove, true);
|
|
7705
|
+
document.removeEventListener("pointerup", endPointerDrag, true);
|
|
7706
|
+
document.removeEventListener("pointercancel", endPointerDrag, true);
|
|
7707
|
+
document.removeEventListener("selectstart", blockSelectStart, true);
|
|
7708
|
+
document.removeEventListener("dragend", onDragEnd, true);
|
|
7709
|
+
unlockItemDragInteraction();
|
|
7710
|
+
};
|
|
7711
|
+
}, [
|
|
7712
|
+
activeElRef,
|
|
7713
|
+
deactivateRef,
|
|
7714
|
+
footerDragRef,
|
|
7715
|
+
getNavigationItemAnchor2,
|
|
7716
|
+
isDragHandleDisabled2,
|
|
7717
|
+
isEditMode,
|
|
7718
|
+
isNavbarButton3,
|
|
7719
|
+
linkPopoverOpenRef,
|
|
7720
|
+
selectedElRef,
|
|
7721
|
+
setLinkPopover,
|
|
7722
|
+
suppressNextClickRef
|
|
7723
|
+
]);
|
|
7724
|
+
const armNavPressFromChrome = (0, import_react8.useCallback)(
|
|
7725
|
+
(selected, clientX, clientY, pointerId) => {
|
|
7726
|
+
const hrefKey = selected.getAttribute("data-ohw-href-key");
|
|
7727
|
+
if (!hrefKey || !isNavbarHrefKey(hrefKey)) return false;
|
|
7728
|
+
if (isNavbarButton3(selected) || isDragHandleDisabled2(selected)) return false;
|
|
7729
|
+
navPointerDragRef.current = {
|
|
7730
|
+
el: selected,
|
|
7731
|
+
startX: clientX,
|
|
7732
|
+
startY: clientY,
|
|
7733
|
+
pointerId,
|
|
7734
|
+
wasSelected: true,
|
|
7735
|
+
started: false
|
|
7736
|
+
};
|
|
7737
|
+
return true;
|
|
7738
|
+
},
|
|
7739
|
+
[isDragHandleDisabled2, isNavbarButton3]
|
|
7740
|
+
);
|
|
7741
|
+
return {
|
|
7742
|
+
navDragRef,
|
|
7743
|
+
navDropSlots,
|
|
7744
|
+
activeNavDropIndex,
|
|
7745
|
+
startNavLinkDrag,
|
|
7746
|
+
commitNavDrag,
|
|
7747
|
+
onNavDragOver,
|
|
7748
|
+
armNavPressFromChrome,
|
|
7749
|
+
clearNavDragVisuals,
|
|
7750
|
+
refreshNavDragVisualsRef
|
|
7751
|
+
};
|
|
7752
|
+
}
|
|
7753
|
+
|
|
7754
|
+
// src/ui/navbar-container-chrome.tsx
|
|
7755
|
+
var import_lucide_react10 = require("lucide-react");
|
|
7756
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
7757
|
+
function NavbarContainerChrome({
|
|
7758
|
+
rect,
|
|
7759
|
+
onAdd
|
|
7760
|
+
}) {
|
|
7761
|
+
const chromeGap = 6;
|
|
7762
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
7763
|
+
"div",
|
|
7764
|
+
{
|
|
7765
|
+
"data-ohw-navbar-container-chrome": "",
|
|
7766
|
+
"data-ohw-bridge": "",
|
|
7767
|
+
className: "pointer-events-none fixed z-[2147483647]",
|
|
7768
|
+
style: {
|
|
7769
|
+
top: rect.top - chromeGap,
|
|
7770
|
+
left: rect.left - chromeGap,
|
|
7771
|
+
width: rect.width + chromeGap * 2,
|
|
7772
|
+
height: rect.height + chromeGap * 2
|
|
7773
|
+
},
|
|
7774
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
7775
|
+
"button",
|
|
7776
|
+
{
|
|
7777
|
+
type: "button",
|
|
7778
|
+
"data-ohw-navbar-add-button": "",
|
|
7779
|
+
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",
|
|
7780
|
+
style: { top: "70%" },
|
|
7781
|
+
"aria-label": "Add item",
|
|
7782
|
+
onMouseDown: (e) => {
|
|
7783
|
+
e.preventDefault();
|
|
7784
|
+
e.stopPropagation();
|
|
7785
|
+
},
|
|
7786
|
+
onClick: (e) => {
|
|
7787
|
+
e.preventDefault();
|
|
7788
|
+
e.stopPropagation();
|
|
7789
|
+
onAdd();
|
|
7790
|
+
},
|
|
7791
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react10.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
|
|
7792
|
+
}
|
|
7793
|
+
)
|
|
7794
|
+
}
|
|
7795
|
+
);
|
|
7796
|
+
}
|
|
7797
|
+
|
|
7798
|
+
// src/ui/drop-indicator.tsx
|
|
7799
|
+
var React10 = __toESM(require("react"), 1);
|
|
7800
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
7801
|
+
var dropIndicatorVariants = cva(
|
|
7802
|
+
"ov-gap-line pointer-events-none shrink-0 transition-opacity duration-150",
|
|
7803
|
+
{
|
|
7804
|
+
variants: {
|
|
7805
|
+
direction: {
|
|
7806
|
+
vertical: "h-6 w-[3px]",
|
|
7807
|
+
horizontal: "h-[3px] w-[200px]"
|
|
7808
|
+
},
|
|
7809
|
+
state: {
|
|
7810
|
+
default: "opacity-0",
|
|
7811
|
+
hover: "opacity-100",
|
|
7812
|
+
dragIdle: "opacity-40",
|
|
7813
|
+
dragActive: "opacity-100"
|
|
7814
|
+
}
|
|
7815
|
+
},
|
|
7816
|
+
defaultVariants: {
|
|
7817
|
+
direction: "vertical",
|
|
7818
|
+
state: "default"
|
|
7819
|
+
}
|
|
7820
|
+
}
|
|
7821
|
+
);
|
|
7822
|
+
var DropIndicator = React10.forwardRef(
|
|
7823
|
+
({ className, direction, state, ...props }, ref) => {
|
|
7824
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
7825
|
+
"div",
|
|
7826
|
+
{
|
|
7827
|
+
ref,
|
|
7828
|
+
"data-slot": "drop-indicator",
|
|
7829
|
+
"data-direction": direction ?? "vertical",
|
|
7830
|
+
"data-state": state ?? "default",
|
|
7831
|
+
"aria-hidden": "true",
|
|
7832
|
+
className: cn(dropIndicatorVariants({ direction, state }), className),
|
|
7833
|
+
...props
|
|
7834
|
+
}
|
|
7835
|
+
);
|
|
7836
|
+
}
|
|
7837
|
+
);
|
|
7838
|
+
DropIndicator.displayName = "DropIndicator";
|
|
7839
|
+
|
|
7840
|
+
// src/ui/badge.tsx
|
|
7841
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
7842
|
+
var badgeVariants = cva(
|
|
7843
|
+
"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",
|
|
7844
|
+
{
|
|
7845
|
+
variants: {
|
|
7846
|
+
variant: {
|
|
7847
|
+
default: "border-transparent bg-primary text-primary-foreground",
|
|
7848
|
+
secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
7849
|
+
destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
|
7850
|
+
outline: "text-foreground"
|
|
7851
|
+
}
|
|
7852
|
+
},
|
|
7853
|
+
defaultVariants: {
|
|
7854
|
+
variant: "default"
|
|
7855
|
+
}
|
|
7856
|
+
}
|
|
7857
|
+
);
|
|
7858
|
+
function Badge({ className, variant, ...props }) {
|
|
7859
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: cn(badgeVariants({ variant }), className), ...props });
|
|
7860
|
+
}
|
|
7861
|
+
|
|
7862
|
+
// src/OhhwellsBridge.tsx
|
|
7863
|
+
var import_lucide_react11 = require("lucide-react");
|
|
7864
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
7865
|
+
var PRIMARY2 = "#0885FE";
|
|
7866
|
+
var IMAGE_FADE_MS = 300;
|
|
7867
|
+
function runOpacityFade(el, onDone) {
|
|
7868
|
+
const anim = el.animate([{ opacity: 0 }, { opacity: 1 }], {
|
|
7869
|
+
duration: IMAGE_FADE_MS,
|
|
7870
|
+
easing: "ease",
|
|
7871
|
+
fill: "forwards"
|
|
7872
|
+
});
|
|
7873
|
+
let finished = false;
|
|
7874
|
+
const finish = () => {
|
|
7875
|
+
if (finished) return;
|
|
7876
|
+
finished = true;
|
|
7877
|
+
anim.cancel();
|
|
7878
|
+
el.style.opacity = "";
|
|
7879
|
+
onDone();
|
|
7880
|
+
};
|
|
7881
|
+
anim.finished.then(finish).catch(finish);
|
|
7882
|
+
window.setTimeout(finish, IMAGE_FADE_MS + 100);
|
|
7883
|
+
}
|
|
7884
|
+
function fadeInImageElement(img, onReady) {
|
|
7885
|
+
onReady();
|
|
7886
|
+
img.style.opacity = "0";
|
|
7887
|
+
runOpacityFade(img, () => {
|
|
7888
|
+
img.style.opacity = "";
|
|
7889
|
+
});
|
|
7890
|
+
}
|
|
7891
|
+
function applyEditableImageSrc(img, url) {
|
|
7892
|
+
img.removeAttribute("srcset");
|
|
7893
|
+
img.removeAttribute("sizes");
|
|
7894
|
+
img.src = url;
|
|
7895
|
+
}
|
|
7896
|
+
function fadeInBgImage(el, url, onReady) {
|
|
7897
|
+
const prevPos = el.style.position;
|
|
7898
|
+
if (!prevPos || prevPos === "static") el.style.position = "relative";
|
|
7899
|
+
const layer = document.createElement("div");
|
|
7900
|
+
layer.setAttribute("data-ohw-bg-fade-layer", "");
|
|
6610
7901
|
Object.assign(layer.style, {
|
|
6611
7902
|
position: "absolute",
|
|
6612
7903
|
inset: "0",
|
|
@@ -6749,7 +8040,7 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
6749
8040
|
const root = (0, import_client.createRoot)(container);
|
|
6750
8041
|
(0, import_react_dom2.flushSync)(() => {
|
|
6751
8042
|
root.render(
|
|
6752
|
-
/* @__PURE__ */ (0,
|
|
8043
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
6753
8044
|
SchedulingWidget,
|
|
6754
8045
|
{
|
|
6755
8046
|
notifyOnConnect,
|
|
@@ -6811,7 +8102,20 @@ function isDragHandleDisabled(el) {
|
|
|
6811
8102
|
return raw === "true" || raw === "";
|
|
6812
8103
|
});
|
|
6813
8104
|
}
|
|
6814
|
-
function
|
|
8105
|
+
function canDragNavigationItem(anchor) {
|
|
8106
|
+
const { key, disabled } = getNavigationItemReorderState(anchor);
|
|
8107
|
+
return Boolean(key) && !disabled;
|
|
8108
|
+
}
|
|
8109
|
+
function syncNavigationDragCursorAttrs() {
|
|
8110
|
+
document.querySelectorAll("nav [data-ohw-href-key], footer [data-ohw-href-key]").forEach((el) => {
|
|
8111
|
+
if (!isNavigationItem(el) || !canDragNavigationItem(el)) {
|
|
8112
|
+
el.removeAttribute("data-ohw-can-drag");
|
|
8113
|
+
return;
|
|
8114
|
+
}
|
|
8115
|
+
el.setAttribute("data-ohw-can-drag", "");
|
|
8116
|
+
});
|
|
8117
|
+
}
|
|
8118
|
+
function collectEditableNodes(extraContent) {
|
|
6815
8119
|
const nodes = Array.from(document.querySelectorAll("[data-ohw-editable]")).map((el) => {
|
|
6816
8120
|
if (el.dataset.ohwEditable === "image") {
|
|
6817
8121
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
@@ -6839,6 +8143,14 @@ function collectEditableNodes() {
|
|
|
6839
8143
|
if (!key) return;
|
|
6840
8144
|
nodes.push({ key, type: "link", text: getLinkHref2(el) });
|
|
6841
8145
|
});
|
|
8146
|
+
if (extraContent) {
|
|
8147
|
+
for (const key of [NAV_ORDER_KEY, FOOTER_ORDER_KEY, NAV_COUNT_KEY]) {
|
|
8148
|
+
const text = extraContent[key];
|
|
8149
|
+
if (typeof text === "string" && text.length > 0) {
|
|
8150
|
+
nodes.push({ key, type: "meta", text });
|
|
8151
|
+
}
|
|
8152
|
+
}
|
|
8153
|
+
}
|
|
6842
8154
|
document.querySelectorAll('[data-ohw-editable="video"]').forEach((el) => {
|
|
6843
8155
|
const key = el.dataset.ohwKey ?? "";
|
|
6844
8156
|
const video = getVideoEl(el);
|
|
@@ -6952,6 +8264,11 @@ function getNavigationItemAnchor(el) {
|
|
|
6952
8264
|
function isNavigationItem(el) {
|
|
6953
8265
|
return getNavigationItemAnchor(el) !== null;
|
|
6954
8266
|
}
|
|
8267
|
+
function listNavigationItems() {
|
|
8268
|
+
return Array.from(
|
|
8269
|
+
document.querySelectorAll("nav [data-ohw-href-key], footer [data-ohw-href-key]")
|
|
8270
|
+
).filter((el) => isNavigationItem(el));
|
|
8271
|
+
}
|
|
6955
8272
|
function getNavigationItemReorderState(anchor) {
|
|
6956
8273
|
if (isNavbarButton2(anchor)) return { key: null, disabled: false };
|
|
6957
8274
|
return getReorderHandleStateFromAnchor(anchor);
|
|
@@ -6980,18 +8297,20 @@ function getNavigationRoot(el) {
|
|
|
6980
8297
|
if (explicit) return explicit;
|
|
6981
8298
|
return el.closest("nav, footer, aside");
|
|
6982
8299
|
}
|
|
8300
|
+
function countFooterNavItems(el) {
|
|
8301
|
+
return Array.from(el.querySelectorAll("[data-ohw-href-key]")).filter(isNavigationItem).length;
|
|
8302
|
+
}
|
|
6983
8303
|
function findFooterItemGroup(item) {
|
|
8304
|
+
const explicit = item.closest("[data-ohw-footer-col], [data-ohw-footer-column]");
|
|
8305
|
+
if (explicit) return explicit;
|
|
6984
8306
|
const footer = item.closest("footer");
|
|
6985
8307
|
if (!footer) return null;
|
|
6986
8308
|
let node = item.parentElement;
|
|
6987
8309
|
while (node && node !== footer) {
|
|
6988
|
-
|
|
6989
|
-
node.querySelectorAll(":scope > [data-ohw-href-key]")
|
|
6990
|
-
).some(isNavigationItem);
|
|
6991
|
-
if (hasDirectNavItems) return node;
|
|
8310
|
+
if (countFooterNavItems(node) >= 2) return node;
|
|
6992
8311
|
node = node.parentElement;
|
|
6993
8312
|
}
|
|
6994
|
-
return
|
|
8313
|
+
return footer;
|
|
6995
8314
|
}
|
|
6996
8315
|
function isNavigationRoot(el) {
|
|
6997
8316
|
return el.hasAttribute("data-ohw-nav-root") || el.matches("nav, footer, aside");
|
|
@@ -6999,16 +8318,49 @@ function isNavigationRoot(el) {
|
|
|
6999
8318
|
function isInferredFooterGroup(el) {
|
|
7000
8319
|
const footer = el.closest("footer");
|
|
7001
8320
|
if (!footer || el === footer) return false;
|
|
7002
|
-
|
|
8321
|
+
if (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column")) return true;
|
|
8322
|
+
return countFooterNavItems(el) >= 2;
|
|
7003
8323
|
}
|
|
7004
8324
|
function isNavigationContainer(el) {
|
|
7005
|
-
return el.hasAttribute("data-ohw-nav-container") || isNavigationRoot(el) || isInferredFooterGroup(el);
|
|
8325
|
+
return el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isNavigationRoot(el) || isInferredFooterGroup(el);
|
|
8326
|
+
}
|
|
8327
|
+
function isNavbarLinksContainer(el) {
|
|
8328
|
+
return el.hasAttribute("data-ohw-nav-container");
|
|
8329
|
+
}
|
|
8330
|
+
function getFooterColumn(el) {
|
|
8331
|
+
return el.closest("[data-ohw-footer-col], [data-ohw-footer-column]");
|
|
8332
|
+
}
|
|
8333
|
+
function resolveFooterColumnSelectionTarget(target, clientX, clientY) {
|
|
8334
|
+
if (getNavigationItemAnchor(target)) return null;
|
|
8335
|
+
const column = getFooterColumn(target);
|
|
8336
|
+
if (!column) return null;
|
|
8337
|
+
if (isPointOverNavItem(column, clientX, clientY)) return null;
|
|
8338
|
+
return column;
|
|
7006
8339
|
}
|
|
7007
8340
|
function isPointOverNavigation(x, y) {
|
|
8341
|
+
const roots = /* @__PURE__ */ new Set();
|
|
7008
8342
|
const navRoot = document.querySelector("[data-ohw-nav-root]") ?? document.querySelector("nav");
|
|
7009
|
-
if (
|
|
7010
|
-
const
|
|
7011
|
-
|
|
8343
|
+
if (navRoot) roots.add(navRoot);
|
|
8344
|
+
const footer = document.querySelector("footer");
|
|
8345
|
+
if (footer) roots.add(footer);
|
|
8346
|
+
for (const root of roots) {
|
|
8347
|
+
const r2 = root.getBoundingClientRect();
|
|
8348
|
+
if (x >= r2.left && x <= r2.right && y >= r2.top && y <= r2.bottom) return true;
|
|
8349
|
+
}
|
|
8350
|
+
return false;
|
|
8351
|
+
}
|
|
8352
|
+
function findHoveredNavOrFooterContainer(x, y) {
|
|
8353
|
+
const candidates = [
|
|
8354
|
+
...document.querySelectorAll("[data-ohw-nav-container]"),
|
|
8355
|
+
...listFooterColumns()
|
|
8356
|
+
];
|
|
8357
|
+
for (const container of candidates) {
|
|
8358
|
+
const r2 = container.getBoundingClientRect();
|
|
8359
|
+
if (x < r2.left || x > r2.right || y < r2.top || y > r2.bottom) continue;
|
|
8360
|
+
if (isPointOverNavItem(container, x, y)) continue;
|
|
8361
|
+
return container;
|
|
8362
|
+
}
|
|
8363
|
+
return null;
|
|
7012
8364
|
}
|
|
7013
8365
|
function isPointOverNavItem(container, x, y) {
|
|
7014
8366
|
return Array.from(container.querySelectorAll("[data-ohw-href-key]")).some((el) => {
|
|
@@ -7041,36 +8393,63 @@ function getNavigationSelectionParent(el) {
|
|
|
7041
8393
|
if (isNavigationItem(el)) {
|
|
7042
8394
|
const explicit = el.closest("[data-ohw-nav-container]");
|
|
7043
8395
|
if (explicit) return explicit;
|
|
8396
|
+
const footerColumn = getFooterColumn(el);
|
|
8397
|
+
if (footerColumn) return footerColumn;
|
|
7044
8398
|
const footerGroup = findFooterItemGroup(el);
|
|
7045
8399
|
if (footerGroup) return footerGroup;
|
|
7046
8400
|
return getNavigationRoot(el);
|
|
7047
8401
|
}
|
|
7048
|
-
if (el.hasAttribute("data-ohw-nav-container") || isInferredFooterGroup(el)) {
|
|
8402
|
+
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup(el)) {
|
|
7049
8403
|
return getNavigationRoot(el);
|
|
7050
8404
|
}
|
|
7051
8405
|
return null;
|
|
7052
8406
|
}
|
|
8407
|
+
function collectNavigationItemSiblingHintRects(selected) {
|
|
8408
|
+
if (!isNavigationItem(selected)) return [];
|
|
8409
|
+
const footerColumn = getFooterColumn(selected);
|
|
8410
|
+
if (footerColumn) {
|
|
8411
|
+
return listFooterLinksInColumn(footerColumn).filter((link) => link !== selected).map((link) => link.getBoundingClientRect());
|
|
8412
|
+
}
|
|
8413
|
+
const navContainer = selected.closest("[data-ohw-nav-container], [data-ohw-nav-drawer]");
|
|
8414
|
+
if (navContainer) {
|
|
8415
|
+
return Array.from(navContainer.querySelectorAll("[data-ohw-href-key]")).filter((el) => isNavigationItem(el) && el !== selected).map((el) => el.getBoundingClientRect());
|
|
8416
|
+
}
|
|
8417
|
+
return listNavigationItems().filter((el) => el !== selected).map((el) => el.getBoundingClientRect());
|
|
8418
|
+
}
|
|
7053
8419
|
function placeCaretAtPoint(el, x, y) {
|
|
7054
8420
|
const selection = window.getSelection();
|
|
7055
8421
|
if (!selection) return;
|
|
7056
|
-
|
|
7057
|
-
|
|
7058
|
-
|
|
7059
|
-
|
|
7060
|
-
|
|
7061
|
-
|
|
8422
|
+
const overlays = Array.from(
|
|
8423
|
+
document.querySelectorAll(
|
|
8424
|
+
"[data-ohw-item-drag-surface], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-ohw-item-toolbar-anchor]"
|
|
8425
|
+
)
|
|
8426
|
+
);
|
|
8427
|
+
const prevPointerEvents = overlays.map((node) => node.style.pointerEvents);
|
|
8428
|
+
for (const node of overlays) node.style.pointerEvents = "none";
|
|
8429
|
+
try {
|
|
8430
|
+
if (typeof document.caretRangeFromPoint === "function") {
|
|
8431
|
+
const range = document.caretRangeFromPoint(x, y);
|
|
8432
|
+
if (range && el.contains(range.startContainer)) {
|
|
8433
|
+
selection.removeAllRanges();
|
|
8434
|
+
selection.addRange(range);
|
|
8435
|
+
return;
|
|
8436
|
+
}
|
|
7062
8437
|
}
|
|
7063
|
-
|
|
7064
|
-
|
|
7065
|
-
|
|
7066
|
-
|
|
7067
|
-
|
|
7068
|
-
|
|
7069
|
-
|
|
7070
|
-
|
|
7071
|
-
|
|
7072
|
-
|
|
8438
|
+
const caretPositionFromPoint = document.caretPositionFromPoint;
|
|
8439
|
+
if (typeof caretPositionFromPoint === "function") {
|
|
8440
|
+
const position = caretPositionFromPoint(x, y);
|
|
8441
|
+
if (position && el.contains(position.offsetNode)) {
|
|
8442
|
+
const range = document.createRange();
|
|
8443
|
+
range.setStart(position.offsetNode, position.offset);
|
|
8444
|
+
range.collapse(true);
|
|
8445
|
+
selection.removeAllRanges();
|
|
8446
|
+
selection.addRange(range);
|
|
8447
|
+
}
|
|
7073
8448
|
}
|
|
8449
|
+
} finally {
|
|
8450
|
+
overlays.forEach((node, i) => {
|
|
8451
|
+
node.style.pointerEvents = prevPointerEvents[i] ?? "";
|
|
8452
|
+
});
|
|
7074
8453
|
}
|
|
7075
8454
|
}
|
|
7076
8455
|
function selectAllTextInEditable(el) {
|
|
@@ -7191,9 +8570,16 @@ function sanitizeHtml(html) {
|
|
|
7191
8570
|
if (!SAFE_TAGS.has(el.tagName)) {
|
|
7192
8571
|
parent.replaceChild(document.createTextNode(el.textContent ?? ""), el);
|
|
7193
8572
|
} else {
|
|
7194
|
-
const
|
|
8573
|
+
const htmlEl = el;
|
|
8574
|
+
const textAlign = htmlEl.style?.textAlign || el.getAttribute("align") || "";
|
|
8575
|
+
const fontWeight = htmlEl.style?.fontWeight || "";
|
|
8576
|
+
const fontStyle = htmlEl.style?.fontStyle || "";
|
|
8577
|
+
const textDecorationLine = htmlEl.style?.textDecorationLine || htmlEl.style?.textDecoration || "";
|
|
7195
8578
|
for (const attr of Array.from(el.attributes)) el.removeAttribute(attr.name);
|
|
7196
|
-
if (textAlign)
|
|
8579
|
+
if (textAlign) htmlEl.style.textAlign = textAlign;
|
|
8580
|
+
if (fontWeight) htmlEl.style.fontWeight = fontWeight;
|
|
8581
|
+
if (fontStyle) htmlEl.style.fontStyle = fontStyle;
|
|
8582
|
+
if (textDecorationLine) htmlEl.style.textDecorationLine = textDecorationLine;
|
|
7197
8583
|
walk(el);
|
|
7198
8584
|
}
|
|
7199
8585
|
}
|
|
@@ -7212,6 +8598,9 @@ var ICONS = {
|
|
|
7212
8598
|
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"/>',
|
|
7213
8599
|
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"/>'
|
|
7214
8600
|
};
|
|
8601
|
+
var SELECTION_CHROME_GAP2 = 4;
|
|
8602
|
+
var TOOLBAR_STROKE_GAP2 = 4;
|
|
8603
|
+
var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
|
|
7215
8604
|
var TOOLBAR_GROUPS = [
|
|
7216
8605
|
[
|
|
7217
8606
|
{ cmd: "bold", title: "Bold" },
|
|
@@ -7233,10 +8622,11 @@ function EditGlowChrome({
|
|
|
7233
8622
|
rect,
|
|
7234
8623
|
elRef,
|
|
7235
8624
|
reorderHrefKey,
|
|
7236
|
-
dragDisabled = false
|
|
8625
|
+
dragDisabled = false,
|
|
8626
|
+
hideHandle = false
|
|
7237
8627
|
}) {
|
|
7238
|
-
const GAP =
|
|
7239
|
-
return /* @__PURE__ */ (0,
|
|
8628
|
+
const GAP = SELECTION_CHROME_GAP2;
|
|
8629
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
7240
8630
|
"div",
|
|
7241
8631
|
{
|
|
7242
8632
|
ref: elRef,
|
|
@@ -7251,7 +8641,7 @@ function EditGlowChrome({
|
|
|
7251
8641
|
zIndex: 2147483646
|
|
7252
8642
|
},
|
|
7253
8643
|
children: [
|
|
7254
|
-
/* @__PURE__ */ (0,
|
|
8644
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
7255
8645
|
"div",
|
|
7256
8646
|
{
|
|
7257
8647
|
style: {
|
|
@@ -7259,12 +8649,12 @@ function EditGlowChrome({
|
|
|
7259
8649
|
inset: 0,
|
|
7260
8650
|
border: "2px solid var(--ohw-primary, #0885FE)",
|
|
7261
8651
|
borderRadius: 8,
|
|
7262
|
-
boxShadow: "0 0 0 4px
|
|
8652
|
+
boxShadow: "0 0 0 4px color-mix(in srgb, var(--ohw-primary, #0885FE) 12%, transparent)",
|
|
7263
8653
|
pointerEvents: "none"
|
|
7264
8654
|
}
|
|
7265
8655
|
}
|
|
7266
8656
|
),
|
|
7267
|
-
reorderHrefKey && /* @__PURE__ */ (0,
|
|
8657
|
+
reorderHrefKey && !hideHandle && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
7268
8658
|
"div",
|
|
7269
8659
|
{
|
|
7270
8660
|
"data-ohw-drag-handle-container": "",
|
|
@@ -7276,7 +8666,7 @@ function EditGlowChrome({
|
|
|
7276
8666
|
transform: "translate(calc(-100% - 7px), -50%)",
|
|
7277
8667
|
pointerEvents: dragDisabled ? "none" : "auto"
|
|
7278
8668
|
},
|
|
7279
|
-
children: /* @__PURE__ */ (0,
|
|
8669
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
7280
8670
|
DragHandle,
|
|
7281
8671
|
{
|
|
7282
8672
|
"aria-label": `Reorder ${reorderHrefKey}`,
|
|
@@ -7307,6 +8697,7 @@ function applyVisibleViewport(el, parentScroll) {
|
|
|
7307
8697
|
el.style.top = `${top}px`;
|
|
7308
8698
|
el.style.height = `${height}px`;
|
|
7309
8699
|
}
|
|
8700
|
+
var TOOLBAR_EDGE_MARGIN2 = 4;
|
|
7310
8701
|
function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
|
|
7311
8702
|
const isAbove = transform.includes("translateY(-100%)");
|
|
7312
8703
|
let visualTop = isAbove ? top - approxH : top;
|
|
@@ -7330,10 +8721,16 @@ function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
|
|
|
7330
8721
|
const pinnedTop = Math.min(maxBottom - approxH, Math.max(minTop, clip.top + gap));
|
|
7331
8722
|
return { top: pinnedTop + approxH, transform: "translateX(-50%) translateY(-100%)" };
|
|
7332
8723
|
}
|
|
7333
|
-
function
|
|
7334
|
-
const
|
|
8724
|
+
function clampToolbarLeft(centerX, toolbarWidth) {
|
|
8725
|
+
const half = toolbarWidth / 2;
|
|
8726
|
+
return Math.max(
|
|
8727
|
+
TOOLBAR_EDGE_MARGIN2 + half,
|
|
8728
|
+
Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN2 - half)
|
|
8729
|
+
);
|
|
8730
|
+
}
|
|
8731
|
+
function calcToolbarPos(rect, parentScroll, toolbarW = 306) {
|
|
8732
|
+
const GAP = TOOLBAR_OFFSET_FROM_ELEMENT;
|
|
7335
8733
|
const APPROX_H = 32;
|
|
7336
|
-
const APPROX_W = approxW;
|
|
7337
8734
|
const clip = getIframeVisibleClip(parentScroll);
|
|
7338
8735
|
const clipTop = clip?.top ?? 0;
|
|
7339
8736
|
const canvasTopInIframe = parentScroll != null ? parentScroll.headerH - parentScroll.iframeOffsetTop : 0;
|
|
@@ -7363,13 +8760,86 @@ function calcToolbarPos(rect, parentScroll, approxW = 306) {
|
|
|
7363
8760
|
transform = clamped.transform;
|
|
7364
8761
|
}
|
|
7365
8762
|
const rawLeft = rect.left + rect.width / 2;
|
|
7366
|
-
const left =
|
|
8763
|
+
const left = clampToolbarLeft(rawLeft, toolbarW);
|
|
7367
8764
|
return { top, left, transform };
|
|
7368
8765
|
}
|
|
7369
8766
|
function resolveItemInteractionState(rect, parentScroll) {
|
|
7370
8767
|
const { transform } = calcToolbarPos(rect, parentScroll, 120);
|
|
7371
8768
|
return transform.includes("translateY(-100%)") ? "active-top" : "active-bottom";
|
|
7372
8769
|
}
|
|
8770
|
+
function resolveSelectionStartElement(sel) {
|
|
8771
|
+
if (!sel || sel.rangeCount === 0) return null;
|
|
8772
|
+
const range = sel.getRangeAt(0);
|
|
8773
|
+
let startNode = range.startContainer;
|
|
8774
|
+
if (startNode.nodeType === Node.ELEMENT_NODE) {
|
|
8775
|
+
const el = startNode;
|
|
8776
|
+
startNode = el.childNodes[range.startOffset] ?? el.childNodes[range.startOffset - 1] ?? el;
|
|
8777
|
+
}
|
|
8778
|
+
return startNode.nodeType === Node.TEXT_NODE ? startNode.parentElement : startNode;
|
|
8779
|
+
}
|
|
8780
|
+
function detectActiveFormats(startEl, activeRoot) {
|
|
8781
|
+
const formats = /* @__PURE__ */ new Set();
|
|
8782
|
+
const cs = getComputedStyle(startEl);
|
|
8783
|
+
const weight = parseInt(cs.fontWeight, 10);
|
|
8784
|
+
let hasBold = cs.fontWeight === "bold" || !Number.isNaN(weight) && weight >= 600;
|
|
8785
|
+
let hasItalic = cs.fontStyle === "italic" || cs.fontStyle === "oblique";
|
|
8786
|
+
let hasUnderline = false;
|
|
8787
|
+
let hasStrike = false;
|
|
8788
|
+
let hasUl = false;
|
|
8789
|
+
let hasOl = false;
|
|
8790
|
+
for (let el = startEl; el; el = el.parentElement) {
|
|
8791
|
+
if (el.tagName === "B" || el.tagName === "STRONG") hasBold = true;
|
|
8792
|
+
if (el.tagName === "I" || el.tagName === "EM") hasItalic = true;
|
|
8793
|
+
const decoration = getComputedStyle(el).textDecorationLine;
|
|
8794
|
+
if (decoration.includes("underline") || el.tagName === "U" || el.tagName === "INS") hasUnderline = true;
|
|
8795
|
+
if (decoration.includes("line-through") || el.tagName === "S" || el.tagName === "STRIKE" || el.tagName === "DEL") hasStrike = true;
|
|
8796
|
+
if (el.tagName === "UL") hasUl = true;
|
|
8797
|
+
if (el.tagName === "OL") hasOl = true;
|
|
8798
|
+
if (el === activeRoot) break;
|
|
8799
|
+
}
|
|
8800
|
+
if (hasBold) formats.add("bold");
|
|
8801
|
+
if (hasItalic) formats.add("italic");
|
|
8802
|
+
if (hasUnderline) formats.add("underline");
|
|
8803
|
+
if (hasStrike) formats.add("strikeThrough");
|
|
8804
|
+
if (hasUl) formats.add("insertUnorderedList");
|
|
8805
|
+
if (hasOl) formats.add("insertOrderedList");
|
|
8806
|
+
const block = startEl.closest("div, p, h1, h2, h3, h4, h5, h6, li, td, th") ?? startEl;
|
|
8807
|
+
const align = getComputedStyle(block).textAlign;
|
|
8808
|
+
if (align === "center") formats.add("justifyCenter");
|
|
8809
|
+
else if (align === "right" || align === "end") formats.add("justifyRight");
|
|
8810
|
+
else formats.add("justifyLeft");
|
|
8811
|
+
return formats;
|
|
8812
|
+
}
|
|
8813
|
+
function setsEqual(a, b) {
|
|
8814
|
+
if (a.size !== b.size) return false;
|
|
8815
|
+
for (const item of a) {
|
|
8816
|
+
if (!b.has(item)) return false;
|
|
8817
|
+
}
|
|
8818
|
+
return true;
|
|
8819
|
+
}
|
|
8820
|
+
function textOffsetInRoot(root, node, offset) {
|
|
8821
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
|
|
8822
|
+
let total = 0;
|
|
8823
|
+
let current;
|
|
8824
|
+
while (current = walker.nextNode()) {
|
|
8825
|
+
if (current === node) return total + offset;
|
|
8826
|
+
total += (current.textContent ?? "").length;
|
|
8827
|
+
}
|
|
8828
|
+
return total;
|
|
8829
|
+
}
|
|
8830
|
+
function pointAtTextOffset(root, targetOffset) {
|
|
8831
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
|
|
8832
|
+
let total = 0;
|
|
8833
|
+
let current;
|
|
8834
|
+
let last = null;
|
|
8835
|
+
while (current = walker.nextNode()) {
|
|
8836
|
+
const len = (current.textContent ?? "").length;
|
|
8837
|
+
if (total + len >= targetOffset) return { node: current, offset: targetOffset - total };
|
|
8838
|
+
total += len;
|
|
8839
|
+
last = current;
|
|
8840
|
+
}
|
|
8841
|
+
return last ? { node: last, offset: (last.textContent ?? "").length } : null;
|
|
8842
|
+
}
|
|
7373
8843
|
function FloatingToolbar({
|
|
7374
8844
|
rect,
|
|
7375
8845
|
parentScroll,
|
|
@@ -7379,11 +8849,37 @@ function FloatingToolbar({
|
|
|
7379
8849
|
showEditLink,
|
|
7380
8850
|
onEditLink
|
|
7381
8851
|
}) {
|
|
7382
|
-
const
|
|
7383
|
-
|
|
8852
|
+
const localRef = import_react9.default.useRef(null);
|
|
8853
|
+
const [measuredW, setMeasuredW] = import_react9.default.useState(330);
|
|
8854
|
+
const setRefs = import_react9.default.useCallback(
|
|
8855
|
+
(node) => {
|
|
8856
|
+
localRef.current = node;
|
|
8857
|
+
if (typeof elRef === "function") elRef(node);
|
|
8858
|
+
else if (elRef) elRef.current = node;
|
|
8859
|
+
if (node) {
|
|
8860
|
+
const w = node.offsetWidth;
|
|
8861
|
+
if (w > 0) setMeasuredW(w);
|
|
8862
|
+
}
|
|
8863
|
+
},
|
|
8864
|
+
[elRef]
|
|
8865
|
+
);
|
|
8866
|
+
import_react9.default.useLayoutEffect(() => {
|
|
8867
|
+
const node = localRef.current;
|
|
8868
|
+
if (!node) return;
|
|
8869
|
+
const update = () => {
|
|
8870
|
+
const w = node.offsetWidth;
|
|
8871
|
+
if (w > 0) setMeasuredW(w);
|
|
8872
|
+
};
|
|
8873
|
+
update();
|
|
8874
|
+
const ro = new ResizeObserver(update);
|
|
8875
|
+
ro.observe(node);
|
|
8876
|
+
return () => ro.disconnect();
|
|
8877
|
+
}, [showEditLink, activeCommands]);
|
|
8878
|
+
const { top, left, transform } = calcToolbarPos(rect, parentScroll, measuredW);
|
|
8879
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
7384
8880
|
"div",
|
|
7385
8881
|
{
|
|
7386
|
-
ref:
|
|
8882
|
+
ref: setRefs,
|
|
7387
8883
|
style: {
|
|
7388
8884
|
position: "fixed",
|
|
7389
8885
|
top,
|
|
@@ -7392,12 +8888,12 @@ function FloatingToolbar({
|
|
|
7392
8888
|
zIndex: 2147483647,
|
|
7393
8889
|
pointerEvents: "auto"
|
|
7394
8890
|
},
|
|
7395
|
-
children: /* @__PURE__ */ (0,
|
|
7396
|
-
TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0,
|
|
7397
|
-
gi > 0 && /* @__PURE__ */ (0,
|
|
8891
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(CustomToolbar, { children: [
|
|
8892
|
+
TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react9.default.Fragment, { children: [
|
|
8893
|
+
gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(CustomToolbarDivider, {}),
|
|
7398
8894
|
btns.map((btn) => {
|
|
7399
8895
|
const isActive = activeCommands.has(btn.cmd);
|
|
7400
|
-
return /* @__PURE__ */ (0,
|
|
8896
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
7401
8897
|
CustomToolbarButton,
|
|
7402
8898
|
{
|
|
7403
8899
|
title: btn.title,
|
|
@@ -7406,7 +8902,7 @@ function FloatingToolbar({
|
|
|
7406
8902
|
e.preventDefault();
|
|
7407
8903
|
onCommand(btn.cmd);
|
|
7408
8904
|
},
|
|
7409
|
-
children: /* @__PURE__ */ (0,
|
|
8905
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
7410
8906
|
"svg",
|
|
7411
8907
|
{
|
|
7412
8908
|
width: "16",
|
|
@@ -7427,7 +8923,7 @@ function FloatingToolbar({
|
|
|
7427
8923
|
);
|
|
7428
8924
|
})
|
|
7429
8925
|
] }, gi)),
|
|
7430
|
-
showEditLink ? /* @__PURE__ */ (0,
|
|
8926
|
+
showEditLink ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
7431
8927
|
CustomToolbarButton,
|
|
7432
8928
|
{
|
|
7433
8929
|
type: "button",
|
|
@@ -7441,7 +8937,7 @@ function FloatingToolbar({
|
|
|
7441
8937
|
e.preventDefault();
|
|
7442
8938
|
e.stopPropagation();
|
|
7443
8939
|
},
|
|
7444
|
-
children: /* @__PURE__ */ (0,
|
|
8940
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react11.Link, { className: "size-4 shrink-0", "aria-hidden": true })
|
|
7445
8941
|
}
|
|
7446
8942
|
) : null
|
|
7447
8943
|
] })
|
|
@@ -7458,7 +8954,7 @@ function StateToggle({
|
|
|
7458
8954
|
states,
|
|
7459
8955
|
onStateChange
|
|
7460
8956
|
}) {
|
|
7461
|
-
return /* @__PURE__ */ (0,
|
|
8957
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
7462
8958
|
ToggleGroup,
|
|
7463
8959
|
{
|
|
7464
8960
|
"data-ohw-state-toggle": "",
|
|
@@ -7472,7 +8968,7 @@ function StateToggle({
|
|
|
7472
8968
|
left: rect.right - 8,
|
|
7473
8969
|
transform: "translateX(-100%)"
|
|
7474
8970
|
},
|
|
7475
|
-
children: states.map((state) => /* @__PURE__ */ (0,
|
|
8971
|
+
children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
|
|
7476
8972
|
}
|
|
7477
8973
|
);
|
|
7478
8974
|
}
|
|
@@ -7499,8 +8995,8 @@ function OhhwellsBridge() {
|
|
|
7499
8995
|
const router = (0, import_navigation2.useRouter)();
|
|
7500
8996
|
const searchParams = (0, import_navigation2.useSearchParams)();
|
|
7501
8997
|
const isEditMode = isEditSessionActive();
|
|
7502
|
-
const [bridgeRoot, setBridgeRoot] = (0,
|
|
7503
|
-
(0,
|
|
8998
|
+
const [bridgeRoot, setBridgeRoot] = (0, import_react9.useState)(null);
|
|
8999
|
+
(0, import_react9.useEffect)(() => {
|
|
7504
9000
|
const figtreeFontId = "ohw-figtree-font";
|
|
7505
9001
|
if (!document.getElementById(figtreeFontId)) {
|
|
7506
9002
|
const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
|
|
@@ -7528,91 +9024,137 @@ function OhhwellsBridge() {
|
|
|
7528
9024
|
const subdomainFromQuery = searchParams.get("subdomain");
|
|
7529
9025
|
const subdomain = resolveSubdomain(subdomainFromQuery);
|
|
7530
9026
|
useLinkHrefGuardian(pathname, subdomain, isEditMode);
|
|
7531
|
-
const postToParent2 = (0,
|
|
9027
|
+
const postToParent2 = (0, import_react9.useCallback)((data) => {
|
|
7532
9028
|
if (typeof window !== "undefined" && window.parent !== window) {
|
|
7533
9029
|
window.parent.postMessage(data, "*");
|
|
7534
9030
|
}
|
|
7535
9031
|
}, []);
|
|
7536
|
-
const [fetchState, setFetchState] = (0,
|
|
7537
|
-
const autoSaveTimers = (0,
|
|
7538
|
-
const activeElRef = (0,
|
|
7539
|
-
const
|
|
7540
|
-
const
|
|
7541
|
-
const
|
|
7542
|
-
const
|
|
7543
|
-
const
|
|
7544
|
-
const
|
|
7545
|
-
const
|
|
9032
|
+
const [fetchState, setFetchState] = (0, import_react9.useState)("idle");
|
|
9033
|
+
const autoSaveTimers = (0, import_react9.useRef)(/* @__PURE__ */ new Map());
|
|
9034
|
+
const activeElRef = (0, import_react9.useRef)(null);
|
|
9035
|
+
const pointerHeldRef = (0, import_react9.useRef)(false);
|
|
9036
|
+
const selectedElRef = (0, import_react9.useRef)(null);
|
|
9037
|
+
const selectedHrefKeyRef = (0, import_react9.useRef)(null);
|
|
9038
|
+
const selectedFooterColAttrRef = (0, import_react9.useRef)(null);
|
|
9039
|
+
const originalContentRef = (0, import_react9.useRef)(null);
|
|
9040
|
+
const activeStateElRef = (0, import_react9.useRef)(null);
|
|
9041
|
+
const parentScrollRef = (0, import_react9.useRef)(null);
|
|
9042
|
+
const visibleViewportRef = (0, import_react9.useRef)(null);
|
|
9043
|
+
const [dialogPortalContainer, setDialogPortalContainer] = (0, import_react9.useState)(null);
|
|
9044
|
+
const attachVisibleViewport = (0, import_react9.useCallback)((node) => {
|
|
7546
9045
|
visibleViewportRef.current = node;
|
|
7547
9046
|
setDialogPortalContainer(node);
|
|
7548
9047
|
if (node) applyVisibleViewport(node, parentScrollRef.current);
|
|
7549
9048
|
}, []);
|
|
7550
|
-
const toolbarElRef = (0,
|
|
7551
|
-
const glowElRef = (0,
|
|
7552
|
-
const hoveredImageRef = (0,
|
|
7553
|
-
const hoveredImageHasTextOverlapRef = (0,
|
|
7554
|
-
const dragOverElRef = (0,
|
|
7555
|
-
const [mediaHover, setMediaHover] = (0,
|
|
7556
|
-
const [uploadingRects, setUploadingRects] = (0,
|
|
7557
|
-
const hoveredGapRef = (0,
|
|
7558
|
-
const imageUnhoverTimerRef = (0,
|
|
7559
|
-
const imageShowTimerRef = (0,
|
|
7560
|
-
const editStylesRef = (0,
|
|
7561
|
-
const activateRef = (0,
|
|
9049
|
+
const toolbarElRef = (0, import_react9.useRef)(null);
|
|
9050
|
+
const glowElRef = (0, import_react9.useRef)(null);
|
|
9051
|
+
const hoveredImageRef = (0, import_react9.useRef)(null);
|
|
9052
|
+
const hoveredImageHasTextOverlapRef = (0, import_react9.useRef)(false);
|
|
9053
|
+
const dragOverElRef = (0, import_react9.useRef)(null);
|
|
9054
|
+
const [mediaHover, setMediaHover] = (0, import_react9.useState)(null);
|
|
9055
|
+
const [uploadingRects, setUploadingRects] = (0, import_react9.useState)({});
|
|
9056
|
+
const hoveredGapRef = (0, import_react9.useRef)(null);
|
|
9057
|
+
const imageUnhoverTimerRef = (0, import_react9.useRef)(null);
|
|
9058
|
+
const imageShowTimerRef = (0, import_react9.useRef)(null);
|
|
9059
|
+
const editStylesRef = (0, import_react9.useRef)(null);
|
|
9060
|
+
const activateRef = (0, import_react9.useRef)(() => {
|
|
7562
9061
|
});
|
|
7563
|
-
const deactivateRef = (0,
|
|
9062
|
+
const deactivateRef = (0, import_react9.useRef)(() => {
|
|
7564
9063
|
});
|
|
7565
|
-
const selectRef = (0,
|
|
9064
|
+
const selectRef = (0, import_react9.useRef)(() => {
|
|
7566
9065
|
});
|
|
7567
|
-
const selectFrameRef = (0,
|
|
9066
|
+
const selectFrameRef = (0, import_react9.useRef)(() => {
|
|
7568
9067
|
});
|
|
7569
|
-
const deselectRef = (0,
|
|
9068
|
+
const deselectRef = (0, import_react9.useRef)(() => {
|
|
7570
9069
|
});
|
|
7571
|
-
const reselectNavigationItemRef = (0,
|
|
9070
|
+
const reselectNavigationItemRef = (0, import_react9.useRef)(() => {
|
|
7572
9071
|
});
|
|
7573
|
-
const commitNavigationTextEditRef = (0,
|
|
9072
|
+
const commitNavigationTextEditRef = (0, import_react9.useRef)(() => {
|
|
7574
9073
|
});
|
|
7575
|
-
const refreshActiveCommandsRef = (0,
|
|
9074
|
+
const refreshActiveCommandsRef = (0, import_react9.useRef)(() => {
|
|
7576
9075
|
});
|
|
7577
|
-
const postToParentRef = (0,
|
|
9076
|
+
const postToParentRef = (0, import_react9.useRef)(postToParent2);
|
|
7578
9077
|
postToParentRef.current = postToParent2;
|
|
7579
|
-
const sectionsLoadedRef = (0,
|
|
7580
|
-
const pendingScheduleConfigRequests = (0,
|
|
7581
|
-
const [toolbarRect, setToolbarRect] = (0,
|
|
7582
|
-
const [toolbarVariant, setToolbarVariant] = (0,
|
|
7583
|
-
const toolbarVariantRef = (0,
|
|
9078
|
+
const sectionsLoadedRef = (0, import_react9.useRef)(false);
|
|
9079
|
+
const pendingScheduleConfigRequests = (0, import_react9.useRef)([]);
|
|
9080
|
+
const [toolbarRect, setToolbarRect] = (0, import_react9.useState)(null);
|
|
9081
|
+
const [toolbarVariant, setToolbarVariant] = (0, import_react9.useState)("none");
|
|
9082
|
+
const toolbarVariantRef = (0, import_react9.useRef)("none");
|
|
7584
9083
|
toolbarVariantRef.current = toolbarVariant;
|
|
7585
|
-
const [
|
|
7586
|
-
const [
|
|
7587
|
-
const [
|
|
7588
|
-
const [
|
|
7589
|
-
const [
|
|
7590
|
-
const [
|
|
7591
|
-
const [
|
|
7592
|
-
const
|
|
7593
|
-
const
|
|
7594
|
-
const
|
|
7595
|
-
const
|
|
7596
|
-
const
|
|
7597
|
-
const
|
|
7598
|
-
const [
|
|
7599
|
-
const [
|
|
7600
|
-
const
|
|
7601
|
-
const
|
|
7602
|
-
const
|
|
7603
|
-
const [
|
|
7604
|
-
const [
|
|
7605
|
-
const
|
|
7606
|
-
const
|
|
7607
|
-
const
|
|
7608
|
-
const
|
|
7609
|
-
const
|
|
9084
|
+
const [selectedIsCta, setSelectedIsCta] = (0, import_react9.useState)(false);
|
|
9085
|
+
const [reorderHrefKey, setReorderHrefKey] = (0, import_react9.useState)(null);
|
|
9086
|
+
const [reorderDragDisabled, setReorderDragDisabled] = (0, import_react9.useState)(false);
|
|
9087
|
+
const [toggleState, setToggleState] = (0, import_react9.useState)(null);
|
|
9088
|
+
const [maxBadge, setMaxBadge] = (0, import_react9.useState)(null);
|
|
9089
|
+
const [activeCommands, setActiveCommands] = (0, import_react9.useState)(/* @__PURE__ */ new Set());
|
|
9090
|
+
const [sectionGap, setSectionGap] = (0, import_react9.useState)(null);
|
|
9091
|
+
const [toolbarShowEditLink, setToolbarShowEditLink] = (0, import_react9.useState)(false);
|
|
9092
|
+
const hoveredNavContainerRef = (0, import_react9.useRef)(null);
|
|
9093
|
+
const [hoveredNavContainerRect, setHoveredNavContainerRect] = (0, import_react9.useState)(null);
|
|
9094
|
+
const hoveredItemElRef = (0, import_react9.useRef)(null);
|
|
9095
|
+
const [hoveredItemRect, setHoveredItemRect] = (0, import_react9.useState)(null);
|
|
9096
|
+
const siblingHintElRef = (0, import_react9.useRef)(null);
|
|
9097
|
+
const [siblingHintRect, setSiblingHintRect] = (0, import_react9.useState)(null);
|
|
9098
|
+
const [siblingHintRects, setSiblingHintRects] = (0, import_react9.useState)([]);
|
|
9099
|
+
const [isItemDragging, setIsItemDragging] = (0, import_react9.useState)(false);
|
|
9100
|
+
const [isFooterFrameSelection, setIsFooterFrameSelection] = (0, import_react9.useState)(false);
|
|
9101
|
+
const footerDragRef = (0, import_react9.useRef)(null);
|
|
9102
|
+
const [footerDropSlots, setFooterDropSlots] = (0, import_react9.useState)([]);
|
|
9103
|
+
const [activeFooterDropIndex, setActiveFooterDropIndex] = (0, import_react9.useState)(null);
|
|
9104
|
+
const [draggedItemRect, setDraggedItemRect] = (0, import_react9.useState)(null);
|
|
9105
|
+
const footerPointerDragRef = (0, import_react9.useRef)(null);
|
|
9106
|
+
const suppressNextClickRef = (0, import_react9.useRef)(false);
|
|
9107
|
+
const suppressClickUntilRef = (0, import_react9.useRef)(0);
|
|
9108
|
+
const [linkPopover, setLinkPopover] = (0, import_react9.useState)(null);
|
|
9109
|
+
const linkPopoverSessionRef = (0, import_react9.useRef)(null);
|
|
9110
|
+
const addNavAfterAnchorRef = (0, import_react9.useRef)(null);
|
|
9111
|
+
const editContentRef = (0, import_react9.useRef)({});
|
|
9112
|
+
const [sitePages, setSitePages] = (0, import_react9.useState)([]);
|
|
9113
|
+
const [sectionsByPath, setSectionsByPath] = (0, import_react9.useState)({});
|
|
9114
|
+
const sectionsPrefetchGenRef = (0, import_react9.useRef)(0);
|
|
9115
|
+
const setLinkPopoverRef = (0, import_react9.useRef)(setLinkPopover);
|
|
9116
|
+
const linkPopoverPanelRef = (0, import_react9.useRef)(null);
|
|
9117
|
+
const linkPopoverOpenRef = (0, import_react9.useRef)(false);
|
|
9118
|
+
const linkPopoverGraceUntilRef = (0, import_react9.useRef)(0);
|
|
7610
9119
|
setLinkPopoverRef.current = setLinkPopover;
|
|
7611
9120
|
linkPopoverSessionRef.current = linkPopover;
|
|
9121
|
+
const {
|
|
9122
|
+
navDragRef,
|
|
9123
|
+
navDropSlots,
|
|
9124
|
+
activeNavDropIndex,
|
|
9125
|
+
startNavLinkDrag,
|
|
9126
|
+
commitNavDrag,
|
|
9127
|
+
onNavDragOver,
|
|
9128
|
+
armNavPressFromChrome,
|
|
9129
|
+
refreshNavDragVisualsRef
|
|
9130
|
+
} = useNavItemDrag({
|
|
9131
|
+
isEditMode,
|
|
9132
|
+
editContentRef,
|
|
9133
|
+
selectedElRef,
|
|
9134
|
+
activeElRef,
|
|
9135
|
+
footerDragRef,
|
|
9136
|
+
suppressNextClickRef,
|
|
9137
|
+
suppressClickUntilRef,
|
|
9138
|
+
siblingHintElRef,
|
|
9139
|
+
postToParentRef,
|
|
9140
|
+
deselectRef,
|
|
9141
|
+
selectRef,
|
|
9142
|
+
deactivateRef,
|
|
9143
|
+
setLinkPopover: () => setLinkPopover(null),
|
|
9144
|
+
linkPopoverOpenRef,
|
|
9145
|
+
setIsItemDragging,
|
|
9146
|
+
setDraggedItemRect,
|
|
9147
|
+
setSiblingHintRect,
|
|
9148
|
+
setSiblingHintRects,
|
|
9149
|
+
setToolbarRect,
|
|
9150
|
+
getNavigationItemAnchor,
|
|
9151
|
+
isDragHandleDisabled,
|
|
9152
|
+
isNavbarButton: isNavbarButton2
|
|
9153
|
+
});
|
|
7612
9154
|
const bumpLinkPopoverGrace = () => {
|
|
7613
9155
|
linkPopoverGraceUntilRef.current = Date.now() + 350;
|
|
7614
9156
|
};
|
|
7615
|
-
const runSectionsPrefetch = (0,
|
|
9157
|
+
const runSectionsPrefetch = (0, import_react9.useCallback)((pages) => {
|
|
7616
9158
|
if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
|
|
7617
9159
|
const gen = ++sectionsPrefetchGenRef.current;
|
|
7618
9160
|
const paths = pages.map((p) => p.path);
|
|
@@ -7631,10 +9173,24 @@ function OhhwellsBridge() {
|
|
|
7631
9173
|
);
|
|
7632
9174
|
});
|
|
7633
9175
|
}, [isEditMode, pathname]);
|
|
7634
|
-
const runSectionsPrefetchRef = (0,
|
|
9176
|
+
const runSectionsPrefetchRef = (0, import_react9.useRef)(runSectionsPrefetch);
|
|
7635
9177
|
runSectionsPrefetchRef.current = runSectionsPrefetch;
|
|
7636
|
-
(0,
|
|
7637
|
-
if (!linkPopover)
|
|
9178
|
+
(0, import_react9.useEffect)(() => {
|
|
9179
|
+
if (!linkPopover) {
|
|
9180
|
+
document.documentElement.removeAttribute("data-ohw-link-popover-open");
|
|
9181
|
+
return;
|
|
9182
|
+
}
|
|
9183
|
+
document.documentElement.setAttribute("data-ohw-link-popover-open", "");
|
|
9184
|
+
hoveredItemElRef.current = null;
|
|
9185
|
+
setHoveredItemRect(null);
|
|
9186
|
+
hoveredNavContainerRef.current = null;
|
|
9187
|
+
setHoveredNavContainerRect(null);
|
|
9188
|
+
siblingHintElRef.current = null;
|
|
9189
|
+
setSiblingHintRect(null);
|
|
9190
|
+
setSiblingHintRects([]);
|
|
9191
|
+
if (selectedElRef.current || toolbarVariantRef.current !== "none") {
|
|
9192
|
+
deselectRef.current();
|
|
9193
|
+
}
|
|
7638
9194
|
if (hoveredImageRef.current) {
|
|
7639
9195
|
hoveredImageRef.current = null;
|
|
7640
9196
|
hoveredImageHasTextOverlapRef.current = false;
|
|
@@ -7668,7 +9224,7 @@ function OhhwellsBridge() {
|
|
|
7668
9224
|
document.removeEventListener("touchmove", preventBackgroundScroll, scrollOpts);
|
|
7669
9225
|
};
|
|
7670
9226
|
}, [linkPopover, postToParent2]);
|
|
7671
|
-
(0,
|
|
9227
|
+
(0, import_react9.useEffect)(() => {
|
|
7672
9228
|
if (!isEditMode) return;
|
|
7673
9229
|
const useFixtures = shouldUseDevFixtures();
|
|
7674
9230
|
if (useFixtures) {
|
|
@@ -7692,14 +9248,14 @@ function OhhwellsBridge() {
|
|
|
7692
9248
|
if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
|
|
7693
9249
|
return () => window.removeEventListener("message", onSitePages);
|
|
7694
9250
|
}, [isEditMode, postToParent2]);
|
|
7695
|
-
(0,
|
|
9251
|
+
(0, import_react9.useEffect)(() => {
|
|
7696
9252
|
if (!isEditMode || shouldUseDevFixtures()) return;
|
|
7697
9253
|
void loadAllSectionsManifest().then((manifest) => {
|
|
7698
9254
|
if (Object.keys(manifest).length === 0) return;
|
|
7699
9255
|
setSectionsByPath((prev) => ({ ...manifest, ...prev }));
|
|
7700
9256
|
});
|
|
7701
9257
|
}, [isEditMode]);
|
|
7702
|
-
(0,
|
|
9258
|
+
(0, import_react9.useEffect)(() => {
|
|
7703
9259
|
const update = () => {
|
|
7704
9260
|
const el = activeElRef.current ?? selectedElRef.current;
|
|
7705
9261
|
if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
|
|
@@ -7723,10 +9279,10 @@ function OhhwellsBridge() {
|
|
|
7723
9279
|
vvp.removeEventListener("resize", update);
|
|
7724
9280
|
};
|
|
7725
9281
|
}, []);
|
|
7726
|
-
const refreshStateRules = (0,
|
|
9282
|
+
const refreshStateRules = (0, import_react9.useCallback)(() => {
|
|
7727
9283
|
editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
|
|
7728
9284
|
}, []);
|
|
7729
|
-
const processConfigRequest = (0,
|
|
9285
|
+
const processConfigRequest = (0, import_react9.useCallback)((insertAfterVal) => {
|
|
7730
9286
|
const tracker = getSectionsTracker();
|
|
7731
9287
|
let entries = [];
|
|
7732
9288
|
try {
|
|
@@ -7749,7 +9305,7 @@ function OhhwellsBridge() {
|
|
|
7749
9305
|
}
|
|
7750
9306
|
window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
|
|
7751
9307
|
}, [isEditMode]);
|
|
7752
|
-
const deactivate = (0,
|
|
9308
|
+
const deactivate = (0, import_react9.useCallback)(() => {
|
|
7753
9309
|
const el = activeElRef.current;
|
|
7754
9310
|
if (!el) return;
|
|
7755
9311
|
const key = el.dataset.ohwKey;
|
|
@@ -7768,6 +9324,7 @@ function OhhwellsBridge() {
|
|
|
7768
9324
|
}
|
|
7769
9325
|
}
|
|
7770
9326
|
el.removeAttribute("contenteditable");
|
|
9327
|
+
el.removeAttribute("data-ohw-editing");
|
|
7771
9328
|
activeElRef.current = null;
|
|
7772
9329
|
setReorderHrefKey(null);
|
|
7773
9330
|
setReorderDragDisabled(false);
|
|
@@ -7780,12 +9337,23 @@ function OhhwellsBridge() {
|
|
|
7780
9337
|
setToolbarShowEditLink(false);
|
|
7781
9338
|
postToParent2({ type: "ow:exit-edit" });
|
|
7782
9339
|
}, [postToParent2]);
|
|
7783
|
-
const
|
|
9340
|
+
const clearSelectedAttr = (0, import_react9.useCallback)(() => {
|
|
9341
|
+
document.querySelectorAll("[data-ohw-selected]").forEach((el) => {
|
|
9342
|
+
el.removeAttribute("data-ohw-selected");
|
|
9343
|
+
});
|
|
9344
|
+
}, []);
|
|
9345
|
+
const deselect = (0, import_react9.useCallback)(() => {
|
|
9346
|
+
clearSelectedAttr();
|
|
7784
9347
|
selectedElRef.current = null;
|
|
9348
|
+
selectedHrefKeyRef.current = null;
|
|
9349
|
+
selectedFooterColAttrRef.current = null;
|
|
9350
|
+
setSelectedIsCta(false);
|
|
7785
9351
|
setReorderHrefKey(null);
|
|
7786
9352
|
setReorderDragDisabled(false);
|
|
9353
|
+
setIsFooterFrameSelection(false);
|
|
7787
9354
|
siblingHintElRef.current = null;
|
|
7788
9355
|
setSiblingHintRect(null);
|
|
9356
|
+
setSiblingHintRects([]);
|
|
7789
9357
|
setIsItemDragging(false);
|
|
7790
9358
|
hoveredNavContainerRef.current = null;
|
|
7791
9359
|
setHoveredNavContainerRect(null);
|
|
@@ -7793,18 +9361,70 @@ function OhhwellsBridge() {
|
|
|
7793
9361
|
setToolbarRect(null);
|
|
7794
9362
|
setToolbarVariant("none");
|
|
7795
9363
|
}
|
|
9364
|
+
}, [clearSelectedAttr]);
|
|
9365
|
+
const markSelected = (0, import_react9.useCallback)((el) => {
|
|
9366
|
+
clearSelectedAttr();
|
|
9367
|
+
el.setAttribute("data-ohw-selected", "");
|
|
9368
|
+
}, [clearSelectedAttr]);
|
|
9369
|
+
const resolveHrefKeyElement = (0, import_react9.useCallback)((hrefKey) => {
|
|
9370
|
+
if (isFooterHrefKey(hrefKey)) {
|
|
9371
|
+
return document.querySelector(
|
|
9372
|
+
`footer [data-ohw-href-key="${CSS.escape(hrefKey)}"]`
|
|
9373
|
+
);
|
|
9374
|
+
}
|
|
9375
|
+
if (isNavbarHrefKey(hrefKey)) {
|
|
9376
|
+
const desktop = document.querySelector("[data-ohw-nav-container]");
|
|
9377
|
+
const drawer = document.querySelector("[data-ohw-nav-drawer]");
|
|
9378
|
+
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)}"]`);
|
|
9379
|
+
}
|
|
9380
|
+
return document.querySelector(
|
|
9381
|
+
`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`
|
|
9382
|
+
);
|
|
7796
9383
|
}, []);
|
|
7797
|
-
const
|
|
9384
|
+
const resyncSelectedNavigationItem = (0, import_react9.useCallback)(() => {
|
|
9385
|
+
const hrefKey = selectedHrefKeyRef.current;
|
|
9386
|
+
if (hrefKey) {
|
|
9387
|
+
const link = resolveHrefKeyElement(hrefKey);
|
|
9388
|
+
if (!link || !isNavigationItem(link)) return;
|
|
9389
|
+
selectedElRef.current = link;
|
|
9390
|
+
const { key, disabled } = getNavigationItemReorderState(link);
|
|
9391
|
+
setReorderHrefKey(key);
|
|
9392
|
+
setReorderDragDisabled(disabled);
|
|
9393
|
+
setIsFooterFrameSelection(false);
|
|
9394
|
+
setToolbarVariant("link-action");
|
|
9395
|
+
setToolbarRect(link.getBoundingClientRect());
|
|
9396
|
+
setSiblingHintRects(collectNavigationItemSiblingHintRects(link));
|
|
9397
|
+
return;
|
|
9398
|
+
}
|
|
9399
|
+
const colAttr = selectedFooterColAttrRef.current;
|
|
9400
|
+
if (colAttr != null) {
|
|
9401
|
+
const column = document.querySelector(`[data-ohw-footer-col="${CSS.escape(colAttr)}"]`) ?? listFooterColumns()[Number(colAttr)] ?? null;
|
|
9402
|
+
if (!column || !isNavigationContainer(column)) return;
|
|
9403
|
+
selectedElRef.current = column;
|
|
9404
|
+
setIsFooterFrameSelection(true);
|
|
9405
|
+
setToolbarVariant("select-frame");
|
|
9406
|
+
setToolbarRect(column.getBoundingClientRect());
|
|
9407
|
+
setSiblingHintRects(
|
|
9408
|
+
listFooterColumns().filter((c) => c !== column).map((c) => c.getBoundingClientRect())
|
|
9409
|
+
);
|
|
9410
|
+
}
|
|
9411
|
+
}, [resolveHrefKeyElement]);
|
|
9412
|
+
const reselectNavigationItem = (0, import_react9.useCallback)((navAnchor) => {
|
|
7798
9413
|
selectedElRef.current = navAnchor;
|
|
9414
|
+
selectedHrefKeyRef.current = navAnchor.getAttribute("data-ohw-href-key");
|
|
9415
|
+
selectedFooterColAttrRef.current = null;
|
|
9416
|
+
markSelected(navAnchor);
|
|
9417
|
+
setSelectedIsCta(isNavbarButton2(navAnchor));
|
|
7799
9418
|
const { key, disabled } = getNavigationItemReorderState(navAnchor);
|
|
7800
9419
|
setReorderHrefKey(key);
|
|
7801
9420
|
setReorderDragDisabled(disabled);
|
|
7802
9421
|
setToolbarVariant("link-action");
|
|
7803
9422
|
setToolbarRect(navAnchor.getBoundingClientRect());
|
|
9423
|
+
setSiblingHintRects(collectNavigationItemSiblingHintRects(navAnchor));
|
|
7804
9424
|
setToolbarShowEditLink(false);
|
|
7805
9425
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
7806
|
-
}, []);
|
|
7807
|
-
const commitNavigationTextEdit = (0,
|
|
9426
|
+
}, [markSelected]);
|
|
9427
|
+
const commitNavigationTextEdit = (0, import_react9.useCallback)((navAnchor) => {
|
|
7808
9428
|
const el = activeElRef.current;
|
|
7809
9429
|
if (!el) return;
|
|
7810
9430
|
const key = el.dataset.ohwKey;
|
|
@@ -7823,6 +9443,7 @@ function OhhwellsBridge() {
|
|
|
7823
9443
|
}
|
|
7824
9444
|
}
|
|
7825
9445
|
el.removeAttribute("contenteditable");
|
|
9446
|
+
el.removeAttribute("data-ohw-editing");
|
|
7826
9447
|
activeElRef.current = null;
|
|
7827
9448
|
setMaxBadge(null);
|
|
7828
9449
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
@@ -7830,7 +9451,7 @@ function OhhwellsBridge() {
|
|
|
7830
9451
|
postToParent2({ type: "ow:exit-edit" });
|
|
7831
9452
|
reselectNavigationItem(navAnchor);
|
|
7832
9453
|
}, [postToParent2, reselectNavigationItem]);
|
|
7833
|
-
const handleAddTopLevelNavItem = (0,
|
|
9454
|
+
const handleAddTopLevelNavItem = (0, import_react9.useCallback)(() => {
|
|
7834
9455
|
const items = listNavbarItems();
|
|
7835
9456
|
addNavAfterAnchorRef.current = items[items.length - 1] ?? null;
|
|
7836
9457
|
deselectRef.current();
|
|
@@ -7842,20 +9463,321 @@ function OhhwellsBridge() {
|
|
|
7842
9463
|
intent: "add-nav"
|
|
7843
9464
|
});
|
|
7844
9465
|
}, []);
|
|
7845
|
-
const
|
|
7846
|
-
|
|
7847
|
-
|
|
7848
|
-
|
|
7849
|
-
|
|
7850
|
-
|
|
9466
|
+
const clearFooterDragVisuals = (0, import_react9.useCallback)(() => {
|
|
9467
|
+
footerDragRef.current = null;
|
|
9468
|
+
setSiblingHintRects([]);
|
|
9469
|
+
setFooterDropSlots([]);
|
|
9470
|
+
setActiveFooterDropIndex(null);
|
|
9471
|
+
setDraggedItemRect(null);
|
|
7851
9472
|
setIsItemDragging(false);
|
|
9473
|
+
unlockFooterDragInteraction();
|
|
9474
|
+
}, []);
|
|
9475
|
+
const refreshFooterDragVisuals = (0, import_react9.useCallback)((session, activeSlot, clientX, clientY) => {
|
|
9476
|
+
const dragged = session.draggedEl;
|
|
9477
|
+
setDraggedItemRect(dragged.getBoundingClientRect());
|
|
9478
|
+
if (typeof clientX === "number" && typeof clientY === "number") {
|
|
9479
|
+
session.lastClientX = clientX;
|
|
9480
|
+
session.lastClientY = clientY;
|
|
9481
|
+
}
|
|
9482
|
+
session.activeSlot = activeSlot;
|
|
9483
|
+
if (session.kind === "link") {
|
|
9484
|
+
const columns2 = listFooterColumns();
|
|
9485
|
+
const focusCols = /* @__PURE__ */ new Set([session.sourceColumnIndex]);
|
|
9486
|
+
if (activeSlot) focusCols.add(activeSlot.columnIndex);
|
|
9487
|
+
const siblingRects = [];
|
|
9488
|
+
columns2.forEach((col, i) => {
|
|
9489
|
+
if (!focusCols.has(i)) return;
|
|
9490
|
+
for (const link of listFooterLinksInColumn(col)) {
|
|
9491
|
+
if (link === dragged) continue;
|
|
9492
|
+
siblingRects.push(link.getBoundingClientRect());
|
|
9493
|
+
}
|
|
9494
|
+
});
|
|
9495
|
+
setSiblingHintRects(siblingRects);
|
|
9496
|
+
const slots2 = [];
|
|
9497
|
+
columns2.forEach((col, i) => {
|
|
9498
|
+
slots2.push(...buildLinkDropSlots(col, i));
|
|
9499
|
+
});
|
|
9500
|
+
setFooterDropSlots(slots2);
|
|
9501
|
+
const activeIdx2 = activeSlot ? slots2.findIndex((s) => s.columnIndex === activeSlot.columnIndex && s.insertIndex === activeSlot.insertIndex) : -1;
|
|
9502
|
+
setActiveFooterDropIndex(activeIdx2 >= 0 ? activeIdx2 : null);
|
|
9503
|
+
return;
|
|
9504
|
+
}
|
|
9505
|
+
const columns = listFooterColumns();
|
|
9506
|
+
setSiblingHintRects(columns.filter((col) => col !== dragged).map((col) => col.getBoundingClientRect()));
|
|
9507
|
+
const slots = buildColumnDropSlots();
|
|
9508
|
+
setFooterDropSlots(slots);
|
|
9509
|
+
const activeIdx = activeSlot ? slots.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
|
|
9510
|
+
setActiveFooterDropIndex(activeIdx >= 0 ? activeIdx : null);
|
|
9511
|
+
}, []);
|
|
9512
|
+
const refreshFooterDragVisualsRef = (0, import_react9.useRef)(refreshFooterDragVisuals);
|
|
9513
|
+
refreshFooterDragVisualsRef.current = refreshFooterDragVisuals;
|
|
9514
|
+
const commitFooterDragRef = (0, import_react9.useRef)(() => {
|
|
9515
|
+
});
|
|
9516
|
+
const beginFooterDragRef = (0, import_react9.useRef)(() => {
|
|
9517
|
+
});
|
|
9518
|
+
const beginFooterDrag = (0, import_react9.useCallback)(
|
|
9519
|
+
(session) => {
|
|
9520
|
+
const rect = session.draggedEl.getBoundingClientRect();
|
|
9521
|
+
session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
|
|
9522
|
+
session.lastClientY = session.lastClientY || rect.top + rect.height / 2;
|
|
9523
|
+
session.activeSlot = session.activeSlot ?? null;
|
|
9524
|
+
footerDragRef.current = session;
|
|
9525
|
+
setIsItemDragging(true);
|
|
9526
|
+
lockFooterDuringDrag();
|
|
9527
|
+
siblingHintElRef.current = null;
|
|
9528
|
+
setSiblingHintRect(null);
|
|
9529
|
+
if (session.wasSelected && selectedElRef.current === session.draggedEl) {
|
|
9530
|
+
setToolbarRect(rect);
|
|
9531
|
+
}
|
|
9532
|
+
const initialSlot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : hitTestColumnDropSlot(session.lastClientX, session.lastClientY);
|
|
9533
|
+
refreshFooterDragVisuals(session, initialSlot, session.lastClientX, session.lastClientY);
|
|
9534
|
+
},
|
|
9535
|
+
[refreshFooterDragVisuals]
|
|
9536
|
+
);
|
|
9537
|
+
beginFooterDragRef.current = beginFooterDrag;
|
|
9538
|
+
const commitFooterDrag = (0, import_react9.useCallback)(
|
|
9539
|
+
(clientX, clientY) => {
|
|
9540
|
+
const session = footerDragRef.current;
|
|
9541
|
+
if (!session) {
|
|
9542
|
+
clearFooterDragVisuals();
|
|
9543
|
+
return;
|
|
9544
|
+
}
|
|
9545
|
+
const x = typeof clientX === "number" && (clientX !== 0 || clientY !== 0) ? clientX : session.lastClientX;
|
|
9546
|
+
const y = typeof clientY === "number" && (clientX !== 0 || clientY !== 0) ? clientY : session.lastClientY;
|
|
9547
|
+
let nextOrder = null;
|
|
9548
|
+
const slot = session.activeSlot ?? (session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(x, y, session.hrefKey) : session.kind === "column" ? hitTestColumnDropSlot(x, y) : null);
|
|
9549
|
+
if (session.kind === "link" && session.hrefKey && slot) {
|
|
9550
|
+
nextOrder = planFooterLinkMove(session.hrefKey, slot.columnIndex, slot.insertIndex);
|
|
9551
|
+
} else if (session.kind === "column" && slot) {
|
|
9552
|
+
nextOrder = planFooterColumnMove(session.sourceColumnIndex, slot.insertIndex);
|
|
9553
|
+
}
|
|
9554
|
+
const wasSelected = session.wasSelected;
|
|
9555
|
+
const draggedEl = session.draggedEl;
|
|
9556
|
+
const hrefKey = session.hrefKey;
|
|
9557
|
+
let movedColumnIndex = null;
|
|
9558
|
+
if (session.kind === "column" && slot && nextOrder) {
|
|
9559
|
+
let adjusted = slot.insertIndex;
|
|
9560
|
+
if (session.sourceColumnIndex < slot.insertIndex) adjusted -= 1;
|
|
9561
|
+
movedColumnIndex = Math.max(0, Math.min(adjusted, nextOrder.length - 1));
|
|
9562
|
+
}
|
|
9563
|
+
const applySelectionAfterDrop = () => {
|
|
9564
|
+
if (!wasSelected) {
|
|
9565
|
+
deselectRef.current();
|
|
9566
|
+
return;
|
|
9567
|
+
}
|
|
9568
|
+
if (hrefKey) {
|
|
9569
|
+
selectedHrefKeyRef.current = hrefKey;
|
|
9570
|
+
selectedFooterColAttrRef.current = null;
|
|
9571
|
+
const link = resolveHrefKeyElement(hrefKey);
|
|
9572
|
+
if (link && isNavigationItem(link)) {
|
|
9573
|
+
selectRef.current(link);
|
|
9574
|
+
return;
|
|
9575
|
+
}
|
|
9576
|
+
}
|
|
9577
|
+
if (movedColumnIndex !== null && nextOrder) {
|
|
9578
|
+
const colKeys = nextOrder[movedColumnIndex] ?? [];
|
|
9579
|
+
let column = null;
|
|
9580
|
+
for (const key of colKeys) {
|
|
9581
|
+
const link = document.querySelector(
|
|
9582
|
+
`footer [data-ohw-href-key="${CSS.escape(key)}"]`
|
|
9583
|
+
);
|
|
9584
|
+
if (link) {
|
|
9585
|
+
column = findFooterColumnForLink(link);
|
|
9586
|
+
if (column) break;
|
|
9587
|
+
}
|
|
9588
|
+
}
|
|
9589
|
+
if (!column) column = listFooterColumns()[movedColumnIndex] ?? null;
|
|
9590
|
+
if (column && isNavigationContainer(column)) {
|
|
9591
|
+
selectFrameRef.current(column);
|
|
9592
|
+
return;
|
|
9593
|
+
}
|
|
9594
|
+
}
|
|
9595
|
+
if (document.body.contains(draggedEl)) {
|
|
9596
|
+
if (isNavigationItem(draggedEl)) {
|
|
9597
|
+
selectRef.current(draggedEl);
|
|
9598
|
+
return;
|
|
9599
|
+
}
|
|
9600
|
+
if (isNavigationContainer(draggedEl)) {
|
|
9601
|
+
selectFrameRef.current(draggedEl);
|
|
9602
|
+
return;
|
|
9603
|
+
}
|
|
9604
|
+
}
|
|
9605
|
+
deselectRef.current();
|
|
9606
|
+
};
|
|
9607
|
+
if (nextOrder) {
|
|
9608
|
+
const orderJson = JSON.stringify(nextOrder);
|
|
9609
|
+
editContentRef.current = {
|
|
9610
|
+
...editContentRef.current,
|
|
9611
|
+
[FOOTER_ORDER_KEY]: orderJson
|
|
9612
|
+
};
|
|
9613
|
+
applyFooterOrder(nextOrder);
|
|
9614
|
+
document.querySelectorAll("footer [data-ohw-href-key]").forEach(disableNativeHrefDrag);
|
|
9615
|
+
postToParentRef.current({
|
|
9616
|
+
type: "ow:change",
|
|
9617
|
+
nodes: [{ key: FOOTER_ORDER_KEY, text: orderJson }]
|
|
9618
|
+
});
|
|
9619
|
+
applySelectionAfterDrop();
|
|
9620
|
+
clearFooterDragVisuals();
|
|
9621
|
+
requestAnimationFrame(() => {
|
|
9622
|
+
if (editContentRef.current[FOOTER_ORDER_KEY] === orderJson) {
|
|
9623
|
+
applyFooterOrder(nextOrder);
|
|
9624
|
+
document.querySelectorAll("footer [data-ohw-href-key]").forEach(disableNativeHrefDrag);
|
|
9625
|
+
}
|
|
9626
|
+
applySelectionAfterDrop();
|
|
9627
|
+
requestAnimationFrame(() => {
|
|
9628
|
+
if (editContentRef.current[FOOTER_ORDER_KEY] === orderJson) {
|
|
9629
|
+
applyFooterOrder(nextOrder);
|
|
9630
|
+
}
|
|
9631
|
+
resyncSelectedNavigationItem();
|
|
9632
|
+
});
|
|
9633
|
+
});
|
|
9634
|
+
return;
|
|
9635
|
+
}
|
|
9636
|
+
applySelectionAfterDrop();
|
|
9637
|
+
clearFooterDragVisuals();
|
|
9638
|
+
},
|
|
9639
|
+
[clearFooterDragVisuals, resolveHrefKeyElement, resyncSelectedNavigationItem]
|
|
9640
|
+
);
|
|
9641
|
+
commitFooterDragRef.current = commitFooterDrag;
|
|
9642
|
+
const startFooterLinkDrag = (0, import_react9.useCallback)(
|
|
9643
|
+
(anchor, clientX, clientY, wasSelected) => {
|
|
9644
|
+
const hrefKey = anchor.getAttribute("data-ohw-href-key");
|
|
9645
|
+
if (!hrefKey || !isFooterHrefKey(hrefKey)) return false;
|
|
9646
|
+
const column = findFooterColumnForLink(anchor);
|
|
9647
|
+
const columns = listFooterColumns();
|
|
9648
|
+
beginFooterDrag({
|
|
9649
|
+
kind: "link",
|
|
9650
|
+
hrefKey,
|
|
9651
|
+
columnEl: column,
|
|
9652
|
+
sourceColumnIndex: column ? columns.indexOf(column) : 0,
|
|
9653
|
+
wasSelected,
|
|
9654
|
+
draggedEl: anchor,
|
|
9655
|
+
lastClientX: clientX,
|
|
9656
|
+
lastClientY: clientY,
|
|
9657
|
+
activeSlot: null
|
|
9658
|
+
});
|
|
9659
|
+
return true;
|
|
9660
|
+
},
|
|
9661
|
+
[beginFooterDrag]
|
|
9662
|
+
);
|
|
9663
|
+
const startFooterColumnDrag = (0, import_react9.useCallback)(
|
|
9664
|
+
(columnEl, clientX, clientY, wasSelected) => {
|
|
9665
|
+
const columns = listFooterColumns();
|
|
9666
|
+
const idx = columns.indexOf(columnEl);
|
|
9667
|
+
if (idx < 0) return false;
|
|
9668
|
+
beginFooterDrag({
|
|
9669
|
+
kind: "column",
|
|
9670
|
+
hrefKey: null,
|
|
9671
|
+
columnEl,
|
|
9672
|
+
sourceColumnIndex: idx,
|
|
9673
|
+
wasSelected,
|
|
9674
|
+
draggedEl: columnEl,
|
|
9675
|
+
lastClientX: clientX,
|
|
9676
|
+
lastClientY: clientY,
|
|
9677
|
+
activeSlot: null
|
|
9678
|
+
});
|
|
9679
|
+
return true;
|
|
9680
|
+
},
|
|
9681
|
+
[beginFooterDrag]
|
|
9682
|
+
);
|
|
9683
|
+
const handleItemDragStart = (0, import_react9.useCallback)(
|
|
9684
|
+
(e) => {
|
|
9685
|
+
const selected = selectedElRef.current;
|
|
9686
|
+
if (!selected) {
|
|
9687
|
+
setIsItemDragging(true);
|
|
9688
|
+
return;
|
|
9689
|
+
}
|
|
9690
|
+
const clientX = e?.clientX ?? selected.getBoundingClientRect().left + 8;
|
|
9691
|
+
const clientY = e?.clientY ?? selected.getBoundingClientRect().top + 8;
|
|
9692
|
+
if (startFooterLinkDrag(selected, clientX, clientY, true)) return;
|
|
9693
|
+
if (selected.hasAttribute("data-ohw-footer-col") || isInferredFooterGroup(selected) && selected.closest("footer")) {
|
|
9694
|
+
if (startFooterColumnDrag(selected, clientX, clientY, true)) return;
|
|
9695
|
+
}
|
|
9696
|
+
if (startNavLinkDrag(selected, clientX, clientY, true)) return;
|
|
9697
|
+
siblingHintElRef.current = null;
|
|
9698
|
+
setSiblingHintRect(null);
|
|
9699
|
+
setIsItemDragging(true);
|
|
9700
|
+
},
|
|
9701
|
+
[startFooterColumnDrag, startFooterLinkDrag, startNavLinkDrag]
|
|
9702
|
+
);
|
|
9703
|
+
const handleItemDragEnd = (0, import_react9.useCallback)(
|
|
9704
|
+
(e) => {
|
|
9705
|
+
if (footerDragRef.current) {
|
|
9706
|
+
const x = e?.clientX;
|
|
9707
|
+
const y = e?.clientY;
|
|
9708
|
+
if (typeof x === "number" && typeof y === "number" && (x !== 0 || y !== 0)) {
|
|
9709
|
+
commitFooterDrag(x, y);
|
|
9710
|
+
} else {
|
|
9711
|
+
commitFooterDrag();
|
|
9712
|
+
}
|
|
9713
|
+
return;
|
|
9714
|
+
}
|
|
9715
|
+
if (navDragRef.current) {
|
|
9716
|
+
const x = e?.clientX;
|
|
9717
|
+
const y = e?.clientY;
|
|
9718
|
+
if (typeof x === "number" && typeof y === "number" && (x !== 0 || y !== 0)) {
|
|
9719
|
+
commitNavDrag(x, y);
|
|
9720
|
+
} else {
|
|
9721
|
+
commitNavDrag();
|
|
9722
|
+
}
|
|
9723
|
+
return;
|
|
9724
|
+
}
|
|
9725
|
+
setIsItemDragging(false);
|
|
9726
|
+
},
|
|
9727
|
+
[commitFooterDrag, commitNavDrag, navDragRef]
|
|
9728
|
+
);
|
|
9729
|
+
const handleItemChromePointerDown = (0, import_react9.useCallback)((e) => {
|
|
9730
|
+
if (e.button !== 0) return;
|
|
9731
|
+
const selected = selectedElRef.current;
|
|
9732
|
+
if (!selected) return;
|
|
9733
|
+
const hrefKey = selected.getAttribute("data-ohw-href-key");
|
|
9734
|
+
if (hrefKey && isFooterHrefKey(hrefKey)) {
|
|
9735
|
+
footerPointerDragRef.current = {
|
|
9736
|
+
el: selected,
|
|
9737
|
+
kind: "link",
|
|
9738
|
+
startX: e.clientX,
|
|
9739
|
+
startY: e.clientY,
|
|
9740
|
+
pointerId: e.pointerId,
|
|
9741
|
+
wasSelected: true,
|
|
9742
|
+
started: false
|
|
9743
|
+
};
|
|
9744
|
+
return;
|
|
9745
|
+
}
|
|
9746
|
+
if (selected.hasAttribute("data-ohw-footer-col") || isInferredFooterGroup(selected) && selected.closest("footer")) {
|
|
9747
|
+
footerPointerDragRef.current = {
|
|
9748
|
+
el: selected,
|
|
9749
|
+
kind: "column",
|
|
9750
|
+
startX: e.clientX,
|
|
9751
|
+
startY: e.clientY,
|
|
9752
|
+
pointerId: e.pointerId,
|
|
9753
|
+
wasSelected: true,
|
|
9754
|
+
started: false
|
|
9755
|
+
};
|
|
9756
|
+
return;
|
|
9757
|
+
}
|
|
9758
|
+
if (armNavPressFromChrome(selected, e.clientX, e.clientY, e.pointerId)) return;
|
|
9759
|
+
}, [armNavPressFromChrome]);
|
|
9760
|
+
const handleItemChromeClick = (0, import_react9.useCallback)((clientX, clientY) => {
|
|
9761
|
+
if (suppressNextClickRef.current || Date.now() < suppressClickUntilRef.current) {
|
|
9762
|
+
suppressNextClickRef.current = false;
|
|
9763
|
+
return;
|
|
9764
|
+
}
|
|
9765
|
+
const selected = selectedElRef.current;
|
|
9766
|
+
if (!selected || !isNavigationItem(selected)) return;
|
|
9767
|
+
const editable = selected.querySelector('[data-ohw-editable="text"]') ?? selected.querySelector("[data-ohw-editable]");
|
|
9768
|
+
if (!editable) return;
|
|
9769
|
+
activateRef.current(editable, { caretX: clientX, caretY: clientY });
|
|
7852
9770
|
}, []);
|
|
7853
9771
|
reselectNavigationItemRef.current = reselectNavigationItem;
|
|
7854
9772
|
commitNavigationTextEditRef.current = commitNavigationTextEdit;
|
|
7855
|
-
const select = (0,
|
|
9773
|
+
const select = (0, import_react9.useCallback)((anchor) => {
|
|
7856
9774
|
if (!isNavigationItem(anchor)) return;
|
|
7857
9775
|
if (activeElRef.current) deactivate();
|
|
7858
9776
|
selectedElRef.current = anchor;
|
|
9777
|
+
selectedHrefKeyRef.current = anchor.getAttribute("data-ohw-href-key");
|
|
9778
|
+
selectedFooterColAttrRef.current = null;
|
|
9779
|
+
markSelected(anchor);
|
|
9780
|
+
setSelectedIsCta(isNavbarButton2(anchor));
|
|
7859
9781
|
clearHrefKeyHover(anchor);
|
|
7860
9782
|
hoveredNavContainerRef.current = null;
|
|
7861
9783
|
setHoveredNavContainerRect(null);
|
|
@@ -7863,19 +9785,26 @@ function OhhwellsBridge() {
|
|
|
7863
9785
|
hoveredItemElRef.current = null;
|
|
7864
9786
|
siblingHintElRef.current = null;
|
|
7865
9787
|
setSiblingHintRect(null);
|
|
9788
|
+
setSiblingHintRects(collectNavigationItemSiblingHintRects(anchor));
|
|
7866
9789
|
setIsItemDragging(false);
|
|
7867
9790
|
const { key, disabled } = getNavigationItemReorderState(anchor);
|
|
7868
9791
|
setReorderHrefKey(key);
|
|
7869
9792
|
setReorderDragDisabled(disabled);
|
|
9793
|
+
setIsFooterFrameSelection(false);
|
|
7870
9794
|
setToolbarVariant("link-action");
|
|
7871
9795
|
setToolbarRect(anchor.getBoundingClientRect());
|
|
7872
9796
|
setToolbarShowEditLink(false);
|
|
7873
9797
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
7874
|
-
}, [deactivate]);
|
|
7875
|
-
const selectFrame = (0,
|
|
9798
|
+
}, [deactivate, markSelected]);
|
|
9799
|
+
const selectFrame = (0, import_react9.useCallback)((el) => {
|
|
7876
9800
|
if (!isNavigationContainer(el)) return;
|
|
7877
9801
|
if (activeElRef.current) deactivate();
|
|
9802
|
+
const isFooterColumn = el.hasAttribute("data-ohw-footer-col") || Boolean(el.closest("footer") && isInferredFooterGroup(el));
|
|
7878
9803
|
selectedElRef.current = el;
|
|
9804
|
+
selectedHrefKeyRef.current = null;
|
|
9805
|
+
selectedFooterColAttrRef.current = isFooterColumn ? el.getAttribute("data-ohw-footer-col") ?? String(listFooterColumns().indexOf(el)) : null;
|
|
9806
|
+
markSelected(el);
|
|
9807
|
+
setSelectedIsCta(false);
|
|
7879
9808
|
clearHrefKeyHover(el);
|
|
7880
9809
|
hoveredNavContainerRef.current = null;
|
|
7881
9810
|
setHoveredNavContainerRect(null);
|
|
@@ -7883,17 +9812,25 @@ function OhhwellsBridge() {
|
|
|
7883
9812
|
hoveredItemElRef.current = null;
|
|
7884
9813
|
siblingHintElRef.current = null;
|
|
7885
9814
|
setSiblingHintRect(null);
|
|
9815
|
+
setSiblingHintRects(
|
|
9816
|
+
isFooterColumn ? listFooterColumns().filter((column) => column !== el).map((column) => column.getBoundingClientRect()) : []
|
|
9817
|
+
);
|
|
7886
9818
|
setIsItemDragging(false);
|
|
7887
9819
|
setReorderHrefKey(null);
|
|
7888
9820
|
setReorderDragDisabled(false);
|
|
9821
|
+
setIsFooterFrameSelection(isFooterColumn);
|
|
7889
9822
|
setToolbarVariant("select-frame");
|
|
7890
9823
|
setToolbarRect(el.getBoundingClientRect());
|
|
7891
9824
|
setToolbarShowEditLink(false);
|
|
7892
9825
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
7893
|
-
}, [deactivate]);
|
|
7894
|
-
const activate = (0,
|
|
9826
|
+
}, [deactivate, markSelected]);
|
|
9827
|
+
const activate = (0, import_react9.useCallback)((el, options) => {
|
|
7895
9828
|
if (activeElRef.current === el) return;
|
|
9829
|
+
clearSelectedAttr();
|
|
7896
9830
|
selectedElRef.current = null;
|
|
9831
|
+
selectedHrefKeyRef.current = null;
|
|
9832
|
+
selectedFooterColAttrRef.current = null;
|
|
9833
|
+
setSelectedIsCta(false);
|
|
7897
9834
|
deactivate();
|
|
7898
9835
|
if (hoveredImageRef.current) {
|
|
7899
9836
|
hoveredImageRef.current = null;
|
|
@@ -7903,14 +9840,34 @@ function OhhwellsBridge() {
|
|
|
7903
9840
|
siblingHintElRef.current = null;
|
|
7904
9841
|
setSiblingHintRect(null);
|
|
7905
9842
|
setIsItemDragging(false);
|
|
9843
|
+
const preActivationSelection = window.getSelection();
|
|
9844
|
+
const preservedRange = preActivationSelection && preActivationSelection.rangeCount > 0 && !preActivationSelection.isCollapsed && el.contains(preActivationSelection.getRangeAt(0).commonAncestorContainer) ? preActivationSelection.getRangeAt(0).cloneRange() : null;
|
|
7906
9845
|
el.setAttribute("contenteditable", "true");
|
|
9846
|
+
el.setAttribute("data-ohw-editing", "");
|
|
7907
9847
|
el.removeAttribute("data-ohw-hovered");
|
|
7908
9848
|
el.closest("[data-ohw-href-key]")?.removeAttribute("data-ohw-hovered");
|
|
7909
9849
|
activeElRef.current = el;
|
|
7910
9850
|
originalContentRef.current = el.innerHTML;
|
|
7911
|
-
el.focus();
|
|
7912
|
-
if (
|
|
7913
|
-
|
|
9851
|
+
el.focus({ preventScroll: true });
|
|
9852
|
+
if (preservedRange) {
|
|
9853
|
+
const selection = window.getSelection();
|
|
9854
|
+
selection?.removeAllRanges();
|
|
9855
|
+
selection?.addRange(preservedRange);
|
|
9856
|
+
} else if (options?.caretX !== void 0 && options?.caretY !== void 0) {
|
|
9857
|
+
const { caretX, caretY } = options;
|
|
9858
|
+
placeCaretAtPoint(el, caretX, caretY);
|
|
9859
|
+
requestAnimationFrame(() => {
|
|
9860
|
+
if (activeElRef.current === el) placeCaretAtPoint(el, caretX, caretY);
|
|
9861
|
+
});
|
|
9862
|
+
} else {
|
|
9863
|
+
const selection = window.getSelection();
|
|
9864
|
+
if (selection && selection.rangeCount === 0) {
|
|
9865
|
+
const range = document.createRange();
|
|
9866
|
+
range.selectNodeContents(el);
|
|
9867
|
+
range.collapse(false);
|
|
9868
|
+
selection.removeAllRanges();
|
|
9869
|
+
selection.addRange(range);
|
|
9870
|
+
}
|
|
7914
9871
|
}
|
|
7915
9872
|
setToolbarShowEditLink(Boolean(getHrefKeyFromElement(el)));
|
|
7916
9873
|
const navAnchor = getNavigationItemAnchor(el);
|
|
@@ -7925,13 +9882,13 @@ function OhhwellsBridge() {
|
|
|
7925
9882
|
setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
|
|
7926
9883
|
postToParent2({ type: "ow:enter-edit", key: el.dataset.ohwKey });
|
|
7927
9884
|
requestAnimationFrame(() => refreshActiveCommandsRef.current());
|
|
7928
|
-
}, [deactivate, postToParent2]);
|
|
9885
|
+
}, [clearSelectedAttr, deactivate, postToParent2]);
|
|
7929
9886
|
activateRef.current = activate;
|
|
7930
9887
|
deactivateRef.current = deactivate;
|
|
7931
9888
|
selectRef.current = select;
|
|
7932
9889
|
selectFrameRef.current = selectFrame;
|
|
7933
9890
|
deselectRef.current = deselect;
|
|
7934
|
-
(0,
|
|
9891
|
+
(0, import_react9.useLayoutEffect)(() => {
|
|
7935
9892
|
if (!subdomain || isEditMode) {
|
|
7936
9893
|
setFetchState("done");
|
|
7937
9894
|
return;
|
|
@@ -7972,6 +9929,7 @@ function OhhwellsBridge() {
|
|
|
7972
9929
|
applyLinkByKey(key, val);
|
|
7973
9930
|
}
|
|
7974
9931
|
reconcileNavbarItemsFromContent(content);
|
|
9932
|
+
reconcileFooterOrderFromContent(content);
|
|
7975
9933
|
enforceLinkHrefs();
|
|
7976
9934
|
initSectionsFromContent(content, true);
|
|
7977
9935
|
sectionsLoadedRef.current = true;
|
|
@@ -8000,7 +9958,7 @@ function OhhwellsBridge() {
|
|
|
8000
9958
|
cancelled = true;
|
|
8001
9959
|
};
|
|
8002
9960
|
}, [subdomain, isEditMode]);
|
|
8003
|
-
(0,
|
|
9961
|
+
(0, import_react9.useEffect)(() => {
|
|
8004
9962
|
if (!subdomain || isEditMode) return;
|
|
8005
9963
|
let debounceTimer = null;
|
|
8006
9964
|
let observer = null;
|
|
@@ -8032,6 +9990,7 @@ function OhhwellsBridge() {
|
|
|
8032
9990
|
applyLinkByKey(key, val);
|
|
8033
9991
|
}
|
|
8034
9992
|
reconcileNavbarItemsFromContent(content);
|
|
9993
|
+
reconcileFooterOrderFromContent(content);
|
|
8035
9994
|
} finally {
|
|
8036
9995
|
observer?.observe(document.body, { childList: true, subtree: true });
|
|
8037
9996
|
}
|
|
@@ -8049,16 +10008,16 @@ function OhhwellsBridge() {
|
|
|
8049
10008
|
if (debounceTimer) clearTimeout(debounceTimer);
|
|
8050
10009
|
};
|
|
8051
10010
|
}, [subdomain, isEditMode, pathname]);
|
|
8052
|
-
(0,
|
|
10011
|
+
(0, import_react9.useLayoutEffect)(() => {
|
|
8053
10012
|
const el = document.getElementById("ohw-loader");
|
|
8054
10013
|
if (!el) return;
|
|
8055
10014
|
const visible = Boolean(subdomain) && fetchState !== "done";
|
|
8056
10015
|
el.style.display = visible ? "flex" : "none";
|
|
8057
10016
|
}, [subdomain, fetchState]);
|
|
8058
|
-
(0,
|
|
10017
|
+
(0, import_react9.useEffect)(() => {
|
|
8059
10018
|
postToParent2({ type: "ow:navigation", path: pathname });
|
|
8060
10019
|
}, [pathname, postToParent2]);
|
|
8061
|
-
(0,
|
|
10020
|
+
(0, import_react9.useEffect)(() => {
|
|
8062
10021
|
if (!isEditMode) return;
|
|
8063
10022
|
if (linkPopoverSessionRef.current?.intent === "add-nav") return;
|
|
8064
10023
|
if (document.querySelector("[data-ohw-section-picker]")) return;
|
|
@@ -8066,23 +10025,72 @@ function OhhwellsBridge() {
|
|
|
8066
10025
|
deselectRef.current();
|
|
8067
10026
|
deactivateRef.current();
|
|
8068
10027
|
}, [pathname, isEditMode]);
|
|
8069
|
-
(0,
|
|
10028
|
+
(0, import_react9.useEffect)(() => {
|
|
8070
10029
|
const contentForNav = () => {
|
|
8071
10030
|
if (isEditMode) return editContentRef.current;
|
|
8072
10031
|
if (!subdomain) return {};
|
|
8073
10032
|
return contentCache.get(subdomain) ?? {};
|
|
8074
10033
|
};
|
|
8075
|
-
const
|
|
10034
|
+
const observeRoots = () => [document.querySelector("nav"), document.querySelector("footer")].filter(
|
|
10035
|
+
(el) => Boolean(el)
|
|
10036
|
+
);
|
|
10037
|
+
const roots = observeRoots();
|
|
10038
|
+
if (roots.length === 0) {
|
|
10039
|
+
reconcileNavbarItemsFromContent(contentForNav());
|
|
10040
|
+
reconcileFooterOrderFromContent(contentForNav());
|
|
10041
|
+
if (isEditMode) syncNavigationDragCursorAttrs();
|
|
10042
|
+
return;
|
|
10043
|
+
}
|
|
10044
|
+
let rafId = null;
|
|
10045
|
+
let applying = false;
|
|
10046
|
+
let observer = null;
|
|
10047
|
+
const attach = () => {
|
|
10048
|
+
for (const root of observeRoots()) {
|
|
10049
|
+
observer?.observe(root, { childList: true, subtree: true });
|
|
10050
|
+
}
|
|
10051
|
+
};
|
|
10052
|
+
const run = () => {
|
|
10053
|
+
if (footerDragRef.current || navDragRef.current || applying) return;
|
|
10054
|
+
applying = true;
|
|
10055
|
+
observer?.disconnect();
|
|
10056
|
+
try {
|
|
10057
|
+
const content = contentForNav();
|
|
10058
|
+
reconcileNavbarItemsFromContent(content);
|
|
10059
|
+
reconcileFooterOrderFromContent(content);
|
|
10060
|
+
document.querySelectorAll("footer [data-ohw-href-key]").forEach((el) => {
|
|
10061
|
+
if (isFooterHrefKey(el.getAttribute("data-ohw-href-key"))) {
|
|
10062
|
+
disableNativeHrefDrag(el);
|
|
10063
|
+
}
|
|
10064
|
+
});
|
|
10065
|
+
document.querySelectorAll(
|
|
10066
|
+
"nav [data-ohw-href-key], [data-ohw-nav-container] [data-ohw-href-key], [data-ohw-nav-drawer] [data-ohw-href-key]"
|
|
10067
|
+
).forEach((el) => {
|
|
10068
|
+
if (isNavbarHrefKey(el.getAttribute("data-ohw-href-key"))) {
|
|
10069
|
+
disableNativeHrefDrag(el);
|
|
10070
|
+
}
|
|
10071
|
+
});
|
|
10072
|
+
resyncSelectedNavigationItem();
|
|
10073
|
+
if (isEditMode) syncNavigationDragCursorAttrs();
|
|
10074
|
+
} finally {
|
|
10075
|
+
applying = false;
|
|
10076
|
+
attach();
|
|
10077
|
+
}
|
|
10078
|
+
};
|
|
10079
|
+
const schedule = () => {
|
|
10080
|
+
if (applying || rafId != null) return;
|
|
10081
|
+
rafId = requestAnimationFrame(() => {
|
|
10082
|
+
rafId = null;
|
|
10083
|
+
run();
|
|
10084
|
+
});
|
|
10085
|
+
};
|
|
10086
|
+
observer = new MutationObserver(schedule);
|
|
8076
10087
|
run();
|
|
8077
|
-
|
|
8078
|
-
|
|
8079
|
-
|
|
8080
|
-
|
|
8081
|
-
|
|
8082
|
-
|
|
8083
|
-
return () => observer.disconnect();
|
|
8084
|
-
}, [isEditMode, pathname, subdomain, fetchState]);
|
|
8085
|
-
(0, import_react8.useEffect)(() => {
|
|
10088
|
+
return () => {
|
|
10089
|
+
if (rafId != null) cancelAnimationFrame(rafId);
|
|
10090
|
+
observer?.disconnect();
|
|
10091
|
+
};
|
|
10092
|
+
}, [isEditMode, pathname, subdomain, fetchState, resyncSelectedNavigationItem]);
|
|
10093
|
+
(0, import_react9.useEffect)(() => {
|
|
8086
10094
|
if (!isEditMode) return;
|
|
8087
10095
|
const measure = () => {
|
|
8088
10096
|
const h = document.body.scrollHeight;
|
|
@@ -8106,7 +10114,7 @@ function OhhwellsBridge() {
|
|
|
8106
10114
|
window.removeEventListener("resize", handleResize);
|
|
8107
10115
|
};
|
|
8108
10116
|
}, [pathname, isEditMode, postToParent2]);
|
|
8109
|
-
(0,
|
|
10117
|
+
(0, import_react9.useEffect)(() => {
|
|
8110
10118
|
if (!subdomainFromQuery || isEditMode) return;
|
|
8111
10119
|
const handleClick = (e) => {
|
|
8112
10120
|
const anchor = e.target.closest("a");
|
|
@@ -8122,19 +10130,24 @@ function OhhwellsBridge() {
|
|
|
8122
10130
|
document.addEventListener("click", handleClick, true);
|
|
8123
10131
|
return () => document.removeEventListener("click", handleClick, true);
|
|
8124
10132
|
}, [subdomainFromQuery, isEditMode, router]);
|
|
8125
|
-
(0,
|
|
10133
|
+
(0, import_react9.useEffect)(() => {
|
|
8126
10134
|
if (!isEditMode) {
|
|
8127
10135
|
editStylesRef.current?.base.remove();
|
|
8128
10136
|
editStylesRef.current?.forceHover.remove();
|
|
8129
10137
|
editStylesRef.current?.stateViews.remove();
|
|
8130
10138
|
editStylesRef.current = null;
|
|
10139
|
+
document.querySelectorAll("[data-ohw-can-drag]").forEach((el) => {
|
|
10140
|
+
el.removeAttribute("data-ohw-can-drag");
|
|
10141
|
+
});
|
|
8131
10142
|
return;
|
|
8132
10143
|
}
|
|
8133
|
-
|
|
8134
|
-
|
|
8135
|
-
|
|
8136
|
-
base.
|
|
8137
|
-
|
|
10144
|
+
const existing = editStylesRef.current;
|
|
10145
|
+
let initialVh = window.innerHeight;
|
|
10146
|
+
if (existing?.base.textContent) {
|
|
10147
|
+
const match = existing.base.textContent.match(/\.min-h-screen[^{]*\{[^}]*min-height:\s*(\d+)px/);
|
|
10148
|
+
if (match) initialVh = parseInt(match[1], 10);
|
|
10149
|
+
}
|
|
10150
|
+
const baseCss = `
|
|
8138
10151
|
html { height: auto !important; }
|
|
8139
10152
|
body { height: auto !important; min-height: 0 !important; overflow: hidden !important; }
|
|
8140
10153
|
.min-h-screen, .min-h-svh, .min-h-dvh { min-height: ${initialVh}px !important; }
|
|
@@ -8145,7 +10158,25 @@ function OhhwellsBridge() {
|
|
|
8145
10158
|
[data-ohw-editable] {
|
|
8146
10159
|
display: block;
|
|
8147
10160
|
}
|
|
8148
|
-
|
|
10161
|
+
/* Body text (no item-action toolbar) \u2014 first click enters text edit \u2192 I-beam.
|
|
10162
|
+
Exclude select-first nav/footer labels so grab/default on [data-ohw-href-key] can win. */
|
|
10163
|
+
[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] *)) {
|
|
10164
|
+
cursor: text !important;
|
|
10165
|
+
}
|
|
10166
|
+
/* Select-first items: default arrow; grab only when drag-start is allowed (data-ohw-can-drag). */
|
|
10167
|
+
[data-ohw-href-key]:not([data-ohw-selected]),
|
|
10168
|
+
[data-ohw-href-key]:not([data-ohw-selected]) * {
|
|
10169
|
+
cursor: default !important;
|
|
10170
|
+
}
|
|
10171
|
+
[data-ohw-href-key][data-ohw-can-drag]:not([data-ohw-selected]),
|
|
10172
|
+
[data-ohw-href-key][data-ohw-can-drag]:not([data-ohw-selected]) * {
|
|
10173
|
+
cursor: grab !important;
|
|
10174
|
+
}
|
|
10175
|
+
/* Selected (action-toolbar) \u2014 next click enters text edit at caret. */
|
|
10176
|
+
[data-ohw-href-key][data-ohw-selected],
|
|
10177
|
+
[data-ohw-href-key][data-ohw-selected] * {
|
|
10178
|
+
cursor: text !important;
|
|
10179
|
+
}
|
|
8149
10180
|
[data-ohw-editable="image"], [data-ohw-editable="image"] *,
|
|
8150
10181
|
[data-ohw-editable="video"], [data-ohw-editable="video"] *,
|
|
8151
10182
|
[data-ohw-editable="bg-image"], [data-ohw-editable="bg-image"] * { cursor: pointer !important; }
|
|
@@ -8161,9 +10192,32 @@ function OhhwellsBridge() {
|
|
|
8161
10192
|
outline: none !important;
|
|
8162
10193
|
outline-offset: 0 !important;
|
|
8163
10194
|
}
|
|
8164
|
-
|
|
10195
|
+
/* Editor chrome owns selection \u2014 suppress native focus rings on nav/footer items. */
|
|
10196
|
+
nav [data-ohw-href-key]:focus,
|
|
10197
|
+
nav [data-ohw-href-key]:focus-visible,
|
|
10198
|
+
nav [data-ohw-href-key]:focus-within,
|
|
10199
|
+
footer [data-ohw-href-key]:focus,
|
|
10200
|
+
footer [data-ohw-href-key]:focus-visible,
|
|
10201
|
+
footer [data-ohw-href-key]:focus-within,
|
|
10202
|
+
nav [data-ohw-href-key] [data-ohw-editable]:focus,
|
|
10203
|
+
nav [data-ohw-href-key] [data-ohw-editable]:focus-visible,
|
|
10204
|
+
footer [data-ohw-href-key] [data-ohw-editable]:focus,
|
|
10205
|
+
footer [data-ohw-href-key] [data-ohw-editable]:focus-visible {
|
|
10206
|
+
outline: none !important;
|
|
10207
|
+
outline-offset: 0 !important;
|
|
10208
|
+
box-shadow: none !important;
|
|
10209
|
+
}
|
|
10210
|
+
/* Text edit wins over grab/default (must beat [data-ohw-can-drag] *). */
|
|
10211
|
+
[data-ohw-editing],
|
|
10212
|
+
[data-ohw-editing] *,
|
|
10213
|
+
[data-ohw-editable][contenteditable],
|
|
10214
|
+
[data-ohw-editable][contenteditable] *,
|
|
10215
|
+
nav [data-ohw-href-key] [data-ohw-editable][contenteditable],
|
|
10216
|
+
nav [data-ohw-href-key] [data-ohw-editable][contenteditable] *,
|
|
10217
|
+
footer [data-ohw-href-key] [data-ohw-editable][contenteditable],
|
|
10218
|
+
footer [data-ohw-href-key] [data-ohw-editable][contenteditable] * {
|
|
8165
10219
|
outline: none !important;
|
|
8166
|
-
caret-color: ${PRIMARY2};
|
|
10220
|
+
caret-color: ${PRIMARY2} !important;
|
|
8167
10221
|
cursor: text !important;
|
|
8168
10222
|
}
|
|
8169
10223
|
[data-ohw-editable][contenteditable]::selection,
|
|
@@ -8172,6 +10226,9 @@ function OhhwellsBridge() {
|
|
|
8172
10226
|
[data-ohw-editable-state][data-ohw-active-state] [data-ohw-editable] { pointer-events: auto !important; }
|
|
8173
10227
|
[data-ohw-editable-state][data-ohw-active-state][data-ohw-editable] { pointer-events: auto !important; }
|
|
8174
10228
|
`;
|
|
10229
|
+
if (!existing) {
|
|
10230
|
+
const base = document.createElement("style");
|
|
10231
|
+
base.setAttribute("data-ohw-edit-style", "");
|
|
8175
10232
|
const forceHover = document.createElement("style");
|
|
8176
10233
|
forceHover.setAttribute("data-ohw-active-state-style", "");
|
|
8177
10234
|
const stateViews = document.createElement("style");
|
|
@@ -8187,14 +10244,43 @@ function OhhwellsBridge() {
|
|
|
8187
10244
|
document.head.appendChild(stateViews);
|
|
8188
10245
|
editStylesRef.current = { base, forceHover, stateViews };
|
|
8189
10246
|
}
|
|
10247
|
+
editStylesRef.current.base.textContent = baseCss;
|
|
10248
|
+
syncNavigationDragCursorAttrs();
|
|
8190
10249
|
refreshStateRules();
|
|
8191
10250
|
const handleClick = (e) => {
|
|
10251
|
+
if (suppressNextClickRef.current || Date.now() < suppressClickUntilRef.current) {
|
|
10252
|
+
suppressNextClickRef.current = false;
|
|
10253
|
+
e.preventDefault();
|
|
10254
|
+
e.stopPropagation();
|
|
10255
|
+
return;
|
|
10256
|
+
}
|
|
8192
10257
|
const target = e.target;
|
|
8193
10258
|
if (target.closest("[data-ohw-toolbar]")) return;
|
|
8194
10259
|
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
8195
10260
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
8196
10261
|
if (isInsideLinkEditor(target)) return;
|
|
8197
10262
|
if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
|
|
10263
|
+
if (target.closest("[data-ohw-item-drag-surface]")) {
|
|
10264
|
+
e.preventDefault();
|
|
10265
|
+
e.stopPropagation();
|
|
10266
|
+
const selected = selectedElRef.current;
|
|
10267
|
+
if (selected && isNavigationItem(selected)) {
|
|
10268
|
+
const editable2 = selected.querySelector('[data-ohw-editable="text"]') ?? selected.querySelector("[data-ohw-editable]");
|
|
10269
|
+
if (editable2) {
|
|
10270
|
+
activateRef.current(editable2, {
|
|
10271
|
+
caretX: e.clientX,
|
|
10272
|
+
caretY: e.clientY
|
|
10273
|
+
});
|
|
10274
|
+
}
|
|
10275
|
+
} else if (selected?.hasAttribute("data-ohw-footer-col")) {
|
|
10276
|
+
const link = listFooterLinksInColumn(selected).find((el) => {
|
|
10277
|
+
const r2 = el.getBoundingClientRect();
|
|
10278
|
+
return e.clientX >= r2.left && e.clientX <= r2.right && e.clientY >= r2.top && e.clientY <= r2.bottom;
|
|
10279
|
+
});
|
|
10280
|
+
if (link) selectRef.current(link);
|
|
10281
|
+
}
|
|
10282
|
+
return;
|
|
10283
|
+
}
|
|
8198
10284
|
const navFromChrome = resolveNavContainerSelectionTarget(target, e.clientX, e.clientY);
|
|
8199
10285
|
if (navFromChrome) {
|
|
8200
10286
|
e.preventDefault();
|
|
@@ -8202,10 +10288,36 @@ function OhhwellsBridge() {
|
|
|
8202
10288
|
selectFrameRef.current(navFromChrome);
|
|
8203
10289
|
return;
|
|
8204
10290
|
}
|
|
10291
|
+
const footerFromChrome = resolveFooterColumnSelectionTarget(target, e.clientX, e.clientY);
|
|
10292
|
+
if (footerFromChrome) {
|
|
10293
|
+
e.preventDefault();
|
|
10294
|
+
e.stopPropagation();
|
|
10295
|
+
selectFrameRef.current(footerFromChrome);
|
|
10296
|
+
return;
|
|
10297
|
+
}
|
|
8205
10298
|
e.preventDefault();
|
|
8206
10299
|
e.stopPropagation();
|
|
8207
10300
|
return;
|
|
8208
10301
|
}
|
|
10302
|
+
if (activeElRef.current) {
|
|
10303
|
+
const active = activeElRef.current;
|
|
10304
|
+
const inActive = active === target || active.contains(target);
|
|
10305
|
+
const navAnchor = getNavigationItemAnchor(active);
|
|
10306
|
+
const inActiveNav = Boolean(
|
|
10307
|
+
navAnchor && (navAnchor === target || navAnchor.contains(target))
|
|
10308
|
+
);
|
|
10309
|
+
if (inActive || inActiveNav) {
|
|
10310
|
+
e.preventDefault();
|
|
10311
|
+
e.stopPropagation();
|
|
10312
|
+
const selection = window.getSelection();
|
|
10313
|
+
const hasRangeSelection = Boolean(selection && !selection.isCollapsed);
|
|
10314
|
+
if (e.detail < 2 && !hasRangeSelection) {
|
|
10315
|
+
placeCaretAtPoint(active, e.clientX, e.clientY);
|
|
10316
|
+
refreshActiveCommandsRef.current();
|
|
10317
|
+
}
|
|
10318
|
+
return;
|
|
10319
|
+
}
|
|
10320
|
+
}
|
|
8209
10321
|
const editable = target.closest("[data-ohw-editable]");
|
|
8210
10322
|
if (editable) {
|
|
8211
10323
|
if (editable.dataset.ohwEditable === "link") {
|
|
@@ -8249,10 +10361,26 @@ function OhhwellsBridge() {
|
|
|
8249
10361
|
if (hrefAnchor) {
|
|
8250
10362
|
e.preventDefault();
|
|
8251
10363
|
e.stopPropagation();
|
|
8252
|
-
if (selectedElRef.current === hrefAnchor)
|
|
10364
|
+
if (selectedElRef.current === hrefAnchor) {
|
|
10365
|
+
const textEditable = hrefAnchor.querySelector('[data-ohw-editable="text"]') ?? hrefAnchor.querySelector("[data-ohw-editable]");
|
|
10366
|
+
if (textEditable) {
|
|
10367
|
+
activateRef.current(textEditable, {
|
|
10368
|
+
caretX: e.clientX,
|
|
10369
|
+
caretY: e.clientY
|
|
10370
|
+
});
|
|
10371
|
+
}
|
|
10372
|
+
return;
|
|
10373
|
+
}
|
|
8253
10374
|
selectRef.current(hrefAnchor);
|
|
8254
10375
|
return;
|
|
8255
10376
|
}
|
|
10377
|
+
const footerColClick = target.closest("[data-ohw-footer-col]");
|
|
10378
|
+
if (footerColClick) {
|
|
10379
|
+
e.preventDefault();
|
|
10380
|
+
e.stopPropagation();
|
|
10381
|
+
selectFrameRef.current(footerColClick);
|
|
10382
|
+
return;
|
|
10383
|
+
}
|
|
8256
10384
|
const navContainerToSelect = resolveNavContainerSelectionTarget(target, e.clientX, e.clientY);
|
|
8257
10385
|
if (navContainerToSelect) {
|
|
8258
10386
|
e.preventDefault();
|
|
@@ -8260,6 +10388,13 @@ function OhhwellsBridge() {
|
|
|
8260
10388
|
selectFrameRef.current(navContainerToSelect);
|
|
8261
10389
|
return;
|
|
8262
10390
|
}
|
|
10391
|
+
const footerColumnToSelect = resolveFooterColumnSelectionTarget(target, e.clientX, e.clientY);
|
|
10392
|
+
if (footerColumnToSelect) {
|
|
10393
|
+
e.preventDefault();
|
|
10394
|
+
e.stopPropagation();
|
|
10395
|
+
selectFrameRef.current(footerColumnToSelect);
|
|
10396
|
+
return;
|
|
10397
|
+
}
|
|
8263
10398
|
const selectedContainer = selectedElRef.current;
|
|
8264
10399
|
if (selectedContainer && isNavigationContainer(selectedContainer)) {
|
|
8265
10400
|
const navItem = getNavigationItemAnchor(target);
|
|
@@ -8319,6 +10454,13 @@ function OhhwellsBridge() {
|
|
|
8319
10454
|
const handleMouseOver = (e) => {
|
|
8320
10455
|
if (document.documentElement.hasAttribute("data-ohw-section-picking")) return;
|
|
8321
10456
|
const target = e.target;
|
|
10457
|
+
if (linkPopoverOpenRef.current) {
|
|
10458
|
+
hoveredItemElRef.current = null;
|
|
10459
|
+
setHoveredItemRect(null);
|
|
10460
|
+
hoveredNavContainerRef.current = null;
|
|
10461
|
+
setHoveredNavContainerRect(null);
|
|
10462
|
+
return;
|
|
10463
|
+
}
|
|
8322
10464
|
if (toolbarVariantRef.current !== "select-frame") {
|
|
8323
10465
|
const navContainer = target.closest("[data-ohw-nav-container]");
|
|
8324
10466
|
if (navContainer && !getNavigationItemAnchor(target)) {
|
|
@@ -8338,12 +10480,21 @@ function OhhwellsBridge() {
|
|
|
8338
10480
|
hoveredNavContainerRef.current = null;
|
|
8339
10481
|
setHoveredNavContainerRect(null);
|
|
8340
10482
|
const selected2 = selectedElRef.current;
|
|
8341
|
-
if (selected2 === navAnchor
|
|
10483
|
+
if (selected2 === navAnchor) return;
|
|
8342
10484
|
clearHrefKeyHover(navAnchor);
|
|
8343
10485
|
hoveredItemElRef.current = navAnchor;
|
|
8344
10486
|
setHoveredItemRect(navAnchor.getBoundingClientRect());
|
|
8345
10487
|
return;
|
|
8346
10488
|
}
|
|
10489
|
+
const footerCol = target.closest("[data-ohw-footer-col]") ?? target.closest("[data-ohw-footer-column]");
|
|
10490
|
+
if (footerCol) {
|
|
10491
|
+
hoveredNavContainerRef.current = null;
|
|
10492
|
+
setHoveredNavContainerRect(null);
|
|
10493
|
+
if (selectedElRef.current === footerCol) return;
|
|
10494
|
+
hoveredItemElRef.current = footerCol;
|
|
10495
|
+
setHoveredItemRect(footerCol.getBoundingClientRect());
|
|
10496
|
+
return;
|
|
10497
|
+
}
|
|
8347
10498
|
const editable = target.closest("[data-ohw-editable]");
|
|
8348
10499
|
if (!editable) return;
|
|
8349
10500
|
const selected = selectedElRef.current;
|
|
@@ -8361,14 +10512,25 @@ function OhhwellsBridge() {
|
|
|
8361
10512
|
};
|
|
8362
10513
|
const handleMouseOut = (e) => {
|
|
8363
10514
|
const target = e.target;
|
|
8364
|
-
if (target.closest("[data-ohw-nav-container]")) {
|
|
10515
|
+
if (target.closest("[data-ohw-nav-container], [data-ohw-footer-col], [data-ohw-footer-column]")) {
|
|
8365
10516
|
const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
8366
|
-
if (related2?.closest("[data-ohw-nav-container], [data-ohw-navbar-container-chrome], [data-ohw-navbar-add-button]")) {
|
|
10517
|
+
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]")) {
|
|
8367
10518
|
return;
|
|
8368
10519
|
}
|
|
8369
10520
|
hoveredNavContainerRef.current = null;
|
|
8370
10521
|
setHoveredNavContainerRect(null);
|
|
8371
10522
|
}
|
|
10523
|
+
const footerCol = target.closest("[data-ohw-footer-col]") ?? target.closest("[data-ohw-footer-column]");
|
|
10524
|
+
if (footerCol && hoveredItemElRef.current === footerCol) {
|
|
10525
|
+
const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
10526
|
+
if (related2?.closest("[data-ohw-drag-handle-container], [data-ohw-item-interaction]")) return;
|
|
10527
|
+
if (related2?.closest("[data-ohw-footer-col], [data-ohw-footer-column]") === footerCol) {
|
|
10528
|
+
return;
|
|
10529
|
+
}
|
|
10530
|
+
hoveredItemElRef.current = null;
|
|
10531
|
+
setHoveredItemRect(null);
|
|
10532
|
+
return;
|
|
10533
|
+
}
|
|
8372
10534
|
const navAnchor = getNavigationItemAnchor(target);
|
|
8373
10535
|
if (navAnchor) {
|
|
8374
10536
|
const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
@@ -8502,43 +10664,75 @@ function OhhwellsBridge() {
|
|
|
8502
10664
|
if (toolbarVariantRef.current === "select-frame") {
|
|
8503
10665
|
hoveredNavContainerRef.current = null;
|
|
8504
10666
|
setHoveredNavContainerRect(null);
|
|
8505
|
-
return;
|
|
8506
10667
|
}
|
|
8507
|
-
const
|
|
8508
|
-
|
|
8509
|
-
|
|
8510
|
-
|
|
8511
|
-
|
|
10668
|
+
const navContainers = Array.from(
|
|
10669
|
+
document.querySelectorAll("[data-ohw-nav-container]")
|
|
10670
|
+
);
|
|
10671
|
+
const footerColumns = listFooterColumns();
|
|
10672
|
+
for (const container of [...navContainers, ...footerColumns]) {
|
|
10673
|
+
const containerRect = container.getBoundingClientRect();
|
|
10674
|
+
const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
|
|
10675
|
+
if (!overContainer) continue;
|
|
10676
|
+
const navItemHit = Array.from(
|
|
10677
|
+
container.querySelectorAll("[data-ohw-href-key]")
|
|
10678
|
+
).find((el) => {
|
|
10679
|
+
if (!isNavigationItem(el) || isNavbarButton2(el)) return false;
|
|
10680
|
+
const itemRect = el.getBoundingClientRect();
|
|
10681
|
+
return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
|
|
10682
|
+
});
|
|
10683
|
+
if (navItemHit) {
|
|
10684
|
+
hoveredNavContainerRef.current = null;
|
|
10685
|
+
setHoveredNavContainerRect(null);
|
|
10686
|
+
const selected = selectedElRef.current;
|
|
10687
|
+
if (selected !== navItemHit) {
|
|
10688
|
+
clearHrefKeyHover(navItemHit);
|
|
10689
|
+
hoveredItemElRef.current = navItemHit;
|
|
10690
|
+
setHoveredItemRect(navItemHit.getBoundingClientRect());
|
|
10691
|
+
} else if (hoveredItemElRef.current === navItemHit) {
|
|
10692
|
+
hoveredItemElRef.current = null;
|
|
10693
|
+
setHoveredItemRect(null);
|
|
10694
|
+
}
|
|
10695
|
+
return;
|
|
10696
|
+
}
|
|
8512
10697
|
}
|
|
8513
|
-
|
|
8514
|
-
|
|
8515
|
-
|
|
10698
|
+
if (toolbarVariantRef.current !== "select-frame") {
|
|
10699
|
+
for (const container of navContainers) {
|
|
10700
|
+
const containerRect = container.getBoundingClientRect();
|
|
10701
|
+
const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
|
|
10702
|
+
if (!overContainer) continue;
|
|
10703
|
+
if (isPointOverNavItem(container, x, y)) continue;
|
|
10704
|
+
hoveredNavContainerRef.current = container;
|
|
10705
|
+
setHoveredNavContainerRect(container.getBoundingClientRect());
|
|
10706
|
+
hoveredItemElRef.current = null;
|
|
10707
|
+
setHoveredItemRect(null);
|
|
10708
|
+
return;
|
|
10709
|
+
}
|
|
8516
10710
|
hoveredNavContainerRef.current = null;
|
|
8517
10711
|
setHoveredNavContainerRect(null);
|
|
8518
|
-
|
|
8519
|
-
}
|
|
8520
|
-
const navItemHit = Array.from(
|
|
8521
|
-
navContainer.querySelectorAll("[data-ohw-href-key]")
|
|
8522
|
-
).find((el) => {
|
|
8523
|
-
if (!isNavigationItem(el) || isNavbarButton2(el)) return false;
|
|
8524
|
-
const itemRect = el.getBoundingClientRect();
|
|
8525
|
-
return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
|
|
8526
|
-
});
|
|
8527
|
-
if (navItemHit) {
|
|
10712
|
+
} else {
|
|
8528
10713
|
hoveredNavContainerRef.current = null;
|
|
8529
10714
|
setHoveredNavContainerRect(null);
|
|
8530
|
-
|
|
8531
|
-
|
|
8532
|
-
|
|
8533
|
-
|
|
8534
|
-
|
|
10715
|
+
}
|
|
10716
|
+
for (const column of footerColumns) {
|
|
10717
|
+
const containerRect = column.getBoundingClientRect();
|
|
10718
|
+
const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
|
|
10719
|
+
if (!overContainer) continue;
|
|
10720
|
+
if (isPointOverNavItem(column, x, y)) continue;
|
|
10721
|
+
if (selectedElRef.current === column) {
|
|
10722
|
+
if (hoveredItemElRef.current === column) {
|
|
10723
|
+
hoveredItemElRef.current = null;
|
|
10724
|
+
setHoveredItemRect(null);
|
|
10725
|
+
}
|
|
10726
|
+
return;
|
|
8535
10727
|
}
|
|
10728
|
+
hoveredItemElRef.current = column;
|
|
10729
|
+
setHoveredItemRect(column.getBoundingClientRect());
|
|
8536
10730
|
return;
|
|
8537
10731
|
}
|
|
8538
|
-
|
|
8539
|
-
|
|
8540
|
-
|
|
8541
|
-
|
|
10732
|
+
if (hoveredItemElRef.current?.hasAttribute("data-ohw-footer-col") || hoveredItemElRef.current?.hasAttribute("data-ohw-footer-column")) {
|
|
10733
|
+
hoveredItemElRef.current = null;
|
|
10734
|
+
setHoveredItemRect(null);
|
|
10735
|
+
}
|
|
8542
10736
|
};
|
|
8543
10737
|
const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
|
|
8544
10738
|
if (linkPopoverOpenRef.current) {
|
|
@@ -8559,6 +10753,10 @@ function OhhwellsBridge() {
|
|
|
8559
10753
|
}
|
|
8560
10754
|
hoveredNavContainerRef.current = null;
|
|
8561
10755
|
setHoveredNavContainerRect(null);
|
|
10756
|
+
if (hoveredItemElRef.current?.hasAttribute("data-ohw-footer-col") || hoveredItemElRef.current?.hasAttribute("data-ohw-footer-column")) {
|
|
10757
|
+
hoveredItemElRef.current = null;
|
|
10758
|
+
setHoveredItemRect(null);
|
|
10759
|
+
}
|
|
8562
10760
|
const toggleEl = document.querySelector("[data-ohw-state-toggle]");
|
|
8563
10761
|
if (toggleEl) {
|
|
8564
10762
|
const tr = toggleEl.getBoundingClientRect();
|
|
@@ -8806,6 +11004,15 @@ function OhhwellsBridge() {
|
|
|
8806
11004
|
probeHoverCardsAt(clientX, clientY);
|
|
8807
11005
|
};
|
|
8808
11006
|
const handleDragOver = (e) => {
|
|
11007
|
+
const footerSession = footerDragRef.current;
|
|
11008
|
+
if (footerSession) {
|
|
11009
|
+
e.preventDefault();
|
|
11010
|
+
if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
|
|
11011
|
+
const slot = footerSession.kind === "link" && footerSession.hrefKey ? hitTestLinkDropSlot(e.clientX, e.clientY, footerSession.hrefKey) : hitTestColumnDropSlot(e.clientX, e.clientY);
|
|
11012
|
+
refreshFooterDragVisualsRef.current(footerSession, slot, e.clientX, e.clientY);
|
|
11013
|
+
return;
|
|
11014
|
+
}
|
|
11015
|
+
if (onNavDragOver(e)) return;
|
|
8809
11016
|
e.preventDefault();
|
|
8810
11017
|
const el = findImageAtPoint(e.clientX, e.clientY, false);
|
|
8811
11018
|
if (!el) {
|
|
@@ -8968,8 +11175,8 @@ function OhhwellsBridge() {
|
|
|
8968
11175
|
if (sibling !== el) sibling.innerHTML = html;
|
|
8969
11176
|
});
|
|
8970
11177
|
const timers = autoSaveTimers.current;
|
|
8971
|
-
const
|
|
8972
|
-
if (
|
|
11178
|
+
const existing2 = timers.get(key);
|
|
11179
|
+
if (existing2) clearTimeout(existing2);
|
|
8973
11180
|
timers.set(key, setTimeout(() => {
|
|
8974
11181
|
timers.delete(key);
|
|
8975
11182
|
postToParentRef.current({ type: "ow:change", nodes: [{ key, text: html }] });
|
|
@@ -9012,6 +11219,7 @@ function OhhwellsBridge() {
|
|
|
9012
11219
|
}
|
|
9013
11220
|
editContentRef.current = { ...editContentRef.current, ...content };
|
|
9014
11221
|
reconcileNavbarItemsFromContent(editContentRef.current);
|
|
11222
|
+
syncNavigationDragCursorAttrs();
|
|
9015
11223
|
enforceLinkHrefs();
|
|
9016
11224
|
postToParentRef.current({ type: "ow:hydrate-done" });
|
|
9017
11225
|
};
|
|
@@ -9032,6 +11240,48 @@ function OhhwellsBridge() {
|
|
|
9032
11240
|
if (e.data?.type !== "ui:escape") return;
|
|
9033
11241
|
if (linkPopoverOpenRef.current) {
|
|
9034
11242
|
setLinkPopoverRef.current(null);
|
|
11243
|
+
return;
|
|
11244
|
+
}
|
|
11245
|
+
if (activeElRef.current) {
|
|
11246
|
+
const hrefCtx = getHrefKeyFromElement(activeElRef.current);
|
|
11247
|
+
const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
|
|
11248
|
+
if (navAnchor) {
|
|
11249
|
+
const el = activeElRef.current;
|
|
11250
|
+
if (originalContentRef.current !== null) {
|
|
11251
|
+
el.innerHTML = originalContentRef.current;
|
|
11252
|
+
}
|
|
11253
|
+
el.removeAttribute("contenteditable");
|
|
11254
|
+
el.removeAttribute("data-ohw-editing");
|
|
11255
|
+
activeElRef.current = null;
|
|
11256
|
+
setMaxBadge(null);
|
|
11257
|
+
setActiveCommands(/* @__PURE__ */ new Set());
|
|
11258
|
+
setToolbarShowEditLink(false);
|
|
11259
|
+
postToParentRef.current({ type: "ow:exit-edit" });
|
|
11260
|
+
reselectNavigationItemRef.current(navAnchor);
|
|
11261
|
+
return;
|
|
11262
|
+
}
|
|
11263
|
+
if (originalContentRef.current !== null) {
|
|
11264
|
+
activeElRef.current.innerHTML = originalContentRef.current;
|
|
11265
|
+
const key = activeElRef.current.dataset.ohwKey;
|
|
11266
|
+
if (key) {
|
|
11267
|
+
postToParentRef.current({ type: "ow:change", nodes: [{ key, text: originalContentRef.current }] });
|
|
11268
|
+
}
|
|
11269
|
+
}
|
|
11270
|
+
deselectRef.current();
|
|
11271
|
+
deactivateRef.current();
|
|
11272
|
+
return;
|
|
11273
|
+
}
|
|
11274
|
+
if (selectedElRef.current) {
|
|
11275
|
+
if (toolbarVariantRef.current === "select-frame") {
|
|
11276
|
+
deselectRef.current();
|
|
11277
|
+
return;
|
|
11278
|
+
}
|
|
11279
|
+
const parent = getNavigationSelectionParent(selectedElRef.current);
|
|
11280
|
+
if (parent && isNavigationContainer(parent)) {
|
|
11281
|
+
selectFrameRef.current(parent);
|
|
11282
|
+
} else {
|
|
11283
|
+
deselectRef.current();
|
|
11284
|
+
}
|
|
9035
11285
|
}
|
|
9036
11286
|
};
|
|
9037
11287
|
window.addEventListener("message", handleUiEscape);
|
|
@@ -9056,7 +11306,7 @@ function OhhwellsBridge() {
|
|
|
9056
11306
|
return;
|
|
9057
11307
|
}
|
|
9058
11308
|
const parent = getNavigationSelectionParent(selectedElRef.current);
|
|
9059
|
-
if (parent) {
|
|
11309
|
+
if (parent && isNavigationContainer(parent)) {
|
|
9060
11310
|
e.preventDefault();
|
|
9061
11311
|
selectFrameRef.current(parent);
|
|
9062
11312
|
} else {
|
|
@@ -9074,6 +11324,7 @@ function OhhwellsBridge() {
|
|
|
9074
11324
|
el2.innerHTML = originalContentRef.current;
|
|
9075
11325
|
}
|
|
9076
11326
|
el2.removeAttribute("contenteditable");
|
|
11327
|
+
el2.removeAttribute("data-ohw-editing");
|
|
9077
11328
|
activeElRef.current = null;
|
|
9078
11329
|
setMaxBadge(null);
|
|
9079
11330
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
@@ -9125,6 +11376,26 @@ function OhhwellsBridge() {
|
|
|
9125
11376
|
if (siblingHintElRef.current) {
|
|
9126
11377
|
setSiblingHintRect(siblingHintElRef.current.getBoundingClientRect());
|
|
9127
11378
|
}
|
|
11379
|
+
const selected = selectedElRef.current;
|
|
11380
|
+
if (selected && !footerDragRef.current && !navDragRef.current) {
|
|
11381
|
+
if (selected.hasAttribute("data-ohw-footer-col") || Boolean(selected.closest("footer") && isInferredFooterGroup(selected))) {
|
|
11382
|
+
setSiblingHintRects(
|
|
11383
|
+
listFooterColumns().filter((column) => column !== selected).map((column) => column.getBoundingClientRect())
|
|
11384
|
+
);
|
|
11385
|
+
} else if (isNavigationItem(selected)) {
|
|
11386
|
+
setSiblingHintRects(collectNavigationItemSiblingHintRects(selected));
|
|
11387
|
+
}
|
|
11388
|
+
}
|
|
11389
|
+
if (footerDragRef.current) {
|
|
11390
|
+
const session = footerDragRef.current;
|
|
11391
|
+
const slot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : hitTestColumnDropSlot(session.lastClientX, session.lastClientY);
|
|
11392
|
+
refreshFooterDragVisualsRef.current(session, slot, session.lastClientX, session.lastClientY);
|
|
11393
|
+
}
|
|
11394
|
+
if (navDragRef.current) {
|
|
11395
|
+
const session = navDragRef.current;
|
|
11396
|
+
const slot = hitTestNavDropSlot(session.lastClientX, session.lastClientY, session.hrefKey);
|
|
11397
|
+
refreshNavDragVisualsRef.current(session, slot, session.lastClientX, session.lastClientY);
|
|
11398
|
+
}
|
|
9128
11399
|
if (hoveredImageRef.current) {
|
|
9129
11400
|
const el = hoveredImageRef.current;
|
|
9130
11401
|
const r2 = el.getBoundingClientRect();
|
|
@@ -9135,7 +11406,7 @@ function OhhwellsBridge() {
|
|
|
9135
11406
|
};
|
|
9136
11407
|
const handleSave = (e) => {
|
|
9137
11408
|
if (e.data?.type !== "ow:save") return;
|
|
9138
|
-
const nodes = collectEditableNodes();
|
|
11409
|
+
const nodes = collectEditableNodes(editContentRef.current);
|
|
9139
11410
|
const tracker = document.querySelector("[data-ohw-sections-tracker]");
|
|
9140
11411
|
if (tracker?.textContent) nodes.push({ key: "__ohw_sections", type: "sections", text: tracker.textContent });
|
|
9141
11412
|
postToParentRef.current({ type: "ow:save-result", nodes });
|
|
@@ -9193,30 +11464,30 @@ function OhhwellsBridge() {
|
|
|
9193
11464
|
const h = document.documentElement.scrollHeight;
|
|
9194
11465
|
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
9195
11466
|
};
|
|
11467
|
+
let selectionChangeRaf = null;
|
|
11468
|
+
const runSelectionChange = () => {
|
|
11469
|
+
selectionChangeRaf = null;
|
|
11470
|
+
const activeRoot = activeElRef.current;
|
|
11471
|
+
if (!activeRoot) return;
|
|
11472
|
+
const startEl = resolveSelectionStartElement(window.getSelection());
|
|
11473
|
+
const next = startEl ? detectActiveFormats(startEl, activeRoot) : /* @__PURE__ */ new Set();
|
|
11474
|
+
setActiveCommands((prev) => setsEqual(prev, next) ? prev : next);
|
|
11475
|
+
};
|
|
9196
11476
|
const handleSelectionChange = () => {
|
|
9197
|
-
if (
|
|
9198
|
-
|
|
9199
|
-
|
|
9200
|
-
|
|
9201
|
-
|
|
9202
|
-
|
|
9203
|
-
|
|
9204
|
-
}
|
|
9205
|
-
const sel = window.getSelection();
|
|
9206
|
-
const anchor = sel?.anchorNode;
|
|
9207
|
-
if (anchor) {
|
|
9208
|
-
const el = anchor.nodeType === Node.TEXT_NODE ? anchor.parentElement : anchor;
|
|
9209
|
-
const block = el?.closest("div, p, h1, h2, h3, h4, h5, h6, li, td, th") ?? el;
|
|
9210
|
-
if (block) {
|
|
9211
|
-
const align = getComputedStyle(block).textAlign;
|
|
9212
|
-
if (align === "center") next.add("justifyCenter");
|
|
9213
|
-
else if (align === "right" || align === "end") next.add("justifyRight");
|
|
9214
|
-
else next.add("justifyLeft");
|
|
9215
|
-
}
|
|
9216
|
-
}
|
|
9217
|
-
setActiveCommands(next);
|
|
11477
|
+
if (pointerHeldRef.current) return;
|
|
11478
|
+
if (selectionChangeRaf !== null) return;
|
|
11479
|
+
selectionChangeRaf = requestAnimationFrame(runSelectionChange);
|
|
11480
|
+
};
|
|
11481
|
+
const markPointerHeld = (e) => {
|
|
11482
|
+
if (e.button !== 0) return;
|
|
11483
|
+
pointerHeldRef.current = true;
|
|
9218
11484
|
};
|
|
9219
|
-
|
|
11485
|
+
const markPointerReleased = () => {
|
|
11486
|
+
if (!pointerHeldRef.current) return;
|
|
11487
|
+
pointerHeldRef.current = false;
|
|
11488
|
+
handleSelectionChange();
|
|
11489
|
+
};
|
|
11490
|
+
refreshActiveCommandsRef.current = runSelectionChange;
|
|
9220
11491
|
const handleDocMouseLeave = () => {
|
|
9221
11492
|
hoveredImageRef.current = null;
|
|
9222
11493
|
setMediaHover(null);
|
|
@@ -9261,15 +11532,15 @@ function OhhwellsBridge() {
|
|
|
9261
11532
|
};
|
|
9262
11533
|
const applyToolbarPos = (rect) => {
|
|
9263
11534
|
const ps = parentScrollRef.current;
|
|
9264
|
-
const
|
|
11535
|
+
const measuredW = toolbarElRef.current?.offsetWidth || 330;
|
|
9265
11536
|
if (toolbarElRef.current) {
|
|
9266
|
-
const { top, left, transform } = calcToolbarPos(rect, ps,
|
|
11537
|
+
const { top, left, transform } = calcToolbarPos(rect, ps, measuredW);
|
|
9267
11538
|
toolbarElRef.current.style.top = `${top}px`;
|
|
9268
11539
|
toolbarElRef.current.style.left = `${left}px`;
|
|
9269
11540
|
toolbarElRef.current.style.transform = transform;
|
|
9270
11541
|
}
|
|
9271
11542
|
if (glowElRef.current) {
|
|
9272
|
-
const GAP =
|
|
11543
|
+
const GAP = SELECTION_CHROME_GAP2;
|
|
9273
11544
|
glowElRef.current.style.top = `${rect.top - GAP}px`;
|
|
9274
11545
|
glowElRef.current.style.left = `${rect.left - GAP}px`;
|
|
9275
11546
|
glowElRef.current.style.width = `${rect.width + GAP * 2}px`;
|
|
@@ -9357,6 +11628,11 @@ function OhhwellsBridge() {
|
|
|
9357
11628
|
return;
|
|
9358
11629
|
}
|
|
9359
11630
|
}
|
|
11631
|
+
const footerColumn = findHoveredNavOrFooterContainer(clientX, clientY);
|
|
11632
|
+
if (footerColumn?.hasAttribute("data-ohw-footer-col") || footerColumn?.hasAttribute("data-ohw-footer-column")) {
|
|
11633
|
+
selectFrameRef.current(footerColumn);
|
|
11634
|
+
return;
|
|
11635
|
+
}
|
|
9360
11636
|
deactivateRef.current();
|
|
9361
11637
|
};
|
|
9362
11638
|
window.addEventListener("message", handleSave);
|
|
@@ -9428,7 +11704,161 @@ function OhhwellsBridge() {
|
|
|
9428
11704
|
if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
|
|
9429
11705
|
};
|
|
9430
11706
|
}, [isEditMode, refreshStateRules]);
|
|
9431
|
-
(0,
|
|
11707
|
+
(0, import_react9.useEffect)(() => {
|
|
11708
|
+
if (!isEditMode) return;
|
|
11709
|
+
const THRESHOLD = 10;
|
|
11710
|
+
const resolveWasSelected = (el) => {
|
|
11711
|
+
if (selectedElRef.current === el) return true;
|
|
11712
|
+
const activeAnchor = activeElRef.current ? getNavigationItemAnchor(activeElRef.current) : null;
|
|
11713
|
+
return activeAnchor === el;
|
|
11714
|
+
};
|
|
11715
|
+
const onPointerDown = (e) => {
|
|
11716
|
+
if (e.button !== 0) return;
|
|
11717
|
+
if (suppressNextClickRef.current && Date.now() >= suppressClickUntilRef.current && !footerDragRef.current && !footerPointerDragRef.current?.started) {
|
|
11718
|
+
suppressNextClickRef.current = false;
|
|
11719
|
+
}
|
|
11720
|
+
if (footerDragRef.current) return;
|
|
11721
|
+
const target = e.target;
|
|
11722
|
+
if (!target) return;
|
|
11723
|
+
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]')) {
|
|
11724
|
+
return;
|
|
11725
|
+
}
|
|
11726
|
+
if (target.closest("[data-ohw-item-drag-surface]")) return;
|
|
11727
|
+
const anchor = getNavigationItemAnchor(target);
|
|
11728
|
+
const hrefKey = anchor?.getAttribute("data-ohw-href-key") ?? null;
|
|
11729
|
+
if (anchor && isFooterHrefKey(hrefKey)) {
|
|
11730
|
+
footerPointerDragRef.current = {
|
|
11731
|
+
el: anchor,
|
|
11732
|
+
kind: "link",
|
|
11733
|
+
startX: e.clientX,
|
|
11734
|
+
startY: e.clientY,
|
|
11735
|
+
pointerId: e.pointerId,
|
|
11736
|
+
wasSelected: resolveWasSelected(anchor),
|
|
11737
|
+
started: false
|
|
11738
|
+
};
|
|
11739
|
+
return;
|
|
11740
|
+
}
|
|
11741
|
+
const col = target.closest("[data-ohw-footer-col]");
|
|
11742
|
+
if (col && !getNavigationItemAnchor(target)) {
|
|
11743
|
+
footerPointerDragRef.current = {
|
|
11744
|
+
el: col,
|
|
11745
|
+
kind: "column",
|
|
11746
|
+
startX: e.clientX,
|
|
11747
|
+
startY: e.clientY,
|
|
11748
|
+
pointerId: e.pointerId,
|
|
11749
|
+
wasSelected: resolveWasSelected(col),
|
|
11750
|
+
started: false
|
|
11751
|
+
};
|
|
11752
|
+
}
|
|
11753
|
+
};
|
|
11754
|
+
const onPointerMove = (e) => {
|
|
11755
|
+
const pending = footerPointerDragRef.current;
|
|
11756
|
+
if (!pending) return;
|
|
11757
|
+
if (pending.started) {
|
|
11758
|
+
e.preventDefault();
|
|
11759
|
+
clearTextSelection();
|
|
11760
|
+
const session = footerDragRef.current;
|
|
11761
|
+
if (!session) return;
|
|
11762
|
+
const slot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(e.clientX, e.clientY, session.hrefKey) : hitTestColumnDropSlot(e.clientX, e.clientY);
|
|
11763
|
+
refreshFooterDragVisualsRef.current(session, slot, e.clientX, e.clientY);
|
|
11764
|
+
return;
|
|
11765
|
+
}
|
|
11766
|
+
const dx = e.clientX - pending.startX;
|
|
11767
|
+
const dy = e.clientY - pending.startY;
|
|
11768
|
+
if (dx * dx + dy * dy < THRESHOLD * THRESHOLD) return;
|
|
11769
|
+
e.preventDefault();
|
|
11770
|
+
pending.started = true;
|
|
11771
|
+
armFooterPressDrag();
|
|
11772
|
+
clearTextSelection();
|
|
11773
|
+
try {
|
|
11774
|
+
document.body.setPointerCapture(pending.pointerId);
|
|
11775
|
+
} catch {
|
|
11776
|
+
}
|
|
11777
|
+
if (linkPopoverOpenRef.current) {
|
|
11778
|
+
setLinkPopoverRef.current(null);
|
|
11779
|
+
}
|
|
11780
|
+
if (activeElRef.current) {
|
|
11781
|
+
deactivateRef.current();
|
|
11782
|
+
}
|
|
11783
|
+
if (pending.kind === "link") {
|
|
11784
|
+
const key = pending.el.getAttribute("data-ohw-href-key");
|
|
11785
|
+
if (!key) return;
|
|
11786
|
+
const column = findFooterColumnForLink(pending.el);
|
|
11787
|
+
const columns2 = listFooterColumns();
|
|
11788
|
+
beginFooterDragRef.current({
|
|
11789
|
+
kind: "link",
|
|
11790
|
+
hrefKey: key,
|
|
11791
|
+
columnEl: column,
|
|
11792
|
+
sourceColumnIndex: column ? columns2.indexOf(column) : 0,
|
|
11793
|
+
wasSelected: pending.wasSelected,
|
|
11794
|
+
draggedEl: pending.el,
|
|
11795
|
+
lastClientX: e.clientX,
|
|
11796
|
+
lastClientY: e.clientY,
|
|
11797
|
+
activeSlot: null
|
|
11798
|
+
});
|
|
11799
|
+
return;
|
|
11800
|
+
}
|
|
11801
|
+
const columns = listFooterColumns();
|
|
11802
|
+
const idx = columns.indexOf(pending.el);
|
|
11803
|
+
if (idx < 0) return;
|
|
11804
|
+
beginFooterDragRef.current({
|
|
11805
|
+
kind: "column",
|
|
11806
|
+
hrefKey: null,
|
|
11807
|
+
columnEl: pending.el,
|
|
11808
|
+
sourceColumnIndex: idx,
|
|
11809
|
+
wasSelected: pending.wasSelected,
|
|
11810
|
+
draggedEl: pending.el,
|
|
11811
|
+
lastClientX: e.clientX,
|
|
11812
|
+
lastClientY: e.clientY,
|
|
11813
|
+
activeSlot: null
|
|
11814
|
+
});
|
|
11815
|
+
};
|
|
11816
|
+
const endPointerDrag = (e) => {
|
|
11817
|
+
const pending = footerPointerDragRef.current;
|
|
11818
|
+
footerPointerDragRef.current = null;
|
|
11819
|
+
try {
|
|
11820
|
+
if (document.body.hasPointerCapture(e.pointerId)) {
|
|
11821
|
+
document.body.releasePointerCapture(e.pointerId);
|
|
11822
|
+
}
|
|
11823
|
+
} catch {
|
|
11824
|
+
}
|
|
11825
|
+
if (!pending) return;
|
|
11826
|
+
if (!pending.started) {
|
|
11827
|
+
unlockFooterDragInteraction();
|
|
11828
|
+
return;
|
|
11829
|
+
}
|
|
11830
|
+
suppressNextClickRef.current = true;
|
|
11831
|
+
suppressClickUntilRef.current = Date.now() + 500;
|
|
11832
|
+
commitFooterDragRef.current(e.clientX, e.clientY);
|
|
11833
|
+
};
|
|
11834
|
+
const blockSelectStart = (e) => {
|
|
11835
|
+
if (footerDragRef.current || footerPointerDragRef.current?.started || document.documentElement.hasAttribute("data-ohw-footer-press-drag")) {
|
|
11836
|
+
e.preventDefault();
|
|
11837
|
+
}
|
|
11838
|
+
};
|
|
11839
|
+
const onDragEnd = (_e) => {
|
|
11840
|
+
if (!footerDragRef.current) return;
|
|
11841
|
+
suppressNextClickRef.current = true;
|
|
11842
|
+
suppressClickUntilRef.current = Date.now() + 500;
|
|
11843
|
+
commitFooterDragRef.current();
|
|
11844
|
+
};
|
|
11845
|
+
document.addEventListener("pointerdown", onPointerDown, true);
|
|
11846
|
+
document.addEventListener("pointermove", onPointerMove, true);
|
|
11847
|
+
document.addEventListener("pointerup", endPointerDrag, true);
|
|
11848
|
+
document.addEventListener("pointercancel", endPointerDrag, true);
|
|
11849
|
+
document.addEventListener("selectstart", blockSelectStart, true);
|
|
11850
|
+
document.addEventListener("dragend", onDragEnd, true);
|
|
11851
|
+
return () => {
|
|
11852
|
+
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
11853
|
+
document.removeEventListener("pointermove", onPointerMove, true);
|
|
11854
|
+
document.removeEventListener("pointerup", endPointerDrag, true);
|
|
11855
|
+
document.removeEventListener("pointercancel", endPointerDrag, true);
|
|
11856
|
+
document.removeEventListener("selectstart", blockSelectStart, true);
|
|
11857
|
+
document.removeEventListener("dragend", onDragEnd, true);
|
|
11858
|
+
unlockFooterDragInteraction();
|
|
11859
|
+
};
|
|
11860
|
+
}, [isEditMode]);
|
|
11861
|
+
(0, import_react9.useEffect)(() => {
|
|
9432
11862
|
const handler = (e) => {
|
|
9433
11863
|
if (e.data?.type !== "ow:request-schedule-config") return;
|
|
9434
11864
|
const insertAfterVal = e.data.insertAfter;
|
|
@@ -9444,7 +11874,7 @@ function OhhwellsBridge() {
|
|
|
9444
11874
|
window.addEventListener("message", handler);
|
|
9445
11875
|
return () => window.removeEventListener("message", handler);
|
|
9446
11876
|
}, [processConfigRequest]);
|
|
9447
|
-
(0,
|
|
11877
|
+
(0, import_react9.useEffect)(() => {
|
|
9448
11878
|
if (!isEditMode) return;
|
|
9449
11879
|
document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
|
|
9450
11880
|
el.removeAttribute("data-ohw-active-state");
|
|
@@ -9465,7 +11895,13 @@ function OhhwellsBridge() {
|
|
|
9465
11895
|
const next = { ...prev, [pathKey]: sections };
|
|
9466
11896
|
return shouldUseDevFixtures() ? { ...DEV_SECTIONS_BY_PATH, ...next } : next;
|
|
9467
11897
|
});
|
|
9468
|
-
postToParent2({
|
|
11898
|
+
postToParent2({
|
|
11899
|
+
type: "ow:ready",
|
|
11900
|
+
version: "1",
|
|
11901
|
+
path: pathname,
|
|
11902
|
+
nodes: collectEditableNodes(editContentRef.current),
|
|
11903
|
+
sections
|
|
11904
|
+
});
|
|
9469
11905
|
postToParent2({ type: "ow:request-site-pages" });
|
|
9470
11906
|
}, 150);
|
|
9471
11907
|
return () => {
|
|
@@ -9473,19 +11909,49 @@ function OhhwellsBridge() {
|
|
|
9473
11909
|
clearTimeout(timer);
|
|
9474
11910
|
};
|
|
9475
11911
|
}, [pathname, isEditMode, refreshStateRules, postToParent2]);
|
|
9476
|
-
(0,
|
|
11912
|
+
(0, import_react9.useEffect)(() => {
|
|
9477
11913
|
scrollToHashSectionWhenReady();
|
|
9478
11914
|
const onHashChange = () => scrollToHashSectionWhenReady();
|
|
9479
11915
|
window.addEventListener("hashchange", onHashChange);
|
|
9480
11916
|
return () => window.removeEventListener("hashchange", onHashChange);
|
|
9481
11917
|
}, [pathname]);
|
|
9482
|
-
const handleCommand = (0,
|
|
11918
|
+
const handleCommand = (0, import_react9.useCallback)((cmd) => {
|
|
11919
|
+
const el = activeElRef.current;
|
|
11920
|
+
const selBefore = window.getSelection();
|
|
11921
|
+
let savedOffsets = null;
|
|
11922
|
+
if (el && selBefore && selBefore.rangeCount > 0 && !selBefore.isCollapsed) {
|
|
11923
|
+
const r2 = selBefore.getRangeAt(0);
|
|
11924
|
+
if (el.contains(r2.commonAncestorContainer)) {
|
|
11925
|
+
savedOffsets = {
|
|
11926
|
+
start: textOffsetInRoot(el, r2.startContainer, r2.startOffset),
|
|
11927
|
+
end: textOffsetInRoot(el, r2.endContainer, r2.endOffset)
|
|
11928
|
+
};
|
|
11929
|
+
}
|
|
11930
|
+
}
|
|
11931
|
+
document.execCommand("styleWithCSS", false, true);
|
|
9483
11932
|
document.execCommand(cmd, false);
|
|
9484
|
-
|
|
9485
|
-
|
|
11933
|
+
if (el && document.activeElement !== el) {
|
|
11934
|
+
el.focus();
|
|
11935
|
+
}
|
|
11936
|
+
const selAfter = window.getSelection();
|
|
11937
|
+
if (el && savedOffsets && selAfter?.isCollapsed) {
|
|
11938
|
+
const start = pointAtTextOffset(el, savedOffsets.start);
|
|
11939
|
+
const end = pointAtTextOffset(el, savedOffsets.end);
|
|
11940
|
+
if (start && end) {
|
|
11941
|
+
try {
|
|
11942
|
+
const range = document.createRange();
|
|
11943
|
+
range.setStart(start.node, start.offset);
|
|
11944
|
+
range.setEnd(end.node, end.offset);
|
|
11945
|
+
selAfter.removeAllRanges();
|
|
11946
|
+
selAfter.addRange(range);
|
|
11947
|
+
} catch {
|
|
11948
|
+
}
|
|
11949
|
+
}
|
|
11950
|
+
}
|
|
11951
|
+
if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
|
|
9486
11952
|
refreshActiveCommandsRef.current();
|
|
9487
11953
|
}, []);
|
|
9488
|
-
const handleStateChange = (0,
|
|
11954
|
+
const handleStateChange = (0, import_react9.useCallback)((state) => {
|
|
9489
11955
|
if (!activeStateElRef.current) return;
|
|
9490
11956
|
const el = activeStateElRef.current;
|
|
9491
11957
|
if (state === "Default") {
|
|
@@ -9498,11 +11964,11 @@ function OhhwellsBridge() {
|
|
|
9498
11964
|
}
|
|
9499
11965
|
setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
|
|
9500
11966
|
}, [deactivate]);
|
|
9501
|
-
const closeLinkPopover = (0,
|
|
11967
|
+
const closeLinkPopover = (0, import_react9.useCallback)(() => {
|
|
9502
11968
|
addNavAfterAnchorRef.current = null;
|
|
9503
11969
|
setLinkPopover(null);
|
|
9504
11970
|
}, []);
|
|
9505
|
-
const openLinkPopoverForActive = (0,
|
|
11971
|
+
const openLinkPopoverForActive = (0, import_react9.useCallback)(() => {
|
|
9506
11972
|
const hrefCtx = getHrefKeyFromElement(activeElRef.current);
|
|
9507
11973
|
if (!hrefCtx) return;
|
|
9508
11974
|
bumpLinkPopoverGrace();
|
|
@@ -9513,7 +11979,7 @@ function OhhwellsBridge() {
|
|
|
9513
11979
|
});
|
|
9514
11980
|
deactivate();
|
|
9515
11981
|
}, [deactivate]);
|
|
9516
|
-
const openLinkPopoverForSelected = (0,
|
|
11982
|
+
const openLinkPopoverForSelected = (0, import_react9.useCallback)(() => {
|
|
9517
11983
|
const anchor = selectedElRef.current;
|
|
9518
11984
|
if (!anchor) return;
|
|
9519
11985
|
const key = anchor.getAttribute("data-ohw-href-key");
|
|
@@ -9526,7 +11992,7 @@ function OhhwellsBridge() {
|
|
|
9526
11992
|
});
|
|
9527
11993
|
deselect();
|
|
9528
11994
|
}, [deselect]);
|
|
9529
|
-
const handleLinkPopoverSubmit = (0,
|
|
11995
|
+
const handleLinkPopoverSubmit = (0, import_react9.useCallback)(
|
|
9530
11996
|
(target) => {
|
|
9531
11997
|
const session = linkPopoverSessionRef.current;
|
|
9532
11998
|
if (!session) return;
|
|
@@ -9585,13 +12051,13 @@ function OhhwellsBridge() {
|
|
|
9585
12051
|
const showEditLink = toolbarShowEditLink;
|
|
9586
12052
|
const currentSections = sectionsByPath[pathname] ?? [];
|
|
9587
12053
|
linkPopoverOpenRef.current = linkPopover !== null;
|
|
9588
|
-
const handleMediaReplace = (0,
|
|
12054
|
+
const handleMediaReplace = (0, import_react9.useCallback)(
|
|
9589
12055
|
(key) => {
|
|
9590
12056
|
postToParent2({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
|
|
9591
12057
|
},
|
|
9592
12058
|
[postToParent2, mediaHover?.elementType]
|
|
9593
12059
|
);
|
|
9594
|
-
const handleMediaFadeOutComplete = (0,
|
|
12060
|
+
const handleMediaFadeOutComplete = (0, import_react9.useCallback)((key) => {
|
|
9595
12061
|
setUploadingRects((prev) => {
|
|
9596
12062
|
if (!(key in prev)) return prev;
|
|
9597
12063
|
const next = { ...prev };
|
|
@@ -9599,7 +12065,7 @@ function OhhwellsBridge() {
|
|
|
9599
12065
|
return next;
|
|
9600
12066
|
});
|
|
9601
12067
|
}, []);
|
|
9602
|
-
const handleVideoSettingsChange = (0,
|
|
12068
|
+
const handleVideoSettingsChange = (0, import_react9.useCallback)(
|
|
9603
12069
|
(key, settings) => {
|
|
9604
12070
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
9605
12071
|
const video = getVideoEl(el);
|
|
@@ -9622,9 +12088,9 @@ function OhhwellsBridge() {
|
|
|
9622
12088
|
[postToParent2]
|
|
9623
12089
|
);
|
|
9624
12090
|
return bridgeRoot ? (0, import_react_dom3.createPortal)(
|
|
9625
|
-
/* @__PURE__ */ (0,
|
|
9626
|
-
/* @__PURE__ */ (0,
|
|
9627
|
-
Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0,
|
|
12091
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
|
|
12092
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
|
|
12093
|
+
Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
9628
12094
|
MediaOverlay,
|
|
9629
12095
|
{
|
|
9630
12096
|
hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
|
|
@@ -9635,7 +12101,7 @@ function OhhwellsBridge() {
|
|
|
9635
12101
|
},
|
|
9636
12102
|
`uploading-${key}`
|
|
9637
12103
|
)),
|
|
9638
|
-
mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ (0,
|
|
12104
|
+
mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
9639
12105
|
MediaOverlay,
|
|
9640
12106
|
{
|
|
9641
12107
|
hover: mediaHover,
|
|
@@ -9644,49 +12110,93 @@ function OhhwellsBridge() {
|
|
|
9644
12110
|
onVideoSettingsChange: handleVideoSettingsChange
|
|
9645
12111
|
}
|
|
9646
12112
|
),
|
|
9647
|
-
siblingHintRect && !isItemDragging && /* @__PURE__ */ (0,
|
|
9648
|
-
|
|
9649
|
-
|
|
9650
|
-
|
|
12113
|
+
siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
|
|
12114
|
+
siblingHintRects.length > 0 && !linkPopover && siblingHintRects.map((rect, i) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
|
|
12115
|
+
isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
|
|
12116
|
+
isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
12117
|
+
"div",
|
|
9651
12118
|
{
|
|
9652
|
-
|
|
9653
|
-
|
|
9654
|
-
|
|
9655
|
-
|
|
9656
|
-
|
|
9657
|
-
|
|
12119
|
+
className: "pointer-events-none fixed z-2147483646",
|
|
12120
|
+
style: {
|
|
12121
|
+
left: slot.left,
|
|
12122
|
+
top: slot.top,
|
|
12123
|
+
width: slot.width,
|
|
12124
|
+
height: slot.height
|
|
12125
|
+
},
|
|
12126
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
12127
|
+
DropIndicator,
|
|
12128
|
+
{
|
|
12129
|
+
direction: slot.direction,
|
|
12130
|
+
state: activeFooterDropIndex === i ? "dragActive" : "dragIdle",
|
|
12131
|
+
className: "!h-full !w-full"
|
|
12132
|
+
}
|
|
12133
|
+
)
|
|
12134
|
+
},
|
|
12135
|
+
`footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
|
|
12136
|
+
)),
|
|
12137
|
+
isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
12138
|
+
"div",
|
|
12139
|
+
{
|
|
12140
|
+
className: "pointer-events-none fixed z-2147483646",
|
|
12141
|
+
style: {
|
|
12142
|
+
left: slot.left,
|
|
12143
|
+
top: slot.top,
|
|
12144
|
+
width: slot.width,
|
|
12145
|
+
height: slot.height
|
|
12146
|
+
},
|
|
12147
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
12148
|
+
DropIndicator,
|
|
12149
|
+
{
|
|
12150
|
+
direction: slot.direction,
|
|
12151
|
+
state: activeNavDropIndex === i ? "dragActive" : "dragIdle",
|
|
12152
|
+
className: "!h-full !w-full"
|
|
12153
|
+
}
|
|
12154
|
+
)
|
|
12155
|
+
},
|
|
12156
|
+
`nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
|
|
12157
|
+
)),
|
|
12158
|
+
hoveredNavContainerRect && toolbarVariant !== "select-frame" && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
|
|
12159
|
+
hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
|
|
12160
|
+
toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
|
|
12161
|
+
toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
9658
12162
|
ItemInteractionLayer,
|
|
9659
12163
|
{
|
|
9660
|
-
rect: toolbarRect,
|
|
12164
|
+
rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
|
|
9661
12165
|
elRef: glowElRef,
|
|
9662
12166
|
state: isItemDragging ? "dragging" : resolveItemInteractionState(toolbarRect, parentScrollRef.current),
|
|
9663
|
-
showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey),
|
|
12167
|
+
showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey) || toolbarVariant === "select-frame" && isFooterFrameSelection,
|
|
9664
12168
|
dragDisabled: reorderDragDisabled,
|
|
9665
12169
|
dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
|
|
9666
12170
|
onDragHandleDragStart: handleItemDragStart,
|
|
9667
12171
|
onDragHandleDragEnd: handleItemDragEnd,
|
|
9668
|
-
|
|
12172
|
+
onItemPointerDown: handleItemChromePointerDown,
|
|
12173
|
+
onItemClick: handleItemChromeClick,
|
|
12174
|
+
itemDragSurface: !isFooterFrameSelection,
|
|
12175
|
+
toolbar: toolbarVariant === "link-action" && !isItemDragging ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
9669
12176
|
ItemActionToolbar,
|
|
9670
12177
|
{
|
|
9671
12178
|
onEditLink: openLinkPopoverForSelected,
|
|
9672
12179
|
addItemDisabled: true,
|
|
9673
12180
|
editLinkDisabled: false,
|
|
9674
|
-
moreDisabled: true
|
|
12181
|
+
moreDisabled: true,
|
|
12182
|
+
showAddItem: !selectedIsCta,
|
|
12183
|
+
showMore: !selectedIsCta
|
|
9675
12184
|
}
|
|
9676
12185
|
) : void 0
|
|
9677
12186
|
}
|
|
9678
12187
|
),
|
|
9679
|
-
toolbarRect && toolbarVariant === "rich-text" && /* @__PURE__ */ (0,
|
|
9680
|
-
/* @__PURE__ */ (0,
|
|
12188
|
+
toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
|
|
12189
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
9681
12190
|
EditGlowChrome,
|
|
9682
12191
|
{
|
|
9683
12192
|
rect: toolbarRect,
|
|
9684
12193
|
elRef: glowElRef,
|
|
9685
12194
|
reorderHrefKey,
|
|
9686
|
-
dragDisabled: reorderDragDisabled
|
|
12195
|
+
dragDisabled: reorderDragDisabled,
|
|
12196
|
+
hideHandle: isItemDragging
|
|
9687
12197
|
}
|
|
9688
12198
|
),
|
|
9689
|
-
/* @__PURE__ */ (0,
|
|
12199
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
9690
12200
|
FloatingToolbar,
|
|
9691
12201
|
{
|
|
9692
12202
|
rect: toolbarRect,
|
|
@@ -9699,7 +12209,7 @@ function OhhwellsBridge() {
|
|
|
9699
12209
|
}
|
|
9700
12210
|
)
|
|
9701
12211
|
] }),
|
|
9702
|
-
maxBadge && /* @__PURE__ */ (0,
|
|
12212
|
+
maxBadge && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
9703
12213
|
"div",
|
|
9704
12214
|
{
|
|
9705
12215
|
"data-ohw-max-badge": "",
|
|
@@ -9725,7 +12235,7 @@ function OhhwellsBridge() {
|
|
|
9725
12235
|
]
|
|
9726
12236
|
}
|
|
9727
12237
|
),
|
|
9728
|
-
toggleState && !linkPopover && /* @__PURE__ */ (0,
|
|
12238
|
+
toggleState && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
9729
12239
|
StateToggle,
|
|
9730
12240
|
{
|
|
9731
12241
|
rect: toggleState.rect,
|
|
@@ -9734,32 +12244,36 @@ function OhhwellsBridge() {
|
|
|
9734
12244
|
onStateChange: handleStateChange
|
|
9735
12245
|
}
|
|
9736
12246
|
),
|
|
9737
|
-
sectionGap && !linkPopover && /* @__PURE__ */ (0,
|
|
12247
|
+
sectionGap && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
9738
12248
|
"div",
|
|
9739
12249
|
{
|
|
9740
12250
|
"data-ohw-section-insert-line": "",
|
|
9741
12251
|
className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
|
|
9742
12252
|
style: { top: sectionGap.y, transform: "translateY(-50%)" },
|
|
9743
12253
|
children: [
|
|
9744
|
-
/* @__PURE__ */ (0,
|
|
9745
|
-
/* @__PURE__ */ (0,
|
|
12254
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
|
|
12255
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
9746
12256
|
Badge,
|
|
9747
12257
|
{
|
|
9748
12258
|
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",
|
|
9749
12259
|
onClick: () => {
|
|
9750
12260
|
window.parent.postMessage(
|
|
9751
|
-
{
|
|
12261
|
+
{
|
|
12262
|
+
type: "ow:add-section",
|
|
12263
|
+
insertAfter: sectionGap.insertAfter,
|
|
12264
|
+
insertBefore: sectionGap.insertBefore
|
|
12265
|
+
},
|
|
9752
12266
|
"*"
|
|
9753
12267
|
);
|
|
9754
12268
|
},
|
|
9755
12269
|
children: "Add Section"
|
|
9756
12270
|
}
|
|
9757
12271
|
),
|
|
9758
|
-
/* @__PURE__ */ (0,
|
|
12272
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
|
|
9759
12273
|
]
|
|
9760
12274
|
}
|
|
9761
12275
|
),
|
|
9762
|
-
linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0,
|
|
12276
|
+
linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
9763
12277
|
LinkPopover,
|
|
9764
12278
|
{
|
|
9765
12279
|
panelRef: linkPopoverPanelRef,
|
|
@@ -9786,6 +12300,7 @@ function OhhwellsBridge() {
|
|
|
9786
12300
|
CustomToolbarButton,
|
|
9787
12301
|
CustomToolbarDivider,
|
|
9788
12302
|
DragHandle,
|
|
12303
|
+
DropIndicator,
|
|
9789
12304
|
ItemActionToolbar,
|
|
9790
12305
|
ItemInteractionLayer,
|
|
9791
12306
|
LinkEditorPanel,
|
|
@@ -9800,6 +12315,7 @@ function OhhwellsBridge() {
|
|
|
9800
12315
|
TooltipProvider,
|
|
9801
12316
|
TooltipTrigger,
|
|
9802
12317
|
buildTarget,
|
|
12318
|
+
dropIndicatorVariants,
|
|
9803
12319
|
filterAvailablePages,
|
|
9804
12320
|
getEditModeInitialState,
|
|
9805
12321
|
isEditSessionActive,
|