@ohhwells/bridge 0.1.37 → 0.1.38-next.56
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 +2105 -614
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +51 -4
- package/dist/index.d.ts +51 -4
- package/dist/index.js +2103 -612
- package/dist/index.js.map +1 -1
- package/dist/styles.css +156 -21
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -60,15 +60,18 @@ __export(index_exports, {
|
|
|
60
60
|
module.exports = __toCommonJS(index_exports);
|
|
61
61
|
|
|
62
62
|
// src/OhhwellsBridge.tsx
|
|
63
|
-
var
|
|
63
|
+
var import_react8 = __toESM(require("react"), 1);
|
|
64
64
|
var import_client = require("react-dom/client");
|
|
65
|
-
var
|
|
65
|
+
var import_react_dom2 = require("react-dom");
|
|
66
66
|
|
|
67
67
|
// src/linkHrefStore.ts
|
|
68
68
|
var linkHrefStore = /* @__PURE__ */ new Map();
|
|
69
69
|
function setStoredLinkHref(key, href) {
|
|
70
70
|
linkHrefStore.set(key, href);
|
|
71
71
|
}
|
|
72
|
+
function getStoredLinkHref(key) {
|
|
73
|
+
return linkHrefStore.get(key);
|
|
74
|
+
}
|
|
72
75
|
function enforceLinkHrefs() {
|
|
73
76
|
document.querySelectorAll("[data-ohw-href-key]").forEach((el) => {
|
|
74
77
|
const key = el.getAttribute("data-ohw-href-key") ?? "";
|
|
@@ -110,6 +113,7 @@ var import_react3 = require("react");
|
|
|
110
113
|
var import_react2 = require("react");
|
|
111
114
|
var import_radix_ui = require("radix-ui");
|
|
112
115
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
116
|
+
var isValidEmail = (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
|
|
113
117
|
function Spinner() {
|
|
114
118
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
115
119
|
"svg",
|
|
@@ -143,12 +147,17 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
|
|
|
143
147
|
const [error, setError] = (0, import_react2.useState)(null);
|
|
144
148
|
const isBook = title === "Confirm your spot";
|
|
145
149
|
const handleSubmit = async () => {
|
|
146
|
-
|
|
150
|
+
const trimmed = email.trim();
|
|
151
|
+
if (!trimmed) return;
|
|
152
|
+
if (!isValidEmail(trimmed)) {
|
|
153
|
+
setError("Please enter a valid email address.");
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
147
156
|
setLoading(true);
|
|
148
157
|
setError(null);
|
|
149
158
|
try {
|
|
150
|
-
await onSubmit(
|
|
151
|
-
setSubmittedEmail(
|
|
159
|
+
await onSubmit(trimmed);
|
|
160
|
+
setSubmittedEmail(trimmed);
|
|
152
161
|
setSuccess(true);
|
|
153
162
|
} catch (e) {
|
|
154
163
|
setError(e instanceof Error ? e.message : "Something went wrong. Please try again.");
|
|
@@ -223,7 +232,10 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
|
|
|
223
232
|
{
|
|
224
233
|
type: "email",
|
|
225
234
|
value: email,
|
|
226
|
-
onChange: (e) =>
|
|
235
|
+
onChange: (e) => {
|
|
236
|
+
setEmail(e.target.value);
|
|
237
|
+
if (error) setError(null);
|
|
238
|
+
},
|
|
227
239
|
onKeyDown: handleKeyDown,
|
|
228
240
|
placeholder: "hello@gmail.com",
|
|
229
241
|
autoFocus: true,
|
|
@@ -280,12 +292,20 @@ function formatClassTime(cls) {
|
|
|
280
292
|
const em = endTotal % 60;
|
|
281
293
|
return `${h}:${cls.startTime.minutes}-${eh}:${String(em).padStart(2, "0")}`;
|
|
282
294
|
}
|
|
295
|
+
function formatBookingLabel(cls) {
|
|
296
|
+
const price = cls.price;
|
|
297
|
+
const isFree = price === null || price === void 0 || `${price}` === "" || `${price}` === "0";
|
|
298
|
+
return isFree ? "Book for free" : `Book for ${cls.currency ?? ""} ${price}`.trim();
|
|
299
|
+
}
|
|
283
300
|
function getBookingsOnDate(cls, date) {
|
|
284
301
|
if (!cls.bookings?.length) return 0;
|
|
285
|
-
const
|
|
302
|
+
const target = new Date(date);
|
|
303
|
+
target.setHours(0, 0, 0, 0);
|
|
286
304
|
return cls.bookings.filter((b) => {
|
|
287
305
|
try {
|
|
288
|
-
|
|
306
|
+
const bookingDate = new Date(b.classDate);
|
|
307
|
+
bookingDate.setHours(0, 0, 0, 0);
|
|
308
|
+
return bookingDate.getTime() === target.getTime();
|
|
289
309
|
} catch {
|
|
290
310
|
return false;
|
|
291
311
|
}
|
|
@@ -589,7 +609,7 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
|
|
|
589
609
|
if (!cls.id) return;
|
|
590
610
|
onOpenModal?.(isFull ? "waitlist" : "book", cls.id, selectedDate);
|
|
591
611
|
},
|
|
592
|
-
children: isFull ? "Join Waitlist" :
|
|
612
|
+
children: isFull ? "Join Waitlist" : formatBookingLabel(cls)
|
|
593
613
|
}
|
|
594
614
|
)
|
|
595
615
|
] })
|
|
@@ -631,6 +651,17 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
631
651
|
const [isHovered, setIsHovered] = (0, import_react3.useState)(false);
|
|
632
652
|
const [modalState, setModalState] = (0, import_react3.useState)(null);
|
|
633
653
|
const switchScheduleIdRef = (0, import_react3.useRef)(null);
|
|
654
|
+
const liveScheduleIdRef = (0, import_react3.useRef)(null);
|
|
655
|
+
const refetchLiveSchedule = (0, import_react3.useCallback)(async () => {
|
|
656
|
+
const id = liveScheduleIdRef.current;
|
|
657
|
+
if (!id) return;
|
|
658
|
+
try {
|
|
659
|
+
const res = await fetch(`${API_URL}/api/schedule/id/${id}`);
|
|
660
|
+
const data = await res.json();
|
|
661
|
+
if (data?.id) setSchedule(data);
|
|
662
|
+
} catch {
|
|
663
|
+
}
|
|
664
|
+
}, []);
|
|
634
665
|
const dates = (0, import_react3.useMemo)(() => {
|
|
635
666
|
const today = /* @__PURE__ */ new Date();
|
|
636
667
|
today.setHours(0, 0, 0, 0);
|
|
@@ -650,6 +681,18 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
650
681
|
}
|
|
651
682
|
}
|
|
652
683
|
}, [schedule, dates]);
|
|
684
|
+
(0, import_react3.useEffect)(() => {
|
|
685
|
+
if (typeof window === "undefined") return;
|
|
686
|
+
const onVisible = () => {
|
|
687
|
+
if (!document.hidden) void refetchLiveSchedule();
|
|
688
|
+
};
|
|
689
|
+
window.addEventListener("focus", refetchLiveSchedule);
|
|
690
|
+
document.addEventListener("visibilitychange", onVisible);
|
|
691
|
+
return () => {
|
|
692
|
+
window.removeEventListener("focus", refetchLiveSchedule);
|
|
693
|
+
document.removeEventListener("visibilitychange", onVisible);
|
|
694
|
+
};
|
|
695
|
+
}, [refetchLiveSchedule]);
|
|
653
696
|
(0, import_react3.useEffect)(() => {
|
|
654
697
|
if (typeof window === "undefined") return;
|
|
655
698
|
const isInEditor = window.self !== window.top;
|
|
@@ -711,7 +754,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
711
754
|
setLoading(false);
|
|
712
755
|
return;
|
|
713
756
|
}
|
|
714
|
-
;
|
|
757
|
+
liveScheduleIdRef.current = effectiveId;
|
|
715
758
|
(async () => {
|
|
716
759
|
try {
|
|
717
760
|
const res = await fetch(`${API_URL}/api/schedule/id/${effectiveId}`);
|
|
@@ -768,18 +811,14 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
768
811
|
const data = await res.json().catch(() => ({}));
|
|
769
812
|
throw new Error(data?.message ?? "Something went wrong. Please try again.");
|
|
770
813
|
}
|
|
814
|
+
await refetchLiveSchedule();
|
|
771
815
|
};
|
|
772
816
|
const handleReplaceSchedule = () => {
|
|
773
817
|
setIsHovered(false);
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
insertAfter
|
|
779
|
-
}, "*");
|
|
780
|
-
} else {
|
|
781
|
-
window.parent.postMessage({ type: "ow:scheduling-not-connected", insertAfter }, "*");
|
|
782
|
-
}
|
|
818
|
+
window.parent.postMessage(
|
|
819
|
+
{ type: "ow:scheduling-not-connected", insertAfter, currentScheduleId: schedule?.id },
|
|
820
|
+
"*"
|
|
821
|
+
);
|
|
783
822
|
};
|
|
784
823
|
if (!inEditor && !loading && !schedule) return null;
|
|
785
824
|
const sectionId = `scheduling-${insertAfter}`;
|
|
@@ -822,7 +861,19 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
822
861
|
),
|
|
823
862
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "max-w-[1280px] mx-auto flex flex-col items-center gap-16", children: [
|
|
824
863
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col items-center gap-4", children: [
|
|
825
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
864
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
865
|
+
"h2",
|
|
866
|
+
{
|
|
867
|
+
className: "font-display text-center m-0 text-(--color-dark,#200C02)",
|
|
868
|
+
style: {
|
|
869
|
+
fontSize: "var(--fs-section-h2, clamp(40px, 4.4vw, 64px))",
|
|
870
|
+
fontWeight: "var(--font-weight-heading, 400)",
|
|
871
|
+
lineHeight: 1.05,
|
|
872
|
+
letterSpacing: "-0.02em"
|
|
873
|
+
},
|
|
874
|
+
children: schedule?.name ?? "Book an appointment"
|
|
875
|
+
}
|
|
876
|
+
),
|
|
826
877
|
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 })
|
|
827
878
|
] }),
|
|
828
879
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "w-full flex flex-col items-end gap-3", children: [
|
|
@@ -4408,6 +4459,7 @@ function ItemActionToolbar({
|
|
|
4408
4459
|
onEditLink,
|
|
4409
4460
|
onAddItem,
|
|
4410
4461
|
onMore,
|
|
4462
|
+
editLinkDisabled = false,
|
|
4411
4463
|
addItemDisabled = true,
|
|
4412
4464
|
moreDisabled = true,
|
|
4413
4465
|
tooltipSide = "bottom"
|
|
@@ -4416,10 +4468,12 @@ function ItemActionToolbar({
|
|
|
4416
4468
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
4417
4469
|
ToolbarActionTooltip,
|
|
4418
4470
|
{
|
|
4419
|
-
label: "
|
|
4471
|
+
label: "Edit link",
|
|
4420
4472
|
side: tooltipSide,
|
|
4473
|
+
disabled: editLinkDisabled,
|
|
4421
4474
|
buttonProps: {
|
|
4422
4475
|
onMouseDown: (e) => {
|
|
4476
|
+
if (editLinkDisabled) return;
|
|
4423
4477
|
e.preventDefault();
|
|
4424
4478
|
e.stopPropagation();
|
|
4425
4479
|
onEditLink?.();
|
|
@@ -4591,9 +4645,223 @@ function ItemInteractionLayer({
|
|
|
4591
4645
|
);
|
|
4592
4646
|
}
|
|
4593
4647
|
|
|
4648
|
+
// src/ui/MediaOverlay.tsx
|
|
4649
|
+
var React6 = __toESM(require("react"), 1);
|
|
4650
|
+
var import_lucide_react3 = require("lucide-react");
|
|
4651
|
+
|
|
4652
|
+
// src/ui/button.tsx
|
|
4653
|
+
var React5 = __toESM(require("react"), 1);
|
|
4654
|
+
var import_radix_ui4 = require("radix-ui");
|
|
4655
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
4656
|
+
var buttonVariants = cva(
|
|
4657
|
+
"inline-flex items-center justify-center gap-1 whitespace-nowrap rounded-md text-sm font-medium transition-colors outline-none disabled:pointer-events-none disabled:opacity-50 min-w-[80px] px-3 py-2",
|
|
4658
|
+
{
|
|
4659
|
+
variants: {
|
|
4660
|
+
variant: {
|
|
4661
|
+
default: "bg-primary text-primary-foreground hover:opacity-90",
|
|
4662
|
+
outline: "border border-border bg-background text-foreground shadow-sm hover:bg-muted/80",
|
|
4663
|
+
ghost: "min-w-0 px-3 py-2 text-foreground hover:bg-muted/50"
|
|
4664
|
+
},
|
|
4665
|
+
size: {
|
|
4666
|
+
default: "h-9",
|
|
4667
|
+
sm: "h-8 min-w-[64px] px-2 py-1.5 text-sm"
|
|
4668
|
+
}
|
|
4669
|
+
},
|
|
4670
|
+
defaultVariants: {
|
|
4671
|
+
variant: "default",
|
|
4672
|
+
size: "default"
|
|
4673
|
+
}
|
|
4674
|
+
}
|
|
4675
|
+
);
|
|
4676
|
+
var Button = React5.forwardRef(
|
|
4677
|
+
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
4678
|
+
const Comp = asChild ? import_radix_ui4.Slot.Root : "button";
|
|
4679
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4680
|
+
Comp,
|
|
4681
|
+
{
|
|
4682
|
+
ref,
|
|
4683
|
+
"data-slot": "button",
|
|
4684
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
4685
|
+
...props
|
|
4686
|
+
}
|
|
4687
|
+
);
|
|
4688
|
+
}
|
|
4689
|
+
);
|
|
4690
|
+
Button.displayName = "Button";
|
|
4691
|
+
|
|
4692
|
+
// src/ui/MediaOverlay.tsx
|
|
4693
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
4694
|
+
var MEDIA_UPLOAD_FADE_MS = 300;
|
|
4695
|
+
var VIDEO_SETTINGS_BAR_INSET = 8;
|
|
4696
|
+
var OVERLAY_BUTTON_STYLE = {
|
|
4697
|
+
pointerEvents: "auto",
|
|
4698
|
+
fontFamily: "Inter, sans-serif",
|
|
4699
|
+
fontSize: 12,
|
|
4700
|
+
color: "#000"
|
|
4701
|
+
};
|
|
4702
|
+
var SKELETON_CSS = `
|
|
4703
|
+
@keyframes ohw-media-shimmer {
|
|
4704
|
+
0% { transform: translateX(-100%); }
|
|
4705
|
+
100% { transform: translateX(100%); }
|
|
4706
|
+
}
|
|
4707
|
+
[data-ohw-media-skeleton] {
|
|
4708
|
+
overflow: hidden;
|
|
4709
|
+
background-color: #d1d5db; /* tailwind gray-300 */
|
|
4710
|
+
}
|
|
4711
|
+
[data-ohw-media-skeleton]::after {
|
|
4712
|
+
content: "";
|
|
4713
|
+
position: absolute;
|
|
4714
|
+
inset: 0;
|
|
4715
|
+
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.6), transparent);
|
|
4716
|
+
animation: ohw-media-shimmer 1.4s infinite;
|
|
4717
|
+
}
|
|
4718
|
+
`;
|
|
4719
|
+
function MediaOverlay({
|
|
4720
|
+
hover,
|
|
4721
|
+
isUploading,
|
|
4722
|
+
fadingOut = false,
|
|
4723
|
+
onFadeOutComplete,
|
|
4724
|
+
onReplace,
|
|
4725
|
+
onVideoSettingsChange
|
|
4726
|
+
}) {
|
|
4727
|
+
const { rect } = hover;
|
|
4728
|
+
const skeletonRef = React6.useRef(null);
|
|
4729
|
+
const isVideo = hover.elementType === "video";
|
|
4730
|
+
const autoplay = hover.videoAutoplay ?? true;
|
|
4731
|
+
const muted = hover.videoMuted ?? true;
|
|
4732
|
+
const box = {
|
|
4733
|
+
position: "fixed",
|
|
4734
|
+
top: rect.top,
|
|
4735
|
+
left: rect.left,
|
|
4736
|
+
width: rect.width,
|
|
4737
|
+
height: rect.height,
|
|
4738
|
+
zIndex: 2147483646
|
|
4739
|
+
};
|
|
4740
|
+
React6.useEffect(() => {
|
|
4741
|
+
if (!isUploading || !fadingOut || !skeletonRef.current) return;
|
|
4742
|
+
const anim = skeletonRef.current.animate([{ opacity: 1 }, { opacity: 0 }], {
|
|
4743
|
+
duration: MEDIA_UPLOAD_FADE_MS,
|
|
4744
|
+
easing: "ease-out",
|
|
4745
|
+
fill: "forwards"
|
|
4746
|
+
});
|
|
4747
|
+
anim.finished.then(() => onFadeOutComplete?.(hover.key)).catch(() => onFadeOutComplete?.(hover.key));
|
|
4748
|
+
return () => anim.cancel();
|
|
4749
|
+
}, [isUploading, fadingOut, onFadeOutComplete, hover.key]);
|
|
4750
|
+
if (isUploading) {
|
|
4751
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
4752
|
+
"div",
|
|
4753
|
+
{
|
|
4754
|
+
ref: skeletonRef,
|
|
4755
|
+
"data-ohw-bridge": "",
|
|
4756
|
+
"data-ohw-media-overlay": "",
|
|
4757
|
+
"data-ohw-media-skeleton": "",
|
|
4758
|
+
"aria-hidden": true,
|
|
4759
|
+
style: { ...box, pointerEvents: "none" },
|
|
4760
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("style", { children: SKELETON_CSS })
|
|
4761
|
+
}
|
|
4762
|
+
);
|
|
4763
|
+
}
|
|
4764
|
+
const settingsBar = isVideo && !hover.isDragOver ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
4765
|
+
"div",
|
|
4766
|
+
{
|
|
4767
|
+
"data-ohw-bridge": "",
|
|
4768
|
+
"data-ohw-media-overlay": "",
|
|
4769
|
+
className: "flex items-center justify-center gap-1.5",
|
|
4770
|
+
style: {
|
|
4771
|
+
position: "fixed",
|
|
4772
|
+
top: rect.top + VIDEO_SETTINGS_BAR_INSET,
|
|
4773
|
+
left: rect.left,
|
|
4774
|
+
width: rect.width,
|
|
4775
|
+
zIndex: 2147483647,
|
|
4776
|
+
pointerEvents: "auto"
|
|
4777
|
+
},
|
|
4778
|
+
onClick: (e) => e.stopPropagation(),
|
|
4779
|
+
children: [
|
|
4780
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
4781
|
+
Button,
|
|
4782
|
+
{
|
|
4783
|
+
"data-ohw-media-overlay": "",
|
|
4784
|
+
variant: "outline",
|
|
4785
|
+
size: "sm",
|
|
4786
|
+
className: "cursor-pointer hover:bg-background",
|
|
4787
|
+
style: { ...OVERLAY_BUTTON_STYLE, minWidth: 0, padding: "0 8px" },
|
|
4788
|
+
"aria-label": autoplay ? "Disable autoplay" : "Enable autoplay",
|
|
4789
|
+
title: autoplay ? "Autoplay on \u2014 click to disable" : "Autoplay off \u2014 click to enable",
|
|
4790
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
4791
|
+
onClick: (e) => {
|
|
4792
|
+
e.stopPropagation();
|
|
4793
|
+
onVideoSettingsChange?.(hover.key, { autoplay: !autoplay });
|
|
4794
|
+
},
|
|
4795
|
+
children: autoplay ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react3.Pause, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react3.Play, { size: 14 })
|
|
4796
|
+
}
|
|
4797
|
+
),
|
|
4798
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
4799
|
+
Button,
|
|
4800
|
+
{
|
|
4801
|
+
"data-ohw-media-overlay": "",
|
|
4802
|
+
variant: "outline",
|
|
4803
|
+
size: "sm",
|
|
4804
|
+
className: "cursor-pointer hover:bg-background",
|
|
4805
|
+
style: { ...OVERLAY_BUTTON_STYLE, minWidth: 0, padding: "0 8px" },
|
|
4806
|
+
"aria-label": muted ? "Unmute video" : "Mute video",
|
|
4807
|
+
title: muted ? "Muted \u2014 click to unmute" : "Sound on \u2014 click to mute",
|
|
4808
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
4809
|
+
onClick: (e) => {
|
|
4810
|
+
e.stopPropagation();
|
|
4811
|
+
onVideoSettingsChange?.(hover.key, { muted: !muted });
|
|
4812
|
+
},
|
|
4813
|
+
children: muted ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react3.VolumeX, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react3.Volume2, { size: 14 })
|
|
4814
|
+
}
|
|
4815
|
+
)
|
|
4816
|
+
]
|
|
4817
|
+
}
|
|
4818
|
+
) : null;
|
|
4819
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
4820
|
+
settingsBar,
|
|
4821
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
4822
|
+
"div",
|
|
4823
|
+
{
|
|
4824
|
+
"data-ohw-bridge": "",
|
|
4825
|
+
"data-ohw-media-overlay": "",
|
|
4826
|
+
className: "flex items-center justify-center cursor-pointer",
|
|
4827
|
+
style: {
|
|
4828
|
+
...box,
|
|
4829
|
+
// When text overlays this media, let clicks fall THROUGH to the text underneath. In the
|
|
4830
|
+
// parent this needed a whole `ow:click-at` round-trip to re-hit-test inside the iframe;
|
|
4831
|
+
// in-document, pointer-events does it natively. The button below opts back in, so
|
|
4832
|
+
// Replace still works.
|
|
4833
|
+
pointerEvents: hover.hasTextOverlap ? "none" : "auto",
|
|
4834
|
+
boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
|
|
4835
|
+
background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
|
|
4836
|
+
},
|
|
4837
|
+
onClick: () => onReplace(hover.key),
|
|
4838
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
4839
|
+
Button,
|
|
4840
|
+
{
|
|
4841
|
+
"data-ohw-media-overlay": "",
|
|
4842
|
+
variant: "outline",
|
|
4843
|
+
size: "sm",
|
|
4844
|
+
className: "gap-1.5 cursor-pointer hover:bg-background",
|
|
4845
|
+
style: OVERLAY_BUTTON_STYLE,
|
|
4846
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
4847
|
+
onClick: (e) => {
|
|
4848
|
+
e.stopPropagation();
|
|
4849
|
+
onReplace(hover.key);
|
|
4850
|
+
},
|
|
4851
|
+
children: [
|
|
4852
|
+
isVideo ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react3.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react3.ImageIcon, { size: 14 }),
|
|
4853
|
+
isVideo ? "Replace video" : "Replace image"
|
|
4854
|
+
]
|
|
4855
|
+
}
|
|
4856
|
+
)
|
|
4857
|
+
}
|
|
4858
|
+
)
|
|
4859
|
+
] });
|
|
4860
|
+
}
|
|
4861
|
+
|
|
4594
4862
|
// src/OhhwellsBridge.tsx
|
|
4595
|
-
var
|
|
4596
|
-
var
|
|
4863
|
+
var import_react_dom3 = require("react-dom");
|
|
4864
|
+
var import_navigation2 = require("next/navigation");
|
|
4597
4865
|
|
|
4598
4866
|
// src/lib/session-search.ts
|
|
4599
4867
|
var STORAGE_KEY = "ohw-preserved-search";
|
|
@@ -4869,62 +5137,30 @@ function scrollToHashSectionWhenReady(behavior = "smooth") {
|
|
|
4869
5137
|
tick();
|
|
4870
5138
|
}
|
|
4871
5139
|
|
|
4872
|
-
// src/ui/
|
|
4873
|
-
var
|
|
4874
|
-
var import_radix_ui4 = require("radix-ui");
|
|
4875
|
-
|
|
4876
|
-
// src/ui/icons.tsx
|
|
4877
|
-
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
4878
|
-
function IconX({ className, ...props }) {
|
|
4879
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
4880
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M18 6 6 18" }),
|
|
4881
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "m6 6 12 12" })
|
|
4882
|
-
] });
|
|
4883
|
-
}
|
|
4884
|
-
function IconChevronDown({ className, ...props }) {
|
|
4885
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "m6 9 6 6 6-6" }) });
|
|
4886
|
-
}
|
|
4887
|
-
function IconFile({ className, ...props }) {
|
|
4888
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
4889
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
|
|
4890
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" })
|
|
4891
|
-
] });
|
|
4892
|
-
}
|
|
4893
|
-
function IconInfo({ className, ...props }) {
|
|
4894
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
4895
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
|
|
4896
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M12 16v-4" }),
|
|
4897
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M12 8h.01" })
|
|
4898
|
-
] });
|
|
4899
|
-
}
|
|
4900
|
-
function IconArrowRight({ className, ...props }) {
|
|
4901
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
4902
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M5 12h14" }),
|
|
4903
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "m12 5 7 7-7 7" })
|
|
4904
|
-
] });
|
|
4905
|
-
}
|
|
4906
|
-
function IconSection({ className, ...props }) {
|
|
4907
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
|
|
4908
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("rect", { width: "18", height: "7", x: "3", y: "3", rx: "1" }),
|
|
4909
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("rect", { width: "9", height: "7", x: "3", y: "14", rx: "1" }),
|
|
4910
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("rect", { width: "5", height: "7", x: "16", y: "14", rx: "1" })
|
|
4911
|
-
] });
|
|
4912
|
-
}
|
|
5140
|
+
// src/ui/link-modal/LinkPopover.tsx
|
|
5141
|
+
var import_react7 = require("react");
|
|
4913
5142
|
|
|
4914
5143
|
// src/ui/dialog.tsx
|
|
4915
|
-
var
|
|
4916
|
-
|
|
4917
|
-
|
|
5144
|
+
var React7 = __toESM(require("react"), 1);
|
|
5145
|
+
var import_radix_ui5 = require("radix-ui");
|
|
5146
|
+
var import_lucide_react4 = require("lucide-react");
|
|
5147
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
5148
|
+
function Dialog2({
|
|
5149
|
+
...props
|
|
5150
|
+
}) {
|
|
5151
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_radix_ui5.Dialog.Root, { "data-slot": "dialog", ...props });
|
|
4918
5152
|
}
|
|
4919
|
-
function DialogPortal({
|
|
4920
|
-
|
|
5153
|
+
function DialogPortal({
|
|
5154
|
+
...props
|
|
5155
|
+
}) {
|
|
5156
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_radix_ui5.Dialog.Portal, { ...props });
|
|
4921
5157
|
}
|
|
4922
5158
|
function DialogOverlay({
|
|
4923
5159
|
className,
|
|
4924
5160
|
...props
|
|
4925
5161
|
}) {
|
|
4926
|
-
return /* @__PURE__ */ (0,
|
|
4927
|
-
|
|
5162
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
5163
|
+
import_radix_ui5.Dialog.Overlay,
|
|
4928
5164
|
{
|
|
4929
5165
|
"data-slot": "dialog-overlay",
|
|
4930
5166
|
"data-ohw-link-modal-root": "",
|
|
@@ -4933,120 +5169,118 @@ function DialogOverlay({
|
|
|
4933
5169
|
}
|
|
4934
5170
|
);
|
|
4935
5171
|
}
|
|
4936
|
-
var DialogContent =
|
|
4937
|
-
|
|
4938
|
-
|
|
4939
|
-
/* @__PURE__ */ (0,
|
|
4940
|
-
|
|
4941
|
-
|
|
4942
|
-
|
|
4943
|
-
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
children
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
});
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
5172
|
+
var DialogContent = React7.forwardRef(
|
|
5173
|
+
({ className, children, showCloseButton = true, container, ...props }, ref) => {
|
|
5174
|
+
const positionMode = container ? "absolute" : "fixed";
|
|
5175
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(DialogPortal, { container: container ?? void 0, children: [
|
|
5176
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(DialogOverlay, { className: cn(positionMode, "inset-0") }),
|
|
5177
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
5178
|
+
import_radix_ui5.Dialog.Content,
|
|
5179
|
+
{
|
|
5180
|
+
ref,
|
|
5181
|
+
"data-slot": "dialog-content",
|
|
5182
|
+
className: cn(
|
|
5183
|
+
positionMode,
|
|
5184
|
+
"left-1/2 top-1/2 z-[2147483647] flex w-full max-w-[483px] -translate-x-1/2 -translate-y-1/2 flex-col overflow-visible",
|
|
5185
|
+
"rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
|
|
5186
|
+
container ? "max-h-[calc(100%-32px)] max-w-[calc(100%-16px)]" : "max-h-[calc(100vh-32px)] max-w-[calc(100vw-16px)]",
|
|
5187
|
+
className
|
|
5188
|
+
),
|
|
5189
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
5190
|
+
...props,
|
|
5191
|
+
children: [
|
|
5192
|
+
children,
|
|
5193
|
+
showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
5194
|
+
import_radix_ui5.Dialog.Close,
|
|
5195
|
+
{
|
|
5196
|
+
type: "button",
|
|
5197
|
+
className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
|
|
5198
|
+
"aria-label": "Close",
|
|
5199
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react4.X, { size: 16, "aria-hidden": true })
|
|
5200
|
+
}
|
|
5201
|
+
) : null
|
|
5202
|
+
]
|
|
5203
|
+
}
|
|
5204
|
+
)
|
|
5205
|
+
] });
|
|
5206
|
+
}
|
|
5207
|
+
);
|
|
5208
|
+
DialogContent.displayName = import_radix_ui5.Dialog.Content.displayName;
|
|
5209
|
+
function DialogHeader({
|
|
5210
|
+
className,
|
|
5211
|
+
...props
|
|
5212
|
+
}) {
|
|
5213
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: cn("flex flex-col gap-1.5", className), ...props });
|
|
4973
5214
|
}
|
|
4974
|
-
function DialogFooter({
|
|
4975
|
-
|
|
5215
|
+
function DialogFooter({
|
|
5216
|
+
className,
|
|
5217
|
+
...props
|
|
5218
|
+
}) {
|
|
5219
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
5220
|
+
"div",
|
|
5221
|
+
{
|
|
5222
|
+
className: cn("flex items-center justify-end gap-2", className),
|
|
5223
|
+
...props
|
|
5224
|
+
}
|
|
5225
|
+
);
|
|
4976
5226
|
}
|
|
4977
|
-
var DialogTitle =
|
|
4978
|
-
|
|
5227
|
+
var DialogTitle = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
5228
|
+
import_radix_ui5.Dialog.Title,
|
|
4979
5229
|
{
|
|
4980
5230
|
ref,
|
|
4981
|
-
className: cn(
|
|
5231
|
+
className: cn(
|
|
5232
|
+
"text-lg font-semibold leading-none tracking-tight text-card-foreground",
|
|
5233
|
+
className
|
|
5234
|
+
),
|
|
4982
5235
|
...props
|
|
4983
5236
|
}
|
|
4984
5237
|
));
|
|
4985
|
-
DialogTitle.displayName =
|
|
4986
|
-
var DialogDescription =
|
|
4987
|
-
|
|
5238
|
+
DialogTitle.displayName = import_radix_ui5.Dialog.Title.displayName;
|
|
5239
|
+
var DialogDescription = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
5240
|
+
import_radix_ui5.Dialog.Description,
|
|
4988
5241
|
{
|
|
4989
5242
|
ref,
|
|
4990
5243
|
className: cn("text-sm text-muted-foreground", className),
|
|
4991
5244
|
...props
|
|
4992
5245
|
}
|
|
4993
5246
|
));
|
|
4994
|
-
DialogDescription.displayName =
|
|
4995
|
-
var DialogClose =
|
|
5247
|
+
DialogDescription.displayName = import_radix_ui5.Dialog.Description.displayName;
|
|
5248
|
+
var DialogClose = import_radix_ui5.Dialog.Close;
|
|
4996
5249
|
|
|
4997
|
-
// src/ui/
|
|
4998
|
-
var
|
|
4999
|
-
var import_radix_ui5 = require("radix-ui");
|
|
5000
|
-
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
5001
|
-
var buttonVariants = cva(
|
|
5002
|
-
"inline-flex items-center justify-center gap-1 whitespace-nowrap rounded-md text-sm font-medium transition-colors outline-none disabled:pointer-events-none disabled:opacity-50 min-w-[80px] px-3 py-2",
|
|
5003
|
-
{
|
|
5004
|
-
variants: {
|
|
5005
|
-
variant: {
|
|
5006
|
-
default: "bg-primary text-primary-foreground hover:opacity-90",
|
|
5007
|
-
outline: "border border-border bg-background text-foreground shadow-sm hover:bg-muted/80",
|
|
5008
|
-
ghost: "min-w-0 px-3 py-2 text-foreground hover:bg-muted/50"
|
|
5009
|
-
},
|
|
5010
|
-
size: {
|
|
5011
|
-
default: "h-9",
|
|
5012
|
-
sm: "h-8 min-w-[64px] px-2 py-1.5 text-sm"
|
|
5013
|
-
}
|
|
5014
|
-
},
|
|
5015
|
-
defaultVariants: {
|
|
5016
|
-
variant: "default",
|
|
5017
|
-
size: "default"
|
|
5018
|
-
}
|
|
5019
|
-
}
|
|
5020
|
-
);
|
|
5021
|
-
var Button = React6.forwardRef(
|
|
5022
|
-
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
5023
|
-
const Comp = asChild ? import_radix_ui5.Slot.Root : "button";
|
|
5024
|
-
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
5025
|
-
Comp,
|
|
5026
|
-
{
|
|
5027
|
-
ref,
|
|
5028
|
-
"data-slot": "button",
|
|
5029
|
-
className: cn(buttonVariants({ variant, size, className })),
|
|
5030
|
-
...props
|
|
5031
|
-
}
|
|
5032
|
-
);
|
|
5033
|
-
}
|
|
5034
|
-
);
|
|
5035
|
-
Button.displayName = "Button";
|
|
5250
|
+
// src/ui/link-modal/LinkEditorPanel.tsx
|
|
5251
|
+
var import_lucide_react8 = require("lucide-react");
|
|
5036
5252
|
|
|
5037
5253
|
// src/ui/link-modal/DestinationBreadcrumb.tsx
|
|
5254
|
+
var import_lucide_react5 = require("lucide-react");
|
|
5038
5255
|
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
5039
|
-
function DestinationBreadcrumb({
|
|
5256
|
+
function DestinationBreadcrumb({
|
|
5257
|
+
pageTitle,
|
|
5258
|
+
sectionLabel
|
|
5259
|
+
}) {
|
|
5040
5260
|
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex w-full flex-col gap-2", children: [
|
|
5041
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-sm font-medium text-foreground", children: "Destination" }),
|
|
5261
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-sm font-medium! text-foreground m-0", children: "Destination" }),
|
|
5042
5262
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-3", children: [
|
|
5043
5263
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
5044
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
5045
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-sm font-medium leading-none text-foreground", children: pageTitle })
|
|
5264
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react5.File, { size: 16, className: "shrink-0 text-foreground", "aria-hidden": true }),
|
|
5265
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-sm font-medium leading-none text-foreground!", children: pageTitle })
|
|
5046
5266
|
] }),
|
|
5047
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
5267
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
5268
|
+
import_lucide_react5.ArrowRight,
|
|
5269
|
+
{
|
|
5270
|
+
size: 16,
|
|
5271
|
+
className: "shrink-0 text-muted-foreground",
|
|
5272
|
+
"aria-hidden": true
|
|
5273
|
+
}
|
|
5274
|
+
),
|
|
5048
5275
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
|
|
5049
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
5276
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
5277
|
+
import_lucide_react5.GalleryVertical,
|
|
5278
|
+
{
|
|
5279
|
+
size: 16,
|
|
5280
|
+
className: "shrink-0 text-foreground",
|
|
5281
|
+
"aria-hidden": true
|
|
5282
|
+
}
|
|
5283
|
+
),
|
|
5050
5284
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
|
|
5051
5285
|
] })
|
|
5052
5286
|
] })
|
|
@@ -5054,8 +5288,13 @@ function DestinationBreadcrumb({ pageTitle, sectionLabel }) {
|
|
|
5054
5288
|
}
|
|
5055
5289
|
|
|
5056
5290
|
// src/ui/link-modal/SectionTreeItem.tsx
|
|
5291
|
+
var import_lucide_react6 = require("lucide-react");
|
|
5057
5292
|
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
5058
|
-
function SectionTreeItem({
|
|
5293
|
+
function SectionTreeItem({
|
|
5294
|
+
section,
|
|
5295
|
+
onSelect,
|
|
5296
|
+
selected
|
|
5297
|
+
}) {
|
|
5059
5298
|
const interactive = Boolean(onSelect);
|
|
5060
5299
|
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex h-9 w-full items-end pl-3", children: [
|
|
5061
5300
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
@@ -5083,30 +5322,28 @@ function SectionTreeItem({ section, onSelect, selected }) {
|
|
|
5083
5322
|
interactive && selected && "border-primary"
|
|
5084
5323
|
),
|
|
5085
5324
|
children: [
|
|
5086
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
5325
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
5326
|
+
import_lucide_react6.GalleryVertical,
|
|
5327
|
+
{
|
|
5328
|
+
size: 16,
|
|
5329
|
+
className: "shrink-0 text-foreground",
|
|
5330
|
+
"aria-hidden": true
|
|
5331
|
+
}
|
|
5332
|
+
),
|
|
5087
5333
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
|
|
5088
5334
|
]
|
|
5089
5335
|
}
|
|
5090
5336
|
)
|
|
5091
5337
|
] });
|
|
5092
5338
|
}
|
|
5093
|
-
function SectionPickerList({ sections, onSelect }) {
|
|
5094
|
-
if (sections.length === 0) {
|
|
5095
|
-
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." });
|
|
5096
|
-
}
|
|
5097
|
-
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col gap-1", children: [
|
|
5098
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-sm text-muted-foreground", children: "Pick a section this link should scroll to." }),
|
|
5099
|
-
sections.map((section) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SectionTreeItem, { section, onSelect }, section.id))
|
|
5100
|
-
] });
|
|
5101
|
-
}
|
|
5102
5339
|
|
|
5103
5340
|
// src/ui/link-modal/UrlOrPageInput.tsx
|
|
5104
5341
|
var import_react4 = require("react");
|
|
5105
5342
|
|
|
5106
5343
|
// src/ui/input.tsx
|
|
5107
|
-
var
|
|
5344
|
+
var React8 = __toESM(require("react"), 1);
|
|
5108
5345
|
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
5109
|
-
var Input =
|
|
5346
|
+
var Input = React8.forwardRef(
|
|
5110
5347
|
({ className, type, ...props }, ref) => {
|
|
5111
5348
|
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
5112
5349
|
"input",
|
|
@@ -5140,8 +5377,11 @@ function Label({ className, ...props }) {
|
|
|
5140
5377
|
}
|
|
5141
5378
|
|
|
5142
5379
|
// src/ui/link-modal/UrlOrPageInput.tsx
|
|
5380
|
+
var import_lucide_react7 = require("lucide-react");
|
|
5143
5381
|
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
5144
|
-
function FieldChevron({
|
|
5382
|
+
function FieldChevron({
|
|
5383
|
+
onClick
|
|
5384
|
+
}) {
|
|
5145
5385
|
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5146
5386
|
"button",
|
|
5147
5387
|
{
|
|
@@ -5150,7 +5390,7 @@ function FieldChevron({ onClick }) {
|
|
|
5150
5390
|
onClick,
|
|
5151
5391
|
"aria-label": "Open page list",
|
|
5152
5392
|
tabIndex: -1,
|
|
5153
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5393
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react7.ChevronDown, { size: 16 })
|
|
5154
5394
|
}
|
|
5155
5395
|
);
|
|
5156
5396
|
}
|
|
@@ -5168,7 +5408,29 @@ function UrlOrPageInput({
|
|
|
5168
5408
|
}) {
|
|
5169
5409
|
const inputId = (0, import_react4.useId)();
|
|
5170
5410
|
const inputRef = (0, import_react4.useRef)(null);
|
|
5411
|
+
const rootRef = (0, import_react4.useRef)(null);
|
|
5171
5412
|
const [isFocused, setIsFocused] = (0, import_react4.useState)(false);
|
|
5413
|
+
(0, import_react4.useEffect)(() => {
|
|
5414
|
+
if (!dropdownOpen) return;
|
|
5415
|
+
const isOutside = (e) => {
|
|
5416
|
+
const root = rootRef.current;
|
|
5417
|
+
if (!root) return true;
|
|
5418
|
+
const path = typeof e.composedPath === "function" ? e.composedPath() : [];
|
|
5419
|
+
if (path.includes(root)) return false;
|
|
5420
|
+
const target = e.target;
|
|
5421
|
+
return !(target instanceof Node && root.contains(target));
|
|
5422
|
+
};
|
|
5423
|
+
const closeIfOutside = (e) => {
|
|
5424
|
+
if (!isOutside(e)) return;
|
|
5425
|
+
onDropdownOpenChange(false);
|
|
5426
|
+
};
|
|
5427
|
+
document.addEventListener("pointerdown", closeIfOutside, true);
|
|
5428
|
+
document.addEventListener("mousedown", closeIfOutside, true);
|
|
5429
|
+
return () => {
|
|
5430
|
+
document.removeEventListener("pointerdown", closeIfOutside, true);
|
|
5431
|
+
document.removeEventListener("mousedown", closeIfOutside, true);
|
|
5432
|
+
};
|
|
5433
|
+
}, [dropdownOpen, onDropdownOpenChange]);
|
|
5172
5434
|
const openDropdown = () => {
|
|
5173
5435
|
if (readOnly || filteredPages.length === 0) return;
|
|
5174
5436
|
onDropdownOpenChange(true);
|
|
@@ -5191,9 +5453,16 @@ function UrlOrPageInput({
|
|
|
5191
5453
|
);
|
|
5192
5454
|
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex w-full flex-col gap-2 p-0", children: [
|
|
5193
5455
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
|
|
5194
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "relative w-full", children: [
|
|
5456
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { ref: rootRef, className: "relative w-full", children: [
|
|
5195
5457
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
|
|
5196
|
-
selectedPage ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5458
|
+
selectedPage ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5459
|
+
import_lucide_react7.File,
|
|
5460
|
+
{
|
|
5461
|
+
size: 16,
|
|
5462
|
+
className: "shrink-0 text-foreground",
|
|
5463
|
+
"aria-hidden": true
|
|
5464
|
+
}
|
|
5465
|
+
) }) : null,
|
|
5197
5466
|
readOnly ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "min-w-0 flex-1 truncate text-sm leading-5 text-foreground", children: selectedPage?.title ?? value }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5198
5467
|
Input,
|
|
5199
5468
|
{
|
|
@@ -5205,7 +5474,14 @@ function UrlOrPageInput({
|
|
|
5205
5474
|
setIsFocused(true);
|
|
5206
5475
|
if (!selectedPage) openDropdown();
|
|
5207
5476
|
},
|
|
5208
|
-
onBlur: () =>
|
|
5477
|
+
onBlur: () => {
|
|
5478
|
+
setIsFocused(false);
|
|
5479
|
+
requestAnimationFrame(() => {
|
|
5480
|
+
if (!rootRef.current?.contains(document.activeElement)) {
|
|
5481
|
+
onDropdownOpenChange(false);
|
|
5482
|
+
}
|
|
5483
|
+
});
|
|
5484
|
+
},
|
|
5209
5485
|
placeholder,
|
|
5210
5486
|
className: cn(
|
|
5211
5487
|
"min-w-0 flex-1 truncate border-0 bg-transparent p-0 text-sm font-normal leading-5 shadow-none outline-none ring-0 caret-foreground",
|
|
@@ -5221,7 +5497,7 @@ function UrlOrPageInput({
|
|
|
5221
5497
|
onMouseDown: clearSelection,
|
|
5222
5498
|
"aria-label": "Clear selected page",
|
|
5223
5499
|
tabIndex: -1,
|
|
5224
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5500
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react7.X, { size: 16, "aria-hidden": true })
|
|
5225
5501
|
}
|
|
5226
5502
|
) : null,
|
|
5227
5503
|
!readOnly ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(FieldChevron, { onClick: toggleDropdown }) : null
|
|
@@ -5230,7 +5506,7 @@ function UrlOrPageInput({
|
|
|
5230
5506
|
"div",
|
|
5231
5507
|
{
|
|
5232
5508
|
"data-ohw-link-page-dropdown": "",
|
|
5233
|
-
className: "absolute left-0 right-0
|
|
5509
|
+
className: "absolute left-0 right-0 top-[calc(100%+4px)] z-50 max-h-48 overflow-auto rounded-lg border border-border bg-popover py-1 shadow-lg",
|
|
5234
5510
|
onMouseDown: (e) => e.preventDefault(),
|
|
5235
5511
|
children: filteredPages.map((page) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
5236
5512
|
"button",
|
|
@@ -5239,7 +5515,7 @@ function UrlOrPageInput({
|
|
|
5239
5515
|
className: "flex h-9 w-full items-center gap-2 border-0 bg-transparent px-3 text-left text-sm leading-5 text-foreground outline-none hover:bg-muted",
|
|
5240
5516
|
onClick: () => onPageSelect(page),
|
|
5241
5517
|
children: [
|
|
5242
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5518
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react7.File, { size: 16, className: "shrink-0", "aria-hidden": true }),
|
|
5243
5519
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "truncate", children: page.title })
|
|
5244
5520
|
]
|
|
5245
5521
|
},
|
|
@@ -5252,38 +5528,375 @@ function UrlOrPageInput({
|
|
|
5252
5528
|
] });
|
|
5253
5529
|
}
|
|
5254
5530
|
|
|
5255
|
-
// src/ui/link-modal/
|
|
5256
|
-
var
|
|
5257
|
-
function
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
|
|
5265
|
-
|
|
5266
|
-
|
|
5267
|
-
|
|
5268
|
-
|
|
5269
|
-
|
|
5270
|
-
|
|
5271
|
-
|
|
5272
|
-
|
|
5273
|
-
|
|
5274
|
-
|
|
5275
|
-
|
|
5276
|
-
|
|
5277
|
-
|
|
5278
|
-
|
|
5279
|
-
|
|
5280
|
-
|
|
5531
|
+
// src/ui/link-modal/LinkEditorPanel.tsx
|
|
5532
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
5533
|
+
function LinkEditorPanel({ state, onClose }) {
|
|
5534
|
+
const isCancel = state.secondaryLabel === "Cancel" || state.secondaryLabel === "Back to sections";
|
|
5535
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
|
|
5536
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DialogClose, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
5537
|
+
"button",
|
|
5538
|
+
{
|
|
5539
|
+
type: "button",
|
|
5540
|
+
className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50 h-7",
|
|
5541
|
+
"aria-label": "Close",
|
|
5542
|
+
onClick: onClose,
|
|
5543
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react8.X, { size: 16, "aria-hidden": true })
|
|
5544
|
+
}
|
|
5545
|
+
) }),
|
|
5546
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DialogHeader, { className: "w-full gap-1.5 p-6 pr-12", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DialogTitle, { className: "m-0 w-full break-words", children: state.title }) }),
|
|
5547
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
|
|
5548
|
+
state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
5549
|
+
DestinationBreadcrumb,
|
|
5550
|
+
{
|
|
5551
|
+
pageTitle: state.selectedPage.title,
|
|
5552
|
+
sectionLabel: state.selectedSection.label
|
|
5553
|
+
}
|
|
5554
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
5555
|
+
UrlOrPageInput,
|
|
5556
|
+
{
|
|
5557
|
+
value: state.searchValue,
|
|
5558
|
+
selectedPage: state.selectedPage,
|
|
5559
|
+
dropdownOpen: state.dropdownOpen,
|
|
5560
|
+
onDropdownOpenChange: state.setDropdownOpen,
|
|
5561
|
+
filteredPages: state.filteredPages,
|
|
5562
|
+
onInputChange: state.handleInputChange,
|
|
5563
|
+
onPageSelect: state.handlePageSelect,
|
|
5564
|
+
urlError: state.urlError
|
|
5565
|
+
}
|
|
5566
|
+
),
|
|
5567
|
+
state.showChooseSection ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex flex-col justify-center gap-2", children: [
|
|
5568
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
5569
|
+
Button,
|
|
5570
|
+
{
|
|
5571
|
+
type: "button",
|
|
5572
|
+
variant: "outline",
|
|
5573
|
+
className: "w-fit cursor-pointer",
|
|
5574
|
+
size: "sm",
|
|
5575
|
+
onClick: state.handleChooseSection,
|
|
5576
|
+
children: "Choose a section"
|
|
5577
|
+
}
|
|
5578
|
+
),
|
|
5579
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
|
|
5580
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react8.Info, { size: 16, className: "shrink-0", "aria-hidden": true }),
|
|
5581
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: "Pick a section this link should scroll to." })
|
|
5582
|
+
] })
|
|
5583
|
+
] }) : null,
|
|
5584
|
+
state.showSectionRow && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
|
|
5585
|
+
] }),
|
|
5586
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(DialogFooter, { className: "w-full px-6 pb-6", children: [
|
|
5587
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
5588
|
+
Button,
|
|
5589
|
+
{
|
|
5590
|
+
type: "button",
|
|
5591
|
+
variant: isCancel ? "outline" : "ghost",
|
|
5592
|
+
className: "leading-6 shadow-none cursor-pointer",
|
|
5593
|
+
style: isCancel ? {
|
|
5594
|
+
backgroundColor: "var(--ohw-background)",
|
|
5595
|
+
borderColor: "var(--ohw-border)",
|
|
5596
|
+
color: "var(--ohw-foreground)"
|
|
5597
|
+
} : void 0,
|
|
5598
|
+
onClick: state.handleSecondary,
|
|
5599
|
+
children: state.secondaryLabel
|
|
5600
|
+
}
|
|
5601
|
+
),
|
|
5602
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
5603
|
+
Button,
|
|
5604
|
+
{
|
|
5605
|
+
type: "button",
|
|
5606
|
+
className: "border-0 leading-6 shadow-none hover:opacity-90 disabled:opacity-50 cursor-pointer",
|
|
5607
|
+
style: {
|
|
5608
|
+
backgroundColor: "var(--ohw-primary)",
|
|
5609
|
+
color: "var(--ohw-primary-foreground)"
|
|
5610
|
+
},
|
|
5611
|
+
disabled: !state.isValid,
|
|
5612
|
+
onClick: state.handleSubmit,
|
|
5613
|
+
children: state.submitLabel
|
|
5614
|
+
}
|
|
5615
|
+
)
|
|
5616
|
+
] })
|
|
5617
|
+
] });
|
|
5618
|
+
}
|
|
5619
|
+
|
|
5620
|
+
// src/ui/link-modal/SectionPickerOverlay.tsx
|
|
5621
|
+
var import_react5 = require("react");
|
|
5622
|
+
var import_react_dom = require("react-dom");
|
|
5623
|
+
var import_lucide_react9 = require("lucide-react");
|
|
5624
|
+
var import_navigation = require("next/navigation");
|
|
5625
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
5626
|
+
var DIM_OVERLAY = "rgba(0, 0, 0, 0.45)";
|
|
5627
|
+
function rectsEqual(a, b) {
|
|
5628
|
+
if (a.size !== b.size) return false;
|
|
5629
|
+
for (const [id, rect] of a) {
|
|
5630
|
+
const other = b.get(id);
|
|
5631
|
+
if (!other || rect.top !== other.top || rect.left !== other.left || rect.width !== other.width || rect.height !== other.height) {
|
|
5632
|
+
return false;
|
|
5633
|
+
}
|
|
5634
|
+
}
|
|
5635
|
+
return true;
|
|
5636
|
+
}
|
|
5637
|
+
function useSectionRects(sectionIdsKey, enabled) {
|
|
5638
|
+
const [rects, setRects] = (0, import_react5.useState)(/* @__PURE__ */ new Map());
|
|
5639
|
+
const sectionIds = (0, import_react5.useMemo)(
|
|
5640
|
+
() => sectionIdsKey ? sectionIdsKey.split("\0") : [],
|
|
5641
|
+
[sectionIdsKey]
|
|
5642
|
+
);
|
|
5643
|
+
(0, import_react5.useEffect)(() => {
|
|
5644
|
+
if (!enabled || sectionIds.length === 0) {
|
|
5645
|
+
setRects((prev) => prev.size === 0 ? prev : /* @__PURE__ */ new Map());
|
|
5646
|
+
return;
|
|
5647
|
+
}
|
|
5648
|
+
const update = () => {
|
|
5649
|
+
const next = /* @__PURE__ */ new Map();
|
|
5650
|
+
for (const id of sectionIds) {
|
|
5651
|
+
const el = document.querySelector(
|
|
5652
|
+
`[data-ohw-section="${CSS.escape(id)}"]`
|
|
5653
|
+
);
|
|
5654
|
+
if (el) next.set(id, el.getBoundingClientRect());
|
|
5655
|
+
}
|
|
5656
|
+
setRects((prev) => rectsEqual(prev, next) ? prev : next);
|
|
5657
|
+
};
|
|
5658
|
+
update();
|
|
5659
|
+
const opts = { capture: true, passive: true };
|
|
5660
|
+
window.addEventListener("scroll", update, opts);
|
|
5661
|
+
window.addEventListener("resize", update);
|
|
5662
|
+
const vv = window.visualViewport;
|
|
5663
|
+
vv?.addEventListener("resize", update);
|
|
5664
|
+
vv?.addEventListener("scroll", update);
|
|
5665
|
+
const ro = new ResizeObserver(update);
|
|
5666
|
+
for (const id of sectionIds) {
|
|
5667
|
+
const el = document.querySelector(
|
|
5668
|
+
`[data-ohw-section="${CSS.escape(id)}"]`
|
|
5669
|
+
);
|
|
5670
|
+
if (el) ro.observe(el);
|
|
5671
|
+
}
|
|
5672
|
+
return () => {
|
|
5673
|
+
window.removeEventListener("scroll", update, opts);
|
|
5674
|
+
window.removeEventListener("resize", update);
|
|
5675
|
+
vv?.removeEventListener("resize", update);
|
|
5676
|
+
vv?.removeEventListener("scroll", update);
|
|
5677
|
+
ro.disconnect();
|
|
5678
|
+
};
|
|
5679
|
+
}, [sectionIds, enabled]);
|
|
5680
|
+
return rects;
|
|
5681
|
+
}
|
|
5682
|
+
function SectionPickerOverlay({
|
|
5683
|
+
pagePath,
|
|
5684
|
+
sections,
|
|
5685
|
+
onBack,
|
|
5686
|
+
onSelect
|
|
5687
|
+
}) {
|
|
5688
|
+
const router = (0, import_navigation.useRouter)();
|
|
5689
|
+
const pathname = (0, import_navigation.usePathname)();
|
|
5690
|
+
const [selectedId, setSelectedId] = (0, import_react5.useState)(null);
|
|
5691
|
+
const [hoveredId, setHoveredId] = (0, import_react5.useState)(null);
|
|
5692
|
+
const [chromeClip, setChromeClip] = (0, import_react5.useState)(
|
|
5693
|
+
() => ({
|
|
5694
|
+
top: 0,
|
|
5695
|
+
bottom: typeof window !== "undefined" ? window.innerHeight : 0
|
|
5696
|
+
})
|
|
5697
|
+
);
|
|
5698
|
+
const normalizedTarget = normalizePath(pagePath);
|
|
5699
|
+
const isOnTargetPage = normalizePath(pathname) === normalizedTarget;
|
|
5700
|
+
(0, import_react5.useEffect)(() => {
|
|
5701
|
+
if (isOnTargetPage) return;
|
|
5702
|
+
const search = readPreservedSearch();
|
|
5703
|
+
router.push(`${normalizedTarget}${search}`);
|
|
5704
|
+
}, [isOnTargetPage, normalizedTarget, router]);
|
|
5705
|
+
(0, import_react5.useEffect)(() => {
|
|
5706
|
+
document.documentElement.setAttribute("data-ohw-section-picking", "");
|
|
5707
|
+
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => {
|
|
5708
|
+
el.removeAttribute("data-ohw-hovered");
|
|
5709
|
+
});
|
|
5710
|
+
return () => {
|
|
5711
|
+
document.documentElement.removeAttribute("data-ohw-section-picking");
|
|
5712
|
+
};
|
|
5713
|
+
}, []);
|
|
5714
|
+
(0, import_react5.useEffect)(() => {
|
|
5715
|
+
const applyClip = (iframeOffsetTop, visibleCanvasTop, canvasH) => {
|
|
5716
|
+
const top = Math.max(0, visibleCanvasTop - iframeOffsetTop);
|
|
5717
|
+
const bottom = Math.min(
|
|
5718
|
+
window.innerHeight,
|
|
5719
|
+
visibleCanvasTop + canvasH - iframeOffsetTop
|
|
5720
|
+
);
|
|
5721
|
+
setChromeClip(
|
|
5722
|
+
(prev) => prev.top === top && prev.bottom === bottom ? prev : { top, bottom: Math.max(top, bottom) }
|
|
5723
|
+
);
|
|
5724
|
+
};
|
|
5725
|
+
const onParentScroll = (e) => {
|
|
5726
|
+
if (e.data?.type !== "ow:parent-scroll") return;
|
|
5727
|
+
const { iframeOffsetTop, headerH, canvasH } = e.data;
|
|
5728
|
+
applyClip(iframeOffsetTop, headerH, canvasH);
|
|
5729
|
+
};
|
|
5730
|
+
const onResize = () => {
|
|
5731
|
+
setChromeClip((prev) => {
|
|
5732
|
+
const bottom = Math.max(prev.top, window.innerHeight);
|
|
5733
|
+
return prev.bottom === bottom ? prev : { ...prev, bottom };
|
|
5734
|
+
});
|
|
5735
|
+
};
|
|
5736
|
+
window.addEventListener("message", onParentScroll);
|
|
5737
|
+
window.addEventListener("resize", onResize);
|
|
5738
|
+
return () => {
|
|
5739
|
+
window.removeEventListener("message", onParentScroll);
|
|
5740
|
+
window.removeEventListener("resize", onResize);
|
|
5741
|
+
};
|
|
5742
|
+
}, []);
|
|
5743
|
+
const liveSections = (0, import_react5.useMemo)(() => {
|
|
5744
|
+
if (!isOnTargetPage) return sections;
|
|
5745
|
+
const live = collectSectionsFromDom();
|
|
5746
|
+
if (live.length === 0) return sections;
|
|
5747
|
+
const labels = new Map(sections.map((s) => [s.id, s.label]));
|
|
5748
|
+
return live.map((s) => ({ id: s.id, label: labels.get(s.id) ?? s.label }));
|
|
5749
|
+
}, [isOnTargetPage, sections, pathname]);
|
|
5750
|
+
const sectionIdsKey = (0, import_react5.useMemo)(
|
|
5751
|
+
() => liveSections.map((s) => s.id).join("\0"),
|
|
5752
|
+
[liveSections]
|
|
5753
|
+
);
|
|
5754
|
+
const rects = useSectionRects(sectionIdsKey, isOnTargetPage);
|
|
5755
|
+
const handleSelect = (0, import_react5.useCallback)(
|
|
5756
|
+
(section) => {
|
|
5757
|
+
if (selectedId) return;
|
|
5758
|
+
setSelectedId(section.id);
|
|
5759
|
+
onSelect(section);
|
|
5760
|
+
},
|
|
5761
|
+
[selectedId, onSelect]
|
|
5762
|
+
);
|
|
5763
|
+
(0, import_react5.useEffect)(() => {
|
|
5764
|
+
const onKeyDown = (e) => {
|
|
5765
|
+
if (e.key === "Escape") {
|
|
5766
|
+
e.preventDefault();
|
|
5767
|
+
e.stopPropagation();
|
|
5768
|
+
onBack();
|
|
5769
|
+
}
|
|
5770
|
+
};
|
|
5771
|
+
window.addEventListener("keydown", onKeyDown, true);
|
|
5772
|
+
return () => window.removeEventListener("keydown", onKeyDown, true);
|
|
5773
|
+
}, [onBack]);
|
|
5774
|
+
const portalRoot = typeof document !== "undefined" ? document.querySelector("[data-ohw-bridge-root]") ?? document.body : null;
|
|
5775
|
+
if (!portalRoot) return null;
|
|
5776
|
+
return (0, import_react_dom.createPortal)(
|
|
5777
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
5778
|
+
"div",
|
|
5779
|
+
{
|
|
5780
|
+
"data-ohw-section-picker": "",
|
|
5781
|
+
"data-ohw-bridge": "",
|
|
5782
|
+
className: `pointer-events-none fixed inset-0 z-[2147483647] transition-opacity duration-200 ${"opacity-100"}`,
|
|
5783
|
+
"aria-modal": true,
|
|
5784
|
+
role: "dialog",
|
|
5785
|
+
"aria-label": "Choose a section",
|
|
5786
|
+
children: [
|
|
5787
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5788
|
+
"div",
|
|
5789
|
+
{
|
|
5790
|
+
className: "pointer-events-auto fixed left-5 z-[2]",
|
|
5791
|
+
style: { top: chromeClip.top + 20 },
|
|
5792
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
5793
|
+
Button,
|
|
5794
|
+
{
|
|
5795
|
+
type: "button",
|
|
5796
|
+
variant: "outline",
|
|
5797
|
+
size: "sm",
|
|
5798
|
+
className: "h-8 min-w-0 gap-1 border-border bg-background px-2 py-1.5 shadow-sm hover:bg-muted cursor-pointer",
|
|
5799
|
+
onClick: onBack,
|
|
5800
|
+
children: [
|
|
5801
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react9.ArrowLeft, { className: "size-4 shrink-0", "aria-hidden": true }),
|
|
5802
|
+
"Back"
|
|
5803
|
+
]
|
|
5804
|
+
}
|
|
5805
|
+
)
|
|
5806
|
+
}
|
|
5807
|
+
),
|
|
5808
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5809
|
+
"div",
|
|
5810
|
+
{
|
|
5811
|
+
className: "pointer-events-none fixed left-1/2 z-[2] rounded-lg px-4 py-3 text-xs leading-4 tracking-[0.18px] text-white shadow-md",
|
|
5812
|
+
style: {
|
|
5813
|
+
top: chromeClip.bottom - 20,
|
|
5814
|
+
transform: "translate(-50%, -100%)",
|
|
5815
|
+
backgroundColor: "var(--ohw-popover-foreground, #0c0a09)"
|
|
5816
|
+
},
|
|
5817
|
+
"data-ohw-section-picker-hint": "",
|
|
5818
|
+
children: "Click on section to select"
|
|
5819
|
+
}
|
|
5820
|
+
),
|
|
5821
|
+
!isOnTargetPage ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5822
|
+
"div",
|
|
5823
|
+
{
|
|
5824
|
+
className: "pointer-events-none fixed left-1/2 z-[1] -translate-x-1/2 rounded-md bg-background/90 px-3 py-2 text-sm text-muted-foreground shadow-sm",
|
|
5825
|
+
style: { top: chromeClip.top + 64 },
|
|
5826
|
+
children: "Loading page preview\u2026"
|
|
5827
|
+
}
|
|
5828
|
+
) : null,
|
|
5829
|
+
isOnTargetPage && liveSections.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "pointer-events-auto fixed inset-0 z-[1] flex items-center justify-center bg-muted/40", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." }) }) : null,
|
|
5830
|
+
isOnTargetPage ? liveSections.map((section) => {
|
|
5831
|
+
const rect = rects.get(section.id);
|
|
5832
|
+
if (!rect || rect.width <= 0 || rect.height <= 0) return null;
|
|
5833
|
+
const isSelected = selectedId === section.id;
|
|
5834
|
+
const isLit = isSelected || hoveredId === section.id;
|
|
5835
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5836
|
+
"button",
|
|
5837
|
+
{
|
|
5838
|
+
type: "button",
|
|
5839
|
+
className: "pointer-events-auto fixed z-[1] cursor-pointer border-0 bg-transparent p-0 transition-[background-color] duration-150",
|
|
5840
|
+
style: {
|
|
5841
|
+
top: rect.top,
|
|
5842
|
+
left: rect.left,
|
|
5843
|
+
width: rect.width,
|
|
5844
|
+
height: rect.height,
|
|
5845
|
+
backgroundColor: isLit ? "transparent" : DIM_OVERLAY
|
|
5846
|
+
},
|
|
5847
|
+
"aria-label": `Select section ${section.label}`,
|
|
5848
|
+
onMouseEnter: () => setHoveredId(section.id),
|
|
5849
|
+
onMouseLeave: () => setHoveredId((prev) => prev === section.id ? null : prev),
|
|
5850
|
+
onClick: () => handleSelect(section),
|
|
5851
|
+
children: isSelected ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5852
|
+
"span",
|
|
5853
|
+
{
|
|
5854
|
+
className: "absolute right-3 top-3 flex size-8 items-center justify-center rounded-full text-white",
|
|
5855
|
+
style: { backgroundColor: "var(--ohw-primary, #0885fe)" },
|
|
5856
|
+
"aria-hidden": true,
|
|
5857
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react9.Check, { className: "size-5" })
|
|
5858
|
+
}
|
|
5859
|
+
) : null
|
|
5860
|
+
},
|
|
5861
|
+
section.id
|
|
5862
|
+
);
|
|
5863
|
+
}) : null
|
|
5864
|
+
]
|
|
5865
|
+
}
|
|
5866
|
+
),
|
|
5867
|
+
portalRoot
|
|
5868
|
+
);
|
|
5869
|
+
}
|
|
5870
|
+
|
|
5871
|
+
// src/ui/link-modal/useLinkModalState.ts
|
|
5872
|
+
var import_react6 = require("react");
|
|
5873
|
+
function useLinkModalState({
|
|
5874
|
+
open,
|
|
5875
|
+
mode,
|
|
5876
|
+
pages,
|
|
5877
|
+
sections: _sections,
|
|
5878
|
+
sectionsByPath,
|
|
5879
|
+
initialTarget,
|
|
5880
|
+
existingTargets: _existingTargets,
|
|
5881
|
+
onClose,
|
|
5882
|
+
onSubmit
|
|
5883
|
+
}) {
|
|
5884
|
+
const availablePages = (0, import_react6.useMemo)(() => pages, [pages]);
|
|
5885
|
+
const [searchValue, setSearchValue] = (0, import_react6.useState)("");
|
|
5886
|
+
const [selectedPage, setSelectedPage] = (0, import_react6.useState)(null);
|
|
5887
|
+
const [selectedSection, setSelectedSection] = (0, import_react6.useState)(null);
|
|
5888
|
+
const [step, setStep] = (0, import_react6.useState)("input");
|
|
5889
|
+
const [dropdownOpen, setDropdownOpen] = (0, import_react6.useState)(false);
|
|
5890
|
+
const [urlError, setUrlError] = (0, import_react6.useState)("");
|
|
5891
|
+
const reset = (0, import_react6.useCallback)(() => {
|
|
5892
|
+
setSearchValue("");
|
|
5893
|
+
setSelectedPage(null);
|
|
5281
5894
|
setSelectedSection(null);
|
|
5282
5895
|
setStep("input");
|
|
5283
5896
|
setDropdownOpen(false);
|
|
5284
5897
|
setUrlError("");
|
|
5285
5898
|
}, []);
|
|
5286
|
-
(0,
|
|
5899
|
+
(0, import_react6.useEffect)(() => {
|
|
5287
5900
|
if (!open) return;
|
|
5288
5901
|
if (mode === "edit" && initialTarget) {
|
|
5289
5902
|
const { pageRoute } = parseTarget(initialTarget);
|
|
@@ -5298,12 +5911,12 @@ function useLinkModalState({
|
|
|
5298
5911
|
}
|
|
5299
5912
|
setDropdownOpen(false);
|
|
5300
5913
|
setUrlError("");
|
|
5301
|
-
}, [open, mode, initialTarget,
|
|
5302
|
-
const filteredPages = (0,
|
|
5914
|
+
}, [open, mode, initialTarget, reset]);
|
|
5915
|
+
const filteredPages = (0, import_react6.useMemo)(() => {
|
|
5303
5916
|
if (!searchValue.trim()) return availablePages;
|
|
5304
5917
|
return availablePages.filter((p) => p.title.toLowerCase().startsWith(searchValue.toLowerCase()));
|
|
5305
5918
|
}, [availablePages, searchValue]);
|
|
5306
|
-
const activeSections = (0,
|
|
5919
|
+
const activeSections = (0, import_react6.useMemo)(() => {
|
|
5307
5920
|
if (!selectedPage) return [];
|
|
5308
5921
|
return getSectionsForPath(sectionsByPath, selectedPage.path);
|
|
5309
5922
|
}, [selectedPage, sectionsByPath]);
|
|
@@ -5345,11 +5958,14 @@ function useLinkModalState({
|
|
|
5345
5958
|
const handleBackToSections = () => {
|
|
5346
5959
|
setStep("sectionPicker");
|
|
5347
5960
|
};
|
|
5961
|
+
const handleSectionPickerBack = () => {
|
|
5962
|
+
setStep("input");
|
|
5963
|
+
};
|
|
5348
5964
|
const handleClose = () => {
|
|
5349
5965
|
reset();
|
|
5350
5966
|
onClose();
|
|
5351
5967
|
};
|
|
5352
|
-
const isValid = (0,
|
|
5968
|
+
const isValid = (0, import_react6.useMemo)(() => {
|
|
5353
5969
|
if (urlError) return false;
|
|
5354
5970
|
if (showBreadcrumb) return true;
|
|
5355
5971
|
if (selectedPage) return true;
|
|
@@ -5382,7 +5998,7 @@ function useLinkModalState({
|
|
|
5382
5998
|
onSubmit(normalizeUrl(searchValue));
|
|
5383
5999
|
handleClose();
|
|
5384
6000
|
};
|
|
5385
|
-
const submitLabel = mode === "edit" ? "Save" : "Create";
|
|
6001
|
+
const submitLabel = showBreadcrumb ? "Save" : mode === "edit" ? "Save" : "Create";
|
|
5386
6002
|
const title = mode === "edit" ? "Edit navigation item" : "Create navigation item";
|
|
5387
6003
|
const secondaryLabel = showBreadcrumb ? "Back to sections" : "Cancel";
|
|
5388
6004
|
const handleSecondary = showBreadcrumb ? handleBackToSections : handleClose;
|
|
@@ -5409,23 +6025,29 @@ function useLinkModalState({
|
|
|
5409
6025
|
handleChooseSection,
|
|
5410
6026
|
handleSectionSelect,
|
|
5411
6027
|
handleBackToSections,
|
|
6028
|
+
handleSectionPickerBack,
|
|
5412
6029
|
handleClose,
|
|
5413
6030
|
handleSecondary,
|
|
5414
6031
|
handleSubmit
|
|
5415
6032
|
};
|
|
5416
6033
|
}
|
|
5417
6034
|
|
|
5418
|
-
// src/ui/link-modal/
|
|
5419
|
-
var
|
|
5420
|
-
function
|
|
6035
|
+
// src/ui/link-modal/LinkPopover.tsx
|
|
6036
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
6037
|
+
function postToParent(data) {
|
|
6038
|
+
window.parent?.postMessage(data, "*");
|
|
6039
|
+
}
|
|
6040
|
+
function LinkPopover({
|
|
5421
6041
|
open = true,
|
|
6042
|
+
panelRef,
|
|
6043
|
+
portalContainer,
|
|
6044
|
+
onClose,
|
|
5422
6045
|
mode = "create",
|
|
5423
6046
|
pages,
|
|
5424
6047
|
sections = [],
|
|
5425
6048
|
sectionsByPath,
|
|
5426
6049
|
initialTarget,
|
|
5427
6050
|
existingTargets = [],
|
|
5428
|
-
onClose,
|
|
5429
6051
|
onSubmit
|
|
5430
6052
|
}) {
|
|
5431
6053
|
const state = useLinkModalState({
|
|
@@ -5439,115 +6061,100 @@ function LinkEditorPanel({
|
|
|
5439
6061
|
onClose,
|
|
5440
6062
|
onSubmit
|
|
5441
6063
|
});
|
|
5442
|
-
const
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
6064
|
+
const sectionPickerActive = state.showSectionPicker && Boolean(state.selectedPage);
|
|
6065
|
+
(0, import_react7.useEffect)(() => {
|
|
6066
|
+
if (!open) return;
|
|
6067
|
+
if (sectionPickerActive) {
|
|
6068
|
+
postToParent({ type: "ow:link-modal-lock", locked: false });
|
|
6069
|
+
postToParent({ type: "ow:section-picker", active: true });
|
|
6070
|
+
document.documentElement.style.overflow = "";
|
|
6071
|
+
document.body.style.overflow = "";
|
|
6072
|
+
return () => {
|
|
6073
|
+
postToParent({ type: "ow:section-picker", active: false });
|
|
6074
|
+
};
|
|
6075
|
+
}
|
|
6076
|
+
postToParent({ type: "ow:section-picker", active: false });
|
|
6077
|
+
postToParent({ type: "ow:link-modal-lock", locked: true });
|
|
6078
|
+
const html = document.documentElement;
|
|
6079
|
+
const body = document.body;
|
|
6080
|
+
const prevHtmlOverflow = html.style.overflow;
|
|
6081
|
+
const prevBodyOverflow = body.style.overflow;
|
|
6082
|
+
const prevHtmlOverscroll = html.style.overscrollBehavior;
|
|
6083
|
+
const prevBodyOverscroll = body.style.overscrollBehavior;
|
|
6084
|
+
html.style.overflow = "hidden";
|
|
6085
|
+
body.style.overflow = "hidden";
|
|
6086
|
+
html.style.overscrollBehavior = "none";
|
|
6087
|
+
body.style.overscrollBehavior = "none";
|
|
6088
|
+
const canScrollElement = (el, deltaY) => {
|
|
6089
|
+
const { overflowY } = getComputedStyle(el);
|
|
6090
|
+
if (overflowY !== "auto" && overflowY !== "scroll") return false;
|
|
6091
|
+
if (el.scrollHeight <= el.clientHeight + 1) return false;
|
|
6092
|
+
if (deltaY < 0) return el.scrollTop > 0;
|
|
6093
|
+
if (deltaY > 0) return el.scrollTop + el.clientHeight < el.scrollHeight - 1;
|
|
6094
|
+
return true;
|
|
6095
|
+
};
|
|
6096
|
+
const allowsInternalScroll = (e) => {
|
|
6097
|
+
const target = e.target;
|
|
6098
|
+
if (!(target instanceof Element)) return false;
|
|
6099
|
+
const scrollRoot = target.closest(
|
|
6100
|
+
"[data-ohw-link-page-dropdown], [data-ohw-allow-scroll]"
|
|
6101
|
+
);
|
|
6102
|
+
if (!scrollRoot) return false;
|
|
6103
|
+
const deltaY = e instanceof WheelEvent ? e.deltaY : 0;
|
|
6104
|
+
return canScrollElement(scrollRoot, deltaY);
|
|
6105
|
+
};
|
|
6106
|
+
const preventBackgroundScroll = (e) => {
|
|
6107
|
+
if (allowsInternalScroll(e)) return;
|
|
6108
|
+
e.preventDefault();
|
|
6109
|
+
};
|
|
6110
|
+
const scrollOpts = { passive: false, capture: true };
|
|
6111
|
+
document.addEventListener("wheel", preventBackgroundScroll, scrollOpts);
|
|
6112
|
+
document.addEventListener("touchmove", preventBackgroundScroll, scrollOpts);
|
|
6113
|
+
return () => {
|
|
6114
|
+
postToParent({ type: "ow:link-modal-lock", locked: false });
|
|
6115
|
+
html.style.overflow = prevHtmlOverflow;
|
|
6116
|
+
body.style.overflow = prevBodyOverflow;
|
|
6117
|
+
html.style.overscrollBehavior = prevHtmlOverscroll;
|
|
6118
|
+
body.style.overscrollBehavior = prevBodyOverscroll;
|
|
6119
|
+
document.removeEventListener("wheel", preventBackgroundScroll, scrollOpts);
|
|
6120
|
+
document.removeEventListener("touchmove", preventBackgroundScroll, scrollOpts);
|
|
6121
|
+
};
|
|
6122
|
+
}, [open, sectionPickerActive]);
|
|
6123
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
|
|
6124
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
6125
|
+
Dialog2,
|
|
5446
6126
|
{
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
6127
|
+
open: open && !sectionPickerActive,
|
|
6128
|
+
onOpenChange: (next) => {
|
|
6129
|
+
if (!next) onClose?.();
|
|
6130
|
+
},
|
|
6131
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
6132
|
+
DialogContent,
|
|
6133
|
+
{
|
|
6134
|
+
ref: panelRef,
|
|
6135
|
+
container: portalContainer,
|
|
6136
|
+
"data-ohw-link-popover-root": "",
|
|
6137
|
+
"data-ohw-link-modal-root": "",
|
|
6138
|
+
"data-ohw-bridge": "",
|
|
6139
|
+
showCloseButton: false,
|
|
6140
|
+
className: "gap-0 p-0 w-full md:w-md pointer-events-auto z-[2147483646] overflow-visible",
|
|
6141
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(LinkEditorPanel, { state, onClose })
|
|
6142
|
+
}
|
|
6143
|
+
)
|
|
5451
6144
|
}
|
|
5452
|
-
)
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
UrlOrPageInput,
|
|
5463
|
-
{
|
|
5464
|
-
value: state.searchValue,
|
|
5465
|
-
selectedPage: state.selectedPage,
|
|
5466
|
-
dropdownOpen: state.dropdownOpen,
|
|
5467
|
-
onDropdownOpenChange: state.setDropdownOpen,
|
|
5468
|
-
filteredPages: state.filteredPages,
|
|
5469
|
-
onInputChange: state.handleInputChange,
|
|
5470
|
-
onPageSelect: state.handlePageSelect,
|
|
5471
|
-
urlError: state.urlError
|
|
5472
|
-
}
|
|
5473
|
-
),
|
|
5474
|
-
state.showChooseSection ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex flex-col justify-center gap-2", children: [
|
|
5475
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { type: "button", variant: "outline", className: "w-fit cursor-pointer", size: "sm", onClick: state.handleChooseSection, children: "Choose a section" }),
|
|
5476
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
|
|
5477
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(IconInfo, { className: "shrink-0", "aria-hidden": true }),
|
|
5478
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: "Pick a section this link should scroll to." })
|
|
5479
|
-
] })
|
|
5480
|
-
] }) : null,
|
|
5481
|
-
state.showSectionPicker ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SectionPickerList, { sections: state.activeSections, onSelect: state.handleSectionSelect }) : null,
|
|
5482
|
-
state.showSectionRow && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
|
|
5483
|
-
] }),
|
|
5484
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(DialogFooter, { className: "w-full px-6 pb-6", children: [
|
|
5485
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
5486
|
-
Button,
|
|
5487
|
-
{
|
|
5488
|
-
type: "button",
|
|
5489
|
-
variant: isCancel ? "outline" : "ghost",
|
|
5490
|
-
className: "leading-6 shadow-none cursor-pointer",
|
|
5491
|
-
style: isCancel ? {
|
|
5492
|
-
backgroundColor: "var(--ohw-background)",
|
|
5493
|
-
borderColor: "var(--ohw-border)",
|
|
5494
|
-
color: "var(--ohw-foreground)"
|
|
5495
|
-
} : void 0,
|
|
5496
|
-
onClick: state.handleSecondary,
|
|
5497
|
-
children: state.secondaryLabel
|
|
5498
|
-
}
|
|
5499
|
-
),
|
|
5500
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
5501
|
-
Button,
|
|
5502
|
-
{
|
|
5503
|
-
type: "button",
|
|
5504
|
-
className: "border-0 leading-6 shadow-none hover:opacity-90 disabled:opacity-50 cursor-pointer",
|
|
5505
|
-
style: {
|
|
5506
|
-
backgroundColor: "var(--ohw-primary)",
|
|
5507
|
-
color: "var(--ohw-primary-foreground)"
|
|
5508
|
-
},
|
|
5509
|
-
disabled: !state.isValid,
|
|
5510
|
-
onClick: state.handleSubmit,
|
|
5511
|
-
children: state.submitLabel
|
|
5512
|
-
}
|
|
5513
|
-
)
|
|
5514
|
-
] })
|
|
6145
|
+
),
|
|
6146
|
+
sectionPickerActive && state.selectedPage ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
6147
|
+
SectionPickerOverlay,
|
|
6148
|
+
{
|
|
6149
|
+
pagePath: state.selectedPage.path,
|
|
6150
|
+
sections: state.activeSections,
|
|
6151
|
+
onBack: state.handleSectionPickerBack,
|
|
6152
|
+
onSelect: state.handleSectionSelect
|
|
6153
|
+
}
|
|
6154
|
+
) : null
|
|
5515
6155
|
] });
|
|
5516
6156
|
}
|
|
5517
6157
|
|
|
5518
|
-
// src/ui/link-modal/LinkPopover.tsx
|
|
5519
|
-
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
5520
|
-
function LinkPopover({
|
|
5521
|
-
open = true,
|
|
5522
|
-
panelRef,
|
|
5523
|
-
portalContainer,
|
|
5524
|
-
onClose,
|
|
5525
|
-
...editorProps
|
|
5526
|
-
}) {
|
|
5527
|
-
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5528
|
-
Dialog2,
|
|
5529
|
-
{
|
|
5530
|
-
open,
|
|
5531
|
-
onOpenChange: (next) => {
|
|
5532
|
-
if (!next) onClose?.();
|
|
5533
|
-
},
|
|
5534
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5535
|
-
DialogContent,
|
|
5536
|
-
{
|
|
5537
|
-
ref: panelRef,
|
|
5538
|
-
container: portalContainer,
|
|
5539
|
-
"data-ohw-link-popover-root": "",
|
|
5540
|
-
"data-ohw-link-modal-root": "",
|
|
5541
|
-
"data-ohw-bridge": "",
|
|
5542
|
-
showCloseButton: false,
|
|
5543
|
-
className: "gap-0 p-0 w-full md:w-md pointer-events-auto",
|
|
5544
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(LinkEditorPanel, { ...editorProps, open, onClose })
|
|
5545
|
-
}
|
|
5546
|
-
)
|
|
5547
|
-
}
|
|
5548
|
-
);
|
|
5549
|
-
}
|
|
5550
|
-
|
|
5551
6158
|
// src/ui/link-modal/devFixtures.ts
|
|
5552
6159
|
var DEV_SITE_PAGES = [
|
|
5553
6160
|
{ path: "/", title: "Home" },
|
|
@@ -5567,16 +6174,21 @@ var DEV_SECTIONS_BY_PATH = {
|
|
|
5567
6174
|
{ id: "founder-teaser", label: "Founder" },
|
|
5568
6175
|
{ id: "plan-form", label: "Plan Form" },
|
|
5569
6176
|
{ id: "testimonials", label: "Testimonials" },
|
|
5570
|
-
{ id: "wordmark", label: "Wordmark" }
|
|
6177
|
+
{ id: "wordmark", label: "Wordmark" },
|
|
6178
|
+
{ id: "footer", label: "Footer" }
|
|
5571
6179
|
],
|
|
5572
6180
|
"/about": [
|
|
5573
6181
|
{ id: "manifesto", label: "Manifesto" },
|
|
5574
6182
|
{ id: "story-letter", label: "Our Story" },
|
|
5575
6183
|
{ id: "lagree-explainer", label: "Lagree Explainer" },
|
|
5576
6184
|
{ id: "waitlist-cta", label: "Waitlist" },
|
|
5577
|
-
{ id: "personal-training", label: "Personal training" }
|
|
6185
|
+
{ id: "personal-training", label: "Personal training" },
|
|
6186
|
+
{ id: "footer", label: "Footer" }
|
|
6187
|
+
],
|
|
6188
|
+
"/classes": [
|
|
6189
|
+
{ id: "class-library", label: "Class Library" },
|
|
6190
|
+
{ id: "footer", label: "Footer" }
|
|
5578
6191
|
],
|
|
5579
|
-
"/classes": [{ id: "class-library", label: "Class Library" }],
|
|
5580
6192
|
"/pricing": [
|
|
5581
6193
|
{ id: "page-header", label: "Page Header" },
|
|
5582
6194
|
{ id: "free-class-cta", label: "Free Class" },
|
|
@@ -5584,19 +6196,25 @@ var DEV_SECTIONS_BY_PATH = {
|
|
|
5584
6196
|
{ id: "monthly-memberships", label: "Memberships" },
|
|
5585
6197
|
{ id: "specialty-programs", label: "Specialty Programs" },
|
|
5586
6198
|
{ id: "package-matcher", label: "Packages" },
|
|
5587
|
-
{ id: "wordmark", label: "Wordmark" }
|
|
6199
|
+
{ id: "wordmark", label: "Wordmark" },
|
|
6200
|
+
{ id: "footer", label: "Footer" }
|
|
5588
6201
|
],
|
|
5589
6202
|
"/studio": [
|
|
5590
6203
|
{ id: "studio-intro", label: "Studio Intro" },
|
|
5591
6204
|
{ id: "studio-features", label: "Studio Features" },
|
|
5592
6205
|
{ id: "studio-gallery", label: "Studio Gallery" },
|
|
5593
|
-
{ id: "studio-visit", label: "Visit Studio" }
|
|
6206
|
+
{ id: "studio-visit", label: "Visit Studio" },
|
|
6207
|
+
{ id: "footer", label: "Footer" }
|
|
6208
|
+
],
|
|
6209
|
+
"/instructors": [
|
|
6210
|
+
{ id: "instructor-grid", label: "Instructors" },
|
|
6211
|
+
{ id: "footer", label: "Footer" }
|
|
5594
6212
|
],
|
|
5595
|
-
"/instructors": [{ id: "instructor-grid", label: "Instructors" }],
|
|
5596
6213
|
"/contact": [
|
|
5597
6214
|
{ id: "hello-hero", label: "Hello" },
|
|
5598
6215
|
{ id: "contact-form", label: "Contact Form" },
|
|
5599
|
-
{ id: "faq", label: "FAQ" }
|
|
6216
|
+
{ id: "faq", label: "FAQ" },
|
|
6217
|
+
{ id: "footer", label: "Footer" }
|
|
5600
6218
|
]
|
|
5601
6219
|
};
|
|
5602
6220
|
function shouldUseDevFixtures() {
|
|
@@ -5606,8 +6224,277 @@ function shouldUseDevFixtures() {
|
|
|
5606
6224
|
return new URLSearchParams(q).get("ohw-fixtures") === "1";
|
|
5607
6225
|
}
|
|
5608
6226
|
|
|
6227
|
+
// src/lib/nav-items.ts
|
|
6228
|
+
var NAV_COUNT_KEY = "__ohw_nav_count";
|
|
6229
|
+
var NAV_ORDER_KEY = "__ohw_nav_order";
|
|
6230
|
+
function getLinkHref(el) {
|
|
6231
|
+
const key = el.getAttribute("data-ohw-href-key");
|
|
6232
|
+
if (key) {
|
|
6233
|
+
const stored = getStoredLinkHref(key);
|
|
6234
|
+
if (stored !== void 0) return stored;
|
|
6235
|
+
}
|
|
6236
|
+
return el.getAttribute("href") ?? "";
|
|
6237
|
+
}
|
|
6238
|
+
function isNavbarButton(el) {
|
|
6239
|
+
return el.hasAttribute("data-ohw-role") && el.getAttribute("data-ohw-role") === "navbar-button";
|
|
6240
|
+
}
|
|
6241
|
+
function isNavbarLinkItem(el) {
|
|
6242
|
+
if (!el.matches("[data-ohw-href-key]")) return false;
|
|
6243
|
+
if (isNavbarButton(el)) return false;
|
|
6244
|
+
if (!el.querySelector('[data-ohw-editable="text"]')) return false;
|
|
6245
|
+
return Boolean(el.closest("nav, [data-ohw-nav-container], [data-ohw-nav-drawer]"));
|
|
6246
|
+
}
|
|
6247
|
+
function getNavbarDesktopContainer() {
|
|
6248
|
+
return document.querySelector("[data-ohw-nav-container]");
|
|
6249
|
+
}
|
|
6250
|
+
function getNavbarDrawerContainer() {
|
|
6251
|
+
return document.querySelector("[data-ohw-nav-drawer]");
|
|
6252
|
+
}
|
|
6253
|
+
function listNavbarItems() {
|
|
6254
|
+
const desktop = getNavbarDesktopContainer();
|
|
6255
|
+
if (desktop) {
|
|
6256
|
+
return Array.from(desktop.querySelectorAll("[data-ohw-href-key]")).filter(isNavbarLinkItem);
|
|
6257
|
+
}
|
|
6258
|
+
const drawer = getNavbarDrawerContainer();
|
|
6259
|
+
if (drawer) {
|
|
6260
|
+
return Array.from(drawer.querySelectorAll("[data-ohw-href-key]")).filter(isNavbarLinkItem);
|
|
6261
|
+
}
|
|
6262
|
+
return Array.from(document.querySelectorAll("nav [data-ohw-href-key]")).filter(isNavbarLinkItem);
|
|
6263
|
+
}
|
|
6264
|
+
function parseNavIndexFromKey(key) {
|
|
6265
|
+
if (!key) return null;
|
|
6266
|
+
const match = key.match(/^nav-(\d+)-href$/);
|
|
6267
|
+
if (!match) return null;
|
|
6268
|
+
return parseInt(match[1], 10);
|
|
6269
|
+
}
|
|
6270
|
+
function getNavbarIndicesInDom() {
|
|
6271
|
+
const indices = /* @__PURE__ */ new Set();
|
|
6272
|
+
for (const item of listNavbarItems()) {
|
|
6273
|
+
const idx = parseNavIndexFromKey(item.getAttribute("data-ohw-href-key"));
|
|
6274
|
+
if (idx !== null) indices.add(idx);
|
|
6275
|
+
}
|
|
6276
|
+
return [...indices].sort((a, b) => a - b);
|
|
6277
|
+
}
|
|
6278
|
+
function getNextNavbarIndex() {
|
|
6279
|
+
const indices = getNavbarIndicesInDom();
|
|
6280
|
+
if (indices.length === 0) return 0;
|
|
6281
|
+
return Math.max(...indices) + 1;
|
|
6282
|
+
}
|
|
6283
|
+
function getNavbarExistingTargets() {
|
|
6284
|
+
return listNavbarItems().map((el) => getLinkHref(el)).filter(Boolean);
|
|
6285
|
+
}
|
|
6286
|
+
function getNavOrderFromDom() {
|
|
6287
|
+
return listNavbarItems().map((el) => el.getAttribute("data-ohw-href-key")).filter((key) => Boolean(key));
|
|
6288
|
+
}
|
|
6289
|
+
function parseNavOrder(content) {
|
|
6290
|
+
const raw = content[NAV_ORDER_KEY];
|
|
6291
|
+
if (!raw) return null;
|
|
6292
|
+
try {
|
|
6293
|
+
const parsed = JSON.parse(raw);
|
|
6294
|
+
if (!Array.isArray(parsed)) return null;
|
|
6295
|
+
return parsed.filter((key) => typeof key === "string" && key.length > 0);
|
|
6296
|
+
} catch {
|
|
6297
|
+
return null;
|
|
6298
|
+
}
|
|
6299
|
+
}
|
|
6300
|
+
function findCounterpartByHrefKey(hrefKey, root) {
|
|
6301
|
+
return root.querySelector(`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`);
|
|
6302
|
+
}
|
|
6303
|
+
function cloneNavLinkShell(template) {
|
|
6304
|
+
const anchor = document.createElement("a");
|
|
6305
|
+
if (template) {
|
|
6306
|
+
anchor.style.cssText = template.style.cssText;
|
|
6307
|
+
if (template.className) anchor.className = template.className;
|
|
6308
|
+
}
|
|
6309
|
+
anchor.style.cursor = "pointer";
|
|
6310
|
+
anchor.style.textDecoration = "none";
|
|
6311
|
+
return anchor;
|
|
6312
|
+
}
|
|
6313
|
+
function buildNavLink(index, href, label, template) {
|
|
6314
|
+
const anchor = cloneNavLinkShell(template);
|
|
6315
|
+
anchor.href = href;
|
|
6316
|
+
anchor.setAttribute("data-ohw-href-key", `nav-${index}-href`);
|
|
6317
|
+
const span = document.createElement("span");
|
|
6318
|
+
span.setAttribute("data-ohw-editable", "text");
|
|
6319
|
+
span.setAttribute("data-ohw-key", `nav-${index}-label`);
|
|
6320
|
+
span.textContent = label;
|
|
6321
|
+
anchor.appendChild(span);
|
|
6322
|
+
return anchor;
|
|
6323
|
+
}
|
|
6324
|
+
function insertNavLinkInContainer(container, anchor, afterHrefKey) {
|
|
6325
|
+
if (!afterHrefKey) {
|
|
6326
|
+
container.appendChild(anchor);
|
|
6327
|
+
return;
|
|
6328
|
+
}
|
|
6329
|
+
const afterEl = findCounterpartByHrefKey(afterHrefKey, container);
|
|
6330
|
+
if (afterEl?.parentElement === container) {
|
|
6331
|
+
afterEl.insertAdjacentElement("afterend", anchor);
|
|
6332
|
+
return;
|
|
6333
|
+
}
|
|
6334
|
+
container.appendChild(anchor);
|
|
6335
|
+
}
|
|
6336
|
+
function insertNavbarItemDom(index, href, label, afterAnchor) {
|
|
6337
|
+
const afterHrefKey = afterAnchor?.getAttribute("data-ohw-href-key") ?? null;
|
|
6338
|
+
const desktopItems = getNavbarDesktopContainer()?.querySelectorAll("[data-ohw-href-key]") ?? [];
|
|
6339
|
+
const drawerItems = getNavbarDrawerContainer()?.querySelectorAll("[data-ohw-href-key]") ?? [];
|
|
6340
|
+
const desktopTemplate = Array.from(desktopItems).find(isNavbarLinkItem) ?? null;
|
|
6341
|
+
const drawerTemplate = Array.from(drawerItems).find(isNavbarLinkItem) ?? null;
|
|
6342
|
+
let primary = null;
|
|
6343
|
+
const desktopContainer = getNavbarDesktopContainer();
|
|
6344
|
+
if (desktopContainer) {
|
|
6345
|
+
const desktopAnchor = buildNavLink(index, href, label, desktopTemplate);
|
|
6346
|
+
insertNavLinkInContainer(desktopContainer, desktopAnchor, afterHrefKey);
|
|
6347
|
+
primary = desktopAnchor;
|
|
6348
|
+
}
|
|
6349
|
+
const drawerContainer = getNavbarDrawerContainer();
|
|
6350
|
+
if (drawerContainer) {
|
|
6351
|
+
const drawerAnchor = buildNavLink(index, href, label, drawerTemplate);
|
|
6352
|
+
insertNavLinkInContainer(drawerContainer, drawerAnchor, afterHrefKey);
|
|
6353
|
+
if (!primary) primary = drawerAnchor;
|
|
6354
|
+
}
|
|
6355
|
+
if (!primary) {
|
|
6356
|
+
const fallback = buildNavLink(index, href, label, listNavbarItems()[0] ?? null);
|
|
6357
|
+
const nav = document.querySelector("nav");
|
|
6358
|
+
nav?.appendChild(fallback);
|
|
6359
|
+
primary = fallback;
|
|
6360
|
+
}
|
|
6361
|
+
return primary;
|
|
6362
|
+
}
|
|
6363
|
+
function applyNavOrderToContainer(container, order) {
|
|
6364
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6365
|
+
for (const hrefKey of order) {
|
|
6366
|
+
if (seen.has(hrefKey)) continue;
|
|
6367
|
+
seen.add(hrefKey);
|
|
6368
|
+
const el = findCounterpartByHrefKey(hrefKey, container);
|
|
6369
|
+
if (el) container.appendChild(el);
|
|
6370
|
+
}
|
|
6371
|
+
for (const el of container.querySelectorAll("[data-ohw-href-key]")) {
|
|
6372
|
+
if (!isNavbarLinkItem(el)) continue;
|
|
6373
|
+
const key = el.getAttribute("data-ohw-href-key");
|
|
6374
|
+
if (!key || seen.has(key)) continue;
|
|
6375
|
+
container.appendChild(el);
|
|
6376
|
+
}
|
|
6377
|
+
}
|
|
6378
|
+
function applyNavOrder(order) {
|
|
6379
|
+
const desktop = getNavbarDesktopContainer();
|
|
6380
|
+
if (desktop) applyNavOrderToContainer(desktop, order);
|
|
6381
|
+
const drawer = getNavbarDrawerContainer();
|
|
6382
|
+
if (drawer) applyNavOrderToContainer(drawer, order);
|
|
6383
|
+
}
|
|
6384
|
+
function collectNavbarIndicesFromContent(content) {
|
|
6385
|
+
const indices = /* @__PURE__ */ new Set();
|
|
6386
|
+
for (const key of Object.keys(content)) {
|
|
6387
|
+
const idx = parseNavIndexFromKey(key);
|
|
6388
|
+
if (idx !== null) indices.add(idx);
|
|
6389
|
+
}
|
|
6390
|
+
const countRaw = content[NAV_COUNT_KEY];
|
|
6391
|
+
if (countRaw) {
|
|
6392
|
+
const count = parseInt(countRaw, 10);
|
|
6393
|
+
if (Number.isFinite(count) && count > 0) {
|
|
6394
|
+
for (let i = 0; i < count; i++) indices.add(i);
|
|
6395
|
+
}
|
|
6396
|
+
}
|
|
6397
|
+
return [...indices].sort((a, b) => a - b);
|
|
6398
|
+
}
|
|
6399
|
+
function navbarIndexExistsInDom(index) {
|
|
6400
|
+
return document.querySelector(`[data-ohw-href-key="nav-${index}-href"]`) !== null;
|
|
6401
|
+
}
|
|
6402
|
+
function reconcileNavbarItemsFromContent(content) {
|
|
6403
|
+
const indices = collectNavbarIndicesFromContent(content);
|
|
6404
|
+
for (const index of indices) {
|
|
6405
|
+
if (navbarIndexExistsInDom(index)) continue;
|
|
6406
|
+
const href = content[`nav-${index}-href`];
|
|
6407
|
+
const label = content[`nav-${index}-label`];
|
|
6408
|
+
if (!href && !label) continue;
|
|
6409
|
+
insertNavbarItemDom(index, href ?? "/", label ?? "Untitled", null);
|
|
6410
|
+
}
|
|
6411
|
+
const order = parseNavOrder(content);
|
|
6412
|
+
if (order?.length) applyNavOrder(order);
|
|
6413
|
+
}
|
|
6414
|
+
function buildNavOrderAfterInsert(afterAnchor, newHrefKey) {
|
|
6415
|
+
const order = getNavOrderFromDom();
|
|
6416
|
+
if (!afterAnchor) {
|
|
6417
|
+
if (!order.includes(newHrefKey)) order.push(newHrefKey);
|
|
6418
|
+
return order;
|
|
6419
|
+
}
|
|
6420
|
+
const afterKey = afterAnchor.getAttribute("data-ohw-href-key");
|
|
6421
|
+
if (!afterKey) {
|
|
6422
|
+
if (!order.includes(newHrefKey)) order.push(newHrefKey);
|
|
6423
|
+
return order;
|
|
6424
|
+
}
|
|
6425
|
+
const withoutNew = order.filter((key) => key !== newHrefKey);
|
|
6426
|
+
const pos = withoutNew.indexOf(afterKey);
|
|
6427
|
+
if (pos >= 0) {
|
|
6428
|
+
withoutNew.splice(pos + 1, 0, newHrefKey);
|
|
6429
|
+
return withoutNew;
|
|
6430
|
+
}
|
|
6431
|
+
withoutNew.push(newHrefKey);
|
|
6432
|
+
return withoutNew;
|
|
6433
|
+
}
|
|
6434
|
+
function insertNavbarItem(href, label, afterAnchor = null) {
|
|
6435
|
+
const index = getNextNavbarIndex();
|
|
6436
|
+
const anchor = insertNavbarItemDom(index, href, label, afterAnchor);
|
|
6437
|
+
if (!anchor) throw new Error("Failed to insert navbar item");
|
|
6438
|
+
const hrefKey = `nav-${index}-href`;
|
|
6439
|
+
const order = buildNavOrderAfterInsert(afterAnchor, hrefKey);
|
|
6440
|
+
applyNavOrder(order);
|
|
6441
|
+
return {
|
|
6442
|
+
anchor,
|
|
6443
|
+
index,
|
|
6444
|
+
hrefKey,
|
|
6445
|
+
labelKey: `nav-${index}-label`,
|
|
6446
|
+
href,
|
|
6447
|
+
label,
|
|
6448
|
+
order
|
|
6449
|
+
};
|
|
6450
|
+
}
|
|
6451
|
+
|
|
6452
|
+
// src/ui/navbar-container-chrome.tsx
|
|
6453
|
+
var import_lucide_react10 = require("lucide-react");
|
|
6454
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
6455
|
+
function NavbarContainerChrome({
|
|
6456
|
+
rect,
|
|
6457
|
+
onAdd
|
|
6458
|
+
}) {
|
|
6459
|
+
const chromeGap = 6;
|
|
6460
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
6461
|
+
"div",
|
|
6462
|
+
{
|
|
6463
|
+
"data-ohw-navbar-container-chrome": "",
|
|
6464
|
+
"data-ohw-bridge": "",
|
|
6465
|
+
className: "pointer-events-none fixed z-[2147483647]",
|
|
6466
|
+
style: {
|
|
6467
|
+
top: rect.top - chromeGap,
|
|
6468
|
+
left: rect.left - chromeGap,
|
|
6469
|
+
width: rect.width + chromeGap * 2,
|
|
6470
|
+
height: rect.height + chromeGap * 2
|
|
6471
|
+
},
|
|
6472
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
6473
|
+
"button",
|
|
6474
|
+
{
|
|
6475
|
+
type: "button",
|
|
6476
|
+
"data-ohw-navbar-add-button": "",
|
|
6477
|
+
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",
|
|
6478
|
+
style: { top: "70%" },
|
|
6479
|
+
"aria-label": "Add item",
|
|
6480
|
+
onMouseDown: (e) => {
|
|
6481
|
+
e.preventDefault();
|
|
6482
|
+
e.stopPropagation();
|
|
6483
|
+
},
|
|
6484
|
+
onClick: (e) => {
|
|
6485
|
+
e.preventDefault();
|
|
6486
|
+
e.stopPropagation();
|
|
6487
|
+
onAdd();
|
|
6488
|
+
},
|
|
6489
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react10.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
|
|
6490
|
+
}
|
|
6491
|
+
)
|
|
6492
|
+
}
|
|
6493
|
+
);
|
|
6494
|
+
}
|
|
6495
|
+
|
|
5609
6496
|
// src/ui/badge.tsx
|
|
5610
|
-
var
|
|
6497
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
5611
6498
|
var badgeVariants = cva(
|
|
5612
6499
|
"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",
|
|
5613
6500
|
{
|
|
@@ -5625,12 +6512,12 @@ var badgeVariants = cva(
|
|
|
5625
6512
|
}
|
|
5626
6513
|
);
|
|
5627
6514
|
function Badge({ className, variant, ...props }) {
|
|
5628
|
-
return /* @__PURE__ */ (0,
|
|
6515
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: cn(badgeVariants({ variant }), className), ...props });
|
|
5629
6516
|
}
|
|
5630
6517
|
|
|
5631
6518
|
// src/OhhwellsBridge.tsx
|
|
5632
|
-
var
|
|
5633
|
-
var
|
|
6519
|
+
var import_lucide_react11 = require("lucide-react");
|
|
6520
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
5634
6521
|
var PRIMARY2 = "#0885FE";
|
|
5635
6522
|
var IMAGE_FADE_MS = 300;
|
|
5636
6523
|
function runOpacityFade(el, onDone) {
|
|
@@ -5807,9 +6694,9 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
5807
6694
|
tail.insertAdjacentElement("afterend", container);
|
|
5808
6695
|
}
|
|
5809
6696
|
const root = (0, import_client.createRoot)(container);
|
|
5810
|
-
(0,
|
|
6697
|
+
(0, import_react_dom2.flushSync)(() => {
|
|
5811
6698
|
root.render(
|
|
5812
|
-
/* @__PURE__ */ (0,
|
|
6699
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
5813
6700
|
SchedulingWidget,
|
|
5814
6701
|
{
|
|
5815
6702
|
notifyOnConnect,
|
|
@@ -5849,7 +6736,7 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
|
|
|
5849
6736
|
}
|
|
5850
6737
|
}
|
|
5851
6738
|
}
|
|
5852
|
-
function
|
|
6739
|
+
function getLinkHref2(el) {
|
|
5853
6740
|
const anchor = el instanceof HTMLAnchorElement ? el : el.querySelector("a");
|
|
5854
6741
|
return anchor?.getAttribute("href") ?? "";
|
|
5855
6742
|
}
|
|
@@ -5882,8 +6769,11 @@ function collectEditableNodes() {
|
|
|
5882
6769
|
const url = raw.replace(/^url\(['"]?/, "").replace(/['"]?\)$/, "");
|
|
5883
6770
|
return { key: el.dataset.ohwKey ?? "", type: "bg-image", text: url };
|
|
5884
6771
|
}
|
|
6772
|
+
if (el.dataset.ohwEditable === "video") {
|
|
6773
|
+
return { key: el.dataset.ohwKey ?? "", type: "video", text: getVideoEl(el)?.src ?? "" };
|
|
6774
|
+
}
|
|
5885
6775
|
if (el.dataset.ohwEditable === "link") {
|
|
5886
|
-
return { key: el.dataset.ohwKey ?? "", type: "link", text:
|
|
6776
|
+
return { key: el.dataset.ohwKey ?? "", type: "link", text: getLinkHref2(el) };
|
|
5887
6777
|
}
|
|
5888
6778
|
return {
|
|
5889
6779
|
key: el.dataset.ohwKey ?? "",
|
|
@@ -5894,9 +6784,79 @@ function collectEditableNodes() {
|
|
|
5894
6784
|
document.querySelectorAll("[data-ohw-href-key]").forEach((el) => {
|
|
5895
6785
|
const key = el.getAttribute("data-ohw-href-key") ?? "";
|
|
5896
6786
|
if (!key) return;
|
|
5897
|
-
nodes.push({ key, type: "link", text:
|
|
6787
|
+
nodes.push({ key, type: "link", text: getLinkHref2(el) });
|
|
6788
|
+
});
|
|
6789
|
+
document.querySelectorAll('[data-ohw-editable="video"]').forEach((el) => {
|
|
6790
|
+
const key = el.dataset.ohwKey ?? "";
|
|
6791
|
+
const video = getVideoEl(el);
|
|
6792
|
+
if (!key || !video) return;
|
|
6793
|
+
nodes.push({ key: `${key}${VIDEO_AUTOPLAY_SUFFIX}`, type: "video-setting", text: String(video.autoplay) });
|
|
6794
|
+
nodes.push({ key: `${key}${VIDEO_MUTED_SUFFIX}`, type: "video-setting", text: String(video.muted) });
|
|
6795
|
+
});
|
|
6796
|
+
return nodes;
|
|
6797
|
+
}
|
|
6798
|
+
function isMediaEditable(el) {
|
|
6799
|
+
const t = el.dataset.ohwEditable;
|
|
6800
|
+
return t === "image" || t === "bg-image" || t === "video";
|
|
6801
|
+
}
|
|
6802
|
+
var MEDIA_SELECTOR = '[data-ohw-editable="image"], [data-ohw-editable="bg-image"], [data-ohw-editable="video"]';
|
|
6803
|
+
var NON_MEDIA_SELECTOR = '[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"])';
|
|
6804
|
+
function getVideoEl(el) {
|
|
6805
|
+
return el instanceof HTMLVideoElement ? el : el.querySelector("video");
|
|
6806
|
+
}
|
|
6807
|
+
var VIDEO_AUTOPLAY_SUFFIX = "__ohw_autoplay";
|
|
6808
|
+
var VIDEO_MUTED_SUFFIX = "__ohw_muted";
|
|
6809
|
+
function isBackgroundVideo(video) {
|
|
6810
|
+
return video.autoplay && video.muted;
|
|
6811
|
+
}
|
|
6812
|
+
function syncVideoPlayback(video) {
|
|
6813
|
+
const background = isBackgroundVideo(video);
|
|
6814
|
+
video.controls = !background;
|
|
6815
|
+
if (video.autoplay) void video.play().catch(() => {
|
|
6816
|
+
});
|
|
6817
|
+
else video.pause();
|
|
6818
|
+
}
|
|
6819
|
+
function lockVideoBox(video) {
|
|
6820
|
+
const { width, height } = video.getBoundingClientRect();
|
|
6821
|
+
if (width > 0 && height > 0 && !video.style.aspectRatio) {
|
|
6822
|
+
video.style.aspectRatio = `${width} / ${height}`;
|
|
6823
|
+
}
|
|
6824
|
+
if (getComputedStyle(video).objectFit === "fill") {
|
|
6825
|
+
video.style.objectFit = "contain";
|
|
6826
|
+
}
|
|
6827
|
+
const fit = video.style.objectFit || getComputedStyle(video).objectFit;
|
|
6828
|
+
const bg = getComputedStyle(video).backgroundColor;
|
|
6829
|
+
const isTransparent = bg === "rgba(0, 0, 0, 0)" || bg === "transparent" || !bg;
|
|
6830
|
+
if (fit === "contain" && isTransparent) {
|
|
6831
|
+
video.style.backgroundColor = "var(--color-dark, #000)";
|
|
6832
|
+
}
|
|
6833
|
+
}
|
|
6834
|
+
function applyVideoSrc(video, url) {
|
|
6835
|
+
const { autoplay, muted } = video;
|
|
6836
|
+
lockVideoBox(video);
|
|
6837
|
+
video.src = url;
|
|
6838
|
+
video.loop = true;
|
|
6839
|
+
video.playsInline = true;
|
|
6840
|
+
video.autoplay = autoplay;
|
|
6841
|
+
video.muted = muted;
|
|
6842
|
+
video.load();
|
|
6843
|
+
syncVideoPlayback(video);
|
|
6844
|
+
}
|
|
6845
|
+
function applyVideoSettingNode(key, val) {
|
|
6846
|
+
const isAutoplay = key.endsWith(VIDEO_AUTOPLAY_SUFFIX);
|
|
6847
|
+
const isMuted = key.endsWith(VIDEO_MUTED_SUFFIX);
|
|
6848
|
+
if (!isAutoplay && !isMuted) return false;
|
|
6849
|
+
const suffixLen = (isAutoplay ? VIDEO_AUTOPLAY_SUFFIX : VIDEO_MUTED_SUFFIX).length;
|
|
6850
|
+
const baseKey = key.slice(0, key.length - suffixLen);
|
|
6851
|
+
const on = val === "true";
|
|
6852
|
+
document.querySelectorAll(`[data-ohw-key="${baseKey}"]`).forEach((el) => {
|
|
6853
|
+
const video = getVideoEl(el);
|
|
6854
|
+
if (!video) return;
|
|
6855
|
+
if (isAutoplay) video.autoplay = on;
|
|
6856
|
+
else video.muted = on;
|
|
6857
|
+
syncVideoPlayback(video);
|
|
5898
6858
|
});
|
|
5899
|
-
return
|
|
6859
|
+
return true;
|
|
5900
6860
|
}
|
|
5901
6861
|
function applyLinkByKey(key, val) {
|
|
5902
6862
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -5910,7 +6870,7 @@ function applyLinkByKey(key, val) {
|
|
|
5910
6870
|
}
|
|
5911
6871
|
function isInsideLinkEditor(target) {
|
|
5912
6872
|
return Boolean(
|
|
5913
|
-
target.closest("[data-ohw-link-popover-root]") || target.closest("[data-ohw-link-modal-root]") || target.closest("[data-ohw-link-page-dropdown]") || target.closest('[data-slot="popover-content"]') || target.closest('[data-slot="dialog-content"]') || target.closest('[data-slot="dialog-overlay"]')
|
|
6873
|
+
target.closest("[data-ohw-link-popover-root]") || target.closest("[data-ohw-link-modal-root]") || target.closest("[data-ohw-link-page-dropdown]") || target.closest("[data-ohw-section-picker]") || target.closest("[data-ohw-navbar-container-chrome]") || target.closest("[data-ohw-navbar-add-button]") || target.closest('[data-slot="popover-content"]') || target.closest('[data-slot="dialog-content"]') || target.closest('[data-slot="dialog-overlay"]')
|
|
5914
6874
|
);
|
|
5915
6875
|
}
|
|
5916
6876
|
function getHrefKeyFromElement(el) {
|
|
@@ -5921,7 +6881,7 @@ function getHrefKeyFromElement(el) {
|
|
|
5921
6881
|
if (!key) return null;
|
|
5922
6882
|
return { anchor, key };
|
|
5923
6883
|
}
|
|
5924
|
-
function
|
|
6884
|
+
function isNavbarButton2(el) {
|
|
5925
6885
|
return Boolean(el.closest('[data-ohw-role="navbar-button"]'));
|
|
5926
6886
|
}
|
|
5927
6887
|
function getNavigationItemAnchor(el) {
|
|
@@ -5933,19 +6893,8 @@ function getNavigationItemAnchor(el) {
|
|
|
5933
6893
|
function isNavigationItem(el) {
|
|
5934
6894
|
return getNavigationItemAnchor(el) !== null;
|
|
5935
6895
|
}
|
|
5936
|
-
function getNavigationItemAddHintTarget(anchor) {
|
|
5937
|
-
const items = listNavigationItems();
|
|
5938
|
-
const idx = items.indexOf(anchor);
|
|
5939
|
-
if (idx >= 0 && idx < items.length - 1) return items[idx + 1];
|
|
5940
|
-
return anchor;
|
|
5941
|
-
}
|
|
5942
|
-
function listNavigationItems() {
|
|
5943
|
-
return Array.from(
|
|
5944
|
-
document.querySelectorAll("nav [data-ohw-href-key], footer [data-ohw-href-key]")
|
|
5945
|
-
).filter((el) => isNavigationItem(el));
|
|
5946
|
-
}
|
|
5947
6896
|
function getNavigationItemReorderState(anchor) {
|
|
5948
|
-
if (
|
|
6897
|
+
if (isNavbarButton2(anchor)) return { key: null, disabled: false };
|
|
5949
6898
|
return getReorderHandleStateFromAnchor(anchor);
|
|
5950
6899
|
}
|
|
5951
6900
|
function getReorderHandleState(el) {
|
|
@@ -5967,6 +6916,120 @@ function clearHrefKeyHover(anchor) {
|
|
|
5967
6916
|
function isInsideNavigationItem(el) {
|
|
5968
6917
|
return getNavigationItemAnchor(el) !== null;
|
|
5969
6918
|
}
|
|
6919
|
+
function getNavigationRoot(el) {
|
|
6920
|
+
const explicit = el.closest("[data-ohw-nav-root]");
|
|
6921
|
+
if (explicit) return explicit;
|
|
6922
|
+
return el.closest("nav, footer, aside");
|
|
6923
|
+
}
|
|
6924
|
+
function findFooterItemGroup(item) {
|
|
6925
|
+
const footer = item.closest("footer");
|
|
6926
|
+
if (!footer) return null;
|
|
6927
|
+
let node = item.parentElement;
|
|
6928
|
+
while (node && node !== footer) {
|
|
6929
|
+
const hasDirectNavItems = Array.from(
|
|
6930
|
+
node.querySelectorAll(":scope > [data-ohw-href-key]")
|
|
6931
|
+
).some(isNavigationItem);
|
|
6932
|
+
if (hasDirectNavItems) return node;
|
|
6933
|
+
node = node.parentElement;
|
|
6934
|
+
}
|
|
6935
|
+
return null;
|
|
6936
|
+
}
|
|
6937
|
+
function isNavigationRoot(el) {
|
|
6938
|
+
return el.hasAttribute("data-ohw-nav-root") || el.matches("nav, footer, aside");
|
|
6939
|
+
}
|
|
6940
|
+
function isInferredFooterGroup(el) {
|
|
6941
|
+
const footer = el.closest("footer");
|
|
6942
|
+
if (!footer || el === footer) return false;
|
|
6943
|
+
return Array.from(el.querySelectorAll(":scope > [data-ohw-href-key]")).some(isNavigationItem);
|
|
6944
|
+
}
|
|
6945
|
+
function isNavigationContainer(el) {
|
|
6946
|
+
return el.hasAttribute("data-ohw-nav-container") || isNavigationRoot(el) || isInferredFooterGroup(el);
|
|
6947
|
+
}
|
|
6948
|
+
function isPointOverNavigation(x, y) {
|
|
6949
|
+
const navRoot = document.querySelector("[data-ohw-nav-root]") ?? document.querySelector("nav");
|
|
6950
|
+
if (!navRoot) return false;
|
|
6951
|
+
const r2 = navRoot.getBoundingClientRect();
|
|
6952
|
+
return x >= r2.left && x <= r2.right && y >= r2.top && y <= r2.bottom;
|
|
6953
|
+
}
|
|
6954
|
+
function isPointOverNavItem(container, x, y) {
|
|
6955
|
+
return Array.from(container.querySelectorAll("[data-ohw-href-key]")).some((el) => {
|
|
6956
|
+
if (!isNavigationItem(el) || isNavbarButton2(el)) return false;
|
|
6957
|
+
const itemRect = el.getBoundingClientRect();
|
|
6958
|
+
return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
|
|
6959
|
+
});
|
|
6960
|
+
}
|
|
6961
|
+
function resolveNavContainerSelectionTarget(target, clientX, clientY) {
|
|
6962
|
+
if (getNavigationItemAnchor(target)) return null;
|
|
6963
|
+
if (target.closest('[data-ohw-role="navbar-button"]')) return null;
|
|
6964
|
+
const plainLink = target.closest("a");
|
|
6965
|
+
if (plainLink && !plainLink.hasAttribute("data-ohw-href-key") && !plainLink.closest("[data-ohw-nav-container]")) {
|
|
6966
|
+
return null;
|
|
6967
|
+
}
|
|
6968
|
+
const fromClosest = target.closest("[data-ohw-nav-container]");
|
|
6969
|
+
if (fromClosest && !isPointOverNavItem(fromClosest, clientX, clientY)) {
|
|
6970
|
+
return fromClosest;
|
|
6971
|
+
}
|
|
6972
|
+
const navRoot = target.closest("[data-ohw-nav-root]");
|
|
6973
|
+
if (!navRoot) return null;
|
|
6974
|
+
const container = navRoot.querySelector("[data-ohw-nav-container]");
|
|
6975
|
+
if (!container || isPointOverNavItem(container, clientX, clientY)) return null;
|
|
6976
|
+
if (target === navRoot || target.hasAttribute("data-ohw-nav-root")) {
|
|
6977
|
+
return container;
|
|
6978
|
+
}
|
|
6979
|
+
return null;
|
|
6980
|
+
}
|
|
6981
|
+
function getNavigationSelectionParent(el) {
|
|
6982
|
+
if (isNavigationItem(el)) {
|
|
6983
|
+
const explicit = el.closest("[data-ohw-nav-container]");
|
|
6984
|
+
if (explicit) return explicit;
|
|
6985
|
+
const footerGroup = findFooterItemGroup(el);
|
|
6986
|
+
if (footerGroup) return footerGroup;
|
|
6987
|
+
return getNavigationRoot(el);
|
|
6988
|
+
}
|
|
6989
|
+
if (el.hasAttribute("data-ohw-nav-container") || isInferredFooterGroup(el)) {
|
|
6990
|
+
return getNavigationRoot(el);
|
|
6991
|
+
}
|
|
6992
|
+
return null;
|
|
6993
|
+
}
|
|
6994
|
+
function placeCaretAtPoint(el, x, y) {
|
|
6995
|
+
const selection = window.getSelection();
|
|
6996
|
+
if (!selection) return;
|
|
6997
|
+
if (typeof document.caretRangeFromPoint === "function") {
|
|
6998
|
+
const range = document.caretRangeFromPoint(x, y);
|
|
6999
|
+
if (range && el.contains(range.startContainer)) {
|
|
7000
|
+
selection.removeAllRanges();
|
|
7001
|
+
selection.addRange(range);
|
|
7002
|
+
return;
|
|
7003
|
+
}
|
|
7004
|
+
}
|
|
7005
|
+
const caretPositionFromPoint = document.caretPositionFromPoint;
|
|
7006
|
+
if (typeof caretPositionFromPoint === "function") {
|
|
7007
|
+
const position = caretPositionFromPoint(x, y);
|
|
7008
|
+
if (position && el.contains(position.offsetNode)) {
|
|
7009
|
+
const range = document.createRange();
|
|
7010
|
+
range.setStart(position.offsetNode, position.offset);
|
|
7011
|
+
range.collapse(true);
|
|
7012
|
+
selection.removeAllRanges();
|
|
7013
|
+
selection.addRange(range);
|
|
7014
|
+
}
|
|
7015
|
+
}
|
|
7016
|
+
}
|
|
7017
|
+
function selectAllTextInEditable(el) {
|
|
7018
|
+
const selection = window.getSelection();
|
|
7019
|
+
if (!selection) return;
|
|
7020
|
+
const range = document.createRange();
|
|
7021
|
+
range.selectNodeContents(el);
|
|
7022
|
+
selection.removeAllRanges();
|
|
7023
|
+
selection.addRange(range);
|
|
7024
|
+
}
|
|
7025
|
+
function getNavigationLabelEditable(target) {
|
|
7026
|
+
const editable = target.closest('[data-ohw-editable="text"]');
|
|
7027
|
+
if (!editable) return null;
|
|
7028
|
+
const hrefCtx = getHrefKeyFromElement(editable);
|
|
7029
|
+
const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
|
|
7030
|
+
if (!navAnchor) return null;
|
|
7031
|
+
return { editable, navAnchor };
|
|
7032
|
+
}
|
|
5970
7033
|
function collectSections() {
|
|
5971
7034
|
return collectSectionsFromDom();
|
|
5972
7035
|
}
|
|
@@ -6090,6 +7153,8 @@ var ICONS = {
|
|
|
6090
7153
|
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"/>',
|
|
6091
7154
|
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"/>'
|
|
6092
7155
|
};
|
|
7156
|
+
var TOOLBAR_PILL_PADDING = 2;
|
|
7157
|
+
var TOOLBAR_TOGGLE_GAP = 4;
|
|
6093
7158
|
var TOOLBAR_GROUPS = [
|
|
6094
7159
|
[
|
|
6095
7160
|
{ cmd: "bold", title: "Bold" },
|
|
@@ -6114,7 +7179,7 @@ function EditGlowChrome({
|
|
|
6114
7179
|
dragDisabled = false
|
|
6115
7180
|
}) {
|
|
6116
7181
|
const GAP = 6;
|
|
6117
|
-
return /* @__PURE__ */ (0,
|
|
7182
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
6118
7183
|
"div",
|
|
6119
7184
|
{
|
|
6120
7185
|
ref: elRef,
|
|
@@ -6129,7 +7194,7 @@ function EditGlowChrome({
|
|
|
6129
7194
|
zIndex: 2147483646
|
|
6130
7195
|
},
|
|
6131
7196
|
children: [
|
|
6132
|
-
/* @__PURE__ */ (0,
|
|
7197
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
6133
7198
|
"div",
|
|
6134
7199
|
{
|
|
6135
7200
|
style: {
|
|
@@ -6142,7 +7207,7 @@ function EditGlowChrome({
|
|
|
6142
7207
|
}
|
|
6143
7208
|
}
|
|
6144
7209
|
),
|
|
6145
|
-
reorderHrefKey && /* @__PURE__ */ (0,
|
|
7210
|
+
reorderHrefKey && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
6146
7211
|
"div",
|
|
6147
7212
|
{
|
|
6148
7213
|
"data-ohw-drag-handle-container": "",
|
|
@@ -6154,7 +7219,7 @@ function EditGlowChrome({
|
|
|
6154
7219
|
transform: "translate(calc(-100% - 7px), -50%)",
|
|
6155
7220
|
pointerEvents: dragDisabled ? "none" : "auto"
|
|
6156
7221
|
},
|
|
6157
|
-
children: /* @__PURE__ */ (0,
|
|
7222
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
6158
7223
|
DragHandle,
|
|
6159
7224
|
{
|
|
6160
7225
|
"aria-label": `Reorder ${reorderHrefKey}`,
|
|
@@ -6258,7 +7323,7 @@ function FloatingToolbar({
|
|
|
6258
7323
|
onEditLink
|
|
6259
7324
|
}) {
|
|
6260
7325
|
const { top, left, transform } = calcToolbarPos(rect, parentScroll, 330);
|
|
6261
|
-
return /* @__PURE__ */ (0,
|
|
7326
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
6262
7327
|
"div",
|
|
6263
7328
|
{
|
|
6264
7329
|
ref: elRef,
|
|
@@ -6268,14 +7333,23 @@ function FloatingToolbar({
|
|
|
6268
7333
|
left,
|
|
6269
7334
|
transform,
|
|
6270
7335
|
zIndex: 2147483647,
|
|
7336
|
+
background: "#fff",
|
|
7337
|
+
border: "1px solid #E7E5E4",
|
|
7338
|
+
borderRadius: 6,
|
|
7339
|
+
boxShadow: "0px 2px 4px -2px rgba(0,0,0,.1),0px 4px 6px -1px rgba(0,0,0,.1)",
|
|
7340
|
+
display: "flex",
|
|
7341
|
+
alignItems: "center",
|
|
7342
|
+
padding: TOOLBAR_PILL_PADDING,
|
|
7343
|
+
gap: TOOLBAR_TOGGLE_GAP,
|
|
7344
|
+
fontFamily: "sans-serif",
|
|
6271
7345
|
pointerEvents: "auto"
|
|
6272
7346
|
},
|
|
6273
|
-
children: /* @__PURE__ */ (0,
|
|
6274
|
-
TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0,
|
|
6275
|
-
gi > 0 && /* @__PURE__ */ (0,
|
|
7347
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(CustomToolbar, { children: [
|
|
7348
|
+
TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react8.default.Fragment, { children: [
|
|
7349
|
+
gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(CustomToolbarDivider, {}),
|
|
6276
7350
|
btns.map((btn) => {
|
|
6277
7351
|
const isActive = activeCommands.has(btn.cmd);
|
|
6278
|
-
return /* @__PURE__ */ (0,
|
|
7352
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
6279
7353
|
CustomToolbarButton,
|
|
6280
7354
|
{
|
|
6281
7355
|
title: btn.title,
|
|
@@ -6284,7 +7358,7 @@ function FloatingToolbar({
|
|
|
6284
7358
|
e.preventDefault();
|
|
6285
7359
|
onCommand(btn.cmd);
|
|
6286
7360
|
},
|
|
6287
|
-
children: /* @__PURE__ */ (0,
|
|
7361
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
6288
7362
|
"svg",
|
|
6289
7363
|
{
|
|
6290
7364
|
width: "16",
|
|
@@ -6305,7 +7379,7 @@ function FloatingToolbar({
|
|
|
6305
7379
|
);
|
|
6306
7380
|
})
|
|
6307
7381
|
] }, gi)),
|
|
6308
|
-
showEditLink ? /* @__PURE__ */ (0,
|
|
7382
|
+
showEditLink ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
6309
7383
|
CustomToolbarButton,
|
|
6310
7384
|
{
|
|
6311
7385
|
type: "button",
|
|
@@ -6319,7 +7393,7 @@ function FloatingToolbar({
|
|
|
6319
7393
|
e.preventDefault();
|
|
6320
7394
|
e.stopPropagation();
|
|
6321
7395
|
},
|
|
6322
|
-
children: /* @__PURE__ */ (0,
|
|
7396
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react11.Link, { className: "size-4 shrink-0", "aria-hidden": true })
|
|
6323
7397
|
}
|
|
6324
7398
|
) : null
|
|
6325
7399
|
] })
|
|
@@ -6336,7 +7410,7 @@ function StateToggle({
|
|
|
6336
7410
|
states,
|
|
6337
7411
|
onStateChange
|
|
6338
7412
|
}) {
|
|
6339
|
-
return /* @__PURE__ */ (0,
|
|
7413
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
6340
7414
|
ToggleGroup,
|
|
6341
7415
|
{
|
|
6342
7416
|
"data-ohw-state-toggle": "",
|
|
@@ -6350,7 +7424,7 @@ function StateToggle({
|
|
|
6350
7424
|
left: rect.right - 8,
|
|
6351
7425
|
transform: "translateX(-100%)"
|
|
6352
7426
|
},
|
|
6353
|
-
children: states.map((state) => /* @__PURE__ */ (0,
|
|
7427
|
+
children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
|
|
6354
7428
|
}
|
|
6355
7429
|
);
|
|
6356
7430
|
}
|
|
@@ -6373,12 +7447,12 @@ function resolveSubdomain(subdomainFromQuery) {
|
|
|
6373
7447
|
return "";
|
|
6374
7448
|
}
|
|
6375
7449
|
function OhhwellsBridge() {
|
|
6376
|
-
const pathname = (0,
|
|
6377
|
-
const router = (0,
|
|
6378
|
-
const searchParams = (0,
|
|
7450
|
+
const pathname = (0, import_navigation2.usePathname)();
|
|
7451
|
+
const router = (0, import_navigation2.useRouter)();
|
|
7452
|
+
const searchParams = (0, import_navigation2.useSearchParams)();
|
|
6379
7453
|
const isEditMode = isEditSessionActive();
|
|
6380
|
-
const [bridgeRoot, setBridgeRoot] = (0,
|
|
6381
|
-
(0,
|
|
7454
|
+
const [bridgeRoot, setBridgeRoot] = (0, import_react8.useState)(null);
|
|
7455
|
+
(0, import_react8.useEffect)(() => {
|
|
6382
7456
|
const figtreeFontId = "ohw-figtree-font";
|
|
6383
7457
|
if (!document.getElementById(figtreeFontId)) {
|
|
6384
7458
|
const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
|
|
@@ -6386,7 +7460,10 @@ function OhhwellsBridge() {
|
|
|
6386
7460
|
const stylesheet = Object.assign(document.createElement("link"), {
|
|
6387
7461
|
id: figtreeFontId,
|
|
6388
7462
|
rel: "stylesheet",
|
|
6389
|
-
|
|
7463
|
+
// Inter is loaded alongside Figtree for the media overlay's Replace button. The bridge
|
|
7464
|
+
// renders inside the customer's document, so it cannot assume any font is present — an
|
|
7465
|
+
// unloaded family would silently fall back to whatever the template happens to use.
|
|
7466
|
+
href: "https://fonts.googleapis.com/css2?family=Figtree:ital,wght@0,300..900;1,300..900&family=Inter:wght@400;500;600&display=swap"
|
|
6390
7467
|
});
|
|
6391
7468
|
document.head.append(preconnect1, preconnect2, stylesheet);
|
|
6392
7469
|
}
|
|
@@ -6403,80 +7480,91 @@ function OhhwellsBridge() {
|
|
|
6403
7480
|
const subdomainFromQuery = searchParams.get("subdomain");
|
|
6404
7481
|
const subdomain = resolveSubdomain(subdomainFromQuery);
|
|
6405
7482
|
useLinkHrefGuardian(pathname, subdomain, isEditMode);
|
|
6406
|
-
const
|
|
7483
|
+
const postToParent2 = (0, import_react8.useCallback)((data) => {
|
|
6407
7484
|
if (typeof window !== "undefined" && window.parent !== window) {
|
|
6408
7485
|
window.parent.postMessage(data, "*");
|
|
6409
7486
|
}
|
|
6410
7487
|
}, []);
|
|
6411
|
-
const [fetchState, setFetchState] = (0,
|
|
6412
|
-
const autoSaveTimers = (0,
|
|
6413
|
-
const activeElRef = (0,
|
|
6414
|
-
const selectedElRef = (0,
|
|
6415
|
-
const originalContentRef = (0,
|
|
6416
|
-
const activeStateElRef = (0,
|
|
6417
|
-
const parentScrollRef = (0,
|
|
6418
|
-
const visibleViewportRef = (0,
|
|
6419
|
-
const [dialogPortalContainer, setDialogPortalContainer] = (0,
|
|
6420
|
-
const attachVisibleViewport = (0,
|
|
7488
|
+
const [fetchState, setFetchState] = (0, import_react8.useState)("idle");
|
|
7489
|
+
const autoSaveTimers = (0, import_react8.useRef)(/* @__PURE__ */ new Map());
|
|
7490
|
+
const activeElRef = (0, import_react8.useRef)(null);
|
|
7491
|
+
const selectedElRef = (0, import_react8.useRef)(null);
|
|
7492
|
+
const originalContentRef = (0, import_react8.useRef)(null);
|
|
7493
|
+
const activeStateElRef = (0, import_react8.useRef)(null);
|
|
7494
|
+
const parentScrollRef = (0, import_react8.useRef)(null);
|
|
7495
|
+
const visibleViewportRef = (0, import_react8.useRef)(null);
|
|
7496
|
+
const [dialogPortalContainer, setDialogPortalContainer] = (0, import_react8.useState)(null);
|
|
7497
|
+
const attachVisibleViewport = (0, import_react8.useCallback)((node) => {
|
|
6421
7498
|
visibleViewportRef.current = node;
|
|
6422
7499
|
setDialogPortalContainer(node);
|
|
6423
7500
|
if (node) applyVisibleViewport(node, parentScrollRef.current);
|
|
6424
7501
|
}, []);
|
|
6425
|
-
const toolbarElRef = (0,
|
|
6426
|
-
const glowElRef = (0,
|
|
6427
|
-
const hoveredImageRef = (0,
|
|
6428
|
-
const hoveredImageHasTextOverlapRef = (0,
|
|
6429
|
-
const
|
|
6430
|
-
const
|
|
6431
|
-
const
|
|
6432
|
-
const
|
|
6433
|
-
const
|
|
7502
|
+
const toolbarElRef = (0, import_react8.useRef)(null);
|
|
7503
|
+
const glowElRef = (0, import_react8.useRef)(null);
|
|
7504
|
+
const hoveredImageRef = (0, import_react8.useRef)(null);
|
|
7505
|
+
const hoveredImageHasTextOverlapRef = (0, import_react8.useRef)(false);
|
|
7506
|
+
const dragOverElRef = (0, import_react8.useRef)(null);
|
|
7507
|
+
const [mediaHover, setMediaHover] = (0, import_react8.useState)(null);
|
|
7508
|
+
const [uploadingRects, setUploadingRects] = (0, import_react8.useState)({});
|
|
7509
|
+
const hoveredGapRef = (0, import_react8.useRef)(null);
|
|
7510
|
+
const imageUnhoverTimerRef = (0, import_react8.useRef)(null);
|
|
7511
|
+
const imageShowTimerRef = (0, import_react8.useRef)(null);
|
|
7512
|
+
const editStylesRef = (0, import_react8.useRef)(null);
|
|
7513
|
+
const activateRef = (0, import_react8.useRef)(() => {
|
|
7514
|
+
});
|
|
7515
|
+
const deactivateRef = (0, import_react8.useRef)(() => {
|
|
6434
7516
|
});
|
|
6435
|
-
const
|
|
7517
|
+
const selectRef = (0, import_react8.useRef)(() => {
|
|
6436
7518
|
});
|
|
6437
|
-
const
|
|
7519
|
+
const selectFrameRef = (0, import_react8.useRef)(() => {
|
|
6438
7520
|
});
|
|
6439
|
-
const deselectRef = (0,
|
|
7521
|
+
const deselectRef = (0, import_react8.useRef)(() => {
|
|
6440
7522
|
});
|
|
6441
|
-
const reselectNavigationItemRef = (0,
|
|
7523
|
+
const reselectNavigationItemRef = (0, import_react8.useRef)(() => {
|
|
6442
7524
|
});
|
|
6443
|
-
const commitNavigationTextEditRef = (0,
|
|
7525
|
+
const commitNavigationTextEditRef = (0, import_react8.useRef)(() => {
|
|
6444
7526
|
});
|
|
6445
|
-
const refreshActiveCommandsRef = (0,
|
|
7527
|
+
const refreshActiveCommandsRef = (0, import_react8.useRef)(() => {
|
|
6446
7528
|
});
|
|
6447
|
-
const postToParentRef = (0,
|
|
6448
|
-
postToParentRef.current =
|
|
6449
|
-
const sectionsLoadedRef = (0,
|
|
6450
|
-
const pendingScheduleConfigRequests = (0,
|
|
6451
|
-
const [toolbarRect, setToolbarRect] = (0,
|
|
6452
|
-
const [toolbarVariant, setToolbarVariant] = (0,
|
|
6453
|
-
const toolbarVariantRef = (0,
|
|
7529
|
+
const postToParentRef = (0, import_react8.useRef)(postToParent2);
|
|
7530
|
+
postToParentRef.current = postToParent2;
|
|
7531
|
+
const sectionsLoadedRef = (0, import_react8.useRef)(false);
|
|
7532
|
+
const pendingScheduleConfigRequests = (0, import_react8.useRef)([]);
|
|
7533
|
+
const [toolbarRect, setToolbarRect] = (0, import_react8.useState)(null);
|
|
7534
|
+
const [toolbarVariant, setToolbarVariant] = (0, import_react8.useState)("none");
|
|
7535
|
+
const toolbarVariantRef = (0, import_react8.useRef)("none");
|
|
6454
7536
|
toolbarVariantRef.current = toolbarVariant;
|
|
6455
|
-
const [reorderHrefKey, setReorderHrefKey] = (0,
|
|
6456
|
-
const [reorderDragDisabled, setReorderDragDisabled] = (0,
|
|
6457
|
-
const [toggleState, setToggleState] = (0,
|
|
6458
|
-
const [maxBadge, setMaxBadge] = (0,
|
|
6459
|
-
const [activeCommands, setActiveCommands] = (0,
|
|
6460
|
-
const [sectionGap, setSectionGap] = (0,
|
|
6461
|
-
const [toolbarShowEditLink, setToolbarShowEditLink] = (0,
|
|
6462
|
-
const
|
|
6463
|
-
const [
|
|
6464
|
-
const
|
|
6465
|
-
const [
|
|
6466
|
-
const
|
|
6467
|
-
const [
|
|
6468
|
-
const [
|
|
6469
|
-
const [
|
|
6470
|
-
const
|
|
6471
|
-
const
|
|
6472
|
-
const
|
|
6473
|
-
const
|
|
6474
|
-
const
|
|
7537
|
+
const [reorderHrefKey, setReorderHrefKey] = (0, import_react8.useState)(null);
|
|
7538
|
+
const [reorderDragDisabled, setReorderDragDisabled] = (0, import_react8.useState)(false);
|
|
7539
|
+
const [toggleState, setToggleState] = (0, import_react8.useState)(null);
|
|
7540
|
+
const [maxBadge, setMaxBadge] = (0, import_react8.useState)(null);
|
|
7541
|
+
const [activeCommands, setActiveCommands] = (0, import_react8.useState)(/* @__PURE__ */ new Set());
|
|
7542
|
+
const [sectionGap, setSectionGap] = (0, import_react8.useState)(null);
|
|
7543
|
+
const [toolbarShowEditLink, setToolbarShowEditLink] = (0, import_react8.useState)(false);
|
|
7544
|
+
const hoveredNavContainerRef = (0, import_react8.useRef)(null);
|
|
7545
|
+
const [hoveredNavContainerRect, setHoveredNavContainerRect] = (0, import_react8.useState)(null);
|
|
7546
|
+
const hoveredItemElRef = (0, import_react8.useRef)(null);
|
|
7547
|
+
const [hoveredItemRect, setHoveredItemRect] = (0, import_react8.useState)(null);
|
|
7548
|
+
const siblingHintElRef = (0, import_react8.useRef)(null);
|
|
7549
|
+
const [siblingHintRect, setSiblingHintRect] = (0, import_react8.useState)(null);
|
|
7550
|
+
const [isItemDragging, setIsItemDragging] = (0, import_react8.useState)(false);
|
|
7551
|
+
const [linkPopover, setLinkPopover] = (0, import_react8.useState)(null);
|
|
7552
|
+
const linkPopoverSessionRef = (0, import_react8.useRef)(null);
|
|
7553
|
+
const addNavAfterAnchorRef = (0, import_react8.useRef)(null);
|
|
7554
|
+
const editContentRef = (0, import_react8.useRef)({});
|
|
7555
|
+
const [sitePages, setSitePages] = (0, import_react8.useState)([]);
|
|
7556
|
+
const [sectionsByPath, setSectionsByPath] = (0, import_react8.useState)({});
|
|
7557
|
+
const sectionsPrefetchGenRef = (0, import_react8.useRef)(0);
|
|
7558
|
+
const setLinkPopoverRef = (0, import_react8.useRef)(setLinkPopover);
|
|
7559
|
+
const linkPopoverPanelRef = (0, import_react8.useRef)(null);
|
|
7560
|
+
const linkPopoverOpenRef = (0, import_react8.useRef)(false);
|
|
7561
|
+
const linkPopoverGraceUntilRef = (0, import_react8.useRef)(0);
|
|
6475
7562
|
setLinkPopoverRef.current = setLinkPopover;
|
|
7563
|
+
linkPopoverSessionRef.current = linkPopover;
|
|
6476
7564
|
const bumpLinkPopoverGrace = () => {
|
|
6477
7565
|
linkPopoverGraceUntilRef.current = Date.now() + 350;
|
|
6478
7566
|
};
|
|
6479
|
-
const runSectionsPrefetch = (0,
|
|
7567
|
+
const runSectionsPrefetch = (0, import_react8.useCallback)((pages) => {
|
|
6480
7568
|
if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
|
|
6481
7569
|
const gen = ++sectionsPrefetchGenRef.current;
|
|
6482
7570
|
const paths = pages.map((p) => p.path);
|
|
@@ -6495,9 +7583,9 @@ function OhhwellsBridge() {
|
|
|
6495
7583
|
);
|
|
6496
7584
|
});
|
|
6497
7585
|
}, [isEditMode, pathname]);
|
|
6498
|
-
const runSectionsPrefetchRef = (0,
|
|
7586
|
+
const runSectionsPrefetchRef = (0, import_react8.useRef)(runSectionsPrefetch);
|
|
6499
7587
|
runSectionsPrefetchRef.current = runSectionsPrefetch;
|
|
6500
|
-
(0,
|
|
7588
|
+
(0, import_react8.useEffect)(() => {
|
|
6501
7589
|
if (!linkPopover) return;
|
|
6502
7590
|
if (hoveredImageRef.current) {
|
|
6503
7591
|
hoveredImageRef.current = null;
|
|
@@ -6505,33 +7593,9 @@ function OhhwellsBridge() {
|
|
|
6505
7593
|
}
|
|
6506
7594
|
hoveredGapRef.current = null;
|
|
6507
7595
|
setSectionGap(null);
|
|
6508
|
-
|
|
6509
|
-
|
|
6510
|
-
|
|
6511
|
-
const body = document.body;
|
|
6512
|
-
const prevHtmlOverflow = html.style.overflow;
|
|
6513
|
-
const prevBodyOverflow = body.style.overflow;
|
|
6514
|
-
html.style.overflow = "hidden";
|
|
6515
|
-
body.style.overflow = "hidden";
|
|
6516
|
-
const preventBackgroundScroll = (e) => {
|
|
6517
|
-
const target = e.target;
|
|
6518
|
-
if (target instanceof Element && target.closest('[data-ohw-link-modal-root], [data-slot="dialog-overlay"]')) {
|
|
6519
|
-
return;
|
|
6520
|
-
}
|
|
6521
|
-
e.preventDefault();
|
|
6522
|
-
};
|
|
6523
|
-
const scrollOpts = { passive: false, capture: true };
|
|
6524
|
-
document.addEventListener("wheel", preventBackgroundScroll, scrollOpts);
|
|
6525
|
-
document.addEventListener("touchmove", preventBackgroundScroll, scrollOpts);
|
|
6526
|
-
return () => {
|
|
6527
|
-
postToParent({ type: "ow:link-modal-lock", locked: false });
|
|
6528
|
-
html.style.overflow = prevHtmlOverflow;
|
|
6529
|
-
body.style.overflow = prevBodyOverflow;
|
|
6530
|
-
document.removeEventListener("wheel", preventBackgroundScroll, scrollOpts);
|
|
6531
|
-
document.removeEventListener("touchmove", preventBackgroundScroll, scrollOpts);
|
|
6532
|
-
};
|
|
6533
|
-
}, [linkPopover, postToParent]);
|
|
6534
|
-
(0, import_react6.useEffect)(() => {
|
|
7596
|
+
postToParent2({ type: "ow:image-unhover" });
|
|
7597
|
+
}, [linkPopover, postToParent2]);
|
|
7598
|
+
(0, import_react8.useEffect)(() => {
|
|
6535
7599
|
if (!isEditMode) return;
|
|
6536
7600
|
const useFixtures = shouldUseDevFixtures();
|
|
6537
7601
|
if (useFixtures) {
|
|
@@ -6552,17 +7616,17 @@ function OhhwellsBridge() {
|
|
|
6552
7616
|
runSectionsPrefetchRef.current(mapped);
|
|
6553
7617
|
};
|
|
6554
7618
|
window.addEventListener("message", onSitePages);
|
|
6555
|
-
if (!useFixtures)
|
|
7619
|
+
if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
|
|
6556
7620
|
return () => window.removeEventListener("message", onSitePages);
|
|
6557
|
-
}, [isEditMode,
|
|
6558
|
-
(0,
|
|
7621
|
+
}, [isEditMode, postToParent2]);
|
|
7622
|
+
(0, import_react8.useEffect)(() => {
|
|
6559
7623
|
if (!isEditMode || shouldUseDevFixtures()) return;
|
|
6560
7624
|
void loadAllSectionsManifest().then((manifest) => {
|
|
6561
7625
|
if (Object.keys(manifest).length === 0) return;
|
|
6562
7626
|
setSectionsByPath((prev) => ({ ...manifest, ...prev }));
|
|
6563
7627
|
});
|
|
6564
7628
|
}, [isEditMode]);
|
|
6565
|
-
(0,
|
|
7629
|
+
(0, import_react8.useEffect)(() => {
|
|
6566
7630
|
const update = () => {
|
|
6567
7631
|
const el = activeElRef.current ?? selectedElRef.current;
|
|
6568
7632
|
if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
|
|
@@ -6586,10 +7650,10 @@ function OhhwellsBridge() {
|
|
|
6586
7650
|
vvp.removeEventListener("resize", update);
|
|
6587
7651
|
};
|
|
6588
7652
|
}, []);
|
|
6589
|
-
const refreshStateRules = (0,
|
|
7653
|
+
const refreshStateRules = (0, import_react8.useCallback)(() => {
|
|
6590
7654
|
editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
|
|
6591
7655
|
}, []);
|
|
6592
|
-
const processConfigRequest = (0,
|
|
7656
|
+
const processConfigRequest = (0, import_react8.useCallback)((insertAfterVal) => {
|
|
6593
7657
|
const tracker = getSectionsTracker();
|
|
6594
7658
|
let entries = [];
|
|
6595
7659
|
try {
|
|
@@ -6612,7 +7676,7 @@ function OhhwellsBridge() {
|
|
|
6612
7676
|
}
|
|
6613
7677
|
window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
|
|
6614
7678
|
}, [isEditMode]);
|
|
6615
|
-
const deactivate = (0,
|
|
7679
|
+
const deactivate = (0, import_react8.useCallback)(() => {
|
|
6616
7680
|
const el = activeElRef.current;
|
|
6617
7681
|
if (!el) return;
|
|
6618
7682
|
const key = el.dataset.ohwKey;
|
|
@@ -6641,21 +7705,23 @@ function OhhwellsBridge() {
|
|
|
6641
7705
|
setMaxBadge(null);
|
|
6642
7706
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
6643
7707
|
setToolbarShowEditLink(false);
|
|
6644
|
-
|
|
6645
|
-
}, [
|
|
6646
|
-
const deselect = (0,
|
|
7708
|
+
postToParent2({ type: "ow:exit-edit" });
|
|
7709
|
+
}, [postToParent2]);
|
|
7710
|
+
const deselect = (0, import_react8.useCallback)(() => {
|
|
6647
7711
|
selectedElRef.current = null;
|
|
6648
7712
|
setReorderHrefKey(null);
|
|
6649
7713
|
setReorderDragDisabled(false);
|
|
6650
7714
|
siblingHintElRef.current = null;
|
|
6651
7715
|
setSiblingHintRect(null);
|
|
6652
7716
|
setIsItemDragging(false);
|
|
7717
|
+
hoveredNavContainerRef.current = null;
|
|
7718
|
+
setHoveredNavContainerRect(null);
|
|
6653
7719
|
if (!activeElRef.current) {
|
|
6654
7720
|
setToolbarRect(null);
|
|
6655
7721
|
setToolbarVariant("none");
|
|
6656
7722
|
}
|
|
6657
7723
|
}, []);
|
|
6658
|
-
const reselectNavigationItem = (0,
|
|
7724
|
+
const reselectNavigationItem = (0, import_react8.useCallback)((navAnchor) => {
|
|
6659
7725
|
selectedElRef.current = navAnchor;
|
|
6660
7726
|
const { key, disabled } = getNavigationItemReorderState(navAnchor);
|
|
6661
7727
|
setReorderHrefKey(key);
|
|
@@ -6665,7 +7731,7 @@ function OhhwellsBridge() {
|
|
|
6665
7731
|
setToolbarShowEditLink(false);
|
|
6666
7732
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
6667
7733
|
}, []);
|
|
6668
|
-
const commitNavigationTextEdit = (0,
|
|
7734
|
+
const commitNavigationTextEdit = (0, import_react8.useCallback)((navAnchor) => {
|
|
6669
7735
|
const el = activeElRef.current;
|
|
6670
7736
|
if (!el) return;
|
|
6671
7737
|
const key = el.dataset.ohwKey;
|
|
@@ -6678,9 +7744,9 @@ function OhhwellsBridge() {
|
|
|
6678
7744
|
const html = sanitizeHtml(el.innerHTML);
|
|
6679
7745
|
const original = originalContentRef.current ?? "";
|
|
6680
7746
|
if (html !== sanitizeHtml(original)) {
|
|
6681
|
-
|
|
7747
|
+
postToParent2({ type: "ow:change", nodes: [{ key, text: html }] });
|
|
6682
7748
|
const h = document.documentElement.scrollHeight;
|
|
6683
|
-
if (h > 50)
|
|
7749
|
+
if (h > 50) postToParent2({ type: "ow:height", height: h });
|
|
6684
7750
|
}
|
|
6685
7751
|
}
|
|
6686
7752
|
el.removeAttribute("contenteditable");
|
|
@@ -6688,31 +7754,38 @@ function OhhwellsBridge() {
|
|
|
6688
7754
|
setMaxBadge(null);
|
|
6689
7755
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
6690
7756
|
setToolbarShowEditLink(false);
|
|
6691
|
-
|
|
7757
|
+
postToParent2({ type: "ow:exit-edit" });
|
|
6692
7758
|
reselectNavigationItem(navAnchor);
|
|
6693
|
-
}, [
|
|
6694
|
-
const
|
|
6695
|
-
const
|
|
6696
|
-
|
|
6697
|
-
|
|
6698
|
-
|
|
6699
|
-
|
|
7759
|
+
}, [postToParent2, reselectNavigationItem]);
|
|
7760
|
+
const handleAddTopLevelNavItem = (0, import_react8.useCallback)(() => {
|
|
7761
|
+
const items = listNavbarItems();
|
|
7762
|
+
addNavAfterAnchorRef.current = items[items.length - 1] ?? null;
|
|
7763
|
+
deselectRef.current();
|
|
7764
|
+
deactivateRef.current();
|
|
7765
|
+
bumpLinkPopoverGrace();
|
|
7766
|
+
setLinkPopover({
|
|
7767
|
+
key: "__add-nav__",
|
|
7768
|
+
mode: "create",
|
|
7769
|
+
intent: "add-nav"
|
|
7770
|
+
});
|
|
6700
7771
|
}, []);
|
|
6701
|
-
const handleItemDragStart = (0,
|
|
7772
|
+
const handleItemDragStart = (0, import_react8.useCallback)(() => {
|
|
6702
7773
|
siblingHintElRef.current = null;
|
|
6703
7774
|
setSiblingHintRect(null);
|
|
6704
7775
|
setIsItemDragging(true);
|
|
6705
7776
|
}, []);
|
|
6706
|
-
const handleItemDragEnd = (0,
|
|
7777
|
+
const handleItemDragEnd = (0, import_react8.useCallback)(() => {
|
|
6707
7778
|
setIsItemDragging(false);
|
|
6708
7779
|
}, []);
|
|
6709
7780
|
reselectNavigationItemRef.current = reselectNavigationItem;
|
|
6710
7781
|
commitNavigationTextEditRef.current = commitNavigationTextEdit;
|
|
6711
|
-
const select = (0,
|
|
7782
|
+
const select = (0, import_react8.useCallback)((anchor) => {
|
|
6712
7783
|
if (!isNavigationItem(anchor)) return;
|
|
6713
7784
|
if (activeElRef.current) deactivate();
|
|
6714
7785
|
selectedElRef.current = anchor;
|
|
6715
7786
|
clearHrefKeyHover(anchor);
|
|
7787
|
+
hoveredNavContainerRef.current = null;
|
|
7788
|
+
setHoveredNavContainerRect(null);
|
|
6716
7789
|
setHoveredItemRect(null);
|
|
6717
7790
|
hoveredItemElRef.current = null;
|
|
6718
7791
|
siblingHintElRef.current = null;
|
|
@@ -6726,13 +7799,32 @@ function OhhwellsBridge() {
|
|
|
6726
7799
|
setToolbarShowEditLink(false);
|
|
6727
7800
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
6728
7801
|
}, [deactivate]);
|
|
6729
|
-
const
|
|
7802
|
+
const selectFrame = (0, import_react8.useCallback)((el) => {
|
|
7803
|
+
if (!isNavigationContainer(el)) return;
|
|
7804
|
+
if (activeElRef.current) deactivate();
|
|
7805
|
+
selectedElRef.current = el;
|
|
7806
|
+
clearHrefKeyHover(el);
|
|
7807
|
+
hoveredNavContainerRef.current = null;
|
|
7808
|
+
setHoveredNavContainerRect(null);
|
|
7809
|
+
setHoveredItemRect(null);
|
|
7810
|
+
hoveredItemElRef.current = null;
|
|
7811
|
+
siblingHintElRef.current = null;
|
|
7812
|
+
setSiblingHintRect(null);
|
|
7813
|
+
setIsItemDragging(false);
|
|
7814
|
+
setReorderHrefKey(null);
|
|
7815
|
+
setReorderDragDisabled(false);
|
|
7816
|
+
setToolbarVariant("select-frame");
|
|
7817
|
+
setToolbarRect(el.getBoundingClientRect());
|
|
7818
|
+
setToolbarShowEditLink(false);
|
|
7819
|
+
setActiveCommands(/* @__PURE__ */ new Set());
|
|
7820
|
+
}, [deactivate]);
|
|
7821
|
+
const activate = (0, import_react8.useCallback)((el, options) => {
|
|
6730
7822
|
if (activeElRef.current === el) return;
|
|
6731
7823
|
selectedElRef.current = null;
|
|
6732
7824
|
deactivate();
|
|
6733
7825
|
if (hoveredImageRef.current) {
|
|
6734
7826
|
hoveredImageRef.current = null;
|
|
6735
|
-
|
|
7827
|
+
setMediaHover(null);
|
|
6736
7828
|
}
|
|
6737
7829
|
setToolbarVariant("rich-text");
|
|
6738
7830
|
siblingHintElRef.current = null;
|
|
@@ -6744,6 +7836,9 @@ function OhhwellsBridge() {
|
|
|
6744
7836
|
activeElRef.current = el;
|
|
6745
7837
|
originalContentRef.current = el.innerHTML;
|
|
6746
7838
|
el.focus();
|
|
7839
|
+
if (options?.caretX !== void 0 && options?.caretY !== void 0) {
|
|
7840
|
+
placeCaretAtPoint(el, options.caretX, options.caretY);
|
|
7841
|
+
}
|
|
6747
7842
|
setToolbarShowEditLink(Boolean(getHrefKeyFromElement(el)));
|
|
6748
7843
|
const navAnchor = getNavigationItemAnchor(el);
|
|
6749
7844
|
if (navAnchor) {
|
|
@@ -6755,14 +7850,15 @@ function OhhwellsBridge() {
|
|
|
6755
7850
|
setReorderDragDisabled(reorderDisabled);
|
|
6756
7851
|
}
|
|
6757
7852
|
setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
|
|
6758
|
-
|
|
7853
|
+
postToParent2({ type: "ow:enter-edit", key: el.dataset.ohwKey });
|
|
6759
7854
|
requestAnimationFrame(() => refreshActiveCommandsRef.current());
|
|
6760
|
-
}, [deactivate,
|
|
7855
|
+
}, [deactivate, postToParent2]);
|
|
6761
7856
|
activateRef.current = activate;
|
|
6762
7857
|
deactivateRef.current = deactivate;
|
|
6763
7858
|
selectRef.current = select;
|
|
7859
|
+
selectFrameRef.current = selectFrame;
|
|
6764
7860
|
deselectRef.current = deselect;
|
|
6765
|
-
(0,
|
|
7861
|
+
(0, import_react8.useLayoutEffect)(() => {
|
|
6766
7862
|
if (!subdomain || isEditMode) {
|
|
6767
7863
|
setFetchState("done");
|
|
6768
7864
|
return;
|
|
@@ -6771,6 +7867,7 @@ function OhhwellsBridge() {
|
|
|
6771
7867
|
const imageLoads = [];
|
|
6772
7868
|
for (const [key, val] of Object.entries(content)) {
|
|
6773
7869
|
if (key === "__ohw_sections") continue;
|
|
7870
|
+
if (applyVideoSettingNode(key, val)) continue;
|
|
6774
7871
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
6775
7872
|
if (el.dataset.ohwEditable === "image") {
|
|
6776
7873
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
@@ -6784,6 +7881,15 @@ function OhhwellsBridge() {
|
|
|
6784
7881
|
} else if (el.dataset.ohwEditable === "bg-image") {
|
|
6785
7882
|
const next = `url('${val}')`;
|
|
6786
7883
|
if (el.style.backgroundImage !== next) el.style.backgroundImage = next;
|
|
7884
|
+
} else if (el.dataset.ohwEditable === "video") {
|
|
7885
|
+
const video = getVideoEl(el);
|
|
7886
|
+
if (video && video.src !== val) {
|
|
7887
|
+
applyVideoSrc(video, val);
|
|
7888
|
+
imageLoads.push(new Promise((resolve) => {
|
|
7889
|
+
video.onloadeddata = () => resolve();
|
|
7890
|
+
video.onerror = () => resolve();
|
|
7891
|
+
}));
|
|
7892
|
+
}
|
|
6787
7893
|
} else if (el.dataset.ohwEditable === "link") {
|
|
6788
7894
|
applyLinkHref(el, val);
|
|
6789
7895
|
} else if (el.innerHTML !== val) {
|
|
@@ -6792,6 +7898,7 @@ function OhhwellsBridge() {
|
|
|
6792
7898
|
});
|
|
6793
7899
|
applyLinkByKey(key, val);
|
|
6794
7900
|
}
|
|
7901
|
+
reconcileNavbarItemsFromContent(content);
|
|
6795
7902
|
enforceLinkHrefs();
|
|
6796
7903
|
initSectionsFromContent(content, true);
|
|
6797
7904
|
sectionsLoadedRef.current = true;
|
|
@@ -6820,7 +7927,7 @@ function OhhwellsBridge() {
|
|
|
6820
7927
|
cancelled = true;
|
|
6821
7928
|
};
|
|
6822
7929
|
}, [subdomain, isEditMode]);
|
|
6823
|
-
(0,
|
|
7930
|
+
(0, import_react8.useEffect)(() => {
|
|
6824
7931
|
if (!subdomain || isEditMode) return;
|
|
6825
7932
|
let debounceTimer = null;
|
|
6826
7933
|
let observer = null;
|
|
@@ -6832,6 +7939,7 @@ function OhhwellsBridge() {
|
|
|
6832
7939
|
try {
|
|
6833
7940
|
for (const [key, val] of Object.entries(content)) {
|
|
6834
7941
|
if (key === "__ohw_sections") continue;
|
|
7942
|
+
if (applyVideoSettingNode(key, val)) continue;
|
|
6835
7943
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
6836
7944
|
if (el.dataset.ohwEditable === "image") {
|
|
6837
7945
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
@@ -6839,6 +7947,9 @@ function OhhwellsBridge() {
|
|
|
6839
7947
|
} else if (el.dataset.ohwEditable === "bg-image") {
|
|
6840
7948
|
const next = `url('${val}')`;
|
|
6841
7949
|
if (el.style.backgroundImage !== next) el.style.backgroundImage = next;
|
|
7950
|
+
} else if (el.dataset.ohwEditable === "video") {
|
|
7951
|
+
const video = getVideoEl(el);
|
|
7952
|
+
if (video && video.src !== val) applyVideoSrc(video, val);
|
|
6842
7953
|
} else if (el.dataset.ohwEditable === "link") {
|
|
6843
7954
|
applyLinkHref(el, val);
|
|
6844
7955
|
} else if (el.innerHTML !== val) {
|
|
@@ -6847,6 +7958,7 @@ function OhhwellsBridge() {
|
|
|
6847
7958
|
});
|
|
6848
7959
|
applyLinkByKey(key, val);
|
|
6849
7960
|
}
|
|
7961
|
+
reconcileNavbarItemsFromContent(content);
|
|
6850
7962
|
} finally {
|
|
6851
7963
|
observer?.observe(document.body, { childList: true, subtree: true });
|
|
6852
7964
|
}
|
|
@@ -6864,26 +7976,44 @@ function OhhwellsBridge() {
|
|
|
6864
7976
|
if (debounceTimer) clearTimeout(debounceTimer);
|
|
6865
7977
|
};
|
|
6866
7978
|
}, [subdomain, isEditMode, pathname]);
|
|
6867
|
-
(0,
|
|
7979
|
+
(0, import_react8.useLayoutEffect)(() => {
|
|
6868
7980
|
const el = document.getElementById("ohw-loader");
|
|
6869
7981
|
if (!el) return;
|
|
6870
7982
|
const visible = Boolean(subdomain) && fetchState !== "done";
|
|
6871
7983
|
el.style.display = visible ? "flex" : "none";
|
|
6872
7984
|
}, [subdomain, fetchState]);
|
|
6873
|
-
(0,
|
|
6874
|
-
|
|
6875
|
-
}, [pathname,
|
|
6876
|
-
(0,
|
|
7985
|
+
(0, import_react8.useEffect)(() => {
|
|
7986
|
+
postToParent2({ type: "ow:navigation", path: pathname });
|
|
7987
|
+
}, [pathname, postToParent2]);
|
|
7988
|
+
(0, import_react8.useEffect)(() => {
|
|
6877
7989
|
if (!isEditMode) return;
|
|
7990
|
+
if (linkPopoverSessionRef.current?.intent === "add-nav") return;
|
|
7991
|
+
if (document.querySelector("[data-ohw-section-picker]")) return;
|
|
6878
7992
|
setLinkPopover(null);
|
|
6879
7993
|
deselectRef.current();
|
|
6880
7994
|
deactivateRef.current();
|
|
6881
7995
|
}, [pathname, isEditMode]);
|
|
6882
|
-
(0,
|
|
7996
|
+
(0, import_react8.useEffect)(() => {
|
|
7997
|
+
const contentForNav = () => {
|
|
7998
|
+
if (isEditMode) return editContentRef.current;
|
|
7999
|
+
if (!subdomain) return {};
|
|
8000
|
+
return contentCache.get(subdomain) ?? {};
|
|
8001
|
+
};
|
|
8002
|
+
const run = () => reconcileNavbarItemsFromContent(contentForNav());
|
|
8003
|
+
run();
|
|
8004
|
+
const nav = document.querySelector("nav");
|
|
8005
|
+
if (!nav) return;
|
|
8006
|
+
const observer = new MutationObserver(() => {
|
|
8007
|
+
requestAnimationFrame(run);
|
|
8008
|
+
});
|
|
8009
|
+
observer.observe(nav, { childList: true, subtree: true });
|
|
8010
|
+
return () => observer.disconnect();
|
|
8011
|
+
}, [isEditMode, pathname, subdomain, fetchState]);
|
|
8012
|
+
(0, import_react8.useEffect)(() => {
|
|
6883
8013
|
if (!isEditMode) return;
|
|
6884
8014
|
const measure = () => {
|
|
6885
8015
|
const h = document.body.scrollHeight;
|
|
6886
|
-
if (h > 50)
|
|
8016
|
+
if (h > 50) postToParent2({ type: "ow:height", height: h });
|
|
6887
8017
|
};
|
|
6888
8018
|
const t1 = setTimeout(measure, 50);
|
|
6889
8019
|
const t2 = setTimeout(measure, 500);
|
|
@@ -6902,8 +8032,8 @@ function OhhwellsBridge() {
|
|
|
6902
8032
|
if (resizeTimer) clearTimeout(resizeTimer);
|
|
6903
8033
|
window.removeEventListener("resize", handleResize);
|
|
6904
8034
|
};
|
|
6905
|
-
}, [pathname, isEditMode,
|
|
6906
|
-
(0,
|
|
8035
|
+
}, [pathname, isEditMode, postToParent2]);
|
|
8036
|
+
(0, import_react8.useEffect)(() => {
|
|
6907
8037
|
if (!subdomainFromQuery || isEditMode) return;
|
|
6908
8038
|
const handleClick = (e) => {
|
|
6909
8039
|
const anchor = e.target.closest("a");
|
|
@@ -6919,7 +8049,7 @@ function OhhwellsBridge() {
|
|
|
6919
8049
|
document.addEventListener("click", handleClick, true);
|
|
6920
8050
|
return () => document.removeEventListener("click", handleClick, true);
|
|
6921
8051
|
}, [subdomainFromQuery, isEditMode, router]);
|
|
6922
|
-
(0,
|
|
8052
|
+
(0, import_react8.useEffect)(() => {
|
|
6923
8053
|
if (!isEditMode) {
|
|
6924
8054
|
editStylesRef.current?.base.remove();
|
|
6925
8055
|
editStylesRef.current?.forceHover.remove();
|
|
@@ -6942,8 +8072,9 @@ function OhhwellsBridge() {
|
|
|
6942
8072
|
[data-ohw-editable] {
|
|
6943
8073
|
display: block;
|
|
6944
8074
|
}
|
|
6945
|
-
[data-ohw-editable]:not([contenteditable]):not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]) { cursor: text !important; }
|
|
8075
|
+
[data-ohw-editable]:not([contenteditable]):not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"]) { cursor: text !important; }
|
|
6946
8076
|
[data-ohw-editable="image"], [data-ohw-editable="image"] *,
|
|
8077
|
+
[data-ohw-editable="video"], [data-ohw-editable="video"] *,
|
|
6947
8078
|
[data-ohw-editable="bg-image"], [data-ohw-editable="bg-image"] * { cursor: pointer !important; }
|
|
6948
8079
|
[data-ohw-editable="link"], [data-ohw-editable="link"] * { cursor: pointer !important; }
|
|
6949
8080
|
[data-ohw-hovered]:not([contenteditable]):not([data-ohw-href-key]) {
|
|
@@ -6992,6 +8123,13 @@ function OhhwellsBridge() {
|
|
|
6992
8123
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
6993
8124
|
if (isInsideLinkEditor(target)) return;
|
|
6994
8125
|
if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
|
|
8126
|
+
const navFromChrome = resolveNavContainerSelectionTarget(target, e.clientX, e.clientY);
|
|
8127
|
+
if (navFromChrome) {
|
|
8128
|
+
e.preventDefault();
|
|
8129
|
+
e.stopPropagation();
|
|
8130
|
+
selectFrameRef.current(navFromChrome);
|
|
8131
|
+
return;
|
|
8132
|
+
}
|
|
6995
8133
|
e.preventDefault();
|
|
6996
8134
|
e.stopPropagation();
|
|
6997
8135
|
return;
|
|
@@ -7006,14 +8144,15 @@ function OhhwellsBridge() {
|
|
|
7006
8144
|
bumpLinkPopoverGrace();
|
|
7007
8145
|
setLinkPopoverRef.current({
|
|
7008
8146
|
key: editable.dataset.ohwKey ?? "",
|
|
7009
|
-
|
|
8147
|
+
mode: "edit",
|
|
8148
|
+
target: getLinkHref2(editable)
|
|
7010
8149
|
});
|
|
7011
8150
|
return;
|
|
7012
8151
|
}
|
|
7013
|
-
if (editable
|
|
8152
|
+
if (isMediaEditable(editable)) {
|
|
7014
8153
|
e.preventDefault();
|
|
7015
8154
|
e.stopPropagation();
|
|
7016
|
-
postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "" });
|
|
8155
|
+
postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "", elementType: editable.dataset.ohwEditable ?? "image" });
|
|
7017
8156
|
return;
|
|
7018
8157
|
}
|
|
7019
8158
|
const hrefCtx = getHrefKeyFromElement(editable);
|
|
@@ -7022,7 +8161,8 @@ function OhhwellsBridge() {
|
|
|
7022
8161
|
e.preventDefault();
|
|
7023
8162
|
e.stopPropagation();
|
|
7024
8163
|
if (selectedElRef.current === navAnchor) {
|
|
7025
|
-
|
|
8164
|
+
if (e.detail >= 2) return;
|
|
8165
|
+
activateRef.current(editable, { caretX: e.clientX, caretY: e.clientY });
|
|
7026
8166
|
return;
|
|
7027
8167
|
}
|
|
7028
8168
|
selectRef.current(navAnchor);
|
|
@@ -7041,6 +8181,22 @@ function OhhwellsBridge() {
|
|
|
7041
8181
|
selectRef.current(hrefAnchor);
|
|
7042
8182
|
return;
|
|
7043
8183
|
}
|
|
8184
|
+
const navContainerToSelect = resolveNavContainerSelectionTarget(target, e.clientX, e.clientY);
|
|
8185
|
+
if (navContainerToSelect) {
|
|
8186
|
+
e.preventDefault();
|
|
8187
|
+
e.stopPropagation();
|
|
8188
|
+
selectFrameRef.current(navContainerToSelect);
|
|
8189
|
+
return;
|
|
8190
|
+
}
|
|
8191
|
+
const selectedContainer = selectedElRef.current;
|
|
8192
|
+
if (selectedContainer && isNavigationContainer(selectedContainer)) {
|
|
8193
|
+
const navItem = getNavigationItemAnchor(target);
|
|
8194
|
+
if (!navItem && (selectedContainer === target || selectedContainer.contains(target))) {
|
|
8195
|
+
e.preventDefault();
|
|
8196
|
+
e.stopPropagation();
|
|
8197
|
+
return;
|
|
8198
|
+
}
|
|
8199
|
+
}
|
|
7044
8200
|
if (activeElRef.current) {
|
|
7045
8201
|
const sel = window.getSelection();
|
|
7046
8202
|
if (sel && !sel.isCollapsed) {
|
|
@@ -7066,10 +8222,48 @@ function OhhwellsBridge() {
|
|
|
7066
8222
|
deselectRef.current();
|
|
7067
8223
|
deactivateRef.current();
|
|
7068
8224
|
};
|
|
8225
|
+
const handleDblClick = (e) => {
|
|
8226
|
+
const target = e.target;
|
|
8227
|
+
if (target.closest("[data-ohw-toolbar]")) return;
|
|
8228
|
+
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
8229
|
+
if (target.closest("[data-ohw-max-badge]")) return;
|
|
8230
|
+
if (isInsideLinkEditor(target)) return;
|
|
8231
|
+
if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
|
|
8232
|
+
return;
|
|
8233
|
+
}
|
|
8234
|
+
const navLabel = getNavigationLabelEditable(target);
|
|
8235
|
+
if (!navLabel) return;
|
|
8236
|
+
const { editable } = navLabel;
|
|
8237
|
+
e.preventDefault();
|
|
8238
|
+
e.stopPropagation();
|
|
8239
|
+
if (activeElRef.current !== editable) {
|
|
8240
|
+
activateRef.current(editable);
|
|
8241
|
+
}
|
|
8242
|
+
requestAnimationFrame(() => {
|
|
8243
|
+
selectAllTextInEditable(editable);
|
|
8244
|
+
refreshActiveCommandsRef.current();
|
|
8245
|
+
});
|
|
8246
|
+
};
|
|
7069
8247
|
const handleMouseOver = (e) => {
|
|
7070
8248
|
const target = e.target;
|
|
8249
|
+
if (toolbarVariantRef.current !== "select-frame") {
|
|
8250
|
+
const navContainer = target.closest("[data-ohw-nav-container]");
|
|
8251
|
+
if (navContainer && !getNavigationItemAnchor(target)) {
|
|
8252
|
+
hoveredNavContainerRef.current = navContainer;
|
|
8253
|
+
setHoveredNavContainerRect(navContainer.getBoundingClientRect());
|
|
8254
|
+
hoveredItemElRef.current = null;
|
|
8255
|
+
setHoveredItemRect(null);
|
|
8256
|
+
return;
|
|
8257
|
+
}
|
|
8258
|
+
if (!target.closest("[data-ohw-nav-container]")) {
|
|
8259
|
+
hoveredNavContainerRef.current = null;
|
|
8260
|
+
setHoveredNavContainerRect(null);
|
|
8261
|
+
}
|
|
8262
|
+
}
|
|
7071
8263
|
const navAnchor = getNavigationItemAnchor(target);
|
|
7072
8264
|
if (navAnchor) {
|
|
8265
|
+
hoveredNavContainerRef.current = null;
|
|
8266
|
+
setHoveredNavContainerRect(null);
|
|
7073
8267
|
const selected2 = selectedElRef.current;
|
|
7074
8268
|
if (selected2 === navAnchor || selected2?.contains(navAnchor)) return;
|
|
7075
8269
|
clearHrefKeyHover(navAnchor);
|
|
@@ -7081,7 +8275,7 @@ function OhhwellsBridge() {
|
|
|
7081
8275
|
if (!editable) return;
|
|
7082
8276
|
const selected = selectedElRef.current;
|
|
7083
8277
|
if (selected && (selected === editable || selected.contains(editable))) return;
|
|
7084
|
-
if (editable
|
|
8278
|
+
if (!isMediaEditable(editable) && !editable.hasAttribute("contenteditable")) {
|
|
7085
8279
|
const hoverTarget = editable.closest("[data-ohw-href-key]") ?? editable;
|
|
7086
8280
|
if (hoverTarget.hasAttribute("data-ohw-href-key")) {
|
|
7087
8281
|
clearHrefKeyHover(hoverTarget);
|
|
@@ -7094,6 +8288,14 @@ function OhhwellsBridge() {
|
|
|
7094
8288
|
};
|
|
7095
8289
|
const handleMouseOut = (e) => {
|
|
7096
8290
|
const target = e.target;
|
|
8291
|
+
if (target.closest("[data-ohw-nav-container]")) {
|
|
8292
|
+
const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
8293
|
+
if (related2?.closest("[data-ohw-nav-container], [data-ohw-navbar-container-chrome], [data-ohw-navbar-add-button]")) {
|
|
8294
|
+
return;
|
|
8295
|
+
}
|
|
8296
|
+
hoveredNavContainerRef.current = null;
|
|
8297
|
+
setHoveredNavContainerRect(null);
|
|
8298
|
+
}
|
|
7097
8299
|
const navAnchor = getNavigationItemAnchor(target);
|
|
7098
8300
|
if (navAnchor) {
|
|
7099
8301
|
const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
@@ -7109,7 +8311,7 @@ function OhhwellsBridge() {
|
|
|
7109
8311
|
if (!editable) return;
|
|
7110
8312
|
const related = e.relatedTarget instanceof Element ? e.relatedTarget : null;
|
|
7111
8313
|
if (related?.closest("[data-ohw-drag-handle-container], [data-ohw-item-interaction]")) return;
|
|
7112
|
-
if (editable
|
|
8314
|
+
if (!isMediaEditable(editable)) {
|
|
7113
8315
|
const hoverTarget = editable.closest("[data-ohw-href-key]") ?? editable;
|
|
7114
8316
|
if (hoverTarget.hasAttribute("data-ohw-href-key")) {
|
|
7115
8317
|
if (!related?.closest("[data-ohw-href-key]")) {
|
|
@@ -7155,23 +8357,26 @@ function OhhwellsBridge() {
|
|
|
7155
8357
|
}
|
|
7156
8358
|
return { top, left, width: Math.max(0, right - left), height: Math.max(0, bottom - top) };
|
|
7157
8359
|
};
|
|
7158
|
-
const
|
|
8360
|
+
const showImageHover = (imgEl, isDragOver = false, forceTextOverlap) => {
|
|
7159
8361
|
const r2 = getVisibleRect(imgEl);
|
|
7160
8362
|
const hasTextOverlap = forceTextOverlap ?? false;
|
|
7161
8363
|
hoveredImageHasTextOverlapRef.current = hasTextOverlap;
|
|
7162
|
-
|
|
7163
|
-
|
|
8364
|
+
const video = imgEl.dataset.ohwEditable === "video" ? getVideoEl(imgEl) : null;
|
|
8365
|
+
setMediaHover({
|
|
7164
8366
|
key: imgEl.dataset.ohwKey ?? "",
|
|
7165
8367
|
rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height },
|
|
8368
|
+
elementType: imgEl.dataset.ohwEditable ?? "image",
|
|
7166
8369
|
hasTextOverlap,
|
|
7167
|
-
|
|
8370
|
+
isDragOver,
|
|
8371
|
+
...video ? { videoAutoplay: video.autoplay, videoMuted: video.muted } : {}
|
|
7168
8372
|
});
|
|
7169
8373
|
const track = imgEl.closest("[data-ohw-hover-pause]");
|
|
7170
8374
|
if (track) track.setAttribute("data-ohw-hover-paused", "");
|
|
7171
8375
|
};
|
|
8376
|
+
const clearImageHover = () => setMediaHover(null);
|
|
7172
8377
|
const findImageAtPoint = (clientX, clientY, fromParentViewport) => {
|
|
7173
8378
|
const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
7174
|
-
const images = Array.from(document.querySelectorAll(
|
|
8379
|
+
const images = Array.from(document.querySelectorAll(MEDIA_SELECTOR));
|
|
7175
8380
|
const matches = [];
|
|
7176
8381
|
for (let i = images.length - 1; i >= 0; i--) {
|
|
7177
8382
|
const el = images[i];
|
|
@@ -7187,7 +8392,9 @@ function OhhwellsBridge() {
|
|
|
7187
8392
|
if (x >= r2.left && x <= r2.left + r2.width && y >= r2.top && y <= r2.top + r2.height) matches.push(el);
|
|
7188
8393
|
}
|
|
7189
8394
|
if (matches.length === 0) return null;
|
|
7190
|
-
const imageTypeMatches = matches.filter(
|
|
8395
|
+
const imageTypeMatches = matches.filter(
|
|
8396
|
+
(el) => el.dataset.ohwEditable === "image" || el.dataset.ohwEditable === "video"
|
|
8397
|
+
);
|
|
7191
8398
|
const candidatePool = imageTypeMatches.length > 0 ? imageTypeMatches : matches;
|
|
7192
8399
|
const smallest = candidatePool.reduce((best, el) => {
|
|
7193
8400
|
const br = getVisibleRect(best);
|
|
@@ -7210,47 +8417,91 @@ function OhhwellsBridge() {
|
|
|
7210
8417
|
}
|
|
7211
8418
|
return smallest;
|
|
7212
8419
|
};
|
|
8420
|
+
const dismissImageHover = () => {
|
|
8421
|
+
if (hoveredImageRef.current) {
|
|
8422
|
+
hoveredImageRef.current = null;
|
|
8423
|
+
hoveredImageHasTextOverlapRef.current = false;
|
|
8424
|
+
resumeAnimTracks();
|
|
8425
|
+
postToParentRef.current({ type: "ow:image-unhover" });
|
|
8426
|
+
}
|
|
8427
|
+
clearImageHover();
|
|
8428
|
+
};
|
|
8429
|
+
const probeNavigationHoverAt = (x, y) => {
|
|
8430
|
+
if (toolbarVariantRef.current === "select-frame") {
|
|
8431
|
+
hoveredNavContainerRef.current = null;
|
|
8432
|
+
setHoveredNavContainerRect(null);
|
|
8433
|
+
return;
|
|
8434
|
+
}
|
|
8435
|
+
const navContainer = document.querySelector("[data-ohw-nav-container]");
|
|
8436
|
+
if (!navContainer) {
|
|
8437
|
+
hoveredNavContainerRef.current = null;
|
|
8438
|
+
setHoveredNavContainerRect(null);
|
|
8439
|
+
return;
|
|
8440
|
+
}
|
|
8441
|
+
const containerRect = navContainer.getBoundingClientRect();
|
|
8442
|
+
const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
|
|
8443
|
+
if (!overContainer) {
|
|
8444
|
+
hoveredNavContainerRef.current = null;
|
|
8445
|
+
setHoveredNavContainerRect(null);
|
|
8446
|
+
return;
|
|
8447
|
+
}
|
|
8448
|
+
const navItemHit = Array.from(
|
|
8449
|
+
navContainer.querySelectorAll("[data-ohw-href-key]")
|
|
8450
|
+
).find((el) => {
|
|
8451
|
+
if (!isNavigationItem(el) || isNavbarButton2(el)) return false;
|
|
8452
|
+
const itemRect = el.getBoundingClientRect();
|
|
8453
|
+
return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
|
|
8454
|
+
});
|
|
8455
|
+
if (navItemHit) {
|
|
8456
|
+
hoveredNavContainerRef.current = null;
|
|
8457
|
+
setHoveredNavContainerRect(null);
|
|
8458
|
+
const selected = selectedElRef.current;
|
|
8459
|
+
if (selected !== navItemHit && !selected?.contains(navItemHit)) {
|
|
8460
|
+
clearHrefKeyHover(navItemHit);
|
|
8461
|
+
hoveredItemElRef.current = navItemHit;
|
|
8462
|
+
setHoveredItemRect(navItemHit.getBoundingClientRect());
|
|
8463
|
+
}
|
|
8464
|
+
return;
|
|
8465
|
+
}
|
|
8466
|
+
hoveredNavContainerRef.current = navContainer;
|
|
8467
|
+
setHoveredNavContainerRect(containerRect);
|
|
8468
|
+
hoveredItemElRef.current = null;
|
|
8469
|
+
setHoveredItemRect(null);
|
|
8470
|
+
};
|
|
7213
8471
|
const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
|
|
7214
8472
|
if (linkPopoverOpenRef.current) {
|
|
7215
|
-
|
|
7216
|
-
|
|
7217
|
-
|
|
7218
|
-
|
|
7219
|
-
|
|
7220
|
-
|
|
8473
|
+
dismissImageHover();
|
|
8474
|
+
return;
|
|
8475
|
+
}
|
|
8476
|
+
const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
8477
|
+
if (isPointOverNavigation(x, y)) {
|
|
8478
|
+
dismissImageHover();
|
|
8479
|
+
probeNavigationHoverAt(x, y);
|
|
7221
8480
|
return;
|
|
7222
8481
|
}
|
|
8482
|
+
hoveredNavContainerRef.current = null;
|
|
8483
|
+
setHoveredNavContainerRect(null);
|
|
7223
8484
|
const toggleEl = document.querySelector("[data-ohw-state-toggle]");
|
|
7224
8485
|
if (toggleEl) {
|
|
7225
|
-
const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
7226
8486
|
const tr = toggleEl.getBoundingClientRect();
|
|
7227
8487
|
if (x >= tr.left && x <= tr.right && y >= tr.top && y <= tr.bottom) {
|
|
7228
|
-
|
|
7229
|
-
hoveredImageRef.current = null;
|
|
7230
|
-
resumeAnimTracks();
|
|
7231
|
-
postToParentRef.current({ type: "ow:image-unhover" });
|
|
7232
|
-
}
|
|
8488
|
+
dismissImageHover();
|
|
7233
8489
|
return;
|
|
7234
8490
|
}
|
|
7235
8491
|
}
|
|
7236
|
-
|
|
7237
|
-
|
|
7238
|
-
|
|
7239
|
-
|
|
7240
|
-
resumeAnimTracks();
|
|
7241
|
-
postToParentRef.current({ type: "ow:image-unhover" });
|
|
7242
|
-
}
|
|
8492
|
+
const imgEl = findImageAtPoint(clientX, clientY, fromParentViewport);
|
|
8493
|
+
const activeEl = activeElRef.current;
|
|
8494
|
+
if (activeEl && (!imgEl || imgEl.contains(activeEl))) {
|
|
8495
|
+
dismissImageHover();
|
|
7243
8496
|
return;
|
|
7244
8497
|
}
|
|
7245
|
-
const imgEl = findImageAtPoint(clientX, clientY, fromParentViewport);
|
|
7246
8498
|
if (imgEl) {
|
|
7247
|
-
const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
7248
8499
|
const topEl = document.elementFromPoint(x, y);
|
|
7249
8500
|
if (topEl?.closest('[data-ohw-toolbar], [data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
|
|
7250
8501
|
if (hoveredImageRef.current) {
|
|
7251
8502
|
hoveredImageRef.current = null;
|
|
7252
8503
|
resumeAnimTracks();
|
|
7253
|
-
|
|
8504
|
+
clearImageHover();
|
|
7254
8505
|
}
|
|
7255
8506
|
return;
|
|
7256
8507
|
}
|
|
@@ -7259,13 +8510,13 @@ function OhhwellsBridge() {
|
|
|
7259
8510
|
hoveredImageRef.current = null;
|
|
7260
8511
|
hoveredImageHasTextOverlapRef.current = false;
|
|
7261
8512
|
resumeAnimTracks();
|
|
7262
|
-
|
|
8513
|
+
clearImageHover();
|
|
7263
8514
|
}
|
|
7264
8515
|
return;
|
|
7265
8516
|
}
|
|
7266
8517
|
const isStateCardImage = !!imgEl.closest("[data-ohw-editable-state]");
|
|
7267
8518
|
const textEditable = Array.from(
|
|
7268
|
-
document.querySelectorAll(
|
|
8519
|
+
document.querySelectorAll(NON_MEDIA_SELECTOR)
|
|
7269
8520
|
).find((el) => {
|
|
7270
8521
|
const er = el.getBoundingClientRect();
|
|
7271
8522
|
return x >= er.left && x <= er.right && y >= er.top && y <= er.bottom;
|
|
@@ -7284,14 +8535,14 @@ function OhhwellsBridge() {
|
|
|
7284
8535
|
hoveredImageRef.current = null;
|
|
7285
8536
|
hoveredImageHasTextOverlapRef.current = false;
|
|
7286
8537
|
resumeAnimTracks();
|
|
7287
|
-
|
|
8538
|
+
clearImageHover();
|
|
7288
8539
|
}
|
|
7289
8540
|
return;
|
|
7290
8541
|
}
|
|
7291
8542
|
if (isStateCardImage) {
|
|
7292
8543
|
if (imgEl !== hoveredImageRef.current || !hoveredImageHasTextOverlapRef.current) {
|
|
7293
8544
|
hoveredImageRef.current = imgEl;
|
|
7294
|
-
|
|
8545
|
+
showImageHover(imgEl, isDragOver, true);
|
|
7295
8546
|
}
|
|
7296
8547
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
7297
8548
|
if (textEditable && !isInsideNavigationItem(textEditable)) {
|
|
@@ -7303,7 +8554,7 @@ function OhhwellsBridge() {
|
|
|
7303
8554
|
hoveredImageRef.current = null;
|
|
7304
8555
|
hoveredImageHasTextOverlapRef.current = false;
|
|
7305
8556
|
resumeAnimTracks();
|
|
7306
|
-
|
|
8557
|
+
clearImageHover();
|
|
7307
8558
|
}
|
|
7308
8559
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
7309
8560
|
if (textEditable && !isInsideNavigationItem(textEditable)) {
|
|
@@ -7315,7 +8566,7 @@ function OhhwellsBridge() {
|
|
|
7315
8566
|
if (hoveredImageRef.current) {
|
|
7316
8567
|
hoveredImageRef.current = null;
|
|
7317
8568
|
resumeAnimTracks();
|
|
7318
|
-
|
|
8569
|
+
clearImageHover();
|
|
7319
8570
|
}
|
|
7320
8571
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
7321
8572
|
return;
|
|
@@ -7323,9 +8574,9 @@ function OhhwellsBridge() {
|
|
|
7323
8574
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
7324
8575
|
if (imgEl !== hoveredImageRef.current || hoveredImageHasTextOverlapRef.current) {
|
|
7325
8576
|
hoveredImageRef.current = imgEl;
|
|
7326
|
-
|
|
8577
|
+
showImageHover(imgEl, isDragOver);
|
|
7327
8578
|
} else if (isDragOver) {
|
|
7328
|
-
|
|
8579
|
+
showImageHover(imgEl, true);
|
|
7329
8580
|
}
|
|
7330
8581
|
} else {
|
|
7331
8582
|
const inIframeView = clientX >= 0 && clientY >= 0 && clientX <= window.innerWidth && clientY <= window.innerHeight;
|
|
@@ -7342,14 +8593,14 @@ function OhhwellsBridge() {
|
|
|
7342
8593
|
hoveredImageRef.current = null;
|
|
7343
8594
|
hoveredImageHasTextOverlapRef.current = false;
|
|
7344
8595
|
resumeAnimTracks();
|
|
7345
|
-
|
|
8596
|
+
clearImageHover();
|
|
7346
8597
|
}
|
|
7347
|
-
const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
8598
|
+
const { x: x2, y: y2 } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
7348
8599
|
const textEl = Array.from(
|
|
7349
|
-
document.querySelectorAll(
|
|
8600
|
+
document.querySelectorAll(NON_MEDIA_SELECTOR)
|
|
7350
8601
|
).find((el) => {
|
|
7351
8602
|
const er = el.getBoundingClientRect();
|
|
7352
|
-
return
|
|
8603
|
+
return x2 >= er.left && x2 <= er.right && y2 >= er.top && y2 <= er.bottom;
|
|
7353
8604
|
});
|
|
7354
8605
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
7355
8606
|
if (textEl && !textEl.hasAttribute("contenteditable")) {
|
|
@@ -7452,18 +8703,20 @@ function OhhwellsBridge() {
|
|
|
7452
8703
|
return;
|
|
7453
8704
|
}
|
|
7454
8705
|
e.dataTransfer.dropEffect = "copy";
|
|
7455
|
-
if (
|
|
8706
|
+
if (dragOverElRef.current !== el) {
|
|
8707
|
+
dragOverElRef.current = el;
|
|
7456
8708
|
hoveredImageRef.current = el;
|
|
7457
8709
|
const isStateCard = !!el.closest("[data-ohw-editable-state]");
|
|
7458
|
-
|
|
8710
|
+
showImageHover(el, true, isStateCard ? true : void 0);
|
|
7459
8711
|
}
|
|
7460
8712
|
};
|
|
7461
8713
|
const handleDragLeave = (e) => {
|
|
7462
8714
|
const imgEl = findImageAtPoint(e.clientX, e.clientY, false);
|
|
7463
8715
|
if (imgEl) return;
|
|
8716
|
+
dragOverElRef.current = null;
|
|
7464
8717
|
hoveredImageRef.current = null;
|
|
7465
8718
|
resumeAnimTracks();
|
|
7466
|
-
|
|
8719
|
+
clearImageHover();
|
|
7467
8720
|
};
|
|
7468
8721
|
const handleDrop = (e) => {
|
|
7469
8722
|
e.preventDefault();
|
|
@@ -7471,7 +8724,9 @@ function OhhwellsBridge() {
|
|
|
7471
8724
|
if (!el) return;
|
|
7472
8725
|
const file = e.dataTransfer?.files?.[0];
|
|
7473
8726
|
if (file) {
|
|
7474
|
-
|
|
8727
|
+
const wantsVideo = el.dataset.ohwEditable === "video";
|
|
8728
|
+
const accepted = wantsVideo ? file.type.startsWith("video/") : file.type.startsWith("image/");
|
|
8729
|
+
if (accepted) {
|
|
7475
8730
|
const key = el.dataset.ohwKey ?? "";
|
|
7476
8731
|
const { name, type: mimeType } = file;
|
|
7477
8732
|
const r2 = el.getBoundingClientRect();
|
|
@@ -7480,12 +8735,13 @@ function OhhwellsBridge() {
|
|
|
7480
8735
|
window.parent.postMessage({ type: "ow:image-drop", key, name, mimeType, buf, rect }, "*", [buf]);
|
|
7481
8736
|
});
|
|
7482
8737
|
} else {
|
|
7483
|
-
postToParentRef.current({ type: "ow:image-drop-invalid" });
|
|
8738
|
+
postToParentRef.current({ type: "ow:image-drop-invalid", expected: wantsVideo ? "video" : "image" });
|
|
7484
8739
|
}
|
|
7485
8740
|
}
|
|
8741
|
+
dragOverElRef.current = null;
|
|
7486
8742
|
hoveredImageRef.current = null;
|
|
7487
8743
|
resumeAnimTracks();
|
|
7488
|
-
|
|
8744
|
+
clearImageHover();
|
|
7489
8745
|
};
|
|
7490
8746
|
const handleImageUrl = (e) => {
|
|
7491
8747
|
if (e.data?.type !== "ow:image-url") return;
|
|
@@ -7503,7 +8759,11 @@ function OhhwellsBridge() {
|
|
|
7503
8759
|
}
|
|
7504
8760
|
});
|
|
7505
8761
|
hoveredImageRef.current = null;
|
|
7506
|
-
|
|
8762
|
+
setUploadingRects((prev) => {
|
|
8763
|
+
const entry = prev[key];
|
|
8764
|
+
if (!entry || entry.fadingOut) return prev;
|
|
8765
|
+
return { ...prev, [key]: { ...entry, fadingOut: true } };
|
|
8766
|
+
});
|
|
7507
8767
|
};
|
|
7508
8768
|
let found = false;
|
|
7509
8769
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -7538,6 +8798,19 @@ function OhhwellsBridge() {
|
|
|
7538
8798
|
requestAnimationFrame(() => onReady());
|
|
7539
8799
|
}
|
|
7540
8800
|
}
|
|
8801
|
+
} else if (el.dataset.ohwEditable === "video") {
|
|
8802
|
+
const video = getVideoEl(el);
|
|
8803
|
+
if (video) {
|
|
8804
|
+
found = true;
|
|
8805
|
+
const onReady = () => {
|
|
8806
|
+
video.onloadeddata = null;
|
|
8807
|
+
video.onerror = null;
|
|
8808
|
+
notify();
|
|
8809
|
+
};
|
|
8810
|
+
video.onloadeddata = onReady;
|
|
8811
|
+
video.onerror = onReady;
|
|
8812
|
+
applyVideoSrc(video, url);
|
|
8813
|
+
}
|
|
7541
8814
|
}
|
|
7542
8815
|
});
|
|
7543
8816
|
if (!found) notify();
|
|
@@ -7604,12 +8877,16 @@ function OhhwellsBridge() {
|
|
|
7604
8877
|
sectionsJson = val;
|
|
7605
8878
|
continue;
|
|
7606
8879
|
}
|
|
8880
|
+
if (applyVideoSettingNode(key, val)) continue;
|
|
7607
8881
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
7608
8882
|
if (el.dataset.ohwEditable === "image") {
|
|
7609
8883
|
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
7610
8884
|
if (img) applyEditableImageSrc(img, val);
|
|
7611
8885
|
} else if (el.dataset.ohwEditable === "bg-image") {
|
|
7612
8886
|
el.style.backgroundImage = `url('${val}')`;
|
|
8887
|
+
} else if (el.dataset.ohwEditable === "video") {
|
|
8888
|
+
const video = getVideoEl(el);
|
|
8889
|
+
if (video && video.src !== val) applyVideoSrc(video, val);
|
|
7613
8890
|
} else if (el.dataset.ohwEditable === "link") {
|
|
7614
8891
|
applyLinkHref(el, val);
|
|
7615
8892
|
} else {
|
|
@@ -7623,6 +8900,8 @@ function OhhwellsBridge() {
|
|
|
7623
8900
|
sectionsLoadedRef.current = true;
|
|
7624
8901
|
pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
|
|
7625
8902
|
}
|
|
8903
|
+
editContentRef.current = { ...editContentRef.current, ...content };
|
|
8904
|
+
reconcileNavbarItemsFromContent(editContentRef.current);
|
|
7626
8905
|
enforceLinkHrefs();
|
|
7627
8906
|
postToParentRef.current({ type: "ow:hydrate-done" });
|
|
7628
8907
|
};
|
|
@@ -7630,6 +8909,7 @@ function OhhwellsBridge() {
|
|
|
7630
8909
|
const handleDeactivate = (e) => {
|
|
7631
8910
|
if (e.data?.type !== "ow:deactivate") return;
|
|
7632
8911
|
if (Date.now() < linkPopoverGraceUntilRef.current) return;
|
|
8912
|
+
if (document.querySelector("[data-ohw-section-picker]")) return;
|
|
7633
8913
|
if (linkPopoverOpenRef.current) {
|
|
7634
8914
|
setLinkPopoverRef.current(null);
|
|
7635
8915
|
return;
|
|
@@ -7639,12 +8919,32 @@ function OhhwellsBridge() {
|
|
|
7639
8919
|
};
|
|
7640
8920
|
window.addEventListener("message", handleDeactivate);
|
|
7641
8921
|
const handleKeyDown = (e) => {
|
|
8922
|
+
if (e.key === "Escape" && document.querySelector("[data-ohw-section-picker]")) return;
|
|
8923
|
+
if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a" && activeElRef.current) {
|
|
8924
|
+
const navAnchor = getNavigationItemAnchor(activeElRef.current);
|
|
8925
|
+
if (navAnchor) {
|
|
8926
|
+
e.preventDefault();
|
|
8927
|
+
selectAllTextInEditable(activeElRef.current);
|
|
8928
|
+
refreshActiveCommandsRef.current();
|
|
8929
|
+
return;
|
|
8930
|
+
}
|
|
8931
|
+
}
|
|
7642
8932
|
if (e.key === "Escape" && linkPopoverOpenRef.current) {
|
|
7643
8933
|
setLinkPopoverRef.current(null);
|
|
7644
8934
|
return;
|
|
7645
8935
|
}
|
|
7646
8936
|
if (e.key === "Escape" && selectedElRef.current && !activeElRef.current) {
|
|
7647
|
-
|
|
8937
|
+
if (toolbarVariantRef.current === "select-frame") {
|
|
8938
|
+
deselectRef.current();
|
|
8939
|
+
return;
|
|
8940
|
+
}
|
|
8941
|
+
const parent = getNavigationSelectionParent(selectedElRef.current);
|
|
8942
|
+
if (parent) {
|
|
8943
|
+
e.preventDefault();
|
|
8944
|
+
selectFrameRef.current(parent);
|
|
8945
|
+
} else {
|
|
8946
|
+
deselectRef.current();
|
|
8947
|
+
}
|
|
7648
8948
|
return;
|
|
7649
8949
|
}
|
|
7650
8950
|
if (e.key === "Escape" && activeElRef.current) {
|
|
@@ -7702,18 +9002,18 @@ function OhhwellsBridge() {
|
|
|
7702
9002
|
if (hoveredItemElRef.current) {
|
|
7703
9003
|
setHoveredItemRect(hoveredItemElRef.current.getBoundingClientRect());
|
|
7704
9004
|
}
|
|
9005
|
+
if (hoveredNavContainerRef.current) {
|
|
9006
|
+
setHoveredNavContainerRect(hoveredNavContainerRef.current.getBoundingClientRect());
|
|
9007
|
+
}
|
|
7705
9008
|
if (siblingHintElRef.current) {
|
|
7706
9009
|
setSiblingHintRect(siblingHintElRef.current.getBoundingClientRect());
|
|
7707
9010
|
}
|
|
7708
9011
|
if (hoveredImageRef.current) {
|
|
7709
9012
|
const el = hoveredImageRef.current;
|
|
7710
9013
|
const r2 = el.getBoundingClientRect();
|
|
7711
|
-
|
|
7712
|
-
|
|
7713
|
-
|
|
7714
|
-
rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height },
|
|
7715
|
-
hasTextOverlap: hoveredImageHasTextOverlapRef.current
|
|
7716
|
-
});
|
|
9014
|
+
setMediaHover(
|
|
9015
|
+
(prev) => prev ? { ...prev, rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height } } : prev
|
|
9016
|
+
);
|
|
7717
9017
|
}
|
|
7718
9018
|
};
|
|
7719
9019
|
const handleSave = (e) => {
|
|
@@ -7802,19 +9102,39 @@ function OhhwellsBridge() {
|
|
|
7802
9102
|
refreshActiveCommandsRef.current = handleSelectionChange;
|
|
7803
9103
|
const handleDocMouseLeave = () => {
|
|
7804
9104
|
hoveredImageRef.current = null;
|
|
9105
|
+
setMediaHover(null);
|
|
7805
9106
|
document.querySelectorAll("[data-ohw-state-hovered]").forEach((el) => el.removeAttribute("data-ohw-state-hovered"));
|
|
7806
9107
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
7807
9108
|
activeStateElRef.current = null;
|
|
7808
9109
|
setToggleState(null);
|
|
7809
9110
|
};
|
|
7810
|
-
const
|
|
7811
|
-
if (e.data?.type !== "ow:
|
|
7812
|
-
const { key } = e.data;
|
|
9111
|
+
const handleImageUploading = (e) => {
|
|
9112
|
+
if (e.data?.type !== "ow:image-uploading") return;
|
|
9113
|
+
const { key, uploading } = e.data;
|
|
9114
|
+
setUploadingRects((prev) => {
|
|
9115
|
+
if (!uploading) {
|
|
9116
|
+
if (!(key in prev)) return prev;
|
|
9117
|
+
const next = { ...prev };
|
|
9118
|
+
delete next[key];
|
|
9119
|
+
return next;
|
|
9120
|
+
}
|
|
9121
|
+
const el = document.querySelector(`[data-ohw-key="${key}"]`);
|
|
9122
|
+
if (!el) return prev;
|
|
9123
|
+
const r2 = getVisibleRect(el);
|
|
9124
|
+
return {
|
|
9125
|
+
...prev,
|
|
9126
|
+
[key]: { rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height } }
|
|
9127
|
+
};
|
|
9128
|
+
});
|
|
7813
9129
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
7814
9130
|
const track = el.closest("[data-ohw-hover-pause]");
|
|
7815
|
-
if (track)
|
|
9131
|
+
if (!track) return;
|
|
9132
|
+
if (uploading) {
|
|
7816
9133
|
uploadLockedTracks.add(track);
|
|
7817
9134
|
track.setAttribute("data-ohw-hover-paused", "");
|
|
9135
|
+
} else {
|
|
9136
|
+
uploadLockedTracks.delete(track);
|
|
9137
|
+
track.removeAttribute("data-ohw-hover-paused");
|
|
7818
9138
|
}
|
|
7819
9139
|
});
|
|
7820
9140
|
};
|
|
@@ -7856,7 +9176,7 @@ function OhhwellsBridge() {
|
|
|
7856
9176
|
if (e.data?.type !== "ow:click-at") return;
|
|
7857
9177
|
const { clientX, clientY } = e.data;
|
|
7858
9178
|
const allImages = Array.from(
|
|
7859
|
-
document.querySelectorAll(
|
|
9179
|
+
document.querySelectorAll(MEDIA_SELECTOR)
|
|
7860
9180
|
).filter((el) => !!el.closest("[data-ohw-editable-state]"));
|
|
7861
9181
|
const stateCardImage = allImages.find((el) => {
|
|
7862
9182
|
const ownerCard = el.closest("[data-ohw-editable-state]");
|
|
@@ -7871,21 +9191,55 @@ function OhhwellsBridge() {
|
|
|
7871
9191
|
return clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom;
|
|
7872
9192
|
});
|
|
7873
9193
|
if (stateCardImage) {
|
|
7874
|
-
postToParentRef.current({ type: "ow:image-pick", key: stateCardImage.dataset.ohwKey ?? "" });
|
|
9194
|
+
postToParentRef.current({ type: "ow:image-pick", key: stateCardImage.dataset.ohwKey ?? "", elementType: stateCardImage.dataset.ohwEditable ?? "image" });
|
|
7875
9195
|
return;
|
|
7876
9196
|
}
|
|
7877
9197
|
const textEditable = Array.from(
|
|
7878
|
-
document.querySelectorAll(
|
|
7879
|
-
'[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"])'
|
|
7880
|
-
)
|
|
9198
|
+
document.querySelectorAll(NON_MEDIA_SELECTOR)
|
|
7881
9199
|
).find((el) => {
|
|
7882
9200
|
const r2 = el.getBoundingClientRect();
|
|
7883
9201
|
return clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom;
|
|
7884
9202
|
});
|
|
7885
9203
|
if (textEditable) {
|
|
7886
|
-
|
|
9204
|
+
const hrefCtx = getHrefKeyFromElement(textEditable);
|
|
9205
|
+
const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
|
|
9206
|
+
if (navAnchor) {
|
|
9207
|
+
if (selectedElRef.current === navAnchor) {
|
|
9208
|
+
activateRef.current(textEditable, { caretX: clientX, caretY: clientY });
|
|
9209
|
+
} else {
|
|
9210
|
+
selectRef.current(navAnchor);
|
|
9211
|
+
}
|
|
9212
|
+
return;
|
|
9213
|
+
}
|
|
9214
|
+
activateRef.current(textEditable, { caretX: clientX, caretY: clientY });
|
|
7887
9215
|
return;
|
|
7888
9216
|
}
|
|
9217
|
+
const navContainer = document.querySelector("[data-ohw-nav-container]");
|
|
9218
|
+
if (navContainer) {
|
|
9219
|
+
const r2 = navContainer.getBoundingClientRect();
|
|
9220
|
+
const pad = 8;
|
|
9221
|
+
const over = clientX >= r2.left - pad && clientX <= r2.right + pad && clientY >= r2.top - pad && clientY <= r2.bottom + pad;
|
|
9222
|
+
if (over && !isPointOverNavItem(navContainer, clientX, clientY)) {
|
|
9223
|
+
selectFrameRef.current(navContainer);
|
|
9224
|
+
return;
|
|
9225
|
+
}
|
|
9226
|
+
}
|
|
9227
|
+
const navRoot = document.querySelector("[data-ohw-nav-root]");
|
|
9228
|
+
if (navRoot && navContainer) {
|
|
9229
|
+
const rr = navRoot.getBoundingClientRect();
|
|
9230
|
+
if (clientX >= rr.left && clientX <= rr.right && clientY >= rr.top && clientY <= rr.bottom && !isPointOverNavItem(navContainer, clientX, clientY)) {
|
|
9231
|
+
const book = navRoot.querySelector('[data-ohw-role="navbar-button"]');
|
|
9232
|
+
if (book) {
|
|
9233
|
+
const br = book.getBoundingClientRect();
|
|
9234
|
+
if (clientX >= br.left && clientX <= br.right && clientY >= br.top && clientY <= br.bottom) {
|
|
9235
|
+
deactivateRef.current();
|
|
9236
|
+
return;
|
|
9237
|
+
}
|
|
9238
|
+
}
|
|
9239
|
+
selectFrameRef.current(navContainer);
|
|
9240
|
+
return;
|
|
9241
|
+
}
|
|
9242
|
+
}
|
|
7889
9243
|
deactivateRef.current();
|
|
7890
9244
|
};
|
|
7891
9245
|
window.addEventListener("message", handleSave);
|
|
@@ -7895,7 +9249,7 @@ function OhhwellsBridge() {
|
|
|
7895
9249
|
window.addEventListener("message", handleClearSchedulingWidget);
|
|
7896
9250
|
window.addEventListener("message", handleRemoveSchedulingSection);
|
|
7897
9251
|
window.addEventListener("message", handleImageUrl);
|
|
7898
|
-
window.addEventListener("message",
|
|
9252
|
+
window.addEventListener("message", handleImageUploading);
|
|
7899
9253
|
window.addEventListener("message", handleCanvasHeight);
|
|
7900
9254
|
window.addEventListener("message", handleParentScroll);
|
|
7901
9255
|
window.addEventListener("message", handlePointerSync);
|
|
@@ -7907,6 +9261,7 @@ function OhhwellsBridge() {
|
|
|
7907
9261
|
};
|
|
7908
9262
|
window.addEventListener("resize", handleViewportResize, { passive: true });
|
|
7909
9263
|
document.addEventListener("click", handleClick, true);
|
|
9264
|
+
document.addEventListener("dblclick", handleDblClick, true);
|
|
7910
9265
|
document.addEventListener("paste", handlePaste, true);
|
|
7911
9266
|
document.addEventListener("input", handleInput, true);
|
|
7912
9267
|
document.addEventListener("mouseover", handleMouseOver, true);
|
|
@@ -7921,6 +9276,7 @@ function OhhwellsBridge() {
|
|
|
7921
9276
|
window.addEventListener("scroll", handleScroll, true);
|
|
7922
9277
|
return () => {
|
|
7923
9278
|
document.removeEventListener("click", handleClick, true);
|
|
9279
|
+
document.removeEventListener("dblclick", handleDblClick, true);
|
|
7924
9280
|
document.removeEventListener("paste", handlePaste, true);
|
|
7925
9281
|
document.removeEventListener("input", handleInput, true);
|
|
7926
9282
|
document.removeEventListener("mouseover", handleMouseOver, true);
|
|
@@ -7940,7 +9296,7 @@ function OhhwellsBridge() {
|
|
|
7940
9296
|
window.removeEventListener("message", handleClearSchedulingWidget);
|
|
7941
9297
|
window.removeEventListener("message", handleRemoveSchedulingSection);
|
|
7942
9298
|
window.removeEventListener("message", handleImageUrl);
|
|
7943
|
-
window.removeEventListener("message",
|
|
9299
|
+
window.removeEventListener("message", handleImageUploading);
|
|
7944
9300
|
window.removeEventListener("message", handleCanvasHeight);
|
|
7945
9301
|
window.removeEventListener("message", handleParentScroll);
|
|
7946
9302
|
window.removeEventListener("resize", handleViewportResize);
|
|
@@ -7954,7 +9310,7 @@ function OhhwellsBridge() {
|
|
|
7954
9310
|
if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
|
|
7955
9311
|
};
|
|
7956
9312
|
}, [isEditMode, refreshStateRules]);
|
|
7957
|
-
(0,
|
|
9313
|
+
(0, import_react8.useEffect)(() => {
|
|
7958
9314
|
const handler = (e) => {
|
|
7959
9315
|
if (e.data?.type !== "ow:request-schedule-config") return;
|
|
7960
9316
|
const insertAfterVal = e.data.insertAfter;
|
|
@@ -7970,7 +9326,7 @@ function OhhwellsBridge() {
|
|
|
7970
9326
|
window.addEventListener("message", handler);
|
|
7971
9327
|
return () => window.removeEventListener("message", handler);
|
|
7972
9328
|
}, [processConfigRequest]);
|
|
7973
|
-
(0,
|
|
9329
|
+
(0, import_react8.useEffect)(() => {
|
|
7974
9330
|
if (!isEditMode) return;
|
|
7975
9331
|
document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
|
|
7976
9332
|
el.removeAttribute("data-ohw-active-state");
|
|
@@ -7991,27 +9347,27 @@ function OhhwellsBridge() {
|
|
|
7991
9347
|
const next = { ...prev, [pathKey]: sections };
|
|
7992
9348
|
return shouldUseDevFixtures() ? { ...DEV_SECTIONS_BY_PATH, ...next } : next;
|
|
7993
9349
|
});
|
|
7994
|
-
|
|
7995
|
-
|
|
9350
|
+
postToParent2({ type: "ow:ready", version: "1", path: pathname, nodes: collectEditableNodes(), sections });
|
|
9351
|
+
postToParent2({ type: "ow:request-site-pages" });
|
|
7996
9352
|
}, 150);
|
|
7997
9353
|
return () => {
|
|
7998
9354
|
cancelAnimationFrame(raf);
|
|
7999
9355
|
clearTimeout(timer);
|
|
8000
9356
|
};
|
|
8001
|
-
}, [pathname, isEditMode, refreshStateRules,
|
|
8002
|
-
(0,
|
|
9357
|
+
}, [pathname, isEditMode, refreshStateRules, postToParent2]);
|
|
9358
|
+
(0, import_react8.useEffect)(() => {
|
|
8003
9359
|
scrollToHashSectionWhenReady();
|
|
8004
9360
|
const onHashChange = () => scrollToHashSectionWhenReady();
|
|
8005
9361
|
window.addEventListener("hashchange", onHashChange);
|
|
8006
9362
|
return () => window.removeEventListener("hashchange", onHashChange);
|
|
8007
9363
|
}, [pathname]);
|
|
8008
|
-
const handleCommand = (0,
|
|
9364
|
+
const handleCommand = (0, import_react8.useCallback)((cmd) => {
|
|
8009
9365
|
document.execCommand(cmd, false);
|
|
8010
9366
|
activeElRef.current?.focus();
|
|
8011
9367
|
if (activeElRef.current) setToolbarRect(getEditMeasureEl(activeElRef.current).getBoundingClientRect());
|
|
8012
9368
|
refreshActiveCommandsRef.current();
|
|
8013
9369
|
}, []);
|
|
8014
|
-
const handleStateChange = (0,
|
|
9370
|
+
const handleStateChange = (0, import_react8.useCallback)((state) => {
|
|
8015
9371
|
if (!activeStateElRef.current) return;
|
|
8016
9372
|
const el = activeStateElRef.current;
|
|
8017
9373
|
if (state === "Default") {
|
|
@@ -8024,18 +9380,22 @@ function OhhwellsBridge() {
|
|
|
8024
9380
|
}
|
|
8025
9381
|
setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
|
|
8026
9382
|
}, [deactivate]);
|
|
8027
|
-
const closeLinkPopover = (0,
|
|
8028
|
-
|
|
9383
|
+
const closeLinkPopover = (0, import_react8.useCallback)(() => {
|
|
9384
|
+
addNavAfterAnchorRef.current = null;
|
|
9385
|
+
setLinkPopover(null);
|
|
9386
|
+
}, []);
|
|
9387
|
+
const openLinkPopoverForActive = (0, import_react8.useCallback)(() => {
|
|
8029
9388
|
const hrefCtx = getHrefKeyFromElement(activeElRef.current);
|
|
8030
9389
|
if (!hrefCtx) return;
|
|
8031
9390
|
bumpLinkPopoverGrace();
|
|
8032
9391
|
setLinkPopover({
|
|
8033
9392
|
key: hrefCtx.key,
|
|
8034
|
-
|
|
9393
|
+
mode: "edit",
|
|
9394
|
+
target: getLinkHref2(hrefCtx.anchor)
|
|
8035
9395
|
});
|
|
8036
9396
|
deactivate();
|
|
8037
9397
|
}, [deactivate]);
|
|
8038
|
-
const openLinkPopoverForSelected = (0,
|
|
9398
|
+
const openLinkPopoverForSelected = (0, import_react8.useCallback)(() => {
|
|
8039
9399
|
const anchor = selectedElRef.current;
|
|
8040
9400
|
if (!anchor) return;
|
|
8041
9401
|
const key = anchor.getAttribute("data-ohw-href-key");
|
|
@@ -8043,51 +9403,156 @@ function OhhwellsBridge() {
|
|
|
8043
9403
|
bumpLinkPopoverGrace();
|
|
8044
9404
|
setLinkPopover({
|
|
8045
9405
|
key,
|
|
8046
|
-
|
|
9406
|
+
mode: "edit",
|
|
9407
|
+
target: getLinkHref2(anchor)
|
|
8047
9408
|
});
|
|
8048
9409
|
deselect();
|
|
8049
9410
|
}, [deselect]);
|
|
8050
|
-
const handleLinkPopoverSubmit = (0,
|
|
9411
|
+
const handleLinkPopoverSubmit = (0, import_react8.useCallback)(
|
|
8051
9412
|
(target) => {
|
|
8052
|
-
|
|
8053
|
-
|
|
9413
|
+
const session = linkPopoverSessionRef.current;
|
|
9414
|
+
if (!session) return;
|
|
9415
|
+
if (session.intent === "add-nav") {
|
|
9416
|
+
const { pageRoute, sectionId } = parseTarget(target);
|
|
9417
|
+
const page = resolvePage(pageRoute, sitePages);
|
|
9418
|
+
const pageSections = getSectionsForPath(sectionsByPath, pageRoute);
|
|
9419
|
+
const section = sectionId ? pageSections.find((s) => s.id === sectionId) : void 0;
|
|
9420
|
+
const label = section?.label ?? page.title;
|
|
9421
|
+
const afterAnchor = addNavAfterAnchorRef.current;
|
|
9422
|
+
const { anchor, hrefKey, labelKey, index, order } = insertNavbarItem(target, label, afterAnchor);
|
|
9423
|
+
applyLinkByKey(hrefKey, target);
|
|
9424
|
+
document.querySelectorAll(`[data-ohw-key="${labelKey}"]`).forEach((el) => {
|
|
9425
|
+
el.textContent = label;
|
|
9426
|
+
});
|
|
9427
|
+
const navCount = String(index + 1);
|
|
9428
|
+
const orderJson = JSON.stringify(order);
|
|
9429
|
+
editContentRef.current = {
|
|
9430
|
+
...editContentRef.current,
|
|
9431
|
+
[hrefKey]: target,
|
|
9432
|
+
[labelKey]: label,
|
|
9433
|
+
[NAV_COUNT_KEY]: navCount,
|
|
9434
|
+
[NAV_ORDER_KEY]: orderJson
|
|
9435
|
+
};
|
|
9436
|
+
postToParent2({
|
|
9437
|
+
type: "ow:change",
|
|
9438
|
+
nodes: [
|
|
9439
|
+
{ key: hrefKey, text: target },
|
|
9440
|
+
{ key: labelKey, text: label },
|
|
9441
|
+
{ key: NAV_COUNT_KEY, text: navCount },
|
|
9442
|
+
{ key: NAV_ORDER_KEY, text: orderJson }
|
|
9443
|
+
]
|
|
9444
|
+
});
|
|
9445
|
+
addNavAfterAnchorRef.current = null;
|
|
9446
|
+
setLinkPopover(null);
|
|
9447
|
+
enforceLinkHrefs();
|
|
9448
|
+
requestAnimationFrame(() => {
|
|
9449
|
+
selectRef.current(anchor);
|
|
9450
|
+
});
|
|
9451
|
+
return;
|
|
9452
|
+
}
|
|
9453
|
+
const { key } = session;
|
|
8054
9454
|
applyLinkByKey(key, target);
|
|
8055
|
-
|
|
9455
|
+
postToParent2({ type: "ow:change", nodes: [{ key, text: target }] });
|
|
8056
9456
|
setLinkPopover(null);
|
|
8057
9457
|
},
|
|
8058
|
-
[
|
|
9458
|
+
[postToParent2, sitePages, sectionsByPath]
|
|
8059
9459
|
);
|
|
8060
9460
|
const showEditLink = toolbarShowEditLink;
|
|
8061
9461
|
const currentSections = sectionsByPath[pathname] ?? [];
|
|
8062
9462
|
linkPopoverOpenRef.current = linkPopover !== null;
|
|
8063
|
-
|
|
8064
|
-
|
|
8065
|
-
|
|
8066
|
-
|
|
8067
|
-
|
|
8068
|
-
|
|
9463
|
+
const handleMediaReplace = (0, import_react8.useCallback)(
|
|
9464
|
+
(key) => {
|
|
9465
|
+
postToParent2({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
|
|
9466
|
+
},
|
|
9467
|
+
[postToParent2, mediaHover?.elementType]
|
|
9468
|
+
);
|
|
9469
|
+
const handleMediaFadeOutComplete = (0, import_react8.useCallback)((key) => {
|
|
9470
|
+
setUploadingRects((prev) => {
|
|
9471
|
+
if (!(key in prev)) return prev;
|
|
9472
|
+
const next = { ...prev };
|
|
9473
|
+
delete next[key];
|
|
9474
|
+
return next;
|
|
9475
|
+
});
|
|
9476
|
+
}, []);
|
|
9477
|
+
const handleVideoSettingsChange = (0, import_react8.useCallback)(
|
|
9478
|
+
(key, settings) => {
|
|
9479
|
+
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
9480
|
+
const video = getVideoEl(el);
|
|
9481
|
+
if (!video) return;
|
|
9482
|
+
if (typeof settings.autoplay === "boolean") video.autoplay = settings.autoplay;
|
|
9483
|
+
if (typeof settings.muted === "boolean") video.muted = settings.muted;
|
|
9484
|
+
syncVideoPlayback(video);
|
|
9485
|
+
postToParent2({
|
|
9486
|
+
type: "ow:change",
|
|
9487
|
+
nodes: [
|
|
9488
|
+
{ key: `${key}${VIDEO_AUTOPLAY_SUFFIX}`, text: String(video.autoplay) },
|
|
9489
|
+
{ key: `${key}${VIDEO_MUTED_SUFFIX}`, text: String(video.muted) }
|
|
9490
|
+
]
|
|
9491
|
+
});
|
|
9492
|
+
setMediaHover(
|
|
9493
|
+
(prev) => prev && prev.key === key ? { ...prev, videoAutoplay: video.autoplay, videoMuted: video.muted } : prev
|
|
9494
|
+
);
|
|
9495
|
+
});
|
|
9496
|
+
},
|
|
9497
|
+
[postToParent2]
|
|
9498
|
+
);
|
|
9499
|
+
return bridgeRoot ? (0, import_react_dom3.createPortal)(
|
|
9500
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
|
|
9501
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
|
|
9502
|
+
Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
9503
|
+
MediaOverlay,
|
|
9504
|
+
{
|
|
9505
|
+
hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
|
|
9506
|
+
isUploading: true,
|
|
9507
|
+
fadingOut,
|
|
9508
|
+
onFadeOutComplete: handleMediaFadeOutComplete,
|
|
9509
|
+
onReplace: handleMediaReplace
|
|
9510
|
+
},
|
|
9511
|
+
`uploading-${key}`
|
|
9512
|
+
)),
|
|
9513
|
+
mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
9514
|
+
MediaOverlay,
|
|
9515
|
+
{
|
|
9516
|
+
hover: mediaHover,
|
|
9517
|
+
isUploading: false,
|
|
9518
|
+
onReplace: handleMediaReplace,
|
|
9519
|
+
onVideoSettingsChange: handleVideoSettingsChange
|
|
9520
|
+
}
|
|
9521
|
+
),
|
|
9522
|
+
siblingHintRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
|
|
9523
|
+
hoveredNavContainerRect && toolbarVariant !== "select-frame" && !linkPopover && !isItemDragging && !siblingHintRect && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
|
|
9524
|
+
toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
9525
|
+
NavbarContainerChrome,
|
|
9526
|
+
{
|
|
9527
|
+
rect: toolbarRect,
|
|
9528
|
+
onAdd: handleAddTopLevelNavItem
|
|
9529
|
+
}
|
|
9530
|
+
),
|
|
9531
|
+
hoveredItemRect && !hoveredNavContainerRect && !siblingHintRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
|
|
9532
|
+
toolbarRect && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
8069
9533
|
ItemInteractionLayer,
|
|
8070
9534
|
{
|
|
8071
9535
|
rect: toolbarRect,
|
|
8072
9536
|
elRef: glowElRef,
|
|
8073
9537
|
state: isItemDragging ? "dragging" : resolveItemInteractionState(toolbarRect, parentScrollRef.current),
|
|
8074
|
-
showHandle: Boolean(reorderHrefKey),
|
|
9538
|
+
showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey),
|
|
8075
9539
|
dragDisabled: reorderDragDisabled,
|
|
8076
9540
|
dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
|
|
8077
9541
|
onDragHandleDragStart: handleItemDragStart,
|
|
8078
9542
|
onDragHandleDragEnd: handleItemDragEnd,
|
|
8079
|
-
toolbar:
|
|
9543
|
+
toolbar: toolbarVariant === "link-action" && !isItemDragging ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
8080
9544
|
ItemActionToolbar,
|
|
8081
9545
|
{
|
|
8082
9546
|
onEditLink: openLinkPopoverForSelected,
|
|
8083
|
-
|
|
8084
|
-
|
|
9547
|
+
addItemDisabled: true,
|
|
9548
|
+
editLinkDisabled: false,
|
|
9549
|
+
moreDisabled: true
|
|
8085
9550
|
}
|
|
8086
|
-
)
|
|
9551
|
+
) : void 0
|
|
8087
9552
|
}
|
|
8088
9553
|
),
|
|
8089
|
-
toolbarRect && toolbarVariant === "rich-text" && /* @__PURE__ */ (0,
|
|
8090
|
-
/* @__PURE__ */ (0,
|
|
9554
|
+
toolbarRect && toolbarVariant === "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
|
|
9555
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
8091
9556
|
EditGlowChrome,
|
|
8092
9557
|
{
|
|
8093
9558
|
rect: toolbarRect,
|
|
@@ -8096,7 +9561,7 @@ function OhhwellsBridge() {
|
|
|
8096
9561
|
dragDisabled: reorderDragDisabled
|
|
8097
9562
|
}
|
|
8098
9563
|
),
|
|
8099
|
-
/* @__PURE__ */ (0,
|
|
9564
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
8100
9565
|
FloatingToolbar,
|
|
8101
9566
|
{
|
|
8102
9567
|
rect: toolbarRect,
|
|
@@ -8109,7 +9574,7 @@ function OhhwellsBridge() {
|
|
|
8109
9574
|
}
|
|
8110
9575
|
)
|
|
8111
9576
|
] }),
|
|
8112
|
-
maxBadge && /* @__PURE__ */ (0,
|
|
9577
|
+
maxBadge && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
8113
9578
|
"div",
|
|
8114
9579
|
{
|
|
8115
9580
|
"data-ohw-max-badge": "",
|
|
@@ -8135,7 +9600,7 @@ function OhhwellsBridge() {
|
|
|
8135
9600
|
]
|
|
8136
9601
|
}
|
|
8137
9602
|
),
|
|
8138
|
-
toggleState && /* @__PURE__ */ (0,
|
|
9603
|
+
toggleState && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
8139
9604
|
StateToggle,
|
|
8140
9605
|
{
|
|
8141
9606
|
rect: toggleState.rect,
|
|
@@ -8144,15 +9609,15 @@ function OhhwellsBridge() {
|
|
|
8144
9609
|
onStateChange: handleStateChange
|
|
8145
9610
|
}
|
|
8146
9611
|
),
|
|
8147
|
-
sectionGap && /* @__PURE__ */ (0,
|
|
9612
|
+
sectionGap && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
8148
9613
|
"div",
|
|
8149
9614
|
{
|
|
8150
9615
|
"data-ohw-section-insert-line": "",
|
|
8151
9616
|
className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
|
|
8152
9617
|
style: { top: sectionGap.y, transform: "translateY(-50%)" },
|
|
8153
9618
|
children: [
|
|
8154
|
-
/* @__PURE__ */ (0,
|
|
8155
|
-
/* @__PURE__ */ (0,
|
|
9619
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
|
|
9620
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
8156
9621
|
Badge,
|
|
8157
9622
|
{
|
|
8158
9623
|
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",
|
|
@@ -8165,26 +9630,52 @@ function OhhwellsBridge() {
|
|
|
8165
9630
|
children: "Add Section"
|
|
8166
9631
|
}
|
|
8167
9632
|
),
|
|
8168
|
-
/* @__PURE__ */ (0,
|
|
9633
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
|
|
8169
9634
|
]
|
|
8170
9635
|
}
|
|
8171
9636
|
),
|
|
8172
|
-
linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0,
|
|
9637
|
+
linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
8173
9638
|
LinkPopover,
|
|
8174
9639
|
{
|
|
8175
9640
|
panelRef: linkPopoverPanelRef,
|
|
8176
9641
|
portalContainer: dialogPortalContainer,
|
|
8177
9642
|
open: true,
|
|
8178
|
-
mode: "edit",
|
|
9643
|
+
mode: linkPopover.mode ?? "edit",
|
|
8179
9644
|
pages: sitePages,
|
|
8180
9645
|
sections: currentSections,
|
|
8181
9646
|
sectionsByPath,
|
|
8182
9647
|
initialTarget: linkPopover.target,
|
|
9648
|
+
existingTargets: linkPopover.intent === "add-nav" ? getNavbarExistingTargets() : [],
|
|
8183
9649
|
onClose: closeLinkPopover,
|
|
8184
9650
|
onSubmit: handleLinkPopoverSubmit
|
|
8185
9651
|
},
|
|
8186
|
-
|
|
8187
|
-
) : null
|
|
9652
|
+
linkPopover.key
|
|
9653
|
+
) : null,
|
|
9654
|
+
sectionGap && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
9655
|
+
"div",
|
|
9656
|
+
{
|
|
9657
|
+
"data-ohw-section-insert-line": "",
|
|
9658
|
+
className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
|
|
9659
|
+
style: { top: sectionGap.y, transform: "translateY(-50%)" },
|
|
9660
|
+
children: [
|
|
9661
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
|
|
9662
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
9663
|
+
Badge,
|
|
9664
|
+
{
|
|
9665
|
+
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",
|
|
9666
|
+
onClick: () => {
|
|
9667
|
+
window.parent.postMessage(
|
|
9668
|
+
{ type: "ow:add-section", insertAfter: sectionGap.insertAfter, insertBefore: sectionGap.insertBefore },
|
|
9669
|
+
"*"
|
|
9670
|
+
);
|
|
9671
|
+
},
|
|
9672
|
+
children: "Add Section"
|
|
9673
|
+
}
|
|
9674
|
+
),
|
|
9675
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
|
|
9676
|
+
]
|
|
9677
|
+
}
|
|
9678
|
+
)
|
|
8188
9679
|
] }),
|
|
8189
9680
|
bridgeRoot
|
|
8190
9681
|
) : null;
|