@redsift/table-pro 12.5.4
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/CONTRIBUTING.md +435 -0
- package/_internal/BaseComponents.js +3 -0
- package/_internal/BaseComponents.js.map +1 -0
- package/_internal/BaseIconButton.js +126 -0
- package/_internal/BaseIconButton.js.map +1 -0
- package/_internal/BaseTextField.js +26 -0
- package/_internal/BaseTextField.js.map +1 -0
- package/_internal/DataGrid.js +2 -0
- package/_internal/DataGrid.js.map +1 -0
- package/_internal/DataGrid2.js +507 -0
- package/_internal/DataGrid2.js.map +1 -0
- package/_internal/GridToolbarFilterSemanticField.js +2 -0
- package/_internal/GridToolbarFilterSemanticField.js.map +1 -0
- package/_internal/GridToolbarFilterSemanticField2.js +6962 -0
- package/_internal/GridToolbarFilterSemanticField2.js.map +1 -0
- package/_internal/Pagination.js +2 -0
- package/_internal/Pagination.js.map +1 -0
- package/_internal/ServerSideControlledPagination.js +324 -0
- package/_internal/ServerSideControlledPagination.js.map +1 -0
- package/_internal/StatefulDataGrid.js +2 -0
- package/_internal/StatefulDataGrid.js.map +1 -0
- package/_internal/StatefulDataGrid2.js +3237 -0
- package/_internal/StatefulDataGrid2.js.map +1 -0
- package/_internal/TextCell.js +2 -0
- package/_internal/TextCell.js.map +1 -0
- package/_internal/TextCell2.js +66 -0
- package/_internal/TextCell2.js.map +1 -0
- package/_internal/Toolbar.js +2 -0
- package/_internal/Toolbar.js.map +1 -0
- package/_internal/Toolbar2.js +102 -0
- package/_internal/Toolbar2.js.map +1 -0
- package/_internal/ToolbarWrapper.js +2 -0
- package/_internal/ToolbarWrapper.js.map +1 -0
- package/_internal/ToolbarWrapper2.js +53 -0
- package/_internal/ToolbarWrapper2.js.map +1 -0
- package/_internal/_rollupPluginBabelHelpers.js +93 -0
- package/_internal/_rollupPluginBabelHelpers.js.map +1 -0
- package/_internal/useControlledDatagridState.js +170 -0
- package/_internal/useControlledDatagridState.js.map +1 -0
- package/index.d.ts +1223 -0
- package/index.js +721 -0
- package/index.js.map +1 -0
- package/package.json +96 -0
- package/style/index.css +7 -0
package/index.js
ADDED
|
@@ -0,0 +1,721 @@
|
|
|
1
|
+
import { o as operatorList, D as DOES_NOT_CONTAIN, a as DOES_NOT_EQUAL, b as DOES_NOT_START_WITH, c as DOES_NOT_END_WITH, I as IS_ANY_OF, d as IS_NOT_ANY_OF, C as CONTAINS_ANY_OF, e as DOES_NOT_CONTAIN_ANY_OF, S as STARTS_WITH_ANY_OF, f as DOES_NOT_START_WITH_ANY_OF, E as ENDS_WITH_ANY_OF, g as DOES_NOT_END_WITH_ANY_OF, h as IS_BETWEEN, i as IS_WITH_SELECT, j as IS_NOT_WITH_SELECT, k as IS_ANY_OF_WITH_SELECT, l as IS_NOT_ANY_OF_WITH_SELECT, A as ARRAY_IS_EMPTY, m as ARRAY_IS_NOT_EMPTY, H as HAS_WITH_SELECT, n as DOES_NOT_HAVE_WITH_SELECT, p as HAS_ANY_OF_WITH_SELECT, q as HAS_ALL_OF_WITH_SELECT, r as DOES_NOT_HAVE_ANY_OF_WITH_SELECT, s as HAS_ONLY_WITH_SELECT, t as HAS, u as DOES_NOT_HAVE, v as HAS_ANY_OF, w as HAS_ALL_OF, x as DOES_NOT_HAVE_ANY_OF, y as HAS_ONLY } from './_internal/StatefulDataGrid2.js';
|
|
2
|
+
export { A as ARRAY_IS_EMPTY, m as ARRAY_IS_NOT_EMPTY, W as CATEGORIES, U as COLUMN_ORDER_MODEL_KEY, C as CONTAINS_ANY_OF, T as DENSITY_MODEL_KEY, Q as DIMENSION_MODEL_KEY, D as DOES_NOT_CONTAIN, e as DOES_NOT_CONTAIN_ANY_OF, c as DOES_NOT_END_WITH, g as DOES_NOT_END_WITH_ANY_OF, a as DOES_NOT_EQUAL, u as DOES_NOT_HAVE, x as DOES_NOT_HAVE_ANY_OF, r as DOES_NOT_HAVE_ANY_OF_WITH_SELECT, n as DOES_NOT_HAVE_WITH_SELECT, b as DOES_NOT_START_WITH, f as DOES_NOT_START_WITH_ANY_OF, E as ENDS_WITH_ANY_OF, M as FILTER_MODEL_KEY, R as FILTER_SEARCH_KEY, t as HAS, w as HAS_ALL_OF, q as HAS_ALL_OF_WITH_SELECT, v as HAS_ANY_OF, p as HAS_ANY_OF_WITH_SELECT, y as HAS_ONLY, s as HAS_ONLY_WITH_SELECT, H as HAS_WITH_SELECT, B as IS, I as IS_ANY_OF, k as IS_ANY_OF_WITH_SELECT, h as IS_BETWEEN, F as IS_NOT, d as IS_NOT_ANY_OF, l as IS_NOT_ANY_OF_WITH_SELECT, j as IS_NOT_WITH_SELECT, i as IS_WITH_SELECT, P as PAGINATION_MODEL_KEY, O as PINNED_COLUMNS, N as SORT_MODEL_KEY, S as STARTS_WITH_ANY_OF, av as StatefulDataGrid, V as VISIBILITY_MODEL_KEY, au as areFilterModelsEquivalent, a3 as areSearchStringsEqual, a2 as buildQueryParamsString, X as buildStorageKey, Z as clearAllVersionStorage, Y as clearPreviousVersionStorage, a0 as convertFromDisplayFormat, $ as convertToDisplayFormat, a4 as decodeValue, a5 as encodeValue, ap as getColumnOrderFromString, ah as getColumnVisibilityFromString, a1 as getDecodedSearchFromUrl, am as getDensityFromString, ao as getDensityModel, ab as getFilterModelFromString, ar as getFinalSearch, z as getGridNumericOperators, J as getGridStringArrayOperators, K as getGridStringArrayOperatorsWithSelect, L as getGridStringArrayOperatorsWithSelectOnStringArrayColumns, G as getGridStringOperators, as as getModelsParsedOrUpdateLocalStorage, af as getPaginationFromString, aj as getPinnedColumnsFromString, aq as getSearchParamsFromColumnOrder, ai as getSearchParamsFromColumnVisibility, an as getSearchParamsFromDensity, ac as getSearchParamsFromFilterModel, ag as getSearchParamsFromPagination, ak as getSearchParamsFromPinnedColumns, ae as getSearchParamsFromSorting, al as getSearchParamsFromTab, ad as getSortingFromString, a9 as isOperatorValueValid, aa as isValueValid, a8 as numberOperatorDecoder, a7 as numberOperatorEncoder, o as operatorList, _ as resetStatefulDataGridState, at as updateUrl, a6 as urlSearchParamsToString } from './_internal/StatefulDataGrid2.js';
|
|
3
|
+
import { GRID_DETAIL_PANEL_TOGGLE_COL_DEF, GridFilterInputMultipleValue, GridFilterInputMultipleSingleSelect, getGridDateOperators, getGridStringOperators, getGridNumericOperators } from '@mui/x-data-grid-pro';
|
|
4
|
+
export { getGridBooleanOperators, getGridDateOperators, getGridSingleSelectOperators } from '@mui/x-data-grid-pro';
|
|
5
|
+
import { _ as _objectSpread2 } from './_internal/_rollupPluginBabelHelpers.js';
|
|
6
|
+
import * as React from 'react';
|
|
7
|
+
import { useState, useRef, useEffect, useCallback, useMemo } from 'react';
|
|
8
|
+
import Box from '@mui/material/Box';
|
|
9
|
+
import TextField from '@mui/material/TextField';
|
|
10
|
+
import { Icon } from '@redsift/design-system';
|
|
11
|
+
import { mdiSync } from '@redsift/icons';
|
|
12
|
+
export { D as DEFAULT_OPERATORS, G as GridToolbarFilterSemanticField, g as getCompletion } from './_internal/GridToolbarFilterSemanticField2.js';
|
|
13
|
+
export { C as ControlledPagination, E as EMPTY_ROW_SELECTION_MODEL, S as ServerSideControlledPagination, c as createRowSelectionModel, f as fixServerSideHeaderCheckboxSelection, b as getSelectableRowIdsInPage, a as getSelectedIds, g as getSelectionCount, i as isRowSelected, n as normalizeRowSelectionModel, o as onServerSideSelectionStatusChange } from './_internal/ServerSideControlledPagination.js';
|
|
14
|
+
export { B as BaseButton, a as BaseCheckbox, b as BaseIcon, c as BaseIconButton, m as muiIconToDSIcon } from './_internal/BaseIconButton.js';
|
|
15
|
+
export { B as BaseTextField } from './_internal/BaseTextField.js';
|
|
16
|
+
export { D as DataGrid } from './_internal/DataGrid2.js';
|
|
17
|
+
export { T as TextCell } from './_internal/TextCell2.js';
|
|
18
|
+
export { T as Toolbar } from './_internal/Toolbar2.js';
|
|
19
|
+
export { T as ToolbarWrapper } from './_internal/ToolbarWrapper2.js';
|
|
20
|
+
|
|
21
|
+
// Don't use a spread operator there or it will break the build due to MUI internal components
|
|
22
|
+
const DETAIL_PANEL_TOGGLE_COL_DEF = GRID_DETAIL_PANEL_TOGGLE_COL_DEF;
|
|
23
|
+
DETAIL_PANEL_TOGGLE_COL_DEF.type = 'actions';
|
|
24
|
+
|
|
25
|
+
const isAnyOfIOperator = {
|
|
26
|
+
label: 'is any of (case-insensitive)',
|
|
27
|
+
value: 'isAnyOfI',
|
|
28
|
+
getApplyFilterFn: filterItem => {
|
|
29
|
+
if (!filterItem.field || !filterItem.value || !filterItem.operator) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
const lowerCaseFilterValues = filterItem.value.map(v => String(v).toLowerCase());
|
|
33
|
+
return value => {
|
|
34
|
+
if (filterItem.value.length === 0) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
if (value == null) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
const paramValues = Array.isArray(value) ? value : [value];
|
|
41
|
+
for (const paramValue of paramValues) {
|
|
42
|
+
if (lowerCaseFilterValues.includes(String(paramValue).toLowerCase())) {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
InputComponent: GridFilterInputMultipleValue
|
|
50
|
+
};
|
|
51
|
+
const IS_ANY_OF_I = isAnyOfIOperator;
|
|
52
|
+
const IS_ANY_OF_I_WITH_SELECT = _objectSpread2(_objectSpread2({}, IS_ANY_OF_I), {}, {
|
|
53
|
+
InputComponent: GridFilterInputMultipleSingleSelect
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const SUBMIT_FILTER_STROKE_TIME = 500;
|
|
57
|
+
const InputDateInterval = props => {
|
|
58
|
+
var _item$value, _filterValueState$, _filterValueState$2;
|
|
59
|
+
const {
|
|
60
|
+
item,
|
|
61
|
+
applyValue,
|
|
62
|
+
focusElementRef = null
|
|
63
|
+
} = props;
|
|
64
|
+
const filterTimeout = React.useRef();
|
|
65
|
+
const [filterValueState, setFilterValueState] = React.useState((_item$value = item.value) !== null && _item$value !== void 0 ? _item$value : ['', '']);
|
|
66
|
+
const [applying, setIsApplying] = React.useState(false);
|
|
67
|
+
React.useEffect(() => {
|
|
68
|
+
return () => {
|
|
69
|
+
clearTimeout(filterTimeout.current);
|
|
70
|
+
};
|
|
71
|
+
}, []);
|
|
72
|
+
React.useEffect(() => {
|
|
73
|
+
var _item$value2;
|
|
74
|
+
const itemValue = (_item$value2 = item.value) !== null && _item$value2 !== void 0 ? _item$value2 : ['', ''];
|
|
75
|
+
setFilterValueState(itemValue);
|
|
76
|
+
}, [item.value]);
|
|
77
|
+
const updateFilterValue = (from, to) => {
|
|
78
|
+
clearTimeout(filterTimeout.current);
|
|
79
|
+
setFilterValueState([from, to]);
|
|
80
|
+
setIsApplying(true);
|
|
81
|
+
filterTimeout.current = setTimeout(() => {
|
|
82
|
+
setIsApplying(false);
|
|
83
|
+
applyValue(_objectSpread2(_objectSpread2({}, item), {}, {
|
|
84
|
+
value: [from, to]
|
|
85
|
+
}));
|
|
86
|
+
}, SUBMIT_FILTER_STROKE_TIME);
|
|
87
|
+
};
|
|
88
|
+
const handleFromChange = event => {
|
|
89
|
+
const newFrom = event.target.value;
|
|
90
|
+
updateFilterValue(newFrom, filterValueState[1]);
|
|
91
|
+
};
|
|
92
|
+
const handleToChange = event => {
|
|
93
|
+
const newTo = event.target.value;
|
|
94
|
+
updateFilterValue(filterValueState[0], newTo);
|
|
95
|
+
};
|
|
96
|
+
return /*#__PURE__*/React.createElement(Box, {
|
|
97
|
+
sx: {
|
|
98
|
+
display: 'inline-flex',
|
|
99
|
+
flexDirection: 'row',
|
|
100
|
+
alignItems: 'end',
|
|
101
|
+
height: 48,
|
|
102
|
+
pl: '20px'
|
|
103
|
+
}
|
|
104
|
+
}, /*#__PURE__*/React.createElement(TextField, {
|
|
105
|
+
name: "date-from-input",
|
|
106
|
+
placeholder: "From",
|
|
107
|
+
label: "From",
|
|
108
|
+
variant: "standard",
|
|
109
|
+
value: (_filterValueState$ = filterValueState[0]) !== null && _filterValueState$ !== void 0 ? _filterValueState$ : '',
|
|
110
|
+
onChange: handleFromChange,
|
|
111
|
+
type: "date",
|
|
112
|
+
inputRef: focusElementRef,
|
|
113
|
+
sx: {
|
|
114
|
+
mr: 2
|
|
115
|
+
},
|
|
116
|
+
InputLabelProps: {
|
|
117
|
+
shrink: true
|
|
118
|
+
}
|
|
119
|
+
}), /*#__PURE__*/React.createElement(TextField, {
|
|
120
|
+
name: "date-to-input",
|
|
121
|
+
placeholder: "To",
|
|
122
|
+
label: "To",
|
|
123
|
+
variant: "standard",
|
|
124
|
+
value: (_filterValueState$2 = filterValueState[1]) !== null && _filterValueState$2 !== void 0 ? _filterValueState$2 : '',
|
|
125
|
+
onChange: handleToChange,
|
|
126
|
+
type: "date",
|
|
127
|
+
InputProps: applying ? {
|
|
128
|
+
endAdornment: /*#__PURE__*/React.createElement(Icon, {
|
|
129
|
+
icon: mdiSync
|
|
130
|
+
})
|
|
131
|
+
} : {},
|
|
132
|
+
InputLabelProps: {
|
|
133
|
+
shrink: true
|
|
134
|
+
}
|
|
135
|
+
}));
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const isBetweenOperator = {
|
|
139
|
+
label: 'is between',
|
|
140
|
+
value: 'isBetween',
|
|
141
|
+
getApplyFilterFn: filterItem => {
|
|
142
|
+
if (!filterItem.field || !filterItem.value || !filterItem.operator) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
if (!Array.isArray(filterItem.value) || filterItem.value.length !== 2) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
if (!filterItem.value[0] || !filterItem.value[1]) {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Parse as local time (not UTC) since the date input produces YYYY-MM-DD
|
|
153
|
+
// strings representing dates in the user's local timezone.
|
|
154
|
+
const [fromYear, fromMonth, fromDay] = filterItem.value[0].split('-').map(Number);
|
|
155
|
+
const [toYear, toMonth, toDay] = filterItem.value[1].split('-').map(Number);
|
|
156
|
+
const fromTime = new Date(fromYear, fromMonth - 1, fromDay).getTime();
|
|
157
|
+
// Set upper bound to end-of-day so dateTime values later that day are included.
|
|
158
|
+
const toTime = new Date(toYear, toMonth - 1, toDay, 23, 59, 59, 999).getTime();
|
|
159
|
+
if (isNaN(fromTime) || isNaN(toTime)) {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
return value => {
|
|
163
|
+
if (value == null) {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
const cellTime = value instanceof Date ? value.getTime() : new Date(value).getTime();
|
|
167
|
+
if (isNaN(cellTime)) {
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
return cellTime >= fromTime && cellTime <= toTime;
|
|
171
|
+
};
|
|
172
|
+
},
|
|
173
|
+
InputComponent: InputDateInterval
|
|
174
|
+
};
|
|
175
|
+
const DATE_IS_BETWEEN = isBetweenOperator;
|
|
176
|
+
|
|
177
|
+
const getGridDateOperatorsExtended = function () {
|
|
178
|
+
let showTime = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
|
|
179
|
+
return [...getGridDateOperators(showTime), DATE_IS_BETWEEN];
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
const lowercaseValue = value => {
|
|
183
|
+
if (typeof value === 'string') {
|
|
184
|
+
return value.toLowerCase();
|
|
185
|
+
}
|
|
186
|
+
if (Array.isArray(value)) {
|
|
187
|
+
return value.map(lowercaseValue);
|
|
188
|
+
}
|
|
189
|
+
return value;
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Wraps a filter operator's `getApplyFilterFn` to lowercase both the cell value
|
|
194
|
+
* and the filter value before comparison, making the operator case-insensitive.
|
|
195
|
+
*
|
|
196
|
+
* Only affects string-based values — numbers, dates, and booleans pass through unchanged.
|
|
197
|
+
*/
|
|
198
|
+
const wrapCaseInsensitive = operator => {
|
|
199
|
+
const originalGetApplyFilterFn = operator.getApplyFilterFn;
|
|
200
|
+
return _objectSpread2(_objectSpread2({}, operator), {}, {
|
|
201
|
+
getApplyFilterFn: (filterItem, column) => {
|
|
202
|
+
const caseInsensitiveFilterItem = _objectSpread2(_objectSpread2({}, filterItem), {}, {
|
|
203
|
+
value: lowercaseValue(filterItem.value)
|
|
204
|
+
});
|
|
205
|
+
const originalFn = originalGetApplyFilterFn(caseInsensitiveFilterItem, column);
|
|
206
|
+
if (!originalFn) {
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
return (value, row, column, apiRef) => {
|
|
210
|
+
const lowercasedValue = lowercaseValue(value);
|
|
211
|
+
return originalFn(lowercasedValue, row, column, apiRef);
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Applies case-insensitive wrapping to an array of filter operators.
|
|
219
|
+
*/
|
|
220
|
+
const makeCaseInsensitive = operators => {
|
|
221
|
+
return operators.map(wrapCaseInsensitive);
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
const getRsStringColumnType = () => {
|
|
225
|
+
return {
|
|
226
|
+
type: 'string',
|
|
227
|
+
filterOperators: operatorList.rsString
|
|
228
|
+
};
|
|
229
|
+
};
|
|
230
|
+
const getRsNumberColumnType = () => {
|
|
231
|
+
return {
|
|
232
|
+
type: 'number',
|
|
233
|
+
filterOperators: operatorList.rsNumber
|
|
234
|
+
};
|
|
235
|
+
};
|
|
236
|
+
const getRsSingleSelectColumnType = () => {
|
|
237
|
+
return {
|
|
238
|
+
type: 'singleSelect',
|
|
239
|
+
filterOperators: operatorList.rsSingleSelect
|
|
240
|
+
};
|
|
241
|
+
};
|
|
242
|
+
const getRsSingleSelectWithShortOperatorListColumnType = () => {
|
|
243
|
+
return {
|
|
244
|
+
type: 'singleSelect',
|
|
245
|
+
filterOperators: operatorList.rsSingleSelectWithShortOperatorList
|
|
246
|
+
};
|
|
247
|
+
};
|
|
248
|
+
const getRsMultipleSelectColumnType = () => {
|
|
249
|
+
return {
|
|
250
|
+
type: 'singleSelect',
|
|
251
|
+
filterOperators: operatorList.rsMultipleSelect
|
|
252
|
+
};
|
|
253
|
+
};
|
|
254
|
+
const getRsMultipleSelectWithShortOperatorListColumnType = () => {
|
|
255
|
+
return {
|
|
256
|
+
type: 'singleSelect',
|
|
257
|
+
filterOperators: operatorList.rsMultipleSelectWithShortOperatorList
|
|
258
|
+
};
|
|
259
|
+
};
|
|
260
|
+
const customColumnTypes = {
|
|
261
|
+
rsString: getRsStringColumnType(),
|
|
262
|
+
rsNumber: getRsNumberColumnType(),
|
|
263
|
+
rsSingleSelect: getRsSingleSelectColumnType(),
|
|
264
|
+
rsSingleSelectWithShortOperatorList: getRsSingleSelectWithShortOperatorListColumnType(),
|
|
265
|
+
rsMultipleSelect: getRsMultipleSelectColumnType(),
|
|
266
|
+
rsMultipleSelectWithShortOperatorList: getRsMultipleSelectWithShortOperatorListColumnType()
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
// ---------------------------------------------------------------------------
|
|
270
|
+
// Operator name unions (for typed `exclude`)
|
|
271
|
+
// ---------------------------------------------------------------------------
|
|
272
|
+
// ---------------------------------------------------------------------------
|
|
273
|
+
// Column type
|
|
274
|
+
// ---------------------------------------------------------------------------
|
|
275
|
+
// ---------------------------------------------------------------------------
|
|
276
|
+
// Options: discriminated union (built-in vs override)
|
|
277
|
+
// ---------------------------------------------------------------------------
|
|
278
|
+
// ---------------------------------------------------------------------------
|
|
279
|
+
// Full & compact operator lists
|
|
280
|
+
// ---------------------------------------------------------------------------
|
|
281
|
+
const getStringOperatorsFull = () => [...getGridStringOperators().filter(op => !['isAnyOf'].includes(op.value)), DOES_NOT_CONTAIN, DOES_NOT_EQUAL, DOES_NOT_START_WITH, DOES_NOT_END_WITH, IS_ANY_OF, IS_NOT_ANY_OF, CONTAINS_ANY_OF, DOES_NOT_CONTAIN_ANY_OF, STARTS_WITH_ANY_OF, DOES_NOT_START_WITH_ANY_OF, ENDS_WITH_ANY_OF, DOES_NOT_END_WITH_ANY_OF];
|
|
282
|
+
const getStringOperatorsCompact = () => [...getGridStringOperators().filter(op => !['isAnyOf', 'startsWith', 'endsWith'].includes(op.value)), DOES_NOT_CONTAIN, DOES_NOT_EQUAL, IS_ANY_OF];
|
|
283
|
+
const getNumberOperatorsFull = () => [...getGridNumericOperators(), IS_BETWEEN];
|
|
284
|
+
const getNumberOperatorsCompact = () => getGridNumericOperators();
|
|
285
|
+
const getDateOperatorsFull = showTime => [...getGridDateOperators(showTime), DATE_IS_BETWEEN];
|
|
286
|
+
const getDateOperatorsCompact = showTime => getGridDateOperators(showTime);
|
|
287
|
+
const getSingleSelectOperatorsFull = () => [IS_WITH_SELECT, IS_NOT_WITH_SELECT, IS_ANY_OF_WITH_SELECT, IS_NOT_ANY_OF_WITH_SELECT, ARRAY_IS_EMPTY, ARRAY_IS_NOT_EMPTY];
|
|
288
|
+
const getSingleSelectOperatorsCompact = () => [IS_WITH_SELECT, IS_NOT_WITH_SELECT, IS_ANY_OF_WITH_SELECT];
|
|
289
|
+
const getMultiSelectOperatorsFull = () => [HAS_WITH_SELECT, DOES_NOT_HAVE_WITH_SELECT, HAS_ANY_OF_WITH_SELECT, HAS_ALL_OF_WITH_SELECT, DOES_NOT_HAVE_ANY_OF_WITH_SELECT, HAS_ONLY_WITH_SELECT, ARRAY_IS_EMPTY, ARRAY_IS_NOT_EMPTY];
|
|
290
|
+
const getMultiSelectOperatorsCompact = () => [HAS_WITH_SELECT, DOES_NOT_HAVE_WITH_SELECT, HAS_ANY_OF_WITH_SELECT];
|
|
291
|
+
const getTagsOperatorsFull = () => [HAS, DOES_NOT_HAVE, HAS_ANY_OF, HAS_ALL_OF, DOES_NOT_HAVE_ANY_OF, HAS_ONLY, CONTAINS_ANY_OF, DOES_NOT_CONTAIN_ANY_OF, ARRAY_IS_EMPTY, ARRAY_IS_NOT_EMPTY];
|
|
292
|
+
const getTagsOperatorsCompact = () => [HAS, DOES_NOT_HAVE, HAS_ANY_OF];
|
|
293
|
+
|
|
294
|
+
// ---------------------------------------------------------------------------
|
|
295
|
+
// Helpers
|
|
296
|
+
// ---------------------------------------------------------------------------
|
|
297
|
+
|
|
298
|
+
const isOverrideOptions = options => {
|
|
299
|
+
return options && 'operators' in options;
|
|
300
|
+
};
|
|
301
|
+
const arraySortComparator = (a, b) => {
|
|
302
|
+
const arrA = Array.isArray(a) ? a : [];
|
|
303
|
+
const arrB = Array.isArray(b) ? b : [];
|
|
304
|
+
if (arrA.length !== arrB.length) {
|
|
305
|
+
return arrA.length - arrB.length;
|
|
306
|
+
}
|
|
307
|
+
const strA = arrA.map(String).sort().join(',');
|
|
308
|
+
const strB = arrB.map(String).sort().join(',');
|
|
309
|
+
return strA.localeCompare(strB);
|
|
310
|
+
};
|
|
311
|
+
const arrayValueFormatter = value => {
|
|
312
|
+
if (Array.isArray(value)) {
|
|
313
|
+
return value.map(String).join(', ');
|
|
314
|
+
}
|
|
315
|
+
return value != null ? String(value) : '';
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
// ---------------------------------------------------------------------------
|
|
319
|
+
// Operator type strings that support case-insensitive wrapping
|
|
320
|
+
// ---------------------------------------------------------------------------
|
|
321
|
+
|
|
322
|
+
const CASE_INSENSITIVE_TYPES = ['string', 'singleSelect', 'tags'];
|
|
323
|
+
|
|
324
|
+
// ---------------------------------------------------------------------------
|
|
325
|
+
// createColumn()
|
|
326
|
+
// ---------------------------------------------------------------------------
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Creates a column configuration with the appropriate MUI type and filter operators
|
|
330
|
+
* for the given column type. Spread the result into your column definition.
|
|
331
|
+
*
|
|
332
|
+
* @example
|
|
333
|
+
* ```tsx
|
|
334
|
+
* const columns = [
|
|
335
|
+
* { ...createColumn('string'), field: 'name', headerName: 'Name' },
|
|
336
|
+
* { ...createColumn('number'), field: 'price', headerName: 'Price' },
|
|
337
|
+
* { ...createColumn('singleSelect', { compact: true }), field: 'status', valueOptions: ['active', 'inactive'] },
|
|
338
|
+
* { ...createColumn('multiSelect'), field: 'tags', valueOptions: ['a', 'b', 'c'] },
|
|
339
|
+
* { ...createColumn('tags'), field: 'labels', headerName: 'Labels' },
|
|
340
|
+
* ];
|
|
341
|
+
* ```
|
|
342
|
+
*/
|
|
343
|
+
function createColumn(type, options) {
|
|
344
|
+
var _builtInOpts$compact, _builtInOpts$caseSens;
|
|
345
|
+
// Override mode: consumer provides full operator list
|
|
346
|
+
if (options && isOverrideOptions(options)) {
|
|
347
|
+
const result = {
|
|
348
|
+
type: getMuiType(type),
|
|
349
|
+
filterOperators: options.operators
|
|
350
|
+
};
|
|
351
|
+
if (type === 'multiSelect' || type === 'tags') {
|
|
352
|
+
result.sortComparator = arraySortComparator;
|
|
353
|
+
result.valueFormatter = arrayValueFormatter;
|
|
354
|
+
}
|
|
355
|
+
return result;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Built-in mode
|
|
359
|
+
const builtInOpts = options !== null && options !== void 0 ? options : {};
|
|
360
|
+
const compact = (_builtInOpts$compact = builtInOpts.compact) !== null && _builtInOpts$compact !== void 0 ? _builtInOpts$compact : false;
|
|
361
|
+
const caseSensitive = (_builtInOpts$caseSens = builtInOpts.caseSensitive) !== null && _builtInOpts$caseSens !== void 0 ? _builtInOpts$caseSens : false;
|
|
362
|
+
let operators = getOperatorsForType(type, compact);
|
|
363
|
+
|
|
364
|
+
// Apply exclude
|
|
365
|
+
if (builtInOpts.exclude && builtInOpts.exclude.length > 0) {
|
|
366
|
+
const excludeSet = new Set(builtInOpts.exclude);
|
|
367
|
+
operators = operators.filter(op => !excludeSet.has(op.value));
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Apply case-insensitive wrapping
|
|
371
|
+
if (!caseSensitive && CASE_INSENSITIVE_TYPES.includes(type)) {
|
|
372
|
+
operators = makeCaseInsensitive(operators);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// Apply extend
|
|
376
|
+
if (builtInOpts.extend && builtInOpts.extend.length > 0) {
|
|
377
|
+
operators = [...operators, ...builtInOpts.extend];
|
|
378
|
+
}
|
|
379
|
+
const result = {
|
|
380
|
+
type: getMuiType(type),
|
|
381
|
+
filterOperators: operators
|
|
382
|
+
};
|
|
383
|
+
if (type === 'multiSelect' || type === 'tags') {
|
|
384
|
+
result.sortComparator = arraySortComparator;
|
|
385
|
+
result.valueFormatter = arrayValueFormatter;
|
|
386
|
+
}
|
|
387
|
+
return result;
|
|
388
|
+
}
|
|
389
|
+
function getMuiType(type) {
|
|
390
|
+
switch (type) {
|
|
391
|
+
case 'multiSelect':
|
|
392
|
+
case 'singleSelect':
|
|
393
|
+
return 'singleSelect';
|
|
394
|
+
case 'tags':
|
|
395
|
+
return 'string';
|
|
396
|
+
default:
|
|
397
|
+
return type;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
function getOperatorsForType(type, compact) {
|
|
401
|
+
switch (type) {
|
|
402
|
+
case 'string':
|
|
403
|
+
return compact ? getStringOperatorsCompact() : getStringOperatorsFull();
|
|
404
|
+
case 'number':
|
|
405
|
+
return compact ? getNumberOperatorsCompact() : getNumberOperatorsFull();
|
|
406
|
+
case 'date':
|
|
407
|
+
return compact ? getDateOperatorsCompact(false) : getDateOperatorsFull(false);
|
|
408
|
+
case 'dateTime':
|
|
409
|
+
return compact ? getDateOperatorsCompact(true) : getDateOperatorsFull(true);
|
|
410
|
+
case 'singleSelect':
|
|
411
|
+
return compact ? getSingleSelectOperatorsCompact() : getSingleSelectOperatorsFull();
|
|
412
|
+
case 'multiSelect':
|
|
413
|
+
return compact ? getMultiSelectOperatorsCompact() : getMultiSelectOperatorsFull();
|
|
414
|
+
case 'tags':
|
|
415
|
+
return compact ? getTagsOperatorsCompact() : getTagsOperatorsFull();
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* A React Router v5 / connected-react-router adapter for `StatefulDataGrid.useRouter`.
|
|
421
|
+
*
|
|
422
|
+
* Defers `history.replace` via `queueMicrotask` to avoid the
|
|
423
|
+
* "Cannot update during an existing state transition" warning
|
|
424
|
+
* that connected-react-router triggers when the grid synchronises
|
|
425
|
+
* URL state during render.
|
|
426
|
+
*
|
|
427
|
+
* Also coalesces multiple `historyReplace` calls within the same microtask
|
|
428
|
+
* by computing per-call deltas against the captured `search` snapshot and
|
|
429
|
+
* merging them into the live URL. This prevents handler stomping when the
|
|
430
|
+
* grid fires several model-change handlers in the same render (e.g. a
|
|
431
|
+
* pivot change re-emits a synthetic column-visibility change alongside a
|
|
432
|
+
* filter change): without coalescing, each handler would compute a full
|
|
433
|
+
* new search from the same captured snapshot, and the second
|
|
434
|
+
* `history.replace` would clobber the first — dropping any keys (such as
|
|
435
|
+
* the filter just typed) that the second handler didn't know about.
|
|
436
|
+
*
|
|
437
|
+
* @example
|
|
438
|
+
* ```tsx
|
|
439
|
+
* import { createReactRouterV5Adapter } from '@redsift/table-pro';
|
|
440
|
+
*
|
|
441
|
+
* const useRouter = createReactRouterV5Adapter(history);
|
|
442
|
+
*
|
|
443
|
+
* <StatefulDataGrid useRouter={useRouter} … />
|
|
444
|
+
* ```
|
|
445
|
+
*/
|
|
446
|
+
|
|
447
|
+
/** Minimal subset of React Router v5 `history` used by the adapter. */
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Create a `useRouter` hook compatible with `StatefulDataGrid` from a
|
|
451
|
+
* React Router v5 `history` object.
|
|
452
|
+
*/
|
|
453
|
+
const createReactRouterV5Adapter = history => {
|
|
454
|
+
// Module-instance state shared across all `historyReplace` calls scheduled
|
|
455
|
+
// within the same microtask. Each `useRouter()` invocation captures its own
|
|
456
|
+
// `search` snapshot for delta computation; `pending` accumulates the deltas
|
|
457
|
+
// and is flushed once per microtask onto the live URL.
|
|
458
|
+
let pending = null;
|
|
459
|
+
let flushScheduled = false;
|
|
460
|
+
const scheduleFlush = () => {
|
|
461
|
+
if (flushScheduled) return;
|
|
462
|
+
flushScheduled = true;
|
|
463
|
+
queueMicrotask(() => {
|
|
464
|
+
flushScheduled = false;
|
|
465
|
+
const flush = pending;
|
|
466
|
+
pending = null;
|
|
467
|
+
if (flush === null) return;
|
|
468
|
+
const serialized = flush.toString();
|
|
469
|
+
const nextSearch = serialized ? `?${serialized}` : '';
|
|
470
|
+
if (nextSearch === history.location.search) return;
|
|
471
|
+
history.replace({
|
|
472
|
+
pathname: history.location.pathname,
|
|
473
|
+
search: nextSearch
|
|
474
|
+
});
|
|
475
|
+
});
|
|
476
|
+
};
|
|
477
|
+
return () => {
|
|
478
|
+
// Capture the search snapshot AT THE TIME useRouter() is called. The
|
|
479
|
+
// grid hands this string to its change handlers, which build a complete
|
|
480
|
+
// new search string from it. Diffing the handler's `newSearch` against
|
|
481
|
+
// this captured snapshot tells us which keys the handler intentionally
|
|
482
|
+
// changed (vs. which are stale passthrough from sibling handlers' models).
|
|
483
|
+
const captured = history.location.search.replace(/^\?/, '');
|
|
484
|
+
const capturedParams = new URLSearchParams(captured);
|
|
485
|
+
const capturedKeys = new Set(capturedParams.keys());
|
|
486
|
+
return {
|
|
487
|
+
pathname: history.location.pathname,
|
|
488
|
+
search: captured,
|
|
489
|
+
historyReplace: newSearch => {
|
|
490
|
+
const newParams = new URLSearchParams(newSearch);
|
|
491
|
+
const newKeys = new Set(newParams.keys());
|
|
492
|
+
|
|
493
|
+
// Lazy-init `pending` from the LIVE URL — not the captured snapshot —
|
|
494
|
+
// so deltas from earlier microtask-scheduled calls (which may have
|
|
495
|
+
// already been flushed, or were scheduled by a previous render and
|
|
496
|
+
// are now reflected in the live URL) are preserved.
|
|
497
|
+
if (pending === null) {
|
|
498
|
+
pending = new URLSearchParams(history.location.search.replace(/^\?/, ''));
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Apply only keys this handler actually changed. A handler builds a
|
|
502
|
+
// complete new search from a captured snapshot, but only some keys
|
|
503
|
+
// reflect its intent — the rest are passthrough of the snapshot.
|
|
504
|
+
// When two handlers fire in the same render and one was triggered
|
|
505
|
+
// by a model the other doesn't care about, passthrough keys would
|
|
506
|
+
// otherwise stomp pending state from earlier handlers.
|
|
507
|
+
for (const key of newKeys) {
|
|
508
|
+
const newValues = newParams.getAll(key);
|
|
509
|
+
const capturedValues = capturedParams.getAll(key);
|
|
510
|
+
const unchanged = newValues.length === capturedValues.length && newValues.every((v, i) => v === capturedValues[i]);
|
|
511
|
+
if (unchanged) continue;
|
|
512
|
+
pending.delete(key);
|
|
513
|
+
for (const value of newValues) {
|
|
514
|
+
pending.append(key, value);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
// Keys that were in the captured snapshot but absent from newSearch
|
|
518
|
+
// were intentionally removed by this handler.
|
|
519
|
+
for (const key of capturedKeys) {
|
|
520
|
+
if (!newKeys.has(key)) pending.delete(key);
|
|
521
|
+
}
|
|
522
|
+
scheduleFlush();
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
};
|
|
526
|
+
};
|
|
527
|
+
|
|
528
|
+
const EMPTY_FILTER_MODEL = {
|
|
529
|
+
items: []
|
|
530
|
+
};
|
|
531
|
+
const sameItems = (a, b) => JSON.stringify(a.items) === JSON.stringify(b.items);
|
|
532
|
+
const filterOutField = (model, field) => model.items.filter(item => item.field !== field);
|
|
533
|
+
const nextItemId = (() => {
|
|
534
|
+
let id = 1;
|
|
535
|
+
return () => id++;
|
|
536
|
+
})();
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* Bridge a DataGrid `filterModel` and the DataCards that drive (and reflect) it.
|
|
540
|
+
*
|
|
541
|
+
* Without this hook, every drilldowned datagrid page hand-rolls the same plumbing:
|
|
542
|
+
* derive selections from `filterModel`, write them back via raw `setFilterModel`
|
|
543
|
+
* mutations, debounce panel changes, and track which fields the panel "owns" so
|
|
544
|
+
* cards don't fight the panel for control. SOFA-6 shipped this logic ad hoc and
|
|
545
|
+
* got it wrong (no debounce, prop-drilled state, no panel/card reconciliation).
|
|
546
|
+
*
|
|
547
|
+
* @example
|
|
548
|
+
* const filter = useLinkedFilterModel();
|
|
549
|
+
*
|
|
550
|
+
* <DataCard.Listbox
|
|
551
|
+
* values={filter.getSelected('Category')}
|
|
552
|
+
* onChange={(values) => filter.setMultiSelect('Category', values)}
|
|
553
|
+
* isDisabled={filter.isFieldExternallyControlled('Category')}
|
|
554
|
+
* >
|
|
555
|
+
* {…}
|
|
556
|
+
* </DataCard.Listbox>
|
|
557
|
+
*
|
|
558
|
+
* <DataGrid filterModel={filter.filterModel} onFilterModelChange={filter.onFilterModelChange} />
|
|
559
|
+
*/
|
|
560
|
+
function useLinkedFilterModel() {
|
|
561
|
+
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
562
|
+
const {
|
|
563
|
+
initialFilterModel = EMPTY_FILTER_MODEL,
|
|
564
|
+
debounceMs = 300,
|
|
565
|
+
onChange
|
|
566
|
+
} = options;
|
|
567
|
+
const [filterModel, setFilterModel] = useState(initialFilterModel);
|
|
568
|
+
|
|
569
|
+
// Fields whose current filter was set by setMultiSelect / setBoolean (not the panel).
|
|
570
|
+
const cardOwnedFields = useRef(new Set());
|
|
571
|
+
// Marks the next onFilterModelChange as originating from a card setter so we skip debouncing.
|
|
572
|
+
const skipNextDebounce = useRef(false);
|
|
573
|
+
const debounceTimer = useRef(null);
|
|
574
|
+
const onChangeRef = useRef(onChange);
|
|
575
|
+
useEffect(() => {
|
|
576
|
+
onChangeRef.current = onChange;
|
|
577
|
+
}, [onChange]);
|
|
578
|
+
useEffect(() => {
|
|
579
|
+
return () => {
|
|
580
|
+
if (debounceTimer.current) clearTimeout(debounceTimer.current);
|
|
581
|
+
};
|
|
582
|
+
}, []);
|
|
583
|
+
const commit = useCallback(next => {
|
|
584
|
+
setFilterModel(prev => {
|
|
585
|
+
var _onChangeRef$current;
|
|
586
|
+
if (sameItems(prev, next)) return prev;
|
|
587
|
+
(_onChangeRef$current = onChangeRef.current) === null || _onChangeRef$current === void 0 ? void 0 : _onChangeRef$current.call(onChangeRef, next);
|
|
588
|
+
return next;
|
|
589
|
+
});
|
|
590
|
+
}, []);
|
|
591
|
+
const onFilterModelChange = useCallback(model => {
|
|
592
|
+
if (skipNextDebounce.current) {
|
|
593
|
+
skipNextDebounce.current = false;
|
|
594
|
+
// If the incoming model matches the current state, this is a DataGrid echo
|
|
595
|
+
// of a card setter — commit (no-op) and preserve card ownership.
|
|
596
|
+
if (sameItems(filterModel, model)) {
|
|
597
|
+
commit(model);
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
// Otherwise a real panel change arrived — fall through to ownership logic.
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// Panel change — drop card ownership for fields the panel now controls / has cleared,
|
|
604
|
+
// then debounce the commit.
|
|
605
|
+
const panelFields = new Set(model.items.map(item => item.field));
|
|
606
|
+
for (const field of Array.from(cardOwnedFields.current)) {
|
|
607
|
+
if (!panelFields.has(field)) cardOwnedFields.current.delete(field);
|
|
608
|
+
}
|
|
609
|
+
// If the panel touched a field the card previously owned, transfer ownership to the panel.
|
|
610
|
+
for (const field of panelFields) {
|
|
611
|
+
cardOwnedFields.current.delete(field);
|
|
612
|
+
}
|
|
613
|
+
if (debounceMs <= 0) {
|
|
614
|
+
commit(model);
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
if (debounceTimer.current) clearTimeout(debounceTimer.current);
|
|
618
|
+
debounceTimer.current = setTimeout(() => {
|
|
619
|
+
debounceTimer.current = null;
|
|
620
|
+
commit(model);
|
|
621
|
+
}, debounceMs);
|
|
622
|
+
}, [commit, debounceMs, filterModel]);
|
|
623
|
+
const getSelected = useCallback(field => {
|
|
624
|
+
const item = filterModel.items.find(i => i.field === field);
|
|
625
|
+
if (!item || item.value === undefined || item.value === null) return [];
|
|
626
|
+
if (item.operator === 'isAnyOf' || item.operator === 'hasAnyOf') {
|
|
627
|
+
return Array.isArray(item.value) ? item.value : [String(item.value)];
|
|
628
|
+
}
|
|
629
|
+
return [];
|
|
630
|
+
}, [filterModel]);
|
|
631
|
+
const getValue = useCallback(field => {
|
|
632
|
+
var _filterModel$items$fi;
|
|
633
|
+
return (_filterModel$items$fi = filterModel.items.find(i => i.field === field)) === null || _filterModel$items$fi === void 0 ? void 0 : _filterModel$items$fi.value;
|
|
634
|
+
}, [filterModel]);
|
|
635
|
+
const setMultiSelect = useCallback(function (field, values) {
|
|
636
|
+
let operator = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'isAnyOf';
|
|
637
|
+
skipNextDebounce.current = true;
|
|
638
|
+
setFilterModel(prev => {
|
|
639
|
+
var _onChangeRef$current2;
|
|
640
|
+
const items = filterOutField(prev, field);
|
|
641
|
+
if (values.length > 0) {
|
|
642
|
+
items.push({
|
|
643
|
+
field,
|
|
644
|
+
id: nextItemId(),
|
|
645
|
+
operator,
|
|
646
|
+
value: values
|
|
647
|
+
});
|
|
648
|
+
cardOwnedFields.current.add(field);
|
|
649
|
+
} else {
|
|
650
|
+
cardOwnedFields.current.delete(field);
|
|
651
|
+
}
|
|
652
|
+
const next = _objectSpread2(_objectSpread2({}, prev), {}, {
|
|
653
|
+
items
|
|
654
|
+
});
|
|
655
|
+
if (sameItems(prev, next)) return prev;
|
|
656
|
+
(_onChangeRef$current2 = onChangeRef.current) === null || _onChangeRef$current2 === void 0 ? void 0 : _onChangeRef$current2.call(onChangeRef, next);
|
|
657
|
+
return next;
|
|
658
|
+
});
|
|
659
|
+
}, []);
|
|
660
|
+
const setBoolean = useCallback((field, value) => {
|
|
661
|
+
skipNextDebounce.current = true;
|
|
662
|
+
setFilterModel(prev => {
|
|
663
|
+
var _onChangeRef$current3;
|
|
664
|
+
const items = filterOutField(prev, field);
|
|
665
|
+
if (value !== null) {
|
|
666
|
+
items.push({
|
|
667
|
+
field,
|
|
668
|
+
id: nextItemId(),
|
|
669
|
+
operator: 'is',
|
|
670
|
+
value: String(value)
|
|
671
|
+
});
|
|
672
|
+
cardOwnedFields.current.add(field);
|
|
673
|
+
} else {
|
|
674
|
+
cardOwnedFields.current.delete(field);
|
|
675
|
+
}
|
|
676
|
+
const next = _objectSpread2(_objectSpread2({}, prev), {}, {
|
|
677
|
+
items
|
|
678
|
+
});
|
|
679
|
+
if (sameItems(prev, next)) return prev;
|
|
680
|
+
(_onChangeRef$current3 = onChangeRef.current) === null || _onChangeRef$current3 === void 0 ? void 0 : _onChangeRef$current3.call(onChangeRef, next);
|
|
681
|
+
return next;
|
|
682
|
+
});
|
|
683
|
+
}, []);
|
|
684
|
+
const clearField = useCallback(field => {
|
|
685
|
+
skipNextDebounce.current = true;
|
|
686
|
+
setFilterModel(prev => {
|
|
687
|
+
var _onChangeRef$current4;
|
|
688
|
+
const items = filterOutField(prev, field);
|
|
689
|
+
cardOwnedFields.current.delete(field);
|
|
690
|
+
const next = _objectSpread2(_objectSpread2({}, prev), {}, {
|
|
691
|
+
items
|
|
692
|
+
});
|
|
693
|
+
if (sameItems(prev, next)) return prev;
|
|
694
|
+
(_onChangeRef$current4 = onChangeRef.current) === null || _onChangeRef$current4 === void 0 ? void 0 : _onChangeRef$current4.call(onChangeRef, next);
|
|
695
|
+
return next;
|
|
696
|
+
});
|
|
697
|
+
}, []);
|
|
698
|
+
const reset = useCallback(() => {
|
|
699
|
+
skipNextDebounce.current = true;
|
|
700
|
+
cardOwnedFields.current.clear();
|
|
701
|
+
commit(initialFilterModel);
|
|
702
|
+
}, [commit, initialFilterModel]);
|
|
703
|
+
const isFieldExternallyControlled = useCallback(field => {
|
|
704
|
+
const hasFilter = filterModel.items.some(item => item.field === field);
|
|
705
|
+
return hasFilter && !cardOwnedFields.current.has(field);
|
|
706
|
+
}, [filterModel]);
|
|
707
|
+
return useMemo(() => ({
|
|
708
|
+
filterModel,
|
|
709
|
+
onFilterModelChange,
|
|
710
|
+
getSelected,
|
|
711
|
+
getValue,
|
|
712
|
+
setMultiSelect,
|
|
713
|
+
setBoolean,
|
|
714
|
+
clearField,
|
|
715
|
+
reset,
|
|
716
|
+
isFieldExternallyControlled
|
|
717
|
+
}), [filterModel, onFilterModelChange, getSelected, getValue, setMultiSelect, setBoolean, clearField, reset, isFieldExternallyControlled]);
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
export { DATE_IS_BETWEEN, DETAIL_PANEL_TOGGLE_COL_DEF, IS_ANY_OF_I, IS_ANY_OF_I_WITH_SELECT, createColumn, createReactRouterV5Adapter, customColumnTypes, getGridDateOperatorsExtended, getRsMultipleSelectColumnType, getRsMultipleSelectWithShortOperatorListColumnType, getRsNumberColumnType, getRsSingleSelectColumnType, getRsSingleSelectWithShortOperatorListColumnType, getRsStringColumnType, makeCaseInsensitive, useLinkedFilterModel, wrapCaseInsensitive };
|
|
721
|
+
//# sourceMappingURL=index.js.map
|