@ohhwells/bridge 0.1.9 → 0.1.11

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
@@ -3830,7 +3830,7 @@ function StateToggle({
3830
3830
  left: rect.right - 8,
3831
3831
  transform: "translateX(-100%)"
3832
3832
  },
3833
- children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ToggleGroupItem, { value: state, children: state }, state))
3833
+ children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
3834
3834
  }
3835
3835
  );
3836
3836
  }
@@ -3840,20 +3840,19 @@ function OhhwellsBridge() {
3840
3840
  const router = (0, import_navigation.useRouter)();
3841
3841
  const searchParams = (0, import_navigation.useSearchParams)();
3842
3842
  const isEditMode = isEditSessionActive();
3843
- (0, import_react.useEffect)(() => {
3844
- if (!isEditMode) return;
3845
- const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
3846
- const preconnect2 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.gstatic.com", crossOrigin: "" });
3847
- 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" });
3848
- document.head.append(preconnect1, preconnect2, stylesheet);
3849
- return () => {
3850
- preconnect1.remove();
3851
- preconnect2.remove();
3852
- stylesheet.remove();
3853
- };
3854
- }, [isEditMode]);
3855
3843
  const [bridgeRoot, setBridgeRoot] = (0, import_react.useState)(null);
3856
3844
  (0, import_react.useEffect)(() => {
3845
+ const figtreeFontId = "ohw-figtree-font";
3846
+ if (!document.getElementById(figtreeFontId)) {
3847
+ const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
3848
+ const preconnect2 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.gstatic.com", crossOrigin: "" });
3849
+ const stylesheet = Object.assign(document.createElement("link"), {
3850
+ id: figtreeFontId,
3851
+ rel: "stylesheet",
3852
+ href: "https://fonts.googleapis.com/css2?family=Figtree:ital,wght@0,300..900;1,300..900&display=swap"
3853
+ });
3854
+ document.head.append(preconnect1, preconnect2, stylesheet);
3855
+ }
3857
3856
  const el = document.createElement("div");
3858
3857
  el.setAttribute("data-ohw-bridge-root", "");
3859
3858
  el.setAttribute("data-ohw-bridge", "");
@@ -3884,6 +3883,9 @@ function OhhwellsBridge() {
3884
3883
  const toolbarElRef = (0, import_react.useRef)(null);
3885
3884
  const glowElRef = (0, import_react.useRef)(null);
3886
3885
  const hoveredImageRef = (0, import_react.useRef)(null);
3886
+ const hoveredImageHasTextOverlapRef = (0, import_react.useRef)(false);
3887
+ const imageUnhoverTimerRef = (0, import_react.useRef)(null);
3888
+ const imageShowTimerRef = (0, import_react.useRef)(null);
3887
3889
  const editStylesRef = (0, import_react.useRef)(null);
3888
3890
  const activateRef = (0, import_react.useRef)(() => {
3889
3891
  });
@@ -3997,7 +3999,7 @@ function OhhwellsBridge() {
3997
3999
  }
3998
4000
  let cancelled = false;
3999
4001
  setFetchState("loading");
4000
- const apiUrl = globalThis.process?.env?.NEXT_PUBLIC_FLOWOPS_API_URL ?? "http://localhost:4005";
4002
+ const apiUrl = globalThis.process?.env?.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
4001
4003
  fetch(`${apiUrl}/api/public/sites/${subdomain}/content`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
4002
4004
  if (cancelled) return;
4003
4005
  const content = data?.content ?? {};
@@ -4124,6 +4126,9 @@ function OhhwellsBridge() {
4124
4126
  [data-ohw-editable][contenteditable] *::selection { background: ${PRIMARY}59 !important; }
4125
4127
  [data-ohw-editable-state], [data-ohw-editable-state] * { pointer-events: none !important; }
4126
4128
  [data-ohw-editable-state][data-ohw-active-state] [data-ohw-editable] { pointer-events: auto !important; }
4129
+ [data-ohw-editable-state][data-ohw-active-state][data-ohw-editable] { pointer-events: auto !important; }
4130
+ [data-ohw-editable-state] [data-ohw-editable="image"],
4131
+ [data-ohw-editable-state][data-ohw-editable="image"] { pointer-events: auto !important; }
4127
4132
  `;
4128
4133
  const forceHover = document.createElement("style");
4129
4134
  forceHover.setAttribute("data-ohw-active-state-style", "");
@@ -4216,12 +4221,15 @@ function OhhwellsBridge() {
4216
4221
  }
4217
4222
  return { top, left, width: Math.max(0, right - left), height: Math.max(0, bottom - top) };
4218
4223
  };
4219
- const postImageHover = (imgEl, isDragOver = false) => {
4224
+ const postImageHover = (imgEl, isDragOver = false, forceTextOverlap) => {
4220
4225
  const r2 = getVisibleRect(imgEl);
4226
+ const hasTextOverlap = forceTextOverlap ?? (imgEl.dataset.ohwEditable === "bg-image" || imgEl.hasAttribute("data-ohw-editable-state"));
4227
+ hoveredImageHasTextOverlapRef.current = hasTextOverlap;
4221
4228
  postToParentRef.current({
4222
4229
  type: "ow:image-hover",
4223
4230
  key: imgEl.dataset.ohwKey ?? "",
4224
4231
  rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height },
4232
+ hasTextOverlap,
4225
4233
  ...isDragOver ? { isDragOver: true } : {}
4226
4234
  });
4227
4235
  const track = imgEl.closest("[data-ohw-hover-pause]");
@@ -4269,7 +4277,6 @@ function OhhwellsBridge() {
4269
4277
  return smallest;
4270
4278
  };
4271
4279
  const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
4272
- if (activeElRef.current) return;
4273
4280
  const toggleEl = document.querySelector("[data-ohw-state-toggle]");
4274
4281
  if (toggleEl) {
4275
4282
  const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
@@ -4295,32 +4302,52 @@ function OhhwellsBridge() {
4295
4302
  }
4296
4303
  return;
4297
4304
  }
4298
- const topEditable = topEl?.closest("[data-ohw-editable]");
4299
- if (topEditable && topEditable.dataset.ohwEditable !== "image" && topEditable.dataset.ohwEditable !== "bg-image") {
4300
- if (hoveredImageRef.current) {
4301
- hoveredImageRef.current = null;
4302
- resumeAnimTracks();
4303
- postToParentRef.current({ type: "ow:image-unhover" });
4304
- }
4305
- document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
4306
- topEditable.setAttribute("data-ohw-hovered", "");
4307
- return;
4305
+ const isStateCardImage = !!imgEl.closest("[data-ohw-editable-state]");
4306
+ const textEditable = Array.from(
4307
+ document.querySelectorAll('[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"])')
4308
+ ).find((el) => {
4309
+ const er = el.getBoundingClientRect();
4310
+ return x >= er.left && x <= er.right && y >= er.top && y <= er.bottom;
4311
+ });
4312
+ if (imageUnhoverTimerRef.current) {
4313
+ clearTimeout(imageUnhoverTimerRef.current);
4314
+ imageUnhoverTimerRef.current = null;
4308
4315
  }
4309
- const activeHovered = document.querySelector("[data-ohw-hovered]");
4310
- if (activeHovered) {
4311
- const outlinePad = 8;
4312
- const hr = activeHovered.getBoundingClientRect();
4313
- if (x >= hr.left - outlinePad && x <= hr.right + outlinePad && y >= hr.top - outlinePad && y <= hr.bottom + outlinePad) {
4316
+ if (imageShowTimerRef.current) {
4317
+ clearTimeout(imageShowTimerRef.current);
4318
+ imageShowTimerRef.current = null;
4319
+ }
4320
+ if (textEditable) {
4321
+ if (textEditable.hasAttribute("contenteditable")) {
4314
4322
  if (hoveredImageRef.current) {
4315
4323
  hoveredImageRef.current = null;
4324
+ hoveredImageHasTextOverlapRef.current = false;
4316
4325
  resumeAnimTracks();
4317
4326
  postToParentRef.current({ type: "ow:image-unhover" });
4318
4327
  }
4319
4328
  return;
4320
4329
  }
4330
+ if (isStateCardImage) {
4331
+ if (imgEl !== hoveredImageRef.current || !hoveredImageHasTextOverlapRef.current) {
4332
+ hoveredImageRef.current = imgEl;
4333
+ postImageHover(imgEl, isDragOver, true);
4334
+ }
4335
+ document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
4336
+ textEditable.setAttribute("data-ohw-hovered", "");
4337
+ return;
4338
+ }
4339
+ if (hoveredImageRef.current) {
4340
+ hoveredImageRef.current = null;
4341
+ hoveredImageHasTextOverlapRef.current = false;
4342
+ resumeAnimTracks();
4343
+ postToParentRef.current({ type: "ow:image-unhover" });
4344
+ }
4345
+ document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
4346
+ textEditable.setAttribute("data-ohw-hovered", "");
4347
+ return;
4321
4348
  }
4322
4349
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
4323
- if (imgEl !== hoveredImageRef.current) {
4350
+ if (imgEl !== hoveredImageRef.current || hoveredImageHasTextOverlapRef.current) {
4324
4351
  hoveredImageRef.current = imgEl;
4325
4352
  postImageHover(imgEl, isDragOver);
4326
4353
  } else if (isDragOver) {
@@ -4329,9 +4356,29 @@ function OhhwellsBridge() {
4329
4356
  } else {
4330
4357
  const inIframeView = clientX >= 0 && clientY >= 0 && clientX <= window.innerWidth && clientY <= window.innerHeight;
4331
4358
  if (!inIframeView) return;
4332
- hoveredImageRef.current = null;
4333
- resumeAnimTracks();
4334
- postToParentRef.current({ type: "ow:image-unhover" });
4359
+ if (imageUnhoverTimerRef.current) {
4360
+ clearTimeout(imageUnhoverTimerRef.current);
4361
+ imageUnhoverTimerRef.current = null;
4362
+ }
4363
+ if (imageShowTimerRef.current) {
4364
+ clearTimeout(imageShowTimerRef.current);
4365
+ imageShowTimerRef.current = null;
4366
+ }
4367
+ if (hoveredImageRef.current) {
4368
+ hoveredImageRef.current = null;
4369
+ hoveredImageHasTextOverlapRef.current = false;
4370
+ resumeAnimTracks();
4371
+ postToParentRef.current({ type: "ow:image-unhover" });
4372
+ }
4373
+ const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
4374
+ const textEl = Array.from(
4375
+ document.querySelectorAll('[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"])')
4376
+ ).find((el) => {
4377
+ const er = el.getBoundingClientRect();
4378
+ return x >= er.left && x <= er.right && y >= er.top && y <= er.bottom;
4379
+ });
4380
+ document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
4381
+ if (textEl && !textEl.hasAttribute("contenteditable")) textEl.setAttribute("data-ohw-hovered", "");
4335
4382
  }
4336
4383
  };
4337
4384
  const probeHoverCardsAt = (clientX, clientY, fromParentViewport = false) => {
@@ -4350,15 +4397,18 @@ function OhhwellsBridge() {
4350
4397
  }) ?? null;
4351
4398
  const currentLocked = activeStateElRef.current?.hasAttribute("data-ohw-active-state") ? activeStateElRef.current : null;
4352
4399
  const active = found ?? currentLocked;
4400
+ const prev = activeStateElRef.current;
4353
4401
  activeStateElRef.current = active;
4354
- document.querySelectorAll("[data-ohw-state-hovered]").forEach((el) => el.removeAttribute("data-ohw-state-hovered"));
4355
- if (active) {
4356
- if (active.querySelector("[data-ohw-state-view]")) active.setAttribute("data-ohw-state-hovered", "");
4357
- const states = deriveStates(active.dataset.ohwEditableState ?? "");
4358
- 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";
4359
- setToggleState({ rect: active.getBoundingClientRect(), activeState, states });
4360
- } else {
4361
- setToggleState(null);
4402
+ if (active !== prev) {
4403
+ if (prev) prev.removeAttribute("data-ohw-state-hovered");
4404
+ if (active) {
4405
+ if (active.querySelector("[data-ohw-state-view]")) active.setAttribute("data-ohw-state-hovered", "");
4406
+ const states = deriveStates(active.dataset.ohwEditableState ?? "");
4407
+ 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";
4408
+ setToggleState({ rect: active.getBoundingClientRect(), activeState, states });
4409
+ } else {
4410
+ setToggleState(null);
4411
+ }
4362
4412
  }
4363
4413
  };
4364
4414
  const handleMouseMove = (e) => {
@@ -4569,11 +4619,14 @@ function OhhwellsBridge() {
4569
4619
  setToggleState((prev) => prev ? { ...prev, rect } : null);
4570
4620
  }
4571
4621
  if (hoveredImageRef.current) {
4572
- const r2 = hoveredImageRef.current.getBoundingClientRect();
4622
+ const el = hoveredImageRef.current;
4623
+ const r2 = el.getBoundingClientRect();
4624
+ const hasTextOverlap = el.dataset.ohwEditable === "bg-image" || el.hasAttribute("data-ohw-editable-state");
4573
4625
  postToParentRef.current({
4574
4626
  type: "ow:image-hover",
4575
- key: hoveredImageRef.current.dataset.ohwKey ?? "",
4576
- rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height }
4627
+ key: el.dataset.ohwKey ?? "",
4628
+ rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height },
4629
+ hasTextOverlap
4577
4630
  });
4578
4631
  }
4579
4632
  };
@@ -4690,6 +4743,8 @@ function OhhwellsBridge() {
4690
4743
  window.removeEventListener("message", handleDeactivate);
4691
4744
  autoSaveTimers.current.forEach(clearTimeout);
4692
4745
  autoSaveTimers.current.clear();
4746
+ if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
4747
+ if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
4693
4748
  };
4694
4749
  }, [isEditMode, refreshStateRules]);
4695
4750
  (0, import_react.useEffect)(() => {