Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //@ts-check
- import React from 'react';
- import jss from 'react-jss';
- import Typography from 'application/Modules/Common/Components/Typography';
- import Downshift from 'downshift';
- import { AutoSizer, List } from 'react-virtualized';
- import cx from 'classnames';
- import themeType, { cpg } from 'application/Utils/theme';
- //@ts-ignore
- import ArrowDown from './arrow-down.svg';
- //@ts-ignore
- import Search from './search.svg';
- import RadioListElement from '../RadioListElement';
- /**
- * @param {typeof themeType & typeof cpg} theme
- */
- const styles = theme => ({
- label: {
- marginLeft: 8,
- marginBottom: 2,
- },
- content: {
- borderRadius: 3,
- backgroundColor: '#F2F4F7',
- padding: 8,
- cursor: 'pointer',
- position: 'relative',
- '&:focus': {
- outline: '1px dotted #106BFE',
- },
- },
- contentArrow: {
- position: 'absolute',
- top: '50%',
- right: 13,
- transform: 'translateY(-50%)',
- width: 8,
- height: 5,
- },
- wrapper: {
- position: 'relative',
- backgroundColor: '#ffffff',
- },
- wrapperOpen: {
- borderRadius: 2,
- boxShadow:
- '0 4px 8px 0 rgba(76,85,104,0.16), 0 1px 2px 0 rgba(76,85,104,0.24)',
- },
- inputWrapper: {
- position: 'relative',
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'flex-start',
- padding: '7px 5px 7px 36px',
- backgroundImage: `url(${Search})`,
- backgroundRepeat: 'no-repeat',
- backgroundPosition: '8px center',
- borderBottom: '1px solid #E8EBF4',
- },
- input: {
- display: 'block',
- flex: '1 1 100%',
- height: 24,
- border: 'none',
- color: '#818BA3',
- fontFamily: 'inherit',
- fontSize: 14,
- lineHeight: '24px',
- },
- list: {
- position: 'absolute',
- top: '100%',
- width: '100%',
- zIndex: theme.zIndex.modal + 10,
- padding: '18px 11px',
- backgroundColor: '#ffffff',
- boxShadow:
- '0 4px 8px 0 rgba(76,85,104,0.16), 0 1px 2px 0 rgba(76,85,104,0.24)',
- overflowX: 'auto',
- '& > div': {
- height: 360,
- },
- },
- closeMenu: {
- width: 24,
- height: 24,
- flex: '0 0 24px',
- backgroundImage: `url(${ArrowDown})`,
- backgroundRepeat: 'no-repeat',
- backgroundPosition: 'center',
- transform: 'rotate(180deg)',
- cursor: 'pointer',
- },
- listItem: {
- marginBottom: 18,
- '& > div': {
- padding: 2,
- },
- '&:last-child': {
- marginBottom: 0,
- },
- },
- highlighted: {
- '& > div': {
- outline: '1px dotted #106BFE',
- outlineOffset: -1,
- },
- },
- });
- const Closed = ({ openMenu, classes, additionalActionOnOpen, children }) => {
- const action = e => {
- if (typeof additionalActionOnOpen === 'function') additionalActionOnOpen();
- openMenu(e);
- };
- return (
- <div
- className={classes.content}
- onClick={action}
- role='button'
- tabIndex={0}
- onKeyPress={e => {
- if (e.key === 'Enter') {
- action(e);
- }
- }}
- >
- <Typography>{children}</Typography>
- <img
- className={classes.contentArrow}
- src={ArrowDown}
- role='presentational'
- />
- </div>
- );
- };
- /**
- * @type React.FC<{
- * label?: string
- * classes: { [K in keyof ReturnType<typeof styles>]: string }
- * items: Array<unknown>
- * value: unknown
- * onChange: (selectedItem: any) => void
- * itemToString: (item: unknown) => string
- * unique: string
- * }>
- */
- const Dropdown = ({
- label,
- classes,
- items,
- onChange,
- itemToString,
- unique,
- value,
- }) => {
- const [inputValue, setInputValue] = React.useState('');
- return (
- <Downshift
- inputValue={inputValue}
- onInputValueChange={s => setInputValue(s)}
- onChange={onChange}
- selectedItem={value}
- itemToString={itemToString}
- >
- {({
- getInputProps,
- getItemProps,
- getLabelProps,
- getMenuProps,
- getToggleButtonProps,
- isOpen,
- openMenu,
- closeMenu,
- inputValue,
- highlightedIndex,
- selectedItem,
- }) => {
- const newItems = items.filter(
- item =>
- !inputValue ||
- String(itemToString(item))
- .toLowerCase()
- .includes(inputValue.toLowerCase()),
- );
- const rowRenderer = ({ index, key, style }) => {
- const item = newItems[index];
- if (item) {
- return (
- <li
- {...getItemProps({
- key: key,
- index,
- style,
- item,
- className: cx(
- classes.listItem,
- highlightedIndex === index && classes.highlighted,
- ),
- })}
- >
- <RadioListElement
- value={null}
- onSelect={() => {}}
- selected={selectedItem[unique] === item[unique]}
- label={itemToString(item)}
- />
- </li>
- );
- }
- return null;
- };
- return (
- <div>
- {label && (
- <Typography
- className={classes.label}
- contrast='semiContrast'
- variant='label'
- {...getLabelProps()}
- >
- {label}
- </Typography>
- )}
- <div className={cx(classes.wrapper, isOpen && classes.wrapperOpen)}>
- {isOpen ? (
- <div className={classes.inputWrapper}>
- <input
- {...getInputProps({})}
- autoFocus
- className={classes.input}
- placeholder='Search'
- />
- <div
- {...getToggleButtonProps({
- disabled: !isOpen,
- })}
- className={classes.closeMenu}
- />
- </div>
- ) : (
- <Closed
- openMenu={openMenu}
- additionalActionOnOpen={() => setInputValue('')}
- classes={classes}
- >
- {itemToString(selectedItem) || 'Select'}
- </Closed>
- )}
- {isOpen && (
- <ul {...getMenuProps()} className={classes.list}>
- <div>
- <AutoSizer disableHeight>
- {({ width }) => (
- <List
- width={width}
- height={360}
- rowCount={items.length}
- rowHeight={42}
- rowRenderer={rowRenderer}
- />
- )}
- </AutoSizer>
- </div>
- </ul>
- )}
- </div>
- </div>
- );
- }}
- </Downshift>
- );
- };
- export default jss(styles)(Dropdown);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement