diff --git a/src/components/LinkChoice/LinkChoice.stories.tsx b/src/components/LinkChoice/LinkChoice.stories.tsx new file mode 100644 index 000000000..0b7f17610 --- /dev/null +++ b/src/components/LinkChoice/LinkChoice.stories.tsx @@ -0,0 +1,26 @@ +import { storiesOf } from "@storybook/react"; +import React from "react"; + +import { countries } from "@saleor/fixtures"; +import CardDecorator from "@saleor/storybook/CardDecorator"; +import Decorator from "@saleor/storybook/Decorator"; +import Form from "../Form"; +import LinkChoice, { LinkChoiceProps } from "./LinkChoice"; + +const suggestions = countries.map(c => ({ label: c.name, value: c.code })); + +const props: Omit = { + choices: suggestions.slice(0, 10), + name: "country" +}; + +storiesOf("Generics / Link with choices", module) + .addDecorator(CardDecorator) + .addDecorator(Decorator) + .add("default", () => ( +
+ {({ change, data }) => ( + + )} + + )); diff --git a/src/components/LinkChoice/LinkChoice.tsx b/src/components/LinkChoice/LinkChoice.tsx new file mode 100644 index 000000000..9cfe19663 --- /dev/null +++ b/src/components/LinkChoice/LinkChoice.tsx @@ -0,0 +1,157 @@ +import React from "react"; +import ClickAwayListener from "@material-ui/core/ClickAwayListener"; +import Paper from "@material-ui/core/Paper"; +import MenuItem from "@material-ui/core/MenuItem"; +import makeStyles from "@material-ui/core/styles/makeStyles"; +import Popper from "@material-ui/core/Popper"; +import { fade } from "@material-ui/core/styles/colorManipulator"; +import classNames from "classnames"; +import { codes } from "keycode"; + +import ArrowDropdown from "@saleor/icons/ArrowDropdown"; +import { FormChange } from "@saleor/hooks/useForm"; +import { SingleAutocompleteChoiceType } from "../SingleAutocompleteSelectField"; +import Link from "../Link"; + +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 { + choices: SingleAutocompleteChoiceType[]; + name: "country"; + value: string; + onChange: FormChange; +} + +const LinkChoice: React.FC = ({ + choices, + name, + value, + onChange +}) => { + const classes = useStyles({}); + const [open, setOpen] = React.useState(false); + const anchor = React.useRef(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) => { + 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 ( + + setOpen(open => !open)}>{current.label} + + + + setOpen(false)} + mouseEvent="onClick" + > + + {choices.map((choice, choiceIndex) => ( + handleChange(choice.value)} + data-tc="select-option" + > + {choice.label} + + ))} + + + + + ); +}; + +LinkChoice.displayName = "LinkChoice"; +export default LinkChoice; diff --git a/src/components/LinkChoice/index.ts b/src/components/LinkChoice/index.ts new file mode 100644 index 000000000..9c927a90f --- /dev/null +++ b/src/components/LinkChoice/index.ts @@ -0,0 +1,2 @@ +export { default } from "./LinkChoice"; +export * from "./LinkChoice";