Итак, у нас есть компонент search select, который отлично выглядит в dev, но в тот момент, когда он запускается в производство, он ломается. Я пробовал перемещать стилирование по-разному, но, похоже, ничего не работает, а только ломает ввод. Кто-нибудь имел опыт работы с этой проблемой и как ее исправить?
Здесь локально:
А вот как это выглядит в производстве:
Вот используемые компоненты:
SearchSelect. js
import PropTypes from "prop-types";
import NoSsr from "@material-ui/core/NoSsr";
import Async from "react-select/lib/Async";
import debounce from "debounce-promise";
import { withStyles } from "@material-ui/core";
import { styles, useStyles } from "./Styles";
import * as Components from "./Components";
const comps = { ...Components };
const SearchSelect = ({
optionsFetcher,
isMulti,
minLength,
delay,
maxOptions,
label,
errors,
onChange,
onBlur,
classes: customClasses,
value,
showErrors,
components,
}) => {
const classes = useStyles();
const [menuIsOpen, setMenuIsOpen] = useState(false);
const [maxReached, setMaxReached] = useState(false);
const debounced = debounce(val => {
if (minLength && val.length <= minLength) {
setMenuIsOpen(false);
return Promise.resolve([]);
}
setMenuIsOpen(true);
return optionsFetcher(val);
}, delay);
const handleChange = (selectedOptions, { action }) => {
if (maxReached && action !== "remove-value" && action !== "clear") {
return;
}
if (selectedOptions && selectedOptions.length <= maxOptions) {
setMaxReached(false);
}
if (maxOptions && isMulti && action === "select-option") {
if (selectedOptions.length === Number(maxOptions)) {
setMaxReached(true);
}
setMenuIsOpen(false);
} else {
setMenuIsOpen(false);
}
onChange(selectedOptions);
};
const noOptionsHelper = input => {
if (input === "") {
return "Please type to search...";
}
return `No options matching "${input}"`;
};
const noOptionsMessage = ({ inputValue }) => {
if (maxReached) {
return `You can only select ${maxOptions} options.`;
}
return noOptionsHelper(inputValue);
};
return (
<div className={classes.root}>
<NoSsr>
<Async
classes={classes}
dropdownIndicator={{
hasValue: false,
}}
inputId="react-select-single"
TextFieldProps={{
label,
InputLabelProps: {
htmlFor: "react-select-single",
shrink: "true",
classes: {
root: customClasses.cssLabel,
focused: customClasses.cssFocused,
},
},
InputProps: {
value: value.label || value,
classes: {
root: customClasses.cssOutlinedInput,
focused: customClasses.cssFocused,
notchedOutline: customClasses.notchedOutline,
disabled: customClasses.disabled,
},
},
}}
error={(showErrors && errors && Boolean(errors.length)) || false}
helperText={errors}
placeholder=""
components={{
...components,
...comps,
DropdownIndicator: () => null,
IndicatorSeparator: () => null,
}}
isClearable
onChange={handleChange}
onBlur={e => {
setMenuIsOpen(false);
onBlur(e);
}}
cacheOptions={false}
loadOptions={val => debounced(val)}
isMulti={isMulti}
menuIsOpen={menuIsOpen}
closeMenuOnSelect
blurInputOnSelect={false}
noOptionsMessage={noOptionsMessage}
styles={{
input: () => ({ height: "50px", paddingTop: "13px" }),
}}
value={value}
/>
</NoSsr>
</div>
);
};
SearchSelect.defaultProps = {
isMulti: false,
minLength: 0,
delay: 150,
maxOptions: null,
showErrors: true,
errors: null,
components: {},
};
SearchSelect.propTypes = {
optionsFetcher: PropTypes.func.isRequired,
isMulti: PropTypes.bool,
minLength: PropTypes.number,
delay: PropTypes.number,
maxOptions: PropTypes.number,
label: PropTypes.string.isRequired,
showErrors: PropTypes.bool,
errors: PropTypes.arrayOf(PropTypes.any),
onChange: PropTypes.func.isRequired,
onBlur: PropTypes.func.isRequired,
classes: PropTypes.objectOf(PropTypes.any).isRequired,
value: PropTypes.objectOf(PropTypes.any).isRequired,
components: PropTypes.objectOf(PropTypes.any),
};
export default withStyles(styles)(SearchSelect);
Компоненты. js
/**
* All code taken and customised
* https://v3.material-ui.com/demos/autocomplete/
* 'react-select' section
*/
import React from "react";
import clsx from "clsx";
import Typography from "@material-ui/core/Typography";
import TextField from "@material-ui/core/TextField";
import Paper from "@material-ui/core/Paper";
import Chip from "@material-ui/core/Chip";
import CancelIcon from "@material-ui/icons/Cancel";
import PropTypes from "prop-types";
import { useStyles } from "./Styles";
export const NoOptionsMessage = ({ selectProps, innerProps, children }) => (
<Typography
color="textSecondary"
className={selectProps.classes.noOptionsMessage}
{...innerProps}
>
{children}
</Typography>
);
NoOptionsMessage.propTypes = {
selectProps: PropTypes.objectOf(PropTypes.any).isRequired,
innerProps: PropTypes.objectOf(PropTypes.any).isRequired,
children: PropTypes.node.isRequired,
};
export const inputComponent = ({ inputRef, ...props }) => <div ref={inputRef} {...props} />;
inputComponent.propTypes = { inputRef: PropTypes.string.isRequired };
export const Control = props => {
const {
children,
innerProps,
innerRef,
selectProps: { TextFieldProps, error, helperText },
} = props;
const classes = useStyles();
return (
<TextField
variant="outlined"
fullWidth
error={error}
helperText={helperText}
{...TextFieldProps}
InputProps={{
inputComponent,
inputProps: {
className: classes.input,
ref: innerRef,
children,
...innerProps,
},
...TextFieldProps.InputProps,
}}
/>
);
};
Control.propTypes = {
children: PropTypes.node.isRequired,
innerProps: PropTypes.objectOf(PropTypes.any).isRequired,
innerRef: PropTypes.string.isRequired,
classes: PropTypes.objectOf(PropTypes.any).isRequired,
TextFieldProps: PropTypes.objectOf(PropTypes.any).isRequired,
error: PropTypes.bool.isRequired,
helperText: PropTypes.oneOfType([PropTypes.array, PropTypes.string]).isRequired,
};
export const Placeholder = props => {
const { selectProps, innerProps = {}, children } = props;
return (
<Typography color="textSecondary" className={selectProps.classes.placeholder} {...innerProps}>
{children}
</Typography>
);
};
Placeholder.propTypes = {
selectProps: PropTypes.objectOf(PropTypes.any).isRequired,
innerProps: PropTypes.objectOf(PropTypes.any).isRequired,
children: PropTypes.node.isRequired,
};
export const SingleValue = ({ selectProps, innerProps, children }) => (
<Typography className={selectProps.classes.singleValue} {...innerProps}>
{children}
</Typography>
);
SingleValue.propTypes = {
selectProps: PropTypes.objectOf(PropTypes.any).isRequired,
innerProps: PropTypes.objectOf(PropTypes.any).isRequired,
children: PropTypes.node.isRequired,
};
export const ValueContainer = ({ selectProps, children }) => (
<div className={selectProps.classes.valueContainer}>{children}</div>
);
ValueContainer.propTypes = {
selectProps: PropTypes.objectOf(PropTypes.any).isRequired,
children: PropTypes.node.isRequired,
};
export const MultiValue = ({ children, selectProps, isFocused, removeProps }) => (
<Chip
tabIndex={-1}
label={children}
className={clsx(selectProps.classes.chip, {
[selectProps.classes.chipFocused]: isFocused,
})}
onDelete={removeProps.onClick}
deleteIcon={<CancelIcon {...removeProps} />}
/>
);
MultiValue.propTypes = {
selectProps: PropTypes.objectOf(PropTypes.any).isRequired,
children: PropTypes.node.isRequired,
isFocused: PropTypes.bool.isRequired,
removeProps: PropTypes.func.isRequired,
};
export const Menu = ({ selectProps, innerProps, children }) => (
<Paper square className={selectProps.classes.paper} {...innerProps}>
{children}
</Paper>
);
Menu.propTypes = {
selectProps: PropTypes.objectOf(PropTypes.any).isRequired,
innerProps: PropTypes.objectOf(PropTypes.any).isRequired,
children: PropTypes.node.isRequired,
};
Стили. js
import { emphasize, makeStyles } from "@material-ui/core/styles";
/**
* Custom styles to override material UI & react-selects
* styles
*/
export const styles = {
cssLabel: {
color: "#333",
fontSize: "12px",
fontWeight: "light",
zIndex: 3,
},
textField: {
width: "100%",
margin: "10px 0",
},
cssOutlinedInput: {
"&$cssFocused $notchedOutline": {
borderColor: "#333 !important",
borderRadius: "8px",
borderWidth: "1.5px",
zIndex: 2,
},
},
inputTypeSearch: {
padding: "16px 14px",
},
disabled: {
"&$disabled": {
cursor: "not-allowed",
backgroundColor: "#ebebeb",
borderRadius: "11px",
},
},
cssFocused: {
"&$cssLabel": {
color: "#333",
},
},
notchedOutline: {
border: "1px solid #DBDADA",
borderRadius: "11px",
zIndex: 2,
},
};
/**
* Code taken from
* https://v3.material-ui.com/demos/autocomplete/
* 'react-select' section
*/
export const useStyles = makeStyles(theme => ({
root: {
flexGrow: 1,
minWidth: 290,
marginBottom: 12,
marginTop: 12,
zIndex: 2,
},
input: {
display: "flex",
padding: 0,
height: "auto",
paddingLeft: "14px",
zIndex: 2,
background: "#fff",
},
valueContainer: {
display: "flex",
flexWrap: "wrap",
flex: 2,
alignItems: "center",
},
chip: {
margin: theme.spacing(0.5, 0.25),
},
chipFocused: {
backgroundColor: emphasize(
theme.palette.type === "light" ? theme.palette.grey[300] : theme.palette.grey[700],
0.08,
),
},
noOptionsMessage: {
padding: theme.spacing(1, 2),
},
singleValue: {
fontSize: 16,
},
placeholder: {
position: "absolute",
left: 14,
bottom: 11,
fontSize: 14,
},
paper: {
background: "#F4F4F4",
border: "none",
boxShadow: "none",
position: "absolute",
top: "30px",
left: "-4%",
padding: "50px 0",
width: "107%",
zIndex: 1,
},
divider: {
height: theme.spacing(2),
},
}));