mirror of
https://github.com/yewprint/yewprint
synced 2025-02-16 12:08:25 +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"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "2.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "24a6904aef64d73cf10ab17ebace7befb918b82164785cb89907993be7f83813"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "boolinator"
|
name = "boolinator"
|
||||||
version = "2.4.0"
|
version = "2.4.0"
|
||||||
|
@ -182,11 +188,11 @@ checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.0.29"
|
version = "4.1.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4d63b9e9c07271b9957ad22c173bae2a4d9a81127680962039296abcd2f8251d"
|
checksum = "42dfd32784433290c51d92c438bb72ea5063797fc3cc9a21a8c4346bebbb2098"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 2.2.1",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
"clap_lex",
|
"clap_lex",
|
||||||
"is-terminal",
|
"is-terminal",
|
||||||
|
@ -197,9 +203,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_derive"
|
name = "clap_derive"
|
||||||
version = "4.0.21"
|
version = "4.1.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014"
|
checksum = "fddf67631444a3a3e3e5ac51c36a5e01335302de677bd78759eaa90ab1f46644"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck 0.4.0",
|
"heck 0.4.0",
|
||||||
"proc-macro-error",
|
"proc-macro-error",
|
||||||
|
|
|
@ -22,7 +22,7 @@ gloo = "0.8"
|
||||||
id_tree = { version = "1.8", optional = true }
|
id_tree = { version = "1.8", optional = true }
|
||||||
implicit-clone = "0.3.5"
|
implicit-clone = "0.3.5"
|
||||||
wasm-bindgen = "0.2"
|
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 = "0.20"
|
||||||
yew-callbacks = "0.2.1"
|
yew-callbacks = "0.2.1"
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
use crate::Intent;
|
use crate::Intent;
|
||||||
|
use wasm_bindgen::JsCast;
|
||||||
|
use web_sys::HtmlTextAreaElement;
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
|
@ -7,7 +9,8 @@ pub struct TextAreaProps {
|
||||||
pub class: Classes,
|
pub class: Classes,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub fill: bool,
|
pub fill: bool,
|
||||||
//TODO pub grow_vertically: bool,
|
#[prop_or_default]
|
||||||
|
pub grow_vertically: bool,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub r#ref: NodeRef,
|
pub r#ref: NodeRef,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
|
@ -18,6 +21,15 @@ pub struct TextAreaProps {
|
||||||
pub small: bool,
|
pub small: bool,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub onchange: Callback<Event>,
|
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)]
|
#[function_component(TextArea)]
|
||||||
|
@ -25,13 +37,38 @@ pub fn text_area(
|
||||||
TextAreaProps {
|
TextAreaProps {
|
||||||
class,
|
class,
|
||||||
fill,
|
fill,
|
||||||
|
grow_vertically,
|
||||||
r#ref,
|
r#ref,
|
||||||
intent,
|
intent,
|
||||||
large,
|
large,
|
||||||
small,
|
small,
|
||||||
onchange,
|
onchange,
|
||||||
|
value,
|
||||||
}: &TextAreaProps,
|
}: &TextAreaProps,
|
||||||
) -> Html {
|
) -> 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! {
|
html! {
|
||||||
<textarea
|
<textarea
|
||||||
class={classes!(
|
class={classes!(
|
||||||
|
@ -44,6 +81,8 @@ pub fn text_area(
|
||||||
)}
|
)}
|
||||||
ref={r#ref}
|
ref={r#ref}
|
||||||
{onchange}
|
{onchange}
|
||||||
|
{oninput}
|
||||||
|
value={value.clone()}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,11 @@ crate::build_example_prop_component! {
|
||||||
checked={ctx.props().example_props.ellipsize}
|
checked={ctx.props().example_props.ellipsize}
|
||||||
label={html!("Ellipsize")}
|
label={html!("Ellipsize")}
|
||||||
/>
|
/>
|
||||||
|
<p
|
||||||
|
style="margin-top: 5px;"
|
||||||
|
>
|
||||||
|
{"Value:"}
|
||||||
|
</p>
|
||||||
<input
|
<input
|
||||||
class="bp3-input"
|
class="bp3-input"
|
||||||
onchange={self.update_props(ctx, |props, e: Event| {
|
onchange={self.update_props(ctx, |props, e: Event| {
|
||||||
|
|
|
@ -7,16 +7,20 @@ pub struct ExampleProps {
|
||||||
pub small: bool,
|
pub small: bool,
|
||||||
pub large: bool,
|
pub large: bool,
|
||||||
pub fill: bool,
|
pub fill: bool,
|
||||||
|
pub grow_vertically: bool,
|
||||||
|
pub text: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[function_component(Example)]
|
#[function_component(Example)]
|
||||||
pub fn example(props: &ExampleProps) -> Html {
|
pub fn example(props: &ExampleProps) -> Html {
|
||||||
html! {
|
html! {
|
||||||
<div style="width: 200px; height: 50px">
|
<div style="width: 200px; min-height: 50px">
|
||||||
<TextArea intent={props.intent}
|
<TextArea intent={props.intent}
|
||||||
large={props.large}
|
large={props.large}
|
||||||
fill={props.fill}
|
fill={props.fill}
|
||||||
small={props.small}
|
small={props.small}
|
||||||
|
grow_vertically={props.grow_vertically}
|
||||||
|
value={Some(props.text.clone())}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ mod example;
|
||||||
use crate::ExampleContainer;
|
use crate::ExampleContainer;
|
||||||
use example::*;
|
use example::*;
|
||||||
use implicit_clone::unsync::IArray;
|
use implicit_clone::unsync::IArray;
|
||||||
|
use web_sys::HtmlInputElement;
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yewprint::{HtmlSelect, Intent, Switch, H1, H5};
|
use yewprint::{HtmlSelect, Intent, Switch, H1, H5};
|
||||||
|
|
||||||
|
@ -23,6 +24,8 @@ impl Component for TextAreaDoc {
|
||||||
large: false,
|
large: false,
|
||||||
small: false,
|
small: false,
|
||||||
fill: 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}
|
checked={ctx.props().example_props.small}
|
||||||
label={html!("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>>
|
<HtmlSelect<Option<Intent>>
|
||||||
options={[
|
options={[
|
||||||
(None, "None".into()),
|
(None, "None".into()),
|
||||||
|
@ -105,6 +121,30 @@ crate::build_example_prop_component! {
|
||||||
})}
|
})}
|
||||||
value={ctx.props().example_props.intent}
|
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>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue