@ohhwells/bridge 0.1.69-next.208 → 0.1.70-next.210

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
@@ -1927,6 +1927,17 @@ function applyAiSectionsToDom(state, options) {
1927
1927
  });
1928
1928
  mounted.set(entry.id, { root, container, serialized });
1929
1929
  }
1930
+ if (state.hideTemplate === true) {
1931
+ let prev = null;
1932
+ for (const entry of pageSections) {
1933
+ const el = mounted.get(entry.id)?.container;
1934
+ if (!el) continue;
1935
+ if (prev && !(prev.compareDocumentPosition(el) & Node.DOCUMENT_POSITION_FOLLOWING)) {
1936
+ prev.insertAdjacentElement("afterend", el);
1937
+ }
1938
+ prev = el;
1939
+ }
1940
+ }
1930
1941
  syncReplacedOriginals(state);
1931
1942
  syncRemovedSections(state);
1932
1943
  syncTemplateHidden(state, pageSections.length > 0);
@@ -10852,11 +10863,15 @@ function referenceBox(slot) {
10852
10863
  }
10853
10864
  function iconMarkupSizedFor(slot, markup) {
10854
10865
  const box = referenceBox(slot);
10855
- if (!box) return markup;
10856
10866
  const holder = document.createElement("div");
10857
10867
  holder.innerHTML = markup;
10858
10868
  const glyph = holder.querySelector(GLYPH_SELECTOR);
10859
10869
  if (!glyph) return markup;
10870
+ if (!box) {
10871
+ glyph.style.width = "1.5em";
10872
+ glyph.style.height = "1.5em";
10873
+ return holder.innerHTML;
10874
+ }
10860
10875
  glyph.style.width = `${Math.round(box.width)}px`;
10861
10876
  glyph.style.height = `${Math.round(box.height)}px`;
10862
10877
  return holder.innerHTML;
@@ -10900,39 +10915,58 @@ function iconMarkupInheritingColour(markup) {
10900
10915
 
10901
10916
  // src/lib/socials-items.ts
10902
10917
  var ICON_SELECTOR = '[data-ohw-editable="icon"]';
10918
+ var PLACEHOLDER_SOCIAL_ICON = '<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/><path d="M2 12h20"/></svg>';
10919
+ var PLACEHOLDER_SOCIAL_LABEL = "Social";
10903
10920
  var SOCIAL_KEY_RE = /(^|-)social(s)?(-|$)/i;
10921
+ var SOCIAL_PLATFORM_KEY_RE = /(^|-)(instagram|facebook|fb|linkedin|twitter|tiktok|youtube|threads|whatsapp|telegram|pinterest|snapchat|discord|behance|dribbble|vimeo|spotify|github|reddit|medium|twitch)(-|$)/i;
10904
10922
  var SOCIALS_ROW_ATTR = "data-ohw-socials-row";
10905
10923
  var SOCIALS_ITEM_ATTR = "data-ohw-social-item";
10906
10924
  function isSocialItem(el) {
10907
10925
  if (!el) return false;
10908
10926
  const anchor = el instanceof HTMLAnchorElement ? el : el.closest("a");
10909
10927
  if (!anchor) return false;
10910
- if (SOCIAL_KEY_RE.test(anchor.getAttribute("data-ohw-href-key") ?? "")) return true;
10928
+ const hrefKey = anchor.getAttribute("data-ohw-href-key") ?? "";
10929
+ if (SOCIAL_KEY_RE.test(hrefKey) || SOCIAL_PLATFORM_KEY_RE.test(hrefKey)) return true;
10911
10930
  return anchor.querySelectorAll(ICON_SELECTOR).length === 1;
10912
10931
  }
10913
10932
  function getSocialItem(el) {
10914
10933
  const anchor = el.closest("a");
10915
10934
  return isSocialItem(anchor) ? anchor : null;
10916
10935
  }
10936
+ function isPerItemWrapper(wrapper) {
10937
+ if (wrapper.matches("li")) return true;
10938
+ if (!wrapper.matches("div, span")) return false;
10939
+ const siblings = Array.from(wrapper.parentElement?.children ?? []).filter(
10940
+ (child) => child instanceof HTMLElement && child.querySelectorAll("a").length === 1
10941
+ );
10942
+ return siblings.length > 1;
10943
+ }
10917
10944
  function findSocialsRow(el) {
10918
10945
  const item = getSocialItem(el);
10919
10946
  if (!item) return null;
10947
+ const marked = item.closest(`[${SOCIALS_ROW_ATTR}]`);
10948
+ if (marked) return marked;
10920
10949
  const wrapper = item.parentElement;
10921
- const row = wrapper && wrapper.querySelectorAll("a").length === 1 && wrapper.matches("li, div, span") ? wrapper.parentElement : wrapper;
10950
+ const row = wrapper && isPerItemWrapper(wrapper) ? wrapper.parentElement : wrapper;
10922
10951
  if (!row) return null;
10923
10952
  const anchors = Array.from(row.querySelectorAll("a"));
10924
10953
  if (!anchors.length || !anchors.every((anchor) => isSocialItem(anchor))) return null;
10925
10954
  return row;
10926
10955
  }
10927
10956
  function isSocialsRow(el) {
10957
+ if (el.hasAttribute(SOCIALS_ROW_ATTR)) return true;
10928
10958
  const anchors = Array.from(el.querySelectorAll("a"));
10929
10959
  if (!anchors.length || !anchors.some((anchor) => isSocialItem(anchor))) return false;
10930
10960
  return findSocialsRow(anchors[0]) === el;
10931
10961
  }
10932
- var MAX_SOCIAL_ITEMS_PER_ROW = 7;
10962
+ var MAX_SOCIAL_ITEMS_PER_ROW = 14;
10933
10963
  function canAddSocialItem(row) {
10934
10964
  return listSocialItems(row).length < MAX_SOCIAL_ITEMS_PER_ROW;
10935
10965
  }
10966
+ function canRemoveSocialItem(item) {
10967
+ const row = findSocialsRow(item);
10968
+ return row ? listSocialItems(row).length > 1 : false;
10969
+ }
10936
10970
  function listSocialItems(row) {
10937
10971
  return Array.from(row.children).map((child) => {
10938
10972
  if (!(child instanceof HTMLElement)) return null;
@@ -11026,8 +11060,10 @@ function fromMarkup(markup) {
11026
11060
  var rowKeys = /* @__PURE__ */ new WeakMap();
11027
11061
  function rowKeyOf(row) {
11028
11062
  const first = listSocialItems(row)[0];
11029
- const itemKey = first ? socialIconKey(first) ?? socialHrefKey(first)?.replace(/-href$/, "") : null;
11030
- const derived = itemKey?.replace(/-[^-]+$/, "") || null;
11063
+ const itemKey = first ? socialIconKey(first)?.replace(/-icon$/, "") ?? socialHrefKey(first)?.replace(/-href$/, "") : null;
11064
+ const withoutItem = itemKey?.replace(/-[^-]+$/, "") || null;
11065
+ const lastSegment = itemKey?.match(/[^-]+$/)?.[0] ?? "";
11066
+ const derived = withoutItem ? SOCIAL_PLATFORM_KEY_RE.test(lastSegment) ? `${withoutItem}-socials` : withoutItem : null;
11031
11067
  if (derived) rowKeys.set(row, derived);
11032
11068
  return derived ?? rowKeys.get(row) ?? "social";
11033
11069
  }
@@ -11055,7 +11091,13 @@ function nextSocialIndex(row, rowKey, content) {
11055
11091
  const used = listSocialItems(row).map((item) => socialHrefKey(item)).concat(Object.keys(content)).map((key) => key?.match(new RegExp(`^${rowKey}-(\\d+)`))?.[1]).map((digits) => digits === void 0 ? -1 : Number(digits));
11056
11092
  return Math.max(-1, ...used) + 1;
11057
11093
  }
11058
- function insertSocialItem(row, after, content = {}) {
11094
+ function planSocialInsert(row, content = {}) {
11095
+ if (!canAddSocialItem(row)) return null;
11096
+ const rowKey = rowKeyOf(row);
11097
+ const iconKey = `${rowKey}-${nextSocialIndex(row, rowKey, content)}`;
11098
+ return { hrefKey: `${iconKey}-href`, iconKey };
11099
+ }
11100
+ function insertSocialItem(row, after, content = {}, { placeholder = true } = {}) {
11059
11101
  const rowKey = rowKeyOf(row);
11060
11102
  const template = listSocialItems(row)[0];
11061
11103
  const remembered = rowTemplates.get(rowKey);
@@ -11076,16 +11118,23 @@ function insertSocialItem(row, after, content = {}) {
11076
11118
  });
11077
11119
  const icon = item.querySelector(ICON_SELECTOR);
11078
11120
  icon?.setAttribute("data-ohw-key", iconKey);
11121
+ if (placeholder && icon) icon.innerHTML = PLACEHOLDER_SOCIAL_ICON;
11079
11122
  item.querySelector(`[${SOCIALS_LABEL_ATTR}]`)?.remove();
11080
11123
  const afterUnit = after ? socialRowUnit(after) : null;
11081
11124
  if (afterUnit && afterUnit.parentElement === row) afterUnit.insertAdjacentElement("afterend", unit);
11082
11125
  else row.appendChild(unit);
11083
11126
  markSocialsRows(row.ownerDocument);
11127
+ if (placeholder) {
11128
+ const label = socialLabelElement(item);
11129
+ if (label && !label.textContent?.trim()) label.textContent = PLACEHOLDER_SOCIAL_LABEL;
11130
+ }
11131
+ applySocialsDisplayToRow(row, socialsDisplayFor(row, content));
11084
11132
  return { item, hrefKey, iconKey, order: getSocialsOrderFromDom(row.ownerDocument) };
11085
11133
  }
11086
11134
  function duplicateSocialItem(item, content) {
11087
11135
  const row = findSocialsRow(item);
11088
- const created = row ? insertSocialItem(row, item, content) : null;
11136
+ if (row && !canAddSocialItem(row)) return null;
11137
+ const created = row ? insertSocialItem(row, item, content, { placeholder: false }) : null;
11089
11138
  if (!created) return null;
11090
11139
  const sourceHref = socialHrefKey(item);
11091
11140
  const sourceIcon = socialIconKey(item);
@@ -11096,14 +11145,19 @@ function duplicateSocialItem(item, content) {
11096
11145
  const slot = link.querySelector(ICON_SELECTOR);
11097
11146
  if (slot) slot.innerHTML = glyph;
11098
11147
  }
11148
+ const sourceLabel = socialLabelElement(item)?.textContent?.trim();
11149
+ const copyLabel = socialLabelElement(link);
11150
+ if (copyLabel && sourceLabel) copyLabel.textContent = sourceLabel;
11151
+ if (row) applySocialsDisplayToRow(row, socialsDisplayFor(row, content));
11099
11152
  return {
11100
11153
  ...created,
11101
11154
  copiedFrom: { href: sourceHref, icon: sourceIcon }
11102
11155
  };
11103
11156
  }
11104
- function removeSocialItem(item, content) {
11157
+ function removeSocialItem(item, content, { allowLast = false } = {}) {
11105
11158
  const row = findSocialsRow(item);
11106
11159
  if (!row) return null;
11160
+ if (!allowLast && !canRemoveSocialItem(item)) return null;
11107
11161
  const hrefKey = socialHrefKey(item);
11108
11162
  const iconKey = socialIconKey(item);
11109
11163
  const removedKeys = [hrefKey, iconKey].filter((key) => Boolean(key));
@@ -11301,14 +11355,19 @@ function applySocialsDisplayFromContent(content, root = document) {
11301
11355
  });
11302
11356
  }
11303
11357
  function socialsMissingIcons(row) {
11304
- return listSocialItems(row).filter((item) => !item.querySelector(ICON_SELECTOR)).map((item) => ({ hrefKey: socialHrefKey(item) ?? "", url: item.getAttribute("href") ?? "" })).filter((entry) => Boolean(entry.hrefKey));
11358
+ return listSocialItems(row).filter((item) => {
11359
+ const slot = item.querySelector(ICON_SELECTOR);
11360
+ return !slot || !slot.firstElementChild;
11361
+ }).map((item) => ({ hrefKey: socialHrefKey(item) ?? "", url: item.getAttribute("href") ?? "" })).filter((entry) => Boolean(entry.hrefKey));
11305
11362
  }
11306
11363
  function ensureIconSlot(item) {
11307
11364
  const existing = item.querySelector(ICON_SELECTOR);
11308
11365
  if (existing) return existing.dataset.ohwKey ?? null;
11309
11366
  const hrefKey = socialHrefKey(item);
11310
11367
  if (!hrefKey) return null;
11311
- const iconKey = hrefKey.replace(/-href$/, "");
11368
+ const base = hrefKey.replace(/-href$/, "");
11369
+ const taken = document.querySelector(`[data-ohw-key="${base}"]`);
11370
+ const iconKey = taken && taken !== item ? `${base}-icon` : base;
11312
11371
  const slot = document.createElement("span");
11313
11372
  slot.setAttribute("data-ohw-key", iconKey);
11314
11373
  slot.setAttribute("data-ohw-editable", "icon");
@@ -14590,6 +14649,9 @@ function isMediaEditable(el) {
14590
14649
  const t = el.dataset.ohwEditable;
14591
14650
  return t === "image" || t === "bg-image" || t === "video";
14592
14651
  }
14652
+ function isIconMarkupValue(value) {
14653
+ return /^\s*<(svg|img)\b/i.test(value);
14654
+ }
14593
14655
  function isIconEditable(el) {
14594
14656
  return el.dataset.ohwEditable === "icon";
14595
14657
  }
@@ -16441,6 +16503,7 @@ function OhhwellsBridge() {
16441
16503
  setNavGroupForceOpen(anchor, true);
16442
16504
  activateRef.current(label);
16443
16505
  }, []);
16506
+ const pendingSocialAddRef = (0, import_react17.useRef)(null);
16444
16507
  const handleAddChildItem = (0, import_react17.useCallback)(() => {
16445
16508
  const selected = selectedElRef.current;
16446
16509
  if (!selected) return;
@@ -16455,21 +16518,17 @@ function OhhwellsBridge() {
16455
16518
  return;
16456
16519
  }
16457
16520
  const after = getSocialItem(selected);
16458
- const result2 = insertSocialItem(socialsRow, after, editContentRef.current);
16459
- if (!result2) return;
16460
- const orderJson = JSON.stringify(result2.order);
16461
- applySocialsDisplayToRow(socialsRow, socialsDisplayFor(socialsRow, editContentRef.current));
16462
- editContentRef.current = { ...editContentRef.current, [SOCIALS_ORDER_KEY]: orderJson };
16463
- postToParent2({ type: "ow:change", nodes: [{ key: SOCIALS_ORDER_KEY, text: orderJson }] });
16521
+ const planned = planSocialInsert(socialsRow, editContentRef.current);
16522
+ if (!planned) return;
16523
+ pendingSocialAddRef.current = { row: socialsRow, after, ...planned };
16464
16524
  postToParentRef.current({
16465
16525
  type: "ow:social-pick",
16466
- hrefKey: result2.hrefKey,
16467
- iconKey: result2.iconKey,
16526
+ hrefKey: planned.hrefKey,
16527
+ iconKey: planned.iconKey,
16468
16528
  url: "",
16469
- iconStyle: detectIconStyle(result2.item),
16529
+ iconStyle: detectIconStyle(getSocialItem(selected) ?? socialsRow),
16470
16530
  platformId: "",
16471
- // Lets the editor undo the insert if the dialog is dismissed: an item that was never given
16472
- // an address should not survive a Cancel.
16531
+ // Tells the editor this one is not on the page yet, so dismissing means "never mind".
16473
16532
  isNew: true
16474
16533
  });
16475
16534
  return;
@@ -17061,6 +17120,19 @@ function OhhwellsBridge() {
17061
17120
  row
17062
17121
  });
17063
17122
  }, []);
17123
+ const isEditModeRef = (0, import_react17.useRef)(false);
17124
+ const requestMissingSocialIconsRef = (0, import_react17.useRef)(() => {
17125
+ });
17126
+ const requestMissingSocialIcons = (0, import_react17.useCallback)(() => {
17127
+ const items = Array.from(document.querySelectorAll(`[${SOCIALS_ROW_ATTR}]`)).filter((row) => socialsDisplayFor(row, editContentRef.current).icon).flatMap((row) => {
17128
+ const missing = socialsMissingIcons(row);
17129
+ listSocialItems(row).forEach((item) => ensureIconSlot(item));
17130
+ return missing;
17131
+ });
17132
+ if (items.length) postToParentRef.current({ type: "ow:social-icons-needed", items });
17133
+ }, []);
17134
+ requestMissingSocialIconsRef.current = requestMissingSocialIcons;
17135
+ isEditModeRef.current = isEditMode;
17064
17136
  const changeSocialsDisplay = (0, import_react17.useCallback)(
17065
17137
  (row, next) => {
17066
17138
  if (next.icon) {
@@ -17321,6 +17393,7 @@ function OhhwellsBridge() {
17321
17393
  } else if (el.dataset.ohwEditable === "icon") {
17322
17394
  applyIconMarkup(el, val);
17323
17395
  } else if (el.dataset.ohwEditable === "form") {
17396
+ } else if (isIconMarkupValue(val)) {
17324
17397
  } else if (el.innerHTML !== val) {
17325
17398
  el.innerHTML = val;
17326
17399
  }
@@ -17333,6 +17406,7 @@ function OhhwellsBridge() {
17333
17406
  reconcileFooterOrderFromContent(content);
17334
17407
  reconcileSocialsFromContent(content);
17335
17408
  applySocialsDisplayFromContent(content);
17409
+ if (isEditModeRef.current) requestMissingSocialIconsRef.current();
17336
17410
  enforceLinkHrefs();
17337
17411
  initSectionsFromContent(content, true);
17338
17412
  initSectionInstancesFromContent(content, window.location.pathname);
@@ -17475,11 +17549,15 @@ function OhhwellsBridge() {
17475
17549
  if (typeof content[BRAND_KIT_KEY] === "string") {
17476
17550
  applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
17477
17551
  }
17552
+ if (typeof content[AI_SECTIONS_KEY] === "string") {
17553
+ applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
17554
+ }
17478
17555
  if (typeof content[STYLE_STORE_KEY] === "string") {
17479
17556
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
17480
17557
  }
17481
17558
  for (const [key, val] of Object.entries(content)) {
17482
17559
  if (key === "__ohw_sections") continue;
17560
+ if (key === AI_SECTIONS_KEY) continue;
17483
17561
  if (key === LOGO_PLACEHOLDER_KEY) continue;
17484
17562
  if (LOGO_IMAGE_KEYS.includes(key)) continue;
17485
17563
  if (key === BRAND_KIT_KEY) continue;
@@ -17501,6 +17579,7 @@ function OhhwellsBridge() {
17501
17579
  } else if (el.dataset.ohwEditable === "link") {
17502
17580
  applyLinkHref(el, val);
17503
17581
  } else if (el.dataset.ohwEditable === "form") {
17582
+ } else if (isIconMarkupValue(val)) {
17504
17583
  } else if (el.innerHTML !== val) {
17505
17584
  el.innerHTML = val;
17506
17585
  }
@@ -17512,6 +17591,7 @@ function OhhwellsBridge() {
17512
17591
  reconcileFooterOrderFromContent(content);
17513
17592
  reconcileSocialsFromContent(content);
17514
17593
  applySocialsDisplayFromContent(content);
17594
+ if (isEditModeRef.current) requestMissingSocialIconsRef.current();
17515
17595
  document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
17516
17596
  if (!form.querySelector("[data-ohw-form-success]")) {
17517
17597
  reconcileFieldsFromContent(form, content);
@@ -17597,6 +17677,7 @@ function OhhwellsBridge() {
17597
17677
  reconcileFooterOrderFromContent(content);
17598
17678
  reconcileSocialsFromContent(content);
17599
17679
  applySocialsDisplayFromContent(content);
17680
+ if (isEditModeRef.current) requestMissingSocialIconsRef.current();
17600
17681
  document.querySelectorAll("footer [data-ohw-href-key]").forEach((el) => {
17601
17682
  if (isFooterHrefKey(el.getAttribute("data-ohw-href-key")) || getSocialItem(el)) {
17602
17683
  disableNativeHrefDrag(el);
@@ -19050,9 +19131,14 @@ function OhhwellsBridge() {
19050
19131
  const handleSocialCancel = (e) => {
19051
19132
  if (e.data?.type !== "ow:social-cancel") return;
19052
19133
  const { hrefKey } = e.data;
19134
+ if (pendingSocialAddRef.current?.hrefKey === hrefKey) {
19135
+ pendingSocialAddRef.current = null;
19136
+ deselectRef.current();
19137
+ return;
19138
+ }
19053
19139
  const item = hrefKey ? findSocialByHrefKey(hrefKey) : null;
19054
19140
  if (!item) return;
19055
- const removed = removeSocialItem(item, editContentRef.current);
19141
+ const removed = removeSocialItem(item, editContentRef.current, { allowLast: true });
19056
19142
  if (!removed) return;
19057
19143
  const orderJson = JSON.stringify(removed.order);
19058
19144
  editContentRef.current = { ...editContentRef.current, [SOCIALS_ORDER_KEY]: orderJson };
@@ -19063,11 +19149,27 @@ function OhhwellsBridge() {
19063
19149
  if (e.data?.type !== "ow:social-update") return;
19064
19150
  const updates = Array.isArray(e.data.items) ? e.data.items : [e.data];
19065
19151
  const nodes = [];
19066
- for (const { hrefKey, iconKey, url, iconMarkup, platformId, label } of updates) {
19152
+ const pending = pendingSocialAddRef.current;
19153
+ if (pending && updates.some((update) => update.hrefKey === pending.hrefKey)) {
19154
+ pendingSocialAddRef.current = null;
19155
+ if (pending.row.isConnected) {
19156
+ const created = insertSocialItem(pending.row, pending.after, editContentRef.current);
19157
+ if (created) {
19158
+ const orderJson = JSON.stringify(created.order);
19159
+ editContentRef.current = { ...editContentRef.current, [SOCIALS_ORDER_KEY]: orderJson };
19160
+ nodes.push({ key: SOCIALS_ORDER_KEY, text: orderJson });
19161
+ }
19162
+ }
19163
+ }
19164
+ for (const { hrefKey, iconKey: requestedIconKey, url, iconMarkup, platformId, label } of updates) {
19067
19165
  if (hrefKey) {
19068
19166
  document.querySelectorAll(`[data-ohw-href-key="${hrefKey}"]`).forEach((el) => applyLinkHref(el, url));
19069
19167
  nodes.push({ key: hrefKey, text: url });
19070
19168
  }
19169
+ const slotFromItem = hrefKey ? findSocialByHrefKey(hrefKey)?.querySelector('[data-ohw-editable="icon"]') : null;
19170
+ const requestedIsIconSlot = Boolean(requestedIconKey) && Boolean(document.querySelector(`[data-ohw-key="${requestedIconKey}"][data-ohw-editable="icon"]`));
19171
+ const requestedIsFree = Boolean(requestedIconKey) && !document.querySelector(`[data-ohw-key="${requestedIconKey}"]`);
19172
+ const iconKey = requestedIsIconSlot ? requestedIconKey : slotFromItem?.dataset.ohwKey ?? (requestedIsFree ? requestedIconKey : void 0);
19071
19173
  if (iconKey && typeof iconMarkup === "string" && iconMarkup) {
19072
19174
  document.querySelectorAll(`[data-ohw-key="${iconKey}"][data-ohw-editable="icon"]`).forEach((el) => {
19073
19175
  applyIconMarkup(el, iconMarkup);
@@ -19271,6 +19373,7 @@ function OhhwellsBridge() {
19271
19373
  applyLinkHref(el, val);
19272
19374
  } else if (el.dataset.ohwEditable === "icon") {
19273
19375
  applyIconMarkup(el, val);
19376
+ } else if (isIconMarkupValue(val)) {
19274
19377
  } else {
19275
19378
  el.innerHTML = val;
19276
19379
  }
@@ -20355,7 +20458,7 @@ function OhhwellsBridge() {
20355
20458
  postToParent2({
20356
20459
  type: "ow:ready",
20357
20460
  version: "1",
20358
- bridgeVersion: "0.1.69",
20461
+ bridgeVersion: "0.1.70",
20359
20462
  path: pathname,
20360
20463
  nodes: collectEditableNodes(editContentRef.current),
20361
20464
  sections
@@ -20541,6 +20644,15 @@ function OhhwellsBridge() {
20541
20644
  if (!hrefKey) return;
20542
20645
  const social = getSocialItem(selected);
20543
20646
  if (social) {
20647
+ const row = findSocialsRow(social);
20648
+ if (row && !canAddSocialItem(row)) {
20649
+ postToParent2({
20650
+ type: "ow:toast",
20651
+ title: `Maximum ${MAX_SOCIAL_ITEMS_PER_ROW} social icons`,
20652
+ toastType: "error"
20653
+ });
20654
+ return;
20655
+ }
20544
20656
  const result = duplicateSocialItem(social, editContentRef.current);
20545
20657
  if (!result) return;
20546
20658
  const orderJson = JSON.stringify(result.order);
@@ -20935,6 +21047,7 @@ function OhhwellsBridge() {
20935
21047
  type: "button",
20936
21048
  className: "flex h-7 items-center gap-1.5 whitespace-nowrap rounded-md px-2 text-[13px] font-semibold text-foreground transition-colors hover:bg-muted/80",
20937
21049
  onClick: () => {
21050
+ setFieldTypePickerOpen(false);
20938
21051
  const form = formPickElRef.current;
20939
21052
  if (!form) return;
20940
21053
  postToParent2({
@@ -20968,6 +21081,7 @@ function OhhwellsBridge() {
20968
21081
  "aria-pressed": formViewState === state,
20969
21082
  className: "rounded-md px-2.5 py-1 text-[13px] font-semibold capitalize transition-colors " + (formViewState === state ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"),
20970
21083
  onClick: () => {
21084
+ setFieldTypePickerOpen(false);
20971
21085
  const form = formPickElRef.current;
20972
21086
  const key = form ? formKeyOf(form) : null;
20973
21087
  if (!form || !key) return;
@@ -21100,7 +21214,15 @@ function OhhwellsBridge() {
21100
21214
  })(),
21101
21215
  editLinkDisabled: false,
21102
21216
  moreDisabled: false,
21103
- duplicateDisabled: isFooterFrameSelection || selectedIsSocialsRow,
21217
+ deleteDisabled: selectedElRef.current !== null && (() => {
21218
+ const social = getSocialItem(selectedElRef.current);
21219
+ return social ? !canRemoveSocialItem(social) : false;
21220
+ })(),
21221
+ duplicateDisabled: isFooterFrameSelection || selectedIsSocialsRow || selectedElRef.current !== null && (() => {
21222
+ const social = getSocialItem(selectedElRef.current);
21223
+ const row = social ? findSocialsRow(social) : null;
21224
+ return row ? !canAddSocialItem(row) : false;
21225
+ })(),
21104
21226
  showEditLink: !isFooterFrameSelection && !selectedIsSocialsRow && navDropdownPreviewOpen === null,
21105
21227
  showAddItem: isFooterFrameSelection || selectedIsSocialsRow || !selectedIsCta && Boolean(
21106
21228
  selectedElRef.current && isNavbarHrefKey(selectedElRef.current.getAttribute("data-ohw-href-key")) && !isNestedNavChild(selectedElRef.current)