@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 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 com as mesmas quebras de página do preview. Monta em qualquer app —
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.b2512170.mjs';
2
- import { BorderStyle, TextRun, ExternalHyperlink, Paragraph, Document, Header, Packer, AlignmentType, PageBreak, LineRuleType, Table, TableRow, TableCell, WidthType, TableLayoutType, Footer, FootnoteReferenceRun, VerticalAlign, ImageRun, HorizontalPositionRelativeFrom, VerticalPositionRelativeFrom, TextWrappingType, FrameAnchorType, PageNumber, HeadingLevel } from 'docx';
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 (TLF ¶36/¶52).
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 do TLF) tem que viajar no run
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 inlineImagesParagraph(islands, innerPx, ctx) {
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 live = domAt(ctx, pos)?.querySelector("img");
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
- items.push({ src, widthPx });
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 null;
721
- const total = items.reduce((a, b) => a + b.widthPx, 0) + GAP_PX * (items.length - 1);
722
- const scale = innerPx > 0 && total > innerPx ? (innerPx - GAP_PX * (items.length - 1)) / (total - GAP_PX * (items.length - 1)) : 1;
723
- const runs = [];
724
- for (let i = 0; i < items.length; i++) {
725
- const run = await dataUrlToImageRun(items[i].src, Math.max(1, Math.round(items[i].widthPx * scale)));
726
- if (!run)
727
- continue;
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
- runs.push(new TextRun({ text: " " }));
730
- runs.push(run);
748
+ paragraphs.push(new Paragraph({ children: runs, alignment: AlignmentType.CENTER, spacing: { after: 0, before: 0 } }));
731
749
  }
732
- if (!runs.length)
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
- const para = await inlineImagesParagraph(islands, cellInnerPx, cellCtx);
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
- if (ctx.breakSet.size)
941
- return [];
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
- // quebras `soft` (dentro de um parágrafo) não viram pageBreakBefore:
1307
- // partir o parágrafo em dois no Word entregaria ao advogado um arquivo
1308
- // que não reflui ao editar. Ali o Word quebra sozinho, no mesmo lugar
1309
- // ou a uma linha de distância.
1310
- breakSet: new Set((options.breaks ?? []).filter((b) => !b.soft).map((b) => b.pos)),
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, u as pocExportDocx } from './shared/minuta-editor.e223a421.mjs';
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, u as pocExportDocx } from './shared/minuta-editor.e223a421.js';
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
@@ -1,5 +1,5 @@
1
1
  export { pocExportDocx } from './chunks/docxExport.mjs';
2
- import './shared/minuta-editor.b2512170.mjs';
2
+ import './shared/minuta-editor.d9d0c0ce.mjs';
3
3
  import '@tiptap/pm/state';
4
4
  import '@tiptap/pm/view';
5
5
  import 'docx';
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.e223a421.mjs';
23
- export { e as PAGINATE_META, a as PocDocxChrome, b as PocDocxExportOptions, q as PocLoneRow, d as PocPageBreak, c as PocPageNote, t as PocPaginationPlugin, s as breaksEqual, h as buildPocFooterEl, g as buildPocHeaderEl, j as buildPocNotesEl, k as computePocBreaks, r as computePocLoneRows, i as isPocChromeCanvas, l as isPocFlexRow, f as pocChromeFlowHeight, o as pocLoneCellIndex, m as pocNodeHasVisibleContent, n as pocNodePaintsBox, p as pocPageKey } from './shared/minuta-editor.e223a421.mjs';
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.e223a421.js';
23
- export { e as PAGINATE_META, a as PocDocxChrome, b as PocDocxExportOptions, q as PocLoneRow, d as PocPageBreak, c as PocPageNote, t as PocPaginationPlugin, s as breaksEqual, h as buildPocFooterEl, g as buildPocHeaderEl, j as buildPocNotesEl, k as computePocBreaks, r as computePocLoneRows, i as isPocChromeCanvas, l as isPocFlexRow, f as pocChromeFlowHeight, o as pocLoneCellIndex, m as pocNodeHasVisibleContent, n as pocNodePaintsBox, p as pocPageKey } from './shared/minuta-editor.e223a421.js';
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, a as sanitizeFootnoteHtml, c as computePocBreaks, b as pocPageKey, d as breaksEqual, e as PAGINATE_META } from './shared/minuta-editor.b2512170.mjs';
26
- export { j as buildPocFooterEl, h as buildPocHeaderEl, k as buildPocNotesEl, o as computePocLoneRows, f as footnoteHtmlToRuns, q as footnoteSizePt, i as isPocChromeCanvas, l as isPocFlexRow, g as pocChromeFlowHeight, p as pocLoneCellIndex, m as pocNodeHasVisibleContent, n as pocNodePaintsBox, r as shouldMoveBreakToHeading } from './shared/minuta-editor.b2512170.mjs';
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
- * - quebra somente entre nós (parágrafo/título/ilha) — nó mais alto que a
24
- * página flui e as páginas internas são contadas, sem chrome no meio;
25
- * - keep-with-next: título não fica órfão no fim da página (a quebra sobe
26
- * para antes do título).
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 da Telefônica desenha uma timeline com `border-right` numa
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, computePocBreaks as k, isPocFlexRow as l, pocNodeHasVisibleContent as m, pocNodePaintsBox as n, pocLoneCellIndex as o, pocPageKey as p, computePocLoneRows as r, breaksEqual as s, PocPaginationPlugin as t, pocExportDocx as u };
166
- export type { PocPageConfig as P, PocDocxChrome as a, PocDocxExportOptions as b, PocPageNote as c, PocPageBreak as d, PocLoneRow as q };
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
- * - quebra somente entre nós (parágrafo/título/ilha) — nó mais alto que a
24
- * página flui e as páginas internas são contadas, sem chrome no meio;
25
- * - keep-with-next: título não fica órfão no fim da página (a quebra sobe
26
- * para antes do título).
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 da Telefônica desenha uma timeline com `border-right` numa
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, computePocBreaks as k, isPocFlexRow as l, pocNodeHasVisibleContent as m, pocNodePaintsBox as n, pocLoneCellIndex as o, pocPageKey as p, computePocLoneRows as r, breaksEqual as s, PocPaginationPlugin as t, pocExportDocx as u };
166
- export type { PocPageConfig as P, PocDocxChrome as a, PocDocxExportOptions as b, PocPageNote as c, PocPageBreak as d, PocLoneRow as q };
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:${-cfg.margins.left}px;width:794px;height:100%;pointer-events:none;`;
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, cfg);
254
+ const content = chromeContentEl(cfg.headerText);
254
255
  if (content.className === "poc-chrome-text" && !content.innerHTML && !cfg.headerLogoUrl)
255
256
  content.innerHTML = "&nbsp;";
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, cfg) : document.createElement("div");
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
- chrome.appendChild(buildPocNotesEl(brk.notes));
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
- if (rects.length < minHead + minTail)
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 rects) {
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 scale = dom.offsetHeight > 0 ? dom.getBoundingClientRect().height / dom.offsetHeight : 1;
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.top + line.bottom) / 2 });
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(32, Math.round(contentHeight * 0.08));
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
- view.state.doc.forEach((block, blockOffset) => {
422
- if (block.type.name !== "minutaBlock") {
423
- return;
424
- }
425
- block.forEach((child, childOffset) => {
426
- const pos = blockOffset + 1 + childOffset;
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
- height: dom.offsetHeight,
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: HEADING_TAGS.has(dom.tagName),
546
+ heading: pocLooksLikeTitle(dom),
451
547
  marker: (dom.textContent || "").trim() === "PAGEBREAK",
452
- // quebra que cai no 1º filho de um bloco vai ANTES do bloco
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.blockStartPos ?? item.pos, fullH - (startWithMargin - pageStart));
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.blockStartPos ?? target.pos, fullH - (startWithMargin - pageStart));
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, () => buildChrome(cfg, brk, pag.total), {
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, sanitizeFootnoteHtml as a, pocPageKey as b, computePocBreaks as c, breaksEqual as d, PAGINATE_META as e, footnoteHtmlToRuns as f, pocChromeFlowHeight as g, buildPocHeaderEl as h, isPocChromeCanvas as i, buildPocFooterEl as j, buildPocNotesEl as k, isPocFlexRow as l, pocNodeHasVisibleContent as m, pocNodePaintsBox as n, computePocLoneRows as o, pocLoneCellIndex as p, footnoteSizePt as q, shouldMoveBreakToHeading as r, sanitizeRichHtml as s };
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.0",
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",