@meistrari/minuta-editor 1.5.0 → 1.7.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 +13 -0
- package/dist/index.d.mts +134 -3
- package/dist/index.d.ts +134 -3
- package/dist/index.mjs +588 -6
- package/dist/style.css +1 -1
- package/package.json +1 -1
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()
|
|
@@ -79,6 +86,12 @@ sozinho toma uma decisão que não é dele.
|
|
|
79
86
|
(antd, Material…) monta a barra dele e fala com o Tiptap direto —
|
|
80
87
|
`editor.tiptap.chain().focus().toggleBold().run()`, `isActive('bold')`. É a API
|
|
81
88
|
do Tiptap, documentada, sem um wrapper de comandos que sempre falta um.
|
|
89
|
+
Os comandos próprios do editor seguem o mesmo caminho:
|
|
90
|
+
`toggleTopicNumber()` / `setTopicNumber()` / `unsetTopicNumber()` numeram o
|
|
91
|
+
parágrafo da seleção com o número de tópico da peça (o nó `topicNumber`, que
|
|
92
|
+
continua a sequência do template e sai como numeração nativa no Word — não é a
|
|
93
|
+
lista `<ol>`); `hasLeadingTopicNumber(editor.tiptap)` dá o estado do botão.
|
|
94
|
+
Enter num parágrafo numerado já continua a numeração sozinho.
|
|
82
95
|
|
|
83
96
|
**CSS em arquivo, com namespace.** Tudo vive sob `.poc-editor-root`, inclusive
|
|
84
97
|
as utilities atômicas que o defesa.ai tira do UnoCSS. Importe
|
package/dist/index.d.mts
CHANGED
|
@@ -18,11 +18,11 @@
|
|
|
18
18
|
/// <reference types="@tiptap/extension-table" />
|
|
19
19
|
/// <reference types="@tiptap/extension-bubble-menu" />
|
|
20
20
|
import { Node, Editor, Extension, Mark } from '@tiptap/core';
|
|
21
|
+
import { Node as Node$1 } from '@tiptap/pm/model';
|
|
21
22
|
import { Transaction } from '@tiptap/pm/state';
|
|
22
23
|
import { EditorView } from '@tiptap/pm/view';
|
|
23
24
|
import { P as PocPageConfig } from './shared/minuta-editor.9e65d163.mjs';
|
|
24
25
|
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';
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* Variáveis de template da minuta — o formato do placeholder e a resolução dele.
|
|
@@ -170,6 +170,18 @@ declare function renumberPocFootnotes(editor: Editor): void;
|
|
|
170
170
|
* nativa do Word, que também se refaz quando o advogado apaga um parágrafo lá.
|
|
171
171
|
* Contrato do marcador em `utils/topicNumber.ts`.
|
|
172
172
|
*/
|
|
173
|
+
declare module '@tiptap/core' {
|
|
174
|
+
interface Commands<ReturnType> {
|
|
175
|
+
topicNumber: {
|
|
176
|
+
/** numera os parágrafos da seleção (continua a sequência do parágrafo numerado mais próximo) */
|
|
177
|
+
setTopicNumber: () => ReturnType;
|
|
178
|
+
/** tira o número (e o separador colado nele) dos parágrafos da seleção */
|
|
179
|
+
unsetTopicNumber: () => ReturnType;
|
|
180
|
+
/** todos numerados → tira; senão numera os que faltam */
|
|
181
|
+
toggleTopicNumber: () => ReturnType;
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
}
|
|
173
185
|
declare const PocTopicNumber: Node<any, any>;
|
|
174
186
|
/**
|
|
175
187
|
* Re-sequencia os números de tópico na ordem do documento, por grupo, dentro
|
|
@@ -185,6 +197,18 @@ declare function renumberPocTopics(editor: Editor): void;
|
|
|
185
197
|
* parágrafo não custa nada além da varredura.
|
|
186
198
|
*/
|
|
187
199
|
declare const PocTopicRenumber: Extension<any, any>;
|
|
200
|
+
/** índice do nó de número que abre o parágrafo (só espaço antes dele; `ref` não conta), ou -1 */
|
|
201
|
+
declare function leadingTopicIndex(block: Node$1): number;
|
|
202
|
+
/** o parágrafo onde está o cursor começa com número de tópico (estado do botão da toolbar) */
|
|
203
|
+
declare function hasLeadingTopicNumber(editor: Editor): boolean;
|
|
204
|
+
/** numera / desnumera os parágrafos da seleção (atalho tipado para `commands.toggleTopicNumber`) */
|
|
205
|
+
declare function toggleTopicNumber(editor: Editor): boolean;
|
|
206
|
+
/**
|
|
207
|
+
* Enter num parágrafo numerado: o seguinte nasce numerado (continua a
|
|
208
|
+
* sequência). Enter num parágrafo que só tem o número tira o número — a
|
|
209
|
+
* mesma saída da lista que o Word dá.
|
|
210
|
+
*/
|
|
211
|
+
declare const PocTopicNumberKeymap: Extension<any, any>;
|
|
188
212
|
declare const PocStyledDiv: Node<any, any>;
|
|
189
213
|
declare const PocInlineStyle: Mark<any, any>;
|
|
190
214
|
declare const PocUnderline: Mark<any, any>;
|
|
@@ -206,6 +230,84 @@ declare function buildPocExtensions(pageConfig?: PocPageConfig, options?: {
|
|
|
206
230
|
handleKeyDown?: (view: EditorView, event: KeyboardEvent) => boolean;
|
|
207
231
|
}): (Node<any, any> | Extension<any, any> | Mark<any, any>)[];
|
|
208
232
|
|
|
233
|
+
/**
|
|
234
|
+
* Impressão digital de um bloco da minuta (nó `minutaBlock` do editor) — base
|
|
235
|
+
* de "o advogado mexeu neste trecho?" quando o checklist muda com uma edição
|
|
236
|
+
* viva. O bloco nasce com `genHash` = impressão do texto gerado; enquanto a
|
|
237
|
+
* impressão atual bater com ela, o trecho é do checklist e pode ser
|
|
238
|
+
* re-gerado sem perder nada.
|
|
239
|
+
*
|
|
240
|
+
* Fica de fora o que muda SEM o advogado editar:
|
|
241
|
+
* - URL descartável de imagem (blob:/placeholder do load progressivo/vault:// do
|
|
242
|
+
* save): a imagem entra pela identidade DURÁVEL (`imageIdentity`), então
|
|
243
|
+
* trocar a imagem de verdade muda a impressão;
|
|
244
|
+
* - número de tópico e de nota (re-sequenciam quando outro trecho muda);
|
|
245
|
+
* - valor das variáveis (o chip é atualizado no lugar, em qualquer bloco —
|
|
246
|
+
* inclusive dentro de lista/tabela guardada como HTML cru).
|
|
247
|
+
*
|
|
248
|
+
* Mesma regra em `client/utils/minutaBlockFingerprint.ts` (o app ainda mantém a
|
|
249
|
+
* cópia dele) — a impressão gravada por um tem que bater com a do outro.
|
|
250
|
+
*
|
|
251
|
+
* Recebe o JSON do nó (`node.toJSON()`), então é pura e não depende de DOM.
|
|
252
|
+
*/
|
|
253
|
+
interface NodeJson {
|
|
254
|
+
type: string;
|
|
255
|
+
attrs?: Record<string, any>;
|
|
256
|
+
content?: NodeJson[];
|
|
257
|
+
marks?: {
|
|
258
|
+
type: string;
|
|
259
|
+
attrs?: Record<string, any>;
|
|
260
|
+
}[];
|
|
261
|
+
text?: string;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Identidade durável de uma imagem a partir do `src` (e do `data-vault-src` do
|
|
265
|
+
* placeholder do load progressivo) — no app, blob: do cache → vault://.
|
|
266
|
+
*/
|
|
267
|
+
type ImageIdentity = (src: string) => string;
|
|
268
|
+
declare function minutaBlockFingerprint(blockJson: NodeJson, identity?: ImageIdentity): string;
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Checklist × edição viva, para quem usa o editor fora do defesa.ai.
|
|
272
|
+
*
|
|
273
|
+
* O documento editado continua dividido em `minutaBlock` (um por bloco do
|
|
274
|
+
* template, `isolating`), e cada bloco guarda em `genHash` a impressão digital
|
|
275
|
+
* do texto que o checklist gerou. Com isso, quando o checklist muda (tese que
|
|
276
|
+
* passou a valer, variável alterada), dá para aplicar a mudança SÓ onde ela
|
|
277
|
+
* cai, sem passar por cima do que o advogado escreveu:
|
|
278
|
+
*
|
|
279
|
+
* - tese que passou a gerar texto → o bloco entra na posição do template;
|
|
280
|
+
* - tese que deixou de gerar → o bloco sai (se foi editado, vira conflito);
|
|
281
|
+
* - variável alterada → o chip atualiza no lugar, em qualquer bloco;
|
|
282
|
+
* - bloco cuja ESTRUTURA mudou → re-gerado se ninguém o editou, conflito se sim.
|
|
283
|
+
*
|
|
284
|
+
* Mesma lógica de `client/composables/poc/pocEditionSync.ts` + o
|
|
285
|
+
* `syncEditionWithChecklist` do app; aqui o documento gerado chega pronto (o
|
|
286
|
+
* `GET /data/case/:id/html?source=blocks`), em vez de renderizado no browser.
|
|
287
|
+
*/
|
|
288
|
+
interface MinutaChecklistConflict {
|
|
289
|
+
blockId: string;
|
|
290
|
+
blockTitle: string | null;
|
|
291
|
+
/** `replace`: o checklist mudou o texto de um trecho editado; `remove`: desligou uma tese editada */
|
|
292
|
+
kind: 'replace' | 'remove';
|
|
293
|
+
}
|
|
294
|
+
interface MinutaChecklistResult {
|
|
295
|
+
inserted: string[];
|
|
296
|
+
removed: string[];
|
|
297
|
+
regenerated: string[];
|
|
298
|
+
/** quantos chips de variável mudaram de valor */
|
|
299
|
+
variablesUpdated: number;
|
|
300
|
+
/** conflitos abertos depois desta aplicação (inclui os que já estavam) */
|
|
301
|
+
conflicts: MinutaChecklistConflict[];
|
|
302
|
+
/** a tese pedida em `toggled.show` não gera texto (condições internas) */
|
|
303
|
+
toggledWithoutContent: boolean;
|
|
304
|
+
/** a remoção não aconteceu porque o documento ficaria sem nenhum bloco */
|
|
305
|
+
lastBlockKept: boolean;
|
|
306
|
+
}
|
|
307
|
+
declare function blockHash(node: Node$1, identity?: ImageIdentity): string;
|
|
308
|
+
/** o conteúdo ainda é o que o checklist gerou (sem `genHash` = editado, por segurança) */
|
|
309
|
+
declare function isBlockUntouched(node: Node$1, identity?: ImageIdentity): boolean;
|
|
310
|
+
|
|
209
311
|
/**
|
|
210
312
|
* O editor de minuta como coisa montável em qualquer lugar: `createMinutaEditor(el, opts)`.
|
|
211
313
|
*
|
|
@@ -374,6 +476,35 @@ interface MinutaEditor {
|
|
|
374
476
|
* guarda uma cópia do documento.
|
|
375
477
|
*/
|
|
376
478
|
refreshVaultImages: (resolveUrl: (vaultUrl: string) => Promise<string>) => Promise<number>;
|
|
479
|
+
/**
|
|
480
|
+
* Checklist junto da edição: aplica o documento GERADO pelo checklist agora
|
|
481
|
+
* (o `GET /data/case/:id/html?source=blocks`) sobre o documento editado,
|
|
482
|
+
* bloco a bloco — tese que passou a valer entra na posição do template, a
|
|
483
|
+
* que deixou de valer sai, variáveis atualizam no lugar e trecho cuja
|
|
484
|
+
* estrutura mudou é re-gerado só se ninguém o editou (senão vira conflito).
|
|
485
|
+
* `toggled` força a decisão de UMA tese (o host ligou/desligou na mão).
|
|
486
|
+
* Uma transação só: o desfazer volta tudo. Blocos novos (e os aceitos em
|
|
487
|
+
* `resolveChecklistConflict`) podem trazer imagem `vault://` — chame
|
|
488
|
+
* `refreshVaultImages` depois de aplicar E de resolver os conflitos.
|
|
489
|
+
*/
|
|
490
|
+
applyChecklist: (generatedHtml: string, options?: {
|
|
491
|
+
toggled?: {
|
|
492
|
+
blockId: string;
|
|
493
|
+
show: boolean;
|
|
494
|
+
};
|
|
495
|
+
}) => MinutaChecklistResult;
|
|
496
|
+
/** trechos editados que o checklist quer mudar e aguardam decisão do advogado */
|
|
497
|
+
checklistConflicts: () => MinutaChecklistConflict[];
|
|
498
|
+
/** `apply` usa o texto novo (ou remove); `keep` mantém o editado e não pergunta de novo pela mesma mudança */
|
|
499
|
+
resolveChecklistConflict: (blockId: string, resolution: 'keep' | 'apply') => boolean;
|
|
500
|
+
/**
|
|
501
|
+
* Marca todos os blocos como "texto gerado". Chame UMA vez ao criar a edição
|
|
502
|
+
* a partir do HTML do checklist — sem a marca, todo bloco conta como editado
|
|
503
|
+
* e o `applyChecklist` pergunta em vez de re-gerar. Devolve quantos marcou.
|
|
504
|
+
*/
|
|
505
|
+
stampGenerated: () => number;
|
|
506
|
+
/** blocos (`data-block-id`) no documento, na ordem — para o checklist mostrar o que está no texto */
|
|
507
|
+
documentBlockIds: () => string[];
|
|
377
508
|
/** repagina (o host chama após mudar algo que afeta altura fora do editor) */
|
|
378
509
|
schedulePaginate: () => void;
|
|
379
510
|
/** reconstrói cabeçalhos/rodapés com o chrome atual, sem repaginar */
|
|
@@ -561,5 +692,5 @@ declare function collectVaultRefs(html: string): string[];
|
|
|
561
692
|
/** aplica as URLs resolvidas às `<img>` do trecho; tags sem resolução ficam como estão */
|
|
562
693
|
declare function renewVaultImageTags(html: string, resolved: Map<string, string>): string;
|
|
563
694
|
|
|
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 };
|
|
695
|
+
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, PocTopicNumberKeymap, 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, hasLeadingTopicNumber, iconSvg, isBlockUntouched, leadingTopicIndex, minutaBlockFingerprint, readTopicNumber, refreshVaultImages, renewVaultImageTags, renumberPocFootnotes, renumberPocTopics, renumberPocTopicsIn, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, shouldMoveBreakToHeading, swapVaultSrc, toRoman, toggleTopicNumber, topicNumberHtml, variableChipHtml, vaultImageHtml, vaultRefOf };
|
|
696
|
+
export type { FootnoteRun, ImageIdentity, MinutaChecklistConflict, MinutaChecklistResult, MinutaChromeText, MinutaEditor, MinutaEditorOptions, MinutaHeader, MinutaMargins, MinutaVariableCatalog, MinutaVariableDef, MinutaVariableRef, PocKeepWithNextItem, RefreshVaultImagesOptions, TopicNumberInfo, VariableClickKind };
|
package/dist/index.d.ts
CHANGED
|
@@ -18,11 +18,11 @@
|
|
|
18
18
|
/// <reference types="@tiptap/extension-table" />
|
|
19
19
|
/// <reference types="@tiptap/extension-bubble-menu" />
|
|
20
20
|
import { Node, Editor, Extension, Mark } from '@tiptap/core';
|
|
21
|
+
import { Node as Node$1 } from '@tiptap/pm/model';
|
|
21
22
|
import { Transaction } from '@tiptap/pm/state';
|
|
22
23
|
import { EditorView } from '@tiptap/pm/view';
|
|
23
24
|
import { P as PocPageConfig } from './shared/minuta-editor.9e65d163.js';
|
|
24
25
|
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';
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* Variáveis de template da minuta — o formato do placeholder e a resolução dele.
|
|
@@ -170,6 +170,18 @@ declare function renumberPocFootnotes(editor: Editor): void;
|
|
|
170
170
|
* nativa do Word, que também se refaz quando o advogado apaga um parágrafo lá.
|
|
171
171
|
* Contrato do marcador em `utils/topicNumber.ts`.
|
|
172
172
|
*/
|
|
173
|
+
declare module '@tiptap/core' {
|
|
174
|
+
interface Commands<ReturnType> {
|
|
175
|
+
topicNumber: {
|
|
176
|
+
/** numera os parágrafos da seleção (continua a sequência do parágrafo numerado mais próximo) */
|
|
177
|
+
setTopicNumber: () => ReturnType;
|
|
178
|
+
/** tira o número (e o separador colado nele) dos parágrafos da seleção */
|
|
179
|
+
unsetTopicNumber: () => ReturnType;
|
|
180
|
+
/** todos numerados → tira; senão numera os que faltam */
|
|
181
|
+
toggleTopicNumber: () => ReturnType;
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
}
|
|
173
185
|
declare const PocTopicNumber: Node<any, any>;
|
|
174
186
|
/**
|
|
175
187
|
* Re-sequencia os números de tópico na ordem do documento, por grupo, dentro
|
|
@@ -185,6 +197,18 @@ declare function renumberPocTopics(editor: Editor): void;
|
|
|
185
197
|
* parágrafo não custa nada além da varredura.
|
|
186
198
|
*/
|
|
187
199
|
declare const PocTopicRenumber: Extension<any, any>;
|
|
200
|
+
/** índice do nó de número que abre o parágrafo (só espaço antes dele; `ref` não conta), ou -1 */
|
|
201
|
+
declare function leadingTopicIndex(block: Node$1): number;
|
|
202
|
+
/** o parágrafo onde está o cursor começa com número de tópico (estado do botão da toolbar) */
|
|
203
|
+
declare function hasLeadingTopicNumber(editor: Editor): boolean;
|
|
204
|
+
/** numera / desnumera os parágrafos da seleção (atalho tipado para `commands.toggleTopicNumber`) */
|
|
205
|
+
declare function toggleTopicNumber(editor: Editor): boolean;
|
|
206
|
+
/**
|
|
207
|
+
* Enter num parágrafo numerado: o seguinte nasce numerado (continua a
|
|
208
|
+
* sequência). Enter num parágrafo que só tem o número tira o número — a
|
|
209
|
+
* mesma saída da lista que o Word dá.
|
|
210
|
+
*/
|
|
211
|
+
declare const PocTopicNumberKeymap: Extension<any, any>;
|
|
188
212
|
declare const PocStyledDiv: Node<any, any>;
|
|
189
213
|
declare const PocInlineStyle: Mark<any, any>;
|
|
190
214
|
declare const PocUnderline: Mark<any, any>;
|
|
@@ -206,6 +230,84 @@ declare function buildPocExtensions(pageConfig?: PocPageConfig, options?: {
|
|
|
206
230
|
handleKeyDown?: (view: EditorView, event: KeyboardEvent) => boolean;
|
|
207
231
|
}): (Node<any, any> | Extension<any, any> | Mark<any, any>)[];
|
|
208
232
|
|
|
233
|
+
/**
|
|
234
|
+
* Impressão digital de um bloco da minuta (nó `minutaBlock` do editor) — base
|
|
235
|
+
* de "o advogado mexeu neste trecho?" quando o checklist muda com uma edição
|
|
236
|
+
* viva. O bloco nasce com `genHash` = impressão do texto gerado; enquanto a
|
|
237
|
+
* impressão atual bater com ela, o trecho é do checklist e pode ser
|
|
238
|
+
* re-gerado sem perder nada.
|
|
239
|
+
*
|
|
240
|
+
* Fica de fora o que muda SEM o advogado editar:
|
|
241
|
+
* - URL descartável de imagem (blob:/placeholder do load progressivo/vault:// do
|
|
242
|
+
* save): a imagem entra pela identidade DURÁVEL (`imageIdentity`), então
|
|
243
|
+
* trocar a imagem de verdade muda a impressão;
|
|
244
|
+
* - número de tópico e de nota (re-sequenciam quando outro trecho muda);
|
|
245
|
+
* - valor das variáveis (o chip é atualizado no lugar, em qualquer bloco —
|
|
246
|
+
* inclusive dentro de lista/tabela guardada como HTML cru).
|
|
247
|
+
*
|
|
248
|
+
* Mesma regra em `client/utils/minutaBlockFingerprint.ts` (o app ainda mantém a
|
|
249
|
+
* cópia dele) — a impressão gravada por um tem que bater com a do outro.
|
|
250
|
+
*
|
|
251
|
+
* Recebe o JSON do nó (`node.toJSON()`), então é pura e não depende de DOM.
|
|
252
|
+
*/
|
|
253
|
+
interface NodeJson {
|
|
254
|
+
type: string;
|
|
255
|
+
attrs?: Record<string, any>;
|
|
256
|
+
content?: NodeJson[];
|
|
257
|
+
marks?: {
|
|
258
|
+
type: string;
|
|
259
|
+
attrs?: Record<string, any>;
|
|
260
|
+
}[];
|
|
261
|
+
text?: string;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Identidade durável de uma imagem a partir do `src` (e do `data-vault-src` do
|
|
265
|
+
* placeholder do load progressivo) — no app, blob: do cache → vault://.
|
|
266
|
+
*/
|
|
267
|
+
type ImageIdentity = (src: string) => string;
|
|
268
|
+
declare function minutaBlockFingerprint(blockJson: NodeJson, identity?: ImageIdentity): string;
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Checklist × edição viva, para quem usa o editor fora do defesa.ai.
|
|
272
|
+
*
|
|
273
|
+
* O documento editado continua dividido em `minutaBlock` (um por bloco do
|
|
274
|
+
* template, `isolating`), e cada bloco guarda em `genHash` a impressão digital
|
|
275
|
+
* do texto que o checklist gerou. Com isso, quando o checklist muda (tese que
|
|
276
|
+
* passou a valer, variável alterada), dá para aplicar a mudança SÓ onde ela
|
|
277
|
+
* cai, sem passar por cima do que o advogado escreveu:
|
|
278
|
+
*
|
|
279
|
+
* - tese que passou a gerar texto → o bloco entra na posição do template;
|
|
280
|
+
* - tese que deixou de gerar → o bloco sai (se foi editado, vira conflito);
|
|
281
|
+
* - variável alterada → o chip atualiza no lugar, em qualquer bloco;
|
|
282
|
+
* - bloco cuja ESTRUTURA mudou → re-gerado se ninguém o editou, conflito se sim.
|
|
283
|
+
*
|
|
284
|
+
* Mesma lógica de `client/composables/poc/pocEditionSync.ts` + o
|
|
285
|
+
* `syncEditionWithChecklist` do app; aqui o documento gerado chega pronto (o
|
|
286
|
+
* `GET /data/case/:id/html?source=blocks`), em vez de renderizado no browser.
|
|
287
|
+
*/
|
|
288
|
+
interface MinutaChecklistConflict {
|
|
289
|
+
blockId: string;
|
|
290
|
+
blockTitle: string | null;
|
|
291
|
+
/** `replace`: o checklist mudou o texto de um trecho editado; `remove`: desligou uma tese editada */
|
|
292
|
+
kind: 'replace' | 'remove';
|
|
293
|
+
}
|
|
294
|
+
interface MinutaChecklistResult {
|
|
295
|
+
inserted: string[];
|
|
296
|
+
removed: string[];
|
|
297
|
+
regenerated: string[];
|
|
298
|
+
/** quantos chips de variável mudaram de valor */
|
|
299
|
+
variablesUpdated: number;
|
|
300
|
+
/** conflitos abertos depois desta aplicação (inclui os que já estavam) */
|
|
301
|
+
conflicts: MinutaChecklistConflict[];
|
|
302
|
+
/** a tese pedida em `toggled.show` não gera texto (condições internas) */
|
|
303
|
+
toggledWithoutContent: boolean;
|
|
304
|
+
/** a remoção não aconteceu porque o documento ficaria sem nenhum bloco */
|
|
305
|
+
lastBlockKept: boolean;
|
|
306
|
+
}
|
|
307
|
+
declare function blockHash(node: Node$1, identity?: ImageIdentity): string;
|
|
308
|
+
/** o conteúdo ainda é o que o checklist gerou (sem `genHash` = editado, por segurança) */
|
|
309
|
+
declare function isBlockUntouched(node: Node$1, identity?: ImageIdentity): boolean;
|
|
310
|
+
|
|
209
311
|
/**
|
|
210
312
|
* O editor de minuta como coisa montável em qualquer lugar: `createMinutaEditor(el, opts)`.
|
|
211
313
|
*
|
|
@@ -374,6 +476,35 @@ interface MinutaEditor {
|
|
|
374
476
|
* guarda uma cópia do documento.
|
|
375
477
|
*/
|
|
376
478
|
refreshVaultImages: (resolveUrl: (vaultUrl: string) => Promise<string>) => Promise<number>;
|
|
479
|
+
/**
|
|
480
|
+
* Checklist junto da edição: aplica o documento GERADO pelo checklist agora
|
|
481
|
+
* (o `GET /data/case/:id/html?source=blocks`) sobre o documento editado,
|
|
482
|
+
* bloco a bloco — tese que passou a valer entra na posição do template, a
|
|
483
|
+
* que deixou de valer sai, variáveis atualizam no lugar e trecho cuja
|
|
484
|
+
* estrutura mudou é re-gerado só se ninguém o editou (senão vira conflito).
|
|
485
|
+
* `toggled` força a decisão de UMA tese (o host ligou/desligou na mão).
|
|
486
|
+
* Uma transação só: o desfazer volta tudo. Blocos novos (e os aceitos em
|
|
487
|
+
* `resolveChecklistConflict`) podem trazer imagem `vault://` — chame
|
|
488
|
+
* `refreshVaultImages` depois de aplicar E de resolver os conflitos.
|
|
489
|
+
*/
|
|
490
|
+
applyChecklist: (generatedHtml: string, options?: {
|
|
491
|
+
toggled?: {
|
|
492
|
+
blockId: string;
|
|
493
|
+
show: boolean;
|
|
494
|
+
};
|
|
495
|
+
}) => MinutaChecklistResult;
|
|
496
|
+
/** trechos editados que o checklist quer mudar e aguardam decisão do advogado */
|
|
497
|
+
checklistConflicts: () => MinutaChecklistConflict[];
|
|
498
|
+
/** `apply` usa o texto novo (ou remove); `keep` mantém o editado e não pergunta de novo pela mesma mudança */
|
|
499
|
+
resolveChecklistConflict: (blockId: string, resolution: 'keep' | 'apply') => boolean;
|
|
500
|
+
/**
|
|
501
|
+
* Marca todos os blocos como "texto gerado". Chame UMA vez ao criar a edição
|
|
502
|
+
* a partir do HTML do checklist — sem a marca, todo bloco conta como editado
|
|
503
|
+
* e o `applyChecklist` pergunta em vez de re-gerar. Devolve quantos marcou.
|
|
504
|
+
*/
|
|
505
|
+
stampGenerated: () => number;
|
|
506
|
+
/** blocos (`data-block-id`) no documento, na ordem — para o checklist mostrar o que está no texto */
|
|
507
|
+
documentBlockIds: () => string[];
|
|
377
508
|
/** repagina (o host chama após mudar algo que afeta altura fora do editor) */
|
|
378
509
|
schedulePaginate: () => void;
|
|
379
510
|
/** reconstrói cabeçalhos/rodapés com o chrome atual, sem repaginar */
|
|
@@ -561,5 +692,5 @@ declare function collectVaultRefs(html: string): string[];
|
|
|
561
692
|
/** aplica as URLs resolvidas às `<img>` do trecho; tags sem resolução ficam como estão */
|
|
562
693
|
declare function renewVaultImageTags(html: string, resolved: Map<string, string>): string;
|
|
563
694
|
|
|
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 };
|
|
695
|
+
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, PocTopicNumberKeymap, 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, hasLeadingTopicNumber, iconSvg, isBlockUntouched, leadingTopicIndex, minutaBlockFingerprint, readTopicNumber, refreshVaultImages, renewVaultImageTags, renumberPocFootnotes, renumberPocTopics, renumberPocTopicsIn, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, shouldMoveBreakToHeading, swapVaultSrc, toRoman, toggleTopicNumber, topicNumberHtml, variableChipHtml, vaultImageHtml, vaultRefOf };
|
|
696
|
+
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
|
})
|
|
@@ -528,6 +550,13 @@ const PocTopicNumber = Node$1.create({
|
|
|
528
550
|
if (node.attrs.ref)
|
|
529
551
|
attrs[TOPIC_REF_ATTR] = "true";
|
|
530
552
|
return ["span", attrs, formatTopicNumber(node.attrs.number, node.attrs.roman)];
|
|
553
|
+
},
|
|
554
|
+
addCommands() {
|
|
555
|
+
return {
|
|
556
|
+
setTopicNumber: () => ({ tr }) => applyTopicNumbers(tr, "set"),
|
|
557
|
+
unsetTopicNumber: () => ({ tr }) => applyTopicNumbers(tr, "unset"),
|
|
558
|
+
toggleTopicNumber: () => ({ tr }) => applyTopicNumbers(tr, "toggle")
|
|
559
|
+
};
|
|
531
560
|
}
|
|
532
561
|
});
|
|
533
562
|
function renumberPocTopicsIn(tr) {
|
|
@@ -565,6 +594,169 @@ const PocTopicRenumber = Extension.create({
|
|
|
565
594
|
})];
|
|
566
595
|
}
|
|
567
596
|
});
|
|
597
|
+
const TOPIC_SEPARATOR_DEFAULT = ". ";
|
|
598
|
+
const TOPIC_SEPARATOR_RE = /^[ \u00A0]*[.)\-–—:]?[ \u00A0]*/u;
|
|
599
|
+
const TOPIC_SEPARATOR_MAX = 4;
|
|
600
|
+
function leadingTopicIndex(block) {
|
|
601
|
+
for (let i = 0; i < block.childCount; i++) {
|
|
602
|
+
const child = block.child(i);
|
|
603
|
+
if (child.isText && !child.text?.trim())
|
|
604
|
+
continue;
|
|
605
|
+
return child.type.name === "topicNumber" && !child.attrs.ref ? i : -1;
|
|
606
|
+
}
|
|
607
|
+
return -1;
|
|
608
|
+
}
|
|
609
|
+
function topicSeparatorAfter(block, topicIndex) {
|
|
610
|
+
const next = block.maybeChild(topicIndex + 1);
|
|
611
|
+
if (!next?.isText || !next.text)
|
|
612
|
+
return "";
|
|
613
|
+
return (next.text.match(TOPIC_SEPARATOR_RE)?.[0] ?? "").slice(0, TOPIC_SEPARATOR_MAX);
|
|
614
|
+
}
|
|
615
|
+
function firstTextMarks(block) {
|
|
616
|
+
for (let i = 0; i < block.childCount; i++) {
|
|
617
|
+
const child = block.child(i);
|
|
618
|
+
if (child.isText && child.text?.trim())
|
|
619
|
+
return child.marks;
|
|
620
|
+
}
|
|
621
|
+
return void 0;
|
|
622
|
+
}
|
|
623
|
+
function findTopicReference(doc, blockPos) {
|
|
624
|
+
let before = null;
|
|
625
|
+
let after = null;
|
|
626
|
+
doc.descendants((node, pos) => {
|
|
627
|
+
if (after)
|
|
628
|
+
return false;
|
|
629
|
+
if (!node.isTextblock)
|
|
630
|
+
return;
|
|
631
|
+
if (pos === blockPos)
|
|
632
|
+
return false;
|
|
633
|
+
const index = leadingTopicIndex(node);
|
|
634
|
+
if (index < 0)
|
|
635
|
+
return false;
|
|
636
|
+
const topic = node.child(index);
|
|
637
|
+
const ref = {
|
|
638
|
+
group: topic.attrs.group || TOPIC_DEFAULT_GROUP,
|
|
639
|
+
roman: Boolean(topic.attrs.roman),
|
|
640
|
+
number: Number(topic.attrs.number) || 0,
|
|
641
|
+
separator: topicSeparatorAfter(node, index) || TOPIC_SEPARATOR_DEFAULT,
|
|
642
|
+
marks: topic.marks
|
|
643
|
+
};
|
|
644
|
+
if (pos < blockPos)
|
|
645
|
+
before = ref;
|
|
646
|
+
else
|
|
647
|
+
after = ref;
|
|
648
|
+
return false;
|
|
649
|
+
});
|
|
650
|
+
return before ?? after;
|
|
651
|
+
}
|
|
652
|
+
function textBlockAt(doc, pos) {
|
|
653
|
+
const $pos = doc.resolve(pos);
|
|
654
|
+
for (let depth = $pos.depth; depth > 0; depth--) {
|
|
655
|
+
const node = $pos.node(depth);
|
|
656
|
+
if (node.type.name === "paragraph" || node.type.name === "heading")
|
|
657
|
+
return { node, pos: $pos.before(depth) };
|
|
658
|
+
if (node.isTextblock)
|
|
659
|
+
return null;
|
|
660
|
+
}
|
|
661
|
+
return null;
|
|
662
|
+
}
|
|
663
|
+
function insertTopicNumberAt(tr, blockPos) {
|
|
664
|
+
const block = tr.doc.nodeAt(blockPos);
|
|
665
|
+
if (!block || !block.isTextblock || leadingTopicIndex(block) >= 0)
|
|
666
|
+
return false;
|
|
667
|
+
const type = tr.doc.type.schema.nodes.topicNumber;
|
|
668
|
+
if (!type)
|
|
669
|
+
return false;
|
|
670
|
+
const ref = findTopicReference(tr.doc, blockPos);
|
|
671
|
+
const marks = firstTextMarks(block) ?? ref?.marks ?? [];
|
|
672
|
+
const topic = type.create({
|
|
673
|
+
number: ref && ref.number > 0 ? ref.number + 1 : 1,
|
|
674
|
+
group: ref?.group ?? TOPIC_DEFAULT_GROUP,
|
|
675
|
+
roman: ref?.roman ?? false,
|
|
676
|
+
ref: false
|
|
677
|
+
}, void 0, marks);
|
|
678
|
+
const separator = ref?.separator ?? TOPIC_SEPARATOR_DEFAULT;
|
|
679
|
+
const content = separator ? [topic, tr.doc.type.schema.text(separator, marks)] : [topic];
|
|
680
|
+
tr.insert(blockPos + 1, content);
|
|
681
|
+
return true;
|
|
682
|
+
}
|
|
683
|
+
function removeTopicNumberAt(tr, blockPos) {
|
|
684
|
+
const block = tr.doc.nodeAt(blockPos);
|
|
685
|
+
if (!block || !block.isTextblock)
|
|
686
|
+
return false;
|
|
687
|
+
const index = leadingTopicIndex(block);
|
|
688
|
+
if (index < 0)
|
|
689
|
+
return false;
|
|
690
|
+
let from = blockPos + 1;
|
|
691
|
+
for (let i = 0; i < index; i++)
|
|
692
|
+
from += block.child(i).nodeSize;
|
|
693
|
+
const to = from + block.child(index).nodeSize + topicSeparatorAfter(block, index).length;
|
|
694
|
+
tr.delete(from, to);
|
|
695
|
+
return true;
|
|
696
|
+
}
|
|
697
|
+
function selectedTextBlocks(tr) {
|
|
698
|
+
const { from, to } = tr.selection;
|
|
699
|
+
const blocks = [];
|
|
700
|
+
tr.doc.nodesBetween(from, to, (node, pos) => {
|
|
701
|
+
if (node.type.name === "paragraph" || node.type.name === "heading")
|
|
702
|
+
blocks.push({ node, pos });
|
|
703
|
+
});
|
|
704
|
+
return blocks;
|
|
705
|
+
}
|
|
706
|
+
function applyTopicNumbers(tr, mode) {
|
|
707
|
+
const blocks = selectedTextBlocks(tr);
|
|
708
|
+
if (!blocks.length)
|
|
709
|
+
return false;
|
|
710
|
+
const allNumbered = blocks.every((b) => leadingTopicIndex(b.node) >= 0);
|
|
711
|
+
const remove = mode === "unset" || mode === "toggle" && allNumbered;
|
|
712
|
+
const stepsBefore = tr.mapping.maps.length;
|
|
713
|
+
let changed = false;
|
|
714
|
+
for (const { pos } of blocks) {
|
|
715
|
+
const mapped = tr.mapping.slice(stepsBefore).map(pos);
|
|
716
|
+
changed = (remove ? removeTopicNumberAt(tr, mapped) : insertTopicNumberAt(tr, mapped)) || changed;
|
|
717
|
+
}
|
|
718
|
+
return changed;
|
|
719
|
+
}
|
|
720
|
+
function hasLeadingTopicNumber(editor) {
|
|
721
|
+
if (!editor || editor.isDestroyed)
|
|
722
|
+
return false;
|
|
723
|
+
const block = textBlockAt(editor.state.doc, editor.state.selection.from);
|
|
724
|
+
return Boolean(block && leadingTopicIndex(block.node) >= 0);
|
|
725
|
+
}
|
|
726
|
+
function toggleTopicNumber(editor) {
|
|
727
|
+
return editor.chain().focus().toggleTopicNumber().run();
|
|
728
|
+
}
|
|
729
|
+
const PocTopicNumberKeymap = Extension.create({
|
|
730
|
+
name: "pocTopicNumberKeymap",
|
|
731
|
+
// acima do keymap base e das listas (100); abaixo do `pocKeyDownFirst` (1000)
|
|
732
|
+
priority: 200,
|
|
733
|
+
addKeyboardShortcuts() {
|
|
734
|
+
return {
|
|
735
|
+
Enter: ({ editor }) => {
|
|
736
|
+
const { selection } = editor.state;
|
|
737
|
+
const { $from } = selection;
|
|
738
|
+
const block = $from.parent;
|
|
739
|
+
if (block.type.name !== "paragraph" && block.type.name !== "heading")
|
|
740
|
+
return false;
|
|
741
|
+
const index = leadingTopicIndex(block);
|
|
742
|
+
if (index < 0)
|
|
743
|
+
return false;
|
|
744
|
+
const body = block.textBetween(0, block.content.size, void 0, "\uFFFC");
|
|
745
|
+
const onlyNumber = !/[\p{L}\p{N}]/u.test(body.replace(/^/, ""));
|
|
746
|
+
if (selection.empty && onlyNumber)
|
|
747
|
+
return editor.chain().command(({ tr }) => removeTopicNumberAt(tr, $from.before())).run();
|
|
748
|
+
const inListItem = $from.depth >= 2 && $from.node(-1).type.name === "listItem";
|
|
749
|
+
return editor.chain().command(({ commands }) => inListItem ? commands.splitListItem("listItem") : commands.splitBlock()).command(({ tr }) => {
|
|
750
|
+
const target = textBlockAt(tr.doc, tr.selection.from);
|
|
751
|
+
if (!target || leadingTopicIndex(target.node) >= 0)
|
|
752
|
+
return true;
|
|
753
|
+
insertTopicNumberAt(tr, target.pos);
|
|
754
|
+
return true;
|
|
755
|
+
}).run();
|
|
756
|
+
}
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
});
|
|
568
760
|
const PocStyledDiv = Node$1.create({
|
|
569
761
|
name: "styledDiv",
|
|
570
762
|
group: "block",
|
|
@@ -696,6 +888,7 @@ function buildPocExtensions(pageConfig, options) {
|
|
|
696
888
|
PocFootnoteRef,
|
|
697
889
|
PocTopicNumber,
|
|
698
890
|
PocTopicRenumber,
|
|
891
|
+
PocTopicNumberKeymap,
|
|
699
892
|
PocStyledDiv,
|
|
700
893
|
PocInlineStyle,
|
|
701
894
|
PocUnderline,
|
|
@@ -728,7 +921,7 @@ const VARIABLE_TAG_RE = /<span\b[^>]*\bdata-minuta-var="([^"]*)"[^>]*>[^<]*<\/sp
|
|
|
728
921
|
function escapeHtml(value) {
|
|
729
922
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
730
923
|
}
|
|
731
|
-
function decodeAttr(value) {
|
|
924
|
+
function decodeAttr$1(value) {
|
|
732
925
|
return value.replace(/"/g, '"').replace(/>/g, ">").replace(/</g, "<").replace(/&/g, "&");
|
|
733
926
|
}
|
|
734
927
|
function extractTemplateVariables(html) {
|
|
@@ -736,7 +929,7 @@ function extractTemplateVariables(html) {
|
|
|
736
929
|
return [];
|
|
737
930
|
const keys = [];
|
|
738
931
|
for (const match of html.matchAll(VARIABLE_TAG_RE)) {
|
|
739
|
-
const key = decodeAttr(match[1] ?? "").trim();
|
|
932
|
+
const key = decodeAttr$1(match[1] ?? "").trim();
|
|
740
933
|
if (key && !keys.includes(key))
|
|
741
934
|
keys.push(key);
|
|
742
935
|
}
|
|
@@ -747,7 +940,7 @@ function resolveTemplateVariables(html, values) {
|
|
|
747
940
|
return { html: "", missing: [] };
|
|
748
941
|
const missing = [];
|
|
749
942
|
const resolved = html.replace(VARIABLE_TAG_RE, (tag, rawKey) => {
|
|
750
|
-
const key = decodeAttr(rawKey ?? "").trim();
|
|
943
|
+
const key = decodeAttr$1(rawKey ?? "").trim();
|
|
751
944
|
if (!key)
|
|
752
945
|
return tag;
|
|
753
946
|
const value = values?.[key];
|
|
@@ -864,6 +1057,362 @@ async function refreshVaultImages(editor, resolveUrl, options = {}) {
|
|
|
864
1057
|
return touched;
|
|
865
1058
|
}
|
|
866
1059
|
|
|
1060
|
+
const IMG_TAG = /<img\b[^>]*>/g;
|
|
1061
|
+
const ATTR = (name) => new RegExp(`\\s${name}="([^"]*)"`);
|
|
1062
|
+
function decodeAttr(value) {
|
|
1063
|
+
return value.replace(/"/g, '"').replace(/>/g, ">").replace(/</g, "<").replace(/&/g, "&");
|
|
1064
|
+
}
|
|
1065
|
+
function normalizeImgTags(html, identity) {
|
|
1066
|
+
if (!html.includes("<img"))
|
|
1067
|
+
return html;
|
|
1068
|
+
return html.replace(IMG_TAG, (tag) => {
|
|
1069
|
+
const vault = tag.match(ATTR("data-vault-src"))?.[1];
|
|
1070
|
+
const src = tag.match(ATTR("src"))?.[1] ?? "";
|
|
1071
|
+
const id = vault ? decodeAttr(vault) : identity(decodeAttr(src));
|
|
1072
|
+
return tag.replace(/\s(?:src|data-vault-src|data-download-url)="[^"]*"/g, "").replace(/^<img\b/, `<img data-img="${id}"`);
|
|
1073
|
+
});
|
|
1074
|
+
}
|
|
1075
|
+
const CHIP_SPAN = /<span\b([^>]*\sdata-variable-id="[^"]*"[^>]*)>[\s\S]*?<\/span>/g;
|
|
1076
|
+
function normalizeChipSpans(html) {
|
|
1077
|
+
if (!html.includes("data-variable-id"))
|
|
1078
|
+
return html;
|
|
1079
|
+
return html.replace(CHIP_SPAN, (_all, attrs) => {
|
|
1080
|
+
const id = attrs.match(/\sdata-variable-id="([^"]*)"/)?.[1] ?? "";
|
|
1081
|
+
const index = attrs.match(/\sdata-(?:loop|variable)-index="([^"]*)"/)?.[1] ?? "";
|
|
1082
|
+
return `<var:${id}:${index}>`;
|
|
1083
|
+
});
|
|
1084
|
+
}
|
|
1085
|
+
function normalizeAttrs(attrs, identity, chipSpans = true) {
|
|
1086
|
+
if (!attrs)
|
|
1087
|
+
return void 0;
|
|
1088
|
+
const out = {};
|
|
1089
|
+
for (const key of Object.keys(attrs).sort()) {
|
|
1090
|
+
if (key === "genHash" || key === "uid")
|
|
1091
|
+
continue;
|
|
1092
|
+
const value = attrs[key];
|
|
1093
|
+
if (key === "src" && typeof value === "string") {
|
|
1094
|
+
out[key] = identity(value);
|
|
1095
|
+
} else {
|
|
1096
|
+
out[key] = typeof value === "string" ? chipSpans ? normalizeChipSpans(normalizeImgTags(value, identity)) : normalizeImgTags(value, identity) : value;
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
return out;
|
|
1100
|
+
}
|
|
1101
|
+
function normalize(node, identity, chipSpans = true) {
|
|
1102
|
+
switch (node.type) {
|
|
1103
|
+
case "variableChip":
|
|
1104
|
+
return ["var", node.attrs?.variableId ?? null];
|
|
1105
|
+
case "topicNumber":
|
|
1106
|
+
return ["topic", node.attrs?.group ?? null, !!node.attrs?.ref];
|
|
1107
|
+
case "footnoteRef":
|
|
1108
|
+
return ["note", node.attrs?.text ?? "", node.attrs?.size ?? null];
|
|
1109
|
+
case "text":
|
|
1110
|
+
return ["text", node.text ?? "", (node.marks ?? []).map((mark) => [mark.type, normalizeAttrs(mark.attrs, identity, chipSpans)])];
|
|
1111
|
+
}
|
|
1112
|
+
return [node.type, normalizeAttrs(node.attrs, identity, chipSpans), (node.content ?? []).map((child) => normalize(child, identity, chipSpans))];
|
|
1113
|
+
}
|
|
1114
|
+
function fnv1a(input) {
|
|
1115
|
+
let hash = 2166136261;
|
|
1116
|
+
for (let i = 0; i < input.length; i++) {
|
|
1117
|
+
hash ^= input.charCodeAt(i);
|
|
1118
|
+
hash = Math.imul(hash, 16777619);
|
|
1119
|
+
}
|
|
1120
|
+
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
1121
|
+
}
|
|
1122
|
+
function minutaBlockFingerprint(blockJson, identity = (src) => src) {
|
|
1123
|
+
const body = JSON.stringify((blockJson.content ?? []).map((child) => normalize(child, identity)));
|
|
1124
|
+
return `${fnv1a(body)}${body.length.toString(16)}`;
|
|
1125
|
+
}
|
|
1126
|
+
function minutaBlockFingerprintV1(blockJson, identity = (src) => src) {
|
|
1127
|
+
const body = JSON.stringify((blockJson.content ?? []).map((child) => normalize(child, identity, false)));
|
|
1128
|
+
return `${fnv1a(body)}${body.length.toString(16)}`;
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
function readChecklist(doc) {
|
|
1132
|
+
const stored = doc.attrs.checklist;
|
|
1133
|
+
return stored ?? { wanted: [...docBlocks(doc).keys()], pending: [] };
|
|
1134
|
+
}
|
|
1135
|
+
const defaultImageIdentity = (src) => src;
|
|
1136
|
+
function blockHash(node, identity = defaultImageIdentity) {
|
|
1137
|
+
return minutaBlockFingerprint(node.toJSON(), identity);
|
|
1138
|
+
}
|
|
1139
|
+
function isBlockUntouched(node, identity = defaultImageIdentity) {
|
|
1140
|
+
const genHash = node.attrs.genHash;
|
|
1141
|
+
if (!genHash)
|
|
1142
|
+
return false;
|
|
1143
|
+
return genHash === blockHash(node, identity) || genHash === minutaBlockFingerprintV1(node.toJSON(), identity);
|
|
1144
|
+
}
|
|
1145
|
+
function docBlocks(doc) {
|
|
1146
|
+
const map = /* @__PURE__ */ new Map();
|
|
1147
|
+
doc.forEach((node, offset) => {
|
|
1148
|
+
const id = node.attrs.blockId;
|
|
1149
|
+
if (node.type.name === "minutaBlock" && id && !map.has(id))
|
|
1150
|
+
map.set(id, { pos: offset, node });
|
|
1151
|
+
});
|
|
1152
|
+
return map;
|
|
1153
|
+
}
|
|
1154
|
+
function parseGeneratedBlocks(schema, html, identity = defaultImageIdentity) {
|
|
1155
|
+
const wrapper = document.createElement("div");
|
|
1156
|
+
wrapper.innerHTML = html;
|
|
1157
|
+
const doc = DOMParser.fromSchema(schema).parse(wrapper);
|
|
1158
|
+
const blocks = [];
|
|
1159
|
+
doc.forEach((node) => {
|
|
1160
|
+
if (node.type.name === "minutaBlock" && node.attrs.blockId)
|
|
1161
|
+
blocks.push(node.type.create({ ...node.attrs, genHash: blockHash(node, identity) }, node.content, node.marks));
|
|
1162
|
+
});
|
|
1163
|
+
return blocks;
|
|
1164
|
+
}
|
|
1165
|
+
function stampGeneratedBlocks(editor, identity = defaultImageIdentity) {
|
|
1166
|
+
const tr = editor.state.tr;
|
|
1167
|
+
let stamped = 0;
|
|
1168
|
+
editor.state.doc.forEach((node, offset) => {
|
|
1169
|
+
if (node.type.name !== "minutaBlock")
|
|
1170
|
+
return;
|
|
1171
|
+
const genHash = blockHash(node, identity);
|
|
1172
|
+
if (node.attrs.genHash !== genHash) {
|
|
1173
|
+
tr.setNodeMarkup(offset, void 0, { ...node.attrs, genHash });
|
|
1174
|
+
stamped++;
|
|
1175
|
+
}
|
|
1176
|
+
});
|
|
1177
|
+
if (tr.docChanged)
|
|
1178
|
+
editor.view.dispatch(tr);
|
|
1179
|
+
return stamped;
|
|
1180
|
+
}
|
|
1181
|
+
function baseChipKey(variableId, parentBlockId) {
|
|
1182
|
+
return `${parentBlockId ?? ""}|${variableId ?? ""}`;
|
|
1183
|
+
}
|
|
1184
|
+
function chipKey(variableId, parentBlockId, loopIndex) {
|
|
1185
|
+
return `${baseChipKey(variableId, parentBlockId)}|${loopIndex ?? ""}`;
|
|
1186
|
+
}
|
|
1187
|
+
function collectChips(html) {
|
|
1188
|
+
const wrapper = document.createElement("div");
|
|
1189
|
+
wrapper.innerHTML = html;
|
|
1190
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
1191
|
+
const byBase = /* @__PURE__ */ new Map();
|
|
1192
|
+
wrapper.querySelectorAll("span[data-variable-id]").forEach((el) => {
|
|
1193
|
+
const variableId = el.getAttribute("data-variable-id");
|
|
1194
|
+
const parentBlockId = el.getAttribute("data-parent-block-id");
|
|
1195
|
+
const loopIndex = el.getAttribute("data-loop-index") ?? el.getAttribute("data-variable-index");
|
|
1196
|
+
const value = { html: el.outerHTML, text: el.textContent ?? "", loopIndex };
|
|
1197
|
+
for (const [map, key] of [[byKey, chipKey(variableId, parentBlockId, loopIndex)], [byBase, baseChipKey(variableId, parentBlockId)]]) {
|
|
1198
|
+
const list = map.get(key) ?? [];
|
|
1199
|
+
list.push(value);
|
|
1200
|
+
map.set(key, list);
|
|
1201
|
+
}
|
|
1202
|
+
});
|
|
1203
|
+
return { byKey, byBase };
|
|
1204
|
+
}
|
|
1205
|
+
function matchByValue(docChips, generated) {
|
|
1206
|
+
const pairs = [];
|
|
1207
|
+
const count = (list, text) => list.filter((t) => t === text).length;
|
|
1208
|
+
const docTexts = docChips.map((chip) => chip.node.attrs.text);
|
|
1209
|
+
const genTexts = generated.map((value) => value.text);
|
|
1210
|
+
const freeDoc = new Set(docChips.keys());
|
|
1211
|
+
const freeGen = new Set(generated.keys());
|
|
1212
|
+
docChips.forEach((chip, i) => {
|
|
1213
|
+
const text = docTexts[i];
|
|
1214
|
+
if (count(docTexts, text) !== 1 || count(genTexts, text) !== 1)
|
|
1215
|
+
return;
|
|
1216
|
+
const j = genTexts.indexOf(text);
|
|
1217
|
+
pairs.push({ ...chip, next: generated[j] });
|
|
1218
|
+
freeDoc.delete(i);
|
|
1219
|
+
freeGen.delete(j);
|
|
1220
|
+
});
|
|
1221
|
+
if (freeDoc.size === 1 && freeGen.size === 1) {
|
|
1222
|
+
const [i] = freeDoc;
|
|
1223
|
+
const [j] = freeGen;
|
|
1224
|
+
pairs.push({ ...docChips[i], next: generated[j] });
|
|
1225
|
+
}
|
|
1226
|
+
return pairs;
|
|
1227
|
+
}
|
|
1228
|
+
function refreshChips(tr, chips) {
|
|
1229
|
+
const inDoc = /* @__PURE__ */ new Map();
|
|
1230
|
+
tr.doc.descendants((node, pos) => {
|
|
1231
|
+
if (node.type.name !== "variableChip")
|
|
1232
|
+
return;
|
|
1233
|
+
const key = chipKey(node.attrs.variableId, node.attrs.parentBlockId, node.attrs.loopIndex);
|
|
1234
|
+
const list = inDoc.get(key) ?? [];
|
|
1235
|
+
list.push({ pos, node });
|
|
1236
|
+
inDoc.set(key, list);
|
|
1237
|
+
});
|
|
1238
|
+
let changed = 0;
|
|
1239
|
+
for (const [key, docChips] of inDoc) {
|
|
1240
|
+
let generated = chips.byKey.get(key);
|
|
1241
|
+
if (!generated?.length && docChips[0].node.attrs.loopIndex == null) {
|
|
1242
|
+
const { variableId, parentBlockId } = docChips[0].node.attrs;
|
|
1243
|
+
generated = chips.byBase.get(baseChipKey(variableId, parentBlockId));
|
|
1244
|
+
}
|
|
1245
|
+
if (!generated?.length)
|
|
1246
|
+
continue;
|
|
1247
|
+
const values = generated;
|
|
1248
|
+
const uniform = values.every((value) => value.html === values[0].html);
|
|
1249
|
+
const pairs = uniform ? docChips.map((chip) => ({ ...chip, next: values[0] })) : matchByValue(docChips, values);
|
|
1250
|
+
for (const { pos, node, next } of pairs) {
|
|
1251
|
+
const loopIndex = uniform ? node.attrs.loopIndex : next.loopIndex ?? node.attrs.loopIndex;
|
|
1252
|
+
if (next.html === node.attrs.html && loopIndex === node.attrs.loopIndex)
|
|
1253
|
+
continue;
|
|
1254
|
+
tr.setNodeMarkup(pos, void 0, { ...node.attrs, html: next.html, text: next.text, loopIndex });
|
|
1255
|
+
if (next.text !== node.attrs.text)
|
|
1256
|
+
changed++;
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
return changed;
|
|
1260
|
+
}
|
|
1261
|
+
function refreshIslandChips(tr, chips) {
|
|
1262
|
+
let changed = 0;
|
|
1263
|
+
tr.doc.descendants((node, pos) => {
|
|
1264
|
+
if (node.type.name !== "htmlIsland" || !String(node.attrs.html ?? "").includes("data-variable-id"))
|
|
1265
|
+
return;
|
|
1266
|
+
const tpl = document.createElement("template");
|
|
1267
|
+
tpl.innerHTML = node.attrs.html;
|
|
1268
|
+
let touched = false;
|
|
1269
|
+
tpl.content.querySelectorAll("span[data-variable-id]").forEach((el) => {
|
|
1270
|
+
const key = chipKey(
|
|
1271
|
+
el.getAttribute("data-variable-id"),
|
|
1272
|
+
el.getAttribute("data-parent-block-id"),
|
|
1273
|
+
el.getAttribute("data-loop-index") ?? el.getAttribute("data-variable-index")
|
|
1274
|
+
);
|
|
1275
|
+
const values = chips.byKey.get(key);
|
|
1276
|
+
if (!values?.length || values.some((value) => value.html !== values[0].html))
|
|
1277
|
+
return;
|
|
1278
|
+
if (el.outerHTML !== values[0].html) {
|
|
1279
|
+
if (el.textContent !== values[0].text)
|
|
1280
|
+
changed++;
|
|
1281
|
+
el.outerHTML = values[0].html;
|
|
1282
|
+
touched = true;
|
|
1283
|
+
}
|
|
1284
|
+
});
|
|
1285
|
+
if (touched)
|
|
1286
|
+
tr.setNodeMarkup(pos, void 0, { ...node.attrs, html: tpl.innerHTML });
|
|
1287
|
+
return false;
|
|
1288
|
+
});
|
|
1289
|
+
return changed;
|
|
1290
|
+
}
|
|
1291
|
+
function insertPos(doc, blockId, order) {
|
|
1292
|
+
const present = docBlocks(doc);
|
|
1293
|
+
const index = order.indexOf(blockId);
|
|
1294
|
+
for (let i = index - 1; i >= 0; i--) {
|
|
1295
|
+
const prev = present.get(order[i]);
|
|
1296
|
+
if (prev)
|
|
1297
|
+
return prev.pos + prev.node.nodeSize;
|
|
1298
|
+
}
|
|
1299
|
+
return 0;
|
|
1300
|
+
}
|
|
1301
|
+
function listConflicts(doc) {
|
|
1302
|
+
return readChecklist(doc).pending.map(({ blockId, kind, title }) => ({ blockId, blockTitle: title, kind }));
|
|
1303
|
+
}
|
|
1304
|
+
function applyChecklistToDocument(editor, generatedHtml, options = {}) {
|
|
1305
|
+
const identity = options.imageIdentity ?? defaultImageIdentity;
|
|
1306
|
+
const generated = parseGeneratedBlocks(editor.schema, generatedHtml, identity);
|
|
1307
|
+
const genById = new Map(generated.map((node) => [node.attrs.blockId, node]));
|
|
1308
|
+
const order = generated.map((node) => node.attrs.blockId);
|
|
1309
|
+
const wanted = new Set(order);
|
|
1310
|
+
const stored = readChecklist(editor.state.doc);
|
|
1311
|
+
const before = new Set(stored.wanted);
|
|
1312
|
+
const previousPending = new Map(stored.pending.map((entry) => [entry.blockId, entry]));
|
|
1313
|
+
const pending = /* @__PURE__ */ new Map();
|
|
1314
|
+
const toggled = options.toggled;
|
|
1315
|
+
const tr = editor.state.tr;
|
|
1316
|
+
const result = {
|
|
1317
|
+
inserted: [],
|
|
1318
|
+
removed: [],
|
|
1319
|
+
regenerated: [],
|
|
1320
|
+
variablesUpdated: 0,
|
|
1321
|
+
conflicts: [],
|
|
1322
|
+
toggledWithoutContent: false,
|
|
1323
|
+
lastBlockKept: false
|
|
1324
|
+
};
|
|
1325
|
+
const setConflict = (id, kind, node, title) => {
|
|
1326
|
+
pending.set(id, { blockId: id, kind, title, node: node ? node.toJSON() : null });
|
|
1327
|
+
};
|
|
1328
|
+
const ids = [...order, ...[...docBlocks(tr.doc).keys()].filter((id) => !wanted.has(id))];
|
|
1329
|
+
if (toggled && !ids.includes(toggled.blockId))
|
|
1330
|
+
ids.push(toggled.blockId);
|
|
1331
|
+
for (const id of ids) {
|
|
1332
|
+
const fresh = genById.get(id) ?? null;
|
|
1333
|
+
const explicit = toggled?.blockId === id;
|
|
1334
|
+
const turnedOn = explicit ? toggled.show : !before.has(id) && !!fresh;
|
|
1335
|
+
const turnedOff = explicit ? !toggled.show : before.has(id) && !fresh;
|
|
1336
|
+
const present = docBlocks(tr.doc).get(id);
|
|
1337
|
+
if (!present) {
|
|
1338
|
+
if (turnedOn && fresh) {
|
|
1339
|
+
tr.insert(insertPos(tr.doc, id, order), fresh);
|
|
1340
|
+
result.inserted.push(id);
|
|
1341
|
+
} else if (explicit && toggled.show && !fresh) {
|
|
1342
|
+
result.toggledWithoutContent = true;
|
|
1343
|
+
}
|
|
1344
|
+
continue;
|
|
1345
|
+
}
|
|
1346
|
+
const untouched = isBlockUntouched(present.node, identity);
|
|
1347
|
+
const title = present.node.attrs.blockTitle ?? null;
|
|
1348
|
+
if (!fresh || turnedOff) {
|
|
1349
|
+
if (!turnedOff) {
|
|
1350
|
+
const open = previousPending.get(id);
|
|
1351
|
+
if (!untouched && open?.kind === "remove")
|
|
1352
|
+
pending.set(id, open);
|
|
1353
|
+
continue;
|
|
1354
|
+
}
|
|
1355
|
+
if (tr.doc.childCount <= 1) {
|
|
1356
|
+
result.lastBlockKept = true;
|
|
1357
|
+
continue;
|
|
1358
|
+
}
|
|
1359
|
+
if (untouched) {
|
|
1360
|
+
tr.delete(present.pos, present.pos + present.node.nodeSize);
|
|
1361
|
+
result.removed.push(id);
|
|
1362
|
+
} else {
|
|
1363
|
+
setConflict(id, "remove", null, title);
|
|
1364
|
+
}
|
|
1365
|
+
continue;
|
|
1366
|
+
}
|
|
1367
|
+
if (fresh.attrs.genHash === present.node.attrs.genHash)
|
|
1368
|
+
continue;
|
|
1369
|
+
if (untouched) {
|
|
1370
|
+
tr.replaceWith(present.pos, present.pos + present.node.nodeSize, fresh);
|
|
1371
|
+
result.regenerated.push(id);
|
|
1372
|
+
} else {
|
|
1373
|
+
setConflict(id, "replace", fresh, title);
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
const chips = collectChips(generatedHtml);
|
|
1377
|
+
result.variablesUpdated = refreshChips(tr, chips) + refreshIslandChips(tr, chips);
|
|
1378
|
+
const next = { wanted: [...wanted], pending: [...pending.values()] };
|
|
1379
|
+
if (JSON.stringify(next) !== JSON.stringify(stored) || tr.docChanged)
|
|
1380
|
+
tr.setDocAttribute("checklist", next);
|
|
1381
|
+
if (tr.docChanged) {
|
|
1382
|
+
editor.view.dispatch(closeHistory(tr));
|
|
1383
|
+
}
|
|
1384
|
+
result.conflicts = next.pending.map(({ blockId, kind, title }) => ({ blockId, blockTitle: title, kind }));
|
|
1385
|
+
return result;
|
|
1386
|
+
}
|
|
1387
|
+
function resolveChecklistConflict(editor, blockId, resolution) {
|
|
1388
|
+
const stored = readChecklist(editor.state.doc);
|
|
1389
|
+
const entry = stored.pending.find((item) => item.blockId === blockId);
|
|
1390
|
+
const present = docBlocks(editor.state.doc).get(blockId);
|
|
1391
|
+
const tr = editor.state.tr;
|
|
1392
|
+
const rest = { ...stored, pending: stored.pending.filter((item) => item.blockId !== blockId) };
|
|
1393
|
+
if (!entry || !present) {
|
|
1394
|
+
if (entry) {
|
|
1395
|
+
tr.setDocAttribute("checklist", rest);
|
|
1396
|
+
editor.view.dispatch(tr);
|
|
1397
|
+
}
|
|
1398
|
+
return false;
|
|
1399
|
+
}
|
|
1400
|
+
if (resolution === "apply" && entry.kind === "remove" && editor.state.doc.childCount <= 1)
|
|
1401
|
+
return false;
|
|
1402
|
+
const fresh = entry.node ? editor.schema.nodeFromJSON(entry.node) : null;
|
|
1403
|
+
if (resolution === "apply") {
|
|
1404
|
+
if (entry.kind === "remove")
|
|
1405
|
+
tr.delete(present.pos, present.pos + present.node.nodeSize);
|
|
1406
|
+
else if (fresh)
|
|
1407
|
+
tr.replaceWith(present.pos, present.pos + present.node.nodeSize, fresh);
|
|
1408
|
+
} else if (entry.kind === "replace" && fresh) {
|
|
1409
|
+
tr.setNodeMarkup(present.pos, void 0, { ...present.node.attrs, genHash: fresh.attrs.genHash });
|
|
1410
|
+
}
|
|
1411
|
+
tr.setDocAttribute("checklist", rest);
|
|
1412
|
+
editor.view.dispatch(closeHistory(tr));
|
|
1413
|
+
return true;
|
|
1414
|
+
}
|
|
1415
|
+
|
|
867
1416
|
function h(tag, attrs = {}, children = []) {
|
|
868
1417
|
const el = document.createElement(tag);
|
|
869
1418
|
if (attrs.class)
|
|
@@ -1252,6 +1801,11 @@ function createToolbar(actions) {
|
|
|
1252
1801
|
const strikeBtn = tool("Tachado", "S", () => ed()?.chain().focus().toggleStrike().run(), "line-through");
|
|
1253
1802
|
const bulletBtn = tool("Lista com marcadores", icon("list-bullets"), () => ed()?.chain().focus().toggleBulletList().run());
|
|
1254
1803
|
const orderedBtn = tool("Lista numerada", icon("list-numbers"), () => ed()?.chain().focus().toggleOrderedList().run());
|
|
1804
|
+
const topicBtn = tool("Numerar par\xE1grafo (continua a numera\xE7\xE3o da pe\xE7a)", h("span", { class: "poc-tool-glyph", text: "1." }), () => {
|
|
1805
|
+
const e = ed();
|
|
1806
|
+
if (e)
|
|
1807
|
+
toggleTopicNumber(e);
|
|
1808
|
+
});
|
|
1255
1809
|
const variableBtn = tool("Inserir vari\xE1vel (ou digite / no texto)", icon("brackets-curly"), actions.openVariablePicker);
|
|
1256
1810
|
const el = h("div", { class: "poc-toolbar", on: { click: (e) => e.stopPropagation() } }, [
|
|
1257
1811
|
tool("Desfazer", icon("arrow-u-up-left"), () => ed()?.chain().focus().undo().run()),
|
|
@@ -1273,6 +1827,7 @@ function createToolbar(actions) {
|
|
|
1273
1827
|
tool("Alinhar \xE0 direita", icon("text-align-right"), () => actions.setAlignment("right")),
|
|
1274
1828
|
tool("Justificar", icon("text-align-justify"), () => actions.setAlignment("justify")),
|
|
1275
1829
|
sep(),
|
|
1830
|
+
topicBtn,
|
|
1276
1831
|
bulletBtn,
|
|
1277
1832
|
orderedBtn,
|
|
1278
1833
|
sep(),
|
|
@@ -1287,7 +1842,7 @@ function createToolbar(actions) {
|
|
|
1287
1842
|
variableBtn.hidden = !actions.hasVariables();
|
|
1288
1843
|
toggleClass(variableBtn, "poc-tool--on", actions.isVariablePickerOpen());
|
|
1289
1844
|
if (!e || e.isDestroyed) {
|
|
1290
|
-
for (const b of [boldBtn, italicBtn, underlineBtn, strikeBtn, bulletBtn, orderedBtn])
|
|
1845
|
+
for (const b of [boldBtn, italicBtn, underlineBtn, strikeBtn, topicBtn, bulletBtn, orderedBtn])
|
|
1291
1846
|
toggleClass(b, "poc-tool--on", false);
|
|
1292
1847
|
return;
|
|
1293
1848
|
}
|
|
@@ -1295,6 +1850,7 @@ function createToolbar(actions) {
|
|
|
1295
1850
|
toggleClass(italicBtn, "poc-tool--on", e.isActive("italic"));
|
|
1296
1851
|
toggleClass(underlineBtn, "poc-tool--on", e.isActive("underline"));
|
|
1297
1852
|
toggleClass(strikeBtn, "poc-tool--on", e.isActive("strike"));
|
|
1853
|
+
toggleClass(topicBtn, "poc-tool--on", hasLeadingTopicNumber(e));
|
|
1298
1854
|
toggleClass(bulletBtn, "poc-tool--on", e.isActive("bulletList"));
|
|
1299
1855
|
toggleClass(orderedBtn, "poc-tool--on", e.isActive("orderedList"));
|
|
1300
1856
|
const family = currentFontFamily(e);
|
|
@@ -2167,6 +2723,32 @@ function createMinutaEditor(element, opts) {
|
|
|
2167
2723
|
return Promise.resolve(0);
|
|
2168
2724
|
return refreshVaultImages(ed, resolveUrl, { meta: { [POC_ASSET_SWAP]: true } });
|
|
2169
2725
|
},
|
|
2726
|
+
applyChecklist(generatedHtml, options) {
|
|
2727
|
+
const ed = tiptap;
|
|
2728
|
+
if (!ed || ed.isDestroyed)
|
|
2729
|
+
throw new Error("editor n\xE3o montado");
|
|
2730
|
+
return applyChecklistToDocument(ed, generatedHtml, options ?? {});
|
|
2731
|
+
},
|
|
2732
|
+
checklistConflicts() {
|
|
2733
|
+
const ed = tiptap;
|
|
2734
|
+
return ed && !ed.isDestroyed ? listConflicts(ed.state.doc) : [];
|
|
2735
|
+
},
|
|
2736
|
+
resolveChecklistConflict(blockId, resolution) {
|
|
2737
|
+
const ed = tiptap;
|
|
2738
|
+
if (!ed || ed.isDestroyed)
|
|
2739
|
+
return false;
|
|
2740
|
+
return resolveChecklistConflict(ed, blockId, resolution);
|
|
2741
|
+
},
|
|
2742
|
+
stampGenerated() {
|
|
2743
|
+
const ed = tiptap;
|
|
2744
|
+
if (!ed || ed.isDestroyed)
|
|
2745
|
+
return 0;
|
|
2746
|
+
return stampGeneratedBlocks(ed);
|
|
2747
|
+
},
|
|
2748
|
+
documentBlockIds() {
|
|
2749
|
+
const ed = tiptap;
|
|
2750
|
+
return ed && !ed.isDestroyed ? [...docBlocks(ed.state.doc).keys()] : [];
|
|
2751
|
+
},
|
|
2170
2752
|
schedulePaginate,
|
|
2171
2753
|
refreshChrome,
|
|
2172
2754
|
totalPages: () => totalPages,
|
|
@@ -2186,4 +2768,4 @@ function createMinutaEditor(element, opts) {
|
|
|
2186
2768
|
return api;
|
|
2187
2769
|
}
|
|
2188
2770
|
|
|
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 };
|
|
2771
|
+
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, PocTopicNumberKeymap, 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, hasLeadingTopicNumber, iconSvg, isBlockUntouched, leadingTopicIndex, minutaBlockFingerprint, pocPageKey, readTopicNumber, refreshVaultImages, renewVaultImageTags, renumberPocFootnotes, renumberPocTopics, renumberPocTopicsIn, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, swapVaultSrc, toggleTopicNumber, variableChipHtml, vaultImageHtml, vaultRefOf };
|
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{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[src^="vault://"]{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-glyph{font-size:11px;font-weight:600;line-height:1}.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[src^="vault://"]{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.
|
|
3
|
+
"version": "1.7.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",
|