sync radius

This commit is contained in:
2026-10-28 17:30:54 +07:00
parent 0b8b619342
commit 5cbffe8172
6 changed files with 43 additions and 8 deletions
+1
View File
@@ -76,6 +76,7 @@ GPUI is a UI framework which also provides primitives for state and concurrency
- Dependency direction is one-way: `gpui-native-kit` (facade) → `gpui-native-core` / `gpui-native-editor` / … → `gpui-native-theme` + `gpui-native-icons` → gpui. No cycles. Nothing depends on `gpui-component`, `gpui-kit`, `gpuikit`, `bezel`, `native-theme`, or any gpui fork. - Dependency direction is one-way: `gpui-native-kit` (facade) → `gpui-native-core` / `gpui-native-editor` / … → `gpui-native-theme` + `gpui-native-icons` → gpui. No cycles. Nothing depends on `gpui-component`, `gpui-kit`, `gpuikit`, `bezel`, `native-theme`, or any gpui fork.
- `crates/theme` owns the native theme engine and every color, radius, spacing, and metric value — no raw `rgb`/`rgba`/`hsla` or layout `px(...)` literals anywhere else. - `crates/theme` owns the native theme engine and every color, radius, spacing, and metric value — no raw `rgb`/`rgba`/`hsla` or layout `px(...)` literals anywhere else.
- Components always take corner radii from the theme `Radius` token (`cx.theme().radius`); never use gpui's `rounded_*` presets or hardcoded radii in components.
- `crates/icons` owns icon resolution; components reference icons by semantic role — no glyph names, unicode symbols, or SVG paths anywhere else. - `crates/icons` owns icon resolution; components reference icons by semantic role — no glyph names, unicode symbols, or SVG paths anywhere else.
- `crates/core` and its sibling crates own components: each one is a small self-contained implementation gated behind its own cargo feature. Features are additive, gate whole modules only, and may depend on other features. Behavior and presentation live together. No separate behavior layer — promote a shared helper only when a third component needs it. - `crates/core` and its sibling crates own components: each one is a small self-contained implementation gated behind its own cargo feature. Features are additive, gate whole modules only, and may depend on other features. Behavior and presentation live together. No separate behavior layer — promote a shared helper only when a third component needs it.
- Components are written in-tree. Other UI toolkits are read for API ideas only; never port their code or depend on them. - Components are written in-tree. Other UI toolkits are read for API ideas only; never port their code or depend on them.
+6 -1
View File
@@ -56,11 +56,16 @@ impl Global for Theme {}
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub struct Radius { pub struct Radius {
pub control: Pixels, pub control: Pixels,
/// Pill and circle shapes.
pub full: Pixels,
} }
impl Default for Radius { impl Default for Radius {
fn default() -> Self { fn default() -> Self {
Self { control: px(6.) } Self {
control: px(6.),
full: px(9999.),
}
} }
} }
+20 -2
View File
@@ -138,8 +138,12 @@ pub(crate) fn resolve(
} }
let mut radius = Radius::default(); let mut radius = Radius::default();
if let Some(control) = preset.and_then(|def| def.control_radius) { if let Some(control) = preset
radius.control = px(control); .and_then(|def| def.control_radius)
.map(px)
.or(system.control_radius)
{
radius.control = control;
} }
ResolvedTheme { ResolvedTheme {
@@ -182,11 +186,25 @@ mod tests {
variant, variant,
accent, accent,
palette, palette,
control_radius: None,
accessibility: AccessibilityPreferences::default(), accessibility: AccessibilityPreferences::default(),
source: SourceKind::Macos, source: SourceKind::Macos,
} }
} }
#[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] #[test]
fn empty_system_resolves_to_the_neutral_fallback() { fn empty_system_resolves_to_the_neutral_fallback() {
for variant in [ThemeVariant::Light, ThemeVariant::Dark] { for variant in [ThemeVariant::Light, ThemeVariant::Dark] {
+4
View File
@@ -18,6 +18,9 @@ use super::ThemeSource;
use crate::ThemeVariant; use crate::ThemeVariant;
use crate::system::{AccessibilityPreferences, PartialPalette, SourceKind, SystemTheme}; use crate::system::{AccessibilityPreferences, PartialPalette, SourceKind, SystemTheme};
/// Default control radius for macOS controls.
const CONTROL_RADIUS_PTS: f32 = 6.0;
#[derive(Default)] #[derive(Default)]
pub(crate) struct MacosSource { pub(crate) struct MacosSource {
_observers: Vec<Retained<ProtocolObject<dyn NSObjectProtocol>>>, _observers: Vec<Retained<ProtocolObject<dyn NSObjectProtocol>>>,
@@ -98,6 +101,7 @@ impl ThemeSource for MacosSource {
variant, variant,
accent: Self::color_to_hsla(&NSColor::controlAccentColor()), accent: Self::color_to_hsla(&NSColor::controlAccentColor()),
palette, palette,
control_radius: Some(gpui::px(CONTROL_RADIUS_PTS)),
accessibility, accessibility,
source: SourceKind::Macos, source: SourceKind::Macos,
} }
+3 -1
View File
@@ -1,6 +1,6 @@
//! The normalized snapshot a platform adapter produces. //! The normalized snapshot a platform adapter produces.
use gpui::Hsla; use gpui::{Hsla, Pixels};
use crate::ThemeVariant; use crate::ThemeVariant;
@@ -55,6 +55,7 @@ pub struct SystemTheme {
pub variant: ThemeVariant, pub variant: ThemeVariant,
pub accent: Option<Hsla>, pub accent: Option<Hsla>,
pub palette: PartialPalette, pub palette: PartialPalette,
pub control_radius: Option<Pixels>,
pub accessibility: AccessibilityPreferences, pub accessibility: AccessibilityPreferences,
pub source: SourceKind, pub source: SourceKind,
} }
@@ -65,6 +66,7 @@ impl SystemTheme {
variant, variant,
accent: None, accent: None,
palette: PartialPalette::default(), palette: PartialPalette::default(),
control_radius: None,
accessibility: AccessibilityPreferences::default(), accessibility: AccessibilityPreferences::default(),
source: SourceKind::Fallback, source: SourceKind::Fallback,
} }
+9 -4
View File
@@ -18,6 +18,7 @@ impl Render for Gallery {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let theme = cx.theme(); let theme = cx.theme();
let colors = theme.colors; let colors = theme.colors;
let radius = theme.radius;
let variant = theme.variant; let variant = theme.variant;
let source = gpui_native_theme::detected_source(cx); let source = gpui_native_theme::detected_source(cx);
let mode_override = gpui_native_theme::mode_override(cx); let mode_override = gpui_native_theme::mode_override(cx);
@@ -105,7 +106,8 @@ impl Render for Gallery {
.text_sm() .text_sm()
.text_color(colors.muted_foreground) .text_color(colors.muted_foreground)
.child(format!( .child(format!(
"phase C — button · source: {source} · variant: {variant:?}" "phase C — button · source: {source} · variant: {variant:?} · control radius {}px",
f32::from(theme.radius.control)
)), )),
), ),
) )
@@ -125,6 +127,7 @@ impl Render for Gallery {
label, label,
active, active,
colors, colors,
radius,
move |_, _, cx| gpui_native_theme::set_mode_override(value, cx), move |_, _, cx| gpui_native_theme::set_mode_override(value, cx),
) )
})), })),
@@ -146,6 +149,7 @@ impl Render for Gallery {
label, label,
active, active,
colors, colors,
radius,
move |_, _, cx| { move |_, _, cx| {
let _ = gpui_native_theme::set_preset(value, cx); let _ = gpui_native_theme::set_preset(value, cx);
}, },
@@ -208,7 +212,7 @@ impl Render for Gallery {
.child( .child(
div() div()
.size_6() .size_6()
.rounded_full() .rounded(radius.full)
.border_1() .border_1()
.border_color(colors.border) .border_color(colors.border)
.bg(color), .bg(color),
@@ -236,7 +240,7 @@ impl Render for Gallery {
.child( .child(
div() div()
.size_6() .size_6()
.rounded_full() .rounded(radius.full)
.border_1() .border_1()
.border_color(colors.border) .border_color(colors.border)
.bg(color), .bg(color),
@@ -292,6 +296,7 @@ fn chip<F>(
label: SharedString, label: SharedString,
active: bool, active: bool,
colors: gpui_native_theme::ColorTokens, colors: gpui_native_theme::ColorTokens,
radius: gpui_native_theme::Radius,
on_click: F, on_click: F,
) -> impl IntoElement + use<F> ) -> impl IntoElement + use<F>
where where
@@ -301,7 +306,7 @@ where
.id(SharedString::from(id)) .id(SharedString::from(id))
.px_3() .px_3()
.py_1() .py_1()
.rounded_full() .rounded(radius.full)
.border_1() .border_1()
.text_xs() .text_xs()
.cursor_pointer() .cursor_pointer()