This commit is contained in:
2026-11-01 15:30:12 +07:00
parent 749b3e4e29
commit 49da45c8ac
16 changed files with 128 additions and 64 deletions
+76 -12
View File
@@ -267,8 +267,20 @@ pub struct ControlMetrics {
pub text_size: Pixels,
/// Icons and on/off indicators.
pub icon_size: Pixels,
/// Icons inline with dense content — menu rows, badges, chevrons.
pub dense_icon_size: Pixels,
/// Selection indicators — checkboxes, radios, and switch knobs.
pub indicator_size: Pixels,
/// Avatars.
pub avatar_size: Pixels,
/// Dense label text.
pub caption_size: Pixels,
/// Tight horizontal padding inside pills, segments, and fields.
pub dense_padding_x: Pixels,
/// The inset between a control's edge and a raised inner plate.
pub plate_inset: Pixels,
/// The band height of multi-segment strips.
pub strip_height: Pixels,
}
/// The control metrics for every size class.
@@ -280,20 +292,72 @@ pub struct SizeTable {
}
impl SizeTable {
/// Every metric derives from the root font size; components fetch, and
/// never scale these themselves.
pub fn with_root_font_size(rem_size: Pixels) -> Self {
let class = |height: f32, padding: f32, text: f32, icon: f32, avatar: f32| ControlMetrics {
control_height: rem_size * height,
input_height: rem_size * (height + 0.125),
padding_x: rem_size * padding,
text_size: rem_size * text,
icon_size: rem_size * icon,
avatar_size: rem_size * avatar,
};
Self {
small: class(1.5, 0.75, 0.85, 0.875, 1.5),
medium: class(1.75, 1.0, 1.0, 1.0, 2.0),
large: class(2.25, 1.25, 1.15, 1.25, 3.0),
// One row per size class: control height, padding, label text, icon,
// avatar, strip band, and plate inset — all as root-size multiples.
struct ClassFactors {
height: f32,
padding: f32,
text: f32,
icon: f32,
avatar: f32,
strip: f32,
inset: f32,
}
let small = ClassFactors {
height: 1.5,
padding: 0.75,
text: 0.85,
icon: 0.875,
avatar: 1.5,
strip: 1.5,
inset: 0.125,
};
let medium = ClassFactors {
height: 1.75,
padding: 1.0,
text: 1.0,
icon: 1.0,
avatar: 2.0,
strip: 2.0,
inset: 0.25,
};
let large = ClassFactors {
height: 2.25,
padding: 1.25,
text: 1.15,
icon: 1.25,
avatar: 3.0,
strip: 3.0,
inset: 0.375,
};
let metrics = |f: &ClassFactors| ControlMetrics {
control_height: rem_size * f.height,
input_height: rem_size * (f.height + 0.125),
padding_x: rem_size * f.padding,
text_size: rem_size * f.text,
icon_size: rem_size * f.icon,
dense_icon_size: rem_size * f.icon * 0.75,
indicator_size: rem_size * f.height * 0.7,
avatar_size: rem_size * f.avatar,
caption_size: rem_size * f.text,
dense_padding_x: rem_size * f.padding * 0.75,
plate_inset: rem_size * f.inset,
strip_height: rem_size * f.strip,
};
let mut table = Self {
small: metrics(&small),
medium: metrics(&medium),
large: metrics(&large),
};
// Dense text stops growing with the large class, and small's is
// one step below its label.
table.small.caption_size = table.small.text_size * 0.85;
table.large.caption_size = table.medium.text_size;
table
}
/// The metrics for `size`.
+6
View File
@@ -292,6 +292,12 @@ mod tests {
assert_eq!(resolved.sizes.medium.input_height, px(30.));
assert_eq!(resolved.sizes.medium.text_size, px(16.));
assert_eq!(resolved.sizes.large.avatar_size, px(48.));
assert_eq!(resolved.sizes.small.caption_size, px(13.6 * 0.85));
assert_eq!(resolved.sizes.medium.caption_size, px(16.));
assert_eq!(resolved.sizes.large.caption_size, px(16.));
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.));
}
}