增加Switch组件。

This commit is contained in:
徐涛 2024-12-28 07:59:04 +08:00
parent 0b9903f4f3
commit 2491fe162f
2 changed files with 82 additions and 0 deletions

View File

@ -0,0 +1,48 @@
@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) * 18);
height: calc(var(--spacing) * 10);
border: 1px solid var(--color-primary);
border-radius: var(--border-radius-xxs);
background-color: oklch(from var(--color-primary-active) calc(l * 0.5) calc(c * 0.5) h);
&::before {
content: '';
position: absolute;
transform: translate(1px, 2px);
width: calc(var(--spacing) * 7);
height: calc(var(--spacing) * 7);
background-color: var(--color-primary);
border-radius: var(--border-radius-xxs);
transition: transform 0.2s ease-in-out;
}
&.checked {
background-color: var(--color-primary-active);
&::before {
transform: translate(calc(var(--spacing) * 10 - 1px), 2px);
}
}
[aria-disabled] & {
--disabled-background: oklch(
from var(--color-primary-disabled) calc(l * 0.5) calc(c * 0.5) h
);
background-color: var(--disabled-background);
border-color: var(--color-primary-disabled);
&.checked {
background-color: oklch(from var(--disabled-background) calc(l + (1 - l) * 0.1) c h);
}
&::before {
background-color: var(--color-primary-disabled);
}
}
}
}

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

@ -0,0 +1,34 @@
import cx from 'clsx';
import { isEqual } from 'lodash-es';
import { useCallback, useEffect, useState } from 'react';
import styles from './Switch.module.css';
type SwitchProps = {
checked?: boolean;
disabled?: boolean;
onChange?: (checked: boolean) => void;
};
export function Switch({ checked = false, disabled = false, onChange }: SwitchProps) {
const [isChecked, setIsChecked] = useState(checked);
const handleSwitch = useCallback(() => {
if (!disabled) {
setIsChecked((prev) => !prev);
onChange?.(!isChecked);
}
}, [onChange, disabled]);
useEffect(() => {
if (!isEqual(checked, isChecked)) {
setIsChecked(checked);
}
}, [checked]);
return (
<div className={styles.switch} aria-disabled={disabled}>
<div
className={cx(styles.switch_handle, isChecked && styles.checked)}
onClick={handleSwitch}></div>
</div>
);
}