Skip to main content

Module typefaces

Module typefaces 

Source
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§

FontFace
One font face a native host can register: a stable family name plus the raw face bytes.
NativeTypefaces
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).