@ohhwells/bridge 0.1.55 → 0.1.57

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.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  // src/OhhwellsBridge.tsx
4
- import React11, { useCallback as useCallback6, useEffect as useEffect11, useLayoutEffect as useLayoutEffect3, useRef as useRef8, useState as useState10 } from "react";
4
+ import React11, { useCallback as useCallback7, useEffect as useEffect12, useLayoutEffect as useLayoutEffect4, useRef as useRef9, useState as useState11 } from "react";
5
5
  import { createRoot as createRoot2 } from "react-dom/client";
6
6
  import { flushSync as flushSync2 } from "react-dom";
7
7
 
@@ -162,13 +162,17 @@ function MediaBox({
162
162
  const url = refValue ? ctx.resolveMedia(refValue) : null;
163
163
  const isIcon = /^(lucide|simple):/.test(refValue);
164
164
  const aspectRatio = aspect && /^\d+:\d+$/.test(aspect) ? aspect.replace(":", " / ") : void 0;
165
- const editAttrs = ctx.keyFor && editPath && !isIcon ? { "data-ohw-key": ctx.keyFor(editPath), "data-ohw-editable": "image" } : {};
165
+ const editAttrs = ctx.keyFor && editPath ? {
166
+ "data-ohw-key": ctx.keyFor(editPath),
167
+ "data-ohw-editable": isIcon ? "icon" : "image"
168
+ } : {};
166
169
  if (isIcon) {
167
170
  const Icon = refValue.startsWith("lucide:") ? lucideByName(refValue.slice(7)) : null;
168
171
  return /* @__PURE__ */ jsx(
169
172
  "span",
170
173
  {
171
174
  "data-ai-icon": refValue,
175
+ ...editAttrs,
172
176
  style: {
173
177
  display: "inline-flex",
174
178
  width: 48,
@@ -5697,7 +5701,7 @@ CustomToolbarButton.displayName = "CustomToolbarButton";
5697
5701
 
5698
5702
  // src/ui/item-action-toolbar.tsx
5699
5703
  import { useState as useState3 } from "react";
5700
- import { Copy, CornerLeftUp, Heading, Link, MoreHorizontal, Plus, Trash2 } from "lucide-react";
5704
+ import { Brush, Copy, CornerLeftUp, Heading, Link, MoreHorizontal, Plus, Trash2 } from "lucide-react";
5701
5705
 
5702
5706
  // src/ui/dropdown-menu.tsx
5703
5707
  import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui";
@@ -5862,6 +5866,7 @@ function ToolbarActionTooltip({
5862
5866
  function ItemActionToolbar({
5863
5867
  onEditLink,
5864
5868
  onAddItem,
5869
+ onStyle,
5865
5870
  onSelectParent,
5866
5871
  onDuplicate,
5867
5872
  onDelete,
@@ -5873,6 +5878,8 @@ function ItemActionToolbar({
5873
5878
  deleteDisabled = false,
5874
5879
  showEditLink = true,
5875
5880
  showAddItem = true,
5881
+ showStyle = false,
5882
+ styleActive = false,
5876
5883
  showMore = true,
5877
5884
  tooltipSide = "bottom",
5878
5885
  dropdownOpen = null,
@@ -5946,6 +5953,22 @@ function ItemActionToolbar({
5946
5953
  children: /* @__PURE__ */ jsx11(Link, { className: "size-4 shrink-0", "aria-hidden": true })
5947
5954
  }
5948
5955
  ) : null,
5956
+ showStyle ? /* @__PURE__ */ jsx11(
5957
+ ToolbarActionTooltip,
5958
+ {
5959
+ label: "Style",
5960
+ side: tooltipSide,
5961
+ buttonProps: {
5962
+ active: styleActive,
5963
+ onMouseDown: (e) => {
5964
+ e.preventDefault();
5965
+ e.stopPropagation();
5966
+ onStyle?.();
5967
+ }
5968
+ },
5969
+ children: /* @__PURE__ */ jsx11(Brush, { className: "size-4 shrink-0", "aria-hidden": true })
5970
+ }
5971
+ ) : null,
5949
5972
  showAddItem ? /* @__PURE__ */ jsx11(
5950
5973
  ToolbarActionTooltip,
5951
5974
  {
@@ -6929,6 +6952,47 @@ function AiSectionOverlay({
6929
6952
  ] });
6930
6953
  }
6931
6954
 
6955
+ // src/lib/section-instances.ts
6956
+ var SECTION_ORDER_KEY = "__ohw_section_order";
6957
+ function getPageSectionOrderEntries(raw, currentPath) {
6958
+ if (!raw) return [];
6959
+ try {
6960
+ const entries = JSON.parse(raw);
6961
+ return entries.filter((e) => !e.pagePath || e.pagePath === currentPath);
6962
+ } catch {
6963
+ return [];
6964
+ }
6965
+ }
6966
+ function rekeySectionSubtree(root, instanceId) {
6967
+ const suffix = `::${instanceId}`;
6968
+ const rekey = (el, attr) => {
6969
+ const current = el.getAttribute(attr);
6970
+ if (current) el.setAttribute(attr, `${current}${suffix}`);
6971
+ };
6972
+ if (root.hasAttribute("data-ohw-key")) rekey(root, "data-ohw-key");
6973
+ if (root.hasAttribute("data-ohw-href-key")) rekey(root, "data-ohw-href-key");
6974
+ root.querySelectorAll("[data-ohw-key]").forEach((el) => rekey(el, "data-ohw-key"));
6975
+ root.querySelectorAll("[data-ohw-href-key]").forEach((el) => rekey(el, "data-ohw-href-key"));
6976
+ }
6977
+ function initSectionInstancesFromContent(content, currentPath) {
6978
+ document.querySelectorAll("[data-ohw-section]:not([data-ohw-instance])").forEach((el) => {
6979
+ el.setAttribute("data-ohw-instance", el.getAttribute("data-ohw-section") ?? "");
6980
+ });
6981
+ const entries = getPageSectionOrderEntries(content[SECTION_ORDER_KEY], currentPath);
6982
+ for (const entry of entries) {
6983
+ if (entry.instanceId === entry.type) continue;
6984
+ if (document.querySelector(`[data-ohw-instance="${CSS.escape(entry.instanceId)}"]`)) continue;
6985
+ const original = document.querySelector(
6986
+ `[data-ohw-section="${CSS.escape(entry.type)}"][data-ohw-instance="${CSS.escape(entry.type)}"]`
6987
+ );
6988
+ if (!original) continue;
6989
+ const clone = original.cloneNode(true);
6990
+ clone.setAttribute("data-ohw-instance", entry.instanceId);
6991
+ rekeySectionSubtree(clone, entry.instanceId);
6992
+ original.insertAdjacentElement("afterend", clone);
6993
+ }
6994
+ }
6995
+
6932
6996
  // src/OhhwellsBridge.tsx
6933
6997
  import { createPortal as createPortal2 } from "react-dom";
6934
6998
  import { usePathname as usePathname2, useRouter as useRouter3, useSearchParams } from "next/navigation";
@@ -6961,9 +7025,16 @@ function isPointOverBridgeChrome(x, y) {
6961
7025
  }
6962
7026
  return false;
6963
7027
  }
6964
- function findCtaButtonAtPoint(x, y, media) {
7028
+ var BUTTON_LIKE_SELECTOR = `button, [role="button"], ${CTA_BUTTON_SELECTOR}`;
7029
+ function isButtonLikeElement(el) {
7030
+ return el.matches(BUTTON_LIKE_SELECTOR);
7031
+ }
7032
+ function findClosestButtonLike(target) {
7033
+ return target.closest(BUTTON_LIKE_SELECTOR);
7034
+ }
7035
+ function findButtonAtPoint(x, y, media) {
6965
7036
  const hits = Array.from(
6966
- document.querySelectorAll(CTA_BUTTON_SELECTOR)
7037
+ document.querySelectorAll(BUTTON_LIKE_SELECTOR)
6967
7038
  ).filter((el) => containsPoint(el, x, y) && !(media && el.contains(media)));
6968
7039
  if (hits.length === 0) return null;
6969
7040
  return hits.reduce((best, el) => best.contains(el) ? el : best);
@@ -9452,6 +9523,449 @@ function deleteNavbarItem(sourceAnchor) {
9452
9523
  };
9453
9524
  }
9454
9525
 
9526
+ // src/lib/icon-markup.ts
9527
+ var GLYPH_SELECTOR = "svg, img";
9528
+ function referenceBox(slot) {
9529
+ const row = slot.closest("[data-ohw-socials-row]") ?? slot.closest("a")?.parentElement ?? null;
9530
+ const neighbour = row ? Array.from(row.querySelectorAll('[data-ohw-editable="icon"]')).find((el) => el !== slot) : null;
9531
+ const source = (neighbour ?? slot).querySelector(GLYPH_SELECTOR);
9532
+ const box = source?.getBoundingClientRect() ?? null;
9533
+ return box?.width && box.height ? box : null;
9534
+ }
9535
+ function iconMarkupSizedFor(slot, markup) {
9536
+ const box = referenceBox(slot);
9537
+ if (!box) return markup;
9538
+ const holder = document.createElement("div");
9539
+ holder.innerHTML = markup;
9540
+ const glyph = holder.querySelector(GLYPH_SELECTOR);
9541
+ if (!glyph) return markup;
9542
+ glyph.style.width = `${Math.round(box.width)}px`;
9543
+ glyph.style.height = `${Math.round(box.height)}px`;
9544
+ return holder.innerHTML;
9545
+ }
9546
+ function applyIconMarkup(slot, markup) {
9547
+ if (!markup) return;
9548
+ const coloured = iconMarkupInheritingColour(markup);
9549
+ const sized = iconMarkupSizedFor(slot, coloured);
9550
+ if (slot.innerHTML !== sized) slot.innerHTML = sized;
9551
+ if (sized === coloured) {
9552
+ requestAnimationFrame(() => {
9553
+ if (!slot.isConnected) return;
9554
+ const resized = iconMarkupSizedFor(slot, coloured);
9555
+ if (resized !== coloured && slot.innerHTML !== resized) slot.innerHTML = resized;
9556
+ });
9557
+ }
9558
+ }
9559
+ function detectIconStyle(el) {
9560
+ const row = el.closest("[data-ohw-socials-row]");
9561
+ const glyphs = Array.from((row ?? el).querySelectorAll("svg"));
9562
+ const outlined = glyphs.some((svg) => {
9563
+ return Array.from(svg.querySelectorAll("*")).some((node) => {
9564
+ return node.getAttribute("stroke") !== null && node.getAttribute("stroke") !== "none";
9565
+ });
9566
+ });
9567
+ return outlined ? "outline" : "fill";
9568
+ }
9569
+ function iconMarkupInheritingColour(markup) {
9570
+ const holder = document.createElement("div");
9571
+ holder.innerHTML = markup;
9572
+ holder.querySelectorAll("svg *").forEach((node) => {
9573
+ if (node.getAttribute("fill") && node.getAttribute("fill") !== "none") {
9574
+ node.setAttribute("fill", "currentColor");
9575
+ }
9576
+ if (node.getAttribute("stroke") && node.getAttribute("stroke") !== "none") {
9577
+ node.setAttribute("stroke", "currentColor");
9578
+ }
9579
+ });
9580
+ return holder.innerHTML;
9581
+ }
9582
+
9583
+ // src/lib/socials-items.ts
9584
+ var ICON_SELECTOR = '[data-ohw-editable="icon"]';
9585
+ var SOCIAL_KEY_RE = /(^|-)social(s)?(-|$)/i;
9586
+ var SOCIALS_ROW_ATTR = "data-ohw-socials-row";
9587
+ var SOCIALS_ITEM_ATTR = "data-ohw-social-item";
9588
+ function isSocialItem(el) {
9589
+ if (!el) return false;
9590
+ const anchor = el instanceof HTMLAnchorElement ? el : el.closest("a");
9591
+ if (!anchor) return false;
9592
+ if (SOCIAL_KEY_RE.test(anchor.getAttribute("data-ohw-href-key") ?? "")) return true;
9593
+ return anchor.querySelectorAll(ICON_SELECTOR).length === 1;
9594
+ }
9595
+ function getSocialItem(el) {
9596
+ const anchor = el.closest("a");
9597
+ return isSocialItem(anchor) ? anchor : null;
9598
+ }
9599
+ function findSocialsRow(el) {
9600
+ const item = getSocialItem(el);
9601
+ if (!item) return null;
9602
+ const wrapper = item.parentElement;
9603
+ const row = wrapper && wrapper.querySelectorAll("a").length === 1 && wrapper.matches("li, div, span") ? wrapper.parentElement : wrapper;
9604
+ if (!row) return null;
9605
+ const anchors = Array.from(row.querySelectorAll("a"));
9606
+ if (!anchors.length || !anchors.every((anchor) => isSocialItem(anchor))) return null;
9607
+ return row;
9608
+ }
9609
+ function isSocialsRow(el) {
9610
+ const anchors = Array.from(el.querySelectorAll("a"));
9611
+ return anchors.length > 0 && anchors.every((anchor) => isSocialItem(anchor));
9612
+ }
9613
+ function listSocialItems(row) {
9614
+ return Array.from(row.children).map((child) => {
9615
+ if (!(child instanceof HTMLElement)) return null;
9616
+ const anchor = child.matches("a") ? child : child.querySelector("a");
9617
+ return isSocialItem(anchor) ? anchor : null;
9618
+ }).filter((item) => item !== null);
9619
+ }
9620
+ function socialRowUnit(item) {
9621
+ const row = findSocialsRow(item);
9622
+ let node = item;
9623
+ while (node.parentElement && node.parentElement !== row) {
9624
+ node = node.parentElement;
9625
+ }
9626
+ return node;
9627
+ }
9628
+ function listSocialsRows(root = document) {
9629
+ const rows = /* @__PURE__ */ new Set();
9630
+ root.querySelectorAll(`${ICON_SELECTOR}, a[data-ohw-href-key]`).forEach((el) => {
9631
+ const row = findSocialsRow(el);
9632
+ if (row) rows.add(row);
9633
+ });
9634
+ root.querySelectorAll(`[${SOCIALS_ROW_ATTR}]`).forEach((row) => rows.add(row));
9635
+ return Array.from(rows);
9636
+ }
9637
+ var rowTemplates = /* @__PURE__ */ new Map();
9638
+ function markSocialsRows(root = document) {
9639
+ root.querySelectorAll(`[${SOCIALS_ITEM_ATTR}]`).forEach((item) => {
9640
+ item.removeAttribute(SOCIALS_ITEM_ATTR);
9641
+ });
9642
+ listSocialsRows(root).forEach((row) => {
9643
+ row.setAttribute(SOCIALS_ROW_ATTR, "");
9644
+ const items = listSocialItems(row);
9645
+ if (items[0]) rowTemplates.set(rowKeyOf(row), socialRowUnit(items[0]).outerHTML);
9646
+ items.forEach((item, index) => {
9647
+ item.setAttribute(SOCIALS_ITEM_ATTR, String(index));
9648
+ const iconKey = socialIconKey(item);
9649
+ if (iconKey) ensureLabelSlot(item, iconKey);
9650
+ });
9651
+ });
9652
+ }
9653
+ var SOCIALS_LABEL_ATTR = "data-ohw-social-label";
9654
+ function ensureLabelSlot(item, iconKey) {
9655
+ if (socialLabelElement(item)) return;
9656
+ const label = document.createElement("span");
9657
+ label.setAttribute("data-ohw-key", `${iconKey}-label`);
9658
+ label.setAttribute("data-ohw-editable", "text");
9659
+ label.setAttribute(SOCIALS_LABEL_ATTR, "");
9660
+ label.style.display = "none";
9661
+ label.textContent = item.getAttribute("aria-label") ?? "";
9662
+ item.appendChild(label);
9663
+ }
9664
+ function socialLabelElement(item) {
9665
+ return item.querySelector(
9666
+ `[${SOCIALS_LABEL_ATTR}], [data-ohw-editable="text"], [data-ohw-editable="plain"]`
9667
+ );
9668
+ }
9669
+ function socialLabelKey(iconKey) {
9670
+ return `${iconKey}-label`;
9671
+ }
9672
+ function applyStoredValues(item, content) {
9673
+ const hrefKey = socialHrefKey(item);
9674
+ const iconKey = socialIconKey(item);
9675
+ if (hrefKey && content[hrefKey] !== void 0) item.setAttribute("href", content[hrefKey]);
9676
+ if (iconKey) {
9677
+ const glyph = item.querySelector(ICON_SELECTOR);
9678
+ if (glyph && content[iconKey]) applyIconMarkup(glyph, content[iconKey]);
9679
+ const label = item.querySelector(`[${SOCIALS_LABEL_ATTR}]`);
9680
+ label?.setAttribute("data-ohw-key", socialLabelKey(iconKey));
9681
+ const stored = content[socialLabelKey(iconKey)];
9682
+ if (label && stored) label.textContent = stored;
9683
+ }
9684
+ }
9685
+ function socialPlatformKey(iconKey) {
9686
+ return `${iconKey}-platform`;
9687
+ }
9688
+ function socialHrefKey(item) {
9689
+ return item.getAttribute("data-ohw-href-key");
9690
+ }
9691
+ function socialIconKey(item) {
9692
+ return item.querySelector(ICON_SELECTOR)?.dataset.ohwKey ?? null;
9693
+ }
9694
+ var SOCIALS_ORDER_KEY = "__ohw_socials_order";
9695
+ function fromMarkup(markup) {
9696
+ const holder = document.createElement("div");
9697
+ holder.innerHTML = markup;
9698
+ return holder.firstElementChild instanceof HTMLElement ? holder.firstElementChild : null;
9699
+ }
9700
+ var rowKeys = /* @__PURE__ */ new WeakMap();
9701
+ function rowKeyOf(row) {
9702
+ const first = listSocialItems(row)[0];
9703
+ const itemKey = first ? socialIconKey(first) ?? socialHrefKey(first)?.replace(/-href$/, "") : null;
9704
+ const derived = itemKey?.replace(/-[^-]+$/, "") || null;
9705
+ if (derived) rowKeys.set(row, derived);
9706
+ return derived ?? rowKeys.get(row) ?? "social";
9707
+ }
9708
+ function getSocialsOrderFromDom(root = document) {
9709
+ const order = {};
9710
+ listSocialsRows(root).forEach((row) => {
9711
+ order[rowKeyOf(row)] = listSocialItems(row).map((item) => socialHrefKey(item)).filter((key) => Boolean(key));
9712
+ });
9713
+ return order;
9714
+ }
9715
+ function hasStoredValue(content, hrefKey) {
9716
+ const iconKey = hrefKey.replace(/-href$/, "");
9717
+ return Boolean(content[hrefKey]) || Boolean(content[iconKey]);
9718
+ }
9719
+ function parseSocialsOrder(raw) {
9720
+ if (!raw) return null;
9721
+ try {
9722
+ const parsed = JSON.parse(raw);
9723
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
9724
+ } catch {
9725
+ return null;
9726
+ }
9727
+ }
9728
+ function nextSocialIndex(row, rowKey, content) {
9729
+ 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));
9730
+ return Math.max(-1, ...used) + 1;
9731
+ }
9732
+ function insertSocialItem(row, after, content = {}) {
9733
+ const rowKey = rowKeyOf(row);
9734
+ const template = listSocialItems(row)[0];
9735
+ const remembered = rowTemplates.get(rowKey);
9736
+ if (!template && !remembered) return null;
9737
+ const index = nextSocialIndex(row, rowKey, content);
9738
+ const iconKey = `${rowKey}-${index}`;
9739
+ const hrefKey = `${iconKey}-href`;
9740
+ const templateUnit = template ? socialRowUnit(template) : null;
9741
+ const unit = templateUnit ? templateUnit.cloneNode(true) : fromMarkup(remembered);
9742
+ const item = unit && (unit.matches("a") ? unit : unit.querySelector("a"));
9743
+ if (!unit || !item) return null;
9744
+ item.setAttribute("data-ohw-href-key", hrefKey);
9745
+ item.setAttribute("href", "");
9746
+ item.removeAttribute("aria-label");
9747
+ item.querySelectorAll("[data-ohw-hovered], [data-ohw-selected]").forEach((el) => {
9748
+ el.removeAttribute("data-ohw-hovered");
9749
+ el.removeAttribute("data-ohw-selected");
9750
+ });
9751
+ const icon = item.querySelector(ICON_SELECTOR);
9752
+ icon?.setAttribute("data-ohw-key", iconKey);
9753
+ item.querySelector(`[${SOCIALS_LABEL_ATTR}]`)?.remove();
9754
+ const afterUnit = after ? socialRowUnit(after) : null;
9755
+ if (afterUnit && afterUnit.parentElement === row) afterUnit.insertAdjacentElement("afterend", unit);
9756
+ else row.appendChild(unit);
9757
+ markSocialsRows(row.ownerDocument);
9758
+ return { item, hrefKey, iconKey, order: getSocialsOrderFromDom(row.ownerDocument) };
9759
+ }
9760
+ function duplicateSocialItem(item, content) {
9761
+ const row = findSocialsRow(item);
9762
+ const created = row ? insertSocialItem(row, item, content) : null;
9763
+ if (!created) return null;
9764
+ const sourceHref = socialHrefKey(item);
9765
+ const sourceIcon = socialIconKey(item);
9766
+ const link = created.item;
9767
+ if (sourceHref) link.setAttribute("href", item.getAttribute("href") ?? "");
9768
+ const glyph = item.querySelector(ICON_SELECTOR)?.innerHTML;
9769
+ if (glyph) {
9770
+ const slot = link.querySelector(ICON_SELECTOR);
9771
+ if (slot) slot.innerHTML = glyph;
9772
+ }
9773
+ return {
9774
+ ...created,
9775
+ copiedFrom: { href: sourceHref, icon: sourceIcon }
9776
+ };
9777
+ }
9778
+ function removeSocialItem(item, content) {
9779
+ const row = findSocialsRow(item);
9780
+ if (!row) return null;
9781
+ const hrefKey = socialHrefKey(item);
9782
+ const iconKey = socialIconKey(item);
9783
+ const removedKeys = [hrefKey, iconKey].filter((key) => Boolean(key));
9784
+ if (!removedKeys.length) return null;
9785
+ const previousOrder = getSocialsOrderFromDom(row.ownerDocument);
9786
+ const previousContent = Object.fromEntries(
9787
+ removedKeys.filter((key) => key in content).map((key) => [key, content[key]])
9788
+ );
9789
+ const unit = socialRowUnit(item);
9790
+ const nextSibling = unit.nextElementSibling;
9791
+ unit.remove();
9792
+ markSocialsRows(row.ownerDocument);
9793
+ return {
9794
+ removedKeys,
9795
+ previousContent,
9796
+ order: getSocialsOrderFromDom(row.ownerDocument),
9797
+ previousOrder,
9798
+ undo: () => {
9799
+ if (nextSibling) nextSibling.before(unit);
9800
+ else row.appendChild(unit);
9801
+ markSocialsRows(row.ownerDocument);
9802
+ }
9803
+ };
9804
+ }
9805
+ function applySocialsOrder(order, root = document) {
9806
+ listSocialsRows(root).forEach((row) => {
9807
+ const wanted = order[rowKeyOf(row)];
9808
+ if (!wanted) return;
9809
+ const byKey = new Map(listSocialItems(row).map((item) => [socialHrefKey(item), item]));
9810
+ wanted.forEach((key) => {
9811
+ const item = byKey.get(key);
9812
+ if (item) row.appendChild(socialRowUnit(item));
9813
+ });
9814
+ });
9815
+ markSocialsRows(root);
9816
+ }
9817
+ function reconcileSocialsFromContent(content, root = document) {
9818
+ markSocialsRows(root);
9819
+ const stored = parseSocialsOrder(content[SOCIALS_ORDER_KEY]);
9820
+ if (!stored) return;
9821
+ listSocialsRows(root).forEach((row) => {
9822
+ const wanted = stored[rowKeyOf(row)];
9823
+ if (!wanted) return;
9824
+ if (!wanted.length) return;
9825
+ wanted.forEach((key) => {
9826
+ if (listSocialItems(row).some((item) => socialHrefKey(item) === key)) return;
9827
+ if (!hasStoredValue(content, key)) return;
9828
+ const created = insertSocialItem(row, null, content);
9829
+ if (created) {
9830
+ created.item.setAttribute("data-ohw-href-key", key);
9831
+ created.item.querySelector(ICON_SELECTOR)?.setAttribute("data-ohw-key", key.replace(/-href$/, ""));
9832
+ applyStoredValues(created.item, content);
9833
+ }
9834
+ });
9835
+ const present = listSocialItems(row);
9836
+ const surviving = present.filter((item) => {
9837
+ const key = socialHrefKey(item);
9838
+ return !key || wanted.includes(key);
9839
+ });
9840
+ if (surviving.length) {
9841
+ present.forEach((item) => {
9842
+ if (!surviving.includes(item)) socialRowUnit(item).remove();
9843
+ });
9844
+ }
9845
+ });
9846
+ applySocialsOrder(stored, root);
9847
+ }
9848
+ var DROP_BAR_THICKNESS = 3;
9849
+ var DROP_BAR_GAP = 8;
9850
+ function buildSocialDropSlots(row) {
9851
+ const items = listSocialItems(row);
9852
+ if (!items.length) return [];
9853
+ const rects = items.map((item) => item.getBoundingClientRect());
9854
+ return items.concat(items[items.length - 1]).map((_, index) => {
9855
+ const previous = rects[index - 1];
9856
+ const next = rects[index];
9857
+ const centre = previous && next ? (previous.right + next.left) / 2 : next ? next.left - DROP_BAR_GAP : previous.right + DROP_BAR_GAP;
9858
+ const rect = next ?? previous;
9859
+ return {
9860
+ insertIndex: index,
9861
+ columnIndex: -1,
9862
+ left: centre - DROP_BAR_THICKNESS / 2,
9863
+ top: rect.top,
9864
+ width: DROP_BAR_THICKNESS,
9865
+ height: rect.height,
9866
+ direction: "vertical"
9867
+ };
9868
+ });
9869
+ }
9870
+ function findSocialByHrefKey(hrefKey, root = document) {
9871
+ const el = root.querySelector(`[data-ohw-href-key="${CSS.escape(hrefKey)}"]`);
9872
+ return el ? getSocialItem(el) : null;
9873
+ }
9874
+ function buildSocialDropSlotsForKey(hrefKey, root = document) {
9875
+ const item = findSocialByHrefKey(hrefKey, root);
9876
+ const row = item ? findSocialsRow(item) : null;
9877
+ return row ? buildSocialDropSlots(row) : [];
9878
+ }
9879
+ function hitTestSocialDropSlot(clientX, clientY, draggedHrefKey, root = document) {
9880
+ const distanceTo = (slot) => {
9881
+ const dx = clientX - (slot.left + slot.width / 2);
9882
+ const dy = clientY < slot.top ? slot.top - clientY : Math.max(0, clientY - (slot.top + slot.height));
9883
+ return Math.hypot(dx, dy);
9884
+ };
9885
+ const slots = buildSocialDropSlotsForKey(draggedHrefKey, root);
9886
+ return slots.reduce((best, slot) => {
9887
+ return !best || distanceTo(slot) < distanceTo(best) ? slot : best;
9888
+ }, null);
9889
+ }
9890
+ function planSocialMove(hrefKey, insertIndex, root = document) {
9891
+ const item = findSocialByHrefKey(hrefKey, root);
9892
+ const row = item ? findSocialsRow(item) : null;
9893
+ if (!row) return null;
9894
+ const order = getSocialsOrderFromDom(root);
9895
+ const key = rowKeyOf(row);
9896
+ const current = order[key];
9897
+ if (!current) return null;
9898
+ const from = current.indexOf(hrefKey);
9899
+ if (from < 0) return null;
9900
+ const next = current.filter((_, index) => index !== from);
9901
+ next.splice(insertIndex > from ? insertIndex - 1 : insertIndex, 0, hrefKey);
9902
+ return { ...order, [key]: next };
9903
+ }
9904
+ var SOCIALS_DISPLAY_KEY = "__ohw_socials_display";
9905
+ function readSocialsDisplay(row) {
9906
+ const items = listSocialItems(row);
9907
+ const visible = (el) => Boolean(el) && el.style.display !== "none" && el.getAttribute("data-ohw-hidden") === null;
9908
+ return {
9909
+ text: items.some((item) => visible(socialLabelElement(item))),
9910
+ icon: items.some((item) => visible(item.querySelector(ICON_SELECTOR)))
9911
+ };
9912
+ }
9913
+ function parseSocialsDisplay(raw) {
9914
+ if (!raw) return null;
9915
+ try {
9916
+ const parsed = JSON.parse(raw);
9917
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
9918
+ } catch {
9919
+ return null;
9920
+ }
9921
+ }
9922
+ function socialsDisplayFor(row, content) {
9923
+ return parseSocialsDisplay(content[SOCIALS_DISPLAY_KEY])?.[rowKeyOf(row)] ?? readSocialsDisplay(row);
9924
+ }
9925
+ function socialsDisplayWith(row, display, content) {
9926
+ return { ...parseSocialsDisplay(content[SOCIALS_DISPLAY_KEY]) ?? {}, [rowKeyOf(row)]: display };
9927
+ }
9928
+ function applySocialsDisplayToRow(row, display) {
9929
+ listSocialItems(row).forEach((item) => {
9930
+ const label = socialLabelElement(item);
9931
+ const icon = item.querySelector(ICON_SELECTOR);
9932
+ if (label) label.style.display = display.text ? "" : "none";
9933
+ if (icon) icon.style.display = display.icon ? "" : "none";
9934
+ });
9935
+ }
9936
+ function applySocialsDisplayFromContent(content, root = document) {
9937
+ const stored = parseSocialsDisplay(content[SOCIALS_DISPLAY_KEY]);
9938
+ if (!stored) return;
9939
+ listSocialsRows(root).forEach((row) => {
9940
+ const display = stored[rowKeyOf(row)];
9941
+ if (!display) return;
9942
+ if (display.icon) {
9943
+ listSocialItems(row).forEach((item) => {
9944
+ const iconKey = ensureIconSlot(item);
9945
+ const slot = item.querySelector(ICON_SELECTOR);
9946
+ if (iconKey && slot && content[iconKey]) applyIconMarkup(slot, content[iconKey]);
9947
+ });
9948
+ }
9949
+ applySocialsDisplayToRow(row, display);
9950
+ });
9951
+ }
9952
+ function socialsMissingIcons(row) {
9953
+ return listSocialItems(row).filter((item) => !item.querySelector(ICON_SELECTOR)).map((item) => ({ hrefKey: socialHrefKey(item) ?? "", url: item.getAttribute("href") ?? "" })).filter((entry) => Boolean(entry.hrefKey));
9954
+ }
9955
+ function ensureIconSlot(item) {
9956
+ const existing = item.querySelector(ICON_SELECTOR);
9957
+ if (existing) return existing.dataset.ohwKey ?? null;
9958
+ const hrefKey = socialHrefKey(item);
9959
+ if (!hrefKey) return null;
9960
+ const iconKey = hrefKey.replace(/-href$/, "");
9961
+ const slot = document.createElement("span");
9962
+ slot.setAttribute("data-ohw-key", iconKey);
9963
+ slot.setAttribute("data-ohw-editable", "icon");
9964
+ slot.style.display = "inline-flex";
9965
+ item.prepend(slot);
9966
+ return iconKey;
9967
+ }
9968
+
9455
9969
  // src/lib/footer-items.ts
9456
9970
  var FOOTER_ORDER_KEY = "__ohw_footer_order";
9457
9971
  var MAX_FOOTER_COLUMNS = 18;
@@ -10328,6 +10842,257 @@ function addFooterColumnWithPersist({
10328
10842
  return result;
10329
10843
  }
10330
10844
 
10845
+ // src/ui/FloatingPanel.tsx
10846
+ import {
10847
+ useCallback as useCallback5,
10848
+ useEffect as useEffect9,
10849
+ useLayoutEffect as useLayoutEffect3,
10850
+ useRef as useRef7,
10851
+ useState as useState8
10852
+ } from "react";
10853
+ import { X as X5 } from "lucide-react";
10854
+ import { jsx as jsx26, jsxs as jsxs16 } from "react/jsx-runtime";
10855
+ var PANEL_WIDTH = 256;
10856
+ var EDGE_MARGIN = 16;
10857
+ function getVisibleClip(parentScroll) {
10858
+ const left = 0;
10859
+ const right = window.innerWidth;
10860
+ if (!parentScroll) {
10861
+ return { top: 0, bottom: window.innerHeight, left, right };
10862
+ }
10863
+ const { iframeOffsetTop, headerH: visibleCanvasTop, canvasH } = parentScroll;
10864
+ const top = Math.max(0, visibleCanvasTop - iframeOffsetTop);
10865
+ const bottom = Math.min(window.innerHeight, visibleCanvasTop + canvasH - iframeOffsetTop);
10866
+ return { top, bottom: Math.max(top, bottom), left, right };
10867
+ }
10868
+ function defaultFloatingPanelPosition(parentScroll, panelHeight = 280) {
10869
+ const clip = getVisibleClip(parentScroll);
10870
+ return {
10871
+ x: Math.max(EDGE_MARGIN, clip.right - PANEL_WIDTH - EDGE_MARGIN),
10872
+ y: Math.min(
10873
+ Math.max(clip.top + EDGE_MARGIN, EDGE_MARGIN),
10874
+ Math.max(clip.top + EDGE_MARGIN, clip.bottom - panelHeight - EDGE_MARGIN)
10875
+ )
10876
+ };
10877
+ }
10878
+ function clampPosition(pos, parentScroll, panelW, panelH) {
10879
+ const clip = getVisibleClip(parentScroll);
10880
+ const maxX = Math.max(clip.left + EDGE_MARGIN, clip.right - panelW - EDGE_MARGIN);
10881
+ const maxY = Math.max(clip.top + EDGE_MARGIN, clip.bottom - panelH - EDGE_MARGIN);
10882
+ return {
10883
+ x: Math.min(Math.max(pos.x, clip.left + EDGE_MARGIN), maxX),
10884
+ y: Math.min(Math.max(pos.y, clip.top + EDGE_MARGIN), maxY)
10885
+ };
10886
+ }
10887
+ function FloatingPanel({
10888
+ open,
10889
+ title,
10890
+ context,
10891
+ icon,
10892
+ onClose,
10893
+ children,
10894
+ position,
10895
+ onPositionChange,
10896
+ parentScroll = null,
10897
+ className,
10898
+ bodyClassName
10899
+ }) {
10900
+ const panelRef = useRef7(null);
10901
+ const [measured, setMeasured] = useState8({ w: PANEL_WIDTH, h: 280 });
10902
+ const dragRef = useRef7(null);
10903
+ const resolved = position ?? defaultFloatingPanelPosition(parentScroll, measured.h);
10904
+ const clamped = clampPosition(resolved, parentScroll, measured.w, measured.h);
10905
+ useLayoutEffect3(() => {
10906
+ if (!open || !panelRef.current) return;
10907
+ const el = panelRef.current;
10908
+ const next = { w: el.offsetWidth || PANEL_WIDTH, h: el.offsetHeight || 280 };
10909
+ setMeasured((prev) => prev.w === next.w && prev.h === next.h ? prev : next);
10910
+ }, [open, children, title, context]);
10911
+ useEffect9(() => {
10912
+ if (!open || !position || !onPositionChange) return;
10913
+ const next = clampPosition(position, parentScroll, measured.w, measured.h);
10914
+ if (next.x !== position.x || next.y !== position.y) onPositionChange(next);
10915
+ }, [open, parentScroll, measured.w, measured.h, position, onPositionChange]);
10916
+ const onHeaderPointerDown = useCallback5(
10917
+ (e) => {
10918
+ if (e.button !== 0) return;
10919
+ if (e.target.closest("[data-ohw-floating-panel-close]")) return;
10920
+ e.preventDefault();
10921
+ e.stopPropagation();
10922
+ const el = e.currentTarget;
10923
+ el.setPointerCapture(e.pointerId);
10924
+ dragRef.current = {
10925
+ pointerId: e.pointerId,
10926
+ startX: e.clientX,
10927
+ startY: e.clientY,
10928
+ originX: clamped.x,
10929
+ originY: clamped.y
10930
+ };
10931
+ },
10932
+ [clamped.x, clamped.y]
10933
+ );
10934
+ const onHeaderPointerMove = useCallback5(
10935
+ (e) => {
10936
+ const drag = dragRef.current;
10937
+ if (!drag || drag.pointerId !== e.pointerId) return;
10938
+ e.preventDefault();
10939
+ const next = clampPosition(
10940
+ {
10941
+ x: drag.originX + (e.clientX - drag.startX),
10942
+ y: drag.originY + (e.clientY - drag.startY)
10943
+ },
10944
+ parentScroll,
10945
+ measured.w,
10946
+ measured.h
10947
+ );
10948
+ onPositionChange?.(next);
10949
+ },
10950
+ [measured.h, measured.w, onPositionChange, parentScroll]
10951
+ );
10952
+ const endDrag = useCallback5((e) => {
10953
+ const drag = dragRef.current;
10954
+ if (!drag || drag.pointerId !== e.pointerId) return;
10955
+ dragRef.current = null;
10956
+ try {
10957
+ e.currentTarget.releasePointerCapture(e.pointerId);
10958
+ } catch {
10959
+ }
10960
+ }, []);
10961
+ if (!open) return null;
10962
+ return /* @__PURE__ */ jsxs16(
10963
+ "div",
10964
+ {
10965
+ ref: panelRef,
10966
+ "data-ohw-floating-panel": "",
10967
+ role: "dialog",
10968
+ "aria-label": title,
10969
+ className: cn(
10970
+ // Above MediaOverlay / item chrome (2147483646); link-modal content shares this tier.
10971
+ "fixed z-[2147483647] flex w-64 flex-col overflow-hidden rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
10972
+ className
10973
+ ),
10974
+ style: { left: clamped.x, top: clamped.y },
10975
+ onMouseDown: (e) => e.stopPropagation(),
10976
+ onPointerDown: (e) => e.stopPropagation(),
10977
+ onClick: (e) => e.stopPropagation(),
10978
+ children: [
10979
+ /* @__PURE__ */ jsxs16(
10980
+ "div",
10981
+ {
10982
+ "data-ohw-floating-panel-header": "",
10983
+ className: "relative flex cursor-grab items-start gap-2 border-b border-border py-5 pl-5 pr-11 active:cursor-grabbing",
10984
+ onPointerDown: onHeaderPointerDown,
10985
+ onPointerMove: onHeaderPointerMove,
10986
+ onPointerUp: endDrag,
10987
+ onPointerCancel: endDrag,
10988
+ children: [
10989
+ /* @__PURE__ */ jsxs16("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children: [
10990
+ /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-2", children: [
10991
+ icon ? /* @__PURE__ */ jsx26("span", { className: "shrink-0 text-foreground", children: icon }) : null,
10992
+ /* @__PURE__ */ jsx26("p", { className: "min-w-0 flex-1 text-lg font-semibold leading-7 text-foreground", children: title })
10993
+ ] }),
10994
+ context ? /* @__PURE__ */ jsx26("p", { className: "w-full text-sm leading-5 text-muted-foreground", children: context }) : null
10995
+ ] }),
10996
+ /* @__PURE__ */ jsx26(
10997
+ "button",
10998
+ {
10999
+ type: "button",
11000
+ "data-ohw-floating-panel-close": "",
11001
+ "aria-label": "Close",
11002
+ className: "absolute right-2.5 top-2.5 rounded-sm p-1.5 text-foreground hover:bg-muted/50",
11003
+ onClick: (e) => {
11004
+ e.stopPropagation();
11005
+ onClose();
11006
+ },
11007
+ onPointerDown: (e) => e.stopPropagation(),
11008
+ children: /* @__PURE__ */ jsx26(X5, { size: 16, "aria-hidden": true })
11009
+ }
11010
+ )
11011
+ ]
11012
+ }
11013
+ ),
11014
+ /* @__PURE__ */ jsx26(
11015
+ "div",
11016
+ {
11017
+ "data-ohw-floating-panel-body": "",
11018
+ className: cn("flex w-full flex-col gap-4 p-5", bodyClassName),
11019
+ children
11020
+ }
11021
+ )
11022
+ ]
11023
+ }
11024
+ );
11025
+ }
11026
+
11027
+ // src/ui/socials-display-panel.tsx
11028
+ import { jsx as jsx27, jsxs as jsxs17 } from "react/jsx-runtime";
11029
+ function DisplaySwitch({
11030
+ label,
11031
+ checked,
11032
+ disabled,
11033
+ onChange
11034
+ }) {
11035
+ return /* @__PURE__ */ jsxs17("div", { className: "flex w-full items-center gap-2", children: [
11036
+ /* @__PURE__ */ jsx27(
11037
+ "span",
11038
+ {
11039
+ className: cn(
11040
+ "min-w-0 flex-1 text-sm font-medium leading-5",
11041
+ disabled ? "text-muted-foreground" : "text-foreground"
11042
+ ),
11043
+ children: label
11044
+ }
11045
+ ),
11046
+ /* @__PURE__ */ jsx27(
11047
+ "button",
11048
+ {
11049
+ type: "button",
11050
+ role: "switch",
11051
+ "aria-checked": checked,
11052
+ "aria-label": label,
11053
+ disabled,
11054
+ onClick: () => onChange(!checked),
11055
+ className: cn(
11056
+ "relative h-5 w-9 shrink-0 rounded-full transition-colors",
11057
+ checked ? "bg-primary" : "bg-primary-50",
11058
+ disabled ? "cursor-default opacity-50" : "cursor-pointer"
11059
+ ),
11060
+ children: /* @__PURE__ */ jsx27(
11061
+ "span",
11062
+ {
11063
+ className: cn(
11064
+ "absolute top-0.5 h-4 w-4 rounded-full bg-white transition-all",
11065
+ checked ? "left-[1.125rem]" : "left-0.5"
11066
+ )
11067
+ }
11068
+ )
11069
+ }
11070
+ )
11071
+ ] });
11072
+ }
11073
+ function SocialsDisplayPanel({ display, onChange, className }) {
11074
+ return /* @__PURE__ */ jsxs17("div", { className: cn("flex w-full flex-col gap-3", className), children: [
11075
+ /* @__PURE__ */ jsx27(
11076
+ DisplaySwitch,
11077
+ {
11078
+ label: "Text",
11079
+ checked: display.text,
11080
+ disabled: display.text && !display.icon,
11081
+ onChange: (text) => onChange({ ...display, text })
11082
+ }
11083
+ ),
11084
+ /* @__PURE__ */ jsx27(
11085
+ DisplaySwitch,
11086
+ {
11087
+ label: "Icon",
11088
+ checked: display.icon,
11089
+ disabled: display.icon && !display.text,
11090
+ onChange: (icon) => onChange({ ...display, icon })
11091
+ }
11092
+ )
11093
+ ] });
11094
+ }
11095
+
10331
11096
  // src/lib/item-drag-interaction.ts
10332
11097
  function disableNativeHrefDrag(el) {
10333
11098
  if (el.draggable) el.draggable = false;
@@ -10526,7 +11291,7 @@ function hitTestNavDropSlot(clientX, clientY, draggedHrefKey) {
10526
11291
  }
10527
11292
 
10528
11293
  // src/useNavItemDrag.ts
10529
- import { useCallback as useCallback5, useEffect as useEffect9, useRef as useRef7, useState as useState8 } from "react";
11294
+ import { useCallback as useCallback6, useEffect as useEffect10, useRef as useRef8, useState as useState9 } from "react";
10530
11295
  function useNavItemDrag({
10531
11296
  isEditMode,
10532
11297
  editContentRef,
@@ -10550,11 +11315,11 @@ function useNavItemDrag({
10550
11315
  getNavigationItemAnchor: getNavigationItemAnchor2,
10551
11316
  isDragHandleDisabled: isDragHandleDisabled2
10552
11317
  }) {
10553
- const navDragRef = useRef7(null);
10554
- const [navDropSlots, setNavDropSlots] = useState8([]);
10555
- const [activeNavDropIndex, setActiveNavDropIndex] = useState8(null);
10556
- const navPointerDragRef = useRef7(null);
10557
- const clearNavDragVisuals = useCallback5(() => {
11318
+ const navDragRef = useRef8(null);
11319
+ const [navDropSlots, setNavDropSlots] = useState9([]);
11320
+ const [activeNavDropIndex, setActiveNavDropIndex] = useState9(null);
11321
+ const navPointerDragRef = useRef8(null);
11322
+ const clearNavDragVisuals = useCallback6(() => {
10558
11323
  const session = navDragRef.current;
10559
11324
  const keepOpenEl = session?.draggedEl?.closest("[data-ohw-nav-children]") != null ? session.draggedEl : null;
10560
11325
  navDragRef.current = null;
@@ -10571,7 +11336,7 @@ function useNavItemDrag({
10571
11336
  document.documentElement.removeAttribute("data-ohw-nav-dragging-root");
10572
11337
  unlockItemDragInteraction();
10573
11338
  }, [setDraggedItemRect, setIsItemDragging, setSiblingHintRects]);
10574
- const refreshNavDragVisuals = useCallback5(
11339
+ const refreshNavDragVisuals = useCallback6(
10575
11340
  (session, activeSlot, clientX, clientY) => {
10576
11341
  setDraggedItemRect(session.draggedEl.getBoundingClientRect());
10577
11342
  if (typeof clientX === "number" && typeof clientY === "number") {
@@ -10589,13 +11354,13 @@ function useNavItemDrag({
10589
11354
  },
10590
11355
  [setDraggedItemRect, setSiblingHintRects]
10591
11356
  );
10592
- const refreshNavDragVisualsRef = useRef7(refreshNavDragVisuals);
11357
+ const refreshNavDragVisualsRef = useRef8(refreshNavDragVisuals);
10593
11358
  refreshNavDragVisualsRef.current = refreshNavDragVisuals;
10594
- const commitNavDragRef = useRef7(() => {
11359
+ const commitNavDragRef = useRef8(() => {
10595
11360
  });
10596
- const beginNavDragRef = useRef7(() => {
11361
+ const beginNavDragRef = useRef8(() => {
10597
11362
  });
10598
- const beginNavDrag = useCallback5(
11363
+ const beginNavDrag = useCallback6(
10599
11364
  (session) => {
10600
11365
  const rect = session.draggedEl.getBoundingClientRect();
10601
11366
  session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
@@ -10629,7 +11394,7 @@ function useNavItemDrag({
10629
11394
  ]
10630
11395
  );
10631
11396
  beginNavDragRef.current = beginNavDrag;
10632
- const commitNavDrag = useCallback5(
11397
+ const commitNavDrag = useCallback6(
10633
11398
  (clientX, clientY) => {
10634
11399
  const session = navDragRef.current;
10635
11400
  if (!session) {
@@ -10690,7 +11455,7 @@ function useNavItemDrag({
10690
11455
  [clearNavDragVisuals, deselectRef, editContentRef, postToParentRef, selectRef]
10691
11456
  );
10692
11457
  commitNavDragRef.current = commitNavDrag;
10693
- const startNavLinkDrag = useCallback5(
11458
+ const startNavLinkDrag = useCallback6(
10694
11459
  (anchor, clientX, clientY, wasSelected) => {
10695
11460
  if (footerDragRef.current) return false;
10696
11461
  const hrefKey = anchor.getAttribute("data-ohw-href-key");
@@ -10708,7 +11473,7 @@ function useNavItemDrag({
10708
11473
  },
10709
11474
  [beginNavDrag, footerDragRef, isDragHandleDisabled2, isCtaButton]
10710
11475
  );
10711
- const onNavDragOver = useCallback5(
11476
+ const onNavDragOver = useCallback6(
10712
11477
  (e) => {
10713
11478
  const session = navDragRef.current;
10714
11479
  if (!session) return false;
@@ -10720,7 +11485,7 @@ function useNavItemDrag({
10720
11485
  },
10721
11486
  []
10722
11487
  );
10723
- useEffect9(() => {
11488
+ useEffect10(() => {
10724
11489
  if (!isEditMode) return;
10725
11490
  const THRESHOLD = 10;
10726
11491
  const resolveWasSelected = (el) => {
@@ -10845,7 +11610,7 @@ function useNavItemDrag({
10845
11610
  setLinkPopover,
10846
11611
  suppressNextClickRef
10847
11612
  ]);
10848
- const armNavPressFromChrome = useCallback5(
11613
+ const armNavPressFromChrome = useCallback6(
10849
11614
  (selected, clientX, clientY, pointerId) => {
10850
11615
  const hrefKey = selected.getAttribute("data-ohw-href-key");
10851
11616
  if (!hrefKey || !isNavbarHrefKey(hrefKey)) return false;
@@ -10877,7 +11642,7 @@ function useNavItemDrag({
10877
11642
 
10878
11643
  // src/ui/footer-container-chrome.tsx
10879
11644
  import { Plus as Plus2 } from "lucide-react";
10880
- import { jsx as jsx26, jsxs as jsxs16 } from "react/jsx-runtime";
11645
+ import { jsx as jsx28, jsxs as jsxs18 } from "react/jsx-runtime";
10881
11646
  function FooterContainerChrome({
10882
11647
  rect,
10883
11648
  onAdd,
@@ -10885,7 +11650,7 @@ function FooterContainerChrome({
10885
11650
  }) {
10886
11651
  const chromeGap = 6;
10887
11652
  const buttonMargin = 7;
10888
- return /* @__PURE__ */ jsx26(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsx26(
11653
+ return /* @__PURE__ */ jsx28(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsx28(
10889
11654
  "div",
10890
11655
  {
10891
11656
  "data-ohw-footer-container-chrome": "",
@@ -10897,8 +11662,8 @@ function FooterContainerChrome({
10897
11662
  width: rect.width + chromeGap * 2,
10898
11663
  height: rect.height + chromeGap * 2
10899
11664
  },
10900
- children: /* @__PURE__ */ jsxs16(Tooltip, { children: [
10901
- /* @__PURE__ */ jsx26(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx26(
11665
+ children: /* @__PURE__ */ jsxs18(Tooltip, { children: [
11666
+ /* @__PURE__ */ jsx28(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx28(
10902
11667
  "button",
10903
11668
  {
10904
11669
  type: "button",
@@ -10917,17 +11682,17 @@ function FooterContainerChrome({
10917
11682
  if (addDisabled) return;
10918
11683
  onAdd();
10919
11684
  },
10920
- children: /* @__PURE__ */ jsx26(Plus2, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
11685
+ children: /* @__PURE__ */ jsx28(Plus2, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
10921
11686
  }
10922
11687
  ) }),
10923
- /* @__PURE__ */ jsx26(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
11688
+ /* @__PURE__ */ jsx28(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
10924
11689
  ] })
10925
11690
  }
10926
11691
  ) });
10927
11692
  }
10928
11693
 
10929
11694
  // src/lib/carousel.ts
10930
- import { useEffect as useEffect10, useState as useState9 } from "react";
11695
+ import { useEffect as useEffect11, useState as useState10 } from "react";
10931
11696
  var CAROUSEL_ATTR = "data-ohw-carousel";
10932
11697
  var CAROUSEL_VALUE_ATTR = "data-ohw-carousel-value";
10933
11698
  var CAROUSEL_SLIDE_ATTR = "data-ohw-carousel-slide";
@@ -10989,8 +11754,8 @@ function applyCarouselNode(key, val) {
10989
11754
  return true;
10990
11755
  }
10991
11756
  function useOhwCarousel(key, initial) {
10992
- const [images, setImages] = useState9(initial);
10993
- useEffect10(() => {
11757
+ const [images, setImages] = useState10(initial);
11758
+ useEffect11(() => {
10994
11759
  const el = document.querySelector(
10995
11760
  `[${CAROUSEL_ATTR}][data-ohw-key="${CSS.escape(key)}"]`
10996
11761
  );
@@ -11205,7 +11970,7 @@ function isNavbarLinksContainer(el) {
11205
11970
  function isNavigationItem(el) {
11206
11971
  const anchor = el.matches("[data-ohw-href-key]") ? el : el.closest("[data-ohw-href-key]");
11207
11972
  if (!anchor) return false;
11208
- return Boolean(anchor.querySelector('[data-ohw-editable="text"]'));
11973
+ return Boolean(anchor.querySelector('[data-ohw-editable="text"]')) || Boolean(getSocialItem(anchor));
11209
11974
  }
11210
11975
  function findFooterItemGroup(item) {
11211
11976
  const explicit = item.closest("[data-ohw-footer-col], [data-ohw-footer-column]");
@@ -11226,8 +11991,9 @@ function isInferredFooterGroup(el) {
11226
11991
  const footer = el.closest("footer");
11227
11992
  if (!footer || el === footer) return false;
11228
11993
  if (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column")) return true;
11994
+ if (isSocialsRow(el)) return false;
11229
11995
  const count = Array.from(el.querySelectorAll("[data-ohw-href-key]")).filter(
11230
- isNavigationItem
11996
+ (item) => isNavigationItem(item) && !getSocialItem(item)
11231
11997
  ).length;
11232
11998
  return count >= 2;
11233
11999
  }
@@ -11271,7 +12037,8 @@ function deleteSelectedNavFooterItem(deps) {
11271
12037
  if (key.endsWith("-href")) applyLinkByKey2(key, text);
11272
12038
  else {
11273
12039
  document.querySelectorAll(`[data-ohw-key="${CSS.escape(key)}"]`).forEach((el) => {
11274
- el.textContent = text;
12040
+ if (el.getAttribute("data-ohw-editable") === "icon") applyIconMarkup(el, text);
12041
+ else el.textContent = text;
11275
12042
  });
11276
12043
  }
11277
12044
  }
@@ -11333,6 +12100,21 @@ function deleteSelectedNavFooterItem(deps) {
11333
12100
  });
11334
12101
  return true;
11335
12102
  }
12103
+ const social = getSocialItem(selected);
12104
+ if (social) {
12105
+ const result = removeSocialItem(social, getEditContent());
12106
+ if (!result) return false;
12107
+ finishDelete({
12108
+ toastTitle: "Social deleted",
12109
+ removedKeys: result.removedKeys,
12110
+ previousContent: result.previousContent,
12111
+ orderKey: SOCIALS_ORDER_KEY,
12112
+ orderJson: JSON.stringify(result.order),
12113
+ previousOrderJson: JSON.stringify(result.previousOrder),
12114
+ undoDom: result.undo
12115
+ });
12116
+ return true;
12117
+ }
11336
12118
  if (isFooterHrefKey(hrefKey)) {
11337
12119
  const result = deleteFooterItem(selected);
11338
12120
  if (!result) return false;
@@ -11352,13 +12134,13 @@ function deleteSelectedNavFooterItem(deps) {
11352
12134
 
11353
12135
  // src/ui/navbar-container-chrome.tsx
11354
12136
  import { Plus as Plus3 } from "lucide-react";
11355
- import { jsx as jsx27 } from "react/jsx-runtime";
12137
+ import { jsx as jsx29 } from "react/jsx-runtime";
11356
12138
  function NavbarContainerChrome({
11357
12139
  rect,
11358
12140
  onAdd
11359
12141
  }) {
11360
12142
  const chromeGap = 6;
11361
- return /* @__PURE__ */ jsx27(
12143
+ return /* @__PURE__ */ jsx29(
11362
12144
  "div",
11363
12145
  {
11364
12146
  "data-ohw-navbar-container-chrome": "",
@@ -11370,7 +12152,7 @@ function NavbarContainerChrome({
11370
12152
  width: rect.width + chromeGap * 2,
11371
12153
  height: rect.height + chromeGap * 2
11372
12154
  },
11373
- children: /* @__PURE__ */ jsx27(
12155
+ children: /* @__PURE__ */ jsx29(
11374
12156
  "button",
11375
12157
  {
11376
12158
  type: "button",
@@ -11387,7 +12169,7 @@ function NavbarContainerChrome({
11387
12169
  e.stopPropagation();
11388
12170
  onAdd();
11389
12171
  },
11390
- children: /* @__PURE__ */ jsx27(Plus3, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
12172
+ children: /* @__PURE__ */ jsx29(Plus3, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
11391
12173
  }
11392
12174
  )
11393
12175
  }
@@ -11396,7 +12178,7 @@ function NavbarContainerChrome({
11396
12178
 
11397
12179
  // src/ui/drop-indicator.tsx
11398
12180
  import * as React10 from "react";
11399
- import { jsx as jsx28 } from "react/jsx-runtime";
12181
+ import { jsx as jsx30 } from "react/jsx-runtime";
11400
12182
  var dropIndicatorVariants = cva(
11401
12183
  "ov-gap-line pointer-events-none shrink-0 transition-opacity duration-150",
11402
12184
  {
@@ -11420,7 +12202,7 @@ var dropIndicatorVariants = cva(
11420
12202
  );
11421
12203
  var DropIndicator = React10.forwardRef(
11422
12204
  ({ className, direction, state, ...props }, ref) => {
11423
- return /* @__PURE__ */ jsx28(
12205
+ return /* @__PURE__ */ jsx30(
11424
12206
  "div",
11425
12207
  {
11426
12208
  ref,
@@ -11437,7 +12219,7 @@ var DropIndicator = React10.forwardRef(
11437
12219
  DropIndicator.displayName = "DropIndicator";
11438
12220
 
11439
12221
  // src/ui/badge.tsx
11440
- import { jsx as jsx29 } from "react/jsx-runtime";
12222
+ import { jsx as jsx31 } from "react/jsx-runtime";
11441
12223
  var badgeVariants = cva(
11442
12224
  "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
11443
12225
  {
@@ -11455,12 +12237,12 @@ var badgeVariants = cva(
11455
12237
  }
11456
12238
  );
11457
12239
  function Badge({ className, variant, ...props }) {
11458
- return /* @__PURE__ */ jsx29("div", { className: cn(badgeVariants({ variant }), className), ...props });
12240
+ return /* @__PURE__ */ jsx31("div", { className: cn(badgeVariants({ variant }), className), ...props });
11459
12241
  }
11460
12242
 
11461
12243
  // src/OhhwellsBridge.tsx
11462
12244
  import { Link as Link2 } from "lucide-react";
11463
- import { Fragment as Fragment8, jsx as jsx30, jsxs as jsxs17 } from "react/jsx-runtime";
12245
+ import { Fragment as Fragment8, jsx as jsx32, jsxs as jsxs19 } from "react/jsx-runtime";
11464
12246
  var PRIMARY3 = "#0885FE";
11465
12247
  var IMAGE_FADE_MS = 300;
11466
12248
  function runOpacityFade(el, onDone) {
@@ -11639,7 +12421,7 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
11639
12421
  const root = createRoot2(container);
11640
12422
  flushSync2(() => {
11641
12423
  root.render(
11642
- /* @__PURE__ */ jsx30(
12424
+ /* @__PURE__ */ jsx32(
11643
12425
  SchedulingWidget,
11644
12426
  {
11645
12427
  notifyOnConnect,
@@ -11687,6 +12469,17 @@ function applyLinkHref(el, val) {
11687
12469
  const anchor = el instanceof HTMLAnchorElement ? el : el.querySelector("a");
11688
12470
  if (anchor) anchor.setAttribute("href", val);
11689
12471
  }
12472
+ function currentIconRef(el) {
12473
+ const uploaded = el instanceof HTMLImageElement ? el : el.querySelector("img");
12474
+ if (uploaded?.getAttribute("src")) {
12475
+ return uploaded.getAttribute("src") ?? "";
12476
+ }
12477
+ const svg = el instanceof SVGElement ? el : el.querySelector("svg");
12478
+ const named = Array.from(svg?.classList ?? []).find(
12479
+ (c) => c.startsWith("lucide-") && c !== "lucide-icon"
12480
+ );
12481
+ return named ? `lucide:${named.slice("lucide-".length)}` : "";
12482
+ }
11690
12483
  function getEditMeasureEl(editable) {
11691
12484
  return editable.closest("[data-ohw-href-key]") ?? editable;
11692
12485
  }
@@ -11731,8 +12524,11 @@ function isMediaEditable(el) {
11731
12524
  const t = el.dataset.ohwEditable;
11732
12525
  return t === "image" || t === "bg-image" || t === "video";
11733
12526
  }
12527
+ function isIconEditable(el) {
12528
+ return el.dataset.ohwEditable === "icon";
12529
+ }
11734
12530
  var MEDIA_SELECTOR = '[data-ohw-editable="image"], [data-ohw-editable="bg-image"], [data-ohw-editable="video"]';
11735
- var NON_MEDIA_SELECTOR = '[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"])';
12531
+ var NON_MEDIA_SELECTOR = '[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"]):not([data-ohw-editable="icon"])';
11736
12532
  function getVideoEl2(el) {
11737
12533
  return el instanceof HTMLVideoElement ? el : el.querySelector("video");
11738
12534
  }
@@ -11850,13 +12646,29 @@ function isNavItemPointerTarget(el) {
11850
12646
  function getNavigationItemAnchor(el) {
11851
12647
  const anchor = el.matches("[data-ohw-href-key]") ? el : el.closest("[data-ohw-href-key]");
11852
12648
  if (!anchor) return null;
11853
- if (!anchor.querySelector('[data-ohw-editable="text"]')) return null;
12649
+ if (!anchor.querySelector('[data-ohw-editable="text"]') && !getSocialItem(anchor)) return null;
11854
12650
  if (!isNavItemPointerTarget(anchor)) return null;
11855
12651
  return anchor;
11856
12652
  }
11857
12653
  function isNavigationItem2(el) {
11858
12654
  return getNavigationItemAnchor(el) !== null;
11859
12655
  }
12656
+ function requestSocialDialog(anchor, post, content) {
12657
+ const item = getSocialItem(anchor);
12658
+ if (!item) return false;
12659
+ const iconKey = item.querySelector('[data-ohw-editable="icon"]')?.dataset.ohwKey ?? "";
12660
+ post({
12661
+ type: "ow:social-pick",
12662
+ hrefKey: item.getAttribute("data-ohw-href-key") ?? "",
12663
+ iconKey,
12664
+ url: getLinkHref4(item),
12665
+ iconStyle: detectIconStyle(item),
12666
+ // What was chosen last time. Guessing from the address instead reads as "Website" for anything
12667
+ // unrecognised, and for an item with no address at all — so a deliberate choice looked lost.
12668
+ platformId: content[socialPlatformKey(iconKey)] ?? ""
12669
+ });
12670
+ return true;
12671
+ }
11860
12672
  function listNavigationItems() {
11861
12673
  return Array.from(
11862
12674
  document.querySelectorAll("nav [data-ohw-href-key], footer [data-ohw-href-key]")
@@ -11891,7 +12703,7 @@ function getNavigationRoot(el) {
11891
12703
  return el.closest("nav, footer, aside");
11892
12704
  }
11893
12705
  function countFooterNavItems(el) {
11894
- return Array.from(el.querySelectorAll("[data-ohw-href-key]")).filter(isNavigationItem2).length;
12706
+ return Array.from(el.querySelectorAll("[data-ohw-href-key]")).filter((item) => isNavigationItem2(item) && !getSocialItem(item)).length;
11895
12707
  }
11896
12708
  function findFooterItemGroup2(item) {
11897
12709
  const explicit = item.closest("[data-ohw-footer-col], [data-ohw-footer-column]");
@@ -11912,10 +12724,11 @@ function isInferredFooterGroup2(el) {
11912
12724
  const footer = el.closest("footer");
11913
12725
  if (!footer || el === footer) return false;
11914
12726
  if (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column")) return true;
12727
+ if (isSocialsRow(el)) return false;
11915
12728
  return countFooterNavItems(el) >= 2;
11916
12729
  }
11917
12730
  function isNavigationContainer(el) {
11918
- return el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el) || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isNavigationRoot(el) || isInferredFooterGroup2(el);
12731
+ return el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el) || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isNavigationRoot(el) || isSocialsRow(el) || isInferredFooterGroup2(el);
11919
12732
  }
11920
12733
  function isNavbarLinksContainer2(el) {
11921
12734
  return el.hasAttribute("data-ohw-nav-container");
@@ -11998,6 +12811,8 @@ function resolveNavContainerSelectionTarget(target, clientX, clientY) {
11998
12811
  return null;
11999
12812
  }
12000
12813
  function getNavigationSelectionParent(el) {
12814
+ const socialsRow = findSocialsRow(el);
12815
+ if (socialsRow) return socialsRow;
12001
12816
  if (isNavigationItem2(el)) {
12002
12817
  const childrenRoot = el.closest("[data-ohw-nav-children]");
12003
12818
  if (childrenRoot) {
@@ -12023,6 +12838,10 @@ function getNavigationSelectionParent(el) {
12023
12838
  }
12024
12839
  function collectNavigationItemSiblingHintRects(selected) {
12025
12840
  if (!isNavigationItem2(selected)) return [];
12841
+ const socialsRow = findSocialsRow(selected);
12842
+ if (socialsRow) {
12843
+ return listSocialItems(socialsRow).filter((item) => item !== selected).map((item) => item.getBoundingClientRect());
12844
+ }
12026
12845
  const footerColumn = getFooterColumn(selected);
12027
12846
  if (footerColumn) {
12028
12847
  return listFooterLinksInColumn(footerColumn).filter((link) => link !== selected).map((link) => link.getBoundingClientRect());
@@ -12255,7 +13074,7 @@ function EditGlowChrome({
12255
13074
  hideHandle = false
12256
13075
  }) {
12257
13076
  const GAP = SELECTION_CHROME_GAP2;
12258
- return /* @__PURE__ */ jsxs17(
13077
+ return /* @__PURE__ */ jsxs19(
12259
13078
  "div",
12260
13079
  {
12261
13080
  ref: elRef,
@@ -12270,7 +13089,7 @@ function EditGlowChrome({
12270
13089
  zIndex: 2147483646
12271
13090
  },
12272
13091
  children: [
12273
- /* @__PURE__ */ jsx30(
13092
+ /* @__PURE__ */ jsx32(
12274
13093
  "div",
12275
13094
  {
12276
13095
  style: {
@@ -12283,7 +13102,7 @@ function EditGlowChrome({
12283
13102
  }
12284
13103
  }
12285
13104
  ),
12286
- reorderHrefKey && !hideHandle && /* @__PURE__ */ jsx30(
13105
+ reorderHrefKey && !hideHandle && /* @__PURE__ */ jsx32(
12287
13106
  "div",
12288
13107
  {
12289
13108
  "data-ohw-drag-handle-container": "",
@@ -12295,7 +13114,7 @@ function EditGlowChrome({
12295
13114
  transform: "translate(calc(-100% - 7px), -50%)",
12296
13115
  pointerEvents: dragDisabled ? "none" : "auto"
12297
13116
  },
12298
- children: /* @__PURE__ */ jsx30(
13117
+ children: /* @__PURE__ */ jsx32(
12299
13118
  DragHandle,
12300
13119
  {
12301
13120
  "aria-label": `Reorder ${reorderHrefKey}`,
@@ -12505,7 +13324,7 @@ function FloatingToolbar({
12505
13324
  return () => ro.disconnect();
12506
13325
  }, [showEditLink, activeCommands]);
12507
13326
  const { top, left, transform } = calcToolbarPos(rect, parentScroll, measuredW);
12508
- return /* @__PURE__ */ jsx30(
13327
+ return /* @__PURE__ */ jsx32(
12509
13328
  "div",
12510
13329
  {
12511
13330
  ref: setRefs,
@@ -12517,12 +13336,12 @@ function FloatingToolbar({
12517
13336
  zIndex: 2147483647,
12518
13337
  pointerEvents: "auto"
12519
13338
  },
12520
- children: /* @__PURE__ */ jsxs17(CustomToolbar, { children: [
12521
- TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs17(React11.Fragment, { children: [
12522
- gi > 0 && /* @__PURE__ */ jsx30(CustomToolbarDivider, {}),
13339
+ children: /* @__PURE__ */ jsxs19(CustomToolbar, { children: [
13340
+ TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ jsxs19(React11.Fragment, { children: [
13341
+ gi > 0 && /* @__PURE__ */ jsx32(CustomToolbarDivider, {}),
12523
13342
  btns.map((btn) => {
12524
13343
  const isActive = activeCommands.has(btn.cmd);
12525
- return /* @__PURE__ */ jsx30(
13344
+ return /* @__PURE__ */ jsx32(
12526
13345
  CustomToolbarButton,
12527
13346
  {
12528
13347
  title: btn.title,
@@ -12531,7 +13350,7 @@ function FloatingToolbar({
12531
13350
  e.preventDefault();
12532
13351
  onCommand(btn.cmd);
12533
13352
  },
12534
- children: /* @__PURE__ */ jsx30(
13353
+ children: /* @__PURE__ */ jsx32(
12535
13354
  "svg",
12536
13355
  {
12537
13356
  width: "16",
@@ -12552,7 +13371,7 @@ function FloatingToolbar({
12552
13371
  );
12553
13372
  })
12554
13373
  ] }, gi)),
12555
- showEditLink ? /* @__PURE__ */ jsx30(
13374
+ showEditLink ? /* @__PURE__ */ jsx32(
12556
13375
  CustomToolbarButton,
12557
13376
  {
12558
13377
  type: "button",
@@ -12566,7 +13385,7 @@ function FloatingToolbar({
12566
13385
  e.preventDefault();
12567
13386
  e.stopPropagation();
12568
13387
  },
12569
- children: /* @__PURE__ */ jsx30(Link2, { className: "size-4 shrink-0", "aria-hidden": true })
13388
+ children: /* @__PURE__ */ jsx32(Link2, { className: "size-4 shrink-0", "aria-hidden": true })
12570
13389
  }
12571
13390
  ) : null
12572
13391
  ] })
@@ -12583,7 +13402,7 @@ function StateToggle({
12583
13402
  states,
12584
13403
  onStateChange
12585
13404
  }) {
12586
- return /* @__PURE__ */ jsx30(
13405
+ return /* @__PURE__ */ jsx32(
12587
13406
  ToggleGroup,
12588
13407
  {
12589
13408
  "data-ohw-state-toggle": "",
@@ -12597,7 +13416,7 @@ function StateToggle({
12597
13416
  left: rect.right - 8,
12598
13417
  transform: "translateX(-100%)"
12599
13418
  },
12600
- children: states.map((state) => /* @__PURE__ */ jsx30(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
13419
+ children: states.map((state) => /* @__PURE__ */ jsx32(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
12601
13420
  }
12602
13421
  );
12603
13422
  }
@@ -12624,8 +13443,8 @@ function OhhwellsBridge() {
12624
13443
  const router = useRouter3();
12625
13444
  const searchParams = useSearchParams();
12626
13445
  const isEditMode = isEditSessionActive();
12627
- const [bridgeRoot, setBridgeRoot] = useState10(null);
12628
- useEffect11(() => {
13446
+ const [bridgeRoot, setBridgeRoot] = useState11(null);
13447
+ useEffect12(() => {
12629
13448
  const figtreeFontId = "ohw-figtree-font";
12630
13449
  if (!document.getElementById(figtreeFontId)) {
12631
13450
  const preconnect1 = Object.assign(document.createElement("link"), { rel: "preconnect", href: "https://fonts.googleapis.com" });
@@ -12654,108 +13473,113 @@ function OhhwellsBridge() {
12654
13473
  const subdomain = resolveSubdomain(subdomainFromQuery);
12655
13474
  useLinkHrefGuardian(pathname, subdomain, isEditMode);
12656
13475
  useSavedLinkNavigation(isEditMode);
12657
- const postToParent2 = useCallback6((data) => {
13476
+ const postToParent2 = useCallback7((data) => {
12658
13477
  if (typeof window !== "undefined" && window.parent !== window) {
12659
13478
  window.parent.postMessage(data, "*");
12660
13479
  }
12661
13480
  }, []);
12662
- const [fetchState, setFetchState] = useState10("idle");
12663
- const autoSaveTimers = useRef8(/* @__PURE__ */ new Map());
12664
- const activeElRef = useRef8(null);
12665
- const pointerHeldRef = useRef8(false);
12666
- const selectedElRef = useRef8(null);
12667
- const selectedHrefKeyRef = useRef8(null);
12668
- const selectedFooterColAttrRef = useRef8(null);
12669
- const originalContentRef = useRef8(null);
12670
- const activeStateElRef = useRef8(null);
12671
- const parentScrollRef = useRef8(null);
12672
- const visibleViewportRef = useRef8(null);
12673
- const [dialogPortalContainer, setDialogPortalContainer] = useState10(null);
12674
- const attachVisibleViewport = useCallback6((node) => {
13481
+ const [fetchState, setFetchState] = useState11("idle");
13482
+ const autoSaveTimers = useRef9(/* @__PURE__ */ new Map());
13483
+ const activeElRef = useRef9(null);
13484
+ const pointerHeldRef = useRef9(false);
13485
+ const selectedElRef = useRef9(null);
13486
+ const selectedHrefKeyRef = useRef9(null);
13487
+ const selectedFooterColAttrRef = useRef9(null);
13488
+ const originalContentRef = useRef9(null);
13489
+ const activeStateElRef = useRef9(null);
13490
+ const parentScrollRef = useRef9(null);
13491
+ const visibleViewportRef = useRef9(null);
13492
+ const [dialogPortalContainer, setDialogPortalContainer] = useState11(null);
13493
+ const attachVisibleViewport = useCallback7((node) => {
12675
13494
  visibleViewportRef.current = node;
12676
13495
  setDialogPortalContainer(node);
12677
13496
  if (node) applyVisibleViewport(node, parentScrollRef.current);
12678
13497
  }, []);
12679
- const toolbarElRef = useRef8(null);
12680
- const glowElRef = useRef8(null);
12681
- const hoveredImageRef = useRef8(null);
12682
- const hoveredImageHasTextOverlapRef = useRef8(false);
12683
- const dragOverElRef = useRef8(null);
12684
- const [mediaHover, setMediaHover] = useState10(null);
12685
- const [carouselHover, setCarouselHover] = useState10(null);
12686
- const [uploadingRects, setUploadingRects] = useState10({});
12687
- const hoveredGapRef = useRef8(null);
12688
- const imageUnhoverTimerRef = useRef8(null);
12689
- const imageShowTimerRef = useRef8(null);
12690
- const editStylesRef = useRef8(null);
12691
- const activateRef = useRef8(() => {
13498
+ const toolbarElRef = useRef9(null);
13499
+ const glowElRef = useRef9(null);
13500
+ const hoveredImageRef = useRef9(null);
13501
+ const hoveredImageHasTextOverlapRef = useRef9(false);
13502
+ const dragOverElRef = useRef9(null);
13503
+ const [mediaHover, setMediaHover] = useState11(null);
13504
+ const [carouselHover, setCarouselHover] = useState11(null);
13505
+ const [uploadingRects, setUploadingRects] = useState11({});
13506
+ const hoveredGapRef = useRef9(null);
13507
+ const imageUnhoverTimerRef = useRef9(null);
13508
+ const imageShowTimerRef = useRef9(null);
13509
+ const editStylesRef = useRef9(null);
13510
+ const activateRef = useRef9(() => {
12692
13511
  });
12693
- const deactivateRef = useRef8(() => {
13512
+ const deactivateRef = useRef9(() => {
12694
13513
  });
12695
- const selectRef = useRef8(() => {
13514
+ const selectRef = useRef9(() => {
12696
13515
  });
12697
- const selectFrameRef = useRef8(() => {
13516
+ const selectFrameRef = useRef9(() => {
12698
13517
  });
12699
- const deselectRef = useRef8(() => {
13518
+ const deselectRef = useRef9(() => {
12700
13519
  });
12701
- const reselectNavigationItemRef = useRef8(() => {
13520
+ const reselectNavigationItemRef = useRef9(() => {
12702
13521
  });
12703
- const commitNavigationTextEditRef = useRef8(() => {
13522
+ const commitNavigationTextEditRef = useRef9(() => {
12704
13523
  });
12705
- const handleDeleteSelectedRef = useRef8(() => false);
12706
- const runPendingDeleteUndoRef = useRef8(() => false);
12707
- const isFooterFrameSelectionRef = useRef8(false);
12708
- const refreshActiveCommandsRef = useRef8(() => {
13524
+ const handleDeleteSelectedRef = useRef9(() => false);
13525
+ const runPendingDeleteUndoRef = useRef9(() => false);
13526
+ const isFooterFrameSelectionRef = useRef9(false);
13527
+ const refreshActiveCommandsRef = useRef9(() => {
12709
13528
  });
12710
- const postToParentRef = useRef8(postToParent2);
13529
+ const postToParentRef = useRef9(postToParent2);
12711
13530
  postToParentRef.current = postToParent2;
12712
- const aiSectionApiRef = useRef8(null);
12713
- const sectionsLoadedRef = useRef8(false);
12714
- const pendingScheduleConfigRequests = useRef8([]);
12715
- const [toolbarRect, setToolbarRect] = useState10(null);
12716
- const [toolbarVariant, setToolbarVariant] = useState10("none");
12717
- const toolbarVariantRef = useRef8("none");
13531
+ const aiSectionApiRef = useRef9(null);
13532
+ const sectionsLoadedRef = useRef9(false);
13533
+ const pendingScheduleConfigRequests = useRef9([]);
13534
+ const [toolbarRect, setToolbarRect] = useState11(null);
13535
+ const [toolbarVariant, setToolbarVariant] = useState11("none");
13536
+ const toolbarVariantRef = useRef9("none");
12718
13537
  toolbarVariantRef.current = toolbarVariant;
12719
- const [selectedIsCta, setSelectedIsCta] = useState10(false);
12720
- const [reorderHrefKey, setReorderHrefKey] = useState10(null);
12721
- const [reorderDragDisabled, setReorderDragDisabled] = useState10(false);
12722
- const [toggleState, setToggleState] = useState10(null);
12723
- const [maxBadge, setMaxBadge] = useState10(null);
12724
- const [activeCommands, setActiveCommands] = useState10(/* @__PURE__ */ new Set());
12725
- const [sectionGap, setSectionGap] = useState10(null);
12726
- const [toolbarShowEditLink, setToolbarShowEditLink] = useState10(false);
12727
- const hoveredNavContainerRef = useRef8(null);
12728
- const [hoveredNavContainerRect, setHoveredNavContainerRect] = useState10(null);
12729
- const hoveredItemElRef = useRef8(null);
12730
- const [hoveredItemRect, setHoveredItemRect] = useState10(null);
12731
- const siblingHintElRef = useRef8(null);
12732
- const [siblingHintRect, setSiblingHintRect] = useState10(null);
12733
- const [siblingHintRects, setSiblingHintRects] = useState10([]);
12734
- const [isItemDragging, setIsItemDragging] = useState10(false);
12735
- const [isFooterFrameSelection, setIsFooterFrameSelection] = useState10(false);
13538
+ const [selectedIsCta, setSelectedIsCta] = useState11(false);
13539
+ const [selectedIsSocial, setSelectedIsSocial] = useState11(false);
13540
+ const [selectedIsSocialsRow, setSelectedIsSocialsRow] = useState11(false);
13541
+ const [reorderHrefKey, setReorderHrefKey] = useState11(null);
13542
+ const [reorderDragDisabled, setReorderDragDisabled] = useState11(false);
13543
+ const [toggleState, setToggleState] = useState11(null);
13544
+ const [maxBadge, setMaxBadge] = useState11(null);
13545
+ const [activeCommands, setActiveCommands] = useState11(/* @__PURE__ */ new Set());
13546
+ const [sectionGap, setSectionGap] = useState11(null);
13547
+ const [toolbarShowEditLink, setToolbarShowEditLink] = useState11(false);
13548
+ const hoveredNavContainerRef = useRef9(null);
13549
+ const [hoveredNavContainerRect, setHoveredNavContainerRect] = useState11(null);
13550
+ const hoveredItemElRef = useRef9(null);
13551
+ const [hoveredItemRect, setHoveredItemRect] = useState11(null);
13552
+ const siblingHintElRef = useRef9(null);
13553
+ const [siblingHintRect, setSiblingHintRect] = useState11(null);
13554
+ const [siblingHintRects, setSiblingHintRects] = useState11([]);
13555
+ const [isItemDragging, setIsItemDragging] = useState11(false);
13556
+ const [isFooterFrameSelection, setIsFooterFrameSelection] = useState11(false);
12736
13557
  isFooterFrameSelectionRef.current = isFooterFrameSelection;
12737
- const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = useState10(null);
12738
- const [footerHeadingVisible, setFooterHeadingVisible] = useState10(null);
12739
- const footerDragRef = useRef8(null);
12740
- const [footerDropSlots, setFooterDropSlots] = useState10([]);
12741
- const [activeFooterDropIndex, setActiveFooterDropIndex] = useState10(null);
12742
- const [draggedItemRect, setDraggedItemRect] = useState10(null);
12743
- const footerPointerDragRef = useRef8(null);
12744
- const suppressNextClickRef = useRef8(false);
12745
- const suppressClickUntilRef = useRef8(0);
12746
- const [linkPopover, setLinkPopover] = useState10(null);
12747
- const linkPopoverSessionRef = useRef8(null);
12748
- const addNavAfterAnchorRef = useRef8(null);
12749
- const editContentRef = useRef8({});
12750
- const aiSectionsRef = useRef8("");
12751
- const pendingDeleteUndoRef = useRef8(null);
12752
- const [sitePages, setSitePages] = useState10([]);
12753
- const [sectionsByPath, setSectionsByPath] = useState10({});
12754
- const sectionsPrefetchGenRef = useRef8(0);
12755
- const setLinkPopoverRef = useRef8(setLinkPopover);
12756
- const linkPopoverPanelRef = useRef8(null);
12757
- const linkPopoverOpenRef = useRef8(false);
12758
- const linkPopoverGraceUntilRef = useRef8(0);
13558
+ const [floatingPanel, setFloatingPanel] = useState11(null);
13559
+ const [floatingPanelPos, setFloatingPanelPos] = useState11(null);
13560
+ const [parentScrollSnap, setParentScrollSnap] = useState11(null);
13561
+ const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = useState11(null);
13562
+ const [footerHeadingVisible, setFooterHeadingVisible] = useState11(null);
13563
+ const footerDragRef = useRef9(null);
13564
+ const [footerDropSlots, setFooterDropSlots] = useState11([]);
13565
+ const [activeFooterDropIndex, setActiveFooterDropIndex] = useState11(null);
13566
+ const [draggedItemRect, setDraggedItemRect] = useState11(null);
13567
+ const footerPointerDragRef = useRef9(null);
13568
+ const suppressNextClickRef = useRef9(false);
13569
+ const suppressClickUntilRef = useRef9(0);
13570
+ const [linkPopover, setLinkPopover] = useState11(null);
13571
+ const linkPopoverSessionRef = useRef9(null);
13572
+ const addNavAfterAnchorRef = useRef9(null);
13573
+ const editContentRef = useRef9({});
13574
+ const aiSectionsRef = useRef9("");
13575
+ const pendingDeleteUndoRef = useRef9(null);
13576
+ const [sitePages, setSitePages] = useState11([]);
13577
+ const [sectionsByPath, setSectionsByPath] = useState11({});
13578
+ const sectionsPrefetchGenRef = useRef9(0);
13579
+ const setLinkPopoverRef = useRef9(setLinkPopover);
13580
+ const linkPopoverPanelRef = useRef9(null);
13581
+ const linkPopoverOpenRef = useRef9(false);
13582
+ const linkPopoverGraceUntilRef = useRef9(0);
12759
13583
  setLinkPopoverRef.current = setLinkPopover;
12760
13584
  linkPopoverSessionRef.current = linkPopover;
12761
13585
  const {
@@ -12793,7 +13617,7 @@ function OhhwellsBridge() {
12793
13617
  const bumpLinkPopoverGrace = () => {
12794
13618
  linkPopoverGraceUntilRef.current = Date.now() + 350;
12795
13619
  };
12796
- const runSectionsPrefetch = useCallback6((pages) => {
13620
+ const runSectionsPrefetch = useCallback7((pages) => {
12797
13621
  if (!isEditMode || shouldUseDevFixtures() || pages.length === 0) return;
12798
13622
  const gen = ++sectionsPrefetchGenRef.current;
12799
13623
  const paths = pages.map((p) => p.path);
@@ -12812,9 +13636,9 @@ function OhhwellsBridge() {
12812
13636
  );
12813
13637
  });
12814
13638
  }, [isEditMode, pathname]);
12815
- const runSectionsPrefetchRef = useRef8(runSectionsPrefetch);
13639
+ const runSectionsPrefetchRef = useRef9(runSectionsPrefetch);
12816
13640
  runSectionsPrefetchRef.current = runSectionsPrefetch;
12817
- useEffect11(() => {
13641
+ useEffect12(() => {
12818
13642
  if (!linkPopover) {
12819
13643
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
12820
13644
  return;
@@ -12842,7 +13666,7 @@ function OhhwellsBridge() {
12842
13666
  document.documentElement.removeAttribute("data-ohw-link-popover-open");
12843
13667
  };
12844
13668
  }, [linkPopover, postToParent2]);
12845
- useEffect11(() => {
13669
+ useEffect12(() => {
12846
13670
  if (!isEditMode) return;
12847
13671
  const useFixtures = shouldUseDevFixtures();
12848
13672
  if (useFixtures) {
@@ -12866,14 +13690,14 @@ function OhhwellsBridge() {
12866
13690
  if (!useFixtures) postToParent2({ type: "ow:request-site-pages" });
12867
13691
  return () => window.removeEventListener("message", onSitePages);
12868
13692
  }, [isEditMode, postToParent2]);
12869
- useEffect11(() => {
13693
+ useEffect12(() => {
12870
13694
  if (!isEditMode || shouldUseDevFixtures()) return;
12871
13695
  void loadAllSectionsManifest().then((manifest) => {
12872
13696
  if (Object.keys(manifest).length === 0) return;
12873
13697
  setSectionsByPath((prev) => ({ ...manifest, ...prev }));
12874
13698
  });
12875
13699
  }, [isEditMode]);
12876
- useEffect11(() => {
13700
+ useEffect12(() => {
12877
13701
  const update = () => {
12878
13702
  const el = activeElRef.current ?? selectedElRef.current;
12879
13703
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
@@ -12897,10 +13721,10 @@ function OhhwellsBridge() {
12897
13721
  vvp.removeEventListener("resize", update);
12898
13722
  };
12899
13723
  }, []);
12900
- const refreshStateRules = useCallback6(() => {
13724
+ const refreshStateRules = useCallback7(() => {
12901
13725
  editStylesRef.current?.forceHover && (editStylesRef.current.forceHover.textContent = collectStateRules());
12902
13726
  }, []);
12903
- const processConfigRequest = useCallback6((insertAfterVal) => {
13727
+ const processConfigRequest = useCallback7((insertAfterVal) => {
12904
13728
  const tracker = getSectionsTracker();
12905
13729
  let entries = [];
12906
13730
  try {
@@ -12923,7 +13747,7 @@ function OhhwellsBridge() {
12923
13747
  }
12924
13748
  window.postMessage({ type: "ow:schedule-config", insertAfter: insertAfterVal, scheduleId: null }, "*");
12925
13749
  }, [isEditMode]);
12926
- const deactivate = useCallback6(() => {
13750
+ const deactivate = useCallback7(() => {
12927
13751
  const el = activeElRef.current;
12928
13752
  if (!el) return;
12929
13753
  const key = el.dataset.ohwKey;
@@ -12956,17 +13780,19 @@ function OhhwellsBridge() {
12956
13780
  setToolbarShowEditLink(false);
12957
13781
  postToParent2({ type: "ow:exit-edit" });
12958
13782
  }, [postToParent2]);
12959
- const clearSelectedAttr = useCallback6(() => {
13783
+ const clearSelectedAttr = useCallback7(() => {
12960
13784
  document.querySelectorAll("[data-ohw-selected]").forEach((el) => {
12961
13785
  el.removeAttribute("data-ohw-selected");
12962
13786
  });
12963
13787
  }, []);
12964
- const deselect = useCallback6(() => {
13788
+ const deselect = useCallback7(() => {
12965
13789
  clearSelectedAttr();
12966
13790
  selectedElRef.current = null;
12967
13791
  selectedHrefKeyRef.current = null;
12968
13792
  selectedFooterColAttrRef.current = null;
12969
13793
  setSelectedIsCta(false);
13794
+ setSelectedIsSocial(false);
13795
+ setSelectedIsSocialsRow(false);
12970
13796
  setReorderHrefKey(null);
12971
13797
  setReorderDragDisabled(false);
12972
13798
  setIsFooterFrameSelection(false);
@@ -12984,11 +13810,11 @@ function OhhwellsBridge() {
12984
13810
  setToolbarVariant("none");
12985
13811
  }
12986
13812
  }, [clearSelectedAttr]);
12987
- const markSelected = useCallback6((el) => {
13813
+ const markSelected = useCallback7((el) => {
12988
13814
  clearSelectedAttr();
12989
13815
  el.setAttribute("data-ohw-selected", "");
12990
13816
  }, [clearSelectedAttr]);
12991
- const resolveHrefKeyElement = useCallback6((hrefKey) => {
13817
+ const resolveHrefKeyElement = useCallback7((hrefKey) => {
12992
13818
  if (isFooterHrefKey(hrefKey)) {
12993
13819
  return document.querySelector(
12994
13820
  `footer [data-ohw-href-key="${CSS.escape(hrefKey)}"]`
@@ -13003,7 +13829,7 @@ function OhhwellsBridge() {
13003
13829
  `[data-ohw-href-key="${CSS.escape(hrefKey)}"]`
13004
13830
  );
13005
13831
  }, []);
13006
- const resyncSelectedNavigationItem = useCallback6(() => {
13832
+ const resyncSelectedNavigationItem = useCallback7(() => {
13007
13833
  const hrefKey = selectedHrefKeyRef.current;
13008
13834
  if (hrefKey) {
13009
13835
  const link = resolveHrefKeyElement(hrefKey);
@@ -13041,12 +13867,14 @@ function OhhwellsBridge() {
13041
13867
  );
13042
13868
  }
13043
13869
  }, [resolveHrefKeyElement]);
13044
- const reselectNavigationItem = useCallback6((navAnchor) => {
13870
+ const reselectNavigationItem = useCallback7((navAnchor) => {
13045
13871
  selectedElRef.current = navAnchor;
13046
13872
  selectedHrefKeyRef.current = navAnchor.getAttribute("data-ohw-href-key");
13047
13873
  selectedFooterColAttrRef.current = null;
13048
13874
  markSelected(navAnchor);
13049
13875
  setSelectedIsCta(isCtaButton(navAnchor));
13876
+ setSelectedIsSocial(Boolean(getSocialItem(navAnchor)));
13877
+ setSelectedIsSocialsRow(false);
13050
13878
  const isDropdownTrigger = !isNestedNavChild(navAnchor) && (navItemHasDropdownChildren(navAnchor) || navItemOwnsDropdownPanel(navAnchor));
13051
13879
  if (isNestedNavChild(navAnchor)) {
13052
13880
  setNavGroupForceOpen(navAnchor, true);
@@ -13070,7 +13898,7 @@ function OhhwellsBridge() {
13070
13898
  setToolbarShowEditLink(false);
13071
13899
  setActiveCommands(/* @__PURE__ */ new Set());
13072
13900
  }, [markSelected]);
13073
- const commitNavigationTextEdit = useCallback6((navAnchor) => {
13901
+ const commitNavigationTextEdit = useCallback7((navAnchor) => {
13074
13902
  const el = activeElRef.current;
13075
13903
  if (!el) return;
13076
13904
  const key = el.dataset.ohwKey;
@@ -13097,7 +13925,7 @@ function OhhwellsBridge() {
13097
13925
  postToParent2({ type: "ow:exit-edit" });
13098
13926
  reselectNavigationItem(navAnchor);
13099
13927
  }, [postToParent2, reselectNavigationItem]);
13100
- const handleAddTopLevelNavItem = useCallback6(() => {
13928
+ const handleAddTopLevelNavItem = useCallback7(() => {
13101
13929
  const items = listNavbarRootItems();
13102
13930
  addNavAfterAnchorRef.current = items[items.length - 1] ?? null;
13103
13931
  deselectRef.current();
@@ -13109,7 +13937,7 @@ function OhhwellsBridge() {
13109
13937
  intent: "add-nav"
13110
13938
  });
13111
13939
  }, []);
13112
- const maybeWarnNavLinkDropdownConflict = useCallback6(
13940
+ const maybeWarnNavLinkDropdownConflict = useCallback7(
13113
13941
  (anchor) => {
13114
13942
  if (!isNavbarHrefKey(anchor.getAttribute("data-ohw-href-key"))) return;
13115
13943
  if (!navDropdownsOpenOnClick()) return;
@@ -13122,7 +13950,7 @@ function OhhwellsBridge() {
13122
13950
  },
13123
13951
  [postToParent2]
13124
13952
  );
13125
- const handleNavDropdownOpenChange = useCallback6((open) => {
13953
+ const handleNavDropdownOpenChange = useCallback7((open) => {
13126
13954
  const selected = selectedElRef.current;
13127
13955
  if (!selected || !isNavigationItem2(selected)) return;
13128
13956
  setNavGroupForceOpen(selected, open);
@@ -13134,7 +13962,7 @@ function OhhwellsBridge() {
13134
13962
  }
13135
13963
  });
13136
13964
  }, []);
13137
- const handleFooterHeadingVisibleChange = useCallback6(
13965
+ const handleFooterHeadingVisibleChange = useCallback7(
13138
13966
  (visible) => {
13139
13967
  const selected = selectedElRef.current;
13140
13968
  if (!selected || !isFooterFrameSelectionRef.current) return;
@@ -13158,7 +13986,7 @@ function OhhwellsBridge() {
13158
13986
  },
13159
13987
  [postToParent2]
13160
13988
  );
13161
- const enterEditOnNewItem = useCallback6((anchor) => {
13989
+ const enterEditOnNewItem = useCallback7((anchor) => {
13162
13990
  const label = anchor.querySelector('[data-ohw-editable="text"]');
13163
13991
  if (!label) {
13164
13992
  selectRef.current(anchor);
@@ -13167,9 +13995,31 @@ function OhhwellsBridge() {
13167
13995
  setNavGroupForceOpen(anchor, true);
13168
13996
  activateRef.current(label);
13169
13997
  }, []);
13170
- const handleAddChildItem = useCallback6(() => {
13998
+ const handleAddChildItem = useCallback7(() => {
13171
13999
  const selected = selectedElRef.current;
13172
14000
  if (!selected) return;
14001
+ const socialsRow = isSocialsRow(selected) ? selected : findSocialsRow(selected);
14002
+ if (socialsRow) {
14003
+ const after = getSocialItem(selected);
14004
+ const result2 = insertSocialItem(socialsRow, after, editContentRef.current);
14005
+ if (!result2) return;
14006
+ const orderJson = JSON.stringify(result2.order);
14007
+ applySocialsDisplayToRow(socialsRow, socialsDisplayFor(socialsRow, editContentRef.current));
14008
+ editContentRef.current = { ...editContentRef.current, [SOCIALS_ORDER_KEY]: orderJson };
14009
+ postToParent2({ type: "ow:change", nodes: [{ key: SOCIALS_ORDER_KEY, text: orderJson }] });
14010
+ postToParentRef.current({
14011
+ type: "ow:social-pick",
14012
+ hrefKey: result2.hrefKey,
14013
+ iconKey: result2.iconKey,
14014
+ url: "",
14015
+ iconStyle: detectIconStyle(result2.item),
14016
+ platformId: "",
14017
+ // Lets the editor undo the insert if the dialog is dismissed: an item that was never given
14018
+ // an address should not survive a Cancel.
14019
+ isNew: true
14020
+ });
14021
+ return;
14022
+ }
13173
14023
  if (toolbarVariantRef.current === "select-frame" && isFooterFrameSelection) {
13174
14024
  if (!selected.hasAttribute("data-ohw-footer-col") && !selected.closest("[data-ohw-footer-col]")) {
13175
14025
  }
@@ -13243,7 +14093,7 @@ function OhhwellsBridge() {
13243
14093
  enterEditOnNewItem(result.anchor);
13244
14094
  });
13245
14095
  }, [enterEditOnNewItem, isFooterFrameSelection, maybeWarnNavLinkDropdownConflict, postToParent2]);
13246
- const handleAddFooterColumn = useCallback6(() => {
14096
+ const handleAddFooterColumn = useCallback7(() => {
13247
14097
  if (!canAddFooterColumn()) {
13248
14098
  postToParent2({
13249
14099
  type: "ow:toast",
@@ -13264,7 +14114,7 @@ function OhhwellsBridge() {
13264
14114
  selectRef.current(result.firstLink);
13265
14115
  });
13266
14116
  }, [postToParent2]);
13267
- const clearFooterDragVisuals = useCallback6(() => {
14117
+ const clearFooterDragVisuals = useCallback7(() => {
13268
14118
  footerDragRef.current = null;
13269
14119
  setSiblingHintRects([]);
13270
14120
  setFooterDropSlots([]);
@@ -13273,7 +14123,7 @@ function OhhwellsBridge() {
13273
14123
  setIsItemDragging(false);
13274
14124
  unlockFooterDragInteraction();
13275
14125
  }, []);
13276
- const refreshFooterDragVisuals = useCallback6((session, activeSlot, clientX, clientY) => {
14126
+ const refreshFooterDragVisuals = useCallback7((session, activeSlot, clientX, clientY) => {
13277
14127
  const dragged = session.draggedEl;
13278
14128
  setDraggedItemRect(dragged.getBoundingClientRect());
13279
14129
  if (typeof clientX === "number" && typeof clientY === "number") {
@@ -13282,6 +14132,13 @@ function OhhwellsBridge() {
13282
14132
  }
13283
14133
  session.activeSlot = activeSlot;
13284
14134
  setSiblingHintRects([]);
14135
+ if (session.kind === "social") {
14136
+ const slots2 = session.hrefKey ? buildSocialDropSlotsForKey(session.hrefKey) : [];
14137
+ setFooterDropSlots(slots2);
14138
+ const activeIdx2 = activeSlot ? slots2.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
14139
+ setActiveFooterDropIndex(activeIdx2 >= 0 ? activeIdx2 : null);
14140
+ return;
14141
+ }
13285
14142
  if (session.kind === "link") {
13286
14143
  const columns = listFooterColumns();
13287
14144
  const slots2 = [];
@@ -13298,13 +14155,13 @@ function OhhwellsBridge() {
13298
14155
  const activeIdx = activeSlot ? slots.findIndex((s) => s.insertIndex === activeSlot.insertIndex) : -1;
13299
14156
  setActiveFooterDropIndex(activeIdx >= 0 ? activeIdx : null);
13300
14157
  }, []);
13301
- const refreshFooterDragVisualsRef = useRef8(refreshFooterDragVisuals);
14158
+ const refreshFooterDragVisualsRef = useRef9(refreshFooterDragVisuals);
13302
14159
  refreshFooterDragVisualsRef.current = refreshFooterDragVisuals;
13303
- const commitFooterDragRef = useRef8(() => {
14160
+ const commitFooterDragRef = useRef9(() => {
13304
14161
  });
13305
- const beginFooterDragRef = useRef8(() => {
14162
+ const beginFooterDragRef = useRef9(() => {
13306
14163
  });
13307
- const beginFooterDrag = useCallback6(
14164
+ const beginFooterDrag = useCallback7(
13308
14165
  (session) => {
13309
14166
  const rect = session.draggedEl.getBoundingClientRect();
13310
14167
  session.lastClientX = session.lastClientX || rect.left + rect.width / 2;
@@ -13318,13 +14175,13 @@ function OhhwellsBridge() {
13318
14175
  if (session.wasSelected && selectedElRef.current === session.draggedEl) {
13319
14176
  setToolbarRect(rect);
13320
14177
  }
13321
- const initialSlot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : hitTestColumnDropSlot(session.lastClientX, session.lastClientY);
14178
+ const initialSlot = session.kind === "social" && session.hrefKey ? hitTestSocialDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : hitTestColumnDropSlot(session.lastClientX, session.lastClientY);
13322
14179
  refreshFooterDragVisuals(session, initialSlot, session.lastClientX, session.lastClientY);
13323
14180
  },
13324
14181
  [refreshFooterDragVisuals]
13325
14182
  );
13326
14183
  beginFooterDragRef.current = beginFooterDrag;
13327
- const commitFooterDrag = useCallback6(
14184
+ const commitFooterDrag = useCallback7(
13328
14185
  (clientX, clientY) => {
13329
14186
  const session = footerDragRef.current;
13330
14187
  if (!session) {
@@ -13334,8 +14191,11 @@ function OhhwellsBridge() {
13334
14191
  const x = typeof clientX === "number" && (clientX !== 0 || clientY !== 0) ? clientX : session.lastClientX;
13335
14192
  const y = typeof clientY === "number" && (clientX !== 0 || clientY !== 0) ? clientY : session.lastClientY;
13336
14193
  let nextOrder = null;
13337
- const slot = session.activeSlot ?? (session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(x, y, session.hrefKey) : session.kind === "column" ? hitTestColumnDropSlot(x, y) : null);
13338
- if (session.kind === "link" && session.hrefKey && slot) {
14194
+ let nextSocialsOrder = null;
14195
+ const slot = session.activeSlot ?? (session.kind === "social" && session.hrefKey ? hitTestSocialDropSlot(x, y, session.hrefKey) : session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(x, y, session.hrefKey) : session.kind === "column" ? hitTestColumnDropSlot(x, y) : null);
14196
+ if (session.kind === "social" && session.hrefKey && slot) {
14197
+ nextSocialsOrder = planSocialMove(session.hrefKey, slot.insertIndex);
14198
+ } else if (session.kind === "link" && session.hrefKey && slot) {
13339
14199
  nextOrder = planFooterLinkMove(session.hrefKey, slot.columnIndex, slot.insertIndex);
13340
14200
  } else if (session.kind === "column" && slot) {
13341
14201
  nextOrder = planFooterColumnMove(session.sourceColumnIndex, slot.insertIndex);
@@ -13393,6 +14253,27 @@ function OhhwellsBridge() {
13393
14253
  }
13394
14254
  deselectRef.current();
13395
14255
  };
14256
+ if (nextSocialsOrder) {
14257
+ const orderJson = JSON.stringify(nextSocialsOrder);
14258
+ editContentRef.current = { ...editContentRef.current, [SOCIALS_ORDER_KEY]: orderJson };
14259
+ applySocialsOrder(nextSocialsOrder);
14260
+ postToParentRef.current({
14261
+ type: "ow:change",
14262
+ nodes: [{ key: SOCIALS_ORDER_KEY, text: orderJson }]
14263
+ });
14264
+ applySelectionAfterDrop();
14265
+ clearFooterDragVisuals();
14266
+ const reapply = nextSocialsOrder;
14267
+ requestAnimationFrame(() => {
14268
+ if (editContentRef.current[SOCIALS_ORDER_KEY] === orderJson) applySocialsOrder(reapply);
14269
+ applySelectionAfterDrop();
14270
+ requestAnimationFrame(() => {
14271
+ if (editContentRef.current[SOCIALS_ORDER_KEY] === orderJson) applySocialsOrder(reapply);
14272
+ resyncSelectedNavigationItem();
14273
+ });
14274
+ });
14275
+ return;
14276
+ }
13396
14277
  if (nextOrder) {
13397
14278
  const orderJson = JSON.stringify(nextOrder);
13398
14279
  editContentRef.current = {
@@ -13428,10 +14309,25 @@ function OhhwellsBridge() {
13428
14309
  [clearFooterDragVisuals, resolveHrefKeyElement, resyncSelectedNavigationItem]
13429
14310
  );
13430
14311
  commitFooterDragRef.current = commitFooterDrag;
13431
- const startFooterLinkDrag = useCallback6(
14312
+ const startFooterLinkDrag = useCallback7(
13432
14313
  (anchor, clientX, clientY, wasSelected) => {
13433
14314
  const hrefKey = anchor.getAttribute("data-ohw-href-key");
13434
- if (!hrefKey || !isFooterHrefKey(hrefKey)) return false;
14315
+ if (!hrefKey) return false;
14316
+ if (getSocialItem(anchor)) {
14317
+ beginFooterDrag({
14318
+ kind: "social",
14319
+ hrefKey,
14320
+ columnEl: null,
14321
+ sourceColumnIndex: 0,
14322
+ wasSelected,
14323
+ draggedEl: anchor,
14324
+ lastClientX: clientX,
14325
+ lastClientY: clientY,
14326
+ activeSlot: null
14327
+ });
14328
+ return true;
14329
+ }
14330
+ if (!isFooterHrefKey(hrefKey)) return false;
13435
14331
  const column = findFooterColumnForLink(anchor);
13436
14332
  const columns = listFooterColumns();
13437
14333
  beginFooterDrag({
@@ -13449,7 +14345,7 @@ function OhhwellsBridge() {
13449
14345
  },
13450
14346
  [beginFooterDrag]
13451
14347
  );
13452
- const startFooterColumnDrag = useCallback6(
14348
+ const startFooterColumnDrag = useCallback7(
13453
14349
  (columnEl, clientX, clientY, wasSelected) => {
13454
14350
  const columns = listFooterColumns();
13455
14351
  const idx = columns.indexOf(columnEl);
@@ -13469,7 +14365,7 @@ function OhhwellsBridge() {
13469
14365
  },
13470
14366
  [beginFooterDrag]
13471
14367
  );
13472
- const handleItemDragStart = useCallback6(
14368
+ const handleItemDragStart = useCallback7(
13473
14369
  (e) => {
13474
14370
  const selected = selectedElRef.current;
13475
14371
  if (!selected) {
@@ -13489,7 +14385,7 @@ function OhhwellsBridge() {
13489
14385
  },
13490
14386
  [startFooterColumnDrag, startFooterLinkDrag, startNavLinkDrag]
13491
14387
  );
13492
- const handleItemDragEnd = useCallback6(
14388
+ const handleItemDragEnd = useCallback7(
13493
14389
  (e) => {
13494
14390
  if (footerDragRef.current) {
13495
14391
  const x = e?.clientX;
@@ -13515,7 +14411,7 @@ function OhhwellsBridge() {
13515
14411
  },
13516
14412
  [commitFooterDrag, commitNavDrag, navDragRef]
13517
14413
  );
13518
- const handleItemChromePointerDown = useCallback6((e) => {
14414
+ const handleItemChromePointerDown = useCallback7((e) => {
13519
14415
  if (e.button !== 0) return;
13520
14416
  const selected = selectedElRef.current;
13521
14417
  if (!selected) return;
@@ -13546,7 +14442,7 @@ function OhhwellsBridge() {
13546
14442
  }
13547
14443
  if (armNavPressFromChrome(selected, e.clientX, e.clientY, e.pointerId)) return;
13548
14444
  }, [armNavPressFromChrome]);
13549
- const handleItemChromeClick = useCallback6((clientX, clientY) => {
14445
+ const handleItemChromeClick = useCallback7((clientX, clientY) => {
13550
14446
  if (suppressNextClickRef.current || Date.now() < suppressClickUntilRef.current) {
13551
14447
  suppressNextClickRef.current = false;
13552
14448
  return;
@@ -13559,7 +14455,7 @@ function OhhwellsBridge() {
13559
14455
  }, []);
13560
14456
  reselectNavigationItemRef.current = reselectNavigationItem;
13561
14457
  commitNavigationTextEditRef.current = commitNavigationTextEdit;
13562
- const select = useCallback6((anchor) => {
14458
+ const select = useCallback7((anchor) => {
13563
14459
  if (!isNavigationItem2(anchor)) return;
13564
14460
  if (activeElRef.current) deactivate();
13565
14461
  aiSectionApiRef.current?.selectFromElement(anchor);
@@ -13568,6 +14464,8 @@ function OhhwellsBridge() {
13568
14464
  selectedFooterColAttrRef.current = null;
13569
14465
  markSelected(anchor);
13570
14466
  setSelectedIsCta(isCtaButton(anchor));
14467
+ setSelectedIsSocial(Boolean(getSocialItem(anchor)));
14468
+ setSelectedIsSocialsRow(false);
13571
14469
  clearHrefKeyHover(anchor);
13572
14470
  const isDropdownTrigger = !isNestedNavChild(anchor) && (navItemHasDropdownChildren(anchor) || navItemOwnsDropdownPanel(anchor));
13573
14471
  if (isNestedNavChild(anchor)) {
@@ -13598,7 +14496,7 @@ function OhhwellsBridge() {
13598
14496
  setToolbarShowEditLink(false);
13599
14497
  setActiveCommands(/* @__PURE__ */ new Set());
13600
14498
  }, [deactivate, markSelected]);
13601
- const selectFrame = useCallback6((el) => {
14499
+ const selectFrame = useCallback7((el) => {
13602
14500
  if (!isNavigationContainer(el)) return;
13603
14501
  if (activeElRef.current) deactivate();
13604
14502
  aiSectionApiRef.current?.selectFromElement(el);
@@ -13608,6 +14506,8 @@ function OhhwellsBridge() {
13608
14506
  selectedFooterColAttrRef.current = isFooterColumn ? el.getAttribute("data-ohw-footer-col") ?? String(listFooterColumns().indexOf(el)) : null;
13609
14507
  markSelected(el);
13610
14508
  setSelectedIsCta(false);
14509
+ setSelectedIsSocial(false);
14510
+ setSelectedIsSocialsRow(isSocialsRow(el));
13611
14511
  clearHrefKeyHover(el);
13612
14512
  setNavGroupForceOpen(null, false);
13613
14513
  hoveredNavContainerRef.current = null;
@@ -13645,13 +14545,57 @@ function OhhwellsBridge() {
13645
14545
  setToolbarShowEditLink(false);
13646
14546
  setActiveCommands(/* @__PURE__ */ new Set());
13647
14547
  }, [deactivate, markSelected, postToParent2]);
13648
- const activate = useCallback6((el, options) => {
14548
+ const openSocialsDisplayPanel = useCallback7((row) => {
14549
+ setParentScrollSnap(parentScrollRef.current);
14550
+ setFloatingPanel({
14551
+ key: "socials-display",
14552
+ title: "Style",
14553
+ context: "Socials \xB7 Footer",
14554
+ kind: "socials-display",
14555
+ row
14556
+ });
14557
+ }, []);
14558
+ const changeSocialsDisplay = useCallback7(
14559
+ (row, next) => {
14560
+ if (next.icon) {
14561
+ const missing = socialsMissingIcons(row);
14562
+ listSocialItems(row).forEach((item) => ensureIconSlot(item));
14563
+ if (missing.length) {
14564
+ postToParentRef.current({ type: "ow:social-icons-needed", items: missing });
14565
+ }
14566
+ }
14567
+ applySocialsDisplayToRow(row, next);
14568
+ requestAnimationFrame(() => {
14569
+ if (selectedElRef.current === row && row.isConnected) setToolbarRect(row.getBoundingClientRect());
14570
+ });
14571
+ const displayJson = JSON.stringify(socialsDisplayWith(row, next, editContentRef.current));
14572
+ editContentRef.current = { ...editContentRef.current, [SOCIALS_DISPLAY_KEY]: displayJson };
14573
+ postToParentRef.current({
14574
+ type: "ow:change",
14575
+ nodes: [{ key: SOCIALS_DISPLAY_KEY, text: displayJson }],
14576
+ flush: true
14577
+ });
14578
+ },
14579
+ []
14580
+ );
14581
+ const closeFloatingPanelOnly = useCallback7(() => {
14582
+ setFloatingPanel(null);
14583
+ }, []);
14584
+ const closeFloatingPanelAndDeselect = useCallback7(() => {
14585
+ setFloatingPanel(null);
14586
+ deselectRef.current();
14587
+ }, []);
14588
+ const activate = useCallback7((el, options) => {
13649
14589
  if (activeElRef.current === el) return;
14590
+ if (isIconEditable(el)) return;
14591
+ if (el.hasAttribute("data-ohw-social-label")) return;
13650
14592
  clearSelectedAttr();
13651
14593
  selectedElRef.current = null;
13652
14594
  selectedHrefKeyRef.current = null;
13653
14595
  selectedFooterColAttrRef.current = null;
13654
14596
  setSelectedIsCta(false);
14597
+ setSelectedIsSocial(false);
14598
+ setSelectedIsSocialsRow(false);
13655
14599
  deactivate();
13656
14600
  if (hoveredImageRef.current) {
13657
14601
  hoveredImageRef.current = null;
@@ -13722,7 +14666,7 @@ function OhhwellsBridge() {
13722
14666
  selectRef.current = select;
13723
14667
  selectFrameRef.current = selectFrame;
13724
14668
  deselectRef.current = deselect;
13725
- useLayoutEffect3(() => {
14669
+ useLayoutEffect4(() => {
13726
14670
  if (!subdomain || isEditMode) {
13727
14671
  setFetchState("done");
13728
14672
  return;
@@ -13762,6 +14706,8 @@ function OhhwellsBridge() {
13762
14706
  }
13763
14707
  } else if (el.dataset.ohwEditable === "link") {
13764
14708
  applyLinkHref(el, val);
14709
+ } else if (el.dataset.ohwEditable === "icon") {
14710
+ applyIconMarkup(el, val);
13765
14711
  } else if (el.innerHTML !== val) {
13766
14712
  el.innerHTML = val;
13767
14713
  }
@@ -13770,8 +14716,11 @@ function OhhwellsBridge() {
13770
14716
  }
13771
14717
  reconcileNavbarItemsFromContent(content);
13772
14718
  reconcileFooterOrderFromContent(content);
14719
+ reconcileSocialsFromContent(content);
14720
+ applySocialsDisplayFromContent(content);
13773
14721
  enforceLinkHrefs();
13774
14722
  initSectionsFromContent(content, true);
14723
+ initSectionInstancesFromContent(content, window.location.pathname);
13775
14724
  sectionsLoadedRef.current = true;
13776
14725
  pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
13777
14726
  return imageLoads.length > 0 ? Promise.all(imageLoads).then(() => {
@@ -13798,7 +14747,7 @@ function OhhwellsBridge() {
13798
14747
  cancelled = true;
13799
14748
  };
13800
14749
  }, [subdomain, isEditMode]);
13801
- useEffect11(() => {
14750
+ useEffect12(() => {
13802
14751
  if (!subdomain || isEditMode) return;
13803
14752
  let debounceTimer = null;
13804
14753
  let observer = null;
@@ -13806,6 +14755,7 @@ function OhhwellsBridge() {
13806
14755
  const content = contentCache.get(subdomain);
13807
14756
  if (!content) return;
13808
14757
  retryMissingSchedulingMounts(getPageSchedulingEntries(content["__ohw_sections"]), false);
14758
+ initSectionInstancesFromContent(content, window.location.pathname);
13809
14759
  observer?.disconnect();
13810
14760
  try {
13811
14761
  for (const [key, val] of Object.entries(content)) {
@@ -13832,6 +14782,8 @@ function OhhwellsBridge() {
13832
14782
  }
13833
14783
  reconcileNavbarItemsFromContent(content);
13834
14784
  reconcileFooterOrderFromContent(content);
14785
+ reconcileSocialsFromContent(content);
14786
+ applySocialsDisplayFromContent(content);
13835
14787
  } finally {
13836
14788
  observer?.observe(document.body, { childList: true, subtree: true });
13837
14789
  }
@@ -13849,16 +14801,16 @@ function OhhwellsBridge() {
13849
14801
  if (debounceTimer) clearTimeout(debounceTimer);
13850
14802
  };
13851
14803
  }, [subdomain, isEditMode, pathname]);
13852
- useLayoutEffect3(() => {
14804
+ useLayoutEffect4(() => {
13853
14805
  const el = document.getElementById("ohw-loader");
13854
14806
  if (!el) return;
13855
14807
  const visible = Boolean(subdomain) && fetchState !== "done";
13856
14808
  el.style.display = visible ? "flex" : "none";
13857
14809
  }, [subdomain, fetchState]);
13858
- useEffect11(() => {
14810
+ useEffect12(() => {
13859
14811
  postToParent2({ type: "ow:navigation", path: pathname });
13860
14812
  }, [pathname, postToParent2]);
13861
- useEffect11(() => {
14813
+ useEffect12(() => {
13862
14814
  if (!isEditMode) return;
13863
14815
  if (linkPopoverSessionRef.current?.intent === "add-nav") return;
13864
14816
  if (document.querySelector("[data-ohw-section-picker]")) return;
@@ -13866,7 +14818,7 @@ function OhhwellsBridge() {
13866
14818
  deselectRef.current();
13867
14819
  deactivateRef.current();
13868
14820
  }, [pathname, isEditMode]);
13869
- useEffect11(() => {
14821
+ useEffect12(() => {
13870
14822
  const contentForNav = () => {
13871
14823
  if (isEditMode) return editContentRef.current;
13872
14824
  if (!subdomain) return {};
@@ -13898,8 +14850,10 @@ function OhhwellsBridge() {
13898
14850
  const content = contentForNav();
13899
14851
  reconcileNavbarItemsFromContent(content);
13900
14852
  reconcileFooterOrderFromContent(content);
14853
+ reconcileSocialsFromContent(content);
14854
+ applySocialsDisplayFromContent(content);
13901
14855
  document.querySelectorAll("footer [data-ohw-href-key]").forEach((el) => {
13902
- if (isFooterHrefKey(el.getAttribute("data-ohw-href-key"))) {
14856
+ if (isFooterHrefKey(el.getAttribute("data-ohw-href-key")) || getSocialItem(el)) {
13903
14857
  disableNativeHrefDrag(el);
13904
14858
  }
13905
14859
  });
@@ -13931,7 +14885,7 @@ function OhhwellsBridge() {
13931
14885
  observer?.disconnect();
13932
14886
  };
13933
14887
  }, [isEditMode, pathname, subdomain, fetchState, resyncSelectedNavigationItem]);
13934
- useEffect11(() => {
14888
+ useEffect12(() => {
13935
14889
  if (!isEditMode) return;
13936
14890
  const measure = () => {
13937
14891
  const h = document.body.scrollHeight;
@@ -13955,7 +14909,7 @@ function OhhwellsBridge() {
13955
14909
  window.removeEventListener("resize", handleResize);
13956
14910
  };
13957
14911
  }, [pathname, isEditMode, postToParent2]);
13958
- useEffect11(() => {
14912
+ useEffect12(() => {
13959
14913
  if (!subdomainFromQuery || isEditMode) return;
13960
14914
  const handleClick = (e) => {
13961
14915
  const anchor = e.target.closest("a");
@@ -13971,7 +14925,7 @@ function OhhwellsBridge() {
13971
14925
  document.addEventListener("click", handleClick, true);
13972
14926
  return () => document.removeEventListener("click", handleClick, true);
13973
14927
  }, [subdomainFromQuery, isEditMode, router]);
13974
- useEffect11(() => {
14928
+ useEffect12(() => {
13975
14929
  if (!isEditMode) {
13976
14930
  editStylesRef.current?.base.remove();
13977
14931
  editStylesRef.current?.forceHover.remove();
@@ -14179,21 +15133,37 @@ function OhhwellsBridge() {
14179
15133
  });
14180
15134
  return;
14181
15135
  }
14182
- if (isMediaEditable(editable)) {
15136
+ if (isIconEditable(editable) && !getSocialItem(editable)) {
15137
+ e.preventDefault();
15138
+ e.stopPropagation();
15139
+ aiSectionApiRef.current?.selectFromElement(editable);
15140
+ postToParentRef.current({
15141
+ type: "ow:icon-pick",
15142
+ key: editable.dataset.ohwKey ?? "",
15143
+ current: currentIconRef(editable)
15144
+ });
15145
+ return;
15146
+ }
15147
+ const clickedButton = findClosestButtonLike(target);
15148
+ const buttonOnMedia = Boolean(clickedButton && isMediaEditable(editable) && editable.contains(clickedButton));
15149
+ if (isMediaEditable(editable) && !buttonOnMedia) {
14183
15150
  e.preventDefault();
14184
15151
  e.stopPropagation();
14185
15152
  aiSectionApiRef.current?.selectFromElement(editable);
14186
15153
  postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "", elementType: editable.dataset.ohwEditable ?? "image" });
14187
15154
  return;
14188
15155
  }
14189
- const hrefCtx = getHrefKeyFromElement(editable);
15156
+ const hrefLookupTarget = buttonOnMedia ? clickedButton : editable;
15157
+ const hrefCtx = getHrefKeyFromElement(hrefLookupTarget);
14190
15158
  const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
14191
15159
  if (navAnchor) {
14192
15160
  e.preventDefault();
14193
15161
  e.stopPropagation();
14194
15162
  if (selectedElRef.current === navAnchor) {
14195
15163
  if (e.detail >= 2) return;
14196
- activateRef.current(editable, { caretX: e.clientX, caretY: e.clientY });
15164
+ if (requestSocialDialog(navAnchor, postToParentRef.current, editContentRef.current)) return;
15165
+ const activateTarget = isButtonLikeElement(hrefLookupTarget) ? navAnchor.querySelector('[data-ohw-editable="text"]') ?? hrefLookupTarget : hrefLookupTarget;
15166
+ activateRef.current(activateTarget, { caretX: e.clientX, caretY: e.clientY });
14197
15167
  return;
14198
15168
  }
14199
15169
  selectRef.current(navAnchor);
@@ -14201,7 +15171,7 @@ function OhhwellsBridge() {
14201
15171
  }
14202
15172
  e.preventDefault();
14203
15173
  e.stopPropagation();
14204
- activateRef.current(editable, { caretX: e.clientX, caretY: e.clientY });
15174
+ activateRef.current(hrefLookupTarget, { caretX: e.clientX, caretY: e.clientY });
14205
15175
  return;
14206
15176
  }
14207
15177
  const hrefAnchor = getNavigationItemAnchor(target);
@@ -14209,6 +15179,7 @@ function OhhwellsBridge() {
14209
15179
  e.preventDefault();
14210
15180
  e.stopPropagation();
14211
15181
  if (selectedElRef.current === hrefAnchor) {
15182
+ if (requestSocialDialog(hrefAnchor, postToParentRef.current, editContentRef.current)) return;
14212
15183
  const textEditable = hrefAnchor.querySelector('[data-ohw-editable="text"]') ?? hrefAnchor.querySelector("[data-ohw-editable]");
14213
15184
  if (textEditable) {
14214
15185
  activateRef.current(textEditable, {
@@ -14247,6 +15218,13 @@ function OhhwellsBridge() {
14247
15218
  selectFrameRef.current(navContainerToSelect);
14248
15219
  return;
14249
15220
  }
15221
+ const socialsRowToSelect = isSocialsRow(target) ? target : null;
15222
+ if (socialsRowToSelect && !getSocialItem(target)) {
15223
+ e.preventDefault();
15224
+ e.stopPropagation();
15225
+ selectFrameRef.current(socialsRowToSelect);
15226
+ return;
15227
+ }
14250
15228
  const footerColumnToSelect = resolveFooterColumnSelectionTarget(target, e.clientX, e.clientY);
14251
15229
  if (footerColumnToSelect) {
14252
15230
  e.preventDefault();
@@ -14298,6 +15276,7 @@ function OhhwellsBridge() {
14298
15276
  if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
14299
15277
  return;
14300
15278
  }
15279
+ if (getSocialItem(target)) return;
14301
15280
  const navLabel = getNavigationLabelEditable(target);
14302
15281
  const editable = navLabel?.editable ?? target.closest('[data-ohw-editable="text"], [data-ohw-editable="plain"]');
14303
15282
  if (!editable || isMediaEditable(editable) || editable.dataset.ohwEditable === "link") return;
@@ -14382,6 +15361,11 @@ function OhhwellsBridge() {
14382
15361
  const selected = selectedElRef.current;
14383
15362
  if (selected && (selected === editable || selected.contains(editable))) return;
14384
15363
  if (!isMediaEditable(editable) && !editable.hasAttribute("contenteditable")) {
15364
+ if (isIconEditable(editable) && !getSocialItem(editable)) {
15365
+ hoveredItemElRef.current = editable;
15366
+ setHoveredItemRect(editable.getBoundingClientRect());
15367
+ return;
15368
+ }
14385
15369
  const hoverTarget = editable.closest("[data-ohw-href-key]") ?? editable;
14386
15370
  if (hoverTarget.hasAttribute("data-ohw-href-key")) {
14387
15371
  clearHrefKeyHover(hoverTarget);
@@ -14429,6 +15413,13 @@ function OhhwellsBridge() {
14429
15413
  const related = e.relatedTarget instanceof Element ? e.relatedTarget : null;
14430
15414
  if (related?.closest("[data-ohw-drag-handle-container], [data-ohw-item-interaction]")) return;
14431
15415
  if (!isMediaEditable(editable)) {
15416
+ if (isIconEditable(editable) && !getSocialItem(editable) && hoveredItemElRef.current === editable) {
15417
+ if (!related?.closest("[data-ohw-item-interaction]")) {
15418
+ hoveredItemElRef.current = null;
15419
+ setHoveredItemRect(null);
15420
+ }
15421
+ return;
15422
+ }
14432
15423
  const hoverTarget = editable.closest("[data-ohw-href-key]") ?? editable;
14433
15424
  if (hoverTarget.hasAttribute("data-ohw-href-key")) {
14434
15425
  if (!related?.closest("[data-ohw-href-key]")) {
@@ -14710,15 +15701,15 @@ function OhhwellsBridge() {
14710
15701
  dismissImageHover();
14711
15702
  return;
14712
15703
  }
14713
- const ctaHit = isDragOver ? null : findCtaButtonAtPoint(x2, y2, imgEl);
14714
- if (ctaHit) {
15704
+ const buttonHit = isDragOver ? null : findButtonAtPoint(x2, y2, imgEl);
15705
+ if (buttonHit) {
14715
15706
  dismissImageHover();
14716
15707
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
14717
15708
  const selected = selectedElRef.current;
14718
- if (selected !== ctaHit && !selected?.contains(ctaHit)) {
14719
- clearHrefKeyHover(ctaHit);
14720
- hoveredItemElRef.current = ctaHit;
14721
- setHoveredItemRect(ctaHit.getBoundingClientRect());
15709
+ if (selected !== buttonHit && !selected?.contains(buttonHit)) {
15710
+ clearHrefKeyHover(buttonHit);
15711
+ hoveredItemElRef.current = buttonHit;
15712
+ setHoveredItemRect(buttonHit.getBoundingClientRect());
14722
15713
  }
14723
15714
  return;
14724
15715
  }
@@ -14977,7 +15968,7 @@ function OhhwellsBridge() {
14977
15968
  if (footerSession) {
14978
15969
  e.preventDefault();
14979
15970
  if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
14980
- const slot = footerSession.kind === "link" && footerSession.hrefKey ? hitTestLinkDropSlot(e.clientX, e.clientY, footerSession.hrefKey) : hitTestColumnDropSlot(e.clientX, e.clientY);
15971
+ const slot = footerSession.kind === "social" && footerSession.hrefKey ? hitTestSocialDropSlot(e.clientX, e.clientY, footerSession.hrefKey) : footerSession.kind === "link" && footerSession.hrefKey ? hitTestLinkDropSlot(e.clientX, e.clientY, footerSession.hrefKey) : hitTestColumnDropSlot(e.clientX, e.clientY);
14981
15972
  refreshFooterDragVisualsRef.current(footerSession, slot, e.clientX, e.clientY);
14982
15973
  return;
14983
15974
  }
@@ -15029,6 +16020,62 @@ function OhhwellsBridge() {
15029
16020
  resumeAnimTracks();
15030
16021
  clearImageHover();
15031
16022
  };
16023
+ const handleSocialCancel = (e) => {
16024
+ if (e.data?.type !== "ow:social-cancel") return;
16025
+ const { hrefKey } = e.data;
16026
+ const item = hrefKey ? findSocialByHrefKey(hrefKey) : null;
16027
+ if (!item) return;
16028
+ const removed = removeSocialItem(item, editContentRef.current);
16029
+ if (!removed) return;
16030
+ const orderJson = JSON.stringify(removed.order);
16031
+ editContentRef.current = { ...editContentRef.current, [SOCIALS_ORDER_KEY]: orderJson };
16032
+ postToParentRef.current({ type: "ow:change", nodes: [{ key: SOCIALS_ORDER_KEY, text: orderJson }] });
16033
+ deselectRef.current();
16034
+ };
16035
+ const handleSocialUpdate = (e) => {
16036
+ if (e.data?.type !== "ow:social-update") return;
16037
+ const updates = Array.isArray(e.data.items) ? e.data.items : [e.data];
16038
+ const nodes = [];
16039
+ for (const { hrefKey, iconKey, url, iconMarkup, platformId, label } of updates) {
16040
+ if (hrefKey) {
16041
+ document.querySelectorAll(`[data-ohw-href-key="${hrefKey}"]`).forEach((el) => applyLinkHref(el, url));
16042
+ nodes.push({ key: hrefKey, text: url });
16043
+ }
16044
+ if (iconKey && typeof iconMarkup === "string" && iconMarkup) {
16045
+ document.querySelectorAll(`[data-ohw-key="${iconKey}"][data-ohw-editable="icon"]`).forEach((el) => {
16046
+ applyIconMarkup(el, iconMarkup);
16047
+ });
16048
+ nodes.push({ key: iconKey, text: iconMarkup });
16049
+ }
16050
+ if (iconKey && platformId) nodes.push({ key: socialPlatformKey(iconKey), text: platformId });
16051
+ if (iconKey && label) {
16052
+ const labelKey = socialLabelKey(iconKey);
16053
+ document.querySelectorAll(`[data-ohw-key="${labelKey}"]`).forEach((el) => {
16054
+ el.textContent = label;
16055
+ });
16056
+ nodes.push({ key: labelKey, text: label });
16057
+ }
16058
+ }
16059
+ if (!nodes.length) return;
16060
+ editContentRef.current = {
16061
+ ...editContentRef.current,
16062
+ ...Object.fromEntries(nodes.map((node) => [node.key, node.text]))
16063
+ };
16064
+ postToParentRef.current({ type: "ow:change", nodes, flush: true });
16065
+ };
16066
+ const handleIconMarkup = (e) => {
16067
+ if (e.data?.type !== "ow:icon-markup") return;
16068
+ const { key, markup } = e.data;
16069
+ if (!key || typeof markup !== "string") return;
16070
+ const targets = document.querySelectorAll(
16071
+ `[data-ohw-key="${key}"][data-ohw-editable="icon"]`
16072
+ );
16073
+ if (!targets.length) return;
16074
+ targets.forEach((el) => {
16075
+ applyIconMarkup(el, markup);
16076
+ });
16077
+ postToParentRef.current({ type: "ow:change", nodes: [{ key, text: markup }], flush: true });
16078
+ };
15032
16079
  const handleImageUrl = (e) => {
15033
16080
  if (e.data?.type !== "ow:image-url") return;
15034
16081
  const { key, url } = e.data;
@@ -15192,6 +16239,7 @@ function OhhwellsBridge() {
15192
16239
  sectionsLoadedRef.current = true;
15193
16240
  pendingScheduleConfigRequests.current.splice(0).forEach(processConfigRequest);
15194
16241
  }
16242
+ initSectionInstancesFromContent(content, window.location.pathname);
15195
16243
  editContentRef.current = { ...editContentRef.current, ...content };
15196
16244
  reconcileNavbarItemsFromContent(editContentRef.current);
15197
16245
  reconcileFooterOrderFromContent(editContentRef.current);
@@ -15455,7 +16503,7 @@ function OhhwellsBridge() {
15455
16503
  }
15456
16504
  if (footerDragRef.current) {
15457
16505
  const session = footerDragRef.current;
15458
- const slot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : hitTestColumnDropSlot(session.lastClientX, session.lastClientY);
16506
+ const slot = session.kind === "social" && session.hrefKey ? hitTestSocialDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(session.lastClientX, session.lastClientY, session.hrefKey) : hitTestColumnDropSlot(session.lastClientX, session.lastClientY);
15459
16507
  refreshFooterDragVisualsRef.current(session, slot, session.lastClientX, session.lastClientY);
15460
16508
  }
15461
16509
  if (navDragRef.current) {
@@ -15775,6 +16823,9 @@ function OhhwellsBridge() {
15775
16823
  window.addEventListener("message", handleClearSchedulingWidget);
15776
16824
  window.addEventListener("message", handleRemoveSchedulingSection);
15777
16825
  window.addEventListener("message", handleCollectSection);
16826
+ window.addEventListener("message", handleSocialCancel);
16827
+ window.addEventListener("message", handleSocialUpdate);
16828
+ window.addEventListener("message", handleIconMarkup);
15778
16829
  window.addEventListener("message", handleImageUrl);
15779
16830
  window.addEventListener("message", handleImageUploading);
15780
16831
  window.addEventListener("message", handleCarouselChange);
@@ -15826,6 +16877,9 @@ function OhhwellsBridge() {
15826
16877
  window.removeEventListener("message", handleClearSchedulingWidget);
15827
16878
  window.removeEventListener("message", handleRemoveSchedulingSection);
15828
16879
  window.removeEventListener("message", handleCollectSection);
16880
+ window.removeEventListener("message", handleSocialCancel);
16881
+ window.removeEventListener("message", handleSocialUpdate);
16882
+ window.removeEventListener("message", handleIconMarkup);
15829
16883
  window.removeEventListener("message", handleImageUrl);
15830
16884
  window.removeEventListener("message", handleImageUploading);
15831
16885
  window.removeEventListener("message", handleCarouselChange);
@@ -15847,7 +16901,7 @@ function OhhwellsBridge() {
15847
16901
  if (imageShowTimerRef.current) clearTimeout(imageShowTimerRef.current);
15848
16902
  };
15849
16903
  }, [isEditMode, refreshStateRules]);
15850
- useEffect11(() => {
16904
+ useEffect12(() => {
15851
16905
  if (!isEditMode) return;
15852
16906
  const THRESHOLD = 10;
15853
16907
  const resolveWasSelected = (el) => {
@@ -15867,9 +16921,9 @@ function OhhwellsBridge() {
15867
16921
  return;
15868
16922
  }
15869
16923
  if (target.closest("[data-ohw-item-drag-surface]")) return;
15870
- const anchor = getNavigationItemAnchor(target);
16924
+ const anchor = getNavigationItemAnchor(target) ?? (document.elementsFromPoint(e.clientX, e.clientY).map((el) => el instanceof HTMLElement ? getNavigationItemAnchor(el) : null).find((found) => found !== null) ?? null);
15871
16925
  const hrefKey = anchor?.getAttribute("data-ohw-href-key") ?? null;
15872
- if (anchor && isFooterHrefKey(hrefKey)) {
16926
+ if (anchor && (isFooterHrefKey(hrefKey) || getSocialItem(anchor))) {
15873
16927
  footerPointerDragRef.current = {
15874
16928
  el: anchor,
15875
16929
  kind: "link",
@@ -15902,7 +16956,7 @@ function OhhwellsBridge() {
15902
16956
  clearTextSelection();
15903
16957
  const session = footerDragRef.current;
15904
16958
  if (!session) return;
15905
- const slot = session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(e.clientX, e.clientY, session.hrefKey) : hitTestColumnDropSlot(e.clientX, e.clientY);
16959
+ const slot = session.kind === "social" && session.hrefKey ? hitTestSocialDropSlot(e.clientX, e.clientY, session.hrefKey) : session.kind === "link" && session.hrefKey ? hitTestLinkDropSlot(e.clientX, e.clientY, session.hrefKey) : hitTestColumnDropSlot(e.clientX, e.clientY);
15906
16960
  refreshFooterDragVisualsRef.current(session, slot, e.clientX, e.clientY);
15907
16961
  return;
15908
16962
  }
@@ -15929,7 +16983,7 @@ function OhhwellsBridge() {
15929
16983
  const column = findFooterColumnForLink(pending.el);
15930
16984
  const columns2 = listFooterColumns();
15931
16985
  beginFooterDragRef.current({
15932
- kind: "link",
16986
+ kind: getSocialItem(pending.el) ? "social" : "link",
15933
16987
  hrefKey: key,
15934
16988
  columnEl: column,
15935
16989
  sourceColumnIndex: column ? columns2.indexOf(column) : 0,
@@ -16001,7 +17055,7 @@ function OhhwellsBridge() {
16001
17055
  unlockFooterDragInteraction();
16002
17056
  };
16003
17057
  }, [isEditMode]);
16004
- useEffect11(() => {
17058
+ useEffect12(() => {
16005
17059
  const handler = (e) => {
16006
17060
  if (e.data?.type !== "ow:request-schedule-config") return;
16007
17061
  const insertAfterVal = e.data.insertAfter;
@@ -16017,7 +17071,7 @@ function OhhwellsBridge() {
16017
17071
  window.addEventListener("message", handler);
16018
17072
  return () => window.removeEventListener("message", handler);
16019
17073
  }, [processConfigRequest]);
16020
- useEffect11(() => {
17074
+ useEffect12(() => {
16021
17075
  if (!isEditMode) return;
16022
17076
  document.querySelectorAll("[data-ohw-active-state]").forEach((el) => {
16023
17077
  el.removeAttribute("data-ohw-active-state");
@@ -16041,7 +17095,7 @@ function OhhwellsBridge() {
16041
17095
  postToParent2({
16042
17096
  type: "ow:ready",
16043
17097
  version: "1",
16044
- bridgeVersion: "0.1.54",
17098
+ bridgeVersion: "0.1.56",
16045
17099
  path: pathname,
16046
17100
  nodes: collectEditableNodes(editContentRef.current),
16047
17101
  sections
@@ -16053,13 +17107,13 @@ function OhhwellsBridge() {
16053
17107
  clearTimeout(timer);
16054
17108
  };
16055
17109
  }, [pathname, isEditMode, refreshStateRules, postToParent2]);
16056
- useEffect11(() => {
17110
+ useEffect12(() => {
16057
17111
  scrollToHashSectionWhenReady();
16058
17112
  const onHashChange = () => scrollToHashSectionWhenReady();
16059
17113
  window.addEventListener("hashchange", onHashChange);
16060
17114
  return () => window.removeEventListener("hashchange", onHashChange);
16061
17115
  }, [pathname]);
16062
- const handleCommand = useCallback6((cmd) => {
17116
+ const handleCommand = useCallback7((cmd) => {
16063
17117
  const el = activeElRef.current;
16064
17118
  const selBefore = window.getSelection();
16065
17119
  let savedOffsets = null;
@@ -16095,7 +17149,7 @@ function OhhwellsBridge() {
16095
17149
  if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
16096
17150
  refreshActiveCommandsRef.current();
16097
17151
  }, []);
16098
- const handleStateChange = useCallback6((state) => {
17152
+ const handleStateChange = useCallback7((state) => {
16099
17153
  if (!activeStateElRef.current) return;
16100
17154
  const el = activeStateElRef.current;
16101
17155
  if (state === "Default") {
@@ -16108,7 +17162,7 @@ function OhhwellsBridge() {
16108
17162
  }
16109
17163
  setToggleState((prev) => prev ? { ...prev, activeState: state } : null);
16110
17164
  }, [deactivate]);
16111
- const reselectAfterLinkPopover = useCallback6(
17165
+ const reselectAfterLinkPopover = useCallback7(
16112
17166
  (hrefKey) => {
16113
17167
  requestAnimationFrame(() => {
16114
17168
  const el = resolveHrefKeyElement(hrefKey);
@@ -16117,7 +17171,7 @@ function OhhwellsBridge() {
16117
17171
  },
16118
17172
  [resolveHrefKeyElement]
16119
17173
  );
16120
- const closeLinkPopover = useCallback6(() => {
17174
+ const closeLinkPopover = useCallback7(() => {
16121
17175
  const session = linkPopoverSessionRef.current;
16122
17176
  addNavAfterAnchorRef.current = null;
16123
17177
  setLinkPopover(null);
@@ -16125,9 +17179,9 @@ function OhhwellsBridge() {
16125
17179
  reselectAfterLinkPopover(session.key);
16126
17180
  }
16127
17181
  }, [reselectAfterLinkPopover]);
16128
- const closeLinkPopoverRef = useRef8(closeLinkPopover);
17182
+ const closeLinkPopoverRef = useRef9(closeLinkPopover);
16129
17183
  closeLinkPopoverRef.current = closeLinkPopover;
16130
- const openLinkPopoverForActive = useCallback6(() => {
17184
+ const openLinkPopoverForActive = useCallback7(() => {
16131
17185
  const hrefCtx = getHrefKeyFromElement(activeElRef.current);
16132
17186
  if (!hrefCtx) return;
16133
17187
  bumpLinkPopoverGrace();
@@ -16138,11 +17192,15 @@ function OhhwellsBridge() {
16138
17192
  });
16139
17193
  deactivate();
16140
17194
  }, [deactivate]);
16141
- const openLinkPopoverForSelected = useCallback6(() => {
17195
+ const openLinkPopoverForSelected = useCallback7(() => {
16142
17196
  const anchor = selectedElRef.current;
16143
17197
  if (!anchor) return;
16144
17198
  const key = anchor.getAttribute("data-ohw-href-key");
16145
17199
  if (!key) return;
17200
+ if (requestSocialDialog(anchor, postToParentRef.current, editContentRef.current)) {
17201
+ deselect();
17202
+ return;
17203
+ }
16146
17204
  bumpLinkPopoverGrace();
16147
17205
  setLinkPopover({
16148
17206
  key,
@@ -16151,7 +17209,7 @@ function OhhwellsBridge() {
16151
17209
  });
16152
17210
  deselect();
16153
17211
  }, [deselect]);
16154
- const handleSelectParent = useCallback6(() => {
17212
+ const handleSelectParent = useCallback7(() => {
16155
17213
  const selected = selectedElRef.current;
16156
17214
  if (!selected) return;
16157
17215
  if (toolbarVariantRef.current === "select-frame") {
@@ -16178,11 +17236,37 @@ function OhhwellsBridge() {
16178
17236
  }
16179
17237
  deselectRef.current();
16180
17238
  }, []);
16181
- const handleDuplicateSelected = useCallback6(() => {
17239
+ const handleDuplicateSelected = useCallback7(() => {
16182
17240
  const selected = selectedElRef.current;
16183
17241
  if (!selected || !isNavigationItem2(selected)) return;
16184
17242
  const hrefKey = selected.getAttribute("data-ohw-href-key");
16185
17243
  if (!hrefKey) return;
17244
+ const social = getSocialItem(selected);
17245
+ if (social) {
17246
+ const result = duplicateSocialItem(social, editContentRef.current);
17247
+ if (!result) return;
17248
+ const orderJson = JSON.stringify(result.order);
17249
+ const carried = [
17250
+ { from: result.copiedFrom?.href, to: result.hrefKey },
17251
+ { from: result.copiedFrom?.icon, to: result.iconKey },
17252
+ { from: result.copiedFrom?.icon ? socialPlatformKey(result.copiedFrom.icon) : null, to: socialPlatformKey(result.iconKey) }
17253
+ ];
17254
+ const nodes = [{ key: SOCIALS_ORDER_KEY, text: orderJson }];
17255
+ for (const { from, to } of carried) {
17256
+ const value = from ? editContentRef.current[from] : void 0;
17257
+ if (value) nodes.push({ key: to, text: value });
17258
+ }
17259
+ editContentRef.current = {
17260
+ ...editContentRef.current,
17261
+ ...Object.fromEntries(nodes.map((node) => [node.key, node.text]))
17262
+ };
17263
+ postToParent2({ type: "ow:change", nodes });
17264
+ enforceLinkHrefs();
17265
+ const copyRow = findSocialsRow(result.item);
17266
+ if (copyRow) applySocialsDisplayToRow(copyRow, socialsDisplayFor(copyRow, editContentRef.current));
17267
+ requestAnimationFrame(() => selectRef.current(result.item));
17268
+ return;
17269
+ }
16186
17270
  if (isNavbarHrefKey(hrefKey)) {
16187
17271
  const result = duplicateNavbarItem(selected);
16188
17272
  if (!result) return;
@@ -16268,7 +17352,7 @@ function OhhwellsBridge() {
16268
17352
  });
16269
17353
  }
16270
17354
  }, [postToParent2]);
16271
- const runPendingDeleteUndo = useCallback6(() => {
17355
+ const runPendingDeleteUndo = useCallback7(() => {
16272
17356
  const pending = pendingDeleteUndoRef.current;
16273
17357
  if (!pending) return false;
16274
17358
  pendingDeleteUndoRef.current = null;
@@ -16276,7 +17360,7 @@ function OhhwellsBridge() {
16276
17360
  enforceLinkHrefs();
16277
17361
  return true;
16278
17362
  }, []);
16279
- const handleDeleteSelected = useCallback6(() => {
17363
+ const handleDeleteSelected = useCallback7(() => {
16280
17364
  const selected = selectedElRef.current;
16281
17365
  if (!selected) return false;
16282
17366
  return deleteSelectedNavFooterItem({
@@ -16297,7 +17381,7 @@ function OhhwellsBridge() {
16297
17381
  }, [postToParent2]);
16298
17382
  handleDeleteSelectedRef.current = handleDeleteSelected;
16299
17383
  runPendingDeleteUndoRef.current = runPendingDeleteUndo;
16300
- const handleLinkPopoverSubmit = useCallback6(
17384
+ const handleLinkPopoverSubmit = useCallback7(
16301
17385
  (target) => {
16302
17386
  const session = linkPopoverSessionRef.current;
16303
17387
  if (!session) return;
@@ -16363,19 +17447,19 @@ function OhhwellsBridge() {
16363
17447
  const showEditLink = toolbarShowEditLink;
16364
17448
  const currentSections = sectionsByPath[pathname] ?? [];
16365
17449
  linkPopoverOpenRef.current = linkPopover !== null;
16366
- const handleMediaReplace = useCallback6(
17450
+ const handleMediaReplace = useCallback7(
16367
17451
  (key) => {
16368
17452
  postToParent2({ type: "ow:image-pick", key, elementType: mediaHover?.elementType ?? "image" });
16369
17453
  },
16370
17454
  [postToParent2, mediaHover?.elementType]
16371
17455
  );
16372
- const handleEditCarousel = useCallback6(
17456
+ const handleEditCarousel = useCallback7(
16373
17457
  (key) => {
16374
17458
  postToParent2({ type: "ow:carousel-open", key, images: readCarouselValue(key) });
16375
17459
  },
16376
17460
  [postToParent2]
16377
17461
  );
16378
- const handleMediaFadeOutComplete = useCallback6((key) => {
17462
+ const handleMediaFadeOutComplete = useCallback7((key) => {
16379
17463
  setUploadingRects((prev) => {
16380
17464
  if (!(key in prev)) return prev;
16381
17465
  const next = { ...prev };
@@ -16383,7 +17467,7 @@ function OhhwellsBridge() {
16383
17467
  return next;
16384
17468
  });
16385
17469
  }, []);
16386
- const handleVideoSettingsChange = useCallback6(
17470
+ const handleVideoSettingsChange = useCallback7(
16387
17471
  (key, settings) => {
16388
17472
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
16389
17473
  const video = getVideoEl2(el);
@@ -16406,10 +17490,10 @@ function OhhwellsBridge() {
16406
17490
  [postToParent2]
16407
17491
  );
16408
17492
  return bridgeRoot ? createPortal2(
16409
- /* @__PURE__ */ jsxs17(Fragment8, { children: [
16410
- /* @__PURE__ */ jsx30("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
16411
- isEditMode && /* @__PURE__ */ jsx30(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
16412
- Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ jsx30(
17493
+ /* @__PURE__ */ jsxs19(Fragment8, { children: [
17494
+ /* @__PURE__ */ jsx32("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
17495
+ isEditMode && /* @__PURE__ */ jsx32(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
17496
+ Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ jsx32(
16413
17497
  MediaOverlay,
16414
17498
  {
16415
17499
  hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
@@ -16420,7 +17504,7 @@ function OhhwellsBridge() {
16420
17504
  },
16421
17505
  `uploading-${key}`
16422
17506
  )),
16423
- mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ jsx30(
17507
+ mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ jsx32(
16424
17508
  MediaOverlay,
16425
17509
  {
16426
17510
  hover: mediaHover,
@@ -16429,11 +17513,11 @@ function OhhwellsBridge() {
16429
17513
  onVideoSettingsChange: handleVideoSettingsChange
16430
17514
  }
16431
17515
  ),
16432
- carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx30(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
16433
- siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ jsx30(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
16434
- siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ jsx30(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
16435
- isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ jsx30(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
16436
- isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ jsx30(
17516
+ carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx32(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
17517
+ siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ jsx32(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
17518
+ siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ jsx32(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
17519
+ isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ jsx32(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
17520
+ isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ jsx32(
16437
17521
  "div",
16438
17522
  {
16439
17523
  className: "pointer-events-none fixed z-2147483646",
@@ -16443,7 +17527,7 @@ function OhhwellsBridge() {
16443
17527
  width: slot.width,
16444
17528
  height: slot.height
16445
17529
  },
16446
- children: /* @__PURE__ */ jsx30(
17530
+ children: /* @__PURE__ */ jsx32(
16447
17531
  DropIndicator,
16448
17532
  {
16449
17533
  direction: slot.direction,
@@ -16454,7 +17538,7 @@ function OhhwellsBridge() {
16454
17538
  },
16455
17539
  `footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
16456
17540
  )),
16457
- isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ jsx30(
17541
+ isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ jsx32(
16458
17542
  "div",
16459
17543
  {
16460
17544
  className: "pointer-events-none fixed z-2147483646",
@@ -16464,7 +17548,7 @@ function OhhwellsBridge() {
16464
17548
  width: slot.width,
16465
17549
  height: slot.height
16466
17550
  },
16467
- children: /* @__PURE__ */ jsx30(
17551
+ children: /* @__PURE__ */ jsx32(
16468
17552
  DropIndicator,
16469
17553
  {
16470
17554
  direction: slot.direction,
@@ -16475,10 +17559,10 @@ function OhhwellsBridge() {
16475
17559
  },
16476
17560
  `nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
16477
17561
  )),
16478
- hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx30(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
16479
- hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx30(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
16480
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ jsx30(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
16481
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ jsx30(
17562
+ hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx32(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
17563
+ hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx32(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
17564
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ jsx32(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
17565
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ jsx32(
16482
17566
  FooterContainerChrome,
16483
17567
  {
16484
17568
  rect: toolbarRect,
@@ -16486,7 +17570,7 @@ function OhhwellsBridge() {
16486
17570
  addDisabled: !canAddFooterColumn()
16487
17571
  }
16488
17572
  ),
16489
- toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ jsx30(
17573
+ toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ jsx32(
16490
17574
  ItemInteractionLayer,
16491
17575
  {
16492
17576
  rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
@@ -16501,10 +17585,18 @@ function OhhwellsBridge() {
16501
17585
  onItemPointerDown: handleItemChromePointerDown,
16502
17586
  onItemClick: handleItemChromeClick,
16503
17587
  itemDragSurface: !isFooterFrameSelection,
16504
- toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && isFooterFrameSelection && !isItemDragging ? /* @__PURE__ */ jsx30(
17588
+ toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && (isFooterFrameSelection || selectedIsSocialsRow) && !isItemDragging ? /* @__PURE__ */ jsx32(
16505
17589
  ItemActionToolbar,
16506
17590
  {
16507
17591
  onEditLink: openLinkPopoverForSelected,
17592
+ onStyle: () => {
17593
+ const row = selectedElRef.current;
17594
+ if (!row) return;
17595
+ if (floatingPanel?.kind === "socials-display") closeFloatingPanelOnly();
17596
+ else openSocialsDisplayPanel(row);
17597
+ },
17598
+ showStyle: selectedIsSocialsRow,
17599
+ styleActive: floatingPanel?.kind === "socials-display",
16508
17600
  onAddItem: handleAddChildItem,
16509
17601
  onSelectParent: handleSelectParent,
16510
17602
  onDuplicate: handleDuplicateSelected,
@@ -16512,12 +17604,12 @@ function OhhwellsBridge() {
16512
17604
  addItemDisabled: false,
16513
17605
  editLinkDisabled: false,
16514
17606
  moreDisabled: false,
16515
- duplicateDisabled: isFooterFrameSelection,
16516
- showEditLink: !isFooterFrameSelection && navDropdownPreviewOpen === null,
16517
- showAddItem: isFooterFrameSelection || !selectedIsCta && Boolean(
17607
+ duplicateDisabled: isFooterFrameSelection || selectedIsSocialsRow,
17608
+ showEditLink: !isFooterFrameSelection && !selectedIsSocialsRow && navDropdownPreviewOpen === null,
17609
+ showAddItem: isFooterFrameSelection || selectedIsSocialsRow || !selectedIsCta && Boolean(
16518
17610
  selectedElRef.current && isNavbarHrefKey(selectedElRef.current.getAttribute("data-ohw-href-key")) && !isNestedNavChild(selectedElRef.current)
16519
17611
  ),
16520
- showMore: !selectedIsCta || isFooterFrameSelection,
17612
+ showMore: (!selectedIsCta || isFooterFrameSelection) && !selectedIsSocialsRow,
16521
17613
  dropdownOpen: navDropdownPreviewOpen,
16522
17614
  onDropdownOpenChange: handleNavDropdownOpenChange,
16523
17615
  headingVisible: footerHeadingVisible,
@@ -16526,8 +17618,8 @@ function OhhwellsBridge() {
16526
17618
  ) : void 0
16527
17619
  }
16528
17620
  ),
16529
- toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ jsxs17(Fragment8, { children: [
16530
- /* @__PURE__ */ jsx30(
17621
+ toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ jsxs19(Fragment8, { children: [
17622
+ /* @__PURE__ */ jsx32(
16531
17623
  EditGlowChrome,
16532
17624
  {
16533
17625
  rect: toolbarRect,
@@ -16537,7 +17629,7 @@ function OhhwellsBridge() {
16537
17629
  hideHandle: isItemDragging
16538
17630
  }
16539
17631
  ),
16540
- /* @__PURE__ */ jsx30(
17632
+ /* @__PURE__ */ jsx32(
16541
17633
  FloatingToolbar,
16542
17634
  {
16543
17635
  rect: toolbarRect,
@@ -16550,7 +17642,7 @@ function OhhwellsBridge() {
16550
17642
  }
16551
17643
  )
16552
17644
  ] }),
16553
- maxBadge && /* @__PURE__ */ jsxs17(
17645
+ maxBadge && /* @__PURE__ */ jsxs19(
16554
17646
  "div",
16555
17647
  {
16556
17648
  "data-ohw-max-badge": "",
@@ -16576,7 +17668,7 @@ function OhhwellsBridge() {
16576
17668
  ]
16577
17669
  }
16578
17670
  ),
16579
- toggleState && !linkPopover && /* @__PURE__ */ jsx30(
17671
+ toggleState && !linkPopover && /* @__PURE__ */ jsx32(
16580
17672
  StateToggle,
16581
17673
  {
16582
17674
  rect: toggleState.rect,
@@ -16585,15 +17677,15 @@ function OhhwellsBridge() {
16585
17677
  onStateChange: handleStateChange
16586
17678
  }
16587
17679
  ),
16588
- sectionGap && !linkPopover && /* @__PURE__ */ jsxs17(
17680
+ sectionGap && !linkPopover && /* @__PURE__ */ jsxs19(
16589
17681
  "div",
16590
17682
  {
16591
17683
  "data-ohw-section-insert-line": "",
16592
17684
  className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
16593
17685
  style: { top: sectionGap.y, transform: "translateY(-50%)" },
16594
17686
  children: [
16595
- /* @__PURE__ */ jsx30("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
16596
- /* @__PURE__ */ jsx30(
17687
+ /* @__PURE__ */ jsx32("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
17688
+ /* @__PURE__ */ jsx32(
16597
17689
  Badge,
16598
17690
  {
16599
17691
  className: "px-8 py-1 bg-primary hover:bg-primary text-primary-foreground text-xs font-medium shrink-0 rounded-full cursor-pointer pointer-events-auto",
@@ -16610,11 +17702,11 @@ function OhhwellsBridge() {
16610
17702
  children: "Add Section"
16611
17703
  }
16612
17704
  ),
16613
- /* @__PURE__ */ jsx30("div", { className: "flex-1 bg-primary", style: { height: 3 } })
17705
+ /* @__PURE__ */ jsx32("div", { className: "flex-1 bg-primary", style: { height: 3 } })
16614
17706
  ]
16615
17707
  }
16616
17708
  ),
16617
- linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx30(
17709
+ linkPopover && dialogPortalContainer ? /* @__PURE__ */ jsx32(
16618
17710
  LinkPopover,
16619
17711
  {
16620
17712
  panelRef: linkPopoverPanelRef,
@@ -16630,6 +17722,28 @@ function OhhwellsBridge() {
16630
17722
  onSubmit: handleLinkPopoverSubmit
16631
17723
  },
16632
17724
  linkPopover.key
17725
+ ) : null,
17726
+ floatingPanel && floatingPanel.kind === "socials-display" ? /* @__PURE__ */ jsx32(
17727
+ FloatingPanel,
17728
+ {
17729
+ open: true,
17730
+ title: floatingPanel.title,
17731
+ context: floatingPanel.context,
17732
+ position: floatingPanelPos,
17733
+ onPositionChange: setFloatingPanelPos,
17734
+ parentScroll: parentScrollSnap ?? parentScrollRef.current,
17735
+ onClose: closeFloatingPanelOnly,
17736
+ children: /* @__PURE__ */ jsx32(
17737
+ SocialsDisplayPanel,
17738
+ {
17739
+ display: socialsDisplayFor(floatingPanel.row, editContentRef.current),
17740
+ onChange: (next) => {
17741
+ changeSocialsDisplay(floatingPanel.row, next);
17742
+ setFloatingPanel({ ...floatingPanel });
17743
+ }
17744
+ }
17745
+ )
17746
+ }
16633
17747
  ) : null
16634
17748
  ] }),
16635
17749
  bridgeRoot