frust_glyph/lib.rs
1//! `frust-glyph`: the Glyph design system, packaged as a design-system plugin.
2//!
3//! Glyph is a terminal-native, **dark-first**, monospace-led design language —
4//! "inspired by Material 3 Expressive, Liquid Glass, and Yaru research ·
5//! original tokens". This crate is the whole system: the [`tokens`] module
6//! (color schemes, type/shape/elevation/motion/glass scales, the
7//! brightness-invariant [`GlyphInk`] extension, the assembled [`baseline`]
8//! theme), the bundled monospace faces, the two Glyph [`motion`] patterns, and
9//! the widget catalog.
10//!
11//! The catalog holds two kinds of component. Most are terminal-native ones with
12//! no Material or Cupertino equivalent (badges/tags/alerts, loaders + toast, nav
13//! chrome, content cards, the terminal block + tooltip, and the command-palette
14//! overlay). The rest are ordinary controls whose *authored Glyph design*
15//! diverges from what re-theming a baseline widget would produce — the baseline
16//! set is token-themed, not re-designed, per design language. [`toggle`] is the
17//! first of those: Glyph authors its own switch (a hairline-bordered pill with a
18//! constant-diameter springing knob and an accent wash), and the baseline
19//! deliberately ships no `Switch` at all for it to re-theme.
20//!
21//! # Installing it
22//!
23//! [`install`] is the one-line entry point, and it must run **before the first
24//! frame**: a shell reads the default-theme slot and drains the font registry
25//! once, at construction. The supported place is `app!`'s `setup` block, which
26//! runs before any shell construction:
27//!
28//! ```no_run
29//! use frust::{AnyView, Component, any, text};
30//!
31//! #[derive(Default)]
32//! struct MyApp;
33//!
34//! impl Component for MyApp {
35//! type State = ();
36//! fn init(&self) -> Self::State {}
37//! fn build(&self, _state: &mut Self::State) -> AnyView<Self::State> {
38//! any(text("glyph"))
39//! }
40//! }
41//!
42//! frust::app!(MyApp, setup = { frust_glyph::install(); });
43//! # fn main() {}
44//! ```
45//!
46//! # Namespace
47//!
48//! Every catalog module is re-exported wholesale from this root, so app code
49//! names one flat namespace — `frust_glyph::GlyphBadge`,
50//! `frust_glyph::show_glyph_dialog`, `frust_glyph::baseline()` — alongside the
51//! `frust::*` baseline widgets a Glyph screen composes with.
52//!
53//! # Charter
54//!
55//! - **Token-driven, never design-language-branching.** A Glyph widget
56//! resolves `Theme::from_paint_ctx`/`from_layout_ctx` and reads the Glyph
57//! token tables ([`tokens`]' color schemes, type scale, status palette,
58//! [`GlyphInk`], …) with an unthemed-fallback constant per resolved value —
59//! exactly like every baseline widget. It never matches on `DesignLanguage`;
60//! a Glyph theme is just a `Theme` whose token tables happen to be the Glyph
61//! ones.
62//! - **Facade-only.** Widgets are `View`/`Widget` pairs authored against
63//! `frust::authoring` (plus `kurbo`/`peniko` for geometry and color); this
64//! crate names no other framework crate, and nothing reactive.
65//!
66//! # Fonts
67//!
68//! The Space Mono and IBM Plex Mono faces the Glyph type scale names are
69//! compiled in and registered by [`install`] behind the crate's
70//! `bundled-fonts` feature (default on); an app that sets
71//! `default-features = false` on this dependency compiles in no font bytes,
72//! `install()` registers none, and text falls back to the platform's system
73//! faces through fontique (Roboto on Android). Both families are OFL-1.1 and
74//! ship with their license text and provenance record
75//! (`plugins/glyph/fonts/README.md`). [`font_data`] exposes the raw bytes for
76//! a host that wants them directly.
77//! Each family's italic face ships too, even though the catalog itself never
78//! requests `FontStyle::Italic` — see [`tokens::fonts`]'s module doc for the
79//! measurement behind keeping them (dropping them would silently fall back
80//! to plain upright text for an app's own italic request, not a synthesized
81//! oblique).
82
83pub mod accordion;
84pub mod alert;
85pub mod appbar;
86pub mod avatar;
87pub mod badge;
88pub mod breadcrumb;
89pub mod card;
90pub mod command_palette;
91pub mod dialog;
92pub mod dots;
93pub mod empty_state;
94pub mod list;
95pub mod menu;
96pub mod motion;
97pub mod navbar;
98mod press;
99pub mod progress;
100pub mod radio;
101pub mod reveal;
102pub mod segmented;
103pub mod sheet;
104pub mod side_sheet;
105pub mod skeleton;
106pub mod stat_card;
107pub mod tabs;
108pub mod tag;
109pub mod term_block;
110pub mod toast;
111pub mod toggle;
112pub mod tokens;
113pub mod tooltip;
114
115pub use accordion::*;
116pub use alert::*;
117pub use appbar::*;
118pub use avatar::*;
119pub use badge::*;
120pub use breadcrumb::*;
121pub use card::*;
122pub use command_palette::*;
123pub use dialog::*;
124pub use dots::*;
125pub use empty_state::*;
126pub use list::*;
127pub use menu::*;
128pub use navbar::*;
129pub use progress::*;
130pub use radio::*;
131pub use reveal::*;
132pub use segmented::*;
133pub use sheet::*;
134pub use side_sheet::*;
135pub use skeleton::*;
136pub use stat_card::*;
137pub use tabs::*;
138pub use tag::*;
139pub use term_block::*;
140pub use toast::*;
141pub use toggle::*;
142pub use tooltip::*;
143
144/// The design language itself, flattened to the root alongside the catalog:
145/// the assembled [`baseline`] theme, its bundled [`font_data`], the
146/// brightness-invariant [`GlyphInk`] extension, and the
147/// [`native_typefaces`](tokens::native_typefaces) binding [`baseline`]
148/// attaches. The per-scale constructors stay behind [`tokens`].
149pub use tokens::{GlyphInk, baseline, font_data};
150
151/// Make the Glyph design system this app's starting point.
152///
153/// Two process-global pushes, both public `frust` seams:
154///
155/// 1. `frust::set_default_theme(`[`baseline()`](baseline)`)` — the *base* a
156/// shell seeds itself with instead of its built-in `Theme::neutral()`
157/// fallback. Deliberately not `set_app_theme`: a seeded default does not pin
158/// brightness, so a Glyph app still follows system dark mode.
159/// 2. `frust::register_app_fonts` for every bundled Glyph face, so the Glyph
160/// type scale's families actually resolve. The faces are compiled in
161/// behind the crate's `bundled-fonts` feature (default on) — see the
162/// crate docs' *Fonts* section for the `default-features = false`
163/// opt-out.
164///
165/// # Timing: must run before the first frame
166///
167/// A shell reads the default-theme slot and drains the font registry **once,
168/// at construction**, before its first rebuild. A call after that takes effect
169/// only on a later `clear_app_theme`-driven reseed, which may never happen — so
170/// a late call silently does nothing visible.
171///
172/// The supported way to get the timing right on all three platforms is
173/// `frust::app!`'s setup block, which runs immediately before the root
174/// component's `Component::init` and therefore before any shell construction —
175/// see the crate docs for the full example. Calling it from `Component::init`
176/// itself also happens to be early enough today, but that is not a contract
177/// this crate keeps; the setup block is.
178///
179/// # Thread contract and repeat calls
180///
181/// Both underlying seams are plain `Mutex`-guarded process-globals callable
182/// from any thread. Calling `install` twice is harmless but wasteful: the
183/// second `set_default_theme` replaces an identical value, and the font bytes
184/// are pushed (and later re-registered, shadowing the same family names) a
185/// second time. Call it once.
186pub fn install() {
187 frust::set_default_theme(baseline());
188 for bytes in font_data() {
189 frust::register_app_fonts(bytes.to_vec());
190 }
191}