example_text_area.rs

  1//! The `ExampleTextArea` view — a multi-line text area component.
  2//!
  3//! Same `ExampleEditor` entity, different presentation: taller box with configurable
  4//! row count. Demonstrates that the same entity type can back different `View`
  5//! components with different props and layouts.
  6
  7use gpui::{
  8    App, BoxShadow, CursorStyle, Entity, Hsla, IntoViewElement, ViewElement, Window, div, hsla,
  9    point, prelude::*, px, white,
 10};
 11
 12use crate::example_editor::ExampleEditor;
 13use crate::example_render_log::RenderLog;
 14use crate::{Backspace, Delete, End, Enter, Home, Left, Right};
 15
 16#[derive(Hash, IntoViewElement)]
 17pub struct ExampleTextArea {
 18    editor: Entity<ExampleEditor>,
 19    render_log: Entity<RenderLog>,
 20    rows: usize,
 21    color: Option<Hsla>,
 22}
 23
 24impl ExampleTextArea {
 25    pub fn new(editor: Entity<ExampleEditor>, render_log: Entity<RenderLog>, rows: usize) -> Self {
 26        Self {
 27            editor,
 28            render_log,
 29            rows,
 30            color: None,
 31        }
 32    }
 33
 34    pub fn color(mut self, color: Hsla) -> Self {
 35        self.color = Some(color);
 36        self
 37    }
 38}
 39
 40impl gpui::ComponentView for ExampleTextArea {
 41    fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
 42        self.render_log
 43            .update(cx, |log, _cx| log.log("ExampleTextArea"));
 44
 45        let focus_handle = self.editor.read(cx).focus_handle.clone();
 46        let is_focused = focus_handle.is_focused(window);
 47        let text_color = self.color.unwrap_or(hsla(0., 0., 0.1, 1.));
 48        let row_height = px(20.);
 49        let box_height = row_height * self.rows as f32 + px(16.);
 50        let editor = self.editor;
 51
 52        div()
 53            .id("text-area")
 54            .key_context("TextInput")
 55            .track_focus(&focus_handle)
 56            .cursor(CursorStyle::IBeam)
 57            .on_action({
 58                let editor = editor.clone();
 59                move |action: &Backspace, _window, cx| {
 60                    editor.update(cx, |state, cx| state.backspace(action, _window, cx));
 61                }
 62            })
 63            .on_action({
 64                let editor = editor.clone();
 65                move |action: &Delete, _window, cx| {
 66                    editor.update(cx, |state, cx| state.delete(action, _window, cx));
 67                }
 68            })
 69            .on_action({
 70                let editor = editor.clone();
 71                move |action: &Left, _window, cx| {
 72                    editor.update(cx, |state, cx| state.left(action, _window, cx));
 73                }
 74            })
 75            .on_action({
 76                let editor = editor.clone();
 77                move |action: &Right, _window, cx| {
 78                    editor.update(cx, |state, cx| state.right(action, _window, cx));
 79                }
 80            })
 81            .on_action({
 82                let editor = editor.clone();
 83                move |action: &Home, _window, cx| {
 84                    editor.update(cx, |state, cx| state.home(action, _window, cx));
 85                }
 86            })
 87            .on_action({
 88                let editor = editor.clone();
 89                move |action: &End, _window, cx| {
 90                    editor.update(cx, |state, cx| state.end(action, _window, cx));
 91                }
 92            })
 93            .on_action({
 94                let editor = editor.clone();
 95                move |_: &Enter, _window, cx| {
 96                    editor.update(cx, |state, cx| state.insert_newline(cx));
 97                }
 98            })
 99            .w(px(400.))
100            .h(box_height)
101            .p(px(8.))
102            .bg(white())
103            .border_1()
104            .border_color(if is_focused {
105                hsla(220. / 360., 0.8, 0.5, 1.)
106            } else {
107                hsla(0., 0., 0.75, 1.)
108            })
109            .when(is_focused, |this| {
110                this.shadow(vec![BoxShadow {
111                    color: hsla(220. / 360., 0.8, 0.5, 0.3),
112                    offset: point(px(0.), px(0.)),
113                    blur_radius: px(4.),
114                    spread_radius: px(1.),
115                }])
116            })
117            .rounded(px(4.))
118            .overflow_hidden()
119            .line_height(row_height)
120            .text_size(px(14.))
121            .text_color(text_color)
122            .child(ViewElement::new(editor))
123    }
124}