saleor-dashboard/src/components/LinkChoice/LinkChoice.tsx

120 lines
3.1 KiB
TypeScript
Raw Normal View History

// @ts-strict-ignore
import { FormChange } from "@dashboard/hooks/useForm";
import ArrowDropdown from "@dashboard/icons/ArrowDropdown";
import { ClickAwayListener, MenuItem, Paper, Popper } from "@material-ui/core";
import clsx from "clsx";
2020-02-07 16:12:01 +00:00
import { codes } from "keycode";
import React from "react";
2020-02-07 16:12:01 +00:00
import Link from "../Link";
import { SingleAutocompleteChoiceType } from "../SingleAutocompleteSelectField";
import { useStyles } from "./styles";
2020-02-07 16:12:01 +00:00
export interface LinkChoiceProps {
className?: string;
2020-02-07 16:12:01 +00:00
choices: SingleAutocompleteChoiceType[];
name?: string;
2020-02-07 16:12:01 +00:00
value: string;
onChange: FormChange;
}
const LinkChoice: React.FC<LinkChoiceProps> = ({
className,
2020-02-07 16:12:01 +00:00
choices,
name,
value,
onChange,
2020-02-07 16:12:01 +00:00
}) => {
const classes = useStyles();
2020-02-07 16:12:01 +00:00
const [open, setOpen] = React.useState(false);
const anchor = React.useRef<HTMLInputElement>(null);
const current = choices.find(c => c.value === value);
const [highlightedIndex, setHighlightedIndex] = React.useState(0);
const handleChange = (value: string) => {
setOpen(false);
onChange({
target: {
name,
value,
},
2020-02-07 16:12:01 +00:00
});
};
const handleKeyPress = (event: React.KeyboardEvent<HTMLSpanElement>) => {
switch (event.keyCode) {
case codes.down:
setHighlightedIndex(
highlightedIndex => (highlightedIndex + 1) % choices.length,
2020-02-07 16:12:01 +00:00
);
break;
case codes.up:
setHighlightedIndex(highlightedIndex =>
highlightedIndex === 0
? choices.length - 1
: (highlightedIndex - 1) % choices.length,
2020-02-07 16:12:01 +00:00
);
break;
case codes.enter:
if (open) {
handleChange(choices[highlightedIndex].value);
} else {
setOpen(true);
}
break;
}
};
return (
<span
className={clsx(classes.root, className)}
2020-02-07 16:12:01 +00:00
ref={anchor}
onKeyDown={handleKeyPress}
tabIndex={0}
>
2020-04-29 14:14:20 +00:00
<Link onClick={() => setOpen(open => !open)}>
{current.label}
<ArrowDropdown
className={clsx(classes.arrow, {
[classes.rotate]: open,
2020-04-29 14:14:20 +00:00
})}
color="primary"
/>
</Link>
2020-02-07 16:12:01 +00:00
<Popper
className={classes.popper}
open={open}
anchorEl={anchor.current}
transition
disablePortal
placement="bottom-start"
>
<ClickAwayListener
onClickAway={() => setOpen(false)}
mouseEvent="onClick"
>
<Paper className={classes.paper}>
{choices.map((choice, choiceIndex) => (
<MenuItem
className={clsx(classes.menuItem, {
[classes.highlighted]: highlightedIndex === choiceIndex,
2020-02-07 16:12:01 +00:00
})}
selected={choice.value === value}
key={choice.value}
onClick={() => handleChange(choice.value)}
data-test-id="select-option"
2020-02-07 16:12:01 +00:00
>
{choice.label}
</MenuItem>
))}
</Paper>
</ClickAwayListener>
</Popper>
</span>
);
};
LinkChoice.displayName = "LinkChoice";
export default LinkChoice;