Add grow_vertically to TextArea (#171)

This change replicates the behaviour on Blueprint.

Improvements could include:
1. adding support for the `value` property and generating the element
with the appropriate height; and
2. reduce the height when text is deleted.

Close #158
This commit is contained in:
Simon Bihel 2023-04-24 08:57:21 +01:00 committed by GitHub
parent 071bbd6d06
commit 31a3ba8946
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 102 additions and 8 deletions

16
Cargo.lock generated
View file

@ -90,6 +90,12 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24a6904aef64d73cf10ab17ebace7befb918b82164785cb89907993be7f83813"
[[package]]
name = "boolinator"
version = "2.4.0"
@ -182,11 +188,11 @@ checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e"
[[package]]
name = "clap"
version = "4.0.29"
version = "4.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d63b9e9c07271b9957ad22c173bae2a4d9a81127680962039296abcd2f8251d"
checksum = "42dfd32784433290c51d92c438bb72ea5063797fc3cc9a21a8c4346bebbb2098"
dependencies = [
"bitflags 1.3.2",
"bitflags 2.2.1",
"clap_derive",
"clap_lex",
"is-terminal",
@ -197,9 +203,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.0.21"
version = "4.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014"
checksum = "fddf67631444a3a3e3e5ac51c36a5e01335302de677bd78759eaa90ab1f46644"
dependencies = [
"heck 0.4.0",
"proc-macro-error",

View file

@ -22,7 +22,7 @@ gloo = "0.8"
id_tree = { version = "1.8", optional = true }
implicit-clone = "0.3.5"
wasm-bindgen = "0.2"
web-sys = { version = "0.3", features = ["DomRect", "Element", "Event", "HtmlSelectElement", "DomTokenList", "Element"] }
web-sys = { version = "0.3", features = ["DomRect", "Element", "Event", "HtmlSelectElement", "DomTokenList", "CssStyleDeclaration"] }
yew = "0.20"
yew-callbacks = "0.2.1"

View file

@ -1,4 +1,6 @@
use crate::Intent;
use wasm_bindgen::JsCast;
use web_sys::HtmlTextAreaElement;
use yew::prelude::*;
#[derive(Clone, PartialEq, Properties)]
@ -7,7 +9,8 @@ pub struct TextAreaProps {
pub class: Classes,
#[prop_or_default]
pub fill: bool,
//TODO pub grow_vertically: bool,
#[prop_or_default]
pub grow_vertically: bool,
#[prop_or_default]
pub r#ref: NodeRef,
#[prop_or_default]
@ -18,6 +21,15 @@ pub struct TextAreaProps {
pub small: bool,
#[prop_or_default]
pub onchange: Callback<Event>,
#[prop_or_default]
pub value: Option<String>,
}
fn resize(input: &HtmlTextAreaElement) {
input
.style()
.set_property("height", &format!("{}px", input.scroll_height()))
.unwrap();
}
#[function_component(TextArea)]
@ -25,13 +37,38 @@ pub fn text_area(
TextAreaProps {
class,
fill,
grow_vertically,
r#ref,
intent,
large,
small,
onchange,
value,
}: &TextAreaProps,
) -> Html {
{
let node_ref = r#ref.clone();
use_effect_with_deps(
move |node_ref| {
let input = node_ref.cast::<HtmlTextAreaElement>().unwrap();
resize(&input);
},
node_ref,
);
}
let oninput = {
let grow_vertically = *grow_vertically;
Callback::from(move |e: InputEvent| {
if grow_vertically {
let input = e
.target()
.and_then(|t| t.dyn_into::<HtmlTextAreaElement>().ok());
if let Some(input) = input {
resize(&input);
}
}
})
};
html! {
<textarea
class={classes!(
@ -44,6 +81,8 @@ pub fn text_area(
)}
ref={r#ref}
{onchange}
{oninput}
value={value.clone()}
/>
}
}

View file

@ -73,6 +73,11 @@ crate::build_example_prop_component! {
checked={ctx.props().example_props.ellipsize}
label={html!("Ellipsize")}
/>
<p
style="margin-top: 5px;"
>
{"Value:"}
</p>
<input
class="bp3-input"
onchange={self.update_props(ctx, |props, e: Event| {

View file

@ -7,16 +7,20 @@ pub struct ExampleProps {
pub small: bool,
pub large: bool,
pub fill: bool,
pub grow_vertically: bool,
pub text: String,
}
#[function_component(Example)]
pub fn example(props: &ExampleProps) -> Html {
html! {
<div style="width: 200px; height: 50px">
<div style="width: 200px; min-height: 50px">
<TextArea intent={props.intent}
large={props.large}
fill={props.fill}
small={props.small}
grow_vertically={props.grow_vertically}
value={Some(props.text.clone())}
/>
</div>
}

View file

@ -3,6 +3,7 @@ mod example;
use crate::ExampleContainer;
use example::*;
use implicit_clone::unsync::IArray;
use web_sys::HtmlInputElement;
use yew::prelude::*;
use yewprint::{HtmlSelect, Intent, Switch, H1, H5};
@ -23,6 +24,8 @@ impl Component for TextAreaDoc {
large: false,
small: false,
fill: false,
grow_vertically: true,
text: "Hello, world!".into(),
},
}
}
@ -91,6 +94,19 @@ crate::build_example_prop_component! {
checked={ctx.props().example_props.small}
label={html!("Small")}
/>
<Switch
onclick={self.update_props(ctx, |props, _| ExampleProps {
grow_vertically: !props.grow_vertically,
..props
})}
checked={ctx.props().example_props.grow_vertically}
label={html!("Grow vertically")}
/>
<p
style="margin-top: 5px;"
>
{"Select intent:"}
</p>
<HtmlSelect<Option<Intent>>
options={[
(None, "None".into()),
@ -105,6 +121,30 @@ crate::build_example_prop_component! {
})}
value={ctx.props().example_props.intent}
/>
<p
style="margin-top: 5px;"
>
{"Default value:"}
</p>
<input
class="bp3-input"
onchange={self.update_props(ctx, |props, e: Event| {
if let Some(input) = e.target_dyn_into::<HtmlInputElement>() {
ExampleProps {
text: input.value().into(),
..props
}
} else {
ExampleProps {
text: "Hello, world!".into(),
..props
}
}
}
)}
type="text"
value={ctx.props().example_props.text.clone()}
/>
</div>
}
}