@parkassist/pa-ui-library
Version:
INX Platform elements
233 lines • 6.39 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import React, { useState } from "react";
import { Column, Row } from "../Layout/Flex";
import styled from "@emotion/styled";
import Palette from "../../constants/Palette";
import { Measures } from "../../index";
import Autocomplete from "react-autocomplete";
import { FormLabel } from "../Input";
import FadeIn from "react-fade-in";
import * as Icons from "../Icons";
const Wrapper = styled(Column)(({
height,
width
}) => ({
backgroundColor: Palette.WHITE,
fontSize: 12,
height,
borderRadius: 3,
minWidth: "fit-content",
overflow: "hidden",
border: `1px solid ${Palette.DIM_GREY}`,
justifyContent: "space-between",
width
}));
const OptionWrapper = styled(Row)(({
width
}) => ({
boxSizing: "border-box",
justifyContent: "space-between",
alignItems: "center",
height: `calc(${Measures.unit} * 2)`,
minHeight: `calc(${Measures.unit} * 2)`,
borderBottom: `1px solid ${Palette.VERY_LIGHT_GREY_NEW}`,
padding: Measures.minMargin,
width: width ? width : "100%",
color: Palette.BLACK,
transition: "all 0.2s",
"&:hover": {
backgroundColor: Palette.WARNING_YELLOW
}
}));
const Item = styled.div(({
isHighlighted
}) => ({
height: `calc(${Measures.unit} * 2)`,
display: "flex",
padding: 4,
alignItems: "center",
background: isHighlighted ? Palette.WARNING_YELLOW : Palette.WHITE
}));
const Input = styled.input(({
width
}) => ({
outline: "none",
border: "none",
marginTop: -4,
marginLeft: 4,
zIndex: 1,
borderRight: `1px solid ${Palette.DIM_GREY}`,
width
}));
const NoOptionsWrapper = styled.div`
height: 100%;
display: flex;
justify-content: center;
align-items: center;
text-transform: uppercase;
font-size: 11px;
color: ${Palette.DIM_GREY};
`;
export const ControlWrapper = styled.div(() => ({
fontSize: 12,
color: Palette.DIM_GREY
}));
export const Control = styled.span(() => ({
cursor: "pointer",
color: "grey",
margin: 2,
"&:hover": {
color: Palette.BLACK
}
}));
const DownArrowWrapper = styled.span(({
visible
}) => ({
display: "flex",
transition: "all 0.2s",
transformOrigin: "center",
width: 18,
height: 18,
transform: `rotate(${visible ? "180deg" : 0})`,
zIndex: 0,
cursor: "pointer"
}));
const menuStyles = (width, maxHeight) => ({
boxShadow: `0 2px 12px ${Palette.VERY_LIGHT_GREY_NEW}`,
background: Palette.WHITE,
fontSize: "90%",
position: "fixed",
zIndex: 99,
marginLeft: -34,
marginTop: 8,
width,
overflow: "auto",
borderRadius: 3,
transition: "all 0.2s",
maxHeight
});
const Option = ({
text,
onRemove,
width
}) => _jsxs(OptionWrapper, {
width: width,
children: [_jsx(Column, {
children: text
}), _jsx(Column, {
style: {
cursor: "pointer"
},
onClick: onRemove,
children: _jsx(Icons.CloseIcon, {})
})]
});
const SearchableSelector = ({
options,
selection = [],
onChange,
width,
height,
title,
optionsMaxHeight = 100,
propertyToShow = "label",
placeholder = "",
allText = "All",
clearText = "Clear",
noSelectionText = "No selection"
}) => {
const [value, setValue] = useState("");
const [visible, setVisible] = useState(false);
const optionsToShow = options.filter(o => {
return o[propertyToShow].toLowerCase().includes(value.toLowerCase()) && !selection.some(s => s[propertyToShow].toLowerCase() === o[propertyToShow].toLowerCase());
});
const handleSelection = text => {
const optionToAdd = options.find(o => o[propertyToShow] === text);
onChange(selection.concat(optionToAdd));
setValue("");
setVisible(false);
};
return _jsxs(Column, {
children: [_jsxs(Row, {
style: {
justifyContent: "space-between"
},
children: [_jsxs(FormLabel, {
children: [title, " (", selection.length, ")"]
}), _jsxs(ControlWrapper, {
children: [_jsx(Control, {
"data-testid": "all",
onClick: () => {
onChange(options);
},
children: allText
}), "|", _jsx(Control, {
"data-testid": "clear",
onClick: () => {
onChange([]);
},
children: clearText
})]
})]
}), _jsx(Row, {
children: _jsxs(Wrapper, {
height: height,
width: width,
children: [_jsx(Row, {
children: _jsxs(Column, {
style: {
height: height - 32,
width: "100%",
overflowY: "auto"
},
children: [selection.length === 0 && _jsx(NoOptionsWrapper, {
children: noSelectionText
}), selection.map((s, i) => _jsx(FadeIn, {
children: _jsx(Option, {
text: s[propertyToShow],
onRemove: () => {
onChange(selection.filter(o => o[propertyToShow] !== s[propertyToShow]));
}
})
}))]
})
}), _jsxs(Row, {
style: {
height: 32,
justifyContent: "space-between",
borderTop: `1px solid ${Palette.DIM_GREY}`,
padding: Measures.minMargin
},
children: [_jsx(Icons.SearchIcon, {}), _jsx(Autocomplete, {
getItemValue: item => item[propertyToShow],
menuStyle: menuStyles(width, optionsMaxHeight),
items: optionsToShow,
renderItem: (item, isHighlighted) => _jsx(Item, {
"data-testid": title.toLowerCase() + "-option",
isHighlighted: isHighlighted,
children: item[propertyToShow]
}, item[propertyToShow]),
value: value,
onChange: e => setValue(e.target.value),
onSelect: handleSelection,
open: visible,
onMenuVisibilityChange: newState => setVisible(newState),
renderInput: props => _jsx(Input, Object.assign({
id: "search" + title,
placeholder: placeholder,
width: width - 64
}, props))
}), _jsx(DownArrowWrapper, {
"data-testid": "open-list",
visible: visible,
onClick: () => {
setVisible(!visible);
},
children: _jsx(Icons.OpenArrowIcon, {})
})]
})]
})
})]
});
};
export default SearchableSelector;