max / makeover-webview
git clone https://makenot.work/git/max/makeover-webview.git
git clone git@ssh.makenot.work:max/makeover-webview.git
| Name | Size | |
|---|---|---|
| dist/ | ||
| examples/ | ||
| src/ | ||
| .gitignore | 99 B | |
| bento.toml | 334 B | |
| Cargo.toml | 2.1 KB | |
| LICENSE | 1.0 KB | |
| README.md | 4.3 KB | |
| rust-toolchain.toml | 86 B |
README
makeover-webview
The webview renderer for
makeover-layout. Emits CSS.
The renderer that needs no palette
makeover-immediate and makeover-tui both take a Palette, because egui and
a terminal need an actual colour before they can put anything on screen. A
webview does not. var(--surface-raised) is the late binding, and the browser
resolves it against whatever the theme layer last wrote onto :root.
So this crate emits text naming intents and never learns a colour, which is the deferral rule with no adapter in the way. It is also why the webview was always the wrong renderer to derive a vocabulary from: it can express anything, so it never pushes back.
Phase A: the stylesheet
No markup here, deliberately. GoingsOn has 145 innerHTML sites and Balanced
Breakfast 175 createElement sites, so moving markup is a migration while
adopting a generated stylesheet is a deletion. The apps keep every line of their
markup and gain the classes.
:root {
--bevel-raised: inset 1px 1px 0 var(--bevel-light), inset -1px -1px 0 var(--bevel-dark);
--bevel-inset: inset 1px 1px 0 var(--bevel-dark), inset -1px -1px 0 var(--bevel-light);
}
.raised { background: var(--surface-raised); box-shadow: var(--bevel-raised); }
.well { background: var(--surface-well, var(--surface-page)); box-shadow: var(--bevel-inset); }
.card:active { background: var(--surface-well, var(--surface-page)); box-shadow: var(--bevel-inset); }
Those two custom properties are byte-identical to what both apps already hand-write, which is asserted in the tests. Adoption removes duplicated lines rather than changing a pixel.
The depth classes are surfaces and nothing more. A raised object that is not
pressable is spelled .raised, and the states belong to the named surfaces:
.card and .button are that same depth and controls, so they carry hover,
press, focus and disabled.
.card:active is the one thing this renderer gets for free: the cascade carries
a pressed state that an immediate-mode renderer resolves per call site, eighteen
of them in audiofiles.
Phase B: form markup
form::field_html renders a makeover_layout::Field to the group both apps
build by hand today: label, control, hint, error, in goingson’s shape and class
names, so adopting it deletes renderFormField rather than restyling anything.
use makeover_layout::{Field, FieldKind};
use makeover_webview::{Emit, form::{Filling, Value, field_html}};
let field = Field::new(FieldKind::Text, "title", "Title");
let html = field_html(&field, &Filling::of(Value::Text("Ship it")), &Emit::default());
It emits strings because both apps interpolate fields into larger string-built
forms, and it escapes them itself. One escaper covers both sinks: goingson needs
four and a correct choice at 543 call sites only because textContent
serialization will not encode a double quote, which is not a constraint Rust
has. The single hole is form::Markup, which a caller has to name.
Three things the emitter does that neither app does at initial render:
aria-invalid="true"on an invalid control, which is what the generated stylesheet keys its danger ring on. goingson sets it from its runtime validation path and not from its renderer, so a field rendered already-invalid is styled as though nothing were wrong.aria-describedbynaming the hint as well as the error, so standing help survives an error appearing.- A secret never carries its value into the markup, on
FieldKind::confidential.
Rows and tables are the other half of phase B and are not written yet.
Substitution, three ways
Fill::Well has no colour on makeover before 2.3.0, and the three renderers
answer that differently. That is the evidence that taking Fill::fallback out of
the description was right:
makeover-immediatesubstitutes the page in Rust.makeover-tuirefuses to substitute and draws an edge, because a terminal quantises the two together.- here, CSS already has the mechanism.
var(--surface-well, var(--surface-page))falls back in the browser and nothing in Rust decides anything.
Status
On crates.io at 0.5.1, which is the CSS half only; the form markup is unreleased. Consumers are GoingsOn and Balanced Breakfast, both through makeover-build.
cargo run --example dump prints the stylesheet.
Licence
MIT.