From ae14076ceb0805b382db82f7ea0915ec2a795dbc Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 15 Oct 2019 12:33:14 +0200 Subject: [PATCH] Improve scrolling experience --- assets/images/ChevronDown.svg | 3 + .../SingleAutocompleteSelectField.stories.tsx | 1 - .../SingleAutocompleteSelectFieldContent.tsx | 59 ++++++++++++------- src/hooks/useElementScroll.ts | 22 +++++-- .../singleAutocompleteSelectChangeHandler.ts | 3 +- 5 files changed, 58 insertions(+), 30 deletions(-) create mode 100644 assets/images/ChevronDown.svg diff --git a/assets/images/ChevronDown.svg b/assets/images/ChevronDown.svg new file mode 100644 index 000000000..cc047ee72 --- /dev/null +++ b/assets/images/ChevronDown.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectField.stories.tsx b/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectField.stories.tsx index 8a4435bd6..b8c11b685 100644 --- a/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectField.stories.tsx +++ b/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectField.stories.tsx @@ -2,7 +2,6 @@ import { storiesOf } from "@storybook/react"; import React from "react"; import Form from "@saleor/components/Form"; -import { maybe } from "@saleor/misc"; import CardDecorator from "@saleor/storybook/CardDecorator"; import Decorator from "@saleor/storybook/Decorator"; import { ChoiceProvider } from "@saleor/storybook/mock"; diff --git a/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectFieldContent.tsx b/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectFieldContent.tsx index 24507368c..72bc9da2a 100644 --- a/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectFieldContent.tsx +++ b/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectFieldContent.tsx @@ -7,9 +7,13 @@ import { makeStyles } from "@material-ui/styles"; import classNames from "classnames"; import { GetItemPropsOptions } from "downshift"; import React from "react"; +import SVG from "react-inlinesvg"; import { FormattedMessage } from "react-intl"; -import useElementScroll from "@saleor/hooks/useElementScroll"; +import chevronDown from "@assets/images/ChevronDown.svg"; +import useElementScroll, { + isScrolledToBottom +} from "@saleor/hooks/useElementScroll"; import { FetchMoreProps } from "@saleor/types"; import Hr from "../Hr"; @@ -35,11 +39,29 @@ export interface SingleAutocompleteSelectFieldContentProps const useStyles = makeStyles( (theme: Theme) => ({ + arrowContainer: { + position: "relative" + }, + arrowInnerContainer: { + alignItems: "center", + background: theme.palette.grey[50], + bottom: 0, + display: "flex", + height: 30, + justifyContent: "center", + opacity: 1, + position: "absolute", + transition: theme.transitions.duration.short + "ms", + width: "100%" + }, content: { maxHeight: menuItemHeight * maxMenuItems + theme.spacing.unit * 2, overflow: "scroll", padding: 8 }, + hide: { + opacity: 0 + }, hr: { margin: `${theme.spacing.unit}px 0` }, @@ -53,22 +75,14 @@ const useStyles = makeStyles( justifyContent: "center" }, root: { - borderRadius: 4, + borderBottomLeftRadius: 8, + borderBottomRightRadius: 8, left: 0, marginTop: theme.spacing.unit, + overflow: "hidden", position: "absolute", right: 0, zIndex: 22 - }, - shadow: { - "&$shadowLine": { - boxShadow: `0px -5px 10px 0px ${theme.palette.grey[800]}` - } - }, - shadowLine: { - boxShadow: `0px 0px 0px 0px ${theme.palette.grey[50]}`, - height: 1, - transition: theme.transitions.duration.short + "ms" } }), { @@ -114,10 +128,7 @@ const SingleAutocompleteSelectFieldContent: React.FC< const scrollPosition = useElementScroll(anchor); const [calledForMore, setCalledForMore] = React.useState(false); - const scrolledToBottom = anchor.current - ? scrollPosition.y + anchor.current.clientHeight + offset >= - anchor.current.scrollHeight - : false; + const scrolledToBottom = isScrolledToBottom(anchor, scrollPosition, 50); React.useEffect(() => { if (!calledForMore && onFetchMore && scrolledToBottom) { @@ -133,7 +144,7 @@ const SingleAutocompleteSelectFieldContent: React.FC< }, [loading]); return ( - +
{choices.length > 0 || displayCustomValue ? ( <> @@ -219,11 +230,15 @@ const SingleAutocompleteSelectFieldContent: React.FC< )}
-
0 - })} - /> +
+
0 + })} + > + +
+
); }; diff --git a/src/hooks/useElementScroll.ts b/src/hooks/useElementScroll.ts index 0804d824e..83392800c 100644 --- a/src/hooks/useElementScroll.ts +++ b/src/hooks/useElementScroll.ts @@ -1,20 +1,30 @@ import throttle from "lodash-es/throttle"; import { MutableRefObject, useEffect, useState } from "react"; -function getPosition(anchor?: HTMLElement) { +export type Position = Record<"x" | "y", number>; + +function getPosition(anchor?: HTMLElement): Position { if (!!anchor) { return { x: anchor.scrollLeft, y: anchor.scrollTop }; } - return { - x: 0, - y: 0 - }; + return undefined; } -function useElementScroll(anchor: MutableRefObject) { +export function isScrolledToBottom( + anchor: MutableRefObject, + position: Position, + offset: number = 0 +) { + return !!anchor.current && position + ? position.y + anchor.current.clientHeight + offset >= + anchor.current.scrollHeight + : false; +} + +function useElementScroll(anchor: MutableRefObject): Position { const [scroll, setScroll] = useState(getPosition(anchor.current)); useEffect(() => { diff --git a/src/utils/handlers/singleAutocompleteSelectChangeHandler.ts b/src/utils/handlers/singleAutocompleteSelectChangeHandler.ts index ee2265185..1f95c8a54 100644 --- a/src/utils/handlers/singleAutocompleteSelectChangeHandler.ts +++ b/src/utils/handlers/singleAutocompleteSelectChangeHandler.ts @@ -10,7 +10,8 @@ function createSingleAutocompleteSelectHandler( change(event); const value = event.target.value; - setSelected(choices.find(category => category.value === value).label); + const choice = choices.find(category => category.value === value) + setSelected(choice ? choice.label : value); }; }