prepare switch component.
This commit is contained in:
		
							
								
								
									
										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> | ||||||
|  |   ); | ||||||
|  | }; | ||||||
		Reference in New Issue
	
	Block a user