@ohhwells/bridge 0.1.42-next.100 → 0.1.42-next.102
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 +118 -95
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +118 -95
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -7252,9 +7252,10 @@ function lockItemDuringDrag() {
|
|
|
7252
7252
|
clearTextSelection();
|
|
7253
7253
|
}
|
|
7254
7254
|
function unlockItemDragInteraction() {
|
|
7255
|
+
const wasDragging = document.documentElement.hasAttribute("data-ohw-item-dragging");
|
|
7255
7256
|
document.documentElement.removeAttribute("data-ohw-footer-press-drag");
|
|
7256
7257
|
document.documentElement.removeAttribute("data-ohw-item-dragging");
|
|
7257
|
-
clearTextSelection();
|
|
7258
|
+
if (wasDragging) clearTextSelection();
|
|
7258
7259
|
}
|
|
7259
7260
|
var armFooterPressDrag = armItemPressDrag;
|
|
7260
7261
|
var lockFooterDuringDrag = lockItemDuringDrag;
|
|
@@ -8569,9 +8570,16 @@ function sanitizeHtml(html) {
|
|
|
8569
8570
|
if (!SAFE_TAGS.has(el.tagName)) {
|
|
8570
8571
|
parent.replaceChild(document.createTextNode(el.textContent ?? ""), el);
|
|
8571
8572
|
} else {
|
|
8572
|
-
const
|
|
8573
|
+
const htmlEl = el;
|
|
8574
|
+
const textAlign = htmlEl.style?.textAlign || el.getAttribute("align") || "";
|
|
8575
|
+
const fontWeight = htmlEl.style?.fontWeight || "";
|
|
8576
|
+
const fontStyle = htmlEl.style?.fontStyle || "";
|
|
8577
|
+
const textDecorationLine = htmlEl.style?.textDecorationLine || htmlEl.style?.textDecoration || "";
|
|
8573
8578
|
for (const attr of Array.from(el.attributes)) el.removeAttribute(attr.name);
|
|
8574
|
-
if (textAlign)
|
|
8579
|
+
if (textAlign) htmlEl.style.textAlign = textAlign;
|
|
8580
|
+
if (fontWeight) htmlEl.style.fontWeight = fontWeight;
|
|
8581
|
+
if (fontStyle) htmlEl.style.fontStyle = fontStyle;
|
|
8582
|
+
if (textDecorationLine) htmlEl.style.textDecorationLine = textDecorationLine;
|
|
8575
8583
|
walk(el);
|
|
8576
8584
|
}
|
|
8577
8585
|
}
|
|
@@ -8759,6 +8767,79 @@ function resolveItemInteractionState(rect, parentScroll) {
|
|
|
8759
8767
|
const { transform } = calcToolbarPos(rect, parentScroll, 120);
|
|
8760
8768
|
return transform.includes("translateY(-100%)") ? "active-top" : "active-bottom";
|
|
8761
8769
|
}
|
|
8770
|
+
function resolveSelectionStartElement(sel) {
|
|
8771
|
+
if (!sel || sel.rangeCount === 0) return null;
|
|
8772
|
+
const range = sel.getRangeAt(0);
|
|
8773
|
+
let startNode = range.startContainer;
|
|
8774
|
+
if (startNode.nodeType === Node.ELEMENT_NODE) {
|
|
8775
|
+
const el = startNode;
|
|
8776
|
+
startNode = el.childNodes[range.startOffset] ?? el.childNodes[range.startOffset - 1] ?? el;
|
|
8777
|
+
}
|
|
8778
|
+
return startNode.nodeType === Node.TEXT_NODE ? startNode.parentElement : startNode;
|
|
8779
|
+
}
|
|
8780
|
+
function detectActiveFormats(startEl, activeRoot) {
|
|
8781
|
+
const formats = /* @__PURE__ */ new Set();
|
|
8782
|
+
const cs = getComputedStyle(startEl);
|
|
8783
|
+
const weight = parseInt(cs.fontWeight, 10);
|
|
8784
|
+
let hasBold = cs.fontWeight === "bold" || !Number.isNaN(weight) && weight >= 600;
|
|
8785
|
+
let hasItalic = cs.fontStyle === "italic" || cs.fontStyle === "oblique";
|
|
8786
|
+
let hasUnderline = false;
|
|
8787
|
+
let hasStrike = false;
|
|
8788
|
+
let hasUl = false;
|
|
8789
|
+
let hasOl = false;
|
|
8790
|
+
for (let el = startEl; el; el = el.parentElement) {
|
|
8791
|
+
if (el.tagName === "B" || el.tagName === "STRONG") hasBold = true;
|
|
8792
|
+
if (el.tagName === "I" || el.tagName === "EM") hasItalic = true;
|
|
8793
|
+
const decoration = getComputedStyle(el).textDecorationLine;
|
|
8794
|
+
if (decoration.includes("underline") || el.tagName === "U" || el.tagName === "INS") hasUnderline = true;
|
|
8795
|
+
if (decoration.includes("line-through") || el.tagName === "S" || el.tagName === "STRIKE" || el.tagName === "DEL") hasStrike = true;
|
|
8796
|
+
if (el.tagName === "UL") hasUl = true;
|
|
8797
|
+
if (el.tagName === "OL") hasOl = true;
|
|
8798
|
+
if (el === activeRoot) break;
|
|
8799
|
+
}
|
|
8800
|
+
if (hasBold) formats.add("bold");
|
|
8801
|
+
if (hasItalic) formats.add("italic");
|
|
8802
|
+
if (hasUnderline) formats.add("underline");
|
|
8803
|
+
if (hasStrike) formats.add("strikeThrough");
|
|
8804
|
+
if (hasUl) formats.add("insertUnorderedList");
|
|
8805
|
+
if (hasOl) formats.add("insertOrderedList");
|
|
8806
|
+
const block = startEl.closest("div, p, h1, h2, h3, h4, h5, h6, li, td, th") ?? startEl;
|
|
8807
|
+
const align = getComputedStyle(block).textAlign;
|
|
8808
|
+
if (align === "center") formats.add("justifyCenter");
|
|
8809
|
+
else if (align === "right" || align === "end") formats.add("justifyRight");
|
|
8810
|
+
else formats.add("justifyLeft");
|
|
8811
|
+
return formats;
|
|
8812
|
+
}
|
|
8813
|
+
function setsEqual(a, b) {
|
|
8814
|
+
if (a.size !== b.size) return false;
|
|
8815
|
+
for (const item of a) {
|
|
8816
|
+
if (!b.has(item)) return false;
|
|
8817
|
+
}
|
|
8818
|
+
return true;
|
|
8819
|
+
}
|
|
8820
|
+
function textOffsetInRoot(root, node, offset) {
|
|
8821
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
|
|
8822
|
+
let total = 0;
|
|
8823
|
+
let current;
|
|
8824
|
+
while (current = walker.nextNode()) {
|
|
8825
|
+
if (current === node) return total + offset;
|
|
8826
|
+
total += (current.textContent ?? "").length;
|
|
8827
|
+
}
|
|
8828
|
+
return total;
|
|
8829
|
+
}
|
|
8830
|
+
function pointAtTextOffset(root, targetOffset) {
|
|
8831
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
|
|
8832
|
+
let total = 0;
|
|
8833
|
+
let current;
|
|
8834
|
+
let last = null;
|
|
8835
|
+
while (current = walker.nextNode()) {
|
|
8836
|
+
const len = (current.textContent ?? "").length;
|
|
8837
|
+
if (total + len >= targetOffset) return { node: current, offset: targetOffset - total };
|
|
8838
|
+
total += len;
|
|
8839
|
+
last = current;
|
|
8840
|
+
}
|
|
8841
|
+
return last ? { node: last, offset: (last.textContent ?? "").length } : null;
|
|
8842
|
+
}
|
|
8762
8843
|
function FloatingToolbar({
|
|
8763
8844
|
rect,
|
|
8764
8845
|
parentScroll,
|
|
@@ -10230,15 +10311,6 @@ function OhhwellsBridge() {
|
|
|
10230
10311
|
e.stopPropagation();
|
|
10231
10312
|
const selection = window.getSelection();
|
|
10232
10313
|
const hasRangeSelection = Boolean(selection && !selection.isCollapsed);
|
|
10233
|
-
console.log(
|
|
10234
|
-
"[OHW DEBUG handleClick] already-active branch",
|
|
10235
|
-
"detail=",
|
|
10236
|
-
e.detail,
|
|
10237
|
-
"hasRangeSelection=",
|
|
10238
|
-
hasRangeSelection,
|
|
10239
|
-
"willPlaceCaret=",
|
|
10240
|
-
e.detail < 2 && !hasRangeSelection
|
|
10241
|
-
);
|
|
10242
10314
|
if (e.detail < 2 && !hasRangeSelection) {
|
|
10243
10315
|
placeCaretAtPoint(active, e.clientX, e.clientY);
|
|
10244
10316
|
refreshActiveCommandsRef.current();
|
|
@@ -10282,15 +10354,6 @@ function OhhwellsBridge() {
|
|
|
10282
10354
|
}
|
|
10283
10355
|
e.preventDefault();
|
|
10284
10356
|
e.stopPropagation();
|
|
10285
|
-
console.log(
|
|
10286
|
-
"[OHW DEBUG handleClick] first-activation branch",
|
|
10287
|
-
"detail=",
|
|
10288
|
-
e.detail,
|
|
10289
|
-
"selectionAtClick=",
|
|
10290
|
-
JSON.stringify(window.getSelection()?.toString() ?? ""),
|
|
10291
|
-
"collapsedAtClick=",
|
|
10292
|
-
window.getSelection()?.isCollapsed
|
|
10293
|
-
);
|
|
10294
10357
|
activateRef.current(editable);
|
|
10295
10358
|
return;
|
|
10296
10359
|
}
|
|
@@ -11406,62 +11469,9 @@ function OhhwellsBridge() {
|
|
|
11406
11469
|
selectionChangeRaf = null;
|
|
11407
11470
|
const activeRoot = activeElRef.current;
|
|
11408
11471
|
if (!activeRoot) return;
|
|
11409
|
-
const
|
|
11410
|
-
const
|
|
11411
|
-
|
|
11412
|
-
if (sel && sel.rangeCount > 0) {
|
|
11413
|
-
const range = sel.getRangeAt(0);
|
|
11414
|
-
startNode = range.startContainer;
|
|
11415
|
-
if (startNode.nodeType === Node.ELEMENT_NODE) {
|
|
11416
|
-
const el = startNode;
|
|
11417
|
-
startNode = el.childNodes[range.startOffset] ?? el.childNodes[range.startOffset - 1] ?? el;
|
|
11418
|
-
}
|
|
11419
|
-
}
|
|
11420
|
-
const startEl = startNode ? startNode.nodeType === Node.TEXT_NODE ? startNode.parentElement : startNode : null;
|
|
11421
|
-
if (startEl) {
|
|
11422
|
-
const cs = getComputedStyle(startEl);
|
|
11423
|
-
const weight = parseInt(cs.fontWeight, 10);
|
|
11424
|
-
let hasBold = cs.fontWeight === "bold" || !Number.isNaN(weight) && weight >= 600;
|
|
11425
|
-
let hasItalic = cs.fontStyle === "italic" || cs.fontStyle === "oblique";
|
|
11426
|
-
let hasUnderline = false;
|
|
11427
|
-
let hasStrike = false;
|
|
11428
|
-
let hasUl = false;
|
|
11429
|
-
let hasOl = false;
|
|
11430
|
-
for (let el = startEl; el; el = el.parentElement) {
|
|
11431
|
-
if (el.tagName === "B" || el.tagName === "STRONG") hasBold = true;
|
|
11432
|
-
if (el.tagName === "I" || el.tagName === "EM") hasItalic = true;
|
|
11433
|
-
const decoration = getComputedStyle(el).textDecorationLine;
|
|
11434
|
-
if (decoration.includes("underline") || el.tagName === "U" || el.tagName === "INS") hasUnderline = true;
|
|
11435
|
-
if (decoration.includes("line-through") || el.tagName === "S" || el.tagName === "STRIKE" || el.tagName === "DEL") hasStrike = true;
|
|
11436
|
-
if (el.tagName === "UL") hasUl = true;
|
|
11437
|
-
if (el.tagName === "OL") hasOl = true;
|
|
11438
|
-
if (el === activeRoot) break;
|
|
11439
|
-
}
|
|
11440
|
-
if (hasBold) next.add("bold");
|
|
11441
|
-
if (hasItalic) next.add("italic");
|
|
11442
|
-
if (hasUnderline) next.add("underline");
|
|
11443
|
-
if (hasStrike) next.add("strikeThrough");
|
|
11444
|
-
if (hasUl) next.add("insertUnorderedList");
|
|
11445
|
-
if (hasOl) next.add("insertOrderedList");
|
|
11446
|
-
const block = startEl.closest("div, p, h1, h2, h3, h4, h5, h6, li, td, th") ?? startEl;
|
|
11447
|
-
const align = getComputedStyle(block).textAlign;
|
|
11448
|
-
if (align === "center") next.add("justifyCenter");
|
|
11449
|
-
else if (align === "right" || align === "end") next.add("justifyRight");
|
|
11450
|
-
else next.add("justifyLeft");
|
|
11451
|
-
}
|
|
11452
|
-
setActiveCommands((prev) => {
|
|
11453
|
-
if (prev.size === next.size) {
|
|
11454
|
-
let same = true;
|
|
11455
|
-
for (const cmd of prev) {
|
|
11456
|
-
if (!next.has(cmd)) {
|
|
11457
|
-
same = false;
|
|
11458
|
-
break;
|
|
11459
|
-
}
|
|
11460
|
-
}
|
|
11461
|
-
if (same) return prev;
|
|
11462
|
-
}
|
|
11463
|
-
return next;
|
|
11464
|
-
});
|
|
11472
|
+
const startEl = resolveSelectionStartElement(window.getSelection());
|
|
11473
|
+
const next = startEl ? detectActiveFormats(startEl, activeRoot) : /* @__PURE__ */ new Set();
|
|
11474
|
+
setActiveCommands((prev) => setsEqual(prev, next) ? prev : next);
|
|
11465
11475
|
};
|
|
11466
11476
|
const handleSelectionChange = () => {
|
|
11467
11477
|
if (pointerHeldRef.current) return;
|
|
@@ -11848,22 +11858,6 @@ function OhhwellsBridge() {
|
|
|
11848
11858
|
unlockFooterDragInteraction();
|
|
11849
11859
|
};
|
|
11850
11860
|
}, [isEditMode]);
|
|
11851
|
-
(0, import_react9.useEffect)(() => {
|
|
11852
|
-
if (!isEditMode) return;
|
|
11853
|
-
const debugSelectionChange = () => {
|
|
11854
|
-
const sel = window.getSelection();
|
|
11855
|
-
console.log(
|
|
11856
|
-
"[OHW DEBUG selectionchange]",
|
|
11857
|
-
JSON.stringify(sel?.toString() ?? ""),
|
|
11858
|
-
"collapsed=",
|
|
11859
|
-
sel?.isCollapsed,
|
|
11860
|
-
"anchorNode=",
|
|
11861
|
-
sel?.anchorNode,
|
|
11862
|
-
"activeEl=",
|
|
11863
|
-
activeElRef.current
|
|
11864
|
-
);
|
|
11865
|
-
};
|
|
11866
|
-
}, [isEditMode]);
|
|
11867
11861
|
(0, import_react9.useEffect)(() => {
|
|
11868
11862
|
const handler = (e) => {
|
|
11869
11863
|
if (e.data?.type !== "ow:request-schedule-config") return;
|
|
@@ -11922,10 +11916,39 @@ function OhhwellsBridge() {
|
|
|
11922
11916
|
return () => window.removeEventListener("hashchange", onHashChange);
|
|
11923
11917
|
}, [pathname]);
|
|
11924
11918
|
const handleCommand = (0, import_react9.useCallback)((cmd) => {
|
|
11919
|
+
const el = activeElRef.current;
|
|
11920
|
+
const selBefore = window.getSelection();
|
|
11921
|
+
let savedOffsets = null;
|
|
11922
|
+
if (el && selBefore && selBefore.rangeCount > 0 && !selBefore.isCollapsed) {
|
|
11923
|
+
const r2 = selBefore.getRangeAt(0);
|
|
11924
|
+
if (el.contains(r2.commonAncestorContainer)) {
|
|
11925
|
+
savedOffsets = {
|
|
11926
|
+
start: textOffsetInRoot(el, r2.startContainer, r2.startOffset),
|
|
11927
|
+
end: textOffsetInRoot(el, r2.endContainer, r2.endOffset)
|
|
11928
|
+
};
|
|
11929
|
+
}
|
|
11930
|
+
}
|
|
11925
11931
|
document.execCommand("styleWithCSS", false, true);
|
|
11926
11932
|
document.execCommand(cmd, false);
|
|
11927
|
-
|
|
11928
|
-
|
|
11933
|
+
if (el && document.activeElement !== el) {
|
|
11934
|
+
el.focus();
|
|
11935
|
+
}
|
|
11936
|
+
const selAfter = window.getSelection();
|
|
11937
|
+
if (el && savedOffsets && selAfter?.isCollapsed) {
|
|
11938
|
+
const start = pointAtTextOffset(el, savedOffsets.start);
|
|
11939
|
+
const end = pointAtTextOffset(el, savedOffsets.end);
|
|
11940
|
+
if (start && end) {
|
|
11941
|
+
try {
|
|
11942
|
+
const range = document.createRange();
|
|
11943
|
+
range.setStart(start.node, start.offset);
|
|
11944
|
+
range.setEnd(end.node, end.offset);
|
|
11945
|
+
selAfter.removeAllRanges();
|
|
11946
|
+
selAfter.addRange(range);
|
|
11947
|
+
} catch {
|
|
11948
|
+
}
|
|
11949
|
+
}
|
|
11950
|
+
}
|
|
11951
|
+
if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
|
|
11929
11952
|
refreshActiveCommandsRef.current();
|
|
11930
11953
|
}, []);
|
|
11931
11954
|
const handleStateChange = (0, import_react9.useCallback)((state) => {
|