DesignTokenViewer shows every token of the theme in the mode shown, named as code reads it: colors with their hex, syntax, chart and terminal colors, the type scale, radii, control and icon sizes, elevations and spacing. A11yChecker audits each text color over the surfaces it sits on at 4.5:1 and the focus ring and chart hues at 3:1, failures first. The audit found fg_subtle under 4.5:1 on hover and overlay; it is #6f6d6a light and #8c8a87 dark now, and a test holds all four Ely palettes to the audit. IconBrowser points to forms::IconPicker and the ScreenshotTest Harness to the gallery's capture, each with a section on the tooling page.
107 lines
3.4 KiB
Rust
107 lines
3.4 KiB
Rust
use gpui::{
|
|
Context, IntoElement, ParentElement, Render, Rgba, Styled, TestAppContext, VisualTestContext,
|
|
Window, div, px,
|
|
};
|
|
|
|
use crate::{
|
|
forms::hex,
|
|
theme::{ControlSize, Density, Palette, Theme},
|
|
tooling::{A11yChecker, DesignTokenViewer},
|
|
};
|
|
|
|
/// gpui takes a static selector, so a formatted one is leaked.
|
|
fn shown(selector: &str, cx: &mut VisualTestContext) -> bool {
|
|
cx.debug_bounds(Box::leak(selector.into())).is_some()
|
|
}
|
|
|
|
struct Tokens;
|
|
|
|
impl Render for Tokens {
|
|
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
|
|
div().w(px(900.0)).child(DesignTokenViewer::new())
|
|
}
|
|
}
|
|
|
|
/// Each token shows its name as code reads it and its value in the mode shown; a changed theme shows through.
|
|
#[gpui::test]
|
|
fn the_viewer_names_each_token_with_its_value(cx: &mut TestAppContext) {
|
|
cx.update(Theme::init);
|
|
let (_, cx) = cx.add_window_view(|_, _| Tokens);
|
|
cx.run_until_parked();
|
|
let light = Palette::light(false);
|
|
let keyword = format!(
|
|
"token-colors.syntax.keyword-{}",
|
|
hex(Rgba::from(light.syntax.keyword))
|
|
);
|
|
let blue = format!(
|
|
"token-colors.hue(0) Blue-{}",
|
|
hex(Rgba::from(light.chart[0]))
|
|
);
|
|
for selector in [
|
|
"token-colors.fg_subtle-#6f6d6a",
|
|
&keyword,
|
|
&blue,
|
|
"token-TextSize::Sm-12",
|
|
"token-Radius::Md-6",
|
|
"token-ControlSize::Md-28",
|
|
"token-IconSize::Md-16",
|
|
"token-gap_2-8",
|
|
"token-Elevation::Modal",
|
|
] {
|
|
assert!(shown(selector, cx), "{selector}");
|
|
}
|
|
cx.update(|_, cx| {
|
|
Theme::update(cx, |theme| {
|
|
theme.colors = Palette::dark(false);
|
|
theme.density = Density::Compact;
|
|
})
|
|
});
|
|
cx.run_until_parked();
|
|
assert!(
|
|
shown("token-colors.fg_subtle-#8c8a87", cx),
|
|
"the dark palette"
|
|
);
|
|
let compact = cx.update(|window, cx| {
|
|
use crate::theme::ActiveTheme;
|
|
cx.theme()
|
|
.control_height(ControlSize::Md)
|
|
.to_pixels(window.rem_size())
|
|
});
|
|
assert_eq!(compact, px(24.0));
|
|
assert!(shown("token-ControlSize::Md-24", cx), "compact density");
|
|
}
|
|
|
|
struct Audit;
|
|
|
|
impl Render for Audit {
|
|
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
|
|
div().w(px(600.0)).child(A11yChecker::new())
|
|
}
|
|
}
|
|
|
|
/// Ely's palette passes; a color moved under its need fails, counted, and lists first.
|
|
#[gpui::test]
|
|
fn the_checker_counts_failures_first(cx: &mut TestAppContext) {
|
|
cx.update(Theme::init);
|
|
let (_, cx) = cx.add_window_view(|_, _| Audit);
|
|
cx.run_until_parked();
|
|
assert!(shown("contrast-summary-41-0", cx), "every pair passes");
|
|
assert!(shown("contrast-fg-bg-AAA", cx));
|
|
assert!(shown("contrast-fg_subtle-hover-AA", cx), "4.53:1 on hover");
|
|
assert!(shown("contrast-focus-surface-AA", cx));
|
|
assert!(shown("contrast-chart Blue-bg-AA", cx));
|
|
cx.update(|_, cx| Theme::update(cx, |theme| theme.colors.fg_subtle = theme.colors.bg));
|
|
cx.run_until_parked();
|
|
assert!(
|
|
shown("contrast-summary-41-5", cx),
|
|
"five surfaces under fg_subtle"
|
|
);
|
|
let failing = cx
|
|
.debug_bounds("contrast-fg_subtle-hover-Fails")
|
|
.expect("a failing row");
|
|
let passing = cx
|
|
.debug_bounds("contrast-fg-bg-AAA")
|
|
.expect("a passing row");
|
|
assert!(failing.top() < passing.top(), "failures list first");
|
|
}
|