refactor: switch

This commit is contained in:
luoxiao 2024-06-03 10:44:51 +08:00
parent f5c0d2a522
commit dd50d450ff
5 changed files with 98 additions and 83 deletions

View file

@ -1,10 +1,10 @@
# Switch
```rust demo
let value = create_rw_signal(false);
let checked = RwSignal::new(false);
view! {
<Switch value />
<Switch checked />
}
```

View file

@ -1,46 +1,51 @@
mod theme;
pub use theme::SwitchTheme;
use crate::{theme::use_theme, Theme};
use leptos::*;
use thaw_utils::{class_list, mount_style, Model, OptionalProp};
#[component]
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)] label: MaybeProp<String>,
) -> impl IntoView {
mount_style("switch", include_str!("./switch.css"));
let theme = use_theme(Theme::light);
let css_vars = create_memo(move |_| {
let mut css_vars = String::new();
theme.with(|theme| {
css_vars.push_str(&format!(
"--thaw-background-color: {};",
theme.switch.background_color
));
css_vars.push_str(&format!(
"--thaw-background-color-active: {};",
theme.common.color_primary
));
});
css_vars
});
let id = uuid::Uuid::new_v4().to_string();
let input_ref = NodeRef::<html::Input>::new();
let on_change = move |_| {
let input = input_ref.get_untracked().unwrap();
checked.set(input.checked());
};
view! {
<div
class=class_list![
"thaw-switch", ("thaw-switch--active", move || value.get()), class.map(| c | move ||
"thaw-switch", class.map(| c | move ||
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>
}
}

View file

@ -1,42 +1,75 @@
.thaw-switch {
align-items: flex-start;
box-sizing: border-box;
display: inline-flex;
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;
top: 2px;
left: 2px;
display: inline-block;
width: 18px;
height: 18px;
border-radius: 9px;
background-color: #fff;
box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.3),
inset 0 0 1px 0 rgba(0, 0, 0, 0.05);
transition: all 0.4s ease;
top: 0px;
left: 0px;
width: calc(40px + 2 * var(--spacingHorizontalS));
height: 100%;
margin: 0px;
opacity: 0;
box-sizing: border-box;
cursor: pointer;
}
.thaw-switch--active {
background-color: var(--thaw-background-color-active);
.thaw-switch__indicator {
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 {
left: 20px;
.thaw-switch__input:enabled:not(:checked) ~ .thaw-switch__indicator {
color: var(--colorNeutralStrokeAccessible);
border-color: var(--colorNeutralStrokeAccessible);
}
.thaw-switch--active:active .thaw-switch__button {
left: 14px;
.thaw-switch__input:enabled:checked ~ .thaw-switch__indicator {
background-color: var(--colorCompoundBrandBackground);
color: var(--colorNeutralForegroundInverted);
border-color: var(--colorTransparentStroke);
}
.thaw-switch:active .thaw-switch__button {
width: 24px;
.thaw-switch__indicator > svg {
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);
}

View file

@ -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(),
}
}
}

View file

@ -6,8 +6,8 @@ use crate::{
mobile::{NavBarTheme, TabbarTheme},
AlertTheme, AnchorTheme, AutoCompleteTheme, BackTopTheme, BreadcrumbTheme, CalendarTheme,
ColorPickerTheme, DatePickerTheme, InputTheme, MenuTheme, MessageTheme, PopoverTheme,
ProgressTheme, ScrollbarTheme, SelectTheme, SkeletionTheme, SpinnerTheme, SwitchTheme,
TableTheme, TagTheme, TimePickerTheme, UploadTheme,
ProgressTheme, ScrollbarTheme, SelectTheme, SkeletionTheme, SpinnerTheme, TableTheme, TagTheme,
TimePickerTheme, UploadTheme,
};
pub use color::ColorTheme;
use leptos::*;
@ -30,7 +30,6 @@ pub struct Theme {
pub tag: TagTheme,
pub message: MessageTheme,
pub select: SelectTheme,
pub switch: SwitchTheme,
pub spinner: SpinnerTheme,
pub upload: UploadTheme,
pub nav_bar: NavBarTheme,
@ -62,7 +61,6 @@ impl Theme {
tag: TagTheme::light(),
message: MessageTheme::light(),
select: SelectTheme::light(),
switch: SwitchTheme::light(),
spinner: SpinnerTheme::light(),
upload: UploadTheme::light(),
nav_bar: NavBarTheme::light(),
@ -93,7 +91,6 @@ impl Theme {
tag: TagTheme::dark(),
message: MessageTheme::dark(),
select: SelectTheme::dark(),
switch: SwitchTheme::dark(),
spinner: SpinnerTheme::dark(),
upload: UploadTheme::dark(),
nav_bar: NavBarTheme::dark(),