@meistrari/minuta-editor 1.1.0 → 1.2.1
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/README.md +13 -1
- package/dist/chunks/docxExport.mjs +47 -32
- package/dist/docx.d.mts +1 -1
- package/dist/docx.d.ts +1 -1
- package/dist/docx.mjs +1 -1
- package/dist/index.d.mts +59 -10
- package/dist/index.d.ts +59 -10
- package/dist/index.mjs +126 -26
- package/dist/shared/{minuta-editor.e223a421.d.mts → minuta-editor.9e65d163.d.mts} +34 -8
- package/dist/shared/{minuta-editor.e223a421.d.ts → minuta-editor.9e65d163.d.ts} +34 -8
- package/dist/shared/{minuta-editor.b2512170.mjs → minuta-editor.d9d0c0ce.mjs} +142 -31
- package/dist/style.css +1 -1
- package/package.json +3 -2
package/dist/index.mjs
CHANGED
|
@@ -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, P as PocPaginationPlugin,
|
|
26
|
-
export {
|
|
25
|
+
import { s as sanitizeRichHtml, P as PocPaginationPlugin, b as sanitizeFootnoteHtml, c as computePocBreaks, d as pocPageKey, e as breaksEqual, g as PAGINATE_META } from './shared/minuta-editor.d9d0c0ce.mjs';
|
|
26
|
+
export { k as buildPocFooterEl, j as buildPocHeaderEl, l as buildPocNotesEl, r as computePocLoneRows, f as footnoteHtmlToRuns, t as footnoteSizePt, i as isPocChromeCanvas, n as isPocFlexRow, h as pocChromeFlowHeight, m as pocDescendsInto, p as pocLoneCellIndex, a as pocLooksLikeTitle, o as pocNodeHasVisibleContent, q as pocNodePaintsBox, u as shouldMoveBreakToHeading } from './shared/minuta-editor.d9d0c0ce.mjs';
|
|
27
27
|
import '@tiptap/pm/view';
|
|
28
28
|
|
|
29
29
|
const POC_ASSET_SWAP = "pocAssetSwap";
|
|
@@ -68,6 +68,11 @@ const PocMinutaBlock = Node$1.create({
|
|
|
68
68
|
}), 0];
|
|
69
69
|
}
|
|
70
70
|
});
|
|
71
|
+
function dispatchVariableClick(editor, detail) {
|
|
72
|
+
if (!detail.variableId)
|
|
73
|
+
return;
|
|
74
|
+
editor.view.dom.dispatchEvent(new CustomEvent("poc:variable-click", { bubbles: true, detail }));
|
|
75
|
+
}
|
|
71
76
|
const PocHtmlIsland = Node$1.create({
|
|
72
77
|
name: "htmlIsland",
|
|
73
78
|
group: "block",
|
|
@@ -95,6 +100,17 @@ const PocHtmlIsland = Node$1.create({
|
|
|
95
100
|
dom.className = "poc-island";
|
|
96
101
|
dom.contentEditable = "false";
|
|
97
102
|
dom.innerHTML = sanitizeRichHtml(node.attrs.html);
|
|
103
|
+
dom.addEventListener("click", (event) => {
|
|
104
|
+
const target = event.target?.closest?.("img[data-variable-id]");
|
|
105
|
+
if (!target)
|
|
106
|
+
return;
|
|
107
|
+
dispatchVariableClick(editor, {
|
|
108
|
+
variableId: target.getAttribute("data-variable-id"),
|
|
109
|
+
parentBlockId: target.getAttribute("data-parent-block-id"),
|
|
110
|
+
text: "",
|
|
111
|
+
kind: "image"
|
|
112
|
+
});
|
|
113
|
+
});
|
|
98
114
|
const img = dom.children.length === 1 && dom.firstElementChild instanceof HTMLImageElement ? dom.firstElementChild : null;
|
|
99
115
|
if (img)
|
|
100
116
|
dom.classList.add("poc-island--img");
|
|
@@ -206,11 +222,23 @@ const PocMissingImage = Node$1.create({
|
|
|
206
222
|
const caixa = document.createElement("div");
|
|
207
223
|
caixa.className = "missing-image-warning";
|
|
208
224
|
caixa.setAttribute("style", MISSING_IMAGE_BOX_STYLE);
|
|
225
|
+
caixa.setAttribute("data-variable-id", node.attrs.variableId ?? "");
|
|
226
|
+
caixa.setAttribute("data-parent-block-id", node.attrs.parentBlockId ?? "");
|
|
209
227
|
const linha = document.createElement("span");
|
|
210
228
|
linha.setAttribute("style", MISSING_IMAGE_ROW_STYLE);
|
|
211
229
|
linha.textContent = `\u26A0 A imagem ${node.attrs.variableId ?? ""} est\xE1 faltando`;
|
|
212
230
|
caixa.appendChild(linha);
|
|
213
231
|
dom.appendChild(caixa);
|
|
232
|
+
dom.addEventListener("click", (event) => {
|
|
233
|
+
if (event.target.closest(".poc-missing-image__remove"))
|
|
234
|
+
return;
|
|
235
|
+
dispatchVariableClick(editor, {
|
|
236
|
+
variableId: node.attrs.variableId,
|
|
237
|
+
parentBlockId: node.attrs.parentBlockId,
|
|
238
|
+
text: "",
|
|
239
|
+
kind: "missingImage"
|
|
240
|
+
});
|
|
241
|
+
});
|
|
214
242
|
if (!editor.isEditable)
|
|
215
243
|
return { dom };
|
|
216
244
|
caixa.style.position = "relative";
|
|
@@ -280,14 +308,12 @@ const PocVariableChip = Node$1.create({
|
|
|
280
308
|
dom.innerHTML = sanitizeRichHtml(node.attrs.html);
|
|
281
309
|
dom.addEventListener("click", (event) => {
|
|
282
310
|
event.preventDefault();
|
|
283
|
-
editor
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
}
|
|
290
|
-
}));
|
|
311
|
+
dispatchVariableClick(editor, {
|
|
312
|
+
variableId: node.attrs.variableId,
|
|
313
|
+
parentBlockId: node.attrs.parentBlockId,
|
|
314
|
+
text: node.attrs.text,
|
|
315
|
+
kind: "text"
|
|
316
|
+
});
|
|
291
317
|
});
|
|
292
318
|
return { dom };
|
|
293
319
|
};
|
|
@@ -300,6 +326,10 @@ function variableChipHtml(currentHtml, text) {
|
|
|
300
326
|
if (!el)
|
|
301
327
|
return currentHtml;
|
|
302
328
|
el.textContent = text;
|
|
329
|
+
if (el.hasAttribute("data-invalid-variable")) {
|
|
330
|
+
el.removeAttribute("data-invalid-variable");
|
|
331
|
+
el.removeAttribute("style");
|
|
332
|
+
}
|
|
303
333
|
return el.outerHTML;
|
|
304
334
|
}
|
|
305
335
|
function readCatalog(catalog) {
|
|
@@ -636,7 +666,7 @@ function resolveTemplateVariables(html, values) {
|
|
|
636
666
|
return { html: resolved, missing };
|
|
637
667
|
}
|
|
638
668
|
|
|
639
|
-
function escapeAttr(value) {
|
|
669
|
+
function escapeAttr$1(value) {
|
|
640
670
|
return value.replace(/&/g, "&").replace(/"/g, """);
|
|
641
671
|
}
|
|
642
672
|
function escapeVaultAttr(value) {
|
|
@@ -646,7 +676,81 @@ function decodeVaultAttr(value) {
|
|
|
646
676
|
return value.replace(/"/g, '"').replace(/>/g, ">").replace(/</g, "<").replace(/&/g, "&");
|
|
647
677
|
}
|
|
648
678
|
function vaultImageHtml(src, vaultUrl) {
|
|
649
|
-
return `<img src="${escapeAttr(src)}" data-vault-src="${escapeVaultAttr(vaultUrl)}" style="width: 420px; height: auto; max-width: 100%;">`;
|
|
679
|
+
return `<img src="${escapeAttr$1(src)}" data-vault-src="${escapeVaultAttr(vaultUrl)}" style="width: 420px; height: auto; max-width: 100%;">`;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
function escapeAttr(value) {
|
|
683
|
+
return value.replace(/&/g, "&").replace(/"/g, """);
|
|
684
|
+
}
|
|
685
|
+
function escapeRegExp(value) {
|
|
686
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
687
|
+
}
|
|
688
|
+
function swapSrcKeepRef(html, attrValue, freshUrl) {
|
|
689
|
+
const needle = `data-vault-src="${attrValue}"`;
|
|
690
|
+
if (!html.includes(needle))
|
|
691
|
+
return html;
|
|
692
|
+
const tagRe = new RegExp(`<img\\b[^>]*?${escapeRegExp(needle)}[^>]*?>`, "g");
|
|
693
|
+
return html.replace(tagRe, (tag) => tag.replace(/\ssrc="[^"]*"/, ` src="${escapeAttr(freshUrl)}"`));
|
|
694
|
+
}
|
|
695
|
+
async function refreshVaultImages(editor, resolveUrl, options = {}) {
|
|
696
|
+
if (!editor || editor.isDestroyed)
|
|
697
|
+
return 0;
|
|
698
|
+
const refs = /* @__PURE__ */ new Set();
|
|
699
|
+
editor.state.doc.descendants((node) => {
|
|
700
|
+
if (node.type.name !== "htmlIsland")
|
|
701
|
+
return;
|
|
702
|
+
for (const m of String(node.attrs.html ?? "").matchAll(/data-vault-src="([^"]+)"/g))
|
|
703
|
+
refs.add(m[1]);
|
|
704
|
+
});
|
|
705
|
+
if (!refs.size)
|
|
706
|
+
return 0;
|
|
707
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
708
|
+
await Promise.all([...refs].map(async (attrValue) => {
|
|
709
|
+
try {
|
|
710
|
+
const fresh = await resolveUrl(decodeVaultAttr(attrValue));
|
|
711
|
+
if (!fresh)
|
|
712
|
+
return;
|
|
713
|
+
await new Promise((done) => {
|
|
714
|
+
const img = new Image();
|
|
715
|
+
const finish = () => done();
|
|
716
|
+
img.onload = finish;
|
|
717
|
+
img.onerror = finish;
|
|
718
|
+
setTimeout(finish, 4e3);
|
|
719
|
+
img.src = fresh;
|
|
720
|
+
});
|
|
721
|
+
resolved.set(attrValue, fresh);
|
|
722
|
+
} catch (error) {
|
|
723
|
+
console.error("minuta: falha ao resolver imagem do vault", attrValue, error);
|
|
724
|
+
}
|
|
725
|
+
}));
|
|
726
|
+
if (!resolved.size || editor.isDestroyed)
|
|
727
|
+
return 0;
|
|
728
|
+
const tr = editor.state.tr;
|
|
729
|
+
let touched = 0;
|
|
730
|
+
editor.state.doc.descendants((node, pos) => {
|
|
731
|
+
if (node.type.name !== "htmlIsland")
|
|
732
|
+
return;
|
|
733
|
+
let html = String(node.attrs.html ?? "");
|
|
734
|
+
let changed = false;
|
|
735
|
+
for (const [attrValue, freshUrl] of resolved) {
|
|
736
|
+
const next = swapSrcKeepRef(html, attrValue, freshUrl);
|
|
737
|
+
if (next !== html) {
|
|
738
|
+
html = next;
|
|
739
|
+
changed = true;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
if (changed) {
|
|
743
|
+
tr.setNodeMarkup(pos, void 0, { ...node.attrs, html });
|
|
744
|
+
touched++;
|
|
745
|
+
}
|
|
746
|
+
});
|
|
747
|
+
if (!touched)
|
|
748
|
+
return 0;
|
|
749
|
+
tr.setMeta("addToHistory", false);
|
|
750
|
+
for (const [key, value] of Object.entries(options.meta ?? {}))
|
|
751
|
+
tr.setMeta(key, value);
|
|
752
|
+
editor.view.dispatch(tr);
|
|
753
|
+
return touched;
|
|
650
754
|
}
|
|
651
755
|
|
|
652
756
|
function h(tag, attrs = {}, children = []) {
|
|
@@ -1650,7 +1754,8 @@ function createMinutaEditor(element, opts) {
|
|
|
1650
1754
|
opts.onVariableClick?.({
|
|
1651
1755
|
variableId: detail.variableId,
|
|
1652
1756
|
parentBlockId: detail.parentBlockId ?? null,
|
|
1653
|
-
text: String(detail.text ?? "")
|
|
1757
|
+
text: String(detail.text ?? ""),
|
|
1758
|
+
kind: detail.kind === "image" || detail.kind === "missingImage" ? detail.kind : "text"
|
|
1654
1759
|
});
|
|
1655
1760
|
}
|
|
1656
1761
|
function variableTargetElement(variableId) {
|
|
@@ -1661,18 +1766,7 @@ function createMinutaEditor(element, opts) {
|
|
|
1661
1766
|
const img = sheet.querySelector(`img[data-variable-id="${id}"]`);
|
|
1662
1767
|
if (img)
|
|
1663
1768
|
return img;
|
|
1664
|
-
|
|
1665
|
-
if (!ed || ed.isDestroyed)
|
|
1666
|
-
return null;
|
|
1667
|
-
let found = null;
|
|
1668
|
-
ed.state.doc.descendants((node, pos) => {
|
|
1669
|
-
if (found || node.type.name !== "missingImage" || node.attrs.variableId !== variableId)
|
|
1670
|
-
return;
|
|
1671
|
-
const dom = ed.view.nodeDOM(pos);
|
|
1672
|
-
if (dom instanceof HTMLElement)
|
|
1673
|
-
found = dom;
|
|
1674
|
-
});
|
|
1675
|
-
return found;
|
|
1769
|
+
return sheet.querySelector(`.poc-missing-image [data-variable-id="${id}"]`);
|
|
1676
1770
|
}
|
|
1677
1771
|
function scrollToVariable(variableId) {
|
|
1678
1772
|
const chip = variableTargetElement(variableId);
|
|
@@ -1939,6 +2033,12 @@ function createMinutaEditor(element, opts) {
|
|
|
1939
2033
|
setVariableValue,
|
|
1940
2034
|
setVariableImage,
|
|
1941
2035
|
variablesInDocument,
|
|
2036
|
+
refreshVaultImages(resolveUrl) {
|
|
2037
|
+
const ed = tiptap;
|
|
2038
|
+
if (!ed || ed.isDestroyed)
|
|
2039
|
+
return Promise.resolve(0);
|
|
2040
|
+
return refreshVaultImages(ed, resolveUrl, { meta: { [POC_ASSET_SWAP]: true } });
|
|
2041
|
+
},
|
|
1942
2042
|
schedulePaginate,
|
|
1943
2043
|
refreshChrome,
|
|
1944
2044
|
totalPages: () => totalPages,
|
|
@@ -1958,4 +2058,4 @@ function createMinutaEditor(element, opts) {
|
|
|
1958
2058
|
return api;
|
|
1959
2059
|
}
|
|
1960
2060
|
|
|
1961
|
-
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, computePocBreaks, createMinutaEditor, decodeVaultAttr, escapeHtml, escapeVaultAttr, extractTemplateVariables, iconSvg, pocPageKey, renumberPocFootnotes, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, variableChipHtml, vaultImageHtml };
|
|
2061
|
+
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, computePocBreaks, createMinutaEditor, decodeVaultAttr, dispatchVariableClick, escapeHtml, escapeVaultAttr, extractTemplateVariables, iconSvg, pocPageKey, refreshVaultImages, renumberPocFootnotes, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, variableChipHtml, vaultImageHtml };
|
|
@@ -19,11 +19,15 @@ import { PluginKey, Plugin } from '@tiptap/pm/state';
|
|
|
19
19
|
* algoritmo sempre enxerga o fluxo "sem paginação" e converge (recomputar
|
|
20
20
|
* com chrome na tela produz os mesmos breaks → sem loop de layout).
|
|
21
21
|
*
|
|
22
|
-
* Regras de quebra:
|
|
23
|
-
* -
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
22
|
+
* Regras de quebra (as mesmas que o Word aplica ao refluir o documento):
|
|
23
|
+
* - a unidade é o bloco-FOLHA: parágrafo, título, ilha (imagem/lista/svg),
|
|
24
|
+
* linha de colunas, linha de tabela. Citação, container simples e lista
|
|
25
|
+
* real são só recipientes — a quebra entra neles e cai entre os filhos;
|
|
26
|
+
* - parágrafo parte entre linhas (viúvas/órfãs de 2 linhas), como no Word;
|
|
27
|
+
* - nó-folha mais alto que a página flui e as páginas internas são contadas,
|
|
28
|
+
* sem chrome no meio;
|
|
29
|
+
* - keep-with-next: título (h1–h4 ou parágrafo curto em negrito/caixa alta)
|
|
30
|
+
* não fica órfão no fim da página — a quebra sobe para antes dele.
|
|
27
31
|
*/
|
|
28
32
|
interface PocPageConfig {
|
|
29
33
|
pageHeight: number;
|
|
@@ -74,6 +78,13 @@ interface PocPageBreak {
|
|
|
74
78
|
* Word quebra naturalmente, e o preview só antecipa onde.
|
|
75
79
|
*/
|
|
76
80
|
soft?: boolean;
|
|
81
|
+
/**
|
|
82
|
+
* quebra pedida pelo TEMPLATE (parágrafo-marcador "PAGEBREAK"). É a única
|
|
83
|
+
* que vira pageBreakBefore no DOCX: as demais são só a previsão do preview
|
|
84
|
+
* de onde o Word vai quebrar, e o Word decide sozinho — forçá-las deixava
|
|
85
|
+
* o pé da página vazio sempre que ele media o conteúdo diferente daqui.
|
|
86
|
+
*/
|
|
87
|
+
manual?: boolean;
|
|
77
88
|
/** notas cujos marcadores estão nesta página — desenhadas acima do rodapé */
|
|
78
89
|
notes?: PocPageNote[];
|
|
79
90
|
/** altura reservada pelas notas (já descontada do filler) */
|
|
@@ -100,6 +111,14 @@ declare function buildPocHeaderEl(cfg: PocPageConfig): HTMLElement;
|
|
|
100
111
|
declare function buildPocFooterEl(cfg: PocPageConfig, pageNo: number, total: number): HTMLElement;
|
|
101
112
|
/** área de notas de rodapé: filete + notas, no pé da área útil (como no Word) */
|
|
102
113
|
declare function buildPocNotesEl(notes: PocPageNote[]): HTMLElement;
|
|
114
|
+
/**
|
|
115
|
+
* O bloco é um título, para efeito de keep-with-next? h1–h4, ou um parágrafo
|
|
116
|
+
* de UMA linha, curto, todo em negrito ou em caixa alta — é assim que os
|
|
117
|
+
* templates marcam seções ("PRELIMINARMENTE", "DO MÉRITO"): com `<p>`
|
|
118
|
+
* estilizado, não com heading. O export usa a mesma régua para pedir ao Word
|
|
119
|
+
* que mantenha o título junto do parágrafo seguinte (keepNext).
|
|
120
|
+
*/
|
|
121
|
+
declare function pocLooksLikeTitle(dom: HTMLElement): boolean;
|
|
103
122
|
declare function computePocBreaks(view: EditorView, cfg: PocPageConfig, sheet: HTMLElement): {
|
|
104
123
|
breaks: PocPageBreak[];
|
|
105
124
|
total: number;
|
|
@@ -109,6 +128,13 @@ declare function computePocBreaks(view: EditorView, cfg: PocPageConfig, sheet: H
|
|
|
109
128
|
}[];
|
|
110
129
|
lastNotes: PocPageNote[];
|
|
111
130
|
};
|
|
131
|
+
/**
|
|
132
|
+
* O nó é só um RECIPIENTE para a paginação — a quebra entra nele e cai entre
|
|
133
|
+
* os filhos? Citação, lista real, tabela (entre linhas) e container simples
|
|
134
|
+
* sem borda nem fundo. Linha de colunas e caixa pintada (borda/fundo) são
|
|
135
|
+
* unidades visuais: partem só se forem mais altas que a página.
|
|
136
|
+
*/
|
|
137
|
+
declare function pocDescendsInto(node: Node): boolean;
|
|
112
138
|
declare function isPocFlexRow(node: Node): boolean;
|
|
113
139
|
/** conteúdo visível = texto, imagem com src preenchido ou svg (imgs vazias do pipeline não contam) */
|
|
114
140
|
declare function pocNodeHasVisibleContent(node: Node): boolean;
|
|
@@ -116,7 +142,7 @@ declare function pocNodeHasVisibleContent(node: Node): boolean;
|
|
|
116
142
|
* A célula/linha PINTA alguma coisa (borda ou fundo)?
|
|
117
143
|
*
|
|
118
144
|
* Uma coluna sem texto mas com borda não é espaço sobrando: é estrutura. A
|
|
119
|
-
* folha de rosto
|
|
145
|
+
* folha de rosto de um template desenha uma timeline com `border-right` numa
|
|
120
146
|
* coluna VAZIA (o eixo central) e `border-bottom` alternando entre as duas —
|
|
121
147
|
* colapsar a coluna "vazia" apaga o eixo e centraliza o que devia ficar
|
|
122
148
|
* alternando esquerda/direita.
|
|
@@ -162,5 +188,5 @@ declare function pocExportDocx(editor: Editor, margins: {
|
|
|
162
188
|
left: number;
|
|
163
189
|
}, chrome?: PocDocxChrome, options?: PocDocxExportOptions): Promise<Blob>;
|
|
164
190
|
|
|
165
|
-
export { PAGINATE_META as e, pocChromeFlowHeight as f, buildPocHeaderEl as g, buildPocFooterEl as h, isPocChromeCanvas as i, buildPocNotesEl as j,
|
|
166
|
-
export type { PocPageConfig as P, PocDocxChrome as a, PocDocxExportOptions as b, PocPageNote as c, PocPageBreak as d, PocLoneRow as
|
|
191
|
+
export { PAGINATE_META as e, pocChromeFlowHeight as f, buildPocHeaderEl as g, buildPocFooterEl as h, isPocChromeCanvas as i, buildPocNotesEl as j, pocLooksLikeTitle as k, computePocBreaks as l, pocDescendsInto as m, isPocFlexRow as n, pocNodeHasVisibleContent as o, pocPageKey as p, pocNodePaintsBox as q, pocLoneCellIndex as r, computePocLoneRows as t, breaksEqual as u, PocPaginationPlugin as v, pocExportDocx as w };
|
|
192
|
+
export type { PocPageConfig as P, PocDocxChrome as a, PocDocxExportOptions as b, PocPageNote as c, PocPageBreak as d, PocLoneRow as s };
|
|
@@ -19,11 +19,15 @@ import { PluginKey, Plugin } from '@tiptap/pm/state';
|
|
|
19
19
|
* algoritmo sempre enxerga o fluxo "sem paginação" e converge (recomputar
|
|
20
20
|
* com chrome na tela produz os mesmos breaks → sem loop de layout).
|
|
21
21
|
*
|
|
22
|
-
* Regras de quebra:
|
|
23
|
-
* -
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
22
|
+
* Regras de quebra (as mesmas que o Word aplica ao refluir o documento):
|
|
23
|
+
* - a unidade é o bloco-FOLHA: parágrafo, título, ilha (imagem/lista/svg),
|
|
24
|
+
* linha de colunas, linha de tabela. Citação, container simples e lista
|
|
25
|
+
* real são só recipientes — a quebra entra neles e cai entre os filhos;
|
|
26
|
+
* - parágrafo parte entre linhas (viúvas/órfãs de 2 linhas), como no Word;
|
|
27
|
+
* - nó-folha mais alto que a página flui e as páginas internas são contadas,
|
|
28
|
+
* sem chrome no meio;
|
|
29
|
+
* - keep-with-next: título (h1–h4 ou parágrafo curto em negrito/caixa alta)
|
|
30
|
+
* não fica órfão no fim da página — a quebra sobe para antes dele.
|
|
27
31
|
*/
|
|
28
32
|
interface PocPageConfig {
|
|
29
33
|
pageHeight: number;
|
|
@@ -74,6 +78,13 @@ interface PocPageBreak {
|
|
|
74
78
|
* Word quebra naturalmente, e o preview só antecipa onde.
|
|
75
79
|
*/
|
|
76
80
|
soft?: boolean;
|
|
81
|
+
/**
|
|
82
|
+
* quebra pedida pelo TEMPLATE (parágrafo-marcador "PAGEBREAK"). É a única
|
|
83
|
+
* que vira pageBreakBefore no DOCX: as demais são só a previsão do preview
|
|
84
|
+
* de onde o Word vai quebrar, e o Word decide sozinho — forçá-las deixava
|
|
85
|
+
* o pé da página vazio sempre que ele media o conteúdo diferente daqui.
|
|
86
|
+
*/
|
|
87
|
+
manual?: boolean;
|
|
77
88
|
/** notas cujos marcadores estão nesta página — desenhadas acima do rodapé */
|
|
78
89
|
notes?: PocPageNote[];
|
|
79
90
|
/** altura reservada pelas notas (já descontada do filler) */
|
|
@@ -100,6 +111,14 @@ declare function buildPocHeaderEl(cfg: PocPageConfig): HTMLElement;
|
|
|
100
111
|
declare function buildPocFooterEl(cfg: PocPageConfig, pageNo: number, total: number): HTMLElement;
|
|
101
112
|
/** área de notas de rodapé: filete + notas, no pé da área útil (como no Word) */
|
|
102
113
|
declare function buildPocNotesEl(notes: PocPageNote[]): HTMLElement;
|
|
114
|
+
/**
|
|
115
|
+
* O bloco é um título, para efeito de keep-with-next? h1–h4, ou um parágrafo
|
|
116
|
+
* de UMA linha, curto, todo em negrito ou em caixa alta — é assim que os
|
|
117
|
+
* templates marcam seções ("PRELIMINARMENTE", "DO MÉRITO"): com `<p>`
|
|
118
|
+
* estilizado, não com heading. O export usa a mesma régua para pedir ao Word
|
|
119
|
+
* que mantenha o título junto do parágrafo seguinte (keepNext).
|
|
120
|
+
*/
|
|
121
|
+
declare function pocLooksLikeTitle(dom: HTMLElement): boolean;
|
|
103
122
|
declare function computePocBreaks(view: EditorView, cfg: PocPageConfig, sheet: HTMLElement): {
|
|
104
123
|
breaks: PocPageBreak[];
|
|
105
124
|
total: number;
|
|
@@ -109,6 +128,13 @@ declare function computePocBreaks(view: EditorView, cfg: PocPageConfig, sheet: H
|
|
|
109
128
|
}[];
|
|
110
129
|
lastNotes: PocPageNote[];
|
|
111
130
|
};
|
|
131
|
+
/**
|
|
132
|
+
* O nó é só um RECIPIENTE para a paginação — a quebra entra nele e cai entre
|
|
133
|
+
* os filhos? Citação, lista real, tabela (entre linhas) e container simples
|
|
134
|
+
* sem borda nem fundo. Linha de colunas e caixa pintada (borda/fundo) são
|
|
135
|
+
* unidades visuais: partem só se forem mais altas que a página.
|
|
136
|
+
*/
|
|
137
|
+
declare function pocDescendsInto(node: Node): boolean;
|
|
112
138
|
declare function isPocFlexRow(node: Node): boolean;
|
|
113
139
|
/** conteúdo visível = texto, imagem com src preenchido ou svg (imgs vazias do pipeline não contam) */
|
|
114
140
|
declare function pocNodeHasVisibleContent(node: Node): boolean;
|
|
@@ -116,7 +142,7 @@ declare function pocNodeHasVisibleContent(node: Node): boolean;
|
|
|
116
142
|
* A célula/linha PINTA alguma coisa (borda ou fundo)?
|
|
117
143
|
*
|
|
118
144
|
* Uma coluna sem texto mas com borda não é espaço sobrando: é estrutura. A
|
|
119
|
-
* folha de rosto
|
|
145
|
+
* folha de rosto de um template desenha uma timeline com `border-right` numa
|
|
120
146
|
* coluna VAZIA (o eixo central) e `border-bottom` alternando entre as duas —
|
|
121
147
|
* colapsar a coluna "vazia" apaga o eixo e centraliza o que devia ficar
|
|
122
148
|
* alternando esquerda/direita.
|
|
@@ -162,5 +188,5 @@ declare function pocExportDocx(editor: Editor, margins: {
|
|
|
162
188
|
left: number;
|
|
163
189
|
}, chrome?: PocDocxChrome, options?: PocDocxExportOptions): Promise<Blob>;
|
|
164
190
|
|
|
165
|
-
export { PAGINATE_META as e, pocChromeFlowHeight as f, buildPocHeaderEl as g, buildPocFooterEl as h, isPocChromeCanvas as i, buildPocNotesEl as j,
|
|
166
|
-
export type { PocPageConfig as P, PocDocxChrome as a, PocDocxExportOptions as b, PocPageNote as c, PocPageBreak as d, PocLoneRow as
|
|
191
|
+
export { PAGINATE_META as e, pocChromeFlowHeight as f, buildPocHeaderEl as g, buildPocFooterEl as h, isPocChromeCanvas as i, buildPocNotesEl as j, pocLooksLikeTitle as k, computePocBreaks as l, pocDescendsInto as m, isPocFlexRow as n, pocNodeHasVisibleContent as o, pocPageKey as p, pocNodePaintsBox as q, pocLoneCellIndex as r, computePocLoneRows as t, breaksEqual as u, PocPaginationPlugin as v, pocExportDocx as w };
|
|
192
|
+
export type { PocPageConfig as P, PocDocxChrome as a, PocDocxExportOptions as b, PocPageNote as c, PocPageBreak as d, PocLoneRow as s };
|