@ohhwells/bridge 0.1.55-next.161 → 0.1.55-next.165

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,9 +7265,16 @@ 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)
7277
+ document.querySelectorAll(BUTTON_LIKE_SELECTOR)
7230
7278
  ).filter((el) => containsPoint(el, x, y) && !(media && el.contains(media)));
7231
7279
  if (hits.length === 0) return null;
7232
7280
  return hits.reduce((best, el) => best.contains(el) ? el : best);
@@ -9802,6 +9850,10 @@ function isSocialsRow(el) {
9802
9850
  const anchors = Array.from(el.querySelectorAll("a"));
9803
9851
  return anchors.length > 0 && anchors.every((anchor) => isSocialItem(anchor));
9804
9852
  }
9853
+ var MAX_SOCIAL_ITEMS_PER_ROW = 7;
9854
+ function canAddSocialItem(row) {
9855
+ return listSocialItems(row).length < MAX_SOCIAL_ITEMS_PER_ROW;
9856
+ }
9805
9857
  function listSocialItems(row) {
9806
9858
  return Array.from(row.children).map((child) => {
9807
9859
  if (!(child instanceof HTMLElement)) return null;
@@ -14709,6 +14761,14 @@ function OhhwellsBridge() {
14709
14761
  if (!selected) return;
14710
14762
  const socialsRow = isSocialsRow(selected) ? selected : findSocialsRow(selected);
14711
14763
  if (socialsRow) {
14764
+ if (!canAddSocialItem(socialsRow)) {
14765
+ postToParent2({
14766
+ type: "ow:toast",
14767
+ title: `Maximum ${MAX_SOCIAL_ITEMS_PER_ROW} social icons`,
14768
+ toastType: "error"
14769
+ });
14770
+ return;
14771
+ }
14712
14772
  const after = getSocialItem(selected);
14713
14773
  const result2 = insertSocialItem(socialsRow, after, editContentRef.current);
14714
14774
  if (!result2) return;
@@ -15565,6 +15625,7 @@ function OhhwellsBridge() {
15565
15625
  applySocialsDisplayFromContent(content);
15566
15626
  enforceLinkHrefs();
15567
15627
  initSectionsFromContent(content, true);
15628
+ initSectionInstancesFromContent(content, window.location.pathname);
15568
15629
  sectionsLoadedRef.current = true;
15569
15630
  pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
15570
15631
  return imageLoads.length > 0 ? Promise.all(imageLoads).then(() => {
@@ -15601,6 +15662,7 @@ function OhhwellsBridge() {
15601
15662
  const content = contentCache.get(subdomain);
15602
15663
  if (!content) return;
15603
15664
  retryMissingSchedulingMounts(getPageSchedulingEntries(content["__ohw_sections"]), false);
15665
+ initSectionInstancesFromContent(content, window.location.pathname);
15604
15666
  observer?.disconnect();
15605
15667
  try {
15606
15668
  applyBrandChrome(content);
@@ -16037,14 +16099,17 @@ function OhhwellsBridge() {
16037
16099
  });
16038
16100
  return;
16039
16101
  }
16040
- if (isMediaEditable(editable)) {
16102
+ const clickedButton = findClosestButtonLike(target);
16103
+ const buttonOnMedia = Boolean(clickedButton && isMediaEditable(editable) && editable.contains(clickedButton));
16104
+ if (isMediaEditable(editable) && !buttonOnMedia) {
16041
16105
  e.preventDefault();
16042
16106
  e.stopPropagation();
16043
16107
  aiSectionApiRef.current?.selectFromElement(editable);
16044
16108
  postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "", elementType: editable.dataset.ohwEditable ?? "image" });
16045
16109
  return;
16046
16110
  }
16047
- const hrefCtx = getHrefKeyFromElement(editable);
16111
+ const hrefLookupTarget = buttonOnMedia ? clickedButton : editable;
16112
+ const hrefCtx = getHrefKeyFromElement(hrefLookupTarget);
16048
16113
  const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
16049
16114
  if (navAnchor) {
16050
16115
  e.preventDefault();
@@ -16052,7 +16117,8 @@ function OhhwellsBridge() {
16052
16117
  if (selectedElRef.current === navAnchor) {
16053
16118
  if (e.detail >= 2) return;
16054
16119
  if (requestSocialDialog(navAnchor, postToParentRef.current, editContentRef.current)) return;
16055
- activateRef.current(editable, { caretX: e.clientX, caretY: e.clientY });
16120
+ const activateTarget = isButtonLikeElement(hrefLookupTarget) ? navAnchor.querySelector('[data-ohw-editable="text"]') ?? hrefLookupTarget : hrefLookupTarget;
16121
+ activateRef.current(activateTarget, { caretX: e.clientX, caretY: e.clientY });
16056
16122
  return;
16057
16123
  }
16058
16124
  selectRef.current(navAnchor);
@@ -16060,7 +16126,7 @@ function OhhwellsBridge() {
16060
16126
  }
16061
16127
  e.preventDefault();
16062
16128
  e.stopPropagation();
16063
- activateRef.current(editable, { caretX: e.clientX, caretY: e.clientY });
16129
+ activateRef.current(hrefLookupTarget, { caretX: e.clientX, caretY: e.clientY });
16064
16130
  return;
16065
16131
  }
16066
16132
  const hrefAnchor = getNavigationItemAnchor(target);
@@ -16655,15 +16721,15 @@ function OhhwellsBridge() {
16655
16721
  dismissImageHover();
16656
16722
  return;
16657
16723
  }
16658
- const ctaHit = isDragOver ? null : findCtaButtonAtPoint(x2, y2, imgEl);
16659
- if (ctaHit) {
16724
+ const buttonHit = isDragOver ? null : findButtonAtPoint(x2, y2, imgEl);
16725
+ if (buttonHit) {
16660
16726
  dismissImageHover();
16661
16727
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
16662
16728
  const selected = selectedElRef.current;
16663
- if (selected !== ctaHit && !selected?.contains(ctaHit)) {
16664
- clearHrefKeyHover(ctaHit);
16665
- hoveredItemElRef.current = ctaHit;
16666
- setHoveredItemRect(ctaHit.getBoundingClientRect());
16729
+ if (selected !== buttonHit && !selected?.contains(buttonHit)) {
16730
+ clearHrefKeyHover(buttonHit);
16731
+ hoveredItemElRef.current = buttonHit;
16732
+ setHoveredItemRect(buttonHit.getBoundingClientRect());
16667
16733
  }
16668
16734
  return;
16669
16735
  }
@@ -17222,6 +17288,7 @@ function OhhwellsBridge() {
17222
17288
  sectionsLoadedRef.current = true;
17223
17289
  pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
17224
17290
  }
17291
+ initSectionInstancesFromContent(content, window.location.pathname);
17225
17292
  editContentRef.current = { ...editContentRef.current, ...content };
17226
17293
  reconcileNavbarItemsFromContent(editContentRef.current);
17227
17294
  reconcileFooterOrderFromContent(editContentRef.current);
@@ -18714,7 +18781,10 @@ function OhhwellsBridge() {
18714
18781
  onSelectParent: handleSelectParent,
18715
18782
  onDuplicate: handleDuplicateSelected,
18716
18783
  onDelete: handleDeleteSelected,
18717
- addItemDisabled: isFooterFrameSelection && isFooterAddItemDisabled(selectedElRef.current),
18784
+ addItemDisabled: isFooterFrameSelection && isFooterAddItemDisabled(selectedElRef.current) || selectedElRef.current !== null && (() => {
18785
+ const row = isSocialsRow(selectedElRef.current) ? selectedElRef.current : findSocialsRow(selectedElRef.current);
18786
+ return row ? !canAddSocialItem(row) : false;
18787
+ })(),
18718
18788
  editLinkDisabled: false,
18719
18789
  moreDisabled: false,
18720
18790
  duplicateDisabled: isFooterFrameSelection || selectedIsSocialsRow,