@meistrari/minuta-editor 1.2.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -34,6 +34,8 @@ const editor = createMinutaEditor(el, {
34
34
  chrome: { header: '', footer: '', showPageNumber: true },
35
35
  variables: [...], // catálogo → liga o modo template
36
36
  uploadImage: async file => ({ src, vaultSrc }) | null,
37
+ imageFallback: 'dataUri', // 'none' = upload falhou → não insere, só onImageUploadError
38
+ onImageUploadError: (error, file) => {},
37
39
  toolbar: true, // false = o host monta a barra dele
38
40
  onReady: tiptap => {},
39
41
  onChange: () => {},
@@ -54,9 +56,10 @@ editor.setBlockClickWhileEditing(bool)
54
56
  // variáveis do case marcadas no documento (<span|img data-variable-id>, aviso de imagem faltando)
55
57
  editor.scrollToVariable(id) // → boolean (rola e dá um flash)
56
58
  editor.setVariableValue(id, texto) // → nº de ocorrências (o aviso de "faltando" vira chip)
57
- editor.setVariableImage(id, src) // → nº de ocorrências (o aviso de imagem vira <img>)
59
+ editor.setVariableImage(id, src, vaultSrc?) // → nº de ocorrências (o aviso de imagem vira <img>; vaultSrc → data-vault-src)
60
+ editor.setImageFallback('dataUri' | 'none')
58
61
  editor.variablesInDocument() // → string[]
59
- editor.refreshVaultImages(vaultUrl => Promise<string>) // renova o src das imagens inseridas (data-vault-src)
62
+ editor.refreshVaultImages(vaultUrl => Promise<string>) // renova o src das imagens do vault (data-vault-src ou src="vault://"); sem undo/onChange
60
63
 
61
64
  editor.schedulePaginate() // repagina (após mudar algo que afeta altura por fora)
62
65
  editor.totalPages()
package/dist/index.d.mts CHANGED
@@ -248,6 +248,16 @@ interface MinutaEditorOptions {
248
248
  src: string;
249
249
  vaultSrc: string;
250
250
  } | null>) | null;
251
+ /**
252
+ * O que fazer quando `uploadImage` falha (lança ou devolve `null`) ou não
253
+ * existe. `'dataUri'` (default) embute a imagem em base64 — conveniência
254
+ * do editor sem backend. `'none'` não insere nada: o host recebe
255
+ * `onImageUploadError` e decide (mostrar erro, tentar de novo). Um host
256
+ * cujo documento canônico depende de `vault://` quer `'none'`.
257
+ */
258
+ imageFallback?: 'dataUri' | 'none';
259
+ /** o upload da imagem da toolbar falhou (ou devolveu `null`); com `imageFallback: 'none'` nada foi inserido */
260
+ onImageUploadError?: (error: unknown, file: File) => void;
251
261
  /** barra de formatação (default: true). `false` = o host monta a dele sobre `tiptap` */
252
262
  toolbar?: boolean;
253
263
  /** realce de proveniência de bloco no hover (só faz sentido no modo estruturado) */
@@ -321,16 +331,24 @@ interface MinutaEditor {
321
331
  /**
322
332
  * Troca a imagem de uma variável de imagem: o `<img data-variable-id>` ganha
323
333
  * o `src` novo, e um aviso de imagem faltando com esse id vira a imagem.
324
- * Devolve quantas ocorrências mudaram.
334
+ * `vaultSrc` (a `vault://` durável) entra como `data-vault-src`: é o que
335
+ * `refreshVaultImages` renova e o que o DOCX do servidor usa quando o `src`
336
+ * presignado expira. Omiti-lo REMOVE a ref durável que estivesse na tag —
337
+ * ela descrevia a imagem antiga. Devolve quantas ocorrências mudaram.
325
338
  */
326
- setVariableImage: (variableId: string, src: string) => number;
339
+ setVariableImage: (variableId: string, src: string, vaultSrc?: string) => number;
340
+ /** troca o modo de fallback do upload de imagem depois de criado (ver `imageFallback`) */
341
+ setImageFallback: (mode: 'dataUri' | 'none') => void;
327
342
  /** ids marcados no documento, na ordem, sem repetição: chips de texto, imagens e imagens faltando */
328
343
  variablesInDocument: () => string[];
329
344
  /**
330
- * Renova o `src` das imagens inseridas no editor (as que têm `data-vault-src`):
331
- * o presignado do upload expira, então quem reabre uma edição salva passa
332
- * um resolvedor `vault://` → URL nova (no defesa.ai, `POST /data/vault/download-url`).
333
- * Devolve quantos nós mudaram. Não entra no undo nem dispara `onChange`.
345
+ * Renova o `src` das imagens do vault: as que têm `data-vault-src` (inseridas
346
+ * no editor, presignado expirado) e as salvas com `src="vault://…"` (a forma
347
+ * durável, que o browser não abre — ganham `data-vault-src` e um `src` novo).
348
+ * Quem reabre uma edição salva passa um resolvedor `vault://` → URL nova (no
349
+ * defesa.ai, `POST /data/vault/download-url`). Devolve quantos nós mudaram.
350
+ * Não entra no undo nem dispara `onChange`; chame `getHTML()` depois se
351
+ * guarda uma cópia do documento.
334
352
  */
335
353
  refreshVaultImages: (resolveUrl: (vaultUrl: string) => Promise<string>) => Promise<number>;
336
354
  /** repagina (o host chama após mudar algo que afeta altura fora do editor) */
@@ -442,8 +460,9 @@ interface RefreshVaultImagesOptions {
442
460
  /**
443
461
  * Re-resolve todas as imagens `vault://` do documento: as inseridas pela
444
462
  * toolbar entram com `src` presignado (funciona agora) e `data-vault-src`
445
- * durável; como o presignado expira, quem reabre uma edição salva chama isto
446
- * no load. `resolveUrl` recebe a `vault://` e devolve a URL nova (no defesa.ai,
463
+ * durável, e uma edição salva pode trazer só `src="vault://…"`. Como o
464
+ * presignado expira, quem reabre uma edição salva chama isto no load.
465
+ * `resolveUrl` recebe a `vault://` e devolve a URL nova (no defesa.ai,
447
466
  * `POST /data/vault/download-url`). Devolve quantos nós mudaram.
448
467
  *
449
468
  * Fora do histórico de undo: renovar um link não é uma edição do advogado.
@@ -472,5 +491,18 @@ declare function escapeVaultAttr(value: string): string;
472
491
  declare function decodeVaultAttr(value: string): string;
473
492
  declare function vaultImageHtml(src: string, vaultUrl: string): string;
474
493
 
475
- export { A4_HEIGHT_PX, A4_WIDTH_PX, DEFAULT_MARGINS, DOC_FONTS, ICON_PATHS, POC_ASSET_SWAP, PocDocument, PocFootnoteRef, PocHtmlIsland, PocInlineStyle, PocMinutaBlock, PocMissingImage, PocPageConfig, PocStylePassthrough, PocStyledDiv, PocTemplateVariable, PocUnderline, PocVariableChip, buildPocExtensions, createMinutaEditor, decodeVaultAttr, dispatchVariableClick, escapeHtml, escapeVaultAttr, extractTemplateVariables, footnoteHtmlToRuns, footnoteSizePt, iconSvg, refreshVaultImages, renumberPocFootnotes, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, shouldMoveBreakToHeading, variableChipHtml, vaultImageHtml };
494
+ /**
495
+ * A `vault://` de uma tag `<img>`: o `data-vault-src` (imagem inserida no
496
+ * editor, presignado + ref durável) ou um `src="vault://…"` (a forma durável
497
+ * salva sem presignado — o browser não abre). Decodificada; null se não há.
498
+ */
499
+ declare function vaultRefOf(tag: string): string | null;
500
+ /** `src` novo, mantendo (ou criando) o `data-vault-src` — a ref durável fica */
501
+ declare function swapVaultSrc(tag: string, vaultUrl: string, freshUrl: string): string;
502
+ /** todas as `vault://` referenciadas por `<img>` num trecho de HTML, sem repetição */
503
+ declare function collectVaultRefs(html: string): string[];
504
+ /** aplica as URLs resolvidas às `<img>` do trecho; tags sem resolução ficam como estão */
505
+ declare function renewVaultImageTags(html: string, resolved: Map<string, string>): string;
506
+
507
+ export { A4_HEIGHT_PX, A4_WIDTH_PX, DEFAULT_MARGINS, DOC_FONTS, ICON_PATHS, POC_ASSET_SWAP, PocDocument, PocFootnoteRef, PocHtmlIsland, PocInlineStyle, PocMinutaBlock, PocMissingImage, PocPageConfig, PocStylePassthrough, PocStyledDiv, PocTemplateVariable, PocUnderline, PocVariableChip, buildPocExtensions, collectVaultRefs, createMinutaEditor, decodeVaultAttr, dispatchVariableClick, escapeHtml, escapeVaultAttr, extractTemplateVariables, footnoteHtmlToRuns, footnoteSizePt, iconSvg, refreshVaultImages, renewVaultImageTags, renumberPocFootnotes, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, shouldMoveBreakToHeading, swapVaultSrc, variableChipHtml, vaultImageHtml, vaultRefOf };
476
508
  export type { FootnoteRun, MinutaChromeText, MinutaEditor, MinutaEditorOptions, MinutaHeader, MinutaMargins, MinutaVariableCatalog, MinutaVariableDef, MinutaVariableRef, PocKeepWithNextItem, RefreshVaultImagesOptions, VariableClickKind };
package/dist/index.d.ts CHANGED
@@ -248,6 +248,16 @@ interface MinutaEditorOptions {
248
248
  src: string;
249
249
  vaultSrc: string;
250
250
  } | null>) | null;
251
+ /**
252
+ * O que fazer quando `uploadImage` falha (lança ou devolve `null`) ou não
253
+ * existe. `'dataUri'` (default) embute a imagem em base64 — conveniência
254
+ * do editor sem backend. `'none'` não insere nada: o host recebe
255
+ * `onImageUploadError` e decide (mostrar erro, tentar de novo). Um host
256
+ * cujo documento canônico depende de `vault://` quer `'none'`.
257
+ */
258
+ imageFallback?: 'dataUri' | 'none';
259
+ /** o upload da imagem da toolbar falhou (ou devolveu `null`); com `imageFallback: 'none'` nada foi inserido */
260
+ onImageUploadError?: (error: unknown, file: File) => void;
251
261
  /** barra de formatação (default: true). `false` = o host monta a dele sobre `tiptap` */
252
262
  toolbar?: boolean;
253
263
  /** realce de proveniência de bloco no hover (só faz sentido no modo estruturado) */
@@ -321,16 +331,24 @@ interface MinutaEditor {
321
331
  /**
322
332
  * Troca a imagem de uma variável de imagem: o `<img data-variable-id>` ganha
323
333
  * o `src` novo, e um aviso de imagem faltando com esse id vira a imagem.
324
- * Devolve quantas ocorrências mudaram.
334
+ * `vaultSrc` (a `vault://` durável) entra como `data-vault-src`: é o que
335
+ * `refreshVaultImages` renova e o que o DOCX do servidor usa quando o `src`
336
+ * presignado expira. Omiti-lo REMOVE a ref durável que estivesse na tag —
337
+ * ela descrevia a imagem antiga. Devolve quantas ocorrências mudaram.
325
338
  */
326
- setVariableImage: (variableId: string, src: string) => number;
339
+ setVariableImage: (variableId: string, src: string, vaultSrc?: string) => number;
340
+ /** troca o modo de fallback do upload de imagem depois de criado (ver `imageFallback`) */
341
+ setImageFallback: (mode: 'dataUri' | 'none') => void;
327
342
  /** ids marcados no documento, na ordem, sem repetição: chips de texto, imagens e imagens faltando */
328
343
  variablesInDocument: () => string[];
329
344
  /**
330
- * Renova o `src` das imagens inseridas no editor (as que têm `data-vault-src`):
331
- * o presignado do upload expira, então quem reabre uma edição salva passa
332
- * um resolvedor `vault://` → URL nova (no defesa.ai, `POST /data/vault/download-url`).
333
- * Devolve quantos nós mudaram. Não entra no undo nem dispara `onChange`.
345
+ * Renova o `src` das imagens do vault: as que têm `data-vault-src` (inseridas
346
+ * no editor, presignado expirado) e as salvas com `src="vault://…"` (a forma
347
+ * durável, que o browser não abre — ganham `data-vault-src` e um `src` novo).
348
+ * Quem reabre uma edição salva passa um resolvedor `vault://` → URL nova (no
349
+ * defesa.ai, `POST /data/vault/download-url`). Devolve quantos nós mudaram.
350
+ * Não entra no undo nem dispara `onChange`; chame `getHTML()` depois se
351
+ * guarda uma cópia do documento.
334
352
  */
335
353
  refreshVaultImages: (resolveUrl: (vaultUrl: string) => Promise<string>) => Promise<number>;
336
354
  /** repagina (o host chama após mudar algo que afeta altura fora do editor) */
@@ -442,8 +460,9 @@ interface RefreshVaultImagesOptions {
442
460
  /**
443
461
  * Re-resolve todas as imagens `vault://` do documento: as inseridas pela
444
462
  * toolbar entram com `src` presignado (funciona agora) e `data-vault-src`
445
- * durável; como o presignado expira, quem reabre uma edição salva chama isto
446
- * no load. `resolveUrl` recebe a `vault://` e devolve a URL nova (no defesa.ai,
463
+ * durável, e uma edição salva pode trazer só `src="vault://…"`. Como o
464
+ * presignado expira, quem reabre uma edição salva chama isto no load.
465
+ * `resolveUrl` recebe a `vault://` e devolve a URL nova (no defesa.ai,
447
466
  * `POST /data/vault/download-url`). Devolve quantos nós mudaram.
448
467
  *
449
468
  * Fora do histórico de undo: renovar um link não é uma edição do advogado.
@@ -472,5 +491,18 @@ declare function escapeVaultAttr(value: string): string;
472
491
  declare function decodeVaultAttr(value: string): string;
473
492
  declare function vaultImageHtml(src: string, vaultUrl: string): string;
474
493
 
475
- export { A4_HEIGHT_PX, A4_WIDTH_PX, DEFAULT_MARGINS, DOC_FONTS, ICON_PATHS, POC_ASSET_SWAP, PocDocument, PocFootnoteRef, PocHtmlIsland, PocInlineStyle, PocMinutaBlock, PocMissingImage, PocPageConfig, PocStylePassthrough, PocStyledDiv, PocTemplateVariable, PocUnderline, PocVariableChip, buildPocExtensions, createMinutaEditor, decodeVaultAttr, dispatchVariableClick, escapeHtml, escapeVaultAttr, extractTemplateVariables, footnoteHtmlToRuns, footnoteSizePt, iconSvg, refreshVaultImages, renumberPocFootnotes, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, shouldMoveBreakToHeading, variableChipHtml, vaultImageHtml };
494
+ /**
495
+ * A `vault://` de uma tag `<img>`: o `data-vault-src` (imagem inserida no
496
+ * editor, presignado + ref durável) ou um `src="vault://…"` (a forma durável
497
+ * salva sem presignado — o browser não abre). Decodificada; null se não há.
498
+ */
499
+ declare function vaultRefOf(tag: string): string | null;
500
+ /** `src` novo, mantendo (ou criando) o `data-vault-src` — a ref durável fica */
501
+ declare function swapVaultSrc(tag: string, vaultUrl: string, freshUrl: string): string;
502
+ /** todas as `vault://` referenciadas por `<img>` num trecho de HTML, sem repetição */
503
+ declare function collectVaultRefs(html: string): string[];
504
+ /** aplica as URLs resolvidas às `<img>` do trecho; tags sem resolução ficam como estão */
505
+ declare function renewVaultImageTags(html: string, resolved: Map<string, string>): string;
506
+
507
+ export { A4_HEIGHT_PX, A4_WIDTH_PX, DEFAULT_MARGINS, DOC_FONTS, ICON_PATHS, POC_ASSET_SWAP, PocDocument, PocFootnoteRef, PocHtmlIsland, PocInlineStyle, PocMinutaBlock, PocMissingImage, PocPageConfig, PocStylePassthrough, PocStyledDiv, PocTemplateVariable, PocUnderline, PocVariableChip, buildPocExtensions, collectVaultRefs, createMinutaEditor, decodeVaultAttr, dispatchVariableClick, escapeHtml, escapeVaultAttr, extractTemplateVariables, footnoteHtmlToRuns, footnoteSizePt, iconSvg, refreshVaultImages, renewVaultImageTags, renumberPocFootnotes, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, shouldMoveBreakToHeading, swapVaultSrc, variableChipHtml, vaultImageHtml, vaultRefOf };
476
508
  export type { FootnoteRun, MinutaChromeText, MinutaEditor, MinutaEditorOptions, MinutaHeader, MinutaMargins, MinutaVariableCatalog, MinutaVariableDef, MinutaVariableRef, PocKeepWithNextItem, RefreshVaultImagesOptions, VariableClickKind };
package/dist/index.mjs CHANGED
@@ -682,16 +682,39 @@ function vaultImageHtml(src, vaultUrl) {
682
682
  function escapeAttr(value) {
683
683
  return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;");
684
684
  }
685
- function escapeRegExp(value) {
686
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
685
+ function vaultRefOf(tag) {
686
+ const durable = tag.match(/\sdata-vault-src="([^"]*)"/)?.[1];
687
+ if (durable)
688
+ return decodeVaultAttr(durable);
689
+ const src = tag.match(/\ssrc="([^"]*)"/)?.[1];
690
+ if (src && decodeVaultAttr(src).startsWith("vault://"))
691
+ return decodeVaultAttr(src);
692
+ return null;
693
+ }
694
+ function swapVaultSrc(tag, vaultUrl, freshUrl) {
695
+ const fresh = ` src="${escapeAttr(freshUrl)}"`;
696
+ const withSrc = /\ssrc="[^"]*"/.test(tag) ? tag.replace(/\ssrc="[^"]*"/, fresh) : tag.replace(/^<img\b/, `<img${fresh}`);
697
+ if (/\sdata-vault-src="/.test(withSrc))
698
+ return withSrc;
699
+ return withSrc.replace(/^<img\b/, `<img data-vault-src="${escapeVaultAttr(vaultUrl)}"`);
687
700
  }
688
- function swapSrcKeepRef(html, attrValue, freshUrl) {
689
- const needle = `data-vault-src="${attrValue}"`;
690
- if (!html.includes(needle))
691
- return html;
692
- const tagRe = new RegExp(`<img\\b[^>]*?${escapeRegExp(needle)}[^>]*?>`, "g");
693
- return html.replace(tagRe, (tag) => tag.replace(/\ssrc="[^"]*"/, ` src="${escapeAttr(freshUrl)}"`));
701
+ function collectVaultRefs(html) {
702
+ const refs = /* @__PURE__ */ new Set();
703
+ for (const [tag] of html.matchAll(/<img\b[^>]*>/g)) {
704
+ const ref = vaultRefOf(tag);
705
+ if (ref)
706
+ refs.add(ref);
707
+ }
708
+ return [...refs];
694
709
  }
710
+ function renewVaultImageTags(html, resolved) {
711
+ return html.replace(/<img\b[^>]*>/g, (tag) => {
712
+ const ref = vaultRefOf(tag);
713
+ const fresh = ref ? resolved.get(ref) : void 0;
714
+ return ref && fresh ? swapVaultSrc(tag, ref, fresh) : tag;
715
+ });
716
+ }
717
+
695
718
  async function refreshVaultImages(editor, resolveUrl, options = {}) {
696
719
  if (!editor || editor.isDestroyed)
697
720
  return 0;
@@ -699,15 +722,15 @@ async function refreshVaultImages(editor, resolveUrl, options = {}) {
699
722
  editor.state.doc.descendants((node) => {
700
723
  if (node.type.name !== "htmlIsland")
701
724
  return;
702
- for (const m of String(node.attrs.html ?? "").matchAll(/data-vault-src="([^"]+)"/g))
703
- refs.add(m[1]);
725
+ for (const ref of collectVaultRefs(String(node.attrs.html ?? "")))
726
+ refs.add(ref);
704
727
  });
705
728
  if (!refs.size)
706
729
  return 0;
707
730
  const resolved = /* @__PURE__ */ new Map();
708
- await Promise.all([...refs].map(async (attrValue) => {
731
+ await Promise.all([...refs].map(async (vaultUrl) => {
709
732
  try {
710
- const fresh = await resolveUrl(decodeVaultAttr(attrValue));
733
+ const fresh = await resolveUrl(vaultUrl);
711
734
  if (!fresh)
712
735
  return;
713
736
  await new Promise((done) => {
@@ -718,9 +741,9 @@ async function refreshVaultImages(editor, resolveUrl, options = {}) {
718
741
  setTimeout(finish, 4e3);
719
742
  img.src = fresh;
720
743
  });
721
- resolved.set(attrValue, fresh);
744
+ resolved.set(vaultUrl, fresh);
722
745
  } catch (error) {
723
- console.error("minuta: falha ao resolver imagem do vault", attrValue, error);
746
+ console.error("minuta: falha ao resolver imagem do vault", vaultUrl, error);
724
747
  }
725
748
  }));
726
749
  if (!resolved.size || editor.isDestroyed)
@@ -730,17 +753,10 @@ async function refreshVaultImages(editor, resolveUrl, options = {}) {
730
753
  editor.state.doc.descendants((node, pos) => {
731
754
  if (node.type.name !== "htmlIsland")
732
755
  return;
733
- let html = String(node.attrs.html ?? "");
734
- let changed = false;
735
- for (const [attrValue, freshUrl] of resolved) {
736
- const next = swapSrcKeepRef(html, attrValue, freshUrl);
737
- if (next !== html) {
738
- html = next;
739
- changed = true;
740
- }
741
- }
742
- if (changed) {
743
- tr.setNodeMarkup(pos, void 0, { ...node.attrs, html });
756
+ const html = String(node.attrs.html ?? "");
757
+ const next = renewVaultImageTags(html, resolved);
758
+ if (next !== html) {
759
+ tr.setNodeMarkup(pos, void 0, { ...node.attrs, html: next });
744
760
  touched++;
745
761
  }
746
762
  });
@@ -1577,6 +1593,14 @@ function createMinutaEditor(element, opts) {
1577
1593
  };
1578
1594
  reader.readAsDataURL(file);
1579
1595
  }
1596
+ let imageFallback = opts.imageFallback ?? "dataUri";
1597
+ function onImageUploadFailed(error, file) {
1598
+ opts.onImageUploadError?.(error, file);
1599
+ if (imageFallback === "none")
1600
+ return;
1601
+ console.error("[minuta-editor] upload de imagem falhou, embutindo como data URI", error);
1602
+ insertDataUriImage(file);
1603
+ }
1580
1604
  function onImageFile(event) {
1581
1605
  const input = event.target;
1582
1606
  const file = input.files?.[0];
@@ -1590,13 +1614,13 @@ function createMinutaEditor(element, opts) {
1590
1614
  tiptap?.chain().focus().insertContent(vaultImageHtml(uploaded.src, uploaded.vaultSrc)).run();
1591
1615
  return;
1592
1616
  }
1617
+ onImageUploadFailed(new Error("uploadImage returned null"), file);
1593
1618
  } catch (error) {
1594
- console.error("[minuta-editor] upload de imagem falhou, embutindo como data URI", error);
1619
+ onImageUploadFailed(error, file);
1595
1620
  }
1596
- insertDataUriImage(file);
1597
1621
  })();
1598
1622
  } else {
1599
- insertDataUriImage(file);
1623
+ onImageUploadFailed(new Error("no uploadImage configured"), file);
1600
1624
  }
1601
1625
  input.value = "";
1602
1626
  }
@@ -1797,7 +1821,7 @@ function createMinutaEditor(element, opts) {
1797
1821
  ed.view.dispatch(tr);
1798
1822
  return count;
1799
1823
  }
1800
- function setVariableImage(variableId, src) {
1824
+ function setVariableImage(variableId, src, vaultSrc) {
1801
1825
  const ed = tiptap;
1802
1826
  if (!ed || ed.isDestroyed)
1803
1827
  return 0;
@@ -1815,7 +1839,8 @@ function createMinutaEditor(element, opts) {
1815
1839
  if (node.type.name === "missingImage") {
1816
1840
  if (!islandType)
1817
1841
  continue;
1818
- const html = `<img src="${escapeAttr(src)}" alt="${escapeAttr(variableId)}" data-variable-id="${escapeAttr(variableId)}" data-parent-block-id="${escapeAttr(String(node.attrs.parentBlockId ?? ""))}" style="max-width: 100%; height: auto;" />`;
1842
+ const vaultAttr = vaultSrc ? ` data-vault-src="${escapeVaultAttr(vaultSrc)}"` : "";
1843
+ const html = `<img src="${escapeAttr(src)}"${vaultAttr} alt="${escapeAttr(variableId)}" data-variable-id="${escapeAttr(variableId)}" data-parent-block-id="${escapeAttr(String(node.attrs.parentBlockId ?? ""))}" style="max-width: 100%; height: auto;" />`;
1819
1844
  tr.replaceWith(pos, pos + node.nodeSize, islandType.create({ html }));
1820
1845
  count++;
1821
1846
  continue;
@@ -1825,8 +1850,13 @@ function createMinutaEditor(element, opts) {
1825
1850
  const imgs = tpl.content.querySelectorAll(`img[data-variable-id="${CSS.escape(variableId)}"]`);
1826
1851
  if (!imgs.length)
1827
1852
  continue;
1828
- for (const img of imgs)
1853
+ for (const img of imgs) {
1829
1854
  img.setAttribute("src", src);
1855
+ if (vaultSrc)
1856
+ img.setAttribute("data-vault-src", vaultSrc);
1857
+ else
1858
+ img.removeAttribute("data-vault-src");
1859
+ }
1830
1860
  tr.setNodeMarkup(pos, void 0, { ...node.attrs, html: tpl.innerHTML });
1831
1861
  count += imgs.length;
1832
1862
  }
@@ -2032,6 +2062,9 @@ function createMinutaEditor(element, opts) {
2032
2062
  scrollToVariable,
2033
2063
  setVariableValue,
2034
2064
  setVariableImage,
2065
+ setImageFallback(mode) {
2066
+ imageFallback = mode;
2067
+ },
2035
2068
  variablesInDocument,
2036
2069
  refreshVaultImages(resolveUrl) {
2037
2070
  const ed = tiptap;
@@ -2058,4 +2091,4 @@ function createMinutaEditor(element, opts) {
2058
2091
  return api;
2059
2092
  }
2060
2093
 
2061
- 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, PocUnderline, PocVariableChip, breaksEqual, buildPocExtensions, computePocBreaks, createMinutaEditor, decodeVaultAttr, dispatchVariableClick, escapeHtml, escapeVaultAttr, extractTemplateVariables, iconSvg, pocPageKey, refreshVaultImages, renumberPocFootnotes, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, variableChipHtml, vaultImageHtml };
2094
+ 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, PocUnderline, PocVariableChip, breaksEqual, buildPocExtensions, collectVaultRefs, computePocBreaks, createMinutaEditor, decodeVaultAttr, dispatchVariableClick, escapeHtml, escapeVaultAttr, extractTemplateVariables, iconSvg, pocPageKey, refreshVaultImages, renewVaultImageTags, renumberPocFootnotes, resolveTemplateVariables, sanitizeFootnoteHtml, sanitizeRichHtml, swapVaultSrc, 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[data-vault-src]{animation:poc-img-loading 1.4s ease-in-out infinite}@keyframes poc-img-loading{0%,to{opacity:.5}50%{opacity:.9}}.poc-editor-root .poc-lone-row{justify-content:center!important}.poc-editor-root .poc-lone-row>:not(.poc-lone-cell){flex:0 0 0!important;min-width:0!important;padding:0!important}.poc-editor-root .poc-lone-row>.poc-lone-cell{align-items:center!important;flex:0 0 auto!important;max-width:100%;min-width:0}.poc-editor-root [data-horizontal-align=left] .poc-island--img>img,.poc-editor-root [data-horizontal-align=left] .poc-island>img:only-child{margin-left:0}.poc-editor-root [data-horizontal-align=right] .poc-island--img>img,.poc-editor-root [data-horizontal-align=right] .poc-island>img:only-child{margin-right:0}.poc-editor-root .poc-review-cursor .poc-minuta-block{cursor:pointer}.poc-editor-root .poc-minuta-block{border-radius:4px;position:relative}.poc-editor-root .poc-minuta-block:hover{outline:1px dashed #c7d2fe;outline-offset:6px}.poc-editor-root.poc-no-block-origin .poc-minuta-block:hover{outline:none}.poc-editor-root.poc-no-block-origin .poc-minuta-block:hover:before{content:none}.poc-editor-root .poc-minuta-block:hover:before{background:#eef2ff;border:1px solid #c7d2fe;border-radius:4px;color:#6366f1;content:attr(data-block-title);font-size:10px;letter-spacing:.04em;padding:1px 8px;pointer-events:none;position:absolute;right:0;text-transform:uppercase;top:-22px;z-index:3}.poc-editor-root .poc-varchip{background:rgba(59,130,246,.06);border-radius:3px;box-shadow:inset 0 0 0 1px rgba(59,130,246,.25);cursor:pointer;transition:background .15s ease}.poc-editor-root .poc-varchip:hover{background:rgba(59,130,246,.16)}.poc-editor-root .poc-tplvar{background:rgba(251,191,36,.16);border-radius:3px;box-shadow:inset 0 0 0 1px rgba(180,83,9,.35);color:#78350f;display:inline;padding:0 2px;white-space:pre-wrap}.poc-editor-root .poc-tplvar--unknown{background:rgba(244,63,94,.12);box-shadow:inset 0 0 0 1px rgba(190,18,60,.45);color:#881337;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}.poc-editor-root .ProseMirror-selectednode.poc-tplvar{box-shadow:inset 0 0 0 2px rgba(180,83,9,.75)}.poc-editor-root .poc-missing-image .missing-image-warning:hover{background-color:rgba(254,174,0,.09);border-color:rgba(223,139,13,.85)}.poc-editor-root .poc-missing-image__remove{background:hsla(0,0%,100%,.75);border:none;border-radius:999px;color:#773613;cursor:pointer;font-size:16px;height:22px;line-height:1;opacity:0;position:absolute;right:4px;top:4px;transition:opacity .15s ease,background .15s ease;width:22px}.poc-editor-root .poc-missing-image:hover .poc-missing-image__remove{opacity:1}.poc-editor-root .poc-missing-image__remove:hover{background:rgba(254,174,0,.35)}.poc-editor-root .poc-missing-image.ProseMirror-selectednode .missing-image-warning{outline:2px solid rgba(223,139,13,.9);outline-offset:2px}.poc-editor-root .poc-page-notes{color:#1c242d;font-size:10.67px;line-height:1.25;padding-top:6px}.poc-editor-root .poc-page-notes:before{border-top:.5px solid #9aa4ae;content:"";display:block;margin-bottom:6px;width:30%}.poc-editor-root .poc-page-note{color:#1c242d;font-size:10.67px;font-weight:400;line-height:1.25;margin:0;text-align:justify}.poc-editor-root .poc-page-note sup{font-size:.8em;line-height:0;vertical-align:super}.poc-editor-root .poc-page-note a{color:#0563c1;text-decoration:underline}.poc-editor-root .poc-footnote{color:#1d4ed8;cursor:help;font-size:.7em;line-height:0;vertical-align:super}.poc-editor-root .poc-island{position:relative}.poc-editor-root .poc-island--img{cursor:grab}.poc-editor-root .poc-img-handle{background:#3b82f6;border:2px solid #fff;border-radius:3px;bottom:-6px;box-shadow:0 1px 3px rgba(0,0,0,.3);cursor:nwse-resize;height:12px;opacity:0;position:absolute;right:-6px;transition:opacity .12s ease;width:12px}.poc-editor-root .poc-island--img.ProseMirror-selectednode .poc-img-handle,.poc-editor-root .poc-island--img:hover .poc-img-handle{opacity:1}.poc-editor-root .poc-island.ProseMirror-selectednode{outline:2px solid #93c5fd;outline-offset:2px}.poc-editor-root .h-full{height:100%}.poc-editor-root .w-full{width:100%}.poc-editor-root .w-1px{width:1px}.poc-editor-root .w-64px{width:64px}.poc-editor-root .h-16px{height:16px}.poc-editor-root .flex{display:flex}.poc-editor-root .flex-col{flex-direction:column}.poc-editor-root .flex-1{flex:1 1 0%}.poc-editor-root .items-center{align-items:center}.poc-editor-root .gap-2px{gap:2px}.poc-editor-root .min-h-0{min-height:0}.poc-editor-root .overflow-y-auto{overflow-y:auto}.poc-editor-root .relative{position:relative}.poc-editor-root .hidden{display:none}.poc-editor-root .inline-block{display:inline-block}.poc-editor-root .align-middle{vertical-align:middle}.poc-editor-root .ml-auto{margin-left:auto}.poc-editor-root .mx-auto{margin-left:auto;margin-right:auto}.poc-editor-root .mx-2px{margin-left:2px;margin-right:2px}.poc-editor-root .p-2px{padding:2px}.poc-editor-root .py-24px{padding-bottom:24px;padding-top:24px}.poc-editor-root .bg-white{background:#fff}.poc-editor-root .bg-gray-120{background:#ebedf0}.poc-editor-root .bg-gray-200{background:#e5e7eb}.poc-editor-root .border{border-style:solid;border-width:1px}.poc-editor-root .border-gray-200{border-color:#e5e7eb}.poc-editor-root .rounded-8px{border-radius:8px}.poc-editor-root .shadow-md{box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1)}.poc-editor-root .shadow-lg{box-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1)}.poc-editor-root .font-bold{font-weight:700}.poc-editor-root .font-semibold{font-weight:600}.poc-editor-root .italic{font-style:italic}.poc-editor-root .underline{text-decoration:underline}.poc-editor-root .line-through{text-decoration:line-through}.poc-editor-root .text-red-600{color:#dc2626}.poc-editor-root .body-13-regular{font-size:13px;font-weight:400}.poc-editor-root{font-family:Inter Variable,Inter,-apple-system,Segoe UI,Roboto,sans-serif}.poc-editor-root .poc-toolbar{background:#fafbfc;border-bottom:.5px solid #dee3e7}.poc-editor-root .poc-tool{background:transparent;border:none;cursor:pointer}.poc-editor-root .poc-tool:hover{background:#ebedf0}.poc-editor-root .poc-tool--on{background:#e2e8f0}.poc-editor-root .poc-tool-select{background:#fff;border:.5px solid #d4d9df;cursor:pointer}.poc-editor-root .ProseMirror{outline:none}.poc-editor-root td,.poc-editor-root th{border:.5px solid #d4d9df}.poc-editor-root .poc-footnote-pop{background:#fff;border:.5px solid #d4d9df;border-radius:10px;box-shadow:0 10px 25px -5px rgba(0,0,0,.18);padding:10px 12px;position:absolute;width:364px;z-index:40}.poc-editor-root .poc-footnote-pop__head{color:#6b7280;font-size:11px;font-weight:650;letter-spacing:.04em;margin-bottom:6px;text-transform:uppercase}.poc-editor-root .poc-footnote-pop__toolbar{align-items:center;display:flex;gap:4px;margin-bottom:6px}.poc-editor-root .poc-footnote-pop__tool{background:transparent;border:none;border-radius:6px;color:#374151;cursor:pointer;font-size:12px;height:24px;width:24px}.poc-editor-root .poc-footnote-pop__tool:hover{background:rgba(28,36,45,.06)}.poc-editor-root .poc-footnote-pop__sep{background:#e5e7eb;height:16px;margin:0 2px;width:1px}.poc-editor-root .poc-footnote-pop__select{background:#fff;border:1px solid #e5e7eb;border-radius:6px;color:#374151;font-size:11px;height:24px;max-width:108px;outline:none}.poc-editor-root .poc-footnote-pop__select--narrow{max-width:58px}.poc-editor-root .poc-footnote-pop__swatch{border:1px solid rgba(0,0,0,.15);border-radius:4px;cursor:pointer;height:14px;padding:0;width:14px}.poc-editor-root .poc-footnote-pop__input{border:1px solid #e5e7eb;border-radius:8px;color:#111827;font-size:12.5px;line-height:1.5;max-height:160px;min-height:58px;outline:none;overflow-y:auto;padding:6px 8px;width:100%}.poc-editor-root .poc-footnote-pop__input:focus{border-color:#a5b4fc}.poc-editor-root .poc-footnote-pop__input:empty:before{color:#9ca3af;content:attr(data-placeholder)}.poc-editor-root .poc-footnote-pop__actions{align-items:center;display:flex;gap:8px;margin-top:8px}.poc-editor-root .poc-footnote-pop__spacer{flex:1}.poc-editor-root .poc-footnote-pop__actions button{background:transparent;border:none;border-radius:8px;color:#565d69;cursor:pointer;font-size:12px;font-weight:500;padding:4px 12px}.poc-editor-root .poc-footnote-pop__remove{color:#b91c1c!important}.poc-editor-root .poc-footnote-pop__save{background:rgba(0,0,0,.88)!important;color:#fff!important}.poc-editor-root{display:flex;flex-direction:column;height:100%;width:100%}.poc-editor-root .w-118px{width:118px}.poc-editor-root .poc-varpicker{background:#fff;border:1px solid #e5e7eb;border-radius:10px;box-shadow:0 12px 24px -8px rgba(0,0,0,.25);display:flex;flex-direction:column;font-size:13px;max-height:300px;overflow:hidden;position:absolute;width:320px;z-index:60}.poc-editor-root .poc-varpicker__search{border:0;border-bottom:1px solid #f3f4f6;font-family:inherit;font-size:13px;outline:none;padding:10px 12px}.poc-editor-root .poc-varpicker__hint{border-bottom:1px solid #f3f4f6;color:#6b7280;font-size:12px;padding:8px 12px}.poc-editor-root .poc-varpicker__list{flex:1;min-height:0;overflow-y:auto;padding:4px}.poc-editor-root .poc-varpicker__empty{color:#6b7280;font-size:12px;margin:0;padding:12px}.poc-editor-root .poc-varpicker__group{color:#9ca3af;font-size:11px;font-weight:600;letter-spacing:.04em;padding:8px 8px 4px;text-transform:uppercase}.poc-editor-root .poc-varpicker__item{background:none;border:0;border-radius:6px;cursor:pointer;display:grid;font-family:inherit;gap:2px 8px;grid-template-columns:1fr auto;padding:6px 8px;text-align:left;width:100%}.poc-editor-root .poc-varpicker__item--on{background:#f3f4f6}.poc-editor-root .poc-varpicker__label{color:#111827;font-weight:500}.poc-editor-root .poc-varpicker__key{color:#9ca3af;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px}.poc-editor-root .poc-varpicker__desc{color:#6b7280;display:-webkit-box;font-size:11px;grid-column:1/-1;-webkit-line-clamp:2;line-height:1.4;overflow:hidden;-webkit-box-orient:vertical}.poc-editor-root [hidden]{display:none!important}.poc-editor-root .poc-varchip--flash{background:rgba(59,130,246,.35);transition:background .9s ease}
1
+ .poc-editor-root .poc-ins{background:rgba(34,197,94,.16);text-decoration:underline;text-decoration-color:#16a34a}.poc-editor-root .poc-del{background:rgba(239,68,68,.12);color:#b91c1c;text-decoration:line-through}.poc-editor-root .poc-bubble-btn{border-radius:6px;font-size:13px;padding:4px 8px;transition:all .15s;transition-timing-function:ease}.poc-editor-root .poc-toolbar{align-items:center;display:flex;flex-wrap:wrap;gap:2px;padding:4px 12px}@media (max-width:640px){.poc-editor-root .poc-toolbar{flex-wrap:nowrap;overflow-x:auto;padding:4px 8px;scrollbar-width:none}.poc-editor-root .poc-toolbar::-webkit-scrollbar{display:none}.poc-editor-root .poc-toolbar>*{flex:none}}.poc-editor-root .poc-tool{align-items:center;border-radius:6px;display:flex;font-size:13px;height:28px;justify-content:center;min-width:28px;padding-left:6px;padding-right:6px;position:relative;transition:all .15s;transition-timing-function:ease}.poc-editor-root .poc-tool-sep{background:#dee3e7;height:20px;margin:0 6px;width:1px}.poc-editor-root .poc-tool-select{border-radius:6px;font-size:12px;height:28px;padding-left:6px;padding-right:6px}.poc-editor-root .poc-color-underline{background:#dc2626;border-radius:1px;bottom:4px;height:3px;left:7px;position:absolute;right:7px}.poc-editor-root .poc-palette{background:#fff;border:.5px solid #dee3e7;border-radius:8px;box-shadow:0 8px 24px rgba(0,0,0,.12);display:flex;flex-wrap:wrap;gap:2px;left:0;padding:8px;position:absolute;top:32px;width:230px;z-index:50}.poc-editor-root .poc-palette-swatch{border:1px solid rgba(0,0,0,.1);border-radius:3px;cursor:pointer;height:19px;width:19px}.poc-editor-root .poc-palette-swatch:hover{transform:scale(1.2)}.poc-editor-root .poc-palette-custom{align-items:center;color:#565d69;cursor:pointer;display:flex;font-size:12px;margin-top:6px;width:100%}.poc-editor-root .poc-color-swatch{border:1px solid rgba(0,0,0,.12);border-radius:4px;cursor:pointer;height:16px;margin:0 2px;width:16px}.poc-editor-root .poc-color-swatch:hover{transform:scale(1.15)}.poc-editor-root .poc-first-header{align-items:center;cursor:pointer;display:flex;gap:12px;position:absolute;top:0}.poc-editor-root .poc-first-header[style*=center]{justify-content:center}.poc-editor-root .poc-first-header[style*=right]{justify-content:flex-end}.poc-editor-root .poc-first-header:hover,.poc-editor-root .poc-last-footer:hover,.poc-editor-root .poc-page-footerarea:hover,.poc-editor-root .poc-page-headerarea:hover{background:rgba(99,102,241,.06);outline:1px dashed #c7d2fe}.poc-editor-root .poc-last-footer{align-items:center;bottom:0;color:#94a3b8;cursor:pointer;display:flex;font-size:11px;justify-content:space-between;position:absolute}.poc-editor-root .poc-chrome-text{color:#64748b;font-size:11px}.poc-editor-root .poc-chrome-text img{display:inline-block;max-height:48px;max-width:200px;vertical-align:middle}.poc-editor-root .poc-pagebreak-marker{border-top:1px dashed #a5b4fc;font-size:0!important;height:16px;line-height:0!important;margin:6px 0!important;position:relative}.poc-editor-root .poc-pagebreak-marker:after{background:#fff;color:#818cf8;content:"quebra de página do template";font-size:10px;left:50%;line-height:16px;padding:0 8px;position:absolute;top:-8px;transform:translateX(-50%)}.poc-editor-root .poc-page-chrome{color:initial;display:block;font-style:normal;font-weight:400;letter-spacing:normal;line-height:normal;pointer-events:none;text-align:initial;text-indent:0;text-transform:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;white-space:normal}.poc-editor-root .poc-page-chrome>.poc-page-footerarea:not(:hover),.poc-editor-root .poc-page-chrome>.poc-page-headerarea:not(:hover),.poc-editor-root .poc-page-chrome>.poc-page-notes{background:#fff}.poc-editor-root tr.poc-page-chrome-row>td.poc-page-chrome-cell{background:transparent!important;border:0!important;padding:0!important;vertical-align:top}.poc-editor-root .poc-page-footerarea,.poc-editor-root .poc-page-headerarea{cursor:pointer;pointer-events:auto}.poc-editor-root .poc-page-footerarea{align-items:center;color:#94a3b8;display:flex;font-size:11px;justify-content:space-between}.poc-editor-root .poc-page-gapband{background:#eceef1;box-shadow:inset 0 6px 6px -6px rgba(0,0,0,.25),inset 0 -6px 6px -6px rgba(0,0,0,.25)}.poc-editor-root .poc-page-headerarea{align-items:center;display:flex}.poc-editor-root .poc-page-headerarea[style*=center]{justify-content:center}.poc-editor-root .poc-page-headerarea[style*=right]{justify-content:flex-end}.poc-editor-root .ProseMirror{white-space:pre-wrap;word-wrap:break-word}.poc-editor-root h1{color:#0f172a;font-size:24px;font-weight:640;letter-spacing:-.3px;line-height:32px;margin:0 0 20px}.poc-editor-root h2{color:#0f172a;font-size:19px;font-weight:620;letter-spacing:-.2px;line-height:26px;margin:28px 0 14px}.poc-editor-root h3{color:#0f172a;font-size:17px;font-weight:600;letter-spacing:-.1px;line-height:24px;margin:24px 0 12px}.poc-editor-root h1:first-child,.poc-editor-root h2:first-child,.poc-editor-root h3:first-child{margin-top:0}.poc-editor-root strong{font-weight:540}.poc-editor-root p{color:#000;line-height:28px;line-height:1.7em;margin-bottom:.75em;text-align:justify}.poc-editor-root blockquote,.poc-editor-root p{font-size:18px;font-weight:400;letter-spacing:-.4px}.poc-editor-root blockquote{line-height:28px;margin-bottom:2em;margin-left:35%}.poc-editor-root ol,.poc-editor-root ul{margin-bottom:2em}.poc-editor-root li{list-style-position:inside;margin-bottom:16px;margin-left:48px}.poc-editor-root ul>li{list-style-type:disc}.poc-editor-root ol>li{list-style-type:decimal}.poc-editor-root table{border:.5px solid #d4d9df;max-width:100%;table-layout:fixed;width:100%}.poc-editor-root th{font-weight:700}.poc-editor-root td,.poc-editor-root th{color:inherit;font-size:inherit;overflow-wrap:anywhere;padding:12px;text-align:left}.poc-editor-root td{line-height:inherit}.poc-editor-root td p,.poc-editor-root th p{color:inherit;font-size:inherit;line-height:inherit;margin-bottom:0}.poc-editor-root img{display:block;max-width:100%}.poc-editor-root .poc-island--img>img,.poc-editor-root .poc-island>img:only-child{margin-left:auto;margin-right:auto}.poc-editor-root .poc-chrome-canvas{overflow:hidden}.poc-editor-root .poc-chrome-canvas [data-el]{position:absolute}.poc-editor-root .poc-chrome-canvas [data-el=text]{color:#64748b;font-size:11px;line-height:1.4;text-align:left;white-space:pre-wrap}.poc-editor-root img[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.2.1",
3
+ "version": "1.3.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",