import { useToken } from '@chakra-ui/react'; import { mergeWith } from '@chakra-ui/utils'; /* eslint-disable react-hooks/exhaustive-deps */ import { useCallback } from 'react'; import { useMobile, useOpposingColor, useOpposingColorCallback, } from '~/hooks'; import { useSelectContext } from './select'; import * as ReactSelect from 'react-select'; import type { SingleOption } from '~/types'; import type { RSStyleCallbackProps, RSStyleFunction, RSThemeFunction } from './types'; export const useContainerStyle = ( props: RSStyleCallbackProps, ): RSStyleFunction<'container', Opt, IsMulti> => { return useCallback((base, state) => { return { width: '100%' }; }, []); }; export const useControlStyle = ( props: RSStyleCallbackProps, ): RSStyleFunction<'control', Opt, IsMulti> => { const { colorMode } = props; const { isError } = useSelectContext(); const focusBorder = useToken('colors', 'brand.500'); const invalidBorder = useToken('colors', 'red.500'); const borderHover = useToken('colors', 'gray.300'); return useCallback( (base, state) => { const { isFocused } = state; const styles = { backgroundColor: useToken('colors', 'white'), borderRadius: useToken('radii', 'md'), color: useToken('colors', 'black'), minHeight: useToken('space', 12), transition: 'all 0.2s', borderColor: isError ? invalidBorder : isFocused ? focusBorder : useToken('gray.100'), boxShadow: isError ? `0 0 0 1px ${invalidBorder}` : isFocused ? `0 0 0 1px ${focusBorder}` : undefined, '&:hover': { borderColor: isFocused ? focusBorder : borderHover }, '&:hover > div > span': { backgroundColor: borderHover }, '&:focus': { borderColor: isError ? invalidBorder : focusBorder }, '&.invalid': { borderColor: invalidBorder, boxShadow: `0 0 0 1px ${invalidBorder}` }, }; return mergeWith({}, base, styles); }, [colorMode, isError], ); }; export const useMenuStyle = ( props: RSStyleCallbackProps, ): RSStyleFunction<'menu', Opt, IsMulti> => { const { colorMode } = props; const { isOpen } = useSelectContext(); const styles = { backgroundColor: useToken('white'), zIndex: 1500 }; return useCallback(base => mergeWith({}, base, styles), [colorMode, isOpen]); }; export const useMenuListStyle = ( props: RSStyleCallbackProps, ): RSStyleFunction<'menuList', Opt, IsMulti> => { const { colorMode } = props; const { isOpen } = useSelectContext(); const scrollbarTrack = useToken('colors', 'blackAlpha.50'); const scrollbarThumb = useToken('colors', 'blackAlpha.300'); const scrollbarThumbHover = useToken('colors', 'blackAlpha.400'); const styles = { borderRadius: useToken('radii', 'md'), backgroundColor: useToken('colors', 'white'), '&::-webkit-scrollbar': { width: '5px' }, '&::-webkit-scrollbar-track': { backgroundColor: scrollbarTrack }, '&::-webkit-scrollbar-thumb': { backgroundColor: scrollbarThumb }, '&::-webkit-scrollbar-thumb:hover': { backgroundColor: scrollbarThumbHover }, '-ms-overflow-style': { display: 'none' }, }; return useCallback(base => mergeWith({}, base, styles), [colorMode, isOpen]); }; export const useOptionStyle = ( props: RSStyleCallbackProps, ): RSStyleFunction<'option', Opt, IsMulti> => { const { colorMode } = props; const { isOpen } = useSelectContext(); const fontSize = useToken('fontSizes', 'lg'); const disabled = useToken('colors', 'whiteAlpha.400'); const active = useToken('colors', 'brand.600'); const focused = useToken('colors', 'brand.500'); const selected = useToken('colors', 'brand.600'); const color = useToken('colors', 'white'); return useCallback( (base, state) => { const { isFocused, isSelected, isDisabled } = state; let backgroundColor = 'transparent'; switch (true) { case isDisabled: backgroundColor = disabled; break; case isSelected: backgroundColor = selected; break; case isFocused: backgroundColor = focused; break; } const styles = { color: backgroundColor === 'transparent' ? 'currentColor' : color, '&:active': { backgroundColor: active, color: color }, '&:focus': { backgroundColor: active, color: color }, backgroundColor, fontSize, }; return mergeWith({}, base, styles); }, [isOpen, colorMode], ); }; export const useIndicatorSeparatorStyle = ( props: RSStyleCallbackProps, ): RSStyleFunction<'indicatorSeparator', Opt, IsMulti> => { const { colorMode } = props; const styles = { backgroundColor: useToken('colors', 'gray.200') }; return useCallback(base => mergeWith({}, base, styles), [colorMode]); }; export const usePlaceholderStyle = ( props: RSStyleCallbackProps, ): RSStyleFunction<'placeholder', Opt, IsMulti> => { const { colorMode } = props; const styles = { color: useToken('colors', 'gray.600'), fontSize: useToken('fontSizes', 'lg') } return useCallback(base => mergeWith({}, base, styles), [colorMode]); }; export const useSingleValueStyle = ( props: RSStyleCallbackProps, ): RSStyleFunction<'singleValue', Opt, IsMulti> => { const { colorMode } = props; const color = useToken('colors', 'black'); const styles = { color, fontSize: useToken('fontSizes', 'lg') }; return useCallback(base => mergeWith({}, base, styles), [color, colorMode]); }; export const useMultiValueStyle = ( props: RSStyleCallbackProps, ): RSStyleFunction<'multiValue', Opt, IsMulti> => { const { colorMode } = props; const backgroundColor = useToken('colors', 'brand.500'); const styles = { backgroundColor: backgroundColor, color: useToken('colors', 'white'), borderRadius: useToken('radii', 'md') }; return useCallback(base => mergeWith({}, base, styles), [backgroundColor, colorMode]); }; export const useMultiValueLabelStyle = ( props: RSStyleCallbackProps, ): RSStyleFunction<'multiValueLabel', Opt, IsMulti> => { const { colorMode } = props; const styles = { color: useToken('colors', 'white') }; return useCallback(base => mergeWith({}, base, styles), [colorMode]); }; export const useMultiValueRemoveStyle = ( props: RSStyleCallbackProps, ): RSStyleFunction<'multiValueRemove', Opt, IsMulti> => { const { colorMode } = props; const color = useToken('colors', 'white'); const styles = { color: color, '&:hover': { backgroundColor: 'transparent', color, opacity: 0.8 }, }; return useCallback(base => mergeWith({}, base, styles), [colorMode]); }; export const useRSTheme = (): RSThemeFunction => { const borderRadius = useToken('radii', 'md') as unknown as number; return useCallback((t: ReactSelect.Theme): ReactSelect.Theme => ({ ...t, borderRadius }), []); }; export const useMenuPortal = (): RSStyleFunction< 'menuPortal', Opt, IsMulti > => { const isMobile = useMobile(); const styles = { zIndex: 1500, }; return useCallback(base => mergeWith({}, base, styles), [isMobile]); };