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

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
@@ -6296,16 +6296,14 @@ var import_react6 = require("react");
6296
6296
  var import_lucide_react3 = require("lucide-react");
6297
6297
 
6298
6298
  // src/ui/dropdown-menu.tsx
6299
+ var React6 = __toESM(require("react"), 1);
6299
6300
  var import_radix_ui3 = require("radix-ui");
6300
6301
  var import_jsx_runtime9 = require("react/jsx-runtime");
6301
6302
  function DropdownMenu({ ...props }) {
6302
6303
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_radix_ui3.DropdownMenu.Root, { "data-slot": "dropdown-menu", ...props });
6303
6304
  }
6304
- function DropdownMenuTrigger({
6305
- ...props
6306
- }) {
6307
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_radix_ui3.DropdownMenu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
6308
- }
6305
+ var DropdownMenuTrigger = React6.forwardRef((props, ref) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_radix_ui3.DropdownMenu.Trigger, { ref, "data-slot": "dropdown-menu-trigger", ...props }));
6306
+ DropdownMenuTrigger.displayName = "DropdownMenuTrigger";
6309
6307
  function DropdownMenuGroup({
6310
6308
  className,
6311
6309
  ...props
@@ -7558,11 +7556,11 @@ function FieldTypePicker({ onPick }) {
7558
7556
  }
7559
7557
 
7560
7558
  // src/ui/MediaOverlay.tsx
7561
- var React7 = __toESM(require("react"), 1);
7559
+ var React8 = __toESM(require("react"), 1);
7562
7560
  var import_lucide_react5 = require("lucide-react");
7563
7561
 
7564
7562
  // src/ui/button.tsx
7565
- var React6 = __toESM(require("react"), 1);
7563
+ var React7 = __toESM(require("react"), 1);
7566
7564
  var import_radix_ui5 = require("radix-ui");
7567
7565
  var import_jsx_runtime14 = require("react/jsx-runtime");
7568
7566
  var buttonVariants = cva(
@@ -7585,7 +7583,7 @@ var buttonVariants = cva(
7585
7583
  }
7586
7584
  }
7587
7585
  );
7588
- var Button = React6.forwardRef(
7586
+ var Button = React7.forwardRef(
7589
7587
  ({ className, variant, size, asChild = false, ...props }, ref) => {
7590
7588
  const Comp = asChild ? import_radix_ui5.Slot.Root : "button";
7591
7589
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
@@ -7640,7 +7638,7 @@ function MediaOverlay({
7640
7638
  onVideoSettingsChange
7641
7639
  }) {
7642
7640
  const { rect } = hover;
7643
- const skeletonRef = React7.useRef(null);
7641
+ const skeletonRef = React8.useRef(null);
7644
7642
  const isVideo = hover.elementType === "video";
7645
7643
  const showChrome = !selected || hovered;
7646
7644
  const autoplay = hover.videoAutoplay ?? true;
@@ -7653,7 +7651,7 @@ function MediaOverlay({
7653
7651
  height: rect.height,
7654
7652
  zIndex: 2147483646
7655
7653
  };
7656
- React7.useEffect(() => {
7654
+ React8.useEffect(() => {
7657
7655
  if (!isUploading || !fadingOut || !skeletonRef.current) return;
7658
7656
  const anim = skeletonRef.current.animate([{ opacity: 1 }, { opacity: 0 }], {
7659
7657
  duration: MEDIA_UPLOAD_FADE_MS,
@@ -8617,7 +8615,7 @@ function scrollToHashSectionWhenReady(behavior = "smooth") {
8617
8615
  var import_react12 = require("react");
8618
8616
 
8619
8617
  // src/ui/dialog.tsx
8620
- var React8 = __toESM(require("react"), 1);
8618
+ var React9 = __toESM(require("react"), 1);
8621
8619
  var import_radix_ui6 = require("radix-ui");
8622
8620
  var import_lucide_react8 = require("lucide-react");
8623
8621
  var import_jsx_runtime18 = require("react/jsx-runtime");
@@ -8645,7 +8643,7 @@ function DialogOverlay({
8645
8643
  }
8646
8644
  );
8647
8645
  }
8648
- var DialogContent = React8.forwardRef(
8646
+ var DialogContent = React9.forwardRef(
8649
8647
  ({ className, children, showCloseButton = true, container, ...props }, ref) => {
8650
8648
  const positionMode = container ? "absolute" : "fixed";
8651
8649
  return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(DialogPortal, { container: container ?? void 0, children: [
@@ -8700,7 +8698,7 @@ function DialogFooter({
8700
8698
  }
8701
8699
  );
8702
8700
  }
8703
- var DialogTitle = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
8701
+ var DialogTitle = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
8704
8702
  import_radix_ui6.Dialog.Title,
8705
8703
  {
8706
8704
  ref,
@@ -8712,7 +8710,7 @@ var DialogTitle = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE
8712
8710
  }
8713
8711
  ));
8714
8712
  DialogTitle.displayName = import_radix_ui6.Dialog.Title.displayName;
8715
- var DialogDescription = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
8713
+ var DialogDescription = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
8716
8714
  import_radix_ui6.Dialog.Description,
8717
8715
  {
8718
8716
  ref,
@@ -8817,9 +8815,9 @@ function SectionTreeItem({
8817
8815
  var import_react9 = require("react");
8818
8816
 
8819
8817
  // src/ui/input.tsx
8820
- var React9 = __toESM(require("react"), 1);
8818
+ var React10 = __toESM(require("react"), 1);
8821
8819
  var import_jsx_runtime21 = require("react/jsx-runtime");
8822
- var Input = React9.forwardRef(
8820
+ var Input = React10.forwardRef(
8823
8821
  ({ className, type, ...props }, ref) => {
8824
8822
  return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8825
8823
  "input",
@@ -10851,7 +10849,9 @@ function deleteNavbarItem(sourceAnchor) {
10851
10849
  var GLYPH_SELECTOR = "svg, img";
10852
10850
  function referenceBox(slot) {
10853
10851
  const row = slot.closest("[data-ohw-socials-row]") ?? slot.closest("a")?.parentElement ?? null;
10854
- const neighbour = row ? Array.from(row.querySelectorAll('[data-ohw-editable="icon"]')).find((el) => el !== slot) : null;
10852
+ const neighbour = row ? Array.from(row.querySelectorAll('[data-ohw-editable="icon"]')).find(
10853
+ (el) => el !== slot && !el.hasAttribute("data-ohw-social-icon-placeholder")
10854
+ ) : null;
10855
10855
  if (neighbour) {
10856
10856
  const box2 = neighbour.querySelector(GLYPH_SELECTOR)?.getBoundingClientRect();
10857
10857
  if (box2?.width && box2.height) return box2;
@@ -10876,11 +10876,14 @@ function iconMarkupSizedFor(slot, markup) {
10876
10876
  glyph.style.height = `${Math.round(box.height)}px`;
10877
10877
  return holder.innerHTML;
10878
10878
  }
10879
+ var ICON_SOURCE_ATTR = "data-ohw-icon-source";
10879
10880
  function applyIconMarkup(slot, markup) {
10880
10881
  if (!markup) return;
10882
+ if (slot.getAttribute(ICON_SOURCE_ATTR) === markup) return;
10881
10883
  const coloured = iconMarkupInheritingColour(markup);
10882
10884
  const sized = iconMarkupSizedFor(slot, coloured);
10883
10885
  if (slot.innerHTML !== sized) slot.innerHTML = sized;
10886
+ slot.setAttribute(ICON_SOURCE_ATTR, markup);
10884
10887
  if (sized === coloured) {
10885
10888
  requestAnimationFrame(() => {
10886
10889
  if (!slot.isConnected) return;
@@ -10915,7 +10918,7 @@ function iconMarkupInheritingColour(markup) {
10915
10918
 
10916
10919
  // src/lib/socials-items.ts
10917
10920
  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>';
10921
+ var PLACEHOLDER_SOCIAL_ICON = '<svg xmlns="http://www.w3.org/2000/svg" width="1.5em" height="1.5em" 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
10922
  var PLACEHOLDER_SOCIAL_LABEL = "Social";
10920
10923
  var SOCIAL_KEY_RE = /(^|-)social(s)?(-|$)/i;
10921
10924
  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;
@@ -10994,31 +10997,67 @@ function listSocialsRows(root = document) {
10994
10997
  }
10995
10998
  var rowTemplates = /* @__PURE__ */ new Map();
10996
10999
  function markSocialsRows(root = document) {
10997
- root.querySelectorAll(`[${SOCIALS_ITEM_ATTR}]`).forEach((item) => {
10998
- item.removeAttribute(SOCIALS_ITEM_ATTR);
10999
- });
11000
+ const stillInARow = /* @__PURE__ */ new Set();
11000
11001
  listSocialsRows(root).forEach((row) => {
11001
- row.setAttribute(SOCIALS_ROW_ATTR, "");
11002
+ if (row.getAttribute(SOCIALS_ROW_ATTR) === null) row.setAttribute(SOCIALS_ROW_ATTR, "");
11003
+ queueMicrotask(
11004
+ () => markEmptySocialLabels(row.ownerDocument, row.ownerDocument.activeElement)
11005
+ );
11002
11006
  allowRowToWrap(row);
11003
11007
  const items = listSocialItems(row);
11004
11008
  const firstUnit = items[0] ? socialRowUnit(items[0], row) : null;
11005
11009
  if (firstUnit) rowTemplates.set(rowKeyOf(row), firstUnit.outerHTML);
11006
11010
  items.forEach((item, index) => {
11007
- item.setAttribute(SOCIALS_ITEM_ATTR, String(index));
11008
- const iconKey = socialIconKey(item);
11011
+ stillInARow.add(item);
11012
+ if (item.getAttribute(SOCIALS_ITEM_ATTR) !== String(index)) {
11013
+ item.setAttribute(SOCIALS_ITEM_ATTR, String(index));
11014
+ }
11015
+ const iconKey = socialIconKey(item) ?? socialHrefKey(item)?.replace(/-href$/, "");
11009
11016
  if (iconKey) ensureLabelSlot(item, iconKey);
11010
11017
  });
11011
11018
  });
11019
+ root.querySelectorAll(`[${SOCIALS_ITEM_ATTR}]`).forEach((item) => {
11020
+ if (!stillInARow.has(item)) item.removeAttribute(SOCIALS_ITEM_ATTR);
11021
+ });
11012
11022
  }
11013
11023
  var SOCIALS_LABEL_ATTR = "data-ohw-social-label";
11024
+ var SOCIALS_ICON_PLACEHOLDER_ATTR = "data-ohw-social-icon-placeholder";
11025
+ var SOCIALS_EMPTY_LABEL_ATTR = "data-ohw-empty-label";
11026
+ var EMPTY_LABEL_WIDTH = "8ch";
11027
+ function markEmptySocialLabels(root = document, skip) {
11028
+ root.querySelectorAll(`[${SOCIALS_ROW_ATTR}]`).forEach((row) => {
11029
+ listSocialItems(row).forEach((item) => {
11030
+ const label = socialLabelElement(item);
11031
+ if (!label || label === skip) return;
11032
+ const empty = !label.textContent?.trim();
11033
+ if (empty === label.hasAttribute(SOCIALS_EMPTY_LABEL_ATTR)) return;
11034
+ if (empty) {
11035
+ label.setAttribute(SOCIALS_EMPTY_LABEL_ATTR, "");
11036
+ label.style.display = "inline-block";
11037
+ label.style.minWidth = EMPTY_LABEL_WIDTH;
11038
+ label.style.minHeight = "1.4em";
11039
+ } else {
11040
+ label.removeAttribute(SOCIALS_EMPTY_LABEL_ATTR);
11041
+ label.style.display = "";
11042
+ label.style.minWidth = "";
11043
+ label.style.minHeight = "";
11044
+ }
11045
+ });
11046
+ });
11047
+ }
11014
11048
  function ensureLabelSlot(item, iconKey) {
11015
11049
  if (socialLabelElement(item)) return;
11016
11050
  const label = document.createElement("span");
11017
11051
  label.setAttribute("data-ohw-key", `${iconKey}-label`);
11018
11052
  label.setAttribute("data-ohw-editable", "text");
11019
11053
  label.setAttribute(SOCIALS_LABEL_ATTR, "");
11020
- label.style.display = "none";
11021
- label.textContent = item.getAttribute("aria-label") ?? "";
11054
+ const ownText = Array.from(item.childNodes).filter(
11055
+ (node) => node.nodeType === Node.TEXT_NODE && node.textContent?.trim()
11056
+ );
11057
+ const carried = ownText.map((node) => node.textContent?.trim()).join(" ");
11058
+ ownText.forEach((node) => node.remove());
11059
+ label.textContent = carried || item.getAttribute("aria-label") || "";
11060
+ label.style.display = carried ? "" : "none";
11022
11061
  item.appendChild(label);
11023
11062
  }
11024
11063
  function socialLabelElement(item) {
@@ -11029,17 +11068,26 @@ function socialLabelElement(item) {
11029
11068
  function socialLabelKey(iconKey) {
11030
11069
  return `${iconKey}-label`;
11031
11070
  }
11071
+ function isEmptyLabelValue(value) {
11072
+ return !value.replace(/<br\s*\/?>/gi, "").replace(/&nbsp;/gi, " ").trim();
11073
+ }
11032
11074
  function applyStoredValues(item, content) {
11033
11075
  const hrefKey = socialHrefKey(item);
11034
11076
  const iconKey = socialIconKey(item);
11035
11077
  if (hrefKey && content[hrefKey] !== void 0) item.setAttribute("href", content[hrefKey]);
11036
11078
  if (iconKey) {
11037
11079
  const glyph = item.querySelector(ICON_SELECTOR);
11038
- if (glyph && content[iconKey]) applyIconMarkup(glyph, content[iconKey]);
11080
+ if (glyph && content[iconKey]) {
11081
+ applyIconMarkup(glyph, content[iconKey]);
11082
+ glyph.removeAttribute(SOCIALS_ICON_PLACEHOLDER_ATTR);
11083
+ }
11039
11084
  const label = item.querySelector(`[${SOCIALS_LABEL_ATTR}]`);
11040
11085
  label?.setAttribute("data-ohw-key", socialLabelKey(iconKey));
11041
11086
  const stored = content[socialLabelKey(iconKey)];
11042
- if (label && stored) label.textContent = stored;
11087
+ if (label && stored !== void 0) {
11088
+ const words = isEmptyLabelValue(stored) ? "" : stored;
11089
+ if (label.innerHTML !== words) label.innerHTML = words;
11090
+ }
11043
11091
  }
11044
11092
  }
11045
11093
  function socialPlatformKey(iconKey) {
@@ -11076,7 +11124,7 @@ function getSocialsOrderFromDom(root = document) {
11076
11124
  }
11077
11125
  function hasStoredValue(content, hrefKey) {
11078
11126
  const iconKey = hrefKey.replace(/-href$/, "");
11079
- return Boolean(content[hrefKey]) || Boolean(content[iconKey]);
11127
+ return Boolean(content[hrefKey]) || Boolean(content[iconKey]) || Boolean(content[socialLabelKey(iconKey)]);
11080
11128
  }
11081
11129
  function parseSocialsOrder(raw) {
11082
11130
  if (!raw) return null;
@@ -11087,24 +11135,24 @@ function parseSocialsOrder(raw) {
11087
11135
  return null;
11088
11136
  }
11089
11137
  }
11090
- function nextSocialIndex(row, rowKey, content) {
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));
11138
+ function nextSocialIndex(row, rowKey, content, reserved = []) {
11139
+ const used = listSocialItems(row).map((item) => socialHrefKey(item)).concat(Object.keys(content)).concat(reserved).map((key) => key?.match(new RegExp(`^${rowKey}-(\\d+)`))?.[1]).map((digits) => digits === void 0 ? -1 : Number(digits));
11092
11140
  return Math.max(-1, ...used) + 1;
11093
11141
  }
11094
- function planSocialInsert(row, content = {}) {
11142
+ function planSocialInsert(row, content = {}, reserved = []) {
11095
11143
  if (!canAddSocialItem(row)) return null;
11096
11144
  const rowKey = rowKeyOf(row);
11097
- const iconKey = `${rowKey}-${nextSocialIndex(row, rowKey, content)}`;
11145
+ const iconKey = `${rowKey}-${nextSocialIndex(row, rowKey, content, reserved)}`;
11098
11146
  return { hrefKey: `${iconKey}-href`, iconKey };
11099
11147
  }
11100
- function insertSocialItem(row, after, content = {}, { placeholder = true } = {}) {
11148
+ function insertSocialItem(row, after, content = {}, { placeholder = true, keys } = {}) {
11101
11149
  const rowKey = rowKeyOf(row);
11102
11150
  const template = listSocialItems(row)[0];
11103
11151
  const remembered = rowTemplates.get(rowKey);
11104
11152
  if (!template && !remembered) return null;
11105
- const index = nextSocialIndex(row, rowKey, content);
11106
- const iconKey = `${rowKey}-${index}`;
11107
- const hrefKey = `${iconKey}-href`;
11153
+ const display = socialsDisplayFor(row, content);
11154
+ const iconKey = keys?.iconKey ?? `${rowKey}-${nextSocialIndex(row, rowKey, content)}`;
11155
+ const hrefKey = keys?.hrefKey ?? `${iconKey}-href`;
11108
11156
  const templateUnit = template ? socialRowUnit(template) : null;
11109
11157
  const unit = templateUnit ? templateUnit.cloneNode(true) : fromMarkup(remembered);
11110
11158
  const item = unit && (unit.matches("a") ? unit : unit.querySelector("a"));
@@ -11119,6 +11167,7 @@ function insertSocialItem(row, after, content = {}, { placeholder = true } = {})
11119
11167
  const icon = item.querySelector(ICON_SELECTOR);
11120
11168
  icon?.setAttribute("data-ohw-key", iconKey);
11121
11169
  if (placeholder && icon) icon.innerHTML = PLACEHOLDER_SOCIAL_ICON;
11170
+ socialLabelElement(item)?.setAttribute("data-ohw-key", socialLabelKey(iconKey));
11122
11171
  item.querySelector(`[${SOCIALS_LABEL_ATTR}]`)?.remove();
11123
11172
  const afterUnit = after ? socialRowUnit(after) : null;
11124
11173
  if (afterUnit && afterUnit.parentElement === row) afterUnit.insertAdjacentElement("afterend", unit);
@@ -11128,7 +11177,7 @@ function insertSocialItem(row, after, content = {}, { placeholder = true } = {})
11128
11177
  const label = socialLabelElement(item);
11129
11178
  if (label) label.textContent = PLACEHOLDER_SOCIAL_LABEL;
11130
11179
  }
11131
- applySocialsDisplayToRow(row, socialsDisplayFor(row, content));
11180
+ applySocialsDisplayToRow(row, display);
11132
11181
  return { item, hrefKey, iconKey, order: getSocialsOrderFromDom(row.ownerDocument) };
11133
11182
  }
11134
11183
  function duplicateSocialItem(item, content) {
@@ -11145,9 +11194,9 @@ function duplicateSocialItem(item, content) {
11145
11194
  const slot = link.querySelector(ICON_SELECTOR);
11146
11195
  if (slot) slot.innerHTML = glyph;
11147
11196
  }
11148
- const sourceLabel = socialLabelElement(item)?.textContent?.trim();
11197
+ const sourceLabel = socialLabelElement(item);
11149
11198
  const copyLabel = socialLabelElement(link);
11150
- if (copyLabel && sourceLabel) copyLabel.textContent = sourceLabel;
11199
+ if (copyLabel && sourceLabel) copyLabel.innerHTML = sourceLabel.innerHTML;
11151
11200
  if (row) applySocialsDisplayToRow(row, socialsDisplayFor(row, content));
11152
11201
  return {
11153
11202
  ...created,
@@ -11188,17 +11237,32 @@ function applySocialsOrder(order, root = document) {
11188
11237
  const wanted = order[rowKeyOf(row)];
11189
11238
  if (!wanted) return;
11190
11239
  const byKey = new Map(listSocialItems(row).map((item) => [socialHrefKey(item), item]));
11191
- wanted.forEach((key) => {
11192
- const item = byKey.get(key);
11193
- if (!item) return;
11194
- const unit = socialRowUnit(item, row);
11195
- if (unit) row.appendChild(unit);
11196
- });
11240
+ const units = wanted.map((key) => byKey.get(key)).filter((item) => Boolean(item)).map((item) => socialRowUnit(item, row)).filter((unit) => Boolean(unit));
11241
+ const tail = Array.from(row.children).slice(-units.length);
11242
+ const inPlace = units.length > 0 && tail.length === units.length && units.every((unit, i) => tail[i] === unit);
11243
+ if (inPlace) return;
11244
+ units.forEach((unit) => row.appendChild(unit));
11197
11245
  });
11198
11246
  markSocialsRows(root);
11199
11247
  }
11200
11248
  function reconcileSocialsFromContent(content, root = document) {
11201
11249
  markSocialsRows(root);
11250
+ listSocialsRows(root).forEach((row) => {
11251
+ const rowDisplay = socialsDisplayFor(row, content);
11252
+ listSocialItems(row).forEach((item) => {
11253
+ const key = socialIconKey(item) ?? socialHrefKey(item)?.replace(/-href$/, "");
11254
+ const stored2 = key ? content[key] : void 0;
11255
+ if (!stored2?.trim()) return;
11256
+ const existing = item.querySelector(ICON_SELECTOR);
11257
+ if (existing && existing.innerHTML.trim() && !existing.hasAttribute(SOCIALS_ICON_PLACEHOLDER_ATTR)) return;
11258
+ ensureIconSlot(item);
11259
+ const slot = item.querySelector(ICON_SELECTOR);
11260
+ if (!slot) return;
11261
+ applyIconMarkup(slot, stored2);
11262
+ slot.removeAttribute(SOCIALS_ICON_PLACEHOLDER_ATTR);
11263
+ if (!rowDisplay.icon) slot.style.display = "none";
11264
+ });
11265
+ });
11202
11266
  const stored = parseSocialsOrder(content[SOCIALS_ORDER_KEY]);
11203
11267
  if (!stored) return;
11204
11268
  listSocialsRows(root).forEach((row) => {
@@ -11208,12 +11272,11 @@ function reconcileSocialsFromContent(content, root = document) {
11208
11272
  wanted.forEach((key) => {
11209
11273
  if (listSocialItems(row).some((item) => socialHrefKey(item) === key)) return;
11210
11274
  if (!hasStoredValue(content, key)) return;
11211
- const created = insertSocialItem(row, null, content);
11212
- if (created) {
11213
- created.item.setAttribute("data-ohw-href-key", key);
11214
- created.item.querySelector(ICON_SELECTOR)?.setAttribute("data-ohw-key", key.replace(/-href$/, ""));
11215
- applyStoredValues(created.item, content);
11216
- }
11275
+ const created = insertSocialItem(row, null, content, {
11276
+ placeholder: false,
11277
+ keys: { hrefKey: key, iconKey: key.replace(/-href$/, "") }
11278
+ });
11279
+ if (created) applyStoredValues(created.item, content);
11217
11280
  });
11218
11281
  const present = listSocialItems(row);
11219
11282
  const surviving = present.filter((item) => {
@@ -11288,9 +11351,10 @@ var SOCIALS_DISPLAY_KEY = "__ohw_socials_display";
11288
11351
  function readSocialsDisplay(row) {
11289
11352
  const items = listSocialItems(row);
11290
11353
  const visible = (el) => Boolean(el) && el.style.display !== "none" && el.getAttribute("data-ohw-hidden") === null;
11354
+ const drawn = (el) => Boolean(el && visible(el) && el.innerHTML.trim());
11291
11355
  return {
11292
11356
  text: items.some((item) => visible(socialLabelElement(item))),
11293
- icon: items.some((item) => visible(item.querySelector(ICON_SELECTOR)))
11357
+ icon: items.some((item) => drawn(item.querySelector(ICON_SELECTOR)))
11294
11358
  };
11295
11359
  }
11296
11360
  function parseSocialsDisplay(raw) {
@@ -11338,6 +11402,20 @@ function allowRowToWrap(row) {
11338
11402
  const display = row.ownerDocument.defaultView?.getComputedStyle(row).display ?? "";
11339
11403
  if (display === "flex" || display === "inline-flex") row.style.flexWrap = "wrap";
11340
11404
  }
11405
+ function applySocialsLabelsFromContent(content, root = document, { fillEmptyOnly = false } = {}) {
11406
+ const focused = root.activeElement ?? document.activeElement;
11407
+ listSocialsRows(root).forEach((row) => {
11408
+ listSocialItems(row).forEach((item) => {
11409
+ const label = socialLabelElement(item);
11410
+ const key = label?.getAttribute("data-ohw-key");
11411
+ const stored = key ? content[key] : void 0;
11412
+ if (!label || !stored || label === focused) return;
11413
+ if (fillEmptyOnly && label.textContent?.trim()) return;
11414
+ if (!stored.replace(/<br\s*\/?>/gi, "").trim()) return;
11415
+ if (label.innerHTML !== stored) label.innerHTML = stored;
11416
+ });
11417
+ });
11418
+ }
11341
11419
  function applySocialsDisplayFromContent(content, root = document) {
11342
11420
  const stored = parseSocialsDisplay(content[SOCIALS_DISPLAY_KEY]);
11343
11421
  if (!stored) return;
@@ -11357,8 +11435,14 @@ function applySocialsDisplayFromContent(content, root = document) {
11357
11435
  function socialsMissingIcons(row) {
11358
11436
  return listSocialItems(row).filter((item) => {
11359
11437
  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));
11438
+ return !slot || !slot.firstElementChild || slot.hasAttribute(SOCIALS_ICON_PLACEHOLDER_ATTR);
11439
+ }).map((item) => ({
11440
+ hrefKey: socialHrefKey(item) ?? "",
11441
+ url: item.getAttribute("href") ?? "",
11442
+ // Templates ship placeholder addresses — serene-oasis writes "[INSTAGRAM URL]" — and then the
11443
+ // words are the only thing naming the network.
11444
+ label: (socialLabelElement(item)?.textContent ?? item.getAttribute("aria-label") ?? "").trim()
11445
+ })).filter((entry) => Boolean(entry.hrefKey));
11362
11446
  }
11363
11447
  function ensureIconSlot(item) {
11364
11448
  const existing = item.querySelector(ICON_SELECTOR);
@@ -11372,6 +11456,8 @@ function ensureIconSlot(item) {
11372
11456
  slot.setAttribute("data-ohw-key", iconKey);
11373
11457
  slot.setAttribute("data-ohw-editable", "icon");
11374
11458
  slot.style.display = "inline-flex";
11459
+ slot.innerHTML = PLACEHOLDER_SOCIAL_ICON;
11460
+ slot.setAttribute(SOCIALS_ICON_PLACEHOLDER_ATTR, "");
11375
11461
  item.prepend(slot);
11376
11462
  return iconKey;
11377
11463
  }
@@ -13945,12 +14031,27 @@ function collectEditableNodes(extraContent, root = document) {
13945
14031
  nodes.push({ key, type: "link", text: href });
13946
14032
  }
13947
14033
  if (extraContent) {
13948
- for (const key of [NAV_ORDER_KEY, FOOTER_ORDER_KEY, NAV_COUNT_KEY, SECTION_ORDER_KEY]) {
14034
+ for (const key of [
14035
+ NAV_ORDER_KEY,
14036
+ FOOTER_ORDER_KEY,
14037
+ NAV_COUNT_KEY,
14038
+ SECTION_ORDER_KEY,
14039
+ // A socials row's order and its icons-vs-words setting live under keys no element carries,
14040
+ // so collecting the DOM alone left them behind: the draft knew the row was showing icons and
14041
+ // had gained an item, and the published page went back to the template's own (OHH-736).
14042
+ SOCIALS_ORDER_KEY,
14043
+ SOCIALS_DISPLAY_KEY
14044
+ ]) {
13949
14045
  const text = extraContent[key];
13950
14046
  if (typeof text === "string" && text.length > 0) {
13951
14047
  nodes.push({ key, type: "meta", text });
13952
14048
  }
13953
14049
  }
14050
+ for (const [key, text] of Object.entries(extraContent)) {
14051
+ if (key.endsWith("-platform") && typeof text === "string" && text.length > 0) {
14052
+ nodes.push({ key, type: "meta", text });
14053
+ }
14054
+ }
13954
14055
  }
13955
14056
  if (!isScoped) {
13956
14057
  document.querySelectorAll('[data-ohw-editable="video"]').forEach((el) => {
@@ -14303,7 +14404,7 @@ function NavbarContainerChrome({
14303
14404
  }
14304
14405
 
14305
14406
  // src/ui/drop-indicator.tsx
14306
- var React10 = __toESM(require("react"), 1);
14407
+ var React11 = __toESM(require("react"), 1);
14307
14408
  var import_jsx_runtime31 = require("react/jsx-runtime");
14308
14409
  var dropIndicatorVariants = cva(
14309
14410
  "ov-gap-line pointer-events-none shrink-0 transition-opacity duration-150",
@@ -14326,7 +14427,7 @@ var dropIndicatorVariants = cva(
14326
14427
  }
14327
14428
  }
14328
14429
  );
14329
- var DropIndicator = React10.forwardRef(
14430
+ var DropIndicator = React11.forwardRef(
14330
14431
  ({ className, direction, state, ...props }, ref) => {
14331
14432
  return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
14332
14433
  "div",
@@ -14940,6 +15041,15 @@ function isPointOverNavItem(container, x, y) {
14940
15041
  return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
14941
15042
  });
14942
15043
  }
15044
+ function socialsRowAtPoint(x, y) {
15045
+ const inside = (el) => {
15046
+ const r2 = el.getBoundingClientRect();
15047
+ return x >= r2.left && x <= r2.right && y >= r2.top && y <= r2.bottom;
15048
+ };
15049
+ return Array.from(document.querySelectorAll(`[${SOCIALS_ROW_ATTR}]`)).find(
15050
+ (row) => inside(row) && !listSocialItems(row).some(inside)
15051
+ ) ?? null;
15052
+ }
14943
15053
  function isPointOverFooterColumn(x, y) {
14944
15054
  return listFooterColumns().some((col) => {
14945
15055
  const r2 = col.getBoundingClientRect();
@@ -16522,7 +16632,8 @@ function OhhwellsBridge() {
16522
16632
  return;
16523
16633
  }
16524
16634
  const after = getSocialItem(selected);
16525
- const planned = planSocialInsert(socialsRow, editContentRef.current);
16635
+ const stillPromised = pendingSocialAddRef.current ? [pendingSocialAddRef.current.iconKey] : [];
16636
+ const planned = planSocialInsert(socialsRow, editContentRef.current, stillPromised);
16526
16637
  if (!planned) return;
16527
16638
  pendingSocialAddRef.current = { row: socialsRow, after, ...planned };
16528
16639
  postToParentRef.current({
@@ -16782,7 +16893,8 @@ function OhhwellsBridge() {
16782
16893
  applySocialsOrder(nextSocialsOrder);
16783
16894
  postToParentRef.current({
16784
16895
  type: "ow:change",
16785
- nodes: [{ key: SOCIALS_ORDER_KEY, text: orderJson }]
16896
+ nodes: [{ key: SOCIALS_ORDER_KEY, text: orderJson }],
16897
+ flush: true
16786
16898
  });
16787
16899
  applySelectionAfterDrop();
16788
16900
  clearFooterDragVisuals();
@@ -16972,7 +17084,7 @@ function OhhwellsBridge() {
16972
17084
  }
16973
17085
  const selected = selectedElRef.current;
16974
17086
  if (!selected || !isNavigationItem2(selected)) return;
16975
- const editable = selected.querySelector('[data-ohw-editable="text"]') ?? selected.querySelector("[data-ohw-editable]");
17087
+ const editable = selected.querySelector('[data-ohw-editable="text"], [data-ohw-editable="plain"]') ?? selected.querySelector('[data-ohw-editable]:not([data-ohw-editable="icon"])');
16976
17088
  if (!editable) return;
16977
17089
  activateRef.current(editable, { caretX: clientX, caretY: clientY });
16978
17090
  }, []);
@@ -17127,13 +17239,16 @@ function OhhwellsBridge() {
17127
17239
  const isEditModeRef = (0, import_react17.useRef)(false);
17128
17240
  const requestMissingSocialIconsRef = (0, import_react17.useRef)(() => {
17129
17241
  });
17242
+ const askedSocialIconsRef = (0, import_react17.useRef)(/* @__PURE__ */ new Set());
17130
17243
  const requestMissingSocialIcons = (0, import_react17.useCallback)(() => {
17131
17244
  const items = Array.from(document.querySelectorAll(`[${SOCIALS_ROW_ATTR}]`)).filter((row) => socialsDisplayFor(row, editContentRef.current).icon).flatMap((row) => {
17132
17245
  const missing = socialsMissingIcons(row);
17133
17246
  listSocialItems(row).forEach((item) => ensureIconSlot(item));
17134
17247
  return missing;
17135
17248
  });
17136
- if (items.length) postToParentRef.current({ type: "ow:social-icons-needed", items });
17249
+ const fresh = items.filter((item) => !askedSocialIconsRef.current.has(`${item.hrefKey}|${item.url}`));
17250
+ fresh.forEach((item) => askedSocialIconsRef.current.add(`${item.hrefKey}|${item.url}`));
17251
+ if (fresh.length) postToParentRef.current({ type: "ow:social-icons-needed", items: fresh });
17137
17252
  }, []);
17138
17253
  requestMissingSocialIconsRef.current = requestMissingSocialIcons;
17139
17254
  isEditModeRef.current = isEditMode;
@@ -17142,6 +17257,7 @@ function OhhwellsBridge() {
17142
17257
  if (next.icon) {
17143
17258
  const missing = socialsMissingIcons(row);
17144
17259
  listSocialItems(row).forEach((item) => ensureIconSlot(item));
17260
+ missing.forEach((item) => askedSocialIconsRef.current.delete(`${item.hrefKey}|${item.url}`));
17145
17261
  if (missing.length) {
17146
17262
  postToParentRef.current({ type: "ow:social-icons-needed", items: missing });
17147
17263
  }
@@ -17231,7 +17347,15 @@ function OhhwellsBridge() {
17231
17347
  );
17232
17348
  const activate = (0, import_react17.useCallback)((el, options) => {
17233
17349
  if (activeElRef.current === el) return;
17234
- if (isIconEditable(el)) return;
17350
+ if (isIconEditable(el)) {
17351
+ const social = getSocialItem(el);
17352
+ const words = social ? social.querySelector('[data-ohw-editable="text"], [data-ohw-editable="plain"]') : null;
17353
+ if (words && words.offsetParent !== null) {
17354
+ if (social && selectedElRef.current !== social) selectRef.current(social);
17355
+ activateRef.current(words, options);
17356
+ }
17357
+ return;
17358
+ }
17235
17359
  if (el.hasAttribute("data-ohw-social-label") && el.offsetParent === null) return;
17236
17360
  clearSelectedAttr();
17237
17361
  selectedElRef.current = null;
@@ -17410,6 +17534,7 @@ function OhhwellsBridge() {
17410
17534
  reconcileFooterOrderFromContent(content);
17411
17535
  reconcileSocialsFromContent(content);
17412
17536
  applySocialsDisplayFromContent(content);
17537
+ applySocialsLabelsFromContent(content, document, { fillEmptyOnly: isEditModeRef.current });
17413
17538
  if (isEditModeRef.current) requestMissingSocialIconsRef.current();
17414
17539
  enforceLinkHrefs();
17415
17540
  initSectionsFromContent(content, true);
@@ -17595,6 +17720,7 @@ function OhhwellsBridge() {
17595
17720
  reconcileFooterOrderFromContent(content);
17596
17721
  reconcileSocialsFromContent(content);
17597
17722
  applySocialsDisplayFromContent(content);
17723
+ applySocialsLabelsFromContent(content, document, { fillEmptyOnly: isEditModeRef.current });
17598
17724
  if (isEditModeRef.current) requestMissingSocialIconsRef.current();
17599
17725
  document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
17600
17726
  if (!form.querySelector("[data-ohw-form-success]")) {
@@ -17681,6 +17807,7 @@ function OhhwellsBridge() {
17681
17807
  reconcileFooterOrderFromContent(content);
17682
17808
  reconcileSocialsFromContent(content);
17683
17809
  applySocialsDisplayFromContent(content);
17810
+ applySocialsLabelsFromContent(content, document, { fillEmptyOnly: isEditModeRef.current });
17684
17811
  if (isEditModeRef.current) requestMissingSocialIconsRef.current();
17685
17812
  document.querySelectorAll("footer [data-ohw-href-key]").forEach((el) => {
17686
17813
  if (isFooterHrefKey(el.getAttribute("data-ohw-href-key")) || getSocialItem(el)) {
@@ -17785,6 +17912,66 @@ function OhhwellsBridge() {
17785
17912
  [style*="100vh"] { min-height: ${initialVh}px !important; height: ${initialVh}px !important; }
17786
17913
  [style*="100svh"] { min-height: ${initialVh}px !important; height: ${initialVh}px !important; }
17787
17914
  [style*="100dvh"] { min-height: ${initialVh}px !important; height: ${initialVh}px !important; }
17915
+ /* Emptied text keeps somewhere to click. A label typed down to nothing collapses to a
17916
+ couple of pixels, and getting back into it meant hunting for the caret with the mouse.
17917
+ Edit mode only \u2014 the published page shows nothing where there is nothing (OHH-736). */
17918
+ [data-ohw-editable="text"]:empty,
17919
+ [data-ohw-editable="plain"]:empty,
17920
+ [data-ohw-editable="text"]:has(> br:only-child),
17921
+ [data-ohw-editable="plain"]:has(> br:only-child) {
17922
+ min-width: 8ch;
17923
+ min-height: 1.4em;
17924
+ padding: 0 4px;
17925
+ }
17926
+ /* A social left deliberately wordless is a choice, not a mistake, so its empty label takes no
17927
+ room at rest \u2014 the row stays as tight as the site draws it. The box appears only while that
17928
+ row is being worked on: pointer over it, or the item selected (OHH-736). */
17929
+ /* The room itself is kept by the element in both modes \u2014 see markEmptySocialLabels. Left
17930
+ here is only what belongs to editing: something to aim at inside that room. */
17931
+ [data-ohw-socials-row] [data-ohw-empty-label] {
17932
+ padding: 0 4px;
17933
+ }
17934
+ [data-ohw-editable="text"]:empty::before,
17935
+ [data-ohw-editable="plain"]:empty::before {
17936
+ content: '';
17937
+ display: inline-block;
17938
+ width: 100%;
17939
+ height: 1.4em;
17940
+ }
17941
+ /* Not inside a socials row. A stand-in the width of its container is right for a paragraph
17942
+ that has been emptied, but beside an icon it opened a gap as wide as the row would allow:
17943
+ the editor showed the icons strewn across three lines while the published page \u2014 which
17944
+ carries no editing chrome at all \u2014 packed them together, and the two looked nothing alike
17945
+ (OHH-736). The box is given its width on hover and selection instead, which is when it is
17946
+ there to be clicked into. */
17947
+ [data-ohw-socials-row] [data-ohw-editable="text"]:empty::before,
17948
+ [data-ohw-socials-row] [data-ohw-editable="plain"]:empty::before {
17949
+ width: 0;
17950
+ }
17951
+ /* Room inside a socials row so the row itself can be clicked. Without it the items fill their
17952
+ own frame edge to edge and the only way to the row was through an icon and Select parent. */
17953
+ [data-ohw-socials-row] {
17954
+ padding: 6px;
17955
+ }
17956
+ /* A row of socials stays a row. The blanket block above is for body text; applied to the
17957
+ words inside a social it stacked every item on its own line, so instead of wrapping the
17958
+ row grew downwards and pushed the footer with it (OHH-736). */
17959
+ [data-ohw-socials-row] [data-ohw-editable="text"],
17960
+ [data-ohw-socials-row] [data-ohw-editable="plain"] {
17961
+ display: inline-block;
17962
+ }
17963
+ /* The glyph too, and this one mattered most: as a block it filled the whole width of its
17964
+ link and sat over the words, so every click meant for the text landed on the icon. */
17965
+ [data-ohw-socials-row] [data-ohw-editable="icon"] {
17966
+ display: inline-flex;
17967
+ flex: 0 0 auto;
17968
+ align-items: center;
17969
+ }
17970
+ [data-ohw-socials-row] a {
17971
+ display: inline-flex;
17972
+ align-items: center;
17973
+ gap: 6px;
17974
+ }
17788
17975
  /* Not the form: it is a layout container (flex/grid with gaps), and forcing block
17789
17976
  crushed its fields together (OHH-490). */
17790
17977
  [data-ohw-editable]:not([data-ohw-editable="form"]) {
@@ -18037,6 +18224,13 @@ function OhhwellsBridge() {
18037
18224
  return;
18038
18225
  }
18039
18226
  }
18227
+ const socialsRowUnderPoint = socialsRowAtPoint(e.clientX, e.clientY);
18228
+ if (socialsRowUnderPoint) {
18229
+ e.preventDefault();
18230
+ e.stopPropagation();
18231
+ selectFrameRef.current(socialsRowUnderPoint);
18232
+ return;
18233
+ }
18040
18234
  const logoEl = getLogoElement(target);
18041
18235
  if (logoEl) {
18042
18236
  e.preventDefault();
@@ -18091,6 +18285,19 @@ function OhhwellsBridge() {
18091
18285
  }
18092
18286
  return;
18093
18287
  }
18288
+ const socialItem = getSocialItem(editable);
18289
+ const isVisibleWords = (editable.dataset.ohwEditable === "text" || editable.dataset.ohwEditable === "plain") && editable.offsetParent !== null;
18290
+ if (socialItem && isVisibleWords) {
18291
+ e.preventDefault();
18292
+ e.stopPropagation();
18293
+ if (activeElRef.current === editable) return;
18294
+ if (selectedElRef.current === socialItem) {
18295
+ activateRef.current(editable, { caretX: e.clientX, caretY: e.clientY });
18296
+ return;
18297
+ }
18298
+ selectRef.current(socialItem);
18299
+ return;
18300
+ }
18094
18301
  const hrefLookupTarget = buttonOnMedia ? clickedButton : editable;
18095
18302
  const hrefCtx = getHrefKeyFromElement(hrefLookupTarget);
18096
18303
  const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
@@ -18160,7 +18367,7 @@ function OhhwellsBridge() {
18160
18367
  selectFrameRef.current(navContainerToSelect);
18161
18368
  return;
18162
18369
  }
18163
- const socialsRowToSelect = isSocialsRow(target) ? target : null;
18370
+ const socialsRowToSelect = isSocialsRow(target) ? target : findSocialsRow(target);
18164
18371
  if (socialsRowToSelect && !getSocialItem(target)) {
18165
18372
  e.preventDefault();
18166
18373
  e.stopPropagation();
@@ -19162,15 +19369,25 @@ function OhhwellsBridge() {
19162
19369
  if (pending && updates.some((update) => update.hrefKey === pending.hrefKey)) {
19163
19370
  pendingSocialAddRef.current = null;
19164
19371
  if (pending.row.isConnected) {
19165
- const created = insertSocialItem(pending.row, pending.after, editContentRef.current);
19372
+ const created = insertSocialItem(pending.row, pending.after, editContentRef.current, {
19373
+ keys: { hrefKey: pending.hrefKey, iconKey: pending.iconKey }
19374
+ });
19166
19375
  if (created) {
19167
19376
  const orderJson = JSON.stringify(created.order);
19168
19377
  editContentRef.current = { ...editContentRef.current, [SOCIALS_ORDER_KEY]: orderJson };
19169
19378
  nodes.push({ key: SOCIALS_ORDER_KEY, text: orderJson });
19379
+ const words = created.item.querySelector(
19380
+ '[data-ohw-social-label], [data-ohw-editable="text"], [data-ohw-editable="plain"]'
19381
+ );
19382
+ const labelKey = words?.getAttribute("data-ohw-key");
19383
+ const labelText = words?.textContent?.trim();
19384
+ if (labelKey && labelText && !editContentRef.current[labelKey]) {
19385
+ nodes.push({ key: labelKey, text: labelText });
19386
+ }
19170
19387
  }
19171
19388
  }
19172
19389
  }
19173
- for (const { hrefKey, iconKey: requestedIconKey, url, iconMarkup, platformId, label } of updates) {
19390
+ for (const { hrefKey, iconKey: requestedIconKey, url, iconMarkup, platformId, label, keepLabel } of updates) {
19174
19391
  if (hrefKey) {
19175
19392
  document.querySelectorAll(`[data-ohw-href-key="${hrefKey}"]`).forEach((el) => applyLinkHref(el, url));
19176
19393
  nodes.push({ key: hrefKey, text: url });
@@ -19182,6 +19399,7 @@ function OhhwellsBridge() {
19182
19399
  if (iconKey && typeof iconMarkup === "string" && iconMarkup) {
19183
19400
  document.querySelectorAll(`[data-ohw-key="${iconKey}"][data-ohw-editable="icon"]`).forEach((el) => {
19184
19401
  applyIconMarkup(el, iconMarkup);
19402
+ el.removeAttribute(SOCIALS_ICON_PLACEHOLDER_ATTR);
19185
19403
  });
19186
19404
  nodes.push({ key: iconKey, text: iconMarkup });
19187
19405
  }
@@ -19189,9 +19407,10 @@ function OhhwellsBridge() {
19189
19407
  if (iconKey && label) {
19190
19408
  const labelKey = socialLabelKey(iconKey);
19191
19409
  document.querySelectorAll(`[data-ohw-key="${labelKey}"]`).forEach((el) => {
19410
+ if (keepLabel && el.textContent?.trim()) return;
19192
19411
  el.textContent = label;
19193
19412
  });
19194
- nodes.push({ key: labelKey, text: label });
19413
+ if (!keepLabel) nodes.push({ key: labelKey, text: label });
19195
19414
  }
19196
19415
  }
19197
19416
  if (!nodes.length) return;
@@ -19324,8 +19543,11 @@ function OhhwellsBridge() {
19324
19543
  }
19325
19544
  setMaxBadge({ rect: el.getBoundingClientRect(), current: Math.min(current, maxLen), max: maxLen });
19326
19545
  }
19546
+ if (el.closest(`[${SOCIALS_ROW_ATTR}]`)) markEmptySocialLabels(document, el);
19327
19547
  const html = sanitizeHtml(el.innerHTML);
19328
- document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((sibling) => {
19548
+ editContentRef.current = { ...editContentRef.current, [key]: html };
19549
+ const sharing = document.querySelectorAll(`[data-ohw-key="${key}"]`);
19550
+ sharing.forEach((sibling) => {
19329
19551
  if (sibling !== el) sibling.innerHTML = html;
19330
19552
  });
19331
19553
  const timers = autoSaveTimers.current;
@@ -20665,15 +20887,23 @@ function OhhwellsBridge() {
20665
20887
  const result = duplicateSocialItem(social, editContentRef.current);
20666
20888
  if (!result) return;
20667
20889
  const orderJson = JSON.stringify(result.order);
20890
+ const copyIcon = result.item.querySelector('[data-ohw-editable="icon"]');
20891
+ const copyLabel = result.item.querySelector(
20892
+ '[data-ohw-social-label], [data-ohw-editable="text"], [data-ohw-editable="plain"]'
20893
+ );
20894
+ const storedOf = (key) => key ? editContentRef.current[key] : void 0;
20668
20895
  const carried = [
20669
- { from: result.copiedFrom?.href, to: result.hrefKey },
20670
- { from: result.copiedFrom?.icon, to: result.iconKey },
20671
- { from: result.copiedFrom?.icon ? socialPlatformKey(result.copiedFrom.icon) : null, to: socialPlatformKey(result.iconKey) }
20896
+ { key: result.hrefKey, text: storedOf(result.copiedFrom?.href) ?? result.item.getAttribute("href") },
20897
+ { key: result.iconKey, text: storedOf(result.copiedFrom?.icon) ?? copyIcon?.innerHTML },
20898
+ {
20899
+ key: socialPlatformKey(result.iconKey),
20900
+ text: storedOf(result.copiedFrom?.icon ? socialPlatformKey(result.copiedFrom.icon) : null)
20901
+ },
20902
+ { key: copyLabel?.getAttribute("data-ohw-key"), text: copyLabel?.textContent?.trim() }
20672
20903
  ];
20673
20904
  const nodes = [{ key: SOCIALS_ORDER_KEY, text: orderJson }];
20674
- for (const { from, to } of carried) {
20675
- const value = from ? editContentRef.current[from] : void 0;
20676
- if (value) nodes.push({ key: to, text: value });
20905
+ for (const { key, text } of carried) {
20906
+ if (key && text) nodes.push({ key, text });
20677
20907
  }
20678
20908
  editContentRef.current = {
20679
20909
  ...editContentRef.current,
@@ -21200,7 +21430,7 @@ function OhhwellsBridge() {
21200
21430
  onDragHandleDragEnd: handleItemDragEnd,
21201
21431
  onItemPointerDown: toolbarVariant === "logo" ? void 0 : handleItemChromePointerDown,
21202
21432
  onItemClick: toolbarVariant === "logo" ? void 0 : handleItemChromeClick,
21203
- itemDragSurface: toolbarVariant !== "logo" && !isFooterFrameSelection,
21433
+ itemDragSurface: toolbarVariant !== "logo" && !isFooterFrameSelection && !selectedIsSocialsRow,
21204
21434
  toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && (isFooterFrameSelection || selectedIsSocialsRow) && !isItemDragging ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
21205
21435
  ItemActionToolbar,
21206
21436
  {