@ohhwells/bridge 0.1.34 → 0.1.36-next.45

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
@@ -31,6 +31,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  // src/index.ts
32
32
  var index_exports = {};
33
33
  __export(index_exports, {
34
+ CustomToolbar: () => CustomToolbar,
35
+ CustomToolbarButton: () => CustomToolbarButton,
36
+ CustomToolbarDivider: () => CustomToolbarDivider,
37
+ DragHandle: () => DragHandle,
38
+ ItemActionToolbar: () => ItemActionToolbar,
39
+ ItemInteractionLayer: () => ItemInteractionLayer,
34
40
  LinkEditorPanel: () => LinkEditorPanel,
35
41
  LinkPopover: () => LinkPopover,
36
42
  OhhwellsBridge: () => OhhwellsBridge,
@@ -38,9 +44,14 @@ __export(index_exports, {
38
44
  Toggle: () => Toggle,
39
45
  ToggleGroup: () => ToggleGroup,
40
46
  ToggleGroupItem: () => ToggleGroupItem,
47
+ Tooltip: () => Tooltip,
48
+ TooltipContent: () => TooltipContent,
49
+ TooltipProvider: () => TooltipProvider,
50
+ TooltipTrigger: () => TooltipTrigger,
41
51
  buildTarget: () => buildTarget,
42
52
  filterAvailablePages: () => filterAvailablePages,
43
53
  getEditModeInitialState: () => getEditModeInitialState,
54
+ isEditSessionActive: () => isEditSessionActive,
44
55
  isValidUrl: () => isValidUrl,
45
56
  parseTarget: () => parseTarget,
46
57
  toggleVariants: () => toggleVariants,
@@ -99,6 +110,7 @@ var import_react3 = require("react");
99
110
  var import_react2 = require("react");
100
111
  var import_radix_ui = require("radix-ui");
101
112
  var import_jsx_runtime = require("react/jsx-runtime");
113
+ var isValidEmail = (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
102
114
  function Spinner() {
103
115
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
104
116
  "svg",
@@ -132,12 +144,17 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
132
144
  const [error, setError] = (0, import_react2.useState)(null);
133
145
  const isBook = title === "Confirm your spot";
134
146
  const handleSubmit = async () => {
135
- if (!email.trim()) return;
147
+ const trimmed = email.trim();
148
+ if (!trimmed) return;
149
+ if (!isValidEmail(trimmed)) {
150
+ setError("Please enter a valid email address.");
151
+ return;
152
+ }
136
153
  setLoading(true);
137
154
  setError(null);
138
155
  try {
139
- await onSubmit(email.trim());
140
- setSubmittedEmail(email.trim());
156
+ await onSubmit(trimmed);
157
+ setSubmittedEmail(trimmed);
141
158
  setSuccess(true);
142
159
  } catch (e) {
143
160
  setError(e instanceof Error ? e.message : "Something went wrong. Please try again.");
@@ -212,7 +229,10 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
212
229
  {
213
230
  type: "email",
214
231
  value: email,
215
- onChange: (e) => setEmail(e.target.value),
232
+ onChange: (e) => {
233
+ setEmail(e.target.value);
234
+ if (error) setError(null);
235
+ },
216
236
  onKeyDown: handleKeyDown,
217
237
  placeholder: "hello@gmail.com",
218
238
  autoFocus: true,
@@ -269,12 +289,20 @@ function formatClassTime(cls) {
269
289
  const em = endTotal % 60;
270
290
  return `${h}:${cls.startTime.minutes}-${eh}:${String(em).padStart(2, "0")}`;
271
291
  }
292
+ function formatBookingLabel(cls) {
293
+ const price = cls.price;
294
+ const isFree = price === null || price === void 0 || `${price}` === "" || `${price}` === "0";
295
+ return isFree ? "Book for free" : `Book for ${cls.currency ?? ""} ${price}`.trim();
296
+ }
272
297
  function getBookingsOnDate(cls, date) {
273
298
  if (!cls.bookings?.length) return 0;
274
- const ds = date.toISOString().split("T")[0];
299
+ const target = new Date(date);
300
+ target.setHours(0, 0, 0, 0);
275
301
  return cls.bookings.filter((b) => {
276
302
  try {
277
- return new Date(b.classDate).toISOString().split("T")[0] === ds;
303
+ const bookingDate = new Date(b.classDate);
304
+ bookingDate.setHours(0, 0, 0, 0);
305
+ return bookingDate.getTime() === target.getTime();
278
306
  } catch {
279
307
  return false;
280
308
  }
@@ -578,7 +606,7 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
578
606
  if (!cls.id) return;
579
607
  onOpenModal?.(isFull ? "waitlist" : "book", cls.id, selectedDate);
580
608
  },
581
- children: isFull ? "Join Waitlist" : "Book Now"
609
+ children: isFull ? "Join Waitlist" : formatBookingLabel(cls)
582
610
  }
583
611
  )
584
612
  ] })
@@ -620,6 +648,17 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
620
648
  const [isHovered, setIsHovered] = (0, import_react3.useState)(false);
621
649
  const [modalState, setModalState] = (0, import_react3.useState)(null);
622
650
  const switchScheduleIdRef = (0, import_react3.useRef)(null);
651
+ const liveScheduleIdRef = (0, import_react3.useRef)(null);
652
+ const refetchLiveSchedule = (0, import_react3.useCallback)(async () => {
653
+ const id = liveScheduleIdRef.current;
654
+ if (!id) return;
655
+ try {
656
+ const res = await fetch(`${API_URL}/api/schedule/id/${id}`);
657
+ const data = await res.json();
658
+ if (data?.id) setSchedule(data);
659
+ } catch {
660
+ }
661
+ }, []);
623
662
  const dates = (0, import_react3.useMemo)(() => {
624
663
  const today = /* @__PURE__ */ new Date();
625
664
  today.setHours(0, 0, 0, 0);
@@ -639,6 +678,18 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
639
678
  }
640
679
  }
641
680
  }, [schedule, dates]);
681
+ (0, import_react3.useEffect)(() => {
682
+ if (typeof window === "undefined") return;
683
+ const onVisible = () => {
684
+ if (!document.hidden) void refetchLiveSchedule();
685
+ };
686
+ window.addEventListener("focus", refetchLiveSchedule);
687
+ document.addEventListener("visibilitychange", onVisible);
688
+ return () => {
689
+ window.removeEventListener("focus", refetchLiveSchedule);
690
+ document.removeEventListener("visibilitychange", onVisible);
691
+ };
692
+ }, [refetchLiveSchedule]);
642
693
  (0, import_react3.useEffect)(() => {
643
694
  if (typeof window === "undefined") return;
644
695
  const isInEditor = window.self !== window.top;
@@ -700,7 +751,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
700
751
  setLoading(false);
701
752
  return;
702
753
  }
703
- ;
754
+ liveScheduleIdRef.current = effectiveId;
704
755
  (async () => {
705
756
  try {
706
757
  const res = await fetch(`${API_URL}/api/schedule/id/${effectiveId}`);
@@ -757,18 +808,14 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
757
808
  const data = await res.json().catch(() => ({}));
758
809
  throw new Error(data?.message ?? "Something went wrong. Please try again.");
759
810
  }
811
+ await refetchLiveSchedule();
760
812
  };
761
813
  const handleReplaceSchedule = () => {
762
814
  setIsHovered(false);
763
- if (schedule) {
764
- window.parent.postMessage({
765
- type: "ow:schedule-connected",
766
- schedule: { id: schedule.id, name: schedule.name },
767
- insertAfter
768
- }, "*");
769
- } else {
770
- window.parent.postMessage({ type: "ow:scheduling-not-connected", insertAfter }, "*");
771
- }
815
+ window.parent.postMessage(
816
+ { type: "ow:scheduling-not-connected", insertAfter, currentScheduleId: schedule?.id },
817
+ "*"
818
+ );
772
819
  };
773
820
  if (!inEditor && !loading && !schedule) return null;
774
821
  const sectionId = `scheduling-${insertAfter}`;
@@ -811,7 +858,19 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
811
858
  ),
812
859
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "max-w-[1280px] mx-auto flex flex-col items-center gap-16", children: [
813
860
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col items-center gap-4", children: [
814
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("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" }),
861
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
862
+ "h2",
863
+ {
864
+ className: "font-display text-center m-0 text-(--color-dark,#200C02)",
865
+ style: {
866
+ fontSize: "var(--fs-section-h2, clamp(40px, 4.4vw, 64px))",
867
+ fontWeight: "var(--font-weight-heading, 400)",
868
+ lineHeight: 1.05,
869
+ letterSpacing: "-0.02em"
870
+ },
871
+ children: schedule?.name ?? "Book an appointment"
872
+ }
873
+ ),
815
874
  schedule?.description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "font-body text-body text-center m-0 text-(--color-accent,#A89B83)", children: schedule.description })
816
875
  ] }),
817
876
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "w-full flex flex-col items-end gap-3", children: [
@@ -4250,6 +4309,336 @@ function ToggleGroupItem({
4250
4309
  );
4251
4310
  }
4252
4311
 
4312
+ // src/ui/drag-handle.tsx
4313
+ var React3 = __toESM(require("react"), 1);
4314
+ var import_lucide_react = require("lucide-react");
4315
+ var import_jsx_runtime5 = require("react/jsx-runtime");
4316
+ var DragHandle = React3.forwardRef(
4317
+ ({ className, type = "button", ...props }, ref) => {
4318
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
4319
+ "button",
4320
+ {
4321
+ ref,
4322
+ type,
4323
+ "data-slot": "drag-handle",
4324
+ className: cn(
4325
+ "inline-flex h-7 w-4 shrink-0 items-center justify-center rounded-md transition-all duration-200 max-h-[30px]",
4326
+ "bg-white border border-transparent text-stone-500 shadow-md cursor-grab",
4327
+ "enabled:hover:border enabled:hover:border-stone-200 enabled:hover:text-stone-950",
4328
+ "enabled:active:border enabled:active:border-primary enabled:active:bg-primary-50 enabled:active:text-stone-950 enabled:active:shadow enabled:active:cursor-grabbing",
4329
+ "disabled:cursor-not-allowed disabled:opacity-40 disabled:text-stone-950 disabled:pointer-events-none",
4330
+ className
4331
+ ),
4332
+ ...props,
4333
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.GripVertical, { className: "size-4 shrink-0", "aria-hidden": "true" })
4334
+ }
4335
+ );
4336
+ }
4337
+ );
4338
+ DragHandle.displayName = "DragHandle";
4339
+
4340
+ // src/ui/custom-toolbar.tsx
4341
+ var React4 = __toESM(require("react"), 1);
4342
+ var import_jsx_runtime6 = require("react/jsx-runtime");
4343
+ var CustomToolbar = React4.forwardRef(({ className, onMouseDown, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4344
+ "div",
4345
+ {
4346
+ ref,
4347
+ "data-ohw-toolbar": "",
4348
+ className: cn(
4349
+ "inline-flex items-center gap-1 rounded-lg border border-border bg-background p-0.5 font-sans whitespace-nowrap shadow-[0px_2px_4px_-2px_rgba(0,0,0,0.1),0px_4px_6px_-1px_rgba(0,0,0,0.1)]",
4350
+ className
4351
+ ),
4352
+ onMouseDown: (e) => {
4353
+ e.stopPropagation();
4354
+ onMouseDown?.(e);
4355
+ },
4356
+ ...props
4357
+ }
4358
+ ));
4359
+ CustomToolbar.displayName = "CustomToolbar";
4360
+ function CustomToolbarDivider({ className, ...props }) {
4361
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4362
+ "span",
4363
+ {
4364
+ "aria-hidden": true,
4365
+ className: cn("block h-6 w-px shrink-0 bg-border", className),
4366
+ ...props
4367
+ }
4368
+ );
4369
+ }
4370
+ var CustomToolbarButton = React4.forwardRef(
4371
+ ({ className, active = false, type = "button", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4372
+ "button",
4373
+ {
4374
+ ref,
4375
+ type,
4376
+ className: cn(
4377
+ "inline-flex shrink-0 items-center justify-center rounded p-1.5 transition-colors",
4378
+ active ? "bg-primary text-primary-foreground" : "bg-transparent text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:text-muted-foreground disabled:opacity-60",
4379
+ className
4380
+ ),
4381
+ ...props
4382
+ }
4383
+ )
4384
+ );
4385
+ CustomToolbarButton.displayName = "CustomToolbarButton";
4386
+
4387
+ // src/ui/item-action-toolbar.tsx
4388
+ var import_lucide_react2 = require("lucide-react");
4389
+
4390
+ // src/ui/tooltip.tsx
4391
+ var import_radix_ui3 = require("radix-ui");
4392
+ var import_jsx_runtime7 = require("react/jsx-runtime");
4393
+ function TooltipProvider({
4394
+ delayDuration = 0,
4395
+ ...props
4396
+ }) {
4397
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_radix_ui3.Tooltip.Provider, { "data-slot": "tooltip-provider", delayDuration, ...props });
4398
+ }
4399
+ function Tooltip({ ...props }) {
4400
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_radix_ui3.Tooltip.Root, { "data-slot": "tooltip", ...props });
4401
+ }
4402
+ function TooltipTrigger({ ...props }) {
4403
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_radix_ui3.Tooltip.Trigger, { "data-slot": "tooltip-trigger", ...props });
4404
+ }
4405
+ var arrowClassBySide = {
4406
+ top: "before:bottom-0 before:left-1/2 before:-translate-x-1/2 before:translate-y-1/2",
4407
+ bottom: "before:top-0 before:left-1/2 before:-translate-x-1/2 before:-translate-y-1/2",
4408
+ left: "before:right-0 before:top-1/2 before:-translate-y-1/2 before:translate-x-1/2",
4409
+ right: "before:left-0 before:top-1/2 before:-translate-y-1/2 before:-translate-x-1/2"
4410
+ };
4411
+ function TooltipContent({
4412
+ className,
4413
+ sideOffset = 6,
4414
+ side = "bottom",
4415
+ children,
4416
+ ...props
4417
+ }) {
4418
+ const resolvedSide = side ?? "bottom";
4419
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_radix_ui3.Tooltip.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4420
+ import_radix_ui3.Tooltip.Content,
4421
+ {
4422
+ "data-slot": "tooltip-content",
4423
+ side,
4424
+ sideOffset,
4425
+ className: cn(
4426
+ "relative z-[2147483647] w-fit max-w-xs rounded-md bg-foreground px-3 py-1.5 text-xs text-background shadow-md",
4427
+ 'before:pointer-events-none before:absolute before:size-2 before:rotate-45 before:bg-foreground before:content-[""]',
4428
+ arrowClassBySide[resolvedSide],
4429
+ "animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
4430
+ "data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2",
4431
+ "data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2",
4432
+ className
4433
+ ),
4434
+ ...props,
4435
+ children
4436
+ }
4437
+ ) });
4438
+ }
4439
+
4440
+ // src/ui/item-action-toolbar.tsx
4441
+ var import_jsx_runtime8 = require("react/jsx-runtime");
4442
+ function ToolbarActionTooltip({
4443
+ label,
4444
+ side = "bottom",
4445
+ disabled = false,
4446
+ buttonProps,
4447
+ children
4448
+ }) {
4449
+ const button = /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CustomToolbarButton, { type: "button", "aria-label": label, disabled, ...buttonProps, children });
4450
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Tooltip, { children: [
4451
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "inline-flex", children: button }) : button }),
4452
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(TooltipContent, { side, children: label })
4453
+ ] });
4454
+ }
4455
+ function ItemActionToolbar({
4456
+ onEditLink,
4457
+ onAddItem,
4458
+ onMore,
4459
+ addItemDisabled = true,
4460
+ moreDisabled = true,
4461
+ tooltipSide = "bottom"
4462
+ }) {
4463
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(CustomToolbar, { children: [
4464
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
4465
+ ToolbarActionTooltip,
4466
+ {
4467
+ label: "Add link",
4468
+ side: tooltipSide,
4469
+ buttonProps: {
4470
+ onMouseDown: (e) => {
4471
+ e.preventDefault();
4472
+ e.stopPropagation();
4473
+ onEditLink?.();
4474
+ },
4475
+ onClick: (e) => {
4476
+ e.preventDefault();
4477
+ e.stopPropagation();
4478
+ }
4479
+ },
4480
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.Link, { className: "size-4 shrink-0", "aria-hidden": true })
4481
+ }
4482
+ ),
4483
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CustomToolbarDivider, {}),
4484
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
4485
+ ToolbarActionTooltip,
4486
+ {
4487
+ label: "Add item",
4488
+ side: tooltipSide,
4489
+ disabled: addItemDisabled,
4490
+ buttonProps: {
4491
+ onMouseDown: (e) => {
4492
+ if (addItemDisabled) return;
4493
+ e.preventDefault();
4494
+ e.stopPropagation();
4495
+ onAddItem?.();
4496
+ }
4497
+ },
4498
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.Plus, { className: "size-4 shrink-0", "aria-hidden": true })
4499
+ }
4500
+ ),
4501
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CustomToolbarDivider, {}),
4502
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
4503
+ ToolbarActionTooltip,
4504
+ {
4505
+ label: "More",
4506
+ side: tooltipSide,
4507
+ disabled: moreDisabled,
4508
+ buttonProps: {
4509
+ onMouseDown: (e) => {
4510
+ if (moreDisabled) return;
4511
+ e.preventDefault();
4512
+ e.stopPropagation();
4513
+ onMore?.();
4514
+ }
4515
+ },
4516
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.MoreHorizontal, { className: "size-4 shrink-0", "aria-hidden": true })
4517
+ }
4518
+ )
4519
+ ] }) });
4520
+ }
4521
+
4522
+ // src/ui/item-interaction-layer.tsx
4523
+ var import_jsx_runtime9 = require("react/jsx-runtime");
4524
+ var PRIMARY = "var(--ohw-primary, #0885FE)";
4525
+ var FOCUS_RING = "0 0 0 4px rgba(8, 133, 254, 0.12)";
4526
+ var DRAG_SHADOW = "0px 4px 6px -1px rgba(0, 0, 0, 0.1), 0px 2px 4px -2px rgba(0, 0, 0, 0.1)";
4527
+ function getChromeStyle(state) {
4528
+ switch (state) {
4529
+ case "hover":
4530
+ return {
4531
+ border: `1.5px dashed ${PRIMARY}`,
4532
+ boxShadow: "none"
4533
+ };
4534
+ case "sibling-hint":
4535
+ return {
4536
+ border: `1.5px dashed color-mix(in srgb, ${PRIMARY} 30%, transparent)`,
4537
+ boxShadow: "none"
4538
+ };
4539
+ case "active-top":
4540
+ case "active-bottom":
4541
+ return {
4542
+ border: `2px solid ${PRIMARY}`,
4543
+ boxShadow: FOCUS_RING
4544
+ };
4545
+ case "dragging":
4546
+ return {
4547
+ border: `2px solid ${PRIMARY}`,
4548
+ boxShadow: DRAG_SHADOW
4549
+ };
4550
+ default:
4551
+ return {};
4552
+ }
4553
+ }
4554
+ function ItemInteractionLayer({
4555
+ rect,
4556
+ state,
4557
+ elRef,
4558
+ toolbar,
4559
+ showHandle = false,
4560
+ dragDisabled = false,
4561
+ dragHandleLabel = "Reorder item",
4562
+ onDragHandleDragStart,
4563
+ onDragHandleDragEnd,
4564
+ chromeGap = 6,
4565
+ className
4566
+ }) {
4567
+ if (state === "default") return null;
4568
+ const isActive = state === "active-top" || state === "active-bottom";
4569
+ const isDragging = state === "dragging";
4570
+ const showToolbar = isActive && toolbar;
4571
+ const showDragHandle = isActive && showHandle && !isDragging;
4572
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
4573
+ "div",
4574
+ {
4575
+ ref: elRef,
4576
+ "data-ohw-item-interaction": "",
4577
+ "data-ohw-item-interaction-state": state,
4578
+ className: cn("pointer-events-none", className),
4579
+ style: {
4580
+ position: "fixed",
4581
+ top: rect.top - chromeGap,
4582
+ left: rect.left - chromeGap,
4583
+ width: rect.width + chromeGap * 2,
4584
+ height: rect.height + chromeGap * 2,
4585
+ zIndex: 2147483646
4586
+ },
4587
+ children: [
4588
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4589
+ "div",
4590
+ {
4591
+ "aria-hidden": true,
4592
+ className: "absolute inset-0 rounded-lg",
4593
+ style: getChromeStyle(state)
4594
+ }
4595
+ ),
4596
+ showDragHandle && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4597
+ "div",
4598
+ {
4599
+ "data-ohw-drag-handle-container": "",
4600
+ className: "pointer-events-auto absolute left-0 top-1/2 -translate-x-[calc(100%+7px)] -translate-y-1/2",
4601
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4602
+ DragHandle,
4603
+ {
4604
+ draggable: !dragDisabled,
4605
+ "aria-label": dragHandleLabel,
4606
+ disabled: dragDisabled,
4607
+ onDragStart: (e) => {
4608
+ if (dragDisabled) {
4609
+ e.preventDefault();
4610
+ return;
4611
+ }
4612
+ e.dataTransfer?.setData("text/plain", dragHandleLabel);
4613
+ e.dataTransfer.effectAllowed = "move";
4614
+ onDragHandleDragStart?.(e);
4615
+ },
4616
+ onDragEnd: onDragHandleDragEnd
4617
+ }
4618
+ )
4619
+ }
4620
+ ),
4621
+ showToolbar && state === "active-top" && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4622
+ "div",
4623
+ {
4624
+ className: "pointer-events-auto absolute bottom-full left-1/2 mb-2 -translate-x-1/2",
4625
+ "data-ohw-item-toolbar-anchor": "top",
4626
+ children: toolbar
4627
+ }
4628
+ ),
4629
+ showToolbar && state === "active-bottom" && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
4630
+ "div",
4631
+ {
4632
+ className: "pointer-events-auto absolute left-1/2 top-full mt-2 -translate-x-1/2",
4633
+ "data-ohw-item-toolbar-anchor": "bottom",
4634
+ children: toolbar
4635
+ }
4636
+ )
4637
+ ]
4638
+ }
4639
+ );
4640
+ }
4641
+
4253
4642
  // src/OhhwellsBridge.tsx
4254
4643
  var import_react_dom2 = require("react-dom");
4255
4644
  var import_navigation = require("next/navigation");
@@ -4529,61 +4918,61 @@ function scrollToHashSectionWhenReady(behavior = "smooth") {
4529
4918
  }
4530
4919
 
4531
4920
  // src/ui/dialog.tsx
4532
- var React3 = __toESM(require("react"), 1);
4533
- var import_radix_ui3 = require("radix-ui");
4921
+ var React5 = __toESM(require("react"), 1);
4922
+ var import_radix_ui4 = require("radix-ui");
4534
4923
 
4535
4924
  // src/ui/icons.tsx
4536
- var import_jsx_runtime5 = require("react/jsx-runtime");
4925
+ var import_jsx_runtime10 = require("react/jsx-runtime");
4537
4926
  function IconX({ className, ...props }) {
4538
- 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: [
4539
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M18 6 6 18" }),
4540
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m6 6 12 12" })
4927
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
4928
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M18 6 6 18" }),
4929
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "m6 6 12 12" })
4541
4930
  ] });
4542
4931
  }
4543
4932
  function IconChevronDown({ className, ...props }) {
4544
- 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" }) });
4933
+ return /* @__PURE__ */ (0, import_jsx_runtime10.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_runtime10.jsx)("path", { d: "m6 9 6 6 6-6" }) });
4545
4934
  }
4546
4935
  function IconFile({ className, ...props }) {
4547
- 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: [
4548
- /* @__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" }),
4549
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" })
4936
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
4937
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
4938
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" })
4550
4939
  ] });
4551
4940
  }
4552
4941
  function IconInfo({ className, ...props }) {
4553
- 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: [
4554
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
4555
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12 16v-4" }),
4556
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12 8h.01" })
4942
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
4943
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
4944
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M12 16v-4" }),
4945
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M12 8h.01" })
4557
4946
  ] });
4558
4947
  }
4559
4948
  function IconArrowRight({ className, ...props }) {
4560
- 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: [
4561
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M5 12h14" }),
4562
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m12 5 7 7-7 7" })
4949
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
4950
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M5 12h14" }),
4951
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "m12 5 7 7-7 7" })
4563
4952
  ] });
4564
4953
  }
4565
4954
  function IconSection({ className, ...props }) {
4566
- 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: [
4567
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("rect", { width: "18", height: "7", x: "3", y: "3", rx: "1" }),
4568
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("rect", { width: "9", height: "7", x: "3", y: "14", rx: "1" }),
4569
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("rect", { width: "5", height: "7", x: "16", y: "14", rx: "1" })
4955
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
4956
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("rect", { width: "18", height: "7", x: "3", y: "3", rx: "1" }),
4957
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("rect", { width: "9", height: "7", x: "3", y: "14", rx: "1" }),
4958
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("rect", { width: "5", height: "7", x: "16", y: "14", rx: "1" })
4570
4959
  ] });
4571
4960
  }
4572
4961
 
4573
4962
  // src/ui/dialog.tsx
4574
- var import_jsx_runtime6 = require("react/jsx-runtime");
4963
+ var import_jsx_runtime11 = require("react/jsx-runtime");
4575
4964
  function Dialog2({ ...props }) {
4576
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_radix_ui3.Dialog.Root, { "data-slot": "dialog", ...props });
4965
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_radix_ui4.Dialog.Root, { "data-slot": "dialog", ...props });
4577
4966
  }
4578
4967
  function DialogPortal({ ...props }) {
4579
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_radix_ui3.Dialog.Portal, { ...props });
4968
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_radix_ui4.Dialog.Portal, { ...props });
4580
4969
  }
4581
4970
  function DialogOverlay({
4582
4971
  className,
4583
4972
  ...props
4584
4973
  }) {
4585
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4586
- import_radix_ui3.Dialog.Overlay,
4974
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
4975
+ import_radix_ui4.Dialog.Overlay,
4587
4976
  {
4588
4977
  "data-slot": "dialog-overlay",
4589
4978
  "data-ohw-link-modal-root": "",
@@ -4592,12 +4981,12 @@ function DialogOverlay({
4592
4981
  }
4593
4982
  );
4594
4983
  }
4595
- var DialogContent = React3.forwardRef(({ className, children, showCloseButton = true, container, ...props }, ref) => {
4984
+ var DialogContent = React5.forwardRef(({ className, children, showCloseButton = true, container, ...props }, ref) => {
4596
4985
  const positionMode = container ? "absolute" : "fixed";
4597
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(DialogPortal, { container: container ?? void 0, children: [
4598
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DialogOverlay, { className: cn(positionMode, "inset-0") }),
4599
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
4600
- import_radix_ui3.Dialog.Content,
4986
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(DialogPortal, { container: container ?? void 0, children: [
4987
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(DialogOverlay, { className: cn(positionMode, "inset-0") }),
4988
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
4989
+ import_radix_ui4.Dialog.Content,
4601
4990
  {
4602
4991
  ref,
4603
4992
  "data-slot": "dialog-content",
@@ -4612,13 +5001,13 @@ var DialogContent = React3.forwardRef(({ className, children, showCloseButton =
4612
5001
  ...props,
4613
5002
  children: [
4614
5003
  children,
4615
- showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4616
- import_radix_ui3.Dialog.Close,
5004
+ showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
5005
+ import_radix_ui4.Dialog.Close,
4617
5006
  {
4618
5007
  type: "button",
4619
5008
  className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
4620
5009
  "aria-label": "Close",
4621
- children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(IconX, { "aria-hidden": true })
5010
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(IconX, { "aria-hidden": true })
4622
5011
  }
4623
5012
  ) : null
4624
5013
  ]
@@ -4626,37 +5015,37 @@ var DialogContent = React3.forwardRef(({ className, children, showCloseButton =
4626
5015
  )
4627
5016
  ] });
4628
5017
  });
4629
- DialogContent.displayName = import_radix_ui3.Dialog.Content.displayName;
5018
+ DialogContent.displayName = import_radix_ui4.Dialog.Content.displayName;
4630
5019
  function DialogHeader({ className, ...props }) {
4631
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: cn("flex flex-col gap-1.5", className), ...props });
5020
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: cn("flex flex-col gap-1.5", className), ...props });
4632
5021
  }
4633
5022
  function DialogFooter({ className, ...props }) {
4634
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: cn("flex items-center justify-end gap-2", className), ...props });
5023
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: cn("flex items-center justify-end gap-2", className), ...props });
4635
5024
  }
4636
- var DialogTitle = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4637
- import_radix_ui3.Dialog.Title,
5025
+ var DialogTitle = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
5026
+ import_radix_ui4.Dialog.Title,
4638
5027
  {
4639
5028
  ref,
4640
5029
  className: cn("text-lg font-semibold leading-none tracking-tight text-card-foreground", className),
4641
5030
  ...props
4642
5031
  }
4643
5032
  ));
4644
- DialogTitle.displayName = import_radix_ui3.Dialog.Title.displayName;
4645
- var DialogDescription = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4646
- import_radix_ui3.Dialog.Description,
5033
+ DialogTitle.displayName = import_radix_ui4.Dialog.Title.displayName;
5034
+ var DialogDescription = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
5035
+ import_radix_ui4.Dialog.Description,
4647
5036
  {
4648
5037
  ref,
4649
5038
  className: cn("text-sm text-muted-foreground", className),
4650
5039
  ...props
4651
5040
  }
4652
5041
  ));
4653
- DialogDescription.displayName = import_radix_ui3.Dialog.Description.displayName;
4654
- var DialogClose = import_radix_ui3.Dialog.Close;
5042
+ DialogDescription.displayName = import_radix_ui4.Dialog.Description.displayName;
5043
+ var DialogClose = import_radix_ui4.Dialog.Close;
4655
5044
 
4656
5045
  // src/ui/button.tsx
4657
- var React4 = __toESM(require("react"), 1);
4658
- var import_radix_ui4 = require("radix-ui");
4659
- var import_jsx_runtime7 = require("react/jsx-runtime");
5046
+ var React6 = __toESM(require("react"), 1);
5047
+ var import_radix_ui5 = require("radix-ui");
5048
+ var import_jsx_runtime12 = require("react/jsx-runtime");
4660
5049
  var buttonVariants = cva(
4661
5050
  "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",
4662
5051
  {
@@ -4677,10 +5066,10 @@ var buttonVariants = cva(
4677
5066
  }
4678
5067
  }
4679
5068
  );
4680
- var Button = React4.forwardRef(
5069
+ var Button = React6.forwardRef(
4681
5070
  ({ className, variant, size, asChild = false, ...props }, ref) => {
4682
- const Comp = asChild ? import_radix_ui4.Slot.Root : "button";
4683
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
5071
+ const Comp = asChild ? import_radix_ui5.Slot.Root : "button";
5072
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
4684
5073
  Comp,
4685
5074
  {
4686
5075
  ref,
@@ -4694,37 +5083,37 @@ var Button = React4.forwardRef(
4694
5083
  Button.displayName = "Button";
4695
5084
 
4696
5085
  // src/ui/link-modal/DestinationBreadcrumb.tsx
4697
- var import_jsx_runtime8 = require("react/jsx-runtime");
5086
+ var import_jsx_runtime13 = require("react/jsx-runtime");
4698
5087
  function DestinationBreadcrumb({ pageTitle, sectionLabel }) {
4699
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex w-full flex-col gap-2", children: [
4700
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "text-sm font-medium text-foreground", children: "Destination" }),
4701
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center gap-3", children: [
4702
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center gap-2", children: [
4703
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(IconFile, { className: "shrink-0 text-foreground", "aria-hidden": true }),
4704
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-sm font-medium leading-none text-foreground", children: pageTitle })
5088
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex w-full flex-col gap-2", children: [
5089
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-sm font-medium text-foreground", children: "Destination" }),
5090
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-3", children: [
5091
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-2", children: [
5092
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(IconFile, { className: "shrink-0 text-foreground", "aria-hidden": true }),
5093
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-sm font-medium leading-none text-foreground", children: pageTitle })
4705
5094
  ] }),
4706
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(IconArrowRight, { className: "shrink-0 text-muted-foreground", "aria-hidden": true }),
4707
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
4708
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(IconSection, { className: "shrink-0 text-foreground", "aria-hidden": true }),
4709
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
5095
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(IconArrowRight, { className: "shrink-0 text-muted-foreground", "aria-hidden": true }),
5096
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
5097
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(IconSection, { className: "shrink-0 text-foreground", "aria-hidden": true }),
5098
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
4710
5099
  ] })
4711
5100
  ] })
4712
5101
  ] });
4713
5102
  }
4714
5103
 
4715
5104
  // src/ui/link-modal/SectionTreeItem.tsx
4716
- var import_jsx_runtime9 = require("react/jsx-runtime");
5105
+ var import_jsx_runtime14 = require("react/jsx-runtime");
4717
5106
  function SectionTreeItem({ section, onSelect, selected }) {
4718
5107
  const interactive = Boolean(onSelect);
4719
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex h-9 w-full items-end pl-3", children: [
4720
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
5108
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex h-9 w-full items-end pl-3", children: [
5109
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
4721
5110
  "div",
4722
5111
  {
4723
5112
  className: "mr-[-1px] h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
4724
5113
  "aria-hidden": true
4725
5114
  }
4726
5115
  ),
4727
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
5116
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
4728
5117
  "div",
4729
5118
  {
4730
5119
  role: interactive ? "button" : void 0,
@@ -4742,8 +5131,8 @@ function SectionTreeItem({ section, onSelect, selected }) {
4742
5131
  interactive && selected && "border-primary"
4743
5132
  ),
4744
5133
  children: [
4745
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(IconSection, { className: "shrink-0 text-foreground", "aria-hidden": true }),
4746
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
5134
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(IconSection, { className: "shrink-0 text-foreground", "aria-hidden": true }),
5135
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
4747
5136
  ]
4748
5137
  }
4749
5138
  )
@@ -4751,11 +5140,11 @@ function SectionTreeItem({ section, onSelect, selected }) {
4751
5140
  }
4752
5141
  function SectionPickerList({ sections, onSelect }) {
4753
5142
  if (sections.length === 0) {
4754
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." });
5143
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." });
4755
5144
  }
4756
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-1", children: [
4757
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "text-sm text-muted-foreground", children: "Pick a section this link should scroll to." }),
4758
- sections.map((section) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SectionTreeItem, { section, onSelect }, section.id))
5145
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col gap-1", children: [
5146
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-sm text-muted-foreground", children: "Pick a section this link should scroll to." }),
5147
+ sections.map((section) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SectionTreeItem, { section, onSelect }, section.id))
4759
5148
  ] });
4760
5149
  }
4761
5150
 
@@ -4763,11 +5152,11 @@ function SectionPickerList({ sections, onSelect }) {
4763
5152
  var import_react4 = require("react");
4764
5153
 
4765
5154
  // src/ui/input.tsx
4766
- var React5 = __toESM(require("react"), 1);
4767
- var import_jsx_runtime10 = require("react/jsx-runtime");
4768
- var Input = React5.forwardRef(
5155
+ var React7 = __toESM(require("react"), 1);
5156
+ var import_jsx_runtime15 = require("react/jsx-runtime");
5157
+ var Input = React7.forwardRef(
4769
5158
  ({ className, type, ...props }, ref) => {
4770
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5159
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
4771
5160
  "input",
4772
5161
  {
4773
5162
  type,
@@ -4785,11 +5174,11 @@ var Input = React5.forwardRef(
4785
5174
  Input.displayName = "Input";
4786
5175
 
4787
5176
  // src/ui/label.tsx
4788
- var import_radix_ui5 = require("radix-ui");
4789
- var import_jsx_runtime11 = require("react/jsx-runtime");
5177
+ var import_radix_ui6 = require("radix-ui");
5178
+ var import_jsx_runtime16 = require("react/jsx-runtime");
4790
5179
  function Label({ className, ...props }) {
4791
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
4792
- import_radix_ui5.Label.Root,
5180
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5181
+ import_radix_ui6.Label.Root,
4793
5182
  {
4794
5183
  "data-slot": "label",
4795
5184
  className: cn("text-sm font-medium leading-5 text-foreground", className),
@@ -4799,9 +5188,9 @@ function Label({ className, ...props }) {
4799
5188
  }
4800
5189
 
4801
5190
  // src/ui/link-modal/UrlOrPageInput.tsx
4802
- var import_jsx_runtime12 = require("react/jsx-runtime");
5191
+ var import_jsx_runtime17 = require("react/jsx-runtime");
4803
5192
  function FieldChevron({ onClick }) {
4804
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
5193
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4805
5194
  "button",
4806
5195
  {
4807
5196
  type: "button",
@@ -4809,7 +5198,7 @@ function FieldChevron({ onClick }) {
4809
5198
  onClick,
4810
5199
  "aria-label": "Open page list",
4811
5200
  tabIndex: -1,
4812
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconChevronDown, {})
5201
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconChevronDown, {})
4813
5202
  }
4814
5203
  );
4815
5204
  }
@@ -4848,12 +5237,12 @@ function UrlOrPageInput({
4848
5237
  "data-ohw-link-field flex h-10 w-full items-center overflow-hidden rounded-md border bg-background pl-3 pr-3 py-2 outline-none transition-[border-color,box-shadow]",
4849
5238
  urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
4850
5239
  );
4851
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex w-full flex-col gap-2 p-0", children: [
4852
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
4853
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "relative w-full", children: [
4854
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
4855
- 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,
4856
- 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)(
5240
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex w-full flex-col gap-2 p-0", children: [
5241
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
5242
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "relative w-full", children: [
5243
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
5244
+ selectedPage ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconFile, { className: "text-foreground", "aria-hidden": true }) }) : null,
5245
+ readOnly ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "min-w-0 flex-1 truncate text-sm leading-5 text-foreground", children: selectedPage?.title ?? value }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4857
5246
  Input,
4858
5247
  {
4859
5248
  ref: inputRef,
@@ -4872,7 +5261,7 @@ function UrlOrPageInput({
4872
5261
  )
4873
5262
  }
4874
5263
  ),
4875
- selectedPage && !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
5264
+ selectedPage && !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4876
5265
  "button",
4877
5266
  {
4878
5267
  type: "button",
@@ -4880,26 +5269,26 @@ function UrlOrPageInput({
4880
5269
  onMouseDown: clearSelection,
4881
5270
  "aria-label": "Clear selected page",
4882
5271
  tabIndex: -1,
4883
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconX, { "aria-hidden": true })
5272
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconX, { "aria-hidden": true })
4884
5273
  }
4885
5274
  ) : null,
4886
- !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(FieldChevron, { onClick: toggleDropdown }) : null
5275
+ !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(FieldChevron, { onClick: toggleDropdown }) : null
4887
5276
  ] }),
4888
- dropdownOpen && !readOnly && filteredPages.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
5277
+ dropdownOpen && !readOnly && filteredPages.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4889
5278
  "div",
4890
5279
  {
4891
5280
  "data-ohw-link-page-dropdown": "",
4892
5281
  className: "absolute left-0 right-0 h-20 top-[calc(100%+4px)] z-10 max-h-48 overflow-auto rounded-lg border border-border bg-popover py-1 shadow-lg",
4893
5282
  onMouseDown: (e) => e.preventDefault(),
4894
- children: filteredPages.map((page) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
5283
+ children: filteredPages.map((page) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
4895
5284
  "button",
4896
5285
  {
4897
5286
  type: "button",
4898
5287
  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",
4899
5288
  onClick: () => onPageSelect(page),
4900
5289
  children: [
4901
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(IconFile, { className: "shrink-0", "aria-hidden": true }),
4902
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "truncate", children: page.title })
5290
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconFile, { className: "shrink-0", "aria-hidden": true }),
5291
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "truncate", children: page.title })
4903
5292
  ]
4904
5293
  },
4905
5294
  page.path
@@ -4907,7 +5296,7 @@ function UrlOrPageInput({
4907
5296
  }
4908
5297
  ) : null
4909
5298
  ] }),
4910
- urlError ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm font-medium text-destructive", children: urlError }) : null
5299
+ urlError ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "text-sm font-medium text-destructive", children: urlError }) : null
4911
5300
  ] });
4912
5301
  }
4913
5302
 
@@ -5075,7 +5464,7 @@ function useLinkModalState({
5075
5464
  }
5076
5465
 
5077
5466
  // src/ui/link-modal/LinkEditorPanel.tsx
5078
- var import_jsx_runtime13 = require("react/jsx-runtime");
5467
+ var import_jsx_runtime18 = require("react/jsx-runtime");
5079
5468
  function LinkEditorPanel({
5080
5469
  open = true,
5081
5470
  mode = "create",
@@ -5099,25 +5488,25 @@ function LinkEditorPanel({
5099
5488
  onSubmit
5100
5489
  });
5101
5490
  const isCancel = state.secondaryLabel === "Cancel";
5102
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
5103
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DialogClose, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5491
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
5492
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DialogClose, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5104
5493
  "button",
5105
5494
  {
5106
5495
  type: "button",
5107
5496
  className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
5108
5497
  "aria-label": "Close",
5109
- children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(IconX, { "aria-hidden": true })
5498
+ children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(IconX, { "aria-hidden": true })
5110
5499
  }
5111
5500
  ) }),
5112
- /* @__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 }) }),
5113
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
5114
- state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5501
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DialogHeader, { className: "w-full gap-1.5 p-6 pr-12", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DialogTitle, { className: "m-0 w-full break-words", children: state.title }) }),
5502
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
5503
+ state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5115
5504
  DestinationBreadcrumb,
5116
5505
  {
5117
5506
  pageTitle: state.selectedPage.title,
5118
5507
  sectionLabel: state.selectedSection.label
5119
5508
  }
5120
- ) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5509
+ ) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5121
5510
  UrlOrPageInput,
5122
5511
  {
5123
5512
  value: state.searchValue,
@@ -5130,18 +5519,18 @@ function LinkEditorPanel({
5130
5519
  urlError: state.urlError
5131
5520
  }
5132
5521
  ),
5133
- state.showChooseSection ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col justify-center gap-2", children: [
5134
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Button, { type: "button", variant: "outline", className: "w-fit cursor-pointer", size: "sm", onClick: state.handleChooseSection, children: "Choose a section" }),
5135
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
5136
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(IconInfo, { className: "shrink-0", "aria-hidden": true }),
5137
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "Pick a section this link should scroll to." })
5522
+ state.showChooseSection ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex flex-col justify-center gap-2", children: [
5523
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { type: "button", variant: "outline", className: "w-fit cursor-pointer", size: "sm", onClick: state.handleChooseSection, children: "Choose a section" }),
5524
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
5525
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(IconInfo, { className: "shrink-0", "aria-hidden": true }),
5526
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: "Pick a section this link should scroll to." })
5138
5527
  ] })
5139
5528
  ] }) : null,
5140
- state.showSectionPicker ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SectionPickerList, { sections: state.activeSections, onSelect: state.handleSectionSelect }) : null,
5141
- state.showSectionRow && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
5529
+ state.showSectionPicker ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SectionPickerList, { sections: state.activeSections, onSelect: state.handleSectionSelect }) : null,
5530
+ state.showSectionRow && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
5142
5531
  ] }),
5143
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DialogFooter, { className: "w-full px-6 pb-6", children: [
5144
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5532
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(DialogFooter, { className: "w-full px-6 pb-6", children: [
5533
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5145
5534
  Button,
5146
5535
  {
5147
5536
  type: "button",
@@ -5156,7 +5545,7 @@ function LinkEditorPanel({
5156
5545
  children: state.secondaryLabel
5157
5546
  }
5158
5547
  ),
5159
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5548
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5160
5549
  Button,
5161
5550
  {
5162
5551
  type: "button",
@@ -5175,7 +5564,7 @@ function LinkEditorPanel({
5175
5564
  }
5176
5565
 
5177
5566
  // src/ui/link-modal/LinkPopover.tsx
5178
- var import_jsx_runtime14 = require("react/jsx-runtime");
5567
+ var import_jsx_runtime19 = require("react/jsx-runtime");
5179
5568
  function LinkPopover({
5180
5569
  open = true,
5181
5570
  panelRef,
@@ -5183,14 +5572,14 @@ function LinkPopover({
5183
5572
  onClose,
5184
5573
  ...editorProps
5185
5574
  }) {
5186
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
5575
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5187
5576
  Dialog2,
5188
5577
  {
5189
5578
  open,
5190
5579
  onOpenChange: (next) => {
5191
5580
  if (!next) onClose?.();
5192
5581
  },
5193
- children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
5582
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5194
5583
  DialogContent,
5195
5584
  {
5196
5585
  ref: panelRef,
@@ -5200,7 +5589,7 @@ function LinkPopover({
5200
5589
  "data-ohw-bridge": "",
5201
5590
  showCloseButton: false,
5202
5591
  className: "gap-0 p-0 w-full md:w-md pointer-events-auto",
5203
- children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(LinkEditorPanel, { ...editorProps, open, onClose })
5592
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(LinkEditorPanel, { ...editorProps, open, onClose })
5204
5593
  }
5205
5594
  )
5206
5595
  }
@@ -5266,7 +5655,7 @@ function shouldUseDevFixtures() {
5266
5655
  }
5267
5656
 
5268
5657
  // src/ui/badge.tsx
5269
- var import_jsx_runtime15 = require("react/jsx-runtime");
5658
+ var import_jsx_runtime20 = require("react/jsx-runtime");
5270
5659
  var badgeVariants = cva(
5271
5660
  "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",
5272
5661
  {
@@ -5284,12 +5673,13 @@ var badgeVariants = cva(
5284
5673
  }
5285
5674
  );
5286
5675
  function Badge({ className, variant, ...props }) {
5287
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: cn(badgeVariants({ variant }), className), ...props });
5676
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: cn(badgeVariants({ variant }), className), ...props });
5288
5677
  }
5289
5678
 
5290
5679
  // src/OhhwellsBridge.tsx
5291
- var import_jsx_runtime16 = require("react/jsx-runtime");
5292
- var PRIMARY = "#0885FE";
5680
+ var import_lucide_react3 = require("lucide-react");
5681
+ var import_jsx_runtime21 = require("react/jsx-runtime");
5682
+ var PRIMARY2 = "#0885FE";
5293
5683
  var IMAGE_FADE_MS = 300;
5294
5684
  function runOpacityFade(el, onDone) {
5295
5685
  const anim = el.animate([{ opacity: 0 }, { opacity: 1 }], {
@@ -5462,7 +5852,7 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
5462
5852
  const root = (0, import_client.createRoot)(container);
5463
5853
  (0, import_react_dom.flushSync)(() => {
5464
5854
  root.render(
5465
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5855
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
5466
5856
  SchedulingWidget,
5467
5857
  {
5468
5858
  notifyOnConnect,
@@ -5510,6 +5900,20 @@ function applyLinkHref(el, val) {
5510
5900
  const anchor = el instanceof HTMLAnchorElement ? el : el.querySelector("a");
5511
5901
  if (anchor) anchor.setAttribute("href", val);
5512
5902
  }
5903
+ function getEditMeasureEl(editable) {
5904
+ return editable.closest("[data-ohw-href-key]") ?? editable;
5905
+ }
5906
+ function isDragHandleDisabled(el) {
5907
+ const carriers = [
5908
+ el.closest("[data-ohw-href-key]"),
5909
+ el.closest("[data-ohw-editable]")
5910
+ ];
5911
+ return carriers.some((carrier) => {
5912
+ if (!carrier) return false;
5913
+ const raw = carrier.getAttribute("data-ohw-drag-disabled");
5914
+ return raw === "true" || raw === "";
5915
+ });
5916
+ }
5513
5917
  function collectEditableNodes() {
5514
5918
  const nodes = Array.from(document.querySelectorAll("[data-ohw-editable]")).map((el) => {
5515
5919
  if (el.dataset.ohwEditable === "image") {
@@ -5563,12 +5967,49 @@ function getHrefKeyFromElement(el) {
5563
5967
  function isNavbarButton(el) {
5564
5968
  return Boolean(el.closest('[data-ohw-role="navbar-button"]'));
5565
5969
  }
5970
+ function getNavigationItemAnchor(el) {
5971
+ const anchor = el.matches("[data-ohw-href-key]") ? el : el.closest("[data-ohw-href-key]");
5972
+ if (!anchor) return null;
5973
+ if (!anchor.querySelector('[data-ohw-editable="text"]')) return null;
5974
+ return anchor;
5975
+ }
5976
+ function isNavigationItem(el) {
5977
+ return getNavigationItemAnchor(el) !== null;
5978
+ }
5979
+ function getNavigationItemAddHintTarget(anchor) {
5980
+ const items = listNavigationItems();
5981
+ const idx = items.indexOf(anchor);
5982
+ if (idx >= 0 && idx < items.length - 1) return items[idx + 1];
5983
+ return anchor;
5984
+ }
5985
+ function listNavigationItems() {
5986
+ return Array.from(
5987
+ document.querySelectorAll("nav [data-ohw-href-key], footer [data-ohw-href-key]")
5988
+ ).filter((el) => isNavigationItem(el));
5989
+ }
5990
+ function getNavigationItemReorderState(anchor) {
5991
+ if (isNavbarButton(anchor)) return { key: null, disabled: false };
5992
+ return getReorderHandleStateFromAnchor(anchor);
5993
+ }
5994
+ function getReorderHandleState(el) {
5995
+ const linkEl = el.closest("[data-ohw-href-key]");
5996
+ if (!linkEl || getNavigationItemAnchor(linkEl)) return { key: null, disabled: false };
5997
+ return getReorderHandleStateFromAnchor(linkEl);
5998
+ }
5999
+ function getReorderHandleStateFromAnchor(anchor) {
6000
+ const key = anchor.getAttribute("data-ohw-href-key");
6001
+ if (!key) return { key: null, disabled: false };
6002
+ return { key, disabled: isDragHandleDisabled(anchor) };
6003
+ }
5566
6004
  function clearHrefKeyHover(anchor) {
5567
6005
  anchor.removeAttribute("data-ohw-hovered");
5568
6006
  anchor.querySelectorAll("[data-ohw-hovered]").forEach((el) => {
5569
6007
  el.removeAttribute("data-ohw-hovered");
5570
6008
  });
5571
6009
  }
6010
+ function isInsideNavigationItem(el) {
6011
+ return getNavigationItemAnchor(el) !== null;
6012
+ }
5572
6013
  function collectSections() {
5573
6014
  return collectSectionsFromDom();
5574
6015
  }
@@ -5692,6 +6133,8 @@ var ICONS = {
5692
6133
  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"/>',
5693
6134
  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"/>'
5694
6135
  };
6136
+ var TOOLBAR_PILL_PADDING = 2;
6137
+ var TOOLBAR_TOGGLE_GAP = 4;
5695
6138
  var TOOLBAR_GROUPS = [
5696
6139
  [
5697
6140
  { cmd: "bold", title: "Bold" },
@@ -5709,24 +6152,64 @@ var TOOLBAR_GROUPS = [
5709
6152
  { cmd: "insertOrderedList", title: "Numbered List" }
5710
6153
  ]
5711
6154
  ];
5712
- function GlowFrame({ rect, elRef }) {
6155
+ function EditGlowChrome({
6156
+ rect,
6157
+ elRef,
6158
+ reorderHrefKey,
6159
+ dragDisabled = false
6160
+ }) {
5713
6161
  const GAP = 6;
5714
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
6162
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
5715
6163
  "div",
5716
6164
  {
5717
6165
  ref: elRef,
6166
+ "data-ohw-edit-chrome": "",
5718
6167
  style: {
5719
6168
  position: "fixed",
5720
6169
  top: rect.top - GAP,
5721
6170
  left: rect.left - GAP,
5722
6171
  width: rect.width + GAP * 2,
5723
6172
  height: rect.height + GAP * 2,
5724
- border: "2px solid #0885FE",
5725
- borderRadius: 8,
5726
- boxShadow: "0 0 0 4px rgba(8, 133, 254, 0.12)",
5727
6173
  pointerEvents: "none",
5728
6174
  zIndex: 2147483646
5729
- }
6175
+ },
6176
+ children: [
6177
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6178
+ "div",
6179
+ {
6180
+ style: {
6181
+ position: "absolute",
6182
+ inset: 0,
6183
+ border: "2px solid var(--ohw-primary, #0885FE)",
6184
+ borderRadius: 8,
6185
+ boxShadow: "0 0 0 4px rgba(8, 133, 254, 0.12)",
6186
+ pointerEvents: "none"
6187
+ }
6188
+ }
6189
+ ),
6190
+ reorderHrefKey && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6191
+ "div",
6192
+ {
6193
+ "data-ohw-drag-handle-container": "",
6194
+ "data-ohw-drag-disabled": dragDisabled ? "" : void 0,
6195
+ style: {
6196
+ position: "absolute",
6197
+ left: 0,
6198
+ top: "50%",
6199
+ transform: "translate(calc(-100% - 7px), -50%)",
6200
+ pointerEvents: dragDisabled ? "none" : "auto"
6201
+ },
6202
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6203
+ DragHandle,
6204
+ {
6205
+ "aria-label": `Reorder ${reorderHrefKey}`,
6206
+ disabled: dragDisabled,
6207
+ "aria-disabled": dragDisabled
6208
+ }
6209
+ )
6210
+ }
6211
+ )
6212
+ ]
5730
6213
  }
5731
6214
  );
5732
6215
  }
@@ -5770,9 +6253,9 @@ function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
5770
6253
  const pinnedTop = Math.min(maxBottom - approxH, Math.max(minTop, clip.top + gap));
5771
6254
  return { top: pinnedTop + approxH, transform: "translateX(-50%) translateY(-100%)" };
5772
6255
  }
5773
- function calcToolbarPos(rect, parentScroll, approxW = 330) {
6256
+ function calcToolbarPos(rect, parentScroll, approxW = 306) {
5774
6257
  const GAP = 8;
5775
- const APPROX_H = 36;
6258
+ const APPROX_H = 32;
5776
6259
  const APPROX_W = approxW;
5777
6260
  const clip = getIframeVisibleClip(parentScroll);
5778
6261
  const clipTop = clip?.top ?? 0;
@@ -5806,119 +6289,24 @@ function calcToolbarPos(rect, parentScroll, approxW = 330) {
5806
6289
  const left = Math.max(GAP + APPROX_W / 2, Math.min(rawLeft, window.innerWidth - GAP - APPROX_W / 2));
5807
6290
  return { top, left, transform };
5808
6291
  }
5809
- var EDIT_LINK_ICON = /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("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: [
5810
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }),
5811
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })
5812
- ] });
6292
+ function resolveItemInteractionState(rect, parentScroll) {
6293
+ const { transform } = calcToolbarPos(rect, parentScroll, 120);
6294
+ return transform.includes("translateY(-100%)") ? "active-top" : "active-bottom";
6295
+ }
5813
6296
  function FloatingToolbar({
5814
6297
  rect,
5815
6298
  parentScroll,
5816
6299
  elRef,
5817
- variant = "rich-text",
5818
6300
  onCommand,
5819
6301
  activeCommands,
5820
6302
  showEditLink,
5821
6303
  onEditLink
5822
6304
  }) {
5823
- const approxW = variant === "link-action" ? 120 : 330;
5824
- const { top, left, transform } = calcToolbarPos(rect, parentScroll, approxW);
5825
- if (variant === "link-action") {
5826
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
5827
- "div",
5828
- {
5829
- ref: elRef,
5830
- "data-ohw-toolbar": "",
5831
- style: {
5832
- position: "fixed",
5833
- top,
5834
- left,
5835
- transform,
5836
- zIndex: 2147483647,
5837
- background: "#fff",
5838
- border: "1px solid #E7E5E4",
5839
- borderRadius: 6,
5840
- boxShadow: "0px 2px 4px -2px rgba(0,0,0,.1),0px 4px 6px -1px rgba(0,0,0,.1)",
5841
- display: "flex",
5842
- alignItems: "center",
5843
- padding: 4,
5844
- gap: 6,
5845
- fontFamily: "sans-serif",
5846
- pointerEvents: "auto",
5847
- whiteSpace: "nowrap"
5848
- },
5849
- onMouseDown: (e) => e.stopPropagation(),
5850
- children: [
5851
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5852
- "button",
5853
- {
5854
- type: "button",
5855
- title: "Edit link",
5856
- onMouseDown: (e) => {
5857
- e.preventDefault();
5858
- e.stopPropagation();
5859
- onEditLink?.();
5860
- },
5861
- onClick: (e) => {
5862
- e.preventDefault();
5863
- e.stopPropagation();
5864
- },
5865
- onMouseEnter: (e) => {
5866
- e.currentTarget.style.background = "#F5F5F4";
5867
- },
5868
- onMouseLeave: (e) => {
5869
- e.currentTarget.style.background = "transparent";
5870
- },
5871
- style: {
5872
- display: "flex",
5873
- alignItems: "center",
5874
- justifyContent: "center",
5875
- border: "none",
5876
- background: "transparent",
5877
- borderRadius: 4,
5878
- cursor: "pointer",
5879
- color: "#1C1917",
5880
- flexShrink: 0,
5881
- padding: 6
5882
- },
5883
- children: EDIT_LINK_ICON
5884
- }
5885
- ),
5886
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { display: "block", width: 1, height: 24, background: "#E7E5E4", flexShrink: 0 } }),
5887
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5888
- "button",
5889
- {
5890
- type: "button",
5891
- title: "Coming soon",
5892
- disabled: true,
5893
- style: {
5894
- display: "flex",
5895
- alignItems: "center",
5896
- justifyContent: "center",
5897
- border: "none",
5898
- background: "transparent",
5899
- borderRadius: 4,
5900
- cursor: "not-allowed",
5901
- color: "#A8A29E",
5902
- flexShrink: 0,
5903
- padding: 6,
5904
- opacity: 0.6
5905
- },
5906
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": true, children: [
5907
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("circle", { cx: "5", cy: "12", r: "1.5" }),
5908
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("circle", { cx: "12", cy: "12", r: "1.5" }),
5909
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("circle", { cx: "19", cy: "12", r: "1.5" })
5910
- ] })
5911
- }
5912
- )
5913
- ]
5914
- }
5915
- );
5916
- }
5917
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
6305
+ const { top, left, transform } = calcToolbarPos(rect, parentScroll, 330);
6306
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
5918
6307
  "div",
5919
6308
  {
5920
6309
  ref: elRef,
5921
- "data-ohw-toolbar": "",
5922
6310
  style: {
5923
6311
  position: "fixed",
5924
6312
  top,
@@ -5931,57 +6319,39 @@ function FloatingToolbar({
5931
6319
  boxShadow: "0px 2px 4px -2px rgba(0,0,0,.1),0px 4px 6px -1px rgba(0,0,0,.1)",
5932
6320
  display: "flex",
5933
6321
  alignItems: "center",
5934
- padding: 4,
5935
- gap: 6,
6322
+ padding: TOOLBAR_PILL_PADDING,
6323
+ gap: TOOLBAR_TOGGLE_GAP,
5936
6324
  fontFamily: "sans-serif",
5937
- pointerEvents: "auto",
5938
- whiteSpace: "nowrap"
6325
+ pointerEvents: "auto"
5939
6326
  },
5940
- onMouseDown: (e) => e.stopPropagation(),
5941
- children: [
5942
- TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_react6.default.Fragment, { children: [
5943
- gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { display: "block", width: 1, height: 24, background: "#E7E5E4", flexShrink: 0 } }),
6327
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(CustomToolbar, { children: [
6328
+ TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react6.default.Fragment, { children: [
6329
+ gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(CustomToolbarDivider, {}),
5944
6330
  btns.map((btn) => {
5945
6331
  const isActive = activeCommands.has(btn.cmd);
5946
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5947
- "button",
6332
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6333
+ CustomToolbarButton,
5948
6334
  {
5949
6335
  title: btn.title,
6336
+ active: isActive,
5950
6337
  onMouseDown: (e) => {
5951
6338
  e.preventDefault();
5952
6339
  onCommand(btn.cmd);
5953
6340
  },
5954
- onMouseEnter: (e) => {
5955
- if (!isActive) e.currentTarget.style.background = "#F5F5F4";
5956
- },
5957
- onMouseLeave: (e) => {
5958
- if (!isActive) e.currentTarget.style.background = "transparent";
5959
- },
5960
- style: {
5961
- display: "flex",
5962
- alignItems: "center",
5963
- justifyContent: "center",
5964
- border: "none",
5965
- background: isActive ? PRIMARY : "transparent",
5966
- borderRadius: 4,
5967
- cursor: "pointer",
5968
- color: isActive ? "#FFFFFF" : "#1C1917",
5969
- flexShrink: 0,
5970
- padding: 6
5971
- },
5972
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
6341
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
5973
6342
  "svg",
5974
6343
  {
5975
6344
  width: "16",
5976
6345
  height: "16",
5977
6346
  viewBox: "0 0 24 24",
5978
6347
  fill: "none",
5979
- stroke: isActive ? "#FFFFFF" : "#1C1917",
6348
+ stroke: "currentColor",
5980
6349
  strokeWidth: "2.5",
5981
6350
  strokeLinecap: "round",
5982
6351
  strokeLinejoin: "round",
5983
- style: isActive && gi > 0 ? { filter: "drop-shadow(0 0 0.5px #fff)" } : void 0,
5984
- dangerouslySetInnerHTML: { __html: ICONS[btn.cmd] }
6352
+ style: isActive && gi > 0 ? { filter: "drop-shadow(0 0 0.5px currentColor)" } : void 0,
6353
+ dangerouslySetInnerHTML: { __html: ICONS[btn.cmd] },
6354
+ "aria-hidden": true
5985
6355
  }
5986
6356
  )
5987
6357
  },
@@ -5989,8 +6359,8 @@ function FloatingToolbar({
5989
6359
  );
5990
6360
  })
5991
6361
  ] }, gi)),
5992
- showEditLink ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5993
- "button",
6362
+ showEditLink ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6363
+ CustomToolbarButton,
5994
6364
  {
5995
6365
  type: "button",
5996
6366
  title: "Edit link",
@@ -6003,28 +6373,10 @@ function FloatingToolbar({
6003
6373
  e.preventDefault();
6004
6374
  e.stopPropagation();
6005
6375
  },
6006
- onMouseEnter: (e) => {
6007
- e.currentTarget.style.background = "#F5F5F4";
6008
- },
6009
- onMouseLeave: (e) => {
6010
- e.currentTarget.style.background = "transparent";
6011
- },
6012
- style: {
6013
- display: "flex",
6014
- alignItems: "center",
6015
- justifyContent: "center",
6016
- border: "none",
6017
- background: "transparent",
6018
- borderRadius: 4,
6019
- cursor: "pointer",
6020
- color: "#1C1917",
6021
- flexShrink: 0,
6022
- padding: 6
6023
- },
6024
- children: EDIT_LINK_ICON
6376
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react3.Link, { className: "size-4 shrink-0", "aria-hidden": true })
6025
6377
  }
6026
6378
  ) : null
6027
- ]
6379
+ ] })
6028
6380
  }
6029
6381
  );
6030
6382
  }
@@ -6038,7 +6390,7 @@ function StateToggle({
6038
6390
  states,
6039
6391
  onStateChange
6040
6392
  }) {
6041
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
6393
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6042
6394
  ToggleGroup,
6043
6395
  {
6044
6396
  "data-ohw-state-toggle": "",
@@ -6052,7 +6404,7 @@ function StateToggle({
6052
6404
  left: rect.right - 8,
6053
6405
  transform: "translateX(-100%)"
6054
6406
  },
6055
- children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
6407
+ children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
6056
6408
  }
6057
6409
  );
6058
6410
  }
@@ -6140,6 +6492,10 @@ function OhhwellsBridge() {
6140
6492
  });
6141
6493
  const deselectRef = (0, import_react6.useRef)(() => {
6142
6494
  });
6495
+ const reselectNavigationItemRef = (0, import_react6.useRef)(() => {
6496
+ });
6497
+ const commitNavigationTextEditRef = (0, import_react6.useRef)(() => {
6498
+ });
6143
6499
  const refreshActiveCommandsRef = (0, import_react6.useRef)(() => {
6144
6500
  });
6145
6501
  const postToParentRef = (0, import_react6.useRef)(postToParent);
@@ -6150,11 +6506,18 @@ function OhhwellsBridge() {
6150
6506
  const [toolbarVariant, setToolbarVariant] = (0, import_react6.useState)("none");
6151
6507
  const toolbarVariantRef = (0, import_react6.useRef)("none");
6152
6508
  toolbarVariantRef.current = toolbarVariant;
6509
+ const [reorderHrefKey, setReorderHrefKey] = (0, import_react6.useState)(null);
6510
+ const [reorderDragDisabled, setReorderDragDisabled] = (0, import_react6.useState)(false);
6153
6511
  const [toggleState, setToggleState] = (0, import_react6.useState)(null);
6154
6512
  const [maxBadge, setMaxBadge] = (0, import_react6.useState)(null);
6155
6513
  const [activeCommands, setActiveCommands] = (0, import_react6.useState)(/* @__PURE__ */ new Set());
6156
6514
  const [sectionGap, setSectionGap] = (0, import_react6.useState)(null);
6157
6515
  const [toolbarShowEditLink, setToolbarShowEditLink] = (0, import_react6.useState)(false);
6516
+ const hoveredItemElRef = (0, import_react6.useRef)(null);
6517
+ const [hoveredItemRect, setHoveredItemRect] = (0, import_react6.useState)(null);
6518
+ const siblingHintElRef = (0, import_react6.useRef)(null);
6519
+ const [siblingHintRect, setSiblingHintRect] = (0, import_react6.useState)(null);
6520
+ const [isItemDragging, setIsItemDragging] = (0, import_react6.useState)(false);
6158
6521
  const [linkPopover, setLinkPopover] = (0, import_react6.useState)(null);
6159
6522
  const [sitePages, setSitePages] = (0, import_react6.useState)([]);
6160
6523
  const [sectionsByPath, setSectionsByPath] = (0, import_react6.useState)({});
@@ -6256,7 +6619,7 @@ function OhhwellsBridge() {
6256
6619
  (0, import_react6.useEffect)(() => {
6257
6620
  const update = () => {
6258
6621
  const el = activeElRef.current ?? selectedElRef.current;
6259
- if (el) setToolbarRect(el.getBoundingClientRect());
6622
+ if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
6260
6623
  setToggleState((prev) => {
6261
6624
  if (!prev || !activeStateElRef.current) return prev;
6262
6625
  return { ...prev, rect: activeStateElRef.current.getBoundingClientRect() };
@@ -6323,6 +6686,8 @@ function OhhwellsBridge() {
6323
6686
  }
6324
6687
  el.removeAttribute("contenteditable");
6325
6688
  activeElRef.current = null;
6689
+ setReorderHrefKey(null);
6690
+ setReorderDragDisabled(false);
6326
6691
  if (!selectedElRef.current) {
6327
6692
  setToolbarRect(null);
6328
6693
  setToolbarVariant("none");
@@ -6334,16 +6699,82 @@ function OhhwellsBridge() {
6334
6699
  }, [postToParent]);
6335
6700
  const deselect = (0, import_react6.useCallback)(() => {
6336
6701
  selectedElRef.current = null;
6702
+ setReorderHrefKey(null);
6703
+ setReorderDragDisabled(false);
6704
+ siblingHintElRef.current = null;
6705
+ setSiblingHintRect(null);
6706
+ setIsItemDragging(false);
6337
6707
  if (!activeElRef.current) {
6338
6708
  setToolbarRect(null);
6339
6709
  setToolbarVariant("none");
6340
6710
  }
6341
6711
  }, []);
6712
+ const reselectNavigationItem = (0, import_react6.useCallback)((navAnchor) => {
6713
+ selectedElRef.current = navAnchor;
6714
+ const { key, disabled } = getNavigationItemReorderState(navAnchor);
6715
+ setReorderHrefKey(key);
6716
+ setReorderDragDisabled(disabled);
6717
+ setToolbarVariant("link-action");
6718
+ setToolbarRect(navAnchor.getBoundingClientRect());
6719
+ setToolbarShowEditLink(false);
6720
+ setActiveCommands(/* @__PURE__ */ new Set());
6721
+ }, []);
6722
+ const commitNavigationTextEdit = (0, import_react6.useCallback)((navAnchor) => {
6723
+ const el = activeElRef.current;
6724
+ if (!el) return;
6725
+ const key = el.dataset.ohwKey;
6726
+ if (key) {
6727
+ const timer = autoSaveTimers.current.get(key);
6728
+ if (timer !== void 0) {
6729
+ clearTimeout(timer);
6730
+ autoSaveTimers.current.delete(key);
6731
+ }
6732
+ const html = sanitizeHtml(el.innerHTML);
6733
+ const original = originalContentRef.current ?? "";
6734
+ if (html !== sanitizeHtml(original)) {
6735
+ postToParent({ type: "ow:change", nodes: [{ key, text: html }] });
6736
+ const h = document.documentElement.scrollHeight;
6737
+ if (h > 50) postToParent({ type: "ow:height", height: h });
6738
+ }
6739
+ }
6740
+ el.removeAttribute("contenteditable");
6741
+ activeElRef.current = null;
6742
+ setMaxBadge(null);
6743
+ setActiveCommands(/* @__PURE__ */ new Set());
6744
+ setToolbarShowEditLink(false);
6745
+ postToParent({ type: "ow:exit-edit" });
6746
+ reselectNavigationItem(navAnchor);
6747
+ }, [postToParent, reselectNavigationItem]);
6748
+ const handleAddNavigationItem = (0, import_react6.useCallback)(() => {
6749
+ const selected = selectedElRef.current;
6750
+ if (!selected) return;
6751
+ const target = getNavigationItemAddHintTarget(selected);
6752
+ siblingHintElRef.current = target;
6753
+ setSiblingHintRect(target.getBoundingClientRect());
6754
+ }, []);
6755
+ const handleItemDragStart = (0, import_react6.useCallback)(() => {
6756
+ siblingHintElRef.current = null;
6757
+ setSiblingHintRect(null);
6758
+ setIsItemDragging(true);
6759
+ }, []);
6760
+ const handleItemDragEnd = (0, import_react6.useCallback)(() => {
6761
+ setIsItemDragging(false);
6762
+ }, []);
6763
+ reselectNavigationItemRef.current = reselectNavigationItem;
6764
+ commitNavigationTextEditRef.current = commitNavigationTextEdit;
6342
6765
  const select = (0, import_react6.useCallback)((anchor) => {
6343
- if (!isNavbarButton(anchor)) return;
6766
+ if (!isNavigationItem(anchor)) return;
6344
6767
  if (activeElRef.current) deactivate();
6345
6768
  selectedElRef.current = anchor;
6346
6769
  clearHrefKeyHover(anchor);
6770
+ setHoveredItemRect(null);
6771
+ hoveredItemElRef.current = null;
6772
+ siblingHintElRef.current = null;
6773
+ setSiblingHintRect(null);
6774
+ setIsItemDragging(false);
6775
+ const { key, disabled } = getNavigationItemReorderState(anchor);
6776
+ setReorderHrefKey(key);
6777
+ setReorderDragDisabled(disabled);
6347
6778
  setToolbarVariant("link-action");
6348
6779
  setToolbarRect(anchor.getBoundingClientRect());
6349
6780
  setToolbarShowEditLink(false);
@@ -6358,13 +6789,26 @@ function OhhwellsBridge() {
6358
6789
  postToParentRef.current({ type: "ow:image-unhover" });
6359
6790
  }
6360
6791
  setToolbarVariant("rich-text");
6792
+ siblingHintElRef.current = null;
6793
+ setSiblingHintRect(null);
6794
+ setIsItemDragging(false);
6361
6795
  el.setAttribute("contenteditable", "true");
6362
6796
  el.removeAttribute("data-ohw-hovered");
6797
+ el.closest("[data-ohw-href-key]")?.removeAttribute("data-ohw-hovered");
6363
6798
  activeElRef.current = el;
6364
6799
  originalContentRef.current = el.innerHTML;
6365
6800
  el.focus();
6366
- setToolbarRect(el.getBoundingClientRect());
6367
6801
  setToolbarShowEditLink(Boolean(getHrefKeyFromElement(el)));
6802
+ const navAnchor = getNavigationItemAnchor(el);
6803
+ if (navAnchor) {
6804
+ setReorderHrefKey(null);
6805
+ setReorderDragDisabled(false);
6806
+ } else {
6807
+ const { key: reorderKey, disabled: reorderDisabled } = getReorderHandleState(el);
6808
+ setReorderHrefKey(reorderKey);
6809
+ setReorderDragDisabled(reorderDisabled);
6810
+ }
6811
+ setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
6368
6812
  postToParent({ type: "ow:enter-edit", key: el.dataset.ohwKey });
6369
6813
  requestAnimationFrame(() => refreshActiveCommandsRef.current());
6370
6814
  }, [deactivate, postToParent]);
@@ -6556,18 +7000,25 @@ function OhhwellsBridge() {
6556
7000
  [data-ohw-editable="image"], [data-ohw-editable="image"] *,
6557
7001
  [data-ohw-editable="bg-image"], [data-ohw-editable="bg-image"] * { cursor: pointer !important; }
6558
7002
  [data-ohw-editable="link"], [data-ohw-editable="link"] * { cursor: pointer !important; }
6559
- [data-ohw-hovered]:not([contenteditable]) {
6560
- outline: 2px dashed ${PRIMARY} !important;
7003
+ [data-ohw-hovered]:not([contenteditable]):not([data-ohw-href-key]) {
7004
+ outline: 2px dashed ${PRIMARY2} !important;
6561
7005
  outline-offset: 4px;
6562
7006
  border-radius: 2px;
6563
7007
  }
7008
+ [data-ohw-href-key] [data-ohw-hovered],
7009
+ [data-ohw-href-key][data-ohw-hovered],
7010
+ nav [data-ohw-href-key] [data-ohw-hovered],
7011
+ footer [data-ohw-href-key] [data-ohw-hovered] {
7012
+ outline: none !important;
7013
+ outline-offset: 0 !important;
7014
+ }
6564
7015
  [data-ohw-editable][contenteditable] {
6565
7016
  outline: none !important;
6566
- caret-color: ${PRIMARY};
7017
+ caret-color: ${PRIMARY2};
6567
7018
  cursor: text !important;
6568
7019
  }
6569
7020
  [data-ohw-editable][contenteditable]::selection,
6570
- [data-ohw-editable][contenteditable] *::selection { background: ${PRIMARY}59 !important; }
7021
+ [data-ohw-editable][contenteditable] *::selection { background: ${PRIMARY2}59 !important; }
6571
7022
  [data-ohw-editable-state], [data-ohw-editable-state] * { pointer-events: none !important; }
6572
7023
  [data-ohw-editable-state][data-ohw-active-state] [data-ohw-editable] { pointer-events: auto !important; }
6573
7024
  [data-ohw-editable-state][data-ohw-active-state][data-ohw-editable] { pointer-events: auto !important; }
@@ -6579,7 +7030,7 @@ function OhhwellsBridge() {
6579
7030
  stateViews.textContent = `
6580
7031
  [data-ohw-state-view]:not([data-ohw-state-view="default"]) { display: none; }
6581
7032
  [data-ohw-state-view="default"] [data-ohw-editable] { pointer-events: auto !important; }
6582
- [data-ohw-state-hovered] { outline: 2px dashed ${PRIMARY} !important; outline-offset: 4px; border-radius: 2px; }
7033
+ [data-ohw-state-hovered] { outline: 2px dashed ${PRIMARY2} !important; outline-offset: 4px; border-radius: 2px; }
6583
7034
  [data-ohw-state-hovered]:has([data-ohw-hovered]) { outline: none !important; }
6584
7035
  `;
6585
7036
  document.head.appendChild(base);
@@ -6594,6 +7045,11 @@ function OhhwellsBridge() {
6594
7045
  if (target.closest("[data-ohw-state-toggle]")) return;
6595
7046
  if (target.closest("[data-ohw-max-badge]")) return;
6596
7047
  if (isInsideLinkEditor(target)) return;
7048
+ if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
7049
+ e.preventDefault();
7050
+ e.stopPropagation();
7051
+ return;
7052
+ }
6597
7053
  const editable = target.closest("[data-ohw-editable]");
6598
7054
  if (editable) {
6599
7055
  if (editable.dataset.ohwEditable === "link") {
@@ -6615,15 +7071,15 @@ function OhhwellsBridge() {
6615
7071
  return;
6616
7072
  }
6617
7073
  const hrefCtx = getHrefKeyFromElement(editable);
6618
- if (hrefCtx && isNavbarButton(hrefCtx.anchor)) {
7074
+ const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
7075
+ if (navAnchor) {
6619
7076
  e.preventDefault();
6620
7077
  e.stopPropagation();
6621
- const { anchor: anchor2 } = hrefCtx;
6622
- if (selectedElRef.current === anchor2) {
7078
+ if (selectedElRef.current === navAnchor) {
6623
7079
  activateRef.current(editable);
6624
7080
  return;
6625
7081
  }
6626
- selectRef.current(anchor2);
7082
+ selectRef.current(navAnchor);
6627
7083
  return;
6628
7084
  }
6629
7085
  e.preventDefault();
@@ -6631,8 +7087,8 @@ function OhhwellsBridge() {
6631
7087
  activateRef.current(editable);
6632
7088
  return;
6633
7089
  }
6634
- const hrefAnchor = target.closest("[data-ohw-href-key]");
6635
- if (hrefAnchor && isNavbarButton(hrefAnchor)) {
7090
+ const hrefAnchor = getNavigationItemAnchor(target);
7091
+ if (hrefAnchor) {
6636
7092
  e.preventDefault();
6637
7093
  e.stopPropagation();
6638
7094
  if (selectedElRef.current === hrefAnchor) return;
@@ -6665,19 +7121,58 @@ function OhhwellsBridge() {
6665
7121
  deactivateRef.current();
6666
7122
  };
6667
7123
  const handleMouseOver = (e) => {
6668
- const editable = e.target.closest("[data-ohw-editable]");
7124
+ const target = e.target;
7125
+ const navAnchor = getNavigationItemAnchor(target);
7126
+ if (navAnchor) {
7127
+ const selected2 = selectedElRef.current;
7128
+ if (selected2 === navAnchor || selected2?.contains(navAnchor)) return;
7129
+ clearHrefKeyHover(navAnchor);
7130
+ hoveredItemElRef.current = navAnchor;
7131
+ setHoveredItemRect(navAnchor.getBoundingClientRect());
7132
+ return;
7133
+ }
7134
+ const editable = target.closest("[data-ohw-editable]");
6669
7135
  if (!editable) return;
6670
7136
  const selected = selectedElRef.current;
6671
7137
  if (selected && (selected === editable || selected.contains(editable))) return;
6672
7138
  if (editable.dataset.ohwEditable !== "image" && editable.dataset.ohwEditable !== "bg-image" && !editable.hasAttribute("contenteditable")) {
6673
- editable.setAttribute("data-ohw-hovered", "");
7139
+ const hoverTarget = editable.closest("[data-ohw-href-key]") ?? editable;
7140
+ if (hoverTarget.hasAttribute("data-ohw-href-key")) {
7141
+ clearHrefKeyHover(hoverTarget);
7142
+ hoveredItemElRef.current = hoverTarget;
7143
+ setHoveredItemRect(hoverTarget.getBoundingClientRect());
7144
+ } else if (!isInsideNavigationItem(editable)) {
7145
+ hoverTarget.setAttribute("data-ohw-hovered", "");
7146
+ }
6674
7147
  }
6675
7148
  };
6676
7149
  const handleMouseOut = (e) => {
6677
- const editable = e.target.closest("[data-ohw-editable]");
7150
+ const target = e.target;
7151
+ const navAnchor = getNavigationItemAnchor(target);
7152
+ if (navAnchor) {
7153
+ const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
7154
+ if (related2?.closest("[data-ohw-drag-handle-container], [data-ohw-item-interaction]")) return;
7155
+ if (related2 && navAnchor.contains(related2)) return;
7156
+ if (hoveredItemElRef.current === navAnchor) {
7157
+ hoveredItemElRef.current = null;
7158
+ setHoveredItemRect(null);
7159
+ }
7160
+ return;
7161
+ }
7162
+ const editable = target.closest("[data-ohw-editable]");
6678
7163
  if (!editable) return;
7164
+ const related = e.relatedTarget instanceof Element ? e.relatedTarget : null;
7165
+ if (related?.closest("[data-ohw-drag-handle-container], [data-ohw-item-interaction]")) return;
6679
7166
  if (editable.dataset.ohwEditable !== "image" && editable.dataset.ohwEditable !== "bg-image") {
6680
- editable.removeAttribute("data-ohw-hovered");
7167
+ const hoverTarget = editable.closest("[data-ohw-href-key]") ?? editable;
7168
+ if (hoverTarget.hasAttribute("data-ohw-href-key")) {
7169
+ if (!related?.closest("[data-ohw-href-key]")) {
7170
+ hoveredItemElRef.current = null;
7171
+ setHoveredItemRect(null);
7172
+ }
7173
+ } else {
7174
+ hoverTarget.removeAttribute("data-ohw-hovered");
7175
+ }
6681
7176
  }
6682
7177
  };
6683
7178
  const toProbeCoords = (clientX, clientY, fromParentViewport) => {
@@ -6792,11 +7287,20 @@ function OhhwellsBridge() {
6792
7287
  return;
6793
7288
  }
6794
7289
  }
7290
+ if (activeElRef.current) {
7291
+ if (hoveredImageRef.current) {
7292
+ hoveredImageRef.current = null;
7293
+ hoveredImageHasTextOverlapRef.current = false;
7294
+ resumeAnimTracks();
7295
+ postToParentRef.current({ type: "ow:image-unhover" });
7296
+ }
7297
+ return;
7298
+ }
6795
7299
  const imgEl = findImageAtPoint(clientX, clientY, fromParentViewport);
6796
7300
  if (imgEl) {
6797
7301
  const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
6798
7302
  const topEl = document.elementFromPoint(x, y);
6799
- if (topEl?.closest("[data-ohw-toolbar]")) {
7303
+ if (topEl?.closest('[data-ohw-toolbar], [data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
6800
7304
  if (hoveredImageRef.current) {
6801
7305
  hoveredImageRef.current = null;
6802
7306
  resumeAnimTracks();
@@ -6844,7 +7348,9 @@ function OhhwellsBridge() {
6844
7348
  postImageHover(imgEl, isDragOver, true);
6845
7349
  }
6846
7350
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
6847
- textEditable.setAttribute("data-ohw-hovered", "");
7351
+ if (textEditable && !isInsideNavigationItem(textEditable)) {
7352
+ textEditable.setAttribute("data-ohw-hovered", "");
7353
+ }
6848
7354
  return;
6849
7355
  }
6850
7356
  if (hoveredImageRef.current) {
@@ -6854,7 +7360,9 @@ function OhhwellsBridge() {
6854
7360
  postToParentRef.current({ type: "ow:image-unhover" });
6855
7361
  }
6856
7362
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
6857
- textEditable.setAttribute("data-ohw-hovered", "");
7363
+ if (textEditable && !isInsideNavigationItem(textEditable)) {
7364
+ textEditable.setAttribute("data-ohw-hovered", "");
7365
+ }
6858
7366
  return;
6859
7367
  }
6860
7368
  if (hoveredGapRef.current) {
@@ -6898,7 +7406,24 @@ function OhhwellsBridge() {
6898
7406
  return x >= er.left && x <= er.right && y >= er.top && y <= er.bottom;
6899
7407
  });
6900
7408
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
6901
- if (textEl && !textEl.hasAttribute("contenteditable")) textEl.setAttribute("data-ohw-hovered", "");
7409
+ if (textEl && !textEl.hasAttribute("contenteditable")) {
7410
+ const navAnchor = getNavigationItemAnchor(textEl);
7411
+ if (navAnchor) {
7412
+ const selected = selectedElRef.current;
7413
+ if (selected !== navAnchor && !selected?.contains(navAnchor)) {
7414
+ clearHrefKeyHover(navAnchor);
7415
+ hoveredItemElRef.current = navAnchor;
7416
+ setHoveredItemRect(navAnchor.getBoundingClientRect());
7417
+ }
7418
+ } else {
7419
+ hoveredItemElRef.current = null;
7420
+ setHoveredItemRect(null);
7421
+ textEl.setAttribute("data-ohw-hovered", "");
7422
+ }
7423
+ } else {
7424
+ hoveredItemElRef.current = null;
7425
+ setHoveredItemRect(null);
7426
+ }
6902
7427
  }
6903
7428
  };
6904
7429
  const probeHoverCardsAt = (clientX, clientY, fromParentViewport = false) => {
@@ -7089,7 +7614,7 @@ function OhhwellsBridge() {
7089
7614
  const el = e.target;
7090
7615
  const key = el.dataset.ohwKey;
7091
7616
  if (!key) return;
7092
- if (el === activeElRef.current) setToolbarRect(el.getBoundingClientRect());
7617
+ if (el === activeElRef.current) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
7093
7618
  const maxLen = el.dataset.ohwMaxLength ? parseInt(el.dataset.ohwMaxLength, 10) : null;
7094
7619
  if (maxLen) {
7095
7620
  const current = el.innerText.replace(/\n$/, "").length;
@@ -7176,6 +7701,33 @@ function OhhwellsBridge() {
7176
7701
  deselectRef.current();
7177
7702
  return;
7178
7703
  }
7704
+ if (e.key === "Escape" && activeElRef.current) {
7705
+ const hrefCtx = getHrefKeyFromElement(activeElRef.current);
7706
+ const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
7707
+ if (navAnchor) {
7708
+ e.preventDefault();
7709
+ const el2 = activeElRef.current;
7710
+ if (originalContentRef.current !== null) {
7711
+ el2.innerHTML = originalContentRef.current;
7712
+ }
7713
+ el2.removeAttribute("contenteditable");
7714
+ activeElRef.current = null;
7715
+ setMaxBadge(null);
7716
+ setActiveCommands(/* @__PURE__ */ new Set());
7717
+ setToolbarShowEditLink(false);
7718
+ postToParentRef.current({ type: "ow:exit-edit" });
7719
+ reselectNavigationItemRef.current(navAnchor);
7720
+ return;
7721
+ }
7722
+ }
7723
+ if (e.key === "Enter" && !e.shiftKey && activeElRef.current) {
7724
+ const navAnchor = getNavigationItemAnchor(activeElRef.current);
7725
+ if (navAnchor) {
7726
+ e.preventDefault();
7727
+ commitNavigationTextEditRef.current(navAnchor);
7728
+ return;
7729
+ }
7730
+ }
7179
7731
  if (e.key !== "Escape") return;
7180
7732
  const el = activeElRef.current;
7181
7733
  if (el && originalContentRef.current !== null) {
@@ -7191,7 +7743,8 @@ function OhhwellsBridge() {
7191
7743
  const handleScroll = () => {
7192
7744
  const focusEl = activeElRef.current ?? selectedElRef.current;
7193
7745
  if (focusEl) {
7194
- const r2 = focusEl.getBoundingClientRect();
7746
+ const measureEl = activeElRef.current ? getEditMeasureEl(activeElRef.current) : focusEl;
7747
+ const r2 = measureEl.getBoundingClientRect();
7195
7748
  applyToolbarPos(r2);
7196
7749
  setToolbarRect(r2);
7197
7750
  setMaxBadge((prev) => prev && activeElRef.current ? { ...prev, rect: r2 } : prev);
@@ -7200,6 +7753,12 @@ function OhhwellsBridge() {
7200
7753
  const rect = activeStateElRef.current.getBoundingClientRect();
7201
7754
  setToggleState((prev) => prev ? { ...prev, rect } : null);
7202
7755
  }
7756
+ if (hoveredItemElRef.current) {
7757
+ setHoveredItemRect(hoveredItemElRef.current.getBoundingClientRect());
7758
+ }
7759
+ if (siblingHintElRef.current) {
7760
+ setSiblingHintRect(siblingHintElRef.current.getBoundingClientRect());
7761
+ }
7203
7762
  if (hoveredImageRef.current) {
7204
7763
  const el = hoveredImageRef.current;
7205
7764
  const r2 = el.getBoundingClientRect();
@@ -7319,7 +7878,7 @@ function OhhwellsBridge() {
7319
7878
  };
7320
7879
  const applyToolbarPos = (rect) => {
7321
7880
  const ps = parentScrollRef.current;
7322
- const approxW = toolbarVariantRef.current === "link-action" ? 120 : 330;
7881
+ const approxW = 330;
7323
7882
  if (toolbarElRef.current) {
7324
7883
  const { top, left, transform } = calcToolbarPos(rect, ps, approxW);
7325
7884
  toolbarElRef.current.style.top = `${top}px`;
@@ -7330,6 +7889,8 @@ function OhhwellsBridge() {
7330
7889
  const GAP = 6;
7331
7890
  glowElRef.current.style.top = `${rect.top - GAP}px`;
7332
7891
  glowElRef.current.style.left = `${rect.left - GAP}px`;
7892
+ glowElRef.current.style.width = `${rect.width + GAP * 2}px`;
7893
+ glowElRef.current.style.height = `${rect.height + GAP * 2}px`;
7333
7894
  }
7334
7895
  };
7335
7896
  const handleParentScroll = (e) => {
@@ -7340,7 +7901,10 @@ function OhhwellsBridge() {
7340
7901
  applyVisibleViewport(visibleViewportRef.current, parentScrollRef.current);
7341
7902
  }
7342
7903
  const focusEl = activeElRef.current ?? selectedElRef.current;
7343
- if (focusEl) applyToolbarPos(focusEl.getBoundingClientRect());
7904
+ if (focusEl) {
7905
+ const measureEl = activeElRef.current ? getEditMeasureEl(activeElRef.current) : focusEl;
7906
+ applyToolbarPos(measureEl.getBoundingClientRect());
7907
+ }
7344
7908
  };
7345
7909
  const handleClickAt = (e) => {
7346
7910
  if (e.data?.type !== "ow:click-at") return;
@@ -7498,7 +8062,7 @@ function OhhwellsBridge() {
7498
8062
  const handleCommand = (0, import_react6.useCallback)((cmd) => {
7499
8063
  document.execCommand(cmd, false);
7500
8064
  activeElRef.current?.focus();
7501
- if (activeElRef.current) setToolbarRect(activeElRef.current.getBoundingClientRect());
8065
+ if (activeElRef.current) setToolbarRect(getEditMeasureEl(activeElRef.current).getBoundingClientRect());
7502
8066
  refreshActiveCommandsRef.current();
7503
8067
  }, []);
7504
8068
  const handleStateChange = (0, import_react6.useCallback)((state) => {
@@ -7551,37 +8115,55 @@ function OhhwellsBridge() {
7551
8115
  const currentSections = sectionsByPath[pathname] ?? [];
7552
8116
  linkPopoverOpenRef.current = linkPopover !== null;
7553
8117
  return bridgeRoot ? (0, import_react_dom2.createPortal)(
7554
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
7555
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
7556
- toolbarRect && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
7557
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(GlowFrame, { rect: toolbarRect, elRef: glowElRef }),
7558
- toolbarVariant === "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
7559
- FloatingToolbar,
8118
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
8119
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
8120
+ siblingHintRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
8121
+ hoveredItemRect && !siblingHintRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
8122
+ toolbarRect && toolbarVariant === "link-action" && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8123
+ ItemInteractionLayer,
8124
+ {
8125
+ rect: toolbarRect,
8126
+ elRef: glowElRef,
8127
+ state: isItemDragging ? "dragging" : resolveItemInteractionState(toolbarRect, parentScrollRef.current),
8128
+ showHandle: Boolean(reorderHrefKey),
8129
+ dragDisabled: reorderDragDisabled,
8130
+ dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
8131
+ onDragHandleDragStart: handleItemDragStart,
8132
+ onDragHandleDragEnd: handleItemDragEnd,
8133
+ toolbar: isItemDragging ? void 0 : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8134
+ ItemActionToolbar,
8135
+ {
8136
+ onEditLink: openLinkPopoverForSelected,
8137
+ onAddItem: handleAddNavigationItem,
8138
+ addItemDisabled: false
8139
+ }
8140
+ )
8141
+ }
8142
+ ),
8143
+ toolbarRect && toolbarVariant === "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
8144
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8145
+ EditGlowChrome,
7560
8146
  {
7561
- variant: "rich-text",
7562
8147
  rect: toolbarRect,
7563
- parentScroll: parentScrollRef.current,
7564
- elRef: toolbarElRef,
7565
- onCommand: handleCommand,
7566
- activeCommands,
7567
- showEditLink,
7568
- onEditLink: openLinkPopoverForActive
8148
+ elRef: glowElRef,
8149
+ reorderHrefKey,
8150
+ dragDisabled: reorderDragDisabled
7569
8151
  }
7570
8152
  ),
7571
- toolbarVariant === "link-action" && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
8153
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7572
8154
  FloatingToolbar,
7573
8155
  {
7574
- variant: "link-action",
7575
8156
  rect: toolbarRect,
7576
8157
  parentScroll: parentScrollRef.current,
7577
8158
  elRef: toolbarElRef,
7578
8159
  onCommand: handleCommand,
7579
8160
  activeCommands,
7580
- onEditLink: openLinkPopoverForSelected
8161
+ showEditLink,
8162
+ onEditLink: openLinkPopoverForActive
7581
8163
  }
7582
8164
  )
7583
8165
  ] }),
7584
- maxBadge && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
8166
+ maxBadge && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
7585
8167
  "div",
7586
8168
  {
7587
8169
  "data-ohw-max-badge": "",
@@ -7607,7 +8189,7 @@ function OhhwellsBridge() {
7607
8189
  ]
7608
8190
  }
7609
8191
  ),
7610
- toggleState && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
8192
+ toggleState && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7611
8193
  StateToggle,
7612
8194
  {
7613
8195
  rect: toggleState.rect,
@@ -7616,15 +8198,15 @@ function OhhwellsBridge() {
7616
8198
  onStateChange: handleStateChange
7617
8199
  }
7618
8200
  ),
7619
- sectionGap && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
8201
+ sectionGap && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
7620
8202
  "div",
7621
8203
  {
7622
8204
  "data-ohw-section-insert-line": "",
7623
8205
  className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
7624
8206
  style: { top: sectionGap.y, transform: "translateY(-50%)" },
7625
8207
  children: [
7626
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
7627
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
8208
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
8209
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7628
8210
  Badge,
7629
8211
  {
7630
8212
  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",
@@ -7637,11 +8219,11 @@ function OhhwellsBridge() {
7637
8219
  children: "Add Section"
7638
8220
  }
7639
8221
  ),
7640
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
8222
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
7641
8223
  ]
7642
8224
  }
7643
8225
  ),
7644
- linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
8226
+ linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7645
8227
  LinkPopover,
7646
8228
  {
7647
8229
  panelRef: linkPopoverPanelRef,
@@ -7656,13 +8238,44 @@ function OhhwellsBridge() {
7656
8238
  onSubmit: handleLinkPopoverSubmit
7657
8239
  },
7658
8240
  `${linkPopover.key}-${pathname}`
7659
- ) : null
8241
+ ) : null,
8242
+ sectionGap && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
8243
+ "div",
8244
+ {
8245
+ "data-ohw-section-insert-line": "",
8246
+ className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
8247
+ style: { top: sectionGap.y, transform: "translateY(-50%)" },
8248
+ children: [
8249
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
8250
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8251
+ Badge,
8252
+ {
8253
+ 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",
8254
+ onClick: () => {
8255
+ window.parent.postMessage(
8256
+ { type: "ow:add-section", insertAfter: sectionGap.insertAfter, insertBefore: sectionGap.insertBefore },
8257
+ "*"
8258
+ );
8259
+ },
8260
+ children: "Add Section"
8261
+ }
8262
+ ),
8263
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
8264
+ ]
8265
+ }
8266
+ )
7660
8267
  ] }),
7661
8268
  bridgeRoot
7662
8269
  ) : null;
7663
8270
  }
7664
8271
  // Annotate the CommonJS export names for ESM import in node:
7665
8272
  0 && (module.exports = {
8273
+ CustomToolbar,
8274
+ CustomToolbarButton,
8275
+ CustomToolbarDivider,
8276
+ DragHandle,
8277
+ ItemActionToolbar,
8278
+ ItemInteractionLayer,
7666
8279
  LinkEditorPanel,
7667
8280
  LinkPopover,
7668
8281
  OhhwellsBridge,
@@ -7670,9 +8283,14 @@ function OhhwellsBridge() {
7670
8283
  Toggle,
7671
8284
  ToggleGroup,
7672
8285
  ToggleGroupItem,
8286
+ Tooltip,
8287
+ TooltipContent,
8288
+ TooltipProvider,
8289
+ TooltipTrigger,
7673
8290
  buildTarget,
7674
8291
  filterAvailablePages,
7675
8292
  getEditModeInitialState,
8293
+ isEditSessionActive,
7676
8294
  isValidUrl,
7677
8295
  parseTarget,
7678
8296
  toggleVariants,