@ohhwells/bridge 0.1.29-next.24 → 0.1.29-next.26

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
@@ -4489,26 +4489,135 @@ function scrollToHashSectionWhenReady(behavior = "smooth") {
4489
4489
  tick();
4490
4490
  }
4491
4491
 
4492
- // src/ui/link-modal/calcPopoverPos.ts
4493
- function calcPopoverPos(rect, parentScroll, approxW = 483, approxH = 320) {
4494
- const GAP = 8;
4495
- const canvasTopInIframe = parentScroll != null ? parentScroll.headerH - parentScroll.iframeOffsetTop : 0;
4496
- const visibleTop = rect.top - canvasTopInIframe;
4497
- let top = rect.top - GAP;
4498
- let transform = "translateX(-50%) translateY(-100%)";
4499
- if (visibleTop < approxH + GAP) {
4500
- top = rect.bottom + GAP;
4501
- transform = "translateX(-50%)";
4502
- }
4503
- const rawLeft = rect.left + rect.width / 2;
4504
- const left = Math.max(GAP + approxW / 2, Math.min(rawLeft, window.innerWidth - GAP - approxW / 2));
4505
- return { top, left, transform };
4506
- }
4507
-
4508
- // src/ui/button.tsx
4492
+ // src/ui/dialog.tsx
4509
4493
  var React3 = __toESM(require("react"), 1);
4510
4494
  var import_radix_ui3 = require("radix-ui");
4495
+
4496
+ // src/ui/icons.tsx
4511
4497
  var import_jsx_runtime5 = require("react/jsx-runtime");
4498
+ function IconX({ className, ...props }) {
4499
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
4500
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M18 6 6 18" }),
4501
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m6 6 12 12" })
4502
+ ] });
4503
+ }
4504
+ function IconChevronDown({ className, ...props }) {
4505
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m6 9 6 6 6-6" }) });
4506
+ }
4507
+ function IconFile({ className, ...props }) {
4508
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
4509
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
4510
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" })
4511
+ ] });
4512
+ }
4513
+ function IconInfo({ className, ...props }) {
4514
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
4515
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
4516
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12 16v-4" }),
4517
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12 8h.01" })
4518
+ ] });
4519
+ }
4520
+ function IconArrowRight({ className, ...props }) {
4521
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
4522
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M5 12h14" }),
4523
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m12 5 7 7-7 7" })
4524
+ ] });
4525
+ }
4526
+ function IconSection({ className, ...props }) {
4527
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
4528
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("rect", { width: "18", height: "7", x: "3", y: "3", rx: "1" }),
4529
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("rect", { width: "9", height: "7", x: "3", y: "14", rx: "1" }),
4530
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("rect", { width: "5", height: "7", x: "16", y: "14", rx: "1" })
4531
+ ] });
4532
+ }
4533
+
4534
+ // src/ui/dialog.tsx
4535
+ var import_jsx_runtime6 = require("react/jsx-runtime");
4536
+ function Dialog2({ ...props }) {
4537
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_radix_ui3.Dialog.Root, { "data-slot": "dialog", ...props });
4538
+ }
4539
+ function DialogPortal({ ...props }) {
4540
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_radix_ui3.Dialog.Portal, { ...props });
4541
+ }
4542
+ function DialogOverlay({
4543
+ className,
4544
+ ...props
4545
+ }) {
4546
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4547
+ import_radix_ui3.Dialog.Overlay,
4548
+ {
4549
+ "data-slot": "dialog-overlay",
4550
+ "data-ohw-link-modal-root": "",
4551
+ className: cn("fixed inset-0 z-[2147483646] bg-black/50", className),
4552
+ ...props
4553
+ }
4554
+ );
4555
+ }
4556
+ var DialogContent = React3.forwardRef(({ className, children, showCloseButton = true, container, ...props }, ref) => {
4557
+ const positionMode = container ? "absolute" : "fixed";
4558
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(DialogPortal, { container: container ?? void 0, children: [
4559
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DialogOverlay, { className: cn(positionMode, "inset-0") }),
4560
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
4561
+ import_radix_ui3.Dialog.Content,
4562
+ {
4563
+ ref,
4564
+ "data-slot": "dialog-content",
4565
+ className: cn(
4566
+ positionMode,
4567
+ "left-1/2 top-1/2 z-[2147483647] flex w-full max-w-[483px] -translate-x-1/2 -translate-y-1/2 flex-col overflow-hidden",
4568
+ "rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
4569
+ container ? "max-h-[calc(100%-32px)] max-w-[calc(100%-16px)]" : "max-h-[calc(100vh-32px)] max-w-[calc(100vw-16px)]",
4570
+ className
4571
+ ),
4572
+ onMouseDown: (e) => e.stopPropagation(),
4573
+ ...props,
4574
+ children: [
4575
+ children,
4576
+ showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4577
+ import_radix_ui3.Dialog.Close,
4578
+ {
4579
+ type: "button",
4580
+ className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
4581
+ "aria-label": "Close",
4582
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(IconX, { "aria-hidden": true })
4583
+ }
4584
+ ) : null
4585
+ ]
4586
+ }
4587
+ )
4588
+ ] });
4589
+ });
4590
+ DialogContent.displayName = import_radix_ui3.Dialog.Content.displayName;
4591
+ function DialogHeader({ className, ...props }) {
4592
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: cn("flex flex-col gap-1.5", className), ...props });
4593
+ }
4594
+ function DialogFooter({ className, ...props }) {
4595
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: cn("flex items-center justify-end gap-2", className), ...props });
4596
+ }
4597
+ var DialogTitle = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4598
+ import_radix_ui3.Dialog.Title,
4599
+ {
4600
+ ref,
4601
+ className: cn("text-lg font-semibold leading-none tracking-tight text-card-foreground", className),
4602
+ ...props
4603
+ }
4604
+ ));
4605
+ DialogTitle.displayName = import_radix_ui3.Dialog.Title.displayName;
4606
+ var DialogDescription = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4607
+ import_radix_ui3.Dialog.Description,
4608
+ {
4609
+ ref,
4610
+ className: cn("text-sm text-muted-foreground", className),
4611
+ ...props
4612
+ }
4613
+ ));
4614
+ DialogDescription.displayName = import_radix_ui3.Dialog.Description.displayName;
4615
+ var DialogClose = import_radix_ui3.Dialog.Close;
4616
+
4617
+ // src/ui/button.tsx
4618
+ var React4 = __toESM(require("react"), 1);
4619
+ var import_radix_ui4 = require("radix-ui");
4620
+ var import_jsx_runtime7 = require("react/jsx-runtime");
4512
4621
  var buttonVariants = cva(
4513
4622
  "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",
4514
4623
  {
@@ -4529,10 +4638,10 @@ var buttonVariants = cva(
4529
4638
  }
4530
4639
  }
4531
4640
  );
4532
- var Button = React3.forwardRef(
4641
+ var Button = React4.forwardRef(
4533
4642
  ({ className, variant, size, asChild = false, ...props }, ref) => {
4534
- const Comp = asChild ? import_radix_ui3.Slot.Root : "button";
4535
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
4643
+ const Comp = asChild ? import_radix_ui4.Slot.Root : "button";
4644
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4536
4645
  Comp,
4537
4646
  {
4538
4647
  ref,
@@ -4545,76 +4654,38 @@ var Button = React3.forwardRef(
4545
4654
  );
4546
4655
  Button.displayName = "Button";
4547
4656
 
4548
- // src/ui/icons.tsx
4549
- var import_jsx_runtime6 = require("react/jsx-runtime");
4550
- function IconX({ className, ...props }) {
4551
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
4552
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M18 6 6 18" }),
4553
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m6 6 12 12" })
4554
- ] });
4555
- }
4556
- function IconChevronDown({ className, ...props }) {
4557
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m6 9 6 6 6-6" }) });
4558
- }
4559
- function IconFile({ className, ...props }) {
4560
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
4561
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
4562
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" })
4563
- ] });
4564
- }
4565
- function IconInfo({ className, ...props }) {
4566
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
4567
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
4568
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M12 16v-4" }),
4569
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M12 8h.01" })
4570
- ] });
4571
- }
4572
- function IconArrowRight({ className, ...props }) {
4573
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
4574
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M5 12h14" }),
4575
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m12 5 7 7-7 7" })
4576
- ] });
4577
- }
4578
- function IconSection({ className, ...props }) {
4579
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
4580
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("rect", { width: "18", height: "7", x: "3", y: "3", rx: "1" }),
4581
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("rect", { width: "9", height: "7", x: "3", y: "14", rx: "1" }),
4582
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("rect", { width: "5", height: "7", x: "16", y: "14", rx: "1" })
4583
- ] });
4584
- }
4585
-
4586
4657
  // src/ui/link-modal/DestinationBreadcrumb.tsx
4587
- var import_jsx_runtime7 = require("react/jsx-runtime");
4658
+ var import_jsx_runtime8 = require("react/jsx-runtime");
4588
4659
  function DestinationBreadcrumb({ pageTitle, sectionLabel }) {
4589
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex w-full flex-col gap-2", children: [
4590
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "text-sm font-medium text-foreground", children: "Destination" }),
4591
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-3", children: [
4592
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-2", children: [
4593
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(IconFile, { className: "shrink-0 text-foreground", "aria-hidden": true }),
4594
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-sm font-medium leading-none text-foreground", children: pageTitle })
4660
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex w-full flex-col gap-2", children: [
4661
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "text-sm font-medium text-foreground", children: "Destination" }),
4662
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center gap-3", children: [
4663
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center gap-2", children: [
4664
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(IconFile, { className: "shrink-0 text-foreground", "aria-hidden": true }),
4665
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-sm font-medium leading-none text-foreground", children: pageTitle })
4595
4666
  ] }),
4596
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(IconArrowRight, { className: "shrink-0 text-muted-foreground", "aria-hidden": true }),
4597
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
4598
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(IconSection, { className: "shrink-0 text-foreground", "aria-hidden": true }),
4599
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
4667
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(IconArrowRight, { className: "shrink-0 text-muted-foreground", "aria-hidden": true }),
4668
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
4669
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(IconSection, { className: "shrink-0 text-foreground", "aria-hidden": true }),
4670
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
4600
4671
  ] })
4601
4672
  ] })
4602
4673
  ] });
4603
4674
  }
4604
4675
 
4605
4676
  // src/ui/link-modal/SectionTreeItem.tsx
4606
- var import_jsx_runtime8 = require("react/jsx-runtime");
4677
+ var import_jsx_runtime9 = require("react/jsx-runtime");
4607
4678
  function SectionTreeItem({ section, onSelect, selected }) {
4608
4679
  const interactive = Boolean(onSelect);
4609
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex h-9 w-full items-end pl-3", children: [
4610
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
4680
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex h-9 w-full items-end pl-3", children: [
4681
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4611
4682
  "div",
4612
4683
  {
4613
4684
  className: "mr-[-1px] h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
4614
4685
  "aria-hidden": true
4615
4686
  }
4616
4687
  ),
4617
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
4688
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
4618
4689
  "div",
4619
4690
  {
4620
4691
  role: interactive ? "button" : void 0,
@@ -4632,8 +4703,8 @@ function SectionTreeItem({ section, onSelect, selected }) {
4632
4703
  interactive && selected && "border-primary"
4633
4704
  ),
4634
4705
  children: [
4635
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(IconSection, { className: "shrink-0 text-foreground", "aria-hidden": true }),
4636
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
4706
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(IconSection, { className: "shrink-0 text-foreground", "aria-hidden": true }),
4707
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
4637
4708
  ]
4638
4709
  }
4639
4710
  )
@@ -4641,11 +4712,11 @@ function SectionTreeItem({ section, onSelect, selected }) {
4641
4712
  }
4642
4713
  function SectionPickerList({ sections, onSelect }) {
4643
4714
  if (sections.length === 0) {
4644
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." });
4715
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." });
4645
4716
  }
4646
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex flex-col gap-1", children: [
4647
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "text-sm text-muted-foreground", children: "Pick a section this link should scroll to." }),
4648
- sections.map((section) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SectionTreeItem, { section, onSelect }, section.id))
4717
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-1", children: [
4718
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-sm text-muted-foreground", children: "Pick a section this link should scroll to." }),
4719
+ sections.map((section) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SectionTreeItem, { section, onSelect }, section.id))
4649
4720
  ] });
4650
4721
  }
4651
4722
 
@@ -4653,11 +4724,11 @@ function SectionPickerList({ sections, onSelect }) {
4653
4724
  var import_react3 = require("react");
4654
4725
 
4655
4726
  // src/ui/input.tsx
4656
- var React4 = __toESM(require("react"), 1);
4657
- var import_jsx_runtime9 = require("react/jsx-runtime");
4658
- var Input = React4.forwardRef(
4727
+ var React5 = __toESM(require("react"), 1);
4728
+ var import_jsx_runtime10 = require("react/jsx-runtime");
4729
+ var Input = React5.forwardRef(
4659
4730
  ({ className, type, ...props }, ref) => {
4660
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4731
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4661
4732
  "input",
4662
4733
  {
4663
4734
  type,
@@ -4675,11 +4746,11 @@ var Input = React4.forwardRef(
4675
4746
  Input.displayName = "Input";
4676
4747
 
4677
4748
  // src/ui/label.tsx
4678
- var import_radix_ui4 = require("radix-ui");
4679
- var import_jsx_runtime10 = require("react/jsx-runtime");
4749
+ var import_radix_ui5 = require("radix-ui");
4750
+ var import_jsx_runtime11 = require("react/jsx-runtime");
4680
4751
  function Label({ className, ...props }) {
4681
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4682
- import_radix_ui4.Label.Root,
4752
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
4753
+ import_radix_ui5.Label.Root,
4683
4754
  {
4684
4755
  "data-slot": "label",
4685
4756
  className: cn("text-sm font-medium leading-5 text-foreground", className),
@@ -4688,36 +4759,6 @@ function Label({ className, ...props }) {
4688
4759
  );
4689
4760
  }
4690
4761
 
4691
- // src/ui/popover.tsx
4692
- var import_radix_ui5 = require("radix-ui");
4693
- var import_jsx_runtime11 = require("react/jsx-runtime");
4694
- function Popover({ ...props }) {
4695
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_radix_ui5.Popover.Root, { "data-slot": "popover", ...props });
4696
- }
4697
- function PopoverTrigger({ ...props }) {
4698
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_radix_ui5.Popover.Trigger, { "data-slot": "popover-trigger", ...props });
4699
- }
4700
- function PopoverContent({
4701
- className,
4702
- align = "start",
4703
- sideOffset = 6,
4704
- ...props
4705
- }) {
4706
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_radix_ui5.Popover.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
4707
- import_radix_ui5.Popover.Content,
4708
- {
4709
- "data-slot": "popover-content",
4710
- align,
4711
- sideOffset,
4712
- className: cn(
4713
- "z-[2147483647] w-[var(--radix-popover-trigger-width)] overflow-auto rounded-lg border border-border bg-popover py-1 shadow-lg outline-none",
4714
- className
4715
- ),
4716
- ...props
4717
- }
4718
- ) });
4719
- }
4720
-
4721
4762
  // src/ui/link-modal/UrlOrPageInput.tsx
4722
4763
  var import_jsx_runtime12 = require("react/jsx-runtime");
4723
4764
  function FieldChevron({ onClick }) {
@@ -4770,8 +4811,8 @@ function UrlOrPageInput({
4770
4811
  );
4771
4812
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex w-full flex-col gap-2 p-0", children: [
4772
4813
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
4773
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Popover, { open: dropdownOpen && !readOnly, onOpenChange: onDropdownOpenChange, children: [
4774
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
4814
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "relative w-full", children: [
4815
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
4775
4816
  selectedPage ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconFile, { className: "text-foreground", "aria-hidden": true }) }) : null,
4776
4817
  readOnly ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "min-w-0 flex-1 truncate text-sm leading-5 text-foreground", children: selectedPage?.title ?? value }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4777
4818
  Input,
@@ -4804,20 +4845,28 @@ function UrlOrPageInput({
4804
4845
  }
4805
4846
  ) : null,
4806
4847
  !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(FieldChevron, { onClick: toggleDropdown }) : null
4807
- ] }) }),
4808
- filteredPages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PopoverContent, { "data-ohw-link-popover-root": "", onOpenAutoFocus: (e) => e.preventDefault(), children: filteredPages.map((page) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
4809
- "button",
4848
+ ] }),
4849
+ dropdownOpen && !readOnly && filteredPages.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4850
+ "div",
4810
4851
  {
4811
- type: "button",
4812
- 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",
4813
- onClick: () => onPageSelect(page),
4814
- children: [
4815
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconFile, { className: "shrink-0", "aria-hidden": true }),
4816
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "truncate", children: page.title })
4817
- ]
4818
- },
4819
- page.path
4820
- )) })
4852
+ "data-ohw-link-page-dropdown": "",
4853
+ className: "absolute left-0 right-0 top-[calc(100%+4px)] z-10 max-h-48 overflow-auto rounded-lg border border-border bg-popover py-1 shadow-lg",
4854
+ onMouseDown: (e) => e.preventDefault(),
4855
+ children: filteredPages.map((page) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
4856
+ "button",
4857
+ {
4858
+ type: "button",
4859
+ 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",
4860
+ onClick: () => onPageSelect(page),
4861
+ children: [
4862
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconFile, { className: "shrink-0", "aria-hidden": true }),
4863
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "truncate", children: page.title })
4864
+ ]
4865
+ },
4866
+ page.path
4867
+ ))
4868
+ }
4869
+ ) : null
4821
4870
  ] }),
4822
4871
  urlError ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm font-medium text-destructive", children: urlError }) : null
4823
4872
  ] });
@@ -5012,17 +5061,16 @@ function LinkEditorPanel({
5012
5061
  });
5013
5062
  const isCancel = state.secondaryLabel === "Cancel";
5014
5063
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
5015
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5064
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DialogClose, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5016
5065
  "button",
5017
5066
  {
5018
5067
  type: "button",
5019
5068
  className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
5020
- onClick: state.handleClose,
5021
5069
  "aria-label": "Close",
5022
5070
  children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(IconX, { "aria-hidden": true })
5023
5071
  }
5024
- ),
5025
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("header", { className: "flex w-full flex-col gap-1.5 p-6 pr-12", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h2", { className: "m-0 w-full break-words text-lg font-semibold leading-none tracking-tight text-card-foreground", children: state.title }) }),
5072
+ ) }),
5073
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DialogHeader, { className: "w-full gap-1.5 p-6 pr-12", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DialogTitle, { className: "m-0 w-full break-words", children: state.title }) }),
5026
5074
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
5027
5075
  state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5028
5076
  DestinationBreadcrumb,
@@ -5053,7 +5101,7 @@ function LinkEditorPanel({
5053
5101
  state.showSectionPicker ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SectionPickerList, { sections: state.activeSections, onSelect: state.handleSectionSelect }) : null,
5054
5102
  state.showSectionRow && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
5055
5103
  ] }),
5056
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("footer", { className: "flex w-full items-center justify-end gap-2 px-6 pb-6", children: [
5104
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DialogFooter, { className: "w-full px-6 pb-6", children: [
5057
5105
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5058
5106
  Button,
5059
5107
  {
@@ -5090,26 +5138,32 @@ function LinkEditorPanel({
5090
5138
  // src/ui/link-modal/LinkPopover.tsx
5091
5139
  var import_jsx_runtime14 = require("react/jsx-runtime");
5092
5140
  function LinkPopover({
5093
- rect,
5094
- parentScroll,
5141
+ open = true,
5095
5142
  panelRef,
5143
+ portalContainer,
5144
+ onClose,
5096
5145
  ...editorProps
5097
5146
  }) {
5098
- const { top, left, transform } = calcPopoverPos(rect, parentScroll);
5099
5147
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
5100
- "div",
5148
+ Dialog2,
5101
5149
  {
5102
- ref: panelRef,
5103
- "data-ohw-link-popover-root": "",
5104
- "data-ohw-link-modal-root": "",
5105
- "data-ohw-bridge": "",
5106
- className: cn(
5107
- "pointer-events-auto fixed z-[2147483647] flex w-[483px] max-w-[calc(100vw-16px)] flex-col overflow-hidden",
5108
- "rounded-xl border border-border bg-background font-sans shadow-lg outline-none"
5109
- ),
5110
- style: { top, left, transform },
5111
- onMouseDown: (e) => e.stopPropagation(),
5112
- children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(LinkEditorPanel, { ...editorProps, open: true })
5150
+ open,
5151
+ onOpenChange: (next) => {
5152
+ if (!next) onClose?.();
5153
+ },
5154
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
5155
+ DialogContent,
5156
+ {
5157
+ ref: panelRef,
5158
+ container: portalContainer,
5159
+ "data-ohw-link-popover-root": "",
5160
+ "data-ohw-link-modal-root": "",
5161
+ "data-ohw-bridge": "",
5162
+ showCloseButton: false,
5163
+ className: "gap-0 p-0 w-full md:w-md pointer-events-auto",
5164
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(LinkEditorPanel, { ...editorProps, open, onClose })
5165
+ }
5166
+ )
5113
5167
  }
5114
5168
  );
5115
5169
  }
@@ -5455,7 +5509,7 @@ function applyLinkByKey(key, val) {
5455
5509
  }
5456
5510
  function isInsideLinkEditor(target) {
5457
5511
  return Boolean(
5458
- target.closest("[data-ohw-link-popover-root]") || target.closest("[data-ohw-link-modal-root]") || target.closest('[data-slot="popover-content"]')
5512
+ target.closest("[data-ohw-link-popover-root]") || target.closest("[data-ohw-link-modal-root]") || target.closest("[data-ohw-link-page-dropdown]") || target.closest('[data-slot="popover-content"]') || target.closest('[data-slot="dialog-content"]') || target.closest('[data-slot="dialog-overlay"]')
5459
5513
  );
5460
5514
  }
5461
5515
  function getHrefKeyFromElement(el) {
@@ -5636,15 +5690,57 @@ function GlowFrame({ rect, elRef }) {
5636
5690
  }
5637
5691
  );
5638
5692
  }
5693
+ function getIframeVisibleClip(parentScroll) {
5694
+ if (!parentScroll) return null;
5695
+ const { iframeOffsetTop, headerH: visibleCanvasTop, canvasH } = parentScroll;
5696
+ const clipTop = Math.max(0, visibleCanvasTop - iframeOffsetTop);
5697
+ const clipBottom = Math.min(
5698
+ window.innerHeight,
5699
+ visibleCanvasTop + canvasH - iframeOffsetTop
5700
+ );
5701
+ return { top: clipTop, bottom: Math.max(clipTop, clipBottom) };
5702
+ }
5703
+ function applyVisibleViewport(el, parentScroll) {
5704
+ const clip = getIframeVisibleClip(parentScroll);
5705
+ const top = clip?.top ?? 0;
5706
+ const height = clip ? clip.bottom - clip.top : window.innerHeight;
5707
+ el.style.top = `${top}px`;
5708
+ el.style.height = `${height}px`;
5709
+ }
5710
+ function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
5711
+ const isAbove = transform.includes("translateY(-100%)");
5712
+ let visualTop = isAbove ? top - approxH : top;
5713
+ let visualBottom = isAbove ? top : top + approxH;
5714
+ const minTop = clip.top + gap;
5715
+ const maxBottom = clip.bottom - gap;
5716
+ if (visualTop >= minTop && visualBottom <= maxBottom) {
5717
+ return { top, transform };
5718
+ }
5719
+ const belowTop = rect.bottom + gap;
5720
+ if (belowTop + approxH <= maxBottom && belowTop >= minTop) {
5721
+ return { top: belowTop, transform: "translateX(-50%)" };
5722
+ }
5723
+ const aboveTop = rect.top - gap;
5724
+ if (aboveTop - approxH >= minTop && aboveTop <= maxBottom) {
5725
+ return { top: aboveTop, transform: "translateX(-50%) translateY(-100%)" };
5726
+ }
5727
+ if (belowTop + approxH <= maxBottom) {
5728
+ return { top: belowTop, transform: "translateX(-50%)" };
5729
+ }
5730
+ const pinnedTop = Math.min(maxBottom - approxH, Math.max(minTop, clip.top + gap));
5731
+ return { top: pinnedTop + approxH, transform: "translateX(-50%) translateY(-100%)" };
5732
+ }
5639
5733
  function calcToolbarPos(rect, parentScroll, approxW = 330) {
5640
5734
  const GAP = 8;
5641
5735
  const APPROX_H = 36;
5642
5736
  const APPROX_W = approxW;
5737
+ const clip = getIframeVisibleClip(parentScroll);
5738
+ const clipTop = clip?.top ?? 0;
5643
5739
  const canvasTopInIframe = parentScroll != null ? parentScroll.headerH - parentScroll.iframeOffsetTop : 0;
5644
5740
  const visibleTop = rect.top - canvasTopInIframe;
5645
5741
  const visibleBottom = rect.bottom - canvasTopInIframe;
5646
5742
  const isTall = rect.height > APPROX_H + GAP;
5647
- const spaceAbove = rect.top - (canvasTopInIframe + GAP);
5743
+ const spaceAbove = rect.top - (clipTop + GAP);
5648
5744
  const fitsAbove = spaceAbove >= APPROX_H + GAP;
5649
5745
  let top;
5650
5746
  let transform;
@@ -5655,12 +5751,17 @@ function calcToolbarPos(rect, parentScroll, approxW = 330) {
5655
5751
  top = rect.bottom + GAP;
5656
5752
  transform = "translateX(-50%)";
5657
5753
  } else if (visibleBottom > APPROX_H + GAP) {
5658
- top = canvasTopInIframe + GAP;
5754
+ top = clipTop + GAP;
5659
5755
  transform = "translateX(-50%)";
5660
5756
  } else {
5661
5757
  top = rect.bottom + GAP;
5662
5758
  transform = "translateX(-50%)";
5663
5759
  }
5760
+ if (clip) {
5761
+ const clamped = clampToolbarToClip(top, transform, rect, clip, APPROX_H, GAP);
5762
+ top = clamped.top;
5763
+ transform = clamped.transform;
5764
+ }
5664
5765
  const rawLeft = rect.left + rect.width / 2;
5665
5766
  const left = Math.max(GAP + APPROX_W / 2, Math.min(rawLeft, window.innerWidth - GAP - APPROX_W / 2));
5666
5767
  return { top, left, transform };
@@ -5975,6 +6076,13 @@ function OhhwellsBridge() {
5975
6076
  const originalContentRef = (0, import_react5.useRef)(null);
5976
6077
  const activeStateElRef = (0, import_react5.useRef)(null);
5977
6078
  const parentScrollRef = (0, import_react5.useRef)(null);
6079
+ const visibleViewportRef = (0, import_react5.useRef)(null);
6080
+ const [dialogPortalContainer, setDialogPortalContainer] = (0, import_react5.useState)(null);
6081
+ const attachVisibleViewport = (0, import_react5.useCallback)((node) => {
6082
+ visibleViewportRef.current = node;
6083
+ setDialogPortalContainer(node);
6084
+ if (node) applyVisibleViewport(node, parentScrollRef.current);
6085
+ }, []);
5978
6086
  const toolbarElRef = (0, import_react5.useRef)(null);
5979
6087
  const glowElRef = (0, import_react5.useRef)(null);
5980
6088
  const hoveredImageRef = (0, import_react5.useRef)(null);
@@ -6045,7 +6153,33 @@ function OhhwellsBridge() {
6045
6153
  hoveredImageRef.current = null;
6046
6154
  hoveredImageHasTextOverlapRef.current = false;
6047
6155
  }
6156
+ hoveredGapRef.current = null;
6157
+ setSectionGap(null);
6048
6158
  postToParent({ type: "ow:image-unhover" });
6159
+ postToParent({ type: "ow:link-modal-lock", locked: true });
6160
+ const html = document.documentElement;
6161
+ const body = document.body;
6162
+ const prevHtmlOverflow = html.style.overflow;
6163
+ const prevBodyOverflow = body.style.overflow;
6164
+ html.style.overflow = "hidden";
6165
+ body.style.overflow = "hidden";
6166
+ const preventBackgroundScroll = (e) => {
6167
+ const target = e.target;
6168
+ if (target instanceof Element && target.closest('[data-ohw-link-modal-root], [data-slot="dialog-overlay"]')) {
6169
+ return;
6170
+ }
6171
+ e.preventDefault();
6172
+ };
6173
+ const scrollOpts = { passive: false, capture: true };
6174
+ document.addEventListener("wheel", preventBackgroundScroll, scrollOpts);
6175
+ document.addEventListener("touchmove", preventBackgroundScroll, scrollOpts);
6176
+ return () => {
6177
+ postToParent({ type: "ow:link-modal-lock", locked: false });
6178
+ html.style.overflow = prevHtmlOverflow;
6179
+ body.style.overflow = prevBodyOverflow;
6180
+ document.removeEventListener("wheel", preventBackgroundScroll, scrollOpts);
6181
+ document.removeEventListener("touchmove", preventBackgroundScroll, scrollOpts);
6182
+ };
6049
6183
  }, [linkPopover, postToParent]);
6050
6184
  (0, import_react5.useEffect)(() => {
6051
6185
  if (!isEditMode) return;
@@ -6300,6 +6434,12 @@ function OhhwellsBridge() {
6300
6434
  (0, import_react5.useEffect)(() => {
6301
6435
  postToParent({ type: "ow:navigation", path: pathname });
6302
6436
  }, [pathname, postToParent]);
6437
+ (0, import_react5.useEffect)(() => {
6438
+ if (!isEditMode) return;
6439
+ setLinkPopover(null);
6440
+ deselectRef.current();
6441
+ deactivateRef.current();
6442
+ }, [pathname, isEditMode]);
6303
6443
  (0, import_react5.useEffect)(() => {
6304
6444
  if (!isEditMode) return;
6305
6445
  const measure = () => {
@@ -6415,8 +6555,7 @@ function OhhwellsBridge() {
6415
6555
  bumpLinkPopoverGrace();
6416
6556
  setLinkPopoverRef.current({
6417
6557
  key: editable.dataset.ohwKey ?? "",
6418
- target: getLinkHref(editable),
6419
- rect: editable.getBoundingClientRect()
6558
+ target: getLinkHref(editable)
6420
6559
  });
6421
6560
  return;
6422
6561
  }
@@ -6616,7 +6755,7 @@ function OhhwellsBridge() {
6616
6755
  }
6617
6756
  return;
6618
6757
  }
6619
- if (topEl?.closest("[data-ohw-link-popover-root]") || topEl?.closest("[data-ohw-link-modal-root]")) {
6758
+ if (topEl?.closest("[data-ohw-link-popover-root]") || topEl?.closest("[data-ohw-link-modal-root]") || topEl?.closest("[data-ohw-link-page-dropdown]")) {
6620
6759
  if (hoveredImageRef.current) {
6621
6760
  hoveredImageRef.current = null;
6622
6761
  hoveredImageHasTextOverlapRef.current = false;
@@ -6744,6 +6883,13 @@ function OhhwellsBridge() {
6744
6883
  }
6745
6884
  };
6746
6885
  const probeSectionGapAt = (clientX, clientY, fromParentViewport = false) => {
6886
+ if (linkPopoverOpenRef.current) {
6887
+ if (hoveredGapRef.current) {
6888
+ hoveredGapRef.current = null;
6889
+ setSectionGap(null);
6890
+ }
6891
+ return;
6892
+ }
6747
6893
  const { y } = toProbeCoords(clientX, clientY, fromParentViewport);
6748
6894
  const sections = Array.from(document.querySelectorAll("[data-ohw-section]")).sort((a, b) => a.getBoundingClientRect().top - b.getBoundingClientRect().top);
6749
6895
  const ZONE = 20;
@@ -7140,6 +7286,9 @@ function OhhwellsBridge() {
7140
7286
  if (e.data?.type !== "ow:parent-scroll") return;
7141
7287
  const { iframeOffsetTop, headerH, canvasH } = e.data;
7142
7288
  parentScrollRef.current = { iframeOffsetTop, headerH, canvasH };
7289
+ if (visibleViewportRef.current) {
7290
+ applyVisibleViewport(visibleViewportRef.current, parentScrollRef.current);
7291
+ }
7143
7292
  const focusEl = activeElRef.current ?? selectedElRef.current;
7144
7293
  if (focusEl) applyToolbarPos(focusEl.getBoundingClientRect());
7145
7294
  };
@@ -7191,6 +7340,12 @@ function OhhwellsBridge() {
7191
7340
  window.addEventListener("message", handleParentScroll);
7192
7341
  window.addEventListener("message", handlePointerSync);
7193
7342
  window.addEventListener("message", handleClickAt);
7343
+ const handleViewportResize = () => {
7344
+ if (visibleViewportRef.current) {
7345
+ applyVisibleViewport(visibleViewportRef.current, parentScrollRef.current);
7346
+ }
7347
+ };
7348
+ window.addEventListener("resize", handleViewportResize, { passive: true });
7194
7349
  document.addEventListener("click", handleClick, true);
7195
7350
  document.addEventListener("paste", handlePaste, true);
7196
7351
  document.addEventListener("input", handleInput, true);
@@ -7228,6 +7383,7 @@ function OhhwellsBridge() {
7228
7383
  window.removeEventListener("message", handleAnimLock);
7229
7384
  window.removeEventListener("message", handleCanvasHeight);
7230
7385
  window.removeEventListener("message", handleParentScroll);
7386
+ window.removeEventListener("resize", handleViewportResize);
7231
7387
  window.removeEventListener("message", handlePointerSync);
7232
7388
  window.removeEventListener("message", handleClickAt);
7233
7389
  window.removeEventListener("message", handleHydrate);
@@ -7315,10 +7471,10 @@ function OhhwellsBridge() {
7315
7471
  bumpLinkPopoverGrace();
7316
7472
  setLinkPopover({
7317
7473
  key: hrefCtx.key,
7318
- target: getLinkHref(hrefCtx.anchor),
7319
- rect: hrefCtx.anchor.getBoundingClientRect()
7474
+ target: getLinkHref(hrefCtx.anchor)
7320
7475
  });
7321
- }, []);
7476
+ deactivate();
7477
+ }, [deactivate]);
7322
7478
  const openLinkPopoverForSelected = (0, import_react5.useCallback)(() => {
7323
7479
  const anchor = selectedElRef.current;
7324
7480
  if (!anchor) return;
@@ -7327,10 +7483,10 @@ function OhhwellsBridge() {
7327
7483
  bumpLinkPopoverGrace();
7328
7484
  setLinkPopover({
7329
7485
  key,
7330
- target: getLinkHref(anchor),
7331
- rect: anchor.getBoundingClientRect()
7486
+ target: getLinkHref(anchor)
7332
7487
  });
7333
- }, []);
7488
+ deselect();
7489
+ }, [deselect]);
7334
7490
  const handleLinkPopoverSubmit = (0, import_react5.useCallback)(
7335
7491
  (target) => {
7336
7492
  if (!linkPopover) return;
@@ -7346,6 +7502,7 @@ function OhhwellsBridge() {
7346
7502
  linkPopoverOpenRef.current = linkPopover !== null;
7347
7503
  return bridgeRoot ? (0, import_react_dom2.createPortal)(
7348
7504
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
7505
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
7349
7506
  toolbarRect && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
7350
7507
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(GlowFrame, { rect: toolbarRect, elRef: glowElRef }),
7351
7508
  toolbarVariant === "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
@@ -7434,12 +7591,11 @@ function OhhwellsBridge() {
7434
7591
  ]
7435
7592
  }
7436
7593
  ),
7437
- linkPopover ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
7594
+ linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
7438
7595
  LinkPopover,
7439
7596
  {
7440
- rect: linkPopover.rect,
7441
- parentScroll: parentScrollRef.current,
7442
7597
  panelRef: linkPopoverPanelRef,
7598
+ portalContainer: dialogPortalContainer,
7443
7599
  open: true,
7444
7600
  mode: "edit",
7445
7601
  pages: sitePages,
@@ -7448,7 +7604,8 @@ function OhhwellsBridge() {
7448
7604
  initialTarget: linkPopover.target,
7449
7605
  onClose: closeLinkPopover,
7450
7606
  onSubmit: handleLinkPopoverSubmit
7451
- }
7607
+ },
7608
+ `${linkPopover.key}-${pathname}`
7452
7609
  ) : null,
7453
7610
  sectionGap && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
7454
7611
  "div",