@medusajs/ui 4.0.22-snapshot-20250829134337 → 4.0.22-snapshot-20250901132949
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.
- package/dist/cjs/blocks/data-table/components/data-table-column-visibility-menu.d.ts +9 -0
- package/dist/cjs/blocks/data-table/components/data-table-column-visibility-menu.d.ts.map +1 -0
- package/dist/cjs/blocks/data-table/components/data-table-column-visibility-menu.js +58 -0
- package/dist/cjs/blocks/data-table/components/data-table-column-visibility-menu.js.map +1 -0
- package/dist/cjs/blocks/data-table/components/data-table-filter-bar.d.ts +5 -1
- package/dist/cjs/blocks/data-table/components/data-table-filter-bar.d.ts.map +1 -1
- package/dist/cjs/blocks/data-table/components/data-table-filter-bar.js +71 -9
- package/dist/cjs/blocks/data-table/components/data-table-filter-bar.js.map +1 -1
- package/dist/cjs/blocks/data-table/components/data-table-filter-menu.d.ts +5 -1
- package/dist/cjs/blocks/data-table/components/data-table-filter-menu.d.ts.map +1 -1
- package/dist/cjs/blocks/data-table/components/data-table-filter-menu.js +35 -7
- package/dist/cjs/blocks/data-table/components/data-table-filter-menu.js.map +1 -1
- package/dist/cjs/blocks/data-table/components/data-table-filter.d.ts +4 -1
- package/dist/cjs/blocks/data-table/components/data-table-filter.d.ts.map +1 -1
- package/dist/cjs/blocks/data-table/components/data-table-filter.js +488 -73
- package/dist/cjs/blocks/data-table/components/data-table-filter.js.map +1 -1
- package/dist/cjs/blocks/data-table/components/data-table-non-sortable-header-cell.d.ts +9 -0
- package/dist/cjs/blocks/data-table/components/data-table-non-sortable-header-cell.d.ts.map +1 -0
- package/dist/cjs/blocks/data-table/components/data-table-non-sortable-header-cell.js +42 -0
- package/dist/cjs/blocks/data-table/components/data-table-non-sortable-header-cell.js.map +1 -0
- package/dist/cjs/blocks/data-table/components/data-table-sortable-header-cell.d.ts +9 -0
- package/dist/cjs/blocks/data-table/components/data-table-sortable-header-cell.d.ts.map +1 -0
- package/dist/cjs/blocks/data-table/components/data-table-sortable-header-cell.js +44 -0
- package/dist/cjs/blocks/data-table/components/data-table-sortable-header-cell.js.map +1 -0
- package/dist/cjs/blocks/data-table/components/data-table-table.d.ts.map +1 -1
- package/dist/cjs/blocks/data-table/components/data-table-table.js +132 -4
- package/dist/cjs/blocks/data-table/components/data-table-table.js.map +1 -1
- package/dist/cjs/blocks/data-table/components/data-table-toolbar.d.ts +12 -0
- package/dist/cjs/blocks/data-table/components/data-table-toolbar.d.ts.map +1 -1
- package/dist/cjs/blocks/data-table/components/data-table-toolbar.js +5 -2
- package/dist/cjs/blocks/data-table/components/data-table-toolbar.js.map +1 -1
- package/dist/cjs/blocks/data-table/context/data-table-context-provider.d.ts.map +1 -1
- package/dist/cjs/blocks/data-table/context/data-table-context-provider.js +5 -1
- package/dist/cjs/blocks/data-table/context/data-table-context-provider.js.map +1 -1
- package/dist/cjs/blocks/data-table/context/data-table-context.d.ts +2 -0
- package/dist/cjs/blocks/data-table/context/data-table-context.d.ts.map +1 -1
- package/dist/cjs/blocks/data-table/context/data-table-context.js.map +1 -1
- package/dist/cjs/blocks/data-table/data-table.d.ts +6 -1
- package/dist/cjs/blocks/data-table/data-table.d.ts.map +1 -1
- package/dist/cjs/blocks/data-table/data-table.js +4 -0
- package/dist/cjs/blocks/data-table/data-table.js.map +1 -1
- package/dist/cjs/blocks/data-table/index.d.ts +2 -1
- package/dist/cjs/blocks/data-table/index.d.ts.map +1 -1
- package/dist/cjs/blocks/data-table/index.js.map +1 -1
- package/dist/cjs/blocks/data-table/types.d.ts +75 -3
- package/dist/cjs/blocks/data-table/types.d.ts.map +1 -1
- package/dist/cjs/blocks/data-table/types.js.map +1 -1
- package/dist/cjs/blocks/data-table/use-data-table.d.ts +21 -3
- package/dist/cjs/blocks/data-table/use-data-table.d.ts.map +1 -1
- package/dist/cjs/blocks/data-table/use-data-table.js +47 -7
- package/dist/cjs/blocks/data-table/use-data-table.js.map +1 -1
- package/dist/cjs/blocks/data-table/utils/create-data-table-column-helper.d.ts.map +1 -1
- package/dist/cjs/blocks/data-table/utils/create-data-table-column-helper.js +2 -1
- package/dist/cjs/blocks/data-table/utils/create-data-table-column-helper.js.map +1 -1
- package/dist/cjs/blocks/data-table/utils/create-data-table-filter-helper.d.ts +27 -0
- package/dist/cjs/blocks/data-table/utils/create-data-table-filter-helper.d.ts.map +1 -1
- package/dist/esm/blocks/data-table/components/data-table-column-visibility-menu.d.ts +9 -0
- package/dist/esm/blocks/data-table/components/data-table-column-visibility-menu.d.ts.map +1 -0
- package/dist/esm/blocks/data-table/components/data-table-column-visibility-menu.js +54 -0
- package/dist/esm/blocks/data-table/components/data-table-column-visibility-menu.js.map +1 -0
- package/dist/esm/blocks/data-table/components/data-table-filter-bar.d.ts +5 -1
- package/dist/esm/blocks/data-table/components/data-table-filter-bar.d.ts.map +1 -1
- package/dist/esm/blocks/data-table/components/data-table-filter-bar.js +71 -9
- package/dist/esm/blocks/data-table/components/data-table-filter-bar.js.map +1 -1
- package/dist/esm/blocks/data-table/components/data-table-filter-menu.d.ts +5 -1
- package/dist/esm/blocks/data-table/components/data-table-filter-menu.d.ts.map +1 -1
- package/dist/esm/blocks/data-table/components/data-table-filter-menu.js +35 -7
- package/dist/esm/blocks/data-table/components/data-table-filter-menu.js.map +1 -1
- package/dist/esm/blocks/data-table/components/data-table-filter.d.ts +4 -1
- package/dist/esm/blocks/data-table/components/data-table-filter.d.ts.map +1 -1
- package/dist/esm/blocks/data-table/components/data-table-filter.js +489 -74
- package/dist/esm/blocks/data-table/components/data-table-filter.js.map +1 -1
- package/dist/esm/blocks/data-table/components/data-table-non-sortable-header-cell.d.ts +9 -0
- package/dist/esm/blocks/data-table/components/data-table-non-sortable-header-cell.d.ts.map +1 -0
- package/dist/esm/blocks/data-table/components/data-table-non-sortable-header-cell.js +38 -0
- package/dist/esm/blocks/data-table/components/data-table-non-sortable-header-cell.js.map +1 -0
- package/dist/esm/blocks/data-table/components/data-table-sortable-header-cell.d.ts +9 -0
- package/dist/esm/blocks/data-table/components/data-table-sortable-header-cell.d.ts.map +1 -0
- package/dist/esm/blocks/data-table/components/data-table-sortable-header-cell.js +40 -0
- package/dist/esm/blocks/data-table/components/data-table-sortable-header-cell.js.map +1 -0
- package/dist/esm/blocks/data-table/components/data-table-table.d.ts.map +1 -1
- package/dist/esm/blocks/data-table/components/data-table-table.js +132 -4
- package/dist/esm/blocks/data-table/components/data-table-table.js.map +1 -1
- package/dist/esm/blocks/data-table/components/data-table-toolbar.d.ts +12 -0
- package/dist/esm/blocks/data-table/components/data-table-toolbar.d.ts.map +1 -1
- package/dist/esm/blocks/data-table/components/data-table-toolbar.js +5 -2
- package/dist/esm/blocks/data-table/components/data-table-toolbar.js.map +1 -1
- package/dist/esm/blocks/data-table/context/data-table-context-provider.d.ts.map +1 -1
- package/dist/esm/blocks/data-table/context/data-table-context-provider.js +5 -1
- package/dist/esm/blocks/data-table/context/data-table-context-provider.js.map +1 -1
- package/dist/esm/blocks/data-table/context/data-table-context.d.ts +2 -0
- package/dist/esm/blocks/data-table/context/data-table-context.d.ts.map +1 -1
- package/dist/esm/blocks/data-table/context/data-table-context.js.map +1 -1
- package/dist/esm/blocks/data-table/data-table.d.ts +6 -1
- package/dist/esm/blocks/data-table/data-table.d.ts.map +1 -1
- package/dist/esm/blocks/data-table/data-table.js +4 -0
- package/dist/esm/blocks/data-table/data-table.js.map +1 -1
- package/dist/esm/blocks/data-table/index.d.ts +2 -1
- package/dist/esm/blocks/data-table/index.d.ts.map +1 -1
- package/dist/esm/blocks/data-table/index.js.map +1 -1
- package/dist/esm/blocks/data-table/types.d.ts +75 -3
- package/dist/esm/blocks/data-table/types.d.ts.map +1 -1
- package/dist/esm/blocks/data-table/types.js.map +1 -1
- package/dist/esm/blocks/data-table/use-data-table.d.ts +21 -3
- package/dist/esm/blocks/data-table/use-data-table.d.ts.map +1 -1
- package/dist/esm/blocks/data-table/use-data-table.js +47 -7
- package/dist/esm/blocks/data-table/use-data-table.js.map +1 -1
- package/dist/esm/blocks/data-table/utils/create-data-table-column-helper.d.ts.map +1 -1
- package/dist/esm/blocks/data-table/utils/create-data-table-column-helper.js +2 -1
- package/dist/esm/blocks/data-table/utils/create-data-table-column-helper.js.map +1 -1
- package/dist/esm/blocks/data-table/utils/create-data-table-filter-helper.d.ts +27 -0
- package/dist/esm/blocks/data-table/utils/create-data-table-filter-helper.d.ts.map +1 -1
- package/package.json +6 -3
@@ -1,11 +1,13 @@
|
|
1
|
-
|
2
|
-
import { CheckMini, EllipseMiniSolid, XMark } from "@medusajs/icons";
|
1
|
+
import { CheckMini, EllipseMiniSolid, XMark, XMarkMini, MagnifyingGlass } from "@medusajs/icons";
|
3
2
|
import * as React from "react";
|
4
3
|
import { useDataTableContext } from "../../data-table/context/use-data-table-context";
|
5
4
|
import { isDateComparisonOperator } from "../../data-table/utils/is-date-comparison-operator";
|
6
5
|
import { DatePicker } from "../../../components/date-picker";
|
7
6
|
import { Label } from "../../../components/label";
|
8
7
|
import { Popover } from "../../../components/popover";
|
8
|
+
import { Input } from "../../../components/input";
|
9
|
+
import { Select } from "../../../components/select";
|
10
|
+
import { Checkbox } from "../../../components/checkbox";
|
9
11
|
import { clx } from "../../../utils/clx";
|
10
12
|
const DEFAULT_FORMAT_DATE_VALUE = (d) => d.toLocaleDateString(undefined, {
|
11
13
|
year: "numeric",
|
@@ -15,28 +17,81 @@ const DEFAULT_FORMAT_DATE_VALUE = (d) => d.toLocaleDateString(undefined, {
|
|
15
17
|
const DEFAULT_RANGE_OPTION_LABEL = "Custom";
|
16
18
|
const DEFAULT_RANGE_OPTION_START_LABEL = "Starting";
|
17
19
|
const DEFAULT_RANGE_OPTION_END_LABEL = "Ending";
|
18
|
-
const DataTableFilter = ({ id, filter }) => {
|
20
|
+
const DataTableFilter = ({ id, filter, isNew = false, onUpdate, onRemove }) => {
|
19
21
|
const { instance } = useDataTableContext();
|
20
|
-
|
21
|
-
const [
|
22
|
-
const
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
// Initialize open state based on isNew prop
|
23
|
+
const [open, setOpen] = React.useState(isNew);
|
24
|
+
const [hasInteracted, setHasInteracted] = React.useState(false);
|
25
|
+
const meta = instance.getFilterMeta(id);
|
26
|
+
if (!meta) {
|
27
|
+
return null;
|
28
|
+
}
|
29
|
+
const { type, label, ...rest } = meta;
|
30
|
+
const options = meta.options;
|
31
|
+
// Helper to check if filter has a meaningful value
|
32
|
+
const hasValue = React.useMemo(() => {
|
33
|
+
if (filter === null || filter === undefined)
|
34
|
+
return false;
|
35
|
+
if (typeof filter === "string" && filter === "")
|
36
|
+
return false;
|
37
|
+
if (Array.isArray(filter) && filter.length === 0)
|
38
|
+
return false;
|
39
|
+
if (typeof filter === "number")
|
40
|
+
return true;
|
41
|
+
if (isDateComparisonOperator(filter)) {
|
42
|
+
return !!(filter.$gte || filter.$lte || filter.$gt || filter.$lt);
|
43
|
+
}
|
44
|
+
if (typeof filter === "object" && filter !== null) {
|
45
|
+
// For number comparison operators
|
46
|
+
const keys = Object.keys(filter);
|
47
|
+
return keys.length > 0 && filter[keys[0]] !== null && filter[keys[0]] !== undefined;
|
26
48
|
}
|
27
|
-
|
28
|
-
}, [
|
49
|
+
return true;
|
50
|
+
}, [filter]);
|
51
|
+
const onOpenChange = React.useCallback((newOpen) => {
|
52
|
+
setOpen(newOpen);
|
53
|
+
// Mark as interacted when user closes
|
54
|
+
if (!newOpen && open) {
|
55
|
+
setHasInteracted(true);
|
56
|
+
}
|
57
|
+
// If closing without a value, remove filter
|
58
|
+
// For new filters that haven't been interacted with, remove immediately
|
59
|
+
if (!newOpen && !hasValue) {
|
60
|
+
// Only remove if it's a new filter being closed without interaction,
|
61
|
+
// or if it's an existing filter with no value
|
62
|
+
if ((isNew && !hasInteracted) || !isNew) {
|
63
|
+
if (onRemove) {
|
64
|
+
onRemove();
|
65
|
+
}
|
66
|
+
else {
|
67
|
+
instance.removeFilter(id);
|
68
|
+
}
|
69
|
+
}
|
70
|
+
}
|
71
|
+
}, [instance, id, open, hasInteracted, isNew, hasValue, onRemove]);
|
29
72
|
const removeFilter = React.useCallback(() => {
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
73
|
+
if (onRemove) {
|
74
|
+
onRemove();
|
75
|
+
}
|
76
|
+
else {
|
77
|
+
instance.removeFilter(id);
|
78
|
+
}
|
79
|
+
}, [instance, id, onRemove]);
|
34
80
|
const { displayValue, isCustomRange } = React.useMemo(() => {
|
35
81
|
var _a, _b, _c, _d, _e;
|
36
82
|
let displayValue = null;
|
37
83
|
let isCustomRange = false;
|
38
84
|
if (typeof filter === "string") {
|
39
|
-
|
85
|
+
// For string filters without options, just show the value
|
86
|
+
if (!options || options.length === 0) {
|
87
|
+
displayValue = filter;
|
88
|
+
}
|
89
|
+
else {
|
90
|
+
displayValue = (_b = (_a = options === null || options === void 0 ? void 0 : options.find((o) => o.value === filter)) === null || _a === void 0 ? void 0 : _a.label) !== null && _b !== void 0 ? _b : null;
|
91
|
+
}
|
92
|
+
}
|
93
|
+
if (typeof filter === "number") {
|
94
|
+
displayValue = String(filter);
|
40
95
|
}
|
41
96
|
if (Array.isArray(filter)) {
|
42
97
|
displayValue =
|
@@ -45,74 +100,122 @@ const DataTableFilter = ({ id, filter }) => {
|
|
45
100
|
.join(", ")) !== null && _c !== void 0 ? _c : null;
|
46
101
|
}
|
47
102
|
if (isDateComparisonOperator(filter)) {
|
103
|
+
// First check if it matches a predefined option
|
48
104
|
displayValue =
|
49
105
|
(_e = (_d = options === null || options === void 0 ? void 0 : options.find((o) => {
|
50
106
|
if (!isDateComparisonOperator(o.value)) {
|
51
107
|
return false;
|
52
108
|
}
|
53
|
-
return (!
|
54
|
-
(filter.$gte === o.value.$gte || (!filter.$gte && !o.value.$gte)) &&
|
109
|
+
return ((filter.$gte === o.value.$gte || (!filter.$gte && !o.value.$gte)) &&
|
55
110
|
(filter.$lte === o.value.$lte || (!filter.$lte && !o.value.$lte)) &&
|
56
111
|
(filter.$gt === o.value.$gt || (!filter.$gt && !o.value.$gt)) &&
|
57
112
|
(filter.$lt === o.value.$lt || (!filter.$lt && !o.value.$lt)));
|
58
113
|
})) === null || _d === void 0 ? void 0 : _d.label) !== null && _e !== void 0 ? _e : null;
|
114
|
+
// If no match found, it's a custom range
|
59
115
|
if (!displayValue && isDateFilterProps(meta)) {
|
116
|
+
isCustomRange = true;
|
60
117
|
const formatDateValue = meta.formatDateValue
|
61
118
|
? meta.formatDateValue
|
62
119
|
: DEFAULT_FORMAT_DATE_VALUE;
|
63
120
|
if (filter.$gte && !filter.$lte) {
|
64
|
-
isCustomRange = true;
|
65
121
|
displayValue = `${meta.rangeOptionStartLabel || DEFAULT_RANGE_OPTION_START_LABEL} ${formatDateValue(new Date(filter.$gte))}`;
|
66
122
|
}
|
67
123
|
if (filter.$lte && !filter.$gte) {
|
68
|
-
isCustomRange = true;
|
69
124
|
displayValue = `${meta.rangeOptionEndLabel || DEFAULT_RANGE_OPTION_END_LABEL} ${formatDateValue(new Date(filter.$lte))}`;
|
70
125
|
}
|
71
126
|
if (filter.$gte && filter.$lte) {
|
72
|
-
isCustomRange = true;
|
73
127
|
displayValue = `${formatDateValue(new Date(filter.$gte))} - ${formatDateValue(new Date(filter.$lte))}`;
|
74
128
|
}
|
75
129
|
}
|
76
130
|
}
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
131
|
+
// Handle number comparison operators
|
132
|
+
if (typeof filter === "object" && filter !== null && !Array.isArray(filter) && !isDateComparisonOperator(filter)) {
|
133
|
+
const operators = {
|
134
|
+
$eq: "=",
|
135
|
+
$gt: ">",
|
136
|
+
$gte: "≥",
|
137
|
+
$lt: "<",
|
138
|
+
$lte: "≤",
|
139
|
+
};
|
140
|
+
const op = Object.keys(filter)[0];
|
141
|
+
const opLabel = operators[op] || op;
|
142
|
+
const value = filter[op];
|
143
|
+
if (typeof value === "number") {
|
144
|
+
displayValue = `${opLabel} ${value}`;
|
145
|
+
}
|
82
146
|
}
|
83
|
-
|
84
|
-
|
85
|
-
return null;
|
86
|
-
}
|
147
|
+
return { displayValue, isCustomRange };
|
148
|
+
}, [filter, options, meta]);
|
87
149
|
return (React.createElement(Popover, { open: open, onOpenChange: onOpenChange, modal: true },
|
88
|
-
React.createElement(
|
89
|
-
React.createElement(
|
90
|
-
|
91
|
-
"border
|
92
|
-
}) },
|
93
|
-
|
94
|
-
React.createElement(
|
95
|
-
|
96
|
-
|
97
|
-
|
150
|
+
React.createElement("div", { className: clx("bg-ui-bg-field flex flex-shrink-0 items-stretch overflow-hidden rounded-md", "txt-compact-small-plus shadow-borders-base") },
|
151
|
+
!hasValue && isNew && React.createElement(Popover.Anchor, null),
|
152
|
+
React.createElement("div", { className: clx("flex items-center px-2 py-1 text-ui-fg-muted", {
|
153
|
+
"border-r": hasValue
|
154
|
+
}) }, label || id),
|
155
|
+
hasValue && (React.createElement(React.Fragment, null,
|
156
|
+
(type === "select" || type === "multiselect" || type === "radio") && (React.createElement("div", { className: "flex items-center border-r px-2 py-1 text-ui-fg-muted" }, "is")),
|
157
|
+
React.createElement(Popover.Trigger, { asChild: true },
|
158
|
+
React.createElement("button", { className: clx("flex flex-1 items-center px-2 py-1 outline-none", "hover:bg-ui-bg-base-hover active:bg-ui-bg-base-pressed transition-fg", {
|
159
|
+
"text-ui-fg-subtle": displayValue,
|
160
|
+
"text-ui-fg-muted": !displayValue,
|
161
|
+
"min-w-[80px] justify-center": !displayValue,
|
162
|
+
"border-r": true
|
163
|
+
}) }, displayValue || "\u00A0")),
|
164
|
+
React.createElement("button", { type: "button", className: "flex size-7 items-center justify-center text-ui-fg-muted outline-none hover:bg-ui-bg-base-hover active:bg-ui-bg-base-pressed transition-fg", onClick: removeFilter },
|
98
165
|
React.createElement(XMark, null))))),
|
99
|
-
React.createElement(Popover.Content, { align: "start", className: "bg-ui-bg-component p-0 outline-none"
|
166
|
+
React.createElement(Popover.Content, { align: "start", sideOffset: 8, collisionPadding: 16, hideWhenDetached: true, className: "bg-ui-bg-component p-0 outline-none", onOpenAutoFocus: (e) => {
|
167
|
+
if (isNew) {
|
168
|
+
// For new filters, ensure the first input gets focus
|
169
|
+
const target = e.currentTarget;
|
170
|
+
if (target) {
|
171
|
+
const firstInput = target.querySelector('input:not([type="hidden"]), [role="list"][tabindex="0"]');
|
172
|
+
firstInput === null || firstInput === void 0 ? void 0 : firstInput.focus();
|
173
|
+
}
|
174
|
+
}
|
175
|
+
}, onCloseAutoFocus: (e) => {
|
176
|
+
// Prevent focus from going to the trigger when closing
|
177
|
+
e.preventDefault();
|
178
|
+
}, onInteractOutside: (e) => {
|
179
|
+
// Check if the click is on a filter menu item
|
180
|
+
const target = e.target;
|
181
|
+
if (target.closest('[role="menuitem"]')) {
|
182
|
+
e.preventDefault();
|
183
|
+
}
|
184
|
+
} }, (() => {
|
100
185
|
switch (type) {
|
101
186
|
case "select":
|
102
|
-
return (React.createElement(DataTableFilterSelectContent, { id: id, filter: filter, options: options }));
|
187
|
+
return (React.createElement(DataTableFilterSelectContent, { id: id, filter: filter, options: options, isNew: isNew, onUpdate: onUpdate }));
|
103
188
|
case "radio":
|
104
|
-
return (React.createElement(DataTableFilterRadioContent, { id: id, filter: filter, options: options }));
|
189
|
+
return (React.createElement(DataTableFilterRadioContent, { id: id, filter: filter, options: options, onUpdate: onUpdate }));
|
105
190
|
case "date":
|
106
|
-
|
191
|
+
const dateRest = rest;
|
192
|
+
return (React.createElement(DataTableFilterDateContent, { id: id, filter: filter, options: options, isCustomRange: isCustomRange, format: dateRest.format, rangeOptionLabel: dateRest.rangeOptionLabel, disableRangeOption: dateRest.disableRangeOption, rangeOptionStartLabel: dateRest.rangeOptionStartLabel, rangeOptionEndLabel: dateRest.rangeOptionEndLabel, onUpdate: onUpdate }));
|
193
|
+
case "multiselect":
|
194
|
+
const multiselectRest = rest;
|
195
|
+
return (React.createElement(DataTableFilterMultiselectContent, { id: id, filter: filter, options: options, searchable: multiselectRest.searchable, onUpdate: onUpdate }));
|
196
|
+
case "string":
|
197
|
+
const stringRest = rest;
|
198
|
+
return (React.createElement(DataTableFilterStringContent, { id: id, filter: filter, placeholder: stringRest.placeholder, onUpdate: onUpdate }));
|
199
|
+
case "number":
|
200
|
+
const numberRest = rest;
|
201
|
+
return (React.createElement(DataTableFilterNumberContent, { id: id, filter: filter, placeholder: numberRest.placeholder, includeOperators: numberRest.includeOperators, onUpdate: onUpdate }));
|
202
|
+
case "custom":
|
203
|
+
const customRest = rest;
|
204
|
+
return (React.createElement(DataTableFilterCustomContent, { id: id, filter: filter, onRemove: removeFilter, render: customRest.render, onUpdate: onUpdate }));
|
107
205
|
default:
|
108
206
|
return null;
|
109
207
|
}
|
110
208
|
})())));
|
111
209
|
};
|
112
210
|
DataTableFilter.displayName = "DataTable.Filter";
|
113
|
-
const DataTableFilterDateContent = ({ id, filter, options, format = "date", rangeOptionLabel = DEFAULT_RANGE_OPTION_LABEL, rangeOptionStartLabel = DEFAULT_RANGE_OPTION_START_LABEL, rangeOptionEndLabel = DEFAULT_RANGE_OPTION_END_LABEL, disableRangeOption = false,
|
211
|
+
const DataTableFilterDateContent = ({ id, filter, options, format = "date", rangeOptionLabel = DEFAULT_RANGE_OPTION_LABEL, rangeOptionStartLabel = DEFAULT_RANGE_OPTION_START_LABEL, rangeOptionEndLabel = DEFAULT_RANGE_OPTION_END_LABEL, disableRangeOption = false, isCustomRange, onUpdate, }) => {
|
114
212
|
const currentValue = filter;
|
115
213
|
const { instance } = useDataTableContext();
|
214
|
+
const [isCustom, setIsCustom] = React.useState(isCustomRange);
|
215
|
+
// Sync isCustom state when isCustomRange changes
|
216
|
+
React.useEffect(() => {
|
217
|
+
setIsCustom(isCustomRange);
|
218
|
+
}, [isCustomRange]);
|
116
219
|
const selectedValue = React.useMemo(() => {
|
117
220
|
if (!currentValue || isCustom) {
|
118
221
|
return undefined;
|
@@ -122,17 +225,27 @@ const DataTableFilterDateContent = ({ id, filter, options, format = "date", rang
|
|
122
225
|
const onValueChange = React.useCallback((valueStr) => {
|
123
226
|
setIsCustom(false);
|
124
227
|
const value = JSON.parse(valueStr);
|
125
|
-
|
126
|
-
|
228
|
+
if (onUpdate) {
|
229
|
+
onUpdate(value);
|
230
|
+
}
|
231
|
+
else {
|
232
|
+
instance.updateFilter({ id, value });
|
233
|
+
}
|
234
|
+
}, [instance, id, onUpdate]);
|
127
235
|
const onSelectCustom = React.useCallback(() => {
|
128
236
|
setIsCustom(true);
|
129
|
-
|
130
|
-
}, [
|
237
|
+
// Don't clear the value when selecting custom - keep the current value
|
238
|
+
}, []);
|
131
239
|
const onCustomValueChange = React.useCallback((input, value) => {
|
132
240
|
const newCurrentValue = { ...currentValue };
|
133
241
|
newCurrentValue[input] = value ? value.toISOString() : undefined;
|
134
|
-
|
135
|
-
|
242
|
+
if (onUpdate) {
|
243
|
+
onUpdate(newCurrentValue);
|
244
|
+
}
|
245
|
+
else {
|
246
|
+
instance.updateFilter({ id, value: newCurrentValue });
|
247
|
+
}
|
248
|
+
}, [instance, id, currentValue, onUpdate]);
|
136
249
|
const { focusedIndex, setFocusedIndex } = useKeyboardNavigation(options, (index) => {
|
137
250
|
if (index === options.length && !disableRangeOption) {
|
138
251
|
onSelectCustom();
|
@@ -181,39 +294,67 @@ const DataTableFilterDateContent = ({ id, filter, options, format = "date", rang
|
|
181
294
|
React.createElement(Label, { id: "custom-end-date-label", size: "xsmall", weight: "plus" }, rangeOptionEndLabel),
|
182
295
|
React.createElement(DatePicker, { "aria-labelledby": "custom-end-date-label", granularity: granularity, minValue: minDate, value: (currentValue === null || currentValue === void 0 ? void 0 : currentValue.$lte) ? new Date(currentValue.$lte) : null, onChange: (value) => onCustomValueChange("$lte", value) })))))));
|
183
296
|
};
|
184
|
-
const DataTableFilterSelectContent = ({ id, filter = [], options, }) => {
|
297
|
+
const DataTableFilterSelectContent = ({ id, filter = [], options, isNew = false, onUpdate, }) => {
|
185
298
|
const { instance } = useDataTableContext();
|
299
|
+
const [search, setSearch] = React.useState("");
|
300
|
+
const filteredOptions = React.useMemo(() => {
|
301
|
+
if (!search)
|
302
|
+
return options;
|
303
|
+
const searchLower = search.toLowerCase();
|
304
|
+
return options.filter(opt => opt.label.toLowerCase().includes(searchLower));
|
305
|
+
}, [options, search]);
|
186
306
|
const onValueChange = React.useCallback((value) => {
|
187
307
|
if (filter === null || filter === void 0 ? void 0 : filter.includes(value)) {
|
188
308
|
const newValues = filter === null || filter === void 0 ? void 0 : filter.filter((v) => v !== value);
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
}
|
309
|
+
const newValue = newValues.length > 0 ? newValues : undefined;
|
310
|
+
if (onUpdate) {
|
311
|
+
onUpdate(newValue);
|
312
|
+
}
|
313
|
+
else {
|
314
|
+
instance.updateFilter({
|
315
|
+
id,
|
316
|
+
value: newValue,
|
317
|
+
});
|
318
|
+
}
|
193
319
|
}
|
194
320
|
else {
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
}
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
321
|
+
const newValue = [...(filter !== null && filter !== void 0 ? filter : []), value];
|
322
|
+
if (onUpdate) {
|
323
|
+
onUpdate(newValue);
|
324
|
+
}
|
325
|
+
else {
|
326
|
+
instance.updateFilter({
|
327
|
+
id,
|
328
|
+
value: newValue,
|
329
|
+
});
|
330
|
+
}
|
205
331
|
}
|
206
|
-
}, [
|
207
|
-
return (React.createElement("div", { className: "
|
208
|
-
|
209
|
-
|
210
|
-
|
332
|
+
}, [instance, id, filter, onUpdate]);
|
333
|
+
return (React.createElement("div", { className: "w-[250px]" },
|
334
|
+
React.createElement("div", { className: "flex items-center gap-x-2 border-b px-3 py-1.5" },
|
335
|
+
React.createElement(MagnifyingGlass, { className: "h-4 w-4 text-ui-fg-muted" }),
|
336
|
+
React.createElement("input", { value: search, onChange: (e) => setSearch(e.target.value), placeholder: "Search...", className: "h-8 flex-1 bg-transparent text-sm outline-none placeholder:text-ui-fg-muted", autoFocus: true }),
|
337
|
+
search && (React.createElement("button", { onClick: () => setSearch(""), className: "text-ui-fg-muted hover:text-ui-fg-subtle" },
|
338
|
+
React.createElement(XMarkMini, { className: "h-4 w-4" })))),
|
339
|
+
React.createElement("div", { className: "max-h-[300px] overflow-auto p-1" },
|
340
|
+
filteredOptions.length === 0 && (React.createElement("div", { className: "py-6 text-center text-sm text-ui-fg-muted" }, "No results found")),
|
341
|
+
filteredOptions.map(option => {
|
342
|
+
const isSelected = filter === null || filter === void 0 ? void 0 : filter.includes(option.value);
|
343
|
+
return (React.createElement("button", { key: String(option.value), onClick: () => onValueChange(option.value), className: clx("flex w-full cursor-pointer items-center gap-x-2 rounded-md px-2 py-1.5 text-sm text-left", "hover:bg-ui-bg-base-hover") },
|
344
|
+
React.createElement("div", { className: "flex size-[15px] items-center justify-center" }, isSelected && React.createElement(CheckMini, null)),
|
345
|
+
React.createElement("span", null, option.label)));
|
346
|
+
}))));
|
211
347
|
};
|
212
|
-
const DataTableFilterRadioContent = ({ id, filter, options, }) => {
|
348
|
+
const DataTableFilterRadioContent = ({ id, filter, options, onUpdate, }) => {
|
213
349
|
const { instance } = useDataTableContext();
|
214
350
|
const onValueChange = React.useCallback((value) => {
|
215
|
-
|
216
|
-
|
351
|
+
if (onUpdate) {
|
352
|
+
onUpdate(value);
|
353
|
+
}
|
354
|
+
else {
|
355
|
+
instance.updateFilter({ id, value });
|
356
|
+
}
|
357
|
+
}, [instance, id, onUpdate]);
|
217
358
|
const { focusedIndex, setFocusedIndex } = useKeyboardNavigation(options, (index) => onValueChange(options[index].value));
|
218
359
|
const onListFocus = React.useCallback(() => {
|
219
360
|
if (focusedIndex === -1) {
|
@@ -231,6 +372,30 @@ function isDateFilterProps(props) {
|
|
231
372
|
}
|
232
373
|
return props.type === "date";
|
233
374
|
}
|
375
|
+
function isMultiselectFilterProps(props) {
|
376
|
+
if (!props) {
|
377
|
+
return false;
|
378
|
+
}
|
379
|
+
return props.type === "multiselect";
|
380
|
+
}
|
381
|
+
function isStringFilterProps(props) {
|
382
|
+
if (!props) {
|
383
|
+
return false;
|
384
|
+
}
|
385
|
+
return props.type === "string";
|
386
|
+
}
|
387
|
+
function isNumberFilterProps(props) {
|
388
|
+
if (!props) {
|
389
|
+
return false;
|
390
|
+
}
|
391
|
+
return props.type === "number";
|
392
|
+
}
|
393
|
+
function isCustomFilterProps(props) {
|
394
|
+
if (!props) {
|
395
|
+
return false;
|
396
|
+
}
|
397
|
+
return props.type === "custom";
|
398
|
+
}
|
234
399
|
const OptionButton = React.memo(({ index, option, isSelected, isFocused, onClick, onMouseEvent, icon: Icon, }) => (React.createElement("button", { type: "button", role: "listitem", className: clx("bg-ui-bg-component txt-compact-small transition-fg flex items-center gap-2 rounded px-2 py-1 outline-none", { "bg-ui-bg-component-hover": isFocused }), onClick: onClick, onMouseEnter: () => onMouseEvent(index), onMouseLeave: () => onMouseEvent(-1), tabIndex: -1 },
|
235
400
|
React.createElement("div", { className: "flex size-[15px] items-center justify-center" }, isSelected && React.createElement(Icon, null)),
|
236
401
|
React.createElement("span", null, option.label))));
|
@@ -267,5 +432,255 @@ function useKeyboardNavigation(options, onSelect, extraItems = 0) {
|
|
267
432
|
}, [onKeyDown]);
|
268
433
|
return { focusedIndex, setFocusedIndex };
|
269
434
|
}
|
435
|
+
const DataTableFilterMultiselectContent = ({ id, filter = [], options, searchable = true, onUpdate, }) => {
|
436
|
+
const { instance } = useDataTableContext();
|
437
|
+
const [search, setSearch] = React.useState("");
|
438
|
+
const filteredOptions = React.useMemo(() => {
|
439
|
+
if (!searchable || !search)
|
440
|
+
return options;
|
441
|
+
const searchLower = search.toLowerCase();
|
442
|
+
return options.filter(opt => opt.label.toLowerCase().includes(searchLower));
|
443
|
+
}, [options, search, searchable]);
|
444
|
+
const onValueChange = React.useCallback((value) => {
|
445
|
+
if (filter === null || filter === void 0 ? void 0 : filter.includes(value)) {
|
446
|
+
const newValues = filter === null || filter === void 0 ? void 0 : filter.filter((v) => v !== value);
|
447
|
+
const newValue = newValues.length > 0 ? newValues : undefined;
|
448
|
+
if (onUpdate) {
|
449
|
+
onUpdate(newValue);
|
450
|
+
}
|
451
|
+
else {
|
452
|
+
instance.updateFilter({
|
453
|
+
id,
|
454
|
+
value: newValue,
|
455
|
+
});
|
456
|
+
}
|
457
|
+
}
|
458
|
+
else {
|
459
|
+
const newValue = [...(filter !== null && filter !== void 0 ? filter : []), value];
|
460
|
+
if (onUpdate) {
|
461
|
+
onUpdate(newValue);
|
462
|
+
}
|
463
|
+
else {
|
464
|
+
instance.updateFilter({
|
465
|
+
id,
|
466
|
+
value: newValue,
|
467
|
+
});
|
468
|
+
}
|
469
|
+
}
|
470
|
+
}, [instance, id, filter, onUpdate]);
|
471
|
+
if (!searchable) {
|
472
|
+
return (React.createElement("div", { className: "w-[250px]" },
|
473
|
+
React.createElement("div", { className: "max-h-[300px] overflow-auto p-1" }, options.map(option => {
|
474
|
+
const isSelected = filter === null || filter === void 0 ? void 0 : filter.includes(option.value);
|
475
|
+
return (React.createElement("button", { key: String(option.value), onClick: () => onValueChange(option.value), className: clx("flex w-full items-center gap-x-2 rounded-md px-2 py-1.5 text-sm", "hover:bg-ui-bg-base-hover cursor-pointer text-left") },
|
476
|
+
React.createElement(Checkbox, { checked: isSelected, className: "pointer-events-none" }),
|
477
|
+
React.createElement("span", null, option.label)));
|
478
|
+
}))));
|
479
|
+
}
|
480
|
+
return (React.createElement("div", { className: "w-[250px]" },
|
481
|
+
React.createElement("div", { className: "flex items-center gap-x-2 border-b px-3 py-1.5" },
|
482
|
+
React.createElement(MagnifyingGlass, { className: "h-4 w-4 text-ui-fg-muted" }),
|
483
|
+
React.createElement("input", { value: search, onChange: (e) => setSearch(e.target.value), placeholder: "Search...", className: "h-8 flex-1 bg-transparent text-sm outline-none placeholder:text-ui-fg-muted", autoFocus: true }),
|
484
|
+
search && (React.createElement("button", { onClick: () => setSearch(""), className: "text-ui-fg-muted hover:text-ui-fg-subtle" },
|
485
|
+
React.createElement(XMarkMini, { className: "h-4 w-4" })))),
|
486
|
+
React.createElement("div", { className: "max-h-[300px] overflow-auto p-1" },
|
487
|
+
filteredOptions.length === 0 && (React.createElement("div", { className: "py-6 text-center text-sm text-ui-fg-muted" }, "No results found")),
|
488
|
+
filteredOptions.map(option => {
|
489
|
+
const isSelected = filter === null || filter === void 0 ? void 0 : filter.includes(option.value);
|
490
|
+
return (React.createElement("button", { key: String(option.value), onClick: () => onValueChange(option.value), className: clx("flex w-full cursor-pointer items-center gap-x-2 rounded-md px-2 py-1.5 text-sm text-left", "hover:bg-ui-bg-base-hover") },
|
491
|
+
React.createElement(Checkbox, { checked: isSelected, className: "pointer-events-none" }),
|
492
|
+
React.createElement("span", null, option.label)));
|
493
|
+
}))));
|
494
|
+
};
|
495
|
+
const DataTableFilterStringContent = ({ id, filter, placeholder = "Enter value...", onUpdate, }) => {
|
496
|
+
const { instance } = useDataTableContext();
|
497
|
+
const [value, setValue] = React.useState(filter || "");
|
498
|
+
const timeoutRef = React.useRef(null);
|
499
|
+
const handleChange = React.useCallback((newValue) => {
|
500
|
+
setValue(newValue);
|
501
|
+
// Clear existing timeout
|
502
|
+
if (timeoutRef.current) {
|
503
|
+
clearTimeout(timeoutRef.current);
|
504
|
+
}
|
505
|
+
// Debounce the update
|
506
|
+
timeoutRef.current = setTimeout(() => {
|
507
|
+
const updateValue = newValue.trim() || undefined;
|
508
|
+
if (onUpdate) {
|
509
|
+
onUpdate(updateValue);
|
510
|
+
}
|
511
|
+
else {
|
512
|
+
instance.updateFilter({
|
513
|
+
id,
|
514
|
+
value: updateValue,
|
515
|
+
});
|
516
|
+
}
|
517
|
+
}, 500);
|
518
|
+
}, [instance, id, onUpdate]);
|
519
|
+
// Cleanup timeout on unmount
|
520
|
+
React.useEffect(() => {
|
521
|
+
return () => {
|
522
|
+
if (timeoutRef.current) {
|
523
|
+
clearTimeout(timeoutRef.current);
|
524
|
+
}
|
525
|
+
};
|
526
|
+
}, []);
|
527
|
+
const handleKeyDown = React.useCallback((e) => {
|
528
|
+
if (e.key === "Enter") {
|
529
|
+
// Clear timeout and apply immediately
|
530
|
+
if (timeoutRef.current) {
|
531
|
+
clearTimeout(timeoutRef.current);
|
532
|
+
}
|
533
|
+
const updateValue = value.trim() || undefined;
|
534
|
+
if (onUpdate) {
|
535
|
+
onUpdate(updateValue);
|
536
|
+
}
|
537
|
+
else {
|
538
|
+
instance.updateFilter({
|
539
|
+
id,
|
540
|
+
value: updateValue,
|
541
|
+
});
|
542
|
+
}
|
543
|
+
}
|
544
|
+
}, [instance, id, value, onUpdate]);
|
545
|
+
return (React.createElement("div", { className: "p-3 w-[250px]" },
|
546
|
+
React.createElement(Input, { placeholder: placeholder, value: value, onChange: (e) => handleChange(e.target.value), onKeyDown: handleKeyDown, autoFocus: true })));
|
547
|
+
};
|
548
|
+
const DataTableFilterNumberContent = ({ id, filter, placeholder = "Enter number...", includeOperators = true, onUpdate, }) => {
|
549
|
+
const { instance } = useDataTableContext();
|
550
|
+
const [operator, setOperator] = React.useState("eq");
|
551
|
+
const [value, setValue] = React.useState("");
|
552
|
+
const timeoutRef = React.useRef(null);
|
553
|
+
React.useEffect(() => {
|
554
|
+
if (filter) {
|
555
|
+
if (typeof filter === "number") {
|
556
|
+
setOperator("eq");
|
557
|
+
setValue(String(filter));
|
558
|
+
}
|
559
|
+
else if (typeof filter === "object") {
|
560
|
+
const op = Object.keys(filter)[0];
|
561
|
+
setOperator(op.replace("$", ""));
|
562
|
+
setValue(String(filter[op]));
|
563
|
+
}
|
564
|
+
}
|
565
|
+
}, [filter]);
|
566
|
+
const handleValueChange = React.useCallback((newValue) => {
|
567
|
+
setValue(newValue);
|
568
|
+
// Clear existing timeout
|
569
|
+
if (timeoutRef.current) {
|
570
|
+
clearTimeout(timeoutRef.current);
|
571
|
+
}
|
572
|
+
// Debounce the update
|
573
|
+
timeoutRef.current = setTimeout(() => {
|
574
|
+
const num = parseFloat(newValue);
|
575
|
+
if (!isNaN(num)) {
|
576
|
+
const filterValue = includeOperators && operator !== "eq"
|
577
|
+
? { [`$${operator}`]: num }
|
578
|
+
: num;
|
579
|
+
if (onUpdate) {
|
580
|
+
onUpdate(filterValue);
|
581
|
+
}
|
582
|
+
else {
|
583
|
+
instance.updateFilter({
|
584
|
+
id,
|
585
|
+
value: filterValue,
|
586
|
+
});
|
587
|
+
}
|
588
|
+
}
|
589
|
+
else if (newValue === "") {
|
590
|
+
if (onUpdate) {
|
591
|
+
onUpdate(undefined);
|
592
|
+
}
|
593
|
+
else {
|
594
|
+
instance.updateFilter({
|
595
|
+
id,
|
596
|
+
value: undefined,
|
597
|
+
});
|
598
|
+
}
|
599
|
+
}
|
600
|
+
}, 500);
|
601
|
+
}, [instance, id, operator, includeOperators, onUpdate]);
|
602
|
+
const handleOperatorChange = React.useCallback((newOperator) => {
|
603
|
+
setOperator(newOperator);
|
604
|
+
// If we have a value, update immediately with new operator
|
605
|
+
const num = parseFloat(value);
|
606
|
+
if (!isNaN(num)) {
|
607
|
+
const filterValue = includeOperators && newOperator !== "eq"
|
608
|
+
? { [`$${newOperator}`]: num }
|
609
|
+
: num;
|
610
|
+
if (onUpdate) {
|
611
|
+
onUpdate(filterValue);
|
612
|
+
}
|
613
|
+
else {
|
614
|
+
instance.updateFilter({
|
615
|
+
id,
|
616
|
+
value: filterValue,
|
617
|
+
});
|
618
|
+
}
|
619
|
+
}
|
620
|
+
}, [instance, id, value, includeOperators, onUpdate]);
|
621
|
+
// Cleanup timeout on unmount
|
622
|
+
React.useEffect(() => {
|
623
|
+
return () => {
|
624
|
+
if (timeoutRef.current) {
|
625
|
+
clearTimeout(timeoutRef.current);
|
626
|
+
}
|
627
|
+
};
|
628
|
+
}, []);
|
629
|
+
const handleKeyDown = React.useCallback((e) => {
|
630
|
+
if (e.key === "Enter") {
|
631
|
+
// Clear timeout and apply immediately
|
632
|
+
if (timeoutRef.current) {
|
633
|
+
clearTimeout(timeoutRef.current);
|
634
|
+
}
|
635
|
+
const num = parseFloat(value);
|
636
|
+
if (!isNaN(num)) {
|
637
|
+
const filterValue = includeOperators && operator !== "eq"
|
638
|
+
? { [`$${operator}`]: num }
|
639
|
+
: num;
|
640
|
+
if (onUpdate) {
|
641
|
+
onUpdate(filterValue);
|
642
|
+
}
|
643
|
+
else {
|
644
|
+
instance.updateFilter({
|
645
|
+
id,
|
646
|
+
value: filterValue,
|
647
|
+
});
|
648
|
+
}
|
649
|
+
}
|
650
|
+
}
|
651
|
+
}, [instance, id, value, operator, includeOperators, onUpdate]);
|
652
|
+
const operators = [
|
653
|
+
{ value: "eq", label: "Equals" },
|
654
|
+
{ value: "gt", label: "Greater than" },
|
655
|
+
{ value: "gte", label: "Greater than or equal" },
|
656
|
+
{ value: "lt", label: "Less than" },
|
657
|
+
{ value: "lte", label: "Less than or equal" },
|
658
|
+
];
|
659
|
+
return (React.createElement("div", { className: "p-3 space-y-3 w-[250px]" },
|
660
|
+
includeOperators && (React.createElement(Select, { value: operator, onValueChange: handleOperatorChange },
|
661
|
+
React.createElement(Select.Trigger, null,
|
662
|
+
React.createElement(Select.Value, null)),
|
663
|
+
React.createElement(Select.Content, null, operators.map(op => (React.createElement(Select.Item, { key: op.value, value: op.value }, op.label)))))),
|
664
|
+
React.createElement(Input, { type: "number", placeholder: placeholder, value: value, onChange: (e) => handleValueChange(e.target.value), onKeyDown: handleKeyDown, autoFocus: !includeOperators })));
|
665
|
+
};
|
666
|
+
const DataTableFilterCustomContent = ({ id, filter, onRemove, render, onUpdate, }) => {
|
667
|
+
const { instance } = useDataTableContext();
|
668
|
+
const handleChange = React.useCallback((value) => {
|
669
|
+
if (onUpdate) {
|
670
|
+
onUpdate(value);
|
671
|
+
}
|
672
|
+
else {
|
673
|
+
instance.updateFilter({
|
674
|
+
id,
|
675
|
+
value,
|
676
|
+
});
|
677
|
+
}
|
678
|
+
}, [instance, id, onUpdate]);
|
679
|
+
return (React.createElement(React.Fragment, null, render({
|
680
|
+
value: filter,
|
681
|
+
onChange: handleChange,
|
682
|
+
onRemove,
|
683
|
+
})));
|
684
|
+
};
|
270
685
|
export { DataTableFilter };
|
271
686
|
//# sourceMappingURL=data-table-filter.js.map
|