new-component by longbridge/gpui-component
npx skills add https://github.com/longbridge/gpui-component --skill new-component创建新的 GPUI 组件时:
crates/ui/src 中的组件进行实现(例如:Button、Select、Dialog)Button)Select 和 SelectState)Dialog 的 )广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
AlertDialogcrates/story/src/main.rs 的故事列表中Button)Select)Dialog 的 AlertDialog)在 crates/ui/src/ 中创建新文件(例如 alert_dialog.rs):
use gpui::{App, ClickEvent, Pixels, SharedString, Window, px};
use std::rc::Rc;
pub struct AlertDialog {
pub(crate) variant: AlertVariant,
pub(crate) title: SharedString,
// ... 其他字段
}
impl AlertDialog {
pub fn new(title: impl Into<SharedString>) -> Self {
// 实现
}
// 构建器方法
pub fn description(mut self, desc: impl Into<SharedString>) -> Self {
// 实现
}
}
将模块添加到 crates/ui/src/lib.rs:
pub mod alert_dialog;
对于类似对话框的组件,向 window_ext.rs 添加辅助方法:
pub trait WindowExt {
fn open_alert_dialog(&mut self, alert: AlertDialog, cx: &mut App);
}
创建 crates/story/src/stories/alert_dialog_story.rs:
pub struct AlertDialogStory {
focus_handle: FocusHandle,
}
impl Story for AlertDialogStory {
fn title() -> &'static str {
"AlertDialog"
}
fn new_view(window: &mut Window, cx: &mut App) -> Entity<impl Render> {
Self::view(window, cx)
}
}
添加到 crates/story/src/stories/mod.rs:
mod alert_dialog_story;
pub use alert_dialog_story::AlertDialogStory;
添加到 crates/story/src/main.rs 的故事列表中:
vec![
StoryContainer::panel::<AlertStory>(window, cx),
StoryContainer::panel::<AlertDialogStory>(window, cx), // 在此处添加
// ...
]
AlertDialog 是一个基于 Dialog 的组合组件,具有以下特点:
AlertDialog::info()、AlertDialog::warning() 等关键设计决策:
description 使用 SharedString 而不是 AnyElement,因为 Dialog 构建器需要是 Fn(可多次调用),而 AnyElement 无法克隆window_ext.rs 中使用 Dialog 作为基础,而不是作为单独的 IntoElement 组件用法:
window.open_alert_dialog(
AlertDialog::warning("未保存的更改")
.description("您有未保存的更改。")
.show_cancel(true)
.on_confirm(|_, window, cx| {
window.push_notification("已确认", cx);
true
}),
cx,
);
所有组件都使用构建器模式进行配置:
AlertDialog::new("标题")
.description("描述")
.width(px(500.))
.on_confirm(|_, _, _| true)
对于支持尺寸变体(xs、sm、md、lg)的组件,实现 Sizable 特性。
使用枚举表示视觉变体(例如 AlertVariant::Info、ButtonVariant::Primary)。
渲染为单个容器元素的组件应实现 Styled,以允许调用者自定义样式。该模式使用 StyleRefinement 字段和来自 StyledExt 的 refine_style():
use gpui::{AnyElement, App, IntoElement, ParentElement, RenderOnce, StyleRefinement, Styled, Window, div};
use crate::StyledExt as _;
#[derive(IntoElement)]
pub struct MyComponent {
style: StyleRefinement,
children: Vec<AnyElement>,
}
impl MyComponent {
pub fn new() -> Self {
Self {
style: StyleRefinement::default(),
children: Vec::new(),
}
}
}
impl ParentElement for MyComponent {
fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
self.children.extend(elements);
}
}
impl Styled for MyComponent {
fn style(&mut self) -> &mut StyleRefinement {
&mut self.style
}
}
impl RenderOnce for MyComponent {
fn render(self, _: &mut Window, _: &mut App) -> impl IntoElement {
div()
// ... 组件的默认样式 ...
.refine_style(&self.style) // 应用用户的样式覆盖
.children(self.children)
}
}
关键点:
StyleRefinement::default() 的 style: StyleRefinement 字段&mut self.style 的 Styled 特性render() 中,在根 div 上调用 .refine_style(&self.style) 以合并用户样式.refine_style() 放在组件默认值之后,但在 .children() 之前,以便用户样式覆盖默认值crates/ui/src/dialog/header.rs(DialogHeader)、crates/ui/src/table/table.rs(Table 及其子组件)对于可能被多次调用的回调,使用 Rc<dyn Fn>:
on_confirm: Option<Rc<dyn Fn(&ClickEvent, &mut Window, &mut App) -> bool + 'static>>
每周安装量
120
代码仓库
GitHub 星标
10.7K
首次出现
2026年1月21日
安全审计
安装于
opencode110
codex106
gemini-cli104
cursor99
github-copilot98
claude-code96
When creating new GPUI components:
crates/ui/src (examples: Button, Select, Dialog)Button)Select and SelectState)AlertDialog based on Dialog)crates/story/src/main.rs story listButton)Select)AlertDialog based on Dialog)Create a new file in crates/ui/src/ (e.g., alert_dialog.rs):
use gpui::{App, ClickEvent, Pixels, SharedString, Window, px};
use std::rc::Rc;
pub struct AlertDialog {
pub(crate) variant: AlertVariant,
pub(crate) title: SharedString,
// ... other fields
}
impl AlertDialog {
pub fn new(title: impl Into<SharedString>) -> Self {
// implementation
}
// Builder methods
pub fn description(mut self, desc: impl Into<SharedString>) -> Self {
// implementation
}
}
Add the module to crates/ui/src/lib.rs:
pub mod alert_dialog;
For dialog-like components, add helper methods to window_ext.rs:
pub trait WindowExt {
fn open_alert_dialog(&mut self, alert: AlertDialog, cx: &mut App);
}
Create crates/story/src/stories/alert_dialog_story.rs:
pub struct AlertDialogStory {
focus_handle: FocusHandle,
}
impl Story for AlertDialogStory {
fn title() -> &'static str {
"AlertDialog"
}
fn new_view(window: &mut Window, cx: &mut App) -> Entity<impl Render> {
Self::view(window, cx)
}
}
Add to crates/story/src/stories/mod.rs:
mod alert_dialog_story;
pub use alert_dialog_story::AlertDialogStory;
Add to crates/story/src/main.rs in the stories list:
vec![
StoryContainer::panel::<AlertStory>(window, cx),
StoryContainer::panel::<AlertDialogStory>(window, cx), // Add here
// ...
]
AlertDialog is a composite component based on Dialog with these features:
AlertDialog::info(), AlertDialog::warning(), etc.Key Design Decisions :
description uses SharedString instead of AnyElement because the Dialog builder needs to be Fn (callable multiple times), and AnyElement cannot be clonedwindow_ext.rs using Dialog as the base, not as a separate IntoElement componentUsage :
window.open_alert_dialog(
AlertDialog::warning("Unsaved Changes")
.description("You have unsaved changes.")
.show_cancel(true)
.on_confirm(|_, window, cx| {
window.push_notification("Confirmed", cx);
true
}),
cx,
);
All components use the builder pattern for configuration:
AlertDialog::new("Title")
.description("Description")
.width(px(500.))
.on_confirm(|_, _, _| true)
Implement Sizable trait for components that support size variants (xs, sm, md, lg).
Use enums for visual variants (e.g., AlertVariant::Info, ButtonVariant::Primary).
Components that render as a single container element should implement Styled to allow callers to customize styles. The pattern uses a StyleRefinement field and refine_style() from StyledExt:
use gpui::{AnyElement, App, IntoElement, ParentElement, RenderOnce, StyleRefinement, Styled, Window, div};
use crate::StyledExt as _;
#[derive(IntoElement)]
pub struct MyComponent {
style: StyleRefinement,
children: Vec<AnyElement>,
}
impl MyComponent {
pub fn new() -> Self {
Self {
style: StyleRefinement::default(),
children: Vec::new(),
}
}
}
impl ParentElement for MyComponent {
fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
self.children.extend(elements);
}
}
impl Styled for MyComponent {
fn style(&mut self) -> &mut StyleRefinement {
&mut self.style
}
}
impl RenderOnce for MyComponent {
fn render(self, _: &mut Window, _: &mut App) -> impl IntoElement {
div()
// ... component's default styles ...
.refine_style(&self.style) // Apply user's style overrides
.children(self.children)
}
}
Key points:
style: StyleRefinement field initialized with StyleRefinement::default()Styled trait returning &mut self.stylerender(), call .refine_style(&self.style) on the root div to merge user styles.refine_style() after component defaults but before .children() so user styles override defaultscrates/ui/src/dialog/header.rs (DialogHeader), crates/ui/src/table/table.rs (Table and sub-components)Use Rc<dyn Fn> for callbacks that may be called multiple times:
on_confirm: Option<Rc<dyn Fn(&ClickEvent, &mut Window, &mut App) -> bool + 'static>>
Weekly Installs
120
Repository
GitHub Stars
10.7K
First Seen
Jan 21, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode110
codex106
gemini-cli104
cursor99
github-copilot98
claude-code96
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
115,300 周安装