@ohhwells/bridge 0.1.32 → 0.1.33-next.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  // src/OhhwellsBridge.tsx
4
- import React6, { useCallback as useCallback2, useEffect as useEffect3, useLayoutEffect as useLayoutEffect2, useRef as useRef3, useState as useState5 } from "react";
4
+ import React7, { useCallback as useCallback2, useEffect as useEffect3, useLayoutEffect as useLayoutEffect2, useRef as useRef3, useState as useState5 } from "react";
5
5
  import { createRoot } from "react-dom/client";
6
6
  import { flushSync } from "react-dom";
7
7
 
@@ -712,15 +712,10 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
712
712
  };
713
713
  const handleReplaceSchedule = () => {
714
714
  setIsHovered(false);
715
- if (schedule) {
716
- window.parent.postMessage({
717
- type: "ow:schedule-connected",
718
- schedule: { id: schedule.id, name: schedule.name },
719
- insertAfter
720
- }, "*");
721
- } else {
722
- window.parent.postMessage({ type: "ow:scheduling-not-connected", insertAfter }, "*");
723
- }
715
+ window.parent.postMessage(
716
+ { type: "ow:scheduling-not-connected", insertAfter, currentScheduleId: schedule?.id },
717
+ "*"
718
+ );
724
719
  };
725
720
  if (!inEditor && !loading && !schedule) return null;
726
721
  const sectionId = `scheduling-${insertAfter}`;
@@ -763,7 +758,19 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
763
758
  ),
764
759
  /* @__PURE__ */ jsxs2("div", { className: "max-w-[1280px] mx-auto flex flex-col items-center gap-16", children: [
765
760
  /* @__PURE__ */ jsxs2("div", { className: "flex flex-col items-center gap-4", children: [
766
- /* @__PURE__ */ jsx2("h2", { className: "font-display text-4xl sm:text-5xl font-bold text-center m-0 text-(--color-dark,#200C02)", children: schedule?.name ?? "Book an appointment" }),
761
+ /* @__PURE__ */ jsx2(
762
+ "h2",
763
+ {
764
+ className: "font-display text-center m-0 text-(--color-dark,#200C02)",
765
+ style: {
766
+ fontSize: "var(--fs-section-h2, clamp(40px, 4.4vw, 64px))",
767
+ fontWeight: "var(--font-weight-heading, 400)",
768
+ lineHeight: 1.05,
769
+ letterSpacing: "-0.02em"
770
+ },
771
+ children: schedule?.name ?? "Book an appointment"
772
+ }
773
+ ),
767
774
  schedule?.description && /* @__PURE__ */ jsx2("p", { className: "font-body text-body text-center m-0 text-(--color-accent,#A89B83)", children: schedule.description })
768
775
  ] }),
769
776
  /* @__PURE__ */ jsxs2("div", { className: "w-full flex flex-col items-end gap-3", children: [
@@ -4202,6 +4209,34 @@ function ToggleGroupItem({
4202
4209
  );
4203
4210
  }
4204
4211
 
4212
+ // src/ui/drag-handle.tsx
4213
+ import * as React3 from "react";
4214
+ import { GripVertical } from "lucide-react";
4215
+ import { jsx as jsx5 } from "react/jsx-runtime";
4216
+ var DragHandle = React3.forwardRef(
4217
+ ({ className, type = "button", ...props }, ref) => {
4218
+ return /* @__PURE__ */ jsx5(
4219
+ "button",
4220
+ {
4221
+ ref,
4222
+ type,
4223
+ "data-slot": "drag-handle",
4224
+ className: cn(
4225
+ "inline-flex h-7 w-4 shrink-0 items-center justify-center rounded-md transition-all duration-200 max-h-[30px]",
4226
+ "bg-white border border-transparent text-stone-500 shadow-md cursor-grab",
4227
+ "enabled:hover:border enabled:hover:border-stone-200 enabled:hover:text-stone-950",
4228
+ "enabled:active:border enabled:active:border-primary enabled:active:bg-primary-50 enabled:active:text-stone-950 enabled:active:shadow enabled:active:cursor-grabbing",
4229
+ "disabled:cursor-not-allowed disabled:opacity-40 disabled:text-stone-950 disabled:pointer-events-none",
4230
+ className
4231
+ ),
4232
+ ...props,
4233
+ children: /* @__PURE__ */ jsx5(GripVertical, { className: "size-4 shrink-0", "aria-hidden": "true" })
4234
+ }
4235
+ );
4236
+ }
4237
+ );
4238
+ DragHandle.displayName = "DragHandle";
4239
+
4205
4240
  // src/OhhwellsBridge.tsx
4206
4241
  import { createPortal } from "react-dom";
4207
4242
  import { usePathname, useRouter, useSearchParams } from "next/navigation";
@@ -4481,60 +4516,60 @@ function scrollToHashSectionWhenReady(behavior = "smooth") {
4481
4516
  }
4482
4517
 
4483
4518
  // src/ui/dialog.tsx
4484
- import * as React3 from "react";
4519
+ import * as React4 from "react";
4485
4520
  import { Dialog as DialogPrimitive } from "radix-ui";
4486
4521
 
4487
4522
  // src/ui/icons.tsx
4488
- import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
4523
+ import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
4489
4524
  function IconX({ className, ...props }) {
4490
4525
  return /* @__PURE__ */ jsxs3("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
4491
- /* @__PURE__ */ jsx5("path", { d: "M18 6 6 18" }),
4492
- /* @__PURE__ */ jsx5("path", { d: "m6 6 12 12" })
4526
+ /* @__PURE__ */ jsx6("path", { d: "M18 6 6 18" }),
4527
+ /* @__PURE__ */ jsx6("path", { d: "m6 6 12 12" })
4493
4528
  ] });
4494
4529
  }
4495
4530
  function IconChevronDown({ className, ...props }) {
4496
- return /* @__PURE__ */ jsx5("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: /* @__PURE__ */ jsx5("path", { d: "m6 9 6 6 6-6" }) });
4531
+ return /* @__PURE__ */ jsx6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: /* @__PURE__ */ jsx6("path", { d: "m6 9 6 6 6-6" }) });
4497
4532
  }
4498
4533
  function IconFile({ className, ...props }) {
4499
4534
  return /* @__PURE__ */ jsxs3("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__ */ jsx5("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
4501
- /* @__PURE__ */ jsx5("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" })
4535
+ /* @__PURE__ */ jsx6("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
4536
+ /* @__PURE__ */ jsx6("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" })
4502
4537
  ] });
4503
4538
  }
4504
4539
  function IconInfo({ className, ...props }) {
4505
4540
  return /* @__PURE__ */ jsxs3("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
4506
- /* @__PURE__ */ jsx5("circle", { cx: "12", cy: "12", r: "10" }),
4507
- /* @__PURE__ */ jsx5("path", { d: "M12 16v-4" }),
4508
- /* @__PURE__ */ jsx5("path", { d: "M12 8h.01" })
4541
+ /* @__PURE__ */ jsx6("circle", { cx: "12", cy: "12", r: "10" }),
4542
+ /* @__PURE__ */ jsx6("path", { d: "M12 16v-4" }),
4543
+ /* @__PURE__ */ jsx6("path", { d: "M12 8h.01" })
4509
4544
  ] });
4510
4545
  }
4511
4546
  function IconArrowRight({ className, ...props }) {
4512
4547
  return /* @__PURE__ */ jsxs3("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
4513
- /* @__PURE__ */ jsx5("path", { d: "M5 12h14" }),
4514
- /* @__PURE__ */ jsx5("path", { d: "m12 5 7 7-7 7" })
4548
+ /* @__PURE__ */ jsx6("path", { d: "M5 12h14" }),
4549
+ /* @__PURE__ */ jsx6("path", { d: "m12 5 7 7-7 7" })
4515
4550
  ] });
4516
4551
  }
4517
4552
  function IconSection({ className, ...props }) {
4518
4553
  return /* @__PURE__ */ jsxs3("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
4519
- /* @__PURE__ */ jsx5("rect", { width: "18", height: "7", x: "3", y: "3", rx: "1" }),
4520
- /* @__PURE__ */ jsx5("rect", { width: "9", height: "7", x: "3", y: "14", rx: "1" }),
4521
- /* @__PURE__ */ jsx5("rect", { width: "5", height: "7", x: "16", y: "14", rx: "1" })
4554
+ /* @__PURE__ */ jsx6("rect", { width: "18", height: "7", x: "3", y: "3", rx: "1" }),
4555
+ /* @__PURE__ */ jsx6("rect", { width: "9", height: "7", x: "3", y: "14", rx: "1" }),
4556
+ /* @__PURE__ */ jsx6("rect", { width: "5", height: "7", x: "16", y: "14", rx: "1" })
4522
4557
  ] });
4523
4558
  }
4524
4559
 
4525
4560
  // src/ui/dialog.tsx
4526
- import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
4561
+ import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
4527
4562
  function Dialog2({ ...props }) {
4528
- return /* @__PURE__ */ jsx6(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
4563
+ return /* @__PURE__ */ jsx7(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
4529
4564
  }
4530
4565
  function DialogPortal({ ...props }) {
4531
- return /* @__PURE__ */ jsx6(DialogPrimitive.Portal, { ...props });
4566
+ return /* @__PURE__ */ jsx7(DialogPrimitive.Portal, { ...props });
4532
4567
  }
4533
4568
  function DialogOverlay({
4534
4569
  className,
4535
4570
  ...props
4536
4571
  }) {
4537
- return /* @__PURE__ */ jsx6(
4572
+ return /* @__PURE__ */ jsx7(
4538
4573
  DialogPrimitive.Overlay,
4539
4574
  {
4540
4575
  "data-slot": "dialog-overlay",
@@ -4544,10 +4579,10 @@ function DialogOverlay({
4544
4579
  }
4545
4580
  );
4546
4581
  }
4547
- var DialogContent = React3.forwardRef(({ className, children, showCloseButton = true, container, ...props }, ref) => {
4582
+ var DialogContent = React4.forwardRef(({ className, children, showCloseButton = true, container, ...props }, ref) => {
4548
4583
  const positionMode = container ? "absolute" : "fixed";
4549
4584
  return /* @__PURE__ */ jsxs4(DialogPortal, { container: container ?? void 0, children: [
4550
- /* @__PURE__ */ jsx6(DialogOverlay, { className: cn(positionMode, "inset-0") }),
4585
+ /* @__PURE__ */ jsx7(DialogOverlay, { className: cn(positionMode, "inset-0") }),
4551
4586
  /* @__PURE__ */ jsxs4(
4552
4587
  DialogPrimitive.Content,
4553
4588
  {
@@ -4564,13 +4599,13 @@ var DialogContent = React3.forwardRef(({ className, children, showCloseButton =
4564
4599
  ...props,
4565
4600
  children: [
4566
4601
  children,
4567
- showCloseButton ? /* @__PURE__ */ jsx6(
4602
+ showCloseButton ? /* @__PURE__ */ jsx7(
4568
4603
  DialogPrimitive.Close,
4569
4604
  {
4570
4605
  type: "button",
4571
4606
  className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
4572
4607
  "aria-label": "Close",
4573
- children: /* @__PURE__ */ jsx6(IconX, { "aria-hidden": true })
4608
+ children: /* @__PURE__ */ jsx7(IconX, { "aria-hidden": true })
4574
4609
  }
4575
4610
  ) : null
4576
4611
  ]
@@ -4580,12 +4615,12 @@ var DialogContent = React3.forwardRef(({ className, children, showCloseButton =
4580
4615
  });
4581
4616
  DialogContent.displayName = DialogPrimitive.Content.displayName;
4582
4617
  function DialogHeader({ className, ...props }) {
4583
- return /* @__PURE__ */ jsx6("div", { className: cn("flex flex-col gap-1.5", className), ...props });
4618
+ return /* @__PURE__ */ jsx7("div", { className: cn("flex flex-col gap-1.5", className), ...props });
4584
4619
  }
4585
4620
  function DialogFooter({ className, ...props }) {
4586
- return /* @__PURE__ */ jsx6("div", { className: cn("flex items-center justify-end gap-2", className), ...props });
4621
+ return /* @__PURE__ */ jsx7("div", { className: cn("flex items-center justify-end gap-2", className), ...props });
4587
4622
  }
4588
- var DialogTitle = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx6(
4623
+ var DialogTitle = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx7(
4589
4624
  DialogPrimitive.Title,
4590
4625
  {
4591
4626
  ref,
@@ -4594,7 +4629,7 @@ var DialogTitle = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE
4594
4629
  }
4595
4630
  ));
4596
4631
  DialogTitle.displayName = DialogPrimitive.Title.displayName;
4597
- var DialogDescription = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx6(
4632
+ var DialogDescription = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx7(
4598
4633
  DialogPrimitive.Description,
4599
4634
  {
4600
4635
  ref,
@@ -4606,9 +4641,9 @@ DialogDescription.displayName = DialogPrimitive.Description.displayName;
4606
4641
  var DialogClose = DialogPrimitive.Close;
4607
4642
 
4608
4643
  // src/ui/button.tsx
4609
- import * as React4 from "react";
4644
+ import * as React5 from "react";
4610
4645
  import { Slot } from "radix-ui";
4611
- import { jsx as jsx7 } from "react/jsx-runtime";
4646
+ import { jsx as jsx8 } from "react/jsx-runtime";
4612
4647
  var buttonVariants = cva(
4613
4648
  "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",
4614
4649
  {
@@ -4629,10 +4664,10 @@ var buttonVariants = cva(
4629
4664
  }
4630
4665
  }
4631
4666
  );
4632
- var Button = React4.forwardRef(
4667
+ var Button = React5.forwardRef(
4633
4668
  ({ className, variant, size, asChild = false, ...props }, ref) => {
4634
4669
  const Comp = asChild ? Slot.Root : "button";
4635
- return /* @__PURE__ */ jsx7(
4670
+ return /* @__PURE__ */ jsx8(
4636
4671
  Comp,
4637
4672
  {
4638
4673
  ref,
@@ -4646,30 +4681,30 @@ var Button = React4.forwardRef(
4646
4681
  Button.displayName = "Button";
4647
4682
 
4648
4683
  // src/ui/link-modal/DestinationBreadcrumb.tsx
4649
- import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
4684
+ import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
4650
4685
  function DestinationBreadcrumb({ pageTitle, sectionLabel }) {
4651
4686
  return /* @__PURE__ */ jsxs5("div", { className: "flex w-full flex-col gap-2", children: [
4652
- /* @__PURE__ */ jsx8("p", { className: "text-sm font-medium text-foreground", children: "Destination" }),
4687
+ /* @__PURE__ */ jsx9("p", { className: "text-sm font-medium text-foreground", children: "Destination" }),
4653
4688
  /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-3", children: [
4654
4689
  /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2", children: [
4655
- /* @__PURE__ */ jsx8(IconFile, { className: "shrink-0 text-foreground", "aria-hidden": true }),
4656
- /* @__PURE__ */ jsx8("span", { className: "text-sm font-medium leading-none text-foreground", children: pageTitle })
4690
+ /* @__PURE__ */ jsx9(IconFile, { className: "shrink-0 text-foreground", "aria-hidden": true }),
4691
+ /* @__PURE__ */ jsx9("span", { className: "text-sm font-medium leading-none text-foreground", children: pageTitle })
4657
4692
  ] }),
4658
- /* @__PURE__ */ jsx8(IconArrowRight, { className: "shrink-0 text-muted-foreground", "aria-hidden": true }),
4693
+ /* @__PURE__ */ jsx9(IconArrowRight, { className: "shrink-0 text-muted-foreground", "aria-hidden": true }),
4659
4694
  /* @__PURE__ */ jsxs5("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
4660
- /* @__PURE__ */ jsx8(IconSection, { className: "shrink-0 text-foreground", "aria-hidden": true }),
4661
- /* @__PURE__ */ jsx8("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
4695
+ /* @__PURE__ */ jsx9(IconSection, { className: "shrink-0 text-foreground", "aria-hidden": true }),
4696
+ /* @__PURE__ */ jsx9("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
4662
4697
  ] })
4663
4698
  ] })
4664
4699
  ] });
4665
4700
  }
4666
4701
 
4667
4702
  // src/ui/link-modal/SectionTreeItem.tsx
4668
- import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
4703
+ import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
4669
4704
  function SectionTreeItem({ section, onSelect, selected }) {
4670
4705
  const interactive = Boolean(onSelect);
4671
4706
  return /* @__PURE__ */ jsxs6("div", { className: "flex h-9 w-full items-end pl-3", children: [
4672
- /* @__PURE__ */ jsx9(
4707
+ /* @__PURE__ */ jsx10(
4673
4708
  "div",
4674
4709
  {
4675
4710
  className: "mr-[-1px] h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
@@ -4694,8 +4729,8 @@ function SectionTreeItem({ section, onSelect, selected }) {
4694
4729
  interactive && selected && "border-primary"
4695
4730
  ),
4696
4731
  children: [
4697
- /* @__PURE__ */ jsx9(IconSection, { className: "shrink-0 text-foreground", "aria-hidden": true }),
4698
- /* @__PURE__ */ jsx9("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
4732
+ /* @__PURE__ */ jsx10(IconSection, { className: "shrink-0 text-foreground", "aria-hidden": true }),
4733
+ /* @__PURE__ */ jsx10("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
4699
4734
  ]
4700
4735
  }
4701
4736
  )
@@ -4703,11 +4738,11 @@ function SectionTreeItem({ section, onSelect, selected }) {
4703
4738
  }
4704
4739
  function SectionPickerList({ sections, onSelect }) {
4705
4740
  if (sections.length === 0) {
4706
- return /* @__PURE__ */ jsx9("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." });
4741
+ return /* @__PURE__ */ jsx10("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." });
4707
4742
  }
4708
4743
  return /* @__PURE__ */ jsxs6("div", { className: "flex flex-col gap-1", children: [
4709
- /* @__PURE__ */ jsx9("p", { className: "text-sm text-muted-foreground", children: "Pick a section this link should scroll to." }),
4710
- sections.map((section) => /* @__PURE__ */ jsx9(SectionTreeItem, { section, onSelect }, section.id))
4744
+ /* @__PURE__ */ jsx10("p", { className: "text-sm text-muted-foreground", children: "Pick a section this link should scroll to." }),
4745
+ sections.map((section) => /* @__PURE__ */ jsx10(SectionTreeItem, { section, onSelect }, section.id))
4711
4746
  ] });
4712
4747
  }
4713
4748
 
@@ -4715,11 +4750,11 @@ function SectionPickerList({ sections, onSelect }) {
4715
4750
  import { useId as useId2, useRef as useRef2, useState as useState3 } from "react";
4716
4751
 
4717
4752
  // src/ui/input.tsx
4718
- import * as React5 from "react";
4719
- import { jsx as jsx10 } from "react/jsx-runtime";
4720
- var Input = React5.forwardRef(
4753
+ import * as React6 from "react";
4754
+ import { jsx as jsx11 } from "react/jsx-runtime";
4755
+ var Input = React6.forwardRef(
4721
4756
  ({ className, type, ...props }, ref) => {
4722
- return /* @__PURE__ */ jsx10(
4757
+ return /* @__PURE__ */ jsx11(
4723
4758
  "input",
4724
4759
  {
4725
4760
  type,
@@ -4738,9 +4773,9 @@ Input.displayName = "Input";
4738
4773
 
4739
4774
  // src/ui/label.tsx
4740
4775
  import { Label as LabelPrimitive } from "radix-ui";
4741
- import { jsx as jsx11 } from "react/jsx-runtime";
4776
+ import { jsx as jsx12 } from "react/jsx-runtime";
4742
4777
  function Label({ className, ...props }) {
4743
- return /* @__PURE__ */ jsx11(
4778
+ return /* @__PURE__ */ jsx12(
4744
4779
  LabelPrimitive.Root,
4745
4780
  {
4746
4781
  "data-slot": "label",
@@ -4751,9 +4786,9 @@ function Label({ className, ...props }) {
4751
4786
  }
4752
4787
 
4753
4788
  // src/ui/link-modal/UrlOrPageInput.tsx
4754
- import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
4789
+ import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
4755
4790
  function FieldChevron({ onClick }) {
4756
- return /* @__PURE__ */ jsx12(
4791
+ return /* @__PURE__ */ jsx13(
4757
4792
  "button",
4758
4793
  {
4759
4794
  type: "button",
@@ -4761,7 +4796,7 @@ function FieldChevron({ onClick }) {
4761
4796
  onClick,
4762
4797
  "aria-label": "Open page list",
4763
4798
  tabIndex: -1,
4764
- children: /* @__PURE__ */ jsx12(IconChevronDown, {})
4799
+ children: /* @__PURE__ */ jsx13(IconChevronDown, {})
4765
4800
  }
4766
4801
  );
4767
4802
  }
@@ -4801,11 +4836,11 @@ function UrlOrPageInput({
4801
4836
  urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
4802
4837
  );
4803
4838
  return /* @__PURE__ */ jsxs7("div", { className: "flex w-full flex-col gap-2 p-0", children: [
4804
- /* @__PURE__ */ jsx12(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
4839
+ /* @__PURE__ */ jsx13(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
4805
4840
  /* @__PURE__ */ jsxs7("div", { className: "relative w-full", children: [
4806
4841
  /* @__PURE__ */ jsxs7("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
4807
- selectedPage ? /* @__PURE__ */ jsx12("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ jsx12(IconFile, { className: "text-foreground", "aria-hidden": true }) }) : null,
4808
- readOnly ? /* @__PURE__ */ jsx12("span", { className: "min-w-0 flex-1 truncate text-sm leading-5 text-foreground", children: selectedPage?.title ?? value }) : /* @__PURE__ */ jsx12(
4842
+ selectedPage ? /* @__PURE__ */ jsx13("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ jsx13(IconFile, { className: "text-foreground", "aria-hidden": true }) }) : null,
4843
+ readOnly ? /* @__PURE__ */ jsx13("span", { className: "min-w-0 flex-1 truncate text-sm leading-5 text-foreground", children: selectedPage?.title ?? value }) : /* @__PURE__ */ jsx13(
4809
4844
  Input,
4810
4845
  {
4811
4846
  ref: inputRef,
@@ -4824,7 +4859,7 @@ function UrlOrPageInput({
4824
4859
  )
4825
4860
  }
4826
4861
  ),
4827
- selectedPage && !readOnly ? /* @__PURE__ */ jsx12(
4862
+ selectedPage && !readOnly ? /* @__PURE__ */ jsx13(
4828
4863
  "button",
4829
4864
  {
4830
4865
  type: "button",
@@ -4832,12 +4867,12 @@ function UrlOrPageInput({
4832
4867
  onMouseDown: clearSelection,
4833
4868
  "aria-label": "Clear selected page",
4834
4869
  tabIndex: -1,
4835
- children: /* @__PURE__ */ jsx12(IconX, { "aria-hidden": true })
4870
+ children: /* @__PURE__ */ jsx13(IconX, { "aria-hidden": true })
4836
4871
  }
4837
4872
  ) : null,
4838
- !readOnly ? /* @__PURE__ */ jsx12(FieldChevron, { onClick: toggleDropdown }) : null
4873
+ !readOnly ? /* @__PURE__ */ jsx13(FieldChevron, { onClick: toggleDropdown }) : null
4839
4874
  ] }),
4840
- dropdownOpen && !readOnly && filteredPages.length > 0 ? /* @__PURE__ */ jsx12(
4875
+ dropdownOpen && !readOnly && filteredPages.length > 0 ? /* @__PURE__ */ jsx13(
4841
4876
  "div",
4842
4877
  {
4843
4878
  "data-ohw-link-page-dropdown": "",
@@ -4850,8 +4885,8 @@ function UrlOrPageInput({
4850
4885
  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",
4851
4886
  onClick: () => onPageSelect(page),
4852
4887
  children: [
4853
- /* @__PURE__ */ jsx12(IconFile, { className: "shrink-0", "aria-hidden": true }),
4854
- /* @__PURE__ */ jsx12("span", { className: "truncate", children: page.title })
4888
+ /* @__PURE__ */ jsx13(IconFile, { className: "shrink-0", "aria-hidden": true }),
4889
+ /* @__PURE__ */ jsx13("span", { className: "truncate", children: page.title })
4855
4890
  ]
4856
4891
  },
4857
4892
  page.path
@@ -4859,7 +4894,7 @@ function UrlOrPageInput({
4859
4894
  }
4860
4895
  ) : null
4861
4896
  ] }),
4862
- urlError ? /* @__PURE__ */ jsx12("p", { className: "text-sm font-medium text-destructive", children: urlError }) : null
4897
+ urlError ? /* @__PURE__ */ jsx13("p", { className: "text-sm font-medium text-destructive", children: urlError }) : null
4863
4898
  ] });
4864
4899
  }
4865
4900
 
@@ -5027,7 +5062,7 @@ function useLinkModalState({
5027
5062
  }
5028
5063
 
5029
5064
  // src/ui/link-modal/LinkEditorPanel.tsx
5030
- import { Fragment as Fragment2, jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
5065
+ import { Fragment as Fragment2, jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
5031
5066
  function LinkEditorPanel({
5032
5067
  open = true,
5033
5068
  mode = "create",
@@ -5052,24 +5087,24 @@ function LinkEditorPanel({
5052
5087
  });
5053
5088
  const isCancel = state.secondaryLabel === "Cancel";
5054
5089
  return /* @__PURE__ */ jsxs8(Fragment2, { children: [
5055
- /* @__PURE__ */ jsx13(DialogClose, { asChild: true, children: /* @__PURE__ */ jsx13(
5090
+ /* @__PURE__ */ jsx14(DialogClose, { asChild: true, children: /* @__PURE__ */ jsx14(
5056
5091
  "button",
5057
5092
  {
5058
5093
  type: "button",
5059
5094
  className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
5060
5095
  "aria-label": "Close",
5061
- children: /* @__PURE__ */ jsx13(IconX, { "aria-hidden": true })
5096
+ children: /* @__PURE__ */ jsx14(IconX, { "aria-hidden": true })
5062
5097
  }
5063
5098
  ) }),
5064
- /* @__PURE__ */ jsx13(DialogHeader, { className: "w-full gap-1.5 p-6 pr-12", children: /* @__PURE__ */ jsx13(DialogTitle, { className: "m-0 w-full break-words", children: state.title }) }),
5099
+ /* @__PURE__ */ jsx14(DialogHeader, { className: "w-full gap-1.5 p-6 pr-12", children: /* @__PURE__ */ jsx14(DialogTitle, { className: "m-0 w-full break-words", children: state.title }) }),
5065
5100
  /* @__PURE__ */ jsxs8("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
5066
- state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ jsx13(
5101
+ state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ jsx14(
5067
5102
  DestinationBreadcrumb,
5068
5103
  {
5069
5104
  pageTitle: state.selectedPage.title,
5070
5105
  sectionLabel: state.selectedSection.label
5071
5106
  }
5072
- ) : /* @__PURE__ */ jsx13(
5107
+ ) : /* @__PURE__ */ jsx14(
5073
5108
  UrlOrPageInput,
5074
5109
  {
5075
5110
  value: state.searchValue,
@@ -5083,17 +5118,17 @@ function LinkEditorPanel({
5083
5118
  }
5084
5119
  ),
5085
5120
  state.showChooseSection ? /* @__PURE__ */ jsxs8("div", { className: "flex flex-col justify-center gap-2", children: [
5086
- /* @__PURE__ */ jsx13(Button, { type: "button", variant: "outline", className: "w-fit cursor-pointer", size: "sm", onClick: state.handleChooseSection, children: "Choose a section" }),
5121
+ /* @__PURE__ */ jsx14(Button, { type: "button", variant: "outline", className: "w-fit cursor-pointer", size: "sm", onClick: state.handleChooseSection, children: "Choose a section" }),
5087
5122
  /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
5088
- /* @__PURE__ */ jsx13(IconInfo, { className: "shrink-0", "aria-hidden": true }),
5089
- /* @__PURE__ */ jsx13("span", { children: "Pick a section this link should scroll to." })
5123
+ /* @__PURE__ */ jsx14(IconInfo, { className: "shrink-0", "aria-hidden": true }),
5124
+ /* @__PURE__ */ jsx14("span", { children: "Pick a section this link should scroll to." })
5090
5125
  ] })
5091
5126
  ] }) : null,
5092
- state.showSectionPicker ? /* @__PURE__ */ jsx13(SectionPickerList, { sections: state.activeSections, onSelect: state.handleSectionSelect }) : null,
5093
- state.showSectionRow && state.selectedSection ? /* @__PURE__ */ jsx13(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
5127
+ state.showSectionPicker ? /* @__PURE__ */ jsx14(SectionPickerList, { sections: state.activeSections, onSelect: state.handleSectionSelect }) : null,
5128
+ state.showSectionRow && state.selectedSection ? /* @__PURE__ */ jsx14(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
5094
5129
  ] }),
5095
5130
  /* @__PURE__ */ jsxs8(DialogFooter, { className: "w-full px-6 pb-6", children: [
5096
- /* @__PURE__ */ jsx13(
5131
+ /* @__PURE__ */ jsx14(
5097
5132
  Button,
5098
5133
  {
5099
5134
  type: "button",
@@ -5108,7 +5143,7 @@ function LinkEditorPanel({
5108
5143
  children: state.secondaryLabel
5109
5144
  }
5110
5145
  ),
5111
- /* @__PURE__ */ jsx13(
5146
+ /* @__PURE__ */ jsx14(
5112
5147
  Button,
5113
5148
  {
5114
5149
  type: "button",
@@ -5127,7 +5162,7 @@ function LinkEditorPanel({
5127
5162
  }
5128
5163
 
5129
5164
  // src/ui/link-modal/LinkPopover.tsx
5130
- import { jsx as jsx14 } from "react/jsx-runtime";
5165
+ import { jsx as jsx15 } from "react/jsx-runtime";
5131
5166
  function LinkPopover({
5132
5167
  open = true,
5133
5168
  panelRef,
@@ -5135,14 +5170,14 @@ function LinkPopover({
5135
5170
  onClose,
5136
5171
  ...editorProps
5137
5172
  }) {
5138
- return /* @__PURE__ */ jsx14(
5173
+ return /* @__PURE__ */ jsx15(
5139
5174
  Dialog2,
5140
5175
  {
5141
5176
  open,
5142
5177
  onOpenChange: (next) => {
5143
5178
  if (!next) onClose?.();
5144
5179
  },
5145
- children: /* @__PURE__ */ jsx14(
5180
+ children: /* @__PURE__ */ jsx15(
5146
5181
  DialogContent,
5147
5182
  {
5148
5183
  ref: panelRef,
@@ -5152,7 +5187,7 @@ function LinkPopover({
5152
5187
  "data-ohw-bridge": "",
5153
5188
  showCloseButton: false,
5154
5189
  className: "gap-0 p-0 w-full md:w-md pointer-events-auto",
5155
- children: /* @__PURE__ */ jsx14(LinkEditorPanel, { ...editorProps, open, onClose })
5190
+ children: /* @__PURE__ */ jsx15(LinkEditorPanel, { ...editorProps, open, onClose })
5156
5191
  }
5157
5192
  )
5158
5193
  }
@@ -5218,7 +5253,7 @@ function shouldUseDevFixtures() {
5218
5253
  }
5219
5254
 
5220
5255
  // src/ui/badge.tsx
5221
- import { jsx as jsx15 } from "react/jsx-runtime";
5256
+ import { jsx as jsx16 } from "react/jsx-runtime";
5222
5257
  var badgeVariants = cva(
5223
5258
  "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",
5224
5259
  {
@@ -5236,11 +5271,11 @@ var badgeVariants = cva(
5236
5271
  }
5237
5272
  );
5238
5273
  function Badge({ className, variant, ...props }) {
5239
- return /* @__PURE__ */ jsx15("div", { className: cn(badgeVariants({ variant }), className), ...props });
5274
+ return /* @__PURE__ */ jsx16("div", { className: cn(badgeVariants({ variant }), className), ...props });
5240
5275
  }
5241
5276
 
5242
5277
  // src/OhhwellsBridge.tsx
5243
- import { Fragment as Fragment3, jsx as jsx16, jsxs as jsxs9 } from "react/jsx-runtime";
5278
+ import { Fragment as Fragment3, jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
5244
5279
  var PRIMARY = "#0885FE";
5245
5280
  var IMAGE_FADE_MS = 300;
5246
5281
  function runOpacityFade(el, onDone) {
@@ -5414,7 +5449,7 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
5414
5449
  const root = createRoot(container);
5415
5450
  flushSync(() => {
5416
5451
  root.render(
5417
- /* @__PURE__ */ jsx16(
5452
+ /* @__PURE__ */ jsx17(
5418
5453
  SchedulingWidget,
5419
5454
  {
5420
5455
  notifyOnConnect,
@@ -5462,6 +5497,20 @@ function applyLinkHref(el, val) {
5462
5497
  const anchor = el instanceof HTMLAnchorElement ? el : el.querySelector("a");
5463
5498
  if (anchor) anchor.setAttribute("href", val);
5464
5499
  }
5500
+ function getEditMeasureEl(editable) {
5501
+ return editable.closest("[data-ohw-href-key]") ?? editable;
5502
+ }
5503
+ function isDragHandleDisabled(el) {
5504
+ const carriers = [
5505
+ el.closest("[data-ohw-href-key]"),
5506
+ el.closest("[data-ohw-editable]")
5507
+ ];
5508
+ return carriers.some((carrier) => {
5509
+ if (!carrier) return false;
5510
+ const raw = carrier.getAttribute("data-ohw-drag-disabled");
5511
+ return raw === "true" || raw === "";
5512
+ });
5513
+ }
5465
5514
  function collectEditableNodes() {
5466
5515
  const nodes = Array.from(document.querySelectorAll("[data-ohw-editable]")).map((el) => {
5467
5516
  if (el.dataset.ohwEditable === "image") {
@@ -5515,6 +5564,14 @@ function getHrefKeyFromElement(el) {
5515
5564
  function isNavbarButton(el) {
5516
5565
  return Boolean(el.closest('[data-ohw-role="navbar-button"]'));
5517
5566
  }
5567
+ function getReorderHandleState(el) {
5568
+ const linkEl = el.closest("[data-ohw-href-key]");
5569
+ if (!linkEl || isNavbarButton(el)) return { key: null, disabled: false };
5570
+ return {
5571
+ key: linkEl.dataset.ohwHrefKey ?? null,
5572
+ disabled: isDragHandleDisabled(el)
5573
+ };
5574
+ }
5518
5575
  function clearHrefKeyHover(anchor) {
5519
5576
  anchor.removeAttribute("data-ohw-hovered");
5520
5577
  anchor.querySelectorAll("[data-ohw-hovered]").forEach((el) => {
@@ -5644,6 +5701,8 @@ var ICONS = {
5644
5701
  insertUnorderedList: '<line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/>',
5645
5702
  insertOrderedList: '<line x1="10" y1="6" x2="21" y2="6"/><line x1="10" y1="12" x2="21" y2="12"/><line x1="10" y1="18" x2="21" y2="18"/><path d="M4 6h1v4"/><path d="M4 10h2"/><path d="M6 18H4c0-1 2-2 2-3s-1-1.5-2-1"/>'
5646
5703
  };
5704
+ var TOOLBAR_PILL_PADDING = 2;
5705
+ var TOOLBAR_TOGGLE_GAP = 4;
5647
5706
  var TOOLBAR_GROUPS = [
5648
5707
  [
5649
5708
  { cmd: "bold", title: "Bold" },
@@ -5661,24 +5720,64 @@ var TOOLBAR_GROUPS = [
5661
5720
  { cmd: "insertOrderedList", title: "Numbered List" }
5662
5721
  ]
5663
5722
  ];
5664
- function GlowFrame({ rect, elRef }) {
5723
+ function EditGlowChrome({
5724
+ rect,
5725
+ elRef,
5726
+ reorderHrefKey,
5727
+ dragDisabled = false
5728
+ }) {
5665
5729
  const GAP = 6;
5666
- return /* @__PURE__ */ jsx16(
5730
+ return /* @__PURE__ */ jsxs9(
5667
5731
  "div",
5668
5732
  {
5669
5733
  ref: elRef,
5734
+ "data-ohw-edit-chrome": "",
5670
5735
  style: {
5671
5736
  position: "fixed",
5672
5737
  top: rect.top - GAP,
5673
5738
  left: rect.left - GAP,
5674
5739
  width: rect.width + GAP * 2,
5675
5740
  height: rect.height + GAP * 2,
5676
- border: "2px solid #0885FE",
5677
- borderRadius: 8,
5678
- boxShadow: "0 0 0 4px rgba(8, 133, 254, 0.12)",
5679
5741
  pointerEvents: "none",
5680
5742
  zIndex: 2147483646
5681
- }
5743
+ },
5744
+ children: [
5745
+ /* @__PURE__ */ jsx17(
5746
+ "div",
5747
+ {
5748
+ style: {
5749
+ position: "absolute",
5750
+ inset: 0,
5751
+ border: "2px solid #0885FE",
5752
+ borderRadius: 8,
5753
+ boxShadow: "0 0 0 4px rgba(8, 133, 254, 0.12)",
5754
+ pointerEvents: "none"
5755
+ }
5756
+ }
5757
+ ),
5758
+ reorderHrefKey && /* @__PURE__ */ jsx17(
5759
+ "div",
5760
+ {
5761
+ "data-ohw-drag-handle-container": "",
5762
+ "data-ohw-drag-disabled": dragDisabled ? "" : void 0,
5763
+ style: {
5764
+ position: "absolute",
5765
+ left: 0,
5766
+ top: "50%",
5767
+ transform: "translate(calc(-100% - 7px), -50%)",
5768
+ pointerEvents: dragDisabled ? "none" : "auto"
5769
+ },
5770
+ children: /* @__PURE__ */ jsx17(
5771
+ DragHandle,
5772
+ {
5773
+ "aria-label": `Reorder ${reorderHrefKey}`,
5774
+ disabled: dragDisabled,
5775
+ "aria-disabled": dragDisabled
5776
+ }
5777
+ )
5778
+ }
5779
+ )
5780
+ ]
5682
5781
  }
5683
5782
  );
5684
5783
  }
@@ -5722,9 +5821,9 @@ function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
5722
5821
  const pinnedTop = Math.min(maxBottom - approxH, Math.max(minTop, clip.top + gap));
5723
5822
  return { top: pinnedTop + approxH, transform: "translateX(-50%) translateY(-100%)" };
5724
5823
  }
5725
- function calcToolbarPos(rect, parentScroll, approxW = 330) {
5824
+ function calcToolbarPos(rect, parentScroll, approxW = 306) {
5726
5825
  const GAP = 8;
5727
- const APPROX_H = 36;
5826
+ const APPROX_H = 32;
5728
5827
  const APPROX_W = approxW;
5729
5828
  const clip = getIframeVisibleClip(parentScroll);
5730
5829
  const clipTop = clip?.top ?? 0;
@@ -5759,8 +5858,8 @@ function calcToolbarPos(rect, parentScroll, approxW = 330) {
5759
5858
  return { top, left, transform };
5760
5859
  }
5761
5860
  var EDIT_LINK_ICON = /* @__PURE__ */ jsxs9("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
5762
- /* @__PURE__ */ jsx16("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }),
5763
- /* @__PURE__ */ jsx16("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })
5861
+ /* @__PURE__ */ jsx17("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }),
5862
+ /* @__PURE__ */ jsx17("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })
5764
5863
  ] });
5765
5864
  function FloatingToolbar({
5766
5865
  rect,
@@ -5772,7 +5871,7 @@ function FloatingToolbar({
5772
5871
  showEditLink,
5773
5872
  onEditLink
5774
5873
  }) {
5775
- const approxW = variant === "link-action" ? 120 : 330;
5874
+ const approxW = variant === "link-action" ? 112 : 306;
5776
5875
  const { top, left, transform } = calcToolbarPos(rect, parentScroll, approxW);
5777
5876
  if (variant === "link-action") {
5778
5877
  return /* @__PURE__ */ jsxs9(
@@ -5792,15 +5891,15 @@ function FloatingToolbar({
5792
5891
  boxShadow: "0px 2px 4px -2px rgba(0,0,0,.1),0px 4px 6px -1px rgba(0,0,0,.1)",
5793
5892
  display: "flex",
5794
5893
  alignItems: "center",
5795
- padding: 4,
5796
- gap: 6,
5894
+ padding: TOOLBAR_PILL_PADDING,
5895
+ gap: TOOLBAR_TOGGLE_GAP,
5797
5896
  fontFamily: "sans-serif",
5798
5897
  pointerEvents: "auto",
5799
5898
  whiteSpace: "nowrap"
5800
5899
  },
5801
5900
  onMouseDown: (e) => e.stopPropagation(),
5802
5901
  children: [
5803
- /* @__PURE__ */ jsx16(
5902
+ /* @__PURE__ */ jsx17(
5804
5903
  "button",
5805
5904
  {
5806
5905
  type: "button",
@@ -5835,8 +5934,8 @@ function FloatingToolbar({
5835
5934
  children: EDIT_LINK_ICON
5836
5935
  }
5837
5936
  ),
5838
- /* @__PURE__ */ jsx16("span", { style: { display: "block", width: 1, height: 24, background: "#E7E5E4", flexShrink: 0 } }),
5839
- /* @__PURE__ */ jsx16(
5937
+ /* @__PURE__ */ jsx17("span", { style: { display: "block", width: 1, height: 24, background: "#E7E5E4", flexShrink: 0 } }),
5938
+ /* @__PURE__ */ jsx17(
5840
5939
  "button",
5841
5940
  {
5842
5941
  type: "button",
@@ -5856,9 +5955,9 @@ function FloatingToolbar({
5856
5955
  opacity: 0.6
5857
5956
  },
5858
5957
  children: /* @__PURE__ */ jsxs9("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": true, children: [
5859
- /* @__PURE__ */ jsx16("circle", { cx: "5", cy: "12", r: "1.5" }),
5860
- /* @__PURE__ */ jsx16("circle", { cx: "12", cy: "12", r: "1.5" }),
5861
- /* @__PURE__ */ jsx16("circle", { cx: "19", cy: "12", r: "1.5" })
5958
+ /* @__PURE__ */ jsx17("circle", { cx: "5", cy: "12", r: "1.5" }),
5959
+ /* @__PURE__ */ jsx17("circle", { cx: "12", cy: "12", r: "1.5" }),
5960
+ /* @__PURE__ */ jsx17("circle", { cx: "19", cy: "12", r: "1.5" })
5862
5961
  ] })
5863
5962
  }
5864
5963
  )
@@ -5883,19 +5982,19 @@ function FloatingToolbar({
5883
5982
  boxShadow: "0px 2px 4px -2px rgba(0,0,0,.1),0px 4px 6px -1px rgba(0,0,0,.1)",
5884
5983
  display: "flex",
5885
5984
  alignItems: "center",
5886
- padding: 4,
5887
- gap: 6,
5985
+ padding: TOOLBAR_PILL_PADDING,
5986
+ gap: TOOLBAR_TOGGLE_GAP,
5888
5987
  fontFamily: "sans-serif",
5889
5988
  pointerEvents: "auto",
5890
5989
  whiteSpace: "nowrap"
5891
5990
  },
5892
5991
  onMouseDown: (e) => e.stopPropagation(),
5893
5992
  children: [
5894
- TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs9(React6.Fragment, { children: [
5895
- gi > 0 && /* @__PURE__ */ jsx16("span", { style: { display: "block", width: 1, height: 24, background: "#E7E5E4", flexShrink: 0 } }),
5993
+ TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs9(React7.Fragment, { children: [
5994
+ gi > 0 && /* @__PURE__ */ jsx17("span", { style: { display: "block", width: 1, height: 24, background: "#E7E5E4", flexShrink: 0 } }),
5896
5995
  btns.map((btn) => {
5897
5996
  const isActive = activeCommands.has(btn.cmd);
5898
- return /* @__PURE__ */ jsx16(
5997
+ return /* @__PURE__ */ jsx17(
5899
5998
  "button",
5900
5999
  {
5901
6000
  title: btn.title,
@@ -5921,7 +6020,7 @@ function FloatingToolbar({
5921
6020
  flexShrink: 0,
5922
6021
  padding: 6
5923
6022
  },
5924
- children: /* @__PURE__ */ jsx16(
6023
+ children: /* @__PURE__ */ jsx17(
5925
6024
  "svg",
5926
6025
  {
5927
6026
  width: "16",
@@ -5941,7 +6040,7 @@ function FloatingToolbar({
5941
6040
  );
5942
6041
  })
5943
6042
  ] }, gi)),
5944
- showEditLink ? /* @__PURE__ */ jsx16(
6043
+ showEditLink ? /* @__PURE__ */ jsx17(
5945
6044
  "button",
5946
6045
  {
5947
6046
  type: "button",
@@ -5990,7 +6089,7 @@ function StateToggle({
5990
6089
  states,
5991
6090
  onStateChange
5992
6091
  }) {
5993
- return /* @__PURE__ */ jsx16(
6092
+ return /* @__PURE__ */ jsx17(
5994
6093
  ToggleGroup,
5995
6094
  {
5996
6095
  "data-ohw-state-toggle": "",
@@ -6004,7 +6103,7 @@ function StateToggle({
6004
6103
  left: rect.right - 8,
6005
6104
  transform: "translateX(-100%)"
6006
6105
  },
6007
- children: states.map((state) => /* @__PURE__ */ jsx16(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
6106
+ children: states.map((state) => /* @__PURE__ */ jsx17(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
6008
6107
  }
6009
6108
  );
6010
6109
  }
@@ -6102,6 +6201,8 @@ function OhhwellsBridge() {
6102
6201
  const [toolbarVariant, setToolbarVariant] = useState5("none");
6103
6202
  const toolbarVariantRef = useRef3("none");
6104
6203
  toolbarVariantRef.current = toolbarVariant;
6204
+ const [reorderHrefKey, setReorderHrefKey] = useState5(null);
6205
+ const [reorderDragDisabled, setReorderDragDisabled] = useState5(false);
6105
6206
  const [toggleState, setToggleState] = useState5(null);
6106
6207
  const [maxBadge, setMaxBadge] = useState5(null);
6107
6208
  const [activeCommands, setActiveCommands] = useState5(/* @__PURE__ */ new Set());
@@ -6208,7 +6309,7 @@ function OhhwellsBridge() {
6208
6309
  useEffect3(() => {
6209
6310
  const update = () => {
6210
6311
  const el = activeElRef.current ?? selectedElRef.current;
6211
- if (el) setToolbarRect(el.getBoundingClientRect());
6312
+ if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
6212
6313
  setToggleState((prev) => {
6213
6314
  if (!prev || !activeStateElRef.current) return prev;
6214
6315
  return { ...prev, rect: activeStateElRef.current.getBoundingClientRect() };
@@ -6275,6 +6376,8 @@ function OhhwellsBridge() {
6275
6376
  }
6276
6377
  el.removeAttribute("contenteditable");
6277
6378
  activeElRef.current = null;
6379
+ setReorderHrefKey(null);
6380
+ setReorderDragDisabled(false);
6278
6381
  if (!selectedElRef.current) {
6279
6382
  setToolbarRect(null);
6280
6383
  setToolbarVariant("none");
@@ -6312,11 +6415,15 @@ function OhhwellsBridge() {
6312
6415
  setToolbarVariant("rich-text");
6313
6416
  el.setAttribute("contenteditable", "true");
6314
6417
  el.removeAttribute("data-ohw-hovered");
6418
+ el.closest("[data-ohw-href-key]")?.removeAttribute("data-ohw-hovered");
6315
6419
  activeElRef.current = el;
6316
6420
  originalContentRef.current = el.innerHTML;
6317
6421
  el.focus();
6318
- setToolbarRect(el.getBoundingClientRect());
6319
6422
  setToolbarShowEditLink(Boolean(getHrefKeyFromElement(el)));
6423
+ const { key: reorderKey, disabled: reorderDisabled } = getReorderHandleState(el);
6424
+ setReorderHrefKey(reorderKey);
6425
+ setReorderDragDisabled(reorderDisabled);
6426
+ setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
6320
6427
  postToParent({ type: "ow:enter-edit", key: el.dataset.ohwKey });
6321
6428
  requestAnimationFrame(() => refreshActiveCommandsRef.current());
6322
6429
  }, [deactivate, postToParent]);
@@ -6381,30 +6488,36 @@ function OhhwellsBridge() {
6381
6488
  return () => {
6382
6489
  cancelled = true;
6383
6490
  };
6384
- }, [subdomain, isEditMode, pathname]);
6491
+ }, [subdomain, isEditMode]);
6385
6492
  useEffect3(() => {
6386
6493
  if (!subdomain || isEditMode) return;
6387
6494
  let debounceTimer = null;
6495
+ let observer = null;
6388
6496
  const applyFromCache = () => {
6389
6497
  const content = contentCache.get(subdomain);
6390
6498
  if (!content) return;
6391
6499
  retryMissingSchedulingMounts(getPageSchedulingEntries(content["__ohw_sections"]), false);
6392
- for (const [key, val] of Object.entries(content)) {
6393
- if (key === "__ohw_sections") continue;
6394
- document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
6395
- if (el.dataset.ohwEditable === "image") {
6396
- const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
6397
- if (img && img.src !== val) img.src = val;
6398
- } else if (el.dataset.ohwEditable === "bg-image") {
6399
- const next = `url('${val}')`;
6400
- if (el.style.backgroundImage !== next) el.style.backgroundImage = next;
6401
- } else if (el.dataset.ohwEditable === "link") {
6402
- applyLinkHref(el, val);
6403
- } else if (el.innerHTML !== val) {
6404
- el.innerHTML = val;
6405
- }
6406
- });
6407
- applyLinkByKey(key, val);
6500
+ observer?.disconnect();
6501
+ try {
6502
+ for (const [key, val] of Object.entries(content)) {
6503
+ if (key === "__ohw_sections") continue;
6504
+ document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
6505
+ if (el.dataset.ohwEditable === "image") {
6506
+ const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
6507
+ if (img && img.src !== val) img.src = val;
6508
+ } else if (el.dataset.ohwEditable === "bg-image") {
6509
+ const next = `url('${val}')`;
6510
+ if (el.style.backgroundImage !== next) el.style.backgroundImage = next;
6511
+ } else if (el.dataset.ohwEditable === "link") {
6512
+ applyLinkHref(el, val);
6513
+ } else if (el.innerHTML !== val) {
6514
+ el.innerHTML = val;
6515
+ }
6516
+ });
6517
+ applyLinkByKey(key, val);
6518
+ }
6519
+ } finally {
6520
+ observer?.observe(document.body, { childList: true, subtree: true });
6408
6521
  }
6409
6522
  enforceLinkHrefs();
6410
6523
  };
@@ -6412,11 +6525,11 @@ function OhhwellsBridge() {
6412
6525
  if (debounceTimer) clearTimeout(debounceTimer);
6413
6526
  debounceTimer = setTimeout(applyFromCache, 150);
6414
6527
  };
6415
- scheduleApply();
6416
- const observer = new MutationObserver(scheduleApply);
6528
+ applyFromCache();
6529
+ observer = new MutationObserver(scheduleApply);
6417
6530
  observer.observe(document.body, { childList: true, subtree: true });
6418
6531
  return () => {
6419
- observer.disconnect();
6532
+ observer?.disconnect();
6420
6533
  if (debounceTimer) clearTimeout(debounceTimer);
6421
6534
  };
6422
6535
  }, [subdomain, isEditMode, pathname]);
@@ -6540,6 +6653,11 @@ function OhhwellsBridge() {
6540
6653
  if (target.closest("[data-ohw-state-toggle]")) return;
6541
6654
  if (target.closest("[data-ohw-max-badge]")) return;
6542
6655
  if (isInsideLinkEditor(target)) return;
6656
+ if (target.closest('[data-ohw-edit-chrome], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
6657
+ e.preventDefault();
6658
+ e.stopPropagation();
6659
+ return;
6660
+ }
6543
6661
  const editable = target.closest("[data-ohw-editable]");
6544
6662
  if (editable) {
6545
6663
  if (editable.dataset.ohwEditable === "link") {
@@ -6616,14 +6734,18 @@ function OhhwellsBridge() {
6616
6734
  const selected = selectedElRef.current;
6617
6735
  if (selected && (selected === editable || selected.contains(editable))) return;
6618
6736
  if (editable.dataset.ohwEditable !== "image" && editable.dataset.ohwEditable !== "bg-image" && !editable.hasAttribute("contenteditable")) {
6619
- editable.setAttribute("data-ohw-hovered", "");
6737
+ const hoverTarget = editable.closest("[data-ohw-href-key]") ?? editable;
6738
+ hoverTarget.setAttribute("data-ohw-hovered", "");
6620
6739
  }
6621
6740
  };
6622
6741
  const handleMouseOut = (e) => {
6623
6742
  const editable = e.target.closest("[data-ohw-editable]");
6624
6743
  if (!editable) return;
6744
+ const related = e.relatedTarget instanceof Element ? e.relatedTarget : null;
6745
+ if (related?.closest("[data-ohw-drag-handle-container]")) return;
6625
6746
  if (editable.dataset.ohwEditable !== "image" && editable.dataset.ohwEditable !== "bg-image") {
6626
- editable.removeAttribute("data-ohw-hovered");
6747
+ const hoverTarget = editable.closest("[data-ohw-href-key]") ?? editable;
6748
+ hoverTarget.removeAttribute("data-ohw-hovered");
6627
6749
  }
6628
6750
  };
6629
6751
  const toProbeCoords = (clientX, clientY, fromParentViewport) => {
@@ -6738,11 +6860,20 @@ function OhhwellsBridge() {
6738
6860
  return;
6739
6861
  }
6740
6862
  }
6863
+ if (activeElRef.current) {
6864
+ if (hoveredImageRef.current) {
6865
+ hoveredImageRef.current = null;
6866
+ hoveredImageHasTextOverlapRef.current = false;
6867
+ resumeAnimTracks();
6868
+ postToParentRef.current({ type: "ow:image-unhover" });
6869
+ }
6870
+ return;
6871
+ }
6741
6872
  const imgEl = findImageAtPoint(clientX, clientY, fromParentViewport);
6742
6873
  if (imgEl) {
6743
6874
  const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
6744
6875
  const topEl = document.elementFromPoint(x, y);
6745
- if (topEl?.closest("[data-ohw-toolbar]")) {
6876
+ if (topEl?.closest('[data-ohw-toolbar], [data-ohw-edit-chrome], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
6746
6877
  if (hoveredImageRef.current) {
6747
6878
  hoveredImageRef.current = null;
6748
6879
  resumeAnimTracks();
@@ -7035,7 +7166,7 @@ function OhhwellsBridge() {
7035
7166
  const el = e.target;
7036
7167
  const key = el.dataset.ohwKey;
7037
7168
  if (!key) return;
7038
- if (el === activeElRef.current) setToolbarRect(el.getBoundingClientRect());
7169
+ if (el === activeElRef.current) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
7039
7170
  const maxLen = el.dataset.ohwMaxLength ? parseInt(el.dataset.ohwMaxLength, 10) : null;
7040
7171
  if (maxLen) {
7041
7172
  const current = el.innerText.replace(/\n$/, "").length;
@@ -7265,7 +7396,7 @@ function OhhwellsBridge() {
7265
7396
  };
7266
7397
  const applyToolbarPos = (rect) => {
7267
7398
  const ps = parentScrollRef.current;
7268
- const approxW = toolbarVariantRef.current === "link-action" ? 120 : 330;
7399
+ const approxW = toolbarVariantRef.current === "link-action" ? 112 : 306;
7269
7400
  if (toolbarElRef.current) {
7270
7401
  const { top, left, transform } = calcToolbarPos(rect, ps, approxW);
7271
7402
  toolbarElRef.current.style.top = `${top}px`;
@@ -7444,7 +7575,7 @@ function OhhwellsBridge() {
7444
7575
  const handleCommand = useCallback2((cmd) => {
7445
7576
  document.execCommand(cmd, false);
7446
7577
  activeElRef.current?.focus();
7447
- if (activeElRef.current) setToolbarRect(activeElRef.current.getBoundingClientRect());
7578
+ if (activeElRef.current) setToolbarRect(getEditMeasureEl(activeElRef.current).getBoundingClientRect());
7448
7579
  refreshActiveCommandsRef.current();
7449
7580
  }, []);
7450
7581
  const handleStateChange = useCallback2((state) => {
@@ -7498,10 +7629,18 @@ function OhhwellsBridge() {
7498
7629
  linkPopoverOpenRef.current = linkPopover !== null;
7499
7630
  return bridgeRoot ? createPortal(
7500
7631
  /* @__PURE__ */ jsxs9(Fragment3, { children: [
7501
- /* @__PURE__ */ jsx16("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
7632
+ /* @__PURE__ */ jsx17("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
7502
7633
  toolbarRect && /* @__PURE__ */ jsxs9(Fragment3, { children: [
7503
- /* @__PURE__ */ jsx16(GlowFrame, { rect: toolbarRect, elRef: glowElRef }),
7504
- toolbarVariant === "rich-text" && /* @__PURE__ */ jsx16(
7634
+ /* @__PURE__ */ jsx17(
7635
+ EditGlowChrome,
7636
+ {
7637
+ rect: toolbarRect,
7638
+ elRef: glowElRef,
7639
+ reorderHrefKey,
7640
+ dragDisabled: reorderDragDisabled
7641
+ }
7642
+ ),
7643
+ toolbarVariant === "rich-text" && /* @__PURE__ */ jsx17(
7505
7644
  FloatingToolbar,
7506
7645
  {
7507
7646
  variant: "rich-text",
@@ -7514,7 +7653,7 @@ function OhhwellsBridge() {
7514
7653
  onEditLink: openLinkPopoverForActive
7515
7654
  }
7516
7655
  ),
7517
- toolbarVariant === "link-action" && /* @__PURE__ */ jsx16(
7656
+ toolbarVariant === "link-action" && /* @__PURE__ */ jsx17(
7518
7657
  FloatingToolbar,
7519
7658
  {
7520
7659
  variant: "link-action",
@@ -7553,7 +7692,7 @@ function OhhwellsBridge() {
7553
7692
  ]
7554
7693
  }
7555
7694
  ),
7556
- toggleState && /* @__PURE__ */ jsx16(
7695
+ toggleState && /* @__PURE__ */ jsx17(
7557
7696
  StateToggle,
7558
7697
  {
7559
7698
  rect: toggleState.rect,
@@ -7569,8 +7708,8 @@ function OhhwellsBridge() {
7569
7708
  className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
7570
7709
  style: { top: sectionGap.y, transform: "translateY(-50%)" },
7571
7710
  children: [
7572
- /* @__PURE__ */ jsx16("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
7573
- /* @__PURE__ */ jsx16(
7711
+ /* @__PURE__ */ jsx17("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
7712
+ /* @__PURE__ */ jsx17(
7574
7713
  Badge,
7575
7714
  {
7576
7715
  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",
@@ -7583,11 +7722,11 @@ function OhhwellsBridge() {
7583
7722
  children: "Add Section"
7584
7723
  }
7585
7724
  ),
7586
- /* @__PURE__ */ jsx16("div", { className: "flex-1 bg-primary", style: { height: 3 } })
7725
+ /* @__PURE__ */ jsx17("div", { className: "flex-1 bg-primary", style: { height: 3 } })
7587
7726
  ]
7588
7727
  }
7589
7728
  ),
7590
- linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx16(
7729
+ linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx17(
7591
7730
  LinkPopover,
7592
7731
  {
7593
7732
  panelRef: linkPopoverPanelRef,
@@ -7602,12 +7741,38 @@ function OhhwellsBridge() {
7602
7741
  onSubmit: handleLinkPopoverSubmit
7603
7742
  },
7604
7743
  `${linkPopover.key}-${pathname}`
7605
- ) : null
7744
+ ) : null,
7745
+ sectionGap && /* @__PURE__ */ jsxs9(
7746
+ "div",
7747
+ {
7748
+ "data-ohw-section-insert-line": "",
7749
+ className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
7750
+ style: { top: sectionGap.y, transform: "translateY(-50%)" },
7751
+ children: [
7752
+ /* @__PURE__ */ jsx17("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
7753
+ /* @__PURE__ */ jsx17(
7754
+ Badge,
7755
+ {
7756
+ 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",
7757
+ onClick: () => {
7758
+ window.parent.postMessage(
7759
+ { type: "ow:add-section", insertAfter: sectionGap.insertAfter, insertBefore: sectionGap.insertBefore },
7760
+ "*"
7761
+ );
7762
+ },
7763
+ children: "Add Section"
7764
+ }
7765
+ ),
7766
+ /* @__PURE__ */ jsx17("div", { className: "flex-1 bg-primary", style: { height: 3 } })
7767
+ ]
7768
+ }
7769
+ )
7606
7770
  ] }),
7607
7771
  bridgeRoot
7608
7772
  ) : null;
7609
7773
  }
7610
7774
  export {
7775
+ DragHandle,
7611
7776
  LinkEditorPanel,
7612
7777
  LinkPopover,
7613
7778
  OhhwellsBridge,
@@ -7618,6 +7783,7 @@ export {
7618
7783
  buildTarget,
7619
7784
  filterAvailablePages,
7620
7785
  getEditModeInitialState,
7786
+ isEditSessionActive,
7621
7787
  isValidUrl,
7622
7788
  parseTarget,
7623
7789
  toggleVariants,