story: Use uniform_list for scroll example. (#1709)
Ref #1621 Update scrollable story to use `UniformList` to avoid performance issue in story. And also renamed it to `ScrollbarStory`.
This commit is contained in:
parent
a792719dbe
commit
4e0f9af789
6 changed files with 72 additions and 38 deletions
|
|
@ -11,7 +11,7 @@ use gpui_component_assets::Assets;
|
|||
use gpui_component_story::{
|
||||
AccordionStory, AppState, AppTitleBar, ButtonStory, CalendarStory, DialogStory, FormStory,
|
||||
IconStory, ImageStory, InputStory, LabelStory, ListStory, NotificationStory, Open,
|
||||
PopoverStory, ProgressStory, ResizableStory, ScrollableStory, SelectStory, SidebarStory,
|
||||
PopoverStory, ProgressStory, ResizableStory, ScrollbarStory, SelectStory, SidebarStory,
|
||||
StoryContainer, SwitchStory, TableStory, TooltipStory, WebViewStory,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
|
|
@ -269,7 +269,7 @@ impl StoryWorkspace {
|
|||
),
|
||||
DockItem::tabs(
|
||||
vec![
|
||||
Arc::new(StoryContainer::panel::<ScrollableStory>(window, cx)),
|
||||
Arc::new(StoryContainer::panel::<ScrollbarStory>(window, cx)),
|
||||
Arc::new(StoryContainer::panel::<AccordionStory>(window, cx)),
|
||||
],
|
||||
None,
|
||||
|
|
@ -358,7 +358,7 @@ impl StoryWorkspace {
|
|||
Arc::new(StoryContainer::panel::<TooltipStory>(window, cx)),
|
||||
Arc::new(StoryContainer::panel::<CalendarStory>(window, cx)),
|
||||
Arc::new(StoryContainer::panel::<ResizableStory>(window, cx)),
|
||||
Arc::new(StoryContainer::panel::<ScrollableStory>(window, cx)),
|
||||
Arc::new(StoryContainer::panel::<ScrollbarStory>(window, cx)),
|
||||
Arc::new(StoryContainer::panel::<AccordionStory>(window, cx)),
|
||||
Arc::new(StoryContainer::panel::<SidebarStory>(window, cx)),
|
||||
Arc::new(StoryContainer::panel::<FormStory>(window, cx)),
|
||||
|
|
@ -447,7 +447,7 @@ impl StoryWorkspace {
|
|||
12 => Arc::new(StoryContainer::panel::<ProgressStory>(window, cx)),
|
||||
13 => Arc::new(StoryContainer::panel::<CalendarStory>(window, cx)),
|
||||
14 => Arc::new(StoryContainer::panel::<ResizableStory>(window, cx)),
|
||||
15 => Arc::new(StoryContainer::panel::<ScrollableStory>(window, cx)),
|
||||
15 => Arc::new(StoryContainer::panel::<ScrollbarStory>(window, cx)),
|
||||
16 => Arc::new(StoryContainer::panel::<AccordionStory>(window, cx)),
|
||||
17 => Arc::new(StoryContainer::panel::<WebViewStory>(window, cx)),
|
||||
_ => Arc::new(StoryContainer::panel::<ButtonStory>(window, cx)),
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ mod popover_story;
|
|||
mod progress_story;
|
||||
mod radio_story;
|
||||
mod resizable_story;
|
||||
mod scrollable_story;
|
||||
mod scrollbar_story;
|
||||
mod select_story;
|
||||
mod settings_story;
|
||||
mod sheet_story;
|
||||
|
|
@ -90,7 +90,7 @@ pub use popover_story::PopoverStory;
|
|||
pub use progress_story::ProgressStory;
|
||||
pub use radio_story::RadioStory;
|
||||
pub use resizable_story::ResizableStory;
|
||||
pub use scrollable_story::ScrollableStory;
|
||||
pub use scrollbar_story::ScrollbarStory;
|
||||
pub use select_story::SelectStory;
|
||||
use serde::{Deserialize, Serialize};
|
||||
pub use settings_story::SettingsStory;
|
||||
|
|
@ -670,7 +670,7 @@ impl StoryState {
|
|||
"PopoverStory" => story!(PopoverStory),
|
||||
"ProgressStory" => story!(ProgressStory),
|
||||
"ResizableStory" => story!(ResizableStory),
|
||||
"ScrollableStory" => story!(ScrollableStory),
|
||||
"ScrollbarStory" => story!(ScrollbarStory),
|
||||
"SwitchStory" => story!(SwitchStory),
|
||||
"TableStory" => story!(TableStory),
|
||||
"LabelStory" => story!(LabelStory),
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ impl Gallery {
|
|||
StoryContainer::panel::<ProgressStory>(window, cx),
|
||||
StoryContainer::panel::<RadioStory>(window, cx),
|
||||
StoryContainer::panel::<ResizableStory>(window, cx),
|
||||
StoryContainer::panel::<ScrollableStory>(window, cx),
|
||||
StoryContainer::panel::<ScrollbarStory>(window, cx),
|
||||
StoryContainer::panel::<SelectStory>(window, cx),
|
||||
StoryContainer::panel::<SettingsStory>(window, cx),
|
||||
StoryContainer::panel::<SheetStory>(window, cx),
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::rc::Rc;
|
|||
|
||||
use gpui::{
|
||||
App, AppContext, Context, Entity, FocusHandle, Focusable, IntoElement, ParentElement, Pixels,
|
||||
Render, Size, Styled, Window, div, px, size,
|
||||
Render, Size, Styled, UniformListScrollHandle, Window, div, px, size, uniform_list,
|
||||
};
|
||||
use gpui_component::{
|
||||
ActiveTheme as _, Selectable,
|
||||
|
|
@ -12,17 +12,18 @@ use gpui_component::{
|
|||
v_flex,
|
||||
};
|
||||
|
||||
pub struct ScrollableStory {
|
||||
pub struct ScrollbarStory {
|
||||
focus_handle: FocusHandle,
|
||||
items: Vec<String>,
|
||||
item_sizes: Rc<Vec<Size<Pixels>>>,
|
||||
test_width: Pixels,
|
||||
size_mode: usize,
|
||||
scroll_handle: UniformListScrollHandle,
|
||||
}
|
||||
|
||||
const ITEM_HEIGHT: Pixels = px(30.);
|
||||
const ITEM_HEIGHT: Pixels = px(50.);
|
||||
|
||||
impl ScrollableStory {
|
||||
impl ScrollbarStory {
|
||||
fn new(_: &mut Window, cx: &mut Context<Self>) -> Self {
|
||||
let items = (0..5000).map(|i| format!("Item {}", i)).collect::<Vec<_>>();
|
||||
let test_width = px(3000.);
|
||||
|
|
@ -37,6 +38,7 @@ impl ScrollableStory {
|
|||
item_sizes: Rc::new(item_sizes),
|
||||
test_width,
|
||||
size_mode: 0,
|
||||
scroll_handle: UniformListScrollHandle::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -113,13 +115,13 @@ impl ScrollableStory {
|
|||
}
|
||||
}
|
||||
|
||||
impl super::Story for ScrollableStory {
|
||||
impl super::Story for ScrollbarStory {
|
||||
fn title() -> &'static str {
|
||||
"Scrollable"
|
||||
"Scrollbar"
|
||||
}
|
||||
|
||||
fn description() -> &'static str {
|
||||
"A scrollable container."
|
||||
"Add scrollbar to a scrollable element."
|
||||
}
|
||||
|
||||
fn new_view(window: &mut Window, cx: &mut App) -> Entity<impl Render> {
|
||||
|
|
@ -127,19 +129,18 @@ impl super::Story for ScrollableStory {
|
|||
}
|
||||
}
|
||||
|
||||
impl Focusable for ScrollableStory {
|
||||
impl Focusable for ScrollbarStory {
|
||||
fn focus_handle(&self, _: &gpui::App) -> gpui::FocusHandle {
|
||||
self.focus_handle.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for ScrollableStory {
|
||||
impl Render for ScrollbarStory {
|
||||
fn render(
|
||||
&mut self,
|
||||
_: &mut gpui::Window,
|
||||
cx: &mut gpui::Context<Self>,
|
||||
) -> impl gpui::IntoElement {
|
||||
let test_width = self.test_width;
|
||||
v_flex()
|
||||
.size_full()
|
||||
.gap_4()
|
||||
|
|
@ -149,26 +150,38 @@ impl Render for ScrollableStory {
|
|||
.relative()
|
||||
.border_1()
|
||||
.border_color(cx.theme().border)
|
||||
.w_full()
|
||||
.max_h(px(400.))
|
||||
.min_h(px(200.))
|
||||
.flex_1()
|
||||
.child(
|
||||
v_flex()
|
||||
.w(test_width)
|
||||
.p_3()
|
||||
.gap_1()
|
||||
.overflow_y_scrollbar()
|
||||
.child("Scrollable Example")
|
||||
.children(self.items.iter().map(|item| {
|
||||
div()
|
||||
.h(ITEM_HEIGHT)
|
||||
.bg(cx.theme().background)
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.text_sm()
|
||||
.child(item.to_string())
|
||||
})),
|
||||
uniform_list("list", self.items.len(), {
|
||||
let items = self.items.clone();
|
||||
move |visible_range, _, cx| {
|
||||
let mut elements = Vec::with_capacity(visible_range.len());
|
||||
for ix in visible_range {
|
||||
let item = &items[ix];
|
||||
elements.push(
|
||||
div()
|
||||
.h(ITEM_HEIGHT)
|
||||
.pt_1()
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.text_sm()
|
||||
.child(
|
||||
div()
|
||||
.p_2()
|
||||
.bg(cx.theme().secondary)
|
||||
.child(item.to_string()),
|
||||
),
|
||||
);
|
||||
}
|
||||
elements
|
||||
}
|
||||
})
|
||||
.py_1()
|
||||
.px_3()
|
||||
.size_full()
|
||||
.track_scroll(self.scroll_handle.clone()),
|
||||
)
|
||||
.vertical_scrollbar(&self.scroll_handle)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -187,6 +187,7 @@ struct StockTableDelegate {
|
|||
columns: Vec<Column>,
|
||||
size: Size,
|
||||
loading: bool,
|
||||
lazy_load: bool,
|
||||
full_loading: bool,
|
||||
eof: bool,
|
||||
visible_rows: Range<usize>,
|
||||
|
|
@ -200,6 +201,7 @@ impl StockTableDelegate {
|
|||
Self {
|
||||
size: Size::default(),
|
||||
stocks: random_stocks(size),
|
||||
lazy_load: false,
|
||||
columns: vec![
|
||||
Column::new("id", "ID")
|
||||
.width(60.)
|
||||
|
|
@ -543,6 +545,10 @@ impl TableDelegate for StockTableDelegate {
|
|||
}
|
||||
|
||||
fn is_eof(&self, _: &App) -> bool {
|
||||
if !self.lazy_load {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !self.loading && !self.eof;
|
||||
}
|
||||
|
||||
|
|
@ -551,6 +557,10 @@ impl TableDelegate for StockTableDelegate {
|
|||
}
|
||||
|
||||
fn load_more(&mut self, _: &mut Window, cx: &mut Context<TableState<Self>>) {
|
||||
if !self.lazy_load {
|
||||
return;
|
||||
}
|
||||
|
||||
self.loading = true;
|
||||
|
||||
self._load_task = cx.spawn(async move |view, cx| {
|
||||
|
|
@ -959,7 +969,18 @@ impl Render for TableStory {
|
|||
this.child(
|
||||
h_flex().gap_1().child(Spinner::new()).child("Loading..."),
|
||||
)
|
||||
}),
|
||||
})
|
||||
.child(
|
||||
Checkbox::new("lazy-load")
|
||||
.label("Lazy Load")
|
||||
.checked(delegate.lazy_load)
|
||||
.on_click(cx.listener(|this, check: &bool, _, cx| {
|
||||
this.table.update(cx, |table, cx| {
|
||||
table.delegate_mut().lazy_load = *check;
|
||||
cx.notify();
|
||||
})
|
||||
})),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
h_flex()
|
||||
|
|
|
|||
2
crates/ui/tests/fixtures/layout.json
vendored
2
crates/ui/tests/fixtures/layout.json
vendored
|
|
@ -136,7 +136,7 @@
|
|||
"children": [],
|
||||
"info": {
|
||||
"panel": {
|
||||
"story_klass": "ScrollableStory"
|
||||
"story_klass": "ScrollbarStory"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue