@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.cjs CHANGED
@@ -36,6 +36,12 @@ __export(index_exports, {
36
36
  CustomToolbarDivider: () => CustomToolbarDivider,
37
37
  DragHandle: () => DragHandle,
38
38
  DropIndicator: () => DropIndicator,
39
+ DropdownMenu: () => DropdownMenu,
40
+ DropdownMenuContent: () => DropdownMenuContent,
41
+ DropdownMenuGroup: () => DropdownMenuGroup,
42
+ DropdownMenuItem: () => DropdownMenuItem,
43
+ DropdownMenuSeparator: () => DropdownMenuSeparator,
44
+ DropdownMenuTrigger: () => DropdownMenuTrigger,
39
45
  ItemActionToolbar: () => ItemActionToolbar,
40
46
  ItemInteractionLayer: () => ItemInteractionLayer,
41
47
  LinkEditorPanel: () => LinkEditorPanel,
@@ -63,7 +69,7 @@ __export(index_exports, {
63
69
  module.exports = __toCommonJS(index_exports);
64
70
 
65
71
  // src/OhhwellsBridge.tsx
66
- var import_react10 = __toESM(require("react"), 1);
72
+ var import_react11 = __toESM(require("react"), 1);
67
73
  var import_client = require("react-dom/client");
68
74
  var import_react_dom2 = require("react-dom");
69
75
 
@@ -75,6 +81,9 @@ function setStoredLinkHref(key, href) {
75
81
  function getStoredLinkHref(key) {
76
82
  return linkHrefStore.get(key);
77
83
  }
84
+ function clearStoredLinkHref(key) {
85
+ linkHrefStore.delete(key);
86
+ }
78
87
  function enforceLinkHrefs() {
79
88
  document.querySelectorAll("[data-ohw-href-key]").forEach((el) => {
80
89
  const key = el.getAttribute("data-ohw-href-key") ?? "";
@@ -4400,22 +4409,116 @@ var CustomToolbarButton = React4.forwardRef(
4400
4409
  CustomToolbarButton.displayName = "CustomToolbarButton";
4401
4410
 
4402
4411
  // src/ui/item-action-toolbar.tsx
4412
+ var import_react4 = require("react");
4403
4413
  var import_lucide_react2 = require("lucide-react");
4404
4414
 
4405
- // src/ui/tooltip.tsx
4415
+ // src/ui/dropdown-menu.tsx
4406
4416
  var import_radix_ui3 = require("radix-ui");
4407
4417
  var import_jsx_runtime7 = require("react/jsx-runtime");
4418
+ function DropdownMenu({ ...props }) {
4419
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_radix_ui3.DropdownMenu.Root, { "data-slot": "dropdown-menu", ...props });
4420
+ }
4421
+ function DropdownMenuTrigger({
4422
+ ...props
4423
+ }) {
4424
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_radix_ui3.DropdownMenu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
4425
+ }
4426
+ function DropdownMenuGroup({
4427
+ className,
4428
+ ...props
4429
+ }) {
4430
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4431
+ import_radix_ui3.DropdownMenu.Group,
4432
+ {
4433
+ "data-slot": "dropdown-menu-group",
4434
+ className: cn("flex w-full flex-col items-start p-1", className),
4435
+ ...props
4436
+ }
4437
+ );
4438
+ }
4439
+ function DropdownMenuContent({
4440
+ className,
4441
+ sideOffset = 6,
4442
+ ...props
4443
+ }) {
4444
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_radix_ui3.DropdownMenu.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4445
+ import_radix_ui3.DropdownMenu.Content,
4446
+ {
4447
+ "data-slot": "dropdown-menu-content",
4448
+ "data-ohw-more-menu": "",
4449
+ sideOffset,
4450
+ className: cn(
4451
+ "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",
4452
+ "shadow-[0px_4px_6px_0px_rgba(0,0,0,0.1),0px_2px_4px_0px_rgba(0,0,0,0.1)]",
4453
+ "origin-[var(--radix-dropdown-menu-content-transform-origin)]",
4454
+ "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",
4455
+ "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",
4456
+ className
4457
+ ),
4458
+ ...props
4459
+ }
4460
+ ) });
4461
+ }
4462
+ function DropdownMenuItem({
4463
+ className,
4464
+ inset,
4465
+ variant = "default",
4466
+ ...props
4467
+ }) {
4468
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4469
+ import_radix_ui3.DropdownMenu.Item,
4470
+ {
4471
+ "data-slot": "dropdown-menu-item",
4472
+ "data-inset": inset ? "" : void 0,
4473
+ "data-variant": variant,
4474
+ className: cn(
4475
+ "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",
4476
+ "text-popover-foreground",
4477
+ "focus:bg-muted data-[highlighted]:bg-muted",
4478
+ "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
4479
+ "[&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
4480
+ "[&_svg:not([class*=absolute])]:relative",
4481
+ // Leading icon — Figma absolute left-2 / top-1/2
4482
+ "[&>svg:first-child]:absolute [&>svg:first-child]:left-2 [&>svg:first-child]:top-1/2 [&>svg:first-child]:-translate-y-1/2",
4483
+ "data-[variant=destructive]:text-destructive",
4484
+ "data-[variant=destructive]:focus:bg-bg-destructive-10 data-[variant=destructive]:focus:text-destructive",
4485
+ "data-[variant=destructive]:data-[highlighted]:bg-bg-destructive-10 data-[variant=destructive]:data-[highlighted]:text-destructive",
4486
+ "data-[variant=destructive]:[&_svg]:text-destructive",
4487
+ inset && "pl-8",
4488
+ className
4489
+ ),
4490
+ ...props
4491
+ }
4492
+ );
4493
+ }
4494
+ function DropdownMenuSeparator({
4495
+ className,
4496
+ ...props
4497
+ }) {
4498
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4499
+ import_radix_ui3.DropdownMenu.Separator,
4500
+ {
4501
+ "data-slot": "dropdown-menu-separator",
4502
+ className: cn("h-px w-full bg-border", className),
4503
+ ...props
4504
+ }
4505
+ );
4506
+ }
4507
+
4508
+ // src/ui/tooltip.tsx
4509
+ var import_radix_ui4 = require("radix-ui");
4510
+ var import_jsx_runtime8 = require("react/jsx-runtime");
4408
4511
  function TooltipProvider({
4409
4512
  delayDuration = 0,
4410
4513
  ...props
4411
4514
  }) {
4412
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_radix_ui3.Tooltip.Provider, { "data-slot": "tooltip-provider", delayDuration, ...props });
4515
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_radix_ui4.Tooltip.Provider, { "data-slot": "tooltip-provider", delayDuration, ...props });
4413
4516
  }
4414
4517
  function Tooltip({ ...props }) {
4415
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_radix_ui3.Tooltip.Root, { "data-slot": "tooltip", ...props });
4518
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_radix_ui4.Tooltip.Root, { "data-slot": "tooltip", ...props });
4416
4519
  }
4417
4520
  function TooltipTrigger({ ...props }) {
4418
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_radix_ui3.Tooltip.Trigger, { "data-slot": "tooltip-trigger", ...props });
4521
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_radix_ui4.Tooltip.Trigger, { "data-slot": "tooltip-trigger", ...props });
4419
4522
  }
4420
4523
  var arrowClassBySide = {
4421
4524
  top: "before:bottom-0 before:left-1/2 before:-translate-x-1/2 before:translate-y-1/2",
@@ -4432,8 +4535,8 @@ function TooltipContent({
4432
4535
  ...props
4433
4536
  }) {
4434
4537
  const resolvedSide = side ?? "bottom";
4435
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_radix_ui3.Tooltip.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4436
- import_radix_ui3.Tooltip.Content,
4538
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_radix_ui4.Tooltip.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
4539
+ import_radix_ui4.Tooltip.Content,
4437
4540
  {
4438
4541
  "data-slot": "tooltip-content",
4439
4542
  side,
@@ -4455,7 +4558,7 @@ function TooltipContent({
4455
4558
  }
4456
4559
 
4457
4560
  // src/ui/item-action-toolbar.tsx
4458
- var import_jsx_runtime8 = require("react/jsx-runtime");
4561
+ var import_jsx_runtime9 = require("react/jsx-runtime");
4459
4562
  function ToolbarActionTooltip({
4460
4563
  label,
4461
4564
  side = "bottom",
@@ -4463,25 +4566,32 @@ function ToolbarActionTooltip({
4463
4566
  buttonProps,
4464
4567
  children
4465
4568
  }) {
4466
- const button = /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CustomToolbarButton, { type: "button", "aria-label": label, disabled, ...buttonProps, children });
4467
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Tooltip, { children: [
4468
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "inline-flex", children: button }) : button }),
4469
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(TooltipContent, { side, sideOffset: 9, children: label })
4569
+ const button = /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CustomToolbarButton, { type: "button", "aria-label": label, disabled, ...buttonProps, children });
4570
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Tooltip, { children: [
4571
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "inline-flex", children: button }) : button }),
4572
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(TooltipContent, { side, sideOffset: 9, children: label })
4470
4573
  ] });
4471
4574
  }
4472
4575
  function ItemActionToolbar({
4473
4576
  onEditLink,
4474
4577
  onAddItem,
4475
- onMore,
4578
+ onSelectParent,
4579
+ onDuplicate,
4580
+ onDelete,
4476
4581
  editLinkDisabled = false,
4477
4582
  addItemDisabled = true,
4478
- moreDisabled = true,
4583
+ moreDisabled = false,
4584
+ selectParentDisabled = false,
4585
+ duplicateDisabled = false,
4586
+ deleteDisabled = false,
4587
+ showEditLink = true,
4479
4588
  showAddItem = true,
4480
4589
  showMore = true,
4481
4590
  tooltipSide = "bottom"
4482
4591
  }) {
4483
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(CustomToolbar, { children: [
4484
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
4592
+ const [moreOpen, setMoreOpen] = (0, import_react4.useState)(false);
4593
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(CustomToolbar, { children: [
4594
+ showEditLink ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4485
4595
  ToolbarActionTooltip,
4486
4596
  {
4487
4597
  label: "Edit link",
@@ -4499,10 +4609,10 @@ function ItemActionToolbar({
4499
4609
  e.stopPropagation();
4500
4610
  }
4501
4611
  },
4502
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.Link, { className: "size-4 shrink-0", "aria-hidden": true })
4612
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react2.Link, { className: "size-4 shrink-0", "aria-hidden": true })
4503
4613
  }
4504
- ),
4505
- showAddItem ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
4614
+ ) : null,
4615
+ showAddItem ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4506
4616
  ToolbarActionTooltip,
4507
4617
  {
4508
4618
  label: "Add item",
@@ -4516,32 +4626,84 @@ function ItemActionToolbar({
4516
4626
  onAddItem?.();
4517
4627
  }
4518
4628
  },
4519
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.Plus, { className: "size-4 shrink-0", "aria-hidden": true })
4629
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react2.Plus, { className: "size-4 shrink-0", "aria-hidden": true })
4520
4630
  }
4521
4631
  ) : null,
4522
- showMore ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
4523
- ToolbarActionTooltip,
4524
- {
4525
- label: "More",
4526
- side: tooltipSide,
4527
- disabled: moreDisabled,
4528
- buttonProps: {
4632
+ showMore ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(DropdownMenu, { open: moreOpen, onOpenChange: setMoreOpen, children: [
4633
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Tooltip, { open: moreOpen ? false : void 0, children: [
4634
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DropdownMenuTrigger, { asChild: true, disabled: moreDisabled, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4635
+ CustomToolbarButton,
4636
+ {
4637
+ type: "button",
4638
+ "aria-label": "More",
4639
+ disabled: moreDisabled,
4640
+ onMouseDown: (e) => {
4641
+ e.preventDefault();
4642
+ e.stopPropagation();
4643
+ },
4644
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react2.MoreHorizontal, { className: "size-4 shrink-0", "aria-hidden": true })
4645
+ }
4646
+ ) }) }),
4647
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(TooltipContent, { side: tooltipSide, sideOffset: 9, children: "More" })
4648
+ ] }),
4649
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
4650
+ DropdownMenuContent,
4651
+ {
4652
+ align: "end",
4653
+ side: "bottom",
4654
+ onCloseAutoFocus: (e) => e.preventDefault(),
4529
4655
  onMouseDown: (e) => {
4530
- if (moreDisabled) return;
4531
4656
  e.preventDefault();
4532
4657
  e.stopPropagation();
4533
- onMore?.();
4534
- }
4535
- },
4536
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.MoreHorizontal, { className: "size-4 shrink-0", "aria-hidden": true })
4537
- }
4538
- ) : null
4658
+ },
4659
+ children: [
4660
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(DropdownMenuGroup, { children: [
4661
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
4662
+ DropdownMenuItem,
4663
+ {
4664
+ disabled: selectParentDisabled,
4665
+ onSelect: () => onSelectParent?.(),
4666
+ children: [
4667
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react2.CornerLeftUp, { size: 12, "aria-hidden": true }),
4668
+ "Select parent"
4669
+ ]
4670
+ }
4671
+ ),
4672
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
4673
+ DropdownMenuItem,
4674
+ {
4675
+ disabled: duplicateDisabled,
4676
+ onSelect: () => onDuplicate?.(),
4677
+ children: [
4678
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react2.Copy, { size: 12, "aria-hidden": true }),
4679
+ "Duplicate"
4680
+ ]
4681
+ }
4682
+ )
4683
+ ] }),
4684
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DropdownMenuSeparator, {}),
4685
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DropdownMenuGroup, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
4686
+ DropdownMenuItem,
4687
+ {
4688
+ variant: "destructive",
4689
+ disabled: deleteDisabled,
4690
+ onSelect: () => onDelete?.(),
4691
+ children: [
4692
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react2.Trash2, { size: 15, "aria-hidden": true }),
4693
+ "Delete"
4694
+ ]
4695
+ }
4696
+ ) })
4697
+ ]
4698
+ }
4699
+ )
4700
+ ] }) : null
4539
4701
  ] }) });
4540
4702
  }
4541
4703
 
4542
4704
  // src/ui/item-interaction-layer.tsx
4543
4705
  var React5 = __toESM(require("react"), 1);
4544
- var import_jsx_runtime9 = require("react/jsx-runtime");
4706
+ var import_jsx_runtime10 = require("react/jsx-runtime");
4545
4707
  var PRIMARY = "var(--ohw-primary, #0885FE)";
4546
4708
  var FOCUS_RING = `0 0 0 4px color-mix(in srgb, ${PRIMARY} 12%, transparent)`;
4547
4709
  var DRAG_SHADOW = "0px 4px 6px -1px rgba(0, 0, 0, 0.1), 0px 2px 4px -2px rgba(0, 0, 0, 0.1)";
@@ -4623,7 +4785,7 @@ function ClampedToolbarSlot({
4623
4785
  window.removeEventListener("resize", clamp);
4624
4786
  };
4625
4787
  }, [placement, children]);
4626
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4788
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4627
4789
  "div",
4628
4790
  {
4629
4791
  ref: slotRef,
@@ -4663,7 +4825,7 @@ function ItemInteractionLayer({
4663
4825
  const showToolbar = isActive && toolbar;
4664
4826
  const showDragHandle = (isActive || isDragging) && showHandle;
4665
4827
  const itemDragEnabled = itemDragSurface && isActive && showHandle && !isDragging && !dragDisabled;
4666
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
4828
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
4667
4829
  "div",
4668
4830
  {
4669
4831
  ref: elRef,
@@ -4679,7 +4841,7 @@ function ItemInteractionLayer({
4679
4841
  zIndex: getChromeZIndex(state)
4680
4842
  },
4681
4843
  children: [
4682
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4844
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4683
4845
  "div",
4684
4846
  {
4685
4847
  "aria-hidden": true,
@@ -4687,7 +4849,7 @@ function ItemInteractionLayer({
4687
4849
  style: getChromeStyle(state)
4688
4850
  }
4689
4851
  ),
4690
- itemDragEnabled && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4852
+ itemDragEnabled && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4691
4853
  "div",
4692
4854
  {
4693
4855
  "data-ohw-item-drag-surface": "",
@@ -4703,14 +4865,14 @@ function ItemInteractionLayer({
4703
4865
  }
4704
4866
  }
4705
4867
  ),
4706
- showDragHandle && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4868
+ showDragHandle && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4707
4869
  "div",
4708
4870
  {
4709
4871
  "data-ohw-drag-handle-container": "",
4710
4872
  className: "pointer-events-auto absolute left-0 top-1/2 z-10 -translate-x-[calc(100%+7px)] -translate-y-1/2",
4711
4873
  style: isDragging ? { opacity: 0 } : void 0,
4712
4874
  "aria-hidden": isDragging || void 0,
4713
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4875
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4714
4876
  DragHandle,
4715
4877
  {
4716
4878
  draggable: !dragDisabled,
@@ -4740,8 +4902,8 @@ function ItemInteractionLayer({
4740
4902
  )
4741
4903
  }
4742
4904
  ),
4743
- showToolbar && state === "active-top" && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ClampedToolbarSlot, { placement: "top", children: toolbar }),
4744
- showToolbar && state === "active-bottom" && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ClampedToolbarSlot, { placement: "bottom", children: toolbar })
4905
+ showToolbar && state === "active-top" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ClampedToolbarSlot, { placement: "top", children: toolbar }),
4906
+ showToolbar && state === "active-bottom" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ClampedToolbarSlot, { placement: "bottom", children: toolbar })
4745
4907
  ]
4746
4908
  }
4747
4909
  );
@@ -4753,8 +4915,8 @@ var import_lucide_react3 = require("lucide-react");
4753
4915
 
4754
4916
  // src/ui/button.tsx
4755
4917
  var React6 = __toESM(require("react"), 1);
4756
- var import_radix_ui4 = require("radix-ui");
4757
- var import_jsx_runtime10 = require("react/jsx-runtime");
4918
+ var import_radix_ui5 = require("radix-ui");
4919
+ var import_jsx_runtime11 = require("react/jsx-runtime");
4758
4920
  var buttonVariants = cva(
4759
4921
  "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",
4760
4922
  {
@@ -4777,8 +4939,8 @@ var buttonVariants = cva(
4777
4939
  );
4778
4940
  var Button = React6.forwardRef(
4779
4941
  ({ className, variant, size, asChild = false, ...props }, ref) => {
4780
- const Comp = asChild ? import_radix_ui4.Slot.Root : "button";
4781
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4942
+ const Comp = asChild ? import_radix_ui5.Slot.Root : "button";
4943
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
4782
4944
  Comp,
4783
4945
  {
4784
4946
  ref,
@@ -4792,7 +4954,7 @@ var Button = React6.forwardRef(
4792
4954
  Button.displayName = "Button";
4793
4955
 
4794
4956
  // src/ui/MediaOverlay.tsx
4795
- var import_jsx_runtime11 = require("react/jsx-runtime");
4957
+ var import_jsx_runtime12 = require("react/jsx-runtime");
4796
4958
  var MEDIA_UPLOAD_FADE_MS = 300;
4797
4959
  var VIDEO_SETTINGS_BAR_INSET = 8;
4798
4960
  var OVERLAY_BUTTON_STYLE = {
@@ -4850,7 +5012,7 @@ function MediaOverlay({
4850
5012
  return () => anim.cancel();
4851
5013
  }, [isUploading, fadingOut, onFadeOutComplete, hover.key]);
4852
5014
  if (isUploading) {
4853
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
5015
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4854
5016
  "div",
4855
5017
  {
4856
5018
  ref: skeletonRef,
@@ -4859,11 +5021,11 @@ function MediaOverlay({
4859
5021
  "data-ohw-media-skeleton": "",
4860
5022
  "aria-hidden": true,
4861
5023
  style: { ...box, pointerEvents: "none" },
4862
- children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("style", { children: SKELETON_CSS })
5024
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("style", { children: SKELETON_CSS })
4863
5025
  }
4864
5026
  );
4865
5027
  }
4866
- const settingsBar = isVideo && !hover.isDragOver ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
5028
+ const settingsBar = isVideo && !hover.isDragOver ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
4867
5029
  "div",
4868
5030
  {
4869
5031
  "data-ohw-bridge": "",
@@ -4879,7 +5041,7 @@ function MediaOverlay({
4879
5041
  },
4880
5042
  onClick: (e) => e.stopPropagation(),
4881
5043
  children: [
4882
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
5044
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4883
5045
  Button,
4884
5046
  {
4885
5047
  "data-ohw-media-overlay": "",
@@ -4894,10 +5056,10 @@ function MediaOverlay({
4894
5056
  e.stopPropagation();
4895
5057
  onVideoSettingsChange?.(hover.key, { autoplay: !autoplay });
4896
5058
  },
4897
- children: autoplay ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react3.Pause, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react3.Play, { size: 14 })
5059
+ children: autoplay ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react3.Pause, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react3.Play, { size: 14 })
4898
5060
  }
4899
5061
  ),
4900
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
5062
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4901
5063
  Button,
4902
5064
  {
4903
5065
  "data-ohw-media-overlay": "",
@@ -4912,15 +5074,15 @@ function MediaOverlay({
4912
5074
  e.stopPropagation();
4913
5075
  onVideoSettingsChange?.(hover.key, { muted: !muted });
4914
5076
  },
4915
- children: muted ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react3.VolumeX, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react3.Volume2, { size: 14 })
5077
+ children: muted ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react3.VolumeX, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react3.Volume2, { size: 14 })
4916
5078
  }
4917
5079
  )
4918
5080
  ]
4919
5081
  }
4920
5082
  ) : null;
4921
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
5083
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
4922
5084
  settingsBar,
4923
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
5085
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4924
5086
  "div",
4925
5087
  {
4926
5088
  "data-ohw-bridge": "",
@@ -4937,21 +5099,25 @@ function MediaOverlay({
4937
5099
  background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
4938
5100
  },
4939
5101
  onClick: () => onReplace(hover.key),
4940
- children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
5102
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
4941
5103
  Button,
4942
5104
  {
4943
5105
  "data-ohw-media-overlay": "",
4944
5106
  variant: "outline",
4945
5107
  size: "sm",
4946
5108
  className: "gap-1.5 cursor-pointer hover:bg-background",
4947
- style: OVERLAY_BUTTON_STYLE,
5109
+ style: {
5110
+ ...OVERLAY_BUTTON_STYLE,
5111
+ // Don't let Replace steal clicks when text (e.g. nav) sits on top of this media.
5112
+ pointerEvents: hover.hasTextOverlap ? "none" : "auto"
5113
+ },
4948
5114
  onMouseDown: (e) => e.preventDefault(),
4949
5115
  onClick: (e) => {
4950
5116
  e.stopPropagation();
4951
5117
  onReplace(hover.key);
4952
5118
  },
4953
5119
  children: [
4954
- isVideo ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react3.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react3.ImageIcon, { size: 14 }),
5120
+ isVideo ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react3.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react3.ImageIcon, { size: 14 }),
4955
5121
  isVideo ? "Replace video" : "Replace image"
4956
5122
  ]
4957
5123
  }
@@ -4963,7 +5129,7 @@ function MediaOverlay({
4963
5129
 
4964
5130
  // src/ui/CarouselOverlay.tsx
4965
5131
  var import_lucide_react4 = require("lucide-react");
4966
- var import_jsx_runtime12 = require("react/jsx-runtime");
5132
+ var import_jsx_runtime13 = require("react/jsx-runtime");
4967
5133
  var OVERLAY_BUTTON_STYLE2 = {
4968
5134
  pointerEvents: "auto",
4969
5135
  fontFamily: "Inter, sans-serif",
@@ -4975,7 +5141,7 @@ function CarouselOverlay({
4975
5141
  onEdit
4976
5142
  }) {
4977
5143
  const { rect } = hover;
4978
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
5144
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
4979
5145
  "div",
4980
5146
  {
4981
5147
  "data-ohw-bridge": "",
@@ -4993,7 +5159,7 @@ function CarouselOverlay({
4993
5159
  background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
4994
5160
  },
4995
5161
  onClick: () => onEdit(hover.key),
4996
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
5162
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
4997
5163
  Button,
4998
5164
  {
4999
5165
  "data-ohw-carousel-overlay": "",
@@ -5007,7 +5173,7 @@ function CarouselOverlay({
5007
5173
  onEdit(hover.key);
5008
5174
  },
5009
5175
  children: [
5010
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react4.GalleryHorizontal, { size: 14 }),
5176
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.GalleryHorizontal, { size: 14 }),
5011
5177
  "Edit gallery"
5012
5178
  ]
5013
5179
  }
@@ -5296,29 +5462,29 @@ function scrollToHashSectionWhenReady(behavior = "smooth") {
5296
5462
  }
5297
5463
 
5298
5464
  // src/ui/link-modal/LinkPopover.tsx
5299
- var import_react7 = require("react");
5465
+ var import_react8 = require("react");
5300
5466
 
5301
5467
  // src/ui/dialog.tsx
5302
5468
  var React8 = __toESM(require("react"), 1);
5303
- var import_radix_ui5 = require("radix-ui");
5469
+ var import_radix_ui6 = require("radix-ui");
5304
5470
  var import_lucide_react5 = require("lucide-react");
5305
- var import_jsx_runtime13 = require("react/jsx-runtime");
5471
+ var import_jsx_runtime14 = require("react/jsx-runtime");
5306
5472
  function Dialog2({
5307
5473
  ...props
5308
5474
  }) {
5309
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_radix_ui5.Dialog.Root, { "data-slot": "dialog", ...props });
5475
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_radix_ui6.Dialog.Root, { "data-slot": "dialog", ...props });
5310
5476
  }
5311
5477
  function DialogPortal({
5312
5478
  ...props
5313
5479
  }) {
5314
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_radix_ui5.Dialog.Portal, { ...props });
5480
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_radix_ui6.Dialog.Portal, { ...props });
5315
5481
  }
5316
5482
  function DialogOverlay({
5317
5483
  className,
5318
5484
  ...props
5319
5485
  }) {
5320
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5321
- import_radix_ui5.Dialog.Overlay,
5486
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
5487
+ import_radix_ui6.Dialog.Overlay,
5322
5488
  {
5323
5489
  "data-slot": "dialog-overlay",
5324
5490
  "data-ohw-link-modal-root": "",
@@ -5330,10 +5496,10 @@ function DialogOverlay({
5330
5496
  var DialogContent = React8.forwardRef(
5331
5497
  ({ className, children, showCloseButton = true, container, ...props }, ref) => {
5332
5498
  const positionMode = container ? "absolute" : "fixed";
5333
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DialogPortal, { container: container ?? void 0, children: [
5334
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DialogOverlay, { className: cn(positionMode, "inset-0") }),
5335
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
5336
- import_radix_ui5.Dialog.Content,
5499
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(DialogPortal, { container: container ?? void 0, children: [
5500
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DialogOverlay, { className: cn(positionMode, "inset-0") }),
5501
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
5502
+ import_radix_ui6.Dialog.Content,
5337
5503
  {
5338
5504
  ref,
5339
5505
  "data-slot": "dialog-content",
@@ -5348,13 +5514,13 @@ var DialogContent = React8.forwardRef(
5348
5514
  ...props,
5349
5515
  children: [
5350
5516
  children,
5351
- showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5352
- import_radix_ui5.Dialog.Close,
5517
+ showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
5518
+ import_radix_ui6.Dialog.Close,
5353
5519
  {
5354
5520
  type: "button",
5355
5521
  className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
5356
5522
  "aria-label": "Close",
5357
- children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react5.X, { size: 16, "aria-hidden": true })
5523
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react5.X, { size: 16, "aria-hidden": true })
5358
5524
  }
5359
5525
  ) : null
5360
5526
  ]
@@ -5363,18 +5529,18 @@ var DialogContent = React8.forwardRef(
5363
5529
  ] });
5364
5530
  }
5365
5531
  );
5366
- DialogContent.displayName = import_radix_ui5.Dialog.Content.displayName;
5532
+ DialogContent.displayName = import_radix_ui6.Dialog.Content.displayName;
5367
5533
  function DialogHeader({
5368
5534
  className,
5369
5535
  ...props
5370
5536
  }) {
5371
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: cn("flex flex-col gap-1.5", className), ...props });
5537
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: cn("flex flex-col gap-1.5", className), ...props });
5372
5538
  }
5373
5539
  function DialogFooter({
5374
5540
  className,
5375
5541
  ...props
5376
5542
  }) {
5377
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5543
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
5378
5544
  "div",
5379
5545
  {
5380
5546
  className: cn("flex items-center justify-end gap-2", className),
@@ -5382,8 +5548,8 @@ function DialogFooter({
5382
5548
  }
5383
5549
  );
5384
5550
  }
5385
- var DialogTitle = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5386
- import_radix_ui5.Dialog.Title,
5551
+ var DialogTitle = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
5552
+ import_radix_ui6.Dialog.Title,
5387
5553
  {
5388
5554
  ref,
5389
5555
  className: cn(
@@ -5393,36 +5559,36 @@ var DialogTitle = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE
5393
5559
  ...props
5394
5560
  }
5395
5561
  ));
5396
- DialogTitle.displayName = import_radix_ui5.Dialog.Title.displayName;
5397
- var DialogDescription = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5398
- import_radix_ui5.Dialog.Description,
5562
+ DialogTitle.displayName = import_radix_ui6.Dialog.Title.displayName;
5563
+ var DialogDescription = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
5564
+ import_radix_ui6.Dialog.Description,
5399
5565
  {
5400
5566
  ref,
5401
5567
  className: cn("text-sm text-muted-foreground", className),
5402
5568
  ...props
5403
5569
  }
5404
5570
  ));
5405
- DialogDescription.displayName = import_radix_ui5.Dialog.Description.displayName;
5406
- var DialogClose = import_radix_ui5.Dialog.Close;
5571
+ DialogDescription.displayName = import_radix_ui6.Dialog.Description.displayName;
5572
+ var DialogClose = import_radix_ui6.Dialog.Close;
5407
5573
 
5408
5574
  // src/ui/link-modal/LinkEditorPanel.tsx
5409
5575
  var import_lucide_react9 = require("lucide-react");
5410
5576
 
5411
5577
  // src/ui/link-modal/DestinationBreadcrumb.tsx
5412
5578
  var import_lucide_react6 = require("lucide-react");
5413
- var import_jsx_runtime14 = require("react/jsx-runtime");
5579
+ var import_jsx_runtime15 = require("react/jsx-runtime");
5414
5580
  function DestinationBreadcrumb({
5415
5581
  pageTitle,
5416
5582
  sectionLabel
5417
5583
  }) {
5418
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex w-full flex-col gap-2", children: [
5419
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-sm font-medium! text-foreground m-0", children: "Destination" }),
5420
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-center gap-3", children: [
5421
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-center gap-2", children: [
5422
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react6.File, { size: 16, className: "shrink-0 text-foreground", "aria-hidden": true }),
5423
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "text-sm font-medium leading-none text-foreground!", children: pageTitle })
5584
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex w-full flex-col gap-2", children: [
5585
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-sm font-medium! text-foreground m-0", children: "Destination" }),
5586
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center gap-3", children: [
5587
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center gap-2", children: [
5588
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react6.File, { size: 16, className: "shrink-0 text-foreground", "aria-hidden": true }),
5589
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-sm font-medium leading-none text-foreground!", children: pageTitle })
5424
5590
  ] }),
5425
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
5591
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5426
5592
  import_lucide_react6.ArrowRight,
5427
5593
  {
5428
5594
  size: 16,
@@ -5430,8 +5596,8 @@ function DestinationBreadcrumb({
5430
5596
  "aria-hidden": true
5431
5597
  }
5432
5598
  ),
5433
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
5434
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
5599
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
5600
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5435
5601
  import_lucide_react6.GalleryVertical,
5436
5602
  {
5437
5603
  size: 16,
@@ -5439,7 +5605,7 @@ function DestinationBreadcrumb({
5439
5605
  "aria-hidden": true
5440
5606
  }
5441
5607
  ),
5442
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
5608
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
5443
5609
  ] })
5444
5610
  ] })
5445
5611
  ] });
@@ -5447,22 +5613,22 @@ function DestinationBreadcrumb({
5447
5613
 
5448
5614
  // src/ui/link-modal/SectionTreeItem.tsx
5449
5615
  var import_lucide_react7 = require("lucide-react");
5450
- var import_jsx_runtime15 = require("react/jsx-runtime");
5616
+ var import_jsx_runtime16 = require("react/jsx-runtime");
5451
5617
  function SectionTreeItem({
5452
5618
  section,
5453
5619
  onSelect,
5454
5620
  selected
5455
5621
  }) {
5456
5622
  const interactive = Boolean(onSelect);
5457
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex h-9 w-full items-end pl-3", children: [
5458
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5623
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex h-9 w-full items-end pl-3", children: [
5624
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5459
5625
  "div",
5460
5626
  {
5461
5627
  className: "mr-[-1px] h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
5462
5628
  "aria-hidden": true
5463
5629
  }
5464
5630
  ),
5465
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
5631
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
5466
5632
  "div",
5467
5633
  {
5468
5634
  role: interactive ? "button" : void 0,
@@ -5480,7 +5646,7 @@ function SectionTreeItem({
5480
5646
  interactive && selected && "border-primary"
5481
5647
  ),
5482
5648
  children: [
5483
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5649
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5484
5650
  import_lucide_react7.GalleryVertical,
5485
5651
  {
5486
5652
  size: 16,
@@ -5488,7 +5654,7 @@ function SectionTreeItem({
5488
5654
  "aria-hidden": true
5489
5655
  }
5490
5656
  ),
5491
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
5657
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
5492
5658
  ]
5493
5659
  }
5494
5660
  )
@@ -5496,14 +5662,14 @@ function SectionTreeItem({
5496
5662
  }
5497
5663
 
5498
5664
  // src/ui/link-modal/UrlOrPageInput.tsx
5499
- var import_react4 = require("react");
5665
+ var import_react5 = require("react");
5500
5666
 
5501
5667
  // src/ui/input.tsx
5502
5668
  var React9 = __toESM(require("react"), 1);
5503
- var import_jsx_runtime16 = require("react/jsx-runtime");
5669
+ var import_jsx_runtime17 = require("react/jsx-runtime");
5504
5670
  var Input = React9.forwardRef(
5505
5671
  ({ className, type, ...props }, ref) => {
5506
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5672
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5507
5673
  "input",
5508
5674
  {
5509
5675
  type,
@@ -5521,11 +5687,11 @@ var Input = React9.forwardRef(
5521
5687
  Input.displayName = "Input";
5522
5688
 
5523
5689
  // src/ui/label.tsx
5524
- var import_radix_ui6 = require("radix-ui");
5525
- var import_jsx_runtime17 = require("react/jsx-runtime");
5690
+ var import_radix_ui7 = require("radix-ui");
5691
+ var import_jsx_runtime18 = require("react/jsx-runtime");
5526
5692
  function Label({ className, ...props }) {
5527
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5528
- import_radix_ui6.Label.Root,
5693
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5694
+ import_radix_ui7.Label.Root,
5529
5695
  {
5530
5696
  "data-slot": "label",
5531
5697
  className: cn("text-sm font-medium leading-5 text-foreground", className),
@@ -5536,11 +5702,11 @@ function Label({ className, ...props }) {
5536
5702
 
5537
5703
  // src/ui/link-modal/UrlOrPageInput.tsx
5538
5704
  var import_lucide_react8 = require("lucide-react");
5539
- var import_jsx_runtime18 = require("react/jsx-runtime");
5705
+ var import_jsx_runtime19 = require("react/jsx-runtime");
5540
5706
  function FieldChevron({
5541
5707
  onClick
5542
5708
  }) {
5543
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5709
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5544
5710
  "button",
5545
5711
  {
5546
5712
  type: "button",
@@ -5548,7 +5714,7 @@ function FieldChevron({
5548
5714
  onClick,
5549
5715
  "aria-label": "Open page list",
5550
5716
  tabIndex: -1,
5551
- children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react8.ChevronDown, { size: 16 })
5717
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react8.ChevronDown, { size: 16 })
5552
5718
  }
5553
5719
  );
5554
5720
  }
@@ -5564,11 +5730,11 @@ function UrlOrPageInput({
5564
5730
  readOnly = false,
5565
5731
  urlError
5566
5732
  }) {
5567
- const inputId = (0, import_react4.useId)();
5568
- const inputRef = (0, import_react4.useRef)(null);
5569
- const rootRef = (0, import_react4.useRef)(null);
5570
- const [isFocused, setIsFocused] = (0, import_react4.useState)(false);
5571
- (0, import_react4.useEffect)(() => {
5733
+ const inputId = (0, import_react5.useId)();
5734
+ const inputRef = (0, import_react5.useRef)(null);
5735
+ const rootRef = (0, import_react5.useRef)(null);
5736
+ const [isFocused, setIsFocused] = (0, import_react5.useState)(false);
5737
+ (0, import_react5.useEffect)(() => {
5572
5738
  if (!dropdownOpen) return;
5573
5739
  const isOutside = (e) => {
5574
5740
  const root = rootRef.current;
@@ -5609,11 +5775,11 @@ function UrlOrPageInput({
5609
5775
  "data-ohw-link-field flex h-[36px] w-full items-center overflow-hidden rounded-md border bg-background pl-3 pr-3 py-2 outline-none transition-[border-color,box-shadow]",
5610
5776
  urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
5611
5777
  );
5612
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex w-full flex-col gap-2 p-0", children: [
5613
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
5614
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { ref: rootRef, className: "relative w-full", children: [
5615
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
5616
- selectedPage ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5778
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex w-full flex-col gap-2 p-0", children: [
5779
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
5780
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { ref: rootRef, className: "relative w-full", children: [
5781
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
5782
+ selectedPage ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5617
5783
  import_lucide_react8.File,
5618
5784
  {
5619
5785
  size: 16,
@@ -5621,7 +5787,7 @@ function UrlOrPageInput({
5621
5787
  "aria-hidden": true
5622
5788
  }
5623
5789
  ) }) : null,
5624
- readOnly ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "min-w-0 flex-1 truncate text-sm leading-5 text-foreground", children: selectedPage?.title ?? value }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5790
+ readOnly ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "min-w-0 flex-1 truncate text-sm leading-5 text-foreground", children: selectedPage?.title ?? value }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5625
5791
  Input,
5626
5792
  {
5627
5793
  ref: inputRef,
@@ -5647,7 +5813,7 @@ function UrlOrPageInput({
5647
5813
  )
5648
5814
  }
5649
5815
  ),
5650
- selectedPage && !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5816
+ selectedPage && !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5651
5817
  "button",
5652
5818
  {
5653
5819
  type: "button",
@@ -5655,26 +5821,26 @@ function UrlOrPageInput({
5655
5821
  onMouseDown: clearSelection,
5656
5822
  "aria-label": "Clear selected page",
5657
5823
  tabIndex: -1,
5658
- children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react8.X, { size: 16, "aria-hidden": true })
5824
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react8.X, { size: 16, "aria-hidden": true })
5659
5825
  }
5660
5826
  ) : null,
5661
- !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(FieldChevron, { onClick: toggleDropdown }) : null
5827
+ !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(FieldChevron, { onClick: toggleDropdown }) : null
5662
5828
  ] }),
5663
- dropdownOpen && !readOnly && filteredPages.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5829
+ dropdownOpen && !readOnly && filteredPages.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5664
5830
  "div",
5665
5831
  {
5666
5832
  "data-ohw-link-page-dropdown": "",
5667
5833
  className: "absolute left-0 right-0 top-[calc(100%+4px)] z-50 max-h-48 overflow-auto rounded-lg border border-border bg-popover py-1 shadow-lg",
5668
5834
  onMouseDown: (e) => e.preventDefault(),
5669
- children: filteredPages.map((page) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
5835
+ children: filteredPages.map((page) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
5670
5836
  "button",
5671
5837
  {
5672
5838
  type: "button",
5673
5839
  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",
5674
5840
  onClick: () => onPageSelect(page),
5675
5841
  children: [
5676
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react8.File, { size: 16, className: "shrink-0", "aria-hidden": true }),
5677
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "truncate", children: page.title })
5842
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react8.File, { size: 16, className: "shrink-0", "aria-hidden": true }),
5843
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "truncate", children: page.title })
5678
5844
  ]
5679
5845
  },
5680
5846
  page.path
@@ -5682,34 +5848,34 @@ function UrlOrPageInput({
5682
5848
  }
5683
5849
  ) : null
5684
5850
  ] }),
5685
- urlError ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "text-sm font-medium text-destructive", children: urlError }) : null
5851
+ urlError ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "text-sm font-medium text-destructive", children: urlError }) : null
5686
5852
  ] });
5687
5853
  }
5688
5854
 
5689
5855
  // src/ui/link-modal/LinkEditorPanel.tsx
5690
- var import_jsx_runtime19 = require("react/jsx-runtime");
5856
+ var import_jsx_runtime20 = require("react/jsx-runtime");
5691
5857
  function LinkEditorPanel({ state, onClose }) {
5692
5858
  const isCancel = state.secondaryLabel === "Cancel" || state.secondaryLabel === "Back to sections";
5693
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
5694
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DialogClose, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5859
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
5860
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DialogClose, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5695
5861
  "button",
5696
5862
  {
5697
5863
  type: "button",
5698
5864
  className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50 h-7",
5699
5865
  "aria-label": "Close",
5700
5866
  onClick: onClose,
5701
- children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react9.X, { size: 16, "aria-hidden": true })
5867
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.X, { size: 16, "aria-hidden": true })
5702
5868
  }
5703
5869
  ) }),
5704
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DialogHeader, { className: "w-full gap-1.5 p-6 pr-12", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DialogTitle, { className: "m-0 w-full break-words", children: state.title }) }),
5705
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
5706
- state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5870
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DialogHeader, { className: "w-full gap-1.5 p-6 pr-12", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DialogTitle, { className: "m-0 w-full break-words", children: state.title }) }),
5871
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
5872
+ state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5707
5873
  DestinationBreadcrumb,
5708
5874
  {
5709
5875
  pageTitle: state.selectedPage.title,
5710
5876
  sectionLabel: state.selectedSection.label
5711
5877
  }
5712
- ) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5878
+ ) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5713
5879
  UrlOrPageInput,
5714
5880
  {
5715
5881
  value: state.searchValue,
@@ -5722,8 +5888,8 @@ function LinkEditorPanel({ state, onClose }) {
5722
5888
  urlError: state.urlError
5723
5889
  }
5724
5890
  ),
5725
- state.showChooseSection ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex flex-col justify-center gap-2", children: [
5726
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5891
+ state.showChooseSection ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-col justify-center gap-2", children: [
5892
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5727
5893
  Button,
5728
5894
  {
5729
5895
  type: "button",
@@ -5734,15 +5900,15 @@ function LinkEditorPanel({ state, onClose }) {
5734
5900
  children: "Choose a section"
5735
5901
  }
5736
5902
  ),
5737
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
5738
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react9.Info, { size: 16, className: "shrink-0", "aria-hidden": true }),
5739
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "Pick a section this link should scroll to." })
5903
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
5904
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.Info, { size: 16, className: "shrink-0", "aria-hidden": true }),
5905
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: "Pick a section this link should scroll to." })
5740
5906
  ] })
5741
5907
  ] }) : null,
5742
- state.showSectionRow && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
5908
+ state.showSectionRow && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
5743
5909
  ] }),
5744
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(DialogFooter, { className: "w-full px-6 pb-6", children: [
5745
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5910
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(DialogFooter, { className: "w-full px-6 pb-6", children: [
5911
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5746
5912
  Button,
5747
5913
  {
5748
5914
  type: "button",
@@ -5757,7 +5923,7 @@ function LinkEditorPanel({ state, onClose }) {
5757
5923
  children: state.secondaryLabel
5758
5924
  }
5759
5925
  ),
5760
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5926
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5761
5927
  Button,
5762
5928
  {
5763
5929
  type: "button",
@@ -5776,11 +5942,11 @@ function LinkEditorPanel({ state, onClose }) {
5776
5942
  }
5777
5943
 
5778
5944
  // src/ui/link-modal/SectionPickerOverlay.tsx
5779
- var import_react5 = require("react");
5945
+ var import_react6 = require("react");
5780
5946
  var import_react_dom = require("react-dom");
5781
5947
  var import_lucide_react10 = require("lucide-react");
5782
5948
  var import_navigation = require("next/navigation");
5783
- var import_jsx_runtime20 = require("react/jsx-runtime");
5949
+ var import_jsx_runtime21 = require("react/jsx-runtime");
5784
5950
  var DIM_OVERLAY = "rgba(0, 0, 0, 0.45)";
5785
5951
  function rectsEqual(a, b) {
5786
5952
  if (a.size !== b.size) return false;
@@ -5813,12 +5979,12 @@ function hitTestSectionId(x, y, sectionIds, rects) {
5813
5979
  return null;
5814
5980
  }
5815
5981
  function useSectionRects(sectionIdsKey, enabled) {
5816
- const [rects, setRects] = (0, import_react5.useState)(/* @__PURE__ */ new Map());
5817
- const sectionIds = (0, import_react5.useMemo)(
5982
+ const [rects, setRects] = (0, import_react6.useState)(/* @__PURE__ */ new Map());
5983
+ const sectionIds = (0, import_react6.useMemo)(
5818
5984
  () => sectionIdsKey ? sectionIdsKey.split("\0") : [],
5819
5985
  [sectionIdsKey]
5820
5986
  );
5821
- (0, import_react5.useEffect)(() => {
5987
+ (0, import_react6.useEffect)(() => {
5822
5988
  if (!enabled || sectionIds.length === 0) {
5823
5989
  setRects((prev) => prev.size === 0 ? prev : /* @__PURE__ */ new Map());
5824
5990
  return;
@@ -5859,13 +6025,13 @@ function SectionPickerOverlay({
5859
6025
  }) {
5860
6026
  const router = (0, import_navigation.useRouter)();
5861
6027
  const pathname = (0, import_navigation.usePathname)();
5862
- const [selectedId, setSelectedId] = (0, import_react5.useState)(null);
5863
- const [hoveredId, setHoveredId] = (0, import_react5.useState)(null);
5864
- const pointerRef = (0, import_react5.useRef)(null);
5865
- const pointerScreenRef = (0, import_react5.useRef)(null);
5866
- const iframeOffsetTopRef = (0, import_react5.useRef)(null);
5867
- const sectionIdsRef = (0, import_react5.useRef)([]);
5868
- const [chromeClip, setChromeClip] = (0, import_react5.useState)(
6028
+ const [selectedId, setSelectedId] = (0, import_react6.useState)(null);
6029
+ const [hoveredId, setHoveredId] = (0, import_react6.useState)(null);
6030
+ const pointerRef = (0, import_react6.useRef)(null);
6031
+ const pointerScreenRef = (0, import_react6.useRef)(null);
6032
+ const iframeOffsetTopRef = (0, import_react6.useRef)(null);
6033
+ const sectionIdsRef = (0, import_react6.useRef)([]);
6034
+ const [chromeClip, setChromeClip] = (0, import_react6.useState)(
5869
6035
  () => ({
5870
6036
  top: 0,
5871
6037
  bottom: typeof window !== "undefined" ? window.innerHeight : 0
@@ -5873,12 +6039,12 @@ function SectionPickerOverlay({
5873
6039
  );
5874
6040
  const normalizedTarget = normalizePath(pagePath);
5875
6041
  const isOnTargetPage = normalizePath(pathname) === normalizedTarget;
5876
- (0, import_react5.useEffect)(() => {
6042
+ (0, import_react6.useEffect)(() => {
5877
6043
  if (isOnTargetPage) return;
5878
6044
  const search = readPreservedSearch();
5879
6045
  router.push(`${normalizedTarget}${search}`);
5880
6046
  }, [isOnTargetPage, normalizedTarget, router]);
5881
- (0, import_react5.useEffect)(() => {
6047
+ (0, import_react6.useEffect)(() => {
5882
6048
  document.documentElement.setAttribute("data-ohw-section-picking", "");
5883
6049
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => {
5884
6050
  el.removeAttribute("data-ohw-hovered");
@@ -5890,24 +6056,24 @@ function SectionPickerOverlay({
5890
6056
  document.documentElement.removeAttribute("data-ohw-section-picking");
5891
6057
  };
5892
6058
  }, []);
5893
- const liveSections = (0, import_react5.useMemo)(() => {
6059
+ const liveSections = (0, import_react6.useMemo)(() => {
5894
6060
  if (!isOnTargetPage) return sections;
5895
6061
  const live = collectSectionsFromDom();
5896
6062
  if (live.length === 0) return sections;
5897
6063
  const labels = new Map(sections.map((s) => [s.id, s.label]));
5898
6064
  return live.map((s) => ({ id: s.id, label: labels.get(s.id) ?? s.label }));
5899
6065
  }, [isOnTargetPage, sections, pathname]);
5900
- const sectionIdsKey = (0, import_react5.useMemo)(
6066
+ const sectionIdsKey = (0, import_react6.useMemo)(
5901
6067
  () => liveSections.map((s) => s.id).join("\0"),
5902
6068
  [liveSections]
5903
6069
  );
5904
- const sectionIds = (0, import_react5.useMemo)(
6070
+ const sectionIds = (0, import_react6.useMemo)(
5905
6071
  () => liveSections.map((s) => s.id),
5906
6072
  [liveSections]
5907
6073
  );
5908
6074
  sectionIdsRef.current = sectionIds;
5909
6075
  const rects = useSectionRects(sectionIdsKey, isOnTargetPage);
5910
- const applyHoverAt = (0, import_react5.useCallback)(
6076
+ const applyHoverAt = (0, import_react6.useCallback)(
5911
6077
  (x, y, liveRects) => {
5912
6078
  const ids = sectionIdsRef.current;
5913
6079
  const map = liveRects ?? readSectionRects(ids);
@@ -5916,7 +6082,7 @@ function SectionPickerOverlay({
5916
6082
  },
5917
6083
  []
5918
6084
  );
5919
- (0, import_react5.useEffect)(() => {
6085
+ (0, import_react6.useEffect)(() => {
5920
6086
  const applyClip = (iframeOffsetTop, visibleCanvasTop, canvasH) => {
5921
6087
  const top = Math.max(0, visibleCanvasTop - iframeOffsetTop);
5922
6088
  const bottom = Math.min(
@@ -5958,12 +6124,12 @@ function SectionPickerOverlay({
5958
6124
  window.removeEventListener("resize", onResize);
5959
6125
  };
5960
6126
  }, [applyHoverAt]);
5961
- (0, import_react5.useEffect)(() => {
6127
+ (0, import_react6.useEffect)(() => {
5962
6128
  const ptr = pointerRef.current;
5963
6129
  if (!ptr) return;
5964
6130
  applyHoverAt(ptr.x, ptr.y, rects);
5965
6131
  }, [rects, applyHoverAt]);
5966
- (0, import_react5.useEffect)(() => {
6132
+ (0, import_react6.useEffect)(() => {
5967
6133
  const rememberPointer = (clientX, clientY) => {
5968
6134
  pointerRef.current = { x: clientX, y: clientY };
5969
6135
  const top = iframeOffsetTopRef.current;
@@ -5987,7 +6153,7 @@ function SectionPickerOverlay({
5987
6153
  window.removeEventListener("message", onPointerSync);
5988
6154
  };
5989
6155
  }, [rects, applyHoverAt]);
5990
- const handleSelect = (0, import_react5.useCallback)(
6156
+ const handleSelect = (0, import_react6.useCallback)(
5991
6157
  (section) => {
5992
6158
  if (selectedId) return;
5993
6159
  setSelectedId(section.id);
@@ -5995,7 +6161,7 @@ function SectionPickerOverlay({
5995
6161
  },
5996
6162
  [selectedId, onSelect]
5997
6163
  );
5998
- (0, import_react5.useEffect)(() => {
6164
+ (0, import_react6.useEffect)(() => {
5999
6165
  const onKeyDown = (e) => {
6000
6166
  if (e.key === "Escape") {
6001
6167
  e.preventDefault();
@@ -6009,7 +6175,7 @@ function SectionPickerOverlay({
6009
6175
  const portalRoot = typeof document !== "undefined" ? document.querySelector("[data-ohw-bridge-root]") ?? document.body : null;
6010
6176
  if (!portalRoot) return null;
6011
6177
  return (0, import_react_dom.createPortal)(
6012
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
6178
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
6013
6179
  "div",
6014
6180
  {
6015
6181
  "data-ohw-section-picker": "",
@@ -6019,12 +6185,12 @@ function SectionPickerOverlay({
6019
6185
  role: "dialog",
6020
6186
  "aria-label": "Choose a section",
6021
6187
  children: [
6022
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
6188
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6023
6189
  "div",
6024
6190
  {
6025
6191
  className: "pointer-events-auto fixed left-5 z-[2]",
6026
6192
  style: { top: chromeClip.top + 20 },
6027
- children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
6193
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
6028
6194
  Button,
6029
6195
  {
6030
6196
  type: "button",
@@ -6033,14 +6199,14 @@ function SectionPickerOverlay({
6033
6199
  className: "h-8 min-w-0 gap-1 border-border bg-background px-2 py-1.5 shadow-sm hover:bg-muted cursor-pointer",
6034
6200
  onClick: onBack,
6035
6201
  children: [
6036
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react10.ArrowLeft, { className: "size-4 shrink-0", "aria-hidden": true }),
6202
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react10.ArrowLeft, { className: "size-4 shrink-0", "aria-hidden": true }),
6037
6203
  "Back"
6038
6204
  ]
6039
6205
  }
6040
6206
  )
6041
6207
  }
6042
6208
  ),
6043
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
6209
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6044
6210
  "div",
6045
6211
  {
6046
6212
  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",
@@ -6053,7 +6219,7 @@ function SectionPickerOverlay({
6053
6219
  children: "Click on section to select"
6054
6220
  }
6055
6221
  ),
6056
- !isOnTargetPage ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
6222
+ !isOnTargetPage ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6057
6223
  "div",
6058
6224
  {
6059
6225
  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",
@@ -6061,14 +6227,14 @@ function SectionPickerOverlay({
6061
6227
  children: "Loading page preview\u2026"
6062
6228
  }
6063
6229
  ) : null,
6064
- isOnTargetPage && liveSections.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "pointer-events-auto fixed inset-0 z-[1] flex items-center justify-center bg-muted/40", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." }) }) : null,
6230
+ isOnTargetPage && liveSections.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "pointer-events-auto fixed inset-0 z-[1] flex items-center justify-center bg-muted/40", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." }) }) : null,
6065
6231
  isOnTargetPage ? liveSections.map((section) => {
6066
6232
  const rect = rects.get(section.id);
6067
6233
  if (!rect || rect.width <= 0 || rect.height <= 0) return null;
6068
6234
  const isSelected = selectedId === section.id;
6069
6235
  const isHovered = hoveredId === section.id;
6070
6236
  const isLit = isSelected || isHovered;
6071
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
6237
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
6072
6238
  "button",
6073
6239
  {
6074
6240
  type: "button",
@@ -6083,7 +6249,7 @@ function SectionPickerOverlay({
6083
6249
  "aria-label": `Select section ${section.label}`,
6084
6250
  onClick: () => handleSelect(section),
6085
6251
  children: [
6086
- isLit ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
6252
+ isLit ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6087
6253
  "span",
6088
6254
  {
6089
6255
  className: "pointer-events-none absolute",
@@ -6096,13 +6262,13 @@ function SectionPickerOverlay({
6096
6262
  "aria-hidden": true
6097
6263
  }
6098
6264
  ) : null,
6099
- isSelected ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
6265
+ isSelected ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6100
6266
  "span",
6101
6267
  {
6102
6268
  className: "absolute right-3 top-3 flex size-8 items-center justify-center rounded-full text-white",
6103
6269
  style: { backgroundColor: "var(--ohw-primary, #0885fe)" },
6104
6270
  "aria-hidden": true,
6105
- children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react10.Check, { className: "size-5" })
6271
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react10.Check, { className: "size-5" })
6106
6272
  }
6107
6273
  ) : null
6108
6274
  ]
@@ -6118,7 +6284,7 @@ function SectionPickerOverlay({
6118
6284
  }
6119
6285
 
6120
6286
  // src/ui/link-modal/useLinkModalState.ts
6121
- var import_react6 = require("react");
6287
+ var import_react7 = require("react");
6122
6288
  function useLinkModalState({
6123
6289
  open,
6124
6290
  mode,
@@ -6130,14 +6296,14 @@ function useLinkModalState({
6130
6296
  onClose,
6131
6297
  onSubmit
6132
6298
  }) {
6133
- const availablePages = (0, import_react6.useMemo)(() => pages, [pages]);
6134
- const [searchValue, setSearchValue] = (0, import_react6.useState)("");
6135
- const [selectedPage, setSelectedPage] = (0, import_react6.useState)(null);
6136
- const [selectedSection, setSelectedSection] = (0, import_react6.useState)(null);
6137
- const [step, setStep] = (0, import_react6.useState)("input");
6138
- const [dropdownOpen, setDropdownOpen] = (0, import_react6.useState)(false);
6139
- const [urlError, setUrlError] = (0, import_react6.useState)("");
6140
- const reset = (0, import_react6.useCallback)(() => {
6299
+ const availablePages = (0, import_react7.useMemo)(() => pages, [pages]);
6300
+ const [searchValue, setSearchValue] = (0, import_react7.useState)("");
6301
+ const [selectedPage, setSelectedPage] = (0, import_react7.useState)(null);
6302
+ const [selectedSection, setSelectedSection] = (0, import_react7.useState)(null);
6303
+ const [step, setStep] = (0, import_react7.useState)("input");
6304
+ const [dropdownOpen, setDropdownOpen] = (0, import_react7.useState)(false);
6305
+ const [urlError, setUrlError] = (0, import_react7.useState)("");
6306
+ const reset = (0, import_react7.useCallback)(() => {
6141
6307
  setSearchValue("");
6142
6308
  setSelectedPage(null);
6143
6309
  setSelectedSection(null);
@@ -6145,7 +6311,7 @@ function useLinkModalState({
6145
6311
  setDropdownOpen(false);
6146
6312
  setUrlError("");
6147
6313
  }, []);
6148
- (0, import_react6.useEffect)(() => {
6314
+ (0, import_react7.useEffect)(() => {
6149
6315
  if (!open) return;
6150
6316
  if (mode === "edit" && initialTarget) {
6151
6317
  const { pageRoute } = parseTarget(initialTarget);
@@ -6161,11 +6327,11 @@ function useLinkModalState({
6161
6327
  setDropdownOpen(false);
6162
6328
  setUrlError("");
6163
6329
  }, [open, mode, initialTarget, reset]);
6164
- const filteredPages = (0, import_react6.useMemo)(() => {
6330
+ const filteredPages = (0, import_react7.useMemo)(() => {
6165
6331
  if (!searchValue.trim()) return availablePages;
6166
6332
  return availablePages.filter((p) => p.title.toLowerCase().startsWith(searchValue.toLowerCase()));
6167
6333
  }, [availablePages, searchValue]);
6168
- const activeSections = (0, import_react6.useMemo)(() => {
6334
+ const activeSections = (0, import_react7.useMemo)(() => {
6169
6335
  if (!selectedPage) return [];
6170
6336
  return getSectionsForPath(sectionsByPath, selectedPage.path);
6171
6337
  }, [selectedPage, sectionsByPath]);
@@ -6214,7 +6380,7 @@ function useLinkModalState({
6214
6380
  reset();
6215
6381
  onClose();
6216
6382
  };
6217
- const isValid = (0, import_react6.useMemo)(() => {
6383
+ const isValid = (0, import_react7.useMemo)(() => {
6218
6384
  if (urlError) return false;
6219
6385
  if (showBreadcrumb) return true;
6220
6386
  if (selectedPage) return true;
@@ -6282,7 +6448,7 @@ function useLinkModalState({
6282
6448
  }
6283
6449
 
6284
6450
  // src/ui/link-modal/LinkPopover.tsx
6285
- var import_jsx_runtime21 = require("react/jsx-runtime");
6451
+ var import_jsx_runtime22 = require("react/jsx-runtime");
6286
6452
  function postToParent(data) {
6287
6453
  window.parent?.postMessage(data, "*");
6288
6454
  }
@@ -6311,7 +6477,7 @@ function LinkPopover({
6311
6477
  onSubmit
6312
6478
  });
6313
6479
  const sectionPickerActive = state.showSectionPicker && Boolean(state.selectedPage);
6314
- (0, import_react7.useEffect)(() => {
6480
+ (0, import_react8.useEffect)(() => {
6315
6481
  if (!open) return;
6316
6482
  if (sectionPickerActive) {
6317
6483
  postToParent({ type: "ui:unlock" });
@@ -6378,15 +6544,15 @@ function LinkPopover({
6378
6544
  );
6379
6545
  };
6380
6546
  }, [open, sectionPickerActive]);
6381
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
6382
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6547
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
6548
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
6383
6549
  Dialog2,
6384
6550
  {
6385
6551
  open: open && !sectionPickerActive,
6386
6552
  onOpenChange: (next) => {
6387
6553
  if (!next) onClose?.();
6388
6554
  },
6389
- children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6555
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
6390
6556
  DialogContent,
6391
6557
  {
6392
6558
  ref: panelRef,
@@ -6396,12 +6562,12 @@ function LinkPopover({
6396
6562
  "data-ohw-bridge": "",
6397
6563
  showCloseButton: false,
6398
6564
  className: "gap-0 p-0 w-full max-w-[448px] pointer-events-auto z-[2147483646] overflow-visible",
6399
- children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(LinkEditorPanel, { state, onClose })
6565
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(LinkEditorPanel, { state, onClose })
6400
6566
  }
6401
6567
  )
6402
6568
  }
6403
6569
  ),
6404
- sectionPickerActive && state.selectedPage ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6570
+ sectionPickerActive && state.selectedPage ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
6405
6571
  SectionPickerOverlay,
6406
6572
  {
6407
6573
  pagePath: state.selectedPage.path,
@@ -6890,6 +7056,22 @@ function navbarIndexExistsInDom(index) {
6890
7056
  return document.querySelector(`[data-ohw-href-key="nav-${index}-href"]`) !== null;
6891
7057
  }
6892
7058
  function reconcileNavbarItemsFromContent(content) {
7059
+ const orderForest = parseNavOrderJson(content[NAV_ORDER_KEY]);
7060
+ if (orderForest?.length) {
7061
+ const allowed = new Set(flattenNavOrder(orderForest));
7062
+ for (const hrefKey of allowed) {
7063
+ const index = parseNavIndexFromKey(hrefKey);
7064
+ if (index === null) continue;
7065
+ if (navbarIndexExistsInDom(index)) continue;
7066
+ const href = content[`nav-${index}-href`];
7067
+ const label = content[`nav-${index}-label`];
7068
+ if (!href && !label) continue;
7069
+ insertNavbarItemDom(index, href ?? "/", label ?? "Untitled", null);
7070
+ }
7071
+ pruneNavbarItemsNotInOrder(allowed);
7072
+ applyNavForest(orderForest);
7073
+ return;
7074
+ }
6893
7075
  const indices = collectNavbarIndicesFromContent(content);
6894
7076
  for (const index of indices) {
6895
7077
  if (navbarIndexExistsInDom(index)) continue;
@@ -6898,9 +7080,22 @@ function reconcileNavbarItemsFromContent(content) {
6898
7080
  if (!href && !label) continue;
6899
7081
  insertNavbarItemDom(index, href ?? "/", label ?? "Untitled", null);
6900
7082
  }
6901
- const orderForest = parseNavOrderJson(content[NAV_ORDER_KEY]);
6902
- if (orderForest?.length) {
6903
- applyNavForest(orderForest);
7083
+ }
7084
+ function pruneNavbarItemsNotInOrder(allowed) {
7085
+ const roots = [getNavbarDesktopContainer(), getNavbarDrawerContainer()].filter(
7086
+ (el) => Boolean(el)
7087
+ );
7088
+ const searchRoots = roots.length > 0 ? roots : [document.body];
7089
+ for (const root of searchRoots) {
7090
+ const items = Array.from(root.querySelectorAll("[data-ohw-href-key]")).filter(
7091
+ isNavbarLinkItem
7092
+ );
7093
+ for (const item of items) {
7094
+ if (!item.isConnected) continue;
7095
+ const key = item.getAttribute("data-ohw-href-key");
7096
+ if (!key || !isNavbarHrefKey(key) || allowed.has(key)) continue;
7097
+ resolveRemovableNavUnit(item).remove();
7098
+ }
6904
7099
  }
6905
7100
  }
6906
7101
  function buildNavOrderAfterInsert(afterAnchor, newHrefKey) {
@@ -6940,9 +7135,126 @@ function insertNavbarItem(href, label, afterAnchor = null) {
6940
7135
  order
6941
7136
  };
6942
7137
  }
7138
+ function duplicateNavbarItem(sourceAnchor) {
7139
+ if (!isNavbarLinkItem(sourceAnchor)) return null;
7140
+ const sourceHrefKey = sourceAnchor.getAttribute("data-ohw-href-key");
7141
+ if (!sourceHrefKey || !isNavbarHrefKey(sourceHrefKey)) return null;
7142
+ const href = getLinkHref(sourceAnchor);
7143
+ const labelEl = sourceAnchor.querySelector('[data-ohw-editable="text"]');
7144
+ const label = (labelEl?.textContent ?? "").trim() || "Untitled";
7145
+ const forest = getNavForestFromDom();
7146
+ const sourceNode = forest.find((n) => n.id === sourceHrefKey);
7147
+ const childIds = sourceNode?.children.map((c) => c.id) ?? [];
7148
+ const primary = insertNavbarItem(href, label, sourceAnchor);
7149
+ const childResults = [];
7150
+ let after = primary.anchor;
7151
+ for (const childId of childIds) {
7152
+ const childEl = findCounterpartByHrefKey(childId, document) ?? document.querySelector(`[data-ohw-href-key="${CSS.escape(childId)}"]`);
7153
+ if (!childEl || !isNavbarLinkItem(childEl)) continue;
7154
+ const childHref = getLinkHref(childEl);
7155
+ const childLabelEl = childEl.querySelector('[data-ohw-editable="text"]');
7156
+ const childLabel = (childLabelEl?.textContent ?? "").trim() || "Untitled";
7157
+ const inserted = insertNavbarItem(childHref, childLabel, after);
7158
+ childResults.push(inserted);
7159
+ after = inserted.anchor;
7160
+ }
7161
+ let orderJson;
7162
+ if (childResults.length > 0) {
7163
+ const nextForest = getNavForestFromDom();
7164
+ const withoutNew = nextForest.filter(
7165
+ (n) => n.id !== primary.hrefKey && !childResults.some((c) => c.hrefKey === n.id)
7166
+ );
7167
+ const sourceIdx = withoutNew.findIndex((n) => n.id === sourceHrefKey);
7168
+ const insertAt = sourceIdx >= 0 ? sourceIdx + 1 : withoutNew.length;
7169
+ withoutNew.splice(insertAt, 0, {
7170
+ id: primary.hrefKey,
7171
+ children: childResults.map((c) => ({ id: c.hrefKey, children: [] }))
7172
+ });
7173
+ applyNavForest(withoutNew);
7174
+ orderJson = serializeNavOrder(withoutNew);
7175
+ } else {
7176
+ orderJson = serializeNavOrder(getNavForestFromDom());
7177
+ }
7178
+ return {
7179
+ ...primary,
7180
+ order: flattenNavOrder(parseNavOrderJson(orderJson) ?? getNavForestFromDom()),
7181
+ childResults,
7182
+ orderJson
7183
+ };
7184
+ }
7185
+ function collectSubtreeHrefKeys(node) {
7186
+ const keys = [node.id];
7187
+ for (const child of node.children) {
7188
+ keys.push(...collectSubtreeHrefKeys(child));
7189
+ }
7190
+ return keys;
7191
+ }
7192
+ function labelKeyFromHrefKey(hrefKey) {
7193
+ return hrefKey.replace(/-href$/, "-label");
7194
+ }
7195
+ function resolveRemovableNavUnit(anchor) {
7196
+ if (anchor.closest("[data-ohw-nav-children]")) return anchor;
7197
+ const group = anchor.closest("[data-ohw-nav-group]");
7198
+ if (group?.querySelector(":scope > [data-ohw-nav-children]")) return group;
7199
+ return anchor;
7200
+ }
7201
+ function deleteNavbarItem(sourceAnchor) {
7202
+ if (!isNavbarLinkItem(sourceAnchor)) return null;
7203
+ const sourceHrefKey = sourceAnchor.getAttribute("data-ohw-href-key");
7204
+ if (!sourceHrefKey || !isNavbarHrefKey(sourceHrefKey)) return null;
7205
+ const labelEl = sourceAnchor.querySelector('[data-ohw-editable="text"]');
7206
+ const label = (labelEl?.textContent ?? "").trim() || "Untitled";
7207
+ const previousForest = getNavForestFromDom();
7208
+ const previousOrderJson = serializeNavOrder(previousForest);
7209
+ const taken = takeNode(previousForest, sourceHrefKey);
7210
+ if (!taken) return null;
7211
+ const removedHrefKeys = collectSubtreeHrefKeys(taken.taken);
7212
+ const removedKeys = removedHrefKeys.flatMap((hrefKey) => [hrefKey, labelKeyFromHrefKey(hrefKey)]);
7213
+ const previousContent = {};
7214
+ for (const hrefKey of removedHrefKeys) {
7215
+ const el = findCounterpartByHrefKey(hrefKey, document) ?? document.querySelector(`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`);
7216
+ previousContent[hrefKey] = el ? getLinkHref(el) : "";
7217
+ const labEl = el?.querySelector('[data-ohw-editable="text"]');
7218
+ previousContent[labelKeyFromHrefKey(hrefKey)] = (labEl?.textContent ?? "").trim();
7219
+ }
7220
+ const roots = [getNavbarDesktopContainer(), getNavbarDrawerContainer()].filter(
7221
+ (el) => Boolean(el)
7222
+ );
7223
+ const searchRoots = roots.length > 0 ? roots : [document.body];
7224
+ const placements = [];
7225
+ for (const root of searchRoots) {
7226
+ const primary = findCounterpartByHrefKey(sourceHrefKey, root);
7227
+ if (!primary?.isConnected || !primary.parentElement) continue;
7228
+ const unit = resolveRemovableNavUnit(primary);
7229
+ if (!unit.parentElement) continue;
7230
+ placements.push({
7231
+ node: unit,
7232
+ parent: unit.parentElement,
7233
+ nextSibling: unit.nextSibling
7234
+ });
7235
+ unit.remove();
7236
+ }
7237
+ applyNavForest(taken.forest);
7238
+ const orderJson = serializeNavOrder(taken.forest);
7239
+ return {
7240
+ label,
7241
+ hrefKey: sourceHrefKey,
7242
+ removedKeys,
7243
+ previousContent,
7244
+ orderJson,
7245
+ previousOrderJson,
7246
+ undo: () => {
7247
+ for (const placement of placements) {
7248
+ placement.parent.insertBefore(placement.node, placement.nextSibling);
7249
+ }
7250
+ applyNavForest(previousForest);
7251
+ }
7252
+ };
7253
+ }
6943
7254
 
6944
7255
  // src/lib/footer-items.ts
6945
7256
  var FOOTER_ORDER_KEY = "__ohw_footer_order";
7257
+ var MAX_FOOTER_COLUMNS = 18;
6946
7258
  var FOOTER_HREF_RE = /^footer-(\d+)-(\d+)-href$/;
6947
7259
  function parseFooterHrefKey(key) {
6948
7260
  if (!key) return null;
@@ -7123,22 +7435,266 @@ function parseFooterOrder(content) {
7123
7435
  return null;
7124
7436
  }
7125
7437
  }
7438
+ var FOOTER_HEADING_RE = /^footer-(\d+)-heading$/;
7439
+ var FOOTER_LABEL_RE = /^footer-(\d+)-(\d+)-label$/;
7440
+ var DEFAULT_FOOTER_COLUMN_HEADING = "New";
7441
+ var DEFAULT_FOOTER_COLUMN_LINK_LABEL = "New link";
7442
+ var DEFAULT_FOOTER_COLUMN_LINK_HREF = "";
7443
+ function isFooterLinksContainer(el) {
7444
+ return el.hasAttribute("data-ohw-footer-links") || el.classList.contains("rb-footer-links");
7445
+ }
7446
+ function getFooterColumnIndicesInDom() {
7447
+ const indices = /* @__PURE__ */ new Set();
7448
+ for (const col of listFooterColumns()) {
7449
+ const attr = col.getAttribute("data-ohw-footer-col");
7450
+ if (attr != null) {
7451
+ const n = parseInt(attr, 10);
7452
+ if (Number.isFinite(n)) indices.add(n);
7453
+ }
7454
+ for (const link of listFooterLinksInColumn(col)) {
7455
+ const parsed = parseFooterHrefKey(link.getAttribute("data-ohw-href-key"));
7456
+ if (parsed) indices.add(parsed.col);
7457
+ }
7458
+ const heading = col.querySelector('[data-ohw-key^="footer-"][data-ohw-key$="-heading"]');
7459
+ const headingKey = heading?.getAttribute("data-ohw-key");
7460
+ if (headingKey) {
7461
+ const match = headingKey.match(FOOTER_HEADING_RE);
7462
+ if (match) indices.add(parseInt(match[1], 10));
7463
+ }
7464
+ }
7465
+ return [...indices].sort((a, b) => a - b);
7466
+ }
7467
+ function getNextFooterColumnIndex() {
7468
+ const indices = getFooterColumnIndicesInDom();
7469
+ if (indices.length === 0) return 0;
7470
+ return Math.max(...indices) + 1;
7471
+ }
7472
+ function canAddFooterColumn() {
7473
+ return listFooterColumns().length < MAX_FOOTER_COLUMNS;
7474
+ }
7475
+ function buildFooterHeading(colIndex, text) {
7476
+ const heading = document.createElement("p");
7477
+ heading.setAttribute("data-ohw-editable", "text");
7478
+ heading.setAttribute("data-ohw-key", `footer-${colIndex}-heading`);
7479
+ heading.textContent = text;
7480
+ heading.style.cssText = [
7481
+ "color: var(--espresso, #3d312b)",
7482
+ "font-size: 14px",
7483
+ "font-weight: 800",
7484
+ "opacity: 0.82",
7485
+ "margin: 0 0 6px",
7486
+ "padding: 0",
7487
+ "line-height: 1.2"
7488
+ ].join(";");
7489
+ return heading;
7490
+ }
7491
+ function buildFooterLink(colIndex, itemIndex, href, label, template) {
7492
+ const anchor = cloneFooterLinkShell(template);
7493
+ anchor.setAttribute("href", href);
7494
+ anchor.setAttribute("data-ohw-href-key", `footer-${colIndex}-${itemIndex}-href`);
7495
+ const span = document.createElement("span");
7496
+ span.setAttribute("data-ohw-editable", "text");
7497
+ span.setAttribute("data-ohw-key", `footer-${colIndex}-${itemIndex}-label`);
7498
+ span.textContent = label;
7499
+ anchor.appendChild(span);
7500
+ return anchor;
7501
+ }
7502
+ function footerColumnExistsInDom(colIndex) {
7503
+ 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;
7504
+ }
7505
+ function getFooterLinkTemplate() {
7506
+ for (const col of listFooterColumns()) {
7507
+ const link = listFooterLinksInColumn(col)[0];
7508
+ if (link) return link;
7509
+ }
7510
+ return null;
7511
+ }
7512
+ function getFooterColumnTemplate() {
7513
+ return listFooterColumns()[0] ?? null;
7514
+ }
7515
+ function insertFooterColumnDom(colIndex, heading, items) {
7516
+ const container = getFooterLinksContainer();
7517
+ if (!container) return null;
7518
+ const colTemplate = getFooterColumnTemplate();
7519
+ const linkTemplate = getFooterLinkTemplate();
7520
+ const column = document.createElement("div");
7521
+ if (colTemplate?.className) column.className = colTemplate.className;
7522
+ else column.className = "rb-footer-link-col";
7523
+ column.setAttribute("data-ohw-footer-col", String(colIndex));
7524
+ if (colTemplate) {
7525
+ const gap = getComputedStyle(colTemplate).gap;
7526
+ if (gap && gap !== "normal") column.style.gap = gap;
7527
+ column.style.display = getComputedStyle(colTemplate).display || "flex";
7528
+ column.style.flexDirection = "column";
7529
+ }
7530
+ column.appendChild(buildFooterHeading(colIndex, heading));
7531
+ let firstLink = null;
7532
+ items.forEach((item, itemIndex) => {
7533
+ const link = buildFooterLink(colIndex, itemIndex, item.href, item.label, linkTemplate);
7534
+ column.appendChild(link);
7535
+ if (!firstLink) firstLink = link;
7536
+ });
7537
+ container.appendChild(column);
7538
+ return { column, firstLink };
7539
+ }
7540
+ function insertFooterColumn(heading = DEFAULT_FOOTER_COLUMN_HEADING, linkLabel = DEFAULT_FOOTER_COLUMN_LINK_LABEL, linkHref = DEFAULT_FOOTER_COLUMN_LINK_HREF) {
7541
+ if (!canAddFooterColumn()) {
7542
+ throw new Error(`Footer column limit reached (${MAX_FOOTER_COLUMNS})`);
7543
+ }
7544
+ const colIndex = getNextFooterColumnIndex();
7545
+ const inserted = insertFooterColumnDom(colIndex, heading, [{ href: linkHref, label: linkLabel }]);
7546
+ if (!inserted?.firstLink) throw new Error("Failed to insert footer column");
7547
+ syncFooterColumnIndices(listFooterColumns());
7548
+ return {
7549
+ column: inserted.column,
7550
+ firstLink: inserted.firstLink,
7551
+ colIndex,
7552
+ headingKey: `footer-${colIndex}-heading`,
7553
+ hrefKey: `footer-${colIndex}-0-href`,
7554
+ labelKey: `footer-${colIndex}-0-label`,
7555
+ heading,
7556
+ label: linkLabel,
7557
+ href: linkHref,
7558
+ order: getFooterOrderFromDom()
7559
+ };
7560
+ }
7561
+ function collectFooterColumnIndicesFromContent(content) {
7562
+ const indices = /* @__PURE__ */ new Set();
7563
+ for (const key of Object.keys(content)) {
7564
+ const href = parseFooterHrefKey(key);
7565
+ if (href) indices.add(href.col);
7566
+ const heading = key.match(FOOTER_HEADING_RE);
7567
+ if (heading) indices.add(parseInt(heading[1], 10));
7568
+ const label = key.match(FOOTER_LABEL_RE);
7569
+ if (label) indices.add(parseInt(label[1], 10));
7570
+ }
7571
+ const order = parseFooterOrder(content);
7572
+ if (order) {
7573
+ for (const col of order) {
7574
+ for (const hrefKey of col) {
7575
+ const parsed = parseFooterHrefKey(hrefKey);
7576
+ if (parsed) indices.add(parsed.col);
7577
+ }
7578
+ }
7579
+ }
7580
+ return [...indices].sort((a, b) => a - b);
7581
+ }
7582
+ function collectFooterItemsForColumn(content, colIndex) {
7583
+ const itemIndices = /* @__PURE__ */ new Set();
7584
+ for (const key of Object.keys(content)) {
7585
+ const href = parseFooterHrefKey(key);
7586
+ if (href?.col === colIndex) itemIndices.add(href.item);
7587
+ const label = key.match(FOOTER_LABEL_RE);
7588
+ if (label && parseInt(label[1], 10) === colIndex) {
7589
+ itemIndices.add(parseInt(label[2], 10));
7590
+ }
7591
+ }
7592
+ const sorted = [...itemIndices].sort((a, b) => a - b);
7593
+ if (sorted.length === 0) {
7594
+ return [
7595
+ {
7596
+ href: content[`footer-${colIndex}-0-href`] ?? DEFAULT_FOOTER_COLUMN_LINK_HREF,
7597
+ label: content[`footer-${colIndex}-0-label`] ?? DEFAULT_FOOTER_COLUMN_LINK_LABEL
7598
+ }
7599
+ ];
7600
+ }
7601
+ return sorted.map((itemIndex) => ({
7602
+ href: content[`footer-${colIndex}-${itemIndex}-href`] ?? DEFAULT_FOOTER_COLUMN_LINK_HREF,
7603
+ label: content[`footer-${colIndex}-${itemIndex}-label`] ?? DEFAULT_FOOTER_COLUMN_LINK_LABEL
7604
+ }));
7605
+ }
7606
+ function reconcileFooterColumnsFromContent(content) {
7607
+ const order = parseFooterOrder(content);
7608
+ const allowedCols = order ? new Set(
7609
+ order.flatMap(
7610
+ (col) => col.map((k) => parseFooterHrefKey(k)?.col).filter((n) => n !== void 0 && n !== null)
7611
+ )
7612
+ ) : null;
7613
+ const indices = collectFooterColumnIndicesFromContent(content);
7614
+ for (const colIndex of indices) {
7615
+ if (allowedCols && !allowedCols.has(colIndex)) continue;
7616
+ if (footerColumnExistsInDom(colIndex)) continue;
7617
+ const heading = content[`footer-${colIndex}-heading`] ?? DEFAULT_FOOTER_COLUMN_HEADING;
7618
+ const items = collectFooterItemsForColumn(content, colIndex);
7619
+ const hasPayload = Boolean(content[`footer-${colIndex}-heading`]) || items.some(
7620
+ (_, i) => content[`footer-${colIndex}-${i}-href`] !== void 0 || content[`footer-${colIndex}-${i}-label`] !== void 0
7621
+ ) || (order?.some((col) => col.some((k) => parseFooterHrefKey(k)?.col === colIndex)) ?? false);
7622
+ if (!hasPayload) continue;
7623
+ insertFooterColumnDom(colIndex, heading, items);
7624
+ }
7625
+ }
7126
7626
  function reconcileFooterOrderFromContent(content) {
7627
+ reconcileFooterColumnsFromContent(content);
7127
7628
  const order = parseFooterOrder(content);
7128
7629
  if (!order?.length) return;
7129
- const current = getFooterOrderFromDom();
7130
- if (ordersEqual(order, current)) {
7131
- syncFooterColumnIndices(listFooterColumns());
7132
- return;
7630
+ const linkTemplate = getFooterLinkTemplate();
7631
+ for (let c = 0; c < order.length; c++) {
7632
+ const colOrder = order[c];
7633
+ for (const hrefKey of colOrder) {
7634
+ if (findFooterLinkByKey(hrefKey)) continue;
7635
+ const parsed = parseFooterHrefKey(hrefKey);
7636
+ if (!parsed) continue;
7637
+ const columns = listFooterColumns();
7638
+ const column = columns.find((col) => col.getAttribute("data-ohw-footer-col") === String(parsed.col)) ?? columns[c] ?? null;
7639
+ if (!column) continue;
7640
+ const href = content[hrefKey] ?? DEFAULT_FOOTER_COLUMN_LINK_HREF;
7641
+ const labelKey = `footer-${parsed.col}-${parsed.item}-label`;
7642
+ const label = content[labelKey] ?? DEFAULT_FOOTER_COLUMN_LINK_LABEL;
7643
+ if (!href && !label) continue;
7644
+ column.appendChild(buildFooterLink(parsed.col, parsed.item, href || "/", label, linkTemplate));
7645
+ }
7133
7646
  }
7647
+ pruneFooterToOrder(order);
7134
7648
  applyFooterOrder(order);
7135
7649
  }
7136
- function isRowLayoutColumn(links) {
7137
- if (links.length < 2) return false;
7138
- const firstTop = links[0].getBoundingClientRect().top;
7139
- return links.every((link) => Math.abs(link.getBoundingClientRect().top - firstTop) < 4);
7140
- }
7141
- function buildLinkDropSlots(column, columnIndex) {
7650
+ function pruneFooterToOrder(order) {
7651
+ const allowedKeys = new Set(order.flat());
7652
+ const allowedColIndices = new Set(
7653
+ [...allowedKeys].map((k) => parseFooterHrefKey(k)?.col).filter((n) => n !== void 0 && n !== null)
7654
+ );
7655
+ for (const column of [...listFooterColumns()]) {
7656
+ if (!column.isConnected) continue;
7657
+ for (const link of [...listFooterLinksInColumn(column)]) {
7658
+ const key = link.getAttribute("data-ohw-href-key");
7659
+ if (!key || allowedKeys.has(key)) continue;
7660
+ link.remove();
7661
+ }
7662
+ const remaining = listFooterLinksInColumn(column);
7663
+ const colAttr = column.getAttribute("data-ohw-footer-col");
7664
+ const colIndex = colAttr != null ? parseInt(colAttr, 10) : NaN;
7665
+ const referenced = remaining.some((link) => allowedKeys.has(link.getAttribute("data-ohw-href-key") ?? ""));
7666
+ if (!referenced && (!Number.isFinite(colIndex) || !allowedColIndices.has(colIndex))) {
7667
+ column.remove();
7668
+ }
7669
+ }
7670
+ syncFooterColumnIndices(listFooterColumns());
7671
+ }
7672
+ function resolveFooterLinksContainerSelectionTarget(target, clientX, clientY, isPointOverItem) {
7673
+ const container = getFooterLinksContainer();
7674
+ if (!container) return null;
7675
+ const inContainer = target === container || container.contains(target) && Boolean(target.closest("[data-ohw-footer-links], .rb-footer-links"));
7676
+ if (!inContainer && target !== container) {
7677
+ const r2 = container.getBoundingClientRect();
7678
+ const over = clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom;
7679
+ if (!over) return null;
7680
+ }
7681
+ if (isPointOverItem(container, clientX, clientY)) return null;
7682
+ const column = target.closest("[data-ohw-footer-col], [data-ohw-footer-column]") ?? null;
7683
+ if (column && container.contains(column)) {
7684
+ if (target === column || column.contains(target)) return null;
7685
+ }
7686
+ if (target === container || container.contains(target) || inContainer) {
7687
+ if (target === container || isFooterLinksContainer(target)) return container;
7688
+ if (!column) return container;
7689
+ }
7690
+ return null;
7691
+ }
7692
+ function isRowLayoutColumn(links) {
7693
+ if (links.length < 2) return false;
7694
+ const firstTop = links[0].getBoundingClientRect().top;
7695
+ return links.every((link) => Math.abs(link.getBoundingClientRect().top - firstTop) < 4);
7696
+ }
7697
+ function buildLinkDropSlots(column, columnIndex) {
7142
7698
  const links = listFooterLinksInColumn(column);
7143
7699
  const colRect = column.getBoundingClientRect();
7144
7700
  const slots = [];
@@ -7287,6 +7843,197 @@ function hitTestColumnDropSlot(clientX, _clientY) {
7287
7843
  }
7288
7844
  return best?.slot ?? null;
7289
7845
  }
7846
+ function getLinkHref2(el) {
7847
+ const key = el.getAttribute("data-ohw-href-key");
7848
+ if (key) {
7849
+ const stored = getStoredLinkHref(key);
7850
+ if (stored !== void 0) return stored;
7851
+ }
7852
+ return el.getAttribute("href") ?? "";
7853
+ }
7854
+ function getNextFooterItemIndex(col) {
7855
+ let max = -1;
7856
+ for (const el of document.querySelectorAll("footer [data-ohw-href-key]")) {
7857
+ const parsed = parseFooterHrefKey(el.getAttribute("data-ohw-href-key"));
7858
+ if (!parsed || parsed.col !== col) continue;
7859
+ if (parsed.item > max) max = parsed.item;
7860
+ }
7861
+ return max + 1;
7862
+ }
7863
+ function cloneFooterLinkShell(template) {
7864
+ const anchor = document.createElement("a");
7865
+ if (template) {
7866
+ anchor.style.cssText = template.style.cssText;
7867
+ if (template.className) anchor.className = template.className;
7868
+ }
7869
+ anchor.style.cursor = "pointer";
7870
+ anchor.style.textDecoration = "none";
7871
+ return anchor;
7872
+ }
7873
+ function insertFooterItem(column, href, label, afterAnchor = null) {
7874
+ const columns = listFooterColumns();
7875
+ const colIndex = columns.indexOf(column);
7876
+ if (colIndex < 0) throw new Error("Footer column not found");
7877
+ const item = getNextFooterItemIndex(colIndex);
7878
+ const hrefKey = `footer-${colIndex}-${item}-href`;
7879
+ const labelKey = `footer-${colIndex}-${item}-label`;
7880
+ const template = listFooterLinksInColumn(column)[0] ?? null;
7881
+ const anchor = cloneFooterLinkShell(template);
7882
+ anchor.href = href;
7883
+ anchor.setAttribute("data-ohw-href-key", hrefKey);
7884
+ const span = document.createElement("span");
7885
+ span.setAttribute("data-ohw-editable", "text");
7886
+ span.setAttribute("data-ohw-key", labelKey);
7887
+ span.textContent = label;
7888
+ anchor.appendChild(span);
7889
+ if (afterAnchor && afterAnchor.parentElement === column) {
7890
+ afterAnchor.insertAdjacentElement("afterend", anchor);
7891
+ } else {
7892
+ column.appendChild(anchor);
7893
+ }
7894
+ const order = getFooterOrderFromDom();
7895
+ applyFooterOrder(order);
7896
+ return {
7897
+ anchor,
7898
+ col: colIndex,
7899
+ item,
7900
+ hrefKey,
7901
+ labelKey,
7902
+ href,
7903
+ label,
7904
+ order
7905
+ };
7906
+ }
7907
+ function duplicateFooterItem(sourceAnchor) {
7908
+ if (!isFooterLinkAnchor(sourceAnchor)) return null;
7909
+ const column = findFooterColumnForLink(sourceAnchor);
7910
+ if (!column) return null;
7911
+ const href = getLinkHref2(sourceAnchor);
7912
+ const labelEl = sourceAnchor.querySelector('[data-ohw-editable="text"]');
7913
+ const label = (labelEl?.textContent ?? "").trim() || "Untitled";
7914
+ return insertFooterItem(column, href || "/", label, sourceAnchor);
7915
+ }
7916
+ function footerLabelKeyFromHrefKey(hrefKey) {
7917
+ return hrefKey.replace(/-href$/, "-label");
7918
+ }
7919
+ function deleteFooterItem(sourceAnchor) {
7920
+ if (!isFooterLinkAnchor(sourceAnchor)) return null;
7921
+ const hrefKey = sourceAnchor.getAttribute("data-ohw-href-key");
7922
+ if (!hrefKey || !isFooterHrefKey(hrefKey)) return null;
7923
+ const labelEl = sourceAnchor.querySelector('[data-ohw-editable="text"]');
7924
+ const label = (labelEl?.textContent ?? "").trim() || "Untitled";
7925
+ const labelKey = footerLabelKeyFromHrefKey(hrefKey);
7926
+ const previousOrder = getFooterOrderFromDom();
7927
+ const previousOrderJson = JSON.stringify(previousOrder);
7928
+ const previousContent = {
7929
+ [hrefKey]: getLinkHref2(sourceAnchor),
7930
+ [labelKey]: label
7931
+ };
7932
+ if (!sourceAnchor.parentElement) return null;
7933
+ const placement = {
7934
+ node: sourceAnchor,
7935
+ parent: sourceAnchor.parentElement,
7936
+ nextSibling: sourceAnchor.nextSibling
7937
+ };
7938
+ sourceAnchor.remove();
7939
+ const order = getFooterOrderFromDom();
7940
+ applyFooterOrder(order);
7941
+ const orderJson = JSON.stringify(order);
7942
+ return {
7943
+ label,
7944
+ removedKeys: [hrefKey, labelKey],
7945
+ previousContent,
7946
+ orderJson,
7947
+ previousOrderJson,
7948
+ undo: () => {
7949
+ placement.parent.insertBefore(placement.node, placement.nextSibling);
7950
+ applyFooterOrder(previousOrder);
7951
+ }
7952
+ };
7953
+ }
7954
+ function deleteFooterColumn(column) {
7955
+ const columns = listFooterColumns();
7956
+ if (!columns.includes(column)) return null;
7957
+ if (!column.parentElement) return null;
7958
+ const links = listFooterLinksInColumn(column);
7959
+ const heading = column.querySelector(
7960
+ '[data-ohw-key^="footer-"][data-ohw-key$="-heading"]'
7961
+ );
7962
+ const headingKey = heading?.getAttribute("data-ohw-key") ?? null;
7963
+ const headingText = (heading?.textContent ?? "").trim();
7964
+ const label = headingText || (links[0]?.querySelector('[data-ohw-editable="text"]')?.textContent ?? "").trim() || "Untitled";
7965
+ const previousOrder = getFooterOrderFromDom();
7966
+ const previousOrderJson = JSON.stringify(previousOrder);
7967
+ const previousContent = {};
7968
+ const removedKeys = [];
7969
+ if (headingKey) {
7970
+ removedKeys.push(headingKey);
7971
+ previousContent[headingKey] = headingText;
7972
+ }
7973
+ for (const link of links) {
7974
+ const hrefKey = link.getAttribute("data-ohw-href-key");
7975
+ if (!hrefKey) continue;
7976
+ const labelKey = footerLabelKeyFromHrefKey(hrefKey);
7977
+ removedKeys.push(hrefKey, labelKey);
7978
+ previousContent[hrefKey] = getLinkHref2(link);
7979
+ previousContent[labelKey] = (link.querySelector('[data-ohw-editable="text"]')?.textContent ?? "").trim();
7980
+ }
7981
+ const placement = {
7982
+ node: column,
7983
+ parent: column.parentElement,
7984
+ nextSibling: column.nextSibling
7985
+ };
7986
+ column.remove();
7987
+ const remaining = listFooterColumns();
7988
+ syncFooterColumnIndices(remaining);
7989
+ const order = getFooterOrderFromDom();
7990
+ applyFooterOrder(order);
7991
+ const orderJson = JSON.stringify(order);
7992
+ return {
7993
+ label,
7994
+ removedKeys,
7995
+ previousContent,
7996
+ orderJson,
7997
+ previousOrderJson,
7998
+ undo: () => {
7999
+ placement.parent.insertBefore(placement.node, placement.nextSibling);
8000
+ syncFooterColumnIndices(listFooterColumns());
8001
+ applyFooterOrder(previousOrder);
8002
+ }
8003
+ };
8004
+ }
8005
+
8006
+ // src/lib/add-footer-column.ts
8007
+ function buildFooterColumnEditContentPatch(result) {
8008
+ return {
8009
+ [result.headingKey]: result.heading,
8010
+ [result.hrefKey]: result.href,
8011
+ [result.labelKey]: result.label,
8012
+ [FOOTER_ORDER_KEY]: JSON.stringify(result.order)
8013
+ };
8014
+ }
8015
+ function addFooterColumnWithPersist({
8016
+ postToParent: postToParent2
8017
+ }) {
8018
+ if (!canAddFooterColumn()) {
8019
+ postToParent2({
8020
+ type: "ow:toast",
8021
+ title: `Maximum ${MAX_FOOTER_COLUMNS} columns`,
8022
+ toastType: "error"
8023
+ });
8024
+ return null;
8025
+ }
8026
+ const result = insertFooterColumn();
8027
+ const patch = buildFooterColumnEditContentPatch(result);
8028
+ setStoredLinkHref(result.hrefKey, result.href);
8029
+ postToParent2({
8030
+ type: "ow:change",
8031
+ nodes: Object.entries(patch).map(([key, text]) => ({ key, text }))
8032
+ });
8033
+ postToParent2({ type: "ow:toast", title: "Item added", toastType: "success" });
8034
+ enforceLinkHrefs();
8035
+ return result;
8036
+ }
7290
8037
 
7291
8038
  // src/lib/item-drag-interaction.ts
7292
8039
  function disableNativeHrefDrag(el) {
@@ -7485,7 +8232,7 @@ function hitTestNavDropSlot(clientX, clientY, draggedHrefKey) {
7485
8232
  }
7486
8233
 
7487
8234
  // src/useNavItemDrag.ts
7488
- var import_react8 = require("react");
8235
+ var import_react9 = require("react");
7489
8236
  function useNavItemDrag({
7490
8237
  isEditMode,
7491
8238
  editContentRef,
@@ -7510,11 +8257,11 @@ function useNavItemDrag({
7510
8257
  isDragHandleDisabled: isDragHandleDisabled2,
7511
8258
  isNavbarButton: isNavbarButton3
7512
8259
  }) {
7513
- const navDragRef = (0, import_react8.useRef)(null);
7514
- const [navDropSlots, setNavDropSlots] = (0, import_react8.useState)([]);
7515
- const [activeNavDropIndex, setActiveNavDropIndex] = (0, import_react8.useState)(null);
7516
- const navPointerDragRef = (0, import_react8.useRef)(null);
7517
- const clearNavDragVisuals = (0, import_react8.useCallback)(() => {
8260
+ const navDragRef = (0, import_react9.useRef)(null);
8261
+ const [navDropSlots, setNavDropSlots] = (0, import_react9.useState)([]);
8262
+ const [activeNavDropIndex, setActiveNavDropIndex] = (0, import_react9.useState)(null);
8263
+ const navPointerDragRef = (0, import_react9.useRef)(null);
8264
+ const clearNavDragVisuals = (0, import_react9.useCallback)(() => {
7518
8265
  navDragRef.current = null;
7519
8266
  setNavDropSlots([]);
7520
8267
  setActiveNavDropIndex(null);
@@ -7523,7 +8270,7 @@ function useNavItemDrag({
7523
8270
  setIsItemDragging(false);
7524
8271
  unlockItemDragInteraction();
7525
8272
  }, [setDraggedItemRect, setIsItemDragging, setSiblingHintRects]);
7526
- const refreshNavDragVisuals = (0, import_react8.useCallback)(
8273
+ const refreshNavDragVisuals = (0, import_react9.useCallback)(
7527
8274
  (session, activeSlot, clientX, clientY) => {
7528
8275
  setDraggedItemRect(session.draggedEl.getBoundingClientRect());
7529
8276
  if (typeof clientX === "number" && typeof clientY === "number") {
@@ -7541,13 +8288,13 @@ function useNavItemDrag({
7541
8288
  },
7542
8289
  [setDraggedItemRect, setSiblingHintRects]
7543
8290
  );
7544
- const refreshNavDragVisualsRef = (0, import_react8.useRef)(refreshNavDragVisuals);
8291
+ const refreshNavDragVisualsRef = (0, import_react9.useRef)(refreshNavDragVisuals);
7545
8292
  refreshNavDragVisualsRef.current = refreshNavDragVisuals;
7546
- const commitNavDragRef = (0, import_react8.useRef)(() => {
8293
+ const commitNavDragRef = (0, import_react9.useRef)(() => {
7547
8294
  });
7548
- const beginNavDragRef = (0, import_react8.useRef)(() => {
8295
+ const beginNavDragRef = (0, import_react9.useRef)(() => {
7549
8296
  });
7550
- const beginNavDrag = (0, import_react8.useCallback)(
8297
+ const beginNavDrag = (0, import_react9.useCallback)(
7551
8298
  (session) => {
7552
8299
  const rect = session.draggedEl.getBoundingClientRect();
7553
8300
  session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
@@ -7574,7 +8321,7 @@ function useNavItemDrag({
7574
8321
  ]
7575
8322
  );
7576
8323
  beginNavDragRef.current = beginNavDrag;
7577
- const commitNavDrag = (0, import_react8.useCallback)(
8324
+ const commitNavDrag = (0, import_react9.useCallback)(
7578
8325
  (clientX, clientY) => {
7579
8326
  const session = navDragRef.current;
7580
8327
  if (!session) {
@@ -7635,7 +8382,7 @@ function useNavItemDrag({
7635
8382
  [clearNavDragVisuals, deselectRef, editContentRef, postToParentRef, selectRef]
7636
8383
  );
7637
8384
  commitNavDragRef.current = commitNavDrag;
7638
- const startNavLinkDrag = (0, import_react8.useCallback)(
8385
+ const startNavLinkDrag = (0, import_react9.useCallback)(
7639
8386
  (anchor, clientX, clientY, wasSelected) => {
7640
8387
  if (footerDragRef.current) return false;
7641
8388
  const hrefKey = anchor.getAttribute("data-ohw-href-key");
@@ -7653,7 +8400,7 @@ function useNavItemDrag({
7653
8400
  },
7654
8401
  [beginNavDrag, footerDragRef, isDragHandleDisabled2, isNavbarButton3]
7655
8402
  );
7656
- const onNavDragOver = (0, import_react8.useCallback)(
8403
+ const onNavDragOver = (0, import_react9.useCallback)(
7657
8404
  (e) => {
7658
8405
  const session = navDragRef.current;
7659
8406
  if (!session) return false;
@@ -7665,7 +8412,7 @@ function useNavItemDrag({
7665
8412
  },
7666
8413
  []
7667
8414
  );
7668
- (0, import_react8.useEffect)(() => {
8415
+ (0, import_react9.useEffect)(() => {
7669
8416
  if (!isEditMode) return;
7670
8417
  const THRESHOLD = 10;
7671
8418
  const resolveWasSelected = (el) => {
@@ -7790,7 +8537,7 @@ function useNavItemDrag({
7790
8537
  setLinkPopover,
7791
8538
  suppressNextClickRef
7792
8539
  ]);
7793
- const armNavPressFromChrome = (0, import_react8.useCallback)(
8540
+ const armNavPressFromChrome = (0, import_react9.useCallback)(
7794
8541
  (selected, clientX, clientY, pointerId) => {
7795
8542
  const hrefKey = selected.getAttribute("data-ohw-href-key");
7796
8543
  if (!hrefKey || !isNavbarHrefKey(hrefKey)) return false;
@@ -7820,8 +8567,59 @@ function useNavItemDrag({
7820
8567
  };
7821
8568
  }
7822
8569
 
8570
+ // src/ui/footer-container-chrome.tsx
8571
+ var import_lucide_react11 = require("lucide-react");
8572
+ var import_jsx_runtime23 = require("react/jsx-runtime");
8573
+ function FooterContainerChrome({
8574
+ rect,
8575
+ onAdd,
8576
+ addDisabled = false
8577
+ }) {
8578
+ const chromeGap = 6;
8579
+ const buttonMargin = 7;
8580
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8581
+ "div",
8582
+ {
8583
+ "data-ohw-footer-container-chrome": "",
8584
+ "data-ohw-bridge": "",
8585
+ className: "pointer-events-none fixed z-[2147483647]",
8586
+ style: {
8587
+ top: rect.top - chromeGap,
8588
+ left: rect.left - chromeGap,
8589
+ width: rect.width + chromeGap * 2,
8590
+ height: rect.height + chromeGap * 2
8591
+ },
8592
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(Tooltip, { children: [
8593
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8594
+ "button",
8595
+ {
8596
+ type: "button",
8597
+ "data-ohw-footer-add-button": "",
8598
+ disabled: addDisabled,
8599
+ 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",
8600
+ style: { top: chromeGap - buttonMargin },
8601
+ "aria-label": "Add item",
8602
+ onMouseDown: (e) => {
8603
+ e.preventDefault();
8604
+ e.stopPropagation();
8605
+ },
8606
+ onClick: (e) => {
8607
+ e.preventDefault();
8608
+ e.stopPropagation();
8609
+ if (addDisabled) return;
8610
+ onAdd();
8611
+ },
8612
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react11.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
8613
+ }
8614
+ ) }),
8615
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
8616
+ ] })
8617
+ }
8618
+ ) });
8619
+ }
8620
+
7823
8621
  // src/lib/carousel.ts
7824
- var import_react9 = require("react");
8622
+ var import_react10 = require("react");
7825
8623
  var CAROUSEL_ATTR = "data-ohw-carousel";
7826
8624
  var CAROUSEL_VALUE_ATTR = "data-ohw-carousel-value";
7827
8625
  var CAROUSEL_SLIDE_ATTR = "data-ohw-carousel-slide";
@@ -7883,8 +8681,8 @@ function applyCarouselNode(key, val) {
7883
8681
  return true;
7884
8682
  }
7885
8683
  function useOhwCarousel(key, initial) {
7886
- const [images, setImages] = (0, import_react9.useState)(initial);
7887
- (0, import_react9.useEffect)(() => {
8684
+ const [images, setImages] = (0, import_react10.useState)(initial);
8685
+ (0, import_react10.useEffect)(() => {
7888
8686
  const el = document.querySelector(
7889
8687
  `[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`
7890
8688
  );
@@ -7904,15 +8702,340 @@ function useOhwCarousel(key, initial) {
7904
8702
  return { images, setImages, bind };
7905
8703
  }
7906
8704
 
8705
+ // src/lib/collect-editable-nodes.ts
8706
+ var VIDEO_AUTOPLAY_SUFFIX = "__ohw_autoplay";
8707
+ var VIDEO_MUTED_SUFFIX = "__ohw_muted";
8708
+ function getVideoEl(el) {
8709
+ return el instanceof HTMLVideoElement ? el : el.querySelector("video");
8710
+ }
8711
+ function getLinkHref3(el) {
8712
+ const key = el.getAttribute("data-ohw-href-key");
8713
+ if (key) {
8714
+ const stored = getStoredLinkHref(key);
8715
+ if (stored !== void 0) return stored;
8716
+ }
8717
+ const anchor = el instanceof HTMLAnchorElement ? el : el.querySelector("a");
8718
+ return anchor?.getAttribute("href") ?? "";
8719
+ }
8720
+ function collectEditableNodes(extraContent) {
8721
+ const nodes = Array.from(
8722
+ document.querySelectorAll("[data-ohw-editable]")
8723
+ ).map((el) => {
8724
+ if (el.dataset.ohwEditable === "image") {
8725
+ const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
8726
+ return { key: el.dataset.ohwKey ?? "", type: "image", text: img?.src ?? "" };
8727
+ }
8728
+ if (el.dataset.ohwEditable === "bg-image") {
8729
+ const raw = el.style.backgroundImage;
8730
+ const url = raw.replace(/^url\(['"]?/, "").replace(/['"]?\)$/, "");
8731
+ return { key: el.dataset.ohwKey ?? "", type: "bg-image", text: url };
8732
+ }
8733
+ if (el.dataset.ohwEditable === "video") {
8734
+ return { key: el.dataset.ohwKey ?? "", type: "video", text: getVideoEl(el)?.src ?? "" };
8735
+ }
8736
+ if (el.dataset.ohwEditable === "link") {
8737
+ return { key: el.dataset.ohwKey ?? "", type: "link", text: getLinkHref3(el) };
8738
+ }
8739
+ return {
8740
+ key: el.dataset.ohwKey ?? "",
8741
+ type: el.dataset.ohwEditable ?? "text",
8742
+ text: el.dataset.ohwEditable === "plain" ? el.innerText ?? "" : el.innerHTML
8743
+ };
8744
+ });
8745
+ document.querySelectorAll("[data-ohw-href-key]").forEach((el) => {
8746
+ const key = el.getAttribute("data-ohw-href-key") ?? "";
8747
+ if (!key) return;
8748
+ nodes.push({ key, type: "link", text: getLinkHref3(el) });
8749
+ });
8750
+ if (extraContent) {
8751
+ for (const key of [NAV_ORDER_KEY, FOOTER_ORDER_KEY, NAV_COUNT_KEY]) {
8752
+ const text = extraContent[key];
8753
+ if (typeof text === "string" && text.length > 0) {
8754
+ nodes.push({ key, type: "meta", text });
8755
+ }
8756
+ }
8757
+ }
8758
+ document.querySelectorAll('[data-ohw-editable="video"]').forEach((el) => {
8759
+ const key = el.dataset.ohwKey ?? "";
8760
+ const video = getVideoEl(el);
8761
+ if (!key || !video) return;
8762
+ nodes.push({
8763
+ key: `${key}${VIDEO_AUTOPLAY_SUFFIX}`,
8764
+ type: "video-setting",
8765
+ text: String(video.autoplay)
8766
+ });
8767
+ nodes.push({
8768
+ key: `${key}${VIDEO_MUTED_SUFFIX}`,
8769
+ type: "video-setting",
8770
+ text: String(video.muted)
8771
+ });
8772
+ });
8773
+ for (const key of listCarouselKeys()) {
8774
+ nodes.push({ key, type: "carousel", text: JSON.stringify(readCarouselValue(key)) });
8775
+ }
8776
+ const byKey = /* @__PURE__ */ new Map();
8777
+ for (const node of nodes) {
8778
+ if (!node.key) continue;
8779
+ if (!byKey.has(node.key)) byKey.set(node.key, node);
8780
+ }
8781
+ if (extraContent) {
8782
+ applyNavFooterDeleteOverrides(byKey, extraContent);
8783
+ }
8784
+ return Array.from(byKey.values());
8785
+ }
8786
+ function applyNavFooterDeleteOverrides(byKey, content) {
8787
+ for (const [key, text] of Object.entries(content)) {
8788
+ if (text !== "") continue;
8789
+ if (!key.startsWith("nav-") && !key.startsWith("footer-")) continue;
8790
+ if (key === "nav-book-href" || key === "nav-book-label") continue;
8791
+ byKey.set(key, { key, type: "meta", text: "" });
8792
+ }
8793
+ const navOrder = content[NAV_ORDER_KEY];
8794
+ if (navOrder) {
8795
+ try {
8796
+ const allowed = parseAllowedNavHrefKeys(navOrder);
8797
+ const clearKey = (key) => {
8798
+ byKey.set(key, { key, type: "meta", text: "" });
8799
+ };
8800
+ for (const key of /* @__PURE__ */ new Set([...byKey.keys(), ...Object.keys(content)])) {
8801
+ if (key === "nav-book-href" || key === "nav-book-label") continue;
8802
+ if (isNavbarHrefKey(key) && !allowed.has(key)) {
8803
+ clearKey(key);
8804
+ clearKey(key.replace(/-href$/, "-label"));
8805
+ } else if (/^nav-\d+-label$/.test(key)) {
8806
+ const hrefKey = key.replace(/-label$/, "-href");
8807
+ if (!allowed.has(hrefKey)) clearKey(key);
8808
+ }
8809
+ }
8810
+ } catch {
8811
+ }
8812
+ }
8813
+ const footerOrder = content[FOOTER_ORDER_KEY];
8814
+ if (footerOrder) {
8815
+ try {
8816
+ const { allowedKeys, allowedCols } = parseAllowedFooterKeys(footerOrder);
8817
+ const clearKey = (key) => {
8818
+ byKey.set(key, { key, type: "meta", text: "" });
8819
+ };
8820
+ for (const key of /* @__PURE__ */ new Set([...byKey.keys(), ...Object.keys(content)])) {
8821
+ if (isFooterHrefKey(key) && !allowedKeys.has(key)) {
8822
+ clearKey(key);
8823
+ clearKey(key.replace(/-href$/, "-label"));
8824
+ continue;
8825
+ }
8826
+ const labelMatch = key.match(/^footer-(\d+)-(\d+)-label$/);
8827
+ if (labelMatch) {
8828
+ const hrefKey = `footer-${labelMatch[1]}-${labelMatch[2]}-href`;
8829
+ if (!allowedKeys.has(hrefKey)) clearKey(key);
8830
+ continue;
8831
+ }
8832
+ const headingMatch = key.match(/^footer-(\d+)-heading$/);
8833
+ if (headingMatch && !allowedCols.has(parseInt(headingMatch[1], 10))) {
8834
+ clearKey(key);
8835
+ }
8836
+ }
8837
+ } catch {
8838
+ }
8839
+ }
8840
+ }
8841
+ function parseAllowedNavHrefKeys(raw) {
8842
+ const parsed = JSON.parse(raw);
8843
+ const allowed = /* @__PURE__ */ new Set();
8844
+ const walk = (nodes) => {
8845
+ if (!Array.isArray(nodes)) return;
8846
+ for (const node of nodes) {
8847
+ if (typeof node === "string" && node.length > 0) {
8848
+ allowed.add(node);
8849
+ continue;
8850
+ }
8851
+ if (node && typeof node === "object" && typeof node.id === "string") {
8852
+ allowed.add(node.id);
8853
+ walk(node.children);
8854
+ }
8855
+ }
8856
+ };
8857
+ walk(parsed);
8858
+ return allowed;
8859
+ }
8860
+ function parseAllowedFooterKeys(raw) {
8861
+ const parsed = JSON.parse(raw);
8862
+ const allowedKeys = /* @__PURE__ */ new Set();
8863
+ const allowedCols = /* @__PURE__ */ new Set();
8864
+ if (Array.isArray(parsed)) {
8865
+ for (const col of parsed) {
8866
+ if (!Array.isArray(col)) continue;
8867
+ for (const key of col) {
8868
+ if (typeof key !== "string" || !key) continue;
8869
+ allowedKeys.add(key);
8870
+ const m = key.match(/^footer-(\d+)-\d+-href$/);
8871
+ if (m) allowedCols.add(parseInt(m[1], 10));
8872
+ }
8873
+ }
8874
+ }
8875
+ return { allowedKeys, allowedCols };
8876
+ }
8877
+
8878
+ // src/lib/delete-nav-footer-selection.ts
8879
+ function isNavbarLinksContainer(el) {
8880
+ return el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer");
8881
+ }
8882
+ function isNavigationItem(el) {
8883
+ const anchor = el.matches("[data-ohw-href-key]") ? el : el.closest("[data-ohw-href-key]");
8884
+ if (!anchor) return false;
8885
+ return Boolean(anchor.querySelector('[data-ohw-editable="text"]'));
8886
+ }
8887
+ function findFooterItemGroup(item) {
8888
+ const explicit = item.closest("[data-ohw-footer-col], [data-ohw-footer-column]");
8889
+ if (explicit) return explicit;
8890
+ const footer = item.closest("footer");
8891
+ if (!footer) return null;
8892
+ let node = item.parentElement;
8893
+ while (node && node !== footer) {
8894
+ const count = Array.from(node.querySelectorAll("[data-ohw-href-key]")).filter(
8895
+ isNavigationItem
8896
+ ).length;
8897
+ if (count >= 2) return node;
8898
+ node = node.parentElement;
8899
+ }
8900
+ return footer;
8901
+ }
8902
+ function isInferredFooterGroup(el) {
8903
+ const footer = el.closest("footer");
8904
+ if (!footer || el === footer) return false;
8905
+ if (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column")) return true;
8906
+ const count = Array.from(el.querySelectorAll("[data-ohw-href-key]")).filter(
8907
+ isNavigationItem
8908
+ ).length;
8909
+ return count >= 2;
8910
+ }
8911
+ function newActionId() {
8912
+ return typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `delete-${Date.now()}`;
8913
+ }
8914
+ function deleteSelectedNavFooterItem(deps) {
8915
+ const {
8916
+ selected,
8917
+ isTextEditing,
8918
+ isSelectFrame,
8919
+ getEditContent,
8920
+ applyLinkByKey: applyLinkByKey2,
8921
+ postToParent: postToParent2,
8922
+ deselect,
8923
+ setEditContent,
8924
+ setPendingUndo
8925
+ } = deps;
8926
+ if (isTextEditing) return false;
8927
+ if (isNavbarLinksContainer(selected) || isFooterLinksContainer(selected)) return false;
8928
+ const finishDelete = (opts) => {
8929
+ const actionId = newActionId();
8930
+ const clearedNodes = opts.removedKeys.map((key) => ({
8931
+ key,
8932
+ text: ""
8933
+ }));
8934
+ clearedNodes.push({ key: opts.orderKey, text: opts.orderJson });
8935
+ const nextContent = { ...getEditContent() };
8936
+ for (const key of opts.removedKeys) {
8937
+ nextContent[key] = "";
8938
+ clearStoredLinkHref(key);
8939
+ }
8940
+ nextContent[opts.orderKey] = opts.orderJson;
8941
+ setEditContent(nextContent);
8942
+ postToParent2({ type: "ow:change", nodes: clearedNodes });
8943
+ setPendingUndo({
8944
+ actionId,
8945
+ restore: () => {
8946
+ opts.undoDom();
8947
+ for (const [key, text] of Object.entries(opts.previousContent)) {
8948
+ if (key.endsWith("-href")) applyLinkByKey2(key, text);
8949
+ else {
8950
+ document.querySelectorAll(`[data-ohw-key="${CSS.escape(key)}"]`).forEach((el) => {
8951
+ el.textContent = text;
8952
+ });
8953
+ }
8954
+ }
8955
+ setEditContent({
8956
+ ...getEditContent(),
8957
+ ...opts.previousContent,
8958
+ [opts.orderKey]: opts.previousOrderJson
8959
+ });
8960
+ postToParent2({
8961
+ type: "ow:change",
8962
+ nodes: [
8963
+ ...Object.entries(opts.previousContent).map(([key, text]) => ({ key, text })),
8964
+ { key: opts.orderKey, text: opts.previousOrderJson }
8965
+ ]
8966
+ });
8967
+ }
8968
+ });
8969
+ deselect();
8970
+ postToParent2({
8971
+ type: "ow:toast",
8972
+ title: opts.toastTitle,
8973
+ toastType: "success",
8974
+ actionLabel: "Undo",
8975
+ actionId,
8976
+ duration: 6e3
8977
+ });
8978
+ };
8979
+ const isFooterColumnSelection = selected.hasAttribute("data-ohw-footer-col") || selected.hasAttribute("data-ohw-footer-column") || isSelectFrame && isInferredFooterGroup(selected) && Boolean(selected.closest("footer"));
8980
+ if (isFooterColumnSelection) {
8981
+ const column = selected.hasAttribute("data-ohw-footer-col") || selected.hasAttribute("data-ohw-footer-column") ? selected : findFooterItemGroup(selected);
8982
+ if (!column) return false;
8983
+ const result = deleteFooterColumn(column);
8984
+ if (!result) return false;
8985
+ finishDelete({
8986
+ toastTitle: "Item deleted",
8987
+ removedKeys: result.removedKeys,
8988
+ previousContent: result.previousContent,
8989
+ orderKey: FOOTER_ORDER_KEY,
8990
+ orderJson: result.orderJson,
8991
+ previousOrderJson: result.previousOrderJson,
8992
+ undoDom: result.undo
8993
+ });
8994
+ return true;
8995
+ }
8996
+ if (!isNavigationItem(selected)) return false;
8997
+ const hrefKey = selected.getAttribute("data-ohw-href-key");
8998
+ if (!hrefKey) return false;
8999
+ if (isNavbarHrefKey(hrefKey)) {
9000
+ const result = deleteNavbarItem(selected);
9001
+ if (!result) return false;
9002
+ finishDelete({
9003
+ toastTitle: "Nav item deleted",
9004
+ removedKeys: result.removedKeys,
9005
+ previousContent: result.previousContent,
9006
+ orderKey: NAV_ORDER_KEY,
9007
+ orderJson: result.orderJson,
9008
+ previousOrderJson: result.previousOrderJson,
9009
+ undoDom: result.undo
9010
+ });
9011
+ return true;
9012
+ }
9013
+ if (isFooterHrefKey(hrefKey)) {
9014
+ const result = deleteFooterItem(selected);
9015
+ if (!result) return false;
9016
+ finishDelete({
9017
+ toastTitle: "Item deleted",
9018
+ removedKeys: result.removedKeys,
9019
+ previousContent: result.previousContent,
9020
+ orderKey: FOOTER_ORDER_KEY,
9021
+ orderJson: result.orderJson,
9022
+ previousOrderJson: result.previousOrderJson,
9023
+ undoDom: result.undo
9024
+ });
9025
+ return true;
9026
+ }
9027
+ return false;
9028
+ }
9029
+
7907
9030
  // src/ui/navbar-container-chrome.tsx
7908
- var import_lucide_react11 = require("lucide-react");
7909
- var import_jsx_runtime22 = require("react/jsx-runtime");
9031
+ var import_lucide_react12 = require("lucide-react");
9032
+ var import_jsx_runtime24 = require("react/jsx-runtime");
7910
9033
  function NavbarContainerChrome({
7911
9034
  rect,
7912
9035
  onAdd
7913
9036
  }) {
7914
9037
  const chromeGap = 6;
7915
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
9038
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
7916
9039
  "div",
7917
9040
  {
7918
9041
  "data-ohw-navbar-container-chrome": "",
@@ -7924,7 +9047,7 @@ function NavbarContainerChrome({
7924
9047
  width: rect.width + chromeGap * 2,
7925
9048
  height: rect.height + chromeGap * 2
7926
9049
  },
7927
- children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
9050
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
7928
9051
  "button",
7929
9052
  {
7930
9053
  type: "button",
@@ -7941,7 +9064,7 @@ function NavbarContainerChrome({
7941
9064
  e.stopPropagation();
7942
9065
  onAdd();
7943
9066
  },
7944
- children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react11.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
9067
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react12.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
7945
9068
  }
7946
9069
  )
7947
9070
  }
@@ -7950,7 +9073,7 @@ function NavbarContainerChrome({
7950
9073
 
7951
9074
  // src/ui/drop-indicator.tsx
7952
9075
  var React10 = __toESM(require("react"), 1);
7953
- var import_jsx_runtime23 = require("react/jsx-runtime");
9076
+ var import_jsx_runtime25 = require("react/jsx-runtime");
7954
9077
  var dropIndicatorVariants = cva(
7955
9078
  "ov-gap-line pointer-events-none shrink-0 transition-opacity duration-150",
7956
9079
  {
@@ -7974,7 +9097,7 @@ var dropIndicatorVariants = cva(
7974
9097
  );
7975
9098
  var DropIndicator = React10.forwardRef(
7976
9099
  ({ className, direction, state, ...props }, ref) => {
7977
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
9100
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
7978
9101
  "div",
7979
9102
  {
7980
9103
  ref,
@@ -7991,7 +9114,7 @@ var DropIndicator = React10.forwardRef(
7991
9114
  DropIndicator.displayName = "DropIndicator";
7992
9115
 
7993
9116
  // src/ui/badge.tsx
7994
- var import_jsx_runtime24 = require("react/jsx-runtime");
9117
+ var import_jsx_runtime26 = require("react/jsx-runtime");
7995
9118
  var badgeVariants = cva(
7996
9119
  "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",
7997
9120
  {
@@ -8009,12 +9132,12 @@ var badgeVariants = cva(
8009
9132
  }
8010
9133
  );
8011
9134
  function Badge({ className, variant, ...props }) {
8012
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: cn(badgeVariants({ variant }), className), ...props });
9135
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: cn(badgeVariants({ variant }), className), ...props });
8013
9136
  }
8014
9137
 
8015
9138
  // src/OhhwellsBridge.tsx
8016
- var import_lucide_react12 = require("lucide-react");
8017
- var import_jsx_runtime25 = require("react/jsx-runtime");
9139
+ var import_lucide_react13 = require("lucide-react");
9140
+ var import_jsx_runtime27 = require("react/jsx-runtime");
8018
9141
  var PRIMARY2 = "#0885FE";
8019
9142
  var IMAGE_FADE_MS = 300;
8020
9143
  function runOpacityFade(el, onDone) {
@@ -8193,7 +9316,7 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
8193
9316
  const root = (0, import_client.createRoot)(container);
8194
9317
  (0, import_react_dom2.flushSync)(() => {
8195
9318
  root.render(
8196
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
9319
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
8197
9320
  SchedulingWidget,
8198
9321
  {
8199
9322
  notifyOnConnect,
@@ -8233,7 +9356,7 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
8233
9356
  }
8234
9357
  }
8235
9358
  }
8236
- function getLinkHref2(el) {
9359
+ function getLinkHref4(el) {
8237
9360
  const anchor = el instanceof HTMLAnchorElement ? el : el.querySelector("a");
8238
9361
  return anchor?.getAttribute("href") ?? "";
8239
9362
  }
@@ -8261,78 +9384,22 @@ function canDragNavigationItem(anchor) {
8261
9384
  }
8262
9385
  function syncNavigationDragCursorAttrs() {
8263
9386
  document.querySelectorAll("nav [data-ohw-href-key], footer [data-ohw-href-key]").forEach((el) => {
8264
- if (!isNavigationItem(el) || !canDragNavigationItem(el)) {
9387
+ if (!isNavigationItem2(el) || !canDragNavigationItem(el)) {
8265
9388
  el.removeAttribute("data-ohw-can-drag");
8266
9389
  return;
8267
9390
  }
8268
9391
  el.setAttribute("data-ohw-can-drag", "");
8269
9392
  });
8270
9393
  }
8271
- function collectEditableNodes(extraContent) {
8272
- const nodes = Array.from(document.querySelectorAll("[data-ohw-editable]")).map((el) => {
8273
- if (el.dataset.ohwEditable === "image") {
8274
- const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
8275
- return { key: el.dataset.ohwKey ?? "", type: "image", text: img?.src ?? "" };
8276
- }
8277
- if (el.dataset.ohwEditable === "bg-image") {
8278
- const raw = el.style.backgroundImage;
8279
- const url = raw.replace(/^url\(['"]?/, "").replace(/['"]?\)$/, "");
8280
- return { key: el.dataset.ohwKey ?? "", type: "bg-image", text: url };
8281
- }
8282
- if (el.dataset.ohwEditable === "video") {
8283
- return { key: el.dataset.ohwKey ?? "", type: "video", text: getVideoEl(el)?.src ?? "" };
8284
- }
8285
- if (el.dataset.ohwEditable === "link") {
8286
- return { key: el.dataset.ohwKey ?? "", type: "link", text: getLinkHref2(el) };
8287
- }
8288
- return {
8289
- key: el.dataset.ohwKey ?? "",
8290
- type: el.dataset.ohwEditable ?? "text",
8291
- text: el.dataset.ohwEditable === "plain" ? el.innerText ?? "" : el.innerHTML
8292
- };
8293
- });
8294
- document.querySelectorAll("[data-ohw-href-key]").forEach((el) => {
8295
- const key = el.getAttribute("data-ohw-href-key") ?? "";
8296
- if (!key) return;
8297
- nodes.push({ key, type: "link", text: getLinkHref2(el) });
8298
- });
8299
- if (extraContent) {
8300
- for (const key of [NAV_ORDER_KEY, FOOTER_ORDER_KEY, NAV_COUNT_KEY]) {
8301
- const text = extraContent[key];
8302
- if (typeof text === "string" && text.length > 0) {
8303
- nodes.push({ key, type: "meta", text });
8304
- }
8305
- }
8306
- }
8307
- document.querySelectorAll('[data-ohw-editable="video"]').forEach((el) => {
8308
- const key = el.dataset.ohwKey ?? "";
8309
- const video = getVideoEl(el);
8310
- if (!key || !video) return;
8311
- nodes.push({ key: `${key}${VIDEO_AUTOPLAY_SUFFIX}`, type: "video-setting", text: String(video.autoplay) });
8312
- nodes.push({ key: `${key}${VIDEO_MUTED_SUFFIX}`, type: "video-setting", text: String(video.muted) });
8313
- });
8314
- for (const key of listCarouselKeys()) {
8315
- nodes.push({ key, type: "carousel", text: JSON.stringify(readCarouselValue(key)) });
8316
- }
8317
- const seen = /* @__PURE__ */ new Set();
8318
- return nodes.filter((node) => {
8319
- if (!node.key) return true;
8320
- if (seen.has(node.key)) return false;
8321
- seen.add(node.key);
8322
- return true;
8323
- });
8324
- }
8325
9394
  function isMediaEditable(el) {
8326
9395
  const t = el.dataset.ohwEditable;
8327
9396
  return t === "image" || t === "bg-image" || t === "video";
8328
9397
  }
8329
9398
  var MEDIA_SELECTOR = '[data-ohw-editable="image"], [data-ohw-editable="bg-image"], [data-ohw-editable="video"]';
8330
9399
  var NON_MEDIA_SELECTOR = '[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"])';
8331
- function getVideoEl(el) {
9400
+ function getVideoEl2(el) {
8332
9401
  return el instanceof HTMLVideoElement ? el : el.querySelector("video");
8333
9402
  }
8334
- var VIDEO_AUTOPLAY_SUFFIX = "__ohw_autoplay";
8335
- var VIDEO_MUTED_SUFFIX = "__ohw_muted";
8336
9403
  function isBackgroundVideo(video) {
8337
9404
  return video.autoplay && video.muted;
8338
9405
  }
@@ -8377,7 +9444,7 @@ function applyVideoSettingNode(key, val) {
8377
9444
  const baseKey = key.slice(0, key.length - suffixLen);
8378
9445
  const on = val === "true";
8379
9446
  document.querySelectorAll(`[data-ohw-key="${baseKey}"]`).forEach((el) => {
8380
- const video = getVideoEl(el);
9447
+ const video = getVideoEl2(el);
8381
9448
  if (!video) return;
8382
9449
  if (isAutoplay) video.autoplay = on;
8383
9450
  else video.muted = on;
@@ -8397,7 +9464,7 @@ function applyLinkByKey(key, val) {
8397
9464
  }
8398
9465
  function isInsideLinkEditor(target) {
8399
9466
  return Boolean(
8400
- 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"]')
9467
+ 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"]')
8401
9468
  );
8402
9469
  }
8403
9470
  function getHrefKeyFromElement(el) {
@@ -8417,13 +9484,13 @@ function getNavigationItemAnchor(el) {
8417
9484
  if (!anchor.querySelector('[data-ohw-editable="text"]')) return null;
8418
9485
  return anchor;
8419
9486
  }
8420
- function isNavigationItem(el) {
9487
+ function isNavigationItem2(el) {
8421
9488
  return getNavigationItemAnchor(el) !== null;
8422
9489
  }
8423
9490
  function listNavigationItems() {
8424
9491
  return Array.from(
8425
9492
  document.querySelectorAll("nav [data-ohw-href-key], footer [data-ohw-href-key]")
8426
- ).filter((el) => isNavigationItem(el));
9493
+ ).filter((el) => isNavigationItem2(el));
8427
9494
  }
8428
9495
  function getNavigationItemReorderState(anchor) {
8429
9496
  if (isNavbarButton2(anchor)) return { key: null, disabled: false };
@@ -8454,9 +9521,9 @@ function getNavigationRoot(el) {
8454
9521
  return el.closest("nav, footer, aside");
8455
9522
  }
8456
9523
  function countFooterNavItems(el) {
8457
- return Array.from(el.querySelectorAll("[data-ohw-href-key]")).filter(isNavigationItem).length;
9524
+ return Array.from(el.querySelectorAll("[data-ohw-href-key]")).filter(isNavigationItem2).length;
8458
9525
  }
8459
- function findFooterItemGroup(item) {
9526
+ function findFooterItemGroup2(item) {
8460
9527
  const explicit = item.closest("[data-ohw-footer-col], [data-ohw-footer-column]");
8461
9528
  if (explicit) return explicit;
8462
9529
  const footer = item.closest("footer");
@@ -8471,16 +9538,16 @@ function findFooterItemGroup(item) {
8471
9538
  function isNavigationRoot(el) {
8472
9539
  return el.hasAttribute("data-ohw-nav-root") || el.matches("nav, footer, aside");
8473
9540
  }
8474
- function isInferredFooterGroup(el) {
9541
+ function isInferredFooterGroup2(el) {
8475
9542
  const footer = el.closest("footer");
8476
9543
  if (!footer || el === footer) return false;
8477
9544
  if (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column")) return true;
8478
9545
  return countFooterNavItems(el) >= 2;
8479
9546
  }
8480
9547
  function isNavigationContainer(el) {
8481
- return el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isNavigationRoot(el) || isInferredFooterGroup(el);
9548
+ 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);
8482
9549
  }
8483
- function isNavbarLinksContainer(el) {
9550
+ function isNavbarLinksContainer2(el) {
8484
9551
  return el.hasAttribute("data-ohw-nav-container");
8485
9552
  }
8486
9553
  function getFooterColumn(el) {
@@ -8497,6 +9564,9 @@ function isPointOverNavigation(x, y) {
8497
9564
  const roots = /* @__PURE__ */ new Set();
8498
9565
  const navRoot = document.querySelector("[data-ohw-nav-root]") ?? document.querySelector("nav");
8499
9566
  if (navRoot) roots.add(navRoot);
9567
+ document.querySelectorAll("[data-ohw-nav-drawer], [data-ohw-nav-container]").forEach((el) => {
9568
+ roots.add(el);
9569
+ });
8500
9570
  const footer = document.querySelector("footer");
8501
9571
  if (footer) roots.add(footer);
8502
9572
  for (const root of roots) {
@@ -8520,11 +9590,17 @@ function findHoveredNavOrFooterContainer(x, y) {
8520
9590
  }
8521
9591
  function isPointOverNavItem(container, x, y) {
8522
9592
  return Array.from(container.querySelectorAll("[data-ohw-href-key]")).some((el) => {
8523
- if (!isNavigationItem(el) || isNavbarButton2(el)) return false;
9593
+ if (!isNavigationItem2(el) || isNavbarButton2(el)) return false;
8524
9594
  const itemRect = el.getBoundingClientRect();
8525
9595
  return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
8526
9596
  });
8527
9597
  }
9598
+ function isPointOverFooterColumn(x, y) {
9599
+ return listFooterColumns().some((col) => {
9600
+ const r2 = col.getBoundingClientRect();
9601
+ return x >= r2.left && x <= r2.right && y >= r2.top && y <= r2.bottom;
9602
+ });
9603
+ }
8528
9604
  function resolveNavContainerSelectionTarget(target, clientX, clientY) {
8529
9605
  if (getNavigationItemAnchor(target)) return null;
8530
9606
  if (target.closest('[data-ohw-role="navbar-button"]')) return null;
@@ -8546,29 +9622,32 @@ function resolveNavContainerSelectionTarget(target, clientX, clientY) {
8546
9622
  return null;
8547
9623
  }
8548
9624
  function getNavigationSelectionParent(el) {
8549
- if (isNavigationItem(el)) {
9625
+ if (isNavigationItem2(el)) {
8550
9626
  const explicit = el.closest("[data-ohw-nav-container]");
8551
9627
  if (explicit) return explicit;
8552
9628
  const footerColumn = getFooterColumn(el);
8553
9629
  if (footerColumn) return footerColumn;
8554
- const footerGroup = findFooterItemGroup(el);
9630
+ const footerGroup = findFooterItemGroup2(el);
8555
9631
  if (footerGroup) return footerGroup;
8556
9632
  return getNavigationRoot(el);
8557
9633
  }
8558
- if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup(el)) {
9634
+ if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
9635
+ return getFooterLinksContainer();
9636
+ }
9637
+ if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isFooterLinksContainer(el) || isInferredFooterGroup2(el)) {
8559
9638
  return getNavigationRoot(el);
8560
9639
  }
8561
9640
  return null;
8562
9641
  }
8563
9642
  function collectNavigationItemSiblingHintRects(selected) {
8564
- if (!isNavigationItem(selected)) return [];
9643
+ if (!isNavigationItem2(selected)) return [];
8565
9644
  const footerColumn = getFooterColumn(selected);
8566
9645
  if (footerColumn) {
8567
9646
  return listFooterLinksInColumn(footerColumn).filter((link) => link !== selected).map((link) => link.getBoundingClientRect());
8568
9647
  }
8569
9648
  const navContainer = selected.closest("[data-ohw-nav-container], [data-ohw-nav-drawer]");
8570
9649
  if (navContainer) {
8571
- return Array.from(navContainer.querySelectorAll("[data-ohw-href-key]")).filter((el) => isNavigationItem(el) && el !== selected).map((el) => el.getBoundingClientRect());
9650
+ return Array.from(navContainer.querySelectorAll("[data-ohw-href-key]")).filter((el) => isNavigationItem2(el) && el !== selected).map((el) => el.getBoundingClientRect());
8572
9651
  }
8573
9652
  return listNavigationItems().filter((el) => el !== selected).map((el) => el.getBoundingClientRect());
8574
9653
  }
@@ -8782,7 +9861,7 @@ function EditGlowChrome({
8782
9861
  hideHandle = false
8783
9862
  }) {
8784
9863
  const GAP = SELECTION_CHROME_GAP2;
8785
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
9864
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
8786
9865
  "div",
8787
9866
  {
8788
9867
  ref: elRef,
@@ -8797,7 +9876,7 @@ function EditGlowChrome({
8797
9876
  zIndex: 2147483646
8798
9877
  },
8799
9878
  children: [
8800
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
9879
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
8801
9880
  "div",
8802
9881
  {
8803
9882
  style: {
@@ -8810,7 +9889,7 @@ function EditGlowChrome({
8810
9889
  }
8811
9890
  }
8812
9891
  ),
8813
- reorderHrefKey && !hideHandle && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
9892
+ reorderHrefKey && !hideHandle && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
8814
9893
  "div",
8815
9894
  {
8816
9895
  "data-ohw-drag-handle-container": "",
@@ -8822,7 +9901,7 @@ function EditGlowChrome({
8822
9901
  transform: "translate(calc(-100% - 7px), -50%)",
8823
9902
  pointerEvents: dragDisabled ? "none" : "auto"
8824
9903
  },
8825
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
9904
+ children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
8826
9905
  DragHandle,
8827
9906
  {
8828
9907
  "aria-label": `Reorder ${reorderHrefKey}`,
@@ -9005,9 +10084,9 @@ function FloatingToolbar({
9005
10084
  showEditLink,
9006
10085
  onEditLink
9007
10086
  }) {
9008
- const localRef = import_react10.default.useRef(null);
9009
- const [measuredW, setMeasuredW] = import_react10.default.useState(330);
9010
- const setRefs = import_react10.default.useCallback(
10087
+ const localRef = import_react11.default.useRef(null);
10088
+ const [measuredW, setMeasuredW] = import_react11.default.useState(330);
10089
+ const setRefs = import_react11.default.useCallback(
9011
10090
  (node) => {
9012
10091
  localRef.current = node;
9013
10092
  if (typeof elRef === "function") elRef(node);
@@ -9019,7 +10098,7 @@ function FloatingToolbar({
9019
10098
  },
9020
10099
  [elRef]
9021
10100
  );
9022
- import_react10.default.useLayoutEffect(() => {
10101
+ import_react11.default.useLayoutEffect(() => {
9023
10102
  const node = localRef.current;
9024
10103
  if (!node) return;
9025
10104
  const update = () => {
@@ -9032,7 +10111,7 @@ function FloatingToolbar({
9032
10111
  return () => ro.disconnect();
9033
10112
  }, [showEditLink, activeCommands]);
9034
10113
  const { top, left, transform } = calcToolbarPos(rect, parentScroll, measuredW);
9035
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
10114
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
9036
10115
  "div",
9037
10116
  {
9038
10117
  ref: setRefs,
@@ -9044,12 +10123,12 @@ function FloatingToolbar({
9044
10123
  zIndex: 2147483647,
9045
10124
  pointerEvents: "auto"
9046
10125
  },
9047
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(CustomToolbar, { children: [
9048
- TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react10.default.Fragment, { children: [
9049
- gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(CustomToolbarDivider, {}),
10126
+ children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(CustomToolbar, { children: [
10127
+ TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_react11.default.Fragment, { children: [
10128
+ gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(CustomToolbarDivider, {}),
9050
10129
  btns.map((btn) => {
9051
10130
  const isActive = activeCommands.has(btn.cmd);
9052
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
10131
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
9053
10132
  CustomToolbarButton,
9054
10133
  {
9055
10134
  title: btn.title,
@@ -9058,7 +10137,7 @@ function FloatingToolbar({
9058
10137
  e.preventDefault();
9059
10138
  onCommand(btn.cmd);
9060
10139
  },
9061
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
10140
+ children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
9062
10141
  "svg",
9063
10142
  {
9064
10143
  width: "16",
@@ -9079,7 +10158,7 @@ function FloatingToolbar({
9079
10158
  );
9080
10159
  })
9081
10160
  ] }, gi)),
9082
- showEditLink ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
10161
+ showEditLink ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
9083
10162
  CustomToolbarButton,
9084
10163
  {
9085
10164
  type: "button",
@@ -9093,7 +10172,7 @@ function FloatingToolbar({
9093
10172
  e.preventDefault();
9094
10173
  e.stopPropagation();
9095
10174
  },
9096
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react12.Link, { className: "size-4 shrink-0", "aria-hidden": true })
10175
+ children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react13.Link, { className: "size-4 shrink-0", "aria-hidden": true })
9097
10176
  }
9098
10177
  ) : null
9099
10178
  ] })
@@ -9110,7 +10189,7 @@ function StateToggle({
9110
10189
  states,
9111
10190
  onStateChange
9112
10191
  }) {
9113
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
10192
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
9114
10193
  ToggleGroup,
9115
10194
  {
9116
10195
  "data-ohw-state-toggle": "",
@@ -9124,7 +10203,7 @@ function StateToggle({
9124
10203
  left: rect.right - 8,
9125
10204
  transform: "translateX(-100%)"
9126
10205
  },
9127
- children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
10206
+ children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
9128
10207
  }
9129
10208
  );
9130
10209
  }
@@ -9151,8 +10230,8 @@ function OhhwellsBridge() {
9151
10230
  const router = (0, import_navigation2.useRouter)();
9152
10231
  const searchParams = (0, import_navigation2.useSearchParams)();
9153
10232
  const isEditMode = isEditSessionActive();
9154
- const [bridgeRoot, setBridgeRoot] = (0, import_react10.useState)(null);
9155
- (0, import_react10.useEffect)(() => {
10233
+ const [bridgeRoot, setBridgeRoot] = (0, import_react11.useState)(null);
10234
+ (0, import_react11.useEffect)(() => {
9156
10235
  const figtreeFontId = "ohw-figtree-font";
9157
10236
  if (!document.getElementById(figtreeFontId)) {
9158
10237
  const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
@@ -9180,99 +10259,104 @@ function OhhwellsBridge() {
9180
10259
  const subdomainFromQuery = searchParams.get("subdomain");
9181
10260
  const subdomain = resolveSubdomain(subdomainFromQuery);
9182
10261
  useLinkHrefGuardian(pathname, subdomain, isEditMode);
9183
- const postToParent2 = (0, import_react10.useCallback)((data) => {
10262
+ const postToParent2 = (0, import_react11.useCallback)((data) => {
9184
10263
  if (typeof window !== "undefined" && window.parent !== window) {
9185
10264
  window.parent.postMessage(data, "*");
9186
10265
  }
9187
10266
  }, []);
9188
- const [fetchState, setFetchState] = (0, import_react10.useState)("idle");
9189
- const autoSaveTimers = (0, import_react10.useRef)(/* @__PURE__ */ new Map());
9190
- const activeElRef = (0, import_react10.useRef)(null);
9191
- const pointerHeldRef = (0, import_react10.useRef)(false);
9192
- const selectedElRef = (0, import_react10.useRef)(null);
9193
- const selectedHrefKeyRef = (0, import_react10.useRef)(null);
9194
- const selectedFooterColAttrRef = (0, import_react10.useRef)(null);
9195
- const originalContentRef = (0, import_react10.useRef)(null);
9196
- const activeStateElRef = (0, import_react10.useRef)(null);
9197
- const parentScrollRef = (0, import_react10.useRef)(null);
9198
- const visibleViewportRef = (0, import_react10.useRef)(null);
9199
- const [dialogPortalContainer, setDialogPortalContainer] = (0, import_react10.useState)(null);
9200
- const attachVisibleViewport = (0, import_react10.useCallback)((node) => {
10267
+ const [fetchState, setFetchState] = (0, import_react11.useState)("idle");
10268
+ const autoSaveTimers = (0, import_react11.useRef)(/* @__PURE__ */ new Map());
10269
+ const activeElRef = (0, import_react11.useRef)(null);
10270
+ const pointerHeldRef = (0, import_react11.useRef)(false);
10271
+ const selectedElRef = (0, import_react11.useRef)(null);
10272
+ const selectedHrefKeyRef = (0, import_react11.useRef)(null);
10273
+ const selectedFooterColAttrRef = (0, import_react11.useRef)(null);
10274
+ const originalContentRef = (0, import_react11.useRef)(null);
10275
+ const activeStateElRef = (0, import_react11.useRef)(null);
10276
+ const parentScrollRef = (0, import_react11.useRef)(null);
10277
+ const visibleViewportRef = (0, import_react11.useRef)(null);
10278
+ const [dialogPortalContainer, setDialogPortalContainer] = (0, import_react11.useState)(null);
10279
+ const attachVisibleViewport = (0, import_react11.useCallback)((node) => {
9201
10280
  visibleViewportRef.current = node;
9202
10281
  setDialogPortalContainer(node);
9203
10282
  if (node) applyVisibleViewport(node, parentScrollRef.current);
9204
10283
  }, []);
9205
- const toolbarElRef = (0, import_react10.useRef)(null);
9206
- const glowElRef = (0, import_react10.useRef)(null);
9207
- const hoveredImageRef = (0, import_react10.useRef)(null);
9208
- const hoveredImageHasTextOverlapRef = (0, import_react10.useRef)(false);
9209
- const dragOverElRef = (0, import_react10.useRef)(null);
9210
- const [mediaHover, setMediaHover] = (0, import_react10.useState)(null);
9211
- const [carouselHover, setCarouselHover] = (0, import_react10.useState)(null);
9212
- const [uploadingRects, setUploadingRects] = (0, import_react10.useState)({});
9213
- const hoveredGapRef = (0, import_react10.useRef)(null);
9214
- const imageUnhoverTimerRef = (0, import_react10.useRef)(null);
9215
- const imageShowTimerRef = (0, import_react10.useRef)(null);
9216
- const editStylesRef = (0, import_react10.useRef)(null);
9217
- const activateRef = (0, import_react10.useRef)(() => {
10284
+ const toolbarElRef = (0, import_react11.useRef)(null);
10285
+ const glowElRef = (0, import_react11.useRef)(null);
10286
+ const hoveredImageRef = (0, import_react11.useRef)(null);
10287
+ const hoveredImageHasTextOverlapRef = (0, import_react11.useRef)(false);
10288
+ const dragOverElRef = (0, import_react11.useRef)(null);
10289
+ const [mediaHover, setMediaHover] = (0, import_react11.useState)(null);
10290
+ const [carouselHover, setCarouselHover] = (0, import_react11.useState)(null);
10291
+ const [uploadingRects, setUploadingRects] = (0, import_react11.useState)({});
10292
+ const hoveredGapRef = (0, import_react11.useRef)(null);
10293
+ const imageUnhoverTimerRef = (0, import_react11.useRef)(null);
10294
+ const imageShowTimerRef = (0, import_react11.useRef)(null);
10295
+ const editStylesRef = (0, import_react11.useRef)(null);
10296
+ const activateRef = (0, import_react11.useRef)(() => {
9218
10297
  });
9219
- const deactivateRef = (0, import_react10.useRef)(() => {
10298
+ const deactivateRef = (0, import_react11.useRef)(() => {
9220
10299
  });
9221
- const selectRef = (0, import_react10.useRef)(() => {
10300
+ const selectRef = (0, import_react11.useRef)(() => {
9222
10301
  });
9223
- const selectFrameRef = (0, import_react10.useRef)(() => {
10302
+ const selectFrameRef = (0, import_react11.useRef)(() => {
9224
10303
  });
9225
- const deselectRef = (0, import_react10.useRef)(() => {
10304
+ const deselectRef = (0, import_react11.useRef)(() => {
9226
10305
  });
9227
- const reselectNavigationItemRef = (0, import_react10.useRef)(() => {
10306
+ const reselectNavigationItemRef = (0, import_react11.useRef)(() => {
9228
10307
  });
9229
- const commitNavigationTextEditRef = (0, import_react10.useRef)(() => {
10308
+ const commitNavigationTextEditRef = (0, import_react11.useRef)(() => {
9230
10309
  });
9231
- const refreshActiveCommandsRef = (0, import_react10.useRef)(() => {
10310
+ const handleDeleteSelectedRef = (0, import_react11.useRef)(() => false);
10311
+ const runPendingDeleteUndoRef = (0, import_react11.useRef)(() => false);
10312
+ const isFooterFrameSelectionRef = (0, import_react11.useRef)(false);
10313
+ const refreshActiveCommandsRef = (0, import_react11.useRef)(() => {
9232
10314
  });
9233
- const postToParentRef = (0, import_react10.useRef)(postToParent2);
10315
+ const postToParentRef = (0, import_react11.useRef)(postToParent2);
9234
10316
  postToParentRef.current = postToParent2;
9235
- const sectionsLoadedRef = (0, import_react10.useRef)(false);
9236
- const pendingScheduleConfigRequests = (0, import_react10.useRef)([]);
9237
- const [toolbarRect, setToolbarRect] = (0, import_react10.useState)(null);
9238
- const [toolbarVariant, setToolbarVariant] = (0, import_react10.useState)("none");
9239
- const toolbarVariantRef = (0, import_react10.useRef)("none");
10317
+ const sectionsLoadedRef = (0, import_react11.useRef)(false);
10318
+ const pendingScheduleConfigRequests = (0, import_react11.useRef)([]);
10319
+ const [toolbarRect, setToolbarRect] = (0, import_react11.useState)(null);
10320
+ const [toolbarVariant, setToolbarVariant] = (0, import_react11.useState)("none");
10321
+ const toolbarVariantRef = (0, import_react11.useRef)("none");
9240
10322
  toolbarVariantRef.current = toolbarVariant;
9241
- const [selectedIsCta, setSelectedIsCta] = (0, import_react10.useState)(false);
9242
- const [reorderHrefKey, setReorderHrefKey] = (0, import_react10.useState)(null);
9243
- const [reorderDragDisabled, setReorderDragDisabled] = (0, import_react10.useState)(false);
9244
- const [toggleState, setToggleState] = (0, import_react10.useState)(null);
9245
- const [maxBadge, setMaxBadge] = (0, import_react10.useState)(null);
9246
- const [activeCommands, setActiveCommands] = (0, import_react10.useState)(/* @__PURE__ */ new Set());
9247
- const [sectionGap, setSectionGap] = (0, import_react10.useState)(null);
9248
- const [toolbarShowEditLink, setToolbarShowEditLink] = (0, import_react10.useState)(false);
9249
- const hoveredNavContainerRef = (0, import_react10.useRef)(null);
9250
- const [hoveredNavContainerRect, setHoveredNavContainerRect] = (0, import_react10.useState)(null);
9251
- const hoveredItemElRef = (0, import_react10.useRef)(null);
9252
- const [hoveredItemRect, setHoveredItemRect] = (0, import_react10.useState)(null);
9253
- const siblingHintElRef = (0, import_react10.useRef)(null);
9254
- const [siblingHintRect, setSiblingHintRect] = (0, import_react10.useState)(null);
9255
- const [siblingHintRects, setSiblingHintRects] = (0, import_react10.useState)([]);
9256
- const [isItemDragging, setIsItemDragging] = (0, import_react10.useState)(false);
9257
- const [isFooterFrameSelection, setIsFooterFrameSelection] = (0, import_react10.useState)(false);
9258
- const footerDragRef = (0, import_react10.useRef)(null);
9259
- const [footerDropSlots, setFooterDropSlots] = (0, import_react10.useState)([]);
9260
- const [activeFooterDropIndex, setActiveFooterDropIndex] = (0, import_react10.useState)(null);
9261
- const [draggedItemRect, setDraggedItemRect] = (0, import_react10.useState)(null);
9262
- const footerPointerDragRef = (0, import_react10.useRef)(null);
9263
- const suppressNextClickRef = (0, import_react10.useRef)(false);
9264
- const suppressClickUntilRef = (0, import_react10.useRef)(0);
9265
- const [linkPopover, setLinkPopover] = (0, import_react10.useState)(null);
9266
- const linkPopoverSessionRef = (0, import_react10.useRef)(null);
9267
- const addNavAfterAnchorRef = (0, import_react10.useRef)(null);
9268
- const editContentRef = (0, import_react10.useRef)({});
9269
- const [sitePages, setSitePages] = (0, import_react10.useState)([]);
9270
- const [sectionsByPath, setSectionsByPath] = (0, import_react10.useState)({});
9271
- const sectionsPrefetchGenRef = (0, import_react10.useRef)(0);
9272
- const setLinkPopoverRef = (0, import_react10.useRef)(setLinkPopover);
9273
- const linkPopoverPanelRef = (0, import_react10.useRef)(null);
9274
- const linkPopoverOpenRef = (0, import_react10.useRef)(false);
9275
- const linkPopoverGraceUntilRef = (0, import_react10.useRef)(0);
10323
+ const [selectedIsCta, setSelectedIsCta] = (0, import_react11.useState)(false);
10324
+ const [reorderHrefKey, setReorderHrefKey] = (0, import_react11.useState)(null);
10325
+ const [reorderDragDisabled, setReorderDragDisabled] = (0, import_react11.useState)(false);
10326
+ const [toggleState, setToggleState] = (0, import_react11.useState)(null);
10327
+ const [maxBadge, setMaxBadge] = (0, import_react11.useState)(null);
10328
+ const [activeCommands, setActiveCommands] = (0, import_react11.useState)(/* @__PURE__ */ new Set());
10329
+ const [sectionGap, setSectionGap] = (0, import_react11.useState)(null);
10330
+ const [toolbarShowEditLink, setToolbarShowEditLink] = (0, import_react11.useState)(false);
10331
+ const hoveredNavContainerRef = (0, import_react11.useRef)(null);
10332
+ const [hoveredNavContainerRect, setHoveredNavContainerRect] = (0, import_react11.useState)(null);
10333
+ const hoveredItemElRef = (0, import_react11.useRef)(null);
10334
+ const [hoveredItemRect, setHoveredItemRect] = (0, import_react11.useState)(null);
10335
+ const siblingHintElRef = (0, import_react11.useRef)(null);
10336
+ const [siblingHintRect, setSiblingHintRect] = (0, import_react11.useState)(null);
10337
+ const [siblingHintRects, setSiblingHintRects] = (0, import_react11.useState)([]);
10338
+ const [isItemDragging, setIsItemDragging] = (0, import_react11.useState)(false);
10339
+ const [isFooterFrameSelection, setIsFooterFrameSelection] = (0, import_react11.useState)(false);
10340
+ isFooterFrameSelectionRef.current = isFooterFrameSelection;
10341
+ const footerDragRef = (0, import_react11.useRef)(null);
10342
+ const [footerDropSlots, setFooterDropSlots] = (0, import_react11.useState)([]);
10343
+ const [activeFooterDropIndex, setActiveFooterDropIndex] = (0, import_react11.useState)(null);
10344
+ const [draggedItemRect, setDraggedItemRect] = (0, import_react11.useState)(null);
10345
+ const footerPointerDragRef = (0, import_react11.useRef)(null);
10346
+ const suppressNextClickRef = (0, import_react11.useRef)(false);
10347
+ const suppressClickUntilRef = (0, import_react11.useRef)(0);
10348
+ const [linkPopover, setLinkPopover] = (0, import_react11.useState)(null);
10349
+ const linkPopoverSessionRef = (0, import_react11.useRef)(null);
10350
+ const addNavAfterAnchorRef = (0, import_react11.useRef)(null);
10351
+ const editContentRef = (0, import_react11.useRef)({});
10352
+ const pendingDeleteUndoRef = (0, import_react11.useRef)(null);
10353
+ const [sitePages, setSitePages] = (0, import_react11.useState)([]);
10354
+ const [sectionsByPath, setSectionsByPath] = (0, import_react11.useState)({});
10355
+ const sectionsPrefetchGenRef = (0, import_react11.useRef)(0);
10356
+ const setLinkPopoverRef = (0, import_react11.useRef)(setLinkPopover);
10357
+ const linkPopoverPanelRef = (0, import_react11.useRef)(null);
10358
+ const linkPopoverOpenRef = (0, import_react11.useRef)(false);
10359
+ const linkPopoverGraceUntilRef = (0, import_react11.useRef)(0);
9276
10360
  setLinkPopoverRef.current = setLinkPopover;
9277
10361
  linkPopoverSessionRef.current = linkPopover;
9278
10362
  const {
@@ -9311,7 +10395,7 @@ function OhhwellsBridge() {
9311
10395
  const bumpLinkPopoverGrace = () => {
9312
10396
  linkPopoverGraceUntilRef.current = Date.now() + 350;
9313
10397
  };
9314
- const runSectionsPrefetch = (0, import_react10.useCallback)((pages) => {
10398
+ const runSectionsPrefetch = (0, import_react11.useCallback)((pages) => {
9315
10399
  if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
9316
10400
  const gen = ++sectionsPrefetchGenRef.current;
9317
10401
  const paths = pages.map((p) => p.path);
@@ -9330,9 +10414,9 @@ function OhhwellsBridge() {
9330
10414
  );
9331
10415
  });
9332
10416
  }, [isEditMode, pathname]);
9333
- const runSectionsPrefetchRef = (0, import_react10.useRef)(runSectionsPrefetch);
10417
+ const runSectionsPrefetchRef = (0, import_react11.useRef)(runSectionsPrefetch);
9334
10418
  runSectionsPrefetchRef.current = runSectionsPrefetch;
9335
- (0, import_react10.useEffect)(() => {
10419
+ (0, import_react11.useEffect)(() => {
9336
10420
  if (!linkPopover) {
9337
10421
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
9338
10422
  return;
@@ -9355,34 +10439,12 @@ function OhhwellsBridge() {
9355
10439
  hoveredGapRef.current = null;
9356
10440
  setSectionGap(null);
9357
10441
  setMediaHover(null);
9358
- postToParent2({ type: "ow:link-modal-lock", locked: true });
9359
- const html = document.documentElement;
9360
- const body = document.body;
9361
- const prevHtmlOverflow = html.style.overflow;
9362
- const prevBodyOverflow = body.style.overflow;
9363
- html.style.overflow = "hidden";
9364
- body.style.overflow = "hidden";
9365
- const preventBackgroundScroll = (e) => {
9366
- const target = e.target;
9367
- if (target instanceof Element && target.closest('[data-ohw-link-modal-root], [data-slot="dialog-overlay"]')) {
9368
- return;
9369
- }
9370
- e.preventDefault();
9371
- };
9372
- const scrollOpts = { passive: false, capture: true };
9373
- document.addEventListener("wheel", preventBackgroundScroll, scrollOpts);
9374
- document.addEventListener("touchmove", preventBackgroundScroll, scrollOpts);
9375
10442
  postToParent2({ type: "ow:image-unhover" });
9376
10443
  return () => {
9377
10444
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
9378
- postToParent2({ type: "ow:link-modal-lock", locked: false });
9379
- html.style.overflow = prevHtmlOverflow;
9380
- body.style.overflow = prevBodyOverflow;
9381
- document.removeEventListener("wheel", preventBackgroundScroll, scrollOpts);
9382
- document.removeEventListener("touchmove", preventBackgroundScroll, scrollOpts);
9383
10445
  };
9384
10446
  }, [linkPopover, postToParent2]);
9385
- (0, import_react10.useEffect)(() => {
10447
+ (0, import_react11.useEffect)(() => {
9386
10448
  if (!isEditMode) return;
9387
10449
  const useFixtures = shouldUseDevFixtures();
9388
10450
  if (useFixtures) {
@@ -9406,14 +10468,14 @@ function OhhwellsBridge() {
9406
10468
  if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
9407
10469
  return () => window.removeEventListener("message", onSitePages);
9408
10470
  }, [isEditMode, postToParent2]);
9409
- (0, import_react10.useEffect)(() => {
10471
+ (0, import_react11.useEffect)(() => {
9410
10472
  if (!isEditMode || shouldUseDevFixtures()) return;
9411
10473
  void loadAllSectionsManifest().then((manifest) => {
9412
10474
  if (Object.keys(manifest).length === 0) return;
9413
10475
  setSectionsByPath((prev) => ({ ...manifest, ...prev }));
9414
10476
  });
9415
10477
  }, [isEditMode]);
9416
- (0, import_react10.useEffect)(() => {
10478
+ (0, import_react11.useEffect)(() => {
9417
10479
  const update = () => {
9418
10480
  const el = activeElRef.current ?? selectedElRef.current;
9419
10481
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
@@ -9437,10 +10499,10 @@ function OhhwellsBridge() {
9437
10499
  vvp.removeEventListener("resize", update);
9438
10500
  };
9439
10501
  }, []);
9440
- const refreshStateRules = (0, import_react10.useCallback)(() => {
10502
+ const refreshStateRules = (0, import_react11.useCallback)(() => {
9441
10503
  editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
9442
10504
  }, []);
9443
- const processConfigRequest = (0, import_react10.useCallback)((insertAfterVal) => {
10505
+ const processConfigRequest = (0, import_react11.useCallback)((insertAfterVal) => {
9444
10506
  const tracker = getSectionsTracker();
9445
10507
  let entries = [];
9446
10508
  try {
@@ -9463,7 +10525,7 @@ function OhhwellsBridge() {
9463
10525
  }
9464
10526
  window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
9465
10527
  }, [isEditMode]);
9466
- const deactivate = (0, import_react10.useCallback)(() => {
10528
+ const deactivate = (0, import_react11.useCallback)(() => {
9467
10529
  const el = activeElRef.current;
9468
10530
  if (!el) return;
9469
10531
  const key = el.dataset.ohwKey;
@@ -9495,12 +10557,12 @@ function OhhwellsBridge() {
9495
10557
  setToolbarShowEditLink(false);
9496
10558
  postToParent2({ type: "ow:exit-edit" });
9497
10559
  }, [postToParent2]);
9498
- const clearSelectedAttr = (0, import_react10.useCallback)(() => {
10560
+ const clearSelectedAttr = (0, import_react11.useCallback)(() => {
9499
10561
  document.querySelectorAll("[data-ohw-selected]").forEach((el) => {
9500
10562
  el.removeAttribute("data-ohw-selected");
9501
10563
  });
9502
10564
  }, []);
9503
- const deselect = (0, import_react10.useCallback)(() => {
10565
+ const deselect = (0, import_react11.useCallback)(() => {
9504
10566
  clearSelectedAttr();
9505
10567
  selectedElRef.current = null;
9506
10568
  selectedHrefKeyRef.current = null;
@@ -9520,11 +10582,11 @@ function OhhwellsBridge() {
9520
10582
  setToolbarVariant("none");
9521
10583
  }
9522
10584
  }, [clearSelectedAttr]);
9523
- const markSelected = (0, import_react10.useCallback)((el) => {
10585
+ const markSelected = (0, import_react11.useCallback)((el) => {
9524
10586
  clearSelectedAttr();
9525
10587
  el.setAttribute("data-ohw-selected", "");
9526
10588
  }, [clearSelectedAttr]);
9527
- const resolveHrefKeyElement = (0, import_react10.useCallback)((hrefKey) => {
10589
+ const resolveHrefKeyElement = (0, import_react11.useCallback)((hrefKey) => {
9528
10590
  if (isFooterHrefKey(hrefKey)) {
9529
10591
  return document.querySelector(
9530
10592
  `footer [data-ohw-href-key="${CSS.escape(hrefKey)}"]`
@@ -9539,11 +10601,11 @@ function OhhwellsBridge() {
9539
10601
  `[data-ohw-href-key="${CSS.escape(hrefKey)}"]`
9540
10602
  );
9541
10603
  }, []);
9542
- const resyncSelectedNavigationItem = (0, import_react10.useCallback)(() => {
10604
+ const resyncSelectedNavigationItem = (0, import_react11.useCallback)(() => {
9543
10605
  const hrefKey = selectedHrefKeyRef.current;
9544
10606
  if (hrefKey) {
9545
10607
  const link = resolveHrefKeyElement(hrefKey);
9546
- if (!link || !isNavigationItem(link)) return;
10608
+ if (!link || !isNavigationItem2(link)) return;
9547
10609
  selectedElRef.current = link;
9548
10610
  const { key, disabled } = getNavigationItemReorderState(link);
9549
10611
  setReorderHrefKey(key);
@@ -9567,7 +10629,7 @@ function OhhwellsBridge() {
9567
10629
  );
9568
10630
  }
9569
10631
  }, [resolveHrefKeyElement]);
9570
- const reselectNavigationItem = (0, import_react10.useCallback)((navAnchor) => {
10632
+ const reselectNavigationItem = (0, import_react11.useCallback)((navAnchor) => {
9571
10633
  selectedElRef.current = navAnchor;
9572
10634
  selectedHrefKeyRef.current = navAnchor.getAttribute("data-ohw-href-key");
9573
10635
  selectedFooterColAttrRef.current = null;
@@ -9582,7 +10644,7 @@ function OhhwellsBridge() {
9582
10644
  setToolbarShowEditLink(false);
9583
10645
  setActiveCommands(/* @__PURE__ */ new Set());
9584
10646
  }, [markSelected]);
9585
- const commitNavigationTextEdit = (0, import_react10.useCallback)((navAnchor) => {
10647
+ const commitNavigationTextEdit = (0, import_react11.useCallback)((navAnchor) => {
9586
10648
  const el = activeElRef.current;
9587
10649
  if (!el) return;
9588
10650
  const key = el.dataset.ohwKey;
@@ -9609,7 +10671,7 @@ function OhhwellsBridge() {
9609
10671
  postToParent2({ type: "ow:exit-edit" });
9610
10672
  reselectNavigationItem(navAnchor);
9611
10673
  }, [postToParent2, reselectNavigationItem]);
9612
- const handleAddTopLevelNavItem = (0, import_react10.useCallback)(() => {
10674
+ const handleAddTopLevelNavItem = (0, import_react11.useCallback)(() => {
9613
10675
  const items = listNavbarItems();
9614
10676
  addNavAfterAnchorRef.current = items[items.length - 1] ?? null;
9615
10677
  deselectRef.current();
@@ -9621,7 +10683,28 @@ function OhhwellsBridge() {
9621
10683
  intent: "add-nav"
9622
10684
  });
9623
10685
  }, []);
9624
- const clearFooterDragVisuals = (0, import_react10.useCallback)(() => {
10686
+ const handleAddFooterColumn = (0, import_react11.useCallback)(() => {
10687
+ if (!canAddFooterColumn()) {
10688
+ postToParent2({
10689
+ type: "ow:toast",
10690
+ title: `Maximum ${MAX_FOOTER_COLUMNS} columns`,
10691
+ toastType: "error"
10692
+ });
10693
+ return;
10694
+ }
10695
+ deselectRef.current();
10696
+ deactivateRef.current();
10697
+ const result = addFooterColumnWithPersist({ postToParent: postToParent2 });
10698
+ if (!result) return;
10699
+ editContentRef.current = {
10700
+ ...editContentRef.current,
10701
+ ...buildFooterColumnEditContentPatch(result)
10702
+ };
10703
+ requestAnimationFrame(() => {
10704
+ selectRef.current(result.firstLink);
10705
+ });
10706
+ }, [postToParent2]);
10707
+ const clearFooterDragVisuals = (0, import_react11.useCallback)(() => {
9625
10708
  footerDragRef.current = null;
9626
10709
  setSiblingHintRects([]);
9627
10710
  setFooterDropSlots([]);
@@ -9630,7 +10713,7 @@ function OhhwellsBridge() {
9630
10713
  setIsItemDragging(false);
9631
10714
  unlockFooterDragInteraction();
9632
10715
  }, []);
9633
- const refreshFooterDragVisuals = (0, import_react10.useCallback)((session, activeSlot, clientX, clientY) => {
10716
+ const refreshFooterDragVisuals = (0, import_react11.useCallback)((session, activeSlot, clientX, clientY) => {
9634
10717
  const dragged = session.draggedEl;
9635
10718
  setDraggedItemRect(dragged.getBoundingClientRect());
9636
10719
  if (typeof clientX === "number" && typeof clientY === "number") {
@@ -9655,13 +10738,13 @@ function OhhwellsBridge() {
9655
10738
  const activeIdx = activeSlot ? slots.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
9656
10739
  setActiveFooterDropIndex(activeIdx >= 0 ? activeIdx : null);
9657
10740
  }, []);
9658
- const refreshFooterDragVisualsRef = (0, import_react10.useRef)(refreshFooterDragVisuals);
10741
+ const refreshFooterDragVisualsRef = (0, import_react11.useRef)(refreshFooterDragVisuals);
9659
10742
  refreshFooterDragVisualsRef.current = refreshFooterDragVisuals;
9660
- const commitFooterDragRef = (0, import_react10.useRef)(() => {
10743
+ const commitFooterDragRef = (0, import_react11.useRef)(() => {
9661
10744
  });
9662
- const beginFooterDragRef = (0, import_react10.useRef)(() => {
10745
+ const beginFooterDragRef = (0, import_react11.useRef)(() => {
9663
10746
  });
9664
- const beginFooterDrag = (0, import_react10.useCallback)(
10747
+ const beginFooterDrag = (0, import_react11.useCallback)(
9665
10748
  (session) => {
9666
10749
  const rect = session.draggedEl.getBoundingClientRect();
9667
10750
  session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
@@ -9681,7 +10764,7 @@ function OhhwellsBridge() {
9681
10764
  [refreshFooterDragVisuals]
9682
10765
  );
9683
10766
  beginFooterDragRef.current = beginFooterDrag;
9684
- const commitFooterDrag = (0, import_react10.useCallback)(
10767
+ const commitFooterDrag = (0, import_react11.useCallback)(
9685
10768
  (clientX, clientY) => {
9686
10769
  const session = footerDragRef.current;
9687
10770
  if (!session) {
@@ -9715,7 +10798,7 @@ function OhhwellsBridge() {
9715
10798
  selectedHrefKeyRef.current = hrefKey;
9716
10799
  selectedFooterColAttrRef.current = null;
9717
10800
  const link = resolveHrefKeyElement(hrefKey);
9718
- if (link && isNavigationItem(link)) {
10801
+ if (link && isNavigationItem2(link)) {
9719
10802
  selectRef.current(link);
9720
10803
  return;
9721
10804
  }
@@ -9739,7 +10822,7 @@ function OhhwellsBridge() {
9739
10822
  }
9740
10823
  }
9741
10824
  if (document.body.contains(draggedEl)) {
9742
- if (isNavigationItem(draggedEl)) {
10825
+ if (isNavigationItem2(draggedEl)) {
9743
10826
  selectRef.current(draggedEl);
9744
10827
  return;
9745
10828
  }
@@ -9785,7 +10868,7 @@ function OhhwellsBridge() {
9785
10868
  [clearFooterDragVisuals, resolveHrefKeyElement, resyncSelectedNavigationItem]
9786
10869
  );
9787
10870
  commitFooterDragRef.current = commitFooterDrag;
9788
- const startFooterLinkDrag = (0, import_react10.useCallback)(
10871
+ const startFooterLinkDrag = (0, import_react11.useCallback)(
9789
10872
  (anchor, clientX, clientY, wasSelected) => {
9790
10873
  const hrefKey = anchor.getAttribute("data-ohw-href-key");
9791
10874
  if (!hrefKey || !isFooterHrefKey(hrefKey)) return false;
@@ -9806,7 +10889,7 @@ function OhhwellsBridge() {
9806
10889
  },
9807
10890
  [beginFooterDrag]
9808
10891
  );
9809
- const startFooterColumnDrag = (0, import_react10.useCallback)(
10892
+ const startFooterColumnDrag = (0, import_react11.useCallback)(
9810
10893
  (columnEl, clientX, clientY, wasSelected) => {
9811
10894
  const columns = listFooterColumns();
9812
10895
  const idx = columns.indexOf(columnEl);
@@ -9826,7 +10909,7 @@ function OhhwellsBridge() {
9826
10909
  },
9827
10910
  [beginFooterDrag]
9828
10911
  );
9829
- const handleItemDragStart = (0, import_react10.useCallback)(
10912
+ const handleItemDragStart = (0, import_react11.useCallback)(
9830
10913
  (e) => {
9831
10914
  const selected = selectedElRef.current;
9832
10915
  if (!selected) {
@@ -9836,7 +10919,7 @@ function OhhwellsBridge() {
9836
10919
  const clientX = e?.clientX ?? selected.getBoundingClientRect().left + 8;
9837
10920
  const clientY = e?.clientY ?? selected.getBoundingClientRect().top + 8;
9838
10921
  if (startFooterLinkDrag(selected, clientX, clientY, true)) return;
9839
- if (selected.hasAttribute("data-ohw-footer-col") || isInferredFooterGroup(selected) && selected.closest("footer")) {
10922
+ if (selected.hasAttribute("data-ohw-footer-col") || isInferredFooterGroup2(selected) && selected.closest("footer")) {
9840
10923
  if (startFooterColumnDrag(selected, clientX, clientY, true)) return;
9841
10924
  }
9842
10925
  if (startNavLinkDrag(selected, clientX, clientY, true)) return;
@@ -9846,7 +10929,7 @@ function OhhwellsBridge() {
9846
10929
  },
9847
10930
  [startFooterColumnDrag, startFooterLinkDrag, startNavLinkDrag]
9848
10931
  );
9849
- const handleItemDragEnd = (0, import_react10.useCallback)(
10932
+ const handleItemDragEnd = (0, import_react11.useCallback)(
9850
10933
  (e) => {
9851
10934
  if (footerDragRef.current) {
9852
10935
  const x = e?.clientX;
@@ -9872,7 +10955,7 @@ function OhhwellsBridge() {
9872
10955
  },
9873
10956
  [commitFooterDrag, commitNavDrag, navDragRef]
9874
10957
  );
9875
- const handleItemChromePointerDown = (0, import_react10.useCallback)((e) => {
10958
+ const handleItemChromePointerDown = (0, import_react11.useCallback)((e) => {
9876
10959
  if (e.button !== 0) return;
9877
10960
  const selected = selectedElRef.current;
9878
10961
  if (!selected) return;
@@ -9889,7 +10972,7 @@ function OhhwellsBridge() {
9889
10972
  };
9890
10973
  return;
9891
10974
  }
9892
- if (selected.hasAttribute("data-ohw-footer-col") || isInferredFooterGroup(selected) && selected.closest("footer")) {
10975
+ if (selected.hasAttribute("data-ohw-footer-col") || isInferredFooterGroup2(selected) && selected.closest("footer")) {
9893
10976
  footerPointerDragRef.current = {
9894
10977
  el: selected,
9895
10978
  kind: "column",
@@ -9903,21 +10986,21 @@ function OhhwellsBridge() {
9903
10986
  }
9904
10987
  if (armNavPressFromChrome(selected, e.clientX, e.clientY, e.pointerId)) return;
9905
10988
  }, [armNavPressFromChrome]);
9906
- const handleItemChromeClick = (0, import_react10.useCallback)((clientX, clientY) => {
10989
+ const handleItemChromeClick = (0, import_react11.useCallback)((clientX, clientY) => {
9907
10990
  if (suppressNextClickRef.current || Date.now() < suppressClickUntilRef.current) {
9908
10991
  suppressNextClickRef.current = false;
9909
10992
  return;
9910
10993
  }
9911
10994
  const selected = selectedElRef.current;
9912
- if (!selected || !isNavigationItem(selected)) return;
10995
+ if (!selected || !isNavigationItem2(selected)) return;
9913
10996
  const editable = selected.querySelector('[data-ohw-editable="text"]') ?? selected.querySelector("[data-ohw-editable]");
9914
10997
  if (!editable) return;
9915
10998
  activateRef.current(editable, { caretX: clientX, caretY: clientY });
9916
10999
  }, []);
9917
11000
  reselectNavigationItemRef.current = reselectNavigationItem;
9918
11001
  commitNavigationTextEditRef.current = commitNavigationTextEdit;
9919
- const select = (0, import_react10.useCallback)((anchor) => {
9920
- if (!isNavigationItem(anchor)) return;
11002
+ const select = (0, import_react11.useCallback)((anchor) => {
11003
+ if (!isNavigationItem2(anchor)) return;
9921
11004
  if (activeElRef.current) deactivate();
9922
11005
  selectedElRef.current = anchor;
9923
11006
  selectedHrefKeyRef.current = anchor.getAttribute("data-ohw-href-key");
@@ -9942,10 +11025,10 @@ function OhhwellsBridge() {
9942
11025
  setToolbarShowEditLink(false);
9943
11026
  setActiveCommands(/* @__PURE__ */ new Set());
9944
11027
  }, [deactivate, markSelected]);
9945
- const selectFrame = (0, import_react10.useCallback)((el) => {
11028
+ const selectFrame = (0, import_react11.useCallback)((el) => {
9946
11029
  if (!isNavigationContainer(el)) return;
9947
11030
  if (activeElRef.current) deactivate();
9948
- const isFooterColumn = el.hasAttribute("data-ohw-footer-col") || Boolean(el.closest("footer") && isInferredFooterGroup(el));
11031
+ const isFooterColumn = !isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || Boolean(el.closest("footer") && isInferredFooterGroup2(el)));
9949
11032
  selectedElRef.current = el;
9950
11033
  selectedHrefKeyRef.current = null;
9951
11034
  selectedFooterColAttrRef.current = isFooterColumn ? el.getAttribute("data-ohw-footer-col") ?? String(listFooterColumns().indexOf(el)) : null;
@@ -9970,7 +11053,7 @@ function OhhwellsBridge() {
9970
11053
  setToolbarShowEditLink(false);
9971
11054
  setActiveCommands(/* @__PURE__ */ new Set());
9972
11055
  }, [deactivate, markSelected]);
9973
- const activate = (0, import_react10.useCallback)((el, options) => {
11056
+ const activate = (0, import_react11.useCallback)((el, options) => {
9974
11057
  if (activeElRef.current === el) return;
9975
11058
  clearSelectedAttr();
9976
11059
  selectedElRef.current = null;
@@ -10035,7 +11118,7 @@ function OhhwellsBridge() {
10035
11118
  selectRef.current = select;
10036
11119
  selectFrameRef.current = selectFrame;
10037
11120
  deselectRef.current = deselect;
10038
- (0, import_react10.useLayoutEffect)(() => {
11121
+ (0, import_react11.useLayoutEffect)(() => {
10039
11122
  if (!subdomain || isEditMode) {
10040
11123
  setFetchState("done");
10041
11124
  return;
@@ -10060,7 +11143,7 @@ function OhhwellsBridge() {
10060
11143
  const next = `url('${val}')`;
10061
11144
  if (el.style.backgroundImage !== next) el.style.backgroundImage = next;
10062
11145
  } else if (el.dataset.ohwEditable === "video") {
10063
- const video = getVideoEl(el);
11146
+ const video = getVideoEl2(el);
10064
11147
  if (video && video.src !== val) {
10065
11148
  applyVideoSrc(video, val);
10066
11149
  imageLoads.push(new Promise((resolve) => {
@@ -10106,7 +11189,7 @@ function OhhwellsBridge() {
10106
11189
  cancelled = true;
10107
11190
  };
10108
11191
  }, [subdomain, isEditMode]);
10109
- (0, import_react10.useEffect)(() => {
11192
+ (0, import_react11.useEffect)(() => {
10110
11193
  if (!subdomain || isEditMode) return;
10111
11194
  let debounceTimer = null;
10112
11195
  let observer = null;
@@ -10128,7 +11211,7 @@ function OhhwellsBridge() {
10128
11211
  const next = `url('${val}')`;
10129
11212
  if (el.style.backgroundImage !== next) el.style.backgroundImage = next;
10130
11213
  } else if (el.dataset.ohwEditable === "video") {
10131
- const video = getVideoEl(el);
11214
+ const video = getVideoEl2(el);
10132
11215
  if (video && video.src !== val) applyVideoSrc(video, val);
10133
11216
  } else if (el.dataset.ohwEditable === "link") {
10134
11217
  applyLinkHref(el, val);
@@ -10157,16 +11240,16 @@ function OhhwellsBridge() {
10157
11240
  if (debounceTimer) clearTimeout(debounceTimer);
10158
11241
  };
10159
11242
  }, [subdomain, isEditMode, pathname]);
10160
- (0, import_react10.useLayoutEffect)(() => {
11243
+ (0, import_react11.useLayoutEffect)(() => {
10161
11244
  const el = document.getElementById("ohw-loader");
10162
11245
  if (!el) return;
10163
11246
  const visible = Boolean(subdomain) && fetchState !== "done";
10164
11247
  el.style.display = visible ? "flex" : "none";
10165
11248
  }, [subdomain, fetchState]);
10166
- (0, import_react10.useEffect)(() => {
11249
+ (0, import_react11.useEffect)(() => {
10167
11250
  postToParent2({ type: "ow:navigation", path: pathname });
10168
11251
  }, [pathname, postToParent2]);
10169
- (0, import_react10.useEffect)(() => {
11252
+ (0, import_react11.useEffect)(() => {
10170
11253
  if (!isEditMode) return;
10171
11254
  if (linkPopoverSessionRef.current?.intent === "add-nav") return;
10172
11255
  if (document.querySelector("[data-ohw-section-picker]")) return;
@@ -10174,7 +11257,7 @@ function OhhwellsBridge() {
10174
11257
  deselectRef.current();
10175
11258
  deactivateRef.current();
10176
11259
  }, [pathname, isEditMode]);
10177
- (0, import_react10.useEffect)(() => {
11260
+ (0, import_react11.useEffect)(() => {
10178
11261
  const contentForNav = () => {
10179
11262
  if (isEditMode) return editContentRef.current;
10180
11263
  if (!subdomain) return {};
@@ -10239,7 +11322,7 @@ function OhhwellsBridge() {
10239
11322
  observer?.disconnect();
10240
11323
  };
10241
11324
  }, [isEditMode, pathname, subdomain, fetchState, resyncSelectedNavigationItem]);
10242
- (0, import_react10.useEffect)(() => {
11325
+ (0, import_react11.useEffect)(() => {
10243
11326
  if (!isEditMode) return;
10244
11327
  const measure = () => {
10245
11328
  const h = document.body.scrollHeight;
@@ -10263,7 +11346,7 @@ function OhhwellsBridge() {
10263
11346
  window.removeEventListener("resize", handleResize);
10264
11347
  };
10265
11348
  }, [pathname, isEditMode, postToParent2]);
10266
- (0, import_react10.useEffect)(() => {
11349
+ (0, import_react11.useEffect)(() => {
10267
11350
  if (!subdomainFromQuery || isEditMode) return;
10268
11351
  const handleClick = (e) => {
10269
11352
  const anchor = e.target.closest("a");
@@ -10279,7 +11362,7 @@ function OhhwellsBridge() {
10279
11362
  document.addEventListener("click", handleClick, true);
10280
11363
  return () => document.removeEventListener("click", handleClick, true);
10281
11364
  }, [subdomainFromQuery, isEditMode, router]);
10282
- (0, import_react10.useEffect)(() => {
11365
+ (0, import_react11.useEffect)(() => {
10283
11366
  if (!isEditMode) {
10284
11367
  editStylesRef.current?.base.remove();
10285
11368
  editStylesRef.current?.forceHover.remove();
@@ -10413,7 +11496,7 @@ function OhhwellsBridge() {
10413
11496
  e.preventDefault();
10414
11497
  e.stopPropagation();
10415
11498
  const selected = selectedElRef.current;
10416
- if (selected && isNavigationItem(selected)) {
11499
+ if (selected && isNavigationItem2(selected)) {
10417
11500
  const editable2 = selected.querySelector('[data-ohw-editable="text"]') ?? selected.querySelector("[data-ohw-editable]");
10418
11501
  if (editable2) {
10419
11502
  activateRef.current(editable2, {
@@ -10478,7 +11561,7 @@ function OhhwellsBridge() {
10478
11561
  setLinkPopoverRef.current({
10479
11562
  key: editable.dataset.ohwKey ?? "",
10480
11563
  mode: "edit",
10481
- target: getLinkHref2(editable)
11564
+ target: getLinkHref4(editable)
10482
11565
  });
10483
11566
  return;
10484
11567
  }
@@ -10503,7 +11586,7 @@ function OhhwellsBridge() {
10503
11586
  }
10504
11587
  e.preventDefault();
10505
11588
  e.stopPropagation();
10506
- activateRef.current(editable);
11589
+ activateRef.current(editable, { caretX: e.clientX, caretY: e.clientY });
10507
11590
  return;
10508
11591
  }
10509
11592
  const hrefAnchor = getNavigationItemAnchor(target);
@@ -10530,6 +11613,18 @@ function OhhwellsBridge() {
10530
11613
  selectFrameRef.current(footerColClick);
10531
11614
  return;
10532
11615
  }
11616
+ const footerLinksToSelect = resolveFooterLinksContainerSelectionTarget(
11617
+ target,
11618
+ e.clientX,
11619
+ e.clientY,
11620
+ isPointOverNavItem
11621
+ );
11622
+ if (footerLinksToSelect) {
11623
+ e.preventDefault();
11624
+ e.stopPropagation();
11625
+ selectFrameRef.current(footerLinksToSelect);
11626
+ return;
11627
+ }
10533
11628
  const navContainerToSelect = resolveNavContainerSelectionTarget(target, e.clientX, e.clientY);
10534
11629
  if (navContainerToSelect) {
10535
11630
  e.preventDefault();
@@ -10588,8 +11683,8 @@ function OhhwellsBridge() {
10588
11683
  return;
10589
11684
  }
10590
11685
  const navLabel = getNavigationLabelEditable(target);
10591
- if (!navLabel) return;
10592
- const { editable } = navLabel;
11686
+ const editable = navLabel?.editable ?? target.closest('[data-ohw-editable="text"], [data-ohw-editable="plain"]');
11687
+ if (!editable || isMediaEditable(editable) || editable.dataset.ohwEditable === "link") return;
10593
11688
  e.preventDefault();
10594
11689
  e.stopPropagation();
10595
11690
  if (activeElRef.current !== editable) {
@@ -10610,16 +11705,38 @@ function OhhwellsBridge() {
10610
11705
  setHoveredNavContainerRect(null);
10611
11706
  return;
10612
11707
  }
10613
- if (toolbarVariantRef.current !== "select-frame") {
10614
- const navContainer = target.closest("[data-ohw-nav-container]");
10615
- if (navContainer && !getNavigationItemAnchor(target)) {
10616
- hoveredNavContainerRef.current = navContainer;
10617
- setHoveredNavContainerRect(navContainer.getBoundingClientRect());
10618
- hoveredItemElRef.current = null;
10619
- setHoveredItemRect(null);
10620
- return;
11708
+ {
11709
+ const selected2 = selectedElRef.current;
11710
+ const selectedIsFooterColumn = Boolean(selected2) && !isFooterLinksContainer(selected2) && (selected2.hasAttribute("data-ohw-footer-col") || selected2.hasAttribute("data-ohw-footer-column") || Boolean(selected2.closest("footer") && isInferredFooterGroup2(selected2)));
11711
+ const allowNavContainerHover = toolbarVariantRef.current !== "select-frame";
11712
+ const allowFooterLinksHover = toolbarVariantRef.current !== "select-frame" || selectedIsFooterColumn;
11713
+ if (allowNavContainerHover) {
11714
+ const navContainer = target.closest("[data-ohw-nav-container]");
11715
+ if (navContainer && !getNavigationItemAnchor(target)) {
11716
+ hoveredNavContainerRef.current = navContainer;
11717
+ setHoveredNavContainerRect(navContainer.getBoundingClientRect());
11718
+ hoveredItemElRef.current = null;
11719
+ setHoveredItemRect(null);
11720
+ return;
11721
+ }
10621
11722
  }
10622
- if (!target.closest("[data-ohw-nav-container]")) {
11723
+ if (allowFooterLinksHover) {
11724
+ const navContainer = target.closest("[data-ohw-nav-container]");
11725
+ if (!navContainer) {
11726
+ const footerLinks = target.closest("[data-ohw-footer-links], .rb-footer-links") ?? null;
11727
+ if (footerLinks && selected2 !== footerLinks && !getNavigationItemAnchor(target) && !target.closest("[data-ohw-footer-col], [data-ohw-footer-column]")) {
11728
+ hoveredNavContainerRef.current = footerLinks;
11729
+ setHoveredNavContainerRect(footerLinks.getBoundingClientRect());
11730
+ hoveredItemElRef.current = null;
11731
+ setHoveredItemRect(null);
11732
+ return;
11733
+ }
11734
+ if (!footerLinks) {
11735
+ hoveredNavContainerRef.current = null;
11736
+ setHoveredNavContainerRect(null);
11737
+ }
11738
+ }
11739
+ } else if (toolbarVariantRef.current === "select-frame") {
10623
11740
  hoveredNavContainerRef.current = null;
10624
11741
  setHoveredNavContainerRect(null);
10625
11742
  }
@@ -10661,9 +11778,9 @@ function OhhwellsBridge() {
10661
11778
  };
10662
11779
  const handleMouseOut = (e) => {
10663
11780
  const target = e.target;
10664
- if (target.closest("[data-ohw-nav-container], [data-ohw-footer-col], [data-ohw-footer-column]")) {
11781
+ if (target.closest("[data-ohw-nav-container], [data-ohw-footer-col], [data-ohw-footer-column], [data-ohw-footer-links], .rb-footer-links")) {
10665
11782
  const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
10666
- 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]")) {
11783
+ 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]")) {
10667
11784
  return;
10668
11785
  }
10669
11786
  hoveredNavContainerRef.current = null;
@@ -10745,7 +11862,7 @@ function OhhwellsBridge() {
10745
11862
  const r2 = getVisibleRect(imgEl);
10746
11863
  const hasTextOverlap = forceTextOverlap ?? false;
10747
11864
  hoveredImageHasTextOverlapRef.current = hasTextOverlap;
10748
- const video = imgEl.dataset.ohwEditable === "video" ? getVideoEl(imgEl) : null;
11865
+ const video = imgEl.dataset.ohwEditable === "video" ? getVideoEl2(imgEl) : null;
10749
11866
  setMediaHover({
10750
11867
  key: imgEl.dataset.ohwKey ?? "",
10751
11868
  rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height },
@@ -10758,6 +11875,15 @@ function OhhwellsBridge() {
10758
11875
  if (track) track.setAttribute("data-ohw-hover-paused", "");
10759
11876
  };
10760
11877
  const clearImageHover = () => setMediaHover(null);
11878
+ const dismissImageHover = () => {
11879
+ if (hoveredImageRef.current) {
11880
+ hoveredImageRef.current = null;
11881
+ hoveredImageHasTextOverlapRef.current = false;
11882
+ resumeAnimTracks();
11883
+ postToParentRef.current({ type: "ow:image-unhover" });
11884
+ }
11885
+ clearImageHover();
11886
+ };
10761
11887
  const findImageAtPoint = (clientX, clientY, fromParentViewport) => {
10762
11888
  const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
10763
11889
  const images = Array.from(document.querySelectorAll(MEDIA_SELECTOR));
@@ -10801,16 +11927,13 @@ function OhhwellsBridge() {
10801
11927
  }
10802
11928
  return smallest;
10803
11929
  };
10804
- const dismissImageHover = () => {
10805
- if (hoveredImageRef.current) {
10806
- hoveredImageRef.current = null;
10807
- hoveredImageHasTextOverlapRef.current = false;
10808
- resumeAnimTracks();
10809
- postToParentRef.current({ type: "ow:image-unhover" });
10810
- }
10811
- };
10812
11930
  const probeNavigationHoverAt = (x, y) => {
10813
- if (toolbarVariantRef.current === "select-frame") {
11931
+ const selected = selectedElRef.current;
11932
+ const selectedIsFooterColumn = Boolean(selected) && !isFooterLinksContainer(selected) && (selected.hasAttribute("data-ohw-footer-col") || selected.hasAttribute("data-ohw-footer-column") || Boolean(selected.closest("footer") && isInferredFooterGroup2(selected)));
11933
+ const selectedIsFooterLinks = Boolean(selected && isFooterLinksContainer(selected));
11934
+ const allowNavContainerHover = toolbarVariantRef.current !== "select-frame";
11935
+ const allowFooterLinksHover = (toolbarVariantRef.current !== "select-frame" || selectedIsFooterColumn) && !selectedIsFooterLinks;
11936
+ if (toolbarVariantRef.current === "select-frame" && !allowFooterLinksHover) {
10814
11937
  hoveredNavContainerRef.current = null;
10815
11938
  setHoveredNavContainerRect(null);
10816
11939
  }
@@ -10825,14 +11948,13 @@ function OhhwellsBridge() {
10825
11948
  const navItemHit = Array.from(
10826
11949
  container.querySelectorAll("[data-ohw-href-key]")
10827
11950
  ).find((el) => {
10828
- if (!isNavigationItem(el) || isNavbarButton2(el)) return false;
11951
+ if (!isNavigationItem2(el) || isNavbarButton2(el)) return false;
10829
11952
  const itemRect = el.getBoundingClientRect();
10830
11953
  return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
10831
11954
  });
10832
11955
  if (navItemHit) {
10833
11956
  hoveredNavContainerRef.current = null;
10834
11957
  setHoveredNavContainerRect(null);
10835
- const selected = selectedElRef.current;
10836
11958
  if (selected !== navItemHit) {
10837
11959
  clearHrefKeyHover(navItemHit);
10838
11960
  hoveredItemElRef.current = navItemHit;
@@ -10844,7 +11966,7 @@ function OhhwellsBridge() {
10844
11966
  return;
10845
11967
  }
10846
11968
  }
10847
- if (toolbarVariantRef.current !== "select-frame") {
11969
+ if (allowNavContainerHover) {
10848
11970
  for (const container of navContainers) {
10849
11971
  const containerRect = container.getBoundingClientRect();
10850
11972
  const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
@@ -10856,12 +11978,23 @@ function OhhwellsBridge() {
10856
11978
  setHoveredItemRect(null);
10857
11979
  return;
10858
11980
  }
10859
- hoveredNavContainerRef.current = null;
10860
- setHoveredNavContainerRect(null);
10861
- } else {
10862
- hoveredNavContainerRef.current = null;
10863
- setHoveredNavContainerRect(null);
10864
11981
  }
11982
+ if (allowFooterLinksHover) {
11983
+ const footerLinks = getFooterLinksContainer();
11984
+ if (footerLinks) {
11985
+ const containerRect = footerLinks.getBoundingClientRect();
11986
+ const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
11987
+ if (overContainer && !isPointOverNavItem(footerLinks, x, y) && !isPointOverFooterColumn(x, y)) {
11988
+ hoveredNavContainerRef.current = footerLinks;
11989
+ setHoveredNavContainerRect(footerLinks.getBoundingClientRect());
11990
+ hoveredItemElRef.current = null;
11991
+ setHoveredItemRect(null);
11992
+ return;
11993
+ }
11994
+ }
11995
+ }
11996
+ hoveredNavContainerRef.current = null;
11997
+ setHoveredNavContainerRect(null);
10865
11998
  for (const column of footerColumns) {
10866
11999
  const containerRect = column.getBoundingClientRect();
10867
12000
  const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
@@ -10900,6 +12033,13 @@ function OhhwellsBridge() {
10900
12033
  probeNavigationHoverAt(x, y);
10901
12034
  return;
10902
12035
  }
12036
+ const overMoreMenu = document.elementFromPoint(x, y)?.closest?.(
12037
+ '[data-ohw-more-menu], [data-slot="dropdown-menu-content"], [data-slot="dropdown-menu-item"]'
12038
+ );
12039
+ if (overMoreMenu) {
12040
+ dismissImageHover();
12041
+ return;
12042
+ }
10903
12043
  hoveredNavContainerRef.current = null;
10904
12044
  setHoveredNavContainerRect(null);
10905
12045
  if (hoveredItemElRef.current?.hasAttribute("data-ohw-footer-col") || hoveredItemElRef.current?.hasAttribute("data-ohw-footer-column")) {
@@ -10946,7 +12086,7 @@ function OhhwellsBridge() {
10946
12086
  return;
10947
12087
  }
10948
12088
  const topEl = document.elementFromPoint(x2, y2);
10949
- if (topEl?.closest('[data-ohw-toolbar], [data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
12089
+ 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"]')) {
10950
12090
  if (hoveredImageRef.current) {
10951
12091
  hoveredImageRef.current = null;
10952
12092
  resumeAnimTracks();
@@ -11266,7 +12406,7 @@ function OhhwellsBridge() {
11266
12406
  }
11267
12407
  }
11268
12408
  } else if (el.dataset.ohwEditable === "video") {
11269
- const video = getVideoEl(el);
12409
+ const video = getVideoEl2(el);
11270
12410
  if (video) {
11271
12411
  found = true;
11272
12412
  const onReady = () => {
@@ -11353,7 +12493,7 @@ function OhhwellsBridge() {
11353
12493
  } else if (el.dataset.ohwEditable === "bg-image") {
11354
12494
  el.style.backgroundImage = `url('${val}')`;
11355
12495
  } else if (el.dataset.ohwEditable === "video") {
11356
- const video = getVideoEl(el);
12496
+ const video = getVideoEl2(el);
11357
12497
  if (video && video.src !== val) applyVideoSrc(video, val);
11358
12498
  } else if (el.dataset.ohwEditable === "link") {
11359
12499
  applyLinkHref(el, val);
@@ -11370,6 +12510,7 @@ function OhhwellsBridge() {
11370
12510
  }
11371
12511
  editContentRef.current = { ...editContentRef.current, ...content };
11372
12512
  reconcileNavbarItemsFromContent(editContentRef.current);
12513
+ reconcileFooterOrderFromContent(editContentRef.current);
11373
12514
  syncNavigationDragCursorAttrs();
11374
12515
  enforceLinkHrefs();
11375
12516
  postToParentRef.current({ type: "ow:hydrate-done" });
@@ -11387,8 +12528,17 @@ function OhhwellsBridge() {
11387
12528
  deactivateRef.current();
11388
12529
  };
11389
12530
  window.addEventListener("message", handleDeactivate);
12531
+ const handleToastAction = (e) => {
12532
+ if (e.data?.type !== "ow:toast-action") return;
12533
+ const actionId = typeof e.data.actionId === "string" ? e.data.actionId : null;
12534
+ const pending = pendingDeleteUndoRef.current;
12535
+ if (!pending || !actionId || pending.actionId !== actionId) return;
12536
+ runPendingDeleteUndoRef.current();
12537
+ };
12538
+ window.addEventListener("message", handleToastAction);
11390
12539
  const handleUiEscape = (e) => {
11391
12540
  if (e.data?.type !== "ui:escape") return;
12541
+ if (document.querySelector("[data-ohw-more-menu]")) return;
11392
12542
  if (linkPopoverOpenRef.current) {
11393
12543
  setLinkPopoverRef.current(null);
11394
12544
  return;
@@ -11424,6 +12574,11 @@ function OhhwellsBridge() {
11424
12574
  }
11425
12575
  if (selectedElRef.current) {
11426
12576
  if (toolbarVariantRef.current === "select-frame") {
12577
+ const parent2 = getNavigationSelectionParent(selectedElRef.current);
12578
+ if (parent2 && isNavigationContainer(parent2) && isFooterLinksContainer(parent2) && !isFooterLinksContainer(selectedElRef.current)) {
12579
+ selectFrameRef.current(parent2);
12580
+ return;
12581
+ }
11427
12582
  deselectRef.current();
11428
12583
  return;
11429
12584
  }
@@ -11438,14 +12593,12 @@ function OhhwellsBridge() {
11438
12593
  window.addEventListener("message", handleUiEscape);
11439
12594
  const handleKeyDown = (e) => {
11440
12595
  if (e.key === "Escape" && document.querySelector("[data-ohw-section-picker]")) return;
12596
+ if (e.key === "Escape" && document.querySelector("[data-ohw-more-menu]")) return;
11441
12597
  if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a" && activeElRef.current) {
11442
- const navAnchor = getNavigationItemAnchor(activeElRef.current);
11443
- if (navAnchor) {
11444
- e.preventDefault();
11445
- selectAllTextInEditable(activeElRef.current);
11446
- refreshActiveCommandsRef.current();
11447
- return;
11448
- }
12598
+ e.preventDefault();
12599
+ selectAllTextInEditable(activeElRef.current);
12600
+ refreshActiveCommandsRef.current();
12601
+ return;
11449
12602
  }
11450
12603
  if (e.key === "Escape" && linkPopoverOpenRef.current) {
11451
12604
  setLinkPopoverRef.current(null);
@@ -11453,6 +12606,12 @@ function OhhwellsBridge() {
11453
12606
  }
11454
12607
  if (e.key === "Escape" && selectedElRef.current && !activeElRef.current) {
11455
12608
  if (toolbarVariantRef.current === "select-frame") {
12609
+ const parent2 = getNavigationSelectionParent(selectedElRef.current);
12610
+ if (parent2 && isNavigationContainer(parent2) && isFooterLinksContainer(parent2) && !isFooterLinksContainer(selectedElRef.current)) {
12611
+ e.preventDefault();
12612
+ selectFrameRef.current(parent2);
12613
+ return;
12614
+ }
11456
12615
  deselectRef.current();
11457
12616
  return;
11458
12617
  }
@@ -11493,6 +12652,18 @@ function OhhwellsBridge() {
11493
12652
  return;
11494
12653
  }
11495
12654
  }
12655
+ if ((e.key === "Delete" || e.key === "Backspace") && selectedElRef.current && !activeElRef.current && !linkPopoverOpenRef.current) {
12656
+ if (handleDeleteSelectedRef.current()) {
12657
+ e.preventDefault();
12658
+ return;
12659
+ }
12660
+ }
12661
+ if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "z" && !activeElRef.current) {
12662
+ if (runPendingDeleteUndoRef.current()) {
12663
+ e.preventDefault();
12664
+ return;
12665
+ }
12666
+ }
11496
12667
  if (e.key !== "Escape") return;
11497
12668
  const el = activeElRef.current;
11498
12669
  if (el && originalContentRef.current !== null) {
@@ -11529,11 +12700,11 @@ function OhhwellsBridge() {
11529
12700
  }
11530
12701
  const selected = selectedElRef.current;
11531
12702
  if (selected && !footerDragRef.current && !navDragRef.current) {
11532
- if (selected.hasAttribute("data-ohw-footer-col") || Boolean(selected.closest("footer") && isInferredFooterGroup(selected))) {
12703
+ if (selected.hasAttribute("data-ohw-footer-col") || Boolean(selected.closest("footer") && isInferredFooterGroup2(selected))) {
11533
12704
  setSiblingHintRects(
11534
12705
  listFooterColumns().filter((column) => column !== selected).map((column) => column.getBoundingClientRect())
11535
12706
  );
11536
- } else if (isNavigationItem(selected)) {
12707
+ } else if (isNavigationItem2(selected)) {
11537
12708
  setSiblingHintRects(collectNavigationItemSiblingHintRects(selected));
11538
12709
  }
11539
12710
  }
@@ -11895,6 +13066,7 @@ function OhhwellsBridge() {
11895
13066
  window.removeEventListener("message", handleClickAt);
11896
13067
  window.removeEventListener("message", handleHydrate);
11897
13068
  window.removeEventListener("message", handleDeactivate);
13069
+ window.removeEventListener("message", handleToastAction);
11898
13070
  window.removeEventListener("message", handleUiEscape);
11899
13071
  autoSaveTimers.current.forEach(clearTimeout);
11900
13072
  autoSaveTimers.current.clear();
@@ -11902,7 +13074,7 @@ function OhhwellsBridge() {
11902
13074
  if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
11903
13075
  };
11904
13076
  }, [isEditMode, refreshStateRules]);
11905
- (0, import_react10.useEffect)(() => {
13077
+ (0, import_react11.useEffect)(() => {
11906
13078
  if (!isEditMode) return;
11907
13079
  const THRESHOLD = 10;
11908
13080
  const resolveWasSelected = (el) => {
@@ -12056,7 +13228,7 @@ function OhhwellsBridge() {
12056
13228
  unlockFooterDragInteraction();
12057
13229
  };
12058
13230
  }, [isEditMode]);
12059
- (0, import_react10.useEffect)(() => {
13231
+ (0, import_react11.useEffect)(() => {
12060
13232
  const handler = (e) => {
12061
13233
  if (e.data?.type !== "ow:request-schedule-config") return;
12062
13234
  const insertAfterVal = e.data.insertAfter;
@@ -12072,7 +13244,7 @@ function OhhwellsBridge() {
12072
13244
  window.addEventListener("message", handler);
12073
13245
  return () => window.removeEventListener("message", handler);
12074
13246
  }, [processConfigRequest]);
12075
- (0, import_react10.useEffect)(() => {
13247
+ (0, import_react11.useEffect)(() => {
12076
13248
  if (!isEditMode) return;
12077
13249
  document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
12078
13250
  el.removeAttribute("data-ohw-active-state");
@@ -12107,13 +13279,13 @@ function OhhwellsBridge() {
12107
13279
  clearTimeout(timer);
12108
13280
  };
12109
13281
  }, [pathname, isEditMode, refreshStateRules, postToParent2]);
12110
- (0, import_react10.useEffect)(() => {
13282
+ (0, import_react11.useEffect)(() => {
12111
13283
  scrollToHashSectionWhenReady();
12112
13284
  const onHashChange = () => scrollToHashSectionWhenReady();
12113
13285
  window.addEventListener("hashchange", onHashChange);
12114
13286
  return () => window.removeEventListener("hashchange", onHashChange);
12115
13287
  }, [pathname]);
12116
- const handleCommand = (0, import_react10.useCallback)((cmd) => {
13288
+ const handleCommand = (0, import_react11.useCallback)((cmd) => {
12117
13289
  const el = activeElRef.current;
12118
13290
  const selBefore = window.getSelection();
12119
13291
  let savedOffsets = null;
@@ -12149,7 +13321,7 @@ function OhhwellsBridge() {
12149
13321
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
12150
13322
  refreshActiveCommandsRef.current();
12151
13323
  }, []);
12152
- const handleStateChange = (0, import_react10.useCallback)((state) => {
13324
+ const handleStateChange = (0, import_react11.useCallback)((state) => {
12153
13325
  if (!activeStateElRef.current) return;
12154
13326
  const el = activeStateElRef.current;
12155
13327
  if (state === "Default") {
@@ -12162,22 +13334,22 @@ function OhhwellsBridge() {
12162
13334
  }
12163
13335
  setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
12164
13336
  }, [deactivate]);
12165
- const closeLinkPopover = (0, import_react10.useCallback)(() => {
13337
+ const closeLinkPopover = (0, import_react11.useCallback)(() => {
12166
13338
  addNavAfterAnchorRef.current = null;
12167
13339
  setLinkPopover(null);
12168
13340
  }, []);
12169
- const openLinkPopoverForActive = (0, import_react10.useCallback)(() => {
13341
+ const openLinkPopoverForActive = (0, import_react11.useCallback)(() => {
12170
13342
  const hrefCtx = getHrefKeyFromElement(activeElRef.current);
12171
13343
  if (!hrefCtx) return;
12172
13344
  bumpLinkPopoverGrace();
12173
13345
  setLinkPopover({
12174
13346
  key: hrefCtx.key,
12175
13347
  mode: "edit",
12176
- target: getLinkHref2(hrefCtx.anchor)
13348
+ target: getLinkHref4(hrefCtx.anchor)
12177
13349
  });
12178
13350
  deactivate();
12179
13351
  }, [deactivate]);
12180
- const openLinkPopoverForSelected = (0, import_react10.useCallback)(() => {
13352
+ const openLinkPopoverForSelected = (0, import_react11.useCallback)(() => {
12181
13353
  const anchor = selectedElRef.current;
12182
13354
  if (!anchor) return;
12183
13355
  const key = anchor.getAttribute("data-ohw-href-key");
@@ -12186,11 +13358,142 @@ function OhhwellsBridge() {
12186
13358
  setLinkPopover({
12187
13359
  key,
12188
13360
  mode: "edit",
12189
- target: getLinkHref2(anchor)
13361
+ target: getLinkHref4(anchor)
12190
13362
  });
12191
13363
  deselect();
12192
13364
  }, [deselect]);
12193
- const handleLinkPopoverSubmit = (0, import_react10.useCallback)(
13365
+ const handleSelectParent = (0, import_react11.useCallback)(() => {
13366
+ const selected = selectedElRef.current;
13367
+ if (!selected) return;
13368
+ if (toolbarVariantRef.current === "select-frame") {
13369
+ const parent2 = getNavigationSelectionParent(selected);
13370
+ if (parent2 && isNavigationContainer(parent2) && isFooterLinksContainer(parent2) && !isFooterLinksContainer(selected)) {
13371
+ selectFrameRef.current(parent2);
13372
+ return;
13373
+ }
13374
+ deselectRef.current();
13375
+ return;
13376
+ }
13377
+ const parent = getNavigationSelectionParent(selected);
13378
+ if (parent && isNavigationContainer(parent)) {
13379
+ selectFrameRef.current(parent);
13380
+ } else {
13381
+ deselectRef.current();
13382
+ }
13383
+ }, []);
13384
+ const handleDuplicateSelected = (0, import_react11.useCallback)(() => {
13385
+ const selected = selectedElRef.current;
13386
+ if (!selected || !isNavigationItem2(selected)) return;
13387
+ const hrefKey = selected.getAttribute("data-ohw-href-key");
13388
+ if (!hrefKey) return;
13389
+ if (isNavbarHrefKey(hrefKey)) {
13390
+ const result = duplicateNavbarItem(selected);
13391
+ if (!result) return;
13392
+ applyLinkByKey(result.hrefKey, result.href);
13393
+ document.querySelectorAll(`[data-ohw-key="${result.labelKey}"]`).forEach((el) => {
13394
+ el.textContent = result.label;
13395
+ });
13396
+ const nodes = [
13397
+ { key: result.hrefKey, text: result.href },
13398
+ { key: result.labelKey, text: result.label }
13399
+ ];
13400
+ for (const child of result.childResults) {
13401
+ applyLinkByKey(child.hrefKey, child.href);
13402
+ document.querySelectorAll(`[data-ohw-key="${child.labelKey}"]`).forEach((el) => {
13403
+ el.textContent = child.label;
13404
+ });
13405
+ nodes.push(
13406
+ { key: child.hrefKey, text: child.href },
13407
+ { key: child.labelKey, text: child.label }
13408
+ );
13409
+ }
13410
+ const maxIndex = Math.max(
13411
+ result.index,
13412
+ ...result.childResults.map((c) => c.index)
13413
+ );
13414
+ const navCount = String(maxIndex + 1);
13415
+ nodes.push(
13416
+ { key: NAV_COUNT_KEY, text: navCount },
13417
+ { key: NAV_ORDER_KEY, text: result.orderJson }
13418
+ );
13419
+ editContentRef.current = {
13420
+ ...editContentRef.current,
13421
+ [result.hrefKey]: result.href,
13422
+ [result.labelKey]: result.label,
13423
+ ...Object.fromEntries(
13424
+ result.childResults.flatMap((c) => [
13425
+ [c.hrefKey, c.href],
13426
+ [c.labelKey, c.label]
13427
+ ])
13428
+ ),
13429
+ [NAV_COUNT_KEY]: navCount,
13430
+ [NAV_ORDER_KEY]: result.orderJson
13431
+ };
13432
+ postToParent2({ type: "ow:change", nodes });
13433
+ enforceLinkHrefs();
13434
+ requestAnimationFrame(() => {
13435
+ selectRef.current(result.anchor);
13436
+ });
13437
+ return;
13438
+ }
13439
+ if (isFooterHrefKey(hrefKey)) {
13440
+ const result = duplicateFooterItem(selected);
13441
+ if (!result) return;
13442
+ applyLinkByKey(result.hrefKey, result.href);
13443
+ document.querySelectorAll(`[data-ohw-key="${result.labelKey}"]`).forEach((el) => {
13444
+ el.textContent = result.label;
13445
+ });
13446
+ const orderJson = JSON.stringify(result.order);
13447
+ editContentRef.current = {
13448
+ ...editContentRef.current,
13449
+ [result.hrefKey]: result.href,
13450
+ [result.labelKey]: result.label,
13451
+ [FOOTER_ORDER_KEY]: orderJson
13452
+ };
13453
+ postToParent2({
13454
+ type: "ow:change",
13455
+ nodes: [
13456
+ { key: result.hrefKey, text: result.href },
13457
+ { key: result.labelKey, text: result.label },
13458
+ { key: FOOTER_ORDER_KEY, text: orderJson }
13459
+ ]
13460
+ });
13461
+ enforceLinkHrefs();
13462
+ requestAnimationFrame(() => {
13463
+ selectRef.current(result.anchor);
13464
+ });
13465
+ }
13466
+ }, [postToParent2]);
13467
+ const runPendingDeleteUndo = (0, import_react11.useCallback)(() => {
13468
+ const pending = pendingDeleteUndoRef.current;
13469
+ if (!pending) return false;
13470
+ pendingDeleteUndoRef.current = null;
13471
+ pending.restore();
13472
+ enforceLinkHrefs();
13473
+ return true;
13474
+ }, []);
13475
+ const handleDeleteSelected = (0, import_react11.useCallback)(() => {
13476
+ const selected = selectedElRef.current;
13477
+ if (!selected) return false;
13478
+ return deleteSelectedNavFooterItem({
13479
+ selected,
13480
+ isTextEditing: Boolean(activeElRef.current),
13481
+ isSelectFrame: toolbarVariantRef.current === "select-frame",
13482
+ getEditContent: () => editContentRef.current,
13483
+ applyLinkByKey,
13484
+ postToParent: postToParent2,
13485
+ deselect: () => deselectRef.current(),
13486
+ setEditContent: (next) => {
13487
+ editContentRef.current = next;
13488
+ },
13489
+ setPendingUndo: (undo) => {
13490
+ pendingDeleteUndoRef.current = undo;
13491
+ }
13492
+ });
13493
+ }, [postToParent2]);
13494
+ handleDeleteSelectedRef.current = handleDeleteSelected;
13495
+ runPendingDeleteUndoRef.current = runPendingDeleteUndo;
13496
+ const handleLinkPopoverSubmit = (0, import_react11.useCallback)(
12194
13497
  (target) => {
12195
13498
  const session = linkPopoverSessionRef.current;
12196
13499
  if (!session) return;
@@ -12249,19 +13552,19 @@ function OhhwellsBridge() {
12249
13552
  const showEditLink = toolbarShowEditLink;
12250
13553
  const currentSections = sectionsByPath[pathname] ?? [];
12251
13554
  linkPopoverOpenRef.current = linkPopover !== null;
12252
- const handleMediaReplace = (0, import_react10.useCallback)(
13555
+ const handleMediaReplace = (0, import_react11.useCallback)(
12253
13556
  (key) => {
12254
13557
  postToParent2({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
12255
13558
  },
12256
13559
  [postToParent2, mediaHover?.elementType]
12257
13560
  );
12258
- const handleEditCarousel = (0, import_react10.useCallback)(
13561
+ const handleEditCarousel = (0, import_react11.useCallback)(
12259
13562
  (key) => {
12260
13563
  postToParent2({ type: "ow:carousel-open", key, images: readCarouselValue(key) });
12261
13564
  },
12262
13565
  [postToParent2]
12263
13566
  );
12264
- const handleMediaFadeOutComplete = (0, import_react10.useCallback)((key) => {
13567
+ const handleMediaFadeOutComplete = (0, import_react11.useCallback)((key) => {
12265
13568
  setUploadingRects((prev) => {
12266
13569
  if (!(key in prev)) return prev;
12267
13570
  const next = { ...prev };
@@ -12269,10 +13572,10 @@ function OhhwellsBridge() {
12269
13572
  return next;
12270
13573
  });
12271
13574
  }, []);
12272
- const handleVideoSettingsChange = (0, import_react10.useCallback)(
13575
+ const handleVideoSettingsChange = (0, import_react11.useCallback)(
12273
13576
  (key, settings) => {
12274
13577
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
12275
- const video = getVideoEl(el);
13578
+ const video = getVideoEl2(el);
12276
13579
  if (!video) return;
12277
13580
  if (typeof settings.autoplay === "boolean") video.autoplay = settings.autoplay;
12278
13581
  if (typeof settings.muted === "boolean") video.muted = settings.muted;
@@ -12292,9 +13595,9 @@ function OhhwellsBridge() {
12292
13595
  [postToParent2]
12293
13596
  );
12294
13597
  return bridgeRoot ? (0, import_react_dom3.createPortal)(
12295
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
12296
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
12297
- Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
13598
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
13599
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
13600
+ Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
12298
13601
  MediaOverlay,
12299
13602
  {
12300
13603
  hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
@@ -12305,7 +13608,7 @@ function OhhwellsBridge() {
12305
13608
  },
12306
13609
  `uploading-${key}`
12307
13610
  )),
12308
- mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
13611
+ mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
12309
13612
  MediaOverlay,
12310
13613
  {
12311
13614
  hover: mediaHover,
@@ -12314,11 +13617,11 @@ function OhhwellsBridge() {
12314
13617
  onVideoSettingsChange: handleVideoSettingsChange
12315
13618
  }
12316
13619
  ),
12317
- carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
12318
- siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
12319
- siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
12320
- isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
12321
- isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
13620
+ carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
13621
+ siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
13622
+ siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
13623
+ isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
13624
+ isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
12322
13625
  "div",
12323
13626
  {
12324
13627
  className: "pointer-events-none fixed z-2147483646",
@@ -12328,7 +13631,7 @@ function OhhwellsBridge() {
12328
13631
  width: slot.width,
12329
13632
  height: slot.height
12330
13633
  },
12331
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
13634
+ children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
12332
13635
  DropIndicator,
12333
13636
  {
12334
13637
  direction: slot.direction,
@@ -12339,7 +13642,7 @@ function OhhwellsBridge() {
12339
13642
  },
12340
13643
  `footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
12341
13644
  )),
12342
- isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
13645
+ isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
12343
13646
  "div",
12344
13647
  {
12345
13648
  className: "pointer-events-none fixed z-2147483646",
@@ -12349,7 +13652,7 @@ function OhhwellsBridge() {
12349
13652
  width: slot.width,
12350
13653
  height: slot.height
12351
13654
  },
12352
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
13655
+ children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
12353
13656
  DropIndicator,
12354
13657
  {
12355
13658
  direction: slot.direction,
@@ -12360,10 +13663,18 @@ function OhhwellsBridge() {
12360
13663
  },
12361
13664
  `nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
12362
13665
  )),
12363
- hoveredNavContainerRect && toolbarVariant !== "select-frame" && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
12364
- hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
12365
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
12366
- toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
13666
+ hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
13667
+ hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
13668
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
13669
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
13670
+ FooterContainerChrome,
13671
+ {
13672
+ rect: toolbarRect,
13673
+ onAdd: handleAddFooterColumn,
13674
+ addDisabled: !canAddFooterColumn()
13675
+ }
13676
+ ),
13677
+ toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
12367
13678
  ItemInteractionLayer,
12368
13679
  {
12369
13680
  rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
@@ -12377,21 +13688,26 @@ function OhhwellsBridge() {
12377
13688
  onItemPointerDown: handleItemChromePointerDown,
12378
13689
  onItemClick: handleItemChromeClick,
12379
13690
  itemDragSurface: !isFooterFrameSelection,
12380
- toolbar: toolbarVariant === "link-action" && !isItemDragging ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
13691
+ toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && isFooterFrameSelection && !isItemDragging ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
12381
13692
  ItemActionToolbar,
12382
13693
  {
12383
13694
  onEditLink: openLinkPopoverForSelected,
13695
+ onSelectParent: handleSelectParent,
13696
+ onDuplicate: handleDuplicateSelected,
13697
+ onDelete: handleDeleteSelected,
12384
13698
  addItemDisabled: true,
12385
13699
  editLinkDisabled: false,
12386
- moreDisabled: true,
12387
- showAddItem: !selectedIsCta,
12388
- showMore: !selectedIsCta
13700
+ moreDisabled: false,
13701
+ duplicateDisabled: isFooterFrameSelection,
13702
+ showEditLink: !isFooterFrameSelection,
13703
+ showAddItem: !selectedIsCta && !isFooterFrameSelection,
13704
+ showMore: !selectedIsCta || isFooterFrameSelection
12389
13705
  }
12390
13706
  ) : void 0
12391
13707
  }
12392
13708
  ),
12393
- toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
12394
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
13709
+ toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
13710
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
12395
13711
  EditGlowChrome,
12396
13712
  {
12397
13713
  rect: toolbarRect,
@@ -12401,7 +13717,7 @@ function OhhwellsBridge() {
12401
13717
  hideHandle: isItemDragging
12402
13718
  }
12403
13719
  ),
12404
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
13720
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
12405
13721
  FloatingToolbar,
12406
13722
  {
12407
13723
  rect: toolbarRect,
@@ -12414,7 +13730,7 @@ function OhhwellsBridge() {
12414
13730
  }
12415
13731
  )
12416
13732
  ] }),
12417
- maxBadge && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
13733
+ maxBadge && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
12418
13734
  "div",
12419
13735
  {
12420
13736
  "data-ohw-max-badge": "",
@@ -12440,7 +13756,7 @@ function OhhwellsBridge() {
12440
13756
  ]
12441
13757
  }
12442
13758
  ),
12443
- toggleState && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
13759
+ toggleState && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
12444
13760
  StateToggle,
12445
13761
  {
12446
13762
  rect: toggleState.rect,
@@ -12449,15 +13765,15 @@ function OhhwellsBridge() {
12449
13765
  onStateChange: handleStateChange
12450
13766
  }
12451
13767
  ),
12452
- sectionGap && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
13768
+ sectionGap && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
12453
13769
  "div",
12454
13770
  {
12455
13771
  "data-ohw-section-insert-line": "",
12456
13772
  className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
12457
13773
  style: { top: sectionGap.y, transform: "translateY(-50%)" },
12458
13774
  children: [
12459
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
12460
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
13775
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
13776
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
12461
13777
  Badge,
12462
13778
  {
12463
13779
  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",
@@ -12474,11 +13790,11 @@ function OhhwellsBridge() {
12474
13790
  children: "Add Section"
12475
13791
  }
12476
13792
  ),
12477
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
13793
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
12478
13794
  ]
12479
13795
  }
12480
13796
  ),
12481
- linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
13797
+ linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
12482
13798
  LinkPopover,
12483
13799
  {
12484
13800
  panelRef: linkPopoverPanelRef,
@@ -12506,6 +13822,12 @@ function OhhwellsBridge() {
12506
13822
  CustomToolbarDivider,
12507
13823
  DragHandle,
12508
13824
  DropIndicator,
13825
+ DropdownMenu,
13826
+ DropdownMenuContent,
13827
+ DropdownMenuGroup,
13828
+ DropdownMenuItem,
13829
+ DropdownMenuSeparator,
13830
+ DropdownMenuTrigger,
12509
13831
  ItemActionToolbar,
12510
13832
  ItemInteractionLayer,
12511
13833
  LinkEditorPanel,