Repository navigation
v5.2.0
A PDF is the page, printed. The PDF and slide writers are replaced by one
paged layout engine: the program is rendered to the HTML and CSS a
template renders, and the compiler lays that out on paper itself — the
real cascade, block, flex and grid layout, shaped and bidirectional text,
pagination, and a PDF with embedded font subsets, an outline and links. No
browser, no external tool. A design that works on the web works on paper.
The engine
- CSS, as the page has it. The engine's rules for every built-in, the
theme's tokens, the project's.cssfiles and everystyle { }block,
through a cascade with combinators, attribute selectors,
:first-child/:nth-child, specificity, inheritance,var(),em,
rem,%and::before/::after.@media printapplies. - Layout. Block, flex and grid, absolute positioning,
gap,
min-/max-sizes,aspect-ratio, inline-blocks on a line, tables
sized by their content, list markers. - Text. Shaped (ligatures, kerning, Arabic joining), bidirectional,
broken at Unicode's opportunities, justified. A right-to-left document
mirrors its rows, grids, tables and list markers. - Paint. Gradients with any number of stops, background pictures,
per-side borders with radii, shadows, opacity, clipping, rotation; PNG,
JPEG, WebP, GIF and SVG (kept vector). - Pagination. Lines kept two to a side, tables broken between rows with
their header repeated, side-by-side columns broken each on its own,
headings kept with what follows,break-inside: avoid,PageBreakand
break-before/break-after.
New elements
Header(on:),Footer(on:)withpageandpagesin scope;
Background(on:), drawn edge to edge behind each page;
Watermark("DRAFT").TableOfContents(levels:, title:)— headings with the page each
lands on, dotted leaders, linked.Chart(kind: .bar | .line | .area | .pie | .donut, …)and
QrCode(value), vector graphics in a PDF, and SVG on a web page
where what they read is known at build time.Document(size:, landscape, margin:, title:, author:, subject:, keywords:, lang:)names the paper and the file's metadata.
Fonts
Liberation Sans, Serif and Mono are built into wf, so Helvetica,
Arial, sans-serif, Times and monospace resolve with nothing
installed. .ttf/.otf files under fonts/ (or src/fonts/,
public/fonts/, pdf.fonts) and local @font-face rules are used by
their family name, variable fonts at the asked weight. A character no
named face has is drawn from one that has it; the build names any family
taken from the machine, and "system_fonts": false forbids it.
Decks
- A
Presentationholdsfor,ifand slide components: a deck
writes its openers and footers once and makes a slide per item of its
data. - A page's
stateandderivedvalues have their values on paper —
and in any template render — so a slide shows a figure worked out from a
datafile. Data handed to a render wins over either. :is()and:where()in the paged cascade. The engine's slide
heading sizes use:where, and the slide margin is a default, so a
deck's own classes always win.
Templates
render_pdf_reportandrender_slides_reportreturn aPdfReport:
the bytes, the page count, each page's text in reading order and the
notes. A template reads fonts and pictures from beside its files.
The editor
- The language server knows what the project writes. In a
pdfor
slidesproject, completion offers only what paper draws — no
Button, noon click, noresource— aPresentationis offered its
slides and the project's slide components, and hover says when an
element is not drawn in this output and why.pageandpagesare names
inside aHeader,FooterorBackground. On a web project the
paper-only elements are offered last.
Fixes
- Right to left, a flex row runs from the right. taffy already
mirrors a row underdirection: rtl; the engine reversed it again, so
rows in an Arabic PDF came out left to right. - A keyed list no longer draws a row twice when a handler that runs as
a row leaves — an input'sblur— writes the list while it is being
drawn. - A
Linkwhosetohas a query (/?show=open) is active only when
the address has those values too; a row of filter links no longer marks
every one as the current page. - Attributes on a component's call reach its root —
class:,
aria-*,data-*,id,role,title,hidden— on the live page
and in the static paint; before, they were dropped without a word. A
component that declares a prop of that name still receives it. - A
Boolprop given a condition —outlined: theme != "light"—
follows it, instead of becoming an attribute. - The static paint draws what the live page does: a component's
derivedthat reads a store, aclass:list with one entry only the
browser knows,hidden:. - On a page with a layout, the skip link jumps past the layout's
chrome to where the page starts. wf test:expectreads the text a reader sees, not the markup; a
date or money literal draws;data:seeds stores in a test that clicks;
wf test tests/x.wfruns that file in its project.- A
validaterule's message may bet("key"), and a rule's argument
that reads state is read when it checks. xs.filter(x => x != null)is a list of what is there ([T?]to
[T]).wf fmtleaves arguments laid out over lines as written.- The breadcrumb JSON-LD lists only pages a reader can open; a page's
head { }counts as reading its values (no falseU02); a store
action called in the store's own initial value is named for what it is. Host(title:)is thetitleattribute.
Diagnostics
V11: a component of the project's own named like a built-in
(component Chart), which shadows it.E109now refuses only what a page means only in a browser;
everything static draws.
Examples
examples/documents/ holds three reference documents: a nine-page
Halyard platform report (dark cover, contents, charts, a 64-row table that
repeats its header, incidents, a QR code), an invoice (band, watermark,
repeated header, totals kept whole), and an Arabic résumé laid out right to
left.
examples/decks/ holds three slide decks: WebFluent itself in the docs
site's design system, Halyard's quarterly review drawn from the report's
data (a slide per incident from a for), and an Arabic workshop.
Tutorials
The cookbook is now Tutorials: three projects built step by step, each
complete under examples/tutorials/ and none needing a server — Todos
(easy), Field Notes, a statically built notes site (medium), and
Pocket, a budget tracker with forms, i18n and offline (hard). A test
holds every file the chapter shows to the project it comes from.
Editors
The tree-sitter grammars and the VS Code grammar highlight the new
elements.
Full Changelog: v5.1.1...v5.2.0