prepare switch component.
This commit is contained in:
parent
32d6e0c875
commit
d1d8def602
46
src/components/Switch.module.css
Normal file
46
src/components/Switch.module.css
Normal 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
38
src/components/Switch.tsx
Normal 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>
|
||||
);
|
||||
};
|
Loading…
Reference in New Issue
Block a user