mirror of
https://github.com/yewprint/yewprint
synced 2024-11-25 04:50:20 +00:00
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:
parent
071bbd6d06
commit
31a3ba8946
6 changed files with 102 additions and 8 deletions
16
Cargo.lock
generated
16
Cargo.lock
generated
|
@ -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",
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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()}
|
||||
/>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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| {
|
||||
|
|
|
@ -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>
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue