The Printer Side
The printer's default implementation is much thinner, since a printed page has no interaction and therefore needs no buttons, panels or shortcuts. What it mainly provides is a set of typesetting widgets and a configuration, so that output from different renderers agrees on the page.
DefaultPrinterComponent
The component does three things: supplies the printer configuration context, lays down a background sheet carrying the body font, and renders the printer component. Its props are:
| Prop | Role |
|---|---|
printer | The printer core |
root | The document tree to render |
config | A partial printer configuration, only what you want changed |
onUpdateCache | Receives the whole cache after each preprocessing pass, which a picker for cross reference targets can be built from |
onUpdateCache appeared in tutorial chapter 6, where it logged the cache to the console to
confirm that reference names really had been written into it. In a real application its purpose is to
supply the editing side with data: a dropdown for choosing which theorem to reference takes its
candidates from that cache.
The printer configuration
The printer configuration is also partial-override, in two parts, margins and fonts:
| Field | Contents |
|---|---|
margins | paragraph (between paragraphs), special (around special elements), colon (a small gap), level (the width of one indentation level), structure (horizontal offset of structural text) |
fonts | body, title, structure, display, weaken |
There are two more fonts than on the editor side: display for displayed text such as a whole
quotation, and weaken for de-emphasised text such as the body of a proof. In Chinese
typesetting these two normally change typeface outright rather than merely size.
The level entry decides how wide one indentation level is. Several of the widgets below read
it, so changing it in one place shifts the indentation of the whole document consistently.
<DefaultPrinterComponent
printer={printer}
root={tree}
config={{
margins: {paragraph: "0.6rem", level: "2.5rem"},
fonts : {display: {fontFamily: "Georgia"}, weaken: {fontSize: "0.95rem"}},
}}
/>
Typesetting widgets
When writing printer renderers, reach for the widgets below rather than bare div and
span. They take their fonts and spacing from the printer configuration, which is what keeps
text playing the same role looking the same throughout the document; a bare tag instead hard-codes
spacing and fonts into one renderer, where later changes to the configuration cannot reach them.
| Widget | Purpose |
|---|---|
PrinterPartBox | One logical block; with subtitle_like it uses the title font |
PrinterStructureBoxText | Structural text, such as a "Theorem 1" heading |
PrinterParagraphBox | An ordinary paragraph container with the standard spacing |
PrinterDisplayText | Displayed text, a quotation for instance |
PrinterWeakenText | De-emphasised text, the body of a proof for instance |
PrinterNewLevelBox | Indents one level inward |
PrinterOldLevelBox | Occupies the width of one indentation level, leaving room on the left for a number |
PrinterDivider | A divider carrying the configured spacing for special elements |
AutoStack | A container that arranges its contents in a row or a column depending on them |
The last two indentation widgets are a pair, and it takes both to produce the familiar "number on the
left, content on the right" arrangement: PrinterNewLevelBox pushes the content in by one
level, and PrinterOldLevelBox places the number within the width of that level. Tutorial
chapter 6 used exactly this combination when numbering items.
Chapters 4 and 5 of the tutorial were already using these widgets while writing the theorem renderer; they merely looked like ordinary layout components at the time. They can now be understood for what they are: the outlet of the printer configuration inside a renderer.
Renderer factories
The printer side has its own set of renderer factories mirroring the editor's:
get_default_group_renderer, get_default_inline_renderer,
get_default_structure_renderer, get_default_abstract_renderer, and
auto_renderer, which belongs to no particular node type. Their options
(outer, inner, pre_element, contexters and the rest)
are covered in tutorial chapters 4 and 6, introduced one at a time in the order they become useful, which
is easier to follow than a table here, so they are not repeated.
There is also a set of useless_renderer_block, useless_renderer_inline and
useless_renderer_text, serving the same purpose as get_default_editors() on the
editor side: they fill the default renderer slots of the Printer constructor so that a node
with no renderer registered still displays.