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

159 lines
3.9 KiB
TypeScript
Raw Normal View History

import { ClickAwayListener, MenuItem, Paper, Popper } from "@material-ui/core";
2020-02-07 16:12:01 +00:00
import { fade } from "@material-ui/core/styles/colorManipulator";
import { FormChange } from "@saleor/hooks/useForm";
import ArrowDropdown from "@saleor/icons/ArrowDropdown";
Use MacawUI (#1229) * Replace withStyleswith useStyles (#1100) * Replace withStyleswith useStyles * Update messages * Use rem as a spacing unit (#1101) * Use rems as spacing units * Fix visual bugs * Update stories * Use macaw-ui as theme provider (#1108) * Use macaw ui as a theme provider * Add react-dom to aliases * Fix jest module resolution * Update useTheme hook usage * Fix test wrapper * Use macaw from git repo * Fix CI * Update stories * Fix aliasing * Extract savebar to macaw ui (#1146) * wip * Use savebar from macaw * Use confirm button from macaw * Improve file structure * Use sidebar context from macaw * Update macaw * Update macaw version * Remove savebar from storybook * Update stories * Use alerts and notifications from macaw (#1166) * Use alerts from macaw * Add notifications from macaw * Update stories * Pin macaw version * Encapsulate limit reached in one component * Remove unused imports * Use backlinks from macaw (#1183) * Use backlink from macaw * Update macaw version * Use macaw sidebar (#1148) * Use sidebar from macaw * Use shipped logo * Use lowercase * Update stories * Use user chip from macaw (#1191) * Use user chip from macaw * Use dedicated components for menu items * Simplify code * Bump version and fix types (#1210) * Rename onBack to onClick * Rename UserChip to UserChipMenu * Rename IMenuItem to SidebarMenuItem * Update macaw version * Fix tables after changes in macaw (#1220) * Update macaw version * Update changelog * Update stories * Fix after rebase * Update to macaw 0.2.0 * Lint files * Update macaw to 0.2.2
2021-07-21 08:59:52 +00:00
import { makeStyles } from "@saleor/macaw-ui";
2020-02-07 16:12:01 +00:00
import classNames from "classnames";
import { codes } from "keycode";
import React from "react";
2020-02-07 16:12:01 +00:00
import Link from "../Link";
import { SingleAutocompleteChoiceType } from "../SingleAutocompleteSelectField";
2020-02-07 16:12:01 +00:00
const useStyles = makeStyles(
theme => ({
arrow: {
position: "relative",
top: 6,
transition: theme.transitions.duration.short + "ms"
},
highlighted: {
background: theme.palette.background.default
},
menuItem: {
"&:not(:last-of-type)": {
marginBottom: theme.spacing()
}
},
paper: {
padding: theme.spacing()
},
popper: {
boxShadow: `0px 5px 10px 0 ${fade(theme.palette.common.black, 0.05)}`,
marginTop: theme.spacing(1),
zIndex: 2
},
root: {
"&:focus": {
textDecoration: "underline"
},
outline: 0,
position: "relative"
},
rotate: {
transform: "rotate(180deg)"
}
}),
{
name: "LinkChoice"
}
);
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
}) => {
const classes = useStyles({});
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
}
});
};
const handleKeyPress = (event: React.KeyboardEvent<HTMLSpanElement>) => {
switch (event.keyCode) {
case codes.down:
setHighlightedIndex(
highlightedIndex => (highlightedIndex + 1) % choices.length
);
break;
case codes.up:
setHighlightedIndex(highlightedIndex =>
highlightedIndex === 0
? choices.length - 1
: (highlightedIndex - 1) % choices.length
);
break;
case codes.enter:
if (open) {
handleChange(choices[highlightedIndex].value);
} else {
setOpen(true);
}
break;
}
};
return (
<span
className={classNames(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={classNames(classes.arrow, {
[classes.rotate]: open
})}
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={classNames(classes.menuItem, {
[classes.highlighted]: highlightedIndex === choiceIndex
})}
selected={choice.value === value}
key={choice.value}
onClick={() => handleChange(choice.value)}
data-test="select-option"
2020-02-07 16:12:01 +00:00
>
{choice.label}
</MenuItem>
))}
</Paper>
</ClickAwayListener>
</Popper>
</span>
);
};
LinkChoice.displayName = "LinkChoice";
export default LinkChoice;