@meistrari/minuta-editor 1.3.1 → 1.5.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/chunks/docxExport.mjs +179 -14
- package/dist/docx.mjs +1 -1
- package/dist/index.d.mts +62 -5
- package/dist/index.d.ts +62 -5
- package/dist/index.mjs +101 -6
- package/dist/shared/{minuta-editor.d9d0c0ce.mjs → minuta-editor.f1239e0b.mjs} +81 -3
- package/package.json +1 -1
|
@@ -1,11 +1,75 @@
|
|
|
1
|
-
import { f as footnoteHtmlToRuns, p as pocLoneCellIndex, a as pocLooksLikeTitle } from '../shared/minuta-editor.
|
|
2
|
-
import { BorderStyle, TextRun, ExternalHyperlink, Paragraph, Document, Header, Packer,
|
|
1
|
+
import { f as footnoteHtmlToRuns, p as pocLoneCellIndex, a as formatTopicNumber, b as pocLooksLikeTitle, c as pocNodeHasVisibleContent, d as pocNodePaintsBox, T as TOPIC_DEFAULT_GROUP } from '../shared/minuta-editor.f1239e0b.mjs';
|
|
2
|
+
import { BorderStyle, TextRun, ExternalHyperlink, Paragraph, Document, LevelFormat, AlignmentType, LevelSuffix, Header, Packer, LineRuleType, Table, TableRow, TableCell, WidthType, TableLayoutType, Footer, FootnoteReferenceRun, VerticalAlign, ImageRun, HorizontalPositionRelativeFrom, VerticalPositionRelativeFrom, TextWrappingType, FrameAnchorType, PageNumber, HeadingLevel } from 'docx';
|
|
3
3
|
import '@tiptap/pm/state';
|
|
4
4
|
import '@tiptap/pm/view';
|
|
5
5
|
|
|
6
6
|
const A4 = { width: 11906, height: 16838 };
|
|
7
7
|
const PX_TO_TWIP = 15;
|
|
8
8
|
const PX_PER_PT = 96 / 72;
|
|
9
|
+
function topicSequenceFor(ctx, group, roman, number) {
|
|
10
|
+
const key = group || TOPIC_DEFAULT_GROUP;
|
|
11
|
+
let seq = ctx.topicSequences.get(key);
|
|
12
|
+
if (!seq || seq.roman !== roman || seq.next !== number) {
|
|
13
|
+
const reference = `cdb-topic-${ctx.topicNumbering.size + 1}`;
|
|
14
|
+
ctx.topicNumbering.set(reference, { roman, start: number });
|
|
15
|
+
seq = { reference, roman, next: number };
|
|
16
|
+
ctx.topicSequences.set(key, seq);
|
|
17
|
+
}
|
|
18
|
+
seq.next = number + 1;
|
|
19
|
+
return seq.reference;
|
|
20
|
+
}
|
|
21
|
+
function listFormatFor(type) {
|
|
22
|
+
switch (type) {
|
|
23
|
+
case "a":
|
|
24
|
+
return LevelFormat.LOWER_LETTER;
|
|
25
|
+
case "A":
|
|
26
|
+
return LevelFormat.UPPER_LETTER;
|
|
27
|
+
case "i":
|
|
28
|
+
return LevelFormat.LOWER_ROMAN;
|
|
29
|
+
case "I":
|
|
30
|
+
return LevelFormat.UPPER_ROMAN;
|
|
31
|
+
default:
|
|
32
|
+
return LevelFormat.DECIMAL;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function listFormatFromCss(listStyleType) {
|
|
36
|
+
switch (listStyleType) {
|
|
37
|
+
case "lower-alpha":
|
|
38
|
+
case "lower-latin":
|
|
39
|
+
return LevelFormat.LOWER_LETTER;
|
|
40
|
+
case "upper-alpha":
|
|
41
|
+
case "upper-latin":
|
|
42
|
+
return LevelFormat.UPPER_LETTER;
|
|
43
|
+
case "lower-roman":
|
|
44
|
+
return LevelFormat.LOWER_ROMAN;
|
|
45
|
+
case "upper-roman":
|
|
46
|
+
return LevelFormat.UPPER_ROMAN;
|
|
47
|
+
default:
|
|
48
|
+
return LevelFormat.DECIMAL;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function listSequenceFor(ctx, list, run) {
|
|
52
|
+
const reference = `cdb-list-${ctx.listNumbering.size + 1}`;
|
|
53
|
+
const start = Number.parseInt(String(list.start ?? 1), 10);
|
|
54
|
+
ctx.listNumbering.set(reference, {
|
|
55
|
+
format: list.format,
|
|
56
|
+
// `start="0"` é válido (o Word aceita w:start=0); só o ausente/inválido vira 1
|
|
57
|
+
start: Number.isFinite(start) && start >= 0 ? start : 1,
|
|
58
|
+
suffix: list.suffix || ".",
|
|
59
|
+
run
|
|
60
|
+
});
|
|
61
|
+
return reference;
|
|
62
|
+
}
|
|
63
|
+
function leadingTopicNumber(node) {
|
|
64
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
65
|
+
const child = node.child(i);
|
|
66
|
+
if (child.isText && !child.text?.trim())
|
|
67
|
+
continue;
|
|
68
|
+
const number = Number(child.attrs.number);
|
|
69
|
+
return child.type.name === "topicNumber" && !child.attrs.ref && Number.isInteger(number) && number >= 1 ? child : null;
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
9
73
|
function getProp(style, prop) {
|
|
10
74
|
if (!style)
|
|
11
75
|
return void 0;
|
|
@@ -185,9 +249,15 @@ function withMarks(base, marks) {
|
|
|
185
249
|
}
|
|
186
250
|
return info;
|
|
187
251
|
}
|
|
188
|
-
function inlineToRuns(node, base, ctx) {
|
|
252
|
+
function inlineToRuns(node, base, ctx, skip) {
|
|
189
253
|
const runs = [];
|
|
190
254
|
node.forEach((child) => {
|
|
255
|
+
if (skip && child === skip)
|
|
256
|
+
return;
|
|
257
|
+
if (child.type.name === "topicNumber") {
|
|
258
|
+
runs.push(new TextRun({ text: formatTopicNumber(child.attrs.number, child.attrs.roman), ...runOptions(withMarks(base, child.marks)) }));
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
191
261
|
if (child.type.name === "footnoteRef") {
|
|
192
262
|
const text2 = String(child.attrs.text ?? "").trim();
|
|
193
263
|
if (ctx && text2) {
|
|
@@ -327,10 +397,18 @@ function textBlockToParagraph(node, pos, ctx, opts = {}) {
|
|
|
327
397
|
if (spacing.before && !breakBefore)
|
|
328
398
|
spacing.before = Math.max(0, spacing.before - ctx.lastAfterTw);
|
|
329
399
|
ctx.lastAfterTw = spacing.after ?? 0;
|
|
330
|
-
const
|
|
400
|
+
const topic = leadingTopicNumber(node);
|
|
401
|
+
let numbering;
|
|
402
|
+
if (topic) {
|
|
403
|
+
const reference = topicSequenceFor(ctx, topic.attrs.group, Boolean(topic.attrs.roman), Number(topic.attrs.number));
|
|
404
|
+
numbering = { reference, level: 0, custom: true };
|
|
405
|
+
}
|
|
406
|
+
const runs = inlineToRuns(node, base, ctx, topic);
|
|
331
407
|
const keepNext = Boolean(opts.heading || m && pocLooksLikeTitle(m.el)) || void 0;
|
|
332
408
|
const paragraph = new Paragraph({
|
|
333
409
|
children: runs,
|
|
410
|
+
numbering,
|
|
411
|
+
run: numbering ? runOptions(topic ? withMarks(base, topic.marks) : base) : void 0,
|
|
334
412
|
// sem alinhamento explícito, corpo de peça vai justificado (o Word
|
|
335
413
|
// usaria esquerda e o .docx sairia diferente da praxe e do preview)
|
|
336
414
|
alignment: m?.align ?? parseAlignment(style) ?? (opts.heading ? void 0 : AlignmentType.JUSTIFIED),
|
|
@@ -340,7 +418,7 @@ function textBlockToParagraph(node, pos, ctx, opts = {}) {
|
|
|
340
418
|
pageBreakBefore: breakBefore,
|
|
341
419
|
keepNext
|
|
342
420
|
});
|
|
343
|
-
ctx.meta.set(paragraph, { spacer: runs.length === 0 && !opts.heading, breakBefore });
|
|
421
|
+
ctx.meta.set(paragraph, { spacer: runs.length === 0 && !numbering && !opts.heading, breakBefore });
|
|
344
422
|
return paragraph;
|
|
345
423
|
}
|
|
346
424
|
async function srcToDataUrl(src) {
|
|
@@ -430,20 +508,28 @@ async function islandToDocx(node, pos, contentWidthPx, ctx) {
|
|
|
430
508
|
const paragraphs = [];
|
|
431
509
|
const liveLis = islandEl ? [...islandEl.querySelectorAll(":scope > ul > li, :scope > ol > li, :scope > li")] : [];
|
|
432
510
|
const parsedLis = [...el.querySelectorAll(":scope > li")];
|
|
433
|
-
let
|
|
511
|
+
let reference = null;
|
|
434
512
|
for (let i = 0; i < parsedLis.length; i++) {
|
|
435
513
|
const live = liveLis[i] ?? null;
|
|
436
514
|
const source = live ?? parsedLis[i];
|
|
437
515
|
const m = live ? measureEl(live) : null;
|
|
438
|
-
const
|
|
439
|
-
|
|
516
|
+
const markerRun = { color: m?.color, size: m?.sizeHalf, font: m ? primaryFont(m.cs) : void 0 };
|
|
517
|
+
if (tag === "ol" && !reference) {
|
|
518
|
+
const liveStyleType = liveLis[0] ? getComputedStyle(liveLis[0]).listStyleType : "";
|
|
519
|
+
reference = listSequenceFor(ctx, {
|
|
520
|
+
format: el.hasAttribute("type") ? listFormatFor(el.getAttribute("type")) : listFormatFromCss(liveStyleType),
|
|
521
|
+
start: el.getAttribute("start"),
|
|
522
|
+
suffix: el.getAttribute("data-list-suffix")
|
|
523
|
+
}, markerRun);
|
|
524
|
+
}
|
|
440
525
|
const runs = live ? domInlineToRuns(live) : [new TextRun({ text: source.textContent?.trim() || "", ...runOptions(parseStyle(source.getAttribute("style"))) })];
|
|
441
526
|
const indentPx = live && islandEl ? live.offsetLeft : 24;
|
|
442
527
|
paragraphs.push(new Paragraph({
|
|
443
528
|
children: [
|
|
444
|
-
new TextRun({ text:
|
|
529
|
+
...tag === "ul" ? [new TextRun({ text: "\u2022 ", ...markerRun })] : [],
|
|
445
530
|
...runs
|
|
446
531
|
],
|
|
532
|
+
numbering: reference ? { reference, level: 0 } : void 0,
|
|
447
533
|
spacing: m ? { after: m.afterTw, before: m.beforeTw, ...m.lineExactTw ? { line: m.lineExactTw, lineRule: LineRuleType.EXACT } : {} } : { after: 80 },
|
|
448
534
|
indent: { left: Math.round(indentPx * PX_TO_TWIP) },
|
|
449
535
|
alignment: m?.align,
|
|
@@ -658,6 +744,27 @@ async function flexRowToDocx(node, pos, contentWidthPx, ctx) {
|
|
|
658
744
|
}
|
|
659
745
|
return tables;
|
|
660
746
|
}
|
|
747
|
+
const INVISIBLE_NODE_TYPES = /* @__PURE__ */ new Set(["paragraph", "styledDiv", "missingImage", "hardBreak", "text"]);
|
|
748
|
+
function rowPaintsOrShowsAnything(row, rowPos, ctx) {
|
|
749
|
+
const paintsAt = (node, pos) => {
|
|
750
|
+
if (pocNodePaintsBox(node))
|
|
751
|
+
return true;
|
|
752
|
+
const dom = domAt(ctx, pos);
|
|
753
|
+
return Boolean(bordersFrom(measureAt(ctx, pos), node.attrs?.style)) || Boolean(cellShading(dom ? getComputedStyle(dom) : null));
|
|
754
|
+
};
|
|
755
|
+
if (paintsAt(row, rowPos))
|
|
756
|
+
return true;
|
|
757
|
+
let found = false;
|
|
758
|
+
row.descendants((node, offset) => {
|
|
759
|
+
if (found)
|
|
760
|
+
return false;
|
|
761
|
+
const pos = rowPos + 1 + offset;
|
|
762
|
+
if (!INVISIBLE_NODE_TYPES.has(node.type.name) || pocNodeHasVisibleContent(node) || paintsAt(node, pos))
|
|
763
|
+
found = true;
|
|
764
|
+
return !found;
|
|
765
|
+
});
|
|
766
|
+
return found;
|
|
767
|
+
}
|
|
661
768
|
function isPlainContainer(node) {
|
|
662
769
|
return node.type.name === "styledDiv" && !isFlexRow(node);
|
|
663
770
|
}
|
|
@@ -894,6 +1001,18 @@ async function nodeToDocx(node, pos, contentWidthPx, ctx) {
|
|
|
894
1001
|
}
|
|
895
1002
|
case "styledDiv": {
|
|
896
1003
|
if (isFlexRow(node)) {
|
|
1004
|
+
if (!rowPaintsOrShowsAnything(node, pos, ctx)) {
|
|
1005
|
+
const rowM2 = measureAt(ctx, pos);
|
|
1006
|
+
const breakBefore = consumeBreak(ctx);
|
|
1007
|
+
const before = breakBefore ? rowM2?.beforeTw ?? 0 : Math.max(0, (rowM2?.beforeTw ?? 0) - ctx.lastAfterTw);
|
|
1008
|
+
const lugar = new Paragraph({
|
|
1009
|
+
children: [],
|
|
1010
|
+
spacing: { after: rowM2?.afterTw ?? 0, before },
|
|
1011
|
+
pageBreakBefore: breakBefore
|
|
1012
|
+
});
|
|
1013
|
+
ctx.lastAfterTw = rowM2?.afterTw ?? 0;
|
|
1014
|
+
return [lugar];
|
|
1015
|
+
}
|
|
897
1016
|
const loneIndex = pocLoneCellIndex(node);
|
|
898
1017
|
if (loneIndex != null) {
|
|
899
1018
|
let childPos = pos + 1;
|
|
@@ -976,31 +1095,41 @@ async function nodeToDocx(node, pos, contentWidthPx, ctx) {
|
|
|
976
1095
|
case "bulletList":
|
|
977
1096
|
case "orderedList": {
|
|
978
1097
|
const paragraphs = [];
|
|
979
|
-
|
|
1098
|
+
const ordered = node.type.name === "orderedList";
|
|
1099
|
+
let reference = null;
|
|
980
1100
|
let liPos = pos + 1;
|
|
981
1101
|
for (let i = 0; i < node.childCount; i++) {
|
|
982
1102
|
const li = node.child(i);
|
|
983
1103
|
let childPos = liPos + 1;
|
|
1104
|
+
let marked = false;
|
|
984
1105
|
li.forEach((child) => {
|
|
985
1106
|
if (child.isTextblock) {
|
|
986
1107
|
const m = measureAt(ctx, childPos);
|
|
987
1108
|
const base = m ? { bold: m.bold, italics: m.italics, color: m.color, size: m.sizeHalf } : parseStyle(child.attrs.style);
|
|
988
|
-
const marker = node.type.name === "orderedList" ? `${n}. ` : "\u2022 ";
|
|
989
1109
|
const liDom = domAt(ctx, liPos);
|
|
990
1110
|
const indentPx = liDom?.offsetLeft ?? 48;
|
|
991
1111
|
const liBreak = consumeBreak(ctx);
|
|
1112
|
+
if (ordered && !reference) {
|
|
1113
|
+
reference = listSequenceFor(
|
|
1114
|
+
ctx,
|
|
1115
|
+
{ format: listFormatFor(node.attrs.type), start: node.attrs.start },
|
|
1116
|
+
{ bold: base.bold, italics: base.italics, color: base.color, size: base.size, font: base.font }
|
|
1117
|
+
);
|
|
1118
|
+
}
|
|
1119
|
+
const bullet = !ordered && !marked ? [new TextRun({ text: "\u2022 ", ...runOptions(base) })] : [];
|
|
992
1120
|
const liParagraph = new Paragraph({
|
|
993
|
-
children: [
|
|
1121
|
+
children: [...bullet, ...inlineToRuns(child, base, ctx)],
|
|
1122
|
+
numbering: ordered && !marked && reference ? { reference, level: 0 } : void 0,
|
|
994
1123
|
spacing: spacingFrom(m, child.attrs.style),
|
|
995
1124
|
indent: { left: Math.round(indentPx * PX_TO_TWIP) },
|
|
996
1125
|
pageBreakBefore: liBreak
|
|
997
1126
|
});
|
|
1127
|
+
marked = true;
|
|
998
1128
|
ctx.meta.set(liParagraph, { breakBefore: liBreak });
|
|
999
1129
|
paragraphs.push(liParagraph);
|
|
1000
1130
|
}
|
|
1001
1131
|
childPos += child.nodeSize;
|
|
1002
1132
|
});
|
|
1003
|
-
n++;
|
|
1004
1133
|
liPos += li.nodeSize;
|
|
1005
1134
|
}
|
|
1006
1135
|
return paragraphs;
|
|
@@ -1317,7 +1446,10 @@ async function pocExportDocx(editor, margins, chrome, options = {}) {
|
|
|
1317
1446
|
pending: { breakBefore: false },
|
|
1318
1447
|
lastAfterTw: 0,
|
|
1319
1448
|
meta: /* @__PURE__ */ new WeakMap(),
|
|
1320
|
-
footnotes: []
|
|
1449
|
+
footnotes: [],
|
|
1450
|
+
topicNumbering: /* @__PURE__ */ new Map(),
|
|
1451
|
+
topicSequences: /* @__PURE__ */ new Map(),
|
|
1452
|
+
listNumbering: /* @__PURE__ */ new Map()
|
|
1321
1453
|
};
|
|
1322
1454
|
const children = [];
|
|
1323
1455
|
let pos = 0;
|
|
@@ -1366,6 +1498,39 @@ async function pocExportDocx(editor, margins, chrome, options = {}) {
|
|
|
1366
1498
|
}
|
|
1367
1499
|
},
|
|
1368
1500
|
footnotes: Object.keys(footnotes).length ? footnotes : void 0,
|
|
1501
|
+
numbering: ctx.topicNumbering.size || ctx.listNumbering.size ? {
|
|
1502
|
+
config: [
|
|
1503
|
+
...[...ctx.topicNumbering].map(([reference, { roman, start }]) => ({
|
|
1504
|
+
reference,
|
|
1505
|
+
levels: [{
|
|
1506
|
+
level: 0,
|
|
1507
|
+
format: roman ? LevelFormat.UPPER_ROMAN : LevelFormat.DECIMAL,
|
|
1508
|
+
text: "%1",
|
|
1509
|
+
start,
|
|
1510
|
+
alignment: AlignmentType.START,
|
|
1511
|
+
// o ". " depois do número é texto do template; e sem
|
|
1512
|
+
// recuo/tab o parágrafo fica igual ao preview
|
|
1513
|
+
suffix: LevelSuffix.NOTHING,
|
|
1514
|
+
style: { paragraph: { indent: { left: 0, hanging: 0 } } }
|
|
1515
|
+
}]
|
|
1516
|
+
})),
|
|
1517
|
+
...[...ctx.listNumbering].map(([reference, { format, start, suffix, run }]) => ({
|
|
1518
|
+
reference,
|
|
1519
|
+
levels: [{
|
|
1520
|
+
level: 0,
|
|
1521
|
+
format,
|
|
1522
|
+
text: `%1${suffix}`,
|
|
1523
|
+
start,
|
|
1524
|
+
alignment: AlignmentType.LEFT,
|
|
1525
|
+
// "a. texto": marcador colado ao item com um espaço,
|
|
1526
|
+
// como o preview (list-style-position: inside); o
|
|
1527
|
+
// recuo é o do parágrafo, não da sequência
|
|
1528
|
+
suffix: LevelSuffix.SPACE,
|
|
1529
|
+
style: { paragraph: { indent: { left: 0, hanging: 0 } }, run }
|
|
1530
|
+
}]
|
|
1531
|
+
}))
|
|
1532
|
+
]
|
|
1533
|
+
} : void 0,
|
|
1369
1534
|
sections: [{
|
|
1370
1535
|
properties: {
|
|
1371
1536
|
page: {
|
package/dist/docx.mjs
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -17,12 +17,12 @@
|
|
|
17
17
|
/// <reference types="@tiptap/extension-text" />
|
|
18
18
|
/// <reference types="@tiptap/extension-table" />
|
|
19
19
|
/// <reference types="@tiptap/extension-bubble-menu" />
|
|
20
|
-
import { Node, Editor,
|
|
20
|
+
import { Node, Editor, Extension, Mark } from '@tiptap/core';
|
|
21
|
+
import { Transaction } from '@tiptap/pm/state';
|
|
21
22
|
import { EditorView } from '@tiptap/pm/view';
|
|
22
23
|
import { P as PocPageConfig } from './shared/minuta-editor.9e65d163.mjs';
|
|
23
24
|
export { e as PAGINATE_META, a as PocDocxChrome, b as PocDocxExportOptions, s as PocLoneRow, d as PocPageBreak, c as PocPageNote, v as PocPaginationPlugin, u as breaksEqual, h as buildPocFooterEl, g as buildPocHeaderEl, j as buildPocNotesEl, l as computePocBreaks, t as computePocLoneRows, i as isPocChromeCanvas, n as isPocFlexRow, f as pocChromeFlowHeight, m as pocDescendsInto, r as pocLoneCellIndex, k as pocLooksLikeTitle, o as pocNodeHasVisibleContent, q as pocNodePaintsBox, p as pocPageKey } from './shared/minuta-editor.9e65d163.mjs';
|
|
24
25
|
import '@tiptap/pm/model';
|
|
25
|
-
import '@tiptap/pm/state';
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* Variáveis de template da minuta — o formato do placeholder e a resolução dele.
|
|
@@ -162,6 +162,29 @@ declare const PocTemplateVariable: Node<{
|
|
|
162
162
|
declare const PocFootnoteRef: Node<any, any>;
|
|
163
163
|
/** re-sequencia a numeração das chamadas de nota na ordem do documento */
|
|
164
164
|
declare function renumberPocFootnotes(editor: Editor): void;
|
|
165
|
+
/**
|
|
166
|
+
* Número de tópico/parágrafo — o `<topic group="paragrafo"/>` do template já
|
|
167
|
+
* resolvido pelo render. É NÓ, e não texto, por dois motivos: quem edita a
|
|
168
|
+
* minuta apaga, move ou insere um parágrafo numerado e a sequência do grupo se
|
|
169
|
+
* refaz sozinha (`PocTopicRenumber`), e o export leva o número como numeração
|
|
170
|
+
* nativa do Word, que também se refaz quando o advogado apaga um parágrafo lá.
|
|
171
|
+
* Contrato do marcador em `utils/topicNumber.ts`.
|
|
172
|
+
*/
|
|
173
|
+
declare const PocTopicNumber: Node<any, any>;
|
|
174
|
+
/**
|
|
175
|
+
* Re-sequencia os números de tópico na ordem do documento, por grupo, dentro
|
|
176
|
+
* da transação dada. Devolve se mudou algo. Um nó `ref` (latest) recebe o
|
|
177
|
+
* último número já contado do grupo — a mesma regra do render.
|
|
178
|
+
*/
|
|
179
|
+
declare function renumberPocTopicsIn(tr: Transaction): boolean;
|
|
180
|
+
/** re-sequencia a numeração dos tópicos no editor dado (uso pontual; o plugin faz isso a cada mudança) */
|
|
181
|
+
declare function renumberPocTopics(editor: Editor): void;
|
|
182
|
+
/**
|
|
183
|
+
* A cada transação que muda o documento, refaz a sequência dos tópicos. Só
|
|
184
|
+
* despacha quando algum número de fato mudou, então digitar dentro de um
|
|
185
|
+
* parágrafo não custa nada além da varredura.
|
|
186
|
+
*/
|
|
187
|
+
declare const PocTopicRenumber: Extension<any, any>;
|
|
165
188
|
declare const PocStyledDiv: Node<any, any>;
|
|
166
189
|
declare const PocInlineStyle: Mark<any, any>;
|
|
167
190
|
declare const PocUnderline: Mark<any, any>;
|
|
@@ -181,7 +204,7 @@ declare function buildPocExtensions(pageConfig?: PocPageConfig, options?: {
|
|
|
181
204
|
* ainda no editor — o seletor de variável — depende disso.
|
|
182
205
|
*/
|
|
183
206
|
handleKeyDown?: (view: EditorView, event: KeyboardEvent) => boolean;
|
|
184
|
-
}): (Node<any, any> |
|
|
207
|
+
}): (Node<any, any> | Extension<any, any> | Mark<any, any>)[];
|
|
185
208
|
|
|
186
209
|
/**
|
|
187
210
|
* O editor de minuta como coisa montável em qualquer lugar: `createMinutaEditor(el, opts)`.
|
|
@@ -480,6 +503,40 @@ declare function refreshVaultImages(editor: Editor, resolveUrl: (vaultUrl: strin
|
|
|
480
503
|
*/
|
|
481
504
|
declare function sanitizeRichHtml(html: string | null | undefined): string;
|
|
482
505
|
|
|
506
|
+
/**
|
|
507
|
+
* Número de tópico/parágrafo — o `<topic group="paragrafo"/>` dos templates.
|
|
508
|
+
*
|
|
509
|
+
* O render resolve o número, mas em vez de achatá-lo em texto ("12") o guarda
|
|
510
|
+
* num `<span data-topic-number>`: no editor ele vira o nó `topicNumber`, que se
|
|
511
|
+
* re-sequencia sozinho quando um parágrafo é apagado, movido ou inserido, e no
|
|
512
|
+
* DOCX vira numeração nativa do Word (que também se refaz quando o advogado
|
|
513
|
+
* apaga um parágrafo lá). Este é o contrato do marcador — server, client e
|
|
514
|
+
* pacote falam por ele.
|
|
515
|
+
*/
|
|
516
|
+
declare const TOPIC_NUMBER_ATTR = "data-topic-number";
|
|
517
|
+
declare const TOPIC_GROUP_ATTR = "data-topic-group";
|
|
518
|
+
declare const TOPIC_ROMAN_ATTR = "data-topic-roman";
|
|
519
|
+
declare const TOPIC_REF_ATTR = "data-topic-ref";
|
|
520
|
+
declare const TOPIC_DEFAULT_GROUP = "default";
|
|
521
|
+
interface TopicNumberInfo {
|
|
522
|
+
/** valor numérico (o que se conta) */
|
|
523
|
+
number: number;
|
|
524
|
+
/** grupo do contador (`group` da tag); sem grupo = `default` */
|
|
525
|
+
group: string;
|
|
526
|
+
/** exibido em algarismos romanos maiúsculos */
|
|
527
|
+
roman: boolean;
|
|
528
|
+
/** `<topic latest="true">`: repete o último número do grupo em vez de avançar */
|
|
529
|
+
ref: boolean;
|
|
530
|
+
}
|
|
531
|
+
declare function toRoman(num: number): string;
|
|
532
|
+
declare function fromRoman(text: string): number | null;
|
|
533
|
+
/** texto exibido para o número (decimal ou romano) */
|
|
534
|
+
declare function formatTopicNumber(number: number, roman: boolean): string;
|
|
535
|
+
/** o marcador em HTML — é o que o render emite e o que o editor lê e grava */
|
|
536
|
+
declare function topicNumberHtml(info: TopicNumberInfo): string;
|
|
537
|
+
/** lê o marcador de um elemento (`span[data-topic-number]`) */
|
|
538
|
+
declare function readTopicNumber(el: Element): TopicNumberInfo;
|
|
539
|
+
|
|
483
540
|
/**
|
|
484
541
|
* A tag de imagem que o editor insere após o upload: guarda o `src` presignado
|
|
485
542
|
* (funciona agora) E o `data-vault-src` durável (`vault://…`). Quem re-resolve
|
|
@@ -504,5 +561,5 @@ declare function collectVaultRefs(html: string): string[];
|
|
|
504
561
|
/** aplica as URLs resolvidas às `<img>` do trecho; tags sem resolução ficam como estão */
|
|
505
562
|
declare function renewVaultImageTags(html: string, resolved: Map<string, string>): string;
|
|
506
563
|
|
|
507
|
-
export { A4_HEIGHT_PX, A4_WIDTH_PX, DEFAULT_MARGINS, DOC_FONTS, ICON_PATHS, POC_ASSET_SWAP, PocDocument, PocFootnoteRef, PocHtmlIsland, PocInlineStyle, PocMinutaBlock, PocMissingImage, PocPageConfig, PocStylePassthrough, PocStyledDiv, PocTemplateVariable, PocUnderline, PocVariableChip, buildPocExtensions, collectVaultRefs, createMinutaEditor, decodeVaultAttr, dispatchVariableClick, escapeHtml, escapeVaultAttr, extractTemplateVariables, footnoteHtmlToRuns, footnoteSizePt, iconSvg, refreshVaultImages, renewVaultImageTags, renumberPocFootnotes, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, shouldMoveBreakToHeading, swapVaultSrc, variableChipHtml, vaultImageHtml, vaultRefOf };
|
|
508
|
-
export type { FootnoteRun, MinutaChromeText, MinutaEditor, MinutaEditorOptions, MinutaHeader, MinutaMargins, MinutaVariableCatalog, MinutaVariableDef, MinutaVariableRef, PocKeepWithNextItem, RefreshVaultImagesOptions, VariableClickKind };
|
|
564
|
+
export { A4_HEIGHT_PX, A4_WIDTH_PX, DEFAULT_MARGINS, DOC_FONTS, ICON_PATHS, POC_ASSET_SWAP, PocDocument, PocFootnoteRef, PocHtmlIsland, PocInlineStyle, PocMinutaBlock, PocMissingImage, PocPageConfig, PocStylePassthrough, PocStyledDiv, PocTemplateVariable, PocTopicNumber, PocTopicRenumber, PocUnderline, PocVariableChip, TOPIC_DEFAULT_GROUP, TOPIC_GROUP_ATTR, TOPIC_NUMBER_ATTR, TOPIC_REF_ATTR, TOPIC_ROMAN_ATTR, buildPocExtensions, collectVaultRefs, createMinutaEditor, decodeVaultAttr, dispatchVariableClick, escapeHtml, escapeVaultAttr, extractTemplateVariables, footnoteHtmlToRuns, footnoteSizePt, formatTopicNumber, fromRoman, iconSvg, readTopicNumber, refreshVaultImages, renewVaultImageTags, renumberPocFootnotes, renumberPocTopics, renumberPocTopicsIn, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, shouldMoveBreakToHeading, swapVaultSrc, toRoman, topicNumberHtml, variableChipHtml, vaultImageHtml, vaultRefOf };
|
|
565
|
+
export type { FootnoteRun, MinutaChromeText, MinutaEditor, MinutaEditorOptions, MinutaHeader, MinutaMargins, MinutaVariableCatalog, MinutaVariableDef, MinutaVariableRef, PocKeepWithNextItem, RefreshVaultImagesOptions, TopicNumberInfo, VariableClickKind };
|
package/dist/index.d.ts
CHANGED
|
@@ -17,12 +17,12 @@
|
|
|
17
17
|
/// <reference types="@tiptap/extension-text" />
|
|
18
18
|
/// <reference types="@tiptap/extension-table" />
|
|
19
19
|
/// <reference types="@tiptap/extension-bubble-menu" />
|
|
20
|
-
import { Node, Editor,
|
|
20
|
+
import { Node, Editor, Extension, Mark } from '@tiptap/core';
|
|
21
|
+
import { Transaction } from '@tiptap/pm/state';
|
|
21
22
|
import { EditorView } from '@tiptap/pm/view';
|
|
22
23
|
import { P as PocPageConfig } from './shared/minuta-editor.9e65d163.js';
|
|
23
24
|
export { e as PAGINATE_META, a as PocDocxChrome, b as PocDocxExportOptions, s as PocLoneRow, d as PocPageBreak, c as PocPageNote, v as PocPaginationPlugin, u as breaksEqual, h as buildPocFooterEl, g as buildPocHeaderEl, j as buildPocNotesEl, l as computePocBreaks, t as computePocLoneRows, i as isPocChromeCanvas, n as isPocFlexRow, f as pocChromeFlowHeight, m as pocDescendsInto, r as pocLoneCellIndex, k as pocLooksLikeTitle, o as pocNodeHasVisibleContent, q as pocNodePaintsBox, p as pocPageKey } from './shared/minuta-editor.9e65d163.js';
|
|
24
25
|
import '@tiptap/pm/model';
|
|
25
|
-
import '@tiptap/pm/state';
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* Variáveis de template da minuta — o formato do placeholder e a resolução dele.
|
|
@@ -162,6 +162,29 @@ declare const PocTemplateVariable: Node<{
|
|
|
162
162
|
declare const PocFootnoteRef: Node<any, any>;
|
|
163
163
|
/** re-sequencia a numeração das chamadas de nota na ordem do documento */
|
|
164
164
|
declare function renumberPocFootnotes(editor: Editor): void;
|
|
165
|
+
/**
|
|
166
|
+
* Número de tópico/parágrafo — o `<topic group="paragrafo"/>` do template já
|
|
167
|
+
* resolvido pelo render. É NÓ, e não texto, por dois motivos: quem edita a
|
|
168
|
+
* minuta apaga, move ou insere um parágrafo numerado e a sequência do grupo se
|
|
169
|
+
* refaz sozinha (`PocTopicRenumber`), e o export leva o número como numeração
|
|
170
|
+
* nativa do Word, que também se refaz quando o advogado apaga um parágrafo lá.
|
|
171
|
+
* Contrato do marcador em `utils/topicNumber.ts`.
|
|
172
|
+
*/
|
|
173
|
+
declare const PocTopicNumber: Node<any, any>;
|
|
174
|
+
/**
|
|
175
|
+
* Re-sequencia os números de tópico na ordem do documento, por grupo, dentro
|
|
176
|
+
* da transação dada. Devolve se mudou algo. Um nó `ref` (latest) recebe o
|
|
177
|
+
* último número já contado do grupo — a mesma regra do render.
|
|
178
|
+
*/
|
|
179
|
+
declare function renumberPocTopicsIn(tr: Transaction): boolean;
|
|
180
|
+
/** re-sequencia a numeração dos tópicos no editor dado (uso pontual; o plugin faz isso a cada mudança) */
|
|
181
|
+
declare function renumberPocTopics(editor: Editor): void;
|
|
182
|
+
/**
|
|
183
|
+
* A cada transação que muda o documento, refaz a sequência dos tópicos. Só
|
|
184
|
+
* despacha quando algum número de fato mudou, então digitar dentro de um
|
|
185
|
+
* parágrafo não custa nada além da varredura.
|
|
186
|
+
*/
|
|
187
|
+
declare const PocTopicRenumber: Extension<any, any>;
|
|
165
188
|
declare const PocStyledDiv: Node<any, any>;
|
|
166
189
|
declare const PocInlineStyle: Mark<any, any>;
|
|
167
190
|
declare const PocUnderline: Mark<any, any>;
|
|
@@ -181,7 +204,7 @@ declare function buildPocExtensions(pageConfig?: PocPageConfig, options?: {
|
|
|
181
204
|
* ainda no editor — o seletor de variável — depende disso.
|
|
182
205
|
*/
|
|
183
206
|
handleKeyDown?: (view: EditorView, event: KeyboardEvent) => boolean;
|
|
184
|
-
}): (Node<any, any> |
|
|
207
|
+
}): (Node<any, any> | Extension<any, any> | Mark<any, any>)[];
|
|
185
208
|
|
|
186
209
|
/**
|
|
187
210
|
* O editor de minuta como coisa montável em qualquer lugar: `createMinutaEditor(el, opts)`.
|
|
@@ -480,6 +503,40 @@ declare function refreshVaultImages(editor: Editor, resolveUrl: (vaultUrl: strin
|
|
|
480
503
|
*/
|
|
481
504
|
declare function sanitizeRichHtml(html: string | null | undefined): string;
|
|
482
505
|
|
|
506
|
+
/**
|
|
507
|
+
* Número de tópico/parágrafo — o `<topic group="paragrafo"/>` dos templates.
|
|
508
|
+
*
|
|
509
|
+
* O render resolve o número, mas em vez de achatá-lo em texto ("12") o guarda
|
|
510
|
+
* num `<span data-topic-number>`: no editor ele vira o nó `topicNumber`, que se
|
|
511
|
+
* re-sequencia sozinho quando um parágrafo é apagado, movido ou inserido, e no
|
|
512
|
+
* DOCX vira numeração nativa do Word (que também se refaz quando o advogado
|
|
513
|
+
* apaga um parágrafo lá). Este é o contrato do marcador — server, client e
|
|
514
|
+
* pacote falam por ele.
|
|
515
|
+
*/
|
|
516
|
+
declare const TOPIC_NUMBER_ATTR = "data-topic-number";
|
|
517
|
+
declare const TOPIC_GROUP_ATTR = "data-topic-group";
|
|
518
|
+
declare const TOPIC_ROMAN_ATTR = "data-topic-roman";
|
|
519
|
+
declare const TOPIC_REF_ATTR = "data-topic-ref";
|
|
520
|
+
declare const TOPIC_DEFAULT_GROUP = "default";
|
|
521
|
+
interface TopicNumberInfo {
|
|
522
|
+
/** valor numérico (o que se conta) */
|
|
523
|
+
number: number;
|
|
524
|
+
/** grupo do contador (`group` da tag); sem grupo = `default` */
|
|
525
|
+
group: string;
|
|
526
|
+
/** exibido em algarismos romanos maiúsculos */
|
|
527
|
+
roman: boolean;
|
|
528
|
+
/** `<topic latest="true">`: repete o último número do grupo em vez de avançar */
|
|
529
|
+
ref: boolean;
|
|
530
|
+
}
|
|
531
|
+
declare function toRoman(num: number): string;
|
|
532
|
+
declare function fromRoman(text: string): number | null;
|
|
533
|
+
/** texto exibido para o número (decimal ou romano) */
|
|
534
|
+
declare function formatTopicNumber(number: number, roman: boolean): string;
|
|
535
|
+
/** o marcador em HTML — é o que o render emite e o que o editor lê e grava */
|
|
536
|
+
declare function topicNumberHtml(info: TopicNumberInfo): string;
|
|
537
|
+
/** lê o marcador de um elemento (`span[data-topic-number]`) */
|
|
538
|
+
declare function readTopicNumber(el: Element): TopicNumberInfo;
|
|
539
|
+
|
|
483
540
|
/**
|
|
484
541
|
* A tag de imagem que o editor insere após o upload: guarda o `src` presignado
|
|
485
542
|
* (funciona agora) E o `data-vault-src` durável (`vault://…`). Quem re-resolve
|
|
@@ -504,5 +561,5 @@ declare function collectVaultRefs(html: string): string[];
|
|
|
504
561
|
/** aplica as URLs resolvidas às `<img>` do trecho; tags sem resolução ficam como estão */
|
|
505
562
|
declare function renewVaultImageTags(html: string, resolved: Map<string, string>): string;
|
|
506
563
|
|
|
507
|
-
export { A4_HEIGHT_PX, A4_WIDTH_PX, DEFAULT_MARGINS, DOC_FONTS, ICON_PATHS, POC_ASSET_SWAP, PocDocument, PocFootnoteRef, PocHtmlIsland, PocInlineStyle, PocMinutaBlock, PocMissingImage, PocPageConfig, PocStylePassthrough, PocStyledDiv, PocTemplateVariable, PocUnderline, PocVariableChip, buildPocExtensions, collectVaultRefs, createMinutaEditor, decodeVaultAttr, dispatchVariableClick, escapeHtml, escapeVaultAttr, extractTemplateVariables, footnoteHtmlToRuns, footnoteSizePt, iconSvg, refreshVaultImages, renewVaultImageTags, renumberPocFootnotes, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, shouldMoveBreakToHeading, swapVaultSrc, variableChipHtml, vaultImageHtml, vaultRefOf };
|
|
508
|
-
export type { FootnoteRun, MinutaChromeText, MinutaEditor, MinutaEditorOptions, MinutaHeader, MinutaMargins, MinutaVariableCatalog, MinutaVariableDef, MinutaVariableRef, PocKeepWithNextItem, RefreshVaultImagesOptions, VariableClickKind };
|
|
564
|
+
export { A4_HEIGHT_PX, A4_WIDTH_PX, DEFAULT_MARGINS, DOC_FONTS, ICON_PATHS, POC_ASSET_SWAP, PocDocument, PocFootnoteRef, PocHtmlIsland, PocInlineStyle, PocMinutaBlock, PocMissingImage, PocPageConfig, PocStylePassthrough, PocStyledDiv, PocTemplateVariable, PocTopicNumber, PocTopicRenumber, PocUnderline, PocVariableChip, TOPIC_DEFAULT_GROUP, TOPIC_GROUP_ATTR, TOPIC_NUMBER_ATTR, TOPIC_REF_ATTR, TOPIC_ROMAN_ATTR, buildPocExtensions, collectVaultRefs, createMinutaEditor, decodeVaultAttr, dispatchVariableClick, escapeHtml, escapeVaultAttr, extractTemplateVariables, footnoteHtmlToRuns, footnoteSizePt, formatTopicNumber, fromRoman, iconSvg, readTopicNumber, refreshVaultImages, renewVaultImageTags, renumberPocFootnotes, renumberPocTopics, renumberPocTopicsIn, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, shouldMoveBreakToHeading, swapVaultSrc, toRoman, topicNumberHtml, variableChipHtml, vaultImageHtml, vaultRefOf };
|
|
565
|
+
export type { FootnoteRun, MinutaChromeText, MinutaEditor, MinutaEditorOptions, MinutaHeader, MinutaMargins, MinutaVariableCatalog, MinutaVariableDef, MinutaVariableRef, PocKeepWithNextItem, RefreshVaultImagesOptions, TopicNumberInfo, VariableClickKind };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Node as Node$1, mergeAttributes,
|
|
1
|
+
import { Node as Node$1, mergeAttributes, Extension, Mark, Editor } from '@tiptap/core';
|
|
2
2
|
import BubbleMenu from '@tiptap/extension-bubble-menu';
|
|
3
3
|
import Bold from '@tiptap/extension-bold';
|
|
4
4
|
import Blockquote from '@tiptap/extension-blockquote';
|
|
@@ -22,8 +22,8 @@ import TableCell from '@tiptap/extension-table-cell';
|
|
|
22
22
|
import TableHeader from '@tiptap/extension-table-header';
|
|
23
23
|
import TableRow from '@tiptap/extension-table-row';
|
|
24
24
|
import { Plugin } from '@tiptap/pm/state';
|
|
25
|
-
import { s as sanitizeRichHtml,
|
|
26
|
-
export {
|
|
25
|
+
import { s as sanitizeRichHtml, e as sanitizeFootnoteHtml, g as footnoteSizePt, T as TOPIC_DEFAULT_GROUP, h as TOPIC_NUMBER_ATTR, r as readTopicNumber, i as TOPIC_GROUP_ATTR, j as TOPIC_ROMAN_ATTR, k as TOPIC_REF_ATTR, a as formatTopicNumber, P as PocPaginationPlugin, l as computePocBreaks, m as pocPageKey, n as breaksEqual, o as PAGINATE_META } from './shared/minuta-editor.f1239e0b.mjs';
|
|
26
|
+
export { v as buildPocFooterEl, u as buildPocHeaderEl, w as buildPocNotesEl, z as computePocLoneRows, f as footnoteHtmlToRuns, C as fromRoman, t as isPocChromeCanvas, y as isPocFlexRow, q as pocChromeFlowHeight, x as pocDescendsInto, p as pocLoneCellIndex, b as pocLooksLikeTitle, c as pocNodeHasVisibleContent, d as pocNodePaintsBox, A as shouldMoveBreakToHeading, B as toRoman, D as topicNumberHtml } from './shared/minuta-editor.f1239e0b.mjs';
|
|
27
27
|
import '@tiptap/pm/view';
|
|
28
28
|
|
|
29
29
|
const POC_ASSET_SWAP = "pocAssetSwap";
|
|
@@ -46,7 +46,17 @@ const PocMinutaBlock = Node$1.create({
|
|
|
46
46
|
addAttributes() {
|
|
47
47
|
return {
|
|
48
48
|
blockId: { default: null },
|
|
49
|
-
blockTitle: { default: null }
|
|
49
|
+
blockTitle: { default: null },
|
|
50
|
+
/**
|
|
51
|
+
* impressão digital do texto GERADO pelo checklist (ver
|
|
52
|
+
* utils/minutaBlockFingerprint no app): enquanto o conteúdo bater
|
|
53
|
+
* com ela o trecho não foi editado e o checklist pode re-gerá-lo
|
|
54
|
+
*/
|
|
55
|
+
genHash: {
|
|
56
|
+
default: null,
|
|
57
|
+
parseHTML: (el) => el.getAttribute("data-gen-hash"),
|
|
58
|
+
renderHTML: (attrs) => attrs.genHash ? { "data-gen-hash": attrs.genHash } : {}
|
|
59
|
+
}
|
|
50
60
|
};
|
|
51
61
|
},
|
|
52
62
|
parseHTML() {
|
|
@@ -408,7 +418,9 @@ const PocFootnoteRef = Node$1.create({
|
|
|
408
418
|
selectable: false,
|
|
409
419
|
addAttributes() {
|
|
410
420
|
return {
|
|
411
|
-
|
|
421
|
+
// o Tiptap relê `number="1"` do `<footnote>` e o converte em número —
|
|
422
|
+
// e o render do ProseMirror só aceita texto como conteúdo
|
|
423
|
+
number: { default: "", parseHTML: (el) => el.getAttribute("number") ?? el.textContent ?? "" },
|
|
412
424
|
/** conteúdo da nota em HTML de ênfase (b/i/u/br) */
|
|
413
425
|
text: { default: "" },
|
|
414
426
|
/** corpo declarado no template (`font-size: 9pt`), em pontos */
|
|
@@ -424,6 +436,17 @@ const PocFootnoteRef = Node$1.create({
|
|
|
424
436
|
text: el.getAttribute("data-footnote") ?? "",
|
|
425
437
|
size: Number.parseFloat(el.getAttribute("data-footnote-size") ?? "") || null
|
|
426
438
|
})
|
|
439
|
+
}, {
|
|
440
|
+
// `<footnote>` cru do template (HTML de servidor antigo ou de
|
|
441
|
+
// outra origem): sem esta regra a tag some e o texto da nota
|
|
442
|
+
// cai no meio do parágrafo
|
|
443
|
+
tag: "footnote",
|
|
444
|
+
priority: 110,
|
|
445
|
+
getAttrs: (el) => ({
|
|
446
|
+
number: el.getAttribute("number") ?? "",
|
|
447
|
+
text: sanitizeFootnoteHtml(el.innerHTML.replace(/ /g, " ")),
|
|
448
|
+
size: footnoteSizePt(el.getAttribute("style"))
|
|
449
|
+
})
|
|
427
450
|
}];
|
|
428
451
|
},
|
|
429
452
|
renderHTML({ node }) {
|
|
@@ -472,6 +495,76 @@ function renumberPocFootnotes(editor) {
|
|
|
472
495
|
if (touched)
|
|
473
496
|
editor.view.dispatch(tr);
|
|
474
497
|
}
|
|
498
|
+
const PocTopicNumber = Node$1.create({
|
|
499
|
+
name: "topicNumber",
|
|
500
|
+
inline: true,
|
|
501
|
+
group: "inline",
|
|
502
|
+
atom: true,
|
|
503
|
+
selectable: false,
|
|
504
|
+
addAttributes() {
|
|
505
|
+
return {
|
|
506
|
+
number: { default: 1 },
|
|
507
|
+
group: { default: TOPIC_DEFAULT_GROUP },
|
|
508
|
+
roman: { default: false },
|
|
509
|
+
/** `<topic latest="true">`: repete o último número do grupo em vez de avançar */
|
|
510
|
+
ref: { default: false }
|
|
511
|
+
};
|
|
512
|
+
},
|
|
513
|
+
parseHTML() {
|
|
514
|
+
return [{
|
|
515
|
+
tag: `span[${TOPIC_NUMBER_ATTR}]`,
|
|
516
|
+
priority: 110,
|
|
517
|
+
getAttrs: (el) => readTopicNumber(el)
|
|
518
|
+
}];
|
|
519
|
+
},
|
|
520
|
+
renderHTML({ node }) {
|
|
521
|
+
const attrs = {
|
|
522
|
+
[TOPIC_NUMBER_ATTR]: String(node.attrs.number),
|
|
523
|
+
[TOPIC_GROUP_ATTR]: node.attrs.group || TOPIC_DEFAULT_GROUP,
|
|
524
|
+
class: "poc-topic-number"
|
|
525
|
+
};
|
|
526
|
+
if (node.attrs.roman)
|
|
527
|
+
attrs[TOPIC_ROMAN_ATTR] = "true";
|
|
528
|
+
if (node.attrs.ref)
|
|
529
|
+
attrs[TOPIC_REF_ATTR] = "true";
|
|
530
|
+
return ["span", attrs, formatTopicNumber(node.attrs.number, node.attrs.roman)];
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
function renumberPocTopicsIn(tr) {
|
|
534
|
+
const counters = {};
|
|
535
|
+
let touched = false;
|
|
536
|
+
tr.doc.descendants((node, pos) => {
|
|
537
|
+
if (node.type.name !== "topicNumber")
|
|
538
|
+
return;
|
|
539
|
+
const group = node.attrs.group || TOPIC_DEFAULT_GROUP;
|
|
540
|
+
const number = node.attrs.ref ? counters[group] ?? 0 : counters[group] = (counters[group] ?? 0) + 1;
|
|
541
|
+
if (node.attrs.number !== number) {
|
|
542
|
+
tr.setNodeMarkup(pos, void 0, { ...node.attrs, number });
|
|
543
|
+
touched = true;
|
|
544
|
+
}
|
|
545
|
+
});
|
|
546
|
+
return touched;
|
|
547
|
+
}
|
|
548
|
+
function renumberPocTopics(editor) {
|
|
549
|
+
if (!editor || editor.isDestroyed)
|
|
550
|
+
return;
|
|
551
|
+
const tr = editor.state.tr;
|
|
552
|
+
if (renumberPocTopicsIn(tr))
|
|
553
|
+
editor.view.dispatch(tr);
|
|
554
|
+
}
|
|
555
|
+
const PocTopicRenumber = Extension.create({
|
|
556
|
+
name: "pocTopicRenumber",
|
|
557
|
+
addProseMirrorPlugins() {
|
|
558
|
+
return [new Plugin({
|
|
559
|
+
appendTransaction(transactions, _oldState, newState) {
|
|
560
|
+
if (!transactions.some((t) => t.docChanged))
|
|
561
|
+
return null;
|
|
562
|
+
const tr = newState.tr;
|
|
563
|
+
return renumberPocTopicsIn(tr) ? tr : null;
|
|
564
|
+
}
|
|
565
|
+
})];
|
|
566
|
+
}
|
|
567
|
+
});
|
|
475
568
|
const PocStyledDiv = Node$1.create({
|
|
476
569
|
name: "styledDiv",
|
|
477
570
|
group: "block",
|
|
@@ -601,6 +694,8 @@ function buildPocExtensions(pageConfig, options) {
|
|
|
601
694
|
PocVariableChip,
|
|
602
695
|
PocTemplateVariable.configure({ catalog: options?.variables ?? [] }),
|
|
603
696
|
PocFootnoteRef,
|
|
697
|
+
PocTopicNumber,
|
|
698
|
+
PocTopicRenumber,
|
|
604
699
|
PocStyledDiv,
|
|
605
700
|
PocInlineStyle,
|
|
606
701
|
PocUnderline,
|
|
@@ -2091,4 +2186,4 @@ function createMinutaEditor(element, opts) {
|
|
|
2091
2186
|
return api;
|
|
2092
2187
|
}
|
|
2093
2188
|
|
|
2094
|
-
export { A4_HEIGHT_PX, A4_WIDTH_PX, DEFAULT_MARGINS, DOC_FONTS, ICON_PATHS, PAGINATE_META, POC_ASSET_SWAP, PocDocument, PocFootnoteRef, PocHtmlIsland, PocInlineStyle, PocMinutaBlock, PocMissingImage, PocPaginationPlugin, PocStylePassthrough, PocStyledDiv, PocTemplateVariable, PocUnderline, PocVariableChip, breaksEqual, buildPocExtensions, collectVaultRefs, computePocBreaks, createMinutaEditor, decodeVaultAttr, dispatchVariableClick, escapeHtml, escapeVaultAttr, extractTemplateVariables, iconSvg, pocPageKey, refreshVaultImages, renewVaultImageTags, renumberPocFootnotes, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, swapVaultSrc, variableChipHtml, vaultImageHtml, vaultRefOf };
|
|
2189
|
+
export { A4_HEIGHT_PX, A4_WIDTH_PX, DEFAULT_MARGINS, DOC_FONTS, ICON_PATHS, PAGINATE_META, POC_ASSET_SWAP, PocDocument, PocFootnoteRef, PocHtmlIsland, PocInlineStyle, PocMinutaBlock, PocMissingImage, PocPaginationPlugin, PocStylePassthrough, PocStyledDiv, PocTemplateVariable, PocTopicNumber, PocTopicRenumber, PocUnderline, PocVariableChip, TOPIC_DEFAULT_GROUP, TOPIC_GROUP_ATTR, TOPIC_NUMBER_ATTR, TOPIC_REF_ATTR, TOPIC_ROMAN_ATTR, breaksEqual, buildPocExtensions, collectVaultRefs, computePocBreaks, createMinutaEditor, decodeVaultAttr, dispatchVariableClick, escapeHtml, escapeVaultAttr, extractTemplateVariables, footnoteSizePt, formatTopicNumber, iconSvg, pocPageKey, readTopicNumber, refreshVaultImages, renewVaultImageTags, renumberPocFootnotes, renumberPocTopics, renumberPocTopicsIn, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, swapVaultSrc, variableChipHtml, vaultImageHtml, vaultRefOf };
|
|
@@ -130,12 +130,12 @@ function sanitizeFootnoteHtml(html) {
|
|
|
130
130
|
return style ? `<span style="${style}">${inner}</span>` : inner;
|
|
131
131
|
}
|
|
132
132
|
if (node.tagName === "DIV" || node.tagName === "P")
|
|
133
|
-
return inner ? `${inner}<br>` : "";
|
|
133
|
+
return inner.trim() ? `${inner}<br>` : "";
|
|
134
134
|
if (INLINE_TAGS.has(node.tagName))
|
|
135
135
|
return `<${node.tagName.toLowerCase()}>${inner}</${node.tagName.toLowerCase()}>`;
|
|
136
136
|
return inner;
|
|
137
137
|
};
|
|
138
|
-
return Array.from(root.childNodes).map(walk).join("").replace(/\s+/g, " ").replace(/(<br>\s*)+$/i, "").trim();
|
|
138
|
+
return Array.from(root.childNodes).map(walk).join("").replace(/\s+/g, " ").replace(/^(\s*<br>)+/i, "").replace(/(<br>\s*)+$/i, "").trim();
|
|
139
139
|
}
|
|
140
140
|
function footnoteHtmlToRuns(html) {
|
|
141
141
|
const runs = [];
|
|
@@ -193,6 +193,84 @@ function footnoteSizePt(style) {
|
|
|
193
193
|
return Number.isFinite(value) ? value : null;
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
+
const TOPIC_NUMBER_ATTR = "data-topic-number";
|
|
197
|
+
const TOPIC_GROUP_ATTR = "data-topic-group";
|
|
198
|
+
const TOPIC_ROMAN_ATTR = "data-topic-roman";
|
|
199
|
+
const TOPIC_REF_ATTR = "data-topic-ref";
|
|
200
|
+
const TOPIC_DEFAULT_GROUP = "default";
|
|
201
|
+
function toRoman(num) {
|
|
202
|
+
if (!Number.isFinite(num) || num <= 0)
|
|
203
|
+
return "";
|
|
204
|
+
const numerals = [
|
|
205
|
+
[1e3, "M"],
|
|
206
|
+
[900, "CM"],
|
|
207
|
+
[500, "D"],
|
|
208
|
+
[400, "CD"],
|
|
209
|
+
[100, "C"],
|
|
210
|
+
[90, "XC"],
|
|
211
|
+
[50, "L"],
|
|
212
|
+
[40, "XL"],
|
|
213
|
+
[10, "X"],
|
|
214
|
+
[9, "IX"],
|
|
215
|
+
[5, "V"],
|
|
216
|
+
[4, "IV"],
|
|
217
|
+
[1, "I"]
|
|
218
|
+
];
|
|
219
|
+
let result = "";
|
|
220
|
+
let rest = Math.floor(num);
|
|
221
|
+
for (const [value, numeral] of numerals) {
|
|
222
|
+
while (rest >= value) {
|
|
223
|
+
result += numeral;
|
|
224
|
+
rest -= value;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return result;
|
|
228
|
+
}
|
|
229
|
+
function fromRoman(text) {
|
|
230
|
+
const upper = text.trim().toUpperCase();
|
|
231
|
+
if (!upper || !/^M{0,3}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$/.test(upper))
|
|
232
|
+
return null;
|
|
233
|
+
const values = { I: 1, V: 5, X: 10, L: 50, C: 100, D: 500, M: 1e3 };
|
|
234
|
+
let total = 0;
|
|
235
|
+
for (let i = 0; i < upper.length; i++) {
|
|
236
|
+
const current = values[upper[i]];
|
|
237
|
+
const next = values[upper[i + 1] ?? ""] ?? 0;
|
|
238
|
+
total += current < next ? -current : current;
|
|
239
|
+
}
|
|
240
|
+
return total;
|
|
241
|
+
}
|
|
242
|
+
function formatTopicNumber(number, roman) {
|
|
243
|
+
return roman ? toRoman(number) : String(number);
|
|
244
|
+
}
|
|
245
|
+
function escapeAttr(value) {
|
|
246
|
+
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
247
|
+
}
|
|
248
|
+
function topicNumberHtml(info) {
|
|
249
|
+
let attrs = `${TOPIC_NUMBER_ATTR}="${info.number}" ${TOPIC_GROUP_ATTR}="${escapeAttr(info.group || TOPIC_DEFAULT_GROUP)}"`;
|
|
250
|
+
if (info.roman)
|
|
251
|
+
attrs += ` ${TOPIC_ROMAN_ATTR}="true"`;
|
|
252
|
+
if (info.ref)
|
|
253
|
+
attrs += ` ${TOPIC_REF_ATTR}="true"`;
|
|
254
|
+
return `<span ${attrs}>${formatTopicNumber(info.number, info.roman)}</span>`;
|
|
255
|
+
}
|
|
256
|
+
function readTopicNumber(el) {
|
|
257
|
+
const roman = el.getAttribute(TOPIC_ROMAN_ATTR) === "true";
|
|
258
|
+
const raw = el.getAttribute(TOPIC_NUMBER_ATTR) ?? "";
|
|
259
|
+
let number = Number.parseInt(raw, 10);
|
|
260
|
+
if (!Number.isFinite(number)) {
|
|
261
|
+
const text = el.textContent?.trim() ?? "";
|
|
262
|
+
number = Number.parseInt(text, 10);
|
|
263
|
+
if (!Number.isFinite(number))
|
|
264
|
+
number = fromRoman(text) ?? 1;
|
|
265
|
+
}
|
|
266
|
+
return {
|
|
267
|
+
number,
|
|
268
|
+
group: el.getAttribute(TOPIC_GROUP_ATTR) || TOPIC_DEFAULT_GROUP,
|
|
269
|
+
roman,
|
|
270
|
+
ref: el.getAttribute(TOPIC_REF_ATTR) === "true"
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
|
|
196
274
|
function shouldMoveBreakToHeading(params) {
|
|
197
275
|
const { heading, item, pageStart, capacity } = params;
|
|
198
276
|
if (!heading || !heading.heading || heading.marker)
|
|
@@ -819,4 +897,4 @@ function PocPaginationPlugin(cfg) {
|
|
|
819
897
|
});
|
|
820
898
|
}
|
|
821
899
|
|
|
822
|
-
export { PocPaginationPlugin as P,
|
|
900
|
+
export { shouldMoveBreakToHeading as A, toRoman as B, fromRoman as C, topicNumberHtml as D, PocPaginationPlugin as P, TOPIC_DEFAULT_GROUP as T, formatTopicNumber as a, pocLooksLikeTitle as b, pocNodeHasVisibleContent as c, pocNodePaintsBox as d, sanitizeFootnoteHtml as e, footnoteHtmlToRuns as f, footnoteSizePt as g, TOPIC_NUMBER_ATTR as h, TOPIC_GROUP_ATTR as i, TOPIC_ROMAN_ATTR as j, TOPIC_REF_ATTR as k, computePocBreaks as l, pocPageKey as m, breaksEqual as n, PAGINATE_META as o, pocLoneCellIndex as p, pocChromeFlowHeight as q, readTopicNumber as r, sanitizeRichHtml as s, isPocChromeCanvas as t, buildPocHeaderEl as u, buildPocFooterEl as v, buildPocNotesEl as w, pocDescendsInto as x, isPocFlexRow as y, computePocLoneRows as z };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meistrari/minuta-editor",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Editor de minuta do defesa.ai sem framework: folha A4 paginada, edição rica, placeholders de variável e export DOCX fiel ao preview — monta em qualquer app (React, Vue, vanilla)",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|