@meistrari/minuta-react 1.0.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 +157 -0
- package/dist/index.d.mts +56 -0
- package/dist/index.d.ts +56 -0
- package/dist/index.mjs +72 -0
- package/package.json +98 -0
package/README.md
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# @meistrari/minuta-react
|
|
2
|
+
|
|
3
|
+
O editor de minuta do **defesa.ai** como componente React — a folha A4 paginada,
|
|
4
|
+
edição rica, placeholders de variável e export DOCX fiel ao preview. Casca fina
|
|
5
|
+
sobre [`@meistrari/minuta-editor`](../minuta-editor), o núcleo sem framework.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { useRef } from 'react'
|
|
9
|
+
import { MinutaEditor, type MinutaEditorHandle } from '@meistrari/minuta-react'
|
|
10
|
+
import '@meistrari/minuta-editor/style.css'
|
|
11
|
+
|
|
12
|
+
function Lapidacao({ html, onSave }: { html: string, onSave: (html: string) => void }) {
|
|
13
|
+
const editor = useRef<MinutaEditorHandle>(null)
|
|
14
|
+
return (
|
|
15
|
+
<>
|
|
16
|
+
<button onClick={() => onSave(editor.current!.getHTML())}>Salvar</button>
|
|
17
|
+
<MinutaEditor ref={editor} html={html} style={{ height: '80vh' }} />
|
|
18
|
+
</>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Zero I/O.** O componente não busca nem salva nada — recebe HTML, devolve HTML e
|
|
24
|
+
um `Blob` de `.docx`. Buscar o documento, persistir a edição e baixar o arquivo
|
|
25
|
+
é do seu app (abaixo, o fluxo com a Data API do defesa.ai).
|
|
26
|
+
|
|
27
|
+
## Props
|
|
28
|
+
|
|
29
|
+
| prop | default | |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| `html` | — | documento inicial. **Lido uma vez** — para carregar outro, troque a `key` |
|
|
32
|
+
| `editable` | `true` | |
|
|
33
|
+
| `margins` | 2,5cm / 3cm | `{ top, right, bottom, left }` em px @96dpi |
|
|
34
|
+
| `header` | — | `{ logoUrl, position }` |
|
|
35
|
+
| `chrome` | — | `{ header, footer, headerScope, footerScope, showPageNumber }` |
|
|
36
|
+
| `variables` | — | catálogo `{ key, label, description?, group? }[]` → liga o modo template |
|
|
37
|
+
| `uploadImage` | — | `(file) => Promise<{ src, vaultSrc } \| null>` |
|
|
38
|
+
| `toolbar` | `true` | `false` = você monta a sua sobre `ref.current.tiptap` |
|
|
39
|
+
| `onChange` | — | `(html) => void`, a cada edição |
|
|
40
|
+
| `onTransaction` | — | qualquer transação, inclusive só de seleção — para toolbar própria |
|
|
41
|
+
| `onReady`, `onEditChrome`, `onBlockClick`, `onError` | — | |
|
|
42
|
+
|
|
43
|
+
O `ref` entrega a instância do editor: `getHTML()`, `exportDocx()` (→ `Blob`),
|
|
44
|
+
`usedVariables()`, `setEditable()`, `setChrome()`, `tiptap` (a instância do
|
|
45
|
+
Tiptap — escotilha de fuga), `root`/`container`/`sheet` (os elementos).
|
|
46
|
+
|
|
47
|
+
### Por que o `html` é lido uma vez
|
|
48
|
+
|
|
49
|
+
O editor é a fonte da verdade enquanto vive. Realimentá-lo com o próprio
|
|
50
|
+
`getHTML()` a cada tecla remontaria o documento e mandaria o cursor para o
|
|
51
|
+
começo. Guarde o que `onChange` entrega; para abrir outro documento, mude a
|
|
52
|
+
`key`:
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
<MinutaEditor key={edicao.id} html={edicao.html} onChange={setHtml} />
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Toolbar própria (antd, Material…)
|
|
59
|
+
|
|
60
|
+
`toolbar={false}` e fale com o Tiptap direto. `onTransaction` é o que faz
|
|
61
|
+
`isActive` acompanhar o cursor, não só o texto:
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
const [, rerender] = useReducer(x => x + 1, 0)
|
|
65
|
+
const t = editor.current?.tiptap
|
|
66
|
+
|
|
67
|
+
<Button type={t?.isActive('bold') ? 'primary' : 'default'} onClick={() => t?.chain().focus().toggleBold().run()}>B</Button>
|
|
68
|
+
<MinutaEditor ref={editor} html={html} toolbar={false} onTransaction={rerender} />
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Os tipos de `chain().toggleBold()` viajam com o pacote — não precisa importar
|
|
72
|
+
`@tiptap/*` no seu código.
|
|
73
|
+
|
|
74
|
+
## O fluxo com a Data API do defesa.ai
|
|
75
|
+
|
|
76
|
+
Tudo pelo seu backend, com `x-api-key` + `x-org-id` — seus usuários não precisam
|
|
77
|
+
de conta no defesa.ai:
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
GET /data/case/:id/html → { html, chrome, margins, source, editionId }
|
|
81
|
+
POST /data/case/:id/editions { name, html } → cria a edição (o documento lapidado)
|
|
82
|
+
PATCH /data/case/:id/editions/:editionId { html } → salva (versão automática)
|
|
83
|
+
POST /data/case/:id/docx → .docx do estado atual (a edição, se existir)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
// abrir
|
|
88
|
+
const doc = await api.get(`/case/${caseId}/html`)
|
|
89
|
+
<MinutaEditor key={caseId} html={doc.html} chrome={doc.chrome ?? undefined} margins={doc.margins ?? undefined} onChange={setHtml} />
|
|
90
|
+
|
|
91
|
+
// salvar (debounce do seu lado)
|
|
92
|
+
await api.patch(`/case/${caseId}/editions/${editionId}`, { html })
|
|
93
|
+
|
|
94
|
+
// baixar — fiel ao preview, gerado no browser
|
|
95
|
+
const blob = await editor.current!.exportDocx()
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Mande `x-user-email` / `x-user-name` nas chamadas de edição para a autoria
|
|
99
|
+
ficar registrada.
|
|
100
|
+
|
|
101
|
+
## Formulário ↔ documento
|
|
102
|
+
|
|
103
|
+
O HTML do `GET /data/case/:id/html` vem com cada variável marcada —
|
|
104
|
+
`<span data-variable-id="nome_cliente" data-parent-block-id="…">valor</span>` —
|
|
105
|
+
e o editor trata a marca como nó atômico. Isso dá as duas direções sem casar
|
|
106
|
+
texto (que erra quando o valor coincide com algo que já existia no template):
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
// documento → formulário: clicou no trecho, foca o campo
|
|
110
|
+
<MinutaEditor ref={editor} html={html} onVariableClick={v => focusField(v.variableId)} />
|
|
111
|
+
|
|
112
|
+
// formulário → documento: focou o campo, rola até o trecho
|
|
113
|
+
editor.current!.scrollToVariable('nome_cliente')
|
|
114
|
+
|
|
115
|
+
// e o formulário continua valendo DEPOIS da edição livre: a marca sobrevive
|
|
116
|
+
// à lapidação, então mudar o valor troca o trecho sem tocar no texto em volta
|
|
117
|
+
editor.current!.setVariableValue('nome_cliente', 'Maria da Silva') // → nº de ocorrências
|
|
118
|
+
editor.current!.variablesInDocument() // → ['nome_cliente', …]
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
A resposta do endpoint traz `variablesMarked` e `markedVariables`: numa
|
|
122
|
+
edição criada a partir de HTML já resolvido (sem marcas) a ponte não existe, e
|
|
123
|
+
é melhor saber antes de montar a tela do que descobrir com
|
|
124
|
+
`variablesInDocument()` vazio.
|
|
125
|
+
|
|
126
|
+
Sobre o fluxo de "enviar variáveis de volta": com uma edição viva o documento
|
|
127
|
+
**é** a edição — o `PATCH` de variáveis no case não re-renderiza a peça (senão
|
|
128
|
+
apagaria o texto do advogado). Ou o formulário trava quando a lapidação começa
|
|
129
|
+
(o modelo do defesa.ai), ou você mantém os dois vivos com `setVariableValue` +
|
|
130
|
+
salva a edição. Decisão de UX do seu app; as duas funcionam.
|
|
131
|
+
|
|
132
|
+
## Next.js (App Router)
|
|
133
|
+
|
|
134
|
+
O entry publicado carrega `'use client'`: dá para importar o componente direto
|
|
135
|
+
de um Server Component, que o Next faz a fronteira de cliente sozinho. O editor
|
|
136
|
+
é DOM, então `dynamic(() => import(...), { ssr: false })` continua sendo uma
|
|
137
|
+
boa ideia em página renderizada no servidor.
|
|
138
|
+
|
|
139
|
+
## Props depois do mount
|
|
140
|
+
|
|
141
|
+
Todas as props são sincronizadas com o editor enquanto ele vive — `toolbar`,
|
|
142
|
+
`margins`, `chrome`, `header`, `variables`, `editable`, `showBlockOrigin`. A
|
|
143
|
+
única só de mount é `html`; voltar uma prop a `undefined` volta ao default.
|
|
144
|
+
|
|
145
|
+
## StrictMode
|
|
146
|
+
|
|
147
|
+
Funciona com o `<React.StrictMode>` do React 18: o duplo-mount do efeito destrói
|
|
148
|
+
e recria a instância sobre o mesmo nó, sem instância órfã nem listener duplicado.
|
|
149
|
+
O playground roda assim de propósito.
|
|
150
|
+
|
|
151
|
+
## Desenvolvimento
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
bun install && bun link @meistrari/minuta-editor # o core, via link em dev
|
|
155
|
+
bun run dev # playground em :3299 (caso real como fixture)
|
|
156
|
+
bun run build
|
|
157
|
+
```
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/// <reference types="@tiptap/extension-bold" />
|
|
2
|
+
/// <reference types="@tiptap/extension-blockquote" />
|
|
3
|
+
/// <reference types="@tiptap/extension-bullet-list" />
|
|
4
|
+
/// <reference types="@tiptap/extension-code" />
|
|
5
|
+
/// <reference types="@tiptap/extension-code-block" />
|
|
6
|
+
/// <reference types="@tiptap/extension-hard-break" />
|
|
7
|
+
/// <reference types="@tiptap/extension-heading" />
|
|
8
|
+
/// <reference types="@tiptap/extension-history" />
|
|
9
|
+
/// <reference types="@tiptap/extension-horizontal-rule" />
|
|
10
|
+
/// <reference types="@tiptap/extension-italic" />
|
|
11
|
+
/// <reference types="@tiptap/extension-list-item" />
|
|
12
|
+
/// <reference types="@tiptap/extension-ordered-list" />
|
|
13
|
+
/// <reference types="@tiptap/extension-paragraph" />
|
|
14
|
+
/// <reference types="@tiptap/extension-strike" />
|
|
15
|
+
/// <reference types="@tiptap/extension-text" />
|
|
16
|
+
/// <reference types="@tiptap/extension-table" />
|
|
17
|
+
/// <reference types="@tiptap/extension-bubble-menu" />
|
|
18
|
+
import * as react from 'react';
|
|
19
|
+
import { CSSProperties } from 'react';
|
|
20
|
+
import { MinutaMargins, MinutaHeader, MinutaChromeText, MinutaVariableCatalog, MinutaEditorOptions, MinutaVariableRef, MinutaEditor as MinutaEditor$1 } from '@meistrari/minuta-editor';
|
|
21
|
+
export { MinutaChromeText, MinutaEditor as MinutaEditorInstance, MinutaEditorOptions, MinutaHeader, MinutaMargins, MinutaVariableCatalog, MinutaVariableDef, MinutaVariableRef, extractTemplateVariables, resolveTemplateVariables } from '@meistrari/minuta-editor';
|
|
22
|
+
|
|
23
|
+
interface MinutaEditorProps {
|
|
24
|
+
/**
|
|
25
|
+
* Documento inicial (HTML). A ÚNICA prop só de mount: lida uma vez — troque a
|
|
26
|
+
* `key` para carregar outro. As demais são sincronizadas com o editor.
|
|
27
|
+
*/
|
|
28
|
+
html: string;
|
|
29
|
+
editable?: boolean;
|
|
30
|
+
margins?: MinutaMargins;
|
|
31
|
+
header?: MinutaHeader;
|
|
32
|
+
chrome?: Partial<MinutaChromeText>;
|
|
33
|
+
variables?: MinutaVariableCatalog;
|
|
34
|
+
uploadImage?: MinutaEditorOptions['uploadImage'];
|
|
35
|
+
/** barra de formatação do pacote (default: true). `false` = monte a sua sobre `ref.tiptap` */
|
|
36
|
+
toolbar?: boolean;
|
|
37
|
+
showBlockOrigin?: boolean;
|
|
38
|
+
onReady?: MinutaEditorOptions['onReady'];
|
|
39
|
+
/** o documento mudou por edição — recebe o HTML atual */
|
|
40
|
+
onChange?: (html: string) => void;
|
|
41
|
+
/** qualquer transação, inclusive só de seleção (para toolbar própria) */
|
|
42
|
+
onTransaction?: () => void;
|
|
43
|
+
onEditChrome?: MinutaEditorOptions['onEditChrome'];
|
|
44
|
+
/** clique numa variável do case no documento — a ponte documento → formulário */
|
|
45
|
+
onVariableClick?: (variable: MinutaVariableRef) => void;
|
|
46
|
+
onBlockClick?: MinutaEditorOptions['onBlockClick'];
|
|
47
|
+
onError?: MinutaEditorOptions['onError'];
|
|
48
|
+
className?: string;
|
|
49
|
+
style?: CSSProperties;
|
|
50
|
+
}
|
|
51
|
+
/** o que o `ref` entrega: a instância do editor (ou `null` antes do mount) */
|
|
52
|
+
type MinutaEditorHandle = MinutaEditor$1;
|
|
53
|
+
declare const MinutaEditor: react.ForwardRefExoticComponent<MinutaEditorProps & react.RefAttributes<MinutaEditor$1 | null>>;
|
|
54
|
+
|
|
55
|
+
export { MinutaEditor };
|
|
56
|
+
export type { MinutaEditorHandle, MinutaEditorProps };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/// <reference types="@tiptap/extension-bold" />
|
|
2
|
+
/// <reference types="@tiptap/extension-blockquote" />
|
|
3
|
+
/// <reference types="@tiptap/extension-bullet-list" />
|
|
4
|
+
/// <reference types="@tiptap/extension-code" />
|
|
5
|
+
/// <reference types="@tiptap/extension-code-block" />
|
|
6
|
+
/// <reference types="@tiptap/extension-hard-break" />
|
|
7
|
+
/// <reference types="@tiptap/extension-heading" />
|
|
8
|
+
/// <reference types="@tiptap/extension-history" />
|
|
9
|
+
/// <reference types="@tiptap/extension-horizontal-rule" />
|
|
10
|
+
/// <reference types="@tiptap/extension-italic" />
|
|
11
|
+
/// <reference types="@tiptap/extension-list-item" />
|
|
12
|
+
/// <reference types="@tiptap/extension-ordered-list" />
|
|
13
|
+
/// <reference types="@tiptap/extension-paragraph" />
|
|
14
|
+
/// <reference types="@tiptap/extension-strike" />
|
|
15
|
+
/// <reference types="@tiptap/extension-text" />
|
|
16
|
+
/// <reference types="@tiptap/extension-table" />
|
|
17
|
+
/// <reference types="@tiptap/extension-bubble-menu" />
|
|
18
|
+
import * as react from 'react';
|
|
19
|
+
import { CSSProperties } from 'react';
|
|
20
|
+
import { MinutaMargins, MinutaHeader, MinutaChromeText, MinutaVariableCatalog, MinutaEditorOptions, MinutaVariableRef, MinutaEditor as MinutaEditor$1 } from '@meistrari/minuta-editor';
|
|
21
|
+
export { MinutaChromeText, MinutaEditor as MinutaEditorInstance, MinutaEditorOptions, MinutaHeader, MinutaMargins, MinutaVariableCatalog, MinutaVariableDef, MinutaVariableRef, extractTemplateVariables, resolveTemplateVariables } from '@meistrari/minuta-editor';
|
|
22
|
+
|
|
23
|
+
interface MinutaEditorProps {
|
|
24
|
+
/**
|
|
25
|
+
* Documento inicial (HTML). A ÚNICA prop só de mount: lida uma vez — troque a
|
|
26
|
+
* `key` para carregar outro. As demais são sincronizadas com o editor.
|
|
27
|
+
*/
|
|
28
|
+
html: string;
|
|
29
|
+
editable?: boolean;
|
|
30
|
+
margins?: MinutaMargins;
|
|
31
|
+
header?: MinutaHeader;
|
|
32
|
+
chrome?: Partial<MinutaChromeText>;
|
|
33
|
+
variables?: MinutaVariableCatalog;
|
|
34
|
+
uploadImage?: MinutaEditorOptions['uploadImage'];
|
|
35
|
+
/** barra de formatação do pacote (default: true). `false` = monte a sua sobre `ref.tiptap` */
|
|
36
|
+
toolbar?: boolean;
|
|
37
|
+
showBlockOrigin?: boolean;
|
|
38
|
+
onReady?: MinutaEditorOptions['onReady'];
|
|
39
|
+
/** o documento mudou por edição — recebe o HTML atual */
|
|
40
|
+
onChange?: (html: string) => void;
|
|
41
|
+
/** qualquer transação, inclusive só de seleção (para toolbar própria) */
|
|
42
|
+
onTransaction?: () => void;
|
|
43
|
+
onEditChrome?: MinutaEditorOptions['onEditChrome'];
|
|
44
|
+
/** clique numa variável do case no documento — a ponte documento → formulário */
|
|
45
|
+
onVariableClick?: (variable: MinutaVariableRef) => void;
|
|
46
|
+
onBlockClick?: MinutaEditorOptions['onBlockClick'];
|
|
47
|
+
onError?: MinutaEditorOptions['onError'];
|
|
48
|
+
className?: string;
|
|
49
|
+
style?: CSSProperties;
|
|
50
|
+
}
|
|
51
|
+
/** o que o `ref` entrega: a instância do editor (ou `null` antes do mount) */
|
|
52
|
+
type MinutaEditorHandle = MinutaEditor$1;
|
|
53
|
+
declare const MinutaEditor: react.ForwardRefExoticComponent<MinutaEditorProps & react.RefAttributes<MinutaEditor$1 | null>>;
|
|
54
|
+
|
|
55
|
+
export { MinutaEditor };
|
|
56
|
+
export type { MinutaEditorHandle, MinutaEditorProps };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { forwardRef, useRef, useLayoutEffect, useEffect, useImperativeHandle, createElement } from 'react';
|
|
3
|
+
import { createMinutaEditor } from '@meistrari/minuta-editor';
|
|
4
|
+
export { extractTemplateVariables, resolveTemplateVariables } from '@meistrari/minuta-editor';
|
|
5
|
+
|
|
6
|
+
const MinutaEditor = forwardRef((props, ref) => {
|
|
7
|
+
const host = useRef(null);
|
|
8
|
+
const instance = useRef(null);
|
|
9
|
+
const callbacks = useRef(props);
|
|
10
|
+
callbacks.current = props;
|
|
11
|
+
useLayoutEffect(() => {
|
|
12
|
+
const el = host.current;
|
|
13
|
+
if (!el)
|
|
14
|
+
return;
|
|
15
|
+
const editor = createMinutaEditor(el, {
|
|
16
|
+
html: props.html,
|
|
17
|
+
editable: props.editable,
|
|
18
|
+
margins: props.margins,
|
|
19
|
+
header: props.header,
|
|
20
|
+
chrome: props.chrome,
|
|
21
|
+
variables: props.variables,
|
|
22
|
+
// lido na hora do upload, não no mount: o host pode trocar a função
|
|
23
|
+
uploadImage: (file) => callbacks.current.uploadImage ? callbacks.current.uploadImage(file) : Promise.resolve(null),
|
|
24
|
+
toolbar: props.toolbar,
|
|
25
|
+
showBlockOrigin: props.showBlockOrigin,
|
|
26
|
+
onReady: (tiptap) => callbacks.current.onReady?.(tiptap),
|
|
27
|
+
onChange: () => callbacks.current.onChange?.(editor.getHTML()),
|
|
28
|
+
onTransaction: () => callbacks.current.onTransaction?.(),
|
|
29
|
+
onEditChrome: (part) => callbacks.current.onEditChrome?.(part),
|
|
30
|
+
onVariableClick: (v) => callbacks.current.onVariableClick?.(v),
|
|
31
|
+
onBlockClick: (id) => callbacks.current.onBlockClick?.(id),
|
|
32
|
+
onError: (message) => callbacks.current.onError?.(message)
|
|
33
|
+
});
|
|
34
|
+
instance.current = editor;
|
|
35
|
+
return () => {
|
|
36
|
+
editor.destroy();
|
|
37
|
+
instance.current = null;
|
|
38
|
+
};
|
|
39
|
+
}, []);
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
if (props.editable !== void 0)
|
|
42
|
+
instance.current?.setEditable(props.editable);
|
|
43
|
+
}, [props.editable]);
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
instance.current?.setChrome(props.chrome ?? { header: "", footer: "", headerScope: "all", footerScope: "all", showPageNumber: true });
|
|
46
|
+
}, [props.chrome?.header, props.chrome?.footer, props.chrome?.headerScope, props.chrome?.footerScope, props.chrome?.showPageNumber]);
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
instance.current?.setHeader(props.header ?? { logoUrl: null, position: "left" });
|
|
49
|
+
}, [props.header?.logoUrl, props.header?.position]);
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
instance.current?.setVariables(props.variables);
|
|
52
|
+
}, [props.variables]);
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
instance.current?.setToolbar(props.toolbar !== false);
|
|
55
|
+
}, [props.toolbar]);
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
if (props.margins)
|
|
58
|
+
instance.current?.setMargins(props.margins);
|
|
59
|
+
}, [props.margins?.top, props.margins?.right, props.margins?.bottom, props.margins?.left]);
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
instance.current?.setShowBlockOrigin(props.showBlockOrigin !== false);
|
|
62
|
+
}, [props.showBlockOrigin]);
|
|
63
|
+
useImperativeHandle(ref, () => instance.current);
|
|
64
|
+
return createElement("div", {
|
|
65
|
+
ref: host,
|
|
66
|
+
className: props.className,
|
|
67
|
+
style: { height: "100%", width: "100%", minHeight: 0, display: "flex", flexDirection: "column", ...props.style }
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
MinutaEditor.displayName = "MinutaEditor";
|
|
71
|
+
|
|
72
|
+
export { MinutaEditor };
|
package/package.json
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@meistrari/minuta-react",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Componente React do editor de minuta do defesa.ai — casca fina sobre @meistrari/minuta-editor",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/meistrari/case-defense-builder.git",
|
|
8
|
+
"directory": "packages/minuta-react"
|
|
9
|
+
},
|
|
10
|
+
"license": "UNLICENSED",
|
|
11
|
+
"type": "module",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.mts",
|
|
15
|
+
"import": "./dist/index.mjs"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"main": "./dist/index.mjs",
|
|
19
|
+
"types": "./dist/index.d.mts",
|
|
20
|
+
"files": [
|
|
21
|
+
"dist"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"prepack": "bun run build",
|
|
25
|
+
"build": "unbuild && node scripts/finish-dist.mjs",
|
|
26
|
+
"dev": "vite playground --port 3299",
|
|
27
|
+
"typecheck": "tsc --noEmit",
|
|
28
|
+
"test:pack": "node scripts/verify-pack.mjs"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@meistrari/minuta-editor": "^1.0.0",
|
|
32
|
+
"@tiptap/core": "2.11.9",
|
|
33
|
+
"@tiptap/extension-blockquote": "2.11.9",
|
|
34
|
+
"@tiptap/extension-bold": "2.11.9",
|
|
35
|
+
"@tiptap/extension-bubble-menu": "2.11.9",
|
|
36
|
+
"@tiptap/extension-bullet-list": "2.11.9",
|
|
37
|
+
"@tiptap/extension-code": "2.11.9",
|
|
38
|
+
"@tiptap/extension-code-block": "2.11.9",
|
|
39
|
+
"@tiptap/extension-dropcursor": "2.11.9",
|
|
40
|
+
"@tiptap/extension-gapcursor": "2.11.9",
|
|
41
|
+
"@tiptap/extension-hard-break": "2.11.9",
|
|
42
|
+
"@tiptap/extension-heading": "2.11.9",
|
|
43
|
+
"@tiptap/extension-history": "2.11.9",
|
|
44
|
+
"@tiptap/extension-horizontal-rule": "2.11.9",
|
|
45
|
+
"@tiptap/extension-italic": "2.11.9",
|
|
46
|
+
"@tiptap/extension-list-item": "2.11.9",
|
|
47
|
+
"@tiptap/extension-ordered-list": "2.11.9",
|
|
48
|
+
"@tiptap/extension-paragraph": "2.11.9",
|
|
49
|
+
"@tiptap/extension-strike": "2.11.9",
|
|
50
|
+
"@tiptap/extension-table": "2.11.9",
|
|
51
|
+
"@tiptap/extension-table-cell": "2.11.9",
|
|
52
|
+
"@tiptap/extension-table-header": "2.11.9",
|
|
53
|
+
"@tiptap/extension-table-row": "2.11.9",
|
|
54
|
+
"@tiptap/extension-text": "2.11.9",
|
|
55
|
+
"@tiptap/pm": "2.11.9"
|
|
56
|
+
},
|
|
57
|
+
"peerDependencies": {
|
|
58
|
+
"react": ">=18.0.0"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@types/react": "18.3.31",
|
|
62
|
+
"@types/react-dom": "18.3.7",
|
|
63
|
+
"@vitejs/plugin-react": "4.7.0",
|
|
64
|
+
"react": "18.3.1",
|
|
65
|
+
"react-dom": "18.3.1",
|
|
66
|
+
"typescript": "5.9.3",
|
|
67
|
+
"unbuild": "2.0.0",
|
|
68
|
+
"vite": "6.4.3"
|
|
69
|
+
},
|
|
70
|
+
"publishConfig": {
|
|
71
|
+
"access": "public"
|
|
72
|
+
},
|
|
73
|
+
"overrides": {
|
|
74
|
+
"@tiptap/core": "2.11.9",
|
|
75
|
+
"@tiptap/extension-blockquote": "2.11.9",
|
|
76
|
+
"@tiptap/extension-bold": "2.11.9",
|
|
77
|
+
"@tiptap/extension-bubble-menu": "2.11.9",
|
|
78
|
+
"@tiptap/extension-bullet-list": "2.11.9",
|
|
79
|
+
"@tiptap/extension-code": "2.11.9",
|
|
80
|
+
"@tiptap/extension-code-block": "2.11.9",
|
|
81
|
+
"@tiptap/extension-document": "2.11.9",
|
|
82
|
+
"@tiptap/extension-dropcursor": "2.11.9",
|
|
83
|
+
"@tiptap/extension-floating-menu": "2.11.9",
|
|
84
|
+
"@tiptap/extension-gapcursor": "2.11.9",
|
|
85
|
+
"@tiptap/extension-hard-break": "2.11.9",
|
|
86
|
+
"@tiptap/extension-heading": "2.11.9",
|
|
87
|
+
"@tiptap/extension-history": "2.11.9",
|
|
88
|
+
"@tiptap/extension-horizontal-rule": "2.11.9",
|
|
89
|
+
"@tiptap/extension-italic": "2.11.9",
|
|
90
|
+
"@tiptap/extension-list-item": "2.11.9",
|
|
91
|
+
"@tiptap/extension-ordered-list": "2.11.9",
|
|
92
|
+
"@tiptap/extension-paragraph": "2.11.9",
|
|
93
|
+
"@tiptap/extension-strike": "2.11.9",
|
|
94
|
+
"@tiptap/extension-text": "2.11.9",
|
|
95
|
+
"@tiptap/extension-text-style": "2.11.9",
|
|
96
|
+
"@tiptap/pm": "2.11.9"
|
|
97
|
+
}
|
|
98
|
+
}
|