Editor de layout
O usuário final mostra, oculta, reordena e redimensiona colunas — e vê o PDF atualizar ao vivo — sem tocar em código nem esperar um deploy. Por baixo, tudo é uma ReportView salva por um ReportStorageAdapter.
Sistema, duplicar, editar
Todo relatório nasce com uma view de sistema — somente leitura, espelhando o defineReport. Para customizar, o usuário duplica: nasce uma cópia editável, livre para virar a nova padrão.
View de sistema (isSystem: true) — somente leitura. O editor abaixo desabilita os controles e mostra apenas o botão "Duplicar para editar".
Duplicar — cria uma view nova (isSystem: false), livre para editar e apagar, a partir da view selecionada.
Definir como padrão — marca a view como isDefault: true e zera o default das demais views do mesmo relatório.
A view editada persiste no seu navegador
Este demo usa createLocalStorageReportAdapter({ prefix: "cm-report-docs" }) — tudo que você mudar abaixo fica salvo no localStorage deste navegador. Recarregue a página: a view continua como você deixou. Para limpar, apague os dados do site nas configurações do navegador.
Editor ao vivo — relatório de Vendas
CmSelect troca a view, os botões duplicam e definem o padrão, e CmReportLayoutEditor edita colunas, cabeçalho e resumo com preview de PDF das 15 primeiras linhas de vendas.
Carregando views…
Como plugar no seu app
O essencial: um adapter, useReportViews para o estado das views e CmReportLayoutEditor controlado — o mesmo padrão do demo acima, com o relatório e os dados do seu app.
import { createLocalStorageReportAdapter } from "cosmemilton-report";
// ou, num backend com banco: import { createPrismaReportAdapter } from "@/lib/report-adapter";
import { CmReportLayoutEditor, useReportViews } from "cosmemilton-report/client";
import { meuRelatorio } from "@/lib/reports/meu-relatorio";
// Uma instância por adapter — reaproveite entre páginas, não recrie a cada render.
const adapter = createLocalStorageReportAdapter({ prefix: "meuapp:relatorios" });
function EditorDoMeuRelatorio() {
const { selectedView, saveView, duplicateView, selectView } = useReportViews({
slug: meuRelatorio.slug,
definition: meuRelatorio,
adapter,
});
if (!selectedView) return null;
return (
<CmReportLayoutEditor
definition={meuRelatorio}
view={selectedView}
onViewChange={selectedView.isSystem ? () => {} : saveView}
onDuplicate={
selectedView.isSystem
? () => duplicateView(selectedView.id).then((v) => selectView(v.id))
: undefined
}
previewRows={minhasLinhasDeAmostra}
/>
);
}