Expand description
NativeTypefaces: the native-control typeface binding a design system
attaches as a crate::extensions::ThemeExtensions payload.
Every widget this repo paints itself resolves its face from
crate::typography::TypeScale (a frust_text::TextStyle family name,
resolved by the text engine’s own font stack). A native control —
frust-native-widgets’ Android TextView/iOS UILabel family — cannot:
the platform resolves fonts itself, so its host half needs the raw face
bytes to register with Typeface.createFromFile/CoreText before any
control can name the face at all.
This extension is that seam, and the only route those bytes take: a
design system attaches its two faces here, and a native host reads them
back with theme.extension::<NativeTypefaces>(). Two slots — a
button/display face and a body face — mirroring the split
frust-native-widgets’ theme ladder already applies (Button on one
face, Label/Switch on the other), and matching the two-payload shape
its platform publish seam already carries; a design system with one face
for everything uses NativeTypefaces::uniform.
§No CORE baseline attaches this
Unlike StatusPalette (attached to
Theme::neutral), nothing this crate
constructs attaches NativeTypefaces. Attaching it is exclusively a
design system’s job, and its absence is what tells a native host to leave
the platform’s own face alone — frust_glyph’s baseline is the shipped
example of a design system that does attach it, which is how its
monospace faces reach native controls at all. See
docs/NATIVE_WIDGETS_ARCHITECTURE.md’s theme ladder.
§Why &'static [u8]
A design system embeds its faces with include_bytes!, so 'static bytes
are what a caller already has and what a platform registration call
already wants (no copy, no Arc, no lifetime threading through the
theme). It also keeps FontFace Copy and keeps
Theme’s own Clone/PartialEq cheap.
Note that ThemeExtensions’
PartialEq compares the set of attached types, never their values (see
that module) — so two Themes differing only in which faces this
extension carries compare equal. A consumer that must react to a face
swap therefore keys off the payload itself (identity or content), never
off Theme equality.
§Examples
use frust_theme::{FontFace, NativeTypefaces, Theme};
// A design system's own embedded faces (`include_bytes!` in real code).
static DISPLAY: &[u8] = b"<display face bytes>";
static BODY: &[u8] = b"<body face bytes>";
let theme = Theme::builder(Theme::neutral())
.extension(NativeTypefaces {
button: Some(FontFace::new("Acme Display", DISPLAY)),
body: Some(FontFace::new("Acme Text", BODY)),
})
.build();
let faces = theme.extension::<NativeTypefaces>().expect("attached above");
assert_eq!(faces.button.map(|f| f.family), Some("Acme Display"));Structs§
- Font
Face - One font face a native host can register: a stable family name plus the raw face bytes.
- Native
Typefaces - The native-control typeface binding: a display/button face and a body face, either of which may be left unset (falling back to whatever the native host resolves without it — see the module doc).