Skip to content

Commit 30fd00d

Browse files
Add component textarea (#157)
* Add component textarea * remove textarea playwright test * tweak styles to more closely match button variants * split out variants into their own sections --------- Co-authored-by: Evan Almloff <[email protected]>
1 parent 72ac67c commit 30fd00d

File tree

12 files changed

+337
-1
lines changed

12 files changed

+337
-1
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ Building styled and more featured component libraries on top of Dioxus Primitive
3333

3434
We're still in the early days - Many components are still being created and stabilized.
3535

36-
30/30
36+
31/31
3737

3838
- [x] Accordion
3939
- [x] Alert Dialog
@@ -60,6 +60,7 @@ We're still in the early days - Many components are still being created and stab
6060
- [x] Slider
6161
- [x] Switch
6262
- [x] Tabs
63+
- [x] Textarea
6364
- [x] Toast
6465
- [x] Toggle
6566
- [x] Toggle Group

component.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"preview/src/components/aspect_ratio",
3535
"preview/src/components/scroll_area",
3636
"preview/src/components/date_picker",
37+
"preview/src/components/textarea",
3738
"preview/src/components/skeleton",
3839
"preview/src/components/card"
3940
]

preview/src/components/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ examples!(
8585
slider,
8686
switch,
8787
tabs,
88+
textarea[outline, fade, ghost],
8889
toast,
8990
toggle_group,
9091
toggle,
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "textarea",
3+
"description": "a textarea component used to allow users to enter multi-line text input",
4+
"authors": [
5+
"zhiyanzhaijie"
6+
],
7+
"exclude": [
8+
"variants",
9+
"docs.md",
10+
"component.json"
11+
],
12+
"cargoDependencies": [
13+
{
14+
"name": "dioxus-primitives",
15+
"git": "https://github.com/DioxusLabs/components"
16+
}
17+
],
18+
"globalAssets": [
19+
"../../../assets/dx-components-theme.css"
20+
]
21+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
use dioxus::prelude::*;
2+
3+
#[derive(Copy, Clone, PartialEq, Default)]
4+
#[non_exhaustive]
5+
pub enum TextareaVariant {
6+
#[default]
7+
Default,
8+
Fade,
9+
Outline,
10+
Ghost,
11+
}
12+
13+
impl TextareaVariant {
14+
pub fn class(&self) -> &'static str {
15+
match self {
16+
TextareaVariant::Default => "default",
17+
TextareaVariant::Fade => "fade",
18+
TextareaVariant::Outline => "outline",
19+
TextareaVariant::Ghost => "ghost",
20+
}
21+
}
22+
}
23+
24+
#[component]
25+
pub fn Textarea(
26+
oninput: Option<EventHandler<FormEvent>>,
27+
onchange: Option<EventHandler<FormEvent>>,
28+
oninvalid: Option<EventHandler<FormEvent>>,
29+
onselect: Option<EventHandler<SelectionEvent>>,
30+
onselectionchange: Option<EventHandler<SelectionEvent>>,
31+
onfocus: Option<EventHandler<FocusEvent>>,
32+
onblur: Option<EventHandler<FocusEvent>>,
33+
onfocusin: Option<EventHandler<FocusEvent>>,
34+
onfocusout: Option<EventHandler<FocusEvent>>,
35+
onkeydown: Option<EventHandler<KeyboardEvent>>,
36+
onkeypress: Option<EventHandler<KeyboardEvent>>,
37+
onkeyup: Option<EventHandler<KeyboardEvent>>,
38+
oncompositionstart: Option<EventHandler<CompositionEvent>>,
39+
oncompositionupdate: Option<EventHandler<CompositionEvent>>,
40+
oncompositionend: Option<EventHandler<CompositionEvent>>,
41+
oncopy: Option<EventHandler<ClipboardEvent>>,
42+
oncut: Option<EventHandler<ClipboardEvent>>,
43+
onpaste: Option<EventHandler<ClipboardEvent>>,
44+
#[props(default)] variant: TextareaVariant,
45+
#[props(extends=GlobalAttributes)]
46+
#[props(extends=textarea)]
47+
attributes: Vec<Attribute>,
48+
children: Element,
49+
) -> Element {
50+
rsx! {
51+
document::Link { rel: "stylesheet", href: asset!("./style.css") }
52+
textarea {
53+
class: "textarea",
54+
"data-slot": "textarea",
55+
"data-style": variant.class(),
56+
oninput: move |e| _ = oninput.map(|callback| callback(e)),
57+
onchange: move |e| _ = onchange.map(|callback| callback(e)),
58+
oninvalid: move |e| _ = oninvalid.map(|callback| callback(e)),
59+
onselect: move |e| _ = onselect.map(|callback| callback(e)),
60+
onselectionchange: move |e| _ = onselectionchange.map(|callback| callback(e)),
61+
onfocus: move |e| _ = onfocus.map(|callback| callback(e)),
62+
onblur: move |e| _ = onblur.map(|callback| callback(e)),
63+
onfocusin: move |e| _ = onfocusin.map(|callback| callback(e)),
64+
onfocusout: move |e| _ = onfocusout.map(|callback| callback(e)),
65+
onkeydown: move |e| _ = onkeydown.map(|callback| callback(e)),
66+
onkeypress: move |e| _ = onkeypress.map(|callback| callback(e)),
67+
onkeyup: move |e| _ = onkeyup.map(|callback| callback(e)),
68+
oncompositionstart: move |e| _ = oncompositionstart.map(|callback| callback(e)),
69+
oncompositionupdate: move |e| _ = oncompositionupdate.map(|callback| callback(e)),
70+
oncompositionend: move |e| _ = oncompositionend.map(|callback| callback(e)),
71+
oncopy: move |e| _ = oncopy.map(|callback| callback(e)),
72+
oncut: move |e| _ = oncut.map(|callback| callback(e)),
73+
onpaste: move |e| _ = onpaste.map(|callback| callback(e)),
74+
..attributes,
75+
{children}
76+
}
77+
}
78+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
The textarea element is used to allow users to enter multi-line text input in a user interface.
2+
3+
## Component Structure
4+
5+
```rust
6+
textarea {
7+
// Global html attributes
8+
class: "textarea",
9+
"data-style": "default",
10+
// Children
11+
{children}
12+
}
13+
```
14+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
mod component;
2+
pub use component::*;
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/* Base */
2+
.textarea {
3+
width: 100%;
4+
min-height: 4rem;
5+
padding: 8px 12px;
6+
line-height: 1.5;
7+
font-family: inherit;
8+
color: var(--secondary-color-4);
9+
outline: none;
10+
resize: vertical;
11+
transition: background-color 100ms ease-out, border-color 100ms ease-out, box-shadow 100ms ease-out;
12+
13+
-webkit-appearance: none;
14+
-moz-appearance: none;
15+
appearance: none;
16+
margin: 0;
17+
border: none;
18+
background: none;
19+
box-sizing: border-box;
20+
border-radius: 0.5rem;
21+
}
22+
23+
.textarea:disabled {
24+
color: var(--secondary-color-5);
25+
cursor: not-allowed;
26+
}
27+
28+
.textarea::placeholder {
29+
color: var(--secondary-color-5);
30+
}
31+
32+
/* Default Variant */
33+
.textarea[data-style="default"] {
34+
background: var(--light, var(--primary-color)) var(--dark, var(--primary-color-3));
35+
box-shadow: inset 0 0 0 1px var(--light, var(--primary-color-6)) var(--dark, var(--primary-color-7));
36+
}
37+
38+
.textarea[data-style="default"]:hover:not(:disabled),
39+
.textarea[data-style="default"]:focus {
40+
background: var(--light, var(--primary-color-4)) var(--dark, var(--primary-color-5));
41+
color: var(--secondary-color-1);
42+
}
43+
44+
/* Fade Variant */
45+
.textarea[data-style="fade"] {
46+
background: var(--light, var(--primary-color)) var(--dark, var(--primary-color-3));
47+
}
48+
49+
.textarea[data-style="fade"]:hover:not(:disabled),
50+
.textarea[data-style="fade"]:focus {
51+
background: var(--light, var(--primary-color-4)) var(--dark, var(--primary-color-5));
52+
color: var(--secondary-color-1);
53+
}
54+
55+
/* Outline Variant */
56+
.textarea[data-style="outline"] {
57+
border: 1px solid var(--primary-color-6);
58+
background-color: var(--light, var(--primary-color))
59+
var(--dark, var(--primary-color-3));
60+
}
61+
62+
.textarea[data-style="outline"]:hover:not(:disabled):not(:focus) {
63+
border-color: var(--primary-color-7);
64+
}
65+
66+
.textarea[data-style="outline"]:focus {
67+
border-color: var(--focused-border-color);
68+
}
69+
70+
.textarea[data-style="outline"]:invalid,
71+
.textarea[data-style="outline"][aria-invalid="true"] {
72+
border-color: var(--primary-error-color);
73+
}
74+
75+
/* Ghost Variant */
76+
.textarea[data-style="ghost"] {
77+
background-color: transparent;
78+
}
79+
80+
.textarea[data-style="ghost"]:hover:not(:disabled) {
81+
background-color: var(--primary-color-5);
82+
color: var(--secondary-color-1);
83+
}
84+
85+
.textarea[data-style="ghost"]:focus {
86+
border-color: var(--focused-border-color);
87+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
use super::super::component::*;
2+
use crate::components::label::Label;
3+
use dioxus::prelude::*;
4+
5+
#[component]
6+
pub fn Demo() -> Element {
7+
let mut description = use_signal(String::new);
8+
rsx! {
9+
div {
10+
display: "flex",
11+
flex_direction: "column",
12+
gap: "1.5rem",
13+
14+
p { id: "textarea-message", "Description here: {description}" }
15+
16+
div {
17+
display: "flex",
18+
flex_direction: "column",
19+
gap: ".5rem",
20+
justify_content: "center",
21+
22+
Label { html_for: "fade", "Fade" }
23+
Textarea {
24+
id: "fade",
25+
variant: TextareaVariant::Fade,
26+
placeholder: "Enter your description",
27+
value: description,
28+
oninput: move |e: FormEvent| description.set(e.value()),
29+
}
30+
}
31+
}
32+
}
33+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
use super::super::component::*;
2+
use crate::components::label::Label;
3+
use dioxus::prelude::*;
4+
5+
#[component]
6+
pub fn Demo() -> Element {
7+
let mut description = use_signal(String::new);
8+
rsx! {
9+
div {
10+
display: "flex",
11+
flex_direction: "column",
12+
gap: "1.5rem",
13+
14+
p { id: "textarea-message", "Description here: {description}" }
15+
16+
div {
17+
display: "flex",
18+
flex_direction: "column",
19+
gap: ".5rem",
20+
justify_content: "center",
21+
22+
Label { html_for: "ghost", "Ghost" }
23+
Textarea {
24+
id: "ghost",
25+
variant: TextareaVariant::Ghost,
26+
placeholder: "Enter your description",
27+
value: description,
28+
oninput: move |e: FormEvent| description.set(e.value()),
29+
}
30+
}
31+
}
32+
}
33+
}

0 commit comments

Comments
 (0)