chore: audit components

This commit is contained in:
2026-11-10 15:06:16 +07:00
parent af2177c6c8
commit 03369f501e
92 changed files with 2744 additions and 1947 deletions
+89 -87
View File
@@ -6,11 +6,12 @@ use std::time::Duration;
use gpui::prelude::FluentBuilder as _;
use gpui::{
Animation, AnimationExt as _, App, Context, ElementId, Entity, InteractiveElement as _,
IntoElement, ParentElement as _, RenderOnce, SharedString, StatefulInteractiveElement as _,
Styled as _, Task, Window, deferred, div, ease_out_quint, px,
IntoElement, ParentElement as _, RenderOnce, Role, SharedString,
StatefulInteractiveElement as _, Styled as _, Task, Window, deferred, div, ease_out_quint, px,
};
use gpui_native_icons::{Icon, IconRole, icon};
use gpui_native_theme::ActiveTheme as _;
use gpui_native_icons::{Icon, IconRole};
use gpui_native_theme::{ActiveTheme as _, TOAST_MAX_WIDTH};
use gpui_native_utils::ResultLogErr as _;
use crate::button::{Button, ButtonVariant};
use crate::common::{DismissHandler, Sizable as _};
@@ -41,6 +42,7 @@ impl ToastAction {
/// A toast notification.
#[derive(Clone)]
#[must_use]
pub struct Toast {
message: SharedString,
icon: Option<Icon>,
@@ -133,7 +135,8 @@ impl Toasts {
if let Some(duration) = duration.filter(|duration| !duration.is_zero()) {
let task = cx.spawn(async move |this, cx| {
cx.background_executor().timer(duration).await;
this.update(cx, |toasts, cx| toasts.dismiss(id, cx)).ok();
this.update(cx, |toasts, cx| toasts.dismiss(id, cx))
.log_err();
});
self.tasks.push(task);
}
@@ -147,8 +150,7 @@ impl Toasts {
self.finish_exit(cx);
return;
}
if self.current.as_ref().is_some_and(|entry| entry.id == id) {
let entry = self.current.take().expect("current checked above");
if let Some(entry) = self.current.take_if(|entry| entry.id == id) {
self.start_exit(entry, cx);
}
}
@@ -177,7 +179,7 @@ impl Toasts {
if let Some(previous) = self.exiting.take()
&& let Some(on_dismiss) = &previous.toast.on_dismiss
{
(on_dismiss.clone())(cx);
on_dismiss(cx);
}
self.exiting = Some(entry);
@@ -186,7 +188,8 @@ impl Toasts {
let fade = cx.theme().motion.overlay;
let task = cx.spawn(async move |this, cx| {
cx.background_executor().timer(fade).await;
this.update(cx, |toasts, cx| toasts.finish_exit(cx)).ok();
this.update(cx, |toasts, cx| toasts.finish_exit(cx))
.log_err();
});
self.tasks.push(task);
}
@@ -195,13 +198,15 @@ impl Toasts {
if let Some(entry) = self.exiting.take() {
cx.notify();
if let Some(on_dismiss) = &entry.toast.on_dismiss {
(on_dismiss.clone())(cx);
on_dismiss(cx);
}
}
}
}
/// The floating stack of toasts, bottom center.
#[derive(IntoElement)]
#[must_use]
pub struct ToastsView {
toasts: Entity<Toasts>,
id: ElementId,
@@ -239,7 +244,7 @@ impl RenderOnce for ToastsView {
.items_center()
.when_some(exiting, |column, entry| {
let id = entry.id;
column.child(pill(&entry, &self.toasts, cx).with_animation(
column.child(entry.pill(&self.toasts, cx).with_animation(
("toast-exit", id),
Animation::new(fade),
|pill, delta| pill.opacity(1. - delta),
@@ -247,7 +252,7 @@ impl RenderOnce for ToastsView {
})
.when_some(current, |column, entry| {
let id = entry.id;
column.child(pill(&entry, &self.toasts, cx).with_animation(
column.child(entry.pill(&self.toasts, cx).with_animation(
("toast-enter", id),
Animation::new(fade).with_easing(ease_out_quint()),
|pill, delta| pill.opacity(delta),
@@ -257,90 +262,87 @@ impl RenderOnce for ToastsView {
}
}
fn pill(entry: &ToastEntry, toasts: &Entity<Toasts>, cx: &App) -> gpui::Stateful<gpui::Div> {
let theme = cx.theme();
let surface = theme.colors.surface;
let border = if theme.borders.overlays {
theme.colors.border
} else {
surface
};
let foreground = theme.colors.foreground;
let muted = theme.colors.muted;
let radius = theme.radius.full;
let shadows = theme.elevations.popover.shadows();
let icon_size = theme.sizes.small.icon_size;
let dense_icon_size = theme.sizes.small.dense_icon_size;
let text_size = theme.sizes.small.text_size;
let toast = &entry.toast;
let toasts = toasts.clone();
let id = entry.id;
impl ToastEntry {
/// The rendered pill for this toast.
fn pill(&self, toasts: &Entity<Toasts>, cx: &App) -> gpui::Stateful<gpui::Div> {
let theme = cx.theme();
let surface = theme.colors.surface;
let border = if theme.borders.overlays {
theme.colors.border
} else {
surface
};
let foreground = theme.colors.foreground;
let radius = theme.radius.full;
let shadows = theme.elevations.popover.shadows();
let icon_size = theme.sizes.small.icon_size;
let text_size = theme.sizes.small.text_size;
let toast = &self.toast;
let toasts = toasts.clone();
let id = self.id;
div()
.id(("toast", id))
.max_w(px(480.))
.flex()
.items_center()
.py_1p5()
.px_3()
.bg(surface)
.border_1()
.border_color(border)
.rounded(radius)
.shadow(shadows.clone())
.when_some(toast.icon.clone(), |pill, icon| {
pill.child(
div()
.id(("toast", id))
.role(Role::Alert)
.aria_label(toast.message.clone())
.max_w(TOAST_MAX_WIDTH)
.flex()
.items_center()
.py_1p5()
.px_3()
.bg(surface)
.border_1()
.border_color(border)
.rounded(radius)
.shadow(shadows.clone())
.when_some(toast.icon.clone(), |pill, icon| {
pill.child(
div()
.flex_none()
.mr_2()
.flex()
.items_center()
.child(icon.size(icon_size).color(foreground)),
)
})
.child(
div()
.flex_none()
.mr_2()
.flex()
.items_center()
.child(icon.size(icon_size).color(foreground)),
.min_w(px(0.))
.truncate()
.text_size(text_size)
.text_color(foreground)
.child(toast.message.clone()),
)
})
.child(
div()
.min_w(px(0.))
.truncate()
.text_size(text_size)
.text_color(foreground)
.child(toast.message.clone()),
)
.when_some(toast.action.clone(), |pill, action| {
let toasts = toasts.clone();
pill.child(
div().flex_none().ml_2p5().child(
Button::new(("toast-action", id))
.label(action.label.clone())
.variant(ButtonVariant::Primary)
.when_some(toast.action.clone(), |pill, action| {
let toasts = toasts.clone();
pill.child(
div().flex_none().ml_2p5().child(
Button::new(("toast-action", id))
.label(action.label.clone())
.variant(ButtonVariant::Primary)
.small()
.on_click(move |_, _window, cx| {
(action.handler)(cx);
toasts.update(cx, |toasts, cx| {
toasts.dismiss(id, cx);
});
}),
),
)
})
.child(
div().flex_none().ml_4().child(
Button::new(("toast-close", id))
.icon(IconRole::Close)
.variant(ButtonVariant::Ghost)
.small()
.accessibility_label("Dismiss")
.on_click(move |_, _window, cx| {
(action.handler.clone())(cx);
toasts.update(cx, |toasts, cx| {
toasts.dismiss(id, cx);
});
}),
),
)
})
.child(
div()
.id(("toast-close", id))
.flex_none()
.ml_4()
.cursor_pointer()
.p_1()
.rounded(theme.radius.sm)
.hover(|style| style.bg(muted))
.child(
icon(IconRole::Close)
.size(dense_icon_size)
.color(theme.colors.muted_foreground),
)
.on_click(move |_, _window, cx| {
toasts.update(cx, |toasts, cx| {
toasts.dismiss(id, cx);
});
}),
)
}
}