@ohhwells/bridge 0.1.113-next.295 → 0.1.113-next.297

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
@@ -778,6 +778,8 @@ function applyStylesToDom(store) {
778
778
  if (isNavbar) {
779
779
  const drawer = document.querySelector("[data-ohw-nav-drawer]");
780
780
  if (drawer && !sections.includes(drawer)) sections.push(drawer);
781
+ const header = document.querySelector("[data-ohw-nav-root]");
782
+ if (header && !sections.includes(header)) sections.push(header);
781
783
  }
782
784
  for (const marker of Array.from(sections)) {
783
785
  const isDrawerMarker = isNavbar && marker.hasAttribute("data-ohw-nav-drawer");
@@ -9100,6 +9102,7 @@ function MediaOverlay({
9100
9102
  fadingOut = false,
9101
9103
  selected = false,
9102
9104
  hovered = false,
9105
+ cueOnly = false,
9103
9106
  onFadeOutComplete,
9104
9107
  onReplace,
9105
9108
  onSelect,
@@ -9108,7 +9111,7 @@ function MediaOverlay({
9108
9111
  const { rect } = hover;
9109
9112
  const skeletonRef = React8.useRef(null);
9110
9113
  const isVideo = hover.elementType === "video";
9111
- const showChrome = !selected || hovered;
9114
+ const showChrome = (!selected || hovered) && !cueOnly;
9112
9115
  const autoplay = hover.videoAutoplay ?? true;
9113
9116
  const muted = hover.videoMuted ?? true;
9114
9117
  const probeRef = React8.useRef(null);
@@ -9225,7 +9228,7 @@ function MediaOverlay({
9225
9228
  // parent this needed a whole `ow:click-at` round-trip to re-hit-test inside the iframe;
9226
9229
  // in-document, pointer-events does it natively. The button below opts back in, so
9227
9230
  // Replace still works.
9228
- pointerEvents: hover.hasTextOverlap ? "none" : "auto",
9231
+ pointerEvents: hover.hasTextOverlap || cueOnly ? "none" : "auto",
9229
9232
  // Selected: a firm component ring with no wash, so the image reads as chosen rather
9230
9233
  // than hovered. Hover keeps the existing tinted preview.
9231
9234
  boxShadow: selected ? "inset 0 0 0 2px var(--color-bridge-primary)" : "inset 0 0 0 1.5px var(--color-bridge-primary)",
@@ -9276,7 +9279,7 @@ function MediaOverlay({
9276
9279
  justifyContent: "center"
9277
9280
  } : null,
9278
9281
  // Don't let Replace steal clicks when text (e.g. nav) sits on top of this media.
9279
- pointerEvents: hover.hasTextOverlap ? "none" : "auto"
9282
+ pointerEvents: hover.hasTextOverlap || cueOnly ? "none" : "auto"
9280
9283
  },
9281
9284
  onMouseDown: (e) => e.preventDefault(),
9282
9285
  onClick: (e) => {
@@ -9306,7 +9309,8 @@ var OVERLAY_BUTTON_STYLE2 = {
9306
9309
  };
9307
9310
  function CarouselOverlay({
9308
9311
  hover,
9309
- onEdit
9312
+ onEdit,
9313
+ cueOnly = false
9310
9314
  }) {
9311
9315
  const { rect } = hover;
9312
9316
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
@@ -9322,12 +9326,12 @@ function CarouselOverlay({
9322
9326
  width: rect.width,
9323
9327
  height: rect.height,
9324
9328
  zIndex: 2147483646,
9325
- pointerEvents: "auto",
9329
+ pointerEvents: cueOnly ? "none" : "auto",
9326
9330
  boxShadow: "inset 0 0 0 1.5px var(--color-bridge-primary)",
9327
9331
  background: "color-mix(in srgb, var(--color-bridge-primary) 20%, transparent)"
9328
9332
  },
9329
9333
  onClick: () => onEdit(hover.key),
9330
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
9334
+ children: cueOnly ? null : /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
9331
9335
  Button,
9332
9336
  {
9333
9337
  "data-ohw-carousel-overlay": "",
@@ -9518,7 +9522,8 @@ function ReviewButton({
9518
9522
  }
9519
9523
  function AiSectionOverlay({
9520
9524
  postToParent: postToParent2,
9521
- apiRef
9525
+ apiRef,
9526
+ onSelectionChange
9522
9527
  }) {
9523
9528
  const [selectedId, setSelectedId] = (0, import_react8.useState)(null);
9524
9529
  const [reviewId, setReviewId] = (0, import_react8.useState)(null);
@@ -9527,6 +9532,9 @@ function AiSectionOverlay({
9527
9532
  reviewIdRef.current = reviewId;
9528
9533
  const selectedIdRef = (0, import_react8.useRef)(null);
9529
9534
  selectedIdRef.current = selectedId;
9535
+ (0, import_react8.useEffect)(() => {
9536
+ onSelectionChange?.(selectedId);
9537
+ }, [selectedId, onSelectionChange]);
9530
9538
  const report = (0, import_react8.useCallback)(
9531
9539
  (el) => {
9532
9540
  const labelSrc = el ? sectionElementOf(el) : null;
@@ -16632,6 +16640,19 @@ function isMediaEditable(el) {
16632
16640
  const t = el.dataset.ohwEditable;
16633
16641
  return t === "image" || t === "bg-image" || t === "video";
16634
16642
  }
16643
+ var FULL_BLEED_MIN_COVERAGE = 0.98;
16644
+ function fullBleedSectionIdOf(media) {
16645
+ const section = media.closest("[data-ohw-section]");
16646
+ if (!section) return null;
16647
+ const s = section.getBoundingClientRect();
16648
+ if (s.width <= 0 || s.height <= 0) return null;
16649
+ const m = media.getBoundingClientRect();
16650
+ const overlapX = Math.min(m.right, s.right) - Math.max(m.left, s.left);
16651
+ const overlapY = Math.min(m.bottom, s.bottom) - Math.max(m.top, s.top);
16652
+ if (overlapX <= 0 || overlapY <= 0) return null;
16653
+ if (overlapX * overlapY / (s.width * s.height) < FULL_BLEED_MIN_COVERAGE) return null;
16654
+ return instanceIdOf(movableUnit(section)) || null;
16655
+ }
16635
16656
  function isIconMarkupValue(value) {
16636
16657
  return /^\s*<(svg|img)\b/i.test(value);
16637
16658
  }
@@ -17842,6 +17863,12 @@ function OhhwellsBridge() {
17842
17863
  const hoveredImageHasTextOverlapRef = (0, import_react17.useRef)(false);
17843
17864
  const dragOverElRef = (0, import_react17.useRef)(null);
17844
17865
  const [mediaHover, setMediaHover] = (0, import_react17.useState)(null);
17866
+ const [selectedAiSectionId, setSelectedAiSectionId] = (0, import_react17.useState)(null);
17867
+ const selectedAiSectionIdRef = (0, import_react17.useRef)(null);
17868
+ const handleAiSectionSelectionChange = (0, import_react17.useCallback)((id) => {
17869
+ selectedAiSectionIdRef.current = id;
17870
+ setSelectedAiSectionId(id);
17871
+ }, []);
17845
17872
  const [selectedMedia, setSelectedMedia] = (0, import_react17.useState)(null);
17846
17873
  const selectedMediaElRef = (0, import_react17.useRef)(null);
17847
17874
  const clearMediaSelection = (0, import_react17.useCallback)(() => {
@@ -20481,6 +20508,14 @@ function OhhwellsBridge() {
20481
20508
  if (isMediaEditable(editable) && !buttonOnMedia) {
20482
20509
  e.preventDefault();
20483
20510
  e.stopPropagation();
20511
+ const fullBleedSectionId = fullBleedSectionIdOf(editable);
20512
+ if (fullBleedSectionId && fullBleedSectionId !== selectedAiSectionIdRef.current) {
20513
+ clearMediaSelectionRef.current();
20514
+ deselectRef.current();
20515
+ deactivateRef.current();
20516
+ aiSectionApiRef.current?.selectFromElement(editable);
20517
+ return;
20518
+ }
20484
20519
  if (selectedMediaElRef.current === editable) {
20485
20520
  postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "", elementType: editable.dataset.ohwEditable ?? "image" });
20486
20521
  } else {
@@ -20932,6 +20967,7 @@ function OhhwellsBridge() {
20932
20967
  elementType: imgEl.dataset.ohwEditable ?? "image",
20933
20968
  hasTextOverlap,
20934
20969
  isDragOver,
20970
+ fullBleedSectionId: fullBleedSectionIdOf(imgEl),
20935
20971
  ...video ? { videoAutoplay: video.autoplay, videoMuted: video.muted } : {}
20936
20972
  });
20937
20973
  const track = imgEl.closest("[data-ohw-hover-pause]");
@@ -22796,7 +22832,11 @@ function OhhwellsBridge() {
22796
22832
  if (!key) return;
22797
22833
  const r2 = getVisibleRect(container);
22798
22834
  setCarouselHover(
22799
- (prev) => prev && prev.key === key && prev.rect.top === r2.top && prev.rect.left === r2.left && prev.rect.width === r2.width && prev.rect.height === r2.height ? prev : { key, rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height } }
22835
+ (prev) => prev && prev.key === key && prev.rect.top === r2.top && prev.rect.left === r2.left && prev.rect.width === r2.width && prev.rect.height === r2.height ? prev : {
22836
+ key,
22837
+ rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height },
22838
+ fullBleedSectionId: fullBleedSectionIdOf(container)
22839
+ }
22800
22840
  );
22801
22841
  };
22802
22842
  const applyToolbarPos = (rect) => {
@@ -23725,7 +23765,14 @@ function OhhwellsBridge() {
23725
23765
  bridgeRoot ? (0, import_react_dom5.createPortal)(
23726
23766
  /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
23727
23767
  /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
23728
- isEditMode && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
23768
+ isEditMode && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
23769
+ AiSectionOverlay,
23770
+ {
23771
+ postToParent: postToParent2,
23772
+ apiRef: aiSectionApiRef,
23773
+ onSelectionChange: handleAiSectionSelectionChange
23774
+ }
23775
+ ),
23729
23776
  isSectionDragging && sectionDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
23730
23777
  "div",
23731
23778
  {
@@ -23758,6 +23805,7 @@ function OhhwellsBridge() {
23758
23805
  {
23759
23806
  hover: mediaHover,
23760
23807
  isUploading: false,
23808
+ cueOnly: !mediaHover.isDragOver && !!mediaHover.fullBleedSectionId && mediaHover.fullBleedSectionId !== selectedAiSectionId,
23761
23809
  onReplace: handleMediaReplace,
23762
23810
  onSelect: handleMediaSelect,
23763
23811
  onVideoSettingsChange: handleVideoSettingsChange
@@ -23775,7 +23823,14 @@ function OhhwellsBridge() {
23775
23823
  onVideoSettingsChange: handleVideoSettingsChange
23776
23824
  }
23777
23825
  ),
23778
- carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
23826
+ carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
23827
+ CarouselOverlay,
23828
+ {
23829
+ hover: carouselHover,
23830
+ onEdit: handleEditCarousel,
23831
+ cueOnly: !!carouselHover.fullBleedSectionId && carouselHover.fullBleedSectionId !== selectedAiSectionId
23832
+ }
23833
+ ),
23779
23834
  siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
23780
23835
  siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
23781
23836
  isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),