@ohhwells/bridge 0.1.139-next.385 → 0.1.139-next.386

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -2479,6 +2479,49 @@ function socialHrefKey(item) {
2479
2479
  function socialIconKey(item) {
2480
2480
  return item.querySelector(ICON_SELECTOR)?.dataset.ohwKey ?? null;
2481
2481
  }
2482
+ var SOCIAL_PLATFORM_LABELS = {
2483
+ instagram: "Instagram",
2484
+ facebook: "Facebook",
2485
+ x: "X",
2486
+ twitter: "X",
2487
+ tiktok: "TikTok",
2488
+ youtube: "YouTube",
2489
+ linkedin: "LinkedIn",
2490
+ pinterest: "Pinterest",
2491
+ whatsapp: "WhatsApp",
2492
+ telegram: "Telegram",
2493
+ spotify: "Spotify",
2494
+ threads: "Threads",
2495
+ vimeo: "Vimeo",
2496
+ discord: "Discord",
2497
+ medium: "Medium",
2498
+ website: "Website"
2499
+ };
2500
+ function socialPlatformLabel(item, content) {
2501
+ const iconKey = socialIconKey(item);
2502
+ const chosen = iconKey ? (content[socialPlatformKey(iconKey)] ?? "").trim().toLowerCase() : "";
2503
+ if (chosen) return SOCIAL_PLATFORM_LABELS[chosen] ?? chosen.charAt(0).toUpperCase() + chosen.slice(1);
2504
+ const label = socialLabelElement(item);
2505
+ const words = label && !label.hasAttribute(SOCIALS_EMPTY_LABEL_ATTR) ? (label.textContent ?? "").replace(/\s+/g, " ").trim() : "";
2506
+ if (words) return words;
2507
+ const link = item.matches("a") ? item : item.querySelector("a");
2508
+ const aria = (link?.getAttribute("aria-label") ?? item.getAttribute("aria-label") ?? "").trim();
2509
+ if (aria) return aria;
2510
+ const href = (link?.getAttribute("href") ?? "").trim();
2511
+ if (/^https?:\/\//i.test(href)) {
2512
+ let host = "";
2513
+ try {
2514
+ host = new URL(href).hostname.replace(/^www\./i, "").toLowerCase();
2515
+ } catch {
2516
+ host = "";
2517
+ }
2518
+ if (host.includes("x.com") || host.includes("twitter.com")) return "X";
2519
+ for (const [id, name] of Object.entries(SOCIAL_PLATFORM_LABELS)) {
2520
+ if (host.includes(id)) return name;
2521
+ }
2522
+ }
2523
+ return "Social";
2524
+ }
2482
2525
  var SOCIALS_ORDER_KEY = "__ohw_socials_order";
2483
2526
  function fromMarkup(markup) {
2484
2527
  const holder = document.createElement("div");
@@ -25172,36 +25215,72 @@ function OhhwellsBridge() {
25172
25215
  const [selectedMedia, setSelectedMedia] = (0, import_react21.useState)(null);
25173
25216
  const selectedMediaElRef = (0, import_react21.useRef)(null);
25174
25217
  const mediaKeyDropTokenRef = (0, import_react21.useRef)(0);
25218
+ const selectedIconElRef = (0, import_react21.useRef)(null);
25219
+ const selectedSocialElRef = (0, import_react21.useRef)(null);
25220
+ const queueSectionKeyDrop = (0, import_react21.useCallback)((prev) => {
25221
+ const sectionEl = prev?.closest("[data-ohw-section]") ?? null;
25222
+ if (!sectionEl) return;
25223
+ const sectionInstanceId = instanceIdOf(movableUnit(sectionEl)) || null;
25224
+ if (!sectionInstanceId) return;
25225
+ const token = ++mediaKeyDropTokenRef.current;
25226
+ const onQueueDrained = (e) => {
25227
+ if (e.source !== window || e.data?.type !== "ow:media-key-drop" || e.data.token !== token) return;
25228
+ window.removeEventListener("message", onQueueDrained);
25229
+ if (aiSectionApiRef.current?.getSelectedId() !== sectionInstanceId) return;
25230
+ if (selectedMediaElRef.current || selectedIconElRef.current || selectedSocialElRef.current) return;
25231
+ postToParentRef.current({
25232
+ type: "ow:section-selected",
25233
+ sectionId: sectionEl.dataset.ohwSection ?? null,
25234
+ sectionLabel: sectionEl.dataset.ohwSectionLabel ?? titleCaseSectionId(sectionEl.dataset.ohwSection ?? ""),
25235
+ key: null
25236
+ });
25237
+ };
25238
+ window.addEventListener("message", onQueueDrained);
25239
+ window.postMessage({ type: "ow:media-key-drop", token }, "*");
25240
+ }, []);
25175
25241
  const clearMediaSelection = (0, import_react21.useCallback)(() => {
25176
25242
  const prev = selectedMediaElRef.current;
25177
25243
  selectedMediaElRef.current = null;
25178
25244
  setSelectedMedia(null);
25179
- const sectionEl = prev?.closest("[data-ohw-section]") ?? null;
25180
- if (sectionEl) {
25181
- const sectionInstanceId = instanceIdOf(movableUnit(sectionEl)) || null;
25182
- if (!sectionInstanceId) return;
25183
- const token = ++mediaKeyDropTokenRef.current;
25184
- const onQueueDrained = (e) => {
25185
- if (e.source !== window || e.data?.type !== "ow:media-key-drop" || e.data.token !== token) return;
25186
- window.removeEventListener("message", onQueueDrained);
25187
- if (aiSectionApiRef.current?.getSelectedId() !== sectionInstanceId) return;
25188
- if (selectedMediaElRef.current) return;
25189
- postToParentRef.current({
25190
- type: "ow:section-selected",
25191
- sectionId: sectionEl.dataset.ohwSection ?? null,
25192
- sectionLabel: sectionEl.dataset.ohwSectionLabel ?? titleCaseSectionId(sectionEl.dataset.ohwSection ?? ""),
25193
- key: null
25194
- });
25195
- };
25196
- window.addEventListener("message", onQueueDrained);
25197
- window.postMessage({ type: "ow:media-key-drop", token }, "*");
25198
- }
25199
- }, []);
25245
+ queueSectionKeyDrop(prev);
25246
+ }, [queueSectionKeyDrop]);
25200
25247
  const clearMediaSelectionRef = (0, import_react21.useRef)(clearMediaSelection);
25201
25248
  clearMediaSelectionRef.current = clearMediaSelection;
25249
+ const clearIconSelection = (0, import_react21.useCallback)(() => {
25250
+ const prev = selectedIconElRef.current;
25251
+ if (!prev) return;
25252
+ selectedIconElRef.current = null;
25253
+ queueSectionKeyDrop(prev);
25254
+ }, [queueSectionKeyDrop]);
25255
+ const clearIconSelectionRef = (0, import_react21.useRef)(clearIconSelection);
25256
+ clearIconSelectionRef.current = clearIconSelection;
25257
+ const clearSocialSelection = (0, import_react21.useCallback)(() => {
25258
+ const prev = selectedSocialElRef.current;
25259
+ if (!prev) return;
25260
+ selectedSocialElRef.current = null;
25261
+ queueSectionKeyDrop(prev);
25262
+ }, [queueSectionKeyDrop]);
25263
+ const clearSocialSelectionRef = (0, import_react21.useRef)(clearSocialSelection);
25264
+ clearSocialSelectionRef.current = clearSocialSelection;
25265
+ const selectIconElement = (0, import_react21.useCallback)((el) => {
25266
+ if (selectedMediaElRef.current) clearMediaSelectionRef.current();
25267
+ selectedIconElRef.current = el;
25268
+ const sectionEl = el.closest("[data-ohw-section]");
25269
+ aiSectionApiRef.current?.selectFromElement(el, { report: false });
25270
+ postToParentRef.current({
25271
+ type: "ow:section-selected",
25272
+ sectionId: sectionEl?.dataset.ohwSection ?? null,
25273
+ sectionLabel: sectionEl ? sectionEl.dataset.ohwSectionLabel ?? titleCaseSectionId(sectionEl.dataset.ohwSection ?? "") : null,
25274
+ key: el.dataset.ohwKey ?? null,
25275
+ keyLabel: "Icon"
25276
+ });
25277
+ }, []);
25278
+ const selectIconElementRef = (0, import_react21.useRef)(selectIconElement);
25279
+ selectIconElementRef.current = selectIconElement;
25202
25280
  const selectMediaElement = (0, import_react21.useCallback)((el) => {
25203
25281
  const r2 = el.getBoundingClientRect();
25204
25282
  const video = el.dataset.ohwEditable === "video" ? el.querySelector("video") : null;
25283
+ selectedIconElRef.current = null;
25205
25284
  selectedMediaElRef.current = el;
25206
25285
  setSelectedMedia({
25207
25286
  key: el.dataset.ohwKey ?? "",
@@ -25866,6 +25945,7 @@ function OhhwellsBridge() {
25866
25945
  selectedElRef.current = null;
25867
25946
  selectedHrefKeyRef.current = null;
25868
25947
  selectedFooterColAttrRef.current = null;
25948
+ clearSocialSelectionRef.current();
25869
25949
  setSelectedIsCta(false);
25870
25950
  setSelectedIsSocial(false);
25871
25951
  setSelectedIsSocialsRow(false);
@@ -26767,7 +26847,22 @@ function OhhwellsBridge() {
26767
26847
  const select = (0, import_react21.useCallback)((anchor) => {
26768
26848
  if (!isNavigationItem2(anchor)) return;
26769
26849
  if (activeElRef.current) deactivate();
26770
- aiSectionApiRef.current?.selectFromElement(anchor);
26850
+ clearSocialSelectionRef.current();
26851
+ const socialItem = getSocialItem(anchor);
26852
+ if (socialItem) {
26853
+ selectedSocialElRef.current = socialItem;
26854
+ const sectionEl = socialItem.closest("[data-ohw-section]");
26855
+ aiSectionApiRef.current?.selectFromElement(anchor, { report: false });
26856
+ postToParentRef.current({
26857
+ type: "ow:section-selected",
26858
+ sectionId: sectionEl?.dataset.ohwSection ?? null,
26859
+ sectionLabel: sectionEl ? sectionEl.dataset.ohwSectionLabel ?? titleCaseSectionId(sectionEl.dataset.ohwSection ?? "") : null,
26860
+ key: socialIconKey(socialItem) ?? socialItem.getAttribute("data-ohw-href-key"),
26861
+ keyLabel: socialPlatformLabel(socialItem, editContentRef.current)
26862
+ });
26863
+ } else {
26864
+ aiSectionApiRef.current?.selectFromElement(anchor);
26865
+ }
26771
26866
  selectedElRef.current = anchor;
26772
26867
  selectedHrefKeyRef.current = anchor.getAttribute("data-ohw-href-key");
26773
26868
  selectedFooterColAttrRef.current = null;
@@ -28076,6 +28171,9 @@ function OhhwellsBridge() {
28076
28171
  if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
28077
28172
  clearMediaSelectionRef.current();
28078
28173
  }
28174
+ if (selectedIconElRef.current && !selectedIconElRef.current.contains(target)) {
28175
+ clearIconSelectionRef.current();
28176
+ }
28079
28177
  if (selectedMediaElRef.current && target.closest("[data-ohw-media-overlay]") && !findClosestButtonLike(target)) {
28080
28178
  const hit = findImageAtPoint(e.clientX, e.clientY, false);
28081
28179
  if (hit && hit !== selectedMediaElRef.current) {
@@ -28246,9 +28344,13 @@ function OhhwellsBridge() {
28246
28344
  if (isIconEditable(editable) && !getSocialItem(editable)) {
28247
28345
  e.preventDefault();
28248
28346
  e.stopPropagation();
28249
- aiSectionApiRef.current?.selectFromElement(editable);
28250
28347
  const aiIcon = editable.hasAttribute("data-ai-icon");
28251
28348
  const featureIcon = aiIcon && /\.features\.\d+\.icon$/.test(editable.dataset.ohwKey ?? "");
28349
+ if (aiIcon) {
28350
+ aiSectionApiRef.current?.selectFromElement(editable);
28351
+ } else {
28352
+ selectIconElementRef.current(editable);
28353
+ }
28252
28354
  postToParentRef.current({
28253
28355
  type: "ow:icon-pick",
28254
28356
  key: editable.dataset.ohwKey ?? "",
@@ -29886,6 +29988,7 @@ function OhhwellsBridge() {
29886
29988
  deactivateRef.current();
29887
29989
  deselectRef.current();
29888
29990
  clearMediaSelectionRef.current();
29991
+ clearIconSelectionRef.current();
29889
29992
  };
29890
29993
  clearInteractionChromeRef.current = clearInteractionChrome;
29891
29994
  const applyTreeToLocalState = (payload) => {
@@ -30309,6 +30412,7 @@ function OhhwellsBridge() {
30309
30412
  deselectRef.current();
30310
30413
  deactivateRef.current();
30311
30414
  clearMediaSelectionRef.current();
30415
+ clearIconSelectionRef.current();
30312
30416
  };
30313
30417
  window.addEventListener("message", handleDeactivate);
30314
30418
  const handleToastAction = (e) => {
@@ -30398,6 +30502,10 @@ function OhhwellsBridge() {
30398
30502
  clearMediaSelectionRef.current();
30399
30503
  return;
30400
30504
  }
30505
+ if (e.key === "Escape" && selectedIconElRef.current) {
30506
+ clearIconSelectionRef.current();
30507
+ return;
30508
+ }
30401
30509
  if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a" && activeElRef.current) {
30402
30510
  e.preventDefault();
30403
30511
  selectAllTextInEditable(activeElRef.current);