Add `LanguageSelector` component

Marshall Bowers created

Change summary

crates/storybook2/src/stories/components.rs                   |  1 
crates/storybook2/src/stories/components/language_selector.rs | 26 +++
crates/storybook2/src/story_selector.rs                       |  4 
crates/ui2/src/components.rs                                  |  2 
crates/ui2/src/components/language_selector.rs                | 40 +++++
5 files changed, 73 insertions(+)

Detailed changes

crates/storybook2/src/stories/components/language_selector.rs 🔗

@@ -0,0 +1,26 @@
+use std::marker::PhantomData;
+
+use ui::prelude::*;
+use ui::LanguageSelector;
+
+use crate::story::Story;
+
+#[derive(Element)]
+pub struct LanguageSelectorStory<S: 'static + Send + Sync + Clone> {
+    state_type: PhantomData<S>,
+}
+
+impl<S: 'static + Send + Sync + Clone> LanguageSelectorStory<S> {
+    pub fn new() -> Self {
+        Self {
+            state_type: PhantomData,
+        }
+    }
+
+    fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
+        Story::container(cx)
+            .child(Story::title_for::<_, LanguageSelector<S>>(cx))
+            .child(Story::label(cx, "Default"))
+            .child(LanguageSelector::new())
+    }
+}

crates/storybook2/src/story_selector.rs 🔗

@@ -45,6 +45,7 @@ pub enum ComponentStory {
     ContextMenu,
     Facepile,
     Keybinding,
+    LanguageSelector,
     MultiBuffer,
     Palette,
     Panel,
@@ -77,6 +78,9 @@ impl ComponentStory {
             Self::ContextMenu => components::context_menu::ContextMenuStory::new().into_any(),
             Self::Facepile => components::facepile::FacepileStory::new().into_any(),
             Self::Keybinding => components::keybinding::KeybindingStory::new().into_any(),
+            Self::LanguageSelector => {
+                components::language_selector::LanguageSelectorStory::new().into_any()
+            }
             Self::MultiBuffer => components::multi_buffer::MultiBufferStory::new().into_any(),
             Self::Palette => components::palette::PaletteStory::new().into_any(),
             Self::Panel => components::panel::PanelStory::new().into_any(),

crates/ui2/src/components.rs 🔗

@@ -9,6 +9,7 @@ mod editor_pane;
 mod facepile;
 mod icon_button;
 mod keybinding;
+mod language_selector;
 mod list;
 mod multi_buffer;
 mod palette;
@@ -37,6 +38,7 @@ pub use editor_pane::*;
 pub use facepile::*;
 pub use icon_button::*;
 pub use keybinding::*;
+pub use language_selector::*;
 pub use list::*;
 pub use multi_buffer::*;
 pub use palette::*;

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

@@ -0,0 +1,40 @@
+use std::marker::PhantomData;
+
+use crate::prelude::*;
+use crate::{OrderMethod, Palette, PaletteItem};
+
+#[derive(Element)]
+pub struct LanguageSelector<S: 'static + Send + Sync + Clone> {
+    state_type: PhantomData<S>,
+    scroll_state: ScrollState,
+}
+
+impl<S: 'static + Send + Sync + Clone> LanguageSelector<S> {
+    pub fn new() -> Self {
+        Self {
+            state_type: PhantomData,
+            scroll_state: ScrollState::default(),
+        }
+    }
+
+    fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
+        div().child(
+            Palette::new(self.scroll_state.clone())
+                .items(vec![
+                    PaletteItem::new("C"),
+                    PaletteItem::new("C++"),
+                    PaletteItem::new("CSS"),
+                    PaletteItem::new("Elixir"),
+                    PaletteItem::new("Elm"),
+                    PaletteItem::new("ERB"),
+                    PaletteItem::new("Rust (current)"),
+                    PaletteItem::new("Scheme"),
+                    PaletteItem::new("TOML"),
+                    PaletteItem::new("TypeScript"),
+                ])
+                .placeholder("Select a language...")
+                .empty_string("No matches")
+                .default_order(OrderMethod::Ascending),
+        )
+    }
+}