Dokumentation
PDFs erstellen
PDFs in Vue
PDFs in Nuxt
PDFs in React
PDFs in Angular
Komponenten
Jede Komponente entspricht einem Element der Engine, und jeder Prop-Typ IST der Optionstyp der Engine: Eine
neue Option der Engine ist am Tag ihres Erscheinens ein typisierter Prop, und ein falscher Wert wird in Ihrem
Editor rot. Boolesche Props haben die übliche JSX-Kurzform: <Text bold> ist <Text bold={true}>.
Alle Komponenten:
Document · Page · Column · Row · Box · Padding · Expanded · Spacer · Divider ·
Image · Svg · Canvas · Text · Paragraph · Span · Table / TableRow / TableCell ·
Positioned · DefaultTextStyle · Link · Anchor · Bookmark · Rotated · RotatedBox ·
PageBreak · KeepTogether · PageNumber · PageCount · SubPageNumber · SubPageCount ·
PageBuilder · SplitView · Flow · Region · ColumnBreak · TextField · Checkbox ·
RadioGroup · Dropdown · ListBox · PushButton · SignatureField.
Wo React einen eigenen Weg hat, wird er verwendet: Text und Labels sind Children, sich wiederholende Bereiche sind Props, und was pro Seite gebaut wird, ist eine Funktion.
Struktur
Document
Die Wurzel jedes PDF. Ihre Text-Props setzen die Standards für das ganze Dokument, die alles darin erbt.
| Prop | Typ |
|---|---|
size, color, font, bold, italic | Standard-Textstil - jeder vererbbare Textstil |
align, lineHeight | Standard-Absatzstil |
meta | { title?, author? } |
fonts | eigene Fonts, siehe Daten und Assets |
emoji | eine Quelle für Farb-Emoji, siehe Emoji |
Page
Eine Seitenvorlage. Sie ordnet ihre Kinder als Column an, gap, justify und align funktionieren also
auch hier.
| Prop | Typ |
|---|---|
size | "A4", "Letter", ... oder eine eigene Größe |
orientation | "portrait" | "landscape" |
margin | eine Zahl, oder Insets pro Seite |
gap | Abstand zwischen den Kindern |
justify | "start" | "center" | "end" | "between" | "around" |
align | "start" | "center" | "end" | "stretch" |
header, footer | ein beliebiges Element, auf jeder Seite wiederholt |
header und footer werden einmal angeordnet und auf jeder physischen Seite wiederholt, über die der
Inhalt läuft, mit dem Platz, den sie brauchen, reserviert - der Inhalt läuft nie darunter:
<Document>
<Page
size="A4"
margin={48}
header={
<Text size={9} color="#94a3b8">
ACME GmbH - Invoice
</Text>
}
footer={
<Row justify="between">
<Text size={9} color="#94a3b8">
acme.example
</Text>
<PageNumber size={9} color="#94a3b8" />
</Row>
}
>
<Text>... long content that paginates across pages ...</Text>
</Page>
</Document>
Layout
Column und Row
Stapeln die Kinder senkrecht (Column) oder waagerecht (Row). Beide nehmen die Optionen der Stacks der
Engine: gap, justify, align, wrap, reverse, alignContent, eine width und height in Punkt
oder "%", und die Page-Break-Props unten.
<Row gap={12} justify="between" align="center">
<Text bold>Item</Text>
<Text>Value</Text>
</Row>
Jedes Kind kann mit alignSelf aus der Ausrichtung seiner Zeile ausscheren, sich mit order verschieben
und minWidth, maxWidth, minHeight, maxHeight und aspectRatio nehmen - siehe
Layout.
Box
Ein Container mit Größe und Gestaltung: Hintergrund, Border, Padding, abgerundete Ecken.
| Prop | Typ |
|---|---|
bg | eine Farbe, oder ein Gradient |
border | eine Farbe |
borderTop / borderRight / borderBottom / borderLeft, borderWidth | Border pro Seite |
padding | eine Zahl, oder Insets pro Seite |
width, height | Punkt, oder ein Prozentwert wie "50%" |
radius | eine Zahl, oder Radien pro Ecke |
relative | macht sie zum Frame für die Positionierung |
overflow | "hidden" schneidet die Kinder auf die Box zu |
Padding, Spacer, Expanded, Divider
<Padding insets={16}>- umgibt ein Kind mit Abstand (eine Zahl oder Insets pro Seite).<Spacer flex={1} />- dehnbarer leerer Raum, der Geschwister auseinanderschiebt.<Expanded flex={1}>- macht sein Kind zum Flex-Item, das seinen Anteil am restlichen Platz nimmt;flexBasisundflexShrinkwie in CSS.<Divider color="#e2e8f0" thickness={1} />- eine Linie.
Text
Text, Paragraph und Span
Text und Paragraph zeichnen ihre Children als Text; Span gestaltet ein Stück darin. Total: {sum}
ist ein Stück, gemessen und gekernt als eines.
| Prop | Typ |
|---|---|
size, font, color | das Grundlegende; font nimmt auch eine Fallback-Liste |
bold, italic | boolesche Kurzformen |
align | "left" | "center" | "right" | "justify" |
lineHeight | Faktor für die Line-Height |
letterSpacing, wordSpacing | in Punkt; negativ verengt |
textIndent | Einzug der ersten Zeile, in Punkt |
textTransform | "uppercase" | "lowercase" | "capitalize" | "none" |
underline, strikethrough, skipInk | Linien; skipInk führt sie um Descender herum |
direction | "ltr" | "rtl" - Hebräisch und Arabisch in richtiger Reihenfolge |
ligatures | false schaltet fi/fl/ffi ab, die standardmäßig an sind |
breakWord, hyphenate | was mit einem Wort geschieht, das zu lang für seine Box ist |
orphans, widows | Mindestzahl an Zeilen, die an einem Page Break zusammenbleiben |
maxLines, overflow | overflow ist "clip" | "ellipsis" |
role | "h1".."h6" | "p" für ein getaggtes, barrierefreies PDF |
href | den Text mit einer externen URL verlinken |
to | den Text mit einem <Anchor> verlinken |
<Span> nimmt die Stile eines Textstücks - size, font, color, bold, italic, die Linien,
letterSpacing, wordSpacing, textTransform, ligatures, breakWord, hyphenate - plus href / to
und verticalAlign ("super" | "sub"), das die Baseline eines Stücks verschiebt, ohne seine Größe zu
ändern. Was zum ganzen Absatz gehört, bleibt an <Text>: align, lineHeight, textIndent,
direction, maxLines, overflow, orphans, widows und role.
<Paragraph>
Built with{" "}
<Span href="https://jasy.dev" bold color="#1450aa">
jasy
</Span>
, and this part is not a link.
</Paragraph>
Leerzeichen zwischen Spans schreiben Sie selbst, als {" "} - JSX verwirft die Zeilenumbrüche um ein Tag.
<DefaultTextStyle> belegt den Textstil für einen ganzen Teilbaum neu vor, das Gegenstück pro Abschnitt zu
den Standards von <Document>.
Image
<Image src={bytes} width={120} height={120} fit="cover" align="top" radius={8} alt="Logo" />
src nimmt Bild-Bytes (ein Uint8Array), eine URL oder - auf dem Server - einen Pfad; siehe
Daten und Assets. fit ist "fill" (der Standard), "contain",
"cover" oder "none", und align sagt, wo das Bild in seiner Box sitzt. Ohne Größe hat das Bild seine
eigene Größe, passend verkleinert. Die Props sind die der Factory Image. Eine
SVG-Quelle wird von selbst erkannt und bleibt ein Vektor.
Svg
<Svg src={logoMarkup} width={120} alt="Acme" />
src nimmt SVG-Markup, die Bytes der Datei oder - auf dem Server - einen Pfad. Ohne Größe zeichnet es in
seiner eigenen Größe; legen Sie eine Achse fest, folgt die andere der viewBox. Mit alt wird es in einem
getaggten PDF zu einer Figure. Was das Subset abdeckt, steht unter SVG und Canvas.
Canvas
Für ein Diagramm, eine Sparkline oder ein Siegel reicht <Canvas> Ihrer Funktion einen typisierten Pen und
die Größe, die das Layout ermittelt hat:
import type { CanvasPaint } from "@jasy/pdf";
const months = [12, 19, 14, 27, 22, 31];
const sparkline: CanvasPaint = (c, { width, height }) => {
const max = Math.max(...months);
c.move(0, height - (months[0] / max) * height);
months
.slice(1)
.forEach((v, i) =>
c.line(((i + 1) / (months.length - 1)) * width, height - (v / max) * height),
);
c.stroke("#1450aa", { width: 1.5, cap: "round" });
};
<Canvas height={46} paint={sparkline} />;
Dieselbe Funktion funktioniert in jeder Breite, eine Definition dient also einer breiten Karte und einer schmalen Seitenleiste.
Table
<Table columns> enthält <TableRow>s aus <TableCell>s. Markieren Sie eine Zeile mit header, um sie
auf jeder Seite zu wiederholen, über die die Tabelle läuft. Eine Zahl ist eine feste Breite in Punkt,
"1fr" ein flexibler Anteil, "auto" die breiteste Zelle.
<Table columns={["1fr", 120]} cellBorder="#e2e8f0" cellPadding={9}>
<TableRow header>
<TableCell>
<Text bold>Description</Text>
</TableCell>
<TableCell>
<Text bold>Amount</Text>
</TableCell>
</TableRow>
{lines.map((line) => (
<TableRow key={line.id}>
<TableCell>{line.name}</TableCell>
<TableCell>{`${line.total} EUR`}</TableCell>
</TableRow>
))}
</Table>
Eine Zelle enthält einen String oder beliebige Komponenten. Table nimmt außerdem gap / rowGap /
colGap, cellPadding, cellBorder und eine Farbe für rule.
Positioned
Platzierung außerhalb des Flows, verankert am nächsten <Box relative> (oder an der Seite). Geben Sie ihm
Kanten (top / right / bottom / left) oder einen Anchor (h / v) plus einen Versatz x / y.
zIndex legt die Zeichenreihenfolge fest - siehe Positionierung.
<Box relative height={200}>
<Positioned top={8} right={8}>
<Text size={9} color="#94a3b8">
draft
</Text>
</Positioned>
</Box>
Navigation
<Link> macht sein Kind anklickbar. href öffnet eine URL, to springt zu einem <Anchor> im selben
Dokument - genau eines von beiden, und die Typen sagen das.
| Komponente | Props |
|---|---|
<Link> | href | to |
<Anchor> | name (Pflicht) |
<Bookmark> | title (Pflicht), level |
Eine Kapitelüberschrift will einen Eintrag in der Seitenleiste und ein Sprungziel. Verschachteln Sie sie:
<Bookmark title="2. Installation" level={1}>
<Anchor name="install">
<Text size={22} bold>
2. Installation
</Text>
</Anchor>
</Bookmark>
Wie Links, Anchors und Bookmarks darunter funktionieren, steht unter Navigation.
Rotated und RotatedBox
<Rotated angle> dreht sein Kind beim Zeichnen: Die Layout-Box bleibt ungedreht, Geschwister ordnen sich
also nicht neu an - ein Stempel oder ein Watermark. <RotatedBox turns> macht Quarter-Turns, die das Layout
berücksichtigt: Eine Drehung um 90 oder 270 Grad tauscht Breite und Höhe, ein senkrechtes Label reserviert
also genau den Streifen, den es einnimmt.
<Row gap={12}>
<RotatedBox turns={3}>
<Text bold>SECTION A</Text>
</RotatedBox>
<Rotated angle={-18}>
<Box bg="#ffe9e9" border="#d33" padding={10}>
<Text size={26} bold color="#d33">
PAID
</Text>
</Box>
</Rotated>
</Row>
Page Breaks
<PageBreak /> unterbricht den Flow: Alles danach beginnt auf einer neuen Seite. <KeepTogether> lässt
seine Kinder nicht teilen und schiebt die ganze Gruppe auf die nächste Seite, wenn sie nicht passt. Beide
gibt es auch als Props (breakBefore, breakAfter, keepTogether) an <Box>, <Column> und <Row>.
<Page>
<Text size={18} bold>
Terms
</Text>
<PageBreak />
<Box keepTogether border="#d0d4da" radius={8} padding={14}>
<Text bold>Signed</Text>
<Text size={9}>This box is never torn across two pages.</Text>
</Box>
</Page>
Seitenzahlen
<PageNumber> und <PageCount> drucken die aktuelle Seite und die Gesamtzahl des Dokuments;
<SubPageNumber> und <SubPageCount> zählen innerhalb einer <Page>, für ein Dokument aus Abschnitten.
Sie nehmen die Props von <Text> plus offset, das zur Zahl addiert wird (-1, wenn ein Deckblatt nicht
mitzählen soll).
Für alles andere, was von der Seite abhängt, nimmt <PageBuilder> eine Funktion als Child und baut sie für
jede Seite, auf der es landet. Geben Sie null zurück, um auf einer Seite nichts zu zeigen:
<Page
header={
<PageBuilder>
{({ pageNumber }) =>
pageNumber === 1 ? null : <Text size={9}>Annual Report, continued</Text>
}
</PageBuilder>
}
footer={
<PageBuilder>
{({ pageNumber, pageCount }) => (
<Text size={9} align="center">
Page {pageNumber} of {pageCount}
</Text>
)}
</PageBuilder>
}
>
{/* body */}
</Page>
Die Funktion bekommt pageNumber, pageCount, pageSize, subPageNumber und subPageTotalPages. Was sie
baut, wird als Ganzes auf ihre Seite gesetzt. Damit die Gesamtzahl stimmt, paginiert jasy das ganze
Dokument, bevor es irgendetwas zeichnet.
Spalten
<SplitView> setzt seinen Inhalt in Zeitungsspalten, die auf der nächsten Seite weitergehen und sich auf
der letzten ausgleichen. <ColumnBreak /> beginnt die nächste Spalte.
<Page gap={12}>
<Text size={28} bold color="#1450aa">
The Valley Courier
</Text>
<SplitView columns={3} colGap={16} rowGap={8}>
{paragraphs.map((p) => (
<Text key={p.id}>{p.text}</Text>
))}
</SplitView>
<Text italic>This line follows the columns, right where they end.</Text>
</Page>
Für ein eigenes Layout nimmt <Flow> es als Render-Prop page: eine Seite des Layouts, mit einer
<Region /> überall dort, wo der Inhalt hin soll. Sie bekommt { index, pageNumber }, die erste Seite
kann also anders aussehen als die übrigen.
<Flow
gap={8}
page={({ index }) => (
<Column gap={12}>
{index === 0 ? (
<Text size={22} bold color="#1450aa">
Annual Report
</Text>
) : (
<Text size={9} italic>
Annual Report, continued
</Text>
)}
<Row gap={16}>
<Expanded>
<Region />
</Expanded>
<Box bg="#f3f5f9" padding={8}>
<Region width={150} />
</Box>
</Row>
</Column>
)}
>
{report.map((p) => (
<Text key={p.id}>{p.text}</Text>
))}
</Flow>
page und die Funktion eines PageBuilder werden an Ort und Stelle gerendert, in Ihrem Baum, während das
PDF angeordnet wird - Hooks und Context funktionieren darin wie überall sonst. Die Optionen und die
benannten Fehler stehen auf der Seite Spalten.
Formularfelder
Ein Formularfeld ist ein Layout-Element wie jedes andere: Es reserviert eine Box, fließt mit seinen Nachbarn und erzeugt ein Widget, in das man im Reader tippen kann. Sieben Arten:
| Komponente | Wofür |
|---|---|
TextField | eine Zeile oder, mit multiline, mehrere; password, maxLength |
Checkbox | ein einzelnes Häkchen; onValue ist das, was gespeichert wird |
RadioGroup | eines von mehreren, für Sie angeordnet; options + value |
Dropdown | eine geschlossene Liste, oder editable für freien Text |
ListBox | eine sichtbare Liste; multiSelect für mehrere gleichzeitig |
PushButton | eine Aktion - "reset", { open: url } oder { submit: url } |
SignatureField | ein leeres Feld, in dem der Leser unterschreibt |
Jedes Feld nimmt name (der Schlüssel, unter dem der Wert gespeichert wird), required, hidden, print
und die Appearance-Props border, background und color. Die einzelnen Widgets ergänzen tooltip,
readOnly und borderWidth; die mit Box (TextField, Dropdown, ListBox, PushButton,
SignatureField) nehmen width und height, eine Checkbox nimmt size. Eine RadioGroup besteht aus
mehreren Buttons und hat deshalb keines dieser drei: Sie nimmt size, gap und die Label-Gestaltung ihrer
Optionen. Das Label einer Checkbox, eines PushButton oder eines SignatureField sind seine Children:
<Column gap={10}>
<TextField name="fullName" width={220} height={22} border="#aab3c2" background="#fbfcfe" />
<RadioGroup
name="plan"
gap={6}
options={[
{ value: "basic", label: "Basic" },
{ value: "pro", label: "Pro" },
]}
/>
<Dropdown name="country" width={110} height={22} options={["DE", "AT", "CH"]} />
<Checkbox name="agree">I have read the statutes</Checkbox>
<PushButton name="clear" action="reset" width={92} height={26}>
Reset form
</PushButton>
</Column>
Es gibt kein onChange: Ein erzeugtes PDF schreibt nichts zurück, value ist also der Wert, mit dem das
Feld beginnt. Ein ausgefülltes Formular zurückzulesen liegt im Core: Formulare.
Eine eigene Komponente
Ihre eigenen Komponenten sind React-Komponenten - setzen Sie sie aus den Komponenten oben zusammen, mit Props, Hooks und Context:
function Callout({ children }: { children: string }) {
return (
<Box bg="#eef1f5" border="#1450aa" radius={6} padding={12}>
<Text color="#1450aa">{children}</Text>
</Box>
);
}