@ohhwells/bridge 0.1.17 → 0.1.18

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
@@ -3472,8 +3472,30 @@ function isEditSessionActive() {
3472
3472
  return new URLSearchParams(q).get("mode") === "edit";
3473
3473
  }
3474
3474
 
3475
- // src/OhhwellsBridge.tsx
3475
+ // src/ui/badge.tsx
3476
3476
  var import_jsx_runtime3 = require("react/jsx-runtime");
3477
+ var badgeVariants = cva(
3478
+ "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",
3479
+ {
3480
+ variants: {
3481
+ variant: {
3482
+ default: "border-transparent bg-primary text-primary-foreground",
3483
+ secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
3484
+ destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
3485
+ outline: "text-foreground"
3486
+ }
3487
+ },
3488
+ defaultVariants: {
3489
+ variant: "default"
3490
+ }
3491
+ }
3492
+ );
3493
+ function Badge({ className, variant, ...props }) {
3494
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: cn(badgeVariants({ variant }), className), ...props });
3495
+ }
3496
+
3497
+ // src/OhhwellsBridge.tsx
3498
+ var import_jsx_runtime4 = require("react/jsx-runtime");
3477
3499
  var PRIMARY = "#0885FE";
3478
3500
  var IMAGE_FADE_MS = 300;
3479
3501
  function runOpacityFade(el, onDone) {
@@ -3681,7 +3703,7 @@ var TOOLBAR_GROUPS = [
3681
3703
  ];
3682
3704
  function GlowFrame({ rect, elRef }) {
3683
3705
  const GAP = 6;
3684
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
3706
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3685
3707
  "div",
3686
3708
  {
3687
3709
  ref: elRef,
@@ -3732,7 +3754,7 @@ function FloatingToolbar({
3732
3754
  activeCommands
3733
3755
  }) {
3734
3756
  const { top, left, transform } = calcToolbarPos(rect, parentScroll);
3735
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
3757
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3736
3758
  "div",
3737
3759
  {
3738
3760
  ref: elRef,
@@ -3755,11 +3777,11 @@ function FloatingToolbar({
3755
3777
  pointerEvents: "auto",
3756
3778
  whiteSpace: "nowrap"
3757
3779
  },
3758
- children: TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react.default.Fragment, { children: [
3759
- gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { display: "block", width: 1, height: 24, background: "#E7E5E4", flexShrink: 0 } }),
3780
+ children: TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react.default.Fragment, { children: [
3781
+ gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { display: "block", width: 1, height: 24, background: "#E7E5E4", flexShrink: 0 } }),
3760
3782
  btns.map((btn) => {
3761
3783
  const isActive = activeCommands.has(btn.cmd);
3762
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
3784
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3763
3785
  "button",
3764
3786
  {
3765
3787
  title: btn.title,
@@ -3785,7 +3807,7 @@ function FloatingToolbar({
3785
3807
  flexShrink: 0,
3786
3808
  padding: 6
3787
3809
  },
3788
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
3810
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3789
3811
  "svg",
3790
3812
  {
3791
3813
  width: "16",
@@ -3818,7 +3840,7 @@ function StateToggle({
3818
3840
  states,
3819
3841
  onStateChange
3820
3842
  }) {
3821
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
3843
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3822
3844
  ToggleGroup,
3823
3845
  {
3824
3846
  "data-ohw-state-toggle": "",
@@ -3832,7 +3854,7 @@ function StateToggle({
3832
3854
  left: rect.right - 8,
3833
3855
  transform: "translateX(-100%)"
3834
3856
  },
3835
- children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
3857
+ children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
3836
3858
  }
3837
3859
  );
3838
3860
  }
@@ -3886,6 +3908,7 @@ function OhhwellsBridge() {
3886
3908
  const glowElRef = (0, import_react.useRef)(null);
3887
3909
  const hoveredImageRef = (0, import_react.useRef)(null);
3888
3910
  const hoveredImageHasTextOverlapRef = (0, import_react.useRef)(false);
3911
+ const hoveredGapRef = (0, import_react.useRef)(null);
3889
3912
  const imageUnhoverTimerRef = (0, import_react.useRef)(null);
3890
3913
  const imageShowTimerRef = (0, import_react.useRef)(null);
3891
3914
  const editStylesRef = (0, import_react.useRef)(null);
@@ -3901,6 +3924,7 @@ function OhhwellsBridge() {
3901
3924
  const [toggleState, setToggleState] = (0, import_react.useState)(null);
3902
3925
  const [maxBadge, setMaxBadge] = (0, import_react.useState)(null);
3903
3926
  const [activeCommands, setActiveCommands] = (0, import_react.useState)(/* @__PURE__ */ new Set());
3927
+ const [sectionGap, setSectionGap] = (0, import_react.useState)(null);
3904
3928
  (0, import_react.useEffect)(() => {
3905
3929
  const update = () => {
3906
3930
  const el = activeElRef.current;
@@ -3909,6 +3933,12 @@ function OhhwellsBridge() {
3909
3933
  if (!prev || !activeStateElRef.current) return prev;
3910
3934
  return { ...prev, rect: activeStateElRef.current.getBoundingClientRect() };
3911
3935
  });
3936
+ setSectionGap((prev) => {
3937
+ if (!prev) return prev;
3938
+ const anchor = document.querySelector(`[data-ohw-section="${prev.insertAfter}"]`);
3939
+ if (!anchor) return prev;
3940
+ return { ...prev, y: anchor.getBoundingClientRect().bottom };
3941
+ });
3912
3942
  };
3913
3943
  const vvp = window.visualViewport;
3914
3944
  if (!vvp) return;
@@ -4413,10 +4443,32 @@ function OhhwellsBridge() {
4413
4443
  }
4414
4444
  }
4415
4445
  };
4446
+ const probeSectionGapAt = (clientX, clientY, fromParentViewport = false) => {
4447
+ const { y } = toProbeCoords(clientX, clientY, fromParentViewport);
4448
+ const sections = Array.from(document.querySelectorAll("[data-ohw-section]")).sort((a, b) => a.getBoundingClientRect().top - b.getBoundingClientRect().top);
4449
+ const ZONE = 20;
4450
+ for (let i = 0; i < sections.length; i++) {
4451
+ const a = sections[i];
4452
+ const b = sections[i + 1] ?? null;
4453
+ const boundaryY = a.getBoundingClientRect().bottom;
4454
+ if (Math.abs(y - boundaryY) <= ZONE) {
4455
+ const insertAfter = a.dataset.ohwSection ?? "";
4456
+ const insertBefore = b?.dataset.ohwSection ?? null;
4457
+ hoveredGapRef.current = { insertAfter, insertBefore };
4458
+ setSectionGap({ insertAfter, insertBefore, y: boundaryY });
4459
+ return;
4460
+ }
4461
+ }
4462
+ if (hoveredGapRef.current) {
4463
+ hoveredGapRef.current = null;
4464
+ setSectionGap(null);
4465
+ }
4466
+ };
4416
4467
  const handleMouseMove = (e) => {
4417
4468
  const { clientX, clientY } = e;
4418
4469
  probeImageAt(clientX, clientY);
4419
4470
  probeHoverCardsAt(clientX, clientY);
4471
+ probeSectionGapAt(clientX, clientY);
4420
4472
  };
4421
4473
  const handlePointerSync = (e) => {
4422
4474
  if (e.data?.type !== "ow:pointer-sync") return;
@@ -4424,6 +4476,7 @@ function OhhwellsBridge() {
4424
4476
  if (typeof clientX !== "number" || typeof clientY !== "number") return;
4425
4477
  probeImageAt(clientX, clientY);
4426
4478
  probeHoverCardsAt(clientX, clientY);
4479
+ probeSectionGapAt(clientX, clientY);
4427
4480
  };
4428
4481
  const handleDragOver = (e) => {
4429
4482
  e.preventDefault();
@@ -4829,12 +4882,12 @@ function OhhwellsBridge() {
4829
4882
  setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
4830
4883
  }, [deactivate]);
4831
4884
  return bridgeRoot ? (0, import_react_dom.createPortal)(
4832
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
4833
- toolbarRect && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
4834
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(GlowFrame, { rect: toolbarRect, elRef: glowElRef }),
4835
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(FloatingToolbar, { rect: toolbarRect, parentScroll: parentScrollRef.current, elRef: toolbarElRef, onCommand: handleCommand, activeCommands })
4885
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
4886
+ toolbarRect && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
4887
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(GlowFrame, { rect: toolbarRect, elRef: glowElRef }),
4888
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(FloatingToolbar, { rect: toolbarRect, parentScroll: parentScrollRef.current, elRef: toolbarElRef, onCommand: handleCommand, activeCommands })
4836
4889
  ] }),
4837
- maxBadge && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
4890
+ maxBadge && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
4838
4891
  "div",
4839
4892
  {
4840
4893
  "data-ohw-max-badge": "",
@@ -4860,7 +4913,7 @@ function OhhwellsBridge() {
4860
4913
  ]
4861
4914
  }
4862
4915
  ),
4863
- toggleState && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
4916
+ toggleState && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
4864
4917
  StateToggle,
4865
4918
  {
4866
4919
  rect: toggleState.rect,
@@ -4868,6 +4921,31 @@ function OhhwellsBridge() {
4868
4921
  states: toggleState.states,
4869
4922
  onStateChange: handleStateChange
4870
4923
  }
4924
+ ),
4925
+ sectionGap && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
4926
+ "div",
4927
+ {
4928
+ "data-ohw-section-insert-line": "",
4929
+ className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
4930
+ style: { top: sectionGap.y, transform: "translateY(-50%)" },
4931
+ children: [
4932
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
4933
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
4934
+ Badge,
4935
+ {
4936
+ 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",
4937
+ onClick: () => {
4938
+ window.parent.postMessage(
4939
+ { type: "ow:add-section", insertAfter: sectionGap.insertAfter, insertBefore: sectionGap.insertBefore },
4940
+ "*"
4941
+ );
4942
+ },
4943
+ children: "Add Section"
4944
+ }
4945
+ ),
4946
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
4947
+ ]
4948
+ }
4871
4949
  )
4872
4950
  ] }),
4873
4951
  bridgeRoot