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

Revert #1573, #1570
This commit is contained in:
Jason Lee 2025-11-13 13:37:05 +08:00 committed by GitHub
parent a19826af2b
commit a176408d81
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 203 additions and 80 deletions

View file

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

View file

@ -409,8 +409,13 @@ pub fn open_new(
}
impl Render for StoryTiles {
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
fn render(&mut self, window: &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()
.font_family(".SystemUIFont")
.relative()
.size_full()
.flex()
@ -419,6 +424,9 @@ impl Render for StoryTiles {
.text_color(cx.theme().foreground)
.child(TitleBar::new().child(div().flex().items_center().child("Story Tiles")))
.child(self.dock_area.clone())
.children(sheet_layer)
.children(dialog_layer)
.children(notification_layer)
}
}

View file

@ -224,7 +224,7 @@ pub fn create_new_window_with_size<F, E>(
let view = crate_view_fn(window, cx);
let root = cx.new(|cx| StoryRoot::new(title.clone(), view, window, cx));
cx.new(|cx| Root::new(root.into(), window, cx).text_base())
cx.new(|cx| Root::new(root.into(), window, cx))
})
.expect("failed to open window");
@ -261,13 +261,22 @@ impl StoryRoot {
}
impl Render for StoryRoot {
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
div().size_full().child(
v_flex()
.size_full()
.child(self.title_bar.clone())
.child(div().flex_1().overflow_hidden().child(self.view.clone())),
)
fn render(&mut self, window: &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()
.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

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

View file

@ -3,12 +3,12 @@ use crate::{
input::InputState,
notification::{Notification, NotificationList},
sheet::Sheet,
window_border, ActiveTheme, Placement, StyledExt, TITLE_BAR_HEIGHT,
window_border, ActiveTheme, Placement,
};
use gpui::{
actions, canvas, div, prelude::FluentBuilder as _, AnyView, App, AppContext, Context,
DefiniteLength, Entity, FocusHandle, InteractiveElement, IntoElement, KeyBinding,
ParentElement as _, Render, StyleRefinement, Styled, Window,
ParentElement as _, Render, Styled, Window,
};
use std::{any::TypeId, rc::Rc};
@ -210,7 +210,6 @@ impl WindowExt for Window {
///
/// It is used to manage the Sheet, Dialog, and Notification.
pub struct Root {
style: StyleRefinement,
/// Used to store the focus handle of the previous view.
/// When the Dialog, Sheet closes, we will focus back to the previous view.
previous_focus_handle: Option<FocusHandle>,
@ -238,7 +237,6 @@ pub(crate) struct ActiveDialog {
impl Root {
pub fn new(view: AnyView, window: &mut Window, cx: &mut Context<Self>) -> Self {
Self {
style: StyleRefinement::default(),
previous_focus_handle: None,
active_sheet: None,
active_dialogs: Vec::new(),
@ -276,64 +274,64 @@ impl Root {
}
// Render Notification layer.
fn render_notification_layer(
&mut self,
_: &mut Window,
_: &mut Context<Self>,
pub fn render_notification_layer(
window: &mut Window,
cx: &mut App,
) -> Option<impl IntoElement> {
let active_sheet_placement = self.active_sheet.clone().map(|d| d.placement);
let root = window.root::<Root>()??;
let active_sheet_placement = root.read(cx).active_sheet.clone().map(|d| d.placement);
let (mt, mr) = match active_sheet_placement {
Some(Placement::Right) => (None, self.sheet_size),
Some(Placement::Top) => (self.sheet_size, None),
Some(Placement::Right) => (None, root.read(cx).sheet_size),
Some(Placement::Top) => (root.read(cx).sheet_size, None),
_ => (None, None),
};
Some(
div()
.absolute()
.top(TITLE_BAR_HEIGHT)
.top_0()
.right_0()
.when_some(mt, |this, offset| this.mt(offset))
.when_some(mr, |this, offset| this.mr(offset))
.child(self.notification.clone()),
.child(root.read(cx).notification.clone()),
)
}
/// Render the Sheet layer.
fn render_sheet_layer(
&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;
pub fn render_sheet_layer(window: &mut Window, cx: &mut App) -> Option<impl IntoElement> {
let root = window.root::<Root>()??;
let size = sheet.size;
if let Some(active_sheet) = root.read(cx).active_sheet.clone() {
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;
Some(
div().relative().child(sheet).child(
canvas(
move |_, _, cx| root.update(cx, |r, _| r.sheet_size = Some(size)),
|_, _, _, _| {},
)
.absolute()
.size_full(),
),
)
let size = sheet.size;
return Some(
div().relative().child(sheet).child(
canvas(
move |_, _, cx| root.update(cx, |r, _| r.sheet_size = Some(size)),
|_, _, _, _| {},
)
.absolute()
.size_full(),
),
);
}
None
}
/// Render the Dialog layer.
fn render_dialog_layer(
&mut self,
window: &mut Window,
cx: &mut Context<Self>,
) -> Option<impl IntoElement> {
let active_dialogs = self.active_dialogs.clone();
pub fn render_dialog_layer(window: &mut Window, cx: &mut App) -> Option<impl IntoElement> {
let root = window.root::<Root>()??;
let active_dialogs = root.read(cx).active_dialogs.clone();
if active_dialogs.is_empty() {
return None;
}
@ -387,12 +385,6 @@ impl Root {
}
}
impl Styled for Root {
fn style(&mut self) -> &mut StyleRefinement {
&mut self.style
}
}
impl Render for Root {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let base_font_size = cx.theme().font_size;
@ -404,16 +396,12 @@ impl Render for Root {
.key_context(CONTEXT)
.on_action(cx.listener(Self::on_action_tab))
.on_action(cx.listener(Self::on_action_tab_prev))
.font_family(".SystemUIFont")
.refine_style(&self.style)
.bg(cx.theme().background)
.text_color(cx.theme().foreground)
.relative()
.size_full()
.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)),
.font_family(".SystemUIFont")
.bg(cx.theme().background)
.text_color(cx.theme().foreground)
.child(self.view.clone()),
)
}
}

View file

@ -16,6 +16,37 @@ use gpui_component::WindowExt;
## 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
```rust

View file

@ -16,6 +16,38 @@ use gpui_component::WindowExt;
## 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
```rust

View file

@ -10,11 +10,43 @@ A Sheet (also known as a sidebar or slide-out panel) is a navigation component t
## Import
```rust
use gpui_component::{WindowExt, Placement};
use gpui_component::WindowExt;
use gpui_component::Placement;
```
## 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
```rust

View file

@ -30,19 +30,33 @@ fn main() {
}
```
## Setup base styles
## Overlays
You can setup window level base styles by using `Styled` fluent method on [Root], then all child views will inherit these styles.
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
Root::new(view.into(), window, cx)
// This default is `.SystemUIFont` it will use system UI font.
.font_family("Your Special Font")
.text_sm()
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
```
```

View file

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

View file

@ -79,7 +79,7 @@ fn main() {
cx.open_window(window_options, |window, cx| {
let view = cx.new(|_| Example);
cx.new(|cx| Root::new(view.into(), window, cx).text_sm())
cx.new(|cx| Root::new(view.into(), window, cx))
})?;
Ok::<_, anyhow::Error>(())