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:
parent
4c62ebe45d
commit
9f7c934dec
8 changed files with 221 additions and 912 deletions
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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",
|
||||
|
|
71
src/components/MultiAutocompleteSelectField/styles.ts
Normal file
71
src/components/MultiAutocompleteSelectField/styles.ts
Normal 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" },
|
||||
);
|
|
@ -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) && (
|
||||
|
|
|
@ -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",
|
||||
|
|
27
src/components/SingleAutocompleteSelectField/styles.ts
Normal file
27
src/components/SingleAutocompleteSelectField/styles.ts
Normal 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
Loading…
Reference in a new issue