ivt
Version:
Ivt Components Library
579 lines (573 loc) • 27.9 kB
JavaScript
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