GPUI Box GitHub

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()
}

Source: crates/gpui-kit/src/overlay/sheet.rs