import chevronDown from "@assets/images/ChevronDown.svg"; import { CircularProgress, MenuItem, Paper, Typography } from "@material-ui/core"; import AddIcon from "@material-ui/icons/Add"; import Checkbox from "@saleor/components/Checkbox"; import useElementScroll, { isScrolledToBottom } from "@saleor/hooks/useElementScroll"; import { makeStyles } from "@saleor/macaw-ui"; import { FetchMoreProps } from "@saleor/types"; import classNames from "classnames"; import { GetItemPropsOptions } from "downshift"; import React from "react"; import SVG from "react-inlinesvg"; import { FormattedMessage } from "react-intl"; import Hr from "../Hr"; const menuItemHeight = 46; const maxMenuItems = 5; const offset = 24; export interface MultiAutocompleteActionType { label: string; onClick: () => void; } export interface MultiAutocompleteChoiceType { label: string; value: any; disabled?: boolean; } export interface MultiAutocompleteSelectFieldContentProps extends Partial { add?: MultiAutocompleteActionType; choices: MultiAutocompleteChoiceType[]; displayCustomValue: boolean; displayValues: MultiAutocompleteChoiceType[]; getItemProps: (options: GetItemPropsOptions) => void; highlightedIndex: number; inputValue: string; } const useStyles = makeStyles( theme => ({ add: { background: theme.palette.background.default, border: `1px solid ${theme.palette.divider}`, borderRadius: "100%", height: 24, margin: theme.spacing(), width: 24 }, addIcon: { height: 24, margin: 9, width: 20 }, arrowContainer: { position: "relative" }, arrowInnerContainer: { alignItems: "center", background: theme.palette.type === "light" ? theme.palette.grey[50] : theme.palette.grey[900], bottom: 0, display: "flex", height: 30, justifyContent: "center", opacity: 1, position: "absolute", transition: theme.transitions.duration.short + "ms", width: "100%" }, checkbox: { height: 24, width: 20 }, content: { maxHeight: `calc(${menuItemHeight * maxMenuItems}px + ${theme.spacing( 2 )})`, overflowY: "scroll", padding: 8 }, hide: { opacity: 0, zIndex: -1 }, hr: { margin: theme.spacing(1, 0) }, menuItem: { "&:focus": { backgroundColor: [ theme.palette.background.default, "!important" ] as any, color: theme.palette.primary.main, fontWeight: 400 }, "&:hover": { backgroundColor: [ theme.palette.background.default, "!important" ] as any, color: theme.palette.primary.main, fontWeight: 700 }, paddingLeft: theme.spacing(1.5), borderRadius: 4, display: "grid", gridColumnGap: theme.spacing(1), gridTemplateColumns: "30px 1fr", height: "auto", marginBottom: theme.spacing(0.5), padding: 0, whiteSpace: "normal" }, menuItemLabel: { overflowWrap: "break-word" }, progress: {}, progressContainer: { display: "flex", justifyContent: "center", padding: theme.spacing(1, 0) }, root: { borderBottomLeftRadius: 8, borderBottomRightRadius: 8, margin: theme.spacing(1, 0), overflow: "hidden", zIndex: 22 } }), { name: "MultiAutocompleteSelectFieldContent" } ); function getChoiceIndex( index: number, displayValues: MultiAutocompleteChoiceType[], displayCustomValue: boolean, add: boolean ) { let choiceIndex = index; if (add || displayCustomValue) { choiceIndex += 2; } if (displayValues.length > 0) { choiceIndex += 1 + displayValues.length; } return choiceIndex; } const MultiAutocompleteSelectFieldContent: React.FC = props => { const { add, choices, displayCustomValue, displayValues, getItemProps, hasMore, highlightedIndex, loading, inputValue, onFetchMore } = props; if (!!add && !!displayCustomValue) { throw new Error("Add and custom value cannot be displayed simultaneously"); } const classes = useStyles(props); const anchor = React.useRef(); const scrollPosition = useElementScroll(anchor); const [calledForMore, setCalledForMore] = React.useState(false); const scrolledToBottom = isScrolledToBottom(anchor, scrollPosition, offset); React.useEffect(() => { if (!calledForMore && onFetchMore && scrolledToBottom) { onFetchMore(); setCalledForMore(true); } }, [scrolledToBottom]); React.useEffect(() => { if (calledForMore && !loading) { setCalledForMore(false); } }, [loading]); const hasValuesToDisplay = displayValues.length > 0 || displayCustomValue || choices.length > 0; return ( {hasValuesToDisplay && (
<> {add && ( {add.label} )} {displayCustomValue && ( )} {(choices.length > 0 || displayValues.length > 0) && displayCustomValue &&
} {displayValues.map(value => ( {value.label} ))} {displayValues.length > 0 && choices.length > 0 && (
)} {choices.map((suggestion, index) => { const choiceIndex = getChoiceIndex( index, displayValues, displayCustomValue, !!add ); return ( {suggestion.label} ); })}
)} {!loading && !hasValuesToDisplay && ( )} {(hasMore || loading) && ( <> {hasMore &&
}
)} {choices.length > maxMenuItems && (
)}
); }; MultiAutocompleteSelectFieldContent.displayName = "MultiAutocompleteSelectFieldContent"; export default MultiAutocompleteSelectFieldContent;