Pular para o conteúdo principal

Exemplos

Cinco apps de exemplo vivem em examples/ no repositório, cada um com seu próprio README, e cada um rodável ao vivo no Playground.

Eles também dividem o espectro de estilo entre si: nenhum repete a abordagem do outro em relação ao CSS do pacote, então juntos eles exercitam os dois exports de CSS mais o modo que não importa nenhum.

ExemploCSS do pacoteEstratégia de estilo
report-buildertheme.csso tema como ele vem, sem customização
composed-layouttheme.cssretema só por token --jpd-*, sem reescrever uma regra
no-previewtheme.cssdark mode por [data-jpd-theme], com toggle
headless-designersó reset.cssaparência escrita à mão, ~5 regras
custom-uinenhum192 seletores .jpd-* do zero

O Tema e CSS percorre essa tabela com os números medidos. Ela tem guard: um teste lê as linhas de import de verdade dos exemplos, então ela não desanda calada.

report-builder​

Abrir no playground →

O designer completo — fontes de dados JSON, um explorador de campos, 6 templates prontos, abas de página (Template.pages — cada aba com seu próprio design, um PDF combinado com numeração contínua) — usando os componentes de UI prontos do pacote (Button/Card/Input/ PdfPreviewModal). O caminho mais rápido: usa os componentes que a lib já distribui.

Ele foi migrado pras peças composáveis na 3.0.0 e o layout ficou idêntico ao do preset — o ponto é o que a migração comprou: um <SelectedFieldBar> na casca do próprio app, lendo a seleção do editor por hook. Isso era impossível na 2.x, em que o <Designer> era dono da seleção e nenhuma prop dirigia ela de fora.

Estilo: json-pdf-designer/theme.css, sem tocar em nada — nenhum token sobrescrito, nenhuma regra .jpd-*. É a ponta "um import e acabou" do espectro. A casca dele é Tailwind (@tailwindcss/vite), e este é o único exemplo em que ainda existe pipeline de Tailwind — do lado do app, nunca do pacote.

composed-layout​

Abrir no playground →

O editor montado peça por peça, sem o componente <Designer>: toolbar em cima ocupando a largura toda, lista de campos à esquerda, canvas no meio, e uma coluna à direita com cinco painéis empilhados que dentro do <Designer> seriam cinco abas. Ele monta o <DesignerProvider> na mão e posiciona as peças num layout que o preset não sabe fazer.

É o exemplo que prova que o <Designer> não é indivisível — e especificamente que o gate por aba é opt-in. Nenhuma peça recebe whenTab, então os cinco painéis da direita renderizam ao mesmo tempo. Medido: oito peças no DOM simultaneamente, zero .jpd-tabs. Se o gate fosse o default, este layout mostraria um painel e apagaria os outros quatro.

Estilo: ele importa o json-pdf-designer/theme.css inteiro e retematiza só por token — o index.css dele troca valores de --jpd-accent* e --jpd-radius-* no :root e não reescreve uma única regra .jpd-*. Medido depois: o .jpd-btn[data-variant="primary"] computa o violeta oklch(0.541 0.245 292.717) e border-radius: 4px, onde o tema default dá sky-600 e 8px. É o caminho mais barato de parecer com a sua marca — ver Tema e CSS. A casca dele é CSS puro, sem plugin de Tailwind em ponta nenhuma. Servidor de dev na porta 5177. Ver Compondo o Designer.

custom-ui​

Abrir no playground →

As mesmas funcionalidades do report-builder, mas a casca inteira (header, sidebar, cards, árvore de campos, modais) é CSS puro escrito à mão — zero Button/Card/Input/ícone importado do pacote. Prova que o próprio <Designer> funciona com qualquer design system, ou nenhum.

Ele fica no <Designer> de propósito, em vez de usar as peças: é o teste de regressão do caminho de uma linha.

Estilo: a ponta mais longe do espectro — ele não importa CSS nenhum do pacote, nem o theme.css nem o reset.css. O que sobra no DOM sem eles são as classes .jpd-* e os atributos de estado data-*, e o index.css dele veste tudo: 192 seletores .jpd-* distintos, escritos à mão. É esse o preço do editor inteiro sem aparência do pacote, e é o que faz "não importar nenhum dos dois" ser modo suportado em vez de promessa.

headless-designer​

Abrir no playground →

Sem o componente <Designer> nenhum. Um canvas montado à mão — a própria lógica de arrastar/redimensionar (mousedown/mousemove/ mouseup puro, sem react-rnd) sobre generatePdf + tipos de json-pdf-designer/server, e o PdfPreview de json-pdf-designer/preview. Prova que o modelo de dados e o motor de PDF funcionam sozinhos, independente do editor de arrastar/soltar — a mesma ideia que um backend Node usa (ver Uso só no servidor e Integração com backend), só que rodando no navegador aqui pra demonstração.

Estilo: é o único exemplo que fica só no json-pdf-designer/reset.css — o export sem aparência, que nada mais no repo exercita. Ele pode porque o <Designer> não aparece aqui: o único componente do pacote que ele renderiza é o <PdfPreview>, cuja superfície de estilo são quatro nomes (.jpd-error, .jpd-error--md, .jpd-preview__count e o token --jpd-shadow-page-preview), então escrever a aparência à mão são umas cinco regras. Medido: chegaram 54 regras do pacote e o --jpd-accent computa vazio. Esse último token é a pegadinha — o PdfPreview lê ele inline, então quem está no modo só-reset tem de declarar, senão a sombra da página desaparece calada. Ver Tema e CSS.

no-preview​

Abrir no playground →

<Designer> + generatePdf + downloadPdf, direto pro download, sem tela de preview — e sem o pdfjs-dist instalado. É o app que prova que a entrada principal nunca precisa do peer opcional: a dependência está deliberadamente ausente do package.json dele, e o build varre o próprio bundle procurando símbolos do pdf.js (o symlink file:../.. deixaria um import vazado resolver o pdf.js pelo repo pai). Nenhum recurso fica de fora aqui: o pdfjs-dist só compra o preview na tela.

Estilo: ele importa o theme.css e o deixa escuro. É o único app do repo que exercita dark mode, e o default dele é escuro: um atributo data-jpd-theme no <html>, alternado pelo header e persistido em localStorage. A parte instrutiva é que um atributo dirige o editor e a casca do app, porque o exemplo declara as variáveis --app-* dele na mesma chave — medido no toggle, 6 de 6 propriedades amostradas trocam juntas, três na casca (background do body, .app-sidebar, .panel-title) e duas dentro do editor (.jpd-sidebar, .jpd-ruler__tick). Ver Tema e CSS.

Ele também é o melhor smoke test do modo sem Tailwind: zero pipeline de Tailwind em ponta nenhuma, então o reset do pacote tem de se sustentar sozinho. O report-builder tem pipeline próprio, então emite Preflight por conta e não reproduziria a falta de reset — testar nele primeiro dá falso verde. (Pro modo sem folha de estilo nenhuma do pacote, o app é o custom-ui.)

O README dele detalha por que a dependência está deliberadamente ausente e por que omitir não basta sozinho; a Arquitetura cobre as três checagens que guardam a fronteira.

Rodando localmente​

Nenhum dos cinco é workspace do npm — cada um aponta pro pacote via "json-pdf-designer": "file:../.." no próprio package.json. A partir da raiz do repositório:

npm run build # builda o pacote raiz uma vez, pra dist/ existir
cd examples/report-builder # ou composed-layout, custom-ui, headless-designer, no-preview
npm install
npm run dev

Os servidores de dev fixam uma porta cada, então dá pra rodar vários ao mesmo tempo: custom-ui 5174, headless-designer 5175, no-preview 5176, composed-layout 5177 — o report-builder não fixa nenhuma e pega a default do Vite, 5173.