T09b overlays: lightbox, spotlight and tour, floating toolbar, peek; images fill their box; overlays take focus back when its element leaves the tree

This commit is contained in:
ZacharyZhang-NY committed 2026-09-25 15:19:57 -04:00
1 parent ca73d24c01
commit ef74bac823
18 files changed
+1754 -228

No files matched your search

+18 -5
View File
@@ -1,6 +1,6 @@
use gpui::{
AnyElement, App, Div, ElementId, Entity, FocusHandle, InteractiveElement, IntoElement,
ParentElement, RenderOnce, StyleRefinement, Styled, Window, actions, div,
ParentElement, RenderOnce, StyleRefinement, Styled, Subscription, Window, actions, div,
};
use crate::theme::ActiveTheme;
@@ -100,18 +100,27 @@ pub(crate) struct Takeover {
pub focus: FocusHandle,
previous: Option<FocusHandle>,
taken: bool,
returned: bool,
_lost: Subscription,
}
/// Keyed focus for an overlay; focused on its first render.
/// Keyed focus for an overlay; focused on its first render, and again whenever the focused element leaves the tree.
pub(crate) fn take_focus(
key: impl Into<gpui::ElementId>,
window: &mut Window,
cx: &mut App,
) -> Entity<Takeover> {
let state = window.use_keyed_state(key, cx, |_, cx| Takeover {
let state = window.use_keyed_state(key, cx, |window, cx| Takeover {
focus: cx.focus_handle(),
previous: None,
taken: false,
returned: false,
_lost: cx.on_focus_lost(window, |takeover: &mut Takeover, window, _| {
if !takeover.returned {
log::info!("focus: its element left the tree; the overlay takes it back");
window.focus(&takeover.focus);
}
}),
});
if !state.read(cx).taken {
let previous = window.focused(cx);
@@ -125,8 +134,12 @@ pub(crate) fn take_focus(
}
/// Returns focus to whatever held it before the overlay opened.
pub(crate) fn give_back(state: &Entity<Takeover>, window: &mut Window, cx: &App) {
match state.read(cx).previous.clone() {
pub(crate) fn give_back(state: &Entity<Takeover>, window: &mut Window, cx: &mut App) {
let previous = state.update(cx, |takeover, _| {
takeover.returned = true;
takeover.previous.clone()
});
match previous {
Some(previous) => {
window.focus(&previous);
log::info!("focus: handed back after an overlay");
+4 -2
View File
@@ -13,7 +13,7 @@ use crate::{
const PULSE: Duration = Duration::from_millis(1600);
/// Themed `img()`; a `Cover` crop keeps square corners.
/// Themed `img()` that fills the box it is given; a `Cover` crop keeps square corners.
#[derive(IntoElement)]
pub struct Image {
id: ElementId,
@@ -82,6 +82,8 @@ impl RenderOnce for Image {
};
let mut picture = img(source)
.id(self.id)
.absolute()
.inset_0()
.size_full()
.object_fit(self.fit)
.with_loading(move || {
@@ -100,6 +102,6 @@ impl RenderOnce for Image {
})
.with_fallback(move || mark(IconName::ImageOff).into_any_element());
picture.style().corner_radii = radii;
self.base.overflow_hidden().child(picture)
self.base.relative().overflow_hidden().child(picture)
}
}