@meistrari/minuta-editor 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -61,6 +61,13 @@ editor.setImageFallback('dataUri' | 'none')
61
61
  editor.variablesInDocument() // → string[]
62
62
  editor.refreshVaultImages(vaultUrl => Promise<string>) // renova o src das imagens do vault (data-vault-src ou src="vault://"); sem undo/onChange
63
63
 
64
+ // checklist junto da edição (o documento gerado vem do GET /data/case/:id/html?source=blocks)
65
+ editor.stampGenerated() // ao CRIAR a edição a partir do HTML do checklist: marca os blocos como "gerados"
66
+ editor.applyChecklist(htmlGerado, { toggled? }) // → { inserted, removed, regenerated, variablesUpdated, conflicts, … }
67
+ editor.checklistConflicts() // → [{ blockId, blockTitle, kind: 'replace' | 'remove' }]
68
+ editor.resolveChecklistConflict(blockId, 'keep' | 'apply')
69
+ editor.documentBlockIds() // → blocos no texto, na ordem
70
+
64
71
  editor.schedulePaginate() // repagina (após mudar algo que afeta altura por fora)
65
72
  editor.totalPages()
66
73
  editor.destroy()
package/dist/index.d.mts CHANGED
@@ -22,7 +22,7 @@ import { Transaction } from '@tiptap/pm/state';
22
22
  import { EditorView } from '@tiptap/pm/view';
23
23
  import { P as PocPageConfig } from './shared/minuta-editor.9e65d163.mjs';
24
24
  export { e as PAGINATE_META, a as PocDocxChrome, b as PocDocxExportOptions, s as PocLoneRow, d as PocPageBreak, c as PocPageNote, v as PocPaginationPlugin, u as breaksEqual, h as buildPocFooterEl, g as buildPocHeaderEl, j as buildPocNotesEl, l as computePocBreaks, t as computePocLoneRows, i as isPocChromeCanvas, n as isPocFlexRow, f as pocChromeFlowHeight, m as pocDescendsInto, r as pocLoneCellIndex, k as pocLooksLikeTitle, o as pocNodeHasVisibleContent, q as pocNodePaintsBox, p as pocPageKey } from './shared/minuta-editor.9e65d163.mjs';
25
- import '@tiptap/pm/model';
25
+ import { Node as Node$1 } from '@tiptap/pm/model';
26
26
 
27
27
  /**
28
28
  * Variáveis de template da minuta — o formato do placeholder e a resolução dele.
@@ -206,6 +206,84 @@ declare function buildPocExtensions(pageConfig?: PocPageConfig, options?: {
206
206
  handleKeyDown?: (view: EditorView, event: KeyboardEvent) => boolean;
207
207
  }): (Node<any, any> | Extension<any, any> | Mark<any, any>)[];
208
208
 
209
+ /**
210
+ * Impressão digital de um bloco da minuta (nó `minutaBlock` do editor) — base
211
+ * de "o advogado mexeu neste trecho?" quando o checklist muda com uma edição
212
+ * viva. O bloco nasce com `genHash` = impressão do texto gerado; enquanto a
213
+ * impressão atual bater com ela, o trecho é do checklist e pode ser
214
+ * re-gerado sem perder nada.
215
+ *
216
+ * Fica de fora o que muda SEM o advogado editar:
217
+ * - URL descartável de imagem (blob:/placeholder do load progressivo/vault:// do
218
+ * save): a imagem entra pela identidade DURÁVEL (`imageIdentity`), então
219
+ * trocar a imagem de verdade muda a impressão;
220
+ * - número de tópico e de nota (re-sequenciam quando outro trecho muda);
221
+ * - valor das variáveis (o chip é atualizado no lugar, em qualquer bloco —
222
+ * inclusive dentro de lista/tabela guardada como HTML cru).
223
+ *
224
+ * Mesma regra em `client/utils/minutaBlockFingerprint.ts` (o app ainda mantém a
225
+ * cópia dele) — a impressão gravada por um tem que bater com a do outro.
226
+ *
227
+ * Recebe o JSON do nó (`node.toJSON()`), então é pura e não depende de DOM.
228
+ */
229
+ interface NodeJson {
230
+ type: string;
231
+ attrs?: Record<string, any>;
232
+ content?: NodeJson[];
233
+ marks?: {
234
+ type: string;
235
+ attrs?: Record<string, any>;
236
+ }[];
237
+ text?: string;
238
+ }
239
+ /**
240
+ * Identidade durável de uma imagem a partir do `src` (e do `data-vault-src` do
241
+ * placeholder do load progressivo) — no app, blob: do cache → vault://.
242
+ */
243
+ type ImageIdentity = (src: string) => string;
244
+ declare function minutaBlockFingerprint(blockJson: NodeJson, identity?: ImageIdentity): string;
245
+
246
+ /**
247
+ * Checklist × edição viva, para quem usa o editor fora do defesa.ai.
248
+ *
249
+ * O documento editado continua dividido em `minutaBlock` (um por bloco do
250
+ * template, `isolating`), e cada bloco guarda em `genHash` a impressão digital
251
+ * do texto que o checklist gerou. Com isso, quando o checklist muda (tese que
252
+ * passou a valer, variável alterada), dá para aplicar a mudança SÓ onde ela
253
+ * cai, sem passar por cima do que o advogado escreveu:
254
+ *
255
+ * - tese que passou a gerar texto → o bloco entra na posição do template;
256
+ * - tese que deixou de gerar → o bloco sai (se foi editado, vira conflito);
257
+ * - variável alterada → o chip atualiza no lugar, em qualquer bloco;
258
+ * - bloco cuja ESTRUTURA mudou → re-gerado se ninguém o editou, conflito se sim.
259
+ *
260
+ * Mesma lógica de `client/composables/poc/pocEditionSync.ts` + o
261
+ * `syncEditionWithChecklist` do app; aqui o documento gerado chega pronto (o
262
+ * `GET /data/case/:id/html?source=blocks`), em vez de renderizado no browser.
263
+ */
264
+ interface MinutaChecklistConflict {
265
+ blockId: string;
266
+ blockTitle: string | null;
267
+ /** `replace`: o checklist mudou o texto de um trecho editado; `remove`: desligou uma tese editada */
268
+ kind: 'replace' | 'remove';
269
+ }
270
+ interface MinutaChecklistResult {
271
+ inserted: string[];
272
+ removed: string[];
273
+ regenerated: string[];
274
+ /** quantos chips de variável mudaram de valor */
275
+ variablesUpdated: number;
276
+ /** conflitos abertos depois desta aplicação (inclui os que já estavam) */
277
+ conflicts: MinutaChecklistConflict[];
278
+ /** a tese pedida em `toggled.show` não gera texto (condições internas) */
279
+ toggledWithoutContent: boolean;
280
+ /** a remoção não aconteceu porque o documento ficaria sem nenhum bloco */
281
+ lastBlockKept: boolean;
282
+ }
283
+ declare function blockHash(node: Node$1, identity?: ImageIdentity): string;
284
+ /** o conteúdo ainda é o que o checklist gerou (sem `genHash` = editado, por segurança) */
285
+ declare function isBlockUntouched(node: Node$1, identity?: ImageIdentity): boolean;
286
+
209
287
  /**
210
288
  * O editor de minuta como coisa montável em qualquer lugar: `createMinutaEditor(el, opts)`.
211
289
  *
@@ -374,6 +452,35 @@ interface MinutaEditor {
374
452
  * guarda uma cópia do documento.
375
453
  */
376
454
  refreshVaultImages: (resolveUrl: (vaultUrl: string) => Promise<string>) => Promise<number>;
455
+ /**
456
+ * Checklist junto da edição: aplica o documento GERADO pelo checklist agora
457
+ * (o `GET /data/case/:id/html?source=blocks`) sobre o documento editado,
458
+ * bloco a bloco — tese que passou a valer entra na posição do template, a
459
+ * que deixou de valer sai, variáveis atualizam no lugar e trecho cuja
460
+ * estrutura mudou é re-gerado só se ninguém o editou (senão vira conflito).
461
+ * `toggled` força a decisão de UMA tese (o host ligou/desligou na mão).
462
+ * Uma transação só: o desfazer volta tudo. Blocos novos (e os aceitos em
463
+ * `resolveChecklistConflict`) podem trazer imagem `vault://` — chame
464
+ * `refreshVaultImages` depois de aplicar E de resolver os conflitos.
465
+ */
466
+ applyChecklist: (generatedHtml: string, options?: {
467
+ toggled?: {
468
+ blockId: string;
469
+ show: boolean;
470
+ };
471
+ }) => MinutaChecklistResult;
472
+ /** trechos editados que o checklist quer mudar e aguardam decisão do advogado */
473
+ checklistConflicts: () => MinutaChecklistConflict[];
474
+ /** `apply` usa o texto novo (ou remove); `keep` mantém o editado e não pergunta de novo pela mesma mudança */
475
+ resolveChecklistConflict: (blockId: string, resolution: 'keep' | 'apply') => boolean;
476
+ /**
477
+ * Marca todos os blocos como "texto gerado". Chame UMA vez ao criar a edição
478
+ * a partir do HTML do checklist — sem a marca, todo bloco conta como editado
479
+ * e o `applyChecklist` pergunta em vez de re-gerar. Devolve quantos marcou.
480
+ */
481
+ stampGenerated: () => number;
482
+ /** blocos (`data-block-id`) no documento, na ordem — para o checklist mostrar o que está no texto */
483
+ documentBlockIds: () => string[];
377
484
  /** repagina (o host chama após mudar algo que afeta altura fora do editor) */
378
485
  schedulePaginate: () => void;
379
486
  /** reconstrói cabeçalhos/rodapés com o chrome atual, sem repaginar */
@@ -561,5 +668,5 @@ declare function collectVaultRefs(html: string): string[];
561
668
  /** aplica as URLs resolvidas às `<img>` do trecho; tags sem resolução ficam como estão */
562
669
  declare function renewVaultImageTags(html: string, resolved: Map<string, string>): string;
563
670
 
564
- export { A4_HEIGHT_PX, A4_WIDTH_PX, DEFAULT_MARGINS, DOC_FONTS, ICON_PATHS, POC_ASSET_SWAP, PocDocument, PocFootnoteRef, PocHtmlIsland, PocInlineStyle, PocMinutaBlock, PocMissingImage, PocPageConfig, PocStylePassthrough, PocStyledDiv, PocTemplateVariable, PocTopicNumber, PocTopicRenumber, PocUnderline, PocVariableChip, TOPIC_DEFAULT_GROUP, TOPIC_GROUP_ATTR, TOPIC_NUMBER_ATTR, TOPIC_REF_ATTR, TOPIC_ROMAN_ATTR, buildPocExtensions, collectVaultRefs, createMinutaEditor, decodeVaultAttr, dispatchVariableClick, escapeHtml, escapeVaultAttr, extractTemplateVariables, footnoteHtmlToRuns, footnoteSizePt, formatTopicNumber, fromRoman, iconSvg, readTopicNumber, refreshVaultImages, renewVaultImageTags, renumberPocFootnotes, renumberPocTopics, renumberPocTopicsIn, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, shouldMoveBreakToHeading, swapVaultSrc, toRoman, topicNumberHtml, variableChipHtml, vaultImageHtml, vaultRefOf };
565
- export type { FootnoteRun, MinutaChromeText, MinutaEditor, MinutaEditorOptions, MinutaHeader, MinutaMargins, MinutaVariableCatalog, MinutaVariableDef, MinutaVariableRef, PocKeepWithNextItem, RefreshVaultImagesOptions, TopicNumberInfo, VariableClickKind };
671
+ export { A4_HEIGHT_PX, A4_WIDTH_PX, DEFAULT_MARGINS, DOC_FONTS, ICON_PATHS, POC_ASSET_SWAP, PocDocument, PocFootnoteRef, PocHtmlIsland, PocInlineStyle, PocMinutaBlock, PocMissingImage, PocPageConfig, PocStylePassthrough, PocStyledDiv, PocTemplateVariable, PocTopicNumber, PocTopicRenumber, PocUnderline, PocVariableChip, TOPIC_DEFAULT_GROUP, TOPIC_GROUP_ATTR, TOPIC_NUMBER_ATTR, TOPIC_REF_ATTR, TOPIC_ROMAN_ATTR, blockHash, buildPocExtensions, collectVaultRefs, createMinutaEditor, decodeVaultAttr, dispatchVariableClick, escapeHtml, escapeVaultAttr, extractTemplateVariables, footnoteHtmlToRuns, footnoteSizePt, formatTopicNumber, fromRoman, iconSvg, isBlockUntouched, minutaBlockFingerprint, readTopicNumber, refreshVaultImages, renewVaultImageTags, renumberPocFootnotes, renumberPocTopics, renumberPocTopicsIn, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, shouldMoveBreakToHeading, swapVaultSrc, toRoman, topicNumberHtml, variableChipHtml, vaultImageHtml, vaultRefOf };
672
+ export type { FootnoteRun, ImageIdentity, MinutaChecklistConflict, MinutaChecklistResult, MinutaChromeText, MinutaEditor, MinutaEditorOptions, MinutaHeader, MinutaMargins, MinutaVariableCatalog, MinutaVariableDef, MinutaVariableRef, PocKeepWithNextItem, RefreshVaultImagesOptions, TopicNumberInfo, VariableClickKind };
package/dist/index.d.ts CHANGED
@@ -22,7 +22,7 @@ import { Transaction } from '@tiptap/pm/state';
22
22
  import { EditorView } from '@tiptap/pm/view';
23
23
  import { P as PocPageConfig } from './shared/minuta-editor.9e65d163.js';
24
24
  export { e as PAGINATE_META, a as PocDocxChrome, b as PocDocxExportOptions, s as PocLoneRow, d as PocPageBreak, c as PocPageNote, v as PocPaginationPlugin, u as breaksEqual, h as buildPocFooterEl, g as buildPocHeaderEl, j as buildPocNotesEl, l as computePocBreaks, t as computePocLoneRows, i as isPocChromeCanvas, n as isPocFlexRow, f as pocChromeFlowHeight, m as pocDescendsInto, r as pocLoneCellIndex, k as pocLooksLikeTitle, o as pocNodeHasVisibleContent, q as pocNodePaintsBox, p as pocPageKey } from './shared/minuta-editor.9e65d163.js';
25
- import '@tiptap/pm/model';
25
+ import { Node as Node$1 } from '@tiptap/pm/model';
26
26
 
27
27
  /**
28
28
  * Variáveis de template da minuta — o formato do placeholder e a resolução dele.
@@ -206,6 +206,84 @@ declare function buildPocExtensions(pageConfig?: PocPageConfig, options?: {
206
206
  handleKeyDown?: (view: EditorView, event: KeyboardEvent) => boolean;
207
207
  }): (Node<any, any> | Extension<any, any> | Mark<any, any>)[];
208
208
 
209
+ /**
210
+ * Impressão digital de um bloco da minuta (nó `minutaBlock` do editor) — base
211
+ * de "o advogado mexeu neste trecho?" quando o checklist muda com uma edição
212
+ * viva. O bloco nasce com `genHash` = impressão do texto gerado; enquanto a
213
+ * impressão atual bater com ela, o trecho é do checklist e pode ser
214
+ * re-gerado sem perder nada.
215
+ *
216
+ * Fica de fora o que muda SEM o advogado editar:
217
+ * - URL descartável de imagem (blob:/placeholder do load progressivo/vault:// do
218
+ * save): a imagem entra pela identidade DURÁVEL (`imageIdentity`), então
219
+ * trocar a imagem de verdade muda a impressão;
220
+ * - número de tópico e de nota (re-sequenciam quando outro trecho muda);
221
+ * - valor das variáveis (o chip é atualizado no lugar, em qualquer bloco —
222
+ * inclusive dentro de lista/tabela guardada como HTML cru).
223
+ *
224
+ * Mesma regra em `client/utils/minutaBlockFingerprint.ts` (o app ainda mantém a
225
+ * cópia dele) — a impressão gravada por um tem que bater com a do outro.
226
+ *
227
+ * Recebe o JSON do nó (`node.toJSON()`), então é pura e não depende de DOM.
228
+ */
229
+ interface NodeJson {
230
+ type: string;
231
+ attrs?: Record<string, any>;
232
+ content?: NodeJson[];
233
+ marks?: {
234
+ type: string;
235
+ attrs?: Record<string, any>;
236
+ }[];
237
+ text?: string;
238
+ }
239
+ /**
240
+ * Identidade durável de uma imagem a partir do `src` (e do `data-vault-src` do
241
+ * placeholder do load progressivo) — no app, blob: do cache → vault://.
242
+ */
243
+ type ImageIdentity = (src: string) => string;
244
+ declare function minutaBlockFingerprint(blockJson: NodeJson, identity?: ImageIdentity): string;
245
+
246
+ /**
247
+ * Checklist × edição viva, para quem usa o editor fora do defesa.ai.
248
+ *
249
+ * O documento editado continua dividido em `minutaBlock` (um por bloco do
250
+ * template, `isolating`), e cada bloco guarda em `genHash` a impressão digital
251
+ * do texto que o checklist gerou. Com isso, quando o checklist muda (tese que
252
+ * passou a valer, variável alterada), dá para aplicar a mudança SÓ onde ela
253
+ * cai, sem passar por cima do que o advogado escreveu:
254
+ *
255
+ * - tese que passou a gerar texto → o bloco entra na posição do template;
256
+ * - tese que deixou de gerar → o bloco sai (se foi editado, vira conflito);
257
+ * - variável alterada → o chip atualiza no lugar, em qualquer bloco;
258
+ * - bloco cuja ESTRUTURA mudou → re-gerado se ninguém o editou, conflito se sim.
259
+ *
260
+ * Mesma lógica de `client/composables/poc/pocEditionSync.ts` + o
261
+ * `syncEditionWithChecklist` do app; aqui o documento gerado chega pronto (o
262
+ * `GET /data/case/:id/html?source=blocks`), em vez de renderizado no browser.
263
+ */
264
+ interface MinutaChecklistConflict {
265
+ blockId: string;
266
+ blockTitle: string | null;
267
+ /** `replace`: o checklist mudou o texto de um trecho editado; `remove`: desligou uma tese editada */
268
+ kind: 'replace' | 'remove';
269
+ }
270
+ interface MinutaChecklistResult {
271
+ inserted: string[];
272
+ removed: string[];
273
+ regenerated: string[];
274
+ /** quantos chips de variável mudaram de valor */
275
+ variablesUpdated: number;
276
+ /** conflitos abertos depois desta aplicação (inclui os que já estavam) */
277
+ conflicts: MinutaChecklistConflict[];
278
+ /** a tese pedida em `toggled.show` não gera texto (condições internas) */
279
+ toggledWithoutContent: boolean;
280
+ /** a remoção não aconteceu porque o documento ficaria sem nenhum bloco */
281
+ lastBlockKept: boolean;
282
+ }
283
+ declare function blockHash(node: Node$1, identity?: ImageIdentity): string;
284
+ /** o conteúdo ainda é o que o checklist gerou (sem `genHash` = editado, por segurança) */
285
+ declare function isBlockUntouched(node: Node$1, identity?: ImageIdentity): boolean;
286
+
209
287
  /**
210
288
  * O editor de minuta como coisa montável em qualquer lugar: `createMinutaEditor(el, opts)`.
211
289
  *
@@ -374,6 +452,35 @@ interface MinutaEditor {
374
452
  * guarda uma cópia do documento.
375
453
  */
376
454
  refreshVaultImages: (resolveUrl: (vaultUrl: string) => Promise<string>) => Promise<number>;
455
+ /**
456
+ * Checklist junto da edição: aplica o documento GERADO pelo checklist agora
457
+ * (o `GET /data/case/:id/html?source=blocks`) sobre o documento editado,
458
+ * bloco a bloco — tese que passou a valer entra na posição do template, a
459
+ * que deixou de valer sai, variáveis atualizam no lugar e trecho cuja
460
+ * estrutura mudou é re-gerado só se ninguém o editou (senão vira conflito).
461
+ * `toggled` força a decisão de UMA tese (o host ligou/desligou na mão).
462
+ * Uma transação só: o desfazer volta tudo. Blocos novos (e os aceitos em
463
+ * `resolveChecklistConflict`) podem trazer imagem `vault://` — chame
464
+ * `refreshVaultImages` depois de aplicar E de resolver os conflitos.
465
+ */
466
+ applyChecklist: (generatedHtml: string, options?: {
467
+ toggled?: {
468
+ blockId: string;
469
+ show: boolean;
470
+ };
471
+ }) => MinutaChecklistResult;
472
+ /** trechos editados que o checklist quer mudar e aguardam decisão do advogado */
473
+ checklistConflicts: () => MinutaChecklistConflict[];
474
+ /** `apply` usa o texto novo (ou remove); `keep` mantém o editado e não pergunta de novo pela mesma mudança */
475
+ resolveChecklistConflict: (blockId: string, resolution: 'keep' | 'apply') => boolean;
476
+ /**
477
+ * Marca todos os blocos como "texto gerado". Chame UMA vez ao criar a edição
478
+ * a partir do HTML do checklist — sem a marca, todo bloco conta como editado
479
+ * e o `applyChecklist` pergunta em vez de re-gerar. Devolve quantos marcou.
480
+ */
481
+ stampGenerated: () => number;
482
+ /** blocos (`data-block-id`) no documento, na ordem — para o checklist mostrar o que está no texto */
483
+ documentBlockIds: () => string[];
377
484
  /** repagina (o host chama após mudar algo que afeta altura fora do editor) */
378
485
  schedulePaginate: () => void;
379
486
  /** reconstrói cabeçalhos/rodapés com o chrome atual, sem repaginar */
@@ -561,5 +668,5 @@ declare function collectVaultRefs(html: string): string[];
561
668
  /** aplica as URLs resolvidas às `<img>` do trecho; tags sem resolução ficam como estão */
562
669
  declare function renewVaultImageTags(html: string, resolved: Map<string, string>): string;
563
670
 
564
- export { A4_HEIGHT_PX, A4_WIDTH_PX, DEFAULT_MARGINS, DOC_FONTS, ICON_PATHS, POC_ASSET_SWAP, PocDocument, PocFootnoteRef, PocHtmlIsland, PocInlineStyle, PocMinutaBlock, PocMissingImage, PocPageConfig, PocStylePassthrough, PocStyledDiv, PocTemplateVariable, PocTopicNumber, PocTopicRenumber, PocUnderline, PocVariableChip, TOPIC_DEFAULT_GROUP, TOPIC_GROUP_ATTR, TOPIC_NUMBER_ATTR, TOPIC_REF_ATTR, TOPIC_ROMAN_ATTR, buildPocExtensions, collectVaultRefs, createMinutaEditor, decodeVaultAttr, dispatchVariableClick, escapeHtml, escapeVaultAttr, extractTemplateVariables, footnoteHtmlToRuns, footnoteSizePt, formatTopicNumber, fromRoman, iconSvg, readTopicNumber, refreshVaultImages, renewVaultImageTags, renumberPocFootnotes, renumberPocTopics, renumberPocTopicsIn, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, shouldMoveBreakToHeading, swapVaultSrc, toRoman, topicNumberHtml, variableChipHtml, vaultImageHtml, vaultRefOf };
565
- export type { FootnoteRun, MinutaChromeText, MinutaEditor, MinutaEditorOptions, MinutaHeader, MinutaMargins, MinutaVariableCatalog, MinutaVariableDef, MinutaVariableRef, PocKeepWithNextItem, RefreshVaultImagesOptions, TopicNumberInfo, VariableClickKind };
671
+ export { A4_HEIGHT_PX, A4_WIDTH_PX, DEFAULT_MARGINS, DOC_FONTS, ICON_PATHS, POC_ASSET_SWAP, PocDocument, PocFootnoteRef, PocHtmlIsland, PocInlineStyle, PocMinutaBlock, PocMissingImage, PocPageConfig, PocStylePassthrough, PocStyledDiv, PocTemplateVariable, PocTopicNumber, PocTopicRenumber, PocUnderline, PocVariableChip, TOPIC_DEFAULT_GROUP, TOPIC_GROUP_ATTR, TOPIC_NUMBER_ATTR, TOPIC_REF_ATTR, TOPIC_ROMAN_ATTR, blockHash, buildPocExtensions, collectVaultRefs, createMinutaEditor, decodeVaultAttr, dispatchVariableClick, escapeHtml, escapeVaultAttr, extractTemplateVariables, footnoteHtmlToRuns, footnoteSizePt, formatTopicNumber, fromRoman, iconSvg, isBlockUntouched, minutaBlockFingerprint, readTopicNumber, refreshVaultImages, renewVaultImageTags, renumberPocFootnotes, renumberPocTopics, renumberPocTopicsIn, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, shouldMoveBreakToHeading, swapVaultSrc, toRoman, topicNumberHtml, variableChipHtml, vaultImageHtml, vaultRefOf };
672
+ export type { FootnoteRun, ImageIdentity, MinutaChecklistConflict, MinutaChecklistResult, MinutaChromeText, MinutaEditor, MinutaEditorOptions, MinutaHeader, MinutaMargins, MinutaVariableCatalog, MinutaVariableDef, MinutaVariableRef, PocKeepWithNextItem, RefreshVaultImagesOptions, TopicNumberInfo, VariableClickKind };
package/dist/index.mjs CHANGED
@@ -24,6 +24,8 @@ import TableRow from '@tiptap/extension-table-row';
24
24
  import { Plugin } from '@tiptap/pm/state';
25
25
  import { s as sanitizeRichHtml, e as sanitizeFootnoteHtml, g as footnoteSizePt, T as TOPIC_DEFAULT_GROUP, h as TOPIC_NUMBER_ATTR, r as readTopicNumber, i as TOPIC_GROUP_ATTR, j as TOPIC_ROMAN_ATTR, k as TOPIC_REF_ATTR, a as formatTopicNumber, P as PocPaginationPlugin, l as computePocBreaks, m as pocPageKey, n as breaksEqual, o as PAGINATE_META } from './shared/minuta-editor.f1239e0b.mjs';
26
26
  export { v as buildPocFooterEl, u as buildPocHeaderEl, w as buildPocNotesEl, z as computePocLoneRows, f as footnoteHtmlToRuns, C as fromRoman, t as isPocChromeCanvas, y as isPocFlexRow, q as pocChromeFlowHeight, x as pocDescendsInto, p as pocLoneCellIndex, b as pocLooksLikeTitle, c as pocNodeHasVisibleContent, d as pocNodePaintsBox, A as shouldMoveBreakToHeading, B as toRoman, D as topicNumberHtml } from './shared/minuta-editor.f1239e0b.mjs';
27
+ import { closeHistory } from '@tiptap/pm/history';
28
+ import { DOMParser } from '@tiptap/pm/model';
27
29
  import '@tiptap/pm/view';
28
30
 
29
31
  const POC_ASSET_SWAP = "pocAssetSwap";
@@ -35,7 +37,18 @@ function htmlToDom(html) {
35
37
  const PocDocument = Node$1.create({
36
38
  name: "doc",
37
39
  topNode: true,
38
- content: "minutaBlock+"
40
+ content: "minutaBlock+",
41
+ addAttributes() {
42
+ return {
43
+ /**
44
+ * Estado do checklist × edição (engine/checklistSync): teses que o
45
+ * checklist queria no texto na última aplicação + conflitos abertos.
46
+ * Vive NO documento para o desfazer do editor voltar junto com o
47
+ * texto; não vai para o HTML (sem documento salvo, nasce do texto).
48
+ */
49
+ checklist: { default: null, rendered: false, parseHTML: () => null }
50
+ };
51
+ }
39
52
  });
40
53
  const PocMinutaBlock = Node$1.create({
41
54
  name: "minutaBlock",
@@ -291,6 +304,14 @@ const PocVariableChip = Node$1.create({
291
304
  return {
292
305
  variableId: { default: null },
293
306
  parentBlockId: { default: null },
307
+ /**
308
+ * linha do `<for>` — distingue a mesma variável em linhas diferentes
309
+ * (`data-loop-index` do app; `data-variable-index` da Data API)
310
+ */
311
+ loopIndex: {
312
+ default: null,
313
+ parseHTML: (el) => el.getAttribute("data-loop-index") ?? el.getAttribute("data-variable-index")
314
+ },
294
315
  html: { default: "" },
295
316
  text: { default: "" }
296
317
  };
@@ -302,6 +323,7 @@ const PocVariableChip = Node$1.create({
302
323
  getAttrs: (el) => ({
303
324
  variableId: el.getAttribute("data-variable-id"),
304
325
  parentBlockId: el.getAttribute("data-parent-block-id"),
326
+ loopIndex: el.getAttribute("data-loop-index") ?? el.getAttribute("data-variable-index"),
305
327
  html: el.outerHTML,
306
328
  text: el.textContent ?? ""
307
329
  })
@@ -728,7 +750,7 @@ const VARIABLE_TAG_RE = /<span\b[^>]*\bdata-minuta-var="([^"]*)"[^>]*>[^<]*<\/sp
728
750
  function escapeHtml(value) {
729
751
  return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
730
752
  }
731
- function decodeAttr(value) {
753
+ function decodeAttr$1(value) {
732
754
  return value.replace(/&quot;/g, '"').replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&amp;/g, "&");
733
755
  }
734
756
  function extractTemplateVariables(html) {
@@ -736,7 +758,7 @@ function extractTemplateVariables(html) {
736
758
  return [];
737
759
  const keys = [];
738
760
  for (const match of html.matchAll(VARIABLE_TAG_RE)) {
739
- const key = decodeAttr(match[1] ?? "").trim();
761
+ const key = decodeAttr$1(match[1] ?? "").trim();
740
762
  if (key && !keys.includes(key))
741
763
  keys.push(key);
742
764
  }
@@ -747,7 +769,7 @@ function resolveTemplateVariables(html, values) {
747
769
  return { html: "", missing: [] };
748
770
  const missing = [];
749
771
  const resolved = html.replace(VARIABLE_TAG_RE, (tag, rawKey) => {
750
- const key = decodeAttr(rawKey ?? "").trim();
772
+ const key = decodeAttr$1(rawKey ?? "").trim();
751
773
  if (!key)
752
774
  return tag;
753
775
  const value = values?.[key];
@@ -864,6 +886,362 @@ async function refreshVaultImages(editor, resolveUrl, options = {}) {
864
886
  return touched;
865
887
  }
866
888
 
889
+ const IMG_TAG = /<img\b[^>]*>/g;
890
+ const ATTR = (name) => new RegExp(`\\s${name}="([^"]*)"`);
891
+ function decodeAttr(value) {
892
+ return value.replace(/&quot;/g, '"').replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&amp;/g, "&");
893
+ }
894
+ function normalizeImgTags(html, identity) {
895
+ if (!html.includes("<img"))
896
+ return html;
897
+ return html.replace(IMG_TAG, (tag) => {
898
+ const vault = tag.match(ATTR("data-vault-src"))?.[1];
899
+ const src = tag.match(ATTR("src"))?.[1] ?? "";
900
+ const id = vault ? decodeAttr(vault) : identity(decodeAttr(src));
901
+ return tag.replace(/\s(?:src|data-vault-src|data-download-url)="[^"]*"/g, "").replace(/^<img\b/, `<img data-img="${id}"`);
902
+ });
903
+ }
904
+ const CHIP_SPAN = /<span\b([^>]*\sdata-variable-id="[^"]*"[^>]*)>[\s\S]*?<\/span>/g;
905
+ function normalizeChipSpans(html) {
906
+ if (!html.includes("data-variable-id"))
907
+ return html;
908
+ return html.replace(CHIP_SPAN, (_all, attrs) => {
909
+ const id = attrs.match(/\sdata-variable-id="([^"]*)"/)?.[1] ?? "";
910
+ const index = attrs.match(/\sdata-(?:loop|variable)-index="([^"]*)"/)?.[1] ?? "";
911
+ return `<var:${id}:${index}>`;
912
+ });
913
+ }
914
+ function normalizeAttrs(attrs, identity, chipSpans = true) {
915
+ if (!attrs)
916
+ return void 0;
917
+ const out = {};
918
+ for (const key of Object.keys(attrs).sort()) {
919
+ if (key === "genHash" || key === "uid")
920
+ continue;
921
+ const value = attrs[key];
922
+ if (key === "src" && typeof value === "string") {
923
+ out[key] = identity(value);
924
+ } else {
925
+ out[key] = typeof value === "string" ? chipSpans ? normalizeChipSpans(normalizeImgTags(value, identity)) : normalizeImgTags(value, identity) : value;
926
+ }
927
+ }
928
+ return out;
929
+ }
930
+ function normalize(node, identity, chipSpans = true) {
931
+ switch (node.type) {
932
+ case "variableChip":
933
+ return ["var", node.attrs?.variableId ?? null];
934
+ case "topicNumber":
935
+ return ["topic", node.attrs?.group ?? null, !!node.attrs?.ref];
936
+ case "footnoteRef":
937
+ return ["note", node.attrs?.text ?? "", node.attrs?.size ?? null];
938
+ case "text":
939
+ return ["text", node.text ?? "", (node.marks ?? []).map((mark) => [mark.type, normalizeAttrs(mark.attrs, identity, chipSpans)])];
940
+ }
941
+ return [node.type, normalizeAttrs(node.attrs, identity, chipSpans), (node.content ?? []).map((child) => normalize(child, identity, chipSpans))];
942
+ }
943
+ function fnv1a(input) {
944
+ let hash = 2166136261;
945
+ for (let i = 0; i < input.length; i++) {
946
+ hash ^= input.charCodeAt(i);
947
+ hash = Math.imul(hash, 16777619);
948
+ }
949
+ return (hash >>> 0).toString(16).padStart(8, "0");
950
+ }
951
+ function minutaBlockFingerprint(blockJson, identity = (src) => src) {
952
+ const body = JSON.stringify((blockJson.content ?? []).map((child) => normalize(child, identity)));
953
+ return `${fnv1a(body)}${body.length.toString(16)}`;
954
+ }
955
+ function minutaBlockFingerprintV1(blockJson, identity = (src) => src) {
956
+ const body = JSON.stringify((blockJson.content ?? []).map((child) => normalize(child, identity, false)));
957
+ return `${fnv1a(body)}${body.length.toString(16)}`;
958
+ }
959
+
960
+ function readChecklist(doc) {
961
+ const stored = doc.attrs.checklist;
962
+ return stored ?? { wanted: [...docBlocks(doc).keys()], pending: [] };
963
+ }
964
+ const defaultImageIdentity = (src) => src;
965
+ function blockHash(node, identity = defaultImageIdentity) {
966
+ return minutaBlockFingerprint(node.toJSON(), identity);
967
+ }
968
+ function isBlockUntouched(node, identity = defaultImageIdentity) {
969
+ const genHash = node.attrs.genHash;
970
+ if (!genHash)
971
+ return false;
972
+ return genHash === blockHash(node, identity) || genHash === minutaBlockFingerprintV1(node.toJSON(), identity);
973
+ }
974
+ function docBlocks(doc) {
975
+ const map = /* @__PURE__ */ new Map();
976
+ doc.forEach((node, offset) => {
977
+ const id = node.attrs.blockId;
978
+ if (node.type.name === "minutaBlock" && id && !map.has(id))
979
+ map.set(id, { pos: offset, node });
980
+ });
981
+ return map;
982
+ }
983
+ function parseGeneratedBlocks(schema, html, identity = defaultImageIdentity) {
984
+ const wrapper = document.createElement("div");
985
+ wrapper.innerHTML = html;
986
+ const doc = DOMParser.fromSchema(schema).parse(wrapper);
987
+ const blocks = [];
988
+ doc.forEach((node) => {
989
+ if (node.type.name === "minutaBlock" && node.attrs.blockId)
990
+ blocks.push(node.type.create({ ...node.attrs, genHash: blockHash(node, identity) }, node.content, node.marks));
991
+ });
992
+ return blocks;
993
+ }
994
+ function stampGeneratedBlocks(editor, identity = defaultImageIdentity) {
995
+ const tr = editor.state.tr;
996
+ let stamped = 0;
997
+ editor.state.doc.forEach((node, offset) => {
998
+ if (node.type.name !== "minutaBlock")
999
+ return;
1000
+ const genHash = blockHash(node, identity);
1001
+ if (node.attrs.genHash !== genHash) {
1002
+ tr.setNodeMarkup(offset, void 0, { ...node.attrs, genHash });
1003
+ stamped++;
1004
+ }
1005
+ });
1006
+ if (tr.docChanged)
1007
+ editor.view.dispatch(tr);
1008
+ return stamped;
1009
+ }
1010
+ function baseChipKey(variableId, parentBlockId) {
1011
+ return `${parentBlockId ?? ""}|${variableId ?? ""}`;
1012
+ }
1013
+ function chipKey(variableId, parentBlockId, loopIndex) {
1014
+ return `${baseChipKey(variableId, parentBlockId)}|${loopIndex ?? ""}`;
1015
+ }
1016
+ function collectChips(html) {
1017
+ const wrapper = document.createElement("div");
1018
+ wrapper.innerHTML = html;
1019
+ const byKey = /* @__PURE__ */ new Map();
1020
+ const byBase = /* @__PURE__ */ new Map();
1021
+ wrapper.querySelectorAll("span[data-variable-id]").forEach((el) => {
1022
+ const variableId = el.getAttribute("data-variable-id");
1023
+ const parentBlockId = el.getAttribute("data-parent-block-id");
1024
+ const loopIndex = el.getAttribute("data-loop-index") ?? el.getAttribute("data-variable-index");
1025
+ const value = { html: el.outerHTML, text: el.textContent ?? "", loopIndex };
1026
+ for (const [map, key] of [[byKey, chipKey(variableId, parentBlockId, loopIndex)], [byBase, baseChipKey(variableId, parentBlockId)]]) {
1027
+ const list = map.get(key) ?? [];
1028
+ list.push(value);
1029
+ map.set(key, list);
1030
+ }
1031
+ });
1032
+ return { byKey, byBase };
1033
+ }
1034
+ function matchByValue(docChips, generated) {
1035
+ const pairs = [];
1036
+ const count = (list, text) => list.filter((t) => t === text).length;
1037
+ const docTexts = docChips.map((chip) => chip.node.attrs.text);
1038
+ const genTexts = generated.map((value) => value.text);
1039
+ const freeDoc = new Set(docChips.keys());
1040
+ const freeGen = new Set(generated.keys());
1041
+ docChips.forEach((chip, i) => {
1042
+ const text = docTexts[i];
1043
+ if (count(docTexts, text) !== 1 || count(genTexts, text) !== 1)
1044
+ return;
1045
+ const j = genTexts.indexOf(text);
1046
+ pairs.push({ ...chip, next: generated[j] });
1047
+ freeDoc.delete(i);
1048
+ freeGen.delete(j);
1049
+ });
1050
+ if (freeDoc.size === 1 && freeGen.size === 1) {
1051
+ const [i] = freeDoc;
1052
+ const [j] = freeGen;
1053
+ pairs.push({ ...docChips[i], next: generated[j] });
1054
+ }
1055
+ return pairs;
1056
+ }
1057
+ function refreshChips(tr, chips) {
1058
+ const inDoc = /* @__PURE__ */ new Map();
1059
+ tr.doc.descendants((node, pos) => {
1060
+ if (node.type.name !== "variableChip")
1061
+ return;
1062
+ const key = chipKey(node.attrs.variableId, node.attrs.parentBlockId, node.attrs.loopIndex);
1063
+ const list = inDoc.get(key) ?? [];
1064
+ list.push({ pos, node });
1065
+ inDoc.set(key, list);
1066
+ });
1067
+ let changed = 0;
1068
+ for (const [key, docChips] of inDoc) {
1069
+ let generated = chips.byKey.get(key);
1070
+ if (!generated?.length && docChips[0].node.attrs.loopIndex == null) {
1071
+ const { variableId, parentBlockId } = docChips[0].node.attrs;
1072
+ generated = chips.byBase.get(baseChipKey(variableId, parentBlockId));
1073
+ }
1074
+ if (!generated?.length)
1075
+ continue;
1076
+ const values = generated;
1077
+ const uniform = values.every((value) => value.html === values[0].html);
1078
+ const pairs = uniform ? docChips.map((chip) => ({ ...chip, next: values[0] })) : matchByValue(docChips, values);
1079
+ for (const { pos, node, next } of pairs) {
1080
+ const loopIndex = uniform ? node.attrs.loopIndex : next.loopIndex ?? node.attrs.loopIndex;
1081
+ if (next.html === node.attrs.html && loopIndex === node.attrs.loopIndex)
1082
+ continue;
1083
+ tr.setNodeMarkup(pos, void 0, { ...node.attrs, html: next.html, text: next.text, loopIndex });
1084
+ if (next.text !== node.attrs.text)
1085
+ changed++;
1086
+ }
1087
+ }
1088
+ return changed;
1089
+ }
1090
+ function refreshIslandChips(tr, chips) {
1091
+ let changed = 0;
1092
+ tr.doc.descendants((node, pos) => {
1093
+ if (node.type.name !== "htmlIsland" || !String(node.attrs.html ?? "").includes("data-variable-id"))
1094
+ return;
1095
+ const tpl = document.createElement("template");
1096
+ tpl.innerHTML = node.attrs.html;
1097
+ let touched = false;
1098
+ tpl.content.querySelectorAll("span[data-variable-id]").forEach((el) => {
1099
+ const key = chipKey(
1100
+ el.getAttribute("data-variable-id"),
1101
+ el.getAttribute("data-parent-block-id"),
1102
+ el.getAttribute("data-loop-index") ?? el.getAttribute("data-variable-index")
1103
+ );
1104
+ const values = chips.byKey.get(key);
1105
+ if (!values?.length || values.some((value) => value.html !== values[0].html))
1106
+ return;
1107
+ if (el.outerHTML !== values[0].html) {
1108
+ if (el.textContent !== values[0].text)
1109
+ changed++;
1110
+ el.outerHTML = values[0].html;
1111
+ touched = true;
1112
+ }
1113
+ });
1114
+ if (touched)
1115
+ tr.setNodeMarkup(pos, void 0, { ...node.attrs, html: tpl.innerHTML });
1116
+ return false;
1117
+ });
1118
+ return changed;
1119
+ }
1120
+ function insertPos(doc, blockId, order) {
1121
+ const present = docBlocks(doc);
1122
+ const index = order.indexOf(blockId);
1123
+ for (let i = index - 1; i >= 0; i--) {
1124
+ const prev = present.get(order[i]);
1125
+ if (prev)
1126
+ return prev.pos + prev.node.nodeSize;
1127
+ }
1128
+ return 0;
1129
+ }
1130
+ function listConflicts(doc) {
1131
+ return readChecklist(doc).pending.map(({ blockId, kind, title }) => ({ blockId, blockTitle: title, kind }));
1132
+ }
1133
+ function applyChecklistToDocument(editor, generatedHtml, options = {}) {
1134
+ const identity = options.imageIdentity ?? defaultImageIdentity;
1135
+ const generated = parseGeneratedBlocks(editor.schema, generatedHtml, identity);
1136
+ const genById = new Map(generated.map((node) => [node.attrs.blockId, node]));
1137
+ const order = generated.map((node) => node.attrs.blockId);
1138
+ const wanted = new Set(order);
1139
+ const stored = readChecklist(editor.state.doc);
1140
+ const before = new Set(stored.wanted);
1141
+ const previousPending = new Map(stored.pending.map((entry) => [entry.blockId, entry]));
1142
+ const pending = /* @__PURE__ */ new Map();
1143
+ const toggled = options.toggled;
1144
+ const tr = editor.state.tr;
1145
+ const result = {
1146
+ inserted: [],
1147
+ removed: [],
1148
+ regenerated: [],
1149
+ variablesUpdated: 0,
1150
+ conflicts: [],
1151
+ toggledWithoutContent: false,
1152
+ lastBlockKept: false
1153
+ };
1154
+ const setConflict = (id, kind, node, title) => {
1155
+ pending.set(id, { blockId: id, kind, title, node: node ? node.toJSON() : null });
1156
+ };
1157
+ const ids = [...order, ...[...docBlocks(tr.doc).keys()].filter((id) => !wanted.has(id))];
1158
+ if (toggled && !ids.includes(toggled.blockId))
1159
+ ids.push(toggled.blockId);
1160
+ for (const id of ids) {
1161
+ const fresh = genById.get(id) ?? null;
1162
+ const explicit = toggled?.blockId === id;
1163
+ const turnedOn = explicit ? toggled.show : !before.has(id) && !!fresh;
1164
+ const turnedOff = explicit ? !toggled.show : before.has(id) && !fresh;
1165
+ const present = docBlocks(tr.doc).get(id);
1166
+ if (!present) {
1167
+ if (turnedOn && fresh) {
1168
+ tr.insert(insertPos(tr.doc, id, order), fresh);
1169
+ result.inserted.push(id);
1170
+ } else if (explicit && toggled.show && !fresh) {
1171
+ result.toggledWithoutContent = true;
1172
+ }
1173
+ continue;
1174
+ }
1175
+ const untouched = isBlockUntouched(present.node, identity);
1176
+ const title = present.node.attrs.blockTitle ?? null;
1177
+ if (!fresh || turnedOff) {
1178
+ if (!turnedOff) {
1179
+ const open = previousPending.get(id);
1180
+ if (!untouched && open?.kind === "remove")
1181
+ pending.set(id, open);
1182
+ continue;
1183
+ }
1184
+ if (tr.doc.childCount <= 1) {
1185
+ result.lastBlockKept = true;
1186
+ continue;
1187
+ }
1188
+ if (untouched) {
1189
+ tr.delete(present.pos, present.pos + present.node.nodeSize);
1190
+ result.removed.push(id);
1191
+ } else {
1192
+ setConflict(id, "remove", null, title);
1193
+ }
1194
+ continue;
1195
+ }
1196
+ if (fresh.attrs.genHash === present.node.attrs.genHash)
1197
+ continue;
1198
+ if (untouched) {
1199
+ tr.replaceWith(present.pos, present.pos + present.node.nodeSize, fresh);
1200
+ result.regenerated.push(id);
1201
+ } else {
1202
+ setConflict(id, "replace", fresh, title);
1203
+ }
1204
+ }
1205
+ const chips = collectChips(generatedHtml);
1206
+ result.variablesUpdated = refreshChips(tr, chips) + refreshIslandChips(tr, chips);
1207
+ const next = { wanted: [...wanted], pending: [...pending.values()] };
1208
+ if (JSON.stringify(next) !== JSON.stringify(stored) || tr.docChanged)
1209
+ tr.setDocAttribute("checklist", next);
1210
+ if (tr.docChanged) {
1211
+ editor.view.dispatch(closeHistory(tr));
1212
+ }
1213
+ result.conflicts = next.pending.map(({ blockId, kind, title }) => ({ blockId, blockTitle: title, kind }));
1214
+ return result;
1215
+ }
1216
+ function resolveChecklistConflict(editor, blockId, resolution) {
1217
+ const stored = readChecklist(editor.state.doc);
1218
+ const entry = stored.pending.find((item) => item.blockId === blockId);
1219
+ const present = docBlocks(editor.state.doc).get(blockId);
1220
+ const tr = editor.state.tr;
1221
+ const rest = { ...stored, pending: stored.pending.filter((item) => item.blockId !== blockId) };
1222
+ if (!entry || !present) {
1223
+ if (entry) {
1224
+ tr.setDocAttribute("checklist", rest);
1225
+ editor.view.dispatch(tr);
1226
+ }
1227
+ return false;
1228
+ }
1229
+ if (resolution === "apply" && entry.kind === "remove" && editor.state.doc.childCount <= 1)
1230
+ return false;
1231
+ const fresh = entry.node ? editor.schema.nodeFromJSON(entry.node) : null;
1232
+ if (resolution === "apply") {
1233
+ if (entry.kind === "remove")
1234
+ tr.delete(present.pos, present.pos + present.node.nodeSize);
1235
+ else if (fresh)
1236
+ tr.replaceWith(present.pos, present.pos + present.node.nodeSize, fresh);
1237
+ } else if (entry.kind === "replace" && fresh) {
1238
+ tr.setNodeMarkup(present.pos, void 0, { ...present.node.attrs, genHash: fresh.attrs.genHash });
1239
+ }
1240
+ tr.setDocAttribute("checklist", rest);
1241
+ editor.view.dispatch(closeHistory(tr));
1242
+ return true;
1243
+ }
1244
+
867
1245
  function h(tag, attrs = {}, children = []) {
868
1246
  const el = document.createElement(tag);
869
1247
  if (attrs.class)
@@ -2167,6 +2545,32 @@ function createMinutaEditor(element, opts) {
2167
2545
  return Promise.resolve(0);
2168
2546
  return refreshVaultImages(ed, resolveUrl, { meta: { [POC_ASSET_SWAP]: true } });
2169
2547
  },
2548
+ applyChecklist(generatedHtml, options) {
2549
+ const ed = tiptap;
2550
+ if (!ed || ed.isDestroyed)
2551
+ throw new Error("editor n\xE3o montado");
2552
+ return applyChecklistToDocument(ed, generatedHtml, options ?? {});
2553
+ },
2554
+ checklistConflicts() {
2555
+ const ed = tiptap;
2556
+ return ed && !ed.isDestroyed ? listConflicts(ed.state.doc) : [];
2557
+ },
2558
+ resolveChecklistConflict(blockId, resolution) {
2559
+ const ed = tiptap;
2560
+ if (!ed || ed.isDestroyed)
2561
+ return false;
2562
+ return resolveChecklistConflict(ed, blockId, resolution);
2563
+ },
2564
+ stampGenerated() {
2565
+ const ed = tiptap;
2566
+ if (!ed || ed.isDestroyed)
2567
+ return 0;
2568
+ return stampGeneratedBlocks(ed);
2569
+ },
2570
+ documentBlockIds() {
2571
+ const ed = tiptap;
2572
+ return ed && !ed.isDestroyed ? [...docBlocks(ed.state.doc).keys()] : [];
2573
+ },
2170
2574
  schedulePaginate,
2171
2575
  refreshChrome,
2172
2576
  totalPages: () => totalPages,
@@ -2186,4 +2590,4 @@ function createMinutaEditor(element, opts) {
2186
2590
  return api;
2187
2591
  }
2188
2592
 
2189
- export { A4_HEIGHT_PX, A4_WIDTH_PX, DEFAULT_MARGINS, DOC_FONTS, ICON_PATHS, PAGINATE_META, POC_ASSET_SWAP, PocDocument, PocFootnoteRef, PocHtmlIsland, PocInlineStyle, PocMinutaBlock, PocMissingImage, PocPaginationPlugin, PocStylePassthrough, PocStyledDiv, PocTemplateVariable, PocTopicNumber, PocTopicRenumber, PocUnderline, PocVariableChip, TOPIC_DEFAULT_GROUP, TOPIC_GROUP_ATTR, TOPIC_NUMBER_ATTR, TOPIC_REF_ATTR, TOPIC_ROMAN_ATTR, breaksEqual, buildPocExtensions, collectVaultRefs, computePocBreaks, createMinutaEditor, decodeVaultAttr, dispatchVariableClick, escapeHtml, escapeVaultAttr, extractTemplateVariables, footnoteSizePt, formatTopicNumber, iconSvg, pocPageKey, readTopicNumber, refreshVaultImages, renewVaultImageTags, renumberPocFootnotes, renumberPocTopics, renumberPocTopicsIn, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, swapVaultSrc, variableChipHtml, vaultImageHtml, vaultRefOf };
2593
+ export { A4_HEIGHT_PX, A4_WIDTH_PX, DEFAULT_MARGINS, DOC_FONTS, ICON_PATHS, PAGINATE_META, POC_ASSET_SWAP, PocDocument, PocFootnoteRef, PocHtmlIsland, PocInlineStyle, PocMinutaBlock, PocMissingImage, PocPaginationPlugin, PocStylePassthrough, PocStyledDiv, PocTemplateVariable, PocTopicNumber, PocTopicRenumber, PocUnderline, PocVariableChip, TOPIC_DEFAULT_GROUP, TOPIC_GROUP_ATTR, TOPIC_NUMBER_ATTR, TOPIC_REF_ATTR, TOPIC_ROMAN_ATTR, blockHash, breaksEqual, buildPocExtensions, collectVaultRefs, computePocBreaks, createMinutaEditor, decodeVaultAttr, dispatchVariableClick, escapeHtml, escapeVaultAttr, extractTemplateVariables, footnoteSizePt, formatTopicNumber, iconSvg, isBlockUntouched, minutaBlockFingerprint, pocPageKey, readTopicNumber, refreshVaultImages, renewVaultImageTags, renumberPocFootnotes, renumberPocTopics, renumberPocTopicsIn, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, swapVaultSrc, variableChipHtml, vaultImageHtml, vaultRefOf };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meistrari/minuta-editor",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "description": "Editor de minuta do defesa.ai sem framework: folha A4 paginada, edição rica, placeholders de variável e export DOCX fiel ao preview — monta em qualquer app (React, Vue, vanilla)",
5
5
  "repository": {
6
6
  "type": "git",