@ohhwells/bridge 0.1.47 → 0.1.48-next.113

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 React11, { useCallback as useCallback4, useEffect as useEffect8, useLayoutEffect as useLayoutEffect3, useRef as useRef7, useState as useState7 } from "react";
4
+ import React11, { useCallback as useCallback5, useEffect as useEffect9, useLayoutEffect as useLayoutEffect3, useRef as useRef7, useState as useState8 } from "react";
5
5
  import { createRoot } from "react-dom/client";
6
6
  import { flushSync } from "react-dom";
7
7
 
@@ -48,12 +48,13 @@ function useLinkHrefGuardian(...deps) {
48
48
  }
49
49
 
50
50
  // src/ui/SchedulingWidget.tsx
51
- import { useEffect, useId, useMemo, useRef, useState as useState2 } from "react";
51
+ import { useCallback, useEffect, useId, useMemo, useRef, useState as useState2 } from "react";
52
52
 
53
53
  // src/ui/EmailCaptureModal.tsx
54
54
  import { useState } from "react";
55
55
  import { Dialog } from "radix-ui";
56
56
  import { jsx, jsxs } from "react/jsx-runtime";
57
+ var isValidEmail = (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
57
58
  function Spinner() {
58
59
  return /* @__PURE__ */ jsxs(
59
60
  "svg",
@@ -87,12 +88,17 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
87
88
  const [error, setError] = useState(null);
88
89
  const isBook = title === "Confirm your spot";
89
90
  const handleSubmit = async () => {
90
- if (!email.trim()) return;
91
+ const trimmed = email.trim();
92
+ if (!trimmed) return;
93
+ if (!isValidEmail(trimmed)) {
94
+ setError("Please enter a valid email address.");
95
+ return;
96
+ }
91
97
  setLoading(true);
92
98
  setError(null);
93
99
  try {
94
- await onSubmit(email.trim());
95
- setSubmittedEmail(email.trim());
100
+ await onSubmit(trimmed);
101
+ setSubmittedEmail(trimmed);
96
102
  setSuccess(true);
97
103
  } catch (e) {
98
104
  setError(e instanceof Error ? e.message : "Something went wrong. Please try again.");
@@ -167,7 +173,10 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
167
173
  {
168
174
  type: "email",
169
175
  value: email,
170
- onChange: (e) => setEmail(e.target.value),
176
+ onChange: (e) => {
177
+ setEmail(e.target.value);
178
+ if (error) setError(null);
179
+ },
171
180
  onKeyDown: handleKeyDown,
172
181
  placeholder: "hello@gmail.com",
173
182
  autoFocus: true,
@@ -224,12 +233,20 @@ function formatClassTime(cls) {
224
233
  const em = endTotal % 60;
225
234
  return `${h}:${cls.startTime.minutes}-${eh}:${String(em).padStart(2, "0")}`;
226
235
  }
236
+ function formatBookingLabel(cls) {
237
+ const price = cls.price;
238
+ const isFree = price === null || price === void 0 || `${price}` === "" || `${price}` === "0";
239
+ return isFree ? "Book for free" : `Book for ${cls.currency ?? ""} ${price}`.trim();
240
+ }
227
241
  function getBookingsOnDate(cls, date) {
228
242
  if (!cls.bookings?.length) return 0;
229
- const ds = date.toISOString().split("T")[0];
243
+ const target = new Date(date);
244
+ target.setHours(0, 0, 0, 0);
230
245
  return cls.bookings.filter((b) => {
231
246
  try {
232
- return new Date(b.classDate).toISOString().split("T")[0] === ds;
247
+ const bookingDate = new Date(b.classDate);
248
+ bookingDate.setHours(0, 0, 0, 0);
249
+ return bookingDate.getTime() === target.getTime();
233
250
  } catch {
234
251
  return false;
235
252
  }
@@ -494,7 +511,7 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
494
511
  }
495
512
  )
496
513
  ] }),
497
- /* @__PURE__ */ jsx2("div", { className: "sm:hidden flex flex-col gap-px", children: isFull ? /* @__PURE__ */ jsx2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
514
+ cls.showAvailability !== false && /* @__PURE__ */ jsx2("div", { className: "sm:hidden flex flex-col gap-px", children: isFull ? /* @__PURE__ */ jsx2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
498
515
  /* @__PURE__ */ jsxs2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: [
499
516
  available,
500
517
  "/",
@@ -506,9 +523,17 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
506
523
  /* @__PURE__ */ jsxs2("div", { className: "flex flex-1 flex-col gap-2 min-w-0 sm:contents", children: [
507
524
  /* @__PURE__ */ jsxs2("div", { className: "flex-1 flex flex-col gap-2 min-w-0", children: [
508
525
  /* @__PURE__ */ jsx2("span", { className: "font-body text-base font-bold text-(--color-dark,#200C02) block truncate", children: cls.name }),
509
- cls.hostName && /* @__PURE__ */ jsx2("span", { className: "font-body text-base font-normal text-(--color-dark,#200C02) opacity-80 block truncate", children: cls.hostName })
526
+ cls.hostName && /* @__PURE__ */ jsx2("span", { className: "font-body text-base font-normal text-(--color-dark,#200C02) opacity-80 block truncate", children: cls.hostName }),
527
+ cls.description && /* @__PURE__ */ jsx2(
528
+ "span",
529
+ {
530
+ className: "font-body text-base font-normal text-(--color-dark,#200C02) opacity-80 block",
531
+ style: { wordBreak: "break-word" },
532
+ children: cls.description
533
+ }
534
+ )
510
535
  ] }),
511
- /* @__PURE__ */ jsx2("div", { className: "hidden sm:flex w-14 shrink-0 flex-col gap-px", children: isFull ? /* @__PURE__ */ jsx2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
536
+ cls.showAvailability !== false && /* @__PURE__ */ jsx2("div", { className: "hidden sm:flex w-14 shrink-0 flex-col gap-px", children: isFull ? /* @__PURE__ */ jsx2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
512
537
  /* @__PURE__ */ jsxs2("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: [
513
538
  available,
514
539
  "/",
@@ -533,7 +558,7 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
533
558
  if (!cls.id) return;
534
559
  onOpenModal?.(isFull ? "waitlist" : "book", cls.id, selectedDate);
535
560
  },
536
- children: isFull ? "Join Waitlist" : "Book Now"
561
+ children: isFull ? "Join Waitlist" : formatBookingLabel(cls)
537
562
  }
538
563
  )
539
564
  ] })
@@ -575,6 +600,17 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
575
600
  const [isHovered, setIsHovered] = useState2(false);
576
601
  const [modalState, setModalState] = useState2(null);
577
602
  const switchScheduleIdRef = useRef(null);
603
+ const liveScheduleIdRef = useRef(null);
604
+ const refetchLiveSchedule = useCallback(async () => {
605
+ const id = liveScheduleIdRef.current;
606
+ if (!id) return;
607
+ try {
608
+ const res = await fetch(`${API_URL}/api/schedule/id/${id}`);
609
+ const data = await res.json();
610
+ if (data?.id) setSchedule(data);
611
+ } catch {
612
+ }
613
+ }, []);
578
614
  const dates = useMemo(() => {
579
615
  const today = /* @__PURE__ */ new Date();
580
616
  today.setHours(0, 0, 0, 0);
@@ -594,6 +630,18 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
594
630
  }
595
631
  }
596
632
  }, [schedule, dates]);
633
+ useEffect(() => {
634
+ if (typeof window === "undefined") return;
635
+ const onVisible = () => {
636
+ if (!document.hidden) void refetchLiveSchedule();
637
+ };
638
+ window.addEventListener("focus", refetchLiveSchedule);
639
+ document.addEventListener("visibilitychange", onVisible);
640
+ return () => {
641
+ window.removeEventListener("focus", refetchLiveSchedule);
642
+ document.removeEventListener("visibilitychange", onVisible);
643
+ };
644
+ }, [refetchLiveSchedule]);
597
645
  useEffect(() => {
598
646
  if (typeof window === "undefined") return;
599
647
  const isInEditor = window.self !== window.top;
@@ -655,7 +703,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
655
703
  setLoading(false);
656
704
  return;
657
705
  }
658
- ;
706
+ liveScheduleIdRef.current = effectiveId;
659
707
  (async () => {
660
708
  try {
661
709
  const res = await fetch(`${API_URL}/api/schedule/id/${effectiveId}`);
@@ -712,18 +760,14 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
712
760
  const data = await res.json().catch(() => ({}));
713
761
  throw new Error(data?.message ?? "Something went wrong. Please try again.");
714
762
  }
763
+ await refetchLiveSchedule();
715
764
  };
716
765
  const handleReplaceSchedule = () => {
717
766
  setIsHovered(false);
718
- if (schedule) {
719
- window.parent.postMessage({
720
- type: "ow:schedule-connected",
721
- schedule: { id: schedule.id, name: schedule.name },
722
- insertAfter
723
- }, "*");
724
- } else {
725
- window.parent.postMessage({ type: "ow:scheduling-not-connected", insertAfter }, "*");
726
- }
767
+ window.parent.postMessage(
768
+ { type: "ow:scheduling-not-connected", insertAfter, currentScheduleId: schedule?.id },
769
+ "*"
770
+ );
727
771
  };
728
772
  if (!inEditor && !loading && !schedule) return null;
729
773
  const sectionId = `scheduling-${insertAfter}`;
@@ -766,7 +810,19 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
766
810
  ),
767
811
  /* @__PURE__ */ jsxs2("div", { className: "max-w-[1280px] mx-auto flex flex-col items-center gap-16", children: [
768
812
  /* @__PURE__ */ jsxs2("div", { className: "flex flex-col items-center gap-4", children: [
769
- /* @__PURE__ */ jsx2("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" }),
813
+ /* @__PURE__ */ jsx2(
814
+ "h2",
815
+ {
816
+ className: "font-display text-center m-0 text-(--color-dark,#200C02)",
817
+ style: {
818
+ fontSize: "var(--fs-section-h2, clamp(40px, 4.4vw, 64px))",
819
+ fontWeight: "var(--font-weight-heading, 400)",
820
+ lineHeight: 1.05,
821
+ letterSpacing: "-0.02em"
822
+ },
823
+ children: schedule?.name ?? "Book an appointment"
824
+ }
825
+ ),
770
826
  schedule?.description && /* @__PURE__ */ jsx2("p", { className: "font-body text-body text-center m-0 text-(--color-accent,#A89B83)", children: schedule.description })
771
827
  ] }),
772
828
  /* @__PURE__ */ jsxs2("div", { className: "w-full flex flex-col items-end gap-3", children: [
@@ -4826,7 +4882,11 @@ function MediaOverlay({
4826
4882
  variant: "outline",
4827
4883
  size: "sm",
4828
4884
  className: "gap-1.5 cursor-pointer hover:bg-background",
4829
- style: OVERLAY_BUTTON_STYLE,
4885
+ style: {
4886
+ ...OVERLAY_BUTTON_STYLE,
4887
+ // Don't let Replace steal clicks when text (e.g. nav) sits on top of this media.
4888
+ pointerEvents: hover.hasTextOverlap ? "none" : "auto"
4889
+ },
4830
4890
  onMouseDown: (e) => e.preventDefault(),
4831
4891
  onClick: (e) => {
4832
4892
  e.stopPropagation();
@@ -4843,6 +4903,61 @@ function MediaOverlay({
4843
4903
  ] });
4844
4904
  }
4845
4905
 
4906
+ // src/ui/CarouselOverlay.tsx
4907
+ import { GalleryHorizontal } from "lucide-react";
4908
+ import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
4909
+ var OVERLAY_BUTTON_STYLE2 = {
4910
+ pointerEvents: "auto",
4911
+ fontFamily: "Inter, sans-serif",
4912
+ fontSize: 12,
4913
+ color: "#000"
4914
+ };
4915
+ function CarouselOverlay({
4916
+ hover,
4917
+ onEdit
4918
+ }) {
4919
+ const { rect } = hover;
4920
+ return /* @__PURE__ */ jsx12(
4921
+ "div",
4922
+ {
4923
+ "data-ohw-bridge": "",
4924
+ "data-ohw-carousel-overlay": "",
4925
+ className: "flex cursor-pointer items-center justify-center",
4926
+ style: {
4927
+ position: "fixed",
4928
+ top: rect.top,
4929
+ left: rect.left,
4930
+ width: rect.width,
4931
+ height: rect.height,
4932
+ zIndex: 2147483646,
4933
+ pointerEvents: "auto",
4934
+ boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
4935
+ background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
4936
+ },
4937
+ onClick: () => onEdit(hover.key),
4938
+ children: /* @__PURE__ */ jsxs6(
4939
+ Button,
4940
+ {
4941
+ "data-ohw-carousel-overlay": "",
4942
+ variant: "outline",
4943
+ size: "sm",
4944
+ className: "cursor-pointer gap-1.5 hover:bg-background",
4945
+ style: OVERLAY_BUTTON_STYLE2,
4946
+ onMouseDown: (e) => e.preventDefault(),
4947
+ onClick: (e) => {
4948
+ e.stopPropagation();
4949
+ onEdit(hover.key);
4950
+ },
4951
+ children: [
4952
+ /* @__PURE__ */ jsx12(GalleryHorizontal, { size: 14 }),
4953
+ "Edit gallery"
4954
+ ]
4955
+ }
4956
+ )
4957
+ }
4958
+ );
4959
+ }
4960
+
4846
4961
  // src/OhhwellsBridge.tsx
4847
4962
  import { createPortal as createPortal2 } from "react-dom";
4848
4963
  import { usePathname as usePathname2, useRouter as useRouter2, useSearchParams } from "next/navigation";
@@ -5129,22 +5244,22 @@ import { useEffect as useEffect6 } from "react";
5129
5244
  import * as React8 from "react";
5130
5245
  import { Dialog as DialogPrimitive } from "radix-ui";
5131
5246
  import { X } from "lucide-react";
5132
- import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
5247
+ import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
5133
5248
  function Dialog2({
5134
5249
  ...props
5135
5250
  }) {
5136
- return /* @__PURE__ */ jsx12(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
5251
+ return /* @__PURE__ */ jsx13(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
5137
5252
  }
5138
5253
  function DialogPortal({
5139
5254
  ...props
5140
5255
  }) {
5141
- return /* @__PURE__ */ jsx12(DialogPrimitive.Portal, { ...props });
5256
+ return /* @__PURE__ */ jsx13(DialogPrimitive.Portal, { ...props });
5142
5257
  }
5143
5258
  function DialogOverlay({
5144
5259
  className,
5145
5260
  ...props
5146
5261
  }) {
5147
- return /* @__PURE__ */ jsx12(
5262
+ return /* @__PURE__ */ jsx13(
5148
5263
  DialogPrimitive.Overlay,
5149
5264
  {
5150
5265
  "data-slot": "dialog-overlay",
@@ -5157,9 +5272,9 @@ function DialogOverlay({
5157
5272
  var DialogContent = React8.forwardRef(
5158
5273
  ({ className, children, showCloseButton = true, container, ...props }, ref) => {
5159
5274
  const positionMode = container ? "absolute" : "fixed";
5160
- return /* @__PURE__ */ jsxs6(DialogPortal, { container: container ?? void 0, children: [
5161
- /* @__PURE__ */ jsx12(DialogOverlay, { className: cn(positionMode, "inset-0") }),
5162
- /* @__PURE__ */ jsxs6(
5275
+ return /* @__PURE__ */ jsxs7(DialogPortal, { container: container ?? void 0, children: [
5276
+ /* @__PURE__ */ jsx13(DialogOverlay, { className: cn(positionMode, "inset-0") }),
5277
+ /* @__PURE__ */ jsxs7(
5163
5278
  DialogPrimitive.Content,
5164
5279
  {
5165
5280
  ref,
@@ -5175,13 +5290,13 @@ var DialogContent = React8.forwardRef(
5175
5290
  ...props,
5176
5291
  children: [
5177
5292
  children,
5178
- showCloseButton ? /* @__PURE__ */ jsx12(
5293
+ showCloseButton ? /* @__PURE__ */ jsx13(
5179
5294
  DialogPrimitive.Close,
5180
5295
  {
5181
5296
  type: "button",
5182
5297
  className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
5183
5298
  "aria-label": "Close",
5184
- children: /* @__PURE__ */ jsx12(X, { size: 16, "aria-hidden": true })
5299
+ children: /* @__PURE__ */ jsx13(X, { size: 16, "aria-hidden": true })
5185
5300
  }
5186
5301
  ) : null
5187
5302
  ]
@@ -5195,13 +5310,13 @@ function DialogHeader({
5195
5310
  className,
5196
5311
  ...props
5197
5312
  }) {
5198
- return /* @__PURE__ */ jsx12("div", { className: cn("flex flex-col gap-1.5", className), ...props });
5313
+ return /* @__PURE__ */ jsx13("div", { className: cn("flex flex-col gap-1.5", className), ...props });
5199
5314
  }
5200
5315
  function DialogFooter({
5201
5316
  className,
5202
5317
  ...props
5203
5318
  }) {
5204
- return /* @__PURE__ */ jsx12(
5319
+ return /* @__PURE__ */ jsx13(
5205
5320
  "div",
5206
5321
  {
5207
5322
  className: cn("flex items-center justify-end gap-2", className),
@@ -5209,7 +5324,7 @@ function DialogFooter({
5209
5324
  }
5210
5325
  );
5211
5326
  }
5212
- var DialogTitle = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx12(
5327
+ var DialogTitle = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx13(
5213
5328
  DialogPrimitive.Title,
5214
5329
  {
5215
5330
  ref,
@@ -5221,7 +5336,7 @@ var DialogTitle = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE
5221
5336
  }
5222
5337
  ));
5223
5338
  DialogTitle.displayName = DialogPrimitive.Title.displayName;
5224
- var DialogDescription = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx12(
5339
+ var DialogDescription = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx13(
5225
5340
  DialogPrimitive.Description,
5226
5341
  {
5227
5342
  ref,
@@ -5237,19 +5352,19 @@ import { Info, X as X3 } from "lucide-react";
5237
5352
 
5238
5353
  // src/ui/link-modal/DestinationBreadcrumb.tsx
5239
5354
  import { ArrowRight, File, GalleryVertical } from "lucide-react";
5240
- import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
5355
+ import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
5241
5356
  function DestinationBreadcrumb({
5242
5357
  pageTitle,
5243
5358
  sectionLabel
5244
5359
  }) {
5245
- return /* @__PURE__ */ jsxs7("div", { className: "flex w-full flex-col gap-2", children: [
5246
- /* @__PURE__ */ jsx13("p", { className: "text-sm font-medium! text-foreground m-0", children: "Destination" }),
5247
- /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-3", children: [
5248
- /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2", children: [
5249
- /* @__PURE__ */ jsx13(File, { size: 16, className: "shrink-0 text-foreground", "aria-hidden": true }),
5250
- /* @__PURE__ */ jsx13("span", { className: "text-sm font-medium leading-none text-foreground!", children: pageTitle })
5360
+ return /* @__PURE__ */ jsxs8("div", { className: "flex w-full flex-col gap-2", children: [
5361
+ /* @__PURE__ */ jsx14("p", { className: "text-sm font-medium! text-foreground m-0", children: "Destination" }),
5362
+ /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-3", children: [
5363
+ /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
5364
+ /* @__PURE__ */ jsx14(File, { size: 16, className: "shrink-0 text-foreground", "aria-hidden": true }),
5365
+ /* @__PURE__ */ jsx14("span", { className: "text-sm font-medium leading-none text-foreground!", children: pageTitle })
5251
5366
  ] }),
5252
- /* @__PURE__ */ jsx13(
5367
+ /* @__PURE__ */ jsx14(
5253
5368
  ArrowRight,
5254
5369
  {
5255
5370
  size: 16,
@@ -5257,8 +5372,8 @@ function DestinationBreadcrumb({
5257
5372
  "aria-hidden": true
5258
5373
  }
5259
5374
  ),
5260
- /* @__PURE__ */ jsxs7("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
5261
- /* @__PURE__ */ jsx13(
5375
+ /* @__PURE__ */ jsxs8("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
5376
+ /* @__PURE__ */ jsx14(
5262
5377
  GalleryVertical,
5263
5378
  {
5264
5379
  size: 16,
@@ -5266,7 +5381,7 @@ function DestinationBreadcrumb({
5266
5381
  "aria-hidden": true
5267
5382
  }
5268
5383
  ),
5269
- /* @__PURE__ */ jsx13("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
5384
+ /* @__PURE__ */ jsx14("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
5270
5385
  ] })
5271
5386
  ] })
5272
5387
  ] });
@@ -5274,22 +5389,22 @@ function DestinationBreadcrumb({
5274
5389
 
5275
5390
  // src/ui/link-modal/SectionTreeItem.tsx
5276
5391
  import { GalleryVertical as GalleryVertical2 } from "lucide-react";
5277
- import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
5392
+ import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
5278
5393
  function SectionTreeItem({
5279
5394
  section,
5280
5395
  onSelect,
5281
5396
  selected
5282
5397
  }) {
5283
5398
  const interactive = Boolean(onSelect);
5284
- return /* @__PURE__ */ jsxs8("div", { className: "flex h-9 w-full items-end pl-3", children: [
5285
- /* @__PURE__ */ jsx14(
5399
+ return /* @__PURE__ */ jsxs9("div", { className: "flex h-9 w-full items-end pl-3", children: [
5400
+ /* @__PURE__ */ jsx15(
5286
5401
  "div",
5287
5402
  {
5288
5403
  className: "mr-[-1px] h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
5289
5404
  "aria-hidden": true
5290
5405
  }
5291
5406
  ),
5292
- /* @__PURE__ */ jsxs8(
5407
+ /* @__PURE__ */ jsxs9(
5293
5408
  "div",
5294
5409
  {
5295
5410
  role: interactive ? "button" : void 0,
@@ -5307,7 +5422,7 @@ function SectionTreeItem({
5307
5422
  interactive && selected && "border-primary"
5308
5423
  ),
5309
5424
  children: [
5310
- /* @__PURE__ */ jsx14(
5425
+ /* @__PURE__ */ jsx15(
5311
5426
  GalleryVertical2,
5312
5427
  {
5313
5428
  size: 16,
@@ -5315,7 +5430,7 @@ function SectionTreeItem({
5315
5430
  "aria-hidden": true
5316
5431
  }
5317
5432
  ),
5318
- /* @__PURE__ */ jsx14("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
5433
+ /* @__PURE__ */ jsx15("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
5319
5434
  ]
5320
5435
  }
5321
5436
  )
@@ -5327,10 +5442,10 @@ import { useEffect as useEffect3, useId as useId2, useRef as useRef4, useState a
5327
5442
 
5328
5443
  // src/ui/input.tsx
5329
5444
  import * as React9 from "react";
5330
- import { jsx as jsx15 } from "react/jsx-runtime";
5445
+ import { jsx as jsx16 } from "react/jsx-runtime";
5331
5446
  var Input = React9.forwardRef(
5332
5447
  ({ className, type, ...props }, ref) => {
5333
- return /* @__PURE__ */ jsx15(
5448
+ return /* @__PURE__ */ jsx16(
5334
5449
  "input",
5335
5450
  {
5336
5451
  type,
@@ -5349,9 +5464,9 @@ Input.displayName = "Input";
5349
5464
 
5350
5465
  // src/ui/label.tsx
5351
5466
  import { Label as LabelPrimitive } from "radix-ui";
5352
- import { jsx as jsx16 } from "react/jsx-runtime";
5467
+ import { jsx as jsx17 } from "react/jsx-runtime";
5353
5468
  function Label({ className, ...props }) {
5354
- return /* @__PURE__ */ jsx16(
5469
+ return /* @__PURE__ */ jsx17(
5355
5470
  LabelPrimitive.Root,
5356
5471
  {
5357
5472
  "data-slot": "label",
@@ -5363,11 +5478,11 @@ function Label({ className, ...props }) {
5363
5478
 
5364
5479
  // src/ui/link-modal/UrlOrPageInput.tsx
5365
5480
  import { ChevronDown, File as File2, X as X2 } from "lucide-react";
5366
- import { jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
5481
+ import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
5367
5482
  function FieldChevron({
5368
5483
  onClick
5369
5484
  }) {
5370
- return /* @__PURE__ */ jsx17(
5485
+ return /* @__PURE__ */ jsx18(
5371
5486
  "button",
5372
5487
  {
5373
5488
  type: "button",
@@ -5375,7 +5490,7 @@ function FieldChevron({
5375
5490
  onClick,
5376
5491
  "aria-label": "Open page list",
5377
5492
  tabIndex: -1,
5378
- children: /* @__PURE__ */ jsx17(ChevronDown, { size: 16 })
5493
+ children: /* @__PURE__ */ jsx18(ChevronDown, { size: 16 })
5379
5494
  }
5380
5495
  );
5381
5496
  }
@@ -5436,11 +5551,11 @@ function UrlOrPageInput({
5436
5551
  "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]",
5437
5552
  urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
5438
5553
  );
5439
- return /* @__PURE__ */ jsxs9("div", { className: "flex w-full flex-col gap-2 p-0", children: [
5440
- /* @__PURE__ */ jsx17(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
5441
- /* @__PURE__ */ jsxs9("div", { ref: rootRef, className: "relative w-full", children: [
5442
- /* @__PURE__ */ jsxs9("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
5443
- selectedPage ? /* @__PURE__ */ jsx17("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ jsx17(
5554
+ return /* @__PURE__ */ jsxs10("div", { className: "flex w-full flex-col gap-2 p-0", children: [
5555
+ /* @__PURE__ */ jsx18(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
5556
+ /* @__PURE__ */ jsxs10("div", { ref: rootRef, className: "relative w-full", children: [
5557
+ /* @__PURE__ */ jsxs10("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
5558
+ selectedPage ? /* @__PURE__ */ jsx18("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ jsx18(
5444
5559
  File2,
5445
5560
  {
5446
5561
  size: 16,
@@ -5448,7 +5563,7 @@ function UrlOrPageInput({
5448
5563
  "aria-hidden": true
5449
5564
  }
5450
5565
  ) }) : null,
5451
- readOnly ? /* @__PURE__ */ jsx17("span", { className: "min-w-0 flex-1 truncate text-sm leading-5 text-foreground", children: selectedPage?.title ?? value }) : /* @__PURE__ */ jsx17(
5566
+ readOnly ? /* @__PURE__ */ jsx18("span", { className: "min-w-0 flex-1 truncate text-sm leading-5 text-foreground", children: selectedPage?.title ?? value }) : /* @__PURE__ */ jsx18(
5452
5567
  Input,
5453
5568
  {
5454
5569
  ref: inputRef,
@@ -5474,7 +5589,7 @@ function UrlOrPageInput({
5474
5589
  )
5475
5590
  }
5476
5591
  ),
5477
- selectedPage && !readOnly ? /* @__PURE__ */ jsx17(
5592
+ selectedPage && !readOnly ? /* @__PURE__ */ jsx18(
5478
5593
  "button",
5479
5594
  {
5480
5595
  type: "button",
@@ -5482,26 +5597,26 @@ function UrlOrPageInput({
5482
5597
  onMouseDown: clearSelection,
5483
5598
  "aria-label": "Clear selected page",
5484
5599
  tabIndex: -1,
5485
- children: /* @__PURE__ */ jsx17(X2, { size: 16, "aria-hidden": true })
5600
+ children: /* @__PURE__ */ jsx18(X2, { size: 16, "aria-hidden": true })
5486
5601
  }
5487
5602
  ) : null,
5488
- !readOnly ? /* @__PURE__ */ jsx17(FieldChevron, { onClick: toggleDropdown }) : null
5603
+ !readOnly ? /* @__PURE__ */ jsx18(FieldChevron, { onClick: toggleDropdown }) : null
5489
5604
  ] }),
5490
- dropdownOpen && !readOnly && filteredPages.length > 0 ? /* @__PURE__ */ jsx17(
5605
+ dropdownOpen && !readOnly && filteredPages.length > 0 ? /* @__PURE__ */ jsx18(
5491
5606
  "div",
5492
5607
  {
5493
5608
  "data-ohw-link-page-dropdown": "",
5494
5609
  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",
5495
5610
  onMouseDown: (e) => e.preventDefault(),
5496
- children: filteredPages.map((page) => /* @__PURE__ */ jsxs9(
5611
+ children: filteredPages.map((page) => /* @__PURE__ */ jsxs10(
5497
5612
  "button",
5498
5613
  {
5499
5614
  type: "button",
5500
5615
  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",
5501
5616
  onClick: () => onPageSelect(page),
5502
5617
  children: [
5503
- /* @__PURE__ */ jsx17(File2, { size: 16, className: "shrink-0", "aria-hidden": true }),
5504
- /* @__PURE__ */ jsx17("span", { className: "truncate", children: page.title })
5618
+ /* @__PURE__ */ jsx18(File2, { size: 16, className: "shrink-0", "aria-hidden": true }),
5619
+ /* @__PURE__ */ jsx18("span", { className: "truncate", children: page.title })
5505
5620
  ]
5506
5621
  },
5507
5622
  page.path
@@ -5509,34 +5624,34 @@ function UrlOrPageInput({
5509
5624
  }
5510
5625
  ) : null
5511
5626
  ] }),
5512
- urlError ? /* @__PURE__ */ jsx17("p", { className: "text-sm font-medium text-destructive", children: urlError }) : null
5627
+ urlError ? /* @__PURE__ */ jsx18("p", { className: "text-sm font-medium text-destructive", children: urlError }) : null
5513
5628
  ] });
5514
5629
  }
5515
5630
 
5516
5631
  // src/ui/link-modal/LinkEditorPanel.tsx
5517
- import { Fragment as Fragment3, jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
5632
+ import { Fragment as Fragment3, jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
5518
5633
  function LinkEditorPanel({ state, onClose }) {
5519
5634
  const isCancel = state.secondaryLabel === "Cancel" || state.secondaryLabel === "Back to sections";
5520
- return /* @__PURE__ */ jsxs10(Fragment3, { children: [
5521
- /* @__PURE__ */ jsx18(DialogClose, { asChild: true, children: /* @__PURE__ */ jsx18(
5635
+ return /* @__PURE__ */ jsxs11(Fragment3, { children: [
5636
+ /* @__PURE__ */ jsx19(DialogClose, { asChild: true, children: /* @__PURE__ */ jsx19(
5522
5637
  "button",
5523
5638
  {
5524
5639
  type: "button",
5525
5640
  className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50 h-7",
5526
5641
  "aria-label": "Close",
5527
5642
  onClick: onClose,
5528
- children: /* @__PURE__ */ jsx18(X3, { size: 16, "aria-hidden": true })
5643
+ children: /* @__PURE__ */ jsx19(X3, { size: 16, "aria-hidden": true })
5529
5644
  }
5530
5645
  ) }),
5531
- /* @__PURE__ */ jsx18(DialogHeader, { className: "w-full gap-1.5 p-6 pr-12", children: /* @__PURE__ */ jsx18(DialogTitle, { className: "m-0 w-full break-words", children: state.title }) }),
5532
- /* @__PURE__ */ jsxs10("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
5533
- state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ jsx18(
5646
+ /* @__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 }) }),
5647
+ /* @__PURE__ */ jsxs11("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
5648
+ state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ jsx19(
5534
5649
  DestinationBreadcrumb,
5535
5650
  {
5536
5651
  pageTitle: state.selectedPage.title,
5537
5652
  sectionLabel: state.selectedSection.label
5538
5653
  }
5539
- ) : /* @__PURE__ */ jsx18(
5654
+ ) : /* @__PURE__ */ jsx19(
5540
5655
  UrlOrPageInput,
5541
5656
  {
5542
5657
  value: state.searchValue,
@@ -5549,8 +5664,8 @@ function LinkEditorPanel({ state, onClose }) {
5549
5664
  urlError: state.urlError
5550
5665
  }
5551
5666
  ),
5552
- state.showChooseSection ? /* @__PURE__ */ jsxs10("div", { className: "flex flex-col justify-center gap-2", children: [
5553
- /* @__PURE__ */ jsx18(
5667
+ state.showChooseSection ? /* @__PURE__ */ jsxs11("div", { className: "flex flex-col justify-center gap-2", children: [
5668
+ /* @__PURE__ */ jsx19(
5554
5669
  Button,
5555
5670
  {
5556
5671
  type: "button",
@@ -5561,15 +5676,15 @@ function LinkEditorPanel({ state, onClose }) {
5561
5676
  children: "Choose a section"
5562
5677
  }
5563
5678
  ),
5564
- /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
5565
- /* @__PURE__ */ jsx18(Info, { size: 16, className: "shrink-0", "aria-hidden": true }),
5566
- /* @__PURE__ */ jsx18("span", { children: "Pick a section this link should scroll to." })
5679
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
5680
+ /* @__PURE__ */ jsx19(Info, { size: 16, className: "shrink-0", "aria-hidden": true }),
5681
+ /* @__PURE__ */ jsx19("span", { children: "Pick a section this link should scroll to." })
5567
5682
  ] })
5568
5683
  ] }) : null,
5569
- state.showSectionRow && state.selectedSection ? /* @__PURE__ */ jsx18(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
5684
+ state.showSectionRow && state.selectedSection ? /* @__PURE__ */ jsx19(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
5570
5685
  ] }),
5571
- /* @__PURE__ */ jsxs10(DialogFooter, { className: "w-full px-6 pb-6", children: [
5572
- /* @__PURE__ */ jsx18(
5686
+ /* @__PURE__ */ jsxs11(DialogFooter, { className: "w-full px-6 pb-6", children: [
5687
+ /* @__PURE__ */ jsx19(
5573
5688
  Button,
5574
5689
  {
5575
5690
  type: "button",
@@ -5584,7 +5699,7 @@ function LinkEditorPanel({ state, onClose }) {
5584
5699
  children: state.secondaryLabel
5585
5700
  }
5586
5701
  ),
5587
- /* @__PURE__ */ jsx18(
5702
+ /* @__PURE__ */ jsx19(
5588
5703
  Button,
5589
5704
  {
5590
5705
  type: "button",
@@ -5603,11 +5718,11 @@ function LinkEditorPanel({ state, onClose }) {
5603
5718
  }
5604
5719
 
5605
5720
  // src/ui/link-modal/SectionPickerOverlay.tsx
5606
- import { useCallback, useEffect as useEffect4, useMemo as useMemo2, useRef as useRef5, useState as useState4 } from "react";
5721
+ import { useCallback as useCallback2, useEffect as useEffect4, useMemo as useMemo2, useRef as useRef5, useState as useState4 } from "react";
5607
5722
  import { createPortal } from "react-dom";
5608
5723
  import { ArrowLeft, Check } from "lucide-react";
5609
5724
  import { usePathname, useRouter } from "next/navigation";
5610
- import { jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
5725
+ import { jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
5611
5726
  var DIM_OVERLAY = "rgba(0, 0, 0, 0.45)";
5612
5727
  function rectsEqual(a, b) {
5613
5728
  if (a.size !== b.size) return false;
@@ -5734,7 +5849,7 @@ function SectionPickerOverlay({
5734
5849
  );
5735
5850
  sectionIdsRef.current = sectionIds;
5736
5851
  const rects = useSectionRects(sectionIdsKey, isOnTargetPage);
5737
- const applyHoverAt = useCallback(
5852
+ const applyHoverAt = useCallback2(
5738
5853
  (x, y, liveRects) => {
5739
5854
  const ids = sectionIdsRef.current;
5740
5855
  const map = liveRects ?? readSectionRects(ids);
@@ -5814,7 +5929,7 @@ function SectionPickerOverlay({
5814
5929
  window.removeEventListener("message", onPointerSync);
5815
5930
  };
5816
5931
  }, [rects, applyHoverAt]);
5817
- const handleSelect = useCallback(
5932
+ const handleSelect = useCallback2(
5818
5933
  (section) => {
5819
5934
  if (selectedId) return;
5820
5935
  setSelectedId(section.id);
@@ -5836,7 +5951,7 @@ function SectionPickerOverlay({
5836
5951
  const portalRoot = typeof document !== "undefined" ? document.querySelector("[data-ohw-bridge-root]") ?? document.body : null;
5837
5952
  if (!portalRoot) return null;
5838
5953
  return createPortal(
5839
- /* @__PURE__ */ jsxs11(
5954
+ /* @__PURE__ */ jsxs12(
5840
5955
  "div",
5841
5956
  {
5842
5957
  "data-ohw-section-picker": "",
@@ -5846,12 +5961,12 @@ function SectionPickerOverlay({
5846
5961
  role: "dialog",
5847
5962
  "aria-label": "Choose a section",
5848
5963
  children: [
5849
- /* @__PURE__ */ jsx19(
5964
+ /* @__PURE__ */ jsx20(
5850
5965
  "div",
5851
5966
  {
5852
5967
  className: "pointer-events-auto fixed left-5 z-[2]",
5853
5968
  style: { top: chromeClip.top + 20 },
5854
- children: /* @__PURE__ */ jsxs11(
5969
+ children: /* @__PURE__ */ jsxs12(
5855
5970
  Button,
5856
5971
  {
5857
5972
  type: "button",
@@ -5860,14 +5975,14 @@ function SectionPickerOverlay({
5860
5975
  className: "h-8 min-w-0 gap-1 border-border bg-background px-2 py-1.5 shadow-sm hover:bg-muted cursor-pointer",
5861
5976
  onClick: onBack,
5862
5977
  children: [
5863
- /* @__PURE__ */ jsx19(ArrowLeft, { className: "size-4 shrink-0", "aria-hidden": true }),
5978
+ /* @__PURE__ */ jsx20(ArrowLeft, { className: "size-4 shrink-0", "aria-hidden": true }),
5864
5979
  "Back"
5865
5980
  ]
5866
5981
  }
5867
5982
  )
5868
5983
  }
5869
5984
  ),
5870
- /* @__PURE__ */ jsx19(
5985
+ /* @__PURE__ */ jsx20(
5871
5986
  "div",
5872
5987
  {
5873
5988
  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",
@@ -5880,7 +5995,7 @@ function SectionPickerOverlay({
5880
5995
  children: "Click on section to select"
5881
5996
  }
5882
5997
  ),
5883
- !isOnTargetPage ? /* @__PURE__ */ jsx19(
5998
+ !isOnTargetPage ? /* @__PURE__ */ jsx20(
5884
5999
  "div",
5885
6000
  {
5886
6001
  className: "pointer-events-none fixed left-1/2 z-[1] -translate-x-1/2 rounded-md px-3 py-2 text-sm text-muted-foreground shadow-sm",
@@ -5888,14 +6003,14 @@ function SectionPickerOverlay({
5888
6003
  children: "Loading page preview\u2026"
5889
6004
  }
5890
6005
  ) : null,
5891
- isOnTargetPage && liveSections.length === 0 ? /* @__PURE__ */ jsx19("div", { className: "pointer-events-auto fixed inset-0 z-[1] flex items-center justify-center bg-muted/40", children: /* @__PURE__ */ jsx19("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." }) }) : null,
6006
+ 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,
5892
6007
  isOnTargetPage ? liveSections.map((section) => {
5893
6008
  const rect = rects.get(section.id);
5894
6009
  if (!rect || rect.width <= 0 || rect.height <= 0) return null;
5895
6010
  const isSelected = selectedId === section.id;
5896
6011
  const isHovered = hoveredId === section.id;
5897
6012
  const isLit = isSelected || isHovered;
5898
- return /* @__PURE__ */ jsxs11(
6013
+ return /* @__PURE__ */ jsxs12(
5899
6014
  "button",
5900
6015
  {
5901
6016
  type: "button",
@@ -5910,7 +6025,7 @@ function SectionPickerOverlay({
5910
6025
  "aria-label": `Select section ${section.label}`,
5911
6026
  onClick: () => handleSelect(section),
5912
6027
  children: [
5913
- isLit ? /* @__PURE__ */ jsx19(
6028
+ isLit ? /* @__PURE__ */ jsx20(
5914
6029
  "span",
5915
6030
  {
5916
6031
  className: "pointer-events-none absolute",
@@ -5923,13 +6038,13 @@ function SectionPickerOverlay({
5923
6038
  "aria-hidden": true
5924
6039
  }
5925
6040
  ) : null,
5926
- isSelected ? /* @__PURE__ */ jsx19(
6041
+ isSelected ? /* @__PURE__ */ jsx20(
5927
6042
  "span",
5928
6043
  {
5929
6044
  className: "absolute right-3 top-3 flex size-8 items-center justify-center rounded-full text-white",
5930
6045
  style: { backgroundColor: "var(--ohw-primary, #0885fe)" },
5931
6046
  "aria-hidden": true,
5932
- children: /* @__PURE__ */ jsx19(Check, { className: "size-5" })
6047
+ children: /* @__PURE__ */ jsx20(Check, { className: "size-5" })
5933
6048
  }
5934
6049
  ) : null
5935
6050
  ]
@@ -5945,7 +6060,7 @@ function SectionPickerOverlay({
5945
6060
  }
5946
6061
 
5947
6062
  // src/ui/link-modal/useLinkModalState.ts
5948
- import { useCallback as useCallback2, useEffect as useEffect5, useMemo as useMemo3, useState as useState5 } from "react";
6063
+ import { useCallback as useCallback3, useEffect as useEffect5, useMemo as useMemo3, useState as useState5 } from "react";
5949
6064
  function useLinkModalState({
5950
6065
  open,
5951
6066
  mode,
@@ -5964,7 +6079,7 @@ function useLinkModalState({
5964
6079
  const [step, setStep] = useState5("input");
5965
6080
  const [dropdownOpen, setDropdownOpen] = useState5(false);
5966
6081
  const [urlError, setUrlError] = useState5("");
5967
- const reset = useCallback2(() => {
6082
+ const reset = useCallback3(() => {
5968
6083
  setSearchValue("");
5969
6084
  setSelectedPage(null);
5970
6085
  setSelectedSection(null);
@@ -6109,7 +6224,7 @@ function useLinkModalState({
6109
6224
  }
6110
6225
 
6111
6226
  // src/ui/link-modal/LinkPopover.tsx
6112
- import { Fragment as Fragment4, jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
6227
+ import { Fragment as Fragment4, jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
6113
6228
  function postToParent(data) {
6114
6229
  window.parent?.postMessage(data, "*");
6115
6230
  }
@@ -6205,15 +6320,15 @@ function LinkPopover({
6205
6320
  );
6206
6321
  };
6207
6322
  }, [open, sectionPickerActive]);
6208
- return /* @__PURE__ */ jsxs12(Fragment4, { children: [
6209
- /* @__PURE__ */ jsx20(
6323
+ return /* @__PURE__ */ jsxs13(Fragment4, { children: [
6324
+ /* @__PURE__ */ jsx21(
6210
6325
  Dialog2,
6211
6326
  {
6212
6327
  open: open && !sectionPickerActive,
6213
6328
  onOpenChange: (next) => {
6214
6329
  if (!next) onClose?.();
6215
6330
  },
6216
- children: /* @__PURE__ */ jsx20(
6331
+ children: /* @__PURE__ */ jsx21(
6217
6332
  DialogContent,
6218
6333
  {
6219
6334
  ref: panelRef,
@@ -6223,12 +6338,12 @@ function LinkPopover({
6223
6338
  "data-ohw-bridge": "",
6224
6339
  showCloseButton: false,
6225
6340
  className: "gap-0 p-0 w-full max-w-[448px] pointer-events-auto z-[2147483646] overflow-visible",
6226
- children: /* @__PURE__ */ jsx20(LinkEditorPanel, { state, onClose })
6341
+ children: /* @__PURE__ */ jsx21(LinkEditorPanel, { state, onClose })
6227
6342
  }
6228
6343
  )
6229
6344
  }
6230
6345
  ),
6231
- sectionPickerActive && state.selectedPage ? /* @__PURE__ */ jsx20(
6346
+ sectionPickerActive && state.selectedPage ? /* @__PURE__ */ jsx21(
6232
6347
  SectionPickerOverlay,
6233
6348
  {
6234
6349
  pagePath: state.selectedPage.path,
@@ -6950,7 +7065,195 @@ function parseFooterOrder(content) {
6950
7065
  return null;
6951
7066
  }
6952
7067
  }
7068
+ var FOOTER_HEADING_RE = /^footer-(\d+)-heading$/;
7069
+ var FOOTER_LABEL_RE = /^footer-(\d+)-(\d+)-label$/;
7070
+ var DEFAULT_FOOTER_COLUMN_HEADING = "New";
7071
+ var DEFAULT_FOOTER_COLUMN_LINK_LABEL = "New link";
7072
+ var DEFAULT_FOOTER_COLUMN_LINK_HREF = "";
7073
+ function isFooterLinksContainer(el) {
7074
+ return el.hasAttribute("data-ohw-footer-links") || el.classList.contains("rb-footer-links");
7075
+ }
7076
+ function getFooterColumnIndicesInDom() {
7077
+ const indices = /* @__PURE__ */ new Set();
7078
+ for (const col of listFooterColumns()) {
7079
+ const attr = col.getAttribute("data-ohw-footer-col");
7080
+ if (attr != null) {
7081
+ const n = parseInt(attr, 10);
7082
+ if (Number.isFinite(n)) indices.add(n);
7083
+ }
7084
+ for (const link of listFooterLinksInColumn(col)) {
7085
+ const parsed = parseFooterHrefKey(link.getAttribute("data-ohw-href-key"));
7086
+ if (parsed) indices.add(parsed.col);
7087
+ }
7088
+ const heading = col.querySelector('[data-ohw-key^="footer-"][data-ohw-key$="-heading"]');
7089
+ const headingKey = heading?.getAttribute("data-ohw-key");
7090
+ if (headingKey) {
7091
+ const match = headingKey.match(FOOTER_HEADING_RE);
7092
+ if (match) indices.add(parseInt(match[1], 10));
7093
+ }
7094
+ }
7095
+ return [...indices].sort((a, b) => a - b);
7096
+ }
7097
+ function getNextFooterColumnIndex() {
7098
+ const indices = getFooterColumnIndicesInDom();
7099
+ if (indices.length === 0) return 0;
7100
+ return Math.max(...indices) + 1;
7101
+ }
7102
+ function cloneFooterLinkShell(template) {
7103
+ const anchor = document.createElement("a");
7104
+ if (template) {
7105
+ anchor.style.cssText = template.style.cssText;
7106
+ if (template.className) anchor.className = template.className;
7107
+ }
7108
+ anchor.style.cursor = "pointer";
7109
+ anchor.style.textDecoration = "none";
7110
+ return anchor;
7111
+ }
7112
+ function buildFooterHeading(colIndex, text) {
7113
+ const heading = document.createElement("p");
7114
+ heading.setAttribute("data-ohw-editable", "text");
7115
+ heading.setAttribute("data-ohw-key", `footer-${colIndex}-heading`);
7116
+ heading.textContent = text;
7117
+ heading.style.cssText = [
7118
+ "color: var(--espresso, #3d312b)",
7119
+ "font-size: 14px",
7120
+ "font-weight: 800",
7121
+ "opacity: 0.82",
7122
+ "margin: 0 0 6px",
7123
+ "padding: 0",
7124
+ "line-height: 1.2"
7125
+ ].join(";");
7126
+ return heading;
7127
+ }
7128
+ function buildFooterLink(colIndex, itemIndex, href, label, template) {
7129
+ const anchor = cloneFooterLinkShell(template);
7130
+ anchor.setAttribute("href", href);
7131
+ anchor.setAttribute("data-ohw-href-key", `footer-${colIndex}-${itemIndex}-href`);
7132
+ const span = document.createElement("span");
7133
+ span.setAttribute("data-ohw-editable", "text");
7134
+ span.setAttribute("data-ohw-key", `footer-${colIndex}-${itemIndex}-label`);
7135
+ span.textContent = label;
7136
+ anchor.appendChild(span);
7137
+ return anchor;
7138
+ }
7139
+ function footerColumnExistsInDom(colIndex) {
7140
+ return document.querySelector(`[data-ohw-footer-col="${colIndex}"]`) !== null || document.querySelector(`[data-ohw-href-key^="footer-${colIndex}-"]`) !== null || document.querySelector(`[data-ohw-key="footer-${colIndex}-heading"]`) !== null;
7141
+ }
7142
+ function getFooterLinkTemplate() {
7143
+ for (const col of listFooterColumns()) {
7144
+ const link = listFooterLinksInColumn(col)[0];
7145
+ if (link) return link;
7146
+ }
7147
+ return null;
7148
+ }
7149
+ function getFooterColumnTemplate() {
7150
+ return listFooterColumns()[0] ?? null;
7151
+ }
7152
+ function insertFooterColumnDom(colIndex, heading, items) {
7153
+ const container = getFooterLinksContainer();
7154
+ if (!container) return null;
7155
+ const colTemplate = getFooterColumnTemplate();
7156
+ const linkTemplate = getFooterLinkTemplate();
7157
+ const column = document.createElement("div");
7158
+ if (colTemplate?.className) column.className = colTemplate.className;
7159
+ else column.className = "rb-footer-link-col";
7160
+ column.setAttribute("data-ohw-footer-col", String(colIndex));
7161
+ if (colTemplate) {
7162
+ const gap = getComputedStyle(colTemplate).gap;
7163
+ if (gap && gap !== "normal") column.style.gap = gap;
7164
+ column.style.display = getComputedStyle(colTemplate).display || "flex";
7165
+ column.style.flexDirection = "column";
7166
+ }
7167
+ column.appendChild(buildFooterHeading(colIndex, heading));
7168
+ let firstLink = null;
7169
+ items.forEach((item, itemIndex) => {
7170
+ const link = buildFooterLink(colIndex, itemIndex, item.href, item.label, linkTemplate);
7171
+ column.appendChild(link);
7172
+ if (!firstLink) firstLink = link;
7173
+ });
7174
+ container.appendChild(column);
7175
+ return { column, firstLink };
7176
+ }
7177
+ function insertFooterColumn(heading = DEFAULT_FOOTER_COLUMN_HEADING, linkLabel = DEFAULT_FOOTER_COLUMN_LINK_LABEL, linkHref = DEFAULT_FOOTER_COLUMN_LINK_HREF) {
7178
+ const colIndex = getNextFooterColumnIndex();
7179
+ const inserted = insertFooterColumnDom(colIndex, heading, [{ href: linkHref, label: linkLabel }]);
7180
+ if (!inserted?.firstLink) throw new Error("Failed to insert footer column");
7181
+ syncFooterColumnIndices(listFooterColumns());
7182
+ return {
7183
+ column: inserted.column,
7184
+ firstLink: inserted.firstLink,
7185
+ colIndex,
7186
+ headingKey: `footer-${colIndex}-heading`,
7187
+ hrefKey: `footer-${colIndex}-0-href`,
7188
+ labelKey: `footer-${colIndex}-0-label`,
7189
+ heading,
7190
+ label: linkLabel,
7191
+ href: linkHref,
7192
+ order: getFooterOrderFromDom()
7193
+ };
7194
+ }
7195
+ function collectFooterColumnIndicesFromContent(content) {
7196
+ const indices = /* @__PURE__ */ new Set();
7197
+ for (const key of Object.keys(content)) {
7198
+ const href = parseFooterHrefKey(key);
7199
+ if (href) indices.add(href.col);
7200
+ const heading = key.match(FOOTER_HEADING_RE);
7201
+ if (heading) indices.add(parseInt(heading[1], 10));
7202
+ const label = key.match(FOOTER_LABEL_RE);
7203
+ if (label) indices.add(parseInt(label[1], 10));
7204
+ }
7205
+ const order = parseFooterOrder(content);
7206
+ if (order) {
7207
+ for (const col of order) {
7208
+ for (const hrefKey of col) {
7209
+ const parsed = parseFooterHrefKey(hrefKey);
7210
+ if (parsed) indices.add(parsed.col);
7211
+ }
7212
+ }
7213
+ }
7214
+ return [...indices].sort((a, b) => a - b);
7215
+ }
7216
+ function collectFooterItemsForColumn(content, colIndex) {
7217
+ const itemIndices = /* @__PURE__ */ new Set();
7218
+ for (const key of Object.keys(content)) {
7219
+ const href = parseFooterHrefKey(key);
7220
+ if (href?.col === colIndex) itemIndices.add(href.item);
7221
+ const label = key.match(FOOTER_LABEL_RE);
7222
+ if (label && parseInt(label[1], 10) === colIndex) {
7223
+ itemIndices.add(parseInt(label[2], 10));
7224
+ }
7225
+ }
7226
+ const sorted = [...itemIndices].sort((a, b) => a - b);
7227
+ if (sorted.length === 0) {
7228
+ return [
7229
+ {
7230
+ href: content[`footer-${colIndex}-0-href`] ?? DEFAULT_FOOTER_COLUMN_LINK_HREF,
7231
+ label: content[`footer-${colIndex}-0-label`] ?? DEFAULT_FOOTER_COLUMN_LINK_LABEL
7232
+ }
7233
+ ];
7234
+ }
7235
+ return sorted.map((itemIndex) => ({
7236
+ href: content[`footer-${colIndex}-${itemIndex}-href`] ?? DEFAULT_FOOTER_COLUMN_LINK_HREF,
7237
+ label: content[`footer-${colIndex}-${itemIndex}-label`] ?? DEFAULT_FOOTER_COLUMN_LINK_LABEL
7238
+ }));
7239
+ }
7240
+ function reconcileFooterColumnsFromContent(content) {
7241
+ const indices = collectFooterColumnIndicesFromContent(content);
7242
+ for (const colIndex of indices) {
7243
+ if (footerColumnExistsInDom(colIndex)) continue;
7244
+ const heading = content[`footer-${colIndex}-heading`] ?? DEFAULT_FOOTER_COLUMN_HEADING;
7245
+ const items = collectFooterItemsForColumn(content, colIndex);
7246
+ const hasPayload = Boolean(content[`footer-${colIndex}-heading`]) || items.some(
7247
+ (_, i) => content[`footer-${colIndex}-${i}-href`] !== void 0 || content[`footer-${colIndex}-${i}-label`] !== void 0
7248
+ ) || (parseFooterOrder(content)?.some(
7249
+ (col) => col.some((k) => parseFooterHrefKey(k)?.col === colIndex)
7250
+ ) ?? false);
7251
+ if (!hasPayload) continue;
7252
+ insertFooterColumnDom(colIndex, heading, items);
7253
+ }
7254
+ }
6953
7255
  function reconcileFooterOrderFromContent(content) {
7256
+ reconcileFooterColumnsFromContent(content);
6954
7257
  const order = parseFooterOrder(content);
6955
7258
  if (!order?.length) return;
6956
7259
  const current = getFooterOrderFromDom();
@@ -6960,6 +7263,26 @@ function reconcileFooterOrderFromContent(content) {
6960
7263
  }
6961
7264
  applyFooterOrder(order);
6962
7265
  }
7266
+ function resolveFooterLinksContainerSelectionTarget(target, clientX, clientY, isPointOverItem) {
7267
+ const container = getFooterLinksContainer();
7268
+ if (!container) return null;
7269
+ const inContainer = target === container || container.contains(target) && Boolean(target.closest("[data-ohw-footer-links], .rb-footer-links"));
7270
+ if (!inContainer && target !== container) {
7271
+ const r2 = container.getBoundingClientRect();
7272
+ const over = clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom;
7273
+ if (!over) return null;
7274
+ }
7275
+ if (isPointOverItem(container, clientX, clientY)) return null;
7276
+ const column = target.closest("[data-ohw-footer-col], [data-ohw-footer-column]") ?? null;
7277
+ if (column && container.contains(column)) {
7278
+ if (target === column || column.contains(target)) return null;
7279
+ }
7280
+ if (target === container || container.contains(target) || inContainer) {
7281
+ if (target === container || isFooterLinksContainer(target)) return container;
7282
+ if (!column) return container;
7283
+ }
7284
+ return null;
7285
+ }
6963
7286
  function isRowLayoutColumn(links) {
6964
7287
  if (links.length < 2) return false;
6965
7288
  const firstTop = links[0].getBoundingClientRect().top;
@@ -7115,6 +7438,30 @@ function hitTestColumnDropSlot(clientX, _clientY) {
7115
7438
  return best?.slot ?? null;
7116
7439
  }
7117
7440
 
7441
+ // src/lib/add-footer-column.ts
7442
+ function buildFooterColumnEditContentPatch(result) {
7443
+ return {
7444
+ [result.headingKey]: result.heading,
7445
+ [result.hrefKey]: result.href,
7446
+ [result.labelKey]: result.label,
7447
+ [FOOTER_ORDER_KEY]: JSON.stringify(result.order)
7448
+ };
7449
+ }
7450
+ function addFooterColumnWithPersist({
7451
+ postToParent: postToParent2
7452
+ }) {
7453
+ const result = insertFooterColumn();
7454
+ const patch = buildFooterColumnEditContentPatch(result);
7455
+ setStoredLinkHref(result.hrefKey, result.href);
7456
+ postToParent2({
7457
+ type: "ow:change",
7458
+ nodes: Object.entries(patch).map(([key, text]) => ({ key, text }))
7459
+ });
7460
+ postToParent2({ type: "ow:toast", title: "Item added", toastType: "success" });
7461
+ enforceLinkHrefs();
7462
+ return result;
7463
+ }
7464
+
7118
7465
  // src/lib/item-drag-interaction.ts
7119
7466
  function disableNativeHrefDrag(el) {
7120
7467
  if (el.draggable) el.draggable = false;
@@ -7312,7 +7659,7 @@ function hitTestNavDropSlot(clientX, clientY, draggedHrefKey) {
7312
7659
  }
7313
7660
 
7314
7661
  // src/useNavItemDrag.ts
7315
- import { useCallback as useCallback3, useEffect as useEffect7, useRef as useRef6, useState as useState6 } from "react";
7662
+ import { useCallback as useCallback4, useEffect as useEffect7, useRef as useRef6, useState as useState6 } from "react";
7316
7663
  function useNavItemDrag({
7317
7664
  isEditMode,
7318
7665
  editContentRef,
@@ -7341,7 +7688,7 @@ function useNavItemDrag({
7341
7688
  const [navDropSlots, setNavDropSlots] = useState6([]);
7342
7689
  const [activeNavDropIndex, setActiveNavDropIndex] = useState6(null);
7343
7690
  const navPointerDragRef = useRef6(null);
7344
- const clearNavDragVisuals = useCallback3(() => {
7691
+ const clearNavDragVisuals = useCallback4(() => {
7345
7692
  navDragRef.current = null;
7346
7693
  setNavDropSlots([]);
7347
7694
  setActiveNavDropIndex(null);
@@ -7350,7 +7697,7 @@ function useNavItemDrag({
7350
7697
  setIsItemDragging(false);
7351
7698
  unlockItemDragInteraction();
7352
7699
  }, [setDraggedItemRect, setIsItemDragging, setSiblingHintRects]);
7353
- const refreshNavDragVisuals = useCallback3(
7700
+ const refreshNavDragVisuals = useCallback4(
7354
7701
  (session, activeSlot, clientX, clientY) => {
7355
7702
  setDraggedItemRect(session.draggedEl.getBoundingClientRect());
7356
7703
  if (typeof clientX === "number" && typeof clientY === "number") {
@@ -7374,7 +7721,7 @@ function useNavItemDrag({
7374
7721
  });
7375
7722
  const beginNavDragRef = useRef6(() => {
7376
7723
  });
7377
- const beginNavDrag = useCallback3(
7724
+ const beginNavDrag = useCallback4(
7378
7725
  (session) => {
7379
7726
  const rect = session.draggedEl.getBoundingClientRect();
7380
7727
  session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
@@ -7401,7 +7748,7 @@ function useNavItemDrag({
7401
7748
  ]
7402
7749
  );
7403
7750
  beginNavDragRef.current = beginNavDrag;
7404
- const commitNavDrag = useCallback3(
7751
+ const commitNavDrag = useCallback4(
7405
7752
  (clientX, clientY) => {
7406
7753
  const session = navDragRef.current;
7407
7754
  if (!session) {
@@ -7462,7 +7809,7 @@ function useNavItemDrag({
7462
7809
  [clearNavDragVisuals, deselectRef, editContentRef, postToParentRef, selectRef]
7463
7810
  );
7464
7811
  commitNavDragRef.current = commitNavDrag;
7465
- const startNavLinkDrag = useCallback3(
7812
+ const startNavLinkDrag = useCallback4(
7466
7813
  (anchor, clientX, clientY, wasSelected) => {
7467
7814
  if (footerDragRef.current) return false;
7468
7815
  const hrefKey = anchor.getAttribute("data-ohw-href-key");
@@ -7480,7 +7827,7 @@ function useNavItemDrag({
7480
7827
  },
7481
7828
  [beginNavDrag, footerDragRef, isDragHandleDisabled2, isNavbarButton3]
7482
7829
  );
7483
- const onNavDragOver = useCallback3(
7830
+ const onNavDragOver = useCallback4(
7484
7831
  (e) => {
7485
7832
  const session = navDragRef.current;
7486
7833
  if (!session) return false;
@@ -7617,7 +7964,7 @@ function useNavItemDrag({
7617
7964
  setLinkPopover,
7618
7965
  suppressNextClickRef
7619
7966
  ]);
7620
- const armNavPressFromChrome = useCallback3(
7967
+ const armNavPressFromChrome = useCallback4(
7621
7968
  (selected, clientX, clientY, pointerId) => {
7622
7969
  const hrefKey = selected.getAttribute("data-ohw-href-key");
7623
7970
  if (!hrefKey || !isNavbarHrefKey(hrefKey)) return false;
@@ -7647,15 +7994,144 @@ function useNavItemDrag({
7647
7994
  };
7648
7995
  }
7649
7996
 
7650
- // src/ui/navbar-container-chrome.tsx
7997
+ // src/ui/footer-container-chrome.tsx
7651
7998
  import { Plus as Plus2 } from "lucide-react";
7652
- import { jsx as jsx21 } from "react/jsx-runtime";
7999
+ import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
8000
+ function FooterContainerChrome({ rect, onAdd }) {
8001
+ const chromeGap = 6;
8002
+ const buttonMargin = 7;
8003
+ return /* @__PURE__ */ jsx22(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsx22(
8004
+ "div",
8005
+ {
8006
+ "data-ohw-footer-container-chrome": "",
8007
+ "data-ohw-bridge": "",
8008
+ className: "pointer-events-none fixed z-[2147483647]",
8009
+ style: {
8010
+ top: rect.top - chromeGap,
8011
+ left: rect.left - chromeGap,
8012
+ width: rect.width + chromeGap * 2,
8013
+ height: rect.height + chromeGap * 2
8014
+ },
8015
+ children: /* @__PURE__ */ jsxs14(Tooltip, { children: [
8016
+ /* @__PURE__ */ jsx22(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx22(
8017
+ "button",
8018
+ {
8019
+ type: "button",
8020
+ "data-ohw-footer-add-button": "",
8021
+ className: "pointer-events-auto absolute left-1/2 flex size-7 -translate-x-1/2 -translate-y-full items-center justify-center rounded-[10px] border border-border bg-background p-0.5 shadow-sm transition-colors hover:bg-muted/80",
8022
+ style: { top: chromeGap - buttonMargin },
8023
+ "aria-label": "Add item",
8024
+ onMouseDown: (e) => {
8025
+ e.preventDefault();
8026
+ e.stopPropagation();
8027
+ },
8028
+ onClick: (e) => {
8029
+ e.preventDefault();
8030
+ e.stopPropagation();
8031
+ onAdd();
8032
+ },
8033
+ children: /* @__PURE__ */ jsx22(Plus2, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
8034
+ }
8035
+ ) }),
8036
+ /* @__PURE__ */ jsx22(TooltipContent, { side: "bottom", sideOffset: 9, children: "Add item" })
8037
+ ] })
8038
+ }
8039
+ ) });
8040
+ }
8041
+
8042
+ // src/lib/carousel.ts
8043
+ import { useEffect as useEffect8, useState as useState7 } from "react";
8044
+ var CAROUSEL_ATTR = "data-ohw-carousel";
8045
+ var CAROUSEL_VALUE_ATTR = "data-ohw-carousel-value";
8046
+ var CAROUSEL_SLIDE_ATTR = "data-ohw-carousel-slide";
8047
+ var CAROUSEL_EVENT = "ohw:carousel-change";
8048
+ function listCarouselKeys() {
8049
+ const keys = /* @__PURE__ */ new Set();
8050
+ document.querySelectorAll(`[${CAROUSEL_ATTR}]`).forEach((el) => {
8051
+ const key = el.getAttribute("data-ohw-key");
8052
+ if (key) keys.add(key);
8053
+ });
8054
+ return [...keys];
8055
+ }
8056
+ function containersForKey(key) {
8057
+ return Array.from(
8058
+ document.querySelectorAll(`[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`)
8059
+ );
8060
+ }
8061
+ function isCarouselKey(key) {
8062
+ return containersForKey(key).length > 0;
8063
+ }
8064
+ function parseSlides(raw) {
8065
+ if (!raw) return [];
8066
+ try {
8067
+ const parsed = JSON.parse(raw);
8068
+ if (!Array.isArray(parsed)) return [];
8069
+ return parsed.filter((s) => Boolean(s) && typeof s === "object").map((s) => ({ src: String(s.src ?? ""), alt: String(s.alt ?? "") }));
8070
+ } catch {
8071
+ return [];
8072
+ }
8073
+ }
8074
+ function readCarouselValue(key) {
8075
+ const container = containersForKey(key)[0];
8076
+ if (!container) return [];
8077
+ const fromAttr = parseSlides(container.getAttribute(CAROUSEL_VALUE_ATTR));
8078
+ if (fromAttr.length > 0) return fromAttr;
8079
+ return Array.from(container.querySelectorAll(`[${CAROUSEL_SLIDE_ATTR}]`)).filter((slide) => slide.closest(`[${CAROUSEL_ATTR}]`) === container).sort((a, b) => slideIndex(a) - slideIndex(b)).map((slide) => {
8080
+ const img = slide instanceof HTMLImageElement ? slide : slide.querySelector("img");
8081
+ return { src: img?.src ?? "", alt: img?.alt ?? "" };
8082
+ });
8083
+ }
8084
+ function slideIndex(el) {
8085
+ const raw = el.getAttribute(CAROUSEL_SLIDE_ATTR);
8086
+ const n = raw ? parseInt(raw, 10) : NaN;
8087
+ return Number.isFinite(n) ? n : 0;
8088
+ }
8089
+ function applyCarouselValue(key, slides) {
8090
+ const value = JSON.stringify(slides);
8091
+ for (const container of containersForKey(key)) {
8092
+ if (container.getAttribute(CAROUSEL_VALUE_ATTR) === value) continue;
8093
+ container.setAttribute(CAROUSEL_VALUE_ATTR, value);
8094
+ container.dispatchEvent(
8095
+ new CustomEvent(CAROUSEL_EVENT, { detail: { images: slides } })
8096
+ );
8097
+ }
8098
+ }
8099
+ function applyCarouselNode(key, val) {
8100
+ if (!isCarouselKey(key)) return false;
8101
+ applyCarouselValue(key, parseSlides(val));
8102
+ return true;
8103
+ }
8104
+ function useOhwCarousel(key, initial) {
8105
+ const [images, setImages] = useState7(initial);
8106
+ useEffect8(() => {
8107
+ const el = document.querySelector(
8108
+ `[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`
8109
+ );
8110
+ if (!el) return;
8111
+ const onChange = (e) => {
8112
+ const detail = e.detail;
8113
+ if (Array.isArray(detail?.images)) setImages(detail.images);
8114
+ };
8115
+ el.addEventListener(CAROUSEL_EVENT, onChange);
8116
+ return () => el.removeEventListener(CAROUSEL_EVENT, onChange);
8117
+ }, [key]);
8118
+ const bind = {
8119
+ [CAROUSEL_ATTR]: "",
8120
+ "data-ohw-key": key,
8121
+ [CAROUSEL_VALUE_ATTR]: JSON.stringify(images)
8122
+ };
8123
+ return { images, setImages, bind };
8124
+ }
8125
+
8126
+ // src/ui/navbar-container-chrome.tsx
8127
+ import { Plus as Plus3 } from "lucide-react";
8128
+ import { jsx as jsx23 } from "react/jsx-runtime";
7653
8129
  function NavbarContainerChrome({
7654
8130
  rect,
7655
8131
  onAdd
7656
8132
  }) {
7657
8133
  const chromeGap = 6;
7658
- return /* @__PURE__ */ jsx21(
8134
+ return /* @__PURE__ */ jsx23(
7659
8135
  "div",
7660
8136
  {
7661
8137
  "data-ohw-navbar-container-chrome": "",
@@ -7667,7 +8143,7 @@ function NavbarContainerChrome({
7667
8143
  width: rect.width + chromeGap * 2,
7668
8144
  height: rect.height + chromeGap * 2
7669
8145
  },
7670
- children: /* @__PURE__ */ jsx21(
8146
+ children: /* @__PURE__ */ jsx23(
7671
8147
  "button",
7672
8148
  {
7673
8149
  type: "button",
@@ -7684,7 +8160,7 @@ function NavbarContainerChrome({
7684
8160
  e.stopPropagation();
7685
8161
  onAdd();
7686
8162
  },
7687
- children: /* @__PURE__ */ jsx21(Plus2, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
8163
+ children: /* @__PURE__ */ jsx23(Plus3, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
7688
8164
  }
7689
8165
  )
7690
8166
  }
@@ -7693,7 +8169,7 @@ function NavbarContainerChrome({
7693
8169
 
7694
8170
  // src/ui/drop-indicator.tsx
7695
8171
  import * as React10 from "react";
7696
- import { jsx as jsx22 } from "react/jsx-runtime";
8172
+ import { jsx as jsx24 } from "react/jsx-runtime";
7697
8173
  var dropIndicatorVariants = cva(
7698
8174
  "ov-gap-line pointer-events-none shrink-0 transition-opacity duration-150",
7699
8175
  {
@@ -7717,7 +8193,7 @@ var dropIndicatorVariants = cva(
7717
8193
  );
7718
8194
  var DropIndicator = React10.forwardRef(
7719
8195
  ({ className, direction, state, ...props }, ref) => {
7720
- return /* @__PURE__ */ jsx22(
8196
+ return /* @__PURE__ */ jsx24(
7721
8197
  "div",
7722
8198
  {
7723
8199
  ref,
@@ -7734,7 +8210,7 @@ var DropIndicator = React10.forwardRef(
7734
8210
  DropIndicator.displayName = "DropIndicator";
7735
8211
 
7736
8212
  // src/ui/badge.tsx
7737
- import { jsx as jsx23 } from "react/jsx-runtime";
8213
+ import { jsx as jsx25 } from "react/jsx-runtime";
7738
8214
  var badgeVariants = cva(
7739
8215
  "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",
7740
8216
  {
@@ -7752,12 +8228,12 @@ var badgeVariants = cva(
7752
8228
  }
7753
8229
  );
7754
8230
  function Badge({ className, variant, ...props }) {
7755
- return /* @__PURE__ */ jsx23("div", { className: cn(badgeVariants({ variant }), className), ...props });
8231
+ return /* @__PURE__ */ jsx25("div", { className: cn(badgeVariants({ variant }), className), ...props });
7756
8232
  }
7757
8233
 
7758
8234
  // src/OhhwellsBridge.tsx
7759
8235
  import { Link as Link2 } from "lucide-react";
7760
- import { Fragment as Fragment5, jsx as jsx24, jsxs as jsxs13 } from "react/jsx-runtime";
8236
+ import { Fragment as Fragment5, jsx as jsx26, jsxs as jsxs15 } from "react/jsx-runtime";
7761
8237
  var PRIMARY2 = "#0885FE";
7762
8238
  var IMAGE_FADE_MS = 300;
7763
8239
  function runOpacityFade(el, onDone) {
@@ -7936,7 +8412,7 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
7936
8412
  const root = createRoot(container);
7937
8413
  flushSync(() => {
7938
8414
  root.render(
7939
- /* @__PURE__ */ jsx24(
8415
+ /* @__PURE__ */ jsx26(
7940
8416
  SchedulingWidget,
7941
8417
  {
7942
8418
  notifyOnConnect,
@@ -8054,6 +8530,9 @@ function collectEditableNodes(extraContent) {
8054
8530
  nodes.push({ key: `${key}${VIDEO_AUTOPLAY_SUFFIX}`, type: "video-setting", text: String(video.autoplay) });
8055
8531
  nodes.push({ key: `${key}${VIDEO_MUTED_SUFFIX}`, type: "video-setting", text: String(video.muted) });
8056
8532
  });
8533
+ for (const key of listCarouselKeys()) {
8534
+ nodes.push({ key, type: "carousel", text: JSON.stringify(readCarouselValue(key)) });
8535
+ }
8057
8536
  const seen = /* @__PURE__ */ new Set();
8058
8537
  return nodes.filter((node) => {
8059
8538
  if (!node.key) return true;
@@ -8137,7 +8616,7 @@ function applyLinkByKey(key, val) {
8137
8616
  }
8138
8617
  function isInsideLinkEditor(target) {
8139
8618
  return Boolean(
8140
- 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"]')
8619
+ 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-ohw-footer-container-chrome]") || target.closest("[data-ohw-footer-add-button]") || target.closest('[data-slot="popover-content"]') || target.closest('[data-slot="dialog-content"]') || target.closest('[data-slot="dialog-overlay"]')
8141
8620
  );
8142
8621
  }
8143
8622
  function getHrefKeyFromElement(el) {
@@ -8218,7 +8697,7 @@ function isInferredFooterGroup(el) {
8218
8697
  return countFooterNavItems(el) >= 2;
8219
8698
  }
8220
8699
  function isNavigationContainer(el) {
8221
- return el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isNavigationRoot(el) || isInferredFooterGroup(el);
8700
+ return el.hasAttribute("data-ohw-nav-container") || isFooterLinksContainer(el) || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isNavigationRoot(el) || isInferredFooterGroup(el);
8222
8701
  }
8223
8702
  function isNavbarLinksContainer(el) {
8224
8703
  return el.hasAttribute("data-ohw-nav-container");
@@ -8237,6 +8716,9 @@ function isPointOverNavigation(x, y) {
8237
8716
  const roots = /* @__PURE__ */ new Set();
8238
8717
  const navRoot = document.querySelector("[data-ohw-nav-root]") ?? document.querySelector("nav");
8239
8718
  if (navRoot) roots.add(navRoot);
8719
+ document.querySelectorAll("[data-ohw-nav-drawer], [data-ohw-nav-container]").forEach((el) => {
8720
+ roots.add(el);
8721
+ });
8240
8722
  const footer = document.querySelector("footer");
8241
8723
  if (footer) roots.add(footer);
8242
8724
  for (const root of roots) {
@@ -8265,6 +8747,12 @@ function isPointOverNavItem(container, x, y) {
8265
8747
  return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
8266
8748
  });
8267
8749
  }
8750
+ function isPointOverFooterColumn(x, y) {
8751
+ return listFooterColumns().some((col) => {
8752
+ const r2 = col.getBoundingClientRect();
8753
+ return x >= r2.left && x <= r2.right && y >= r2.top && y <= r2.bottom;
8754
+ });
8755
+ }
8268
8756
  function resolveNavContainerSelectionTarget(target, clientX, clientY) {
8269
8757
  if (getNavigationItemAnchor(target)) return null;
8270
8758
  if (target.closest('[data-ohw-role="navbar-button"]')) return null;
@@ -8295,7 +8783,10 @@ function getNavigationSelectionParent(el) {
8295
8783
  if (footerGroup) return footerGroup;
8296
8784
  return getNavigationRoot(el);
8297
8785
  }
8298
- if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup(el)) {
8786
+ if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup(el))) {
8787
+ return getFooterLinksContainer();
8788
+ }
8789
+ if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isFooterLinksContainer(el) || isInferredFooterGroup(el)) {
8299
8790
  return getNavigationRoot(el);
8300
8791
  }
8301
8792
  return null;
@@ -8522,7 +9013,7 @@ function EditGlowChrome({
8522
9013
  hideHandle = false
8523
9014
  }) {
8524
9015
  const GAP = SELECTION_CHROME_GAP2;
8525
- return /* @__PURE__ */ jsxs13(
9016
+ return /* @__PURE__ */ jsxs15(
8526
9017
  "div",
8527
9018
  {
8528
9019
  ref: elRef,
@@ -8537,7 +9028,7 @@ function EditGlowChrome({
8537
9028
  zIndex: 2147483646
8538
9029
  },
8539
9030
  children: [
8540
- /* @__PURE__ */ jsx24(
9031
+ /* @__PURE__ */ jsx26(
8541
9032
  "div",
8542
9033
  {
8543
9034
  style: {
@@ -8550,7 +9041,7 @@ function EditGlowChrome({
8550
9041
  }
8551
9042
  }
8552
9043
  ),
8553
- reorderHrefKey && !hideHandle && /* @__PURE__ */ jsx24(
9044
+ reorderHrefKey && !hideHandle && /* @__PURE__ */ jsx26(
8554
9045
  "div",
8555
9046
  {
8556
9047
  "data-ohw-drag-handle-container": "",
@@ -8562,7 +9053,7 @@ function EditGlowChrome({
8562
9053
  transform: "translate(calc(-100% - 7px), -50%)",
8563
9054
  pointerEvents: dragDisabled ? "none" : "auto"
8564
9055
  },
8565
- children: /* @__PURE__ */ jsx24(
9056
+ children: /* @__PURE__ */ jsx26(
8566
9057
  DragHandle,
8567
9058
  {
8568
9059
  "aria-label": `Reorder ${reorderHrefKey}`,
@@ -8772,7 +9263,7 @@ function FloatingToolbar({
8772
9263
  return () => ro.disconnect();
8773
9264
  }, [showEditLink, activeCommands]);
8774
9265
  const { top, left, transform } = calcToolbarPos(rect, parentScroll, measuredW);
8775
- return /* @__PURE__ */ jsx24(
9266
+ return /* @__PURE__ */ jsx26(
8776
9267
  "div",
8777
9268
  {
8778
9269
  ref: setRefs,
@@ -8784,12 +9275,12 @@ function FloatingToolbar({
8784
9275
  zIndex: 2147483647,
8785
9276
  pointerEvents: "auto"
8786
9277
  },
8787
- children: /* @__PURE__ */ jsxs13(CustomToolbar, { children: [
8788
- TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs13(React11.Fragment, { children: [
8789
- gi > 0 && /* @__PURE__ */ jsx24(CustomToolbarDivider, {}),
9278
+ children: /* @__PURE__ */ jsxs15(CustomToolbar, { children: [
9279
+ TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs15(React11.Fragment, { children: [
9280
+ gi > 0 && /* @__PURE__ */ jsx26(CustomToolbarDivider, {}),
8790
9281
  btns.map((btn) => {
8791
9282
  const isActive = activeCommands.has(btn.cmd);
8792
- return /* @__PURE__ */ jsx24(
9283
+ return /* @__PURE__ */ jsx26(
8793
9284
  CustomToolbarButton,
8794
9285
  {
8795
9286
  title: btn.title,
@@ -8798,7 +9289,7 @@ function FloatingToolbar({
8798
9289
  e.preventDefault();
8799
9290
  onCommand(btn.cmd);
8800
9291
  },
8801
- children: /* @__PURE__ */ jsx24(
9292
+ children: /* @__PURE__ */ jsx26(
8802
9293
  "svg",
8803
9294
  {
8804
9295
  width: "16",
@@ -8819,7 +9310,7 @@ function FloatingToolbar({
8819
9310
  );
8820
9311
  })
8821
9312
  ] }, gi)),
8822
- showEditLink ? /* @__PURE__ */ jsx24(
9313
+ showEditLink ? /* @__PURE__ */ jsx26(
8823
9314
  CustomToolbarButton,
8824
9315
  {
8825
9316
  type: "button",
@@ -8833,7 +9324,7 @@ function FloatingToolbar({
8833
9324
  e.preventDefault();
8834
9325
  e.stopPropagation();
8835
9326
  },
8836
- children: /* @__PURE__ */ jsx24(Link2, { className: "size-4 shrink-0", "aria-hidden": true })
9327
+ children: /* @__PURE__ */ jsx26(Link2, { className: "size-4 shrink-0", "aria-hidden": true })
8837
9328
  }
8838
9329
  ) : null
8839
9330
  ] })
@@ -8850,7 +9341,7 @@ function StateToggle({
8850
9341
  states,
8851
9342
  onStateChange
8852
9343
  }) {
8853
- return /* @__PURE__ */ jsx24(
9344
+ return /* @__PURE__ */ jsx26(
8854
9345
  ToggleGroup,
8855
9346
  {
8856
9347
  "data-ohw-state-toggle": "",
@@ -8864,7 +9355,7 @@ function StateToggle({
8864
9355
  left: rect.right - 8,
8865
9356
  transform: "translateX(-100%)"
8866
9357
  },
8867
- children: states.map((state) => /* @__PURE__ */ jsx24(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
9358
+ children: states.map((state) => /* @__PURE__ */ jsx26(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
8868
9359
  }
8869
9360
  );
8870
9361
  }
@@ -8891,8 +9382,8 @@ function OhhwellsBridge() {
8891
9382
  const router = useRouter2();
8892
9383
  const searchParams = useSearchParams();
8893
9384
  const isEditMode = isEditSessionActive();
8894
- const [bridgeRoot, setBridgeRoot] = useState7(null);
8895
- useEffect8(() => {
9385
+ const [bridgeRoot, setBridgeRoot] = useState8(null);
9386
+ useEffect9(() => {
8896
9387
  const figtreeFontId = "ohw-figtree-font";
8897
9388
  if (!document.getElementById(figtreeFontId)) {
8898
9389
  const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
@@ -8920,12 +9411,12 @@ function OhhwellsBridge() {
8920
9411
  const subdomainFromQuery = searchParams.get("subdomain");
8921
9412
  const subdomain = resolveSubdomain(subdomainFromQuery);
8922
9413
  useLinkHrefGuardian(pathname, subdomain, isEditMode);
8923
- const postToParent2 = useCallback4((data) => {
9414
+ const postToParent2 = useCallback5((data) => {
8924
9415
  if (typeof window !== "undefined" && window.parent !== window) {
8925
9416
  window.parent.postMessage(data, "*");
8926
9417
  }
8927
9418
  }, []);
8928
- const [fetchState, setFetchState] = useState7("idle");
9419
+ const [fetchState, setFetchState] = useState8("idle");
8929
9420
  const autoSaveTimers = useRef7(/* @__PURE__ */ new Map());
8930
9421
  const activeElRef = useRef7(null);
8931
9422
  const pointerHeldRef = useRef7(false);
@@ -8936,8 +9427,8 @@ function OhhwellsBridge() {
8936
9427
  const activeStateElRef = useRef7(null);
8937
9428
  const parentScrollRef = useRef7(null);
8938
9429
  const visibleViewportRef = useRef7(null);
8939
- const [dialogPortalContainer, setDialogPortalContainer] = useState7(null);
8940
- const attachVisibleViewport = useCallback4((node) => {
9430
+ const [dialogPortalContainer, setDialogPortalContainer] = useState8(null);
9431
+ const attachVisibleViewport = useCallback5((node) => {
8941
9432
  visibleViewportRef.current = node;
8942
9433
  setDialogPortalContainer(node);
8943
9434
  if (node) applyVisibleViewport(node, parentScrollRef.current);
@@ -8947,8 +9438,9 @@ function OhhwellsBridge() {
8947
9438
  const hoveredImageRef = useRef7(null);
8948
9439
  const hoveredImageHasTextOverlapRef = useRef7(false);
8949
9440
  const dragOverElRef = useRef7(null);
8950
- const [mediaHover, setMediaHover] = useState7(null);
8951
- const [uploadingRects, setUploadingRects] = useState7({});
9441
+ const [mediaHover, setMediaHover] = useState8(null);
9442
+ const [carouselHover, setCarouselHover] = useState8(null);
9443
+ const [uploadingRects, setUploadingRects] = useState8({});
8952
9444
  const hoveredGapRef = useRef7(null);
8953
9445
  const imageUnhoverTimerRef = useRef7(null);
8954
9446
  const imageShowTimerRef = useRef7(null);
@@ -8973,40 +9465,40 @@ function OhhwellsBridge() {
8973
9465
  postToParentRef.current = postToParent2;
8974
9466
  const sectionsLoadedRef = useRef7(false);
8975
9467
  const pendingScheduleConfigRequests = useRef7([]);
8976
- const [toolbarRect, setToolbarRect] = useState7(null);
8977
- const [toolbarVariant, setToolbarVariant] = useState7("none");
9468
+ const [toolbarRect, setToolbarRect] = useState8(null);
9469
+ const [toolbarVariant, setToolbarVariant] = useState8("none");
8978
9470
  const toolbarVariantRef = useRef7("none");
8979
9471
  toolbarVariantRef.current = toolbarVariant;
8980
- const [selectedIsCta, setSelectedIsCta] = useState7(false);
8981
- const [reorderHrefKey, setReorderHrefKey] = useState7(null);
8982
- const [reorderDragDisabled, setReorderDragDisabled] = useState7(false);
8983
- const [toggleState, setToggleState] = useState7(null);
8984
- const [maxBadge, setMaxBadge] = useState7(null);
8985
- const [activeCommands, setActiveCommands] = useState7(/* @__PURE__ */ new Set());
8986
- const [sectionGap, setSectionGap] = useState7(null);
8987
- const [toolbarShowEditLink, setToolbarShowEditLink] = useState7(false);
9472
+ const [selectedIsCta, setSelectedIsCta] = useState8(false);
9473
+ const [reorderHrefKey, setReorderHrefKey] = useState8(null);
9474
+ const [reorderDragDisabled, setReorderDragDisabled] = useState8(false);
9475
+ const [toggleState, setToggleState] = useState8(null);
9476
+ const [maxBadge, setMaxBadge] = useState8(null);
9477
+ const [activeCommands, setActiveCommands] = useState8(/* @__PURE__ */ new Set());
9478
+ const [sectionGap, setSectionGap] = useState8(null);
9479
+ const [toolbarShowEditLink, setToolbarShowEditLink] = useState8(false);
8988
9480
  const hoveredNavContainerRef = useRef7(null);
8989
- const [hoveredNavContainerRect, setHoveredNavContainerRect] = useState7(null);
9481
+ const [hoveredNavContainerRect, setHoveredNavContainerRect] = useState8(null);
8990
9482
  const hoveredItemElRef = useRef7(null);
8991
- const [hoveredItemRect, setHoveredItemRect] = useState7(null);
9483
+ const [hoveredItemRect, setHoveredItemRect] = useState8(null);
8992
9484
  const siblingHintElRef = useRef7(null);
8993
- const [siblingHintRect, setSiblingHintRect] = useState7(null);
8994
- const [siblingHintRects, setSiblingHintRects] = useState7([]);
8995
- const [isItemDragging, setIsItemDragging] = useState7(false);
8996
- const [isFooterFrameSelection, setIsFooterFrameSelection] = useState7(false);
9485
+ const [siblingHintRect, setSiblingHintRect] = useState8(null);
9486
+ const [siblingHintRects, setSiblingHintRects] = useState8([]);
9487
+ const [isItemDragging, setIsItemDragging] = useState8(false);
9488
+ const [isFooterFrameSelection, setIsFooterFrameSelection] = useState8(false);
8997
9489
  const footerDragRef = useRef7(null);
8998
- const [footerDropSlots, setFooterDropSlots] = useState7([]);
8999
- const [activeFooterDropIndex, setActiveFooterDropIndex] = useState7(null);
9000
- const [draggedItemRect, setDraggedItemRect] = useState7(null);
9490
+ const [footerDropSlots, setFooterDropSlots] = useState8([]);
9491
+ const [activeFooterDropIndex, setActiveFooterDropIndex] = useState8(null);
9492
+ const [draggedItemRect, setDraggedItemRect] = useState8(null);
9001
9493
  const footerPointerDragRef = useRef7(null);
9002
9494
  const suppressNextClickRef = useRef7(false);
9003
9495
  const suppressClickUntilRef = useRef7(0);
9004
- const [linkPopover, setLinkPopover] = useState7(null);
9496
+ const [linkPopover, setLinkPopover] = useState8(null);
9005
9497
  const linkPopoverSessionRef = useRef7(null);
9006
9498
  const addNavAfterAnchorRef = useRef7(null);
9007
9499
  const editContentRef = useRef7({});
9008
- const [sitePages, setSitePages] = useState7([]);
9009
- const [sectionsByPath, setSectionsByPath] = useState7({});
9500
+ const [sitePages, setSitePages] = useState8([]);
9501
+ const [sectionsByPath, setSectionsByPath] = useState8({});
9010
9502
  const sectionsPrefetchGenRef = useRef7(0);
9011
9503
  const setLinkPopoverRef = useRef7(setLinkPopover);
9012
9504
  const linkPopoverPanelRef = useRef7(null);
@@ -9050,7 +9542,7 @@ function OhhwellsBridge() {
9050
9542
  const bumpLinkPopoverGrace = () => {
9051
9543
  linkPopoverGraceUntilRef.current = Date.now() + 350;
9052
9544
  };
9053
- const runSectionsPrefetch = useCallback4((pages) => {
9545
+ const runSectionsPrefetch = useCallback5((pages) => {
9054
9546
  if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
9055
9547
  const gen = ++sectionsPrefetchGenRef.current;
9056
9548
  const paths = pages.map((p) => p.path);
@@ -9071,7 +9563,7 @@ function OhhwellsBridge() {
9071
9563
  }, [isEditMode, pathname]);
9072
9564
  const runSectionsPrefetchRef = useRef7(runSectionsPrefetch);
9073
9565
  runSectionsPrefetchRef.current = runSectionsPrefetch;
9074
- useEffect8(() => {
9566
+ useEffect9(() => {
9075
9567
  if (!linkPopover) {
9076
9568
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
9077
9569
  return;
@@ -9121,7 +9613,7 @@ function OhhwellsBridge() {
9121
9613
  document.removeEventListener("touchmove", preventBackgroundScroll, scrollOpts);
9122
9614
  };
9123
9615
  }, [linkPopover, postToParent2]);
9124
- useEffect8(() => {
9616
+ useEffect9(() => {
9125
9617
  if (!isEditMode) return;
9126
9618
  const useFixtures = shouldUseDevFixtures();
9127
9619
  if (useFixtures) {
@@ -9145,14 +9637,14 @@ function OhhwellsBridge() {
9145
9637
  if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
9146
9638
  return () => window.removeEventListener("message", onSitePages);
9147
9639
  }, [isEditMode, postToParent2]);
9148
- useEffect8(() => {
9640
+ useEffect9(() => {
9149
9641
  if (!isEditMode || shouldUseDevFixtures()) return;
9150
9642
  void loadAllSectionsManifest().then((manifest) => {
9151
9643
  if (Object.keys(manifest).length === 0) return;
9152
9644
  setSectionsByPath((prev) => ({ ...manifest, ...prev }));
9153
9645
  });
9154
9646
  }, [isEditMode]);
9155
- useEffect8(() => {
9647
+ useEffect9(() => {
9156
9648
  const update = () => {
9157
9649
  const el = activeElRef.current ?? selectedElRef.current;
9158
9650
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
@@ -9176,10 +9668,10 @@ function OhhwellsBridge() {
9176
9668
  vvp.removeEventListener("resize", update);
9177
9669
  };
9178
9670
  }, []);
9179
- const refreshStateRules = useCallback4(() => {
9671
+ const refreshStateRules = useCallback5(() => {
9180
9672
  editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
9181
9673
  }, []);
9182
- const processConfigRequest = useCallback4((insertAfterVal) => {
9674
+ const processConfigRequest = useCallback5((insertAfterVal) => {
9183
9675
  const tracker = getSectionsTracker();
9184
9676
  let entries = [];
9185
9677
  try {
@@ -9202,7 +9694,7 @@ function OhhwellsBridge() {
9202
9694
  }
9203
9695
  window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
9204
9696
  }, [isEditMode]);
9205
- const deactivate = useCallback4(() => {
9697
+ const deactivate = useCallback5(() => {
9206
9698
  const el = activeElRef.current;
9207
9699
  if (!el) return;
9208
9700
  const key = el.dataset.ohwKey;
@@ -9234,12 +9726,12 @@ function OhhwellsBridge() {
9234
9726
  setToolbarShowEditLink(false);
9235
9727
  postToParent2({ type: "ow:exit-edit" });
9236
9728
  }, [postToParent2]);
9237
- const clearSelectedAttr = useCallback4(() => {
9729
+ const clearSelectedAttr = useCallback5(() => {
9238
9730
  document.querySelectorAll("[data-ohw-selected]").forEach((el) => {
9239
9731
  el.removeAttribute("data-ohw-selected");
9240
9732
  });
9241
9733
  }, []);
9242
- const deselect = useCallback4(() => {
9734
+ const deselect = useCallback5(() => {
9243
9735
  clearSelectedAttr();
9244
9736
  selectedElRef.current = null;
9245
9737
  selectedHrefKeyRef.current = null;
@@ -9259,11 +9751,11 @@ function OhhwellsBridge() {
9259
9751
  setToolbarVariant("none");
9260
9752
  }
9261
9753
  }, [clearSelectedAttr]);
9262
- const markSelected = useCallback4((el) => {
9754
+ const markSelected = useCallback5((el) => {
9263
9755
  clearSelectedAttr();
9264
9756
  el.setAttribute("data-ohw-selected", "");
9265
9757
  }, [clearSelectedAttr]);
9266
- const resolveHrefKeyElement = useCallback4((hrefKey) => {
9758
+ const resolveHrefKeyElement = useCallback5((hrefKey) => {
9267
9759
  if (isFooterHrefKey(hrefKey)) {
9268
9760
  return document.querySelector(
9269
9761
  `footer [data-ohw-href-key="${CSS.escape(hrefKey)}"]`
@@ -9278,7 +9770,7 @@ function OhhwellsBridge() {
9278
9770
  `[data-ohw-href-key="${CSS.escape(hrefKey)}"]`
9279
9771
  );
9280
9772
  }, []);
9281
- const resyncSelectedNavigationItem = useCallback4(() => {
9773
+ const resyncSelectedNavigationItem = useCallback5(() => {
9282
9774
  const hrefKey = selectedHrefKeyRef.current;
9283
9775
  if (hrefKey) {
9284
9776
  const link = resolveHrefKeyElement(hrefKey);
@@ -9306,7 +9798,7 @@ function OhhwellsBridge() {
9306
9798
  );
9307
9799
  }
9308
9800
  }, [resolveHrefKeyElement]);
9309
- const reselectNavigationItem = useCallback4((navAnchor) => {
9801
+ const reselectNavigationItem = useCallback5((navAnchor) => {
9310
9802
  selectedElRef.current = navAnchor;
9311
9803
  selectedHrefKeyRef.current = navAnchor.getAttribute("data-ohw-href-key");
9312
9804
  selectedFooterColAttrRef.current = null;
@@ -9321,7 +9813,7 @@ function OhhwellsBridge() {
9321
9813
  setToolbarShowEditLink(false);
9322
9814
  setActiveCommands(/* @__PURE__ */ new Set());
9323
9815
  }, [markSelected]);
9324
- const commitNavigationTextEdit = useCallback4((navAnchor) => {
9816
+ const commitNavigationTextEdit = useCallback5((navAnchor) => {
9325
9817
  const el = activeElRef.current;
9326
9818
  if (!el) return;
9327
9819
  const key = el.dataset.ohwKey;
@@ -9348,7 +9840,7 @@ function OhhwellsBridge() {
9348
9840
  postToParent2({ type: "ow:exit-edit" });
9349
9841
  reselectNavigationItem(navAnchor);
9350
9842
  }, [postToParent2, reselectNavigationItem]);
9351
- const handleAddTopLevelNavItem = useCallback4(() => {
9843
+ const handleAddTopLevelNavItem = useCallback5(() => {
9352
9844
  const items = listNavbarItems();
9353
9845
  addNavAfterAnchorRef.current = items[items.length - 1] ?? null;
9354
9846
  deselectRef.current();
@@ -9360,7 +9852,19 @@ function OhhwellsBridge() {
9360
9852
  intent: "add-nav"
9361
9853
  });
9362
9854
  }, []);
9363
- const clearFooterDragVisuals = useCallback4(() => {
9855
+ const handleAddFooterColumn = useCallback5(() => {
9856
+ deselectRef.current();
9857
+ deactivateRef.current();
9858
+ const result = addFooterColumnWithPersist({ postToParent: postToParent2 });
9859
+ editContentRef.current = {
9860
+ ...editContentRef.current,
9861
+ ...buildFooterColumnEditContentPatch(result)
9862
+ };
9863
+ requestAnimationFrame(() => {
9864
+ selectRef.current(result.firstLink);
9865
+ });
9866
+ }, [postToParent2]);
9867
+ const clearFooterDragVisuals = useCallback5(() => {
9364
9868
  footerDragRef.current = null;
9365
9869
  setSiblingHintRects([]);
9366
9870
  setFooterDropSlots([]);
@@ -9369,7 +9873,7 @@ function OhhwellsBridge() {
9369
9873
  setIsItemDragging(false);
9370
9874
  unlockFooterDragInteraction();
9371
9875
  }, []);
9372
- const refreshFooterDragVisuals = useCallback4((session, activeSlot, clientX, clientY) => {
9876
+ const refreshFooterDragVisuals = useCallback5((session, activeSlot, clientX, clientY) => {
9373
9877
  const dragged = session.draggedEl;
9374
9878
  setDraggedItemRect(dragged.getBoundingClientRect());
9375
9879
  if (typeof clientX === "number" && typeof clientY === "number") {
@@ -9400,7 +9904,7 @@ function OhhwellsBridge() {
9400
9904
  });
9401
9905
  const beginFooterDragRef = useRef7(() => {
9402
9906
  });
9403
- const beginFooterDrag = useCallback4(
9907
+ const beginFooterDrag = useCallback5(
9404
9908
  (session) => {
9405
9909
  const rect = session.draggedEl.getBoundingClientRect();
9406
9910
  session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
@@ -9420,7 +9924,7 @@ function OhhwellsBridge() {
9420
9924
  [refreshFooterDragVisuals]
9421
9925
  );
9422
9926
  beginFooterDragRef.current = beginFooterDrag;
9423
- const commitFooterDrag = useCallback4(
9927
+ const commitFooterDrag = useCallback5(
9424
9928
  (clientX, clientY) => {
9425
9929
  const session = footerDragRef.current;
9426
9930
  if (!session) {
@@ -9524,7 +10028,7 @@ function OhhwellsBridge() {
9524
10028
  [clearFooterDragVisuals, resolveHrefKeyElement, resyncSelectedNavigationItem]
9525
10029
  );
9526
10030
  commitFooterDragRef.current = commitFooterDrag;
9527
- const startFooterLinkDrag = useCallback4(
10031
+ const startFooterLinkDrag = useCallback5(
9528
10032
  (anchor, clientX, clientY, wasSelected) => {
9529
10033
  const hrefKey = anchor.getAttribute("data-ohw-href-key");
9530
10034
  if (!hrefKey || !isFooterHrefKey(hrefKey)) return false;
@@ -9545,7 +10049,7 @@ function OhhwellsBridge() {
9545
10049
  },
9546
10050
  [beginFooterDrag]
9547
10051
  );
9548
- const startFooterColumnDrag = useCallback4(
10052
+ const startFooterColumnDrag = useCallback5(
9549
10053
  (columnEl, clientX, clientY, wasSelected) => {
9550
10054
  const columns = listFooterColumns();
9551
10055
  const idx = columns.indexOf(columnEl);
@@ -9565,7 +10069,7 @@ function OhhwellsBridge() {
9565
10069
  },
9566
10070
  [beginFooterDrag]
9567
10071
  );
9568
- const handleItemDragStart = useCallback4(
10072
+ const handleItemDragStart = useCallback5(
9569
10073
  (e) => {
9570
10074
  const selected = selectedElRef.current;
9571
10075
  if (!selected) {
@@ -9585,7 +10089,7 @@ function OhhwellsBridge() {
9585
10089
  },
9586
10090
  [startFooterColumnDrag, startFooterLinkDrag, startNavLinkDrag]
9587
10091
  );
9588
- const handleItemDragEnd = useCallback4(
10092
+ const handleItemDragEnd = useCallback5(
9589
10093
  (e) => {
9590
10094
  if (footerDragRef.current) {
9591
10095
  const x = e?.clientX;
@@ -9611,7 +10115,7 @@ function OhhwellsBridge() {
9611
10115
  },
9612
10116
  [commitFooterDrag, commitNavDrag, navDragRef]
9613
10117
  );
9614
- const handleItemChromePointerDown = useCallback4((e) => {
10118
+ const handleItemChromePointerDown = useCallback5((e) => {
9615
10119
  if (e.button !== 0) return;
9616
10120
  const selected = selectedElRef.current;
9617
10121
  if (!selected) return;
@@ -9642,7 +10146,7 @@ function OhhwellsBridge() {
9642
10146
  }
9643
10147
  if (armNavPressFromChrome(selected, e.clientX, e.clientY, e.pointerId)) return;
9644
10148
  }, [armNavPressFromChrome]);
9645
- const handleItemChromeClick = useCallback4((clientX, clientY) => {
10149
+ const handleItemChromeClick = useCallback5((clientX, clientY) => {
9646
10150
  if (suppressNextClickRef.current || Date.now() < suppressClickUntilRef.current) {
9647
10151
  suppressNextClickRef.current = false;
9648
10152
  return;
@@ -9655,7 +10159,7 @@ function OhhwellsBridge() {
9655
10159
  }, []);
9656
10160
  reselectNavigationItemRef.current = reselectNavigationItem;
9657
10161
  commitNavigationTextEditRef.current = commitNavigationTextEdit;
9658
- const select = useCallback4((anchor) => {
10162
+ const select = useCallback5((anchor) => {
9659
10163
  if (!isNavigationItem(anchor)) return;
9660
10164
  if (activeElRef.current) deactivate();
9661
10165
  selectedElRef.current = anchor;
@@ -9681,10 +10185,10 @@ function OhhwellsBridge() {
9681
10185
  setToolbarShowEditLink(false);
9682
10186
  setActiveCommands(/* @__PURE__ */ new Set());
9683
10187
  }, [deactivate, markSelected]);
9684
- const selectFrame = useCallback4((el) => {
10188
+ const selectFrame = useCallback5((el) => {
9685
10189
  if (!isNavigationContainer(el)) return;
9686
10190
  if (activeElRef.current) deactivate();
9687
- const isFooterColumn = el.hasAttribute("data-ohw-footer-col") || Boolean(el.closest("footer") && isInferredFooterGroup(el));
10191
+ const isFooterColumn = !isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || Boolean(el.closest("footer") && isInferredFooterGroup(el)));
9688
10192
  selectedElRef.current = el;
9689
10193
  selectedHrefKeyRef.current = null;
9690
10194
  selectedFooterColAttrRef.current = isFooterColumn ? el.getAttribute("data-ohw-footer-col") ?? String(listFooterColumns().indexOf(el)) : null;
@@ -9709,7 +10213,7 @@ function OhhwellsBridge() {
9709
10213
  setToolbarShowEditLink(false);
9710
10214
  setActiveCommands(/* @__PURE__ */ new Set());
9711
10215
  }, [deactivate, markSelected]);
9712
- const activate = useCallback4((el, options) => {
10216
+ const activate = useCallback5((el, options) => {
9713
10217
  if (activeElRef.current === el) return;
9714
10218
  clearSelectedAttr();
9715
10219
  selectedElRef.current = null;
@@ -9784,6 +10288,7 @@ function OhhwellsBridge() {
9784
10288
  for (const [key, val] of Object.entries(content)) {
9785
10289
  if (key === "__ohw_sections") continue;
9786
10290
  if (applyVideoSettingNode(key, val)) continue;
10291
+ if (applyCarouselNode(key, val)) continue;
9787
10292
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
9788
10293
  if (el.dataset.ohwEditable === "image") {
9789
10294
  const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
@@ -9844,7 +10349,7 @@ function OhhwellsBridge() {
9844
10349
  cancelled = true;
9845
10350
  };
9846
10351
  }, [subdomain, isEditMode]);
9847
- useEffect8(() => {
10352
+ useEffect9(() => {
9848
10353
  if (!subdomain || isEditMode) return;
9849
10354
  let debounceTimer = null;
9850
10355
  let observer = null;
@@ -9857,6 +10362,7 @@ function OhhwellsBridge() {
9857
10362
  for (const [key, val] of Object.entries(content)) {
9858
10363
  if (key === "__ohw_sections") continue;
9859
10364
  if (applyVideoSettingNode(key, val)) continue;
10365
+ if (applyCarouselNode(key, val)) continue;
9860
10366
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
9861
10367
  if (el.dataset.ohwEditable === "image") {
9862
10368
  const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
@@ -9900,10 +10406,10 @@ function OhhwellsBridge() {
9900
10406
  const visible = Boolean(subdomain) && fetchState !== "done";
9901
10407
  el.style.display = visible ? "flex" : "none";
9902
10408
  }, [subdomain, fetchState]);
9903
- useEffect8(() => {
10409
+ useEffect9(() => {
9904
10410
  postToParent2({ type: "ow:navigation", path: pathname });
9905
10411
  }, [pathname, postToParent2]);
9906
- useEffect8(() => {
10412
+ useEffect9(() => {
9907
10413
  if (!isEditMode) return;
9908
10414
  if (linkPopoverSessionRef.current?.intent === "add-nav") return;
9909
10415
  if (document.querySelector("[data-ohw-section-picker]")) return;
@@ -9911,7 +10417,7 @@ function OhhwellsBridge() {
9911
10417
  deselectRef.current();
9912
10418
  deactivateRef.current();
9913
10419
  }, [pathname, isEditMode]);
9914
- useEffect8(() => {
10420
+ useEffect9(() => {
9915
10421
  const contentForNav = () => {
9916
10422
  if (isEditMode) return editContentRef.current;
9917
10423
  if (!subdomain) return {};
@@ -9976,7 +10482,7 @@ function OhhwellsBridge() {
9976
10482
  observer?.disconnect();
9977
10483
  };
9978
10484
  }, [isEditMode, pathname, subdomain, fetchState, resyncSelectedNavigationItem]);
9979
- useEffect8(() => {
10485
+ useEffect9(() => {
9980
10486
  if (!isEditMode) return;
9981
10487
  const measure = () => {
9982
10488
  const h = document.body.scrollHeight;
@@ -10000,7 +10506,7 @@ function OhhwellsBridge() {
10000
10506
  window.removeEventListener("resize", handleResize);
10001
10507
  };
10002
10508
  }, [pathname, isEditMode, postToParent2]);
10003
- useEffect8(() => {
10509
+ useEffect9(() => {
10004
10510
  if (!subdomainFromQuery || isEditMode) return;
10005
10511
  const handleClick = (e) => {
10006
10512
  const anchor = e.target.closest("a");
@@ -10016,7 +10522,7 @@ function OhhwellsBridge() {
10016
10522
  document.addEventListener("click", handleClick, true);
10017
10523
  return () => document.removeEventListener("click", handleClick, true);
10018
10524
  }, [subdomainFromQuery, isEditMode, router]);
10019
- useEffect8(() => {
10525
+ useEffect9(() => {
10020
10526
  if (!isEditMode) {
10021
10527
  editStylesRef.current?.base.remove();
10022
10528
  editStylesRef.current?.forceHover.remove();
@@ -10240,7 +10746,7 @@ function OhhwellsBridge() {
10240
10746
  }
10241
10747
  e.preventDefault();
10242
10748
  e.stopPropagation();
10243
- activateRef.current(editable);
10749
+ activateRef.current(editable, { caretX: e.clientX, caretY: e.clientY });
10244
10750
  return;
10245
10751
  }
10246
10752
  const hrefAnchor = getNavigationItemAnchor(target);
@@ -10267,6 +10773,18 @@ function OhhwellsBridge() {
10267
10773
  selectFrameRef.current(footerColClick);
10268
10774
  return;
10269
10775
  }
10776
+ const footerLinksToSelect = resolveFooterLinksContainerSelectionTarget(
10777
+ target,
10778
+ e.clientX,
10779
+ e.clientY,
10780
+ isPointOverNavItem
10781
+ );
10782
+ if (footerLinksToSelect) {
10783
+ e.preventDefault();
10784
+ e.stopPropagation();
10785
+ selectFrameRef.current(footerLinksToSelect);
10786
+ return;
10787
+ }
10270
10788
  const navContainerToSelect = resolveNavContainerSelectionTarget(target, e.clientX, e.clientY);
10271
10789
  if (navContainerToSelect) {
10272
10790
  e.preventDefault();
@@ -10325,8 +10843,8 @@ function OhhwellsBridge() {
10325
10843
  return;
10326
10844
  }
10327
10845
  const navLabel = getNavigationLabelEditable(target);
10328
- if (!navLabel) return;
10329
- const { editable } = navLabel;
10846
+ const editable = navLabel?.editable ?? target.closest('[data-ohw-editable="text"], [data-ohw-editable="plain"]');
10847
+ if (!editable || isMediaEditable(editable) || editable.dataset.ohwEditable === "link") return;
10330
10848
  e.preventDefault();
10331
10849
  e.stopPropagation();
10332
10850
  if (activeElRef.current !== editable) {
@@ -10347,16 +10865,38 @@ function OhhwellsBridge() {
10347
10865
  setHoveredNavContainerRect(null);
10348
10866
  return;
10349
10867
  }
10350
- if (toolbarVariantRef.current !== "select-frame") {
10351
- const navContainer = target.closest("[data-ohw-nav-container]");
10352
- if (navContainer && !getNavigationItemAnchor(target)) {
10353
- hoveredNavContainerRef.current = navContainer;
10354
- setHoveredNavContainerRect(navContainer.getBoundingClientRect());
10355
- hoveredItemElRef.current = null;
10356
- setHoveredItemRect(null);
10357
- return;
10868
+ {
10869
+ const selected2 = selectedElRef.current;
10870
+ const selectedIsFooterColumn = Boolean(selected2) && !isFooterLinksContainer(selected2) && (selected2.hasAttribute("data-ohw-footer-col") || selected2.hasAttribute("data-ohw-footer-column") || Boolean(selected2.closest("footer") && isInferredFooterGroup(selected2)));
10871
+ const allowNavContainerHover = toolbarVariantRef.current !== "select-frame";
10872
+ const allowFooterLinksHover = toolbarVariantRef.current !== "select-frame" || selectedIsFooterColumn;
10873
+ if (allowNavContainerHover) {
10874
+ const navContainer = target.closest("[data-ohw-nav-container]");
10875
+ if (navContainer && !getNavigationItemAnchor(target)) {
10876
+ hoveredNavContainerRef.current = navContainer;
10877
+ setHoveredNavContainerRect(navContainer.getBoundingClientRect());
10878
+ hoveredItemElRef.current = null;
10879
+ setHoveredItemRect(null);
10880
+ return;
10881
+ }
10358
10882
  }
10359
- if (!target.closest("[data-ohw-nav-container]")) {
10883
+ if (allowFooterLinksHover) {
10884
+ const navContainer = target.closest("[data-ohw-nav-container]");
10885
+ if (!navContainer) {
10886
+ const footerLinks = target.closest("[data-ohw-footer-links], .rb-footer-links") ?? null;
10887
+ if (footerLinks && selected2 !== footerLinks && !getNavigationItemAnchor(target) && !target.closest("[data-ohw-footer-col], [data-ohw-footer-column]")) {
10888
+ hoveredNavContainerRef.current = footerLinks;
10889
+ setHoveredNavContainerRect(footerLinks.getBoundingClientRect());
10890
+ hoveredItemElRef.current = null;
10891
+ setHoveredItemRect(null);
10892
+ return;
10893
+ }
10894
+ if (!footerLinks) {
10895
+ hoveredNavContainerRef.current = null;
10896
+ setHoveredNavContainerRect(null);
10897
+ }
10898
+ }
10899
+ } else if (toolbarVariantRef.current === "select-frame") {
10360
10900
  hoveredNavContainerRef.current = null;
10361
10901
  setHoveredNavContainerRect(null);
10362
10902
  }
@@ -10398,9 +10938,9 @@ function OhhwellsBridge() {
10398
10938
  };
10399
10939
  const handleMouseOut = (e) => {
10400
10940
  const target = e.target;
10401
- if (target.closest("[data-ohw-nav-container], [data-ohw-footer-col], [data-ohw-footer-column]")) {
10941
+ if (target.closest("[data-ohw-nav-container], [data-ohw-footer-col], [data-ohw-footer-column], [data-ohw-footer-links], .rb-footer-links")) {
10402
10942
  const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
10403
- if (related2?.closest("[data-ohw-nav-container], [data-ohw-footer-col], [data-ohw-footer-column], [data-ohw-navbar-container-chrome], [data-ohw-navbar-add-button]")) {
10943
+ if (related2?.closest("[data-ohw-nav-container], [data-ohw-footer-col], [data-ohw-footer-column], [data-ohw-footer-links], .rb-footer-links, [data-ohw-navbar-container-chrome], [data-ohw-navbar-add-button], [data-ohw-footer-container-chrome], [data-ohw-footer-add-button]")) {
10404
10944
  return;
10405
10945
  }
10406
10946
  hoveredNavContainerRef.current = null;
@@ -10495,6 +11035,15 @@ function OhhwellsBridge() {
10495
11035
  if (track) track.setAttribute("data-ohw-hover-paused", "");
10496
11036
  };
10497
11037
  const clearImageHover = () => setMediaHover(null);
11038
+ const dismissImageHover = () => {
11039
+ if (hoveredImageRef.current) {
11040
+ hoveredImageRef.current = null;
11041
+ hoveredImageHasTextOverlapRef.current = false;
11042
+ resumeAnimTracks();
11043
+ postToParentRef.current({ type: "ow:image-unhover" });
11044
+ }
11045
+ clearImageHover();
11046
+ };
10498
11047
  const findImageAtPoint = (clientX, clientY, fromParentViewport) => {
10499
11048
  const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
10500
11049
  const images = Array.from(document.querySelectorAll(MEDIA_SELECTOR));
@@ -10538,16 +11087,13 @@ function OhhwellsBridge() {
10538
11087
  }
10539
11088
  return smallest;
10540
11089
  };
10541
- const dismissImageHover = () => {
10542
- if (hoveredImageRef.current) {
10543
- hoveredImageRef.current = null;
10544
- hoveredImageHasTextOverlapRef.current = false;
10545
- resumeAnimTracks();
10546
- postToParentRef.current({ type: "ow:image-unhover" });
10547
- }
10548
- };
10549
11090
  const probeNavigationHoverAt = (x, y) => {
10550
- if (toolbarVariantRef.current === "select-frame") {
11091
+ const selected = selectedElRef.current;
11092
+ const selectedIsFooterColumn = Boolean(selected) && !isFooterLinksContainer(selected) && (selected.hasAttribute("data-ohw-footer-col") || selected.hasAttribute("data-ohw-footer-column") || Boolean(selected.closest("footer") && isInferredFooterGroup(selected)));
11093
+ const selectedIsFooterLinks = Boolean(selected && isFooterLinksContainer(selected));
11094
+ const allowNavContainerHover = toolbarVariantRef.current !== "select-frame";
11095
+ const allowFooterLinksHover = (toolbarVariantRef.current !== "select-frame" || selectedIsFooterColumn) && !selectedIsFooterLinks;
11096
+ if (toolbarVariantRef.current === "select-frame" && !allowFooterLinksHover) {
10551
11097
  hoveredNavContainerRef.current = null;
10552
11098
  setHoveredNavContainerRect(null);
10553
11099
  }
@@ -10569,7 +11115,6 @@ function OhhwellsBridge() {
10569
11115
  if (navItemHit) {
10570
11116
  hoveredNavContainerRef.current = null;
10571
11117
  setHoveredNavContainerRect(null);
10572
- const selected = selectedElRef.current;
10573
11118
  if (selected !== navItemHit) {
10574
11119
  clearHrefKeyHover(navItemHit);
10575
11120
  hoveredItemElRef.current = navItemHit;
@@ -10581,7 +11126,7 @@ function OhhwellsBridge() {
10581
11126
  return;
10582
11127
  }
10583
11128
  }
10584
- if (toolbarVariantRef.current !== "select-frame") {
11129
+ if (allowNavContainerHover) {
10585
11130
  for (const container of navContainers) {
10586
11131
  const containerRect = container.getBoundingClientRect();
10587
11132
  const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
@@ -10593,12 +11138,23 @@ function OhhwellsBridge() {
10593
11138
  setHoveredItemRect(null);
10594
11139
  return;
10595
11140
  }
10596
- hoveredNavContainerRef.current = null;
10597
- setHoveredNavContainerRect(null);
10598
- } else {
10599
- hoveredNavContainerRef.current = null;
10600
- setHoveredNavContainerRect(null);
10601
11141
  }
11142
+ if (allowFooterLinksHover) {
11143
+ const footerLinks = getFooterLinksContainer();
11144
+ if (footerLinks) {
11145
+ const containerRect = footerLinks.getBoundingClientRect();
11146
+ const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
11147
+ if (overContainer && !isPointOverNavItem(footerLinks, x, y) && !isPointOverFooterColumn(x, y)) {
11148
+ hoveredNavContainerRef.current = footerLinks;
11149
+ setHoveredNavContainerRect(footerLinks.getBoundingClientRect());
11150
+ hoveredItemElRef.current = null;
11151
+ setHoveredItemRect(null);
11152
+ return;
11153
+ }
11154
+ }
11155
+ }
11156
+ hoveredNavContainerRef.current = null;
11157
+ setHoveredNavContainerRect(null);
10602
11158
  for (const column of footerColumns) {
10603
11159
  const containerRect = column.getBoundingClientRect();
10604
11160
  const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
@@ -10860,6 +11416,7 @@ function OhhwellsBridge() {
10860
11416
  const ZONE = 20;
10861
11417
  for (let i = 0; i < sections.length; i++) {
10862
11418
  const a = sections[i];
11419
+ if (a.dataset.ohwSection === "footer") continue;
10863
11420
  const b = sections[i + 1] ?? null;
10864
11421
  const boundaryY = a.getBoundingClientRect().bottom;
10865
11422
  if (Math.abs(y - boundaryY) <= ZONE) {
@@ -11081,6 +11638,7 @@ function OhhwellsBridge() {
11081
11638
  continue;
11082
11639
  }
11083
11640
  if (applyVideoSettingNode(key, val)) continue;
11641
+ if (applyCarouselNode(key, val)) continue;
11084
11642
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
11085
11643
  if (el.dataset.ohwEditable === "image") {
11086
11644
  const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
@@ -11105,6 +11663,7 @@ function OhhwellsBridge() {
11105
11663
  }
11106
11664
  editContentRef.current = { ...editContentRef.current, ...content };
11107
11665
  reconcileNavbarItemsFromContent(editContentRef.current);
11666
+ reconcileFooterOrderFromContent(editContentRef.current);
11108
11667
  syncNavigationDragCursorAttrs();
11109
11668
  enforceLinkHrefs();
11110
11669
  postToParentRef.current({ type: "ow:hydrate-done" });
@@ -11159,6 +11718,11 @@ function OhhwellsBridge() {
11159
11718
  }
11160
11719
  if (selectedElRef.current) {
11161
11720
  if (toolbarVariantRef.current === "select-frame") {
11721
+ const parent2 = getNavigationSelectionParent(selectedElRef.current);
11722
+ if (parent2 && isNavigationContainer(parent2) && isFooterLinksContainer(parent2) && !isFooterLinksContainer(selectedElRef.current)) {
11723
+ selectFrameRef.current(parent2);
11724
+ return;
11725
+ }
11162
11726
  deselectRef.current();
11163
11727
  return;
11164
11728
  }
@@ -11174,13 +11738,10 @@ function OhhwellsBridge() {
11174
11738
  const handleKeyDown = (e) => {
11175
11739
  if (e.key === "Escape" && document.querySelector("[data-ohw-section-picker]")) return;
11176
11740
  if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a" && activeElRef.current) {
11177
- const navAnchor = getNavigationItemAnchor(activeElRef.current);
11178
- if (navAnchor) {
11179
- e.preventDefault();
11180
- selectAllTextInEditable(activeElRef.current);
11181
- refreshActiveCommandsRef.current();
11182
- return;
11183
- }
11741
+ e.preventDefault();
11742
+ selectAllTextInEditable(activeElRef.current);
11743
+ refreshActiveCommandsRef.current();
11744
+ return;
11184
11745
  }
11185
11746
  if (e.key === "Escape" && linkPopoverOpenRef.current) {
11186
11747
  setLinkPopoverRef.current(null);
@@ -11188,6 +11749,12 @@ function OhhwellsBridge() {
11188
11749
  }
11189
11750
  if (e.key === "Escape" && selectedElRef.current && !activeElRef.current) {
11190
11751
  if (toolbarVariantRef.current === "select-frame") {
11752
+ const parent2 = getNavigationSelectionParent(selectedElRef.current);
11753
+ if (parent2 && isNavigationContainer(parent2) && isFooterLinksContainer(parent2) && !isFooterLinksContainer(selectedElRef.current)) {
11754
+ e.preventDefault();
11755
+ selectFrameRef.current(parent2);
11756
+ return;
11757
+ }
11191
11758
  deselectRef.current();
11192
11759
  return;
11193
11760
  }
@@ -11377,6 +11944,7 @@ function OhhwellsBridge() {
11377
11944
  const handleDocMouseLeave = () => {
11378
11945
  hoveredImageRef.current = null;
11379
11946
  setMediaHover(null);
11947
+ setCarouselHover(null);
11380
11948
  document.querySelectorAll("[data-ohw-state-hovered]").forEach((el) => el.removeAttribute("data-ohw-state-hovered"));
11381
11949
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
11382
11950
  activeStateElRef.current = null;
@@ -11416,6 +11984,48 @@ function OhhwellsBridge() {
11416
11984
  if (e.data?.type !== "ow:canvas-height" || typeof e.data.height !== "number") return;
11417
11985
  document.documentElement.style.setProperty("--ohw-canvas-h", `${e.data.height}px`);
11418
11986
  };
11987
+ const handleCarouselChange = (e) => {
11988
+ if (e.data?.type !== "ow:carousel-change") return;
11989
+ const { key, images } = e.data;
11990
+ if (!key || !Array.isArray(images)) return;
11991
+ const text = JSON.stringify(images);
11992
+ applyCarouselValue(key, images);
11993
+ editContentRef.current = { ...editContentRef.current, [key]: text };
11994
+ postToParentRef.current({ type: "ow:change", nodes: [{ key, text }] });
11995
+ setCarouselHover(null);
11996
+ };
11997
+ const findCarouselAtPoint = (clientX, clientY) => {
11998
+ const containers = Array.from(document.querySelectorAll(`[${CAROUSEL_ATTR}]`));
11999
+ for (let i = containers.length - 1; i >= 0; i--) {
12000
+ const r2 = containers[i].getBoundingClientRect();
12001
+ if (clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom) {
12002
+ return containers[i];
12003
+ }
12004
+ }
12005
+ return null;
12006
+ };
12007
+ const isPointOverEditable = (scope, clientX, clientY) => {
12008
+ const editables = scope.querySelectorAll("[data-ohw-editable], [data-ohw-href-key]");
12009
+ for (const el of editables) {
12010
+ const r2 = el.getBoundingClientRect();
12011
+ if (clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom) return true;
12012
+ }
12013
+ return false;
12014
+ };
12015
+ const handleCarouselHover = (e) => {
12016
+ const container = findCarouselAtPoint(e.clientX, e.clientY);
12017
+ const scope = container?.closest("[data-ohw-section]") ?? container?.parentElement ?? null;
12018
+ if (!container || !scope || isPointOverEditable(scope, e.clientX, e.clientY)) {
12019
+ setCarouselHover((prev) => prev ? null : prev);
12020
+ return;
12021
+ }
12022
+ const key = container.getAttribute("data-ohw-key") ?? "";
12023
+ if (!key) return;
12024
+ const r2 = getVisibleRect(container);
12025
+ setCarouselHover(
12026
+ (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 } }
12027
+ );
12028
+ };
11419
12029
  const applyToolbarPos = (rect) => {
11420
12030
  const ps = parentScrollRef.current;
11421
12031
  const measuredW = toolbarElRef.current?.offsetWidth || 330;
@@ -11529,6 +12139,7 @@ function OhhwellsBridge() {
11529
12139
  window.addEventListener("message", handleRemoveSchedulingSection);
11530
12140
  window.addEventListener("message", handleImageUrl);
11531
12141
  window.addEventListener("message", handleImageUploading);
12142
+ window.addEventListener("message", handleCarouselChange);
11532
12143
  window.addEventListener("message", handleCanvasHeight);
11533
12144
  window.addEventListener("message", handleParentScroll);
11534
12145
  window.addEventListener("message", handlePointerSync);
@@ -11546,6 +12157,7 @@ function OhhwellsBridge() {
11546
12157
  document.addEventListener("mouseover", handleMouseOver, true);
11547
12158
  document.addEventListener("mouseout", handleMouseOut, true);
11548
12159
  document.addEventListener("mousemove", handleMouseMove, true);
12160
+ document.addEventListener("mousemove", handleCarouselHover, true);
11549
12161
  document.addEventListener("mouseleave", handleDocMouseLeave);
11550
12162
  document.addEventListener("dragover", handleDragOver, true);
11551
12163
  document.addEventListener("dragleave", handleDragLeave, true);
@@ -11561,6 +12173,7 @@ function OhhwellsBridge() {
11561
12173
  document.removeEventListener("mouseover", handleMouseOver, true);
11562
12174
  document.removeEventListener("mouseout", handleMouseOut, true);
11563
12175
  document.removeEventListener("mousemove", handleMouseMove, true);
12176
+ document.removeEventListener("mousemove", handleCarouselHover, true);
11564
12177
  document.removeEventListener("mouseleave", handleDocMouseLeave);
11565
12178
  document.removeEventListener("dragover", handleDragOver, true);
11566
12179
  document.removeEventListener("dragleave", handleDragLeave, true);
@@ -11576,6 +12189,7 @@ function OhhwellsBridge() {
11576
12189
  window.removeEventListener("message", handleRemoveSchedulingSection);
11577
12190
  window.removeEventListener("message", handleImageUrl);
11578
12191
  window.removeEventListener("message", handleImageUploading);
12192
+ window.removeEventListener("message", handleCarouselChange);
11579
12193
  window.removeEventListener("message", handleCanvasHeight);
11580
12194
  window.removeEventListener("message", handleParentScroll);
11581
12195
  window.removeEventListener("resize", handleViewportResize);
@@ -11590,7 +12204,7 @@ function OhhwellsBridge() {
11590
12204
  if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
11591
12205
  };
11592
12206
  }, [isEditMode, refreshStateRules]);
11593
- useEffect8(() => {
12207
+ useEffect9(() => {
11594
12208
  if (!isEditMode) return;
11595
12209
  const THRESHOLD = 10;
11596
12210
  const resolveWasSelected = (el) => {
@@ -11744,7 +12358,7 @@ function OhhwellsBridge() {
11744
12358
  unlockFooterDragInteraction();
11745
12359
  };
11746
12360
  }, [isEditMode]);
11747
- useEffect8(() => {
12361
+ useEffect9(() => {
11748
12362
  const handler = (e) => {
11749
12363
  if (e.data?.type !== "ow:request-schedule-config") return;
11750
12364
  const insertAfterVal = e.data.insertAfter;
@@ -11760,7 +12374,7 @@ function OhhwellsBridge() {
11760
12374
  window.addEventListener("message", handler);
11761
12375
  return () => window.removeEventListener("message", handler);
11762
12376
  }, [processConfigRequest]);
11763
- useEffect8(() => {
12377
+ useEffect9(() => {
11764
12378
  if (!isEditMode) return;
11765
12379
  document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
11766
12380
  el.removeAttribute("data-ohw-active-state");
@@ -11795,13 +12409,13 @@ function OhhwellsBridge() {
11795
12409
  clearTimeout(timer);
11796
12410
  };
11797
12411
  }, [pathname, isEditMode, refreshStateRules, postToParent2]);
11798
- useEffect8(() => {
12412
+ useEffect9(() => {
11799
12413
  scrollToHashSectionWhenReady();
11800
12414
  const onHashChange = () => scrollToHashSectionWhenReady();
11801
12415
  window.addEventListener("hashchange", onHashChange);
11802
12416
  return () => window.removeEventListener("hashchange", onHashChange);
11803
12417
  }, [pathname]);
11804
- const handleCommand = useCallback4((cmd) => {
12418
+ const handleCommand = useCallback5((cmd) => {
11805
12419
  const el = activeElRef.current;
11806
12420
  const selBefore = window.getSelection();
11807
12421
  let savedOffsets = null;
@@ -11837,7 +12451,7 @@ function OhhwellsBridge() {
11837
12451
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
11838
12452
  refreshActiveCommandsRef.current();
11839
12453
  }, []);
11840
- const handleStateChange = useCallback4((state) => {
12454
+ const handleStateChange = useCallback5((state) => {
11841
12455
  if (!activeStateElRef.current) return;
11842
12456
  const el = activeStateElRef.current;
11843
12457
  if (state === "Default") {
@@ -11850,11 +12464,11 @@ function OhhwellsBridge() {
11850
12464
  }
11851
12465
  setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
11852
12466
  }, [deactivate]);
11853
- const closeLinkPopover = useCallback4(() => {
12467
+ const closeLinkPopover = useCallback5(() => {
11854
12468
  addNavAfterAnchorRef.current = null;
11855
12469
  setLinkPopover(null);
11856
12470
  }, []);
11857
- const openLinkPopoverForActive = useCallback4(() => {
12471
+ const openLinkPopoverForActive = useCallback5(() => {
11858
12472
  const hrefCtx = getHrefKeyFromElement(activeElRef.current);
11859
12473
  if (!hrefCtx) return;
11860
12474
  bumpLinkPopoverGrace();
@@ -11865,7 +12479,7 @@ function OhhwellsBridge() {
11865
12479
  });
11866
12480
  deactivate();
11867
12481
  }, [deactivate]);
11868
- const openLinkPopoverForSelected = useCallback4(() => {
12482
+ const openLinkPopoverForSelected = useCallback5(() => {
11869
12483
  const anchor = selectedElRef.current;
11870
12484
  if (!anchor) return;
11871
12485
  const key = anchor.getAttribute("data-ohw-href-key");
@@ -11878,7 +12492,7 @@ function OhhwellsBridge() {
11878
12492
  });
11879
12493
  deselect();
11880
12494
  }, [deselect]);
11881
- const handleLinkPopoverSubmit = useCallback4(
12495
+ const handleLinkPopoverSubmit = useCallback5(
11882
12496
  (target) => {
11883
12497
  const session = linkPopoverSessionRef.current;
11884
12498
  if (!session) return;
@@ -11937,13 +12551,19 @@ function OhhwellsBridge() {
11937
12551
  const showEditLink = toolbarShowEditLink;
11938
12552
  const currentSections = sectionsByPath[pathname] ?? [];
11939
12553
  linkPopoverOpenRef.current = linkPopover !== null;
11940
- const handleMediaReplace = useCallback4(
12554
+ const handleMediaReplace = useCallback5(
11941
12555
  (key) => {
11942
12556
  postToParent2({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
11943
12557
  },
11944
12558
  [postToParent2, mediaHover?.elementType]
11945
12559
  );
11946
- const handleMediaFadeOutComplete = useCallback4((key) => {
12560
+ const handleEditCarousel = useCallback5(
12561
+ (key) => {
12562
+ postToParent2({ type: "ow:carousel-open", key, images: readCarouselValue(key) });
12563
+ },
12564
+ [postToParent2]
12565
+ );
12566
+ const handleMediaFadeOutComplete = useCallback5((key) => {
11947
12567
  setUploadingRects((prev) => {
11948
12568
  if (!(key in prev)) return prev;
11949
12569
  const next = { ...prev };
@@ -11951,7 +12571,7 @@ function OhhwellsBridge() {
11951
12571
  return next;
11952
12572
  });
11953
12573
  }, []);
11954
- const handleVideoSettingsChange = useCallback4(
12574
+ const handleVideoSettingsChange = useCallback5(
11955
12575
  (key, settings) => {
11956
12576
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
11957
12577
  const video = getVideoEl(el);
@@ -11974,9 +12594,9 @@ function OhhwellsBridge() {
11974
12594
  [postToParent2]
11975
12595
  );
11976
12596
  return bridgeRoot ? createPortal2(
11977
- /* @__PURE__ */ jsxs13(Fragment5, { children: [
11978
- /* @__PURE__ */ jsx24("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
11979
- Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ jsx24(
12597
+ /* @__PURE__ */ jsxs15(Fragment5, { children: [
12598
+ /* @__PURE__ */ jsx26("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
12599
+ Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ jsx26(
11980
12600
  MediaOverlay,
11981
12601
  {
11982
12602
  hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
@@ -11987,7 +12607,7 @@ function OhhwellsBridge() {
11987
12607
  },
11988
12608
  `uploading-${key}`
11989
12609
  )),
11990
- mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ jsx24(
12610
+ mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ jsx26(
11991
12611
  MediaOverlay,
11992
12612
  {
11993
12613
  hover: mediaHover,
@@ -11996,10 +12616,11 @@ function OhhwellsBridge() {
11996
12616
  onVideoSettingsChange: handleVideoSettingsChange
11997
12617
  }
11998
12618
  ),
11999
- siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ jsx24(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
12000
- siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ jsx24(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
12001
- isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ jsx24(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
12002
- isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ jsx24(
12619
+ carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx26(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
12620
+ siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ jsx26(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
12621
+ siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ jsx26(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
12622
+ isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ jsx26(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
12623
+ isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ jsx26(
12003
12624
  "div",
12004
12625
  {
12005
12626
  className: "pointer-events-none fixed z-2147483646",
@@ -12009,7 +12630,7 @@ function OhhwellsBridge() {
12009
12630
  width: slot.width,
12010
12631
  height: slot.height
12011
12632
  },
12012
- children: /* @__PURE__ */ jsx24(
12633
+ children: /* @__PURE__ */ jsx26(
12013
12634
  DropIndicator,
12014
12635
  {
12015
12636
  direction: slot.direction,
@@ -12020,7 +12641,7 @@ function OhhwellsBridge() {
12020
12641
  },
12021
12642
  `footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
12022
12643
  )),
12023
- isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ jsx24(
12644
+ isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ jsx26(
12024
12645
  "div",
12025
12646
  {
12026
12647
  className: "pointer-events-none fixed z-2147483646",
@@ -12030,7 +12651,7 @@ function OhhwellsBridge() {
12030
12651
  width: slot.width,
12031
12652
  height: slot.height
12032
12653
  },
12033
- children: /* @__PURE__ */ jsx24(
12654
+ children: /* @__PURE__ */ jsx26(
12034
12655
  DropIndicator,
12035
12656
  {
12036
12657
  direction: slot.direction,
@@ -12041,10 +12662,11 @@ function OhhwellsBridge() {
12041
12662
  },
12042
12663
  `nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
12043
12664
  )),
12044
- hoveredNavContainerRect && toolbarVariant !== "select-frame" && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx24(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
12045
- hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx24(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
12046
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer(selectedElRef.current) && /* @__PURE__ */ jsx24(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
12047
- toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ jsx24(
12665
+ hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx26(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
12666
+ hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx26(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
12667
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer(selectedElRef.current) && /* @__PURE__ */ jsx26(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
12668
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ jsx26(FooterContainerChrome, { rect: toolbarRect, onAdd: handleAddFooterColumn }),
12669
+ toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ jsx26(
12048
12670
  ItemInteractionLayer,
12049
12671
  {
12050
12672
  rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
@@ -12058,7 +12680,7 @@ function OhhwellsBridge() {
12058
12680
  onItemPointerDown: handleItemChromePointerDown,
12059
12681
  onItemClick: handleItemChromeClick,
12060
12682
  itemDragSurface: !isFooterFrameSelection,
12061
- toolbar: toolbarVariant === "link-action" && !isItemDragging ? /* @__PURE__ */ jsx24(
12683
+ toolbar: toolbarVariant === "link-action" && !isItemDragging ? /* @__PURE__ */ jsx26(
12062
12684
  ItemActionToolbar,
12063
12685
  {
12064
12686
  onEditLink: openLinkPopoverForSelected,
@@ -12071,8 +12693,8 @@ function OhhwellsBridge() {
12071
12693
  ) : void 0
12072
12694
  }
12073
12695
  ),
12074
- toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ jsxs13(Fragment5, { children: [
12075
- /* @__PURE__ */ jsx24(
12696
+ toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ jsxs15(Fragment5, { children: [
12697
+ /* @__PURE__ */ jsx26(
12076
12698
  EditGlowChrome,
12077
12699
  {
12078
12700
  rect: toolbarRect,
@@ -12082,7 +12704,7 @@ function OhhwellsBridge() {
12082
12704
  hideHandle: isItemDragging
12083
12705
  }
12084
12706
  ),
12085
- /* @__PURE__ */ jsx24(
12707
+ /* @__PURE__ */ jsx26(
12086
12708
  FloatingToolbar,
12087
12709
  {
12088
12710
  rect: toolbarRect,
@@ -12095,7 +12717,7 @@ function OhhwellsBridge() {
12095
12717
  }
12096
12718
  )
12097
12719
  ] }),
12098
- maxBadge && /* @__PURE__ */ jsxs13(
12720
+ maxBadge && /* @__PURE__ */ jsxs15(
12099
12721
  "div",
12100
12722
  {
12101
12723
  "data-ohw-max-badge": "",
@@ -12121,7 +12743,7 @@ function OhhwellsBridge() {
12121
12743
  ]
12122
12744
  }
12123
12745
  ),
12124
- toggleState && !linkPopover && /* @__PURE__ */ jsx24(
12746
+ toggleState && !linkPopover && /* @__PURE__ */ jsx26(
12125
12747
  StateToggle,
12126
12748
  {
12127
12749
  rect: toggleState.rect,
@@ -12130,15 +12752,15 @@ function OhhwellsBridge() {
12130
12752
  onStateChange: handleStateChange
12131
12753
  }
12132
12754
  ),
12133
- sectionGap && !linkPopover && /* @__PURE__ */ jsxs13(
12755
+ sectionGap && !linkPopover && /* @__PURE__ */ jsxs15(
12134
12756
  "div",
12135
12757
  {
12136
12758
  "data-ohw-section-insert-line": "",
12137
12759
  className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
12138
12760
  style: { top: sectionGap.y, transform: "translateY(-50%)" },
12139
12761
  children: [
12140
- /* @__PURE__ */ jsx24("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
12141
- /* @__PURE__ */ jsx24(
12762
+ /* @__PURE__ */ jsx26("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
12763
+ /* @__PURE__ */ jsx26(
12142
12764
  Badge,
12143
12765
  {
12144
12766
  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",
@@ -12155,11 +12777,11 @@ function OhhwellsBridge() {
12155
12777
  children: "Add Section"
12156
12778
  }
12157
12779
  ),
12158
- /* @__PURE__ */ jsx24("div", { className: "flex-1 bg-primary", style: { height: 3 } })
12780
+ /* @__PURE__ */ jsx26("div", { className: "flex-1 bg-primary", style: { height: 3 } })
12159
12781
  ]
12160
12782
  }
12161
12783
  ),
12162
- linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx24(
12784
+ linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx26(
12163
12785
  LinkPopover,
12164
12786
  {
12165
12787
  panelRef: linkPopoverPanelRef,
@@ -12207,6 +12829,7 @@ export {
12207
12829
  isValidUrl,
12208
12830
  parseTarget,
12209
12831
  toggleVariants,
12832
+ useOhwCarousel,
12210
12833
  validateUrlInput
12211
12834
  };
12212
12835
  //# sourceMappingURL=index.js.map