@ohhwells/bridge 0.1.48 → 0.1.49-next.114

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 useEffect9, useLayoutEffect as useLayoutEffect3, useRef as useRef7, useState as useState8 } from "react";
4
+ import React11, { useCallback as useCallback5, useEffect as useEffect9, useLayoutEffect as useLayoutEffect3, useRef as useRef7, useState as useState9 } 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: [
@@ -4282,22 +4338,116 @@ var CustomToolbarButton = React4.forwardRef(
4282
4338
  CustomToolbarButton.displayName = "CustomToolbarButton";
4283
4339
 
4284
4340
  // src/ui/item-action-toolbar.tsx
4285
- import { Link, MoreHorizontal, Plus } from "lucide-react";
4341
+ import { useState as useState3 } from "react";
4342
+ import { Copy, CornerLeftUp, Link, MoreHorizontal, Plus, Trash2 } from "lucide-react";
4343
+
4344
+ // src/ui/dropdown-menu.tsx
4345
+ import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui";
4346
+ import { jsx as jsx7 } from "react/jsx-runtime";
4347
+ function DropdownMenu({ ...props }) {
4348
+ return /* @__PURE__ */ jsx7(DropdownMenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
4349
+ }
4350
+ function DropdownMenuTrigger({
4351
+ ...props
4352
+ }) {
4353
+ return /* @__PURE__ */ jsx7(DropdownMenuPrimitive.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
4354
+ }
4355
+ function DropdownMenuGroup({
4356
+ className,
4357
+ ...props
4358
+ }) {
4359
+ return /* @__PURE__ */ jsx7(
4360
+ DropdownMenuPrimitive.Group,
4361
+ {
4362
+ "data-slot": "dropdown-menu-group",
4363
+ className: cn("flex w-full flex-col items-start p-1", className),
4364
+ ...props
4365
+ }
4366
+ );
4367
+ }
4368
+ function DropdownMenuContent({
4369
+ className,
4370
+ sideOffset = 6,
4371
+ ...props
4372
+ }) {
4373
+ return /* @__PURE__ */ jsx7(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx7(
4374
+ DropdownMenuPrimitive.Content,
4375
+ {
4376
+ "data-slot": "dropdown-menu-content",
4377
+ "data-ohw-more-menu": "",
4378
+ sideOffset,
4379
+ className: cn(
4380
+ "z-[2147483647] flex w-56 min-w-32 flex-col items-center overflow-hidden rounded-[6px] border border-border bg-popover p-0 text-popover-foreground outline-none",
4381
+ "shadow-[0px_4px_6px_0px_rgba(0,0,0,0.1),0px_2px_4px_0px_rgba(0,0,0,0.1)]",
4382
+ "origin-[var(--radix-dropdown-menu-content-transform-origin)]",
4383
+ "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
4384
+ "data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
4385
+ className
4386
+ ),
4387
+ ...props
4388
+ }
4389
+ ) });
4390
+ }
4391
+ function DropdownMenuItem({
4392
+ className,
4393
+ inset,
4394
+ variant = "default",
4395
+ ...props
4396
+ }) {
4397
+ return /* @__PURE__ */ jsx7(
4398
+ DropdownMenuPrimitive.Item,
4399
+ {
4400
+ "data-slot": "dropdown-menu-item",
4401
+ "data-inset": inset ? "" : void 0,
4402
+ "data-variant": variant,
4403
+ className: cn(
4404
+ "relative flex w-full min-w-32 cursor-pointer select-none items-center gap-2 rounded-[calc(var(--radius,0.5rem)-4px)] py-1.5 pl-8 pr-2 text-sm leading-5 outline-none",
4405
+ "text-popover-foreground",
4406
+ "focus:bg-muted data-[highlighted]:bg-muted",
4407
+ "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
4408
+ "[&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
4409
+ "[&_svg:not([class*=absolute])]:relative",
4410
+ // Leading icon — Figma absolute left-2 / top-1/2
4411
+ "[&>svg:first-child]:absolute [&>svg:first-child]:left-2 [&>svg:first-child]:top-1/2 [&>svg:first-child]:-translate-y-1/2",
4412
+ "data-[variant=destructive]:text-destructive",
4413
+ "data-[variant=destructive]:focus:bg-bg-destructive-10 data-[variant=destructive]:focus:text-destructive",
4414
+ "data-[variant=destructive]:data-[highlighted]:bg-bg-destructive-10 data-[variant=destructive]:data-[highlighted]:text-destructive",
4415
+ "data-[variant=destructive]:[&_svg]:text-destructive",
4416
+ inset && "pl-8",
4417
+ className
4418
+ ),
4419
+ ...props
4420
+ }
4421
+ );
4422
+ }
4423
+ function DropdownMenuSeparator({
4424
+ className,
4425
+ ...props
4426
+ }) {
4427
+ return /* @__PURE__ */ jsx7(
4428
+ DropdownMenuPrimitive.Separator,
4429
+ {
4430
+ "data-slot": "dropdown-menu-separator",
4431
+ className: cn("h-px w-full bg-border", className),
4432
+ ...props
4433
+ }
4434
+ );
4435
+ }
4286
4436
 
4287
4437
  // src/ui/tooltip.tsx
4288
4438
  import { Tooltip as TooltipPrimitive } from "radix-ui";
4289
- import { jsx as jsx7 } from "react/jsx-runtime";
4439
+ import { jsx as jsx8 } from "react/jsx-runtime";
4290
4440
  function TooltipProvider({
4291
4441
  delayDuration = 0,
4292
4442
  ...props
4293
4443
  }) {
4294
- return /* @__PURE__ */ jsx7(TooltipPrimitive.Provider, { "data-slot": "tooltip-provider", delayDuration, ...props });
4444
+ return /* @__PURE__ */ jsx8(TooltipPrimitive.Provider, { "data-slot": "tooltip-provider", delayDuration, ...props });
4295
4445
  }
4296
4446
  function Tooltip({ ...props }) {
4297
- return /* @__PURE__ */ jsx7(TooltipPrimitive.Root, { "data-slot": "tooltip", ...props });
4447
+ return /* @__PURE__ */ jsx8(TooltipPrimitive.Root, { "data-slot": "tooltip", ...props });
4298
4448
  }
4299
4449
  function TooltipTrigger({ ...props }) {
4300
- return /* @__PURE__ */ jsx7(TooltipPrimitive.Trigger, { "data-slot": "tooltip-trigger", ...props });
4450
+ return /* @__PURE__ */ jsx8(TooltipPrimitive.Trigger, { "data-slot": "tooltip-trigger", ...props });
4301
4451
  }
4302
4452
  var arrowClassBySide = {
4303
4453
  top: "before:bottom-0 before:left-1/2 before:-translate-x-1/2 before:translate-y-1/2",
@@ -4314,7 +4464,7 @@ function TooltipContent({
4314
4464
  ...props
4315
4465
  }) {
4316
4466
  const resolvedSide = side ?? "bottom";
4317
- return /* @__PURE__ */ jsx7(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsx7(
4467
+ return /* @__PURE__ */ jsx8(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsx8(
4318
4468
  TooltipPrimitive.Content,
4319
4469
  {
4320
4470
  "data-slot": "tooltip-content",
@@ -4337,7 +4487,7 @@ function TooltipContent({
4337
4487
  }
4338
4488
 
4339
4489
  // src/ui/item-action-toolbar.tsx
4340
- import { jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
4490
+ import { jsx as jsx9, jsxs as jsxs3 } from "react/jsx-runtime";
4341
4491
  function ToolbarActionTooltip({
4342
4492
  label,
4343
4493
  side = "bottom",
@@ -4345,25 +4495,31 @@ function ToolbarActionTooltip({
4345
4495
  buttonProps,
4346
4496
  children
4347
4497
  }) {
4348
- const button = /* @__PURE__ */ jsx8(CustomToolbarButton, { type: "button", "aria-label": label, disabled, ...buttonProps, children });
4498
+ const button = /* @__PURE__ */ jsx9(CustomToolbarButton, { type: "button", "aria-label": label, disabled, ...buttonProps, children });
4349
4499
  return /* @__PURE__ */ jsxs3(Tooltip, { children: [
4350
- /* @__PURE__ */ jsx8(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ jsx8("span", { className: "inline-flex", children: button }) : button }),
4351
- /* @__PURE__ */ jsx8(TooltipContent, { side, sideOffset: 9, children: label })
4500
+ /* @__PURE__ */ jsx9(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ jsx9("span", { className: "inline-flex", children: button }) : button }),
4501
+ /* @__PURE__ */ jsx9(TooltipContent, { side, sideOffset: 9, children: label })
4352
4502
  ] });
4353
4503
  }
4354
4504
  function ItemActionToolbar({
4355
4505
  onEditLink,
4356
4506
  onAddItem,
4357
- onMore,
4507
+ onSelectParent,
4508
+ onDuplicate,
4509
+ onDelete,
4358
4510
  editLinkDisabled = false,
4359
4511
  addItemDisabled = true,
4360
- moreDisabled = true,
4512
+ moreDisabled = false,
4513
+ selectParentDisabled = false,
4514
+ duplicateDisabled = false,
4515
+ deleteDisabled = false,
4361
4516
  showAddItem = true,
4362
4517
  showMore = true,
4363
4518
  tooltipSide = "bottom"
4364
4519
  }) {
4365
- return /* @__PURE__ */ jsx8(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs3(CustomToolbar, { children: [
4366
- /* @__PURE__ */ jsx8(
4520
+ const [moreOpen, setMoreOpen] = useState3(false);
4521
+ return /* @__PURE__ */ jsx9(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs3(CustomToolbar, { children: [
4522
+ /* @__PURE__ */ jsx9(
4367
4523
  ToolbarActionTooltip,
4368
4524
  {
4369
4525
  label: "Edit link",
@@ -4381,10 +4537,10 @@ function ItemActionToolbar({
4381
4537
  e.stopPropagation();
4382
4538
  }
4383
4539
  },
4384
- children: /* @__PURE__ */ jsx8(Link, { className: "size-4 shrink-0", "aria-hidden": true })
4540
+ children: /* @__PURE__ */ jsx9(Link, { className: "size-4 shrink-0", "aria-hidden": true })
4385
4541
  }
4386
4542
  ),
4387
- showAddItem ? /* @__PURE__ */ jsx8(
4543
+ showAddItem ? /* @__PURE__ */ jsx9(
4388
4544
  ToolbarActionTooltip,
4389
4545
  {
4390
4546
  label: "Add item",
@@ -4398,32 +4554,84 @@ function ItemActionToolbar({
4398
4554
  onAddItem?.();
4399
4555
  }
4400
4556
  },
4401
- children: /* @__PURE__ */ jsx8(Plus, { className: "size-4 shrink-0", "aria-hidden": true })
4557
+ children: /* @__PURE__ */ jsx9(Plus, { className: "size-4 shrink-0", "aria-hidden": true })
4402
4558
  }
4403
4559
  ) : null,
4404
- showMore ? /* @__PURE__ */ jsx8(
4405
- ToolbarActionTooltip,
4406
- {
4407
- label: "More",
4408
- side: tooltipSide,
4409
- disabled: moreDisabled,
4410
- buttonProps: {
4560
+ showMore ? /* @__PURE__ */ jsxs3(DropdownMenu, { open: moreOpen, onOpenChange: setMoreOpen, children: [
4561
+ /* @__PURE__ */ jsxs3(Tooltip, { open: moreOpen ? false : void 0, children: [
4562
+ /* @__PURE__ */ jsx9(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx9(DropdownMenuTrigger, { asChild: true, disabled: moreDisabled, children: /* @__PURE__ */ jsx9(
4563
+ CustomToolbarButton,
4564
+ {
4565
+ type: "button",
4566
+ "aria-label": "More",
4567
+ disabled: moreDisabled,
4568
+ onMouseDown: (e) => {
4569
+ e.preventDefault();
4570
+ e.stopPropagation();
4571
+ },
4572
+ children: /* @__PURE__ */ jsx9(MoreHorizontal, { className: "size-4 shrink-0", "aria-hidden": true })
4573
+ }
4574
+ ) }) }),
4575
+ /* @__PURE__ */ jsx9(TooltipContent, { side: tooltipSide, sideOffset: 9, children: "More" })
4576
+ ] }),
4577
+ /* @__PURE__ */ jsxs3(
4578
+ DropdownMenuContent,
4579
+ {
4580
+ align: "end",
4581
+ side: "bottom",
4582
+ onCloseAutoFocus: (e) => e.preventDefault(),
4411
4583
  onMouseDown: (e) => {
4412
- if (moreDisabled) return;
4413
4584
  e.preventDefault();
4414
4585
  e.stopPropagation();
4415
- onMore?.();
4416
- }
4417
- },
4418
- children: /* @__PURE__ */ jsx8(MoreHorizontal, { className: "size-4 shrink-0", "aria-hidden": true })
4419
- }
4420
- ) : null
4586
+ },
4587
+ children: [
4588
+ /* @__PURE__ */ jsxs3(DropdownMenuGroup, { children: [
4589
+ /* @__PURE__ */ jsxs3(
4590
+ DropdownMenuItem,
4591
+ {
4592
+ disabled: selectParentDisabled,
4593
+ onSelect: () => onSelectParent?.(),
4594
+ children: [
4595
+ /* @__PURE__ */ jsx9(CornerLeftUp, { size: 12, "aria-hidden": true }),
4596
+ "Select parent"
4597
+ ]
4598
+ }
4599
+ ),
4600
+ /* @__PURE__ */ jsxs3(
4601
+ DropdownMenuItem,
4602
+ {
4603
+ disabled: duplicateDisabled,
4604
+ onSelect: () => onDuplicate?.(),
4605
+ children: [
4606
+ /* @__PURE__ */ jsx9(Copy, { size: 12, "aria-hidden": true }),
4607
+ "Duplicate"
4608
+ ]
4609
+ }
4610
+ )
4611
+ ] }),
4612
+ /* @__PURE__ */ jsx9(DropdownMenuSeparator, {}),
4613
+ /* @__PURE__ */ jsx9(DropdownMenuGroup, { children: /* @__PURE__ */ jsxs3(
4614
+ DropdownMenuItem,
4615
+ {
4616
+ variant: "destructive",
4617
+ disabled: deleteDisabled,
4618
+ onSelect: () => onDelete?.(),
4619
+ children: [
4620
+ /* @__PURE__ */ jsx9(Trash2, { size: 15, "aria-hidden": true }),
4621
+ "Delete"
4622
+ ]
4623
+ }
4624
+ ) })
4625
+ ]
4626
+ }
4627
+ )
4628
+ ] }) : null
4421
4629
  ] }) });
4422
4630
  }
4423
4631
 
4424
4632
  // src/ui/item-interaction-layer.tsx
4425
4633
  import * as React5 from "react";
4426
- import { jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
4634
+ import { jsx as jsx10, jsxs as jsxs4 } from "react/jsx-runtime";
4427
4635
  var PRIMARY = "var(--ohw-primary, #0885FE)";
4428
4636
  var FOCUS_RING = `0 0 0 4px color-mix(in srgb, ${PRIMARY} 12%, transparent)`;
4429
4637
  var DRAG_SHADOW = "0px 4px 6px -1px rgba(0, 0, 0, 0.1), 0px 2px 4px -2px rgba(0, 0, 0, 0.1)";
@@ -4505,7 +4713,7 @@ function ClampedToolbarSlot({
4505
4713
  window.removeEventListener("resize", clamp);
4506
4714
  };
4507
4715
  }, [placement, children]);
4508
- return /* @__PURE__ */ jsx9(
4716
+ return /* @__PURE__ */ jsx10(
4509
4717
  "div",
4510
4718
  {
4511
4719
  ref: slotRef,
@@ -4561,7 +4769,7 @@ function ItemInteractionLayer({
4561
4769
  zIndex: getChromeZIndex(state)
4562
4770
  },
4563
4771
  children: [
4564
- /* @__PURE__ */ jsx9(
4772
+ /* @__PURE__ */ jsx10(
4565
4773
  "div",
4566
4774
  {
4567
4775
  "aria-hidden": true,
@@ -4569,7 +4777,7 @@ function ItemInteractionLayer({
4569
4777
  style: getChromeStyle(state)
4570
4778
  }
4571
4779
  ),
4572
- itemDragEnabled && /* @__PURE__ */ jsx9(
4780
+ itemDragEnabled && /* @__PURE__ */ jsx10(
4573
4781
  "div",
4574
4782
  {
4575
4783
  "data-ohw-item-drag-surface": "",
@@ -4585,14 +4793,14 @@ function ItemInteractionLayer({
4585
4793
  }
4586
4794
  }
4587
4795
  ),
4588
- showDragHandle && /* @__PURE__ */ jsx9(
4796
+ showDragHandle && /* @__PURE__ */ jsx10(
4589
4797
  "div",
4590
4798
  {
4591
4799
  "data-ohw-drag-handle-container": "",
4592
4800
  className: "pointer-events-auto absolute left-0 top-1/2 z-10 -translate-x-[calc(100%+7px)] -translate-y-1/2",
4593
4801
  style: isDragging ? { opacity: 0 } : void 0,
4594
4802
  "aria-hidden": isDragging || void 0,
4595
- children: /* @__PURE__ */ jsx9(
4803
+ children: /* @__PURE__ */ jsx10(
4596
4804
  DragHandle,
4597
4805
  {
4598
4806
  draggable: !dragDisabled,
@@ -4622,8 +4830,8 @@ function ItemInteractionLayer({
4622
4830
  )
4623
4831
  }
4624
4832
  ),
4625
- showToolbar && state === "active-top" && /* @__PURE__ */ jsx9(ClampedToolbarSlot, { placement: "top", children: toolbar }),
4626
- showToolbar && state === "active-bottom" && /* @__PURE__ */ jsx9(ClampedToolbarSlot, { placement: "bottom", children: toolbar })
4833
+ showToolbar && state === "active-top" && /* @__PURE__ */ jsx10(ClampedToolbarSlot, { placement: "top", children: toolbar }),
4834
+ showToolbar && state === "active-bottom" && /* @__PURE__ */ jsx10(ClampedToolbarSlot, { placement: "bottom", children: toolbar })
4627
4835
  ]
4628
4836
  }
4629
4837
  );
@@ -4636,7 +4844,7 @@ import { Film, ImageIcon, Pause, Play, Volume2, VolumeX } from "lucide-react";
4636
4844
  // src/ui/button.tsx
4637
4845
  import * as React6 from "react";
4638
4846
  import { Slot } from "radix-ui";
4639
- import { jsx as jsx10 } from "react/jsx-runtime";
4847
+ import { jsx as jsx11 } from "react/jsx-runtime";
4640
4848
  var buttonVariants = cva(
4641
4849
  "inline-flex items-center justify-center gap-1 whitespace-nowrap rounded-md text-sm font-medium transition-colors outline-none disabled:pointer-events-none disabled:opacity-50 min-w-[80px] px-3 py-2",
4642
4850
  {
@@ -4660,7 +4868,7 @@ var buttonVariants = cva(
4660
4868
  var Button = React6.forwardRef(
4661
4869
  ({ className, variant, size, asChild = false, ...props }, ref) => {
4662
4870
  const Comp = asChild ? Slot.Root : "button";
4663
- return /* @__PURE__ */ jsx10(
4871
+ return /* @__PURE__ */ jsx11(
4664
4872
  Comp,
4665
4873
  {
4666
4874
  ref,
@@ -4674,7 +4882,7 @@ var Button = React6.forwardRef(
4674
4882
  Button.displayName = "Button";
4675
4883
 
4676
4884
  // src/ui/MediaOverlay.tsx
4677
- import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
4885
+ import { Fragment as Fragment2, jsx as jsx12, jsxs as jsxs5 } from "react/jsx-runtime";
4678
4886
  var MEDIA_UPLOAD_FADE_MS = 300;
4679
4887
  var VIDEO_SETTINGS_BAR_INSET = 8;
4680
4888
  var OVERLAY_BUTTON_STYLE = {
@@ -4732,7 +4940,7 @@ function MediaOverlay({
4732
4940
  return () => anim.cancel();
4733
4941
  }, [isUploading, fadingOut, onFadeOutComplete, hover.key]);
4734
4942
  if (isUploading) {
4735
- return /* @__PURE__ */ jsx11(
4943
+ return /* @__PURE__ */ jsx12(
4736
4944
  "div",
4737
4945
  {
4738
4946
  ref: skeletonRef,
@@ -4741,7 +4949,7 @@ function MediaOverlay({
4741
4949
  "data-ohw-media-skeleton": "",
4742
4950
  "aria-hidden": true,
4743
4951
  style: { ...box, pointerEvents: "none" },
4744
- children: /* @__PURE__ */ jsx11("style", { children: SKELETON_CSS })
4952
+ children: /* @__PURE__ */ jsx12("style", { children: SKELETON_CSS })
4745
4953
  }
4746
4954
  );
4747
4955
  }
@@ -4761,7 +4969,7 @@ function MediaOverlay({
4761
4969
  },
4762
4970
  onClick: (e) => e.stopPropagation(),
4763
4971
  children: [
4764
- /* @__PURE__ */ jsx11(
4972
+ /* @__PURE__ */ jsx12(
4765
4973
  Button,
4766
4974
  {
4767
4975
  "data-ohw-media-overlay": "",
@@ -4776,10 +4984,10 @@ function MediaOverlay({
4776
4984
  e.stopPropagation();
4777
4985
  onVideoSettingsChange?.(hover.key, { autoplay: !autoplay });
4778
4986
  },
4779
- children: autoplay ? /* @__PURE__ */ jsx11(Pause, { size: 14 }) : /* @__PURE__ */ jsx11(Play, { size: 14 })
4987
+ children: autoplay ? /* @__PURE__ */ jsx12(Pause, { size: 14 }) : /* @__PURE__ */ jsx12(Play, { size: 14 })
4780
4988
  }
4781
4989
  ),
4782
- /* @__PURE__ */ jsx11(
4990
+ /* @__PURE__ */ jsx12(
4783
4991
  Button,
4784
4992
  {
4785
4993
  "data-ohw-media-overlay": "",
@@ -4794,7 +5002,7 @@ function MediaOverlay({
4794
5002
  e.stopPropagation();
4795
5003
  onVideoSettingsChange?.(hover.key, { muted: !muted });
4796
5004
  },
4797
- children: muted ? /* @__PURE__ */ jsx11(VolumeX, { size: 14 }) : /* @__PURE__ */ jsx11(Volume2, { size: 14 })
5005
+ children: muted ? /* @__PURE__ */ jsx12(VolumeX, { size: 14 }) : /* @__PURE__ */ jsx12(Volume2, { size: 14 })
4798
5006
  }
4799
5007
  )
4800
5008
  ]
@@ -4802,7 +5010,7 @@ function MediaOverlay({
4802
5010
  ) : null;
4803
5011
  return /* @__PURE__ */ jsxs5(Fragment2, { children: [
4804
5012
  settingsBar,
4805
- /* @__PURE__ */ jsx11(
5013
+ /* @__PURE__ */ jsx12(
4806
5014
  "div",
4807
5015
  {
4808
5016
  "data-ohw-bridge": "",
@@ -4826,14 +5034,18 @@ function MediaOverlay({
4826
5034
  variant: "outline",
4827
5035
  size: "sm",
4828
5036
  className: "gap-1.5 cursor-pointer hover:bg-background",
4829
- style: OVERLAY_BUTTON_STYLE,
5037
+ style: {
5038
+ ...OVERLAY_BUTTON_STYLE,
5039
+ // Don't let Replace steal clicks when text (e.g. nav) sits on top of this media.
5040
+ pointerEvents: hover.hasTextOverlap ? "none" : "auto"
5041
+ },
4830
5042
  onMouseDown: (e) => e.preventDefault(),
4831
5043
  onClick: (e) => {
4832
5044
  e.stopPropagation();
4833
5045
  onReplace(hover.key);
4834
5046
  },
4835
5047
  children: [
4836
- isVideo ? /* @__PURE__ */ jsx11(Film, { size: 14 }) : /* @__PURE__ */ jsx11(ImageIcon, { size: 14 }),
5048
+ isVideo ? /* @__PURE__ */ jsx12(Film, { size: 14 }) : /* @__PURE__ */ jsx12(ImageIcon, { size: 14 }),
4837
5049
  isVideo ? "Replace video" : "Replace image"
4838
5050
  ]
4839
5051
  }
@@ -4845,7 +5057,7 @@ function MediaOverlay({
4845
5057
 
4846
5058
  // src/ui/CarouselOverlay.tsx
4847
5059
  import { GalleryHorizontal } from "lucide-react";
4848
- import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
5060
+ import { jsx as jsx13, jsxs as jsxs6 } from "react/jsx-runtime";
4849
5061
  var OVERLAY_BUTTON_STYLE2 = {
4850
5062
  pointerEvents: "auto",
4851
5063
  fontFamily: "Inter, sans-serif",
@@ -4857,7 +5069,7 @@ function CarouselOverlay({
4857
5069
  onEdit
4858
5070
  }) {
4859
5071
  const { rect } = hover;
4860
- return /* @__PURE__ */ jsx12(
5072
+ return /* @__PURE__ */ jsx13(
4861
5073
  "div",
4862
5074
  {
4863
5075
  "data-ohw-bridge": "",
@@ -4889,7 +5101,7 @@ function CarouselOverlay({
4889
5101
  onEdit(hover.key);
4890
5102
  },
4891
5103
  children: [
4892
- /* @__PURE__ */ jsx12(GalleryHorizontal, { size: 14 }),
5104
+ /* @__PURE__ */ jsx13(GalleryHorizontal, { size: 14 }),
4893
5105
  "Edit gallery"
4894
5106
  ]
4895
5107
  }
@@ -5184,22 +5396,22 @@ import { useEffect as useEffect6 } from "react";
5184
5396
  import * as React8 from "react";
5185
5397
  import { Dialog as DialogPrimitive } from "radix-ui";
5186
5398
  import { X } from "lucide-react";
5187
- import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
5399
+ import { jsx as jsx14, jsxs as jsxs7 } from "react/jsx-runtime";
5188
5400
  function Dialog2({
5189
5401
  ...props
5190
5402
  }) {
5191
- return /* @__PURE__ */ jsx13(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
5403
+ return /* @__PURE__ */ jsx14(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
5192
5404
  }
5193
5405
  function DialogPortal({
5194
5406
  ...props
5195
5407
  }) {
5196
- return /* @__PURE__ */ jsx13(DialogPrimitive.Portal, { ...props });
5408
+ return /* @__PURE__ */ jsx14(DialogPrimitive.Portal, { ...props });
5197
5409
  }
5198
5410
  function DialogOverlay({
5199
5411
  className,
5200
5412
  ...props
5201
5413
  }) {
5202
- return /* @__PURE__ */ jsx13(
5414
+ return /* @__PURE__ */ jsx14(
5203
5415
  DialogPrimitive.Overlay,
5204
5416
  {
5205
5417
  "data-slot": "dialog-overlay",
@@ -5213,7 +5425,7 @@ var DialogContent = React8.forwardRef(
5213
5425
  ({ className, children, showCloseButton = true, container, ...props }, ref) => {
5214
5426
  const positionMode = container ? "absolute" : "fixed";
5215
5427
  return /* @__PURE__ */ jsxs7(DialogPortal, { container: container ?? void 0, children: [
5216
- /* @__PURE__ */ jsx13(DialogOverlay, { className: cn(positionMode, "inset-0") }),
5428
+ /* @__PURE__ */ jsx14(DialogOverlay, { className: cn(positionMode, "inset-0") }),
5217
5429
  /* @__PURE__ */ jsxs7(
5218
5430
  DialogPrimitive.Content,
5219
5431
  {
@@ -5230,13 +5442,13 @@ var DialogContent = React8.forwardRef(
5230
5442
  ...props,
5231
5443
  children: [
5232
5444
  children,
5233
- showCloseButton ? /* @__PURE__ */ jsx13(
5445
+ showCloseButton ? /* @__PURE__ */ jsx14(
5234
5446
  DialogPrimitive.Close,
5235
5447
  {
5236
5448
  type: "button",
5237
5449
  className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
5238
5450
  "aria-label": "Close",
5239
- children: /* @__PURE__ */ jsx13(X, { size: 16, "aria-hidden": true })
5451
+ children: /* @__PURE__ */ jsx14(X, { size: 16, "aria-hidden": true })
5240
5452
  }
5241
5453
  ) : null
5242
5454
  ]
@@ -5250,13 +5462,13 @@ function DialogHeader({
5250
5462
  className,
5251
5463
  ...props
5252
5464
  }) {
5253
- return /* @__PURE__ */ jsx13("div", { className: cn("flex flex-col gap-1.5", className), ...props });
5465
+ return /* @__PURE__ */ jsx14("div", { className: cn("flex flex-col gap-1.5", className), ...props });
5254
5466
  }
5255
5467
  function DialogFooter({
5256
5468
  className,
5257
5469
  ...props
5258
5470
  }) {
5259
- return /* @__PURE__ */ jsx13(
5471
+ return /* @__PURE__ */ jsx14(
5260
5472
  "div",
5261
5473
  {
5262
5474
  className: cn("flex items-center justify-end gap-2", className),
@@ -5264,7 +5476,7 @@ function DialogFooter({
5264
5476
  }
5265
5477
  );
5266
5478
  }
5267
- var DialogTitle = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx13(
5479
+ var DialogTitle = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx14(
5268
5480
  DialogPrimitive.Title,
5269
5481
  {
5270
5482
  ref,
@@ -5276,7 +5488,7 @@ var DialogTitle = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE
5276
5488
  }
5277
5489
  ));
5278
5490
  DialogTitle.displayName = DialogPrimitive.Title.displayName;
5279
- var DialogDescription = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx13(
5491
+ var DialogDescription = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx14(
5280
5492
  DialogPrimitive.Description,
5281
5493
  {
5282
5494
  ref,
@@ -5292,19 +5504,19 @@ import { Info, X as X3 } from "lucide-react";
5292
5504
 
5293
5505
  // src/ui/link-modal/DestinationBreadcrumb.tsx
5294
5506
  import { ArrowRight, File, GalleryVertical } from "lucide-react";
5295
- import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
5507
+ import { jsx as jsx15, jsxs as jsxs8 } from "react/jsx-runtime";
5296
5508
  function DestinationBreadcrumb({
5297
5509
  pageTitle,
5298
5510
  sectionLabel
5299
5511
  }) {
5300
5512
  return /* @__PURE__ */ jsxs8("div", { className: "flex w-full flex-col gap-2", children: [
5301
- /* @__PURE__ */ jsx14("p", { className: "text-sm font-medium! text-foreground m-0", children: "Destination" }),
5513
+ /* @__PURE__ */ jsx15("p", { className: "text-sm font-medium! text-foreground m-0", children: "Destination" }),
5302
5514
  /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-3", children: [
5303
5515
  /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
5304
- /* @__PURE__ */ jsx14(File, { size: 16, className: "shrink-0 text-foreground", "aria-hidden": true }),
5305
- /* @__PURE__ */ jsx14("span", { className: "text-sm font-medium leading-none text-foreground!", children: pageTitle })
5516
+ /* @__PURE__ */ jsx15(File, { size: 16, className: "shrink-0 text-foreground", "aria-hidden": true }),
5517
+ /* @__PURE__ */ jsx15("span", { className: "text-sm font-medium leading-none text-foreground!", children: pageTitle })
5306
5518
  ] }),
5307
- /* @__PURE__ */ jsx14(
5519
+ /* @__PURE__ */ jsx15(
5308
5520
  ArrowRight,
5309
5521
  {
5310
5522
  size: 16,
@@ -5313,7 +5525,7 @@ function DestinationBreadcrumb({
5313
5525
  }
5314
5526
  ),
5315
5527
  /* @__PURE__ */ jsxs8("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
5316
- /* @__PURE__ */ jsx14(
5528
+ /* @__PURE__ */ jsx15(
5317
5529
  GalleryVertical,
5318
5530
  {
5319
5531
  size: 16,
@@ -5321,7 +5533,7 @@ function DestinationBreadcrumb({
5321
5533
  "aria-hidden": true
5322
5534
  }
5323
5535
  ),
5324
- /* @__PURE__ */ jsx14("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
5536
+ /* @__PURE__ */ jsx15("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
5325
5537
  ] })
5326
5538
  ] })
5327
5539
  ] });
@@ -5329,7 +5541,7 @@ function DestinationBreadcrumb({
5329
5541
 
5330
5542
  // src/ui/link-modal/SectionTreeItem.tsx
5331
5543
  import { GalleryVertical as GalleryVertical2 } from "lucide-react";
5332
- import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
5544
+ import { jsx as jsx16, jsxs as jsxs9 } from "react/jsx-runtime";
5333
5545
  function SectionTreeItem({
5334
5546
  section,
5335
5547
  onSelect,
@@ -5337,7 +5549,7 @@ function SectionTreeItem({
5337
5549
  }) {
5338
5550
  const interactive = Boolean(onSelect);
5339
5551
  return /* @__PURE__ */ jsxs9("div", { className: "flex h-9 w-full items-end pl-3", children: [
5340
- /* @__PURE__ */ jsx15(
5552
+ /* @__PURE__ */ jsx16(
5341
5553
  "div",
5342
5554
  {
5343
5555
  className: "mr-[-1px] h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
@@ -5362,7 +5574,7 @@ function SectionTreeItem({
5362
5574
  interactive && selected && "border-primary"
5363
5575
  ),
5364
5576
  children: [
5365
- /* @__PURE__ */ jsx15(
5577
+ /* @__PURE__ */ jsx16(
5366
5578
  GalleryVertical2,
5367
5579
  {
5368
5580
  size: 16,
@@ -5370,7 +5582,7 @@ function SectionTreeItem({
5370
5582
  "aria-hidden": true
5371
5583
  }
5372
5584
  ),
5373
- /* @__PURE__ */ jsx15("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
5585
+ /* @__PURE__ */ jsx16("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
5374
5586
  ]
5375
5587
  }
5376
5588
  )
@@ -5378,14 +5590,14 @@ function SectionTreeItem({
5378
5590
  }
5379
5591
 
5380
5592
  // src/ui/link-modal/UrlOrPageInput.tsx
5381
- import { useEffect as useEffect3, useId as useId2, useRef as useRef4, useState as useState3 } from "react";
5593
+ import { useEffect as useEffect3, useId as useId2, useRef as useRef4, useState as useState4 } from "react";
5382
5594
 
5383
5595
  // src/ui/input.tsx
5384
5596
  import * as React9 from "react";
5385
- import { jsx as jsx16 } from "react/jsx-runtime";
5597
+ import { jsx as jsx17 } from "react/jsx-runtime";
5386
5598
  var Input = React9.forwardRef(
5387
5599
  ({ className, type, ...props }, ref) => {
5388
- return /* @__PURE__ */ jsx16(
5600
+ return /* @__PURE__ */ jsx17(
5389
5601
  "input",
5390
5602
  {
5391
5603
  type,
@@ -5404,9 +5616,9 @@ Input.displayName = "Input";
5404
5616
 
5405
5617
  // src/ui/label.tsx
5406
5618
  import { Label as LabelPrimitive } from "radix-ui";
5407
- import { jsx as jsx17 } from "react/jsx-runtime";
5619
+ import { jsx as jsx18 } from "react/jsx-runtime";
5408
5620
  function Label({ className, ...props }) {
5409
- return /* @__PURE__ */ jsx17(
5621
+ return /* @__PURE__ */ jsx18(
5410
5622
  LabelPrimitive.Root,
5411
5623
  {
5412
5624
  "data-slot": "label",
@@ -5418,11 +5630,11 @@ function Label({ className, ...props }) {
5418
5630
 
5419
5631
  // src/ui/link-modal/UrlOrPageInput.tsx
5420
5632
  import { ChevronDown, File as File2, X as X2 } from "lucide-react";
5421
- import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
5633
+ import { jsx as jsx19, jsxs as jsxs10 } from "react/jsx-runtime";
5422
5634
  function FieldChevron({
5423
5635
  onClick
5424
5636
  }) {
5425
- return /* @__PURE__ */ jsx18(
5637
+ return /* @__PURE__ */ jsx19(
5426
5638
  "button",
5427
5639
  {
5428
5640
  type: "button",
@@ -5430,7 +5642,7 @@ function FieldChevron({
5430
5642
  onClick,
5431
5643
  "aria-label": "Open page list",
5432
5644
  tabIndex: -1,
5433
- children: /* @__PURE__ */ jsx18(ChevronDown, { size: 16 })
5645
+ children: /* @__PURE__ */ jsx19(ChevronDown, { size: 16 })
5434
5646
  }
5435
5647
  );
5436
5648
  }
@@ -5449,7 +5661,7 @@ function UrlOrPageInput({
5449
5661
  const inputId = useId2();
5450
5662
  const inputRef = useRef4(null);
5451
5663
  const rootRef = useRef4(null);
5452
- const [isFocused, setIsFocused] = useState3(false);
5664
+ const [isFocused, setIsFocused] = useState4(false);
5453
5665
  useEffect3(() => {
5454
5666
  if (!dropdownOpen) return;
5455
5667
  const isOutside = (e) => {
@@ -5492,10 +5704,10 @@ function UrlOrPageInput({
5492
5704
  urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
5493
5705
  );
5494
5706
  return /* @__PURE__ */ jsxs10("div", { className: "flex w-full flex-col gap-2 p-0", children: [
5495
- /* @__PURE__ */ jsx18(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
5707
+ /* @__PURE__ */ jsx19(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
5496
5708
  /* @__PURE__ */ jsxs10("div", { ref: rootRef, className: "relative w-full", children: [
5497
5709
  /* @__PURE__ */ jsxs10("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
5498
- selectedPage ? /* @__PURE__ */ jsx18("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ jsx18(
5710
+ selectedPage ? /* @__PURE__ */ jsx19("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ jsx19(
5499
5711
  File2,
5500
5712
  {
5501
5713
  size: 16,
@@ -5503,7 +5715,7 @@ function UrlOrPageInput({
5503
5715
  "aria-hidden": true
5504
5716
  }
5505
5717
  ) }) : null,
5506
- readOnly ? /* @__PURE__ */ jsx18("span", { className: "min-w-0 flex-1 truncate text-sm leading-5 text-foreground", children: selectedPage?.title ?? value }) : /* @__PURE__ */ jsx18(
5718
+ readOnly ? /* @__PURE__ */ jsx19("span", { className: "min-w-0 flex-1 truncate text-sm leading-5 text-foreground", children: selectedPage?.title ?? value }) : /* @__PURE__ */ jsx19(
5507
5719
  Input,
5508
5720
  {
5509
5721
  ref: inputRef,
@@ -5529,7 +5741,7 @@ function UrlOrPageInput({
5529
5741
  )
5530
5742
  }
5531
5743
  ),
5532
- selectedPage && !readOnly ? /* @__PURE__ */ jsx18(
5744
+ selectedPage && !readOnly ? /* @__PURE__ */ jsx19(
5533
5745
  "button",
5534
5746
  {
5535
5747
  type: "button",
@@ -5537,12 +5749,12 @@ function UrlOrPageInput({
5537
5749
  onMouseDown: clearSelection,
5538
5750
  "aria-label": "Clear selected page",
5539
5751
  tabIndex: -1,
5540
- children: /* @__PURE__ */ jsx18(X2, { size: 16, "aria-hidden": true })
5752
+ children: /* @__PURE__ */ jsx19(X2, { size: 16, "aria-hidden": true })
5541
5753
  }
5542
5754
  ) : null,
5543
- !readOnly ? /* @__PURE__ */ jsx18(FieldChevron, { onClick: toggleDropdown }) : null
5755
+ !readOnly ? /* @__PURE__ */ jsx19(FieldChevron, { onClick: toggleDropdown }) : null
5544
5756
  ] }),
5545
- dropdownOpen && !readOnly && filteredPages.length > 0 ? /* @__PURE__ */ jsx18(
5757
+ dropdownOpen && !readOnly && filteredPages.length > 0 ? /* @__PURE__ */ jsx19(
5546
5758
  "div",
5547
5759
  {
5548
5760
  "data-ohw-link-page-dropdown": "",
@@ -5555,8 +5767,8 @@ function UrlOrPageInput({
5555
5767
  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",
5556
5768
  onClick: () => onPageSelect(page),
5557
5769
  children: [
5558
- /* @__PURE__ */ jsx18(File2, { size: 16, className: "shrink-0", "aria-hidden": true }),
5559
- /* @__PURE__ */ jsx18("span", { className: "truncate", children: page.title })
5770
+ /* @__PURE__ */ jsx19(File2, { size: 16, className: "shrink-0", "aria-hidden": true }),
5771
+ /* @__PURE__ */ jsx19("span", { className: "truncate", children: page.title })
5560
5772
  ]
5561
5773
  },
5562
5774
  page.path
@@ -5564,34 +5776,34 @@ function UrlOrPageInput({
5564
5776
  }
5565
5777
  ) : null
5566
5778
  ] }),
5567
- urlError ? /* @__PURE__ */ jsx18("p", { className: "text-sm font-medium text-destructive", children: urlError }) : null
5779
+ urlError ? /* @__PURE__ */ jsx19("p", { className: "text-sm font-medium text-destructive", children: urlError }) : null
5568
5780
  ] });
5569
5781
  }
5570
5782
 
5571
5783
  // src/ui/link-modal/LinkEditorPanel.tsx
5572
- import { Fragment as Fragment3, jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
5784
+ import { Fragment as Fragment3, jsx as jsx20, jsxs as jsxs11 } from "react/jsx-runtime";
5573
5785
  function LinkEditorPanel({ state, onClose }) {
5574
5786
  const isCancel = state.secondaryLabel === "Cancel" || state.secondaryLabel === "Back to sections";
5575
5787
  return /* @__PURE__ */ jsxs11(Fragment3, { children: [
5576
- /* @__PURE__ */ jsx19(DialogClose, { asChild: true, children: /* @__PURE__ */ jsx19(
5788
+ /* @__PURE__ */ jsx20(DialogClose, { asChild: true, children: /* @__PURE__ */ jsx20(
5577
5789
  "button",
5578
5790
  {
5579
5791
  type: "button",
5580
5792
  className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50 h-7",
5581
5793
  "aria-label": "Close",
5582
5794
  onClick: onClose,
5583
- children: /* @__PURE__ */ jsx19(X3, { size: 16, "aria-hidden": true })
5795
+ children: /* @__PURE__ */ jsx20(X3, { size: 16, "aria-hidden": true })
5584
5796
  }
5585
5797
  ) }),
5586
- /* @__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 }) }),
5798
+ /* @__PURE__ */ jsx20(DialogHeader, { className: "w-full gap-1.5 p-6 pr-12", children: /* @__PURE__ */ jsx20(DialogTitle, { className: "m-0 w-full break-words", children: state.title }) }),
5587
5799
  /* @__PURE__ */ jsxs11("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
5588
- state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ jsx19(
5800
+ state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ jsx20(
5589
5801
  DestinationBreadcrumb,
5590
5802
  {
5591
5803
  pageTitle: state.selectedPage.title,
5592
5804
  sectionLabel: state.selectedSection.label
5593
5805
  }
5594
- ) : /* @__PURE__ */ jsx19(
5806
+ ) : /* @__PURE__ */ jsx20(
5595
5807
  UrlOrPageInput,
5596
5808
  {
5597
5809
  value: state.searchValue,
@@ -5605,7 +5817,7 @@ function LinkEditorPanel({ state, onClose }) {
5605
5817
  }
5606
5818
  ),
5607
5819
  state.showChooseSection ? /* @__PURE__ */ jsxs11("div", { className: "flex flex-col justify-center gap-2", children: [
5608
- /* @__PURE__ */ jsx19(
5820
+ /* @__PURE__ */ jsx20(
5609
5821
  Button,
5610
5822
  {
5611
5823
  type: "button",
@@ -5617,14 +5829,14 @@ function LinkEditorPanel({ state, onClose }) {
5617
5829
  }
5618
5830
  ),
5619
5831
  /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
5620
- /* @__PURE__ */ jsx19(Info, { size: 16, className: "shrink-0", "aria-hidden": true }),
5621
- /* @__PURE__ */ jsx19("span", { children: "Pick a section this link should scroll to." })
5832
+ /* @__PURE__ */ jsx20(Info, { size: 16, className: "shrink-0", "aria-hidden": true }),
5833
+ /* @__PURE__ */ jsx20("span", { children: "Pick a section this link should scroll to." })
5622
5834
  ] })
5623
5835
  ] }) : null,
5624
- state.showSectionRow && state.selectedSection ? /* @__PURE__ */ jsx19(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
5836
+ state.showSectionRow && state.selectedSection ? /* @__PURE__ */ jsx20(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
5625
5837
  ] }),
5626
5838
  /* @__PURE__ */ jsxs11(DialogFooter, { className: "w-full px-6 pb-6", children: [
5627
- /* @__PURE__ */ jsx19(
5839
+ /* @__PURE__ */ jsx20(
5628
5840
  Button,
5629
5841
  {
5630
5842
  type: "button",
@@ -5639,7 +5851,7 @@ function LinkEditorPanel({ state, onClose }) {
5639
5851
  children: state.secondaryLabel
5640
5852
  }
5641
5853
  ),
5642
- /* @__PURE__ */ jsx19(
5854
+ /* @__PURE__ */ jsx20(
5643
5855
  Button,
5644
5856
  {
5645
5857
  type: "button",
@@ -5658,11 +5870,11 @@ function LinkEditorPanel({ state, onClose }) {
5658
5870
  }
5659
5871
 
5660
5872
  // src/ui/link-modal/SectionPickerOverlay.tsx
5661
- import { useCallback, useEffect as useEffect4, useMemo as useMemo2, useRef as useRef5, useState as useState4 } from "react";
5873
+ import { useCallback as useCallback2, useEffect as useEffect4, useMemo as useMemo2, useRef as useRef5, useState as useState5 } from "react";
5662
5874
  import { createPortal } from "react-dom";
5663
5875
  import { ArrowLeft, Check } from "lucide-react";
5664
5876
  import { usePathname, useRouter } from "next/navigation";
5665
- import { jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
5877
+ import { jsx as jsx21, jsxs as jsxs12 } from "react/jsx-runtime";
5666
5878
  var DIM_OVERLAY = "rgba(0, 0, 0, 0.45)";
5667
5879
  function rectsEqual(a, b) {
5668
5880
  if (a.size !== b.size) return false;
@@ -5695,7 +5907,7 @@ function hitTestSectionId(x, y, sectionIds, rects) {
5695
5907
  return null;
5696
5908
  }
5697
5909
  function useSectionRects(sectionIdsKey, enabled) {
5698
- const [rects, setRects] = useState4(/* @__PURE__ */ new Map());
5910
+ const [rects, setRects] = useState5(/* @__PURE__ */ new Map());
5699
5911
  const sectionIds = useMemo2(
5700
5912
  () => sectionIdsKey ? sectionIdsKey.split("\0") : [],
5701
5913
  [sectionIdsKey]
@@ -5741,13 +5953,13 @@ function SectionPickerOverlay({
5741
5953
  }) {
5742
5954
  const router = useRouter();
5743
5955
  const pathname = usePathname();
5744
- const [selectedId, setSelectedId] = useState4(null);
5745
- const [hoveredId, setHoveredId] = useState4(null);
5956
+ const [selectedId, setSelectedId] = useState5(null);
5957
+ const [hoveredId, setHoveredId] = useState5(null);
5746
5958
  const pointerRef = useRef5(null);
5747
5959
  const pointerScreenRef = useRef5(null);
5748
5960
  const iframeOffsetTopRef = useRef5(null);
5749
5961
  const sectionIdsRef = useRef5([]);
5750
- const [chromeClip, setChromeClip] = useState4(
5962
+ const [chromeClip, setChromeClip] = useState5(
5751
5963
  () => ({
5752
5964
  top: 0,
5753
5965
  bottom: typeof window !== "undefined" ? window.innerHeight : 0
@@ -5789,7 +6001,7 @@ function SectionPickerOverlay({
5789
6001
  );
5790
6002
  sectionIdsRef.current = sectionIds;
5791
6003
  const rects = useSectionRects(sectionIdsKey, isOnTargetPage);
5792
- const applyHoverAt = useCallback(
6004
+ const applyHoverAt = useCallback2(
5793
6005
  (x, y, liveRects) => {
5794
6006
  const ids = sectionIdsRef.current;
5795
6007
  const map = liveRects ?? readSectionRects(ids);
@@ -5869,7 +6081,7 @@ function SectionPickerOverlay({
5869
6081
  window.removeEventListener("message", onPointerSync);
5870
6082
  };
5871
6083
  }, [rects, applyHoverAt]);
5872
- const handleSelect = useCallback(
6084
+ const handleSelect = useCallback2(
5873
6085
  (section) => {
5874
6086
  if (selectedId) return;
5875
6087
  setSelectedId(section.id);
@@ -5901,7 +6113,7 @@ function SectionPickerOverlay({
5901
6113
  role: "dialog",
5902
6114
  "aria-label": "Choose a section",
5903
6115
  children: [
5904
- /* @__PURE__ */ jsx20(
6116
+ /* @__PURE__ */ jsx21(
5905
6117
  "div",
5906
6118
  {
5907
6119
  className: "pointer-events-auto fixed left-5 z-[2]",
@@ -5915,14 +6127,14 @@ function SectionPickerOverlay({
5915
6127
  className: "h-8 min-w-0 gap-1 border-border bg-background px-2 py-1.5 shadow-sm hover:bg-muted cursor-pointer",
5916
6128
  onClick: onBack,
5917
6129
  children: [
5918
- /* @__PURE__ */ jsx20(ArrowLeft, { className: "size-4 shrink-0", "aria-hidden": true }),
6130
+ /* @__PURE__ */ jsx21(ArrowLeft, { className: "size-4 shrink-0", "aria-hidden": true }),
5919
6131
  "Back"
5920
6132
  ]
5921
6133
  }
5922
6134
  )
5923
6135
  }
5924
6136
  ),
5925
- /* @__PURE__ */ jsx20(
6137
+ /* @__PURE__ */ jsx21(
5926
6138
  "div",
5927
6139
  {
5928
6140
  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",
@@ -5935,7 +6147,7 @@ function SectionPickerOverlay({
5935
6147
  children: "Click on section to select"
5936
6148
  }
5937
6149
  ),
5938
- !isOnTargetPage ? /* @__PURE__ */ jsx20(
6150
+ !isOnTargetPage ? /* @__PURE__ */ jsx21(
5939
6151
  "div",
5940
6152
  {
5941
6153
  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",
@@ -5943,7 +6155,7 @@ function SectionPickerOverlay({
5943
6155
  children: "Loading page preview\u2026"
5944
6156
  }
5945
6157
  ) : null,
5946
- 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,
6158
+ isOnTargetPage && liveSections.length === 0 ? /* @__PURE__ */ jsx21("div", { className: "pointer-events-auto fixed inset-0 z-[1] flex items-center justify-center bg-muted/40", children: /* @__PURE__ */ jsx21("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." }) }) : null,
5947
6159
  isOnTargetPage ? liveSections.map((section) => {
5948
6160
  const rect = rects.get(section.id);
5949
6161
  if (!rect || rect.width <= 0 || rect.height <= 0) return null;
@@ -5965,7 +6177,7 @@ function SectionPickerOverlay({
5965
6177
  "aria-label": `Select section ${section.label}`,
5966
6178
  onClick: () => handleSelect(section),
5967
6179
  children: [
5968
- isLit ? /* @__PURE__ */ jsx20(
6180
+ isLit ? /* @__PURE__ */ jsx21(
5969
6181
  "span",
5970
6182
  {
5971
6183
  className: "pointer-events-none absolute",
@@ -5978,13 +6190,13 @@ function SectionPickerOverlay({
5978
6190
  "aria-hidden": true
5979
6191
  }
5980
6192
  ) : null,
5981
- isSelected ? /* @__PURE__ */ jsx20(
6193
+ isSelected ? /* @__PURE__ */ jsx21(
5982
6194
  "span",
5983
6195
  {
5984
6196
  className: "absolute right-3 top-3 flex size-8 items-center justify-center rounded-full text-white",
5985
6197
  style: { backgroundColor: "var(--ohw-primary, #0885fe)" },
5986
6198
  "aria-hidden": true,
5987
- children: /* @__PURE__ */ jsx20(Check, { className: "size-5" })
6199
+ children: /* @__PURE__ */ jsx21(Check, { className: "size-5" })
5988
6200
  }
5989
6201
  ) : null
5990
6202
  ]
@@ -6000,7 +6212,7 @@ function SectionPickerOverlay({
6000
6212
  }
6001
6213
 
6002
6214
  // src/ui/link-modal/useLinkModalState.ts
6003
- import { useCallback as useCallback2, useEffect as useEffect5, useMemo as useMemo3, useState as useState5 } from "react";
6215
+ import { useCallback as useCallback3, useEffect as useEffect5, useMemo as useMemo3, useState as useState6 } from "react";
6004
6216
  function useLinkModalState({
6005
6217
  open,
6006
6218
  mode,
@@ -6013,13 +6225,13 @@ function useLinkModalState({
6013
6225
  onSubmit
6014
6226
  }) {
6015
6227
  const availablePages = useMemo3(() => pages, [pages]);
6016
- const [searchValue, setSearchValue] = useState5("");
6017
- const [selectedPage, setSelectedPage] = useState5(null);
6018
- const [selectedSection, setSelectedSection] = useState5(null);
6019
- const [step, setStep] = useState5("input");
6020
- const [dropdownOpen, setDropdownOpen] = useState5(false);
6021
- const [urlError, setUrlError] = useState5("");
6022
- const reset = useCallback2(() => {
6228
+ const [searchValue, setSearchValue] = useState6("");
6229
+ const [selectedPage, setSelectedPage] = useState6(null);
6230
+ const [selectedSection, setSelectedSection] = useState6(null);
6231
+ const [step, setStep] = useState6("input");
6232
+ const [dropdownOpen, setDropdownOpen] = useState6(false);
6233
+ const [urlError, setUrlError] = useState6("");
6234
+ const reset = useCallback3(() => {
6023
6235
  setSearchValue("");
6024
6236
  setSelectedPage(null);
6025
6237
  setSelectedSection(null);
@@ -6164,7 +6376,7 @@ function useLinkModalState({
6164
6376
  }
6165
6377
 
6166
6378
  // src/ui/link-modal/LinkPopover.tsx
6167
- import { Fragment as Fragment4, jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
6379
+ import { Fragment as Fragment4, jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
6168
6380
  function postToParent(data) {
6169
6381
  window.parent?.postMessage(data, "*");
6170
6382
  }
@@ -6261,14 +6473,14 @@ function LinkPopover({
6261
6473
  };
6262
6474
  }, [open, sectionPickerActive]);
6263
6475
  return /* @__PURE__ */ jsxs13(Fragment4, { children: [
6264
- /* @__PURE__ */ jsx21(
6476
+ /* @__PURE__ */ jsx22(
6265
6477
  Dialog2,
6266
6478
  {
6267
6479
  open: open && !sectionPickerActive,
6268
6480
  onOpenChange: (next) => {
6269
6481
  if (!next) onClose?.();
6270
6482
  },
6271
- children: /* @__PURE__ */ jsx21(
6483
+ children: /* @__PURE__ */ jsx22(
6272
6484
  DialogContent,
6273
6485
  {
6274
6486
  ref: panelRef,
@@ -6278,12 +6490,12 @@ function LinkPopover({
6278
6490
  "data-ohw-bridge": "",
6279
6491
  showCloseButton: false,
6280
6492
  className: "gap-0 p-0 w-full max-w-[448px] pointer-events-auto z-[2147483646] overflow-visible",
6281
- children: /* @__PURE__ */ jsx21(LinkEditorPanel, { state, onClose })
6493
+ children: /* @__PURE__ */ jsx22(LinkEditorPanel, { state, onClose })
6282
6494
  }
6283
6495
  )
6284
6496
  }
6285
6497
  ),
6286
- sectionPickerActive && state.selectedPage ? /* @__PURE__ */ jsx21(
6498
+ sectionPickerActive && state.selectedPage ? /* @__PURE__ */ jsx22(
6287
6499
  SectionPickerOverlay,
6288
6500
  {
6289
6501
  pagePath: state.selectedPage.path,
@@ -6822,6 +7034,53 @@ function insertNavbarItem(href, label, afterAnchor = null) {
6822
7034
  order
6823
7035
  };
6824
7036
  }
7037
+ function duplicateNavbarItem(sourceAnchor) {
7038
+ if (!isNavbarLinkItem(sourceAnchor)) return null;
7039
+ const sourceHrefKey = sourceAnchor.getAttribute("data-ohw-href-key");
7040
+ if (!sourceHrefKey || !isNavbarHrefKey(sourceHrefKey)) return null;
7041
+ const href = getLinkHref(sourceAnchor);
7042
+ const labelEl = sourceAnchor.querySelector('[data-ohw-editable="text"]');
7043
+ const label = (labelEl?.textContent ?? "").trim() || "Untitled";
7044
+ const forest = getNavForestFromDom();
7045
+ const sourceNode = forest.find((n) => n.id === sourceHrefKey);
7046
+ const childIds = sourceNode?.children.map((c) => c.id) ?? [];
7047
+ const primary = insertNavbarItem(href, label, sourceAnchor);
7048
+ const childResults = [];
7049
+ let after = primary.anchor;
7050
+ for (const childId of childIds) {
7051
+ const childEl = findCounterpartByHrefKey(childId, document) ?? document.querySelector(`[data-ohw-href-key="${CSS.escape(childId)}"]`);
7052
+ if (!childEl || !isNavbarLinkItem(childEl)) continue;
7053
+ const childHref = getLinkHref(childEl);
7054
+ const childLabelEl = childEl.querySelector('[data-ohw-editable="text"]');
7055
+ const childLabel = (childLabelEl?.textContent ?? "").trim() || "Untitled";
7056
+ const inserted = insertNavbarItem(childHref, childLabel, after);
7057
+ childResults.push(inserted);
7058
+ after = inserted.anchor;
7059
+ }
7060
+ let orderJson;
7061
+ if (childResults.length > 0) {
7062
+ const nextForest = getNavForestFromDom();
7063
+ const withoutNew = nextForest.filter(
7064
+ (n) => n.id !== primary.hrefKey && !childResults.some((c) => c.hrefKey === n.id)
7065
+ );
7066
+ const sourceIdx = withoutNew.findIndex((n) => n.id === sourceHrefKey);
7067
+ const insertAt = sourceIdx >= 0 ? sourceIdx + 1 : withoutNew.length;
7068
+ withoutNew.splice(insertAt, 0, {
7069
+ id: primary.hrefKey,
7070
+ children: childResults.map((c) => ({ id: c.hrefKey, children: [] }))
7071
+ });
7072
+ applyNavForest(withoutNew);
7073
+ orderJson = serializeNavOrder(withoutNew);
7074
+ } else {
7075
+ orderJson = serializeNavOrder(getNavForestFromDom());
7076
+ }
7077
+ return {
7078
+ ...primary,
7079
+ order: flattenNavOrder(parseNavOrderJson(orderJson) ?? getNavForestFromDom()),
7080
+ childResults,
7081
+ orderJson
7082
+ };
7083
+ }
6825
7084
 
6826
7085
  // src/lib/footer-items.ts
6827
7086
  var FOOTER_ORDER_KEY = "__ohw_footer_order";
@@ -7005,7 +7264,185 @@ function parseFooterOrder(content) {
7005
7264
  return null;
7006
7265
  }
7007
7266
  }
7267
+ var FOOTER_HEADING_RE = /^footer-(\d+)-heading$/;
7268
+ var FOOTER_LABEL_RE = /^footer-(\d+)-(\d+)-label$/;
7269
+ var DEFAULT_FOOTER_COLUMN_HEADING = "New";
7270
+ var DEFAULT_FOOTER_COLUMN_LINK_LABEL = "New link";
7271
+ var DEFAULT_FOOTER_COLUMN_LINK_HREF = "";
7272
+ function isFooterLinksContainer(el) {
7273
+ return el.hasAttribute("data-ohw-footer-links") || el.classList.contains("rb-footer-links");
7274
+ }
7275
+ function getFooterColumnIndicesInDom() {
7276
+ const indices = /* @__PURE__ */ new Set();
7277
+ for (const col of listFooterColumns()) {
7278
+ const attr = col.getAttribute("data-ohw-footer-col");
7279
+ if (attr != null) {
7280
+ const n = parseInt(attr, 10);
7281
+ if (Number.isFinite(n)) indices.add(n);
7282
+ }
7283
+ for (const link of listFooterLinksInColumn(col)) {
7284
+ const parsed = parseFooterHrefKey(link.getAttribute("data-ohw-href-key"));
7285
+ if (parsed) indices.add(parsed.col);
7286
+ }
7287
+ const heading = col.querySelector('[data-ohw-key^="footer-"][data-ohw-key$="-heading"]');
7288
+ const headingKey = heading?.getAttribute("data-ohw-key");
7289
+ if (headingKey) {
7290
+ const match = headingKey.match(FOOTER_HEADING_RE);
7291
+ if (match) indices.add(parseInt(match[1], 10));
7292
+ }
7293
+ }
7294
+ return [...indices].sort((a, b) => a - b);
7295
+ }
7296
+ function getNextFooterColumnIndex() {
7297
+ const indices = getFooterColumnIndicesInDom();
7298
+ if (indices.length === 0) return 0;
7299
+ return Math.max(...indices) + 1;
7300
+ }
7301
+ function buildFooterHeading(colIndex, text) {
7302
+ const heading = document.createElement("p");
7303
+ heading.setAttribute("data-ohw-editable", "text");
7304
+ heading.setAttribute("data-ohw-key", `footer-${colIndex}-heading`);
7305
+ heading.textContent = text;
7306
+ heading.style.cssText = [
7307
+ "color: var(--espresso, #3d312b)",
7308
+ "font-size: 14px",
7309
+ "font-weight: 800",
7310
+ "opacity: 0.82",
7311
+ "margin: 0 0 6px",
7312
+ "padding: 0",
7313
+ "line-height: 1.2"
7314
+ ].join(";");
7315
+ return heading;
7316
+ }
7317
+ function buildFooterLink(colIndex, itemIndex, href, label, template) {
7318
+ const anchor = cloneFooterLinkShell(template);
7319
+ anchor.setAttribute("href", href);
7320
+ anchor.setAttribute("data-ohw-href-key", `footer-${colIndex}-${itemIndex}-href`);
7321
+ const span = document.createElement("span");
7322
+ span.setAttribute("data-ohw-editable", "text");
7323
+ span.setAttribute("data-ohw-key", `footer-${colIndex}-${itemIndex}-label`);
7324
+ span.textContent = label;
7325
+ anchor.appendChild(span);
7326
+ return anchor;
7327
+ }
7328
+ function footerColumnExistsInDom(colIndex) {
7329
+ 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;
7330
+ }
7331
+ function getFooterLinkTemplate() {
7332
+ for (const col of listFooterColumns()) {
7333
+ const link = listFooterLinksInColumn(col)[0];
7334
+ if (link) return link;
7335
+ }
7336
+ return null;
7337
+ }
7338
+ function getFooterColumnTemplate() {
7339
+ return listFooterColumns()[0] ?? null;
7340
+ }
7341
+ function insertFooterColumnDom(colIndex, heading, items) {
7342
+ const container = getFooterLinksContainer();
7343
+ if (!container) return null;
7344
+ const colTemplate = getFooterColumnTemplate();
7345
+ const linkTemplate = getFooterLinkTemplate();
7346
+ const column = document.createElement("div");
7347
+ if (colTemplate?.className) column.className = colTemplate.className;
7348
+ else column.className = "rb-footer-link-col";
7349
+ column.setAttribute("data-ohw-footer-col", String(colIndex));
7350
+ if (colTemplate) {
7351
+ const gap = getComputedStyle(colTemplate).gap;
7352
+ if (gap && gap !== "normal") column.style.gap = gap;
7353
+ column.style.display = getComputedStyle(colTemplate).display || "flex";
7354
+ column.style.flexDirection = "column";
7355
+ }
7356
+ column.appendChild(buildFooterHeading(colIndex, heading));
7357
+ let firstLink = null;
7358
+ items.forEach((item, itemIndex) => {
7359
+ const link = buildFooterLink(colIndex, itemIndex, item.href, item.label, linkTemplate);
7360
+ column.appendChild(link);
7361
+ if (!firstLink) firstLink = link;
7362
+ });
7363
+ container.appendChild(column);
7364
+ return { column, firstLink };
7365
+ }
7366
+ function insertFooterColumn(heading = DEFAULT_FOOTER_COLUMN_HEADING, linkLabel = DEFAULT_FOOTER_COLUMN_LINK_LABEL, linkHref = DEFAULT_FOOTER_COLUMN_LINK_HREF) {
7367
+ const colIndex = getNextFooterColumnIndex();
7368
+ const inserted = insertFooterColumnDom(colIndex, heading, [{ href: linkHref, label: linkLabel }]);
7369
+ if (!inserted?.firstLink) throw new Error("Failed to insert footer column");
7370
+ syncFooterColumnIndices(listFooterColumns());
7371
+ return {
7372
+ column: inserted.column,
7373
+ firstLink: inserted.firstLink,
7374
+ colIndex,
7375
+ headingKey: `footer-${colIndex}-heading`,
7376
+ hrefKey: `footer-${colIndex}-0-href`,
7377
+ labelKey: `footer-${colIndex}-0-label`,
7378
+ heading,
7379
+ label: linkLabel,
7380
+ href: linkHref,
7381
+ order: getFooterOrderFromDom()
7382
+ };
7383
+ }
7384
+ function collectFooterColumnIndicesFromContent(content) {
7385
+ const indices = /* @__PURE__ */ new Set();
7386
+ for (const key of Object.keys(content)) {
7387
+ const href = parseFooterHrefKey(key);
7388
+ if (href) indices.add(href.col);
7389
+ const heading = key.match(FOOTER_HEADING_RE);
7390
+ if (heading) indices.add(parseInt(heading[1], 10));
7391
+ const label = key.match(FOOTER_LABEL_RE);
7392
+ if (label) indices.add(parseInt(label[1], 10));
7393
+ }
7394
+ const order = parseFooterOrder(content);
7395
+ if (order) {
7396
+ for (const col of order) {
7397
+ for (const hrefKey of col) {
7398
+ const parsed = parseFooterHrefKey(hrefKey);
7399
+ if (parsed) indices.add(parsed.col);
7400
+ }
7401
+ }
7402
+ }
7403
+ return [...indices].sort((a, b) => a - b);
7404
+ }
7405
+ function collectFooterItemsForColumn(content, colIndex) {
7406
+ const itemIndices = /* @__PURE__ */ new Set();
7407
+ for (const key of Object.keys(content)) {
7408
+ const href = parseFooterHrefKey(key);
7409
+ if (href?.col === colIndex) itemIndices.add(href.item);
7410
+ const label = key.match(FOOTER_LABEL_RE);
7411
+ if (label && parseInt(label[1], 10) === colIndex) {
7412
+ itemIndices.add(parseInt(label[2], 10));
7413
+ }
7414
+ }
7415
+ const sorted = [...itemIndices].sort((a, b) => a - b);
7416
+ if (sorted.length === 0) {
7417
+ return [
7418
+ {
7419
+ href: content[`footer-${colIndex}-0-href`] ?? DEFAULT_FOOTER_COLUMN_LINK_HREF,
7420
+ label: content[`footer-${colIndex}-0-label`] ?? DEFAULT_FOOTER_COLUMN_LINK_LABEL
7421
+ }
7422
+ ];
7423
+ }
7424
+ return sorted.map((itemIndex) => ({
7425
+ href: content[`footer-${colIndex}-${itemIndex}-href`] ?? DEFAULT_FOOTER_COLUMN_LINK_HREF,
7426
+ label: content[`footer-${colIndex}-${itemIndex}-label`] ?? DEFAULT_FOOTER_COLUMN_LINK_LABEL
7427
+ }));
7428
+ }
7429
+ function reconcileFooterColumnsFromContent(content) {
7430
+ const indices = collectFooterColumnIndicesFromContent(content);
7431
+ for (const colIndex of indices) {
7432
+ if (footerColumnExistsInDom(colIndex)) continue;
7433
+ const heading = content[`footer-${colIndex}-heading`] ?? DEFAULT_FOOTER_COLUMN_HEADING;
7434
+ const items = collectFooterItemsForColumn(content, colIndex);
7435
+ const hasPayload = Boolean(content[`footer-${colIndex}-heading`]) || items.some(
7436
+ (_, i) => content[`footer-${colIndex}-${i}-href`] !== void 0 || content[`footer-${colIndex}-${i}-label`] !== void 0
7437
+ ) || (parseFooterOrder(content)?.some(
7438
+ (col) => col.some((k) => parseFooterHrefKey(k)?.col === colIndex)
7439
+ ) ?? false);
7440
+ if (!hasPayload) continue;
7441
+ insertFooterColumnDom(colIndex, heading, items);
7442
+ }
7443
+ }
7008
7444
  function reconcileFooterOrderFromContent(content) {
7445
+ reconcileFooterColumnsFromContent(content);
7009
7446
  const order = parseFooterOrder(content);
7010
7447
  if (!order?.length) return;
7011
7448
  const current = getFooterOrderFromDom();
@@ -7015,6 +7452,26 @@ function reconcileFooterOrderFromContent(content) {
7015
7452
  }
7016
7453
  applyFooterOrder(order);
7017
7454
  }
7455
+ function resolveFooterLinksContainerSelectionTarget(target, clientX, clientY, isPointOverItem) {
7456
+ const container = getFooterLinksContainer();
7457
+ if (!container) return null;
7458
+ const inContainer = target === container || container.contains(target) && Boolean(target.closest("[data-ohw-footer-links], .rb-footer-links"));
7459
+ if (!inContainer && target !== container) {
7460
+ const r2 = container.getBoundingClientRect();
7461
+ const over = clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom;
7462
+ if (!over) return null;
7463
+ }
7464
+ if (isPointOverItem(container, clientX, clientY)) return null;
7465
+ const column = target.closest("[data-ohw-footer-col], [data-ohw-footer-column]") ?? null;
7466
+ if (column && container.contains(column)) {
7467
+ if (target === column || column.contains(target)) return null;
7468
+ }
7469
+ if (target === container || container.contains(target) || inContainer) {
7470
+ if (target === container || isFooterLinksContainer(target)) return container;
7471
+ if (!column) return container;
7472
+ }
7473
+ return null;
7474
+ }
7018
7475
  function isRowLayoutColumn(links) {
7019
7476
  if (links.length < 2) return false;
7020
7477
  const firstTop = links[0].getBoundingClientRect().top;
@@ -7169,6 +7626,100 @@ function hitTestColumnDropSlot(clientX, _clientY) {
7169
7626
  }
7170
7627
  return best?.slot ?? null;
7171
7628
  }
7629
+ function getLinkHref2(el) {
7630
+ const key = el.getAttribute("data-ohw-href-key");
7631
+ if (key) {
7632
+ const stored = getStoredLinkHref(key);
7633
+ if (stored !== void 0) return stored;
7634
+ }
7635
+ return el.getAttribute("href") ?? "";
7636
+ }
7637
+ function getNextFooterItemIndex(col) {
7638
+ let max = -1;
7639
+ for (const el of document.querySelectorAll("footer [data-ohw-href-key]")) {
7640
+ const parsed = parseFooterHrefKey(el.getAttribute("data-ohw-href-key"));
7641
+ if (!parsed || parsed.col !== col) continue;
7642
+ if (parsed.item > max) max = parsed.item;
7643
+ }
7644
+ return max + 1;
7645
+ }
7646
+ function cloneFooterLinkShell(template) {
7647
+ const anchor = document.createElement("a");
7648
+ if (template) {
7649
+ anchor.style.cssText = template.style.cssText;
7650
+ if (template.className) anchor.className = template.className;
7651
+ }
7652
+ anchor.style.cursor = "pointer";
7653
+ anchor.style.textDecoration = "none";
7654
+ return anchor;
7655
+ }
7656
+ function insertFooterItem(column, href, label, afterAnchor = null) {
7657
+ const columns = listFooterColumns();
7658
+ const colIndex = columns.indexOf(column);
7659
+ if (colIndex < 0) throw new Error("Footer column not found");
7660
+ const item = getNextFooterItemIndex(colIndex);
7661
+ const hrefKey = `footer-${colIndex}-${item}-href`;
7662
+ const labelKey = `footer-${colIndex}-${item}-label`;
7663
+ const template = listFooterLinksInColumn(column)[0] ?? null;
7664
+ const anchor = cloneFooterLinkShell(template);
7665
+ anchor.href = href;
7666
+ anchor.setAttribute("data-ohw-href-key", hrefKey);
7667
+ const span = document.createElement("span");
7668
+ span.setAttribute("data-ohw-editable", "text");
7669
+ span.setAttribute("data-ohw-key", labelKey);
7670
+ span.textContent = label;
7671
+ anchor.appendChild(span);
7672
+ if (afterAnchor && afterAnchor.parentElement === column) {
7673
+ afterAnchor.insertAdjacentElement("afterend", anchor);
7674
+ } else {
7675
+ column.appendChild(anchor);
7676
+ }
7677
+ const order = getFooterOrderFromDom();
7678
+ applyFooterOrder(order);
7679
+ return {
7680
+ anchor,
7681
+ col: colIndex,
7682
+ item,
7683
+ hrefKey,
7684
+ labelKey,
7685
+ href,
7686
+ label,
7687
+ order
7688
+ };
7689
+ }
7690
+ function duplicateFooterItem(sourceAnchor) {
7691
+ if (!isFooterLinkAnchor(sourceAnchor)) return null;
7692
+ const column = findFooterColumnForLink(sourceAnchor);
7693
+ if (!column) return null;
7694
+ const href = getLinkHref2(sourceAnchor);
7695
+ const labelEl = sourceAnchor.querySelector('[data-ohw-editable="text"]');
7696
+ const label = (labelEl?.textContent ?? "").trim() || "Untitled";
7697
+ return insertFooterItem(column, href || "/", label, sourceAnchor);
7698
+ }
7699
+
7700
+ // src/lib/add-footer-column.ts
7701
+ function buildFooterColumnEditContentPatch(result) {
7702
+ return {
7703
+ [result.headingKey]: result.heading,
7704
+ [result.hrefKey]: result.href,
7705
+ [result.labelKey]: result.label,
7706
+ [FOOTER_ORDER_KEY]: JSON.stringify(result.order)
7707
+ };
7708
+ }
7709
+ function addFooterColumnWithPersist({
7710
+ postToParent: postToParent2
7711
+ }) {
7712
+ const result = insertFooterColumn();
7713
+ const patch = buildFooterColumnEditContentPatch(result);
7714
+ setStoredLinkHref(result.hrefKey, result.href);
7715
+ postToParent2({
7716
+ type: "ow:change",
7717
+ nodes: Object.entries(patch).map(([key, text]) => ({ key, text }))
7718
+ });
7719
+ postToParent2({ type: "ow:toast", title: "Item added", toastType: "success" });
7720
+ enforceLinkHrefs();
7721
+ return result;
7722
+ }
7172
7723
 
7173
7724
  // src/lib/item-drag-interaction.ts
7174
7725
  function disableNativeHrefDrag(el) {
@@ -7367,7 +7918,7 @@ function hitTestNavDropSlot(clientX, clientY, draggedHrefKey) {
7367
7918
  }
7368
7919
 
7369
7920
  // src/useNavItemDrag.ts
7370
- import { useCallback as useCallback3, useEffect as useEffect7, useRef as useRef6, useState as useState6 } from "react";
7921
+ import { useCallback as useCallback4, useEffect as useEffect7, useRef as useRef6, useState as useState7 } from "react";
7371
7922
  function useNavItemDrag({
7372
7923
  isEditMode,
7373
7924
  editContentRef,
@@ -7393,10 +7944,10 @@ function useNavItemDrag({
7393
7944
  isNavbarButton: isNavbarButton3
7394
7945
  }) {
7395
7946
  const navDragRef = useRef6(null);
7396
- const [navDropSlots, setNavDropSlots] = useState6([]);
7397
- const [activeNavDropIndex, setActiveNavDropIndex] = useState6(null);
7947
+ const [navDropSlots, setNavDropSlots] = useState7([]);
7948
+ const [activeNavDropIndex, setActiveNavDropIndex] = useState7(null);
7398
7949
  const navPointerDragRef = useRef6(null);
7399
- const clearNavDragVisuals = useCallback3(() => {
7950
+ const clearNavDragVisuals = useCallback4(() => {
7400
7951
  navDragRef.current = null;
7401
7952
  setNavDropSlots([]);
7402
7953
  setActiveNavDropIndex(null);
@@ -7405,7 +7956,7 @@ function useNavItemDrag({
7405
7956
  setIsItemDragging(false);
7406
7957
  unlockItemDragInteraction();
7407
7958
  }, [setDraggedItemRect, setIsItemDragging, setSiblingHintRects]);
7408
- const refreshNavDragVisuals = useCallback3(
7959
+ const refreshNavDragVisuals = useCallback4(
7409
7960
  (session, activeSlot, clientX, clientY) => {
7410
7961
  setDraggedItemRect(session.draggedEl.getBoundingClientRect());
7411
7962
  if (typeof clientX === "number" && typeof clientY === "number") {
@@ -7429,7 +7980,7 @@ function useNavItemDrag({
7429
7980
  });
7430
7981
  const beginNavDragRef = useRef6(() => {
7431
7982
  });
7432
- const beginNavDrag = useCallback3(
7983
+ const beginNavDrag = useCallback4(
7433
7984
  (session) => {
7434
7985
  const rect = session.draggedEl.getBoundingClientRect();
7435
7986
  session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
@@ -7456,7 +8007,7 @@ function useNavItemDrag({
7456
8007
  ]
7457
8008
  );
7458
8009
  beginNavDragRef.current = beginNavDrag;
7459
- const commitNavDrag = useCallback3(
8010
+ const commitNavDrag = useCallback4(
7460
8011
  (clientX, clientY) => {
7461
8012
  const session = navDragRef.current;
7462
8013
  if (!session) {
@@ -7517,7 +8068,7 @@ function useNavItemDrag({
7517
8068
  [clearNavDragVisuals, deselectRef, editContentRef, postToParentRef, selectRef]
7518
8069
  );
7519
8070
  commitNavDragRef.current = commitNavDrag;
7520
- const startNavLinkDrag = useCallback3(
8071
+ const startNavLinkDrag = useCallback4(
7521
8072
  (anchor, clientX, clientY, wasSelected) => {
7522
8073
  if (footerDragRef.current) return false;
7523
8074
  const hrefKey = anchor.getAttribute("data-ohw-href-key");
@@ -7535,7 +8086,7 @@ function useNavItemDrag({
7535
8086
  },
7536
8087
  [beginNavDrag, footerDragRef, isDragHandleDisabled2, isNavbarButton3]
7537
8088
  );
7538
- const onNavDragOver = useCallback3(
8089
+ const onNavDragOver = useCallback4(
7539
8090
  (e) => {
7540
8091
  const session = navDragRef.current;
7541
8092
  if (!session) return false;
@@ -7672,7 +8223,7 @@ function useNavItemDrag({
7672
8223
  setLinkPopover,
7673
8224
  suppressNextClickRef
7674
8225
  ]);
7675
- const armNavPressFromChrome = useCallback3(
8226
+ const armNavPressFromChrome = useCallback4(
7676
8227
  (selected, clientX, clientY, pointerId) => {
7677
8228
  const hrefKey = selected.getAttribute("data-ohw-href-key");
7678
8229
  if (!hrefKey || !isNavbarHrefKey(hrefKey)) return false;
@@ -7702,8 +8253,53 @@ function useNavItemDrag({
7702
8253
  };
7703
8254
  }
7704
8255
 
8256
+ // src/ui/footer-container-chrome.tsx
8257
+ import { Plus as Plus2 } from "lucide-react";
8258
+ import { jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
8259
+ function FooterContainerChrome({ rect, onAdd }) {
8260
+ const chromeGap = 6;
8261
+ const buttonMargin = 7;
8262
+ return /* @__PURE__ */ jsx23(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsx23(
8263
+ "div",
8264
+ {
8265
+ "data-ohw-footer-container-chrome": "",
8266
+ "data-ohw-bridge": "",
8267
+ className: "pointer-events-none fixed z-[2147483647]",
8268
+ style: {
8269
+ top: rect.top - chromeGap,
8270
+ left: rect.left - chromeGap,
8271
+ width: rect.width + chromeGap * 2,
8272
+ height: rect.height + chromeGap * 2
8273
+ },
8274
+ children: /* @__PURE__ */ jsxs14(Tooltip, { children: [
8275
+ /* @__PURE__ */ jsx23(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx23(
8276
+ "button",
8277
+ {
8278
+ type: "button",
8279
+ "data-ohw-footer-add-button": "",
8280
+ 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",
8281
+ style: { top: chromeGap - buttonMargin },
8282
+ "aria-label": "Add item",
8283
+ onMouseDown: (e) => {
8284
+ e.preventDefault();
8285
+ e.stopPropagation();
8286
+ },
8287
+ onClick: (e) => {
8288
+ e.preventDefault();
8289
+ e.stopPropagation();
8290
+ onAdd();
8291
+ },
8292
+ children: /* @__PURE__ */ jsx23(Plus2, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
8293
+ }
8294
+ ) }),
8295
+ /* @__PURE__ */ jsx23(TooltipContent, { side: "bottom", sideOffset: 9, children: "Add item" })
8296
+ ] })
8297
+ }
8298
+ ) });
8299
+ }
8300
+
7705
8301
  // src/lib/carousel.ts
7706
- import { useEffect as useEffect8, useState as useState7 } from "react";
8302
+ import { useEffect as useEffect8, useState as useState8 } from "react";
7707
8303
  var CAROUSEL_ATTR = "data-ohw-carousel";
7708
8304
  var CAROUSEL_VALUE_ATTR = "data-ohw-carousel-value";
7709
8305
  var CAROUSEL_SLIDE_ATTR = "data-ohw-carousel-slide";
@@ -7765,7 +8361,7 @@ function applyCarouselNode(key, val) {
7765
8361
  return true;
7766
8362
  }
7767
8363
  function useOhwCarousel(key, initial) {
7768
- const [images, setImages] = useState7(initial);
8364
+ const [images, setImages] = useState8(initial);
7769
8365
  useEffect8(() => {
7770
8366
  const el = document.querySelector(
7771
8367
  `[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`
@@ -7787,14 +8383,14 @@ function useOhwCarousel(key, initial) {
7787
8383
  }
7788
8384
 
7789
8385
  // src/ui/navbar-container-chrome.tsx
7790
- import { Plus as Plus2 } from "lucide-react";
7791
- import { jsx as jsx22 } from "react/jsx-runtime";
8386
+ import { Plus as Plus3 } from "lucide-react";
8387
+ import { jsx as jsx24 } from "react/jsx-runtime";
7792
8388
  function NavbarContainerChrome({
7793
8389
  rect,
7794
8390
  onAdd
7795
8391
  }) {
7796
8392
  const chromeGap = 6;
7797
- return /* @__PURE__ */ jsx22(
8393
+ return /* @__PURE__ */ jsx24(
7798
8394
  "div",
7799
8395
  {
7800
8396
  "data-ohw-navbar-container-chrome": "",
@@ -7806,7 +8402,7 @@ function NavbarContainerChrome({
7806
8402
  width: rect.width + chromeGap * 2,
7807
8403
  height: rect.height + chromeGap * 2
7808
8404
  },
7809
- children: /* @__PURE__ */ jsx22(
8405
+ children: /* @__PURE__ */ jsx24(
7810
8406
  "button",
7811
8407
  {
7812
8408
  type: "button",
@@ -7823,7 +8419,7 @@ function NavbarContainerChrome({
7823
8419
  e.stopPropagation();
7824
8420
  onAdd();
7825
8421
  },
7826
- children: /* @__PURE__ */ jsx22(Plus2, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
8422
+ children: /* @__PURE__ */ jsx24(Plus3, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
7827
8423
  }
7828
8424
  )
7829
8425
  }
@@ -7832,7 +8428,7 @@ function NavbarContainerChrome({
7832
8428
 
7833
8429
  // src/ui/drop-indicator.tsx
7834
8430
  import * as React10 from "react";
7835
- import { jsx as jsx23 } from "react/jsx-runtime";
8431
+ import { jsx as jsx25 } from "react/jsx-runtime";
7836
8432
  var dropIndicatorVariants = cva(
7837
8433
  "ov-gap-line pointer-events-none shrink-0 transition-opacity duration-150",
7838
8434
  {
@@ -7856,7 +8452,7 @@ var dropIndicatorVariants = cva(
7856
8452
  );
7857
8453
  var DropIndicator = React10.forwardRef(
7858
8454
  ({ className, direction, state, ...props }, ref) => {
7859
- return /* @__PURE__ */ jsx23(
8455
+ return /* @__PURE__ */ jsx25(
7860
8456
  "div",
7861
8457
  {
7862
8458
  ref,
@@ -7873,7 +8469,7 @@ var DropIndicator = React10.forwardRef(
7873
8469
  DropIndicator.displayName = "DropIndicator";
7874
8470
 
7875
8471
  // src/ui/badge.tsx
7876
- import { jsx as jsx24 } from "react/jsx-runtime";
8472
+ import { jsx as jsx26 } from "react/jsx-runtime";
7877
8473
  var badgeVariants = cva(
7878
8474
  "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",
7879
8475
  {
@@ -7891,12 +8487,12 @@ var badgeVariants = cva(
7891
8487
  }
7892
8488
  );
7893
8489
  function Badge({ className, variant, ...props }) {
7894
- return /* @__PURE__ */ jsx24("div", { className: cn(badgeVariants({ variant }), className), ...props });
8490
+ return /* @__PURE__ */ jsx26("div", { className: cn(badgeVariants({ variant }), className), ...props });
7895
8491
  }
7896
8492
 
7897
8493
  // src/OhhwellsBridge.tsx
7898
8494
  import { Link as Link2 } from "lucide-react";
7899
- import { Fragment as Fragment5, jsx as jsx25, jsxs as jsxs14 } from "react/jsx-runtime";
8495
+ import { Fragment as Fragment5, jsx as jsx27, jsxs as jsxs15 } from "react/jsx-runtime";
7900
8496
  var PRIMARY2 = "#0885FE";
7901
8497
  var IMAGE_FADE_MS = 300;
7902
8498
  function runOpacityFade(el, onDone) {
@@ -8075,7 +8671,7 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
8075
8671
  const root = createRoot(container);
8076
8672
  flushSync(() => {
8077
8673
  root.render(
8078
- /* @__PURE__ */ jsx25(
8674
+ /* @__PURE__ */ jsx27(
8079
8675
  SchedulingWidget,
8080
8676
  {
8081
8677
  notifyOnConnect,
@@ -8115,7 +8711,7 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
8115
8711
  }
8116
8712
  }
8117
8713
  }
8118
- function getLinkHref2(el) {
8714
+ function getLinkHref3(el) {
8119
8715
  const anchor = el instanceof HTMLAnchorElement ? el : el.querySelector("a");
8120
8716
  return anchor?.getAttribute("href") ?? "";
8121
8717
  }
@@ -8165,7 +8761,7 @@ function collectEditableNodes(extraContent) {
8165
8761
  return { key: el.dataset.ohwKey ?? "", type: "video", text: getVideoEl(el)?.src ?? "" };
8166
8762
  }
8167
8763
  if (el.dataset.ohwEditable === "link") {
8168
- return { key: el.dataset.ohwKey ?? "", type: "link", text: getLinkHref2(el) };
8764
+ return { key: el.dataset.ohwKey ?? "", type: "link", text: getLinkHref3(el) };
8169
8765
  }
8170
8766
  return {
8171
8767
  key: el.dataset.ohwKey ?? "",
@@ -8176,7 +8772,7 @@ function collectEditableNodes(extraContent) {
8176
8772
  document.querySelectorAll("[data-ohw-href-key]").forEach((el) => {
8177
8773
  const key = el.getAttribute("data-ohw-href-key") ?? "";
8178
8774
  if (!key) return;
8179
- nodes.push({ key, type: "link", text: getLinkHref2(el) });
8775
+ nodes.push({ key, type: "link", text: getLinkHref3(el) });
8180
8776
  });
8181
8777
  if (extraContent) {
8182
8778
  for (const key of [NAV_ORDER_KEY, FOOTER_ORDER_KEY, NAV_COUNT_KEY]) {
@@ -8279,7 +8875,7 @@ function applyLinkByKey(key, val) {
8279
8875
  }
8280
8876
  function isInsideLinkEditor(target) {
8281
8877
  return Boolean(
8282
- 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"]')
8878
+ 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-ohw-more-menu]") || target.closest('[data-slot="dropdown-menu-content"]') || target.closest('[data-slot="popover-content"]') || target.closest('[data-slot="dialog-content"]') || target.closest('[data-slot="dialog-overlay"]')
8283
8879
  );
8284
8880
  }
8285
8881
  function getHrefKeyFromElement(el) {
@@ -8360,7 +8956,7 @@ function isInferredFooterGroup(el) {
8360
8956
  return countFooterNavItems(el) >= 2;
8361
8957
  }
8362
8958
  function isNavigationContainer(el) {
8363
- return el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isNavigationRoot(el) || isInferredFooterGroup(el);
8959
+ 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);
8364
8960
  }
8365
8961
  function isNavbarLinksContainer(el) {
8366
8962
  return el.hasAttribute("data-ohw-nav-container");
@@ -8379,6 +8975,9 @@ function isPointOverNavigation(x, y) {
8379
8975
  const roots = /* @__PURE__ */ new Set();
8380
8976
  const navRoot = document.querySelector("[data-ohw-nav-root]") ?? document.querySelector("nav");
8381
8977
  if (navRoot) roots.add(navRoot);
8978
+ document.querySelectorAll("[data-ohw-nav-drawer], [data-ohw-nav-container]").forEach((el) => {
8979
+ roots.add(el);
8980
+ });
8382
8981
  const footer = document.querySelector("footer");
8383
8982
  if (footer) roots.add(footer);
8384
8983
  for (const root of roots) {
@@ -8407,6 +9006,12 @@ function isPointOverNavItem(container, x, y) {
8407
9006
  return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
8408
9007
  });
8409
9008
  }
9009
+ function isPointOverFooterColumn(x, y) {
9010
+ return listFooterColumns().some((col) => {
9011
+ const r2 = col.getBoundingClientRect();
9012
+ return x >= r2.left && x <= r2.right && y >= r2.top && y <= r2.bottom;
9013
+ });
9014
+ }
8410
9015
  function resolveNavContainerSelectionTarget(target, clientX, clientY) {
8411
9016
  if (getNavigationItemAnchor(target)) return null;
8412
9017
  if (target.closest('[data-ohw-role="navbar-button"]')) return null;
@@ -8437,7 +9042,10 @@ function getNavigationSelectionParent(el) {
8437
9042
  if (footerGroup) return footerGroup;
8438
9043
  return getNavigationRoot(el);
8439
9044
  }
8440
- if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup(el)) {
9045
+ if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup(el))) {
9046
+ return getFooterLinksContainer();
9047
+ }
9048
+ if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isFooterLinksContainer(el) || isInferredFooterGroup(el)) {
8441
9049
  return getNavigationRoot(el);
8442
9050
  }
8443
9051
  return null;
@@ -8664,7 +9272,7 @@ function EditGlowChrome({
8664
9272
  hideHandle = false
8665
9273
  }) {
8666
9274
  const GAP = SELECTION_CHROME_GAP2;
8667
- return /* @__PURE__ */ jsxs14(
9275
+ return /* @__PURE__ */ jsxs15(
8668
9276
  "div",
8669
9277
  {
8670
9278
  ref: elRef,
@@ -8679,7 +9287,7 @@ function EditGlowChrome({
8679
9287
  zIndex: 2147483646
8680
9288
  },
8681
9289
  children: [
8682
- /* @__PURE__ */ jsx25(
9290
+ /* @__PURE__ */ jsx27(
8683
9291
  "div",
8684
9292
  {
8685
9293
  style: {
@@ -8692,7 +9300,7 @@ function EditGlowChrome({
8692
9300
  }
8693
9301
  }
8694
9302
  ),
8695
- reorderHrefKey && !hideHandle && /* @__PURE__ */ jsx25(
9303
+ reorderHrefKey && !hideHandle && /* @__PURE__ */ jsx27(
8696
9304
  "div",
8697
9305
  {
8698
9306
  "data-ohw-drag-handle-container": "",
@@ -8704,7 +9312,7 @@ function EditGlowChrome({
8704
9312
  transform: "translate(calc(-100% - 7px), -50%)",
8705
9313
  pointerEvents: dragDisabled ? "none" : "auto"
8706
9314
  },
8707
- children: /* @__PURE__ */ jsx25(
9315
+ children: /* @__PURE__ */ jsx27(
8708
9316
  DragHandle,
8709
9317
  {
8710
9318
  "aria-label": `Reorder ${reorderHrefKey}`,
@@ -8914,7 +9522,7 @@ function FloatingToolbar({
8914
9522
  return () => ro.disconnect();
8915
9523
  }, [showEditLink, activeCommands]);
8916
9524
  const { top, left, transform } = calcToolbarPos(rect, parentScroll, measuredW);
8917
- return /* @__PURE__ */ jsx25(
9525
+ return /* @__PURE__ */ jsx27(
8918
9526
  "div",
8919
9527
  {
8920
9528
  ref: setRefs,
@@ -8926,12 +9534,12 @@ function FloatingToolbar({
8926
9534
  zIndex: 2147483647,
8927
9535
  pointerEvents: "auto"
8928
9536
  },
8929
- children: /* @__PURE__ */ jsxs14(CustomToolbar, { children: [
8930
- TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs14(React11.Fragment, { children: [
8931
- gi > 0 && /* @__PURE__ */ jsx25(CustomToolbarDivider, {}),
9537
+ children: /* @__PURE__ */ jsxs15(CustomToolbar, { children: [
9538
+ TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs15(React11.Fragment, { children: [
9539
+ gi > 0 && /* @__PURE__ */ jsx27(CustomToolbarDivider, {}),
8932
9540
  btns.map((btn) => {
8933
9541
  const isActive = activeCommands.has(btn.cmd);
8934
- return /* @__PURE__ */ jsx25(
9542
+ return /* @__PURE__ */ jsx27(
8935
9543
  CustomToolbarButton,
8936
9544
  {
8937
9545
  title: btn.title,
@@ -8940,7 +9548,7 @@ function FloatingToolbar({
8940
9548
  e.preventDefault();
8941
9549
  onCommand(btn.cmd);
8942
9550
  },
8943
- children: /* @__PURE__ */ jsx25(
9551
+ children: /* @__PURE__ */ jsx27(
8944
9552
  "svg",
8945
9553
  {
8946
9554
  width: "16",
@@ -8961,7 +9569,7 @@ function FloatingToolbar({
8961
9569
  );
8962
9570
  })
8963
9571
  ] }, gi)),
8964
- showEditLink ? /* @__PURE__ */ jsx25(
9572
+ showEditLink ? /* @__PURE__ */ jsx27(
8965
9573
  CustomToolbarButton,
8966
9574
  {
8967
9575
  type: "button",
@@ -8975,7 +9583,7 @@ function FloatingToolbar({
8975
9583
  e.preventDefault();
8976
9584
  e.stopPropagation();
8977
9585
  },
8978
- children: /* @__PURE__ */ jsx25(Link2, { className: "size-4 shrink-0", "aria-hidden": true })
9586
+ children: /* @__PURE__ */ jsx27(Link2, { className: "size-4 shrink-0", "aria-hidden": true })
8979
9587
  }
8980
9588
  ) : null
8981
9589
  ] })
@@ -8992,7 +9600,7 @@ function StateToggle({
8992
9600
  states,
8993
9601
  onStateChange
8994
9602
  }) {
8995
- return /* @__PURE__ */ jsx25(
9603
+ return /* @__PURE__ */ jsx27(
8996
9604
  ToggleGroup,
8997
9605
  {
8998
9606
  "data-ohw-state-toggle": "",
@@ -9006,7 +9614,7 @@ function StateToggle({
9006
9614
  left: rect.right - 8,
9007
9615
  transform: "translateX(-100%)"
9008
9616
  },
9009
- children: states.map((state) => /* @__PURE__ */ jsx25(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
9617
+ children: states.map((state) => /* @__PURE__ */ jsx27(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
9010
9618
  }
9011
9619
  );
9012
9620
  }
@@ -9033,7 +9641,7 @@ function OhhwellsBridge() {
9033
9641
  const router = useRouter2();
9034
9642
  const searchParams = useSearchParams();
9035
9643
  const isEditMode = isEditSessionActive();
9036
- const [bridgeRoot, setBridgeRoot] = useState8(null);
9644
+ const [bridgeRoot, setBridgeRoot] = useState9(null);
9037
9645
  useEffect9(() => {
9038
9646
  const figtreeFontId = "ohw-figtree-font";
9039
9647
  if (!document.getElementById(figtreeFontId)) {
@@ -9062,12 +9670,12 @@ function OhhwellsBridge() {
9062
9670
  const subdomainFromQuery = searchParams.get("subdomain");
9063
9671
  const subdomain = resolveSubdomain(subdomainFromQuery);
9064
9672
  useLinkHrefGuardian(pathname, subdomain, isEditMode);
9065
- const postToParent2 = useCallback4((data) => {
9673
+ const postToParent2 = useCallback5((data) => {
9066
9674
  if (typeof window !== "undefined" && window.parent !== window) {
9067
9675
  window.parent.postMessage(data, "*");
9068
9676
  }
9069
9677
  }, []);
9070
- const [fetchState, setFetchState] = useState8("idle");
9678
+ const [fetchState, setFetchState] = useState9("idle");
9071
9679
  const autoSaveTimers = useRef7(/* @__PURE__ */ new Map());
9072
9680
  const activeElRef = useRef7(null);
9073
9681
  const pointerHeldRef = useRef7(false);
@@ -9078,8 +9686,8 @@ function OhhwellsBridge() {
9078
9686
  const activeStateElRef = useRef7(null);
9079
9687
  const parentScrollRef = useRef7(null);
9080
9688
  const visibleViewportRef = useRef7(null);
9081
- const [dialogPortalContainer, setDialogPortalContainer] = useState8(null);
9082
- const attachVisibleViewport = useCallback4((node) => {
9689
+ const [dialogPortalContainer, setDialogPortalContainer] = useState9(null);
9690
+ const attachVisibleViewport = useCallback5((node) => {
9083
9691
  visibleViewportRef.current = node;
9084
9692
  setDialogPortalContainer(node);
9085
9693
  if (node) applyVisibleViewport(node, parentScrollRef.current);
@@ -9089,9 +9697,9 @@ function OhhwellsBridge() {
9089
9697
  const hoveredImageRef = useRef7(null);
9090
9698
  const hoveredImageHasTextOverlapRef = useRef7(false);
9091
9699
  const dragOverElRef = useRef7(null);
9092
- const [mediaHover, setMediaHover] = useState8(null);
9093
- const [carouselHover, setCarouselHover] = useState8(null);
9094
- const [uploadingRects, setUploadingRects] = useState8({});
9700
+ const [mediaHover, setMediaHover] = useState9(null);
9701
+ const [carouselHover, setCarouselHover] = useState9(null);
9702
+ const [uploadingRects, setUploadingRects] = useState9({});
9095
9703
  const hoveredGapRef = useRef7(null);
9096
9704
  const imageUnhoverTimerRef = useRef7(null);
9097
9705
  const imageShowTimerRef = useRef7(null);
@@ -9116,40 +9724,40 @@ function OhhwellsBridge() {
9116
9724
  postToParentRef.current = postToParent2;
9117
9725
  const sectionsLoadedRef = useRef7(false);
9118
9726
  const pendingScheduleConfigRequests = useRef7([]);
9119
- const [toolbarRect, setToolbarRect] = useState8(null);
9120
- const [toolbarVariant, setToolbarVariant] = useState8("none");
9727
+ const [toolbarRect, setToolbarRect] = useState9(null);
9728
+ const [toolbarVariant, setToolbarVariant] = useState9("none");
9121
9729
  const toolbarVariantRef = useRef7("none");
9122
9730
  toolbarVariantRef.current = toolbarVariant;
9123
- const [selectedIsCta, setSelectedIsCta] = useState8(false);
9124
- const [reorderHrefKey, setReorderHrefKey] = useState8(null);
9125
- const [reorderDragDisabled, setReorderDragDisabled] = useState8(false);
9126
- const [toggleState, setToggleState] = useState8(null);
9127
- const [maxBadge, setMaxBadge] = useState8(null);
9128
- const [activeCommands, setActiveCommands] = useState8(/* @__PURE__ */ new Set());
9129
- const [sectionGap, setSectionGap] = useState8(null);
9130
- const [toolbarShowEditLink, setToolbarShowEditLink] = useState8(false);
9731
+ const [selectedIsCta, setSelectedIsCta] = useState9(false);
9732
+ const [reorderHrefKey, setReorderHrefKey] = useState9(null);
9733
+ const [reorderDragDisabled, setReorderDragDisabled] = useState9(false);
9734
+ const [toggleState, setToggleState] = useState9(null);
9735
+ const [maxBadge, setMaxBadge] = useState9(null);
9736
+ const [activeCommands, setActiveCommands] = useState9(/* @__PURE__ */ new Set());
9737
+ const [sectionGap, setSectionGap] = useState9(null);
9738
+ const [toolbarShowEditLink, setToolbarShowEditLink] = useState9(false);
9131
9739
  const hoveredNavContainerRef = useRef7(null);
9132
- const [hoveredNavContainerRect, setHoveredNavContainerRect] = useState8(null);
9740
+ const [hoveredNavContainerRect, setHoveredNavContainerRect] = useState9(null);
9133
9741
  const hoveredItemElRef = useRef7(null);
9134
- const [hoveredItemRect, setHoveredItemRect] = useState8(null);
9742
+ const [hoveredItemRect, setHoveredItemRect] = useState9(null);
9135
9743
  const siblingHintElRef = useRef7(null);
9136
- const [siblingHintRect, setSiblingHintRect] = useState8(null);
9137
- const [siblingHintRects, setSiblingHintRects] = useState8([]);
9138
- const [isItemDragging, setIsItemDragging] = useState8(false);
9139
- const [isFooterFrameSelection, setIsFooterFrameSelection] = useState8(false);
9744
+ const [siblingHintRect, setSiblingHintRect] = useState9(null);
9745
+ const [siblingHintRects, setSiblingHintRects] = useState9([]);
9746
+ const [isItemDragging, setIsItemDragging] = useState9(false);
9747
+ const [isFooterFrameSelection, setIsFooterFrameSelection] = useState9(false);
9140
9748
  const footerDragRef = useRef7(null);
9141
- const [footerDropSlots, setFooterDropSlots] = useState8([]);
9142
- const [activeFooterDropIndex, setActiveFooterDropIndex] = useState8(null);
9143
- const [draggedItemRect, setDraggedItemRect] = useState8(null);
9749
+ const [footerDropSlots, setFooterDropSlots] = useState9([]);
9750
+ const [activeFooterDropIndex, setActiveFooterDropIndex] = useState9(null);
9751
+ const [draggedItemRect, setDraggedItemRect] = useState9(null);
9144
9752
  const footerPointerDragRef = useRef7(null);
9145
9753
  const suppressNextClickRef = useRef7(false);
9146
9754
  const suppressClickUntilRef = useRef7(0);
9147
- const [linkPopover, setLinkPopover] = useState8(null);
9755
+ const [linkPopover, setLinkPopover] = useState9(null);
9148
9756
  const linkPopoverSessionRef = useRef7(null);
9149
9757
  const addNavAfterAnchorRef = useRef7(null);
9150
9758
  const editContentRef = useRef7({});
9151
- const [sitePages, setSitePages] = useState8([]);
9152
- const [sectionsByPath, setSectionsByPath] = useState8({});
9759
+ const [sitePages, setSitePages] = useState9([]);
9760
+ const [sectionsByPath, setSectionsByPath] = useState9({});
9153
9761
  const sectionsPrefetchGenRef = useRef7(0);
9154
9762
  const setLinkPopoverRef = useRef7(setLinkPopover);
9155
9763
  const linkPopoverPanelRef = useRef7(null);
@@ -9193,7 +9801,7 @@ function OhhwellsBridge() {
9193
9801
  const bumpLinkPopoverGrace = () => {
9194
9802
  linkPopoverGraceUntilRef.current = Date.now() + 350;
9195
9803
  };
9196
- const runSectionsPrefetch = useCallback4((pages) => {
9804
+ const runSectionsPrefetch = useCallback5((pages) => {
9197
9805
  if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
9198
9806
  const gen = ++sectionsPrefetchGenRef.current;
9199
9807
  const paths = pages.map((p) => p.path);
@@ -9319,10 +9927,10 @@ function OhhwellsBridge() {
9319
9927
  vvp.removeEventListener("resize", update);
9320
9928
  };
9321
9929
  }, []);
9322
- const refreshStateRules = useCallback4(() => {
9930
+ const refreshStateRules = useCallback5(() => {
9323
9931
  editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
9324
9932
  }, []);
9325
- const processConfigRequest = useCallback4((insertAfterVal) => {
9933
+ const processConfigRequest = useCallback5((insertAfterVal) => {
9326
9934
  const tracker = getSectionsTracker();
9327
9935
  let entries = [];
9328
9936
  try {
@@ -9345,7 +9953,7 @@ function OhhwellsBridge() {
9345
9953
  }
9346
9954
  window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
9347
9955
  }, [isEditMode]);
9348
- const deactivate = useCallback4(() => {
9956
+ const deactivate = useCallback5(() => {
9349
9957
  const el = activeElRef.current;
9350
9958
  if (!el) return;
9351
9959
  const key = el.dataset.ohwKey;
@@ -9377,12 +9985,12 @@ function OhhwellsBridge() {
9377
9985
  setToolbarShowEditLink(false);
9378
9986
  postToParent2({ type: "ow:exit-edit" });
9379
9987
  }, [postToParent2]);
9380
- const clearSelectedAttr = useCallback4(() => {
9988
+ const clearSelectedAttr = useCallback5(() => {
9381
9989
  document.querySelectorAll("[data-ohw-selected]").forEach((el) => {
9382
9990
  el.removeAttribute("data-ohw-selected");
9383
9991
  });
9384
9992
  }, []);
9385
- const deselect = useCallback4(() => {
9993
+ const deselect = useCallback5(() => {
9386
9994
  clearSelectedAttr();
9387
9995
  selectedElRef.current = null;
9388
9996
  selectedHrefKeyRef.current = null;
@@ -9402,11 +10010,11 @@ function OhhwellsBridge() {
9402
10010
  setToolbarVariant("none");
9403
10011
  }
9404
10012
  }, [clearSelectedAttr]);
9405
- const markSelected = useCallback4((el) => {
10013
+ const markSelected = useCallback5((el) => {
9406
10014
  clearSelectedAttr();
9407
10015
  el.setAttribute("data-ohw-selected", "");
9408
10016
  }, [clearSelectedAttr]);
9409
- const resolveHrefKeyElement = useCallback4((hrefKey) => {
10017
+ const resolveHrefKeyElement = useCallback5((hrefKey) => {
9410
10018
  if (isFooterHrefKey(hrefKey)) {
9411
10019
  return document.querySelector(
9412
10020
  `footer [data-ohw-href-key="${CSS.escape(hrefKey)}"]`
@@ -9421,7 +10029,7 @@ function OhhwellsBridge() {
9421
10029
  `[data-ohw-href-key="${CSS.escape(hrefKey)}"]`
9422
10030
  );
9423
10031
  }, []);
9424
- const resyncSelectedNavigationItem = useCallback4(() => {
10032
+ const resyncSelectedNavigationItem = useCallback5(() => {
9425
10033
  const hrefKey = selectedHrefKeyRef.current;
9426
10034
  if (hrefKey) {
9427
10035
  const link = resolveHrefKeyElement(hrefKey);
@@ -9449,7 +10057,7 @@ function OhhwellsBridge() {
9449
10057
  );
9450
10058
  }
9451
10059
  }, [resolveHrefKeyElement]);
9452
- const reselectNavigationItem = useCallback4((navAnchor) => {
10060
+ const reselectNavigationItem = useCallback5((navAnchor) => {
9453
10061
  selectedElRef.current = navAnchor;
9454
10062
  selectedHrefKeyRef.current = navAnchor.getAttribute("data-ohw-href-key");
9455
10063
  selectedFooterColAttrRef.current = null;
@@ -9464,7 +10072,7 @@ function OhhwellsBridge() {
9464
10072
  setToolbarShowEditLink(false);
9465
10073
  setActiveCommands(/* @__PURE__ */ new Set());
9466
10074
  }, [markSelected]);
9467
- const commitNavigationTextEdit = useCallback4((navAnchor) => {
10075
+ const commitNavigationTextEdit = useCallback5((navAnchor) => {
9468
10076
  const el = activeElRef.current;
9469
10077
  if (!el) return;
9470
10078
  const key = el.dataset.ohwKey;
@@ -9491,7 +10099,7 @@ function OhhwellsBridge() {
9491
10099
  postToParent2({ type: "ow:exit-edit" });
9492
10100
  reselectNavigationItem(navAnchor);
9493
10101
  }, [postToParent2, reselectNavigationItem]);
9494
- const handleAddTopLevelNavItem = useCallback4(() => {
10102
+ const handleAddTopLevelNavItem = useCallback5(() => {
9495
10103
  const items = listNavbarItems();
9496
10104
  addNavAfterAnchorRef.current = items[items.length - 1] ?? null;
9497
10105
  deselectRef.current();
@@ -9503,7 +10111,19 @@ function OhhwellsBridge() {
9503
10111
  intent: "add-nav"
9504
10112
  });
9505
10113
  }, []);
9506
- const clearFooterDragVisuals = useCallback4(() => {
10114
+ const handleAddFooterColumn = useCallback5(() => {
10115
+ deselectRef.current();
10116
+ deactivateRef.current();
10117
+ const result = addFooterColumnWithPersist({ postToParent: postToParent2 });
10118
+ editContentRef.current = {
10119
+ ...editContentRef.current,
10120
+ ...buildFooterColumnEditContentPatch(result)
10121
+ };
10122
+ requestAnimationFrame(() => {
10123
+ selectRef.current(result.firstLink);
10124
+ });
10125
+ }, [postToParent2]);
10126
+ const clearFooterDragVisuals = useCallback5(() => {
9507
10127
  footerDragRef.current = null;
9508
10128
  setSiblingHintRects([]);
9509
10129
  setFooterDropSlots([]);
@@ -9512,7 +10132,7 @@ function OhhwellsBridge() {
9512
10132
  setIsItemDragging(false);
9513
10133
  unlockFooterDragInteraction();
9514
10134
  }, []);
9515
- const refreshFooterDragVisuals = useCallback4((session, activeSlot, clientX, clientY) => {
10135
+ const refreshFooterDragVisuals = useCallback5((session, activeSlot, clientX, clientY) => {
9516
10136
  const dragged = session.draggedEl;
9517
10137
  setDraggedItemRect(dragged.getBoundingClientRect());
9518
10138
  if (typeof clientX === "number" && typeof clientY === "number") {
@@ -9543,7 +10163,7 @@ function OhhwellsBridge() {
9543
10163
  });
9544
10164
  const beginFooterDragRef = useRef7(() => {
9545
10165
  });
9546
- const beginFooterDrag = useCallback4(
10166
+ const beginFooterDrag = useCallback5(
9547
10167
  (session) => {
9548
10168
  const rect = session.draggedEl.getBoundingClientRect();
9549
10169
  session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
@@ -9563,7 +10183,7 @@ function OhhwellsBridge() {
9563
10183
  [refreshFooterDragVisuals]
9564
10184
  );
9565
10185
  beginFooterDragRef.current = beginFooterDrag;
9566
- const commitFooterDrag = useCallback4(
10186
+ const commitFooterDrag = useCallback5(
9567
10187
  (clientX, clientY) => {
9568
10188
  const session = footerDragRef.current;
9569
10189
  if (!session) {
@@ -9667,7 +10287,7 @@ function OhhwellsBridge() {
9667
10287
  [clearFooterDragVisuals, resolveHrefKeyElement, resyncSelectedNavigationItem]
9668
10288
  );
9669
10289
  commitFooterDragRef.current = commitFooterDrag;
9670
- const startFooterLinkDrag = useCallback4(
10290
+ const startFooterLinkDrag = useCallback5(
9671
10291
  (anchor, clientX, clientY, wasSelected) => {
9672
10292
  const hrefKey = anchor.getAttribute("data-ohw-href-key");
9673
10293
  if (!hrefKey || !isFooterHrefKey(hrefKey)) return false;
@@ -9688,7 +10308,7 @@ function OhhwellsBridge() {
9688
10308
  },
9689
10309
  [beginFooterDrag]
9690
10310
  );
9691
- const startFooterColumnDrag = useCallback4(
10311
+ const startFooterColumnDrag = useCallback5(
9692
10312
  (columnEl, clientX, clientY, wasSelected) => {
9693
10313
  const columns = listFooterColumns();
9694
10314
  const idx = columns.indexOf(columnEl);
@@ -9708,7 +10328,7 @@ function OhhwellsBridge() {
9708
10328
  },
9709
10329
  [beginFooterDrag]
9710
10330
  );
9711
- const handleItemDragStart = useCallback4(
10331
+ const handleItemDragStart = useCallback5(
9712
10332
  (e) => {
9713
10333
  const selected = selectedElRef.current;
9714
10334
  if (!selected) {
@@ -9728,7 +10348,7 @@ function OhhwellsBridge() {
9728
10348
  },
9729
10349
  [startFooterColumnDrag, startFooterLinkDrag, startNavLinkDrag]
9730
10350
  );
9731
- const handleItemDragEnd = useCallback4(
10351
+ const handleItemDragEnd = useCallback5(
9732
10352
  (e) => {
9733
10353
  if (footerDragRef.current) {
9734
10354
  const x = e?.clientX;
@@ -9754,7 +10374,7 @@ function OhhwellsBridge() {
9754
10374
  },
9755
10375
  [commitFooterDrag, commitNavDrag, navDragRef]
9756
10376
  );
9757
- const handleItemChromePointerDown = useCallback4((e) => {
10377
+ const handleItemChromePointerDown = useCallback5((e) => {
9758
10378
  if (e.button !== 0) return;
9759
10379
  const selected = selectedElRef.current;
9760
10380
  if (!selected) return;
@@ -9785,7 +10405,7 @@ function OhhwellsBridge() {
9785
10405
  }
9786
10406
  if (armNavPressFromChrome(selected, e.clientX, e.clientY, e.pointerId)) return;
9787
10407
  }, [armNavPressFromChrome]);
9788
- const handleItemChromeClick = useCallback4((clientX, clientY) => {
10408
+ const handleItemChromeClick = useCallback5((clientX, clientY) => {
9789
10409
  if (suppressNextClickRef.current || Date.now() < suppressClickUntilRef.current) {
9790
10410
  suppressNextClickRef.current = false;
9791
10411
  return;
@@ -9798,7 +10418,7 @@ function OhhwellsBridge() {
9798
10418
  }, []);
9799
10419
  reselectNavigationItemRef.current = reselectNavigationItem;
9800
10420
  commitNavigationTextEditRef.current = commitNavigationTextEdit;
9801
- const select = useCallback4((anchor) => {
10421
+ const select = useCallback5((anchor) => {
9802
10422
  if (!isNavigationItem(anchor)) return;
9803
10423
  if (activeElRef.current) deactivate();
9804
10424
  selectedElRef.current = anchor;
@@ -9824,10 +10444,10 @@ function OhhwellsBridge() {
9824
10444
  setToolbarShowEditLink(false);
9825
10445
  setActiveCommands(/* @__PURE__ */ new Set());
9826
10446
  }, [deactivate, markSelected]);
9827
- const selectFrame = useCallback4((el) => {
10447
+ const selectFrame = useCallback5((el) => {
9828
10448
  if (!isNavigationContainer(el)) return;
9829
10449
  if (activeElRef.current) deactivate();
9830
- const isFooterColumn = el.hasAttribute("data-ohw-footer-col") || Boolean(el.closest("footer") && isInferredFooterGroup(el));
10450
+ const isFooterColumn = !isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || Boolean(el.closest("footer") && isInferredFooterGroup(el)));
9831
10451
  selectedElRef.current = el;
9832
10452
  selectedHrefKeyRef.current = null;
9833
10453
  selectedFooterColAttrRef.current = isFooterColumn ? el.getAttribute("data-ohw-footer-col") ?? String(listFooterColumns().indexOf(el)) : null;
@@ -9852,7 +10472,7 @@ function OhhwellsBridge() {
9852
10472
  setToolbarShowEditLink(false);
9853
10473
  setActiveCommands(/* @__PURE__ */ new Set());
9854
10474
  }, [deactivate, markSelected]);
9855
- const activate = useCallback4((el, options) => {
10475
+ const activate = useCallback5((el, options) => {
9856
10476
  if (activeElRef.current === el) return;
9857
10477
  clearSelectedAttr();
9858
10478
  selectedElRef.current = null;
@@ -10360,7 +10980,7 @@ function OhhwellsBridge() {
10360
10980
  setLinkPopoverRef.current({
10361
10981
  key: editable.dataset.ohwKey ?? "",
10362
10982
  mode: "edit",
10363
- target: getLinkHref2(editable)
10983
+ target: getLinkHref3(editable)
10364
10984
  });
10365
10985
  return;
10366
10986
  }
@@ -10385,7 +11005,7 @@ function OhhwellsBridge() {
10385
11005
  }
10386
11006
  e.preventDefault();
10387
11007
  e.stopPropagation();
10388
- activateRef.current(editable);
11008
+ activateRef.current(editable, { caretX: e.clientX, caretY: e.clientY });
10389
11009
  return;
10390
11010
  }
10391
11011
  const hrefAnchor = getNavigationItemAnchor(target);
@@ -10412,6 +11032,18 @@ function OhhwellsBridge() {
10412
11032
  selectFrameRef.current(footerColClick);
10413
11033
  return;
10414
11034
  }
11035
+ const footerLinksToSelect = resolveFooterLinksContainerSelectionTarget(
11036
+ target,
11037
+ e.clientX,
11038
+ e.clientY,
11039
+ isPointOverNavItem
11040
+ );
11041
+ if (footerLinksToSelect) {
11042
+ e.preventDefault();
11043
+ e.stopPropagation();
11044
+ selectFrameRef.current(footerLinksToSelect);
11045
+ return;
11046
+ }
10415
11047
  const navContainerToSelect = resolveNavContainerSelectionTarget(target, e.clientX, e.clientY);
10416
11048
  if (navContainerToSelect) {
10417
11049
  e.preventDefault();
@@ -10470,8 +11102,8 @@ function OhhwellsBridge() {
10470
11102
  return;
10471
11103
  }
10472
11104
  const navLabel = getNavigationLabelEditable(target);
10473
- if (!navLabel) return;
10474
- const { editable } = navLabel;
11105
+ const editable = navLabel?.editable ?? target.closest('[data-ohw-editable="text"], [data-ohw-editable="plain"]');
11106
+ if (!editable || isMediaEditable(editable) || editable.dataset.ohwEditable === "link") return;
10475
11107
  e.preventDefault();
10476
11108
  e.stopPropagation();
10477
11109
  if (activeElRef.current !== editable) {
@@ -10492,16 +11124,38 @@ function OhhwellsBridge() {
10492
11124
  setHoveredNavContainerRect(null);
10493
11125
  return;
10494
11126
  }
10495
- if (toolbarVariantRef.current !== "select-frame") {
10496
- const navContainer = target.closest("[data-ohw-nav-container]");
10497
- if (navContainer && !getNavigationItemAnchor(target)) {
10498
- hoveredNavContainerRef.current = navContainer;
10499
- setHoveredNavContainerRect(navContainer.getBoundingClientRect());
10500
- hoveredItemElRef.current = null;
10501
- setHoveredItemRect(null);
10502
- return;
11127
+ {
11128
+ const selected2 = selectedElRef.current;
11129
+ const selectedIsFooterColumn = Boolean(selected2) && !isFooterLinksContainer(selected2) && (selected2.hasAttribute("data-ohw-footer-col") || selected2.hasAttribute("data-ohw-footer-column") || Boolean(selected2.closest("footer") && isInferredFooterGroup(selected2)));
11130
+ const allowNavContainerHover = toolbarVariantRef.current !== "select-frame";
11131
+ const allowFooterLinksHover = toolbarVariantRef.current !== "select-frame" || selectedIsFooterColumn;
11132
+ if (allowNavContainerHover) {
11133
+ const navContainer = target.closest("[data-ohw-nav-container]");
11134
+ if (navContainer && !getNavigationItemAnchor(target)) {
11135
+ hoveredNavContainerRef.current = navContainer;
11136
+ setHoveredNavContainerRect(navContainer.getBoundingClientRect());
11137
+ hoveredItemElRef.current = null;
11138
+ setHoveredItemRect(null);
11139
+ return;
11140
+ }
10503
11141
  }
10504
- if (!target.closest("[data-ohw-nav-container]")) {
11142
+ if (allowFooterLinksHover) {
11143
+ const navContainer = target.closest("[data-ohw-nav-container]");
11144
+ if (!navContainer) {
11145
+ const footerLinks = target.closest("[data-ohw-footer-links], .rb-footer-links") ?? null;
11146
+ if (footerLinks && selected2 !== footerLinks && !getNavigationItemAnchor(target) && !target.closest("[data-ohw-footer-col], [data-ohw-footer-column]")) {
11147
+ hoveredNavContainerRef.current = footerLinks;
11148
+ setHoveredNavContainerRect(footerLinks.getBoundingClientRect());
11149
+ hoveredItemElRef.current = null;
11150
+ setHoveredItemRect(null);
11151
+ return;
11152
+ }
11153
+ if (!footerLinks) {
11154
+ hoveredNavContainerRef.current = null;
11155
+ setHoveredNavContainerRect(null);
11156
+ }
11157
+ }
11158
+ } else if (toolbarVariantRef.current === "select-frame") {
10505
11159
  hoveredNavContainerRef.current = null;
10506
11160
  setHoveredNavContainerRect(null);
10507
11161
  }
@@ -10543,9 +11197,9 @@ function OhhwellsBridge() {
10543
11197
  };
10544
11198
  const handleMouseOut = (e) => {
10545
11199
  const target = e.target;
10546
- if (target.closest("[data-ohw-nav-container], [data-ohw-footer-col], [data-ohw-footer-column]")) {
11200
+ if (target.closest("[data-ohw-nav-container], [data-ohw-footer-col], [data-ohw-footer-column], [data-ohw-footer-links], .rb-footer-links")) {
10547
11201
  const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
10548
- 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]")) {
11202
+ 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]")) {
10549
11203
  return;
10550
11204
  }
10551
11205
  hoveredNavContainerRef.current = null;
@@ -10640,6 +11294,15 @@ function OhhwellsBridge() {
10640
11294
  if (track) track.setAttribute("data-ohw-hover-paused", "");
10641
11295
  };
10642
11296
  const clearImageHover = () => setMediaHover(null);
11297
+ const dismissImageHover = () => {
11298
+ if (hoveredImageRef.current) {
11299
+ hoveredImageRef.current = null;
11300
+ hoveredImageHasTextOverlapRef.current = false;
11301
+ resumeAnimTracks();
11302
+ postToParentRef.current({ type: "ow:image-unhover" });
11303
+ }
11304
+ clearImageHover();
11305
+ };
10643
11306
  const findImageAtPoint = (clientX, clientY, fromParentViewport) => {
10644
11307
  const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
10645
11308
  const images = Array.from(document.querySelectorAll(MEDIA_SELECTOR));
@@ -10683,16 +11346,13 @@ function OhhwellsBridge() {
10683
11346
  }
10684
11347
  return smallest;
10685
11348
  };
10686
- const dismissImageHover = () => {
10687
- if (hoveredImageRef.current) {
10688
- hoveredImageRef.current = null;
10689
- hoveredImageHasTextOverlapRef.current = false;
10690
- resumeAnimTracks();
10691
- postToParentRef.current({ type: "ow:image-unhover" });
10692
- }
10693
- };
10694
11349
  const probeNavigationHoverAt = (x, y) => {
10695
- if (toolbarVariantRef.current === "select-frame") {
11350
+ const selected = selectedElRef.current;
11351
+ const selectedIsFooterColumn = Boolean(selected) && !isFooterLinksContainer(selected) && (selected.hasAttribute("data-ohw-footer-col") || selected.hasAttribute("data-ohw-footer-column") || Boolean(selected.closest("footer") && isInferredFooterGroup(selected)));
11352
+ const selectedIsFooterLinks = Boolean(selected && isFooterLinksContainer(selected));
11353
+ const allowNavContainerHover = toolbarVariantRef.current !== "select-frame";
11354
+ const allowFooterLinksHover = (toolbarVariantRef.current !== "select-frame" || selectedIsFooterColumn) && !selectedIsFooterLinks;
11355
+ if (toolbarVariantRef.current === "select-frame" && !allowFooterLinksHover) {
10696
11356
  hoveredNavContainerRef.current = null;
10697
11357
  setHoveredNavContainerRect(null);
10698
11358
  }
@@ -10714,7 +11374,6 @@ function OhhwellsBridge() {
10714
11374
  if (navItemHit) {
10715
11375
  hoveredNavContainerRef.current = null;
10716
11376
  setHoveredNavContainerRect(null);
10717
- const selected = selectedElRef.current;
10718
11377
  if (selected !== navItemHit) {
10719
11378
  clearHrefKeyHover(navItemHit);
10720
11379
  hoveredItemElRef.current = navItemHit;
@@ -10726,7 +11385,7 @@ function OhhwellsBridge() {
10726
11385
  return;
10727
11386
  }
10728
11387
  }
10729
- if (toolbarVariantRef.current !== "select-frame") {
11388
+ if (allowNavContainerHover) {
10730
11389
  for (const container of navContainers) {
10731
11390
  const containerRect = container.getBoundingClientRect();
10732
11391
  const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
@@ -10738,12 +11397,23 @@ function OhhwellsBridge() {
10738
11397
  setHoveredItemRect(null);
10739
11398
  return;
10740
11399
  }
10741
- hoveredNavContainerRef.current = null;
10742
- setHoveredNavContainerRect(null);
10743
- } else {
10744
- hoveredNavContainerRef.current = null;
10745
- setHoveredNavContainerRect(null);
10746
11400
  }
11401
+ if (allowFooterLinksHover) {
11402
+ const footerLinks = getFooterLinksContainer();
11403
+ if (footerLinks) {
11404
+ const containerRect = footerLinks.getBoundingClientRect();
11405
+ const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
11406
+ if (overContainer && !isPointOverNavItem(footerLinks, x, y) && !isPointOverFooterColumn(x, y)) {
11407
+ hoveredNavContainerRef.current = footerLinks;
11408
+ setHoveredNavContainerRect(footerLinks.getBoundingClientRect());
11409
+ hoveredItemElRef.current = null;
11410
+ setHoveredItemRect(null);
11411
+ return;
11412
+ }
11413
+ }
11414
+ }
11415
+ hoveredNavContainerRef.current = null;
11416
+ setHoveredNavContainerRect(null);
10747
11417
  for (const column of footerColumns) {
10748
11418
  const containerRect = column.getBoundingClientRect();
10749
11419
  const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
@@ -10782,6 +11452,13 @@ function OhhwellsBridge() {
10782
11452
  probeNavigationHoverAt(x, y);
10783
11453
  return;
10784
11454
  }
11455
+ const overMoreMenu = document.elementFromPoint(x, y)?.closest?.(
11456
+ '[data-ohw-more-menu], [data-slot="dropdown-menu-content"], [data-slot="dropdown-menu-item"]'
11457
+ );
11458
+ if (overMoreMenu) {
11459
+ dismissImageHover();
11460
+ return;
11461
+ }
10785
11462
  hoveredNavContainerRef.current = null;
10786
11463
  setHoveredNavContainerRect(null);
10787
11464
  if (hoveredItemElRef.current?.hasAttribute("data-ohw-footer-col") || hoveredItemElRef.current?.hasAttribute("data-ohw-footer-column")) {
@@ -10828,7 +11505,7 @@ function OhhwellsBridge() {
10828
11505
  return;
10829
11506
  }
10830
11507
  const topEl = document.elementFromPoint(x2, y2);
10831
- if (topEl?.closest('[data-ohw-toolbar], [data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
11508
+ if (topEl?.closest('[data-ohw-toolbar], [data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"], [data-ohw-more-menu], [data-slot="dropdown-menu-content"], [data-slot="dropdown-menu-item"]')) {
10832
11509
  if (hoveredImageRef.current) {
10833
11510
  hoveredImageRef.current = null;
10834
11511
  resumeAnimTracks();
@@ -11005,6 +11682,7 @@ function OhhwellsBridge() {
11005
11682
  const ZONE = 20;
11006
11683
  for (let i = 0; i < sections.length; i++) {
11007
11684
  const a = sections[i];
11685
+ if (a.dataset.ohwSection === "footer") continue;
11008
11686
  const b = sections[i + 1] ?? null;
11009
11687
  const boundaryY = a.getBoundingClientRect().bottom;
11010
11688
  if (Math.abs(y - boundaryY) <= ZONE) {
@@ -11251,6 +11929,7 @@ function OhhwellsBridge() {
11251
11929
  }
11252
11930
  editContentRef.current = { ...editContentRef.current, ...content };
11253
11931
  reconcileNavbarItemsFromContent(editContentRef.current);
11932
+ reconcileFooterOrderFromContent(editContentRef.current);
11254
11933
  syncNavigationDragCursorAttrs();
11255
11934
  enforceLinkHrefs();
11256
11935
  postToParentRef.current({ type: "ow:hydrate-done" });
@@ -11270,6 +11949,7 @@ function OhhwellsBridge() {
11270
11949
  window.addEventListener("message", handleDeactivate);
11271
11950
  const handleUiEscape = (e) => {
11272
11951
  if (e.data?.type !== "ui:escape") return;
11952
+ if (document.querySelector("[data-ohw-more-menu]")) return;
11273
11953
  if (linkPopoverOpenRef.current) {
11274
11954
  setLinkPopoverRef.current(null);
11275
11955
  return;
@@ -11305,6 +11985,11 @@ function OhhwellsBridge() {
11305
11985
  }
11306
11986
  if (selectedElRef.current) {
11307
11987
  if (toolbarVariantRef.current === "select-frame") {
11988
+ const parent2 = getNavigationSelectionParent(selectedElRef.current);
11989
+ if (parent2 && isNavigationContainer(parent2) && isFooterLinksContainer(parent2) && !isFooterLinksContainer(selectedElRef.current)) {
11990
+ selectFrameRef.current(parent2);
11991
+ return;
11992
+ }
11308
11993
  deselectRef.current();
11309
11994
  return;
11310
11995
  }
@@ -11319,14 +12004,12 @@ function OhhwellsBridge() {
11319
12004
  window.addEventListener("message", handleUiEscape);
11320
12005
  const handleKeyDown = (e) => {
11321
12006
  if (e.key === "Escape" && document.querySelector("[data-ohw-section-picker]")) return;
12007
+ if (e.key === "Escape" && document.querySelector("[data-ohw-more-menu]")) return;
11322
12008
  if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a" && activeElRef.current) {
11323
- const navAnchor = getNavigationItemAnchor(activeElRef.current);
11324
- if (navAnchor) {
11325
- e.preventDefault();
11326
- selectAllTextInEditable(activeElRef.current);
11327
- refreshActiveCommandsRef.current();
11328
- return;
11329
- }
12009
+ e.preventDefault();
12010
+ selectAllTextInEditable(activeElRef.current);
12011
+ refreshActiveCommandsRef.current();
12012
+ return;
11330
12013
  }
11331
12014
  if (e.key === "Escape" && linkPopoverOpenRef.current) {
11332
12015
  setLinkPopoverRef.current(null);
@@ -11334,6 +12017,12 @@ function OhhwellsBridge() {
11334
12017
  }
11335
12018
  if (e.key === "Escape" && selectedElRef.current && !activeElRef.current) {
11336
12019
  if (toolbarVariantRef.current === "select-frame") {
12020
+ const parent2 = getNavigationSelectionParent(selectedElRef.current);
12021
+ if (parent2 && isNavigationContainer(parent2) && isFooterLinksContainer(parent2) && !isFooterLinksContainer(selectedElRef.current)) {
12022
+ e.preventDefault();
12023
+ selectFrameRef.current(parent2);
12024
+ return;
12025
+ }
11337
12026
  deselectRef.current();
11338
12027
  return;
11339
12028
  }
@@ -11994,7 +12683,7 @@ function OhhwellsBridge() {
11994
12683
  window.addEventListener("hashchange", onHashChange);
11995
12684
  return () => window.removeEventListener("hashchange", onHashChange);
11996
12685
  }, [pathname]);
11997
- const handleCommand = useCallback4((cmd) => {
12686
+ const handleCommand = useCallback5((cmd) => {
11998
12687
  const el = activeElRef.current;
11999
12688
  const selBefore = window.getSelection();
12000
12689
  let savedOffsets = null;
@@ -12030,7 +12719,7 @@ function OhhwellsBridge() {
12030
12719
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
12031
12720
  refreshActiveCommandsRef.current();
12032
12721
  }, []);
12033
- const handleStateChange = useCallback4((state) => {
12722
+ const handleStateChange = useCallback5((state) => {
12034
12723
  if (!activeStateElRef.current) return;
12035
12724
  const el = activeStateElRef.current;
12036
12725
  if (state === "Default") {
@@ -12043,22 +12732,22 @@ function OhhwellsBridge() {
12043
12732
  }
12044
12733
  setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
12045
12734
  }, [deactivate]);
12046
- const closeLinkPopover = useCallback4(() => {
12735
+ const closeLinkPopover = useCallback5(() => {
12047
12736
  addNavAfterAnchorRef.current = null;
12048
12737
  setLinkPopover(null);
12049
12738
  }, []);
12050
- const openLinkPopoverForActive = useCallback4(() => {
12739
+ const openLinkPopoverForActive = useCallback5(() => {
12051
12740
  const hrefCtx = getHrefKeyFromElement(activeElRef.current);
12052
12741
  if (!hrefCtx) return;
12053
12742
  bumpLinkPopoverGrace();
12054
12743
  setLinkPopover({
12055
12744
  key: hrefCtx.key,
12056
12745
  mode: "edit",
12057
- target: getLinkHref2(hrefCtx.anchor)
12746
+ target: getLinkHref3(hrefCtx.anchor)
12058
12747
  });
12059
12748
  deactivate();
12060
12749
  }, [deactivate]);
12061
- const openLinkPopoverForSelected = useCallback4(() => {
12750
+ const openLinkPopoverForSelected = useCallback5(() => {
12062
12751
  const anchor = selectedElRef.current;
12063
12752
  if (!anchor) return;
12064
12753
  const key = anchor.getAttribute("data-ohw-href-key");
@@ -12067,11 +12756,108 @@ function OhhwellsBridge() {
12067
12756
  setLinkPopover({
12068
12757
  key,
12069
12758
  mode: "edit",
12070
- target: getLinkHref2(anchor)
12759
+ target: getLinkHref3(anchor)
12071
12760
  });
12072
12761
  deselect();
12073
12762
  }, [deselect]);
12074
- const handleLinkPopoverSubmit = useCallback4(
12763
+ const handleSelectParent = useCallback5(() => {
12764
+ const selected = selectedElRef.current;
12765
+ if (!selected) return;
12766
+ if (toolbarVariantRef.current === "select-frame") {
12767
+ deselectRef.current();
12768
+ return;
12769
+ }
12770
+ const parent = getNavigationSelectionParent(selected);
12771
+ if (parent && isNavigationContainer(parent)) {
12772
+ selectFrameRef.current(parent);
12773
+ } else {
12774
+ deselectRef.current();
12775
+ }
12776
+ }, []);
12777
+ const handleDuplicateSelected = useCallback5(() => {
12778
+ const selected = selectedElRef.current;
12779
+ if (!selected || !isNavigationItem(selected)) return;
12780
+ const hrefKey = selected.getAttribute("data-ohw-href-key");
12781
+ if (!hrefKey) return;
12782
+ if (isNavbarHrefKey(hrefKey)) {
12783
+ const result = duplicateNavbarItem(selected);
12784
+ if (!result) return;
12785
+ applyLinkByKey(result.hrefKey, result.href);
12786
+ document.querySelectorAll(`[data-ohw-key="${result.labelKey}"]`).forEach((el) => {
12787
+ el.textContent = result.label;
12788
+ });
12789
+ const nodes = [
12790
+ { key: result.hrefKey, text: result.href },
12791
+ { key: result.labelKey, text: result.label }
12792
+ ];
12793
+ for (const child of result.childResults) {
12794
+ applyLinkByKey(child.hrefKey, child.href);
12795
+ document.querySelectorAll(`[data-ohw-key="${child.labelKey}"]`).forEach((el) => {
12796
+ el.textContent = child.label;
12797
+ });
12798
+ nodes.push(
12799
+ { key: child.hrefKey, text: child.href },
12800
+ { key: child.labelKey, text: child.label }
12801
+ );
12802
+ }
12803
+ const maxIndex = Math.max(
12804
+ result.index,
12805
+ ...result.childResults.map((c) => c.index)
12806
+ );
12807
+ const navCount = String(maxIndex + 1);
12808
+ nodes.push(
12809
+ { key: NAV_COUNT_KEY, text: navCount },
12810
+ { key: NAV_ORDER_KEY, text: result.orderJson }
12811
+ );
12812
+ editContentRef.current = {
12813
+ ...editContentRef.current,
12814
+ [result.hrefKey]: result.href,
12815
+ [result.labelKey]: result.label,
12816
+ ...Object.fromEntries(
12817
+ result.childResults.flatMap((c) => [
12818
+ [c.hrefKey, c.href],
12819
+ [c.labelKey, c.label]
12820
+ ])
12821
+ ),
12822
+ [NAV_COUNT_KEY]: navCount,
12823
+ [NAV_ORDER_KEY]: result.orderJson
12824
+ };
12825
+ postToParent2({ type: "ow:change", nodes });
12826
+ enforceLinkHrefs();
12827
+ requestAnimationFrame(() => {
12828
+ selectRef.current(result.anchor);
12829
+ });
12830
+ return;
12831
+ }
12832
+ if (isFooterHrefKey(hrefKey)) {
12833
+ const result = duplicateFooterItem(selected);
12834
+ if (!result) return;
12835
+ applyLinkByKey(result.hrefKey, result.href);
12836
+ document.querySelectorAll(`[data-ohw-key="${result.labelKey}"]`).forEach((el) => {
12837
+ el.textContent = result.label;
12838
+ });
12839
+ const orderJson = JSON.stringify(result.order);
12840
+ editContentRef.current = {
12841
+ ...editContentRef.current,
12842
+ [result.hrefKey]: result.href,
12843
+ [result.labelKey]: result.label,
12844
+ [FOOTER_ORDER_KEY]: orderJson
12845
+ };
12846
+ postToParent2({
12847
+ type: "ow:change",
12848
+ nodes: [
12849
+ { key: result.hrefKey, text: result.href },
12850
+ { key: result.labelKey, text: result.label },
12851
+ { key: FOOTER_ORDER_KEY, text: orderJson }
12852
+ ]
12853
+ });
12854
+ enforceLinkHrefs();
12855
+ requestAnimationFrame(() => {
12856
+ selectRef.current(result.anchor);
12857
+ });
12858
+ }
12859
+ }, [postToParent2]);
12860
+ const handleLinkPopoverSubmit = useCallback5(
12075
12861
  (target) => {
12076
12862
  const session = linkPopoverSessionRef.current;
12077
12863
  if (!session) return;
@@ -12130,19 +12916,19 @@ function OhhwellsBridge() {
12130
12916
  const showEditLink = toolbarShowEditLink;
12131
12917
  const currentSections = sectionsByPath[pathname] ?? [];
12132
12918
  linkPopoverOpenRef.current = linkPopover !== null;
12133
- const handleMediaReplace = useCallback4(
12919
+ const handleMediaReplace = useCallback5(
12134
12920
  (key) => {
12135
12921
  postToParent2({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
12136
12922
  },
12137
12923
  [postToParent2, mediaHover?.elementType]
12138
12924
  );
12139
- const handleEditCarousel = useCallback4(
12925
+ const handleEditCarousel = useCallback5(
12140
12926
  (key) => {
12141
12927
  postToParent2({ type: "ow:carousel-open", key, images: readCarouselValue(key) });
12142
12928
  },
12143
12929
  [postToParent2]
12144
12930
  );
12145
- const handleMediaFadeOutComplete = useCallback4((key) => {
12931
+ const handleMediaFadeOutComplete = useCallback5((key) => {
12146
12932
  setUploadingRects((prev) => {
12147
12933
  if (!(key in prev)) return prev;
12148
12934
  const next = { ...prev };
@@ -12150,7 +12936,7 @@ function OhhwellsBridge() {
12150
12936
  return next;
12151
12937
  });
12152
12938
  }, []);
12153
- const handleVideoSettingsChange = useCallback4(
12939
+ const handleVideoSettingsChange = useCallback5(
12154
12940
  (key, settings) => {
12155
12941
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
12156
12942
  const video = getVideoEl(el);
@@ -12173,9 +12959,9 @@ function OhhwellsBridge() {
12173
12959
  [postToParent2]
12174
12960
  );
12175
12961
  return bridgeRoot ? createPortal2(
12176
- /* @__PURE__ */ jsxs14(Fragment5, { children: [
12177
- /* @__PURE__ */ jsx25("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
12178
- Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ jsx25(
12962
+ /* @__PURE__ */ jsxs15(Fragment5, { children: [
12963
+ /* @__PURE__ */ jsx27("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
12964
+ Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ jsx27(
12179
12965
  MediaOverlay,
12180
12966
  {
12181
12967
  hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
@@ -12186,7 +12972,7 @@ function OhhwellsBridge() {
12186
12972
  },
12187
12973
  `uploading-${key}`
12188
12974
  )),
12189
- mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ jsx25(
12975
+ mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ jsx27(
12190
12976
  MediaOverlay,
12191
12977
  {
12192
12978
  hover: mediaHover,
@@ -12195,11 +12981,11 @@ function OhhwellsBridge() {
12195
12981
  onVideoSettingsChange: handleVideoSettingsChange
12196
12982
  }
12197
12983
  ),
12198
- carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx25(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
12199
- siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
12200
- siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
12201
- isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
12202
- isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ jsx25(
12984
+ carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx27(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
12985
+ siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ jsx27(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
12986
+ siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ jsx27(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
12987
+ isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ jsx27(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
12988
+ isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ jsx27(
12203
12989
  "div",
12204
12990
  {
12205
12991
  className: "pointer-events-none fixed z-2147483646",
@@ -12209,7 +12995,7 @@ function OhhwellsBridge() {
12209
12995
  width: slot.width,
12210
12996
  height: slot.height
12211
12997
  },
12212
- children: /* @__PURE__ */ jsx25(
12998
+ children: /* @__PURE__ */ jsx27(
12213
12999
  DropIndicator,
12214
13000
  {
12215
13001
  direction: slot.direction,
@@ -12220,7 +13006,7 @@ function OhhwellsBridge() {
12220
13006
  },
12221
13007
  `footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
12222
13008
  )),
12223
- isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ jsx25(
13009
+ isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ jsx27(
12224
13010
  "div",
12225
13011
  {
12226
13012
  className: "pointer-events-none fixed z-2147483646",
@@ -12230,7 +13016,7 @@ function OhhwellsBridge() {
12230
13016
  width: slot.width,
12231
13017
  height: slot.height
12232
13018
  },
12233
- children: /* @__PURE__ */ jsx25(
13019
+ children: /* @__PURE__ */ jsx27(
12234
13020
  DropIndicator,
12235
13021
  {
12236
13022
  direction: slot.direction,
@@ -12241,10 +13027,11 @@ function OhhwellsBridge() {
12241
13027
  },
12242
13028
  `nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
12243
13029
  )),
12244
- hoveredNavContainerRect && toolbarVariant !== "select-frame" && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
12245
- hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
12246
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer(selectedElRef.current) && /* @__PURE__ */ jsx25(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
12247
- toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ jsx25(
13030
+ hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx27(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
13031
+ hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx27(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
13032
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer(selectedElRef.current) && /* @__PURE__ */ jsx27(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
13033
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ jsx27(FooterContainerChrome, { rect: toolbarRect, onAdd: handleAddFooterColumn }),
13034
+ toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ jsx27(
12248
13035
  ItemInteractionLayer,
12249
13036
  {
12250
13037
  rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
@@ -12258,21 +13045,23 @@ function OhhwellsBridge() {
12258
13045
  onItemPointerDown: handleItemChromePointerDown,
12259
13046
  onItemClick: handleItemChromeClick,
12260
13047
  itemDragSurface: !isFooterFrameSelection,
12261
- toolbar: toolbarVariant === "link-action" && !isItemDragging ? /* @__PURE__ */ jsx25(
13048
+ toolbar: toolbarVariant === "link-action" && !isItemDragging ? /* @__PURE__ */ jsx27(
12262
13049
  ItemActionToolbar,
12263
13050
  {
12264
13051
  onEditLink: openLinkPopoverForSelected,
13052
+ onSelectParent: handleSelectParent,
13053
+ onDuplicate: handleDuplicateSelected,
12265
13054
  addItemDisabled: true,
12266
13055
  editLinkDisabled: false,
12267
- moreDisabled: true,
13056
+ moreDisabled: false,
12268
13057
  showAddItem: !selectedIsCta,
12269
13058
  showMore: !selectedIsCta
12270
13059
  }
12271
13060
  ) : void 0
12272
13061
  }
12273
13062
  ),
12274
- toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ jsxs14(Fragment5, { children: [
12275
- /* @__PURE__ */ jsx25(
13063
+ toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ jsxs15(Fragment5, { children: [
13064
+ /* @__PURE__ */ jsx27(
12276
13065
  EditGlowChrome,
12277
13066
  {
12278
13067
  rect: toolbarRect,
@@ -12282,7 +13071,7 @@ function OhhwellsBridge() {
12282
13071
  hideHandle: isItemDragging
12283
13072
  }
12284
13073
  ),
12285
- /* @__PURE__ */ jsx25(
13074
+ /* @__PURE__ */ jsx27(
12286
13075
  FloatingToolbar,
12287
13076
  {
12288
13077
  rect: toolbarRect,
@@ -12295,7 +13084,7 @@ function OhhwellsBridge() {
12295
13084
  }
12296
13085
  )
12297
13086
  ] }),
12298
- maxBadge && /* @__PURE__ */ jsxs14(
13087
+ maxBadge && /* @__PURE__ */ jsxs15(
12299
13088
  "div",
12300
13089
  {
12301
13090
  "data-ohw-max-badge": "",
@@ -12321,7 +13110,7 @@ function OhhwellsBridge() {
12321
13110
  ]
12322
13111
  }
12323
13112
  ),
12324
- toggleState && !linkPopover && /* @__PURE__ */ jsx25(
13113
+ toggleState && !linkPopover && /* @__PURE__ */ jsx27(
12325
13114
  StateToggle,
12326
13115
  {
12327
13116
  rect: toggleState.rect,
@@ -12330,15 +13119,15 @@ function OhhwellsBridge() {
12330
13119
  onStateChange: handleStateChange
12331
13120
  }
12332
13121
  ),
12333
- sectionGap && !linkPopover && /* @__PURE__ */ jsxs14(
13122
+ sectionGap && !linkPopover && /* @__PURE__ */ jsxs15(
12334
13123
  "div",
12335
13124
  {
12336
13125
  "data-ohw-section-insert-line": "",
12337
13126
  className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
12338
13127
  style: { top: sectionGap.y, transform: "translateY(-50%)" },
12339
13128
  children: [
12340
- /* @__PURE__ */ jsx25("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
12341
- /* @__PURE__ */ jsx25(
13129
+ /* @__PURE__ */ jsx27("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
13130
+ /* @__PURE__ */ jsx27(
12342
13131
  Badge,
12343
13132
  {
12344
13133
  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",
@@ -12355,11 +13144,11 @@ function OhhwellsBridge() {
12355
13144
  children: "Add Section"
12356
13145
  }
12357
13146
  ),
12358
- /* @__PURE__ */ jsx25("div", { className: "flex-1 bg-primary", style: { height: 3 } })
13147
+ /* @__PURE__ */ jsx27("div", { className: "flex-1 bg-primary", style: { height: 3 } })
12359
13148
  ]
12360
13149
  }
12361
13150
  ),
12362
- linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx25(
13151
+ linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx27(
12363
13152
  LinkPopover,
12364
13153
  {
12365
13154
  panelRef: linkPopoverPanelRef,
@@ -12386,6 +13175,12 @@ export {
12386
13175
  CustomToolbarDivider,
12387
13176
  DragHandle,
12388
13177
  DropIndicator,
13178
+ DropdownMenu,
13179
+ DropdownMenuContent,
13180
+ DropdownMenuGroup,
13181
+ DropdownMenuItem,
13182
+ DropdownMenuSeparator,
13183
+ DropdownMenuTrigger,
12389
13184
  ItemActionToolbar,
12390
13185
  ItemInteractionLayer,
12391
13186
  LinkEditorPanel,