@ohhwells/bridge 0.1.70-next.209 → 0.1.70-next.211

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
@@ -10863,11 +10863,15 @@ function referenceBox(slot) {
10863
10863
  }
10864
10864
  function iconMarkupSizedFor(slot, markup) {
10865
10865
  const box = referenceBox(slot);
10866
- if (!box) return markup;
10867
10866
  const holder = document.createElement("div");
10868
10867
  holder.innerHTML = markup;
10869
10868
  const glyph = holder.querySelector(GLYPH_SELECTOR);
10870
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
+ }
10871
10875
  glyph.style.width = `${Math.round(box.width)}px`;
10872
10876
  glyph.style.height = `${Math.round(box.height)}px`;
10873
10877
  return holder.innerHTML;
@@ -10911,39 +10915,58 @@ function iconMarkupInheritingColour(markup) {
10911
10915
 
10912
10916
  // src/lib/socials-items.ts
10913
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";
10914
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;
10915
10922
  var SOCIALS_ROW_ATTR = "data-ohw-socials-row";
10916
10923
  var SOCIALS_ITEM_ATTR = "data-ohw-social-item";
10917
10924
  function isSocialItem(el) {
10918
10925
  if (!el) return false;
10919
10926
  const anchor = el instanceof HTMLAnchorElement ? el : el.closest("a");
10920
10927
  if (!anchor) return false;
10921
- 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;
10922
10930
  return anchor.querySelectorAll(ICON_SELECTOR).length === 1;
10923
10931
  }
10924
10932
  function getSocialItem(el) {
10925
10933
  const anchor = el.closest("a");
10926
10934
  return isSocialItem(anchor) ? anchor : null;
10927
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
+ }
10928
10944
  function findSocialsRow(el) {
10929
10945
  const item = getSocialItem(el);
10930
10946
  if (!item) return null;
10947
+ const marked = item.closest(`[${SOCIALS_ROW_ATTR}]`);
10948
+ if (marked) return marked;
10931
10949
  const wrapper = item.parentElement;
10932
- 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;
10933
10951
  if (!row) return null;
10934
10952
  const anchors = Array.from(row.querySelectorAll("a"));
10935
10953
  if (!anchors.length || !anchors.every((anchor) => isSocialItem(anchor))) return null;
10936
10954
  return row;
10937
10955
  }
10938
10956
  function isSocialsRow(el) {
10957
+ if (el.hasAttribute(SOCIALS_ROW_ATTR)) return true;
10939
10958
  const anchors = Array.from(el.querySelectorAll("a"));
10940
10959
  if (!anchors.length || !anchors.some((anchor) => isSocialItem(anchor))) return false;
10941
10960
  return findSocialsRow(anchors[0]) === el;
10942
10961
  }
10943
- var MAX_SOCIAL_ITEMS_PER_ROW = 7;
10962
+ var MAX_SOCIAL_ITEMS_PER_ROW = 14;
10944
10963
  function canAddSocialItem(row) {
10945
10964
  return listSocialItems(row).length < MAX_SOCIAL_ITEMS_PER_ROW;
10946
10965
  }
10966
+ function canRemoveSocialItem(item) {
10967
+ const row = findSocialsRow(item);
10968
+ return row ? listSocialItems(row).length > 1 : false;
10969
+ }
10947
10970
  function listSocialItems(row) {
10948
10971
  return Array.from(row.children).map((child) => {
10949
10972
  if (!(child instanceof HTMLElement)) return null;
@@ -11037,8 +11060,10 @@ function fromMarkup(markup) {
11037
11060
  var rowKeys = /* @__PURE__ */ new WeakMap();
11038
11061
  function rowKeyOf(row) {
11039
11062
  const first = listSocialItems(row)[0];
11040
- const itemKey = first ? socialIconKey(first) ?? socialHrefKey(first)?.replace(/-href$/, "") : null;
11041
- 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;
11042
11067
  if (derived) rowKeys.set(row, derived);
11043
11068
  return derived ?? rowKeys.get(row) ?? "social";
11044
11069
  }
@@ -11066,7 +11091,13 @@ function nextSocialIndex(row, rowKey, content) {
11066
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));
11067
11092
  return Math.max(-1, ...used) + 1;
11068
11093
  }
11069
- 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 } = {}) {
11070
11101
  const rowKey = rowKeyOf(row);
11071
11102
  const template = listSocialItems(row)[0];
11072
11103
  const remembered = rowTemplates.get(rowKey);
@@ -11087,16 +11118,23 @@ function insertSocialItem(row, after, content = {}) {
11087
11118
  });
11088
11119
  const icon = item.querySelector(ICON_SELECTOR);
11089
11120
  icon?.setAttribute("data-ohw-key", iconKey);
11121
+ if (placeholder && icon) icon.innerHTML = PLACEHOLDER_SOCIAL_ICON;
11090
11122
  item.querySelector(`[${SOCIALS_LABEL_ATTR}]`)?.remove();
11091
11123
  const afterUnit = after ? socialRowUnit(after) : null;
11092
11124
  if (afterUnit && afterUnit.parentElement === row) afterUnit.insertAdjacentElement("afterend", unit);
11093
11125
  else row.appendChild(unit);
11094
11126
  markSocialsRows(row.ownerDocument);
11127
+ if (placeholder) {
11128
+ const label = socialLabelElement(item);
11129
+ if (label) label.textContent = PLACEHOLDER_SOCIAL_LABEL;
11130
+ }
11131
+ applySocialsDisplayToRow(row, socialsDisplayFor(row, content));
11095
11132
  return { item, hrefKey, iconKey, order: getSocialsOrderFromDom(row.ownerDocument) };
11096
11133
  }
11097
11134
  function duplicateSocialItem(item, content) {
11098
11135
  const row = findSocialsRow(item);
11099
- 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;
11100
11138
  if (!created) return null;
11101
11139
  const sourceHref = socialHrefKey(item);
11102
11140
  const sourceIcon = socialIconKey(item);
@@ -11107,14 +11145,19 @@ function duplicateSocialItem(item, content) {
11107
11145
  const slot = link.querySelector(ICON_SELECTOR);
11108
11146
  if (slot) slot.innerHTML = glyph;
11109
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));
11110
11152
  return {
11111
11153
  ...created,
11112
11154
  copiedFrom: { href: sourceHref, icon: sourceIcon }
11113
11155
  };
11114
11156
  }
11115
- function removeSocialItem(item, content) {
11157
+ function removeSocialItem(item, content, { allowLast = false } = {}) {
11116
11158
  const row = findSocialsRow(item);
11117
11159
  if (!row) return null;
11160
+ if (!allowLast && !canRemoveSocialItem(item)) return null;
11118
11161
  const hrefKey = socialHrefKey(item);
11119
11162
  const iconKey = socialIconKey(item);
11120
11163
  const removedKeys = [hrefKey, iconKey].filter((key) => Boolean(key));
@@ -11312,14 +11355,19 @@ function applySocialsDisplayFromContent(content, root = document) {
11312
11355
  });
11313
11356
  }
11314
11357
  function socialsMissingIcons(row) {
11315
- 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));
11316
11362
  }
11317
11363
  function ensureIconSlot(item) {
11318
11364
  const existing = item.querySelector(ICON_SELECTOR);
11319
11365
  if (existing) return existing.dataset.ohwKey ?? null;
11320
11366
  const hrefKey = socialHrefKey(item);
11321
11367
  if (!hrefKey) return null;
11322
- 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;
11323
11371
  const slot = document.createElement("span");
11324
11372
  slot.setAttribute("data-ohw-key", iconKey);
11325
11373
  slot.setAttribute("data-ohw-editable", "icon");
@@ -14601,6 +14649,9 @@ function isMediaEditable(el) {
14601
14649
  const t = el.dataset.ohwEditable;
14602
14650
  return t === "image" || t === "bg-image" || t === "video";
14603
14651
  }
14652
+ function isIconMarkupValue(value) {
14653
+ return /^\s*<(svg|img)\b/i.test(value);
14654
+ }
14604
14655
  function isIconEditable(el) {
14605
14656
  return el.dataset.ohwEditable === "icon";
14606
14657
  }
@@ -14742,6 +14793,10 @@ function getNavigationItemAnchor(el) {
14742
14793
  function isNavigationItem2(el) {
14743
14794
  return getNavigationItemAnchor(el) !== null;
14744
14795
  }
14796
+ function socialWordsClicked(target, item) {
14797
+ const text = target.closest('[data-ohw-editable="text"], [data-ohw-editable="plain"]');
14798
+ return Boolean(text && item.contains(text));
14799
+ }
14745
14800
  function requestSocialDialog(anchor, post, content) {
14746
14801
  const item = getSocialItem(anchor);
14747
14802
  if (!item) return false;
@@ -16452,6 +16507,7 @@ function OhhwellsBridge() {
16452
16507
  setNavGroupForceOpen(anchor, true);
16453
16508
  activateRef.current(label);
16454
16509
  }, []);
16510
+ const pendingSocialAddRef = (0, import_react17.useRef)(null);
16455
16511
  const handleAddChildItem = (0, import_react17.useCallback)(() => {
16456
16512
  const selected = selectedElRef.current;
16457
16513
  if (!selected) return;
@@ -16466,21 +16522,17 @@ function OhhwellsBridge() {
16466
16522
  return;
16467
16523
  }
16468
16524
  const after = getSocialItem(selected);
16469
- const result2 = insertSocialItem(socialsRow, after, editContentRef.current);
16470
- if (!result2) return;
16471
- const orderJson = JSON.stringify(result2.order);
16472
- applySocialsDisplayToRow(socialsRow, socialsDisplayFor(socialsRow, editContentRef.current));
16473
- editContentRef.current = { ...editContentRef.current, [SOCIALS_ORDER_KEY]: orderJson };
16474
- postToParent2({ type: "ow:change", nodes: [{ key: SOCIALS_ORDER_KEY, text: orderJson }] });
16525
+ const planned = planSocialInsert(socialsRow, editContentRef.current);
16526
+ if (!planned) return;
16527
+ pendingSocialAddRef.current = { row: socialsRow, after, ...planned };
16475
16528
  postToParentRef.current({
16476
16529
  type: "ow:social-pick",
16477
- hrefKey: result2.hrefKey,
16478
- iconKey: result2.iconKey,
16530
+ hrefKey: planned.hrefKey,
16531
+ iconKey: planned.iconKey,
16479
16532
  url: "",
16480
- iconStyle: detectIconStyle(result2.item),
16533
+ iconStyle: detectIconStyle(getSocialItem(selected) ?? socialsRow),
16481
16534
  platformId: "",
16482
- // Lets the editor undo the insert if the dialog is dismissed: an item that was never given
16483
- // an address should not survive a Cancel.
16535
+ // Tells the editor this one is not on the page yet, so dismissing means "never mind".
16484
16536
  isNew: true
16485
16537
  });
16486
16538
  return;
@@ -17072,6 +17124,19 @@ function OhhwellsBridge() {
17072
17124
  row
17073
17125
  });
17074
17126
  }, []);
17127
+ const isEditModeRef = (0, import_react17.useRef)(false);
17128
+ const requestMissingSocialIconsRef = (0, import_react17.useRef)(() => {
17129
+ });
17130
+ const requestMissingSocialIcons = (0, import_react17.useCallback)(() => {
17131
+ const items = Array.from(document.querySelectorAll(`[${SOCIALS_ROW_ATTR}]`)).filter((row) => socialsDisplayFor(row, editContentRef.current).icon).flatMap((row) => {
17132
+ const missing = socialsMissingIcons(row);
17133
+ listSocialItems(row).forEach((item) => ensureIconSlot(item));
17134
+ return missing;
17135
+ });
17136
+ if (items.length) postToParentRef.current({ type: "ow:social-icons-needed", items });
17137
+ }, []);
17138
+ requestMissingSocialIconsRef.current = requestMissingSocialIcons;
17139
+ isEditModeRef.current = isEditMode;
17075
17140
  const changeSocialsDisplay = (0, import_react17.useCallback)(
17076
17141
  (row, next) => {
17077
17142
  if (next.icon) {
@@ -17167,7 +17232,7 @@ function OhhwellsBridge() {
17167
17232
  const activate = (0, import_react17.useCallback)((el, options) => {
17168
17233
  if (activeElRef.current === el) return;
17169
17234
  if (isIconEditable(el)) return;
17170
- if (el.hasAttribute("data-ohw-social-label")) return;
17235
+ if (el.hasAttribute("data-ohw-social-label") && el.offsetParent === null) return;
17171
17236
  clearSelectedAttr();
17172
17237
  selectedElRef.current = null;
17173
17238
  selectedHrefKeyRef.current = null;
@@ -17332,6 +17397,7 @@ function OhhwellsBridge() {
17332
17397
  } else if (el.dataset.ohwEditable === "icon") {
17333
17398
  applyIconMarkup(el, val);
17334
17399
  } else if (el.dataset.ohwEditable === "form") {
17400
+ } else if (isIconMarkupValue(val)) {
17335
17401
  } else if (el.innerHTML !== val) {
17336
17402
  el.innerHTML = val;
17337
17403
  }
@@ -17344,6 +17410,7 @@ function OhhwellsBridge() {
17344
17410
  reconcileFooterOrderFromContent(content);
17345
17411
  reconcileSocialsFromContent(content);
17346
17412
  applySocialsDisplayFromContent(content);
17413
+ if (isEditModeRef.current) requestMissingSocialIconsRef.current();
17347
17414
  enforceLinkHrefs();
17348
17415
  initSectionsFromContent(content, true);
17349
17416
  initSectionInstancesFromContent(content, window.location.pathname);
@@ -17516,6 +17583,7 @@ function OhhwellsBridge() {
17516
17583
  } else if (el.dataset.ohwEditable === "link") {
17517
17584
  applyLinkHref(el, val);
17518
17585
  } else if (el.dataset.ohwEditable === "form") {
17586
+ } else if (isIconMarkupValue(val)) {
17519
17587
  } else if (el.innerHTML !== val) {
17520
17588
  el.innerHTML = val;
17521
17589
  }
@@ -17527,6 +17595,7 @@ function OhhwellsBridge() {
17527
17595
  reconcileFooterOrderFromContent(content);
17528
17596
  reconcileSocialsFromContent(content);
17529
17597
  applySocialsDisplayFromContent(content);
17598
+ if (isEditModeRef.current) requestMissingSocialIconsRef.current();
17530
17599
  document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
17531
17600
  if (!form.querySelector("[data-ohw-form-success]")) {
17532
17601
  reconcileFieldsFromContent(form, content);
@@ -17612,6 +17681,7 @@ function OhhwellsBridge() {
17612
17681
  reconcileFooterOrderFromContent(content);
17613
17682
  reconcileSocialsFromContent(content);
17614
17683
  applySocialsDisplayFromContent(content);
17684
+ if (isEditModeRef.current) requestMissingSocialIconsRef.current();
17615
17685
  document.querySelectorAll("footer [data-ohw-href-key]").forEach((el) => {
17616
17686
  if (isFooterHrefKey(el.getAttribute("data-ohw-href-key")) || getSocialItem(el)) {
17617
17687
  disableNativeHrefDrag(el);
@@ -18029,7 +18099,9 @@ function OhhwellsBridge() {
18029
18099
  e.stopPropagation();
18030
18100
  if (selectedElRef.current === navAnchor) {
18031
18101
  if (e.detail >= 2) return;
18032
- if (requestSocialDialog(navAnchor, postToParentRef.current, editContentRef.current)) return;
18102
+ if (!socialWordsClicked(target, navAnchor) && requestSocialDialog(navAnchor, postToParentRef.current, editContentRef.current)) {
18103
+ return;
18104
+ }
18033
18105
  const activateTarget = isButtonLikeElement(hrefLookupTarget) ? navAnchor.querySelector('[data-ohw-editable="text"]') ?? hrefLookupTarget : hrefLookupTarget;
18034
18106
  activateRef.current(activateTarget, { caretX: e.clientX, caretY: e.clientY });
18035
18107
  return;
@@ -18047,7 +18119,9 @@ function OhhwellsBridge() {
18047
18119
  e.preventDefault();
18048
18120
  e.stopPropagation();
18049
18121
  if (selectedElRef.current === hrefAnchor) {
18050
- if (requestSocialDialog(hrefAnchor, postToParentRef.current, editContentRef.current)) return;
18122
+ if (!socialWordsClicked(target, hrefAnchor) && requestSocialDialog(hrefAnchor, postToParentRef.current, editContentRef.current)) {
18123
+ return;
18124
+ }
18051
18125
  const textEditable = hrefAnchor.querySelector('[data-ohw-editable="text"]') ?? hrefAnchor.querySelector("[data-ohw-editable]");
18052
18126
  if (textEditable) {
18053
18127
  activateRef.current(textEditable, {
@@ -18146,7 +18220,8 @@ function OhhwellsBridge() {
18146
18220
  if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
18147
18221
  return;
18148
18222
  }
18149
- if (getSocialItem(target)) return;
18223
+ const socialWords = getSocialItem(target) ? target.closest('[data-ohw-editable="text"], [data-ohw-editable="plain"]') : null;
18224
+ if (getSocialItem(target) && (!socialWords || socialWords.offsetParent === null)) return;
18150
18225
  const navLabel = getNavigationLabelEditable(target);
18151
18226
  const editable = navLabel?.editable ?? target.closest('[data-ohw-editable="text"], [data-ohw-editable="plain"]');
18152
18227
  if (!editable || isMediaEditable(editable) || editable.dataset.ohwEditable === "link") return;
@@ -19065,9 +19140,14 @@ function OhhwellsBridge() {
19065
19140
  const handleSocialCancel = (e) => {
19066
19141
  if (e.data?.type !== "ow:social-cancel") return;
19067
19142
  const { hrefKey } = e.data;
19143
+ if (pendingSocialAddRef.current?.hrefKey === hrefKey) {
19144
+ pendingSocialAddRef.current = null;
19145
+ deselectRef.current();
19146
+ return;
19147
+ }
19068
19148
  const item = hrefKey ? findSocialByHrefKey(hrefKey) : null;
19069
19149
  if (!item) return;
19070
- const removed = removeSocialItem(item, editContentRef.current);
19150
+ const removed = removeSocialItem(item, editContentRef.current, { allowLast: true });
19071
19151
  if (!removed) return;
19072
19152
  const orderJson = JSON.stringify(removed.order);
19073
19153
  editContentRef.current = { ...editContentRef.current, [SOCIALS_ORDER_KEY]: orderJson };
@@ -19078,11 +19158,27 @@ function OhhwellsBridge() {
19078
19158
  if (e.data?.type !== "ow:social-update") return;
19079
19159
  const updates = Array.isArray(e.data.items) ? e.data.items : [e.data];
19080
19160
  const nodes = [];
19081
- for (const { hrefKey, iconKey, url, iconMarkup, platformId, label } of updates) {
19161
+ const pending = pendingSocialAddRef.current;
19162
+ if (pending && updates.some((update) => update.hrefKey === pending.hrefKey)) {
19163
+ pendingSocialAddRef.current = null;
19164
+ if (pending.row.isConnected) {
19165
+ const created = insertSocialItem(pending.row, pending.after, editContentRef.current);
19166
+ if (created) {
19167
+ const orderJson = JSON.stringify(created.order);
19168
+ editContentRef.current = { ...editContentRef.current, [SOCIALS_ORDER_KEY]: orderJson };
19169
+ nodes.push({ key: SOCIALS_ORDER_KEY, text: orderJson });
19170
+ }
19171
+ }
19172
+ }
19173
+ for (const { hrefKey, iconKey: requestedIconKey, url, iconMarkup, platformId, label } of updates) {
19082
19174
  if (hrefKey) {
19083
19175
  document.querySelectorAll(`[data-ohw-href-key="${hrefKey}"]`).forEach((el) => applyLinkHref(el, url));
19084
19176
  nodes.push({ key: hrefKey, text: url });
19085
19177
  }
19178
+ const slotFromItem = hrefKey ? findSocialByHrefKey(hrefKey)?.querySelector('[data-ohw-editable="icon"]') : null;
19179
+ const requestedIsIconSlot = Boolean(requestedIconKey) && Boolean(document.querySelector(`[data-ohw-key="${requestedIconKey}"][data-ohw-editable="icon"]`));
19180
+ const requestedIsFree = Boolean(requestedIconKey) && !document.querySelector(`[data-ohw-key="${requestedIconKey}"]`);
19181
+ const iconKey = requestedIsIconSlot ? requestedIconKey : slotFromItem?.dataset.ohwKey ?? (requestedIsFree ? requestedIconKey : void 0);
19086
19182
  if (iconKey && typeof iconMarkup === "string" && iconMarkup) {
19087
19183
  document.querySelectorAll(`[data-ohw-key="${iconKey}"][data-ohw-editable="icon"]`).forEach((el) => {
19088
19184
  applyIconMarkup(el, iconMarkup);
@@ -19286,6 +19382,7 @@ function OhhwellsBridge() {
19286
19382
  applyLinkHref(el, val);
19287
19383
  } else if (el.dataset.ohwEditable === "icon") {
19288
19384
  applyIconMarkup(el, val);
19385
+ } else if (isIconMarkupValue(val)) {
19289
19386
  } else {
19290
19387
  el.innerHTML = val;
19291
19388
  }
@@ -20556,6 +20653,15 @@ function OhhwellsBridge() {
20556
20653
  if (!hrefKey) return;
20557
20654
  const social = getSocialItem(selected);
20558
20655
  if (social) {
20656
+ const row = findSocialsRow(social);
20657
+ if (row && !canAddSocialItem(row)) {
20658
+ postToParent2({
20659
+ type: "ow:toast",
20660
+ title: `Maximum ${MAX_SOCIAL_ITEMS_PER_ROW} social icons`,
20661
+ toastType: "error"
20662
+ });
20663
+ return;
20664
+ }
20559
20665
  const result = duplicateSocialItem(social, editContentRef.current);
20560
20666
  if (!result) return;
20561
20667
  const orderJson = JSON.stringify(result.order);
@@ -20950,6 +21056,7 @@ function OhhwellsBridge() {
20950
21056
  type: "button",
20951
21057
  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",
20952
21058
  onClick: () => {
21059
+ setFieldTypePickerOpen(false);
20953
21060
  const form = formPickElRef.current;
20954
21061
  if (!form) return;
20955
21062
  postToParent2({
@@ -20983,6 +21090,7 @@ function OhhwellsBridge() {
20983
21090
  "aria-pressed": formViewState === state,
20984
21091
  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"),
20985
21092
  onClick: () => {
21093
+ setFieldTypePickerOpen(false);
20986
21094
  const form = formPickElRef.current;
20987
21095
  const key = form ? formKeyOf(form) : null;
20988
21096
  if (!form || !key) return;
@@ -21115,7 +21223,15 @@ function OhhwellsBridge() {
21115
21223
  })(),
21116
21224
  editLinkDisabled: false,
21117
21225
  moreDisabled: false,
21118
- duplicateDisabled: isFooterFrameSelection || selectedIsSocialsRow,
21226
+ deleteDisabled: selectedElRef.current !== null && (() => {
21227
+ const social = getSocialItem(selectedElRef.current);
21228
+ return social ? !canRemoveSocialItem(social) : false;
21229
+ })(),
21230
+ duplicateDisabled: isFooterFrameSelection || selectedIsSocialsRow || selectedElRef.current !== null && (() => {
21231
+ const social = getSocialItem(selectedElRef.current);
21232
+ const row = social ? findSocialsRow(social) : null;
21233
+ return row ? !canAddSocialItem(row) : false;
21234
+ })(),
21119
21235
  showEditLink: !isFooterFrameSelection && !selectedIsSocialsRow && navDropdownPreviewOpen === null,
21120
21236
  showAddItem: isFooterFrameSelection || selectedIsSocialsRow || !selectedIsCta && Boolean(
21121
21237
  selectedElRef.current && isNavbarHrefKey(selectedElRef.current.getAttribute("data-ohw-href-key")) && !isNestedNavChild(selectedElRef.current)