Rich Text Editor (tempest-react-sdk/editor)
Editor WYSIWYG controlado, construído sobre tiptap. Vive
num subpath separado (tempest-react-sdk/editor) porque o tiptap é pesado — e
quem não usa o editor não paga nada por ele.
Por que um subpath separado?
Um editor rich-text traz uma árvore de dependências grande (tiptap +
ProseMirror). Forçar isso em todo app que instala o SDK seria injusto com quem só
quer um Button e um createApiClient.
A solução é o mesmo padrão dos outros wrappers do SDK: o caller injeta a
dependência pesada. O RichTextEditor importa @tiptap/react e
@tiptap/starter-kit, mas esses pacotes são peer deps opcionais — declarados
no SDK como optional e externalizados no bundle. Resultado:
- Quem usa o editor instala o tiptap explicitamente uma vez.
- Quem não usa nunca puxa tiptap pro bundle — o subpath fica fora do barrel raiz.
Importe do subpath, não do barrel raiz
RichTextEditor só existe em tempest-react-sdk/editor. Ele não é
re-exportado de tempest-react-sdk — assim o tiptap nunca vaza pro bundle de
quem só importa o barrel principal.
Instalação
Instale o SDK normalmente e adicione os dois peers do tiptap:
npm install tempest-react-sdk
npm install @tiptap/react @tiptap/starter-kit
Por que os peers são opcionais
@tiptap/react e @tiptap/starter-kit são declarados como
peerDependencies opcionais. Apps que nunca importam
tempest-react-sdk/editor podem ignorá-los sem warning de instalação. No
momento em que você importar o editor sem tê-los instalado, o bundler
acusa o módulo faltando — aí é só rodar o npm install acima.
Estilos
O RichTextEditor usa CSS Modules com tokens --tempest-*, então ele já segue
o tema do app (claro/escuro) sem config extra. Basta importar o styles.css do
SDK uma vez no entry do app (você já faz isso pros outros componentes):
// src/main.tsx
import "tempest-react-sdk/styles.css";
A área editável (a .ProseMirror) e a toolbar herdam cor de texto, borda, anel
de foco e radius dos tokens --tempest-*. Para customizar, sobrescreva os
tokens no :root como em qualquer outro componente — veja
Styles & tokens.
API
<RichTextEditor
value={html} // string HTML controlada (obrigatório)
onChange={setHtml} // (html: string) => void (obrigatório)
placeholder="Escreva algo…" // texto quando vazio (opcional)
editable // false = somente leitura (default true)
toolbar // false = esconde a toolbar (default true)
className="meu-editor" // classes extras no wrapper (opcional)
/>
| Prop | Tipo | Default | Descrição |
|---|---|---|---|
value |
string |
— | Conteúdo do editor como HTML (controlado). |
onChange |
(html: string) => void |
— | Chamado com o HTML atualizado a cada mudança. |
placeholder |
string |
— | Texto exibido quando o editor está vazio. |
editable |
boolean |
true |
false torna o conteúdo somente leitura. |
toolbar |
boolean |
true |
false esconde a toolbar de formatação. |
className |
string |
— | Classes extras aplicadas ao elemento wrapper. |
A toolbar embutida
Quando toolbar é true (default), o editor renderiza uma barra acima da área
editável com os comandos do StarterKit:
- Negrito, Itálico, Tachado, Código (inline)
- Título 1, Título 2
- Lista com marcadores, Lista numerada, Citação (blockquote)
- Desfazer / Refazer (desabilitados quando não há histórico)
Os botões refletem o estado do cursor (ficam ativos quando a seleção já está em
negrito, dentro de uma lista, etc.) e têm aria-label + aria-pressed para
acessibilidade.
Exemplo completo — editor controlado
Programa copiável de ponta a ponta. O estado HTML vive no React via useState,
o editor o reflete e um <details> mostra o HTML emitido ao vivo.
import { useState } from "react";
import { RichTextEditor } from "tempest-react-sdk/editor";
import "tempest-react-sdk/styles.css";
export function ArticleEditor() {
const [html, setHtml] = useState<string>("<p>Comece a escrever seu artigo…</p>");
return (
<div style={{ maxWidth: 720, margin: "0 auto" }}>
<h1>Novo artigo</h1>
<RichTextEditor
value={html}
onChange={setHtml}
placeholder="Escreva algo incrível…"
/>
<details style={{ marginTop: 16 }}>
<summary>HTML emitido</summary>
<pre>{html}</pre>
</details>
</div>
);
}
value é HTML, onChange recebe HTML
O editor é totalmente controlado por uma string HTML. Você guarda esse HTML
onde quiser (state, formulário, API) e o passa de volta em value. Mudanças
externas em value são sincronizadas para dentro do editor sem
re-disparar onChange, então não há loop de atualização.
Somente leitura
Para exibir conteúdo sem permitir edição (preview de um artigo, por exemplo),
passe editable={false}. Você normalmente também esconde a toolbar:
<RichTextEditor value={savedHtml} onChange={() => {}} editable={false} toolbar={false} />
Renderize HTML salvo com o mesmo tema
Usar o RichTextEditor em modo editable={false} é a forma mais simples de
renderizar HTML salvo com a mesma tipografia e tokens da edição — a
.ProseMirror aplica o estilo do tema tanto na escrita quanto na leitura.
onChange continua obrigatório
onChange é uma prop obrigatória mesmo em modo somente leitura. Em
editable={false} ela nunca é chamada, então passe um no-op
(() => {}) para satisfazer o tipo.
Sem toolbar (UI própria)
Passe toolbar={false} quando quiser uma barra de formatação própria ou um
editor minimalista (um campo de comentário, por exemplo):
<RichTextEditor value={comment} onChange={setComment} toolbar={false} placeholder="Comente…" />
Recap
RichTextEditoré um editor WYSIWYG controlado sobre tiptap, exposto no subpathtempest-react-sdk/editor— fora do barrel raiz, então quem não usa não paga nada.@tiptap/reacte@tiptap/starter-kitsão peer deps opcionais: o caller injeta a dependência pesada comnpm i @tiptap/react @tiptap/starter-kit.valueé uma string HTML eonChange(html)devolve o HTML a cada edição; mudanças externas emvaluesão sincronizadas sem re-dispararonChange.- A toolbar embutida cobre negrito/itálico/tachado/código, H1/H2, listas,
citação e desfazer/refazer — desligue com
toolbar={false}. editable={false}deixa o editor somente leitura (ótimo para preview); o visual da.ProseMirrorsegue os tokens--tempest-*viastyles.css.
Veja também
- Styles & tokens — customizar o tema
--tempest-*da.ProseMirror. - Forms — integrar o HTML do editor num formulário controlado.