@codeworker.br/govbr-tw-react
Version:
Biblioteca de componentes React usando Tailwind CSS que implementa o Padrão Digital de Governo.
86 lines (85 loc) • 5.99 kB
JavaScript
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useEffect, useRef, useState } from "react";
import BASE_CLASSNAMES from "../../config/baseClassNames";
import { cn } from "../../libs/utils";
import Checkbox from "../Checkbox";
import { v4 as uuidv4 } from "uuid";
import Input from "../Input";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faChevronLeft, faChevronRight, faFilter, faXmark, } from "@fortawesome/free-solid-svg-icons";
import { Button } from "../Button";
const MultiComboBox = (_a) => {
var { className, name = `multiComboBox-${uuidv4()}`, options, selectAllLabel = ["Selecionar Todas", "Deselecionar Todas"], pageSize = 5, // Define quantas opções por página,
onChange = () => [], noOptionFoundLabel = "Nenhuma opção encontrada", values = [], sortOrder = 'none', filterPlaceholder = "Filtrar ..." } = _a, props = __rest(_a, ["className", "name", "options", "selectAllLabel", "pageSize", "onChange", "noOptionFoundLabel", "values", "sortOrder", "filterPlaceholder"]);
const [filter, setFilter] = useState("");
const [currentPage, setCurrentPage] = useState(1);
const [selectedOptions, setSelectedOptions] = useState(values);
const [ulHeight, setUlHeight] = useState(0);
// Ref para o ul
const ulRef = useRef(null);
// Filtra as opções com base no filtro de busca
const filteredOptions = options.filter((option) => option.label.toLowerCase().includes(filter.toLowerCase()));
if (sortOrder !== "none") {
filteredOptions.sort((a, b) => {
const comparison = a.label.localeCompare(b.label);
return sortOrder === "asc" ? comparison : -comparison;
});
}
const totalPages = Math.ceil(filteredOptions.length / pageSize);
// Pagina as opções filtradas
const paginatedOptions = filteredOptions.slice((currentPage - 1) * pageSize, currentPage * pageSize);
// Verifica se todas as opções filtradas (não apenas da página atual) estão selecionadas
const allSelected = options.length > 0 &&
options.every((option) => selectedOptions.includes(option.value));
// Lógica para selecionar todas as opções filtradas
const handleSelectAll = () => {
if (allSelected) {
// Desmarca todos os itens filtrados
const remainingSelected = selectedOptions.filter((opt) => !filteredOptions.some((option) => option.value === opt));
setSelectedOptions(remainingSelected);
onChange(remainingSelected);
}
else {
// Seleciona todas as opções filtradas
const newSelections = filteredOptions
.map((option) => option.value)
.filter((value) => !selectedOptions.includes(value));
const newValue = [...selectedOptions, ...newSelections];
setSelectedOptions(newValue);
onChange(newValue);
}
};
const handleClearFilter = () => {
setFilter("");
};
const handleOptionChange = (value) => {
if (selectedOptions.includes(value)) {
const newValue = selectedOptions.filter((opt) => opt !== value);
setSelectedOptions(newValue);
onChange(newValue);
}
else {
const newValue = [...selectedOptions, value];
setSelectedOptions(newValue);
onChange(newValue);
}
};
useEffect(() => {
if (ulRef.current) {
setUlHeight(ulRef.current.clientHeight); // Atualiza a altura dinamicamente
}
}, []);
return (_jsxs("div", { className: cn(BASE_CLASSNAMES.multiComboBox.root, "flex flex-col gap-2"), children: [_jsx("div", { className: "flex gap-2", children: _jsxs(Input, { placeholder: filterPlaceholder, type: "text", iconPosition: "both", value: filter, onChange: (e) => setFilter(e.target.value), children: [_jsx(FontAwesomeIcon, { icon: faFilter }), _jsx(Button, { size: "icon", variant: "ghost", density: "high", onClick: handleClearFilter, children: _jsx(FontAwesomeIcon, { icon: faXmark }) })] }) }), _jsx("div", { style: { minHeight: `${ulHeight}px` }, children: _jsxs("ul", { className: cn("flex flex-col gap-1"), ref: ulRef, children: [_jsx("li", { children: _jsxs(Checkbox, { name: `selectAll-${name}`, checked: allSelected, onChange: handleSelectAll, children: [selectAllLabel[allSelected ? 1 : 0], " (", options.length, ")"] }) }), filteredOptions.length === 0 ? (_jsx("li", { className: "text-govbr-gray-20", children: noOptionFoundLabel })) : (paginatedOptions.map((option) => (_jsx("li", { children: _jsx(Checkbox, { name: name, value: option.value, checked: selectedOptions.includes(option.value), onChange: () => handleOptionChange(option.value), children: option.label }) }, uuidv4()))))] }) }), filteredOptions.length > pageSize && (_jsx("div", { className: "flex justify-between mt-2", children: _jsxs("div", { className: "flex gap-2 items-center w-full", children: [_jsx(Button, { variant: "ghost", size: "icon", disabled: currentPage === 1, onClick: () => setCurrentPage(currentPage - 1), children: _jsx(FontAwesomeIcon, { icon: faChevronLeft }) }), _jsxs("div", { className: "flex-1 text-center text-sm", children: [currentPage, "/", totalPages] }), _jsx(Button, { variant: "ghost", size: "icon", disabled: currentPage === totalPages, onClick: () => setCurrentPage(currentPage + 1), children: _jsx(FontAwesomeIcon, { icon: faChevronRight }) })] }) }))] }));
};
export { MultiComboBox };