@redsift/table 12.5.3-alpha.5 → 12.5.3-alpha.6
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/_internal/StatefulDataGrid2.js +13 -4
- package/_internal/StatefulDataGrid2.js.map +1 -1
- package/index.d.ts +111 -1
- package/index.js +233 -1
- package/index.js.map +1 -1
- package/package.json +2 -2
package/index.d.ts
CHANGED
|
@@ -338,10 +338,22 @@ declare const DENSITY_MODEL_KEY = "densityModel";
|
|
|
338
338
|
declare const COLUMN_ORDER_MODEL_KEY = "columnOrderModel";
|
|
339
339
|
declare const ROW_GROUPING_MODEL_KEY = "rowGroupingModel";
|
|
340
340
|
declare const AGGREGATION_MODEL_KEY = "aggregationModel";
|
|
341
|
+
/** Storage category key for the pivot column/row/value configuration. Consumer interop — use with `buildStorageKey`. */
|
|
341
342
|
declare const PIVOT_MODEL_KEY = "pivotModel";
|
|
343
|
+
/** Storage category key for whether pivoting is active. Consumer interop — use with `buildStorageKey`. */
|
|
342
344
|
declare const PIVOT_ACTIVE_KEY = "pivotActive";
|
|
343
345
|
declare const CATEGORIES: readonly ["paginationModel", "filterModel", "sortModel", "visibilityModel", "dimension", "searchModel", "pinnedColumns", "densityModel", "columnOrderModel", "rowGroupingModel", "aggregationModel", "pivotModel", "pivotActive"];
|
|
344
346
|
type Category = (typeof CATEGORIES)[number];
|
|
347
|
+
/**
|
|
348
|
+
* Build the localStorage key for a specific grid state category.
|
|
349
|
+
* Consumers can use this to read or clear individual state entries directly.
|
|
350
|
+
*
|
|
351
|
+
* @example
|
|
352
|
+
* ```ts
|
|
353
|
+
* const key = buildStorageKey({ id: pathname, version: 2, category: PIVOT_ACTIVE_KEY });
|
|
354
|
+
* localStorage.removeItem(key);
|
|
355
|
+
* ```
|
|
356
|
+
*/
|
|
345
357
|
declare const buildStorageKey: ({ id, version, category }: {
|
|
346
358
|
id: string;
|
|
347
359
|
version: number;
|
|
@@ -946,6 +958,104 @@ type DataGridModel = {
|
|
|
946
958
|
declare const updateUrl: ({ filterModel, sortModel, paginationModel, columnsModel: columnsVisibilityModel, pinnedColumnsModel, density, columnOrderModel, defaultColumnOrder, rowGroupingModel, aggregationModel, pivotModel, pivotActive, }: DataGridModel, search: string, localStorageVersion: number, historyReplace: (newSearch: string) => void, columns: DataGridProps["columns"]) => void;
|
|
947
959
|
declare const areFilterModelsEquivalent: (filterModel: GridFilterModel, filterModelToMatch: GridFilterModel) => boolean;
|
|
948
960
|
|
|
961
|
+
/**
|
|
962
|
+
* A React Router v5 / connected-react-router adapter for `StatefulDataGrid.useRouter`.
|
|
963
|
+
*
|
|
964
|
+
* Defers `history.replace` via `queueMicrotask` to avoid the
|
|
965
|
+
* "Cannot update during an existing state transition" warning
|
|
966
|
+
* that connected-react-router triggers when the grid synchronises
|
|
967
|
+
* URL state during render.
|
|
968
|
+
*
|
|
969
|
+
* @example
|
|
970
|
+
* ```tsx
|
|
971
|
+
* import { createReactRouterV5Adapter } from '@redsift/table';
|
|
972
|
+
*
|
|
973
|
+
* const useRouter = createReactRouterV5Adapter(history);
|
|
974
|
+
*
|
|
975
|
+
* <StatefulDataGrid useRouter={useRouter} … />
|
|
976
|
+
* ```
|
|
977
|
+
*/
|
|
978
|
+
/** Minimal subset of React Router v5 `history` used by the adapter. */
|
|
979
|
+
interface ReactRouterV5History {
|
|
980
|
+
location: {
|
|
981
|
+
pathname: string;
|
|
982
|
+
search: string;
|
|
983
|
+
};
|
|
984
|
+
replace: (path: {
|
|
985
|
+
pathname: string;
|
|
986
|
+
search: string;
|
|
987
|
+
}) => void;
|
|
988
|
+
}
|
|
989
|
+
/**
|
|
990
|
+
* Create a `useRouter` hook compatible with `StatefulDataGrid` from a
|
|
991
|
+
* React Router v5 `history` object.
|
|
992
|
+
*/
|
|
993
|
+
declare const createReactRouterV5Adapter: (history: ReactRouterV5History) => (() => {
|
|
994
|
+
pathname: string;
|
|
995
|
+
search: string;
|
|
996
|
+
historyReplace: (newSearch: string) => void;
|
|
997
|
+
});
|
|
998
|
+
|
|
999
|
+
interface UseLinkedFilterModelOptions {
|
|
1000
|
+
/** Starting filter model. Defaults to `{ items: [] }`. */
|
|
1001
|
+
initialFilterModel?: GridFilterModel;
|
|
1002
|
+
/**
|
|
1003
|
+
* Debounce window (ms) applied to changes coming from the DataGrid filter panel.
|
|
1004
|
+
* Card-driven changes via `setMultiSelect` / `setBoolean` are never debounced.
|
|
1005
|
+
* Defaults to `300`. Pass `0` to disable.
|
|
1006
|
+
*/
|
|
1007
|
+
debounceMs?: number;
|
|
1008
|
+
/** Optional callback fired on every settled filter model change. */
|
|
1009
|
+
onChange?: (model: GridFilterModel) => void;
|
|
1010
|
+
}
|
|
1011
|
+
interface UseLinkedFilterModelReturn {
|
|
1012
|
+
/** Current filter model. Pass to DataGrid `filterModel` and read for DataCard derivations. */
|
|
1013
|
+
filterModel: GridFilterModel;
|
|
1014
|
+
/** Bind to DataGrid `onFilterModelChange`. Debounced for panel changes. */
|
|
1015
|
+
onFilterModelChange: (model: GridFilterModel) => void;
|
|
1016
|
+
/** Read selected values for an `isAnyOf` / `hasAnyOf` field. Empty array when not set. */
|
|
1017
|
+
getSelected: (field: string) => string[];
|
|
1018
|
+
/** Read the raw filter value for a field (e.g. boolean toggles). */
|
|
1019
|
+
getValue: (field: string) => unknown;
|
|
1020
|
+
/** Set a multi-select filter from a DataCard. Empty array clears the field. */
|
|
1021
|
+
setMultiSelect: (field: string, values: string[], operator?: string) => void;
|
|
1022
|
+
/** Set a boolean filter. Pass `null` to clear. */
|
|
1023
|
+
setBoolean: (field: string, value: boolean | null) => void;
|
|
1024
|
+
/** Remove a single field from the filter model. */
|
|
1025
|
+
clearField: (field: string) => void;
|
|
1026
|
+
/** Reset the filter model to the initial value. */
|
|
1027
|
+
reset: () => void;
|
|
1028
|
+
/**
|
|
1029
|
+
* Whether a field's filter was set externally (DataGrid filter panel) rather than
|
|
1030
|
+
* via this hook's setters. Useful for disabling the corresponding DataCard so the
|
|
1031
|
+
* panel and card don't fight over the same field.
|
|
1032
|
+
*/
|
|
1033
|
+
isFieldExternallyControlled: (field: string) => boolean;
|
|
1034
|
+
}
|
|
1035
|
+
/**
|
|
1036
|
+
* Bridge a DataGrid `filterModel` and the DataCards that drive (and reflect) it.
|
|
1037
|
+
*
|
|
1038
|
+
* Without this hook, every drilldowned datagrid page hand-rolls the same plumbing:
|
|
1039
|
+
* derive selections from `filterModel`, write them back via raw `setFilterModel`
|
|
1040
|
+
* mutations, debounce panel changes, and track which fields the panel "owns" so
|
|
1041
|
+
* cards don't fight the panel for control. SOFA-6 shipped this logic ad hoc and
|
|
1042
|
+
* got it wrong (no debounce, prop-drilled state, no panel/card reconciliation).
|
|
1043
|
+
*
|
|
1044
|
+
* @example
|
|
1045
|
+
* const filter = useLinkedFilterModel();
|
|
1046
|
+
*
|
|
1047
|
+
* <DataCard.Listbox
|
|
1048
|
+
* values={filter.getSelected('Category')}
|
|
1049
|
+
* onChange={(values) => filter.setMultiSelect('Category', values)}
|
|
1050
|
+
* isDisabled={filter.isFieldExternallyControlled('Category')}
|
|
1051
|
+
* >
|
|
1052
|
+
* {…}
|
|
1053
|
+
* </DataCard.Listbox>
|
|
1054
|
+
*
|
|
1055
|
+
* <DataGrid filterModel={filter.filterModel} onFilterModelChange={filter.onFilterModelChange} />
|
|
1056
|
+
*/
|
|
1057
|
+
declare function useLinkedFilterModel(options?: UseLinkedFilterModelOptions): UseLinkedFilterModelReturn;
|
|
1058
|
+
|
|
949
1059
|
declare const BaseButton: React$1.JSXElementConstructor<any>;
|
|
950
1060
|
|
|
951
1061
|
declare const BaseCheckbox: React$1.JSXElementConstructor<any>;
|
|
@@ -1151,4 +1261,4 @@ type ToolbarWrapperProps = {
|
|
|
1151
1261
|
};
|
|
1152
1262
|
declare const ToolbarWrapper: React$1.FC<ToolbarWrapperProps>;
|
|
1153
1263
|
|
|
1154
|
-
export { AGGREGATION_MODEL_KEY, ARRAY_IS_EMPTY, ARRAY_IS_NOT_EMPTY, BaseButton, BaseCheckbox, BaseIcon, BaseIconButton, BaseTextField, CATEGORIES, COLUMN_ORDER_MODEL_KEY, CONTAINS_ANY_OF, Category, ColumnOptions, ColumnOrderModel, ColumnType, CompletionResponse, ControlledPagination, ControlledPaginationProps, DATE_IS_BETWEEN, DEFAULT_OPERATORS, DENSITY_MODEL_KEY, DETAIL_PANEL_TOGGLE_COL_DEF, DIMENSION_MODEL_KEY, DOES_NOT_CONTAIN, DOES_NOT_CONTAIN_ANY_OF, DOES_NOT_END_WITH, DOES_NOT_END_WITH_ANY_OF, DOES_NOT_EQUAL, DOES_NOT_HAVE, DOES_NOT_HAVE_ANY_OF, DOES_NOT_HAVE_ANY_OF_WITH_SELECT, DOES_NOT_HAVE_WITH_SELECT, DOES_NOT_START_WITH, DOES_NOT_START_WITH_ANY_OF, DataGrid, DataGridModel, DataGridProps, DateOperatorName, EMPTY_ROW_SELECTION_MODEL, ENDS_WITH_ANY_OF, FILTER_MODEL_KEY, FILTER_SEARCH_KEY, FilterConfig, FilterConfigColumn, GridDensityValue, GridToolbarFilterSemanticField, GridToolbarFilterSemanticFieldProps, HAS, HAS_ALL_OF, HAS_ALL_OF_WITH_SELECT, HAS_ANY_OF, HAS_ANY_OF_WITH_SELECT, HAS_ONLY, HAS_ONLY_WITH_SELECT, HAS_WITH_SELECT, IS, IS_ANY_OF, IS_ANY_OF_I, IS_ANY_OF_I_WITH_SELECT, IS_ANY_OF_WITH_SELECT, IS_BETWEEN, IS_NOT, IS_NOT_ANY_OF, IS_NOT_ANY_OF_WITH_SELECT, IS_NOT_WITH_SELECT, IS_WITH_SELECT, LegacyRowSelectionModel, MultiSelectOperatorName, NumberOperatorName, PAGINATION_MODEL_KEY, PINNED_COLUMNS, PIVOT_ACTIVE_KEY, PIVOT_MODEL_KEY, PinnedColumns, PivotModel, ROW_GROUPING_MODEL_KEY, RowSelectionModelInput, SORT_MODEL_KEY, STARTS_WITH_ANY_OF, SelectionStatus, ServerSideControlledPagination, ServerSideControlledPaginationProps, SingleSelectOperatorName, StatefulDataGrid, StatefulDataGridProps, StringOperatorName, StyledDataGridProps, TagsOperatorName, TextCell, Toolbar, ToolbarWrapper, ToolbarWrapperProps, VISIBILITY_MODEL_KEY, areFilterModelsEquivalent, areSearchStringsEqual, buildQueryParamsString, buildStorageKey, clearAllVersionStorage, clearPreviousVersionStorage, convertFromDisplayFormat, convertToDisplayFormat, createColumn, createRowSelectionModel, customColumnTypes, decodeValue, encodeValue, fixServerSideHeaderCheckboxSelection, fromGridPivotModel, getAggregationFromString, getColumnOrderFromString, getColumnVisibilityFromString, getCompletion, getDecodedSearchFromUrl, getDensityFromString, getDensityModel, getFilterModelFromString, getFinalSearch, getGridDateOperatorsExtended, getGridNumericOperators, getGridStringArrayOperators, getGridStringArrayOperatorsWithSelect, getGridStringArrayOperatorsWithSelectOnStringArrayColumns, getGridStringOperators, getModelsParsedOrUpdateLocalStorage, getPaginationFromString, getPinnedColumnsFromString, getPivotActiveFromString, getPivotFromString, getRowGroupingFromString, getRsMultipleSelectColumnType, getRsMultipleSelectWithShortOperatorListColumnType, getRsNumberColumnType, getRsSingleSelectColumnType, getRsSingleSelectWithShortOperatorListColumnType, getRsStringColumnType, getSearchParamsFromAggregation, getSearchParamsFromColumnOrder, getSearchParamsFromColumnVisibility, getSearchParamsFromDensity, getSearchParamsFromFilterModel, getSearchParamsFromPagination, getSearchParamsFromPinnedColumns, getSearchParamsFromPivot, getSearchParamsFromPivotActive, getSearchParamsFromRowGrouping, getSearchParamsFromSorting, getSearchParamsFromTab, getSelectableRowIdsInPage, getSelectedIds, getSelectionCount, getSortingFromString, isOperatorValueValid, isRowSelected, isValueValid, makeCaseInsensitive, muiIconToDSIcon, normalizeRowSelectionModel, numberOperatorDecoder, numberOperatorEncoder, onServerSideSelectionStatusChange, operatorList, resetStatefulDataGridState, updateUrl, urlSearchParamsToString, wrapCaseInsensitive };
|
|
1264
|
+
export { AGGREGATION_MODEL_KEY, ARRAY_IS_EMPTY, ARRAY_IS_NOT_EMPTY, BaseButton, BaseCheckbox, BaseIcon, BaseIconButton, BaseTextField, CATEGORIES, COLUMN_ORDER_MODEL_KEY, CONTAINS_ANY_OF, Category, ColumnOptions, ColumnOrderModel, ColumnType, CompletionResponse, ControlledPagination, ControlledPaginationProps, DATE_IS_BETWEEN, DEFAULT_OPERATORS, DENSITY_MODEL_KEY, DETAIL_PANEL_TOGGLE_COL_DEF, DIMENSION_MODEL_KEY, DOES_NOT_CONTAIN, DOES_NOT_CONTAIN_ANY_OF, DOES_NOT_END_WITH, DOES_NOT_END_WITH_ANY_OF, DOES_NOT_EQUAL, DOES_NOT_HAVE, DOES_NOT_HAVE_ANY_OF, DOES_NOT_HAVE_ANY_OF_WITH_SELECT, DOES_NOT_HAVE_WITH_SELECT, DOES_NOT_START_WITH, DOES_NOT_START_WITH_ANY_OF, DataGrid, DataGridModel, DataGridProps, DateOperatorName, EMPTY_ROW_SELECTION_MODEL, ENDS_WITH_ANY_OF, FILTER_MODEL_KEY, FILTER_SEARCH_KEY, FilterConfig, FilterConfigColumn, GridDensityValue, GridToolbarFilterSemanticField, GridToolbarFilterSemanticFieldProps, HAS, HAS_ALL_OF, HAS_ALL_OF_WITH_SELECT, HAS_ANY_OF, HAS_ANY_OF_WITH_SELECT, HAS_ONLY, HAS_ONLY_WITH_SELECT, HAS_WITH_SELECT, IS, IS_ANY_OF, IS_ANY_OF_I, IS_ANY_OF_I_WITH_SELECT, IS_ANY_OF_WITH_SELECT, IS_BETWEEN, IS_NOT, IS_NOT_ANY_OF, IS_NOT_ANY_OF_WITH_SELECT, IS_NOT_WITH_SELECT, IS_WITH_SELECT, LegacyRowSelectionModel, MultiSelectOperatorName, NumberOperatorName, PAGINATION_MODEL_KEY, PINNED_COLUMNS, PIVOT_ACTIVE_KEY, PIVOT_MODEL_KEY, PinnedColumns, PivotModel, ROW_GROUPING_MODEL_KEY, ReactRouterV5History, RowSelectionModelInput, SORT_MODEL_KEY, STARTS_WITH_ANY_OF, SelectionStatus, ServerSideControlledPagination, ServerSideControlledPaginationProps, SingleSelectOperatorName, StatefulDataGrid, StatefulDataGridProps, StringOperatorName, StyledDataGridProps, TagsOperatorName, TextCell, Toolbar, ToolbarWrapper, ToolbarWrapperProps, UseLinkedFilterModelOptions, UseLinkedFilterModelReturn, VISIBILITY_MODEL_KEY, areFilterModelsEquivalent, areSearchStringsEqual, buildQueryParamsString, buildStorageKey, clearAllVersionStorage, clearPreviousVersionStorage, convertFromDisplayFormat, convertToDisplayFormat, createColumn, createReactRouterV5Adapter, createRowSelectionModel, customColumnTypes, decodeValue, encodeValue, fixServerSideHeaderCheckboxSelection, fromGridPivotModel, getAggregationFromString, getColumnOrderFromString, getColumnVisibilityFromString, getCompletion, getDecodedSearchFromUrl, getDensityFromString, getDensityModel, getFilterModelFromString, getFinalSearch, getGridDateOperatorsExtended, getGridNumericOperators, getGridStringArrayOperators, getGridStringArrayOperatorsWithSelect, getGridStringArrayOperatorsWithSelectOnStringArrayColumns, getGridStringOperators, getModelsParsedOrUpdateLocalStorage, getPaginationFromString, getPinnedColumnsFromString, getPivotActiveFromString, getPivotFromString, getRowGroupingFromString, getRsMultipleSelectColumnType, getRsMultipleSelectWithShortOperatorListColumnType, getRsNumberColumnType, getRsSingleSelectColumnType, getRsSingleSelectWithShortOperatorListColumnType, getRsStringColumnType, getSearchParamsFromAggregation, getSearchParamsFromColumnOrder, getSearchParamsFromColumnVisibility, getSearchParamsFromDensity, getSearchParamsFromFilterModel, getSearchParamsFromPagination, getSearchParamsFromPinnedColumns, getSearchParamsFromPivot, getSearchParamsFromPivotActive, getSearchParamsFromRowGrouping, getSearchParamsFromSorting, getSearchParamsFromTab, getSelectableRowIdsInPage, getSelectedIds, getSelectionCount, getSortingFromString, isOperatorValueValid, isRowSelected, isValueValid, makeCaseInsensitive, muiIconToDSIcon, normalizeRowSelectionModel, numberOperatorDecoder, numberOperatorEncoder, onServerSideSelectionStatusChange, operatorList, resetStatefulDataGridState, updateUrl, urlSearchParamsToString, useLinkedFilterModel, wrapCaseInsensitive };
|
package/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { GRID_DETAIL_PANEL_TOGGLE_COL_DEF, GridFilterInputMultipleValue, GridFil
|
|
|
4
4
|
export { getGridBooleanOperators, getGridDateOperators, getGridSingleSelectOperators } from '@mui/x-data-grid-premium';
|
|
5
5
|
import { _ as _objectSpread2 } from './_internal/_rollupPluginBabelHelpers.js';
|
|
6
6
|
import * as React from 'react';
|
|
7
|
+
import { useState, useRef, useEffect, useCallback, useMemo } from 'react';
|
|
7
8
|
import Box from '@mui/material/Box';
|
|
8
9
|
import TextField from '@mui/material/TextField';
|
|
9
10
|
import { Icon } from '@redsift/design-system';
|
|
@@ -415,5 +416,236 @@ function getOperatorsForType(type, compact) {
|
|
|
415
416
|
}
|
|
416
417
|
}
|
|
417
418
|
|
|
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
|
+
* @example
|
|
428
|
+
* ```tsx
|
|
429
|
+
* import { createReactRouterV5Adapter } from '@redsift/table';
|
|
430
|
+
*
|
|
431
|
+
* const useRouter = createReactRouterV5Adapter(history);
|
|
432
|
+
*
|
|
433
|
+
* <StatefulDataGrid useRouter={useRouter} … />
|
|
434
|
+
* ```
|
|
435
|
+
*/
|
|
436
|
+
|
|
437
|
+
/** Minimal subset of React Router v5 `history` used by the adapter. */
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Create a `useRouter` hook compatible with `StatefulDataGrid` from a
|
|
441
|
+
* React Router v5 `history` object.
|
|
442
|
+
*/
|
|
443
|
+
const createReactRouterV5Adapter = history => {
|
|
444
|
+
return () => ({
|
|
445
|
+
pathname: history.location.pathname,
|
|
446
|
+
search: history.location.search.replace(/^\?/, ''),
|
|
447
|
+
historyReplace: newSearch => {
|
|
448
|
+
queueMicrotask(() => {
|
|
449
|
+
history.replace({
|
|
450
|
+
pathname: history.location.pathname,
|
|
451
|
+
search: newSearch ? `?${newSearch}` : ''
|
|
452
|
+
});
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
});
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
const EMPTY_FILTER_MODEL = {
|
|
459
|
+
items: []
|
|
460
|
+
};
|
|
461
|
+
const sameItems = (a, b) => JSON.stringify(a.items) === JSON.stringify(b.items);
|
|
462
|
+
const filterOutField = (model, field) => model.items.filter(item => item.field !== field);
|
|
463
|
+
const nextItemId = (() => {
|
|
464
|
+
let id = 1;
|
|
465
|
+
return () => id++;
|
|
466
|
+
})();
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Bridge a DataGrid `filterModel` and the DataCards that drive (and reflect) it.
|
|
470
|
+
*
|
|
471
|
+
* Without this hook, every drilldowned datagrid page hand-rolls the same plumbing:
|
|
472
|
+
* derive selections from `filterModel`, write them back via raw `setFilterModel`
|
|
473
|
+
* mutations, debounce panel changes, and track which fields the panel "owns" so
|
|
474
|
+
* cards don't fight the panel for control. SOFA-6 shipped this logic ad hoc and
|
|
475
|
+
* got it wrong (no debounce, prop-drilled state, no panel/card reconciliation).
|
|
476
|
+
*
|
|
477
|
+
* @example
|
|
478
|
+
* const filter = useLinkedFilterModel();
|
|
479
|
+
*
|
|
480
|
+
* <DataCard.Listbox
|
|
481
|
+
* values={filter.getSelected('Category')}
|
|
482
|
+
* onChange={(values) => filter.setMultiSelect('Category', values)}
|
|
483
|
+
* isDisabled={filter.isFieldExternallyControlled('Category')}
|
|
484
|
+
* >
|
|
485
|
+
* {…}
|
|
486
|
+
* </DataCard.Listbox>
|
|
487
|
+
*
|
|
488
|
+
* <DataGrid filterModel={filter.filterModel} onFilterModelChange={filter.onFilterModelChange} />
|
|
489
|
+
*/
|
|
490
|
+
function useLinkedFilterModel() {
|
|
491
|
+
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
492
|
+
const {
|
|
493
|
+
initialFilterModel = EMPTY_FILTER_MODEL,
|
|
494
|
+
debounceMs = 300,
|
|
495
|
+
onChange
|
|
496
|
+
} = options;
|
|
497
|
+
const [filterModel, setFilterModel] = useState(initialFilterModel);
|
|
498
|
+
|
|
499
|
+
// Fields whose current filter was set by setMultiSelect / setBoolean (not the panel).
|
|
500
|
+
const cardOwnedFields = useRef(new Set());
|
|
501
|
+
// Marks the next onFilterModelChange as originating from a card setter so we skip debouncing.
|
|
502
|
+
const skipNextDebounce = useRef(false);
|
|
503
|
+
const debounceTimer = useRef(null);
|
|
504
|
+
const onChangeRef = useRef(onChange);
|
|
505
|
+
useEffect(() => {
|
|
506
|
+
onChangeRef.current = onChange;
|
|
507
|
+
}, [onChange]);
|
|
508
|
+
useEffect(() => {
|
|
509
|
+
return () => {
|
|
510
|
+
if (debounceTimer.current) clearTimeout(debounceTimer.current);
|
|
511
|
+
};
|
|
512
|
+
}, []);
|
|
513
|
+
const commit = useCallback(next => {
|
|
514
|
+
setFilterModel(prev => {
|
|
515
|
+
var _onChangeRef$current;
|
|
516
|
+
if (sameItems(prev, next)) return prev;
|
|
517
|
+
(_onChangeRef$current = onChangeRef.current) === null || _onChangeRef$current === void 0 ? void 0 : _onChangeRef$current.call(onChangeRef, next);
|
|
518
|
+
return next;
|
|
519
|
+
});
|
|
520
|
+
}, []);
|
|
521
|
+
const onFilterModelChange = useCallback(model => {
|
|
522
|
+
if (skipNextDebounce.current) {
|
|
523
|
+
skipNextDebounce.current = false;
|
|
524
|
+
// If the incoming model matches the current state, this is a DataGrid echo
|
|
525
|
+
// of a card setter — commit (no-op) and preserve card ownership.
|
|
526
|
+
if (sameItems(filterModel, model)) {
|
|
527
|
+
commit(model);
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
// Otherwise a real panel change arrived — fall through to ownership logic.
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// Panel change — drop card ownership for fields the panel now controls / has cleared,
|
|
534
|
+
// then debounce the commit.
|
|
535
|
+
const panelFields = new Set(model.items.map(item => item.field));
|
|
536
|
+
for (const field of Array.from(cardOwnedFields.current)) {
|
|
537
|
+
if (!panelFields.has(field)) cardOwnedFields.current.delete(field);
|
|
538
|
+
}
|
|
539
|
+
// If the panel touched a field the card previously owned, transfer ownership to the panel.
|
|
540
|
+
for (const field of panelFields) {
|
|
541
|
+
cardOwnedFields.current.delete(field);
|
|
542
|
+
}
|
|
543
|
+
if (debounceMs <= 0) {
|
|
544
|
+
commit(model);
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
if (debounceTimer.current) clearTimeout(debounceTimer.current);
|
|
548
|
+
debounceTimer.current = setTimeout(() => {
|
|
549
|
+
debounceTimer.current = null;
|
|
550
|
+
commit(model);
|
|
551
|
+
}, debounceMs);
|
|
552
|
+
}, [commit, debounceMs, filterModel]);
|
|
553
|
+
const getSelected = useCallback(field => {
|
|
554
|
+
const item = filterModel.items.find(i => i.field === field);
|
|
555
|
+
if (!item || item.value === undefined || item.value === null) return [];
|
|
556
|
+
if (item.operator === 'isAnyOf' || item.operator === 'hasAnyOf') {
|
|
557
|
+
return Array.isArray(item.value) ? item.value : [String(item.value)];
|
|
558
|
+
}
|
|
559
|
+
return [];
|
|
560
|
+
}, [filterModel]);
|
|
561
|
+
const getValue = useCallback(field => {
|
|
562
|
+
var _filterModel$items$fi;
|
|
563
|
+
return (_filterModel$items$fi = filterModel.items.find(i => i.field === field)) === null || _filterModel$items$fi === void 0 ? void 0 : _filterModel$items$fi.value;
|
|
564
|
+
}, [filterModel]);
|
|
565
|
+
const setMultiSelect = useCallback(function (field, values) {
|
|
566
|
+
let operator = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'isAnyOf';
|
|
567
|
+
skipNextDebounce.current = true;
|
|
568
|
+
setFilterModel(prev => {
|
|
569
|
+
var _onChangeRef$current2;
|
|
570
|
+
const items = filterOutField(prev, field);
|
|
571
|
+
if (values.length > 0) {
|
|
572
|
+
items.push({
|
|
573
|
+
field,
|
|
574
|
+
id: nextItemId(),
|
|
575
|
+
operator,
|
|
576
|
+
value: values
|
|
577
|
+
});
|
|
578
|
+
cardOwnedFields.current.add(field);
|
|
579
|
+
} else {
|
|
580
|
+
cardOwnedFields.current.delete(field);
|
|
581
|
+
}
|
|
582
|
+
const next = _objectSpread2(_objectSpread2({}, prev), {}, {
|
|
583
|
+
items
|
|
584
|
+
});
|
|
585
|
+
if (sameItems(prev, next)) return prev;
|
|
586
|
+
(_onChangeRef$current2 = onChangeRef.current) === null || _onChangeRef$current2 === void 0 ? void 0 : _onChangeRef$current2.call(onChangeRef, next);
|
|
587
|
+
return next;
|
|
588
|
+
});
|
|
589
|
+
}, []);
|
|
590
|
+
const setBoolean = useCallback((field, value) => {
|
|
591
|
+
skipNextDebounce.current = true;
|
|
592
|
+
setFilterModel(prev => {
|
|
593
|
+
var _onChangeRef$current3;
|
|
594
|
+
const items = filterOutField(prev, field);
|
|
595
|
+
if (value !== null) {
|
|
596
|
+
items.push({
|
|
597
|
+
field,
|
|
598
|
+
id: nextItemId(),
|
|
599
|
+
operator: 'is',
|
|
600
|
+
value: String(value)
|
|
601
|
+
});
|
|
602
|
+
cardOwnedFields.current.add(field);
|
|
603
|
+
} else {
|
|
604
|
+
cardOwnedFields.current.delete(field);
|
|
605
|
+
}
|
|
606
|
+
const next = _objectSpread2(_objectSpread2({}, prev), {}, {
|
|
607
|
+
items
|
|
608
|
+
});
|
|
609
|
+
if (sameItems(prev, next)) return prev;
|
|
610
|
+
(_onChangeRef$current3 = onChangeRef.current) === null || _onChangeRef$current3 === void 0 ? void 0 : _onChangeRef$current3.call(onChangeRef, next);
|
|
611
|
+
return next;
|
|
612
|
+
});
|
|
613
|
+
}, []);
|
|
614
|
+
const clearField = useCallback(field => {
|
|
615
|
+
skipNextDebounce.current = true;
|
|
616
|
+
setFilterModel(prev => {
|
|
617
|
+
var _onChangeRef$current4;
|
|
618
|
+
const items = filterOutField(prev, field);
|
|
619
|
+
cardOwnedFields.current.delete(field);
|
|
620
|
+
const next = _objectSpread2(_objectSpread2({}, prev), {}, {
|
|
621
|
+
items
|
|
622
|
+
});
|
|
623
|
+
if (sameItems(prev, next)) return prev;
|
|
624
|
+
(_onChangeRef$current4 = onChangeRef.current) === null || _onChangeRef$current4 === void 0 ? void 0 : _onChangeRef$current4.call(onChangeRef, next);
|
|
625
|
+
return next;
|
|
626
|
+
});
|
|
627
|
+
}, []);
|
|
628
|
+
const reset = useCallback(() => {
|
|
629
|
+
skipNextDebounce.current = true;
|
|
630
|
+
cardOwnedFields.current.clear();
|
|
631
|
+
commit(initialFilterModel);
|
|
632
|
+
}, [commit, initialFilterModel]);
|
|
633
|
+
const isFieldExternallyControlled = useCallback(field => {
|
|
634
|
+
const hasFilter = filterModel.items.some(item => item.field === field);
|
|
635
|
+
return hasFilter && !cardOwnedFields.current.has(field);
|
|
636
|
+
}, [filterModel]);
|
|
637
|
+
return useMemo(() => ({
|
|
638
|
+
filterModel,
|
|
639
|
+
onFilterModelChange,
|
|
640
|
+
getSelected,
|
|
641
|
+
getValue,
|
|
642
|
+
setMultiSelect,
|
|
643
|
+
setBoolean,
|
|
644
|
+
clearField,
|
|
645
|
+
reset,
|
|
646
|
+
isFieldExternallyControlled
|
|
647
|
+
}), [filterModel, onFilterModelChange, getSelected, getValue, setMultiSelect, setBoolean, clearField, reset, isFieldExternallyControlled]);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
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 };
|
|
419
651
|
//# sourceMappingURL=index.js.map
|