import React, { useContext, ReactNode, Ref, CSSProperties } from "react"; import classNames from "classnames"; import ReactSelect, { Props as ReactSelectProps, components as ReactSelectComponents, Styles as ReactSelectStyles, IndicatorProps as ReactSelectIndicatorProps, OptionProps as ReactSelectOptionProps, MultiValueProps as ReactSelectMultiValueProps, } from "react-select"; import { SelectComponents } from "react-select/src/components"; import { MenuListComponentProps } from "react-select/src/components/Menu"; import ReactSelectCreatable, { Props as ReactSelectCreatableProps, } from "react-select/creatable"; import ReactSelectAsync, { Props as ReactSelectAsyncProps, } from "react-select/async"; import { colors, height, zIndex } from "../../tokens"; import { STATUS_VARIANT } from "../../types"; import { bemHOF, toNumber } from "../../utilities"; import { BoxProps, Box } from "../Box"; import { Flex } from "../Flex"; import { FormGroupContext } from "../FormGroup/FormGroupContext"; import { Icon, ICON_TYPE } from "../Icon"; import { CloseButton } from "../CloseButton"; import { Token } from "../Token"; import { adsTheme } from "./theme"; const cn = bemHOF("Select"); const MultiValue = ({ removeProps, selectProps, children, }: ReactSelectMultiValueProps) => { const { onClick: onRemove, ...restRemoveProps } = removeProps; const { isDisabled } = selectProps; return ( {children} ); }; const OptionComponent = ({ children, isFocused = false, ...rest }: { children: ReactNode; isFocused?: boolean; }) => { return ( {children} Or press [Enter] ); }; const adsComponents = { IndicatorSeparator: null, DropdownIndicator: ({ className: iconClassName }: BoxProps) => ( ), ClearIndicator: ({ innerProps }: ReactSelectIndicatorProps) => ( ), MultiValue, Option: (props: ReactSelectOptionProps) => { const { data, innerRef, isFocused, children, innerProps } = props; if (data.__isNew__) { return ( {children} ); } return ; }, }; const getClassNames = ( classNameProp: string | undefined, variant?: STATUS_VARIANT, ) => { return classNames([cn(), cn({ m: variant }), classNameProp]); }; const getMenuListComponent = (menuRef?: Ref) => ({ innerRef, children, ...listRest }: MenuListComponentProps) => ( {children} ); const generateHardcodedProps = ({ controlHeight, menuInPortal, menuRef, components, styles, }: { controlHeight: number; menuInPortal: boolean; menuRef?: Ref; components?: Partial>; styles?: ReactSelectStyles; }) => { const customComponents = menuInPortal ? { ...adsComponents, MenuList: getMenuListComponent(menuRef) } : adsComponents; return { components: { ...customComponents, ...components }, menuPortalTarget: menuInPortal ? document.body : undefined, styles: { ...styles, menuPortal: (base: CSSProperties): CSSProperties => ({ ...base, zIndex: zIndex.max, }), singleValue: (base: CSSProperties, state: any): CSSProperties => { return { ...base, paddingLeft: state.selectProps.isSearchable ? "2px" : "0", color: state.selectProps.menuIsOpen && state.selectProps.isSearchable ? colors.gray["600"] : base.color, }; }, }, classNamePrefix: cn(), theme: { ...adsTheme, spacing: { ...adsTheme.spacing, controlHeight, }, }, }; }; type ArrowSelectProps = { menuInPortal?: boolean; menuRef?: Ref; height?: number; }; export type SelectProps = ReactSelectProps & ArrowSelectProps; export type SelectCreatableProps = ReactSelectCreatableProps & ArrowSelectProps; export type SelectAsyncProps = ReactSelectAsyncProps & ArrowSelectProps; export type SelectBaseProps = | ({ type: "default" } & SelectProps) | ({ type: "creatable" } & SelectCreatableProps) | ({ type: "async" } & SelectAsyncProps); const SelectBase = ({ variant: variantProp = STATUS_VARIANT.DEFAULT, id: idProp, className, height: controlHeight = toNumber(height["10"]), menuInPortal = false, menuRef, components, styles, ...rest }: SelectBaseProps) => { const { variant: variantContext, id: idContext } = useContext( FormGroupContext, ); const id = idContext || idProp; const variant = variantContext || variantProp; const hardcodedProps = generateHardcodedProps({ controlHeight, menuInPortal, menuRef, styles, components, }); if (rest.type === "async") { return ( ); } if (rest.type === "creatable") { return ( ); } return ( ); }; const SelectAsync = (props: SelectAsyncProps) => { return ; }; const SelectCreatable = (props: SelectCreatableProps) => { return ; }; const Select = (props: SelectProps) => { return ; }; Select.Creatable = SelectCreatable; Select.Async = SelectAsync; export { Select };