@sofereditor/react 0.5.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 +939 -147
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +45 -2
- package/dist/index.d.ts +45 -2
- package/dist/index.js +831 -38
- 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_core9 = require("@sofereditor/core");
|
|
58
59
|
|
|
59
60
|
// src/dom-bridge.ts
|
|
60
61
|
function findContainingBlockElement(node, root) {
|
|
@@ -329,6 +330,746 @@ 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
|
+
|
|
339
|
+
// src/imageConstraints.ts
|
|
340
|
+
var MAX_INSERT_WIDTH = 600;
|
|
341
|
+
|
|
342
|
+
// src/htmlToSlice.ts
|
|
343
|
+
function htmlToSlice(html) {
|
|
344
|
+
if (!html || html.trim().length === 0) return null;
|
|
345
|
+
let doc;
|
|
346
|
+
try {
|
|
347
|
+
doc = new DOMParser().parseFromString(html, "text/html");
|
|
348
|
+
} catch {
|
|
349
|
+
return null;
|
|
350
|
+
}
|
|
351
|
+
const body = doc.body;
|
|
352
|
+
if (!body) return null;
|
|
353
|
+
const blocks = [];
|
|
354
|
+
try {
|
|
355
|
+
walkBlockLevel(body, {}, blocks);
|
|
356
|
+
} catch {
|
|
357
|
+
return null;
|
|
358
|
+
}
|
|
359
|
+
if (blocks.length === 0) return null;
|
|
360
|
+
normalizeListLevels(blocks);
|
|
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;
|
|
365
|
+
const blockLevel = blocks.length > 1 || blocks[0].type !== "paragraph";
|
|
366
|
+
return { blocks, openStart: false, openEnd: false, ...blockLevel ? { blockLevel: true } : {} };
|
|
367
|
+
}
|
|
368
|
+
var IGNORED_TAGS = /* @__PURE__ */ new Set(["script", "style", "meta", "link", "head", "title", "xml"]);
|
|
369
|
+
var BLOCK_LEVEL_TAGS = /* @__PURE__ */ new Set([
|
|
370
|
+
"p",
|
|
371
|
+
"div",
|
|
372
|
+
"section",
|
|
373
|
+
"article",
|
|
374
|
+
"header",
|
|
375
|
+
"footer",
|
|
376
|
+
"main",
|
|
377
|
+
"figure",
|
|
378
|
+
"figcaption",
|
|
379
|
+
"pre",
|
|
380
|
+
"address"
|
|
381
|
+
]);
|
|
382
|
+
var BLOCK_TRIGGER_TAGS = /* @__PURE__ */ new Set([
|
|
383
|
+
"p",
|
|
384
|
+
"div",
|
|
385
|
+
"ul",
|
|
386
|
+
"ol",
|
|
387
|
+
"li",
|
|
388
|
+
"h1",
|
|
389
|
+
"h2",
|
|
390
|
+
"h3",
|
|
391
|
+
"h4",
|
|
392
|
+
"h5",
|
|
393
|
+
"h6",
|
|
394
|
+
"blockquote",
|
|
395
|
+
"table",
|
|
396
|
+
"tr",
|
|
397
|
+
"td",
|
|
398
|
+
"th"
|
|
399
|
+
]);
|
|
400
|
+
function isNamespacedTag(tag) {
|
|
401
|
+
return tag.includes(":");
|
|
402
|
+
}
|
|
403
|
+
function hasBlockDescendant(el) {
|
|
404
|
+
const all = el.querySelectorAll("*");
|
|
405
|
+
for (const e of Array.from(all)) {
|
|
406
|
+
if (BLOCK_TRIGGER_TAGS.has(e.tagName.toLowerCase())) return true;
|
|
407
|
+
}
|
|
408
|
+
return false;
|
|
409
|
+
}
|
|
410
|
+
function walkBlockLevel(container, marks, blocks) {
|
|
411
|
+
let loose = [];
|
|
412
|
+
const flushLoose = () => {
|
|
413
|
+
if (loose.length === 0) return;
|
|
414
|
+
const nodes = loose;
|
|
415
|
+
loose = [];
|
|
416
|
+
const delta = inlineDeltaFromNodes(nodes, marks);
|
|
417
|
+
if (delta.length > 0) blocks.push(makeBlock("paragraph", delta, {}));
|
|
418
|
+
};
|
|
419
|
+
for (const node of Array.from(container.childNodes)) {
|
|
420
|
+
if (node.nodeType === Node.COMMENT_NODE) continue;
|
|
421
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
422
|
+
loose.push(node);
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
if (node.nodeType !== Node.ELEMENT_NODE) continue;
|
|
426
|
+
const el = node;
|
|
427
|
+
const tag = el.tagName.toLowerCase();
|
|
428
|
+
if (IGNORED_TAGS.has(tag) || isNamespacedTag(tag)) continue;
|
|
429
|
+
switch (tag) {
|
|
430
|
+
case "ul":
|
|
431
|
+
case "ol": {
|
|
432
|
+
flushLoose();
|
|
433
|
+
handleList(el, tag === "ol" ? "ordered" : "bullet", 0, marks, blocks);
|
|
434
|
+
break;
|
|
435
|
+
}
|
|
436
|
+
case "h1":
|
|
437
|
+
case "h2":
|
|
438
|
+
case "h3":
|
|
439
|
+
case "h4":
|
|
440
|
+
case "h5":
|
|
441
|
+
case "h6": {
|
|
442
|
+
flushLoose();
|
|
443
|
+
const level = Number(tag[1]);
|
|
444
|
+
const attrs = { level };
|
|
445
|
+
const align = readAlign(el);
|
|
446
|
+
if (align) attrs.align = align;
|
|
447
|
+
const delta = inlineDeltaFromNodes(Array.from(el.childNodes), marks);
|
|
448
|
+
blocks.push(makeBlock("heading", delta, attrs));
|
|
449
|
+
break;
|
|
450
|
+
}
|
|
451
|
+
case "blockquote": {
|
|
452
|
+
flushLoose();
|
|
453
|
+
handleBlockquote(el, marks, blocks);
|
|
454
|
+
break;
|
|
455
|
+
}
|
|
456
|
+
case "table": {
|
|
457
|
+
flushLoose();
|
|
458
|
+
handleTable(el, marks, blocks);
|
|
459
|
+
break;
|
|
460
|
+
}
|
|
461
|
+
case "li": {
|
|
462
|
+
flushLoose();
|
|
463
|
+
const nestedLists = topLevelListDescendants(el);
|
|
464
|
+
const clone = el.cloneNode(true);
|
|
465
|
+
for (const l of topLevelListDescendants(clone)) l.remove();
|
|
466
|
+
const delta = inlineDeltaFromNodes(Array.from(clone.childNodes), marks);
|
|
467
|
+
blocks.push(makeBlock("listItem", delta, { listKind: "bullet", listLevel: 0 }));
|
|
468
|
+
for (const nested of nestedLists) {
|
|
469
|
+
const nestedKind = nested.tagName.toLowerCase() === "ol" ? "ordered" : "bullet";
|
|
470
|
+
handleList(nested, nestedKind, 1, marks, blocks);
|
|
471
|
+
}
|
|
472
|
+
break;
|
|
473
|
+
}
|
|
474
|
+
case "img":
|
|
475
|
+
loose.push(node);
|
|
476
|
+
break;
|
|
477
|
+
case "br":
|
|
478
|
+
loose.push(node);
|
|
479
|
+
break;
|
|
480
|
+
default: {
|
|
481
|
+
const styleAttr = el.getAttribute("style") ?? "";
|
|
482
|
+
const wordListLevel = parseWordListLevel(styleAttr);
|
|
483
|
+
if (wordListLevel != null && !hasBlockDescendant(el)) {
|
|
484
|
+
flushLoose();
|
|
485
|
+
const marker = findWordListMarker(el);
|
|
486
|
+
const listKind = marker ? detectWordListKind(marker) : "bullet";
|
|
487
|
+
const attrs = { listKind, listLevel: wordListLevel };
|
|
488
|
+
const align = readAlign(el);
|
|
489
|
+
if (align) attrs.align = align;
|
|
490
|
+
const delta = inlineDeltaFromNodes(Array.from(el.childNodes), marks);
|
|
491
|
+
blocks.push(makeBlock("listItem", delta, attrs));
|
|
492
|
+
break;
|
|
493
|
+
}
|
|
494
|
+
if (hasBlockDescendant(el)) {
|
|
495
|
+
flushLoose();
|
|
496
|
+
let nextMarks = applyTagMarks(tag, marks);
|
|
497
|
+
nextMarks = applyStyleMarks(el.getAttribute("style"), nextMarks);
|
|
498
|
+
walkBlockLevel(el, nextMarks, blocks);
|
|
499
|
+
break;
|
|
500
|
+
}
|
|
501
|
+
if (BLOCK_LEVEL_TAGS.has(tag)) {
|
|
502
|
+
flushLoose();
|
|
503
|
+
const attrs = {};
|
|
504
|
+
const align = readAlign(el);
|
|
505
|
+
if (align) attrs.align = align;
|
|
506
|
+
const delta = inlineDeltaFromNodes(Array.from(el.childNodes), marks);
|
|
507
|
+
blocks.push(makeBlock("paragraph", delta, attrs));
|
|
508
|
+
break;
|
|
509
|
+
}
|
|
510
|
+
loose.push(node);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
flushLoose();
|
|
515
|
+
}
|
|
516
|
+
function handleList(listEl, kind, level, marks, blocks) {
|
|
517
|
+
for (const child of Array.from(listEl.children)) {
|
|
518
|
+
const tag = child.tagName.toLowerCase();
|
|
519
|
+
if (tag === "ul" || tag === "ol") {
|
|
520
|
+
const siblingKind = tag === "ol" ? "ordered" : "bullet";
|
|
521
|
+
handleList(child, siblingKind, level + 1, marks, blocks);
|
|
522
|
+
continue;
|
|
523
|
+
}
|
|
524
|
+
if (tag !== "li") continue;
|
|
525
|
+
const nestedLists = topLevelListDescendants(child);
|
|
526
|
+
const clone = child.cloneNode(true);
|
|
527
|
+
for (const l of topLevelListDescendants(clone)) l.remove();
|
|
528
|
+
const delta = inlineDeltaFromNodes(Array.from(clone.childNodes), marks);
|
|
529
|
+
const attrs = { listKind: kind, listLevel: clampLevel(level) };
|
|
530
|
+
const align = readAlign(child);
|
|
531
|
+
if (align) attrs.align = align;
|
|
532
|
+
blocks.push(makeBlock("listItem", delta, attrs));
|
|
533
|
+
for (const nested of nestedLists) {
|
|
534
|
+
const nestedKind = nested.tagName.toLowerCase() === "ol" ? "ordered" : "bullet";
|
|
535
|
+
handleList(nested, nestedKind, level + 1, marks, blocks);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
function topLevelListDescendants(root) {
|
|
540
|
+
const all = Array.from(root.querySelectorAll("ul, ol"));
|
|
541
|
+
return all.filter((el) => {
|
|
542
|
+
let p = el.parentElement;
|
|
543
|
+
while (p && p !== root) {
|
|
544
|
+
const t = p.tagName.toLowerCase();
|
|
545
|
+
if (t === "ul" || t === "ol" || t === "table" || t === "td" || t === "th") return false;
|
|
546
|
+
p = p.parentElement;
|
|
547
|
+
}
|
|
548
|
+
return true;
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
function handleBlockquote(el, marks, blocks) {
|
|
552
|
+
if (!hasBlockDescendant(el)) {
|
|
553
|
+
const attrs = {};
|
|
554
|
+
const align = readAlign(el);
|
|
555
|
+
if (align) attrs.align = align;
|
|
556
|
+
const delta = inlineDeltaFromNodes(Array.from(el.childNodes), marks);
|
|
557
|
+
blocks.push(makeBlock("blockquote", delta, attrs));
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
const nested = [];
|
|
561
|
+
walkBlockLevel(el, marks, nested);
|
|
562
|
+
for (const b of nested) {
|
|
563
|
+
blocks.push(b.type === "paragraph" ? { ...b, type: "blockquote" } : b);
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
function handleTable(table, marks, blocks) {
|
|
567
|
+
for (const row of directRows(table)) {
|
|
568
|
+
const cells = Array.from(row.children).filter(
|
|
569
|
+
(c) => ["td", "th"].includes(c.tagName.toLowerCase())
|
|
570
|
+
);
|
|
571
|
+
for (const cell of cells) {
|
|
572
|
+
const cellBlocks = [];
|
|
573
|
+
walkBlockLevel(cell, marks, cellBlocks);
|
|
574
|
+
for (const b of cellBlocks) {
|
|
575
|
+
const attrs = {};
|
|
576
|
+
if (b.attrs.align) attrs.align = b.attrs.align;
|
|
577
|
+
blocks.push(makeBlock("paragraph", b.delta, attrs));
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
function directRows(table) {
|
|
583
|
+
const rows = [];
|
|
584
|
+
for (const child of Array.from(table.children)) {
|
|
585
|
+
const tag = child.tagName.toLowerCase();
|
|
586
|
+
if (tag === "tr") {
|
|
587
|
+
rows.push(child);
|
|
588
|
+
} else if (tag === "tbody" || tag === "thead" || tag === "tfoot") {
|
|
589
|
+
for (const r of Array.from(child.children)) {
|
|
590
|
+
if (r.tagName.toLowerCase() === "tr") rows.push(r);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
return rows;
|
|
595
|
+
}
|
|
596
|
+
function parseWordListLevel(styleAttr) {
|
|
597
|
+
const m = /mso-list\s*:\s*l\d+\s+level(\d+)/i.exec(styleAttr);
|
|
598
|
+
if (!m) return null;
|
|
599
|
+
const n = Number.parseInt(m[1], 10);
|
|
600
|
+
const fromLevelN = Number.isFinite(n) ? Math.max(0, n - 1) : 0;
|
|
601
|
+
const fromMargin = wordListLevelFromMarginLeft(marginLeftPt(styleAttr));
|
|
602
|
+
return clampLevel(Math.max(fromLevelN, fromMargin));
|
|
603
|
+
}
|
|
604
|
+
function marginLeftPt(styleAttr) {
|
|
605
|
+
const raw = parseStyle(styleAttr)["margin-left"];
|
|
606
|
+
if (!raw) return 0;
|
|
607
|
+
const m = /^(-?[\d.]+)\s*(pt|cm|in|px)$/i.exec(raw.trim());
|
|
608
|
+
if (!m) return 0;
|
|
609
|
+
const val = Number.parseFloat(m[1]);
|
|
610
|
+
if (!Number.isFinite(val) || val < 0) return 0;
|
|
611
|
+
switch (m[2].toLowerCase()) {
|
|
612
|
+
case "pt":
|
|
613
|
+
return val;
|
|
614
|
+
case "cm":
|
|
615
|
+
return val * 28.3465;
|
|
616
|
+
case "in":
|
|
617
|
+
return val * 72;
|
|
618
|
+
case "px":
|
|
619
|
+
return val * 0.75;
|
|
620
|
+
default:
|
|
621
|
+
return 0;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
function wordListLevelFromMarginLeft(pt) {
|
|
625
|
+
if (pt <= 0) return 0;
|
|
626
|
+
return Math.max(0, Math.round(pt / 36) - 1);
|
|
627
|
+
}
|
|
628
|
+
function findWordListMarker(el) {
|
|
629
|
+
const all = el.querySelectorAll("*");
|
|
630
|
+
for (const e of Array.from(all)) {
|
|
631
|
+
const style = (e.getAttribute("style") ?? "").toLowerCase().replace(/\s+/g, "");
|
|
632
|
+
if (style.includes("mso-list:ignore")) return e;
|
|
633
|
+
}
|
|
634
|
+
return null;
|
|
635
|
+
}
|
|
636
|
+
function detectWordListKind(markerEl) {
|
|
637
|
+
const all = [markerEl, ...Array.from(markerEl.querySelectorAll("*"))];
|
|
638
|
+
for (const e of all) {
|
|
639
|
+
const style = (e.getAttribute("style") ?? "").toLowerCase();
|
|
640
|
+
if (style.includes("symbol") || style.includes("wingdings")) return "bullet";
|
|
641
|
+
}
|
|
642
|
+
const text = (markerEl.textContent ?? "").replace(/ /g, " ").trim();
|
|
643
|
+
if (/^[0-9]+[.)]/.test(text)) return "ordered";
|
|
644
|
+
if (/^[a-zA-Z][.)]/.test(text)) return "ordered";
|
|
645
|
+
return "bullet";
|
|
646
|
+
}
|
|
647
|
+
function inlineDeltaFromNodes(nodes, marks) {
|
|
648
|
+
const ops = [];
|
|
649
|
+
for (const n of nodes) walkInlineNode(n, marks, ops);
|
|
650
|
+
return trimEdgeWhitespace(collapseRepeatedSpaces(mergeAdjacentOps(ops)));
|
|
651
|
+
}
|
|
652
|
+
function collapseRepeatedSpaces(ops) {
|
|
653
|
+
return ops.map(
|
|
654
|
+
(op) => typeof op.insert === "string" ? { ...op, insert: op.insert.replace(/ {2,}/g, " ") } : op
|
|
655
|
+
);
|
|
656
|
+
}
|
|
657
|
+
function walkInlineNode(node, marks, ops) {
|
|
658
|
+
if (node.nodeType === Node.COMMENT_NODE) return;
|
|
659
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
660
|
+
const text = normalizeWhitespace(node.textContent ?? "");
|
|
661
|
+
if (text.length > 0) pushOp(ops, text, marks);
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
if (node.nodeType !== Node.ELEMENT_NODE) return;
|
|
665
|
+
const el = node;
|
|
666
|
+
const tag = el.tagName.toLowerCase();
|
|
667
|
+
if (IGNORED_TAGS.has(tag) || isNamespacedTag(tag)) return;
|
|
668
|
+
if (tag === "img") {
|
|
669
|
+
const op = imageEmbedFromElement(el);
|
|
670
|
+
if (op) ops.push(op);
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
if (tag === "br") {
|
|
674
|
+
ops.push({ insert: " " });
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
const styleAttr = (el.getAttribute("style") ?? "").toLowerCase().replace(/\s+/g, "");
|
|
678
|
+
if (styleAttr.includes("mso-list:ignore")) return;
|
|
679
|
+
let nextMarks = applyTagMarks(tag, marks);
|
|
680
|
+
nextMarks = applyStyleMarks(el.getAttribute("style"), nextMarks);
|
|
681
|
+
if (tag === "a") {
|
|
682
|
+
const href = el.getAttribute("href");
|
|
683
|
+
if (href) nextMarks = { ...nextMarks, link: { href } };
|
|
684
|
+
}
|
|
685
|
+
for (const child of Array.from(el.childNodes)) walkInlineNode(child, nextMarks, ops);
|
|
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
|
+
}
|
|
754
|
+
function applyTagMarks(tag, marks) {
|
|
755
|
+
switch (tag) {
|
|
756
|
+
case "b":
|
|
757
|
+
case "strong":
|
|
758
|
+
return { ...marks, bold: true };
|
|
759
|
+
case "i":
|
|
760
|
+
case "em":
|
|
761
|
+
return { ...marks, italic: true };
|
|
762
|
+
case "u":
|
|
763
|
+
return { ...marks, underline: true };
|
|
764
|
+
case "s":
|
|
765
|
+
case "strike":
|
|
766
|
+
case "del":
|
|
767
|
+
return { ...marks, strike: true };
|
|
768
|
+
default:
|
|
769
|
+
return marks;
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
function parseStyle(styleAttr) {
|
|
773
|
+
const out = {};
|
|
774
|
+
if (!styleAttr) return out;
|
|
775
|
+
for (const decl of styleAttr.split(";")) {
|
|
776
|
+
const idx = decl.indexOf(":");
|
|
777
|
+
if (idx === -1) continue;
|
|
778
|
+
const prop = decl.slice(0, idx).trim().toLowerCase();
|
|
779
|
+
const val = decl.slice(idx + 1).trim();
|
|
780
|
+
if (prop) out[prop] = val;
|
|
781
|
+
}
|
|
782
|
+
return out;
|
|
783
|
+
}
|
|
784
|
+
function applyStyleMarks(styleAttr, marks) {
|
|
785
|
+
const decls = parseStyle(styleAttr);
|
|
786
|
+
if (Object.keys(decls).length === 0) return marks;
|
|
787
|
+
const next = { ...marks };
|
|
788
|
+
if ("font-weight" in decls) {
|
|
789
|
+
const v = decls["font-weight"].toLowerCase();
|
|
790
|
+
if (v === "bold" || /^[5-9]00$/.test(v)) next.bold = true;
|
|
791
|
+
else if (v === "normal" || /^[1-4]00$/.test(v)) delete next.bold;
|
|
792
|
+
}
|
|
793
|
+
if ("font-style" in decls) {
|
|
794
|
+
const v = decls["font-style"].toLowerCase();
|
|
795
|
+
if (v === "italic" || v === "oblique") next.italic = true;
|
|
796
|
+
else if (v === "normal") delete next.italic;
|
|
797
|
+
}
|
|
798
|
+
const deco = decls["text-decoration-line"] ?? decls["text-decoration"];
|
|
799
|
+
if (deco !== void 0) {
|
|
800
|
+
const v = deco.toLowerCase();
|
|
801
|
+
delete next.underline;
|
|
802
|
+
delete next.strike;
|
|
803
|
+
if (v.includes("underline")) next.underline = true;
|
|
804
|
+
if (v.includes("line-through")) next.strike = true;
|
|
805
|
+
}
|
|
806
|
+
if ("color" in decls) {
|
|
807
|
+
const css = normalizeCssColor(decls.color);
|
|
808
|
+
if (css && !isBlack(css)) next.color = css;
|
|
809
|
+
else delete next.color;
|
|
810
|
+
}
|
|
811
|
+
const bg = decls["background-color"] ?? decls.background;
|
|
812
|
+
if (bg !== void 0) {
|
|
813
|
+
const css = normalizeCssColor(bg);
|
|
814
|
+
if (css && css !== "#ffffff") next.highlight = css;
|
|
815
|
+
else delete next.highlight;
|
|
816
|
+
}
|
|
817
|
+
if ("font-size" in decls) {
|
|
818
|
+
const pt = parseFontSizePt(decls["font-size"]);
|
|
819
|
+
if (pt != null) next.fontSize = formatFontSizePt(pt);
|
|
820
|
+
}
|
|
821
|
+
return next;
|
|
822
|
+
}
|
|
823
|
+
function parseFontSizePt(raw) {
|
|
824
|
+
const v = raw.trim().toLowerCase();
|
|
825
|
+
const m = /^(-?[\d.]+)\s*(pt|px|in)$/.exec(v);
|
|
826
|
+
if (!m) return void 0;
|
|
827
|
+
const num = Number.parseFloat(m[1]);
|
|
828
|
+
if (!Number.isFinite(num)) return void 0;
|
|
829
|
+
let pt;
|
|
830
|
+
switch (m[2]) {
|
|
831
|
+
case "pt":
|
|
832
|
+
pt = num;
|
|
833
|
+
break;
|
|
834
|
+
case "px":
|
|
835
|
+
pt = num * 0.75;
|
|
836
|
+
break;
|
|
837
|
+
case "in":
|
|
838
|
+
pt = num * 72;
|
|
839
|
+
break;
|
|
840
|
+
default:
|
|
841
|
+
return void 0;
|
|
842
|
+
}
|
|
843
|
+
const rounded = Math.round(pt * 10) / 10;
|
|
844
|
+
if (rounded <= 0 || rounded > 200) return void 0;
|
|
845
|
+
return rounded;
|
|
846
|
+
}
|
|
847
|
+
function formatFontSizePt(pt) {
|
|
848
|
+
const rounded = Math.round(pt * 10) / 10;
|
|
849
|
+
const str = Number.isInteger(rounded) ? String(rounded) : rounded.toFixed(1);
|
|
850
|
+
return `${str}pt`;
|
|
851
|
+
}
|
|
852
|
+
var NAMED_COLORS = {
|
|
853
|
+
black: "#000000",
|
|
854
|
+
white: "#ffffff",
|
|
855
|
+
red: "#ff0000",
|
|
856
|
+
green: "#008000",
|
|
857
|
+
blue: "#0000ff",
|
|
858
|
+
yellow: "#ffff00",
|
|
859
|
+
cyan: "#00ffff",
|
|
860
|
+
magenta: "#ff00ff",
|
|
861
|
+
gray: "#808080",
|
|
862
|
+
grey: "#808080",
|
|
863
|
+
orange: "#ffa500",
|
|
864
|
+
purple: "#800080"
|
|
865
|
+
};
|
|
866
|
+
function normalizeCssColor(raw) {
|
|
867
|
+
if (!raw) return void 0;
|
|
868
|
+
const v = raw.trim().toLowerCase();
|
|
869
|
+
if (!v || v === "transparent" || v === "none" || v === "inherit" || v === "initial") return void 0;
|
|
870
|
+
if (v.startsWith("#")) {
|
|
871
|
+
let hex = v.slice(1);
|
|
872
|
+
if (hex.length === 3) hex = hex.split("").map((c) => c + c).join("");
|
|
873
|
+
return /^[0-9a-f]{6}$/.test(hex) ? `#${hex}` : void 0;
|
|
874
|
+
}
|
|
875
|
+
const rgbMatch = /^rgba?\(([^)]+)\)$/.exec(v);
|
|
876
|
+
if (rgbMatch) {
|
|
877
|
+
const parts = rgbMatch[1].split(",").map((s) => s.trim());
|
|
878
|
+
if (parts.length < 3) return void 0;
|
|
879
|
+
const alpha = parts[3] !== void 0 ? Number.parseFloat(parts[3]) : 1;
|
|
880
|
+
if (alpha === 0) return void 0;
|
|
881
|
+
const toHex = (n) => {
|
|
882
|
+
const num = Math.max(0, Math.min(255, Number.parseInt(n, 10) || 0));
|
|
883
|
+
return num.toString(16).padStart(2, "0");
|
|
884
|
+
};
|
|
885
|
+
return `#${toHex(parts[0])}${toHex(parts[1])}${toHex(parts[2])}`;
|
|
886
|
+
}
|
|
887
|
+
return NAMED_COLORS[v];
|
|
888
|
+
}
|
|
889
|
+
function isBlack(hex) {
|
|
890
|
+
return hex.toLowerCase() === "#000000";
|
|
891
|
+
}
|
|
892
|
+
function readAlign(el) {
|
|
893
|
+
const style = parseStyle(el.getAttribute("style"));
|
|
894
|
+
const v = style["text-align"];
|
|
895
|
+
if (!v) return void 0;
|
|
896
|
+
switch (v.toLowerCase()) {
|
|
897
|
+
case "left":
|
|
898
|
+
case "start":
|
|
899
|
+
return "left";
|
|
900
|
+
case "center":
|
|
901
|
+
return "center";
|
|
902
|
+
case "right":
|
|
903
|
+
case "end":
|
|
904
|
+
return "right";
|
|
905
|
+
case "justify":
|
|
906
|
+
return "justify";
|
|
907
|
+
default:
|
|
908
|
+
return void 0;
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
function clampLevel(n) {
|
|
912
|
+
if (!Number.isFinite(n)) return 0;
|
|
913
|
+
return Math.max(0, Math.min(import_core.MAX_LIST_LEVEL, Math.trunc(n)));
|
|
914
|
+
}
|
|
915
|
+
function normalizeListLevels(blocks) {
|
|
916
|
+
let i = 0;
|
|
917
|
+
while (i < blocks.length) {
|
|
918
|
+
if (blocks[i].type !== "listItem") {
|
|
919
|
+
i++;
|
|
920
|
+
continue;
|
|
921
|
+
}
|
|
922
|
+
let j = i + 1;
|
|
923
|
+
while (j < blocks.length && blocks[j].type === "listItem") j++;
|
|
924
|
+
if (j - i > 1) {
|
|
925
|
+
let min = Number.POSITIVE_INFINITY;
|
|
926
|
+
for (let k = i; k < j; k++) {
|
|
927
|
+
const lvl = blocks[k].attrs.listLevel ?? 0;
|
|
928
|
+
if (lvl < min) min = lvl;
|
|
929
|
+
}
|
|
930
|
+
if (min > 0) {
|
|
931
|
+
for (let k = i; k < j; k++) {
|
|
932
|
+
const lvl = blocks[k].attrs.listLevel ?? 0;
|
|
933
|
+
blocks[k].attrs.listLevel = clampLevel(lvl - min);
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
i = j;
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
function pushOp(ops, text, marks) {
|
|
941
|
+
const hasMarks = Object.keys(marks).length > 0;
|
|
942
|
+
ops.push(hasMarks ? { insert: text, attributes: { ...marks } } : { insert: text });
|
|
943
|
+
}
|
|
944
|
+
function normalizeWhitespace(raw) {
|
|
945
|
+
return raw.replace(/[ \t\r\n]+/g, " ");
|
|
946
|
+
}
|
|
947
|
+
function trimEdgeWhitespace(ops) {
|
|
948
|
+
let out = ops;
|
|
949
|
+
if (out.length > 0 && typeof out[0].insert === "string") {
|
|
950
|
+
const trimmed = out[0].insert.replace(/^ +/, "");
|
|
951
|
+
if (trimmed.length === 0) out = out.slice(1);
|
|
952
|
+
else if (trimmed !== out[0].insert) out = [{ ...out[0], insert: trimmed }, ...out.slice(1)];
|
|
953
|
+
}
|
|
954
|
+
if (out.length > 0 && typeof out[out.length - 1].insert === "string") {
|
|
955
|
+
const last = out[out.length - 1];
|
|
956
|
+
const trimmed = last.insert.replace(/ +$/, "");
|
|
957
|
+
if (trimmed.length === 0) out = out.slice(0, -1);
|
|
958
|
+
else if (trimmed !== last.insert) out = [...out.slice(0, -1), { ...last, insert: trimmed }];
|
|
959
|
+
}
|
|
960
|
+
return out;
|
|
961
|
+
}
|
|
962
|
+
function mergeAdjacentOps(ops) {
|
|
963
|
+
const out = [];
|
|
964
|
+
for (const op of ops) {
|
|
965
|
+
const prev = out[out.length - 1];
|
|
966
|
+
if (prev && typeof prev.insert === "string" && typeof op.insert === "string" && sameMarks(prev.attributes, op.attributes)) {
|
|
967
|
+
prev.insert = prev.insert + op.insert;
|
|
968
|
+
continue;
|
|
969
|
+
}
|
|
970
|
+
out.push({ ...op });
|
|
971
|
+
}
|
|
972
|
+
return out;
|
|
973
|
+
}
|
|
974
|
+
function sameMarks(a, b) {
|
|
975
|
+
const ak = a ? Object.keys(a).sort() : [];
|
|
976
|
+
const bk = b ? Object.keys(b).sort() : [];
|
|
977
|
+
if (ak.length !== bk.length) return false;
|
|
978
|
+
for (let i = 0; i < ak.length; i++) {
|
|
979
|
+
if (ak[i] !== bk[i]) return false;
|
|
980
|
+
const av = a[ak[i]];
|
|
981
|
+
const bv = b[bk[i]];
|
|
982
|
+
if (typeof av === "object" && av !== null && typeof bv === "object" && bv !== null) {
|
|
983
|
+
if (JSON.stringify(av) !== JSON.stringify(bv)) return false;
|
|
984
|
+
} else if (av !== bv) {
|
|
985
|
+
return false;
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
return true;
|
|
989
|
+
}
|
|
990
|
+
function deltaToText(delta) {
|
|
991
|
+
let s = "";
|
|
992
|
+
for (const op of delta) if (typeof op.insert === "string") s += op.insert;
|
|
993
|
+
return s;
|
|
994
|
+
}
|
|
995
|
+
function makeBlock(type, delta, attrs) {
|
|
996
|
+
return { type, text: deltaToText(delta), delta, attrs };
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
// src/pastePlan.ts
|
|
1000
|
+
function planPaste(cd) {
|
|
1001
|
+
const raw = cd.getData(import_core2.SOFER_MIME);
|
|
1002
|
+
if (raw) {
|
|
1003
|
+
try {
|
|
1004
|
+
const slice = JSON.parse(raw);
|
|
1005
|
+
if (slice && Array.isArray(slice.blocks)) return { kind: "sofer", slice };
|
|
1006
|
+
} catch {
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
const html = cd.getData("text/html");
|
|
1010
|
+
if (html) {
|
|
1011
|
+
const slice = htmlToSlice(html);
|
|
1012
|
+
if (slice) return { kind: "html", slice };
|
|
1013
|
+
}
|
|
1014
|
+
const files = Array.from(cd.files ?? []).filter((f) => f.type.startsWith("image/"));
|
|
1015
|
+
if (files.length > 0) return { kind: "images", files };
|
|
1016
|
+
const text = cd.getData("text/plain");
|
|
1017
|
+
if (text.length > 0) return { kind: "text", text };
|
|
1018
|
+
return { kind: "none" };
|
|
1019
|
+
}
|
|
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
|
+
|
|
332
1073
|
// src/BehindImageSelectAffordance.tsx
|
|
333
1074
|
var import_react = require("react");
|
|
334
1075
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -645,7 +1386,7 @@ function LinkDialog() {
|
|
|
645
1386
|
|
|
646
1387
|
// src/PageConfigDialog.tsx
|
|
647
1388
|
var import_react3 = require("react");
|
|
648
|
-
var
|
|
1389
|
+
var import_core4 = require("@sofereditor/core");
|
|
649
1390
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
650
1391
|
function PageConfigDialog() {
|
|
651
1392
|
const { pageConfigRequest, resolvePageConfigRequest, setPageSettings } = useEditorContext();
|
|
@@ -679,14 +1420,14 @@ function PageConfigDialog() {
|
|
|
679
1420
|
}, [pageConfigRequest]);
|
|
680
1421
|
(0, import_react3.useEffect)(() => {
|
|
681
1422
|
if (sizePreset === "custom") return;
|
|
682
|
-
const p =
|
|
683
|
-
setWidthMm(roundMm((0,
|
|
684
|
-
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)));
|
|
685
1426
|
}, [sizePreset]);
|
|
686
1427
|
(0, import_react3.useEffect)(() => {
|
|
687
1428
|
if (marginPreset === "custom") return;
|
|
688
|
-
const px =
|
|
689
|
-
const mm = roundMm((0,
|
|
1429
|
+
const px = import_core4.MARGIN_PRESETS[marginPreset];
|
|
1430
|
+
const mm = roundMm((0, import_core4.pxToMm)(px));
|
|
690
1431
|
setMarginTopMm(mm);
|
|
691
1432
|
setMarginBottomMm(mm);
|
|
692
1433
|
setMarginLeftMm(mm);
|
|
@@ -695,8 +1436,8 @@ function PageConfigDialog() {
|
|
|
695
1436
|
const customWidth = sizePreset === "custom";
|
|
696
1437
|
const previewPx = (0, import_react3.useMemo)(
|
|
697
1438
|
() => ({
|
|
698
|
-
width: Math.round((0,
|
|
699
|
-
height: Math.round((0,
|
|
1439
|
+
width: Math.round((0, import_core4.mmToPx)(widthMm)),
|
|
1440
|
+
height: Math.round((0, import_core4.mmToPx)(heightMm))
|
|
700
1441
|
}),
|
|
701
1442
|
[widthMm, heightMm]
|
|
702
1443
|
);
|
|
@@ -704,12 +1445,12 @@ function PageConfigDialog() {
|
|
|
704
1445
|
const onApply = (e) => {
|
|
705
1446
|
e.preventDefault();
|
|
706
1447
|
const next = {
|
|
707
|
-
width: (0,
|
|
708
|
-
height: (0,
|
|
709
|
-
marginTop: (0,
|
|
710
|
-
marginBottom: (0,
|
|
711
|
-
marginLeft: (0,
|
|
712
|
-
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)
|
|
713
1454
|
};
|
|
714
1455
|
setPageSettings(next);
|
|
715
1456
|
resolvePageConfigRequest(true);
|
|
@@ -968,14 +1709,14 @@ function roundMm(mm) {
|
|
|
968
1709
|
return Math.round(mm * 10) / 10;
|
|
969
1710
|
}
|
|
970
1711
|
function hydrateFromSettings(s, setters) {
|
|
971
|
-
const preset = (0,
|
|
1712
|
+
const preset = (0, import_core4.detectPreset)(s.width, s.height);
|
|
972
1713
|
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,
|
|
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));
|
|
979
1720
|
setters.setMarginTopMm(top);
|
|
980
1721
|
setters.setMarginBottomMm(bottom);
|
|
981
1722
|
setters.setMarginLeftMm(left);
|
|
@@ -986,7 +1727,7 @@ function detectMarginPreset(s) {
|
|
|
986
1727
|
const TOL = 1;
|
|
987
1728
|
const allEqual = Math.abs(s.marginTop - s.marginBottom) <= TOL && Math.abs(s.marginTop - s.marginLeft) <= TOL && Math.abs(s.marginTop - s.marginRight) <= TOL;
|
|
988
1729
|
if (!allEqual) return "custom";
|
|
989
|
-
for (const [name, px] of Object.entries(
|
|
1730
|
+
for (const [name, px] of Object.entries(import_core4.MARGIN_PRESETS)) {
|
|
990
1731
|
if (Math.abs(s.marginTop - px) <= TOL) return name;
|
|
991
1732
|
}
|
|
992
1733
|
return "custom";
|
|
@@ -1546,7 +2287,7 @@ function Handle({
|
|
|
1546
2287
|
|
|
1547
2288
|
// src/RemoteCursorsOverlay.tsx
|
|
1548
2289
|
var import_react7 = require("react");
|
|
1549
|
-
var
|
|
2290
|
+
var import_core5 = require("@sofereditor/core");
|
|
1550
2291
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1551
2292
|
var DEFAULT_COLOR = "#3b82f6";
|
|
1552
2293
|
function RemoteCursorsOverlay({
|
|
@@ -1569,7 +2310,7 @@ function RemoteCursorsOverlay({
|
|
|
1569
2310
|
if (clientId === awareness.clientID) return;
|
|
1570
2311
|
const s = state;
|
|
1571
2312
|
if (!s.cursor) return;
|
|
1572
|
-
const sel = (0,
|
|
2313
|
+
const sel = (0, import_core5.decodeSelection)(doc, s.cursor);
|
|
1573
2314
|
if (!sel) return;
|
|
1574
2315
|
const color = s.user?.color || DEFAULT_COLOR;
|
|
1575
2316
|
const name = s.user?.name || "An\xF4nimo";
|
|
@@ -1716,11 +2457,11 @@ function RemoteCursorsOverlay({
|
|
|
1716
2457
|
|
|
1717
2458
|
// src/NodeView.tsx
|
|
1718
2459
|
var import_react10 = require("react");
|
|
1719
|
-
var
|
|
2460
|
+
var import_core7 = require("@sofereditor/core");
|
|
1720
2461
|
|
|
1721
2462
|
// src/renderInline.tsx
|
|
1722
2463
|
var import_react8 = require("react");
|
|
1723
|
-
var
|
|
2464
|
+
var import_core6 = require("@sofereditor/core");
|
|
1724
2465
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1725
2466
|
function renderInline(delta, keyPrefix) {
|
|
1726
2467
|
if (delta.length === 0 || delta.length === 1 && typeof delta[0].insert === "string" && delta[0].insert === "") {
|
|
@@ -1736,7 +2477,7 @@ function renderInline(delta, keyPrefix) {
|
|
|
1736
2477
|
const key = `${keyPrefix}-${offset}`;
|
|
1737
2478
|
body.push(/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react8.Fragment, { children: wrap(text, op.attributes) }, key));
|
|
1738
2479
|
offset += text.length;
|
|
1739
|
-
} else if ((0,
|
|
2480
|
+
} else if ((0, import_core6.isImageEmbed)(op.insert)) {
|
|
1740
2481
|
const key = `${keyPrefix}-${offset}`;
|
|
1741
2482
|
const layout = op.insert.layout ?? "inline";
|
|
1742
2483
|
const commentMarkId = op.attributes?.comment?.markId;
|
|
@@ -1900,10 +2641,10 @@ function ImageEmbedViewImpl({
|
|
|
1900
2641
|
);
|
|
1901
2642
|
}
|
|
1902
2643
|
function decorateBlanks(text) {
|
|
1903
|
-
const segs = (0,
|
|
2644
|
+
const segs = (0, import_core6.splitUnderscoreRuns)(text);
|
|
1904
2645
|
if (segs.length === 1 && !segs[0].blank) return text;
|
|
1905
2646
|
return segs.map(
|
|
1906
|
-
(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)
|
|
1907
2648
|
);
|
|
1908
2649
|
}
|
|
1909
2650
|
function wrap(text, attrs) {
|
|
@@ -2101,7 +2842,7 @@ function NodeView({ block, index, children, fragment, tableFragment }) {
|
|
|
2101
2842
|
const common = commonBlockProps(block.attrs, index, block.type, fragment);
|
|
2102
2843
|
switch (block.type) {
|
|
2103
2844
|
case "heading": {
|
|
2104
|
-
const level =
|
|
2845
|
+
const level = clampLevel2(block.attrs.level);
|
|
2105
2846
|
const Tag = `h${level}`;
|
|
2106
2847
|
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
2107
2848
|
Tag,
|
|
@@ -2162,7 +2903,7 @@ function NodeView({ block, index, children, fragment, tableFragment }) {
|
|
|
2162
2903
|
function commonBlockProps(attrs, index, type, fragment) {
|
|
2163
2904
|
const style = {};
|
|
2164
2905
|
if (attrs.align) style.textAlign = attrs.align;
|
|
2165
|
-
Object.assign(style, (0,
|
|
2906
|
+
Object.assign(style, (0, import_core7.answerLineStyle)(attrs) ?? {});
|
|
2166
2907
|
const base = {
|
|
2167
2908
|
"data-block-index": index,
|
|
2168
2909
|
"data-block-type": type,
|
|
@@ -2188,7 +2929,7 @@ function cellStyle(attrs, border) {
|
|
|
2188
2929
|
if (attrs?.bgColor) style.backgroundColor = attrs.bgColor;
|
|
2189
2930
|
return Object.keys(style).length > 0 ? style : void 0;
|
|
2190
2931
|
}
|
|
2191
|
-
function
|
|
2932
|
+
function clampLevel2(l) {
|
|
2192
2933
|
if (l === 2 || l === 3 || l === 4 || l === 5 || l === 6) return l;
|
|
2193
2934
|
return 1;
|
|
2194
2935
|
}
|
|
@@ -2209,7 +2950,7 @@ function TableView({ block, index, tableFragment }) {
|
|
|
2209
2950
|
const rect = (0, import_react10.useMemo)(() => {
|
|
2210
2951
|
if (editor.selection.anchor.blockIndex !== index) return null;
|
|
2211
2952
|
if (editor.selection.focus.blockIndex !== index) return null;
|
|
2212
|
-
return (0,
|
|
2953
|
+
return (0, import_core7.tableRectSelection)(editor.doc, editor.selection);
|
|
2213
2954
|
}, [editor.doc, editor.selection, index]);
|
|
2214
2955
|
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "ed-table-wrap", children: [
|
|
2215
2956
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
@@ -2245,7 +2986,7 @@ function TableView({ block, index, tableFragment }) {
|
|
|
2245
2986
|
cell?.attrs,
|
|
2246
2987
|
// rowStart/rowEnd são os limites do FRAGMENTO: numa tabela
|
|
2247
2988
|
// quebrada entre páginas, cada página fecha a própria caixa.
|
|
2248
|
-
(0,
|
|
2989
|
+
(0, import_core7.cellBorderStyle)(
|
|
2249
2990
|
block.attrs.borderPreset,
|
|
2250
2991
|
{ row: r, col: c, rowspan, colspan, cols, rowStart, rowEnd },
|
|
2251
2992
|
"screen",
|
|
@@ -2821,14 +3562,13 @@ function shallowEqual(a, b) {
|
|
|
2821
3562
|
}
|
|
2822
3563
|
|
|
2823
3564
|
// src/useEditor.ts
|
|
2824
|
-
var
|
|
2825
|
-
var MAX_INSERT_WIDTH = 600;
|
|
3565
|
+
var import_core8 = require("@sofereditor/core");
|
|
2826
3566
|
function useEditor(opts = {}) {
|
|
2827
|
-
const doc = (0, import_react13.useMemo)(() => opts.document ?? new
|
|
2828
|
-
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]);
|
|
2829
3569
|
const [snapshot, setSnapshot] = (0, import_react13.useState)(() => doc.toJSON());
|
|
2830
3570
|
const [selection, setSelectionState] = (0, import_react13.useState)(
|
|
2831
|
-
() => (0,
|
|
3571
|
+
() => (0, import_core8.collapsedSelection)({ blockIndex: 0, offset: 0 })
|
|
2832
3572
|
);
|
|
2833
3573
|
const selectionRef = (0, import_react13.useRef)(selection);
|
|
2834
3574
|
selectionRef.current = selection;
|
|
@@ -2893,7 +3633,7 @@ function useEditor(opts = {}) {
|
|
|
2893
3633
|
const isMarkActive = (0, import_react13.useCallback)(
|
|
2894
3634
|
(name, value) => {
|
|
2895
3635
|
const sel = selectionRef.current;
|
|
2896
|
-
const { start, end } = (0,
|
|
3636
|
+
const { start, end } = (0, import_core8.orderedRange)(sel);
|
|
2897
3637
|
if (start.blockIndex === end.blockIndex && start.offset === end.offset) {
|
|
2898
3638
|
const pending = pendingMarksRef.current[name];
|
|
2899
3639
|
if (pending !== void 0) {
|
|
@@ -2902,7 +3642,7 @@ function useEditor(opts = {}) {
|
|
|
2902
3642
|
}
|
|
2903
3643
|
const yText2 = doc.getBlockText(start.blockIndex);
|
|
2904
3644
|
if (!yText2 || start.offset === 0) return false;
|
|
2905
|
-
return (0,
|
|
3645
|
+
return (0, import_core8.isMarkUniformInRange)(yText2, start.offset - 1, start.offset, name, value);
|
|
2906
3646
|
}
|
|
2907
3647
|
if (start.blockIndex !== end.blockIndex) {
|
|
2908
3648
|
for (let i = start.blockIndex; i <= end.blockIndex; i++) {
|
|
@@ -2911,19 +3651,19 @@ function useEditor(opts = {}) {
|
|
|
2911
3651
|
const s = i === start.blockIndex ? start.offset : 0;
|
|
2912
3652
|
const e = i === end.blockIndex ? end.offset : yText2.length;
|
|
2913
3653
|
if (s >= e) continue;
|
|
2914
|
-
if (!(0,
|
|
3654
|
+
if (!(0, import_core8.isMarkUniformInRange)(yText2, s, e, name, value)) return false;
|
|
2915
3655
|
}
|
|
2916
3656
|
return true;
|
|
2917
3657
|
}
|
|
2918
3658
|
const yText = doc.getBlockText(start.blockIndex);
|
|
2919
3659
|
if (!yText) return false;
|
|
2920
|
-
return (0,
|
|
3660
|
+
return (0, import_core8.isMarkUniformInRange)(yText, start.offset, end.offset, name, value);
|
|
2921
3661
|
},
|
|
2922
3662
|
[doc]
|
|
2923
3663
|
);
|
|
2924
3664
|
const getActiveMarks = (0, import_react13.useCallback)(() => {
|
|
2925
3665
|
const sel = selectionRef.current;
|
|
2926
|
-
const { start, end } = (0,
|
|
3666
|
+
const { start, end } = (0, import_core8.orderedRange)(sel);
|
|
2927
3667
|
if (start.blockIndex !== end.blockIndex) {
|
|
2928
3668
|
return {};
|
|
2929
3669
|
}
|
|
@@ -2931,14 +3671,14 @@ function useEditor(opts = {}) {
|
|
|
2931
3671
|
if (!yText) return {};
|
|
2932
3672
|
if (start.offset === end.offset) {
|
|
2933
3673
|
if (start.offset === 0) return {};
|
|
2934
|
-
return (0,
|
|
3674
|
+
return (0, import_core8.getMarksInRange)(yText, start.offset - 1, start.offset);
|
|
2935
3675
|
}
|
|
2936
|
-
return (0,
|
|
3676
|
+
return (0, import_core8.getMarksInRange)(yText, start.offset, end.offset);
|
|
2937
3677
|
}, [doc]);
|
|
2938
3678
|
const toggleMark = (0, import_react13.useCallback)(
|
|
2939
3679
|
(name, value) => {
|
|
2940
3680
|
const sel = selectionRef.current;
|
|
2941
|
-
const { start, end } = (0,
|
|
3681
|
+
const { start, end } = (0, import_core8.orderedRange)(sel);
|
|
2942
3682
|
const isCollapsed = start.blockIndex === end.blockIndex && start.offset === end.offset;
|
|
2943
3683
|
if (isCollapsed) {
|
|
2944
3684
|
const next = { ...pendingMarksRef.current };
|
|
@@ -2951,39 +3691,39 @@ function useEditor(opts = {}) {
|
|
|
2951
3691
|
setPendingMarks(next);
|
|
2952
3692
|
return;
|
|
2953
3693
|
}
|
|
2954
|
-
(0,
|
|
3694
|
+
(0, import_core8.toggleMark)(ctxRef.current, name, value);
|
|
2955
3695
|
},
|
|
2956
3696
|
[isMarkActive, setPendingMarks]
|
|
2957
3697
|
);
|
|
2958
3698
|
const setMark = (0, import_react13.useCallback)(
|
|
2959
3699
|
(name, value) => {
|
|
2960
3700
|
const sel = selectionRef.current;
|
|
2961
|
-
const { start, end } = (0,
|
|
3701
|
+
const { start, end } = (0, import_core8.orderedRange)(sel);
|
|
2962
3702
|
const isCollapsed = start.blockIndex === end.blockIndex && start.offset === end.offset;
|
|
2963
3703
|
if (isCollapsed) {
|
|
2964
3704
|
setPendingMarks({ ...pendingMarksRef.current, [name]: value });
|
|
2965
3705
|
return;
|
|
2966
3706
|
}
|
|
2967
|
-
(0,
|
|
3707
|
+
(0, import_core8.setMark)(ctxRef.current, name, value);
|
|
2968
3708
|
},
|
|
2969
3709
|
[setPendingMarks]
|
|
2970
3710
|
);
|
|
2971
3711
|
const removeMark = (0, import_react13.useCallback)(
|
|
2972
3712
|
(name) => {
|
|
2973
3713
|
const sel = selectionRef.current;
|
|
2974
|
-
const { start, end } = (0,
|
|
3714
|
+
const { start, end } = (0, import_core8.orderedRange)(sel);
|
|
2975
3715
|
const isCollapsed = start.blockIndex === end.blockIndex && start.offset === end.offset;
|
|
2976
3716
|
if (isCollapsed) {
|
|
2977
3717
|
setPendingMarks({ ...pendingMarksRef.current, [name]: null });
|
|
2978
3718
|
return;
|
|
2979
3719
|
}
|
|
2980
|
-
(0,
|
|
3720
|
+
(0, import_core8.removeMark)(ctxRef.current, name);
|
|
2981
3721
|
},
|
|
2982
3722
|
[setPendingMarks]
|
|
2983
3723
|
);
|
|
2984
3724
|
const getBlockType = (0, import_react13.useCallback)(() => {
|
|
2985
3725
|
const sel = selectionRef.current;
|
|
2986
|
-
const { start, end } = (0,
|
|
3726
|
+
const { start, end } = (0, import_core8.orderedRange)(sel);
|
|
2987
3727
|
const first = doc.getBlockType(start.blockIndex);
|
|
2988
3728
|
if (first === void 0) return "paragraph";
|
|
2989
3729
|
for (let i = start.blockIndex + 1; i <= end.blockIndex; i++) {
|
|
@@ -2994,7 +3734,7 @@ function useEditor(opts = {}) {
|
|
|
2994
3734
|
const getBlockAttr = (0, import_react13.useCallback)(
|
|
2995
3735
|
(key) => {
|
|
2996
3736
|
const sel = selectionRef.current;
|
|
2997
|
-
const { start, end } = (0,
|
|
3737
|
+
const { start, end } = (0, import_core8.orderedRange)(sel);
|
|
2998
3738
|
const first = doc.getBlockAttrs(start.blockIndex)[key];
|
|
2999
3739
|
for (let i = start.blockIndex + 1; i <= end.blockIndex; i++) {
|
|
3000
3740
|
const next = doc.getBlockAttrs(i)[key];
|
|
@@ -3005,19 +3745,19 @@ function useEditor(opts = {}) {
|
|
|
3005
3745
|
[doc]
|
|
3006
3746
|
);
|
|
3007
3747
|
const setBlockType = (0, import_react13.useCallback)((type, attrs) => {
|
|
3008
|
-
(0,
|
|
3748
|
+
(0, import_core8.setBlockType)(ctxRef.current, type, attrs);
|
|
3009
3749
|
}, []);
|
|
3010
3750
|
const setBlockAttr = (0, import_react13.useCallback)(
|
|
3011
3751
|
(key, value) => {
|
|
3012
|
-
(0,
|
|
3752
|
+
(0, import_core8.setBlockAttr)(ctxRef.current, key, value);
|
|
3013
3753
|
},
|
|
3014
3754
|
[]
|
|
3015
3755
|
);
|
|
3016
3756
|
const setAlign = (0, import_react13.useCallback)((value) => {
|
|
3017
3757
|
const sel = selectionRef.current;
|
|
3018
3758
|
const inCell = sel.focus.cellIndex != null;
|
|
3019
|
-
if (inCell) (0,
|
|
3020
|
-
else (0,
|
|
3759
|
+
if (inCell) (0, import_core8.setCellAttr)(ctxRef.current, "align", value);
|
|
3760
|
+
else (0, import_core8.setBlockAttr)(ctxRef.current, "align", value);
|
|
3021
3761
|
}, []);
|
|
3022
3762
|
const getAlign = (0, import_react13.useCallback)(() => {
|
|
3023
3763
|
const sel = selectionRef.current;
|
|
@@ -3027,7 +3767,7 @@ function useEditor(opts = {}) {
|
|
|
3027
3767
|
return getBlockAttr("align");
|
|
3028
3768
|
}, [doc, getBlockAttr]);
|
|
3029
3769
|
const setCellBackground = (0, import_react13.useCallback)((color) => {
|
|
3030
|
-
(0,
|
|
3770
|
+
(0, import_core8.setCellAttr)(ctxRef.current, "bgColor", color);
|
|
3031
3771
|
}, []);
|
|
3032
3772
|
const getCellBackground = (0, import_react13.useCallback)(() => {
|
|
3033
3773
|
const sel = selectionRef.current;
|
|
@@ -3037,7 +3777,7 @@ function useEditor(opts = {}) {
|
|
|
3037
3777
|
const setTableBorderPreset = (0, import_react13.useCallback)((preset) => {
|
|
3038
3778
|
const sel = selectionRef.current;
|
|
3039
3779
|
if (!doc.isTable(sel.focus.blockIndex)) return;
|
|
3040
|
-
(0,
|
|
3780
|
+
(0, import_core8.setBlockAttrAtIndex)(ctxRef.current, sel.focus.blockIndex, "borderPreset", preset);
|
|
3041
3781
|
}, [doc]);
|
|
3042
3782
|
const getTableBorderPreset = (0, import_react13.useCallback)(() => {
|
|
3043
3783
|
const sel = selectionRef.current;
|
|
@@ -3047,7 +3787,7 @@ function useEditor(opts = {}) {
|
|
|
3047
3787
|
const setTableBorderColor = (0, import_react13.useCallback)((color) => {
|
|
3048
3788
|
const sel = selectionRef.current;
|
|
3049
3789
|
if (!doc.isTable(sel.focus.blockIndex)) return;
|
|
3050
|
-
(0,
|
|
3790
|
+
(0, import_core8.setBlockAttrAtIndex)(ctxRef.current, sel.focus.blockIndex, "borderColor", color);
|
|
3051
3791
|
}, [doc]);
|
|
3052
3792
|
const getTableBorderColor = (0, import_react13.useCallback)(() => {
|
|
3053
3793
|
const sel = selectionRef.current;
|
|
@@ -3057,7 +3797,7 @@ function useEditor(opts = {}) {
|
|
|
3057
3797
|
const isListActive = (0, import_react13.useCallback)(
|
|
3058
3798
|
(kind) => {
|
|
3059
3799
|
const sel = selectionRef.current;
|
|
3060
|
-
const { start, end } = (0,
|
|
3800
|
+
const { start, end } = (0, import_core8.orderedRange)(sel);
|
|
3061
3801
|
for (let i = start.blockIndex; i <= end.blockIndex; i++) {
|
|
3062
3802
|
if (doc.getBlockType(i) !== "listItem") return false;
|
|
3063
3803
|
if (doc.getBlockAttrs(i).listKind !== kind) return false;
|
|
@@ -3067,112 +3807,112 @@ function useEditor(opts = {}) {
|
|
|
3067
3807
|
[doc]
|
|
3068
3808
|
);
|
|
3069
3809
|
const toggleList = (0, import_react13.useCallback)((kind) => {
|
|
3070
|
-
(0,
|
|
3810
|
+
(0, import_core8.toggleList)(ctxRef.current, kind);
|
|
3071
3811
|
}, []);
|
|
3072
3812
|
const indentList = (0, import_react13.useCallback)(() => {
|
|
3073
|
-
(0,
|
|
3813
|
+
(0, import_core8.indentList)(ctxRef.current);
|
|
3074
3814
|
}, []);
|
|
3075
3815
|
const dedentList = (0, import_react13.useCallback)(() => {
|
|
3076
|
-
(0,
|
|
3816
|
+
(0, import_core8.dedentList)(ctxRef.current);
|
|
3077
3817
|
}, []);
|
|
3078
3818
|
const splitListItem = (0, import_react13.useCallback)(() => {
|
|
3079
|
-
return (0,
|
|
3819
|
+
return (0, import_core8.splitListItem)(ctxRef.current);
|
|
3080
3820
|
}, []);
|
|
3081
3821
|
const isInTable = (0, import_react13.useCallback)(() => {
|
|
3082
3822
|
return selectionRef.current.focus.cellIndex != null;
|
|
3083
3823
|
}, []);
|
|
3084
3824
|
const getTableLocation = (0, import_react13.useCallback)(() => {
|
|
3085
|
-
return (0,
|
|
3825
|
+
return (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3086
3826
|
}, [doc]);
|
|
3087
3827
|
const insertTable = (0, import_react13.useCallback)((rows, cols) => {
|
|
3088
|
-
(0,
|
|
3828
|
+
(0, import_core8.insertTable)(ctxRef.current, rows, cols);
|
|
3089
3829
|
}, []);
|
|
3090
3830
|
const insertAnswerLines = (0, import_react13.useCallback)((count, spacing) => {
|
|
3091
|
-
(0,
|
|
3831
|
+
(0, import_core8.insertAnswerLines)(ctxRef.current, count, spacing);
|
|
3092
3832
|
}, []);
|
|
3093
3833
|
const deleteTable = (0, import_react13.useCallback)((blockIndex) => {
|
|
3094
3834
|
const idx = blockIndex ?? selectionRef.current.focus.blockIndex;
|
|
3095
|
-
(0,
|
|
3835
|
+
(0, import_core8.deleteTable)(ctxRef.current, idx);
|
|
3096
3836
|
}, []);
|
|
3097
3837
|
const insertRowAbove = (0, import_react13.useCallback)(() => {
|
|
3098
|
-
const loc = (0,
|
|
3838
|
+
const loc = (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3099
3839
|
if (!loc) return;
|
|
3100
|
-
(0,
|
|
3840
|
+
(0, import_core8.insertTableRow)(ctxRef.current, loc.blockIndex, loc.row, "before");
|
|
3101
3841
|
}, [doc]);
|
|
3102
3842
|
const insertRowBelow = (0, import_react13.useCallback)(() => {
|
|
3103
|
-
const loc = (0,
|
|
3843
|
+
const loc = (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3104
3844
|
if (!loc) return;
|
|
3105
|
-
(0,
|
|
3845
|
+
(0, import_core8.insertTableRow)(ctxRef.current, loc.blockIndex, loc.row, "after");
|
|
3106
3846
|
}, [doc]);
|
|
3107
3847
|
const deleteCurrentRow = (0, import_react13.useCallback)(() => {
|
|
3108
|
-
const loc = (0,
|
|
3848
|
+
const loc = (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3109
3849
|
if (!loc) return;
|
|
3110
|
-
(0,
|
|
3850
|
+
(0, import_core8.deleteTableRow)(ctxRef.current, loc.blockIndex, loc.row);
|
|
3111
3851
|
}, [doc]);
|
|
3112
3852
|
const insertColumnLeft = (0, import_react13.useCallback)(() => {
|
|
3113
|
-
const loc = (0,
|
|
3853
|
+
const loc = (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3114
3854
|
if (!loc) return;
|
|
3115
|
-
(0,
|
|
3855
|
+
(0, import_core8.insertTableColumn)(ctxRef.current, loc.blockIndex, loc.col, "before");
|
|
3116
3856
|
}, [doc]);
|
|
3117
3857
|
const insertColumnRight = (0, import_react13.useCallback)(() => {
|
|
3118
|
-
const loc = (0,
|
|
3858
|
+
const loc = (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3119
3859
|
if (!loc) return;
|
|
3120
|
-
(0,
|
|
3860
|
+
(0, import_core8.insertTableColumn)(ctxRef.current, loc.blockIndex, loc.col, "after");
|
|
3121
3861
|
}, [doc]);
|
|
3122
3862
|
const deleteCurrentColumn = (0, import_react13.useCallback)(() => {
|
|
3123
|
-
const loc = (0,
|
|
3863
|
+
const loc = (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3124
3864
|
if (!loc) return;
|
|
3125
|
-
(0,
|
|
3865
|
+
(0, import_core8.deleteTableColumn)(ctxRef.current, loc.blockIndex, loc.col);
|
|
3126
3866
|
}, [doc]);
|
|
3127
3867
|
const moveToNextCell = (0, import_react13.useCallback)(() => {
|
|
3128
|
-
(0,
|
|
3868
|
+
(0, import_core8.moveToNextCell)(ctxRef.current);
|
|
3129
3869
|
}, []);
|
|
3130
3870
|
const moveToPrevCell = (0, import_react13.useCallback)(() => {
|
|
3131
|
-
(0,
|
|
3871
|
+
(0, import_core8.moveToPrevCell)(ctxRef.current);
|
|
3132
3872
|
}, []);
|
|
3133
3873
|
const mergeRight = (0, import_react13.useCallback)(() => {
|
|
3134
|
-
const loc = (0,
|
|
3874
|
+
const loc = (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3135
3875
|
if (!loc) return false;
|
|
3136
|
-
return (0,
|
|
3876
|
+
return (0, import_core8.mergeRight)(ctxRef.current, loc.blockIndex, loc.row, loc.col);
|
|
3137
3877
|
}, [doc]);
|
|
3138
3878
|
const mergeDown = (0, import_react13.useCallback)(() => {
|
|
3139
|
-
const loc = (0,
|
|
3879
|
+
const loc = (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3140
3880
|
if (!loc) return false;
|
|
3141
|
-
return (0,
|
|
3881
|
+
return (0, import_core8.mergeDown)(ctxRef.current, loc.blockIndex, loc.row, loc.col);
|
|
3142
3882
|
}, [doc]);
|
|
3143
3883
|
const splitCell = (0, import_react13.useCallback)(() => {
|
|
3144
|
-
const loc = (0,
|
|
3884
|
+
const loc = (0, import_core8.tableLocationOf)(doc, selectionRef.current.focus);
|
|
3145
3885
|
if (!loc) return false;
|
|
3146
|
-
return (0,
|
|
3886
|
+
return (0, import_core8.splitCell)(ctxRef.current, loc.blockIndex, loc.row, loc.col);
|
|
3147
3887
|
}, [doc]);
|
|
3148
3888
|
const setColumnWidth = (0, import_react13.useCallback)(
|
|
3149
3889
|
(blockIndex, col, widthPx) => {
|
|
3150
|
-
(0,
|
|
3890
|
+
(0, import_core8.setColumnWidth)(ctxRef.current, blockIndex, col, widthPx);
|
|
3151
3891
|
},
|
|
3152
3892
|
[]
|
|
3153
3893
|
);
|
|
3154
3894
|
const getTableRect = (0, import_react13.useCallback)(
|
|
3155
|
-
() => (0,
|
|
3895
|
+
() => (0, import_core8.tableRectSelection)(doc, selectionRef.current),
|
|
3156
3896
|
[doc]
|
|
3157
3897
|
);
|
|
3158
3898
|
const hasTableRectSelection = (0, import_react13.useCallback)(() => {
|
|
3159
|
-
return (0,
|
|
3899
|
+
return (0, import_core8.tableRectSelection)(doc, selectionRef.current) !== null;
|
|
3160
3900
|
}, [doc]);
|
|
3161
3901
|
const mergeSelection = (0, import_react13.useCallback)(() => {
|
|
3162
|
-
return (0,
|
|
3902
|
+
return (0, import_core8.mergeSelection)(ctxRef.current);
|
|
3163
3903
|
}, []);
|
|
3164
3904
|
const insertImage = (0, import_react13.useCallback)((embed) => {
|
|
3165
|
-
(0,
|
|
3905
|
+
(0, import_core8.insertImage)(ctxRef.current, embed);
|
|
3166
3906
|
}, []);
|
|
3167
3907
|
const setImageAttrs = (0, import_react13.useCallback)(
|
|
3168
3908
|
(blockIndex, offset, partial, cellIndex, newOffset) => {
|
|
3169
|
-
(0,
|
|
3909
|
+
(0, import_core8.setImageAttrs)(ctxRef.current, blockIndex, offset, partial, cellIndex, newOffset);
|
|
3170
3910
|
},
|
|
3171
3911
|
[]
|
|
3172
3912
|
);
|
|
3173
3913
|
const moveEmbedAnchor = (0, import_react13.useCallback)(
|
|
3174
3914
|
(from, to, newOffsetX, newOffsetY) => {
|
|
3175
|
-
(0,
|
|
3915
|
+
(0, import_core8.moveEmbedAnchor)(ctxRef.current, from, to, newOffsetX, newOffsetY);
|
|
3176
3916
|
},
|
|
3177
3917
|
[]
|
|
3178
3918
|
);
|
|
@@ -3190,7 +3930,7 @@ function useEditor(opts = {}) {
|
|
|
3190
3930
|
}
|
|
3191
3931
|
const upload = uploadImageRef.current;
|
|
3192
3932
|
const src = upload ? await upload(file) : dataUrl;
|
|
3193
|
-
(0,
|
|
3933
|
+
(0, import_core8.insertImage)(ctxRef.current, { type: "image", src, width: w, height: h });
|
|
3194
3934
|
}, []);
|
|
3195
3935
|
const getSelectedEmbed = (0, import_react13.useCallback)(() => {
|
|
3196
3936
|
const sel = selectionRef.current;
|
|
@@ -3209,7 +3949,7 @@ function useEditor(opts = {}) {
|
|
|
3209
3949
|
cursor += op.insert.length;
|
|
3210
3950
|
continue;
|
|
3211
3951
|
}
|
|
3212
|
-
if (cursor === start && (0,
|
|
3952
|
+
if (cursor === start && (0, import_core8.isImageEmbed)(op.insert)) {
|
|
3213
3953
|
return {
|
|
3214
3954
|
blockIndex: sel.anchor.blockIndex,
|
|
3215
3955
|
cellIndex: sel.anchor.cellIndex,
|
|
@@ -3342,7 +4082,8 @@ function useEditor(opts = {}) {
|
|
|
3342
4082
|
resolvePageConfigRequest,
|
|
3343
4083
|
imageCaptionRequest,
|
|
3344
4084
|
requestImageCaption,
|
|
3345
|
-
resolveImageCaptionRequest
|
|
4085
|
+
resolveImageCaptionRequest,
|
|
4086
|
+
uploadImage: opts.uploadImage
|
|
3346
4087
|
};
|
|
3347
4088
|
}
|
|
3348
4089
|
function readAsDataURL(file) {
|
|
@@ -3389,6 +4130,7 @@ function Editor({
|
|
|
3389
4130
|
const { doc, history, snapshot, getSelection, setSelection } = editor;
|
|
3390
4131
|
const rootRef = (0, import_react14.useRef)(null);
|
|
3391
4132
|
const isComposingRef = (0, import_react14.useRef)(false);
|
|
4133
|
+
const pasteInFlightRef = (0, import_react14.useRef)(false);
|
|
3392
4134
|
const [hoveredBehind, setHoveredBehind] = (0, import_react14.useState)(null);
|
|
3393
4135
|
const hoveredBehindRef = (0, import_react14.useRef)(null);
|
|
3394
4136
|
const [hoveredLink, setHoveredLink] = (0, import_react14.useState)(null);
|
|
@@ -3404,7 +4146,7 @@ function Editor({
|
|
|
3404
4146
|
const sel = readDomSelection(root);
|
|
3405
4147
|
awareness.setLocalStateField(
|
|
3406
4148
|
"cursor",
|
|
3407
|
-
sel ? (0,
|
|
4149
|
+
sel ? (0, import_core9.encodeSelection)(doc, sel) ?? null : null
|
|
3408
4150
|
);
|
|
3409
4151
|
};
|
|
3410
4152
|
const onSelChange = () => {
|
|
@@ -3705,14 +4447,14 @@ function Editor({
|
|
|
3705
4447
|
const data = e.data ?? "";
|
|
3706
4448
|
if (data.length > 0) {
|
|
3707
4449
|
e.preventDefault();
|
|
3708
|
-
(0,
|
|
4450
|
+
(0, import_core9.insertText)(ctx, data, ed.consumePendingMarks());
|
|
3709
4451
|
}
|
|
3710
4452
|
return;
|
|
3711
4453
|
}
|
|
3712
4454
|
case "insertLineBreak": {
|
|
3713
4455
|
e.preventDefault();
|
|
3714
4456
|
if (ed.getBlockType() === "listItem") {
|
|
3715
|
-
(0,
|
|
4457
|
+
(0, import_core9.insertText)(ctx, "\n", ed.consumePendingMarks());
|
|
3716
4458
|
return;
|
|
3717
4459
|
}
|
|
3718
4460
|
const selEmbed = ed.getSelectedEmbed();
|
|
@@ -3732,7 +4474,7 @@ function Editor({
|
|
|
3732
4474
|
});
|
|
3733
4475
|
}
|
|
3734
4476
|
if (ed.splitListItem()) return;
|
|
3735
|
-
(0,
|
|
4477
|
+
(0, import_core9.insertParagraph)(ctx);
|
|
3736
4478
|
return;
|
|
3737
4479
|
}
|
|
3738
4480
|
case "insertParagraph": {
|
|
@@ -3754,14 +4496,14 @@ function Editor({
|
|
|
3754
4496
|
});
|
|
3755
4497
|
}
|
|
3756
4498
|
if (ed.splitListItem()) return;
|
|
3757
|
-
(0,
|
|
4499
|
+
(0, import_core9.insertParagraph)(ctx);
|
|
3758
4500
|
return;
|
|
3759
4501
|
}
|
|
3760
4502
|
case "insertReplacementText": {
|
|
3761
4503
|
const text = e.data ?? e.dataTransfer?.getData("text/plain") ?? "";
|
|
3762
4504
|
if (text.length > 0) {
|
|
3763
4505
|
e.preventDefault();
|
|
3764
|
-
(0,
|
|
4506
|
+
(0, import_core9.insertText)(ctx, text, ed.consumePendingMarks());
|
|
3765
4507
|
}
|
|
3766
4508
|
return;
|
|
3767
4509
|
}
|
|
@@ -3774,7 +4516,7 @@ function Editor({
|
|
|
3774
4516
|
case "deleteSoftLineBackward":
|
|
3775
4517
|
case "deleteHardLineBackward": {
|
|
3776
4518
|
e.preventDefault();
|
|
3777
|
-
(0,
|
|
4519
|
+
(0, import_core9.deleteBackward)(ctx);
|
|
3778
4520
|
return;
|
|
3779
4521
|
}
|
|
3780
4522
|
case "deleteContentForward":
|
|
@@ -3782,7 +4524,7 @@ function Editor({
|
|
|
3782
4524
|
case "deleteSoftLineForward":
|
|
3783
4525
|
case "deleteHardLineForward": {
|
|
3784
4526
|
e.preventDefault();
|
|
3785
|
-
(0,
|
|
4527
|
+
(0, import_core9.deleteForward)(ctx);
|
|
3786
4528
|
return;
|
|
3787
4529
|
}
|
|
3788
4530
|
case "historyUndo": {
|
|
@@ -3809,10 +4551,10 @@ function Editor({
|
|
|
3809
4551
|
if (!root) return;
|
|
3810
4552
|
const writeSlice = (e) => {
|
|
3811
4553
|
const ctx = ctxRef.current;
|
|
3812
|
-
const slice = (0,
|
|
4554
|
+
const slice = (0, import_core9.serializeSelection)(ctx.doc, ctx.getSelection());
|
|
3813
4555
|
if (!slice || !e.clipboardData) return false;
|
|
3814
|
-
e.clipboardData.setData(
|
|
3815
|
-
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));
|
|
3816
4558
|
return true;
|
|
3817
4559
|
};
|
|
3818
4560
|
const onCopy = (e) => {
|
|
@@ -3820,40 +4562,73 @@ function Editor({
|
|
|
3820
4562
|
};
|
|
3821
4563
|
const onCut = (e) => {
|
|
3822
4564
|
e.preventDefault();
|
|
3823
|
-
if (writeSlice(e)) (0,
|
|
4565
|
+
if (writeSlice(e)) (0, import_core9.deleteSelection)(ctxRef.current);
|
|
3824
4566
|
};
|
|
3825
4567
|
const onPaste = (e) => {
|
|
3826
4568
|
const ctx = ctxRef.current;
|
|
3827
4569
|
const cd = e.clipboardData;
|
|
3828
4570
|
if (!cd) return;
|
|
3829
|
-
const
|
|
3830
|
-
if (
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
4571
|
+
const plan = planPaste(cd);
|
|
4572
|
+
if (plan.kind === "none") return;
|
|
4573
|
+
e.preventDefault();
|
|
4574
|
+
switch (plan.kind) {
|
|
4575
|
+
case "sofer":
|
|
4576
|
+
(0, import_core9.insertSlice)(ctx, plan.slice);
|
|
4577
|
+
return;
|
|
4578
|
+
case "html": {
|
|
4579
|
+
if (!sliceHasDataImageEmbeds(plan.slice)) {
|
|
4580
|
+
(0, import_core9.insertSlice)(ctx, plan.slice);
|
|
3836
4581
|
return;
|
|
3837
4582
|
}
|
|
3838
|
-
|
|
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
|
+
}
|
|
4618
|
+
case "images":
|
|
4619
|
+
void (async () => {
|
|
4620
|
+
for (const f of plan.files) await editorRef.current.insertImageFromFile(f);
|
|
4621
|
+
})();
|
|
4622
|
+
return;
|
|
4623
|
+
case "text": {
|
|
4624
|
+
const lines = plan.text.split(/\r\n|\r|\n/);
|
|
4625
|
+
lines.forEach((line, i) => {
|
|
4626
|
+
if (i > 0) (0, import_core9.insertParagraph)(ctx);
|
|
4627
|
+
if (line.length > 0) (0, import_core9.insertText)(ctx, line);
|
|
4628
|
+
});
|
|
4629
|
+
return;
|
|
3839
4630
|
}
|
|
3840
4631
|
}
|
|
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
4632
|
};
|
|
3858
4633
|
root.addEventListener("copy", onCopy);
|
|
3859
4634
|
root.addEventListener("cut", onCut);
|
|
@@ -3892,6 +4667,17 @@ function Editor({
|
|
|
3892
4667
|
}
|
|
3893
4668
|
return;
|
|
3894
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
|
+
}
|
|
3895
4681
|
if (!mod) return;
|
|
3896
4682
|
const key = e.key.toLowerCase();
|
|
3897
4683
|
if (!e.shiftKey && !e.altKey && key === "z") {
|
|
@@ -3944,7 +4730,7 @@ function Editor({
|
|
|
3944
4730
|
const onCompositionEnd = (0, import_react14.useCallback)((e) => {
|
|
3945
4731
|
isComposingRef.current = false;
|
|
3946
4732
|
if (e.data && e.data.length > 0) {
|
|
3947
|
-
(0,
|
|
4733
|
+
(0, import_core9.insertText)(ctxRef.current, e.data);
|
|
3948
4734
|
}
|
|
3949
4735
|
}, []);
|
|
3950
4736
|
const topLevels = (0, import_react14.useMemo)(() => groupTopLevels(snapshot.blocks), [snapshot]);
|
|
@@ -4108,11 +4894,15 @@ function groupTopLevels(snapshot) {
|
|
|
4108
4894
|
const groupStart = i;
|
|
4109
4895
|
const items = [];
|
|
4110
4896
|
const kind = block.attrs.listKind === "ordered" ? "ordered" : "bullet";
|
|
4897
|
+
const leaderLevel = clampListLevel2(block.attrs.listLevel);
|
|
4111
4898
|
const groupStyle = block.attrs.listStyle;
|
|
4112
4899
|
while (i < snapshot.length) {
|
|
4113
4900
|
const b = snapshot[i];
|
|
4114
4901
|
if (b.type !== "listItem") break;
|
|
4115
|
-
|
|
4902
|
+
const bLevel = clampListLevel2(b.attrs.listLevel);
|
|
4903
|
+
if (bLevel <= leaderLevel && (b.attrs.listKind ?? "bullet") !== kind) {
|
|
4904
|
+
break;
|
|
4905
|
+
}
|
|
4116
4906
|
if (i > groupStart) {
|
|
4117
4907
|
if (typeof b.attrs.listStart === "number") break;
|
|
4118
4908
|
const itemStyle = b.attrs.listStyle;
|
|
@@ -4220,7 +5010,7 @@ function buildListTree(items) {
|
|
|
4220
5010
|
function renderListTree(tree, top, start, key) {
|
|
4221
5011
|
const className = `ed-list ed-list-${top.listKind}`;
|
|
4222
5012
|
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,
|
|
5013
|
+
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
5014
|
if (top.listKind === "ordered") {
|
|
4225
5015
|
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
4226
5016
|
"ol",
|
|
@@ -4236,9 +5026,10 @@ function renderListTree(tree, top, start, key) {
|
|
|
4236
5026
|
}
|
|
4237
5027
|
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("ul", { className, "data-list-kind": "bullet", style, children: items }, key);
|
|
4238
5028
|
}
|
|
4239
|
-
function renderNestedListTree(tree,
|
|
5029
|
+
function renderNestedListTree(tree, key) {
|
|
5030
|
+
const kind = tree[0]?.entry.block.attrs.listKind === "ordered" ? "ordered" : "bullet";
|
|
4240
5031
|
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,
|
|
5032
|
+
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
5033
|
}
|
|
4243
5034
|
function clampListLevel2(l) {
|
|
4244
5035
|
if (typeof l !== "number" || !Number.isFinite(l)) return 0;
|
|
@@ -4267,7 +5058,7 @@ function caretRangeFromPoint(x, y) {
|
|
|
4267
5058
|
|
|
4268
5059
|
// src/Toolbar.tsx
|
|
4269
5060
|
var import_react15 = require("react");
|
|
4270
|
-
var
|
|
5061
|
+
var import_core10 = require("@sofereditor/core");
|
|
4271
5062
|
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
4272
5063
|
var FONT_FAMILIES = ["Arial"];
|
|
4273
5064
|
var FONT_SIZES = ["8pt", "10pt", "11pt", "12pt", "14pt", "16pt", "18pt", "24pt", "32pt", "48pt"];
|
|
@@ -4739,7 +5530,7 @@ function AnswerLinesMenu() {
|
|
|
4739
5530
|
document.addEventListener("mousedown", onDown);
|
|
4740
5531
|
return () => document.removeEventListener("mousedown", onDown);
|
|
4741
5532
|
}, [open]);
|
|
4742
|
-
const clamped = Math.max(1, Math.min(
|
|
5533
|
+
const clamped = Math.max(1, Math.min(import_core10.ANSWER_LINE_MAX, Math.trunc(count) || 1));
|
|
4743
5534
|
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { ref: rootRef, className: "ed-toolbar-tablemenu", children: [
|
|
4744
5535
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
4745
5536
|
"button",
|
|
@@ -4772,7 +5563,7 @@ function AnswerLinesMenu() {
|
|
|
4772
5563
|
{
|
|
4773
5564
|
type: "number",
|
|
4774
5565
|
min: 1,
|
|
4775
|
-
max:
|
|
5566
|
+
max: import_core10.ANSWER_LINE_MAX,
|
|
4776
5567
|
value: count,
|
|
4777
5568
|
onChange: (e) => setCount(Number(e.target.value)),
|
|
4778
5569
|
"aria-label": "Quantidade de linhas"
|
|
@@ -4965,7 +5756,7 @@ function TableMenu() {
|
|
|
4965
5756
|
{
|
|
4966
5757
|
className: "ed-toolbar-swatch",
|
|
4967
5758
|
"aria-hidden": true,
|
|
4968
|
-
style: { background: editor.getTableBorderColor() ??
|
|
5759
|
+
style: { background: editor.getTableBorderColor() ?? import_core10.TABLE_BORDER_COLOR }
|
|
4969
5760
|
}
|
|
4970
5761
|
),
|
|
4971
5762
|
"Cor da borda",
|
|
@@ -4973,7 +5764,7 @@ function TableMenu() {
|
|
|
4973
5764
|
"input",
|
|
4974
5765
|
{
|
|
4975
5766
|
type: "color",
|
|
4976
|
-
value: editor.getTableBorderColor() ??
|
|
5767
|
+
value: editor.getTableBorderColor() ?? import_core10.TABLE_BORDER_COLOR,
|
|
4977
5768
|
onChange: (e) => editor.setTableBorderColor(e.target.value),
|
|
4978
5769
|
"aria-label": "Cor da borda"
|
|
4979
5770
|
}
|
|
@@ -5095,6 +5886,7 @@ function MarkButton({ title, pressed, onClick, children }) {
|
|
|
5095
5886
|
getBlockElement,
|
|
5096
5887
|
getCellElement,
|
|
5097
5888
|
getFragmentForOffset,
|
|
5889
|
+
htmlToSlice,
|
|
5098
5890
|
isTableRectSelection,
|
|
5099
5891
|
locatePoint,
|
|
5100
5892
|
readDomSelection,
|