Files
Ely-GPUI-Components/src/buttons/fab.rs
T

101 lines
3.2 KiB
Rust

use gpui::{
Animation, AnimationExt, App, ClickEvent, ElementId, FontWeight, InteractiveElement,
IntoElement, MouseButton, ParentElement, RenderOnce, SharedString, StatefulInteractiveElement,
Styled, Window, div, prelude::*,
};
use super::button::ClickHandler;
use crate::{
motion,
primitives::{FocusRing, Icon, IconName, Tooltip},
theme::{ActiveTheme, Elevation, IconSize, TextSize},
};
/// A raised round button for a screen's main action; a label makes it a pill.
#[derive(IntoElement)]
pub struct FloatingActionButton {
id: ElementId,
icon: IconName,
label: Option<SharedString>,
tooltip: Option<SharedString>,
on_click: Option<ClickHandler>,
}
impl FloatingActionButton {
pub fn new(id: impl Into<ElementId>, icon: IconName) -> Self {
Self {
id: id.into(),
icon,
label: None,
tooltip: None,
on_click: None,
}
}
pub fn label(mut self, label: impl Into<SharedString>) -> Self {
self.label = Some(label.into());
self
}
pub fn tooltip(mut self, text: impl Into<SharedString>) -> Self {
self.tooltip = Some(text.into());
self
}
pub fn on_click(
mut self,
handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
) -> Self {
self.on_click = Some(Box::new(handler));
self
}
}
impl RenderOnce for FloatingActionButton {
fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
let theme = cx.theme();
let colors = &theme.colors;
let side = theme.fab_size();
let (hover, lifted) = (colors.accent_hover, theme.elevation(Elevation::Modal));
div()
.id(self.id)
.flex()
.flex_none()
.items_center()
.justify_center()
.gap_2()
.h(side)
.map(|fab| match &self.label {
Some(_) => fab.pl_5().pr_6(),
None => fab.w(side),
})
.rounded_full()
.bg(colors.accent)
.text_color(colors.on_accent)
.text_size(theme.text_size(TextSize::Md))
.font_weight(FontWeight::MEDIUM)
.border_1()
.border_color(gpui::transparent_black())
.shadow(theme.elevation(Elevation::Floating))
.cursor_pointer()
.tab_index(0)
.focus_ring(cx)
.hover(move |style| style.bg(hover).shadow(lifted))
.on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
.when_some(self.on_click, |fab, handler| fab.on_click(handler))
.when_some(self.tooltip, |fab, text| fab.tooltip(Tooltip::text(text)))
.child(
Icon::new(self.icon)
.size(IconSize::Lg)
.color(colors.on_accent),
)
.when_some(self.label, |fab, label| fab.child(label))
.with_animation(
"fab-in",
Animation::new(motion::duration(motion::SLOW, cx))
.with_easing(motion::ease_out_cubic),
|fab, t| fab.opacity(t).mt(motion::NUDGE * 2.0 * (1.0 - t)),
)
}
}