feat: implement disabled behavior for all components
This commit is contained in:
1 parent
75a8f2d6d4
commit
df8b248ae4
4 files changed
+83
-67
No files matched your search
@@ -4,7 +4,8 @@ use leptos::prelude::*;
|
|||||||
pub fn Checkbox(
|
pub fn Checkbox(
|
||||||
#[prop()] checked: Signal<bool>,
|
#[prop()] checked: Signal<bool>,
|
||||||
#[prop(into)] on_change: Callback<(), ()>,
|
#[prop(into)] on_change: Callback<(), ()>,
|
||||||
#[prop(into)] value: String
|
#[prop(into)] value: String,
|
||||||
|
#[prop(default = RwSignal::new(false))] disabled: RwSignal<bool>,
|
||||||
) -> impl IntoView {
|
) -> impl IntoView {
|
||||||
view! {
|
view! {
|
||||||
<label for=value
|
<label for=value
|
||||||
@@ -20,13 +21,16 @@ pub fn Checkbox(
|
|||||||
id={value.clone()}
|
id={value.clone()}
|
||||||
on:change = move |_| on_change.run(())
|
on:change = move |_| on_change.run(())
|
||||||
prop:checked = checked
|
prop:checked = checked
|
||||||
|
disabled = disabled
|
||||||
/>
|
/>
|
||||||
// This div displays the box for the checkbox, and applies some styling to the child
|
// This div displays the box for the checkbox, and applies some styling to the child
|
||||||
// span element.
|
// span element.
|
||||||
<div
|
<div
|
||||||
class="relative inline-block h-5 w-5 m-1 rounded-sm border border-gray-300 bg-white
|
class="relative inline-block h-5 w-5 m-1 mr-2 rounded-sm border border-gray-300 bg-white
|
||||||
transition-bg duration-150 peer-checked:bg-red-700 peer-checked:border-red-700
|
transition-bg duration-150 peer-checked:bg-red-700 peer-checked:border-red-700
|
||||||
[&>span]:opacity-0 peer-checked:[&>span]:opacity-100"
|
[&>span]:opacity-0 peer-checked:[&>span]:opacity-100
|
||||||
|
peer-disabled:bg-gray-600/33 peer-disabled:border-gray-600
|
||||||
|
peer-disabled:peer-checked:bg-gray-600"
|
||||||
>
|
>
|
||||||
// This span is the check icon. It is centered within the div and has a border on the bottom
|
// This span is the check icon. It is centered within the div and has a border on the bottom
|
||||||
// and right sides, which is then rotated to appear like a checkmark.
|
// and right sides, which is then rotated to appear like a checkmark.
|
||||||
@@ -44,7 +48,8 @@ pub fn Checkbox(
|
|||||||
#[component]
|
#[component]
|
||||||
pub fn CheckboxList(
|
pub fn CheckboxList(
|
||||||
#[prop(default = RwSignal::new(vec![]))] selected: RwSignal<Vec<String>>,
|
#[prop(default = RwSignal::new(vec![]))] selected: RwSignal<Vec<String>>,
|
||||||
#[prop()] items: Vec<String>
|
#[prop()] items: Vec<String>,
|
||||||
|
#[prop(default = RwSignal::new(false))] disabled: RwSignal<bool>,
|
||||||
) -> impl IntoView {
|
) -> impl IntoView {
|
||||||
view! {
|
view! {
|
||||||
// Checkbox elements go in here. Each one will have a derived signal
|
// Checkbox elements go in here. Each one will have a derived signal
|
||||||
@@ -53,39 +58,42 @@ pub fn CheckboxList(
|
|||||||
|
|
||||||
// Somehow create a derived signal??
|
// Somehow create a derived signal??
|
||||||
|
|
||||||
{
|
<div>
|
||||||
items.into_iter().map(|item| {
|
{
|
||||||
let is_checked = {
|
items.into_iter().map(|item| {
|
||||||
let item_name = item.clone();
|
let is_checked = {
|
||||||
move || {
|
let item_name = item.clone();
|
||||||
// Check if this checkbox should be selected
|
move || {
|
||||||
selected.get().contains(&item_name)
|
// Check if this checkbox should be selected
|
||||||
}
|
selected.get().contains(&item_name)
|
||||||
};
|
|
||||||
|
|
||||||
let checked_signal = Signal::derive(is_checked);
|
|
||||||
|
|
||||||
view! {
|
|
||||||
<Checkbox
|
|
||||||
checked = checked_signal
|
|
||||||
on_change = {
|
|
||||||
// Clone this value to avoid moving it into the closure
|
|
||||||
let item_name = item.clone();
|
|
||||||
move || {
|
|
||||||
selected.update(|list| {
|
|
||||||
// Check if the list contains this element. If so, remove it. If not, add it.
|
|
||||||
if let Some(index) = list.iter().position(|val| *val == item_name) {
|
|
||||||
list.remove(index);
|
|
||||||
} else {
|
|
||||||
list.push(item_name.clone());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// The actual selected values are tracked by this element, not by the checkboxes themselves.
|
};
|
||||||
value = item.clone() />
|
|
||||||
}
|
let checked_signal = Signal::derive(is_checked);
|
||||||
}).collect::<Vec<_>>()
|
|
||||||
}
|
view! {
|
||||||
|
<Checkbox
|
||||||
|
checked = checked_signal
|
||||||
|
on_change = {
|
||||||
|
// Clone this value to avoid moving it into the closure
|
||||||
|
let item_name = item.clone();
|
||||||
|
move || {
|
||||||
|
selected.update(|list| {
|
||||||
|
// Check if the list contains this element. If so, remove it. If not, add it.
|
||||||
|
if let Some(index) = list.iter().position(|val| *val == item_name) {
|
||||||
|
list.remove(index);
|
||||||
|
} else {
|
||||||
|
list.push(item_name.clone());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// The actual selected values are tracked by this element, not by the checkboxes themselves.
|
||||||
|
value = item.clone()
|
||||||
|
disabled = disabled />
|
||||||
|
}
|
||||||
|
}).collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16,12 +16,14 @@ pub fn Select(
|
|||||||
<label>
|
<label>
|
||||||
{label}
|
{label}
|
||||||
<select
|
<select
|
||||||
class="relative border-2 m-1.5 p-1.5 rounded-md"
|
class="relative border-2 m-1.5 p-1.5 rounded-md
|
||||||
class=(["border-red-700", "bg-transparent"], move || !disabled.get())
|
transition-border duration-150
|
||||||
class=(["border-gray-600", "pointer-events-none", "bg-gray-600/33"], move || disabled.get())
|
border-red-700 bg-transparent
|
||||||
|
disabled:border-gray-600 disabled:pointer-events-none disabled:bg-gray-600/33"
|
||||||
on:change:target=move |e| {
|
on:change:target=move |e| {
|
||||||
value.set(e.target().value());
|
value.set(e.target().value());
|
||||||
}>
|
}
|
||||||
|
disabled = disabled >
|
||||||
// This closure handles the display of the options.
|
// This closure handles the display of the options.
|
||||||
{move || {
|
{move || {
|
||||||
value_list.iter().map(
|
value_list.iter().map(
|
||||||
|
|||||||
@@ -22,19 +22,21 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
view! (
|
view! (
|
||||||
<label>
|
<div>
|
||||||
{ label }
|
<label>
|
||||||
<input
|
{ label }
|
||||||
class="border-2 m-1.5 p-1.5 rounded-md bg-transparent mt-6 relative transition-all duration-400"
|
<input
|
||||||
class=(["border-red-700", "bg-transparent"], move || !disabled.get())
|
class="border-2 m-1.5 p-1.5 rounded-md bg-transparent mt-6 relative transition-all duration-150
|
||||||
class=(["border-gray-600", "pointer-events-none", "bg-gray-600/33"], move || disabled.get())
|
border-red-700 bg-transparent
|
||||||
r#type={input_type}
|
disabled:border-gray-600 disabled:pointer-events-none disabled:bg-gray-600/33"
|
||||||
disabled={disabled}
|
r#type={input_type}
|
||||||
placeholder={placeholder}
|
disabled={disabled}
|
||||||
prop:name=name
|
placeholder={placeholder}
|
||||||
prop:value={move || value.get().to_string()} // Sets the initial value.
|
prop:name=name
|
||||||
on:input=on_input // Sets the value on each input.
|
prop:value={move || value.get().to_string()} // Sets the initial value.
|
||||||
/>
|
on:input=on_input // Sets the value on each input.
|
||||||
</label>
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
+16
-12
@@ -155,39 +155,43 @@ pub fn HomePage() -> impl IntoView {
|
|||||||
let select_value = RwSignal::new(String::from("Math"));
|
let select_value = RwSignal::new(String::from("Math"));
|
||||||
let chk_select = RwSignal::new(vec!["Testing 2".into()]);
|
let chk_select = RwSignal::new(vec!["Testing 2".into()]);
|
||||||
|
|
||||||
|
let elements_disabled = RwSignal::new(false);
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
<p>
|
<p>
|
||||||
"Current user's reported full name from the API: "
|
"Current user's reported full name from the API: "
|
||||||
{reactive_info.first_name}" "{reactive_info.last_name}
|
{reactive_info.first_name}" "{reactive_info.last_name}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<form>
|
<form
|
||||||
<div>
|
class="flex flex-col gap-4">
|
||||||
|
<div class="flex flex-row gap-2">
|
||||||
<OutlinedTextField
|
<OutlinedTextField
|
||||||
label="First Name".into()
|
label="First Name".into()
|
||||||
placeholder="John".into()
|
placeholder="John".into()
|
||||||
|
disabled=elements_disabled
|
||||||
value=reactive_info.first_name />
|
value=reactive_info.first_name />
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<OutlinedTextField
|
<OutlinedTextField
|
||||||
label="Last Name".into()
|
label="Last Name".into()
|
||||||
placeholder="Smith".into()
|
placeholder="Smith".into()
|
||||||
|
disabled=elements_disabled
|
||||||
value=reactive_info.last_name />
|
value=reactive_info.last_name />
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<OutlinedTextField
|
<OutlinedTextField
|
||||||
label="Testing".into()
|
label="Testing".into()
|
||||||
placeholder="Test".into()
|
placeholder="Test".into()
|
||||||
|
disabled=elements_disabled
|
||||||
value=reactive_info.math_sat_score />
|
value=reactive_info.math_sat_score />
|
||||||
</div>
|
</div>
|
||||||
<Select
|
<div class="flex flex-row gap-2">
|
||||||
value_list = vec!["Math".into(), "English".into(), "Science".into()]
|
<Select
|
||||||
value = select_value
|
value_list = vec!["Math".into(), "English".into(), "Science".into()]
|
||||||
/>
|
value = select_value
|
||||||
<div>
|
disabled=elements_disabled
|
||||||
|
/>
|
||||||
<CheckboxList
|
<CheckboxList
|
||||||
selected = chk_select
|
selected = chk_select
|
||||||
items = vec!["Testing 1".into(), "Testing 2".into()] />
|
items = vec!["Testing 1".into(), "Testing 2".into()]
|
||||||
|
disabled=elements_disabled />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
|
|||||||
Reference in new issue
Block a user