@ohhwells/bridge 0.1.36-next.48 → 0.1.36-next.50

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
@@ -4639,6 +4639,220 @@ function ItemInteractionLayer({
4639
4639
  );
4640
4640
  }
4641
4641
 
4642
+ // src/ui/MediaOverlay.tsx
4643
+ var React6 = __toESM(require("react"), 1);
4644
+ var import_lucide_react3 = require("lucide-react");
4645
+
4646
+ // src/ui/button.tsx
4647
+ var React5 = __toESM(require("react"), 1);
4648
+ var import_radix_ui4 = require("radix-ui");
4649
+ var import_jsx_runtime10 = require("react/jsx-runtime");
4650
+ var buttonVariants = cva(
4651
+ "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",
4652
+ {
4653
+ variants: {
4654
+ variant: {
4655
+ default: "bg-primary text-primary-foreground hover:opacity-90",
4656
+ outline: "border border-border bg-background text-foreground shadow-sm hover:bg-muted/80",
4657
+ ghost: "min-w-0 px-3 py-2 text-foreground hover:bg-muted/50"
4658
+ },
4659
+ size: {
4660
+ default: "h-9",
4661
+ sm: "h-8 min-w-[64px] px-2 py-1.5 text-sm"
4662
+ }
4663
+ },
4664
+ defaultVariants: {
4665
+ variant: "default",
4666
+ size: "default"
4667
+ }
4668
+ }
4669
+ );
4670
+ var Button = React5.forwardRef(
4671
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
4672
+ const Comp = asChild ? import_radix_ui4.Slot.Root : "button";
4673
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
4674
+ Comp,
4675
+ {
4676
+ ref,
4677
+ "data-slot": "button",
4678
+ className: cn(buttonVariants({ variant, size, className })),
4679
+ ...props
4680
+ }
4681
+ );
4682
+ }
4683
+ );
4684
+ Button.displayName = "Button";
4685
+
4686
+ // src/ui/MediaOverlay.tsx
4687
+ var import_jsx_runtime11 = require("react/jsx-runtime");
4688
+ var MEDIA_UPLOAD_FADE_MS = 300;
4689
+ var VIDEO_SETTINGS_BAR_INSET = 8;
4690
+ var OVERLAY_BUTTON_STYLE = {
4691
+ pointerEvents: "auto",
4692
+ fontFamily: "Inter, sans-serif",
4693
+ fontSize: 12,
4694
+ color: "#000"
4695
+ };
4696
+ var SKELETON_CSS = `
4697
+ @keyframes ohw-media-shimmer {
4698
+ 0% { transform: translateX(-100%); }
4699
+ 100% { transform: translateX(100%); }
4700
+ }
4701
+ [data-ohw-media-skeleton] {
4702
+ overflow: hidden;
4703
+ background-color: #d1d5db; /* tailwind gray-300 */
4704
+ }
4705
+ [data-ohw-media-skeleton]::after {
4706
+ content: "";
4707
+ position: absolute;
4708
+ inset: 0;
4709
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.6), transparent);
4710
+ animation: ohw-media-shimmer 1.4s infinite;
4711
+ }
4712
+ `;
4713
+ function MediaOverlay({
4714
+ hover,
4715
+ isUploading,
4716
+ fadingOut = false,
4717
+ onFadeOutComplete,
4718
+ onReplace,
4719
+ onVideoSettingsChange
4720
+ }) {
4721
+ const { rect } = hover;
4722
+ const skeletonRef = React6.useRef(null);
4723
+ const isVideo = hover.elementType === "video";
4724
+ const autoplay = hover.videoAutoplay ?? true;
4725
+ const muted = hover.videoMuted ?? true;
4726
+ const box = {
4727
+ position: "fixed",
4728
+ top: rect.top,
4729
+ left: rect.left,
4730
+ width: rect.width,
4731
+ height: rect.height,
4732
+ zIndex: 2147483646
4733
+ };
4734
+ React6.useEffect(() => {
4735
+ if (!isUploading || !fadingOut || !skeletonRef.current) return;
4736
+ const anim = skeletonRef.current.animate([{ opacity: 1 }, { opacity: 0 }], {
4737
+ duration: MEDIA_UPLOAD_FADE_MS,
4738
+ easing: "ease-out",
4739
+ fill: "forwards"
4740
+ });
4741
+ anim.finished.then(() => onFadeOutComplete?.(hover.key)).catch(() => onFadeOutComplete?.(hover.key));
4742
+ return () => anim.cancel();
4743
+ }, [isUploading, fadingOut, onFadeOutComplete, hover.key]);
4744
+ if (isUploading) {
4745
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
4746
+ "div",
4747
+ {
4748
+ ref: skeletonRef,
4749
+ "data-ohw-bridge": "",
4750
+ "data-ohw-media-overlay": "",
4751
+ "data-ohw-media-skeleton": "",
4752
+ "aria-hidden": true,
4753
+ style: { ...box, pointerEvents: "none" },
4754
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("style", { children: SKELETON_CSS })
4755
+ }
4756
+ );
4757
+ }
4758
+ const settingsBar = isVideo && !hover.isDragOver ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
4759
+ "div",
4760
+ {
4761
+ "data-ohw-bridge": "",
4762
+ "data-ohw-media-overlay": "",
4763
+ className: "flex items-center justify-center gap-1.5",
4764
+ style: {
4765
+ position: "fixed",
4766
+ top: rect.top + VIDEO_SETTINGS_BAR_INSET,
4767
+ left: rect.left,
4768
+ width: rect.width,
4769
+ zIndex: 2147483647,
4770
+ pointerEvents: "auto"
4771
+ },
4772
+ onClick: (e) => e.stopPropagation(),
4773
+ children: [
4774
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
4775
+ Button,
4776
+ {
4777
+ "data-ohw-media-overlay": "",
4778
+ variant: "outline",
4779
+ size: "sm",
4780
+ className: "cursor-pointer hover:bg-background",
4781
+ style: { ...OVERLAY_BUTTON_STYLE, minWidth: 0, padding: "0 8px" },
4782
+ "aria-label": autoplay ? "Disable autoplay" : "Enable autoplay",
4783
+ title: autoplay ? "Autoplay on \u2014 click to disable" : "Autoplay off \u2014 click to enable",
4784
+ onMouseDown: (e) => e.preventDefault(),
4785
+ onClick: (e) => {
4786
+ e.stopPropagation();
4787
+ onVideoSettingsChange?.(hover.key, { autoplay: !autoplay });
4788
+ },
4789
+ children: autoplay ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react3.Pause, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react3.Play, { size: 14 })
4790
+ }
4791
+ ),
4792
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
4793
+ Button,
4794
+ {
4795
+ "data-ohw-media-overlay": "",
4796
+ variant: "outline",
4797
+ size: "sm",
4798
+ className: "cursor-pointer hover:bg-background",
4799
+ style: { ...OVERLAY_BUTTON_STYLE, minWidth: 0, padding: "0 8px" },
4800
+ "aria-label": muted ? "Unmute video" : "Mute video",
4801
+ title: muted ? "Muted \u2014 click to unmute" : "Sound on \u2014 click to mute",
4802
+ onMouseDown: (e) => e.preventDefault(),
4803
+ onClick: (e) => {
4804
+ e.stopPropagation();
4805
+ onVideoSettingsChange?.(hover.key, { muted: !muted });
4806
+ },
4807
+ children: muted ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react3.VolumeX, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react3.Volume2, { size: 14 })
4808
+ }
4809
+ )
4810
+ ]
4811
+ }
4812
+ ) : null;
4813
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
4814
+ settingsBar,
4815
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
4816
+ "div",
4817
+ {
4818
+ "data-ohw-bridge": "",
4819
+ "data-ohw-media-overlay": "",
4820
+ className: "flex items-center justify-center cursor-pointer",
4821
+ style: {
4822
+ ...box,
4823
+ // When text overlays this media, let clicks fall THROUGH to the text underneath. In the
4824
+ // parent this needed a whole `ow:click-at` round-trip to re-hit-test inside the iframe;
4825
+ // in-document, pointer-events does it natively. The button below opts back in, so
4826
+ // Replace still works.
4827
+ pointerEvents: hover.hasTextOverlap ? "none" : "auto",
4828
+ boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
4829
+ background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
4830
+ },
4831
+ onClick: () => onReplace(hover.key),
4832
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
4833
+ Button,
4834
+ {
4835
+ "data-ohw-media-overlay": "",
4836
+ variant: "outline",
4837
+ size: "sm",
4838
+ className: "gap-1.5 cursor-pointer hover:bg-background",
4839
+ style: OVERLAY_BUTTON_STYLE,
4840
+ onMouseDown: (e) => e.preventDefault(),
4841
+ onClick: (e) => {
4842
+ e.stopPropagation();
4843
+ onReplace(hover.key);
4844
+ },
4845
+ children: [
4846
+ isVideo ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react3.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react3.ImageIcon, { size: 14 }),
4847
+ isVideo ? "Replace video" : "Replace image"
4848
+ ]
4849
+ }
4850
+ )
4851
+ }
4852
+ )
4853
+ ] });
4854
+ }
4855
+
4642
4856
  // src/OhhwellsBridge.tsx
4643
4857
  var import_react_dom2 = require("react-dom");
4644
4858
  var import_navigation = require("next/navigation");
@@ -4918,61 +5132,61 @@ function scrollToHashSectionWhenReady(behavior = "smooth") {
4918
5132
  }
4919
5133
 
4920
5134
  // src/ui/dialog.tsx
4921
- var React5 = __toESM(require("react"), 1);
4922
- var import_radix_ui4 = require("radix-ui");
5135
+ var React7 = __toESM(require("react"), 1);
5136
+ var import_radix_ui5 = require("radix-ui");
4923
5137
 
4924
5138
  // src/ui/icons.tsx
4925
- var import_jsx_runtime10 = require("react/jsx-runtime");
5139
+ var import_jsx_runtime12 = require("react/jsx-runtime");
4926
5140
  function IconX({ className, ...props }) {
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" })
5141
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
5142
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M18 6 6 18" }),
5143
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "m6 6 12 12" })
4930
5144
  ] });
4931
5145
  }
4932
5146
  function IconChevronDown({ className, ...props }) {
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" }) });
5147
+ return /* @__PURE__ */ (0, import_jsx_runtime12.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_runtime12.jsx)("path", { d: "m6 9 6 6 6-6" }) });
4934
5148
  }
4935
5149
  function IconFile({ className, ...props }) {
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" })
5150
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
5151
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
5152
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" })
4939
5153
  ] });
4940
5154
  }
4941
5155
  function IconInfo({ className, ...props }) {
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" })
5156
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
5157
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
5158
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M12 16v-4" }),
5159
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M12 8h.01" })
4946
5160
  ] });
4947
5161
  }
4948
5162
  function IconArrowRight({ className, ...props }) {
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" })
5163
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
5164
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M5 12h14" }),
5165
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "m12 5 7 7-7 7" })
4952
5166
  ] });
4953
5167
  }
4954
5168
  function IconSection({ className, ...props }) {
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" })
5169
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, ...props, children: [
5170
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("rect", { width: "18", height: "7", x: "3", y: "3", rx: "1" }),
5171
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("rect", { width: "9", height: "7", x: "3", y: "14", rx: "1" }),
5172
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("rect", { width: "5", height: "7", x: "16", y: "14", rx: "1" })
4959
5173
  ] });
4960
5174
  }
4961
5175
 
4962
5176
  // src/ui/dialog.tsx
4963
- var import_jsx_runtime11 = require("react/jsx-runtime");
5177
+ var import_jsx_runtime13 = require("react/jsx-runtime");
4964
5178
  function Dialog2({ ...props }) {
4965
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_radix_ui4.Dialog.Root, { "data-slot": "dialog", ...props });
5179
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_radix_ui5.Dialog.Root, { "data-slot": "dialog", ...props });
4966
5180
  }
4967
5181
  function DialogPortal({ ...props }) {
4968
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_radix_ui4.Dialog.Portal, { ...props });
5182
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_radix_ui5.Dialog.Portal, { ...props });
4969
5183
  }
4970
5184
  function DialogOverlay({
4971
5185
  className,
4972
5186
  ...props
4973
5187
  }) {
4974
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
4975
- import_radix_ui4.Dialog.Overlay,
5188
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5189
+ import_radix_ui5.Dialog.Overlay,
4976
5190
  {
4977
5191
  "data-slot": "dialog-overlay",
4978
5192
  "data-ohw-link-modal-root": "",
@@ -4981,12 +5195,12 @@ function DialogOverlay({
4981
5195
  }
4982
5196
  );
4983
5197
  }
4984
- var DialogContent = React5.forwardRef(({ className, children, showCloseButton = true, container, ...props }, ref) => {
5198
+ var DialogContent = React7.forwardRef(({ className, children, showCloseButton = true, container, ...props }, ref) => {
4985
5199
  const positionMode = container ? "absolute" : "fixed";
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,
5200
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DialogPortal, { container: container ?? void 0, children: [
5201
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DialogOverlay, { className: cn(positionMode, "inset-0") }),
5202
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
5203
+ import_radix_ui5.Dialog.Content,
4990
5204
  {
4991
5205
  ref,
4992
5206
  "data-slot": "dialog-content",
@@ -5001,13 +5215,13 @@ var DialogContent = React5.forwardRef(({ className, children, showCloseButton =
5001
5215
  ...props,
5002
5216
  children: [
5003
5217
  children,
5004
- showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
5005
- import_radix_ui4.Dialog.Close,
5218
+ showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5219
+ import_radix_ui5.Dialog.Close,
5006
5220
  {
5007
5221
  type: "button",
5008
5222
  className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
5009
5223
  "aria-label": "Close",
5010
- children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(IconX, { "aria-hidden": true })
5224
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(IconX, { "aria-hidden": true })
5011
5225
  }
5012
5226
  ) : null
5013
5227
  ]
@@ -5015,105 +5229,65 @@ var DialogContent = React5.forwardRef(({ className, children, showCloseButton =
5015
5229
  )
5016
5230
  ] });
5017
5231
  });
5018
- DialogContent.displayName = import_radix_ui4.Dialog.Content.displayName;
5232
+ DialogContent.displayName = import_radix_ui5.Dialog.Content.displayName;
5019
5233
  function DialogHeader({ className, ...props }) {
5020
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: cn("flex flex-col gap-1.5", className), ...props });
5234
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: cn("flex flex-col gap-1.5", className), ...props });
5021
5235
  }
5022
5236
  function DialogFooter({ className, ...props }) {
5023
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: cn("flex items-center justify-end gap-2", className), ...props });
5237
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: cn("flex items-center justify-end gap-2", className), ...props });
5024
5238
  }
5025
- var DialogTitle = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
5026
- import_radix_ui4.Dialog.Title,
5239
+ var DialogTitle = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5240
+ import_radix_ui5.Dialog.Title,
5027
5241
  {
5028
5242
  ref,
5029
5243
  className: cn("text-lg font-semibold leading-none tracking-tight text-card-foreground", className),
5030
5244
  ...props
5031
5245
  }
5032
5246
  ));
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,
5247
+ DialogTitle.displayName = import_radix_ui5.Dialog.Title.displayName;
5248
+ var DialogDescription = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5249
+ import_radix_ui5.Dialog.Description,
5036
5250
  {
5037
5251
  ref,
5038
5252
  className: cn("text-sm text-muted-foreground", className),
5039
5253
  ...props
5040
5254
  }
5041
5255
  ));
5042
- DialogDescription.displayName = import_radix_ui4.Dialog.Description.displayName;
5043
- var DialogClose = import_radix_ui4.Dialog.Close;
5044
-
5045
- // src/ui/button.tsx
5046
- var React6 = __toESM(require("react"), 1);
5047
- var import_radix_ui5 = require("radix-ui");
5048
- var import_jsx_runtime12 = require("react/jsx-runtime");
5049
- var buttonVariants = cva(
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",
5051
- {
5052
- variants: {
5053
- variant: {
5054
- default: "bg-primary text-primary-foreground hover:opacity-90",
5055
- outline: "border border-border bg-background text-foreground shadow-sm hover:bg-muted/80",
5056
- ghost: "min-w-0 px-3 py-2 text-foreground hover:bg-muted/50"
5057
- },
5058
- size: {
5059
- default: "h-9",
5060
- sm: "h-8 min-w-[64px] px-2 py-1.5 text-sm"
5061
- }
5062
- },
5063
- defaultVariants: {
5064
- variant: "default",
5065
- size: "default"
5066
- }
5067
- }
5068
- );
5069
- var Button = React6.forwardRef(
5070
- ({ className, variant, size, asChild = false, ...props }, ref) => {
5071
- const Comp = asChild ? import_radix_ui5.Slot.Root : "button";
5072
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
5073
- Comp,
5074
- {
5075
- ref,
5076
- "data-slot": "button",
5077
- className: cn(buttonVariants({ variant, size, className })),
5078
- ...props
5079
- }
5080
- );
5081
- }
5082
- );
5083
- Button.displayName = "Button";
5256
+ DialogDescription.displayName = import_radix_ui5.Dialog.Description.displayName;
5257
+ var DialogClose = import_radix_ui5.Dialog.Close;
5084
5258
 
5085
5259
  // src/ui/link-modal/DestinationBreadcrumb.tsx
5086
- var import_jsx_runtime13 = require("react/jsx-runtime");
5260
+ var import_jsx_runtime14 = require("react/jsx-runtime");
5087
5261
  function DestinationBreadcrumb({ pageTitle, sectionLabel }) {
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 })
5262
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex w-full flex-col gap-2", children: [
5263
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-sm font-medium text-foreground", children: "Destination" }),
5264
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-center gap-3", children: [
5265
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-center gap-2", children: [
5266
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(IconFile, { className: "shrink-0 text-foreground", "aria-hidden": true }),
5267
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "text-sm font-medium leading-none text-foreground", children: pageTitle })
5094
5268
  ] }),
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 })
5269
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(IconArrowRight, { className: "shrink-0 text-muted-foreground", "aria-hidden": true }),
5270
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
5271
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(IconSection, { className: "shrink-0 text-foreground", "aria-hidden": true }),
5272
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
5099
5273
  ] })
5100
5274
  ] })
5101
5275
  ] });
5102
5276
  }
5103
5277
 
5104
5278
  // src/ui/link-modal/SectionTreeItem.tsx
5105
- var import_jsx_runtime14 = require("react/jsx-runtime");
5279
+ var import_jsx_runtime15 = require("react/jsx-runtime");
5106
5280
  function SectionTreeItem({ section, onSelect, selected }) {
5107
5281
  const interactive = Boolean(onSelect);
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)(
5282
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex h-9 w-full items-end pl-3", children: [
5283
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5110
5284
  "div",
5111
5285
  {
5112
5286
  className: "mr-[-1px] h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
5113
5287
  "aria-hidden": true
5114
5288
  }
5115
5289
  ),
5116
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
5290
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
5117
5291
  "div",
5118
5292
  {
5119
5293
  role: interactive ? "button" : void 0,
@@ -5131,8 +5305,8 @@ function SectionTreeItem({ section, onSelect, selected }) {
5131
5305
  interactive && selected && "border-primary"
5132
5306
  ),
5133
5307
  children: [
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 })
5308
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(IconSection, { className: "shrink-0 text-foreground", "aria-hidden": true }),
5309
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
5136
5310
  ]
5137
5311
  }
5138
5312
  )
@@ -5140,11 +5314,11 @@ function SectionTreeItem({ section, onSelect, selected }) {
5140
5314
  }
5141
5315
  function SectionPickerList({ sections, onSelect }) {
5142
5316
  if (sections.length === 0) {
5143
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." });
5317
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." });
5144
5318
  }
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))
5319
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-col gap-1", children: [
5320
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-sm text-muted-foreground", children: "Pick a section this link should scroll to." }),
5321
+ sections.map((section) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SectionTreeItem, { section, onSelect }, section.id))
5148
5322
  ] });
5149
5323
  }
5150
5324
 
@@ -5152,11 +5326,11 @@ function SectionPickerList({ sections, onSelect }) {
5152
5326
  var import_react4 = require("react");
5153
5327
 
5154
5328
  // src/ui/input.tsx
5155
- var React7 = __toESM(require("react"), 1);
5156
- var import_jsx_runtime15 = require("react/jsx-runtime");
5157
- var Input = React7.forwardRef(
5329
+ var React8 = __toESM(require("react"), 1);
5330
+ var import_jsx_runtime16 = require("react/jsx-runtime");
5331
+ var Input = React8.forwardRef(
5158
5332
  ({ className, type, ...props }, ref) => {
5159
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5333
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5160
5334
  "input",
5161
5335
  {
5162
5336
  type,
@@ -5175,9 +5349,9 @@ Input.displayName = "Input";
5175
5349
 
5176
5350
  // src/ui/label.tsx
5177
5351
  var import_radix_ui6 = require("radix-ui");
5178
- var import_jsx_runtime16 = require("react/jsx-runtime");
5352
+ var import_jsx_runtime17 = require("react/jsx-runtime");
5179
5353
  function Label({ className, ...props }) {
5180
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
5354
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5181
5355
  import_radix_ui6.Label.Root,
5182
5356
  {
5183
5357
  "data-slot": "label",
@@ -5188,9 +5362,9 @@ function Label({ className, ...props }) {
5188
5362
  }
5189
5363
 
5190
5364
  // src/ui/link-modal/UrlOrPageInput.tsx
5191
- var import_jsx_runtime17 = require("react/jsx-runtime");
5365
+ var import_jsx_runtime18 = require("react/jsx-runtime");
5192
5366
  function FieldChevron({ onClick }) {
5193
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5367
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5194
5368
  "button",
5195
5369
  {
5196
5370
  type: "button",
@@ -5198,7 +5372,7 @@ function FieldChevron({ onClick }) {
5198
5372
  onClick,
5199
5373
  "aria-label": "Open page list",
5200
5374
  tabIndex: -1,
5201
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconChevronDown, {})
5375
+ children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(IconChevronDown, {})
5202
5376
  }
5203
5377
  );
5204
5378
  }
@@ -5237,12 +5411,12 @@ function UrlOrPageInput({
5237
5411
  "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]",
5238
5412
  urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
5239
5413
  );
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)(
5414
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex w-full flex-col gap-2 p-0", children: [
5415
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
5416
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "relative w-full", children: [
5417
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
5418
+ selectedPage ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(IconFile, { className: "text-foreground", "aria-hidden": true }) }) : null,
5419
+ readOnly ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "min-w-0 flex-1 truncate text-sm leading-5 text-foreground", children: selectedPage?.title ?? value }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5246
5420
  Input,
5247
5421
  {
5248
5422
  ref: inputRef,
@@ -5261,7 +5435,7 @@ function UrlOrPageInput({
5261
5435
  )
5262
5436
  }
5263
5437
  ),
5264
- selectedPage && !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5438
+ selectedPage && !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5265
5439
  "button",
5266
5440
  {
5267
5441
  type: "button",
@@ -5269,26 +5443,26 @@ function UrlOrPageInput({
5269
5443
  onMouseDown: clearSelection,
5270
5444
  "aria-label": "Clear selected page",
5271
5445
  tabIndex: -1,
5272
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(IconX, { "aria-hidden": true })
5446
+ children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(IconX, { "aria-hidden": true })
5273
5447
  }
5274
5448
  ) : null,
5275
- !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(FieldChevron, { onClick: toggleDropdown }) : null
5449
+ !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(FieldChevron, { onClick: toggleDropdown }) : null
5276
5450
  ] }),
5277
- dropdownOpen && !readOnly && filteredPages.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5451
+ dropdownOpen && !readOnly && filteredPages.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5278
5452
  "div",
5279
5453
  {
5280
5454
  "data-ohw-link-page-dropdown": "",
5281
5455
  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",
5282
5456
  onMouseDown: (e) => e.preventDefault(),
5283
- children: filteredPages.map((page) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
5457
+ children: filteredPages.map((page) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
5284
5458
  "button",
5285
5459
  {
5286
5460
  type: "button",
5287
5461
  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",
5288
5462
  onClick: () => onPageSelect(page),
5289
5463
  children: [
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 })
5464
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(IconFile, { className: "shrink-0", "aria-hidden": true }),
5465
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "truncate", children: page.title })
5292
5466
  ]
5293
5467
  },
5294
5468
  page.path
@@ -5296,7 +5470,7 @@ function UrlOrPageInput({
5296
5470
  }
5297
5471
  ) : null
5298
5472
  ] }),
5299
- urlError ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "text-sm font-medium text-destructive", children: urlError }) : null
5473
+ urlError ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "text-sm font-medium text-destructive", children: urlError }) : null
5300
5474
  ] });
5301
5475
  }
5302
5476
 
@@ -5464,7 +5638,7 @@ function useLinkModalState({
5464
5638
  }
5465
5639
 
5466
5640
  // src/ui/link-modal/LinkEditorPanel.tsx
5467
- var import_jsx_runtime18 = require("react/jsx-runtime");
5641
+ var import_jsx_runtime19 = require("react/jsx-runtime");
5468
5642
  function LinkEditorPanel({
5469
5643
  open = true,
5470
5644
  mode = "create",
@@ -5488,25 +5662,25 @@ function LinkEditorPanel({
5488
5662
  onSubmit
5489
5663
  });
5490
5664
  const isCancel = state.secondaryLabel === "Cancel";
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)(
5665
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
5666
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DialogClose, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5493
5667
  "button",
5494
5668
  {
5495
5669
  type: "button",
5496
5670
  className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
5497
5671
  "aria-label": "Close",
5498
- children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(IconX, { "aria-hidden": true })
5672
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(IconX, { "aria-hidden": true })
5499
5673
  }
5500
5674
  ) }),
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)(
5675
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DialogHeader, { className: "w-full gap-1.5 p-6 pr-12", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DialogTitle, { className: "m-0 w-full break-words", children: state.title }) }),
5676
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
5677
+ state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5504
5678
  DestinationBreadcrumb,
5505
5679
  {
5506
5680
  pageTitle: state.selectedPage.title,
5507
5681
  sectionLabel: state.selectedSection.label
5508
5682
  }
5509
- ) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5683
+ ) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5510
5684
  UrlOrPageInput,
5511
5685
  {
5512
5686
  value: state.searchValue,
@@ -5519,18 +5693,18 @@ function LinkEditorPanel({
5519
5693
  urlError: state.urlError
5520
5694
  }
5521
5695
  ),
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." })
5696
+ state.showChooseSection ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex flex-col justify-center gap-2", children: [
5697
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Button, { type: "button", variant: "outline", className: "w-fit cursor-pointer", size: "sm", onClick: state.handleChooseSection, children: "Choose a section" }),
5698
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
5699
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(IconInfo, { className: "shrink-0", "aria-hidden": true }),
5700
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: "Pick a section this link should scroll to." })
5527
5701
  ] })
5528
5702
  ] }) : 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
5703
+ state.showSectionPicker ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(SectionPickerList, { sections: state.activeSections, onSelect: state.handleSectionSelect }) : null,
5704
+ state.showSectionRow && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
5531
5705
  ] }),
5532
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(DialogFooter, { className: "w-full px-6 pb-6", children: [
5533
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5706
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(DialogFooter, { className: "w-full px-6 pb-6", children: [
5707
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5534
5708
  Button,
5535
5709
  {
5536
5710
  type: "button",
@@ -5545,7 +5719,7 @@ function LinkEditorPanel({
5545
5719
  children: state.secondaryLabel
5546
5720
  }
5547
5721
  ),
5548
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5722
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5549
5723
  Button,
5550
5724
  {
5551
5725
  type: "button",
@@ -5564,7 +5738,7 @@ function LinkEditorPanel({
5564
5738
  }
5565
5739
 
5566
5740
  // src/ui/link-modal/LinkPopover.tsx
5567
- var import_jsx_runtime19 = require("react/jsx-runtime");
5741
+ var import_jsx_runtime20 = require("react/jsx-runtime");
5568
5742
  function LinkPopover({
5569
5743
  open = true,
5570
5744
  panelRef,
@@ -5572,14 +5746,14 @@ function LinkPopover({
5572
5746
  onClose,
5573
5747
  ...editorProps
5574
5748
  }) {
5575
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5749
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5576
5750
  Dialog2,
5577
5751
  {
5578
5752
  open,
5579
5753
  onOpenChange: (next) => {
5580
5754
  if (!next) onClose?.();
5581
5755
  },
5582
- children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5756
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
5583
5757
  DialogContent,
5584
5758
  {
5585
5759
  ref: panelRef,
@@ -5589,7 +5763,7 @@ function LinkPopover({
5589
5763
  "data-ohw-bridge": "",
5590
5764
  showCloseButton: false,
5591
5765
  className: "gap-0 p-0 w-full md:w-md pointer-events-auto",
5592
- children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(LinkEditorPanel, { ...editorProps, open, onClose })
5766
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(LinkEditorPanel, { ...editorProps, open, onClose })
5593
5767
  }
5594
5768
  )
5595
5769
  }
@@ -5655,7 +5829,7 @@ function shouldUseDevFixtures() {
5655
5829
  }
5656
5830
 
5657
5831
  // src/ui/badge.tsx
5658
- var import_jsx_runtime20 = require("react/jsx-runtime");
5832
+ var import_jsx_runtime21 = require("react/jsx-runtime");
5659
5833
  var badgeVariants = cva(
5660
5834
  "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",
5661
5835
  {
@@ -5673,12 +5847,12 @@ var badgeVariants = cva(
5673
5847
  }
5674
5848
  );
5675
5849
  function Badge({ className, variant, ...props }) {
5676
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: cn(badgeVariants({ variant }), className), ...props });
5850
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: cn(badgeVariants({ variant }), className), ...props });
5677
5851
  }
5678
5852
 
5679
5853
  // src/OhhwellsBridge.tsx
5680
- var import_lucide_react3 = require("lucide-react");
5681
- var import_jsx_runtime21 = require("react/jsx-runtime");
5854
+ var import_lucide_react4 = require("lucide-react");
5855
+ var import_jsx_runtime22 = require("react/jsx-runtime");
5682
5856
  var PRIMARY2 = "#0885FE";
5683
5857
  var IMAGE_FADE_MS = 300;
5684
5858
  function runOpacityFade(el, onDone) {
@@ -5852,7 +6026,7 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
5852
6026
  const root = (0, import_client.createRoot)(container);
5853
6027
  (0, import_react_dom.flushSync)(() => {
5854
6028
  root.render(
5855
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6029
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
5856
6030
  SchedulingWidget,
5857
6031
  {
5858
6032
  notifyOnConnect,
@@ -5925,6 +6099,9 @@ function collectEditableNodes() {
5925
6099
  const url = raw.replace(/^url\(['"]?/, "").replace(/['"]?\)$/, "");
5926
6100
  return { key: el.dataset.ohwKey ?? "", type: "bg-image", text: url };
5927
6101
  }
6102
+ if (el.dataset.ohwEditable === "video") {
6103
+ return { key: el.dataset.ohwKey ?? "", type: "video", text: getVideoEl(el)?.src ?? "" };
6104
+ }
5928
6105
  if (el.dataset.ohwEditable === "link") {
5929
6106
  return { key: el.dataset.ohwKey ?? "", type: "link", text: getLinkHref(el) };
5930
6107
  }
@@ -5939,8 +6116,62 @@ function collectEditableNodes() {
5939
6116
  if (!key) return;
5940
6117
  nodes.push({ key, type: "link", text: getLinkHref(el) });
5941
6118
  });
6119
+ document.querySelectorAll('[data-ohw-editable="video"]').forEach((el) => {
6120
+ const key = el.dataset.ohwKey ?? "";
6121
+ const video = getVideoEl(el);
6122
+ if (!key || !video) return;
6123
+ nodes.push({ key: `${key}${VIDEO_AUTOPLAY_SUFFIX}`, type: "video-setting", text: String(video.autoplay) });
6124
+ nodes.push({ key: `${key}${VIDEO_MUTED_SUFFIX}`, type: "video-setting", text: String(video.muted) });
6125
+ });
5942
6126
  return nodes;
5943
6127
  }
6128
+ function isMediaEditable(el) {
6129
+ const t = el.dataset.ohwEditable;
6130
+ return t === "image" || t === "bg-image" || t === "video";
6131
+ }
6132
+ var MEDIA_SELECTOR = '[data-ohw-editable="image"], [data-ohw-editable="bg-image"], [data-ohw-editable="video"]';
6133
+ var NON_MEDIA_SELECTOR = '[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"])';
6134
+ function getVideoEl(el) {
6135
+ return el instanceof HTMLVideoElement ? el : el.querySelector("video");
6136
+ }
6137
+ var VIDEO_AUTOPLAY_SUFFIX = "__ohw_autoplay";
6138
+ var VIDEO_MUTED_SUFFIX = "__ohw_muted";
6139
+ function isBackgroundVideo(video) {
6140
+ return video.autoplay && video.muted;
6141
+ }
6142
+ function syncVideoPlayback(video) {
6143
+ const background = isBackgroundVideo(video);
6144
+ video.controls = !background;
6145
+ if (video.autoplay) void video.play().catch(() => {
6146
+ });
6147
+ else video.pause();
6148
+ }
6149
+ function applyVideoSrc(video, url) {
6150
+ const { autoplay, muted } = video;
6151
+ video.src = url;
6152
+ video.loop = true;
6153
+ video.playsInline = true;
6154
+ video.autoplay = autoplay;
6155
+ video.muted = muted;
6156
+ video.load();
6157
+ syncVideoPlayback(video);
6158
+ }
6159
+ function applyVideoSettingNode(key, val) {
6160
+ const isAutoplay = key.endsWith(VIDEO_AUTOPLAY_SUFFIX);
6161
+ const isMuted = key.endsWith(VIDEO_MUTED_SUFFIX);
6162
+ if (!isAutoplay && !isMuted) return false;
6163
+ const suffixLen = (isAutoplay ? VIDEO_AUTOPLAY_SUFFIX : VIDEO_MUTED_SUFFIX).length;
6164
+ const baseKey = key.slice(0, key.length - suffixLen);
6165
+ const on = val === "true";
6166
+ document.querySelectorAll(`[data-ohw-key="${baseKey}"]`).forEach((el) => {
6167
+ const video = getVideoEl(el);
6168
+ if (!video) return;
6169
+ if (isAutoplay) video.autoplay = on;
6170
+ else video.muted = on;
6171
+ syncVideoPlayback(video);
6172
+ });
6173
+ return true;
6174
+ }
5944
6175
  function applyLinkByKey(key, val) {
5945
6176
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
5946
6177
  if (el.dataset.ohwEditable === "link") applyLinkHref(el, val);
@@ -6240,7 +6471,7 @@ function EditGlowChrome({
6240
6471
  dragDisabled = false
6241
6472
  }) {
6242
6473
  const GAP = 6;
6243
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
6474
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
6244
6475
  "div",
6245
6476
  {
6246
6477
  ref: elRef,
@@ -6255,7 +6486,7 @@ function EditGlowChrome({
6255
6486
  zIndex: 2147483646
6256
6487
  },
6257
6488
  children: [
6258
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6489
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
6259
6490
  "div",
6260
6491
  {
6261
6492
  style: {
@@ -6268,7 +6499,7 @@ function EditGlowChrome({
6268
6499
  }
6269
6500
  }
6270
6501
  ),
6271
- reorderHrefKey && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6502
+ reorderHrefKey && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
6272
6503
  "div",
6273
6504
  {
6274
6505
  "data-ohw-drag-handle-container": "",
@@ -6280,7 +6511,7 @@ function EditGlowChrome({
6280
6511
  transform: "translate(calc(-100% - 7px), -50%)",
6281
6512
  pointerEvents: dragDisabled ? "none" : "auto"
6282
6513
  },
6283
- children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6514
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
6284
6515
  DragHandle,
6285
6516
  {
6286
6517
  "aria-label": `Reorder ${reorderHrefKey}`,
@@ -6384,7 +6615,7 @@ function FloatingToolbar({
6384
6615
  onEditLink
6385
6616
  }) {
6386
6617
  const { top, left, transform } = calcToolbarPos(rect, parentScroll, 330);
6387
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6618
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
6388
6619
  "div",
6389
6620
  {
6390
6621
  ref: elRef,
@@ -6405,12 +6636,12 @@ function FloatingToolbar({
6405
6636
  fontFamily: "sans-serif",
6406
6637
  pointerEvents: "auto"
6407
6638
  },
6408
- children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(CustomToolbar, { children: [
6409
- TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react6.default.Fragment, { children: [
6410
- gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(CustomToolbarDivider, {}),
6639
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(CustomToolbar, { children: [
6640
+ TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_react6.default.Fragment, { children: [
6641
+ gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(CustomToolbarDivider, {}),
6411
6642
  btns.map((btn) => {
6412
6643
  const isActive = activeCommands.has(btn.cmd);
6413
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6644
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
6414
6645
  CustomToolbarButton,
6415
6646
  {
6416
6647
  title: btn.title,
@@ -6419,7 +6650,7 @@ function FloatingToolbar({
6419
6650
  e.preventDefault();
6420
6651
  onCommand(btn.cmd);
6421
6652
  },
6422
- children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6653
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
6423
6654
  "svg",
6424
6655
  {
6425
6656
  width: "16",
@@ -6440,7 +6671,7 @@ function FloatingToolbar({
6440
6671
  );
6441
6672
  })
6442
6673
  ] }, gi)),
6443
- showEditLink ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6674
+ showEditLink ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
6444
6675
  CustomToolbarButton,
6445
6676
  {
6446
6677
  type: "button",
@@ -6454,7 +6685,7 @@ function FloatingToolbar({
6454
6685
  e.preventDefault();
6455
6686
  e.stopPropagation();
6456
6687
  },
6457
- children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react3.Link, { className: "size-4 shrink-0", "aria-hidden": true })
6688
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react4.Link, { className: "size-4 shrink-0", "aria-hidden": true })
6458
6689
  }
6459
6690
  ) : null
6460
6691
  ] })
@@ -6471,7 +6702,7 @@ function StateToggle({
6471
6702
  states,
6472
6703
  onStateChange
6473
6704
  }) {
6474
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6705
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
6475
6706
  ToggleGroup,
6476
6707
  {
6477
6708
  "data-ohw-state-toggle": "",
@@ -6485,7 +6716,7 @@ function StateToggle({
6485
6716
  left: rect.right - 8,
6486
6717
  transform: "translateX(-100%)"
6487
6718
  },
6488
- children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
6719
+ children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
6489
6720
  }
6490
6721
  );
6491
6722
  }
@@ -6521,7 +6752,10 @@ function OhhwellsBridge() {
6521
6752
  const stylesheet = Object.assign(document.createElement("link"), {
6522
6753
  id: figtreeFontId,
6523
6754
  rel: "stylesheet",
6524
- href: "https://fonts.googleapis.com/css2?family=Figtree:ital,wght@0,300..900;1,300..900&display=swap"
6755
+ // Inter is loaded alongside Figtree for the media overlay's Replace button. The bridge
6756
+ // renders inside the customer's document, so it cannot assume any font is present — an
6757
+ // unloaded family would silently fall back to whatever the template happens to use.
6758
+ href: "https://fonts.googleapis.com/css2?family=Figtree:ital,wght@0,300..900;1,300..900&family=Inter:wght@400;500;600&display=swap"
6525
6759
  });
6526
6760
  document.head.append(preconnect1, preconnect2, stylesheet);
6527
6761
  }
@@ -6561,6 +6795,8 @@ function OhhwellsBridge() {
6561
6795
  const glowElRef = (0, import_react6.useRef)(null);
6562
6796
  const hoveredImageRef = (0, import_react6.useRef)(null);
6563
6797
  const hoveredImageHasTextOverlapRef = (0, import_react6.useRef)(false);
6798
+ const [mediaHover, setMediaHover] = (0, import_react6.useState)(null);
6799
+ const [uploadingRects, setUploadingRects] = (0, import_react6.useState)({});
6564
6800
  const hoveredGapRef = (0, import_react6.useRef)(null);
6565
6801
  const imageUnhoverTimerRef = (0, import_react6.useRef)(null);
6566
6802
  const imageShowTimerRef = (0, import_react6.useRef)(null);
@@ -6642,7 +6878,7 @@ function OhhwellsBridge() {
6642
6878
  }
6643
6879
  hoveredGapRef.current = null;
6644
6880
  setSectionGap(null);
6645
- postToParent({ type: "ow:image-unhover" });
6881
+ setMediaHover(null);
6646
6882
  postToParent({ type: "ow:link-modal-lock", locked: true });
6647
6883
  const html = document.documentElement;
6648
6884
  const body = document.body;
@@ -6886,7 +7122,7 @@ function OhhwellsBridge() {
6886
7122
  deactivate();
6887
7123
  if (hoveredImageRef.current) {
6888
7124
  hoveredImageRef.current = null;
6889
- postToParentRef.current({ type: "ow:image-unhover" });
7125
+ setMediaHover(null);
6890
7126
  }
6891
7127
  setToolbarVariant("rich-text");
6892
7128
  siblingHintElRef.current = null;
@@ -6929,6 +7165,7 @@ function OhhwellsBridge() {
6929
7165
  const imageLoads = [];
6930
7166
  for (const [key, val] of Object.entries(content)) {
6931
7167
  if (key === "__ohw_sections") continue;
7168
+ if (applyVideoSettingNode(key, val)) continue;
6932
7169
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
6933
7170
  if (el.dataset.ohwEditable === "image") {
6934
7171
  const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
@@ -6942,6 +7179,15 @@ function OhhwellsBridge() {
6942
7179
  } else if (el.dataset.ohwEditable === "bg-image") {
6943
7180
  const next = `url('${val}')`;
6944
7181
  if (el.style.backgroundImage !== next) el.style.backgroundImage = next;
7182
+ } else if (el.dataset.ohwEditable === "video") {
7183
+ const video = getVideoEl(el);
7184
+ if (video && video.src !== val) {
7185
+ applyVideoSrc(video, val);
7186
+ imageLoads.push(new Promise((resolve) => {
7187
+ video.onloadeddata = () => resolve();
7188
+ video.onerror = () => resolve();
7189
+ }));
7190
+ }
6945
7191
  } else if (el.dataset.ohwEditable === "link") {
6946
7192
  applyLinkHref(el, val);
6947
7193
  } else if (el.innerHTML !== val) {
@@ -6990,6 +7236,7 @@ function OhhwellsBridge() {
6990
7236
  try {
6991
7237
  for (const [key, val] of Object.entries(content)) {
6992
7238
  if (key === "__ohw_sections") continue;
7239
+ if (applyVideoSettingNode(key, val)) continue;
6993
7240
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
6994
7241
  if (el.dataset.ohwEditable === "image") {
6995
7242
  const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
@@ -6997,6 +7244,9 @@ function OhhwellsBridge() {
6997
7244
  } else if (el.dataset.ohwEditable === "bg-image") {
6998
7245
  const next = `url('${val}')`;
6999
7246
  if (el.style.backgroundImage !== next) el.style.backgroundImage = next;
7247
+ } else if (el.dataset.ohwEditable === "video") {
7248
+ const video = getVideoEl(el);
7249
+ if (video && video.src !== val) applyVideoSrc(video, val);
7000
7250
  } else if (el.dataset.ohwEditable === "link") {
7001
7251
  applyLinkHref(el, val);
7002
7252
  } else if (el.innerHTML !== val) {
@@ -7100,8 +7350,9 @@ function OhhwellsBridge() {
7100
7350
  [data-ohw-editable] {
7101
7351
  display: block;
7102
7352
  }
7103
- [data-ohw-editable]:not([contenteditable]):not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]) { cursor: text !important; }
7353
+ [data-ohw-editable]:not([contenteditable]):not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"]) { cursor: text !important; }
7104
7354
  [data-ohw-editable="image"], [data-ohw-editable="image"] *,
7355
+ [data-ohw-editable="video"], [data-ohw-editable="video"] *,
7105
7356
  [data-ohw-editable="bg-image"], [data-ohw-editable="bg-image"] * { cursor: pointer !important; }
7106
7357
  [data-ohw-editable="link"], [data-ohw-editable="link"] * { cursor: pointer !important; }
7107
7358
  [data-ohw-hovered]:not([contenteditable]):not([data-ohw-href-key]) {
@@ -7168,10 +7419,10 @@ function OhhwellsBridge() {
7168
7419
  });
7169
7420
  return;
7170
7421
  }
7171
- if (editable.dataset.ohwEditable === "image" || editable.dataset.ohwEditable === "bg-image") {
7422
+ if (isMediaEditable(editable)) {
7172
7423
  e.preventDefault();
7173
7424
  e.stopPropagation();
7174
- postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "" });
7425
+ postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "", elementType: editable.dataset.ohwEditable ?? "image" });
7175
7426
  return;
7176
7427
  }
7177
7428
  const hrefCtx = getHrefKeyFromElement(editable);
@@ -7271,7 +7522,7 @@ function OhhwellsBridge() {
7271
7522
  if (!editable) return;
7272
7523
  const selected = selectedElRef.current;
7273
7524
  if (selected && (selected === editable || selected.contains(editable))) return;
7274
- if (editable.dataset.ohwEditable !== "image" && editable.dataset.ohwEditable !== "bg-image" && !editable.hasAttribute("contenteditable")) {
7525
+ if (!isMediaEditable(editable) && !editable.hasAttribute("contenteditable")) {
7275
7526
  const hoverTarget = editable.closest("[data-ohw-href-key]") ?? editable;
7276
7527
  if (hoverTarget.hasAttribute("data-ohw-href-key")) {
7277
7528
  clearHrefKeyHover(hoverTarget);
@@ -7299,7 +7550,7 @@ function OhhwellsBridge() {
7299
7550
  if (!editable) return;
7300
7551
  const related = e.relatedTarget instanceof Element ? e.relatedTarget : null;
7301
7552
  if (related?.closest("[data-ohw-drag-handle-container], [data-ohw-item-interaction]")) return;
7302
- if (editable.dataset.ohwEditable !== "image" && editable.dataset.ohwEditable !== "bg-image") {
7553
+ if (!isMediaEditable(editable)) {
7303
7554
  const hoverTarget = editable.closest("[data-ohw-href-key]") ?? editable;
7304
7555
  if (hoverTarget.hasAttribute("data-ohw-href-key")) {
7305
7556
  if (!related?.closest("[data-ohw-href-key]")) {
@@ -7345,23 +7596,26 @@ function OhhwellsBridge() {
7345
7596
  }
7346
7597
  return { top, left, width: Math.max(0, right - left), height: Math.max(0, bottom - top) };
7347
7598
  };
7348
- const postImageHover = (imgEl, isDragOver = false, forceTextOverlap) => {
7599
+ const showImageHover = (imgEl, isDragOver = false, forceTextOverlap) => {
7349
7600
  const r2 = getVisibleRect(imgEl);
7350
7601
  const hasTextOverlap = forceTextOverlap ?? false;
7351
7602
  hoveredImageHasTextOverlapRef.current = hasTextOverlap;
7352
- postToParentRef.current({
7353
- type: "ow:image-hover",
7603
+ const video = imgEl.dataset.ohwEditable === "video" ? getVideoEl(imgEl) : null;
7604
+ setMediaHover({
7354
7605
  key: imgEl.dataset.ohwKey ?? "",
7355
7606
  rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height },
7607
+ elementType: imgEl.dataset.ohwEditable ?? "image",
7356
7608
  hasTextOverlap,
7357
- ...isDragOver ? { isDragOver: true } : {}
7609
+ isDragOver,
7610
+ ...video ? { videoAutoplay: video.autoplay, videoMuted: video.muted } : {}
7358
7611
  });
7359
7612
  const track = imgEl.closest("[data-ohw-hover-pause]");
7360
7613
  if (track) track.setAttribute("data-ohw-hover-paused", "");
7361
7614
  };
7615
+ const clearImageHover = () => setMediaHover(null);
7362
7616
  const findImageAtPoint = (clientX, clientY, fromParentViewport) => {
7363
7617
  const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
7364
- const images = Array.from(document.querySelectorAll('[data-ohw-editable="image"], [data-ohw-editable="bg-image"]'));
7618
+ const images = Array.from(document.querySelectorAll(MEDIA_SELECTOR));
7365
7619
  const matches = [];
7366
7620
  for (let i = images.length - 1; i >= 0; i--) {
7367
7621
  const el = images[i];
@@ -7377,7 +7631,9 @@ function OhhwellsBridge() {
7377
7631
  if (x >= r2.left && x <= r2.left + r2.width && y >= r2.top && y <= r2.top + r2.height) matches.push(el);
7378
7632
  }
7379
7633
  if (matches.length === 0) return null;
7380
- const imageTypeMatches = matches.filter((el) => el.dataset.ohwEditable === "image");
7634
+ const imageTypeMatches = matches.filter(
7635
+ (el) => el.dataset.ohwEditable === "image" || el.dataset.ohwEditable === "video"
7636
+ );
7381
7637
  const candidatePool = imageTypeMatches.length > 0 ? imageTypeMatches : matches;
7382
7638
  const smallest = candidatePool.reduce((best, el) => {
7383
7639
  const br = getVisibleRect(best);
@@ -7406,7 +7662,7 @@ function OhhwellsBridge() {
7406
7662
  hoveredImageRef.current = null;
7407
7663
  hoveredImageHasTextOverlapRef.current = false;
7408
7664
  resumeAnimTracks();
7409
- postToParentRef.current({ type: "ow:image-unhover" });
7665
+ clearImageHover();
7410
7666
  }
7411
7667
  return;
7412
7668
  }
@@ -7418,21 +7674,22 @@ function OhhwellsBridge() {
7418
7674
  if (hoveredImageRef.current) {
7419
7675
  hoveredImageRef.current = null;
7420
7676
  resumeAnimTracks();
7421
- postToParentRef.current({ type: "ow:image-unhover" });
7677
+ clearImageHover();
7422
7678
  }
7423
7679
  return;
7424
7680
  }
7425
7681
  }
7426
- if (activeElRef.current) {
7682
+ const imgEl = findImageAtPoint(clientX, clientY, fromParentViewport);
7683
+ const activeEl = activeElRef.current;
7684
+ if (activeEl && (!imgEl || imgEl.contains(activeEl))) {
7427
7685
  if (hoveredImageRef.current) {
7428
7686
  hoveredImageRef.current = null;
7429
7687
  hoveredImageHasTextOverlapRef.current = false;
7430
7688
  resumeAnimTracks();
7431
- postToParentRef.current({ type: "ow:image-unhover" });
7689
+ clearImageHover();
7432
7690
  }
7433
7691
  return;
7434
7692
  }
7435
- const imgEl = findImageAtPoint(clientX, clientY, fromParentViewport);
7436
7693
  if (imgEl) {
7437
7694
  const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
7438
7695
  const topEl = document.elementFromPoint(x, y);
@@ -7440,7 +7697,7 @@ function OhhwellsBridge() {
7440
7697
  if (hoveredImageRef.current) {
7441
7698
  hoveredImageRef.current = null;
7442
7699
  resumeAnimTracks();
7443
- postToParentRef.current({ type: "ow:image-unhover" });
7700
+ clearImageHover();
7444
7701
  }
7445
7702
  return;
7446
7703
  }
@@ -7449,13 +7706,13 @@ function OhhwellsBridge() {
7449
7706
  hoveredImageRef.current = null;
7450
7707
  hoveredImageHasTextOverlapRef.current = false;
7451
7708
  resumeAnimTracks();
7452
- postToParentRef.current({ type: "ow:image-unhover" });
7709
+ clearImageHover();
7453
7710
  }
7454
7711
  return;
7455
7712
  }
7456
7713
  const isStateCardImage = !!imgEl.closest("[data-ohw-editable-state]");
7457
7714
  const textEditable = Array.from(
7458
- document.querySelectorAll('[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"])')
7715
+ document.querySelectorAll(NON_MEDIA_SELECTOR)
7459
7716
  ).find((el) => {
7460
7717
  const er = el.getBoundingClientRect();
7461
7718
  return x >= er.left && x <= er.right && y >= er.top && y <= er.bottom;
@@ -7474,14 +7731,14 @@ function OhhwellsBridge() {
7474
7731
  hoveredImageRef.current = null;
7475
7732
  hoveredImageHasTextOverlapRef.current = false;
7476
7733
  resumeAnimTracks();
7477
- postToParentRef.current({ type: "ow:image-unhover" });
7734
+ clearImageHover();
7478
7735
  }
7479
7736
  return;
7480
7737
  }
7481
7738
  if (isStateCardImage) {
7482
7739
  if (imgEl !== hoveredImageRef.current || !hoveredImageHasTextOverlapRef.current) {
7483
7740
  hoveredImageRef.current = imgEl;
7484
- postImageHover(imgEl, isDragOver, true);
7741
+ showImageHover(imgEl, isDragOver, true);
7485
7742
  }
7486
7743
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
7487
7744
  if (textEditable && !isInsideNavigationItem(textEditable)) {
@@ -7493,7 +7750,7 @@ function OhhwellsBridge() {
7493
7750
  hoveredImageRef.current = null;
7494
7751
  hoveredImageHasTextOverlapRef.current = false;
7495
7752
  resumeAnimTracks();
7496
- postToParentRef.current({ type: "ow:image-unhover" });
7753
+ clearImageHover();
7497
7754
  }
7498
7755
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
7499
7756
  if (textEditable && !isInsideNavigationItem(textEditable)) {
@@ -7505,7 +7762,7 @@ function OhhwellsBridge() {
7505
7762
  if (hoveredImageRef.current) {
7506
7763
  hoveredImageRef.current = null;
7507
7764
  resumeAnimTracks();
7508
- postToParentRef.current({ type: "ow:image-unhover" });
7765
+ clearImageHover();
7509
7766
  }
7510
7767
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
7511
7768
  return;
@@ -7513,9 +7770,9 @@ function OhhwellsBridge() {
7513
7770
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
7514
7771
  if (imgEl !== hoveredImageRef.current || hoveredImageHasTextOverlapRef.current) {
7515
7772
  hoveredImageRef.current = imgEl;
7516
- postImageHover(imgEl, isDragOver);
7773
+ showImageHover(imgEl, isDragOver);
7517
7774
  } else if (isDragOver) {
7518
- postImageHover(imgEl, true);
7775
+ showImageHover(imgEl, true);
7519
7776
  }
7520
7777
  } else {
7521
7778
  const inIframeView = clientX >= 0 && clientY >= 0 && clientX <= window.innerWidth && clientY <= window.innerHeight;
@@ -7532,11 +7789,11 @@ function OhhwellsBridge() {
7532
7789
  hoveredImageRef.current = null;
7533
7790
  hoveredImageHasTextOverlapRef.current = false;
7534
7791
  resumeAnimTracks();
7535
- postToParentRef.current({ type: "ow:image-unhover" });
7792
+ clearImageHover();
7536
7793
  }
7537
7794
  const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
7538
7795
  const textEl = Array.from(
7539
- document.querySelectorAll('[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"])')
7796
+ document.querySelectorAll(NON_MEDIA_SELECTOR)
7540
7797
  ).find((el) => {
7541
7798
  const er = el.getBoundingClientRect();
7542
7799
  return x >= er.left && x <= er.right && y >= er.top && y <= er.bottom;
@@ -7645,7 +7902,7 @@ function OhhwellsBridge() {
7645
7902
  if (hoveredImageRef.current !== el) {
7646
7903
  hoveredImageRef.current = el;
7647
7904
  const isStateCard = !!el.closest("[data-ohw-editable-state]");
7648
- postImageHover(el, true, isStateCard ? true : void 0);
7905
+ showImageHover(el, true, isStateCard ? true : void 0);
7649
7906
  }
7650
7907
  };
7651
7908
  const handleDragLeave = (e) => {
@@ -7653,7 +7910,7 @@ function OhhwellsBridge() {
7653
7910
  if (imgEl) return;
7654
7911
  hoveredImageRef.current = null;
7655
7912
  resumeAnimTracks();
7656
- postToParentRef.current({ type: "ow:image-unhover" });
7913
+ clearImageHover();
7657
7914
  };
7658
7915
  const handleDrop = (e) => {
7659
7916
  e.preventDefault();
@@ -7661,7 +7918,9 @@ function OhhwellsBridge() {
7661
7918
  if (!el) return;
7662
7919
  const file = e.dataTransfer?.files?.[0];
7663
7920
  if (file) {
7664
- if (file.type.startsWith("image/")) {
7921
+ const wantsVideo = el.dataset.ohwEditable === "video";
7922
+ const accepted = wantsVideo ? file.type.startsWith("video/") : file.type.startsWith("image/");
7923
+ if (accepted) {
7665
7924
  const key = el.dataset.ohwKey ?? "";
7666
7925
  const { name, type: mimeType } = file;
7667
7926
  const r2 = el.getBoundingClientRect();
@@ -7675,7 +7934,7 @@ function OhhwellsBridge() {
7675
7934
  }
7676
7935
  hoveredImageRef.current = null;
7677
7936
  resumeAnimTracks();
7678
- postToParentRef.current({ type: "ow:image-unhover" });
7937
+ clearImageHover();
7679
7938
  };
7680
7939
  const handleImageUrl = (e) => {
7681
7940
  if (e.data?.type !== "ow:image-url") return;
@@ -7693,7 +7952,11 @@ function OhhwellsBridge() {
7693
7952
  }
7694
7953
  });
7695
7954
  hoveredImageRef.current = null;
7696
- postToParentRef.current({ type: "ow:image-loaded", key });
7955
+ setUploadingRects((prev) => {
7956
+ const entry = prev[key];
7957
+ if (!entry || entry.fadingOut) return prev;
7958
+ return { ...prev, [key]: { ...entry, fadingOut: true } };
7959
+ });
7697
7960
  };
7698
7961
  let found = false;
7699
7962
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -7728,6 +7991,19 @@ function OhhwellsBridge() {
7728
7991
  requestAnimationFrame(() => onReady());
7729
7992
  }
7730
7993
  }
7994
+ } else if (el.dataset.ohwEditable === "video") {
7995
+ const video = getVideoEl(el);
7996
+ if (video) {
7997
+ found = true;
7998
+ const onReady = () => {
7999
+ video.onloadeddata = null;
8000
+ video.onerror = null;
8001
+ notify();
8002
+ };
8003
+ video.onloadeddata = onReady;
8004
+ video.onerror = onReady;
8005
+ applyVideoSrc(video, url);
8006
+ }
7731
8007
  }
7732
8008
  });
7733
8009
  if (!found) notify();
@@ -7794,12 +8070,16 @@ function OhhwellsBridge() {
7794
8070
  sectionsJson = val;
7795
8071
  continue;
7796
8072
  }
8073
+ if (applyVideoSettingNode(key, val)) continue;
7797
8074
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
7798
8075
  if (el.dataset.ohwEditable === "image") {
7799
8076
  const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
7800
8077
  if (img) img.src = val;
7801
8078
  } else if (el.dataset.ohwEditable === "bg-image") {
7802
8079
  el.style.backgroundImage = `url('${val}')`;
8080
+ } else if (el.dataset.ohwEditable === "video") {
8081
+ const video = getVideoEl(el);
8082
+ if (video && video.src !== val) applyVideoSrc(video, val);
7803
8083
  } else if (el.dataset.ohwEditable === "link") {
7804
8084
  applyLinkHref(el, val);
7805
8085
  } else {
@@ -7912,12 +8192,9 @@ function OhhwellsBridge() {
7912
8192
  if (hoveredImageRef.current) {
7913
8193
  const el = hoveredImageRef.current;
7914
8194
  const r2 = el.getBoundingClientRect();
7915
- postToParentRef.current({
7916
- type: "ow:image-hover",
7917
- key: el.dataset.ohwKey ?? "",
7918
- rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height },
7919
- hasTextOverlap: hoveredImageHasTextOverlapRef.current
7920
- });
8195
+ setMediaHover(
8196
+ (prev) => prev ? { ...prev, rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height } } : prev
8197
+ );
7921
8198
  }
7922
8199
  };
7923
8200
  const handleSave = (e) => {
@@ -8006,19 +8283,39 @@ function OhhwellsBridge() {
8006
8283
  refreshActiveCommandsRef.current = handleSelectionChange;
8007
8284
  const handleDocMouseLeave = () => {
8008
8285
  hoveredImageRef.current = null;
8286
+ setMediaHover(null);
8009
8287
  document.querySelectorAll("[data-ohw-state-hovered]").forEach((el) => el.removeAttribute("data-ohw-state-hovered"));
8010
8288
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
8011
8289
  activeStateElRef.current = null;
8012
8290
  setToggleState(null);
8013
8291
  };
8014
- const handleAnimLock = (e) => {
8015
- if (e.data?.type !== "ow:anim-lock") return;
8016
- const { key } = e.data;
8292
+ const handleImageUploading = (e) => {
8293
+ if (e.data?.type !== "ow:image-uploading") return;
8294
+ const { key, uploading } = e.data;
8295
+ setUploadingRects((prev) => {
8296
+ if (!uploading) {
8297
+ if (!(key in prev)) return prev;
8298
+ const next = { ...prev };
8299
+ delete next[key];
8300
+ return next;
8301
+ }
8302
+ const el = document.querySelector(`[data-ohw-key="${key}"]`);
8303
+ if (!el) return prev;
8304
+ const r2 = getVisibleRect(el);
8305
+ return {
8306
+ ...prev,
8307
+ [key]: { rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height } }
8308
+ };
8309
+ });
8017
8310
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
8018
8311
  const track = el.closest("[data-ohw-hover-pause]");
8019
- if (track) {
8312
+ if (!track) return;
8313
+ if (uploading) {
8020
8314
  uploadLockedTracks.add(track);
8021
8315
  track.setAttribute("data-ohw-hover-paused", "");
8316
+ } else {
8317
+ uploadLockedTracks.delete(track);
8318
+ track.removeAttribute("data-ohw-hover-paused");
8022
8319
  }
8023
8320
  });
8024
8321
  };
@@ -8060,7 +8357,7 @@ function OhhwellsBridge() {
8060
8357
  if (e.data?.type !== "ow:click-at") return;
8061
8358
  const { clientX, clientY } = e.data;
8062
8359
  const allImages = Array.from(
8063
- document.querySelectorAll('[data-ohw-editable="image"], [data-ohw-editable="bg-image"]')
8360
+ document.querySelectorAll(MEDIA_SELECTOR)
8064
8361
  ).filter((el) => !!el.closest("[data-ohw-editable-state]"));
8065
8362
  const stateCardImage = allImages.find((el) => {
8066
8363
  const ownerCard = el.closest("[data-ohw-editable-state]");
@@ -8075,13 +8372,11 @@ function OhhwellsBridge() {
8075
8372
  return clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom;
8076
8373
  });
8077
8374
  if (stateCardImage) {
8078
- postToParentRef.current({ type: "ow:image-pick", key: stateCardImage.dataset.ohwKey ?? "" });
8375
+ postToParentRef.current({ type: "ow:image-pick", key: stateCardImage.dataset.ohwKey ?? "", elementType: stateCardImage.dataset.ohwEditable ?? "image" });
8079
8376
  return;
8080
8377
  }
8081
8378
  const textEditable = Array.from(
8082
- document.querySelectorAll(
8083
- '[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"])'
8084
- )
8379
+ document.querySelectorAll(NON_MEDIA_SELECTOR)
8085
8380
  ).find((el) => {
8086
8381
  const r2 = el.getBoundingClientRect();
8087
8382
  return clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom;
@@ -8109,7 +8404,7 @@ function OhhwellsBridge() {
8109
8404
  window.addEventListener("message", handleClearSchedulingWidget);
8110
8405
  window.addEventListener("message", handleRemoveSchedulingSection);
8111
8406
  window.addEventListener("message", handleImageUrl);
8112
- window.addEventListener("message", handleAnimLock);
8407
+ window.addEventListener("message", handleImageUploading);
8113
8408
  window.addEventListener("message", handleCanvasHeight);
8114
8409
  window.addEventListener("message", handleParentScroll);
8115
8410
  window.addEventListener("message", handlePointerSync);
@@ -8156,7 +8451,7 @@ function OhhwellsBridge() {
8156
8451
  window.removeEventListener("message", handleClearSchedulingWidget);
8157
8452
  window.removeEventListener("message", handleRemoveSchedulingSection);
8158
8453
  window.removeEventListener("message", handleImageUrl);
8159
- window.removeEventListener("message", handleAnimLock);
8454
+ window.removeEventListener("message", handleImageUploading);
8160
8455
  window.removeEventListener("message", handleCanvasHeight);
8161
8456
  window.removeEventListener("message", handleParentScroll);
8162
8457
  window.removeEventListener("resize", handleViewportResize);
@@ -8276,12 +8571,68 @@ function OhhwellsBridge() {
8276
8571
  const showEditLink = toolbarShowEditLink;
8277
8572
  const currentSections = sectionsByPath[pathname] ?? [];
8278
8573
  linkPopoverOpenRef.current = linkPopover !== null;
8574
+ const handleMediaReplace = (0, import_react6.useCallback)(
8575
+ (key) => {
8576
+ postToParent({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
8577
+ },
8578
+ [postToParent, mediaHover?.elementType]
8579
+ );
8580
+ const handleVideoSettingsChange = (0, import_react6.useCallback)(
8581
+ (key, settings) => {
8582
+ document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
8583
+ const video = getVideoEl(el);
8584
+ if (!video) return;
8585
+ if (typeof settings.autoplay === "boolean") video.autoplay = settings.autoplay;
8586
+ if (typeof settings.muted === "boolean") video.muted = settings.muted;
8587
+ syncVideoPlayback(video);
8588
+ postToParent({
8589
+ type: "ow:change",
8590
+ nodes: [
8591
+ { key: `${key}${VIDEO_AUTOPLAY_SUFFIX}`, text: String(video.autoplay) },
8592
+ { key: `${key}${VIDEO_MUTED_SUFFIX}`, text: String(video.muted) }
8593
+ ]
8594
+ });
8595
+ setMediaHover(
8596
+ (prev) => prev && prev.key === key ? { ...prev, videoAutoplay: video.autoplay, videoMuted: video.muted } : prev
8597
+ );
8598
+ });
8599
+ },
8600
+ [postToParent]
8601
+ );
8602
+ const handleMediaFadeOutComplete = (0, import_react6.useCallback)((key) => {
8603
+ setUploadingRects((prev) => {
8604
+ if (!(key in prev)) return prev;
8605
+ const next = { ...prev };
8606
+ delete next[key];
8607
+ return next;
8608
+ });
8609
+ }, []);
8279
8610
  return bridgeRoot ? (0, import_react_dom2.createPortal)(
8280
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
8281
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
8282
- siblingHintRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
8283
- hoveredItemRect && !siblingHintRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
8284
- toolbarRect && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8611
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
8612
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
8613
+ Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8614
+ MediaOverlay,
8615
+ {
8616
+ hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
8617
+ isUploading: true,
8618
+ fadingOut,
8619
+ onFadeOutComplete: handleMediaFadeOutComplete,
8620
+ onReplace: handleMediaReplace
8621
+ },
8622
+ `uploading-${key}`
8623
+ )),
8624
+ mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8625
+ MediaOverlay,
8626
+ {
8627
+ hover: mediaHover,
8628
+ isUploading: false,
8629
+ onReplace: handleMediaReplace,
8630
+ onVideoSettingsChange: handleVideoSettingsChange
8631
+ }
8632
+ ),
8633
+ siblingHintRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
8634
+ hoveredItemRect && !siblingHintRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
8635
+ toolbarRect && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8285
8636
  ItemInteractionLayer,
8286
8637
  {
8287
8638
  rect: toolbarRect,
@@ -8292,7 +8643,7 @@ function OhhwellsBridge() {
8292
8643
  dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
8293
8644
  onDragHandleDragStart: handleItemDragStart,
8294
8645
  onDragHandleDragEnd: handleItemDragEnd,
8295
- toolbar: toolbarVariant === "link-action" && !isItemDragging ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8646
+ toolbar: toolbarVariant === "link-action" && !isItemDragging ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8296
8647
  ItemActionToolbar,
8297
8648
  {
8298
8649
  onEditLink: openLinkPopoverForSelected,
@@ -8302,8 +8653,8 @@ function OhhwellsBridge() {
8302
8653
  ) : void 0
8303
8654
  }
8304
8655
  ),
8305
- toolbarRect && toolbarVariant === "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
8306
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8656
+ toolbarRect && toolbarVariant === "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
8657
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8307
8658
  EditGlowChrome,
8308
8659
  {
8309
8660
  rect: toolbarRect,
@@ -8312,7 +8663,7 @@ function OhhwellsBridge() {
8312
8663
  dragDisabled: reorderDragDisabled
8313
8664
  }
8314
8665
  ),
8315
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8666
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8316
8667
  FloatingToolbar,
8317
8668
  {
8318
8669
  rect: toolbarRect,
@@ -8325,7 +8676,7 @@ function OhhwellsBridge() {
8325
8676
  }
8326
8677
  )
8327
8678
  ] }),
8328
- maxBadge && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
8679
+ maxBadge && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
8329
8680
  "div",
8330
8681
  {
8331
8682
  "data-ohw-max-badge": "",
@@ -8351,7 +8702,7 @@ function OhhwellsBridge() {
8351
8702
  ]
8352
8703
  }
8353
8704
  ),
8354
- toggleState && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8705
+ toggleState && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8355
8706
  StateToggle,
8356
8707
  {
8357
8708
  rect: toggleState.rect,
@@ -8360,15 +8711,15 @@ function OhhwellsBridge() {
8360
8711
  onStateChange: handleStateChange
8361
8712
  }
8362
8713
  ),
8363
- sectionGap && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
8714
+ sectionGap && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
8364
8715
  "div",
8365
8716
  {
8366
8717
  "data-ohw-section-insert-line": "",
8367
8718
  className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
8368
8719
  style: { top: sectionGap.y, transform: "translateY(-50%)" },
8369
8720
  children: [
8370
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
8371
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8721
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
8722
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8372
8723
  Badge,
8373
8724
  {
8374
8725
  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",
@@ -8381,11 +8732,11 @@ function OhhwellsBridge() {
8381
8732
  children: "Add Section"
8382
8733
  }
8383
8734
  ),
8384
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
8735
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
8385
8736
  ]
8386
8737
  }
8387
8738
  ),
8388
- linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8739
+ linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8389
8740
  LinkPopover,
8390
8741
  {
8391
8742
  panelRef: linkPopoverPanelRef,
@@ -8401,15 +8752,15 @@ function OhhwellsBridge() {
8401
8752
  },
8402
8753
  `${linkPopover.key}-${pathname}`
8403
8754
  ) : null,
8404
- sectionGap && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
8755
+ sectionGap && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
8405
8756
  "div",
8406
8757
  {
8407
8758
  "data-ohw-section-insert-line": "",
8408
8759
  className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
8409
8760
  style: { top: sectionGap.y, transform: "translateY(-50%)" },
8410
8761
  children: [
8411
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
8412
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8762
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
8763
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8413
8764
  Badge,
8414
8765
  {
8415
8766
  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",
@@ -8422,7 +8773,7 @@ function OhhwellsBridge() {
8422
8773
  children: "Add Section"
8423
8774
  }
8424
8775
  ),
8425
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
8776
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
8426
8777
  ]
8427
8778
  }
8428
8779
  )