Skip to content

Instantly share code, notes, and snippets.

@jonathasborges1
Last active September 7, 2023 23:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jonathasborges1/2162c72d666daf218855baf20b3210a4 to your computer and use it in GitHub Desktop.
Save jonathasborges1/2162c72d666daf218855baf20b3210a4 to your computer and use it in GitHub Desktop.
TextFieldMultiSelect.tsx
import React, { useState } from "react";
import Autocomplete, {
AutocompleteRenderInputParams,
} from "@mui/material/Autocomplete";
import { Checkbox, IconButton, Grid, Typography, Box } from "@mui/material";
import TextField from "@mui/material/TextField";
import { useTheme } from "@material-ui/core";
import { ArrowDownSelectIcon } from "@components/Icons";
interface Option {
value: string;
label: string;
}
interface TextFieldMultiSelectProps {
label?: string;
options: Option[];
onChange?: (e: Option[]) => void;
}
const TextFieldMultiSelect: React.FC<TextFieldMultiSelectProps> = ({
options,
...props
}) => {
const theme = useTheme();
const [selectedOptions, setSelectedOptions] = useState<Option[]>([]);
const [isMenuOpen, setIsMenuOpen] = useState(true);
const handleOptionChange = (_event, newOptions: Option[]) => {
// Verifica se "Todos" esta contido na lista
const isAllSelected = newOptions.some((option) => option.value === "todos");
// Verifique se "Todos" foi selecionado
const optionTodosIsSelected = _event.target?.innerText.includes("Todos");
let optionsResult: Option[] = [];
// Cenario 1 - Clicou em "Todos" entao marca todas as opcoes disponives
if (optionTodosIsSelected && isAllSelected) {
optionsResult = options;
setSelectedOptions(optionsResult);
}
// Cenario 2 - Clicou em todos pelo segunda vez entao desmarca todas as opcoes disponives
if (optionTodosIsSelected && !isAllSelected) {
optionsResult = [];
setSelectedOptions(optionsResult);
}
// Cenario 3 - Clicou em todos e depois desmarcou algum opcao
if (isAllSelected && !optionTodosIsSelected) {
optionsResult = newOptions.filter((op) => op.value !== "todos");
setSelectedOptions(optionsResult);
}
// Cenario 4 - Opcao "Todos" esta desmarcado
if (!isAllSelected && !optionTodosIsSelected) {
optionsResult = newOptions;
setSelectedOptions(optionsResult);
}
// remove a opcao "Todos" da lista (se existir) e envia para o componente pai
props.onChange &&
props.onChange(optionsResult.filter((op) => op.value !== "todos"));
};
const handleOpenMenu = () => {
setIsMenuOpen(true);
};
const handleCloseMenu = () => {
setIsMenuOpen(false);
};
const handleIconButtonMenu = () => {
setIsMenuOpen(!isMenuOpen);
};
const customRenderOptionsLabel = (options: Option[]) => {
if (options.find((op) => op.value === "todos")) return "Todos";
const optionsLabel = options.map((option) => {
return option.label;
});
return optionsLabel.join(" / ");
};
return (
<Autocomplete
open={isMenuOpen}
onOpen={handleOpenMenu}
onClose={handleCloseMenu}
multiple
id="multi-select"
options={options}
value={selectedOptions}
onChange={handleOptionChange}
getOptionLabel={(option) => option.label}
renderInput={(params: AutocompleteRenderInputParams) => (
<Grid container justifyContent={"end"} sx={{ border: "0px solid red" }}>
<TextField
{...params}
className="TextField-select-custom"
label={props.label} //"Selecione opções"
variant="outlined"
fullWidth
sx={{
border: "0px solid red",
"& svg": { display: "none" },
"& .MuiAutocomplete-inputRoot": {
border: "0px solid blue",
padding: "1rem 0rem 1rem 1rem !important",
margin: 0,
},
"& .MuiInputLabel-shrink": {
fontWeight: 700,
fontSize: "1.4rem",
letterSpacing: "1.5px",
background: "white",
},
"& label": {
fontSize: "1.2rem",
fontFamily: theme.typography.fontFamily,
color: `rgba(0, 0, 0, 0.50)`,
},
"& fieldset": {
border: "1px solid rgba(114, 101, 81, 0.40)",
borderRadius: 1,
},
"& input": {
maxWidth: "min-content",
minWidth: "min-content",
},
}}
/>
<IconButton
onClick={handleIconButtonMenu}
sx={{ position: "absolute", margin: "1rem 1rem 1rem 0rem" }}
>
<ArrowDownSelectIcon sx={{ fontSize: 11 }} />{" "}
{/* Ícone personalizado */}
</IconButton>
</Grid>
)}
renderOption={(props, option, { selected }) => (
<li {...props} style={{ border: "0px solid red", cursor: "pointer" }}>
<div style={{ display: "flex", alignItems: "center" }}>
<Checkbox
style={{
color: selected ? "red" : "inherit",
pointerEvents: "none",
}}
checked={selected}
/>
<Typography
sx={{
fontFamily: theme.typography.fontFamily,
}}
>
{option.label}
</Typography>
</div>
</li>
)}
disableCloseOnSelect
isOptionEqualToValue={(option: Option, value: Option) =>
option.value === value.value
}
// renderiza os valores selecionados no componente textField
renderTags={(value: Option[], getTagProps) => (
<Box
sx={{
border: "0px solid red",
display: "flex",
maxWidth: "90%", // Set maximum width
whiteSpace: "nowrap", // Prevent text from wrapping
}}
>
<Typography
variant="body2"
sx={{
fontSize: { lg: "1.2rem" },
border: "0px solid blue",
fontFamily: theme.typography.fontFamily,
fontWeight: 500,
padding: "1px",
marginX: "8px",
overflow: "hidden", // Hide overflow content
textOverflow: "ellipsis", // Display ellipsis for overflow
}}
>
{customRenderOptionsLabel(value)}
</Typography>
</Box>
)}
/>
);
};
export default TextFieldMultiSelect;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment