UNPKG

ivt

Version:

Ivt Components Library

579 lines (573 loc) 27.9 kB
import { g as get, s as set, h as appendErrors, i as useForm, F as Form, f as FormField, a as FormItem, b as FormLabel, c as FormControl, d as FormDescription, e as FormMessage } from '../chunks/form-0eamcSZm.mjs'; import React__default from 'react'; import { N as NumericFormat, P as PatternFormat } from '../chunks/react-number-format.es-DSc45Db0.mjs'; import { c as cn } from '../chunks/utils-05LlW3Cl.mjs'; import { f as formatDateToBrazilian, a as parseFieldDate, p as ptBR } from '../chunks/date-bAe2UaSj.mjs'; import { a as formatNumberWithComma, s as styleInput, c as styleSelect } from '../chunks/format-numbers-BMHnFGse.mjs'; import { S as Sheet, a as SheetTrigger, c as SheetContent, d as SheetHeader, f as SheetTitle, e as SheetFooter, b as SheetClose } from '../chunks/sheet-BVDcVKli.mjs'; import { c as createLucideIcon } from '../chunks/createLucideIcon-DLrNgMqk.mjs'; import { C as CalendarDays } from '../chunks/calendar-days-D8ft1Hpj.mjs'; import { C as CalendarRange } from '../chunks/CalendarRange-BCcF9etO.mjs'; import { C as ComboboxField } from '../chunks/ComboboxField-C8LG3Dfr.mjs'; import { M as MultiSelect } from '../chunks/multi-select-dor8SMeS.mjs'; import { B as Button } from '../chunks/button-Co_1yLv6.mjs'; import { B as Badge } from '../chunks/badge-rV4HbE_R.mjs'; import { S as ScrollArea } from '../chunks/scroll-area-Cr1Iu-Ot.mjs'; import { P as Popover, a as PopoverTrigger, b as PopoverContent } from '../chunks/popover-CsYW0nDm.mjs'; import { C as Calendar } from '../chunks/calendar-olAv9AH7.mjs'; import { f as format } from '../chunks/format-Cn5wls3k.mjs'; import { L as Label } from '../chunks/label-atj6gghV.mjs'; import { C as Checkbox } from '../chunks/checkbox-D9LLByPZ.mjs'; import { S as Separator } from '../chunks/separator-StpvupIv.mjs'; import { S as Select, h as SelectTrigger, i as SelectValue, a as SelectContent, c as SelectItem } from '../chunks/select-C4BJbkha.mjs'; import { I as Input } from '../chunks/input-BEkvMaQp.mjs'; import '@radix-ui/react-slot'; import '../chunks/bundle-mjs-BYcyWisL.mjs'; import '../chunks/index-BRYGnp2Q.mjs'; import '../chunks/index-Bl-WJHvp.mjs'; import '../chunks/index-1tQVI0Jh.mjs'; import '../chunks/index-DT8WgpCS.mjs'; import 'react/jsx-runtime'; import '../chunks/index-tkRL9Tft.mjs'; import '../chunks/index-DKOlG3mh.mjs'; import '../chunks/index-D4FMFHi9.mjs'; import '../chunks/index-DUpRrJTH.mjs'; import '../chunks/index-DgKlJYZP.mjs'; import 'react-dom'; import '../chunks/index-Cbm3--wc.mjs'; import '../chunks/index-DvCZGX3H.mjs'; import '../chunks/tslib.es6-DXUeYCTx.mjs'; import '../chunks/index-BTe1rv5Z.mjs'; import '../chunks/index-C6s8KI_8.mjs'; import '../chunks/x-BOMmTgZd.mjs'; import '../chunks/chevrons-up-down-BFiJwHit.mjs'; import '../chunks/check-BBGTedl-.mjs'; import '../chunks/command-IckfUQsK.mjs'; import '../chunks/dialog-BkF50Tmo.mjs'; import 'class-variance-authority'; import '../chunks/wand-sparkles-BIbU0kjG.mjs'; import '../chunks/tooltip-BTEGteNb.mjs'; import '../chunks/index-aLIsJMgt.mjs'; import '../chunks/index-DmY774z-.mjs'; import '../chunks/index-An4yBrAZ.mjs'; import '../chunks/index-CGLjQEjG.mjs'; import '../chunks/index-GgS4otoq.mjs'; import '../chunks/chevron-left-D7OzIyKL.mjs'; import '../chunks/chevron-right-mC6NR8jW.mjs'; import '../chunks/chevron-down-DNXEgdv9.mjs'; import '../chunks/index-FL3PKmOS.mjs'; import '@radix-ui/react-select'; const __iconNode = [ [ "path", { d: "M3 6h18", key: "d0wm0j" } ], [ "path", { d: "M7 12h10", key: "b7w52i" } ], [ "path", { d: "M10 18h4", key: "1ulq68" } ] ]; const ListFilter = createLucideIcon("ListFilter", __iconNode); const r = (t, r, o)=>{ if (t && "reportValidity" in t) { const s = get(o, r); t.setCustomValidity(s && s.message || ""), t.reportValidity(); } }, o = (e, t)=>{ for(const o in t.fields){ const s = t.fields[o]; s && s.ref && "reportValidity" in s.ref ? r(s.ref, o, e) : s && s.refs && s.refs.forEach((t)=>r(t, o, e)); } }, s$1 = (r, s)=>{ s.shouldUseNativeValidation && o(r, s); const n = {}; for(const o in r){ const f = get(s.fields, o), c = Object.assign(r[o] || {}, { ref: f && f.ref }); if (i(s.names || Object.keys(r), o)) { const r = Object.assign({}, get(n, o)); set(r, "root", c), set(n, o, r); } else set(n, o, c); } return n; }, i = (e, t)=>{ const r = n$1(t); return e.some((e)=>n$1(e).match(`^${r}\\.\\d+`)); }; function n$1(e) { return e.replace(/\]|\[/g, ""); } function n(r, e) { for(var n = {}; r.length;){ var s = r[0], t = s.code, i = s.message, a = s.path.join("."); if (!n[a]) if ("unionErrors" in s) { var u = s.unionErrors[0].errors[0]; n[a] = { message: u.message, type: u.code }; } else n[a] = { message: i, type: t }; if ("unionErrors" in s && s.unionErrors.forEach(function(e) { return e.errors.forEach(function(e) { return r.push(e); }); }), e) { var c = n[a].types, f = c && c[s.code]; n[a] = appendErrors(a, e, n, t, f ? [].concat(f, s.message) : s.message); } r.shift(); } return n; } function s(o$1, s, t) { return void 0 === t && (t = {}), function(i, a, u) { try { return Promise.resolve(function(e, n) { try { var a = Promise.resolve(o$1["sync" === t.mode ? "parse" : "parseAsync"](i, s)).then(function(e) { return u.shouldUseNativeValidation && o({}, u), { errors: {}, values: t.raw ? Object.assign({}, i) : e }; }); } catch (r) { return n(r); } return a && a.then ? a.then(void 0, n) : a; }(0, function(r) { if (function(r) { return Array.isArray(null == r ? void 0 : r.errors); }(r)) return { values: {}, errors: s$1(n(r.errors, !u.shouldUseNativeValidation && "all" === u.criteriaMode), u) }; throw r; })); } catch (r) { return Promise.reject(r); } }; } // biome-ignore lint/suspicious/noExplicitAny: <any> function TableFilter({ table, defaultSide = "right", disabled, title, schema, fieldConfigs, defaultFilterValues, appliedFiltersCount = 0, setAppliedFiltersCount, applyFiltersOnMount, onClearFilters, onApplyFilters, badgeMultiselectVariant = "default", badgeMultiselectSubtle = false }) { React__default.useEffect(()=>{ for (const { name, filterType } of fieldConfigs){ const column = table.getColumn(name); if (column) { const filterValue = column.getFilterValue(); let valueToFilter = filterValue; if (filterType === "currency" && typeof filterValue === "number") { valueToFilter = formatNumberWithComma({ value: filterValue, minimumFractionDigits: 2, maximumFractionDigits: 2 }); } if (valueToFilter !== undefined && valueToFilter !== null && valueToFilter !== "") { column.setFilterValue(valueToFilter); } } } }, [ table, fieldConfigs ]); const [clearTrigger, setClearTrigger] = React__default.useState(0); const form = useForm({ resolver: schema ? s(schema) : undefined, defaultValues: defaultFilterValues }); const countAppliedFilters = (data)=>{ return Object.values(data).filter((value)=>{ if (Array.isArray(value)) return value.length > 0; if (value === null || value === undefined) return false; // Para strings (texto e data), verificar se não está vazio if (typeof value === "string") return value.trim() !== ""; if (typeof value === "object") { // biome-ignore lint/suspicious/noExplicitAny: <any> const val = value; // Para DateRange, verificar se tem from ou to if ("from" in val || "to" in val) { return Boolean(val.from || val.to); } // Para NumericFilterValue, verificar se tem valor (incluindo 0) if ("value" in val && "operator" in val) { return val.value !== null && val.value !== undefined && String(val.value) !== ""; } return true; } // Para números, aceitar 0 como válido if (typeof value === "number") return true; return Boolean(value); }).length; }; // biome-ignore lint/correctness/useExhaustiveDependencies: <useCallback> const handleCleanFilters = React__default.useCallback(()=>{ for (const column of table.getAllColumns()){ if (column.getCanFilter()) { column.setFilterValue(undefined); } } if (setAppliedFiltersCount) { setAppliedFiltersCount(0); } form.reset(defaultFilterValues); // Trigger para forçar re-render do MultiSelect setClearTrigger((prev)=>prev + 1); if (onClearFilters) { onClearFilters(); } }, []); const handleApplyFilters = (data)=>{ const allFieldsEmpty = Object.entries(data).every(([, value])=>{ // Para arrays (multiselect), verificar se tem itens if (Array.isArray(value)) { return value.length === 0; } // Para strings (texto e data), verificar se não está vazio if (typeof value === "string") { return value.trim() === ""; } // Para objetos (numeric_range ou dateRange), verificar se tem valor if (typeof value === "object" && value !== null) { // Verificar se é NumericFilterValue if ("value" in value && "operator" in value) { const numericValue = value; return numericValue.value === null || numericValue.value === undefined || String(numericValue.value) === ""; } // Verificar se é DateRange if ("from" in value || "to" in value) { const dateRange = value; return !dateRange.from && !dateRange.to; } } return value === null || value === ""; }); if (allFieldsEmpty && appliedFiltersCount > 0) { handleCleanFilters(); return; } const hasValues = Object.entries(data).some(([, value])=>{ // Para arrays (multiselect), verificar se tem itens if (Array.isArray(value)) { return value.length > 0; } // Para strings (texto e data), verificar se não está vazio if (typeof value === "string") { return value.trim() !== ""; } // Para objetos (numeric_range ou dateRange), verificar se tem valor if (typeof value === "object" && value !== null) { // Verificar se é NumericFilterValue if ("value" in value && "operator" in value) { const numericValue = value; return numericValue.value !== null && numericValue.value !== undefined && String(numericValue.value) !== ""; } // Verificar se é DateRange if ("from" in value || "to" in value) { const dateRange = value; return Boolean(dateRange.from || dateRange.to); } } // Para números simples, aceitar 0 como válido if (typeof value === "number") { return true; } return value !== null && value !== ""; }); if (!hasValues) return; for (const { name } of fieldConfigs){ const column = table.getColumn(name); if (column) { let filterValue = data[name]; if (Array.isArray(filterValue) && filterValue.length === 0) { filterValue = undefined; } if (typeof filterValue === "string" && filterValue.trim() === "") { filterValue = undefined; } // Para objetos DateRange vazios, definir como undefined if (typeof filterValue === "object" && filterValue !== null && "from" in filterValue && "to" in filterValue) { const dateRange = filterValue; if (!dateRange.from && !dateRange.to) { filterValue = undefined; } } column.setFilterValue(filterValue); } } const count = countAppliedFilters(data); if (setAppliedFiltersCount) { setAppliedFiltersCount(count); } // Chamar callback de aplicar filtros (para filtragem server-side) // Só chama se onApplyFilters existir e data for válido if (onApplyFilters && data) { onApplyFilters(data); } }; const handleOpenChange = (open)=>{ if (!open) { form.handleSubmit(handleApplyFilters)(); } }; // Event listener para scroll do mouse (CSS global já cuida do resto) React__default.useEffect(()=>{ const handleWheel = (e)=>{ const cmdkList = e.target.closest("[cmdk-list]"); if (cmdkList) { e.preventDefault(); cmdkList.scrollTop += e.deltaY; } }; document.addEventListener("wheel", handleWheel, { passive: false }); return ()=>{ document.removeEventListener("wheel", handleWheel); }; }, []); // biome-ignore lint/correctness/useExhaustiveDependencies: <useEffect> React__default.useEffect(()=>{ if (applyFiltersOnMount) { handleApplyFilters(form.getValues()); } }, [ form ]); return /*#__PURE__*/ React__default.createElement(Sheet, { onOpenChange: handleOpenChange }, /*#__PURE__*/ React__default.createElement("div", { className: "text-foreground flex items-center gap-2" }, appliedFiltersCount > 0 && /*#__PURE__*/ React__default.createElement(Button, { variant: "ghost", onClick: handleCleanFilters, "aria-label": "Limpar filtros" }, "Limpar filtros"), /*#__PURE__*/ React__default.createElement(SheetTrigger, { asChild: true }, /*#__PURE__*/ React__default.createElement(Button, { variant: "secondary", size: "sm", "aria-label": "Mais filtros", className: "relative", disabled: disabled }, /*#__PURE__*/ React__default.createElement(ListFilter, { className: "size-4" }), /*#__PURE__*/ React__default.createElement("span", null, "Filtrar"), appliedFiltersCount > 0 && /*#__PURE__*/ React__default.createElement(Badge, { className: "bg-primary h-5 w-7" }, appliedFiltersCount)))), /*#__PURE__*/ React__default.createElement(SheetContent, { side: defaultSide, className: "text-foreground z-50 w-4/5 max-w-sm space-y-2" }, /*#__PURE__*/ React__default.createElement(SheetHeader, { className: "px-1 text-left" }, /*#__PURE__*/ React__default.createElement(SheetTitle, null, title)), /*#__PURE__*/ React__default.createElement(Form, form, /*#__PURE__*/ React__default.createElement("form", { onSubmit: form.handleSubmit(handleApplyFilters), className: "flex h-full flex-col gap-6 py-2 pb-6 2xl:justify-start" }, /*#__PURE__*/ React__default.createElement(ScrollArea, { className: "max-h-[64vh] space-y-4 pr-2" }, /*#__PURE__*/ React__default.createElement("div", { className: "space-y-4 pb-2" }, fieldConfigs.map(({ name, label, placeholder, type, allowNegative, isCurrency, isPercent, options, style, items, description, currency })=>/*#__PURE__*/ React__default.createElement(FormField, { key: String(name), control: form.control, name: name, render: ({ field })=>/*#__PURE__*/ React__default.createElement(FormItem, { className: "pr-4 pl-1" }, /*#__PURE__*/ React__default.createElement(FormLabel, null, label), /*#__PURE__*/ React__default.createElement(FormControl, null, type === "number" ? /*#__PURE__*/ React__default.createElement(NumericFormat, { placeholder: placeholder, // biome-ignore lint/suspicious/noExplicitAny: <any> value: field.value ?? "", maxLength: isCurrency ? undefined : 15, allowNegative: allowNegative ?? true, allowLeadingZeros: false, decimalScale: isCurrency ? 2 : undefined, onValueChange: (values)=>{ const numericValue = values.floatValue ?? null; field.onChange(numericValue); }, className: styleInput, fixedDecimalScale: !!isCurrency, decimalSeparator: ",", thousandSeparator: ".", suffix: isPercent ? "%" : undefined, prefix: currency === "BRL" ? "R$ " : undefined }) : type === "date" ? /*#__PURE__*/ React__default.createElement(Popover, null, /*#__PURE__*/ React__default.createElement(PopoverTrigger, { asChild: true }, /*#__PURE__*/ React__default.createElement(FormControl, null, /*#__PURE__*/ React__default.createElement(Button, { variant: "outline", className: cn("text-foreground hover:text-foreground w-full items-center justify-start px-3 text-left font-normal hover:bg-inherit", !field.value && "text-muted-foreground hover:text-muted-foreground") }, /*#__PURE__*/ React__default.createElement(CalendarDays, { className: "h-4 w-4" }), field.value ? formatDateToBrazilian(field.value) : /*#__PURE__*/ React__default.createElement("span", null, "Selecione uma data")))), /*#__PURE__*/ React__default.createElement(PopoverContent, { className: "border-switch z-99999999999 mr-12 w-auto p-0" }, /*#__PURE__*/ React__default.createElement(Calendar, { captionLayout: "dropdown", mode: "single", locale: ptBR, selected: field.value ? parseFieldDate(field.value) : undefined, onSelect: (date)=>{ field.onChange(date ? format(date, "yyyy-MM-dd") : ""); } }))) : type === "checkbox" && options ? /*#__PURE__*/ React__default.createElement("div", { className: "flex flex-wrap items-center gap-2" }, options.map((option)=>/*#__PURE__*/ React__default.createElement(FormControl, { key: option.value, className: cn("mt-2", style === "badge" && "flex-1/4") }, /*#__PURE__*/ React__default.createElement(Label, null, /*#__PURE__*/ React__default.createElement(Checkbox, { checked: Array.isArray(field.value) && field.value.includes(option.value), onCheckedChange: (checked)=>{ const isChecked = !!checked; const currentValue = Array.isArray(field.value) ? field.value : []; const newValue = isChecked ? [ ...currentValue, option.value ] : currentValue.filter((v)=>v !== option.value); field.onChange(newValue); }, className: cn("border-destructive size-4 border", style === "badge" && "sr-only") }), style === "badge" ? /*#__PURE__*/ React__default.createElement(Badge, { variant: Array.isArray(field.value) && field.value.includes(option.value) ? "default" : "secondary", className: cn("flex cursor-pointer gap-2 rounded-md px-4 py-2 text-sm") }, option.icon, option.label) : option.label))), /*#__PURE__*/ React__default.createElement(Separator, { className: "mt-4" })) : type === "cnpj" ? /*#__PURE__*/ React__default.createElement(PatternFormat, { ...field, format: "##.###.###/####-##", mask: "_", placeholder: placeholder, className: styleInput, value: Array.isArray(field.value) ? field.value[0] ?? "" : String(field.value ?? ""), onValueChange: (values)=>{ const unformattedValue = values.value?.replace(/\D/g, ""); field.onChange(unformattedValue); } }) : type === "dateRange" ? /*#__PURE__*/ React__default.createElement(FormField, { key: field.name, control: form.control, name: field.name, render: ({ field: controller })=>/*#__PURE__*/ React__default.createElement(CalendarRange, { value: field.value, onChange: controller.onChange, placeholder: placeholder, popoverContentClassName: "z-[99999999999]", className: "h-10 w-full" }) }) : type === "select" && items ? /*#__PURE__*/ React__default.createElement(ComboboxField, { // biome-ignore lint/suspicious/noExplicitAny: <any> value: field.value ?? [], onChange: (val)=>field.onChange(val), items: items, placeholder: placeholder, className: cn(styleInput, "text-muted-foreground hover:text-muted-foreground"), classNamePopover: "z-[99999999999]" }) : type === "numeric_range" ? /*#__PURE__*/ React__default.createElement("div", { className: "space-y-2" }, /*#__PURE__*/ React__default.createElement("div", { className: "flex gap-2" }, /*#__PURE__*/ React__default.createElement(Select, { value: field.value?.operator || "eq", onValueChange: (operator)=>{ field.onChange({ ...field.value || { operator: "eq", value: null }, operator: operator }); } }, /*#__PURE__*/ React__default.createElement(SelectTrigger, { className: "w-24 cursor-pointer" }, /*#__PURE__*/ React__default.createElement(SelectValue, null)), /*#__PURE__*/ React__default.createElement(SelectContent, null, /*#__PURE__*/ React__default.createElement(SelectItem, { value: "eq", className: styleSelect }, "="), /*#__PURE__*/ React__default.createElement(SelectItem, { value: "gt", className: styleSelect }, ">"), /*#__PURE__*/ React__default.createElement(SelectItem, { value: "lt", className: styleSelect }, "<"), /*#__PURE__*/ React__default.createElement(SelectItem, { value: "gte", className: styleSelect }, ">="), /*#__PURE__*/ React__default.createElement(SelectItem, { value: "lte", className: styleSelect }, "<="))), /*#__PURE__*/ React__default.createElement(NumericFormat, { placeholder: placeholder, value: field.value?.value ?? "", maxLength: isCurrency ? undefined : 25, allowNegative: allowNegative ?? true, allowLeadingZeros: false, decimalScale: isCurrency ? 20 : 20, onValueChange: (values)=>{ const numericValue = values.floatValue ?? null; field.onChange({ ...field.value || { operator: "eq", value: null }, value: numericValue }); }, className: styleInput, fixedDecimalScale: false, decimalSeparator: ",", thousandSeparator: ".", suffix: isPercent ? "%" : undefined, prefix: currency === "BRL" ? "R$ " : undefined }))) : type === "multiselect" && options ? /*#__PURE__*/ React__default.createElement(MultiSelect, { key: `${String(name)}-clear-${clearTrigger}`, options: options.map((opt)=>({ label: String(opt.label), value: String(opt.value) })), defaultValue: Array.isArray(field.value) ? field.value : [], onValueChange: (val)=>{ field.onChange(val); }, placeholder: placeholder, variant: badgeMultiselectVariant, subtle: badgeMultiselectSubtle }) : /*#__PURE__*/ React__default.createElement(Input, { ...field, value: field.value ?? "", placeholder: placeholder, className: "bg-background", onChange: (e)=>{ const value = e.target.value || null; field.onChange(value); } })), description && /*#__PURE__*/ React__default.createElement(FormDescription, null, description), /*#__PURE__*/ React__default.createElement(FormMessage, null)) })))), /*#__PURE__*/ React__default.createElement(SheetFooter, { className: "flex w-full flex-wrap gap-2" }, /*#__PURE__*/ React__default.createElement(SheetClose, { asChild: true }, /*#__PURE__*/ React__default.createElement(Button, { className: "bg-primary w-full text-white", type: "submit" }, "Aplicar Filtros")), /*#__PURE__*/ React__default.createElement(Button, { type: "button", variant: "secondary", className: "mt-2 w-full", onClick: handleCleanFilters }, "Limpar Filtros")))))); } export { TableFilter }; //# sourceMappingURL=index.mjs.map