@patternfly/react-data-view 5.5.1 → 5.7.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.
- package/dist/cjs/DataViewCheckboxFilter/DataViewCheckboxFilter.d.ts +29 -0
- package/dist/cjs/DataViewCheckboxFilter/DataViewCheckboxFilter.js +70 -0
- package/dist/cjs/DataViewCheckboxFilter/DataViewCheckboxFilter.test.d.ts +1 -0
- package/dist/cjs/DataViewCheckboxFilter/DataViewCheckboxFilter.test.js +25 -0
- package/dist/cjs/DataViewCheckboxFilter/index.d.ts +2 -0
- package/dist/cjs/DataViewCheckboxFilter/index.js +23 -0
- package/dist/cjs/DataViewFilters/DataViewFilters.d.ts +7 -1
- package/dist/cjs/DataViewFilters/DataViewFilters.js +16 -1
- package/dist/cjs/DataViewTextFilter/DataViewTextFilter.js +1 -1
- package/dist/cjs/Hooks/filters.js +13 -14
- package/dist/cjs/Hooks/index.d.ts +1 -0
- package/dist/cjs/Hooks/index.js +1 -0
- package/dist/cjs/Hooks/sort.d.ts +32 -0
- package/dist/cjs/Hooks/sort.js +47 -0
- package/dist/cjs/Hooks/sort.test.d.ts +1 -0
- package/dist/cjs/Hooks/sort.test.js +68 -0
- package/dist/cjs/index.d.ts +2 -0
- package/dist/cjs/index.js +4 -1
- package/dist/dynamic/DataViewCheckboxFilter/package.json +1 -0
- package/dist/esm/DataViewCheckboxFilter/DataViewCheckboxFilter.d.ts +29 -0
- package/dist/esm/DataViewCheckboxFilter/DataViewCheckboxFilter.js +62 -0
- package/dist/esm/DataViewCheckboxFilter/DataViewCheckboxFilter.test.d.ts +1 -0
- package/dist/esm/DataViewCheckboxFilter/DataViewCheckboxFilter.test.js +20 -0
- package/dist/esm/DataViewCheckboxFilter/index.d.ts +2 -0
- package/dist/esm/DataViewCheckboxFilter/index.js +2 -0
- package/dist/esm/DataViewFilters/DataViewFilters.d.ts +7 -1
- package/dist/esm/DataViewFilters/DataViewFilters.js +16 -1
- package/dist/esm/DataViewTextFilter/DataViewTextFilter.js +1 -1
- package/dist/esm/Hooks/filters.js +13 -14
- package/dist/esm/Hooks/index.d.ts +1 -0
- package/dist/esm/Hooks/index.js +1 -0
- package/dist/esm/Hooks/sort.d.ts +32 -0
- package/dist/esm/Hooks/sort.js +43 -0
- package/dist/esm/Hooks/sort.test.d.ts +1 -0
- package/dist/esm/Hooks/sort.test.js +66 -0
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +2 -0
- package/package.json +1 -1
- package/patternfly-docs/content/extensions/data-view/examples/Functionality/FiltersExample.tsx +31 -16
- package/patternfly-docs/content/extensions/data-view/examples/Functionality/Functionality.md +36 -4
- package/patternfly-docs/content/extensions/data-view/examples/Functionality/SortingExample.tsx +87 -0
- package/src/DataViewCheckboxFilter/DataViewCheckboxFilter.test.tsx +24 -0
- package/src/DataViewCheckboxFilter/DataViewCheckboxFilter.tsx +175 -0
- package/src/DataViewCheckboxFilter/__snapshots__/DataViewCheckboxFilter.test.tsx.snap +194 -0
- package/src/DataViewCheckboxFilter/index.ts +2 -0
- package/src/DataViewFilters/DataViewFilters.tsx +26 -7
- package/src/DataViewTextFilter/DataViewTextFilter.tsx +1 -0
- package/src/Hooks/filters.ts +14 -13
- package/src/Hooks/index.ts +1 -0
- package/src/Hooks/sort.test.tsx +84 -0
- package/src/Hooks/sort.ts +87 -0
- package/src/index.ts +3 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { MenuProps } from '@patternfly/react-core';
|
|
3
|
+
import { DataViewFilterOption } from '../DataViewFilters';
|
|
4
|
+
export declare const isDataViewFilterOption: (obj: unknown) => obj is DataViewFilterOption;
|
|
5
|
+
/** extends MenuProps */
|
|
6
|
+
export interface DataViewCheckboxFilterProps extends Omit<MenuProps, 'onSelect' | 'onChange'> {
|
|
7
|
+
/** Unique key for the filter attribute */
|
|
8
|
+
filterId: string;
|
|
9
|
+
/** Array of current filter values */
|
|
10
|
+
value?: string[];
|
|
11
|
+
/** Filter title displayed in the toolbar */
|
|
12
|
+
title: string;
|
|
13
|
+
/** Placeholder text of the menu */
|
|
14
|
+
placeholder?: string;
|
|
15
|
+
/** Filter options displayed */
|
|
16
|
+
options: (DataViewFilterOption | string)[];
|
|
17
|
+
/** Callback for updating when item selection changes. */
|
|
18
|
+
onChange?: (event?: React.MouseEvent, values?: string[]) => void;
|
|
19
|
+
/** Controls visibility of the filter in the toolbar */
|
|
20
|
+
showToolbarItem?: boolean;
|
|
21
|
+
/** Controls visibility of the filter icon */
|
|
22
|
+
showIcon?: boolean;
|
|
23
|
+
/** Controls visibility of the selected items badge */
|
|
24
|
+
showBadge?: boolean;
|
|
25
|
+
/** Custom OUIA ID */
|
|
26
|
+
ouiaId?: string;
|
|
27
|
+
}
|
|
28
|
+
export declare const DataViewCheckboxFilter: React.FC<DataViewCheckboxFilterProps>;
|
|
29
|
+
export default DataViewCheckboxFilter;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
3
|
+
var t = {};
|
|
4
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
5
|
+
t[p] = s[p];
|
|
6
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
7
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
8
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
9
|
+
t[p[i]] = s[p[i]];
|
|
10
|
+
}
|
|
11
|
+
return t;
|
|
12
|
+
};
|
|
13
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
14
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.DataViewCheckboxFilter = exports.isDataViewFilterOption = void 0;
|
|
18
|
+
const react_1 = __importDefault(require("react"));
|
|
19
|
+
const react_core_1 = require("@patternfly/react-core");
|
|
20
|
+
const react_icons_1 = require("@patternfly/react-icons");
|
|
21
|
+
const isToolbarChip = (chip) => typeof chip === 'object' && 'key' in chip;
|
|
22
|
+
const isDataViewFilterOption = (obj) => !!obj &&
|
|
23
|
+
typeof obj === 'object' &&
|
|
24
|
+
'label' in obj &&
|
|
25
|
+
'value' in obj &&
|
|
26
|
+
typeof obj.value === 'string';
|
|
27
|
+
exports.isDataViewFilterOption = isDataViewFilterOption;
|
|
28
|
+
const DataViewCheckboxFilter = (_a) => {
|
|
29
|
+
var { filterId, title, value = [], onChange, placeholder, options = [], showToolbarItem, showIcon = !placeholder, showBadge = !placeholder, ouiaId = 'DataViewCheckboxFilter' } = _a, props = __rest(_a, ["filterId", "title", "value", "onChange", "placeholder", "options", "showToolbarItem", "showIcon", "showBadge", "ouiaId"]);
|
|
30
|
+
const [isOpen, setIsOpen] = react_1.default.useState(false);
|
|
31
|
+
const toggleRef = react_1.default.useRef(null);
|
|
32
|
+
const menuRef = react_1.default.useRef(null);
|
|
33
|
+
const containerRef = react_1.default.useRef(null);
|
|
34
|
+
const normalizeOptions = react_1.default.useMemo(() => options.map(option => typeof option === 'string'
|
|
35
|
+
? { label: option, value: option }
|
|
36
|
+
: option), [options]);
|
|
37
|
+
const handleToggleClick = (event) => {
|
|
38
|
+
event.stopPropagation();
|
|
39
|
+
setTimeout(() => {
|
|
40
|
+
var _a;
|
|
41
|
+
const firstElement = (_a = menuRef.current) === null || _a === void 0 ? void 0 : _a.querySelector('li > button:not(:disabled)');
|
|
42
|
+
firstElement === null || firstElement === void 0 ? void 0 : firstElement.focus();
|
|
43
|
+
}, 0);
|
|
44
|
+
setIsOpen(prev => !prev);
|
|
45
|
+
};
|
|
46
|
+
const handleSelect = (event, itemId) => {
|
|
47
|
+
const activeItem = String(itemId);
|
|
48
|
+
const isSelected = value.includes(activeItem);
|
|
49
|
+
onChange === null || onChange === void 0 ? void 0 : onChange(event, isSelected ? value.filter(item => item !== activeItem) : [activeItem, ...value]);
|
|
50
|
+
};
|
|
51
|
+
const handleClickOutside = (event) => isOpen &&
|
|
52
|
+
menuRef.current && toggleRef.current &&
|
|
53
|
+
!menuRef.current.contains(event.target) && !toggleRef.current.contains(event.target)
|
|
54
|
+
&& setIsOpen(false);
|
|
55
|
+
react_1.default.useEffect(() => {
|
|
56
|
+
window.addEventListener('click', handleClickOutside);
|
|
57
|
+
return () => {
|
|
58
|
+
window.removeEventListener('click', handleClickOutside);
|
|
59
|
+
};
|
|
60
|
+
}, [isOpen]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
61
|
+
return (react_1.default.createElement(react_core_1.ToolbarFilter, { key: ouiaId, "data-ouia-component-id": ouiaId, chips: value.map(item => {
|
|
62
|
+
const activeOption = normalizeOptions.find(option => option.value === item);
|
|
63
|
+
return ({ key: activeOption === null || activeOption === void 0 ? void 0 : activeOption.value, node: activeOption === null || activeOption === void 0 ? void 0 : activeOption.label });
|
|
64
|
+
}), deleteChip: (_, chip) => onChange === null || onChange === void 0 ? void 0 : onChange(undefined, value.filter(item => item !== (isToolbarChip(chip) ? chip.key : chip))), categoryName: title, showToolbarItem: showToolbarItem },
|
|
65
|
+
react_1.default.createElement(react_core_1.Popper, { trigger: react_1.default.createElement(react_core_1.MenuToggle, { ouiaId: `${ouiaId}-toggle`, ref: toggleRef, onClick: handleToggleClick, isExpanded: isOpen, icon: showIcon ? react_1.default.createElement(react_icons_1.FilterIcon, null) : undefined, badge: value.length > 0 && showBadge ? react_1.default.createElement(react_core_1.Badge, { "data-ouia-component-id": `${ouiaId}-badge`, isRead: true }, value.length) : undefined, style: { width: '200px' } }, placeholder !== null && placeholder !== void 0 ? placeholder : title), triggerRef: toggleRef, popper: react_1.default.createElement(react_core_1.Menu, Object.assign({ ref: menuRef, ouiaId: `${ouiaId}-menu`, onSelect: handleSelect, selected: value }, props),
|
|
66
|
+
react_1.default.createElement(react_core_1.MenuContent, null,
|
|
67
|
+
react_1.default.createElement(react_core_1.MenuList, null, normalizeOptions.map(option => (react_1.default.createElement(react_core_1.MenuItem, { "data-ouia-component-id": `${ouiaId}-filter-item-${option.value}`, key: option.value, itemId: option.value, isSelected: value.includes(option.value), hasCheckbox: true }, option.label)))))), popperRef: menuRef, appendTo: containerRef.current || undefined, "aria-label": `${title !== null && title !== void 0 ? title : filterId} filter`, isVisible: isOpen })));
|
|
68
|
+
};
|
|
69
|
+
exports.DataViewCheckboxFilter = DataViewCheckboxFilter;
|
|
70
|
+
exports.default = exports.DataViewCheckboxFilter;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const react_1 = __importDefault(require("react"));
|
|
7
|
+
const react_2 = require("@testing-library/react");
|
|
8
|
+
const DataViewCheckboxFilter_1 = __importDefault(require("./DataViewCheckboxFilter"));
|
|
9
|
+
const DataViewToolbar_1 = __importDefault(require("../DataViewToolbar"));
|
|
10
|
+
describe('DataViewCheckboxFilter component', () => {
|
|
11
|
+
const defaultProps = {
|
|
12
|
+
filterId: 'test-checkbox-filter',
|
|
13
|
+
title: 'Test Checkbox Filter',
|
|
14
|
+
value: ['workspace-one'],
|
|
15
|
+
options: [
|
|
16
|
+
{ label: 'Workspace one', value: 'workspace-one' },
|
|
17
|
+
{ label: 'Workspace two', value: 'workspace-two' },
|
|
18
|
+
{ label: 'Workspace three', value: 'workspace-three' },
|
|
19
|
+
],
|
|
20
|
+
};
|
|
21
|
+
it('should render correctly', () => {
|
|
22
|
+
const { container } = (0, react_2.render)(react_1.default.createElement(DataViewToolbar_1.default, { filters: react_1.default.createElement(DataViewCheckboxFilter_1.default, Object.assign({}, defaultProps)) }));
|
|
23
|
+
expect(container).toMatchSnapshot();
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
17
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
|
+
};
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.default = void 0;
|
|
21
|
+
var DataViewCheckboxFilter_1 = require("./DataViewCheckboxFilter");
|
|
22
|
+
Object.defineProperty(exports, "default", { enumerable: true, get: function () { return __importDefault(DataViewCheckboxFilter_1).default; } });
|
|
23
|
+
__exportStar(require("./DataViewCheckboxFilter"), exports);
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
2
2
|
import { ToolbarToggleGroupProps } from '@patternfly/react-core';
|
|
3
|
+
export interface DataViewFilterOption {
|
|
4
|
+
/** Filter option label */
|
|
5
|
+
label: ReactNode;
|
|
6
|
+
/** Filter option value */
|
|
7
|
+
value: string;
|
|
8
|
+
}
|
|
3
9
|
/** extends ToolbarToggleGroupProps */
|
|
4
10
|
export interface DataViewFiltersProps<T extends object> extends Omit<ToolbarToggleGroupProps, 'toggleIcon' | 'breakpoint' | 'onChange'> {
|
|
5
11
|
/** Content rendered inside the data view */
|
|
@@ -52,6 +52,19 @@ const DataViewFilters = (_a) => {
|
|
|
52
52
|
(0, react_1.useEffect)(() => {
|
|
53
53
|
filterItems.length > 0 && setActiveAttributeMenu(filterItems[0].title);
|
|
54
54
|
}, [filterItems]);
|
|
55
|
+
const handleClickOutside = (event) => {
|
|
56
|
+
var _a, _b;
|
|
57
|
+
return isAttributeMenuOpen &&
|
|
58
|
+
!((_a = attributeMenuRef.current) === null || _a === void 0 ? void 0 : _a.contains(event.target)) &&
|
|
59
|
+
!((_b = attributeToggleRef.current) === null || _b === void 0 ? void 0 : _b.contains(event.target))
|
|
60
|
+
&& setIsAttributeMenuOpen(false);
|
|
61
|
+
};
|
|
62
|
+
(0, react_1.useEffect)(() => {
|
|
63
|
+
window.addEventListener('click', handleClickOutside);
|
|
64
|
+
return () => {
|
|
65
|
+
window.removeEventListener('click', handleClickOutside);
|
|
66
|
+
};
|
|
67
|
+
}, [isAttributeMenuOpen]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
55
68
|
const attributeToggle = (react_1.default.createElement(react_core_1.MenuToggle, { ref: attributeToggleRef, onClick: () => setIsAttributeMenuOpen(!isAttributeMenuOpen), isExpanded: isAttributeMenuOpen, icon: toggleIcon }, activeAttributeMenu));
|
|
56
69
|
const attributeMenu = (react_1.default.createElement(react_core_1.Menu, { ref: attributeMenuRef, onSelect: (_ev, itemId) => {
|
|
57
70
|
const selectedItem = filterItems.find(item => item.filterId === itemId);
|
|
@@ -64,7 +77,9 @@ const DataViewFilters = (_a) => {
|
|
|
64
77
|
react_1.default.createElement(react_core_1.ToolbarGroup, { variant: "filter-group" },
|
|
65
78
|
react_1.default.createElement("div", { ref: attributeContainerRef },
|
|
66
79
|
react_1.default.createElement(react_core_1.Popper, { trigger: attributeToggle, triggerRef: attributeToggleRef, popper: attributeMenu, popperRef: attributeMenuRef, appendTo: attributeContainerRef.current || undefined, isVisible: isAttributeMenuOpen })),
|
|
67
|
-
react_1.default.Children.map(children, (child) =>
|
|
80
|
+
react_1.default.Children.map(children, (child) => react_1.default.isValidElement(child)
|
|
81
|
+
? react_1.default.cloneElement(child, Object.assign({ showToolbarItem: activeAttributeMenu === child.props.title, onChange: (event, value) => onChange === null || onChange === void 0 ? void 0 : onChange(event, { [child.props.filterId]: value }), value: values === null || values === void 0 ? void 0 : values[child.props.filterId] }, child.props))
|
|
82
|
+
: child))));
|
|
68
83
|
};
|
|
69
84
|
exports.DataViewFilters = DataViewFilters;
|
|
70
85
|
exports.default = exports.DataViewFilters;
|
|
@@ -19,7 +19,7 @@ const react_1 = __importDefault(require("react"));
|
|
|
19
19
|
const react_core_1 = require("@patternfly/react-core");
|
|
20
20
|
const DataViewTextFilter = (_a) => {
|
|
21
21
|
var { filterId, title, value = '', onChange, onClear = () => onChange === null || onChange === void 0 ? void 0 : onChange(undefined, ''), showToolbarItem, trimValue = true, ouiaId = 'DataViewTextFilter' } = _a, props = __rest(_a, ["filterId", "title", "value", "onChange", "onClear", "showToolbarItem", "trimValue", "ouiaId"]);
|
|
22
|
-
return (react_1.default.createElement(react_core_1.ToolbarFilter, { "data-ouia-component-id": ouiaId, chips: value.length > 0 ? [{ key: title, node: value }] : [], deleteChip: () => onChange === null || onChange === void 0 ? void 0 : onChange(undefined, ''), categoryName: title, showToolbarItem: showToolbarItem },
|
|
22
|
+
return (react_1.default.createElement(react_core_1.ToolbarFilter, { key: ouiaId, "data-ouia-component-id": ouiaId, chips: value.length > 0 ? [{ key: title, node: value }] : [], deleteChip: () => onChange === null || onChange === void 0 ? void 0 : onChange(undefined, ''), categoryName: title, showToolbarItem: showToolbarItem },
|
|
23
23
|
react_1.default.createElement(react_core_1.SearchInput, Object.assign({ searchInputId: filterId, value: value, onChange: (e, inputValue) => onChange === null || onChange === void 0 ? void 0 : onChange(e, trimValue ? inputValue.trim() : inputValue), onClear: onClear, placeholder: `Filter by ${title}`, "aria-label": `${title !== null && title !== void 0 ? title : filterId} filter`, "data-ouia-component-id": `${ouiaId}-input` }, props))));
|
|
24
24
|
};
|
|
25
25
|
exports.DataViewTextFilter = DataViewTextFilter;
|
|
@@ -5,25 +5,24 @@ const react_1 = require("react");
|
|
|
5
5
|
;
|
|
6
6
|
const useDataViewFilters = ({ initialFilters = {}, searchParams, setSearchParams, }) => {
|
|
7
7
|
const isUrlSyncEnabled = (0, react_1.useMemo)(() => searchParams && !!setSearchParams, [searchParams, setSearchParams]);
|
|
8
|
-
const getInitialFilters = (0, react_1.useCallback)(() => isUrlSyncEnabled
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
8
|
+
const getInitialFilters = (0, react_1.useCallback)(() => isUrlSyncEnabled
|
|
9
|
+
? Object.keys(initialFilters).reduce((loadedFilters, key) => {
|
|
10
|
+
const urlValue = searchParams === null || searchParams === void 0 ? void 0 : searchParams.get(key);
|
|
11
|
+
const isArrayFilter = Array.isArray(initialFilters[key]);
|
|
12
|
+
// eslint-disable-next-line no-nested-ternary
|
|
13
|
+
loadedFilters[key] = urlValue
|
|
14
|
+
? (isArrayFilter && !Array.isArray(urlValue) ? [urlValue] : urlValue)
|
|
15
|
+
: initialFilters[key];
|
|
16
|
+
return loadedFilters;
|
|
17
|
+
}, Object.assign({}, initialFilters))
|
|
18
|
+
: initialFilters, [isUrlSyncEnabled, initialFilters, searchParams]);
|
|
16
19
|
const [filters, setFilters] = (0, react_1.useState)(getInitialFilters());
|
|
17
20
|
const updateSearchParams = (0, react_1.useCallback)((newFilters) => {
|
|
18
21
|
if (isUrlSyncEnabled) {
|
|
19
22
|
const params = new URLSearchParams(searchParams);
|
|
20
23
|
Object.entries(newFilters).forEach(([key, value]) => {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
else {
|
|
25
|
-
params.delete(key);
|
|
26
|
-
}
|
|
24
|
+
params.delete(key);
|
|
25
|
+
(Array.isArray(value) ? value : [value]).forEach((val) => value && params.append(key, val));
|
|
27
26
|
});
|
|
28
27
|
setSearchParams === null || setSearchParams === void 0 ? void 0 : setSearchParams(params);
|
|
29
28
|
}
|
package/dist/cjs/Hooks/index.js
CHANGED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ISortBy } from "@patternfly/react-table";
|
|
2
|
+
export declare enum DataViewSortParams {
|
|
3
|
+
SORT_BY = "sortBy",
|
|
4
|
+
DIRECTION = "direction"
|
|
5
|
+
}
|
|
6
|
+
export interface DataViewSortConfig {
|
|
7
|
+
/** Attribute to sort the entries by */
|
|
8
|
+
sortBy: string | undefined;
|
|
9
|
+
/** Sort direction */
|
|
10
|
+
direction: ISortBy['direction'];
|
|
11
|
+
}
|
|
12
|
+
export interface UseDataViewSortProps {
|
|
13
|
+
/** Initial sort config */
|
|
14
|
+
initialSort?: DataViewSortConfig;
|
|
15
|
+
/** Current search parameters as a string */
|
|
16
|
+
searchParams?: URLSearchParams;
|
|
17
|
+
/** Function to set search parameters */
|
|
18
|
+
setSearchParams?: (params: URLSearchParams) => void;
|
|
19
|
+
/** Default direction */
|
|
20
|
+
defaultDirection?: ISortBy['direction'];
|
|
21
|
+
/** Sort by URL param name */
|
|
22
|
+
sortByParam?: string;
|
|
23
|
+
/** Direction URL param name */
|
|
24
|
+
directionParam?: string;
|
|
25
|
+
}
|
|
26
|
+
export declare const useDataViewSort: (props?: UseDataViewSortProps) => {
|
|
27
|
+
onSort: (_event: React.MouseEvent | React.KeyboardEvent | MouseEvent | undefined, newSortBy: string, newSortDirection: ISortBy['direction']) => void;
|
|
28
|
+
/** Attribute to sort the entries by */
|
|
29
|
+
sortBy: string | undefined;
|
|
30
|
+
/** Sort direction */
|
|
31
|
+
direction: ISortBy['direction'];
|
|
32
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useDataViewSort = exports.DataViewSortParams = void 0;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
var DataViewSortParams;
|
|
6
|
+
(function (DataViewSortParams) {
|
|
7
|
+
DataViewSortParams["SORT_BY"] = "sortBy";
|
|
8
|
+
DataViewSortParams["DIRECTION"] = "direction";
|
|
9
|
+
})(DataViewSortParams || (exports.DataViewSortParams = DataViewSortParams = {}));
|
|
10
|
+
;
|
|
11
|
+
const validateDirection = (direction, defaultDirection) => (direction === 'asc' || direction === 'desc' ? direction : defaultDirection);
|
|
12
|
+
;
|
|
13
|
+
;
|
|
14
|
+
const useDataViewSort = (props) => {
|
|
15
|
+
var _a;
|
|
16
|
+
const { initialSort, searchParams, setSearchParams, defaultDirection = 'asc', sortByParam = DataViewSortParams.SORT_BY, directionParam = DataViewSortParams.DIRECTION } = props !== null && props !== void 0 ? props : {};
|
|
17
|
+
const isUrlSyncEnabled = (0, react_1.useMemo)(() => searchParams && !!setSearchParams, [searchParams, setSearchParams]);
|
|
18
|
+
const [state, setState] = (0, react_1.useState)({
|
|
19
|
+
sortBy: (_a = searchParams === null || searchParams === void 0 ? void 0 : searchParams.get(sortByParam)) !== null && _a !== void 0 ? _a : initialSort === null || initialSort === void 0 ? void 0 : initialSort.sortBy,
|
|
20
|
+
direction: validateDirection(searchParams === null || searchParams === void 0 ? void 0 : searchParams.get(directionParam), initialSort === null || initialSort === void 0 ? void 0 : initialSort.direction),
|
|
21
|
+
});
|
|
22
|
+
const updateSearchParams = (sortBy, direction) => {
|
|
23
|
+
if (isUrlSyncEnabled && sortBy) {
|
|
24
|
+
const params = new URLSearchParams(searchParams);
|
|
25
|
+
params.set(sortByParam, `${sortBy}`);
|
|
26
|
+
params.set(directionParam, `${direction}`);
|
|
27
|
+
setSearchParams === null || setSearchParams === void 0 ? void 0 : setSearchParams(params);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
(0, react_1.useEffect)(() => {
|
|
31
|
+
state.sortBy && state.direction && updateSearchParams(state.sortBy, state.direction);
|
|
32
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
33
|
+
}, []);
|
|
34
|
+
(0, react_1.useEffect)(() => {
|
|
35
|
+
const currentSortBy = (searchParams === null || searchParams === void 0 ? void 0 : searchParams.get(sortByParam)) || state.sortBy;
|
|
36
|
+
const currentDirection = (searchParams === null || searchParams === void 0 ? void 0 : searchParams.get(directionParam)) || state.direction;
|
|
37
|
+
const validDirection = validateDirection(currentDirection, defaultDirection);
|
|
38
|
+
currentSortBy !== state.sortBy || validDirection !== state.direction && setState({ sortBy: currentSortBy, direction: validDirection });
|
|
39
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
40
|
+
}, [searchParams === null || searchParams === void 0 ? void 0 : searchParams.toString()]);
|
|
41
|
+
const onSort = (_event, newSortBy, newSortDirection) => {
|
|
42
|
+
setState({ sortBy: newSortBy, direction: newSortDirection });
|
|
43
|
+
updateSearchParams(newSortBy, newSortDirection);
|
|
44
|
+
};
|
|
45
|
+
return Object.assign(Object.assign({}, state), { onSort });
|
|
46
|
+
};
|
|
47
|
+
exports.useDataViewSort = useDataViewSort;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '@testing-library/jest-dom';
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
require("@testing-library/jest-dom");
|
|
4
|
+
const react_1 = require("@testing-library/react");
|
|
5
|
+
const sort_1 = require("./sort");
|
|
6
|
+
describe('useDataViewSort', () => {
|
|
7
|
+
const initialSort = { sortBy: 'name', direction: 'asc' };
|
|
8
|
+
it('should initialize with provided initial sort config', () => {
|
|
9
|
+
const { result } = (0, react_1.renderHook)(() => (0, sort_1.useDataViewSort)({ initialSort }));
|
|
10
|
+
expect(result.current).toEqual(expect.objectContaining(initialSort));
|
|
11
|
+
});
|
|
12
|
+
it('should initialize with empty sort config if no initialSort is provided', () => {
|
|
13
|
+
const { result } = (0, react_1.renderHook)(() => (0, sort_1.useDataViewSort)());
|
|
14
|
+
expect(result.current).toEqual(expect.objectContaining({ sortBy: undefined, direction: 'asc' }));
|
|
15
|
+
});
|
|
16
|
+
it('should update sort state when onSort is called', () => {
|
|
17
|
+
const { result } = (0, react_1.renderHook)(() => (0, sort_1.useDataViewSort)({ initialSort }));
|
|
18
|
+
(0, react_1.act)(() => {
|
|
19
|
+
result.current.onSort(undefined, 'age', 'desc');
|
|
20
|
+
});
|
|
21
|
+
expect(result.current).toEqual(expect.objectContaining({ sortBy: 'age', direction: 'desc' }));
|
|
22
|
+
});
|
|
23
|
+
it('should sync with URL search params if isUrlSyncEnabled', () => {
|
|
24
|
+
const searchParams = new URLSearchParams();
|
|
25
|
+
const setSearchParams = jest.fn();
|
|
26
|
+
const props = {
|
|
27
|
+
initialSort,
|
|
28
|
+
searchParams,
|
|
29
|
+
setSearchParams,
|
|
30
|
+
};
|
|
31
|
+
const { result } = (0, react_1.renderHook)(() => (0, sort_1.useDataViewSort)(props));
|
|
32
|
+
expect(setSearchParams).toHaveBeenCalledTimes(1);
|
|
33
|
+
expect(result.current).toEqual(expect.objectContaining(initialSort));
|
|
34
|
+
});
|
|
35
|
+
it('should validate direction and fallback to default direction if invalid direction is provided', () => {
|
|
36
|
+
const searchParams = new URLSearchParams();
|
|
37
|
+
searchParams.set(sort_1.DataViewSortParams.SORT_BY, 'name');
|
|
38
|
+
searchParams.set(sort_1.DataViewSortParams.DIRECTION, 'invalid-direction');
|
|
39
|
+
const { result } = (0, react_1.renderHook)(() => (0, sort_1.useDataViewSort)({ searchParams, defaultDirection: 'desc' }));
|
|
40
|
+
expect(result.current).toEqual(expect.objectContaining({ sortBy: 'name', direction: 'desc' }));
|
|
41
|
+
});
|
|
42
|
+
it('should update search params when URL sync is enabled and sort changes', () => {
|
|
43
|
+
const searchParams = new URLSearchParams();
|
|
44
|
+
const setSearchParams = jest.fn();
|
|
45
|
+
const props = {
|
|
46
|
+
initialSort,
|
|
47
|
+
searchParams,
|
|
48
|
+
setSearchParams,
|
|
49
|
+
};
|
|
50
|
+
const { result } = (0, react_1.renderHook)(() => (0, sort_1.useDataViewSort)(props));
|
|
51
|
+
(0, react_1.act)(() => {
|
|
52
|
+
expect(setSearchParams).toHaveBeenCalledTimes(1);
|
|
53
|
+
result.current.onSort(undefined, 'priority', 'desc');
|
|
54
|
+
});
|
|
55
|
+
expect(setSearchParams).toHaveBeenCalledTimes(2);
|
|
56
|
+
expect(result.current).toEqual(expect.objectContaining({ sortBy: 'priority', direction: 'desc' }));
|
|
57
|
+
});
|
|
58
|
+
it('should prioritize searchParams values', () => {
|
|
59
|
+
const searchParams = new URLSearchParams();
|
|
60
|
+
searchParams.set(sort_1.DataViewSortParams.SORT_BY, 'category');
|
|
61
|
+
searchParams.set(sort_1.DataViewSortParams.DIRECTION, 'desc');
|
|
62
|
+
const { result } = (0, react_1.renderHook)((props) => (0, sort_1.useDataViewSort)(props), { initialProps: { initialSort, searchParams } });
|
|
63
|
+
expect(result.current).toEqual(expect.objectContaining({
|
|
64
|
+
sortBy: 'category',
|
|
65
|
+
direction: 'desc',
|
|
66
|
+
}));
|
|
67
|
+
});
|
|
68
|
+
});
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -15,5 +15,7 @@ export { default as DataViewTable } from './DataViewTable';
|
|
|
15
15
|
export * from './DataViewTable';
|
|
16
16
|
export { default as DataViewEventsContext } from './DataViewEventsContext';
|
|
17
17
|
export * from './DataViewEventsContext';
|
|
18
|
+
export { default as DataViewCheckboxFilter } from './DataViewCheckboxFilter';
|
|
19
|
+
export * from './DataViewCheckboxFilter';
|
|
18
20
|
export { default as DataView } from './DataView';
|
|
19
21
|
export * from './DataView';
|
package/dist/cjs/index.js
CHANGED
|
@@ -18,7 +18,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
18
18
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
19
19
|
};
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
-
exports.DataView = exports.DataViewEventsContext = exports.DataViewTable = exports.DataViewTableBasic = exports.DataViewTableHead = exports.DataViewTableTree = exports.DataViewTextFilter = exports.DataViewToolbar = exports.InternalContext = void 0;
|
|
21
|
+
exports.DataView = exports.DataViewCheckboxFilter = exports.DataViewEventsContext = exports.DataViewTable = exports.DataViewTableBasic = exports.DataViewTableHead = exports.DataViewTableTree = exports.DataViewTextFilter = exports.DataViewToolbar = exports.InternalContext = void 0;
|
|
22
22
|
var InternalContext_1 = require("./InternalContext");
|
|
23
23
|
Object.defineProperty(exports, "InternalContext", { enumerable: true, get: function () { return __importDefault(InternalContext_1).default; } });
|
|
24
24
|
__exportStar(require("./InternalContext"), exports);
|
|
@@ -44,6 +44,9 @@ __exportStar(require("./DataViewTable"), exports);
|
|
|
44
44
|
var DataViewEventsContext_1 = require("./DataViewEventsContext");
|
|
45
45
|
Object.defineProperty(exports, "DataViewEventsContext", { enumerable: true, get: function () { return __importDefault(DataViewEventsContext_1).default; } });
|
|
46
46
|
__exportStar(require("./DataViewEventsContext"), exports);
|
|
47
|
+
var DataViewCheckboxFilter_1 = require("./DataViewCheckboxFilter");
|
|
48
|
+
Object.defineProperty(exports, "DataViewCheckboxFilter", { enumerable: true, get: function () { return __importDefault(DataViewCheckboxFilter_1).default; } });
|
|
49
|
+
__exportStar(require("./DataViewCheckboxFilter"), exports);
|
|
47
50
|
var DataView_1 = require("./DataView");
|
|
48
51
|
Object.defineProperty(exports, "DataView", { enumerable: true, get: function () { return __importDefault(DataView_1).default; } });
|
|
49
52
|
__exportStar(require("./DataView"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"main":"../../cjs/DataViewCheckboxFilter/index.js","module":"../../esm/DataViewCheckboxFilter/index.js","typings":"../../esm/DataViewCheckboxFilter/index.d.ts"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { MenuProps } from '@patternfly/react-core';
|
|
3
|
+
import { DataViewFilterOption } from '../DataViewFilters';
|
|
4
|
+
export declare const isDataViewFilterOption: (obj: unknown) => obj is DataViewFilterOption;
|
|
5
|
+
/** extends MenuProps */
|
|
6
|
+
export interface DataViewCheckboxFilterProps extends Omit<MenuProps, 'onSelect' | 'onChange'> {
|
|
7
|
+
/** Unique key for the filter attribute */
|
|
8
|
+
filterId: string;
|
|
9
|
+
/** Array of current filter values */
|
|
10
|
+
value?: string[];
|
|
11
|
+
/** Filter title displayed in the toolbar */
|
|
12
|
+
title: string;
|
|
13
|
+
/** Placeholder text of the menu */
|
|
14
|
+
placeholder?: string;
|
|
15
|
+
/** Filter options displayed */
|
|
16
|
+
options: (DataViewFilterOption | string)[];
|
|
17
|
+
/** Callback for updating when item selection changes. */
|
|
18
|
+
onChange?: (event?: React.MouseEvent, values?: string[]) => void;
|
|
19
|
+
/** Controls visibility of the filter in the toolbar */
|
|
20
|
+
showToolbarItem?: boolean;
|
|
21
|
+
/** Controls visibility of the filter icon */
|
|
22
|
+
showIcon?: boolean;
|
|
23
|
+
/** Controls visibility of the selected items badge */
|
|
24
|
+
showBadge?: boolean;
|
|
25
|
+
/** Custom OUIA ID */
|
|
26
|
+
ouiaId?: string;
|
|
27
|
+
}
|
|
28
|
+
export declare const DataViewCheckboxFilter: React.FC<DataViewCheckboxFilterProps>;
|
|
29
|
+
export default DataViewCheckboxFilter;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
import React from 'react';
|
|
13
|
+
import { Badge, Menu, MenuContent, MenuItem, MenuList, MenuToggle, Popper, ToolbarFilter, } from '@patternfly/react-core';
|
|
14
|
+
import { FilterIcon } from '@patternfly/react-icons';
|
|
15
|
+
const isToolbarChip = (chip) => typeof chip === 'object' && 'key' in chip;
|
|
16
|
+
export const isDataViewFilterOption = (obj) => !!obj &&
|
|
17
|
+
typeof obj === 'object' &&
|
|
18
|
+
'label' in obj &&
|
|
19
|
+
'value' in obj &&
|
|
20
|
+
typeof obj.value === 'string';
|
|
21
|
+
export const DataViewCheckboxFilter = (_a) => {
|
|
22
|
+
var { filterId, title, value = [], onChange, placeholder, options = [], showToolbarItem, showIcon = !placeholder, showBadge = !placeholder, ouiaId = 'DataViewCheckboxFilter' } = _a, props = __rest(_a, ["filterId", "title", "value", "onChange", "placeholder", "options", "showToolbarItem", "showIcon", "showBadge", "ouiaId"]);
|
|
23
|
+
const [isOpen, setIsOpen] = React.useState(false);
|
|
24
|
+
const toggleRef = React.useRef(null);
|
|
25
|
+
const menuRef = React.useRef(null);
|
|
26
|
+
const containerRef = React.useRef(null);
|
|
27
|
+
const normalizeOptions = React.useMemo(() => options.map(option => typeof option === 'string'
|
|
28
|
+
? { label: option, value: option }
|
|
29
|
+
: option), [options]);
|
|
30
|
+
const handleToggleClick = (event) => {
|
|
31
|
+
event.stopPropagation();
|
|
32
|
+
setTimeout(() => {
|
|
33
|
+
var _a;
|
|
34
|
+
const firstElement = (_a = menuRef.current) === null || _a === void 0 ? void 0 : _a.querySelector('li > button:not(:disabled)');
|
|
35
|
+
firstElement === null || firstElement === void 0 ? void 0 : firstElement.focus();
|
|
36
|
+
}, 0);
|
|
37
|
+
setIsOpen(prev => !prev);
|
|
38
|
+
};
|
|
39
|
+
const handleSelect = (event, itemId) => {
|
|
40
|
+
const activeItem = String(itemId);
|
|
41
|
+
const isSelected = value.includes(activeItem);
|
|
42
|
+
onChange === null || onChange === void 0 ? void 0 : onChange(event, isSelected ? value.filter(item => item !== activeItem) : [activeItem, ...value]);
|
|
43
|
+
};
|
|
44
|
+
const handleClickOutside = (event) => isOpen &&
|
|
45
|
+
menuRef.current && toggleRef.current &&
|
|
46
|
+
!menuRef.current.contains(event.target) && !toggleRef.current.contains(event.target)
|
|
47
|
+
&& setIsOpen(false);
|
|
48
|
+
React.useEffect(() => {
|
|
49
|
+
window.addEventListener('click', handleClickOutside);
|
|
50
|
+
return () => {
|
|
51
|
+
window.removeEventListener('click', handleClickOutside);
|
|
52
|
+
};
|
|
53
|
+
}, [isOpen]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
54
|
+
return (React.createElement(ToolbarFilter, { key: ouiaId, "data-ouia-component-id": ouiaId, chips: value.map(item => {
|
|
55
|
+
const activeOption = normalizeOptions.find(option => option.value === item);
|
|
56
|
+
return ({ key: activeOption === null || activeOption === void 0 ? void 0 : activeOption.value, node: activeOption === null || activeOption === void 0 ? void 0 : activeOption.label });
|
|
57
|
+
}), deleteChip: (_, chip) => onChange === null || onChange === void 0 ? void 0 : onChange(undefined, value.filter(item => item !== (isToolbarChip(chip) ? chip.key : chip))), categoryName: title, showToolbarItem: showToolbarItem },
|
|
58
|
+
React.createElement(Popper, { trigger: React.createElement(MenuToggle, { ouiaId: `${ouiaId}-toggle`, ref: toggleRef, onClick: handleToggleClick, isExpanded: isOpen, icon: showIcon ? React.createElement(FilterIcon, null) : undefined, badge: value.length > 0 && showBadge ? React.createElement(Badge, { "data-ouia-component-id": `${ouiaId}-badge`, isRead: true }, value.length) : undefined, style: { width: '200px' } }, placeholder !== null && placeholder !== void 0 ? placeholder : title), triggerRef: toggleRef, popper: React.createElement(Menu, Object.assign({ ref: menuRef, ouiaId: `${ouiaId}-menu`, onSelect: handleSelect, selected: value }, props),
|
|
59
|
+
React.createElement(MenuContent, null,
|
|
60
|
+
React.createElement(MenuList, null, normalizeOptions.map(option => (React.createElement(MenuItem, { "data-ouia-component-id": `${ouiaId}-filter-item-${option.value}`, key: option.value, itemId: option.value, isSelected: value.includes(option.value), hasCheckbox: true }, option.label)))))), popperRef: menuRef, appendTo: containerRef.current || undefined, "aria-label": `${title !== null && title !== void 0 ? title : filterId} filter`, isVisible: isOpen })));
|
|
61
|
+
};
|
|
62
|
+
export default DataViewCheckboxFilter;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render } from '@testing-library/react';
|
|
3
|
+
import DataViewCheckboxFilter from './DataViewCheckboxFilter';
|
|
4
|
+
import DataViewToolbar from '../DataViewToolbar';
|
|
5
|
+
describe('DataViewCheckboxFilter component', () => {
|
|
6
|
+
const defaultProps = {
|
|
7
|
+
filterId: 'test-checkbox-filter',
|
|
8
|
+
title: 'Test Checkbox Filter',
|
|
9
|
+
value: ['workspace-one'],
|
|
10
|
+
options: [
|
|
11
|
+
{ label: 'Workspace one', value: 'workspace-one' },
|
|
12
|
+
{ label: 'Workspace two', value: 'workspace-two' },
|
|
13
|
+
{ label: 'Workspace three', value: 'workspace-three' },
|
|
14
|
+
],
|
|
15
|
+
};
|
|
16
|
+
it('should render correctly', () => {
|
|
17
|
+
const { container } = render(React.createElement(DataViewToolbar, { filters: React.createElement(DataViewCheckboxFilter, Object.assign({}, defaultProps)) }));
|
|
18
|
+
expect(container).toMatchSnapshot();
|
|
19
|
+
});
|
|
20
|
+
});
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
2
2
|
import { ToolbarToggleGroupProps } from '@patternfly/react-core';
|
|
3
|
+
export interface DataViewFilterOption {
|
|
4
|
+
/** Filter option label */
|
|
5
|
+
label: ReactNode;
|
|
6
|
+
/** Filter option value */
|
|
7
|
+
value: string;
|
|
8
|
+
}
|
|
3
9
|
/** extends ToolbarToggleGroupProps */
|
|
4
10
|
export interface DataViewFiltersProps<T extends object> extends Omit<ToolbarToggleGroupProps, 'toggleIcon' | 'breakpoint' | 'onChange'> {
|
|
5
11
|
/** Content rendered inside the data view */
|