Add `IconButton` component

Marshall Bowers created

Change summary

crates/storybook2/src/workspace.rs       |  2 
crates/ui2/src/components.rs             |  2 
crates/ui2/src/components/icon_button.rs | 71 ++++++++++++++++++++++++++
crates/ui2/src/elements.rs               |  2 
crates/ui2/src/elements/button.rs        |  6 ++
crates/ui2/src/prelude.rs                |  4 -
6 files changed, 83 insertions(+), 4 deletions(-)

Detailed changes

crates/storybook2/src/workspace.rs 🔗

@@ -3,7 +3,7 @@ use gpui3::{
     ViewContext, WindowContext,
 };
 use ui::prelude::*;
-use ui::{theme, themed, Panel, Stack};
+use ui::{themed, Panel, Stack};
 
 use crate::{
     collab_panel::{collab_panel, CollabPanel},

crates/ui2/src/components/icon_button.rs 🔗

@@ -0,0 +1,71 @@
+use std::marker::PhantomData;
+
+use crate::prelude::*;
+use crate::{theme, Icon, IconColor, IconElement};
+
+#[derive(Element)]
+pub struct IconButton<S: 'static + Send + Sync> {
+    state_type: PhantomData<S>,
+    icon: Icon,
+    color: IconColor,
+    variant: ButtonVariant,
+    state: InteractionState,
+}
+
+impl<S: 'static + Send + Sync> IconButton<S> {
+    pub fn new(icon: Icon) -> Self {
+        Self {
+            state_type: PhantomData,
+            icon,
+            color: IconColor::default(),
+            variant: ButtonVariant::default(),
+            state: InteractionState::default(),
+        }
+    }
+
+    pub fn icon(mut self, icon: Icon) -> Self {
+        self.icon = icon;
+        self
+    }
+
+    pub fn color(mut self, color: IconColor) -> Self {
+        self.color = color;
+        self
+    }
+
+    pub fn variant(mut self, variant: ButtonVariant) -> Self {
+        self.variant = variant;
+        self
+    }
+
+    pub fn state(mut self, state: InteractionState) -> Self {
+        self.state = state;
+        self
+    }
+
+    fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
+        let theme = theme(cx);
+
+        let icon_color = match (self.state, self.color) {
+            (InteractionState::Disabled, _) => IconColor::Disabled,
+            _ => self.color,
+        };
+
+        let mut div = div();
+        if self.variant == ButtonVariant::Filled {
+            div = div.fill(theme.highest.on.default.background);
+        }
+
+        div.w_7()
+            .h_6()
+            .flex()
+            .items_center()
+            .justify_center()
+            .rounded_md()
+            // .hover()
+            // .fill(theme.highest.base.hovered.background)
+            // .active()
+            // .fill(theme.highest.base.pressed.background)
+            .child(IconElement::new(self.icon).color(icon_color))
+    }
+}

crates/ui2/src/elements.rs 🔗

@@ -1,9 +1,11 @@
 mod avatar;
+mod button;
 mod icon;
 mod label;
 mod stack;
 
 pub use avatar::*;
+pub use button::*;
 pub use icon::*;
 pub use label::*;
 pub use stack::*;

crates/ui2/src/prelude.rs 🔗

@@ -3,13 +3,11 @@ pub use gpui3::{
     WindowContext,
 };
 
-pub use crate::{HackyChildren, HackyChildrenPayload, ElementExt};
+pub use crate::{theme, ButtonVariant, ElementExt, HackyChildren, HackyChildrenPayload, Theme};
 
 use gpui3::{hsla, rgb, Hsla};
 use strum::EnumIter;
 
-use crate::theme::{theme, Theme};
-
 #[derive(Default)]
 pub struct SystemColor {
     pub transparent: Hsla,