Skip to content

Commit 7e50cef

Browse files
committed
Init checkbox
1 parent e122f5f commit 7e50cef

File tree

9 files changed

+351
-7
lines changed

9 files changed

+351
-7
lines changed

packages/module/patternfly-docs/content/extensions/data-view/examples/Functionality/FiltersExample.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { DataViewTable } from '@patternfly/react-data-view/dist/dynamic/DataView
77
import { DataViewToolbar } from '@patternfly/react-data-view/dist/dynamic/DataViewToolbar';
88
import { DataViewFilters } from '@patternfly/react-data-view/dist/dynamic/DataViewFilters';
99
import { DataViewTextFilter } from '@patternfly/react-data-view/dist/dynamic/DataViewTextFilter';
10+
import { DataViewCheckboxFilter } from '@patternfly/react-data-view/dist/dynamic/DataViewCheckboxFilter';
1011

1112
const perPageOptions = [
1213
{ title: '5', value: 5 },
@@ -29,10 +30,10 @@ interface RepositoryFilters {
2930
const repositories: Repository[] = [
3031
{ name: 'Repository one', branch: 'Branch one', prs: 'Pull request one', workspaces: 'Workspace one', lastCommit: 'Timestamp one' },
3132
{ name: 'Repository two', branch: 'Branch two', prs: 'Pull request two', workspaces: 'Workspace two', lastCommit: 'Timestamp two' },
32-
{ name: 'Repository three', branch: 'Branch three', prs: 'Pull request three', workspaces: 'Workspace three', lastCommit: 'Timestamp three' },
33-
{ name: 'Repository four', branch: 'Branch four', prs: 'Pull request four', workspaces: 'Workspace four', lastCommit: 'Timestamp four' },
34-
{ name: 'Repository five', branch: 'Branch five', prs: 'Pull request five', workspaces: 'Workspace five', lastCommit: 'Timestamp five' },
35-
{ name: 'Repository six', branch: 'Branch six', prs: 'Pull request six', workspaces: 'Workspace six', lastCommit: 'Timestamp six' }
33+
{ name: 'Repository three', branch: 'Branch three', prs: 'Pull request three', workspaces: 'Workspace one', lastCommit: 'Timestamp three' },
34+
{ name: 'Repository four', branch: 'Branch four', prs: 'Pull request four', workspaces: 'Workspace one', lastCommit: 'Timestamp four' },
35+
{ name: 'Repository five', branch: 'Branch five', prs: 'Pull request five', workspaces: 'Workspace two', lastCommit: 'Timestamp five' },
36+
{ name: 'Repository six', branch: 'Branch six', prs: 'Pull request six', workspaces: 'Workspace three', lastCommit: 'Timestamp six' }
3637
];
3738

3839
const columns = [ 'Name', 'Branch', 'Pull requests', 'Workspaces', 'Last commit' ];
@@ -66,6 +67,7 @@ const MyTable: React.FunctionComponent = () => {
6667
<DataViewFilters onChange={(_e, values) => onSetFilters(values)} values={filters}>
6768
<DataViewTextFilter filterId="name" title='Name' placeholder='Filter by name' />
6869
<DataViewTextFilter filterId="branch" title='Branch' placeholder='Filter by branch' />
70+
<DataViewCheckboxFilter filterId="workspace" title='Workspace' placeholder='Filter by workspace' options={[]} />
6971
</DataViewFilters>
7072
}
7173
/>

packages/module/patternfly-docs/content/extensions/data-view/examples/Functionality/Functionality.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { DataViewToolbar } from '@patternfly/react-data-view/dist/dynamic/DataVi
2323
import { DataViewTable } from '@patternfly/react-data-view/dist/dynamic/DataViewTable';
2424
import { DataViewFilters } from '@patternfly/react-data-view/dist/dynamic/DataViewFilters';
2525
import { DataViewTextFilter } from '@patternfly/react-data-view/dist/dynamic/DataViewTextFilter';
26+
import { DataViewCheckboxFilter } from '@patternfly/react-data-view/dist/dynamic/DataViewCheckboxFilter';
2627

2728
This is a list of functionality you can use to manage data displayed in the **data view**.
2829

packages/module/patternfly-docs/generated/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ module.exports = {
2525
'/extensions/data-view/functionality/react': {
2626
id: "Functionality",
2727
title: "Functionality",
28-
toc: [[{"text":"Toolbar usage"},{"text":"Pagination state"},{"text":"Pagination example"},{"text":"Toolbar usage","id":"toolbar-usage-0"},{"text":"Selection state"},{"text":"Selection example"}]],
29-
examples: ["Pagination example","Selection example"],
28+
toc: [[{"text":"Toolbar usage"},{"text":"Pagination state"},{"text":"Pagination example"},{"text":"Toolbar usage","id":"toolbar-usage-0"},{"text":"Selection state"},{"text":"Selection example"},{"text":"Toolbar usage","id":"toolbar-usage-1"},{"text":"Filters state"},{"text":"Filtering example"}]],
29+
examples: ["Pagination example","Selection example","Filtering example"],
3030
section: "extensions",
3131
subsection: "Data view",
3232
source: "react",
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import React from 'react';
2+
import { render } from '@testing-library/react';
3+
import DataViewTextFilter, { DataViewTextFilterProps } from '../DataViewTextFilter';
4+
import DataViewToolbar from '../DataViewToolbar';
5+
6+
describe('DataViewTextFilter component', () => {
7+
const mockOnChange = jest.fn();
8+
9+
const defaultProps: DataViewTextFilterProps = {
10+
filterId: 'test-filter',
11+
title: 'Test Filter',
12+
value: 'initial value',
13+
onChange: mockOnChange,
14+
};
15+
16+
it('should render correctly', () => {
17+
const { container } = render(<DataViewToolbar
18+
filters={
19+
<DataViewTextFilter {...defaultProps} />
20+
}
21+
/>);
22+
expect(container).toMatchSnapshot();
23+
});
24+
});
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import React from 'react';
2+
import { Badge, Menu, MenuContent, MenuItem, MenuList, MenuProps, MenuToggle, Popper, ToolbarChip, ToolbarFilter, ToolbarFilterProps } from '@patternfly/react-core';
3+
import { FilterIcon } from '@patternfly/react-icons';
4+
import { DataViewFilterOption } from '../DataViewFilters';
5+
6+
const isToolbarChip = (chip: string | ToolbarChip): chip is ToolbarChip => typeof chip === 'object' && 'key' in chip;
7+
8+
/** extends MenuProps */
9+
export interface DataViewCheckboxFilterProps extends Omit<MenuProps, 'onSelect' | 'onChange'> {
10+
/** Unique key for the filter attribute */
11+
filterId: string;
12+
/** Current filter value */
13+
value?: string[];
14+
/** Filter title displayed in the toolbar */
15+
title: string;
16+
/** Placeholder text of the menu */
17+
placeholder?: string;
18+
/** Filter options displayed */
19+
options: DataViewFilterOption[];
20+
/** Callback for updating when item selection changes. */
21+
onChange?: (event?: React.MouseEvent, values?: (string | number)[]) => void;
22+
/** Controls visibility of the filter in the toolbar */
23+
showToolbarItem?: ToolbarFilterProps['showToolbarItem'];
24+
/** Controls visibility of the filter icon */
25+
showIcon?: boolean;
26+
/** Controls visibility of the selected items badge */
27+
showBadge?: boolean;
28+
/** Custom OUIA ID */
29+
ouiaId?: string;
30+
}
31+
32+
export const DataViewCheckboxFilter: React.FC<DataViewCheckboxFilterProps> = ({
33+
filterId,
34+
title,
35+
value = [],
36+
onChange,
37+
placeholder,
38+
options = [],
39+
showToolbarItem,
40+
showIcon = !placeholder,
41+
showBadge = !placeholder,
42+
ouiaId = 'DataViewCheckboxFilter',
43+
...props
44+
}: DataViewCheckboxFilterProps) => {
45+
const [ isOpen, setIsOpen ] = React.useState<boolean>(false);
46+
const toggleRef = React.useRef<HTMLButtonElement>(null);
47+
const menuRef = React.useRef<HTMLDivElement>(null);
48+
const containerRef = React.useRef<HTMLDivElement>(null);
49+
50+
const onToggleClick = (ev: React.MouseEvent) => {
51+
ev.stopPropagation();
52+
setTimeout(() => {
53+
if (menuRef.current) {
54+
const firstElement = menuRef.current.querySelector('li > button:not(:disabled)');
55+
firstElement && (firstElement as HTMLElement).focus();
56+
}
57+
}, 0);
58+
setIsOpen(!isOpen);
59+
};
60+
61+
const toggle = (
62+
<MenuToggle
63+
ref={toggleRef}
64+
onClick={onToggleClick}
65+
isExpanded={isOpen}
66+
icon={showIcon ? <FilterIcon /> : undefined}
67+
{...(value.length > 0 && showBadge && { badge: <Badge isRead>{value.length}</Badge> })}
68+
style={
69+
{
70+
width: '200px'
71+
} as React.CSSProperties
72+
}
73+
>
74+
{placeholder ?? title}
75+
</MenuToggle>
76+
);
77+
78+
const menu = (
79+
<Menu ref={menuRef} ouiaId={`${ouiaId}-menu`} onSelect={(event, item) => item !== undefined && onChange?.(event, value.includes(String(item)) ? value.filter((selection) => selection !== item) : [ item, ...value ])} selected={value} {...props}>
80+
<MenuContent>
81+
<MenuList>
82+
{options.map(option => <MenuItem hasCheckbox data-ouia-component-id={`${option.key}-checkbox-option`} key={String(option.key)} isSelected={value.includes(option.key)} itemId="Bangalore">
83+
{option.label}
84+
</MenuItem>)}
85+
</MenuList>
86+
</MenuContent>
87+
</Menu>
88+
);
89+
return (
90+
<ToolbarFilter
91+
data-ouia-component-id={ouiaId}
92+
chips={value.map(item => ({ key: item, node: options.find(option => option.key === item)?.label }))}
93+
deleteChip={(_category, chip) => onChange?.(undefined, value.filter(key => key !== (isToolbarChip(chip) ? chip.key : chip)))}
94+
categoryName={title}
95+
showToolbarItem={showToolbarItem}
96+
>
97+
<Popper
98+
trigger={toggle}
99+
triggerRef={toggleRef}
100+
popper={menu}
101+
popperRef={menuRef}
102+
appendTo={containerRef.current || undefined}
103+
aria-label={`${title ?? filterId} filter`}
104+
isVisible={isOpen}
105+
/>
106+
</ToolbarFilter>);
107+
}
108+
109+
export default DataViewCheckboxFilter;
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`DataViewTextFilter component should render correctly 1`] = `
4+
<div>
5+
<div
6+
class="pf-v5-c-toolbar"
7+
data-ouia-component-id="DataViewToolbar"
8+
data-ouia-component-type="PF5/Toolbar"
9+
data-ouia-safe="true"
10+
id="pf-random-id-0"
11+
>
12+
<div
13+
class="pf-v5-c-toolbar__content"
14+
>
15+
<div
16+
class="pf-v5-c-toolbar__content-section"
17+
>
18+
<div
19+
class="pf-v5-c-toolbar__item pf-m-search-filter"
20+
>
21+
<div
22+
class="pf-v5-c-toolbar__item"
23+
data-ouia-component-id="DataViewTextFilter"
24+
>
25+
<div
26+
class="pf-v5-c-text-input-group"
27+
data-ouia-component-id="DataViewTextFilter-input"
28+
>
29+
<div
30+
class="pf-v5-c-text-input-group__main pf-m-icon"
31+
>
32+
<span
33+
class="pf-v5-c-text-input-group__text"
34+
>
35+
<span
36+
class="pf-v5-c-text-input-group__icon"
37+
>
38+
<svg
39+
aria-hidden="true"
40+
class="pf-v5-svg"
41+
fill="currentColor"
42+
height="1em"
43+
role="img"
44+
viewBox="0 0 512 512"
45+
width="1em"
46+
>
47+
<path
48+
d="M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z"
49+
/>
50+
</svg>
51+
</span>
52+
<input
53+
aria-label="Test Filter filter"
54+
class="pf-v5-c-text-input-group__text-input"
55+
id="test-filter"
56+
placeholder="Filter by Test Filter"
57+
type="text"
58+
value="initial value"
59+
/>
60+
</span>
61+
</div>
62+
<div
63+
class="pf-v5-c-text-input-group__utilities"
64+
>
65+
<button
66+
aria-disabled="false"
67+
aria-label="Reset"
68+
class="pf-v5-c-button pf-m-plain"
69+
data-ouia-component-id="OUIA-Generated-Button-plain-2"
70+
data-ouia-component-type="PF5/Button"
71+
data-ouia-safe="true"
72+
type="button"
73+
>
74+
<svg
75+
aria-hidden="true"
76+
class="pf-v5-svg"
77+
fill="currentColor"
78+
height="1em"
79+
role="img"
80+
viewBox="0 0 352 512"
81+
width="1em"
82+
>
83+
<path
84+
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"
85+
/>
86+
</svg>
87+
</button>
88+
</div>
89+
</div>
90+
</div>
91+
</div>
92+
</div>
93+
</div>
94+
<div
95+
class="pf-v5-c-toolbar__content pf-m-chip-container"
96+
>
97+
<div
98+
class="pf-v5-c-toolbar__group"
99+
>
100+
<div
101+
class="pf-v5-c-toolbar__item pf-m-chip-group"
102+
>
103+
<div
104+
aria-labelledby="pf-random-id-1"
105+
class="pf-v5-c-chip-group pf-m-category"
106+
data-ouia-component-type="PF5/ChipGroup"
107+
data-ouia-safe="true"
108+
role="group"
109+
>
110+
<div
111+
class="pf-v5-c-chip-group__main"
112+
>
113+
<span
114+
class="pf-v5-c-chip-group__label"
115+
id="pf-random-id-1"
116+
>
117+
Test Filter
118+
</span>
119+
<ul
120+
aria-labelledby="pf-random-id-1"
121+
class="pf-v5-c-chip-group__list"
122+
role="list"
123+
>
124+
<li
125+
class="pf-v5-c-chip-group__list-item"
126+
>
127+
<div
128+
class="pf-v5-c-chip"
129+
data-ouia-component-id="OUIA-Generated-Chip-1"
130+
data-ouia-component-type="PF5/Chip"
131+
data-ouia-safe="true"
132+
>
133+
<span
134+
class="pf-v5-c-chip__content"
135+
>
136+
<span
137+
class="pf-v5-c-chip__text"
138+
id="pf-random-id-2"
139+
>
140+
initial value
141+
</span>
142+
</span>
143+
<span
144+
class="pf-v5-c-chip__actions"
145+
>
146+
<button
147+
aria-disabled="false"
148+
aria-label="close"
149+
aria-labelledby="remove_pf-random-id-2 pf-random-id-2"
150+
class="pf-v5-c-button pf-m-plain"
151+
data-ouia-component-id="close"
152+
data-ouia-component-type="PF5/Button"
153+
data-ouia-safe="true"
154+
id="remove_pf-random-id-2"
155+
type="button"
156+
>
157+
<svg
158+
aria-hidden="true"
159+
class="pf-v5-svg"
160+
fill="currentColor"
161+
height="1em"
162+
role="img"
163+
viewBox="0 0 352 512"
164+
width="1em"
165+
>
166+
<path
167+
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"
168+
/>
169+
</svg>
170+
</button>
171+
</span>
172+
</div>
173+
</li>
174+
</ul>
175+
</div>
176+
</div>
177+
</div>
178+
</div>
179+
<div
180+
class="pf-v5-c-toolbar__item"
181+
>
182+
<button
183+
aria-disabled="false"
184+
class="pf-v5-c-button pf-m-link pf-m-inline"
185+
data-ouia-component-id="DataViewToolbar-clear-all-filters"
186+
data-ouia-component-type="PF5/Button"
187+
data-ouia-safe="true"
188+
type="button"
189+
>
190+
Clear filters
191+
</button>
192+
</div>
193+
</div>
194+
</div>
195+
</div>
196+
`;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { default } from './DataViewCheckboxFilter';
2+
export * from './DataViewCheckboxFilter';

0 commit comments

Comments
 (0)