@meistrari/minuta-editor 1.1.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md 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
@@ -37,6 +38,8 @@ const editor = createMinutaEditor(el, {
37
38
  onReady: tiptap => {},
38
39
  onChange: () => {},
39
40
  onEditChrome: part => {}, // clique no cabeçalho/rodapé
41
+ onVariableClick: ({ variableId, parentBlockId, text, kind }) => {}, // kind: 'text' | 'image' | 'missingImage'
42
+ onBlockClick: blockId => {}, // read-only (ou com blockClickWhileEditing)
40
43
  })
41
44
 
42
45
  editor.getHTML() // → string
@@ -46,6 +49,15 @@ editor.setEditable(bool)
46
49
  editor.setChrome({ header, footer, headerScope, footerScope, showPageNumber })
47
50
  editor.setHeader({ logoUrl, position })
48
51
  editor.setVariables(catalogo)
52
+ editor.setBlockClickWhileEditing(bool)
53
+
54
+ // variáveis do case marcadas no documento (<span|img data-variable-id>, aviso de imagem faltando)
55
+ editor.scrollToVariable(id) // → boolean (rola e dá um flash)
56
+ editor.setVariableValue(id, texto) // → nº de ocorrências (o aviso de "faltando" vira chip)
57
+ editor.setVariableImage(id, src) // → nº de ocorrências (o aviso de imagem vira <img>)
58
+ editor.variablesInDocument() // → string[]
59
+ editor.refreshVaultImages(vaultUrl => Promise<string>) // renova o src das imagens inseridas (data-vault-src)
60
+
49
61
  editor.schedulePaginate() // repagina (após mudar algo que afeta altura por fora)
50
62
  editor.totalPages()
51
63
  editor.destroy()
@@ -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
 
@@ -92,6 +92,19 @@ declare function resolveTemplateVariables(html: string | null | undefined, value
92
92
  declare const POC_ASSET_SWAP = "pocAssetSwap";
93
93
  declare const PocDocument: Node<any, any>;
94
94
  declare const PocMinutaBlock: Node<any, any>;
95
+ /**
96
+ * Clique numa variável do case — a ponte documento → formulário. Disparado no
97
+ * DOM do editor (com bubbling), não em `window`: dois editores na página não
98
+ * se cruzam, e o host escuta no próprio elemento. `kind` diz o que foi
99
+ * clicado: chip de texto, `<img data-variable-id>` ou aviso de imagem faltando.
100
+ */
101
+ type VariableClickKind = 'text' | 'image' | 'missingImage';
102
+ declare function dispatchVariableClick(editor: Editor, detail: {
103
+ variableId: string | null;
104
+ parentBlockId: string | null;
105
+ text: string;
106
+ kind: VariableClickKind;
107
+ }): void;
95
108
  declare const PocHtmlIsland: Node<any, any>;
96
109
  /**
97
110
  * Aviso de imagem faltando — a caixa tracejada que o render emite quando a
@@ -113,7 +126,12 @@ declare const PocHtmlIsland: Node<any, any>;
113
126
  */
114
127
  declare const PocMissingImage: Node<any, any>;
115
128
  declare const PocVariableChip: Node<any, any>;
116
- /** `<span data-variable-id>` com o texto trocado — o que `setVariableValue` grava no chip */
129
+ /**
130
+ * `<span data-variable-id>` com o texto trocado — o que `setVariableValue` grava
131
+ * no chip. O aviso de variável sem valor (`data-invalid-variable`, vermelho)
132
+ * é o mesmo nó: ao receber um valor ele vira chip comum — perde a marca de
133
+ * inválido e o estilo do aviso, mantém id, bloco e índice.
134
+ */
117
135
  declare function variableChipHtml(currentHtml: string, text: string): string;
118
136
  /**
119
137
  * Placeholder de variável do TEMPLATE — o `#NOME_VARIAVEL` de antigamente, só
@@ -198,12 +216,14 @@ interface MinutaChromeText {
198
216
  footerScope?: 'all' | 'first';
199
217
  showPageNumber?: boolean;
200
218
  }
201
- /** uma variável do case dentro do documento (`<span data-variable-id>`) */
219
+ /** uma variável do case dentro do documento (`<span data-variable-id>`, `<img data-variable-id>` ou aviso de imagem faltando) */
202
220
  interface MinutaVariableRef {
203
221
  variableId: string;
204
222
  parentBlockId: string | null;
205
- /** texto atual do trecho */
223
+ /** texto atual do trecho (vazio para imagens) */
206
224
  text: string;
225
+ /** o que foi clicado: chip de texto, imagem marcada, ou o aviso de imagem faltando */
226
+ kind: 'text' | 'image' | 'missingImage';
207
227
  }
208
228
  interface MinutaEditorOptions {
209
229
  /** documento inicial (HTML) */
@@ -252,8 +272,10 @@ interface MinutaEditorOptions {
252
272
  /** clique no cabeçalho/rodapé da folha (além do CustomEvent `poc:edit-chrome`) */
253
273
  onEditChrome?: (part: 'header' | 'footer') => void;
254
274
  /**
255
- * Clique numa variável renderizada (`<span data-variable-id>` do documento).
256
- * É a ponte documento → formulário: o host recebe o id e foca o campo.
275
+ * Clique numa variável renderizada: chip de texto (`<span data-variable-id>`),
276
+ * imagem marcada (`<img data-variable-id>`) ou aviso de imagem faltando —
277
+ * `kind` diz qual. É a ponte documento → formulário: o host recebe o id e
278
+ * foca o campo.
257
279
  */
258
280
  onVariableClick?: (variable: MinutaVariableRef) => void;
259
281
  onError?: (message: string) => void;
@@ -291,7 +313,9 @@ interface MinutaEditor {
291
313
  * Troca o texto de TODAS as ocorrências da variável no documento — inclusive
292
314
  * numa edição livre, porque a marca é um nó e sobrevive à lapidação. É o que
293
315
  * deixa um formulário de variáveis continuar valendo depois que o advogado
294
- * editou o texto em volta. Devolve quantas ocorrências mudaram.
316
+ * editou o texto em volta. O aviso de variável sem valor
317
+ * (`data-invalid-variable`) também é uma ocorrência: ao receber valor vira
318
+ * chip comum. Devolve quantas ocorrências mudaram.
295
319
  */
296
320
  setVariableValue: (variableId: string, value: string) => number;
297
321
  /**
@@ -302,6 +326,13 @@ interface MinutaEditor {
302
326
  setVariableImage: (variableId: string, src: string) => number;
303
327
  /** ids marcados no documento, na ordem, sem repetição: chips de texto, imagens e imagens faltando */
304
328
  variablesInDocument: () => string[];
329
+ /**
330
+ * Renova o `src` das imagens inseridas no editor (as que têm `data-vault-src`):
331
+ * o presignado do upload expira, então quem reabre uma edição salva passa
332
+ * um resolvedor `vault://` → URL nova (no defesa.ai, `POST /data/vault/download-url`).
333
+ * Devolve quantos nós mudaram. Não entra no undo nem dispara `onChange`.
334
+ */
335
+ refreshVaultImages: (resolveUrl: (vaultUrl: string) => Promise<string>) => Promise<number>;
305
336
  /** repagina (o host chama após mudar algo que afeta altura fora do editor) */
306
337
  schedulePaginate: () => void;
307
338
  /** reconstrói cabeçalhos/rodapés com o chrome atual, sem repaginar */
@@ -401,6 +432,24 @@ declare function shouldMoveBreakToHeading(params: {
401
432
  capacity: number;
402
433
  }): boolean;
403
434
 
435
+ interface RefreshVaultImagesOptions {
436
+ /**
437
+ * Metadados extras da transação (ex.: a marca de "programática" do embed
438
+ * Nuxt, para o rastro de anotações não contar a troca como texto novo).
439
+ */
440
+ meta?: Record<string, unknown>;
441
+ }
442
+ /**
443
+ * Re-resolve todas as imagens `vault://` do documento: as inseridas pela
444
+ * toolbar entram com `src` presignado (funciona agora) e `data-vault-src`
445
+ * durável; como o presignado expira, quem reabre uma edição salva chama isto
446
+ * no load. `resolveUrl` recebe a `vault://` e devolve a URL nova (no defesa.ai,
447
+ * `POST /data/vault/download-url`). Devolve quantos nós mudaram.
448
+ *
449
+ * Fora do histórico de undo: renovar um link não é uma edição do advogado.
450
+ */
451
+ declare function refreshVaultImages(editor: Editor, resolveUrl: (vaultUrl: string) => Promise<string>, options?: RefreshVaultImagesOptions): Promise<number>;
452
+
404
453
  /**
405
454
  * Sanitização do HTML rico de cabeçalho/rodapé (chrome) — conteúdo criado em
406
455
  * contenteditable e PERSISTIDO (template.headers, case_edition.chrome). Sem
@@ -423,5 +472,5 @@ declare function escapeVaultAttr(value: string): string;
423
472
  declare function decodeVaultAttr(value: string): string;
424
473
  declare function vaultImageHtml(src: string, vaultUrl: string): string;
425
474
 
426
- export { A4_HEIGHT_PX, A4_WIDTH_PX, DEFAULT_MARGINS, DOC_FONTS, ICON_PATHS, POC_ASSET_SWAP, PocDocument, PocFootnoteRef, PocHtmlIsland, PocInlineStyle, PocMinutaBlock, PocMissingImage, PocPageConfig, PocStylePassthrough, PocStyledDiv, PocTemplateVariable, PocUnderline, PocVariableChip, buildPocExtensions, createMinutaEditor, decodeVaultAttr, escapeHtml, escapeVaultAttr, extractTemplateVariables, footnoteHtmlToRuns, footnoteSizePt, iconSvg, renumberPocFootnotes, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, shouldMoveBreakToHeading, variableChipHtml, vaultImageHtml };
427
- export type { FootnoteRun, MinutaChromeText, MinutaEditor, MinutaEditorOptions, MinutaHeader, MinutaMargins, MinutaVariableCatalog, MinutaVariableDef, MinutaVariableRef, PocKeepWithNextItem };
475
+ export { A4_HEIGHT_PX, A4_WIDTH_PX, DEFAULT_MARGINS, DOC_FONTS, ICON_PATHS, POC_ASSET_SWAP, PocDocument, PocFootnoteRef, PocHtmlIsland, PocInlineStyle, PocMinutaBlock, PocMissingImage, PocPageConfig, PocStylePassthrough, PocStyledDiv, PocTemplateVariable, PocUnderline, PocVariableChip, buildPocExtensions, createMinutaEditor, decodeVaultAttr, dispatchVariableClick, escapeHtml, escapeVaultAttr, extractTemplateVariables, footnoteHtmlToRuns, footnoteSizePt, iconSvg, refreshVaultImages, renumberPocFootnotes, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, shouldMoveBreakToHeading, variableChipHtml, vaultImageHtml };
476
+ export type { FootnoteRun, MinutaChromeText, MinutaEditor, MinutaEditorOptions, MinutaHeader, MinutaMargins, MinutaVariableCatalog, MinutaVariableDef, MinutaVariableRef, PocKeepWithNextItem, RefreshVaultImagesOptions, VariableClickKind };
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
 
@@ -92,6 +92,19 @@ declare function resolveTemplateVariables(html: string | null | undefined, value
92
92
  declare const POC_ASSET_SWAP = "pocAssetSwap";
93
93
  declare const PocDocument: Node<any, any>;
94
94
  declare const PocMinutaBlock: Node<any, any>;
95
+ /**
96
+ * Clique numa variável do case — a ponte documento → formulário. Disparado no
97
+ * DOM do editor (com bubbling), não em `window`: dois editores na página não
98
+ * se cruzam, e o host escuta no próprio elemento. `kind` diz o que foi
99
+ * clicado: chip de texto, `<img data-variable-id>` ou aviso de imagem faltando.
100
+ */
101
+ type VariableClickKind = 'text' | 'image' | 'missingImage';
102
+ declare function dispatchVariableClick(editor: Editor, detail: {
103
+ variableId: string | null;
104
+ parentBlockId: string | null;
105
+ text: string;
106
+ kind: VariableClickKind;
107
+ }): void;
95
108
  declare const PocHtmlIsland: Node<any, any>;
96
109
  /**
97
110
  * Aviso de imagem faltando — a caixa tracejada que o render emite quando a
@@ -113,7 +126,12 @@ declare const PocHtmlIsland: Node<any, any>;
113
126
  */
114
127
  declare const PocMissingImage: Node<any, any>;
115
128
  declare const PocVariableChip: Node<any, any>;
116
- /** `<span data-variable-id>` com o texto trocado — o que `setVariableValue` grava no chip */
129
+ /**
130
+ * `<span data-variable-id>` com o texto trocado — o que `setVariableValue` grava
131
+ * no chip. O aviso de variável sem valor (`data-invalid-variable`, vermelho)
132
+ * é o mesmo nó: ao receber um valor ele vira chip comum — perde a marca de
133
+ * inválido e o estilo do aviso, mantém id, bloco e índice.
134
+ */
117
135
  declare function variableChipHtml(currentHtml: string, text: string): string;
118
136
  /**
119
137
  * Placeholder de variável do TEMPLATE — o `#NOME_VARIAVEL` de antigamente, só
@@ -198,12 +216,14 @@ interface MinutaChromeText {
198
216
  footerScope?: 'all' | 'first';
199
217
  showPageNumber?: boolean;
200
218
  }
201
- /** uma variável do case dentro do documento (`<span data-variable-id>`) */
219
+ /** uma variável do case dentro do documento (`<span data-variable-id>`, `<img data-variable-id>` ou aviso de imagem faltando) */
202
220
  interface MinutaVariableRef {
203
221
  variableId: string;
204
222
  parentBlockId: string | null;
205
- /** texto atual do trecho */
223
+ /** texto atual do trecho (vazio para imagens) */
206
224
  text: string;
225
+ /** o que foi clicado: chip de texto, imagem marcada, ou o aviso de imagem faltando */
226
+ kind: 'text' | 'image' | 'missingImage';
207
227
  }
208
228
  interface MinutaEditorOptions {
209
229
  /** documento inicial (HTML) */
@@ -252,8 +272,10 @@ interface MinutaEditorOptions {
252
272
  /** clique no cabeçalho/rodapé da folha (além do CustomEvent `poc:edit-chrome`) */
253
273
  onEditChrome?: (part: 'header' | 'footer') => void;
254
274
  /**
255
- * Clique numa variável renderizada (`<span data-variable-id>` do documento).
256
- * É a ponte documento → formulário: o host recebe o id e foca o campo.
275
+ * Clique numa variável renderizada: chip de texto (`<span data-variable-id>`),
276
+ * imagem marcada (`<img data-variable-id>`) ou aviso de imagem faltando —
277
+ * `kind` diz qual. É a ponte documento → formulário: o host recebe o id e
278
+ * foca o campo.
257
279
  */
258
280
  onVariableClick?: (variable: MinutaVariableRef) => void;
259
281
  onError?: (message: string) => void;
@@ -291,7 +313,9 @@ interface MinutaEditor {
291
313
  * Troca o texto de TODAS as ocorrências da variável no documento — inclusive
292
314
  * numa edição livre, porque a marca é um nó e sobrevive à lapidação. É o que
293
315
  * deixa um formulário de variáveis continuar valendo depois que o advogado
294
- * editou o texto em volta. Devolve quantas ocorrências mudaram.
316
+ * editou o texto em volta. O aviso de variável sem valor
317
+ * (`data-invalid-variable`) também é uma ocorrência: ao receber valor vira
318
+ * chip comum. Devolve quantas ocorrências mudaram.
295
319
  */
296
320
  setVariableValue: (variableId: string, value: string) => number;
297
321
  /**
@@ -302,6 +326,13 @@ interface MinutaEditor {
302
326
  setVariableImage: (variableId: string, src: string) => number;
303
327
  /** ids marcados no documento, na ordem, sem repetição: chips de texto, imagens e imagens faltando */
304
328
  variablesInDocument: () => string[];
329
+ /**
330
+ * Renova o `src` das imagens inseridas no editor (as que têm `data-vault-src`):
331
+ * o presignado do upload expira, então quem reabre uma edição salva passa
332
+ * um resolvedor `vault://` → URL nova (no defesa.ai, `POST /data/vault/download-url`).
333
+ * Devolve quantos nós mudaram. Não entra no undo nem dispara `onChange`.
334
+ */
335
+ refreshVaultImages: (resolveUrl: (vaultUrl: string) => Promise<string>) => Promise<number>;
305
336
  /** repagina (o host chama após mudar algo que afeta altura fora do editor) */
306
337
  schedulePaginate: () => void;
307
338
  /** reconstrói cabeçalhos/rodapés com o chrome atual, sem repaginar */
@@ -401,6 +432,24 @@ declare function shouldMoveBreakToHeading(params: {
401
432
  capacity: number;
402
433
  }): boolean;
403
434
 
435
+ interface RefreshVaultImagesOptions {
436
+ /**
437
+ * Metadados extras da transação (ex.: a marca de "programática" do embed
438
+ * Nuxt, para o rastro de anotações não contar a troca como texto novo).
439
+ */
440
+ meta?: Record<string, unknown>;
441
+ }
442
+ /**
443
+ * Re-resolve todas as imagens `vault://` do documento: as inseridas pela
444
+ * toolbar entram com `src` presignado (funciona agora) e `data-vault-src`
445
+ * durável; como o presignado expira, quem reabre uma edição salva chama isto
446
+ * no load. `resolveUrl` recebe a `vault://` e devolve a URL nova (no defesa.ai,
447
+ * `POST /data/vault/download-url`). Devolve quantos nós mudaram.
448
+ *
449
+ * Fora do histórico de undo: renovar um link não é uma edição do advogado.
450
+ */
451
+ declare function refreshVaultImages(editor: Editor, resolveUrl: (vaultUrl: string) => Promise<string>, options?: RefreshVaultImagesOptions): Promise<number>;
452
+
404
453
  /**
405
454
  * Sanitização do HTML rico de cabeçalho/rodapé (chrome) — conteúdo criado em
406
455
  * contenteditable e PERSISTIDO (template.headers, case_edition.chrome). Sem
@@ -423,5 +472,5 @@ declare function escapeVaultAttr(value: string): string;
423
472
  declare function decodeVaultAttr(value: string): string;
424
473
  declare function vaultImageHtml(src: string, vaultUrl: string): string;
425
474
 
426
- export { A4_HEIGHT_PX, A4_WIDTH_PX, DEFAULT_MARGINS, DOC_FONTS, ICON_PATHS, POC_ASSET_SWAP, PocDocument, PocFootnoteRef, PocHtmlIsland, PocInlineStyle, PocMinutaBlock, PocMissingImage, PocPageConfig, PocStylePassthrough, PocStyledDiv, PocTemplateVariable, PocUnderline, PocVariableChip, buildPocExtensions, createMinutaEditor, decodeVaultAttr, escapeHtml, escapeVaultAttr, extractTemplateVariables, footnoteHtmlToRuns, footnoteSizePt, iconSvg, renumberPocFootnotes, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, shouldMoveBreakToHeading, variableChipHtml, vaultImageHtml };
427
- export type { FootnoteRun, MinutaChromeText, MinutaEditor, MinutaEditorOptions, MinutaHeader, MinutaMargins, MinutaVariableCatalog, MinutaVariableDef, MinutaVariableRef, PocKeepWithNextItem };
475
+ export { A4_HEIGHT_PX, A4_WIDTH_PX, DEFAULT_MARGINS, DOC_FONTS, ICON_PATHS, POC_ASSET_SWAP, PocDocument, PocFootnoteRef, PocHtmlIsland, PocInlineStyle, PocMinutaBlock, PocMissingImage, PocPageConfig, PocStylePassthrough, PocStyledDiv, PocTemplateVariable, PocUnderline, PocVariableChip, buildPocExtensions, createMinutaEditor, decodeVaultAttr, dispatchVariableClick, escapeHtml, escapeVaultAttr, extractTemplateVariables, footnoteHtmlToRuns, footnoteSizePt, iconSvg, refreshVaultImages, renumberPocFootnotes, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, shouldMoveBreakToHeading, variableChipHtml, vaultImageHtml };
476
+ export type { FootnoteRun, MinutaChromeText, MinutaEditor, MinutaEditorOptions, MinutaHeader, MinutaMargins, MinutaVariableCatalog, MinutaVariableDef, MinutaVariableRef, PocKeepWithNextItem, RefreshVaultImagesOptions, VariableClickKind };