@ohhwells/bridge 0.1.71-next.216 → 0.1.71-next.218
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 +139 -39
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +225 -125
- package/dist/index.js.map +1 -1
- package/dist/social-glyphs.cjs +61 -0
- package/dist/social-glyphs.cjs.map +1 -0
- package/dist/social-glyphs.d.cts +30 -0
- package/dist/social-glyphs.d.ts +30 -0
- package/dist/social-glyphs.js +31 -0
- package/dist/social-glyphs.js.map +1 -0
- package/package.json +6 -1
package/dist/index.cjs
CHANGED
|
@@ -6791,6 +6791,7 @@ function ItemActionToolbar({
|
|
|
6791
6791
|
var import_react7 = require("react");
|
|
6792
6792
|
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
6793
6793
|
var PRIMARY = "var(--ohw-primary, #0885FE)";
|
|
6794
|
+
var CHROME_RADIUS = 6;
|
|
6794
6795
|
var FOCUS_RING = `0 0 0 4px color-mix(in srgb, ${PRIMARY} 12%, transparent)`;
|
|
6795
6796
|
var DRAG_SHADOW = "0px 4px 6px -1px rgba(0, 0, 0, 0.1), 0px 2px 4px -2px rgba(0, 0, 0, 0.1)";
|
|
6796
6797
|
var TOOLBAR_EDGE_MARGIN = 4;
|
|
@@ -6985,15 +6986,16 @@ function ItemInteractionLayer({
|
|
|
6985
6986
|
"div",
|
|
6986
6987
|
{
|
|
6987
6988
|
"aria-hidden": true,
|
|
6988
|
-
className: "absolute inset-0
|
|
6989
|
-
style: getChromeStyle(state)
|
|
6989
|
+
className: "absolute inset-0",
|
|
6990
|
+
style: { ...getChromeStyle(state), borderRadius: CHROME_RADIUS }
|
|
6990
6991
|
}
|
|
6991
6992
|
),
|
|
6992
6993
|
itemDragEnabled && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
6993
6994
|
"div",
|
|
6994
6995
|
{
|
|
6995
6996
|
"data-ohw-item-drag-surface": "",
|
|
6996
|
-
className: "pointer-events-auto absolute inset-0 cursor-text
|
|
6997
|
+
className: "pointer-events-auto absolute inset-0 cursor-text",
|
|
6998
|
+
style: { borderRadius: CHROME_RADIUS },
|
|
6997
6999
|
onPointerDown: (e) => {
|
|
6998
7000
|
if (e.button !== 0) return;
|
|
6999
7001
|
onItemPointerDown?.(e);
|
|
@@ -7745,6 +7747,15 @@ var SKELETON_CSS = `
|
|
|
7745
7747
|
animation: ohw-media-shimmer 1.4s infinite;
|
|
7746
7748
|
}
|
|
7747
7749
|
`;
|
|
7750
|
+
var REPLACE_BUTTON_INSET = 12;
|
|
7751
|
+
function replaceButtonMode(image, button) {
|
|
7752
|
+
if (!button.fullWidth || !button.height) return "none";
|
|
7753
|
+
const room = REPLACE_BUTTON_INSET * 2;
|
|
7754
|
+
if (image.height < button.height + room) return "none";
|
|
7755
|
+
if (image.width >= button.fullWidth + room) return "full";
|
|
7756
|
+
if (image.width >= button.height + room) return "icon";
|
|
7757
|
+
return "none";
|
|
7758
|
+
}
|
|
7748
7759
|
function MediaOverlay({
|
|
7749
7760
|
hover,
|
|
7750
7761
|
isUploading,
|
|
@@ -7762,6 +7773,19 @@ function MediaOverlay({
|
|
|
7762
7773
|
const showChrome = !selected || hovered;
|
|
7763
7774
|
const autoplay = hover.videoAutoplay ?? true;
|
|
7764
7775
|
const muted = hover.videoMuted ?? true;
|
|
7776
|
+
const probeRef = React8.useRef(null);
|
|
7777
|
+
const [buttonSize, setButtonSize] = React8.useState(null);
|
|
7778
|
+
React8.useLayoutEffect(() => {
|
|
7779
|
+
const probe = probeRef.current;
|
|
7780
|
+
if (!probe) return;
|
|
7781
|
+
const { width, height } = probe.getBoundingClientRect();
|
|
7782
|
+
if (!width || !height) return;
|
|
7783
|
+
setButtonSize(
|
|
7784
|
+
(prev) => prev && prev.fullWidth === width && prev.height === height ? prev : { fullWidth: width, height }
|
|
7785
|
+
);
|
|
7786
|
+
}, [isVideo]);
|
|
7787
|
+
const replaceLabel = isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image";
|
|
7788
|
+
const replaceMode = buttonSize ? replaceButtonMode({ width: rect.width, height: rect.height }, buttonSize) : "none";
|
|
7765
7789
|
const box = {
|
|
7766
7790
|
position: "fixed",
|
|
7767
7791
|
top: rect.top,
|
|
@@ -7851,7 +7875,7 @@ function MediaOverlay({
|
|
|
7851
7875
|
) : null;
|
|
7852
7876
|
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
|
|
7853
7877
|
settingsBar,
|
|
7854
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.
|
|
7878
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
7855
7879
|
"div",
|
|
7856
7880
|
{
|
|
7857
7881
|
"data-ohw-bridge": "",
|
|
@@ -7870,29 +7894,64 @@ function MediaOverlay({
|
|
|
7870
7894
|
background: selected ? "transparent" : "color-mix(in srgb, var(--color-primary) 20%, transparent)"
|
|
7871
7895
|
},
|
|
7872
7896
|
onClick: () => onSelect && !selected ? onSelect(hover.key) : onReplace(hover.key),
|
|
7873
|
-
children:
|
|
7874
|
-
|
|
7875
|
-
|
|
7876
|
-
|
|
7877
|
-
|
|
7878
|
-
|
|
7879
|
-
|
|
7880
|
-
|
|
7881
|
-
|
|
7882
|
-
|
|
7883
|
-
|
|
7884
|
-
|
|
7885
|
-
|
|
7886
|
-
|
|
7887
|
-
|
|
7888
|
-
|
|
7889
|
-
|
|
7890
|
-
|
|
7891
|
-
|
|
7892
|
-
|
|
7893
|
-
|
|
7894
|
-
|
|
7895
|
-
|
|
7897
|
+
children: [
|
|
7898
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
7899
|
+
Button,
|
|
7900
|
+
{
|
|
7901
|
+
ref: probeRef,
|
|
7902
|
+
"aria-hidden": true,
|
|
7903
|
+
tabIndex: -1,
|
|
7904
|
+
variant: "outline",
|
|
7905
|
+
size: "sm",
|
|
7906
|
+
className: "gap-1.5",
|
|
7907
|
+
style: {
|
|
7908
|
+
...OVERLAY_BUTTON_STYLE,
|
|
7909
|
+
position: "fixed",
|
|
7910
|
+
top: 0,
|
|
7911
|
+
left: 0,
|
|
7912
|
+
visibility: "hidden",
|
|
7913
|
+
pointerEvents: "none"
|
|
7914
|
+
},
|
|
7915
|
+
children: [
|
|
7916
|
+
isVideo ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.ImageIcon, { size: 14 }),
|
|
7917
|
+
replaceLabel
|
|
7918
|
+
]
|
|
7919
|
+
}
|
|
7920
|
+
),
|
|
7921
|
+
showChrome && replaceMode !== "none" && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
7922
|
+
Button,
|
|
7923
|
+
{
|
|
7924
|
+
"data-ohw-media-overlay": "",
|
|
7925
|
+
variant: "outline",
|
|
7926
|
+
size: "sm",
|
|
7927
|
+
"aria-label": replaceLabel,
|
|
7928
|
+
className: "gap-1.5 cursor-pointer hover:bg-background",
|
|
7929
|
+
style: {
|
|
7930
|
+
...OVERLAY_BUTTON_STYLE,
|
|
7931
|
+
// Icon-only is a square of the same height, so the pair can never differ vertically.
|
|
7932
|
+
// `minWidth` has to go too: the button's own size carries `min-w-[64px]`, and a
|
|
7933
|
+
// minimum beats a width — the square came out wider than the avatar it sat on.
|
|
7934
|
+
...replaceMode === "icon" && buttonSize ? {
|
|
7935
|
+
width: buttonSize.height,
|
|
7936
|
+
minWidth: buttonSize.height,
|
|
7937
|
+
padding: 0,
|
|
7938
|
+
justifyContent: "center"
|
|
7939
|
+
} : null,
|
|
7940
|
+
// Don't let Replace steal clicks when text (e.g. nav) sits on top of this media.
|
|
7941
|
+
pointerEvents: hover.hasTextOverlap ? "none" : "auto"
|
|
7942
|
+
},
|
|
7943
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
7944
|
+
onClick: (e) => {
|
|
7945
|
+
e.stopPropagation();
|
|
7946
|
+
onReplace(hover.key);
|
|
7947
|
+
},
|
|
7948
|
+
children: [
|
|
7949
|
+
isVideo ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.ImageIcon, { size: 14 }),
|
|
7950
|
+
replaceMode === "full" ? replaceLabel : null
|
|
7951
|
+
]
|
|
7952
|
+
}
|
|
7953
|
+
)
|
|
7954
|
+
]
|
|
7896
7955
|
}
|
|
7897
7956
|
)
|
|
7898
7957
|
] });
|
|
@@ -14882,9 +14941,21 @@ function getLinkHref4(el) {
|
|
|
14882
14941
|
const anchor = el instanceof HTMLAnchorElement ? el : el.querySelector("a");
|
|
14883
14942
|
return anchor?.getAttribute("href") ?? "";
|
|
14884
14943
|
}
|
|
14944
|
+
function normalizeLinkHref(value) {
|
|
14945
|
+
const href = value.trim();
|
|
14946
|
+
if (!href) return href;
|
|
14947
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(href)) return href;
|
|
14948
|
+
if (href.startsWith("/") || href.startsWith("#") || href.startsWith("?")) return href;
|
|
14949
|
+
if (!/^[^\s/]+\.[a-z]{2,}(?:[/:?#]|$)/i.test(href)) return href;
|
|
14950
|
+
return `https://${href}`;
|
|
14951
|
+
}
|
|
14952
|
+
function isPageFrameSection(el) {
|
|
14953
|
+
const id = el.dataset.ohwSection ?? "";
|
|
14954
|
+
return el.tagName === "FOOTER" || el.tagName === "HEADER" || Boolean(el.closest("footer")) || /(^|[-_])(footer|navbar)$/i.test(id);
|
|
14955
|
+
}
|
|
14885
14956
|
function applyLinkHref(el, val) {
|
|
14886
14957
|
const anchor = el instanceof HTMLAnchorElement ? el : el.querySelector("a");
|
|
14887
|
-
if (anchor) anchor.setAttribute("href", val);
|
|
14958
|
+
if (anchor) anchor.setAttribute("href", normalizeLinkHref(val));
|
|
14888
14959
|
}
|
|
14889
14960
|
function currentIconRef(el) {
|
|
14890
14961
|
const uploaded = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
@@ -15014,7 +15085,7 @@ function applyLinkByKey(key, val) {
|
|
|
15014
15085
|
});
|
|
15015
15086
|
const hrefAnchors = document.querySelectorAll(`[data-ohw-href-key="${key}"]`);
|
|
15016
15087
|
if (hrefAnchors.length > 0) {
|
|
15017
|
-
setStoredLinkHref(key, val);
|
|
15088
|
+
setStoredLinkHref(key, normalizeLinkHref(val));
|
|
15018
15089
|
hrefAnchors.forEach((el) => applyLinkHref(el, val));
|
|
15019
15090
|
}
|
|
15020
15091
|
}
|
|
@@ -15556,7 +15627,8 @@ function EditGlowChrome({
|
|
|
15556
15627
|
position: "absolute",
|
|
15557
15628
|
inset: 0,
|
|
15558
15629
|
border: "2px solid var(--ohw-primary, #0885FE)",
|
|
15559
|
-
|
|
15630
|
+
// Same radius as every other interaction frame — this one was drawing 8 (OHH-701/722).
|
|
15631
|
+
borderRadius: CHROME_RADIUS,
|
|
15560
15632
|
boxShadow: "0 0 0 4px color-mix(in srgb, var(--ohw-primary, #0885FE) 12%, transparent)",
|
|
15561
15633
|
pointerEvents: "none"
|
|
15562
15634
|
}
|
|
@@ -16300,7 +16372,8 @@ function OhhwellsBridge() {
|
|
|
16300
16372
|
const el = document.querySelector(
|
|
16301
16373
|
'[data-ohw-hovered]:not([contenteditable]):not([data-ohw-href-key]):not([data-ohw-editable="form"] *)'
|
|
16302
16374
|
);
|
|
16303
|
-
const
|
|
16375
|
+
const busy = el?.querySelector('[contenteditable="true"]') ?? null;
|
|
16376
|
+
const target = el && !el.closest("[data-ohw-href-key]") && !busy ? el : null;
|
|
16304
16377
|
if (!target) {
|
|
16305
16378
|
setHoveredTextRect(null);
|
|
16306
16379
|
return;
|
|
@@ -16311,7 +16384,10 @@ function OhhwellsBridge() {
|
|
|
16311
16384
|
const observer = new MutationObserver(sync);
|
|
16312
16385
|
observer.observe(document.documentElement, {
|
|
16313
16386
|
attributes: true,
|
|
16314
|
-
|
|
16387
|
+
// `contenteditable` too: the box is recomputed only when one of these changes, and a click
|
|
16388
|
+
// that opens an element for typing changes nothing else — so the frame measured a moment
|
|
16389
|
+
// earlier, while merely hovering, stayed on screen inside the solid one (OHH-762).
|
|
16390
|
+
attributeFilter: ["data-ohw-hovered", "contenteditable"],
|
|
16315
16391
|
subtree: true
|
|
16316
16392
|
});
|
|
16317
16393
|
return () => observer.disconnect();
|
|
@@ -16621,6 +16697,14 @@ function OhhwellsBridge() {
|
|
|
16621
16697
|
el.removeAttribute("data-ohw-hovered");
|
|
16622
16698
|
el.setAttribute("data-ohw-selected", "");
|
|
16623
16699
|
}, [clearSelectedAttr]);
|
|
16700
|
+
const isSelectedForHover = (0, import_react17.useCallback)((el) => {
|
|
16701
|
+
if (!el) return false;
|
|
16702
|
+
return [selectedElRef.current, activeElRef.current].some(
|
|
16703
|
+
(busy) => busy && (el === busy || busy.contains(el) || el.contains(busy))
|
|
16704
|
+
);
|
|
16705
|
+
}, []);
|
|
16706
|
+
const isSelectedForHoverRef = (0, import_react17.useRef)(isSelectedForHover);
|
|
16707
|
+
isSelectedForHoverRef.current = isSelectedForHover;
|
|
16624
16708
|
const resolveHrefKeyElement = (0, import_react17.useCallback)((hrefKey) => {
|
|
16625
16709
|
if (isFooterHrefKey(hrefKey)) {
|
|
16626
16710
|
return document.querySelector(
|
|
@@ -17538,6 +17622,12 @@ function OhhwellsBridge() {
|
|
|
17538
17622
|
);
|
|
17539
17623
|
const activate = (0, import_react17.useCallback)((el, options) => {
|
|
17540
17624
|
if (activeElRef.current === el) return;
|
|
17625
|
+
document.querySelectorAll("[data-ohw-hovered]").forEach((hovered) => {
|
|
17626
|
+
hovered.removeAttribute("data-ohw-hovered");
|
|
17627
|
+
});
|
|
17628
|
+
setHoveredTextRect(null);
|
|
17629
|
+
hoveredItemElRef.current = null;
|
|
17630
|
+
setHoveredItemRect(null);
|
|
17541
17631
|
if (isIconEditable(el)) {
|
|
17542
17632
|
const social = getSocialItem(el);
|
|
17543
17633
|
const words = social ? social.querySelector('[data-ohw-editable="text"], [data-ohw-editable="plain"]') : null;
|
|
@@ -18776,7 +18866,7 @@ function OhhwellsBridge() {
|
|
|
18776
18866
|
clearHrefKeyHover(hoverTarget);
|
|
18777
18867
|
hoveredItemElRef.current = hoverTarget;
|
|
18778
18868
|
setHoveredItemRect(hoverTarget.getBoundingClientRect());
|
|
18779
|
-
} else if (!isInsideNavigationItem(editable) &&
|
|
18869
|
+
} else if (!isInsideNavigationItem(editable) && !isSelectedForHoverRef.current(hoverTarget)) {
|
|
18780
18870
|
hoverTarget.setAttribute("data-ohw-hovered", "");
|
|
18781
18871
|
if (editable.closest("footer") || editable.closest('[data-ohw-section="footer"]')) {
|
|
18782
18872
|
hoveredNavContainerRef.current = null;
|
|
@@ -19236,7 +19326,7 @@ function OhhwellsBridge() {
|
|
|
19236
19326
|
showImageHover(imgEl, isDragOver, true);
|
|
19237
19327
|
}
|
|
19238
19328
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
19239
|
-
if (textEditable && !textEditable.closest("[data-ohw-href-key]")) {
|
|
19329
|
+
if (textEditable && !textEditable.closest("[data-ohw-href-key]") && !isSelectedForHoverRef.current(textEditable)) {
|
|
19240
19330
|
textEditable.setAttribute("data-ohw-hovered", "");
|
|
19241
19331
|
}
|
|
19242
19332
|
return;
|
|
@@ -19248,7 +19338,7 @@ function OhhwellsBridge() {
|
|
|
19248
19338
|
clearImageHover();
|
|
19249
19339
|
}
|
|
19250
19340
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
19251
|
-
if (textEditable && !textEditable.closest("[data-ohw-href-key]")) {
|
|
19341
|
+
if (textEditable && !textEditable.closest("[data-ohw-href-key]") && !isSelectedForHoverRef.current(textEditable)) {
|
|
19252
19342
|
textEditable.setAttribute("data-ohw-hovered", "");
|
|
19253
19343
|
}
|
|
19254
19344
|
return;
|
|
@@ -19322,7 +19412,7 @@ function OhhwellsBridge() {
|
|
|
19322
19412
|
hoveredItemElRef.current = navAnchor;
|
|
19323
19413
|
setHoveredItemRect(navAnchor.getBoundingClientRect());
|
|
19324
19414
|
}
|
|
19325
|
-
} else if (!textEl.closest("[data-ohw-href-key]")) {
|
|
19415
|
+
} else if (!textEl.closest("[data-ohw-href-key]") && !isSelectedForHoverRef.current(textEl)) {
|
|
19326
19416
|
hoveredItemElRef.current = null;
|
|
19327
19417
|
setHoveredItemRect(null);
|
|
19328
19418
|
textEl.setAttribute("data-ohw-hovered", "");
|
|
@@ -19418,7 +19508,7 @@ function OhhwellsBridge() {
|
|
|
19418
19508
|
const ZONE = 20;
|
|
19419
19509
|
for (let i = 0; i < sections.length; i++) {
|
|
19420
19510
|
const a = sections[i];
|
|
19421
|
-
if (a
|
|
19511
|
+
if (isPageFrameSection(a)) continue;
|
|
19422
19512
|
const b = sections[i + 1] ?? null;
|
|
19423
19513
|
const boundaryY = a.getBoundingClientRect().bottom;
|
|
19424
19514
|
if (Math.abs(y - boundaryY) <= ZONE) {
|
|
@@ -19910,9 +20000,10 @@ function OhhwellsBridge() {
|
|
|
19910
20000
|
const handleAiDeleteSection = (e) => {
|
|
19911
20001
|
if (e.data?.type !== "ow:ai-delete-section") return;
|
|
19912
20002
|
const sectionId = typeof e.data.sectionId === "string" ? e.data.sectionId : "";
|
|
19913
|
-
if (!sectionId
|
|
20003
|
+
if (!sectionId) return;
|
|
19914
20004
|
const exists = document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`);
|
|
19915
20005
|
if (!exists) return;
|
|
20006
|
+
if (isPageFrameSection(exists)) return;
|
|
19916
20007
|
clearInteractionChrome();
|
|
19917
20008
|
const previous = aiSectionsRef.current;
|
|
19918
20009
|
const nextState = deleteSectionFromState(parseAiSectionsState(previous), sectionId);
|
|
@@ -20653,6 +20744,15 @@ function OhhwellsBridge() {
|
|
|
20653
20744
|
if (visibleViewportRef.current) {
|
|
20654
20745
|
applyVisibleViewport(visibleViewportRef.current, parentScrollRef.current);
|
|
20655
20746
|
}
|
|
20747
|
+
handleScroll();
|
|
20748
|
+
document.querySelectorAll("[data-ohw-hovered]").forEach((hovered) => {
|
|
20749
|
+
hovered.removeAttribute("data-ohw-hovered");
|
|
20750
|
+
});
|
|
20751
|
+
setHoveredTextRect(null);
|
|
20752
|
+
hoveredItemElRef.current = null;
|
|
20753
|
+
setHoveredItemRect(null);
|
|
20754
|
+
hoveredNavContainerRef.current = null;
|
|
20755
|
+
setHoveredNavContainerRect(null);
|
|
20656
20756
|
};
|
|
20657
20757
|
window.addEventListener("resize", handleViewportResize, { passive: true });
|
|
20658
20758
|
document.addEventListener("click", handleClick, true);
|
|
@@ -20923,7 +21023,7 @@ function OhhwellsBridge() {
|
|
|
20923
21023
|
postToParent2({
|
|
20924
21024
|
type: "ow:ready",
|
|
20925
21025
|
version: "1",
|
|
20926
|
-
bridgeVersion: "0.1.71",
|
|
21026
|
+
bridgeVersion: "0.1.71-next.218",
|
|
20927
21027
|
path: pathname,
|
|
20928
21028
|
nodes: collectEditableNodes(editContentRef.current),
|
|
20929
21029
|
sections
|