component: Add component and component_preview crates to power UI components (#24456)

This PR formalizes design components with the Component and
ComponentPreview traits.

You can open the preview UI with `workspace: open component preview`.

Component previews no longer need to return `Self` allowing for more
complex previews, and previews of components like `ui::Tooltip` that
supplement other components rather than are rendered by default.

`cargo-machete` incorrectly identifies `linkme` as an unused dep on
crates that have components deriving `IntoComponent`, so you may need to
add this to that crate's `Cargo.toml`:

```toml
# cargo-machete doesn't understand that linkme is used in the component macro
[package.metadata.cargo-machete]
ignored = ["linkme"]
```

Release Notes:

- N/A

---------

Co-authored-by: Marshall Bowers <git@maxdeviant.com>
This commit is contained in:
Nate Butler
2025-02-09 13:25:03 -05:00
committed by GitHub
co-authored by Marshall Bowers
parent 56cfc60875
commit 8f1ff189cc
36 changed files with 1582 additions and 976 deletions
+12 -15
View File
@@ -1,4 +1,5 @@
use crate::prelude::*;
use component::{example_group, single_example, ComponentPreview};
use gpui::{AnyElement, IntoElement, ParentElement, StyleRefinement, Styled};
use smallvec::SmallVec;
@@ -22,7 +23,8 @@ pub fn h_group() -> ContentGroup {
}
/// A flexible container component that can hold other elements.
#[derive(IntoElement)]
#[derive(IntoElement, IntoComponent)]
#[component(scope = "layout")]
pub struct ContentGroup {
base: Div,
border: bool,
@@ -87,16 +89,8 @@ impl RenderOnce for ContentGroup {
}
impl ComponentPreview for ContentGroup {
fn description() -> impl Into<Option<&'static str>> {
"A flexible container component that can hold other elements. It can be customized with or without a border and background fill."
}
fn example_label_side() -> ExampleLabelSide {
ExampleLabelSide::Bottom
}
fn examples(_window: &mut Window, _: &mut App) -> Vec<ComponentExampleGroup<Self>> {
vec![example_group(vec![
fn preview(_window: &mut Window, _cx: &App) -> AnyElement {
example_group(vec![
single_example(
"Default",
ContentGroup::new()
@@ -104,7 +98,8 @@ impl ComponentPreview for ContentGroup {
.items_center()
.justify_center()
.h_48()
.child(Label::new("Default ContentBox")),
.child(Label::new("Default ContentBox"))
.into_any_element(),
)
.grow(),
single_example(
@@ -115,7 +110,8 @@ impl ComponentPreview for ContentGroup {
.justify_center()
.h_48()
.borderless()
.child(Label::new("Borderless ContentBox")),
.child(Label::new("Borderless ContentBox"))
.into_any_element(),
)
.grow(),
single_example(
@@ -126,10 +122,11 @@ impl ComponentPreview for ContentGroup {
.justify_center()
.h_48()
.unfilled()
.child(Label::new("Unfilled ContentBox")),
.child(Label::new("Unfilled ContentBox"))
.into_any_element(),
)
.grow(),
])
.grow()]
.into_any_element()
}
}