Grundlagen
Dokumente und Nodes
Ein Dokument ist ein Baum aus Komponenten, von denen jede ihre Daten als State nimmt und die Nodes zurückgibt, die sie will.
Ein Dokument ist ein Template plus ein Datentyp. Das Template ist ein Baum aus
Komponenten; jede gibt Nodes zurück, und den Baum gegen Daten aufzulösen
ergibt ein DocumentModel — reines JSON, ohne dass damit ein Rendering gemeint
wäre.
Eine Komponente nimmt ihre Daten als State
import { Paragraph, useState } from "docxcelerate/template";
import type { DocumentData } from "../types.ts";
export const Greeting: Paragraph = () => {
const [state] = useState((data: DocumentData) => ({
name: data.residentName,
}));
return <Paragraph id="greeting">Dear {state.name},</Paragraph>;
};
useState ist die Stelle, an der Daten in eine Komponente kommen — und die
einzige. Alles danach liest State. Das ist eine Regel mit einem Grund: Weil jede
Abhängigkeit durch eine einzige Deklaration läuft, steht aufgeschrieben, was
eine Komponente braucht, statt sich über den Code zu verteilen, der es benutzt.
Der Initializer ist gewöhnliches TypeScript. Es gibt keine Template-Sprache, Bedingungen, Formatierung und Importe stehen also einfach zur Verfügung.
Paragraph benennt zugleich das Element und den Komponententyp — ein Wert und
ein Typ dürfen sich einen Namen teilen. const Greeting: Paragraph sagt also,
was hier geliefert wird, und ein <Section> daraus zurückzugeben ist ein
Compile-Fehler.
Daten können auch als Props ankommen
Eine Komponente, der man gibt, was sie braucht, muss nicht selbst danach greifen:
export const Arrears: Paragraph<{ amount: number }> = ({ amount }) => {
const { currency } = useFormat();
return <Paragraph id="arrears">You owe {currency(amount)}.</Paragraph>;
};
Irgendwer muss die Daten zuerst lesen, eine reine Props-Komponente sitzt also unter einer Eltern-Komponente, die sie in State genommen hat. Nehmen Sie Props für Komponenten, die Sie gegen verschiedene Werte wiederverwenden wollen, und State für Komponenten, die wissen, zu welchem Dokument sie gehören.
Entscheidungen sind ein gewöhnliches if
export const Balance: Paragraph = () => {
const [state] = useState((data: DocumentData) => ({
settled: data.balanceDue === 0,
}));
if (state.settled) {
return <Paragraph id="settled">Nothing outstanding.</Paragraph>;
}
return <Paragraph id="arrears">A balance remains.</Paragraph>;
};
Geben Sie jedem Zweig eine eigene id. Das aufgelöste Dokument hält dann fest, welchen dieser Empfänger bekommen hat — und das ist der Unterschied zwischen einem Dokument, das Sie prüfen können, und einem, das Sie nur ansehen können.
Zum Verzweigen gibt es eine Sache zu wissen, bevor Sie an eine Engine veröffentlichen: siehe was sich beim Veröffentlichen ändert.
Ids
Eine id ist die Adresse, unter der eine Engine einen Node anspricht und unter der Build-Artefakte zwischen Läufen diffbar bleiben. Behandeln Sie eine Umbenennung als Breaking Change.
Sie dürfen sie weglassen. Ein Node ohne id bekommt eine aus seiner Position, und genau das verhindert, dass Verzweigungen und Schleifen Sie zwingen, Namen zu erfinden. Was nicht geht, ist dieselbe zweimal: Zwei Nodes, die eine id beanspruchen, sind ein Fehler — gemeldet mit beiden Positionen — und kein Wettlauf, den der spätere gewinnt.
Sections verschachteln, Nodes nicht
Section ist die einzige verschachtelnde Konstruktion. Ihr Titel trägt in die
Gliederung des Dokuments:
<Section id="opening" title="Opening">
<Greeting />
<Offer />
</Section>
Siehe Section dafür, was eine Section enthalten darf und wie tief.
Hooks
Hooks sind der Weg, auf dem eine Komponente den Build um sich herum erreicht:
| Hook | Was er Ihnen gibt |
|---|---|
useState | Daten, einmal hereingenommen und behalten |
useShared | Ein Wert für die Komponenten, die danach gerendert werden |
useSetPrompts | Prompts für den gelieferten Node — was ihn dynamisch macht |
useSetPlaceholders | Was Vorschauen statt erzeugter Inhalte zeigen |
usePlaceholderData | Ersatz-Namen, -Daten und -Zahlen für Vorschauen |
useFormat | Sprachraumgerechte Währungen, Daten, Listen und Pluralformen |
useAvailableTokens | Das Token-Budget, das dieser Build zugeteilt hat |
useDeriver | Führt einen registrierten Deriver jetzt aus |
Sie laufen in Aufrufreihenfolge, jeder Hook muss also vor dem ersten await und
vor jeder Verzweigung erreicht werden — dieselbe Regel wie in React, aus
demselben Grund. Einen nach einem await aufzurufen ist ein Fehler, der das
auch sagt, statt sich still an die nächste gerenderte Komponente zu hängen.
Das Dokument bauen
import { buildDocument } from "docxcelerate";
const doc = await buildDocument(documentTemplate, data);
Das Ergebnis ist ein DocumentModel: eine schemaVersion, eine id, ein
title und ein nodes-Array. Es enthält kein Styling und kein Layout — die
kommen später von dem Renderer, der es konsumiert.
Für ein mit defineDocumentProject definiertes Dokumentprojekt nehmen Sie
besser buildProjectPreviewDocument: Es wendet den Stil des Projekts an und
löst dynamische Nodes zu ihren Platzhaltern auf:
import { buildProjectPreviewDocument } from "docxcelerate";
const doc = await buildProjectPreviewDocument(project);
Genau das ruft die Vorschau-App auf, was Sie im Code bauen entspricht also dem, was Sie im Browser gesehen haben.
Diese Seite auf GitHub bearbeiten ↗ Diese Seite als Markdown lesen