@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 +306 -124
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +195 -11
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
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
|
|
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
|
|
357
|
-
|
|
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")
|
|
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
|
|
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 =
|
|
1293
|
-
setWidthMm(roundMm((0,
|
|
1294
|
-
setHeightMm(roundMm((0,
|
|
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 =
|
|
1299
|
-
const mm = roundMm((0,
|
|
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,
|
|
1309
|
-
height: Math.round((0,
|
|
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,
|
|
1318
|
-
height: (0,
|
|
1319
|
-
marginTop: (0,
|
|
1320
|
-
marginBottom: (0,
|
|
1321
|
-
marginLeft: (0,
|
|
1322
|
-
marginRight: (0,
|
|
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,
|
|
1712
|
+
const preset = (0, import_core4.detectPreset)(s.width, s.height);
|
|
1582
1713
|
setters.setSizePreset(preset);
|
|
1583
|
-
setters.setWidthMm(roundMm((0,
|
|
1584
|
-
setters.setHeightMm(roundMm((0,
|
|
1585
|
-
const top = roundMm((0,
|
|
1586
|
-
const bottom = roundMm((0,
|
|
1587
|
-
const left = roundMm((0,
|
|
1588
|
-
const right = roundMm((0,
|
|
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(
|
|
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
|
|
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,
|
|
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
|
|
2460
|
+
var import_core7 = require("@sofereditor/core");
|
|
2330
2461
|
|
|
2331
2462
|
// src/renderInline.tsx
|
|
2332
2463
|
var import_react8 = require("react");
|
|
2333
|
-
var
|
|
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,
|
|
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,
|
|
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:
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
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
|
|
3438
|
-
const history = (0, import_react13.useMemo)(() => new
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
3674
|
+
return (0, import_core8.getMarksInRange)(yText, start.offset - 1, start.offset);
|
|
3545
3675
|
}
|
|
3546
|
-
return (0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
3630
|
-
else (0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
3810
|
+
(0, import_core8.toggleList)(ctxRef.current, kind);
|
|
3681
3811
|
}, []);
|
|
3682
3812
|
const indentList = (0, import_react13.useCallback)(() => {
|
|
3683
|
-
(0,
|
|
3813
|
+
(0, import_core8.indentList)(ctxRef.current);
|
|
3684
3814
|
}, []);
|
|
3685
3815
|
const dedentList = (0, import_react13.useCallback)(() => {
|
|
3686
|
-
(0,
|
|
3816
|
+
(0, import_core8.dedentList)(ctxRef.current);
|
|
3687
3817
|
}, []);
|
|
3688
3818
|
const splitListItem = (0, import_react13.useCallback)(() => {
|
|
3689
|
-
return (0,
|
|
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,
|
|
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,
|
|
3828
|
+
(0, import_core8.insertTable)(ctxRef.current, rows, cols);
|
|
3699
3829
|
}, []);
|
|
3700
3830
|
const insertAnswerLines = (0, import_react13.useCallback)((count, spacing) => {
|
|
3701
|
-
(0,
|
|
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,
|
|
3835
|
+
(0, import_core8.deleteTable)(ctxRef.current, idx);
|
|
3706
3836
|
}, []);
|
|
3707
3837
|
const insertRowAbove = (0, import_react13.useCallback)(() => {
|
|
3708
|
-
const loc = (0,
|
|
3838
|
+
const loc = (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3709
3839
|
if (!loc) return;
|
|
3710
|
-
(0,
|
|
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,
|
|
3843
|
+
const loc = (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3714
3844
|
if (!loc) return;
|
|
3715
|
-
(0,
|
|
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,
|
|
3848
|
+
const loc = (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3719
3849
|
if (!loc) return;
|
|
3720
|
-
(0,
|
|
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,
|
|
3853
|
+
const loc = (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3724
3854
|
if (!loc) return;
|
|
3725
|
-
(0,
|
|
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,
|
|
3858
|
+
const loc = (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3729
3859
|
if (!loc) return;
|
|
3730
|
-
(0,
|
|
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,
|
|
3863
|
+
const loc = (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3734
3864
|
if (!loc) return;
|
|
3735
|
-
(0,
|
|
3865
|
+
(0, import_core8.deleteTableColumn)(ctxRef.current, loc.blockIndex, loc.col);
|
|
3736
3866
|
}, [doc]);
|
|
3737
3867
|
const moveToNextCell = (0, import_react13.useCallback)(() => {
|
|
3738
|
-
(0,
|
|
3868
|
+
(0, import_core8.moveToNextCell)(ctxRef.current);
|
|
3739
3869
|
}, []);
|
|
3740
3870
|
const moveToPrevCell = (0, import_react13.useCallback)(() => {
|
|
3741
|
-
(0,
|
|
3871
|
+
(0, import_core8.moveToPrevCell)(ctxRef.current);
|
|
3742
3872
|
}, []);
|
|
3743
3873
|
const mergeRight = (0, import_react13.useCallback)(() => {
|
|
3744
|
-
const loc = (0,
|
|
3874
|
+
const loc = (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3745
3875
|
if (!loc) return false;
|
|
3746
|
-
return (0,
|
|
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,
|
|
3879
|
+
const loc = (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3750
3880
|
if (!loc) return false;
|
|
3751
|
-
return (0,
|
|
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,
|
|
3884
|
+
const loc = (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3755
3885
|
if (!loc) return false;
|
|
3756
|
-
return (0,
|
|
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,
|
|
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,
|
|
3895
|
+
() => (0, import_core8.tableRectSelection)(doc, selectionRef.current),
|
|
3766
3896
|
[doc]
|
|
3767
3897
|
);
|
|
3768
3898
|
const hasTableRectSelection = (0, import_react13.useCallback)(() => {
|
|
3769
|
-
return (0,
|
|
3899
|
+
return (0, import_core8.tableRectSelection)(doc, selectionRef.current) !== null;
|
|
3770
3900
|
}, [doc]);
|
|
3771
3901
|
const mergeSelection = (0, import_react13.useCallback)(() => {
|
|
3772
|
-
return (0,
|
|
3902
|
+
return (0, import_core8.mergeSelection)(ctxRef.current);
|
|
3773
3903
|
}, []);
|
|
3774
3904
|
const insertImage = (0, import_react13.useCallback)((embed) => {
|
|
3775
|
-
(0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
4554
|
+
const slice = (0, import_core9.serializeSelection)(ctx.doc, ctx.getSelection());
|
|
4423
4555
|
if (!slice || !e.clipboardData) return false;
|
|
4424
|
-
e.clipboardData.setData(
|
|
4425
|
-
e.clipboardData.setData("text/plain", (0,
|
|
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,
|
|
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
|
-
|
|
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,
|
|
4456
|
-
if (line.length > 0) (0,
|
|
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,
|
|
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
|
|
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(
|
|
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:
|
|
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() ??
|
|
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() ??
|
|
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
|
}
|