@meistrari/minuta-nuxt 1.1.1 → 1.2.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.
@@ -1,93 +0,0 @@
1
- import type { Editor } from '@tiptap/core';
2
- import { Extension as TiptapExtension, Mark as TiptapMark, Node as TiptapNode } from '@tiptap/core';
3
- import type { EditorView as PMEditorView } from '@tiptap/pm/view';
4
- import type { PocPageConfig } from './paginationPlugin.js';
5
- import type { MinutaVariableDef } from '../utils/templateVariables.js';
6
- /**
7
- * Extensões Tiptap da PoC do editor de minuta.
8
- *
9
- * Modelo: doc → minutaBlock+ → (paragraph | heading | styledDiv | htmlIsland | ...)
10
- * - minutaBlock: wrapper com proveniência (blockId/título do bloco do template)
11
- * - htmlIsland: tabelas/listas/imagens/svg preservados como ilhas não-editáveis (HTML cru)
12
- * - variableChip: <span data-variable-id> vira nó atômico — a variável continua "viva"
13
- * - templateVariable: <span data-minuta-var> — placeholder NÃO resolvido do template
14
- * - inlineStyle/styledDiv/passthrough: preservam o CSS inline do pipeline de render
15
- */
16
- /**
17
- * Meta de transação: troca de imagem fria pelo blob recém-baixado (load
18
- * progressivo). Não é edição do advogado — fica fora do undo e não pode
19
- * marcar o documento como sujo (senão o autosave dispara sozinho no load).
20
- */
21
- export declare const POC_ASSET_SWAP = "pocAssetSwap";
22
- export declare const PocDocument: TiptapNode<any, any>;
23
- export declare const PocMinutaBlock: TiptapNode<any, any>;
24
- export declare const PocHtmlIsland: TiptapNode<any, any>;
25
- /**
26
- * Aviso de imagem faltando — a caixa tracejada que o render emite quando a
27
- * variável de imagem não foi preenchida.
28
- *
29
- * Antes ela chegava aqui como um `styledDiv` comum: apagar exigia selecionar o
30
- * texto por dentro, e a moldura sobrava no documento. Como nó próprio ela é
31
- * atômica e selecionável (um clique + Backspace resolve), ganha um botão de
32
- * remover e um alvo de clique para escolher a imagem ali mesmo.
33
- *
34
- * Na etapa de edição o DOCUMENTO é a verdade — o checklist fica travado —, então
35
- * escolher a imagem insere no texto editado; não mexe na variável do caso.
36
- *
37
- * O nó guarda só o ID da variável e REDESENHA a caixa a partir dele. Guardar o
38
- * `outerHTML` e devolvê-lo a um `innerHTML` faria do corpo da edição — que é
39
- * dado persistido, editável por qualquer um do workspace — um vetor de stored
40
- * XSS: bastaria uma `div.missing-image-warning` forjada com `onerror` para
41
- * rodar script no editor de quem abrisse o caso depois.
42
- */
43
- export declare const PocMissingImage: TiptapNode<any, any>;
44
- export declare const PocVariableChip: TiptapNode<any, any>;
45
- /**
46
- * Placeholder de variável do TEMPLATE — o `#NOME_VARIAVEL` de antigamente, só
47
- * que como nó atômico em vez de texto (ver `utils/templateVariables.ts` para o
48
- * porquê e para o formato).
49
- *
50
- * O catálogo (`options.catalog`) vem do app hospedeiro: o CDB não sabe o que é
51
- * `SIGLA_FORO`, só sabe que existe um lugar no documento com esse nome. O nó
52
- * guarda o rótulo junto (para um template abrir legível sem catálogo, ex.: no
53
- * histórico), mas quem manda na exibição é o catálogo — renomear uma variável
54
- * no host reflete em todo template já salvo, sem migrar documento nenhum.
55
- *
56
- * Sobrevive à geração: `resolveTemplateVariables` só troca o que tem valor, e o
57
- * que sobra continua sendo este nó — um buraco visível no parágrafo em que ele
58
- * está, e não um erro genérico no rodapé de um modal.
59
- */
60
- /** o catálogo pode chegar depois do mount (host que carrega async) — daí o getter */
61
- export type MinutaVariableCatalog = MinutaVariableDef[] | (() => MinutaVariableDef[]);
62
- export declare const PocTemplateVariable: TiptapNode<{
63
- catalog: MinutaVariableCatalog;
64
- }, any>;
65
- /**
66
- * Nota de rodapé: o render devolve `<sup data-footnote="texto">n</sup>` e o
67
- * export transforma em nota de rodapé DE VERDADE no Word (o pipeline legado faz
68
- * o mesmo via footnotes_filter.lua do conversor). Precisa ser um nó do schema —
69
- * senão o Tiptap descarta o data-footnote no round-trip e o texto da nota some.
70
- */
71
- export declare const PocFootnoteRef: TiptapNode<any, any>;
72
- /** re-sequencia a numeração das chamadas de nota na ordem do documento */
73
- export declare function renumberPocFootnotes(editor: Editor): void;
74
- export declare const PocStyledDiv: TiptapNode<any, any>;
75
- export declare const PocInlineStyle: TiptapMark<any, any>;
76
- export declare const PocUnderline: TiptapMark<any, any>;
77
- /** Preserva style/class inline nos blocos de texto (o pipeline de render inlina todo o CSS). */
78
- export declare const PocStylePassthrough: TiptapExtension<any, any>;
79
- export declare function buildPocExtensions(pageConfig?: PocPageConfig, options?: {
80
- /** catálogo de variáveis do host — habilita os chips do modo template */
81
- variables?: MinutaVariableCatalog;
82
- /**
83
- * Primeiro a ver o teclado, ANTES do keymap do editor. Devolver `true`
84
- * consome a tecla.
85
- *
86
- * Existe porque `editorProps.handleKeyDown` não serve: o `someProp` do
87
- * ProseMirror percorre os plugins antes das props diretas, então o keymap
88
- * do StarterKit trata o Enter (quebra o parágrafo) e o handler da view
89
- * nunca roda. Quem precisa de um popover dirigido pelo teclado com o foco
90
- * ainda no editor — o seletor de variável — depende disso.
91
- */
92
- handleKeyDown?: (view: PMEditorView, event: KeyboardEvent) => boolean;
93
- }): (TiptapNode<any, any> | TiptapMark<any, any> | TiptapExtension<any, any>)[];
@@ -1,548 +0,0 @@
1
- import { Extension as TiptapExtension, Mark as TiptapMark, Node as TiptapNode, mergeAttributes } from "@tiptap/core";
2
- import TiptapStarterKit from "@tiptap/starter-kit";
3
- import Table from "@tiptap/extension-table";
4
- import TableCell from "@tiptap/extension-table-cell";
5
- import TableHeader from "@tiptap/extension-table-header";
6
- import TableRow from "@tiptap/extension-table-row";
7
- import { Plugin as PMPlugin } from "@tiptap/pm/state";
8
- import { sanitizeRichHtml } from "../utils/sanitizeRichHtml.js";
9
- import { PocPaginationPlugin } from "./paginationPlugin.js";
10
- export const POC_ASSET_SWAP = "pocAssetSwap";
11
- function htmlToDom(html) {
12
- const tpl = document.createElement("template");
13
- tpl.innerHTML = sanitizeRichHtml(html);
14
- return tpl.content.firstElementChild ?? document.createElement("div");
15
- }
16
- export const PocDocument = TiptapNode.create({
17
- name: "doc",
18
- topNode: true,
19
- content: "minutaBlock+"
20
- });
21
- export const PocMinutaBlock = TiptapNode.create({
22
- name: "minutaBlock",
23
- group: "block",
24
- content: "block+",
25
- defining: true,
26
- isolating: true,
27
- addAttributes() {
28
- return {
29
- blockId: { default: null },
30
- blockTitle: { default: null }
31
- };
32
- },
33
- parseHTML() {
34
- return [{
35
- tag: "div[data-minuta-block]",
36
- priority: 120,
37
- getAttrs: (el) => ({
38
- blockId: el.getAttribute("data-block-id"),
39
- blockTitle: el.getAttribute("data-block-title")
40
- })
41
- }];
42
- },
43
- renderHTML({ HTMLAttributes, node }) {
44
- return ["div", mergeAttributes(HTMLAttributes, {
45
- "data-minuta-block": "",
46
- "data-block-id": node.attrs.blockId,
47
- "data-block-title": node.attrs.blockTitle,
48
- "class": "poc-minuta-block"
49
- }), 0];
50
- }
51
- });
52
- export const PocHtmlIsland = TiptapNode.create({
53
- name: "htmlIsland",
54
- group: "block",
55
- atom: true,
56
- selectable: true,
57
- // atomos arrastáveis: mover imagens/tabelas pelo documento
58
- draggable: true,
59
- addAttributes() {
60
- return { html: { default: "" } };
61
- },
62
- parseHTML() {
63
- const capture = (el) => ({ html: el.outerHTML });
64
- return ["ul", "ol", "img", "figure", "svg"].map((tag) => ({
65
- tag,
66
- priority: 100,
67
- getAttrs: capture
68
- }));
69
- },
70
- renderHTML({ node }) {
71
- return htmlToDom(node.attrs.html);
72
- },
73
- addNodeView() {
74
- return ({ node, getPos, editor }) => {
75
- const dom = document.createElement("div");
76
- dom.className = "poc-island";
77
- dom.contentEditable = "false";
78
- dom.innerHTML = sanitizeRichHtml(node.attrs.html);
79
- const img = dom.children.length === 1 && dom.firstElementChild instanceof HTMLImageElement ? dom.firstElementChild : null;
80
- if (img)
81
- dom.classList.add("poc-island--img");
82
- if (img && editor.isEditable) {
83
- const handle = document.createElement("div");
84
- handle.className = "poc-img-handle";
85
- handle.title = "Arraste para redimensionar";
86
- dom.appendChild(handle);
87
- let startX = 0;
88
- let startWidth = 0;
89
- let scale = 1;
90
- let maxWidth = Number.POSITIVE_INFINITY;
91
- const onMove = (event) => {
92
- const width = Math.round(startWidth + (event.clientX - startX) / scale);
93
- img.style.width = `${Math.min(maxWidth, Math.max(40, width))}px`;
94
- img.style.height = "auto";
95
- };
96
- const onUp = () => {
97
- document.removeEventListener("mousemove", onMove);
98
- document.removeEventListener("mouseup", onUp);
99
- const pos = typeof getPos === "function" ? getPos() : null;
100
- if (typeof pos === "number") {
101
- const clone = dom.cloneNode(true);
102
- clone.querySelector(".poc-img-handle")?.remove();
103
- editor.view.dispatch(
104
- editor.state.tr.setNodeMarkup(pos, void 0, { html: clone.innerHTML })
105
- );
106
- }
107
- };
108
- handle.addEventListener("mousedown", (event) => {
109
- event.preventDefault();
110
- event.stopPropagation();
111
- startX = event.clientX;
112
- startWidth = img.offsetWidth;
113
- scale = img.offsetWidth ? img.getBoundingClientRect().width / img.offsetWidth : 1;
114
- maxWidth = dom.parentElement?.clientWidth || Number.POSITIVE_INFINITY;
115
- document.addEventListener("mousemove", onMove);
116
- document.addEventListener("mouseup", onUp);
117
- });
118
- }
119
- return { dom };
120
- };
121
- }
122
- });
123
- let missingImageSeq = 0;
124
- function nextMissingImageUid() {
125
- missingImageSeq += 1;
126
- return `mi-${missingImageSeq}`;
127
- }
128
- const MISSING_IMAGE_BOX_STYLE = "box-sizing: border-box; max-width: 100%; border: 2px dashed rgba(223, 139, 13, 0.43); padding: 16px; margin: 12px 0; border-radius: 8px; background-color: rgba(254, 174, 0, 0.03); color: rgb(119, 54, 19); text-align: center; box-shadow: inset 0 0 8px #e6510011;";
129
- const MISSING_IMAGE_ROW_STYLE = "display: flex; align-items: center; justify-content: center; gap: 8px;";
130
- export const PocMissingImage = TiptapNode.create({
131
- name: "missingImage",
132
- group: "block",
133
- atom: true,
134
- selectable: true,
135
- draggable: true,
136
- addAttributes() {
137
- return {
138
- variableId: { default: null },
139
- parentBlockId: { default: null },
140
- /**
141
- * Identidade do nó DENTRO desta sessão do editor.
142
- *
143
- * Um fluxo demorado (escolher arquivo + upload) precisa voltar
144
- * exatamente ao aviso que foi clicado. Posição não serve: o
145
- * documento muda no meio. Tipo + variável também não: o mesmo
146
- * aviso pode aparecer várias vezes, e um delete+insert põe outro
147
- * igual no mesmo lugar. Com um id por nó, achar é inequívoco —
148
- * se ele sumiu, não achamos; se ele andou, achamos onde parou.
149
- *
150
- * Gerado no parse e NÃO serializado: vale enquanto o editor viver,
151
- * que é o tempo de vida do fluxo. Colar um aviso passa pelo parse
152
- * de novo e ganha id próprio, então nunca há dois iguais.
153
- */
154
- uid: { default: null }
155
- };
156
- },
157
- parseHTML() {
158
- return [{
159
- tag: "div.missing-image-warning",
160
- // acima do styledDiv (40), senão a caixa vira container editável de novo
161
- priority: 120,
162
- getAttrs: (el) => ({
163
- variableId: el.getAttribute("data-variable-id"),
164
- parentBlockId: el.getAttribute("data-parent-block-id"),
165
- uid: nextMissingImageUid()
166
- })
167
- }];
168
- },
169
- renderHTML({ node }) {
170
- return [
171
- "div",
172
- {
173
- "class": "missing-image-warning",
174
- "data-variable-id": node.attrs.variableId ?? "",
175
- "data-parent-block-id": node.attrs.parentBlockId ?? "",
176
- "style": MISSING_IMAGE_BOX_STYLE
177
- // `uid` fica de fora de propósito: é identidade de sessão, não dado
178
- },
179
- ["span", { style: MISSING_IMAGE_ROW_STYLE }, `A imagem ${node.attrs.variableId ?? ""} est\xE1 faltando`]
180
- ];
181
- },
182
- addNodeView() {
183
- return ({ node, getPos, editor }) => {
184
- const dom = document.createElement("div");
185
- dom.className = "poc-missing-image";
186
- dom.contentEditable = "false";
187
- const caixa = document.createElement("div");
188
- caixa.className = "missing-image-warning";
189
- caixa.setAttribute("style", MISSING_IMAGE_BOX_STYLE);
190
- const linha = document.createElement("span");
191
- linha.setAttribute("style", MISSING_IMAGE_ROW_STYLE);
192
- linha.textContent = `\u26A0 A imagem ${node.attrs.variableId ?? ""} est\xE1 faltando`;
193
- caixa.appendChild(linha);
194
- dom.appendChild(caixa);
195
- if (!editor.isEditable)
196
- return { dom };
197
- caixa.style.position = "relative";
198
- caixa.style.cursor = "pointer";
199
- caixa.title = "Clique para escolher uma imagem";
200
- const remover = document.createElement("button");
201
- remover.type = "button";
202
- remover.className = "poc-missing-image__remove";
203
- remover.title = "Remover este aviso";
204
- remover.setAttribute("aria-label", "Remover este aviso");
205
- remover.textContent = "\xD7";
206
- remover.addEventListener("mousedown", (event) => {
207
- event.preventDefault();
208
- event.stopPropagation();
209
- const pos = typeof getPos === "function" ? getPos() : null;
210
- if (typeof pos === "number")
211
- editor.view.dispatch(editor.state.tr.delete(pos, pos + node.nodeSize));
212
- });
213
- caixa.appendChild(remover);
214
- dom.addEventListener("click", (event) => {
215
- if (event.target.closest(".poc-missing-image__remove"))
216
- return;
217
- event.preventDefault();
218
- const pos = typeof getPos === "function" ? getPos() : null;
219
- window.dispatchEvent(new CustomEvent("poc:pick-image", {
220
- detail: { variableId: node.attrs.variableId, uid: node.attrs.uid, hintPos: pos }
221
- }));
222
- });
223
- return { dom };
224
- };
225
- }
226
- });
227
- export const PocVariableChip = TiptapNode.create({
228
- name: "variableChip",
229
- inline: true,
230
- group: "inline",
231
- atom: true,
232
- selectable: true,
233
- addAttributes() {
234
- return {
235
- variableId: { default: null },
236
- parentBlockId: { default: null },
237
- html: { default: "" },
238
- text: { default: "" }
239
- };
240
- },
241
- parseHTML() {
242
- return [{
243
- tag: "span[data-variable-id]",
244
- priority: 110,
245
- getAttrs: (el) => ({
246
- variableId: el.getAttribute("data-variable-id"),
247
- parentBlockId: el.getAttribute("data-parent-block-id"),
248
- html: el.outerHTML,
249
- text: el.textContent ?? ""
250
- })
251
- }];
252
- },
253
- renderHTML({ node }) {
254
- return htmlToDom(node.attrs.html);
255
- },
256
- addNodeView() {
257
- return ({ node }) => {
258
- const dom = document.createElement("span");
259
- dom.className = "poc-varchip";
260
- dom.contentEditable = "false";
261
- dom.innerHTML = sanitizeRichHtml(node.attrs.html);
262
- dom.addEventListener("click", (event) => {
263
- event.preventDefault();
264
- window.dispatchEvent(new CustomEvent("poc:variable-click", {
265
- detail: {
266
- variableId: node.attrs.variableId,
267
- parentBlockId: node.attrs.parentBlockId,
268
- text: node.attrs.text
269
- }
270
- }));
271
- });
272
- return { dom };
273
- };
274
- }
275
- });
276
- function readCatalog(catalog) {
277
- return typeof catalog === "function" ? catalog() : catalog;
278
- }
279
- export const PocTemplateVariable = TiptapNode.create({
280
- name: "templateVariable",
281
- inline: true,
282
- group: "inline",
283
- atom: true,
284
- selectable: true,
285
- addOptions() {
286
- return { catalog: [] };
287
- },
288
- addAttributes() {
289
- return {
290
- varKey: { default: null },
291
- label: { default: null }
292
- };
293
- },
294
- parseHTML() {
295
- return [{
296
- // acima do PocInlineStyle (40): é nó, não span estilizado
297
- tag: "span[data-minuta-var]",
298
- priority: 115,
299
- getAttrs: (el) => {
300
- const key = el.getAttribute("data-minuta-var")?.trim();
301
- if (!key)
302
- return false;
303
- return {
304
- varKey: key,
305
- label: el.getAttribute("data-minuta-var-label")?.trim() || el.textContent?.trim() || key
306
- };
307
- }
308
- }];
309
- },
310
- renderHTML({ node }) {
311
- const key = node.attrs.varKey ?? "";
312
- const label = node.attrs.label || key;
313
- return ["span", {
314
- "data-minuta-var": key,
315
- "data-minuta-var-label": label,
316
- "class": "poc-tplvar"
317
- }, label];
318
- },
319
- addNodeView() {
320
- return ({ node }) => {
321
- const key = node.attrs.varKey ?? "";
322
- const catalog = readCatalog(this.options.catalog);
323
- const def = catalog.find((item) => item.key === key);
324
- const dom = document.createElement("span");
325
- dom.className = "poc-tplvar";
326
- dom.contentEditable = "false";
327
- dom.setAttribute("data-minuta-var", key);
328
- dom.textContent = def?.label || node.attrs.label || key;
329
- dom.title = def?.description ? `${key} \u2014 ${def.description}` : key;
330
- if (catalog.length && !def)
331
- dom.classList.add("poc-tplvar--unknown");
332
- return { dom };
333
- };
334
- },
335
- addCommands() {
336
- return {
337
- insertTemplateVariable: (variable) => ({ commands }) => commands.insertContent({
338
- type: "templateVariable",
339
- attrs: { varKey: variable.key, label: variable.label }
340
- })
341
- };
342
- }
343
- });
344
- export const PocFootnoteRef = TiptapNode.create({
345
- name: "footnoteRef",
346
- inline: true,
347
- group: "inline",
348
- atom: true,
349
- selectable: false,
350
- addAttributes() {
351
- return {
352
- number: { default: "" },
353
- /** conteúdo da nota em HTML de ênfase (b/i/u/br) */
354
- text: { default: "" },
355
- /** corpo declarado no template (`font-size: 9pt`), em pontos */
356
- size: { default: null }
357
- };
358
- },
359
- parseHTML() {
360
- return [{
361
- tag: "sup[data-footnote]",
362
- priority: 110,
363
- getAttrs: (el) => ({
364
- number: el.textContent ?? "",
365
- text: el.getAttribute("data-footnote") ?? "",
366
- size: Number.parseFloat(el.getAttribute("data-footnote-size") ?? "") || null
367
- })
368
- }];
369
- },
370
- renderHTML({ node }) {
371
- const attrs = { "data-footnote": node.attrs.text, "class": "poc-footnote" };
372
- if (node.attrs.size)
373
- attrs["data-footnote-size"] = String(node.attrs.size);
374
- return ["sup", attrs, node.attrs.number];
375
- },
376
- addNodeView() {
377
- return ({ node, editor, getPos }) => {
378
- const dom = document.createElement("sup");
379
- dom.className = "poc-footnote";
380
- dom.contentEditable = "false";
381
- dom.textContent = node.attrs.number;
382
- dom.title = node.attrs.text;
383
- dom.addEventListener("click", (event) => {
384
- if (!editor.isEditable || typeof getPos !== "function")
385
- return;
386
- event.preventDefault();
387
- event.stopPropagation();
388
- const pos = getPos();
389
- if (pos == null)
390
- return;
391
- window.dispatchEvent(new CustomEvent("poc:edit-footnote", { detail: { pos } }));
392
- });
393
- return { dom };
394
- };
395
- }
396
- });
397
- export function renumberPocFootnotes(editor) {
398
- if (!editor || editor.isDestroyed)
399
- return;
400
- const tr = editor.state.tr;
401
- let index = 0;
402
- let touched = false;
403
- editor.state.doc.descendants((node, pos) => {
404
- if (node.type.name !== "footnoteRef")
405
- return;
406
- index++;
407
- const number = String(index);
408
- if (node.attrs.number !== number) {
409
- tr.setNodeMarkup(pos, void 0, { ...node.attrs, number });
410
- touched = true;
411
- }
412
- });
413
- if (touched)
414
- editor.view.dispatch(tr);
415
- }
416
- export const PocStyledDiv = TiptapNode.create({
417
- name: "styledDiv",
418
- group: "block",
419
- content: "block+",
420
- addAttributes() {
421
- const passthrough = (name) => ({
422
- default: null,
423
- parseHTML: (el) => el.getAttribute(name),
424
- renderHTML: (attrs) => attrs[name] != null ? { [name]: attrs[name] } : {}
425
- });
426
- return {
427
- "style": { default: null },
428
- "class": { default: null },
429
- // alinhamento de colunas do template (usado pelo CSS de centralização de imagens)
430
- "data-horizontal-align": passthrough("data-horizontal-align"),
431
- "data-vertical-align": passthrough("data-vertical-align"),
432
- "data-width": passthrough("data-width")
433
- };
434
- },
435
- parseHTML() {
436
- return [{
437
- tag: "div",
438
- priority: 40,
439
- getAttrs: (el) => {
440
- if (el.hasAttribute("data-minuta-block"))
441
- return false;
442
- return { style: el.getAttribute("style"), class: el.getAttribute("class") };
443
- }
444
- }];
445
- },
446
- renderHTML({ HTMLAttributes }) {
447
- return ["div", mergeAttributes(HTMLAttributes), 0];
448
- }
449
- });
450
- export const PocInlineStyle = TiptapMark.create({
451
- name: "inlineStyle",
452
- addAttributes() {
453
- return {
454
- style: { default: null },
455
- class: { default: null }
456
- };
457
- },
458
- parseHTML() {
459
- return [{
460
- tag: "span",
461
- priority: 40,
462
- getAttrs: (el) => {
463
- if (el.hasAttribute("data-variable-id") || el.hasAttribute("data-minuta-var"))
464
- return false;
465
- const style = el.getAttribute("style");
466
- const cls = el.getAttribute("class");
467
- if (!style && !cls)
468
- return false;
469
- return { style, class: cls };
470
- }
471
- }];
472
- },
473
- renderHTML({ HTMLAttributes }) {
474
- return ["span", mergeAttributes(HTMLAttributes), 0];
475
- }
476
- });
477
- export const PocUnderline = TiptapMark.create({
478
- name: "underline",
479
- parseHTML() {
480
- return [
481
- { tag: "u" },
482
- { style: "text-decoration", consuming: false, getAttrs: (value) => value.includes("underline") ? {} : false }
483
- ];
484
- },
485
- renderHTML() {
486
- return ["u", 0];
487
- },
488
- addCommands() {
489
- return {
490
- toggleUnderline: () => ({ commands }) => commands.toggleMark("underline")
491
- };
492
- }
493
- });
494
- export const PocStylePassthrough = TiptapExtension.create({
495
- name: "pocStylePassthrough",
496
- addGlobalAttributes() {
497
- const attr = (name) => ({
498
- default: null,
499
- parseHTML: (el) => el.getAttribute(name),
500
- renderHTML: (attrs) => attrs[name] ? { [name]: attrs[name] } : {}
501
- });
502
- return [{
503
- types: ["paragraph", "heading", "blockquote", "table", "tableRow", "tableCell", "tableHeader"],
504
- attributes: { style: attr("style"), class: attr("class") }
505
- }];
506
- }
507
- });
508
- export function buildPocExtensions(pageConfig, options) {
509
- const extensions = [
510
- PocDocument,
511
- TiptapStarterKit.configure({ document: false }),
512
- Table.configure({ resizable: true }),
513
- TableRow,
514
- TableCell,
515
- TableHeader,
516
- PocMinutaBlock,
517
- PocHtmlIsland,
518
- PocMissingImage,
519
- PocVariableChip,
520
- PocTemplateVariable.configure({ catalog: options?.variables ?? [] }),
521
- PocFootnoteRef,
522
- PocStyledDiv,
523
- PocInlineStyle,
524
- PocUnderline,
525
- PocStylePassthrough
526
- ];
527
- const handleKeyDown = options?.handleKeyDown;
528
- if (handleKeyDown) {
529
- extensions.push(TiptapExtension.create({
530
- name: "pocKeyDownFirst",
531
- // acima do StarterKit (100): o ExtensionManager ordena os plugins
532
- // por prioridade, e é essa ordem que o someProp percorre
533
- priority: 1e3,
534
- addProseMirrorPlugins() {
535
- return [new PMPlugin({ props: { handleKeyDown } })];
536
- }
537
- }));
538
- }
539
- if (pageConfig) {
540
- extensions.push(TiptapExtension.create({
541
- name: "pocPagination",
542
- addProseMirrorPlugins() {
543
- return [PocPaginationPlugin(pageConfig)];
544
- }
545
- }));
546
- }
547
- return extensions;
548
- }