feat: add field component

This commit is contained in:
2026-11-03 19:07:15 +07:00
parent 7399d92f36
commit 0c8d7f05d4
6 changed files with 404 additions and 7 deletions
+105 -1
View File
@@ -15,7 +15,8 @@ use gpui_native_core::common::{Sizable as _, Size, h_flex, v_flex};
use gpui_native_core::context_menu::ContextMenu;
use gpui_native_core::dialog::Dialog;
use gpui_native_core::empty_state::EmptyState;
use gpui_native_core::input::{Input, InputState};
use gpui_native_core::field::{Field, FieldVariant};
use gpui_native_core::input::{Input, InputState, InputStateEvent};
use gpui_native_core::link::Link;
use gpui_native_core::menu::{Menu, MenuItem};
use gpui_native_core::popover::Popover;
@@ -51,6 +52,7 @@ const CATALOG: &[(&str, &[(&str, &str)])] = &[
&[
("button", "Button"),
("input", "Input"),
("field", "Field"),
("checkbox", "Checkbox"),
("radio", "Radio"),
("switch", "Switch"),
@@ -382,6 +384,10 @@ impl Gallery {
PanelDescriptor::new("input", "Input", |_, cx| cx.new(InputDemo::new).into()),
cx,
);
dock.register_panel(
PanelDescriptor::new("field", "Field", |_, cx| cx.new(FieldDemo::new).into()),
cx,
);
dock.register_panel(
PanelDescriptor::new("checkbox", "Checkbox", |_, cx| {
cx.new(|_| CheckboxDemo { checked: false }).into()
@@ -844,6 +850,104 @@ impl Render for InputDemo {
}
}
struct FieldDemo {
url: Entity<InputState>,
name: Entity<InputState>,
notifications: bool,
sync_on_open: bool,
_subscription: gpui::Subscription,
}
impl FieldDemo {
fn new(cx: &mut Context<Self>) -> Self {
let url = InputState::new(cx);
let name = InputState::new_with_text("reya", cx);
let subscription = cx.subscribe(&url, |_, _, event, cx| {
if matches!(event, InputStateEvent::TextChanged) {
cx.notify();
}
});
Self {
url,
name,
notifications: false,
sync_on_open: true,
_subscription: subscription,
}
}
}
impl Render for FieldDemo {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let view = cx.entity();
let colors = cx.theme().colors;
let url_error = self.url.read(cx).value().is_empty().then_some("Required");
let url_error_render = url_error.map(SharedString::from);
ScrollArea::new("field-demo")
.size_full()
.p_4()
.child(demo_section(
"block",
colors,
v_flex()
.gap_3()
.child(
Field::new("field-demo-url", "Server URL")
.description("Where your patches are sent.")
.error(url_error_render)
.child(Input::new("field-demo-url-input", self.url.clone())),
)
.child(
Field::new("field-demo-name", "Display name")
.description("Shown next to your commits.")
.child(Input::new("field-demo-name-input", self.name.clone())),
),
))
.child(demo_section(
"row",
colors,
v_flex()
.gap_3()
.child(
Field::new("field-demo-notifications", "Desktop notifications")
.description("Tell me when a push lands.")
.variant(FieldVariant::Row)
.child(
Switch::new("field-demo-notifications-switch")
.checked(self.notifications)
.on_change({
let view = view.clone();
move |checked, _, cx| {
view.update(cx, |demo, cx| {
demo.notifications = checked;
cx.notify();
});
}
}),
),
)
.child(
Field::new("field-demo-sync", "Sync on open")
.variant(FieldVariant::Row)
.child(
Switch::new("field-demo-sync-switch")
.checked(self.sync_on_open)
.on_change({
let view = view.clone();
move |checked, _, cx| {
view.update(cx, |demo, cx| {
demo.sync_on_open = checked;
cx.notify();
});
}
}),
),
),
))
}
}
struct CheckboxDemo {
checked: bool,
}