@ohhwells/bridge 0.1.38-next.68 → 0.1.38

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/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  // src/OhhwellsBridge.tsx
4
- import React10, { useCallback as useCallback4, useEffect as useEffect8, useLayoutEffect as useLayoutEffect2, useRef as useRef5, useState as useState7 } from "react";
4
+ import React9, { useCallback as useCallback2, useEffect as useEffect4, useLayoutEffect as useLayoutEffect2, useRef as useRef4, useState as useState5 } from "react";
5
5
  import { createRoot } from "react-dom/client";
6
6
  import { flushSync } from "react-dom";
7
7
 
@@ -10,9 +10,6 @@ var linkHrefStore = /* @__PURE__ */ new Map();
10
10
  function setStoredLinkHref(key, href) {
11
11
  linkHrefStore.set(key, href);
12
12
  }
13
- function getStoredLinkHref(key) {
14
- return linkHrefStore.get(key);
15
- }
16
13
  function enforceLinkHrefs() {
17
14
  document.querySelectorAll("[data-ohw-href-key]").forEach((el) => {
18
15
  const key = el.getAttribute("data-ohw-href-key") ?? "";
@@ -48,13 +45,12 @@ function useLinkHrefGuardian(...deps) {
48
45
  }
49
46
 
50
47
  // src/ui/SchedulingWidget.tsx
51
- import { useCallback, useEffect, useId, useMemo, useRef, useState as useState2 } from "react";
48
+ import { useEffect, useId, useMemo, useRef, useState as useState2 } from "react";
52
49
 
53
50
  // src/ui/EmailCaptureModal.tsx
54
51
  import { useState } from "react";
55
52
  import { Dialog } from "radix-ui";
56
53
  import { jsx, jsxs } from "react/jsx-runtime";
57
- var isValidEmail = (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
58
54
  function Spinner() {
59
55
  return /* @__PURE__ */ jsxs(
60
56
  "svg",
@@ -88,17 +84,12 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
88
84
  const [error, setError] = useState(null);
89
85
  const isBook = title === "Confirm your spot";
90
86
  const handleSubmit = async () => {
91
- const trimmed = email.trim();
92
- if (!trimmed) return;
93
- if (!isValidEmail(trimmed)) {
94
- setError("Please enter a valid email address.");
95
- return;
96
- }
87
+ if (!email.trim()) return;
97
88
  setLoading(true);
98
89
  setError(null);
99
90
  try {
100
- await onSubmit(trimmed);
101
- setSubmittedEmail(trimmed);
91
+ await onSubmit(email.trim());
92
+ setSubmittedEmail(email.trim());
102
93
  setSuccess(true);
103
94
  } catch (e) {
104
95
  setError(e instanceof Error ? e.message : "Something went wrong. Please try again.");
@@ -173,10 +164,7 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
173
164
  {
174
165
  type: "email",
175
166
  value: email,
176
- onChange: (e) => {
177
- setEmail(e.target.value);
178
- if (error) setError(null);
179
- },
167
+ onChange: (e) => setEmail(e.target.value),
180
168
  onKeyDown: handleKeyDown,
181
169
  placeholder: "hello@gmail.com",
182
170
  autoFocus: true,
@@ -233,20 +221,12 @@ function formatClassTime(cls) {
233
221
  const em = endTotal % 60;
234
222
  return `${h}:${cls.startTime.minutes}-${eh}:${String(em).padStart(2, "0")}`;
235
223
  }
236
- function formatBookingLabel(cls) {
237
- const price = cls.price;
238
- const isFree = price === null || price === void 0 || `${price}` === "" || `${price}` === "0";
239
- return isFree ? "Book for free" : `Book for ${cls.currency ?? ""} ${price}`.trim();
240
- }
241
224
  function getBookingsOnDate(cls, date) {
242
225
  if (!cls.bookings?.length) return 0;
243
- const target = new Date(date);
244
- target.setHours(0, 0, 0, 0);
226
+ const ds = date.toISOString().split("T")[0];
245
227
  return cls.bookings.filter((b) => {
246
228
  try {
247
- const bookingDate = new Date(b.classDate);
248
- bookingDate.setHours(0, 0, 0, 0);
249
- return bookingDate.getTime() === target.getTime();
229
+ return new Date(b.classDate).toISOString().split("T")[0] === ds;
250
230
  } catch {
251
231
  return false;
252
232
  }
@@ -511,7 +491,7 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
511
491
  }
512
492
  )
513
493
  ] }),
514
- cls.showAvailability !== false && /* @__PURE__ */ jsx2("div", { className: "sm:hidden flex flex-col gap-px", children: isFull ? /* @__PURE__ */ jsx2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
494
+ /* @__PURE__ */ jsx2("div", { className: "sm:hidden flex flex-col gap-px", children: isFull ? /* @__PURE__ */ jsx2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
515
495
  /* @__PURE__ */ jsxs2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: [
516
496
  available,
517
497
  "/",
@@ -523,10 +503,9 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
523
503
  /* @__PURE__ */ jsxs2("div", { className: "flex flex-1 flex-col gap-2 min-w-0 sm:contents", children: [
524
504
  /* @__PURE__ */ jsxs2("div", { className: "flex-1 flex flex-col gap-2 min-w-0", children: [
525
505
  /* @__PURE__ */ jsx2("span", { className: "font-body text-base font-bold text-(--color-dark,#200C02) block truncate", children: cls.name }),
526
- cls.hostName && /* @__PURE__ */ jsx2("span", { className: "font-body text-base font-normal text-(--color-dark,#200C02) opacity-80 block truncate", children: cls.hostName }),
527
- cls.description && /* @__PURE__ */ jsx2("span", { className: "font-body text-sm font-normal text-(--color-dark,#200C02) opacity-70 block truncate", children: cls.description })
506
+ cls.hostName && /* @__PURE__ */ jsx2("span", { className: "font-body text-base font-normal text-(--color-dark,#200C02) opacity-80 block truncate", children: cls.hostName })
528
507
  ] }),
529
- cls.showAvailability !== false && /* @__PURE__ */ jsx2("div", { className: "hidden sm:flex w-14 shrink-0 flex-col gap-px", children: isFull ? /* @__PURE__ */ jsx2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
508
+ /* @__PURE__ */ jsx2("div", { className: "hidden sm:flex w-14 shrink-0 flex-col gap-px", children: isFull ? /* @__PURE__ */ jsx2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
530
509
  /* @__PURE__ */ jsxs2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: [
531
510
  available,
532
511
  "/",
@@ -551,7 +530,7 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
551
530
  if (!cls.id) return;
552
531
  onOpenModal?.(isFull ? "waitlist" : "book", cls.id, selectedDate);
553
532
  },
554
- children: isFull ? "Join Waitlist" : formatBookingLabel(cls)
533
+ children: isFull ? "Join Waitlist" : "Book Now"
555
534
  }
556
535
  )
557
536
  ] })
@@ -593,17 +572,6 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
593
572
  const [isHovered, setIsHovered] = useState2(false);
594
573
  const [modalState, setModalState] = useState2(null);
595
574
  const switchScheduleIdRef = useRef(null);
596
- const liveScheduleIdRef = useRef(null);
597
- const refetchLiveSchedule = useCallback(async () => {
598
- const id = liveScheduleIdRef.current;
599
- if (!id) return;
600
- try {
601
- const res = await fetch(`${API_URL}/api/schedule/id/${id}`);
602
- const data = await res.json();
603
- if (data?.id) setSchedule(data);
604
- } catch {
605
- }
606
- }, []);
607
575
  const dates = useMemo(() => {
608
576
  const today = /* @__PURE__ */ new Date();
609
577
  today.setHours(0, 0, 0, 0);
@@ -623,18 +591,6 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
623
591
  }
624
592
  }
625
593
  }, [schedule, dates]);
626
- useEffect(() => {
627
- if (typeof window === "undefined") return;
628
- const onVisible = () => {
629
- if (!document.hidden) void refetchLiveSchedule();
630
- };
631
- window.addEventListener("focus", refetchLiveSchedule);
632
- document.addEventListener("visibilitychange", onVisible);
633
- return () => {
634
- window.removeEventListener("focus", refetchLiveSchedule);
635
- document.removeEventListener("visibilitychange", onVisible);
636
- };
637
- }, [refetchLiveSchedule]);
638
594
  useEffect(() => {
639
595
  if (typeof window === "undefined") return;
640
596
  const isInEditor = window.self !== window.top;
@@ -696,7 +652,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
696
652
  setLoading(false);
697
653
  return;
698
654
  }
699
- liveScheduleIdRef.current = effectiveId;
655
+ ;
700
656
  (async () => {
701
657
  try {
702
658
  const res = await fetch(`${API_URL}/api/schedule/id/${effectiveId}`);
@@ -753,14 +709,18 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
753
709
  const data = await res.json().catch(() => ({}));
754
710
  throw new Error(data?.message ?? "Something went wrong. Please try again.");
755
711
  }
756
- await refetchLiveSchedule();
757
712
  };
758
713
  const handleReplaceSchedule = () => {
759
714
  setIsHovered(false);
760
- window.parent.postMessage(
761
- { type: "ow:scheduling-not-connected", insertAfter, currentScheduleId: schedule?.id },
762
- "*"
763
- );
715
+ if (schedule) {
716
+ window.parent.postMessage({
717
+ type: "ow:schedule-connected",
718
+ schedule: { id: schedule.id, name: schedule.name },
719
+ insertAfter
720
+ }, "*");
721
+ } else {
722
+ window.parent.postMessage({ type: "ow:scheduling-not-connected", insertAfter }, "*");
723
+ }
764
724
  };
765
725
  if (!inEditor && !loading && !schedule) return null;
766
726
  const sectionId = `scheduling-${insertAfter}`;
@@ -803,19 +763,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
803
763
  ),
804
764
  /* @__PURE__ */ jsxs2("div", { className: "max-w-[1280px] mx-auto flex flex-col items-center gap-16", children: [
805
765
  /* @__PURE__ */ jsxs2("div", { className: "flex flex-col items-center gap-4", children: [
806
- /* @__PURE__ */ jsx2(
807
- "h2",
808
- {
809
- className: "font-display text-center m-0 text-(--color-dark,#200C02)",
810
- style: {
811
- fontSize: "var(--fs-section-h2, clamp(40px, 4.4vw, 64px))",
812
- fontWeight: "var(--font-weight-heading, 400)",
813
- lineHeight: 1.05,
814
- letterSpacing: "-0.02em"
815
- },
816
- children: schedule?.name ?? "Book an appointment"
817
- }
818
- ),
766
+ /* @__PURE__ */ jsx2("h2", { className: "font-display text-4xl sm:text-5xl font-bold text-center m-0 text-(--color-dark,#200C02)", children: schedule?.name ?? "Book an appointment" }),
819
767
  schedule?.description && /* @__PURE__ */ jsx2("p", { className: "font-body text-body text-center m-0 text-(--color-accent,#A89B83)", children: schedule.description })
820
768
  ] }),
821
769
  /* @__PURE__ */ jsxs2("div", { className: "w-full flex flex-col items-end gap-3", children: [
@@ -4401,7 +4349,6 @@ function ItemActionToolbar({
4401
4349
  onEditLink,
4402
4350
  onAddItem,
4403
4351
  onMore,
4404
- editLinkDisabled = false,
4405
4352
  addItemDisabled = true,
4406
4353
  moreDisabled = true,
4407
4354
  tooltipSide = "bottom"
@@ -4410,12 +4357,10 @@ function ItemActionToolbar({
4410
4357
  /* @__PURE__ */ jsx8(
4411
4358
  ToolbarActionTooltip,
4412
4359
  {
4413
- label: "Edit link",
4360
+ label: "Add link",
4414
4361
  side: tooltipSide,
4415
- disabled: editLinkDisabled,
4416
4362
  buttonProps: {
4417
4363
  onMouseDown: (e) => {
4418
- if (editLinkDisabled) return;
4419
4364
  e.preventDefault();
4420
4365
  e.stopPropagation();
4421
4366
  onEditLink?.();
@@ -4493,7 +4438,7 @@ function getChromeStyle(state) {
4493
4438
  case "dragging":
4494
4439
  return {
4495
4440
  border: `2px solid ${PRIMARY}`,
4496
- boxShadow: `${FOCUS_RING}, ${DRAG_SHADOW}`
4441
+ boxShadow: DRAG_SHADOW
4497
4442
  };
4498
4443
  default:
4499
4444
  return {};
@@ -4509,8 +4454,6 @@ function ItemInteractionLayer({
4509
4454
  dragHandleLabel = "Reorder item",
4510
4455
  onDragHandleDragStart,
4511
4456
  onDragHandleDragEnd,
4512
- onItemPointerDown,
4513
- onItemClick,
4514
4457
  chromeGap = 6,
4515
4458
  className
4516
4459
  }) {
@@ -4518,8 +4461,7 @@ function ItemInteractionLayer({
4518
4461
  const isActive = state === "active-top" || state === "active-bottom";
4519
4462
  const isDragging = state === "dragging";
4520
4463
  const showToolbar = isActive && toolbar;
4521
- const showDragHandle = (isActive || isDragging) && showHandle;
4522
- const itemDragEnabled = isActive && showHandle && !isDragging && !dragDisabled;
4464
+ const showDragHandle = isActive && showHandle && !isDragging;
4523
4465
  return /* @__PURE__ */ jsxs4(
4524
4466
  "div",
4525
4467
  {
@@ -4544,28 +4486,11 @@ function ItemInteractionLayer({
4544
4486
  style: getChromeStyle(state)
4545
4487
  }
4546
4488
  ),
4547
- itemDragEnabled && /* @__PURE__ */ jsx9(
4548
- "div",
4549
- {
4550
- "data-ohw-item-drag-surface": "",
4551
- className: "pointer-events-auto absolute inset-0 cursor-grab rounded-lg active:cursor-grabbing",
4552
- onPointerDown: (e) => {
4553
- if (e.button !== 0) return;
4554
- onItemPointerDown?.(e);
4555
- },
4556
- onClick: (e) => {
4557
- e.preventDefault();
4558
- e.stopPropagation();
4559
- onItemClick?.(e.clientX, e.clientY);
4560
- }
4561
- }
4562
- ),
4563
4489
  showDragHandle && /* @__PURE__ */ jsx9(
4564
4490
  "div",
4565
4491
  {
4566
4492
  "data-ohw-drag-handle-container": "",
4567
- className: "pointer-events-auto absolute left-0 top-1/2 z-10 -translate-x-[calc(100%+7px)] -translate-y-1/2",
4568
- style: isDragging ? { visibility: "hidden" } : void 0,
4493
+ className: "pointer-events-auto absolute left-0 top-1/2 -translate-x-[calc(100%+7px)] -translate-y-1/2",
4569
4494
  children: /* @__PURE__ */ jsx9(
4570
4495
  DragHandle,
4571
4496
  {
@@ -4788,12 +4713,15 @@ function MediaOverlay({
4788
4713
  className: "flex items-center justify-center cursor-pointer",
4789
4714
  style: {
4790
4715
  ...box,
4791
- // Keep the full-size visual overlay click-through so carousel controls and editable
4792
- // content underneath remain interactive. The Replace button opts back in below.
4793
- pointerEvents: "none",
4716
+ // When text overlays this media, let clicks fall THROUGH to the text underneath. In the
4717
+ // parent this needed a whole `ow:click-at` round-trip to re-hit-test inside the iframe;
4718
+ // in-document, pointer-events does it natively. The button below opts back in, so
4719
+ // Replace still works.
4720
+ pointerEvents: hover.hasTextOverlap ? "none" : "auto",
4794
4721
  boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
4795
4722
  background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
4796
4723
  },
4724
+ onClick: () => onReplace(hover.key),
4797
4725
  children: /* @__PURE__ */ jsxs5(
4798
4726
  Button,
4799
4727
  {
@@ -4818,64 +4746,9 @@ function MediaOverlay({
4818
4746
  ] });
4819
4747
  }
4820
4748
 
4821
- // src/ui/CarouselOverlay.tsx
4822
- import { GalleryHorizontal } from "lucide-react";
4823
- import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
4824
- var OVERLAY_BUTTON_STYLE2 = {
4825
- pointerEvents: "auto",
4826
- fontFamily: "Inter, sans-serif",
4827
- fontSize: 12,
4828
- color: "#000"
4829
- };
4830
- function CarouselOverlay({
4831
- hover,
4832
- onEdit
4833
- }) {
4834
- const { rect } = hover;
4835
- return /* @__PURE__ */ jsx12(
4836
- "div",
4837
- {
4838
- "data-ohw-bridge": "",
4839
- "data-ohw-carousel-overlay": "",
4840
- className: "flex cursor-pointer items-center justify-center",
4841
- style: {
4842
- position: "fixed",
4843
- top: rect.top,
4844
- left: rect.left,
4845
- width: rect.width,
4846
- height: rect.height,
4847
- zIndex: 2147483646,
4848
- pointerEvents: "auto",
4849
- boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
4850
- background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
4851
- },
4852
- onClick: () => onEdit(hover.key),
4853
- children: /* @__PURE__ */ jsxs6(
4854
- Button,
4855
- {
4856
- "data-ohw-carousel-overlay": "",
4857
- variant: "outline",
4858
- size: "sm",
4859
- className: "cursor-pointer gap-1.5 hover:bg-background",
4860
- style: OVERLAY_BUTTON_STYLE2,
4861
- onMouseDown: (e) => e.preventDefault(),
4862
- onClick: (e) => {
4863
- e.stopPropagation();
4864
- onEdit(hover.key);
4865
- },
4866
- children: [
4867
- /* @__PURE__ */ jsx12(GalleryHorizontal, { size: 14 }),
4868
- "Edit gallery"
4869
- ]
4870
- }
4871
- )
4872
- }
4873
- );
4874
- }
4875
-
4876
4749
  // src/OhhwellsBridge.tsx
4877
- import { createPortal as createPortal2 } from "react-dom";
4878
- import { usePathname as usePathname2, useRouter as useRouter2, useSearchParams } from "next/navigation";
4750
+ import { createPortal } from "react-dom";
4751
+ import { usePathname, useRouter, useSearchParams } from "next/navigation";
4879
4752
 
4880
4753
  // src/lib/session-search.ts
4881
4754
  var STORAGE_KEY = "ohw-preserved-search";
@@ -4905,7 +4778,6 @@ function parseSectionsFromRoot(root) {
4905
4778
  for (const el of root.querySelectorAll("[data-ohw-section]")) {
4906
4779
  const id = el.getAttribute("data-ohw-section") ?? "";
4907
4780
  if (!id || seen.has(id)) continue;
4908
- if (el.parentElement?.closest("[data-ohw-section]")) continue;
4909
4781
  seen.add(id);
4910
4782
  const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
4911
4783
  sections.push({ id, label });
@@ -5152,22 +5024,54 @@ function scrollToHashSectionWhenReady(behavior = "smooth") {
5152
5024
  tick();
5153
5025
  }
5154
5026
 
5155
- // src/ui/link-modal/LinkPopover.tsx
5156
- import { useEffect as useEffect6 } from "react";
5157
-
5158
5027
  // src/ui/dialog.tsx
5159
5028
  import * as React7 from "react";
5160
5029
  import { Dialog as DialogPrimitive } from "radix-ui";
5161
- import { X } from "lucide-react";
5030
+
5031
+ // src/ui/icons.tsx
5032
+ import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
5033
+ function IconX({ className, ...props }) {
5034
+ return /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
5035
+ /* @__PURE__ */ jsx12("path", { d: "M18 6 6 18" }),
5036
+ /* @__PURE__ */ jsx12("path", { d: "m6 6 12 12" })
5037
+ ] });
5038
+ }
5039
+ function IconChevronDown({ className, ...props }) {
5040
+ return /* @__PURE__ */ jsx12("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: /* @__PURE__ */ jsx12("path", { d: "m6 9 6 6 6-6" }) });
5041
+ }
5042
+ function IconFile({ className, ...props }) {
5043
+ return /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
5044
+ /* @__PURE__ */ jsx12("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
5045
+ /* @__PURE__ */ jsx12("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" })
5046
+ ] });
5047
+ }
5048
+ function IconInfo({ className, ...props }) {
5049
+ return /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
5050
+ /* @__PURE__ */ jsx12("circle", { cx: "12", cy: "12", r: "10" }),
5051
+ /* @__PURE__ */ jsx12("path", { d: "M12 16v-4" }),
5052
+ /* @__PURE__ */ jsx12("path", { d: "M12 8h.01" })
5053
+ ] });
5054
+ }
5055
+ function IconArrowRight({ className, ...props }) {
5056
+ return /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
5057
+ /* @__PURE__ */ jsx12("path", { d: "M5 12h14" }),
5058
+ /* @__PURE__ */ jsx12("path", { d: "m12 5 7 7-7 7" })
5059
+ ] });
5060
+ }
5061
+ function IconSection({ className, ...props }) {
5062
+ return /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
5063
+ /* @__PURE__ */ jsx12("rect", { width: "18", height: "7", x: "3", y: "3", rx: "1" }),
5064
+ /* @__PURE__ */ jsx12("rect", { width: "9", height: "7", x: "3", y: "14", rx: "1" }),
5065
+ /* @__PURE__ */ jsx12("rect", { width: "5", height: "7", x: "16", y: "14", rx: "1" })
5066
+ ] });
5067
+ }
5068
+
5069
+ // src/ui/dialog.tsx
5162
5070
  import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
5163
- function Dialog2({
5164
- ...props
5165
- }) {
5071
+ function Dialog2({ ...props }) {
5166
5072
  return /* @__PURE__ */ jsx13(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
5167
5073
  }
5168
- function DialogPortal({
5169
- ...props
5170
- }) {
5074
+ function DialogPortal({ ...props }) {
5171
5075
  return /* @__PURE__ */ jsx13(DialogPrimitive.Portal, { ...props });
5172
5076
  }
5173
5077
  function DialogOverlay({
@@ -5184,69 +5088,52 @@ function DialogOverlay({
5184
5088
  }
5185
5089
  );
5186
5090
  }
5187
- var DialogContent = React7.forwardRef(
5188
- ({ className, children, showCloseButton = true, container, ...props }, ref) => {
5189
- const positionMode = container ? "absolute" : "fixed";
5190
- return /* @__PURE__ */ jsxs7(DialogPortal, { container: container ?? void 0, children: [
5191
- /* @__PURE__ */ jsx13(DialogOverlay, { className: cn(positionMode, "inset-0") }),
5192
- /* @__PURE__ */ jsxs7(
5193
- DialogPrimitive.Content,
5194
- {
5195
- ref,
5196
- "data-slot": "dialog-content",
5197
- className: cn(
5198
- positionMode,
5199
- "left-1/2 top-1/2 z-[2147483647] flex w-full max-w-[448px] -translate-x-1/2 -translate-y-1/2 flex-col overflow-visible",
5200
- "rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
5201
- container ? "max-h-[calc(100%-32px)]" : "max-h-[calc(100vh-32px)]",
5202
- className
5203
- ),
5204
- onMouseDown: (e) => e.stopPropagation(),
5205
- ...props,
5206
- children: [
5207
- children,
5208
- showCloseButton ? /* @__PURE__ */ jsx13(
5209
- DialogPrimitive.Close,
5210
- {
5211
- type: "button",
5212
- className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
5213
- "aria-label": "Close",
5214
- children: /* @__PURE__ */ jsx13(X, { size: 16, "aria-hidden": true })
5215
- }
5216
- ) : null
5217
- ]
5218
- }
5219
- )
5220
- ] });
5221
- }
5222
- );
5091
+ var DialogContent = React7.forwardRef(({ className, children, showCloseButton = true, container, ...props }, ref) => {
5092
+ const positionMode = container ? "absolute" : "fixed";
5093
+ return /* @__PURE__ */ jsxs7(DialogPortal, { container: container ?? void 0, children: [
5094
+ /* @__PURE__ */ jsx13(DialogOverlay, { className: cn(positionMode, "inset-0") }),
5095
+ /* @__PURE__ */ jsxs7(
5096
+ DialogPrimitive.Content,
5097
+ {
5098
+ ref,
5099
+ "data-slot": "dialog-content",
5100
+ className: cn(
5101
+ positionMode,
5102
+ "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-hidden",
5103
+ "rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
5104
+ container ? "max-h-[calc(100%-32px)] max-w-[calc(100%-16px)]" : "max-h-[calc(100vh-32px)] max-w-[calc(100vw-16px)]",
5105
+ className
5106
+ ),
5107
+ onMouseDown: (e) => e.stopPropagation(),
5108
+ ...props,
5109
+ children: [
5110
+ children,
5111
+ showCloseButton ? /* @__PURE__ */ jsx13(
5112
+ DialogPrimitive.Close,
5113
+ {
5114
+ type: "button",
5115
+ className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
5116
+ "aria-label": "Close",
5117
+ children: /* @__PURE__ */ jsx13(IconX, { "aria-hidden": true })
5118
+ }
5119
+ ) : null
5120
+ ]
5121
+ }
5122
+ )
5123
+ ] });
5124
+ });
5223
5125
  DialogContent.displayName = DialogPrimitive.Content.displayName;
5224
- function DialogHeader({
5225
- className,
5226
- ...props
5227
- }) {
5126
+ function DialogHeader({ className, ...props }) {
5228
5127
  return /* @__PURE__ */ jsx13("div", { className: cn("flex flex-col gap-1.5", className), ...props });
5229
5128
  }
5230
- function DialogFooter({
5231
- className,
5232
- ...props
5233
- }) {
5234
- return /* @__PURE__ */ jsx13(
5235
- "div",
5236
- {
5237
- className: cn("flex items-center justify-end gap-2", className),
5238
- ...props
5239
- }
5240
- );
5129
+ function DialogFooter({ className, ...props }) {
5130
+ return /* @__PURE__ */ jsx13("div", { className: cn("flex items-center justify-end gap-2", className), ...props });
5241
5131
  }
5242
5132
  var DialogTitle = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx13(
5243
5133
  DialogPrimitive.Title,
5244
5134
  {
5245
5135
  ref,
5246
- className: cn(
5247
- "text-lg font-semibold leading-none tracking-tight text-card-foreground",
5248
- className
5249
- ),
5136
+ className: cn("text-lg font-semibold leading-none tracking-tight text-card-foreground", className),
5250
5137
  ...props
5251
5138
  }
5252
5139
  ));
@@ -5262,40 +5149,19 @@ var DialogDescription = React7.forwardRef(({ className, ...props }, ref) => /* @
5262
5149
  DialogDescription.displayName = DialogPrimitive.Description.displayName;
5263
5150
  var DialogClose = DialogPrimitive.Close;
5264
5151
 
5265
- // src/ui/link-modal/LinkEditorPanel.tsx
5266
- import { Info, X as X3 } from "lucide-react";
5267
-
5268
5152
  // src/ui/link-modal/DestinationBreadcrumb.tsx
5269
- import { ArrowRight, File, GalleryVertical } from "lucide-react";
5270
5153
  import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
5271
- function DestinationBreadcrumb({
5272
- pageTitle,
5273
- sectionLabel
5274
- }) {
5154
+ function DestinationBreadcrumb({ pageTitle, sectionLabel }) {
5275
5155
  return /* @__PURE__ */ jsxs8("div", { className: "flex w-full flex-col gap-2", children: [
5276
- /* @__PURE__ */ jsx14("p", { className: "text-sm font-medium! text-foreground m-0", children: "Destination" }),
5156
+ /* @__PURE__ */ jsx14("p", { className: "text-sm font-medium text-foreground", children: "Destination" }),
5277
5157
  /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-3", children: [
5278
5158
  /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
5279
- /* @__PURE__ */ jsx14(File, { size: 16, className: "shrink-0 text-foreground", "aria-hidden": true }),
5280
- /* @__PURE__ */ jsx14("span", { className: "text-sm font-medium leading-none text-foreground!", children: pageTitle })
5159
+ /* @__PURE__ */ jsx14(IconFile, { className: "shrink-0 text-foreground", "aria-hidden": true }),
5160
+ /* @__PURE__ */ jsx14("span", { className: "text-sm font-medium leading-none text-foreground", children: pageTitle })
5281
5161
  ] }),
5282
- /* @__PURE__ */ jsx14(
5283
- ArrowRight,
5284
- {
5285
- size: 16,
5286
- className: "shrink-0 text-muted-foreground",
5287
- "aria-hidden": true
5288
- }
5289
- ),
5162
+ /* @__PURE__ */ jsx14(IconArrowRight, { className: "shrink-0 text-muted-foreground", "aria-hidden": true }),
5290
5163
  /* @__PURE__ */ jsxs8("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
5291
- /* @__PURE__ */ jsx14(
5292
- GalleryVertical,
5293
- {
5294
- size: 16,
5295
- className: "shrink-0 text-foreground",
5296
- "aria-hidden": true
5297
- }
5298
- ),
5164
+ /* @__PURE__ */ jsx14(IconSection, { className: "shrink-0 text-foreground", "aria-hidden": true }),
5299
5165
  /* @__PURE__ */ jsx14("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
5300
5166
  ] })
5301
5167
  ] })
@@ -5303,13 +5169,8 @@ function DestinationBreadcrumb({
5303
5169
  }
5304
5170
 
5305
5171
  // src/ui/link-modal/SectionTreeItem.tsx
5306
- import { GalleryVertical as GalleryVertical2 } from "lucide-react";
5307
5172
  import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
5308
- function SectionTreeItem({
5309
- section,
5310
- onSelect,
5311
- selected
5312
- }) {
5173
+ function SectionTreeItem({ section, onSelect, selected }) {
5313
5174
  const interactive = Boolean(onSelect);
5314
5175
  return /* @__PURE__ */ jsxs9("div", { className: "flex h-9 w-full items-end pl-3", children: [
5315
5176
  /* @__PURE__ */ jsx15(
@@ -5337,23 +5198,25 @@ function SectionTreeItem({
5337
5198
  interactive && selected && "border-primary"
5338
5199
  ),
5339
5200
  children: [
5340
- /* @__PURE__ */ jsx15(
5341
- GalleryVertical2,
5342
- {
5343
- size: 16,
5344
- className: "shrink-0 text-foreground",
5345
- "aria-hidden": true
5346
- }
5347
- ),
5201
+ /* @__PURE__ */ jsx15(IconSection, { className: "shrink-0 text-foreground", "aria-hidden": true }),
5348
5202
  /* @__PURE__ */ jsx15("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
5349
5203
  ]
5350
5204
  }
5351
5205
  )
5352
5206
  ] });
5353
5207
  }
5208
+ function SectionPickerList({ sections, onSelect }) {
5209
+ if (sections.length === 0) {
5210
+ return /* @__PURE__ */ jsx15("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." });
5211
+ }
5212
+ return /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-1", children: [
5213
+ /* @__PURE__ */ jsx15("p", { className: "text-sm text-muted-foreground", children: "Pick a section this link should scroll to." }),
5214
+ sections.map((section) => /* @__PURE__ */ jsx15(SectionTreeItem, { section, onSelect }, section.id))
5215
+ ] });
5216
+ }
5354
5217
 
5355
5218
  // src/ui/link-modal/UrlOrPageInput.tsx
5356
- import { useEffect as useEffect3, useId as useId2, useRef as useRef3, useState as useState3 } from "react";
5219
+ import { useId as useId2, useRef as useRef3, useState as useState3 } from "react";
5357
5220
 
5358
5221
  // src/ui/input.tsx
5359
5222
  import * as React8 from "react";
@@ -5392,11 +5255,8 @@ function Label({ className, ...props }) {
5392
5255
  }
5393
5256
 
5394
5257
  // src/ui/link-modal/UrlOrPageInput.tsx
5395
- import { ChevronDown, File as File2, X as X2 } from "lucide-react";
5396
5258
  import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
5397
- function FieldChevron({
5398
- onClick
5399
- }) {
5259
+ function FieldChevron({ onClick }) {
5400
5260
  return /* @__PURE__ */ jsx18(
5401
5261
  "button",
5402
5262
  {
@@ -5405,7 +5265,7 @@ function FieldChevron({
5405
5265
  onClick,
5406
5266
  "aria-label": "Open page list",
5407
5267
  tabIndex: -1,
5408
- children: /* @__PURE__ */ jsx18(ChevronDown, { size: 16 })
5268
+ children: /* @__PURE__ */ jsx18(IconChevronDown, {})
5409
5269
  }
5410
5270
  );
5411
5271
  }
@@ -5423,29 +5283,7 @@ function UrlOrPageInput({
5423
5283
  }) {
5424
5284
  const inputId = useId2();
5425
5285
  const inputRef = useRef3(null);
5426
- const rootRef = useRef3(null);
5427
5286
  const [isFocused, setIsFocused] = useState3(false);
5428
- useEffect3(() => {
5429
- if (!dropdownOpen) return;
5430
- const isOutside = (e) => {
5431
- const root = rootRef.current;
5432
- if (!root) return true;
5433
- const path = typeof e.composedPath === "function" ? e.composedPath() : [];
5434
- if (path.includes(root)) return false;
5435
- const target = e.target;
5436
- return !(target instanceof Node && root.contains(target));
5437
- };
5438
- const closeIfOutside = (e) => {
5439
- if (!isOutside(e)) return;
5440
- onDropdownOpenChange(false);
5441
- };
5442
- document.addEventListener("pointerdown", closeIfOutside, true);
5443
- document.addEventListener("mousedown", closeIfOutside, true);
5444
- return () => {
5445
- document.removeEventListener("pointerdown", closeIfOutside, true);
5446
- document.removeEventListener("mousedown", closeIfOutside, true);
5447
- };
5448
- }, [dropdownOpen, onDropdownOpenChange]);
5449
5287
  const openDropdown = () => {
5450
5288
  if (readOnly || filteredPages.length === 0) return;
5451
5289
  onDropdownOpenChange(true);
@@ -5463,21 +5301,14 @@ function UrlOrPageInput({
5463
5301
  requestAnimationFrame(() => inputRef.current?.focus());
5464
5302
  };
5465
5303
  const fieldClassName = cn(
5466
- "data-ohw-link-field flex h-[36px] w-full items-center overflow-hidden rounded-md border bg-background pl-3 pr-3 py-2 outline-none transition-[border-color,box-shadow]",
5304
+ "data-ohw-link-field flex h-10 w-full items-center overflow-hidden rounded-md border bg-background pl-3 pr-3 py-2 outline-none transition-[border-color,box-shadow]",
5467
5305
  urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
5468
5306
  );
5469
5307
  return /* @__PURE__ */ jsxs10("div", { className: "flex w-full flex-col gap-2 p-0", children: [
5470
5308
  /* @__PURE__ */ jsx18(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
5471
- /* @__PURE__ */ jsxs10("div", { ref: rootRef, className: "relative w-full", children: [
5309
+ /* @__PURE__ */ jsxs10("div", { className: "relative w-full", children: [
5472
5310
  /* @__PURE__ */ jsxs10("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
5473
- selectedPage ? /* @__PURE__ */ jsx18("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ jsx18(
5474
- File2,
5475
- {
5476
- size: 16,
5477
- className: "shrink-0 text-foreground",
5478
- "aria-hidden": true
5479
- }
5480
- ) }) : null,
5311
+ selectedPage ? /* @__PURE__ */ jsx18("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ jsx18(IconFile, { className: "text-foreground", "aria-hidden": true }) }) : null,
5481
5312
  readOnly ? /* @__PURE__ */ jsx18("span", { className: "min-w-0 flex-1 truncate text-sm leading-5 text-foreground", children: selectedPage?.title ?? value }) : /* @__PURE__ */ jsx18(
5482
5313
  Input,
5483
5314
  {
@@ -5489,14 +5320,7 @@ function UrlOrPageInput({
5489
5320
  setIsFocused(true);
5490
5321
  if (!selectedPage) openDropdown();
5491
5322
  },
5492
- onBlur: () => {
5493
- setIsFocused(false);
5494
- requestAnimationFrame(() => {
5495
- if (!rootRef.current?.contains(document.activeElement)) {
5496
- onDropdownOpenChange(false);
5497
- }
5498
- });
5499
- },
5323
+ onBlur: () => setIsFocused(false),
5500
5324
  placeholder,
5501
5325
  className: cn(
5502
5326
  "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",
@@ -5512,7 +5336,7 @@ function UrlOrPageInput({
5512
5336
  onMouseDown: clearSelection,
5513
5337
  "aria-label": "Clear selected page",
5514
5338
  tabIndex: -1,
5515
- children: /* @__PURE__ */ jsx18(X2, { size: 16, "aria-hidden": true })
5339
+ children: /* @__PURE__ */ jsx18(IconX, { "aria-hidden": true })
5516
5340
  }
5517
5341
  ) : null,
5518
5342
  !readOnly ? /* @__PURE__ */ jsx18(FieldChevron, { onClick: toggleDropdown }) : null
@@ -5521,7 +5345,7 @@ function UrlOrPageInput({
5521
5345
  "div",
5522
5346
  {
5523
5347
  "data-ohw-link-page-dropdown": "",
5524
- 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",
5348
+ className: "absolute left-0 right-0 h-20 top-[calc(100%+4px)] z-10 max-h-48 overflow-auto rounded-lg border border-border bg-popover py-1 shadow-lg",
5525
5349
  onMouseDown: (e) => e.preventDefault(),
5526
5350
  children: filteredPages.map((page) => /* @__PURE__ */ jsxs10(
5527
5351
  "button",
@@ -5530,7 +5354,7 @@ function UrlOrPageInput({
5530
5354
  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",
5531
5355
  onClick: () => onPageSelect(page),
5532
5356
  children: [
5533
- /* @__PURE__ */ jsx18(File2, { size: 16, className: "shrink-0", "aria-hidden": true }),
5357
+ /* @__PURE__ */ jsx18(IconFile, { className: "shrink-0", "aria-hidden": true }),
5534
5358
  /* @__PURE__ */ jsx18("span", { className: "truncate", children: page.title })
5535
5359
  ]
5536
5360
  },
@@ -5543,458 +5367,30 @@ function UrlOrPageInput({
5543
5367
  ] });
5544
5368
  }
5545
5369
 
5546
- // src/ui/link-modal/LinkEditorPanel.tsx
5547
- import { Fragment as Fragment3, jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
5548
- function LinkEditorPanel({ state, onClose }) {
5549
- const isCancel = state.secondaryLabel === "Cancel" || state.secondaryLabel === "Back to sections";
5550
- return /* @__PURE__ */ jsxs11(Fragment3, { children: [
5551
- /* @__PURE__ */ jsx19(DialogClose, { asChild: true, children: /* @__PURE__ */ jsx19(
5552
- "button",
5553
- {
5554
- type: "button",
5555
- className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50 h-7",
5556
- "aria-label": "Close",
5557
- onClick: onClose,
5558
- children: /* @__PURE__ */ jsx19(X3, { size: 16, "aria-hidden": true })
5559
- }
5560
- ) }),
5561
- /* @__PURE__ */ jsx19(DialogHeader, { className: "w-full gap-1.5 p-6 pr-12", children: /* @__PURE__ */ jsx19(DialogTitle, { className: "m-0 w-full break-words", children: state.title }) }),
5562
- /* @__PURE__ */ jsxs11("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
5563
- state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ jsx19(
5564
- DestinationBreadcrumb,
5565
- {
5566
- pageTitle: state.selectedPage.title,
5567
- sectionLabel: state.selectedSection.label
5568
- }
5569
- ) : /* @__PURE__ */ jsx19(
5570
- UrlOrPageInput,
5571
- {
5572
- value: state.searchValue,
5573
- selectedPage: state.selectedPage,
5574
- dropdownOpen: state.dropdownOpen,
5575
- onDropdownOpenChange: state.setDropdownOpen,
5576
- filteredPages: state.filteredPages,
5577
- onInputChange: state.handleInputChange,
5578
- onPageSelect: state.handlePageSelect,
5579
- urlError: state.urlError
5580
- }
5581
- ),
5582
- state.showChooseSection ? /* @__PURE__ */ jsxs11("div", { className: "flex flex-col justify-center gap-2", children: [
5583
- /* @__PURE__ */ jsx19(
5584
- Button,
5585
- {
5586
- type: "button",
5587
- variant: "outline",
5588
- className: "w-fit cursor-pointer",
5589
- size: "sm",
5590
- onClick: state.handleChooseSection,
5591
- children: "Choose a section"
5592
- }
5593
- ),
5594
- /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
5595
- /* @__PURE__ */ jsx19(Info, { size: 16, className: "shrink-0", "aria-hidden": true }),
5596
- /* @__PURE__ */ jsx19("span", { children: "Pick a section this link should scroll to." })
5597
- ] })
5598
- ] }) : null,
5599
- state.showSectionRow && state.selectedSection ? /* @__PURE__ */ jsx19(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
5600
- ] }),
5601
- /* @__PURE__ */ jsxs11(DialogFooter, { className: "w-full px-6 pb-6", children: [
5602
- /* @__PURE__ */ jsx19(
5603
- Button,
5604
- {
5605
- type: "button",
5606
- variant: isCancel ? "outline" : "ghost",
5607
- className: "leading-6 shadow-none cursor-pointer",
5608
- style: isCancel ? {
5609
- backgroundColor: "var(--ohw-background)",
5610
- borderColor: "var(--ohw-border)",
5611
- color: "var(--ohw-foreground)"
5612
- } : void 0,
5613
- onClick: state.handleSecondary,
5614
- children: state.secondaryLabel
5615
- }
5616
- ),
5617
- /* @__PURE__ */ jsx19(
5618
- Button,
5619
- {
5620
- type: "button",
5621
- className: "border-0 leading-6 shadow-none hover:opacity-90 disabled:opacity-50 cursor-pointer",
5622
- style: {
5623
- backgroundColor: "var(--ohw-primary)",
5624
- color: "var(--ohw-primary-foreground)"
5625
- },
5626
- disabled: !state.isValid,
5627
- onClick: state.handleSubmit,
5628
- children: state.submitLabel
5629
- }
5630
- )
5631
- ] })
5632
- ] });
5633
- }
5634
-
5635
- // src/ui/link-modal/SectionPickerOverlay.tsx
5636
- import { useCallback as useCallback2, useEffect as useEffect4, useMemo as useMemo2, useRef as useRef4, useState as useState4 } from "react";
5637
- import { createPortal } from "react-dom";
5638
- import { ArrowLeft, Check } from "lucide-react";
5639
- import { usePathname, useRouter } from "next/navigation";
5640
- import { jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
5641
- var DIM_OVERLAY = "rgba(0, 0, 0, 0.45)";
5642
- function rectsEqual(a, b) {
5643
- if (a.size !== b.size) return false;
5644
- for (const [id, rect] of a) {
5645
- const other = b.get(id);
5646
- if (!other || rect.top !== other.top || rect.left !== other.left || rect.width !== other.width || rect.height !== other.height) {
5647
- return false;
5648
- }
5649
- }
5650
- return true;
5651
- }
5652
- function readSectionRects(sectionIds) {
5653
- const next = /* @__PURE__ */ new Map();
5654
- for (const id of sectionIds) {
5655
- const el = document.querySelector(
5656
- `[data-ohw-section="${CSS.escape(id)}"]`
5657
- );
5658
- if (el) next.set(id, el.getBoundingClientRect());
5659
- }
5660
- return next;
5661
- }
5662
- function hitTestSectionId(x, y, sectionIds, rects) {
5663
- for (const id of sectionIds) {
5664
- const rect = rects.get(id);
5665
- if (!rect || rect.width <= 0 || rect.height <= 0) continue;
5666
- if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) {
5667
- return id;
5668
- }
5669
- }
5670
- return null;
5671
- }
5672
- function useSectionRects(sectionIdsKey, enabled) {
5673
- const [rects, setRects] = useState4(/* @__PURE__ */ new Map());
5674
- const sectionIds = useMemo2(
5675
- () => sectionIdsKey ? sectionIdsKey.split("\0") : [],
5676
- [sectionIdsKey]
5370
+ // src/ui/link-modal/useLinkModalState.ts
5371
+ import { useCallback, useEffect as useEffect3, useMemo as useMemo2, useState as useState4 } from "react";
5372
+ function useLinkModalState({
5373
+ open,
5374
+ mode,
5375
+ pages,
5376
+ sections: _sections,
5377
+ sectionsByPath,
5378
+ initialTarget,
5379
+ existingTargets,
5380
+ onClose,
5381
+ onSubmit
5382
+ }) {
5383
+ const availablePages = useMemo2(
5384
+ () => mode === "create" ? filterAvailablePages(pages, existingTargets) : pages,
5385
+ [mode, pages, existingTargets]
5677
5386
  );
5678
- useEffect4(() => {
5679
- if (!enabled || sectionIds.length === 0) {
5680
- setRects((prev) => prev.size === 0 ? prev : /* @__PURE__ */ new Map());
5681
- return;
5682
- }
5683
- const update = () => {
5684
- const next = readSectionRects(sectionIds);
5685
- setRects((prev) => rectsEqual(prev, next) ? prev : next);
5686
- };
5687
- update();
5688
- const opts = { capture: true, passive: true };
5689
- window.addEventListener("scroll", update, opts);
5690
- window.addEventListener("resize", update);
5691
- const vv = window.visualViewport;
5692
- vv?.addEventListener("resize", update);
5693
- vv?.addEventListener("scroll", update);
5694
- const ro = new ResizeObserver(update);
5695
- for (const id of sectionIds) {
5696
- const el = document.querySelector(
5697
- `[data-ohw-section="${CSS.escape(id)}"]`
5698
- );
5699
- if (el) ro.observe(el);
5700
- }
5701
- return () => {
5702
- window.removeEventListener("scroll", update, opts);
5703
- window.removeEventListener("resize", update);
5704
- vv?.removeEventListener("resize", update);
5705
- vv?.removeEventListener("scroll", update);
5706
- ro.disconnect();
5707
- };
5708
- }, [sectionIds, enabled]);
5709
- return rects;
5710
- }
5711
- function SectionPickerOverlay({
5712
- pagePath,
5713
- sections,
5714
- onBack,
5715
- onSelect
5716
- }) {
5717
- const router = useRouter();
5718
- const pathname = usePathname();
5719
- const [selectedId, setSelectedId] = useState4(null);
5720
- const [hoveredId, setHoveredId] = useState4(null);
5721
- const pointerRef = useRef4(null);
5722
- const pointerScreenRef = useRef4(null);
5723
- const iframeOffsetTopRef = useRef4(null);
5724
- const sectionIdsRef = useRef4([]);
5725
- const [chromeClip, setChromeClip] = useState4(
5726
- () => ({
5727
- top: 0,
5728
- bottom: typeof window !== "undefined" ? window.innerHeight : 0
5729
- })
5730
- );
5731
- const normalizedTarget = normalizePath(pagePath);
5732
- const isOnTargetPage = normalizePath(pathname) === normalizedTarget;
5733
- useEffect4(() => {
5734
- if (isOnTargetPage) return;
5735
- const search = readPreservedSearch();
5736
- router.push(`${normalizedTarget}${search}`);
5737
- }, [isOnTargetPage, normalizedTarget, router]);
5738
- useEffect4(() => {
5739
- document.documentElement.setAttribute("data-ohw-section-picking", "");
5740
- document.querySelectorAll("[data-ohw-hovered]").forEach((el) => {
5741
- el.removeAttribute("data-ohw-hovered");
5742
- });
5743
- document.querySelectorAll("[data-ohw-state-hovered]").forEach((el) => {
5744
- el.removeAttribute("data-ohw-state-hovered");
5745
- });
5746
- return () => {
5747
- document.documentElement.removeAttribute("data-ohw-section-picking");
5748
- };
5749
- }, []);
5750
- const liveSections = useMemo2(() => {
5751
- if (!isOnTargetPage) return sections;
5752
- const live = collectSectionsFromDom();
5753
- if (live.length === 0) return sections;
5754
- const labels = new Map(sections.map((s) => [s.id, s.label]));
5755
- return live.map((s) => ({ id: s.id, label: labels.get(s.id) ?? s.label }));
5756
- }, [isOnTargetPage, sections, pathname]);
5757
- const sectionIdsKey = useMemo2(
5758
- () => liveSections.map((s) => s.id).join("\0"),
5759
- [liveSections]
5760
- );
5761
- const sectionIds = useMemo2(
5762
- () => liveSections.map((s) => s.id),
5763
- [liveSections]
5764
- );
5765
- sectionIdsRef.current = sectionIds;
5766
- const rects = useSectionRects(sectionIdsKey, isOnTargetPage);
5767
- const applyHoverAt = useCallback2(
5768
- (x, y, liveRects) => {
5769
- const ids = sectionIdsRef.current;
5770
- const map = liveRects ?? readSectionRects(ids);
5771
- const next = hitTestSectionId(x, y, ids, map);
5772
- setHoveredId((prev) => prev === next ? prev : next);
5773
- },
5774
- []
5775
- );
5776
- useEffect4(() => {
5777
- const applyClip = (iframeOffsetTop, visibleCanvasTop, canvasH) => {
5778
- const top = Math.max(0, visibleCanvasTop - iframeOffsetTop);
5779
- const bottom = Math.min(
5780
- window.innerHeight,
5781
- visibleCanvasTop + canvasH - iframeOffsetTop
5782
- );
5783
- setChromeClip(
5784
- (prev) => prev.top === top && prev.bottom === bottom ? prev : { top, bottom: Math.max(top, bottom) }
5785
- );
5786
- };
5787
- const onParentScroll = (e) => {
5788
- if (e.data?.type !== "ow:parent-scroll") return;
5789
- const { iframeOffsetTop, headerH, canvasH } = e.data;
5790
- applyClip(iframeOffsetTop, headerH, canvasH);
5791
- iframeOffsetTopRef.current = iframeOffsetTop;
5792
- if (!pointerScreenRef.current && pointerRef.current) {
5793
- pointerScreenRef.current = {
5794
- x: pointerRef.current.x,
5795
- y: pointerRef.current.y + iframeOffsetTop
5796
- };
5797
- }
5798
- const screen = pointerScreenRef.current;
5799
- if (screen) {
5800
- const next = { x: screen.x, y: screen.y - iframeOffsetTop };
5801
- pointerRef.current = next;
5802
- applyHoverAt(next.x, next.y);
5803
- }
5804
- };
5805
- const onResize = () => {
5806
- setChromeClip((prev) => {
5807
- const bottom = Math.max(prev.top, window.innerHeight);
5808
- return prev.bottom === bottom ? prev : { ...prev, bottom };
5809
- });
5810
- };
5811
- window.addEventListener("message", onParentScroll);
5812
- window.addEventListener("resize", onResize);
5813
- return () => {
5814
- window.removeEventListener("message", onParentScroll);
5815
- window.removeEventListener("resize", onResize);
5816
- };
5817
- }, [applyHoverAt]);
5818
- useEffect4(() => {
5819
- const ptr = pointerRef.current;
5820
- if (!ptr) return;
5821
- applyHoverAt(ptr.x, ptr.y, rects);
5822
- }, [rects, applyHoverAt]);
5823
- useEffect4(() => {
5824
- const rememberPointer = (clientX, clientY) => {
5825
- pointerRef.current = { x: clientX, y: clientY };
5826
- const top = iframeOffsetTopRef.current;
5827
- if (top != null) {
5828
- pointerScreenRef.current = { x: clientX, y: clientY + top };
5829
- }
5830
- applyHoverAt(clientX, clientY, rects);
5831
- };
5832
- const onPointerMove = (e) => {
5833
- rememberPointer(e.clientX, e.clientY);
5834
- };
5835
- const onPointerSync = (e) => {
5836
- if (e.data?.type !== "ow:pointer-sync") return;
5837
- const { clientX, clientY } = e.data;
5838
- rememberPointer(clientX, clientY);
5839
- };
5840
- window.addEventListener("pointermove", onPointerMove, { passive: true });
5841
- window.addEventListener("message", onPointerSync);
5842
- return () => {
5843
- window.removeEventListener("pointermove", onPointerMove);
5844
- window.removeEventListener("message", onPointerSync);
5845
- };
5846
- }, [rects, applyHoverAt]);
5847
- const handleSelect = useCallback2(
5848
- (section) => {
5849
- if (selectedId) return;
5850
- setSelectedId(section.id);
5851
- onSelect(section);
5852
- },
5853
- [selectedId, onSelect]
5854
- );
5855
- useEffect4(() => {
5856
- const onKeyDown = (e) => {
5857
- if (e.key === "Escape") {
5858
- e.preventDefault();
5859
- e.stopPropagation();
5860
- onBack();
5861
- }
5862
- };
5863
- window.addEventListener("keydown", onKeyDown, true);
5864
- return () => window.removeEventListener("keydown", onKeyDown, true);
5865
- }, [onBack]);
5866
- const portalRoot = typeof document !== "undefined" ? document.querySelector("[data-ohw-bridge-root]") ?? document.body : null;
5867
- if (!portalRoot) return null;
5868
- return createPortal(
5869
- /* @__PURE__ */ jsxs12(
5870
- "div",
5871
- {
5872
- "data-ohw-section-picker": "",
5873
- "data-ohw-bridge": "",
5874
- className: `pointer-events-none fixed inset-0 z-[2147483647] transition-opacity duration-200 ${"opacity-100"}`,
5875
- "aria-modal": true,
5876
- role: "dialog",
5877
- "aria-label": "Choose a section",
5878
- children: [
5879
- /* @__PURE__ */ jsx20(
5880
- "div",
5881
- {
5882
- className: "pointer-events-auto fixed left-5 z-[2]",
5883
- style: { top: chromeClip.top + 20 },
5884
- children: /* @__PURE__ */ jsxs12(
5885
- Button,
5886
- {
5887
- type: "button",
5888
- variant: "outline",
5889
- size: "sm",
5890
- className: "h-8 min-w-0 gap-1 border-border bg-background px-2 py-1.5 shadow-sm hover:bg-muted cursor-pointer",
5891
- onClick: onBack,
5892
- children: [
5893
- /* @__PURE__ */ jsx20(ArrowLeft, { className: "size-4 shrink-0", "aria-hidden": true }),
5894
- "Back"
5895
- ]
5896
- }
5897
- )
5898
- }
5899
- ),
5900
- /* @__PURE__ */ jsx20(
5901
- "div",
5902
- {
5903
- 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",
5904
- style: {
5905
- top: chromeClip.bottom - 20,
5906
- transform: "translate(-50%, -100%)",
5907
- backgroundColor: "var(--ohw-popover-foreground, #0c0a09)"
5908
- },
5909
- "data-ohw-section-picker-hint": "",
5910
- children: "Click on section to select"
5911
- }
5912
- ),
5913
- !isOnTargetPage ? /* @__PURE__ */ jsx20(
5914
- "div",
5915
- {
5916
- 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",
5917
- style: { top: chromeClip.top + 64 },
5918
- children: "Loading page preview\u2026"
5919
- }
5920
- ) : null,
5921
- isOnTargetPage && liveSections.length === 0 ? /* @__PURE__ */ jsx20("div", { className: "pointer-events-auto fixed inset-0 z-[1] flex items-center justify-center bg-muted/40", children: /* @__PURE__ */ jsx20("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." }) }) : null,
5922
- isOnTargetPage ? liveSections.map((section) => {
5923
- const rect = rects.get(section.id);
5924
- if (!rect || rect.width <= 0 || rect.height <= 0) return null;
5925
- const isSelected = selectedId === section.id;
5926
- const isHovered = hoveredId === section.id;
5927
- const isLit = isSelected || isHovered;
5928
- return /* @__PURE__ */ jsxs12(
5929
- "button",
5930
- {
5931
- type: "button",
5932
- className: "pointer-events-auto fixed z-[1] cursor-pointer border-0 bg-transparent p-0 transition-[background-color] duration-150",
5933
- style: {
5934
- top: rect.top,
5935
- left: rect.left,
5936
- width: rect.width,
5937
- height: rect.height,
5938
- backgroundColor: isLit ? "transparent" : DIM_OVERLAY
5939
- },
5940
- "aria-label": `Select section ${section.label}`,
5941
- onClick: () => handleSelect(section),
5942
- children: [
5943
- isLit ? /* @__PURE__ */ jsx20(
5944
- "span",
5945
- {
5946
- className: "pointer-events-none absolute",
5947
- style: {
5948
- inset: 4,
5949
- borderRadius: "var(--radius, 6px)",
5950
- border: "1.5px dashed var(--primary, #0885FE)",
5951
- boxSizing: "border-box"
5952
- },
5953
- "aria-hidden": true
5954
- }
5955
- ) : null,
5956
- isSelected ? /* @__PURE__ */ jsx20(
5957
- "span",
5958
- {
5959
- className: "absolute right-3 top-3 flex size-8 items-center justify-center rounded-full text-white",
5960
- style: { backgroundColor: "var(--ohw-primary, #0885fe)" },
5961
- "aria-hidden": true,
5962
- children: /* @__PURE__ */ jsx20(Check, { className: "size-5" })
5963
- }
5964
- ) : null
5965
- ]
5966
- },
5967
- section.id
5968
- );
5969
- }) : null
5970
- ]
5971
- }
5972
- ),
5973
- portalRoot
5974
- );
5975
- }
5976
-
5977
- // src/ui/link-modal/useLinkModalState.ts
5978
- import { useCallback as useCallback3, useEffect as useEffect5, useMemo as useMemo3, useState as useState5 } from "react";
5979
- function useLinkModalState({
5980
- open,
5981
- mode,
5982
- pages,
5983
- sections: _sections,
5984
- sectionsByPath,
5985
- initialTarget,
5986
- existingTargets: _existingTargets,
5987
- onClose,
5988
- onSubmit
5989
- }) {
5990
- const availablePages = useMemo3(() => pages, [pages]);
5991
- const [searchValue, setSearchValue] = useState5("");
5992
- const [selectedPage, setSelectedPage] = useState5(null);
5993
- const [selectedSection, setSelectedSection] = useState5(null);
5994
- const [step, setStep] = useState5("input");
5995
- const [dropdownOpen, setDropdownOpen] = useState5(false);
5996
- const [urlError, setUrlError] = useState5("");
5997
- const reset = useCallback3(() => {
5387
+ const [searchValue, setSearchValue] = useState4("");
5388
+ const [selectedPage, setSelectedPage] = useState4(null);
5389
+ const [selectedSection, setSelectedSection] = useState4(null);
5390
+ const [step, setStep] = useState4("input");
5391
+ const [dropdownOpen, setDropdownOpen] = useState4(false);
5392
+ const [urlError, setUrlError] = useState4("");
5393
+ const reset = useCallback(() => {
5998
5394
  setSearchValue("");
5999
5395
  setSelectedPage(null);
6000
5396
  setSelectedSection(null);
@@ -6002,7 +5398,7 @@ function useLinkModalState({
6002
5398
  setDropdownOpen(false);
6003
5399
  setUrlError("");
6004
5400
  }, []);
6005
- useEffect5(() => {
5401
+ useEffect3(() => {
6006
5402
  if (!open) return;
6007
5403
  if (mode === "edit" && initialTarget) {
6008
5404
  const { pageRoute } = parseTarget(initialTarget);
@@ -6017,12 +5413,12 @@ function useLinkModalState({
6017
5413
  }
6018
5414
  setDropdownOpen(false);
6019
5415
  setUrlError("");
6020
- }, [open, mode, initialTarget, reset]);
6021
- const filteredPages = useMemo3(() => {
5416
+ }, [open, mode, initialTarget, pages, sectionsByPath, reset]);
5417
+ const filteredPages = useMemo2(() => {
6022
5418
  if (!searchValue.trim()) return availablePages;
6023
5419
  return availablePages.filter((p) => p.title.toLowerCase().startsWith(searchValue.toLowerCase()));
6024
5420
  }, [availablePages, searchValue]);
6025
- const activeSections = useMemo3(() => {
5421
+ const activeSections = useMemo2(() => {
6026
5422
  if (!selectedPage) return [];
6027
5423
  return getSectionsForPath(sectionsByPath, selectedPage.path);
6028
5424
  }, [selectedPage, sectionsByPath]);
@@ -6064,14 +5460,11 @@ function useLinkModalState({
6064
5460
  const handleBackToSections = () => {
6065
5461
  setStep("sectionPicker");
6066
5462
  };
6067
- const handleSectionPickerBack = () => {
6068
- setStep("input");
6069
- };
6070
5463
  const handleClose = () => {
6071
5464
  reset();
6072
5465
  onClose();
6073
5466
  };
6074
- const isValid = useMemo3(() => {
5467
+ const isValid = useMemo2(() => {
6075
5468
  if (urlError) return false;
6076
5469
  if (showBreadcrumb) return true;
6077
5470
  if (selectedPage) return true;
@@ -6104,7 +5497,7 @@ function useLinkModalState({
6104
5497
  onSubmit(normalizeUrl(searchValue));
6105
5498
  handleClose();
6106
5499
  };
6107
- const submitLabel = showBreadcrumb ? "Save" : mode === "edit" ? "Save" : "Create";
5500
+ const submitLabel = mode === "edit" ? "Save" : "Create";
6108
5501
  const title = mode === "edit" ? "Edit navigation item" : "Create navigation item";
6109
5502
  const secondaryLabel = showBreadcrumb ? "Back to sections" : "Cancel";
6110
5503
  const handleSecondary = showBreadcrumb ? handleBackToSections : handleClose;
@@ -6131,29 +5524,23 @@ function useLinkModalState({
6131
5524
  handleChooseSection,
6132
5525
  handleSectionSelect,
6133
5526
  handleBackToSections,
6134
- handleSectionPickerBack,
6135
5527
  handleClose,
6136
5528
  handleSecondary,
6137
5529
  handleSubmit
6138
5530
  };
6139
5531
  }
6140
5532
 
6141
- // src/ui/link-modal/LinkPopover.tsx
6142
- import { Fragment as Fragment4, jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
6143
- function postToParent(data) {
6144
- window.parent?.postMessage(data, "*");
6145
- }
6146
- function LinkPopover({
5533
+ // src/ui/link-modal/LinkEditorPanel.tsx
5534
+ import { Fragment as Fragment3, jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
5535
+ function LinkEditorPanel({
6147
5536
  open = true,
6148
- panelRef,
6149
- portalContainer,
6150
- onClose,
6151
5537
  mode = "create",
6152
5538
  pages,
6153
5539
  sections = [],
6154
5540
  sectionsByPath,
6155
5541
  initialTarget,
6156
5542
  existingTargets = [],
5543
+ onClose,
6157
5544
  onSubmit
6158
5545
  }) {
6159
5546
  const state = useLinkModalState({
@@ -6167,109 +5554,115 @@ function LinkPopover({
6167
5554
  onClose,
6168
5555
  onSubmit
6169
5556
  });
6170
- const sectionPickerActive = state.showSectionPicker && Boolean(state.selectedPage);
6171
- useEffect6(() => {
6172
- if (!open) return;
6173
- if (sectionPickerActive) {
6174
- postToParent({ type: "ui:unlock" });
6175
- postToParent({ type: "ow:section-picker", active: true });
6176
- document.documentElement.style.overflow = "";
6177
- document.body.style.overflow = "";
6178
- return () => {
6179
- postToParent({ type: "ow:section-picker", active: false });
6180
- };
6181
- }
6182
- postToParent({ type: "ow:section-picker", active: false });
6183
- postToParent({ type: "ui:lock" });
6184
- const html = document.documentElement;
6185
- const body = document.body;
6186
- const prevHtmlOverflow = html.style.overflow;
6187
- const prevBodyOverflow = body.style.overflow;
6188
- const prevHtmlOverscroll = html.style.overscrollBehavior;
6189
- const prevBodyOverscroll = body.style.overscrollBehavior;
6190
- html.style.overflow = "hidden";
6191
- body.style.overflow = "hidden";
6192
- html.style.overscrollBehavior = "none";
6193
- body.style.overscrollBehavior = "none";
6194
- const canScrollElement = (el, deltaY) => {
6195
- const { overflowY } = getComputedStyle(el);
6196
- if (overflowY !== "auto" && overflowY !== "scroll") return false;
6197
- if (el.scrollHeight <= el.clientHeight + 1) return false;
6198
- if (deltaY < 0) return el.scrollTop > 0;
6199
- if (deltaY > 0)
6200
- return el.scrollTop + el.clientHeight < el.scrollHeight - 1;
6201
- return true;
6202
- };
6203
- const allowsInternalScroll = (e) => {
6204
- const target = e.target;
6205
- if (!(target instanceof Element)) return false;
6206
- const scrollRoot = target.closest(
6207
- "[data-ohw-link-page-dropdown], [data-ohw-allow-scroll]"
6208
- );
6209
- if (!scrollRoot) return false;
6210
- const deltaY = e instanceof WheelEvent ? e.deltaY : 0;
6211
- return canScrollElement(scrollRoot, deltaY);
6212
- };
6213
- const preventBackgroundScroll = (e) => {
6214
- if (allowsInternalScroll(e)) return;
6215
- e.preventDefault();
6216
- };
6217
- const scrollOpts = { passive: false, capture: true };
6218
- document.addEventListener("wheel", preventBackgroundScroll, scrollOpts);
6219
- document.addEventListener("touchmove", preventBackgroundScroll, scrollOpts);
6220
- return () => {
6221
- postToParent({ type: "ui:unlock" });
6222
- html.style.overflow = prevHtmlOverflow;
6223
- body.style.overflow = prevBodyOverflow;
6224
- html.style.overscrollBehavior = prevHtmlOverscroll;
6225
- body.style.overscrollBehavior = prevBodyOverscroll;
6226
- document.removeEventListener(
6227
- "wheel",
6228
- preventBackgroundScroll,
6229
- scrollOpts
6230
- );
6231
- document.removeEventListener(
6232
- "touchmove",
6233
- preventBackgroundScroll,
6234
- scrollOpts
6235
- );
6236
- };
6237
- }, [open, sectionPickerActive]);
6238
- return /* @__PURE__ */ jsxs13(Fragment4, { children: [
6239
- /* @__PURE__ */ jsx21(
6240
- Dialog2,
6241
- {
6242
- open: open && !sectionPickerActive,
6243
- onOpenChange: (next) => {
6244
- if (!next) onClose?.();
6245
- },
6246
- children: /* @__PURE__ */ jsx21(
6247
- DialogContent,
6248
- {
6249
- ref: panelRef,
6250
- container: portalContainer,
6251
- "data-ohw-link-popover-root": "",
6252
- "data-ohw-link-modal-root": "",
6253
- "data-ohw-bridge": "",
6254
- showCloseButton: false,
6255
- className: "gap-0 p-0 w-full max-w-[448px] pointer-events-auto z-[2147483646] overflow-visible",
6256
- children: /* @__PURE__ */ jsx21(LinkEditorPanel, { state, onClose })
6257
- }
6258
- )
6259
- }
6260
- ),
6261
- sectionPickerActive && state.selectedPage ? /* @__PURE__ */ jsx21(
6262
- SectionPickerOverlay,
5557
+ const isCancel = state.secondaryLabel === "Cancel";
5558
+ return /* @__PURE__ */ jsxs11(Fragment3, { children: [
5559
+ /* @__PURE__ */ jsx19(DialogClose, { asChild: true, children: /* @__PURE__ */ jsx19(
5560
+ "button",
6263
5561
  {
6264
- pagePath: state.selectedPage.path,
6265
- sections: state.activeSections,
6266
- onBack: state.handleSectionPickerBack,
6267
- onSelect: state.handleSectionSelect
5562
+ type: "button",
5563
+ className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
5564
+ "aria-label": "Close",
5565
+ children: /* @__PURE__ */ jsx19(IconX, { "aria-hidden": true })
6268
5566
  }
6269
- ) : null
5567
+ ) }),
5568
+ /* @__PURE__ */ jsx19(DialogHeader, { className: "w-full gap-1.5 p-6 pr-12", children: /* @__PURE__ */ jsx19(DialogTitle, { className: "m-0 w-full break-words", children: state.title }) }),
5569
+ /* @__PURE__ */ jsxs11("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
5570
+ state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ jsx19(
5571
+ DestinationBreadcrumb,
5572
+ {
5573
+ pageTitle: state.selectedPage.title,
5574
+ sectionLabel: state.selectedSection.label
5575
+ }
5576
+ ) : /* @__PURE__ */ jsx19(
5577
+ UrlOrPageInput,
5578
+ {
5579
+ value: state.searchValue,
5580
+ selectedPage: state.selectedPage,
5581
+ dropdownOpen: state.dropdownOpen,
5582
+ onDropdownOpenChange: state.setDropdownOpen,
5583
+ filteredPages: state.filteredPages,
5584
+ onInputChange: state.handleInputChange,
5585
+ onPageSelect: state.handlePageSelect,
5586
+ urlError: state.urlError
5587
+ }
5588
+ ),
5589
+ state.showChooseSection ? /* @__PURE__ */ jsxs11("div", { className: "flex flex-col justify-center gap-2", children: [
5590
+ /* @__PURE__ */ jsx19(Button, { type: "button", variant: "outline", className: "w-fit cursor-pointer", size: "sm", onClick: state.handleChooseSection, children: "Choose a section" }),
5591
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
5592
+ /* @__PURE__ */ jsx19(IconInfo, { className: "shrink-0", "aria-hidden": true }),
5593
+ /* @__PURE__ */ jsx19("span", { children: "Pick a section this link should scroll to." })
5594
+ ] })
5595
+ ] }) : null,
5596
+ state.showSectionPicker ? /* @__PURE__ */ jsx19(SectionPickerList, { sections: state.activeSections, onSelect: state.handleSectionSelect }) : null,
5597
+ state.showSectionRow && state.selectedSection ? /* @__PURE__ */ jsx19(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
5598
+ ] }),
5599
+ /* @__PURE__ */ jsxs11(DialogFooter, { className: "w-full px-6 pb-6", children: [
5600
+ /* @__PURE__ */ jsx19(
5601
+ Button,
5602
+ {
5603
+ type: "button",
5604
+ variant: isCancel ? "outline" : "ghost",
5605
+ className: "leading-6 shadow-none cursor-pointer",
5606
+ style: isCancel ? {
5607
+ backgroundColor: "var(--ohw-background)",
5608
+ borderColor: "var(--ohw-border)",
5609
+ color: "var(--ohw-foreground)"
5610
+ } : void 0,
5611
+ onClick: state.handleSecondary,
5612
+ children: state.secondaryLabel
5613
+ }
5614
+ ),
5615
+ /* @__PURE__ */ jsx19(
5616
+ Button,
5617
+ {
5618
+ type: "button",
5619
+ className: "border-0 leading-6 shadow-none hover:opacity-90 disabled:opacity-50 cursor-pointer",
5620
+ style: {
5621
+ backgroundColor: "var(--ohw-primary)",
5622
+ color: "var(--ohw-primary-foreground)"
5623
+ },
5624
+ disabled: !state.isValid,
5625
+ onClick: state.handleSubmit,
5626
+ children: state.submitLabel
5627
+ }
5628
+ )
5629
+ ] })
6270
5630
  ] });
6271
5631
  }
6272
5632
 
5633
+ // src/ui/link-modal/LinkPopover.tsx
5634
+ import { jsx as jsx20 } from "react/jsx-runtime";
5635
+ function LinkPopover({
5636
+ open = true,
5637
+ panelRef,
5638
+ portalContainer,
5639
+ onClose,
5640
+ ...editorProps
5641
+ }) {
5642
+ return /* @__PURE__ */ jsx20(
5643
+ Dialog2,
5644
+ {
5645
+ open,
5646
+ onOpenChange: (next) => {
5647
+ if (!next) onClose?.();
5648
+ },
5649
+ children: /* @__PURE__ */ jsx20(
5650
+ DialogContent,
5651
+ {
5652
+ ref: panelRef,
5653
+ container: portalContainer,
5654
+ "data-ohw-link-popover-root": "",
5655
+ "data-ohw-link-modal-root": "",
5656
+ "data-ohw-bridge": "",
5657
+ showCloseButton: false,
5658
+ className: "gap-0 p-0 w-full md:w-md pointer-events-auto",
5659
+ children: /* @__PURE__ */ jsx20(LinkEditorPanel, { ...editorProps, open, onClose })
5660
+ }
5661
+ )
5662
+ }
5663
+ );
5664
+ }
5665
+
6273
5666
  // src/ui/link-modal/devFixtures.ts
6274
5667
  var DEV_SITE_PAGES = [
6275
5668
  { path: "/", title: "Home" },
@@ -6288,767 +5681,48 @@ var DEV_SECTIONS_BY_PATH = {
6288
5681
  { id: "feel-split", label: "Feel Split" },
6289
5682
  { id: "founder-teaser", label: "Founder" },
6290
5683
  { id: "plan-form", label: "Plan Form" },
6291
- { id: "testimonials", label: "Testimonials" },
6292
- { id: "wordmark", label: "Wordmark" },
6293
- { id: "footer", label: "Footer" }
6294
- ],
6295
- "/about": [
6296
- { id: "manifesto", label: "Manifesto" },
6297
- { id: "story-letter", label: "Our Story" },
6298
- { id: "lagree-explainer", label: "Lagree Explainer" },
6299
- { id: "waitlist-cta", label: "Waitlist" },
6300
- { id: "personal-training", label: "Personal training" },
6301
- { id: "footer", label: "Footer" }
6302
- ],
6303
- "/classes": [
6304
- { id: "class-library", label: "Class Library" },
6305
- { id: "footer", label: "Footer" }
6306
- ],
6307
- "/pricing": [
6308
- { id: "page-header", label: "Page Header" },
6309
- { id: "free-class-cta", label: "Free Class" },
6310
- { id: "benefits-marquee", label: "Benefits" },
6311
- { id: "monthly-memberships", label: "Memberships" },
6312
- { id: "specialty-programs", label: "Specialty Programs" },
6313
- { id: "package-matcher", label: "Packages" },
6314
- { id: "wordmark", label: "Wordmark" },
6315
- { id: "footer", label: "Footer" }
6316
- ],
6317
- "/studio": [
6318
- { id: "studio-intro", label: "Studio Intro" },
6319
- { id: "studio-features", label: "Studio Features" },
6320
- { id: "studio-gallery", label: "Studio Gallery" },
6321
- { id: "studio-visit", label: "Visit Studio" },
6322
- { id: "footer", label: "Footer" }
6323
- ],
6324
- "/instructors": [
6325
- { id: "instructor-grid", label: "Instructors" },
6326
- { id: "footer", label: "Footer" }
6327
- ],
6328
- "/contact": [
6329
- { id: "hello-hero", label: "Hello" },
6330
- { id: "contact-form", label: "Contact Form" },
6331
- { id: "faq", label: "FAQ" },
6332
- { id: "footer", label: "Footer" }
6333
- ]
6334
- };
6335
- function shouldUseDevFixtures() {
6336
- if (typeof window === "undefined") return false;
6337
- const raw = readPreservedSearch();
6338
- const q = raw.startsWith("?") ? raw.slice(1) : raw;
6339
- return new URLSearchParams(q).get("ohw-fixtures") === "1";
6340
- }
6341
-
6342
- // src/lib/nav-items.ts
6343
- var NAV_COUNT_KEY = "__ohw_nav_count";
6344
- var NAV_ORDER_KEY = "__ohw_nav_order";
6345
- function getLinkHref(el) {
6346
- const key = el.getAttribute("data-ohw-href-key");
6347
- if (key) {
6348
- const stored = getStoredLinkHref(key);
6349
- if (stored !== void 0) return stored;
6350
- }
6351
- return el.getAttribute("href") ?? "";
6352
- }
6353
- function isNavbarButton(el) {
6354
- return el.hasAttribute("data-ohw-role") && el.getAttribute("data-ohw-role") === "navbar-button";
6355
- }
6356
- function isNavbarLinkItem(el) {
6357
- if (!el.matches("[data-ohw-href-key]")) return false;
6358
- if (isNavbarButton(el)) return false;
6359
- if (!el.querySelector('[data-ohw-editable="text"]')) return false;
6360
- return Boolean(el.closest("nav, [data-ohw-nav-container], [data-ohw-nav-drawer]"));
6361
- }
6362
- function getNavbarDesktopContainer() {
6363
- return document.querySelector("[data-ohw-nav-container]");
6364
- }
6365
- function getNavbarDrawerContainer() {
6366
- return document.querySelector("[data-ohw-nav-drawer]");
6367
- }
6368
- function listNavbarItems() {
6369
- const desktop = getNavbarDesktopContainer();
6370
- if (desktop) {
6371
- return Array.from(desktop.querySelectorAll("[data-ohw-href-key]")).filter(isNavbarLinkItem);
6372
- }
6373
- const drawer = getNavbarDrawerContainer();
6374
- if (drawer) {
6375
- return Array.from(drawer.querySelectorAll("[data-ohw-href-key]")).filter(isNavbarLinkItem);
6376
- }
6377
- return Array.from(document.querySelectorAll("nav [data-ohw-href-key]")).filter(isNavbarLinkItem);
6378
- }
6379
- function parseNavIndexFromKey(key) {
6380
- if (!key) return null;
6381
- const match = key.match(/^nav-(\d+)-href$/);
6382
- if (!match) return null;
6383
- return parseInt(match[1], 10);
6384
- }
6385
- function getNavbarIndicesInDom() {
6386
- const indices = /* @__PURE__ */ new Set();
6387
- for (const item of listNavbarItems()) {
6388
- const idx = parseNavIndexFromKey(item.getAttribute("data-ohw-href-key"));
6389
- if (idx !== null) indices.add(idx);
6390
- }
6391
- return [...indices].sort((a, b) => a - b);
6392
- }
6393
- function getNextNavbarIndex() {
6394
- const indices = getNavbarIndicesInDom();
6395
- if (indices.length === 0) return 0;
6396
- return Math.max(...indices) + 1;
6397
- }
6398
- function getNavbarExistingTargets() {
6399
- return listNavbarItems().map((el) => getLinkHref(el)).filter(Boolean);
6400
- }
6401
- function getNavOrderFromDom() {
6402
- return listNavbarItems().map((el) => el.getAttribute("data-ohw-href-key")).filter((key) => Boolean(key));
6403
- }
6404
- function parseNavOrder(content) {
6405
- const raw = content[NAV_ORDER_KEY];
6406
- if (!raw) return null;
6407
- try {
6408
- const parsed = JSON.parse(raw);
6409
- if (!Array.isArray(parsed)) return null;
6410
- return parsed.filter((key) => typeof key === "string" && key.length > 0);
6411
- } catch {
6412
- return null;
6413
- }
6414
- }
6415
- function findCounterpartByHrefKey(hrefKey, root) {
6416
- return root.querySelector(`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`);
6417
- }
6418
- function cloneNavLinkShell(template) {
6419
- const anchor = document.createElement("a");
6420
- if (template) {
6421
- anchor.style.cssText = template.style.cssText;
6422
- if (template.className) anchor.className = template.className;
6423
- }
6424
- anchor.style.cursor = "pointer";
6425
- anchor.style.textDecoration = "none";
6426
- return anchor;
6427
- }
6428
- function buildNavLink(index, href, label, template) {
6429
- const anchor = cloneNavLinkShell(template);
6430
- anchor.href = href;
6431
- anchor.setAttribute("data-ohw-href-key", `nav-${index}-href`);
6432
- const span = document.createElement("span");
6433
- span.setAttribute("data-ohw-editable", "text");
6434
- span.setAttribute("data-ohw-key", `nav-${index}-label`);
6435
- span.textContent = label;
6436
- anchor.appendChild(span);
6437
- return anchor;
6438
- }
6439
- function insertNavLinkInContainer(container, anchor, afterHrefKey) {
6440
- if (!afterHrefKey) {
6441
- container.appendChild(anchor);
6442
- return;
6443
- }
6444
- const afterEl = findCounterpartByHrefKey(afterHrefKey, container);
6445
- if (afterEl?.parentElement === container) {
6446
- afterEl.insertAdjacentElement("afterend", anchor);
6447
- return;
6448
- }
6449
- container.appendChild(anchor);
6450
- }
6451
- function insertNavbarItemDom(index, href, label, afterAnchor) {
6452
- const afterHrefKey = afterAnchor?.getAttribute("data-ohw-href-key") ?? null;
6453
- const desktopItems = getNavbarDesktopContainer()?.querySelectorAll("[data-ohw-href-key]") ?? [];
6454
- const drawerItems = getNavbarDrawerContainer()?.querySelectorAll("[data-ohw-href-key]") ?? [];
6455
- const desktopTemplate = Array.from(desktopItems).find(isNavbarLinkItem) ?? null;
6456
- const drawerTemplate = Array.from(drawerItems).find(isNavbarLinkItem) ?? null;
6457
- let primary = null;
6458
- const desktopContainer = getNavbarDesktopContainer();
6459
- if (desktopContainer) {
6460
- const desktopAnchor = buildNavLink(index, href, label, desktopTemplate);
6461
- insertNavLinkInContainer(desktopContainer, desktopAnchor, afterHrefKey);
6462
- primary = desktopAnchor;
6463
- }
6464
- const drawerContainer = getNavbarDrawerContainer();
6465
- if (drawerContainer) {
6466
- const drawerAnchor = buildNavLink(index, href, label, drawerTemplate);
6467
- insertNavLinkInContainer(drawerContainer, drawerAnchor, afterHrefKey);
6468
- if (!primary) primary = drawerAnchor;
6469
- }
6470
- if (!primary) {
6471
- const fallback = buildNavLink(index, href, label, listNavbarItems()[0] ?? null);
6472
- const nav = document.querySelector("nav");
6473
- nav?.appendChild(fallback);
6474
- primary = fallback;
6475
- }
6476
- return primary;
6477
- }
6478
- function applyNavOrderToContainer(container, order) {
6479
- const seen = /* @__PURE__ */ new Set();
6480
- for (const hrefKey of order) {
6481
- if (seen.has(hrefKey)) continue;
6482
- seen.add(hrefKey);
6483
- const el = findCounterpartByHrefKey(hrefKey, container);
6484
- if (el) container.appendChild(el);
6485
- }
6486
- for (const el of container.querySelectorAll("[data-ohw-href-key]")) {
6487
- if (!isNavbarLinkItem(el)) continue;
6488
- const key = el.getAttribute("data-ohw-href-key");
6489
- if (!key || seen.has(key)) continue;
6490
- container.appendChild(el);
6491
- }
6492
- }
6493
- function applyNavOrder(order) {
6494
- const desktop = getNavbarDesktopContainer();
6495
- if (desktop) applyNavOrderToContainer(desktop, order);
6496
- const drawer = getNavbarDrawerContainer();
6497
- if (drawer) applyNavOrderToContainer(drawer, order);
6498
- }
6499
- function collectNavbarIndicesFromContent(content) {
6500
- const indices = /* @__PURE__ */ new Set();
6501
- for (const key of Object.keys(content)) {
6502
- const idx = parseNavIndexFromKey(key);
6503
- if (idx !== null) indices.add(idx);
6504
- }
6505
- const countRaw = content[NAV_COUNT_KEY];
6506
- if (countRaw) {
6507
- const count = parseInt(countRaw, 10);
6508
- if (Number.isFinite(count) && count > 0) {
6509
- for (let i = 0; i < count; i++) indices.add(i);
6510
- }
6511
- }
6512
- return [...indices].sort((a, b) => a - b);
6513
- }
6514
- function navbarIndexExistsInDom(index) {
6515
- return document.querySelector(`[data-ohw-href-key="nav-${index}-href"]`) !== null;
6516
- }
6517
- function reconcileNavbarItemsFromContent(content) {
6518
- const indices = collectNavbarIndicesFromContent(content);
6519
- for (const index of indices) {
6520
- if (navbarIndexExistsInDom(index)) continue;
6521
- const href = content[`nav-${index}-href`];
6522
- const label = content[`nav-${index}-label`];
6523
- if (!href && !label) continue;
6524
- insertNavbarItemDom(index, href ?? "/", label ?? "Untitled", null);
6525
- }
6526
- const order = parseNavOrder(content);
6527
- if (order?.length) applyNavOrder(order);
6528
- }
6529
- function buildNavOrderAfterInsert(afterAnchor, newHrefKey) {
6530
- const order = getNavOrderFromDom();
6531
- if (!afterAnchor) {
6532
- if (!order.includes(newHrefKey)) order.push(newHrefKey);
6533
- return order;
6534
- }
6535
- const afterKey = afterAnchor.getAttribute("data-ohw-href-key");
6536
- if (!afterKey) {
6537
- if (!order.includes(newHrefKey)) order.push(newHrefKey);
6538
- return order;
6539
- }
6540
- const withoutNew = order.filter((key) => key !== newHrefKey);
6541
- const pos = withoutNew.indexOf(afterKey);
6542
- if (pos >= 0) {
6543
- withoutNew.splice(pos + 1, 0, newHrefKey);
6544
- return withoutNew;
6545
- }
6546
- withoutNew.push(newHrefKey);
6547
- return withoutNew;
6548
- }
6549
- function insertNavbarItem(href, label, afterAnchor = null) {
6550
- const index = getNextNavbarIndex();
6551
- const anchor = insertNavbarItemDom(index, href, label, afterAnchor);
6552
- if (!anchor) throw new Error("Failed to insert navbar item");
6553
- const hrefKey = `nav-${index}-href`;
6554
- const order = buildNavOrderAfterInsert(afterAnchor, hrefKey);
6555
- applyNavOrder(order);
6556
- return {
6557
- anchor,
6558
- index,
6559
- hrefKey,
6560
- labelKey: `nav-${index}-label`,
6561
- href,
6562
- label,
6563
- order
6564
- };
6565
- }
6566
-
6567
- // src/lib/footer-items.ts
6568
- var FOOTER_ORDER_KEY = "__ohw_footer_order";
6569
- var FOOTER_HREF_RE = /^footer-(\d+)-(\d+)-href$/;
6570
- function parseFooterHrefKey(key) {
6571
- if (!key) return null;
6572
- const match = key.match(FOOTER_HREF_RE);
6573
- if (!match) return null;
6574
- return { col: parseInt(match[1], 10), item: parseInt(match[2], 10) };
6575
- }
6576
- function isFooterHrefKey(key) {
6577
- return parseFooterHrefKey(key) !== null;
6578
- }
6579
- function getFooterRoot() {
6580
- return document.querySelector('footer[data-ohw-section="footer"], footer');
6581
- }
6582
- function getFooterLinksContainer() {
6583
- return document.querySelector("[data-ohw-footer-links]") ?? document.querySelector(".rb-footer-links");
6584
- }
6585
- function isFooterLinkAnchor(el) {
6586
- if (!el.matches("[data-ohw-href-key]")) return false;
6587
- if (!isFooterHrefKey(el.getAttribute("data-ohw-href-key"))) return false;
6588
- return Boolean(el.querySelector('[data-ohw-editable="text"]'));
6589
- }
6590
- function listFooterColumns() {
6591
- const root = getFooterLinksContainer() ?? getFooterRoot()?.querySelector(".rb-footer-links") ?? null;
6592
- if (!root) return [];
6593
- const explicit = Array.from(root.querySelectorAll(":scope > [data-ohw-footer-col]"));
6594
- if (explicit.length > 0) return explicit;
6595
- return Array.from(root.children).filter((el) => {
6596
- if (!(el instanceof HTMLElement)) return false;
6597
- return Array.from(el.querySelectorAll(":scope > [data-ohw-href-key]")).some(
6598
- isFooterLinkAnchor
6599
- );
6600
- });
6601
- }
6602
- function listFooterLinksInColumn(column) {
6603
- return Array.from(column.querySelectorAll(":scope > [data-ohw-href-key]")).filter(
6604
- isFooterLinkAnchor
6605
- );
6606
- }
6607
- function findFooterColumnForLink(anchor) {
6608
- const columns = listFooterColumns();
6609
- return columns.find((col) => col.contains(anchor)) ?? null;
6610
- }
6611
- function getFooterOrderFromDom() {
6612
- return listFooterColumns().map(
6613
- (col) => listFooterLinksInColumn(col).map((el) => el.getAttribute("data-ohw-href-key")).filter((key) => Boolean(key))
6614
- );
6615
- }
6616
- function findFooterLinkByKey(hrefKey) {
6617
- return document.querySelector(
6618
- `footer [data-ohw-href-key="${CSS.escape(hrefKey)}"]`
6619
- );
6620
- }
6621
- function syncFooterColumnIndices(columns) {
6622
- columns.forEach((col, index) => {
6623
- const next = String(index);
6624
- if (col.getAttribute("data-ohw-footer-col") !== next) {
6625
- col.setAttribute("data-ohw-footer-col", next);
6626
- }
6627
- });
6628
- }
6629
- function appendChildIfNeeded(parent, child) {
6630
- if (parent.lastElementChild !== child) {
6631
- parent.appendChild(child);
6632
- }
6633
- }
6634
- function insertLinkBeforeNext(col, el, nextEl) {
6635
- if (nextEl) {
6636
- if (el.nextElementSibling !== nextEl) {
6637
- col.insertBefore(el, nextEl);
6638
- }
6639
- return;
6640
- }
6641
- if (col.lastElementChild !== el) {
6642
- col.appendChild(el);
6643
- }
6644
- }
6645
- function applyFooterOrder(order) {
6646
- const container = getFooterLinksContainer();
6647
- if (!container) return;
6648
- const columns = listFooterColumns();
6649
- if (columns.length === 0) return;
6650
- const currentOrder = getFooterOrderFromDom();
6651
- if (ordersEqual(order, currentOrder)) {
6652
- syncFooterColumnIndices(columns);
6653
- return;
6654
- }
6655
- const colCount = Math.max(columns.length, order.length);
6656
- const working = columns.slice(0, colCount);
6657
- for (let i = 0; i < order.length && i < working.length; i++) {
6658
- appendChildIfNeeded(container, working[i]);
6659
- }
6660
- for (let i = order.length; i < working.length; i++) {
6661
- appendChildIfNeeded(container, working[i]);
6662
- }
6663
- const freshColumns = listFooterColumns();
6664
- syncFooterColumnIndices(freshColumns);
6665
- for (let c = 0; c < order.length; c++) {
6666
- const col = freshColumns[c];
6667
- if (!col) continue;
6668
- const colOrder = order[c];
6669
- for (let j = 0; j < colOrder.length; j++) {
6670
- const hrefKey = colOrder[j];
6671
- const el = findFooterLinkByKey(hrefKey);
6672
- if (!el) continue;
6673
- if (el.parentElement !== col) {
6674
- col.appendChild(el);
6675
- }
6676
- const nextKey = colOrder[j + 1];
6677
- const nextEl = nextKey ? findFooterLinkByKey(nextKey) : null;
6678
- insertLinkBeforeNext(col, el, nextEl?.parentElement === col ? nextEl : null);
6679
- }
6680
- }
6681
- }
6682
- function ordersEqual(a, b) {
6683
- if (a.length !== b.length) return false;
6684
- for (let i = 0; i < a.length; i++) {
6685
- const left = a[i];
6686
- const right = b[i];
6687
- if (left.length !== right.length) return false;
6688
- for (let j = 0; j < left.length; j++) {
6689
- if (left[j] !== right[j]) return false;
6690
- }
6691
- }
6692
- return true;
6693
- }
6694
- function planFooterLinkMove(hrefKey, targetColIndex, insertIndex) {
6695
- const order = getFooterOrderFromDom();
6696
- if (targetColIndex < 0 || targetColIndex >= order.length) return null;
6697
- let fromCol = -1;
6698
- let fromIdx = -1;
6699
- for (let c = 0; c < order.length; c++) {
6700
- const idx = order[c].indexOf(hrefKey);
6701
- if (idx >= 0) {
6702
- fromCol = c;
6703
- fromIdx = idx;
6704
- break;
6705
- }
6706
- }
6707
- if (fromCol < 0) return null;
6708
- const next = order.map((col) => [...col]);
6709
- next[fromCol].splice(fromIdx, 1);
6710
- let adjusted = insertIndex;
6711
- if (fromCol === targetColIndex && fromIdx < insertIndex) adjusted -= 1;
6712
- adjusted = Math.max(0, Math.min(adjusted, next[targetColIndex].length));
6713
- next[targetColIndex].splice(adjusted, 0, hrefKey);
6714
- if (ordersEqual(next, order)) return null;
6715
- return next;
6716
- }
6717
- function planFooterColumnMove(fromIndex, toIndex) {
6718
- const order = getFooterOrderFromDom();
6719
- const columns = listFooterColumns();
6720
- if (fromIndex < 0 || fromIndex >= columns.length || toIndex < 0 || toIndex > columns.length) {
6721
- return null;
6722
- }
6723
- if (toIndex === fromIndex || toIndex === fromIndex + 1) return null;
6724
- const nextOrder = order.map((col) => [...col]);
6725
- const [movedOrder] = nextOrder.splice(fromIndex, 1);
6726
- if (!movedOrder) return null;
6727
- let adjusted = toIndex;
6728
- if (fromIndex < toIndex) adjusted -= 1;
6729
- adjusted = Math.max(0, Math.min(adjusted, nextOrder.length));
6730
- nextOrder.splice(adjusted, 0, movedOrder);
6731
- if (ordersEqual(nextOrder, order)) return null;
6732
- return nextOrder;
6733
- }
6734
- function parseFooterOrder(content) {
6735
- const raw = content[FOOTER_ORDER_KEY];
6736
- if (!raw) return null;
6737
- try {
6738
- const parsed = JSON.parse(raw);
6739
- if (!Array.isArray(parsed)) return null;
6740
- return parsed.filter((col) => Array.isArray(col)).map((col) => col.filter((key) => typeof key === "string" && key.length > 0));
6741
- } catch {
6742
- return null;
6743
- }
6744
- }
6745
- function reconcileFooterOrderFromContent(content) {
6746
- const order = parseFooterOrder(content);
6747
- if (!order?.length) return;
6748
- const current = getFooterOrderFromDom();
6749
- if (ordersEqual(order, current)) {
6750
- syncFooterColumnIndices(listFooterColumns());
6751
- return;
6752
- }
6753
- applyFooterOrder(order);
6754
- }
6755
- function buildLinkDropSlots(column, columnIndex) {
6756
- const links = listFooterLinksInColumn(column);
6757
- const colRect = column.getBoundingClientRect();
6758
- const slots = [];
6759
- const barThickness = 3;
6760
- if (links.length === 0) {
6761
- slots.push({
6762
- insertIndex: 0,
6763
- columnIndex,
6764
- left: colRect.left,
6765
- top: colRect.top + colRect.height / 2 - barThickness / 2,
6766
- width: colRect.width,
6767
- height: barThickness,
6768
- direction: "horizontal"
6769
- });
6770
- return slots;
6771
- }
6772
- for (let i = 0; i <= links.length; i++) {
6773
- let top;
6774
- if (i === 0) {
6775
- top = links[0].getBoundingClientRect().top - barThickness / 2;
6776
- } else if (i === links.length) {
6777
- const last = links[links.length - 1].getBoundingClientRect();
6778
- top = last.bottom - barThickness / 2;
6779
- } else {
6780
- const prev = links[i - 1].getBoundingClientRect();
6781
- const next = links[i].getBoundingClientRect();
6782
- top = (prev.bottom + next.top) / 2 - barThickness / 2;
6783
- }
6784
- const widthRef = i === 0 ? links[0].getBoundingClientRect() : i === links.length ? links[links.length - 1].getBoundingClientRect() : links[i].getBoundingClientRect();
6785
- slots.push({
6786
- insertIndex: i,
6787
- columnIndex,
6788
- left: widthRef.left,
6789
- top,
6790
- width: Math.max(widthRef.width, colRect.width * 0.8),
6791
- height: barThickness,
6792
- direction: "horizontal"
6793
- });
6794
- }
6795
- return slots;
6796
- }
6797
- function buildColumnDropSlots() {
6798
- const columns = listFooterColumns();
6799
- const slots = [];
6800
- const barThickness = 3;
6801
- if (columns.length === 0) return slots;
6802
- for (let i = 0; i <= columns.length; i++) {
6803
- let left;
6804
- let height;
6805
- let top;
6806
- if (i === 0) {
6807
- const first = columns[0].getBoundingClientRect();
6808
- left = first.left - barThickness / 2;
6809
- top = first.top;
6810
- height = first.height;
6811
- } else if (i === columns.length) {
6812
- const last = columns[columns.length - 1].getBoundingClientRect();
6813
- left = last.right - barThickness / 2;
6814
- top = last.top;
6815
- height = last.height;
6816
- } else {
6817
- const prev = columns[i - 1].getBoundingClientRect();
6818
- const next = columns[i].getBoundingClientRect();
6819
- left = (prev.right + next.left) / 2 - barThickness / 2;
6820
- top = Math.min(prev.top, next.top);
6821
- height = Math.max(prev.bottom, next.bottom) - top;
6822
- }
6823
- slots.push({
6824
- insertIndex: i,
6825
- columnIndex: i,
6826
- left,
6827
- top,
6828
- width: barThickness,
6829
- height: Math.max(height, 24),
6830
- direction: "vertical"
6831
- });
6832
- }
6833
- return slots;
6834
- }
6835
- function hitTestLinkDropSlot(clientX, clientY, draggedHrefKey) {
6836
- const columns = listFooterColumns();
6837
- let best = null;
6838
- for (let c = 0; c < columns.length; c++) {
6839
- const col = columns[c];
6840
- const colRect = col.getBoundingClientRect();
6841
- const inColX = clientX >= colRect.left - 24 && clientX <= colRect.right + 24;
6842
- if (!inColX) continue;
6843
- const slots = buildLinkDropSlots(col, c).filter((slot) => {
6844
- const links = listFooterLinksInColumn(col);
6845
- const fromIdx = links.findIndex(
6846
- (el) => el.getAttribute("data-ohw-href-key") === draggedHrefKey
6847
- );
6848
- if (fromIdx < 0) return true;
6849
- if (c === findColumnIndexForKey(draggedHrefKey) && (slot.insertIndex === fromIdx || slot.insertIndex === fromIdx + 1)) {
6850
- return true;
6851
- }
6852
- return true;
6853
- });
6854
- for (const slot of slots) {
6855
- const cy = slot.top + slot.height / 2;
6856
- const dist = Math.abs(clientY - cy) + (inColX ? 0 : 1e3);
6857
- if (!best || dist < best.dist) best = { slot, dist };
6858
- }
6859
- }
6860
- return best?.slot ?? null;
6861
- }
6862
- function findColumnIndexForKey(hrefKey) {
6863
- const order = getFooterOrderFromDom();
6864
- for (let c = 0; c < order.length; c++) {
6865
- if (order[c].includes(hrefKey)) return c;
6866
- }
6867
- return -1;
6868
- }
6869
- function hitTestColumnDropSlot(clientX, _clientY) {
6870
- const slots = buildColumnDropSlots();
6871
- let best = null;
6872
- for (const slot of slots) {
6873
- const cx2 = slot.left + slot.width / 2;
6874
- const dist = Math.abs(clientX - cx2);
6875
- if (!best || dist < best.dist) best = { slot, dist };
6876
- }
6877
- return best?.slot ?? null;
6878
- }
6879
-
6880
- // src/lib/carousel.ts
6881
- import { useEffect as useEffect7, useState as useState6 } from "react";
6882
- var CAROUSEL_ATTR = "data-ohw-carousel";
6883
- var CAROUSEL_VALUE_ATTR = "data-ohw-carousel-value";
6884
- var CAROUSEL_SLIDE_ATTR = "data-ohw-carousel-slide";
6885
- var CAROUSEL_EVENT = "ohw:carousel-change";
6886
- function listCarouselKeys() {
6887
- const keys = /* @__PURE__ */ new Set();
6888
- document.querySelectorAll(`[${CAROUSEL_ATTR}]`).forEach((el) => {
6889
- const key = el.getAttribute("data-ohw-key");
6890
- if (key) keys.add(key);
6891
- });
6892
- return [...keys];
6893
- }
6894
- function containersForKey(key) {
6895
- return Array.from(
6896
- document.querySelectorAll(`[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`)
6897
- );
6898
- }
6899
- function isCarouselKey(key) {
6900
- return containersForKey(key).length > 0;
6901
- }
6902
- function parseSlides(raw) {
6903
- if (!raw) return [];
6904
- try {
6905
- const parsed = JSON.parse(raw);
6906
- if (!Array.isArray(parsed)) return [];
6907
- return parsed.filter((s) => Boolean(s) && typeof s === "object").map((s) => ({ src: String(s.src ?? ""), alt: String(s.alt ?? "") }));
6908
- } catch {
6909
- return [];
6910
- }
6911
- }
6912
- function readCarouselValue(key) {
6913
- const container = containersForKey(key)[0];
6914
- if (!container) return [];
6915
- const fromAttr = parseSlides(container.getAttribute(CAROUSEL_VALUE_ATTR));
6916
- if (fromAttr.length > 0) return fromAttr;
6917
- return Array.from(container.querySelectorAll(`[${CAROUSEL_SLIDE_ATTR}]`)).filter((slide) => slide.closest(`[${CAROUSEL_ATTR}]`) === container).sort((a, b) => slideIndex(a) - slideIndex(b)).map((slide) => {
6918
- const img = slide instanceof HTMLImageElement ? slide : slide.querySelector("img");
6919
- return { src: img?.src ?? "", alt: img?.alt ?? "" };
6920
- });
6921
- }
6922
- function slideIndex(el) {
6923
- const raw = el.getAttribute(CAROUSEL_SLIDE_ATTR);
6924
- const n = raw ? parseInt(raw, 10) : NaN;
6925
- return Number.isFinite(n) ? n : 0;
6926
- }
6927
- function applyCarouselValue(key, slides) {
6928
- const value = JSON.stringify(slides);
6929
- for (const container of containersForKey(key)) {
6930
- if (container.getAttribute(CAROUSEL_VALUE_ATTR) === value) continue;
6931
- container.setAttribute(CAROUSEL_VALUE_ATTR, value);
6932
- container.dispatchEvent(
6933
- new CustomEvent(CAROUSEL_EVENT, { detail: { images: slides } })
6934
- );
6935
- }
6936
- }
6937
- function applyCarouselNode(key, val) {
6938
- if (!isCarouselKey(key)) return false;
6939
- applyCarouselValue(key, parseSlides(val));
6940
- return true;
6941
- }
6942
- function useOhwCarousel(key, initial) {
6943
- const [images, setImages] = useState6(initial);
6944
- useEffect7(() => {
6945
- const el = document.querySelector(
6946
- `[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`
6947
- );
6948
- if (!el) return;
6949
- const onChange = (e) => {
6950
- const detail = e.detail;
6951
- if (Array.isArray(detail?.images)) setImages(detail.images);
6952
- };
6953
- el.addEventListener(CAROUSEL_EVENT, onChange);
6954
- return () => el.removeEventListener(CAROUSEL_EVENT, onChange);
6955
- }, [key]);
6956
- const bind = {
6957
- [CAROUSEL_ATTR]: "",
6958
- "data-ohw-key": key,
6959
- [CAROUSEL_VALUE_ATTR]: JSON.stringify(images)
6960
- };
6961
- return { images, setImages, bind };
6962
- }
6963
-
6964
- // src/ui/navbar-container-chrome.tsx
6965
- import { Plus as Plus2 } from "lucide-react";
6966
- import { jsx as jsx22 } from "react/jsx-runtime";
6967
- function NavbarContainerChrome({
6968
- rect,
6969
- onAdd
6970
- }) {
6971
- const chromeGap = 6;
6972
- return /* @__PURE__ */ jsx22(
6973
- "div",
6974
- {
6975
- "data-ohw-navbar-container-chrome": "",
6976
- "data-ohw-bridge": "",
6977
- className: "pointer-events-none fixed z-[2147483647]",
6978
- style: {
6979
- top: rect.top - chromeGap,
6980
- left: rect.left - chromeGap,
6981
- width: rect.width + chromeGap * 2,
6982
- height: rect.height + chromeGap * 2
6983
- },
6984
- children: /* @__PURE__ */ jsx22(
6985
- "button",
6986
- {
6987
- type: "button",
6988
- "data-ohw-navbar-add-button": "",
6989
- 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",
6990
- style: { top: "70%" },
6991
- "aria-label": "Add item",
6992
- onMouseDown: (e) => {
6993
- e.preventDefault();
6994
- e.stopPropagation();
6995
- },
6996
- onClick: (e) => {
6997
- e.preventDefault();
6998
- e.stopPropagation();
6999
- onAdd();
7000
- },
7001
- children: /* @__PURE__ */ jsx22(Plus2, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
7002
- }
7003
- )
7004
- }
7005
- );
5684
+ { id: "testimonials", label: "Testimonials" },
5685
+ { id: "wordmark", label: "Wordmark" }
5686
+ ],
5687
+ "/about": [
5688
+ { id: "manifesto", label: "Manifesto" },
5689
+ { id: "story-letter", label: "Our Story" },
5690
+ { id: "lagree-explainer", label: "Lagree Explainer" },
5691
+ { id: "waitlist-cta", label: "Waitlist" },
5692
+ { id: "personal-training", label: "Personal training" }
5693
+ ],
5694
+ "/classes": [{ id: "class-library", label: "Class Library" }],
5695
+ "/pricing": [
5696
+ { id: "page-header", label: "Page Header" },
5697
+ { id: "free-class-cta", label: "Free Class" },
5698
+ { id: "benefits-marquee", label: "Benefits" },
5699
+ { id: "monthly-memberships", label: "Memberships" },
5700
+ { id: "specialty-programs", label: "Specialty Programs" },
5701
+ { id: "package-matcher", label: "Packages" },
5702
+ { id: "wordmark", label: "Wordmark" }
5703
+ ],
5704
+ "/studio": [
5705
+ { id: "studio-intro", label: "Studio Intro" },
5706
+ { id: "studio-features", label: "Studio Features" },
5707
+ { id: "studio-gallery", label: "Studio Gallery" },
5708
+ { id: "studio-visit", label: "Visit Studio" }
5709
+ ],
5710
+ "/instructors": [{ id: "instructor-grid", label: "Instructors" }],
5711
+ "/contact": [
5712
+ { id: "hello-hero", label: "Hello" },
5713
+ { id: "contact-form", label: "Contact Form" },
5714
+ { id: "faq", label: "FAQ" }
5715
+ ]
5716
+ };
5717
+ function shouldUseDevFixtures() {
5718
+ if (typeof window === "undefined") return false;
5719
+ const raw = readPreservedSearch();
5720
+ const q = raw.startsWith("?") ? raw.slice(1) : raw;
5721
+ return new URLSearchParams(q).get("ohw-fixtures") === "1";
7006
5722
  }
7007
5723
 
7008
- // src/ui/drop-indicator.tsx
7009
- import * as React9 from "react";
7010
- import { jsx as jsx23 } from "react/jsx-runtime";
7011
- var dropIndicatorVariants = cva(
7012
- "ov-gap-line pointer-events-none shrink-0 transition-opacity duration-150",
7013
- {
7014
- variants: {
7015
- direction: {
7016
- vertical: "h-6 w-[3px]",
7017
- horizontal: "h-[3px] w-[200px]"
7018
- },
7019
- state: {
7020
- default: "opacity-0",
7021
- hover: "opacity-100",
7022
- dragIdle: "opacity-40",
7023
- dragActive: "opacity-100"
7024
- }
7025
- },
7026
- defaultVariants: {
7027
- direction: "vertical",
7028
- state: "default"
7029
- }
7030
- }
7031
- );
7032
- var DropIndicator = React9.forwardRef(
7033
- ({ className, direction, state, ...props }, ref) => {
7034
- return /* @__PURE__ */ jsx23(
7035
- "div",
7036
- {
7037
- ref,
7038
- "data-slot": "drop-indicator",
7039
- "data-direction": direction ?? "vertical",
7040
- "data-state": state ?? "default",
7041
- "aria-hidden": "true",
7042
- className: cn(dropIndicatorVariants({ direction, state }), className),
7043
- ...props
7044
- }
7045
- );
7046
- }
7047
- );
7048
- DropIndicator.displayName = "DropIndicator";
7049
-
7050
5724
  // src/ui/badge.tsx
7051
- import { jsx as jsx24 } from "react/jsx-runtime";
5725
+ import { jsx as jsx21 } from "react/jsx-runtime";
7052
5726
  var badgeVariants = cva(
7053
5727
  "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",
7054
5728
  {
@@ -7066,12 +5740,12 @@ var badgeVariants = cva(
7066
5740
  }
7067
5741
  );
7068
5742
  function Badge({ className, variant, ...props }) {
7069
- return /* @__PURE__ */ jsx24("div", { className: cn(badgeVariants({ variant }), className), ...props });
5743
+ return /* @__PURE__ */ jsx21("div", { className: cn(badgeVariants({ variant }), className), ...props });
7070
5744
  }
7071
5745
 
7072
5746
  // src/OhhwellsBridge.tsx
7073
5747
  import { Link as Link2 } from "lucide-react";
7074
- import { Fragment as Fragment5, jsx as jsx25, jsxs as jsxs14 } from "react/jsx-runtime";
5748
+ import { Fragment as Fragment4, jsx as jsx22, jsxs as jsxs12 } from "react/jsx-runtime";
7075
5749
  var PRIMARY2 = "#0885FE";
7076
5750
  var IMAGE_FADE_MS = 300;
7077
5751
  function runOpacityFade(el, onDone) {
@@ -7250,7 +5924,7 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
7250
5924
  const root = createRoot(container);
7251
5925
  flushSync(() => {
7252
5926
  root.render(
7253
- /* @__PURE__ */ jsx25(
5927
+ /* @__PURE__ */ jsx22(
7254
5928
  SchedulingWidget,
7255
5929
  {
7256
5930
  notifyOnConnect,
@@ -7290,7 +5964,7 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
7290
5964
  }
7291
5965
  }
7292
5966
  }
7293
- function getLinkHref2(el) {
5967
+ function getLinkHref(el) {
7294
5968
  const anchor = el instanceof HTMLAnchorElement ? el : el.querySelector("a");
7295
5969
  return anchor?.getAttribute("href") ?? "";
7296
5970
  }
@@ -7312,7 +5986,7 @@ function isDragHandleDisabled(el) {
7312
5986
  return raw === "true" || raw === "";
7313
5987
  });
7314
5988
  }
7315
- function collectEditableNodes(extraContent) {
5989
+ function collectEditableNodes() {
7316
5990
  const nodes = Array.from(document.querySelectorAll("[data-ohw-editable]")).map((el) => {
7317
5991
  if (el.dataset.ohwEditable === "image") {
7318
5992
  const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
@@ -7327,7 +6001,7 @@ function collectEditableNodes(extraContent) {
7327
6001
  return { key: el.dataset.ohwKey ?? "", type: "video", text: getVideoEl(el)?.src ?? "" };
7328
6002
  }
7329
6003
  if (el.dataset.ohwEditable === "link") {
7330
- return { key: el.dataset.ohwKey ?? "", type: "link", text: getLinkHref2(el) };
6004
+ return { key: el.dataset.ohwKey ?? "", type: "link", text: getLinkHref(el) };
7331
6005
  }
7332
6006
  return {
7333
6007
  key: el.dataset.ohwKey ?? "",
@@ -7338,16 +6012,8 @@ function collectEditableNodes(extraContent) {
7338
6012
  document.querySelectorAll("[data-ohw-href-key]").forEach((el) => {
7339
6013
  const key = el.getAttribute("data-ohw-href-key") ?? "";
7340
6014
  if (!key) return;
7341
- nodes.push({ key, type: "link", text: getLinkHref2(el) });
6015
+ nodes.push({ key, type: "link", text: getLinkHref(el) });
7342
6016
  });
7343
- if (extraContent) {
7344
- for (const key of [NAV_ORDER_KEY, FOOTER_ORDER_KEY, NAV_COUNT_KEY]) {
7345
- const text = extraContent[key];
7346
- if (typeof text === "string" && text.length > 0) {
7347
- nodes.push({ key, type: "meta", text });
7348
- }
7349
- }
7350
- }
7351
6017
  document.querySelectorAll('[data-ohw-editable="video"]').forEach((el) => {
7352
6018
  const key = el.dataset.ohwKey ?? "";
7353
6019
  const video = getVideoEl(el);
@@ -7355,9 +6021,6 @@ function collectEditableNodes(extraContent) {
7355
6021
  nodes.push({ key: `${key}${VIDEO_AUTOPLAY_SUFFIX}`, type: "video-setting", text: String(video.autoplay) });
7356
6022
  nodes.push({ key: `${key}${VIDEO_MUTED_SUFFIX}`, type: "video-setting", text: String(video.muted) });
7357
6023
  });
7358
- for (const key of listCarouselKeys()) {
7359
- nodes.push({ key, type: "carousel", text: JSON.stringify(readCarouselValue(key)) });
7360
- }
7361
6024
  return nodes;
7362
6025
  }
7363
6026
  function isMediaEditable(el) {
@@ -7435,7 +6098,7 @@ function applyLinkByKey(key, val) {
7435
6098
  }
7436
6099
  function isInsideLinkEditor(target) {
7437
6100
  return Boolean(
7438
- 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"]')
6101
+ 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"]')
7439
6102
  );
7440
6103
  }
7441
6104
  function getHrefKeyFromElement(el) {
@@ -7446,30 +6109,7 @@ function getHrefKeyFromElement(el) {
7446
6109
  if (!key) return null;
7447
6110
  return { anchor, key };
7448
6111
  }
7449
- function disableNativeHrefDrag(el) {
7450
- if (el.draggable) el.draggable = false;
7451
- if (el.getAttribute("draggable") !== "false") {
7452
- el.setAttribute("draggable", "false");
7453
- }
7454
- }
7455
- function clearTextSelection() {
7456
- const sel = window.getSelection();
7457
- if (sel && !sel.isCollapsed) sel.removeAllRanges();
7458
- }
7459
- function armFooterPressDrag() {
7460
- document.documentElement.setAttribute("data-ohw-footer-press-drag", "");
7461
- }
7462
- function lockFooterDuringDrag() {
7463
- document.documentElement.removeAttribute("data-ohw-footer-press-drag");
7464
- document.documentElement.setAttribute("data-ohw-item-dragging", "");
7465
- clearTextSelection();
7466
- }
7467
- function unlockFooterDragInteraction() {
7468
- document.documentElement.removeAttribute("data-ohw-footer-press-drag");
7469
- document.documentElement.removeAttribute("data-ohw-item-dragging");
7470
- clearTextSelection();
7471
- }
7472
- function isNavbarButton2(el) {
6112
+ function isNavbarButton(el) {
7473
6113
  return Boolean(el.closest('[data-ohw-role="navbar-button"]'));
7474
6114
  }
7475
6115
  function getNavigationItemAnchor(el) {
@@ -7481,8 +6121,19 @@ function getNavigationItemAnchor(el) {
7481
6121
  function isNavigationItem(el) {
7482
6122
  return getNavigationItemAnchor(el) !== null;
7483
6123
  }
6124
+ function getNavigationItemAddHintTarget(anchor) {
6125
+ const items = listNavigationItems();
6126
+ const idx = items.indexOf(anchor);
6127
+ if (idx >= 0 && idx < items.length - 1) return items[idx + 1];
6128
+ return anchor;
6129
+ }
6130
+ function listNavigationItems() {
6131
+ return Array.from(
6132
+ document.querySelectorAll("nav [data-ohw-href-key], footer [data-ohw-href-key]")
6133
+ ).filter((el) => isNavigationItem(el));
6134
+ }
7484
6135
  function getNavigationItemReorderState(anchor) {
7485
- if (isNavbarButton2(anchor)) return { key: null, disabled: false };
6136
+ if (isNavbarButton(anchor)) return { key: null, disabled: false };
7486
6137
  return getReorderHandleStateFromAnchor(anchor);
7487
6138
  }
7488
6139
  function getReorderHandleState(el) {
@@ -7504,120 +6155,6 @@ function clearHrefKeyHover(anchor) {
7504
6155
  function isInsideNavigationItem(el) {
7505
6156
  return getNavigationItemAnchor(el) !== null;
7506
6157
  }
7507
- function getNavigationRoot(el) {
7508
- const explicit = el.closest("[data-ohw-nav-root]");
7509
- if (explicit) return explicit;
7510
- return el.closest("nav, footer, aside");
7511
- }
7512
- function findFooterItemGroup(item) {
7513
- const footer = item.closest("footer");
7514
- if (!footer) return null;
7515
- let node = item.parentElement;
7516
- while (node && node !== footer) {
7517
- const hasDirectNavItems = Array.from(
7518
- node.querySelectorAll(":scope > [data-ohw-href-key]")
7519
- ).some(isNavigationItem);
7520
- if (hasDirectNavItems) return node;
7521
- node = node.parentElement;
7522
- }
7523
- return null;
7524
- }
7525
- function isNavigationRoot(el) {
7526
- return el.hasAttribute("data-ohw-nav-root") || el.matches("nav, footer, aside");
7527
- }
7528
- function isInferredFooterGroup(el) {
7529
- const footer = el.closest("footer");
7530
- if (!footer || el === footer) return false;
7531
- return Array.from(el.querySelectorAll(":scope > [data-ohw-href-key]")).some(isNavigationItem);
7532
- }
7533
- function isNavigationContainer(el) {
7534
- return el.hasAttribute("data-ohw-nav-container") || isNavigationRoot(el) || isInferredFooterGroup(el);
7535
- }
7536
- function isPointOverNavigation(x, y) {
7537
- const navRoot = document.querySelector("[data-ohw-nav-root]") ?? document.querySelector("nav");
7538
- if (!navRoot) return false;
7539
- const r2 = navRoot.getBoundingClientRect();
7540
- return x >= r2.left && x <= r2.right && y >= r2.top && y <= r2.bottom;
7541
- }
7542
- function isPointOverNavItem(container, x, y) {
7543
- return Array.from(container.querySelectorAll("[data-ohw-href-key]")).some((el) => {
7544
- if (!isNavigationItem(el) || isNavbarButton2(el)) return false;
7545
- const itemRect = el.getBoundingClientRect();
7546
- return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
7547
- });
7548
- }
7549
- function resolveNavContainerSelectionTarget(target, clientX, clientY) {
7550
- if (getNavigationItemAnchor(target)) return null;
7551
- if (target.closest('[data-ohw-role="navbar-button"]')) return null;
7552
- const plainLink = target.closest("a");
7553
- if (plainLink && !plainLink.hasAttribute("data-ohw-href-key") && !plainLink.closest("[data-ohw-nav-container]")) {
7554
- return null;
7555
- }
7556
- const fromClosest = target.closest("[data-ohw-nav-container]");
7557
- if (fromClosest && !isPointOverNavItem(fromClosest, clientX, clientY)) {
7558
- return fromClosest;
7559
- }
7560
- const navRoot = target.closest("[data-ohw-nav-root]");
7561
- if (!navRoot) return null;
7562
- const container = navRoot.querySelector("[data-ohw-nav-container]");
7563
- if (!container || isPointOverNavItem(container, clientX, clientY)) return null;
7564
- if (target === navRoot || target.hasAttribute("data-ohw-nav-root")) {
7565
- return container;
7566
- }
7567
- return null;
7568
- }
7569
- function getNavigationSelectionParent(el) {
7570
- if (isNavigationItem(el)) {
7571
- const explicit = el.closest("[data-ohw-nav-container]");
7572
- if (explicit) return explicit;
7573
- const footerGroup = findFooterItemGroup(el);
7574
- if (footerGroup) return footerGroup;
7575
- return getNavigationRoot(el);
7576
- }
7577
- if (el.hasAttribute("data-ohw-nav-container") || isInferredFooterGroup(el)) {
7578
- return getNavigationRoot(el);
7579
- }
7580
- return null;
7581
- }
7582
- function placeCaretAtPoint(el, x, y) {
7583
- const selection = window.getSelection();
7584
- if (!selection) return;
7585
- if (typeof document.caretRangeFromPoint === "function") {
7586
- const range = document.caretRangeFromPoint(x, y);
7587
- if (range && el.contains(range.startContainer)) {
7588
- selection.removeAllRanges();
7589
- selection.addRange(range);
7590
- return;
7591
- }
7592
- }
7593
- const caretPositionFromPoint = document.caretPositionFromPoint;
7594
- if (typeof caretPositionFromPoint === "function") {
7595
- const position = caretPositionFromPoint(x, y);
7596
- if (position && el.contains(position.offsetNode)) {
7597
- const range = document.createRange();
7598
- range.setStart(position.offsetNode, position.offset);
7599
- range.collapse(true);
7600
- selection.removeAllRanges();
7601
- selection.addRange(range);
7602
- }
7603
- }
7604
- }
7605
- function selectAllTextInEditable(el) {
7606
- const selection = window.getSelection();
7607
- if (!selection) return;
7608
- const range = document.createRange();
7609
- range.selectNodeContents(el);
7610
- selection.removeAllRanges();
7611
- selection.addRange(range);
7612
- }
7613
- function getNavigationLabelEditable(target) {
7614
- const editable = target.closest('[data-ohw-editable="text"]');
7615
- if (!editable) return null;
7616
- const hrefCtx = getHrefKeyFromElement(editable);
7617
- const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
7618
- if (!navAnchor) return null;
7619
- return { editable, navAnchor };
7620
- }
7621
6158
  function collectSections() {
7622
6159
  return collectSectionsFromDom();
7623
6160
  }
@@ -7741,8 +6278,6 @@ var ICONS = {
7741
6278
  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"/>',
7742
6279
  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"/>'
7743
6280
  };
7744
- var TOOLBAR_PILL_PADDING = 2;
7745
- var TOOLBAR_TOGGLE_GAP = 4;
7746
6281
  var TOOLBAR_GROUPS = [
7747
6282
  [
7748
6283
  { cmd: "bold", title: "Bold" },
@@ -7767,7 +6302,7 @@ function EditGlowChrome({
7767
6302
  dragDisabled = false
7768
6303
  }) {
7769
6304
  const GAP = 6;
7770
- return /* @__PURE__ */ jsxs14(
6305
+ return /* @__PURE__ */ jsxs12(
7771
6306
  "div",
7772
6307
  {
7773
6308
  ref: elRef,
@@ -7782,7 +6317,7 @@ function EditGlowChrome({
7782
6317
  zIndex: 2147483646
7783
6318
  },
7784
6319
  children: [
7785
- /* @__PURE__ */ jsx25(
6320
+ /* @__PURE__ */ jsx22(
7786
6321
  "div",
7787
6322
  {
7788
6323
  style: {
@@ -7795,7 +6330,7 @@ function EditGlowChrome({
7795
6330
  }
7796
6331
  }
7797
6332
  ),
7798
- reorderHrefKey && /* @__PURE__ */ jsx25(
6333
+ reorderHrefKey && /* @__PURE__ */ jsx22(
7799
6334
  "div",
7800
6335
  {
7801
6336
  "data-ohw-drag-handle-container": "",
@@ -7807,7 +6342,7 @@ function EditGlowChrome({
7807
6342
  transform: "translate(calc(-100% - 7px), -50%)",
7808
6343
  pointerEvents: dragDisabled ? "none" : "auto"
7809
6344
  },
7810
- children: /* @__PURE__ */ jsx25(
6345
+ children: /* @__PURE__ */ jsx22(
7811
6346
  DragHandle,
7812
6347
  {
7813
6348
  "aria-label": `Reorder ${reorderHrefKey}`,
@@ -7911,7 +6446,7 @@ function FloatingToolbar({
7911
6446
  onEditLink
7912
6447
  }) {
7913
6448
  const { top, left, transform } = calcToolbarPos(rect, parentScroll, 330);
7914
- return /* @__PURE__ */ jsx25(
6449
+ return /* @__PURE__ */ jsx22(
7915
6450
  "div",
7916
6451
  {
7917
6452
  ref: elRef,
@@ -7921,23 +6456,14 @@ function FloatingToolbar({
7921
6456
  left,
7922
6457
  transform,
7923
6458
  zIndex: 2147483647,
7924
- background: "#fff",
7925
- border: "1px solid #E7E5E4",
7926
- borderRadius: 6,
7927
- boxShadow: "0px 2px 4px -2px rgba(0,0,0,.1),0px 4px 6px -1px rgba(0,0,0,.1)",
7928
- display: "flex",
7929
- alignItems: "center",
7930
- padding: TOOLBAR_PILL_PADDING,
7931
- gap: TOOLBAR_TOGGLE_GAP,
7932
- fontFamily: "sans-serif",
7933
6459
  pointerEvents: "auto"
7934
6460
  },
7935
- children: /* @__PURE__ */ jsxs14(CustomToolbar, { children: [
7936
- TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs14(React10.Fragment, { children: [
7937
- gi > 0 && /* @__PURE__ */ jsx25(CustomToolbarDivider, {}),
6461
+ children: /* @__PURE__ */ jsxs12(CustomToolbar, { children: [
6462
+ TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs12(React9.Fragment, { children: [
6463
+ gi > 0 && /* @__PURE__ */ jsx22(CustomToolbarDivider, {}),
7938
6464
  btns.map((btn) => {
7939
6465
  const isActive = activeCommands.has(btn.cmd);
7940
- return /* @__PURE__ */ jsx25(
6466
+ return /* @__PURE__ */ jsx22(
7941
6467
  CustomToolbarButton,
7942
6468
  {
7943
6469
  title: btn.title,
@@ -7946,7 +6472,7 @@ function FloatingToolbar({
7946
6472
  e.preventDefault();
7947
6473
  onCommand(btn.cmd);
7948
6474
  },
7949
- children: /* @__PURE__ */ jsx25(
6475
+ children: /* @__PURE__ */ jsx22(
7950
6476
  "svg",
7951
6477
  {
7952
6478
  width: "16",
@@ -7967,7 +6493,7 @@ function FloatingToolbar({
7967
6493
  );
7968
6494
  })
7969
6495
  ] }, gi)),
7970
- showEditLink ? /* @__PURE__ */ jsx25(
6496
+ showEditLink ? /* @__PURE__ */ jsx22(
7971
6497
  CustomToolbarButton,
7972
6498
  {
7973
6499
  type: "button",
@@ -7981,7 +6507,7 @@ function FloatingToolbar({
7981
6507
  e.preventDefault();
7982
6508
  e.stopPropagation();
7983
6509
  },
7984
- children: /* @__PURE__ */ jsx25(Link2, { className: "size-4 shrink-0", "aria-hidden": true })
6510
+ children: /* @__PURE__ */ jsx22(Link2, { className: "size-4 shrink-0", "aria-hidden": true })
7985
6511
  }
7986
6512
  ) : null
7987
6513
  ] })
@@ -7998,7 +6524,7 @@ function StateToggle({
7998
6524
  states,
7999
6525
  onStateChange
8000
6526
  }) {
8001
- return /* @__PURE__ */ jsx25(
6527
+ return /* @__PURE__ */ jsx22(
8002
6528
  ToggleGroup,
8003
6529
  {
8004
6530
  "data-ohw-state-toggle": "",
@@ -8012,7 +6538,7 @@ function StateToggle({
8012
6538
  left: rect.right - 8,
8013
6539
  transform: "translateX(-100%)"
8014
6540
  },
8015
- children: states.map((state) => /* @__PURE__ */ jsx25(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
6541
+ children: states.map((state) => /* @__PURE__ */ jsx22(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
8016
6542
  }
8017
6543
  );
8018
6544
  }
@@ -8035,12 +6561,12 @@ function resolveSubdomain(subdomainFromQuery) {
8035
6561
  return "";
8036
6562
  }
8037
6563
  function OhhwellsBridge() {
8038
- const pathname = usePathname2();
8039
- const router = useRouter2();
6564
+ const pathname = usePathname();
6565
+ const router = useRouter();
8040
6566
  const searchParams = useSearchParams();
8041
6567
  const isEditMode = isEditSessionActive();
8042
- const [bridgeRoot, setBridgeRoot] = useState7(null);
8043
- useEffect8(() => {
6568
+ const [bridgeRoot, setBridgeRoot] = useState5(null);
6569
+ useEffect4(() => {
8044
6570
  const figtreeFontId = "ohw-figtree-font";
8045
6571
  if (!document.getElementById(figtreeFontId)) {
8046
6572
  const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
@@ -8068,100 +6594,83 @@ function OhhwellsBridge() {
8068
6594
  const subdomainFromQuery = searchParams.get("subdomain");
8069
6595
  const subdomain = resolveSubdomain(subdomainFromQuery);
8070
6596
  useLinkHrefGuardian(pathname, subdomain, isEditMode);
8071
- const postToParent2 = useCallback4((data) => {
6597
+ const postToParent = useCallback2((data) => {
8072
6598
  if (typeof window !== "undefined" && window.parent !== window) {
8073
6599
  window.parent.postMessage(data, "*");
8074
6600
  }
8075
6601
  }, []);
8076
- const [fetchState, setFetchState] = useState7("idle");
8077
- const autoSaveTimers = useRef5(/* @__PURE__ */ new Map());
8078
- const activeElRef = useRef5(null);
8079
- const selectedElRef = useRef5(null);
8080
- const originalContentRef = useRef5(null);
8081
- const activeStateElRef = useRef5(null);
8082
- const parentScrollRef = useRef5(null);
8083
- const visibleViewportRef = useRef5(null);
8084
- const [dialogPortalContainer, setDialogPortalContainer] = useState7(null);
8085
- const attachVisibleViewport = useCallback4((node) => {
6602
+ const [fetchState, setFetchState] = useState5("idle");
6603
+ const autoSaveTimers = useRef4(/* @__PURE__ */ new Map());
6604
+ const activeElRef = useRef4(null);
6605
+ const selectedElRef = useRef4(null);
6606
+ const originalContentRef = useRef4(null);
6607
+ const activeStateElRef = useRef4(null);
6608
+ const parentScrollRef = useRef4(null);
6609
+ const visibleViewportRef = useRef4(null);
6610
+ const [dialogPortalContainer, setDialogPortalContainer] = useState5(null);
6611
+ const attachVisibleViewport = useCallback2((node) => {
8086
6612
  visibleViewportRef.current = node;
8087
6613
  setDialogPortalContainer(node);
8088
6614
  if (node) applyVisibleViewport(node, parentScrollRef.current);
8089
6615
  }, []);
8090
- const toolbarElRef = useRef5(null);
8091
- const glowElRef = useRef5(null);
8092
- const hoveredImageRef = useRef5(null);
8093
- const hoveredImageHasTextOverlapRef = useRef5(false);
8094
- const dragOverElRef = useRef5(null);
8095
- const [mediaHover, setMediaHover] = useState7(null);
8096
- const [carouselHover, setCarouselHover] = useState7(null);
8097
- const [uploadingRects, setUploadingRects] = useState7({});
8098
- const hoveredGapRef = useRef5(null);
8099
- const imageUnhoverTimerRef = useRef5(null);
8100
- const imageShowTimerRef = useRef5(null);
8101
- const editStylesRef = useRef5(null);
8102
- const activateRef = useRef5(() => {
6616
+ const toolbarElRef = useRef4(null);
6617
+ const glowElRef = useRef4(null);
6618
+ const hoveredImageRef = useRef4(null);
6619
+ const hoveredImageHasTextOverlapRef = useRef4(false);
6620
+ const dragOverElRef = useRef4(null);
6621
+ const [mediaHover, setMediaHover] = useState5(null);
6622
+ const [uploadingRects, setUploadingRects] = useState5({});
6623
+ const hoveredGapRef = useRef4(null);
6624
+ const imageUnhoverTimerRef = useRef4(null);
6625
+ const imageShowTimerRef = useRef4(null);
6626
+ const editStylesRef = useRef4(null);
6627
+ const activateRef = useRef4(() => {
8103
6628
  });
8104
- const deactivateRef = useRef5(() => {
6629
+ const deactivateRef = useRef4(() => {
8105
6630
  });
8106
- const selectRef = useRef5(() => {
6631
+ const selectRef = useRef4(() => {
8107
6632
  });
8108
- const selectFrameRef = useRef5(() => {
6633
+ const deselectRef = useRef4(() => {
8109
6634
  });
8110
- const deselectRef = useRef5(() => {
6635
+ const reselectNavigationItemRef = useRef4(() => {
8111
6636
  });
8112
- const reselectNavigationItemRef = useRef5(() => {
6637
+ const commitNavigationTextEditRef = useRef4(() => {
8113
6638
  });
8114
- const commitNavigationTextEditRef = useRef5(() => {
6639
+ const refreshActiveCommandsRef = useRef4(() => {
8115
6640
  });
8116
- const refreshActiveCommandsRef = useRef5(() => {
8117
- });
8118
- const postToParentRef = useRef5(postToParent2);
8119
- postToParentRef.current = postToParent2;
8120
- const sectionsLoadedRef = useRef5(false);
8121
- const pendingScheduleConfigRequests = useRef5([]);
8122
- const [toolbarRect, setToolbarRect] = useState7(null);
8123
- const [toolbarVariant, setToolbarVariant] = useState7("none");
8124
- const toolbarVariantRef = useRef5("none");
6641
+ const postToParentRef = useRef4(postToParent);
6642
+ postToParentRef.current = postToParent;
6643
+ const sectionsLoadedRef = useRef4(false);
6644
+ const pendingScheduleConfigRequests = useRef4([]);
6645
+ const [toolbarRect, setToolbarRect] = useState5(null);
6646
+ const [toolbarVariant, setToolbarVariant] = useState5("none");
6647
+ const toolbarVariantRef = useRef4("none");
8125
6648
  toolbarVariantRef.current = toolbarVariant;
8126
- const [reorderHrefKey, setReorderHrefKey] = useState7(null);
8127
- const [reorderDragDisabled, setReorderDragDisabled] = useState7(false);
8128
- const [toggleState, setToggleState] = useState7(null);
8129
- const [maxBadge, setMaxBadge] = useState7(null);
8130
- const [activeCommands, setActiveCommands] = useState7(/* @__PURE__ */ new Set());
8131
- const [sectionGap, setSectionGap] = useState7(null);
8132
- const [toolbarShowEditLink, setToolbarShowEditLink] = useState7(false);
8133
- const hoveredNavContainerRef = useRef5(null);
8134
- const [hoveredNavContainerRect, setHoveredNavContainerRect] = useState7(null);
8135
- const hoveredItemElRef = useRef5(null);
8136
- const [hoveredItemRect, setHoveredItemRect] = useState7(null);
8137
- const siblingHintElRef = useRef5(null);
8138
- const [siblingHintRect, setSiblingHintRect] = useState7(null);
8139
- const [siblingHintRects, setSiblingHintRects] = useState7([]);
8140
- const [isItemDragging, setIsItemDragging] = useState7(false);
8141
- const [isFooterFrameSelection, setIsFooterFrameSelection] = useState7(false);
8142
- const footerDragRef = useRef5(null);
8143
- const [footerDropSlots, setFooterDropSlots] = useState7([]);
8144
- const [activeFooterDropIndex, setActiveFooterDropIndex] = useState7(null);
8145
- const [draggedItemRect, setDraggedItemRect] = useState7(null);
8146
- const footerPointerDragRef = useRef5(null);
8147
- const suppressNextClickRef = useRef5(false);
8148
- const [linkPopover, setLinkPopover] = useState7(null);
8149
- const linkPopoverSessionRef = useRef5(null);
8150
- const addNavAfterAnchorRef = useRef5(null);
8151
- const editContentRef = useRef5({});
8152
- const [sitePages, setSitePages] = useState7([]);
8153
- const [sectionsByPath, setSectionsByPath] = useState7({});
8154
- const sectionsPrefetchGenRef = useRef5(0);
8155
- const setLinkPopoverRef = useRef5(setLinkPopover);
8156
- const linkPopoverPanelRef = useRef5(null);
8157
- const linkPopoverOpenRef = useRef5(false);
8158
- const linkPopoverGraceUntilRef = useRef5(0);
6649
+ const [reorderHrefKey, setReorderHrefKey] = useState5(null);
6650
+ const [reorderDragDisabled, setReorderDragDisabled] = useState5(false);
6651
+ const [toggleState, setToggleState] = useState5(null);
6652
+ const [maxBadge, setMaxBadge] = useState5(null);
6653
+ const [activeCommands, setActiveCommands] = useState5(/* @__PURE__ */ new Set());
6654
+ const [sectionGap, setSectionGap] = useState5(null);
6655
+ const [toolbarShowEditLink, setToolbarShowEditLink] = useState5(false);
6656
+ const hoveredItemElRef = useRef4(null);
6657
+ const [hoveredItemRect, setHoveredItemRect] = useState5(null);
6658
+ const siblingHintElRef = useRef4(null);
6659
+ const [siblingHintRect, setSiblingHintRect] = useState5(null);
6660
+ const [isItemDragging, setIsItemDragging] = useState5(false);
6661
+ const [linkPopover, setLinkPopover] = useState5(null);
6662
+ const [sitePages, setSitePages] = useState5([]);
6663
+ const [sectionsByPath, setSectionsByPath] = useState5({});
6664
+ const sectionsPrefetchGenRef = useRef4(0);
6665
+ const setLinkPopoverRef = useRef4(setLinkPopover);
6666
+ const linkPopoverPanelRef = useRef4(null);
6667
+ const linkPopoverOpenRef = useRef4(false);
6668
+ const linkPopoverGraceUntilRef = useRef4(0);
8159
6669
  setLinkPopoverRef.current = setLinkPopover;
8160
- linkPopoverSessionRef.current = linkPopover;
8161
6670
  const bumpLinkPopoverGrace = () => {
8162
6671
  linkPopoverGraceUntilRef.current = Date.now() + 350;
8163
6672
  };
8164
- const runSectionsPrefetch = useCallback4((pages) => {
6673
+ const runSectionsPrefetch = useCallback2((pages) => {
8165
6674
  if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
8166
6675
  const gen = ++sectionsPrefetchGenRef.current;
8167
6676
  const paths = pages.map((p) => p.path);
@@ -8180,9 +6689,9 @@ function OhhwellsBridge() {
8180
6689
  );
8181
6690
  });
8182
6691
  }, [isEditMode, pathname]);
8183
- const runSectionsPrefetchRef = useRef5(runSectionsPrefetch);
6692
+ const runSectionsPrefetchRef = useRef4(runSectionsPrefetch);
8184
6693
  runSectionsPrefetchRef.current = runSectionsPrefetch;
8185
- useEffect8(() => {
6694
+ useEffect4(() => {
8186
6695
  if (!linkPopover) return;
8187
6696
  if (hoveredImageRef.current) {
8188
6697
  hoveredImageRef.current = null;
@@ -8190,9 +6699,33 @@ function OhhwellsBridge() {
8190
6699
  }
8191
6700
  hoveredGapRef.current = null;
8192
6701
  setSectionGap(null);
8193
- postToParent2({ type: "ow:image-unhover" });
8194
- }, [linkPopover, postToParent2]);
8195
- useEffect8(() => {
6702
+ setMediaHover(null);
6703
+ postToParent({ type: "ow:link-modal-lock", locked: true });
6704
+ const html = document.documentElement;
6705
+ const body = document.body;
6706
+ const prevHtmlOverflow = html.style.overflow;
6707
+ const prevBodyOverflow = body.style.overflow;
6708
+ html.style.overflow = "hidden";
6709
+ body.style.overflow = "hidden";
6710
+ const preventBackgroundScroll = (e) => {
6711
+ const target = e.target;
6712
+ if (target instanceof Element && target.closest('[data-ohw-link-modal-root], [data-slot="dialog-overlay"]')) {
6713
+ return;
6714
+ }
6715
+ e.preventDefault();
6716
+ };
6717
+ const scrollOpts = { passive: false, capture: true };
6718
+ document.addEventListener("wheel", preventBackgroundScroll, scrollOpts);
6719
+ document.addEventListener("touchmove", preventBackgroundScroll, scrollOpts);
6720
+ return () => {
6721
+ postToParent({ type: "ow:link-modal-lock", locked: false });
6722
+ html.style.overflow = prevHtmlOverflow;
6723
+ body.style.overflow = prevBodyOverflow;
6724
+ document.removeEventListener("wheel", preventBackgroundScroll, scrollOpts);
6725
+ document.removeEventListener("touchmove", preventBackgroundScroll, scrollOpts);
6726
+ };
6727
+ }, [linkPopover, postToParent]);
6728
+ useEffect4(() => {
8196
6729
  if (!isEditMode) return;
8197
6730
  const useFixtures = shouldUseDevFixtures();
8198
6731
  if (useFixtures) {
@@ -8213,17 +6746,17 @@ function OhhwellsBridge() {
8213
6746
  runSectionsPrefetchRef.current(mapped);
8214
6747
  };
8215
6748
  window.addEventListener("message", onSitePages);
8216
- if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
6749
+ if (!useFixtures) postToParent({ type: "ow:request-site-pages" });
8217
6750
  return () => window.removeEventListener("message", onSitePages);
8218
- }, [isEditMode, postToParent2]);
8219
- useEffect8(() => {
6751
+ }, [isEditMode, postToParent]);
6752
+ useEffect4(() => {
8220
6753
  if (!isEditMode || shouldUseDevFixtures()) return;
8221
6754
  void loadAllSectionsManifest().then((manifest) => {
8222
6755
  if (Object.keys(manifest).length === 0) return;
8223
6756
  setSectionsByPath((prev) => ({ ...manifest, ...prev }));
8224
6757
  });
8225
6758
  }, [isEditMode]);
8226
- useEffect8(() => {
6759
+ useEffect4(() => {
8227
6760
  const update = () => {
8228
6761
  const el = activeElRef.current ?? selectedElRef.current;
8229
6762
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
@@ -8247,10 +6780,10 @@ function OhhwellsBridge() {
8247
6780
  vvp.removeEventListener("resize", update);
8248
6781
  };
8249
6782
  }, []);
8250
- const refreshStateRules = useCallback4(() => {
6783
+ const refreshStateRules = useCallback2(() => {
8251
6784
  editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
8252
6785
  }, []);
8253
- const processConfigRequest = useCallback4((insertAfterVal) => {
6786
+ const processConfigRequest = useCallback2((insertAfterVal) => {
8254
6787
  const tracker = getSectionsTracker();
8255
6788
  let entries = [];
8256
6789
  try {
@@ -8273,7 +6806,7 @@ function OhhwellsBridge() {
8273
6806
  }
8274
6807
  window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
8275
6808
  }, [isEditMode]);
8276
- const deactivate = useCallback4(() => {
6809
+ const deactivate = useCallback2(() => {
8277
6810
  const el = activeElRef.current;
8278
6811
  if (!el) return;
8279
6812
  const key = el.dataset.ohwKey;
@@ -8302,25 +6835,21 @@ function OhhwellsBridge() {
8302
6835
  setMaxBadge(null);
8303
6836
  setActiveCommands(/* @__PURE__ */ new Set());
8304
6837
  setToolbarShowEditLink(false);
8305
- postToParent2({ type: "ow:exit-edit" });
8306
- }, [postToParent2]);
8307
- const deselect = useCallback4(() => {
6838
+ postToParent({ type: "ow:exit-edit" });
6839
+ }, [postToParent]);
6840
+ const deselect = useCallback2(() => {
8308
6841
  selectedElRef.current = null;
8309
6842
  setReorderHrefKey(null);
8310
6843
  setReorderDragDisabled(false);
8311
- setIsFooterFrameSelection(false);
8312
6844
  siblingHintElRef.current = null;
8313
6845
  setSiblingHintRect(null);
8314
- setSiblingHintRects([]);
8315
6846
  setIsItemDragging(false);
8316
- hoveredNavContainerRef.current = null;
8317
- setHoveredNavContainerRect(null);
8318
6847
  if (!activeElRef.current) {
8319
6848
  setToolbarRect(null);
8320
6849
  setToolbarVariant("none");
8321
6850
  }
8322
6851
  }, []);
8323
- const reselectNavigationItem = useCallback4((navAnchor) => {
6852
+ const reselectNavigationItem = useCallback2((navAnchor) => {
8324
6853
  selectedElRef.current = navAnchor;
8325
6854
  const { key, disabled } = getNavigationItemReorderState(navAnchor);
8326
6855
  setReorderHrefKey(key);
@@ -8330,7 +6859,7 @@ function OhhwellsBridge() {
8330
6859
  setToolbarShowEditLink(false);
8331
6860
  setActiveCommands(/* @__PURE__ */ new Set());
8332
6861
  }, []);
8333
- const commitNavigationTextEdit = useCallback4((navAnchor) => {
6862
+ const commitNavigationTextEdit = useCallback2((navAnchor) => {
8334
6863
  const el = activeElRef.current;
8335
6864
  if (!el) return;
8336
6865
  const key = el.dataset.ohwKey;
@@ -8343,9 +6872,9 @@ function OhhwellsBridge() {
8343
6872
  const html = sanitizeHtml(el.innerHTML);
8344
6873
  const original = originalContentRef.current ?? "";
8345
6874
  if (html !== sanitizeHtml(original)) {
8346
- postToParent2({ type: "ow:change", nodes: [{ key, text: html }] });
6875
+ postToParent({ type: "ow:change", nodes: [{ key, text: html }] });
8347
6876
  const h = document.documentElement.scrollHeight;
8348
- if (h > 50) postToParent2({ type: "ow:height", height: h });
6877
+ if (h > 50) postToParent({ type: "ow:height", height: h });
8349
6878
  }
8350
6879
  }
8351
6880
  el.removeAttribute("contenteditable");
@@ -8353,364 +6882,79 @@ function OhhwellsBridge() {
8353
6882
  setMaxBadge(null);
8354
6883
  setActiveCommands(/* @__PURE__ */ new Set());
8355
6884
  setToolbarShowEditLink(false);
8356
- postToParent2({ type: "ow:exit-edit" });
6885
+ postToParent({ type: "ow:exit-edit" });
8357
6886
  reselectNavigationItem(navAnchor);
8358
- }, [postToParent2, reselectNavigationItem]);
8359
- const handleAddTopLevelNavItem = useCallback4(() => {
8360
- const items = listNavbarItems();
8361
- addNavAfterAnchorRef.current = items[items.length - 1] ?? null;
8362
- deselectRef.current();
8363
- deactivateRef.current();
8364
- bumpLinkPopoverGrace();
8365
- setLinkPopover({
8366
- key: "__add-nav__",
8367
- mode: "create",
8368
- intent: "add-nav"
8369
- });
8370
- }, []);
8371
- const clearFooterDragVisuals = useCallback4(() => {
8372
- footerDragRef.current = null;
8373
- setSiblingHintRects([]);
8374
- setFooterDropSlots([]);
8375
- setActiveFooterDropIndex(null);
8376
- setDraggedItemRect(null);
8377
- setIsItemDragging(false);
8378
- unlockFooterDragInteraction();
8379
- }, []);
8380
- const refreshFooterDragVisuals = useCallback4((session, activeSlot, clientX, clientY) => {
8381
- const dragged = session.draggedEl;
8382
- setDraggedItemRect(dragged.getBoundingClientRect());
8383
- if (typeof clientX === "number" && typeof clientY === "number") {
8384
- session.lastClientX = clientX;
8385
- session.lastClientY = clientY;
8386
- }
8387
- session.activeSlot = activeSlot;
8388
- if (session.kind === "link") {
8389
- const columns2 = listFooterColumns();
8390
- const focusCols = /* @__PURE__ */ new Set([session.sourceColumnIndex]);
8391
- if (activeSlot) focusCols.add(activeSlot.columnIndex);
8392
- const siblingRects = [];
8393
- columns2.forEach((col, i) => {
8394
- if (!focusCols.has(i)) return;
8395
- for (const link of listFooterLinksInColumn(col)) {
8396
- if (link === dragged) continue;
8397
- siblingRects.push(link.getBoundingClientRect());
8398
- }
8399
- });
8400
- setSiblingHintRects(siblingRects);
8401
- const slots2 = [];
8402
- columns2.forEach((col, i) => {
8403
- slots2.push(...buildLinkDropSlots(col, i));
8404
- });
8405
- setFooterDropSlots(slots2);
8406
- const activeIdx2 = activeSlot ? slots2.findIndex((s) => s.columnIndex === activeSlot.columnIndex && s.insertIndex === activeSlot.insertIndex) : -1;
8407
- setActiveFooterDropIndex(activeIdx2 >= 0 ? activeIdx2 : null);
8408
- return;
8409
- }
8410
- const columns = listFooterColumns();
8411
- setSiblingHintRects(columns.filter((col) => col !== dragged).map((col) => col.getBoundingClientRect()));
8412
- const slots = buildColumnDropSlots();
8413
- setFooterDropSlots(slots);
8414
- const activeIdx = activeSlot ? slots.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
8415
- setActiveFooterDropIndex(activeIdx >= 0 ? activeIdx : null);
8416
- }, []);
8417
- const refreshFooterDragVisualsRef = useRef5(refreshFooterDragVisuals);
8418
- refreshFooterDragVisualsRef.current = refreshFooterDragVisuals;
8419
- const commitFooterDragRef = useRef5(() => {
8420
- });
8421
- const beginFooterDragRef = useRef5(() => {
8422
- });
8423
- const beginFooterDrag = useCallback4(
8424
- (session) => {
8425
- const rect = session.draggedEl.getBoundingClientRect();
8426
- session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
8427
- session.lastClientY = session.lastClientY || rect.top + rect.height / 2;
8428
- session.activeSlot = session.activeSlot ?? null;
8429
- footerDragRef.current = session;
8430
- setIsItemDragging(true);
8431
- lockFooterDuringDrag();
8432
- siblingHintElRef.current = null;
8433
- setSiblingHintRect(null);
8434
- if (session.wasSelected && selectedElRef.current === session.draggedEl) {
8435
- setToolbarRect(rect);
8436
- }
8437
- const initialSlot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : hitTestColumnDropSlot(session.lastClientX, session.lastClientY);
8438
- refreshFooterDragVisuals(session, initialSlot, session.lastClientX, session.lastClientY);
8439
- },
8440
- [refreshFooterDragVisuals]
8441
- );
8442
- beginFooterDragRef.current = beginFooterDrag;
8443
- const commitFooterDrag = useCallback4(
8444
- (clientX, clientY) => {
8445
- const session = footerDragRef.current;
8446
- if (!session) {
8447
- clearFooterDragVisuals();
8448
- return;
8449
- }
8450
- const x = typeof clientX === "number" && (clientX !== 0 || clientY !== 0) ? clientX : session.lastClientX;
8451
- const y = typeof clientY === "number" && (clientX !== 0 || clientY !== 0) ? clientY : session.lastClientY;
8452
- let nextOrder = null;
8453
- const slot = session.activeSlot ?? (session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(x, y, session.hrefKey) : session.kind === "column" ? hitTestColumnDropSlot(x, y) : null);
8454
- if (session.kind === "link" && session.hrefKey && slot) {
8455
- nextOrder = planFooterLinkMove(session.hrefKey, slot.columnIndex, slot.insertIndex);
8456
- } else if (session.kind === "column" && slot) {
8457
- nextOrder = planFooterColumnMove(session.sourceColumnIndex, slot.insertIndex);
8458
- }
8459
- const wasSelected = session.wasSelected;
8460
- const draggedEl = session.draggedEl;
8461
- const hrefKey = session.hrefKey;
8462
- let movedColumnIndex = null;
8463
- if (session.kind === "column" && slot && nextOrder) {
8464
- let adjusted = slot.insertIndex;
8465
- if (session.sourceColumnIndex < slot.insertIndex) adjusted -= 1;
8466
- movedColumnIndex = Math.max(0, Math.min(adjusted, nextOrder.length - 1));
8467
- }
8468
- clearFooterDragVisuals();
8469
- if (nextOrder) {
8470
- const orderJson = JSON.stringify(nextOrder);
8471
- editContentRef.current = {
8472
- ...editContentRef.current,
8473
- [FOOTER_ORDER_KEY]: orderJson
8474
- };
8475
- applyFooterOrder(nextOrder);
8476
- document.querySelectorAll("footer [data-ohw-href-key]").forEach(disableNativeHrefDrag);
8477
- requestAnimationFrame(() => {
8478
- if (editContentRef.current[FOOTER_ORDER_KEY] === orderJson) {
8479
- applyFooterOrder(nextOrder);
8480
- document.querySelectorAll("footer [data-ohw-href-key]").forEach(disableNativeHrefDrag);
8481
- }
8482
- });
8483
- postToParentRef.current({
8484
- type: "ow:change",
8485
- nodes: [{ key: FOOTER_ORDER_KEY, text: orderJson }]
8486
- });
8487
- }
8488
- const still = (hrefKey ? document.querySelector(`footer [data-ohw-href-key="${CSS.escape(hrefKey)}"]`) : null) ?? (movedColumnIndex !== null ? listFooterColumns()[movedColumnIndex] ?? null : null) ?? (document.body.contains(draggedEl) ? draggedEl : null);
8489
- if (still && isNavigationItem(still)) {
8490
- selectRef.current(still);
8491
- } else if (still && isNavigationContainer(still)) {
8492
- selectFrameRef.current(still);
8493
- } else if (wasSelected) {
8494
- deselectRef.current();
8495
- }
8496
- },
8497
- [clearFooterDragVisuals]
8498
- );
8499
- commitFooterDragRef.current = commitFooterDrag;
8500
- const startFooterLinkDrag = useCallback4(
8501
- (anchor, clientX, clientY, wasSelected) => {
8502
- const hrefKey = anchor.getAttribute("data-ohw-href-key");
8503
- if (!hrefKey || !isFooterHrefKey(hrefKey)) return false;
8504
- const column = findFooterColumnForLink(anchor);
8505
- const columns = listFooterColumns();
8506
- beginFooterDrag({
8507
- kind: "link",
8508
- hrefKey,
8509
- columnEl: column,
8510
- sourceColumnIndex: column ? columns.indexOf(column) : 0,
8511
- wasSelected,
8512
- draggedEl: anchor,
8513
- lastClientX: clientX,
8514
- lastClientY: clientY,
8515
- activeSlot: null
8516
- });
8517
- return true;
8518
- },
8519
- [beginFooterDrag]
8520
- );
8521
- const startFooterColumnDrag = useCallback4(
8522
- (columnEl, clientX, clientY, wasSelected) => {
8523
- const columns = listFooterColumns();
8524
- const idx = columns.indexOf(columnEl);
8525
- if (idx < 0) return false;
8526
- beginFooterDrag({
8527
- kind: "column",
8528
- hrefKey: null,
8529
- columnEl,
8530
- sourceColumnIndex: idx,
8531
- wasSelected,
8532
- draggedEl: columnEl,
8533
- lastClientX: clientX,
8534
- lastClientY: clientY,
8535
- activeSlot: null
8536
- });
8537
- return true;
8538
- },
8539
- [beginFooterDrag]
8540
- );
8541
- const handleItemDragStart = useCallback4(
8542
- (e) => {
8543
- const selected = selectedElRef.current;
8544
- if (!selected) {
8545
- setIsItemDragging(true);
8546
- return;
8547
- }
8548
- const clientX = e?.clientX ?? selected.getBoundingClientRect().left + 8;
8549
- const clientY = e?.clientY ?? selected.getBoundingClientRect().top + 8;
8550
- if (startFooterLinkDrag(selected, clientX, clientY, true)) return;
8551
- if (selected.hasAttribute("data-ohw-footer-col") || isInferredFooterGroup(selected) && selected.closest("footer")) {
8552
- if (startFooterColumnDrag(selected, clientX, clientY, true)) return;
8553
- }
8554
- siblingHintElRef.current = null;
8555
- setSiblingHintRect(null);
8556
- setIsItemDragging(true);
8557
- },
8558
- [startFooterColumnDrag, startFooterLinkDrag]
8559
- );
8560
- const handleItemDragEnd = useCallback4(
8561
- (e) => {
8562
- if (footerDragRef.current) {
8563
- const x = e?.clientX;
8564
- const y = e?.clientY;
8565
- if (typeof x === "number" && typeof y === "number" && (x !== 0 || y !== 0)) {
8566
- commitFooterDrag(x, y);
8567
- } else {
8568
- commitFooterDrag();
8569
- }
8570
- return;
8571
- }
8572
- setIsItemDragging(false);
8573
- },
8574
- [commitFooterDrag]
8575
- );
8576
- const handleItemChromePointerDown = useCallback4((e) => {
8577
- if (e.button !== 0) return;
6887
+ }, [postToParent, reselectNavigationItem]);
6888
+ const handleAddNavigationItem = useCallback2(() => {
8578
6889
  const selected = selectedElRef.current;
8579
6890
  if (!selected) return;
8580
- armFooterPressDrag();
8581
- const hrefKey = selected.getAttribute("data-ohw-href-key");
8582
- if (hrefKey && isFooterHrefKey(hrefKey)) {
8583
- footerPointerDragRef.current = {
8584
- el: selected,
8585
- kind: "link",
8586
- startX: e.clientX,
8587
- startY: e.clientY,
8588
- pointerId: e.pointerId,
8589
- wasSelected: true,
8590
- started: false
8591
- };
8592
- return;
8593
- }
8594
- if (selected.hasAttribute("data-ohw-footer-col") || isInferredFooterGroup(selected) && selected.closest("footer")) {
8595
- footerPointerDragRef.current = {
8596
- el: selected,
8597
- kind: "column",
8598
- startX: e.clientX,
8599
- startY: e.clientY,
8600
- pointerId: e.pointerId,
8601
- wasSelected: true,
8602
- started: false
8603
- };
8604
- }
6891
+ const target = getNavigationItemAddHintTarget(selected);
6892
+ siblingHintElRef.current = target;
6893
+ setSiblingHintRect(target.getBoundingClientRect());
8605
6894
  }, []);
8606
- const handleItemChromeClick = useCallback4((clientX, clientY) => {
8607
- if (suppressNextClickRef.current) {
8608
- suppressNextClickRef.current = false;
8609
- return;
8610
- }
8611
- const selected = selectedElRef.current;
8612
- if (!selected || !isNavigationItem(selected)) return;
8613
- const editable = selected.querySelector('[data-ohw-editable="text"]') ?? selected.querySelector("[data-ohw-editable]");
8614
- if (!editable) return;
8615
- activateRef.current(editable, { caretX: clientX, caretY: clientY });
6895
+ const handleItemDragStart = useCallback2(() => {
6896
+ siblingHintElRef.current = null;
6897
+ setSiblingHintRect(null);
6898
+ setIsItemDragging(true);
6899
+ }, []);
6900
+ const handleItemDragEnd = useCallback2(() => {
6901
+ setIsItemDragging(false);
8616
6902
  }, []);
8617
6903
  reselectNavigationItemRef.current = reselectNavigationItem;
8618
6904
  commitNavigationTextEditRef.current = commitNavigationTextEdit;
8619
- const select = useCallback4(
8620
- (anchor) => {
8621
- if (!isNavigationItem(anchor)) return;
8622
- if (activeElRef.current) deactivate();
8623
- selectedElRef.current = anchor;
8624
- clearHrefKeyHover(anchor);
8625
- hoveredNavContainerRef.current = null;
8626
- setHoveredNavContainerRect(null);
8627
- setHoveredItemRect(null);
8628
- hoveredItemElRef.current = null;
8629
- siblingHintElRef.current = null;
8630
- setSiblingHintRect(null);
8631
- setSiblingHintRects([]);
8632
- setIsItemDragging(false);
8633
- const { key, disabled } = getNavigationItemReorderState(anchor);
8634
- setReorderHrefKey(key);
8635
- setReorderDragDisabled(disabled);
8636
- setIsFooterFrameSelection(false);
8637
- setToolbarVariant("link-action");
8638
- setToolbarRect(anchor.getBoundingClientRect());
8639
- setToolbarShowEditLink(false);
8640
- setActiveCommands(/* @__PURE__ */ new Set());
8641
- },
8642
- [deactivate]
8643
- );
8644
- const selectFrame = useCallback4(
8645
- (el) => {
8646
- if (!isNavigationContainer(el)) return;
8647
- if (activeElRef.current) deactivate();
8648
- const isFooterColumn = el.hasAttribute("data-ohw-footer-col") || Boolean(el.closest("footer") && isInferredFooterGroup(el));
8649
- selectedElRef.current = el;
8650
- clearHrefKeyHover(el);
8651
- hoveredNavContainerRef.current = null;
8652
- setHoveredNavContainerRect(null);
8653
- setHoveredItemRect(null);
8654
- hoveredItemElRef.current = null;
8655
- siblingHintElRef.current = null;
8656
- setSiblingHintRect(null);
8657
- setSiblingHintRects(
8658
- isFooterColumn ? listFooterColumns().filter((column) => column !== el).map((column) => column.getBoundingClientRect()) : []
8659
- );
8660
- setIsItemDragging(false);
6905
+ const select = useCallback2((anchor) => {
6906
+ if (!isNavigationItem(anchor)) return;
6907
+ if (activeElRef.current) deactivate();
6908
+ selectedElRef.current = anchor;
6909
+ clearHrefKeyHover(anchor);
6910
+ setHoveredItemRect(null);
6911
+ hoveredItemElRef.current = null;
6912
+ siblingHintElRef.current = null;
6913
+ setSiblingHintRect(null);
6914
+ setIsItemDragging(false);
6915
+ const { key, disabled } = getNavigationItemReorderState(anchor);
6916
+ setReorderHrefKey(key);
6917
+ setReorderDragDisabled(disabled);
6918
+ setToolbarVariant("link-action");
6919
+ setToolbarRect(anchor.getBoundingClientRect());
6920
+ setToolbarShowEditLink(false);
6921
+ setActiveCommands(/* @__PURE__ */ new Set());
6922
+ }, [deactivate]);
6923
+ const activate = useCallback2((el) => {
6924
+ if (activeElRef.current === el) return;
6925
+ selectedElRef.current = null;
6926
+ deactivate();
6927
+ if (hoveredImageRef.current) {
6928
+ hoveredImageRef.current = null;
6929
+ setMediaHover(null);
6930
+ }
6931
+ setToolbarVariant("rich-text");
6932
+ siblingHintElRef.current = null;
6933
+ setSiblingHintRect(null);
6934
+ setIsItemDragging(false);
6935
+ el.setAttribute("contenteditable", "true");
6936
+ el.removeAttribute("data-ohw-hovered");
6937
+ el.closest("[data-ohw-href-key]")?.removeAttribute("data-ohw-hovered");
6938
+ activeElRef.current = el;
6939
+ originalContentRef.current = el.innerHTML;
6940
+ el.focus();
6941
+ setToolbarShowEditLink(Boolean(getHrefKeyFromElement(el)));
6942
+ const navAnchor = getNavigationItemAnchor(el);
6943
+ if (navAnchor) {
8661
6944
  setReorderHrefKey(null);
8662
6945
  setReorderDragDisabled(false);
8663
- setIsFooterFrameSelection(isFooterColumn);
8664
- setToolbarVariant("select-frame");
8665
- setToolbarRect(el.getBoundingClientRect());
8666
- setToolbarShowEditLink(false);
8667
- setActiveCommands(/* @__PURE__ */ new Set());
8668
- },
8669
- [deactivate]
8670
- );
8671
- const activate = useCallback4(
8672
- (el, options) => {
8673
- if (activeElRef.current === el) return;
8674
- selectedElRef.current = null;
8675
- deactivate();
8676
- if (hoveredImageRef.current) {
8677
- hoveredImageRef.current = null;
8678
- postToParentRef.current({ type: "ow:image-unhover" });
8679
- }
8680
- setToolbarVariant("rich-text");
8681
- siblingHintElRef.current = null;
8682
- setSiblingHintRect(null);
8683
- setSiblingHintRects([]);
8684
- setIsItemDragging(false);
8685
- el.setAttribute("contenteditable", "true");
8686
- el.removeAttribute("data-ohw-hovered");
8687
- el.closest("[data-ohw-href-key]")?.removeAttribute("data-ohw-hovered");
8688
- activeElRef.current = el;
8689
- originalContentRef.current = el.innerHTML;
8690
- el.focus();
8691
- if (options?.caretX !== void 0 && options?.caretY !== void 0) {
8692
- placeCaretAtPoint(el, options.caretX, options.caretY);
8693
- }
8694
- setToolbarShowEditLink(Boolean(getHrefKeyFromElement(el)));
8695
- const navAnchor = getNavigationItemAnchor(el);
8696
- if (navAnchor) {
8697
- setReorderHrefKey(null);
8698
- setReorderDragDisabled(false);
8699
- } else {
8700
- const { key: reorderKey, disabled: reorderDisabled } = getReorderHandleState(el);
8701
- setReorderHrefKey(reorderKey);
8702
- setReorderDragDisabled(reorderDisabled);
8703
- }
8704
- setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
8705
- postToParent2({ type: "ow:enter-edit", key: el.dataset.ohwKey });
8706
- requestAnimationFrame(() => refreshActiveCommandsRef.current());
8707
- },
8708
- [deactivate, postToParent2]
8709
- );
6946
+ } else {
6947
+ const { key: reorderKey, disabled: reorderDisabled } = getReorderHandleState(el);
6948
+ setReorderHrefKey(reorderKey);
6949
+ setReorderDragDisabled(reorderDisabled);
6950
+ }
6951
+ setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
6952
+ postToParent({ type: "ow:enter-edit", key: el.dataset.ohwKey });
6953
+ requestAnimationFrame(() => refreshActiveCommandsRef.current());
6954
+ }, [deactivate, postToParent]);
8710
6955
  activateRef.current = activate;
8711
6956
  deactivateRef.current = deactivate;
8712
6957
  selectRef.current = select;
8713
- selectFrameRef.current = selectFrame;
8714
6958
  deselectRef.current = deselect;
8715
6959
  useLayoutEffect2(() => {
8716
6960
  if (!subdomain || isEditMode) {
@@ -8722,7 +6966,6 @@ function OhhwellsBridge() {
8722
6966
  for (const [key, val] of Object.entries(content)) {
8723
6967
  if (key === "__ohw_sections") continue;
8724
6968
  if (applyVideoSettingNode(key, val)) continue;
8725
- if (applyCarouselNode(key, val)) continue;
8726
6969
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
8727
6970
  if (el.dataset.ohwEditable === "image") {
8728
6971
  const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
@@ -8753,8 +6996,6 @@ function OhhwellsBridge() {
8753
6996
  });
8754
6997
  applyLinkByKey(key, val);
8755
6998
  }
8756
- reconcileNavbarItemsFromContent(content);
8757
- reconcileFooterOrderFromContent(content);
8758
6999
  enforceLinkHrefs();
8759
7000
  initSectionsFromContent(content, true);
8760
7001
  sectionsLoadedRef.current = true;
@@ -8783,7 +7024,7 @@ function OhhwellsBridge() {
8783
7024
  cancelled = true;
8784
7025
  };
8785
7026
  }, [subdomain, isEditMode]);
8786
- useEffect8(() => {
7027
+ useEffect4(() => {
8787
7028
  if (!subdomain || isEditMode) return;
8788
7029
  let debounceTimer = null;
8789
7030
  let observer = null;
@@ -8796,7 +7037,6 @@ function OhhwellsBridge() {
8796
7037
  for (const [key, val] of Object.entries(content)) {
8797
7038
  if (key === "__ohw_sections") continue;
8798
7039
  if (applyVideoSettingNode(key, val)) continue;
8799
- if (applyCarouselNode(key, val)) continue;
8800
7040
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
8801
7041
  if (el.dataset.ohwEditable === "image") {
8802
7042
  const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
@@ -8815,8 +7055,6 @@ function OhhwellsBridge() {
8815
7055
  });
8816
7056
  applyLinkByKey(key, val);
8817
7057
  }
8818
- reconcileNavbarItemsFromContent(content);
8819
- reconcileFooterOrderFromContent(content);
8820
7058
  } finally {
8821
7059
  observer?.observe(document.body, { childList: true, subtree: true });
8822
7060
  }
@@ -8840,65 +7078,20 @@ function OhhwellsBridge() {
8840
7078
  const visible = Boolean(subdomain) && fetchState !== "done";
8841
7079
  el.style.display = visible ? "flex" : "none";
8842
7080
  }, [subdomain, fetchState]);
8843
- useEffect8(() => {
8844
- postToParent2({ type: "ow:navigation", path: pathname });
8845
- }, [pathname, postToParent2]);
8846
- useEffect8(() => {
7081
+ useEffect4(() => {
7082
+ postToParent({ type: "ow:navigation", path: pathname });
7083
+ }, [pathname, postToParent]);
7084
+ useEffect4(() => {
8847
7085
  if (!isEditMode) return;
8848
- if (linkPopoverSessionRef.current?.intent === "add-nav") return;
8849
- if (document.querySelector("[data-ohw-section-picker]")) return;
8850
7086
  setLinkPopover(null);
8851
7087
  deselectRef.current();
8852
7088
  deactivateRef.current();
8853
7089
  }, [pathname, isEditMode]);
8854
- useEffect8(() => {
8855
- const contentForNav = () => {
8856
- if (isEditMode) return editContentRef.current;
8857
- if (!subdomain) return {};
8858
- return contentCache.get(subdomain) ?? {};
8859
- };
8860
- let applying = false;
8861
- let rafId = null;
8862
- const run = () => {
8863
- if (footerDragRef.current || applying) return;
8864
- applying = true;
8865
- try {
8866
- const content = contentForNav();
8867
- reconcileNavbarItemsFromContent(content);
8868
- reconcileFooterOrderFromContent(content);
8869
- document.querySelectorAll("footer [data-ohw-href-key]").forEach((el) => {
8870
- if (isFooterHrefKey(el.getAttribute("data-ohw-href-key"))) {
8871
- disableNativeHrefDrag(el);
8872
- }
8873
- });
8874
- } finally {
8875
- applying = false;
8876
- }
8877
- };
8878
- const scheduleRun = () => {
8879
- if (rafId !== null) cancelAnimationFrame(rafId);
8880
- rafId = requestAnimationFrame(() => {
8881
- rafId = null;
8882
- run();
8883
- });
8884
- };
8885
- run();
8886
- const nav = document.querySelector("nav");
8887
- const footer = document.querySelector("footer");
8888
- const observer = new MutationObserver(scheduleRun);
8889
- if (nav) observer.observe(nav, { childList: true, subtree: true });
8890
- if (footer) observer.observe(footer, { childList: true, subtree: true });
8891
- if (!nav && !footer) return;
8892
- return () => {
8893
- observer.disconnect();
8894
- if (rafId !== null) cancelAnimationFrame(rafId);
8895
- };
8896
- }, [isEditMode, pathname, subdomain, fetchState]);
8897
- useEffect8(() => {
7090
+ useEffect4(() => {
8898
7091
  if (!isEditMode) return;
8899
7092
  const measure = () => {
8900
7093
  const h = document.body.scrollHeight;
8901
- if (h > 50) postToParent2({ type: "ow:height", height: h });
7094
+ if (h > 50) postToParent({ type: "ow:height", height: h });
8902
7095
  };
8903
7096
  const t1 = setTimeout(measure, 50);
8904
7097
  const t2 = setTimeout(measure, 500);
@@ -8917,8 +7110,8 @@ function OhhwellsBridge() {
8917
7110
  if (resizeTimer) clearTimeout(resizeTimer);
8918
7111
  window.removeEventListener("resize", handleResize);
8919
7112
  };
8920
- }, [pathname, isEditMode, postToParent2]);
8921
- useEffect8(() => {
7113
+ }, [pathname, isEditMode, postToParent]);
7114
+ useEffect4(() => {
8922
7115
  if (!subdomainFromQuery || isEditMode) return;
8923
7116
  const handleClick = (e) => {
8924
7117
  const anchor = e.target.closest("a");
@@ -8934,7 +7127,7 @@ function OhhwellsBridge() {
8934
7127
  document.addEventListener("click", handleClick, true);
8935
7128
  return () => document.removeEventListener("click", handleClick, true);
8936
7129
  }, [subdomainFromQuery, isEditMode, router]);
8937
- useEffect8(() => {
7130
+ useEffect4(() => {
8938
7131
  if (!isEditMode) {
8939
7132
  editStylesRef.current?.base.remove();
8940
7133
  editStylesRef.current?.forceHover.remove();
@@ -8957,29 +7150,6 @@ function OhhwellsBridge() {
8957
7150
  [data-ohw-editable] {
8958
7151
  display: block;
8959
7152
  }
8960
- /* Native <a> drag steals clicks \u2014 disable for edit links; reorder via press-to-drag / handle. */
8961
- footer [data-ohw-href-key] {
8962
- -webkit-user-drag: none !important;
8963
- }
8964
- footer [data-ohw-footer-col]:hover {
8965
- outline: 1.5px dashed ${PRIMARY2} !important;
8966
- outline-offset: 6px;
8967
- border-radius: 8px;
8968
- }
8969
- html[data-ohw-footer-press-drag] footer,
8970
- html[data-ohw-footer-press-drag] footer * {
8971
- user-select: none !important;
8972
- -webkit-user-select: none !important;
8973
- }
8974
- html[data-ohw-item-dragging] footer,
8975
- html[data-ohw-item-dragging] footer * {
8976
- user-select: none !important;
8977
- -webkit-user-select: none !important;
8978
- pointer-events: none !important;
8979
- }
8980
- html[data-ohw-item-dragging] {
8981
- cursor: grabbing !important;
8982
- }
8983
7153
  [data-ohw-editable]:not([contenteditable]):not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"]) { cursor: text !important; }
8984
7154
  [data-ohw-editable="image"], [data-ohw-editable="image"] *,
8985
7155
  [data-ohw-editable="video"], [data-ohw-editable="video"] *,
@@ -9022,49 +7192,15 @@ function OhhwellsBridge() {
9022
7192
  document.head.appendChild(forceHover);
9023
7193
  document.head.appendChild(stateViews);
9024
7194
  editStylesRef.current = { base, forceHover, stateViews };
9025
- }
9026
- refreshStateRules();
9027
- const handleClick = (e) => {
9028
- if (suppressNextClickRef.current) {
9029
- suppressNextClickRef.current = false;
9030
- e.preventDefault();
9031
- e.stopPropagation();
9032
- return;
9033
- }
9034
- const target = e.target;
9035
- if (target.closest("[data-ohw-toolbar]")) return;
9036
- if (target.closest("[data-ohw-state-toggle]")) return;
9037
- if (target.closest("[data-ohw-max-badge]")) return;
9038
- if (isInsideLinkEditor(target)) return;
9039
- if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
9040
- if (target.closest("[data-ohw-item-drag-surface]")) {
9041
- e.preventDefault();
9042
- e.stopPropagation();
9043
- const selected = selectedElRef.current;
9044
- if (selected && isNavigationItem(selected)) {
9045
- const editable2 = selected.querySelector('[data-ohw-editable="text"]') ?? selected.querySelector("[data-ohw-editable]");
9046
- if (editable2) {
9047
- activateRef.current(editable2, {
9048
- caretX: e.clientX,
9049
- caretY: e.clientY
9050
- });
9051
- }
9052
- } else if (selected?.hasAttribute("data-ohw-footer-col")) {
9053
- const link = listFooterLinksInColumn(selected).find((el) => {
9054
- const r2 = el.getBoundingClientRect();
9055
- return e.clientX >= r2.left && e.clientX <= r2.right && e.clientY >= r2.top && e.clientY <= r2.bottom;
9056
- });
9057
- if (link) selectRef.current(link);
9058
- }
9059
- return;
9060
- }
9061
- const navFromChrome = resolveNavContainerSelectionTarget(target, e.clientX, e.clientY);
9062
- if (navFromChrome) {
9063
- e.preventDefault();
9064
- e.stopPropagation();
9065
- selectFrameRef.current(navFromChrome);
9066
- return;
9067
- }
7195
+ }
7196
+ refreshStateRules();
7197
+ const handleClick = (e) => {
7198
+ const target = e.target;
7199
+ if (target.closest("[data-ohw-toolbar]")) return;
7200
+ if (target.closest("[data-ohw-state-toggle]")) return;
7201
+ if (target.closest("[data-ohw-max-badge]")) return;
7202
+ if (isInsideLinkEditor(target)) return;
7203
+ if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
9068
7204
  e.preventDefault();
9069
7205
  e.stopPropagation();
9070
7206
  return;
@@ -9079,8 +7215,7 @@ function OhhwellsBridge() {
9079
7215
  bumpLinkPopoverGrace();
9080
7216
  setLinkPopoverRef.current({
9081
7217
  key: editable.dataset.ohwKey ?? "",
9082
- mode: "edit",
9083
- target: getLinkHref2(editable)
7218
+ target: getLinkHref(editable)
9084
7219
  });
9085
7220
  return;
9086
7221
  }
@@ -9096,8 +7231,7 @@ function OhhwellsBridge() {
9096
7231
  e.preventDefault();
9097
7232
  e.stopPropagation();
9098
7233
  if (selectedElRef.current === navAnchor) {
9099
- if (e.detail >= 2) return;
9100
- activateRef.current(editable, { caretX: e.clientX, caretY: e.clientY });
7234
+ activateRef.current(editable);
9101
7235
  return;
9102
7236
  }
9103
7237
  selectRef.current(navAnchor);
@@ -9112,42 +7246,10 @@ function OhhwellsBridge() {
9112
7246
  if (hrefAnchor) {
9113
7247
  e.preventDefault();
9114
7248
  e.stopPropagation();
9115
- if (selectedElRef.current === hrefAnchor) {
9116
- const textEditable = hrefAnchor.querySelector('[data-ohw-editable="text"]') ?? hrefAnchor.querySelector("[data-ohw-editable]");
9117
- if (textEditable) {
9118
- activateRef.current(textEditable, {
9119
- caretX: e.clientX,
9120
- caretY: e.clientY
9121
- });
9122
- }
9123
- return;
9124
- }
7249
+ if (selectedElRef.current === hrefAnchor) return;
9125
7250
  selectRef.current(hrefAnchor);
9126
7251
  return;
9127
7252
  }
9128
- const footerColClick = target.closest("[data-ohw-footer-col]");
9129
- if (footerColClick) {
9130
- e.preventDefault();
9131
- e.stopPropagation();
9132
- selectFrameRef.current(footerColClick);
9133
- return;
9134
- }
9135
- const navContainerToSelect = resolveNavContainerSelectionTarget(target, e.clientX, e.clientY);
9136
- if (navContainerToSelect) {
9137
- e.preventDefault();
9138
- e.stopPropagation();
9139
- selectFrameRef.current(navContainerToSelect);
9140
- return;
9141
- }
9142
- const selectedContainer = selectedElRef.current;
9143
- if (selectedContainer && isNavigationContainer(selectedContainer)) {
9144
- const navItem = getNavigationItemAnchor(target);
9145
- if (!navItem && (selectedContainer === target || selectedContainer.contains(target))) {
9146
- e.preventDefault();
9147
- e.stopPropagation();
9148
- return;
9149
- }
9150
- }
9151
7253
  if (activeElRef.current) {
9152
7254
  const sel = window.getSelection();
9153
7255
  if (sel && !sel.isCollapsed) {
@@ -9173,58 +7275,10 @@ function OhhwellsBridge() {
9173
7275
  deselectRef.current();
9174
7276
  deactivateRef.current();
9175
7277
  };
9176
- const handleDblClick = (e) => {
9177
- const target = e.target;
9178
- if (target.closest("[data-ohw-toolbar]")) return;
9179
- if (target.closest("[data-ohw-state-toggle]")) return;
9180
- if (target.closest("[data-ohw-max-badge]")) return;
9181
- if (isInsideLinkEditor(target)) return;
9182
- if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
9183
- return;
9184
- }
9185
- const navLabel = getNavigationLabelEditable(target);
9186
- if (!navLabel) return;
9187
- const { editable } = navLabel;
9188
- e.preventDefault();
9189
- e.stopPropagation();
9190
- if (activeElRef.current !== editable) {
9191
- activateRef.current(editable);
9192
- }
9193
- requestAnimationFrame(() => {
9194
- selectAllTextInEditable(editable);
9195
- refreshActiveCommandsRef.current();
9196
- });
9197
- };
9198
7278
  const handleMouseOver = (e) => {
9199
- if (document.documentElement.hasAttribute("data-ohw-section-picking")) return;
9200
7279
  const target = e.target;
9201
- if (toolbarVariantRef.current !== "select-frame") {
9202
- const navContainer = target.closest("[data-ohw-nav-container]");
9203
- if (navContainer && !getNavigationItemAnchor(target)) {
9204
- hoveredNavContainerRef.current = navContainer;
9205
- setHoveredNavContainerRect(navContainer.getBoundingClientRect());
9206
- hoveredItemElRef.current = null;
9207
- setHoveredItemRect(null);
9208
- return;
9209
- }
9210
- if (!target.closest("[data-ohw-nav-container]")) {
9211
- hoveredNavContainerRef.current = null;
9212
- setHoveredNavContainerRect(null);
9213
- }
9214
- }
9215
- const footerCol = target.closest("[data-ohw-footer-col]");
9216
- if (footerCol) {
9217
- hoveredNavContainerRef.current = null;
9218
- setHoveredNavContainerRect(null);
9219
- if (selectedElRef.current === footerCol) return;
9220
- hoveredItemElRef.current = footerCol;
9221
- setHoveredItemRect(footerCol.getBoundingClientRect());
9222
- return;
9223
- }
9224
7280
  const navAnchor = getNavigationItemAnchor(target);
9225
7281
  if (navAnchor) {
9226
- hoveredNavContainerRef.current = null;
9227
- setHoveredNavContainerRect(null);
9228
7282
  const selected2 = selectedElRef.current;
9229
7283
  if (selected2 === navAnchor || selected2?.contains(navAnchor)) return;
9230
7284
  clearHrefKeyHover(navAnchor);
@@ -9249,23 +7303,6 @@ function OhhwellsBridge() {
9249
7303
  };
9250
7304
  const handleMouseOut = (e) => {
9251
7305
  const target = e.target;
9252
- if (target.closest("[data-ohw-nav-container]")) {
9253
- const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
9254
- if (related2?.closest("[data-ohw-nav-container], [data-ohw-navbar-container-chrome], [data-ohw-navbar-add-button]")) {
9255
- return;
9256
- }
9257
- hoveredNavContainerRef.current = null;
9258
- setHoveredNavContainerRect(null);
9259
- }
9260
- const footerCol = target.closest("[data-ohw-footer-col]");
9261
- if (footerCol && hoveredItemElRef.current === footerCol) {
9262
- const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
9263
- if (related2?.closest("[data-ohw-drag-handle-container], [data-ohw-item-interaction]")) return;
9264
- if (related2?.closest("[data-ohw-footer-col]") === footerCol) return;
9265
- hoveredItemElRef.current = null;
9266
- setHoveredItemRect(null);
9267
- return;
9268
- }
9269
7306
  const navAnchor = getNavigationItemAnchor(target);
9270
7307
  if (navAnchor) {
9271
7308
  const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
@@ -9387,85 +7424,42 @@ function OhhwellsBridge() {
9387
7424
  }
9388
7425
  return smallest;
9389
7426
  };
9390
- const dismissImageHover = () => {
9391
- if (hoveredImageRef.current) {
9392
- hoveredImageRef.current = null;
9393
- hoveredImageHasTextOverlapRef.current = false;
9394
- resumeAnimTracks();
9395
- postToParentRef.current({ type: "ow:image-unhover" });
9396
- }
9397
- clearImageHover();
9398
- };
9399
- const probeNavigationHoverAt = (x, y) => {
9400
- if (toolbarVariantRef.current === "select-frame") {
9401
- hoveredNavContainerRef.current = null;
9402
- setHoveredNavContainerRect(null);
9403
- return;
9404
- }
9405
- const navContainer = document.querySelector("[data-ohw-nav-container]");
9406
- if (!navContainer) {
9407
- hoveredNavContainerRef.current = null;
9408
- setHoveredNavContainerRect(null);
9409
- return;
9410
- }
9411
- const containerRect = navContainer.getBoundingClientRect();
9412
- const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
9413
- if (!overContainer) {
9414
- hoveredNavContainerRef.current = null;
9415
- setHoveredNavContainerRect(null);
9416
- return;
9417
- }
9418
- const navItemHit = Array.from(
9419
- navContainer.querySelectorAll("[data-ohw-href-key]")
9420
- ).find((el) => {
9421
- if (!isNavigationItem(el) || isNavbarButton2(el)) return false;
9422
- const itemRect = el.getBoundingClientRect();
9423
- return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
9424
- });
9425
- if (navItemHit) {
9426
- hoveredNavContainerRef.current = null;
9427
- setHoveredNavContainerRect(null);
9428
- const selected = selectedElRef.current;
9429
- if (selected !== navItemHit && !selected?.contains(navItemHit)) {
9430
- clearHrefKeyHover(navItemHit);
9431
- hoveredItemElRef.current = navItemHit;
9432
- setHoveredItemRect(navItemHit.getBoundingClientRect());
9433
- }
9434
- return;
9435
- }
9436
- hoveredNavContainerRef.current = navContainer;
9437
- setHoveredNavContainerRect(containerRect);
9438
- hoveredItemElRef.current = null;
9439
- setHoveredItemRect(null);
9440
- };
9441
7427
  const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
9442
7428
  if (linkPopoverOpenRef.current) {
9443
- dismissImageHover();
9444
- return;
9445
- }
9446
- const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
9447
- if (isPointOverNavigation(x, y)) {
9448
- dismissImageHover();
9449
- probeNavigationHoverAt(x, y);
7429
+ if (hoveredImageRef.current) {
7430
+ hoveredImageRef.current = null;
7431
+ hoveredImageHasTextOverlapRef.current = false;
7432
+ resumeAnimTracks();
7433
+ clearImageHover();
7434
+ }
9450
7435
  return;
9451
7436
  }
9452
- hoveredNavContainerRef.current = null;
9453
- setHoveredNavContainerRect(null);
9454
7437
  const toggleEl = document.querySelector("[data-ohw-state-toggle]");
9455
7438
  if (toggleEl) {
7439
+ const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
9456
7440
  const tr = toggleEl.getBoundingClientRect();
9457
7441
  if (x >= tr.left && x <= tr.right && y >= tr.top && y <= tr.bottom) {
9458
- dismissImageHover();
7442
+ if (hoveredImageRef.current) {
7443
+ hoveredImageRef.current = null;
7444
+ resumeAnimTracks();
7445
+ clearImageHover();
7446
+ }
9459
7447
  return;
9460
7448
  }
9461
7449
  }
9462
7450
  const imgEl = findImageAtPoint(clientX, clientY, fromParentViewport);
9463
7451
  const activeEl = activeElRef.current;
9464
7452
  if (activeEl && (!imgEl || imgEl.contains(activeEl))) {
9465
- dismissImageHover();
7453
+ if (hoveredImageRef.current) {
7454
+ hoveredImageRef.current = null;
7455
+ hoveredImageHasTextOverlapRef.current = false;
7456
+ resumeAnimTracks();
7457
+ clearImageHover();
7458
+ }
9466
7459
  return;
9467
7460
  }
9468
7461
  if (imgEl) {
7462
+ const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
9469
7463
  const topEl = document.elementFromPoint(x, y);
9470
7464
  if (topEl?.closest('[data-ohw-toolbar], [data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
9471
7465
  if (hoveredImageRef.current) {
@@ -9565,12 +7559,12 @@ function OhhwellsBridge() {
9565
7559
  resumeAnimTracks();
9566
7560
  clearImageHover();
9567
7561
  }
9568
- const { x: x2, y: y2 } = toProbeCoords(clientX, clientY, fromParentViewport);
7562
+ const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
9569
7563
  const textEl = Array.from(
9570
7564
  document.querySelectorAll(NON_MEDIA_SELECTOR)
9571
7565
  ).find((el) => {
9572
7566
  const er = el.getBoundingClientRect();
9573
- return x2 >= er.left && x2 <= er.right && y2 >= er.top && y2 <= er.bottom;
7567
+ return x >= er.left && x <= er.right && y >= er.top && y <= er.bottom;
9574
7568
  });
9575
7569
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
9576
7570
  if (textEl && !textEl.hasAttribute("contenteditable")) {
@@ -9594,14 +7588,6 @@ function OhhwellsBridge() {
9594
7588
  }
9595
7589
  };
9596
7590
  const probeHoverCardsAt = (clientX, clientY, fromParentViewport = false) => {
9597
- if (linkPopoverOpenRef.current || document.documentElement.hasAttribute("data-ohw-section-picking")) {
9598
- if (activeStateElRef.current) {
9599
- activeStateElRef.current.removeAttribute("data-ohw-state-hovered");
9600
- activeStateElRef.current = null;
9601
- setToggleState(null);
9602
- }
9603
- return;
9604
- }
9605
7591
  const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
9606
7592
  const toggleEl = document.querySelector("[data-ohw-state-toggle]");
9607
7593
  if (toggleEl) {
@@ -9674,14 +7660,6 @@ function OhhwellsBridge() {
9674
7660
  probeHoverCardsAt(clientX, clientY);
9675
7661
  };
9676
7662
  const handleDragOver = (e) => {
9677
- const footerSession = footerDragRef.current;
9678
- if (footerSession) {
9679
- e.preventDefault();
9680
- if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
9681
- const slot = footerSession.kind === "link" && footerSession.hrefKey ? hitTestLinkDropSlot(e.clientX, e.clientY, footerSession.hrefKey) : hitTestColumnDropSlot(e.clientX, e.clientY);
9682
- refreshFooterDragVisualsRef.current(footerSession, slot, e.clientX, e.clientY);
9683
- return;
9684
- }
9685
7663
  e.preventDefault();
9686
7664
  const el = findImageAtPoint(e.clientX, e.clientY, false);
9687
7665
  if (!el) {
@@ -9864,7 +7842,6 @@ function OhhwellsBridge() {
9864
7842
  continue;
9865
7843
  }
9866
7844
  if (applyVideoSettingNode(key, val)) continue;
9867
- if (applyCarouselNode(key, val)) continue;
9868
7845
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
9869
7846
  if (el.dataset.ohwEditable === "image") {
9870
7847
  const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
@@ -9887,9 +7864,6 @@ function OhhwellsBridge() {
9887
7864
  sectionsLoadedRef.current = true;
9888
7865
  pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
9889
7866
  }
9890
- editContentRef.current = { ...editContentRef.current, ...content };
9891
- reconcileNavbarItemsFromContent(editContentRef.current);
9892
- reconcileFooterOrderFromContent(editContentRef.current);
9893
7867
  enforceLinkHrefs();
9894
7868
  postToParentRef.current({ type: "ow:hydrate-done" });
9895
7869
  };
@@ -9897,7 +7871,6 @@ function OhhwellsBridge() {
9897
7871
  const handleDeactivate = (e) => {
9898
7872
  if (e.data?.type !== "ow:deactivate") return;
9899
7873
  if (Date.now() < linkPopoverGraceUntilRef.current) return;
9900
- if (document.querySelector("[data-ohw-section-picker]")) return;
9901
7874
  if (linkPopoverOpenRef.current) {
9902
7875
  setLinkPopoverRef.current(null);
9903
7876
  return;
@@ -9906,40 +7879,13 @@ function OhhwellsBridge() {
9906
7879
  deactivateRef.current();
9907
7880
  };
9908
7881
  window.addEventListener("message", handleDeactivate);
9909
- const handleUiEscape = (e) => {
9910
- if (e.data?.type !== "ui:escape") return;
9911
- if (linkPopoverOpenRef.current) {
9912
- setLinkPopoverRef.current(null);
9913
- }
9914
- };
9915
- window.addEventListener("message", handleUiEscape);
9916
7882
  const handleKeyDown = (e) => {
9917
- if (e.key === "Escape" && document.querySelector("[data-ohw-section-picker]")) return;
9918
- if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a" && activeElRef.current) {
9919
- const navAnchor = getNavigationItemAnchor(activeElRef.current);
9920
- if (navAnchor) {
9921
- e.preventDefault();
9922
- selectAllTextInEditable(activeElRef.current);
9923
- refreshActiveCommandsRef.current();
9924
- return;
9925
- }
9926
- }
9927
7883
  if (e.key === "Escape" && linkPopoverOpenRef.current) {
9928
7884
  setLinkPopoverRef.current(null);
9929
7885
  return;
9930
7886
  }
9931
7887
  if (e.key === "Escape" && selectedElRef.current && !activeElRef.current) {
9932
- if (toolbarVariantRef.current === "select-frame") {
9933
- deselectRef.current();
9934
- return;
9935
- }
9936
- const parent = getNavigationSelectionParent(selectedElRef.current);
9937
- if (parent) {
9938
- e.preventDefault();
9939
- selectFrameRef.current(parent);
9940
- } else {
9941
- deselectRef.current();
9942
- }
7888
+ deselectRef.current();
9943
7889
  return;
9944
7890
  }
9945
7891
  if (e.key === "Escape" && activeElRef.current) {
@@ -9997,23 +7943,9 @@ function OhhwellsBridge() {
9997
7943
  if (hoveredItemElRef.current) {
9998
7944
  setHoveredItemRect(hoveredItemElRef.current.getBoundingClientRect());
9999
7945
  }
10000
- if (hoveredNavContainerRef.current) {
10001
- setHoveredNavContainerRect(hoveredNavContainerRef.current.getBoundingClientRect());
10002
- }
10003
7946
  if (siblingHintElRef.current) {
10004
7947
  setSiblingHintRect(siblingHintElRef.current.getBoundingClientRect());
10005
7948
  }
10006
- const selected = selectedElRef.current;
10007
- if (selected && !footerDragRef.current && (selected.hasAttribute("data-ohw-footer-col") || Boolean(selected.closest("footer") && isInferredFooterGroup(selected)))) {
10008
- setSiblingHintRects(
10009
- listFooterColumns().filter((column) => column !== selected).map((column) => column.getBoundingClientRect())
10010
- );
10011
- }
10012
- if (footerDragRef.current) {
10013
- const session = footerDragRef.current;
10014
- const slot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : hitTestColumnDropSlot(session.lastClientX, session.lastClientY);
10015
- refreshFooterDragVisualsRef.current(session, slot, session.lastClientX, session.lastClientY);
10016
- }
10017
7949
  if (hoveredImageRef.current) {
10018
7950
  const el = hoveredImageRef.current;
10019
7951
  const r2 = el.getBoundingClientRect();
@@ -10024,7 +7956,7 @@ function OhhwellsBridge() {
10024
7956
  };
10025
7957
  const handleSave = (e) => {
10026
7958
  if (e.data?.type !== "ow:save") return;
10027
- const nodes = collectEditableNodes(editContentRef.current);
7959
+ const nodes = collectEditableNodes();
10028
7960
  const tracker = document.querySelector("[data-ohw-sections-tracker]");
10029
7961
  if (tracker?.textContent) nodes.push({ key: "__ohw_sections", type: "sections", text: tracker.textContent });
10030
7962
  postToParentRef.current({ type: "ow:save-result", nodes });
@@ -10109,7 +8041,6 @@ function OhhwellsBridge() {
10109
8041
  const handleDocMouseLeave = () => {
10110
8042
  hoveredImageRef.current = null;
10111
8043
  setMediaHover(null);
10112
- setCarouselHover(null);
10113
8044
  document.querySelectorAll("[data-ohw-state-hovered]").forEach((el) => el.removeAttribute("data-ohw-state-hovered"));
10114
8045
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
10115
8046
  activeStateElRef.current = null;
@@ -10149,48 +8080,6 @@ function OhhwellsBridge() {
10149
8080
  if (e.data?.type !== "ow:canvas-height" || typeof e.data.height !== "number") return;
10150
8081
  document.documentElement.style.setProperty("--ohw-canvas-h", `${e.data.height}px`);
10151
8082
  };
10152
- const handleCarouselChange = (e) => {
10153
- if (e.data?.type !== "ow:carousel-change") return;
10154
- const { key, images } = e.data;
10155
- if (!key || !Array.isArray(images)) return;
10156
- const text = JSON.stringify(images);
10157
- applyCarouselValue(key, images);
10158
- editContentRef.current = { ...editContentRef.current, [key]: text };
10159
- postToParentRef.current({ type: "ow:change", nodes: [{ key, text }] });
10160
- setCarouselHover(null);
10161
- };
10162
- const findCarouselAtPoint = (clientX, clientY) => {
10163
- const containers = Array.from(document.querySelectorAll(`[${CAROUSEL_ATTR}]`));
10164
- for (let i = containers.length - 1; i >= 0; i--) {
10165
- const r2 = containers[i].getBoundingClientRect();
10166
- if (clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom) {
10167
- return containers[i];
10168
- }
10169
- }
10170
- return null;
10171
- };
10172
- const isPointOverEditable = (scope, clientX, clientY) => {
10173
- const editables = scope.querySelectorAll("[data-ohw-editable], [data-ohw-href-key]");
10174
- for (const el of editables) {
10175
- const r2 = el.getBoundingClientRect();
10176
- if (clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom) return true;
10177
- }
10178
- return false;
10179
- };
10180
- const handleCarouselHover = (e) => {
10181
- const container = findCarouselAtPoint(e.clientX, e.clientY);
10182
- const scope = container?.closest("[data-ohw-section]") ?? container?.parentElement ?? null;
10183
- if (!container || !scope || isPointOverEditable(scope, e.clientX, e.clientY)) {
10184
- setCarouselHover((prev) => prev ? null : prev);
10185
- return;
10186
- }
10187
- const key = container.getAttribute("data-ohw-key") ?? "";
10188
- if (!key) return;
10189
- const r2 = getVisibleRect(container);
10190
- setCarouselHover(
10191
- (prev) => prev && prev.key === key && prev.rect.top === r2.top && prev.rect.left === r2.left && prev.rect.width === r2.width && prev.rect.height === r2.height ? prev : { key, rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height } }
10192
- );
10193
- };
10194
8083
  const applyToolbarPos = (rect) => {
10195
8084
  const ps = parentScrollRef.current;
10196
8085
  const approxW = 330;
@@ -10250,45 +8139,9 @@ function OhhwellsBridge() {
10250
8139
  return clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom;
10251
8140
  });
10252
8141
  if (textEditable) {
10253
- const hrefCtx = getHrefKeyFromElement(textEditable);
10254
- const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
10255
- if (navAnchor) {
10256
- if (selectedElRef.current === navAnchor) {
10257
- activateRef.current(textEditable, { caretX: clientX, caretY: clientY });
10258
- } else {
10259
- selectRef.current(navAnchor);
10260
- }
10261
- return;
10262
- }
10263
- activateRef.current(textEditable, { caretX: clientX, caretY: clientY });
8142
+ activateRef.current(textEditable);
10264
8143
  return;
10265
8144
  }
10266
- const navContainer = document.querySelector("[data-ohw-nav-container]");
10267
- if (navContainer) {
10268
- const r2 = navContainer.getBoundingClientRect();
10269
- const pad = 8;
10270
- const over = clientX >= r2.left - pad && clientX <= r2.right + pad && clientY >= r2.top - pad && clientY <= r2.bottom + pad;
10271
- if (over && !isPointOverNavItem(navContainer, clientX, clientY)) {
10272
- selectFrameRef.current(navContainer);
10273
- return;
10274
- }
10275
- }
10276
- const navRoot = document.querySelector("[data-ohw-nav-root]");
10277
- if (navRoot && navContainer) {
10278
- const rr = navRoot.getBoundingClientRect();
10279
- if (clientX >= rr.left && clientX <= rr.right && clientY >= rr.top && clientY <= rr.bottom && !isPointOverNavItem(navContainer, clientX, clientY)) {
10280
- const book = navRoot.querySelector('[data-ohw-role="navbar-button"]');
10281
- if (book) {
10282
- const br = book.getBoundingClientRect();
10283
- if (clientX >= br.left && clientX <= br.right && clientY >= br.top && clientY <= br.bottom) {
10284
- deactivateRef.current();
10285
- return;
10286
- }
10287
- }
10288
- selectFrameRef.current(navContainer);
10289
- return;
10290
- }
10291
- }
10292
8145
  deactivateRef.current();
10293
8146
  };
10294
8147
  window.addEventListener("message", handleSave);
@@ -10299,7 +8152,6 @@ function OhhwellsBridge() {
10299
8152
  window.addEventListener("message", handleRemoveSchedulingSection);
10300
8153
  window.addEventListener("message", handleImageUrl);
10301
8154
  window.addEventListener("message", handleImageUploading);
10302
- window.addEventListener("message", handleCarouselChange);
10303
8155
  window.addEventListener("message", handleCanvasHeight);
10304
8156
  window.addEventListener("message", handleParentScroll);
10305
8157
  window.addEventListener("message", handlePointerSync);
@@ -10311,13 +8163,11 @@ function OhhwellsBridge() {
10311
8163
  };
10312
8164
  window.addEventListener("resize", handleViewportResize, { passive: true });
10313
8165
  document.addEventListener("click", handleClick, true);
10314
- document.addEventListener("dblclick", handleDblClick, true);
10315
8166
  document.addEventListener("paste", handlePaste, true);
10316
8167
  document.addEventListener("input", handleInput, true);
10317
8168
  document.addEventListener("mouseover", handleMouseOver, true);
10318
8169
  document.addEventListener("mouseout", handleMouseOut, true);
10319
8170
  document.addEventListener("mousemove", handleMouseMove, true);
10320
- document.addEventListener("mousemove", handleCarouselHover, true);
10321
8171
  document.addEventListener("mouseleave", handleDocMouseLeave);
10322
8172
  document.addEventListener("dragover", handleDragOver, true);
10323
8173
  document.addEventListener("dragleave", handleDragLeave, true);
@@ -10327,13 +8177,11 @@ function OhhwellsBridge() {
10327
8177
  window.addEventListener("scroll", handleScroll, true);
10328
8178
  return () => {
10329
8179
  document.removeEventListener("click", handleClick, true);
10330
- document.removeEventListener("dblclick", handleDblClick, true);
10331
8180
  document.removeEventListener("paste", handlePaste, true);
10332
8181
  document.removeEventListener("input", handleInput, true);
10333
8182
  document.removeEventListener("mouseover", handleMouseOver, true);
10334
8183
  document.removeEventListener("mouseout", handleMouseOut, true);
10335
8184
  document.removeEventListener("mousemove", handleMouseMove, true);
10336
- document.removeEventListener("mousemove", handleCarouselHover, true);
10337
8185
  document.removeEventListener("mouseleave", handleDocMouseLeave);
10338
8186
  document.removeEventListener("dragover", handleDragOver, true);
10339
8187
  document.removeEventListener("dragleave", handleDragLeave, true);
@@ -10349,7 +8197,6 @@ function OhhwellsBridge() {
10349
8197
  window.removeEventListener("message", handleRemoveSchedulingSection);
10350
8198
  window.removeEventListener("message", handleImageUrl);
10351
8199
  window.removeEventListener("message", handleImageUploading);
10352
- window.removeEventListener("message", handleCarouselChange);
10353
8200
  window.removeEventListener("message", handleCanvasHeight);
10354
8201
  window.removeEventListener("message", handleParentScroll);
10355
8202
  window.removeEventListener("resize", handleViewportResize);
@@ -10357,162 +8204,13 @@ function OhhwellsBridge() {
10357
8204
  window.removeEventListener("message", handleClickAt);
10358
8205
  window.removeEventListener("message", handleHydrate);
10359
8206
  window.removeEventListener("message", handleDeactivate);
10360
- window.removeEventListener("message", handleUiEscape);
10361
8207
  autoSaveTimers.current.forEach(clearTimeout);
10362
8208
  autoSaveTimers.current.clear();
10363
8209
  if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
10364
8210
  if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
10365
8211
  };
10366
8212
  }, [isEditMode, refreshStateRules]);
10367
- useEffect8(() => {
10368
- if (!isEditMode) return;
10369
- const THRESHOLD = 10;
10370
- const resolveWasSelected = (el) => {
10371
- if (selectedElRef.current === el) return true;
10372
- const activeAnchor = activeElRef.current ? getNavigationItemAnchor(activeElRef.current) : null;
10373
- return activeAnchor === el;
10374
- };
10375
- const onPointerDown = (e) => {
10376
- if (e.button !== 0) return;
10377
- if (footerDragRef.current) return;
10378
- const target = e.target;
10379
- if (!target) return;
10380
- if (target.closest('[data-ohw-drag-handle-container], [data-slot="drag-handle"], [data-ohw-toolbar], [data-ohw-item-toolbar-anchor], [data-ohw-link-popover-root]')) {
10381
- return;
10382
- }
10383
- if (target.closest("[data-ohw-item-drag-surface]")) return;
10384
- const anchor = getNavigationItemAnchor(target);
10385
- const hrefKey = anchor?.getAttribute("data-ohw-href-key") ?? null;
10386
- if (anchor && isFooterHrefKey(hrefKey)) {
10387
- armFooterPressDrag();
10388
- footerPointerDragRef.current = {
10389
- el: anchor,
10390
- kind: "link",
10391
- startX: e.clientX,
10392
- startY: e.clientY,
10393
- pointerId: e.pointerId,
10394
- wasSelected: resolveWasSelected(anchor),
10395
- started: false
10396
- };
10397
- return;
10398
- }
10399
- const col = target.closest("[data-ohw-footer-col]");
10400
- if (col && !getNavigationItemAnchor(target)) {
10401
- armFooterPressDrag();
10402
- footerPointerDragRef.current = {
10403
- el: col,
10404
- kind: "column",
10405
- startX: e.clientX,
10406
- startY: e.clientY,
10407
- pointerId: e.pointerId,
10408
- wasSelected: resolveWasSelected(col),
10409
- started: false
10410
- };
10411
- }
10412
- };
10413
- const onPointerMove = (e) => {
10414
- const pending = footerPointerDragRef.current;
10415
- if (!pending) return;
10416
- if (pending.started) {
10417
- e.preventDefault();
10418
- clearTextSelection();
10419
- const session = footerDragRef.current;
10420
- if (!session) return;
10421
- const slot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(e.clientX, e.clientY, session.hrefKey) : hitTestColumnDropSlot(e.clientX, e.clientY);
10422
- refreshFooterDragVisualsRef.current(session, slot, e.clientX, e.clientY);
10423
- return;
10424
- }
10425
- const dx = e.clientX - pending.startX;
10426
- const dy = e.clientY - pending.startY;
10427
- if (dx * dx + dy * dy < THRESHOLD * THRESHOLD) return;
10428
- e.preventDefault();
10429
- pending.started = true;
10430
- clearTextSelection();
10431
- try {
10432
- document.body.setPointerCapture(pending.pointerId);
10433
- } catch {
10434
- }
10435
- if (linkPopoverOpenRef.current) {
10436
- setLinkPopoverRef.current(null);
10437
- }
10438
- if (activeElRef.current) {
10439
- deactivateRef.current();
10440
- }
10441
- if (pending.kind === "link") {
10442
- const key = pending.el.getAttribute("data-ohw-href-key");
10443
- if (!key) return;
10444
- const column = findFooterColumnForLink(pending.el);
10445
- const columns2 = listFooterColumns();
10446
- beginFooterDragRef.current({
10447
- kind: "link",
10448
- hrefKey: key,
10449
- columnEl: column,
10450
- sourceColumnIndex: column ? columns2.indexOf(column) : 0,
10451
- wasSelected: pending.wasSelected,
10452
- draggedEl: pending.el,
10453
- lastClientX: e.clientX,
10454
- lastClientY: e.clientY,
10455
- activeSlot: null
10456
- });
10457
- return;
10458
- }
10459
- const columns = listFooterColumns();
10460
- const idx = columns.indexOf(pending.el);
10461
- if (idx < 0) return;
10462
- beginFooterDragRef.current({
10463
- kind: "column",
10464
- hrefKey: null,
10465
- columnEl: pending.el,
10466
- sourceColumnIndex: idx,
10467
- wasSelected: pending.wasSelected,
10468
- draggedEl: pending.el,
10469
- lastClientX: e.clientX,
10470
- lastClientY: e.clientY,
10471
- activeSlot: null
10472
- });
10473
- };
10474
- const endPointerDrag = (e) => {
10475
- const pending = footerPointerDragRef.current;
10476
- footerPointerDragRef.current = null;
10477
- try {
10478
- if (document.body.hasPointerCapture(e.pointerId)) {
10479
- document.body.releasePointerCapture(e.pointerId);
10480
- }
10481
- } catch {
10482
- }
10483
- if (!pending?.started) {
10484
- unlockFooterDragInteraction();
10485
- return;
10486
- }
10487
- suppressNextClickRef.current = true;
10488
- commitFooterDragRef.current(e.clientX, e.clientY);
10489
- };
10490
- const blockSelectStart = (e) => {
10491
- if (footerDragRef.current || footerPointerDragRef.current?.started || document.documentElement.hasAttribute("data-ohw-footer-press-drag")) {
10492
- e.preventDefault();
10493
- }
10494
- };
10495
- const onDragEnd = (_e) => {
10496
- if (!footerDragRef.current) return;
10497
- commitFooterDragRef.current();
10498
- };
10499
- document.addEventListener("pointerdown", onPointerDown, true);
10500
- document.addEventListener("pointermove", onPointerMove, true);
10501
- document.addEventListener("pointerup", endPointerDrag, true);
10502
- document.addEventListener("pointercancel", endPointerDrag, true);
10503
- document.addEventListener("selectstart", blockSelectStart, true);
10504
- document.addEventListener("dragend", onDragEnd, true);
10505
- return () => {
10506
- document.removeEventListener("pointerdown", onPointerDown, true);
10507
- document.removeEventListener("pointermove", onPointerMove, true);
10508
- document.removeEventListener("pointerup", endPointerDrag, true);
10509
- document.removeEventListener("pointercancel", endPointerDrag, true);
10510
- document.removeEventListener("selectstart", blockSelectStart, true);
10511
- document.removeEventListener("dragend", onDragEnd, true);
10512
- unlockFooterDragInteraction();
10513
- };
10514
- }, [isEditMode]);
10515
- useEffect8(() => {
8213
+ useEffect4(() => {
10516
8214
  const handler = (e) => {
10517
8215
  if (e.data?.type !== "ow:request-schedule-config") return;
10518
8216
  const insertAfterVal = e.data.insertAfter;
@@ -10528,7 +8226,7 @@ function OhhwellsBridge() {
10528
8226
  window.addEventListener("message", handler);
10529
8227
  return () => window.removeEventListener("message", handler);
10530
8228
  }, [processConfigRequest]);
10531
- useEffect8(() => {
8229
+ useEffect4(() => {
10532
8230
  if (!isEditMode) return;
10533
8231
  document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
10534
8232
  el.removeAttribute("data-ohw-active-state");
@@ -10549,33 +8247,27 @@ function OhhwellsBridge() {
10549
8247
  const next = { ...prev, [pathKey]: sections };
10550
8248
  return shouldUseDevFixtures() ? { ...DEV_SECTIONS_BY_PATH, ...next } : next;
10551
8249
  });
10552
- postToParent2({
10553
- type: "ow:ready",
10554
- version: "1",
10555
- path: pathname,
10556
- nodes: collectEditableNodes(editContentRef.current),
10557
- sections
10558
- });
10559
- postToParent2({ type: "ow:request-site-pages" });
8250
+ postToParent({ type: "ow:ready", version: "1", path: pathname, nodes: collectEditableNodes(), sections });
8251
+ postToParent({ type: "ow:request-site-pages" });
10560
8252
  }, 150);
10561
8253
  return () => {
10562
8254
  cancelAnimationFrame(raf);
10563
8255
  clearTimeout(timer);
10564
8256
  };
10565
- }, [pathname, isEditMode, refreshStateRules, postToParent2]);
10566
- useEffect8(() => {
8257
+ }, [pathname, isEditMode, refreshStateRules, postToParent]);
8258
+ useEffect4(() => {
10567
8259
  scrollToHashSectionWhenReady();
10568
8260
  const onHashChange = () => scrollToHashSectionWhenReady();
10569
8261
  window.addEventListener("hashchange", onHashChange);
10570
8262
  return () => window.removeEventListener("hashchange", onHashChange);
10571
8263
  }, [pathname]);
10572
- const handleCommand = useCallback4((cmd) => {
8264
+ const handleCommand = useCallback2((cmd) => {
10573
8265
  document.execCommand(cmd, false);
10574
8266
  activeElRef.current?.focus();
10575
8267
  if (activeElRef.current) setToolbarRect(getEditMeasureEl(activeElRef.current).getBoundingClientRect());
10576
8268
  refreshActiveCommandsRef.current();
10577
8269
  }, []);
10578
- const handleStateChange = useCallback4((state) => {
8270
+ const handleStateChange = useCallback2((state) => {
10579
8271
  if (!activeStateElRef.current) return;
10580
8272
  const el = activeStateElRef.current;
10581
8273
  if (state === "Default") {
@@ -10588,22 +8280,18 @@ function OhhwellsBridge() {
10588
8280
  }
10589
8281
  setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
10590
8282
  }, [deactivate]);
10591
- const closeLinkPopover = useCallback4(() => {
10592
- addNavAfterAnchorRef.current = null;
10593
- setLinkPopover(null);
10594
- }, []);
10595
- const openLinkPopoverForActive = useCallback4(() => {
8283
+ const closeLinkPopover = useCallback2(() => setLinkPopover(null), []);
8284
+ const openLinkPopoverForActive = useCallback2(() => {
10596
8285
  const hrefCtx = getHrefKeyFromElement(activeElRef.current);
10597
8286
  if (!hrefCtx) return;
10598
8287
  bumpLinkPopoverGrace();
10599
8288
  setLinkPopover({
10600
8289
  key: hrefCtx.key,
10601
- mode: "edit",
10602
- target: getLinkHref2(hrefCtx.anchor)
8290
+ target: getLinkHref(hrefCtx.anchor)
10603
8291
  });
10604
8292
  deactivate();
10605
8293
  }, [deactivate]);
10606
- const openLinkPopoverForSelected = useCallback4(() => {
8294
+ const openLinkPopoverForSelected = useCallback2(() => {
10607
8295
  const anchor = selectedElRef.current;
10608
8296
  if (!anchor) return;
10609
8297
  const key = anchor.getAttribute("data-ohw-href-key");
@@ -10611,80 +8299,30 @@ function OhhwellsBridge() {
10611
8299
  bumpLinkPopoverGrace();
10612
8300
  setLinkPopover({
10613
8301
  key,
10614
- mode: "edit",
10615
- target: getLinkHref2(anchor)
8302
+ target: getLinkHref(anchor)
10616
8303
  });
10617
8304
  deselect();
10618
8305
  }, [deselect]);
10619
- const handleLinkPopoverSubmit = useCallback4(
8306
+ const handleLinkPopoverSubmit = useCallback2(
10620
8307
  (target) => {
10621
- const session = linkPopoverSessionRef.current;
10622
- if (!session) return;
10623
- if (session.intent === "add-nav") {
10624
- const trimmed = target.trim();
10625
- let href = trimmed;
10626
- let label = "Untitled";
10627
- if (trimmed) {
10628
- const { pageRoute, sectionId } = parseTarget(trimmed);
10629
- const page = resolvePage(pageRoute, sitePages);
10630
- const pageSections = getSectionsForPath(sectionsByPath, pageRoute);
10631
- const section = sectionId ? pageSections.find((s) => s.id === sectionId) : void 0;
10632
- label = section?.label ?? page.title;
10633
- href = trimmed;
10634
- }
10635
- const afterAnchor = addNavAfterAnchorRef.current;
10636
- const { anchor, hrefKey, labelKey, index, order } = insertNavbarItem(href, label, afterAnchor);
10637
- applyLinkByKey(hrefKey, href);
10638
- document.querySelectorAll(`[data-ohw-key="${labelKey}"]`).forEach((el) => {
10639
- el.textContent = label;
10640
- });
10641
- const navCount = String(index + 1);
10642
- const orderJson = JSON.stringify(order);
10643
- editContentRef.current = {
10644
- ...editContentRef.current,
10645
- [hrefKey]: href,
10646
- [labelKey]: label,
10647
- [NAV_COUNT_KEY]: navCount,
10648
- [NAV_ORDER_KEY]: orderJson
10649
- };
10650
- postToParent2({
10651
- type: "ow:change",
10652
- nodes: [
10653
- { key: hrefKey, text: href },
10654
- { key: labelKey, text: label },
10655
- { key: NAV_COUNT_KEY, text: navCount },
10656
- { key: NAV_ORDER_KEY, text: orderJson }
10657
- ]
10658
- });
10659
- postToParent2({ type: "ow:toast", title: "Link added", toastType: "success" });
10660
- addNavAfterAnchorRef.current = null;
10661
- setLinkPopover(null);
10662
- enforceLinkHrefs();
10663
- requestAnimationFrame(() => {
10664
- selectRef.current(anchor);
10665
- });
10666
- return;
10667
- }
10668
- const { key } = session;
8308
+ if (!linkPopover) return;
8309
+ const { key } = linkPopover;
10669
8310
  applyLinkByKey(key, target);
10670
- postToParent2({ type: "ow:change", nodes: [{ key, text: target }] });
8311
+ postToParent({ type: "ow:change", nodes: [{ key, text: target }] });
10671
8312
  setLinkPopover(null);
10672
8313
  },
10673
- [postToParent2, sitePages, sectionsByPath]
10674
- );
10675
- const handleMediaReplace = useCallback4(
10676
- (key) => {
10677
- postToParent2({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
10678
- },
10679
- [postToParent2, mediaHover?.elementType]
8314
+ [linkPopover, postToParent]
10680
8315
  );
10681
- const handleEditCarousel = useCallback4(
8316
+ const showEditLink = toolbarShowEditLink;
8317
+ const currentSections = sectionsByPath[pathname] ?? [];
8318
+ linkPopoverOpenRef.current = linkPopover !== null;
8319
+ const handleMediaReplace = useCallback2(
10682
8320
  (key) => {
10683
- postToParent2({ type: "ow:carousel-open", key, images: readCarouselValue(key) });
8321
+ postToParent({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
10684
8322
  },
10685
- [postToParent2]
8323
+ [postToParent, mediaHover?.elementType]
10686
8324
  );
10687
- const handleMediaFadeOutComplete = useCallback4((key) => {
8325
+ const handleMediaFadeOutComplete = useCallback2((key) => {
10688
8326
  setUploadingRects((prev) => {
10689
8327
  if (!(key in prev)) return prev;
10690
8328
  const next = { ...prev };
@@ -10692,7 +8330,7 @@ function OhhwellsBridge() {
10692
8330
  return next;
10693
8331
  });
10694
8332
  }, []);
10695
- const handleVideoSettingsChange = useCallback4(
8333
+ const handleVideoSettingsChange = useCallback2(
10696
8334
  (key, settings) => {
10697
8335
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
10698
8336
  const video = getVideoEl(el);
@@ -10700,7 +8338,7 @@ function OhhwellsBridge() {
10700
8338
  if (typeof settings.autoplay === "boolean") video.autoplay = settings.autoplay;
10701
8339
  if (typeof settings.muted === "boolean") video.muted = settings.muted;
10702
8340
  syncVideoPlayback(video);
10703
- postToParent2({
8341
+ postToParent({
10704
8342
  type: "ow:change",
10705
8343
  nodes: [
10706
8344
  { key: `${key}${VIDEO_AUTOPLAY_SUFFIX}`, text: String(video.autoplay) },
@@ -10712,15 +8350,12 @@ function OhhwellsBridge() {
10712
8350
  );
10713
8351
  });
10714
8352
  },
10715
- [postToParent2]
8353
+ [postToParent]
10716
8354
  );
10717
- const showEditLink = toolbarShowEditLink;
10718
- const currentSections = sectionsByPath[pathname] ?? [];
10719
- linkPopoverOpenRef.current = linkPopover !== null;
10720
- return bridgeRoot ? createPortal2(
10721
- /* @__PURE__ */ jsxs14(Fragment5, { children: [
10722
- /* @__PURE__ */ jsx25("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
10723
- Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ jsx25(
8355
+ return bridgeRoot ? createPortal(
8356
+ /* @__PURE__ */ jsxs12(Fragment4, { children: [
8357
+ /* @__PURE__ */ jsx22("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
8358
+ Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ jsx22(
10724
8359
  MediaOverlay,
10725
8360
  {
10726
8361
  hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
@@ -10731,7 +8366,7 @@ function OhhwellsBridge() {
10731
8366
  },
10732
8367
  `uploading-${key}`
10733
8368
  )),
10734
- mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ jsx25(
8369
+ mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ jsx22(
10735
8370
  MediaOverlay,
10736
8371
  {
10737
8372
  hover: mediaHover,
@@ -10740,33 +8375,53 @@ function OhhwellsBridge() {
10740
8375
  onVideoSettingsChange: handleVideoSettingsChange
10741
8376
  }
10742
8377
  ),
10743
- carouselHover && /* @__PURE__ */ jsx25(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
10744
- siblingHintRect && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
10745
- siblingHintRects.map((rect, i) => /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
10746
- isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
10747
- isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ jsx25(
10748
- "div",
8378
+ siblingHintRect && !isItemDragging && /* @__PURE__ */ jsx22(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
8379
+ hoveredItemRect && !siblingHintRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx22(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
8380
+ toolbarRect && toolbarVariant === "link-action" && /* @__PURE__ */ jsx22(
8381
+ ItemInteractionLayer,
10749
8382
  {
10750
- className: "pointer-events-none fixed z-2147483646",
10751
- style: {
10752
- left: slot.left,
10753
- top: slot.top,
10754
- width: slot.width,
10755
- height: slot.height
10756
- },
10757
- children: /* @__PURE__ */ jsx25(DropIndicator, { direction: slot.direction, state: activeFooterDropIndex === i ? "dragActive" : "dragIdle", className: slot.direction === "horizontal" ? "!h-full !w-full" : "!h-full !w-full" })
10758
- },
10759
- `footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
10760
- )),
10761
- hoveredNavContainerRect && toolbarVariant !== "select-frame" && !linkPopover && !isItemDragging && !siblingHintRect && siblingHintRects.length === 0 && /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
10762
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && /* @__PURE__ */ jsx25(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
10763
- hoveredItemRect && !hoveredNavContainerRect && !siblingHintRect && siblingHintRects.length === 0 && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
10764
- toolbarRect && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect: isItemDragging && draggedItemRect && footerDragRef.current?.wasSelected ? draggedItemRect : toolbarRect, elRef: glowElRef, state: isItemDragging ? "dragging" : resolveItemInteractionState(toolbarRect, parentScrollRef.current), showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey) || toolbarVariant === "select-frame" && isFooterFrameSelection, dragDisabled: reorderDragDisabled, dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item", onDragHandleDragStart: handleItemDragStart, onDragHandleDragEnd: handleItemDragEnd, onItemPointerDown: handleItemChromePointerDown, onItemClick: handleItemChromeClick, toolbar: toolbarVariant === "link-action" && !isItemDragging ? /* @__PURE__ */ jsx25(ItemActionToolbar, { onEditLink: openLinkPopoverForSelected, addItemDisabled: true, editLinkDisabled: false, moreDisabled: true }) : void 0 }),
10765
- toolbarRect && toolbarVariant === "rich-text" && /* @__PURE__ */ jsxs14(Fragment5, { children: [
10766
- /* @__PURE__ */ jsx25(EditGlowChrome, { rect: toolbarRect, elRef: glowElRef, reorderHrefKey, dragDisabled: reorderDragDisabled }),
10767
- /* @__PURE__ */ jsx25(FloatingToolbar, { rect: toolbarRect, parentScroll: parentScrollRef.current, elRef: toolbarElRef, onCommand: handleCommand, activeCommands, showEditLink, onEditLink: openLinkPopoverForActive })
8383
+ rect: toolbarRect,
8384
+ elRef: glowElRef,
8385
+ state: isItemDragging ? "dragging" : resolveItemInteractionState(toolbarRect, parentScrollRef.current),
8386
+ showHandle: Boolean(reorderHrefKey),
8387
+ dragDisabled: reorderDragDisabled,
8388
+ dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
8389
+ onDragHandleDragStart: handleItemDragStart,
8390
+ onDragHandleDragEnd: handleItemDragEnd,
8391
+ toolbar: isItemDragging ? void 0 : /* @__PURE__ */ jsx22(
8392
+ ItemActionToolbar,
8393
+ {
8394
+ onEditLink: openLinkPopoverForSelected,
8395
+ onAddItem: handleAddNavigationItem,
8396
+ addItemDisabled: false
8397
+ }
8398
+ )
8399
+ }
8400
+ ),
8401
+ toolbarRect && toolbarVariant === "rich-text" && /* @__PURE__ */ jsxs12(Fragment4, { children: [
8402
+ /* @__PURE__ */ jsx22(
8403
+ EditGlowChrome,
8404
+ {
8405
+ rect: toolbarRect,
8406
+ elRef: glowElRef,
8407
+ reorderHrefKey,
8408
+ dragDisabled: reorderDragDisabled
8409
+ }
8410
+ ),
8411
+ /* @__PURE__ */ jsx22(
8412
+ FloatingToolbar,
8413
+ {
8414
+ rect: toolbarRect,
8415
+ parentScroll: parentScrollRef.current,
8416
+ elRef: toolbarElRef,
8417
+ onCommand: handleCommand,
8418
+ activeCommands,
8419
+ showEditLink,
8420
+ onEditLink: openLinkPopoverForActive
8421
+ }
8422
+ )
10768
8423
  ] }),
10769
- maxBadge && /* @__PURE__ */ jsxs14(
8424
+ maxBadge && /* @__PURE__ */ jsxs12(
10770
8425
  "div",
10771
8426
  {
10772
8427
  "data-ohw-max-badge": "",
@@ -10792,29 +8447,56 @@ function OhhwellsBridge() {
10792
8447
  ]
10793
8448
  }
10794
8449
  ),
10795
- toggleState && !linkPopover && /* @__PURE__ */ jsx25(StateToggle, { rect: toggleState.rect, activeState: toggleState.activeState, states: toggleState.states, onStateChange: handleStateChange }),
10796
- sectionGap && !linkPopover && /* @__PURE__ */ jsxs14("div", { "data-ohw-section-insert-line": "", className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none", style: { top: sectionGap.y, transform: "translateY(-50%)" }, children: [
10797
- /* @__PURE__ */ jsx25("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
10798
- /* @__PURE__ */ jsx25(
10799
- Badge,
10800
- {
10801
- 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",
10802
- onClick: () => {
10803
- window.parent.postMessage(
10804
- {
10805
- type: "ow:add-section",
10806
- insertAfter: sectionGap.insertAfter,
10807
- insertBefore: sectionGap.insertBefore
8450
+ toggleState && /* @__PURE__ */ jsx22(
8451
+ StateToggle,
8452
+ {
8453
+ rect: toggleState.rect,
8454
+ activeState: toggleState.activeState,
8455
+ states: toggleState.states,
8456
+ onStateChange: handleStateChange
8457
+ }
8458
+ ),
8459
+ sectionGap && /* @__PURE__ */ jsxs12(
8460
+ "div",
8461
+ {
8462
+ "data-ohw-section-insert-line": "",
8463
+ className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
8464
+ style: { top: sectionGap.y, transform: "translateY(-50%)" },
8465
+ children: [
8466
+ /* @__PURE__ */ jsx22("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
8467
+ /* @__PURE__ */ jsx22(
8468
+ Badge,
8469
+ {
8470
+ 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",
8471
+ onClick: () => {
8472
+ window.parent.postMessage(
8473
+ { type: "ow:add-section", insertAfter: sectionGap.insertAfter, insertBefore: sectionGap.insertBefore },
8474
+ "*"
8475
+ );
10808
8476
  },
10809
- "*"
10810
- );
10811
- },
10812
- children: "Add Section"
10813
- }
10814
- ),
10815
- /* @__PURE__ */ jsx25("div", { className: "flex-1 bg-primary", style: { height: 3 } })
10816
- ] }),
10817
- linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx25(LinkPopover, { panelRef: linkPopoverPanelRef, portalContainer: dialogPortalContainer, open: true, mode: linkPopover.mode ?? "edit", pages: sitePages, sections: currentSections, sectionsByPath, initialTarget: linkPopover.target, existingTargets: linkPopover.intent === "add-nav" ? getNavbarExistingTargets() : [], onClose: closeLinkPopover, onSubmit: handleLinkPopoverSubmit }, linkPopover.key) : null
8477
+ children: "Add Section"
8478
+ }
8479
+ ),
8480
+ /* @__PURE__ */ jsx22("div", { className: "flex-1 bg-primary", style: { height: 3 } })
8481
+ ]
8482
+ }
8483
+ ),
8484
+ linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx22(
8485
+ LinkPopover,
8486
+ {
8487
+ panelRef: linkPopoverPanelRef,
8488
+ portalContainer: dialogPortalContainer,
8489
+ open: true,
8490
+ mode: "edit",
8491
+ pages: sitePages,
8492
+ sections: currentSections,
8493
+ sectionsByPath,
8494
+ initialTarget: linkPopover.target,
8495
+ onClose: closeLinkPopover,
8496
+ onSubmit: handleLinkPopoverSubmit
8497
+ },
8498
+ `${linkPopover.key}-${pathname}`
8499
+ ) : null
10818
8500
  ] }),
10819
8501
  bridgeRoot
10820
8502
  ) : null;
@@ -10824,7 +8506,6 @@ export {
10824
8506
  CustomToolbarButton,
10825
8507
  CustomToolbarDivider,
10826
8508
  DragHandle,
10827
- DropIndicator,
10828
8509
  ItemActionToolbar,
10829
8510
  ItemInteractionLayer,
10830
8511
  LinkEditorPanel,
@@ -10839,14 +8520,12 @@ export {
10839
8520
  TooltipProvider,
10840
8521
  TooltipTrigger,
10841
8522
  buildTarget,
10842
- dropIndicatorVariants,
10843
8523
  filterAvailablePages,
10844
8524
  getEditModeInitialState,
10845
8525
  isEditSessionActive,
10846
8526
  isValidUrl,
10847
8527
  parseTarget,
10848
8528
  toggleVariants,
10849
- useOhwCarousel,
10850
8529
  validateUrlInput
10851
8530
  };
10852
8531
  //# sourceMappingURL=index.js.map