@ohhwells/bridge 0.1.114 → 0.1.115

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.js CHANGED
@@ -386,6 +386,20 @@ var BG_VALUES = {
386
386
  accent: "var(--ohw-brand-primary, var(--color-primary, #0078E5))",
387
387
  "accent-soft": "color-mix(in srgb, var(--ohw-brand-primary, var(--color-primary, #0078E5)) 12%, var(--ohw-brand-light, var(--color-light, #FFFFFF)))"
388
388
  };
389
+ var NAVBAR_COLOR_TOKENS = ["dark", "primary", "accent", "light"];
390
+ function navbarColorVar(token) {
391
+ const fallback = {
392
+ dark: "#0C0A09",
393
+ primary: "#0078E5",
394
+ accent: "#0078E5",
395
+ light: "#FFFFFF"
396
+ };
397
+ return `var(--ohw-brand-${token}, var(--color-${token}, ${fallback[token]}))`;
398
+ }
399
+ function resolveNavbarValue(value) {
400
+ if (value === void 0) return void 0;
401
+ return NAVBAR_COLOR_TOKENS.includes(value) ? navbarColorVar(value) : value;
402
+ }
389
403
  var HEADLINE_SIZES = { md: 24, lg: 32, xl: 40, display: 56 };
390
404
  function styleSheetCss() {
391
405
  const rules = [];
@@ -555,8 +569,18 @@ function applyStylesToDom(store) {
555
569
  for (const [sectionId, override] of Object.entries(store.sections)) {
556
570
  const escaped = CSS.escape(sectionId);
557
571
  const byInstance = document.querySelectorAll(`[data-ohw-instance="${escaped}"]`);
558
- const sections = byInstance.length ? byInstance : document.querySelectorAll(`[data-ohw-section="${escaped}"]`);
572
+ const sections = Array.from(
573
+ byInstance.length ? byInstance : document.querySelectorAll(`[data-ohw-section="${escaped}"]`)
574
+ );
575
+ const isNavbar = sectionId === "navbar";
576
+ if (isNavbar) {
577
+ const drawer = document.querySelector("[data-ohw-nav-drawer]");
578
+ if (drawer && !sections.includes(drawer)) sections.push(drawer);
579
+ const header = document.querySelector("[data-ohw-nav-root]");
580
+ if (header && !sections.includes(header)) sections.push(header);
581
+ }
559
582
  for (const marker of Array.from(sections)) {
583
+ const isDrawerMarker = isNavbar && marker.hasAttribute("data-ohw-nav-drawer");
560
584
  const section = marker.querySelector(":scope > [data-ai-section]") ?? marker;
561
585
  for (const [prop, attr] of Object.entries(SECTION_ATTRS)) {
562
586
  const value = override[prop];
@@ -564,19 +588,23 @@ function applyStylesToDom(store) {
564
588
  if (prop === "sectionBackground" && override.sectionBackgroundColor !== void 0) continue;
565
589
  section.setAttribute(attr, String(value).replace(":", "-"));
566
590
  }
567
- if (override.sectionBackgroundColor !== void 0) {
591
+ const bgOverride = isDrawerMarker ? override.navbarMobileBackground : override.sectionBackgroundColor;
592
+ const textOverride = isDrawerMarker ? override.navbarMobileTextColor : override.textColor;
593
+ const bgValue = isNavbar ? resolveNavbarValue(bgOverride) : bgOverride;
594
+ const textValue = isNavbar ? resolveNavbarValue(textOverride) : textOverride;
595
+ if (bgValue !== void 0) {
568
596
  saveInline(section, "background");
569
- section.style.setProperty("background", override.sectionBackgroundColor, "important");
597
+ section.style.setProperty("background", bgValue, "important");
570
598
  section.setAttribute("data-ohw-style-bgcolor", "");
571
599
  }
572
- if (override.textColor !== void 0 || override.fontFamily !== void 0) {
600
+ if (textValue !== void 0 || override.fontFamily !== void 0) {
573
601
  const textEls = marker.querySelectorAll(
574
602
  '[data-ohw-editable="text"], [data-ohw-editable="plain"], [data-ohw-field-label]'
575
603
  );
576
604
  for (const el of Array.from(textEls)) {
577
- if (override.textColor !== void 0) {
605
+ if (textValue !== void 0) {
578
606
  saveInline(el, "color");
579
- el.style.setProperty("color", override.textColor, "important");
607
+ el.style.setProperty("color", textValue, "important");
580
608
  el.setAttribute(NODE_WROTE_ATTR, "");
581
609
  }
582
610
  if (override.fontFamily !== void 0) {
@@ -9028,6 +9056,57 @@ function useLiveSectionRect(sectionId) {
9028
9056
  }, [sectionId]);
9029
9057
  return rect;
9030
9058
  }
9059
+ var NAV_TOGGLE_LABEL_RE = /^(toggle menu|open menu|close menu)$/i;
9060
+ function readNavToggleRect() {
9061
+ const el = Array.from(document.querySelectorAll("button[aria-label]")).find(
9062
+ (e) => NAV_TOGGLE_LABEL_RE.test(e.getAttribute("aria-label") ?? "")
9063
+ );
9064
+ if (!el) return null;
9065
+ const r2 = el.getBoundingClientRect();
9066
+ if (r2.width <= 0 || r2.height <= 0) return null;
9067
+ return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
9068
+ }
9069
+ function useLiveNavToggleHole(active) {
9070
+ const [rect, setRect] = useState6(null);
9071
+ useEffect4(() => {
9072
+ if (!active) {
9073
+ setRect(null);
9074
+ return;
9075
+ }
9076
+ const update = () => {
9077
+ const next = readNavToggleRect();
9078
+ setRect(
9079
+ (prev) => prev && next && prev.top === next.top && prev.left === next.left && prev.width === next.width && prev.height === next.height ? prev : next
9080
+ );
9081
+ };
9082
+ update();
9083
+ const opts = { capture: true, passive: true };
9084
+ window.addEventListener("scroll", update, opts);
9085
+ window.addEventListener("resize", update);
9086
+ const interval = setInterval(update, 500);
9087
+ return () => {
9088
+ window.removeEventListener("scroll", update, opts);
9089
+ window.removeEventListener("resize", update);
9090
+ clearInterval(interval);
9091
+ };
9092
+ }, [active]);
9093
+ return rect;
9094
+ }
9095
+ function subtractRect(outer, hole) {
9096
+ if (!hole) return [outer];
9097
+ const l = Math.max(outer.left, hole.left);
9098
+ const t = Math.max(outer.top, hole.top);
9099
+ const r2 = Math.min(outer.left + outer.width, hole.left + hole.width);
9100
+ const b = Math.min(outer.top + outer.height, hole.top + hole.height);
9101
+ if (l >= r2 || t >= b) return [outer];
9102
+ const rects = [];
9103
+ if (t > outer.top) rects.push({ left: outer.left, top: outer.top, width: outer.width, height: t - outer.top });
9104
+ const midHeight = b - t;
9105
+ if (l > outer.left) rects.push({ left: outer.left, top: t, width: l - outer.left, height: midHeight });
9106
+ if (r2 < outer.left + outer.width) rects.push({ left: r2, top: t, width: outer.left + outer.width - r2, height: midHeight });
9107
+ if (b < outer.top + outer.height) rects.push({ left: outer.left, top: b, width: outer.width, height: outer.top + outer.height - b });
9108
+ return rects;
9109
+ }
9031
9110
  function computeSectionBoundaryFlags(instanceId) {
9032
9111
  const topLevel = topLevelSections();
9033
9112
  const index = topLevel.findIndex((el) => instanceIdOf(el) === instanceId);
@@ -9243,6 +9322,7 @@ function AiSectionOverlay({
9243
9322
  const activeSelectionId = reviewId ? null : selectedId;
9244
9323
  const selectionRect = useLiveSectionRect(activeSelectionId);
9245
9324
  const reviewRect = useLiveSectionRect(reviewId);
9325
+ const navToggleHole = useLiveNavToggleHole(Boolean(reviewId));
9246
9326
  const hoverRect = useLiveSectionRect(reviewId || hoveredId === selectedId ? null : hoveredId);
9247
9327
  const showSelectionBorder = Boolean(selectionRect) && !navDropdownForceOpen;
9248
9328
  useEffect4(() => {
@@ -9302,48 +9382,65 @@ function AiSectionOverlay({
9302
9382
  }
9303
9383
  }
9304
9384
  ),
9305
- reviewRect && /* @__PURE__ */ jsx17(
9306
- "div",
9307
- {
9308
- "data-ohw-ai-review": "",
9309
- style: {
9310
- position: "fixed",
9311
- top: reviewRect.top,
9312
- left: reviewRect.left,
9313
- width: reviewRect.width,
9314
- height: reviewRect.height,
9315
- border: `2px solid ${PRIMARY2}`,
9316
- borderRadius: edgeAwareRadius(reviewRect),
9317
- zIndex: 2147483200,
9318
- // The veil itself: swallows clicks so the section stays locked until decided. This
9319
- // stopPropagation only guards the bubble phase; the bridge's capture-phase click
9320
- // handlers additionally bail on `[data-ohw-ai-review]`, without which a click on
9321
- // Accept/Discard resolves to the media beneath and opens the file picker.
9322
- background: "rgba(8, 133, 254, 0.04)",
9323
- pointerEvents: "auto",
9324
- cursor: "default"
9385
+ reviewRect && /* @__PURE__ */ jsxs9(Fragment5, { children: [
9386
+ subtractRect(reviewRect, navToggleHole).map((r2, i) => /* @__PURE__ */ jsx17(
9387
+ "div",
9388
+ {
9389
+ "data-ohw-ai-review": "",
9390
+ "aria-hidden": true,
9391
+ style: {
9392
+ position: "fixed",
9393
+ top: r2.top,
9394
+ left: r2.left,
9395
+ width: r2.width,
9396
+ height: r2.height,
9397
+ background: "rgba(8, 133, 254, 0.04)",
9398
+ pointerEvents: "auto",
9399
+ cursor: "default",
9400
+ zIndex: 2147483200
9401
+ },
9402
+ onClick: (e) => e.stopPropagation()
9325
9403
  },
9326
- onClick: (e) => e.stopPropagation(),
9327
- children: !reviewButtonsHidden && /* @__PURE__ */ jsxs9(
9328
- "div",
9329
- {
9330
- style: {
9331
- position: "sticky",
9332
- top: 12,
9333
- display: "flex",
9334
- gap: 8,
9335
- justifyContent: "flex-end",
9336
- paddingRight: 12,
9337
- paddingTop: 12
9338
- },
9339
- children: [
9340
- /* @__PURE__ */ jsx17(ReviewButton, { label: "Accept", onClick: () => decide("accept"), background: PRIMARY2, color: "#ffffff", children: /* @__PURE__ */ jsx17(Check, { size: 16, strokeWidth: 2.5, "aria-hidden": true }) }),
9341
- /* @__PURE__ */ jsx17(ReviewButton, { label: "Discard", onClick: () => decide("discard"), background: "#EFF6FF", color: "#0c0a09", children: /* @__PURE__ */ jsx17(X, { size: 16, strokeWidth: 2, "aria-hidden": true }) })
9342
- ]
9404
+ i
9405
+ )),
9406
+ /* @__PURE__ */ jsx17(
9407
+ "div",
9408
+ {
9409
+ "aria-hidden": true,
9410
+ style: {
9411
+ position: "fixed",
9412
+ top: reviewRect.top,
9413
+ left: reviewRect.left,
9414
+ width: reviewRect.width,
9415
+ height: reviewRect.height,
9416
+ border: `2px solid ${PRIMARY2}`,
9417
+ borderRadius: edgeAwareRadius(reviewRect),
9418
+ pointerEvents: "none",
9419
+ zIndex: 2147483200
9343
9420
  }
9344
- )
9345
- }
9346
- )
9421
+ }
9422
+ ),
9423
+ !reviewButtonsHidden && /* @__PURE__ */ jsxs9(
9424
+ "div",
9425
+ {
9426
+ style: {
9427
+ position: "fixed",
9428
+ top: reviewRect.top + 12,
9429
+ left: reviewRect.left,
9430
+ width: reviewRect.width,
9431
+ display: "flex",
9432
+ gap: 8,
9433
+ justifyContent: "flex-end",
9434
+ paddingRight: 12,
9435
+ zIndex: 2147483201
9436
+ },
9437
+ children: [
9438
+ /* @__PURE__ */ jsx17(ReviewButton, { label: "Accept", onClick: () => decide("accept"), background: PRIMARY2, color: "#ffffff", children: /* @__PURE__ */ jsx17(Check, { size: 16, strokeWidth: 2.5, "aria-hidden": true }) }),
9439
+ /* @__PURE__ */ jsx17(ReviewButton, { label: "Discard", onClick: () => decide("discard"), background: "#EFF6FF", color: "#0c0a09", children: /* @__PURE__ */ jsx17(X, { size: 16, strokeWidth: 2, "aria-hidden": true }) })
9440
+ ]
9441
+ }
9442
+ )
9443
+ ] })
9347
9444
  ] });
9348
9445
  }
9349
9446
 
@@ -11006,6 +11103,15 @@ function getNavbarDesktopContainer() {
11006
11103
  function getNavbarDrawerContainer() {
11007
11104
  return document.querySelector("[data-ohw-nav-drawer]");
11008
11105
  }
11106
+ function isNavDrawerOpen() {
11107
+ return document.querySelector('[data-ohw-nav-drawer][data-ohw-section="navbar"]') !== null;
11108
+ }
11109
+ function isPointOutsideOpenDrawer(clientX, clientY) {
11110
+ const drawer = document.querySelector('[data-ohw-nav-drawer][data-ohw-section="navbar"]');
11111
+ if (!drawer) return false;
11112
+ const r2 = drawer.getBoundingClientRect();
11113
+ return clientX < r2.left || clientX > r2.right || clientY < r2.top || clientY > r2.bottom;
11114
+ }
11009
11115
  function isNavbarListContainerVisible(el) {
11010
11116
  if (el.hasAttribute("hidden")) return false;
11011
11117
  if (el.closest("[hidden]")) return false;
@@ -17738,6 +17844,7 @@ function OhhwellsBridge() {
17738
17844
  const aiSectionsRef = useRef10("");
17739
17845
  const brandKitRef = useRef10("");
17740
17846
  const stylesRef = useRef10("");
17847
+ const appliedDrawerRef = useRef10(null);
17741
17848
  const pendingDeleteUndoRef = useRef10(null);
17742
17849
  const [sitePages, setSitePages] = useState14([]);
17743
17850
  const [sectionsByPath, setSectionsByPath] = useState14({});
@@ -19403,6 +19510,17 @@ function OhhwellsBridge() {
19403
19510
  if (!isEditMode) return;
19404
19511
  initSectionInstancesFromContent(editContentRef.current, pathname);
19405
19512
  }, [pathname, isEditMode]);
19513
+ useEffect13(() => {
19514
+ if (!isEditMode) return;
19515
+ const observer = new MutationObserver(() => {
19516
+ const drawer = document.querySelector("[data-ohw-nav-drawer]");
19517
+ if (!drawer || drawer === appliedDrawerRef.current) return;
19518
+ appliedDrawerRef.current = drawer;
19519
+ applyStylesToDom(parseStyleStore(stylesRef.current));
19520
+ });
19521
+ observer.observe(document.body, { childList: true, subtree: true });
19522
+ return () => observer.disconnect();
19523
+ }, [isEditMode, pathname]);
19406
19524
  useEffect13(() => {
19407
19525
  const contentForNav = () => {
19408
19526
  if (isEditMode) return editContentRef.current;
@@ -20164,6 +20282,19 @@ function OhhwellsBridge() {
20164
20282
  const handleMouseOver = (e) => {
20165
20283
  if (document.documentElement.hasAttribute("data-ohw-section-picking")) return;
20166
20284
  const target = e.target;
20285
+ if (isNavDrawerOpen() && isPointOutsideOpenDrawer(e.clientX, e.clientY)) {
20286
+ document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
20287
+ hoveredItemElRef.current = null;
20288
+ setHoveredItemRect(null);
20289
+ hoveredNavContainerRef.current = null;
20290
+ setHoveredNavContainerRect(null);
20291
+ formHoverElRef.current = null;
20292
+ setFormHoverRect(null);
20293
+ siblingHintElRef.current = null;
20294
+ setSiblingHintRect(null);
20295
+ setSiblingHintRects([]);
20296
+ return;
20297
+ }
20167
20298
  if (linkPopoverOpenRef.current) {
20168
20299
  hoveredItemElRef.current = null;
20169
20300
  setHoveredItemRect(null);
@@ -20980,6 +21111,26 @@ function OhhwellsBridge() {
20980
21111
  const handleMouseMove = (e) => {
20981
21112
  const { clientX, clientY } = e;
20982
21113
  if (pointOwnedByFloatingPanel(clientX, clientY)) return;
21114
+ if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) {
21115
+ document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
21116
+ formHoverElRef.current = null;
21117
+ setFormHoverRect(null);
21118
+ hoveredItemElRef.current = null;
21119
+ setHoveredItemRect(null);
21120
+ hoveredNavContainerRef.current = null;
21121
+ setHoveredNavContainerRect(null);
21122
+ dismissImageHover();
21123
+ if (hoveredGapRef.current) {
21124
+ hoveredGapRef.current = null;
21125
+ setSectionGap(null);
21126
+ }
21127
+ if (activeStateElRef.current) {
21128
+ activeStateElRef.current.removeAttribute("data-ohw-state-hovered");
21129
+ activeStateElRef.current = null;
21130
+ setToggleState(null);
21131
+ }
21132
+ return;
21133
+ }
20983
21134
  if (isOverEditorChrome(clientX, clientY)) {
20984
21135
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
20985
21136
  formHoverElRef.current = null;
@@ -21001,6 +21152,7 @@ function OhhwellsBridge() {
21001
21152
  const { clientX, clientY } = e.data;
21002
21153
  if (typeof clientX !== "number" || typeof clientY !== "number") return;
21003
21154
  if (pointOwnedByFloatingPanel(clientX, clientY)) return;
21155
+ if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) return;
21004
21156
  if (probeSocialsRowAt(clientX, clientY)) return;
21005
21157
  probeSectionGapAt(clientX, clientY);
21006
21158
  probeImageAt(clientX, clientY);
@@ -22696,7 +22848,7 @@ function OhhwellsBridge() {
22696
22848
  postToParent2({
22697
22849
  type: "ow:ready",
22698
22850
  version: "1",
22699
- bridgeVersion: "0.1.113",
22851
+ bridgeVersion: "0.1.114",
22700
22852
  path: pathname,
22701
22853
  nodes: collectEditableNodes(editContentRef.current),
22702
22854
  sections