chore: audit all components (#2)

Reviewed-on: #2
This commit was merged in pull request #2.
This commit is contained in:
2026-11-08 06:27:12 +00:00
parent 0ad5c3fe90
commit 11b29dc91a
51 changed files with 2096 additions and 958 deletions
+167 -42
View File
@@ -1,7 +1,9 @@
use crate::definition::ThemeDefinition;
use crate::ramps::{AccentShades, Oklch, contrast_foreground, derive_shades, mix};
use crate::system::SystemTheme;
use crate::{ColorTokens, Elevations, Motion, Radius, Scrollbar, SizeTable, ThemeVariant};
use crate::{
Borders, ColorTokens, Elevations, Motion, Radius, Scrollbar, SizeTable, Spacing, ThemeVariant,
};
use gpui::px;
/// The floor of a custom titlebar's height, in px at 100% scaling: the height
@@ -26,6 +28,8 @@ pub struct ResolvedTheme {
pub colors: ColorTokens,
pub ramps: Ramps,
pub radius: Radius,
pub borders: Borders,
pub spacing: Spacing,
pub elevations: Elevations,
pub motion: Motion,
pub scrollbar: Scrollbar,
@@ -198,18 +202,35 @@ pub(crate) fn resolve(
//
// Fallback: 16 (the web default gpui also uses for rems).
let root_font_size = system.root_font_size.unwrap_or(px(16.));
let mut sizes = SizeTable::with_root_font_size(root_font_size);
if let Some(control_height) = system.control_height {
sizes.set_control_height(control_height);
}
if let Some(input_height) = system.input_height {
sizes.set_input_height(input_height);
}
if let Some(switch_height) = system.switch_height {
sizes.set_switch_metrics(
switch_height,
system.switch_width.unwrap_or(switch_height * 2.25),
system.switch_knob.unwrap_or(switch_height * 0.85),
);
}
if let Some(menu_item_height) = system.menu_item_height {
sizes.set_menu_item_height(menu_item_height);
}
// A platform that states its titlebar height wins.
let titlebar_height = system
.titlebar_height
.unwrap_or_else(|| sizes.medium.control_height.max(px(TITLEBAR_HEIGHT_MIN_PX)));
let mut radius = Radius::default();
if let Some(control) = preset
.and_then(|def| def.control_radius)
.map(px)
@@ -218,6 +239,22 @@ pub(crate) fn resolve(
radius.control = control;
}
if let Some(overlay) = preset
.and_then(|def| def.overlay_radius)
.map(px)
.or(system.overlay_radius)
{
radius.overlay = overlay;
}
if let Some(sm) = preset
.and_then(|def| def.sm_radius)
.map(px)
.or(system.sm_radius)
{
radius.sm = sm;
}
ResolvedTheme {
variant,
ramps: Ramps {
@@ -238,6 +275,10 @@ pub(crate) fn resolve(
},
colors,
radius,
borders: Borders::for_platform(system.source, variant),
spacing: Spacing {
unit: system.source.spacing_unit(),
},
elevations: Elevations::for_platform(system.source, variant),
motion: Motion::default(),
scrollbar: Scrollbar {
@@ -283,7 +324,14 @@ mod tests {
accent,
palette,
control_radius: None,
overlay_radius: None,
sm_radius: None,
control_height: None,
input_height: None,
menu_item_height: None,
switch_height: None,
switch_width: None,
switch_knob: None,
titlebar_height: None,
root_font_size: None,
accessibility: AccessibilityPreferences::default(),
@@ -291,24 +339,14 @@ mod tests {
}
}
#[test]
fn metric_priority_is_definition_then_system_then_fallback() {
let mut stated = system(ThemeVariant::Dark, PartialPalette::default(), None);
stated.control_radius = Some(px(4.));
let resolved = resolve(&stated, None, None);
assert_eq!(resolved.radius.control, px(4.));
let def = ThemeDefinition::parse_toml("control_radius = 12.0\n").unwrap();
let overridden = resolve(&stated, Some(&def), None);
assert_eq!(overridden.radius.control, px(12.));
}
#[test]
fn empty_system_resolves_to_the_neutral_fallback() {
for variant in [ThemeVariant::Light, ThemeVariant::Dark] {
let resolved = resolve(
&system(variant, PartialPalette::default(), None),
&SystemTheme {
source: SourceKind::Fallback,
..system(variant, PartialPalette::default(), None)
},
None,
None,
);
@@ -333,6 +371,21 @@ mod tests {
assert_eq!(resolved.sizes.medium.dense_padding_x, px(16. * 0.75));
assert_eq!(resolved.sizes.medium.plate_inset, px(4.));
assert_eq!(resolved.sizes.medium.strip_height, px(32.));
assert_eq!(resolved.sizes.medium.icon_size, px(16.));
assert_eq!(resolved.sizes.medium.menu_item_height, px(28. * 0.85));
assert_eq!(resolved.sizes.medium.switch_height, px(21.));
assert_eq!(resolved.sizes.medium.switch_width, px(21. * 2.25));
assert_eq!(resolved.sizes.medium.switch_knob, px(21. * 0.85));
assert_eq!(
resolved.borders,
Borders {
buttons: true,
fields: true,
overlays: true,
focus_ring: false,
}
);
assert_eq!(resolved.spacing.unit, px(4.));
assert_eq!(resolved.titlebar_height, px(34.));
}
}
@@ -383,17 +436,105 @@ mod tests {
let mut stated = system(ThemeVariant::Light, PartialPalette::default(), None);
stated.input_height = Some(px(24.));
let resolved = resolve(&stated, None, None);
// The medium class takes the stated height verbatim, and the other
// classes keep their derived ratio to the medium class.
assert_eq!(resolved.sizes.medium.input_height, px(24.));
// Derive what small would be without the statement, scale it by the
// stated-to-derived ratio, and compare.
let derived = SizeTable::with_root_font_size(px(16.));
let scale = px(24.) / derived.medium.input_height;
let expected_small = derived.small.input_height * scale;
assert!((resolved.sizes.small.input_height - expected_small).abs() < px(0.01));
let expected_small = (derived.small.input_height * scale).floor();
assert_eq!(resolved.sizes.small.input_height, expected_small);
}
#[test]
fn a_stated_control_height_overrides_the_medium_class_and_scales() {
let mut stated = system(ThemeVariant::Light, PartialPalette::default(), None);
stated.control_height = Some(px(32.));
let resolved = resolve(&stated, None, None);
assert_eq!(resolved.sizes.medium.control_height, px(32.));
let derived = SizeTable::with_root_font_size(px(16.));
let scale = px(32.) / derived.medium.control_height;
let expected_small = (derived.small.control_height * scale).floor();
let expected_large = (derived.large.control_height * scale).floor();
assert_eq!(resolved.sizes.small.control_height, expected_small);
assert_eq!(resolved.sizes.large.control_height, expected_large);
}
#[test]
fn stated_switch_and_menu_metrics_override_the_derived_ones() {
let mut stated = system(ThemeVariant::Light, PartialPalette::default(), None);
stated.switch_height = Some(px(20.));
stated.switch_width = Some(px(40.));
stated.switch_knob = Some(px(12.));
stated.menu_item_height = Some(px(33.));
let resolved = resolve(&stated, None, None);
assert_eq!(resolved.sizes.medium.switch_height, px(20.));
assert_eq!(resolved.sizes.medium.switch_width, px(40.));
assert_eq!(resolved.sizes.medium.switch_knob, px(12.));
assert_eq!(resolved.sizes.medium.menu_item_height, px(33.));
}
#[test]
fn the_radius_ladder_follows_stated_values_with_preset_priority() {
let mut stated = system(ThemeVariant::Light, PartialPalette::default(), None);
stated.control_radius = Some(px(9.));
stated.overlay_radius = Some(px(15.));
stated.sm_radius = Some(px(6.));
let resolved = resolve(&stated, None, None);
assert_eq!(resolved.radius.control, px(9.));
assert_eq!(resolved.radius.overlay, px(15.));
assert_eq!(resolved.radius.sm, px(6.));
let def = ThemeDefinition::parse_toml("overlay_radius = 12.0\n").unwrap();
let overridden = resolve(&stated, Some(&def), None);
assert_eq!(overridden.radius.overlay, px(12.));
assert_eq!(overridden.radius.sm, px(6.));
}
#[test]
fn borders_and_spacing_follow_the_platform_source() {
let chrome = |source| {
let mut stated = system(ThemeVariant::Light, PartialPalette::default(), None);
stated.source = source;
let resolved = resolve(&stated, None, None);
(resolved.borders, resolved.spacing.unit)
};
let (borders, unit) = chrome(SourceKind::Windows);
assert!(borders.buttons && borders.fields && borders.overlays && !borders.focus_ring);
assert_eq!(unit, px(4.));
let (borders, unit) = chrome(SourceKind::Kde);
assert!(borders.buttons && borders.fields && borders.overlays && !borders.focus_ring);
assert_eq!(unit, px(4.));
let (borders, unit) = chrome(SourceKind::Macos);
assert!(!borders.buttons && borders.fields && !borders.overlays && borders.focus_ring);
assert_eq!(unit, px(4.));
for source in [SourceKind::Gnome, SourceKind::Omarchy] {
let (borders, unit) = chrome(source);
assert!(!borders.buttons && !borders.fields && !borders.overlays && borders.focus_ring);
assert_eq!(unit, px(6.));
}
let (borders, unit) = chrome(SourceKind::Fallback);
assert!(borders.buttons && borders.fields && borders.overlays && !borders.focus_ring);
assert_eq!(unit, px(4.));
}
#[test]
fn dark_mode_separates_overlays_by_border() {
for source in [SourceKind::Macos, SourceKind::Gnome, SourceKind::Omarchy] {
let mut stated = system(ThemeVariant::Dark, PartialPalette::default(), None);
stated.source = source;
let resolved = resolve(&stated, None, None);
assert!(
resolved.borders.overlays,
"{source:?} frames floating layers in dark"
);
assert!(resolved.elevations.popover.shadows().is_empty());
assert!(resolved.elevations.dialog.shadows().is_empty());
}
}
#[test]
@@ -426,7 +567,7 @@ mod tests {
#[test]
fn elevations_and_motion_resolve_with_defaults() {
let resolved = resolve(
&system(ThemeVariant::Dark, PartialPalette::default(), None),
&system(ThemeVariant::Light, PartialPalette::default(), None),
None,
None,
);
@@ -438,7 +579,7 @@ mod tests {
);
assert!(resolved.motion.overlay > std::time::Duration::ZERO);
let shadows = resolved.elevations.popover.shadows();
assert_eq!(shadows.len(), 1);
assert_eq!(shadows.len(), 2);
assert!(!shadows[0].inset);
}
@@ -666,20 +807,4 @@ mod tests {
let preset_stated = resolve(&system(ThemeVariant::Dark, palette, None), Some(&def), None);
assert_eq!(preset_stated.colors.info, hsla(0x0ea5e9));
}
#[test]
fn muted_hover_follows_the_overlay_chain() {
// No platform states a hover wash; a preset or user file is the only
// override above the neutral base.
let palette = PartialPalette {
muted_hover: Some(hsla(0x155e75)),
..PartialPalette::default()
};
let stated = resolve(&system(ThemeVariant::Dark, palette, None), None, None);
assert_eq!(stated.colors.muted_hover, hsla(0x155e75));
let def = ThemeDefinition::parse_toml("muted_hover = \"#0ea5e9\"\n").unwrap();
let preset_stated = resolve(&system(ThemeVariant::Dark, palette, None), Some(&def), None);
assert_eq!(preset_stated.colors.muted_hover, hsla(0x0ea5e9));
}
}