UNPKG

@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
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 };