Começar

O primeiro template

Um template é um componente React que devolve um <Document>, opcionalmente dentro de <Tailwind>.

templates/factura.tsx
import { Tailwind, Document, Row, Logo, DocumentTitle, DocumentNumber,
  DocumentDate, Customer, Issuer, Items, Totals, LegalNotes } from "@veroao/invoice"

export default function MyInvoice() {
  return (
    <Tailwind config={{ theme: { extend: { colors: { brand: "#0E4C63" } } } }}>
      <Document className="bg-white px-12 pt-10 text-[11px]">
        <Row className="items-start justify-between">
          <Logo className="h-12" />
          <DocumentTitle className="text-3xl font-bold uppercase text-brand" />
        </Row>
        <DocumentNumber className="mt-2 text-right font-bold" />
        <DocumentDate className="text-right text-zinc-500" />
        <Row className="mt-8 gap-6">
          <Customer className="flex-1 border border-zinc-200 p-3" labelClassName="font-bold text-brand" />
          <Issuer className="flex-1" />
        </Row>
        <Items className="mt-6" rowClassName="border-b border-zinc-200 even:bg-zinc-50" />
        <Totals className="ml-auto mt-4 w-1/2" totalClassName="text-xl font-bold text-brand" />
        <LegalNotes className="mt-6 text-[9px] text-zinc-500" />
      </Document>
    </Tailwind>
  )
}

O que está a acontecer#

  • <Tailwind config> define as cores (brand) e as letras do template, como o tailwind.config.
  • <Document> é a página A4: bg-* é o fundo, px-* as margens, pt-* o espaço acima do corpo.
  • Os componentes do documento (DocumentTitle, Customer, Items…) recebem só classes - os dados vêm de cada documento.

Ver o resultado#

terminal
npx @veroao/invoice dev

Abre http://localhost:3200 com o PDF, que se actualiza cada vez que gravas. Para gerar o PDF no teu código, ver Gerar o PDF.

Os teus componentes#

Podes partir o template em componentes, usar listas (.map) e condições. Hooks não funcionam: um template não tem estado - corre uma vez para dar o JSON.

templates/factura.tsx
const card = "flex-1 rounded border border-zinc-200 p-3"

function Parties() {
  return (
    <Row className="gap-6">
      <Customer className={card} />
      <Issuer className={card} />
    </Row>
  )
}
Se faltar algum elemento obrigatório (tipo, número, data, partes, artigos, totais, menções legais), o PDF de pré-visualização avisa; num documento emitido, é acrescentado.