@sofereditor/react 0.5.0 → 0.6.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 +757 -147
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +36 -2
- package/dist/index.d.ts +36 -2
- package/dist/index.js +643 -34
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -38,6 +38,7 @@ __export(index_exports, {
|
|
|
38
38
|
getBlockElement: () => getBlockElement,
|
|
39
39
|
getCellElement: () => getCellElement,
|
|
40
40
|
getFragmentForOffset: () => getFragmentForOffset,
|
|
41
|
+
htmlToSlice: () => htmlToSlice,
|
|
41
42
|
isTableRectSelection: () => isTableRectSelection,
|
|
42
43
|
locatePoint: () => locatePoint,
|
|
43
44
|
readDomSelection: () => readDomSelection,
|
|
@@ -54,7 +55,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
54
55
|
|
|
55
56
|
// src/Editor.tsx
|
|
56
57
|
var import_react14 = require("react");
|
|
57
|
-
var
|
|
58
|
+
var import_core8 = require("@sofereditor/core");
|
|
58
59
|
|
|
59
60
|
// src/dom-bridge.ts
|
|
60
61
|
function findContainingBlockElement(node, root) {
|
|
@@ -329,6 +330,615 @@ function applyDomSelection(root, modelSel) {
|
|
|
329
330
|
}
|
|
330
331
|
}
|
|
331
332
|
|
|
333
|
+
// src/pastePlan.ts
|
|
334
|
+
var import_core2 = require("@sofereditor/core");
|
|
335
|
+
|
|
336
|
+
// src/htmlToSlice.ts
|
|
337
|
+
var import_core = require("@sofereditor/core");
|
|
338
|
+
function htmlToSlice(html) {
|
|
339
|
+
if (!html || html.trim().length === 0) return null;
|
|
340
|
+
let doc;
|
|
341
|
+
try {
|
|
342
|
+
doc = new DOMParser().parseFromString(html, "text/html");
|
|
343
|
+
} catch {
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
346
|
+
const body = doc.body;
|
|
347
|
+
if (!body) return null;
|
|
348
|
+
const blocks = [];
|
|
349
|
+
try {
|
|
350
|
+
walkBlockLevel(body, {}, blocks);
|
|
351
|
+
} catch {
|
|
352
|
+
return null;
|
|
353
|
+
}
|
|
354
|
+
if (blocks.length === 0) return null;
|
|
355
|
+
normalizeListLevels(blocks);
|
|
356
|
+
const temTexto = blocks.some((b) => b.text.trim().length > 0);
|
|
357
|
+
if (!temTexto) return null;
|
|
358
|
+
const blockLevel = blocks.length > 1 || blocks[0].type !== "paragraph";
|
|
359
|
+
return { blocks, openStart: false, openEnd: false, ...blockLevel ? { blockLevel: true } : {} };
|
|
360
|
+
}
|
|
361
|
+
var IGNORED_TAGS = /* @__PURE__ */ new Set(["script", "style", "meta", "link", "head", "title", "xml"]);
|
|
362
|
+
var BLOCK_LEVEL_TAGS = /* @__PURE__ */ new Set([
|
|
363
|
+
"p",
|
|
364
|
+
"div",
|
|
365
|
+
"section",
|
|
366
|
+
"article",
|
|
367
|
+
"header",
|
|
368
|
+
"footer",
|
|
369
|
+
"main",
|
|
370
|
+
"figure",
|
|
371
|
+
"figcaption",
|
|
372
|
+
"pre",
|
|
373
|
+
"address"
|
|
374
|
+
]);
|
|
375
|
+
var BLOCK_TRIGGER_TAGS = /* @__PURE__ */ new Set([
|
|
376
|
+
"p",
|
|
377
|
+
"div",
|
|
378
|
+
"ul",
|
|
379
|
+
"ol",
|
|
380
|
+
"li",
|
|
381
|
+
"h1",
|
|
382
|
+
"h2",
|
|
383
|
+
"h3",
|
|
384
|
+
"h4",
|
|
385
|
+
"h5",
|
|
386
|
+
"h6",
|
|
387
|
+
"blockquote",
|
|
388
|
+
"table",
|
|
389
|
+
"tr",
|
|
390
|
+
"td",
|
|
391
|
+
"th"
|
|
392
|
+
]);
|
|
393
|
+
function isNamespacedTag(tag) {
|
|
394
|
+
return tag.includes(":");
|
|
395
|
+
}
|
|
396
|
+
function hasBlockDescendant(el) {
|
|
397
|
+
const all = el.querySelectorAll("*");
|
|
398
|
+
for (const e of Array.from(all)) {
|
|
399
|
+
if (BLOCK_TRIGGER_TAGS.has(e.tagName.toLowerCase())) return true;
|
|
400
|
+
}
|
|
401
|
+
return false;
|
|
402
|
+
}
|
|
403
|
+
function walkBlockLevel(container, marks, blocks) {
|
|
404
|
+
let loose = [];
|
|
405
|
+
const flushLoose = () => {
|
|
406
|
+
if (loose.length === 0) return;
|
|
407
|
+
const nodes = loose;
|
|
408
|
+
loose = [];
|
|
409
|
+
const delta = inlineDeltaFromNodes(nodes, marks);
|
|
410
|
+
if (delta.length > 0) blocks.push(makeBlock("paragraph", delta, {}));
|
|
411
|
+
};
|
|
412
|
+
for (const node of Array.from(container.childNodes)) {
|
|
413
|
+
if (node.nodeType === Node.COMMENT_NODE) continue;
|
|
414
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
415
|
+
loose.push(node);
|
|
416
|
+
continue;
|
|
417
|
+
}
|
|
418
|
+
if (node.nodeType !== Node.ELEMENT_NODE) continue;
|
|
419
|
+
const el = node;
|
|
420
|
+
const tag = el.tagName.toLowerCase();
|
|
421
|
+
if (IGNORED_TAGS.has(tag) || isNamespacedTag(tag)) continue;
|
|
422
|
+
switch (tag) {
|
|
423
|
+
case "ul":
|
|
424
|
+
case "ol": {
|
|
425
|
+
flushLoose();
|
|
426
|
+
handleList(el, tag === "ol" ? "ordered" : "bullet", 0, marks, blocks);
|
|
427
|
+
break;
|
|
428
|
+
}
|
|
429
|
+
case "h1":
|
|
430
|
+
case "h2":
|
|
431
|
+
case "h3":
|
|
432
|
+
case "h4":
|
|
433
|
+
case "h5":
|
|
434
|
+
case "h6": {
|
|
435
|
+
flushLoose();
|
|
436
|
+
const level = Number(tag[1]);
|
|
437
|
+
const attrs = { level };
|
|
438
|
+
const align = readAlign(el);
|
|
439
|
+
if (align) attrs.align = align;
|
|
440
|
+
const delta = inlineDeltaFromNodes(Array.from(el.childNodes), marks);
|
|
441
|
+
blocks.push(makeBlock("heading", delta, attrs));
|
|
442
|
+
break;
|
|
443
|
+
}
|
|
444
|
+
case "blockquote": {
|
|
445
|
+
flushLoose();
|
|
446
|
+
handleBlockquote(el, marks, blocks);
|
|
447
|
+
break;
|
|
448
|
+
}
|
|
449
|
+
case "table": {
|
|
450
|
+
flushLoose();
|
|
451
|
+
handleTable(el, marks, blocks);
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
454
|
+
case "li": {
|
|
455
|
+
flushLoose();
|
|
456
|
+
const nestedLists = topLevelListDescendants(el);
|
|
457
|
+
const clone = el.cloneNode(true);
|
|
458
|
+
for (const l of topLevelListDescendants(clone)) l.remove();
|
|
459
|
+
const delta = inlineDeltaFromNodes(Array.from(clone.childNodes), marks);
|
|
460
|
+
blocks.push(makeBlock("listItem", delta, { listKind: "bullet", listLevel: 0 }));
|
|
461
|
+
for (const nested of nestedLists) {
|
|
462
|
+
const nestedKind = nested.tagName.toLowerCase() === "ol" ? "ordered" : "bullet";
|
|
463
|
+
handleList(nested, nestedKind, 1, marks, blocks);
|
|
464
|
+
}
|
|
465
|
+
break;
|
|
466
|
+
}
|
|
467
|
+
case "img":
|
|
468
|
+
break;
|
|
469
|
+
case "br":
|
|
470
|
+
loose.push(node);
|
|
471
|
+
break;
|
|
472
|
+
default: {
|
|
473
|
+
const styleAttr = el.getAttribute("style") ?? "";
|
|
474
|
+
const wordListLevel = parseWordListLevel(styleAttr);
|
|
475
|
+
if (wordListLevel != null && !hasBlockDescendant(el)) {
|
|
476
|
+
flushLoose();
|
|
477
|
+
const marker = findWordListMarker(el);
|
|
478
|
+
const listKind = marker ? detectWordListKind(marker) : "bullet";
|
|
479
|
+
const attrs = { listKind, listLevel: wordListLevel };
|
|
480
|
+
const align = readAlign(el);
|
|
481
|
+
if (align) attrs.align = align;
|
|
482
|
+
const delta = inlineDeltaFromNodes(Array.from(el.childNodes), marks);
|
|
483
|
+
blocks.push(makeBlock("listItem", delta, attrs));
|
|
484
|
+
break;
|
|
485
|
+
}
|
|
486
|
+
if (hasBlockDescendant(el)) {
|
|
487
|
+
flushLoose();
|
|
488
|
+
let nextMarks = applyTagMarks(tag, marks);
|
|
489
|
+
nextMarks = applyStyleMarks(el.getAttribute("style"), nextMarks);
|
|
490
|
+
walkBlockLevel(el, nextMarks, blocks);
|
|
491
|
+
break;
|
|
492
|
+
}
|
|
493
|
+
if (BLOCK_LEVEL_TAGS.has(tag)) {
|
|
494
|
+
flushLoose();
|
|
495
|
+
const attrs = {};
|
|
496
|
+
const align = readAlign(el);
|
|
497
|
+
if (align) attrs.align = align;
|
|
498
|
+
const delta = inlineDeltaFromNodes(Array.from(el.childNodes), marks);
|
|
499
|
+
blocks.push(makeBlock("paragraph", delta, attrs));
|
|
500
|
+
break;
|
|
501
|
+
}
|
|
502
|
+
loose.push(node);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
flushLoose();
|
|
507
|
+
}
|
|
508
|
+
function handleList(listEl, kind, level, marks, blocks) {
|
|
509
|
+
for (const child of Array.from(listEl.children)) {
|
|
510
|
+
const tag = child.tagName.toLowerCase();
|
|
511
|
+
if (tag === "ul" || tag === "ol") {
|
|
512
|
+
const siblingKind = tag === "ol" ? "ordered" : "bullet";
|
|
513
|
+
handleList(child, siblingKind, level + 1, marks, blocks);
|
|
514
|
+
continue;
|
|
515
|
+
}
|
|
516
|
+
if (tag !== "li") continue;
|
|
517
|
+
const nestedLists = topLevelListDescendants(child);
|
|
518
|
+
const clone = child.cloneNode(true);
|
|
519
|
+
for (const l of topLevelListDescendants(clone)) l.remove();
|
|
520
|
+
const delta = inlineDeltaFromNodes(Array.from(clone.childNodes), marks);
|
|
521
|
+
const attrs = { listKind: kind, listLevel: clampLevel(level) };
|
|
522
|
+
const align = readAlign(child);
|
|
523
|
+
if (align) attrs.align = align;
|
|
524
|
+
blocks.push(makeBlock("listItem", delta, attrs));
|
|
525
|
+
for (const nested of nestedLists) {
|
|
526
|
+
const nestedKind = nested.tagName.toLowerCase() === "ol" ? "ordered" : "bullet";
|
|
527
|
+
handleList(nested, nestedKind, level + 1, marks, blocks);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
function topLevelListDescendants(root) {
|
|
532
|
+
const all = Array.from(root.querySelectorAll("ul, ol"));
|
|
533
|
+
return all.filter((el) => {
|
|
534
|
+
let p = el.parentElement;
|
|
535
|
+
while (p && p !== root) {
|
|
536
|
+
const t = p.tagName.toLowerCase();
|
|
537
|
+
if (t === "ul" || t === "ol" || t === "table" || t === "td" || t === "th") return false;
|
|
538
|
+
p = p.parentElement;
|
|
539
|
+
}
|
|
540
|
+
return true;
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
function handleBlockquote(el, marks, blocks) {
|
|
544
|
+
if (!hasBlockDescendant(el)) {
|
|
545
|
+
const attrs = {};
|
|
546
|
+
const align = readAlign(el);
|
|
547
|
+
if (align) attrs.align = align;
|
|
548
|
+
const delta = inlineDeltaFromNodes(Array.from(el.childNodes), marks);
|
|
549
|
+
blocks.push(makeBlock("blockquote", delta, attrs));
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
const nested = [];
|
|
553
|
+
walkBlockLevel(el, marks, nested);
|
|
554
|
+
for (const b of nested) {
|
|
555
|
+
blocks.push(b.type === "paragraph" ? { ...b, type: "blockquote" } : b);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
function handleTable(table, marks, blocks) {
|
|
559
|
+
for (const row of directRows(table)) {
|
|
560
|
+
const cells = Array.from(row.children).filter(
|
|
561
|
+
(c) => ["td", "th"].includes(c.tagName.toLowerCase())
|
|
562
|
+
);
|
|
563
|
+
for (const cell of cells) {
|
|
564
|
+
const cellBlocks = [];
|
|
565
|
+
walkBlockLevel(cell, marks, cellBlocks);
|
|
566
|
+
for (const b of cellBlocks) {
|
|
567
|
+
const attrs = {};
|
|
568
|
+
if (b.attrs.align) attrs.align = b.attrs.align;
|
|
569
|
+
blocks.push(makeBlock("paragraph", b.delta, attrs));
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
function directRows(table) {
|
|
575
|
+
const rows = [];
|
|
576
|
+
for (const child of Array.from(table.children)) {
|
|
577
|
+
const tag = child.tagName.toLowerCase();
|
|
578
|
+
if (tag === "tr") {
|
|
579
|
+
rows.push(child);
|
|
580
|
+
} else if (tag === "tbody" || tag === "thead" || tag === "tfoot") {
|
|
581
|
+
for (const r of Array.from(child.children)) {
|
|
582
|
+
if (r.tagName.toLowerCase() === "tr") rows.push(r);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
return rows;
|
|
587
|
+
}
|
|
588
|
+
function parseWordListLevel(styleAttr) {
|
|
589
|
+
const m = /mso-list\s*:\s*l\d+\s+level(\d+)/i.exec(styleAttr);
|
|
590
|
+
if (!m) return null;
|
|
591
|
+
const n = Number.parseInt(m[1], 10);
|
|
592
|
+
const fromLevelN = Number.isFinite(n) ? Math.max(0, n - 1) : 0;
|
|
593
|
+
const fromMargin = wordListLevelFromMarginLeft(marginLeftPt(styleAttr));
|
|
594
|
+
return clampLevel(Math.max(fromLevelN, fromMargin));
|
|
595
|
+
}
|
|
596
|
+
function marginLeftPt(styleAttr) {
|
|
597
|
+
const raw = parseStyle(styleAttr)["margin-left"];
|
|
598
|
+
if (!raw) return 0;
|
|
599
|
+
const m = /^(-?[\d.]+)\s*(pt|cm|in|px)$/i.exec(raw.trim());
|
|
600
|
+
if (!m) return 0;
|
|
601
|
+
const val = Number.parseFloat(m[1]);
|
|
602
|
+
if (!Number.isFinite(val) || val < 0) return 0;
|
|
603
|
+
switch (m[2].toLowerCase()) {
|
|
604
|
+
case "pt":
|
|
605
|
+
return val;
|
|
606
|
+
case "cm":
|
|
607
|
+
return val * 28.3465;
|
|
608
|
+
case "in":
|
|
609
|
+
return val * 72;
|
|
610
|
+
case "px":
|
|
611
|
+
return val * 0.75;
|
|
612
|
+
default:
|
|
613
|
+
return 0;
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
function wordListLevelFromMarginLeft(pt) {
|
|
617
|
+
if (pt <= 0) return 0;
|
|
618
|
+
return Math.max(0, Math.round(pt / 36) - 1);
|
|
619
|
+
}
|
|
620
|
+
function findWordListMarker(el) {
|
|
621
|
+
const all = el.querySelectorAll("*");
|
|
622
|
+
for (const e of Array.from(all)) {
|
|
623
|
+
const style = (e.getAttribute("style") ?? "").toLowerCase().replace(/\s+/g, "");
|
|
624
|
+
if (style.includes("mso-list:ignore")) return e;
|
|
625
|
+
}
|
|
626
|
+
return null;
|
|
627
|
+
}
|
|
628
|
+
function detectWordListKind(markerEl) {
|
|
629
|
+
const all = [markerEl, ...Array.from(markerEl.querySelectorAll("*"))];
|
|
630
|
+
for (const e of all) {
|
|
631
|
+
const style = (e.getAttribute("style") ?? "").toLowerCase();
|
|
632
|
+
if (style.includes("symbol") || style.includes("wingdings")) return "bullet";
|
|
633
|
+
}
|
|
634
|
+
const text = (markerEl.textContent ?? "").replace(/ /g, " ").trim();
|
|
635
|
+
if (/^[0-9]+[.)]/.test(text)) return "ordered";
|
|
636
|
+
if (/^[a-zA-Z][.)]/.test(text)) return "ordered";
|
|
637
|
+
return "bullet";
|
|
638
|
+
}
|
|
639
|
+
function inlineDeltaFromNodes(nodes, marks) {
|
|
640
|
+
const ops = [];
|
|
641
|
+
for (const n of nodes) walkInlineNode(n, marks, ops);
|
|
642
|
+
return trimEdgeWhitespace(collapseRepeatedSpaces(mergeAdjacentOps(ops)));
|
|
643
|
+
}
|
|
644
|
+
function collapseRepeatedSpaces(ops) {
|
|
645
|
+
return ops.map(
|
|
646
|
+
(op) => typeof op.insert === "string" ? { ...op, insert: op.insert.replace(/ {2,}/g, " ") } : op
|
|
647
|
+
);
|
|
648
|
+
}
|
|
649
|
+
function walkInlineNode(node, marks, ops) {
|
|
650
|
+
if (node.nodeType === Node.COMMENT_NODE) return;
|
|
651
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
652
|
+
const text = normalizeWhitespace(node.textContent ?? "");
|
|
653
|
+
if (text.length > 0) pushOp(ops, text, marks);
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
if (node.nodeType !== Node.ELEMENT_NODE) return;
|
|
657
|
+
const el = node;
|
|
658
|
+
const tag = el.tagName.toLowerCase();
|
|
659
|
+
if (IGNORED_TAGS.has(tag) || isNamespacedTag(tag)) return;
|
|
660
|
+
if (tag === "img") return;
|
|
661
|
+
if (tag === "br") {
|
|
662
|
+
ops.push({ insert: " " });
|
|
663
|
+
return;
|
|
664
|
+
}
|
|
665
|
+
const styleAttr = (el.getAttribute("style") ?? "").toLowerCase().replace(/\s+/g, "");
|
|
666
|
+
if (styleAttr.includes("mso-list:ignore")) return;
|
|
667
|
+
let nextMarks = applyTagMarks(tag, marks);
|
|
668
|
+
nextMarks = applyStyleMarks(el.getAttribute("style"), nextMarks);
|
|
669
|
+
if (tag === "a") {
|
|
670
|
+
const href = el.getAttribute("href");
|
|
671
|
+
if (href) nextMarks = { ...nextMarks, link: { href } };
|
|
672
|
+
}
|
|
673
|
+
for (const child of Array.from(el.childNodes)) walkInlineNode(child, nextMarks, ops);
|
|
674
|
+
}
|
|
675
|
+
function applyTagMarks(tag, marks) {
|
|
676
|
+
switch (tag) {
|
|
677
|
+
case "b":
|
|
678
|
+
case "strong":
|
|
679
|
+
return { ...marks, bold: true };
|
|
680
|
+
case "i":
|
|
681
|
+
case "em":
|
|
682
|
+
return { ...marks, italic: true };
|
|
683
|
+
case "u":
|
|
684
|
+
return { ...marks, underline: true };
|
|
685
|
+
case "s":
|
|
686
|
+
case "strike":
|
|
687
|
+
case "del":
|
|
688
|
+
return { ...marks, strike: true };
|
|
689
|
+
default:
|
|
690
|
+
return marks;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
function parseStyle(styleAttr) {
|
|
694
|
+
const out = {};
|
|
695
|
+
if (!styleAttr) return out;
|
|
696
|
+
for (const decl of styleAttr.split(";")) {
|
|
697
|
+
const idx = decl.indexOf(":");
|
|
698
|
+
if (idx === -1) continue;
|
|
699
|
+
const prop = decl.slice(0, idx).trim().toLowerCase();
|
|
700
|
+
const val = decl.slice(idx + 1).trim();
|
|
701
|
+
if (prop) out[prop] = val;
|
|
702
|
+
}
|
|
703
|
+
return out;
|
|
704
|
+
}
|
|
705
|
+
function applyStyleMarks(styleAttr, marks) {
|
|
706
|
+
const decls = parseStyle(styleAttr);
|
|
707
|
+
if (Object.keys(decls).length === 0) return marks;
|
|
708
|
+
const next = { ...marks };
|
|
709
|
+
if ("font-weight" in decls) {
|
|
710
|
+
const v = decls["font-weight"].toLowerCase();
|
|
711
|
+
if (v === "bold" || /^[5-9]00$/.test(v)) next.bold = true;
|
|
712
|
+
else if (v === "normal" || /^[1-4]00$/.test(v)) delete next.bold;
|
|
713
|
+
}
|
|
714
|
+
if ("font-style" in decls) {
|
|
715
|
+
const v = decls["font-style"].toLowerCase();
|
|
716
|
+
if (v === "italic" || v === "oblique") next.italic = true;
|
|
717
|
+
else if (v === "normal") delete next.italic;
|
|
718
|
+
}
|
|
719
|
+
const deco = decls["text-decoration-line"] ?? decls["text-decoration"];
|
|
720
|
+
if (deco !== void 0) {
|
|
721
|
+
const v = deco.toLowerCase();
|
|
722
|
+
delete next.underline;
|
|
723
|
+
delete next.strike;
|
|
724
|
+
if (v.includes("underline")) next.underline = true;
|
|
725
|
+
if (v.includes("line-through")) next.strike = true;
|
|
726
|
+
}
|
|
727
|
+
if ("color" in decls) {
|
|
728
|
+
const css = normalizeCssColor(decls.color);
|
|
729
|
+
if (css && !isBlack(css)) next.color = css;
|
|
730
|
+
else delete next.color;
|
|
731
|
+
}
|
|
732
|
+
const bg = decls["background-color"] ?? decls.background;
|
|
733
|
+
if (bg !== void 0) {
|
|
734
|
+
const css = normalizeCssColor(bg);
|
|
735
|
+
if (css && css !== "#ffffff") next.highlight = css;
|
|
736
|
+
else delete next.highlight;
|
|
737
|
+
}
|
|
738
|
+
if ("font-size" in decls) {
|
|
739
|
+
const pt = parseFontSizePt(decls["font-size"]);
|
|
740
|
+
if (pt != null) next.fontSize = formatFontSizePt(pt);
|
|
741
|
+
}
|
|
742
|
+
return next;
|
|
743
|
+
}
|
|
744
|
+
function parseFontSizePt(raw) {
|
|
745
|
+
const v = raw.trim().toLowerCase();
|
|
746
|
+
const m = /^(-?[\d.]+)\s*(pt|px|in)$/.exec(v);
|
|
747
|
+
if (!m) return void 0;
|
|
748
|
+
const num = Number.parseFloat(m[1]);
|
|
749
|
+
if (!Number.isFinite(num)) return void 0;
|
|
750
|
+
let pt;
|
|
751
|
+
switch (m[2]) {
|
|
752
|
+
case "pt":
|
|
753
|
+
pt = num;
|
|
754
|
+
break;
|
|
755
|
+
case "px":
|
|
756
|
+
pt = num * 0.75;
|
|
757
|
+
break;
|
|
758
|
+
case "in":
|
|
759
|
+
pt = num * 72;
|
|
760
|
+
break;
|
|
761
|
+
default:
|
|
762
|
+
return void 0;
|
|
763
|
+
}
|
|
764
|
+
const rounded = Math.round(pt * 10) / 10;
|
|
765
|
+
if (rounded <= 0 || rounded > 200) return void 0;
|
|
766
|
+
return rounded;
|
|
767
|
+
}
|
|
768
|
+
function formatFontSizePt(pt) {
|
|
769
|
+
const rounded = Math.round(pt * 10) / 10;
|
|
770
|
+
const str = Number.isInteger(rounded) ? String(rounded) : rounded.toFixed(1);
|
|
771
|
+
return `${str}pt`;
|
|
772
|
+
}
|
|
773
|
+
var NAMED_COLORS = {
|
|
774
|
+
black: "#000000",
|
|
775
|
+
white: "#ffffff",
|
|
776
|
+
red: "#ff0000",
|
|
777
|
+
green: "#008000",
|
|
778
|
+
blue: "#0000ff",
|
|
779
|
+
yellow: "#ffff00",
|
|
780
|
+
cyan: "#00ffff",
|
|
781
|
+
magenta: "#ff00ff",
|
|
782
|
+
gray: "#808080",
|
|
783
|
+
grey: "#808080",
|
|
784
|
+
orange: "#ffa500",
|
|
785
|
+
purple: "#800080"
|
|
786
|
+
};
|
|
787
|
+
function normalizeCssColor(raw) {
|
|
788
|
+
if (!raw) return void 0;
|
|
789
|
+
const v = raw.trim().toLowerCase();
|
|
790
|
+
if (!v || v === "transparent" || v === "none" || v === "inherit" || v === "initial") return void 0;
|
|
791
|
+
if (v.startsWith("#")) {
|
|
792
|
+
let hex = v.slice(1);
|
|
793
|
+
if (hex.length === 3) hex = hex.split("").map((c) => c + c).join("");
|
|
794
|
+
return /^[0-9a-f]{6}$/.test(hex) ? `#${hex}` : void 0;
|
|
795
|
+
}
|
|
796
|
+
const rgbMatch = /^rgba?\(([^)]+)\)$/.exec(v);
|
|
797
|
+
if (rgbMatch) {
|
|
798
|
+
const parts = rgbMatch[1].split(",").map((s) => s.trim());
|
|
799
|
+
if (parts.length < 3) return void 0;
|
|
800
|
+
const alpha = parts[3] !== void 0 ? Number.parseFloat(parts[3]) : 1;
|
|
801
|
+
if (alpha === 0) return void 0;
|
|
802
|
+
const toHex = (n) => {
|
|
803
|
+
const num = Math.max(0, Math.min(255, Number.parseInt(n, 10) || 0));
|
|
804
|
+
return num.toString(16).padStart(2, "0");
|
|
805
|
+
};
|
|
806
|
+
return `#${toHex(parts[0])}${toHex(parts[1])}${toHex(parts[2])}`;
|
|
807
|
+
}
|
|
808
|
+
return NAMED_COLORS[v];
|
|
809
|
+
}
|
|
810
|
+
function isBlack(hex) {
|
|
811
|
+
return hex.toLowerCase() === "#000000";
|
|
812
|
+
}
|
|
813
|
+
function readAlign(el) {
|
|
814
|
+
const style = parseStyle(el.getAttribute("style"));
|
|
815
|
+
const v = style["text-align"];
|
|
816
|
+
if (!v) return void 0;
|
|
817
|
+
switch (v.toLowerCase()) {
|
|
818
|
+
case "left":
|
|
819
|
+
case "start":
|
|
820
|
+
return "left";
|
|
821
|
+
case "center":
|
|
822
|
+
return "center";
|
|
823
|
+
case "right":
|
|
824
|
+
case "end":
|
|
825
|
+
return "right";
|
|
826
|
+
case "justify":
|
|
827
|
+
return "justify";
|
|
828
|
+
default:
|
|
829
|
+
return void 0;
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
function clampLevel(n) {
|
|
833
|
+
if (!Number.isFinite(n)) return 0;
|
|
834
|
+
return Math.max(0, Math.min(import_core.MAX_LIST_LEVEL, Math.trunc(n)));
|
|
835
|
+
}
|
|
836
|
+
function normalizeListLevels(blocks) {
|
|
837
|
+
let i = 0;
|
|
838
|
+
while (i < blocks.length) {
|
|
839
|
+
if (blocks[i].type !== "listItem") {
|
|
840
|
+
i++;
|
|
841
|
+
continue;
|
|
842
|
+
}
|
|
843
|
+
let j = i + 1;
|
|
844
|
+
while (j < blocks.length && blocks[j].type === "listItem") j++;
|
|
845
|
+
if (j - i > 1) {
|
|
846
|
+
let min = Number.POSITIVE_INFINITY;
|
|
847
|
+
for (let k = i; k < j; k++) {
|
|
848
|
+
const lvl = blocks[k].attrs.listLevel ?? 0;
|
|
849
|
+
if (lvl < min) min = lvl;
|
|
850
|
+
}
|
|
851
|
+
if (min > 0) {
|
|
852
|
+
for (let k = i; k < j; k++) {
|
|
853
|
+
const lvl = blocks[k].attrs.listLevel ?? 0;
|
|
854
|
+
blocks[k].attrs.listLevel = clampLevel(lvl - min);
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
i = j;
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
function pushOp(ops, text, marks) {
|
|
862
|
+
const hasMarks = Object.keys(marks).length > 0;
|
|
863
|
+
ops.push(hasMarks ? { insert: text, attributes: { ...marks } } : { insert: text });
|
|
864
|
+
}
|
|
865
|
+
function normalizeWhitespace(raw) {
|
|
866
|
+
return raw.replace(/[ \t\r\n]+/g, " ");
|
|
867
|
+
}
|
|
868
|
+
function trimEdgeWhitespace(ops) {
|
|
869
|
+
let out = ops;
|
|
870
|
+
if (out.length > 0 && typeof out[0].insert === "string") {
|
|
871
|
+
const trimmed = out[0].insert.replace(/^ +/, "");
|
|
872
|
+
if (trimmed.length === 0) out = out.slice(1);
|
|
873
|
+
else if (trimmed !== out[0].insert) out = [{ ...out[0], insert: trimmed }, ...out.slice(1)];
|
|
874
|
+
}
|
|
875
|
+
if (out.length > 0 && typeof out[out.length - 1].insert === "string") {
|
|
876
|
+
const last = out[out.length - 1];
|
|
877
|
+
const trimmed = last.insert.replace(/ +$/, "");
|
|
878
|
+
if (trimmed.length === 0) out = out.slice(0, -1);
|
|
879
|
+
else if (trimmed !== last.insert) out = [...out.slice(0, -1), { ...last, insert: trimmed }];
|
|
880
|
+
}
|
|
881
|
+
return out;
|
|
882
|
+
}
|
|
883
|
+
function mergeAdjacentOps(ops) {
|
|
884
|
+
const out = [];
|
|
885
|
+
for (const op of ops) {
|
|
886
|
+
const prev = out[out.length - 1];
|
|
887
|
+
if (prev && typeof prev.insert === "string" && typeof op.insert === "string" && sameMarks(prev.attributes, op.attributes)) {
|
|
888
|
+
prev.insert = prev.insert + op.insert;
|
|
889
|
+
continue;
|
|
890
|
+
}
|
|
891
|
+
out.push({ ...op });
|
|
892
|
+
}
|
|
893
|
+
return out;
|
|
894
|
+
}
|
|
895
|
+
function sameMarks(a, b) {
|
|
896
|
+
const ak = a ? Object.keys(a).sort() : [];
|
|
897
|
+
const bk = b ? Object.keys(b).sort() : [];
|
|
898
|
+
if (ak.length !== bk.length) return false;
|
|
899
|
+
for (let i = 0; i < ak.length; i++) {
|
|
900
|
+
if (ak[i] !== bk[i]) return false;
|
|
901
|
+
const av = a[ak[i]];
|
|
902
|
+
const bv = b[bk[i]];
|
|
903
|
+
if (typeof av === "object" && av !== null && typeof bv === "object" && bv !== null) {
|
|
904
|
+
if (JSON.stringify(av) !== JSON.stringify(bv)) return false;
|
|
905
|
+
} else if (av !== bv) {
|
|
906
|
+
return false;
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
return true;
|
|
910
|
+
}
|
|
911
|
+
function deltaToText(delta) {
|
|
912
|
+
let s = "";
|
|
913
|
+
for (const op of delta) if (typeof op.insert === "string") s += op.insert;
|
|
914
|
+
return s;
|
|
915
|
+
}
|
|
916
|
+
function makeBlock(type, delta, attrs) {
|
|
917
|
+
return { type, text: deltaToText(delta), delta, attrs };
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
// src/pastePlan.ts
|
|
921
|
+
function planPaste(cd) {
|
|
922
|
+
const raw = cd.getData(import_core2.SOFER_MIME);
|
|
923
|
+
if (raw) {
|
|
924
|
+
try {
|
|
925
|
+
const slice = JSON.parse(raw);
|
|
926
|
+
if (slice && Array.isArray(slice.blocks)) return { kind: "sofer", slice };
|
|
927
|
+
} catch {
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
const html = cd.getData("text/html");
|
|
931
|
+
if (html) {
|
|
932
|
+
const slice = htmlToSlice(html);
|
|
933
|
+
if (slice) return { kind: "html", slice };
|
|
934
|
+
}
|
|
935
|
+
const files = Array.from(cd.files ?? []).filter((f) => f.type.startsWith("image/"));
|
|
936
|
+
if (files.length > 0) return { kind: "images", files };
|
|
937
|
+
const text = cd.getData("text/plain");
|
|
938
|
+
if (text.length > 0) return { kind: "text", text };
|
|
939
|
+
return { kind: "none" };
|
|
940
|
+
}
|
|
941
|
+
|
|
332
942
|
// src/BehindImageSelectAffordance.tsx
|
|
333
943
|
var import_react = require("react");
|
|
334
944
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -645,7 +1255,7 @@ function LinkDialog() {
|
|
|
645
1255
|
|
|
646
1256
|
// src/PageConfigDialog.tsx
|
|
647
1257
|
var import_react3 = require("react");
|
|
648
|
-
var
|
|
1258
|
+
var import_core3 = require("@sofereditor/core");
|
|
649
1259
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
650
1260
|
function PageConfigDialog() {
|
|
651
1261
|
const { pageConfigRequest, resolvePageConfigRequest, setPageSettings } = useEditorContext();
|
|
@@ -679,14 +1289,14 @@ function PageConfigDialog() {
|
|
|
679
1289
|
}, [pageConfigRequest]);
|
|
680
1290
|
(0, import_react3.useEffect)(() => {
|
|
681
1291
|
if (sizePreset === "custom") return;
|
|
682
|
-
const p =
|
|
683
|
-
setWidthMm(roundMm((0,
|
|
684
|
-
setHeightMm(roundMm((0,
|
|
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)));
|
|
685
1295
|
}, [sizePreset]);
|
|
686
1296
|
(0, import_react3.useEffect)(() => {
|
|
687
1297
|
if (marginPreset === "custom") return;
|
|
688
|
-
const px =
|
|
689
|
-
const mm = roundMm((0,
|
|
1298
|
+
const px = import_core3.MARGIN_PRESETS[marginPreset];
|
|
1299
|
+
const mm = roundMm((0, import_core3.pxToMm)(px));
|
|
690
1300
|
setMarginTopMm(mm);
|
|
691
1301
|
setMarginBottomMm(mm);
|
|
692
1302
|
setMarginLeftMm(mm);
|
|
@@ -695,8 +1305,8 @@ function PageConfigDialog() {
|
|
|
695
1305
|
const customWidth = sizePreset === "custom";
|
|
696
1306
|
const previewPx = (0, import_react3.useMemo)(
|
|
697
1307
|
() => ({
|
|
698
|
-
width: Math.round((0,
|
|
699
|
-
height: Math.round((0,
|
|
1308
|
+
width: Math.round((0, import_core3.mmToPx)(widthMm)),
|
|
1309
|
+
height: Math.round((0, import_core3.mmToPx)(heightMm))
|
|
700
1310
|
}),
|
|
701
1311
|
[widthMm, heightMm]
|
|
702
1312
|
);
|
|
@@ -704,12 +1314,12 @@ function PageConfigDialog() {
|
|
|
704
1314
|
const onApply = (e) => {
|
|
705
1315
|
e.preventDefault();
|
|
706
1316
|
const next = {
|
|
707
|
-
width: (0,
|
|
708
|
-
height: (0,
|
|
709
|
-
marginTop: (0,
|
|
710
|
-
marginBottom: (0,
|
|
711
|
-
marginLeft: (0,
|
|
712
|
-
marginRight: (0,
|
|
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)
|
|
713
1323
|
};
|
|
714
1324
|
setPageSettings(next);
|
|
715
1325
|
resolvePageConfigRequest(true);
|
|
@@ -968,14 +1578,14 @@ function roundMm(mm) {
|
|
|
968
1578
|
return Math.round(mm * 10) / 10;
|
|
969
1579
|
}
|
|
970
1580
|
function hydrateFromSettings(s, setters) {
|
|
971
|
-
const preset = (0,
|
|
1581
|
+
const preset = (0, import_core3.detectPreset)(s.width, s.height);
|
|
972
1582
|
setters.setSizePreset(preset);
|
|
973
|
-
setters.setWidthMm(roundMm((0,
|
|
974
|
-
setters.setHeightMm(roundMm((0,
|
|
975
|
-
const top = roundMm((0,
|
|
976
|
-
const bottom = roundMm((0,
|
|
977
|
-
const left = roundMm((0,
|
|
978
|
-
const right = roundMm((0,
|
|
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));
|
|
979
1589
|
setters.setMarginTopMm(top);
|
|
980
1590
|
setters.setMarginBottomMm(bottom);
|
|
981
1591
|
setters.setMarginLeftMm(left);
|
|
@@ -986,7 +1596,7 @@ function detectMarginPreset(s) {
|
|
|
986
1596
|
const TOL = 1;
|
|
987
1597
|
const allEqual = Math.abs(s.marginTop - s.marginBottom) <= TOL && Math.abs(s.marginTop - s.marginLeft) <= TOL && Math.abs(s.marginTop - s.marginRight) <= TOL;
|
|
988
1598
|
if (!allEqual) return "custom";
|
|
989
|
-
for (const [name, px] of Object.entries(
|
|
1599
|
+
for (const [name, px] of Object.entries(import_core3.MARGIN_PRESETS)) {
|
|
990
1600
|
if (Math.abs(s.marginTop - px) <= TOL) return name;
|
|
991
1601
|
}
|
|
992
1602
|
return "custom";
|
|
@@ -1546,7 +2156,7 @@ function Handle({
|
|
|
1546
2156
|
|
|
1547
2157
|
// src/RemoteCursorsOverlay.tsx
|
|
1548
2158
|
var import_react7 = require("react");
|
|
1549
|
-
var
|
|
2159
|
+
var import_core4 = require("@sofereditor/core");
|
|
1550
2160
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1551
2161
|
var DEFAULT_COLOR = "#3b82f6";
|
|
1552
2162
|
function RemoteCursorsOverlay({
|
|
@@ -1569,7 +2179,7 @@ function RemoteCursorsOverlay({
|
|
|
1569
2179
|
if (clientId === awareness.clientID) return;
|
|
1570
2180
|
const s = state;
|
|
1571
2181
|
if (!s.cursor) return;
|
|
1572
|
-
const sel = (0,
|
|
2182
|
+
const sel = (0, import_core4.decodeSelection)(doc, s.cursor);
|
|
1573
2183
|
if (!sel) return;
|
|
1574
2184
|
const color = s.user?.color || DEFAULT_COLOR;
|
|
1575
2185
|
const name = s.user?.name || "An\xF4nimo";
|
|
@@ -1716,11 +2326,11 @@ function RemoteCursorsOverlay({
|
|
|
1716
2326
|
|
|
1717
2327
|
// src/NodeView.tsx
|
|
1718
2328
|
var import_react10 = require("react");
|
|
1719
|
-
var
|
|
2329
|
+
var import_core6 = require("@sofereditor/core");
|
|
1720
2330
|
|
|
1721
2331
|
// src/renderInline.tsx
|
|
1722
2332
|
var import_react8 = require("react");
|
|
1723
|
-
var
|
|
2333
|
+
var import_core5 = require("@sofereditor/core");
|
|
1724
2334
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1725
2335
|
function renderInline(delta, keyPrefix) {
|
|
1726
2336
|
if (delta.length === 0 || delta.length === 1 && typeof delta[0].insert === "string" && delta[0].insert === "") {
|
|
@@ -1736,7 +2346,7 @@ function renderInline(delta, keyPrefix) {
|
|
|
1736
2346
|
const key = `${keyPrefix}-${offset}`;
|
|
1737
2347
|
body.push(/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react8.Fragment, { children: wrap(text, op.attributes) }, key));
|
|
1738
2348
|
offset += text.length;
|
|
1739
|
-
} else if ((0,
|
|
2349
|
+
} else if ((0, import_core5.isImageEmbed)(op.insert)) {
|
|
1740
2350
|
const key = `${keyPrefix}-${offset}`;
|
|
1741
2351
|
const layout = op.insert.layout ?? "inline";
|
|
1742
2352
|
const commentMarkId = op.attributes?.comment?.markId;
|
|
@@ -1900,10 +2510,10 @@ function ImageEmbedViewImpl({
|
|
|
1900
2510
|
);
|
|
1901
2511
|
}
|
|
1902
2512
|
function decorateBlanks(text) {
|
|
1903
|
-
const segs = (0,
|
|
2513
|
+
const segs = (0, import_core5.splitUnderscoreRuns)(text);
|
|
1904
2514
|
if (segs.length === 1 && !segs[0].blank) return text;
|
|
1905
2515
|
return segs.map(
|
|
1906
|
-
(s, i) => s.blank ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { "data-blank": "true", style:
|
|
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)
|
|
1907
2517
|
);
|
|
1908
2518
|
}
|
|
1909
2519
|
function wrap(text, attrs) {
|
|
@@ -2101,7 +2711,7 @@ function NodeView({ block, index, children, fragment, tableFragment }) {
|
|
|
2101
2711
|
const common = commonBlockProps(block.attrs, index, block.type, fragment);
|
|
2102
2712
|
switch (block.type) {
|
|
2103
2713
|
case "heading": {
|
|
2104
|
-
const level =
|
|
2714
|
+
const level = clampLevel2(block.attrs.level);
|
|
2105
2715
|
const Tag = `h${level}`;
|
|
2106
2716
|
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2107
2717
|
Tag,
|
|
@@ -2162,7 +2772,7 @@ function NodeView({ block, index, children, fragment, tableFragment }) {
|
|
|
2162
2772
|
function commonBlockProps(attrs, index, type, fragment) {
|
|
2163
2773
|
const style = {};
|
|
2164
2774
|
if (attrs.align) style.textAlign = attrs.align;
|
|
2165
|
-
Object.assign(style, (0,
|
|
2775
|
+
Object.assign(style, (0, import_core6.answerLineStyle)(attrs) ?? {});
|
|
2166
2776
|
const base = {
|
|
2167
2777
|
"data-block-index": index,
|
|
2168
2778
|
"data-block-type": type,
|
|
@@ -2188,7 +2798,7 @@ function cellStyle(attrs, border) {
|
|
|
2188
2798
|
if (attrs?.bgColor) style.backgroundColor = attrs.bgColor;
|
|
2189
2799
|
return Object.keys(style).length > 0 ? style : void 0;
|
|
2190
2800
|
}
|
|
2191
|
-
function
|
|
2801
|
+
function clampLevel2(l) {
|
|
2192
2802
|
if (l === 2 || l === 3 || l === 4 || l === 5 || l === 6) return l;
|
|
2193
2803
|
return 1;
|
|
2194
2804
|
}
|
|
@@ -2209,7 +2819,7 @@ function TableView({ block, index, tableFragment }) {
|
|
|
2209
2819
|
const rect = (0, import_react10.useMemo)(() => {
|
|
2210
2820
|
if (editor.selection.anchor.blockIndex !== index) return null;
|
|
2211
2821
|
if (editor.selection.focus.blockIndex !== index) return null;
|
|
2212
|
-
return (0,
|
|
2822
|
+
return (0, import_core6.tableRectSelection)(editor.doc, editor.selection);
|
|
2213
2823
|
}, [editor.doc, editor.selection, index]);
|
|
2214
2824
|
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "ed-table-wrap", children: [
|
|
2215
2825
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
@@ -2245,7 +2855,7 @@ function TableView({ block, index, tableFragment }) {
|
|
|
2245
2855
|
cell?.attrs,
|
|
2246
2856
|
// rowStart/rowEnd são os limites do FRAGMENTO: numa tabela
|
|
2247
2857
|
// quebrada entre páginas, cada página fecha a própria caixa.
|
|
2248
|
-
(0,
|
|
2858
|
+
(0, import_core6.cellBorderStyle)(
|
|
2249
2859
|
block.attrs.borderPreset,
|
|
2250
2860
|
{ row: r, col: c, rowspan, colspan, cols, rowStart, rowEnd },
|
|
2251
2861
|
"screen",
|
|
@@ -2821,14 +3431,14 @@ function shallowEqual(a, b) {
|
|
|
2821
3431
|
}
|
|
2822
3432
|
|
|
2823
3433
|
// src/useEditor.ts
|
|
2824
|
-
var
|
|
3434
|
+
var import_core7 = require("@sofereditor/core");
|
|
2825
3435
|
var MAX_INSERT_WIDTH = 600;
|
|
2826
3436
|
function useEditor(opts = {}) {
|
|
2827
|
-
const doc = (0, import_react13.useMemo)(() => opts.document ?? new
|
|
2828
|
-
const history = (0, import_react13.useMemo)(() => new
|
|
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]);
|
|
2829
3439
|
const [snapshot, setSnapshot] = (0, import_react13.useState)(() => doc.toJSON());
|
|
2830
3440
|
const [selection, setSelectionState] = (0, import_react13.useState)(
|
|
2831
|
-
() => (0,
|
|
3441
|
+
() => (0, import_core7.collapsedSelection)({ blockIndex: 0, offset: 0 })
|
|
2832
3442
|
);
|
|
2833
3443
|
const selectionRef = (0, import_react13.useRef)(selection);
|
|
2834
3444
|
selectionRef.current = selection;
|
|
@@ -2893,7 +3503,7 @@ function useEditor(opts = {}) {
|
|
|
2893
3503
|
const isMarkActive = (0, import_react13.useCallback)(
|
|
2894
3504
|
(name, value) => {
|
|
2895
3505
|
const sel = selectionRef.current;
|
|
2896
|
-
const { start, end } = (0,
|
|
3506
|
+
const { start, end } = (0, import_core7.orderedRange)(sel);
|
|
2897
3507
|
if (start.blockIndex === end.blockIndex && start.offset === end.offset) {
|
|
2898
3508
|
const pending = pendingMarksRef.current[name];
|
|
2899
3509
|
if (pending !== void 0) {
|
|
@@ -2902,7 +3512,7 @@ function useEditor(opts = {}) {
|
|
|
2902
3512
|
}
|
|
2903
3513
|
const yText2 = doc.getBlockText(start.blockIndex);
|
|
2904
3514
|
if (!yText2 || start.offset === 0) return false;
|
|
2905
|
-
return (0,
|
|
3515
|
+
return (0, import_core7.isMarkUniformInRange)(yText2, start.offset - 1, start.offset, name, value);
|
|
2906
3516
|
}
|
|
2907
3517
|
if (start.blockIndex !== end.blockIndex) {
|
|
2908
3518
|
for (let i = start.blockIndex; i <= end.blockIndex; i++) {
|
|
@@ -2911,19 +3521,19 @@ function useEditor(opts = {}) {
|
|
|
2911
3521
|
const s = i === start.blockIndex ? start.offset : 0;
|
|
2912
3522
|
const e = i === end.blockIndex ? end.offset : yText2.length;
|
|
2913
3523
|
if (s >= e) continue;
|
|
2914
|
-
if (!(0,
|
|
3524
|
+
if (!(0, import_core7.isMarkUniformInRange)(yText2, s, e, name, value)) return false;
|
|
2915
3525
|
}
|
|
2916
3526
|
return true;
|
|
2917
3527
|
}
|
|
2918
3528
|
const yText = doc.getBlockText(start.blockIndex);
|
|
2919
3529
|
if (!yText) return false;
|
|
2920
|
-
return (0,
|
|
3530
|
+
return (0, import_core7.isMarkUniformInRange)(yText, start.offset, end.offset, name, value);
|
|
2921
3531
|
},
|
|
2922
3532
|
[doc]
|
|
2923
3533
|
);
|
|
2924
3534
|
const getActiveMarks = (0, import_react13.useCallback)(() => {
|
|
2925
3535
|
const sel = selectionRef.current;
|
|
2926
|
-
const { start, end } = (0,
|
|
3536
|
+
const { start, end } = (0, import_core7.orderedRange)(sel);
|
|
2927
3537
|
if (start.blockIndex !== end.blockIndex) {
|
|
2928
3538
|
return {};
|
|
2929
3539
|
}
|
|
@@ -2931,14 +3541,14 @@ function useEditor(opts = {}) {
|
|
|
2931
3541
|
if (!yText) return {};
|
|
2932
3542
|
if (start.offset === end.offset) {
|
|
2933
3543
|
if (start.offset === 0) return {};
|
|
2934
|
-
return (0,
|
|
3544
|
+
return (0, import_core7.getMarksInRange)(yText, start.offset - 1, start.offset);
|
|
2935
3545
|
}
|
|
2936
|
-
return (0,
|
|
3546
|
+
return (0, import_core7.getMarksInRange)(yText, start.offset, end.offset);
|
|
2937
3547
|
}, [doc]);
|
|
2938
3548
|
const toggleMark = (0, import_react13.useCallback)(
|
|
2939
3549
|
(name, value) => {
|
|
2940
3550
|
const sel = selectionRef.current;
|
|
2941
|
-
const { start, end } = (0,
|
|
3551
|
+
const { start, end } = (0, import_core7.orderedRange)(sel);
|
|
2942
3552
|
const isCollapsed = start.blockIndex === end.blockIndex && start.offset === end.offset;
|
|
2943
3553
|
if (isCollapsed) {
|
|
2944
3554
|
const next = { ...pendingMarksRef.current };
|
|
@@ -2951,39 +3561,39 @@ function useEditor(opts = {}) {
|
|
|
2951
3561
|
setPendingMarks(next);
|
|
2952
3562
|
return;
|
|
2953
3563
|
}
|
|
2954
|
-
(0,
|
|
3564
|
+
(0, import_core7.toggleMark)(ctxRef.current, name, value);
|
|
2955
3565
|
},
|
|
2956
3566
|
[isMarkActive, setPendingMarks]
|
|
2957
3567
|
);
|
|
2958
3568
|
const setMark = (0, import_react13.useCallback)(
|
|
2959
3569
|
(name, value) => {
|
|
2960
3570
|
const sel = selectionRef.current;
|
|
2961
|
-
const { start, end } = (0,
|
|
3571
|
+
const { start, end } = (0, import_core7.orderedRange)(sel);
|
|
2962
3572
|
const isCollapsed = start.blockIndex === end.blockIndex && start.offset === end.offset;
|
|
2963
3573
|
if (isCollapsed) {
|
|
2964
3574
|
setPendingMarks({ ...pendingMarksRef.current, [name]: value });
|
|
2965
3575
|
return;
|
|
2966
3576
|
}
|
|
2967
|
-
(0,
|
|
3577
|
+
(0, import_core7.setMark)(ctxRef.current, name, value);
|
|
2968
3578
|
},
|
|
2969
3579
|
[setPendingMarks]
|
|
2970
3580
|
);
|
|
2971
3581
|
const removeMark = (0, import_react13.useCallback)(
|
|
2972
3582
|
(name) => {
|
|
2973
3583
|
const sel = selectionRef.current;
|
|
2974
|
-
const { start, end } = (0,
|
|
3584
|
+
const { start, end } = (0, import_core7.orderedRange)(sel);
|
|
2975
3585
|
const isCollapsed = start.blockIndex === end.blockIndex && start.offset === end.offset;
|
|
2976
3586
|
if (isCollapsed) {
|
|
2977
3587
|
setPendingMarks({ ...pendingMarksRef.current, [name]: null });
|
|
2978
3588
|
return;
|
|
2979
3589
|
}
|
|
2980
|
-
(0,
|
|
3590
|
+
(0, import_core7.removeMark)(ctxRef.current, name);
|
|
2981
3591
|
},
|
|
2982
3592
|
[setPendingMarks]
|
|
2983
3593
|
);
|
|
2984
3594
|
const getBlockType = (0, import_react13.useCallback)(() => {
|
|
2985
3595
|
const sel = selectionRef.current;
|
|
2986
|
-
const { start, end } = (0,
|
|
3596
|
+
const { start, end } = (0, import_core7.orderedRange)(sel);
|
|
2987
3597
|
const first = doc.getBlockType(start.blockIndex);
|
|
2988
3598
|
if (first === void 0) return "paragraph";
|
|
2989
3599
|
for (let i = start.blockIndex + 1; i <= end.blockIndex; i++) {
|
|
@@ -2994,7 +3604,7 @@ function useEditor(opts = {}) {
|
|
|
2994
3604
|
const getBlockAttr = (0, import_react13.useCallback)(
|
|
2995
3605
|
(key) => {
|
|
2996
3606
|
const sel = selectionRef.current;
|
|
2997
|
-
const { start, end } = (0,
|
|
3607
|
+
const { start, end } = (0, import_core7.orderedRange)(sel);
|
|
2998
3608
|
const first = doc.getBlockAttrs(start.blockIndex)[key];
|
|
2999
3609
|
for (let i = start.blockIndex + 1; i <= end.blockIndex; i++) {
|
|
3000
3610
|
const next = doc.getBlockAttrs(i)[key];
|
|
@@ -3005,19 +3615,19 @@ function useEditor(opts = {}) {
|
|
|
3005
3615
|
[doc]
|
|
3006
3616
|
);
|
|
3007
3617
|
const setBlockType = (0, import_react13.useCallback)((type, attrs) => {
|
|
3008
|
-
(0,
|
|
3618
|
+
(0, import_core7.setBlockType)(ctxRef.current, type, attrs);
|
|
3009
3619
|
}, []);
|
|
3010
3620
|
const setBlockAttr = (0, import_react13.useCallback)(
|
|
3011
3621
|
(key, value) => {
|
|
3012
|
-
(0,
|
|
3622
|
+
(0, import_core7.setBlockAttr)(ctxRef.current, key, value);
|
|
3013
3623
|
},
|
|
3014
3624
|
[]
|
|
3015
3625
|
);
|
|
3016
3626
|
const setAlign = (0, import_react13.useCallback)((value) => {
|
|
3017
3627
|
const sel = selectionRef.current;
|
|
3018
3628
|
const inCell = sel.focus.cellIndex != null;
|
|
3019
|
-
if (inCell) (0,
|
|
3020
|
-
else (0,
|
|
3629
|
+
if (inCell) (0, import_core7.setCellAttr)(ctxRef.current, "align", value);
|
|
3630
|
+
else (0, import_core7.setBlockAttr)(ctxRef.current, "align", value);
|
|
3021
3631
|
}, []);
|
|
3022
3632
|
const getAlign = (0, import_react13.useCallback)(() => {
|
|
3023
3633
|
const sel = selectionRef.current;
|
|
@@ -3027,7 +3637,7 @@ function useEditor(opts = {}) {
|
|
|
3027
3637
|
return getBlockAttr("align");
|
|
3028
3638
|
}, [doc, getBlockAttr]);
|
|
3029
3639
|
const setCellBackground = (0, import_react13.useCallback)((color) => {
|
|
3030
|
-
(0,
|
|
3640
|
+
(0, import_core7.setCellAttr)(ctxRef.current, "bgColor", color);
|
|
3031
3641
|
}, []);
|
|
3032
3642
|
const getCellBackground = (0, import_react13.useCallback)(() => {
|
|
3033
3643
|
const sel = selectionRef.current;
|
|
@@ -3037,7 +3647,7 @@ function useEditor(opts = {}) {
|
|
|
3037
3647
|
const setTableBorderPreset = (0, import_react13.useCallback)((preset) => {
|
|
3038
3648
|
const sel = selectionRef.current;
|
|
3039
3649
|
if (!doc.isTable(sel.focus.blockIndex)) return;
|
|
3040
|
-
(0,
|
|
3650
|
+
(0, import_core7.setBlockAttrAtIndex)(ctxRef.current, sel.focus.blockIndex, "borderPreset", preset);
|
|
3041
3651
|
}, [doc]);
|
|
3042
3652
|
const getTableBorderPreset = (0, import_react13.useCallback)(() => {
|
|
3043
3653
|
const sel = selectionRef.current;
|
|
@@ -3047,7 +3657,7 @@ function useEditor(opts = {}) {
|
|
|
3047
3657
|
const setTableBorderColor = (0, import_react13.useCallback)((color) => {
|
|
3048
3658
|
const sel = selectionRef.current;
|
|
3049
3659
|
if (!doc.isTable(sel.focus.blockIndex)) return;
|
|
3050
|
-
(0,
|
|
3660
|
+
(0, import_core7.setBlockAttrAtIndex)(ctxRef.current, sel.focus.blockIndex, "borderColor", color);
|
|
3051
3661
|
}, [doc]);
|
|
3052
3662
|
const getTableBorderColor = (0, import_react13.useCallback)(() => {
|
|
3053
3663
|
const sel = selectionRef.current;
|
|
@@ -3057,7 +3667,7 @@ function useEditor(opts = {}) {
|
|
|
3057
3667
|
const isListActive = (0, import_react13.useCallback)(
|
|
3058
3668
|
(kind) => {
|
|
3059
3669
|
const sel = selectionRef.current;
|
|
3060
|
-
const { start, end } = (0,
|
|
3670
|
+
const { start, end } = (0, import_core7.orderedRange)(sel);
|
|
3061
3671
|
for (let i = start.blockIndex; i <= end.blockIndex; i++) {
|
|
3062
3672
|
if (doc.getBlockType(i) !== "listItem") return false;
|
|
3063
3673
|
if (doc.getBlockAttrs(i).listKind !== kind) return false;
|
|
@@ -3067,112 +3677,112 @@ function useEditor(opts = {}) {
|
|
|
3067
3677
|
[doc]
|
|
3068
3678
|
);
|
|
3069
3679
|
const toggleList = (0, import_react13.useCallback)((kind) => {
|
|
3070
|
-
(0,
|
|
3680
|
+
(0, import_core7.toggleList)(ctxRef.current, kind);
|
|
3071
3681
|
}, []);
|
|
3072
3682
|
const indentList = (0, import_react13.useCallback)(() => {
|
|
3073
|
-
(0,
|
|
3683
|
+
(0, import_core7.indentList)(ctxRef.current);
|
|
3074
3684
|
}, []);
|
|
3075
3685
|
const dedentList = (0, import_react13.useCallback)(() => {
|
|
3076
|
-
(0,
|
|
3686
|
+
(0, import_core7.dedentList)(ctxRef.current);
|
|
3077
3687
|
}, []);
|
|
3078
3688
|
const splitListItem = (0, import_react13.useCallback)(() => {
|
|
3079
|
-
return (0,
|
|
3689
|
+
return (0, import_core7.splitListItem)(ctxRef.current);
|
|
3080
3690
|
}, []);
|
|
3081
3691
|
const isInTable = (0, import_react13.useCallback)(() => {
|
|
3082
3692
|
return selectionRef.current.focus.cellIndex != null;
|
|
3083
3693
|
}, []);
|
|
3084
3694
|
const getTableLocation = (0, import_react13.useCallback)(() => {
|
|
3085
|
-
return (0,
|
|
3695
|
+
return (0, import_core7.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3086
3696
|
}, [doc]);
|
|
3087
3697
|
const insertTable = (0, import_react13.useCallback)((rows, cols) => {
|
|
3088
|
-
(0,
|
|
3698
|
+
(0, import_core7.insertTable)(ctxRef.current, rows, cols);
|
|
3089
3699
|
}, []);
|
|
3090
3700
|
const insertAnswerLines = (0, import_react13.useCallback)((count, spacing) => {
|
|
3091
|
-
(0,
|
|
3701
|
+
(0, import_core7.insertAnswerLines)(ctxRef.current, count, spacing);
|
|
3092
3702
|
}, []);
|
|
3093
3703
|
const deleteTable = (0, import_react13.useCallback)((blockIndex) => {
|
|
3094
3704
|
const idx = blockIndex ?? selectionRef.current.focus.blockIndex;
|
|
3095
|
-
(0,
|
|
3705
|
+
(0, import_core7.deleteTable)(ctxRef.current, idx);
|
|
3096
3706
|
}, []);
|
|
3097
3707
|
const insertRowAbove = (0, import_react13.useCallback)(() => {
|
|
3098
|
-
const loc = (0,
|
|
3708
|
+
const loc = (0, import_core7.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3099
3709
|
if (!loc) return;
|
|
3100
|
-
(0,
|
|
3710
|
+
(0, import_core7.insertTableRow)(ctxRef.current, loc.blockIndex, loc.row, "before");
|
|
3101
3711
|
}, [doc]);
|
|
3102
3712
|
const insertRowBelow = (0, import_react13.useCallback)(() => {
|
|
3103
|
-
const loc = (0,
|
|
3713
|
+
const loc = (0, import_core7.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3104
3714
|
if (!loc) return;
|
|
3105
|
-
(0,
|
|
3715
|
+
(0, import_core7.insertTableRow)(ctxRef.current, loc.blockIndex, loc.row, "after");
|
|
3106
3716
|
}, [doc]);
|
|
3107
3717
|
const deleteCurrentRow = (0, import_react13.useCallback)(() => {
|
|
3108
|
-
const loc = (0,
|
|
3718
|
+
const loc = (0, import_core7.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3109
3719
|
if (!loc) return;
|
|
3110
|
-
(0,
|
|
3720
|
+
(0, import_core7.deleteTableRow)(ctxRef.current, loc.blockIndex, loc.row);
|
|
3111
3721
|
}, [doc]);
|
|
3112
3722
|
const insertColumnLeft = (0, import_react13.useCallback)(() => {
|
|
3113
|
-
const loc = (0,
|
|
3723
|
+
const loc = (0, import_core7.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3114
3724
|
if (!loc) return;
|
|
3115
|
-
(0,
|
|
3725
|
+
(0, import_core7.insertTableColumn)(ctxRef.current, loc.blockIndex, loc.col, "before");
|
|
3116
3726
|
}, [doc]);
|
|
3117
3727
|
const insertColumnRight = (0, import_react13.useCallback)(() => {
|
|
3118
|
-
const loc = (0,
|
|
3728
|
+
const loc = (0, import_core7.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3119
3729
|
if (!loc) return;
|
|
3120
|
-
(0,
|
|
3730
|
+
(0, import_core7.insertTableColumn)(ctxRef.current, loc.blockIndex, loc.col, "after");
|
|
3121
3731
|
}, [doc]);
|
|
3122
3732
|
const deleteCurrentColumn = (0, import_react13.useCallback)(() => {
|
|
3123
|
-
const loc = (0,
|
|
3733
|
+
const loc = (0, import_core7.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3124
3734
|
if (!loc) return;
|
|
3125
|
-
(0,
|
|
3735
|
+
(0, import_core7.deleteTableColumn)(ctxRef.current, loc.blockIndex, loc.col);
|
|
3126
3736
|
}, [doc]);
|
|
3127
3737
|
const moveToNextCell = (0, import_react13.useCallback)(() => {
|
|
3128
|
-
(0,
|
|
3738
|
+
(0, import_core7.moveToNextCell)(ctxRef.current);
|
|
3129
3739
|
}, []);
|
|
3130
3740
|
const moveToPrevCell = (0, import_react13.useCallback)(() => {
|
|
3131
|
-
(0,
|
|
3741
|
+
(0, import_core7.moveToPrevCell)(ctxRef.current);
|
|
3132
3742
|
}, []);
|
|
3133
3743
|
const mergeRight = (0, import_react13.useCallback)(() => {
|
|
3134
|
-
const loc = (0,
|
|
3744
|
+
const loc = (0, import_core7.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3135
3745
|
if (!loc) return false;
|
|
3136
|
-
return (0,
|
|
3746
|
+
return (0, import_core7.mergeRight)(ctxRef.current, loc.blockIndex, loc.row, loc.col);
|
|
3137
3747
|
}, [doc]);
|
|
3138
3748
|
const mergeDown = (0, import_react13.useCallback)(() => {
|
|
3139
|
-
const loc = (0,
|
|
3749
|
+
const loc = (0, import_core7.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3140
3750
|
if (!loc) return false;
|
|
3141
|
-
return (0,
|
|
3751
|
+
return (0, import_core7.mergeDown)(ctxRef.current, loc.blockIndex, loc.row, loc.col);
|
|
3142
3752
|
}, [doc]);
|
|
3143
3753
|
const splitCell = (0, import_react13.useCallback)(() => {
|
|
3144
|
-
const loc = (0,
|
|
3754
|
+
const loc = (0, import_core7.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3145
3755
|
if (!loc) return false;
|
|
3146
|
-
return (0,
|
|
3756
|
+
return (0, import_core7.splitCell)(ctxRef.current, loc.blockIndex, loc.row, loc.col);
|
|
3147
3757
|
}, [doc]);
|
|
3148
3758
|
const setColumnWidth = (0, import_react13.useCallback)(
|
|
3149
3759
|
(blockIndex, col, widthPx) => {
|
|
3150
|
-
(0,
|
|
3760
|
+
(0, import_core7.setColumnWidth)(ctxRef.current, blockIndex, col, widthPx);
|
|
3151
3761
|
},
|
|
3152
3762
|
[]
|
|
3153
3763
|
);
|
|
3154
3764
|
const getTableRect = (0, import_react13.useCallback)(
|
|
3155
|
-
() => (0,
|
|
3765
|
+
() => (0, import_core7.tableRectSelection)(doc, selectionRef.current),
|
|
3156
3766
|
[doc]
|
|
3157
3767
|
);
|
|
3158
3768
|
const hasTableRectSelection = (0, import_react13.useCallback)(() => {
|
|
3159
|
-
return (0,
|
|
3769
|
+
return (0, import_core7.tableRectSelection)(doc, selectionRef.current) !== null;
|
|
3160
3770
|
}, [doc]);
|
|
3161
3771
|
const mergeSelection = (0, import_react13.useCallback)(() => {
|
|
3162
|
-
return (0,
|
|
3772
|
+
return (0, import_core7.mergeSelection)(ctxRef.current);
|
|
3163
3773
|
}, []);
|
|
3164
3774
|
const insertImage = (0, import_react13.useCallback)((embed) => {
|
|
3165
|
-
(0,
|
|
3775
|
+
(0, import_core7.insertImage)(ctxRef.current, embed);
|
|
3166
3776
|
}, []);
|
|
3167
3777
|
const setImageAttrs = (0, import_react13.useCallback)(
|
|
3168
3778
|
(blockIndex, offset, partial, cellIndex, newOffset) => {
|
|
3169
|
-
(0,
|
|
3779
|
+
(0, import_core7.setImageAttrs)(ctxRef.current, blockIndex, offset, partial, cellIndex, newOffset);
|
|
3170
3780
|
},
|
|
3171
3781
|
[]
|
|
3172
3782
|
);
|
|
3173
3783
|
const moveEmbedAnchor = (0, import_react13.useCallback)(
|
|
3174
3784
|
(from, to, newOffsetX, newOffsetY) => {
|
|
3175
|
-
(0,
|
|
3785
|
+
(0, import_core7.moveEmbedAnchor)(ctxRef.current, from, to, newOffsetX, newOffsetY);
|
|
3176
3786
|
},
|
|
3177
3787
|
[]
|
|
3178
3788
|
);
|
|
@@ -3190,7 +3800,7 @@ function useEditor(opts = {}) {
|
|
|
3190
3800
|
}
|
|
3191
3801
|
const upload = uploadImageRef.current;
|
|
3192
3802
|
const src = upload ? await upload(file) : dataUrl;
|
|
3193
|
-
(0,
|
|
3803
|
+
(0, import_core7.insertImage)(ctxRef.current, { type: "image", src, width: w, height: h });
|
|
3194
3804
|
}, []);
|
|
3195
3805
|
const getSelectedEmbed = (0, import_react13.useCallback)(() => {
|
|
3196
3806
|
const sel = selectionRef.current;
|
|
@@ -3209,7 +3819,7 @@ function useEditor(opts = {}) {
|
|
|
3209
3819
|
cursor += op.insert.length;
|
|
3210
3820
|
continue;
|
|
3211
3821
|
}
|
|
3212
|
-
if (cursor === start && (0,
|
|
3822
|
+
if (cursor === start && (0, import_core7.isImageEmbed)(op.insert)) {
|
|
3213
3823
|
return {
|
|
3214
3824
|
blockIndex: sel.anchor.blockIndex,
|
|
3215
3825
|
cellIndex: sel.anchor.cellIndex,
|
|
@@ -3404,7 +4014,7 @@ function Editor({
|
|
|
3404
4014
|
const sel = readDomSelection(root);
|
|
3405
4015
|
awareness.setLocalStateField(
|
|
3406
4016
|
"cursor",
|
|
3407
|
-
sel ? (0,
|
|
4017
|
+
sel ? (0, import_core8.encodeSelection)(doc, sel) ?? null : null
|
|
3408
4018
|
);
|
|
3409
4019
|
};
|
|
3410
4020
|
const onSelChange = () => {
|
|
@@ -3705,14 +4315,14 @@ function Editor({
|
|
|
3705
4315
|
const data = e.data ?? "";
|
|
3706
4316
|
if (data.length > 0) {
|
|
3707
4317
|
e.preventDefault();
|
|
3708
|
-
(0,
|
|
4318
|
+
(0, import_core8.insertText)(ctx, data, ed.consumePendingMarks());
|
|
3709
4319
|
}
|
|
3710
4320
|
return;
|
|
3711
4321
|
}
|
|
3712
4322
|
case "insertLineBreak": {
|
|
3713
4323
|
e.preventDefault();
|
|
3714
4324
|
if (ed.getBlockType() === "listItem") {
|
|
3715
|
-
(0,
|
|
4325
|
+
(0, import_core8.insertText)(ctx, "\n", ed.consumePendingMarks());
|
|
3716
4326
|
return;
|
|
3717
4327
|
}
|
|
3718
4328
|
const selEmbed = ed.getSelectedEmbed();
|
|
@@ -3732,7 +4342,7 @@ function Editor({
|
|
|
3732
4342
|
});
|
|
3733
4343
|
}
|
|
3734
4344
|
if (ed.splitListItem()) return;
|
|
3735
|
-
(0,
|
|
4345
|
+
(0, import_core8.insertParagraph)(ctx);
|
|
3736
4346
|
return;
|
|
3737
4347
|
}
|
|
3738
4348
|
case "insertParagraph": {
|
|
@@ -3754,14 +4364,14 @@ function Editor({
|
|
|
3754
4364
|
});
|
|
3755
4365
|
}
|
|
3756
4366
|
if (ed.splitListItem()) return;
|
|
3757
|
-
(0,
|
|
4367
|
+
(0, import_core8.insertParagraph)(ctx);
|
|
3758
4368
|
return;
|
|
3759
4369
|
}
|
|
3760
4370
|
case "insertReplacementText": {
|
|
3761
4371
|
const text = e.data ?? e.dataTransfer?.getData("text/plain") ?? "";
|
|
3762
4372
|
if (text.length > 0) {
|
|
3763
4373
|
e.preventDefault();
|
|
3764
|
-
(0,
|
|
4374
|
+
(0, import_core8.insertText)(ctx, text, ed.consumePendingMarks());
|
|
3765
4375
|
}
|
|
3766
4376
|
return;
|
|
3767
4377
|
}
|
|
@@ -3774,7 +4384,7 @@ function Editor({
|
|
|
3774
4384
|
case "deleteSoftLineBackward":
|
|
3775
4385
|
case "deleteHardLineBackward": {
|
|
3776
4386
|
e.preventDefault();
|
|
3777
|
-
(0,
|
|
4387
|
+
(0, import_core8.deleteBackward)(ctx);
|
|
3778
4388
|
return;
|
|
3779
4389
|
}
|
|
3780
4390
|
case "deleteContentForward":
|
|
@@ -3782,7 +4392,7 @@ function Editor({
|
|
|
3782
4392
|
case "deleteSoftLineForward":
|
|
3783
4393
|
case "deleteHardLineForward": {
|
|
3784
4394
|
e.preventDefault();
|
|
3785
|
-
(0,
|
|
4395
|
+
(0, import_core8.deleteForward)(ctx);
|
|
3786
4396
|
return;
|
|
3787
4397
|
}
|
|
3788
4398
|
case "historyUndo": {
|
|
@@ -3809,10 +4419,10 @@ function Editor({
|
|
|
3809
4419
|
if (!root) return;
|
|
3810
4420
|
const writeSlice = (e) => {
|
|
3811
4421
|
const ctx = ctxRef.current;
|
|
3812
|
-
const slice = (0,
|
|
4422
|
+
const slice = (0, import_core8.serializeSelection)(ctx.doc, ctx.getSelection());
|
|
3813
4423
|
if (!slice || !e.clipboardData) return false;
|
|
3814
|
-
e.clipboardData.setData(
|
|
3815
|
-
e.clipboardData.setData("text/plain", (0,
|
|
4424
|
+
e.clipboardData.setData(import_core8.SOFER_MIME, JSON.stringify(slice));
|
|
4425
|
+
e.clipboardData.setData("text/plain", (0, import_core8.sliceToText)(slice));
|
|
3816
4426
|
return true;
|
|
3817
4427
|
};
|
|
3818
4428
|
const onCopy = (e) => {
|
|
@@ -3820,40 +4430,34 @@ function Editor({
|
|
|
3820
4430
|
};
|
|
3821
4431
|
const onCut = (e) => {
|
|
3822
4432
|
e.preventDefault();
|
|
3823
|
-
if (writeSlice(e)) (0,
|
|
4433
|
+
if (writeSlice(e)) (0, import_core8.deleteSelection)(ctxRef.current);
|
|
3824
4434
|
};
|
|
3825
4435
|
const onPaste = (e) => {
|
|
3826
4436
|
const ctx = ctxRef.current;
|
|
3827
4437
|
const cd = e.clipboardData;
|
|
3828
4438
|
if (!cd) return;
|
|
3829
|
-
const
|
|
3830
|
-
if (
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
4439
|
+
const plan = planPaste(cd);
|
|
4440
|
+
if (plan.kind === "none") return;
|
|
4441
|
+
e.preventDefault();
|
|
4442
|
+
switch (plan.kind) {
|
|
4443
|
+
case "sofer":
|
|
4444
|
+
case "html":
|
|
4445
|
+
(0, import_core8.insertSlice)(ctx, plan.slice);
|
|
4446
|
+
return;
|
|
4447
|
+
case "images":
|
|
4448
|
+
void (async () => {
|
|
4449
|
+
for (const f of plan.files) await editorRef.current.insertImageFromFile(f);
|
|
4450
|
+
})();
|
|
4451
|
+
return;
|
|
4452
|
+
case "text": {
|
|
4453
|
+
const lines = plan.text.split(/\r\n|\r|\n/);
|
|
4454
|
+
lines.forEach((line, i) => {
|
|
4455
|
+
if (i > 0) (0, import_core8.insertParagraph)(ctx);
|
|
4456
|
+
if (line.length > 0) (0, import_core8.insertText)(ctx, line);
|
|
4457
|
+
});
|
|
4458
|
+
return;
|
|
3839
4459
|
}
|
|
3840
4460
|
}
|
|
3841
|
-
const images = Array.from(cd.files ?? []).filter((f) => f.type.startsWith("image/"));
|
|
3842
|
-
if (images.length > 0) {
|
|
3843
|
-
e.preventDefault();
|
|
3844
|
-
void (async () => {
|
|
3845
|
-
for (const f of images) await editorRef.current.insertImageFromFile(f);
|
|
3846
|
-
})();
|
|
3847
|
-
return;
|
|
3848
|
-
}
|
|
3849
|
-
const text = cd.getData("text/plain");
|
|
3850
|
-
if (text.length === 0) return;
|
|
3851
|
-
e.preventDefault();
|
|
3852
|
-
const lines = text.split(/\r\n|\r|\n/);
|
|
3853
|
-
lines.forEach((line, i) => {
|
|
3854
|
-
if (i > 0) (0, import_core6.insertParagraph)(ctx);
|
|
3855
|
-
if (line.length > 0) (0, import_core6.insertText)(ctx, line);
|
|
3856
|
-
});
|
|
3857
4461
|
};
|
|
3858
4462
|
root.addEventListener("copy", onCopy);
|
|
3859
4463
|
root.addEventListener("cut", onCut);
|
|
@@ -3944,7 +4548,7 @@ function Editor({
|
|
|
3944
4548
|
const onCompositionEnd = (0, import_react14.useCallback)((e) => {
|
|
3945
4549
|
isComposingRef.current = false;
|
|
3946
4550
|
if (e.data && e.data.length > 0) {
|
|
3947
|
-
(0,
|
|
4551
|
+
(0, import_core8.insertText)(ctxRef.current, e.data);
|
|
3948
4552
|
}
|
|
3949
4553
|
}, []);
|
|
3950
4554
|
const topLevels = (0, import_react14.useMemo)(() => groupTopLevels(snapshot.blocks), [snapshot]);
|
|
@@ -4108,11 +4712,15 @@ function groupTopLevels(snapshot) {
|
|
|
4108
4712
|
const groupStart = i;
|
|
4109
4713
|
const items = [];
|
|
4110
4714
|
const kind = block.attrs.listKind === "ordered" ? "ordered" : "bullet";
|
|
4715
|
+
const leaderLevel = clampListLevel2(block.attrs.listLevel);
|
|
4111
4716
|
const groupStyle = block.attrs.listStyle;
|
|
4112
4717
|
while (i < snapshot.length) {
|
|
4113
4718
|
const b = snapshot[i];
|
|
4114
4719
|
if (b.type !== "listItem") break;
|
|
4115
|
-
|
|
4720
|
+
const bLevel = clampListLevel2(b.attrs.listLevel);
|
|
4721
|
+
if (bLevel <= leaderLevel && (b.attrs.listKind ?? "bullet") !== kind) {
|
|
4722
|
+
break;
|
|
4723
|
+
}
|
|
4116
4724
|
if (i > groupStart) {
|
|
4117
4725
|
if (typeof b.attrs.listStart === "number") break;
|
|
4118
4726
|
const itemStyle = b.attrs.listStyle;
|
|
@@ -4220,7 +4828,7 @@ function buildListTree(items) {
|
|
|
4220
4828
|
function renderListTree(tree, top, start, key) {
|
|
4221
4829
|
const className = `ed-list ed-list-${top.listKind}`;
|
|
4222
4830
|
const style = top.listStyle ? { listStyleType: top.listStyle } : void 0;
|
|
4223
|
-
const items = tree.map((node) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(NodeView, { block: node.entry.block, index: node.entry.index, children: node.children.length > 0 ? renderNestedListTree(node.children,
|
|
4831
|
+
const items = tree.map((node) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(NodeView, { block: node.entry.block, index: node.entry.index, children: node.children.length > 0 ? renderNestedListTree(node.children, `nested-${node.entry.index}`) : null }, node.entry.index));
|
|
4224
4832
|
if (top.listKind === "ordered") {
|
|
4225
4833
|
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
4226
4834
|
"ol",
|
|
@@ -4236,9 +4844,10 @@ function renderListTree(tree, top, start, key) {
|
|
|
4236
4844
|
}
|
|
4237
4845
|
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("ul", { className, "data-list-kind": "bullet", style, children: items }, key);
|
|
4238
4846
|
}
|
|
4239
|
-
function renderNestedListTree(tree,
|
|
4847
|
+
function renderNestedListTree(tree, key) {
|
|
4848
|
+
const kind = tree[0]?.entry.block.attrs.listKind === "ordered" ? "ordered" : "bullet";
|
|
4240
4849
|
const Tag = kind === "ordered" ? "ol" : "ul";
|
|
4241
|
-
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Tag, { className: `ed-list ed-list-${kind}`, "data-list-kind": kind, children: tree.map((node) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(NodeView, { block: node.entry.block, index: node.entry.index, children: node.children.length > 0 ? renderNestedListTree(node.children,
|
|
4850
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Tag, { className: `ed-list ed-list-${kind}`, "data-list-kind": kind, children: tree.map((node) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(NodeView, { block: node.entry.block, index: node.entry.index, children: node.children.length > 0 ? renderNestedListTree(node.children, `nested-${node.entry.index}`) : null }, node.entry.index)) }, key);
|
|
4242
4851
|
}
|
|
4243
4852
|
function clampListLevel2(l) {
|
|
4244
4853
|
if (typeof l !== "number" || !Number.isFinite(l)) return 0;
|
|
@@ -4267,7 +4876,7 @@ function caretRangeFromPoint(x, y) {
|
|
|
4267
4876
|
|
|
4268
4877
|
// src/Toolbar.tsx
|
|
4269
4878
|
var import_react15 = require("react");
|
|
4270
|
-
var
|
|
4879
|
+
var import_core9 = require("@sofereditor/core");
|
|
4271
4880
|
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
4272
4881
|
var FONT_FAMILIES = ["Arial"];
|
|
4273
4882
|
var FONT_SIZES = ["8pt", "10pt", "11pt", "12pt", "14pt", "16pt", "18pt", "24pt", "32pt", "48pt"];
|
|
@@ -4739,7 +5348,7 @@ function AnswerLinesMenu() {
|
|
|
4739
5348
|
document.addEventListener("mousedown", onDown);
|
|
4740
5349
|
return () => document.removeEventListener("mousedown", onDown);
|
|
4741
5350
|
}, [open]);
|
|
4742
|
-
const clamped = Math.max(1, Math.min(
|
|
5351
|
+
const clamped = Math.max(1, Math.min(import_core9.ANSWER_LINE_MAX, Math.trunc(count) || 1));
|
|
4743
5352
|
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { ref: rootRef, className: "ed-toolbar-tablemenu", children: [
|
|
4744
5353
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
4745
5354
|
"button",
|
|
@@ -4772,7 +5381,7 @@ function AnswerLinesMenu() {
|
|
|
4772
5381
|
{
|
|
4773
5382
|
type: "number",
|
|
4774
5383
|
min: 1,
|
|
4775
|
-
max:
|
|
5384
|
+
max: import_core9.ANSWER_LINE_MAX,
|
|
4776
5385
|
value: count,
|
|
4777
5386
|
onChange: (e) => setCount(Number(e.target.value)),
|
|
4778
5387
|
"aria-label": "Quantidade de linhas"
|
|
@@ -4965,7 +5574,7 @@ function TableMenu() {
|
|
|
4965
5574
|
{
|
|
4966
5575
|
className: "ed-toolbar-swatch",
|
|
4967
5576
|
"aria-hidden": true,
|
|
4968
|
-
style: { background: editor.getTableBorderColor() ??
|
|
5577
|
+
style: { background: editor.getTableBorderColor() ?? import_core9.TABLE_BORDER_COLOR }
|
|
4969
5578
|
}
|
|
4970
5579
|
),
|
|
4971
5580
|
"Cor da borda",
|
|
@@ -4973,7 +5582,7 @@ function TableMenu() {
|
|
|
4973
5582
|
"input",
|
|
4974
5583
|
{
|
|
4975
5584
|
type: "color",
|
|
4976
|
-
value: editor.getTableBorderColor() ??
|
|
5585
|
+
value: editor.getTableBorderColor() ?? import_core9.TABLE_BORDER_COLOR,
|
|
4977
5586
|
onChange: (e) => editor.setTableBorderColor(e.target.value),
|
|
4978
5587
|
"aria-label": "Cor da borda"
|
|
4979
5588
|
}
|
|
@@ -5095,6 +5704,7 @@ function MarkButton({ title, pressed, onClick, children }) {
|
|
|
5095
5704
|
getBlockElement,
|
|
5096
5705
|
getCellElement,
|
|
5097
5706
|
getFragmentForOffset,
|
|
5707
|
+
htmlToSlice,
|
|
5098
5708
|
isTableRectSelection,
|
|
5099
5709
|
locatePoint,
|
|
5100
5710
|
readDomSelection,
|