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

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