import React, { useEffect, useMemo, useRef, useState } from 'react' import { NormalSizes } from '../utils/prop-types' import useClickAway from '../utils/use-click-away' import { pickChildByProps, pickChildrenFirst } from '../utils/collections' import SelectIcon from './select-icon' import SelectOption from './select-option' import useTheme from '../styles/use-theme' import SelectDropdown from './select-dropdown' import { SelectContext, SelectConfig } from './select-context' import { getSizes } from './styles' interface Props { disabled?: boolean size?: NormalSizes value?: string initialValue?: string placeholder?: React.ReactNode | string icon?: React.ComponentType onChange?: (value: string) => void pure?: boolean className?: string dropdownClassName?: string dropdownStyle?: object } const defaultProps = { disabled: false, size: 'medium' as NormalSizes, icon: SelectIcon as React.ComponentType, pure: false, className: '', } type NativeAttrs = Omit, keyof Props> export type SelectProps = Props & typeof defaultProps & NativeAttrs const Select: React.FC> = ({ children, size, disabled, initialValue: init, value: customValue, icon: Icon, onChange, className, pure, placeholder, dropdownClassName, dropdownStyle, ...props }) => { const theme = useTheme() const ref = useRef(null) const [visible, setVisible] = useState(false) const [value, setValue] = useState(init) const sizes = useMemo(() => getSizes(theme, size), [theme, size]) const updateVisible = (next: boolean) => setVisible(next) const updateValue = (next: string) => { setValue(next) onChange && onChange(next) setVisible(false) } const initialValue: SelectConfig = useMemo( () => ({ value, visible, updateValue, updateVisible, size, ref, disableAll: disabled, }), [visible, size, disabled, ref], ) const clickHandler = (event: React.MouseEvent) => { event.stopPropagation() event.nativeEvent.stopImmediatePropagation() event.preventDefault() if (disabled) return setVisible(!visible) } useClickAway(ref, () => setVisible(false)) useEffect(() => { if (customValue === undefined) return setValue(customValue) }, [customValue]) const selectedChild = useMemo(() => { const [, optionChildren] = pickChildByProps(children, 'value', value) const child = pickChildrenFirst(optionChildren) if (!React.isValidElement(child)) return optionChildren return React.cloneElement(child, { preventAllEvents: true }) }, [value, children]) return (
{!value && {placeholder}} {value && {selectedChild}} {children} {!pure && (
)}
) } type SelectComponent

= React.FC

& { Option: typeof SelectOption } type ComponentProps = Partial & Omit & NativeAttrs ;(Select as SelectComponent).defaultProps = defaultProps export default Select as SelectComponent