Remove storybook and story crates (#53511)

Lukas Wirth created

Remove the standalone storybook binary and the story crate, as component
previews are now handled by the component_preview crate.

Also removes the stories features from the ui and title_bar crates.

Release Notes:

- N/A or Added/Fixed/Improved ...

Change summary

Cargo.lock                                         |  83 ------
Cargo.toml                                         |   4 
crates/story/Cargo.toml                            |  17 -
crates/story/LICENSE-GPL                           |   1 
crates/story/src/story.rs                          | 209 ----------------
crates/storybook/Cargo.toml                        |  41 ---
crates/storybook/LICENSE-GPL                       |   1 
crates/storybook/build.rs                          |   9 
crates/storybook/docs/thoughts.md                  |  57 ----
crates/storybook/src/actions.rs                    |   2 
crates/storybook/src/app_menus.rs                  |   7 
crates/storybook/src/assets.rs                     |  32 --
crates/storybook/src/stories.rs                    |  23 -
crates/storybook/src/stories/auto_height_editor.rs |  36 --
crates/storybook/src/stories/cursor.rs             | 109 --------
crates/storybook/src/stories/focus.rs              | 123 ---------
crates/storybook/src/stories/indent_guides.rs      |  82 ------
crates/storybook/src/stories/kitchen_sink.rs       |  32 --
crates/storybook/src/stories/overflow_scroll.rs    |  41 ---
crates/storybook/src/stories/picker.rs             | 206 ---------------
crates/storybook/src/stories/scroll.rs             |  52 ---
crates/storybook/src/stories/text.rs               | 120 ---------
crates/storybook/src/stories/viewport_units.rs     |  32 --
crates/storybook/src/stories/with_rem_size.rs      |  61 ----
crates/storybook/src/story_selector.rs             | 109 --------
crates/storybook/src/storybook.rs                  | 162 ------------
crates/theme/Cargo.toml                            |   1 
crates/theme/src/registry.rs                       |  17 +
crates/theme/src/theme.rs                          |  27 +
crates/title_bar/Cargo.toml                        |   3 
crates/title_bar/src/stories/application_menu.rs   |  29 --
crates/title_bar/src/title_bar.rs                  |   6 
crates/ui/Cargo.toml                               |   2 
crates/ui/src/components.rs                        |   6 
crates/ui/src/components/stories/context_menu.rs   |  81 ------
35 files changed, 40 insertions(+), 1,783 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -3418,19 +3418,6 @@ dependencies = [
  "crossbeam-utils",
 ]
 
-[[package]]
-name = "console"
-version = "0.15.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8"
-dependencies = [
- "encode_unicode",
- "libc",
- "once_cell",
- "unicode-width",
- "windows-sys 0.59.0",
-]
-
 [[package]]
 name = "console_error_panic_hook"
 version = "0.1.7"
@@ -4851,20 +4838,6 @@ dependencies = [
  "zlog",
 ]
 
-[[package]]
-name = "dialoguer"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de"
-dependencies = [
- "console",
- "fuzzy-matcher",
- "shell-words",
- "tempfile",
- "thiserror 1.0.69",
- "zeroize",
-]
-
 [[package]]
 name = "diff"
 version = "0.1.13"
@@ -5546,12 +5519,6 @@ dependencies = [
  "phf 0.11.3",
 ]
 
-[[package]]
-name = "encode_unicode"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
-
 [[package]]
 name = "encoding_rs"
 version = "0.8.35"
@@ -6747,15 +6714,6 @@ dependencies = [
  "util",
 ]
 
-[[package]]
-name = "fuzzy-matcher"
-version = "0.3.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94"
-dependencies = [
- "thread_local",
-]
-
 [[package]]
 name = "fuzzy_nucleo"
 version = "0.1.0"
@@ -16745,44 +16703,6 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
 
-[[package]]
-name = "story"
-version = "0.1.0"
-dependencies = [
- "gpui",
- "itertools 0.14.0",
- "smallvec",
-]
-
-[[package]]
-name = "storybook"
-version = "0.1.0"
-dependencies = [
- "anyhow",
- "clap",
- "ctrlc",
- "dialoguer",
- "editor",
- "fuzzy",
- "gpui",
- "gpui_platform",
- "indoc",
- "language",
- "log",
- "menu",
- "picker",
- "reqwest_client",
- "rust-embed",
- "settings",
- "simplelog",
- "story",
- "strum 0.27.2",
- "theme",
- "theme_settings",
- "title_bar",
- "ui",
-]
-
 [[package]]
 name = "streaming-iterator"
 version = "0.1.9"
@@ -17704,7 +17624,6 @@ version = "0.1.0"
 dependencies = [
  "anyhow",
  "collections",
- "derive_more",
  "gpui",
  "palette",
  "parking_lot",
@@ -18027,7 +17946,6 @@ dependencies = [
  "serde",
  "settings",
  "smallvec",
- "story",
  "telemetry",
  "theme",
  "ui",
@@ -18926,7 +18844,6 @@ dependencies = [
  "schemars",
  "serde",
  "smallvec",
- "story",
  "strum 0.27.2",
  "theme",
  "ui_macros",

Cargo.toml 🔗

@@ -183,8 +183,6 @@ members = [
     "crates/snippets_ui",
     "crates/sqlez",
     "crates/sqlez_macros",
-    "crates/story",
-    "crates/storybook",
     "crates/streaming_diff",
     "crates/sum_tree",
     "crates/svg_preview",
@@ -437,7 +435,6 @@ snippet_provider = { path = "crates/snippet_provider" }
 snippets_ui = { path = "crates/snippets_ui" }
 sqlez = { path = "crates/sqlez" }
 sqlez_macros = { path = "crates/sqlez_macros" }
-story = { path = "crates/story" }
 streaming_diff = { path = "crates/streaming_diff" }
 sum_tree = { path = "crates/sum_tree" }
 codestral = { path = "crates/codestral" }
@@ -935,7 +932,6 @@ session = { codegen-units = 1 }
 sidebar = { codegen-units = 1 }
 snippet = { codegen-units = 1 }
 snippets_ui = { codegen-units = 1 }
-story = { codegen-units = 1 }
 telemetry_events = { codegen-units = 1 }
 theme_selector = { codegen-units = 1 }
 time_format = { codegen-units = 1 }

crates/story/Cargo.toml 🔗

@@ -1,17 +0,0 @@
-[package]
-name = "story"
-version = "0.1.0"
-edition.workspace = true
-publish.workspace = true
-license = "GPL-3.0-or-later"
-
-[lib]
-path = "src/story.rs"
-
-[lints]
-workspace = true
-
-[dependencies]
-gpui.workspace = true
-itertools.workspace = true
-smallvec.workspace = true

crates/story/src/story.rs 🔗

@@ -1,209 +0,0 @@
-use gpui::{
-    AnyElement, App, Div, SharedString, Window, colors::DefaultColors, div, prelude::*, px, rems,
-};
-use itertools::Itertools;
-use smallvec::SmallVec;
-
-pub struct Story {}
-
-impl Story {
-    pub fn container(cx: &App) -> gpui::Stateful<Div> {
-        div()
-            .id("story_container")
-            .overflow_y_scroll()
-            .w_full()
-            .min_h_full()
-            .flex()
-            .flex_col()
-            .text_color(cx.default_colors().text)
-            .bg(cx.default_colors().background)
-    }
-
-    pub fn title(title: impl Into<SharedString>, cx: &App) -> impl Element {
-        div()
-            .text_xs()
-            .text_color(cx.default_colors().text)
-            .child(title.into())
-    }
-
-    pub fn title_for<T>(cx: &App) -> impl Element {
-        Self::title(std::any::type_name::<T>(), cx)
-    }
-
-    pub fn section(cx: &App) -> Div {
-        div()
-            .p_4()
-            .m_4()
-            .border_1()
-            .border_color(cx.default_colors().separator)
-    }
-
-    pub fn section_title(cx: &App) -> Div {
-        div().text_lg().text_color(cx.default_colors().text)
-    }
-
-    pub fn group(cx: &App) -> Div {
-        div().my_2().bg(cx.default_colors().container)
-    }
-
-    pub fn code_block(code: impl Into<SharedString>, cx: &App) -> Div {
-        div()
-            .size_full()
-            .p_2()
-            .max_w(rems(36.))
-            .bg(cx.default_colors().container)
-            .rounded_sm()
-            .text_sm()
-            .text_color(cx.default_colors().text)
-            .overflow_hidden()
-            .child(code.into())
-    }
-
-    pub fn divider(cx: &App) -> Div {
-        div().my_2().h(px(1.)).bg(cx.default_colors().separator)
-    }
-
-    pub fn description(description: impl Into<SharedString>, cx: &App) -> impl Element {
-        div()
-            .text_sm()
-            .text_color(cx.default_colors().text)
-            .min_w_96()
-            .child(description.into())
-    }
-
-    pub fn label(label: impl Into<SharedString>, cx: &App) -> impl Element {
-        div()
-            .text_xs()
-            .text_color(cx.default_colors().text)
-            .child(label.into())
-    }
-
-    /// Note: Not `ui::v_flex` as the `story` crate doesn't depend on the `ui` crate.
-    pub fn v_flex() -> Div {
-        div().flex().flex_col().gap_1()
-    }
-}
-
-#[derive(IntoElement)]
-pub struct StoryItem {
-    label: SharedString,
-    item: AnyElement,
-    description: Option<SharedString>,
-    usage: Option<SharedString>,
-}
-
-impl StoryItem {
-    pub fn new(label: impl Into<SharedString>, item: impl IntoElement) -> Self {
-        Self {
-            label: label.into(),
-            item: item.into_any_element(),
-            description: None,
-            usage: None,
-        }
-    }
-
-    pub fn description(mut self, description: impl Into<SharedString>) -> Self {
-        self.description = Some(description.into());
-        self
-    }
-
-    pub fn usage(mut self, code: impl Into<SharedString>) -> Self {
-        self.usage = Some(code.into());
-        self
-    }
-}
-
-impl RenderOnce for StoryItem {
-    fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
-        let colors = cx.default_colors();
-
-        div()
-            .my_2()
-            .flex()
-            .gap_4()
-            .w_full()
-            .child(
-                Story::v_flex()
-                    .px_2()
-                    .w_1_2()
-                    .min_h_px()
-                    .child(Story::label(self.label, cx))
-                    .child(
-                        div()
-                            .rounded_sm()
-                            .bg(colors.background)
-                            .border_1()
-                            .border_color(colors.border)
-                            .py_1()
-                            .px_2()
-                            .overflow_hidden()
-                            .child(self.item),
-                    )
-                    .when_some(self.description, |this, description| {
-                        this.child(Story::description(description, cx))
-                    }),
-            )
-            .child(
-                Story::v_flex()
-                    .px_2()
-                    .flex_none()
-                    .w_1_2()
-                    .min_h_px()
-                    .when_some(self.usage, |this, usage| {
-                        this.child(Story::label("Example Usage", cx))
-                            .child(Story::code_block(usage, cx))
-                    }),
-            )
-    }
-}
-
-#[derive(IntoElement)]
-pub struct StorySection {
-    description: Option<SharedString>,
-    children: SmallVec<[AnyElement; 2]>,
-}
-
-impl Default for StorySection {
-    fn default() -> Self {
-        Self::new()
-    }
-}
-
-impl StorySection {
-    pub fn new() -> Self {
-        Self {
-            description: None,
-            children: SmallVec::new(),
-        }
-    }
-
-    pub fn description(mut self, description: impl Into<SharedString>) -> Self {
-        self.description = Some(description.into());
-        self
-    }
-}
-
-impl RenderOnce for StorySection {
-    fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
-        let children: SmallVec<[AnyElement; 2]> = SmallVec::from_iter(Itertools::intersperse_with(
-            self.children.into_iter(),
-            || Story::divider(cx).into_any_element(),
-        ));
-
-        Story::section(cx)
-            // Section title
-            .py_2()
-            // Section description
-            .when_some(self.description, |section, description| {
-                section.child(Story::description(description, cx))
-            })
-            .child(div().flex().flex_col().gap_2().children(children))
-            .child(Story::divider(cx))
-    }
-}
-
-impl ParentElement for StorySection {
-    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
-        self.children.extend(elements)
-    }
-}

crates/storybook/Cargo.toml 🔗

@@ -1,41 +0,0 @@
-[package]
-name = "storybook"
-version = "0.1.0"
-edition.workspace = true
-publish.workspace = true
-license = "GPL-3.0-or-later"
-
-[lints]
-workspace = true
-
-[[bin]]
-name = "storybook"
-path = "src/storybook.rs"
-
-[dependencies]
-anyhow.workspace = true
-clap = { workspace = true, features = ["derive", "string"] }
-ctrlc = "3.4"
-dialoguer = { version = "0.11.0", features = ["fuzzy-select"] }
-editor.workspace = true
-fuzzy.workspace = true
-gpui = { workspace = true, default-features = true }
-gpui_platform.workspace = true
-indoc.workspace = true
-language.workspace = true
-log.workspace = true
-menu.workspace = true
-picker.workspace = true
-reqwest_client.workspace = true
-rust-embed.workspace = true
-settings.workspace = true
-theme_settings.workspace = true
-simplelog.workspace = true
-story.workspace = true
-strum = { workspace = true, features = ["derive"] }
-theme.workspace = true
-title_bar = { workspace = true, features = ["stories"] }
-ui = { workspace = true, features = ["stories"] }
-
-[dev-dependencies]
-gpui = { workspace = true, features = ["test-support"] }

crates/storybook/build.rs 🔗

@@ -1,9 +0,0 @@
-fn main() {
-    #[cfg(target_os = "windows")]
-    {
-        #[cfg(target_env = "msvc")]
-        {
-            println!("cargo:rustc-link-arg=/stack:{}", 8 * 1024 * 1024);
-        }
-    }
-}

crates/storybook/docs/thoughts.md 🔗

@@ -1,57 +0,0 @@
-Much of element styling is now handled by an external engine.
-
-How do I make an element hover.
-
-There's a hover style.
-
-Hoverable needs to wrap another element. That element can be styled.
-
-```rs
-struct Hoverable<E: Element> {
-
-}
-
-impl<V> Element<V> for Hoverable {
-
-}
-```
-
-```rs
-#[derive(Styled, Interactive)]
-pub struct Div {
-    declared_style: StyleRefinement,
-    interactions: Interactions
-}
-
-pub trait Styled {
-    fn declared_style(&mut self) -> &mut StyleRefinement;
-    fn compute_style(&mut self) -> Style {
-        Style::default().refine(self.declared_style())
-    }
-
-    // All the tailwind classes, modifying self.declared_style()
-}
-
-impl Style {
-    pub fn paint_background<V>(layout: Layout, cx: &mut PaintContext<V>);
-    pub fn paint_foreground<V>(layout: Layout, cx: &mut PaintContext<V>);
-}
-
-pub trait Interactive<V> {
-    fn interactions(&mut self) -> &mut Interactions<V>;
-
-    fn on_click(self, )
-}
-
-struct Interactions<V> {
-    click: SmallVec<[<Rc<dyn Fn(&mut V, &dyn Any, )>; 1]>,
-}
-```
-
-```rs
-trait Stylable {
-    type Style;
-
-    fn with_style(self, style: Self::Style) -> Self;
-}
-```

crates/storybook/src/app_menus.rs 🔗

@@ -1,7 +0,0 @@
-use gpui::{Menu, MenuItem};
-
-pub fn app_menus() -> Vec<Menu> {
-    use crate::actions::Quit;
-
-    vec![Menu::new("Storybook").items([MenuItem::action("Quit", Quit)])]
-}

crates/storybook/src/assets.rs 🔗

@@ -1,32 +0,0 @@
-use std::borrow::Cow;
-
-use anyhow::{Context as _, Result};
-use gpui::{AssetSource, SharedString};
-use rust_embed::RustEmbed;
-
-#[derive(RustEmbed)]
-#[folder = "../../assets"]
-#[include = "fonts/**/*"]
-#[include = "icons/**/*"]
-#[include = "images/**/*"]
-#[include = "themes/**/*"]
-#[include = "sounds/**/*"]
-#[include = "*.md"]
-#[exclude = "*.DS_Store"]
-pub struct Assets;
-
-impl AssetSource for Assets {
-    fn load(&self, path: &str) -> Result<Option<Cow<'static, [u8]>>> {
-        Self::get(path)
-            .map(|f| f.data)
-            .with_context(|| format!("could not find asset at path {path:?}"))
-            .map(Some)
-    }
-
-    fn list(&self, path: &str) -> Result<Vec<SharedString>> {
-        Ok(Self::iter()
-            .filter(|p| p.starts_with(path))
-            .map(SharedString::from)
-            .collect())
-    }
-}

crates/storybook/src/stories.rs 🔗

@@ -1,23 +0,0 @@
-mod auto_height_editor;
-mod cursor;
-mod focus;
-mod indent_guides;
-mod kitchen_sink;
-mod overflow_scroll;
-mod picker;
-mod scroll;
-mod text;
-mod viewport_units;
-mod with_rem_size;
-
-pub use auto_height_editor::*;
-pub use cursor::*;
-pub use focus::*;
-pub use indent_guides::*;
-pub use kitchen_sink::*;
-pub use overflow_scroll::*;
-pub use picker::*;
-pub use scroll::*;
-pub use text::*;
-pub use viewport_units::*;
-pub use with_rem_size::*;

crates/storybook/src/stories/auto_height_editor.rs 🔗

@@ -1,36 +0,0 @@
-use editor::Editor;
-use gpui::{
-    App, AppContext as _, Context, Entity, IntoElement, KeyBinding, ParentElement, Render, Styled,
-    Window, div, white,
-};
-
-pub struct AutoHeightEditorStory {
-    editor: Entity<Editor>,
-}
-
-impl AutoHeightEditorStory {
-    pub fn new(window: &mut Window, cx: &mut App) -> gpui::Entity<Self> {
-        cx.bind_keys([KeyBinding::new(
-            "enter",
-            editor::actions::Newline,
-            Some("Editor"),
-        )]);
-        cx.new(|cx| Self {
-            editor: cx.new(|cx| {
-                let mut editor = Editor::auto_height(1, 3, window, cx);
-                editor.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
-                editor
-            }),
-        })
-    }
-}
-
-impl Render for AutoHeightEditorStory {
-    fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
-        div()
-            .size_full()
-            .bg(white())
-            .text_sm()
-            .child(div().w_32().bg(gpui::black()).child(self.editor.clone()))
-    }
-}

crates/storybook/src/stories/cursor.rs 🔗

@@ -1,109 +0,0 @@
-use gpui::{Div, Render, Stateful};
-use story::Story;
-use ui::prelude::*;
-
-pub struct CursorStory;
-
-impl Render for CursorStory {
-    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
-        let all_cursors: [(&str, Box<dyn Fn(Stateful<Div>) -> Stateful<Div>>); 19] = [
-            (
-                "cursor_default",
-                Box::new(|el: Stateful<Div>| el.cursor_default()),
-            ),
-            (
-                "cursor_pointer",
-                Box::new(|el: Stateful<Div>| el.cursor_pointer()),
-            ),
-            (
-                "cursor_text",
-                Box::new(|el: Stateful<Div>| el.cursor_text()),
-            ),
-            (
-                "cursor_move",
-                Box::new(|el: Stateful<Div>| el.cursor_move()),
-            ),
-            (
-                "cursor_not_allowed",
-                Box::new(|el: Stateful<Div>| el.cursor_not_allowed()),
-            ),
-            (
-                "cursor_context_menu",
-                Box::new(|el: Stateful<Div>| el.cursor_context_menu()),
-            ),
-            (
-                "cursor_crosshair",
-                Box::new(|el: Stateful<Div>| el.cursor_crosshair()),
-            ),
-            (
-                "cursor_vertical_text",
-                Box::new(|el: Stateful<Div>| el.cursor_vertical_text()),
-            ),
-            (
-                "cursor_alias",
-                Box::new(|el: Stateful<Div>| el.cursor_alias()),
-            ),
-            (
-                "cursor_copy",
-                Box::new(|el: Stateful<Div>| el.cursor_copy()),
-            ),
-            (
-                "cursor_no_drop",
-                Box::new(|el: Stateful<Div>| el.cursor_no_drop()),
-            ),
-            (
-                "cursor_grab",
-                Box::new(|el: Stateful<Div>| el.cursor_grab()),
-            ),
-            (
-                "cursor_grabbing",
-                Box::new(|el: Stateful<Div>| el.cursor_grabbing()),
-            ),
-            (
-                "cursor_col_resize",
-                Box::new(|el: Stateful<Div>| el.cursor_col_resize()),
-            ),
-            (
-                "cursor_row_resize",
-                Box::new(|el: Stateful<Div>| el.cursor_row_resize()),
-            ),
-            (
-                "cursor_n_resize",
-                Box::new(|el: Stateful<Div>| el.cursor_n_resize()),
-            ),
-            (
-                "cursor_e_resize",
-                Box::new(|el: Stateful<Div>| el.cursor_e_resize()),
-            ),
-            (
-                "cursor_s_resize",
-                Box::new(|el: Stateful<Div>| el.cursor_s_resize()),
-            ),
-            (
-                "cursor_w_resize",
-                Box::new(|el: Stateful<Div>| el.cursor_w_resize()),
-            ),
-        ];
-
-        Story::container(cx)
-            .flex()
-            .gap_1()
-            .child(Story::title("cursor", cx))
-            .children(all_cursors.map(|(name, apply_cursor)| {
-                div().gap_1().flex().text_color(gpui::white()).child(
-                    div()
-                        .flex()
-                        .items_center()
-                        .justify_center()
-                        .id(name)
-                        .map(apply_cursor)
-                        .w_64()
-                        .h_8()
-                        .bg(gpui::red())
-                        .active(|style| style.bg(gpui::green()))
-                        .text_sm()
-                        .child(Story::label(name, cx)),
-                )
-            }))
-    }
-}

crates/storybook/src/stories/focus.rs 🔗

@@ -1,123 +0,0 @@
-use gpui::{
-    App, Entity, FocusHandle, KeyBinding, Render, Subscription, Window, actions, div, prelude::*,
-};
-use ui::prelude::*;
-
-actions!(focus, [ActionA, ActionB, ActionC]);
-
-pub struct FocusStory {
-    parent_focus: FocusHandle,
-    child_1_focus: FocusHandle,
-    child_2_focus: FocusHandle,
-    _focus_subscriptions: Vec<Subscription>,
-}
-
-impl FocusStory {
-    pub fn model(window: &mut Window, cx: &mut App) -> Entity<Self> {
-        cx.bind_keys([
-            KeyBinding::new("cmd-a", ActionA, Some("parent")),
-            KeyBinding::new("cmd-a", ActionB, Some("child-1")),
-            KeyBinding::new("cmd-c", ActionC, None),
-        ]);
-
-        cx.new(|cx| {
-            let parent_focus = cx.focus_handle();
-            let child_1_focus = cx.focus_handle();
-            let child_2_focus = cx.focus_handle();
-            let _focus_subscriptions = vec![
-                cx.on_focus(&parent_focus, window, |_, _, _| {
-                    println!("Parent focused");
-                }),
-                cx.on_blur(&parent_focus, window, |_, _, _| {
-                    println!("Parent blurred");
-                }),
-                cx.on_focus(&child_1_focus, window, |_, _, _| {
-                    println!("Child 1 focused");
-                }),
-                cx.on_blur(&child_1_focus, window, |_, _, _| {
-                    println!("Child 1 blurred");
-                }),
-                cx.on_focus(&child_2_focus, window, |_, _, _| {
-                    println!("Child 2 focused");
-                }),
-                cx.on_blur(&child_2_focus, window, |_, _, _| {
-                    println!("Child 2 blurred");
-                }),
-            ];
-
-            Self {
-                parent_focus,
-                child_1_focus,
-                child_2_focus,
-                _focus_subscriptions,
-            }
-        })
-    }
-}
-
-impl Render for FocusStory {
-    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
-        let theme = cx.theme();
-        let color_1 = theme.status().created;
-        let color_2 = theme.status().modified;
-        let color_4 = theme.status().conflict;
-        let color_5 = theme.status().ignored;
-        let color_6 = theme.status().renamed;
-        let color_7 = theme.status().hint;
-
-        div()
-            .id("parent")
-            .active(|style| style.bg(color_7))
-            .track_focus(&self.parent_focus)
-            .key_context("parent")
-            .on_action(cx.listener(|_, _action: &ActionA, _window, _cx| {
-                println!("Action A dispatched on parent");
-            }))
-            .on_action(cx.listener(|_, _action: &ActionB, _window, _cx| {
-                println!("Action B dispatched on parent");
-            }))
-            .on_key_down(cx.listener(|_, event, _, _| println!("Key down on parent {:?}", event)))
-            .on_key_up(cx.listener(|_, event, _, _| println!("Key up on parent {:?}", event)))
-            .size_full()
-            .bg(color_1)
-            .focus(|style| style.bg(color_2))
-            .child(
-                div()
-                    .track_focus(&self.child_1_focus)
-                    .key_context("child-1")
-                    .on_action(cx.listener(|_, _action: &ActionB, _window, _cx| {
-                        println!("Action B dispatched on child 1 during");
-                    }))
-                    .w_full()
-                    .h_6()
-                    .bg(color_4)
-                    .focus(|style| style.bg(color_5))
-                    .in_focus(|style| style.bg(color_6))
-                    .on_key_down(
-                        cx.listener(|_, event, _, _| println!("Key down on child 1 {:?}", event)),
-                    )
-                    .on_key_up(
-                        cx.listener(|_, event, _, _| println!("Key up on child 1 {:?}", event)),
-                    )
-                    .child("Child 1"),
-            )
-            .child(
-                div()
-                    .track_focus(&self.child_2_focus)
-                    .key_context("child-2")
-                    .on_action(cx.listener(|_, _action: &ActionC, _window, _cx| {
-                        println!("Action C dispatched on child 2");
-                    }))
-                    .w_full()
-                    .h_6()
-                    .bg(color_4)
-                    .on_key_down(
-                        cx.listener(|_, event, _, _| println!("Key down on child 2 {:?}", event)),
-                    )
-                    .on_key_up(
-                        cx.listener(|_, event, _, _| println!("Key up on child 2 {:?}", event)),
-                    )
-                    .child("Child 2"),
-            )
-    }
-}

crates/storybook/src/stories/indent_guides.rs 🔗

@@ -1,82 +0,0 @@
-use std::ops::Range;
-
-use gpui::{Entity, Render, div, uniform_list};
-use gpui::{prelude::*, *};
-use ui::{AbsoluteLength, Color, DefiniteLength, Label, LabelCommon, px, v_flex};
-
-use story::Story;
-
-const LENGTH: usize = 100;
-
-pub struct IndentGuidesStory {
-    depths: Vec<usize>,
-}
-
-impl IndentGuidesStory {
-    pub fn model(_window: &mut Window, cx: &mut App) -> Entity<Self> {
-        let mut depths = Vec::new();
-        depths.push(0);
-        depths.push(1);
-        depths.push(2);
-        for _ in 0..LENGTH - 6 {
-            depths.push(3);
-        }
-        depths.push(2);
-        depths.push(1);
-        depths.push(0);
-
-        cx.new(|_cx| Self { depths })
-    }
-}
-
-impl Render for IndentGuidesStory {
-    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
-        Story::container(cx)
-            .child(Story::title("Indent guides", cx))
-            .child(
-                v_flex().size_full().child(
-                    uniform_list(
-                        "some-list",
-                        self.depths.len(),
-                        cx.processor(move |this, range: Range<usize>, _window, _cx| {
-                            this.depths
-                                .iter()
-                                .enumerate()
-                                .skip(range.start)
-                                .take(range.end - range.start)
-                                .map(|(i, depth)| {
-                                    div()
-                                        .pl(DefiniteLength::Absolute(AbsoluteLength::Pixels(px(
-                                            16. * (*depth as f32),
-                                        ))))
-                                        .child(Label::new(format!("Item {}", i)).color(Color::Info))
-                                })
-                                .collect()
-                        }),
-                    )
-                    .with_sizing_behavior(gpui::ListSizingBehavior::Infer)
-                    .with_decoration(
-                        ui::indent_guides(
-                            px(16.),
-                            ui::IndentGuideColors {
-                                default: Color::Info.color(cx),
-                                hover: Color::Accent.color(cx),
-                                active: Color::Accent.color(cx),
-                            },
-                        )
-                        .with_compute_indents_fn(
-                            cx.entity(),
-                            |this, range, _cx, _context| {
-                                this.depths
-                                    .iter()
-                                    .skip(range.start)
-                                    .take(range.end - range.start)
-                                    .cloned()
-                                    .collect()
-                            },
-                        ),
-                    ),
-                ),
-            )
-    }
-}

crates/storybook/src/stories/kitchen_sink.rs 🔗

@@ -1,32 +0,0 @@
-use gpui::{Entity, Render, prelude::*};
-use story::Story;
-use strum::IntoEnumIterator;
-use ui::prelude::*;
-
-use crate::story_selector::ComponentStory;
-
-pub struct KitchenSinkStory;
-
-impl KitchenSinkStory {
-    pub fn model(cx: &mut App) -> Entity<Self> {
-        cx.new(|_| Self)
-    }
-}
-
-impl Render for KitchenSinkStory {
-    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
-        let component_stories = ComponentStory::iter()
-            .map(|selector| selector.story(window, cx))
-            .collect::<Vec<_>>();
-
-        Story::container(cx)
-            .id("kitchen-sink")
-            .overflow_y_scroll()
-            .child(Story::title("Kitchen Sink", cx))
-            .child(Story::label("Components", cx))
-            .child(div().flex().flex_col().children(component_stories))
-            // Add a bit of space at the bottom of the kitchen sink so elements
-            // don't end up squished right up against the bottom of the screen.
-            .child(div().p_4())
-    }
-}

crates/storybook/src/stories/overflow_scroll.rs 🔗

@@ -1,41 +0,0 @@
-use gpui::Render;
-use story::Story;
-
-use ui::prelude::*;
-
-pub struct OverflowScrollStory;
-
-impl Render for OverflowScrollStory {
-    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
-        Story::container(cx)
-            .child(Story::title("Overflow Scroll", cx))
-            .child(Story::label("`overflow_x_scroll`", cx))
-            .child(
-                h_flex()
-                    .id("overflow_x_scroll")
-                    .gap_2()
-                    .overflow_x_scroll()
-                    .children((0..100).map(|i| {
-                        div()
-                            .p_4()
-                            .debug_bg_cyan()
-                            .child(SharedString::from(format!("Child {}", i + 1)))
-                    })),
-            )
-            .child(Story::label("`overflow_y_scroll`", cx))
-            .child(
-                v_flex()
-                    .w_full()
-                    .flex_1()
-                    .id("overflow_y_scroll")
-                    .gap_2()
-                    .overflow_y_scroll()
-                    .children((0..100).map(|i| {
-                        div()
-                            .p_4()
-                            .debug_bg_green()
-                            .child(SharedString::from(format!("Child {}", i + 1)))
-                    })),
-            )
-    }
-}

crates/storybook/src/stories/picker.rs 🔗

@@ -1,206 +0,0 @@
-use fuzzy::StringMatchCandidate;
-use gpui::{App, Entity, KeyBinding, Render, SharedString, Styled, Task, Window, div, prelude::*};
-use picker::{Picker, PickerDelegate};
-use std::sync::Arc;
-use ui::{Label, ListItem};
-use ui::{ListItemSpacing, prelude::*};
-
-pub struct PickerStory {
-    picker: Entity<Picker<Delegate>>,
-}
-
-struct Delegate {
-    candidates: Arc<[StringMatchCandidate]>,
-    matches: Vec<usize>,
-    selected_ix: usize,
-}
-
-impl Delegate {
-    fn new(strings: &[&str]) -> Self {
-        Self {
-            candidates: strings
-                .iter()
-                .copied()
-                .enumerate()
-                .map(|(id, string)| StringMatchCandidate::new(id, string))
-                .collect(),
-            matches: vec![],
-            selected_ix: 0,
-        }
-    }
-}
-
-impl PickerDelegate for Delegate {
-    type ListItem = ListItem;
-
-    fn match_count(&self) -> usize {
-        self.candidates.len()
-    }
-
-    fn placeholder_text(&self, _window: &mut Window, _cx: &mut App) -> Arc<str> {
-        "Test".into()
-    }
-
-    fn render_match(
-        &self,
-        ix: usize,
-        selected: bool,
-        _window: &mut Window,
-        _cx: &mut Context<Picker<Self>>,
-    ) -> Option<Self::ListItem> {
-        let candidate_ix = self.matches.get(ix)?;
-        // TASK: Make StringMatchCandidate::string a SharedString
-        let candidate = SharedString::from(self.candidates[*candidate_ix].string.clone());
-
-        Some(
-            ListItem::new(ix)
-                .inset(true)
-                .spacing(ListItemSpacing::Sparse)
-                .toggle_state(selected)
-                .child(Label::new(candidate)),
-        )
-    }
-
-    fn selected_index(&self) -> usize {
-        self.selected_ix
-    }
-
-    fn set_selected_index(&mut self, ix: usize, _: &mut Window, cx: &mut Context<Picker<Self>>) {
-        self.selected_ix = ix;
-        cx.notify();
-    }
-
-    fn confirm(&mut self, secondary: bool, _window: &mut Window, _cx: &mut Context<Picker<Self>>) {
-        let candidate_ix = self.matches[self.selected_ix];
-        let candidate = self.candidates[candidate_ix].string.clone();
-
-        if secondary {
-            eprintln!("Secondary confirmed {}", candidate)
-        } else {
-            eprintln!("Confirmed {}", candidate)
-        }
-    }
-
-    fn dismissed(&mut self, _: &mut Window, cx: &mut Context<Picker<Self>>) {
-        cx.quit();
-    }
-
-    fn update_matches(
-        &mut self,
-        query: String,
-        _: &mut Window,
-        cx: &mut Context<Picker<Self>>,
-    ) -> Task<()> {
-        let candidates = self.candidates.clone();
-        self.matches = cx
-            .foreground_executor()
-            .block_on(fuzzy::match_strings(
-                &candidates,
-                &query,
-                true,
-                true,
-                100,
-                &Default::default(),
-                cx.background_executor().clone(),
-            ))
-            .into_iter()
-            .map(|r| r.candidate_id)
-            .collect();
-        self.selected_ix = 0;
-        Task::ready(())
-    }
-}
-
-impl PickerStory {
-    pub fn new(window: &mut Window, cx: &mut App) -> Entity<Self> {
-        cx.new(|cx| {
-            cx.bind_keys([
-                KeyBinding::new("up", menu::SelectPrevious, Some("picker")),
-                KeyBinding::new("pageup", menu::SelectFirst, Some("picker")),
-                KeyBinding::new("shift-pageup", menu::SelectFirst, Some("picker")),
-                KeyBinding::new("ctrl-p", menu::SelectPrevious, Some("picker")),
-                KeyBinding::new("down", menu::SelectNext, Some("picker")),
-                KeyBinding::new("pagedown", menu::SelectLast, Some("picker")),
-                KeyBinding::new("shift-pagedown", menu::SelectFirst, Some("picker")),
-                KeyBinding::new("ctrl-n", menu::SelectNext, Some("picker")),
-                KeyBinding::new("cmd-up", menu::SelectFirst, Some("picker")),
-                KeyBinding::new("cmd-down", menu::SelectLast, Some("picker")),
-                KeyBinding::new("enter", menu::Confirm, Some("picker")),
-                KeyBinding::new("ctrl-enter", menu::SecondaryConfirm, Some("picker")),
-                KeyBinding::new("cmd-enter", menu::SecondaryConfirm, Some("picker")),
-                KeyBinding::new("escape", menu::Cancel, Some("picker")),
-                KeyBinding::new("ctrl-c", menu::Cancel, Some("picker")),
-            ]);
-
-            PickerStory {
-                picker: cx.new(|cx| {
-                    let mut delegate = Delegate::new(&[
-                        "Baguette (France)",
-                        "Baklava (Turkey)",
-                        "Beef Wellington (UK)",
-                        "Biryani (India)",
-                        "Borscht (Ukraine)",
-                        "Bratwurst (Germany)",
-                        "Bulgogi (Korea)",
-                        "Burrito (USA)",
-                        "Ceviche (Peru)",
-                        "Chicken Tikka Masala (India)",
-                        "Churrasco (Brazil)",
-                        "Couscous (North Africa)",
-                        "Croissant (France)",
-                        "Dim Sum (China)",
-                        "Empanada (Argentina)",
-                        "Fajitas (Mexico)",
-                        "Falafel (Middle East)",
-                        "Feijoada (Brazil)",
-                        "Fish and Chips (UK)",
-                        "Fondue (Switzerland)",
-                        "Goulash (Hungary)",
-                        "Haggis (Scotland)",
-                        "Kebab (Middle East)",
-                        "Kimchi (Korea)",
-                        "Lasagna (Italy)",
-                        "Maple Syrup Pancakes (Canada)",
-                        "Moussaka (Greece)",
-                        "Pad Thai (Thailand)",
-                        "Paella (Spain)",
-                        "Pancakes (USA)",
-                        "Pasta Carbonara (Italy)",
-                        "Pavlova (Australia)",
-                        "Peking Duck (China)",
-                        "Pho (Vietnam)",
-                        "Pierogi (Poland)",
-                        "Pizza (Italy)",
-                        "Poutine (Canada)",
-                        "Pretzel (Germany)",
-                        "Ramen (Japan)",
-                        "Rendang (Indonesia)",
-                        "Sashimi (Japan)",
-                        "Satay (Indonesia)",
-                        "Shepherd's Pie (Ireland)",
-                        "Sushi (Japan)",
-                        "Tacos (Mexico)",
-                        "Tandoori Chicken (India)",
-                        "Tortilla (Spain)",
-                        "Tzatziki (Greece)",
-                        "Wiener Schnitzel (Austria)",
-                    ]);
-                    delegate.update_matches("".into(), window, cx).detach();
-
-                    let picker = Picker::uniform_list(delegate, window, cx);
-                    picker.focus(window, cx);
-                    picker
-                }),
-            }
-        })
-    }
-}
-
-impl Render for PickerStory {
-    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
-        div()
-            .bg(cx.theme().styles.colors.background)
-            .size_full()
-            .child(self.picker.clone())
-    }
-}

crates/storybook/src/stories/scroll.rs 🔗

@@ -1,52 +0,0 @@
-use gpui::{App, Entity, Render, SharedString, Styled, Window, div, prelude::*, px};
-use ui::Tooltip;
-use ui::prelude::*;
-
-pub struct ScrollStory;
-
-impl ScrollStory {
-    pub fn model(cx: &mut App) -> Entity<ScrollStory> {
-        cx.new(|_| ScrollStory)
-    }
-}
-
-impl Render for ScrollStory {
-    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
-        let theme = cx.theme();
-        let color_1 = theme.status().created;
-        let color_2 = theme.status().modified;
-
-        div()
-            .id("parent")
-            .bg(theme.colors().background)
-            .size_full()
-            .overflow_scroll()
-            .children((0..10).map(|row| {
-                div()
-                    .w(px(1000.))
-                    .h(px(100.))
-                    .flex()
-                    .flex_row()
-                    .children((0..10).map(|column| {
-                        let id = SharedString::from(format!("{}, {}", row, column));
-                        let bg = if row % 2 == column % 2 {
-                            color_1
-                        } else {
-                            color_2
-                        };
-                        div()
-                            .id(id.clone())
-                            .tooltip(Tooltip::text(id))
-                            .bg(bg)
-                            .size(px(100_f32))
-                            .when(row >= 5 && column >= 5, |d| {
-                                d.overflow_scroll()
-                                    .child(div().size(px(50.)).bg(color_1))
-                                    .child(div().size(px(50.)).bg(color_2))
-                                    .child(div().size(px(50.)).bg(color_1))
-                                    .child(div().size(px(50.)).bg(color_2))
-                            })
-                    }))
-            }))
-    }
-}

crates/storybook/src/stories/text.rs 🔗

@@ -1,120 +0,0 @@
-use gpui::{
-    App, AppContext as _, Context, Entity, HighlightStyle, InteractiveText, IntoElement,
-    ParentElement, Render, Styled, StyledText, Window, div, green, red,
-};
-use indoc::indoc;
-use story::*;
-
-pub struct TextStory;
-
-impl TextStory {
-    pub fn model(cx: &mut App) -> Entity<Self> {
-        cx.new(|_| Self)
-    }
-}
-
-impl Render for TextStory {
-    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
-        Story::container(cx)
-            .child(Story::title("Text", cx))
-            .children(vec![
-                StorySection::new()
-                    .child(
-                        StoryItem::new("Default", div().bg(gpui::blue()).child("Hello World!"))
-                            .usage(indoc! {r##"
-                                div()
-                                    .child("Hello World!")
-                                "##
-                            }),
-                    )
-                    .child(
-                        StoryItem::new(
-                            "Wrapping Text",
-                            div().max_w_96().child(concat!(
-                                "The quick brown fox jumps over the lazy dog. ",
-                                "Meanwhile, the lazy dog decided it was time for a change. ",
-                                "He started daily workout routines, ate healthier and became the fastest dog in town.",
-                            )),
-                        )
-                        .description("Set a width or max-width to enable text wrapping.")
-                        .usage(indoc! {r##"
-                            div()
-                                .max_w_96()
-                                .child("Some text that you want to wrap.")
-                            "##
-                        }),
-                    )
-                    .child(
-                        StoryItem::new(
-                            "tbd",
-                            div().flex().w_96().child(
-                                div().overflow_hidden().child(concat!(
-                                    "flex-row. width 96. overflow-hidden. The quick brown fox jumps over the lazy dog. ",
-                                    "Meanwhile, the lazy dog decided it was time for a change. ",
-                                    "He started daily workout routines, ate healthier and became the fastest dog in town.",
-                                )),
-                            ),
-                        ),
-                    )
-                    .child(
-                        StoryItem::new(
-                            "Text in Horizontal Flex",
-                            div().flex().w_96().bg(red()).child(concat!(
-                                "flex-row. width 96. The quick brown fox jumps over the lazy dog. ",
-                                "Meanwhile, the lazy dog decided it was time for a change. ",
-                                "He started daily workout routines, ate healthier and became the fastest dog in town.",
-                            )),
-                        )
-                        .usage(indoc! {r##"
-                            // NOTE: When rendering text in a horizontal flex container,
-                            // Taffy will not pass width constraints down from the parent.
-                            // To fix this, render text in a parent with overflow: hidden
-
-                            div()
-                                .max_w_96()
-                                .child("Some text that you want to wrap.")
-                            "##
-                        }),
-                    )
-                    .child(
-                        StoryItem::new(
-                            "Interactive Text",
-                            InteractiveText::new(
-                                "interactive",
-                                StyledText::new("Hello world, how is it going?").with_default_highlights(
-                                    &window.text_style(),
-                                    [
-                                        (
-                                            6..11,
-                                            HighlightStyle {
-                                                background_color: Some(green()),
-                                                ..Default::default()
-                                            },
-                                        ),
-                                    ],
-                                ),
-                            )
-                            .on_click(vec![2..4, 1..3, 7..9], |range_ix, _, _cx| {
-                                println!("Clicked range {range_ix}");
-                            }),
-                        )
-                        .usage(indoc! {r##"
-                            InteractiveText::new(
-                                "interactive",
-                                StyledText::new("Hello world, how is it going?").with_highlights(&window.text_style(), [
-                                    (6..11, HighlightStyle {
-                                        background_color: Some(green()),
-                                        ..Default::default()
-                                    }),
-                                ]),
-                            )
-                            .on_click(vec![2..4, 1..3, 7..9], |range_ix, _cx| {
-                                println!("Clicked range {range_ix}");
-                            })
-                            "##
-                        }),
-                    ),
-            ])
-            .into_element()
-    }
-}

crates/storybook/src/stories/viewport_units.rs 🔗

@@ -1,32 +0,0 @@
-use gpui::Render;
-use story::Story;
-
-use ui::prelude::*;
-
-pub struct ViewportUnitsStory;
-
-impl Render for ViewportUnitsStory {
-    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
-        Story::container(cx).child(
-            div()
-                .flex()
-                .flex_row()
-                .child(
-                    div()
-                        .w(vw(0.5, window))
-                        .h(vh(0.8, window))
-                        .bg(gpui::red())
-                        .text_color(gpui::white())
-                        .child("50vw, 80vh"),
-                )
-                .child(
-                    div()
-                        .w(vw(0.25, window))
-                        .h(vh(0.33, window))
-                        .bg(gpui::green())
-                        .text_color(gpui::white())
-                        .child("25vw, 33vh"),
-                ),
-        )
-    }
-}

crates/storybook/src/stories/with_rem_size.rs 🔗

@@ -1,61 +0,0 @@
-use gpui::{AnyElement, Hsla, Render};
-use story::Story;
-
-use ui::{prelude::*, utils::WithRemSize};
-
-pub struct WithRemSizeStory;
-
-impl Render for WithRemSizeStory {
-    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
-        Story::container(cx).child(
-            Example::new(16., gpui::red())
-                .child(
-                    Example::new(24., gpui::green())
-                        .child(Example::new(8., gpui::blue()))
-                        .child(Example::new(16., gpui::yellow())),
-                )
-                .child(
-                    Example::new(12., gpui::green())
-                        .child(Example::new(48., gpui::blue()))
-                        .child(Example::new(16., gpui::yellow())),
-                ),
-        )
-    }
-}
-
-#[derive(IntoElement)]
-struct Example {
-    rem_size: Pixels,
-    border_color: Hsla,
-    children: Vec<AnyElement>,
-}
-
-impl Example {
-    pub fn new(rem_size: impl Into<Pixels>, border_color: Hsla) -> Self {
-        Self {
-            rem_size: rem_size.into(),
-            border_color,
-            children: Vec::new(),
-        }
-    }
-}
-
-impl ParentElement for Example {
-    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
-        self.children.extend(elements);
-    }
-}
-
-impl RenderOnce for Example {
-    fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
-        WithRemSize::new(self.rem_size).child(
-            v_flex()
-                .gap_2()
-                .p_2()
-                .border_2()
-                .border_color(self.border_color)
-                .child(Label::new(format!("1rem = {}px", f32::from(self.rem_size))))
-                .children(self.children),
-        )
-    }
-}

crates/storybook/src/story_selector.rs 🔗

@@ -1,109 +0,0 @@
-use std::str::FromStr;
-use std::sync::OnceLock;
-
-use crate::stories::*;
-use clap::ValueEnum;
-use clap::builder::PossibleValue;
-use gpui::AnyView;
-use strum::{EnumIter, EnumString, IntoEnumIterator};
-use ui::prelude::*;
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy, strum::Display, EnumString, EnumIter)]
-#[strum(serialize_all = "snake_case")]
-pub enum ComponentStory {
-    ApplicationMenu,
-    AutoHeightEditor,
-    ContextMenu,
-    Cursor,
-    Focus,
-    OverflowScroll,
-    Picker,
-    Scroll,
-    Text,
-    ViewportUnits,
-    WithRemSize,
-    IndentGuides,
-}
-
-impl ComponentStory {
-    pub fn story(&self, window: &mut Window, cx: &mut App) -> AnyView {
-        match self {
-            Self::ApplicationMenu => cx
-                .new(|cx| title_bar::ApplicationMenuStory::new(window, cx))
-                .into(),
-            Self::AutoHeightEditor => AutoHeightEditorStory::new(window, cx).into(),
-            Self::ContextMenu => cx.new(|_| ui::ContextMenuStory).into(),
-            Self::Cursor => cx.new(|_| crate::stories::CursorStory).into(),
-            Self::Focus => FocusStory::model(window, cx).into(),
-            Self::OverflowScroll => cx.new(|_| crate::stories::OverflowScrollStory).into(),
-            Self::Picker => PickerStory::new(window, cx).into(),
-            Self::Scroll => ScrollStory::model(cx).into(),
-            Self::Text => TextStory::model(cx).into(),
-            Self::ViewportUnits => cx.new(|_| crate::stories::ViewportUnitsStory).into(),
-            Self::WithRemSize => cx.new(|_| crate::stories::WithRemSizeStory).into(),
-            Self::IndentGuides => crate::stories::IndentGuidesStory::model(window, cx).into(),
-        }
-    }
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-pub enum StorySelector {
-    Component(ComponentStory),
-    KitchenSink,
-}
-
-impl FromStr for StorySelector {
-    type Err = anyhow::Error;
-
-    fn from_str(raw_story_name: &str) -> std::result::Result<Self, Self::Err> {
-        use anyhow::Context as _;
-
-        let story = raw_story_name.to_ascii_lowercase();
-
-        if story == "kitchen_sink" {
-            return Ok(Self::KitchenSink);
-        }
-
-        if let Some((_, story)) = story.split_once("components/") {
-            let component_story = ComponentStory::from_str(story)
-                .with_context(|| format!("story not found for component '{story}'"))?;
-
-            return Ok(Self::Component(component_story));
-        }
-
-        anyhow::bail!("story not found for '{raw_story_name}'")
-    }
-}
-
-impl StorySelector {
-    pub fn story(&self, window: &mut Window, cx: &mut App) -> AnyView {
-        match self {
-            Self::Component(component_story) => component_story.story(window, cx),
-            Self::KitchenSink => KitchenSinkStory::model(cx).into(),
-        }
-    }
-}
-
-/// The list of all stories available in the storybook.
-static ALL_STORY_SELECTORS: OnceLock<Vec<StorySelector>> = OnceLock::new();
-
-impl ValueEnum for StorySelector {
-    fn value_variants<'a>() -> &'a [Self] {
-        (ALL_STORY_SELECTORS.get_or_init(|| {
-            let component_stories = ComponentStory::iter().map(StorySelector::Component);
-
-            component_stories
-                .chain(std::iter::once(StorySelector::KitchenSink))
-                .collect::<Vec<_>>()
-        })) as _
-    }
-
-    fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> {
-        let value = match self {
-            Self::Component(story) => format!("components/{story}"),
-            Self::KitchenSink => "kitchen_sink".to_string(),
-        };
-
-        Some(PossibleValue::new(value))
-    }
-}

crates/storybook/src/storybook.rs 🔗

@@ -1,162 +0,0 @@
-mod actions;
-mod app_menus;
-mod assets;
-mod stories;
-mod story_selector;
-
-use std::sync::Arc;
-
-use clap::Parser;
-use dialoguer::FuzzySelect;
-use gpui::{
-    AnyView, App, Bounds, Context, Render, Window, WindowBounds, WindowOptions,
-    colors::{Colors, GlobalColors},
-    div, px, size,
-};
-use log::LevelFilter;
-use reqwest_client::ReqwestClient;
-use settings::{KeymapFile, Settings as _};
-use simplelog::SimpleLogger;
-use strum::IntoEnumIterator;
-use theme_settings::ThemeSettings;
-use ui::prelude::*;
-
-use crate::app_menus::app_menus;
-use crate::assets::Assets;
-use crate::story_selector::{ComponentStory, StorySelector};
-use actions::Quit;
-pub use indoc::indoc;
-
-#[derive(Parser)]
-#[command(author, version, about, long_about = None)]
-struct Args {
-    #[arg(value_enum)]
-    story: Option<StorySelector>,
-
-    /// The name of the theme to use in the storybook.
-    ///
-    /// If not provided, the default theme will be used.
-    #[arg(long)]
-    theme: Option<String>,
-}
-
-fn main() {
-    SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger");
-
-    menu::init();
-    let args = Args::parse();
-
-    let story_selector = args.story.unwrap_or_else(|| {
-        let stories = ComponentStory::iter().collect::<Vec<_>>();
-
-        ctrlc::set_handler(move || {}).unwrap();
-
-        let result = FuzzySelect::new()
-            .with_prompt("Choose a story to run:")
-            .items(&stories)
-            .interact();
-
-        let Ok(selection) = result else {
-            dialoguer::console::Term::stderr().show_cursor().unwrap();
-            std::process::exit(0);
-        };
-
-        StorySelector::Component(stories[selection])
-    });
-    let theme_name = args.theme.unwrap_or("One Dark".to_string());
-
-    gpui_platform::application()
-        .with_assets(Assets)
-        .run(move |cx| {
-            load_embedded_fonts(cx).unwrap();
-
-            cx.set_global(GlobalColors(Arc::new(Colors::default())));
-
-            let http_client = ReqwestClient::user_agent("zed_storybook").unwrap();
-            cx.set_http_client(Arc::new(http_client));
-
-            settings::init(cx);
-            theme_settings::init(theme::LoadThemes::All(Box::new(Assets)), cx);
-
-            let selector = story_selector;
-
-            let mut theme_settings = ThemeSettings::get_global(cx).clone();
-            theme_settings.theme =
-                theme_settings::ThemeSelection::Static(settings::ThemeName(theme_name.into()));
-            ThemeSettings::override_global(theme_settings, cx);
-
-            editor::init(cx);
-            init(cx);
-            load_storybook_keymap(cx);
-            cx.set_menus(app_menus());
-
-            let size = size(px(1500.), px(780.));
-            let bounds = Bounds::centered(None, size, cx);
-            let _window = cx.open_window(
-                WindowOptions {
-                    window_bounds: Some(WindowBounds::Windowed(bounds)),
-                    ..Default::default()
-                },
-                move |window, cx| {
-                    theme_settings::setup_ui_font(window, cx);
-
-                    cx.new(|cx| StoryWrapper::new(selector.story(window, cx)))
-                },
-            );
-
-            cx.activate(true);
-        });
-}
-
-#[derive(Clone)]
-pub struct StoryWrapper {
-    story: AnyView,
-}
-
-impl StoryWrapper {
-    pub(crate) fn new(story: AnyView) -> Self {
-        Self { story }
-    }
-}
-
-impl Render for StoryWrapper {
-    fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
-        div()
-            .flex()
-            .flex_col()
-            .size_full()
-            .font_family(".ZedMono")
-            .child(self.story.clone())
-    }
-}
-
-fn load_embedded_fonts(cx: &App) -> anyhow::Result<()> {
-    let font_paths = cx.asset_source().list("fonts")?;
-    let mut embedded_fonts = Vec::new();
-    for font_path in font_paths {
-        if font_path.ends_with(".ttf") {
-            let font_bytes = cx
-                .asset_source()
-                .load(&font_path)?
-                .expect("Should never be None in the storybook");
-            embedded_fonts.push(font_bytes);
-        }
-    }
-
-    cx.text_system().add_fonts(embedded_fonts)
-}
-
-fn load_storybook_keymap(cx: &mut App) {
-    cx.bind_keys(KeymapFile::load_asset("keymaps/storybook.json", None, cx).unwrap());
-}
-
-pub fn init(cx: &mut App) {
-    cx.on_action(quit);
-}
-
-fn quit(_: &Quit, cx: &mut App) {
-    cx.spawn(async move |cx| {
-        cx.update(|cx| cx.quit());
-    })
-    .detach();
-}

crates/theme/Cargo.toml 🔗

@@ -19,7 +19,6 @@ doctest = false
 [dependencies]
 anyhow.workspace = true
 collections.workspace = true
-derive_more.workspace = true
 gpui.workspace = true
 syntax_theme.workspace = true
 palette = { workspace = true, default-features = false, features = ["std"] }

crates/theme/src/registry.rs 🔗

@@ -3,7 +3,6 @@ use std::{fmt::Debug, path::Path};
 
 use anyhow::Result;
 use collections::HashMap;
-use derive_more::{Deref, DerefMut};
 use gpui::{App, AssetSource, Global, SharedString};
 use parking_lot::RwLock;
 use thiserror::Error;
@@ -38,9 +37,23 @@ pub struct IconThemeNotFoundError(pub SharedString);
 /// inserting the [`ThemeRegistry`] into the context as a global.
 ///
 /// This should not be exposed outside of this module.
-#[derive(Default, Deref, DerefMut)]
+#[derive(Default)]
 struct GlobalThemeRegistry(Arc<ThemeRegistry>);
 
+impl std::ops::DerefMut for GlobalThemeRegistry {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+impl std::ops::Deref for GlobalThemeRegistry {
+    type Target = Arc<ThemeRegistry>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
 impl Global for GlobalThemeRegistry {}
 
 struct ThemeRegistryState {

crates/theme/src/theme.rs 🔗

@@ -22,7 +22,6 @@ mod ui_density;
 
 use std::sync::Arc;
 
-use derive_more::{Deref, DerefMut};
 use gpui::BorrowAppContext;
 use gpui::Global;
 use gpui::{
@@ -129,18 +128,40 @@ impl ActiveTheme for App {
 }
 
 /// The appearance of the system.
-#[derive(Debug, Clone, Copy, Deref)]
+#[derive(Debug, Clone, Copy)]
 pub struct SystemAppearance(pub Appearance);
 
+impl std::ops::Deref for SystemAppearance {
+    type Target = Appearance;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
 impl Default for SystemAppearance {
     fn default() -> Self {
         Self(Appearance::Dark)
     }
 }
 
-#[derive(Deref, DerefMut, Default)]
+#[derive(Default)]
 struct GlobalSystemAppearance(SystemAppearance);
 
+impl std::ops::DerefMut for GlobalSystemAppearance {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+impl std::ops::Deref for GlobalSystemAppearance {
+    type Target = SystemAppearance;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
 impl Global for GlobalSystemAppearance {}
 
 impl SystemAppearance {

crates/title_bar/Cargo.toml 🔗

@@ -14,7 +14,7 @@ doctest = false
 
 [features]
 default = []
-stories = ["dep:story"]
+
 test-support = [
     "call/test-support",
     "client/test-support",
@@ -53,7 +53,6 @@ schemars.workspace = true
 serde.workspace = true
 settings.workspace = true
 smallvec.workspace = true
-story = { workspace = true, optional = true }
 telemetry.workspace = true
 theme.workspace = true
 ui.workspace = true

crates/title_bar/src/stories/application_menu.rs 🔗

@@ -1,29 +0,0 @@
-use gpui::{Entity, Render};
-use story::{Story, StoryItem, StorySection};
-
-use ui::prelude::*;
-
-use crate::application_menu::ApplicationMenu;
-
-pub struct ApplicationMenuStory {
-    menu: Entity<ApplicationMenu>,
-}
-
-impl ApplicationMenuStory {
-    pub fn new(window: &mut Window, cx: &mut App) -> Self {
-        Self {
-            menu: cx.new(|cx| ApplicationMenu::new(window, cx)),
-        }
-    }
-}
-
-impl Render for ApplicationMenuStory {
-    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
-        Story::container(cx)
-            .child(Story::title_for::<ApplicationMenu>(cx))
-            .child(StorySection::new().child(StoryItem::new(
-                "Application Menu",
-                h_flex().child(self.menu.clone()),
-            )))
-    }
-}

crates/title_bar/src/title_bar.rs 🔗

@@ -5,9 +5,6 @@ mod plan_chip;
 mod title_bar_settings;
 mod update_version;
 
-#[cfg(feature = "stories")]
-mod stories;
-
 use crate::application_menu::{ApplicationMenu, show_menus};
 use crate::plan_chip::PlanChip;
 pub use platform_title_bar::{
@@ -56,9 +53,6 @@ use zed_actions::OpenRemote;
 
 pub use onboarding_banner::restore_banner;
 
-#[cfg(feature = "stories")]
-pub use stories::*;
-
 const MAX_PROJECT_NAME_LENGTH: usize = 40;
 const MAX_BRANCH_NAME_LENGTH: usize = 40;
 const MAX_SHORT_SHA_LENGTH: usize = 8;

crates/ui/Cargo.toml 🔗

@@ -24,7 +24,6 @@ menu.workspace = true
 schemars.workspace = true
 serde.workspace = true
 smallvec.workspace = true
-story = { workspace = true, optional = true }
 strum.workspace = true
 theme.workspace = true
 ui_macros.workspace = true
@@ -38,4 +37,3 @@ gpui = { workspace = true, features = ["test-support"] }
 
 [features]
 default = []
-stories = ["dep:story"]

crates/ui/src/components.rs 🔗

@@ -40,9 +40,6 @@ mod toggle;
 mod tooltip;
 mod tree_view_item;
 
-#[cfg(feature = "stories")]
-mod stories;
-
 pub use ai::*;
 pub use avatar::*;
 pub use banner::*;
@@ -84,6 +81,3 @@ pub use tab_bar::*;
 pub use toggle::*;
 pub use tooltip::*;
 pub use tree_view_item::*;
-
-#[cfg(feature = "stories")]
-pub use stories::*;

crates/ui/src/components/stories/context_menu.rs 🔗

@@ -1,81 +0,0 @@
-use gpui::{Corner, Entity, Render, actions};
-use story::Story;
-
-use crate::prelude::*;
-use crate::{ContextMenu, Label, right_click_menu};
-
-actions!(stories, [PrintCurrentDate, PrintBestFood]);
-
-fn build_menu(
-    window: &mut Window,
-    cx: &mut App,
-    header: impl Into<SharedString>,
-) -> Entity<ContextMenu> {
-    ContextMenu::build(window, cx, |menu, _, _| {
-        menu.header(header)
-            .separator()
-            .action("Print current time", Box::new(PrintCurrentDate))
-            .entry(
-                "Print best food",
-                Some(Box::new(PrintBestFood)),
-                |window, cx| window.dispatch_action(Box::new(PrintBestFood), cx),
-            )
-    })
-}
-
-pub struct ContextMenuStory;
-
-impl Render for ContextMenuStory {
-    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
-        Story::container(cx)
-            .on_action(|_: &PrintCurrentDate, _, _| {
-                println!("printing unix time!");
-                if let Ok(unix_time) = std::time::UNIX_EPOCH.elapsed() {
-                    println!("Current Unix time is {:?}", unix_time.as_secs());
-                }
-            })
-            .on_action(|_: &PrintBestFood, _, _| {
-                println!("burrito");
-            })
-            .flex()
-            .flex_row()
-            .justify_between()
-            .child(
-                div()
-                    .flex()
-                    .flex_col()
-                    .justify_between()
-                    .child(
-                        right_click_menu("test2")
-                            .trigger(|_, _, _| Label::new("TOP LEFT"))
-                            .menu(move |window, cx| build_menu(window, cx, "top left")),
-                    )
-                    .child(
-                        right_click_menu("test1")
-                            .trigger(|_, _, _| Label::new("BOTTOM LEFT"))
-                            .anchor(Corner::BottomLeft)
-                            .attach(Corner::TopLeft)
-                            .menu(move |window, cx| build_menu(window, cx, "bottom left")),
-                    ),
-            )
-            .child(
-                div()
-                    .flex()
-                    .flex_col()
-                    .justify_between()
-                    .child(
-                        right_click_menu("test3")
-                            .trigger(|_, _, _| Label::new("TOP RIGHT"))
-                            .anchor(Corner::TopRight)
-                            .menu(move |window, cx| build_menu(window, cx, "top right")),
-                    )
-                    .child(
-                        right_click_menu("test4")
-                            .trigger(|_, _, _| Label::new("BOTTOM RIGHT"))
-                            .anchor(Corner::BottomRight)
-                            .attach(Corner::TopRight)
-                            .menu(move |window, cx| build_menu(window, cx, "bottom right")),
-                    ),
-            )
-    }
-}