mantine-composite-filters 0.3.0 → 0.4.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.
Files changed (117) hide show
  1. package/dist/cjs/components/CompositeFiltersInput/CompositeFiltersInput.cjs +896 -0
  2. package/dist/cjs/components/CompositeFiltersInput/CompositeFiltersInput.cjs.map +1 -0
  3. package/dist/cjs/components/CompositeFiltersInput/CompositeFiltersInput.classes.cjs +49 -0
  4. package/dist/cjs/components/CompositeFiltersInput/CompositeFiltersInput.classes.cjs.map +1 -0
  5. package/dist/cjs/components/CompositeFiltersInput/CompositeFiltersInput.module.css.cjs +7 -0
  6. package/dist/cjs/components/CompositeFiltersInput/CompositeFiltersInput.module.css.cjs.map +1 -0
  7. package/dist/cjs/components/CompositeFiltersInput/CurrentFieldIndicator.cjs +25 -0
  8. package/dist/cjs/components/CompositeFiltersInput/CurrentFieldIndicator.cjs.map +1 -0
  9. package/dist/cjs/components/CompositeFiltersInput/CurrentFieldIndicator.module.css.cjs +7 -0
  10. package/dist/cjs/components/CompositeFiltersInput/CurrentFieldIndicator.module.css.cjs.map +1 -0
  11. package/dist/cjs/components/CompositeFiltersInput/FilterActionsMenu.cjs +168 -0
  12. package/dist/cjs/components/CompositeFiltersInput/FilterActionsMenu.cjs.map +1 -0
  13. package/dist/cjs/components/CompositeFiltersInput/FilterMaxReached.cjs +15 -0
  14. package/dist/cjs/components/CompositeFiltersInput/FilterMaxReached.cjs.map +1 -0
  15. package/dist/cjs/components/CompositeFiltersInput/FilterMaxReached.module.css.cjs +7 -0
  16. package/dist/cjs/components/CompositeFiltersInput/FilterMaxReached.module.css.cjs.map +1 -0
  17. package/dist/cjs/components/CompositeFiltersInput/FilterPill.cjs +89 -0
  18. package/dist/cjs/components/CompositeFiltersInput/FilterPill.cjs.map +1 -0
  19. package/dist/cjs/components/CompositeFiltersInput/FilterPill.module.css.cjs +7 -0
  20. package/dist/cjs/components/CompositeFiltersInput/FilterPill.module.css.cjs.map +1 -0
  21. package/dist/cjs/components/CompositeFiltersInput/FilterStatusBar.cjs +32 -0
  22. package/dist/cjs/components/CompositeFiltersInput/FilterStatusBar.cjs.map +1 -0
  23. package/dist/cjs/components/CompositeFiltersInput/FilterStatusBar.module.css.cjs +7 -0
  24. package/dist/cjs/components/CompositeFiltersInput/FilterStatusBar.module.css.cjs.map +1 -0
  25. package/dist/cjs/components/CompositeFiltersInput/context/FilterContext.cjs +233 -0
  26. package/dist/cjs/components/CompositeFiltersInput/context/FilterContext.cjs.map +1 -0
  27. package/dist/cjs/components/CompositeFiltersInput/dropdowns/FieldDropdown.cjs +34 -0
  28. package/dist/cjs/components/CompositeFiltersInput/dropdowns/FieldDropdown.cjs.map +1 -0
  29. package/dist/cjs/components/CompositeFiltersInput/dropdowns/FieldDropdown.module.css.cjs +7 -0
  30. package/dist/cjs/components/CompositeFiltersInput/dropdowns/FieldDropdown.module.css.cjs.map +1 -0
  31. package/dist/cjs/components/CompositeFiltersInput/dropdowns/OperatorDropdown.cjs +29 -0
  32. package/dist/cjs/components/CompositeFiltersInput/dropdowns/OperatorDropdown.cjs.map +1 -0
  33. package/dist/cjs/components/CompositeFiltersInput/dropdowns/OperatorDropdown.module.css.cjs +7 -0
  34. package/dist/cjs/components/CompositeFiltersInput/dropdowns/OperatorDropdown.module.css.cjs.map +1 -0
  35. package/dist/cjs/components/CompositeFiltersInput/dropdowns/ValueDropdown.cjs +57 -0
  36. package/dist/cjs/components/CompositeFiltersInput/dropdowns/ValueDropdown.cjs.map +1 -0
  37. package/dist/cjs/components/CompositeFiltersInput/dropdowns/ValueDropdown.module.css.cjs +7 -0
  38. package/dist/cjs/components/CompositeFiltersInput/dropdowns/ValueDropdown.module.css.cjs.map +1 -0
  39. package/dist/cjs/components/CompositeFiltersInput/value-inputs/DateRangeValueInput.cjs +58 -0
  40. package/dist/cjs/components/CompositeFiltersInput/value-inputs/DateRangeValueInput.cjs.map +1 -0
  41. package/dist/cjs/components/CompositeFiltersInput/value-inputs/DateRangeValueInput.module.css.cjs +7 -0
  42. package/dist/cjs/components/CompositeFiltersInput/value-inputs/DateRangeValueInput.module.css.cjs.map +1 -0
  43. package/dist/cjs/components/CompositeFiltersInput/value-inputs/DateValueInput.cjs +71 -0
  44. package/dist/cjs/components/CompositeFiltersInput/value-inputs/DateValueInput.cjs.map +1 -0
  45. package/dist/cjs/components/CompositeFiltersInput/value-inputs/DateValueInput.module.css.cjs +7 -0
  46. package/dist/cjs/components/CompositeFiltersInput/value-inputs/DateValueInput.module.css.cjs.map +1 -0
  47. package/dist/cjs/hooks/useFilterHistory.cjs +49 -0
  48. package/dist/cjs/hooks/useFilterHistory.cjs.map +1 -0
  49. package/dist/cjs/hooks/useFilterPresets.cjs +101 -0
  50. package/dist/cjs/hooks/useFilterPresets.cjs.map +1 -0
  51. package/dist/cjs/hooks/useFilters.cjs +92 -0
  52. package/dist/cjs/hooks/useFilters.cjs.map +1 -0
  53. package/dist/cjs/index.cjs +56 -0
  54. package/dist/cjs/index.cjs.map +1 -0
  55. package/dist/cjs/utils/formatters.cjs +46 -0
  56. package/dist/cjs/utils/formatters.cjs.map +1 -0
  57. package/dist/cjs/utils/operators.cjs +55 -0
  58. package/dist/cjs/utils/operators.cjs.map +1 -0
  59. package/dist/esm/components/CompositeFiltersInput/CompositeFiltersInput.classes.mjs +44 -0
  60. package/dist/esm/components/CompositeFiltersInput/CompositeFiltersInput.classes.mjs.map +1 -0
  61. package/dist/esm/components/CompositeFiltersInput/CompositeFiltersInput.mjs +891 -0
  62. package/dist/esm/components/CompositeFiltersInput/CompositeFiltersInput.mjs.map +1 -0
  63. package/dist/esm/components/CompositeFiltersInput/CompositeFiltersInput.module.css.mjs +5 -0
  64. package/dist/esm/components/CompositeFiltersInput/CompositeFiltersInput.module.css.mjs.map +1 -0
  65. package/dist/esm/components/CompositeFiltersInput/CurrentFieldIndicator.mjs +20 -0
  66. package/dist/esm/components/CompositeFiltersInput/CurrentFieldIndicator.mjs.map +1 -0
  67. package/dist/esm/components/CompositeFiltersInput/CurrentFieldIndicator.module.css.mjs +5 -0
  68. package/dist/esm/components/CompositeFiltersInput/CurrentFieldIndicator.module.css.mjs.map +1 -0
  69. package/dist/esm/components/CompositeFiltersInput/FilterActionsMenu.mjs +163 -0
  70. package/dist/esm/components/CompositeFiltersInput/FilterActionsMenu.mjs.map +1 -0
  71. package/dist/esm/components/CompositeFiltersInput/FilterMaxReached.mjs +10 -0
  72. package/dist/esm/components/CompositeFiltersInput/FilterMaxReached.mjs.map +1 -0
  73. package/dist/esm/components/CompositeFiltersInput/FilterMaxReached.module.css.mjs +5 -0
  74. package/dist/esm/components/CompositeFiltersInput/FilterMaxReached.module.css.mjs.map +1 -0
  75. package/dist/esm/components/CompositeFiltersInput/FilterPill.mjs +84 -0
  76. package/dist/esm/components/CompositeFiltersInput/FilterPill.mjs.map +1 -0
  77. package/dist/esm/components/CompositeFiltersInput/FilterPill.module.css.mjs +5 -0
  78. package/dist/esm/components/CompositeFiltersInput/FilterPill.module.css.mjs.map +1 -0
  79. package/dist/esm/components/CompositeFiltersInput/FilterStatusBar.mjs +27 -0
  80. package/dist/esm/components/CompositeFiltersInput/FilterStatusBar.mjs.map +1 -0
  81. package/dist/esm/components/CompositeFiltersInput/FilterStatusBar.module.css.mjs +5 -0
  82. package/dist/esm/components/CompositeFiltersInput/FilterStatusBar.module.css.mjs.map +1 -0
  83. package/dist/esm/components/CompositeFiltersInput/context/FilterContext.mjs +227 -0
  84. package/dist/esm/components/CompositeFiltersInput/context/FilterContext.mjs.map +1 -0
  85. package/dist/esm/components/CompositeFiltersInput/dropdowns/FieldDropdown.mjs +29 -0
  86. package/dist/esm/components/CompositeFiltersInput/dropdowns/FieldDropdown.mjs.map +1 -0
  87. package/dist/esm/components/CompositeFiltersInput/dropdowns/FieldDropdown.module.css.mjs +5 -0
  88. package/dist/esm/components/CompositeFiltersInput/dropdowns/FieldDropdown.module.css.mjs.map +1 -0
  89. package/dist/esm/components/CompositeFiltersInput/dropdowns/OperatorDropdown.mjs +24 -0
  90. package/dist/esm/components/CompositeFiltersInput/dropdowns/OperatorDropdown.mjs.map +1 -0
  91. package/dist/esm/components/CompositeFiltersInput/dropdowns/OperatorDropdown.module.css.mjs +5 -0
  92. package/dist/esm/components/CompositeFiltersInput/dropdowns/OperatorDropdown.module.css.mjs.map +1 -0
  93. package/dist/esm/components/CompositeFiltersInput/dropdowns/ValueDropdown.mjs +52 -0
  94. package/dist/esm/components/CompositeFiltersInput/dropdowns/ValueDropdown.mjs.map +1 -0
  95. package/dist/esm/components/CompositeFiltersInput/dropdowns/ValueDropdown.module.css.mjs +5 -0
  96. package/dist/esm/components/CompositeFiltersInput/dropdowns/ValueDropdown.module.css.mjs.map +1 -0
  97. package/dist/esm/components/CompositeFiltersInput/value-inputs/DateRangeValueInput.mjs +53 -0
  98. package/dist/esm/components/CompositeFiltersInput/value-inputs/DateRangeValueInput.mjs.map +1 -0
  99. package/dist/esm/components/CompositeFiltersInput/value-inputs/DateRangeValueInput.module.css.mjs +5 -0
  100. package/dist/esm/components/CompositeFiltersInput/value-inputs/DateRangeValueInput.module.css.mjs.map +1 -0
  101. package/dist/esm/components/CompositeFiltersInput/value-inputs/DateValueInput.mjs +66 -0
  102. package/dist/esm/components/CompositeFiltersInput/value-inputs/DateValueInput.mjs.map +1 -0
  103. package/dist/esm/components/CompositeFiltersInput/value-inputs/DateValueInput.module.css.mjs +5 -0
  104. package/dist/esm/components/CompositeFiltersInput/value-inputs/DateValueInput.module.css.mjs.map +1 -0
  105. package/dist/esm/hooks/useFilterHistory.mjs +47 -0
  106. package/dist/esm/hooks/useFilterHistory.mjs.map +1 -0
  107. package/dist/esm/hooks/useFilterPresets.mjs +99 -0
  108. package/dist/esm/hooks/useFilterPresets.mjs.map +1 -0
  109. package/dist/esm/hooks/useFilters.mjs +90 -0
  110. package/dist/esm/hooks/useFilters.mjs.map +1 -0
  111. package/dist/esm/index.mjs +19 -0
  112. package/dist/esm/index.mjs.map +1 -0
  113. package/dist/esm/utils/formatters.mjs +40 -0
  114. package/dist/esm/utils/formatters.mjs.map +1 -0
  115. package/dist/esm/utils/operators.mjs +48 -0
  116. package/dist/esm/utils/operators.mjs.map +1 -0
  117. package/package.json +1 -1
@@ -0,0 +1,896 @@
1
+ 'use client';
2
+ 'use strict';
3
+
4
+ Object.defineProperty(exports, '__esModule', { value: true });
5
+
6
+ var React = require('react');
7
+ var core = require('@mantine/core');
8
+ var hooks = require('@mantine/hooks');
9
+ var iconsReact = require('@tabler/icons-react');
10
+ var clsx = require('../../node_modules/clsx/dist/clsx.cjs');
11
+ var CompositeFiltersInput_module = require('./CompositeFiltersInput.module.css.cjs');
12
+ var CompositeFiltersInput_classes = require('./CompositeFiltersInput.classes.cjs');
13
+ var useFilterHistory = require('../../hooks/useFilterHistory.cjs');
14
+ var useFilterPresets = require('../../hooks/useFilterPresets.cjs');
15
+ var operators = require('../../utils/operators.cjs');
16
+ var formatters = require('../../utils/formatters.cjs');
17
+ var CurrentFieldIndicator = require('./CurrentFieldIndicator.cjs');
18
+ var FieldDropdown = require('./dropdowns/FieldDropdown.cjs');
19
+ var OperatorDropdown = require('./dropdowns/OperatorDropdown.cjs');
20
+ var ValueDropdown = require('./dropdowns/ValueDropdown.cjs');
21
+ var FilterActionsMenu = require('./FilterActionsMenu.cjs');
22
+ var FilterMaxReached = require('./FilterMaxReached.cjs');
23
+ var FilterPill = require('./FilterPill.cjs');
24
+ var DateValueInput = require('./value-inputs/DateValueInput.cjs');
25
+ var DateRangeValueInput = require('./value-inputs/DateRangeValueInput.cjs');
26
+
27
+ const CompositeFiltersInputBase = ({
28
+ filters,
29
+ value: activeFilters,
30
+ onChange,
31
+ placeholder = "Filter by...",
32
+ maxFilters,
33
+ className,
34
+ renderPill,
35
+ disablePresets = false,
36
+ disableHistory = false,
37
+ storageKeyPrefix = "filters",
38
+ customActions = [],
39
+ overflowMode = "scroll",
40
+ styles,
41
+ classNames,
42
+ operatorPlaceholder = "Select operator...",
43
+ valuePlaceholder = "Enter value...",
44
+ searchPlaceholder = "Search options...",
45
+ ...boxProps
46
+ }) => {
47
+ const theme = core.useMantineTheme();
48
+ const resolvedStyles = React.useMemo(() => {
49
+ return typeof styles === "function" ? styles(theme) : styles || {};
50
+ }, [styles, theme]);
51
+ const getClassName = React.useCallback((selector) => {
52
+ return clsx.clsx(
53
+ CompositeFiltersInput_classes.staticClasses[selector],
54
+ CompositeFiltersInput_classes.cssModuleClasses[selector],
55
+ classNames?.[selector]
56
+ );
57
+ }, [classNames]);
58
+ const [inputStep, setInputStep] = React.useState("field");
59
+ const [selectedField, setSelectedField] = React.useState(null);
60
+ const [selectedOperator, setSelectedOperator] = React.useState(null);
61
+ const [inputValue, setInputValue] = React.useState("");
62
+ const [dateValue, setDateValue] = React.useState(null);
63
+ const [dateRangeValue, setDateRangeValue] = React.useState([null, null]);
64
+ const [multiSelectValues, setMultiSelectValues] = React.useState([]);
65
+ const [_isFocused, setIsFocused] = React.useState(false);
66
+ const [highlightedFilterId, setHighlightedFilterId] = React.useState(null);
67
+ const [editingFilterId, setEditingFilterId] = React.useState(null);
68
+ const [editingPart, setEditingPart] = React.useState(null);
69
+ const inputRef = React.useRef(null);
70
+ const pillsContainerRef = React.useRef(null);
71
+ const [isCompactMode, setIsCompactMode] = hooks.useLocalStorage({
72
+ key: `${storageKeyPrefix}-compact-mode`,
73
+ defaultValue: false
74
+ });
75
+ const [showFilterCount, setShowFilterCount] = hooks.useLocalStorage({
76
+ key: `${storageKeyPrefix}-show-count`,
77
+ defaultValue: true
78
+ });
79
+ const {
80
+ presets: savedPresets,
81
+ savePreset,
82
+ loadPreset,
83
+ toggleFavorite: togglePresetFavorite,
84
+ deletePreset
85
+ } = useFilterPresets.useFilterPresets({
86
+ storageKey: `${storageKeyPrefix}-saved-presets`,
87
+ onLoad: onChange
88
+ });
89
+ const { history: filterHistory } = useFilterHistory.useFilterHistory(activeFilters, {
90
+ storageKey: `${storageKeyPrefix}-history`,
91
+ enabled: !disableHistory
92
+ });
93
+ const combobox = core.useCombobox({
94
+ onDropdownClose: () => combobox.resetSelectedOption(),
95
+ onDropdownOpen: () => combobox.selectFirstOption()
96
+ });
97
+ const availableFilters = React.useMemo(() => {
98
+ const usedKeys = new Set(activeFilters.map((f) => f.key));
99
+ return filters.filter((f) => !usedKeys.has(f.key));
100
+ }, [filters, activeFilters]);
101
+ const filteredFields = React.useMemo(() => {
102
+ if (!inputValue.trim()) {
103
+ return availableFilters;
104
+ }
105
+ return availableFilters.filter(
106
+ (f) => f.label.toLowerCase().includes(inputValue.toLowerCase())
107
+ );
108
+ }, [availableFilters, inputValue]);
109
+ const filteredOptions = React.useMemo(() => {
110
+ if (!selectedField?.options) {
111
+ return [];
112
+ }
113
+ if (!inputValue.trim()) {
114
+ return selectedField.options;
115
+ }
116
+ return selectedField.options.filter(
117
+ (opt) => opt.label.toLowerCase().includes(inputValue.toLowerCase())
118
+ );
119
+ }, [selectedField, inputValue]);
120
+ const isInputDisabled = maxFilters !== void 0 && activeFilters.length >= maxFilters;
121
+ hooks.useHotkeys([
122
+ ["mod+/", () => {
123
+ inputRef.current?.focus();
124
+ combobox.openDropdown();
125
+ combobox.selectFirstOption();
126
+ }],
127
+ ["mod+Backspace", () => handleClearAll()]
128
+ ]);
129
+ const resetInput = React.useCallback(() => {
130
+ setInputStep("field");
131
+ setSelectedField(null);
132
+ setSelectedOperator(null);
133
+ setInputValue("");
134
+ setDateValue(null);
135
+ setDateRangeValue([null, null]);
136
+ setMultiSelectValues([]);
137
+ setEditingFilterId(null);
138
+ setEditingPart(null);
139
+ }, []);
140
+ const handleRemoveFilter = React.useCallback(
141
+ (id) => {
142
+ onChange(activeFilters.filter((f) => f.id !== id));
143
+ },
144
+ [activeFilters, onChange]
145
+ );
146
+ const handleClearAll = React.useCallback(() => {
147
+ onChange([]);
148
+ resetInput();
149
+ setEditingFilterId(null);
150
+ setEditingPart(null);
151
+ }, [onChange, resetInput]);
152
+ const handleFilterOperatorClick = React.useCallback((filter) => {
153
+ const field = filters.find((f) => f.key === filter.key);
154
+ if (!field) {
155
+ return;
156
+ }
157
+ setEditingFilterId(filter.id);
158
+ setEditingPart("operator");
159
+ setSelectedField(field);
160
+ setSelectedOperator(filter.operator);
161
+ setInputValue("");
162
+ setDateValue(null);
163
+ setDateRangeValue([null, null]);
164
+ setMultiSelectValues([]);
165
+ setInputStep("operator");
166
+ setTimeout(() => {
167
+ combobox.openDropdown();
168
+ combobox.selectFirstOption();
169
+ }, 0);
170
+ }, [filters, combobox]);
171
+ const handleFilterValueClick = React.useCallback((filter) => {
172
+ const field = filters.find((f) => f.key === filter.key);
173
+ if (!field) {
174
+ return;
175
+ }
176
+ setEditingFilterId(filter.id);
177
+ setEditingPart("value");
178
+ setSelectedField(field);
179
+ setSelectedOperator(filter.operator);
180
+ if (field.type === "date") {
181
+ const dateVal = typeof filter.value === "string" ? new Date(filter.value) : null;
182
+ setDateValue(dateVal);
183
+ setInputValue("");
184
+ } else if (field.type === "date_range") {
185
+ if (Array.isArray(filter.value) && filter.value.length === 2) {
186
+ const range = [
187
+ filter.value[0] instanceof Date ? filter.value[0] : filter.value[0] ? new Date(filter.value[0]) : null,
188
+ filter.value[1] instanceof Date ? filter.value[1] : filter.value[1] ? new Date(filter.value[1]) : null
189
+ ];
190
+ setDateRangeValue(range);
191
+ } else {
192
+ setDateRangeValue([null, null]);
193
+ }
194
+ setInputValue("");
195
+ } else if (field.type === "multi_select") {
196
+ const values = Array.isArray(filter.value) ? filter.value : [];
197
+ setMultiSelectValues(values);
198
+ setInputValue("");
199
+ } else {
200
+ const textValue = typeof filter.value === "string" ? filter.value : String(filter.value || "");
201
+ setInputValue(textValue);
202
+ }
203
+ setInputStep("value");
204
+ if (field.type === "select" || field.type === "multi_select") {
205
+ setTimeout(() => {
206
+ combobox.openDropdown();
207
+ combobox.selectFirstOption();
208
+ }, 0);
209
+ } else {
210
+ setTimeout(() => {
211
+ inputRef.current?.focus();
212
+ inputRef.current?.select();
213
+ }, 0);
214
+ }
215
+ }, [filters, combobox]);
216
+ const handleFieldSelect = React.useCallback(
217
+ (field) => {
218
+ setSelectedField(field);
219
+ setInputValue("");
220
+ const operators$1 = operators.getOperatorsForField(field);
221
+ if (editingFilterId && editingPart === "field") {
222
+ if (operators$1.length === 1) {
223
+ setSelectedOperator(operators$1[0]);
224
+ setDateValue(null);
225
+ setDateRangeValue([null, null]);
226
+ setMultiSelectValues([]);
227
+ setInputStep("value");
228
+ if (field.type === "select" || field.type === "multi_select") {
229
+ setTimeout(() => {
230
+ combobox.openDropdown();
231
+ combobox.selectFirstOption();
232
+ }, 0);
233
+ }
234
+ } else {
235
+ setDateValue(null);
236
+ setDateRangeValue([null, null]);
237
+ setMultiSelectValues([]);
238
+ setInputStep("operator");
239
+ setTimeout(() => {
240
+ combobox.openDropdown();
241
+ combobox.selectFirstOption();
242
+ }, 0);
243
+ }
244
+ } else if (operators$1.length === 1) {
245
+ setSelectedOperator(operators$1[0]);
246
+ setInputStep("value");
247
+ } else {
248
+ setInputStep("operator");
249
+ }
250
+ },
251
+ [editingFilterId, editingPart, combobox]
252
+ );
253
+ const handleOperatorSelect = React.useCallback((operator) => {
254
+ setSelectedOperator(operator);
255
+ if (editingFilterId && editingPart === "operator" && selectedField) {
256
+ const existingFilter = activeFilters.find((f) => f.id === editingFilterId);
257
+ if (existingFilter) {
258
+ if (selectedField.type === "date") {
259
+ const dateVal = typeof existingFilter.value === "string" ? new Date(existingFilter.value) : null;
260
+ setDateValue(dateVal);
261
+ if (dateVal) {
262
+ const updatedFilters = activeFilters.map(
263
+ (f) => f.id === editingFilterId ? {
264
+ ...f,
265
+ operator,
266
+ value: dateVal.toISOString(),
267
+ displayValue: formatters.formatDate(dateVal)
268
+ } : f
269
+ );
270
+ onChange(updatedFilters);
271
+ setEditingFilterId(null);
272
+ setEditingPart(null);
273
+ resetInput();
274
+ return;
275
+ }
276
+ } else if (selectedField.type === "date_range") {
277
+ if (Array.isArray(existingFilter.value) && existingFilter.value.length === 2) {
278
+ const range = [
279
+ existingFilter.value[0] instanceof Date ? existingFilter.value[0] : existingFilter.value[0] ? new Date(existingFilter.value[0]) : null,
280
+ existingFilter.value[1] instanceof Date ? existingFilter.value[1] : existingFilter.value[1] ? new Date(existingFilter.value[1]) : null
281
+ ];
282
+ setDateRangeValue(range);
283
+ if (range[0] && range[1]) {
284
+ const updatedFilters = activeFilters.map(
285
+ (f) => f.id === editingFilterId ? {
286
+ ...f,
287
+ operator,
288
+ value: range,
289
+ displayValue: formatters.formatDateRange(range[0], range[1])
290
+ } : f
291
+ );
292
+ onChange(updatedFilters);
293
+ setEditingFilterId(null);
294
+ setEditingPart(null);
295
+ resetInput();
296
+ return;
297
+ }
298
+ }
299
+ } else if (selectedField.type === "multi_select") {
300
+ const values = Array.isArray(existingFilter.value) ? existingFilter.value : [];
301
+ setMultiSelectValues(values);
302
+ if (values.length > 0) {
303
+ const labels = values.map((v) => selectedField.options?.find((o) => o.value === v)?.label || v).join(", ");
304
+ const updatedFilters = activeFilters.map(
305
+ (f) => f.id === editingFilterId ? {
306
+ ...f,
307
+ operator,
308
+ value: values,
309
+ displayValue: labels
310
+ } : f
311
+ );
312
+ onChange(updatedFilters);
313
+ setEditingFilterId(null);
314
+ setEditingPart(null);
315
+ resetInput();
316
+ return;
317
+ }
318
+ } else if (selectedField.type === "select") {
319
+ const textValue = typeof existingFilter.value === "string" ? existingFilter.value : String(existingFilter.value || "");
320
+ setInputValue(textValue);
321
+ if (textValue) {
322
+ const option = selectedField.options?.find((o) => o.value === textValue);
323
+ const updatedFilters = activeFilters.map(
324
+ (f) => f.id === editingFilterId ? {
325
+ ...f,
326
+ operator,
327
+ value: textValue,
328
+ displayValue: option?.label || textValue
329
+ } : f
330
+ );
331
+ onChange(updatedFilters);
332
+ setEditingFilterId(null);
333
+ setEditingPart(null);
334
+ resetInput();
335
+ return;
336
+ }
337
+ } else {
338
+ const textValue = typeof existingFilter.value === "string" ? existingFilter.value : String(existingFilter.value || "");
339
+ if (textValue) {
340
+ const updatedFilters = activeFilters.map(
341
+ (f) => f.id === editingFilterId ? {
342
+ ...f,
343
+ operator
344
+ } : f
345
+ );
346
+ onChange(updatedFilters);
347
+ setEditingFilterId(null);
348
+ setEditingPart(null);
349
+ resetInput();
350
+ return;
351
+ }
352
+ }
353
+ }
354
+ }
355
+ setInputValue("");
356
+ setInputStep("value");
357
+ if (selectedField && (selectedField.type === "select" || selectedField.type === "multi_select")) {
358
+ combobox.openDropdown();
359
+ combobox.selectFirstOption();
360
+ }
361
+ }, [editingFilterId, editingPart, activeFilters, selectedField, combobox, onChange, resetInput]);
362
+ const addFilter = React.useCallback(
363
+ (displayValue, rawValue) => {
364
+ if (!selectedField || !selectedOperator) {
365
+ return;
366
+ }
367
+ if (editingFilterId) {
368
+ const updatedFilters = activeFilters.map(
369
+ (f) => f.id === editingFilterId ? {
370
+ ...f,
371
+ key: selectedField.key,
372
+ label: selectedField.label,
373
+ type: selectedField.type,
374
+ operator: selectedOperator,
375
+ value: rawValue,
376
+ displayValue,
377
+ icon: selectedField.icon
378
+ } : f
379
+ );
380
+ onChange(updatedFilters);
381
+ setEditingFilterId(null);
382
+ setEditingPart(null);
383
+ } else {
384
+ const newFilter = {
385
+ id: formatters.generateId(),
386
+ key: selectedField.key,
387
+ label: selectedField.label,
388
+ type: selectedField.type,
389
+ operator: selectedOperator,
390
+ value: rawValue,
391
+ displayValue,
392
+ icon: selectedField.icon
393
+ };
394
+ onChange([...activeFilters, newFilter]);
395
+ setHighlightedFilterId(newFilter.id);
396
+ setTimeout(() => setHighlightedFilterId(null), 1e3);
397
+ }
398
+ resetInput();
399
+ if (overflowMode === "scroll" && pillsContainerRef.current) {
400
+ setTimeout(() => {
401
+ if (pillsContainerRef.current) {
402
+ pillsContainerRef.current.scrollLeft = pillsContainerRef.current.scrollWidth;
403
+ }
404
+ }, 50);
405
+ }
406
+ },
407
+ [selectedField, selectedOperator, activeFilters, onChange, resetInput, overflowMode, editingFilterId]
408
+ );
409
+ const handleValueSubmit = React.useCallback(() => {
410
+ if (!selectedField || !selectedOperator) {
411
+ return;
412
+ }
413
+ if (editingFilterId && editingPart === "value") {
414
+ switch (selectedField.type) {
415
+ case "text":
416
+ case "email":
417
+ case "number":
418
+ if (inputValue.trim()) {
419
+ const updatedFilters = activeFilters.map(
420
+ (f) => f.id === editingFilterId ? {
421
+ ...f,
422
+ value: inputValue.trim(),
423
+ displayValue: inputValue.trim(),
424
+ operator: selectedOperator
425
+ } : f
426
+ );
427
+ onChange(updatedFilters);
428
+ setEditingFilterId(null);
429
+ setEditingPart(null);
430
+ resetInput();
431
+ }
432
+ return;
433
+ case "date":
434
+ if (dateValue) {
435
+ const updatedFilters = activeFilters.map(
436
+ (f) => f.id === editingFilterId ? {
437
+ ...f,
438
+ value: dateValue.toISOString(),
439
+ displayValue: formatters.formatDate(dateValue),
440
+ operator: selectedOperator
441
+ } : f
442
+ );
443
+ onChange(updatedFilters);
444
+ setEditingFilterId(null);
445
+ setEditingPart(null);
446
+ resetInput();
447
+ }
448
+ return;
449
+ case "date_range":
450
+ if (dateRangeValue[0] && dateRangeValue[1]) {
451
+ const updatedFilters = activeFilters.map(
452
+ (f) => f.id === editingFilterId ? {
453
+ ...f,
454
+ value: dateRangeValue,
455
+ displayValue: formatters.formatDateRange(dateRangeValue[0], dateRangeValue[1]),
456
+ operator: selectedOperator
457
+ } : f
458
+ );
459
+ onChange(updatedFilters);
460
+ setEditingFilterId(null);
461
+ setEditingPart(null);
462
+ resetInput();
463
+ }
464
+ return;
465
+ case "select":
466
+ if (inputValue) {
467
+ const option = selectedField.options?.find((o) => o.value === inputValue);
468
+ const updatedFilters = activeFilters.map(
469
+ (f) => f.id === editingFilterId ? {
470
+ ...f,
471
+ value: inputValue,
472
+ displayValue: option?.label || inputValue,
473
+ operator: selectedOperator
474
+ } : f
475
+ );
476
+ onChange(updatedFilters);
477
+ setEditingFilterId(null);
478
+ setEditingPart(null);
479
+ resetInput();
480
+ }
481
+ return;
482
+ case "multi_select":
483
+ if (multiSelectValues.length > 0) {
484
+ const labels = multiSelectValues.map((v) => selectedField.options?.find((o) => o.value === v)?.label || v).join(", ");
485
+ const updatedFilters = activeFilters.map(
486
+ (f) => f.id === editingFilterId ? {
487
+ ...f,
488
+ value: multiSelectValues,
489
+ displayValue: labels,
490
+ operator: selectedOperator
491
+ } : f
492
+ );
493
+ onChange(updatedFilters);
494
+ setEditingFilterId(null);
495
+ setEditingPart(null);
496
+ resetInput();
497
+ }
498
+ return;
499
+ }
500
+ }
501
+ switch (selectedField.type) {
502
+ case "text":
503
+ case "email":
504
+ case "number":
505
+ if (inputValue.trim()) {
506
+ addFilter(inputValue.trim(), inputValue.trim());
507
+ }
508
+ break;
509
+ case "date":
510
+ if (dateValue) {
511
+ addFilter(formatters.formatDate(dateValue), dateValue.toISOString());
512
+ }
513
+ break;
514
+ case "date_range":
515
+ if (dateRangeValue[0] && dateRangeValue[1]) {
516
+ addFilter(formatters.formatDateRange(dateRangeValue[0], dateRangeValue[1]), dateRangeValue);
517
+ }
518
+ break;
519
+ case "select":
520
+ if (inputValue) {
521
+ const option = selectedField.options?.find((o) => o.value === inputValue);
522
+ addFilter(option?.label || inputValue, inputValue);
523
+ }
524
+ break;
525
+ case "multi_select":
526
+ if (multiSelectValues.length > 0) {
527
+ const labels = multiSelectValues.map((v) => selectedField.options?.find((o) => o.value === v)?.label || v).join(", ");
528
+ addFilter(labels, multiSelectValues);
529
+ }
530
+ break;
531
+ }
532
+ }, [selectedField, selectedOperator, inputValue, dateValue, dateRangeValue, multiSelectValues, addFilter, editingFilterId, editingPart, activeFilters, onChange, resetInput]);
533
+ const handleOptionSelect = React.useCallback(
534
+ (value) => {
535
+ if (!selectedField) {
536
+ return;
537
+ }
538
+ if (selectedField.type === "multi_select") {
539
+ setMultiSelectValues(
540
+ (prev) => prev.includes(value) ? prev.filter((v) => v !== value) : [...prev, value]
541
+ );
542
+ } else {
543
+ const option = selectedField.options?.find((o) => o.value === value);
544
+ if (editingFilterId && editingPart === "value" && selectedOperator) {
545
+ const updatedFilters = activeFilters.map(
546
+ (f) => f.id === editingFilterId ? {
547
+ ...f,
548
+ value,
549
+ displayValue: option?.label || value,
550
+ operator: selectedOperator
551
+ } : f
552
+ );
553
+ onChange(updatedFilters);
554
+ setEditingFilterId(null);
555
+ setEditingPart(null);
556
+ resetInput();
557
+ } else {
558
+ addFilter(option?.label || value, value);
559
+ }
560
+ }
561
+ },
562
+ [selectedField, addFilter, editingFilterId, editingPart, selectedOperator, activeFilters, onChange, resetInput]
563
+ );
564
+ const handleKeyDown = React.useCallback(
565
+ (e) => {
566
+ if (e.key === "Enter" && inputStep === "value") {
567
+ e.preventDefault();
568
+ if (selectedField?.type === "multi_select" && multiSelectValues.length > 0) {
569
+ handleValueSubmit();
570
+ } else if (["text", "email", "number"].includes(selectedField?.type || "")) {
571
+ handleValueSubmit();
572
+ }
573
+ }
574
+ if (e.key === "Escape") {
575
+ resetInput();
576
+ combobox.closeDropdown();
577
+ }
578
+ if (e.key === "Backspace" && !inputValue) {
579
+ if (inputStep === "value") {
580
+ e.preventDefault();
581
+ setSelectedOperator(null);
582
+ setInputStep("operator");
583
+ setDateValue(null);
584
+ setDateRangeValue([null, null]);
585
+ setMultiSelectValues([]);
586
+ } else if (inputStep === "operator") {
587
+ e.preventDefault();
588
+ setSelectedField(null);
589
+ setInputStep("field");
590
+ } else if (inputStep === "field" && activeFilters.length > 0) {
591
+ handleRemoveFilter(activeFilters[activeFilters.length - 1].id);
592
+ }
593
+ }
594
+ },
595
+ [inputStep, selectedField, multiSelectValues, handleValueSubmit, inputValue, activeFilters, resetInput, combobox, handleRemoveFilter]
596
+ );
597
+ const handleSavePreset = React.useCallback(() => {
598
+ savePreset(activeFilters);
599
+ }, [activeFilters, savePreset]);
600
+ const showDropdown = inputStep === "field" || inputStep === "operator" || inputStep === "value" && (selectedField?.type === "select" || selectedField?.type === "multi_select");
601
+ const shouldShowDateInput = inputStep === "value" && (selectedField?.type === "date" || selectedField?.type === "date_range");
602
+ const getInputPlaceholder = () => {
603
+ if (inputStep === "field") {
604
+ return placeholder;
605
+ }
606
+ if (inputStep === "operator") {
607
+ return operatorPlaceholder;
608
+ }
609
+ if (inputStep === "value") {
610
+ if (selectedField?.type === "select" || selectedField?.type === "multi_select") {
611
+ return searchPlaceholder;
612
+ }
613
+ return selectedField?.placeholder || valuePlaceholder;
614
+ }
615
+ return placeholder;
616
+ };
617
+ const renderValueInput = () => {
618
+ if (!selectedField || inputStep !== "value") {
619
+ return null;
620
+ }
621
+ switch (selectedField.type) {
622
+ case "date":
623
+ return /* @__PURE__ */ React.createElement(
624
+ DateValueInput.DateValueInput,
625
+ {
626
+ value: dateValue,
627
+ onChange: setDateValue,
628
+ onComplete: addFilter,
629
+ onCancel: resetInput
630
+ }
631
+ );
632
+ case "date_range":
633
+ return /* @__PURE__ */ React.createElement(
634
+ DateRangeValueInput.DateRangeValueInput,
635
+ {
636
+ value: dateRangeValue,
637
+ onChange: setDateRangeValue,
638
+ onComplete: addFilter,
639
+ onCancel: resetInput
640
+ }
641
+ );
642
+ default:
643
+ return null;
644
+ }
645
+ };
646
+ const renderDropdownContent = () => {
647
+ if (inputStep === "field") {
648
+ return /* @__PURE__ */ React.createElement(
649
+ FieldDropdown.FieldDropdown,
650
+ {
651
+ fields: filteredFields
652
+ }
653
+ );
654
+ }
655
+ if (inputStep === "operator" && selectedField) {
656
+ return /* @__PURE__ */ React.createElement(
657
+ OperatorDropdown.OperatorDropdown,
658
+ {
659
+ field: selectedField
660
+ }
661
+ );
662
+ }
663
+ if (inputStep === "value" && selectedField) {
664
+ return /* @__PURE__ */ React.createElement(
665
+ ValueDropdown.ValueDropdown,
666
+ {
667
+ field: selectedField,
668
+ options: filteredOptions,
669
+ selectedValues: multiSelectValues,
670
+ onSubmit: handleValueSubmit
671
+ }
672
+ );
673
+ }
674
+ return null;
675
+ };
676
+ return /* @__PURE__ */ React.createElement(
677
+ core.Box,
678
+ {
679
+ className: clsx.clsx(getClassName("root"), className),
680
+ style: { ...resolvedStyles.root, ...boxProps.style },
681
+ ...boxProps
682
+ },
683
+ /* @__PURE__ */ React.createElement(
684
+ core.Combobox,
685
+ {
686
+ store: combobox,
687
+ onOptionSubmit: (val) => {
688
+ if (inputStep === "field") {
689
+ const field = filters.find((f) => f.key === val);
690
+ if (field) {
691
+ handleFieldSelect(field);
692
+ }
693
+ } else if (inputStep === "operator") {
694
+ handleOperatorSelect(val);
695
+ } else if (inputStep === "value") {
696
+ handleOptionSelect(val);
697
+ }
698
+ },
699
+ position: "bottom-start",
700
+ offset: 4,
701
+ middlewares: { flip: true, shift: true },
702
+ withinPortal: true
703
+ },
704
+ /* @__PURE__ */ React.createElement(core.Combobox.DropdownTarget, null, /* @__PURE__ */ React.createElement(
705
+ "div",
706
+ {
707
+ role: "button",
708
+ tabIndex: 0,
709
+ onClick: () => {
710
+ if (!isInputDisabled) {
711
+ inputRef.current?.focus();
712
+ combobox.openDropdown();
713
+ combobox.selectFirstOption();
714
+ }
715
+ },
716
+ onFocus: (e) => {
717
+ if (e.target === e.currentTarget && !isInputDisabled) {
718
+ inputRef.current?.focus();
719
+ combobox.openDropdown();
720
+ combobox.selectFirstOption();
721
+ }
722
+ },
723
+ onKeyDown: (e) => {
724
+ const isInput = e.target.tagName === "INPUT";
725
+ if ((e.key === "Enter" || e.key === " ") && !isInput) {
726
+ e.preventDefault();
727
+ if (!isInputDisabled) {
728
+ combobox.openDropdown();
729
+ combobox.selectFirstOption();
730
+ }
731
+ }
732
+ },
733
+ className: getClassName("container"),
734
+ style: resolvedStyles.container
735
+ },
736
+ /* @__PURE__ */ React.createElement(
737
+ core.ActionIcon,
738
+ {
739
+ color: "gray",
740
+ variant: "subtle",
741
+ size: "md",
742
+ pl: "xs",
743
+ className: getClassName("leftIcon"),
744
+ style: resolvedStyles.leftIcon
745
+ },
746
+ /* @__PURE__ */ React.createElement(iconsReact.IconSearch, { size: 16 })
747
+ ),
748
+ /* @__PURE__ */ React.createElement(
749
+ "div",
750
+ {
751
+ ref: pillsContainerRef,
752
+ className: clsx.clsx(
753
+ getClassName("pillsContainer"),
754
+ overflowMode === "scroll" ? CompositeFiltersInput_module.pillsContainerScroll : CompositeFiltersInput_module.pillsContainerWrap
755
+ ),
756
+ style: resolvedStyles.pillsContainer
757
+ },
758
+ activeFilters.map((filter) => renderPill ? renderPill(filter, () => handleRemoveFilter(filter.id)) : /* @__PURE__ */ React.createElement(
759
+ FilterPill.FilterPill,
760
+ {
761
+ key: filter.id,
762
+ filter,
763
+ onRemove: handleRemoveFilter,
764
+ onOperatorClick: handleFilterOperatorClick,
765
+ onValueClick: handleFilterValueClick,
766
+ isHighlighted: highlightedFilterId === filter.id,
767
+ isCompact: isCompactMode
768
+ }
769
+ )),
770
+ inputStep !== "field" && selectedField && /* @__PURE__ */ React.createElement(
771
+ CurrentFieldIndicator.CurrentFieldIndicator,
772
+ {
773
+ field: selectedField,
774
+ operator: selectedOperator,
775
+ showValueIndicator: inputStep === "value" && !shouldShowDateInput,
776
+ isCompact: isCompactMode
777
+ }
778
+ ),
779
+ shouldShowDateInput ? renderValueInput() : /* @__PURE__ */ React.createElement(core.Combobox.EventsTarget, null, /* @__PURE__ */ React.createElement(
780
+ "input",
781
+ {
782
+ ref: inputRef,
783
+ value: inputValue,
784
+ onChange: (e) => {
785
+ setInputValue(e.currentTarget.value);
786
+ combobox.openDropdown();
787
+ combobox.selectFirstOption();
788
+ },
789
+ onFocus: () => {
790
+ setIsFocused(true);
791
+ combobox.openDropdown();
792
+ combobox.selectFirstOption();
793
+ if (overflowMode === "scroll" && pillsContainerRef.current && inputRef.current) {
794
+ const container = pillsContainerRef.current;
795
+ const input = inputRef.current;
796
+ const containerRect = container.getBoundingClientRect();
797
+ const inputRect = input.getBoundingClientRect();
798
+ const inputLeft = inputRect.left - containerRect.left + container.scrollLeft;
799
+ const inputWidth = inputRect.width;
800
+ const containerWidth = containerRect.width;
801
+ const scrollPosition = inputLeft - containerWidth / 2 + inputWidth / 2;
802
+ container.scrollTo({
803
+ left: Math.max(0, scrollPosition),
804
+ behavior: "smooth"
805
+ });
806
+ }
807
+ },
808
+ onBlur: () => {
809
+ setIsFocused(false);
810
+ combobox.closeDropdown();
811
+ if (overflowMode === "scroll" && pillsContainerRef.current) {
812
+ pillsContainerRef.current.scrollTo({
813
+ left: 0,
814
+ behavior: "smooth"
815
+ });
816
+ }
817
+ },
818
+ onKeyDown: handleKeyDown,
819
+ placeholder: getInputPlaceholder(),
820
+ disabled: isInputDisabled,
821
+ className: getClassName("input"),
822
+ style: resolvedStyles.input
823
+ }
824
+ ))
825
+ ),
826
+ /* @__PURE__ */ React.createElement(
827
+ "div",
828
+ {
829
+ className: getClassName("rightSection"),
830
+ style: resolvedStyles.rightSection
831
+ },
832
+ activeFilters.length > 0 && /* @__PURE__ */ React.createElement(React.Fragment, null, showFilterCount && /* @__PURE__ */ React.createElement(
833
+ core.Badge,
834
+ {
835
+ variant: "filled",
836
+ size: "xs",
837
+ className: getClassName("badge"),
838
+ style: resolvedStyles.badge
839
+ },
840
+ activeFilters.length
841
+ ), /* @__PURE__ */ React.createElement(core.Tooltip, { label: "Clear all (\u2318+\u232B)", withArrow: true }, /* @__PURE__ */ React.createElement(
842
+ core.ActionIcon,
843
+ {
844
+ color: "red",
845
+ variant: "light",
846
+ size: "sm",
847
+ className: getClassName("clearButton"),
848
+ style: resolvedStyles.clearButton,
849
+ onClick: (e) => {
850
+ e.stopPropagation();
851
+ handleClearAll();
852
+ }
853
+ },
854
+ /* @__PURE__ */ React.createElement(iconsReact.IconX, { size: 14 })
855
+ ))),
856
+ /* @__PURE__ */ React.createElement(
857
+ FilterActionsMenu.FilterActionsMenu,
858
+ {
859
+ activeFilters,
860
+ onChange,
861
+ isCompactMode,
862
+ setIsCompactMode,
863
+ showFilterCount,
864
+ setShowFilterCount,
865
+ savedPresets,
866
+ onSavePreset: handleSavePreset,
867
+ onLoadPreset: loadPreset,
868
+ onTogglePresetFavorite: togglePresetFavorite,
869
+ onDeletePreset: deletePreset,
870
+ filterHistory,
871
+ customActions,
872
+ disablePresets,
873
+ disableHistory
874
+ }
875
+ )
876
+ )
877
+ )),
878
+ showDropdown && /* @__PURE__ */ React.createElement(
879
+ core.Combobox.Dropdown,
880
+ {
881
+ className: getClassName("dropdown"),
882
+ style: resolvedStyles.dropdown
883
+ },
884
+ renderDropdownContent()
885
+ )
886
+ ),
887
+ maxFilters !== void 0 && activeFilters.length >= maxFilters && /* @__PURE__ */ React.createElement(FilterMaxReached.FilterMaxReached, { maxFilters })
888
+ );
889
+ };
890
+ const CompositeFiltersInput = Object.assign(CompositeFiltersInputBase, {
891
+ classes: CompositeFiltersInput_classes.CompositeFiltersInputClasses
892
+ });
893
+
894
+ exports.CompositeFiltersInput = CompositeFiltersInput;
895
+ exports.default = CompositeFiltersInput;
896
+ //# sourceMappingURL=CompositeFiltersInput.cjs.map