@patternfly/react-data-view 6.0.0-prerelease.1 → 6.1.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.
Files changed (237) hide show
  1. package/dist/cjs/DataView/DataView.d.ts +15 -1
  2. package/dist/cjs/DataView/DataView.js +14 -3
  3. package/dist/cjs/DataViewCheckboxFilter/DataViewCheckboxFilter.d.ts +29 -0
  4. package/dist/cjs/DataViewCheckboxFilter/DataViewCheckboxFilter.js +70 -0
  5. package/dist/cjs/DataViewCheckboxFilter/DataViewCheckboxFilter.test.d.ts +1 -0
  6. package/dist/cjs/DataViewCheckboxFilter/DataViewCheckboxFilter.test.js +25 -0
  7. package/dist/cjs/DataViewCheckboxFilter/index.d.ts +2 -0
  8. package/dist/cjs/DataViewCheckboxFilter/index.js +23 -0
  9. package/dist/cjs/DataViewEventsContext/DataViewEventsContext.d.ts +16 -0
  10. package/dist/cjs/DataViewEventsContext/DataViewEventsContext.js +62 -0
  11. package/dist/cjs/DataViewEventsContext/DataViewEventsContext.test.d.ts +1 -0
  12. package/dist/cjs/DataViewEventsContext/DataViewEventsContext.test.js +72 -0
  13. package/dist/cjs/DataViewEventsContext/index.d.ts +2 -0
  14. package/dist/cjs/DataViewEventsContext/index.js +23 -0
  15. package/dist/cjs/DataViewFilters/DataViewFilters.d.ts +25 -0
  16. package/dist/cjs/DataViewFilters/DataViewFilters.js +85 -0
  17. package/dist/cjs/DataViewFilters/DataViewFilters.test.d.ts +1 -0
  18. package/dist/cjs/DataViewFilters/DataViewFilters.test.js +19 -0
  19. package/dist/cjs/DataViewFilters/index.d.ts +2 -0
  20. package/dist/cjs/DataViewFilters/index.js +23 -0
  21. package/dist/cjs/DataViewTable/DataViewTable.d.ts +49 -0
  22. package/dist/cjs/DataViewTable/DataViewTable.js +18 -0
  23. package/dist/cjs/DataViewTable/DataViewTable.test.d.ts +1 -0
  24. package/dist/cjs/DataViewTable/DataViewTable.test.js +57 -0
  25. package/dist/cjs/DataViewTable/index.d.ts +2 -0
  26. package/dist/cjs/DataViewTable/index.js +23 -0
  27. package/dist/cjs/DataViewTableBasic/DataViewTableBasic.d.ts +19 -0
  28. package/dist/cjs/DataViewTableBasic/DataViewTableBasic.js +71 -0
  29. package/dist/cjs/DataViewTableBasic/DataViewTableBasic.test.d.ts +1 -0
  30. package/dist/cjs/DataViewTableBasic/DataViewTableBasic.test.js +43 -0
  31. package/dist/cjs/DataViewTableBasic/index.d.ts +2 -0
  32. package/dist/cjs/DataViewTableBasic/index.js +23 -0
  33. package/dist/cjs/DataViewTableHead/DataViewTableHead.d.ts +14 -0
  34. package/dist/cjs/DataViewTableHead/DataViewTableHead.js +57 -0
  35. package/dist/cjs/DataViewTableHead/DataViewTableHead.test.d.ts +1 -0
  36. package/dist/cjs/DataViewTableHead/DataViewTableHead.test.js +36 -0
  37. package/dist/cjs/DataViewTableHead/index.d.ts +2 -0
  38. package/dist/cjs/DataViewTableHead/index.js +23 -0
  39. package/dist/cjs/DataViewTableTree/DataViewTableTree.d.ts +25 -0
  40. package/dist/cjs/DataViewTableTree/DataViewTableTree.js +144 -0
  41. package/dist/cjs/DataViewTableTree/DataViewTableTree.test.d.ts +1 -0
  42. package/dist/cjs/DataViewTableTree/DataViewTableTree.test.js +90 -0
  43. package/dist/cjs/DataViewTableTree/index.d.ts +2 -0
  44. package/dist/cjs/DataViewTableTree/index.js +23 -0
  45. package/dist/cjs/DataViewTextFilter/DataViewTextFilter.d.ts +21 -0
  46. package/dist/cjs/DataViewTextFilter/DataViewTextFilter.js +26 -0
  47. package/dist/cjs/DataViewTextFilter/DataViewTextFilter.test.d.ts +1 -0
  48. package/dist/cjs/DataViewTextFilter/DataViewTextFilter.test.js +22 -0
  49. package/dist/cjs/DataViewTextFilter/index.d.ts +2 -0
  50. package/dist/cjs/DataViewTextFilter/index.js +23 -0
  51. package/dist/cjs/DataViewToolbar/DataViewToolbar.d.ts +11 -3
  52. package/dist/cjs/DataViewToolbar/DataViewToolbar.js +30 -6
  53. package/dist/cjs/Hooks/filters.d.ts +14 -0
  54. package/dist/cjs/Hooks/filters.js +69 -0
  55. package/dist/cjs/Hooks/filters.test.d.ts +1 -0
  56. package/dist/cjs/Hooks/filters.test.js +50 -0
  57. package/dist/cjs/Hooks/index.d.ts +2 -0
  58. package/dist/cjs/Hooks/index.js +2 -0
  59. package/dist/cjs/Hooks/pagination.d.ts +14 -1
  60. package/dist/cjs/Hooks/pagination.js +36 -4
  61. package/dist/cjs/Hooks/pagination.test.js +1 -1
  62. package/dist/cjs/Hooks/selection.d.ts +3 -3
  63. package/dist/cjs/Hooks/selection.js +4 -4
  64. package/dist/cjs/Hooks/selection.test.js +4 -4
  65. package/dist/cjs/Hooks/sort.d.ts +32 -0
  66. package/dist/cjs/Hooks/sort.js +47 -0
  67. package/dist/cjs/Hooks/sort.test.d.ts +1 -0
  68. package/dist/cjs/Hooks/sort.test.js +68 -0
  69. package/dist/cjs/InternalContext/InternalContext.d.ts +26 -0
  70. package/dist/cjs/InternalContext/InternalContext.js +40 -0
  71. package/dist/cjs/InternalContext/InternalContext.test.d.ts +1 -0
  72. package/dist/cjs/InternalContext/InternalContext.test.js +56 -0
  73. package/dist/cjs/InternalContext/index.d.ts +2 -0
  74. package/dist/cjs/InternalContext/index.js +23 -0
  75. package/dist/cjs/index.d.ts +16 -0
  76. package/dist/cjs/index.js +26 -2
  77. package/dist/dynamic/DataViewCheckboxFilter/package.json +1 -0
  78. package/dist/dynamic/DataViewEventsContext/package.json +1 -0
  79. package/dist/dynamic/DataViewFilters/package.json +1 -0
  80. package/dist/dynamic/DataViewTable/package.json +1 -0
  81. package/dist/dynamic/DataViewTableBasic/package.json +1 -0
  82. package/dist/dynamic/DataViewTableHead/package.json +1 -0
  83. package/dist/dynamic/DataViewTableTree/package.json +1 -0
  84. package/dist/dynamic/DataViewTextFilter/package.json +1 -0
  85. package/dist/dynamic/InternalContext/package.json +1 -0
  86. package/dist/esm/DataView/DataView.d.ts +15 -1
  87. package/dist/esm/DataView/DataView.js +13 -2
  88. package/dist/esm/DataViewCheckboxFilter/DataViewCheckboxFilter.d.ts +29 -0
  89. package/dist/esm/DataViewCheckboxFilter/DataViewCheckboxFilter.js +62 -0
  90. package/dist/esm/DataViewCheckboxFilter/DataViewCheckboxFilter.test.d.ts +1 -0
  91. package/dist/esm/DataViewCheckboxFilter/DataViewCheckboxFilter.test.js +20 -0
  92. package/dist/esm/DataViewCheckboxFilter/index.d.ts +2 -0
  93. package/dist/esm/DataViewCheckboxFilter/index.js +2 -0
  94. package/dist/esm/DataViewEventsContext/DataViewEventsContext.d.ts +16 -0
  95. package/dist/esm/DataViewEventsContext/DataViewEventsContext.js +34 -0
  96. package/dist/esm/DataViewEventsContext/DataViewEventsContext.test.d.ts +1 -0
  97. package/dist/esm/DataViewEventsContext/DataViewEventsContext.test.js +67 -0
  98. package/dist/esm/DataViewEventsContext/index.d.ts +2 -0
  99. package/dist/esm/DataViewEventsContext/index.js +2 -0
  100. package/dist/esm/DataViewFilters/DataViewFilters.d.ts +25 -0
  101. package/dist/esm/DataViewFilters/DataViewFilters.js +58 -0
  102. package/dist/esm/DataViewFilters/DataViewFilters.test.d.ts +1 -0
  103. package/dist/esm/DataViewFilters/DataViewFilters.test.js +14 -0
  104. package/dist/esm/DataViewFilters/index.d.ts +2 -0
  105. package/dist/esm/DataViewFilters/index.js +2 -0
  106. package/dist/esm/DataViewTable/DataViewTable.d.ts +49 -0
  107. package/dist/esm/DataViewTable/DataViewTable.js +8 -0
  108. package/dist/esm/DataViewTable/DataViewTable.test.d.ts +1 -0
  109. package/dist/esm/DataViewTable/DataViewTable.test.js +52 -0
  110. package/dist/esm/DataViewTable/index.d.ts +2 -0
  111. package/dist/esm/DataViewTable/index.js +2 -0
  112. package/dist/esm/DataViewTableBasic/DataViewTableBasic.d.ts +19 -0
  113. package/dist/esm/DataViewTableBasic/DataViewTableBasic.js +44 -0
  114. package/dist/esm/DataViewTableBasic/DataViewTableBasic.test.d.ts +1 -0
  115. package/dist/esm/DataViewTableBasic/DataViewTableBasic.test.js +38 -0
  116. package/dist/esm/DataViewTableBasic/index.d.ts +2 -0
  117. package/dist/esm/DataViewTableBasic/index.js +2 -0
  118. package/dist/esm/DataViewTableHead/DataViewTableHead.d.ts +14 -0
  119. package/dist/esm/DataViewTableHead/DataViewTableHead.js +30 -0
  120. package/dist/esm/DataViewTableHead/DataViewTableHead.test.d.ts +1 -0
  121. package/dist/esm/DataViewTableHead/DataViewTableHead.test.js +31 -0
  122. package/dist/esm/DataViewTableHead/index.d.ts +2 -0
  123. package/dist/esm/DataViewTableHead/index.js +2 -0
  124. package/dist/esm/DataViewTableTree/DataViewTableTree.d.ts +25 -0
  125. package/dist/esm/DataViewTableTree/DataViewTableTree.js +117 -0
  126. package/dist/esm/DataViewTableTree/DataViewTableTree.test.d.ts +1 -0
  127. package/dist/esm/DataViewTableTree/DataViewTableTree.test.js +85 -0
  128. package/dist/esm/DataViewTableTree/index.d.ts +2 -0
  129. package/dist/esm/DataViewTableTree/index.js +2 -0
  130. package/dist/esm/DataViewTextFilter/DataViewTextFilter.d.ts +21 -0
  131. package/dist/esm/DataViewTextFilter/DataViewTextFilter.js +19 -0
  132. package/dist/esm/DataViewTextFilter/DataViewTextFilter.test.d.ts +1 -0
  133. package/dist/esm/DataViewTextFilter/DataViewTextFilter.test.js +17 -0
  134. package/dist/esm/DataViewTextFilter/index.d.ts +2 -0
  135. package/dist/esm/DataViewTextFilter/index.js +2 -0
  136. package/dist/esm/DataViewToolbar/DataViewToolbar.d.ts +11 -3
  137. package/dist/esm/DataViewToolbar/DataViewToolbar.js +8 -4
  138. package/dist/esm/Hooks/filters.d.ts +14 -0
  139. package/dist/esm/Hooks/filters.js +65 -0
  140. package/dist/esm/Hooks/filters.test.d.ts +1 -0
  141. package/dist/esm/Hooks/filters.test.js +48 -0
  142. package/dist/esm/Hooks/index.d.ts +2 -0
  143. package/dist/esm/Hooks/index.js +2 -0
  144. package/dist/esm/Hooks/pagination.d.ts +14 -1
  145. package/dist/esm/Hooks/pagination.js +36 -4
  146. package/dist/esm/Hooks/pagination.test.js +1 -1
  147. package/dist/esm/Hooks/selection.d.ts +3 -3
  148. package/dist/esm/Hooks/selection.js +4 -4
  149. package/dist/esm/Hooks/selection.test.js +4 -4
  150. package/dist/esm/Hooks/sort.d.ts +32 -0
  151. package/dist/esm/Hooks/sort.js +43 -0
  152. package/dist/esm/Hooks/sort.test.d.ts +1 -0
  153. package/dist/esm/Hooks/sort.test.js +66 -0
  154. package/dist/esm/InternalContext/InternalContext.d.ts +26 -0
  155. package/dist/esm/InternalContext/InternalContext.js +12 -0
  156. package/dist/esm/InternalContext/InternalContext.test.d.ts +1 -0
  157. package/dist/esm/InternalContext/InternalContext.test.js +51 -0
  158. package/dist/esm/InternalContext/index.d.ts +2 -0
  159. package/dist/esm/InternalContext/index.js +2 -0
  160. package/dist/esm/index.d.ts +16 -0
  161. package/dist/esm/index.js +16 -0
  162. package/dist/tsconfig.tsbuildinfo +1 -0
  163. package/package.json +16 -15
  164. package/patternfly-docs/content/extensions/data-view/examples/DataView/DataView.md +63 -0
  165. package/patternfly-docs/content/extensions/data-view/examples/DataView/EventsExample.tsx +130 -0
  166. package/patternfly-docs/content/extensions/data-view/examples/DataView/PredefinedLayoutFullExample.tsx +275 -0
  167. package/patternfly-docs/content/extensions/data-view/examples/Table/DataViewTableEmptyExample.tsx +57 -0
  168. package/patternfly-docs/content/extensions/data-view/examples/Table/DataViewTableErrorExample.tsx +45 -0
  169. package/patternfly-docs/content/extensions/data-view/examples/Table/DataViewTableExample.tsx +67 -0
  170. package/patternfly-docs/content/extensions/data-view/examples/Table/DataViewTableLoadingExample.tsx +27 -0
  171. package/patternfly-docs/content/extensions/data-view/examples/Table/DataViewTableTreeExample.tsx +71 -0
  172. package/patternfly-docs/content/extensions/data-view/examples/Table/SortingExample.tsx +87 -0
  173. package/patternfly-docs/content/extensions/data-view/examples/Table/Table.md +130 -0
  174. package/patternfly-docs/content/extensions/data-view/examples/Toolbar/DataViewToolbarActionsExample.tsx +27 -0
  175. package/patternfly-docs/content/extensions/data-view/examples/Toolbar/DataViewToolbarExample.tsx +36 -0
  176. package/patternfly-docs/content/extensions/data-view/examples/Toolbar/FiltersExample.tsx +107 -0
  177. package/patternfly-docs/content/extensions/data-view/examples/Toolbar/PaginationExample.tsx +56 -0
  178. package/patternfly-docs/content/extensions/data-view/examples/Toolbar/SelectionExample.tsx +57 -0
  179. package/patternfly-docs/content/extensions/data-view/examples/Toolbar/Toolbar.md +142 -0
  180. package/patternfly-docs/pages/index.js +1 -1
  181. package/src/DataView/DataView.tsx +28 -5
  182. package/src/DataView/__snapshots__/DataView.test.tsx.snap +2 -2
  183. package/src/DataViewCheckboxFilter/DataViewCheckboxFilter.test.tsx +24 -0
  184. package/src/DataViewCheckboxFilter/DataViewCheckboxFilter.tsx +175 -0
  185. package/src/DataViewCheckboxFilter/__snapshots__/DataViewCheckboxFilter.test.tsx.snap +197 -0
  186. package/src/DataViewCheckboxFilter/index.ts +2 -0
  187. package/src/DataViewEventsContext/DataViewEventsContext.test.tsx +105 -0
  188. package/src/DataViewEventsContext/DataViewEventsContext.tsx +70 -0
  189. package/src/DataViewEventsContext/index.ts +2 -0
  190. package/src/DataViewFilters/DataViewFilters.test.tsx +21 -0
  191. package/src/DataViewFilters/DataViewFilters.tsx +144 -0
  192. package/src/DataViewFilters/__snapshots__/DataViewFilters.test.tsx.snap +194 -0
  193. package/src/DataViewFilters/index.tsx +2 -0
  194. package/src/DataViewTable/DataViewTable.test.tsx +80 -0
  195. package/src/DataViewTable/DataViewTable.tsx +57 -0
  196. package/src/DataViewTable/__snapshots__/DataViewTable.test.tsx.snap +1042 -0
  197. package/src/DataViewTable/index.ts +2 -0
  198. package/src/DataViewTableBasic/DataViewTableBasic.test.tsx +65 -0
  199. package/src/DataViewTableBasic/DataViewTableBasic.tsx +83 -0
  200. package/src/DataViewTableBasic/__snapshots__/DataViewTableBasic.test.tsx.snap +555 -0
  201. package/src/DataViewTableBasic/index.ts +2 -0
  202. package/src/DataViewTableHead/DataViewTableHead.test.tsx +50 -0
  203. package/src/DataViewTableHead/DataViewTableHead.tsx +54 -0
  204. package/src/DataViewTableHead/__snapshots__/DataViewTableHead.test.tsx.snap +227 -0
  205. package/src/DataViewTableHead/index.ts +2 -0
  206. package/src/DataViewTableTree/DataViewTableTree.test.tsx +113 -0
  207. package/src/DataViewTableTree/DataViewTableTree.tsx +186 -0
  208. package/src/DataViewTableTree/__snapshots__/DataViewTableTree.test.tsx.snap +1200 -0
  209. package/src/DataViewTableTree/index.ts +2 -0
  210. package/src/DataViewTextFilter/DataViewTextFilter.test.tsx +24 -0
  211. package/src/DataViewTextFilter/DataViewTextFilter.tsx +54 -0
  212. package/src/DataViewTextFilter/__snapshots__/DataViewTextFilter.test.tsx.snap +203 -0
  213. package/src/DataViewTextFilter/index.ts +2 -0
  214. package/src/DataViewToolbar/DataViewToolbar.tsx +48 -22
  215. package/src/DataViewToolbar/__snapshots__/DataViewToolbar.test.tsx.snap +264 -174
  216. package/src/Hooks/filters.test.tsx +62 -0
  217. package/src/Hooks/filters.ts +97 -0
  218. package/src/Hooks/index.ts +2 -0
  219. package/src/Hooks/pagination.test.tsx +1 -1
  220. package/src/Hooks/pagination.ts +69 -12
  221. package/src/Hooks/selection.test.tsx +5 -5
  222. package/src/Hooks/selection.ts +7 -7
  223. package/src/Hooks/sort.test.tsx +84 -0
  224. package/src/Hooks/sort.ts +87 -0
  225. package/src/InternalContext/InternalContext.test.tsx +89 -0
  226. package/src/InternalContext/InternalContext.tsx +52 -0
  227. package/src/InternalContext/index.ts +2 -0
  228. package/src/index.ts +24 -0
  229. package/patternfly-docs/content/extensions/data-view/about-data-view.md +0 -14
  230. package/patternfly-docs/content/extensions/data-view/examples/Components/Components.md +0 -31
  231. package/patternfly-docs/content/extensions/data-view/examples/Components/DataViewToolbarExample.tsx +0 -20
  232. package/patternfly-docs/content/extensions/data-view/examples/Functionality/Functionality.md +0 -77
  233. package/patternfly-docs/content/extensions/data-view/examples/Functionality/PaginationExample.tsx +0 -65
  234. package/patternfly-docs/content/extensions/data-view/examples/Functionality/SelectionExample.tsx +0 -88
  235. package/patternfly-docs/content/extensions/data-view/examples/Layout/Layout.md +0 -39
  236. package/patternfly-docs/content/extensions/data-view/examples/Layout/PredefinedLayoutExample.tsx +0 -120
  237. /package/patternfly-docs/content/extensions/data-view/examples/{Layout → DataView}/AbstractLayoutExample.tsx +0 -0
@@ -0,0 +1,24 @@
1
+ import React from 'react';
2
+ import { render } from '@testing-library/react';
3
+ import DataViewCheckboxFilter, { DataViewCheckboxFilterProps } from './DataViewCheckboxFilter';
4
+ import DataViewToolbar from '../DataViewToolbar';
5
+
6
+ describe('DataViewCheckboxFilter component', () => {
7
+ const defaultProps: DataViewCheckboxFilterProps = {
8
+ filterId: 'test-checkbox-filter',
9
+ title: 'Test Checkbox Filter',
10
+ value: [ 'workspace-one' ],
11
+ options: [
12
+ { label: 'Workspace one', value: 'workspace-one' },
13
+ { label: 'Workspace two', value: 'workspace-two' },
14
+ { label: 'Workspace three', value: 'workspace-three' },
15
+ ],
16
+ };
17
+
18
+ it('should render correctly', () => {
19
+ const { container } = render(
20
+ <DataViewToolbar filters={<DataViewCheckboxFilter {...defaultProps} />} />
21
+ );
22
+ expect(container).toMatchSnapshot();
23
+ });
24
+ });
@@ -0,0 +1,175 @@
1
+ import React from 'react';
2
+ import {
3
+ Badge,
4
+ Menu,
5
+ MenuContent,
6
+ MenuItem,
7
+ MenuList,
8
+ MenuProps,
9
+ MenuToggle,
10
+ Popper,
11
+ ToolbarLabel,
12
+ ToolbarFilter,
13
+ } from '@patternfly/react-core';
14
+ import { FilterIcon } from '@patternfly/react-icons';
15
+ import { DataViewFilterOption } from '../DataViewFilters';
16
+
17
+ const isToolbarLabel = (label: string | ToolbarLabel): label is ToolbarLabel =>
18
+ typeof label === 'object' && 'key' in label;
19
+
20
+ export const isDataViewFilterOption = (obj: unknown): obj is DataViewFilterOption =>
21
+ !!obj &&
22
+ typeof obj === 'object' &&
23
+ 'label' in obj &&
24
+ 'value' in obj &&
25
+ typeof (obj as DataViewFilterOption).value === 'string';
26
+
27
+ /** extends MenuProps */
28
+ export interface DataViewCheckboxFilterProps extends Omit<MenuProps, 'onSelect' | 'onChange'> {
29
+ /** Unique key for the filter attribute */
30
+ filterId: string;
31
+ /** Array of current filter values */
32
+ value?: string[];
33
+ /** Filter title displayed in the toolbar */
34
+ title: string;
35
+ /** Placeholder text of the menu */
36
+ placeholder?: string;
37
+ /** Filter options displayed */
38
+ options: (DataViewFilterOption | string)[];
39
+ /** Callback for updating when item selection changes. */
40
+ onChange?: (event?: React.MouseEvent, values?: string[]) => void;
41
+ /** Controls visibility of the filter in the toolbar */
42
+ showToolbarItem?: boolean;
43
+ /** Controls visibility of the filter icon */
44
+ showIcon?: boolean;
45
+ /** Controls visibility of the selected items badge */
46
+ showBadge?: boolean;
47
+ /** Custom OUIA ID */
48
+ ouiaId?: string;
49
+ }
50
+
51
+ export const DataViewCheckboxFilter: React.FC<DataViewCheckboxFilterProps> = ({
52
+ filterId,
53
+ title,
54
+ value = [],
55
+ onChange,
56
+ placeholder,
57
+ options = [],
58
+ showToolbarItem,
59
+ showIcon = !placeholder,
60
+ showBadge = !placeholder,
61
+ ouiaId = 'DataViewCheckboxFilter',
62
+ ...props
63
+ }: DataViewCheckboxFilterProps) => {
64
+ const [ isOpen, setIsOpen ] = React.useState(false);
65
+ const toggleRef = React.useRef<HTMLButtonElement>(null);
66
+ const menuRef = React.useRef<HTMLDivElement>(null);
67
+ const containerRef = React.useRef<HTMLDivElement>(null);
68
+
69
+ const normalizeOptions = React.useMemo(
70
+ () =>
71
+ options.map(option =>
72
+ typeof option === 'string'
73
+ ? { label: option, value: option }
74
+ : option
75
+ ),
76
+ [ options ]
77
+ );
78
+
79
+ const handleToggleClick = (event: React.MouseEvent) => {
80
+ event.stopPropagation();
81
+ setTimeout(() => {
82
+ const firstElement = menuRef.current?.querySelector('li > button:not(:disabled)') as HTMLElement;
83
+ firstElement?.focus();
84
+ }, 0);
85
+ setIsOpen(prev => !prev);
86
+ };
87
+
88
+ const handleSelect = (event?: React.MouseEvent, itemId?: string | number) => {
89
+ const activeItem = String(itemId);
90
+ const isSelected = value.includes(activeItem);
91
+
92
+ onChange?.(
93
+ event,
94
+ isSelected ? value.filter(item => item !== activeItem) : [ activeItem, ...value ]
95
+ );
96
+ };
97
+
98
+ const handleClickOutside = (event: MouseEvent) =>
99
+ isOpen &&
100
+ menuRef.current && toggleRef.current &&
101
+ !menuRef.current.contains(event.target as Node) && !toggleRef.current.contains(event.target as Node)
102
+ && setIsOpen(false);
103
+
104
+
105
+ React.useEffect(() => {
106
+ window.addEventListener('click', handleClickOutside);
107
+ return () => {
108
+ window.removeEventListener('click', handleClickOutside);
109
+ };
110
+ }, [ isOpen ]); // eslint-disable-line react-hooks/exhaustive-deps
111
+
112
+ return (
113
+ <ToolbarFilter
114
+ key={ouiaId}
115
+ data-ouia-component-id={ouiaId}
116
+ labels={value.map(item => {
117
+ const activeOption = normalizeOptions.find(option => option.value === item);
118
+ return ({ key: activeOption?.value as string, node: activeOption?.label })
119
+ })}
120
+ deleteLabel={(_, label) =>
121
+ onChange?.(undefined, value.filter(item => item !== (isToolbarLabel(label) ? label.key : label)))
122
+ }
123
+ categoryName={title}
124
+ showToolbarItem={showToolbarItem}
125
+ >
126
+ <Popper
127
+ trigger={
128
+ <MenuToggle
129
+ ouiaId={`${ouiaId}-toggle`}
130
+ ref={toggleRef}
131
+ onClick={handleToggleClick}
132
+ isExpanded={isOpen}
133
+ icon={showIcon ? <FilterIcon /> : undefined}
134
+ badge={value.length > 0 && showBadge ? <Badge data-ouia-component-id={`${ouiaId}-badge`} isRead>{value.length}</Badge> : undefined}
135
+ style={{ width: '200px' }}
136
+ >
137
+ {placeholder ?? title}
138
+ </MenuToggle>
139
+ }
140
+ triggerRef={toggleRef}
141
+ popper={
142
+ <Menu
143
+ ref={menuRef}
144
+ ouiaId={`${ouiaId}-menu`}
145
+ onSelect={handleSelect}
146
+ selected={value}
147
+ {...props}
148
+ >
149
+ <MenuContent>
150
+ <MenuList>
151
+ {normalizeOptions.map(option => (
152
+ <MenuItem
153
+ data-ouia-component-id={`${ouiaId}-filter-item-${option.value}`}
154
+ key={option.value}
155
+ itemId={option.value}
156
+ isSelected={value.includes(option.value)}
157
+ hasCheckbox
158
+ >
159
+ {option.label}
160
+ </MenuItem>
161
+ ))}
162
+ </MenuList>
163
+ </MenuContent>
164
+ </Menu>
165
+ }
166
+ popperRef={menuRef}
167
+ appendTo={containerRef.current || undefined}
168
+ aria-label={`${title ?? filterId} filter`}
169
+ isVisible={isOpen}
170
+ />
171
+ </ToolbarFilter>
172
+ );
173
+ };
174
+
175
+ export default DataViewCheckboxFilter;
@@ -0,0 +1,197 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`DataViewCheckboxFilter component should render correctly 1`] = `
4
+ <div>
5
+ <div
6
+ class="pf-v6-c-toolbar"
7
+ data-ouia-component-id="DataViewToolbar"
8
+ data-ouia-component-type="PF6/Toolbar"
9
+ data-ouia-safe="true"
10
+ id="pf-random-id-0"
11
+ >
12
+ <div
13
+ class="pf-v6-c-toolbar__content"
14
+ >
15
+ <div
16
+ class="pf-v6-c-toolbar__content-section"
17
+ >
18
+ <div
19
+ class="pf-v6-c-toolbar__item"
20
+ >
21
+ <div
22
+ class="pf-v6-c-toolbar__item"
23
+ data-ouia-component-id="DataViewCheckboxFilter"
24
+ >
25
+ <button
26
+ aria-expanded="false"
27
+ class="pf-v6-c-menu-toggle"
28
+ data-ouia-component-id="DataViewCheckboxFilter-toggle"
29
+ data-ouia-component-type="PF6/MenuToggle"
30
+ data-ouia-safe="true"
31
+ style="width: 200px;"
32
+ type="button"
33
+ >
34
+ <span
35
+ class="pf-v6-c-menu-toggle__icon"
36
+ >
37
+ <svg
38
+ aria-hidden="true"
39
+ class="pf-v6-svg"
40
+ fill="currentColor"
41
+ height="1em"
42
+ role="img"
43
+ viewBox="0 0 512 512"
44
+ width="1em"
45
+ >
46
+ <path
47
+ d="M487.976 0H24.028C2.71 0-8.047 25.866 7.058 40.971L192 225.941V432c0 7.831 3.821 15.17 10.237 19.662l80 55.98C298.02 518.69 320 507.493 320 487.98V225.941l184.947-184.97C520.021 25.896 509.338 0 487.976 0z"
48
+ />
49
+ </svg>
50
+ </span>
51
+ <span
52
+ class="pf-v6-c-menu-toggle__text"
53
+ >
54
+ Test Checkbox Filter
55
+ </span>
56
+ <span
57
+ class="pf-v6-c-menu-toggle__count"
58
+ >
59
+ <span
60
+ class="pf-v6-c-badge pf-m-read"
61
+ data-ouia-component-id="DataViewCheckboxFilter-badge"
62
+ >
63
+ 1
64
+ </span>
65
+ </span>
66
+ <span
67
+ class="pf-v6-c-menu-toggle__controls"
68
+ >
69
+ <span
70
+ class="pf-v6-c-menu-toggle__toggle-icon"
71
+ >
72
+ <svg
73
+ aria-hidden="true"
74
+ class="pf-v6-svg"
75
+ fill="currentColor"
76
+ height="1em"
77
+ role="img"
78
+ viewBox="0 0 320 512"
79
+ width="1em"
80
+ >
81
+ <path
82
+ d="M31.3 192h257.3c17.8 0 26.7 21.5 14.1 34.1L174.1 354.8c-7.8 7.8-20.5 7.8-28.3 0L17.2 226.1C4.6 213.5 13.5 192 31.3 192z"
83
+ />
84
+ </svg>
85
+ </span>
86
+ </span>
87
+ </button>
88
+ </div>
89
+ </div>
90
+ </div>
91
+ </div>
92
+ <div
93
+ class="pf-v6-c-toolbar__content"
94
+ >
95
+ <div
96
+ class="pf-v6-c-toolbar__group"
97
+ >
98
+ <div
99
+ class="pf-v6-c-toolbar__item pf-m-label-group pf-m-label-group"
100
+ >
101
+ <div
102
+ class="pf-v6-c-label-group pf-m-category"
103
+ >
104
+ <div
105
+ class="pf-v6-c-label-group__main"
106
+ >
107
+ <span
108
+ aria-hidden="true"
109
+ class="pf-v6-c-label-group__label"
110
+ id="pf-random-id-1"
111
+ >
112
+ Test Checkbox Filter
113
+ </span>
114
+ <ul
115
+ aria-labelledby="pf-random-id-1"
116
+ class="pf-v6-c-label-group__list"
117
+ role="list"
118
+ >
119
+ <li
120
+ class="pf-v6-c-label-group__list-item"
121
+ >
122
+ <span
123
+ class="pf-v6-c-label pf-m-filled"
124
+ >
125
+ <span
126
+ class="pf-v6-c-label__content"
127
+ >
128
+ <span
129
+ class="pf-v6-c-label__text"
130
+ >
131
+ Workspace one
132
+ </span>
133
+ </span>
134
+ <span
135
+ class="pf-v6-c-label__actions"
136
+ >
137
+ <button
138
+ aria-disabled="false"
139
+ aria-label="Close Workspace one"
140
+ class="pf-v6-c-button pf-m-plain pf-m-no-padding"
141
+ data-ouia-component-id="OUIA-Generated-Button-plain-1"
142
+ data-ouia-component-type="PF6/Button"
143
+ data-ouia-safe="true"
144
+ type="button"
145
+ >
146
+ <span
147
+ class="pf-v6-c-button__icon"
148
+ >
149
+ <svg
150
+ aria-hidden="true"
151
+ class="pf-v6-svg"
152
+ fill="currentColor"
153
+ height="1em"
154
+ role="img"
155
+ viewBox="0 0 352 512"
156
+ width="1em"
157
+ >
158
+ <path
159
+ d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z"
160
+ />
161
+ </svg>
162
+ </span>
163
+ </button>
164
+ </span>
165
+ </span>
166
+ </li>
167
+ </ul>
168
+ </div>
169
+ </div>
170
+ </div>
171
+ </div>
172
+ <div
173
+ class="pf-v6-c-toolbar__group pf-m-action-group-inline"
174
+ >
175
+ <div
176
+ class="pf-v6-c-toolbar__item"
177
+ >
178
+ <button
179
+ aria-disabled="false"
180
+ class="pf-v6-c-button pf-m-link pf-m-inline"
181
+ data-ouia-component-id="DataViewToolbar-clear-all-filters"
182
+ data-ouia-component-type="PF6/Button"
183
+ data-ouia-safe="true"
184
+ type="button"
185
+ >
186
+ <span
187
+ class="pf-v6-c-button__text"
188
+ >
189
+ Clear filters
190
+ </span>
191
+ </button>
192
+ </div>
193
+ </div>
194
+ </div>
195
+ </div>
196
+ </div>
197
+ `;
@@ -0,0 +1,2 @@
1
+ export { default } from './DataViewCheckboxFilter';
2
+ export * from './DataViewCheckboxFilter';
@@ -0,0 +1,105 @@
1
+ import React from 'react';
2
+ import { render, fireEvent } from '@testing-library/react';
3
+ import { useDataViewEventsContext, DataViewEventsProvider, EventTypes } from './DataViewEventsContext';
4
+
5
+ let id = 0;
6
+
7
+ beforeAll(() => {
8
+ Object.defineProperty(global, 'crypto', {
9
+ value: {
10
+ randomUUID: jest.fn(() => `mocked-uuid-${id++}`),
11
+ },
12
+ });
13
+ });
14
+
15
+ describe('DataViewEventsContext', () => {
16
+ test('should provide context value and allow subscriptions', () => {
17
+ const callback = jest.fn();
18
+
19
+ const TestComponent = () => {
20
+ const { subscribe, trigger } = useDataViewEventsContext();
21
+
22
+ React.useEffect(() => {
23
+ const unsubscribe = subscribe(EventTypes.rowClick, callback);
24
+ return () => unsubscribe();
25
+ // eslint-disable-next-line react-hooks/exhaustive-deps
26
+ }, []);
27
+
28
+ return (
29
+ <button onClick={() => trigger(EventTypes.rowClick, 'some payload')}>Trigger</button>
30
+ );
31
+ };
32
+
33
+ const { getByText } = render(
34
+ <DataViewEventsProvider>
35
+ <TestComponent />
36
+ </DataViewEventsProvider>
37
+ );
38
+
39
+ fireEvent.click(getByText('Trigger'));
40
+ expect(callback).toHaveBeenCalledWith('some payload');
41
+ });
42
+
43
+ test('should handle unsubscribing correctly', () => {
44
+ const callback = jest.fn();
45
+
46
+ const TestComponent = () => {
47
+ const { subscribe, trigger } = useDataViewEventsContext();
48
+
49
+ React.useEffect(() => {
50
+ const unsubscribe = subscribe(EventTypes.rowClick, callback);
51
+ unsubscribe();
52
+ // eslint-disable-next-line react-hooks/exhaustive-deps
53
+ }, []);
54
+
55
+ return (
56
+ <button onClick={() => trigger(EventTypes.rowClick, 'some payload')}>Trigger</button>
57
+ );
58
+ };
59
+
60
+ const { getByText } = render(
61
+ <DataViewEventsProvider>
62
+ <TestComponent />
63
+ </DataViewEventsProvider>
64
+ );
65
+
66
+ fireEvent.click(getByText('Trigger'));
67
+
68
+ expect(callback).not.toHaveBeenCalled();
69
+ });
70
+
71
+ test('should handle multiple subscriptions and trigger events correctly', () => {
72
+ const callback1 = jest.fn();
73
+ const callback2 = jest.fn();
74
+
75
+ const TestComponent = () => {
76
+ const { subscribe, trigger } = useDataViewEventsContext();
77
+
78
+ React.useEffect(() => {
79
+ const unsubscribe1 = subscribe(EventTypes.rowClick, callback1);
80
+ const unsubscribe2 = subscribe(EventTypes.rowClick, callback2);
81
+
82
+ return () => {
83
+ unsubscribe1();
84
+ unsubscribe2();
85
+ };
86
+ // eslint-disable-next-line react-hooks/exhaustive-deps
87
+ }, []);
88
+
89
+ return (
90
+ <button onClick={() => trigger(EventTypes.rowClick, 'some payload')}>Trigger</button>
91
+ );
92
+ };
93
+
94
+ const { getByText } = render(
95
+ <DataViewEventsProvider>
96
+ <TestComponent />
97
+ </DataViewEventsProvider>
98
+ );
99
+
100
+ fireEvent.click(getByText('Trigger'));
101
+
102
+ expect(callback1).toHaveBeenCalledWith('some payload');
103
+ expect(callback2).toHaveBeenCalledWith('some payload');
104
+ });
105
+ });
@@ -0,0 +1,70 @@
1
+ import React, {
2
+ PropsWithChildren,
3
+ createContext,
4
+ useCallback,
5
+ useContext,
6
+ useState
7
+ } from "react";
8
+
9
+ export const EventTypes = {
10
+ rowClick: 'rowClick'
11
+ } as const;
12
+
13
+ export type DataViewEvent = typeof EventTypes[keyof typeof EventTypes];
14
+
15
+ type Callback = (...args: any[]) => void; // eslint-disable-line @typescript-eslint/no-explicit-any
16
+ interface Subscriptions { [id: string]: Callback }
17
+ type EventSubscriptions = { [event in DataViewEvent]: Subscriptions };
18
+ type Subscribe = (event: DataViewEvent, callback: Callback) => () => void;
19
+ type Trigger = (event: DataViewEvent, ...payload: any[]) => void; // eslint-disable-line @typescript-eslint/no-explicit-any
20
+
21
+ export interface DataViewEventsContextValue {
22
+ subscribe: Subscribe;
23
+ trigger: Trigger;
24
+ }
25
+
26
+ export const DataViewEventsContext = createContext<DataViewEventsContextValue>({
27
+ subscribe: () => () => null,
28
+ trigger: () => null
29
+ });
30
+
31
+ export const DataViewEventsProvider = ({ children }: PropsWithChildren) => {
32
+ const [ subscriptions, setSubscriptions ] = useState<EventSubscriptions>({
33
+ [EventTypes.rowClick]: {}
34
+ });
35
+
36
+ const subscribe: Subscribe = (event, callback) => {
37
+ const id = crypto.randomUUID();
38
+
39
+ // set new subscription
40
+ setSubscriptions(prevSubscriptions => ({
41
+ ...prevSubscriptions,
42
+ [event]: { ...prevSubscriptions[event], [id]: callback }
43
+ }));
44
+
45
+ // return unsubscribe function
46
+ return () => {
47
+ setSubscriptions(prevSubscriptions => {
48
+ const updatedSubscriptions = { ...prevSubscriptions };
49
+ delete updatedSubscriptions[event][id];
50
+ return updatedSubscriptions;
51
+ });
52
+ };
53
+ };
54
+
55
+ const trigger = useCallback((event: DataViewEvent, ...payload: unknown[]) => {
56
+ Object.values(subscriptions[event]).forEach(callback => {
57
+ callback(...payload);
58
+ });
59
+ }, [ subscriptions ]);
60
+
61
+ return (
62
+ <DataViewEventsContext.Provider value={{ subscribe, trigger }}>
63
+ {children}
64
+ </DataViewEventsContext.Provider>
65
+ );
66
+ };
67
+
68
+ export const useDataViewEventsContext = () => useContext(DataViewEventsContext);
69
+
70
+ export default DataViewEventsContext;
@@ -0,0 +1,2 @@
1
+ export { default } from './DataViewEventsContext';
2
+ export * from './DataViewEventsContext';
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ import { render } from '@testing-library/react';
3
+ import DataViewFilters from './DataViewFilters';
4
+ import DataViewToolbar from '../DataViewToolbar';
5
+ import DataViewTextFilter from '../DataViewTextFilter';
6
+
7
+ describe('DataViewFilters component', () => {
8
+ const mockOnChange = jest.fn();
9
+
10
+ it('should render correctly', () => {
11
+ const { container } = render(<DataViewToolbar
12
+ filters={
13
+ <DataViewFilters onChange={mockOnChange} values={{}}>
14
+ <DataViewTextFilter filterId="one" title="One" />
15
+ <DataViewTextFilter filterId="two" title="Two" />
16
+ </DataViewFilters>
17
+ }
18
+ />);
19
+ expect(container).toMatchSnapshot();
20
+ });
21
+ });