WIP: Work toward eliminating Component trait

This refactor enhances the overall design by promoting reusable and composable UI component structures within the Zed project codebase.
This commit is contained in:
Nathan Sobo 2023-11-18 00:03:23 -07:00
parent 2515bbf990
commit 23ffce9fbe
46 changed files with 192 additions and 90 deletions

View file

@ -21,7 +21,7 @@ impl Avatar {
self
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
let mut img = img();
if self.shape == Shape::Circle {

View file

@ -164,7 +164,7 @@ impl<V: 'static> Button<V> {
self.icon.map(|i| IconElement::new(i).color(icon_color))
}
pub fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
pub fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
let (icon_color, label_color) = match (self.disabled, self.color) {
(true, _) => (TextColor::Disabled, TextColor::Disabled),
(_, None) => (TextColor::Default, TextColor::Default),
@ -222,7 +222,7 @@ impl<V: 'static> ButtonGroup<V> {
Self { buttons }
}
fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
let mut el = h_stack().text_ui();
for button in self.buttons {

View file

@ -1,4 +1,4 @@
use gpui::{div, prelude::*, Component, ElementId, Styled, ViewContext};
use gpui::{div, prelude::*, Component, Element, ElementId, Styled, ViewContext};
use std::sync::Arc;
use theme2::ActiveTheme;
@ -42,7 +42,7 @@ impl<V: 'static> Checkbox<V> {
self
}
pub fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
pub fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
let group_id = format!("checkbox_group_{:?}", self.id);
let icon = match self.checked {

View file

@ -27,7 +27,7 @@ impl<V: 'static> Details<V> {
self
}
fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
v_stack()
.p_1()
.gap_0p5()

View file

@ -31,7 +31,7 @@ impl Divider {
self
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
div()
.map(|this| match self.direction {
DividerDirection::Horizontal => {

View file

@ -13,7 +13,7 @@ impl Facepile {
}
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
let player_count = self.players.len();
let player_list = self.players.iter().enumerate().map(|(ix, player)| {
let isnt_last = ix < player_count - 1;

View file

@ -163,7 +163,7 @@ impl IconElement {
self
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
let svg_size = match self.size {
IconSize::Small => rems(0.75),
IconSize::Medium => rems(0.9375),

View file

@ -80,7 +80,7 @@ impl<V: 'static> IconButton<V> {
self.on_click(move |this, cx| cx.dispatch_action(action.boxed_clone()))
}
fn render(mut self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
fn render(mut self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
let icon_color = match (self.state, self.color) {
(InteractionState::Disabled, _) => TextColor::Disabled,
(InteractionState::Active, _) => TextColor::Selected,

View file

@ -10,7 +10,7 @@ impl UnreadIndicator {
Self
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
div()
.rounded_full()
.border_2()

View file

@ -55,7 +55,7 @@ impl Input {
self
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
let (input_bg, input_hover_bg, input_active_bg) = match self.variant {
InputVariant::Ghost => (
cx.theme().colors().ghost_element_background,

View file

@ -24,7 +24,7 @@ impl KeyBinding {
Self { key_binding }
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
div()
.flex()
.gap_2()
@ -52,7 +52,7 @@ impl Key {
Self { key: key.into() }
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
div()
.px_2()
.py_0()

View file

@ -100,7 +100,7 @@ impl Label {
self
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
div()
.when(self.strikethrough, |this| {
this.relative().child(
@ -161,7 +161,7 @@ impl HighlightedLabel {
self
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
let highlight_color = cx.theme().colors().text_accent;
let mut text_style = cx.text_style().clone();

View file

@ -57,7 +57,7 @@ impl ListHeader {
self
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
let disclosure_control = disclosure_control(self.toggle);
let meta = match self.meta {
@ -138,7 +138,7 @@ impl ListSubHeader {
self
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
h_stack().flex_1().w_full().relative().py_1().child(
div()
.h_6()
@ -198,7 +198,7 @@ impl From<ListSubHeader> for ListItem {
}
impl ListItem {
fn render<V: 'static>(self, view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
fn render<V: 'static>(self, view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
match self {
ListItem::Entry(entry) => div().child(entry.render(view, cx)),
ListItem::Separator(separator) => div().child(separator.render(view, cx)),
@ -307,7 +307,7 @@ impl ListEntry {
self
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
let settings = user_settings(cx);
let left_content = match self.left_slot.clone() {
@ -385,7 +385,7 @@ impl ListSeparator {
Self
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
div().h_px().w_full().bg(cx.theme().colors().border_variant)
}
}
@ -425,7 +425,7 @@ impl List {
self
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
let list_content = match (self.items.is_empty(), self.toggle) {
(false, _) => div().children(self.items),
(true, Toggle::Toggled(false)) => div(),

View file

@ -38,7 +38,7 @@ impl<V: 'static> Modal<V> {
self
}
fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
v_stack()
.id(self.id.clone())
.w_96()

View file

@ -22,7 +22,7 @@ impl NotificationToast {
self
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
h_stack()
.z_index(5)
.absolute()

View file

@ -42,7 +42,7 @@ impl Palette {
self
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
v_stack()
.id(self.id.clone())
.w_96()
@ -135,7 +135,7 @@ impl PaletteItem {
self
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
div()
.flex()
.flex_row()

View file

@ -92,7 +92,7 @@ impl<V: 'static> Panel<V> {
self
}
fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
let current_size = self.width.unwrap_or(self.initial_width);
v_stack()

View file

@ -13,7 +13,7 @@ impl PlayerStack {
}
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
let player = self.player_with_call_status.get_player();
let followers = self

View file

@ -86,7 +86,7 @@ impl Tab {
self
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
let has_fs_conflict = self.fs_status == FileSystemStatus::Conflict;
let is_deleted = self.fs_status == FileSystemStatus::Deleted;

View file

@ -21,12 +21,41 @@ pub enum ToastOrigin {
/// they are actively showing the a process in progress.
///
/// Only one toast may be visible at a time.
#[derive(Component)]
pub struct Toast<V: 'static> {
origin: ToastOrigin,
children: SmallVec<[AnyElement<V>; 2]>,
}
impl<V: 'static> Element<V> for Toast<V> {
type State = Option<AnyElement<V>>;
fn element_id(&self) -> Option<ElementId> {
None
}
fn layout(
&mut self,
view_state: &mut V,
_element_state: Option<Self::State>,
cx: &mut ViewContext<V>,
) -> (gpui::LayoutId, Self::State) {
let mut element = self.render(view_state, cx).into_any();
let layout_id = element.layout(view_state, cx);
(layout_id, Some(element))
}
fn paint(
self,
bounds: gpui::Bounds<gpui::Pixels>,
view_state: &mut V,
element: &mut Self::State,
cx: &mut ViewContext<V>,
) {
let element = element.take().unwrap();
element.paint(view_state, cx);
}
}
impl<V: 'static> Toast<V> {
pub fn new(origin: ToastOrigin) -> Self {
Self {
@ -35,7 +64,7 @@ impl<V: 'static> Toast<V> {
}
}
fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
let mut div = div();
if self.origin == ToastOrigin::Bottom {

View file

@ -1,4 +1,4 @@
use gpui::{div, Component, ParentComponent};
use gpui::{div, Component, Element, ParentComponent};
use crate::{Icon, IconElement, IconSize, TextColor};
@ -44,7 +44,7 @@ impl From<bool> for Toggle {
}
}
pub fn disclosure_control<V: 'static>(toggle: Toggle) -> impl Component<V> {
pub fn disclosure_control<V: 'static>(toggle: Toggle) -> impl Element<V> {
match (toggle.is_toggleable(), toggle.is_toggled()) {
(false, _) => div(),
(_, true) => div().child(

View file

@ -8,7 +8,7 @@ impl ToolDivider {
Self
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
div().w_px().h_3().bg(cx.theme().colors().border)
}
}