nest-filter 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,11 @@
1
+ import { FilterGroup, ColumnDefinition } from "../types";
2
+ interface AdvancedFilterProps<T> {
3
+ isOpen: boolean;
4
+ onClose: () => void;
5
+ data: T[];
6
+ columns: ColumnDefinition<T>[];
7
+ setFilteredData: (data: T[]) => void;
8
+ initialFilters?: FilterGroup<T>;
9
+ }
10
+ export declare const AdvancedFilter: <T>({ isOpen, onClose, data, columns, setFilteredData, initialFilters, }: AdvancedFilterProps<T>) => import("react/jsx-runtime").JSX.Element;
11
+ export {};
@@ -0,0 +1,163 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useState, useEffect, useCallback } from 'react';
3
+ import { Button } from './ui/Button.js';
4
+ import { Input } from './ui/Input.js';
5
+ import { Select } from './ui/Select.js';
6
+ import { Dialog } from './ui/Dialog.js';
7
+ import { FilterX, Plus, Layers, Trash2, Binary, ListFilter } from 'lucide-react';
8
+ import { applyFilters } from '../utils/filterLogic.js';
9
+
10
+ const getOperatorsForType = (type) => {
11
+ switch (type) {
12
+ case "string":
13
+ return [
14
+ { value: "contains", label: "Contains" },
15
+ { value: "not_contains", label: "Does not contain" },
16
+ { value: "equals", label: "Exact match" },
17
+ ];
18
+ case "select":
19
+ return [
20
+ { value: "equals", label: "Is" },
21
+ { value: "not_equals", label: "Is not" },
22
+ ];
23
+ case "number":
24
+ return [
25
+ { value: "equals", label: "=" },
26
+ { value: "not_equals", label: "!=" },
27
+ { value: "gt", label: ">" },
28
+ { value: "lt", label: "<" },
29
+ { value: "gte", label: ">=" },
30
+ { value: "lte", label: "<=" },
31
+ ];
32
+ case "date":
33
+ return [
34
+ { value: "is", label: "On date" },
35
+ { value: "before", label: "Before" },
36
+ { value: "after", label: "After" },
37
+ ];
38
+ case "boolean":
39
+ return [
40
+ { value: "true", label: "True" },
41
+ { value: "false", label: "False" },
42
+ ];
43
+ default:
44
+ return [];
45
+ }
46
+ };
47
+ const FilterGroupUI = ({ group, depth, columns, onAddRule, onAddGroup, onUpdateRule, onUpdateGroupLogic, onRemoveItem, }) => {
48
+ return (jsxs("div", { className: `rounded-lg border border-slate-200 bg-slate-50/50 p-4 mb-4 ${depth > 0 ? "ml-6 md:ml-10 relative border-l-2 border-l-slate-300" : ""}`, children: [jsxs("div", { className: "flex flex-wrap items-center justify-between gap-4 mb-4", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: "text-[10px] font-bold uppercase tracking-widest text-slate-500", children: "Group Logic" }), jsxs("div", { className: "flex rounded-md border border-slate-200 bg-white p-1 shadow-sm", children: [jsx("button", { onClick: () => onUpdateGroupLogic(group.id, "AND"), className: `px-3 py-1 text-[10px] font-black rounded-sm transition-all ${group.logic === "AND"
49
+ ? "bg-slate-900 text-slate-50"
50
+ : "text-slate-500 hover:text-slate-900"}`, children: "AND" }), jsx("button", { onClick: () => onUpdateGroupLogic(group.id, "OR"), className: `px-3 py-1 text-[10px] font-black rounded-sm transition-all ${group.logic === "OR"
51
+ ? "bg-slate-900 text-slate-50"
52
+ : "text-slate-500 hover:text-slate-900"}`, children: "OR" })] })] }), jsxs("div", { className: "flex items-center gap-2", children: [jsxs(Button, { variant: "outline", size: "sm", onClick: () => onAddRule(group.id), className: "h-7 text-[10px] font-bold uppercase", children: [jsx(Plus, { className: "mr-1 h-3 w-3" }), " Rule"] }), jsxs(Button, { variant: "outline", size: "sm", onClick: () => onAddGroup(group.id), className: "h-7 text-[10px] font-bold uppercase", children: [jsx(Layers, { className: "mr-1 h-3 w-3" }), " Group"] }), depth > 0 && (jsx(Button, { variant: "ghost", size: "sm", onClick: () => onRemoveItem(group.id), className: "text-slate-400", children: jsx(Trash2, { className: "h-5 w-5 text-red-500" }) }))] })] }), jsxs("div", { className: "space-y-3", children: [group.items.map((item) => {
53
+ const column = columns.find((c) => c.id === (item.type === "rule" ? item.columnId : null));
54
+ return item.type === "rule" ? (jsxs("div", { className: "flex flex-col md:flex-row md:items-center gap-3 p-3 bg-white border border-slate-200 rounded-md shadow-sm", children: [jsx("div", { className: "flex-1 min-w-[140px]", children: jsx(Select, { value: item.columnId, options: columns.map((c) => ({
55
+ value: c.id,
56
+ label: c.label,
57
+ })), onValueChange: (val) => {
58
+ const colId = val;
59
+ const col = columns.find((c) => c.id === colId);
60
+ onUpdateRule(item.id, {
61
+ columnId: colId,
62
+ operator: col?.type === "date"
63
+ ? "is"
64
+ : col?.type === "number"
65
+ ? "equals"
66
+ : col?.type === "select"
67
+ ? "equals"
68
+ : "contains",
69
+ value: "",
70
+ });
71
+ } }) }), jsx("div", { className: "w-full md:w-44", children: jsx(Select, { value: item.operator, options: getOperatorsForType(column?.type || "string"), onValueChange: (val) => onUpdateRule(item.id, { operator: val }) }) }), jsx("div", { className: "flex-[1.5] min-w-[180px]", children: column?.type === "date" ? (jsx(Input, { type: "date", value: item.value || "", onChange: (e) => onUpdateRule(item.id, { value: e.target.value }) })) : column?.type === "boolean" ? (jsxs("div", { className: "h-10 flex items-center px-3 border border-slate-200 rounded-md bg-slate-50 text-[10px] font-black uppercase tracking-tighter text-slate-400 italic", children: [jsx(Binary, { className: "h-3 w-3 mr-2" }), "Binary state"] })) : column?.type === "select" ? (jsx(Select, { value: item.value || "", placeholder: "Choose option...", options: (column.options || []).map((opt) => ({
72
+ value: opt,
73
+ label: opt,
74
+ })), onValueChange: (val) => onUpdateRule(item.id, { value: val }) })) : (jsx(Input, { placeholder: "Search query...", value: item.value || "", onChange: (e) => onUpdateRule(item.id, { value: e.target.value }) })) }), jsx(Button, { variant: "ghost", size: "icon", onClick: () => onRemoveItem(item.id), className: "h-9 w-9 text-slate-300 hover:text-red-500 hover:bg-red-50", children: jsx(Trash2, { className: "h-5 w-5 text-red-500" }) })] }, item.id)) : (jsx(FilterGroupUI, { group: item, depth: depth + 1, columns: columns, onAddRule: onAddRule, onAddGroup: onAddGroup, onUpdateRule: onUpdateRule, onUpdateGroupLogic: onUpdateGroupLogic, onRemoveItem: onRemoveItem }));
75
+ }), group.items.length === 0 && (jsxs("div", { className: "flex flex-col items-center justify-center py-6 rounded-md border border-dashed border-slate-200 bg-white/50", children: [jsx(ListFilter, { className: "h-5 w-5 text-slate-300 mb-1" }), jsx("p", { className: "text-[10px] text-slate-400 font-bold uppercase tracking-widest", children: "Add a rule to filter" })] }))] })] }));
76
+ };
77
+ const AdvancedFilter = ({ isOpen, onClose, data, columns, setFilteredData, initialFilters, }) => {
78
+ const [rootGroup, setRootGroup] = useState({
79
+ type: "group",
80
+ id: "root",
81
+ logic: "AND",
82
+ items: [],
83
+ });
84
+ useEffect(() => {
85
+ if (initialFilters)
86
+ setRootGroup(initialFilters);
87
+ }, [initialFilters, isOpen]);
88
+ const updateItemRecursively = useCallback((group, targetId, updater) => {
89
+ if (group.id === targetId)
90
+ return updater(group);
91
+ return {
92
+ ...group,
93
+ items: group.items
94
+ .map((item) => {
95
+ if (item.id === targetId)
96
+ return updater(item);
97
+ if (item.type === "group")
98
+ return updateItemRecursively(item, targetId, updater);
99
+ return item;
100
+ })
101
+ .filter(Boolean),
102
+ };
103
+ }, []);
104
+ const handleAddRule = useCallback((parentId) => {
105
+ const firstCol = columns[0];
106
+ const newRule = {
107
+ type: "rule",
108
+ id: Math.random().toString(36).substr(2, 9),
109
+ columnId: firstCol.id,
110
+ operator: firstCol.type === "string"
111
+ ? "contains"
112
+ : firstCol.type === "select"
113
+ ? "equals"
114
+ : "equals",
115
+ value: "",
116
+ };
117
+ setRootGroup((prev) => updateItemRecursively(prev, parentId, (group) => ({
118
+ ...group,
119
+ items: [...group.items, newRule],
120
+ })));
121
+ }, [columns, updateItemRecursively]);
122
+ const handleAddGroup = useCallback((parentId) => {
123
+ const newGroup = {
124
+ type: "group",
125
+ id: Math.random().toString(36).substr(2, 9),
126
+ logic: "AND",
127
+ items: [],
128
+ };
129
+ setRootGroup((prev) => updateItemRecursively(prev, parentId, (group) => ({
130
+ ...group,
131
+ items: [...group.items, newGroup],
132
+ })));
133
+ }, [updateItemRecursively]);
134
+ const handleUpdateRule = useCallback((ruleId, updates) => {
135
+ setRootGroup((prev) => updateItemRecursively(prev, ruleId, (rule) => ({ ...rule, ...updates })));
136
+ }, [updateItemRecursively]);
137
+ const handleUpdateGroupLogic = useCallback((groupId, logic) => {
138
+ setRootGroup((prev) => updateItemRecursively(prev, groupId, (group) => ({ ...group, logic })));
139
+ }, [updateItemRecursively]);
140
+ const handleRemoveItem = useCallback((itemId) => {
141
+ setRootGroup((prev) => updateItemRecursively(prev, itemId, () => null));
142
+ }, [updateItemRecursively]);
143
+ const handleApply = () => {
144
+ const filtered = applyFilters(data, rootGroup, columns);
145
+ setFilteredData(filtered);
146
+ onClose();
147
+ };
148
+ const handleClear = () => {
149
+ const emptyGroup = {
150
+ type: "group",
151
+ id: "root",
152
+ logic: "AND",
153
+ items: [],
154
+ };
155
+ setRootGroup(emptyGroup);
156
+ setFilteredData(data);
157
+ onClose();
158
+ };
159
+ return (jsxs(Dialog, { open: isOpen, onOpenChange: onClose, title: "Advanced Filters", description: "Refine your dataset using structured logic and multi-type comparisons.", children: [jsx("div", { className: "max-h-[60vh] overflow-y-auto px-1 custom-scrollbar pr-3 pb-32", children: jsx(FilterGroupUI, { group: rootGroup, depth: 0, columns: columns, onAddRule: handleAddRule, onAddGroup: handleAddGroup, onUpdateRule: handleUpdateRule, onUpdateGroupLogic: handleUpdateGroupLogic, onRemoveItem: handleRemoveItem }) }), jsxs("div", { className: "flex w-full justify-between items-center gap-4", children: [jsxs(Button, { variant: "ghost", onClick: handleClear, className: "text-slate-400 hover:text-red-500 font-black text-[10px] uppercase tracking-widest gap-2", children: [jsx(FilterX, { className: "h-4 w-4" }), " Reset Filters"] }), jsxs("div", { className: "flex gap-2", children: [jsx(Button, { variant: "outline", onClick: onClose, className: "font-bold h-11 px-6", children: "Cancel" }), jsx(Button, { onClick: handleApply, className: "bg-slate-900 font-bold h-11 px-10 rounded-lg shadow-lg hover:shadow-xl transition-shadow", children: "Apply View" })] })] })] }));
160
+ };
161
+
162
+ export { AdvancedFilter };
163
+ //# sourceMappingURL=AdvancedFilter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AdvancedFilter.js","sources":["../../src/components/AdvancedFilter.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { useState, useEffect, useCallback } from \"react\";\nimport {\n FilterRule,\n FilterGroup,\n ColumnDefinition,\n LogicalOperator,\n FilterOperator,\n FilterItem,\n} from \"../types\";\nimport { Button } from \"./ui/Button\";\nimport { Input } from \"./ui/Input\";\nimport { Select } from \"./ui/Select\";\nimport { Dialog } from \"./ui/Dialog\";\nimport {\n Plus,\n Trash2,\n Layers,\n Binary,\n FilterX,\n ListFilter,\n} from \"lucide-react\";\nimport { applyFilters } from \"../utils/filterLogic\";\n\ninterface AdvancedFilterProps<T> {\n isOpen: boolean;\n onClose: () => void;\n data: T[];\n columns: ColumnDefinition<T>[];\n setFilteredData: (data: T[]) => void;\n initialFilters?: FilterGroup<T>;\n}\n\nconst getOperatorsForType = (\n type: string\n): { value: FilterOperator; label: string }[] => {\n switch (type) {\n case \"string\":\n return [\n { value: \"contains\", label: \"Contains\" },\n { value: \"not_contains\", label: \"Does not contain\" },\n { value: \"equals\", label: \"Exact match\" },\n ];\n case \"select\":\n return [\n { value: \"equals\", label: \"Is\" },\n { value: \"not_equals\", label: \"Is not\" },\n ];\n case \"number\":\n return [\n { value: \"equals\", label: \"=\" },\n { value: \"not_equals\", label: \"!=\" },\n { value: \"gt\", label: \">\" },\n { value: \"lt\", label: \"<\" },\n { value: \"gte\", label: \">=\" },\n { value: \"lte\", label: \"<=\" },\n ];\n case \"date\":\n return [\n { value: \"is\", label: \"On date\" },\n { value: \"before\", label: \"Before\" },\n { value: \"after\", label: \"After\" },\n ];\n case \"boolean\":\n return [\n { value: \"true\", label: \"True\" },\n { value: \"false\", label: \"False\" },\n ];\n default:\n return [];\n }\n};\n\nconst FilterGroupUI = <T,>({\n group,\n depth,\n columns,\n onAddRule,\n onAddGroup,\n onUpdateRule,\n onUpdateGroupLogic,\n onRemoveItem,\n}: {\n group: FilterGroup<T>;\n depth: number;\n columns: ColumnDefinition<T>[];\n onAddRule: (parentId: string) => void;\n onAddGroup: (parentId: string) => void;\n onUpdateRule: (ruleId: string, updates: Partial<FilterRule<T>>) => void;\n onUpdateGroupLogic: (groupId: string, logic: LogicalOperator) => void;\n onRemoveItem: (itemId: string) => void;\n}) => {\n return (\n <div\n className={`rounded-lg border border-slate-200 bg-slate-50/50 p-4 mb-4 ${\n depth > 0 ? \"ml-6 md:ml-10 relative border-l-2 border-l-slate-300\" : \"\"\n }`}\n >\n <div className=\"flex flex-wrap items-center justify-between gap-4 mb-4\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-[10px] font-bold uppercase tracking-widest text-slate-500\">\n Group Logic\n </span>\n <div className=\"flex rounded-md border border-slate-200 bg-white p-1 shadow-sm\">\n <button\n onClick={() => onUpdateGroupLogic(group.id, \"AND\")}\n className={`px-3 py-1 text-[10px] font-black rounded-sm transition-all ${\n group.logic === \"AND\"\n ? \"bg-slate-900 text-slate-50\"\n : \"text-slate-500 hover:text-slate-900\"\n }`}\n >\n AND\n </button>\n <button\n onClick={() => onUpdateGroupLogic(group.id, \"OR\")}\n className={`px-3 py-1 text-[10px] font-black rounded-sm transition-all ${\n group.logic === \"OR\"\n ? \"bg-slate-900 text-slate-50\"\n : \"text-slate-500 hover:text-slate-900\"\n }`}\n >\n OR\n </button>\n </div>\n </div>\n\n <div className=\"flex items-center gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => onAddRule(group.id)}\n className=\"h-7 text-[10px] font-bold uppercase\"\n >\n <Plus className=\"mr-1 h-3 w-3\" /> Rule\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => onAddGroup(group.id)}\n className=\"h-7 text-[10px] font-bold uppercase\"\n >\n <Layers className=\"mr-1 h-3 w-3\" /> Group\n </Button>\n {depth > 0 && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => onRemoveItem(group.id)}\n className=\"text-slate-400\"\n >\n <Trash2 className=\"h-5 w-5 text-red-500\" />\n </Button>\n )}\n </div>\n </div>\n\n <div className=\"space-y-3\">\n {group.items.map((item) => {\n const column = columns.find(\n (c) => c.id === (item.type === \"rule\" ? item.columnId : null)\n );\n return item.type === \"rule\" ? (\n <div\n key={item.id}\n className=\"flex flex-col md:flex-row md:items-center gap-3 p-3 bg-white border border-slate-200 rounded-md shadow-sm\"\n >\n <div className=\"flex-1 min-w-[140px]\">\n <Select\n value={item.columnId as string}\n options={columns.map((c) => ({\n value: c.id as string,\n label: c.label,\n }))}\n onValueChange={(val) => {\n const colId = val as keyof T;\n const col = columns.find((c) => c.id === colId);\n onUpdateRule(item.id, {\n columnId: colId,\n operator:\n col?.type === \"date\"\n ? \"is\"\n : col?.type === \"number\"\n ? \"equals\"\n : col?.type === \"select\"\n ? \"equals\"\n : \"contains\",\n value: \"\",\n });\n }}\n />\n </div>\n <div className=\"w-full md:w-44\">\n <Select\n value={item.operator}\n options={getOperatorsForType(column?.type || \"string\")}\n onValueChange={(val) =>\n onUpdateRule(item.id, { operator: val as FilterOperator })\n }\n />\n </div>\n <div className=\"flex-[1.5] min-w-[180px]\">\n {column?.type === \"date\" ? (\n <Input\n type=\"date\"\n value={item.value || \"\"}\n onChange={(e) =>\n onUpdateRule(item.id, { value: e.target.value })\n }\n />\n ) : column?.type === \"boolean\" ? (\n <div className=\"h-10 flex items-center px-3 border border-slate-200 rounded-md bg-slate-50 text-[10px] font-black uppercase tracking-tighter text-slate-400 italic\">\n <Binary className=\"h-3 w-3 mr-2\" />\n Binary state\n </div>\n ) : column?.type === \"select\" ? (\n <Select\n value={item.value || \"\"}\n placeholder=\"Choose option...\"\n options={(column.options || []).map((opt) => ({\n value: opt,\n label: opt,\n }))}\n onValueChange={(val) =>\n onUpdateRule(item.id, { value: val })\n }\n />\n ) : (\n <Input\n placeholder=\"Search query...\"\n value={item.value || \"\"}\n onChange={(e) =>\n onUpdateRule(item.id, { value: e.target.value })\n }\n />\n )}\n </div>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => onRemoveItem(item.id)}\n className=\"h-9 w-9 text-slate-300 hover:text-red-500 hover:bg-red-50\"\n >\n <Trash2 className=\"h-5 w-5 text-red-500\" />\n </Button>\n </div>\n ) : (\n <FilterGroupUI\n group={item}\n depth={depth + 1}\n columns={columns}\n onAddRule={onAddRule}\n onAddGroup={onAddGroup}\n onUpdateRule={onUpdateRule}\n onUpdateGroupLogic={onUpdateGroupLogic}\n onRemoveItem={onRemoveItem}\n />\n );\n })}\n {group.items.length === 0 && (\n <div className=\"flex flex-col items-center justify-center py-6 rounded-md border border-dashed border-slate-200 bg-white/50\">\n <ListFilter className=\"h-5 w-5 text-slate-300 mb-1\" />\n <p className=\"text-[10px] text-slate-400 font-bold uppercase tracking-widest\">\n Add a rule to filter\n </p>\n </div>\n )}\n </div>\n </div>\n );\n};\n\nexport const AdvancedFilter = <T,>({\n isOpen,\n onClose,\n data,\n columns,\n setFilteredData,\n initialFilters,\n}: AdvancedFilterProps<T>) => {\n const [rootGroup, setRootGroup] = useState<FilterGroup<T>>({\n type: \"group\",\n id: \"root\",\n logic: \"AND\",\n items: [],\n });\n\n useEffect(() => {\n if (initialFilters) setRootGroup(initialFilters);\n }, [initialFilters, isOpen]);\n\n const updateItemRecursively = useCallback(\n (\n group: FilterGroup<T>,\n targetId: string,\n updater: (item: FilterItem<T>) => FilterItem<T> | null\n ): FilterGroup<T> => {\n if (group.id === targetId) return updater(group) as FilterGroup<T>;\n return {\n ...group,\n items: group.items\n .map((item) => {\n if (item.id === targetId) return updater(item);\n if (item.type === \"group\")\n return updateItemRecursively(item, targetId, updater);\n return item;\n })\n .filter(Boolean) as FilterItem<T>[],\n };\n },\n []\n );\n\n const handleAddRule = useCallback(\n (parentId: string) => {\n const firstCol = columns[0];\n const newRule: FilterRule<T> = {\n type: \"rule\",\n id: Math.random().toString(36).substr(2, 9),\n columnId: firstCol.id,\n operator:\n firstCol.type === \"string\"\n ? \"contains\"\n : firstCol.type === \"select\"\n ? \"equals\"\n : \"equals\",\n value: \"\",\n };\n setRootGroup((prev) =>\n updateItemRecursively(prev, parentId, (group) => ({\n ...(group as FilterGroup<T>),\n items: [...(group as FilterGroup<T>).items, newRule],\n }))\n );\n },\n [columns, updateItemRecursively]\n );\n\n const handleAddGroup = useCallback(\n (parentId: string) => {\n const newGroup: FilterGroup<T> = {\n type: \"group\",\n id: Math.random().toString(36).substr(2, 9),\n logic: \"AND\",\n items: [],\n };\n setRootGroup((prev) =>\n updateItemRecursively(prev, parentId, (group) => ({\n ...(group as FilterGroup<T>),\n items: [...(group as FilterGroup<T>).items, newGroup],\n }))\n );\n },\n [updateItemRecursively]\n );\n\n const handleUpdateRule = useCallback(\n (ruleId: string, updates: Partial<FilterRule<T>>) => {\n setRootGroup((prev) =>\n updateItemRecursively(\n prev,\n ruleId,\n (rule) => ({ ...rule, ...updates } as FilterRule<T>)\n )\n );\n },\n [updateItemRecursively]\n );\n\n const handleUpdateGroupLogic = useCallback(\n (groupId: string, logic: LogicalOperator) => {\n setRootGroup((prev) =>\n updateItemRecursively(\n prev,\n groupId,\n (group) => ({ ...group, logic } as FilterGroup<T>)\n )\n );\n },\n [updateItemRecursively]\n );\n\n const handleRemoveItem = useCallback(\n (itemId: string) => {\n setRootGroup((prev) => updateItemRecursively(prev, itemId, () => null));\n },\n [updateItemRecursively]\n );\n\n const handleApply = () => {\n const filtered = applyFilters(data, rootGroup, columns);\n setFilteredData(filtered);\n onClose();\n };\n\n const handleClear = () => {\n const emptyGroup: FilterGroup<T> = {\n type: \"group\",\n id: \"root\",\n logic: \"AND\",\n items: [],\n };\n setRootGroup(emptyGroup);\n setFilteredData(data);\n onClose();\n };\n\n return (\n <Dialog\n open={isOpen}\n onOpenChange={onClose}\n title=\"Advanced Filters\"\n description=\"Refine your dataset using structured logic and multi-type comparisons.\"\n >\n <div className=\"max-h-[60vh] overflow-y-auto px-1 custom-scrollbar pr-3 pb-32\">\n <FilterGroupUI\n group={rootGroup}\n depth={0}\n columns={columns}\n onAddRule={handleAddRule}\n onAddGroup={handleAddGroup}\n onUpdateRule={handleUpdateRule}\n onUpdateGroupLogic={handleUpdateGroupLogic}\n onRemoveItem={handleRemoveItem}\n />\n </div>\n <div className=\"flex w-full justify-between items-center gap-4\">\n <Button\n variant=\"ghost\"\n onClick={handleClear}\n className=\"text-slate-400 hover:text-red-500 font-black text-[10px] uppercase tracking-widest gap-2\"\n >\n <FilterX className=\"h-4 w-4\" /> Reset Filters\n </Button>\n <div className=\"flex gap-2\">\n <Button\n variant=\"outline\"\n onClick={onClose}\n className=\"font-bold h-11 px-6\"\n >\n Cancel\n </Button>\n <Button\n onClick={handleApply}\n className=\"bg-slate-900 font-bold h-11 px-10 rounded-lg shadow-lg hover:shadow-xl transition-shadow\"\n >\n Apply View\n </Button>\n </div>\n </div>\n </Dialog>\n );\n};\n"],"names":["_jsxs","_jsx"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
3
+ variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link';
4
+ size?: 'default' | 'sm' | 'lg' | 'icon';
5
+ }
6
+ export declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
7
+ export {};
@@ -0,0 +1,24 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import React from 'react';
3
+
4
+ const Button = React.forwardRef(({ className = '', variant = 'default', size = 'default', ...props }, ref) => {
5
+ const baseStyles = 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-950 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50';
6
+ const variants = {
7
+ default: 'bg-slate-900 text-slate-50 hover:bg-slate-900/90',
8
+ destructive: 'bg-red-500 text-slate-50 hover:bg-red-500/90',
9
+ outline: 'border border-slate-200 bg-white hover:bg-slate-100 hover:text-slate-900',
10
+ secondary: 'bg-slate-100 text-slate-900 hover:bg-slate-100/80',
11
+ ghost: 'hover:bg-slate-100 hover:text-slate-900',
12
+ link: 'text-slate-900 underline-offset-4 hover:underline',
13
+ };
14
+ const sizes = {
15
+ default: 'h-10 px-4 py-2',
16
+ sm: 'h-9 rounded-md px-3',
17
+ lg: 'h-11 rounded-md px-8',
18
+ icon: 'h-10 w-10',
19
+ };
20
+ return (jsx("button", { ref: ref, className: `${baseStyles} ${variants[variant]} ${sizes[size]} ${className}`, ...props }));
21
+ });
22
+
23
+ export { Button };
24
+ //# sourceMappingURL=Button.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Button.js","sources":["../../../src/components/ui/Button.tsx"],"sourcesContent":["\nimport React from 'react';\n\ninterface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link';\n size?: 'default' | 'sm' | 'lg' | 'icon';\n}\n\nexport const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className = '', variant = 'default', size = 'default', ...props }, ref) => {\n const baseStyles = 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-950 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50';\n \n const variants = {\n default: 'bg-slate-900 text-slate-50 hover:bg-slate-900/90',\n destructive: 'bg-red-500 text-slate-50 hover:bg-red-500/90',\n outline: 'border border-slate-200 bg-white hover:bg-slate-100 hover:text-slate-900',\n secondary: 'bg-slate-100 text-slate-900 hover:bg-slate-100/80',\n ghost: 'hover:bg-slate-100 hover:text-slate-900',\n link: 'text-slate-900 underline-offset-4 hover:underline',\n };\n\n const sizes = {\n default: 'h-10 px-4 py-2',\n sm: 'h-9 rounded-md px-3',\n lg: 'h-11 rounded-md px-8',\n icon: 'h-10 w-10',\n };\n\n return (\n <button\n ref={ref}\n className={`${baseStyles} ${variants[variant]} ${sizes[size]} ${className}`}\n {...props}\n />\n );\n }\n);\n"],"names":["_jsx"],"mappings":";;;AAQO,MAAM,MAAM,GAAG,KAAK,CAAC,UAAU,CACpC,CAAC,EAAE,SAAS,GAAG,EAAE,EAAE,OAAO,GAAG,SAAS,EAAE,IAAI,GAAG,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,GAAG,KAAI;IAC3E,MAAM,UAAU,GAAG,wRAAwR;AAE3S,IAAA,MAAM,QAAQ,GAAG;AACf,QAAA,OAAO,EAAE,kDAAkD;AAC3D,QAAA,WAAW,EAAE,8CAA8C;AAC3D,QAAA,OAAO,EAAE,0EAA0E;AACnF,QAAA,SAAS,EAAE,mDAAmD;AAC9D,QAAA,KAAK,EAAE,yCAAyC;AAChD,QAAA,IAAI,EAAE,mDAAmD;KAC1D;AAED,IAAA,MAAM,KAAK,GAAG;AACZ,QAAA,OAAO,EAAE,gBAAgB;AACzB,QAAA,EAAE,EAAE,qBAAqB;AACzB,QAAA,EAAE,EAAE,sBAAsB;AAC1B,QAAA,IAAI,EAAE,WAAW;KAClB;IAED,QACEA,GAAA,CAAA,QAAA,EAAA,EACE,GAAG,EAAE,GAAG,EACR,SAAS,EAAE,CAAA,EAAG,UAAU,CAAA,CAAA,EAAI,QAAQ,CAAC,OAAO,CAAC,CAAA,CAAA,EAAI,KAAK,CAAC,IAAI,CAAC,CAAA,CAAA,EAAI,SAAS,CAAA,CAAE,EAAA,GACvE,KAAK,EAAA,CACT;AAEN,CAAC;;;;"}
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ interface DialogProps {
3
+ open: boolean;
4
+ onOpenChange: (open: boolean) => void;
5
+ title: string;
6
+ description?: string;
7
+ children: React.ReactNode;
8
+ footer?: React.ReactNode;
9
+ }
10
+ export declare const Dialog: React.FC<DialogProps>;
11
+ export {};
@@ -0,0 +1,11 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { X } from 'lucide-react';
3
+
4
+ const Dialog = ({ open, onOpenChange, title, description, children, footer }) => {
5
+ if (!open)
6
+ return null;
7
+ return (jsx("div", { className: "fixed inset-0 z-50 flex items-start justify-center overflow-y-auto bg-slate-950/80 p-4 pt-[5vh] backdrop-blur-sm animate-in fade-in duration-200", children: jsxs("div", { className: "relative w-full max-w-4xl rounded-lg border border-slate-200 bg-white p-6 shadow-lg animate-in zoom-in-95 duration-200", children: [jsxs("div", { className: "flex flex-col space-y-1.5 text-center sm:text-left mb-6", children: [jsx("h2", { className: "text-lg font-semibold leading-none tracking-tight", children: title }), description && jsx("p", { className: "text-sm text-slate-500", children: description }), jsxs("button", { onClick: () => onOpenChange(false), className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-white transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-slate-950 focus:ring-offset-2 disabled:pointer-events-none", children: [jsx(X, { className: "h-4 w-4" }), jsx("span", { className: "sr-only", children: "Close" })] })] }), jsx("div", { className: "py-2", children: children }), footer && (jsx("div", { className: "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2 mt-6", children: footer }))] }) }));
8
+ };
9
+
10
+ export { Dialog };
11
+ //# sourceMappingURL=Dialog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Dialog.js","sources":["../../../src/components/ui/Dialog.tsx"],"sourcesContent":["\nimport React from 'react';\nimport { X } from 'lucide-react';\n\ninterface DialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n title: string;\n description?: string;\n children: React.ReactNode;\n footer?: React.ReactNode;\n}\n\nexport const Dialog: React.FC<DialogProps> = ({ open, onOpenChange, title, description, children, footer }) => {\n if (!open) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-start justify-center overflow-y-auto bg-slate-950/80 p-4 pt-[5vh] backdrop-blur-sm animate-in fade-in duration-200\">\n <div className=\"relative w-full max-w-4xl rounded-lg border border-slate-200 bg-white p-6 shadow-lg animate-in zoom-in-95 duration-200\">\n <div className=\"flex flex-col space-y-1.5 text-center sm:text-left mb-6\">\n <h2 className=\"text-lg font-semibold leading-none tracking-tight\">{title}</h2>\n {description && <p className=\"text-sm text-slate-500\">{description}</p>}\n <button\n onClick={() => onOpenChange(false)}\n className=\"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-white transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-slate-950 focus:ring-offset-2 disabled:pointer-events-none\"\n >\n <X className=\"h-4 w-4\" />\n <span className=\"sr-only\">Close</span>\n </button>\n </div>\n <div className=\"py-2\">\n {children}\n </div>\n {footer && (\n <div className=\"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2 mt-6\">\n {footer}\n </div>\n )}\n </div>\n </div>\n );\n};\n"],"names":["_jsx","_jsxs"],"mappings":";;;AAaO,MAAM,MAAM,GAA0B,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAI;AAC5G,IAAA,IAAI,CAAC,IAAI;AAAE,QAAA,OAAO,IAAI;AAEtB,IAAA,QACEA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,kJAAkJ,EAAA,QAAA,EAC/JC,cAAK,SAAS,EAAC,wHAAwH,EAAA,QAAA,EAAA,CACrIA,cAAK,SAAS,EAAC,yDAAyD,EAAA,QAAA,EAAA,CACtED,GAAA,CAAA,IAAA,EAAA,EAAI,SAAS,EAAC,mDAAmD,EAAA,QAAA,EAAE,KAAK,GAAM,EAC7E,WAAW,IAAIA,GAAA,CAAA,GAAA,EAAA,EAAG,SAAS,EAAC,wBAAwB,EAAA,QAAA,EAAE,WAAW,EAAA,CAAK,EACvEC,iBACE,OAAO,EAAE,MAAM,YAAY,CAAC,KAAK,CAAC,EAClC,SAAS,EAAC,2MAA2M,aAErND,GAAA,CAAC,CAAC,IAAC,SAAS,EAAC,SAAS,EAAA,CAAG,EACzBA,cAAM,SAAS,EAAC,SAAS,EAAA,QAAA,EAAA,OAAA,EAAA,CAAa,CAAA,EAAA,CAC/B,IACL,EACNA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,MAAM,EAAA,QAAA,EAClB,QAAQ,GACL,EACL,MAAM,KACLA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,oEAAoE,YAChF,MAAM,EAAA,CACH,CACP,CAAA,EAAA,CACG,EAAA,CACF;AAEV;;;;"}
@@ -0,0 +1,2 @@
1
+ import React from 'react';
2
+ export declare const Input: React.ForwardRefExoticComponent<React.InputHTMLAttributes<HTMLInputElement> & React.RefAttributes<HTMLInputElement>>;
@@ -0,0 +1,9 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import React from 'react';
3
+
4
+ const Input = React.forwardRef(({ className = '', type, ...props }, ref) => {
5
+ return (jsx("input", { type: type, className: `flex h-10 w-full rounded-md border border-slate-200 bg-white px-3 py-2 text-sm ring-offset-white file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-slate-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-950 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 ${className}`, ref: ref, ...props }));
6
+ });
7
+
8
+ export { Input };
9
+ //# sourceMappingURL=Input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Input.js","sources":["../../../src/components/ui/Input.tsx"],"sourcesContent":["\nimport React from 'react';\n\nexport const Input = React.forwardRef<HTMLInputElement, React.InputHTMLAttributes<HTMLInputElement>>(\n ({ className = '', type, ...props }, ref) => {\n return (\n <input\n type={type}\n className={`flex h-10 w-full rounded-md border border-slate-200 bg-white px-3 py-2 text-sm ring-offset-white file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-slate-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-950 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 ${className}`}\n ref={ref}\n {...props}\n />\n );\n }\n);\n"],"names":["_jsx"],"mappings":";;;MAGa,KAAK,GAAG,KAAK,CAAC,UAAU,CACnC,CAAC,EAAE,SAAS,GAAG,EAAE,EAAE,IAAI,EAAE,GAAG,KAAK,EAAE,EAAE,GAAG,KAAI;AAC1C,IAAA,QACEA,GAAA,CAAA,OAAA,EAAA,EACE,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,CAAA,qVAAA,EAAwV,SAAS,CAAA,CAAE,EAC9W,GAAG,EAAE,GAAG,KACJ,KAAK,EAAA,CACT;AAEN,CAAC;;;;"}
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ interface SelectProps {
3
+ value: string;
4
+ onValueChange: (value: string) => void;
5
+ options: {
6
+ value: string;
7
+ label: string;
8
+ }[];
9
+ placeholder?: string;
10
+ className?: string;
11
+ }
12
+ export declare const Select: React.FC<SelectProps>;
13
+ export {};
@@ -0,0 +1,24 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useState, useRef, useEffect } from 'react';
3
+ import { ChevronDown, Check } from 'lucide-react';
4
+
5
+ const Select = ({ value, onValueChange, options, placeholder = "Select...", className = "" }) => {
6
+ const [isOpen, setIsOpen] = useState(false);
7
+ const containerRef = useRef(null);
8
+ const selected = options.find(o => o.value === value);
9
+ useEffect(() => {
10
+ const handleOutside = (e) => {
11
+ if (containerRef.current && !containerRef.current.contains(e.target))
12
+ setIsOpen(false);
13
+ };
14
+ document.addEventListener('mousedown', handleOutside);
15
+ return () => document.removeEventListener('mousedown', handleOutside);
16
+ }, []);
17
+ return (jsxs("div", { className: `relative w-full ${className}`, ref: containerRef, style: { zIndex: isOpen ? 60 : 1 }, children: [jsxs("button", { type: "button", onClick: () => setIsOpen(!isOpen), className: "flex h-10 w-full items-center justify-between rounded-md border border-slate-200 bg-white px-3 py-2 text-sm ring-offset-white placeholder:text-slate-500 focus:outline-none focus:ring-2 focus:ring-slate-950 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 transition-colors hover:border-slate-300", children: [jsx("span", { className: "truncate", children: selected ? selected.label : placeholder }), jsx(ChevronDown, { className: `h-4 w-4 opacity-50 transition-transform duration-200 ${isOpen ? 'rotate-180' : ''}` })] }), isOpen && (jsx("div", { className: "absolute top-full left-0 z-50 mt-1 min-w-[8rem] w-full max-h-[200px] overflow-y-auto rounded-md border border-slate-200 bg-white text-slate-950 shadow-xl animate-in fade-in zoom-in-95 duration-100", children: jsx("div", { className: "p-1", children: options.length > 0 ? options.map((opt) => (jsxs("button", { onClick: () => {
18
+ onValueChange(opt.value);
19
+ setIsOpen(false);
20
+ }, className: `relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none hover:bg-slate-100 hover:text-slate-900 transition-colors ${opt.value === value ? 'bg-slate-100 font-medium' : ''}`, children: [opt.value === value && (jsx("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: jsx(Check, { className: "h-4 w-4 text-slate-900" }) })), jsx("span", { className: "truncate", children: opt.label })] }, opt.value))) : (jsx("div", { className: "py-2 px-2 text-xs text-slate-400 italic text-center", children: "No options" })) }) }))] }));
21
+ };
22
+
23
+ export { Select };
24
+ //# sourceMappingURL=Select.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Select.js","sources":["../../../src/components/ui/Select.tsx"],"sourcesContent":["\nimport React, { useState, useRef, useEffect } from 'react';\nimport { ChevronDown, Check } from 'lucide-react';\n\ninterface SelectProps {\n value: string;\n onValueChange: (value: string) => void;\n options: { value: string; label: string }[];\n placeholder?: string;\n className?: string;\n}\n\nexport const Select: React.FC<SelectProps> = ({ value, onValueChange, options, placeholder = \"Select...\", className = \"\" }) => {\n const [isOpen, setIsOpen] = useState(false);\n const containerRef = useRef<HTMLDivElement>(null);\n const selected = options.find(o => o.value === value);\n\n useEffect(() => {\n const handleOutside = (e: MouseEvent) => {\n if (containerRef.current && !containerRef.current.contains(e.target as Node)) setIsOpen(false);\n };\n document.addEventListener('mousedown', handleOutside);\n return () => document.removeEventListener('mousedown', handleOutside);\n }, []);\n\n return (\n <div className={`relative w-full ${className}`} ref={containerRef} style={{ zIndex: isOpen ? 60 : 1 }}>\n <button\n type=\"button\"\n onClick={() => setIsOpen(!isOpen)}\n className=\"flex h-10 w-full items-center justify-between rounded-md border border-slate-200 bg-white px-3 py-2 text-sm ring-offset-white placeholder:text-slate-500 focus:outline-none focus:ring-2 focus:ring-slate-950 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 transition-colors hover:border-slate-300\"\n >\n <span className=\"truncate\">{selected ? selected.label : placeholder}</span>\n <ChevronDown className={`h-4 w-4 opacity-50 transition-transform duration-200 ${isOpen ? 'rotate-180' : ''}`} />\n </button>\n {isOpen && (\n <div className=\"absolute top-full left-0 z-50 mt-1 min-w-[8rem] w-full max-h-[200px] overflow-y-auto rounded-md border border-slate-200 bg-white text-slate-950 shadow-xl animate-in fade-in zoom-in-95 duration-100\">\n <div className=\"p-1\">\n {options.length > 0 ? options.map((opt) => (\n <button\n key={opt.value}\n onClick={() => {\n onValueChange(opt.value);\n setIsOpen(false);\n }}\n className={`relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none hover:bg-slate-100 hover:text-slate-900 transition-colors ${opt.value === value ? 'bg-slate-100 font-medium' : ''}`}\n >\n {opt.value === value && (\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <Check className=\"h-4 w-4 text-slate-900\" />\n </span>\n )}\n <span className=\"truncate\">{opt.label}</span>\n </button>\n )) : (\n <div className=\"py-2 px-2 text-xs text-slate-400 italic text-center\">No options</div>\n )}\n </div>\n </div>\n )}\n </div>\n );\n};\n"],"names":["_jsxs","_jsx"],"mappings":";;;;MAYa,MAAM,GAA0B,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,GAAG,WAAW,EAAE,SAAS,GAAG,EAAE,EAAE,KAAI;IAC5H,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC;AAC3C,IAAA,MAAM,YAAY,GAAG,MAAM,CAAiB,IAAI,CAAC;AACjD,IAAA,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC;IAErD,SAAS,CAAC,MAAK;AACb,QAAA,MAAM,aAAa,GAAG,CAAC,CAAa,KAAI;AACtC,YAAA,IAAI,YAAY,CAAC,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAc,CAAC;gBAAE,SAAS,CAAC,KAAK,CAAC;AAChG,QAAA,CAAC;AACD,QAAA,QAAQ,CAAC,gBAAgB,CAAC,WAAW,EAAE,aAAa,CAAC;QACrD,OAAO,MAAM,QAAQ,CAAC,mBAAmB,CAAC,WAAW,EAAE,aAAa,CAAC;IACvE,CAAC,EAAE,EAAE,CAAC;IAEN,QACEA,IAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAE,CAAA,gBAAA,EAAmB,SAAS,CAAA,CAAE,EAAE,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,EAAE,GAAG,CAAC,EAAE,EAAA,QAAA,EAAA,CACnGA,IAAA,CAAA,QAAA,EAAA,EACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,MAAM,SAAS,CAAC,CAAC,MAAM,CAAC,EACjC,SAAS,EAAC,4TAA4T,EAAA,QAAA,EAAA,CAEtUC,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,UAAU,EAAA,QAAA,EAAE,QAAQ,GAAG,QAAQ,CAAC,KAAK,GAAG,WAAW,EAAA,CAAQ,EAC3EA,GAAA,CAAC,WAAW,EAAA,EAAC,SAAS,EAAE,CAAA,qDAAA,EAAwD,MAAM,GAAG,YAAY,GAAG,EAAE,CAAA,CAAE,EAAA,CAAI,CAAA,EAAA,CACzG,EACR,MAAM,KACLA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,sMAAsM,EAAA,QAAA,EACnNA,GAAA,CAAA,KAAA,EAAA,EAAK,SAAS,EAAC,KAAK,EAAA,QAAA,EACjB,OAAO,CAAC,MAAM,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,MACpCD,IAAA,CAAA,QAAA,EAAA,EAEE,OAAO,EAAE,MAAK;AACZ,4BAAA,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC;4BACxB,SAAS,CAAC,KAAK,CAAC;AAClB,wBAAA,CAAC,EACD,SAAS,EAAE,CAAA,wKAAA,EAA2K,GAAG,CAAC,KAAK,KAAK,KAAK,GAAG,0BAA0B,GAAG,EAAE,CAAA,CAAE,EAAA,QAAA,EAAA,CAE5O,GAAG,CAAC,KAAK,KAAK,KAAK,KAClBC,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,8DAA8D,EAAA,QAAA,EAC5EA,GAAA,CAAC,KAAK,IAAC,SAAS,EAAC,wBAAwB,EAAA,CAAG,EAAA,CACvC,CACR,EACDA,GAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,UAAU,EAAA,QAAA,EAAE,GAAG,CAAC,KAAK,EAAA,CAAQ,CAAA,EAAA,EAZxC,GAAG,CAAC,KAAK,CAaP,CACV,CAAC,IACAA,aAAK,SAAS,EAAC,qDAAqD,EAAA,QAAA,EAAA,YAAA,EAAA,CAAiB,CACtF,EAAA,CACG,EAAA,CACF,CACP,CAAA,EAAA,CACG;AAEV;;;;"}
@@ -0,0 +1 @@
1
+ export * from './components/AdvancedFilter';
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { AdvancedFilter } from './components/AdvancedFilter.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -0,0 +1,39 @@
1
+ export type ColumnType = 'string' | 'number' | 'date' | 'boolean' | 'select';
2
+ export type LogicalOperator = 'AND' | 'OR';
3
+ export type FilterOperator = 'equals' | 'not_equals' | 'contains' | 'not_contains' | 'gt' | 'lt' | 'gte' | 'lte' | 'before' | 'after' | 'is' | 'true' | 'false';
4
+ export interface FilterRule<T = any> {
5
+ type: 'rule';
6
+ id: string;
7
+ columnId: keyof T;
8
+ operator: FilterOperator;
9
+ value: any;
10
+ }
11
+ export interface FilterGroup<T = any> {
12
+ type: 'group';
13
+ id: string;
14
+ logic: LogicalOperator;
15
+ items: (FilterRule<T> | FilterGroup<T>)[];
16
+ }
17
+ export type FilterItem<T = any> = FilterRule<T> | FilterGroup<T>;
18
+ export interface ColumnDefinition<T = any> {
19
+ id: keyof T;
20
+ label: string;
21
+ type: ColumnType;
22
+ options?: string[];
23
+ }
24
+ export interface TableData {
25
+ id: number;
26
+ cost_centre: string;
27
+ cost_centre_desc: string;
28
+ cost_centre_limit: string | number;
29
+ cost_centre_owner: string;
30
+ approving_authority: string;
31
+ created_by: string;
32
+ timestamp: string;
33
+ is_archive: boolean;
34
+ year: string;
35
+ expense_type: string;
36
+ is_freeze: boolean;
37
+ status?: string;
38
+ [key: string]: any;
39
+ }
@@ -0,0 +1,2 @@
1
+ import { FilterGroup, ColumnDefinition } from '../types';
2
+ export declare const applyFilters: <T>(data: T[], rootGroup: FilterGroup<T>, columns: ColumnDefinition<T>[]) => T[];
@@ -0,0 +1,96 @@
1
+ const evaluateRule = (row, rule, columns) => {
2
+ const column = columns.find(c => c.id === rule.columnId);
3
+ if (!column)
4
+ return true;
5
+ const rawValue = row[rule.columnId];
6
+ let rowValue = rawValue;
7
+ // Normalize Row Value based on column type
8
+ if (column.type === 'number') {
9
+ rowValue = parseFloat(String(rawValue));
10
+ }
11
+ else if (column.type === 'date') {
12
+ rowValue = rawValue ? new Date(rawValue).getTime() : 0;
13
+ }
14
+ else if (column.type === 'string' || column.type === 'select') {
15
+ rowValue = String(rawValue || '').toLowerCase().trim();
16
+ }
17
+ else if (column.type === 'boolean') {
18
+ rowValue = !!rawValue;
19
+ }
20
+ // Handle empty filter values
21
+ const isValueEmpty = rule.value === undefined || rule.value === null || rule.value === '';
22
+ const isBooleanOp = rule.operator === 'true' || rule.operator === 'false';
23
+ if (isValueEmpty && !isBooleanOp) {
24
+ return true;
25
+ }
26
+ let filterValue = rule.value;
27
+ if (column.type === 'string' || column.type === 'select') {
28
+ filterValue = String(rule.value || '').toLowerCase().trim();
29
+ }
30
+ else if (column.type === 'number') {
31
+ filterValue = parseFloat(rule.value);
32
+ if (isNaN(filterValue))
33
+ return true;
34
+ }
35
+ switch (rule.operator) {
36
+ case 'equals':
37
+ return rowValue === filterValue;
38
+ case 'not_equals':
39
+ return rowValue !== filterValue;
40
+ case 'contains':
41
+ return typeof rowValue === 'string' && rowValue.includes(filterValue);
42
+ case 'not_contains':
43
+ return typeof rowValue === 'string' && !rowValue.includes(filterValue);
44
+ case 'gt':
45
+ return rowValue > filterValue;
46
+ case 'lt':
47
+ return rowValue < filterValue;
48
+ case 'gte':
49
+ return rowValue >= filterValue;
50
+ case 'lte':
51
+ return rowValue <= filterValue;
52
+ case 'is':
53
+ if (column.type === 'date') {
54
+ const d1 = new Date(rawValue).setHours(0, 0, 0, 0);
55
+ const d2 = new Date(rule.value).setHours(0, 0, 0, 0);
56
+ return d1 === d2;
57
+ }
58
+ return rowValue === filterValue;
59
+ case 'before':
60
+ return rowValue < new Date(rule.value).getTime();
61
+ case 'after':
62
+ return rowValue > new Date(rule.value).getTime();
63
+ case 'true':
64
+ return rowValue === true;
65
+ case 'false':
66
+ return rowValue === false;
67
+ default:
68
+ return true;
69
+ }
70
+ };
71
+ const evaluateItem = (row, item, columns) => {
72
+ if (item.type === 'rule') {
73
+ return evaluateRule(row, item, columns);
74
+ }
75
+ else {
76
+ return evaluateGroup(row, item, columns);
77
+ }
78
+ };
79
+ const evaluateGroup = (row, group, columns) => {
80
+ if (group.items.length === 0)
81
+ return true;
82
+ if (group.logic === 'AND') {
83
+ return group.items.every(item => evaluateItem(row, item, columns));
84
+ }
85
+ else {
86
+ return group.items.some(item => evaluateItem(row, item, columns));
87
+ }
88
+ };
89
+ const applyFilters = (data, rootGroup, columns) => {
90
+ if (!rootGroup || rootGroup.items.length === 0)
91
+ return data;
92
+ return data.filter(row => evaluateGroup(row, rootGroup, columns));
93
+ };
94
+
95
+ export { applyFilters };
96
+ //# sourceMappingURL=filterLogic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filterLogic.js","sources":["../../src/utils/filterLogic.ts"],"sourcesContent":["\nimport { FilterRule, FilterGroup, ColumnDefinition, FilterItem } from '../types';\n\nconst evaluateRule = <T>(row: T, rule: FilterRule<T>, columns: ColumnDefinition<T>[]): boolean => {\n const column = columns.find(c => c.id === rule.columnId);\n if (!column) return true;\n\n const rawValue = (row as any)[rule.columnId];\n let rowValue: any = rawValue;\n\n // Normalize Row Value based on column type\n if (column.type === 'number') {\n rowValue = parseFloat(String(rawValue));\n } else if (column.type === 'date') {\n rowValue = rawValue ? new Date(rawValue as string).getTime() : 0;\n } else if (column.type === 'string' || column.type === 'select') {\n rowValue = String(rawValue || '').toLowerCase().trim();\n } else if (column.type === 'boolean') {\n rowValue = !!rawValue;\n }\n\n // Handle empty filter values\n const isValueEmpty = rule.value === undefined || rule.value === null || rule.value === '';\n const isBooleanOp = rule.operator === 'true' || rule.operator === 'false';\n \n if (isValueEmpty && !isBooleanOp) {\n return true; \n }\n\n let filterValue = rule.value;\n if (column.type === 'string' || column.type === 'select') {\n filterValue = String(rule.value || '').toLowerCase().trim();\n } else if (column.type === 'number') {\n filterValue = parseFloat(rule.value);\n if (isNaN(filterValue)) return true;\n }\n\n switch (rule.operator) {\n case 'equals':\n return rowValue === filterValue;\n case 'not_equals':\n return rowValue !== filterValue;\n case 'contains':\n return typeof rowValue === 'string' && rowValue.includes(filterValue);\n case 'not_contains':\n return typeof rowValue === 'string' && !rowValue.includes(filterValue);\n case 'gt':\n return rowValue > filterValue;\n case 'lt':\n return rowValue < filterValue;\n case 'gte':\n return rowValue >= filterValue;\n case 'lte':\n return rowValue <= filterValue;\n case 'is':\n if (column.type === 'date') {\n const d1 = new Date(rawValue as string).setHours(0,0,0,0);\n const d2 = new Date(rule.value as string).setHours(0,0,0,0);\n return d1 === d2;\n }\n return rowValue === filterValue;\n case 'before':\n return rowValue < new Date(rule.value as string).getTime();\n case 'after':\n return rowValue > new Date(rule.value as string).getTime();\n case 'true':\n return rowValue === true;\n case 'false':\n return rowValue === false;\n default:\n return true;\n }\n};\n\nconst evaluateItem = <T>(row: T, item: FilterItem<T>, columns: ColumnDefinition<T>[]): boolean => {\n if (item.type === 'rule') {\n return evaluateRule(row, item, columns);\n } else {\n return evaluateGroup(row, item, columns);\n }\n};\n\nconst evaluateGroup = <T>(row: T, group: FilterGroup<T>, columns: ColumnDefinition<T>[]): boolean => {\n if (group.items.length === 0) return true;\n\n if (group.logic === 'AND') {\n return group.items.every(item => evaluateItem(row, item, columns));\n } else {\n return group.items.some(item => evaluateItem(row, item, columns));\n }\n};\n\nexport const applyFilters = <T>(data: T[], rootGroup: FilterGroup<T>, columns: ColumnDefinition<T>[]): T[] => {\n if (!rootGroup || rootGroup.items.length === 0) return data;\n return data.filter(row => evaluateGroup(row, rootGroup, columns));\n};\n"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "nest-filter",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/index.js",
10
+ "types": "./dist/index.d.ts"
11
+ }
12
+ },
13
+ "scripts": {
14
+ "test": "echo \"Error: no test specified\" && exit 1",
15
+ "build": "npx rollup -c"
16
+ },
17
+ "keywords": [],
18
+ "author": "",
19
+ "license": "ISC",
20
+ "type": "module",
21
+ "devDependencies": {
22
+ "@rollup/plugin-babel": "^6.1.0",
23
+ "@rollup/plugin-typescript": "^12.3.0",
24
+ "@tailwindcss/vite": "^4.1.18",
25
+ "@types/react": "^19.2.8",
26
+ "lucide-react": "^0.562.0",
27
+ "react": "^19.2.3",
28
+ "react-dom": "^19.2.3",
29
+ "rollup": "^4.55.1",
30
+ "tailwindcss": "^4.1.18",
31
+ "tslib": "^2.8.1"
32
+ }
33
+ }
@@ -0,0 +1,25 @@
1
+ import { defineConfig } from "rollup";
2
+ import typescript from "@rollup/plugin-typescript";
3
+
4
+ export default defineConfig({
5
+ input: "src/index.ts",
6
+ output: [
7
+ {
8
+ dir: "dist",
9
+ format: "es",
10
+ preserveModules: true,
11
+ sourcemap: true
12
+ }
13
+ ],
14
+ external: [
15
+ "react",
16
+ "react-dom",
17
+ "tailwindcss",
18
+ "lucide-react"
19
+ ],
20
+ plugins: [
21
+ typescript({
22
+ tsconfig: "./tsconfig.json"
23
+ })
24
+ ]
25
+ });