@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 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: () => Y2,
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
- return createBlock(block.type, "", block.attrs);
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 Y2 = __toESM(require("yjs"), 1);
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 Y2.Map();
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 Y2.Map();
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 Y2.Map();
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
- if (op.attributes && Object.keys(op.attributes).length > 0) {
1717
- yText.insert(cursor, op.insert, op.attributes);
1718
- } else {
1719
- yText.insert(cursor, op.insert);
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 Y3 = __toESM(require("yjs"), 1);
2158
+ var Y4 = __toESM(require("yjs"), 1);
1787
2159
  var EditorHistory = class {
1788
2160
  undoManager;
1789
2161
  constructor(doc) {
1790
- this.undoManager = new Y3.UndoManager(doc.blocks, {
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,