root: Render overlays inside Root element by default. (#1570)

## Break Change

- The `Root::render_notification_layer`, `Root::render_sheet_layer`,
`Root::render_dialog_layer` has been removed, we don't need it now, the
Root element has default rendered them.
This commit is contained in:
Jason Lee 2025-11-12 16:04:54 +08:00 committed by GitHub
parent f88b547b70
commit f26f01909e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 55 additions and 201 deletions

View file

@ -505,11 +505,7 @@ pub fn open_new(
} }
impl Render for StoryWorkspace { impl Render for StoryWorkspace {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let sheet_layer = Root::render_sheet_layer(window, cx);
let dialog_layer = Root::render_dialog_layer(window, cx);
let notification_layer = Root::render_notification_layer(window, cx);
div() div()
.id("story-workspace") .id("story-workspace")
.on_action(cx.listener(Self::on_action_add_panel)) .on_action(cx.listener(Self::on_action_add_panel))
@ -521,9 +517,6 @@ impl Render for StoryWorkspace {
.flex_col() .flex_col()
.child(self.title_bar.clone()) .child(self.title_bar.clone())
.child(self.dock_area.clone()) .child(self.dock_area.clone())
.children(sheet_layer)
.children(dialog_layer)
.children(notification_layer)
} }
} }

View file

@ -409,11 +409,7 @@ pub fn open_new(
} }
impl Render for StoryTiles { impl Render for StoryTiles {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let sheet_layer = Root::render_sheet_layer(window, cx);
let dialog_layer = Root::render_dialog_layer(window, cx);
let notification_layer = Root::render_notification_layer(window, cx);
div() div()
.font_family(".SystemUIFont") .font_family(".SystemUIFont")
.relative() .relative()
@ -424,9 +420,6 @@ impl Render for StoryTiles {
.text_color(cx.theme().foreground) .text_color(cx.theme().foreground)
.child(TitleBar::new().child(div().flex().items_center().child("Story Tiles"))) .child(TitleBar::new().child(div().flex().items_center().child("Story Tiles")))
.child(self.dock_area.clone()) .child(self.dock_area.clone())
.children(sheet_layer)
.children(dialog_layer)
.children(notification_layer)
} }
} }

View file

@ -261,22 +261,13 @@ impl StoryRoot {
} }
impl Render for StoryRoot { impl Render for StoryRoot {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
let sheet_layer = Root::render_sheet_layer(window, cx); div().size_full().child(
let dialog_layer = Root::render_dialog_layer(window, cx); v_flex()
let notification_layer = Root::render_notification_layer(window, cx); .size_full()
.child(self.title_bar.clone())
div() .child(div().flex_1().overflow_hidden().child(self.view.clone())),
.size_full() )
.child(
v_flex()
.size_full()
.child(self.title_bar.clone())
.child(div().flex_1().overflow_hidden().child(self.view.clone())),
)
.children(sheet_layer)
.children(dialog_layer)
.children(notification_layer)
} }
} }

View file

@ -318,8 +318,8 @@ impl Render for Notification {
.child( .child(
h_flex() h_flex()
.absolute() .absolute()
.top_3p5() .top_1p5()
.right_3p5() .right_1p5()
.invisible() .invisible()
.group_hover("", |this| this.visible()) .group_hover("", |this| this.visible())
.child( .child(

View file

@ -3,7 +3,7 @@ use crate::{
input::InputState, input::InputState,
notification::{Notification, NotificationList}, notification::{Notification, NotificationList},
sheet::Sheet, sheet::Sheet,
window_border, ActiveTheme, Placement, window_border, ActiveTheme, Placement, TITLE_BAR_HEIGHT,
}; };
use gpui::{ use gpui::{
actions, canvas, div, prelude::FluentBuilder as _, AnyView, App, AppContext, Context, actions, canvas, div, prelude::FluentBuilder as _, AnyView, App, AppContext, Context,
@ -274,64 +274,64 @@ impl Root {
} }
// Render Notification layer. // Render Notification layer.
pub fn render_notification_layer( fn render_notification_layer(
window: &mut Window, &mut self,
cx: &mut App, _: &mut Window,
_: &mut Context<Self>,
) -> Option<impl IntoElement> { ) -> Option<impl IntoElement> {
let root = window.root::<Root>()??; let active_sheet_placement = self.active_sheet.clone().map(|d| d.placement);
let active_sheet_placement = root.read(cx).active_sheet.clone().map(|d| d.placement);
let (mt, mr) = match active_sheet_placement { let (mt, mr) = match active_sheet_placement {
Some(Placement::Right) => (None, root.read(cx).sheet_size), Some(Placement::Right) => (None, self.sheet_size),
Some(Placement::Top) => (root.read(cx).sheet_size, None), Some(Placement::Top) => (self.sheet_size, None),
_ => (None, None), _ => (None, None),
}; };
Some( Some(
div() div()
.absolute() .absolute()
.top_0() .top(TITLE_BAR_HEIGHT)
.right_0() .right_0()
.when_some(mt, |this, offset| this.mt(offset)) .when_some(mt, |this, offset| this.mt(offset))
.when_some(mr, |this, offset| this.mr(offset)) .when_some(mr, |this, offset| this.mr(offset))
.child(root.read(cx).notification.clone()), .child(self.notification.clone()),
) )
} }
/// Render the Sheet layer. /// Render the Sheet layer.
pub fn render_sheet_layer(window: &mut Window, cx: &mut App) -> Option<impl IntoElement> { fn render_sheet_layer(
let root = window.root::<Root>()??; &mut self,
window: &mut Window,
cx: &mut Context<Self>,
) -> Option<impl IntoElement> {
let active_sheet = self.active_sheet.clone()?;
let root = cx.entity();
let mut sheet = Sheet::new(window, cx);
sheet = (active_sheet.builder)(sheet, window, cx);
sheet.focus_handle = active_sheet.focus_handle.clone();
sheet.placement = active_sheet.placement;
if let Some(active_sheet) = root.read(cx).active_sheet.clone() { let size = sheet.size;
let mut sheet = Sheet::new(window, cx);
sheet = (active_sheet.builder)(sheet, window, cx);
sheet.focus_handle = active_sheet.focus_handle.clone();
sheet.placement = active_sheet.placement;
let size = sheet.size; Some(
div().relative().child(sheet).child(
return Some( canvas(
div().relative().child(sheet).child( move |_, _, cx| root.update(cx, |r, _| r.sheet_size = Some(size)),
canvas( |_, _, _, _| {},
move |_, _, cx| root.update(cx, |r, _| r.sheet_size = Some(size)), )
|_, _, _, _| {}, .absolute()
) .size_full(),
.absolute() ),
.size_full(), )
),
);
}
None
} }
/// Render the Dialog layer. /// Render the Dialog layer.
pub fn render_dialog_layer(window: &mut Window, cx: &mut App) -> Option<impl IntoElement> { fn render_dialog_layer(
let root = window.root::<Root>()??; &mut self,
window: &mut Window,
let active_dialogs = root.read(cx).active_dialogs.clone(); cx: &mut Context<Self>,
) -> Option<impl IntoElement> {
let active_dialogs = self.active_dialogs.clone();
if active_dialogs.is_empty() { if active_dialogs.is_empty() {
return None; return None;
} }
@ -401,7 +401,10 @@ impl Render for Root {
.font_family(".SystemUIFont") .font_family(".SystemUIFont")
.bg(cx.theme().background) .bg(cx.theme().background)
.text_color(cx.theme().foreground) .text_color(cx.theme().foreground)
.child(self.view.clone()), .child(self.view.clone())
.children(self.render_sheet_layer(window, cx))
.children(self.render_dialog_layer(window, cx))
.children(self.render_notification_layer(window, cx)),
) )
} }
} }

View file

@ -16,37 +16,6 @@ use gpui_component::WindowExt;
## Usage ## Usage
### Setup application root view for display of dialogs
You need to set up your application's root view to render the dialog layer. This is typically done in your main application struct's render method.
The [Root::render_dialog_layer](https://docs.rs/gpui-component/latest/gpui_component/struct.Root.html#method.render_dialog_layer) function handles rendering any active dialogs on top of your app content.
```rust
use gpui_component::TitleBar;
struct MyApp {
view: AnyView,
}
impl Render for MyApp {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let dialog_layer = Root::render_dialog_layer(window, cx);
div()
.size_full()
.child(
v_flex()
.size_full()
.child(TitleBar::new())
.child(div().flex_1().overflow_hidden().child(self.view.clone())),
)
// Render the dialog layer on top of the app content
.children(dialog_layer)
}
}
```
### Basic Dialog ### Basic Dialog
```rust ```rust

View file

@ -16,38 +16,6 @@ use gpui_component::WindowExt;
## Usage ## Usage
### Setup application root view for display of notifications
You need to set up your application's root view to render the notification layer. This is typically done in your main application struct's render method.
The [Root::render_notification_layer](https://docs.rs/gpui-component/latest/gpui_component/struct.Root.html#method.render_notification_layer) function handles rendering any active modals on top of your app content.
```rust
use gpui_component::TitleBar;
struct MyApp {
view: AnyView,
}
impl Render for MyApp {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let notification_layer = Root::render_notification_layer(window, cx);
div()
.size_full()
.child(
v_flex()
.size_full()
.child(TitleBar::new())
.child(div().flex_1().overflow_hidden().child(self.view.clone())),
)
// Render the notification layer on top of the app content
.children(notification_layer)
}
}
```
### Basic Notification ### Basic Notification
```rust ```rust

View file

@ -10,43 +10,11 @@ A Sheet (also known as a sidebar or slide-out panel) is a navigation component t
## Import ## Import
```rust ```rust
use gpui_component::WindowExt; use gpui_component::{WindowExt, Placement};
use gpui_component::Placement;
``` ```
## Usage ## Usage
### Setup application root view for display of sheets
You need to set up your application's root view to render the sheet layer. This is typically done in your main application struct's render method.
The [Root::render_sheet_layer](https://docs.rs/gpui-component/latest/gpui_component/struct.Root.html#method.render_sheet_layer) function handles rendering any active modals on top of your app content.
```rust
use gpui_component::TitleBar;
struct MyApp {
view: AnyView,
}
impl Render for MyApp {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let sheet_layer = Root::render_sheet_layer(window, cx);
div()
.size_full()
.child(
v_flex()
.size_full()
.child(TitleBar::new())
.child(div().flex_1().overflow_hidden().child(self.view.clone())),
)
// Render the sheet layer on top of the app content
.children(sheet_layer)
}
}
```
### Basic Sheet ### Basic Sheet
```rust ```rust

View file

@ -30,33 +30,4 @@ fn main() {
} }
``` ```
## Overlays
We have dialogs, sheets, notifications, we need placement for them to show, so [Root] provides methods to render these overlays:
- [Root::render_dialog_layer](https://docs.rs/gpui-component/latest/gpui_component/struct.Root.html#method.render_dialog_layer) - Render the current opened modals.
- [Root::render_sheet_layer](https://docs.rs/gpui-component/latest/gpui_component/struct.Root.html#method.render_sheet_layer) - Render the current opened drawers.
- [Root::render_notification_layer](https://docs.rs/gpui-component/latest/gpui_component/struct.Root.html#method.render_notification_layer) - Render the notification list.
We can put these layers in the `render` method your first level view (Root > YourFirstView):
```rs
struct MyApp;
impl Render for MyApp {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
div()
.size_full()
.child("My App Content")
.children(Root::render_dialog_layer(cx))
.children(Root::render_sheet_layer(cx))
.children(Root::render_notification_layer(cx))
}
}
```
:::tip
Here the example we used `children` method, it because if there is no opened dialogs, sheets, notifications, these methods will return `None`, so GPUI will not render anything.
:::
[Root]: https://docs.rs/gpui-component/latest/gpui_component/root/struct.Root.html [Root]: https://docs.rs/gpui-component/latest/gpui_component/root/struct.Root.html

View file

@ -20,7 +20,7 @@ impl HelloWorld {
} }
impl Render for HelloWorld { impl Render for HelloWorld {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
div() div()
.bg(gpui::white()) .bg(gpui::white())
.size_full() .size_full()
@ -72,8 +72,6 @@ impl Render for HelloWorld {
}), }),
), ),
) )
.children(Root::render_dialog_layer(window, cx))
.children(Root::render_sheet_layer(window, cx))
} }
} }