@trafica/editor 1.0.44 → 1.0.46
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 +217 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +217 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2201,6 +2201,10 @@ function mergeAtCursor(state, pastedDoc, sel) {
|
|
|
2201
2201
|
const lastIdx = mergedDoc.children.length - 1;
|
|
2202
2202
|
return { mergedDoc, cursorPos: endOfBlock(mergedDoc.children[lastIdx], lastIdx) };
|
|
2203
2203
|
}
|
|
2204
|
+
const LIST_CONTAINERS = /* @__PURE__ */ new Set(["bullet_list", "ordered_list", "check_list"]);
|
|
2205
|
+
if (LIST_CONTAINERS.has(currentBlock.type) && relPath.length > 0) {
|
|
2206
|
+
return mergeIntoListContainer(state, pasted, existingBlocks, blockIdx, currentBlock, relPath, charOffset);
|
|
2207
|
+
}
|
|
2204
2208
|
const [beforeChildren, afterChildren] = splitBlockChildren(currentBlock, relPath, charOffset);
|
|
2205
2209
|
let newBlocks;
|
|
2206
2210
|
let cursorBlockOffset;
|
|
@@ -2258,6 +2262,85 @@ function mergeAtCursor(state, pastedDoc, sel) {
|
|
|
2258
2262
|
cursorPos: cursorInBlock
|
|
2259
2263
|
};
|
|
2260
2264
|
}
|
|
2265
|
+
function mergeIntoListContainer(state, pasted, existingBlocks, blockIdx, listBlock, relPath, charOffset) {
|
|
2266
|
+
var _a, _b, _c, _d, _e;
|
|
2267
|
+
const itemIdx = relPath[0];
|
|
2268
|
+
const itemRelPath = relPath.slice(1);
|
|
2269
|
+
const listItems = listBlock.children;
|
|
2270
|
+
const currentItem = listItems[itemIdx];
|
|
2271
|
+
const isCheckList = listBlock.type === "check_list";
|
|
2272
|
+
const itemType = isCheckList ? "check_list_item" : "list_item";
|
|
2273
|
+
if (!currentItem) {
|
|
2274
|
+
const newBlocks = [...existingBlocks, ...pasted];
|
|
2275
|
+
const lastIdx = newBlocks.length - 1;
|
|
2276
|
+
return {
|
|
2277
|
+
mergedDoc: { ...state.doc, children: newBlocks },
|
|
2278
|
+
cursorPos: endOfBlock(newBlocks[lastIdx], lastIdx)
|
|
2279
|
+
};
|
|
2280
|
+
}
|
|
2281
|
+
const [beforeChildren, afterChildren] = splitBlockChildren(currentItem, itemRelPath, charOffset);
|
|
2282
|
+
const makeItem = (children) => ({
|
|
2283
|
+
type: itemType,
|
|
2284
|
+
attrs: isCheckList ? { checked: false } : {},
|
|
2285
|
+
children: children.length > 0 ? children : [{ type: "text", text: "", marks: [] }]
|
|
2286
|
+
});
|
|
2287
|
+
let newItems;
|
|
2288
|
+
let cursorItemIdx;
|
|
2289
|
+
if (pasted.length === 1) {
|
|
2290
|
+
const pastedChildren = (_a = pasted[0].children) != null ? _a : [];
|
|
2291
|
+
const merged = [...beforeChildren, ...pastedChildren, ...afterChildren];
|
|
2292
|
+
newItems = [
|
|
2293
|
+
...listItems.slice(0, itemIdx),
|
|
2294
|
+
{ ...currentItem, children: merged.length > 0 ? merged : [{ type: "text", text: "", marks: [] }] },
|
|
2295
|
+
...listItems.slice(itemIdx + 1)
|
|
2296
|
+
];
|
|
2297
|
+
cursorItemIdx = itemIdx;
|
|
2298
|
+
} else {
|
|
2299
|
+
const firstPasted = pasted[0];
|
|
2300
|
+
const lastPasted = pasted[pasted.length - 1];
|
|
2301
|
+
const middlePasted = pasted.slice(1, -1);
|
|
2302
|
+
const firstItem = { ...currentItem, children: [...beforeChildren, ...(_b = firstPasted.children) != null ? _b : []] };
|
|
2303
|
+
const lastItem = makeItem([...(_c = lastPasted.children) != null ? _c : [], ...afterChildren]);
|
|
2304
|
+
const midItems = middlePasted.map((p) => {
|
|
2305
|
+
var _a2;
|
|
2306
|
+
return makeItem((_a2 = p.children) != null ? _a2 : []);
|
|
2307
|
+
});
|
|
2308
|
+
newItems = [
|
|
2309
|
+
...listItems.slice(0, itemIdx),
|
|
2310
|
+
firstItem,
|
|
2311
|
+
...midItems,
|
|
2312
|
+
lastItem,
|
|
2313
|
+
...listItems.slice(itemIdx + 1)
|
|
2314
|
+
];
|
|
2315
|
+
cursorItemIdx = itemIdx + 1 + midItems.length;
|
|
2316
|
+
}
|
|
2317
|
+
const newList = { ...listBlock, children: newItems };
|
|
2318
|
+
const mergedBlocks = [
|
|
2319
|
+
...existingBlocks.slice(0, blockIdx),
|
|
2320
|
+
newList,
|
|
2321
|
+
...existingBlocks.slice(blockIdx + 1)
|
|
2322
|
+
];
|
|
2323
|
+
const targetItem = newItems[cursorItemIdx];
|
|
2324
|
+
let cursorPos;
|
|
2325
|
+
if (pasted.length === 1) {
|
|
2326
|
+
const pastedChildren = (_d = pasted[0].children) != null ? _d : [];
|
|
2327
|
+
const cursorChildIdx = beforeChildren.length + pastedChildren.length;
|
|
2328
|
+
const nodeBefore = targetItem == null ? void 0 : targetItem.children[cursorChildIdx - 1];
|
|
2329
|
+
cursorPos = nodeBefore && isTextNode(nodeBefore) ? { path: [blockIdx, cursorItemIdx, cursorChildIdx - 1], offset: nodeBefore.text.length } : { path: [blockIdx, cursorItemIdx], offset: 0 };
|
|
2330
|
+
} else {
|
|
2331
|
+
const lpChildren = (_e = pasted[pasted.length - 1].children) != null ? _e : [];
|
|
2332
|
+
if (lpChildren.length > 0) {
|
|
2333
|
+
const lastNode = lpChildren[lpChildren.length - 1];
|
|
2334
|
+
cursorPos = {
|
|
2335
|
+
path: [blockIdx, cursorItemIdx, lpChildren.length - 1],
|
|
2336
|
+
offset: isTextNode(lastNode) ? lastNode.text.length : 0
|
|
2337
|
+
};
|
|
2338
|
+
} else {
|
|
2339
|
+
cursorPos = { path: [blockIdx, cursorItemIdx], offset: 0 };
|
|
2340
|
+
}
|
|
2341
|
+
}
|
|
2342
|
+
return { mergedDoc: { ...state.doc, children: mergedBlocks }, cursorPos };
|
|
2343
|
+
}
|
|
2261
2344
|
function splitBlockChildren(block, relPath, offset) {
|
|
2262
2345
|
const children = block.children;
|
|
2263
2346
|
if (children.length === 0) return [[], []];
|
|
@@ -7951,6 +8034,7 @@ function EditorCore({
|
|
|
7951
8034
|
const isComposingRef = useRef(false);
|
|
7952
8035
|
const stateRef = useRef(engine.getState());
|
|
7953
8036
|
const [selectedImagePath, setSelectedImagePath] = useState(null);
|
|
8037
|
+
const [imageDragState, setImageDragState] = useState(null);
|
|
7954
8038
|
const [findReplaceOpen, setFindReplaceOpen] = useState(false);
|
|
7955
8039
|
const [findReplaceMode, setFindReplaceMode] = useState("find");
|
|
7956
8040
|
const [linkPopupOpen, setLinkPopupOpen] = useState(false);
|
|
@@ -8431,7 +8515,21 @@ function EditorCore({
|
|
|
8431
8515
|
const fig = target.closest("[data-image-path]");
|
|
8432
8516
|
if (fig == null ? void 0 : fig.dataset.imagePath) {
|
|
8433
8517
|
e.preventDefault();
|
|
8434
|
-
|
|
8518
|
+
const path = JSON.parse(fig.dataset.imagePath);
|
|
8519
|
+
setSelectedImagePath(path);
|
|
8520
|
+
if (path.length === 1) {
|
|
8521
|
+
const imgEl = fig.querySelector("img");
|
|
8522
|
+
const rect = imgEl == null ? void 0 : imgEl.getBoundingClientRect();
|
|
8523
|
+
imageDragRef.current = {
|
|
8524
|
+
imagePath: path,
|
|
8525
|
+
startX: e.clientX,
|
|
8526
|
+
startY: e.clientY,
|
|
8527
|
+
active: false,
|
|
8528
|
+
ghostW: Math.min((rect == null ? void 0 : rect.width) || 300, 320),
|
|
8529
|
+
ghostH: Math.min((rect == null ? void 0 : rect.height) || 200, 200),
|
|
8530
|
+
ghostSrc: (imgEl == null ? void 0 : imgEl.src) || ""
|
|
8531
|
+
};
|
|
8532
|
+
}
|
|
8435
8533
|
return;
|
|
8436
8534
|
}
|
|
8437
8535
|
setSelectedImagePath(null);
|
|
@@ -8484,6 +8582,7 @@ function EditorCore({
|
|
|
8484
8582
|
engine.dispatch(tr);
|
|
8485
8583
|
}, [engine]);
|
|
8486
8584
|
const imageResizeRef = useRef(null);
|
|
8585
|
+
const imageDragRef = useRef(null);
|
|
8487
8586
|
useEffect(() => {
|
|
8488
8587
|
const onMouseMove = (e) => {
|
|
8489
8588
|
const drag = imageResizeRef.current;
|
|
@@ -8516,6 +8615,48 @@ function EditorCore({
|
|
|
8516
8615
|
document.removeEventListener("mouseup", onMouseUp);
|
|
8517
8616
|
};
|
|
8518
8617
|
}, [engine]);
|
|
8618
|
+
useEffect(() => {
|
|
8619
|
+
const DRAG_THRESHOLD = 6;
|
|
8620
|
+
const onMouseMove = (e) => {
|
|
8621
|
+
const drag = imageDragRef.current;
|
|
8622
|
+
if (!drag) return;
|
|
8623
|
+
const dx = e.clientX - drag.startX;
|
|
8624
|
+
const dy = e.clientY - drag.startY;
|
|
8625
|
+
if (!drag.active && Math.sqrt(dx * dx + dy * dy) < DRAG_THRESHOLD) return;
|
|
8626
|
+
drag.active = true;
|
|
8627
|
+
const container = containerRef.current;
|
|
8628
|
+
const { dropIndex, indicatorClientY } = getImageDropTarget(container, e.clientY, drag.imagePath);
|
|
8629
|
+
setImageDragState({
|
|
8630
|
+
ghostX: e.clientX,
|
|
8631
|
+
ghostY: e.clientY,
|
|
8632
|
+
ghostW: drag.ghostW,
|
|
8633
|
+
ghostH: drag.ghostH,
|
|
8634
|
+
ghostSrc: drag.ghostSrc,
|
|
8635
|
+
dropIndicatorClientY: indicatorClientY,
|
|
8636
|
+
dropIndex,
|
|
8637
|
+
imagePath: drag.imagePath
|
|
8638
|
+
});
|
|
8639
|
+
};
|
|
8640
|
+
const onMouseUp = (e) => {
|
|
8641
|
+
const drag = imageDragRef.current;
|
|
8642
|
+
if (!drag) return;
|
|
8643
|
+
imageDragRef.current = null;
|
|
8644
|
+
if (!drag.active) {
|
|
8645
|
+
setImageDragState(null);
|
|
8646
|
+
return;
|
|
8647
|
+
}
|
|
8648
|
+
const container = containerRef.current;
|
|
8649
|
+
const { dropIndex } = getImageDropTarget(container, e.clientY, drag.imagePath);
|
|
8650
|
+
setImageDragState(null);
|
|
8651
|
+
moveImageInDoc(drag.imagePath, dropIndex, engine);
|
|
8652
|
+
};
|
|
8653
|
+
document.addEventListener("mousemove", onMouseMove);
|
|
8654
|
+
document.addEventListener("mouseup", onMouseUp);
|
|
8655
|
+
return () => {
|
|
8656
|
+
document.removeEventListener("mousemove", onMouseMove);
|
|
8657
|
+
document.removeEventListener("mouseup", onMouseUp);
|
|
8658
|
+
};
|
|
8659
|
+
}, [engine]);
|
|
8519
8660
|
useEffect(() => {
|
|
8520
8661
|
const container = containerRef.current;
|
|
8521
8662
|
if (!container) return;
|
|
@@ -8633,6 +8774,19 @@ function EditorCore({
|
|
|
8633
8774
|
].join(" ")
|
|
8634
8775
|
}
|
|
8635
8776
|
),
|
|
8777
|
+
imageDragState && (() => {
|
|
8778
|
+
const container = containerRef.current;
|
|
8779
|
+
if (!container) return null;
|
|
8780
|
+
const cr = container.getBoundingClientRect();
|
|
8781
|
+
const relY = imageDragState.dropIndicatorClientY - cr.top + container.scrollTop;
|
|
8782
|
+
return /* @__PURE__ */ jsx(
|
|
8783
|
+
"div",
|
|
8784
|
+
{
|
|
8785
|
+
className: "editor-image-drop-indicator",
|
|
8786
|
+
style: { top: relY }
|
|
8787
|
+
}
|
|
8788
|
+
);
|
|
8789
|
+
})(),
|
|
8636
8790
|
linkTooltip && /* @__PURE__ */ jsxs(
|
|
8637
8791
|
"div",
|
|
8638
8792
|
{
|
|
@@ -8693,6 +8847,26 @@ function EditorCore({
|
|
|
8693
8847
|
onClose: () => setSelectedImagePath(null)
|
|
8694
8848
|
}
|
|
8695
8849
|
),
|
|
8850
|
+
imageDragState && /* @__PURE__ */ jsx(
|
|
8851
|
+
"div",
|
|
8852
|
+
{
|
|
8853
|
+
className: "editor-image-drag-ghost",
|
|
8854
|
+
style: {
|
|
8855
|
+
left: imageDragState.ghostX,
|
|
8856
|
+
top: imageDragState.ghostY,
|
|
8857
|
+
width: imageDragState.ghostW,
|
|
8858
|
+
height: imageDragState.ghostH
|
|
8859
|
+
},
|
|
8860
|
+
children: /* @__PURE__ */ jsx(
|
|
8861
|
+
"img",
|
|
8862
|
+
{
|
|
8863
|
+
src: imageDragState.ghostSrc,
|
|
8864
|
+
alt: "",
|
|
8865
|
+
style: { width: "100%", height: "100%", objectFit: "contain", display: "block" }
|
|
8866
|
+
}
|
|
8867
|
+
)
|
|
8868
|
+
}
|
|
8869
|
+
),
|
|
8696
8870
|
!readOnly && /* @__PURE__ */ jsx(
|
|
8697
8871
|
"div",
|
|
8698
8872
|
{
|
|
@@ -8715,6 +8889,46 @@ function EditorCore({
|
|
|
8715
8889
|
}
|
|
8716
8890
|
);
|
|
8717
8891
|
}
|
|
8892
|
+
function getImageDropTarget(container, clientY, imagePath) {
|
|
8893
|
+
const fallback = { dropIndex: imagePath[0], indicatorClientY: clientY };
|
|
8894
|
+
if (!container) return fallback;
|
|
8895
|
+
const blocks = Array.from(
|
|
8896
|
+
container.querySelectorAll(":scope > [data-block-path]")
|
|
8897
|
+
);
|
|
8898
|
+
if (blocks.length === 0) return fallback;
|
|
8899
|
+
const gaps = [];
|
|
8900
|
+
gaps.push({ y: blocks[0].getBoundingClientRect().top, index: 0 });
|
|
8901
|
+
for (let i = 0; i < blocks.length - 1; i++) {
|
|
8902
|
+
const bottom = blocks[i].getBoundingClientRect().bottom;
|
|
8903
|
+
const top = blocks[i + 1].getBoundingClientRect().top;
|
|
8904
|
+
gaps.push({ y: (bottom + top) / 2, index: i + 1 });
|
|
8905
|
+
}
|
|
8906
|
+
gaps.push({ y: blocks[blocks.length - 1].getBoundingClientRect().bottom, index: blocks.length });
|
|
8907
|
+
let best = gaps[0];
|
|
8908
|
+
let bestDist = Math.abs(clientY - best.y);
|
|
8909
|
+
for (const gap of gaps) {
|
|
8910
|
+
const dist = Math.abs(clientY - gap.y);
|
|
8911
|
+
if (dist < bestDist) {
|
|
8912
|
+
bestDist = dist;
|
|
8913
|
+
best = gap;
|
|
8914
|
+
}
|
|
8915
|
+
}
|
|
8916
|
+
return { dropIndex: best.index, indicatorClientY: best.y };
|
|
8917
|
+
}
|
|
8918
|
+
function moveImageInDoc(imagePath, targetIndex, engine) {
|
|
8919
|
+
const state = engine.getState();
|
|
8920
|
+
const imageNode = getNodeAtPath(state.doc, imagePath);
|
|
8921
|
+
if (!imageNode) return;
|
|
8922
|
+
const oldIndex = imagePath[imagePath.length - 1];
|
|
8923
|
+
const parentPath = imagePath.slice(0, -1);
|
|
8924
|
+
let adj = targetIndex > oldIndex ? targetIndex - 1 : targetIndex;
|
|
8925
|
+
adj = Math.max(0, Math.min(state.doc.children.length - 1, adj));
|
|
8926
|
+
if (adj === oldIndex) return;
|
|
8927
|
+
const tr = createTransaction();
|
|
8928
|
+
tr.steps.push({ type: "delete_node", path: imagePath });
|
|
8929
|
+
tr.steps.push({ type: "insert_node", parentPath, index: adj, node: imageNode });
|
|
8930
|
+
engine.dispatch(tr);
|
|
8931
|
+
}
|
|
8718
8932
|
var BLOCK_TAGS = "p|h[1-6]|ul|ol|li|blockquote|pre|figure|table|thead|tbody|tr|th|td";
|
|
8719
8933
|
var _OPEN_ONLY_RE = new RegExp(`^<(${BLOCK_TAGS})(?:\\s[^>]*)?>$`, "i");
|
|
8720
8934
|
var _CLOSE_ONLY_RE = new RegExp(`^<\\/(${BLOCK_TAGS})>$`, "i");
|
|
@@ -9066,7 +9280,9 @@ ${text}
|
|
|
9066
9280
|
}
|
|
9067
9281
|
}
|
|
9068
9282
|
function serializeMDInline(children) {
|
|
9283
|
+
if (!children) return "";
|
|
9069
9284
|
return children.map((child) => {
|
|
9285
|
+
if (!child) return "";
|
|
9070
9286
|
if (!isTextNode(child)) return serializeMDBlock(child, 0);
|
|
9071
9287
|
return serializeMDText(child);
|
|
9072
9288
|
}).join("");
|