From f2ee61553f58abb435fb996ffe60040fa26a1ce8 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Tue, 10 Oct 2023 16:00:04 -0400 Subject: [PATCH] Colocate element stories with their elements --- crates/storybook2/src/stories.rs | 2 +- crates/storybook2/src/stories/elements.rs | 7 - .../storybook2/src/stories/elements/avatar.rs | 33 --- .../storybook2/src/stories/elements/button.rs | 200 ----------------- .../src/stories/elements/details.rs | 31 --- .../storybook2/src/stories/elements/icon.rs | 29 --- .../storybook2/src/stories/elements/input.rs | 26 --- .../storybook2/src/stories/elements/label.rs | 28 --- .../src/stories/{elements => }/z_index.rs | 0 crates/storybook2/src/story_selector.rs | 16 +- crates/ui2/src/elements/avatar.rs | 37 ++++ crates/ui2/src/elements/button.rs | 203 ++++++++++++++++++ crates/ui2/src/elements/details.rs | 35 +++ crates/ui2/src/elements/icon.rs | 34 +++ crates/ui2/src/elements/input.rs | 30 +++ crates/ui2/src/elements/label.rs | 32 +++ 16 files changed, 379 insertions(+), 364 deletions(-) delete mode 100644 crates/storybook2/src/stories/elements.rs delete mode 100644 crates/storybook2/src/stories/elements/avatar.rs delete mode 100644 crates/storybook2/src/stories/elements/button.rs delete mode 100644 crates/storybook2/src/stories/elements/details.rs delete mode 100644 crates/storybook2/src/stories/elements/icon.rs delete mode 100644 crates/storybook2/src/stories/elements/input.rs delete mode 100644 crates/storybook2/src/stories/elements/label.rs rename crates/storybook2/src/stories/{elements => }/z_index.rs (100%) diff --git a/crates/storybook2/src/stories.rs b/crates/storybook2/src/stories.rs index 5df182e193..a7b09443e6 100644 --- a/crates/storybook2/src/stories.rs +++ b/crates/storybook2/src/stories.rs @@ -1,2 +1,2 @@ -pub mod elements; pub mod kitchen_sink; +pub mod z_index; diff --git a/crates/storybook2/src/stories/elements.rs b/crates/storybook2/src/stories/elements.rs deleted file mode 100644 index 1807e0efdc..0000000000 --- a/crates/storybook2/src/stories/elements.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub mod avatar; -pub mod button; -pub mod details; -pub mod icon; -pub mod input; -pub mod label; -pub mod z_index; diff --git a/crates/storybook2/src/stories/elements/avatar.rs b/crates/storybook2/src/stories/elements/avatar.rs deleted file mode 100644 index 36fc841b9f..0000000000 --- a/crates/storybook2/src/stories/elements/avatar.rs +++ /dev/null @@ -1,33 +0,0 @@ -use std::marker::PhantomData; - -use ui::prelude::*; -use ui::Avatar; - -use crate::story::Story; - -#[derive(Element)] -pub struct AvatarStory { - state_type: PhantomData, -} - -impl AvatarStory { - pub fn new() -> Self { - Self { - state_type: PhantomData, - } - } - - fn render(&mut self, cx: &mut ViewContext) -> impl Element { - Story::container(cx) - .child(Story::title_for::<_, Avatar>(cx)) - .child(Story::label(cx, "Default")) - .child(Avatar::new( - "https://avatars.githubusercontent.com/u/1714999?v=4", - )) - .child(Story::label(cx, "Rounded rectangle")) - .child( - Avatar::new("https://avatars.githubusercontent.com/u/1714999?v=4") - .shape(Shape::RoundedRectangle), - ) - } -} diff --git a/crates/storybook2/src/stories/elements/button.rs b/crates/storybook2/src/stories/elements/button.rs deleted file mode 100644 index 650d9fd9f7..0000000000 --- a/crates/storybook2/src/stories/elements/button.rs +++ /dev/null @@ -1,200 +0,0 @@ -use std::marker::PhantomData; - -use gpui3::rems; -use strum::IntoEnumIterator; -use ui::prelude::*; -use ui::{h_stack, v_stack, Button, Icon, IconPosition, Label}; - -use crate::story::Story; - -#[derive(Element)] -pub struct ButtonStory { - state_type: PhantomData, -} - -impl ButtonStory { - pub fn new() -> Self { - Self { - state_type: PhantomData, - } - } - - fn render(&mut self, cx: &mut ViewContext) -> impl Element { - let states = InteractionState::iter(); - - Story::container(cx) - .child(Story::title_for::<_, Button>(cx)) - .child( - div() - .flex() - .gap_8() - .child( - div() - .child(Story::label(cx, "Ghost (Default)")) - .child(h_stack().gap_2().children(states.clone().map(|state| { - v_stack() - .gap_1() - .child( - Label::new(state.to_string()) - .color(ui::LabelColor::Muted) - .size(ui::LabelSize::Small), - ) - .child( - Button::new("Label") - .variant(ButtonVariant::Ghost) - .state(state), - ) - }))) - .child(Story::label(cx, "Ghost – Left Icon")) - .child(h_stack().gap_2().children(states.clone().map(|state| { - v_stack() - .gap_1() - .child( - Label::new(state.to_string()) - .color(ui::LabelColor::Muted) - .size(ui::LabelSize::Small), - ) - .child( - Button::new("Label") - .variant(ButtonVariant::Ghost) - .icon(Icon::Plus) - .icon_position(IconPosition::Left) - .state(state), - ) - }))) - .child(Story::label(cx, "Ghost – Right Icon")) - .child(h_stack().gap_2().children(states.clone().map(|state| { - v_stack() - .gap_1() - .child( - Label::new(state.to_string()) - .color(ui::LabelColor::Muted) - .size(ui::LabelSize::Small), - ) - .child( - Button::new("Label") - .variant(ButtonVariant::Ghost) - .icon(Icon::Plus) - .icon_position(IconPosition::Right) - .state(state), - ) - }))), - ) - .child( - div() - .child(Story::label(cx, "Filled")) - .child(h_stack().gap_2().children(states.clone().map(|state| { - v_stack() - .gap_1() - .child( - Label::new(state.to_string()) - .color(ui::LabelColor::Muted) - .size(ui::LabelSize::Small), - ) - .child( - Button::new("Label") - .variant(ButtonVariant::Filled) - .state(state), - ) - }))) - .child(Story::label(cx, "Filled – Left Button")) - .child(h_stack().gap_2().children(states.clone().map(|state| { - v_stack() - .gap_1() - .child( - Label::new(state.to_string()) - .color(ui::LabelColor::Muted) - .size(ui::LabelSize::Small), - ) - .child( - Button::new("Label") - .variant(ButtonVariant::Filled) - .icon(Icon::Plus) - .icon_position(IconPosition::Left) - .state(state), - ) - }))) - .child(Story::label(cx, "Filled – Right Button")) - .child(h_stack().gap_2().children(states.clone().map(|state| { - v_stack() - .gap_1() - .child( - Label::new(state.to_string()) - .color(ui::LabelColor::Muted) - .size(ui::LabelSize::Small), - ) - .child( - Button::new("Label") - .variant(ButtonVariant::Filled) - .icon(Icon::Plus) - .icon_position(IconPosition::Right) - .state(state), - ) - }))), - ) - .child( - div() - .child(Story::label(cx, "Fixed With")) - .child(h_stack().gap_2().children(states.clone().map(|state| { - v_stack() - .gap_1() - .child( - Label::new(state.to_string()) - .color(ui::LabelColor::Muted) - .size(ui::LabelSize::Small), - ) - .child( - Button::new("Label") - .variant(ButtonVariant::Filled) - .state(state) - .width(Some(rems(6.).into())), - ) - }))) - .child(Story::label(cx, "Fixed With – Left Icon")) - .child(h_stack().gap_2().children(states.clone().map(|state| { - v_stack() - .gap_1() - .child( - Label::new(state.to_string()) - .color(ui::LabelColor::Muted) - .size(ui::LabelSize::Small), - ) - .child( - Button::new("Label") - .variant(ButtonVariant::Filled) - .state(state) - .icon(Icon::Plus) - .icon_position(IconPosition::Left) - .width(Some(rems(6.).into())), - ) - }))) - .child(Story::label(cx, "Fixed With – Right Icon")) - .child(h_stack().gap_2().children(states.clone().map(|state| { - v_stack() - .gap_1() - .child( - Label::new(state.to_string()) - .color(ui::LabelColor::Muted) - .size(ui::LabelSize::Small), - ) - .child( - Button::new("Label") - .variant(ButtonVariant::Filled) - .state(state) - .icon(Icon::Plus) - .icon_position(IconPosition::Right) - .width(Some(rems(6.).into())), - ) - }))), - ), - ) - .child(Story::label(cx, "Button with `on_click`")) - .child( - Button::new("Label") - .variant(ButtonVariant::Ghost) - // NOTE: There currently appears to be a bug in GPUI2 where only the last event handler will fire. - // So adding additional buttons with `on_click`s after this one will cause this `on_click` to not fire. - // .on_click(|_view, _cx| println!("Button clicked.")), - ) - } -} diff --git a/crates/storybook2/src/stories/elements/details.rs b/crates/storybook2/src/stories/elements/details.rs deleted file mode 100644 index 889770cacd..0000000000 --- a/crates/storybook2/src/stories/elements/details.rs +++ /dev/null @@ -1,31 +0,0 @@ -use std::marker::PhantomData; - -use ui::prelude::*; -use ui::Details; - -use crate::story::Story; - -#[derive(Element)] -pub struct DetailsStory { - state_type: PhantomData, -} - -impl DetailsStory { - pub fn new() -> Self { - Self { - state_type: PhantomData, - } - } - - fn render(&mut self, cx: &mut ViewContext) -> impl Element { - Story::container(cx) - .child(Story::title_for::<_, Details>(cx)) - .child(Story::label(cx, "Default")) - .child(Details::new("The quick brown fox jumps over the lazy dog")) - .child(Story::label(cx, "With meta")) - .child( - Details::new("The quick brown fox jumps over the lazy dog") - .meta_text("Sphinx of black quartz, judge my vow."), - ) - } -} diff --git a/crates/storybook2/src/stories/elements/icon.rs b/crates/storybook2/src/stories/elements/icon.rs deleted file mode 100644 index ada454297f..0000000000 --- a/crates/storybook2/src/stories/elements/icon.rs +++ /dev/null @@ -1,29 +0,0 @@ -use std::marker::PhantomData; - -use strum::IntoEnumIterator; -use ui::prelude::*; -use ui::{Icon, IconElement}; - -use crate::story::Story; - -#[derive(Element, Default)] -pub struct IconStory { - state_type: PhantomData, -} - -impl IconStory { - pub fn new() -> Self { - Self { - state_type: PhantomData, - } - } - - fn render(&mut self, cx: &mut ViewContext) -> impl Element { - let icons = Icon::iter(); - - Story::container(cx) - .child(Story::title_for::<_, IconElement>(cx)) - .child(Story::label(cx, "All Icons")) - .child(div().flex().gap_3().children(icons.map(IconElement::new))) - } -} diff --git a/crates/storybook2/src/stories/elements/input.rs b/crates/storybook2/src/stories/elements/input.rs deleted file mode 100644 index 4e45bc613a..0000000000 --- a/crates/storybook2/src/stories/elements/input.rs +++ /dev/null @@ -1,26 +0,0 @@ -use std::marker::PhantomData; - -use ui::prelude::*; -use ui::Input; - -use crate::story::Story; - -#[derive(Element)] -pub struct InputStory { - state_type: PhantomData, -} - -impl InputStory { - pub fn new() -> Self { - Self { - state_type: PhantomData, - } - } - - fn render(&mut self, cx: &mut ViewContext) -> impl Element { - Story::container(cx) - .child(Story::title_for::<_, Input>(cx)) - .child(Story::label(cx, "Default")) - .child(div().flex().child(Input::new("Search"))) - } -} diff --git a/crates/storybook2/src/stories/elements/label.rs b/crates/storybook2/src/stories/elements/label.rs deleted file mode 100644 index 0f6ebcc292..0000000000 --- a/crates/storybook2/src/stories/elements/label.rs +++ /dev/null @@ -1,28 +0,0 @@ -use std::marker::PhantomData; - -use ui::prelude::*; -use ui::Label; - -use crate::story::Story; - -#[derive(Element)] -pub struct LabelStory { - state_type: PhantomData, -} - -impl LabelStory { - pub fn new() -> Self { - Self { - state_type: PhantomData, - } - } - - fn render(&mut self, cx: &mut ViewContext) -> impl Element { - Story::container(cx) - .child(Story::title_for::<_, Label>(cx)) - .child(Story::label(cx, "Default")) - .child(Label::new("Hello, world!")) - .child(Story::label(cx, "Highlighted")) - .child(Label::new("Hello, world!").with_highlights(vec![0, 1, 2, 7, 8, 12])) - } -} diff --git a/crates/storybook2/src/stories/elements/z_index.rs b/crates/storybook2/src/stories/z_index.rs similarity index 100% rename from crates/storybook2/src/stories/elements/z_index.rs rename to crates/storybook2/src/stories/z_index.rs diff --git a/crates/storybook2/src/story_selector.rs b/crates/storybook2/src/story_selector.rs index a2aeab3ced..63a3b43c10 100644 --- a/crates/storybook2/src/story_selector.rs +++ b/crates/storybook2/src/story_selector.rs @@ -23,16 +23,14 @@ pub enum ElementStory { impl ElementStory { pub fn story(&self) -> AnyElement { - use crate::stories::elements; - match self { - Self::Avatar => elements::avatar::AvatarStory::new().into_any(), - Self::Button => elements::button::ButtonStory::new().into_any(), - Self::Details => elements::details::DetailsStory::new().into_any(), - Self::Icon => elements::icon::IconStory::new().into_any(), - Self::Input => elements::input::InputStory::new().into_any(), - Self::Label => elements::label::LabelStory::new().into_any(), - Self::ZIndex => elements::z_index::ZIndexStory::new().into_any(), + Self::Avatar => ui::AvatarStory::new().into_any(), + Self::Button => ui::ButtonStory::new().into_any(), + Self::Details => ui::DetailsStory::new().into_any(), + Self::Icon => ui::IconStory::new().into_any(), + Self::Input => ui::InputStory::new().into_any(), + Self::Label => ui::LabelStory::new().into_any(), + Self::ZIndex => crate::stories::z_index::ZIndexStory::new().into_any(), } } } diff --git a/crates/ui2/src/elements/avatar.rs b/crates/ui2/src/elements/avatar.rs index ada77fe4db..bb43d37e18 100644 --- a/crates/ui2/src/elements/avatar.rs +++ b/crates/ui2/src/elements/avatar.rs @@ -42,3 +42,40 @@ impl Avatar { .fill(theme.middle.warning.default.foreground) } } + +#[cfg(feature = "stories")] +pub use stories::*; + +#[cfg(feature = "stories")] +mod stories { + use crate::Story; + + use super::*; + + #[derive(Element)] + pub struct AvatarStory { + state_type: PhantomData, + } + + impl AvatarStory { + pub fn new() -> Self { + Self { + state_type: PhantomData, + } + } + + fn render(&mut self, cx: &mut ViewContext) -> impl Element { + Story::container(cx) + .child(Story::title_for::<_, Avatar>(cx)) + .child(Story::label(cx, "Default")) + .child(Avatar::new( + "https://avatars.githubusercontent.com/u/1714999?v=4", + )) + .child(Story::label(cx, "Rounded rectangle")) + .child( + Avatar::new("https://avatars.githubusercontent.com/u/1714999?v=4") + .shape(Shape::RoundedRectangle), + ) + } + } +} diff --git a/crates/ui2/src/elements/button.rs b/crates/ui2/src/elements/button.rs index fd4c4ffa1a..a8f40c1e68 100644 --- a/crates/ui2/src/elements/button.rs +++ b/crates/ui2/src/elements/button.rs @@ -202,3 +202,206 @@ impl Button { el } } + +#[cfg(feature = "stories")] +pub use stories::*; + +#[cfg(feature = "stories")] +mod stories { + use gpui3::rems; + use strum::IntoEnumIterator; + + use crate::{h_stack, v_stack, LabelColor, LabelSize, Story}; + + use super::*; + + #[derive(Element)] + pub struct ButtonStory { + state_type: PhantomData, + } + + impl ButtonStory { + pub fn new() -> Self { + Self { + state_type: PhantomData, + } + } + + fn render(&mut self, cx: &mut ViewContext) -> impl Element { + let states = InteractionState::iter(); + + Story::container(cx) + .child(Story::title_for::<_, Button>(cx)) + .child( + div() + .flex() + .gap_8() + .child( + div() + .child(Story::label(cx, "Ghost (Default)")) + .child(h_stack().gap_2().children(states.clone().map(|state| { + v_stack() + .gap_1() + .child( + Label::new(state.to_string()) + .color(LabelColor::Muted) + .size(LabelSize::Small), + ) + .child( + Button::new("Label") + .variant(ButtonVariant::Ghost) + .state(state), + ) + }))) + .child(Story::label(cx, "Ghost – Left Icon")) + .child(h_stack().gap_2().children(states.clone().map(|state| { + v_stack() + .gap_1() + .child( + Label::new(state.to_string()) + .color(LabelColor::Muted) + .size(LabelSize::Small), + ) + .child( + Button::new("Label") + .variant(ButtonVariant::Ghost) + .icon(Icon::Plus) + .icon_position(IconPosition::Left) + .state(state), + ) + }))) + .child(Story::label(cx, "Ghost – Right Icon")) + .child(h_stack().gap_2().children(states.clone().map(|state| { + v_stack() + .gap_1() + .child( + Label::new(state.to_string()) + .color(LabelColor::Muted) + .size(LabelSize::Small), + ) + .child( + Button::new("Label") + .variant(ButtonVariant::Ghost) + .icon(Icon::Plus) + .icon_position(IconPosition::Right) + .state(state), + ) + }))), + ) + .child( + div() + .child(Story::label(cx, "Filled")) + .child(h_stack().gap_2().children(states.clone().map(|state| { + v_stack() + .gap_1() + .child( + Label::new(state.to_string()) + .color(LabelColor::Muted) + .size(LabelSize::Small), + ) + .child( + Button::new("Label") + .variant(ButtonVariant::Filled) + .state(state), + ) + }))) + .child(Story::label(cx, "Filled – Left Button")) + .child(h_stack().gap_2().children(states.clone().map(|state| { + v_stack() + .gap_1() + .child( + Label::new(state.to_string()) + .color(LabelColor::Muted) + .size(LabelSize::Small), + ) + .child( + Button::new("Label") + .variant(ButtonVariant::Filled) + .icon(Icon::Plus) + .icon_position(IconPosition::Left) + .state(state), + ) + }))) + .child(Story::label(cx, "Filled – Right Button")) + .child(h_stack().gap_2().children(states.clone().map(|state| { + v_stack() + .gap_1() + .child( + Label::new(state.to_string()) + .color(LabelColor::Muted) + .size(LabelSize::Small), + ) + .child( + Button::new("Label") + .variant(ButtonVariant::Filled) + .icon(Icon::Plus) + .icon_position(IconPosition::Right) + .state(state), + ) + }))), + ) + .child( + div() + .child(Story::label(cx, "Fixed With")) + .child(h_stack().gap_2().children(states.clone().map(|state| { + v_stack() + .gap_1() + .child( + Label::new(state.to_string()) + .color(LabelColor::Muted) + .size(LabelSize::Small), + ) + .child( + Button::new("Label") + .variant(ButtonVariant::Filled) + .state(state) + .width(Some(rems(6.).into())), + ) + }))) + .child(Story::label(cx, "Fixed With – Left Icon")) + .child(h_stack().gap_2().children(states.clone().map(|state| { + v_stack() + .gap_1() + .child( + Label::new(state.to_string()) + .color(LabelColor::Muted) + .size(LabelSize::Small), + ) + .child( + Button::new("Label") + .variant(ButtonVariant::Filled) + .state(state) + .icon(Icon::Plus) + .icon_position(IconPosition::Left) + .width(Some(rems(6.).into())), + ) + }))) + .child(Story::label(cx, "Fixed With – Right Icon")) + .child(h_stack().gap_2().children(states.clone().map(|state| { + v_stack() + .gap_1() + .child( + Label::new(state.to_string()) + .color(LabelColor::Muted) + .size(LabelSize::Small), + ) + .child( + Button::new("Label") + .variant(ButtonVariant::Filled) + .state(state) + .icon(Icon::Plus) + .icon_position(IconPosition::Right) + .width(Some(rems(6.).into())), + ) + }))), + ), + ) + .child(Story::label(cx, "Button with `on_click`")) + .child( + Button::new("Label").variant(ButtonVariant::Ghost), // NOTE: There currently appears to be a bug in GPUI2 where only the last event handler will fire. + // So adding additional buttons with `on_click`s after this one will cause this `on_click` to not fire. + // .on_click(|_view, _cx| println!("Button clicked.")), + ) + } + } +} diff --git a/crates/ui2/src/elements/details.rs b/crates/ui2/src/elements/details.rs index fbf6d820d2..50b361ea8b 100644 --- a/crates/ui2/src/elements/details.rs +++ b/crates/ui2/src/elements/details.rs @@ -38,3 +38,38 @@ impl Details { .children(self.meta.map(|m| m)) } } + +#[cfg(feature = "stories")] +pub use stories::*; + +#[cfg(feature = "stories")] +mod stories { + use crate::Story; + + use super::*; + + #[derive(Element)] + pub struct DetailsStory { + state_type: PhantomData, + } + + impl DetailsStory { + pub fn new() -> Self { + Self { + state_type: PhantomData, + } + } + + fn render(&mut self, cx: &mut ViewContext) -> impl Element { + Story::container(cx) + .child(Story::title_for::<_, Details>(cx)) + .child(Story::label(cx, "Default")) + .child(Details::new("The quick brown fox jumps over the lazy dog")) + .child(Story::label(cx, "With meta")) + .child( + Details::new("The quick brown fox jumps over the lazy dog") + .meta_text("Sphinx of black quartz, judge my vow."), + ) + } + } +} diff --git a/crates/ui2/src/elements/icon.rs b/crates/ui2/src/elements/icon.rs index 358ae820ea..b63eca561a 100644 --- a/crates/ui2/src/elements/icon.rs +++ b/crates/ui2/src/elements/icon.rs @@ -182,3 +182,37 @@ impl IconElement { sized_svg.flex_none().path(self.icon.path()).fill(fill) } } + +#[cfg(feature = "stories")] +pub use stories::*; + +#[cfg(feature = "stories")] +mod stories { + use strum::IntoEnumIterator; + + use crate::Story; + + use super::*; + + #[derive(Element, Default)] + pub struct IconStory { + state_type: PhantomData, + } + + impl IconStory { + pub fn new() -> Self { + Self { + state_type: PhantomData, + } + } + + fn render(&mut self, cx: &mut ViewContext) -> impl Element { + let icons = Icon::iter(); + + Story::container(cx) + .child(Story::title_for::<_, IconElement>(cx)) + .child(Story::label(cx, "All Icons")) + .child(div().flex().gap_3().children(icons.map(IconElement::new))) + } + } +} diff --git a/crates/ui2/src/elements/input.rs b/crates/ui2/src/elements/input.rs index 4cc32ccc0d..a6cbf2576d 100644 --- a/crates/ui2/src/elements/input.rs +++ b/crates/ui2/src/elements/input.rs @@ -108,3 +108,33 @@ impl Input { ) } } + +#[cfg(feature = "stories")] +pub use stories::*; + +#[cfg(feature = "stories")] +mod stories { + use crate::Story; + + use super::*; + + #[derive(Element)] + pub struct InputStory { + state_type: PhantomData, + } + + impl InputStory { + pub fn new() -> Self { + Self { + state_type: PhantomData, + } + } + + fn render(&mut self, cx: &mut ViewContext) -> impl Element { + Story::container(cx) + .child(Story::title_for::<_, Input>(cx)) + .child(Story::label(cx, "Default")) + .child(div().flex().child(Input::new("Search"))) + } + } +} diff --git a/crates/ui2/src/elements/label.rs b/crates/ui2/src/elements/label.rs index c6fc25ce87..a937468a35 100644 --- a/crates/ui2/src/elements/label.rs +++ b/crates/ui2/src/elements/label.rs @@ -163,3 +163,35 @@ struct Run { pub text: String, pub color: Hsla, } + +#[cfg(feature = "stories")] +pub use stories::*; + +#[cfg(feature = "stories")] +mod stories { + use crate::Story; + + use super::*; + + #[derive(Element)] + pub struct LabelStory { + state_type: PhantomData, + } + + impl LabelStory { + pub fn new() -> Self { + Self { + state_type: PhantomData, + } + } + + fn render(&mut self, cx: &mut ViewContext) -> impl Element { + Story::container(cx) + .child(Story::title_for::<_, Label>(cx)) + .child(Story::label(cx, "Default")) + .child(Label::new("Hello, world!")) + .child(Story::label(cx, "Highlighted")) + .child(Label::new("Hello, world!").with_highlights(vec![0, 1, 2, 7, 8, 12])) + } + } +}