Dokumentation

Tabellen

Eine Table ist das Herz der meisten Rechnungen und Berichte. Sie geben ihr die Spaltenbreiten und die Zeilen, und sie richtet jede Zelle aus, wiederholt den Header auf jeder Seite und bricht zwischen Zeilen um, sodass eine Zeile nie in der Mitte geteilt wird.

import { Table, Text } from "@jasy/pdf";

Table(
  {
    columns: ["1fr", 50, 80, 90],
    header: [
      Text("Description", { bold: true }),
      Text("Qty", { bold: true, align: "right" }),
      Text("Unit", { bold: true, align: "right" }),
      Text("Amount", { bold: true, align: "right" }),
    ],
    cellPadding: { x: 8, y: 6 },
    rule: "#c2ccdb",
  },
  [
    [
      Text("Website design & build"),
      Text("1", { align: "right" }),
      Text("9600.00", { align: "right" }),
      Text("9600.00", { align: "right" }),
    ],
    [
      Text("Strategy consulting"),
      Text("12", { align: "right" }),
      Text("140.00", { align: "right" }),
      Text("1680.00", { align: "right" }),
    ],
  ],
);

Spalten

columns hat einen Eintrag pro Spalte und legt fest, wie breit jede ist. Die drei Arten lassen sich frei mischen.

BreiteBedeutung
90eine feste Breite in Punkt
"1fr", "2fr"ein Bruchteil des restlichen Platzes, anteilig geteilt (wie CSS fr)
"auto"so breit wie die breiteste Zelle der Spalte, gemessen beim Layout
"minmax(40, auto)"wie "auto", aber nie schmaler als 40pt - für eine Spalte, die auch leer bleiben darf seit beta.4

Eine typische Rechnung hat eine Beschreibungsspalte mit "1fr", die den freien Platz aufnimmt, und rechts Zahlenspalten mit fester Breite.

Zellen und Zeilen

rows ist ein Array aus Zeilen, jede ein Array aus Zellen. Eine Zelle ist ein beliebiges Element oder ein einfacher String (der für Sie in Text verpackt wird). Zahlenspalten richten Sie mit Text(value, { align: "right" }) rechtsbündig aus.

[
  ["Apples", "Granny Smith", Text("12", { align: "right" })],
  ["Oranges", "Valencia", Text("8", { align: "right" })],
];

Optionen

PropTypWas es tut
columnsColumnWidth[]eine Breite pro Spalte (Pflicht)
headerCell[]eine Header-Zeile, die oben auf jeder Seite wiederholt wird, über die die Tabelle läuft
cellPaddingInsetsPadding in jeder Zelle
ruleColorInputeine dünne waagerechte Linie unter dem Header und am Ende
cellBorderColorInputein vollständiges Gitter um jede Zelle
gapnumberAbstand zwischen Zeilen und Spalten
rowGap colGapnumbergap für eine Achse überschreiben

Linien oder ein volles Gitter

rule zieht zwei dünne Linien, unter dem Header und am Ende - der klare Look, den die meisten Rechnungen haben. cellBorder zieht stattdessen das komplette Gitter um jede Zelle.

// invoice style: thin separators
{ columns: ["1fr", 80], rule: "#c2ccdb", cellPadding: { x: 8, y: 6 } }

// spreadsheet style: full grid
{ columns: ["1fr", 80], cellBorder: "#c2ccdb", cellPadding: 8 }

Verwenden Sie das eine oder das andere. cellBorder zeichnet die Außenkanten bereits, umschließen Sie die Tabelle also nicht zusätzlich mit der Border einer Box, sonst sind die Kanten doppelt.

Über mehrere Seiten

Eine Table ist schlicht eine Column aus unteilbaren Zeilen, sie bricht also von selbst auf Seiten um: Passt eine Zeile nicht mehr auf die aktuelle Seite, wandert sie als Ganzes auf die nächste, und die header-Zeile wird oben neu gedruckt. Sie schreiben die Zeilen einmal, und lange Tabellen fließen einfach weiter.

Alles in einer Datei

import { writeFileSync } from "node:fs";
import { Document, Page, Table, Text, renderToBytes } from "@jasy/pdf";

const money = (n: number) => Text(n.toFixed(2), { align: "right" });

async function build() {
  const doc = Document([
    Page({ size: "A4", margin: 56 }, [
      Table(
        {
          columns: ["1fr", 50, 80, 90],
          header: [
            Text("Description", { bold: true }),
            Text("Qty", { bold: true, align: "right" }),
            Text("Unit", { bold: true, align: "right" }),
            Text("Amount", { bold: true, align: "right" }),
          ],
          cellPadding: { x: 8, y: 6 },
          rule: "#c2ccdb",
        },
        [
          [Text("Website design & build"), Text("1", { align: "right" }), money(9600), money(9600)],
          [Text("Strategy consulting"), Text("12", { align: "right" }), money(140), money(1680)],
          [Text("Printed brand book"), Text("25", { align: "right" }), money(28), money(700)],
        ],
      ),
    ]),
  ]);

  writeFileSync("table.pdf", await renderToBytes(doc));
}

build();