import CircularProgress from "@material-ui/core/CircularProgress"; import IconButton from "@material-ui/core/IconButton"; import MenuItem from "@material-ui/core/MenuItem"; import Paper from "@material-ui/core/Paper"; import { createStyles, Theme, withStyles, WithStyles } from "@material-ui/core/styles"; import TextField from "@material-ui/core/TextField"; import Typography from "@material-ui/core/Typography"; import CloseIcon from "@material-ui/icons/Close"; import Downshift, { ControllerStateAndHelpers } from "downshift"; import React from "react"; import { FormattedMessage } from "react-intl"; import { compareTwoStrings } from "string-similarity"; import { fade } from "@material-ui/core/styles/colorManipulator"; import Checkbox from "@saleor/components/Checkbox"; import Debounce, { DebounceProps } from "@saleor/components/Debounce"; import ArrowDropdownIcon from "@saleor/icons/ArrowDropdown"; import Hr from "../Hr"; export interface MultiAutocompleteChoiceType { label: string; value: string; } const styles = (theme: Theme) => createStyles({ checkbox: { height: 24, width: 20 }, chip: { width: "100%" }, chipClose: { height: 32, padding: 0, width: 32 }, chipContainer: { display: "flex", flexDirection: "column", marginTop: theme.spacing.unit }, chipInner: { "& svg": { color: theme.palette.primary.contrastText }, alignItems: "center", background: fade(theme.palette.primary.main, 0.6), borderRadius: 24, color: theme.palette.primary.contrastText, display: "flex", justifyContent: "space-between", margin: `${theme.spacing.unit}px 0`, paddingLeft: theme.spacing.unit * 2, paddingRight: theme.spacing.unit }, chipLabel: { color: theme.palette.primary.contrastText }, container: { flexGrow: 1, position: "relative" }, hr: { margin: `${theme.spacing.unit}px 0` }, menuItem: { display: "grid", gridColumnGap: theme.spacing.unit + "px", gridTemplateColumns: "20px 1fr", height: "auto", whiteSpace: "normal" }, menuItemLabel: { overflowWrap: "break-word" }, paper: { left: 0, marginTop: theme.spacing.unit, padding: theme.spacing.unit, position: "absolute", right: 0, zIndex: 2 } }); export interface MultiAutocompleteSelectFieldProps { allowCustomValues?: boolean; displayValues: MultiAutocompleteChoiceType[]; name: string; choices: MultiAutocompleteChoiceType[]; value: string[]; loading?: boolean; placeholder?: string; helperText?: string; label?: string; fetchChoices?: (value: string) => void; onChange: (event: React.ChangeEvent) => void; } const DebounceAutocomplete: React.ComponentType< DebounceProps > = Debounce; export const MultiAutocompleteSelectFieldComponent = withStyles(styles, { name: "MultiAutocompleteSelectField" })( ({ allowCustomValues, choices, classes, displayValues, helperText, label, loading, name, placeholder, value, fetchChoices, onChange, ...props }: MultiAutocompleteSelectFieldProps & WithStyles) => { const handleSelect = ( item: string, downshiftOpts?: ControllerStateAndHelpers ) => { if (downshiftOpts) { downshiftOpts.reset({ inputValue: "" }); } onChange({ target: { name, value: item } } as any); }; const suggestions = choices.filter(choice => !value.includes(choice.value)); return ( <> ""} > {({ getInputProps, getItemProps, isOpen, toggleMenu, highlightedIndex, inputValue }) => (
{loading ? ( ) : ( )}
), id: undefined, onClick: toggleMenu }} helperText={helperText} label={label} fullWidth={true} /> {isOpen && (!!inputValue || !!choices.length) && ( {choices.length > 0 || displayValues.length > 0 || allowCustomValues ? ( <> {displayValues.map(value => ( {value.label} ))} {displayValues.length > 0 && suggestions.length > 0 && (
)} {suggestions.map((suggestion, index) => ( {suggestion.label} ))} {allowCustomValues && inputValue && !choices.find( choice => choice.label.toLowerCase() === inputValue.toLowerCase() ) && ( )} ) : ( !loading && ( ) )}
)} )}
{displayValues.map(value => (
{value.label} handleSelect(value.value)} >
))}
); } ); const MultiAutocompleteSelectField: React.FC< MultiAutocompleteSelectFieldProps > = ({ choices, fetchChoices, ...props }) => { const [query, setQuery] = React.useState(""); if (fetchChoices) { return ( {debounceFn => ( )} ); } const sortedChoices = choices.sort((a, b) => { const ratingA = compareTwoStrings(query, a.label); const ratingB = compareTwoStrings(query, b.label); if (ratingA > ratingB) { return -1; } if (ratingA < ratingB) { return 1; } return 0; }); return ( setQuery(q || "")} choices={sortedChoices} {...props} /> ); }; MultiAutocompleteSelectField.displayName = "MultiAutocompleteSelectField"; export default MultiAutocompleteSelectField;