@sofereditor/core 0.2.0 → 0.3.0
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 +384 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +97 -1
- package/dist/index.d.ts +97 -1
- package/dist/index.js +371 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -89,6 +89,19 @@ function withDefaults(partial) {
|
|
|
89
89
|
|
|
90
90
|
// src/document.ts
|
|
91
91
|
import * as Y from "yjs";
|
|
92
|
+
function newBlockId() {
|
|
93
|
+
try {
|
|
94
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
95
|
+
return crypto.randomUUID();
|
|
96
|
+
}
|
|
97
|
+
} catch {
|
|
98
|
+
}
|
|
99
|
+
return `b-${Math.random().toString(36).slice(2, 10)}${Date.now().toString(36)}`;
|
|
100
|
+
}
|
|
101
|
+
function getBlockId(block) {
|
|
102
|
+
const id = block.get("id");
|
|
103
|
+
return typeof id === "string" ? id : void 0;
|
|
104
|
+
}
|
|
92
105
|
var EditorDocument = class _EditorDocument {
|
|
93
106
|
ydoc;
|
|
94
107
|
blocks;
|
|
@@ -350,6 +363,7 @@ function createBlock(type, initialText = "", attrs) {
|
|
|
350
363
|
return createTableBlock(rows, cols);
|
|
351
364
|
}
|
|
352
365
|
const block = new Y.Map();
|
|
366
|
+
block.set("id", newBlockId());
|
|
353
367
|
block.set("type", type);
|
|
354
368
|
const yText = new Y.Text();
|
|
355
369
|
if (initialText.length > 0) yText.insert(0, initialText);
|
|
@@ -366,6 +380,7 @@ function createTableBlock(rows, cols) {
|
|
|
366
380
|
const r = Math.max(1, Math.trunc(rows));
|
|
367
381
|
const c = Math.max(1, Math.trunc(cols));
|
|
368
382
|
const block = new Y.Map();
|
|
383
|
+
block.set("id", newBlockId());
|
|
369
384
|
block.set("type", "table");
|
|
370
385
|
const attrsMap = new Y.Map();
|
|
371
386
|
attrsMap.set("rows", r);
|
|
@@ -400,6 +415,7 @@ function buildEmptyBlockFromSerialized(block) {
|
|
|
400
415
|
const rows = typeof block.attrs.rows === "number" ? Math.max(1, Math.trunc(block.attrs.rows)) : 1;
|
|
401
416
|
const cols = typeof block.attrs.cols === "number" ? Math.max(1, Math.trunc(block.attrs.cols)) : 1;
|
|
402
417
|
const yBlock = new Y.Map();
|
|
418
|
+
yBlock.set("id", typeof block.id === "string" ? block.id : newBlockId());
|
|
403
419
|
yBlock.set("type", "table");
|
|
404
420
|
const attrsMap = new Y.Map();
|
|
405
421
|
attrsMap.set("rows", rows);
|
|
@@ -422,7 +438,9 @@ function buildEmptyBlockFromSerialized(block) {
|
|
|
422
438
|
yBlock.set("cells", cellsArr);
|
|
423
439
|
return yBlock;
|
|
424
440
|
}
|
|
425
|
-
|
|
441
|
+
const yb = createBlock(block.type, "", block.attrs);
|
|
442
|
+
if (typeof block.id === "string") yb.set("id", block.id);
|
|
443
|
+
return yb;
|
|
426
444
|
}
|
|
427
445
|
function applyDeltaIntoBlock(yBlock, src) {
|
|
428
446
|
if (!yBlock) return;
|
|
@@ -450,6 +468,95 @@ function spanOf(value) {
|
|
|
450
468
|
return Math.max(1, Math.trunc(value));
|
|
451
469
|
}
|
|
452
470
|
|
|
471
|
+
// src/collab-cursor.ts
|
|
472
|
+
import * as Y2 from "yjs";
|
|
473
|
+
function toBase64(bytes) {
|
|
474
|
+
if (typeof Buffer !== "undefined") return Buffer.from(bytes).toString("base64");
|
|
475
|
+
let s = "";
|
|
476
|
+
for (let i = 0; i < bytes.length; i++) s += String.fromCharCode(bytes[i]);
|
|
477
|
+
return btoa(s);
|
|
478
|
+
}
|
|
479
|
+
function fromBase64(b64) {
|
|
480
|
+
if (typeof Buffer !== "undefined") return new Uint8Array(Buffer.from(b64, "base64"));
|
|
481
|
+
const s = atob(b64);
|
|
482
|
+
const out = new Uint8Array(s.length);
|
|
483
|
+
for (let i = 0; i < s.length; i++) out[i] = s.charCodeAt(i);
|
|
484
|
+
return out;
|
|
485
|
+
}
|
|
486
|
+
function yTextAt(doc, pos) {
|
|
487
|
+
const block = doc.blocks.get(pos.blockIndex);
|
|
488
|
+
if (!block) return null;
|
|
489
|
+
if (typeof pos.cellIndex === "number") {
|
|
490
|
+
const cells = block.get("cells");
|
|
491
|
+
const cell = cells?.get(pos.cellIndex);
|
|
492
|
+
const t2 = cell?.get("text");
|
|
493
|
+
return t2 instanceof Y2.Text ? t2 : null;
|
|
494
|
+
}
|
|
495
|
+
const t = block.get("text");
|
|
496
|
+
return t instanceof Y2.Text ? t : null;
|
|
497
|
+
}
|
|
498
|
+
function locateYText(doc, target) {
|
|
499
|
+
const blocks = doc.blocks;
|
|
500
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
501
|
+
const block = blocks.get(i);
|
|
502
|
+
if (block.get("text") === target) return { blockIndex: i };
|
|
503
|
+
const cells = block.get("cells");
|
|
504
|
+
if (cells) {
|
|
505
|
+
for (let c = 0; c < cells.length; c++) {
|
|
506
|
+
if (cells.get(c)?.get("text") === target) {
|
|
507
|
+
return { blockIndex: i, cellIndex: c };
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
return null;
|
|
513
|
+
}
|
|
514
|
+
function encodePoint(doc, pos) {
|
|
515
|
+
const yText = yTextAt(doc, pos);
|
|
516
|
+
if (!yText) return null;
|
|
517
|
+
const offset = Math.max(0, Math.min(pos.offset, yText.length));
|
|
518
|
+
const rel = Y2.createRelativePositionFromTypeIndex(yText, offset);
|
|
519
|
+
const block = doc.blocks.get(pos.blockIndex);
|
|
520
|
+
const point = { rel: toBase64(Y2.encodeRelativePosition(rel)) };
|
|
521
|
+
const blockId = block ? getBlockId(block) : void 0;
|
|
522
|
+
if (blockId) point.blockId = blockId;
|
|
523
|
+
if (typeof pos.cellIndex === "number") point.cellIndex = pos.cellIndex;
|
|
524
|
+
return point;
|
|
525
|
+
}
|
|
526
|
+
function decodePoint(doc, enc) {
|
|
527
|
+
try {
|
|
528
|
+
const rel = Y2.decodeRelativePosition(fromBase64(enc.rel));
|
|
529
|
+
const abs = Y2.createAbsolutePositionFromRelativePosition(rel, doc.ydoc);
|
|
530
|
+
if (abs && abs.type instanceof Y2.Text) {
|
|
531
|
+
const loc = locateYText(doc, abs.type);
|
|
532
|
+
if (loc) return { ...loc, offset: abs.index };
|
|
533
|
+
}
|
|
534
|
+
} catch {
|
|
535
|
+
}
|
|
536
|
+
if (enc.blockId) {
|
|
537
|
+
for (let i = 0; i < doc.blocks.length; i++) {
|
|
538
|
+
if (getBlockId(doc.blocks.get(i)) === enc.blockId) {
|
|
539
|
+
const p = { blockIndex: i, offset: 0 };
|
|
540
|
+
if (typeof enc.cellIndex === "number") p.cellIndex = enc.cellIndex;
|
|
541
|
+
return p;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
return null;
|
|
546
|
+
}
|
|
547
|
+
function encodeSelection(doc, sel) {
|
|
548
|
+
const anchor = encodePoint(doc, sel.anchor);
|
|
549
|
+
const focus = encodePoint(doc, sel.focus);
|
|
550
|
+
if (!anchor || !focus) return null;
|
|
551
|
+
return { anchor, focus };
|
|
552
|
+
}
|
|
553
|
+
function decodeSelection(doc, enc) {
|
|
554
|
+
const anchor = decodePoint(doc, enc.anchor);
|
|
555
|
+
const focus = decodePoint(doc, enc.focus);
|
|
556
|
+
if (!anchor || !focus) return null;
|
|
557
|
+
return { anchor, focus };
|
|
558
|
+
}
|
|
559
|
+
|
|
453
560
|
// src/selection.ts
|
|
454
561
|
function isCollapsed(sel) {
|
|
455
562
|
return positionsEqual(sel.anchor, sel.focus);
|
|
@@ -478,6 +585,20 @@ function sameTextRun(a, b) {
|
|
|
478
585
|
}
|
|
479
586
|
|
|
480
587
|
// src/marks.ts
|
|
588
|
+
var ALL_MARKS = {
|
|
589
|
+
bold: true,
|
|
590
|
+
italic: true,
|
|
591
|
+
underline: true,
|
|
592
|
+
strike: true,
|
|
593
|
+
color: true,
|
|
594
|
+
fontFamily: true,
|
|
595
|
+
fontSize: true,
|
|
596
|
+
link: true,
|
|
597
|
+
comment: true
|
|
598
|
+
};
|
|
599
|
+
var CLEAR_ALL_MARKS = Object.fromEntries(
|
|
600
|
+
Object.keys(ALL_MARKS).map((k) => [k, null])
|
|
601
|
+
);
|
|
481
602
|
function iterateRunsInRange(yText, start, end, visit) {
|
|
482
603
|
if (start >= end) return;
|
|
483
604
|
const delta = yText.toDelta();
|
|
@@ -602,7 +723,87 @@ function sameMarkValue(a, b) {
|
|
|
602
723
|
}
|
|
603
724
|
|
|
604
725
|
// src/commands.ts
|
|
605
|
-
import * as
|
|
726
|
+
import * as Y3 from "yjs";
|
|
727
|
+
|
|
728
|
+
// src/clipboard.ts
|
|
729
|
+
var SOFER_MIME = "application/x-sofer-slice";
|
|
730
|
+
function deltaToText(delta) {
|
|
731
|
+
let s = "";
|
|
732
|
+
for (const op of delta) if (typeof op.insert === "string") s += op.insert;
|
|
733
|
+
return s;
|
|
734
|
+
}
|
|
735
|
+
function blockFromDelta(doc, blockIndex, cellIndex, delta) {
|
|
736
|
+
if (cellIndex != null) {
|
|
737
|
+
return { type: "paragraph", text: deltaToText(delta), delta, attrs: {} };
|
|
738
|
+
}
|
|
739
|
+
return {
|
|
740
|
+
type: doc.getBlockType(blockIndex) ?? "paragraph",
|
|
741
|
+
text: deltaToText(delta),
|
|
742
|
+
delta,
|
|
743
|
+
attrs: doc.getBlockAttrs(blockIndex)
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
function serializeSelection(doc, sel) {
|
|
747
|
+
if (isCollapsed(sel)) return null;
|
|
748
|
+
const { start, end } = orderedRange(sel);
|
|
749
|
+
if ((start.cellIndex ?? -1) !== (end.cellIndex ?? -1)) return null;
|
|
750
|
+
if (start.blockIndex === end.blockIndex) {
|
|
751
|
+
const yText = doc.textAt(start.blockIndex, start.cellIndex);
|
|
752
|
+
if (!yText) return null;
|
|
753
|
+
const delta = sliceDelta(yText.toDelta(), start.offset, end.offset);
|
|
754
|
+
return {
|
|
755
|
+
blocks: [blockFromDelta(doc, start.blockIndex, start.cellIndex, delta)],
|
|
756
|
+
openStart: start.offset > 0,
|
|
757
|
+
openEnd: end.offset < yText.length
|
|
758
|
+
};
|
|
759
|
+
}
|
|
760
|
+
if (start.cellIndex != null || end.cellIndex != null) return null;
|
|
761
|
+
for (let i = start.blockIndex; i <= end.blockIndex; i++) {
|
|
762
|
+
if (doc.getBlockType(i) === "table") return null;
|
|
763
|
+
}
|
|
764
|
+
const startText = doc.getBlockText(start.blockIndex);
|
|
765
|
+
const endText = doc.getBlockText(end.blockIndex);
|
|
766
|
+
if (!startText || !endText) return null;
|
|
767
|
+
const blocks = [];
|
|
768
|
+
blocks.push(
|
|
769
|
+
blockFromDelta(
|
|
770
|
+
doc,
|
|
771
|
+
start.blockIndex,
|
|
772
|
+
void 0,
|
|
773
|
+
sliceDelta(startText.toDelta(), start.offset, startText.length)
|
|
774
|
+
)
|
|
775
|
+
);
|
|
776
|
+
for (let i = start.blockIndex + 1; i < end.blockIndex; i++) {
|
|
777
|
+
const t = doc.getBlockText(i);
|
|
778
|
+
blocks.push(blockFromDelta(doc, i, void 0, t?.toDelta() ?? []));
|
|
779
|
+
}
|
|
780
|
+
blocks.push(
|
|
781
|
+
blockFromDelta(
|
|
782
|
+
doc,
|
|
783
|
+
end.blockIndex,
|
|
784
|
+
void 0,
|
|
785
|
+
sliceDelta(endText.toDelta(), 0, end.offset)
|
|
786
|
+
)
|
|
787
|
+
);
|
|
788
|
+
return {
|
|
789
|
+
blocks,
|
|
790
|
+
openStart: start.offset > 0,
|
|
791
|
+
openEnd: end.offset < endText.length
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
function sliceToText(slice) {
|
|
795
|
+
return slice.blocks.map((b) => deltaToText(b.delta)).join("\n");
|
|
796
|
+
}
|
|
797
|
+
function sliceToInlineDelta(slice) {
|
|
798
|
+
const out = [];
|
|
799
|
+
slice.blocks.forEach((b, i) => {
|
|
800
|
+
if (i > 0) out.push({ insert: "\n" });
|
|
801
|
+
out.push(...b.delta);
|
|
802
|
+
});
|
|
803
|
+
return out;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
// src/commands.ts
|
|
606
807
|
var COMMAND_ORIGIN = /* @__PURE__ */ Symbol("editor-command");
|
|
607
808
|
function transact(doc, fn) {
|
|
608
809
|
doc.ydoc.transact(fn, COMMAND_ORIGIN);
|
|
@@ -811,7 +1012,7 @@ function setBlockType(ctx, type, attrs) {
|
|
|
811
1012
|
const block = ctx.doc.getBlock(i);
|
|
812
1013
|
if (!block) continue;
|
|
813
1014
|
block.set("type", type);
|
|
814
|
-
const attrsMap = block.get("attrs") ?? new
|
|
1015
|
+
const attrsMap = block.get("attrs") ?? new Y3.Map();
|
|
815
1016
|
if (!block.get("attrs")) block.set("attrs", attrsMap);
|
|
816
1017
|
const next = { ...defaultAttrsFor(type), ...attrs ?? {} };
|
|
817
1018
|
const keep = new Set(Object.keys(next));
|
|
@@ -834,7 +1035,7 @@ function setBlockAttr(ctx, key, value) {
|
|
|
834
1035
|
for (const i of indices) {
|
|
835
1036
|
const block = ctx.doc.getBlock(i);
|
|
836
1037
|
if (!block) continue;
|
|
837
|
-
const attrsMap = block.get("attrs") ?? new
|
|
1038
|
+
const attrsMap = block.get("attrs") ?? new Y3.Map();
|
|
838
1039
|
if (!block.get("attrs")) block.set("attrs", attrsMap);
|
|
839
1040
|
if (value === null || value === void 0) {
|
|
840
1041
|
attrsMap.delete(key);
|
|
@@ -845,6 +1046,109 @@ function setBlockAttr(ctx, key, value) {
|
|
|
845
1046
|
ctx.setSelection(sel);
|
|
846
1047
|
});
|
|
847
1048
|
}
|
|
1049
|
+
function setCellAttr(ctx, key, value) {
|
|
1050
|
+
transact(ctx.doc, () => {
|
|
1051
|
+
const sel = ctx.getSelection();
|
|
1052
|
+
const { blockIndex, cellIndex } = sel.focus;
|
|
1053
|
+
if (cellIndex == null || !ctx.doc.isTable(blockIndex)) return;
|
|
1054
|
+
const { cols } = ctx.doc.getTableSize(blockIndex);
|
|
1055
|
+
if (cols <= 0) return;
|
|
1056
|
+
const rect = tableRectSelection(ctx.doc, sel);
|
|
1057
|
+
const targets = [];
|
|
1058
|
+
if (rect) {
|
|
1059
|
+
for (let r = rect.top; r <= rect.bottom; r++)
|
|
1060
|
+
for (let c = rect.left; c <= rect.right; c++) targets.push(r * cols + c);
|
|
1061
|
+
} else {
|
|
1062
|
+
const real = ctx.doc.realCellIndex(blockIndex, cellIndex);
|
|
1063
|
+
if (real != null) targets.push(real);
|
|
1064
|
+
}
|
|
1065
|
+
for (const flat of targets) {
|
|
1066
|
+
if (ctx.doc.getCellAttrs(blockIndex, flat).covered) continue;
|
|
1067
|
+
const m = ctx.doc.getCellAttrsMap(blockIndex, flat);
|
|
1068
|
+
if (!m) continue;
|
|
1069
|
+
if (value === null || value === void 0) m.delete(key);
|
|
1070
|
+
else m.set(key, value);
|
|
1071
|
+
}
|
|
1072
|
+
ctx.setSelection(sel);
|
|
1073
|
+
});
|
|
1074
|
+
}
|
|
1075
|
+
function deleteSelection(ctx) {
|
|
1076
|
+
transact(ctx.doc, () => {
|
|
1077
|
+
const s = deleteRange(ctx.doc, ctx.getSelection());
|
|
1078
|
+
ctx.setSelection(s);
|
|
1079
|
+
});
|
|
1080
|
+
}
|
|
1081
|
+
function insertSlice(ctx, slice) {
|
|
1082
|
+
if (!slice.blocks || slice.blocks.length === 0) return;
|
|
1083
|
+
transact(ctx.doc, () => {
|
|
1084
|
+
let sel = ctx.getSelection();
|
|
1085
|
+
if (!isCollapsed(sel)) sel = deleteRange(ctx.doc, sel);
|
|
1086
|
+
const { blockIndex, cellIndex, offset } = sel.focus;
|
|
1087
|
+
if (cellIndex != null) {
|
|
1088
|
+
const cellText = ctx.doc.textAt(blockIndex, cellIndex);
|
|
1089
|
+
if (!cellText) return;
|
|
1090
|
+
const after = writeDeltaInto(cellText, offset, sliceToInlineDelta(slice));
|
|
1091
|
+
ctx.setSelection(collapsedSelection({ blockIndex, cellIndex, offset: after }));
|
|
1092
|
+
return;
|
|
1093
|
+
}
|
|
1094
|
+
const targetText = ctx.doc.getBlockText(blockIndex);
|
|
1095
|
+
if (!targetText) return;
|
|
1096
|
+
const full = targetText.toDelta();
|
|
1097
|
+
const tailDelta = sliceDelta(full, offset, deltaLength(full));
|
|
1098
|
+
targetText.delete(offset, targetText.length - offset);
|
|
1099
|
+
const blocks = slice.blocks;
|
|
1100
|
+
if (blocks.length === 1) {
|
|
1101
|
+
const afterS0 = writeDeltaInto(targetText, offset, blocks[0].delta);
|
|
1102
|
+
writeDeltaInto(targetText, afterS0, tailDelta);
|
|
1103
|
+
ctx.setSelection(collapsedSelection({ blockIndex, offset: afterS0 }));
|
|
1104
|
+
return;
|
|
1105
|
+
}
|
|
1106
|
+
const originalType = ctx.doc.getBlockType(blockIndex);
|
|
1107
|
+
const originalAttrs = ctx.doc.getBlockAttrs(blockIndex);
|
|
1108
|
+
let insertAt = blockIndex;
|
|
1109
|
+
if (slice.openStart) {
|
|
1110
|
+
writeDeltaInto(targetText, offset, blocks[0].delta);
|
|
1111
|
+
} else if (offset === 0) {
|
|
1112
|
+
const blk = ctx.doc.blocks.get(blockIndex);
|
|
1113
|
+
blk.set("type", blocks[0].type);
|
|
1114
|
+
const am = blk.get("attrs");
|
|
1115
|
+
am.clear();
|
|
1116
|
+
for (const [k, v] of Object.entries(blocks[0].attrs)) {
|
|
1117
|
+
if (v !== void 0) am.set(k, v);
|
|
1118
|
+
}
|
|
1119
|
+
writeDeltaInto(targetText, 0, blocks[0].delta);
|
|
1120
|
+
} else {
|
|
1121
|
+
const b = createBlock(blocks[0].type, "", blocks[0].attrs);
|
|
1122
|
+
ctx.doc.blocks.insert(++insertAt, [b]);
|
|
1123
|
+
writeDeltaInto(b.get("text"), 0, blocks[0].delta);
|
|
1124
|
+
}
|
|
1125
|
+
for (let i = 1; i < blocks.length - 1; i++) {
|
|
1126
|
+
const b = createBlock(blocks[i].type, "", blocks[i].attrs);
|
|
1127
|
+
ctx.doc.blocks.insert(++insertAt, [b]);
|
|
1128
|
+
writeDeltaInto(b.get("text"), 0, blocks[i].delta);
|
|
1129
|
+
}
|
|
1130
|
+
const last = blocks[blocks.length - 1];
|
|
1131
|
+
if (slice.openEnd) {
|
|
1132
|
+
const b = createBlock(last.type, "", last.attrs);
|
|
1133
|
+
ctx.doc.blocks.insert(++insertAt, [b]);
|
|
1134
|
+
const t = b.get("text");
|
|
1135
|
+
const caretPos = writeDeltaInto(t, 0, last.delta);
|
|
1136
|
+
writeDeltaInto(t, caretPos, tailDelta);
|
|
1137
|
+
ctx.setSelection(collapsedSelection({ blockIndex: insertAt, offset: caretPos }));
|
|
1138
|
+
} else {
|
|
1139
|
+
const b = createBlock(last.type, "", last.attrs);
|
|
1140
|
+
ctx.doc.blocks.insert(++insertAt, [b]);
|
|
1141
|
+
const lastLen = writeDeltaInto(b.get("text"), 0, last.delta);
|
|
1142
|
+
const lastIdx = insertAt;
|
|
1143
|
+
if (tailDelta.length > 0) {
|
|
1144
|
+
const tb = createBlock(originalType ?? "paragraph", "", originalAttrs);
|
|
1145
|
+
ctx.doc.blocks.insert(++insertAt, [tb]);
|
|
1146
|
+
writeDeltaInto(tb.get("text"), 0, tailDelta);
|
|
1147
|
+
}
|
|
1148
|
+
ctx.setSelection(collapsedSelection({ blockIndex: lastIdx, offset: lastLen }));
|
|
1149
|
+
}
|
|
1150
|
+
});
|
|
1151
|
+
}
|
|
848
1152
|
function selectedBlockIndices(sel, blockCount) {
|
|
849
1153
|
const { start, end } = orderedRange(sel);
|
|
850
1154
|
const out = [];
|
|
@@ -994,7 +1298,7 @@ function setBlockTypeAtIndex(doc, index, type, attrs) {
|
|
|
994
1298
|
const block = doc.getBlock(index);
|
|
995
1299
|
if (!block) return;
|
|
996
1300
|
block.set("type", type);
|
|
997
|
-
const attrsMap = block.get("attrs") ?? new
|
|
1301
|
+
const attrsMap = block.get("attrs") ?? new Y3.Map();
|
|
998
1302
|
if (!block.get("attrs")) block.set("attrs", attrsMap);
|
|
999
1303
|
const next = { ...defaultAttrsFor(type), ...attrs };
|
|
1000
1304
|
const keep = new Set(Object.keys(next));
|
|
@@ -1018,6 +1322,9 @@ function insertTable(ctx, rows, cols) {
|
|
|
1018
1322
|
const focusBlock = Math.max(0, Math.min(sel.focus.blockIndex, ctx.doc.blockCount() - 1));
|
|
1019
1323
|
const insertAt = focusBlock + 1;
|
|
1020
1324
|
ctx.doc.blocks.insert(insertAt, [createTableBlock(r, c)]);
|
|
1325
|
+
if (insertAt === ctx.doc.blockCount() - 1) {
|
|
1326
|
+
ctx.doc.blocks.insert(insertAt + 1, [createBlock("paragraph")]);
|
|
1327
|
+
}
|
|
1021
1328
|
ctx.setSelection(
|
|
1022
1329
|
collapsedSelection({ blockIndex: insertAt, cellIndex: 0, offset: 0 })
|
|
1023
1330
|
);
|
|
@@ -1626,11 +1933,10 @@ function writeDeltaInto(yText, pos, delta) {
|
|
|
1626
1933
|
for (const op of delta) {
|
|
1627
1934
|
if (typeof op.insert === "string") {
|
|
1628
1935
|
if (op.insert.length === 0) continue;
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
}
|
|
1936
|
+
yText.insert(cursor, op.insert, {
|
|
1937
|
+
...CLEAR_ALL_MARKS,
|
|
1938
|
+
...op.attributes ?? {}
|
|
1939
|
+
});
|
|
1634
1940
|
cursor += op.insert.length;
|
|
1635
1941
|
} else if (op.insert != null) {
|
|
1636
1942
|
if (op.attributes && Object.keys(op.attributes).length > 0) {
|
|
@@ -1690,17 +1996,56 @@ function setImageAttrs(ctx, blockIndex, embedOffset, partial, cellIndex, newOffs
|
|
|
1690
1996
|
yText.insert(insertAt, merged);
|
|
1691
1997
|
});
|
|
1692
1998
|
}
|
|
1999
|
+
var REANCHORABLE_LAYOUTS = /* @__PURE__ */ new Set(["front", "behind"]);
|
|
2000
|
+
function moveEmbedAnchor(ctx, from, to, newOffsetX, newOffsetY) {
|
|
2001
|
+
transact(ctx.doc, () => {
|
|
2002
|
+
const srcText = ctx.doc.textAt(from.blockIndex, from.cellIndex);
|
|
2003
|
+
if (!srcText) return;
|
|
2004
|
+
const delta = srcText.toDelta();
|
|
2005
|
+
let cursor = 0;
|
|
2006
|
+
let prev = null;
|
|
2007
|
+
for (const op of delta) {
|
|
2008
|
+
if (typeof op.insert === "string") {
|
|
2009
|
+
cursor += op.insert.length;
|
|
2010
|
+
continue;
|
|
2011
|
+
}
|
|
2012
|
+
if (cursor === from.offset && isImageEmbed(op.insert)) {
|
|
2013
|
+
prev = op.insert;
|
|
2014
|
+
break;
|
|
2015
|
+
}
|
|
2016
|
+
cursor += 1;
|
|
2017
|
+
}
|
|
2018
|
+
if (!prev) return;
|
|
2019
|
+
const layout = prev.layout ?? "inline";
|
|
2020
|
+
if (!REANCHORABLE_LAYOUTS.has(layout)) return;
|
|
2021
|
+
const dstText = ctx.doc.textAt(to.blockIndex, to.cellIndex);
|
|
2022
|
+
if (!dstText) return;
|
|
2023
|
+
const merged = { ...prev, offsetX: newOffsetX, offsetY: newOffsetY };
|
|
2024
|
+
const sameRun = srcText === dstText;
|
|
2025
|
+
srcText.delete(from.offset, 1);
|
|
2026
|
+
let landed = to.offset;
|
|
2027
|
+
if (sameRun && to.offset > from.offset) {
|
|
2028
|
+
landed = to.offset - 1;
|
|
2029
|
+
}
|
|
2030
|
+
landed = Math.max(0, Math.min(landed, dstText.length));
|
|
2031
|
+
dstText.insert(landed, merged);
|
|
2032
|
+
ctx.setSelection({
|
|
2033
|
+
anchor: { blockIndex: to.blockIndex, cellIndex: to.cellIndex, offset: landed },
|
|
2034
|
+
focus: { blockIndex: to.blockIndex, cellIndex: to.cellIndex, offset: landed + 1 }
|
|
2035
|
+
});
|
|
2036
|
+
});
|
|
2037
|
+
}
|
|
1693
2038
|
function isCommandOrigin(origin) {
|
|
1694
2039
|
return origin === COMMAND_ORIGIN;
|
|
1695
2040
|
}
|
|
1696
2041
|
var TRACKED_ORIGINS = /* @__PURE__ */ new Set([COMMAND_ORIGIN]);
|
|
1697
2042
|
|
|
1698
2043
|
// src/history.ts
|
|
1699
|
-
import * as
|
|
2044
|
+
import * as Y4 from "yjs";
|
|
1700
2045
|
var EditorHistory = class {
|
|
1701
2046
|
undoManager;
|
|
1702
2047
|
constructor(doc) {
|
|
1703
|
-
this.undoManager = new
|
|
2048
|
+
this.undoManager = new Y4.UndoManager(doc.blocks, {
|
|
1704
2049
|
trackedOrigins: TRACKED_ORIGINS,
|
|
1705
2050
|
captureTimeout: 400
|
|
1706
2051
|
});
|
|
@@ -1717,6 +2062,7 @@ var EditorHistory = class {
|
|
|
1717
2062
|
};
|
|
1718
2063
|
export {
|
|
1719
2064
|
BLOCK_SPECS,
|
|
2065
|
+
CLEAR_ALL_MARKS,
|
|
1720
2066
|
COMMAND_ORIGIN,
|
|
1721
2067
|
DEFAULT_PAGE_SETTINGS,
|
|
1722
2068
|
EditorDocument,
|
|
@@ -1724,8 +2070,9 @@ export {
|
|
|
1724
2070
|
MARGIN_PRESETS,
|
|
1725
2071
|
MAX_LIST_LEVEL,
|
|
1726
2072
|
PAGE_PRESETS,
|
|
2073
|
+
SOFER_MIME,
|
|
1727
2074
|
TRACKED_ORIGINS,
|
|
1728
|
-
|
|
2075
|
+
Y3 as Y,
|
|
1729
2076
|
cellsInRect,
|
|
1730
2077
|
clearRectCells,
|
|
1731
2078
|
collapsedSelection,
|
|
@@ -1733,20 +2080,25 @@ export {
|
|
|
1733
2080
|
createBlock,
|
|
1734
2081
|
createCell,
|
|
1735
2082
|
createTableBlock,
|
|
2083
|
+
decodeSelection,
|
|
1736
2084
|
dedentList,
|
|
1737
2085
|
defaultAttrsFor,
|
|
1738
2086
|
deleteBackward,
|
|
1739
2087
|
deleteForward,
|
|
2088
|
+
deleteSelection,
|
|
1740
2089
|
deleteTable,
|
|
1741
2090
|
deleteTableColumn,
|
|
1742
2091
|
deleteTableRow,
|
|
1743
2092
|
deltaLength,
|
|
1744
2093
|
detectPreset,
|
|
2094
|
+
encodeSelection,
|
|
1745
2095
|
expandTableRect,
|
|
2096
|
+
getBlockId,
|
|
1746
2097
|
getMarksInRange,
|
|
1747
2098
|
indentList,
|
|
1748
2099
|
insertImage,
|
|
1749
2100
|
insertParagraph,
|
|
2101
|
+
insertSlice,
|
|
1750
2102
|
insertTable,
|
|
1751
2103
|
insertTableColumn,
|
|
1752
2104
|
insertTableRow,
|
|
@@ -1761,19 +2113,25 @@ export {
|
|
|
1761
2113
|
mergeRight,
|
|
1762
2114
|
mergeSelection,
|
|
1763
2115
|
mmToPx,
|
|
2116
|
+
moveEmbedAnchor,
|
|
1764
2117
|
moveToNextCell,
|
|
1765
2118
|
moveToPrevCell,
|
|
2119
|
+
newBlockId,
|
|
1766
2120
|
orderedRange,
|
|
1767
2121
|
positionsEqual,
|
|
1768
2122
|
pxToMm,
|
|
1769
2123
|
removeMark,
|
|
1770
2124
|
sameTextRun,
|
|
2125
|
+
serializeSelection,
|
|
1771
2126
|
setBlockAttr,
|
|
1772
2127
|
setBlockType,
|
|
2128
|
+
setCellAttr,
|
|
1773
2129
|
setColumnWidth,
|
|
1774
2130
|
setImageAttrs,
|
|
1775
2131
|
setMark,
|
|
1776
2132
|
sliceDelta,
|
|
2133
|
+
sliceToInlineDelta,
|
|
2134
|
+
sliceToText,
|
|
1777
2135
|
spanOf,
|
|
1778
2136
|
splitCell,
|
|
1779
2137
|
splitListItem,
|