Components / overlay
BottomSheet view
A retained bottom Drawer with explicit detents and cancellable drag preview.
A view survives a frame. Hold it in an Entity with cx.new(..) and reach it with .update(..).
use gpui_kit::overlay::BottomSheet;
Reviewed in bottom-sheet.
Construct
new(ident: impl Into<Ident>, window: &mut Window, cx: &mut Context<Self>) -> Self
Commands
Need a Context, so they need a view.
set_detents(detents: Vec<SheetDetent>, selected: impl Into<SharedString>, cx: &mut Context<Self>) -> bool
set_detent(id: impl Into<SharedString>, cx: &mut Context<Self>) -> bool
set_title(title: impl Into<SharedString>, cx: &mut Context<Self>)
set_content(content: Option<Body>, cx: &mut Context<Self>)
set_scroll_handle(scroll: Option<ScrollHandle>, cx: &mut Context<Self>)
set_focus_stops(stops: impl IntoIterator<Item = FocusHandle>, cx: &mut Context<Self>)
set_dismissable(dismissable: bool, cx: &mut Context<Self>)
open(window: &mut Window, cx: &mut Context<Self>)
close(window: &mut Window, cx: &mut Context<Self>)
settle(cx: &mut Context<Self>)
Queries
Only answer; they change nothing.
selected_detent() -> &SharedString
is_open(cx: &App) -> bool
Reports
The variants of the event it emits. It never applies the change itself.
- Opened
- Dismissed
- Closed
- DetentRequested
Example · bottom-sheet
fn bottom_sheet(window: &mut Window, cx: &mut App) -> AnyElement {
use crate::overlay::sheet::{BottomSheet, BottomSheetEvent, SheetDetent};
if !cx.has_global::<SceneBottomSheet>() {
let sheet = cx.new(|cx| BottomSheet::new("scene.bottom-sheet", window, cx));
sheet.update(cx, |sheet, cx| {
sheet.set_title("Choose destination · fixture", cx);
sheet.set_detents(
vec![
SheetDetent::new("Compact", 290.0),
SheetDetent::new("Half", 430.0),
SheetDetent::new("Full", 640.0),
],
"Half",
cx,
);
let scroll = gpui::ScrollHandle::new();
sheet.set_scroll_handle(Some(scroll.clone()), cx);
sheet.set_content(
Some(Rc::new(move |_, cx| {
let _theme = cx.theme().clone();
div()
.id("scene.bottom-sheet.list")
.column()
.size_full()
.overflow_y_scroll()
.track_scroll(&scroll)
.children(
[
("home", "Home"),
("work", "Work"),
("library", "Library"),
("airport", "Airport"),
("station", "Station"),
("garden", "Garden"),
("museum", "Museum"),
]
.into_iter()
.map(|(id, label)| {
Button::new(format!("scene.bottom-sheet.destination.{id}"))
.label(label)
.secondary()
.control_size(gpui_kit_theme::ControlSize::Touch)
.on_click(|_, _| {})
}),
)
.into_any_element()
})),
cx,
);
sheet.open(window, cx);
sheet.settle(cx);
});
cx.subscribe(&sheet, |sheet, event, cx| {
if let BottomSheetEvent::DetentRequested(id) = event {
sheet.update(cx, |sheet, cx| {
sheet.set_detent(id.clone(), cx);
});
}
})
.detach();
cx.set_global(SceneBottomSheet(sheet));
}
let theme = cx.theme().clone();
stack(&theme)
.w_full()
.h(px(640.0))
.child(page_behind(&theme, "Caller-owned destinations"))
.child(cx.global::<SceneBottomSheet>().0.clone())
.into_any_element()
}