@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 +93 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +89 -11
- package/dist/index.js.map +1 -1
- package/dist/styles.css +120 -0
- package/package.json +2 -1
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/
|
|
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,
|
|
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,
|
|
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,
|
|
3759
|
-
gi > 0 && /* @__PURE__ */ (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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
4833
|
-
toolbarRect && /* @__PURE__ */ (0,
|
|
4834
|
-
/* @__PURE__ */ (0,
|
|
4835
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
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
|