From a8bf0834e6afde50107b4bc067dd86a00141f86a Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Wed, 29 Nov 2023 12:23:09 -0500 Subject: [PATCH] =?UTF-8?q?Button2=20=E2=80=93=20Part1=20(#3420)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## TODO - [x] Remove `InteractionState` - [ ] `Selectable` should use `Selection` instead of a boolean - [x] Clean out ui2 prelude - [ ] Build out button2 button types - [ ] Port old buttons Release Notes: - N/A --------- Co-authored-by: Marshall Bowers <1486634+maxdeviant@users.noreply.github.com> --- crates/collab_ui2/src/collab_titlebar_item.rs | 26 +- crates/storybook2/src/stories/focus.rs | 2 +- crates/storybook2/src/stories/picker.rs | 2 +- crates/storybook2/src/stories/scroll.rs | 2 +- crates/storybook2/src/story_selector.rs | 2 - crates/ui2/src/clickable.rs | 5 + crates/ui2/src/components.rs | 4 +- crates/ui2/src/components/button2.rs | 413 ++++++++++++++++++ crates/ui2/src/components/icon_button.rs | 18 +- crates/ui2/src/components/input.rs | 108 ----- crates/ui2/src/components/stories.rs | 3 - crates/ui2/src/components/stories/button.rs | 164 ++----- crates/ui2/src/components/stories/input.rs | 18 - crates/ui2/src/fixed.rs | 6 + crates/ui2/src/prelude.rs | 59 +-- crates/ui2/src/selectable.rs | 26 ++ crates/ui2/src/styles/color.rs | 2 +- crates/ui2/src/ui2.rs | 6 + crates/workspace2/src/dock.rs | 24 +- crates/workspace2/src/pane.rs | 12 +- crates/workspace2/src/status_bar.rs | 2 +- crates/workspace2/src/toolbar.rs | 2 +- 22 files changed, 567 insertions(+), 339 deletions(-) create mode 100644 crates/ui2/src/clickable.rs create mode 100644 crates/ui2/src/components/button2.rs delete mode 100644 crates/ui2/src/components/input.rs delete mode 100644 crates/ui2/src/components/stories/input.rs create mode 100644 crates/ui2/src/fixed.rs create mode 100644 crates/ui2/src/selectable.rs diff --git a/crates/collab_ui2/src/collab_titlebar_item.rs b/crates/collab_ui2/src/collab_titlebar_item.rs index 2307ba2fcb..ac72176d67 100644 --- a/crates/collab_ui2/src/collab_titlebar_item.rs +++ b/crates/collab_ui2/src/collab_titlebar_item.rs @@ -37,7 +37,10 @@ use gpui::{ }; use project::Project; use theme::ActiveTheme; -use ui::{h_stack, Avatar, Button, ButtonVariant, Color, IconButton, KeyBinding, Tooltip}; +use ui::{ + h_stack, Avatar, Button, ButtonCommon, ButtonLike, ButtonVariant, Clickable, Color, IconButton, + IconElement, IconSize, KeyBinding, Tooltip, +}; use util::ResultExt; use workspace::{notifications::NotifyResultExt, Workspace}; @@ -298,6 +301,27 @@ impl Render for CollabTitlebarItem { }) .detach(); })) + // Temporary, will be removed when the last part of button2 is merged + .child( + div().border().border_color(gpui::blue()).child( + ButtonLike::new("test-button") + .children([ + Avatar::uri( + "https://avatars.githubusercontent.com/u/1714999?v=4", + ) + .into_element() + .into_any(), + IconElement::new(ui::Icon::ChevronDown) + .size(IconSize::Small) + .into_element() + .into_any(), + ]) + .on_click(move |event, _cx| { + dbg!(format!("clicked: {:?}", event.down.position)); + }) + .tooltip(|cx| Tooltip::text("Test tooltip", cx)), + ), + ) } }) } diff --git a/crates/storybook2/src/stories/focus.rs b/crates/storybook2/src/stories/focus.rs index 77aa057b09..7b375b10e3 100644 --- a/crates/storybook2/src/stories/focus.rs +++ b/crates/storybook2/src/stories/focus.rs @@ -2,7 +2,7 @@ use gpui::{ actions, div, prelude::*, Div, FocusHandle, Focusable, KeyBinding, Render, Stateful, View, WindowContext, }; -use theme2::ActiveTheme; +use ui::prelude::*; actions!(ActionA, ActionB, ActionC); diff --git a/crates/storybook2/src/stories/picker.rs b/crates/storybook2/src/stories/picker.rs index 75eb0d88e7..75aa7aed05 100644 --- a/crates/storybook2/src/stories/picker.rs +++ b/crates/storybook2/src/stories/picker.rs @@ -4,7 +4,7 @@ use gpui::{ }; use picker::{Picker, PickerDelegate}; use std::sync::Arc; -use theme2::ActiveTheme; +use ui::prelude::*; use ui::{Label, ListItem}; pub struct PickerStory { diff --git a/crates/storybook2/src/stories/scroll.rs b/crates/storybook2/src/stories/scroll.rs index 297e65d411..300aae1144 100644 --- a/crates/storybook2/src/stories/scroll.rs +++ b/crates/storybook2/src/stories/scroll.rs @@ -1,5 +1,5 @@ use gpui::{div, prelude::*, px, Div, Render, SharedString, Stateful, Styled, View, WindowContext}; -use theme2::ActiveTheme; +use ui::prelude::*; use ui::Tooltip; pub struct ScrollStory; diff --git a/crates/storybook2/src/story_selector.rs b/crates/storybook2/src/story_selector.rs index 9945b2e7ef..1c0890e4be 100644 --- a/crates/storybook2/src/story_selector.rs +++ b/crates/storybook2/src/story_selector.rs @@ -19,7 +19,6 @@ pub enum ComponentStory { Focus, Icon, IconButton, - Input, Keybinding, Label, ListItem, @@ -39,7 +38,6 @@ impl ComponentStory { Self::Focus => FocusStory::view(cx).into(), Self::Icon => cx.build_view(|_| ui::IconStory).into(), Self::IconButton => cx.build_view(|_| ui::IconButtonStory).into(), - Self::Input => cx.build_view(|_| ui::InputStory).into(), Self::Keybinding => cx.build_view(|_| ui::KeybindingStory).into(), Self::Label => cx.build_view(|_| ui::LabelStory).into(), Self::ListItem => cx.build_view(|_| ui::ListItemStory).into(), diff --git a/crates/ui2/src/clickable.rs b/crates/ui2/src/clickable.rs new file mode 100644 index 0000000000..b25f6b0e70 --- /dev/null +++ b/crates/ui2/src/clickable.rs @@ -0,0 +1,5 @@ +use gpui::{ClickEvent, WindowContext}; + +pub trait Clickable { + fn on_click(self, handler: impl Fn(&ClickEvent, &mut WindowContext) + 'static) -> Self; +} diff --git a/crates/ui2/src/components.rs b/crates/ui2/src/components.rs index c467576f4a..9dc061e31f 100644 --- a/crates/ui2/src/components.rs +++ b/crates/ui2/src/components.rs @@ -1,12 +1,12 @@ mod avatar; mod button; +mod button2; mod checkbox; mod context_menu; mod disclosure; mod divider; mod icon; mod icon_button; -mod input; mod keybinding; mod label; mod list; @@ -21,13 +21,13 @@ mod stories; pub use avatar::*; pub use button::*; +pub use button2::*; pub use checkbox::*; pub use context_menu::*; pub use disclosure::*; pub use divider::*; pub use icon::*; pub use icon_button::*; -pub use input::*; pub use keybinding::*; pub use label::*; pub use list::*; diff --git a/crates/ui2/src/components/button2.rs b/crates/ui2/src/components/button2.rs new file mode 100644 index 0000000000..e9192afea0 --- /dev/null +++ b/crates/ui2/src/components/button2.rs @@ -0,0 +1,413 @@ +use gpui::{ + rems, AnyElement, AnyView, ClickEvent, Div, Hsla, IntoElement, Rems, Stateful, + StatefulInteractiveElement, WindowContext, +}; +use smallvec::SmallVec; + +use crate::{h_stack, prelude::*}; + +// 🚧 Heavily WIP 🚧 + +// #[derive(Default, PartialEq, Clone, Copy)] +// pub enum ButtonType2 { +// #[default] +// DefaultButton, +// IconButton, +// ButtonLike, +// SplitButton, +// ToggleButton, +// } + +#[derive(Default, PartialEq, Clone, Copy)] +pub enum IconPosition2 { + #[default] + Before, + After, +} + +#[derive(Default, PartialEq, Clone, Copy)] +pub enum ButtonStyle2 { + #[default] + Filled, + // Tinted, + Subtle, + Transparent, +} + +#[derive(Debug, Clone, Copy)] +pub struct ButtonStyle { + pub background: Hsla, + pub border_color: Hsla, + pub label_color: Hsla, + pub icon_color: Hsla, +} + +impl ButtonStyle2 { + pub fn enabled(self, cx: &mut WindowContext) -> ButtonStyle { + match self { + ButtonStyle2::Filled => ButtonStyle { + background: cx.theme().colors().element_background, + border_color: gpui::transparent_black(), + label_color: Color::Default.color(cx), + icon_color: Color::Default.color(cx), + }, + ButtonStyle2::Subtle => ButtonStyle { + background: cx.theme().colors().ghost_element_background, + border_color: gpui::transparent_black(), + label_color: Color::Default.color(cx), + icon_color: Color::Default.color(cx), + }, + ButtonStyle2::Transparent => ButtonStyle { + background: gpui::transparent_black(), + border_color: gpui::transparent_black(), + label_color: Color::Default.color(cx), + icon_color: Color::Default.color(cx), + }, + } + } + + pub fn hovered(self, cx: &mut WindowContext) -> ButtonStyle { + match self { + ButtonStyle2::Filled => ButtonStyle { + background: cx.theme().colors().element_hover, + border_color: gpui::transparent_black(), + label_color: Color::Default.color(cx), + icon_color: Color::Default.color(cx), + }, + ButtonStyle2::Subtle => ButtonStyle { + background: cx.theme().colors().ghost_element_hover, + border_color: gpui::transparent_black(), + label_color: Color::Default.color(cx), + icon_color: Color::Default.color(cx), + }, + ButtonStyle2::Transparent => ButtonStyle { + background: gpui::transparent_black(), + border_color: gpui::transparent_black(), + // TODO: These are not great + label_color: Color::Muted.color(cx), + // TODO: These are not great + icon_color: Color::Muted.color(cx), + }, + } + } + + pub fn active(self, cx: &mut WindowContext) -> ButtonStyle { + match self { + ButtonStyle2::Filled => ButtonStyle { + background: cx.theme().colors().element_active, + border_color: gpui::transparent_black(), + label_color: Color::Default.color(cx), + icon_color: Color::Default.color(cx), + }, + ButtonStyle2::Subtle => ButtonStyle { + background: cx.theme().colors().ghost_element_active, + border_color: gpui::transparent_black(), + label_color: Color::Default.color(cx), + icon_color: Color::Default.color(cx), + }, + ButtonStyle2::Transparent => ButtonStyle { + background: gpui::transparent_black(), + border_color: gpui::transparent_black(), + // TODO: These are not great + label_color: Color::Muted.color(cx), + // TODO: These are not great + icon_color: Color::Muted.color(cx), + }, + } + } + + pub fn focused(self, cx: &mut WindowContext) -> ButtonStyle { + match self { + ButtonStyle2::Filled => ButtonStyle { + background: cx.theme().colors().element_background, + border_color: cx.theme().colors().border_focused, + label_color: Color::Default.color(cx), + icon_color: Color::Default.color(cx), + }, + ButtonStyle2::Subtle => ButtonStyle { + background: cx.theme().colors().ghost_element_background, + border_color: cx.theme().colors().border_focused, + label_color: Color::Default.color(cx), + icon_color: Color::Default.color(cx), + }, + ButtonStyle2::Transparent => ButtonStyle { + background: gpui::transparent_black(), + border_color: cx.theme().colors().border_focused, + label_color: Color::Accent.color(cx), + icon_color: Color::Accent.color(cx), + }, + } + } + + pub fn disabled(self, cx: &mut WindowContext) -> ButtonStyle { + match self { + ButtonStyle2::Filled => ButtonStyle { + background: cx.theme().colors().element_disabled, + border_color: cx.theme().colors().border_disabled, + label_color: Color::Disabled.color(cx), + icon_color: Color::Disabled.color(cx), + }, + ButtonStyle2::Subtle => ButtonStyle { + background: cx.theme().colors().ghost_element_disabled, + border_color: cx.theme().colors().border_disabled, + label_color: Color::Disabled.color(cx), + icon_color: Color::Disabled.color(cx), + }, + ButtonStyle2::Transparent => ButtonStyle { + background: gpui::transparent_black(), + border_color: gpui::transparent_black(), + label_color: Color::Disabled.color(cx), + icon_color: Color::Disabled.color(cx), + }, + } + } +} + +#[derive(Default, PartialEq, Clone, Copy)] +pub enum ButtonSize2 { + #[default] + Default, + Compact, + None, +} + +impl ButtonSize2 { + fn height(self) -> Rems { + match self { + ButtonSize2::Default => rems(22. / 16.), + ButtonSize2::Compact => rems(18. / 16.), + ButtonSize2::None => rems(16. / 16.), + } + } +} + +// pub struct Button { +// id: ElementId, +// icon: Option, +// icon_color: Option, +// icon_position: Option, +// label: Option