Skip to repository content122 lines · 3.9 KB · rust
tenant.openagents/omega
No repository description is available.
OpenAgents Git authority 2026-07-28T04:25:15.381Z Public web read
NIP-34 coordinate
30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omegaMaintainersHidden in public view
References2 branches · 1 tag
Read-only clone
git clone https://openagents.com/git/tenant.openagents/omega.gitBrowse files
example_input.rs
1//! `Input` — a single-line text input. The shaping layer over `Editor`.
2//!
3//! Construct it two ways, depending on how much state you want to own:
4//! * `Input::new(value: Entity<String>)` — you hold just the string; the input
5//! allocates the `Editor` internally via `use_state`. Value readable, cursor hidden.
6//! * `Input::editor(editor: Entity<Editor>)` — you hold the editor; cursor/selection
7//! are now yours to read and drive too.
8//!
9//! Either way the chrome is identical. Because the string (or editor) is the
10//! input's *identity*, the internal `use_state(Editor)` is collision-safe across
11//! any number of inputs.
12
13use gpui::{
14 App, BoxShadow, CursorStyle, Entity, EntityId, Hsla, IntoElement, Pixels, StyleRefinement,
15 Window, div, hsla, point, prelude::*, px, white,
16};
17
18use crate::example_editor::{Editor, standard_actions};
19
20enum Source {
21 Value(Entity<String>),
22 Editor(Entity<Editor>),
23}
24
25#[derive(IntoElement)]
26pub struct Input {
27 source: Source,
28 width: Option<Pixels>,
29 color: Option<Hsla>,
30}
31
32impl Input {
33 /// Backed by a bare string; the editor is allocated internally.
34 pub fn new(value: Entity<String>) -> Self {
35 Self {
36 source: Source::Value(value),
37 width: None,
38 color: None,
39 }
40 }
41
42 /// Backed by an editor you own (so you can read/drive its cursor).
43 pub fn editor(editor: Entity<Editor>) -> Self {
44 Self {
45 source: Source::Editor(editor),
46 width: None,
47 color: None,
48 }
49 }
50
51 pub fn width(mut self, width: Pixels) -> Self {
52 self.width = Some(width);
53 self
54 }
55
56 pub fn color(mut self, color: Hsla) -> Self {
57 self.color = Some(color);
58 self
59 }
60}
61
62impl gpui::View for Input {
63 fn entity_id(&self) -> Option<EntityId> {
64 Some(match &self.source {
65 Source::Value(value) => value.entity_id(),
66 Source::Editor(editor) => editor.entity_id(),
67 })
68 }
69
70 fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
71 // Get the editor: use the one we were handed, or allocate it under our
72 // own (string-derived) identity so it persists and never collides.
73 let editor = match self.source {
74 Source::Value(value) => {
75 window.use_state(cx, move |window, cx| Editor::over(value, window, cx))
76 }
77 Source::Editor(editor) => editor,
78 };
79
80 let focus_handle = editor.read(cx).focus_handle.clone();
81 let is_focused = focus_handle.is_focused(window);
82 let text_color = self.color.unwrap_or(hsla(0., 0., 0.1, 1.));
83 let box_width = self.width.unwrap_or(px(300.));
84
85 let border = if is_focused {
86 hsla(220. / 360., 0.8, 0.5, 1.)
87 } else {
88 hsla(0., 0., 0.75, 1.)
89 };
90
91 div()
92 .id("input")
93 .key_context("TextInput")
94 .track_focus(&focus_handle)
95 .cursor(CursorStyle::IBeam)
96 .map(standard_actions(editor.clone()))
97 .w(box_width)
98 .h(px(36.))
99 .px(px(8.))
100 .bg(white())
101 .border_1()
102 .border_color(border)
103 .when(is_focused, |this| {
104 this.shadow(vec![BoxShadow {
105 color: hsla(220. / 360., 0.8, 0.5, 0.3),
106 offset: point(px(0.), px(0.)),
107 blur_radius: px(4.),
108 spread_radius: px(1.),
109 inset: false,
110 }])
111 })
112 .rounded(px(4.))
113 .overflow_hidden()
114 .flex()
115 .items_center()
116 .line_height(px(20.))
117 .text_size(px(14.))
118 .text_color(text_color)
119 .child(editor.cached(StyleRefinement::default().size_full()))
120 }
121}
122