@ohhwells/bridge 0.1.55-next.163 → 0.1.55-next.168

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
@@ -7192,6 +7192,47 @@ function AiSectionOverlay({
7192
7192
  ] });
7193
7193
  }
7194
7194
 
7195
+ // src/lib/section-instances.ts
7196
+ var SECTION_ORDER_KEY = "__ohw_section_order";
7197
+ function getPageSectionOrderEntries(raw, currentPath) {
7198
+ if (!raw) return [];
7199
+ try {
7200
+ const entries = JSON.parse(raw);
7201
+ return entries.filter((e) => !e.pagePath || e.pagePath === currentPath);
7202
+ } catch {
7203
+ return [];
7204
+ }
7205
+ }
7206
+ function rekeySectionSubtree(root, instanceId) {
7207
+ const suffix = `::${instanceId}`;
7208
+ const rekey = (el, attr) => {
7209
+ const current = el.getAttribute(attr);
7210
+ if (current) el.setAttribute(attr, `${current}${suffix}`);
7211
+ };
7212
+ if (root.hasAttribute("data-ohw-key")) rekey(root, "data-ohw-key");
7213
+ if (root.hasAttribute("data-ohw-href-key")) rekey(root, "data-ohw-href-key");
7214
+ root.querySelectorAll("[data-ohw-key]").forEach((el) => rekey(el, "data-ohw-key"));
7215
+ root.querySelectorAll("[data-ohw-href-key]").forEach((el) => rekey(el, "data-ohw-href-key"));
7216
+ }
7217
+ function initSectionInstancesFromContent(content, currentPath) {
7218
+ document.querySelectorAll("[data-ohw-section]:not([data-ohw-instance])").forEach((el) => {
7219
+ el.setAttribute("data-ohw-instance", el.getAttribute("data-ohw-section") ?? "");
7220
+ });
7221
+ const entries = getPageSectionOrderEntries(content[SECTION_ORDER_KEY], currentPath);
7222
+ for (const entry of entries) {
7223
+ if (entry.instanceId === entry.type) continue;
7224
+ if (document.querySelector(`[data-ohw-instance="${CSS.escape(entry.instanceId)}"]`)) continue;
7225
+ const original = document.querySelector(
7226
+ `[data-ohw-section="${CSS.escape(entry.type)}"][data-ohw-instance="${CSS.escape(entry.type)}"]`
7227
+ );
7228
+ if (!original) continue;
7229
+ const clone = original.cloneNode(true);
7230
+ clone.setAttribute("data-ohw-instance", entry.instanceId);
7231
+ rekeySectionSubtree(clone, entry.instanceId);
7232
+ original.insertAdjacentElement("afterend", clone);
7233
+ }
7234
+ }
7235
+
7195
7236
  // src/OhhwellsBridge.tsx
7196
7237
  var import_react_dom4 = require("react-dom");
7197
7238
  var import_navigation3 = require("next/navigation");
@@ -7224,10 +7265,24 @@ function isPointOverBridgeChrome(x, y) {
7224
7265
  }
7225
7266
  return false;
7226
7267
  }
7227
- function findCtaButtonAtPoint(x, y, media) {
7268
+ var BUTTON_LIKE_SELECTOR = `button, [role="button"], ${CTA_BUTTON_SELECTOR}`;
7269
+ function isButtonLikeElement(el) {
7270
+ return el.matches(BUTTON_LIKE_SELECTOR);
7271
+ }
7272
+ function findClosestButtonLike(target) {
7273
+ return target.closest(BUTTON_LIKE_SELECTOR);
7274
+ }
7275
+ function findButtonAtPoint(x, y, media) {
7228
7276
  const hits = Array.from(
7229
- document.querySelectorAll(CTA_BUTTON_SELECTOR)
7230
- ).filter((el) => containsPoint(el, x, y) && !(media && el.contains(media)));
7277
+ document.querySelectorAll(BUTTON_LIKE_SELECTOR)
7278
+ ).filter(
7279
+ (el) => containsPoint(el, x, y) && !(media && el.contains(media)) && // Bridge-injected chrome (e.g. MediaOverlay's own "Replace image" button) is never a
7280
+ // site button. Without this, once the media overlay renders its button lands right
7281
+ // under the cursor, gets detected as "a button on the media", and dismisses the very
7282
+ // overlay it belongs to — which removes the button, so the next hit-test finds nothing
7283
+ // and the overlay reappears. Flip-flops every tick: the "Replace image" button flashes.
7284
+ !el.closest("[data-ohw-bridge]")
7285
+ );
7231
7286
  if (hits.length === 0) return null;
7232
7287
  return hits.reduce((best, el) => best.contains(el) ? el : best);
7233
7288
  }
@@ -15577,6 +15632,7 @@ function OhhwellsBridge() {
15577
15632
  applySocialsDisplayFromContent(content);
15578
15633
  enforceLinkHrefs();
15579
15634
  initSectionsFromContent(content, true);
15635
+ initSectionInstancesFromContent(content, window.location.pathname);
15580
15636
  sectionsLoadedRef.current = true;
15581
15637
  pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
15582
15638
  return imageLoads.length > 0 ? Promise.all(imageLoads).then(() => {
@@ -15613,6 +15669,7 @@ function OhhwellsBridge() {
15613
15669
  const content = contentCache.get(subdomain);
15614
15670
  if (!content) return;
15615
15671
  retryMissingSchedulingMounts(getPageSchedulingEntries(content["__ohw_sections"]), false);
15672
+ initSectionInstancesFromContent(content, window.location.pathname);
15616
15673
  observer?.disconnect();
15617
15674
  try {
15618
15675
  applyBrandChrome(content);
@@ -16049,14 +16106,17 @@ function OhhwellsBridge() {
16049
16106
  });
16050
16107
  return;
16051
16108
  }
16052
- if (isMediaEditable(editable)) {
16109
+ const clickedButton = findClosestButtonLike(target);
16110
+ const buttonOnMedia = Boolean(clickedButton && isMediaEditable(editable) && editable.contains(clickedButton));
16111
+ if (isMediaEditable(editable) && !buttonOnMedia) {
16053
16112
  e.preventDefault();
16054
16113
  e.stopPropagation();
16055
16114
  aiSectionApiRef.current?.selectFromElement(editable);
16056
16115
  postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "", elementType: editable.dataset.ohwEditable ?? "image" });
16057
16116
  return;
16058
16117
  }
16059
- const hrefCtx = getHrefKeyFromElement(editable);
16118
+ const hrefLookupTarget = buttonOnMedia ? clickedButton : editable;
16119
+ const hrefCtx = getHrefKeyFromElement(hrefLookupTarget);
16060
16120
  const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
16061
16121
  if (navAnchor) {
16062
16122
  e.preventDefault();
@@ -16064,7 +16124,8 @@ function OhhwellsBridge() {
16064
16124
  if (selectedElRef.current === navAnchor) {
16065
16125
  if (e.detail >= 2) return;
16066
16126
  if (requestSocialDialog(navAnchor, postToParentRef.current, editContentRef.current)) return;
16067
- activateRef.current(editable, { caretX: e.clientX, caretY: e.clientY });
16127
+ const activateTarget = isButtonLikeElement(hrefLookupTarget) ? navAnchor.querySelector('[data-ohw-editable="text"]') ?? hrefLookupTarget : hrefLookupTarget;
16128
+ activateRef.current(activateTarget, { caretX: e.clientX, caretY: e.clientY });
16068
16129
  return;
16069
16130
  }
16070
16131
  selectRef.current(navAnchor);
@@ -16072,7 +16133,7 @@ function OhhwellsBridge() {
16072
16133
  }
16073
16134
  e.preventDefault();
16074
16135
  e.stopPropagation();
16075
- activateRef.current(editable, { caretX: e.clientX, caretY: e.clientY });
16136
+ activateRef.current(hrefLookupTarget, { caretX: e.clientX, caretY: e.clientY });
16076
16137
  return;
16077
16138
  }
16078
16139
  const hrefAnchor = getNavigationItemAnchor(target);
@@ -16667,15 +16728,15 @@ function OhhwellsBridge() {
16667
16728
  dismissImageHover();
16668
16729
  return;
16669
16730
  }
16670
- const ctaHit = isDragOver ? null : findCtaButtonAtPoint(x2, y2, imgEl);
16671
- if (ctaHit) {
16731
+ const buttonHit = isDragOver ? null : findButtonAtPoint(x2, y2, imgEl);
16732
+ if (buttonHit) {
16672
16733
  dismissImageHover();
16673
16734
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
16674
16735
  const selected = selectedElRef.current;
16675
- if (selected !== ctaHit && !selected?.contains(ctaHit)) {
16676
- clearHrefKeyHover(ctaHit);
16677
- hoveredItemElRef.current = ctaHit;
16678
- setHoveredItemRect(ctaHit.getBoundingClientRect());
16736
+ if (selected !== buttonHit && !selected?.contains(buttonHit)) {
16737
+ clearHrefKeyHover(buttonHit);
16738
+ hoveredItemElRef.current = buttonHit;
16739
+ setHoveredItemRect(buttonHit.getBoundingClientRect());
16679
16740
  }
16680
16741
  return;
16681
16742
  }
@@ -17234,6 +17295,7 @@ function OhhwellsBridge() {
17234
17295
  sectionsLoadedRef.current = true;
17235
17296
  pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
17236
17297
  }
17298
+ initSectionInstancesFromContent(content, window.location.pathname);
17237
17299
  editContentRef.current = { ...editContentRef.current, ...content };
17238
17300
  reconcileNavbarItemsFromContent(editContentRef.current);
17239
17301
  reconcileFooterOrderFromContent(editContentRef.current);