mirror of
https://github.com/adoyle0/thaw.git
synced 2025-01-22 22:09:22 -05:00
refactor: switch
This commit is contained in:
parent
f5c0d2a522
commit
dd50d450ff
5 changed files with 98 additions and 83 deletions
|
@ -1,10 +1,10 @@
|
||||||
# Switch
|
# Switch
|
||||||
|
|
||||||
```rust demo
|
```rust demo
|
||||||
let value = create_rw_signal(false);
|
let checked = RwSignal::new(false);
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
<Switch value />
|
<Switch checked />
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -1,46 +1,51 @@
|
||||||
mod theme;
|
|
||||||
|
|
||||||
pub use theme::SwitchTheme;
|
|
||||||
|
|
||||||
use crate::{theme::use_theme, Theme};
|
|
||||||
use leptos::*;
|
use leptos::*;
|
||||||
use thaw_utils::{class_list, mount_style, Model, OptionalProp};
|
use thaw_utils::{class_list, mount_style, Model, OptionalProp};
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Switch(
|
pub fn Switch(
|
||||||
#[prop(optional, into)] value: Model<bool>,
|
#[prop(optional, into)] checked: Model<bool>,
|
||||||
#[prop(optional, into)] class: OptionalProp<MaybeSignal<String>>,
|
#[prop(optional, into)] class: OptionalProp<MaybeSignal<String>>,
|
||||||
|
#[prop(optional, into)] label: MaybeProp<String>,
|
||||||
) -> impl IntoView {
|
) -> impl IntoView {
|
||||||
mount_style("switch", include_str!("./switch.css"));
|
mount_style("switch", include_str!("./switch.css"));
|
||||||
let theme = use_theme(Theme::light);
|
|
||||||
let css_vars = create_memo(move |_| {
|
let id = uuid::Uuid::new_v4().to_string();
|
||||||
let mut css_vars = String::new();
|
let input_ref = NodeRef::<html::Input>::new();
|
||||||
theme.with(|theme| {
|
let on_change = move |_| {
|
||||||
css_vars.push_str(&format!(
|
let input = input_ref.get_untracked().unwrap();
|
||||||
"--thaw-background-color: {};",
|
checked.set(input.checked());
|
||||||
theme.switch.background_color
|
};
|
||||||
));
|
|
||||||
css_vars.push_str(&format!(
|
|
||||||
"--thaw-background-color-active: {};",
|
|
||||||
theme.common.color_primary
|
|
||||||
));
|
|
||||||
});
|
|
||||||
css_vars
|
|
||||||
});
|
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
<div
|
<div
|
||||||
class=class_list![
|
class=class_list![
|
||||||
"thaw-switch", ("thaw-switch--active", move || value.get()), class.map(| c | move ||
|
"thaw-switch", class.map(| c | move ||
|
||||||
c.get())
|
c.get())
|
||||||
]
|
]
|
||||||
|
|
||||||
style=move || css_vars.get()
|
|
||||||
on:click=move |_| value.set(!value.get_untracked())
|
|
||||||
role="switch"
|
|
||||||
aria-checked=move || if value.get() { "true" } else { "false" }
|
|
||||||
>
|
>
|
||||||
<div class="thaw-switch__button"></div>
|
<input
|
||||||
|
class="thaw-switch__input"
|
||||||
|
role="switch"
|
||||||
|
type="checkbox"
|
||||||
|
id=id.clone()
|
||||||
|
checked=checked.get_untracked()
|
||||||
|
ref=input_ref
|
||||||
|
on:change=on_change
|
||||||
|
/>
|
||||||
|
<div aria-hidden="true" class="thaw-switch__indicator thaw-switch__button">
|
||||||
|
<svg fill="currentColor" aria-hidden="true" width="1em" height="1em" viewBox="0 0 20 20">
|
||||||
|
<path d="M10 2a8 8 0 1 0 0 16 8 8 0 0 0 0-16Z" fill="currentColor"></path>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
{
|
||||||
|
move || if let Some(label) = label.get() {
|
||||||
|
view! {
|
||||||
|
<label class="thaw-switch__label" for=id.clone()>{label}</label>
|
||||||
|
}.into()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,42 +1,75 @@
|
||||||
.thaw-switch {
|
.thaw-switch {
|
||||||
|
align-items: flex-start;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: inline-flex;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-block;
|
|
||||||
width: 40px;
|
|
||||||
height: 22px;
|
|
||||||
background-color: var(--thaw-background-color);
|
|
||||||
border-radius: 11px;
|
|
||||||
cursor: pointer;
|
|
||||||
box-shadow: inset 0 0 1px 0 rgba(0, 0, 0, 0.05);
|
|
||||||
transition: all 0.4s ease;
|
|
||||||
user-select: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.thaw-switch__button {
|
.thaw-switch__input {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 2px;
|
top: 0px;
|
||||||
left: 2px;
|
left: 0px;
|
||||||
display: inline-block;
|
width: calc(40px + 2 * var(--spacingHorizontalS));
|
||||||
width: 18px;
|
height: 100%;
|
||||||
height: 18px;
|
margin: 0px;
|
||||||
border-radius: 9px;
|
opacity: 0;
|
||||||
background-color: #fff;
|
box-sizing: border-box;
|
||||||
box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.3),
|
cursor: pointer;
|
||||||
inset 0 0 1px 0 rgba(0, 0, 0, 0.05);
|
|
||||||
transition: all 0.4s ease;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.thaw-switch--active {
|
.thaw-switch__indicator {
|
||||||
background-color: var(--thaw-background-color-active);
|
flex-shrink: 0;
|
||||||
|
width: 40px;
|
||||||
|
height: 20px;
|
||||||
|
margin: var(--spacingVerticalS) var(--spacingHorizontalS);
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 0;
|
||||||
|
border-radius: var(--borderRadiusCircular);
|
||||||
|
border: 1px solid;
|
||||||
|
box-sizing: border-box;
|
||||||
|
fill: currentcolor;
|
||||||
|
pointer-events: none;
|
||||||
|
transition-duration: var(--durationNormal);
|
||||||
|
transition-timing-function: var(--curveEasyEase);
|
||||||
|
transition-property: background, border, color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.thaw-switch--active .thaw-switch__button {
|
.thaw-switch__input:enabled:not(:checked) ~ .thaw-switch__indicator {
|
||||||
left: 20px;
|
color: var(--colorNeutralStrokeAccessible);
|
||||||
|
border-color: var(--colorNeutralStrokeAccessible);
|
||||||
}
|
}
|
||||||
|
|
||||||
.thaw-switch--active:active .thaw-switch__button {
|
.thaw-switch__input:enabled:checked ~ .thaw-switch__indicator {
|
||||||
left: 14px;
|
background-color: var(--colorCompoundBrandBackground);
|
||||||
|
color: var(--colorNeutralForegroundInverted);
|
||||||
|
border-color: var(--colorTransparentStroke);
|
||||||
}
|
}
|
||||||
|
|
||||||
.thaw-switch:active .thaw-switch__button {
|
.thaw-switch__indicator > svg {
|
||||||
width: 24px;
|
display: inline;
|
||||||
|
line-height: 0;
|
||||||
|
|
||||||
|
transition-duration: var(--durationNormal);
|
||||||
|
transition-timing-function: var(--curveEasyEase);
|
||||||
|
transition-property: transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thaw-switch__input:checked ~ .thaw-switch__indicator > svg {
|
||||||
|
transform: translateX(20px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.thaw-switch__label {
|
||||||
|
margin-top: calc((20px - var(--lineHeightBase300)) / 2);
|
||||||
|
margin-bottom: calc((20px - var(--lineHeightBase300)) / 2);
|
||||||
|
padding: var(--spacingVerticalS) var(--spacingHorizontalS);
|
||||||
|
padding-left: var(--spacingHorizontalXS);
|
||||||
|
line-height: var(--lineHeightBase300);
|
||||||
|
font-size: var(--fontSizeBase300);
|
||||||
|
font-family: var(--fontFamilyBase);
|
||||||
|
color: var(--colorNeutralForeground1);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thaw-switch__input:enabled:not(:checked) ~ .thaw-switch__label {
|
||||||
|
color: var(--colorNeutralForeground1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
use crate::theme::ThemeMethod;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct SwitchTheme {
|
|
||||||
pub background_color: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ThemeMethod for SwitchTheme {
|
|
||||||
fn light() -> Self {
|
|
||||||
Self {
|
|
||||||
background_color: "#00000024".into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dark() -> Self {
|
|
||||||
Self {
|
|
||||||
background_color: "#ffffff33".into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,8 +6,8 @@ use crate::{
|
||||||
mobile::{NavBarTheme, TabbarTheme},
|
mobile::{NavBarTheme, TabbarTheme},
|
||||||
AlertTheme, AnchorTheme, AutoCompleteTheme, BackTopTheme, BreadcrumbTheme, CalendarTheme,
|
AlertTheme, AnchorTheme, AutoCompleteTheme, BackTopTheme, BreadcrumbTheme, CalendarTheme,
|
||||||
ColorPickerTheme, DatePickerTheme, InputTheme, MenuTheme, MessageTheme, PopoverTheme,
|
ColorPickerTheme, DatePickerTheme, InputTheme, MenuTheme, MessageTheme, PopoverTheme,
|
||||||
ProgressTheme, ScrollbarTheme, SelectTheme, SkeletionTheme, SpinnerTheme, SwitchTheme,
|
ProgressTheme, ScrollbarTheme, SelectTheme, SkeletionTheme, SpinnerTheme, TableTheme, TagTheme,
|
||||||
TableTheme, TagTheme, TimePickerTheme, UploadTheme,
|
TimePickerTheme, UploadTheme,
|
||||||
};
|
};
|
||||||
pub use color::ColorTheme;
|
pub use color::ColorTheme;
|
||||||
use leptos::*;
|
use leptos::*;
|
||||||
|
@ -30,7 +30,6 @@ pub struct Theme {
|
||||||
pub tag: TagTheme,
|
pub tag: TagTheme,
|
||||||
pub message: MessageTheme,
|
pub message: MessageTheme,
|
||||||
pub select: SelectTheme,
|
pub select: SelectTheme,
|
||||||
pub switch: SwitchTheme,
|
|
||||||
pub spinner: SpinnerTheme,
|
pub spinner: SpinnerTheme,
|
||||||
pub upload: UploadTheme,
|
pub upload: UploadTheme,
|
||||||
pub nav_bar: NavBarTheme,
|
pub nav_bar: NavBarTheme,
|
||||||
|
@ -62,7 +61,6 @@ impl Theme {
|
||||||
tag: TagTheme::light(),
|
tag: TagTheme::light(),
|
||||||
message: MessageTheme::light(),
|
message: MessageTheme::light(),
|
||||||
select: SelectTheme::light(),
|
select: SelectTheme::light(),
|
||||||
switch: SwitchTheme::light(),
|
|
||||||
spinner: SpinnerTheme::light(),
|
spinner: SpinnerTheme::light(),
|
||||||
upload: UploadTheme::light(),
|
upload: UploadTheme::light(),
|
||||||
nav_bar: NavBarTheme::light(),
|
nav_bar: NavBarTheme::light(),
|
||||||
|
@ -93,7 +91,6 @@ impl Theme {
|
||||||
tag: TagTheme::dark(),
|
tag: TagTheme::dark(),
|
||||||
message: MessageTheme::dark(),
|
message: MessageTheme::dark(),
|
||||||
select: SelectTheme::dark(),
|
select: SelectTheme::dark(),
|
||||||
switch: SwitchTheme::dark(),
|
|
||||||
spinner: SpinnerTheme::dark(),
|
spinner: SpinnerTheme::dark(),
|
||||||
upload: UploadTheme::dark(),
|
upload: UploadTheme::dark(),
|
||||||
nav_bar: NavBarTheme::dark(),
|
nav_bar: NavBarTheme::dark(),
|
||||||
|
|
Loading…
Add table
Reference in a new issue