@ohhwells/bridge 0.1.46 → 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,
@@ -6600,6 +6715,8 @@ function applyNavOrderToContainer(container, order) {
6600
6715
  if (current.length === expected.length && current.every((key, i) => key === expected[i])) {
6601
6716
  return;
6602
6717
  }
6718
+ const lastCurrentLinkEl = current.length > 0 ? findCounterpartByHrefKey(current[current.length - 1], container) : null;
6719
+ const anchor = lastCurrentLinkEl?.parentElement === container ? lastCurrentLinkEl.nextElementSibling : null;
6603
6720
  const seen = /* @__PURE__ */ new Set();
6604
6721
  for (const hrefKey of desired) {
6605
6722
  if (seen.has(hrefKey)) continue;
@@ -6614,7 +6731,9 @@ function applyNavOrderToContainer(container, order) {
6614
6731
  orderedEls.push(el);
6615
6732
  }
6616
6733
  for (const el of orderedEls) {
6617
- if (container.lastElementChild !== el) {
6734
+ if (anchor) {
6735
+ if (el.nextSibling !== anchor) container.insertBefore(el, anchor);
6736
+ } else if (container.lastElementChild !== el) {
6618
6737
  container.appendChild(el);
6619
6738
  }
6620
6739
  }
@@ -6946,7 +7065,195 @@ function parseFooterOrder(content) {
6946
7065
  return null;
6947
7066
  }
6948
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
+ }
6949
7255
  function reconcileFooterOrderFromContent(content) {
7256
+ reconcileFooterColumnsFromContent(content);
6950
7257
  const order = parseFooterOrder(content);
6951
7258
  if (!order?.length) return;
6952
7259
  const current = getFooterOrderFromDom();
@@ -6956,6 +7263,31 @@ function reconcileFooterOrderFromContent(content) {
6956
7263
  }
6957
7264
  applyFooterOrder(order);
6958
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
+ }
7286
+ function isRowLayoutColumn(links) {
7287
+ if (links.length < 2) return false;
7288
+ const firstTop = links[0].getBoundingClientRect().top;
7289
+ return links.every((link) => Math.abs(link.getBoundingClientRect().top - firstTop) < 4);
7290
+ }
6959
7291
  function buildLinkDropSlots(column, columnIndex) {
6960
7292
  const links = listFooterLinksInColumn(column);
6961
7293
  const colRect = column.getBoundingClientRect();
@@ -6973,6 +7305,32 @@ function buildLinkDropSlots(column, columnIndex) {
6973
7305
  });
6974
7306
  return slots;
6975
7307
  }
7308
+ if (isRowLayoutColumn(links)) {
7309
+ for (let i = 0; i <= links.length; i++) {
7310
+ let left;
7311
+ if (i === 0) {
7312
+ left = links[0].getBoundingClientRect().left - barThickness / 2;
7313
+ } else if (i === links.length) {
7314
+ const last = links[links.length - 1].getBoundingClientRect();
7315
+ left = last.right - barThickness / 2;
7316
+ } else {
7317
+ const prev = links[i - 1].getBoundingClientRect();
7318
+ const next = links[i].getBoundingClientRect();
7319
+ left = (prev.right + next.left) / 2 - barThickness / 2;
7320
+ }
7321
+ const heightRef = i === 0 ? links[0].getBoundingClientRect() : i === links.length ? links[links.length - 1].getBoundingClientRect() : links[i].getBoundingClientRect();
7322
+ slots.push({
7323
+ insertIndex: i,
7324
+ columnIndex,
7325
+ left,
7326
+ top: heightRef.top,
7327
+ width: barThickness,
7328
+ height: Math.max(heightRef.height, colRect.height * 0.8),
7329
+ direction: "vertical"
7330
+ });
7331
+ }
7332
+ return slots;
7333
+ }
6976
7334
  for (let i = 0; i <= links.length; i++) {
6977
7335
  let top;
6978
7336
  if (i === 0) {
@@ -7056,8 +7414,7 @@ function hitTestLinkDropSlot(clientX, clientY, draggedHrefKey) {
7056
7414
  return true;
7057
7415
  });
7058
7416
  for (const slot of slots) {
7059
- const cy = slot.top + slot.height / 2;
7060
- const dist = Math.abs(clientY - cy) + (inColX ? 0 : 1e3);
7417
+ const dist = slot.direction === "vertical" ? Math.abs(clientX - (slot.left + slot.width / 2)) : Math.abs(clientY - (slot.top + slot.height / 2));
7061
7418
  if (!best || dist < best.dist) best = { slot, dist };
7062
7419
  }
7063
7420
  }
@@ -7081,6 +7438,30 @@ function hitTestColumnDropSlot(clientX, _clientY) {
7081
7438
  return best?.slot ?? null;
7082
7439
  }
7083
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
+
7084
7465
  // src/lib/item-drag-interaction.ts
7085
7466
  function disableNativeHrefDrag(el) {
7086
7467
  if (el.draggable) el.draggable = false;
@@ -7101,9 +7482,10 @@ function lockItemDuringDrag() {
7101
7482
  clearTextSelection();
7102
7483
  }
7103
7484
  function unlockItemDragInteraction() {
7485
+ const wasDragging = document.documentElement.hasAttribute("data-ohw-item-dragging");
7104
7486
  document.documentElement.removeAttribute("data-ohw-footer-press-drag");
7105
7487
  document.documentElement.removeAttribute("data-ohw-item-dragging");
7106
- clearTextSelection();
7488
+ if (wasDragging) clearTextSelection();
7107
7489
  }
7108
7490
  var armFooterPressDrag = armItemPressDrag;
7109
7491
  var lockFooterDuringDrag = lockItemDuringDrag;
@@ -7277,7 +7659,7 @@ function hitTestNavDropSlot(clientX, clientY, draggedHrefKey) {
7277
7659
  }
7278
7660
 
7279
7661
  // src/useNavItemDrag.ts
7280
- 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";
7281
7663
  function useNavItemDrag({
7282
7664
  isEditMode,
7283
7665
  editContentRef,
@@ -7306,7 +7688,7 @@ function useNavItemDrag({
7306
7688
  const [navDropSlots, setNavDropSlots] = useState6([]);
7307
7689
  const [activeNavDropIndex, setActiveNavDropIndex] = useState6(null);
7308
7690
  const navPointerDragRef = useRef6(null);
7309
- const clearNavDragVisuals = useCallback3(() => {
7691
+ const clearNavDragVisuals = useCallback4(() => {
7310
7692
  navDragRef.current = null;
7311
7693
  setNavDropSlots([]);
7312
7694
  setActiveNavDropIndex(null);
@@ -7315,7 +7697,7 @@ function useNavItemDrag({
7315
7697
  setIsItemDragging(false);
7316
7698
  unlockItemDragInteraction();
7317
7699
  }, [setDraggedItemRect, setIsItemDragging, setSiblingHintRects]);
7318
- const refreshNavDragVisuals = useCallback3(
7700
+ const refreshNavDragVisuals = useCallback4(
7319
7701
  (session, activeSlot, clientX, clientY) => {
7320
7702
  setDraggedItemRect(session.draggedEl.getBoundingClientRect());
7321
7703
  if (typeof clientX === "number" && typeof clientY === "number") {
@@ -7339,7 +7721,7 @@ function useNavItemDrag({
7339
7721
  });
7340
7722
  const beginNavDragRef = useRef6(() => {
7341
7723
  });
7342
- const beginNavDrag = useCallback3(
7724
+ const beginNavDrag = useCallback4(
7343
7725
  (session) => {
7344
7726
  const rect = session.draggedEl.getBoundingClientRect();
7345
7727
  session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
@@ -7366,7 +7748,7 @@ function useNavItemDrag({
7366
7748
  ]
7367
7749
  );
7368
7750
  beginNavDragRef.current = beginNavDrag;
7369
- const commitNavDrag = useCallback3(
7751
+ const commitNavDrag = useCallback4(
7370
7752
  (clientX, clientY) => {
7371
7753
  const session = navDragRef.current;
7372
7754
  if (!session) {
@@ -7427,7 +7809,7 @@ function useNavItemDrag({
7427
7809
  [clearNavDragVisuals, deselectRef, editContentRef, postToParentRef, selectRef]
7428
7810
  );
7429
7811
  commitNavDragRef.current = commitNavDrag;
7430
- const startNavLinkDrag = useCallback3(
7812
+ const startNavLinkDrag = useCallback4(
7431
7813
  (anchor, clientX, clientY, wasSelected) => {
7432
7814
  if (footerDragRef.current) return false;
7433
7815
  const hrefKey = anchor.getAttribute("data-ohw-href-key");
@@ -7445,7 +7827,7 @@ function useNavItemDrag({
7445
7827
  },
7446
7828
  [beginNavDrag, footerDragRef, isDragHandleDisabled2, isNavbarButton3]
7447
7829
  );
7448
- const onNavDragOver = useCallback3(
7830
+ const onNavDragOver = useCallback4(
7449
7831
  (e) => {
7450
7832
  const session = navDragRef.current;
7451
7833
  if (!session) return false;
@@ -7480,7 +7862,6 @@ function useNavItemDrag({
7480
7862
  const hrefKey = anchor?.getAttribute("data-ohw-href-key") ?? null;
7481
7863
  if (!anchor || !isNavbarHrefKey(hrefKey)) return;
7482
7864
  if (isNavbarButton3(anchor) || isDragHandleDisabled2(anchor)) return;
7483
- armItemPressDrag();
7484
7865
  navPointerDragRef.current = {
7485
7866
  el: anchor,
7486
7867
  startX: e.clientX,
@@ -7507,6 +7888,7 @@ function useNavItemDrag({
7507
7888
  if (dx * dx + dy * dy < THRESHOLD * THRESHOLD) return;
7508
7889
  e.preventDefault();
7509
7890
  pending.started = true;
7891
+ armItemPressDrag();
7510
7892
  clearTextSelection();
7511
7893
  try {
7512
7894
  document.body.setPointerCapture(pending.pointerId);
@@ -7534,7 +7916,8 @@ function useNavItemDrag({
7534
7916
  }
7535
7917
  } catch {
7536
7918
  }
7537
- if (!pending?.started) {
7919
+ if (!pending) return;
7920
+ if (!pending.started) {
7538
7921
  unlockItemDragInteraction();
7539
7922
  return;
7540
7923
  }
@@ -7581,12 +7964,11 @@ function useNavItemDrag({
7581
7964
  setLinkPopover,
7582
7965
  suppressNextClickRef
7583
7966
  ]);
7584
- const armNavPressFromChrome = useCallback3(
7967
+ const armNavPressFromChrome = useCallback4(
7585
7968
  (selected, clientX, clientY, pointerId) => {
7586
7969
  const hrefKey = selected.getAttribute("data-ohw-href-key");
7587
7970
  if (!hrefKey || !isNavbarHrefKey(hrefKey)) return false;
7588
7971
  if (isNavbarButton3(selected) || isDragHandleDisabled2(selected)) return false;
7589
- armItemPressDrag();
7590
7972
  navPointerDragRef.current = {
7591
7973
  el: selected,
7592
7974
  startX: clientX,
@@ -7612,15 +7994,144 @@ function useNavItemDrag({
7612
7994
  };
7613
7995
  }
7614
7996
 
7615
- // src/ui/navbar-container-chrome.tsx
7997
+ // src/ui/footer-container-chrome.tsx
7616
7998
  import { Plus as Plus2 } from "lucide-react";
7617
- 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";
7618
8129
  function NavbarContainerChrome({
7619
8130
  rect,
7620
8131
  onAdd
7621
8132
  }) {
7622
8133
  const chromeGap = 6;
7623
- return /* @__PURE__ */ jsx21(
8134
+ return /* @__PURE__ */ jsx23(
7624
8135
  "div",
7625
8136
  {
7626
8137
  "data-ohw-navbar-container-chrome": "",
@@ -7632,7 +8143,7 @@ function NavbarContainerChrome({
7632
8143
  width: rect.width + chromeGap * 2,
7633
8144
  height: rect.height + chromeGap * 2
7634
8145
  },
7635
- children: /* @__PURE__ */ jsx21(
8146
+ children: /* @__PURE__ */ jsx23(
7636
8147
  "button",
7637
8148
  {
7638
8149
  type: "button",
@@ -7649,7 +8160,7 @@ function NavbarContainerChrome({
7649
8160
  e.stopPropagation();
7650
8161
  onAdd();
7651
8162
  },
7652
- 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 })
7653
8164
  }
7654
8165
  )
7655
8166
  }
@@ -7658,7 +8169,7 @@ function NavbarContainerChrome({
7658
8169
 
7659
8170
  // src/ui/drop-indicator.tsx
7660
8171
  import * as React10 from "react";
7661
- import { jsx as jsx22 } from "react/jsx-runtime";
8172
+ import { jsx as jsx24 } from "react/jsx-runtime";
7662
8173
  var dropIndicatorVariants = cva(
7663
8174
  "ov-gap-line pointer-events-none shrink-0 transition-opacity duration-150",
7664
8175
  {
@@ -7682,7 +8193,7 @@ var dropIndicatorVariants = cva(
7682
8193
  );
7683
8194
  var DropIndicator = React10.forwardRef(
7684
8195
  ({ className, direction, state, ...props }, ref) => {
7685
- return /* @__PURE__ */ jsx22(
8196
+ return /* @__PURE__ */ jsx24(
7686
8197
  "div",
7687
8198
  {
7688
8199
  ref,
@@ -7699,7 +8210,7 @@ var DropIndicator = React10.forwardRef(
7699
8210
  DropIndicator.displayName = "DropIndicator";
7700
8211
 
7701
8212
  // src/ui/badge.tsx
7702
- import { jsx as jsx23 } from "react/jsx-runtime";
8213
+ import { jsx as jsx25 } from "react/jsx-runtime";
7703
8214
  var badgeVariants = cva(
7704
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",
7705
8216
  {
@@ -7717,12 +8228,12 @@ var badgeVariants = cva(
7717
8228
  }
7718
8229
  );
7719
8230
  function Badge({ className, variant, ...props }) {
7720
- return /* @__PURE__ */ jsx23("div", { className: cn(badgeVariants({ variant }), className), ...props });
8231
+ return /* @__PURE__ */ jsx25("div", { className: cn(badgeVariants({ variant }), className), ...props });
7721
8232
  }
7722
8233
 
7723
8234
  // src/OhhwellsBridge.tsx
7724
8235
  import { Link as Link2 } from "lucide-react";
7725
- 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";
7726
8237
  var PRIMARY2 = "#0885FE";
7727
8238
  var IMAGE_FADE_MS = 300;
7728
8239
  function runOpacityFade(el, onDone) {
@@ -7901,7 +8412,7 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
7901
8412
  const root = createRoot(container);
7902
8413
  flushSync(() => {
7903
8414
  root.render(
7904
- /* @__PURE__ */ jsx24(
8415
+ /* @__PURE__ */ jsx26(
7905
8416
  SchedulingWidget,
7906
8417
  {
7907
8418
  notifyOnConnect,
@@ -8019,6 +8530,9 @@ function collectEditableNodes(extraContent) {
8019
8530
  nodes.push({ key: `${key}${VIDEO_AUTOPLAY_SUFFIX}`, type: "video-setting", text: String(video.autoplay) });
8020
8531
  nodes.push({ key: `${key}${VIDEO_MUTED_SUFFIX}`, type: "video-setting", text: String(video.muted) });
8021
8532
  });
8533
+ for (const key of listCarouselKeys()) {
8534
+ nodes.push({ key, type: "carousel", text: JSON.stringify(readCarouselValue(key)) });
8535
+ }
8022
8536
  const seen = /* @__PURE__ */ new Set();
8023
8537
  return nodes.filter((node) => {
8024
8538
  if (!node.key) return true;
@@ -8102,7 +8616,7 @@ function applyLinkByKey(key, val) {
8102
8616
  }
8103
8617
  function isInsideLinkEditor(target) {
8104
8618
  return Boolean(
8105
- 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"]')
8106
8620
  );
8107
8621
  }
8108
8622
  function getHrefKeyFromElement(el) {
@@ -8183,7 +8697,7 @@ function isInferredFooterGroup(el) {
8183
8697
  return countFooterNavItems(el) >= 2;
8184
8698
  }
8185
8699
  function isNavigationContainer(el) {
8186
- 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);
8187
8701
  }
8188
8702
  function isNavbarLinksContainer(el) {
8189
8703
  return el.hasAttribute("data-ohw-nav-container");
@@ -8202,6 +8716,9 @@ function isPointOverNavigation(x, y) {
8202
8716
  const roots = /* @__PURE__ */ new Set();
8203
8717
  const navRoot = document.querySelector("[data-ohw-nav-root]") ?? document.querySelector("nav");
8204
8718
  if (navRoot) roots.add(navRoot);
8719
+ document.querySelectorAll("[data-ohw-nav-drawer], [data-ohw-nav-container]").forEach((el) => {
8720
+ roots.add(el);
8721
+ });
8205
8722
  const footer = document.querySelector("footer");
8206
8723
  if (footer) roots.add(footer);
8207
8724
  for (const root of roots) {
@@ -8230,6 +8747,12 @@ function isPointOverNavItem(container, x, y) {
8230
8747
  return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
8231
8748
  });
8232
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
+ }
8233
8756
  function resolveNavContainerSelectionTarget(target, clientX, clientY) {
8234
8757
  if (getNavigationItemAnchor(target)) return null;
8235
8758
  if (target.closest('[data-ohw-role="navbar-button"]')) return null;
@@ -8260,7 +8783,10 @@ function getNavigationSelectionParent(el) {
8260
8783
  if (footerGroup) return footerGroup;
8261
8784
  return getNavigationRoot(el);
8262
8785
  }
8263
- 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)) {
8264
8790
  return getNavigationRoot(el);
8265
8791
  }
8266
8792
  return null;
@@ -8431,9 +8957,16 @@ function sanitizeHtml(html) {
8431
8957
  if (!SAFE_TAGS.has(el.tagName)) {
8432
8958
  parent.replaceChild(document.createTextNode(el.textContent ?? ""), el);
8433
8959
  } else {
8434
- const textAlign = el.style?.textAlign || el.getAttribute("align") || "";
8960
+ const htmlEl = el;
8961
+ const textAlign = htmlEl.style?.textAlign || el.getAttribute("align") || "";
8962
+ const fontWeight = htmlEl.style?.fontWeight || "";
8963
+ const fontStyle = htmlEl.style?.fontStyle || "";
8964
+ const textDecorationLine = htmlEl.style?.textDecorationLine || htmlEl.style?.textDecoration || "";
8435
8965
  for (const attr of Array.from(el.attributes)) el.removeAttribute(attr.name);
8436
- if (textAlign) el.style.textAlign = textAlign;
8966
+ if (textAlign) htmlEl.style.textAlign = textAlign;
8967
+ if (fontWeight) htmlEl.style.fontWeight = fontWeight;
8968
+ if (fontStyle) htmlEl.style.fontStyle = fontStyle;
8969
+ if (textDecorationLine) htmlEl.style.textDecorationLine = textDecorationLine;
8437
8970
  walk(el);
8438
8971
  }
8439
8972
  }
@@ -8480,7 +9013,7 @@ function EditGlowChrome({
8480
9013
  hideHandle = false
8481
9014
  }) {
8482
9015
  const GAP = SELECTION_CHROME_GAP2;
8483
- return /* @__PURE__ */ jsxs13(
9016
+ return /* @__PURE__ */ jsxs15(
8484
9017
  "div",
8485
9018
  {
8486
9019
  ref: elRef,
@@ -8495,7 +9028,7 @@ function EditGlowChrome({
8495
9028
  zIndex: 2147483646
8496
9029
  },
8497
9030
  children: [
8498
- /* @__PURE__ */ jsx24(
9031
+ /* @__PURE__ */ jsx26(
8499
9032
  "div",
8500
9033
  {
8501
9034
  style: {
@@ -8508,7 +9041,7 @@ function EditGlowChrome({
8508
9041
  }
8509
9042
  }
8510
9043
  ),
8511
- reorderHrefKey && !hideHandle && /* @__PURE__ */ jsx24(
9044
+ reorderHrefKey && !hideHandle && /* @__PURE__ */ jsx26(
8512
9045
  "div",
8513
9046
  {
8514
9047
  "data-ohw-drag-handle-container": "",
@@ -8520,7 +9053,7 @@ function EditGlowChrome({
8520
9053
  transform: "translate(calc(-100% - 7px), -50%)",
8521
9054
  pointerEvents: dragDisabled ? "none" : "auto"
8522
9055
  },
8523
- children: /* @__PURE__ */ jsx24(
9056
+ children: /* @__PURE__ */ jsx26(
8524
9057
  DragHandle,
8525
9058
  {
8526
9059
  "aria-label": `Reorder ${reorderHrefKey}`,
@@ -8621,6 +9154,79 @@ function resolveItemInteractionState(rect, parentScroll) {
8621
9154
  const { transform } = calcToolbarPos(rect, parentScroll, 120);
8622
9155
  return transform.includes("translateY(-100%)") ? "active-top" : "active-bottom";
8623
9156
  }
9157
+ function resolveSelectionStartElement(sel) {
9158
+ if (!sel || sel.rangeCount === 0) return null;
9159
+ const range = sel.getRangeAt(0);
9160
+ let startNode = range.startContainer;
9161
+ if (startNode.nodeType === Node.ELEMENT_NODE) {
9162
+ const el = startNode;
9163
+ startNode = el.childNodes[range.startOffset] ?? el.childNodes[range.startOffset - 1] ?? el;
9164
+ }
9165
+ return startNode.nodeType === Node.TEXT_NODE ? startNode.parentElement : startNode;
9166
+ }
9167
+ function detectActiveFormats(startEl, activeRoot) {
9168
+ const formats = /* @__PURE__ */ new Set();
9169
+ const cs = getComputedStyle(startEl);
9170
+ const weight = parseInt(cs.fontWeight, 10);
9171
+ let hasBold = cs.fontWeight === "bold" || !Number.isNaN(weight) && weight >= 600;
9172
+ let hasItalic = cs.fontStyle === "italic" || cs.fontStyle === "oblique";
9173
+ let hasUnderline = false;
9174
+ let hasStrike = false;
9175
+ let hasUl = false;
9176
+ let hasOl = false;
9177
+ for (let el = startEl; el; el = el.parentElement) {
9178
+ if (el.tagName === "B" || el.tagName === "STRONG") hasBold = true;
9179
+ if (el.tagName === "I" || el.tagName === "EM") hasItalic = true;
9180
+ const decoration = getComputedStyle(el).textDecorationLine;
9181
+ if (decoration.includes("underline") || el.tagName === "U" || el.tagName === "INS") hasUnderline = true;
9182
+ if (decoration.includes("line-through") || el.tagName === "S" || el.tagName === "STRIKE" || el.tagName === "DEL") hasStrike = true;
9183
+ if (el.tagName === "UL") hasUl = true;
9184
+ if (el.tagName === "OL") hasOl = true;
9185
+ if (el === activeRoot) break;
9186
+ }
9187
+ if (hasBold) formats.add("bold");
9188
+ if (hasItalic) formats.add("italic");
9189
+ if (hasUnderline) formats.add("underline");
9190
+ if (hasStrike) formats.add("strikeThrough");
9191
+ if (hasUl) formats.add("insertUnorderedList");
9192
+ if (hasOl) formats.add("insertOrderedList");
9193
+ const block = startEl.closest("div, p, h1, h2, h3, h4, h5, h6, li, td, th") ?? startEl;
9194
+ const align = getComputedStyle(block).textAlign;
9195
+ if (align === "center") formats.add("justifyCenter");
9196
+ else if (align === "right" || align === "end") formats.add("justifyRight");
9197
+ else formats.add("justifyLeft");
9198
+ return formats;
9199
+ }
9200
+ function setsEqual(a, b) {
9201
+ if (a.size !== b.size) return false;
9202
+ for (const item of a) {
9203
+ if (!b.has(item)) return false;
9204
+ }
9205
+ return true;
9206
+ }
9207
+ function textOffsetInRoot(root, node, offset) {
9208
+ const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
9209
+ let total = 0;
9210
+ let current;
9211
+ while (current = walker.nextNode()) {
9212
+ if (current === node) return total + offset;
9213
+ total += (current.textContent ?? "").length;
9214
+ }
9215
+ return total;
9216
+ }
9217
+ function pointAtTextOffset(root, targetOffset) {
9218
+ const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
9219
+ let total = 0;
9220
+ let current;
9221
+ let last = null;
9222
+ while (current = walker.nextNode()) {
9223
+ const len = (current.textContent ?? "").length;
9224
+ if (total + len >= targetOffset) return { node: current, offset: targetOffset - total };
9225
+ total += len;
9226
+ last = current;
9227
+ }
9228
+ return last ? { node: last, offset: (last.textContent ?? "").length } : null;
9229
+ }
8624
9230
  function FloatingToolbar({
8625
9231
  rect,
8626
9232
  parentScroll,
@@ -8657,7 +9263,7 @@ function FloatingToolbar({
8657
9263
  return () => ro.disconnect();
8658
9264
  }, [showEditLink, activeCommands]);
8659
9265
  const { top, left, transform } = calcToolbarPos(rect, parentScroll, measuredW);
8660
- return /* @__PURE__ */ jsx24(
9266
+ return /* @__PURE__ */ jsx26(
8661
9267
  "div",
8662
9268
  {
8663
9269
  ref: setRefs,
@@ -8669,12 +9275,12 @@ function FloatingToolbar({
8669
9275
  zIndex: 2147483647,
8670
9276
  pointerEvents: "auto"
8671
9277
  },
8672
- children: /* @__PURE__ */ jsxs13(CustomToolbar, { children: [
8673
- TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs13(React11.Fragment, { children: [
8674
- 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, {}),
8675
9281
  btns.map((btn) => {
8676
9282
  const isActive = activeCommands.has(btn.cmd);
8677
- return /* @__PURE__ */ jsx24(
9283
+ return /* @__PURE__ */ jsx26(
8678
9284
  CustomToolbarButton,
8679
9285
  {
8680
9286
  title: btn.title,
@@ -8683,7 +9289,7 @@ function FloatingToolbar({
8683
9289
  e.preventDefault();
8684
9290
  onCommand(btn.cmd);
8685
9291
  },
8686
- children: /* @__PURE__ */ jsx24(
9292
+ children: /* @__PURE__ */ jsx26(
8687
9293
  "svg",
8688
9294
  {
8689
9295
  width: "16",
@@ -8704,7 +9310,7 @@ function FloatingToolbar({
8704
9310
  );
8705
9311
  })
8706
9312
  ] }, gi)),
8707
- showEditLink ? /* @__PURE__ */ jsx24(
9313
+ showEditLink ? /* @__PURE__ */ jsx26(
8708
9314
  CustomToolbarButton,
8709
9315
  {
8710
9316
  type: "button",
@@ -8718,7 +9324,7 @@ function FloatingToolbar({
8718
9324
  e.preventDefault();
8719
9325
  e.stopPropagation();
8720
9326
  },
8721
- 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 })
8722
9328
  }
8723
9329
  ) : null
8724
9330
  ] })
@@ -8735,7 +9341,7 @@ function StateToggle({
8735
9341
  states,
8736
9342
  onStateChange
8737
9343
  }) {
8738
- return /* @__PURE__ */ jsx24(
9344
+ return /* @__PURE__ */ jsx26(
8739
9345
  ToggleGroup,
8740
9346
  {
8741
9347
  "data-ohw-state-toggle": "",
@@ -8749,7 +9355,7 @@ function StateToggle({
8749
9355
  left: rect.right - 8,
8750
9356
  transform: "translateX(-100%)"
8751
9357
  },
8752
- 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))
8753
9359
  }
8754
9360
  );
8755
9361
  }
@@ -8776,8 +9382,8 @@ function OhhwellsBridge() {
8776
9382
  const router = useRouter2();
8777
9383
  const searchParams = useSearchParams();
8778
9384
  const isEditMode = isEditSessionActive();
8779
- const [bridgeRoot, setBridgeRoot] = useState7(null);
8780
- useEffect8(() => {
9385
+ const [bridgeRoot, setBridgeRoot] = useState8(null);
9386
+ useEffect9(() => {
8781
9387
  const figtreeFontId = "ohw-figtree-font";
8782
9388
  if (!document.getElementById(figtreeFontId)) {
8783
9389
  const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
@@ -8805,14 +9411,15 @@ function OhhwellsBridge() {
8805
9411
  const subdomainFromQuery = searchParams.get("subdomain");
8806
9412
  const subdomain = resolveSubdomain(subdomainFromQuery);
8807
9413
  useLinkHrefGuardian(pathname, subdomain, isEditMode);
8808
- const postToParent2 = useCallback4((data) => {
9414
+ const postToParent2 = useCallback5((data) => {
8809
9415
  if (typeof window !== "undefined" && window.parent !== window) {
8810
9416
  window.parent.postMessage(data, "*");
8811
9417
  }
8812
9418
  }, []);
8813
- const [fetchState, setFetchState] = useState7("idle");
9419
+ const [fetchState, setFetchState] = useState8("idle");
8814
9420
  const autoSaveTimers = useRef7(/* @__PURE__ */ new Map());
8815
9421
  const activeElRef = useRef7(null);
9422
+ const pointerHeldRef = useRef7(false);
8816
9423
  const selectedElRef = useRef7(null);
8817
9424
  const selectedHrefKeyRef = useRef7(null);
8818
9425
  const selectedFooterColAttrRef = useRef7(null);
@@ -8820,8 +9427,8 @@ function OhhwellsBridge() {
8820
9427
  const activeStateElRef = useRef7(null);
8821
9428
  const parentScrollRef = useRef7(null);
8822
9429
  const visibleViewportRef = useRef7(null);
8823
- const [dialogPortalContainer, setDialogPortalContainer] = useState7(null);
8824
- const attachVisibleViewport = useCallback4((node) => {
9430
+ const [dialogPortalContainer, setDialogPortalContainer] = useState8(null);
9431
+ const attachVisibleViewport = useCallback5((node) => {
8825
9432
  visibleViewportRef.current = node;
8826
9433
  setDialogPortalContainer(node);
8827
9434
  if (node) applyVisibleViewport(node, parentScrollRef.current);
@@ -8831,8 +9438,9 @@ function OhhwellsBridge() {
8831
9438
  const hoveredImageRef = useRef7(null);
8832
9439
  const hoveredImageHasTextOverlapRef = useRef7(false);
8833
9440
  const dragOverElRef = useRef7(null);
8834
- const [mediaHover, setMediaHover] = useState7(null);
8835
- const [uploadingRects, setUploadingRects] = useState7({});
9441
+ const [mediaHover, setMediaHover] = useState8(null);
9442
+ const [carouselHover, setCarouselHover] = useState8(null);
9443
+ const [uploadingRects, setUploadingRects] = useState8({});
8836
9444
  const hoveredGapRef = useRef7(null);
8837
9445
  const imageUnhoverTimerRef = useRef7(null);
8838
9446
  const imageShowTimerRef = useRef7(null);
@@ -8857,40 +9465,40 @@ function OhhwellsBridge() {
8857
9465
  postToParentRef.current = postToParent2;
8858
9466
  const sectionsLoadedRef = useRef7(false);
8859
9467
  const pendingScheduleConfigRequests = useRef7([]);
8860
- const [toolbarRect, setToolbarRect] = useState7(null);
8861
- const [toolbarVariant, setToolbarVariant] = useState7("none");
9468
+ const [toolbarRect, setToolbarRect] = useState8(null);
9469
+ const [toolbarVariant, setToolbarVariant] = useState8("none");
8862
9470
  const toolbarVariantRef = useRef7("none");
8863
9471
  toolbarVariantRef.current = toolbarVariant;
8864
- const [selectedIsCta, setSelectedIsCta] = useState7(false);
8865
- const [reorderHrefKey, setReorderHrefKey] = useState7(null);
8866
- const [reorderDragDisabled, setReorderDragDisabled] = useState7(false);
8867
- const [toggleState, setToggleState] = useState7(null);
8868
- const [maxBadge, setMaxBadge] = useState7(null);
8869
- const [activeCommands, setActiveCommands] = useState7(/* @__PURE__ */ new Set());
8870
- const [sectionGap, setSectionGap] = useState7(null);
8871
- 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);
8872
9480
  const hoveredNavContainerRef = useRef7(null);
8873
- const [hoveredNavContainerRect, setHoveredNavContainerRect] = useState7(null);
9481
+ const [hoveredNavContainerRect, setHoveredNavContainerRect] = useState8(null);
8874
9482
  const hoveredItemElRef = useRef7(null);
8875
- const [hoveredItemRect, setHoveredItemRect] = useState7(null);
9483
+ const [hoveredItemRect, setHoveredItemRect] = useState8(null);
8876
9484
  const siblingHintElRef = useRef7(null);
8877
- const [siblingHintRect, setSiblingHintRect] = useState7(null);
8878
- const [siblingHintRects, setSiblingHintRects] = useState7([]);
8879
- const [isItemDragging, setIsItemDragging] = useState7(false);
8880
- 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);
8881
9489
  const footerDragRef = useRef7(null);
8882
- const [footerDropSlots, setFooterDropSlots] = useState7([]);
8883
- const [activeFooterDropIndex, setActiveFooterDropIndex] = useState7(null);
8884
- const [draggedItemRect, setDraggedItemRect] = useState7(null);
9490
+ const [footerDropSlots, setFooterDropSlots] = useState8([]);
9491
+ const [activeFooterDropIndex, setActiveFooterDropIndex] = useState8(null);
9492
+ const [draggedItemRect, setDraggedItemRect] = useState8(null);
8885
9493
  const footerPointerDragRef = useRef7(null);
8886
9494
  const suppressNextClickRef = useRef7(false);
8887
9495
  const suppressClickUntilRef = useRef7(0);
8888
- const [linkPopover, setLinkPopover] = useState7(null);
9496
+ const [linkPopover, setLinkPopover] = useState8(null);
8889
9497
  const linkPopoverSessionRef = useRef7(null);
8890
9498
  const addNavAfterAnchorRef = useRef7(null);
8891
9499
  const editContentRef = useRef7({});
8892
- const [sitePages, setSitePages] = useState7([]);
8893
- const [sectionsByPath, setSectionsByPath] = useState7({});
9500
+ const [sitePages, setSitePages] = useState8([]);
9501
+ const [sectionsByPath, setSectionsByPath] = useState8({});
8894
9502
  const sectionsPrefetchGenRef = useRef7(0);
8895
9503
  const setLinkPopoverRef = useRef7(setLinkPopover);
8896
9504
  const linkPopoverPanelRef = useRef7(null);
@@ -8934,7 +9542,7 @@ function OhhwellsBridge() {
8934
9542
  const bumpLinkPopoverGrace = () => {
8935
9543
  linkPopoverGraceUntilRef.current = Date.now() + 350;
8936
9544
  };
8937
- const runSectionsPrefetch = useCallback4((pages) => {
9545
+ const runSectionsPrefetch = useCallback5((pages) => {
8938
9546
  if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
8939
9547
  const gen = ++sectionsPrefetchGenRef.current;
8940
9548
  const paths = pages.map((p) => p.path);
@@ -8955,7 +9563,7 @@ function OhhwellsBridge() {
8955
9563
  }, [isEditMode, pathname]);
8956
9564
  const runSectionsPrefetchRef = useRef7(runSectionsPrefetch);
8957
9565
  runSectionsPrefetchRef.current = runSectionsPrefetch;
8958
- useEffect8(() => {
9566
+ useEffect9(() => {
8959
9567
  if (!linkPopover) {
8960
9568
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
8961
9569
  return;
@@ -9005,7 +9613,7 @@ function OhhwellsBridge() {
9005
9613
  document.removeEventListener("touchmove", preventBackgroundScroll, scrollOpts);
9006
9614
  };
9007
9615
  }, [linkPopover, postToParent2]);
9008
- useEffect8(() => {
9616
+ useEffect9(() => {
9009
9617
  if (!isEditMode) return;
9010
9618
  const useFixtures = shouldUseDevFixtures();
9011
9619
  if (useFixtures) {
@@ -9029,14 +9637,14 @@ function OhhwellsBridge() {
9029
9637
  if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
9030
9638
  return () => window.removeEventListener("message", onSitePages);
9031
9639
  }, [isEditMode, postToParent2]);
9032
- useEffect8(() => {
9640
+ useEffect9(() => {
9033
9641
  if (!isEditMode || shouldUseDevFixtures()) return;
9034
9642
  void loadAllSectionsManifest().then((manifest) => {
9035
9643
  if (Object.keys(manifest).length === 0) return;
9036
9644
  setSectionsByPath((prev) => ({ ...manifest, ...prev }));
9037
9645
  });
9038
9646
  }, [isEditMode]);
9039
- useEffect8(() => {
9647
+ useEffect9(() => {
9040
9648
  const update = () => {
9041
9649
  const el = activeElRef.current ?? selectedElRef.current;
9042
9650
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
@@ -9060,10 +9668,10 @@ function OhhwellsBridge() {
9060
9668
  vvp.removeEventListener("resize", update);
9061
9669
  };
9062
9670
  }, []);
9063
- const refreshStateRules = useCallback4(() => {
9671
+ const refreshStateRules = useCallback5(() => {
9064
9672
  editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
9065
9673
  }, []);
9066
- const processConfigRequest = useCallback4((insertAfterVal) => {
9674
+ const processConfigRequest = useCallback5((insertAfterVal) => {
9067
9675
  const tracker = getSectionsTracker();
9068
9676
  let entries = [];
9069
9677
  try {
@@ -9086,7 +9694,7 @@ function OhhwellsBridge() {
9086
9694
  }
9087
9695
  window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
9088
9696
  }, [isEditMode]);
9089
- const deactivate = useCallback4(() => {
9697
+ const deactivate = useCallback5(() => {
9090
9698
  const el = activeElRef.current;
9091
9699
  if (!el) return;
9092
9700
  const key = el.dataset.ohwKey;
@@ -9118,12 +9726,12 @@ function OhhwellsBridge() {
9118
9726
  setToolbarShowEditLink(false);
9119
9727
  postToParent2({ type: "ow:exit-edit" });
9120
9728
  }, [postToParent2]);
9121
- const clearSelectedAttr = useCallback4(() => {
9729
+ const clearSelectedAttr = useCallback5(() => {
9122
9730
  document.querySelectorAll("[data-ohw-selected]").forEach((el) => {
9123
9731
  el.removeAttribute("data-ohw-selected");
9124
9732
  });
9125
9733
  }, []);
9126
- const deselect = useCallback4(() => {
9734
+ const deselect = useCallback5(() => {
9127
9735
  clearSelectedAttr();
9128
9736
  selectedElRef.current = null;
9129
9737
  selectedHrefKeyRef.current = null;
@@ -9143,11 +9751,11 @@ function OhhwellsBridge() {
9143
9751
  setToolbarVariant("none");
9144
9752
  }
9145
9753
  }, [clearSelectedAttr]);
9146
- const markSelected = useCallback4((el) => {
9754
+ const markSelected = useCallback5((el) => {
9147
9755
  clearSelectedAttr();
9148
9756
  el.setAttribute("data-ohw-selected", "");
9149
9757
  }, [clearSelectedAttr]);
9150
- const resolveHrefKeyElement = useCallback4((hrefKey) => {
9758
+ const resolveHrefKeyElement = useCallback5((hrefKey) => {
9151
9759
  if (isFooterHrefKey(hrefKey)) {
9152
9760
  return document.querySelector(
9153
9761
  `footer [data-ohw-href-key="${CSS.escape(hrefKey)}"]`
@@ -9162,7 +9770,7 @@ function OhhwellsBridge() {
9162
9770
  `[data-ohw-href-key="${CSS.escape(hrefKey)}"]`
9163
9771
  );
9164
9772
  }, []);
9165
- const resyncSelectedNavigationItem = useCallback4(() => {
9773
+ const resyncSelectedNavigationItem = useCallback5(() => {
9166
9774
  const hrefKey = selectedHrefKeyRef.current;
9167
9775
  if (hrefKey) {
9168
9776
  const link = resolveHrefKeyElement(hrefKey);
@@ -9190,7 +9798,7 @@ function OhhwellsBridge() {
9190
9798
  );
9191
9799
  }
9192
9800
  }, [resolveHrefKeyElement]);
9193
- const reselectNavigationItem = useCallback4((navAnchor) => {
9801
+ const reselectNavigationItem = useCallback5((navAnchor) => {
9194
9802
  selectedElRef.current = navAnchor;
9195
9803
  selectedHrefKeyRef.current = navAnchor.getAttribute("data-ohw-href-key");
9196
9804
  selectedFooterColAttrRef.current = null;
@@ -9205,7 +9813,7 @@ function OhhwellsBridge() {
9205
9813
  setToolbarShowEditLink(false);
9206
9814
  setActiveCommands(/* @__PURE__ */ new Set());
9207
9815
  }, [markSelected]);
9208
- const commitNavigationTextEdit = useCallback4((navAnchor) => {
9816
+ const commitNavigationTextEdit = useCallback5((navAnchor) => {
9209
9817
  const el = activeElRef.current;
9210
9818
  if (!el) return;
9211
9819
  const key = el.dataset.ohwKey;
@@ -9232,7 +9840,7 @@ function OhhwellsBridge() {
9232
9840
  postToParent2({ type: "ow:exit-edit" });
9233
9841
  reselectNavigationItem(navAnchor);
9234
9842
  }, [postToParent2, reselectNavigationItem]);
9235
- const handleAddTopLevelNavItem = useCallback4(() => {
9843
+ const handleAddTopLevelNavItem = useCallback5(() => {
9236
9844
  const items = listNavbarItems();
9237
9845
  addNavAfterAnchorRef.current = items[items.length - 1] ?? null;
9238
9846
  deselectRef.current();
@@ -9244,7 +9852,19 @@ function OhhwellsBridge() {
9244
9852
  intent: "add-nav"
9245
9853
  });
9246
9854
  }, []);
9247
- 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(() => {
9248
9868
  footerDragRef.current = null;
9249
9869
  setSiblingHintRects([]);
9250
9870
  setFooterDropSlots([]);
@@ -9253,7 +9873,7 @@ function OhhwellsBridge() {
9253
9873
  setIsItemDragging(false);
9254
9874
  unlockFooterDragInteraction();
9255
9875
  }, []);
9256
- const refreshFooterDragVisuals = useCallback4((session, activeSlot, clientX, clientY) => {
9876
+ const refreshFooterDragVisuals = useCallback5((session, activeSlot, clientX, clientY) => {
9257
9877
  const dragged = session.draggedEl;
9258
9878
  setDraggedItemRect(dragged.getBoundingClientRect());
9259
9879
  if (typeof clientX === "number" && typeof clientY === "number") {
@@ -9284,7 +9904,7 @@ function OhhwellsBridge() {
9284
9904
  });
9285
9905
  const beginFooterDragRef = useRef7(() => {
9286
9906
  });
9287
- const beginFooterDrag = useCallback4(
9907
+ const beginFooterDrag = useCallback5(
9288
9908
  (session) => {
9289
9909
  const rect = session.draggedEl.getBoundingClientRect();
9290
9910
  session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
@@ -9304,7 +9924,7 @@ function OhhwellsBridge() {
9304
9924
  [refreshFooterDragVisuals]
9305
9925
  );
9306
9926
  beginFooterDragRef.current = beginFooterDrag;
9307
- const commitFooterDrag = useCallback4(
9927
+ const commitFooterDrag = useCallback5(
9308
9928
  (clientX, clientY) => {
9309
9929
  const session = footerDragRef.current;
9310
9930
  if (!session) {
@@ -9408,7 +10028,7 @@ function OhhwellsBridge() {
9408
10028
  [clearFooterDragVisuals, resolveHrefKeyElement, resyncSelectedNavigationItem]
9409
10029
  );
9410
10030
  commitFooterDragRef.current = commitFooterDrag;
9411
- const startFooterLinkDrag = useCallback4(
10031
+ const startFooterLinkDrag = useCallback5(
9412
10032
  (anchor, clientX, clientY, wasSelected) => {
9413
10033
  const hrefKey = anchor.getAttribute("data-ohw-href-key");
9414
10034
  if (!hrefKey || !isFooterHrefKey(hrefKey)) return false;
@@ -9429,7 +10049,7 @@ function OhhwellsBridge() {
9429
10049
  },
9430
10050
  [beginFooterDrag]
9431
10051
  );
9432
- const startFooterColumnDrag = useCallback4(
10052
+ const startFooterColumnDrag = useCallback5(
9433
10053
  (columnEl, clientX, clientY, wasSelected) => {
9434
10054
  const columns = listFooterColumns();
9435
10055
  const idx = columns.indexOf(columnEl);
@@ -9449,7 +10069,7 @@ function OhhwellsBridge() {
9449
10069
  },
9450
10070
  [beginFooterDrag]
9451
10071
  );
9452
- const handleItemDragStart = useCallback4(
10072
+ const handleItemDragStart = useCallback5(
9453
10073
  (e) => {
9454
10074
  const selected = selectedElRef.current;
9455
10075
  if (!selected) {
@@ -9469,7 +10089,7 @@ function OhhwellsBridge() {
9469
10089
  },
9470
10090
  [startFooterColumnDrag, startFooterLinkDrag, startNavLinkDrag]
9471
10091
  );
9472
- const handleItemDragEnd = useCallback4(
10092
+ const handleItemDragEnd = useCallback5(
9473
10093
  (e) => {
9474
10094
  if (footerDragRef.current) {
9475
10095
  const x = e?.clientX;
@@ -9495,11 +10115,10 @@ function OhhwellsBridge() {
9495
10115
  },
9496
10116
  [commitFooterDrag, commitNavDrag, navDragRef]
9497
10117
  );
9498
- const handleItemChromePointerDown = useCallback4((e) => {
10118
+ const handleItemChromePointerDown = useCallback5((e) => {
9499
10119
  if (e.button !== 0) return;
9500
10120
  const selected = selectedElRef.current;
9501
10121
  if (!selected) return;
9502
- armFooterPressDrag();
9503
10122
  const hrefKey = selected.getAttribute("data-ohw-href-key");
9504
10123
  if (hrefKey && isFooterHrefKey(hrefKey)) {
9505
10124
  footerPointerDragRef.current = {
@@ -9527,7 +10146,7 @@ function OhhwellsBridge() {
9527
10146
  }
9528
10147
  if (armNavPressFromChrome(selected, e.clientX, e.clientY, e.pointerId)) return;
9529
10148
  }, [armNavPressFromChrome]);
9530
- const handleItemChromeClick = useCallback4((clientX, clientY) => {
10149
+ const handleItemChromeClick = useCallback5((clientX, clientY) => {
9531
10150
  if (suppressNextClickRef.current || Date.now() < suppressClickUntilRef.current) {
9532
10151
  suppressNextClickRef.current = false;
9533
10152
  return;
@@ -9540,7 +10159,7 @@ function OhhwellsBridge() {
9540
10159
  }, []);
9541
10160
  reselectNavigationItemRef.current = reselectNavigationItem;
9542
10161
  commitNavigationTextEditRef.current = commitNavigationTextEdit;
9543
- const select = useCallback4((anchor) => {
10162
+ const select = useCallback5((anchor) => {
9544
10163
  if (!isNavigationItem(anchor)) return;
9545
10164
  if (activeElRef.current) deactivate();
9546
10165
  selectedElRef.current = anchor;
@@ -9566,10 +10185,10 @@ function OhhwellsBridge() {
9566
10185
  setToolbarShowEditLink(false);
9567
10186
  setActiveCommands(/* @__PURE__ */ new Set());
9568
10187
  }, [deactivate, markSelected]);
9569
- const selectFrame = useCallback4((el) => {
10188
+ const selectFrame = useCallback5((el) => {
9570
10189
  if (!isNavigationContainer(el)) return;
9571
10190
  if (activeElRef.current) deactivate();
9572
- 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)));
9573
10192
  selectedElRef.current = el;
9574
10193
  selectedHrefKeyRef.current = null;
9575
10194
  selectedFooterColAttrRef.current = isFooterColumn ? el.getAttribute("data-ohw-footer-col") ?? String(listFooterColumns().indexOf(el)) : null;
@@ -9594,7 +10213,7 @@ function OhhwellsBridge() {
9594
10213
  setToolbarShowEditLink(false);
9595
10214
  setActiveCommands(/* @__PURE__ */ new Set());
9596
10215
  }, [deactivate, markSelected]);
9597
- const activate = useCallback4((el, options) => {
10216
+ const activate = useCallback5((el, options) => {
9598
10217
  if (activeElRef.current === el) return;
9599
10218
  clearSelectedAttr();
9600
10219
  selectedElRef.current = null;
@@ -9611,6 +10230,8 @@ function OhhwellsBridge() {
9611
10230
  setSiblingHintRect(null);
9612
10231
  setSiblingHintRects([]);
9613
10232
  setIsItemDragging(false);
10233
+ const preActivationSelection = window.getSelection();
10234
+ const preservedRange = preActivationSelection && preActivationSelection.rangeCount > 0 && !preActivationSelection.isCollapsed && el.contains(preActivationSelection.getRangeAt(0).commonAncestorContainer) ? preActivationSelection.getRangeAt(0).cloneRange() : null;
9614
10235
  el.setAttribute("contenteditable", "true");
9615
10236
  el.setAttribute("data-ohw-editing", "");
9616
10237
  el.removeAttribute("data-ohw-hovered");
@@ -9618,7 +10239,11 @@ function OhhwellsBridge() {
9618
10239
  activeElRef.current = el;
9619
10240
  originalContentRef.current = el.innerHTML;
9620
10241
  el.focus({ preventScroll: true });
9621
- if (options?.caretX !== void 0 && options?.caretY !== void 0) {
10242
+ if (preservedRange) {
10243
+ const selection = window.getSelection();
10244
+ selection?.removeAllRanges();
10245
+ selection?.addRange(preservedRange);
10246
+ } else if (options?.caretX !== void 0 && options?.caretY !== void 0) {
9622
10247
  const { caretX, caretY } = options;
9623
10248
  placeCaretAtPoint(el, caretX, caretY);
9624
10249
  requestAnimationFrame(() => {
@@ -9663,6 +10288,7 @@ function OhhwellsBridge() {
9663
10288
  for (const [key, val] of Object.entries(content)) {
9664
10289
  if (key === "__ohw_sections") continue;
9665
10290
  if (applyVideoSettingNode(key, val)) continue;
10291
+ if (applyCarouselNode(key, val)) continue;
9666
10292
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
9667
10293
  if (el.dataset.ohwEditable === "image") {
9668
10294
  const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
@@ -9723,7 +10349,7 @@ function OhhwellsBridge() {
9723
10349
  cancelled = true;
9724
10350
  };
9725
10351
  }, [subdomain, isEditMode]);
9726
- useEffect8(() => {
10352
+ useEffect9(() => {
9727
10353
  if (!subdomain || isEditMode) return;
9728
10354
  let debounceTimer = null;
9729
10355
  let observer = null;
@@ -9736,6 +10362,7 @@ function OhhwellsBridge() {
9736
10362
  for (const [key, val] of Object.entries(content)) {
9737
10363
  if (key === "__ohw_sections") continue;
9738
10364
  if (applyVideoSettingNode(key, val)) continue;
10365
+ if (applyCarouselNode(key, val)) continue;
9739
10366
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
9740
10367
  if (el.dataset.ohwEditable === "image") {
9741
10368
  const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
@@ -9779,10 +10406,10 @@ function OhhwellsBridge() {
9779
10406
  const visible = Boolean(subdomain) && fetchState !== "done";
9780
10407
  el.style.display = visible ? "flex" : "none";
9781
10408
  }, [subdomain, fetchState]);
9782
- useEffect8(() => {
10409
+ useEffect9(() => {
9783
10410
  postToParent2({ type: "ow:navigation", path: pathname });
9784
10411
  }, [pathname, postToParent2]);
9785
- useEffect8(() => {
10412
+ useEffect9(() => {
9786
10413
  if (!isEditMode) return;
9787
10414
  if (linkPopoverSessionRef.current?.intent === "add-nav") return;
9788
10415
  if (document.querySelector("[data-ohw-section-picker]")) return;
@@ -9790,7 +10417,7 @@ function OhhwellsBridge() {
9790
10417
  deselectRef.current();
9791
10418
  deactivateRef.current();
9792
10419
  }, [pathname, isEditMode]);
9793
- useEffect8(() => {
10420
+ useEffect9(() => {
9794
10421
  const contentForNav = () => {
9795
10422
  if (isEditMode) return editContentRef.current;
9796
10423
  if (!subdomain) return {};
@@ -9855,7 +10482,7 @@ function OhhwellsBridge() {
9855
10482
  observer?.disconnect();
9856
10483
  };
9857
10484
  }, [isEditMode, pathname, subdomain, fetchState, resyncSelectedNavigationItem]);
9858
- useEffect8(() => {
10485
+ useEffect9(() => {
9859
10486
  if (!isEditMode) return;
9860
10487
  const measure = () => {
9861
10488
  const h = document.body.scrollHeight;
@@ -9879,7 +10506,7 @@ function OhhwellsBridge() {
9879
10506
  window.removeEventListener("resize", handleResize);
9880
10507
  };
9881
10508
  }, [pathname, isEditMode, postToParent2]);
9882
- useEffect8(() => {
10509
+ useEffect9(() => {
9883
10510
  if (!subdomainFromQuery || isEditMode) return;
9884
10511
  const handleClick = (e) => {
9885
10512
  const anchor = e.target.closest("a");
@@ -9895,7 +10522,7 @@ function OhhwellsBridge() {
9895
10522
  document.addEventListener("click", handleClick, true);
9896
10523
  return () => document.removeEventListener("click", handleClick, true);
9897
10524
  }, [subdomainFromQuery, isEditMode, router]);
9898
- useEffect8(() => {
10525
+ useEffect9(() => {
9899
10526
  if (!isEditMode) {
9900
10527
  editStylesRef.current?.base.remove();
9901
10528
  editStylesRef.current?.forceHover.remove();
@@ -10074,7 +10701,9 @@ function OhhwellsBridge() {
10074
10701
  if (inActive || inActiveNav) {
10075
10702
  e.preventDefault();
10076
10703
  e.stopPropagation();
10077
- if (e.detail < 2) {
10704
+ const selection = window.getSelection();
10705
+ const hasRangeSelection = Boolean(selection && !selection.isCollapsed);
10706
+ if (e.detail < 2 && !hasRangeSelection) {
10078
10707
  placeCaretAtPoint(active, e.clientX, e.clientY);
10079
10708
  refreshActiveCommandsRef.current();
10080
10709
  }
@@ -10117,7 +10746,7 @@ function OhhwellsBridge() {
10117
10746
  }
10118
10747
  e.preventDefault();
10119
10748
  e.stopPropagation();
10120
- activateRef.current(editable);
10749
+ activateRef.current(editable, { caretX: e.clientX, caretY: e.clientY });
10121
10750
  return;
10122
10751
  }
10123
10752
  const hrefAnchor = getNavigationItemAnchor(target);
@@ -10144,6 +10773,18 @@ function OhhwellsBridge() {
10144
10773
  selectFrameRef.current(footerColClick);
10145
10774
  return;
10146
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
+ }
10147
10788
  const navContainerToSelect = resolveNavContainerSelectionTarget(target, e.clientX, e.clientY);
10148
10789
  if (navContainerToSelect) {
10149
10790
  e.preventDefault();
@@ -10202,8 +10843,8 @@ function OhhwellsBridge() {
10202
10843
  return;
10203
10844
  }
10204
10845
  const navLabel = getNavigationLabelEditable(target);
10205
- if (!navLabel) return;
10206
- 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;
10207
10848
  e.preventDefault();
10208
10849
  e.stopPropagation();
10209
10850
  if (activeElRef.current !== editable) {
@@ -10224,16 +10865,38 @@ function OhhwellsBridge() {
10224
10865
  setHoveredNavContainerRect(null);
10225
10866
  return;
10226
10867
  }
10227
- if (toolbarVariantRef.current !== "select-frame") {
10228
- const navContainer = target.closest("[data-ohw-nav-container]");
10229
- if (navContainer && !getNavigationItemAnchor(target)) {
10230
- hoveredNavContainerRef.current = navContainer;
10231
- setHoveredNavContainerRect(navContainer.getBoundingClientRect());
10232
- hoveredItemElRef.current = null;
10233
- setHoveredItemRect(null);
10234
- 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
+ }
10235
10882
  }
10236
- 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") {
10237
10900
  hoveredNavContainerRef.current = null;
10238
10901
  setHoveredNavContainerRect(null);
10239
10902
  }
@@ -10275,9 +10938,9 @@ function OhhwellsBridge() {
10275
10938
  };
10276
10939
  const handleMouseOut = (e) => {
10277
10940
  const target = e.target;
10278
- 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")) {
10279
10942
  const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
10280
- 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]")) {
10281
10944
  return;
10282
10945
  }
10283
10946
  hoveredNavContainerRef.current = null;
@@ -10372,6 +11035,15 @@ function OhhwellsBridge() {
10372
11035
  if (track) track.setAttribute("data-ohw-hover-paused", "");
10373
11036
  };
10374
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
+ };
10375
11047
  const findImageAtPoint = (clientX, clientY, fromParentViewport) => {
10376
11048
  const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
10377
11049
  const images = Array.from(document.querySelectorAll(MEDIA_SELECTOR));
@@ -10415,16 +11087,13 @@ function OhhwellsBridge() {
10415
11087
  }
10416
11088
  return smallest;
10417
11089
  };
10418
- const dismissImageHover = () => {
10419
- if (hoveredImageRef.current) {
10420
- hoveredImageRef.current = null;
10421
- hoveredImageHasTextOverlapRef.current = false;
10422
- resumeAnimTracks();
10423
- postToParentRef.current({ type: "ow:image-unhover" });
10424
- }
10425
- };
10426
11090
  const probeNavigationHoverAt = (x, y) => {
10427
- 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) {
10428
11097
  hoveredNavContainerRef.current = null;
10429
11098
  setHoveredNavContainerRect(null);
10430
11099
  }
@@ -10446,7 +11115,6 @@ function OhhwellsBridge() {
10446
11115
  if (navItemHit) {
10447
11116
  hoveredNavContainerRef.current = null;
10448
11117
  setHoveredNavContainerRect(null);
10449
- const selected = selectedElRef.current;
10450
11118
  if (selected !== navItemHit) {
10451
11119
  clearHrefKeyHover(navItemHit);
10452
11120
  hoveredItemElRef.current = navItemHit;
@@ -10458,7 +11126,7 @@ function OhhwellsBridge() {
10458
11126
  return;
10459
11127
  }
10460
11128
  }
10461
- if (toolbarVariantRef.current !== "select-frame") {
11129
+ if (allowNavContainerHover) {
10462
11130
  for (const container of navContainers) {
10463
11131
  const containerRect = container.getBoundingClientRect();
10464
11132
  const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
@@ -10470,12 +11138,23 @@ function OhhwellsBridge() {
10470
11138
  setHoveredItemRect(null);
10471
11139
  return;
10472
11140
  }
10473
- hoveredNavContainerRef.current = null;
10474
- setHoveredNavContainerRect(null);
10475
- } else {
10476
- hoveredNavContainerRef.current = null;
10477
- setHoveredNavContainerRect(null);
10478
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);
10479
11158
  for (const column of footerColumns) {
10480
11159
  const containerRect = column.getBoundingClientRect();
10481
11160
  const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
@@ -10737,6 +11416,7 @@ function OhhwellsBridge() {
10737
11416
  const ZONE = 20;
10738
11417
  for (let i = 0; i < sections.length; i++) {
10739
11418
  const a = sections[i];
11419
+ if (a.dataset.ohwSection === "footer") continue;
10740
11420
  const b = sections[i + 1] ?? null;
10741
11421
  const boundaryY = a.getBoundingClientRect().bottom;
10742
11422
  if (Math.abs(y - boundaryY) <= ZONE) {
@@ -10958,6 +11638,7 @@ function OhhwellsBridge() {
10958
11638
  continue;
10959
11639
  }
10960
11640
  if (applyVideoSettingNode(key, val)) continue;
11641
+ if (applyCarouselNode(key, val)) continue;
10961
11642
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
10962
11643
  if (el.dataset.ohwEditable === "image") {
10963
11644
  const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
@@ -10982,6 +11663,7 @@ function OhhwellsBridge() {
10982
11663
  }
10983
11664
  editContentRef.current = { ...editContentRef.current, ...content };
10984
11665
  reconcileNavbarItemsFromContent(editContentRef.current);
11666
+ reconcileFooterOrderFromContent(editContentRef.current);
10985
11667
  syncNavigationDragCursorAttrs();
10986
11668
  enforceLinkHrefs();
10987
11669
  postToParentRef.current({ type: "ow:hydrate-done" });
@@ -11036,6 +11718,11 @@ function OhhwellsBridge() {
11036
11718
  }
11037
11719
  if (selectedElRef.current) {
11038
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
+ }
11039
11726
  deselectRef.current();
11040
11727
  return;
11041
11728
  }
@@ -11051,13 +11738,10 @@ function OhhwellsBridge() {
11051
11738
  const handleKeyDown = (e) => {
11052
11739
  if (e.key === "Escape" && document.querySelector("[data-ohw-section-picker]")) return;
11053
11740
  if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a" && activeElRef.current) {
11054
- const navAnchor = getNavigationItemAnchor(activeElRef.current);
11055
- if (navAnchor) {
11056
- e.preventDefault();
11057
- selectAllTextInEditable(activeElRef.current);
11058
- refreshActiveCommandsRef.current();
11059
- return;
11060
- }
11741
+ e.preventDefault();
11742
+ selectAllTextInEditable(activeElRef.current);
11743
+ refreshActiveCommandsRef.current();
11744
+ return;
11061
11745
  }
11062
11746
  if (e.key === "Escape" && linkPopoverOpenRef.current) {
11063
11747
  setLinkPopoverRef.current(null);
@@ -11065,6 +11749,12 @@ function OhhwellsBridge() {
11065
11749
  }
11066
11750
  if (e.key === "Escape" && selectedElRef.current && !activeElRef.current) {
11067
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
+ }
11068
11758
  deselectRef.current();
11069
11759
  return;
11070
11760
  }
@@ -11227,33 +11917,34 @@ function OhhwellsBridge() {
11227
11917
  const h = document.documentElement.scrollHeight;
11228
11918
  if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
11229
11919
  };
11920
+ let selectionChangeRaf = null;
11921
+ const runSelectionChange = () => {
11922
+ selectionChangeRaf = null;
11923
+ const activeRoot = activeElRef.current;
11924
+ if (!activeRoot) return;
11925
+ const startEl = resolveSelectionStartElement(window.getSelection());
11926
+ const next = startEl ? detectActiveFormats(startEl, activeRoot) : /* @__PURE__ */ new Set();
11927
+ setActiveCommands((prev) => setsEqual(prev, next) ? prev : next);
11928
+ };
11230
11929
  const handleSelectionChange = () => {
11231
- if (!activeElRef.current) return;
11232
- const next = /* @__PURE__ */ new Set();
11233
- for (const cmd of ["bold", "italic", "underline", "strikeThrough", "insertUnorderedList", "insertOrderedList"]) {
11234
- try {
11235
- if (document.queryCommandState(cmd)) next.add(cmd);
11236
- } catch {
11237
- }
11238
- }
11239
- const sel = window.getSelection();
11240
- const anchor = sel?.anchorNode;
11241
- if (anchor) {
11242
- const el = anchor.nodeType === Node.TEXT_NODE ? anchor.parentElement : anchor;
11243
- const block = el?.closest("div, p, h1, h2, h3, h4, h5, h6, li, td, th") ?? el;
11244
- if (block) {
11245
- const align = getComputedStyle(block).textAlign;
11246
- if (align === "center") next.add("justifyCenter");
11247
- else if (align === "right" || align === "end") next.add("justifyRight");
11248
- else next.add("justifyLeft");
11249
- }
11250
- }
11251
- setActiveCommands(next);
11930
+ if (pointerHeldRef.current) return;
11931
+ if (selectionChangeRaf !== null) return;
11932
+ selectionChangeRaf = requestAnimationFrame(runSelectionChange);
11933
+ };
11934
+ const markPointerHeld = (e) => {
11935
+ if (e.button !== 0) return;
11936
+ pointerHeldRef.current = true;
11252
11937
  };
11253
- refreshActiveCommandsRef.current = handleSelectionChange;
11938
+ const markPointerReleased = () => {
11939
+ if (!pointerHeldRef.current) return;
11940
+ pointerHeldRef.current = false;
11941
+ handleSelectionChange();
11942
+ };
11943
+ refreshActiveCommandsRef.current = runSelectionChange;
11254
11944
  const handleDocMouseLeave = () => {
11255
11945
  hoveredImageRef.current = null;
11256
11946
  setMediaHover(null);
11947
+ setCarouselHover(null);
11257
11948
  document.querySelectorAll("[data-ohw-state-hovered]").forEach((el) => el.removeAttribute("data-ohw-state-hovered"));
11258
11949
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
11259
11950
  activeStateElRef.current = null;
@@ -11293,6 +11984,48 @@ function OhhwellsBridge() {
11293
11984
  if (e.data?.type !== "ow:canvas-height" || typeof e.data.height !== "number") return;
11294
11985
  document.documentElement.style.setProperty("--ohw-canvas-h", `${e.data.height}px`);
11295
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
+ };
11296
12029
  const applyToolbarPos = (rect) => {
11297
12030
  const ps = parentScrollRef.current;
11298
12031
  const measuredW = toolbarElRef.current?.offsetWidth || 330;
@@ -11406,6 +12139,7 @@ function OhhwellsBridge() {
11406
12139
  window.addEventListener("message", handleRemoveSchedulingSection);
11407
12140
  window.addEventListener("message", handleImageUrl);
11408
12141
  window.addEventListener("message", handleImageUploading);
12142
+ window.addEventListener("message", handleCarouselChange);
11409
12143
  window.addEventListener("message", handleCanvasHeight);
11410
12144
  window.addEventListener("message", handleParentScroll);
11411
12145
  window.addEventListener("message", handlePointerSync);
@@ -11423,6 +12157,7 @@ function OhhwellsBridge() {
11423
12157
  document.addEventListener("mouseover", handleMouseOver, true);
11424
12158
  document.addEventListener("mouseout", handleMouseOut, true);
11425
12159
  document.addEventListener("mousemove", handleMouseMove, true);
12160
+ document.addEventListener("mousemove", handleCarouselHover, true);
11426
12161
  document.addEventListener("mouseleave", handleDocMouseLeave);
11427
12162
  document.addEventListener("dragover", handleDragOver, true);
11428
12163
  document.addEventListener("dragleave", handleDragLeave, true);
@@ -11438,6 +12173,7 @@ function OhhwellsBridge() {
11438
12173
  document.removeEventListener("mouseover", handleMouseOver, true);
11439
12174
  document.removeEventListener("mouseout", handleMouseOut, true);
11440
12175
  document.removeEventListener("mousemove", handleMouseMove, true);
12176
+ document.removeEventListener("mousemove", handleCarouselHover, true);
11441
12177
  document.removeEventListener("mouseleave", handleDocMouseLeave);
11442
12178
  document.removeEventListener("dragover", handleDragOver, true);
11443
12179
  document.removeEventListener("dragleave", handleDragLeave, true);
@@ -11453,6 +12189,7 @@ function OhhwellsBridge() {
11453
12189
  window.removeEventListener("message", handleRemoveSchedulingSection);
11454
12190
  window.removeEventListener("message", handleImageUrl);
11455
12191
  window.removeEventListener("message", handleImageUploading);
12192
+ window.removeEventListener("message", handleCarouselChange);
11456
12193
  window.removeEventListener("message", handleCanvasHeight);
11457
12194
  window.removeEventListener("message", handleParentScroll);
11458
12195
  window.removeEventListener("resize", handleViewportResize);
@@ -11467,7 +12204,7 @@ function OhhwellsBridge() {
11467
12204
  if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
11468
12205
  };
11469
12206
  }, [isEditMode, refreshStateRules]);
11470
- useEffect8(() => {
12207
+ useEffect9(() => {
11471
12208
  if (!isEditMode) return;
11472
12209
  const THRESHOLD = 10;
11473
12210
  const resolveWasSelected = (el) => {
@@ -11490,7 +12227,6 @@ function OhhwellsBridge() {
11490
12227
  const anchor = getNavigationItemAnchor(target);
11491
12228
  const hrefKey = anchor?.getAttribute("data-ohw-href-key") ?? null;
11492
12229
  if (anchor && isFooterHrefKey(hrefKey)) {
11493
- armFooterPressDrag();
11494
12230
  footerPointerDragRef.current = {
11495
12231
  el: anchor,
11496
12232
  kind: "link",
@@ -11504,7 +12240,6 @@ function OhhwellsBridge() {
11504
12240
  }
11505
12241
  const col = target.closest("[data-ohw-footer-col]");
11506
12242
  if (col && !getNavigationItemAnchor(target)) {
11507
- armFooterPressDrag();
11508
12243
  footerPointerDragRef.current = {
11509
12244
  el: col,
11510
12245
  kind: "column",
@@ -11533,6 +12268,7 @@ function OhhwellsBridge() {
11533
12268
  if (dx * dx + dy * dy < THRESHOLD * THRESHOLD) return;
11534
12269
  e.preventDefault();
11535
12270
  pending.started = true;
12271
+ armFooterPressDrag();
11536
12272
  clearTextSelection();
11537
12273
  try {
11538
12274
  document.body.setPointerCapture(pending.pointerId);
@@ -11586,7 +12322,8 @@ function OhhwellsBridge() {
11586
12322
  }
11587
12323
  } catch {
11588
12324
  }
11589
- if (!pending?.started) {
12325
+ if (!pending) return;
12326
+ if (!pending.started) {
11590
12327
  unlockFooterDragInteraction();
11591
12328
  return;
11592
12329
  }
@@ -11621,7 +12358,7 @@ function OhhwellsBridge() {
11621
12358
  unlockFooterDragInteraction();
11622
12359
  };
11623
12360
  }, [isEditMode]);
11624
- useEffect8(() => {
12361
+ useEffect9(() => {
11625
12362
  const handler = (e) => {
11626
12363
  if (e.data?.type !== "ow:request-schedule-config") return;
11627
12364
  const insertAfterVal = e.data.insertAfter;
@@ -11637,7 +12374,7 @@ function OhhwellsBridge() {
11637
12374
  window.addEventListener("message", handler);
11638
12375
  return () => window.removeEventListener("message", handler);
11639
12376
  }, [processConfigRequest]);
11640
- useEffect8(() => {
12377
+ useEffect9(() => {
11641
12378
  if (!isEditMode) return;
11642
12379
  document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
11643
12380
  el.removeAttribute("data-ohw-active-state");
@@ -11672,19 +12409,49 @@ function OhhwellsBridge() {
11672
12409
  clearTimeout(timer);
11673
12410
  };
11674
12411
  }, [pathname, isEditMode, refreshStateRules, postToParent2]);
11675
- useEffect8(() => {
12412
+ useEffect9(() => {
11676
12413
  scrollToHashSectionWhenReady();
11677
12414
  const onHashChange = () => scrollToHashSectionWhenReady();
11678
12415
  window.addEventListener("hashchange", onHashChange);
11679
12416
  return () => window.removeEventListener("hashchange", onHashChange);
11680
12417
  }, [pathname]);
11681
- const handleCommand = useCallback4((cmd) => {
12418
+ const handleCommand = useCallback5((cmd) => {
12419
+ const el = activeElRef.current;
12420
+ const selBefore = window.getSelection();
12421
+ let savedOffsets = null;
12422
+ if (el && selBefore && selBefore.rangeCount > 0 && !selBefore.isCollapsed) {
12423
+ const r2 = selBefore.getRangeAt(0);
12424
+ if (el.contains(r2.commonAncestorContainer)) {
12425
+ savedOffsets = {
12426
+ start: textOffsetInRoot(el, r2.startContainer, r2.startOffset),
12427
+ end: textOffsetInRoot(el, r2.endContainer, r2.endOffset)
12428
+ };
12429
+ }
12430
+ }
12431
+ document.execCommand("styleWithCSS", false, true);
11682
12432
  document.execCommand(cmd, false);
11683
- activeElRef.current?.focus();
11684
- if (activeElRef.current) setToolbarRect(getEditMeasureEl(activeElRef.current).getBoundingClientRect());
12433
+ if (el && document.activeElement !== el) {
12434
+ el.focus();
12435
+ }
12436
+ const selAfter = window.getSelection();
12437
+ if (el && savedOffsets && selAfter?.isCollapsed) {
12438
+ const start = pointAtTextOffset(el, savedOffsets.start);
12439
+ const end = pointAtTextOffset(el, savedOffsets.end);
12440
+ if (start && end) {
12441
+ try {
12442
+ const range = document.createRange();
12443
+ range.setStart(start.node, start.offset);
12444
+ range.setEnd(end.node, end.offset);
12445
+ selAfter.removeAllRanges();
12446
+ selAfter.addRange(range);
12447
+ } catch {
12448
+ }
12449
+ }
12450
+ }
12451
+ if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
11685
12452
  refreshActiveCommandsRef.current();
11686
12453
  }, []);
11687
- const handleStateChange = useCallback4((state) => {
12454
+ const handleStateChange = useCallback5((state) => {
11688
12455
  if (!activeStateElRef.current) return;
11689
12456
  const el = activeStateElRef.current;
11690
12457
  if (state === "Default") {
@@ -11697,11 +12464,11 @@ function OhhwellsBridge() {
11697
12464
  }
11698
12465
  setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
11699
12466
  }, [deactivate]);
11700
- const closeLinkPopover = useCallback4(() => {
12467
+ const closeLinkPopover = useCallback5(() => {
11701
12468
  addNavAfterAnchorRef.current = null;
11702
12469
  setLinkPopover(null);
11703
12470
  }, []);
11704
- const openLinkPopoverForActive = useCallback4(() => {
12471
+ const openLinkPopoverForActive = useCallback5(() => {
11705
12472
  const hrefCtx = getHrefKeyFromElement(activeElRef.current);
11706
12473
  if (!hrefCtx) return;
11707
12474
  bumpLinkPopoverGrace();
@@ -11712,7 +12479,7 @@ function OhhwellsBridge() {
11712
12479
  });
11713
12480
  deactivate();
11714
12481
  }, [deactivate]);
11715
- const openLinkPopoverForSelected = useCallback4(() => {
12482
+ const openLinkPopoverForSelected = useCallback5(() => {
11716
12483
  const anchor = selectedElRef.current;
11717
12484
  if (!anchor) return;
11718
12485
  const key = anchor.getAttribute("data-ohw-href-key");
@@ -11725,7 +12492,7 @@ function OhhwellsBridge() {
11725
12492
  });
11726
12493
  deselect();
11727
12494
  }, [deselect]);
11728
- const handleLinkPopoverSubmit = useCallback4(
12495
+ const handleLinkPopoverSubmit = useCallback5(
11729
12496
  (target) => {
11730
12497
  const session = linkPopoverSessionRef.current;
11731
12498
  if (!session) return;
@@ -11784,13 +12551,19 @@ function OhhwellsBridge() {
11784
12551
  const showEditLink = toolbarShowEditLink;
11785
12552
  const currentSections = sectionsByPath[pathname] ?? [];
11786
12553
  linkPopoverOpenRef.current = linkPopover !== null;
11787
- const handleMediaReplace = useCallback4(
12554
+ const handleMediaReplace = useCallback5(
11788
12555
  (key) => {
11789
12556
  postToParent2({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
11790
12557
  },
11791
12558
  [postToParent2, mediaHover?.elementType]
11792
12559
  );
11793
- 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) => {
11794
12567
  setUploadingRects((prev) => {
11795
12568
  if (!(key in prev)) return prev;
11796
12569
  const next = { ...prev };
@@ -11798,7 +12571,7 @@ function OhhwellsBridge() {
11798
12571
  return next;
11799
12572
  });
11800
12573
  }, []);
11801
- const handleVideoSettingsChange = useCallback4(
12574
+ const handleVideoSettingsChange = useCallback5(
11802
12575
  (key, settings) => {
11803
12576
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
11804
12577
  const video = getVideoEl(el);
@@ -11821,9 +12594,9 @@ function OhhwellsBridge() {
11821
12594
  [postToParent2]
11822
12595
  );
11823
12596
  return bridgeRoot ? createPortal2(
11824
- /* @__PURE__ */ jsxs13(Fragment5, { children: [
11825
- /* @__PURE__ */ jsx24("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
11826
- 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(
11827
12600
  MediaOverlay,
11828
12601
  {
11829
12602
  hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
@@ -11834,7 +12607,7 @@ function OhhwellsBridge() {
11834
12607
  },
11835
12608
  `uploading-${key}`
11836
12609
  )),
11837
- mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ jsx24(
12610
+ mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ jsx26(
11838
12611
  MediaOverlay,
11839
12612
  {
11840
12613
  hover: mediaHover,
@@ -11843,10 +12616,11 @@ function OhhwellsBridge() {
11843
12616
  onVideoSettingsChange: handleVideoSettingsChange
11844
12617
  }
11845
12618
  ),
11846
- siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ jsx24(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
11847
- siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ jsx24(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
11848
- isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ jsx24(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
11849
- 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(
11850
12624
  "div",
11851
12625
  {
11852
12626
  className: "pointer-events-none fixed z-2147483646",
@@ -11856,7 +12630,7 @@ function OhhwellsBridge() {
11856
12630
  width: slot.width,
11857
12631
  height: slot.height
11858
12632
  },
11859
- children: /* @__PURE__ */ jsx24(
12633
+ children: /* @__PURE__ */ jsx26(
11860
12634
  DropIndicator,
11861
12635
  {
11862
12636
  direction: slot.direction,
@@ -11867,7 +12641,7 @@ function OhhwellsBridge() {
11867
12641
  },
11868
12642
  `footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
11869
12643
  )),
11870
- isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ jsx24(
12644
+ isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ jsx26(
11871
12645
  "div",
11872
12646
  {
11873
12647
  className: "pointer-events-none fixed z-2147483646",
@@ -11877,7 +12651,7 @@ function OhhwellsBridge() {
11877
12651
  width: slot.width,
11878
12652
  height: slot.height
11879
12653
  },
11880
- children: /* @__PURE__ */ jsx24(
12654
+ children: /* @__PURE__ */ jsx26(
11881
12655
  DropIndicator,
11882
12656
  {
11883
12657
  direction: slot.direction,
@@ -11888,10 +12662,11 @@ function OhhwellsBridge() {
11888
12662
  },
11889
12663
  `nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
11890
12664
  )),
11891
- hoveredNavContainerRect && toolbarVariant !== "select-frame" && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx24(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
11892
- hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx24(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
11893
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer(selectedElRef.current) && /* @__PURE__ */ jsx24(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
11894
- 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(
11895
12670
  ItemInteractionLayer,
11896
12671
  {
11897
12672
  rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
@@ -11905,7 +12680,7 @@ function OhhwellsBridge() {
11905
12680
  onItemPointerDown: handleItemChromePointerDown,
11906
12681
  onItemClick: handleItemChromeClick,
11907
12682
  itemDragSurface: !isFooterFrameSelection,
11908
- toolbar: toolbarVariant === "link-action" && !isItemDragging ? /* @__PURE__ */ jsx24(
12683
+ toolbar: toolbarVariant === "link-action" && !isItemDragging ? /* @__PURE__ */ jsx26(
11909
12684
  ItemActionToolbar,
11910
12685
  {
11911
12686
  onEditLink: openLinkPopoverForSelected,
@@ -11918,8 +12693,8 @@ function OhhwellsBridge() {
11918
12693
  ) : void 0
11919
12694
  }
11920
12695
  ),
11921
- toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ jsxs13(Fragment5, { children: [
11922
- /* @__PURE__ */ jsx24(
12696
+ toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ jsxs15(Fragment5, { children: [
12697
+ /* @__PURE__ */ jsx26(
11923
12698
  EditGlowChrome,
11924
12699
  {
11925
12700
  rect: toolbarRect,
@@ -11929,7 +12704,7 @@ function OhhwellsBridge() {
11929
12704
  hideHandle: isItemDragging
11930
12705
  }
11931
12706
  ),
11932
- /* @__PURE__ */ jsx24(
12707
+ /* @__PURE__ */ jsx26(
11933
12708
  FloatingToolbar,
11934
12709
  {
11935
12710
  rect: toolbarRect,
@@ -11942,7 +12717,7 @@ function OhhwellsBridge() {
11942
12717
  }
11943
12718
  )
11944
12719
  ] }),
11945
- maxBadge && /* @__PURE__ */ jsxs13(
12720
+ maxBadge && /* @__PURE__ */ jsxs15(
11946
12721
  "div",
11947
12722
  {
11948
12723
  "data-ohw-max-badge": "",
@@ -11968,7 +12743,7 @@ function OhhwellsBridge() {
11968
12743
  ]
11969
12744
  }
11970
12745
  ),
11971
- toggleState && !linkPopover && /* @__PURE__ */ jsx24(
12746
+ toggleState && !linkPopover && /* @__PURE__ */ jsx26(
11972
12747
  StateToggle,
11973
12748
  {
11974
12749
  rect: toggleState.rect,
@@ -11977,15 +12752,15 @@ function OhhwellsBridge() {
11977
12752
  onStateChange: handleStateChange
11978
12753
  }
11979
12754
  ),
11980
- sectionGap && !linkPopover && /* @__PURE__ */ jsxs13(
12755
+ sectionGap && !linkPopover && /* @__PURE__ */ jsxs15(
11981
12756
  "div",
11982
12757
  {
11983
12758
  "data-ohw-section-insert-line": "",
11984
12759
  className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
11985
12760
  style: { top: sectionGap.y, transform: "translateY(-50%)" },
11986
12761
  children: [
11987
- /* @__PURE__ */ jsx24("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
11988
- /* @__PURE__ */ jsx24(
12762
+ /* @__PURE__ */ jsx26("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
12763
+ /* @__PURE__ */ jsx26(
11989
12764
  Badge,
11990
12765
  {
11991
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",
@@ -12002,11 +12777,11 @@ function OhhwellsBridge() {
12002
12777
  children: "Add Section"
12003
12778
  }
12004
12779
  ),
12005
- /* @__PURE__ */ jsx24("div", { className: "flex-1 bg-primary", style: { height: 3 } })
12780
+ /* @__PURE__ */ jsx26("div", { className: "flex-1 bg-primary", style: { height: 3 } })
12006
12781
  ]
12007
12782
  }
12008
12783
  ),
12009
- linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx24(
12784
+ linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx26(
12010
12785
  LinkPopover,
12011
12786
  {
12012
12787
  panelRef: linkPopoverPanelRef,
@@ -12054,6 +12829,7 @@ export {
12054
12829
  isValidUrl,
12055
12830
  parseTarget,
12056
12831
  toggleVariants,
12832
+ useOhwCarousel,
12057
12833
  validateUrlInput
12058
12834
  };
12059
12835
  //# sourceMappingURL=index.js.map