@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.
Files changed (151) hide show
  1. package/dist/cjs/DataView/DataView.d.ts +12 -0
  2. package/dist/cjs/DataView/DataView.js +14 -3
  3. package/dist/cjs/DataViewEventsContext/DataViewEventsContext.d.ts +16 -0
  4. package/dist/cjs/DataViewEventsContext/DataViewEventsContext.js +62 -0
  5. package/dist/cjs/DataViewEventsContext/DataViewEventsContext.test.d.ts +1 -0
  6. package/dist/cjs/DataViewEventsContext/DataViewEventsContext.test.js +72 -0
  7. package/dist/cjs/DataViewEventsContext/index.d.ts +2 -0
  8. package/dist/cjs/DataViewEventsContext/index.js +23 -0
  9. package/dist/cjs/DataViewTable/DataViewTable.d.ts +41 -0
  10. package/dist/cjs/DataViewTable/DataViewTable.js +18 -0
  11. package/dist/cjs/DataViewTable/DataViewTable.test.d.ts +1 -0
  12. package/dist/cjs/DataViewTable/DataViewTable.test.js +57 -0
  13. package/dist/cjs/DataViewTable/index.d.ts +2 -0
  14. package/dist/cjs/DataViewTable/index.js +23 -0
  15. package/dist/cjs/DataViewTableBasic/DataViewTableBasic.d.ts +18 -0
  16. package/dist/cjs/DataViewTableBasic/DataViewTableBasic.js +71 -0
  17. package/dist/cjs/DataViewTableBasic/DataViewTableBasic.test.d.ts +1 -0
  18. package/dist/cjs/DataViewTableBasic/DataViewTableBasic.test.js +43 -0
  19. package/dist/cjs/DataViewTableBasic/index.d.ts +2 -0
  20. package/dist/cjs/DataViewTableBasic/index.js +23 -0
  21. package/dist/cjs/DataViewTableHead/DataViewTableHead.d.ts +13 -0
  22. package/dist/cjs/DataViewTableHead/DataViewTableHead.js +57 -0
  23. package/dist/cjs/DataViewTableHead/DataViewTableHead.test.d.ts +1 -0
  24. package/dist/cjs/DataViewTableHead/DataViewTableHead.test.js +36 -0
  25. package/dist/cjs/DataViewTableHead/index.d.ts +2 -0
  26. package/dist/cjs/DataViewTableHead/index.js +23 -0
  27. package/dist/cjs/DataViewTableTree/DataViewTableTree.d.ts +24 -0
  28. package/dist/cjs/DataViewTableTree/DataViewTableTree.js +132 -0
  29. package/dist/cjs/DataViewTableTree/DataViewTableTree.test.d.ts +1 -0
  30. package/dist/cjs/DataViewTableTree/DataViewTableTree.test.js +90 -0
  31. package/dist/cjs/DataViewTableTree/index.d.ts +2 -0
  32. package/dist/cjs/DataViewTableTree/index.js +23 -0
  33. package/dist/cjs/DataViewToolbar/DataViewToolbar.d.ts +2 -0
  34. package/dist/cjs/DataViewToolbar/DataViewToolbar.js +2 -1
  35. package/dist/cjs/Hooks/pagination.d.ts +13 -1
  36. package/dist/cjs/Hooks/pagination.js +36 -4
  37. package/dist/cjs/Hooks/pagination.test.js +1 -1
  38. package/dist/cjs/Hooks/selection.d.ts +3 -3
  39. package/dist/cjs/Hooks/selection.js +4 -6
  40. package/dist/cjs/Hooks/selection.test.js +4 -4
  41. package/dist/cjs/InternalContext/InternalContext.d.ts +25 -0
  42. package/dist/cjs/InternalContext/InternalContext.js +40 -0
  43. package/dist/cjs/InternalContext/InternalContext.test.d.ts +1 -0
  44. package/dist/cjs/InternalContext/InternalContext.test.js +56 -0
  45. package/dist/cjs/InternalContext/index.d.ts +2 -0
  46. package/dist/cjs/InternalContext/index.js +23 -0
  47. package/dist/cjs/index.d.ts +12 -0
  48. package/dist/cjs/index.js +20 -2
  49. package/dist/dynamic/DataViewEventsContext/package.json +1 -0
  50. package/dist/dynamic/DataViewTable/package.json +1 -0
  51. package/dist/dynamic/DataViewTableBasic/package.json +1 -0
  52. package/dist/dynamic/DataViewTableHead/package.json +1 -0
  53. package/dist/dynamic/DataViewTableTree/package.json +1 -0
  54. package/dist/dynamic/InternalContext/package.json +1 -0
  55. package/dist/esm/DataView/DataView.d.ts +12 -0
  56. package/dist/esm/DataView/DataView.js +13 -2
  57. package/dist/esm/DataViewEventsContext/DataViewEventsContext.d.ts +16 -0
  58. package/dist/esm/DataViewEventsContext/DataViewEventsContext.js +34 -0
  59. package/dist/esm/DataViewEventsContext/DataViewEventsContext.test.d.ts +1 -0
  60. package/dist/esm/DataViewEventsContext/DataViewEventsContext.test.js +67 -0
  61. package/dist/esm/DataViewEventsContext/index.d.ts +2 -0
  62. package/dist/esm/DataViewEventsContext/index.js +2 -0
  63. package/dist/esm/DataViewTable/DataViewTable.d.ts +41 -0
  64. package/dist/esm/DataViewTable/DataViewTable.js +8 -0
  65. package/dist/esm/DataViewTable/DataViewTable.test.d.ts +1 -0
  66. package/dist/esm/DataViewTable/DataViewTable.test.js +52 -0
  67. package/dist/esm/DataViewTable/index.d.ts +2 -0
  68. package/dist/esm/DataViewTable/index.js +2 -0
  69. package/dist/esm/DataViewTableBasic/DataViewTableBasic.d.ts +18 -0
  70. package/dist/esm/DataViewTableBasic/DataViewTableBasic.js +44 -0
  71. package/dist/esm/DataViewTableBasic/DataViewTableBasic.test.d.ts +1 -0
  72. package/dist/esm/DataViewTableBasic/DataViewTableBasic.test.js +38 -0
  73. package/dist/esm/DataViewTableBasic/index.d.ts +2 -0
  74. package/dist/esm/DataViewTableBasic/index.js +2 -0
  75. package/dist/esm/DataViewTableHead/DataViewTableHead.d.ts +13 -0
  76. package/dist/esm/DataViewTableHead/DataViewTableHead.js +30 -0
  77. package/dist/esm/DataViewTableHead/DataViewTableHead.test.d.ts +1 -0
  78. package/dist/esm/DataViewTableHead/DataViewTableHead.test.js +31 -0
  79. package/dist/esm/DataViewTableHead/index.d.ts +2 -0
  80. package/dist/esm/DataViewTableHead/index.js +2 -0
  81. package/dist/esm/DataViewTableTree/DataViewTableTree.d.ts +24 -0
  82. package/dist/esm/DataViewTableTree/DataViewTableTree.js +105 -0
  83. package/dist/esm/DataViewTableTree/DataViewTableTree.test.d.ts +1 -0
  84. package/dist/esm/DataViewTableTree/DataViewTableTree.test.js +85 -0
  85. package/dist/esm/DataViewTableTree/index.d.ts +2 -0
  86. package/dist/esm/DataViewTableTree/index.js +2 -0
  87. package/dist/esm/DataViewToolbar/DataViewToolbar.d.ts +2 -0
  88. package/dist/esm/DataViewToolbar/DataViewToolbar.js +2 -1
  89. package/dist/esm/Hooks/pagination.d.ts +13 -1
  90. package/dist/esm/Hooks/pagination.js +36 -4
  91. package/dist/esm/Hooks/pagination.test.js +1 -1
  92. package/dist/esm/Hooks/selection.d.ts +3 -3
  93. package/dist/esm/Hooks/selection.js +4 -6
  94. package/dist/esm/Hooks/selection.test.js +4 -4
  95. package/dist/esm/InternalContext/InternalContext.d.ts +25 -0
  96. package/dist/esm/InternalContext/InternalContext.js +12 -0
  97. package/dist/esm/InternalContext/InternalContext.test.d.ts +1 -0
  98. package/dist/esm/InternalContext/InternalContext.test.js +51 -0
  99. package/dist/esm/InternalContext/index.d.ts +2 -0
  100. package/dist/esm/InternalContext/index.js +2 -0
  101. package/dist/esm/index.d.ts +12 -0
  102. package/dist/esm/index.js +12 -0
  103. package/dist/tsconfig.tsbuildinfo +1 -0
  104. package/package.json +9 -9
  105. package/patternfly-docs/content/extensions/data-view/examples/Components/Components.md +80 -5
  106. package/patternfly-docs/content/extensions/data-view/examples/Components/DataViewTableEmptyExample.tsx +57 -0
  107. package/patternfly-docs/content/extensions/data-view/examples/Components/DataViewTableErrorExample.tsx +45 -0
  108. package/patternfly-docs/content/extensions/data-view/examples/Components/DataViewTableExample.tsx +67 -0
  109. package/patternfly-docs/content/extensions/data-view/examples/Components/DataViewTableLoadingExample.tsx +27 -0
  110. package/patternfly-docs/content/extensions/data-view/examples/Components/DataViewTableTreeExample.tsx +71 -0
  111. package/patternfly-docs/content/extensions/data-view/examples/Components/DataViewToolbarActionsExample.tsx +27 -0
  112. package/patternfly-docs/content/extensions/data-view/examples/Components/DataViewToolbarExample.tsx +4 -4
  113. package/patternfly-docs/content/extensions/data-view/examples/EventsContext/EventsContext.md +32 -0
  114. package/patternfly-docs/content/extensions/data-view/examples/EventsContext/EventsExample.tsx +108 -0
  115. package/patternfly-docs/content/extensions/data-view/examples/Functionality/Functionality.md +14 -6
  116. package/patternfly-docs/content/extensions/data-view/examples/Functionality/PaginationExample.tsx +28 -37
  117. package/patternfly-docs/content/extensions/data-view/examples/Functionality/SelectionExample.tsx +15 -46
  118. package/patternfly-docs/content/extensions/data-view/examples/Layout/Layout.md +2 -1
  119. package/patternfly-docs/content/extensions/data-view/examples/Layout/PredefinedLayoutExample.tsx +20 -51
  120. package/patternfly-docs/pages/index.js +1 -1
  121. package/src/DataView/DataView.tsx +25 -3
  122. package/src/DataView/__snapshots__/DataView.test.tsx.snap +2 -2
  123. package/src/DataViewEventsContext/DataViewEventsContext.test.tsx +105 -0
  124. package/src/DataViewEventsContext/DataViewEventsContext.tsx +70 -0
  125. package/src/DataViewEventsContext/index.ts +2 -0
  126. package/src/DataViewTable/DataViewTable.test.tsx +80 -0
  127. package/src/DataViewTable/DataViewTable.tsx +37 -0
  128. package/src/DataViewTable/__snapshots__/DataViewTable.test.tsx.snap +1042 -0
  129. package/src/DataViewTable/index.ts +2 -0
  130. package/src/DataViewTableBasic/DataViewTableBasic.test.tsx +65 -0
  131. package/src/DataViewTableBasic/DataViewTableBasic.tsx +82 -0
  132. package/src/DataViewTableBasic/__snapshots__/DataViewTableBasic.test.tsx.snap +555 -0
  133. package/src/DataViewTableBasic/index.ts +2 -0
  134. package/src/DataViewTableHead/DataViewTableHead.test.tsx +50 -0
  135. package/src/DataViewTableHead/DataViewTableHead.tsx +53 -0
  136. package/src/DataViewTableHead/__snapshots__/DataViewTableHead.test.tsx.snap +227 -0
  137. package/src/DataViewTableHead/index.ts +2 -0
  138. package/src/DataViewTableTree/DataViewTableTree.test.tsx +113 -0
  139. package/src/DataViewTableTree/DataViewTableTree.tsx +164 -0
  140. package/src/DataViewTableTree/__snapshots__/DataViewTableTree.test.tsx.snap +1200 -0
  141. package/src/DataViewTableTree/index.ts +2 -0
  142. package/src/DataViewToolbar/DataViewToolbar.tsx +9 -2
  143. package/src/DataViewToolbar/__snapshots__/DataViewToolbar.test.tsx.snap +8 -8
  144. package/src/Hooks/pagination.test.tsx +1 -1
  145. package/src/Hooks/pagination.ts +68 -12
  146. package/src/Hooks/selection.test.tsx +5 -5
  147. package/src/Hooks/selection.ts +6 -7
  148. package/src/InternalContext/InternalContext.test.tsx +89 -0
  149. package/src/InternalContext/InternalContext.tsx +51 -0
  150. package/src/InternalContext/index.ts +2 -0
  151. package/src/index.ts +18 -0
@@ -0,0 +1,2 @@
1
+ export { default } from './DataViewTableTree';
2
+ export * from './DataViewTableTree';
@@ -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 pf-m-start"
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 pf-m-start"
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 pf-m-start"
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 pf-m-start"
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 pf-m-start"
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 pf-m-start"
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 pf-m-start"
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 pf-m-start"
499
+ class="pf-v6-c-button__icon"
500
500
  >
501
501
  <svg
502
502
  aria-hidden="true"
@@ -49,7 +49,7 @@ describe('useDataViewPagination', () => {
49
49
  expect(result.current).toEqual({
50
50
  onPerPageSelect: expect.any(Function),
51
51
  onSetPage: expect.any(Function),
52
- page: 3,
52
+ page: 1,
53
53
  perPage: 50
54
54
  })
55
55
  });
@@ -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 const useDataViewPagination = ({ page = 1, perPage }: UseDataViewPaginationProps) => {
16
- const [ state, setState ] = useState({ page, perPage });
17
-
18
- const onPerPageSelect = (_event: React.MouseEvent | React.KeyboardEvent | MouseEvent | undefined, newPerPage: number) => {
19
- setState(prev => ({ ...prev, perPage: newPerPage }));
20
- }
21
-
22
- const onSetPage = (_event: React.MouseEvent | React.KeyboardEvent | MouseEvent | undefined, newPage: number) => {
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);
@@ -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 = (props: UseDataViewSelectionProps) => {
12
- const [ selected, setSelected ] = useState<any[]>(props.initialSelected ?? []);
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 => props?.matchOption ? Boolean(selected.find(selected => matchOption(selected, item))) : selected.includes(item);
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;
@@ -0,0 +1,2 @@
1
+ export { default } from './InternalContext';
2
+ export * from './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';