Skip to content

Commit a1e9cbb

Browse files
feat(VariantManagement): Initial Version
1 parent b685e68 commit a1e9cbb

File tree

6 files changed

+287
-0
lines changed

6 files changed

+287
-0
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { VariantManagement } 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+
7+
const variantItems = [{ label: 'Variant 1', key: '1' }, { label: 'Variant 2', key: '2' }];
8+
9+
use(matchSnapshot);
10+
11+
describe('VariantManagement', () => {
12+
let appRoot: HTMLElement;
13+
14+
before(() => {
15+
appRoot = document.createElement('div');
16+
document.body.appendChild(appRoot);
17+
});
18+
19+
after(() => {
20+
document.body.removeChild(appRoot);
21+
});
22+
23+
it('Render without crashing', () => {
24+
const wrapper = mountThemedComponent(<VariantManagement variantItems={variantItems} />);
25+
expect(wrapper.debug()).to.matchSnapshot();
26+
});
27+
28+
// it('With suggestions', () => {
29+
// const callback = sinon.spy();
30+
// const wrapper = mountThemedComponent(<VariantManagement onSelect={callback} variantItems={variantItems} />);
31+
//
32+
// console.log('find button', wrapper.find(Button));
33+
//
34+
//
35+
//
36+
// // @ts-ignore
37+
// (wrapper.find(Button).first().prop('onPress') as any)({target: {}});
38+
//
39+
//
40+
// wrapper.update();
41+
//
42+
// const listItem = wrapper
43+
// // @ts-ignore
44+
// .find(ListItem.InnerComponent)
45+
// .last()
46+
// .find('li');
47+
// listItem.simulate('click');
48+
//
49+
// expect(wrapper.debug()).to.matchSnapshot();
50+
// expect(getEventFromCallback(callback).getParameter('selectedItem')).to.equal(variantItems[1]);
51+
//
52+
//
53+
// });
54+
});
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`VariantManagement Render Basic VariantManagement 1`] = `
4+
<div
5+
style="display: inline-block;"
6+
>
7+
<div
8+
class="VariantManagement-VariantManagement-"
9+
>
10+
<span
11+
class="VariantManagement-VariantManagementText-"
12+
>
13+
<h4
14+
class="Component-title- Component-h4-"
15+
>
16+
Variant 1
17+
</h4>
18+
</span>
19+
<button
20+
class="Button-button- Button-compact- Button-transparent-"
21+
>
22+
<span
23+
class="Button-buttonInner- Button-iconOnly-"
24+
>
25+
<span
26+
aria-label="navigation-down-arrow"
27+
class="Icon-icon- Icon-icon-"
28+
data-icon-content=""
29+
role="presentation"
30+
style="font-family: SAP-icons;"
31+
tabindex="-1"
32+
/>
33+
</span>
34+
</button>
35+
</div>
36+
</div>
37+
`;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import React from 'react';
2+
import { boolean, select } from '@storybook/addon-knobs';
3+
import { action } from '@storybook/addon-actions';
4+
import { storiesOf } from '@storybook/react';
5+
import { VariantManagement } from './index';
6+
import { PlacementType } from '@fiori-for-react/core/enums/PlacementType';
7+
8+
import { TitleLevel } from '../..';
9+
10+
function renderStory() {
11+
const variantItems = [{ label: 'Variant 1', key: '1' }, { label: 'Variant 2', key: '2' }];
12+
13+
return (
14+
<VariantManagement
15+
style={{ width: '300px', height: 'auto' }}
16+
closeOnItemSelect={boolean('closeOnItemSelect', true)}
17+
initialSelectedKey={'2'}
18+
variantItems={variantItems}
19+
onSelect={action('onSelect')}
20+
placement={select('Placement', PlacementType, PlacementType.Bottom)}
21+
level={select('level', TitleLevel, TitleLevel.H4)}
22+
/>
23+
);
24+
}
25+
26+
storiesOf('F4R Components | VariantManagement', module).add('Default', renderStory);
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
import React, { Component, ReactElement } from 'react';
2+
import { ButtonType, PlacementType } from '@fiori-for-react/core/enums';
3+
import { Event } from '@fiori-for-react/utils';
4+
import { ClassProps, JSSTheme } from '@fiori-for-react/core/types';
5+
import { withStyles } from '@fiori-for-react/core/utils/withStyles';
6+
import { Title } from '../../webComponents/Title';
7+
import { Button, ButtonPropTypes } from '../../webComponents/Button';
8+
import { ResponsivePopover } from '../ResponsivePopover';
9+
import { List } from '../../webComponents/List';
10+
import { ListItemTypes, ListMode, TitleLevel } from '../..';
11+
import { CommonProps } from '@fiori-for-react/core/interfaces';
12+
import { StandardListItem } from '../../webComponents/StandardListItem';
13+
14+
export interface VariantItem {
15+
key: string;
16+
label: string;
17+
}
18+
19+
export interface VariantManagementPropTypes extends CommonProps {
20+
enabled?: boolean;
21+
placement?: PlacementType;
22+
popupTitle?: string;
23+
initialSelectedKey?: string;
24+
closeOnItemSelect?: boolean;
25+
variantItems: VariantItem[];
26+
onSelect?: (event: Event) => void;
27+
level?: TitleLevel;
28+
}
29+
30+
interface VariantManagementInternalProps extends VariantManagementPropTypes, ClassProps {
31+
theme: JSSTheme;
32+
}
33+
34+
interface VariantManagementState {
35+
selectedKey: string;
36+
open: boolean;
37+
}
38+
39+
const styles = ({ parameters }: JSSTheme) => ({
40+
VariantManagement: {
41+
display: 'inline',
42+
textAlign: 'center',
43+
cursor: 'pointer'
44+
},
45+
VariantManagementText: {
46+
'& > *': {
47+
cursor: 'pointer',
48+
textShadow: parameters.sapUiContentShadowColor
49+
}
50+
},
51+
footer: {
52+
float: 'right',
53+
padding: '0.5rem'
54+
}
55+
});
56+
57+
@withStyles(styles)
58+
export class VariantManagement extends Component<VariantManagementPropTypes, VariantManagementState> {
59+
static defaultProps = {
60+
enabled: true,
61+
popupTitle: 'Variants',
62+
initialSelectedKey: null,
63+
onSelect: () => {},
64+
closeOnItemSelect: true,
65+
placement: PlacementType.Bottom,
66+
level: TitleLevel.H4
67+
};
68+
69+
private initialSelectedKey = this.props.variantItems && this.props.variantItems[0] && this.props.variantItems[0].key;
70+
71+
state = {
72+
selectedKey: this.initialSelectedKey,
73+
open: false
74+
};
75+
76+
_getItemByKey(key, items) {
77+
return items.filter((item) => item.key === key)[0];
78+
}
79+
80+
private handleCancelButtonClick = () => {
81+
this.setState({ open: false });
82+
};
83+
84+
private handleAfterOpen = () => {
85+
this.setState({ open: true });
86+
};
87+
88+
private handleVariantItemSelect = (event) => {
89+
const selectedKey = event.getParameter('item').getAttribute('data-key');
90+
const { variantItems } = this.props as VariantManagementInternalProps;
91+
const selectedItem = this._getItemByKey(selectedKey, variantItems) || variantItems[0];
92+
this.setState({ selectedKey });
93+
this.props.onSelect(Event.of(this, event.getOriginalEvent(), { selectedItem }));
94+
if (this.props.closeOnItemSelect) {
95+
const openPopover = !this.state.open;
96+
this.setState({ open: openPopover });
97+
}
98+
};
99+
100+
private get variantManagementButton() {
101+
const { classes, variantItems, level } = this.props as VariantManagementInternalProps;
102+
const { selectedKey } = this.state;
103+
const selectedItem = this._getItemByKey(selectedKey, variantItems) || variantItems[0];
104+
105+
return (
106+
<div className={classes.VariantManagement}>
107+
<span className={classes.VariantManagementText}>
108+
<Title level={level}>{selectedItem.label}</Title>
109+
</span>
110+
<Button type={ButtonType.Transparent} icon={'navigation-down-arrow'} />
111+
</div>
112+
);
113+
}
114+
115+
private getVariantManagementFooterButtons = () => {
116+
const { classes } = this.props as VariantManagementInternalProps;
117+
return [
118+
<Button
119+
className={classes.footer}
120+
key="btn-cancel"
121+
onPress={this.handleCancelButtonClick}
122+
type={ButtonType.Emphasized}
123+
>
124+
Cancel
125+
</Button>
126+
] as Array<ReactElement<ButtonPropTypes>>;
127+
};
128+
129+
render() {
130+
const { variantItems, popupTitle, className, style, tooltip } = this.props;
131+
const { selectedKey } = this.state;
132+
133+
if (!variantItems || variantItems.length < 1) {
134+
return null;
135+
}
136+
137+
return (
138+
<ResponsivePopover
139+
open={this.state.open}
140+
onAfterOpen={this.handleAfterOpen}
141+
headerText={popupTitle}
142+
placementType={this.props.placement}
143+
openBy={this.variantManagementButton}
144+
footer={this.getVariantManagementFooterButtons() as Array<ReactElement<ButtonPropTypes>>}
145+
className={className}
146+
innerStyles={style}
147+
tooltip={tooltip}
148+
>
149+
<List onItemPress={this.handleVariantItemSelect} mode={ListMode.SingleSelect}>
150+
{variantItems.map((item) => (
151+
<StandardListItem
152+
style={{ width: '300px' }}
153+
data-key={item.key}
154+
type={ListItemTypes.Active}
155+
key={item.key}
156+
selected={selectedKey === item.key}
157+
>
158+
{item.label}
159+
</StandardListItem>
160+
))}
161+
</List>
162+
</ResponsivePopover>
163+
);
164+
}
165+
}

packages/fiori3/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ import { ToggleButton } from './lib/ToggleButton';
7979
import { Token } from './lib/Token';
8080
import { Tokenizer } from './lib/Tokenizer';
8181
import { ValueState } from './lib/ValueState';
82+
import { VariantManagement } from './lib/VariantManagement';
8283
import { YearPicker } from './lib/YearPicker';
8384

8485
export {
@@ -90,6 +91,7 @@ export {
9091
Size,
9192
TitleLevel,
9293
ValueState,
94+
VariantManagement,
9395
ActionSheet,
9496
AnalyticalCard,
9597
AnalyticalCardHeader,
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { VariantManagement } from '../components/VariantManagement';
2+
3+
export { VariantManagement };

0 commit comments

Comments
 (0)