@sofereditor/react 0.6.0 → 0.7.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
@@ -55,7 +55,7 @@ module.exports = __toCommonJS(index_exports);
55
55
 
56
56
  // src/Editor.tsx
57
57
  var import_react14 = require("react");
58
- var import_core8 = require("@sofereditor/core");
58
+ var import_core9 = require("@sofereditor/core");
59
59
 
60
60
  // src/dom-bridge.ts
61
61
  function findContainingBlockElement(node, root) {
@@ -335,6 +335,11 @@ var import_core2 = require("@sofereditor/core");
335
335
 
336
336
  // src/htmlToSlice.ts
337
337
  var import_core = require("@sofereditor/core");
338
+
339
+ // src/imageConstraints.ts
340
+ var MAX_INSERT_WIDTH = 600;
341
+
342
+ // src/htmlToSlice.ts
338
343
  function htmlToSlice(html) {
339
344
  if (!html || html.trim().length === 0) return null;
340
345
  let doc;
@@ -353,8 +358,10 @@ function htmlToSlice(html) {
353
358
  }
354
359
  if (blocks.length === 0) return null;
355
360
  normalizeListLevels(blocks);
356
- const temTexto = blocks.some((b) => b.text.trim().length > 0);
357
- if (!temTexto) return null;
361
+ const temConteudo = blocks.some(
362
+ (b) => b.text.trim().length > 0 || b.delta.some((op) => (0, import_core.isImageEmbed)(op.insert))
363
+ );
364
+ if (!temConteudo) return null;
358
365
  const blockLevel = blocks.length > 1 || blocks[0].type !== "paragraph";
359
366
  return { blocks, openStart: false, openEnd: false, ...blockLevel ? { blockLevel: true } : {} };
360
367
  }
@@ -465,6 +472,7 @@ function walkBlockLevel(container, marks, blocks) {
465
472
  break;
466
473
  }
467
474
  case "img":
475
+ loose.push(node);
468
476
  break;
469
477
  case "br":
470
478
  loose.push(node);
@@ -657,7 +665,11 @@ function walkInlineNode(node, marks, ops) {
657
665
  const el = node;
658
666
  const tag = el.tagName.toLowerCase();
659
667
  if (IGNORED_TAGS.has(tag) || isNamespacedTag(tag)) return;
660
- if (tag === "img") return;
668
+ if (tag === "img") {
669
+ const op = imageEmbedFromElement(el);
670
+ if (op) ops.push(op);
671
+ return;
672
+ }
661
673
  if (tag === "br") {
662
674
  ops.push({ insert: " " });
663
675
  return;
@@ -672,6 +684,73 @@ function walkInlineNode(node, marks, ops) {
672
684
  }
673
685
  for (const child of Array.from(el.childNodes)) walkInlineNode(child, nextMarks, ops);
674
686
  }
687
+ var MIN_EMBED_BYTES = 1024;
688
+ function decodedDataUrlByteLength(dataUrl) {
689
+ const commaIndex = dataUrl.indexOf(",");
690
+ if (commaIndex === -1) return 0;
691
+ const meta = dataUrl.slice(0, commaIndex);
692
+ const payload = dataUrl.slice(commaIndex + 1);
693
+ if (/;base64$/i.test(meta)) {
694
+ const padding = payload.endsWith("==") ? 2 : payload.endsWith("=") ? 1 : 0;
695
+ return Math.max(0, Math.floor(payload.length * 3 / 4) - padding);
696
+ }
697
+ try {
698
+ return decodeURIComponent(payload).length;
699
+ } catch {
700
+ return payload.length;
701
+ }
702
+ }
703
+ function imageEmbedFromElement(el) {
704
+ const src = el.getAttribute("src");
705
+ if (!src || !src.startsWith("data:image/")) return null;
706
+ if (decodedDataUrlByteLength(src) < MIN_EMBED_BYTES) return null;
707
+ const style = parseStyle(el.getAttribute("style"));
708
+ const width = readImageDimension(el, "width", style);
709
+ const height = readImageDimension(el, "height", style);
710
+ if (width == null || height == null) return null;
711
+ let w = width;
712
+ let h = height;
713
+ if (w > MAX_INSERT_WIDTH) {
714
+ h = h * MAX_INSERT_WIDTH / w;
715
+ w = MAX_INSERT_WIDTH;
716
+ }
717
+ return { insert: { type: "image", src, width: Math.round(w), height: Math.round(h) } };
718
+ }
719
+ function readImageDimension(el, attr, style) {
720
+ const raw = el.getAttribute(attr);
721
+ if (raw && /^\d+(\.\d+)?$/.test(raw.trim())) {
722
+ const n = Number.parseFloat(raw);
723
+ if (Number.isFinite(n) && n > 0) return n;
724
+ }
725
+ const fromStyle = style[attr];
726
+ if (fromStyle) {
727
+ const n = cssLengthToPx(fromStyle);
728
+ if (n != null) return n;
729
+ }
730
+ return void 0;
731
+ }
732
+ function cssLengthToPx(raw) {
733
+ const v = raw.trim();
734
+ const m = /^(-?[\d.]+)\s*(px|pt|in|cm|mm)?$/i.exec(v);
735
+ if (!m) return void 0;
736
+ const num = Number.parseFloat(m[1]);
737
+ if (!Number.isFinite(num) || num <= 0) return void 0;
738
+ const unit = (m[2] ?? "px").toLowerCase();
739
+ switch (unit) {
740
+ case "px":
741
+ return num;
742
+ case "pt":
743
+ return num * (96 / 72);
744
+ case "in":
745
+ return num * 96;
746
+ case "cm":
747
+ return num * (96 / 2.54);
748
+ case "mm":
749
+ return num * (96 / 25.4);
750
+ default:
751
+ return void 0;
752
+ }
753
+ }
675
754
  function applyTagMarks(tag, marks) {
676
755
  switch (tag) {
677
756
  case "b":
@@ -939,6 +1018,58 @@ function planPaste(cd) {
939
1018
  return { kind: "none" };
940
1019
  }
941
1020
 
1021
+ // src/resolvePastedImages.ts
1022
+ var import_core3 = require("@sofereditor/core");
1023
+ function sliceHasDataImageEmbeds(slice) {
1024
+ return slice.blocks.some(
1025
+ (b) => b.delta.some((op) => (0, import_core3.isImageEmbed)(op.insert) && op.insert.src.startsWith("data:image/"))
1026
+ );
1027
+ }
1028
+ async function resolvePastedImageUploads(slice, upload) {
1029
+ if (!upload) return slice;
1030
+ const blocks = await Promise.all(
1031
+ slice.blocks.map(async (block) => {
1032
+ let changed = false;
1033
+ const delta = await Promise.all(
1034
+ block.delta.map(async (op) => {
1035
+ if (!(0, import_core3.isImageEmbed)(op.insert) || !op.insert.src.startsWith("data:image/")) return op;
1036
+ try {
1037
+ const file = await dataUrlToFile(op.insert.src);
1038
+ const newSrc = await upload(file);
1039
+ changed = true;
1040
+ return { ...op, insert: { ...op.insert, src: newSrc } };
1041
+ } catch (err) {
1042
+ console.error(
1043
+ "[sofereditor] falha ao subir imagem colada para o storage \u2014 mantendo a imagem embutida (data:) nesta colagem",
1044
+ err
1045
+ );
1046
+ return op;
1047
+ }
1048
+ })
1049
+ );
1050
+ return changed ? { ...block, delta } : block;
1051
+ })
1052
+ );
1053
+ return { ...slice, blocks };
1054
+ }
1055
+ async function dataUrlToFile(dataUrl) {
1056
+ const blob = await fetch(dataUrl).then((r) => r.blob());
1057
+ const mime = blob.type;
1058
+ return new File([blob], `imagem-colada-${Date.now()}.${extensionForMime(mime)}`, { type: mime });
1059
+ }
1060
+ var MIME_EXTENSIONS = {
1061
+ "image/png": "png",
1062
+ "image/jpeg": "jpg",
1063
+ "image/jpg": "jpg",
1064
+ "image/gif": "gif",
1065
+ "image/webp": "webp",
1066
+ "image/bmp": "bmp",
1067
+ "image/svg+xml": "svg"
1068
+ };
1069
+ function extensionForMime(mime) {
1070
+ return MIME_EXTENSIONS[mime.toLowerCase()] ?? "png";
1071
+ }
1072
+
942
1073
  // src/BehindImageSelectAffordance.tsx
943
1074
  var import_react = require("react");
944
1075
  var import_jsx_runtime = require("react/jsx-runtime");
@@ -1255,7 +1386,7 @@ function LinkDialog() {
1255
1386
 
1256
1387
  // src/PageConfigDialog.tsx
1257
1388
  var import_react3 = require("react");
1258
- var import_core3 = require("@sofereditor/core");
1389
+ var import_core4 = require("@sofereditor/core");
1259
1390
  var import_jsx_runtime4 = require("react/jsx-runtime");
1260
1391
  function PageConfigDialog() {
1261
1392
  const { pageConfigRequest, resolvePageConfigRequest, setPageSettings } = useEditorContext();
@@ -1289,14 +1420,14 @@ function PageConfigDialog() {
1289
1420
  }, [pageConfigRequest]);
1290
1421
  (0, import_react3.useEffect)(() => {
1291
1422
  if (sizePreset === "custom") return;
1292
- const p = import_core3.PAGE_PRESETS[sizePreset];
1293
- setWidthMm(roundMm((0, import_core3.pxToMm)(p.width)));
1294
- setHeightMm(roundMm((0, import_core3.pxToMm)(p.height)));
1423
+ const p = import_core4.PAGE_PRESETS[sizePreset];
1424
+ setWidthMm(roundMm((0, import_core4.pxToMm)(p.width)));
1425
+ setHeightMm(roundMm((0, import_core4.pxToMm)(p.height)));
1295
1426
  }, [sizePreset]);
1296
1427
  (0, import_react3.useEffect)(() => {
1297
1428
  if (marginPreset === "custom") return;
1298
- const px = import_core3.MARGIN_PRESETS[marginPreset];
1299
- const mm = roundMm((0, import_core3.pxToMm)(px));
1429
+ const px = import_core4.MARGIN_PRESETS[marginPreset];
1430
+ const mm = roundMm((0, import_core4.pxToMm)(px));
1300
1431
  setMarginTopMm(mm);
1301
1432
  setMarginBottomMm(mm);
1302
1433
  setMarginLeftMm(mm);
@@ -1305,8 +1436,8 @@ function PageConfigDialog() {
1305
1436
  const customWidth = sizePreset === "custom";
1306
1437
  const previewPx = (0, import_react3.useMemo)(
1307
1438
  () => ({
1308
- width: Math.round((0, import_core3.mmToPx)(widthMm)),
1309
- height: Math.round((0, import_core3.mmToPx)(heightMm))
1439
+ width: Math.round((0, import_core4.mmToPx)(widthMm)),
1440
+ height: Math.round((0, import_core4.mmToPx)(heightMm))
1310
1441
  }),
1311
1442
  [widthMm, heightMm]
1312
1443
  );
@@ -1314,12 +1445,12 @@ function PageConfigDialog() {
1314
1445
  const onApply = (e) => {
1315
1446
  e.preventDefault();
1316
1447
  const next = {
1317
- width: (0, import_core3.mmToPx)(widthMm),
1318
- height: (0, import_core3.mmToPx)(heightMm),
1319
- marginTop: (0, import_core3.mmToPx)(marginTopMm),
1320
- marginBottom: (0, import_core3.mmToPx)(marginBottomMm),
1321
- marginLeft: (0, import_core3.mmToPx)(marginLeftMm),
1322
- marginRight: (0, import_core3.mmToPx)(marginRightMm)
1448
+ width: (0, import_core4.mmToPx)(widthMm),
1449
+ height: (0, import_core4.mmToPx)(heightMm),
1450
+ marginTop: (0, import_core4.mmToPx)(marginTopMm),
1451
+ marginBottom: (0, import_core4.mmToPx)(marginBottomMm),
1452
+ marginLeft: (0, import_core4.mmToPx)(marginLeftMm),
1453
+ marginRight: (0, import_core4.mmToPx)(marginRightMm)
1323
1454
  };
1324
1455
  setPageSettings(next);
1325
1456
  resolvePageConfigRequest(true);
@@ -1578,14 +1709,14 @@ function roundMm(mm) {
1578
1709
  return Math.round(mm * 10) / 10;
1579
1710
  }
1580
1711
  function hydrateFromSettings(s, setters) {
1581
- const preset = (0, import_core3.detectPreset)(s.width, s.height);
1712
+ const preset = (0, import_core4.detectPreset)(s.width, s.height);
1582
1713
  setters.setSizePreset(preset);
1583
- setters.setWidthMm(roundMm((0, import_core3.pxToMm)(s.width)));
1584
- setters.setHeightMm(roundMm((0, import_core3.pxToMm)(s.height)));
1585
- const top = roundMm((0, import_core3.pxToMm)(s.marginTop));
1586
- const bottom = roundMm((0, import_core3.pxToMm)(s.marginBottom));
1587
- const left = roundMm((0, import_core3.pxToMm)(s.marginLeft));
1588
- const right = roundMm((0, import_core3.pxToMm)(s.marginRight));
1714
+ setters.setWidthMm(roundMm((0, import_core4.pxToMm)(s.width)));
1715
+ setters.setHeightMm(roundMm((0, import_core4.pxToMm)(s.height)));
1716
+ const top = roundMm((0, import_core4.pxToMm)(s.marginTop));
1717
+ const bottom = roundMm((0, import_core4.pxToMm)(s.marginBottom));
1718
+ const left = roundMm((0, import_core4.pxToMm)(s.marginLeft));
1719
+ const right = roundMm((0, import_core4.pxToMm)(s.marginRight));
1589
1720
  setters.setMarginTopMm(top);
1590
1721
  setters.setMarginBottomMm(bottom);
1591
1722
  setters.setMarginLeftMm(left);
@@ -1596,7 +1727,7 @@ function detectMarginPreset(s) {
1596
1727
  const TOL = 1;
1597
1728
  const allEqual = Math.abs(s.marginTop - s.marginBottom) <= TOL && Math.abs(s.marginTop - s.marginLeft) <= TOL && Math.abs(s.marginTop - s.marginRight) <= TOL;
1598
1729
  if (!allEqual) return "custom";
1599
- for (const [name, px] of Object.entries(import_core3.MARGIN_PRESETS)) {
1730
+ for (const [name, px] of Object.entries(import_core4.MARGIN_PRESETS)) {
1600
1731
  if (Math.abs(s.marginTop - px) <= TOL) return name;
1601
1732
  }
1602
1733
  return "custom";
@@ -2156,7 +2287,7 @@ function Handle({
2156
2287
 
2157
2288
  // src/RemoteCursorsOverlay.tsx
2158
2289
  var import_react7 = require("react");
2159
- var import_core4 = require("@sofereditor/core");
2290
+ var import_core5 = require("@sofereditor/core");
2160
2291
  var import_jsx_runtime8 = require("react/jsx-runtime");
2161
2292
  var DEFAULT_COLOR = "#3b82f6";
2162
2293
  function RemoteCursorsOverlay({
@@ -2179,7 +2310,7 @@ function RemoteCursorsOverlay({
2179
2310
  if (clientId === awareness.clientID) return;
2180
2311
  const s = state;
2181
2312
  if (!s.cursor) return;
2182
- const sel = (0, import_core4.decodeSelection)(doc, s.cursor);
2313
+ const sel = (0, import_core5.decodeSelection)(doc, s.cursor);
2183
2314
  if (!sel) return;
2184
2315
  const color = s.user?.color || DEFAULT_COLOR;
2185
2316
  const name = s.user?.name || "An\xF4nimo";
@@ -2326,11 +2457,11 @@ function RemoteCursorsOverlay({
2326
2457
 
2327
2458
  // src/NodeView.tsx
2328
2459
  var import_react10 = require("react");
2329
- var import_core6 = require("@sofereditor/core");
2460
+ var import_core7 = require("@sofereditor/core");
2330
2461
 
2331
2462
  // src/renderInline.tsx
2332
2463
  var import_react8 = require("react");
2333
- var import_core5 = require("@sofereditor/core");
2464
+ var import_core6 = require("@sofereditor/core");
2334
2465
  var import_jsx_runtime9 = require("react/jsx-runtime");
2335
2466
  function renderInline(delta, keyPrefix) {
2336
2467
  if (delta.length === 0 || delta.length === 1 && typeof delta[0].insert === "string" && delta[0].insert === "") {
@@ -2346,7 +2477,7 @@ function renderInline(delta, keyPrefix) {
2346
2477
  const key = `${keyPrefix}-${offset}`;
2347
2478
  body.push(/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react8.Fragment, { children: wrap(text, op.attributes) }, key));
2348
2479
  offset += text.length;
2349
- } else if ((0, import_core5.isImageEmbed)(op.insert)) {
2480
+ } else if ((0, import_core6.isImageEmbed)(op.insert)) {
2350
2481
  const key = `${keyPrefix}-${offset}`;
2351
2482
  const layout = op.insert.layout ?? "inline";
2352
2483
  const commentMarkId = op.attributes?.comment?.markId;
@@ -2510,10 +2641,10 @@ function ImageEmbedViewImpl({
2510
2641
  );
2511
2642
  }
2512
2643
  function decorateBlanks(text) {
2513
- const segs = (0, import_core5.splitUnderscoreRuns)(text);
2644
+ const segs = (0, import_core6.splitUnderscoreRuns)(text);
2514
2645
  if (segs.length === 1 && !segs[0].blank) return text;
2515
2646
  return segs.map(
2516
- (s, i) => s.blank ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { "data-blank": "true", style: import_core5.BLANK_STYLE, children: s.text }, i) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react8.Fragment, { children: s.text }, i)
2647
+ (s, i) => s.blank ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { "data-blank": "true", style: import_core6.BLANK_STYLE, children: s.text }, i) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react8.Fragment, { children: s.text }, i)
2517
2648
  );
2518
2649
  }
2519
2650
  function wrap(text, attrs) {
@@ -2772,7 +2903,7 @@ function NodeView({ block, index, children, fragment, tableFragment }) {
2772
2903
  function commonBlockProps(attrs, index, type, fragment) {
2773
2904
  const style = {};
2774
2905
  if (attrs.align) style.textAlign = attrs.align;
2775
- Object.assign(style, (0, import_core6.answerLineStyle)(attrs) ?? {});
2906
+ Object.assign(style, (0, import_core7.answerLineStyle)(attrs) ?? {});
2776
2907
  const base = {
2777
2908
  "data-block-index": index,
2778
2909
  "data-block-type": type,
@@ -2819,7 +2950,7 @@ function TableView({ block, index, tableFragment }) {
2819
2950
  const rect = (0, import_react10.useMemo)(() => {
2820
2951
  if (editor.selection.anchor.blockIndex !== index) return null;
2821
2952
  if (editor.selection.focus.blockIndex !== index) return null;
2822
- return (0, import_core6.tableRectSelection)(editor.doc, editor.selection);
2953
+ return (0, import_core7.tableRectSelection)(editor.doc, editor.selection);
2823
2954
  }, [editor.doc, editor.selection, index]);
2824
2955
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "ed-table-wrap", children: [
2825
2956
  /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
@@ -2855,7 +2986,7 @@ function TableView({ block, index, tableFragment }) {
2855
2986
  cell?.attrs,
2856
2987
  // rowStart/rowEnd são os limites do FRAGMENTO: numa tabela
2857
2988
  // quebrada entre páginas, cada página fecha a própria caixa.
2858
- (0, import_core6.cellBorderStyle)(
2989
+ (0, import_core7.cellBorderStyle)(
2859
2990
  block.attrs.borderPreset,
2860
2991
  { row: r, col: c, rowspan, colspan, cols, rowStart, rowEnd },
2861
2992
  "screen",
@@ -3431,14 +3562,13 @@ function shallowEqual(a, b) {
3431
3562
  }
3432
3563
 
3433
3564
  // src/useEditor.ts
3434
- var import_core7 = require("@sofereditor/core");
3435
- var MAX_INSERT_WIDTH = 600;
3565
+ var import_core8 = require("@sofereditor/core");
3436
3566
  function useEditor(opts = {}) {
3437
- const doc = (0, import_react13.useMemo)(() => opts.document ?? new import_core7.EditorDocument(), [opts.document]);
3438
- const history = (0, import_react13.useMemo)(() => new import_core7.EditorHistory(doc), [doc]);
3567
+ const doc = (0, import_react13.useMemo)(() => opts.document ?? new import_core8.EditorDocument(), [opts.document]);
3568
+ const history = (0, import_react13.useMemo)(() => new import_core8.EditorHistory(doc), [doc]);
3439
3569
  const [snapshot, setSnapshot] = (0, import_react13.useState)(() => doc.toJSON());
3440
3570
  const [selection, setSelectionState] = (0, import_react13.useState)(
3441
- () => (0, import_core7.collapsedSelection)({ blockIndex: 0, offset: 0 })
3571
+ () => (0, import_core8.collapsedSelection)({ blockIndex: 0, offset: 0 })
3442
3572
  );
3443
3573
  const selectionRef = (0, import_react13.useRef)(selection);
3444
3574
  selectionRef.current = selection;
@@ -3503,7 +3633,7 @@ function useEditor(opts = {}) {
3503
3633
  const isMarkActive = (0, import_react13.useCallback)(
3504
3634
  (name, value) => {
3505
3635
  const sel = selectionRef.current;
3506
- const { start, end } = (0, import_core7.orderedRange)(sel);
3636
+ const { start, end } = (0, import_core8.orderedRange)(sel);
3507
3637
  if (start.blockIndex === end.blockIndex && start.offset === end.offset) {
3508
3638
  const pending = pendingMarksRef.current[name];
3509
3639
  if (pending !== void 0) {
@@ -3512,7 +3642,7 @@ function useEditor(opts = {}) {
3512
3642
  }
3513
3643
  const yText2 = doc.getBlockText(start.blockIndex);
3514
3644
  if (!yText2 || start.offset === 0) return false;
3515
- return (0, import_core7.isMarkUniformInRange)(yText2, start.offset - 1, start.offset, name, value);
3645
+ return (0, import_core8.isMarkUniformInRange)(yText2, start.offset - 1, start.offset, name, value);
3516
3646
  }
3517
3647
  if (start.blockIndex !== end.blockIndex) {
3518
3648
  for (let i = start.blockIndex; i <= end.blockIndex; i++) {
@@ -3521,19 +3651,19 @@ function useEditor(opts = {}) {
3521
3651
  const s = i === start.blockIndex ? start.offset : 0;
3522
3652
  const e = i === end.blockIndex ? end.offset : yText2.length;
3523
3653
  if (s >= e) continue;
3524
- if (!(0, import_core7.isMarkUniformInRange)(yText2, s, e, name, value)) return false;
3654
+ if (!(0, import_core8.isMarkUniformInRange)(yText2, s, e, name, value)) return false;
3525
3655
  }
3526
3656
  return true;
3527
3657
  }
3528
3658
  const yText = doc.getBlockText(start.blockIndex);
3529
3659
  if (!yText) return false;
3530
- return (0, import_core7.isMarkUniformInRange)(yText, start.offset, end.offset, name, value);
3660
+ return (0, import_core8.isMarkUniformInRange)(yText, start.offset, end.offset, name, value);
3531
3661
  },
3532
3662
  [doc]
3533
3663
  );
3534
3664
  const getActiveMarks = (0, import_react13.useCallback)(() => {
3535
3665
  const sel = selectionRef.current;
3536
- const { start, end } = (0, import_core7.orderedRange)(sel);
3666
+ const { start, end } = (0, import_core8.orderedRange)(sel);
3537
3667
  if (start.blockIndex !== end.blockIndex) {
3538
3668
  return {};
3539
3669
  }
@@ -3541,14 +3671,14 @@ function useEditor(opts = {}) {
3541
3671
  if (!yText) return {};
3542
3672
  if (start.offset === end.offset) {
3543
3673
  if (start.offset === 0) return {};
3544
- return (0, import_core7.getMarksInRange)(yText, start.offset - 1, start.offset);
3674
+ return (0, import_core8.getMarksInRange)(yText, start.offset - 1, start.offset);
3545
3675
  }
3546
- return (0, import_core7.getMarksInRange)(yText, start.offset, end.offset);
3676
+ return (0, import_core8.getMarksInRange)(yText, start.offset, end.offset);
3547
3677
  }, [doc]);
3548
3678
  const toggleMark = (0, import_react13.useCallback)(
3549
3679
  (name, value) => {
3550
3680
  const sel = selectionRef.current;
3551
- const { start, end } = (0, import_core7.orderedRange)(sel);
3681
+ const { start, end } = (0, import_core8.orderedRange)(sel);
3552
3682
  const isCollapsed = start.blockIndex === end.blockIndex && start.offset === end.offset;
3553
3683
  if (isCollapsed) {
3554
3684
  const next = { ...pendingMarksRef.current };
@@ -3561,39 +3691,39 @@ function useEditor(opts = {}) {
3561
3691
  setPendingMarks(next);
3562
3692
  return;
3563
3693
  }
3564
- (0, import_core7.toggleMark)(ctxRef.current, name, value);
3694
+ (0, import_core8.toggleMark)(ctxRef.current, name, value);
3565
3695
  },
3566
3696
  [isMarkActive, setPendingMarks]
3567
3697
  );
3568
3698
  const setMark = (0, import_react13.useCallback)(
3569
3699
  (name, value) => {
3570
3700
  const sel = selectionRef.current;
3571
- const { start, end } = (0, import_core7.orderedRange)(sel);
3701
+ const { start, end } = (0, import_core8.orderedRange)(sel);
3572
3702
  const isCollapsed = start.blockIndex === end.blockIndex && start.offset === end.offset;
3573
3703
  if (isCollapsed) {
3574
3704
  setPendingMarks({ ...pendingMarksRef.current, [name]: value });
3575
3705
  return;
3576
3706
  }
3577
- (0, import_core7.setMark)(ctxRef.current, name, value);
3707
+ (0, import_core8.setMark)(ctxRef.current, name, value);
3578
3708
  },
3579
3709
  [setPendingMarks]
3580
3710
  );
3581
3711
  const removeMark = (0, import_react13.useCallback)(
3582
3712
  (name) => {
3583
3713
  const sel = selectionRef.current;
3584
- const { start, end } = (0, import_core7.orderedRange)(sel);
3714
+ const { start, end } = (0, import_core8.orderedRange)(sel);
3585
3715
  const isCollapsed = start.blockIndex === end.blockIndex && start.offset === end.offset;
3586
3716
  if (isCollapsed) {
3587
3717
  setPendingMarks({ ...pendingMarksRef.current, [name]: null });
3588
3718
  return;
3589
3719
  }
3590
- (0, import_core7.removeMark)(ctxRef.current, name);
3720
+ (0, import_core8.removeMark)(ctxRef.current, name);
3591
3721
  },
3592
3722
  [setPendingMarks]
3593
3723
  );
3594
3724
  const getBlockType = (0, import_react13.useCallback)(() => {
3595
3725
  const sel = selectionRef.current;
3596
- const { start, end } = (0, import_core7.orderedRange)(sel);
3726
+ const { start, end } = (0, import_core8.orderedRange)(sel);
3597
3727
  const first = doc.getBlockType(start.blockIndex);
3598
3728
  if (first === void 0) return "paragraph";
3599
3729
  for (let i = start.blockIndex + 1; i <= end.blockIndex; i++) {
@@ -3604,7 +3734,7 @@ function useEditor(opts = {}) {
3604
3734
  const getBlockAttr = (0, import_react13.useCallback)(
3605
3735
  (key) => {
3606
3736
  const sel = selectionRef.current;
3607
- const { start, end } = (0, import_core7.orderedRange)(sel);
3737
+ const { start, end } = (0, import_core8.orderedRange)(sel);
3608
3738
  const first = doc.getBlockAttrs(start.blockIndex)[key];
3609
3739
  for (let i = start.blockIndex + 1; i <= end.blockIndex; i++) {
3610
3740
  const next = doc.getBlockAttrs(i)[key];
@@ -3615,19 +3745,19 @@ function useEditor(opts = {}) {
3615
3745
  [doc]
3616
3746
  );
3617
3747
  const setBlockType = (0, import_react13.useCallback)((type, attrs) => {
3618
- (0, import_core7.setBlockType)(ctxRef.current, type, attrs);
3748
+ (0, import_core8.setBlockType)(ctxRef.current, type, attrs);
3619
3749
  }, []);
3620
3750
  const setBlockAttr = (0, import_react13.useCallback)(
3621
3751
  (key, value) => {
3622
- (0, import_core7.setBlockAttr)(ctxRef.current, key, value);
3752
+ (0, import_core8.setBlockAttr)(ctxRef.current, key, value);
3623
3753
  },
3624
3754
  []
3625
3755
  );
3626
3756
  const setAlign = (0, import_react13.useCallback)((value) => {
3627
3757
  const sel = selectionRef.current;
3628
3758
  const inCell = sel.focus.cellIndex != null;
3629
- if (inCell) (0, import_core7.setCellAttr)(ctxRef.current, "align", value);
3630
- else (0, import_core7.setBlockAttr)(ctxRef.current, "align", value);
3759
+ if (inCell) (0, import_core8.setCellAttr)(ctxRef.current, "align", value);
3760
+ else (0, import_core8.setBlockAttr)(ctxRef.current, "align", value);
3631
3761
  }, []);
3632
3762
  const getAlign = (0, import_react13.useCallback)(() => {
3633
3763
  const sel = selectionRef.current;
@@ -3637,7 +3767,7 @@ function useEditor(opts = {}) {
3637
3767
  return getBlockAttr("align");
3638
3768
  }, [doc, getBlockAttr]);
3639
3769
  const setCellBackground = (0, import_react13.useCallback)((color) => {
3640
- (0, import_core7.setCellAttr)(ctxRef.current, "bgColor", color);
3770
+ (0, import_core8.setCellAttr)(ctxRef.current, "bgColor", color);
3641
3771
  }, []);
3642
3772
  const getCellBackground = (0, import_react13.useCallback)(() => {
3643
3773
  const sel = selectionRef.current;
@@ -3647,7 +3777,7 @@ function useEditor(opts = {}) {
3647
3777
  const setTableBorderPreset = (0, import_react13.useCallback)((preset) => {
3648
3778
  const sel = selectionRef.current;
3649
3779
  if (!doc.isTable(sel.focus.blockIndex)) return;
3650
- (0, import_core7.setBlockAttrAtIndex)(ctxRef.current, sel.focus.blockIndex, "borderPreset", preset);
3780
+ (0, import_core8.setBlockAttrAtIndex)(ctxRef.current, sel.focus.blockIndex, "borderPreset", preset);
3651
3781
  }, [doc]);
3652
3782
  const getTableBorderPreset = (0, import_react13.useCallback)(() => {
3653
3783
  const sel = selectionRef.current;
@@ -3657,7 +3787,7 @@ function useEditor(opts = {}) {
3657
3787
  const setTableBorderColor = (0, import_react13.useCallback)((color) => {
3658
3788
  const sel = selectionRef.current;
3659
3789
  if (!doc.isTable(sel.focus.blockIndex)) return;
3660
- (0, import_core7.setBlockAttrAtIndex)(ctxRef.current, sel.focus.blockIndex, "borderColor", color);
3790
+ (0, import_core8.setBlockAttrAtIndex)(ctxRef.current, sel.focus.blockIndex, "borderColor", color);
3661
3791
  }, [doc]);
3662
3792
  const getTableBorderColor = (0, import_react13.useCallback)(() => {
3663
3793
  const sel = selectionRef.current;
@@ -3667,7 +3797,7 @@ function useEditor(opts = {}) {
3667
3797
  const isListActive = (0, import_react13.useCallback)(
3668
3798
  (kind) => {
3669
3799
  const sel = selectionRef.current;
3670
- const { start, end } = (0, import_core7.orderedRange)(sel);
3800
+ const { start, end } = (0, import_core8.orderedRange)(sel);
3671
3801
  for (let i = start.blockIndex; i <= end.blockIndex; i++) {
3672
3802
  if (doc.getBlockType(i) !== "listItem") return false;
3673
3803
  if (doc.getBlockAttrs(i).listKind !== kind) return false;
@@ -3677,112 +3807,112 @@ function useEditor(opts = {}) {
3677
3807
  [doc]
3678
3808
  );
3679
3809
  const toggleList = (0, import_react13.useCallback)((kind) => {
3680
- (0, import_core7.toggleList)(ctxRef.current, kind);
3810
+ (0, import_core8.toggleList)(ctxRef.current, kind);
3681
3811
  }, []);
3682
3812
  const indentList = (0, import_react13.useCallback)(() => {
3683
- (0, import_core7.indentList)(ctxRef.current);
3813
+ (0, import_core8.indentList)(ctxRef.current);
3684
3814
  }, []);
3685
3815
  const dedentList = (0, import_react13.useCallback)(() => {
3686
- (0, import_core7.dedentList)(ctxRef.current);
3816
+ (0, import_core8.dedentList)(ctxRef.current);
3687
3817
  }, []);
3688
3818
  const splitListItem = (0, import_react13.useCallback)(() => {
3689
- return (0, import_core7.splitListItem)(ctxRef.current);
3819
+ return (0, import_core8.splitListItem)(ctxRef.current);
3690
3820
  }, []);
3691
3821
  const isInTable = (0, import_react13.useCallback)(() => {
3692
3822
  return selectionRef.current.focus.cellIndex != null;
3693
3823
  }, []);
3694
3824
  const getTableLocation = (0, import_react13.useCallback)(() => {
3695
- return (0, import_core7.tableLocationOf)(doc, selectionRef.current.focus);
3825
+ return (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
3696
3826
  }, [doc]);
3697
3827
  const insertTable = (0, import_react13.useCallback)((rows, cols) => {
3698
- (0, import_core7.insertTable)(ctxRef.current, rows, cols);
3828
+ (0, import_core8.insertTable)(ctxRef.current, rows, cols);
3699
3829
  }, []);
3700
3830
  const insertAnswerLines = (0, import_react13.useCallback)((count, spacing) => {
3701
- (0, import_core7.insertAnswerLines)(ctxRef.current, count, spacing);
3831
+ (0, import_core8.insertAnswerLines)(ctxRef.current, count, spacing);
3702
3832
  }, []);
3703
3833
  const deleteTable = (0, import_react13.useCallback)((blockIndex) => {
3704
3834
  const idx = blockIndex ?? selectionRef.current.focus.blockIndex;
3705
- (0, import_core7.deleteTable)(ctxRef.current, idx);
3835
+ (0, import_core8.deleteTable)(ctxRef.current, idx);
3706
3836
  }, []);
3707
3837
  const insertRowAbove = (0, import_react13.useCallback)(() => {
3708
- const loc = (0, import_core7.tableLocationOf)(doc, selectionRef.current.focus);
3838
+ const loc = (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
3709
3839
  if (!loc) return;
3710
- (0, import_core7.insertTableRow)(ctxRef.current, loc.blockIndex, loc.row, "before");
3840
+ (0, import_core8.insertTableRow)(ctxRef.current, loc.blockIndex, loc.row, "before");
3711
3841
  }, [doc]);
3712
3842
  const insertRowBelow = (0, import_react13.useCallback)(() => {
3713
- const loc = (0, import_core7.tableLocationOf)(doc, selectionRef.current.focus);
3843
+ const loc = (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
3714
3844
  if (!loc) return;
3715
- (0, import_core7.insertTableRow)(ctxRef.current, loc.blockIndex, loc.row, "after");
3845
+ (0, import_core8.insertTableRow)(ctxRef.current, loc.blockIndex, loc.row, "after");
3716
3846
  }, [doc]);
3717
3847
  const deleteCurrentRow = (0, import_react13.useCallback)(() => {
3718
- const loc = (0, import_core7.tableLocationOf)(doc, selectionRef.current.focus);
3848
+ const loc = (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
3719
3849
  if (!loc) return;
3720
- (0, import_core7.deleteTableRow)(ctxRef.current, loc.blockIndex, loc.row);
3850
+ (0, import_core8.deleteTableRow)(ctxRef.current, loc.blockIndex, loc.row);
3721
3851
  }, [doc]);
3722
3852
  const insertColumnLeft = (0, import_react13.useCallback)(() => {
3723
- const loc = (0, import_core7.tableLocationOf)(doc, selectionRef.current.focus);
3853
+ const loc = (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
3724
3854
  if (!loc) return;
3725
- (0, import_core7.insertTableColumn)(ctxRef.current, loc.blockIndex, loc.col, "before");
3855
+ (0, import_core8.insertTableColumn)(ctxRef.current, loc.blockIndex, loc.col, "before");
3726
3856
  }, [doc]);
3727
3857
  const insertColumnRight = (0, import_react13.useCallback)(() => {
3728
- const loc = (0, import_core7.tableLocationOf)(doc, selectionRef.current.focus);
3858
+ const loc = (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
3729
3859
  if (!loc) return;
3730
- (0, import_core7.insertTableColumn)(ctxRef.current, loc.blockIndex, loc.col, "after");
3860
+ (0, import_core8.insertTableColumn)(ctxRef.current, loc.blockIndex, loc.col, "after");
3731
3861
  }, [doc]);
3732
3862
  const deleteCurrentColumn = (0, import_react13.useCallback)(() => {
3733
- const loc = (0, import_core7.tableLocationOf)(doc, selectionRef.current.focus);
3863
+ const loc = (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
3734
3864
  if (!loc) return;
3735
- (0, import_core7.deleteTableColumn)(ctxRef.current, loc.blockIndex, loc.col);
3865
+ (0, import_core8.deleteTableColumn)(ctxRef.current, loc.blockIndex, loc.col);
3736
3866
  }, [doc]);
3737
3867
  const moveToNextCell = (0, import_react13.useCallback)(() => {
3738
- (0, import_core7.moveToNextCell)(ctxRef.current);
3868
+ (0, import_core8.moveToNextCell)(ctxRef.current);
3739
3869
  }, []);
3740
3870
  const moveToPrevCell = (0, import_react13.useCallback)(() => {
3741
- (0, import_core7.moveToPrevCell)(ctxRef.current);
3871
+ (0, import_core8.moveToPrevCell)(ctxRef.current);
3742
3872
  }, []);
3743
3873
  const mergeRight = (0, import_react13.useCallback)(() => {
3744
- const loc = (0, import_core7.tableLocationOf)(doc, selectionRef.current.focus);
3874
+ const loc = (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
3745
3875
  if (!loc) return false;
3746
- return (0, import_core7.mergeRight)(ctxRef.current, loc.blockIndex, loc.row, loc.col);
3876
+ return (0, import_core8.mergeRight)(ctxRef.current, loc.blockIndex, loc.row, loc.col);
3747
3877
  }, [doc]);
3748
3878
  const mergeDown = (0, import_react13.useCallback)(() => {
3749
- const loc = (0, import_core7.tableLocationOf)(doc, selectionRef.current.focus);
3879
+ const loc = (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
3750
3880
  if (!loc) return false;
3751
- return (0, import_core7.mergeDown)(ctxRef.current, loc.blockIndex, loc.row, loc.col);
3881
+ return (0, import_core8.mergeDown)(ctxRef.current, loc.blockIndex, loc.row, loc.col);
3752
3882
  }, [doc]);
3753
3883
  const splitCell = (0, import_react13.useCallback)(() => {
3754
- const loc = (0, import_core7.tableLocationOf)(doc, selectionRef.current.focus);
3884
+ const loc = (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
3755
3885
  if (!loc) return false;
3756
- return (0, import_core7.splitCell)(ctxRef.current, loc.blockIndex, loc.row, loc.col);
3886
+ return (0, import_core8.splitCell)(ctxRef.current, loc.blockIndex, loc.row, loc.col);
3757
3887
  }, [doc]);
3758
3888
  const setColumnWidth = (0, import_react13.useCallback)(
3759
3889
  (blockIndex, col, widthPx) => {
3760
- (0, import_core7.setColumnWidth)(ctxRef.current, blockIndex, col, widthPx);
3890
+ (0, import_core8.setColumnWidth)(ctxRef.current, blockIndex, col, widthPx);
3761
3891
  },
3762
3892
  []
3763
3893
  );
3764
3894
  const getTableRect = (0, import_react13.useCallback)(
3765
- () => (0, import_core7.tableRectSelection)(doc, selectionRef.current),
3895
+ () => (0, import_core8.tableRectSelection)(doc, selectionRef.current),
3766
3896
  [doc]
3767
3897
  );
3768
3898
  const hasTableRectSelection = (0, import_react13.useCallback)(() => {
3769
- return (0, import_core7.tableRectSelection)(doc, selectionRef.current) !== null;
3899
+ return (0, import_core8.tableRectSelection)(doc, selectionRef.current) !== null;
3770
3900
  }, [doc]);
3771
3901
  const mergeSelection = (0, import_react13.useCallback)(() => {
3772
- return (0, import_core7.mergeSelection)(ctxRef.current);
3902
+ return (0, import_core8.mergeSelection)(ctxRef.current);
3773
3903
  }, []);
3774
3904
  const insertImage = (0, import_react13.useCallback)((embed) => {
3775
- (0, import_core7.insertImage)(ctxRef.current, embed);
3905
+ (0, import_core8.insertImage)(ctxRef.current, embed);
3776
3906
  }, []);
3777
3907
  const setImageAttrs = (0, import_react13.useCallback)(
3778
3908
  (blockIndex, offset, partial, cellIndex, newOffset) => {
3779
- (0, import_core7.setImageAttrs)(ctxRef.current, blockIndex, offset, partial, cellIndex, newOffset);
3909
+ (0, import_core8.setImageAttrs)(ctxRef.current, blockIndex, offset, partial, cellIndex, newOffset);
3780
3910
  },
3781
3911
  []
3782
3912
  );
3783
3913
  const moveEmbedAnchor = (0, import_react13.useCallback)(
3784
3914
  (from, to, newOffsetX, newOffsetY) => {
3785
- (0, import_core7.moveEmbedAnchor)(ctxRef.current, from, to, newOffsetX, newOffsetY);
3915
+ (0, import_core8.moveEmbedAnchor)(ctxRef.current, from, to, newOffsetX, newOffsetY);
3786
3916
  },
3787
3917
  []
3788
3918
  );
@@ -3800,7 +3930,7 @@ function useEditor(opts = {}) {
3800
3930
  }
3801
3931
  const upload = uploadImageRef.current;
3802
3932
  const src = upload ? await upload(file) : dataUrl;
3803
- (0, import_core7.insertImage)(ctxRef.current, { type: "image", src, width: w, height: h });
3933
+ (0, import_core8.insertImage)(ctxRef.current, { type: "image", src, width: w, height: h });
3804
3934
  }, []);
3805
3935
  const getSelectedEmbed = (0, import_react13.useCallback)(() => {
3806
3936
  const sel = selectionRef.current;
@@ -3819,7 +3949,7 @@ function useEditor(opts = {}) {
3819
3949
  cursor += op.insert.length;
3820
3950
  continue;
3821
3951
  }
3822
- if (cursor === start && (0, import_core7.isImageEmbed)(op.insert)) {
3952
+ if (cursor === start && (0, import_core8.isImageEmbed)(op.insert)) {
3823
3953
  return {
3824
3954
  blockIndex: sel.anchor.blockIndex,
3825
3955
  cellIndex: sel.anchor.cellIndex,
@@ -3952,7 +4082,8 @@ function useEditor(opts = {}) {
3952
4082
  resolvePageConfigRequest,
3953
4083
  imageCaptionRequest,
3954
4084
  requestImageCaption,
3955
- resolveImageCaptionRequest
4085
+ resolveImageCaptionRequest,
4086
+ uploadImage: opts.uploadImage
3956
4087
  };
3957
4088
  }
3958
4089
  function readAsDataURL(file) {
@@ -3999,6 +4130,7 @@ function Editor({
3999
4130
  const { doc, history, snapshot, getSelection, setSelection } = editor;
4000
4131
  const rootRef = (0, import_react14.useRef)(null);
4001
4132
  const isComposingRef = (0, import_react14.useRef)(false);
4133
+ const pasteInFlightRef = (0, import_react14.useRef)(false);
4002
4134
  const [hoveredBehind, setHoveredBehind] = (0, import_react14.useState)(null);
4003
4135
  const hoveredBehindRef = (0, import_react14.useRef)(null);
4004
4136
  const [hoveredLink, setHoveredLink] = (0, import_react14.useState)(null);
@@ -4014,7 +4146,7 @@ function Editor({
4014
4146
  const sel = readDomSelection(root);
4015
4147
  awareness.setLocalStateField(
4016
4148
  "cursor",
4017
- sel ? (0, import_core8.encodeSelection)(doc, sel) ?? null : null
4149
+ sel ? (0, import_core9.encodeSelection)(doc, sel) ?? null : null
4018
4150
  );
4019
4151
  };
4020
4152
  const onSelChange = () => {
@@ -4315,14 +4447,14 @@ function Editor({
4315
4447
  const data = e.data ?? "";
4316
4448
  if (data.length > 0) {
4317
4449
  e.preventDefault();
4318
- (0, import_core8.insertText)(ctx, data, ed.consumePendingMarks());
4450
+ (0, import_core9.insertText)(ctx, data, ed.consumePendingMarks());
4319
4451
  }
4320
4452
  return;
4321
4453
  }
4322
4454
  case "insertLineBreak": {
4323
4455
  e.preventDefault();
4324
4456
  if (ed.getBlockType() === "listItem") {
4325
- (0, import_core8.insertText)(ctx, "\n", ed.consumePendingMarks());
4457
+ (0, import_core9.insertText)(ctx, "\n", ed.consumePendingMarks());
4326
4458
  return;
4327
4459
  }
4328
4460
  const selEmbed = ed.getSelectedEmbed();
@@ -4342,7 +4474,7 @@ function Editor({
4342
4474
  });
4343
4475
  }
4344
4476
  if (ed.splitListItem()) return;
4345
- (0, import_core8.insertParagraph)(ctx);
4477
+ (0, import_core9.insertParagraph)(ctx);
4346
4478
  return;
4347
4479
  }
4348
4480
  case "insertParagraph": {
@@ -4364,14 +4496,14 @@ function Editor({
4364
4496
  });
4365
4497
  }
4366
4498
  if (ed.splitListItem()) return;
4367
- (0, import_core8.insertParagraph)(ctx);
4499
+ (0, import_core9.insertParagraph)(ctx);
4368
4500
  return;
4369
4501
  }
4370
4502
  case "insertReplacementText": {
4371
4503
  const text = e.data ?? e.dataTransfer?.getData("text/plain") ?? "";
4372
4504
  if (text.length > 0) {
4373
4505
  e.preventDefault();
4374
- (0, import_core8.insertText)(ctx, text, ed.consumePendingMarks());
4506
+ (0, import_core9.insertText)(ctx, text, ed.consumePendingMarks());
4375
4507
  }
4376
4508
  return;
4377
4509
  }
@@ -4384,7 +4516,7 @@ function Editor({
4384
4516
  case "deleteSoftLineBackward":
4385
4517
  case "deleteHardLineBackward": {
4386
4518
  e.preventDefault();
4387
- (0, import_core8.deleteBackward)(ctx);
4519
+ (0, import_core9.deleteBackward)(ctx);
4388
4520
  return;
4389
4521
  }
4390
4522
  case "deleteContentForward":
@@ -4392,7 +4524,7 @@ function Editor({
4392
4524
  case "deleteSoftLineForward":
4393
4525
  case "deleteHardLineForward": {
4394
4526
  e.preventDefault();
4395
- (0, import_core8.deleteForward)(ctx);
4527
+ (0, import_core9.deleteForward)(ctx);
4396
4528
  return;
4397
4529
  }
4398
4530
  case "historyUndo": {
@@ -4419,10 +4551,10 @@ function Editor({
4419
4551
  if (!root) return;
4420
4552
  const writeSlice = (e) => {
4421
4553
  const ctx = ctxRef.current;
4422
- const slice = (0, import_core8.serializeSelection)(ctx.doc, ctx.getSelection());
4554
+ const slice = (0, import_core9.serializeSelection)(ctx.doc, ctx.getSelection());
4423
4555
  if (!slice || !e.clipboardData) return false;
4424
- e.clipboardData.setData(import_core8.SOFER_MIME, JSON.stringify(slice));
4425
- e.clipboardData.setData("text/plain", (0, import_core8.sliceToText)(slice));
4556
+ e.clipboardData.setData(import_core9.SOFER_MIME, JSON.stringify(slice));
4557
+ e.clipboardData.setData("text/plain", (0, import_core9.sliceToText)(slice));
4426
4558
  return true;
4427
4559
  };
4428
4560
  const onCopy = (e) => {
@@ -4430,7 +4562,7 @@ function Editor({
4430
4562
  };
4431
4563
  const onCut = (e) => {
4432
4564
  e.preventDefault();
4433
- if (writeSlice(e)) (0, import_core8.deleteSelection)(ctxRef.current);
4565
+ if (writeSlice(e)) (0, import_core9.deleteSelection)(ctxRef.current);
4434
4566
  };
4435
4567
  const onPaste = (e) => {
4436
4568
  const ctx = ctxRef.current;
@@ -4441,9 +4573,48 @@ function Editor({
4441
4573
  e.preventDefault();
4442
4574
  switch (plan.kind) {
4443
4575
  case "sofer":
4444
- case "html":
4445
- (0, import_core8.insertSlice)(ctx, plan.slice);
4576
+ (0, import_core9.insertSlice)(ctx, plan.slice);
4446
4577
  return;
4578
+ case "html": {
4579
+ if (!sliceHasDataImageEmbeds(plan.slice)) {
4580
+ (0, import_core9.insertSlice)(ctx, plan.slice);
4581
+ return;
4582
+ }
4583
+ if (pasteInFlightRef.current) {
4584
+ console.warn(
4585
+ "[sofereditor] colagem com imagem ainda subindo \u2014 descartando esta colagem concorrente para n\xE3o corromper a posi\xE7\xE3o de inser\xE7\xE3o"
4586
+ );
4587
+ return;
4588
+ }
4589
+ pasteInFlightRef.current = true;
4590
+ const capturedSelection = ctx.getSelection();
4591
+ void (async () => {
4592
+ try {
4593
+ const resolved = await resolvePastedImageUploads(plan.slice, editorRef.current.uploadImage);
4594
+ const liveSelection = ctxRef.current.getSelection();
4595
+ const userMovedAway = !selectionsEqual(liveSelection, capturedSelection);
4596
+ const { blockIndex, cellIndex } = capturedSelection.focus;
4597
+ const targetText = ctxRef.current.doc.textAt(blockIndex, cellIndex);
4598
+ let insertAt = capturedSelection;
4599
+ if (!targetText) {
4600
+ console.error(
4601
+ "[sofereditor] bloco de destino da colagem sumiu durante o upload da imagem \u2014 inserindo no fim do documento em vez de descartar a colagem"
4602
+ );
4603
+ const lastIndex = Math.max(0, ctxRef.current.doc.blockCount() - 1);
4604
+ const lastText = ctxRef.current.doc.getBlockText(lastIndex);
4605
+ insertAt = (0, import_core9.collapsedSelection)({ blockIndex: lastIndex, offset: lastText ? lastText.length : 0 });
4606
+ }
4607
+ ctxRef.current.setSelection(insertAt);
4608
+ (0, import_core9.insertSlice)(ctxRef.current, resolved);
4609
+ if (userMovedAway) {
4610
+ ctxRef.current.setSelection(liveSelection);
4611
+ }
4612
+ } finally {
4613
+ pasteInFlightRef.current = false;
4614
+ }
4615
+ })();
4616
+ return;
4617
+ }
4447
4618
  case "images":
4448
4619
  void (async () => {
4449
4620
  for (const f of plan.files) await editorRef.current.insertImageFromFile(f);
@@ -4452,8 +4623,8 @@ function Editor({
4452
4623
  case "text": {
4453
4624
  const lines = plan.text.split(/\r\n|\r|\n/);
4454
4625
  lines.forEach((line, i) => {
4455
- if (i > 0) (0, import_core8.insertParagraph)(ctx);
4456
- if (line.length > 0) (0, import_core8.insertText)(ctx, line);
4626
+ if (i > 0) (0, import_core9.insertParagraph)(ctx);
4627
+ if (line.length > 0) (0, import_core9.insertText)(ctx, line);
4457
4628
  });
4458
4629
  return;
4459
4630
  }
@@ -4496,6 +4667,17 @@ function Editor({
4496
4667
  }
4497
4668
  return;
4498
4669
  }
4670
+ if (!mod && (e.key === "Backspace" || e.key === "Delete")) {
4671
+ if (isComposingRef.current) return;
4672
+ const direction = e.key === "Backspace" ? "backward" : "forward";
4673
+ const shouldIntercept = ed.getSelectedEmbed() != null || (0, import_core9.isEmbedAdjacentToCaret)(ctxRef.current, direction);
4674
+ if (shouldIntercept) {
4675
+ e.preventDefault();
4676
+ if (direction === "backward") (0, import_core9.deleteBackward)(ctxRef.current);
4677
+ else (0, import_core9.deleteForward)(ctxRef.current);
4678
+ }
4679
+ return;
4680
+ }
4499
4681
  if (!mod) return;
4500
4682
  const key = e.key.toLowerCase();
4501
4683
  if (!e.shiftKey && !e.altKey && key === "z") {
@@ -4548,7 +4730,7 @@ function Editor({
4548
4730
  const onCompositionEnd = (0, import_react14.useCallback)((e) => {
4549
4731
  isComposingRef.current = false;
4550
4732
  if (e.data && e.data.length > 0) {
4551
- (0, import_core8.insertText)(ctxRef.current, e.data);
4733
+ (0, import_core9.insertText)(ctxRef.current, e.data);
4552
4734
  }
4553
4735
  }, []);
4554
4736
  const topLevels = (0, import_react14.useMemo)(() => groupTopLevels(snapshot.blocks), [snapshot]);
@@ -4876,7 +5058,7 @@ function caretRangeFromPoint(x, y) {
4876
5058
 
4877
5059
  // src/Toolbar.tsx
4878
5060
  var import_react15 = require("react");
4879
- var import_core9 = require("@sofereditor/core");
5061
+ var import_core10 = require("@sofereditor/core");
4880
5062
  var import_jsx_runtime13 = require("react/jsx-runtime");
4881
5063
  var FONT_FAMILIES = ["Arial"];
4882
5064
  var FONT_SIZES = ["8pt", "10pt", "11pt", "12pt", "14pt", "16pt", "18pt", "24pt", "32pt", "48pt"];
@@ -5348,7 +5530,7 @@ function AnswerLinesMenu() {
5348
5530
  document.addEventListener("mousedown", onDown);
5349
5531
  return () => document.removeEventListener("mousedown", onDown);
5350
5532
  }, [open]);
5351
- const clamped = Math.max(1, Math.min(import_core9.ANSWER_LINE_MAX, Math.trunc(count) || 1));
5533
+ const clamped = Math.max(1, Math.min(import_core10.ANSWER_LINE_MAX, Math.trunc(count) || 1));
5352
5534
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { ref: rootRef, className: "ed-toolbar-tablemenu", children: [
5353
5535
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5354
5536
  "button",
@@ -5381,7 +5563,7 @@ function AnswerLinesMenu() {
5381
5563
  {
5382
5564
  type: "number",
5383
5565
  min: 1,
5384
- max: import_core9.ANSWER_LINE_MAX,
5566
+ max: import_core10.ANSWER_LINE_MAX,
5385
5567
  value: count,
5386
5568
  onChange: (e) => setCount(Number(e.target.value)),
5387
5569
  "aria-label": "Quantidade de linhas"
@@ -5574,7 +5756,7 @@ function TableMenu() {
5574
5756
  {
5575
5757
  className: "ed-toolbar-swatch",
5576
5758
  "aria-hidden": true,
5577
- style: { background: editor.getTableBorderColor() ?? import_core9.TABLE_BORDER_COLOR }
5759
+ style: { background: editor.getTableBorderColor() ?? import_core10.TABLE_BORDER_COLOR }
5578
5760
  }
5579
5761
  ),
5580
5762
  "Cor da borda",
@@ -5582,7 +5764,7 @@ function TableMenu() {
5582
5764
  "input",
5583
5765
  {
5584
5766
  type: "color",
5585
- value: editor.getTableBorderColor() ?? import_core9.TABLE_BORDER_COLOR,
5767
+ value: editor.getTableBorderColor() ?? import_core10.TABLE_BORDER_COLOR,
5586
5768
  onChange: (e) => editor.setTableBorderColor(e.target.value),
5587
5769
  "aria-label": "Cor da borda"
5588
5770
  }