@meistrari/minuta-editor 1.2.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 +2 -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 +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +2 -2
- 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/README.md
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
O editor de minuta do **defesa.ai** sem framework: a folha A4 paginada de
|
|
4
4
|
verdade, edição rica, cabeçalho/rodapé, placeholders de variável e export
|
|
5
|
-
DOCX
|
|
5
|
+
DOCX que reflui no Word como na folha (só a quebra manual do template é
|
|
6
|
+
forçada; título leva keep-with-next). Monta em qualquer app —
|
|
6
7
|
React, Vue, Svelte, vanilla — com uma chamada:
|
|
7
8
|
|
|
8
9
|
```ts
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { f as footnoteHtmlToRuns, p as pocLoneCellIndex } from '../shared/minuta-editor.
|
|
2
|
-
import { BorderStyle, TextRun, ExternalHyperlink, Paragraph, Document, Header, Packer, AlignmentType,
|
|
1
|
+
import { f as footnoteHtmlToRuns, p as pocLoneCellIndex, a as pocLooksLikeTitle } from '../shared/minuta-editor.d9d0c0ce.mjs';
|
|
2
|
+
import { BorderStyle, TextRun, ExternalHyperlink, Paragraph, Document, Header, Packer, AlignmentType, 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
|
|
|
@@ -117,7 +117,7 @@ function measureEl(el) {
|
|
|
117
117
|
// Piso = 1.0em: protege o caso patológico (0.7em) SEM inflar entrelinha
|
|
118
118
|
// justa (1.0em, comum em citações) — com 1.15em o export ficava mais
|
|
119
119
|
// alto que o preview mediu, o conteúdo derramava no Word e a quebra
|
|
120
|
-
// explícita seguinte abria página quase vazia
|
|
120
|
+
// explícita seguinte abria página quase vazia.
|
|
121
121
|
lineExactTw: lineHpx && Number.isFinite(lineHpx) ? Math.round(Math.max(lineHpx, fontPx) * PX_TO_TWIP) : null,
|
|
122
122
|
afterTw: Math.round((Number.parseFloat(cs.marginBottom) || 0) * PX_TO_TWIP),
|
|
123
123
|
beforeTw: Math.round((Number.parseFloat(cs.marginTop) || 0) * PX_TO_TWIP),
|
|
@@ -257,7 +257,7 @@ function domInlineToRuns(root, fallback = {}) {
|
|
|
257
257
|
runs.push(new TextRun({
|
|
258
258
|
text,
|
|
259
259
|
// sem rFonts o run cai no default Arial do Document — a fonte
|
|
260
|
-
// REAL do preview (ex.: Calibri
|
|
260
|
+
// REAL do preview (ex.: Calibri) tem que viajar no run
|
|
261
261
|
font: primaryFont(cs) ?? fallback.font,
|
|
262
262
|
size: Math.round((Number.parseFloat(cs.fontSize) || 16) / PX_PER_PT * 2),
|
|
263
263
|
color: cssColorToHex(cs.color) ?? fallback.color,
|
|
@@ -328,6 +328,7 @@ function textBlockToParagraph(node, pos, ctx, opts = {}) {
|
|
|
328
328
|
spacing.before = Math.max(0, spacing.before - ctx.lastAfterTw);
|
|
329
329
|
ctx.lastAfterTw = spacing.after ?? 0;
|
|
330
330
|
const runs = inlineToRuns(node, base, ctx);
|
|
331
|
+
const keepNext = Boolean(opts.heading || m && pocLooksLikeTitle(m.el)) || void 0;
|
|
331
332
|
const paragraph = new Paragraph({
|
|
332
333
|
children: runs,
|
|
333
334
|
// sem alinhamento explícito, corpo de peça vai justificado (o Word
|
|
@@ -336,7 +337,8 @@ function textBlockToParagraph(node, pos, ctx, opts = {}) {
|
|
|
336
337
|
spacing,
|
|
337
338
|
indent: total ? { left: total } : void 0,
|
|
338
339
|
heading: opts.heading ? headingLevelFor(opts.heading) : void 0,
|
|
339
|
-
pageBreakBefore: breakBefore
|
|
340
|
+
pageBreakBefore: breakBefore,
|
|
341
|
+
keepNext
|
|
340
342
|
});
|
|
341
343
|
ctx.meta.set(paragraph, { spacer: runs.length === 0 && !opts.heading, breakBefore });
|
|
342
344
|
return paragraph;
|
|
@@ -703,7 +705,7 @@ function collectImageIslands(node, pos) {
|
|
|
703
705
|
}
|
|
704
706
|
return out.length ? out : null;
|
|
705
707
|
}
|
|
706
|
-
async function
|
|
708
|
+
async function inlineImagesParagraphs(islands, innerPx, ctx) {
|
|
707
709
|
const GAP_PX = 8;
|
|
708
710
|
const items = [];
|
|
709
711
|
for (const { node, pos } of islands) {
|
|
@@ -711,27 +713,41 @@ async function inlineImagesParagraph(islands, innerPx, ctx) {
|
|
|
711
713
|
const src = await srcToDataUrl(img.getAttribute("src") || "");
|
|
712
714
|
if (!src)
|
|
713
715
|
continue;
|
|
714
|
-
const
|
|
716
|
+
const islandEl = domAt(ctx, pos);
|
|
717
|
+
const live = islandEl?.querySelector("img");
|
|
715
718
|
const styleW = Number.parseFloat(getProp(img.getAttribute("style"), "width") ?? "");
|
|
716
719
|
const widthPx = live?.offsetWidth || 0 || (Number.isFinite(styleW) && styleW > 0 ? styleW : 0) || Math.min(innerPx, 200);
|
|
717
|
-
|
|
720
|
+
const zoom = islandEl ? zoomFactor(islandEl) : 1;
|
|
721
|
+
const top = islandEl ? islandEl.getBoundingClientRect().top / zoom : Number.NaN;
|
|
722
|
+
items.push({ src, widthPx, top });
|
|
718
723
|
}
|
|
719
724
|
if (!items.length)
|
|
720
|
-
return
|
|
721
|
-
const
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
725
|
+
return [];
|
|
726
|
+
const lines = [];
|
|
727
|
+
for (const item of items) {
|
|
728
|
+
const line = lines[lines.length - 1];
|
|
729
|
+
if (line && (Number.isNaN(item.top) || Number.isNaN(line[0].top) || Math.abs(item.top - line[0].top) <= 8))
|
|
730
|
+
line.push(item);
|
|
731
|
+
else
|
|
732
|
+
lines.push([item]);
|
|
733
|
+
}
|
|
734
|
+
const paragraphs = [];
|
|
735
|
+
for (const line of lines) {
|
|
736
|
+
const total = line.reduce((a, b) => a + b.widthPx, 0) + GAP_PX * (line.length - 1);
|
|
737
|
+
const scale = innerPx > 0 && total > innerPx ? (innerPx - GAP_PX * (line.length - 1)) / (total - GAP_PX * (line.length - 1)) : 1;
|
|
738
|
+
const runs = [];
|
|
739
|
+
for (const item of line) {
|
|
740
|
+
const run = await dataUrlToImageRun(item.src, Math.max(1, Math.round(item.widthPx * scale)));
|
|
741
|
+
if (!run)
|
|
742
|
+
continue;
|
|
743
|
+
if (runs.length)
|
|
744
|
+
runs.push(new TextRun({ text: " " }));
|
|
745
|
+
runs.push(run);
|
|
746
|
+
}
|
|
728
747
|
if (runs.length)
|
|
729
|
-
|
|
730
|
-
runs.push(run);
|
|
748
|
+
paragraphs.push(new Paragraph({ children: runs, alignment: AlignmentType.CENTER, spacing: { after: 0, before: 0 } }));
|
|
731
749
|
}
|
|
732
|
-
|
|
733
|
-
return null;
|
|
734
|
-
return new Paragraph({ children: runs, alignment: AlignmentType.CENTER, spacing: { after: 0, before: 0 } });
|
|
750
|
+
return paragraphs;
|
|
735
751
|
}
|
|
736
752
|
async function tableToDocx(node, pos, contentWidthPx, ctx) {
|
|
737
753
|
const tableDomRaw = domAt(ctx, pos);
|
|
@@ -785,9 +801,7 @@ async function tableToDocx(node, pos, contentWidthPx, ctx) {
|
|
|
785
801
|
endPos += next.nodeSize;
|
|
786
802
|
end++;
|
|
787
803
|
}
|
|
788
|
-
|
|
789
|
-
if (para)
|
|
790
|
-
cellContent.push(para);
|
|
804
|
+
cellContent.push(...await inlineImagesParagraphs(islands, cellInnerPx, cellCtx));
|
|
791
805
|
childPos = endPos;
|
|
792
806
|
k = end - 1;
|
|
793
807
|
continue;
|
|
@@ -937,9 +951,8 @@ async function nodeToDocx(node, pos, contentWidthPx, ctx) {
|
|
|
937
951
|
}
|
|
938
952
|
case "paragraph": {
|
|
939
953
|
if (node.textContent.trim() === "PAGEBREAK") {
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
return [new Paragraph({ children: [new PageBreak()] })];
|
|
954
|
+
ctx.pending.breakBefore = true;
|
|
955
|
+
return [];
|
|
943
956
|
}
|
|
944
957
|
return [textBlockToParagraph(node, pos, ctx)];
|
|
945
958
|
}
|
|
@@ -1303,11 +1316,13 @@ async function pocExportDocx(editor, margins, chrome, options = {}) {
|
|
|
1303
1316
|
const doc = editor.state.doc;
|
|
1304
1317
|
const ctx = {
|
|
1305
1318
|
view: editor.view,
|
|
1306
|
-
//
|
|
1307
|
-
//
|
|
1308
|
-
//
|
|
1309
|
-
//
|
|
1310
|
-
|
|
1319
|
+
// só a quebra pedida pelo template vira pageBreakBefore. As demais
|
|
1320
|
+
// (entre blocos ou entre linhas de um parágrafo) ficam por conta do
|
|
1321
|
+
// Word: ele parte parágrafo, lista e tabela sozinho e empurra imagem
|
|
1322
|
+
// só quando ela de fato não cabe na página DELE. Forçar a quebra do
|
|
1323
|
+
// preview deixava o arquivo com o pé da página vazio sempre que o
|
|
1324
|
+
// Word cabia mais (ou menos) texto que o browser.
|
|
1325
|
+
breakSet: new Set((options.breaks ?? []).filter((b) => b.manual).map((b) => b.pos)),
|
|
1311
1326
|
pending: { breakBefore: false },
|
|
1312
1327
|
lastAfterTw: 0,
|
|
1313
1328
|
meta: /* @__PURE__ */ new WeakMap(),
|
package/dist/docx.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { a as PocDocxChrome, b as PocDocxExportOptions,
|
|
1
|
+
export { a as PocDocxChrome, b as PocDocxExportOptions, w as pocExportDocx } from './shared/minuta-editor.9e65d163.mjs';
|
|
2
2
|
import '@tiptap/core';
|
|
3
3
|
import '@tiptap/pm/model';
|
|
4
4
|
import '@tiptap/pm/view';
|
package/dist/docx.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { a as PocDocxChrome, b as PocDocxExportOptions,
|
|
1
|
+
export { a as PocDocxChrome, b as PocDocxExportOptions, w as pocExportDocx } from './shared/minuta-editor.9e65d163.js';
|
|
2
2
|
import '@tiptap/core';
|
|
3
3
|
import '@tiptap/pm/model';
|
|
4
4
|
import '@tiptap/pm/view';
|
package/dist/docx.mjs
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
/// <reference types="@tiptap/extension-bubble-menu" />
|
|
20
20
|
import { Node, Editor, Mark, Extension } from '@tiptap/core';
|
|
21
21
|
import { EditorView } from '@tiptap/pm/view';
|
|
22
|
-
import { P as PocPageConfig } from './shared/minuta-editor.
|
|
23
|
-
export { e as PAGINATE_META, a as PocDocxChrome, b as PocDocxExportOptions,
|
|
22
|
+
import { P as PocPageConfig } from './shared/minuta-editor.9e65d163.mjs';
|
|
23
|
+
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
24
|
import '@tiptap/pm/model';
|
|
25
25
|
import '@tiptap/pm/state';
|
|
26
26
|
|
package/dist/index.d.ts
CHANGED
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
/// <reference types="@tiptap/extension-bubble-menu" />
|
|
20
20
|
import { Node, Editor, Mark, Extension } from '@tiptap/core';
|
|
21
21
|
import { EditorView } from '@tiptap/pm/view';
|
|
22
|
-
import { P as PocPageConfig } from './shared/minuta-editor.
|
|
23
|
-
export { e as PAGINATE_META, a as PocDocxChrome, b as PocDocxExportOptions,
|
|
22
|
+
import { P as PocPageConfig } from './shared/minuta-editor.9e65d163.js';
|
|
23
|
+
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
24
|
import '@tiptap/pm/model';
|
|
25
25
|
import '@tiptap/pm/state';
|
|
26
26
|
|
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";
|
|
@@ -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 };
|
|
@@ -223,7 +223,7 @@ function chromeContentEl(html, cfg) {
|
|
|
223
223
|
if (isPocChromeCanvas(clean)) {
|
|
224
224
|
const canvas = document.createElement("div");
|
|
225
225
|
canvas.className = "poc-chrome-canvas";
|
|
226
|
-
canvas.style.cssText = `position:absolute;top:0;left
|
|
226
|
+
canvas.style.cssText = `position:absolute;top:0;left:0;width:794px;height:100%;pointer-events:none;`;
|
|
227
227
|
canvas.innerHTML = clean;
|
|
228
228
|
return canvas;
|
|
229
229
|
}
|
|
@@ -237,6 +237,7 @@ function buildPocHeaderEl(cfg) {
|
|
|
237
237
|
header.className = "poc-page-headerarea";
|
|
238
238
|
header.style.height = `${cfg.margins.top}px`;
|
|
239
239
|
header.style.position = "relative";
|
|
240
|
+
padToMargins(header, cfg);
|
|
240
241
|
header.style.justifyContent = cfg.headerPosition === "center" ? "center" : cfg.headerPosition === "right" ? "flex-end" : "flex-start";
|
|
241
242
|
header.title = "Clique para editar o cabe\xE7alho";
|
|
242
243
|
header.addEventListener("click", editHint("header"));
|
|
@@ -250,7 +251,7 @@ function buildPocHeaderEl(cfg) {
|
|
|
250
251
|
img.style.display = "inline-block";
|
|
251
252
|
header.appendChild(img);
|
|
252
253
|
}
|
|
253
|
-
const content = chromeContentEl(cfg.headerText
|
|
254
|
+
const content = chromeContentEl(cfg.headerText);
|
|
254
255
|
if (content.className === "poc-chrome-text" && !content.innerHTML && !cfg.headerLogoUrl)
|
|
255
256
|
content.innerHTML = " ";
|
|
256
257
|
header.appendChild(content);
|
|
@@ -261,10 +262,11 @@ function buildPocFooterEl(cfg, pageNo, total) {
|
|
|
261
262
|
footer.className = "poc-page-footerarea";
|
|
262
263
|
footer.style.height = `${cfg.margins.bottom}px`;
|
|
263
264
|
footer.style.position = "relative";
|
|
265
|
+
padToMargins(footer, cfg);
|
|
264
266
|
footer.title = "Clique para editar o rodap\xE9";
|
|
265
267
|
footer.addEventListener("click", editHint("footer"));
|
|
266
268
|
const showCustom = !(cfg.footerScope === "first" && pageNo !== 1);
|
|
267
|
-
const custom = showCustom ? chromeContentEl(cfg.footerText
|
|
269
|
+
const custom = showCustom ? chromeContentEl(cfg.footerText) : document.createElement("div");
|
|
268
270
|
if (!showCustom)
|
|
269
271
|
custom.className = "poc-chrome-text";
|
|
270
272
|
footer.appendChild(custom);
|
|
@@ -290,26 +292,81 @@ function buildPocNotesEl(notes) {
|
|
|
290
292
|
}
|
|
291
293
|
return box;
|
|
292
294
|
}
|
|
295
|
+
function padToMargins(el, cfg) {
|
|
296
|
+
el.style.boxSizing = "border-box";
|
|
297
|
+
el.style.paddingLeft = `${cfg.margins.left}px`;
|
|
298
|
+
el.style.paddingRight = `${cfg.margins.right}px`;
|
|
299
|
+
}
|
|
293
300
|
function buildChrome(cfg, brk, total) {
|
|
294
301
|
const chrome = document.createElement("div");
|
|
295
302
|
chrome.className = "poc-page-chrome";
|
|
296
303
|
chrome.contentEditable = "false";
|
|
297
304
|
chrome.style.height = `${brk.filler + (brk.notesH ?? 0) + pocChromeFlowHeight(cfg)}px`;
|
|
305
|
+
chrome.style.boxSizing = "border-box";
|
|
306
|
+
chrome.style.width = `calc(100% + ${cfg.margins.left + cfg.margins.right}px)`;
|
|
307
|
+
chrome.style.marginLeft = `-${cfg.margins.left}px`;
|
|
298
308
|
const filler = document.createElement("div");
|
|
299
309
|
filler.style.height = `${brk.filler}px`;
|
|
300
310
|
chrome.appendChild(filler);
|
|
301
|
-
if (brk.notes?.length)
|
|
302
|
-
|
|
311
|
+
if (brk.notes?.length) {
|
|
312
|
+
const notes = buildPocNotesEl(brk.notes);
|
|
313
|
+
padToMargins(notes, cfg);
|
|
314
|
+
chrome.appendChild(notes);
|
|
315
|
+
}
|
|
303
316
|
chrome.appendChild(buildPocFooterEl(cfg, brk.pageNo, total));
|
|
304
317
|
const band = document.createElement("div");
|
|
305
318
|
band.className = "poc-page-gapband";
|
|
306
319
|
band.style.height = `${cfg.gap}px`;
|
|
307
|
-
band.style.marginLeft = `-${cfg.margins.left}px`;
|
|
308
|
-
band.style.marginRight = `-${cfg.margins.right}px`;
|
|
309
320
|
chrome.appendChild(band);
|
|
310
321
|
chrome.appendChild(buildPocHeaderEl(cfg));
|
|
322
|
+
queueMicrotask(() => alignChromeToSheet(chrome));
|
|
311
323
|
return chrome;
|
|
312
324
|
}
|
|
325
|
+
function alignChromeToSheet(chrome) {
|
|
326
|
+
if (!chrome.isConnected)
|
|
327
|
+
return;
|
|
328
|
+
const sheet = chrome.closest(".poc-sheet");
|
|
329
|
+
if (!sheet)
|
|
330
|
+
return;
|
|
331
|
+
const currentMl = Number.parseFloat(chrome.style.marginLeft) || 0;
|
|
332
|
+
const naturalLeft = absLeft(chrome, sheet) - currentMl;
|
|
333
|
+
const ml = -naturalLeft;
|
|
334
|
+
if (Math.abs(ml - currentMl) > 0.5)
|
|
335
|
+
chrome.style.marginLeft = `${ml}px`;
|
|
336
|
+
chrome.style.width = `${sheet.clientWidth}px`;
|
|
337
|
+
}
|
|
338
|
+
function buildChromeWidget(view, cfg, brk, total) {
|
|
339
|
+
const chrome = buildChrome(cfg, brk, total);
|
|
340
|
+
let table = null;
|
|
341
|
+
try {
|
|
342
|
+
const parent = view.state.doc.resolve(brk.pos).parent;
|
|
343
|
+
if (parent.type.name === "table")
|
|
344
|
+
table = parent;
|
|
345
|
+
} catch {
|
|
346
|
+
table = null;
|
|
347
|
+
}
|
|
348
|
+
if (!table)
|
|
349
|
+
return chrome;
|
|
350
|
+
let cols = 0;
|
|
351
|
+
table.firstChild?.forEach((cell2) => {
|
|
352
|
+
cols += Math.max(1, Number(cell2.attrs.colspan) || 1);
|
|
353
|
+
});
|
|
354
|
+
const row = document.createElement("tr");
|
|
355
|
+
row.className = "poc-page-chrome-row";
|
|
356
|
+
row.contentEditable = "false";
|
|
357
|
+
const cell = document.createElement("td");
|
|
358
|
+
cell.className = "poc-page-chrome-cell";
|
|
359
|
+
cell.colSpan = Math.max(1, cols);
|
|
360
|
+
cell.appendChild(chrome);
|
|
361
|
+
row.appendChild(cell);
|
|
362
|
+
return row;
|
|
363
|
+
}
|
|
364
|
+
function pocChromeHeightInside(el) {
|
|
365
|
+
let sum = 0;
|
|
366
|
+
for (const chrome of el.querySelectorAll(".poc-page-chrome"))
|
|
367
|
+
sum += chrome.offsetHeight;
|
|
368
|
+
return sum;
|
|
369
|
+
}
|
|
313
370
|
function absTop(el, sheet) {
|
|
314
371
|
let top = 0;
|
|
315
372
|
let node = el;
|
|
@@ -319,7 +376,35 @@ function absTop(el, sheet) {
|
|
|
319
376
|
}
|
|
320
377
|
return top;
|
|
321
378
|
}
|
|
379
|
+
function absLeft(el, sheet) {
|
|
380
|
+
let left = 0;
|
|
381
|
+
let node = el;
|
|
382
|
+
while (node && node !== sheet) {
|
|
383
|
+
left += node.offsetLeft;
|
|
384
|
+
node = node.offsetParent;
|
|
385
|
+
}
|
|
386
|
+
return left;
|
|
387
|
+
}
|
|
322
388
|
const HEADING_TAGS = /* @__PURE__ */ new Set(["H1", "H2", "H3", "H4"]);
|
|
389
|
+
function pocLooksLikeTitle(dom) {
|
|
390
|
+
if (HEADING_TAGS.has(dom.tagName))
|
|
391
|
+
return true;
|
|
392
|
+
if (dom.tagName !== "P")
|
|
393
|
+
return false;
|
|
394
|
+
const text = (dom.textContent || "").trim();
|
|
395
|
+
if (!text || text.length > 120)
|
|
396
|
+
return false;
|
|
397
|
+
const cs = getComputedStyle(dom);
|
|
398
|
+
const fontPx = Number.parseFloat(cs.fontSize) || 16;
|
|
399
|
+
const lineHpx = cs.lineHeight === "normal" ? fontPx * 1.3 : Number.parseFloat(cs.lineHeight) || fontPx * 1.3;
|
|
400
|
+
if (dom.offsetHeight > lineHpx * 1.6)
|
|
401
|
+
return false;
|
|
402
|
+
const boldChars = Array.from(dom.querySelectorAll("b, strong")).reduce((n, el) => n + (el.textContent || "").trim().length, 0);
|
|
403
|
+
const bold = (Number.parseInt(cs.fontWeight) || 400) >= 600 || boldChars >= text.length * 0.9;
|
|
404
|
+
const letters = text.replace(/[^\p{L}]/gu, "");
|
|
405
|
+
const upper = cs.textTransform === "uppercase" || letters.length >= 4 && letters === letters.toUpperCase();
|
|
406
|
+
return bold || upper;
|
|
407
|
+
}
|
|
323
408
|
const SPLITTABLE_TAGS = /* @__PURE__ */ new Set(["P"]);
|
|
324
409
|
const MIN_LINES_PER_SIDE = 2;
|
|
325
410
|
function findInlineSplit(view, dom, availablePx, fromLine = 0, minHead = MIN_LINES_PER_SIDE, minTail = MIN_LINES_PER_SIDE) {
|
|
@@ -333,21 +418,28 @@ function findInlineSplit(view, dom, availablePx, fromLine = 0, minHead = MIN_LIN
|
|
|
333
418
|
} catch {
|
|
334
419
|
return null;
|
|
335
420
|
}
|
|
336
|
-
|
|
421
|
+
const chromes = Array.from(dom.querySelectorAll(".poc-page-chrome")).map((c) => c.getBoundingClientRect()).filter((r) => r.height > 0);
|
|
422
|
+
const insideChrome = (r) => chromes.some((c) => r.top >= c.top - 0.5 && r.bottom <= c.bottom + 0.5);
|
|
423
|
+
const chromeAbove = (top) => chromes.reduce((sum, c) => sum + (c.top < top ? c.height : 0), 0);
|
|
424
|
+
const flowRects = rects.filter((r) => !insideChrome(r)).map((r) => ({ top: r.top - chromeAbove(r.top), bottom: r.bottom - chromeAbove(r.top), left: r.left, liveTop: r.top, liveBottom: r.bottom }));
|
|
425
|
+
if (flowRects.length < minHead + minTail)
|
|
337
426
|
return null;
|
|
338
427
|
const lines = [];
|
|
339
|
-
for (const r of
|
|
428
|
+
for (const r of flowRects) {
|
|
340
429
|
const last2 = lines[lines.length - 1];
|
|
341
430
|
if (last2 && r.top < last2.bottom - 1) {
|
|
342
431
|
last2.bottom = Math.max(last2.bottom, r.bottom);
|
|
432
|
+
last2.liveBottom = Math.max(last2.liveBottom, r.liveBottom);
|
|
343
433
|
last2.left = Math.min(last2.left, r.left);
|
|
344
434
|
} else {
|
|
345
|
-
lines.push({ top: r.top, bottom: r.bottom, left: r.left });
|
|
435
|
+
lines.push({ top: r.top, bottom: r.bottom, left: r.left, liveTop: r.liveTop, liveBottom: r.liveBottom });
|
|
346
436
|
}
|
|
347
437
|
}
|
|
348
438
|
if (lines.length < minHead + minTail)
|
|
349
439
|
return null;
|
|
350
|
-
const
|
|
440
|
+
const flowHeightPx = dom.offsetHeight - pocChromeHeightInside(dom);
|
|
441
|
+
const flowRectPx = dom.getBoundingClientRect().height - chromes.reduce((sum, c) => sum + c.height, 0);
|
|
442
|
+
const scale = flowHeightPx > 0 ? flowRectPx / flowHeightPx : 1;
|
|
351
443
|
if (!Number.isFinite(scale) || scale <= 0)
|
|
352
444
|
return null;
|
|
353
445
|
const originTop = lines[0].top;
|
|
@@ -363,13 +455,13 @@ function findInlineSplit(view, dom, availablePx, fromLine = 0, minHead = MIN_LIN
|
|
|
363
455
|
if (cut < first || cut > last)
|
|
364
456
|
return null;
|
|
365
457
|
const line = lines[cut];
|
|
366
|
-
const found = view.posAtCoords({ left: line.left + 1, top: (line.
|
|
458
|
+
const found = view.posAtCoords({ left: line.left + 1, top: (line.liveTop + line.liveBottom) / 2 });
|
|
367
459
|
if (!found)
|
|
368
460
|
return null;
|
|
369
461
|
return { pos: found.pos, usedPx: (lines[cut - 1].bottom - originTop) / scale, line: cut };
|
|
370
462
|
}
|
|
371
463
|
function pageSafetyPx(contentHeight) {
|
|
372
|
-
return Math.max(
|
|
464
|
+
return Math.max(8, Math.round(contentHeight * 0.02));
|
|
373
465
|
}
|
|
374
466
|
const NOTES_RULE_PX = 4;
|
|
375
467
|
function createNotesMeasurer(sheet, contentWidth) {
|
|
@@ -418,12 +510,14 @@ function computePocBreaks(view, cfg, sheet) {
|
|
|
418
510
|
const items = [];
|
|
419
511
|
const baseY = cfg.margins.top;
|
|
420
512
|
let noteCounter = 0;
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
513
|
+
const collect = (parent, parentPos, firstChain) => {
|
|
514
|
+
parent.forEach((child, offset, index) => {
|
|
515
|
+
const pos = parentPos + 1 + offset;
|
|
516
|
+
const chainStart = index === 0 ? firstChain ?? parentPos : null;
|
|
517
|
+
if (pocDescendsInto(child)) {
|
|
518
|
+
collect(child, pos, chainStart);
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
427
521
|
const dom = view.nodeDOM(pos);
|
|
428
522
|
if (!(dom instanceof HTMLElement))
|
|
429
523
|
return;
|
|
@@ -440,21 +534,24 @@ function computePocBreaks(view, cfg, sheet) {
|
|
|
440
534
|
pos,
|
|
441
535
|
size: child.nodeSize,
|
|
442
536
|
top,
|
|
443
|
-
|
|
537
|
+
// sem o chrome que uma quebra suave anterior deixou dentro do
|
|
538
|
+
// parágrafo (o fluxo "sem paginação" é o que se mede)
|
|
539
|
+
height: dom.offsetHeight - pocChromeHeightInside(dom),
|
|
444
540
|
notes,
|
|
445
541
|
dom,
|
|
446
542
|
// margem superior conta como parte da página que o item abre —
|
|
447
543
|
// senão a "página" do preview fica mais alta que um A4 real e
|
|
448
544
|
// o DOCX (página física) divergiria
|
|
449
545
|
marginTop: Number.parseFloat(getComputedStyle(dom).marginTop) || 0,
|
|
450
|
-
heading:
|
|
546
|
+
heading: pocLooksLikeTitle(dom),
|
|
451
547
|
marker: (dom.textContent || "").trim() === "PAGEBREAK",
|
|
452
|
-
|
|
453
|
-
// (o chrome fora do div do bloco — senão o outline/label de
|
|
454
|
-
// proveniência "vaza" para a página anterior)
|
|
455
|
-
blockStartPos: childOffset === 0 ? blockOffset : null
|
|
548
|
+
breakPos: chainStart ?? pos
|
|
456
549
|
});
|
|
457
550
|
});
|
|
551
|
+
};
|
|
552
|
+
view.state.doc.forEach((block, blockOffset) => {
|
|
553
|
+
if (block.type.name === "minutaBlock")
|
|
554
|
+
collect(block, blockOffset, null);
|
|
458
555
|
});
|
|
459
556
|
if (!items.length)
|
|
460
557
|
return { breaks: [], total: 1, markers: [], lastNotes: [] };
|
|
@@ -467,9 +564,9 @@ function computePocBreaks(view, cfg, sheet) {
|
|
|
467
564
|
let forcedBreakPending = false;
|
|
468
565
|
let pageNotes = [];
|
|
469
566
|
const notesH = (notes) => measurer && notes.length ? measurer.height(notes) : 0;
|
|
470
|
-
const closePage = (pos, filler, soft = false) => {
|
|
567
|
+
const closePage = (pos, filler, soft = false, manual = false) => {
|
|
471
568
|
const height = notesH(pageNotes);
|
|
472
|
-
breaks.push({ pos, filler: Math.max(0, filler - height), pageNo, notes: pageNotes, notesH: height, soft });
|
|
569
|
+
breaks.push({ pos, filler: Math.max(0, filler - height), pageNo, notes: pageNotes, notesH: height, soft, manual });
|
|
473
570
|
pageNo++;
|
|
474
571
|
pageNotes = [];
|
|
475
572
|
};
|
|
@@ -490,7 +587,7 @@ function computePocBreaks(view, cfg, sheet) {
|
|
|
490
587
|
const capacity = contentH - notesH([...pageNotes, ...item.notes]);
|
|
491
588
|
if (forcedBreakPending && item.top > pageStart) {
|
|
492
589
|
const startWithMargin = item.top - item.marginTop;
|
|
493
|
-
closePage(item.
|
|
590
|
+
closePage(item.breakPos, fullH - (startWithMargin - pageStart), false, true);
|
|
494
591
|
pageStart = startWithMargin;
|
|
495
592
|
forcedBreakPending = false;
|
|
496
593
|
} else if (item.top > pageStart && itemEnd - pageStart > capacity) {
|
|
@@ -546,7 +643,7 @@ function computePocBreaks(view, cfg, sheet) {
|
|
|
546
643
|
moved.push(note);
|
|
547
644
|
}
|
|
548
645
|
}
|
|
549
|
-
closePage(target.
|
|
646
|
+
closePage(target.breakPos, fullH - (startWithMargin - pageStart));
|
|
550
647
|
pageNotes = moved;
|
|
551
648
|
pageStart = startWithMargin;
|
|
552
649
|
if (breakIndex < i) {
|
|
@@ -570,6 +667,20 @@ function pocStyleProp(style, prop) {
|
|
|
570
667
|
const match = style.match(new RegExp(`(?:^|;)\\s*${prop}\\s*:\\s*([^;]+)`, "i"));
|
|
571
668
|
return match?.[1]?.trim();
|
|
572
669
|
}
|
|
670
|
+
function pocDescendsInto(node) {
|
|
671
|
+
switch (node.type.name) {
|
|
672
|
+
case "blockquote":
|
|
673
|
+
case "bulletList":
|
|
674
|
+
case "orderedList":
|
|
675
|
+
case "listItem":
|
|
676
|
+
case "table":
|
|
677
|
+
return true;
|
|
678
|
+
case "styledDiv":
|
|
679
|
+
return !isPocFlexRow(node) && !pocNodePaintsBox(node);
|
|
680
|
+
default:
|
|
681
|
+
return false;
|
|
682
|
+
}
|
|
683
|
+
}
|
|
573
684
|
function isPocFlexRow(node) {
|
|
574
685
|
if (node.type.name !== "styledDiv")
|
|
575
686
|
return false;
|
|
@@ -687,7 +798,7 @@ function PocPaginationPlugin(cfg) {
|
|
|
687
798
|
decorations(state) {
|
|
688
799
|
const pag = pocPageKey.getState(state);
|
|
689
800
|
const decorations = (pag?.breaks ?? []).map(
|
|
690
|
-
(brk) => Decoration.widget(brk.pos, () =>
|
|
801
|
+
(brk) => Decoration.widget(brk.pos, (view) => buildChromeWidget(view, cfg, brk, pag.total), {
|
|
691
802
|
side: -1,
|
|
692
803
|
key: `chrome-${brk.pageNo}-${Math.round(brk.filler)}-${brk.notes?.length ?? 0}-${pag.total}-v${cfg.version ?? 0}`
|
|
693
804
|
})
|
|
@@ -708,4 +819,4 @@ function PocPaginationPlugin(cfg) {
|
|
|
708
819
|
});
|
|
709
820
|
}
|
|
710
821
|
|
|
711
|
-
export { PocPaginationPlugin as P,
|
|
822
|
+
export { PocPaginationPlugin as P, pocLooksLikeTitle as a, sanitizeFootnoteHtml as b, computePocBreaks as c, pocPageKey as d, breaksEqual as e, footnoteHtmlToRuns as f, PAGINATE_META as g, pocChromeFlowHeight as h, isPocChromeCanvas as i, buildPocHeaderEl as j, buildPocFooterEl as k, buildPocNotesEl as l, pocDescendsInto as m, isPocFlexRow as n, pocNodeHasVisibleContent as o, pocLoneCellIndex as p, pocNodePaintsBox as q, computePocLoneRows as r, sanitizeRichHtml as s, footnoteSizePt as t, shouldMoveBreakToHeading as u };
|
package/dist/style.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.poc-editor-root .poc-ins{background:rgba(34,197,94,.16);text-decoration:underline;text-decoration-color:#16a34a}.poc-editor-root .poc-del{background:rgba(239,68,68,.12);color:#b91c1c;text-decoration:line-through}.poc-editor-root .poc-bubble-btn{border-radius:6px;font-size:13px;padding:4px 8px;transition:all .15s;transition-timing-function:ease}.poc-editor-root .poc-toolbar{align-items:center;display:flex;flex-wrap:wrap;gap:2px;padding:4px 12px}@media (max-width:640px){.poc-editor-root .poc-toolbar{flex-wrap:nowrap;overflow-x:auto;padding:4px 8px;scrollbar-width:none}.poc-editor-root .poc-toolbar::-webkit-scrollbar{display:none}.poc-editor-root .poc-toolbar>*{flex:none}}.poc-editor-root .poc-tool{align-items:center;border-radius:6px;display:flex;font-size:13px;height:28px;justify-content:center;min-width:28px;padding-left:6px;padding-right:6px;position:relative;transition:all .15s;transition-timing-function:ease}.poc-editor-root .poc-tool-sep{background:#dee3e7;height:20px;margin:0 6px;width:1px}.poc-editor-root .poc-tool-select{border-radius:6px;font-size:12px;height:28px;padding-left:6px;padding-right:6px}.poc-editor-root .poc-color-underline{background:#dc2626;border-radius:1px;bottom:4px;height:3px;left:7px;position:absolute;right:7px}.poc-editor-root .poc-palette{background:#fff;border:.5px solid #dee3e7;border-radius:8px;box-shadow:0 8px 24px rgba(0,0,0,.12);display:flex;flex-wrap:wrap;gap:2px;left:0;padding:8px;position:absolute;top:32px;width:230px;z-index:50}.poc-editor-root .poc-palette-swatch{border:1px solid rgba(0,0,0,.1);border-radius:3px;cursor:pointer;height:19px;width:19px}.poc-editor-root .poc-palette-swatch:hover{transform:scale(1.2)}.poc-editor-root .poc-palette-custom{align-items:center;color:#565d69;cursor:pointer;display:flex;font-size:12px;margin-top:6px;width:100%}.poc-editor-root .poc-color-swatch{border:1px solid rgba(0,0,0,.12);border-radius:4px;cursor:pointer;height:16px;margin:0 2px;width:16px}.poc-editor-root .poc-color-swatch:hover{transform:scale(1.15)}.poc-editor-root .poc-first-header{align-items:center;cursor:pointer;display:flex;gap:12px;position:absolute;top:0}.poc-editor-root .poc-first-header[style*=center]{justify-content:center}.poc-editor-root .poc-first-header[style*=right]{justify-content:flex-end}.poc-editor-root .poc-first-header:hover,.poc-editor-root .poc-last-footer:hover,.poc-editor-root .poc-page-footerarea:hover,.poc-editor-root .poc-page-headerarea:hover{background:rgba(99,102,241,.06);outline:1px dashed #c7d2fe}.poc-editor-root .poc-last-footer{align-items:center;bottom:0;color:#94a3b8;cursor:pointer;display:flex;font-size:11px;justify-content:space-between;position:absolute}.poc-editor-root .poc-chrome-text{color:#64748b;font-size:11px}.poc-editor-root .poc-chrome-text img{display:inline-block;max-height:48px;max-width:200px;vertical-align:middle}.poc-editor-root .poc-pagebreak-marker{border-top:1px dashed #a5b4fc;font-size:0!important;height:16px;line-height:0!important;margin:6px 0!important;position:relative}.poc-editor-root .poc-pagebreak-marker:after{background:#fff;color:#818cf8;content:"quebra de página do template";font-size:10px;left:50%;line-height:16px;padding:0 8px;position:absolute;top:-8px;transform:translateX(-50%)}.poc-editor-root .poc-page-chrome{display:block;pointer-events:none;text-align:initial;text-indent:0;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:100%}.poc-editor-root .poc-page-footerarea,.poc-editor-root .poc-page-headerarea{cursor:pointer;pointer-events:auto}.poc-editor-root .poc-page-footerarea{align-items:center;color:#94a3b8;display:flex;font-size:11px;justify-content:space-between}.poc-editor-root .poc-page-gapband{background:#eceef1;box-shadow:inset 0 6px 6px -6px rgba(0,0,0,.25),inset 0 -6px 6px -6px rgba(0,0,0,.25)}.poc-editor-root .poc-page-headerarea{align-items:center;display:flex}.poc-editor-root .poc-page-headerarea[style*=center]{justify-content:center}.poc-editor-root .poc-page-headerarea[style*=right]{justify-content:flex-end}.poc-editor-root .ProseMirror{white-space:pre-wrap;word-wrap:break-word}.poc-editor-root h1{color:#0f172a;font-size:24px;font-weight:640;letter-spacing:-.3px;line-height:32px;margin:0 0 20px}.poc-editor-root h2{color:#0f172a;font-size:19px;font-weight:620;letter-spacing:-.2px;line-height:26px;margin:28px 0 14px}.poc-editor-root h3{color:#0f172a;font-size:17px;font-weight:600;letter-spacing:-.1px;line-height:24px;margin:24px 0 12px}.poc-editor-root h1:first-child,.poc-editor-root h2:first-child,.poc-editor-root h3:first-child{margin-top:0}.poc-editor-root strong{font-weight:540}.poc-editor-root p{color:#000;line-height:28px;line-height:1.7em;margin-bottom:.75em;text-align:justify}.poc-editor-root blockquote,.poc-editor-root p{font-size:18px;font-weight:400;letter-spacing:-.4px}.poc-editor-root blockquote{line-height:28px;margin-bottom:2em;margin-left:35%}.poc-editor-root ol,.poc-editor-root ul{margin-bottom:2em}.poc-editor-root li{list-style-position:inside;margin-bottom:16px;margin-left:48px}.poc-editor-root ul>li{list-style-type:disc}.poc-editor-root ol>li{list-style-type:decimal}.poc-editor-root table{border:.5px solid #d4d9df;max-width:100%;table-layout:fixed;width:100%}.poc-editor-root th{font-weight:700}.poc-editor-root td,.poc-editor-root th{color:inherit;font-size:inherit;overflow-wrap:anywhere;padding:12px;text-align:left}.poc-editor-root td{line-height:inherit}.poc-editor-root td p,.poc-editor-root th p{color:inherit;font-size:inherit;line-height:inherit;margin-bottom:0}.poc-editor-root img{display:block;max-width:100%}.poc-editor-root .poc-island--img>img,.poc-editor-root .poc-island>img:only-child{margin-left:auto;margin-right:auto}.poc-editor-root .poc-chrome-canvas{overflow:hidden}.poc-editor-root .poc-chrome-canvas [data-el]{position:absolute}.poc-editor-root .poc-chrome-canvas [data-el=text]{color:#64748b;font-size:11px;line-height:1.4;text-align:left;white-space:pre-wrap}.poc-editor-root img[data-vault-src]{animation:poc-img-loading 1.4s ease-in-out infinite}@keyframes poc-img-loading{0%,to{opacity:.5}50%{opacity:.9}}.poc-editor-root .poc-lone-row{justify-content:center!important}.poc-editor-root .poc-lone-row>:not(.poc-lone-cell){flex:0 0 0!important;min-width:0!important;padding:0!important}.poc-editor-root .poc-lone-row>.poc-lone-cell{align-items:center!important;flex:0 0 auto!important;max-width:100%;min-width:0}.poc-editor-root [data-horizontal-align=left] .poc-island--img>img,.poc-editor-root [data-horizontal-align=left] .poc-island>img:only-child{margin-left:0}.poc-editor-root [data-horizontal-align=right] .poc-island--img>img,.poc-editor-root [data-horizontal-align=right] .poc-island>img:only-child{margin-right:0}.poc-editor-root .poc-review-cursor .poc-minuta-block{cursor:pointer}.poc-editor-root .poc-minuta-block{border-radius:4px;position:relative}.poc-editor-root .poc-minuta-block:hover{outline:1px dashed #c7d2fe;outline-offset:6px}.poc-editor-root.poc-no-block-origin .poc-minuta-block:hover{outline:none}.poc-editor-root.poc-no-block-origin .poc-minuta-block:hover:before{content:none}.poc-editor-root .poc-minuta-block:hover:before{background:#eef2ff;border:1px solid #c7d2fe;border-radius:4px;color:#6366f1;content:attr(data-block-title);font-size:10px;letter-spacing:.04em;padding:1px 8px;pointer-events:none;position:absolute;right:0;text-transform:uppercase;top:-22px;z-index:3}.poc-editor-root .poc-varchip{background:rgba(59,130,246,.06);border-radius:3px;box-shadow:inset 0 0 0 1px rgba(59,130,246,.25);cursor:pointer;transition:background .15s ease}.poc-editor-root .poc-varchip:hover{background:rgba(59,130,246,.16)}.poc-editor-root .poc-tplvar{background:rgba(251,191,36,.16);border-radius:3px;box-shadow:inset 0 0 0 1px rgba(180,83,9,.35);color:#78350f;display:inline;padding:0 2px;white-space:pre-wrap}.poc-editor-root .poc-tplvar--unknown{background:rgba(244,63,94,.12);box-shadow:inset 0 0 0 1px rgba(190,18,60,.45);color:#881337;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}.poc-editor-root .ProseMirror-selectednode.poc-tplvar{box-shadow:inset 0 0 0 2px rgba(180,83,9,.75)}.poc-editor-root .poc-missing-image .missing-image-warning:hover{background-color:rgba(254,174,0,.09);border-color:rgba(223,139,13,.85)}.poc-editor-root .poc-missing-image__remove{background:hsla(0,0%,100%,.75);border:none;border-radius:999px;color:#773613;cursor:pointer;font-size:16px;height:22px;line-height:1;opacity:0;position:absolute;right:4px;top:4px;transition:opacity .15s ease,background .15s ease;width:22px}.poc-editor-root .poc-missing-image:hover .poc-missing-image__remove{opacity:1}.poc-editor-root .poc-missing-image__remove:hover{background:rgba(254,174,0,.35)}.poc-editor-root .poc-missing-image.ProseMirror-selectednode .missing-image-warning{outline:2px solid rgba(223,139,13,.9);outline-offset:2px}.poc-editor-root .poc-page-notes{color:#1c242d;font-size:10.67px;line-height:1.25;padding-top:6px}.poc-editor-root .poc-page-notes:before{border-top:.5px solid #9aa4ae;content:"";display:block;margin-bottom:6px;width:30%}.poc-editor-root .poc-page-note{color:#1c242d;font-size:10.67px;font-weight:400;line-height:1.25;margin:0;text-align:justify}.poc-editor-root .poc-page-note sup{font-size:.8em;line-height:0;vertical-align:super}.poc-editor-root .poc-page-note a{color:#0563c1;text-decoration:underline}.poc-editor-root .poc-footnote{color:#1d4ed8;cursor:help;font-size:.7em;line-height:0;vertical-align:super}.poc-editor-root .poc-island{position:relative}.poc-editor-root .poc-island--img{cursor:grab}.poc-editor-root .poc-img-handle{background:#3b82f6;border:2px solid #fff;border-radius:3px;bottom:-6px;box-shadow:0 1px 3px rgba(0,0,0,.3);cursor:nwse-resize;height:12px;opacity:0;position:absolute;right:-6px;transition:opacity .12s ease;width:12px}.poc-editor-root .poc-island--img.ProseMirror-selectednode .poc-img-handle,.poc-editor-root .poc-island--img:hover .poc-img-handle{opacity:1}.poc-editor-root .poc-island.ProseMirror-selectednode{outline:2px solid #93c5fd;outline-offset:2px}.poc-editor-root .h-full{height:100%}.poc-editor-root .w-full{width:100%}.poc-editor-root .w-1px{width:1px}.poc-editor-root .w-64px{width:64px}.poc-editor-root .h-16px{height:16px}.poc-editor-root .flex{display:flex}.poc-editor-root .flex-col{flex-direction:column}.poc-editor-root .flex-1{flex:1 1 0%}.poc-editor-root .items-center{align-items:center}.poc-editor-root .gap-2px{gap:2px}.poc-editor-root .min-h-0{min-height:0}.poc-editor-root .overflow-y-auto{overflow-y:auto}.poc-editor-root .relative{position:relative}.poc-editor-root .hidden{display:none}.poc-editor-root .inline-block{display:inline-block}.poc-editor-root .align-middle{vertical-align:middle}.poc-editor-root .ml-auto{margin-left:auto}.poc-editor-root .mx-auto{margin-left:auto;margin-right:auto}.poc-editor-root .mx-2px{margin-left:2px;margin-right:2px}.poc-editor-root .p-2px{padding:2px}.poc-editor-root .py-24px{padding-bottom:24px;padding-top:24px}.poc-editor-root .bg-white{background:#fff}.poc-editor-root .bg-gray-120{background:#ebedf0}.poc-editor-root .bg-gray-200{background:#e5e7eb}.poc-editor-root .border{border-style:solid;border-width:1px}.poc-editor-root .border-gray-200{border-color:#e5e7eb}.poc-editor-root .rounded-8px{border-radius:8px}.poc-editor-root .shadow-md{box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1)}.poc-editor-root .shadow-lg{box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1)}.poc-editor-root .font-bold{font-weight:700}.poc-editor-root .font-semibold{font-weight:600}.poc-editor-root .italic{font-style:italic}.poc-editor-root .underline{text-decoration:underline}.poc-editor-root .line-through{text-decoration:line-through}.poc-editor-root .text-red-600{color:#dc2626}.poc-editor-root .body-13-regular{font-size:13px;font-weight:400}.poc-editor-root{font-family:Inter Variable,Inter,-apple-system,Segoe UI,Roboto,sans-serif}.poc-editor-root .poc-toolbar{background:#fafbfc;border-bottom:.5px solid #dee3e7}.poc-editor-root .poc-tool{background:transparent;border:none;cursor:pointer}.poc-editor-root .poc-tool:hover{background:#ebedf0}.poc-editor-root .poc-tool--on{background:#e2e8f0}.poc-editor-root .poc-tool-select{background:#fff;border:.5px solid #d4d9df;cursor:pointer}.poc-editor-root .ProseMirror{outline:none}.poc-editor-root td,.poc-editor-root th{border:.5px solid #d4d9df}.poc-editor-root .poc-footnote-pop{background:#fff;border:.5px solid #d4d9df;border-radius:10px;box-shadow:0 10px 25px -5px rgba(0,0,0,.18);padding:10px 12px;position:absolute;width:364px;z-index:40}.poc-editor-root .poc-footnote-pop__head{color:#6b7280;font-size:11px;font-weight:650;letter-spacing:.04em;margin-bottom:6px;text-transform:uppercase}.poc-editor-root .poc-footnote-pop__toolbar{align-items:center;display:flex;gap:4px;margin-bottom:6px}.poc-editor-root .poc-footnote-pop__tool{background:transparent;border:none;border-radius:6px;color:#374151;cursor:pointer;font-size:12px;height:24px;width:24px}.poc-editor-root .poc-footnote-pop__tool:hover{background:rgba(28,36,45,.06)}.poc-editor-root .poc-footnote-pop__sep{background:#e5e7eb;height:16px;margin:0 2px;width:1px}.poc-editor-root .poc-footnote-pop__select{background:#fff;border:1px solid #e5e7eb;border-radius:6px;color:#374151;font-size:11px;height:24px;max-width:108px;outline:none}.poc-editor-root .poc-footnote-pop__select--narrow{max-width:58px}.poc-editor-root .poc-footnote-pop__swatch{border:1px solid rgba(0,0,0,.15);border-radius:4px;cursor:pointer;height:14px;padding:0;width:14px}.poc-editor-root .poc-footnote-pop__input{border:1px solid #e5e7eb;border-radius:8px;color:#111827;font-size:12.5px;line-height:1.5;max-height:160px;min-height:58px;outline:none;overflow-y:auto;padding:6px 8px;width:100%}.poc-editor-root .poc-footnote-pop__input:focus{border-color:#a5b4fc}.poc-editor-root .poc-footnote-pop__input:empty:before{color:#9ca3af;content:attr(data-placeholder)}.poc-editor-root .poc-footnote-pop__actions{align-items:center;display:flex;gap:8px;margin-top:8px}.poc-editor-root .poc-footnote-pop__spacer{flex:1}.poc-editor-root .poc-footnote-pop__actions button{background:transparent;border:none;border-radius:8px;color:#565d69;cursor:pointer;font-size:12px;font-weight:500;padding:4px 12px}.poc-editor-root .poc-footnote-pop__remove{color:#b91c1c!important}.poc-editor-root .poc-footnote-pop__save{background:rgba(0,0,0,.88)!important;color:#fff!important}.poc-editor-root{display:flex;flex-direction:column;height:100%;width:100%}.poc-editor-root .w-118px{width:118px}.poc-editor-root .poc-varpicker{background:#fff;border:1px solid #e5e7eb;border-radius:10px;box-shadow:0 12px 24px -8px rgba(0,0,0,.25);display:flex;flex-direction:column;font-size:13px;max-height:300px;overflow:hidden;position:absolute;width:320px;z-index:60}.poc-editor-root .poc-varpicker__search{border:0;border-bottom:1px solid #f3f4f6;font-family:inherit;font-size:13px;outline:none;padding:10px 12px}.poc-editor-root .poc-varpicker__hint{border-bottom:1px solid #f3f4f6;color:#6b7280;font-size:12px;padding:8px 12px}.poc-editor-root .poc-varpicker__list{flex:1;min-height:0;overflow-y:auto;padding:4px}.poc-editor-root .poc-varpicker__empty{color:#6b7280;font-size:12px;margin:0;padding:12px}.poc-editor-root .poc-varpicker__group{color:#9ca3af;font-size:11px;font-weight:600;letter-spacing:.04em;padding:8px 8px 4px;text-transform:uppercase}.poc-editor-root .poc-varpicker__item{background:none;border:0;border-radius:6px;cursor:pointer;display:grid;font-family:inherit;gap:2px 8px;grid-template-columns:1fr auto;padding:6px 8px;text-align:left;width:100%}.poc-editor-root .poc-varpicker__item--on{background:#f3f4f6}.poc-editor-root .poc-varpicker__label{color:#111827;font-weight:500}.poc-editor-root .poc-varpicker__key{color:#9ca3af;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px}.poc-editor-root .poc-varpicker__desc{color:#6b7280;display:-webkit-box;font-size:11px;grid-column:1/-1;-webkit-line-clamp:2;line-height:1.4;overflow:hidden;-webkit-box-orient:vertical}.poc-editor-root [hidden]{display:none!important}.poc-editor-root .poc-varchip--flash{background:rgba(59,130,246,.35);transition:background .9s ease}
|
|
1
|
+
.poc-editor-root .poc-ins{background:rgba(34,197,94,.16);text-decoration:underline;text-decoration-color:#16a34a}.poc-editor-root .poc-del{background:rgba(239,68,68,.12);color:#b91c1c;text-decoration:line-through}.poc-editor-root .poc-bubble-btn{border-radius:6px;font-size:13px;padding:4px 8px;transition:all .15s;transition-timing-function:ease}.poc-editor-root .poc-toolbar{align-items:center;display:flex;flex-wrap:wrap;gap:2px;padding:4px 12px}@media (max-width:640px){.poc-editor-root .poc-toolbar{flex-wrap:nowrap;overflow-x:auto;padding:4px 8px;scrollbar-width:none}.poc-editor-root .poc-toolbar::-webkit-scrollbar{display:none}.poc-editor-root .poc-toolbar>*{flex:none}}.poc-editor-root .poc-tool{align-items:center;border-radius:6px;display:flex;font-size:13px;height:28px;justify-content:center;min-width:28px;padding-left:6px;padding-right:6px;position:relative;transition:all .15s;transition-timing-function:ease}.poc-editor-root .poc-tool-sep{background:#dee3e7;height:20px;margin:0 6px;width:1px}.poc-editor-root .poc-tool-select{border-radius:6px;font-size:12px;height:28px;padding-left:6px;padding-right:6px}.poc-editor-root .poc-color-underline{background:#dc2626;border-radius:1px;bottom:4px;height:3px;left:7px;position:absolute;right:7px}.poc-editor-root .poc-palette{background:#fff;border:.5px solid #dee3e7;border-radius:8px;box-shadow:0 8px 24px rgba(0,0,0,.12);display:flex;flex-wrap:wrap;gap:2px;left:0;padding:8px;position:absolute;top:32px;width:230px;z-index:50}.poc-editor-root .poc-palette-swatch{border:1px solid rgba(0,0,0,.1);border-radius:3px;cursor:pointer;height:19px;width:19px}.poc-editor-root .poc-palette-swatch:hover{transform:scale(1.2)}.poc-editor-root .poc-palette-custom{align-items:center;color:#565d69;cursor:pointer;display:flex;font-size:12px;margin-top:6px;width:100%}.poc-editor-root .poc-color-swatch{border:1px solid rgba(0,0,0,.12);border-radius:4px;cursor:pointer;height:16px;margin:0 2px;width:16px}.poc-editor-root .poc-color-swatch:hover{transform:scale(1.15)}.poc-editor-root .poc-first-header{align-items:center;cursor:pointer;display:flex;gap:12px;position:absolute;top:0}.poc-editor-root .poc-first-header[style*=center]{justify-content:center}.poc-editor-root .poc-first-header[style*=right]{justify-content:flex-end}.poc-editor-root .poc-first-header:hover,.poc-editor-root .poc-last-footer:hover,.poc-editor-root .poc-page-footerarea:hover,.poc-editor-root .poc-page-headerarea:hover{background:rgba(99,102,241,.06);outline:1px dashed #c7d2fe}.poc-editor-root .poc-last-footer{align-items:center;bottom:0;color:#94a3b8;cursor:pointer;display:flex;font-size:11px;justify-content:space-between;position:absolute}.poc-editor-root .poc-chrome-text{color:#64748b;font-size:11px}.poc-editor-root .poc-chrome-text img{display:inline-block;max-height:48px;max-width:200px;vertical-align:middle}.poc-editor-root .poc-pagebreak-marker{border-top:1px dashed #a5b4fc;font-size:0!important;height:16px;line-height:0!important;margin:6px 0!important;position:relative}.poc-editor-root .poc-pagebreak-marker:after{background:#fff;color:#818cf8;content:"quebra de página do template";font-size:10px;left:50%;line-height:16px;padding:0 8px;position:absolute;top:-8px;transform:translateX(-50%)}.poc-editor-root .poc-page-chrome{color:initial;display:block;font-style:normal;font-weight:400;letter-spacing:normal;line-height:normal;pointer-events:none;text-align:initial;text-indent:0;text-transform:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;white-space:normal}.poc-editor-root .poc-page-chrome>.poc-page-footerarea:not(:hover),.poc-editor-root .poc-page-chrome>.poc-page-headerarea:not(:hover),.poc-editor-root .poc-page-chrome>.poc-page-notes{background:#fff}.poc-editor-root tr.poc-page-chrome-row>td.poc-page-chrome-cell{background:transparent!important;border:0!important;padding:0!important;vertical-align:top}.poc-editor-root .poc-page-footerarea,.poc-editor-root .poc-page-headerarea{cursor:pointer;pointer-events:auto}.poc-editor-root .poc-page-footerarea{align-items:center;color:#94a3b8;display:flex;font-size:11px;justify-content:space-between}.poc-editor-root .poc-page-gapband{background:#eceef1;box-shadow:inset 0 6px 6px -6px rgba(0,0,0,.25),inset 0 -6px 6px -6px rgba(0,0,0,.25)}.poc-editor-root .poc-page-headerarea{align-items:center;display:flex}.poc-editor-root .poc-page-headerarea[style*=center]{justify-content:center}.poc-editor-root .poc-page-headerarea[style*=right]{justify-content:flex-end}.poc-editor-root .ProseMirror{white-space:pre-wrap;word-wrap:break-word}.poc-editor-root h1{color:#0f172a;font-size:24px;font-weight:640;letter-spacing:-.3px;line-height:32px;margin:0 0 20px}.poc-editor-root h2{color:#0f172a;font-size:19px;font-weight:620;letter-spacing:-.2px;line-height:26px;margin:28px 0 14px}.poc-editor-root h3{color:#0f172a;font-size:17px;font-weight:600;letter-spacing:-.1px;line-height:24px;margin:24px 0 12px}.poc-editor-root h1:first-child,.poc-editor-root h2:first-child,.poc-editor-root h3:first-child{margin-top:0}.poc-editor-root strong{font-weight:540}.poc-editor-root p{color:#000;line-height:28px;line-height:1.7em;margin-bottom:.75em;text-align:justify}.poc-editor-root blockquote,.poc-editor-root p{font-size:18px;font-weight:400;letter-spacing:-.4px}.poc-editor-root blockquote{line-height:28px;margin-bottom:2em;margin-left:35%}.poc-editor-root ol,.poc-editor-root ul{margin-bottom:2em}.poc-editor-root li{list-style-position:inside;margin-bottom:16px;margin-left:48px}.poc-editor-root ul>li{list-style-type:disc}.poc-editor-root ol>li{list-style-type:decimal}.poc-editor-root table{border:.5px solid #d4d9df;max-width:100%;table-layout:fixed;width:100%}.poc-editor-root th{font-weight:700}.poc-editor-root td,.poc-editor-root th{color:inherit;font-size:inherit;overflow-wrap:anywhere;padding:12px;text-align:left}.poc-editor-root td{line-height:inherit}.poc-editor-root td p,.poc-editor-root th p{color:inherit;font-size:inherit;line-height:inherit;margin-bottom:0}.poc-editor-root img{display:block;max-width:100%}.poc-editor-root .poc-island--img>img,.poc-editor-root .poc-island>img:only-child{margin-left:auto;margin-right:auto}.poc-editor-root .poc-chrome-canvas{overflow:hidden}.poc-editor-root .poc-chrome-canvas [data-el]{position:absolute}.poc-editor-root .poc-chrome-canvas [data-el=text]{color:#64748b;font-size:11px;line-height:1.4;text-align:left;white-space:pre-wrap}.poc-editor-root img[data-vault-src]{animation:poc-img-loading 1.4s ease-in-out infinite}@keyframes poc-img-loading{0%,to{opacity:.5}50%{opacity:.9}}.poc-editor-root .poc-lone-row{justify-content:center!important}.poc-editor-root .poc-lone-row>:not(.poc-lone-cell){flex:0 0 0!important;min-width:0!important;padding:0!important}.poc-editor-root .poc-lone-row>.poc-lone-cell{align-items:center!important;flex:0 0 auto!important;max-width:100%;min-width:0}.poc-editor-root [data-horizontal-align=left] .poc-island--img>img,.poc-editor-root [data-horizontal-align=left] .poc-island>img:only-child{margin-left:0}.poc-editor-root [data-horizontal-align=right] .poc-island--img>img,.poc-editor-root [data-horizontal-align=right] .poc-island>img:only-child{margin-right:0}.poc-editor-root .poc-review-cursor .poc-minuta-block{cursor:pointer}.poc-editor-root .poc-minuta-block{border-radius:4px;position:relative}.poc-editor-root .poc-minuta-block:hover{outline:1px dashed #c7d2fe;outline-offset:6px}.poc-editor-root.poc-no-block-origin .poc-minuta-block:hover{outline:none}.poc-editor-root.poc-no-block-origin .poc-minuta-block:hover:before{content:none}.poc-editor-root .poc-minuta-block:hover:before{background:#eef2ff;border:1px solid #c7d2fe;border-radius:4px;color:#6366f1;content:attr(data-block-title);font-size:10px;letter-spacing:.04em;padding:1px 8px;pointer-events:none;position:absolute;right:0;text-transform:uppercase;top:-22px;z-index:3}.poc-editor-root .poc-varchip{background:rgba(59,130,246,.06);border-radius:3px;box-shadow:inset 0 0 0 1px rgba(59,130,246,.25);cursor:pointer;transition:background .15s ease}.poc-editor-root .poc-varchip:hover{background:rgba(59,130,246,.16)}.poc-editor-root .poc-tplvar{background:rgba(251,191,36,.16);border-radius:3px;box-shadow:inset 0 0 0 1px rgba(180,83,9,.35);color:#78350f;display:inline;padding:0 2px;white-space:pre-wrap}.poc-editor-root .poc-tplvar--unknown{background:rgba(244,63,94,.12);box-shadow:inset 0 0 0 1px rgba(190,18,60,.45);color:#881337;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}.poc-editor-root .ProseMirror-selectednode.poc-tplvar{box-shadow:inset 0 0 0 2px rgba(180,83,9,.75)}.poc-editor-root .poc-missing-image .missing-image-warning:hover{background-color:rgba(254,174,0,.09);border-color:rgba(223,139,13,.85)}.poc-editor-root .poc-missing-image__remove{background:hsla(0,0%,100%,.75);border:none;border-radius:999px;color:#773613;cursor:pointer;font-size:16px;height:22px;line-height:1;opacity:0;position:absolute;right:4px;top:4px;transition:opacity .15s ease,background .15s ease;width:22px}.poc-editor-root .poc-missing-image:hover .poc-missing-image__remove{opacity:1}.poc-editor-root .poc-missing-image__remove:hover{background:rgba(254,174,0,.35)}.poc-editor-root .poc-missing-image.ProseMirror-selectednode .missing-image-warning{outline:2px solid rgba(223,139,13,.9);outline-offset:2px}.poc-editor-root .poc-page-notes{color:#1c242d;font-size:10.67px;line-height:1.25;padding-top:6px}.poc-editor-root .poc-page-notes:before{border-top:.5px solid #9aa4ae;content:"";display:block;margin-bottom:6px;width:30%}.poc-editor-root .poc-page-note{color:#1c242d;font-size:10.67px;font-weight:400;line-height:1.25;margin:0;text-align:justify}.poc-editor-root .poc-page-note sup{font-size:.8em;line-height:0;vertical-align:super}.poc-editor-root .poc-page-note a{color:#0563c1;text-decoration:underline}.poc-editor-root .poc-footnote{color:#1d4ed8;cursor:help;font-size:.7em;line-height:0;vertical-align:super}.poc-editor-root .poc-island{position:relative}.poc-editor-root .poc-island--img{cursor:grab}.poc-editor-root .poc-img-handle{background:#3b82f6;border:2px solid #fff;border-radius:3px;bottom:-6px;box-shadow:0 1px 3px rgba(0,0,0,.3);cursor:nwse-resize;height:12px;opacity:0;position:absolute;right:-6px;transition:opacity .12s ease;width:12px}.poc-editor-root .poc-island--img.ProseMirror-selectednode .poc-img-handle,.poc-editor-root .poc-island--img:hover .poc-img-handle{opacity:1}.poc-editor-root .poc-island.ProseMirror-selectednode{outline:2px solid #93c5fd;outline-offset:2px}.poc-editor-root .h-full{height:100%}.poc-editor-root .w-full{width:100%}.poc-editor-root .w-1px{width:1px}.poc-editor-root .w-64px{width:64px}.poc-editor-root .h-16px{height:16px}.poc-editor-root .flex{display:flex}.poc-editor-root .flex-col{flex-direction:column}.poc-editor-root .flex-1{flex:1 1 0%}.poc-editor-root .items-center{align-items:center}.poc-editor-root .gap-2px{gap:2px}.poc-editor-root .min-h-0{min-height:0}.poc-editor-root .overflow-y-auto{overflow-y:auto}.poc-editor-root .relative{position:relative}.poc-editor-root .hidden{display:none}.poc-editor-root .inline-block{display:inline-block}.poc-editor-root .align-middle{vertical-align:middle}.poc-editor-root .ml-auto{margin-left:auto}.poc-editor-root .mx-auto{margin-left:auto;margin-right:auto}.poc-editor-root .mx-2px{margin-left:2px;margin-right:2px}.poc-editor-root .p-2px{padding:2px}.poc-editor-root .py-24px{padding-bottom:24px;padding-top:24px}.poc-editor-root .bg-white{background:#fff}.poc-editor-root .bg-gray-120{background:#ebedf0}.poc-editor-root .bg-gray-200{background:#e5e7eb}.poc-editor-root .border{border-style:solid;border-width:1px}.poc-editor-root .border-gray-200{border-color:#e5e7eb}.poc-editor-root .rounded-8px{border-radius:8px}.poc-editor-root .shadow-md{box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1)}.poc-editor-root .shadow-lg{box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1)}.poc-editor-root .font-bold{font-weight:700}.poc-editor-root .font-semibold{font-weight:600}.poc-editor-root .italic{font-style:italic}.poc-editor-root .underline{text-decoration:underline}.poc-editor-root .line-through{text-decoration:line-through}.poc-editor-root .text-red-600{color:#dc2626}.poc-editor-root .body-13-regular{font-size:13px;font-weight:400}.poc-editor-root{font-family:Inter Variable,Inter,-apple-system,Segoe UI,Roboto,sans-serif}.poc-editor-root .poc-toolbar{background:#fafbfc;border-bottom:.5px solid #dee3e7}.poc-editor-root .poc-tool{background:transparent;border:none;cursor:pointer}.poc-editor-root .poc-tool:hover{background:#ebedf0}.poc-editor-root .poc-tool--on{background:#e2e8f0}.poc-editor-root .poc-tool-select{background:#fff;border:.5px solid #d4d9df;cursor:pointer}.poc-editor-root .ProseMirror{outline:none}.poc-editor-root td,.poc-editor-root th{border:.5px solid #d4d9df}.poc-editor-root .poc-footnote-pop{background:#fff;border:.5px solid #d4d9df;border-radius:10px;box-shadow:0 10px 25px -5px rgba(0,0,0,.18);padding:10px 12px;position:absolute;width:364px;z-index:40}.poc-editor-root .poc-footnote-pop__head{color:#6b7280;font-size:11px;font-weight:650;letter-spacing:.04em;margin-bottom:6px;text-transform:uppercase}.poc-editor-root .poc-footnote-pop__toolbar{align-items:center;display:flex;gap:4px;margin-bottom:6px}.poc-editor-root .poc-footnote-pop__tool{background:transparent;border:none;border-radius:6px;color:#374151;cursor:pointer;font-size:12px;height:24px;width:24px}.poc-editor-root .poc-footnote-pop__tool:hover{background:rgba(28,36,45,.06)}.poc-editor-root .poc-footnote-pop__sep{background:#e5e7eb;height:16px;margin:0 2px;width:1px}.poc-editor-root .poc-footnote-pop__select{background:#fff;border:1px solid #e5e7eb;border-radius:6px;color:#374151;font-size:11px;height:24px;max-width:108px;outline:none}.poc-editor-root .poc-footnote-pop__select--narrow{max-width:58px}.poc-editor-root .poc-footnote-pop__swatch{border:1px solid rgba(0,0,0,.15);border-radius:4px;cursor:pointer;height:14px;padding:0;width:14px}.poc-editor-root .poc-footnote-pop__input{border:1px solid #e5e7eb;border-radius:8px;color:#111827;font-size:12.5px;line-height:1.5;max-height:160px;min-height:58px;outline:none;overflow-y:auto;padding:6px 8px;width:100%}.poc-editor-root .poc-footnote-pop__input:focus{border-color:#a5b4fc}.poc-editor-root .poc-footnote-pop__input:empty:before{color:#9ca3af;content:attr(data-placeholder)}.poc-editor-root .poc-footnote-pop__actions{align-items:center;display:flex;gap:8px;margin-top:8px}.poc-editor-root .poc-footnote-pop__spacer{flex:1}.poc-editor-root .poc-footnote-pop__actions button{background:transparent;border:none;border-radius:8px;color:#565d69;cursor:pointer;font-size:12px;font-weight:500;padding:4px 12px}.poc-editor-root .poc-footnote-pop__remove{color:#b91c1c!important}.poc-editor-root .poc-footnote-pop__save{background:rgba(0,0,0,.88)!important;color:#fff!important}.poc-editor-root{display:flex;flex-direction:column;height:100%;width:100%}.poc-editor-root .w-118px{width:118px}.poc-editor-root .poc-varpicker{background:#fff;border:1px solid #e5e7eb;border-radius:10px;box-shadow:0 12px 24px -8px rgba(0,0,0,.25);display:flex;flex-direction:column;font-size:13px;max-height:300px;overflow:hidden;position:absolute;width:320px;z-index:60}.poc-editor-root .poc-varpicker__search{border:0;border-bottom:1px solid #f3f4f6;font-family:inherit;font-size:13px;outline:none;padding:10px 12px}.poc-editor-root .poc-varpicker__hint{border-bottom:1px solid #f3f4f6;color:#6b7280;font-size:12px;padding:8px 12px}.poc-editor-root .poc-varpicker__list{flex:1;min-height:0;overflow-y:auto;padding:4px}.poc-editor-root .poc-varpicker__empty{color:#6b7280;font-size:12px;margin:0;padding:12px}.poc-editor-root .poc-varpicker__group{color:#9ca3af;font-size:11px;font-weight:600;letter-spacing:.04em;padding:8px 8px 4px;text-transform:uppercase}.poc-editor-root .poc-varpicker__item{background:none;border:0;border-radius:6px;cursor:pointer;display:grid;font-family:inherit;gap:2px 8px;grid-template-columns:1fr auto;padding:6px 8px;text-align:left;width:100%}.poc-editor-root .poc-varpicker__item--on{background:#f3f4f6}.poc-editor-root .poc-varpicker__label{color:#111827;font-weight:500}.poc-editor-root .poc-varpicker__key{color:#9ca3af;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px}.poc-editor-root .poc-varpicker__desc{color:#6b7280;display:-webkit-box;font-size:11px;grid-column:1/-1;-webkit-line-clamp:2;line-height:1.4;overflow:hidden;-webkit-box-orient:vertical}.poc-editor-root [hidden]{display:none!important}.poc-editor-root .poc-varchip--flash{background:rgba(59,130,246,.35);transition:background .9s ease}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meistrari/minuta-editor",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.1",
|
|
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",
|
|
@@ -32,7 +32,8 @@
|
|
|
32
32
|
"prepack": "bun run build",
|
|
33
33
|
"build": "unbuild && node scripts/add-type-refs.mjs",
|
|
34
34
|
"typecheck": "tsc --noEmit",
|
|
35
|
-
"test:pack": "node scripts/verify-pack.mjs"
|
|
35
|
+
"test:pack": "node scripts/verify-pack.mjs",
|
|
36
|
+
"test": "bun test src"
|
|
36
37
|
},
|
|
37
38
|
"dependencies": {
|
|
38
39
|
"@tiptap/core": "2.11.9",
|