@ohhwells/bridge 0.1.50 → 0.1.51-next.119

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 useCallback5, 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
 
@@ -13,6 +13,9 @@ function setStoredLinkHref(key, href) {
13
13
  function getStoredLinkHref(key) {
14
14
  return linkHrefStore.get(key);
15
15
  }
16
+ function clearStoredLinkHref(key) {
17
+ linkHrefStore.delete(key);
18
+ }
16
19
  function enforceLinkHrefs() {
17
20
  document.querySelectorAll("[data-ohw-href-key]").forEach((el) => {
18
21
  const key = el.getAttribute("data-ohw-href-key") ?? "";
@@ -4338,22 +4341,116 @@ var CustomToolbarButton = React4.forwardRef(
4338
4341
  CustomToolbarButton.displayName = "CustomToolbarButton";
4339
4342
 
4340
4343
  // src/ui/item-action-toolbar.tsx
4341
- import { Link, MoreHorizontal, Plus } from "lucide-react";
4344
+ import { useState as useState3 } from "react";
4345
+ import { Copy, CornerLeftUp, Link, MoreHorizontal, Plus, Trash2 } from "lucide-react";
4346
+
4347
+ // src/ui/dropdown-menu.tsx
4348
+ import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui";
4349
+ import { jsx as jsx7 } from "react/jsx-runtime";
4350
+ function DropdownMenu({ ...props }) {
4351
+ return /* @__PURE__ */ jsx7(DropdownMenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
4352
+ }
4353
+ function DropdownMenuTrigger({
4354
+ ...props
4355
+ }) {
4356
+ return /* @__PURE__ */ jsx7(DropdownMenuPrimitive.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
4357
+ }
4358
+ function DropdownMenuGroup({
4359
+ className,
4360
+ ...props
4361
+ }) {
4362
+ return /* @__PURE__ */ jsx7(
4363
+ DropdownMenuPrimitive.Group,
4364
+ {
4365
+ "data-slot": "dropdown-menu-group",
4366
+ className: cn("flex w-full flex-col items-start p-1", className),
4367
+ ...props
4368
+ }
4369
+ );
4370
+ }
4371
+ function DropdownMenuContent({
4372
+ className,
4373
+ sideOffset = 6,
4374
+ ...props
4375
+ }) {
4376
+ return /* @__PURE__ */ jsx7(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx7(
4377
+ DropdownMenuPrimitive.Content,
4378
+ {
4379
+ "data-slot": "dropdown-menu-content",
4380
+ "data-ohw-more-menu": "",
4381
+ sideOffset,
4382
+ className: cn(
4383
+ "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",
4384
+ "shadow-[0px_4px_6px_0px_rgba(0,0,0,0.1),0px_2px_4px_0px_rgba(0,0,0,0.1)]",
4385
+ "origin-[var(--radix-dropdown-menu-content-transform-origin)]",
4386
+ "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",
4387
+ "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",
4388
+ className
4389
+ ),
4390
+ ...props
4391
+ }
4392
+ ) });
4393
+ }
4394
+ function DropdownMenuItem({
4395
+ className,
4396
+ inset,
4397
+ variant = "default",
4398
+ ...props
4399
+ }) {
4400
+ return /* @__PURE__ */ jsx7(
4401
+ DropdownMenuPrimitive.Item,
4402
+ {
4403
+ "data-slot": "dropdown-menu-item",
4404
+ "data-inset": inset ? "" : void 0,
4405
+ "data-variant": variant,
4406
+ className: cn(
4407
+ "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",
4408
+ "text-popover-foreground",
4409
+ "focus:bg-muted data-[highlighted]:bg-muted",
4410
+ "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
4411
+ "[&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
4412
+ "[&_svg:not([class*=absolute])]:relative",
4413
+ // Leading icon — Figma absolute left-2 / top-1/2
4414
+ "[&>svg:first-child]:absolute [&>svg:first-child]:left-2 [&>svg:first-child]:top-1/2 [&>svg:first-child]:-translate-y-1/2",
4415
+ "data-[variant=destructive]:text-destructive",
4416
+ "data-[variant=destructive]:focus:bg-bg-destructive-10 data-[variant=destructive]:focus:text-destructive",
4417
+ "data-[variant=destructive]:data-[highlighted]:bg-bg-destructive-10 data-[variant=destructive]:data-[highlighted]:text-destructive",
4418
+ "data-[variant=destructive]:[&_svg]:text-destructive",
4419
+ inset && "pl-8",
4420
+ className
4421
+ ),
4422
+ ...props
4423
+ }
4424
+ );
4425
+ }
4426
+ function DropdownMenuSeparator({
4427
+ className,
4428
+ ...props
4429
+ }) {
4430
+ return /* @__PURE__ */ jsx7(
4431
+ DropdownMenuPrimitive.Separator,
4432
+ {
4433
+ "data-slot": "dropdown-menu-separator",
4434
+ className: cn("h-px w-full bg-border", className),
4435
+ ...props
4436
+ }
4437
+ );
4438
+ }
4342
4439
 
4343
4440
  // src/ui/tooltip.tsx
4344
4441
  import { Tooltip as TooltipPrimitive } from "radix-ui";
4345
- import { jsx as jsx7 } from "react/jsx-runtime";
4442
+ import { jsx as jsx8 } from "react/jsx-runtime";
4346
4443
  function TooltipProvider({
4347
4444
  delayDuration = 0,
4348
4445
  ...props
4349
4446
  }) {
4350
- return /* @__PURE__ */ jsx7(TooltipPrimitive.Provider, { "data-slot": "tooltip-provider", delayDuration, ...props });
4447
+ return /* @__PURE__ */ jsx8(TooltipPrimitive.Provider, { "data-slot": "tooltip-provider", delayDuration, ...props });
4351
4448
  }
4352
4449
  function Tooltip({ ...props }) {
4353
- return /* @__PURE__ */ jsx7(TooltipPrimitive.Root, { "data-slot": "tooltip", ...props });
4450
+ return /* @__PURE__ */ jsx8(TooltipPrimitive.Root, { "data-slot": "tooltip", ...props });
4354
4451
  }
4355
4452
  function TooltipTrigger({ ...props }) {
4356
- return /* @__PURE__ */ jsx7(TooltipPrimitive.Trigger, { "data-slot": "tooltip-trigger", ...props });
4453
+ return /* @__PURE__ */ jsx8(TooltipPrimitive.Trigger, { "data-slot": "tooltip-trigger", ...props });
4357
4454
  }
4358
4455
  var arrowClassBySide = {
4359
4456
  top: "before:bottom-0 before:left-1/2 before:-translate-x-1/2 before:translate-y-1/2",
@@ -4370,7 +4467,7 @@ function TooltipContent({
4370
4467
  ...props
4371
4468
  }) {
4372
4469
  const resolvedSide = side ?? "bottom";
4373
- return /* @__PURE__ */ jsx7(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsx7(
4470
+ return /* @__PURE__ */ jsx8(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsx8(
4374
4471
  TooltipPrimitive.Content,
4375
4472
  {
4376
4473
  "data-slot": "tooltip-content",
@@ -4393,7 +4490,7 @@ function TooltipContent({
4393
4490
  }
4394
4491
 
4395
4492
  // src/ui/item-action-toolbar.tsx
4396
- import { jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
4493
+ import { jsx as jsx9, jsxs as jsxs3 } from "react/jsx-runtime";
4397
4494
  function ToolbarActionTooltip({
4398
4495
  label,
4399
4496
  side = "bottom",
@@ -4401,25 +4498,32 @@ function ToolbarActionTooltip({
4401
4498
  buttonProps,
4402
4499
  children
4403
4500
  }) {
4404
- const button = /* @__PURE__ */ jsx8(CustomToolbarButton, { type: "button", "aria-label": label, disabled, ...buttonProps, children });
4501
+ const button = /* @__PURE__ */ jsx9(CustomToolbarButton, { type: "button", "aria-label": label, disabled, ...buttonProps, children });
4405
4502
  return /* @__PURE__ */ jsxs3(Tooltip, { children: [
4406
- /* @__PURE__ */ jsx8(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ jsx8("span", { className: "inline-flex", children: button }) : button }),
4407
- /* @__PURE__ */ jsx8(TooltipContent, { side, sideOffset: 9, children: label })
4503
+ /* @__PURE__ */ jsx9(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ jsx9("span", { className: "inline-flex", children: button }) : button }),
4504
+ /* @__PURE__ */ jsx9(TooltipContent, { side, sideOffset: 9, children: label })
4408
4505
  ] });
4409
4506
  }
4410
4507
  function ItemActionToolbar({
4411
4508
  onEditLink,
4412
4509
  onAddItem,
4413
- onMore,
4510
+ onSelectParent,
4511
+ onDuplicate,
4512
+ onDelete,
4414
4513
  editLinkDisabled = false,
4415
4514
  addItemDisabled = true,
4416
- moreDisabled = true,
4515
+ moreDisabled = false,
4516
+ selectParentDisabled = false,
4517
+ duplicateDisabled = false,
4518
+ deleteDisabled = false,
4519
+ showEditLink = true,
4417
4520
  showAddItem = true,
4418
4521
  showMore = true,
4419
4522
  tooltipSide = "bottom"
4420
4523
  }) {
4421
- return /* @__PURE__ */ jsx8(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs3(CustomToolbar, { children: [
4422
- /* @__PURE__ */ jsx8(
4524
+ const [moreOpen, setMoreOpen] = useState3(false);
4525
+ return /* @__PURE__ */ jsx9(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsxs3(CustomToolbar, { children: [
4526
+ showEditLink ? /* @__PURE__ */ jsx9(
4423
4527
  ToolbarActionTooltip,
4424
4528
  {
4425
4529
  label: "Edit link",
@@ -4437,10 +4541,10 @@ function ItemActionToolbar({
4437
4541
  e.stopPropagation();
4438
4542
  }
4439
4543
  },
4440
- children: /* @__PURE__ */ jsx8(Link, { className: "size-4 shrink-0", "aria-hidden": true })
4544
+ children: /* @__PURE__ */ jsx9(Link, { className: "size-4 shrink-0", "aria-hidden": true })
4441
4545
  }
4442
- ),
4443
- showAddItem ? /* @__PURE__ */ jsx8(
4546
+ ) : null,
4547
+ showAddItem ? /* @__PURE__ */ jsx9(
4444
4548
  ToolbarActionTooltip,
4445
4549
  {
4446
4550
  label: "Add item",
@@ -4454,32 +4558,84 @@ function ItemActionToolbar({
4454
4558
  onAddItem?.();
4455
4559
  }
4456
4560
  },
4457
- children: /* @__PURE__ */ jsx8(Plus, { className: "size-4 shrink-0", "aria-hidden": true })
4561
+ children: /* @__PURE__ */ jsx9(Plus, { className: "size-4 shrink-0", "aria-hidden": true })
4458
4562
  }
4459
4563
  ) : null,
4460
- showMore ? /* @__PURE__ */ jsx8(
4461
- ToolbarActionTooltip,
4462
- {
4463
- label: "More",
4464
- side: tooltipSide,
4465
- disabled: moreDisabled,
4466
- buttonProps: {
4564
+ showMore ? /* @__PURE__ */ jsxs3(DropdownMenu, { open: moreOpen, onOpenChange: setMoreOpen, children: [
4565
+ /* @__PURE__ */ jsxs3(Tooltip, { open: moreOpen ? false : void 0, children: [
4566
+ /* @__PURE__ */ jsx9(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx9(DropdownMenuTrigger, { asChild: true, disabled: moreDisabled, children: /* @__PURE__ */ jsx9(
4567
+ CustomToolbarButton,
4568
+ {
4569
+ type: "button",
4570
+ "aria-label": "More",
4571
+ disabled: moreDisabled,
4572
+ onMouseDown: (e) => {
4573
+ e.preventDefault();
4574
+ e.stopPropagation();
4575
+ },
4576
+ children: /* @__PURE__ */ jsx9(MoreHorizontal, { className: "size-4 shrink-0", "aria-hidden": true })
4577
+ }
4578
+ ) }) }),
4579
+ /* @__PURE__ */ jsx9(TooltipContent, { side: tooltipSide, sideOffset: 9, children: "More" })
4580
+ ] }),
4581
+ /* @__PURE__ */ jsxs3(
4582
+ DropdownMenuContent,
4583
+ {
4584
+ align: "end",
4585
+ side: "bottom",
4586
+ onCloseAutoFocus: (e) => e.preventDefault(),
4467
4587
  onMouseDown: (e) => {
4468
- if (moreDisabled) return;
4469
4588
  e.preventDefault();
4470
4589
  e.stopPropagation();
4471
- onMore?.();
4472
- }
4473
- },
4474
- children: /* @__PURE__ */ jsx8(MoreHorizontal, { className: "size-4 shrink-0", "aria-hidden": true })
4475
- }
4476
- ) : null
4590
+ },
4591
+ children: [
4592
+ /* @__PURE__ */ jsxs3(DropdownMenuGroup, { children: [
4593
+ /* @__PURE__ */ jsxs3(
4594
+ DropdownMenuItem,
4595
+ {
4596
+ disabled: selectParentDisabled,
4597
+ onSelect: () => onSelectParent?.(),
4598
+ children: [
4599
+ /* @__PURE__ */ jsx9(CornerLeftUp, { size: 12, "aria-hidden": true }),
4600
+ "Select parent"
4601
+ ]
4602
+ }
4603
+ ),
4604
+ /* @__PURE__ */ jsxs3(
4605
+ DropdownMenuItem,
4606
+ {
4607
+ disabled: duplicateDisabled,
4608
+ onSelect: () => onDuplicate?.(),
4609
+ children: [
4610
+ /* @__PURE__ */ jsx9(Copy, { size: 12, "aria-hidden": true }),
4611
+ "Duplicate"
4612
+ ]
4613
+ }
4614
+ )
4615
+ ] }),
4616
+ /* @__PURE__ */ jsx9(DropdownMenuSeparator, {}),
4617
+ /* @__PURE__ */ jsx9(DropdownMenuGroup, { children: /* @__PURE__ */ jsxs3(
4618
+ DropdownMenuItem,
4619
+ {
4620
+ variant: "destructive",
4621
+ disabled: deleteDisabled,
4622
+ onSelect: () => onDelete?.(),
4623
+ children: [
4624
+ /* @__PURE__ */ jsx9(Trash2, { size: 15, "aria-hidden": true }),
4625
+ "Delete"
4626
+ ]
4627
+ }
4628
+ ) })
4629
+ ]
4630
+ }
4631
+ )
4632
+ ] }) : null
4477
4633
  ] }) });
4478
4634
  }
4479
4635
 
4480
4636
  // src/ui/item-interaction-layer.tsx
4481
4637
  import * as React5 from "react";
4482
- import { jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
4638
+ import { jsx as jsx10, jsxs as jsxs4 } from "react/jsx-runtime";
4483
4639
  var PRIMARY = "var(--ohw-primary, #0885FE)";
4484
4640
  var FOCUS_RING = `0 0 0 4px color-mix(in srgb, ${PRIMARY} 12%, transparent)`;
4485
4641
  var DRAG_SHADOW = "0px 4px 6px -1px rgba(0, 0, 0, 0.1), 0px 2px 4px -2px rgba(0, 0, 0, 0.1)";
@@ -4561,7 +4717,7 @@ function ClampedToolbarSlot({
4561
4717
  window.removeEventListener("resize", clamp);
4562
4718
  };
4563
4719
  }, [placement, children]);
4564
- return /* @__PURE__ */ jsx9(
4720
+ return /* @__PURE__ */ jsx10(
4565
4721
  "div",
4566
4722
  {
4567
4723
  ref: slotRef,
@@ -4617,7 +4773,7 @@ function ItemInteractionLayer({
4617
4773
  zIndex: getChromeZIndex(state)
4618
4774
  },
4619
4775
  children: [
4620
- /* @__PURE__ */ jsx9(
4776
+ /* @__PURE__ */ jsx10(
4621
4777
  "div",
4622
4778
  {
4623
4779
  "aria-hidden": true,
@@ -4625,7 +4781,7 @@ function ItemInteractionLayer({
4625
4781
  style: getChromeStyle(state)
4626
4782
  }
4627
4783
  ),
4628
- itemDragEnabled && /* @__PURE__ */ jsx9(
4784
+ itemDragEnabled && /* @__PURE__ */ jsx10(
4629
4785
  "div",
4630
4786
  {
4631
4787
  "data-ohw-item-drag-surface": "",
@@ -4641,14 +4797,14 @@ function ItemInteractionLayer({
4641
4797
  }
4642
4798
  }
4643
4799
  ),
4644
- showDragHandle && /* @__PURE__ */ jsx9(
4800
+ showDragHandle && /* @__PURE__ */ jsx10(
4645
4801
  "div",
4646
4802
  {
4647
4803
  "data-ohw-drag-handle-container": "",
4648
4804
  className: "pointer-events-auto absolute left-0 top-1/2 z-10 -translate-x-[calc(100%+7px)] -translate-y-1/2",
4649
4805
  style: isDragging ? { opacity: 0 } : void 0,
4650
4806
  "aria-hidden": isDragging || void 0,
4651
- children: /* @__PURE__ */ jsx9(
4807
+ children: /* @__PURE__ */ jsx10(
4652
4808
  DragHandle,
4653
4809
  {
4654
4810
  draggable: !dragDisabled,
@@ -4678,8 +4834,8 @@ function ItemInteractionLayer({
4678
4834
  )
4679
4835
  }
4680
4836
  ),
4681
- showToolbar && state === "active-top" && /* @__PURE__ */ jsx9(ClampedToolbarSlot, { placement: "top", children: toolbar }),
4682
- showToolbar && state === "active-bottom" && /* @__PURE__ */ jsx9(ClampedToolbarSlot, { placement: "bottom", children: toolbar })
4837
+ showToolbar && state === "active-top" && /* @__PURE__ */ jsx10(ClampedToolbarSlot, { placement: "top", children: toolbar }),
4838
+ showToolbar && state === "active-bottom" && /* @__PURE__ */ jsx10(ClampedToolbarSlot, { placement: "bottom", children: toolbar })
4683
4839
  ]
4684
4840
  }
4685
4841
  );
@@ -4692,7 +4848,7 @@ import { Film, ImageIcon, Pause, Play, Volume2, VolumeX } from "lucide-react";
4692
4848
  // src/ui/button.tsx
4693
4849
  import * as React6 from "react";
4694
4850
  import { Slot } from "radix-ui";
4695
- import { jsx as jsx10 } from "react/jsx-runtime";
4851
+ import { jsx as jsx11 } from "react/jsx-runtime";
4696
4852
  var buttonVariants = cva(
4697
4853
  "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",
4698
4854
  {
@@ -4716,7 +4872,7 @@ var buttonVariants = cva(
4716
4872
  var Button = React6.forwardRef(
4717
4873
  ({ className, variant, size, asChild = false, ...props }, ref) => {
4718
4874
  const Comp = asChild ? Slot.Root : "button";
4719
- return /* @__PURE__ */ jsx10(
4875
+ return /* @__PURE__ */ jsx11(
4720
4876
  Comp,
4721
4877
  {
4722
4878
  ref,
@@ -4730,7 +4886,7 @@ var Button = React6.forwardRef(
4730
4886
  Button.displayName = "Button";
4731
4887
 
4732
4888
  // src/ui/MediaOverlay.tsx
4733
- import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
4889
+ import { Fragment as Fragment2, jsx as jsx12, jsxs as jsxs5 } from "react/jsx-runtime";
4734
4890
  var MEDIA_UPLOAD_FADE_MS = 300;
4735
4891
  var VIDEO_SETTINGS_BAR_INSET = 8;
4736
4892
  var OVERLAY_BUTTON_STYLE = {
@@ -4788,7 +4944,7 @@ function MediaOverlay({
4788
4944
  return () => anim.cancel();
4789
4945
  }, [isUploading, fadingOut, onFadeOutComplete, hover.key]);
4790
4946
  if (isUploading) {
4791
- return /* @__PURE__ */ jsx11(
4947
+ return /* @__PURE__ */ jsx12(
4792
4948
  "div",
4793
4949
  {
4794
4950
  ref: skeletonRef,
@@ -4797,7 +4953,7 @@ function MediaOverlay({
4797
4953
  "data-ohw-media-skeleton": "",
4798
4954
  "aria-hidden": true,
4799
4955
  style: { ...box, pointerEvents: "none" },
4800
- children: /* @__PURE__ */ jsx11("style", { children: SKELETON_CSS })
4956
+ children: /* @__PURE__ */ jsx12("style", { children: SKELETON_CSS })
4801
4957
  }
4802
4958
  );
4803
4959
  }
@@ -4817,7 +4973,7 @@ function MediaOverlay({
4817
4973
  },
4818
4974
  onClick: (e) => e.stopPropagation(),
4819
4975
  children: [
4820
- /* @__PURE__ */ jsx11(
4976
+ /* @__PURE__ */ jsx12(
4821
4977
  Button,
4822
4978
  {
4823
4979
  "data-ohw-media-overlay": "",
@@ -4832,10 +4988,10 @@ function MediaOverlay({
4832
4988
  e.stopPropagation();
4833
4989
  onVideoSettingsChange?.(hover.key, { autoplay: !autoplay });
4834
4990
  },
4835
- children: autoplay ? /* @__PURE__ */ jsx11(Pause, { size: 14 }) : /* @__PURE__ */ jsx11(Play, { size: 14 })
4991
+ children: autoplay ? /* @__PURE__ */ jsx12(Pause, { size: 14 }) : /* @__PURE__ */ jsx12(Play, { size: 14 })
4836
4992
  }
4837
4993
  ),
4838
- /* @__PURE__ */ jsx11(
4994
+ /* @__PURE__ */ jsx12(
4839
4995
  Button,
4840
4996
  {
4841
4997
  "data-ohw-media-overlay": "",
@@ -4850,7 +5006,7 @@ function MediaOverlay({
4850
5006
  e.stopPropagation();
4851
5007
  onVideoSettingsChange?.(hover.key, { muted: !muted });
4852
5008
  },
4853
- children: muted ? /* @__PURE__ */ jsx11(VolumeX, { size: 14 }) : /* @__PURE__ */ jsx11(Volume2, { size: 14 })
5009
+ children: muted ? /* @__PURE__ */ jsx12(VolumeX, { size: 14 }) : /* @__PURE__ */ jsx12(Volume2, { size: 14 })
4854
5010
  }
4855
5011
  )
4856
5012
  ]
@@ -4858,7 +5014,7 @@ function MediaOverlay({
4858
5014
  ) : null;
4859
5015
  return /* @__PURE__ */ jsxs5(Fragment2, { children: [
4860
5016
  settingsBar,
4861
- /* @__PURE__ */ jsx11(
5017
+ /* @__PURE__ */ jsx12(
4862
5018
  "div",
4863
5019
  {
4864
5020
  "data-ohw-bridge": "",
@@ -4882,14 +5038,18 @@ function MediaOverlay({
4882
5038
  variant: "outline",
4883
5039
  size: "sm",
4884
5040
  className: "gap-1.5 cursor-pointer hover:bg-background",
4885
- style: OVERLAY_BUTTON_STYLE,
5041
+ style: {
5042
+ ...OVERLAY_BUTTON_STYLE,
5043
+ // Don't let Replace steal clicks when text (e.g. nav) sits on top of this media.
5044
+ pointerEvents: hover.hasTextOverlap ? "none" : "auto"
5045
+ },
4886
5046
  onMouseDown: (e) => e.preventDefault(),
4887
5047
  onClick: (e) => {
4888
5048
  e.stopPropagation();
4889
5049
  onReplace(hover.key);
4890
5050
  },
4891
5051
  children: [
4892
- isVideo ? /* @__PURE__ */ jsx11(Film, { size: 14 }) : /* @__PURE__ */ jsx11(ImageIcon, { size: 14 }),
5052
+ isVideo ? /* @__PURE__ */ jsx12(Film, { size: 14 }) : /* @__PURE__ */ jsx12(ImageIcon, { size: 14 }),
4893
5053
  isVideo ? "Replace video" : "Replace image"
4894
5054
  ]
4895
5055
  }
@@ -4901,7 +5061,7 @@ function MediaOverlay({
4901
5061
 
4902
5062
  // src/ui/CarouselOverlay.tsx
4903
5063
  import { GalleryHorizontal } from "lucide-react";
4904
- import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
5064
+ import { jsx as jsx13, jsxs as jsxs6 } from "react/jsx-runtime";
4905
5065
  var OVERLAY_BUTTON_STYLE2 = {
4906
5066
  pointerEvents: "auto",
4907
5067
  fontFamily: "Inter, sans-serif",
@@ -4913,7 +5073,7 @@ function CarouselOverlay({
4913
5073
  onEdit
4914
5074
  }) {
4915
5075
  const { rect } = hover;
4916
- return /* @__PURE__ */ jsx12(
5076
+ return /* @__PURE__ */ jsx13(
4917
5077
  "div",
4918
5078
  {
4919
5079
  "data-ohw-bridge": "",
@@ -4945,7 +5105,7 @@ function CarouselOverlay({
4945
5105
  onEdit(hover.key);
4946
5106
  },
4947
5107
  children: [
4948
- /* @__PURE__ */ jsx12(GalleryHorizontal, { size: 14 }),
5108
+ /* @__PURE__ */ jsx13(GalleryHorizontal, { size: 14 }),
4949
5109
  "Edit gallery"
4950
5110
  ]
4951
5111
  }
@@ -5240,22 +5400,22 @@ import { useEffect as useEffect6 } from "react";
5240
5400
  import * as React8 from "react";
5241
5401
  import { Dialog as DialogPrimitive } from "radix-ui";
5242
5402
  import { X } from "lucide-react";
5243
- import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
5403
+ import { jsx as jsx14, jsxs as jsxs7 } from "react/jsx-runtime";
5244
5404
  function Dialog2({
5245
5405
  ...props
5246
5406
  }) {
5247
- return /* @__PURE__ */ jsx13(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
5407
+ return /* @__PURE__ */ jsx14(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
5248
5408
  }
5249
5409
  function DialogPortal({
5250
5410
  ...props
5251
5411
  }) {
5252
- return /* @__PURE__ */ jsx13(DialogPrimitive.Portal, { ...props });
5412
+ return /* @__PURE__ */ jsx14(DialogPrimitive.Portal, { ...props });
5253
5413
  }
5254
5414
  function DialogOverlay({
5255
5415
  className,
5256
5416
  ...props
5257
5417
  }) {
5258
- return /* @__PURE__ */ jsx13(
5418
+ return /* @__PURE__ */ jsx14(
5259
5419
  DialogPrimitive.Overlay,
5260
5420
  {
5261
5421
  "data-slot": "dialog-overlay",
@@ -5269,7 +5429,7 @@ var DialogContent = React8.forwardRef(
5269
5429
  ({ className, children, showCloseButton = true, container, ...props }, ref) => {
5270
5430
  const positionMode = container ? "absolute" : "fixed";
5271
5431
  return /* @__PURE__ */ jsxs7(DialogPortal, { container: container ?? void 0, children: [
5272
- /* @__PURE__ */ jsx13(DialogOverlay, { className: cn(positionMode, "inset-0") }),
5432
+ /* @__PURE__ */ jsx14(DialogOverlay, { className: cn(positionMode, "inset-0") }),
5273
5433
  /* @__PURE__ */ jsxs7(
5274
5434
  DialogPrimitive.Content,
5275
5435
  {
@@ -5286,13 +5446,13 @@ var DialogContent = React8.forwardRef(
5286
5446
  ...props,
5287
5447
  children: [
5288
5448
  children,
5289
- showCloseButton ? /* @__PURE__ */ jsx13(
5449
+ showCloseButton ? /* @__PURE__ */ jsx14(
5290
5450
  DialogPrimitive.Close,
5291
5451
  {
5292
5452
  type: "button",
5293
5453
  className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
5294
5454
  "aria-label": "Close",
5295
- children: /* @__PURE__ */ jsx13(X, { size: 16, "aria-hidden": true })
5455
+ children: /* @__PURE__ */ jsx14(X, { size: 16, "aria-hidden": true })
5296
5456
  }
5297
5457
  ) : null
5298
5458
  ]
@@ -5306,13 +5466,13 @@ function DialogHeader({
5306
5466
  className,
5307
5467
  ...props
5308
5468
  }) {
5309
- return /* @__PURE__ */ jsx13("div", { className: cn("flex flex-col gap-1.5", className), ...props });
5469
+ return /* @__PURE__ */ jsx14("div", { className: cn("flex flex-col gap-1.5", className), ...props });
5310
5470
  }
5311
5471
  function DialogFooter({
5312
5472
  className,
5313
5473
  ...props
5314
5474
  }) {
5315
- return /* @__PURE__ */ jsx13(
5475
+ return /* @__PURE__ */ jsx14(
5316
5476
  "div",
5317
5477
  {
5318
5478
  className: cn("flex items-center justify-end gap-2", className),
@@ -5320,7 +5480,7 @@ function DialogFooter({
5320
5480
  }
5321
5481
  );
5322
5482
  }
5323
- var DialogTitle = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx13(
5483
+ var DialogTitle = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx14(
5324
5484
  DialogPrimitive.Title,
5325
5485
  {
5326
5486
  ref,
@@ -5332,7 +5492,7 @@ var DialogTitle = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE
5332
5492
  }
5333
5493
  ));
5334
5494
  DialogTitle.displayName = DialogPrimitive.Title.displayName;
5335
- var DialogDescription = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx13(
5495
+ var DialogDescription = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx14(
5336
5496
  DialogPrimitive.Description,
5337
5497
  {
5338
5498
  ref,
@@ -5348,19 +5508,19 @@ import { Info, X as X3 } from "lucide-react";
5348
5508
 
5349
5509
  // src/ui/link-modal/DestinationBreadcrumb.tsx
5350
5510
  import { ArrowRight, File, GalleryVertical } from "lucide-react";
5351
- import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
5511
+ import { jsx as jsx15, jsxs as jsxs8 } from "react/jsx-runtime";
5352
5512
  function DestinationBreadcrumb({
5353
5513
  pageTitle,
5354
5514
  sectionLabel
5355
5515
  }) {
5356
5516
  return /* @__PURE__ */ jsxs8("div", { className: "flex w-full flex-col gap-2", children: [
5357
- /* @__PURE__ */ jsx14("p", { className: "text-sm font-medium! text-foreground m-0", children: "Destination" }),
5517
+ /* @__PURE__ */ jsx15("p", { className: "text-sm font-medium! text-foreground m-0", children: "Destination" }),
5358
5518
  /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-3", children: [
5359
5519
  /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
5360
- /* @__PURE__ */ jsx14(File, { size: 16, className: "shrink-0 text-foreground", "aria-hidden": true }),
5361
- /* @__PURE__ */ jsx14("span", { className: "text-sm font-medium leading-none text-foreground!", children: pageTitle })
5520
+ /* @__PURE__ */ jsx15(File, { size: 16, className: "shrink-0 text-foreground", "aria-hidden": true }),
5521
+ /* @__PURE__ */ jsx15("span", { className: "text-sm font-medium leading-none text-foreground!", children: pageTitle })
5362
5522
  ] }),
5363
- /* @__PURE__ */ jsx14(
5523
+ /* @__PURE__ */ jsx15(
5364
5524
  ArrowRight,
5365
5525
  {
5366
5526
  size: 16,
@@ -5369,7 +5529,7 @@ function DestinationBreadcrumb({
5369
5529
  }
5370
5530
  ),
5371
5531
  /* @__PURE__ */ jsxs8("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
5372
- /* @__PURE__ */ jsx14(
5532
+ /* @__PURE__ */ jsx15(
5373
5533
  GalleryVertical,
5374
5534
  {
5375
5535
  size: 16,
@@ -5377,7 +5537,7 @@ function DestinationBreadcrumb({
5377
5537
  "aria-hidden": true
5378
5538
  }
5379
5539
  ),
5380
- /* @__PURE__ */ jsx14("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
5540
+ /* @__PURE__ */ jsx15("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
5381
5541
  ] })
5382
5542
  ] })
5383
5543
  ] });
@@ -5385,7 +5545,7 @@ function DestinationBreadcrumb({
5385
5545
 
5386
5546
  // src/ui/link-modal/SectionTreeItem.tsx
5387
5547
  import { GalleryVertical as GalleryVertical2 } from "lucide-react";
5388
- import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
5548
+ import { jsx as jsx16, jsxs as jsxs9 } from "react/jsx-runtime";
5389
5549
  function SectionTreeItem({
5390
5550
  section,
5391
5551
  onSelect,
@@ -5393,7 +5553,7 @@ function SectionTreeItem({
5393
5553
  }) {
5394
5554
  const interactive = Boolean(onSelect);
5395
5555
  return /* @__PURE__ */ jsxs9("div", { className: "flex h-9 w-full items-end pl-3", children: [
5396
- /* @__PURE__ */ jsx15(
5556
+ /* @__PURE__ */ jsx16(
5397
5557
  "div",
5398
5558
  {
5399
5559
  className: "mr-[-1px] h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
@@ -5418,7 +5578,7 @@ function SectionTreeItem({
5418
5578
  interactive && selected && "border-primary"
5419
5579
  ),
5420
5580
  children: [
5421
- /* @__PURE__ */ jsx15(
5581
+ /* @__PURE__ */ jsx16(
5422
5582
  GalleryVertical2,
5423
5583
  {
5424
5584
  size: 16,
@@ -5426,7 +5586,7 @@ function SectionTreeItem({
5426
5586
  "aria-hidden": true
5427
5587
  }
5428
5588
  ),
5429
- /* @__PURE__ */ jsx15("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
5589
+ /* @__PURE__ */ jsx16("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
5430
5590
  ]
5431
5591
  }
5432
5592
  )
@@ -5434,14 +5594,14 @@ function SectionTreeItem({
5434
5594
  }
5435
5595
 
5436
5596
  // src/ui/link-modal/UrlOrPageInput.tsx
5437
- import { useEffect as useEffect3, useId as useId2, useRef as useRef4, useState as useState3 } from "react";
5597
+ import { useEffect as useEffect3, useId as useId2, useRef as useRef4, useState as useState4 } from "react";
5438
5598
 
5439
5599
  // src/ui/input.tsx
5440
5600
  import * as React9 from "react";
5441
- import { jsx as jsx16 } from "react/jsx-runtime";
5601
+ import { jsx as jsx17 } from "react/jsx-runtime";
5442
5602
  var Input = React9.forwardRef(
5443
5603
  ({ className, type, ...props }, ref) => {
5444
- return /* @__PURE__ */ jsx16(
5604
+ return /* @__PURE__ */ jsx17(
5445
5605
  "input",
5446
5606
  {
5447
5607
  type,
@@ -5460,9 +5620,9 @@ Input.displayName = "Input";
5460
5620
 
5461
5621
  // src/ui/label.tsx
5462
5622
  import { Label as LabelPrimitive } from "radix-ui";
5463
- import { jsx as jsx17 } from "react/jsx-runtime";
5623
+ import { jsx as jsx18 } from "react/jsx-runtime";
5464
5624
  function Label({ className, ...props }) {
5465
- return /* @__PURE__ */ jsx17(
5625
+ return /* @__PURE__ */ jsx18(
5466
5626
  LabelPrimitive.Root,
5467
5627
  {
5468
5628
  "data-slot": "label",
@@ -5474,11 +5634,11 @@ function Label({ className, ...props }) {
5474
5634
 
5475
5635
  // src/ui/link-modal/UrlOrPageInput.tsx
5476
5636
  import { ChevronDown, File as File2, X as X2 } from "lucide-react";
5477
- import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
5637
+ import { jsx as jsx19, jsxs as jsxs10 } from "react/jsx-runtime";
5478
5638
  function FieldChevron({
5479
5639
  onClick
5480
5640
  }) {
5481
- return /* @__PURE__ */ jsx18(
5641
+ return /* @__PURE__ */ jsx19(
5482
5642
  "button",
5483
5643
  {
5484
5644
  type: "button",
@@ -5486,7 +5646,7 @@ function FieldChevron({
5486
5646
  onClick,
5487
5647
  "aria-label": "Open page list",
5488
5648
  tabIndex: -1,
5489
- children: /* @__PURE__ */ jsx18(ChevronDown, { size: 16 })
5649
+ children: /* @__PURE__ */ jsx19(ChevronDown, { size: 16 })
5490
5650
  }
5491
5651
  );
5492
5652
  }
@@ -5505,7 +5665,7 @@ function UrlOrPageInput({
5505
5665
  const inputId = useId2();
5506
5666
  const inputRef = useRef4(null);
5507
5667
  const rootRef = useRef4(null);
5508
- const [isFocused, setIsFocused] = useState3(false);
5668
+ const [isFocused, setIsFocused] = useState4(false);
5509
5669
  useEffect3(() => {
5510
5670
  if (!dropdownOpen) return;
5511
5671
  const isOutside = (e) => {
@@ -5548,10 +5708,10 @@ function UrlOrPageInput({
5548
5708
  urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
5549
5709
  );
5550
5710
  return /* @__PURE__ */ jsxs10("div", { className: "flex w-full flex-col gap-2 p-0", children: [
5551
- /* @__PURE__ */ jsx18(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
5711
+ /* @__PURE__ */ jsx19(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
5552
5712
  /* @__PURE__ */ jsxs10("div", { ref: rootRef, className: "relative w-full", children: [
5553
5713
  /* @__PURE__ */ jsxs10("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
5554
- selectedPage ? /* @__PURE__ */ jsx18("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ jsx18(
5714
+ selectedPage ? /* @__PURE__ */ jsx19("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ jsx19(
5555
5715
  File2,
5556
5716
  {
5557
5717
  size: 16,
@@ -5559,7 +5719,7 @@ function UrlOrPageInput({
5559
5719
  "aria-hidden": true
5560
5720
  }
5561
5721
  ) }) : null,
5562
- readOnly ? /* @__PURE__ */ jsx18("span", { className: "min-w-0 flex-1 truncate text-sm leading-5 text-foreground", children: selectedPage?.title ?? value }) : /* @__PURE__ */ jsx18(
5722
+ readOnly ? /* @__PURE__ */ jsx19("span", { className: "min-w-0 flex-1 truncate text-sm leading-5 text-foreground", children: selectedPage?.title ?? value }) : /* @__PURE__ */ jsx19(
5563
5723
  Input,
5564
5724
  {
5565
5725
  ref: inputRef,
@@ -5585,7 +5745,7 @@ function UrlOrPageInput({
5585
5745
  )
5586
5746
  }
5587
5747
  ),
5588
- selectedPage && !readOnly ? /* @__PURE__ */ jsx18(
5748
+ selectedPage && !readOnly ? /* @__PURE__ */ jsx19(
5589
5749
  "button",
5590
5750
  {
5591
5751
  type: "button",
@@ -5593,12 +5753,12 @@ function UrlOrPageInput({
5593
5753
  onMouseDown: clearSelection,
5594
5754
  "aria-label": "Clear selected page",
5595
5755
  tabIndex: -1,
5596
- children: /* @__PURE__ */ jsx18(X2, { size: 16, "aria-hidden": true })
5756
+ children: /* @__PURE__ */ jsx19(X2, { size: 16, "aria-hidden": true })
5597
5757
  }
5598
5758
  ) : null,
5599
- !readOnly ? /* @__PURE__ */ jsx18(FieldChevron, { onClick: toggleDropdown }) : null
5759
+ !readOnly ? /* @__PURE__ */ jsx19(FieldChevron, { onClick: toggleDropdown }) : null
5600
5760
  ] }),
5601
- dropdownOpen && !readOnly && filteredPages.length > 0 ? /* @__PURE__ */ jsx18(
5761
+ dropdownOpen && !readOnly && filteredPages.length > 0 ? /* @__PURE__ */ jsx19(
5602
5762
  "div",
5603
5763
  {
5604
5764
  "data-ohw-link-page-dropdown": "",
@@ -5611,8 +5771,8 @@ function UrlOrPageInput({
5611
5771
  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",
5612
5772
  onClick: () => onPageSelect(page),
5613
5773
  children: [
5614
- /* @__PURE__ */ jsx18(File2, { size: 16, className: "shrink-0", "aria-hidden": true }),
5615
- /* @__PURE__ */ jsx18("span", { className: "truncate", children: page.title })
5774
+ /* @__PURE__ */ jsx19(File2, { size: 16, className: "shrink-0", "aria-hidden": true }),
5775
+ /* @__PURE__ */ jsx19("span", { className: "truncate", children: page.title })
5616
5776
  ]
5617
5777
  },
5618
5778
  page.path
@@ -5620,34 +5780,34 @@ function UrlOrPageInput({
5620
5780
  }
5621
5781
  ) : null
5622
5782
  ] }),
5623
- urlError ? /* @__PURE__ */ jsx18("p", { className: "text-sm font-medium text-destructive", children: urlError }) : null
5783
+ urlError ? /* @__PURE__ */ jsx19("p", { className: "text-sm font-medium text-destructive", children: urlError }) : null
5624
5784
  ] });
5625
5785
  }
5626
5786
 
5627
5787
  // src/ui/link-modal/LinkEditorPanel.tsx
5628
- import { Fragment as Fragment3, jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
5788
+ import { Fragment as Fragment3, jsx as jsx20, jsxs as jsxs11 } from "react/jsx-runtime";
5629
5789
  function LinkEditorPanel({ state, onClose }) {
5630
5790
  const isCancel = state.secondaryLabel === "Cancel" || state.secondaryLabel === "Back to sections";
5631
5791
  return /* @__PURE__ */ jsxs11(Fragment3, { children: [
5632
- /* @__PURE__ */ jsx19(DialogClose, { asChild: true, children: /* @__PURE__ */ jsx19(
5792
+ /* @__PURE__ */ jsx20(DialogClose, { asChild: true, children: /* @__PURE__ */ jsx20(
5633
5793
  "button",
5634
5794
  {
5635
5795
  type: "button",
5636
5796
  className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50 h-7",
5637
5797
  "aria-label": "Close",
5638
5798
  onClick: onClose,
5639
- children: /* @__PURE__ */ jsx19(X3, { size: 16, "aria-hidden": true })
5799
+ children: /* @__PURE__ */ jsx20(X3, { size: 16, "aria-hidden": true })
5640
5800
  }
5641
5801
  ) }),
5642
- /* @__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 }) }),
5802
+ /* @__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 }) }),
5643
5803
  /* @__PURE__ */ jsxs11("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
5644
- state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ jsx19(
5804
+ state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ jsx20(
5645
5805
  DestinationBreadcrumb,
5646
5806
  {
5647
5807
  pageTitle: state.selectedPage.title,
5648
5808
  sectionLabel: state.selectedSection.label
5649
5809
  }
5650
- ) : /* @__PURE__ */ jsx19(
5810
+ ) : /* @__PURE__ */ jsx20(
5651
5811
  UrlOrPageInput,
5652
5812
  {
5653
5813
  value: state.searchValue,
@@ -5661,7 +5821,7 @@ function LinkEditorPanel({ state, onClose }) {
5661
5821
  }
5662
5822
  ),
5663
5823
  state.showChooseSection ? /* @__PURE__ */ jsxs11("div", { className: "flex flex-col justify-center gap-2", children: [
5664
- /* @__PURE__ */ jsx19(
5824
+ /* @__PURE__ */ jsx20(
5665
5825
  Button,
5666
5826
  {
5667
5827
  type: "button",
@@ -5673,14 +5833,14 @@ function LinkEditorPanel({ state, onClose }) {
5673
5833
  }
5674
5834
  ),
5675
5835
  /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
5676
- /* @__PURE__ */ jsx19(Info, { size: 16, className: "shrink-0", "aria-hidden": true }),
5677
- /* @__PURE__ */ jsx19("span", { children: "Pick a section this link should scroll to." })
5836
+ /* @__PURE__ */ jsx20(Info, { size: 16, className: "shrink-0", "aria-hidden": true }),
5837
+ /* @__PURE__ */ jsx20("span", { children: "Pick a section this link should scroll to." })
5678
5838
  ] })
5679
5839
  ] }) : null,
5680
- state.showSectionRow && state.selectedSection ? /* @__PURE__ */ jsx19(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
5840
+ state.showSectionRow && state.selectedSection ? /* @__PURE__ */ jsx20(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
5681
5841
  ] }),
5682
5842
  /* @__PURE__ */ jsxs11(DialogFooter, { className: "w-full px-6 pb-6", children: [
5683
- /* @__PURE__ */ jsx19(
5843
+ /* @__PURE__ */ jsx20(
5684
5844
  Button,
5685
5845
  {
5686
5846
  type: "button",
@@ -5695,7 +5855,7 @@ function LinkEditorPanel({ state, onClose }) {
5695
5855
  children: state.secondaryLabel
5696
5856
  }
5697
5857
  ),
5698
- /* @__PURE__ */ jsx19(
5858
+ /* @__PURE__ */ jsx20(
5699
5859
  Button,
5700
5860
  {
5701
5861
  type: "button",
@@ -5714,11 +5874,11 @@ function LinkEditorPanel({ state, onClose }) {
5714
5874
  }
5715
5875
 
5716
5876
  // src/ui/link-modal/SectionPickerOverlay.tsx
5717
- import { useCallback as useCallback2, useEffect as useEffect4, useMemo as useMemo2, useRef as useRef5, useState as useState4 } from "react";
5877
+ import { useCallback as useCallback2, useEffect as useEffect4, useMemo as useMemo2, useRef as useRef5, useState as useState5 } from "react";
5718
5878
  import { createPortal } from "react-dom";
5719
5879
  import { ArrowLeft, Check } from "lucide-react";
5720
5880
  import { usePathname, useRouter } from "next/navigation";
5721
- import { jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
5881
+ import { jsx as jsx21, jsxs as jsxs12 } from "react/jsx-runtime";
5722
5882
  var DIM_OVERLAY = "rgba(0, 0, 0, 0.45)";
5723
5883
  function rectsEqual(a, b) {
5724
5884
  if (a.size !== b.size) return false;
@@ -5751,7 +5911,7 @@ function hitTestSectionId(x, y, sectionIds, rects) {
5751
5911
  return null;
5752
5912
  }
5753
5913
  function useSectionRects(sectionIdsKey, enabled) {
5754
- const [rects, setRects] = useState4(/* @__PURE__ */ new Map());
5914
+ const [rects, setRects] = useState5(/* @__PURE__ */ new Map());
5755
5915
  const sectionIds = useMemo2(
5756
5916
  () => sectionIdsKey ? sectionIdsKey.split("\0") : [],
5757
5917
  [sectionIdsKey]
@@ -5797,13 +5957,13 @@ function SectionPickerOverlay({
5797
5957
  }) {
5798
5958
  const router = useRouter();
5799
5959
  const pathname = usePathname();
5800
- const [selectedId, setSelectedId] = useState4(null);
5801
- const [hoveredId, setHoveredId] = useState4(null);
5960
+ const [selectedId, setSelectedId] = useState5(null);
5961
+ const [hoveredId, setHoveredId] = useState5(null);
5802
5962
  const pointerRef = useRef5(null);
5803
5963
  const pointerScreenRef = useRef5(null);
5804
5964
  const iframeOffsetTopRef = useRef5(null);
5805
5965
  const sectionIdsRef = useRef5([]);
5806
- const [chromeClip, setChromeClip] = useState4(
5966
+ const [chromeClip, setChromeClip] = useState5(
5807
5967
  () => ({
5808
5968
  top: 0,
5809
5969
  bottom: typeof window !== "undefined" ? window.innerHeight : 0
@@ -5957,7 +6117,7 @@ function SectionPickerOverlay({
5957
6117
  role: "dialog",
5958
6118
  "aria-label": "Choose a section",
5959
6119
  children: [
5960
- /* @__PURE__ */ jsx20(
6120
+ /* @__PURE__ */ jsx21(
5961
6121
  "div",
5962
6122
  {
5963
6123
  className: "pointer-events-auto fixed left-5 z-[2]",
@@ -5971,14 +6131,14 @@ function SectionPickerOverlay({
5971
6131
  className: "h-8 min-w-0 gap-1 border-border bg-background px-2 py-1.5 shadow-sm hover:bg-muted cursor-pointer",
5972
6132
  onClick: onBack,
5973
6133
  children: [
5974
- /* @__PURE__ */ jsx20(ArrowLeft, { className: "size-4 shrink-0", "aria-hidden": true }),
6134
+ /* @__PURE__ */ jsx21(ArrowLeft, { className: "size-4 shrink-0", "aria-hidden": true }),
5975
6135
  "Back"
5976
6136
  ]
5977
6137
  }
5978
6138
  )
5979
6139
  }
5980
6140
  ),
5981
- /* @__PURE__ */ jsx20(
6141
+ /* @__PURE__ */ jsx21(
5982
6142
  "div",
5983
6143
  {
5984
6144
  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",
@@ -5991,7 +6151,7 @@ function SectionPickerOverlay({
5991
6151
  children: "Click on section to select"
5992
6152
  }
5993
6153
  ),
5994
- !isOnTargetPage ? /* @__PURE__ */ jsx20(
6154
+ !isOnTargetPage ? /* @__PURE__ */ jsx21(
5995
6155
  "div",
5996
6156
  {
5997
6157
  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",
@@ -5999,7 +6159,7 @@ function SectionPickerOverlay({
5999
6159
  children: "Loading page preview\u2026"
6000
6160
  }
6001
6161
  ) : null,
6002
- 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,
6162
+ 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,
6003
6163
  isOnTargetPage ? liveSections.map((section) => {
6004
6164
  const rect = rects.get(section.id);
6005
6165
  if (!rect || rect.width <= 0 || rect.height <= 0) return null;
@@ -6021,7 +6181,7 @@ function SectionPickerOverlay({
6021
6181
  "aria-label": `Select section ${section.label}`,
6022
6182
  onClick: () => handleSelect(section),
6023
6183
  children: [
6024
- isLit ? /* @__PURE__ */ jsx20(
6184
+ isLit ? /* @__PURE__ */ jsx21(
6025
6185
  "span",
6026
6186
  {
6027
6187
  className: "pointer-events-none absolute",
@@ -6034,13 +6194,13 @@ function SectionPickerOverlay({
6034
6194
  "aria-hidden": true
6035
6195
  }
6036
6196
  ) : null,
6037
- isSelected ? /* @__PURE__ */ jsx20(
6197
+ isSelected ? /* @__PURE__ */ jsx21(
6038
6198
  "span",
6039
6199
  {
6040
6200
  className: "absolute right-3 top-3 flex size-8 items-center justify-center rounded-full text-white",
6041
6201
  style: { backgroundColor: "var(--ohw-primary, #0885fe)" },
6042
6202
  "aria-hidden": true,
6043
- children: /* @__PURE__ */ jsx20(Check, { className: "size-5" })
6203
+ children: /* @__PURE__ */ jsx21(Check, { className: "size-5" })
6044
6204
  }
6045
6205
  ) : null
6046
6206
  ]
@@ -6056,7 +6216,7 @@ function SectionPickerOverlay({
6056
6216
  }
6057
6217
 
6058
6218
  // src/ui/link-modal/useLinkModalState.ts
6059
- import { useCallback as useCallback3, useEffect as useEffect5, useMemo as useMemo3, useState as useState5 } from "react";
6219
+ import { useCallback as useCallback3, useEffect as useEffect5, useMemo as useMemo3, useState as useState6 } from "react";
6060
6220
  function useLinkModalState({
6061
6221
  open,
6062
6222
  mode,
@@ -6069,12 +6229,12 @@ function useLinkModalState({
6069
6229
  onSubmit
6070
6230
  }) {
6071
6231
  const availablePages = useMemo3(() => pages, [pages]);
6072
- const [searchValue, setSearchValue] = useState5("");
6073
- const [selectedPage, setSelectedPage] = useState5(null);
6074
- const [selectedSection, setSelectedSection] = useState5(null);
6075
- const [step, setStep] = useState5("input");
6076
- const [dropdownOpen, setDropdownOpen] = useState5(false);
6077
- const [urlError, setUrlError] = useState5("");
6232
+ const [searchValue, setSearchValue] = useState6("");
6233
+ const [selectedPage, setSelectedPage] = useState6(null);
6234
+ const [selectedSection, setSelectedSection] = useState6(null);
6235
+ const [step, setStep] = useState6("input");
6236
+ const [dropdownOpen, setDropdownOpen] = useState6(false);
6237
+ const [urlError, setUrlError] = useState6("");
6078
6238
  const reset = useCallback3(() => {
6079
6239
  setSearchValue("");
6080
6240
  setSelectedPage(null);
@@ -6220,7 +6380,7 @@ function useLinkModalState({
6220
6380
  }
6221
6381
 
6222
6382
  // src/ui/link-modal/LinkPopover.tsx
6223
- import { Fragment as Fragment4, jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
6383
+ import { Fragment as Fragment4, jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
6224
6384
  function postToParent(data) {
6225
6385
  window.parent?.postMessage(data, "*");
6226
6386
  }
@@ -6317,14 +6477,14 @@ function LinkPopover({
6317
6477
  };
6318
6478
  }, [open, sectionPickerActive]);
6319
6479
  return /* @__PURE__ */ jsxs13(Fragment4, { children: [
6320
- /* @__PURE__ */ jsx21(
6480
+ /* @__PURE__ */ jsx22(
6321
6481
  Dialog2,
6322
6482
  {
6323
6483
  open: open && !sectionPickerActive,
6324
6484
  onOpenChange: (next) => {
6325
6485
  if (!next) onClose?.();
6326
6486
  },
6327
- children: /* @__PURE__ */ jsx21(
6487
+ children: /* @__PURE__ */ jsx22(
6328
6488
  DialogContent,
6329
6489
  {
6330
6490
  ref: panelRef,
@@ -6334,12 +6494,12 @@ function LinkPopover({
6334
6494
  "data-ohw-bridge": "",
6335
6495
  showCloseButton: false,
6336
6496
  className: "gap-0 p-0 w-full max-w-[448px] pointer-events-auto z-[2147483646] overflow-visible",
6337
- children: /* @__PURE__ */ jsx21(LinkEditorPanel, { state, onClose })
6497
+ children: /* @__PURE__ */ jsx22(LinkEditorPanel, { state, onClose })
6338
6498
  }
6339
6499
  )
6340
6500
  }
6341
6501
  ),
6342
- sectionPickerActive && state.selectedPage ? /* @__PURE__ */ jsx21(
6502
+ sectionPickerActive && state.selectedPage ? /* @__PURE__ */ jsx22(
6343
6503
  SectionPickerOverlay,
6344
6504
  {
6345
6505
  pagePath: state.selectedPage.path,
@@ -6828,6 +6988,22 @@ function navbarIndexExistsInDom(index) {
6828
6988
  return document.querySelector(`[data-ohw-href-key="nav-${index}-href"]`) !== null;
6829
6989
  }
6830
6990
  function reconcileNavbarItemsFromContent(content) {
6991
+ const orderForest = parseNavOrderJson(content[NAV_ORDER_KEY]);
6992
+ if (orderForest?.length) {
6993
+ const allowed = new Set(flattenNavOrder(orderForest));
6994
+ for (const hrefKey of allowed) {
6995
+ const index = parseNavIndexFromKey(hrefKey);
6996
+ if (index === null) continue;
6997
+ if (navbarIndexExistsInDom(index)) continue;
6998
+ const href = content[`nav-${index}-href`];
6999
+ const label = content[`nav-${index}-label`];
7000
+ if (!href && !label) continue;
7001
+ insertNavbarItemDom(index, href ?? "/", label ?? "Untitled", null);
7002
+ }
7003
+ pruneNavbarItemsNotInOrder(allowed);
7004
+ applyNavForest(orderForest);
7005
+ return;
7006
+ }
6831
7007
  const indices = collectNavbarIndicesFromContent(content);
6832
7008
  for (const index of indices) {
6833
7009
  if (navbarIndexExistsInDom(index)) continue;
@@ -6836,9 +7012,22 @@ function reconcileNavbarItemsFromContent(content) {
6836
7012
  if (!href && !label) continue;
6837
7013
  insertNavbarItemDom(index, href ?? "/", label ?? "Untitled", null);
6838
7014
  }
6839
- const orderForest = parseNavOrderJson(content[NAV_ORDER_KEY]);
6840
- if (orderForest?.length) {
6841
- applyNavForest(orderForest);
7015
+ }
7016
+ function pruneNavbarItemsNotInOrder(allowed) {
7017
+ const roots = [getNavbarDesktopContainer(), getNavbarDrawerContainer()].filter(
7018
+ (el) => Boolean(el)
7019
+ );
7020
+ const searchRoots = roots.length > 0 ? roots : [document.body];
7021
+ for (const root of searchRoots) {
7022
+ const items = Array.from(root.querySelectorAll("[data-ohw-href-key]")).filter(
7023
+ isNavbarLinkItem
7024
+ );
7025
+ for (const item of items) {
7026
+ if (!item.isConnected) continue;
7027
+ const key = item.getAttribute("data-ohw-href-key");
7028
+ if (!key || !isNavbarHrefKey(key) || allowed.has(key)) continue;
7029
+ resolveRemovableNavUnit(item).remove();
7030
+ }
6842
7031
  }
6843
7032
  }
6844
7033
  function buildNavOrderAfterInsert(afterAnchor, newHrefKey) {
@@ -6878,9 +7067,126 @@ function insertNavbarItem(href, label, afterAnchor = null) {
6878
7067
  order
6879
7068
  };
6880
7069
  }
7070
+ function duplicateNavbarItem(sourceAnchor) {
7071
+ if (!isNavbarLinkItem(sourceAnchor)) return null;
7072
+ const sourceHrefKey = sourceAnchor.getAttribute("data-ohw-href-key");
7073
+ if (!sourceHrefKey || !isNavbarHrefKey(sourceHrefKey)) return null;
7074
+ const href = getLinkHref(sourceAnchor);
7075
+ const labelEl = sourceAnchor.querySelector('[data-ohw-editable="text"]');
7076
+ const label = (labelEl?.textContent ?? "").trim() || "Untitled";
7077
+ const forest = getNavForestFromDom();
7078
+ const sourceNode = forest.find((n) => n.id === sourceHrefKey);
7079
+ const childIds = sourceNode?.children.map((c) => c.id) ?? [];
7080
+ const primary = insertNavbarItem(href, label, sourceAnchor);
7081
+ const childResults = [];
7082
+ let after = primary.anchor;
7083
+ for (const childId of childIds) {
7084
+ const childEl = findCounterpartByHrefKey(childId, document) ?? document.querySelector(`[data-ohw-href-key="${CSS.escape(childId)}"]`);
7085
+ if (!childEl || !isNavbarLinkItem(childEl)) continue;
7086
+ const childHref = getLinkHref(childEl);
7087
+ const childLabelEl = childEl.querySelector('[data-ohw-editable="text"]');
7088
+ const childLabel = (childLabelEl?.textContent ?? "").trim() || "Untitled";
7089
+ const inserted = insertNavbarItem(childHref, childLabel, after);
7090
+ childResults.push(inserted);
7091
+ after = inserted.anchor;
7092
+ }
7093
+ let orderJson;
7094
+ if (childResults.length > 0) {
7095
+ const nextForest = getNavForestFromDom();
7096
+ const withoutNew = nextForest.filter(
7097
+ (n) => n.id !== primary.hrefKey && !childResults.some((c) => c.hrefKey === n.id)
7098
+ );
7099
+ const sourceIdx = withoutNew.findIndex((n) => n.id === sourceHrefKey);
7100
+ const insertAt = sourceIdx >= 0 ? sourceIdx + 1 : withoutNew.length;
7101
+ withoutNew.splice(insertAt, 0, {
7102
+ id: primary.hrefKey,
7103
+ children: childResults.map((c) => ({ id: c.hrefKey, children: [] }))
7104
+ });
7105
+ applyNavForest(withoutNew);
7106
+ orderJson = serializeNavOrder(withoutNew);
7107
+ } else {
7108
+ orderJson = serializeNavOrder(getNavForestFromDom());
7109
+ }
7110
+ return {
7111
+ ...primary,
7112
+ order: flattenNavOrder(parseNavOrderJson(orderJson) ?? getNavForestFromDom()),
7113
+ childResults,
7114
+ orderJson
7115
+ };
7116
+ }
7117
+ function collectSubtreeHrefKeys(node) {
7118
+ const keys = [node.id];
7119
+ for (const child of node.children) {
7120
+ keys.push(...collectSubtreeHrefKeys(child));
7121
+ }
7122
+ return keys;
7123
+ }
7124
+ function labelKeyFromHrefKey(hrefKey) {
7125
+ return hrefKey.replace(/-href$/, "-label");
7126
+ }
7127
+ function resolveRemovableNavUnit(anchor) {
7128
+ if (anchor.closest("[data-ohw-nav-children]")) return anchor;
7129
+ const group = anchor.closest("[data-ohw-nav-group]");
7130
+ if (group?.querySelector(":scope > [data-ohw-nav-children]")) return group;
7131
+ return anchor;
7132
+ }
7133
+ function deleteNavbarItem(sourceAnchor) {
7134
+ if (!isNavbarLinkItem(sourceAnchor)) return null;
7135
+ const sourceHrefKey = sourceAnchor.getAttribute("data-ohw-href-key");
7136
+ if (!sourceHrefKey || !isNavbarHrefKey(sourceHrefKey)) return null;
7137
+ const labelEl = sourceAnchor.querySelector('[data-ohw-editable="text"]');
7138
+ const label = (labelEl?.textContent ?? "").trim() || "Untitled";
7139
+ const previousForest = getNavForestFromDom();
7140
+ const previousOrderJson = serializeNavOrder(previousForest);
7141
+ const taken = takeNode(previousForest, sourceHrefKey);
7142
+ if (!taken) return null;
7143
+ const removedHrefKeys = collectSubtreeHrefKeys(taken.taken);
7144
+ const removedKeys = removedHrefKeys.flatMap((hrefKey) => [hrefKey, labelKeyFromHrefKey(hrefKey)]);
7145
+ const previousContent = {};
7146
+ for (const hrefKey of removedHrefKeys) {
7147
+ const el = findCounterpartByHrefKey(hrefKey, document) ?? document.querySelector(`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`);
7148
+ previousContent[hrefKey] = el ? getLinkHref(el) : "";
7149
+ const labEl = el?.querySelector('[data-ohw-editable="text"]');
7150
+ previousContent[labelKeyFromHrefKey(hrefKey)] = (labEl?.textContent ?? "").trim();
7151
+ }
7152
+ const roots = [getNavbarDesktopContainer(), getNavbarDrawerContainer()].filter(
7153
+ (el) => Boolean(el)
7154
+ );
7155
+ const searchRoots = roots.length > 0 ? roots : [document.body];
7156
+ const placements = [];
7157
+ for (const root of searchRoots) {
7158
+ const primary = findCounterpartByHrefKey(sourceHrefKey, root);
7159
+ if (!primary?.isConnected || !primary.parentElement) continue;
7160
+ const unit = resolveRemovableNavUnit(primary);
7161
+ if (!unit.parentElement) continue;
7162
+ placements.push({
7163
+ node: unit,
7164
+ parent: unit.parentElement,
7165
+ nextSibling: unit.nextSibling
7166
+ });
7167
+ unit.remove();
7168
+ }
7169
+ applyNavForest(taken.forest);
7170
+ const orderJson = serializeNavOrder(taken.forest);
7171
+ return {
7172
+ label,
7173
+ hrefKey: sourceHrefKey,
7174
+ removedKeys,
7175
+ previousContent,
7176
+ orderJson,
7177
+ previousOrderJson,
7178
+ undo: () => {
7179
+ for (const placement of placements) {
7180
+ placement.parent.insertBefore(placement.node, placement.nextSibling);
7181
+ }
7182
+ applyNavForest(previousForest);
7183
+ }
7184
+ };
7185
+ }
6881
7186
 
6882
7187
  // src/lib/footer-items.ts
6883
7188
  var FOOTER_ORDER_KEY = "__ohw_footer_order";
7189
+ var MAX_FOOTER_COLUMNS = 18;
6884
7190
  var FOOTER_HREF_RE = /^footer-(\d+)-(\d+)-href$/;
6885
7191
  function parseFooterHrefKey(key) {
6886
7192
  if (!key) return null;
@@ -7061,16 +7367,260 @@ function parseFooterOrder(content) {
7061
7367
  return null;
7062
7368
  }
7063
7369
  }
7370
+ var FOOTER_HEADING_RE = /^footer-(\d+)-heading$/;
7371
+ var FOOTER_LABEL_RE = /^footer-(\d+)-(\d+)-label$/;
7372
+ var DEFAULT_FOOTER_COLUMN_HEADING = "New";
7373
+ var DEFAULT_FOOTER_COLUMN_LINK_LABEL = "New link";
7374
+ var DEFAULT_FOOTER_COLUMN_LINK_HREF = "";
7375
+ function isFooterLinksContainer(el) {
7376
+ return el.hasAttribute("data-ohw-footer-links") || el.classList.contains("rb-footer-links");
7377
+ }
7378
+ function getFooterColumnIndicesInDom() {
7379
+ const indices = /* @__PURE__ */ new Set();
7380
+ for (const col of listFooterColumns()) {
7381
+ const attr = col.getAttribute("data-ohw-footer-col");
7382
+ if (attr != null) {
7383
+ const n = parseInt(attr, 10);
7384
+ if (Number.isFinite(n)) indices.add(n);
7385
+ }
7386
+ for (const link of listFooterLinksInColumn(col)) {
7387
+ const parsed = parseFooterHrefKey(link.getAttribute("data-ohw-href-key"));
7388
+ if (parsed) indices.add(parsed.col);
7389
+ }
7390
+ const heading = col.querySelector('[data-ohw-key^="footer-"][data-ohw-key$="-heading"]');
7391
+ const headingKey = heading?.getAttribute("data-ohw-key");
7392
+ if (headingKey) {
7393
+ const match = headingKey.match(FOOTER_HEADING_RE);
7394
+ if (match) indices.add(parseInt(match[1], 10));
7395
+ }
7396
+ }
7397
+ return [...indices].sort((a, b) => a - b);
7398
+ }
7399
+ function getNextFooterColumnIndex() {
7400
+ const indices = getFooterColumnIndicesInDom();
7401
+ if (indices.length === 0) return 0;
7402
+ return Math.max(...indices) + 1;
7403
+ }
7404
+ function canAddFooterColumn() {
7405
+ return listFooterColumns().length < MAX_FOOTER_COLUMNS;
7406
+ }
7407
+ function buildFooterHeading(colIndex, text) {
7408
+ const heading = document.createElement("p");
7409
+ heading.setAttribute("data-ohw-editable", "text");
7410
+ heading.setAttribute("data-ohw-key", `footer-${colIndex}-heading`);
7411
+ heading.textContent = text;
7412
+ heading.style.cssText = [
7413
+ "color: var(--espresso, #3d312b)",
7414
+ "font-size: 14px",
7415
+ "font-weight: 800",
7416
+ "opacity: 0.82",
7417
+ "margin: 0 0 6px",
7418
+ "padding: 0",
7419
+ "line-height: 1.2"
7420
+ ].join(";");
7421
+ return heading;
7422
+ }
7423
+ function buildFooterLink(colIndex, itemIndex, href, label, template) {
7424
+ const anchor = cloneFooterLinkShell(template);
7425
+ anchor.setAttribute("href", href);
7426
+ anchor.setAttribute("data-ohw-href-key", `footer-${colIndex}-${itemIndex}-href`);
7427
+ const span = document.createElement("span");
7428
+ span.setAttribute("data-ohw-editable", "text");
7429
+ span.setAttribute("data-ohw-key", `footer-${colIndex}-${itemIndex}-label`);
7430
+ span.textContent = label;
7431
+ anchor.appendChild(span);
7432
+ return anchor;
7433
+ }
7434
+ function footerColumnExistsInDom(colIndex) {
7435
+ 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;
7436
+ }
7437
+ function getFooterLinkTemplate() {
7438
+ for (const col of listFooterColumns()) {
7439
+ const link = listFooterLinksInColumn(col)[0];
7440
+ if (link) return link;
7441
+ }
7442
+ return null;
7443
+ }
7444
+ function getFooterColumnTemplate() {
7445
+ return listFooterColumns()[0] ?? null;
7446
+ }
7447
+ function insertFooterColumnDom(colIndex, heading, items) {
7448
+ const container = getFooterLinksContainer();
7449
+ if (!container) return null;
7450
+ const colTemplate = getFooterColumnTemplate();
7451
+ const linkTemplate = getFooterLinkTemplate();
7452
+ const column = document.createElement("div");
7453
+ if (colTemplate?.className) column.className = colTemplate.className;
7454
+ else column.className = "rb-footer-link-col";
7455
+ column.setAttribute("data-ohw-footer-col", String(colIndex));
7456
+ if (colTemplate) {
7457
+ const gap = getComputedStyle(colTemplate).gap;
7458
+ if (gap && gap !== "normal") column.style.gap = gap;
7459
+ column.style.display = getComputedStyle(colTemplate).display || "flex";
7460
+ column.style.flexDirection = "column";
7461
+ }
7462
+ column.appendChild(buildFooterHeading(colIndex, heading));
7463
+ let firstLink = null;
7464
+ items.forEach((item, itemIndex) => {
7465
+ const link = buildFooterLink(colIndex, itemIndex, item.href, item.label, linkTemplate);
7466
+ column.appendChild(link);
7467
+ if (!firstLink) firstLink = link;
7468
+ });
7469
+ container.appendChild(column);
7470
+ return { column, firstLink };
7471
+ }
7472
+ function insertFooterColumn(heading = DEFAULT_FOOTER_COLUMN_HEADING, linkLabel = DEFAULT_FOOTER_COLUMN_LINK_LABEL, linkHref = DEFAULT_FOOTER_COLUMN_LINK_HREF) {
7473
+ if (!canAddFooterColumn()) {
7474
+ throw new Error(`Footer column limit reached (${MAX_FOOTER_COLUMNS})`);
7475
+ }
7476
+ const colIndex = getNextFooterColumnIndex();
7477
+ const inserted = insertFooterColumnDom(colIndex, heading, [{ href: linkHref, label: linkLabel }]);
7478
+ if (!inserted?.firstLink) throw new Error("Failed to insert footer column");
7479
+ syncFooterColumnIndices(listFooterColumns());
7480
+ return {
7481
+ column: inserted.column,
7482
+ firstLink: inserted.firstLink,
7483
+ colIndex,
7484
+ headingKey: `footer-${colIndex}-heading`,
7485
+ hrefKey: `footer-${colIndex}-0-href`,
7486
+ labelKey: `footer-${colIndex}-0-label`,
7487
+ heading,
7488
+ label: linkLabel,
7489
+ href: linkHref,
7490
+ order: getFooterOrderFromDom()
7491
+ };
7492
+ }
7493
+ function collectFooterColumnIndicesFromContent(content) {
7494
+ const indices = /* @__PURE__ */ new Set();
7495
+ for (const key of Object.keys(content)) {
7496
+ const href = parseFooterHrefKey(key);
7497
+ if (href) indices.add(href.col);
7498
+ const heading = key.match(FOOTER_HEADING_RE);
7499
+ if (heading) indices.add(parseInt(heading[1], 10));
7500
+ const label = key.match(FOOTER_LABEL_RE);
7501
+ if (label) indices.add(parseInt(label[1], 10));
7502
+ }
7503
+ const order = parseFooterOrder(content);
7504
+ if (order) {
7505
+ for (const col of order) {
7506
+ for (const hrefKey of col) {
7507
+ const parsed = parseFooterHrefKey(hrefKey);
7508
+ if (parsed) indices.add(parsed.col);
7509
+ }
7510
+ }
7511
+ }
7512
+ return [...indices].sort((a, b) => a - b);
7513
+ }
7514
+ function collectFooterItemsForColumn(content, colIndex) {
7515
+ const itemIndices = /* @__PURE__ */ new Set();
7516
+ for (const key of Object.keys(content)) {
7517
+ const href = parseFooterHrefKey(key);
7518
+ if (href?.col === colIndex) itemIndices.add(href.item);
7519
+ const label = key.match(FOOTER_LABEL_RE);
7520
+ if (label && parseInt(label[1], 10) === colIndex) {
7521
+ itemIndices.add(parseInt(label[2], 10));
7522
+ }
7523
+ }
7524
+ const sorted = [...itemIndices].sort((a, b) => a - b);
7525
+ if (sorted.length === 0) {
7526
+ return [
7527
+ {
7528
+ href: content[`footer-${colIndex}-0-href`] ?? DEFAULT_FOOTER_COLUMN_LINK_HREF,
7529
+ label: content[`footer-${colIndex}-0-label`] ?? DEFAULT_FOOTER_COLUMN_LINK_LABEL
7530
+ }
7531
+ ];
7532
+ }
7533
+ return sorted.map((itemIndex) => ({
7534
+ href: content[`footer-${colIndex}-${itemIndex}-href`] ?? DEFAULT_FOOTER_COLUMN_LINK_HREF,
7535
+ label: content[`footer-${colIndex}-${itemIndex}-label`] ?? DEFAULT_FOOTER_COLUMN_LINK_LABEL
7536
+ }));
7537
+ }
7538
+ function reconcileFooterColumnsFromContent(content) {
7539
+ const order = parseFooterOrder(content);
7540
+ const allowedCols = order ? new Set(
7541
+ order.flatMap(
7542
+ (col) => col.map((k) => parseFooterHrefKey(k)?.col).filter((n) => n !== void 0 && n !== null)
7543
+ )
7544
+ ) : null;
7545
+ const indices = collectFooterColumnIndicesFromContent(content);
7546
+ for (const colIndex of indices) {
7547
+ if (allowedCols && !allowedCols.has(colIndex)) continue;
7548
+ if (footerColumnExistsInDom(colIndex)) continue;
7549
+ const heading = content[`footer-${colIndex}-heading`] ?? DEFAULT_FOOTER_COLUMN_HEADING;
7550
+ const items = collectFooterItemsForColumn(content, colIndex);
7551
+ const hasPayload = Boolean(content[`footer-${colIndex}-heading`]) || items.some(
7552
+ (_, i) => content[`footer-${colIndex}-${i}-href`] !== void 0 || content[`footer-${colIndex}-${i}-label`] !== void 0
7553
+ ) || (order?.some((col) => col.some((k) => parseFooterHrefKey(k)?.col === colIndex)) ?? false);
7554
+ if (!hasPayload) continue;
7555
+ insertFooterColumnDom(colIndex, heading, items);
7556
+ }
7557
+ }
7064
7558
  function reconcileFooterOrderFromContent(content) {
7559
+ reconcileFooterColumnsFromContent(content);
7065
7560
  const order = parseFooterOrder(content);
7066
7561
  if (!order?.length) return;
7067
- const current = getFooterOrderFromDom();
7068
- if (ordersEqual(order, current)) {
7069
- syncFooterColumnIndices(listFooterColumns());
7070
- return;
7562
+ const linkTemplate = getFooterLinkTemplate();
7563
+ for (let c = 0; c < order.length; c++) {
7564
+ const colOrder = order[c];
7565
+ for (const hrefKey of colOrder) {
7566
+ if (findFooterLinkByKey(hrefKey)) continue;
7567
+ const parsed = parseFooterHrefKey(hrefKey);
7568
+ if (!parsed) continue;
7569
+ const columns = listFooterColumns();
7570
+ const column = columns.find((col) => col.getAttribute("data-ohw-footer-col") === String(parsed.col)) ?? columns[c] ?? null;
7571
+ if (!column) continue;
7572
+ const href = content[hrefKey] ?? DEFAULT_FOOTER_COLUMN_LINK_HREF;
7573
+ const labelKey = `footer-${parsed.col}-${parsed.item}-label`;
7574
+ const label = content[labelKey] ?? DEFAULT_FOOTER_COLUMN_LINK_LABEL;
7575
+ if (!href && !label) continue;
7576
+ column.appendChild(buildFooterLink(parsed.col, parsed.item, href || "/", label, linkTemplate));
7577
+ }
7071
7578
  }
7579
+ pruneFooterToOrder(order);
7072
7580
  applyFooterOrder(order);
7073
7581
  }
7582
+ function pruneFooterToOrder(order) {
7583
+ const allowedKeys = new Set(order.flat());
7584
+ const allowedColIndices = new Set(
7585
+ [...allowedKeys].map((k) => parseFooterHrefKey(k)?.col).filter((n) => n !== void 0 && n !== null)
7586
+ );
7587
+ for (const column of [...listFooterColumns()]) {
7588
+ if (!column.isConnected) continue;
7589
+ for (const link of [...listFooterLinksInColumn(column)]) {
7590
+ const key = link.getAttribute("data-ohw-href-key");
7591
+ if (!key || allowedKeys.has(key)) continue;
7592
+ link.remove();
7593
+ }
7594
+ const remaining = listFooterLinksInColumn(column);
7595
+ const colAttr = column.getAttribute("data-ohw-footer-col");
7596
+ const colIndex = colAttr != null ? parseInt(colAttr, 10) : NaN;
7597
+ const referenced = remaining.some((link) => allowedKeys.has(link.getAttribute("data-ohw-href-key") ?? ""));
7598
+ if (!referenced && (!Number.isFinite(colIndex) || !allowedColIndices.has(colIndex))) {
7599
+ column.remove();
7600
+ }
7601
+ }
7602
+ syncFooterColumnIndices(listFooterColumns());
7603
+ }
7604
+ function resolveFooterLinksContainerSelectionTarget(target, clientX, clientY, isPointOverItem) {
7605
+ const container = getFooterLinksContainer();
7606
+ if (!container) return null;
7607
+ const inContainer = target === container || container.contains(target) && Boolean(target.closest("[data-ohw-footer-links], .rb-footer-links"));
7608
+ if (!inContainer && target !== container) {
7609
+ const r2 = container.getBoundingClientRect();
7610
+ const over = clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom;
7611
+ if (!over) return null;
7612
+ }
7613
+ if (isPointOverItem(container, clientX, clientY)) return null;
7614
+ const column = target.closest("[data-ohw-footer-col], [data-ohw-footer-column]") ?? null;
7615
+ if (column && container.contains(column)) {
7616
+ if (target === column || column.contains(target)) return null;
7617
+ }
7618
+ if (target === container || container.contains(target) || inContainer) {
7619
+ if (target === container || isFooterLinksContainer(target)) return container;
7620
+ if (!column) return container;
7621
+ }
7622
+ return null;
7623
+ }
7074
7624
  function isRowLayoutColumn(links) {
7075
7625
  if (links.length < 2) return false;
7076
7626
  const firstTop = links[0].getBoundingClientRect().top;
@@ -7225,34 +7775,225 @@ function hitTestColumnDropSlot(clientX, _clientY) {
7225
7775
  }
7226
7776
  return best?.slot ?? null;
7227
7777
  }
7228
-
7229
- // src/lib/item-drag-interaction.ts
7230
- function disableNativeHrefDrag(el) {
7231
- if (el.draggable) el.draggable = false;
7232
- if (el.getAttribute("draggable") !== "false") {
7233
- el.setAttribute("draggable", "false");
7778
+ function getLinkHref2(el) {
7779
+ const key = el.getAttribute("data-ohw-href-key");
7780
+ if (key) {
7781
+ const stored = getStoredLinkHref(key);
7782
+ if (stored !== void 0) return stored;
7234
7783
  }
7784
+ return el.getAttribute("href") ?? "";
7235
7785
  }
7236
- function clearTextSelection() {
7237
- const sel = window.getSelection();
7238
- if (sel && !sel.isCollapsed) sel.removeAllRanges();
7239
- }
7240
- function armItemPressDrag() {
7241
- document.documentElement.setAttribute("data-ohw-footer-press-drag", "");
7786
+ function getNextFooterItemIndex(col) {
7787
+ let max = -1;
7788
+ for (const el of document.querySelectorAll("footer [data-ohw-href-key]")) {
7789
+ const parsed = parseFooterHrefKey(el.getAttribute("data-ohw-href-key"));
7790
+ if (!parsed || parsed.col !== col) continue;
7791
+ if (parsed.item > max) max = parsed.item;
7792
+ }
7793
+ return max + 1;
7242
7794
  }
7243
- function lockItemDuringDrag() {
7244
- document.documentElement.removeAttribute("data-ohw-footer-press-drag");
7245
- document.documentElement.setAttribute("data-ohw-item-dragging", "");
7246
- clearTextSelection();
7795
+ function cloneFooterLinkShell(template) {
7796
+ const anchor = document.createElement("a");
7797
+ if (template) {
7798
+ anchor.style.cssText = template.style.cssText;
7799
+ if (template.className) anchor.className = template.className;
7800
+ }
7801
+ anchor.style.cursor = "pointer";
7802
+ anchor.style.textDecoration = "none";
7803
+ return anchor;
7247
7804
  }
7248
- function unlockItemDragInteraction() {
7249
- const wasDragging = document.documentElement.hasAttribute("data-ohw-item-dragging");
7250
- document.documentElement.removeAttribute("data-ohw-footer-press-drag");
7251
- document.documentElement.removeAttribute("data-ohw-item-dragging");
7252
- if (wasDragging) clearTextSelection();
7805
+ function insertFooterItem(column, href, label, afterAnchor = null) {
7806
+ const columns = listFooterColumns();
7807
+ const colIndex = columns.indexOf(column);
7808
+ if (colIndex < 0) throw new Error("Footer column not found");
7809
+ const item = getNextFooterItemIndex(colIndex);
7810
+ const hrefKey = `footer-${colIndex}-${item}-href`;
7811
+ const labelKey = `footer-${colIndex}-${item}-label`;
7812
+ const template = listFooterLinksInColumn(column)[0] ?? null;
7813
+ const anchor = cloneFooterLinkShell(template);
7814
+ anchor.href = href;
7815
+ anchor.setAttribute("data-ohw-href-key", hrefKey);
7816
+ const span = document.createElement("span");
7817
+ span.setAttribute("data-ohw-editable", "text");
7818
+ span.setAttribute("data-ohw-key", labelKey);
7819
+ span.textContent = label;
7820
+ anchor.appendChild(span);
7821
+ if (afterAnchor && afterAnchor.parentElement === column) {
7822
+ afterAnchor.insertAdjacentElement("afterend", anchor);
7823
+ } else {
7824
+ column.appendChild(anchor);
7825
+ }
7826
+ const order = getFooterOrderFromDom();
7827
+ applyFooterOrder(order);
7828
+ return {
7829
+ anchor,
7830
+ col: colIndex,
7831
+ item,
7832
+ hrefKey,
7833
+ labelKey,
7834
+ href,
7835
+ label,
7836
+ order
7837
+ };
7253
7838
  }
7254
- var armFooterPressDrag = armItemPressDrag;
7255
- var lockFooterDuringDrag = lockItemDuringDrag;
7839
+ function duplicateFooterItem(sourceAnchor) {
7840
+ if (!isFooterLinkAnchor(sourceAnchor)) return null;
7841
+ const column = findFooterColumnForLink(sourceAnchor);
7842
+ if (!column) return null;
7843
+ const href = getLinkHref2(sourceAnchor);
7844
+ const labelEl = sourceAnchor.querySelector('[data-ohw-editable="text"]');
7845
+ const label = (labelEl?.textContent ?? "").trim() || "Untitled";
7846
+ return insertFooterItem(column, href || "/", label, sourceAnchor);
7847
+ }
7848
+ function footerLabelKeyFromHrefKey(hrefKey) {
7849
+ return hrefKey.replace(/-href$/, "-label");
7850
+ }
7851
+ function deleteFooterItem(sourceAnchor) {
7852
+ if (!isFooterLinkAnchor(sourceAnchor)) return null;
7853
+ const hrefKey = sourceAnchor.getAttribute("data-ohw-href-key");
7854
+ if (!hrefKey || !isFooterHrefKey(hrefKey)) return null;
7855
+ const labelEl = sourceAnchor.querySelector('[data-ohw-editable="text"]');
7856
+ const label = (labelEl?.textContent ?? "").trim() || "Untitled";
7857
+ const labelKey = footerLabelKeyFromHrefKey(hrefKey);
7858
+ const previousOrder = getFooterOrderFromDom();
7859
+ const previousOrderJson = JSON.stringify(previousOrder);
7860
+ const previousContent = {
7861
+ [hrefKey]: getLinkHref2(sourceAnchor),
7862
+ [labelKey]: label
7863
+ };
7864
+ if (!sourceAnchor.parentElement) return null;
7865
+ const placement = {
7866
+ node: sourceAnchor,
7867
+ parent: sourceAnchor.parentElement,
7868
+ nextSibling: sourceAnchor.nextSibling
7869
+ };
7870
+ sourceAnchor.remove();
7871
+ const order = getFooterOrderFromDom();
7872
+ applyFooterOrder(order);
7873
+ const orderJson = JSON.stringify(order);
7874
+ return {
7875
+ label,
7876
+ removedKeys: [hrefKey, labelKey],
7877
+ previousContent,
7878
+ orderJson,
7879
+ previousOrderJson,
7880
+ undo: () => {
7881
+ placement.parent.insertBefore(placement.node, placement.nextSibling);
7882
+ applyFooterOrder(previousOrder);
7883
+ }
7884
+ };
7885
+ }
7886
+ function deleteFooterColumn(column) {
7887
+ const columns = listFooterColumns();
7888
+ if (!columns.includes(column)) return null;
7889
+ if (!column.parentElement) return null;
7890
+ const links = listFooterLinksInColumn(column);
7891
+ const heading = column.querySelector(
7892
+ '[data-ohw-key^="footer-"][data-ohw-key$="-heading"]'
7893
+ );
7894
+ const headingKey = heading?.getAttribute("data-ohw-key") ?? null;
7895
+ const headingText = (heading?.textContent ?? "").trim();
7896
+ const label = headingText || (links[0]?.querySelector('[data-ohw-editable="text"]')?.textContent ?? "").trim() || "Untitled";
7897
+ const previousOrder = getFooterOrderFromDom();
7898
+ const previousOrderJson = JSON.stringify(previousOrder);
7899
+ const previousContent = {};
7900
+ const removedKeys = [];
7901
+ if (headingKey) {
7902
+ removedKeys.push(headingKey);
7903
+ previousContent[headingKey] = headingText;
7904
+ }
7905
+ for (const link of links) {
7906
+ const hrefKey = link.getAttribute("data-ohw-href-key");
7907
+ if (!hrefKey) continue;
7908
+ const labelKey = footerLabelKeyFromHrefKey(hrefKey);
7909
+ removedKeys.push(hrefKey, labelKey);
7910
+ previousContent[hrefKey] = getLinkHref2(link);
7911
+ previousContent[labelKey] = (link.querySelector('[data-ohw-editable="text"]')?.textContent ?? "").trim();
7912
+ }
7913
+ const placement = {
7914
+ node: column,
7915
+ parent: column.parentElement,
7916
+ nextSibling: column.nextSibling
7917
+ };
7918
+ column.remove();
7919
+ const remaining = listFooterColumns();
7920
+ syncFooterColumnIndices(remaining);
7921
+ const order = getFooterOrderFromDom();
7922
+ applyFooterOrder(order);
7923
+ const orderJson = JSON.stringify(order);
7924
+ return {
7925
+ label,
7926
+ removedKeys,
7927
+ previousContent,
7928
+ orderJson,
7929
+ previousOrderJson,
7930
+ undo: () => {
7931
+ placement.parent.insertBefore(placement.node, placement.nextSibling);
7932
+ syncFooterColumnIndices(listFooterColumns());
7933
+ applyFooterOrder(previousOrder);
7934
+ }
7935
+ };
7936
+ }
7937
+
7938
+ // src/lib/add-footer-column.ts
7939
+ function buildFooterColumnEditContentPatch(result) {
7940
+ return {
7941
+ [result.headingKey]: result.heading,
7942
+ [result.hrefKey]: result.href,
7943
+ [result.labelKey]: result.label,
7944
+ [FOOTER_ORDER_KEY]: JSON.stringify(result.order)
7945
+ };
7946
+ }
7947
+ function addFooterColumnWithPersist({
7948
+ postToParent: postToParent2
7949
+ }) {
7950
+ if (!canAddFooterColumn()) {
7951
+ postToParent2({
7952
+ type: "ow:toast",
7953
+ title: `Maximum ${MAX_FOOTER_COLUMNS} columns`,
7954
+ toastType: "error"
7955
+ });
7956
+ return null;
7957
+ }
7958
+ const result = insertFooterColumn();
7959
+ const patch = buildFooterColumnEditContentPatch(result);
7960
+ setStoredLinkHref(result.hrefKey, result.href);
7961
+ postToParent2({
7962
+ type: "ow:change",
7963
+ nodes: Object.entries(patch).map(([key, text]) => ({ key, text }))
7964
+ });
7965
+ postToParent2({ type: "ow:toast", title: "Item added", toastType: "success" });
7966
+ enforceLinkHrefs();
7967
+ return result;
7968
+ }
7969
+
7970
+ // src/lib/item-drag-interaction.ts
7971
+ function disableNativeHrefDrag(el) {
7972
+ if (el.draggable) el.draggable = false;
7973
+ if (el.getAttribute("draggable") !== "false") {
7974
+ el.setAttribute("draggable", "false");
7975
+ }
7976
+ }
7977
+ function clearTextSelection() {
7978
+ const sel = window.getSelection();
7979
+ if (sel && !sel.isCollapsed) sel.removeAllRanges();
7980
+ }
7981
+ function armItemPressDrag() {
7982
+ document.documentElement.setAttribute("data-ohw-footer-press-drag", "");
7983
+ }
7984
+ function lockItemDuringDrag() {
7985
+ document.documentElement.removeAttribute("data-ohw-footer-press-drag");
7986
+ document.documentElement.setAttribute("data-ohw-item-dragging", "");
7987
+ clearTextSelection();
7988
+ }
7989
+ function unlockItemDragInteraction() {
7990
+ const wasDragging = document.documentElement.hasAttribute("data-ohw-item-dragging");
7991
+ document.documentElement.removeAttribute("data-ohw-footer-press-drag");
7992
+ document.documentElement.removeAttribute("data-ohw-item-dragging");
7993
+ if (wasDragging) clearTextSelection();
7994
+ }
7995
+ var armFooterPressDrag = armItemPressDrag;
7996
+ var lockFooterDuringDrag = lockItemDuringDrag;
7256
7997
  var unlockFooterDragInteraction = unlockItemDragInteraction;
7257
7998
 
7258
7999
  // src/lib/nav-dnd.ts
@@ -7423,7 +8164,7 @@ function hitTestNavDropSlot(clientX, clientY, draggedHrefKey) {
7423
8164
  }
7424
8165
 
7425
8166
  // src/useNavItemDrag.ts
7426
- import { useCallback as useCallback4, useEffect as useEffect7, useRef as useRef6, useState as useState6 } from "react";
8167
+ import { useCallback as useCallback4, useEffect as useEffect7, useRef as useRef6, useState as useState7 } from "react";
7427
8168
  function useNavItemDrag({
7428
8169
  isEditMode,
7429
8170
  editContentRef,
@@ -7449,8 +8190,8 @@ function useNavItemDrag({
7449
8190
  isNavbarButton: isNavbarButton3
7450
8191
  }) {
7451
8192
  const navDragRef = useRef6(null);
7452
- const [navDropSlots, setNavDropSlots] = useState6([]);
7453
- const [activeNavDropIndex, setActiveNavDropIndex] = useState6(null);
8193
+ const [navDropSlots, setNavDropSlots] = useState7([]);
8194
+ const [activeNavDropIndex, setActiveNavDropIndex] = useState7(null);
7454
8195
  const navPointerDragRef = useRef6(null);
7455
8196
  const clearNavDragVisuals = useCallback4(() => {
7456
8197
  navDragRef.current = null;
@@ -7758,8 +8499,59 @@ function useNavItemDrag({
7758
8499
  };
7759
8500
  }
7760
8501
 
8502
+ // src/ui/footer-container-chrome.tsx
8503
+ import { Plus as Plus2 } from "lucide-react";
8504
+ import { jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
8505
+ function FooterContainerChrome({
8506
+ rect,
8507
+ onAdd,
8508
+ addDisabled = false
8509
+ }) {
8510
+ const chromeGap = 6;
8511
+ const buttonMargin = 7;
8512
+ return /* @__PURE__ */ jsx23(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsx23(
8513
+ "div",
8514
+ {
8515
+ "data-ohw-footer-container-chrome": "",
8516
+ "data-ohw-bridge": "",
8517
+ className: "pointer-events-none fixed z-[2147483647]",
8518
+ style: {
8519
+ top: rect.top - chromeGap,
8520
+ left: rect.left - chromeGap,
8521
+ width: rect.width + chromeGap * 2,
8522
+ height: rect.height + chromeGap * 2
8523
+ },
8524
+ children: /* @__PURE__ */ jsxs14(Tooltip, { children: [
8525
+ /* @__PURE__ */ jsx23(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx23(
8526
+ "button",
8527
+ {
8528
+ type: "button",
8529
+ "data-ohw-footer-add-button": "",
8530
+ disabled: addDisabled,
8531
+ 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 disabled:pointer-events-none disabled:opacity-40",
8532
+ style: { top: chromeGap - buttonMargin },
8533
+ "aria-label": "Add item",
8534
+ onMouseDown: (e) => {
8535
+ e.preventDefault();
8536
+ e.stopPropagation();
8537
+ },
8538
+ onClick: (e) => {
8539
+ e.preventDefault();
8540
+ e.stopPropagation();
8541
+ if (addDisabled) return;
8542
+ onAdd();
8543
+ },
8544
+ children: /* @__PURE__ */ jsx23(Plus2, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
8545
+ }
8546
+ ) }),
8547
+ /* @__PURE__ */ jsx23(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
8548
+ ] })
8549
+ }
8550
+ ) });
8551
+ }
8552
+
7761
8553
  // src/lib/carousel.ts
7762
- import { useEffect as useEffect8, useState as useState7 } from "react";
8554
+ import { useEffect as useEffect8, useState as useState8 } from "react";
7763
8555
  var CAROUSEL_ATTR = "data-ohw-carousel";
7764
8556
  var CAROUSEL_VALUE_ATTR = "data-ohw-carousel-value";
7765
8557
  var CAROUSEL_SLIDE_ATTR = "data-ohw-carousel-slide";
@@ -7821,7 +8613,7 @@ function applyCarouselNode(key, val) {
7821
8613
  return true;
7822
8614
  }
7823
8615
  function useOhwCarousel(key, initial) {
7824
- const [images, setImages] = useState7(initial);
8616
+ const [images, setImages] = useState8(initial);
7825
8617
  useEffect8(() => {
7826
8618
  const el = document.querySelector(
7827
8619
  `[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`
@@ -7842,15 +8634,340 @@ function useOhwCarousel(key, initial) {
7842
8634
  return { images, setImages, bind };
7843
8635
  }
7844
8636
 
8637
+ // src/lib/collect-editable-nodes.ts
8638
+ var VIDEO_AUTOPLAY_SUFFIX = "__ohw_autoplay";
8639
+ var VIDEO_MUTED_SUFFIX = "__ohw_muted";
8640
+ function getVideoEl(el) {
8641
+ return el instanceof HTMLVideoElement ? el : el.querySelector("video");
8642
+ }
8643
+ function getLinkHref3(el) {
8644
+ const key = el.getAttribute("data-ohw-href-key");
8645
+ if (key) {
8646
+ const stored = getStoredLinkHref(key);
8647
+ if (stored !== void 0) return stored;
8648
+ }
8649
+ const anchor = el instanceof HTMLAnchorElement ? el : el.querySelector("a");
8650
+ return anchor?.getAttribute("href") ?? "";
8651
+ }
8652
+ function collectEditableNodes(extraContent) {
8653
+ const nodes = Array.from(
8654
+ document.querySelectorAll("[data-ohw-editable]")
8655
+ ).map((el) => {
8656
+ if (el.dataset.ohwEditable === "image") {
8657
+ const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
8658
+ return { key: el.dataset.ohwKey ?? "", type: "image", text: img?.src ?? "" };
8659
+ }
8660
+ if (el.dataset.ohwEditable === "bg-image") {
8661
+ const raw = el.style.backgroundImage;
8662
+ const url = raw.replace(/^url\(['"]?/, "").replace(/['"]?\)$/, "");
8663
+ return { key: el.dataset.ohwKey ?? "", type: "bg-image", text: url };
8664
+ }
8665
+ if (el.dataset.ohwEditable === "video") {
8666
+ return { key: el.dataset.ohwKey ?? "", type: "video", text: getVideoEl(el)?.src ?? "" };
8667
+ }
8668
+ if (el.dataset.ohwEditable === "link") {
8669
+ return { key: el.dataset.ohwKey ?? "", type: "link", text: getLinkHref3(el) };
8670
+ }
8671
+ return {
8672
+ key: el.dataset.ohwKey ?? "",
8673
+ type: el.dataset.ohwEditable ?? "text",
8674
+ text: el.dataset.ohwEditable === "plain" ? el.innerText ?? "" : el.innerHTML
8675
+ };
8676
+ });
8677
+ document.querySelectorAll("[data-ohw-href-key]").forEach((el) => {
8678
+ const key = el.getAttribute("data-ohw-href-key") ?? "";
8679
+ if (!key) return;
8680
+ nodes.push({ key, type: "link", text: getLinkHref3(el) });
8681
+ });
8682
+ if (extraContent) {
8683
+ for (const key of [NAV_ORDER_KEY, FOOTER_ORDER_KEY, NAV_COUNT_KEY]) {
8684
+ const text = extraContent[key];
8685
+ if (typeof text === "string" && text.length > 0) {
8686
+ nodes.push({ key, type: "meta", text });
8687
+ }
8688
+ }
8689
+ }
8690
+ document.querySelectorAll('[data-ohw-editable="video"]').forEach((el) => {
8691
+ const key = el.dataset.ohwKey ?? "";
8692
+ const video = getVideoEl(el);
8693
+ if (!key || !video) return;
8694
+ nodes.push({
8695
+ key: `${key}${VIDEO_AUTOPLAY_SUFFIX}`,
8696
+ type: "video-setting",
8697
+ text: String(video.autoplay)
8698
+ });
8699
+ nodes.push({
8700
+ key: `${key}${VIDEO_MUTED_SUFFIX}`,
8701
+ type: "video-setting",
8702
+ text: String(video.muted)
8703
+ });
8704
+ });
8705
+ for (const key of listCarouselKeys()) {
8706
+ nodes.push({ key, type: "carousel", text: JSON.stringify(readCarouselValue(key)) });
8707
+ }
8708
+ const byKey = /* @__PURE__ */ new Map();
8709
+ for (const node of nodes) {
8710
+ if (!node.key) continue;
8711
+ if (!byKey.has(node.key)) byKey.set(node.key, node);
8712
+ }
8713
+ if (extraContent) {
8714
+ applyNavFooterDeleteOverrides(byKey, extraContent);
8715
+ }
8716
+ return Array.from(byKey.values());
8717
+ }
8718
+ function applyNavFooterDeleteOverrides(byKey, content) {
8719
+ for (const [key, text] of Object.entries(content)) {
8720
+ if (text !== "") continue;
8721
+ if (!key.startsWith("nav-") && !key.startsWith("footer-")) continue;
8722
+ if (key === "nav-book-href" || key === "nav-book-label") continue;
8723
+ byKey.set(key, { key, type: "meta", text: "" });
8724
+ }
8725
+ const navOrder = content[NAV_ORDER_KEY];
8726
+ if (navOrder) {
8727
+ try {
8728
+ const allowed = parseAllowedNavHrefKeys(navOrder);
8729
+ const clearKey = (key) => {
8730
+ byKey.set(key, { key, type: "meta", text: "" });
8731
+ };
8732
+ for (const key of /* @__PURE__ */ new Set([...byKey.keys(), ...Object.keys(content)])) {
8733
+ if (key === "nav-book-href" || key === "nav-book-label") continue;
8734
+ if (isNavbarHrefKey(key) && !allowed.has(key)) {
8735
+ clearKey(key);
8736
+ clearKey(key.replace(/-href$/, "-label"));
8737
+ } else if (/^nav-\d+-label$/.test(key)) {
8738
+ const hrefKey = key.replace(/-label$/, "-href");
8739
+ if (!allowed.has(hrefKey)) clearKey(key);
8740
+ }
8741
+ }
8742
+ } catch {
8743
+ }
8744
+ }
8745
+ const footerOrder = content[FOOTER_ORDER_KEY];
8746
+ if (footerOrder) {
8747
+ try {
8748
+ const { allowedKeys, allowedCols } = parseAllowedFooterKeys(footerOrder);
8749
+ const clearKey = (key) => {
8750
+ byKey.set(key, { key, type: "meta", text: "" });
8751
+ };
8752
+ for (const key of /* @__PURE__ */ new Set([...byKey.keys(), ...Object.keys(content)])) {
8753
+ if (isFooterHrefKey(key) && !allowedKeys.has(key)) {
8754
+ clearKey(key);
8755
+ clearKey(key.replace(/-href$/, "-label"));
8756
+ continue;
8757
+ }
8758
+ const labelMatch = key.match(/^footer-(\d+)-(\d+)-label$/);
8759
+ if (labelMatch) {
8760
+ const hrefKey = `footer-${labelMatch[1]}-${labelMatch[2]}-href`;
8761
+ if (!allowedKeys.has(hrefKey)) clearKey(key);
8762
+ continue;
8763
+ }
8764
+ const headingMatch = key.match(/^footer-(\d+)-heading$/);
8765
+ if (headingMatch && !allowedCols.has(parseInt(headingMatch[1], 10))) {
8766
+ clearKey(key);
8767
+ }
8768
+ }
8769
+ } catch {
8770
+ }
8771
+ }
8772
+ }
8773
+ function parseAllowedNavHrefKeys(raw) {
8774
+ const parsed = JSON.parse(raw);
8775
+ const allowed = /* @__PURE__ */ new Set();
8776
+ const walk = (nodes) => {
8777
+ if (!Array.isArray(nodes)) return;
8778
+ for (const node of nodes) {
8779
+ if (typeof node === "string" && node.length > 0) {
8780
+ allowed.add(node);
8781
+ continue;
8782
+ }
8783
+ if (node && typeof node === "object" && typeof node.id === "string") {
8784
+ allowed.add(node.id);
8785
+ walk(node.children);
8786
+ }
8787
+ }
8788
+ };
8789
+ walk(parsed);
8790
+ return allowed;
8791
+ }
8792
+ function parseAllowedFooterKeys(raw) {
8793
+ const parsed = JSON.parse(raw);
8794
+ const allowedKeys = /* @__PURE__ */ new Set();
8795
+ const allowedCols = /* @__PURE__ */ new Set();
8796
+ if (Array.isArray(parsed)) {
8797
+ for (const col of parsed) {
8798
+ if (!Array.isArray(col)) continue;
8799
+ for (const key of col) {
8800
+ if (typeof key !== "string" || !key) continue;
8801
+ allowedKeys.add(key);
8802
+ const m = key.match(/^footer-(\d+)-\d+-href$/);
8803
+ if (m) allowedCols.add(parseInt(m[1], 10));
8804
+ }
8805
+ }
8806
+ }
8807
+ return { allowedKeys, allowedCols };
8808
+ }
8809
+
8810
+ // src/lib/delete-nav-footer-selection.ts
8811
+ function isNavbarLinksContainer(el) {
8812
+ return el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer");
8813
+ }
8814
+ function isNavigationItem(el) {
8815
+ const anchor = el.matches("[data-ohw-href-key]") ? el : el.closest("[data-ohw-href-key]");
8816
+ if (!anchor) return false;
8817
+ return Boolean(anchor.querySelector('[data-ohw-editable="text"]'));
8818
+ }
8819
+ function findFooterItemGroup(item) {
8820
+ const explicit = item.closest("[data-ohw-footer-col], [data-ohw-footer-column]");
8821
+ if (explicit) return explicit;
8822
+ const footer = item.closest("footer");
8823
+ if (!footer) return null;
8824
+ let node = item.parentElement;
8825
+ while (node && node !== footer) {
8826
+ const count = Array.from(node.querySelectorAll("[data-ohw-href-key]")).filter(
8827
+ isNavigationItem
8828
+ ).length;
8829
+ if (count >= 2) return node;
8830
+ node = node.parentElement;
8831
+ }
8832
+ return footer;
8833
+ }
8834
+ function isInferredFooterGroup(el) {
8835
+ const footer = el.closest("footer");
8836
+ if (!footer || el === footer) return false;
8837
+ if (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column")) return true;
8838
+ const count = Array.from(el.querySelectorAll("[data-ohw-href-key]")).filter(
8839
+ isNavigationItem
8840
+ ).length;
8841
+ return count >= 2;
8842
+ }
8843
+ function newActionId() {
8844
+ return typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `delete-${Date.now()}`;
8845
+ }
8846
+ function deleteSelectedNavFooterItem(deps) {
8847
+ const {
8848
+ selected,
8849
+ isTextEditing,
8850
+ isSelectFrame,
8851
+ getEditContent,
8852
+ applyLinkByKey: applyLinkByKey2,
8853
+ postToParent: postToParent2,
8854
+ deselect,
8855
+ setEditContent,
8856
+ setPendingUndo
8857
+ } = deps;
8858
+ if (isTextEditing) return false;
8859
+ if (isNavbarLinksContainer(selected) || isFooterLinksContainer(selected)) return false;
8860
+ const finishDelete = (opts) => {
8861
+ const actionId = newActionId();
8862
+ const clearedNodes = opts.removedKeys.map((key) => ({
8863
+ key,
8864
+ text: ""
8865
+ }));
8866
+ clearedNodes.push({ key: opts.orderKey, text: opts.orderJson });
8867
+ const nextContent = { ...getEditContent() };
8868
+ for (const key of opts.removedKeys) {
8869
+ nextContent[key] = "";
8870
+ clearStoredLinkHref(key);
8871
+ }
8872
+ nextContent[opts.orderKey] = opts.orderJson;
8873
+ setEditContent(nextContent);
8874
+ postToParent2({ type: "ow:change", nodes: clearedNodes });
8875
+ setPendingUndo({
8876
+ actionId,
8877
+ restore: () => {
8878
+ opts.undoDom();
8879
+ for (const [key, text] of Object.entries(opts.previousContent)) {
8880
+ if (key.endsWith("-href")) applyLinkByKey2(key, text);
8881
+ else {
8882
+ document.querySelectorAll(`[data-ohw-key="${CSS.escape(key)}"]`).forEach((el) => {
8883
+ el.textContent = text;
8884
+ });
8885
+ }
8886
+ }
8887
+ setEditContent({
8888
+ ...getEditContent(),
8889
+ ...opts.previousContent,
8890
+ [opts.orderKey]: opts.previousOrderJson
8891
+ });
8892
+ postToParent2({
8893
+ type: "ow:change",
8894
+ nodes: [
8895
+ ...Object.entries(opts.previousContent).map(([key, text]) => ({ key, text })),
8896
+ { key: opts.orderKey, text: opts.previousOrderJson }
8897
+ ]
8898
+ });
8899
+ }
8900
+ });
8901
+ deselect();
8902
+ postToParent2({
8903
+ type: "ow:toast",
8904
+ title: opts.toastTitle,
8905
+ toastType: "success",
8906
+ actionLabel: "Undo",
8907
+ actionId,
8908
+ duration: 6e3
8909
+ });
8910
+ };
8911
+ const isFooterColumnSelection = selected.hasAttribute("data-ohw-footer-col") || selected.hasAttribute("data-ohw-footer-column") || isSelectFrame && isInferredFooterGroup(selected) && Boolean(selected.closest("footer"));
8912
+ if (isFooterColumnSelection) {
8913
+ const column = selected.hasAttribute("data-ohw-footer-col") || selected.hasAttribute("data-ohw-footer-column") ? selected : findFooterItemGroup(selected);
8914
+ if (!column) return false;
8915
+ const result = deleteFooterColumn(column);
8916
+ if (!result) return false;
8917
+ finishDelete({
8918
+ toastTitle: "Item deleted",
8919
+ removedKeys: result.removedKeys,
8920
+ previousContent: result.previousContent,
8921
+ orderKey: FOOTER_ORDER_KEY,
8922
+ orderJson: result.orderJson,
8923
+ previousOrderJson: result.previousOrderJson,
8924
+ undoDom: result.undo
8925
+ });
8926
+ return true;
8927
+ }
8928
+ if (!isNavigationItem(selected)) return false;
8929
+ const hrefKey = selected.getAttribute("data-ohw-href-key");
8930
+ if (!hrefKey) return false;
8931
+ if (isNavbarHrefKey(hrefKey)) {
8932
+ const result = deleteNavbarItem(selected);
8933
+ if (!result) return false;
8934
+ finishDelete({
8935
+ toastTitle: "Nav item deleted",
8936
+ removedKeys: result.removedKeys,
8937
+ previousContent: result.previousContent,
8938
+ orderKey: NAV_ORDER_KEY,
8939
+ orderJson: result.orderJson,
8940
+ previousOrderJson: result.previousOrderJson,
8941
+ undoDom: result.undo
8942
+ });
8943
+ return true;
8944
+ }
8945
+ if (isFooterHrefKey(hrefKey)) {
8946
+ const result = deleteFooterItem(selected);
8947
+ if (!result) return false;
8948
+ finishDelete({
8949
+ toastTitle: "Item deleted",
8950
+ removedKeys: result.removedKeys,
8951
+ previousContent: result.previousContent,
8952
+ orderKey: FOOTER_ORDER_KEY,
8953
+ orderJson: result.orderJson,
8954
+ previousOrderJson: result.previousOrderJson,
8955
+ undoDom: result.undo
8956
+ });
8957
+ return true;
8958
+ }
8959
+ return false;
8960
+ }
8961
+
7845
8962
  // src/ui/navbar-container-chrome.tsx
7846
- import { Plus as Plus2 } from "lucide-react";
7847
- import { jsx as jsx22 } from "react/jsx-runtime";
8963
+ import { Plus as Plus3 } from "lucide-react";
8964
+ import { jsx as jsx24 } from "react/jsx-runtime";
7848
8965
  function NavbarContainerChrome({
7849
8966
  rect,
7850
8967
  onAdd
7851
8968
  }) {
7852
8969
  const chromeGap = 6;
7853
- return /* @__PURE__ */ jsx22(
8970
+ return /* @__PURE__ */ jsx24(
7854
8971
  "div",
7855
8972
  {
7856
8973
  "data-ohw-navbar-container-chrome": "",
@@ -7862,7 +8979,7 @@ function NavbarContainerChrome({
7862
8979
  width: rect.width + chromeGap * 2,
7863
8980
  height: rect.height + chromeGap * 2
7864
8981
  },
7865
- children: /* @__PURE__ */ jsx22(
8982
+ children: /* @__PURE__ */ jsx24(
7866
8983
  "button",
7867
8984
  {
7868
8985
  type: "button",
@@ -7879,7 +8996,7 @@ function NavbarContainerChrome({
7879
8996
  e.stopPropagation();
7880
8997
  onAdd();
7881
8998
  },
7882
- children: /* @__PURE__ */ jsx22(Plus2, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
8999
+ children: /* @__PURE__ */ jsx24(Plus3, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
7883
9000
  }
7884
9001
  )
7885
9002
  }
@@ -7888,7 +9005,7 @@ function NavbarContainerChrome({
7888
9005
 
7889
9006
  // src/ui/drop-indicator.tsx
7890
9007
  import * as React10 from "react";
7891
- import { jsx as jsx23 } from "react/jsx-runtime";
9008
+ import { jsx as jsx25 } from "react/jsx-runtime";
7892
9009
  var dropIndicatorVariants = cva(
7893
9010
  "ov-gap-line pointer-events-none shrink-0 transition-opacity duration-150",
7894
9011
  {
@@ -7912,7 +9029,7 @@ var dropIndicatorVariants = cva(
7912
9029
  );
7913
9030
  var DropIndicator = React10.forwardRef(
7914
9031
  ({ className, direction, state, ...props }, ref) => {
7915
- return /* @__PURE__ */ jsx23(
9032
+ return /* @__PURE__ */ jsx25(
7916
9033
  "div",
7917
9034
  {
7918
9035
  ref,
@@ -7929,7 +9046,7 @@ var DropIndicator = React10.forwardRef(
7929
9046
  DropIndicator.displayName = "DropIndicator";
7930
9047
 
7931
9048
  // src/ui/badge.tsx
7932
- import { jsx as jsx24 } from "react/jsx-runtime";
9049
+ import { jsx as jsx26 } from "react/jsx-runtime";
7933
9050
  var badgeVariants = cva(
7934
9051
  "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",
7935
9052
  {
@@ -7947,12 +9064,12 @@ var badgeVariants = cva(
7947
9064
  }
7948
9065
  );
7949
9066
  function Badge({ className, variant, ...props }) {
7950
- return /* @__PURE__ */ jsx24("div", { className: cn(badgeVariants({ variant }), className), ...props });
9067
+ return /* @__PURE__ */ jsx26("div", { className: cn(badgeVariants({ variant }), className), ...props });
7951
9068
  }
7952
9069
 
7953
9070
  // src/OhhwellsBridge.tsx
7954
9071
  import { Link as Link2 } from "lucide-react";
7955
- import { Fragment as Fragment5, jsx as jsx25, jsxs as jsxs14 } from "react/jsx-runtime";
9072
+ import { Fragment as Fragment5, jsx as jsx27, jsxs as jsxs15 } from "react/jsx-runtime";
7956
9073
  var PRIMARY2 = "#0885FE";
7957
9074
  var IMAGE_FADE_MS = 300;
7958
9075
  function runOpacityFade(el, onDone) {
@@ -8131,7 +9248,7 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
8131
9248
  const root = createRoot(container);
8132
9249
  flushSync(() => {
8133
9250
  root.render(
8134
- /* @__PURE__ */ jsx25(
9251
+ /* @__PURE__ */ jsx27(
8135
9252
  SchedulingWidget,
8136
9253
  {
8137
9254
  notifyOnConnect,
@@ -8171,7 +9288,7 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
8171
9288
  }
8172
9289
  }
8173
9290
  }
8174
- function getLinkHref2(el) {
9291
+ function getLinkHref4(el) {
8175
9292
  const anchor = el instanceof HTMLAnchorElement ? el : el.querySelector("a");
8176
9293
  return anchor?.getAttribute("href") ?? "";
8177
9294
  }
@@ -8199,78 +9316,22 @@ function canDragNavigationItem(anchor) {
8199
9316
  }
8200
9317
  function syncNavigationDragCursorAttrs() {
8201
9318
  document.querySelectorAll("nav [data-ohw-href-key], footer [data-ohw-href-key]").forEach((el) => {
8202
- if (!isNavigationItem(el) || !canDragNavigationItem(el)) {
9319
+ if (!isNavigationItem2(el) || !canDragNavigationItem(el)) {
8203
9320
  el.removeAttribute("data-ohw-can-drag");
8204
9321
  return;
8205
9322
  }
8206
9323
  el.setAttribute("data-ohw-can-drag", "");
8207
9324
  });
8208
9325
  }
8209
- function collectEditableNodes(extraContent) {
8210
- const nodes = Array.from(document.querySelectorAll("[data-ohw-editable]")).map((el) => {
8211
- if (el.dataset.ohwEditable === "image") {
8212
- const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
8213
- return { key: el.dataset.ohwKey ?? "", type: "image", text: img?.src ?? "" };
8214
- }
8215
- if (el.dataset.ohwEditable === "bg-image") {
8216
- const raw = el.style.backgroundImage;
8217
- const url = raw.replace(/^url\(['"]?/, "").replace(/['"]?\)$/, "");
8218
- return { key: el.dataset.ohwKey ?? "", type: "bg-image", text: url };
8219
- }
8220
- if (el.dataset.ohwEditable === "video") {
8221
- return { key: el.dataset.ohwKey ?? "", type: "video", text: getVideoEl(el)?.src ?? "" };
8222
- }
8223
- if (el.dataset.ohwEditable === "link") {
8224
- return { key: el.dataset.ohwKey ?? "", type: "link", text: getLinkHref2(el) };
8225
- }
8226
- return {
8227
- key: el.dataset.ohwKey ?? "",
8228
- type: el.dataset.ohwEditable ?? "text",
8229
- text: el.dataset.ohwEditable === "plain" ? el.innerText ?? "" : el.innerHTML
8230
- };
8231
- });
8232
- document.querySelectorAll("[data-ohw-href-key]").forEach((el) => {
8233
- const key = el.getAttribute("data-ohw-href-key") ?? "";
8234
- if (!key) return;
8235
- nodes.push({ key, type: "link", text: getLinkHref2(el) });
8236
- });
8237
- if (extraContent) {
8238
- for (const key of [NAV_ORDER_KEY, FOOTER_ORDER_KEY, NAV_COUNT_KEY]) {
8239
- const text = extraContent[key];
8240
- if (typeof text === "string" && text.length > 0) {
8241
- nodes.push({ key, type: "meta", text });
8242
- }
8243
- }
8244
- }
8245
- document.querySelectorAll('[data-ohw-editable="video"]').forEach((el) => {
8246
- const key = el.dataset.ohwKey ?? "";
8247
- const video = getVideoEl(el);
8248
- if (!key || !video) return;
8249
- nodes.push({ key: `${key}${VIDEO_AUTOPLAY_SUFFIX}`, type: "video-setting", text: String(video.autoplay) });
8250
- nodes.push({ key: `${key}${VIDEO_MUTED_SUFFIX}`, type: "video-setting", text: String(video.muted) });
8251
- });
8252
- for (const key of listCarouselKeys()) {
8253
- nodes.push({ key, type: "carousel", text: JSON.stringify(readCarouselValue(key)) });
8254
- }
8255
- const seen = /* @__PURE__ */ new Set();
8256
- return nodes.filter((node) => {
8257
- if (!node.key) return true;
8258
- if (seen.has(node.key)) return false;
8259
- seen.add(node.key);
8260
- return true;
8261
- });
8262
- }
8263
9326
  function isMediaEditable(el) {
8264
9327
  const t = el.dataset.ohwEditable;
8265
9328
  return t === "image" || t === "bg-image" || t === "video";
8266
9329
  }
8267
9330
  var MEDIA_SELECTOR = '[data-ohw-editable="image"], [data-ohw-editable="bg-image"], [data-ohw-editable="video"]';
8268
9331
  var NON_MEDIA_SELECTOR = '[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"])';
8269
- function getVideoEl(el) {
9332
+ function getVideoEl2(el) {
8270
9333
  return el instanceof HTMLVideoElement ? el : el.querySelector("video");
8271
9334
  }
8272
- var VIDEO_AUTOPLAY_SUFFIX = "__ohw_autoplay";
8273
- var VIDEO_MUTED_SUFFIX = "__ohw_muted";
8274
9335
  function isBackgroundVideo(video) {
8275
9336
  return video.autoplay && video.muted;
8276
9337
  }
@@ -8315,7 +9376,7 @@ function applyVideoSettingNode(key, val) {
8315
9376
  const baseKey = key.slice(0, key.length - suffixLen);
8316
9377
  const on = val === "true";
8317
9378
  document.querySelectorAll(`[data-ohw-key="${baseKey}"]`).forEach((el) => {
8318
- const video = getVideoEl(el);
9379
+ const video = getVideoEl2(el);
8319
9380
  if (!video) return;
8320
9381
  if (isAutoplay) video.autoplay = on;
8321
9382
  else video.muted = on;
@@ -8335,7 +9396,7 @@ function applyLinkByKey(key, val) {
8335
9396
  }
8336
9397
  function isInsideLinkEditor(target) {
8337
9398
  return Boolean(
8338
- 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"]')
9399
+ 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"]')
8339
9400
  );
8340
9401
  }
8341
9402
  function getHrefKeyFromElement(el) {
@@ -8355,13 +9416,13 @@ function getNavigationItemAnchor(el) {
8355
9416
  if (!anchor.querySelector('[data-ohw-editable="text"]')) return null;
8356
9417
  return anchor;
8357
9418
  }
8358
- function isNavigationItem(el) {
9419
+ function isNavigationItem2(el) {
8359
9420
  return getNavigationItemAnchor(el) !== null;
8360
9421
  }
8361
9422
  function listNavigationItems() {
8362
9423
  return Array.from(
8363
9424
  document.querySelectorAll("nav [data-ohw-href-key], footer [data-ohw-href-key]")
8364
- ).filter((el) => isNavigationItem(el));
9425
+ ).filter((el) => isNavigationItem2(el));
8365
9426
  }
8366
9427
  function getNavigationItemReorderState(anchor) {
8367
9428
  if (isNavbarButton2(anchor)) return { key: null, disabled: false };
@@ -8392,9 +9453,9 @@ function getNavigationRoot(el) {
8392
9453
  return el.closest("nav, footer, aside");
8393
9454
  }
8394
9455
  function countFooterNavItems(el) {
8395
- return Array.from(el.querySelectorAll("[data-ohw-href-key]")).filter(isNavigationItem).length;
9456
+ return Array.from(el.querySelectorAll("[data-ohw-href-key]")).filter(isNavigationItem2).length;
8396
9457
  }
8397
- function findFooterItemGroup(item) {
9458
+ function findFooterItemGroup2(item) {
8398
9459
  const explicit = item.closest("[data-ohw-footer-col], [data-ohw-footer-column]");
8399
9460
  if (explicit) return explicit;
8400
9461
  const footer = item.closest("footer");
@@ -8409,16 +9470,16 @@ function findFooterItemGroup(item) {
8409
9470
  function isNavigationRoot(el) {
8410
9471
  return el.hasAttribute("data-ohw-nav-root") || el.matches("nav, footer, aside");
8411
9472
  }
8412
- function isInferredFooterGroup(el) {
9473
+ function isInferredFooterGroup2(el) {
8413
9474
  const footer = el.closest("footer");
8414
9475
  if (!footer || el === footer) return false;
8415
9476
  if (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column")) return true;
8416
9477
  return countFooterNavItems(el) >= 2;
8417
9478
  }
8418
9479
  function isNavigationContainer(el) {
8419
- return el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isNavigationRoot(el) || isInferredFooterGroup(el);
9480
+ return el.hasAttribute("data-ohw-nav-container") || isFooterLinksContainer(el) || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isNavigationRoot(el) || isInferredFooterGroup2(el);
8420
9481
  }
8421
- function isNavbarLinksContainer(el) {
9482
+ function isNavbarLinksContainer2(el) {
8422
9483
  return el.hasAttribute("data-ohw-nav-container");
8423
9484
  }
8424
9485
  function getFooterColumn(el) {
@@ -8435,6 +9496,9 @@ function isPointOverNavigation(x, y) {
8435
9496
  const roots = /* @__PURE__ */ new Set();
8436
9497
  const navRoot = document.querySelector("[data-ohw-nav-root]") ?? document.querySelector("nav");
8437
9498
  if (navRoot) roots.add(navRoot);
9499
+ document.querySelectorAll("[data-ohw-nav-drawer], [data-ohw-nav-container]").forEach((el) => {
9500
+ roots.add(el);
9501
+ });
8438
9502
  const footer = document.querySelector("footer");
8439
9503
  if (footer) roots.add(footer);
8440
9504
  for (const root of roots) {
@@ -8458,11 +9522,17 @@ function findHoveredNavOrFooterContainer(x, y) {
8458
9522
  }
8459
9523
  function isPointOverNavItem(container, x, y) {
8460
9524
  return Array.from(container.querySelectorAll("[data-ohw-href-key]")).some((el) => {
8461
- if (!isNavigationItem(el) || isNavbarButton2(el)) return false;
9525
+ if (!isNavigationItem2(el) || isNavbarButton2(el)) return false;
8462
9526
  const itemRect = el.getBoundingClientRect();
8463
9527
  return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
8464
9528
  });
8465
9529
  }
9530
+ function isPointOverFooterColumn(x, y) {
9531
+ return listFooterColumns().some((col) => {
9532
+ const r2 = col.getBoundingClientRect();
9533
+ return x >= r2.left && x <= r2.right && y >= r2.top && y <= r2.bottom;
9534
+ });
9535
+ }
8466
9536
  function resolveNavContainerSelectionTarget(target, clientX, clientY) {
8467
9537
  if (getNavigationItemAnchor(target)) return null;
8468
9538
  if (target.closest('[data-ohw-role="navbar-button"]')) return null;
@@ -8484,29 +9554,32 @@ function resolveNavContainerSelectionTarget(target, clientX, clientY) {
8484
9554
  return null;
8485
9555
  }
8486
9556
  function getNavigationSelectionParent(el) {
8487
- if (isNavigationItem(el)) {
9557
+ if (isNavigationItem2(el)) {
8488
9558
  const explicit = el.closest("[data-ohw-nav-container]");
8489
9559
  if (explicit) return explicit;
8490
9560
  const footerColumn = getFooterColumn(el);
8491
9561
  if (footerColumn) return footerColumn;
8492
- const footerGroup = findFooterItemGroup(el);
9562
+ const footerGroup = findFooterItemGroup2(el);
8493
9563
  if (footerGroup) return footerGroup;
8494
9564
  return getNavigationRoot(el);
8495
9565
  }
8496
- if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup(el)) {
9566
+ if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
9567
+ return getFooterLinksContainer();
9568
+ }
9569
+ if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isFooterLinksContainer(el) || isInferredFooterGroup2(el)) {
8497
9570
  return getNavigationRoot(el);
8498
9571
  }
8499
9572
  return null;
8500
9573
  }
8501
9574
  function collectNavigationItemSiblingHintRects(selected) {
8502
- if (!isNavigationItem(selected)) return [];
9575
+ if (!isNavigationItem2(selected)) return [];
8503
9576
  const footerColumn = getFooterColumn(selected);
8504
9577
  if (footerColumn) {
8505
9578
  return listFooterLinksInColumn(footerColumn).filter((link) => link !== selected).map((link) => link.getBoundingClientRect());
8506
9579
  }
8507
9580
  const navContainer = selected.closest("[data-ohw-nav-container], [data-ohw-nav-drawer]");
8508
9581
  if (navContainer) {
8509
- return Array.from(navContainer.querySelectorAll("[data-ohw-href-key]")).filter((el) => isNavigationItem(el) && el !== selected).map((el) => el.getBoundingClientRect());
9582
+ return Array.from(navContainer.querySelectorAll("[data-ohw-href-key]")).filter((el) => isNavigationItem2(el) && el !== selected).map((el) => el.getBoundingClientRect());
8510
9583
  }
8511
9584
  return listNavigationItems().filter((el) => el !== selected).map((el) => el.getBoundingClientRect());
8512
9585
  }
@@ -8720,7 +9793,7 @@ function EditGlowChrome({
8720
9793
  hideHandle = false
8721
9794
  }) {
8722
9795
  const GAP = SELECTION_CHROME_GAP2;
8723
- return /* @__PURE__ */ jsxs14(
9796
+ return /* @__PURE__ */ jsxs15(
8724
9797
  "div",
8725
9798
  {
8726
9799
  ref: elRef,
@@ -8735,7 +9808,7 @@ function EditGlowChrome({
8735
9808
  zIndex: 2147483646
8736
9809
  },
8737
9810
  children: [
8738
- /* @__PURE__ */ jsx25(
9811
+ /* @__PURE__ */ jsx27(
8739
9812
  "div",
8740
9813
  {
8741
9814
  style: {
@@ -8748,7 +9821,7 @@ function EditGlowChrome({
8748
9821
  }
8749
9822
  }
8750
9823
  ),
8751
- reorderHrefKey && !hideHandle && /* @__PURE__ */ jsx25(
9824
+ reorderHrefKey && !hideHandle && /* @__PURE__ */ jsx27(
8752
9825
  "div",
8753
9826
  {
8754
9827
  "data-ohw-drag-handle-container": "",
@@ -8760,7 +9833,7 @@ function EditGlowChrome({
8760
9833
  transform: "translate(calc(-100% - 7px), -50%)",
8761
9834
  pointerEvents: dragDisabled ? "none" : "auto"
8762
9835
  },
8763
- children: /* @__PURE__ */ jsx25(
9836
+ children: /* @__PURE__ */ jsx27(
8764
9837
  DragHandle,
8765
9838
  {
8766
9839
  "aria-label": `Reorder ${reorderHrefKey}`,
@@ -8970,7 +10043,7 @@ function FloatingToolbar({
8970
10043
  return () => ro.disconnect();
8971
10044
  }, [showEditLink, activeCommands]);
8972
10045
  const { top, left, transform } = calcToolbarPos(rect, parentScroll, measuredW);
8973
- return /* @__PURE__ */ jsx25(
10046
+ return /* @__PURE__ */ jsx27(
8974
10047
  "div",
8975
10048
  {
8976
10049
  ref: setRefs,
@@ -8982,12 +10055,12 @@ function FloatingToolbar({
8982
10055
  zIndex: 2147483647,
8983
10056
  pointerEvents: "auto"
8984
10057
  },
8985
- children: /* @__PURE__ */ jsxs14(CustomToolbar, { children: [
8986
- TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs14(React11.Fragment, { children: [
8987
- gi > 0 && /* @__PURE__ */ jsx25(CustomToolbarDivider, {}),
10058
+ children: /* @__PURE__ */ jsxs15(CustomToolbar, { children: [
10059
+ TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs15(React11.Fragment, { children: [
10060
+ gi > 0 && /* @__PURE__ */ jsx27(CustomToolbarDivider, {}),
8988
10061
  btns.map((btn) => {
8989
10062
  const isActive = activeCommands.has(btn.cmd);
8990
- return /* @__PURE__ */ jsx25(
10063
+ return /* @__PURE__ */ jsx27(
8991
10064
  CustomToolbarButton,
8992
10065
  {
8993
10066
  title: btn.title,
@@ -8996,7 +10069,7 @@ function FloatingToolbar({
8996
10069
  e.preventDefault();
8997
10070
  onCommand(btn.cmd);
8998
10071
  },
8999
- children: /* @__PURE__ */ jsx25(
10072
+ children: /* @__PURE__ */ jsx27(
9000
10073
  "svg",
9001
10074
  {
9002
10075
  width: "16",
@@ -9017,7 +10090,7 @@ function FloatingToolbar({
9017
10090
  );
9018
10091
  })
9019
10092
  ] }, gi)),
9020
- showEditLink ? /* @__PURE__ */ jsx25(
10093
+ showEditLink ? /* @__PURE__ */ jsx27(
9021
10094
  CustomToolbarButton,
9022
10095
  {
9023
10096
  type: "button",
@@ -9031,7 +10104,7 @@ function FloatingToolbar({
9031
10104
  e.preventDefault();
9032
10105
  e.stopPropagation();
9033
10106
  },
9034
- children: /* @__PURE__ */ jsx25(Link2, { className: "size-4 shrink-0", "aria-hidden": true })
10107
+ children: /* @__PURE__ */ jsx27(Link2, { className: "size-4 shrink-0", "aria-hidden": true })
9035
10108
  }
9036
10109
  ) : null
9037
10110
  ] })
@@ -9048,7 +10121,7 @@ function StateToggle({
9048
10121
  states,
9049
10122
  onStateChange
9050
10123
  }) {
9051
- return /* @__PURE__ */ jsx25(
10124
+ return /* @__PURE__ */ jsx27(
9052
10125
  ToggleGroup,
9053
10126
  {
9054
10127
  "data-ohw-state-toggle": "",
@@ -9062,7 +10135,7 @@ function StateToggle({
9062
10135
  left: rect.right - 8,
9063
10136
  transform: "translateX(-100%)"
9064
10137
  },
9065
- children: states.map((state) => /* @__PURE__ */ jsx25(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
10138
+ children: states.map((state) => /* @__PURE__ */ jsx27(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
9066
10139
  }
9067
10140
  );
9068
10141
  }
@@ -9089,7 +10162,7 @@ function OhhwellsBridge() {
9089
10162
  const router = useRouter2();
9090
10163
  const searchParams = useSearchParams();
9091
10164
  const isEditMode = isEditSessionActive();
9092
- const [bridgeRoot, setBridgeRoot] = useState8(null);
10165
+ const [bridgeRoot, setBridgeRoot] = useState9(null);
9093
10166
  useEffect9(() => {
9094
10167
  const figtreeFontId = "ohw-figtree-font";
9095
10168
  if (!document.getElementById(figtreeFontId)) {
@@ -9123,7 +10196,7 @@ function OhhwellsBridge() {
9123
10196
  window.parent.postMessage(data, "*");
9124
10197
  }
9125
10198
  }, []);
9126
- const [fetchState, setFetchState] = useState8("idle");
10199
+ const [fetchState, setFetchState] = useState9("idle");
9127
10200
  const autoSaveTimers = useRef7(/* @__PURE__ */ new Map());
9128
10201
  const activeElRef = useRef7(null);
9129
10202
  const pointerHeldRef = useRef7(false);
@@ -9134,7 +10207,7 @@ function OhhwellsBridge() {
9134
10207
  const activeStateElRef = useRef7(null);
9135
10208
  const parentScrollRef = useRef7(null);
9136
10209
  const visibleViewportRef = useRef7(null);
9137
- const [dialogPortalContainer, setDialogPortalContainer] = useState8(null);
10210
+ const [dialogPortalContainer, setDialogPortalContainer] = useState9(null);
9138
10211
  const attachVisibleViewport = useCallback5((node) => {
9139
10212
  visibleViewportRef.current = node;
9140
10213
  setDialogPortalContainer(node);
@@ -9145,9 +10218,9 @@ function OhhwellsBridge() {
9145
10218
  const hoveredImageRef = useRef7(null);
9146
10219
  const hoveredImageHasTextOverlapRef = useRef7(false);
9147
10220
  const dragOverElRef = useRef7(null);
9148
- const [mediaHover, setMediaHover] = useState8(null);
9149
- const [carouselHover, setCarouselHover] = useState8(null);
9150
- const [uploadingRects, setUploadingRects] = useState8({});
10221
+ const [mediaHover, setMediaHover] = useState9(null);
10222
+ const [carouselHover, setCarouselHover] = useState9(null);
10223
+ const [uploadingRects, setUploadingRects] = useState9({});
9151
10224
  const hoveredGapRef = useRef7(null);
9152
10225
  const imageUnhoverTimerRef = useRef7(null);
9153
10226
  const imageShowTimerRef = useRef7(null);
@@ -9166,46 +10239,51 @@ function OhhwellsBridge() {
9166
10239
  });
9167
10240
  const commitNavigationTextEditRef = useRef7(() => {
9168
10241
  });
10242
+ const handleDeleteSelectedRef = useRef7(() => false);
10243
+ const runPendingDeleteUndoRef = useRef7(() => false);
10244
+ const isFooterFrameSelectionRef = useRef7(false);
9169
10245
  const refreshActiveCommandsRef = useRef7(() => {
9170
10246
  });
9171
10247
  const postToParentRef = useRef7(postToParent2);
9172
10248
  postToParentRef.current = postToParent2;
9173
10249
  const sectionsLoadedRef = useRef7(false);
9174
10250
  const pendingScheduleConfigRequests = useRef7([]);
9175
- const [toolbarRect, setToolbarRect] = useState8(null);
9176
- const [toolbarVariant, setToolbarVariant] = useState8("none");
10251
+ const [toolbarRect, setToolbarRect] = useState9(null);
10252
+ const [toolbarVariant, setToolbarVariant] = useState9("none");
9177
10253
  const toolbarVariantRef = useRef7("none");
9178
10254
  toolbarVariantRef.current = toolbarVariant;
9179
- const [selectedIsCta, setSelectedIsCta] = useState8(false);
9180
- const [reorderHrefKey, setReorderHrefKey] = useState8(null);
9181
- const [reorderDragDisabled, setReorderDragDisabled] = useState8(false);
9182
- const [toggleState, setToggleState] = useState8(null);
9183
- const [maxBadge, setMaxBadge] = useState8(null);
9184
- const [activeCommands, setActiveCommands] = useState8(/* @__PURE__ */ new Set());
9185
- const [sectionGap, setSectionGap] = useState8(null);
9186
- const [toolbarShowEditLink, setToolbarShowEditLink] = useState8(false);
10255
+ const [selectedIsCta, setSelectedIsCta] = useState9(false);
10256
+ const [reorderHrefKey, setReorderHrefKey] = useState9(null);
10257
+ const [reorderDragDisabled, setReorderDragDisabled] = useState9(false);
10258
+ const [toggleState, setToggleState] = useState9(null);
10259
+ const [maxBadge, setMaxBadge] = useState9(null);
10260
+ const [activeCommands, setActiveCommands] = useState9(/* @__PURE__ */ new Set());
10261
+ const [sectionGap, setSectionGap] = useState9(null);
10262
+ const [toolbarShowEditLink, setToolbarShowEditLink] = useState9(false);
9187
10263
  const hoveredNavContainerRef = useRef7(null);
9188
- const [hoveredNavContainerRect, setHoveredNavContainerRect] = useState8(null);
10264
+ const [hoveredNavContainerRect, setHoveredNavContainerRect] = useState9(null);
9189
10265
  const hoveredItemElRef = useRef7(null);
9190
- const [hoveredItemRect, setHoveredItemRect] = useState8(null);
10266
+ const [hoveredItemRect, setHoveredItemRect] = useState9(null);
9191
10267
  const siblingHintElRef = useRef7(null);
9192
- const [siblingHintRect, setSiblingHintRect] = useState8(null);
9193
- const [siblingHintRects, setSiblingHintRects] = useState8([]);
9194
- const [isItemDragging, setIsItemDragging] = useState8(false);
9195
- const [isFooterFrameSelection, setIsFooterFrameSelection] = useState8(false);
10268
+ const [siblingHintRect, setSiblingHintRect] = useState9(null);
10269
+ const [siblingHintRects, setSiblingHintRects] = useState9([]);
10270
+ const [isItemDragging, setIsItemDragging] = useState9(false);
10271
+ const [isFooterFrameSelection, setIsFooterFrameSelection] = useState9(false);
10272
+ isFooterFrameSelectionRef.current = isFooterFrameSelection;
9196
10273
  const footerDragRef = useRef7(null);
9197
- const [footerDropSlots, setFooterDropSlots] = useState8([]);
9198
- const [activeFooterDropIndex, setActiveFooterDropIndex] = useState8(null);
9199
- const [draggedItemRect, setDraggedItemRect] = useState8(null);
10274
+ const [footerDropSlots, setFooterDropSlots] = useState9([]);
10275
+ const [activeFooterDropIndex, setActiveFooterDropIndex] = useState9(null);
10276
+ const [draggedItemRect, setDraggedItemRect] = useState9(null);
9200
10277
  const footerPointerDragRef = useRef7(null);
9201
10278
  const suppressNextClickRef = useRef7(false);
9202
10279
  const suppressClickUntilRef = useRef7(0);
9203
- const [linkPopover, setLinkPopover] = useState8(null);
10280
+ const [linkPopover, setLinkPopover] = useState9(null);
9204
10281
  const linkPopoverSessionRef = useRef7(null);
9205
10282
  const addNavAfterAnchorRef = useRef7(null);
9206
10283
  const editContentRef = useRef7({});
9207
- const [sitePages, setSitePages] = useState8([]);
9208
- const [sectionsByPath, setSectionsByPath] = useState8({});
10284
+ const pendingDeleteUndoRef = useRef7(null);
10285
+ const [sitePages, setSitePages] = useState9([]);
10286
+ const [sectionsByPath, setSectionsByPath] = useState9({});
9209
10287
  const sectionsPrefetchGenRef = useRef7(0);
9210
10288
  const setLinkPopoverRef = useRef7(setLinkPopover);
9211
10289
  const linkPopoverPanelRef = useRef7(null);
@@ -9293,31 +10371,9 @@ function OhhwellsBridge() {
9293
10371
  hoveredGapRef.current = null;
9294
10372
  setSectionGap(null);
9295
10373
  setMediaHover(null);
9296
- postToParent2({ type: "ow:link-modal-lock", locked: true });
9297
- const html = document.documentElement;
9298
- const body = document.body;
9299
- const prevHtmlOverflow = html.style.overflow;
9300
- const prevBodyOverflow = body.style.overflow;
9301
- html.style.overflow = "hidden";
9302
- body.style.overflow = "hidden";
9303
- const preventBackgroundScroll = (e) => {
9304
- const target = e.target;
9305
- if (target instanceof Element && target.closest('[data-ohw-link-modal-root], [data-slot="dialog-overlay"]')) {
9306
- return;
9307
- }
9308
- e.preventDefault();
9309
- };
9310
- const scrollOpts = { passive: false, capture: true };
9311
- document.addEventListener("wheel", preventBackgroundScroll, scrollOpts);
9312
- document.addEventListener("touchmove", preventBackgroundScroll, scrollOpts);
9313
10374
  postToParent2({ type: "ow:image-unhover" });
9314
10375
  return () => {
9315
10376
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
9316
- postToParent2({ type: "ow:link-modal-lock", locked: false });
9317
- html.style.overflow = prevHtmlOverflow;
9318
- body.style.overflow = prevBodyOverflow;
9319
- document.removeEventListener("wheel", preventBackgroundScroll, scrollOpts);
9320
- document.removeEventListener("touchmove", preventBackgroundScroll, scrollOpts);
9321
10377
  };
9322
10378
  }, [linkPopover, postToParent2]);
9323
10379
  useEffect9(() => {
@@ -9481,7 +10537,7 @@ function OhhwellsBridge() {
9481
10537
  const hrefKey = selectedHrefKeyRef.current;
9482
10538
  if (hrefKey) {
9483
10539
  const link = resolveHrefKeyElement(hrefKey);
9484
- if (!link || !isNavigationItem(link)) return;
10540
+ if (!link || !isNavigationItem2(link)) return;
9485
10541
  selectedElRef.current = link;
9486
10542
  const { key, disabled } = getNavigationItemReorderState(link);
9487
10543
  setReorderHrefKey(key);
@@ -9559,6 +10615,27 @@ function OhhwellsBridge() {
9559
10615
  intent: "add-nav"
9560
10616
  });
9561
10617
  }, []);
10618
+ const handleAddFooterColumn = useCallback5(() => {
10619
+ if (!canAddFooterColumn()) {
10620
+ postToParent2({
10621
+ type: "ow:toast",
10622
+ title: `Maximum ${MAX_FOOTER_COLUMNS} columns`,
10623
+ toastType: "error"
10624
+ });
10625
+ return;
10626
+ }
10627
+ deselectRef.current();
10628
+ deactivateRef.current();
10629
+ const result = addFooterColumnWithPersist({ postToParent: postToParent2 });
10630
+ if (!result) return;
10631
+ editContentRef.current = {
10632
+ ...editContentRef.current,
10633
+ ...buildFooterColumnEditContentPatch(result)
10634
+ };
10635
+ requestAnimationFrame(() => {
10636
+ selectRef.current(result.firstLink);
10637
+ });
10638
+ }, [postToParent2]);
9562
10639
  const clearFooterDragVisuals = useCallback5(() => {
9563
10640
  footerDragRef.current = null;
9564
10641
  setSiblingHintRects([]);
@@ -9653,7 +10730,7 @@ function OhhwellsBridge() {
9653
10730
  selectedHrefKeyRef.current = hrefKey;
9654
10731
  selectedFooterColAttrRef.current = null;
9655
10732
  const link = resolveHrefKeyElement(hrefKey);
9656
- if (link && isNavigationItem(link)) {
10733
+ if (link && isNavigationItem2(link)) {
9657
10734
  selectRef.current(link);
9658
10735
  return;
9659
10736
  }
@@ -9677,7 +10754,7 @@ function OhhwellsBridge() {
9677
10754
  }
9678
10755
  }
9679
10756
  if (document.body.contains(draggedEl)) {
9680
- if (isNavigationItem(draggedEl)) {
10757
+ if (isNavigationItem2(draggedEl)) {
9681
10758
  selectRef.current(draggedEl);
9682
10759
  return;
9683
10760
  }
@@ -9774,7 +10851,7 @@ function OhhwellsBridge() {
9774
10851
  const clientX = e?.clientX ?? selected.getBoundingClientRect().left + 8;
9775
10852
  const clientY = e?.clientY ?? selected.getBoundingClientRect().top + 8;
9776
10853
  if (startFooterLinkDrag(selected, clientX, clientY, true)) return;
9777
- if (selected.hasAttribute("data-ohw-footer-col") || isInferredFooterGroup(selected) && selected.closest("footer")) {
10854
+ if (selected.hasAttribute("data-ohw-footer-col") || isInferredFooterGroup2(selected) && selected.closest("footer")) {
9778
10855
  if (startFooterColumnDrag(selected, clientX, clientY, true)) return;
9779
10856
  }
9780
10857
  if (startNavLinkDrag(selected, clientX, clientY, true)) return;
@@ -9827,7 +10904,7 @@ function OhhwellsBridge() {
9827
10904
  };
9828
10905
  return;
9829
10906
  }
9830
- if (selected.hasAttribute("data-ohw-footer-col") || isInferredFooterGroup(selected) && selected.closest("footer")) {
10907
+ if (selected.hasAttribute("data-ohw-footer-col") || isInferredFooterGroup2(selected) && selected.closest("footer")) {
9831
10908
  footerPointerDragRef.current = {
9832
10909
  el: selected,
9833
10910
  kind: "column",
@@ -9847,7 +10924,7 @@ function OhhwellsBridge() {
9847
10924
  return;
9848
10925
  }
9849
10926
  const selected = selectedElRef.current;
9850
- if (!selected || !isNavigationItem(selected)) return;
10927
+ if (!selected || !isNavigationItem2(selected)) return;
9851
10928
  const editable = selected.querySelector('[data-ohw-editable="text"]') ?? selected.querySelector("[data-ohw-editable]");
9852
10929
  if (!editable) return;
9853
10930
  activateRef.current(editable, { caretX: clientX, caretY: clientY });
@@ -9855,7 +10932,7 @@ function OhhwellsBridge() {
9855
10932
  reselectNavigationItemRef.current = reselectNavigationItem;
9856
10933
  commitNavigationTextEditRef.current = commitNavigationTextEdit;
9857
10934
  const select = useCallback5((anchor) => {
9858
- if (!isNavigationItem(anchor)) return;
10935
+ if (!isNavigationItem2(anchor)) return;
9859
10936
  if (activeElRef.current) deactivate();
9860
10937
  selectedElRef.current = anchor;
9861
10938
  selectedHrefKeyRef.current = anchor.getAttribute("data-ohw-href-key");
@@ -9883,7 +10960,7 @@ function OhhwellsBridge() {
9883
10960
  const selectFrame = useCallback5((el) => {
9884
10961
  if (!isNavigationContainer(el)) return;
9885
10962
  if (activeElRef.current) deactivate();
9886
- const isFooterColumn = el.hasAttribute("data-ohw-footer-col") || Boolean(el.closest("footer") && isInferredFooterGroup(el));
10963
+ const isFooterColumn = !isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || Boolean(el.closest("footer") && isInferredFooterGroup2(el)));
9887
10964
  selectedElRef.current = el;
9888
10965
  selectedHrefKeyRef.current = null;
9889
10966
  selectedFooterColAttrRef.current = isFooterColumn ? el.getAttribute("data-ohw-footer-col") ?? String(listFooterColumns().indexOf(el)) : null;
@@ -9998,7 +11075,7 @@ function OhhwellsBridge() {
9998
11075
  const next = `url('${val}')`;
9999
11076
  if (el.style.backgroundImage !== next) el.style.backgroundImage = next;
10000
11077
  } else if (el.dataset.ohwEditable === "video") {
10001
- const video = getVideoEl(el);
11078
+ const video = getVideoEl2(el);
10002
11079
  if (video && video.src !== val) {
10003
11080
  applyVideoSrc(video, val);
10004
11081
  imageLoads.push(new Promise((resolve) => {
@@ -10066,7 +11143,7 @@ function OhhwellsBridge() {
10066
11143
  const next = `url('${val}')`;
10067
11144
  if (el.style.backgroundImage !== next) el.style.backgroundImage = next;
10068
11145
  } else if (el.dataset.ohwEditable === "video") {
10069
- const video = getVideoEl(el);
11146
+ const video = getVideoEl2(el);
10070
11147
  if (video && video.src !== val) applyVideoSrc(video, val);
10071
11148
  } else if (el.dataset.ohwEditable === "link") {
10072
11149
  applyLinkHref(el, val);
@@ -10351,7 +11428,7 @@ function OhhwellsBridge() {
10351
11428
  e.preventDefault();
10352
11429
  e.stopPropagation();
10353
11430
  const selected = selectedElRef.current;
10354
- if (selected && isNavigationItem(selected)) {
11431
+ if (selected && isNavigationItem2(selected)) {
10355
11432
  const editable2 = selected.querySelector('[data-ohw-editable="text"]') ?? selected.querySelector("[data-ohw-editable]");
10356
11433
  if (editable2) {
10357
11434
  activateRef.current(editable2, {
@@ -10416,7 +11493,7 @@ function OhhwellsBridge() {
10416
11493
  setLinkPopoverRef.current({
10417
11494
  key: editable.dataset.ohwKey ?? "",
10418
11495
  mode: "edit",
10419
- target: getLinkHref2(editable)
11496
+ target: getLinkHref4(editable)
10420
11497
  });
10421
11498
  return;
10422
11499
  }
@@ -10441,7 +11518,7 @@ function OhhwellsBridge() {
10441
11518
  }
10442
11519
  e.preventDefault();
10443
11520
  e.stopPropagation();
10444
- activateRef.current(editable);
11521
+ activateRef.current(editable, { caretX: e.clientX, caretY: e.clientY });
10445
11522
  return;
10446
11523
  }
10447
11524
  const hrefAnchor = getNavigationItemAnchor(target);
@@ -10468,6 +11545,18 @@ function OhhwellsBridge() {
10468
11545
  selectFrameRef.current(footerColClick);
10469
11546
  return;
10470
11547
  }
11548
+ const footerLinksToSelect = resolveFooterLinksContainerSelectionTarget(
11549
+ target,
11550
+ e.clientX,
11551
+ e.clientY,
11552
+ isPointOverNavItem
11553
+ );
11554
+ if (footerLinksToSelect) {
11555
+ e.preventDefault();
11556
+ e.stopPropagation();
11557
+ selectFrameRef.current(footerLinksToSelect);
11558
+ return;
11559
+ }
10471
11560
  const navContainerToSelect = resolveNavContainerSelectionTarget(target, e.clientX, e.clientY);
10472
11561
  if (navContainerToSelect) {
10473
11562
  e.preventDefault();
@@ -10526,8 +11615,8 @@ function OhhwellsBridge() {
10526
11615
  return;
10527
11616
  }
10528
11617
  const navLabel = getNavigationLabelEditable(target);
10529
- if (!navLabel) return;
10530
- const { editable } = navLabel;
11618
+ const editable = navLabel?.editable ?? target.closest('[data-ohw-editable="text"], [data-ohw-editable="plain"]');
11619
+ if (!editable || isMediaEditable(editable) || editable.dataset.ohwEditable === "link") return;
10531
11620
  e.preventDefault();
10532
11621
  e.stopPropagation();
10533
11622
  if (activeElRef.current !== editable) {
@@ -10548,16 +11637,38 @@ function OhhwellsBridge() {
10548
11637
  setHoveredNavContainerRect(null);
10549
11638
  return;
10550
11639
  }
10551
- if (toolbarVariantRef.current !== "select-frame") {
10552
- const navContainer = target.closest("[data-ohw-nav-container]");
10553
- if (navContainer && !getNavigationItemAnchor(target)) {
10554
- hoveredNavContainerRef.current = navContainer;
10555
- setHoveredNavContainerRect(navContainer.getBoundingClientRect());
10556
- hoveredItemElRef.current = null;
10557
- setHoveredItemRect(null);
10558
- return;
11640
+ {
11641
+ const selected2 = selectedElRef.current;
11642
+ const selectedIsFooterColumn = Boolean(selected2) && !isFooterLinksContainer(selected2) && (selected2.hasAttribute("data-ohw-footer-col") || selected2.hasAttribute("data-ohw-footer-column") || Boolean(selected2.closest("footer") && isInferredFooterGroup2(selected2)));
11643
+ const allowNavContainerHover = toolbarVariantRef.current !== "select-frame";
11644
+ const allowFooterLinksHover = toolbarVariantRef.current !== "select-frame" || selectedIsFooterColumn;
11645
+ if (allowNavContainerHover) {
11646
+ const navContainer = target.closest("[data-ohw-nav-container]");
11647
+ if (navContainer && !getNavigationItemAnchor(target)) {
11648
+ hoveredNavContainerRef.current = navContainer;
11649
+ setHoveredNavContainerRect(navContainer.getBoundingClientRect());
11650
+ hoveredItemElRef.current = null;
11651
+ setHoveredItemRect(null);
11652
+ return;
11653
+ }
10559
11654
  }
10560
- if (!target.closest("[data-ohw-nav-container]")) {
11655
+ if (allowFooterLinksHover) {
11656
+ const navContainer = target.closest("[data-ohw-nav-container]");
11657
+ if (!navContainer) {
11658
+ const footerLinks = target.closest("[data-ohw-footer-links], .rb-footer-links") ?? null;
11659
+ if (footerLinks && selected2 !== footerLinks && !getNavigationItemAnchor(target) && !target.closest("[data-ohw-footer-col], [data-ohw-footer-column]")) {
11660
+ hoveredNavContainerRef.current = footerLinks;
11661
+ setHoveredNavContainerRect(footerLinks.getBoundingClientRect());
11662
+ hoveredItemElRef.current = null;
11663
+ setHoveredItemRect(null);
11664
+ return;
11665
+ }
11666
+ if (!footerLinks) {
11667
+ hoveredNavContainerRef.current = null;
11668
+ setHoveredNavContainerRect(null);
11669
+ }
11670
+ }
11671
+ } else if (toolbarVariantRef.current === "select-frame") {
10561
11672
  hoveredNavContainerRef.current = null;
10562
11673
  setHoveredNavContainerRect(null);
10563
11674
  }
@@ -10599,9 +11710,9 @@ function OhhwellsBridge() {
10599
11710
  };
10600
11711
  const handleMouseOut = (e) => {
10601
11712
  const target = e.target;
10602
- if (target.closest("[data-ohw-nav-container], [data-ohw-footer-col], [data-ohw-footer-column]")) {
11713
+ if (target.closest("[data-ohw-nav-container], [data-ohw-footer-col], [data-ohw-footer-column], [data-ohw-footer-links], .rb-footer-links")) {
10603
11714
  const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
10604
- 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]")) {
11715
+ 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]")) {
10605
11716
  return;
10606
11717
  }
10607
11718
  hoveredNavContainerRef.current = null;
@@ -10683,7 +11794,7 @@ function OhhwellsBridge() {
10683
11794
  const r2 = getVisibleRect(imgEl);
10684
11795
  const hasTextOverlap = forceTextOverlap ?? false;
10685
11796
  hoveredImageHasTextOverlapRef.current = hasTextOverlap;
10686
- const video = imgEl.dataset.ohwEditable === "video" ? getVideoEl(imgEl) : null;
11797
+ const video = imgEl.dataset.ohwEditable === "video" ? getVideoEl2(imgEl) : null;
10687
11798
  setMediaHover({
10688
11799
  key: imgEl.dataset.ohwKey ?? "",
10689
11800
  rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height },
@@ -10696,6 +11807,15 @@ function OhhwellsBridge() {
10696
11807
  if (track) track.setAttribute("data-ohw-hover-paused", "");
10697
11808
  };
10698
11809
  const clearImageHover = () => setMediaHover(null);
11810
+ const dismissImageHover = () => {
11811
+ if (hoveredImageRef.current) {
11812
+ hoveredImageRef.current = null;
11813
+ hoveredImageHasTextOverlapRef.current = false;
11814
+ resumeAnimTracks();
11815
+ postToParentRef.current({ type: "ow:image-unhover" });
11816
+ }
11817
+ clearImageHover();
11818
+ };
10699
11819
  const findImageAtPoint = (clientX, clientY, fromParentViewport) => {
10700
11820
  const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
10701
11821
  const images = Array.from(document.querySelectorAll(MEDIA_SELECTOR));
@@ -10739,16 +11859,13 @@ function OhhwellsBridge() {
10739
11859
  }
10740
11860
  return smallest;
10741
11861
  };
10742
- const dismissImageHover = () => {
10743
- if (hoveredImageRef.current) {
10744
- hoveredImageRef.current = null;
10745
- hoveredImageHasTextOverlapRef.current = false;
10746
- resumeAnimTracks();
10747
- postToParentRef.current({ type: "ow:image-unhover" });
10748
- }
10749
- };
10750
11862
  const probeNavigationHoverAt = (x, y) => {
10751
- if (toolbarVariantRef.current === "select-frame") {
11863
+ const selected = selectedElRef.current;
11864
+ const selectedIsFooterColumn = Boolean(selected) && !isFooterLinksContainer(selected) && (selected.hasAttribute("data-ohw-footer-col") || selected.hasAttribute("data-ohw-footer-column") || Boolean(selected.closest("footer") && isInferredFooterGroup2(selected)));
11865
+ const selectedIsFooterLinks = Boolean(selected && isFooterLinksContainer(selected));
11866
+ const allowNavContainerHover = toolbarVariantRef.current !== "select-frame";
11867
+ const allowFooterLinksHover = (toolbarVariantRef.current !== "select-frame" || selectedIsFooterColumn) && !selectedIsFooterLinks;
11868
+ if (toolbarVariantRef.current === "select-frame" && !allowFooterLinksHover) {
10752
11869
  hoveredNavContainerRef.current = null;
10753
11870
  setHoveredNavContainerRect(null);
10754
11871
  }
@@ -10763,14 +11880,13 @@ function OhhwellsBridge() {
10763
11880
  const navItemHit = Array.from(
10764
11881
  container.querySelectorAll("[data-ohw-href-key]")
10765
11882
  ).find((el) => {
10766
- if (!isNavigationItem(el) || isNavbarButton2(el)) return false;
11883
+ if (!isNavigationItem2(el) || isNavbarButton2(el)) return false;
10767
11884
  const itemRect = el.getBoundingClientRect();
10768
11885
  return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
10769
11886
  });
10770
11887
  if (navItemHit) {
10771
11888
  hoveredNavContainerRef.current = null;
10772
11889
  setHoveredNavContainerRect(null);
10773
- const selected = selectedElRef.current;
10774
11890
  if (selected !== navItemHit) {
10775
11891
  clearHrefKeyHover(navItemHit);
10776
11892
  hoveredItemElRef.current = navItemHit;
@@ -10782,7 +11898,7 @@ function OhhwellsBridge() {
10782
11898
  return;
10783
11899
  }
10784
11900
  }
10785
- if (toolbarVariantRef.current !== "select-frame") {
11901
+ if (allowNavContainerHover) {
10786
11902
  for (const container of navContainers) {
10787
11903
  const containerRect = container.getBoundingClientRect();
10788
11904
  const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
@@ -10794,12 +11910,23 @@ function OhhwellsBridge() {
10794
11910
  setHoveredItemRect(null);
10795
11911
  return;
10796
11912
  }
10797
- hoveredNavContainerRef.current = null;
10798
- setHoveredNavContainerRect(null);
10799
- } else {
10800
- hoveredNavContainerRef.current = null;
10801
- setHoveredNavContainerRect(null);
10802
11913
  }
11914
+ if (allowFooterLinksHover) {
11915
+ const footerLinks = getFooterLinksContainer();
11916
+ if (footerLinks) {
11917
+ const containerRect = footerLinks.getBoundingClientRect();
11918
+ const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
11919
+ if (overContainer && !isPointOverNavItem(footerLinks, x, y) && !isPointOverFooterColumn(x, y)) {
11920
+ hoveredNavContainerRef.current = footerLinks;
11921
+ setHoveredNavContainerRect(footerLinks.getBoundingClientRect());
11922
+ hoveredItemElRef.current = null;
11923
+ setHoveredItemRect(null);
11924
+ return;
11925
+ }
11926
+ }
11927
+ }
11928
+ hoveredNavContainerRef.current = null;
11929
+ setHoveredNavContainerRect(null);
10803
11930
  for (const column of footerColumns) {
10804
11931
  const containerRect = column.getBoundingClientRect();
10805
11932
  const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
@@ -10838,6 +11965,13 @@ function OhhwellsBridge() {
10838
11965
  probeNavigationHoverAt(x, y);
10839
11966
  return;
10840
11967
  }
11968
+ const overMoreMenu = document.elementFromPoint(x, y)?.closest?.(
11969
+ '[data-ohw-more-menu], [data-slot="dropdown-menu-content"], [data-slot="dropdown-menu-item"]'
11970
+ );
11971
+ if (overMoreMenu) {
11972
+ dismissImageHover();
11973
+ return;
11974
+ }
10841
11975
  hoveredNavContainerRef.current = null;
10842
11976
  setHoveredNavContainerRect(null);
10843
11977
  if (hoveredItemElRef.current?.hasAttribute("data-ohw-footer-col") || hoveredItemElRef.current?.hasAttribute("data-ohw-footer-column")) {
@@ -10884,7 +12018,7 @@ function OhhwellsBridge() {
10884
12018
  return;
10885
12019
  }
10886
12020
  const topEl = document.elementFromPoint(x2, y2);
10887
- if (topEl?.closest('[data-ohw-toolbar], [data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
12021
+ 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"]')) {
10888
12022
  if (hoveredImageRef.current) {
10889
12023
  hoveredImageRef.current = null;
10890
12024
  resumeAnimTracks();
@@ -11204,7 +12338,7 @@ function OhhwellsBridge() {
11204
12338
  }
11205
12339
  }
11206
12340
  } else if (el.dataset.ohwEditable === "video") {
11207
- const video = getVideoEl(el);
12341
+ const video = getVideoEl2(el);
11208
12342
  if (video) {
11209
12343
  found = true;
11210
12344
  const onReady = () => {
@@ -11291,7 +12425,7 @@ function OhhwellsBridge() {
11291
12425
  } else if (el.dataset.ohwEditable === "bg-image") {
11292
12426
  el.style.backgroundImage = `url('${val}')`;
11293
12427
  } else if (el.dataset.ohwEditable === "video") {
11294
- const video = getVideoEl(el);
12428
+ const video = getVideoEl2(el);
11295
12429
  if (video && video.src !== val) applyVideoSrc(video, val);
11296
12430
  } else if (el.dataset.ohwEditable === "link") {
11297
12431
  applyLinkHref(el, val);
@@ -11308,6 +12442,7 @@ function OhhwellsBridge() {
11308
12442
  }
11309
12443
  editContentRef.current = { ...editContentRef.current, ...content };
11310
12444
  reconcileNavbarItemsFromContent(editContentRef.current);
12445
+ reconcileFooterOrderFromContent(editContentRef.current);
11311
12446
  syncNavigationDragCursorAttrs();
11312
12447
  enforceLinkHrefs();
11313
12448
  postToParentRef.current({ type: "ow:hydrate-done" });
@@ -11325,8 +12460,17 @@ function OhhwellsBridge() {
11325
12460
  deactivateRef.current();
11326
12461
  };
11327
12462
  window.addEventListener("message", handleDeactivate);
12463
+ const handleToastAction = (e) => {
12464
+ if (e.data?.type !== "ow:toast-action") return;
12465
+ const actionId = typeof e.data.actionId === "string" ? e.data.actionId : null;
12466
+ const pending = pendingDeleteUndoRef.current;
12467
+ if (!pending || !actionId || pending.actionId !== actionId) return;
12468
+ runPendingDeleteUndoRef.current();
12469
+ };
12470
+ window.addEventListener("message", handleToastAction);
11328
12471
  const handleUiEscape = (e) => {
11329
12472
  if (e.data?.type !== "ui:escape") return;
12473
+ if (document.querySelector("[data-ohw-more-menu]")) return;
11330
12474
  if (linkPopoverOpenRef.current) {
11331
12475
  setLinkPopoverRef.current(null);
11332
12476
  return;
@@ -11362,6 +12506,11 @@ function OhhwellsBridge() {
11362
12506
  }
11363
12507
  if (selectedElRef.current) {
11364
12508
  if (toolbarVariantRef.current === "select-frame") {
12509
+ const parent2 = getNavigationSelectionParent(selectedElRef.current);
12510
+ if (parent2 && isNavigationContainer(parent2) && isFooterLinksContainer(parent2) && !isFooterLinksContainer(selectedElRef.current)) {
12511
+ selectFrameRef.current(parent2);
12512
+ return;
12513
+ }
11365
12514
  deselectRef.current();
11366
12515
  return;
11367
12516
  }
@@ -11376,14 +12525,12 @@ function OhhwellsBridge() {
11376
12525
  window.addEventListener("message", handleUiEscape);
11377
12526
  const handleKeyDown = (e) => {
11378
12527
  if (e.key === "Escape" && document.querySelector("[data-ohw-section-picker]")) return;
12528
+ if (e.key === "Escape" && document.querySelector("[data-ohw-more-menu]")) return;
11379
12529
  if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a" && activeElRef.current) {
11380
- const navAnchor = getNavigationItemAnchor(activeElRef.current);
11381
- if (navAnchor) {
11382
- e.preventDefault();
11383
- selectAllTextInEditable(activeElRef.current);
11384
- refreshActiveCommandsRef.current();
11385
- return;
11386
- }
12530
+ e.preventDefault();
12531
+ selectAllTextInEditable(activeElRef.current);
12532
+ refreshActiveCommandsRef.current();
12533
+ return;
11387
12534
  }
11388
12535
  if (e.key === "Escape" && linkPopoverOpenRef.current) {
11389
12536
  setLinkPopoverRef.current(null);
@@ -11391,6 +12538,12 @@ function OhhwellsBridge() {
11391
12538
  }
11392
12539
  if (e.key === "Escape" && selectedElRef.current && !activeElRef.current) {
11393
12540
  if (toolbarVariantRef.current === "select-frame") {
12541
+ const parent2 = getNavigationSelectionParent(selectedElRef.current);
12542
+ if (parent2 && isNavigationContainer(parent2) && isFooterLinksContainer(parent2) && !isFooterLinksContainer(selectedElRef.current)) {
12543
+ e.preventDefault();
12544
+ selectFrameRef.current(parent2);
12545
+ return;
12546
+ }
11394
12547
  deselectRef.current();
11395
12548
  return;
11396
12549
  }
@@ -11431,6 +12584,18 @@ function OhhwellsBridge() {
11431
12584
  return;
11432
12585
  }
11433
12586
  }
12587
+ if ((e.key === "Delete" || e.key === "Backspace") && selectedElRef.current && !activeElRef.current && !linkPopoverOpenRef.current) {
12588
+ if (handleDeleteSelectedRef.current()) {
12589
+ e.preventDefault();
12590
+ return;
12591
+ }
12592
+ }
12593
+ if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "z" && !activeElRef.current) {
12594
+ if (runPendingDeleteUndoRef.current()) {
12595
+ e.preventDefault();
12596
+ return;
12597
+ }
12598
+ }
11434
12599
  if (e.key !== "Escape") return;
11435
12600
  const el = activeElRef.current;
11436
12601
  if (el && originalContentRef.current !== null) {
@@ -11467,11 +12632,11 @@ function OhhwellsBridge() {
11467
12632
  }
11468
12633
  const selected = selectedElRef.current;
11469
12634
  if (selected && !footerDragRef.current && !navDragRef.current) {
11470
- if (selected.hasAttribute("data-ohw-footer-col") || Boolean(selected.closest("footer") && isInferredFooterGroup(selected))) {
12635
+ if (selected.hasAttribute("data-ohw-footer-col") || Boolean(selected.closest("footer") && isInferredFooterGroup2(selected))) {
11471
12636
  setSiblingHintRects(
11472
12637
  listFooterColumns().filter((column) => column !== selected).map((column) => column.getBoundingClientRect())
11473
12638
  );
11474
- } else if (isNavigationItem(selected)) {
12639
+ } else if (isNavigationItem2(selected)) {
11475
12640
  setSiblingHintRects(collectNavigationItemSiblingHintRects(selected));
11476
12641
  }
11477
12642
  }
@@ -11833,6 +12998,7 @@ function OhhwellsBridge() {
11833
12998
  window.removeEventListener("message", handleClickAt);
11834
12999
  window.removeEventListener("message", handleHydrate);
11835
13000
  window.removeEventListener("message", handleDeactivate);
13001
+ window.removeEventListener("message", handleToastAction);
11836
13002
  window.removeEventListener("message", handleUiEscape);
11837
13003
  autoSaveTimers.current.forEach(clearTimeout);
11838
13004
  autoSaveTimers.current.clear();
@@ -12111,7 +13277,7 @@ function OhhwellsBridge() {
12111
13277
  setLinkPopover({
12112
13278
  key: hrefCtx.key,
12113
13279
  mode: "edit",
12114
- target: getLinkHref2(hrefCtx.anchor)
13280
+ target: getLinkHref4(hrefCtx.anchor)
12115
13281
  });
12116
13282
  deactivate();
12117
13283
  }, [deactivate]);
@@ -12124,10 +13290,141 @@ function OhhwellsBridge() {
12124
13290
  setLinkPopover({
12125
13291
  key,
12126
13292
  mode: "edit",
12127
- target: getLinkHref2(anchor)
13293
+ target: getLinkHref4(anchor)
12128
13294
  });
12129
13295
  deselect();
12130
13296
  }, [deselect]);
13297
+ const handleSelectParent = useCallback5(() => {
13298
+ const selected = selectedElRef.current;
13299
+ if (!selected) return;
13300
+ if (toolbarVariantRef.current === "select-frame") {
13301
+ const parent2 = getNavigationSelectionParent(selected);
13302
+ if (parent2 && isNavigationContainer(parent2) && isFooterLinksContainer(parent2) && !isFooterLinksContainer(selected)) {
13303
+ selectFrameRef.current(parent2);
13304
+ return;
13305
+ }
13306
+ deselectRef.current();
13307
+ return;
13308
+ }
13309
+ const parent = getNavigationSelectionParent(selected);
13310
+ if (parent && isNavigationContainer(parent)) {
13311
+ selectFrameRef.current(parent);
13312
+ } else {
13313
+ deselectRef.current();
13314
+ }
13315
+ }, []);
13316
+ const handleDuplicateSelected = useCallback5(() => {
13317
+ const selected = selectedElRef.current;
13318
+ if (!selected || !isNavigationItem2(selected)) return;
13319
+ const hrefKey = selected.getAttribute("data-ohw-href-key");
13320
+ if (!hrefKey) return;
13321
+ if (isNavbarHrefKey(hrefKey)) {
13322
+ const result = duplicateNavbarItem(selected);
13323
+ if (!result) return;
13324
+ applyLinkByKey(result.hrefKey, result.href);
13325
+ document.querySelectorAll(`[data-ohw-key="${result.labelKey}"]`).forEach((el) => {
13326
+ el.textContent = result.label;
13327
+ });
13328
+ const nodes = [
13329
+ { key: result.hrefKey, text: result.href },
13330
+ { key: result.labelKey, text: result.label }
13331
+ ];
13332
+ for (const child of result.childResults) {
13333
+ applyLinkByKey(child.hrefKey, child.href);
13334
+ document.querySelectorAll(`[data-ohw-key="${child.labelKey}"]`).forEach((el) => {
13335
+ el.textContent = child.label;
13336
+ });
13337
+ nodes.push(
13338
+ { key: child.hrefKey, text: child.href },
13339
+ { key: child.labelKey, text: child.label }
13340
+ );
13341
+ }
13342
+ const maxIndex = Math.max(
13343
+ result.index,
13344
+ ...result.childResults.map((c) => c.index)
13345
+ );
13346
+ const navCount = String(maxIndex + 1);
13347
+ nodes.push(
13348
+ { key: NAV_COUNT_KEY, text: navCount },
13349
+ { key: NAV_ORDER_KEY, text: result.orderJson }
13350
+ );
13351
+ editContentRef.current = {
13352
+ ...editContentRef.current,
13353
+ [result.hrefKey]: result.href,
13354
+ [result.labelKey]: result.label,
13355
+ ...Object.fromEntries(
13356
+ result.childResults.flatMap((c) => [
13357
+ [c.hrefKey, c.href],
13358
+ [c.labelKey, c.label]
13359
+ ])
13360
+ ),
13361
+ [NAV_COUNT_KEY]: navCount,
13362
+ [NAV_ORDER_KEY]: result.orderJson
13363
+ };
13364
+ postToParent2({ type: "ow:change", nodes });
13365
+ enforceLinkHrefs();
13366
+ requestAnimationFrame(() => {
13367
+ selectRef.current(result.anchor);
13368
+ });
13369
+ return;
13370
+ }
13371
+ if (isFooterHrefKey(hrefKey)) {
13372
+ const result = duplicateFooterItem(selected);
13373
+ if (!result) return;
13374
+ applyLinkByKey(result.hrefKey, result.href);
13375
+ document.querySelectorAll(`[data-ohw-key="${result.labelKey}"]`).forEach((el) => {
13376
+ el.textContent = result.label;
13377
+ });
13378
+ const orderJson = JSON.stringify(result.order);
13379
+ editContentRef.current = {
13380
+ ...editContentRef.current,
13381
+ [result.hrefKey]: result.href,
13382
+ [result.labelKey]: result.label,
13383
+ [FOOTER_ORDER_KEY]: orderJson
13384
+ };
13385
+ postToParent2({
13386
+ type: "ow:change",
13387
+ nodes: [
13388
+ { key: result.hrefKey, text: result.href },
13389
+ { key: result.labelKey, text: result.label },
13390
+ { key: FOOTER_ORDER_KEY, text: orderJson }
13391
+ ]
13392
+ });
13393
+ enforceLinkHrefs();
13394
+ requestAnimationFrame(() => {
13395
+ selectRef.current(result.anchor);
13396
+ });
13397
+ }
13398
+ }, [postToParent2]);
13399
+ const runPendingDeleteUndo = useCallback5(() => {
13400
+ const pending = pendingDeleteUndoRef.current;
13401
+ if (!pending) return false;
13402
+ pendingDeleteUndoRef.current = null;
13403
+ pending.restore();
13404
+ enforceLinkHrefs();
13405
+ return true;
13406
+ }, []);
13407
+ const handleDeleteSelected = useCallback5(() => {
13408
+ const selected = selectedElRef.current;
13409
+ if (!selected) return false;
13410
+ return deleteSelectedNavFooterItem({
13411
+ selected,
13412
+ isTextEditing: Boolean(activeElRef.current),
13413
+ isSelectFrame: toolbarVariantRef.current === "select-frame",
13414
+ getEditContent: () => editContentRef.current,
13415
+ applyLinkByKey,
13416
+ postToParent: postToParent2,
13417
+ deselect: () => deselectRef.current(),
13418
+ setEditContent: (next) => {
13419
+ editContentRef.current = next;
13420
+ },
13421
+ setPendingUndo: (undo) => {
13422
+ pendingDeleteUndoRef.current = undo;
13423
+ }
13424
+ });
13425
+ }, [postToParent2]);
13426
+ handleDeleteSelectedRef.current = handleDeleteSelected;
13427
+ runPendingDeleteUndoRef.current = runPendingDeleteUndo;
12131
13428
  const handleLinkPopoverSubmit = useCallback5(
12132
13429
  (target) => {
12133
13430
  const session = linkPopoverSessionRef.current;
@@ -12210,7 +13507,7 @@ function OhhwellsBridge() {
12210
13507
  const handleVideoSettingsChange = useCallback5(
12211
13508
  (key, settings) => {
12212
13509
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
12213
- const video = getVideoEl(el);
13510
+ const video = getVideoEl2(el);
12214
13511
  if (!video) return;
12215
13512
  if (typeof settings.autoplay === "boolean") video.autoplay = settings.autoplay;
12216
13513
  if (typeof settings.muted === "boolean") video.muted = settings.muted;
@@ -12230,9 +13527,9 @@ function OhhwellsBridge() {
12230
13527
  [postToParent2]
12231
13528
  );
12232
13529
  return bridgeRoot ? createPortal2(
12233
- /* @__PURE__ */ jsxs14(Fragment5, { children: [
12234
- /* @__PURE__ */ jsx25("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
12235
- Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ jsx25(
13530
+ /* @__PURE__ */ jsxs15(Fragment5, { children: [
13531
+ /* @__PURE__ */ jsx27("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
13532
+ Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ jsx27(
12236
13533
  MediaOverlay,
12237
13534
  {
12238
13535
  hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
@@ -12243,7 +13540,7 @@ function OhhwellsBridge() {
12243
13540
  },
12244
13541
  `uploading-${key}`
12245
13542
  )),
12246
- mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ jsx25(
13543
+ mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ jsx27(
12247
13544
  MediaOverlay,
12248
13545
  {
12249
13546
  hover: mediaHover,
@@ -12252,11 +13549,11 @@ function OhhwellsBridge() {
12252
13549
  onVideoSettingsChange: handleVideoSettingsChange
12253
13550
  }
12254
13551
  ),
12255
- carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx25(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
12256
- siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
12257
- siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
12258
- isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
12259
- isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ jsx25(
13552
+ carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx27(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
13553
+ siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ jsx27(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
13554
+ siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ jsx27(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
13555
+ isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ jsx27(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
13556
+ isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ jsx27(
12260
13557
  "div",
12261
13558
  {
12262
13559
  className: "pointer-events-none fixed z-2147483646",
@@ -12266,7 +13563,7 @@ function OhhwellsBridge() {
12266
13563
  width: slot.width,
12267
13564
  height: slot.height
12268
13565
  },
12269
- children: /* @__PURE__ */ jsx25(
13566
+ children: /* @__PURE__ */ jsx27(
12270
13567
  DropIndicator,
12271
13568
  {
12272
13569
  direction: slot.direction,
@@ -12277,7 +13574,7 @@ function OhhwellsBridge() {
12277
13574
  },
12278
13575
  `footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
12279
13576
  )),
12280
- isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ jsx25(
13577
+ isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ jsx27(
12281
13578
  "div",
12282
13579
  {
12283
13580
  className: "pointer-events-none fixed z-2147483646",
@@ -12287,7 +13584,7 @@ function OhhwellsBridge() {
12287
13584
  width: slot.width,
12288
13585
  height: slot.height
12289
13586
  },
12290
- children: /* @__PURE__ */ jsx25(
13587
+ children: /* @__PURE__ */ jsx27(
12291
13588
  DropIndicator,
12292
13589
  {
12293
13590
  direction: slot.direction,
@@ -12298,10 +13595,18 @@ function OhhwellsBridge() {
12298
13595
  },
12299
13596
  `nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
12300
13597
  )),
12301
- hoveredNavContainerRect && toolbarVariant !== "select-frame" && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
12302
- hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx25(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
12303
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer(selectedElRef.current) && /* @__PURE__ */ jsx25(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
12304
- toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ jsx25(
13598
+ hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx27(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
13599
+ hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx27(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
13600
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ jsx27(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
13601
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ jsx27(
13602
+ FooterContainerChrome,
13603
+ {
13604
+ rect: toolbarRect,
13605
+ onAdd: handleAddFooterColumn,
13606
+ addDisabled: !canAddFooterColumn()
13607
+ }
13608
+ ),
13609
+ toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ jsx27(
12305
13610
  ItemInteractionLayer,
12306
13611
  {
12307
13612
  rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
@@ -12315,21 +13620,26 @@ function OhhwellsBridge() {
12315
13620
  onItemPointerDown: handleItemChromePointerDown,
12316
13621
  onItemClick: handleItemChromeClick,
12317
13622
  itemDragSurface: !isFooterFrameSelection,
12318
- toolbar: toolbarVariant === "link-action" && !isItemDragging ? /* @__PURE__ */ jsx25(
13623
+ toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && isFooterFrameSelection && !isItemDragging ? /* @__PURE__ */ jsx27(
12319
13624
  ItemActionToolbar,
12320
13625
  {
12321
13626
  onEditLink: openLinkPopoverForSelected,
13627
+ onSelectParent: handleSelectParent,
13628
+ onDuplicate: handleDuplicateSelected,
13629
+ onDelete: handleDeleteSelected,
12322
13630
  addItemDisabled: true,
12323
13631
  editLinkDisabled: false,
12324
- moreDisabled: true,
12325
- showAddItem: !selectedIsCta,
12326
- showMore: !selectedIsCta
13632
+ moreDisabled: false,
13633
+ duplicateDisabled: isFooterFrameSelection,
13634
+ showEditLink: !isFooterFrameSelection,
13635
+ showAddItem: !selectedIsCta && !isFooterFrameSelection,
13636
+ showMore: !selectedIsCta || isFooterFrameSelection
12327
13637
  }
12328
13638
  ) : void 0
12329
13639
  }
12330
13640
  ),
12331
- toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ jsxs14(Fragment5, { children: [
12332
- /* @__PURE__ */ jsx25(
13641
+ toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ jsxs15(Fragment5, { children: [
13642
+ /* @__PURE__ */ jsx27(
12333
13643
  EditGlowChrome,
12334
13644
  {
12335
13645
  rect: toolbarRect,
@@ -12339,7 +13649,7 @@ function OhhwellsBridge() {
12339
13649
  hideHandle: isItemDragging
12340
13650
  }
12341
13651
  ),
12342
- /* @__PURE__ */ jsx25(
13652
+ /* @__PURE__ */ jsx27(
12343
13653
  FloatingToolbar,
12344
13654
  {
12345
13655
  rect: toolbarRect,
@@ -12352,7 +13662,7 @@ function OhhwellsBridge() {
12352
13662
  }
12353
13663
  )
12354
13664
  ] }),
12355
- maxBadge && /* @__PURE__ */ jsxs14(
13665
+ maxBadge && /* @__PURE__ */ jsxs15(
12356
13666
  "div",
12357
13667
  {
12358
13668
  "data-ohw-max-badge": "",
@@ -12378,7 +13688,7 @@ function OhhwellsBridge() {
12378
13688
  ]
12379
13689
  }
12380
13690
  ),
12381
- toggleState && !linkPopover && /* @__PURE__ */ jsx25(
13691
+ toggleState && !linkPopover && /* @__PURE__ */ jsx27(
12382
13692
  StateToggle,
12383
13693
  {
12384
13694
  rect: toggleState.rect,
@@ -12387,15 +13697,15 @@ function OhhwellsBridge() {
12387
13697
  onStateChange: handleStateChange
12388
13698
  }
12389
13699
  ),
12390
- sectionGap && !linkPopover && /* @__PURE__ */ jsxs14(
13700
+ sectionGap && !linkPopover && /* @__PURE__ */ jsxs15(
12391
13701
  "div",
12392
13702
  {
12393
13703
  "data-ohw-section-insert-line": "",
12394
13704
  className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
12395
13705
  style: { top: sectionGap.y, transform: "translateY(-50%)" },
12396
13706
  children: [
12397
- /* @__PURE__ */ jsx25("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
12398
- /* @__PURE__ */ jsx25(
13707
+ /* @__PURE__ */ jsx27("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
13708
+ /* @__PURE__ */ jsx27(
12399
13709
  Badge,
12400
13710
  {
12401
13711
  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",
@@ -12412,11 +13722,11 @@ function OhhwellsBridge() {
12412
13722
  children: "Add Section"
12413
13723
  }
12414
13724
  ),
12415
- /* @__PURE__ */ jsx25("div", { className: "flex-1 bg-primary", style: { height: 3 } })
13725
+ /* @__PURE__ */ jsx27("div", { className: "flex-1 bg-primary", style: { height: 3 } })
12416
13726
  ]
12417
13727
  }
12418
13728
  ),
12419
- linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx25(
13729
+ linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx27(
12420
13730
  LinkPopover,
12421
13731
  {
12422
13732
  panelRef: linkPopoverPanelRef,
@@ -12443,6 +13753,12 @@ export {
12443
13753
  CustomToolbarDivider,
12444
13754
  DragHandle,
12445
13755
  DropIndicator,
13756
+ DropdownMenu,
13757
+ DropdownMenuContent,
13758
+ DropdownMenuGroup,
13759
+ DropdownMenuItem,
13760
+ DropdownMenuSeparator,
13761
+ DropdownMenuTrigger,
12446
13762
  ItemActionToolbar,
12447
13763
  ItemInteractionLayer,
12448
13764
  LinkEditorPanel,