@sofereditor/core 0.1.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 +399 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +133 -1
- package/dist/index.d.ts +133 -1
- package/dist/index.js +386 -14
- package/dist/index.js.map +1 -1
- package/package.json +26 -14
package/dist/index.cjs
CHANGED
|
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
BLOCK_SPECS: () => BLOCK_SPECS,
|
|
34
|
+
CLEAR_ALL_MARKS: () => CLEAR_ALL_MARKS,
|
|
34
35
|
COMMAND_ORIGIN: () => COMMAND_ORIGIN,
|
|
35
36
|
DEFAULT_PAGE_SETTINGS: () => DEFAULT_PAGE_SETTINGS,
|
|
36
37
|
EditorDocument: () => EditorDocument,
|
|
@@ -38,8 +39,9 @@ __export(index_exports, {
|
|
|
38
39
|
MARGIN_PRESETS: () => MARGIN_PRESETS,
|
|
39
40
|
MAX_LIST_LEVEL: () => MAX_LIST_LEVEL,
|
|
40
41
|
PAGE_PRESETS: () => PAGE_PRESETS,
|
|
42
|
+
SOFER_MIME: () => SOFER_MIME,
|
|
41
43
|
TRACKED_ORIGINS: () => TRACKED_ORIGINS,
|
|
42
|
-
Y: () =>
|
|
44
|
+
Y: () => Y3,
|
|
43
45
|
cellsInRect: () => cellsInRect,
|
|
44
46
|
clearRectCells: () => clearRectCells,
|
|
45
47
|
collapsedSelection: () => collapsedSelection,
|
|
@@ -47,20 +49,25 @@ __export(index_exports, {
|
|
|
47
49
|
createBlock: () => createBlock,
|
|
48
50
|
createCell: () => createCell,
|
|
49
51
|
createTableBlock: () => createTableBlock,
|
|
52
|
+
decodeSelection: () => decodeSelection,
|
|
50
53
|
dedentList: () => dedentList,
|
|
51
54
|
defaultAttrsFor: () => defaultAttrsFor,
|
|
52
55
|
deleteBackward: () => deleteBackward,
|
|
53
56
|
deleteForward: () => deleteForward,
|
|
57
|
+
deleteSelection: () => deleteSelection,
|
|
54
58
|
deleteTable: () => deleteTable,
|
|
55
59
|
deleteTableColumn: () => deleteTableColumn,
|
|
56
60
|
deleteTableRow: () => deleteTableRow,
|
|
57
61
|
deltaLength: () => deltaLength,
|
|
58
62
|
detectPreset: () => detectPreset,
|
|
63
|
+
encodeSelection: () => encodeSelection,
|
|
59
64
|
expandTableRect: () => expandTableRect,
|
|
65
|
+
getBlockId: () => getBlockId,
|
|
60
66
|
getMarksInRange: () => getMarksInRange,
|
|
61
67
|
indentList: () => indentList,
|
|
62
68
|
insertImage: () => insertImage,
|
|
63
69
|
insertParagraph: () => insertParagraph,
|
|
70
|
+
insertSlice: () => insertSlice,
|
|
64
71
|
insertTable: () => insertTable,
|
|
65
72
|
insertTableColumn: () => insertTableColumn,
|
|
66
73
|
insertTableRow: () => insertTableRow,
|
|
@@ -75,19 +82,25 @@ __export(index_exports, {
|
|
|
75
82
|
mergeRight: () => mergeRight,
|
|
76
83
|
mergeSelection: () => mergeSelection,
|
|
77
84
|
mmToPx: () => mmToPx,
|
|
85
|
+
moveEmbedAnchor: () => moveEmbedAnchor,
|
|
78
86
|
moveToNextCell: () => moveToNextCell,
|
|
79
87
|
moveToPrevCell: () => moveToPrevCell,
|
|
88
|
+
newBlockId: () => newBlockId,
|
|
80
89
|
orderedRange: () => orderedRange,
|
|
81
90
|
positionsEqual: () => positionsEqual,
|
|
82
91
|
pxToMm: () => pxToMm,
|
|
83
92
|
removeMark: () => removeMark,
|
|
84
93
|
sameTextRun: () => sameTextRun,
|
|
94
|
+
serializeSelection: () => serializeSelection,
|
|
85
95
|
setBlockAttr: () => setBlockAttr,
|
|
86
96
|
setBlockType: () => setBlockType,
|
|
97
|
+
setCellAttr: () => setCellAttr,
|
|
87
98
|
setColumnWidth: () => setColumnWidth,
|
|
88
99
|
setImageAttrs: () => setImageAttrs,
|
|
89
100
|
setMark: () => setMark,
|
|
90
101
|
sliceDelta: () => sliceDelta,
|
|
102
|
+
sliceToInlineDelta: () => sliceToInlineDelta,
|
|
103
|
+
sliceToText: () => sliceToText,
|
|
91
104
|
spanOf: () => spanOf,
|
|
92
105
|
splitCell: () => splitCell,
|
|
93
106
|
splitListItem: () => splitListItem,
|
|
@@ -190,6 +203,19 @@ function withDefaults(partial) {
|
|
|
190
203
|
|
|
191
204
|
// src/document.ts
|
|
192
205
|
var Y = __toESM(require("yjs"), 1);
|
|
206
|
+
function newBlockId() {
|
|
207
|
+
try {
|
|
208
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
209
|
+
return crypto.randomUUID();
|
|
210
|
+
}
|
|
211
|
+
} catch {
|
|
212
|
+
}
|
|
213
|
+
return `b-${Math.random().toString(36).slice(2, 10)}${Date.now().toString(36)}`;
|
|
214
|
+
}
|
|
215
|
+
function getBlockId(block) {
|
|
216
|
+
const id = block.get("id");
|
|
217
|
+
return typeof id === "string" ? id : void 0;
|
|
218
|
+
}
|
|
193
219
|
var EditorDocument = class _EditorDocument {
|
|
194
220
|
ydoc;
|
|
195
221
|
blocks;
|
|
@@ -222,7 +248,9 @@ var EditorDocument = class _EditorDocument {
|
|
|
222
248
|
marginTop: pick("marginTop") ?? DEFAULT_PAGE_SETTINGS.marginTop,
|
|
223
249
|
marginBottom: pick("marginBottom") ?? DEFAULT_PAGE_SETTINGS.marginBottom,
|
|
224
250
|
marginLeft: pick("marginLeft") ?? DEFAULT_PAGE_SETTINGS.marginLeft,
|
|
225
|
-
marginRight: pick("marginRight") ?? DEFAULT_PAGE_SETTINGS.marginRight
|
|
251
|
+
marginRight: pick("marginRight") ?? DEFAULT_PAGE_SETTINGS.marginRight,
|
|
252
|
+
systemHeaderTitle: pick("systemHeaderTitle"),
|
|
253
|
+
systemHeaderAuthor: pick("systemHeaderAuthor")
|
|
226
254
|
};
|
|
227
255
|
merged.preset = detectPreset(merged.width, merged.height);
|
|
228
256
|
return merged;
|
|
@@ -358,6 +386,17 @@ var EditorDocument = class _EditorDocument {
|
|
|
358
386
|
*/
|
|
359
387
|
loadFromJSON(serialized) {
|
|
360
388
|
const { blocks: sourceBlocks, pageSettings } = normalizeSerialized(serialized);
|
|
389
|
+
const LOCK_KEY = "__importLock";
|
|
390
|
+
const LOCK_TTL_MS = 5e3;
|
|
391
|
+
const existing = this.docSettings.get(LOCK_KEY);
|
|
392
|
+
if (typeof existing === "number" && Date.now() - existing < LOCK_TTL_MS) {
|
|
393
|
+
const ageMs = Date.now() - existing;
|
|
394
|
+
console.warn(
|
|
395
|
+
`[EditorDocument.loadFromJSON] import j\xE1 em andamento (${ageMs}ms atr\xE1s, TTL ${LOCK_TTL_MS}ms) \u2014 ignorando esta chamada para evitar duplica\xE7\xE3o de blocks.`
|
|
396
|
+
);
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
this.docSettings.set(LOCK_KEY, Date.now());
|
|
361
400
|
this.ydoc.transact(() => {
|
|
362
401
|
if (this.blocks.length > 0) {
|
|
363
402
|
this.blocks.delete(0, this.blocks.length);
|
|
@@ -377,6 +416,7 @@ var EditorDocument = class _EditorDocument {
|
|
|
377
416
|
this.docSettings.set(k, v);
|
|
378
417
|
}
|
|
379
418
|
}
|
|
419
|
+
this.docSettings.delete(LOCK_KEY);
|
|
380
420
|
}, "import");
|
|
381
421
|
}
|
|
382
422
|
/** Build a fresh `EditorDocument` from a `SerializedDocument`. */
|
|
@@ -437,6 +477,7 @@ function createBlock(type, initialText = "", attrs) {
|
|
|
437
477
|
return createTableBlock(rows, cols);
|
|
438
478
|
}
|
|
439
479
|
const block = new Y.Map();
|
|
480
|
+
block.set("id", newBlockId());
|
|
440
481
|
block.set("type", type);
|
|
441
482
|
const yText = new Y.Text();
|
|
442
483
|
if (initialText.length > 0) yText.insert(0, initialText);
|
|
@@ -453,6 +494,7 @@ function createTableBlock(rows, cols) {
|
|
|
453
494
|
const r = Math.max(1, Math.trunc(rows));
|
|
454
495
|
const c = Math.max(1, Math.trunc(cols));
|
|
455
496
|
const block = new Y.Map();
|
|
497
|
+
block.set("id", newBlockId());
|
|
456
498
|
block.set("type", "table");
|
|
457
499
|
const attrsMap = new Y.Map();
|
|
458
500
|
attrsMap.set("rows", r);
|
|
@@ -487,6 +529,7 @@ function buildEmptyBlockFromSerialized(block) {
|
|
|
487
529
|
const rows = typeof block.attrs.rows === "number" ? Math.max(1, Math.trunc(block.attrs.rows)) : 1;
|
|
488
530
|
const cols = typeof block.attrs.cols === "number" ? Math.max(1, Math.trunc(block.attrs.cols)) : 1;
|
|
489
531
|
const yBlock = new Y.Map();
|
|
532
|
+
yBlock.set("id", typeof block.id === "string" ? block.id : newBlockId());
|
|
490
533
|
yBlock.set("type", "table");
|
|
491
534
|
const attrsMap = new Y.Map();
|
|
492
535
|
attrsMap.set("rows", rows);
|
|
@@ -509,7 +552,9 @@ function buildEmptyBlockFromSerialized(block) {
|
|
|
509
552
|
yBlock.set("cells", cellsArr);
|
|
510
553
|
return yBlock;
|
|
511
554
|
}
|
|
512
|
-
|
|
555
|
+
const yb = createBlock(block.type, "", block.attrs);
|
|
556
|
+
if (typeof block.id === "string") yb.set("id", block.id);
|
|
557
|
+
return yb;
|
|
513
558
|
}
|
|
514
559
|
function applyDeltaIntoBlock(yBlock, src) {
|
|
515
560
|
if (!yBlock) return;
|
|
@@ -537,6 +582,95 @@ function spanOf(value) {
|
|
|
537
582
|
return Math.max(1, Math.trunc(value));
|
|
538
583
|
}
|
|
539
584
|
|
|
585
|
+
// src/collab-cursor.ts
|
|
586
|
+
var Y2 = __toESM(require("yjs"), 1);
|
|
587
|
+
function toBase64(bytes) {
|
|
588
|
+
if (typeof Buffer !== "undefined") return Buffer.from(bytes).toString("base64");
|
|
589
|
+
let s = "";
|
|
590
|
+
for (let i = 0; i < bytes.length; i++) s += String.fromCharCode(bytes[i]);
|
|
591
|
+
return btoa(s);
|
|
592
|
+
}
|
|
593
|
+
function fromBase64(b64) {
|
|
594
|
+
if (typeof Buffer !== "undefined") return new Uint8Array(Buffer.from(b64, "base64"));
|
|
595
|
+
const s = atob(b64);
|
|
596
|
+
const out = new Uint8Array(s.length);
|
|
597
|
+
for (let i = 0; i < s.length; i++) out[i] = s.charCodeAt(i);
|
|
598
|
+
return out;
|
|
599
|
+
}
|
|
600
|
+
function yTextAt(doc, pos) {
|
|
601
|
+
const block = doc.blocks.get(pos.blockIndex);
|
|
602
|
+
if (!block) return null;
|
|
603
|
+
if (typeof pos.cellIndex === "number") {
|
|
604
|
+
const cells = block.get("cells");
|
|
605
|
+
const cell = cells?.get(pos.cellIndex);
|
|
606
|
+
const t2 = cell?.get("text");
|
|
607
|
+
return t2 instanceof Y2.Text ? t2 : null;
|
|
608
|
+
}
|
|
609
|
+
const t = block.get("text");
|
|
610
|
+
return t instanceof Y2.Text ? t : null;
|
|
611
|
+
}
|
|
612
|
+
function locateYText(doc, target) {
|
|
613
|
+
const blocks = doc.blocks;
|
|
614
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
615
|
+
const block = blocks.get(i);
|
|
616
|
+
if (block.get("text") === target) return { blockIndex: i };
|
|
617
|
+
const cells = block.get("cells");
|
|
618
|
+
if (cells) {
|
|
619
|
+
for (let c = 0; c < cells.length; c++) {
|
|
620
|
+
if (cells.get(c)?.get("text") === target) {
|
|
621
|
+
return { blockIndex: i, cellIndex: c };
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
return null;
|
|
627
|
+
}
|
|
628
|
+
function encodePoint(doc, pos) {
|
|
629
|
+
const yText = yTextAt(doc, pos);
|
|
630
|
+
if (!yText) return null;
|
|
631
|
+
const offset = Math.max(0, Math.min(pos.offset, yText.length));
|
|
632
|
+
const rel = Y2.createRelativePositionFromTypeIndex(yText, offset);
|
|
633
|
+
const block = doc.blocks.get(pos.blockIndex);
|
|
634
|
+
const point = { rel: toBase64(Y2.encodeRelativePosition(rel)) };
|
|
635
|
+
const blockId = block ? getBlockId(block) : void 0;
|
|
636
|
+
if (blockId) point.blockId = blockId;
|
|
637
|
+
if (typeof pos.cellIndex === "number") point.cellIndex = pos.cellIndex;
|
|
638
|
+
return point;
|
|
639
|
+
}
|
|
640
|
+
function decodePoint(doc, enc) {
|
|
641
|
+
try {
|
|
642
|
+
const rel = Y2.decodeRelativePosition(fromBase64(enc.rel));
|
|
643
|
+
const abs = Y2.createAbsolutePositionFromRelativePosition(rel, doc.ydoc);
|
|
644
|
+
if (abs && abs.type instanceof Y2.Text) {
|
|
645
|
+
const loc = locateYText(doc, abs.type);
|
|
646
|
+
if (loc) return { ...loc, offset: abs.index };
|
|
647
|
+
}
|
|
648
|
+
} catch {
|
|
649
|
+
}
|
|
650
|
+
if (enc.blockId) {
|
|
651
|
+
for (let i = 0; i < doc.blocks.length; i++) {
|
|
652
|
+
if (getBlockId(doc.blocks.get(i)) === enc.blockId) {
|
|
653
|
+
const p = { blockIndex: i, offset: 0 };
|
|
654
|
+
if (typeof enc.cellIndex === "number") p.cellIndex = enc.cellIndex;
|
|
655
|
+
return p;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
return null;
|
|
660
|
+
}
|
|
661
|
+
function encodeSelection(doc, sel) {
|
|
662
|
+
const anchor = encodePoint(doc, sel.anchor);
|
|
663
|
+
const focus = encodePoint(doc, sel.focus);
|
|
664
|
+
if (!anchor || !focus) return null;
|
|
665
|
+
return { anchor, focus };
|
|
666
|
+
}
|
|
667
|
+
function decodeSelection(doc, enc) {
|
|
668
|
+
const anchor = decodePoint(doc, enc.anchor);
|
|
669
|
+
const focus = decodePoint(doc, enc.focus);
|
|
670
|
+
if (!anchor || !focus) return null;
|
|
671
|
+
return { anchor, focus };
|
|
672
|
+
}
|
|
673
|
+
|
|
540
674
|
// src/selection.ts
|
|
541
675
|
function isCollapsed(sel) {
|
|
542
676
|
return positionsEqual(sel.anchor, sel.focus);
|
|
@@ -565,6 +699,20 @@ function sameTextRun(a, b) {
|
|
|
565
699
|
}
|
|
566
700
|
|
|
567
701
|
// src/marks.ts
|
|
702
|
+
var ALL_MARKS = {
|
|
703
|
+
bold: true,
|
|
704
|
+
italic: true,
|
|
705
|
+
underline: true,
|
|
706
|
+
strike: true,
|
|
707
|
+
color: true,
|
|
708
|
+
fontFamily: true,
|
|
709
|
+
fontSize: true,
|
|
710
|
+
link: true,
|
|
711
|
+
comment: true
|
|
712
|
+
};
|
|
713
|
+
var CLEAR_ALL_MARKS = Object.fromEntries(
|
|
714
|
+
Object.keys(ALL_MARKS).map((k) => [k, null])
|
|
715
|
+
);
|
|
568
716
|
function iterateRunsInRange(yText, start, end, visit) {
|
|
569
717
|
if (start >= end) return;
|
|
570
718
|
const delta = yText.toDelta();
|
|
@@ -689,7 +837,87 @@ function sameMarkValue(a, b) {
|
|
|
689
837
|
}
|
|
690
838
|
|
|
691
839
|
// src/commands.ts
|
|
692
|
-
var
|
|
840
|
+
var Y3 = __toESM(require("yjs"), 1);
|
|
841
|
+
|
|
842
|
+
// src/clipboard.ts
|
|
843
|
+
var SOFER_MIME = "application/x-sofer-slice";
|
|
844
|
+
function deltaToText(delta) {
|
|
845
|
+
let s = "";
|
|
846
|
+
for (const op of delta) if (typeof op.insert === "string") s += op.insert;
|
|
847
|
+
return s;
|
|
848
|
+
}
|
|
849
|
+
function blockFromDelta(doc, blockIndex, cellIndex, delta) {
|
|
850
|
+
if (cellIndex != null) {
|
|
851
|
+
return { type: "paragraph", text: deltaToText(delta), delta, attrs: {} };
|
|
852
|
+
}
|
|
853
|
+
return {
|
|
854
|
+
type: doc.getBlockType(blockIndex) ?? "paragraph",
|
|
855
|
+
text: deltaToText(delta),
|
|
856
|
+
delta,
|
|
857
|
+
attrs: doc.getBlockAttrs(blockIndex)
|
|
858
|
+
};
|
|
859
|
+
}
|
|
860
|
+
function serializeSelection(doc, sel) {
|
|
861
|
+
if (isCollapsed(sel)) return null;
|
|
862
|
+
const { start, end } = orderedRange(sel);
|
|
863
|
+
if ((start.cellIndex ?? -1) !== (end.cellIndex ?? -1)) return null;
|
|
864
|
+
if (start.blockIndex === end.blockIndex) {
|
|
865
|
+
const yText = doc.textAt(start.blockIndex, start.cellIndex);
|
|
866
|
+
if (!yText) return null;
|
|
867
|
+
const delta = sliceDelta(yText.toDelta(), start.offset, end.offset);
|
|
868
|
+
return {
|
|
869
|
+
blocks: [blockFromDelta(doc, start.blockIndex, start.cellIndex, delta)],
|
|
870
|
+
openStart: start.offset > 0,
|
|
871
|
+
openEnd: end.offset < yText.length
|
|
872
|
+
};
|
|
873
|
+
}
|
|
874
|
+
if (start.cellIndex != null || end.cellIndex != null) return null;
|
|
875
|
+
for (let i = start.blockIndex; i <= end.blockIndex; i++) {
|
|
876
|
+
if (doc.getBlockType(i) === "table") return null;
|
|
877
|
+
}
|
|
878
|
+
const startText = doc.getBlockText(start.blockIndex);
|
|
879
|
+
const endText = doc.getBlockText(end.blockIndex);
|
|
880
|
+
if (!startText || !endText) return null;
|
|
881
|
+
const blocks = [];
|
|
882
|
+
blocks.push(
|
|
883
|
+
blockFromDelta(
|
|
884
|
+
doc,
|
|
885
|
+
start.blockIndex,
|
|
886
|
+
void 0,
|
|
887
|
+
sliceDelta(startText.toDelta(), start.offset, startText.length)
|
|
888
|
+
)
|
|
889
|
+
);
|
|
890
|
+
for (let i = start.blockIndex + 1; i < end.blockIndex; i++) {
|
|
891
|
+
const t = doc.getBlockText(i);
|
|
892
|
+
blocks.push(blockFromDelta(doc, i, void 0, t?.toDelta() ?? []));
|
|
893
|
+
}
|
|
894
|
+
blocks.push(
|
|
895
|
+
blockFromDelta(
|
|
896
|
+
doc,
|
|
897
|
+
end.blockIndex,
|
|
898
|
+
void 0,
|
|
899
|
+
sliceDelta(endText.toDelta(), 0, end.offset)
|
|
900
|
+
)
|
|
901
|
+
);
|
|
902
|
+
return {
|
|
903
|
+
blocks,
|
|
904
|
+
openStart: start.offset > 0,
|
|
905
|
+
openEnd: end.offset < endText.length
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
function sliceToText(slice) {
|
|
909
|
+
return slice.blocks.map((b) => deltaToText(b.delta)).join("\n");
|
|
910
|
+
}
|
|
911
|
+
function sliceToInlineDelta(slice) {
|
|
912
|
+
const out = [];
|
|
913
|
+
slice.blocks.forEach((b, i) => {
|
|
914
|
+
if (i > 0) out.push({ insert: "\n" });
|
|
915
|
+
out.push(...b.delta);
|
|
916
|
+
});
|
|
917
|
+
return out;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
// src/commands.ts
|
|
693
921
|
var COMMAND_ORIGIN = /* @__PURE__ */ Symbol("editor-command");
|
|
694
922
|
function transact(doc, fn) {
|
|
695
923
|
doc.ydoc.transact(fn, COMMAND_ORIGIN);
|
|
@@ -898,7 +1126,7 @@ function setBlockType(ctx, type, attrs) {
|
|
|
898
1126
|
const block = ctx.doc.getBlock(i);
|
|
899
1127
|
if (!block) continue;
|
|
900
1128
|
block.set("type", type);
|
|
901
|
-
const attrsMap = block.get("attrs") ?? new
|
|
1129
|
+
const attrsMap = block.get("attrs") ?? new Y3.Map();
|
|
902
1130
|
if (!block.get("attrs")) block.set("attrs", attrsMap);
|
|
903
1131
|
const next = { ...defaultAttrsFor(type), ...attrs ?? {} };
|
|
904
1132
|
const keep = new Set(Object.keys(next));
|
|
@@ -921,7 +1149,7 @@ function setBlockAttr(ctx, key, value) {
|
|
|
921
1149
|
for (const i of indices) {
|
|
922
1150
|
const block = ctx.doc.getBlock(i);
|
|
923
1151
|
if (!block) continue;
|
|
924
|
-
const attrsMap = block.get("attrs") ?? new
|
|
1152
|
+
const attrsMap = block.get("attrs") ?? new Y3.Map();
|
|
925
1153
|
if (!block.get("attrs")) block.set("attrs", attrsMap);
|
|
926
1154
|
if (value === null || value === void 0) {
|
|
927
1155
|
attrsMap.delete(key);
|
|
@@ -932,6 +1160,109 @@ function setBlockAttr(ctx, key, value) {
|
|
|
932
1160
|
ctx.setSelection(sel);
|
|
933
1161
|
});
|
|
934
1162
|
}
|
|
1163
|
+
function setCellAttr(ctx, key, value) {
|
|
1164
|
+
transact(ctx.doc, () => {
|
|
1165
|
+
const sel = ctx.getSelection();
|
|
1166
|
+
const { blockIndex, cellIndex } = sel.focus;
|
|
1167
|
+
if (cellIndex == null || !ctx.doc.isTable(blockIndex)) return;
|
|
1168
|
+
const { cols } = ctx.doc.getTableSize(blockIndex);
|
|
1169
|
+
if (cols <= 0) return;
|
|
1170
|
+
const rect = tableRectSelection(ctx.doc, sel);
|
|
1171
|
+
const targets = [];
|
|
1172
|
+
if (rect) {
|
|
1173
|
+
for (let r = rect.top; r <= rect.bottom; r++)
|
|
1174
|
+
for (let c = rect.left; c <= rect.right; c++) targets.push(r * cols + c);
|
|
1175
|
+
} else {
|
|
1176
|
+
const real = ctx.doc.realCellIndex(blockIndex, cellIndex);
|
|
1177
|
+
if (real != null) targets.push(real);
|
|
1178
|
+
}
|
|
1179
|
+
for (const flat of targets) {
|
|
1180
|
+
if (ctx.doc.getCellAttrs(blockIndex, flat).covered) continue;
|
|
1181
|
+
const m = ctx.doc.getCellAttrsMap(blockIndex, flat);
|
|
1182
|
+
if (!m) continue;
|
|
1183
|
+
if (value === null || value === void 0) m.delete(key);
|
|
1184
|
+
else m.set(key, value);
|
|
1185
|
+
}
|
|
1186
|
+
ctx.setSelection(sel);
|
|
1187
|
+
});
|
|
1188
|
+
}
|
|
1189
|
+
function deleteSelection(ctx) {
|
|
1190
|
+
transact(ctx.doc, () => {
|
|
1191
|
+
const s = deleteRange(ctx.doc, ctx.getSelection());
|
|
1192
|
+
ctx.setSelection(s);
|
|
1193
|
+
});
|
|
1194
|
+
}
|
|
1195
|
+
function insertSlice(ctx, slice) {
|
|
1196
|
+
if (!slice.blocks || slice.blocks.length === 0) return;
|
|
1197
|
+
transact(ctx.doc, () => {
|
|
1198
|
+
let sel = ctx.getSelection();
|
|
1199
|
+
if (!isCollapsed(sel)) sel = deleteRange(ctx.doc, sel);
|
|
1200
|
+
const { blockIndex, cellIndex, offset } = sel.focus;
|
|
1201
|
+
if (cellIndex != null) {
|
|
1202
|
+
const cellText = ctx.doc.textAt(blockIndex, cellIndex);
|
|
1203
|
+
if (!cellText) return;
|
|
1204
|
+
const after = writeDeltaInto(cellText, offset, sliceToInlineDelta(slice));
|
|
1205
|
+
ctx.setSelection(collapsedSelection({ blockIndex, cellIndex, offset: after }));
|
|
1206
|
+
return;
|
|
1207
|
+
}
|
|
1208
|
+
const targetText = ctx.doc.getBlockText(blockIndex);
|
|
1209
|
+
if (!targetText) return;
|
|
1210
|
+
const full = targetText.toDelta();
|
|
1211
|
+
const tailDelta = sliceDelta(full, offset, deltaLength(full));
|
|
1212
|
+
targetText.delete(offset, targetText.length - offset);
|
|
1213
|
+
const blocks = slice.blocks;
|
|
1214
|
+
if (blocks.length === 1) {
|
|
1215
|
+
const afterS0 = writeDeltaInto(targetText, offset, blocks[0].delta);
|
|
1216
|
+
writeDeltaInto(targetText, afterS0, tailDelta);
|
|
1217
|
+
ctx.setSelection(collapsedSelection({ blockIndex, offset: afterS0 }));
|
|
1218
|
+
return;
|
|
1219
|
+
}
|
|
1220
|
+
const originalType = ctx.doc.getBlockType(blockIndex);
|
|
1221
|
+
const originalAttrs = ctx.doc.getBlockAttrs(blockIndex);
|
|
1222
|
+
let insertAt = blockIndex;
|
|
1223
|
+
if (slice.openStart) {
|
|
1224
|
+
writeDeltaInto(targetText, offset, blocks[0].delta);
|
|
1225
|
+
} else if (offset === 0) {
|
|
1226
|
+
const blk = ctx.doc.blocks.get(blockIndex);
|
|
1227
|
+
blk.set("type", blocks[0].type);
|
|
1228
|
+
const am = blk.get("attrs");
|
|
1229
|
+
am.clear();
|
|
1230
|
+
for (const [k, v] of Object.entries(blocks[0].attrs)) {
|
|
1231
|
+
if (v !== void 0) am.set(k, v);
|
|
1232
|
+
}
|
|
1233
|
+
writeDeltaInto(targetText, 0, blocks[0].delta);
|
|
1234
|
+
} else {
|
|
1235
|
+
const b = createBlock(blocks[0].type, "", blocks[0].attrs);
|
|
1236
|
+
ctx.doc.blocks.insert(++insertAt, [b]);
|
|
1237
|
+
writeDeltaInto(b.get("text"), 0, blocks[0].delta);
|
|
1238
|
+
}
|
|
1239
|
+
for (let i = 1; i < blocks.length - 1; i++) {
|
|
1240
|
+
const b = createBlock(blocks[i].type, "", blocks[i].attrs);
|
|
1241
|
+
ctx.doc.blocks.insert(++insertAt, [b]);
|
|
1242
|
+
writeDeltaInto(b.get("text"), 0, blocks[i].delta);
|
|
1243
|
+
}
|
|
1244
|
+
const last = blocks[blocks.length - 1];
|
|
1245
|
+
if (slice.openEnd) {
|
|
1246
|
+
const b = createBlock(last.type, "", last.attrs);
|
|
1247
|
+
ctx.doc.blocks.insert(++insertAt, [b]);
|
|
1248
|
+
const t = b.get("text");
|
|
1249
|
+
const caretPos = writeDeltaInto(t, 0, last.delta);
|
|
1250
|
+
writeDeltaInto(t, caretPos, tailDelta);
|
|
1251
|
+
ctx.setSelection(collapsedSelection({ blockIndex: insertAt, offset: caretPos }));
|
|
1252
|
+
} else {
|
|
1253
|
+
const b = createBlock(last.type, "", last.attrs);
|
|
1254
|
+
ctx.doc.blocks.insert(++insertAt, [b]);
|
|
1255
|
+
const lastLen = writeDeltaInto(b.get("text"), 0, last.delta);
|
|
1256
|
+
const lastIdx = insertAt;
|
|
1257
|
+
if (tailDelta.length > 0) {
|
|
1258
|
+
const tb = createBlock(originalType ?? "paragraph", "", originalAttrs);
|
|
1259
|
+
ctx.doc.blocks.insert(++insertAt, [tb]);
|
|
1260
|
+
writeDeltaInto(tb.get("text"), 0, tailDelta);
|
|
1261
|
+
}
|
|
1262
|
+
ctx.setSelection(collapsedSelection({ blockIndex: lastIdx, offset: lastLen }));
|
|
1263
|
+
}
|
|
1264
|
+
});
|
|
1265
|
+
}
|
|
935
1266
|
function selectedBlockIndices(sel, blockCount) {
|
|
936
1267
|
const { start, end } = orderedRange(sel);
|
|
937
1268
|
const out = [];
|
|
@@ -1081,7 +1412,7 @@ function setBlockTypeAtIndex(doc, index, type, attrs) {
|
|
|
1081
1412
|
const block = doc.getBlock(index);
|
|
1082
1413
|
if (!block) return;
|
|
1083
1414
|
block.set("type", type);
|
|
1084
|
-
const attrsMap = block.get("attrs") ?? new
|
|
1415
|
+
const attrsMap = block.get("attrs") ?? new Y3.Map();
|
|
1085
1416
|
if (!block.get("attrs")) block.set("attrs", attrsMap);
|
|
1086
1417
|
const next = { ...defaultAttrsFor(type), ...attrs };
|
|
1087
1418
|
const keep = new Set(Object.keys(next));
|
|
@@ -1105,6 +1436,9 @@ function insertTable(ctx, rows, cols) {
|
|
|
1105
1436
|
const focusBlock = Math.max(0, Math.min(sel.focus.blockIndex, ctx.doc.blockCount() - 1));
|
|
1106
1437
|
const insertAt = focusBlock + 1;
|
|
1107
1438
|
ctx.doc.blocks.insert(insertAt, [createTableBlock(r, c)]);
|
|
1439
|
+
if (insertAt === ctx.doc.blockCount() - 1) {
|
|
1440
|
+
ctx.doc.blocks.insert(insertAt + 1, [createBlock("paragraph")]);
|
|
1441
|
+
}
|
|
1108
1442
|
ctx.setSelection(
|
|
1109
1443
|
collapsedSelection({ blockIndex: insertAt, cellIndex: 0, offset: 0 })
|
|
1110
1444
|
);
|
|
@@ -1713,11 +2047,10 @@ function writeDeltaInto(yText, pos, delta) {
|
|
|
1713
2047
|
for (const op of delta) {
|
|
1714
2048
|
if (typeof op.insert === "string") {
|
|
1715
2049
|
if (op.insert.length === 0) continue;
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
}
|
|
2050
|
+
yText.insert(cursor, op.insert, {
|
|
2051
|
+
...CLEAR_ALL_MARKS,
|
|
2052
|
+
...op.attributes ?? {}
|
|
2053
|
+
});
|
|
1721
2054
|
cursor += op.insert.length;
|
|
1722
2055
|
} else if (op.insert != null) {
|
|
1723
2056
|
if (op.attributes && Object.keys(op.attributes).length > 0) {
|
|
@@ -1777,17 +2110,56 @@ function setImageAttrs(ctx, blockIndex, embedOffset, partial, cellIndex, newOffs
|
|
|
1777
2110
|
yText.insert(insertAt, merged);
|
|
1778
2111
|
});
|
|
1779
2112
|
}
|
|
2113
|
+
var REANCHORABLE_LAYOUTS = /* @__PURE__ */ new Set(["front", "behind"]);
|
|
2114
|
+
function moveEmbedAnchor(ctx, from, to, newOffsetX, newOffsetY) {
|
|
2115
|
+
transact(ctx.doc, () => {
|
|
2116
|
+
const srcText = ctx.doc.textAt(from.blockIndex, from.cellIndex);
|
|
2117
|
+
if (!srcText) return;
|
|
2118
|
+
const delta = srcText.toDelta();
|
|
2119
|
+
let cursor = 0;
|
|
2120
|
+
let prev = null;
|
|
2121
|
+
for (const op of delta) {
|
|
2122
|
+
if (typeof op.insert === "string") {
|
|
2123
|
+
cursor += op.insert.length;
|
|
2124
|
+
continue;
|
|
2125
|
+
}
|
|
2126
|
+
if (cursor === from.offset && isImageEmbed(op.insert)) {
|
|
2127
|
+
prev = op.insert;
|
|
2128
|
+
break;
|
|
2129
|
+
}
|
|
2130
|
+
cursor += 1;
|
|
2131
|
+
}
|
|
2132
|
+
if (!prev) return;
|
|
2133
|
+
const layout = prev.layout ?? "inline";
|
|
2134
|
+
if (!REANCHORABLE_LAYOUTS.has(layout)) return;
|
|
2135
|
+
const dstText = ctx.doc.textAt(to.blockIndex, to.cellIndex);
|
|
2136
|
+
if (!dstText) return;
|
|
2137
|
+
const merged = { ...prev, offsetX: newOffsetX, offsetY: newOffsetY };
|
|
2138
|
+
const sameRun = srcText === dstText;
|
|
2139
|
+
srcText.delete(from.offset, 1);
|
|
2140
|
+
let landed = to.offset;
|
|
2141
|
+
if (sameRun && to.offset > from.offset) {
|
|
2142
|
+
landed = to.offset - 1;
|
|
2143
|
+
}
|
|
2144
|
+
landed = Math.max(0, Math.min(landed, dstText.length));
|
|
2145
|
+
dstText.insert(landed, merged);
|
|
2146
|
+
ctx.setSelection({
|
|
2147
|
+
anchor: { blockIndex: to.blockIndex, cellIndex: to.cellIndex, offset: landed },
|
|
2148
|
+
focus: { blockIndex: to.blockIndex, cellIndex: to.cellIndex, offset: landed + 1 }
|
|
2149
|
+
});
|
|
2150
|
+
});
|
|
2151
|
+
}
|
|
1780
2152
|
function isCommandOrigin(origin) {
|
|
1781
2153
|
return origin === COMMAND_ORIGIN;
|
|
1782
2154
|
}
|
|
1783
2155
|
var TRACKED_ORIGINS = /* @__PURE__ */ new Set([COMMAND_ORIGIN]);
|
|
1784
2156
|
|
|
1785
2157
|
// src/history.ts
|
|
1786
|
-
var
|
|
2158
|
+
var Y4 = __toESM(require("yjs"), 1);
|
|
1787
2159
|
var EditorHistory = class {
|
|
1788
2160
|
undoManager;
|
|
1789
2161
|
constructor(doc) {
|
|
1790
|
-
this.undoManager = new
|
|
2162
|
+
this.undoManager = new Y4.UndoManager(doc.blocks, {
|
|
1791
2163
|
trackedOrigins: TRACKED_ORIGINS,
|
|
1792
2164
|
captureTimeout: 400
|
|
1793
2165
|
});
|
|
@@ -1805,6 +2177,7 @@ var EditorHistory = class {
|
|
|
1805
2177
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1806
2178
|
0 && (module.exports = {
|
|
1807
2179
|
BLOCK_SPECS,
|
|
2180
|
+
CLEAR_ALL_MARKS,
|
|
1808
2181
|
COMMAND_ORIGIN,
|
|
1809
2182
|
DEFAULT_PAGE_SETTINGS,
|
|
1810
2183
|
EditorDocument,
|
|
@@ -1812,6 +2185,7 @@ var EditorHistory = class {
|
|
|
1812
2185
|
MARGIN_PRESETS,
|
|
1813
2186
|
MAX_LIST_LEVEL,
|
|
1814
2187
|
PAGE_PRESETS,
|
|
2188
|
+
SOFER_MIME,
|
|
1815
2189
|
TRACKED_ORIGINS,
|
|
1816
2190
|
Y,
|
|
1817
2191
|
cellsInRect,
|
|
@@ -1821,20 +2195,25 @@ var EditorHistory = class {
|
|
|
1821
2195
|
createBlock,
|
|
1822
2196
|
createCell,
|
|
1823
2197
|
createTableBlock,
|
|
2198
|
+
decodeSelection,
|
|
1824
2199
|
dedentList,
|
|
1825
2200
|
defaultAttrsFor,
|
|
1826
2201
|
deleteBackward,
|
|
1827
2202
|
deleteForward,
|
|
2203
|
+
deleteSelection,
|
|
1828
2204
|
deleteTable,
|
|
1829
2205
|
deleteTableColumn,
|
|
1830
2206
|
deleteTableRow,
|
|
1831
2207
|
deltaLength,
|
|
1832
2208
|
detectPreset,
|
|
2209
|
+
encodeSelection,
|
|
1833
2210
|
expandTableRect,
|
|
2211
|
+
getBlockId,
|
|
1834
2212
|
getMarksInRange,
|
|
1835
2213
|
indentList,
|
|
1836
2214
|
insertImage,
|
|
1837
2215
|
insertParagraph,
|
|
2216
|
+
insertSlice,
|
|
1838
2217
|
insertTable,
|
|
1839
2218
|
insertTableColumn,
|
|
1840
2219
|
insertTableRow,
|
|
@@ -1849,19 +2228,25 @@ var EditorHistory = class {
|
|
|
1849
2228
|
mergeRight,
|
|
1850
2229
|
mergeSelection,
|
|
1851
2230
|
mmToPx,
|
|
2231
|
+
moveEmbedAnchor,
|
|
1852
2232
|
moveToNextCell,
|
|
1853
2233
|
moveToPrevCell,
|
|
2234
|
+
newBlockId,
|
|
1854
2235
|
orderedRange,
|
|
1855
2236
|
positionsEqual,
|
|
1856
2237
|
pxToMm,
|
|
1857
2238
|
removeMark,
|
|
1858
2239
|
sameTextRun,
|
|
2240
|
+
serializeSelection,
|
|
1859
2241
|
setBlockAttr,
|
|
1860
2242
|
setBlockType,
|
|
2243
|
+
setCellAttr,
|
|
1861
2244
|
setColumnWidth,
|
|
1862
2245
|
setImageAttrs,
|
|
1863
2246
|
setMark,
|
|
1864
2247
|
sliceDelta,
|
|
2248
|
+
sliceToInlineDelta,
|
|
2249
|
+
sliceToText,
|
|
1865
2250
|
spanOf,
|
|
1866
2251
|
splitCell,
|
|
1867
2252
|
splitListItem,
|