Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T04:31:06.539Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git
Browse files

example_text_area.rs

119 lines · 3.8 KB · rust
1//! `TextArea` — a multi-line text box. Same `Editor` workhorse, taller chrome,
2//! and `Enter` inserts a newline instead of being ignored. Constructible from a
3//! string or an editor, exactly like [`Input`](crate::example_input::Input).
4
5use gpui::{
6    App, BoxShadow, CursorStyle, Entity, EntityId, Hsla, IntoElement, StyleRefinement, Window, div,
7    hsla, point, prelude::*, px, white,
8};
9
10use crate::Enter;
11use crate::example_editor::{Editor, standard_actions};
12
13enum Source {
14    Value(Entity<String>),
15    Editor(Entity<Editor>),
16}
17
18#[derive(IntoElement)]
19pub struct TextArea {
20    source: Source,
21    rows: usize,
22    color: Option<Hsla>,
23}
24
25impl TextArea {
26    pub fn new(value: Entity<String>, rows: usize) -> Self {
27        Self {
28            source: Source::Value(value),
29            rows,
30            color: None,
31        }
32    }
33
34    pub fn editor(editor: Entity<Editor>, rows: usize) -> Self {
35        Self {
36            source: Source::Editor(editor),
37            rows,
38            color: None,
39        }
40    }
41
42    pub fn color(mut self, color: Hsla) -> Self {
43        self.color = Some(color);
44        self
45    }
46}
47
48impl gpui::View for TextArea {
49    fn entity_id(&self) -> Option<EntityId> {
50        Some(match &self.source {
51            Source::Value(value) => value.entity_id(),
52            Source::Editor(editor) => editor.entity_id(),
53        })
54    }
55
56    fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
57        let editor = match self.source {
58            Source::Value(value) => {
59                window.use_state(cx, move |window, cx| Editor::over(value, window, cx))
60            }
61            Source::Editor(editor) => editor,
62        };
63
64        let focus_handle = editor.read(cx).focus_handle.clone();
65        let is_focused = focus_handle.is_focused(window);
66        let text_color = self.color.unwrap_or(hsla(0., 0., 0.1, 1.));
67        let row_height = px(20.);
68        let box_height = row_height * self.rows as f32 + px(16.);
69
70        let border = if is_focused {
71            hsla(220. / 360., 0.8, 0.5, 1.)
72        } else {
73            hsla(0., 0., 0.75, 1.)
74        };
75
76        div()
77            .id("text-area")
78            .key_context("TextInput")
79            .track_focus(&focus_handle)
80            .cursor(CursorStyle::IBeam)
81            .map(standard_actions(editor.clone()))
82            // Enter is the one binding that differs from a single-line input.
83            .on_action({
84                let editor = editor.clone();
85                move |_: &Enter, _window, cx| editor.update(cx, |e, cx| e.insert_newline(cx))
86            })
87            .w(px(400.))
88            .h(box_height)
89            .p(px(8.))
90            .bg(white())
91            .border_1()
92            .border_color(border)
93            .when(is_focused, |this| {
94                this.shadow(vec![BoxShadow {
95                    color: hsla(220. / 360., 0.8, 0.5, 0.3),
96                    offset: point(px(0.), px(0.)),
97                    blur_radius: px(4.),
98                    spread_radius: px(1.),
99                    inset: false,
100                }])
101            })
102            .rounded(px(4.))
103            .overflow_hidden()
104            .line_height(row_height)
105            .text_size(px(14.))
106            .text_color(text_color)
107            // The cache style is computed from the `rows` prop: change `rows` and
108            // the editor's cached bounds change, busting its cache and re-laying
109            // out the text. (`Input` just uses `size_full()` — nothing to vary.)
110            .child(
111                editor.cached(
112                    StyleRefinement::default()
113                        .w_full()
114                        .h(row_height * self.rows as f32),
115                ),
116            )
117    }
118}
119
Served at tenant.openagents/omega Member data and write actions are omitted.