Skip to content

Commit 77fcdb1

Browse files
jeff-phillips-18priley86
authored andcommitted
feat(Toolbar): Add Toolbar and its components (#150)
* feat(Toolbar): Add Toolbar and its components * remove extraneous span wrapper from ToolbarFind * Updates per review comments * More updates per review comments * Add more action logging for toolbar
1 parent d80eb00 commit 77fcdb1

30 files changed

+3172
-123
lines changed

package-lock.json

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/Filter/Filter.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
11
import cx from 'classnames';
22
import React from 'react';
33
import PropTypes from 'prop-types';
4+
import { getContext } from 'recompose';
5+
import { toolbarContextTypes } from '../Toolbar/ToolbarConstants';
6+
7+
// Disabled eslint due to `isDescendantOfToolbar` being a context property we don't want passed by consumers
8+
const Filter = ({ children, className, isDescendantOfToolbar, ...rest }) => { // eslint-disable-line
9+
const classes = cx(
10+
{
11+
'filter-pf form-group': true,
12+
'toolbar-pf-filter': isDescendantOfToolbar
13+
},
14+
className
15+
);
416

5-
const Filter = ({ children, className, ...rest }) => {
6-
const classes = cx('filter-pf form-group', className);
717
return (
818
<div className={classes} {...rest}>
919
<div className="filter-pf-fields">
@@ -20,4 +30,4 @@ Filter.propTypes = {
2030
className: PropTypes.string
2131
};
2232

23-
export default Filter;
33+
export default getContext(toolbarContextTypes)(Filter);

src/components/Filter/Filter.stories.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ import {
88
FilterTypeSelector,
99
FilterValueSelector,
1010
FilterCategorySelector,
11-
FilterCategoryValueSelector
11+
FilterCategoryValueSelector,
12+
FilterActiveLabel,
13+
FilterList,
14+
FilterItem
1215
} from '../../index';
1316

1417
import {
@@ -34,7 +37,10 @@ stories.add(
3437
FilterTypeSelector,
3538
FilterValueSelector,
3639
FilterCategorySelector,
37-
FilterCategoryValueSelector
40+
FilterCategoryValueSelector,
41+
FilterActiveLabel,
42+
FilterList,
43+
FilterItem
3844
],
3945
propTablesExclude: [MockFilterExample],
4046
text: (
Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,18 @@
11
import React from 'react';
22
import renderer from 'react-test-renderer';
3-
import {
4-
Filter,
5-
FilterTypeSelector,
6-
FilterValueSelector,
7-
FilterCategorySelector,
8-
FilterCategoryValueSelector
9-
} from '../../index';
3+
import { Filter, FormControl, Toolbar } from '../../index';
104
import { mockFilterExampleFields } from './__mocks__/mockFilterExample';
115

126
test('Filter input renders properly', () => {
137
const component = renderer.create(
148
<Filter>
15-
<FilterTypeSelector
9+
<Filter.TypeSelector
1610
filterTypes={mockFilterExampleFields}
1711
currentFilterType={mockFilterExampleFields[0]}
1812
/>
19-
<input
20-
className="form-control"
13+
<FormControl
2114
type={mockFilterExampleFields[0].filterType}
15+
id="filterInput"
2216
value=""
2317
placeholder="Filter by Name"
2418
/>
@@ -32,11 +26,11 @@ test('Filter input renders properly', () => {
3226
test('Filter select renders properly', () => {
3327
const component = renderer.create(
3428
<Filter>
35-
<FilterTypeSelector
29+
<Filter.TypeSelector
3630
filterTypes={mockFilterExampleFields}
3731
currentFilterType={mockFilterExampleFields[2]}
3832
/>
39-
<FilterValueSelector
33+
<Filter.ValueSelector
4034
filterValues={mockFilterExampleFields[2].filterValues}
4135
currentValue={mockFilterExampleFields[2].filterValues[4]}
4236
/>
@@ -50,16 +44,16 @@ test('Filter select renders properly', () => {
5044
test('Filter categories renders properly', () => {
5145
const component = renderer.create(
5246
<Filter>
53-
<FilterTypeSelector
47+
<Filter.TypeSelector
5448
filterTypes={mockFilterExampleFields}
5549
currentFilterType={mockFilterExampleFields[3]}
5650
/>
57-
<FilterCategorySelector
51+
<Filter.CategorySelector
5852
filterCategories={mockFilterExampleFields[3].filterCategories}
5953
currentCategory={mockFilterExampleFields[3].filterCategories[0]}
6054
placeholder={mockFilterExampleFields[3].placeholder}
6155
>
62-
<FilterCategoryValueSelector
56+
<Filter.CategoryValueSelector
6357
categoryValues={
6458
mockFilterExampleFields[3].filterCategories[0].filterValues
6559
}
@@ -68,10 +62,47 @@ test('Filter categories renders properly', () => {
6862
}
6963
placeholder={mockFilterExampleFields[3].filterCategoriesPlaceholder}
7064
/>
71-
</FilterCategorySelector>
65+
</Filter.CategorySelector>
7266
</Filter>
7367
);
7468

7569
const tree = component.toJSON();
7670
expect(tree).toMatchSnapshot();
7771
});
72+
73+
test('Filter renders properly in a Toolbar', () => {
74+
const component = renderer.create(
75+
<Toolbar>
76+
<Filter>
77+
<Filter.TypeSelector
78+
filterTypes={mockFilterExampleFields}
79+
currentFilterType={mockFilterExampleFields[0]}
80+
/>
81+
<FormControl
82+
type={mockFilterExampleFields[0].filterType}
83+
id="filterInput"
84+
value=""
85+
placeholder="Filter by Name"
86+
/>
87+
</Filter>
88+
</Toolbar>
89+
);
90+
91+
const tree = component.toJSON();
92+
expect(tree).toMatchSnapshot();
93+
});
94+
95+
test('Filter active components render properly', () => {
96+
const component = renderer.create(
97+
<Toolbar.Results>
98+
<Filter.ActiveLabel title="Active Filters:" />
99+
<Filter.List>
100+
<Filter.Item label={'Name: John'} />
101+
<Filter.Item label={'Address: Westford'} />
102+
</Filter.List>
103+
</Toolbar.Results>
104+
);
105+
106+
const tree = component.toJSON();
107+
expect(tree).toMatchSnapshot();
108+
});
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import cx from 'classnames';
2+
import React from 'react';
3+
import PropTypes from 'prop-types';
4+
5+
const FilterActiveLabel = ({ children, className, ...rest }) => {
6+
const classes = cx('filter-pf-active-label', className);
7+
return <p className={classes}>{children}</p>;
8+
};
9+
10+
FilterActiveLabel.propTypes = {
11+
/** Children nodes */
12+
children: PropTypes.node,
13+
/** Additional css classes */
14+
className: PropTypes.string
15+
};
16+
17+
export default FilterActiveLabel;
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import cx from 'classnames';
2+
import React from 'react';
3+
import PropTypes from 'prop-types';
4+
5+
const FilterItem = ({ children, className, onRemove, filterData, ...rest }) => {
6+
const classes = cx(className);
7+
8+
return (
9+
<li className={classes} {...rest}>
10+
<span className="label label-info">
11+
{children}
12+
<a
13+
href="#"
14+
onClick={e => {
15+
e.preventDefault();
16+
onRemove && onRemove(filterData);
17+
}}
18+
>
19+
<span className="pficon pficon-close" aria-hidden="true" />
20+
<span className="sr-only">Remove</span>
21+
</a>
22+
</span>
23+
</li>
24+
);
25+
};
26+
27+
FilterItem.propTypes = {
28+
/** Children nodes */
29+
children: PropTypes.node,
30+
/** additional filter item classes */
31+
className: PropTypes.string,
32+
/** callback when filter is removed */
33+
onRemove: PropTypes.func,
34+
/** Data to pass to onRemove function */
35+
filterData: PropTypes.object
36+
};
37+
38+
export default FilterItem;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import cx from 'classnames';
2+
import React from 'react';
3+
import PropTypes from 'prop-types';
4+
5+
const FilterList = ({ children, className, ...rest }) => {
6+
if (!children) {
7+
return null;
8+
}
9+
const classes = cx('list-inline', className);
10+
return <ul className={classes}>{children}</ul>;
11+
};
12+
13+
FilterList.propTypes = {
14+
/** Children nodes */
15+
children: PropTypes.node,
16+
/** Additional css classes */
17+
className: PropTypes.string
18+
};
19+
20+
export default FilterList;

0 commit comments

Comments
 (0)