prepare switch component.

This commit is contained in:
Vixalie 2025-03-09 22:14:20 +08:00
parent 32d6e0c875
commit d1d8def602
2 changed files with 84 additions and 0 deletions

View File

@ -0,0 +1,46 @@
@layer components {
.switch {
display: inline-flex;
align-items: center;
gap: 1em;
cursor: pointer;
&[aria-disabled] {
cursor: not-allowed;
}
}
.switch_handle {
position: relative;
width: calc(var(--spacing) * 9);
height: calc(var(--spacing) * 5);
border: 1px solid var(--color-primary);
border-radius: calc(var(--border-radius) * 2);
background-color: var(--color-surface-container-high);
&::before {
content: '';
position: absolute;
transform: translate(1px, 2px);
width: calc(var(--spacing) * 3);
height: calc(var(--spacing) * 3);
border-radius: calc(var(--border-radius) * 2);
background-color: var(--color-primary);
transition: transform 0.2s ease-in-out;
}
&.checked {
background-color: var(--color-primary);
&::before {
transform: translate(calc(var(--spacing) * 5 - 1px), 2px);
}
[aria-disabled] & {
--disabled-color: color-mix(in oklch, var(--color-on-surface) 38%, transparent);
background-color: var(--disabled-color);
border-color: var(--disabled-color);
&.checked {
background-color: var(--disabled-color);
}
&::before {
background-color: color-mix(in oklch, var(--color-on-surface) 45%, transparent);
}
}
}
}
}

38
src/components/Switch.tsx Normal file
View File

@ -0,0 +1,38 @@
import cx from 'clsx';
import { FC, useCallback, useEffect, useState } from 'react';
import styles from './Switch.module.css';
type SwitchProps = {
name?: string;
checked?: boolean;
disabled?: boolean;
onChange?: (checked: boolean) => void;
};
const Switch: FC<SwitchProps> = ({ name, checked = false, disabled = false, onChange }) => {
const [isChecked, setChecked] = useState(checked);
const handleChange = useCallback(() => {
if (!disabled) {
setChecked((prev) => !prev);
onChange?.(!isChecked);
}
}, [disabled, onChange, isChecked]);
useEffect(() => {
if (checked !== isChecked) {
setChecked(checked);
}
}, [checked]);
return (
<div aria-disabled={disabled} className={styles.switch}>
<div
className={cx(styles.switch_handle, isChecked && styles.checked)}
onClick={handleChange}
/>
{name !== undefined && (
<input type="hidden" name={name} value={isChecked ? 'true' : 'false'} />
)}
</div>
);
};