import React, { useCallback, useEffect, useMemo, useState } from 'react' import withDefaults from '../utils/with-defaults' import useTheme from '../styles/use-theme' import { NormalSizes } from '../utils/prop-types' interface ToggleEventTarget { checked: boolean } export interface ToggleEvent { target: ToggleEventTarget stopPropagation: () => void preventDefault: () => void nativeEvent: React.ChangeEvent } interface Props { checked?: boolean initialChecked?: boolean onChange?: (ev: ToggleEvent) => void disabled?: boolean size?: NormalSizes className?: string } const defaultProps = { size: 'medium' as NormalSizes, disabled: false, initialChecked: false, className: '', } type NativeAttrs = Omit, keyof Props> export type ToggleProps = Props & typeof defaultProps & NativeAttrs export type ToggleSize = { width: string height: string } const getSizes = (size: NormalSizes) => { const sizes: { [key in NormalSizes]: ToggleSize } = { mini: { width: '1.67rem', height: '.835rem', }, small: { width: '1.67rem', height: '.835rem', }, medium: { width: '1.75rem', height: '.875rem', }, large: { width: '2rem', height: '1rem', }, } return sizes[size] } const Toggle: React.FC = ({ initialChecked, checked, disabled, onChange, size, className, ...props }) => { const theme = useTheme() const [selfChecked, setSelfChecked] = useState(initialChecked) const { width, height } = useMemo(() => getSizes(size), [size]) const changeHandle = useCallback( (ev: React.ChangeEvent) => { if (disabled) return const selfEvent: ToggleEvent = { target: { checked: !selfChecked, }, stopPropagation: ev.stopPropagation, preventDefault: ev.preventDefault, nativeEvent: ev, } setSelfChecked(!selfChecked) onChange && onChange(selfEvent) }, [disabled, selfChecked, onChange], ) useEffect(() => { if (checked === undefined) return setSelfChecked(checked) }, [checked]) return ( ) } const MemoToggle = React.memo(Toggle) export default withDefaults(MemoToggle, defaultProps)