gpui-component/crates/story/src/textarea_story.rs
Jason Lee 5e504d10bb
chore: Refactor tab key to switch focus. (#991)
Wait https://github.com/zed-industries/zed/pull/33008,
https://github.com/zed-industries/zed/pull/34804 to merge.


https://github.com/user-attachments/assets/3c21ebc9-44a0-4311-bb0f-5f63fe8d4bb3

- Improved `focus_ring` to render like an outline.
- Added to support press `Enter`, `Space` key to trigger Checkbox,
Button, Radio.

## Break Changes

- The `FocusableExt` has been changed to only for crate internal.
- The `FocusableCycle` has been removed, now GPUI has it own tab stop
implementation.
2025-09-29 16:48:24 +08:00

176 lines
6 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use gpui::{
px, App, AppContext as _, ClickEvent, Context, Entity, Focusable, InteractiveElement,
IntoElement, ParentElement as _, Render, Styled, Window,
};
use crate::section;
use gpui_component::{
button::Button,
h_flex,
input::{InputState, TextInput},
v_flex, Sizable,
};
pub fn init(_: &mut App) {}
pub struct TextareaStory {
textarea: Entity<InputState>,
textarea_auto_grow: Entity<InputState>,
textarea_no_wrap: Entity<InputState>,
}
impl super::Story for TextareaStory {
fn title() -> &'static str {
"Textarea"
}
fn description() -> &'static str {
"TextInput with multi-line mode."
}
fn closable() -> bool {
false
}
fn new_view(window: &mut Window, cx: &mut App) -> Entity<impl Render> {
Self::view(window, cx)
}
}
impl TextareaStory {
pub fn view(window: &mut Window, cx: &mut App) -> Entity<Self> {
cx.new(|cx| Self::new(window, cx))
}
fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
let textarea = cx.new(|cx| {
InputState::new(window, cx)
.multi_line()
.rows(10)
.placeholder("Enter text here...")
.searchable(true)
.default_value(
unindent::unindent(
r#"Hello 世界this is GPUI component.
The GPUI Component is a collection of UI components for GPUI framework, including.
Button, Input, Checkbox, Radio, Dropdown, Tab, and more...
Here is an application that is built by using GPUI Component.
> This application is still under development, not published yet.
![image](https://github.com/user-attachments/assets/559a648d-19df-4b5a-b563-b78cc79c8894)
![image](https://github.com/user-attachments/assets/5e06ad5d-7ea0-43db-8d13-86a240da4c8d)
## Demo
If you want to see the demo, here is a some demo applications.
"#,
)
)
});
let textarea_auto_grow = cx.new(|cx| {
InputState::new(window, cx)
.auto_grow(1, 5)
.placeholder("Enter text here...")
.default_value("Hello 世界this is GPUI component.")
});
let textarea_no_wrap = cx.new(|cx| {
InputState::new(window, cx)
.multi_line()
.rows(6)
.soft_wrap(false)
.default_value("This is a very long line of text to test if the horizontal scrolling function is working properly, and it should not wrap automatically but display a horizontal scrollbar.\nThe second line is also very long text, used to test the horizontal scrolling effect under multiple lines, and you can input more content to test.\nThe third line: Here you can input other long text content that requires horizontal scrolling.\n")
});
Self {
textarea,
textarea_auto_grow,
textarea_no_wrap,
}
}
fn on_insert_text_to_textarea(
&mut self,
_: &ClickEvent,
window: &mut Window,
cx: &mut Context<Self>,
) {
self.textarea.update(cx, |input, cx| {
input.insert("Hello 你好", window, cx);
});
}
fn on_replace_text_to_textarea(
&mut self,
_: &ClickEvent,
window: &mut Window,
cx: &mut Context<Self>,
) {
self.textarea.update(cx, |input, cx| {
input.replace("Hello 你好", window, cx);
});
}
}
impl Focusable for TextareaStory {
fn focus_handle(&self, cx: &gpui::App) -> gpui::FocusHandle {
self.textarea.focus_handle(cx)
}
}
impl Render for TextareaStory {
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let loc = self.textarea.read(cx).cursor_position();
v_flex()
.id("textarea-story")
.gap_3()
.child(
section("Textarea").child(
v_flex()
.gap_2()
.w_full()
.child(TextInput::new(&self.textarea).h(px(320.)))
.child(
h_flex()
.justify_between()
.child(
h_flex()
.gap_2()
.child(
Button::new("btn-insert-text")
.outline()
.xsmall()
.label("Insert Text")
.on_click(
cx.listener(Self::on_insert_text_to_textarea),
),
)
.child(
Button::new("btn-replace-text")
.outline()
.xsmall()
.label("Replace Text")
.on_click(
cx.listener(Self::on_replace_text_to_textarea),
),
),
)
.child(format!("{}:{}", loc.line, loc.character)),
),
),
)
.child(section("Textarea Auto Grow").child(TextInput::new(&self.textarea_auto_grow)))
.child(
section("No Wrap")
.max_w_md()
.child(TextInput::new(&self.textarea_no_wrap).h(px(200.))),
)
}
}