Skip to content

Commit 422bdbd

Browse files
feat(FilterBar): Initial Version
1 parent 19a23ec commit 422bdbd

File tree

6 files changed

+373
-0
lines changed

6 files changed

+373
-0
lines changed
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { fonts, sap_fiori_3 } from '@fiori-for-react/styles';
2+
import { JSSTheme } from '@fiori-for-react/core/types/JSSTheme';
3+
4+
const styles = ({ theme, contentDensity, parameters }: JSSTheme) => {
5+
return {
6+
outerContainer: {
7+
paddingTop: '0.5rem',
8+
paddingLeft: '2rem',
9+
paddingRight: '2rem',
10+
paddingBottom: '1px',
11+
background: sap_fiori_3.sapUiObjectHeaderBackground,
12+
boxShadow: sap_fiori_3.sapUiShadowHeader
13+
},
14+
filterBarHeader: {
15+
alignItems: 'center',
16+
display: 'flex',
17+
background: sap_fiori_3.sapUiObjectHeaderBackground,
18+
minHeight: '3rem',
19+
paddingBottom: '0.5rem',
20+
boxShadow: 'none'
21+
},
22+
vLine: {
23+
borderLeft: '1px solid gray',
24+
paddingLeft: '0.5rem'
25+
},
26+
filterArea: {
27+
display: 'flex',
28+
flexWrap: 'wrap',
29+
paddingTop: '1rem',
30+
paddingBottom: '1rem',
31+
background: sap_fiori_3.sapUiObjectHeaderBackground
32+
},
33+
'@media (max-width: 599px)': {
34+
filterArea: {
35+
columnCount: 3,
36+
columnGap: '0.5rem',
37+
rowGap: '0.5rem'
38+
}
39+
},
40+
'@media (min-width: 600px) and (max-width: 1023px)': {
41+
filterArea: {
42+
columnCount: 8,
43+
columnGap: '1rem',
44+
rowGap: '1rem'
45+
}
46+
},
47+
'@media (min-width: 1024px) and (max-width: 1439px)': {
48+
filterArea: {
49+
columnCount: 12,
50+
columnGap: '1rem',
51+
rowGap: '1rem'
52+
}
53+
},
54+
'@media (min-width: 1440px)': {
55+
filterArea: {
56+
columnCount: 16,
57+
columnGap: '1rem',
58+
rowGap: '1rem'
59+
}
60+
},
61+
headerRowRight: {
62+
display: 'flex',
63+
justifyContent: 'flex-end',
64+
width: '100%'
65+
},
66+
// is being applied to the span which represents the InfoLabel Text
67+
label: {
68+
fontSize: fonts.sapMFontSmallSize,
69+
fontFamily: fonts.sapUiFontFamily,
70+
lineHeight: '1.125rem',
71+
fontWeight: 600,
72+
letterSpacing: '0.0125rem',
73+
textTransform: 'uppercase',
74+
textAlign: 'center',
75+
verticalAlign: 'top',
76+
textOverflow: 'ellipsis',
77+
whiteSpace: 'nowrap',
78+
display: 'inline-block',
79+
color: parameters.sapUiBaseText
80+
},
81+
// specific padding needed for purely numeric input
82+
numeric: {},
83+
// specific padding needed for text input
84+
text: {},
85+
// displayOnly mode
86+
displayOnly: {}
87+
};
88+
};
89+
90+
export default styles;
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import { FilterBar } from './index';
2+
import React from 'react';
3+
import { mountThemedComponent } from '@shared/tests/utils';
4+
import { expect, use } from 'chai';
5+
import { matchSnapshot } from 'chai-karma-snapshot';
6+
import { VariantManagement } from '../VariantManagement';
7+
import { FilterItem } from '../FilterItem';
8+
import { FilterType } from '../../enums/FilterType';
9+
import { Switch } from '../../webComponents/Switch';
10+
import { Button } from '../../webComponents/Button';
11+
12+
const variantItems = [{ label: 'Variant 1', key: '1' }, { label: 'Variant 2', key: '2' }];
13+
const filterItems = [{ text: 'Text 1', key: '1' }, { text: 'Text 2', key: '2' }];
14+
15+
const renderVariants = () => <VariantManagement variantItems={variantItems} />;
16+
17+
use(matchSnapshot);
18+
19+
describe('FilterBar', () => {
20+
it('Render without crashing', () => {
21+
const wrapper = mountThemedComponent(
22+
<FilterBar renderVariants={renderVariants}>
23+
<FilterItem
24+
// onChange={(e) => alert(e.getParameter('selectedItem').key)}
25+
filterItems={filterItems}
26+
label="Classification"
27+
key="classification"
28+
type={FilterType.Select}
29+
/>
30+
<FilterItem
31+
key={'filter2'}
32+
type={FilterType.Custom}
33+
label={'Custom Filter 1'}
34+
changeEventName={'onClick'}
35+
valueParamName={'state'}
36+
>
37+
<Switch />
38+
</FilterItem>
39+
</FilterBar>
40+
);
41+
expect(wrapper.debug()).to.matchSnapshot();
42+
});
43+
44+
it('Hide Filter Bar', () => {
45+
const wrapper = mountThemedComponent(
46+
<FilterBar renderVariants={renderVariants}>
47+
<FilterItem
48+
// onChange={(e) => alert(e.getParameter('selectedItem').key)}
49+
filterItems={filterItems}
50+
label="Classification"
51+
key="classification"
52+
type={FilterType.Select}
53+
/>
54+
<FilterItem
55+
key={'filter2'}
56+
type={FilterType.Custom}
57+
label={'Custom Filter 1'}
58+
changeEventName={'onClick'}
59+
valueParamName={'state'}
60+
>
61+
<Switch />
62+
</FilterItem>
63+
<FilterItem
64+
loading
65+
key={'filter2'}
66+
type={FilterType.Custom}
67+
label={'Custom Filter 1'}
68+
changeEventName={'onClick'}
69+
valueParamName={'state'}
70+
>
71+
<Switch />
72+
</FilterItem>
73+
</FilterBar>
74+
);
75+
(wrapper
76+
.find('Button')
77+
.at(2)
78+
.prop('onPress') as any)({ target: {} });
79+
80+
expect(wrapper.debug()).to.matchSnapshot();
81+
});
82+
83+
it('Select Filter Item', () => {
84+
const wrapper = mountThemedComponent(
85+
<FilterBar renderVariants={renderVariants}>
86+
<FilterItem
87+
// onChange={(e) => alert(e.getParameter('selectedItem').key)}
88+
filterItems={filterItems}
89+
label="Classification"
90+
key="classification"
91+
type={FilterType.Select}
92+
/>
93+
<FilterItem
94+
// onChange={(e) => alert(e.getParameter('selectedItem').key)}
95+
loading
96+
filterItems={filterItems}
97+
label="Classification"
98+
key="classification"
99+
type={FilterType.Select}
100+
/>
101+
<FilterItem
102+
// onChange={(e) => alert(e.getParameter('selectedItem').key)}
103+
// filterItems={filterItems}
104+
label="Classification"
105+
key="classification"
106+
type={FilterType.Default}
107+
/>
108+
</FilterBar>
109+
);
110+
// console.log(wrapper.debug());
111+
// console.log(wrapper.find('Select').debug());
112+
console.log(wrapper.find('ui5-li').debug());
113+
wrapper
114+
.find('ui5-li')
115+
.at(1)
116+
.simulate('change');
117+
118+
expect(wrapper.debug()).to.matchSnapshot();
119+
});
120+
});
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import React from 'react';
2+
import { storiesOf } from '@storybook/react';
3+
import { boolean, select } from '@storybook/addon-knobs';
4+
import { FilterBar } from './index';
5+
import { VariantManagement } from '../VariantManagement';
6+
import { FilterItem } from '../FilterItem';
7+
import { PlacementType } from '@fiori-for-react/core/enums/PlacementType';
8+
import { TitleLevel } from '@fiori-for-react/core';
9+
import { FilterType } from '../../enums/FilterType';
10+
import { CheckBox } from '../../webComponents/CheckBox';
11+
import { Select } from '../../webComponents/Select';
12+
import { Switch } from '../../webComponents/Switch';
13+
14+
const flavours = [];
15+
for (let i = 1; i <= 9; i++) {
16+
flavours.push(i);
17+
}
18+
const variantItems = [{ label: 'Variant 1', key: '1' }, { label: 'Variant 2', key: '2' }];
19+
const filterItems = [{ text: 'Text 1', key: '1' }, { text: 'Text 2', key: '2' }];
20+
21+
const renderVariants = () => {
22+
return (
23+
<VariantManagement
24+
style={{ width: '300px', height: 'auto' }}
25+
closeOnItemSelect={boolean('closeOnItemSelect', true)}
26+
initialSelectedKey={'2'}
27+
variantItems={variantItems}
28+
onSelect={(e) => {
29+
console.log(e.getParameter('selectedItem').key);
30+
}}
31+
placement={select('Placement', PlacementType, PlacementType.Bottom)}
32+
level={select('level', TitleLevel, TitleLevel.H6)}
33+
/>
34+
);
35+
};
36+
37+
function renderStory() {
38+
return (
39+
<FilterBar renderVariants={renderVariants}>
40+
<FilterItem
41+
onChange={(e) => alert(e.getParameter('selectedItem').key)}
42+
filterItems={filterItems}
43+
label="Classification"
44+
key="classification"
45+
type={FilterType.Select}
46+
/>
47+
<FilterItem
48+
onChange={(e) => alert(e.getParameter('selectedItem').key)}
49+
filterItems={filterItems}
50+
label="Classification"
51+
key="classification"
52+
type={FilterType.Select}
53+
/>
54+
<FilterItem
55+
onChange={(e) => alert(e.getParameter('selectedItem').key)}
56+
filterItems={filterItems}
57+
label="Classification"
58+
key="classification"
59+
type={FilterType.Select}
60+
/>
61+
<FilterItem
62+
onChange={(e) => alert(e.getParameter('selectedItem').key)}
63+
filterItems={filterItems}
64+
label="Classification"
65+
key="classification"
66+
type={FilterType.Select}
67+
/>
68+
<FilterItem
69+
onChange={(e) => alert(e.getParameter('selectedItem').key)}
70+
filterItems={filterItems}
71+
label="Classification"
72+
key="classification"
73+
type={FilterType.Select}
74+
/>
75+
<FilterItem
76+
onChange={(e) => alert(e.getParameter('selectedItem').key)}
77+
filterItems={filterItems}
78+
label="Classification"
79+
key="classification"
80+
type={FilterType.Select}
81+
/>
82+
<FilterItem
83+
onChange={(e) => alert(e.getParameter('selectedItem').key)}
84+
filterItems={filterItems}
85+
label="Classification"
86+
key="classification"
87+
type={FilterType.Select}
88+
/>
89+
<FilterItem
90+
key={'filter2'}
91+
type={FilterType.Custom}
92+
label={'Custom Filter 1'}
93+
changeEventName={'onClick'}
94+
valueParamName={'state'}
95+
>
96+
<Switch />
97+
</FilterItem>
98+
</FilterBar>
99+
);
100+
}
101+
102+
storiesOf('F4R Components | FilterBar', module).add('Default', renderStory);
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { ClassProps } from '@fiori-for-react/core/types/ClassProps';
2+
import { withStyles } from '@fiori-for-react/core/utils/withStyles';
3+
import React, { PureComponent, ReactNode, ReactNodeArray } from 'react';
4+
import { Fiori3CommonProps } from '../../interfaces/Fiori3CommonProps';
5+
import styles from './FilterBar.jss';
6+
import { Input } from '../../webComponents/Input';
7+
import { Button } from '../../webComponents/Button';
8+
import { ButtonType } from '../..';
9+
10+
export interface FilterBarPropTypes extends Fiori3CommonProps {
11+
renderVariants?: () => JSX.Element;
12+
renderSearch?: boolean;
13+
children: ReactNode | ReactNodeArray;
14+
}
15+
16+
interface FilterBarInternalProps extends FilterBarPropTypes, ClassProps {}
17+
18+
@withStyles(styles)
19+
export class FilterBar extends PureComponent<FilterBarPropTypes> {
20+
static defaultProps = {
21+
children: '',
22+
displayOnly: true,
23+
renderSearch: true
24+
};
25+
26+
state = {
27+
showFilters: true
28+
};
29+
30+
handelHideFilterBar = () => {
31+
this.setState({ showFilters: !this.state.showFilters });
32+
};
33+
34+
render() {
35+
const { children, classes, renderVariants, renderSearch } = this.props as FilterBarInternalProps;
36+
37+
return (
38+
<div className={classes.outerContainer}>
39+
<div className={classes.filterBarHeader}>
40+
{renderVariants && renderVariants()}
41+
{renderSearch && (
42+
<div className={classes.vLine}>
43+
<Input placeholder={'Search'} />
44+
</div>
45+
)}
46+
<div className={classes.headerRowRight}>
47+
<Button onPress={this.handelHideFilterBar} type={ButtonType.Transparent}>
48+
{this.state.showFilters ? 'Hide Filter Bar' : 'Show Filter Bar'}
49+
</Button>
50+
</div>
51+
</div>
52+
{this.state.showFilters && <div className={classes.filterArea}>{children}</div>}
53+
</div>
54+
);
55+
}
56+
}

packages/fiori3/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { CustomListItem } from './lib/CustomListItem';
1616
import { DatePicker } from './lib/DatePicker';
1717
import { DeviationIndicator } from './lib/DeviationIndicator';
1818
import { Dialog } from './lib/Dialog';
19+
import { FilterBar } from './lib/FilterBar';
1920
import { FilterItem } from './lib/FilterItem';
2021
import { FlexBox } from './lib/FlexBox';
2122
import { FlexBoxAlignItems } from './lib/FlexBoxAlignItems';
@@ -101,6 +102,7 @@ export {
101102
Carousel,
102103
InfoLabel,
103104
Bar,
105+
FilterBar,
104106
FilterItem,
105107
FlexBox,
106108
FlexBoxJustifyContent,

packages/fiori3/src/lib/FilterBar.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { FilterBar } from '../components/FilterBar';
2+
3+
export { FilterBar };

0 commit comments

Comments
 (0)