import React, { ReactElement, ReactNode, useRef } from 'react' import { ControllerStateAndHelpers } from 'downshift' import * as O from 'fp-ts/lib/Option' import { pipe } from 'fp-ts/lib/pipeable' import { Colors, getColor } from '@monorail/helpers/color' import { ellipsis, visible } from '@monorail/helpers/exports' import { flexFlow } from '@monorail/helpers/flex' import styled, { css } from '@monorail/helpers/styled-components' import { isEmptyString, isNotNil } from '@monorail/sharedHelpers/typeGuards' import { DisplayType } from '@monorail/visualComponents/inputs/inputTypes' import { IconsAndInputContainer, TextField, } from '@monorail/visualComponents/inputs/TextField' import { Text } from '@monorail/visualComponents/typography/Text' import { ButtonDisplay, ButtonSize } from '../buttons/buttonTypes' import { IconButton } from '../buttons/IconButton' import { DropdownItem } from './DropdownItem' import { DownshiftGetInputProps, DropdownType } from './helpers' import { DropdownParser } from './parsers' export declare interface RenderItemProps { children?: ReactNode disabled?: boolean highlighted: boolean item: T selected: boolean } export type CustomRenderHandlerHook = ( props: RenderHandlerProps, ) => ReactElement export declare interface RenderHandlerProps { customRender?: CustomRenderHandlerHook downshiftProps: ControllerStateAndHelpers handlerProps: DownshiftGetInputProps display?: DisplayType clearable?: boolean } export declare interface RenderListProps { children: ReactNode downshiftProps: ControllerStateAndHelpers items: Array parser: DropdownParser } export declare interface DropdownRender { handler: (props: RenderHandlerProps) => ReactElement item: (props: RenderItemProps) => ReactElement list?: (props: RenderListProps) => ReactElement } export const DropdownPlaceholder = styled.span` ${ellipsis}; color: ${getColor(Colors.Black54a)}; font-style: italic; ` const HandlerWrapper = styled.div` ${flexFlow('row')} border-radius: inherit; flex: 1; min-height: 1rem; overflow: hidden; padding: 6px 30px 6px 8px; position: relative; ` const StyledHandler = styled.div<{ searching: boolean }>( ({ searching = false }) => css` ${visible(!searching)} ${flexFlow('row')} ${ellipsis}; align-items: center; flex: 1; pointer-events: none; `, ) const TextFieldStyles = (searching: boolean = false) => css` border-radius: inherit; bottom: 0; left: 0; position: absolute; right: 0; top: 0; width: auto; ${IconsAndInputContainer} { border-radius: inherit; } input { ${!searching && 'text-indent: -100vw;'}; padding-top: 3px; /* Fix dropdown bottom border being hidden. Padding comes from StyledInput in TextField */ border-radius: inherit; cursor: pointer; } ` const List = ({ children, }: RenderListProps): ReactElement => { return <>{children} } const Item = ({ children, disabled = false, highlighted = false, selected = false, }: RenderItemProps): ReactElement => { return ( {children} ) } const renderHandlerLabelDefault = ({ downshiftProps, handlerProps, }: RenderHandlerProps): ReactElement => pipe( O.fromNullable(downshiftProps.selectedItem), O.fold( () => ( {handlerProps.placeholder} ), item => ( {downshiftProps.itemToString(item)} ), ), ) const Handler = ({ customRender = renderHandlerLabelDefault, downshiftProps, handlerProps, clearable = true, }: RenderHandlerProps): ReactElement => { const inputRef = useRef(null) const { display = DisplayType.Edit, ...textFieldProps } = handlerProps const { isOpen, inputValue } = downshiftProps const searching = isOpen && !isEmptyString(inputValue) return display === DisplayType.Edit ? ( {customRender({ handlerProps, downshiftProps })} {isNotNil(downshiftProps.selectedItem) && clearable && ( downshiftProps.clearSelection()} css={css` margin: auto 0; `} > )} ) : ( customRender({ handlerProps, downshiftProps }) ) } export const createCustomHandler = ( customRender: CustomRenderHandlerHook = renderHandlerLabelDefault, ) => (props: RenderHandlerProps): ReactElement => ( ) export const createDefaultDropdownRender = < T extends DropdownType >(): DropdownRender => ({ handler: Handler, item: Item, list: List, })