Fix dropdown select arrow clicks bugs (#2301)

* Fix dropdown arrow click

* Fix multi-select dropdown arrow click

* Update changelog

* Update test snapshots of select inputs

* Grey out select dropdowns bottom arrow

* Prevent clearing input value in multiselect on item select

Co-authored-by: Patryk Andrzejewski <vox3r69@gmail.com>
This commit is contained in:
Dawid 2022-09-23 13:39:25 +02:00 committed by GitHub
parent 4c62ebe45d
commit 9f7c934dec
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 221 additions and 912 deletions

View file

@ -6,6 +6,7 @@ All notable, unreleased changes to this project will be documented in this file.
- Pass query params in `ORDER_DETAILS_MORE_ACTIONS` and `PRODUCT_DETAILS_MORE_ACTIONS` mounting points - #2100 by @witoszekdev
- Add product variant reference attribute - #2268 by @droniu
- Fix dropdown select arrow clicks bugs - #2301 by @orzechdev
- Fix invalid values in channel picker - #2313 by @orzechdev
- Fix missing metadata and payment balance on unconfirmed orders - #2314 by @orzechdev
- Fix exit form dialog false positive - #2311 by @orzechdev

View file

@ -4,10 +4,9 @@ import {
TextField,
Typography,
} from "@material-ui/core";
import { fade } from "@material-ui/core/styles/colorManipulator";
import CloseIcon from "@material-ui/icons/Close";
import Debounce, { DebounceProps } from "@saleor/components/Debounce";
import { ChevronIcon, IconButton, makeStyles } from "@saleor/macaw-ui";
import { ChevronIcon, IconButton } from "@saleor/macaw-ui";
import { FetchMoreProps } from "@saleor/types";
import classNames from "classnames";
import Downshift, { ControllerStateAndHelpers } from "downshift";
@ -18,75 +17,7 @@ import MultiAutocompleteSelectFieldContent, {
MultiAutocompleteActionType,
MultiAutocompleteChoiceType,
} from "./MultiAutocompleteSelectFieldContent";
const useStyles = makeStyles(
theme => ({
chip: {
width: "100%",
},
chipClose: {
height: 32,
padding: 0,
width: 32,
},
chipContainer: {
display: "flex",
flexDirection: "column",
marginTop: theme.spacing(1),
},
chipInner: {
"& svg": {
color: theme.palette.primary.contrastText,
},
alignItems: "center",
background: fade(theme.palette.primary.main, 0.8),
borderRadius: 18,
color: theme.palette.primary.contrastText,
display: "flex",
justifyContent: "space-between",
margin: theme.spacing(1, 0),
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(1),
},
chipLabel: {
color: theme.palette.primary.contrastText,
},
container: {
flexGrow: 1,
position: "relative",
},
disabledChipInner: {
"& svg": {
color: theme.palette.grey[200],
},
alignItems: "center",
background: fade(theme.palette.grey[400], 0.8),
borderRadius: 18,
color: theme.palette.primary.contrastText,
display: "flex",
justifyContent: "space-between",
margin: theme.spacing(1, 0),
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(1),
},
adornment: {
color: theme.palette.saleor.main[3],
cursor: "pointer",
userSelect: "none",
display: "flex",
alignItems: "center",
"& svg": {
transition: theme.transitions.duration.shorter + "ms",
},
},
adornmentRotate: {
"& svg": {
transform: "rotate(180deg)",
},
},
}),
{ name: "MultiAutocompleteSelectField" },
);
import { useStyles } from "./styles";
export interface MultiAutocompleteSelectFieldProps
extends Partial<FetchMoreProps> {
@ -141,14 +72,20 @@ const MultiAutocompleteSelectFieldComponent: React.FC<MultiAutocompleteSelectFie
...rest
} = props;
const classes = useStyles(props);
const anchor = React.useRef<HTMLInputElement | null>(null);
const anchor = React.useRef<HTMLDivElement | null>(null);
const input = React.useRef<HTMLInputElement | null>(null);
const [inputValue, setInputValue] = React.useState("");
const handleSelect = (
item: string,
downshiftOpts?: ControllerStateAndHelpers<string>,
) => {
if (downshiftOpts) {
downshiftOpts.reset({ inputValue: "", isOpen: true });
downshiftOpts.reset({
inputValue: downshiftOpts.inputValue,
isOpen: true,
});
}
onChange({
target: { name, value: item },
@ -157,12 +94,17 @@ const MultiAutocompleteSelectFieldComponent: React.FC<MultiAutocompleteSelectFie
return (
<>
<DebounceAutocomplete debounceFn={fetchChoices}>
<DebounceAutocomplete
debounceFn={value => {
setInputValue(value);
fetchChoices(value);
}}
>
{debounceFn => (
<Downshift
onInputValueChange={value => debounceFn(value)}
onSelect={handleSelect}
itemToString={() => ""}
itemToString={() => inputValue}
// this is to prevent unwanted state updates when the dropdown is closed with an empty value,
// which downshift interprets as the value being updated with an empty string, causing side-effects
stateReducer={(state, changes) => {
@ -181,7 +123,6 @@ const MultiAutocompleteSelectFieldComponent: React.FC<MultiAutocompleteSelectFie
getMenuProps,
highlightedIndex,
inputValue,
getToggleButtonProps,
}) => {
const displayCustomValue =
inputValue &&
@ -192,13 +133,30 @@ const MultiAutocompleteSelectFieldComponent: React.FC<MultiAutocompleteSelectFie
choice.label.toLowerCase() === inputValue.toLowerCase(),
);
const handleFocus = () => {
if (fetchOnFocus) {
fetchChoices(inputValue);
}
input.current.select();
};
const handleToggleMenu = () => {
if (disabled) {
return;
}
toggleMenu();
};
return (
<div className={classes.container} {...rest}>
<TextField
InputProps={{
endAdornment: (
<div
{...getToggleButtonProps()}
onClick={() => {
handleToggleMenu();
handleFocus();
}}
className={classNames(classes.adornment, {
[classes.adornmentRotate]: isOpen,
})}
@ -207,18 +165,15 @@ const MultiAutocompleteSelectFieldComponent: React.FC<MultiAutocompleteSelectFie
<ChevronIcon />
</div>
),
id: undefined,
onFocus: handleFocus,
ref: anchor,
onFocus: () => {
if (fetchOnFocus) {
fetchChoices(inputValue);
}
},
}}
inputProps={{
...getInputProps({
placeholder,
testId,
onClick: toggleMenu,
onClick: handleToggleMenu,
}),
...getMenuProps(),
}}
@ -227,7 +182,9 @@ const MultiAutocompleteSelectFieldComponent: React.FC<MultiAutocompleteSelectFie
label={label}
fullWidth={true}
disabled={disabled}
autoFocus={true}
onBlur={onBlur}
inputRef={input}
/>
{isOpen && (
<Popper
@ -241,7 +198,7 @@ const MultiAutocompleteSelectFieldComponent: React.FC<MultiAutocompleteSelectFie
>
<MultiAutocompleteSelectFieldContent
add={
add && {
!!add && {
...add,
onClick: () => {
add.onClick();

View file

@ -71,6 +71,7 @@ const useStyles = makeStyles(
? theme.palette.grey[50]
: theme.palette.grey[900],
bottom: 0,
color: theme.palette.grey[500],
display: "flex",
height: 30,
justifyContent: "center",

View file

@ -0,0 +1,71 @@
import { fade } from "@material-ui/core/styles/colorManipulator";
import { makeStyles } from "@saleor/macaw-ui";
export const useStyles = makeStyles(
theme => ({
chip: {
width: "100%",
},
chipClose: {
height: 32,
padding: 0,
width: 32,
},
chipContainer: {
display: "flex",
flexDirection: "column",
marginTop: theme.spacing(1),
},
chipInner: {
"& svg": {
color: theme.palette.primary.contrastText,
},
alignItems: "center",
background: fade(theme.palette.primary.main, 0.8),
borderRadius: 18,
color: theme.palette.primary.contrastText,
display: "flex",
justifyContent: "space-between",
margin: theme.spacing(1, 0),
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(1),
},
chipLabel: {
color: theme.palette.primary.contrastText,
},
container: {
flexGrow: 1,
position: "relative",
},
disabledChipInner: {
"& svg": {
color: theme.palette.grey[200],
},
alignItems: "center",
background: fade(theme.palette.grey[400], 0.8),
borderRadius: 18,
color: theme.palette.primary.contrastText,
display: "flex",
justifyContent: "space-between",
margin: theme.spacing(1, 0),
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(1),
},
adornment: {
color: theme.palette.saleor.main[3],
cursor: "pointer",
userSelect: "none",
display: "flex",
alignItems: "center",
"& svg": {
transition: theme.transitions.duration.shorter + "ms",
},
},
adornmentRotate: {
"& svg": {
transform: "rotate(180deg)",
},
},
}),
{ name: "MultiAutocompleteSelectField" },
);

View file

@ -6,7 +6,7 @@ import {
} from "@material-ui/core";
import { InputProps } from "@material-ui/core/Input";
import { ExtendedFormHelperTextProps } from "@saleor/channels/components/ChannelForm/types";
import { ChevronIcon, makeStyles } from "@saleor/macaw-ui";
import { ChevronIcon } from "@saleor/macaw-ui";
import { FetchMoreProps } from "@saleor/types";
import classNames from "classnames";
import Downshift from "downshift";
@ -18,32 +18,7 @@ import SingleAutocompleteSelectFieldContent, {
SingleAutocompleteActionType,
SingleAutocompleteChoiceType,
} from "./SingleAutocompleteSelectFieldContent";
const useStyles = makeStyles(
theme => ({
container: {
flexGrow: 1,
position: "relative",
},
nakedInput: {
padding: theme.spacing(2, 0),
},
adornment: {
color: theme.palette.saleor.main[3],
cursor: "pointer",
userSelect: "none",
"& svg": {
transition: theme.transitions.duration.shorter + "ms",
},
},
adornmentRotate: {
"& svg": {
transform: "rotate(180deg)",
},
},
}),
{ name: "SingleAutocompleteSelectField" },
);
import { useStyles } from "./styles";
export interface SingleAutocompleteSelectFieldProps
extends Partial<FetchMoreProps> {
@ -142,7 +117,6 @@ const SingleAutocompleteSelectFieldComponent: React.FC<SingleAutocompleteSelectF
closeMenu,
highlightedIndex,
reset,
getToggleButtonProps,
}) => {
const isCustomValueSelected =
choices && selectedItem
@ -187,13 +161,30 @@ const SingleAutocompleteSelectFieldComponent: React.FC<SingleAutocompleteSelectF
closeMenu();
};
const handleFocus = () => {
if (fetchOnFocus) {
fetchChoices(inputValue);
}
input.current.select();
};
const handleToggleMenu = () => {
if (disabled) {
return;
}
toggleMenu();
};
const TextFieldComponent = nakedInput ? InputBase : TextField;
const commonInputProps = {
...InputProps,
endAdornment: (
<div
{...getToggleButtonProps()}
onClick={() => {
handleToggleMenu();
handleFocus();
}}
className={classNames(classes.adornment, {
[classes.adornmentRotate]: isOpen,
})}
@ -203,12 +194,8 @@ const SingleAutocompleteSelectFieldComponent: React.FC<SingleAutocompleteSelectF
),
error,
id: undefined,
onFocus: () => {
if (fetchOnFocus) {
fetchChoices(inputValue);
}
input.current.select();
},
onFocus: handleFocus,
ref: anchor,
};
const nakedInputProps = nakedInput
@ -234,12 +221,7 @@ const SingleAutocompleteSelectFieldComponent: React.FC<SingleAutocompleteSelectF
inputProps={{
...getInputProps({
placeholder,
onClick: () => {
if (disabled) {
return;
}
toggleMenu();
},
onClick: handleToggleMenu,
}),
}}
error={error}
@ -249,7 +231,6 @@ const SingleAutocompleteSelectFieldComponent: React.FC<SingleAutocompleteSelectF
label={label}
fullWidth={true}
onBlur={onBlur}
ref={anchor}
inputRef={input}
/>
{isOpen && (!!inputValue || !!choices.length) && (

View file

@ -69,7 +69,7 @@ const useStyles = makeStyles(
? theme.palette.grey[50]
: theme.palette.grey[900],
bottom: 0,
color: theme.palette.primary.main,
color: theme.palette.grey[500],
display: "flex",
height: 30,
justifyContent: "center",

View file

@ -0,0 +1,27 @@
import { makeStyles } from "@saleor/macaw-ui";
export const useStyles = makeStyles(
theme => ({
container: {
flexGrow: 1,
position: "relative",
},
nakedInput: {
padding: theme.spacing(2, 0),
},
adornment: {
color: theme.palette.saleor.main[3],
cursor: "pointer",
userSelect: "none",
"& svg": {
transition: theme.transitions.duration.shorter + "ms",
},
},
adornmentRotate: {
"& svg": {
transform: "rotate(180deg)",
},
},
}),
{ name: "SingleAutocompleteSelectField" },
);

File diff suppressed because it is too large Load diff