@ohhwells/bridge 0.1.14 → 0.1.16-next.8
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/README.md +198 -70
- package/dist/index.cjs +242 -65
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +238 -61
- package/dist/index.js.map +1 -1
- package/dist/styles.css +127 -72
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -3396,7 +3396,9 @@ function ToggleGroupItem({
|
|
|
3396
3396
|
Toggle,
|
|
3397
3397
|
{
|
|
3398
3398
|
pressed: groupValue === value,
|
|
3399
|
-
onPressedChange: () =>
|
|
3399
|
+
onPressedChange: (pressed) => {
|
|
3400
|
+
if (pressed) onValueChange(value);
|
|
3401
|
+
},
|
|
3400
3402
|
className: cn(
|
|
3401
3403
|
"text-foreground cursor-pointer hover:bg-transparent hover:text-foreground",
|
|
3402
3404
|
"data-[state=on]:bg-background data-[state=on]:shadow-sm",
|
|
@@ -3431,8 +3433,30 @@ function isEditSessionActive() {
|
|
|
3431
3433
|
return new URLSearchParams(q).get("mode") === "edit";
|
|
3432
3434
|
}
|
|
3433
3435
|
|
|
3436
|
+
// src/ui/badge.tsx
|
|
3437
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
3438
|
+
var badgeVariants = cva(
|
|
3439
|
+
"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",
|
|
3440
|
+
{
|
|
3441
|
+
variants: {
|
|
3442
|
+
variant: {
|
|
3443
|
+
default: "border-transparent bg-primary text-primary-foreground",
|
|
3444
|
+
secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
3445
|
+
destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
|
3446
|
+
outline: "text-foreground"
|
|
3447
|
+
}
|
|
3448
|
+
},
|
|
3449
|
+
defaultVariants: {
|
|
3450
|
+
variant: "default"
|
|
3451
|
+
}
|
|
3452
|
+
}
|
|
3453
|
+
);
|
|
3454
|
+
function Badge({ className, variant, ...props }) {
|
|
3455
|
+
return /* @__PURE__ */ jsx3("div", { className: cn(badgeVariants({ variant }), className), ...props });
|
|
3456
|
+
}
|
|
3457
|
+
|
|
3434
3458
|
// src/OhhwellsBridge.tsx
|
|
3435
|
-
import { Fragment, jsx as
|
|
3459
|
+
import { Fragment, jsx as jsx4, jsxs } from "react/jsx-runtime";
|
|
3436
3460
|
var PRIMARY = "#0885FE";
|
|
3437
3461
|
var IMAGE_FADE_MS = 300;
|
|
3438
3462
|
function runOpacityFade(el, onDone) {
|
|
@@ -3640,7 +3664,7 @@ var TOOLBAR_GROUPS = [
|
|
|
3640
3664
|
];
|
|
3641
3665
|
function GlowFrame({ rect, elRef }) {
|
|
3642
3666
|
const GAP = 6;
|
|
3643
|
-
return /* @__PURE__ */
|
|
3667
|
+
return /* @__PURE__ */ jsx4(
|
|
3644
3668
|
"div",
|
|
3645
3669
|
{
|
|
3646
3670
|
ref: elRef,
|
|
@@ -3691,7 +3715,7 @@ function FloatingToolbar({
|
|
|
3691
3715
|
activeCommands
|
|
3692
3716
|
}) {
|
|
3693
3717
|
const { top, left, transform } = calcToolbarPos(rect, parentScroll);
|
|
3694
|
-
return /* @__PURE__ */
|
|
3718
|
+
return /* @__PURE__ */ jsx4(
|
|
3695
3719
|
"div",
|
|
3696
3720
|
{
|
|
3697
3721
|
ref: elRef,
|
|
@@ -3715,10 +3739,10 @@ function FloatingToolbar({
|
|
|
3715
3739
|
whiteSpace: "nowrap"
|
|
3716
3740
|
},
|
|
3717
3741
|
children: TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs(React2.Fragment, { children: [
|
|
3718
|
-
gi > 0 && /* @__PURE__ */
|
|
3742
|
+
gi > 0 && /* @__PURE__ */ jsx4("span", { style: { display: "block", width: 1, height: 24, background: "#E7E5E4", flexShrink: 0 } }),
|
|
3719
3743
|
btns.map((btn) => {
|
|
3720
3744
|
const isActive = activeCommands.has(btn.cmd);
|
|
3721
|
-
return /* @__PURE__ */
|
|
3745
|
+
return /* @__PURE__ */ jsx4(
|
|
3722
3746
|
"button",
|
|
3723
3747
|
{
|
|
3724
3748
|
title: btn.title,
|
|
@@ -3744,7 +3768,7 @@ function FloatingToolbar({
|
|
|
3744
3768
|
flexShrink: 0,
|
|
3745
3769
|
padding: 6
|
|
3746
3770
|
},
|
|
3747
|
-
children: /* @__PURE__ */
|
|
3771
|
+
children: /* @__PURE__ */ jsx4(
|
|
3748
3772
|
"svg",
|
|
3749
3773
|
{
|
|
3750
3774
|
width: "16",
|
|
@@ -3777,7 +3801,7 @@ function StateToggle({
|
|
|
3777
3801
|
states,
|
|
3778
3802
|
onStateChange
|
|
3779
3803
|
}) {
|
|
3780
|
-
return /* @__PURE__ */
|
|
3804
|
+
return /* @__PURE__ */ jsx4(
|
|
3781
3805
|
ToggleGroup,
|
|
3782
3806
|
{
|
|
3783
3807
|
"data-ohw-state-toggle": "",
|
|
@@ -3791,7 +3815,7 @@ function StateToggle({
|
|
|
3791
3815
|
left: rect.right - 8,
|
|
3792
3816
|
transform: "translateX(-100%)"
|
|
3793
3817
|
},
|
|
3794
|
-
children: states.map((state) => /* @__PURE__ */
|
|
3818
|
+
children: states.map((state) => /* @__PURE__ */ jsx4(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
|
|
3795
3819
|
}
|
|
3796
3820
|
);
|
|
3797
3821
|
}
|
|
@@ -3801,20 +3825,19 @@ function OhhwellsBridge() {
|
|
|
3801
3825
|
const router = useRouter();
|
|
3802
3826
|
const searchParams = useSearchParams();
|
|
3803
3827
|
const isEditMode = isEditSessionActive();
|
|
3804
|
-
useEffect(() => {
|
|
3805
|
-
if (!isEditMode) return;
|
|
3806
|
-
const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
|
|
3807
|
-
const preconnect2 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.gstatic.com", crossOrigin: "" });
|
|
3808
|
-
const stylesheet = Object.assign(document.createElement("link"), { rel: "stylesheet", href: "https://fonts.googleapis.com/css2?family=Figtree:ital,wght@0,300..900;1,300..900&display=swap" });
|
|
3809
|
-
document.head.append(preconnect1, preconnect2, stylesheet);
|
|
3810
|
-
return () => {
|
|
3811
|
-
preconnect1.remove();
|
|
3812
|
-
preconnect2.remove();
|
|
3813
|
-
stylesheet.remove();
|
|
3814
|
-
};
|
|
3815
|
-
}, [isEditMode]);
|
|
3816
3828
|
const [bridgeRoot, setBridgeRoot] = useState(null);
|
|
3817
3829
|
useEffect(() => {
|
|
3830
|
+
const figtreeFontId = "ohw-figtree-font";
|
|
3831
|
+
if (!document.getElementById(figtreeFontId)) {
|
|
3832
|
+
const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
|
|
3833
|
+
const preconnect2 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.gstatic.com", crossOrigin: "" });
|
|
3834
|
+
const stylesheet = Object.assign(document.createElement("link"), {
|
|
3835
|
+
id: figtreeFontId,
|
|
3836
|
+
rel: "stylesheet",
|
|
3837
|
+
href: "https://fonts.googleapis.com/css2?family=Figtree:ital,wght@0,300..900;1,300..900&display=swap"
|
|
3838
|
+
});
|
|
3839
|
+
document.head.append(preconnect1, preconnect2, stylesheet);
|
|
3840
|
+
}
|
|
3818
3841
|
const el = document.createElement("div");
|
|
3819
3842
|
el.setAttribute("data-ohw-bridge-root", "");
|
|
3820
3843
|
el.setAttribute("data-ohw-bridge", "");
|
|
@@ -3845,6 +3868,10 @@ function OhhwellsBridge() {
|
|
|
3845
3868
|
const toolbarElRef = useRef(null);
|
|
3846
3869
|
const glowElRef = useRef(null);
|
|
3847
3870
|
const hoveredImageRef = useRef(null);
|
|
3871
|
+
const hoveredImageHasTextOverlapRef = useRef(false);
|
|
3872
|
+
const hoveredGapRef = useRef(null);
|
|
3873
|
+
const imageUnhoverTimerRef = useRef(null);
|
|
3874
|
+
const imageShowTimerRef = useRef(null);
|
|
3848
3875
|
const editStylesRef = useRef(null);
|
|
3849
3876
|
const activateRef = useRef(() => {
|
|
3850
3877
|
});
|
|
@@ -3858,6 +3885,7 @@ function OhhwellsBridge() {
|
|
|
3858
3885
|
const [toggleState, setToggleState] = useState(null);
|
|
3859
3886
|
const [maxBadge, setMaxBadge] = useState(null);
|
|
3860
3887
|
const [activeCommands, setActiveCommands] = useState(/* @__PURE__ */ new Set());
|
|
3888
|
+
const [sectionGap, setSectionGap] = useState(null);
|
|
3861
3889
|
useEffect(() => {
|
|
3862
3890
|
const update = () => {
|
|
3863
3891
|
const el = activeElRef.current;
|
|
@@ -3866,6 +3894,12 @@ function OhhwellsBridge() {
|
|
|
3866
3894
|
if (!prev || !activeStateElRef.current) return prev;
|
|
3867
3895
|
return { ...prev, rect: activeStateElRef.current.getBoundingClientRect() };
|
|
3868
3896
|
});
|
|
3897
|
+
setSectionGap((prev) => {
|
|
3898
|
+
if (!prev) return prev;
|
|
3899
|
+
const anchor = document.querySelector(`[data-ohw-section="${prev.insertAfter}"]`);
|
|
3900
|
+
if (!anchor) return prev;
|
|
3901
|
+
return { ...prev, y: anchor.getBoundingClientRect().bottom };
|
|
3902
|
+
});
|
|
3869
3903
|
};
|
|
3870
3904
|
const vvp = window.visualViewport;
|
|
3871
3905
|
if (!vvp) return;
|
|
@@ -3907,6 +3941,10 @@ function OhhwellsBridge() {
|
|
|
3907
3941
|
const activate = useCallback((el) => {
|
|
3908
3942
|
if (activeElRef.current === el) return;
|
|
3909
3943
|
deactivate();
|
|
3944
|
+
if (hoveredImageRef.current) {
|
|
3945
|
+
hoveredImageRef.current = null;
|
|
3946
|
+
postToParentRef.current({ type: "ow:image-unhover" });
|
|
3947
|
+
}
|
|
3910
3948
|
el.setAttribute("contenteditable", "true");
|
|
3911
3949
|
el.removeAttribute("data-ohw-hovered");
|
|
3912
3950
|
activeElRef.current = el;
|
|
@@ -3954,7 +3992,7 @@ function OhhwellsBridge() {
|
|
|
3954
3992
|
}
|
|
3955
3993
|
let cancelled = false;
|
|
3956
3994
|
setFetchState("loading");
|
|
3957
|
-
const apiUrl =
|
|
3995
|
+
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
3958
3996
|
fetch(`${apiUrl}/api/public/sites/${subdomain}/content`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
|
|
3959
3997
|
if (cancelled) return;
|
|
3960
3998
|
const content = data?.content ?? {};
|
|
@@ -4081,6 +4119,7 @@ function OhhwellsBridge() {
|
|
|
4081
4119
|
[data-ohw-editable][contenteditable] *::selection { background: ${PRIMARY}59 !important; }
|
|
4082
4120
|
[data-ohw-editable-state], [data-ohw-editable-state] * { pointer-events: none !important; }
|
|
4083
4121
|
[data-ohw-editable-state][data-ohw-active-state] [data-ohw-editable] { pointer-events: auto !important; }
|
|
4122
|
+
[data-ohw-editable-state][data-ohw-active-state][data-ohw-editable] { pointer-events: auto !important; }
|
|
4084
4123
|
`;
|
|
4085
4124
|
const forceHover = document.createElement("style");
|
|
4086
4125
|
forceHover.setAttribute("data-ohw-active-state-style", "");
|
|
@@ -4107,10 +4146,12 @@ function OhhwellsBridge() {
|
|
|
4107
4146
|
if (editable) {
|
|
4108
4147
|
if (editable.dataset.ohwEditable === "image" || editable.dataset.ohwEditable === "bg-image") {
|
|
4109
4148
|
e.preventDefault();
|
|
4149
|
+
e.stopPropagation();
|
|
4110
4150
|
postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "" });
|
|
4111
4151
|
return;
|
|
4112
4152
|
}
|
|
4113
4153
|
e.preventDefault();
|
|
4154
|
+
e.stopPropagation();
|
|
4114
4155
|
activateRef.current(editable);
|
|
4115
4156
|
return;
|
|
4116
4157
|
}
|
|
@@ -4173,12 +4214,15 @@ function OhhwellsBridge() {
|
|
|
4173
4214
|
}
|
|
4174
4215
|
return { top, left, width: Math.max(0, right - left), height: Math.max(0, bottom - top) };
|
|
4175
4216
|
};
|
|
4176
|
-
const postImageHover = (imgEl, isDragOver = false) => {
|
|
4217
|
+
const postImageHover = (imgEl, isDragOver = false, forceTextOverlap) => {
|
|
4177
4218
|
const r2 = getVisibleRect(imgEl);
|
|
4219
|
+
const hasTextOverlap = forceTextOverlap ?? false;
|
|
4220
|
+
hoveredImageHasTextOverlapRef.current = hasTextOverlap;
|
|
4178
4221
|
postToParentRef.current({
|
|
4179
4222
|
type: "ow:image-hover",
|
|
4180
4223
|
key: imgEl.dataset.ohwKey ?? "",
|
|
4181
4224
|
rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height },
|
|
4225
|
+
hasTextOverlap,
|
|
4182
4226
|
...isDragOver ? { isDragOver: true } : {}
|
|
4183
4227
|
});
|
|
4184
4228
|
const track = imgEl.closest("[data-ohw-hover-pause]");
|
|
@@ -4225,7 +4269,7 @@ function OhhwellsBridge() {
|
|
|
4225
4269
|
}
|
|
4226
4270
|
return smallest;
|
|
4227
4271
|
};
|
|
4228
|
-
const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false
|
|
4272
|
+
const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
|
|
4229
4273
|
const toggleEl = document.querySelector("[data-ohw-state-toggle]");
|
|
4230
4274
|
if (toggleEl) {
|
|
4231
4275
|
const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
@@ -4251,33 +4295,52 @@ function OhhwellsBridge() {
|
|
|
4251
4295
|
}
|
|
4252
4296
|
return;
|
|
4253
4297
|
}
|
|
4254
|
-
const
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
return;
|
|
4298
|
+
const isStateCardImage = !!imgEl.closest("[data-ohw-editable-state]");
|
|
4299
|
+
const textEditable = Array.from(
|
|
4300
|
+
document.querySelectorAll('[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"])')
|
|
4301
|
+
).find((el) => {
|
|
4302
|
+
const er = el.getBoundingClientRect();
|
|
4303
|
+
return x >= er.left && x <= er.right && y >= er.top && y <= er.bottom;
|
|
4304
|
+
});
|
|
4305
|
+
if (imageUnhoverTimerRef.current) {
|
|
4306
|
+
clearTimeout(imageUnhoverTimerRef.current);
|
|
4307
|
+
imageUnhoverTimerRef.current = null;
|
|
4265
4308
|
}
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4309
|
+
if (imageShowTimerRef.current) {
|
|
4310
|
+
clearTimeout(imageShowTimerRef.current);
|
|
4311
|
+
imageShowTimerRef.current = null;
|
|
4312
|
+
}
|
|
4313
|
+
if (textEditable) {
|
|
4314
|
+
if (textEditable.hasAttribute("contenteditable")) {
|
|
4271
4315
|
if (hoveredImageRef.current) {
|
|
4272
4316
|
hoveredImageRef.current = null;
|
|
4317
|
+
hoveredImageHasTextOverlapRef.current = false;
|
|
4273
4318
|
resumeAnimTracks();
|
|
4274
4319
|
postToParentRef.current({ type: "ow:image-unhover" });
|
|
4275
4320
|
}
|
|
4276
4321
|
return;
|
|
4277
4322
|
}
|
|
4323
|
+
if (isStateCardImage) {
|
|
4324
|
+
if (imgEl !== hoveredImageRef.current || !hoveredImageHasTextOverlapRef.current) {
|
|
4325
|
+
hoveredImageRef.current = imgEl;
|
|
4326
|
+
postImageHover(imgEl, isDragOver, true);
|
|
4327
|
+
}
|
|
4328
|
+
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
4329
|
+
textEditable.setAttribute("data-ohw-hovered", "");
|
|
4330
|
+
return;
|
|
4331
|
+
}
|
|
4332
|
+
if (hoveredImageRef.current) {
|
|
4333
|
+
hoveredImageRef.current = null;
|
|
4334
|
+
hoveredImageHasTextOverlapRef.current = false;
|
|
4335
|
+
resumeAnimTracks();
|
|
4336
|
+
postToParentRef.current({ type: "ow:image-unhover" });
|
|
4337
|
+
}
|
|
4338
|
+
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
4339
|
+
textEditable.setAttribute("data-ohw-hovered", "");
|
|
4340
|
+
return;
|
|
4278
4341
|
}
|
|
4279
4342
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
4280
|
-
if (imgEl !== hoveredImageRef.current) {
|
|
4343
|
+
if (imgEl !== hoveredImageRef.current || hoveredImageHasTextOverlapRef.current) {
|
|
4281
4344
|
hoveredImageRef.current = imgEl;
|
|
4282
4345
|
postImageHover(imgEl, isDragOver);
|
|
4283
4346
|
} else if (isDragOver) {
|
|
@@ -4286,9 +4349,29 @@ function OhhwellsBridge() {
|
|
|
4286
4349
|
} else {
|
|
4287
4350
|
const inIframeView = clientX >= 0 && clientY >= 0 && clientX <= window.innerWidth && clientY <= window.innerHeight;
|
|
4288
4351
|
if (!inIframeView) return;
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4352
|
+
if (imageUnhoverTimerRef.current) {
|
|
4353
|
+
clearTimeout(imageUnhoverTimerRef.current);
|
|
4354
|
+
imageUnhoverTimerRef.current = null;
|
|
4355
|
+
}
|
|
4356
|
+
if (imageShowTimerRef.current) {
|
|
4357
|
+
clearTimeout(imageShowTimerRef.current);
|
|
4358
|
+
imageShowTimerRef.current = null;
|
|
4359
|
+
}
|
|
4360
|
+
if (hoveredImageRef.current) {
|
|
4361
|
+
hoveredImageRef.current = null;
|
|
4362
|
+
hoveredImageHasTextOverlapRef.current = false;
|
|
4363
|
+
resumeAnimTracks();
|
|
4364
|
+
postToParentRef.current({ type: "ow:image-unhover" });
|
|
4365
|
+
}
|
|
4366
|
+
const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
4367
|
+
const textEl = Array.from(
|
|
4368
|
+
document.querySelectorAll('[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"])')
|
|
4369
|
+
).find((el) => {
|
|
4370
|
+
const er = el.getBoundingClientRect();
|
|
4371
|
+
return x >= er.left && x <= er.right && y >= er.top && y <= er.bottom;
|
|
4372
|
+
});
|
|
4373
|
+
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
4374
|
+
if (textEl && !textEl.hasAttribute("contenteditable")) textEl.setAttribute("data-ohw-hovered", "");
|
|
4292
4375
|
}
|
|
4293
4376
|
};
|
|
4294
4377
|
const probeHoverCardsAt = (clientX, clientY, fromParentViewport = false) => {
|
|
@@ -4307,28 +4390,54 @@ function OhhwellsBridge() {
|
|
|
4307
4390
|
}) ?? null;
|
|
4308
4391
|
const currentLocked = activeStateElRef.current?.hasAttribute("data-ohw-active-state") ? activeStateElRef.current : null;
|
|
4309
4392
|
const active = found ?? currentLocked;
|
|
4393
|
+
const prev = activeStateElRef.current;
|
|
4310
4394
|
activeStateElRef.current = active;
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
if (active
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4395
|
+
if (active !== prev) {
|
|
4396
|
+
if (prev) prev.removeAttribute("data-ohw-state-hovered");
|
|
4397
|
+
if (active) {
|
|
4398
|
+
if (active.querySelector("[data-ohw-state-view]")) active.setAttribute("data-ohw-state-hovered", "");
|
|
4399
|
+
const states = deriveStates(active.dataset.ohwEditableState ?? "");
|
|
4400
|
+
const activeState = active.hasAttribute("data-ohw-active-state") ? (active.getAttribute("data-ohw-active-state") ?? "Default").charAt(0).toUpperCase() + (active.getAttribute("data-ohw-active-state") ?? "").slice(1) : "Default";
|
|
4401
|
+
setToggleState({ rect: active.getBoundingClientRect(), activeState, states });
|
|
4402
|
+
} else {
|
|
4403
|
+
setToggleState(null);
|
|
4404
|
+
}
|
|
4405
|
+
}
|
|
4406
|
+
};
|
|
4407
|
+
const probeSectionGapAt = (clientX, clientY, fromParentViewport = false) => {
|
|
4408
|
+
const { y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
4409
|
+
const sections = Array.from(document.querySelectorAll("[data-ohw-section]")).sort((a, b) => a.getBoundingClientRect().top - b.getBoundingClientRect().top);
|
|
4410
|
+
const ZONE = 20;
|
|
4411
|
+
for (let i = 0; i < sections.length; i++) {
|
|
4412
|
+
const a = sections[i];
|
|
4413
|
+
const b = sections[i + 1] ?? null;
|
|
4414
|
+
const boundaryY = a.getBoundingClientRect().bottom;
|
|
4415
|
+
if (Math.abs(y - boundaryY) <= ZONE) {
|
|
4416
|
+
const insertAfter = a.dataset.ohwSection ?? "";
|
|
4417
|
+
const insertBefore = b?.dataset.ohwSection ?? null;
|
|
4418
|
+
hoveredGapRef.current = { insertAfter, insertBefore };
|
|
4419
|
+
setSectionGap({ insertAfter, insertBefore, y: boundaryY });
|
|
4420
|
+
return;
|
|
4421
|
+
}
|
|
4422
|
+
}
|
|
4423
|
+
if (hoveredGapRef.current) {
|
|
4424
|
+
hoveredGapRef.current = null;
|
|
4425
|
+
setSectionGap(null);
|
|
4319
4426
|
}
|
|
4320
4427
|
};
|
|
4321
4428
|
const handleMouseMove = (e) => {
|
|
4322
4429
|
const { clientX, clientY } = e;
|
|
4323
4430
|
probeImageAt(clientX, clientY);
|
|
4324
4431
|
probeHoverCardsAt(clientX, clientY);
|
|
4432
|
+
probeSectionGapAt(clientX, clientY);
|
|
4325
4433
|
};
|
|
4326
4434
|
const handlePointerSync = (e) => {
|
|
4327
4435
|
if (e.data?.type !== "ow:pointer-sync") return;
|
|
4328
|
-
const { clientX, clientY
|
|
4436
|
+
const { clientX, clientY } = e.data;
|
|
4329
4437
|
if (typeof clientX !== "number" || typeof clientY !== "number") return;
|
|
4330
|
-
probeImageAt(clientX, clientY
|
|
4438
|
+
probeImageAt(clientX, clientY);
|
|
4331
4439
|
probeHoverCardsAt(clientX, clientY);
|
|
4440
|
+
probeSectionGapAt(clientX, clientY);
|
|
4332
4441
|
};
|
|
4333
4442
|
const handleDragOver = (e) => {
|
|
4334
4443
|
e.preventDefault();
|
|
@@ -4340,7 +4449,8 @@ function OhhwellsBridge() {
|
|
|
4340
4449
|
e.dataTransfer.dropEffect = "copy";
|
|
4341
4450
|
if (hoveredImageRef.current !== el) {
|
|
4342
4451
|
hoveredImageRef.current = el;
|
|
4343
|
-
|
|
4452
|
+
const isStateCard = !!el.closest("[data-ohw-editable-state]");
|
|
4453
|
+
postImageHover(el, true, isStateCard ? true : void 0);
|
|
4344
4454
|
}
|
|
4345
4455
|
};
|
|
4346
4456
|
const handleDragLeave = (e) => {
|
|
@@ -4526,11 +4636,13 @@ function OhhwellsBridge() {
|
|
|
4526
4636
|
setToggleState((prev) => prev ? { ...prev, rect } : null);
|
|
4527
4637
|
}
|
|
4528
4638
|
if (hoveredImageRef.current) {
|
|
4529
|
-
const
|
|
4639
|
+
const el = hoveredImageRef.current;
|
|
4640
|
+
const r2 = el.getBoundingClientRect();
|
|
4530
4641
|
postToParentRef.current({
|
|
4531
4642
|
type: "ow:image-hover",
|
|
4532
|
-
key:
|
|
4533
|
-
rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height }
|
|
4643
|
+
key: el.dataset.ohwKey ?? "",
|
|
4644
|
+
rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height },
|
|
4645
|
+
hasTextOverlap: hoveredImageHasTextOverlapRef.current
|
|
4534
4646
|
});
|
|
4535
4647
|
}
|
|
4536
4648
|
};
|
|
@@ -4604,12 +4716,49 @@ function OhhwellsBridge() {
|
|
|
4604
4716
|
parentScrollRef.current = { iframeOffsetTop, headerH, canvasH };
|
|
4605
4717
|
if (activeElRef.current) applyToolbarPos(activeElRef.current.getBoundingClientRect());
|
|
4606
4718
|
};
|
|
4719
|
+
const handleClickAt = (e) => {
|
|
4720
|
+
if (e.data?.type !== "ow:click-at") return;
|
|
4721
|
+
const { clientX, clientY } = e.data;
|
|
4722
|
+
const allImages = Array.from(
|
|
4723
|
+
document.querySelectorAll('[data-ohw-editable="image"], [data-ohw-editable="bg-image"]')
|
|
4724
|
+
).filter((el) => !!el.closest("[data-ohw-editable-state]"));
|
|
4725
|
+
const stateCardImage = allImages.find((el) => {
|
|
4726
|
+
const ownerCard = el.closest("[data-ohw-editable-state]");
|
|
4727
|
+
if (ownerCard) {
|
|
4728
|
+
const inHoverState = ownerCard.getAttribute("data-ohw-active-state") === "hover";
|
|
4729
|
+
const elState = el.dataset.ohwState;
|
|
4730
|
+
if (el === ownerCard && inHoverState) return false;
|
|
4731
|
+
if (elState === "default" && inHoverState) return false;
|
|
4732
|
+
if (elState === "hover" && !inHoverState) return false;
|
|
4733
|
+
}
|
|
4734
|
+
const r2 = el.getBoundingClientRect();
|
|
4735
|
+
return clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom;
|
|
4736
|
+
});
|
|
4737
|
+
if (stateCardImage) {
|
|
4738
|
+
postToParentRef.current({ type: "ow:image-pick", key: stateCardImage.dataset.ohwKey ?? "" });
|
|
4739
|
+
return;
|
|
4740
|
+
}
|
|
4741
|
+
const textEditable = Array.from(
|
|
4742
|
+
document.querySelectorAll(
|
|
4743
|
+
'[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"])'
|
|
4744
|
+
)
|
|
4745
|
+
).find((el) => {
|
|
4746
|
+
const r2 = el.getBoundingClientRect();
|
|
4747
|
+
return clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom;
|
|
4748
|
+
});
|
|
4749
|
+
if (textEditable) {
|
|
4750
|
+
activateRef.current(textEditable);
|
|
4751
|
+
return;
|
|
4752
|
+
}
|
|
4753
|
+
deactivateRef.current();
|
|
4754
|
+
};
|
|
4607
4755
|
window.addEventListener("message", handleSave);
|
|
4608
4756
|
window.addEventListener("message", handleImageUrl);
|
|
4609
4757
|
window.addEventListener("message", handleAnimLock);
|
|
4610
4758
|
window.addEventListener("message", handleCanvasHeight);
|
|
4611
4759
|
window.addEventListener("message", handleParentScroll);
|
|
4612
4760
|
window.addEventListener("message", handlePointerSync);
|
|
4761
|
+
window.addEventListener("message", handleClickAt);
|
|
4613
4762
|
document.addEventListener("click", handleClick, true);
|
|
4614
4763
|
document.addEventListener("paste", handlePaste, true);
|
|
4615
4764
|
document.addEventListener("input", handleInput, true);
|
|
@@ -4643,10 +4792,13 @@ function OhhwellsBridge() {
|
|
|
4643
4792
|
window.removeEventListener("message", handleCanvasHeight);
|
|
4644
4793
|
window.removeEventListener("message", handleParentScroll);
|
|
4645
4794
|
window.removeEventListener("message", handlePointerSync);
|
|
4795
|
+
window.removeEventListener("message", handleClickAt);
|
|
4646
4796
|
window.removeEventListener("message", handleHydrate);
|
|
4647
4797
|
window.removeEventListener("message", handleDeactivate);
|
|
4648
4798
|
autoSaveTimers.current.forEach(clearTimeout);
|
|
4649
4799
|
autoSaveTimers.current.clear();
|
|
4800
|
+
if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
|
|
4801
|
+
if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
|
|
4650
4802
|
};
|
|
4651
4803
|
}, [isEditMode, refreshStateRules]);
|
|
4652
4804
|
useEffect(() => {
|
|
@@ -4693,8 +4845,8 @@ function OhhwellsBridge() {
|
|
|
4693
4845
|
return bridgeRoot ? createPortal(
|
|
4694
4846
|
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4695
4847
|
toolbarRect && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4696
|
-
/* @__PURE__ */
|
|
4697
|
-
/* @__PURE__ */
|
|
4848
|
+
/* @__PURE__ */ jsx4(GlowFrame, { rect: toolbarRect, elRef: glowElRef }),
|
|
4849
|
+
/* @__PURE__ */ jsx4(FloatingToolbar, { rect: toolbarRect, parentScroll: parentScrollRef.current, elRef: toolbarElRef, onCommand: handleCommand, activeCommands })
|
|
4698
4850
|
] }),
|
|
4699
4851
|
maxBadge && /* @__PURE__ */ jsxs(
|
|
4700
4852
|
"div",
|
|
@@ -4722,7 +4874,7 @@ function OhhwellsBridge() {
|
|
|
4722
4874
|
]
|
|
4723
4875
|
}
|
|
4724
4876
|
),
|
|
4725
|
-
toggleState && /* @__PURE__ */
|
|
4877
|
+
toggleState && /* @__PURE__ */ jsx4(
|
|
4726
4878
|
StateToggle,
|
|
4727
4879
|
{
|
|
4728
4880
|
rect: toggleState.rect,
|
|
@@ -4730,6 +4882,31 @@ function OhhwellsBridge() {
|
|
|
4730
4882
|
states: toggleState.states,
|
|
4731
4883
|
onStateChange: handleStateChange
|
|
4732
4884
|
}
|
|
4885
|
+
),
|
|
4886
|
+
sectionGap && /* @__PURE__ */ jsxs(
|
|
4887
|
+
"div",
|
|
4888
|
+
{
|
|
4889
|
+
"data-ohw-section-insert-line": "",
|
|
4890
|
+
className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
|
|
4891
|
+
style: { top: sectionGap.y, transform: "translateY(-50%)" },
|
|
4892
|
+
children: [
|
|
4893
|
+
/* @__PURE__ */ jsx4("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
|
|
4894
|
+
/* @__PURE__ */ jsx4(
|
|
4895
|
+
Badge,
|
|
4896
|
+
{
|
|
4897
|
+
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",
|
|
4898
|
+
onClick: () => {
|
|
4899
|
+
window.parent.postMessage(
|
|
4900
|
+
{ type: "ow:add-section", insertAfter: sectionGap.insertAfter, insertBefore: sectionGap.insertBefore },
|
|
4901
|
+
"*"
|
|
4902
|
+
);
|
|
4903
|
+
},
|
|
4904
|
+
children: "Add Section"
|
|
4905
|
+
}
|
|
4906
|
+
),
|
|
4907
|
+
/* @__PURE__ */ jsx4("div", { className: "flex-1 bg-primary", style: { height: 3 } })
|
|
4908
|
+
]
|
|
4909
|
+
}
|
|
4733
4910
|
)
|
|
4734
4911
|
] }),
|
|
4735
4912
|
bridgeRoot
|