use gpui::{App, InteractiveElement, StatefulInteractiveElement, StyleRefinement, Styled, px};
use gpui_kit_theme::{ActiveTheme, Elevation};
pub trait Pressable: StatefulInteractiveElement + Styled + Sized {
fn pressable(self, cx: &App) -> Self {
if cx.reduce_motion() {
return self;
}
let sink = px(cx.theme().motion.press_offset);
self.active(|style| style.top(sink))
}
}
impl<T: StatefulInteractiveElement + Styled + Sized> Pressable for T {}
pub trait HoverLift: InteractiveElement + Styled + Sized {
fn hover_lift(self, cx: &App) -> Self {
self.hover_lift_with(cx, |style| style)
}
fn hover_lift_with(
self,
cx: &App,
wash: impl FnOnce(StyleRefinement) -> StyleRefinement,
) -> Self {
if cx.reduce_motion() {
return self.hover(wash);
}
let theme = cx.theme();
let lift = px(-theme.motion.hover_lift);
let shadow = theme.shadow(Elevation::Raised).to_vec();
self.hover(move |style| wash(style).top(lift).shadow(shadow.clone()))
}
}
impl<T: InteractiveElement + Styled + Sized> HoverLift for T {}
#[cfg(test)]
mod tests {
use gpui_kit_theme::Theme;
#[test]
fn the_pointer_responses_stay_within_a_hairline() {
for theme in [Theme::studio_dark(), Theme::studio_light()] {
assert!(theme.motion.press_offset > 0.0);
assert!(theme.motion.press_offset <= theme.borders.thick);
assert!(theme.motion.hover_lift > 0.0);
assert!(theme.motion.hover_lift <= theme.borders.thick);
}
}
}