@patternfly/react-data-view 6.1.0-prerelease.1 → 7.0.0-prerelease.2
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/DataView/DataView.d.ts +12 -0
- package/dist/cjs/DataView/DataView.js +14 -3
- package/dist/cjs/DataViewEventsContext/DataViewEventsContext.d.ts +16 -0
- package/dist/cjs/DataViewEventsContext/DataViewEventsContext.js +62 -0
- package/dist/cjs/DataViewEventsContext/DataViewEventsContext.test.d.ts +1 -0
- package/dist/cjs/DataViewEventsContext/DataViewEventsContext.test.js +72 -0
- package/dist/cjs/DataViewEventsContext/index.d.ts +2 -0
- package/dist/cjs/DataViewEventsContext/index.js +23 -0
- package/dist/cjs/DataViewTable/DataViewTable.d.ts +41 -0
- package/dist/cjs/DataViewTable/DataViewTable.js +18 -0
- package/dist/cjs/DataViewTable/DataViewTable.test.d.ts +1 -0
- package/dist/cjs/DataViewTable/DataViewTable.test.js +57 -0
- package/dist/cjs/DataViewTable/index.d.ts +2 -0
- package/dist/cjs/DataViewTable/index.js +23 -0
- package/dist/cjs/DataViewTableBasic/DataViewTableBasic.d.ts +18 -0
- package/dist/cjs/DataViewTableBasic/DataViewTableBasic.js +71 -0
- package/dist/cjs/DataViewTableBasic/DataViewTableBasic.test.d.ts +1 -0
- package/dist/cjs/DataViewTableBasic/DataViewTableBasic.test.js +43 -0
- package/dist/cjs/DataViewTableBasic/index.d.ts +2 -0
- package/dist/cjs/DataViewTableBasic/index.js +23 -0
- package/dist/cjs/DataViewTableHead/DataViewTableHead.d.ts +13 -0
- package/dist/cjs/DataViewTableHead/DataViewTableHead.js +57 -0
- package/dist/cjs/DataViewTableHead/DataViewTableHead.test.d.ts +1 -0
- package/dist/cjs/DataViewTableHead/DataViewTableHead.test.js +36 -0
- package/dist/cjs/DataViewTableHead/index.d.ts +2 -0
- package/dist/cjs/DataViewTableHead/index.js +23 -0
- package/dist/cjs/DataViewTableTree/DataViewTableTree.d.ts +24 -0
- package/dist/cjs/DataViewTableTree/DataViewTableTree.js +132 -0
- package/dist/cjs/DataViewTableTree/DataViewTableTree.test.d.ts +1 -0
- package/dist/cjs/DataViewTableTree/DataViewTableTree.test.js +90 -0
- package/dist/cjs/DataViewTableTree/index.d.ts +2 -0
- package/dist/cjs/DataViewTableTree/index.js +23 -0
- package/dist/cjs/DataViewToolbar/DataViewToolbar.d.ts +2 -0
- package/dist/cjs/DataViewToolbar/DataViewToolbar.js +2 -1
- package/dist/cjs/Hooks/pagination.d.ts +13 -1
- package/dist/cjs/Hooks/pagination.js +36 -4
- package/dist/cjs/Hooks/pagination.test.js +1 -1
- package/dist/cjs/Hooks/selection.d.ts +3 -3
- package/dist/cjs/Hooks/selection.js +4 -6
- package/dist/cjs/Hooks/selection.test.js +4 -4
- package/dist/cjs/InternalContext/InternalContext.d.ts +25 -0
- package/dist/cjs/InternalContext/InternalContext.js +40 -0
- package/dist/cjs/InternalContext/InternalContext.test.d.ts +1 -0
- package/dist/cjs/InternalContext/InternalContext.test.js +56 -0
- package/dist/cjs/InternalContext/index.d.ts +2 -0
- package/dist/cjs/InternalContext/index.js +23 -0
- package/dist/cjs/index.d.ts +12 -0
- package/dist/cjs/index.js +20 -2
- package/dist/dynamic/DataViewEventsContext/package.json +1 -0
- package/dist/dynamic/DataViewTable/package.json +1 -0
- package/dist/dynamic/DataViewTableBasic/package.json +1 -0
- package/dist/dynamic/DataViewTableHead/package.json +1 -0
- package/dist/dynamic/DataViewTableTree/package.json +1 -0
- package/dist/dynamic/InternalContext/package.json +1 -0
- package/dist/esm/DataView/DataView.d.ts +12 -0
- package/dist/esm/DataView/DataView.js +13 -2
- package/dist/esm/DataViewEventsContext/DataViewEventsContext.d.ts +16 -0
- package/dist/esm/DataViewEventsContext/DataViewEventsContext.js +34 -0
- package/dist/esm/DataViewEventsContext/DataViewEventsContext.test.d.ts +1 -0
- package/dist/esm/DataViewEventsContext/DataViewEventsContext.test.js +67 -0
- package/dist/esm/DataViewEventsContext/index.d.ts +2 -0
- package/dist/esm/DataViewEventsContext/index.js +2 -0
- package/dist/esm/DataViewTable/DataViewTable.d.ts +41 -0
- package/dist/esm/DataViewTable/DataViewTable.js +8 -0
- package/dist/esm/DataViewTable/DataViewTable.test.d.ts +1 -0
- package/dist/esm/DataViewTable/DataViewTable.test.js +52 -0
- package/dist/esm/DataViewTable/index.d.ts +2 -0
- package/dist/esm/DataViewTable/index.js +2 -0
- package/dist/esm/DataViewTableBasic/DataViewTableBasic.d.ts +18 -0
- package/dist/esm/DataViewTableBasic/DataViewTableBasic.js +44 -0
- package/dist/esm/DataViewTableBasic/DataViewTableBasic.test.d.ts +1 -0
- package/dist/esm/DataViewTableBasic/DataViewTableBasic.test.js +38 -0
- package/dist/esm/DataViewTableBasic/index.d.ts +2 -0
- package/dist/esm/DataViewTableBasic/index.js +2 -0
- package/dist/esm/DataViewTableHead/DataViewTableHead.d.ts +13 -0
- package/dist/esm/DataViewTableHead/DataViewTableHead.js +30 -0
- package/dist/esm/DataViewTableHead/DataViewTableHead.test.d.ts +1 -0
- package/dist/esm/DataViewTableHead/DataViewTableHead.test.js +31 -0
- package/dist/esm/DataViewTableHead/index.d.ts +2 -0
- package/dist/esm/DataViewTableHead/index.js +2 -0
- package/dist/esm/DataViewTableTree/DataViewTableTree.d.ts +24 -0
- package/dist/esm/DataViewTableTree/DataViewTableTree.js +105 -0
- package/dist/esm/DataViewTableTree/DataViewTableTree.test.d.ts +1 -0
- package/dist/esm/DataViewTableTree/DataViewTableTree.test.js +85 -0
- package/dist/esm/DataViewTableTree/index.d.ts +2 -0
- package/dist/esm/DataViewTableTree/index.js +2 -0
- package/dist/esm/DataViewToolbar/DataViewToolbar.d.ts +2 -0
- package/dist/esm/DataViewToolbar/DataViewToolbar.js +2 -1
- package/dist/esm/Hooks/pagination.d.ts +13 -1
- package/dist/esm/Hooks/pagination.js +36 -4
- package/dist/esm/Hooks/pagination.test.js +1 -1
- package/dist/esm/Hooks/selection.d.ts +3 -3
- package/dist/esm/Hooks/selection.js +4 -6
- package/dist/esm/Hooks/selection.test.js +4 -4
- package/dist/esm/InternalContext/InternalContext.d.ts +25 -0
- package/dist/esm/InternalContext/InternalContext.js +12 -0
- package/dist/esm/InternalContext/InternalContext.test.d.ts +1 -0
- package/dist/esm/InternalContext/InternalContext.test.js +51 -0
- package/dist/esm/InternalContext/index.d.ts +2 -0
- package/dist/esm/InternalContext/index.js +2 -0
- package/dist/esm/index.d.ts +12 -0
- package/dist/esm/index.js +12 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +9 -9
- package/patternfly-docs/content/extensions/data-view/examples/Components/Components.md +80 -5
- package/patternfly-docs/content/extensions/data-view/examples/Components/DataViewTableEmptyExample.tsx +57 -0
- package/patternfly-docs/content/extensions/data-view/examples/Components/DataViewTableErrorExample.tsx +45 -0
- package/patternfly-docs/content/extensions/data-view/examples/Components/DataViewTableExample.tsx +67 -0
- package/patternfly-docs/content/extensions/data-view/examples/Components/DataViewTableLoadingExample.tsx +27 -0
- package/patternfly-docs/content/extensions/data-view/examples/Components/DataViewTableTreeExample.tsx +71 -0
- package/patternfly-docs/content/extensions/data-view/examples/Components/DataViewToolbarActionsExample.tsx +27 -0
- package/patternfly-docs/content/extensions/data-view/examples/Components/DataViewToolbarExample.tsx +4 -4
- package/patternfly-docs/content/extensions/data-view/examples/EventsContext/EventsContext.md +32 -0
- package/patternfly-docs/content/extensions/data-view/examples/EventsContext/EventsExample.tsx +108 -0
- package/patternfly-docs/content/extensions/data-view/examples/Functionality/Functionality.md +14 -6
- package/patternfly-docs/content/extensions/data-view/examples/Functionality/PaginationExample.tsx +28 -37
- package/patternfly-docs/content/extensions/data-view/examples/Functionality/SelectionExample.tsx +15 -46
- package/patternfly-docs/content/extensions/data-view/examples/Layout/Layout.md +2 -1
- package/patternfly-docs/content/extensions/data-view/examples/Layout/PredefinedLayoutExample.tsx +20 -51
- package/patternfly-docs/pages/index.js +1 -1
- package/src/DataView/DataView.tsx +25 -3
- package/src/DataView/__snapshots__/DataView.test.tsx.snap +2 -2
- package/src/DataViewEventsContext/DataViewEventsContext.test.tsx +105 -0
- package/src/DataViewEventsContext/DataViewEventsContext.tsx +70 -0
- package/src/DataViewEventsContext/index.ts +2 -0
- package/src/DataViewTable/DataViewTable.test.tsx +80 -0
- package/src/DataViewTable/DataViewTable.tsx +37 -0
- package/src/DataViewTable/__snapshots__/DataViewTable.test.tsx.snap +1042 -0
- package/src/DataViewTable/index.ts +2 -0
- package/src/DataViewTableBasic/DataViewTableBasic.test.tsx +65 -0
- package/src/DataViewTableBasic/DataViewTableBasic.tsx +82 -0
- package/src/DataViewTableBasic/__snapshots__/DataViewTableBasic.test.tsx.snap +555 -0
- package/src/DataViewTableBasic/index.ts +2 -0
- package/src/DataViewTableHead/DataViewTableHead.test.tsx +50 -0
- package/src/DataViewTableHead/DataViewTableHead.tsx +53 -0
- package/src/DataViewTableHead/__snapshots__/DataViewTableHead.test.tsx.snap +227 -0
- package/src/DataViewTableHead/index.ts +2 -0
- package/src/DataViewTableTree/DataViewTableTree.test.tsx +113 -0
- package/src/DataViewTableTree/DataViewTableTree.tsx +164 -0
- package/src/DataViewTableTree/__snapshots__/DataViewTableTree.test.tsx.snap +1200 -0
- package/src/DataViewTableTree/index.ts +2 -0
- package/src/DataViewToolbar/DataViewToolbar.tsx +9 -2
- package/src/DataViewToolbar/__snapshots__/DataViewToolbar.test.tsx.snap +8 -8
- package/src/Hooks/pagination.test.tsx +1 -1
- package/src/Hooks/pagination.ts +68 -12
- package/src/Hooks/selection.test.tsx +5 -5
- package/src/Hooks/selection.ts +6 -7
- package/src/InternalContext/InternalContext.test.tsx +89 -0
- package/src/InternalContext/InternalContext.tsx +51 -0
- package/src/InternalContext/index.ts +2 -0
- package/src/index.ts +18 -0
|
@@ -10,9 +10,11 @@ export interface DataViewToolbarProps extends PropsWithChildren {
|
|
|
10
10
|
bulkSelect?: React.ReactNode;
|
|
11
11
|
/** React component to display pagination */
|
|
12
12
|
pagination?: React.ReactNode;
|
|
13
|
+
/** React component to display actions */
|
|
14
|
+
actions?: React.ReactNode;
|
|
13
15
|
}
|
|
14
16
|
|
|
15
|
-
export const DataViewToolbar: React.FC<DataViewToolbarProps> = ({ className, ouiaId = 'DataViewToolbar', bulkSelect, pagination, children, ...props }: DataViewToolbarProps) => (
|
|
17
|
+
export const DataViewToolbar: React.FC<DataViewToolbarProps> = ({ className, ouiaId = 'DataViewToolbar', bulkSelect, actions, pagination, children, ...props }: DataViewToolbarProps) => (
|
|
16
18
|
<Toolbar ouiaId={ouiaId} className={className} {...props}>
|
|
17
19
|
<ToolbarContent>
|
|
18
20
|
{bulkSelect && (
|
|
@@ -20,6 +22,11 @@ export const DataViewToolbar: React.FC<DataViewToolbarProps> = ({ className, oui
|
|
|
20
22
|
{bulkSelect}
|
|
21
23
|
</ToolbarItem>
|
|
22
24
|
)}
|
|
25
|
+
{actions && (
|
|
26
|
+
<ToolbarItem>
|
|
27
|
+
{actions}
|
|
28
|
+
</ToolbarItem>
|
|
29
|
+
)}
|
|
23
30
|
{pagination && (
|
|
24
31
|
<ToolbarItem variant={ToolbarItemVariant.pagination} data-ouia-component-id={`${ouiaId}-pagination`}>
|
|
25
32
|
{pagination}
|
|
@@ -28,7 +35,7 @@ export const DataViewToolbar: React.FC<DataViewToolbarProps> = ({ className, oui
|
|
|
28
35
|
{children}
|
|
29
36
|
</ToolbarContent>
|
|
30
37
|
</Toolbar>
|
|
31
|
-
)
|
|
38
|
+
)
|
|
32
39
|
|
|
33
40
|
export default DataViewToolbar;
|
|
34
41
|
|
|
@@ -117,7 +117,7 @@ exports[`DataViewToolbar component should render correctly 1`] = `
|
|
|
117
117
|
type="button"
|
|
118
118
|
>
|
|
119
119
|
<span
|
|
120
|
-
class="pf-v6-c-button__icon
|
|
120
|
+
class="pf-v6-c-button__icon"
|
|
121
121
|
>
|
|
122
122
|
<svg
|
|
123
123
|
aria-hidden="true"
|
|
@@ -150,7 +150,7 @@ exports[`DataViewToolbar component should render correctly 1`] = `
|
|
|
150
150
|
type="button"
|
|
151
151
|
>
|
|
152
152
|
<span
|
|
153
|
-
class="pf-v6-c-button__icon
|
|
153
|
+
class="pf-v6-c-button__icon"
|
|
154
154
|
>
|
|
155
155
|
<svg
|
|
156
156
|
aria-hidden="true"
|
|
@@ -201,7 +201,7 @@ exports[`DataViewToolbar component should render correctly 1`] = `
|
|
|
201
201
|
type="button"
|
|
202
202
|
>
|
|
203
203
|
<span
|
|
204
|
-
class="pf-v6-c-button__icon
|
|
204
|
+
class="pf-v6-c-button__icon"
|
|
205
205
|
>
|
|
206
206
|
<svg
|
|
207
207
|
aria-hidden="true"
|
|
@@ -233,7 +233,7 @@ exports[`DataViewToolbar component should render correctly 1`] = `
|
|
|
233
233
|
type="button"
|
|
234
234
|
>
|
|
235
235
|
<span
|
|
236
|
-
class="pf-v6-c-button__icon
|
|
236
|
+
class="pf-v6-c-button__icon"
|
|
237
237
|
>
|
|
238
238
|
<svg
|
|
239
239
|
aria-hidden="true"
|
|
@@ -380,7 +380,7 @@ exports[`DataViewToolbar component should render correctly 1`] = `
|
|
|
380
380
|
type="button"
|
|
381
381
|
>
|
|
382
382
|
<span
|
|
383
|
-
class="pf-v6-c-button__icon
|
|
383
|
+
class="pf-v6-c-button__icon"
|
|
384
384
|
>
|
|
385
385
|
<svg
|
|
386
386
|
aria-hidden="true"
|
|
@@ -413,7 +413,7 @@ exports[`DataViewToolbar component should render correctly 1`] = `
|
|
|
413
413
|
type="button"
|
|
414
414
|
>
|
|
415
415
|
<span
|
|
416
|
-
class="pf-v6-c-button__icon
|
|
416
|
+
class="pf-v6-c-button__icon"
|
|
417
417
|
>
|
|
418
418
|
<svg
|
|
419
419
|
aria-hidden="true"
|
|
@@ -464,7 +464,7 @@ exports[`DataViewToolbar component should render correctly 1`] = `
|
|
|
464
464
|
type="button"
|
|
465
465
|
>
|
|
466
466
|
<span
|
|
467
|
-
class="pf-v6-c-button__icon
|
|
467
|
+
class="pf-v6-c-button__icon"
|
|
468
468
|
>
|
|
469
469
|
<svg
|
|
470
470
|
aria-hidden="true"
|
|
@@ -496,7 +496,7 @@ exports[`DataViewToolbar component should render correctly 1`] = `
|
|
|
496
496
|
type="button"
|
|
497
497
|
>
|
|
498
498
|
<span
|
|
499
|
-
class="pf-v6-c-button__icon
|
|
499
|
+
class="pf-v6-c-button__icon"
|
|
500
500
|
>
|
|
501
501
|
<svg
|
|
502
502
|
aria-hidden="true"
|
package/src/Hooks/pagination.ts
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
|
-
import { useState } from "react";
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
2
|
|
|
3
3
|
export interface UseDataViewPaginationProps {
|
|
4
4
|
/** Initial page */
|
|
5
5
|
page?: number;
|
|
6
6
|
/** Items per page */
|
|
7
7
|
perPage: number;
|
|
8
|
+
/** Current search parameters as a string */
|
|
9
|
+
searchParams?: URLSearchParams;
|
|
10
|
+
/** Function to set search parameters */
|
|
11
|
+
setSearchParams?: (params: URLSearchParams) => void;
|
|
12
|
+
/** Custom URL parameter name for page */
|
|
13
|
+
pageParam?: string;
|
|
14
|
+
/** Custom URL parameter name for per page */
|
|
15
|
+
perPageParam?: string;
|
|
8
16
|
}
|
|
9
17
|
|
|
10
18
|
export interface DataViewPaginationProps extends UseDataViewPaginationProps {
|
|
@@ -12,20 +20,68 @@ export interface DataViewPaginationProps extends UseDataViewPaginationProps {
|
|
|
12
20
|
page: number;
|
|
13
21
|
}
|
|
14
22
|
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
export enum PaginationParams {
|
|
24
|
+
PAGE = 'page',
|
|
25
|
+
PER_PAGE = 'perPage'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const useDataViewPagination = ({
|
|
29
|
+
page = 1,
|
|
30
|
+
perPage,
|
|
31
|
+
searchParams,
|
|
32
|
+
setSearchParams,
|
|
33
|
+
pageParam = PaginationParams.PAGE,
|
|
34
|
+
perPageParam = PaginationParams.PER_PAGE,
|
|
35
|
+
}: UseDataViewPaginationProps) => {
|
|
36
|
+
const [ state, setState ] = useState({
|
|
37
|
+
page: parseInt(searchParams?.get(pageParam) || `${page}`),
|
|
38
|
+
perPage: parseInt(searchParams?.get(perPageParam) || `${perPage}`),
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const updateSearchParams = (page: number, perPage: number) => {
|
|
42
|
+
if (searchParams && setSearchParams) {
|
|
43
|
+
const params = new URLSearchParams(searchParams);
|
|
44
|
+
params.set(pageParam, `${page}`);
|
|
45
|
+
params.set(perPageParam, `${perPage}`);
|
|
46
|
+
setSearchParams(params);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
// Make sure search params are loaded or set if not present on mount
|
|
52
|
+
updateSearchParams(state.page, state.perPage);
|
|
53
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
54
|
+
}, []);
|
|
55
|
+
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
// Listen on URL params changes
|
|
58
|
+
const currentPage = parseInt(searchParams?.get(pageParam) || `${state.page}`);
|
|
59
|
+
const currentPerPage = parseInt(searchParams?.get(perPageParam) || `${state.perPage}`);
|
|
60
|
+
if (currentPage !== state.page || currentPerPage !== state.perPage) {
|
|
61
|
+
setState({ page: currentPage, perPage: currentPerPage });
|
|
62
|
+
}
|
|
63
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
64
|
+
}, [ searchParams?.toString() ]);
|
|
65
|
+
|
|
66
|
+
const onPerPageSelect = (
|
|
67
|
+
_event: React.MouseEvent | React.KeyboardEvent | MouseEvent | undefined,
|
|
68
|
+
newPerPage: number
|
|
69
|
+
) => {
|
|
70
|
+
updateSearchParams(1, newPerPage);
|
|
71
|
+
setState({ perPage: newPerPage, page: 1 });
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const onSetPage = (
|
|
75
|
+
_event: React.MouseEvent | React.KeyboardEvent | MouseEvent | undefined,
|
|
76
|
+
newPage: number
|
|
77
|
+
) => {
|
|
78
|
+
updateSearchParams(newPage, state.perPage);
|
|
23
79
|
setState(prev => ({ ...prev, page: newPage }));
|
|
24
80
|
}
|
|
25
81
|
|
|
26
82
|
return {
|
|
27
83
|
...state,
|
|
28
84
|
onPerPageSelect,
|
|
29
|
-
onSetPage
|
|
30
|
-
}
|
|
31
|
-
}
|
|
85
|
+
onSetPage,
|
|
86
|
+
};
|
|
87
|
+
};
|
|
@@ -4,7 +4,7 @@ import { useDataViewSelection } from './selection';
|
|
|
4
4
|
|
|
5
5
|
describe('useDataViewSelection', () => {
|
|
6
6
|
it('should get initial state correctly - no initialSelected', () => {
|
|
7
|
-
const { result } = renderHook(() => useDataViewSelection({}))
|
|
7
|
+
const { result } = renderHook(() => useDataViewSelection({ matchOption: (a, b) => a.id === b.id }))
|
|
8
8
|
expect(result.current).toEqual({
|
|
9
9
|
selected: [],
|
|
10
10
|
onSelect: expect.any(Function),
|
|
@@ -14,7 +14,7 @@ describe('useDataViewSelection', () => {
|
|
|
14
14
|
|
|
15
15
|
it('should get initial state correctly - with initialSelected', () => {
|
|
16
16
|
const initialSelected = [ { id: 1, name: 'test1' } ];
|
|
17
|
-
const { result } = renderHook(() => useDataViewSelection({ initialSelected }))
|
|
17
|
+
const { result } = renderHook(() => useDataViewSelection({ initialSelected, matchOption: (a, b) => a.id === b.id }))
|
|
18
18
|
expect(result.current).toEqual({
|
|
19
19
|
selected: initialSelected,
|
|
20
20
|
onSelect: expect.any(Function),
|
|
@@ -24,7 +24,7 @@ describe('useDataViewSelection', () => {
|
|
|
24
24
|
|
|
25
25
|
it('should select items correctly - objects', async () => {
|
|
26
26
|
const initialSelected = [ { id: 1, name: 'test1' } ];
|
|
27
|
-
const { result } = renderHook(() => useDataViewSelection({ initialSelected }))
|
|
27
|
+
const { result } = renderHook(() => useDataViewSelection({ initialSelected, matchOption: (a, b) => a.id === b.id }))
|
|
28
28
|
|
|
29
29
|
await act(async () => {
|
|
30
30
|
result.current.onSelect(true, { id: 2, name: 'test2' });
|
|
@@ -34,7 +34,7 @@ describe('useDataViewSelection', () => {
|
|
|
34
34
|
|
|
35
35
|
it('should deselect items correctly - strings', async () => {
|
|
36
36
|
const initialSelected = [ 'test1', 'test2' ];
|
|
37
|
-
const { result } = renderHook(() => useDataViewSelection({ initialSelected }))
|
|
37
|
+
const { result } = renderHook(() => useDataViewSelection({ initialSelected, matchOption: (a, b) => a === b }))
|
|
38
38
|
|
|
39
39
|
await act(async () => {
|
|
40
40
|
result.current.onSelect(false, 'test2');
|
|
@@ -44,7 +44,7 @@ describe('useDataViewSelection', () => {
|
|
|
44
44
|
|
|
45
45
|
it('should check if item is selected correctly - objects', () => {
|
|
46
46
|
const initialSelected = [ { id: 1, name: 'test1' }, { id: 2, name: 'test2' } ];
|
|
47
|
-
const { result } = renderHook(() => useDataViewSelection({ initialSelected, matchOption: (a,b) => a.id === b.id }))
|
|
47
|
+
const { result } = renderHook(() => useDataViewSelection({ initialSelected, matchOption: (a, b) => a.id === b.id }))
|
|
48
48
|
|
|
49
49
|
expect(result.current.isSelected({ id: 1, name: 'test1' })).toBe(true);
|
|
50
50
|
expect(result.current.isSelected({ id: 3, name: 'test2' })).toBe(false);
|
package/src/Hooks/selection.ts
CHANGED
|
@@ -2,18 +2,17 @@
|
|
|
2
2
|
import { useState } from "react";
|
|
3
3
|
|
|
4
4
|
export interface UseDataViewSelectionProps {
|
|
5
|
+
/** Function to compare items when checking if item is selected */
|
|
6
|
+
matchOption: (item: any, another: any) => boolean;
|
|
5
7
|
/** Array of initially selected entries */
|
|
6
8
|
initialSelected?: (any)[];
|
|
7
|
-
/** Function to compare items when checking if entry is selected */
|
|
8
|
-
matchOption?: (item: any, another: any) => boolean;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export const useDataViewSelection = (
|
|
12
|
-
const [ selected, setSelected ] = useState<any[]>(
|
|
13
|
-
const matchOption = props.matchOption ? props.matchOption : (option, another) => (option === another);
|
|
11
|
+
export const useDataViewSelection = ({ matchOption, initialSelected = [] }: UseDataViewSelectionProps) => {
|
|
12
|
+
const [ selected, setSelected ] = useState<any[]>(initialSelected);
|
|
14
13
|
|
|
15
14
|
const onSelect = (isSelecting: boolean, items?: any[] | any) => {
|
|
16
|
-
isSelecting ?
|
|
15
|
+
isSelecting && items ?
|
|
17
16
|
setSelected(prev => {
|
|
18
17
|
const newSelectedItems = [ ...prev ];
|
|
19
18
|
(Array.isArray(items) ? items : [ items ]).forEach(newItem => !prev.some(prevItem => matchOption(prevItem, newItem)) && newSelectedItems.push(newItem));
|
|
@@ -22,7 +21,7 @@ export const useDataViewSelection = (props: UseDataViewSelectionProps) => {
|
|
|
22
21
|
: setSelected(items ? prev => prev.filter(prevSelected => !(Array.isArray(items) ? items : [ items ]).some(item => matchOption(item, prevSelected))) : []);
|
|
23
22
|
};
|
|
24
23
|
|
|
25
|
-
const isSelected = (item: any): boolean =>
|
|
24
|
+
const isSelected = (item: any): boolean => Boolean(selected.find(selected => matchOption(selected, item)));
|
|
26
25
|
|
|
27
26
|
return {
|
|
28
27
|
selected,
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, fireEvent } from '@testing-library/react';
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
4
|
+
import { useInternalContext, DataViewSelection } from './InternalContext';
|
|
5
|
+
import { DataView } from '../DataView';
|
|
6
|
+
|
|
7
|
+
describe('InternalContext', () => {
|
|
8
|
+
const mockSelection: DataViewSelection = {
|
|
9
|
+
onSelect: jest.fn(),
|
|
10
|
+
isSelected: jest.fn(),
|
|
11
|
+
isSelectDisabled: jest.fn(),
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
test('should provide context value and allow consuming it', () => {
|
|
15
|
+
const TestComponent = () => {
|
|
16
|
+
const { selection } = useInternalContext();
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<div>
|
|
20
|
+
<button onClick={() => selection?.onSelect(true, [ 'item1' ])}>Select item</button>
|
|
21
|
+
<span>{selection?.isSelected('item1') ? 'Selected' : 'Not selected'}</span>
|
|
22
|
+
</div>
|
|
23
|
+
);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const { getByText } = render(
|
|
27
|
+
<DataView selection={mockSelection}>
|
|
28
|
+
<TestComponent />
|
|
29
|
+
</DataView>
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
fireEvent.click(getByText('Select item'));
|
|
33
|
+
expect(mockSelection.onSelect).toHaveBeenCalledWith(true, [ 'item1' ]);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('should handle selection state correctly', () => {
|
|
37
|
+
const mockSelectionState = {
|
|
38
|
+
...mockSelection,
|
|
39
|
+
isSelected: jest.fn((item) => item === 'item1'),
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const TestComponent = () => {
|
|
43
|
+
const { selection } = useInternalContext();
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<div>
|
|
47
|
+
<span>{selection?.isSelected('item1') ? 'Item 1 is selected' : 'Item 1 is not selected'}</span>
|
|
48
|
+
<span>{selection?.isSelected('item2') ? 'Item 2 is selected' : 'Item 2 is not selected'}</span>
|
|
49
|
+
</div>
|
|
50
|
+
);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const { getByText } = render(
|
|
54
|
+
<DataView selection={mockSelectionState}>
|
|
55
|
+
<TestComponent />
|
|
56
|
+
</DataView>
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
expect(getByText('Item 1 is selected')).toBeInTheDocument();
|
|
60
|
+
expect(getByText('Item 2 is not selected')).toBeInTheDocument();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test('should handle selection disabled correctly', () => {
|
|
64
|
+
const mockSelectionWithDisabled = {
|
|
65
|
+
...mockSelection,
|
|
66
|
+
isSelectDisabled: jest.fn((item) => item === 'item3'),
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const TestComponent = () => {
|
|
70
|
+
const { selection } = useInternalContext();
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<div>
|
|
74
|
+
<span>{selection?.isSelectDisabled?.('item3') ? 'Item 3 is disabled' : 'Item 3 is enabled'}</span>
|
|
75
|
+
<span>{selection?.isSelectDisabled?.('item1') ? 'Item 1 is disabled' : 'Item 1 is enabled'}</span>
|
|
76
|
+
</div>
|
|
77
|
+
);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const { getByText } = render(
|
|
81
|
+
<DataView selection={mockSelectionWithDisabled}>
|
|
82
|
+
<TestComponent />
|
|
83
|
+
</DataView>
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
expect(getByText('Item 3 is disabled')).toBeInTheDocument();
|
|
87
|
+
expect(getByText('Item 1 is enabled')).toBeInTheDocument();
|
|
88
|
+
});
|
|
89
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React, { createContext, PropsWithChildren, useContext, useMemo } from 'react';
|
|
2
|
+
import { DataViewState } from '../DataView';
|
|
3
|
+
|
|
4
|
+
export interface DataViewSelection {
|
|
5
|
+
/** Called when the selection of items changes */
|
|
6
|
+
onSelect: (isSelecting: boolean, items?: any[] | any) => void; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
7
|
+
/** Checks if a specific item is currently selected */
|
|
8
|
+
isSelected: (item: any) => boolean; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
9
|
+
/** Determines if selection is disabled for a given item */
|
|
10
|
+
isSelectDisabled?: (item: any) => boolean; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface InternalContextProps {
|
|
14
|
+
/** Data selection props */
|
|
15
|
+
selection?: DataViewSelection;
|
|
16
|
+
/** Currently active state */
|
|
17
|
+
activeState?: DataViewState | string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface InternalContextValue extends InternalContextProps {
|
|
21
|
+
/** Flag indicating if data view is selectable (auto-calculated) */
|
|
22
|
+
isSelectable: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const InternalContext = createContext<InternalContextValue>({
|
|
26
|
+
selection: undefined,
|
|
27
|
+
activeState: undefined,
|
|
28
|
+
isSelectable: false,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export type InternalProviderProps = PropsWithChildren<InternalContextProps>
|
|
32
|
+
|
|
33
|
+
export const InternalContextProvider: React.FC<InternalProviderProps> = ({
|
|
34
|
+
children,
|
|
35
|
+
selection,
|
|
36
|
+
activeState
|
|
37
|
+
}) => {
|
|
38
|
+
const isSelectable = useMemo(() => Boolean(selection?.onSelect && selection?.isSelected), [ selection?.onSelect, selection?.isSelected ]);
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<InternalContext.Provider
|
|
42
|
+
value={{ selection, activeState, isSelectable }}
|
|
43
|
+
>
|
|
44
|
+
{children}
|
|
45
|
+
</InternalContext.Provider>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const useInternalContext = () => useContext(InternalContext);
|
|
50
|
+
|
|
51
|
+
export default InternalContext;
|
package/src/index.ts
CHANGED
|
@@ -1,8 +1,26 @@
|
|
|
1
1
|
// this file is autogenerated by generate-index.js, modifying it manually will have no effect
|
|
2
|
+
|
|
3
|
+
export { default as InternalContext } from './InternalContext';
|
|
4
|
+
export * from './InternalContext';
|
|
2
5
|
export * from './Hooks';
|
|
3
6
|
|
|
4
7
|
export { default as DataViewToolbar } from './DataViewToolbar';
|
|
5
8
|
export * from './DataViewToolbar';
|
|
6
9
|
|
|
10
|
+
export { default as DataViewTableTree } from './DataViewTableTree';
|
|
11
|
+
export * from './DataViewTableTree';
|
|
12
|
+
|
|
13
|
+
export { default as DataViewTableHead } from './DataViewTableHead';
|
|
14
|
+
export * from './DataViewTableHead';
|
|
15
|
+
|
|
16
|
+
export { default as DataViewTableBasic } from './DataViewTableBasic';
|
|
17
|
+
export * from './DataViewTableBasic';
|
|
18
|
+
|
|
19
|
+
export { default as DataViewTable } from './DataViewTable';
|
|
20
|
+
export * from './DataViewTable';
|
|
21
|
+
|
|
22
|
+
export { default as DataViewEventsContext } from './DataViewEventsContext';
|
|
23
|
+
export * from './DataViewEventsContext';
|
|
24
|
+
|
|
7
25
|
export { default as DataView } from './DataView';
|
|
8
26
|
export * from './DataView';
|