Skip to content

Commit 0edb563

Browse files
committed
feat(component): introduce the pf4 switch component
fix #728
1 parent 25ca229 commit 0edb563

File tree

11 files changed

+375
-0
lines changed

11 files changed

+375
-0
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { Switch } from '@patternfly/react-core';
2+
import Controlled from './examples/ControlledSwitch';
3+
import Uncontrolled from './examples/UncontrolledSwitch';
4+
import OneLabel from './examples/OneLabelSwitch';
5+
import NoLabel from './examples/NoLabelSwitch';
6+
import Disabled from './examples/DisabledSwitch';
7+
8+
export default {
9+
title: 'Switch',
10+
components: {
11+
Switch
12+
},
13+
examples: [Controlled, OneLabel, NoLabel, Uncontrolled, Disabled]
14+
};
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import React from 'react';
2+
// import styles from '@patternfly/patternfly-next/components/Switch/styles.css';
3+
// import { css } from '@patternfly/react-styles';
4+
import PropTypes from 'prop-types';
5+
6+
const propTypes = {
7+
/** id for the label. */
8+
id: PropTypes.string.isRequired,
9+
/** Additional classes added to the Switch */
10+
className: PropTypes.string,
11+
/** Text value for off label */
12+
labelOff: PropTypes.string,
13+
/** Text value for on label */
14+
labelOn: PropTypes.string,
15+
/** flag to display the switch in mode one label. */
16+
oneLabel: PropTypes.bool,
17+
/** Flag to hide labels. */
18+
noLabel: PropTypes.bool,
19+
/** Flag to show if the Switch is checked. */
20+
isChecked: PropTypes.bool,
21+
/** Flag to show if the Switch is disabled. */
22+
isDisabled: PropTypes.bool,
23+
/** A callback for when the Switch selection changes. */
24+
onChange: PropTypes.func,
25+
/** Adds accessible text to the input. */
26+
'aria-label': PropTypes.string.isRequired
27+
};
28+
29+
const defaultProps = {
30+
className: '',
31+
labelOff: 'Off',
32+
labelOn: 'On',
33+
oneLabel: false,
34+
noLabel: false,
35+
isChecked: true,
36+
isDisabled: false,
37+
onChange: (isChecked, event) => undefined,
38+
'aria-label': ''
39+
};
40+
41+
class Switch extends React.Component {
42+
handleChange = event => {
43+
this.props.onChange(event.currentTarget.checked, event);
44+
};
45+
46+
render() {
47+
const {
48+
id,
49+
className,
50+
labelOff,
51+
labelOn,
52+
oneLabel,
53+
noLabel,
54+
isChecked,
55+
isDisabled,
56+
onChange,
57+
...props
58+
} = this.props;
59+
const oneLabelText = isChecked ? labelOn : labelOff;
60+
return (
61+
<label className="pf-c-switch" htmlFor={id}>
62+
<input
63+
{...props}
64+
id={id}
65+
className="pf-c-switch__input"
66+
type="checkbox"
67+
onChange={onChange ? this.handleChange : null}
68+
checked={isChecked}
69+
disabled={isDisabled}
70+
/>
71+
{noLabel || oneLabel ? null : <span className="pf-c-switch__label pf-m-off">{labelOff}</span>}
72+
<span className="pf-c-switch__toggle" />
73+
{noLabel ? null : <span className="pf-c-switch__label pf-m-on">{oneLabel ? oneLabelText : labelOn}</span>}
74+
</label>
75+
);
76+
}
77+
}
78+
79+
Switch.propTypes = propTypes;
80+
Switch.defaultProps = defaultProps;
81+
82+
export default Switch;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import React from 'react';
2+
import { shallow } from 'enzyme';
3+
import Switch from './Switch';
4+
5+
const props = {
6+
onChange: jest.fn(),
7+
checked: false
8+
};
9+
10+
test('controlled', () => {
11+
const view = shallow(<Switch isChecked />);
12+
expect(view).toMatchSnapshot();
13+
});
14+
15+
test('oneLabel', () => {
16+
const view = shallow(<Switch oneLabel />);
17+
expect(view).toMatchSnapshot();
18+
});
19+
20+
test('noLabel', () => {
21+
const view = shallow(<Switch noLabel />);
22+
expect(view).toMatchSnapshot();
23+
});
24+
25+
test('uncontrolled', () => {
26+
const view = shallow(<Switch />);
27+
expect(view).toMatchSnapshot();
28+
});
29+
30+
test('isDisabled', () => {
31+
const view = shallow(<Switch isDisabled />);
32+
expect(view).toMatchSnapshot();
33+
});
34+
35+
test('switch passes value and event to onChange handler', () => {
36+
const newValue = true;
37+
const event = {
38+
currentTarget: { checked: newValue }
39+
};
40+
const view = shallow(<Switch {...props} />);
41+
view.find('input').simulate('change', event);
42+
expect(props.onChange).toBeCalledWith(newValue, event);
43+
});
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`controlled 1`] = `
4+
<label
5+
className="pf-c-switch"
6+
>
7+
<input
8+
aria-label=""
9+
checked={true}
10+
className="pf-c-switch__input"
11+
disabled={false}
12+
onChange={[Function]}
13+
type="checkbox"
14+
/>
15+
<span
16+
className="pf-c-switch__label pf-m-off"
17+
>
18+
Off
19+
</span>
20+
<span
21+
className="pf-c-switch__toggle"
22+
/>
23+
<span
24+
className="pf-c-switch__label pf-m-on"
25+
>
26+
On
27+
</span>
28+
</label>
29+
`;
30+
31+
exports[`isDisabled 1`] = `
32+
<label
33+
className="pf-c-switch"
34+
>
35+
<input
36+
aria-label=""
37+
checked={true}
38+
className="pf-c-switch__input"
39+
disabled={true}
40+
onChange={[Function]}
41+
type="checkbox"
42+
/>
43+
<span
44+
className="pf-c-switch__label pf-m-off"
45+
>
46+
Off
47+
</span>
48+
<span
49+
className="pf-c-switch__toggle"
50+
/>
51+
<span
52+
className="pf-c-switch__label pf-m-on"
53+
>
54+
On
55+
</span>
56+
</label>
57+
`;
58+
59+
exports[`noLabel 1`] = `
60+
<label
61+
className="pf-c-switch"
62+
>
63+
<input
64+
aria-label=""
65+
checked={true}
66+
className="pf-c-switch__input"
67+
disabled={false}
68+
onChange={[Function]}
69+
type="checkbox"
70+
/>
71+
<span
72+
className="pf-c-switch__toggle"
73+
/>
74+
</label>
75+
`;
76+
77+
exports[`oneLabel 1`] = `
78+
<label
79+
className="pf-c-switch"
80+
>
81+
<input
82+
aria-label=""
83+
checked={true}
84+
className="pf-c-switch__input"
85+
disabled={false}
86+
onChange={[Function]}
87+
type="checkbox"
88+
/>
89+
<span
90+
className="pf-c-switch__toggle"
91+
/>
92+
<span
93+
className="pf-c-switch__label pf-m-on"
94+
>
95+
On
96+
</span>
97+
</label>
98+
`;
99+
100+
exports[`uncontrolled 1`] = `
101+
<label
102+
className="pf-c-switch"
103+
>
104+
<input
105+
aria-label=""
106+
checked={true}
107+
className="pf-c-switch__input"
108+
disabled={false}
109+
onChange={[Function]}
110+
type="checkbox"
111+
/>
112+
<span
113+
className="pf-c-switch__label pf-m-off"
114+
>
115+
Off
116+
</span>
117+
<span
118+
className="pf-c-switch__toggle"
119+
/>
120+
<span
121+
className="pf-c-switch__label pf-m-on"
122+
>
123+
On
124+
</span>
125+
</label>
126+
`;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React from 'react';
2+
import { Switch } from '@patternfly/react-core';
3+
4+
class ControlledSwitch extends React.Component {
5+
static title = 'Controlled Switch';
6+
7+
state = {
8+
checked: true
9+
};
10+
11+
handleChange = checked => {
12+
this.setState({ checked });
13+
};
14+
15+
render() {
16+
return (
17+
<Switch
18+
id="controlled-switch"
19+
isChecked={this.state.checked}
20+
onChange={this.handleChange}
21+
aria-label="controlled Switch example"
22+
/>
23+
);
24+
}
25+
}
26+
27+
export default ControlledSwitch;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import React from 'react';
2+
import { Switch } from '@patternfly/react-core';
3+
4+
class DisabledSwitch extends React.Component {
5+
static title = 'Disabled Switch';
6+
render() {
7+
return (
8+
<React.Fragment>
9+
<Switch id="disabled-switch-on" aria-label="disabled checked switch example" isChecked isDisabled />
10+
<br />
11+
<Switch id="disabled-switch-off" aria-label="disabled switch example" isChecked={false} isDisabled />
12+
</React.Fragment>
13+
);
14+
}
15+
}
16+
17+
export default DisabledSwitch;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import React from 'react';
2+
import { Switch } from '@patternfly/react-core';
3+
4+
class NoLabelSwitch extends React.Component {
5+
static title = 'No Label Switch';
6+
render() {
7+
return (
8+
<React.Fragment>
9+
<Switch id="no-label-switch-on" aria-label="no label checked switch example" noLabel isChecked />
10+
<br />
11+
<Switch id="no-label-switch-off" aria-label="no label switch example" noLabel isChecked={false} />
12+
</React.Fragment>
13+
);
14+
}
15+
}
16+
17+
export default NoLabelSwitch;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import React from 'react';
2+
import { Switch } from '@patternfly/react-core';
3+
4+
class OneLabelSwitch extends React.Component {
5+
static title = 'OneLabel Switch';
6+
7+
state = {
8+
checked: true
9+
};
10+
11+
handleChange = checked => {
12+
this.setState({ checked });
13+
};
14+
15+
render() {
16+
return (
17+
<Switch
18+
id="controlled-switch"
19+
labelOff="inactive"
20+
labelOn="active"
21+
oneLabel
22+
isChecked={this.state.checked}
23+
onChange={this.handleChange}
24+
aria-label="controlled Switch example"
25+
/>
26+
);
27+
}
28+
}
29+
30+
export default OneLabelSwitch;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import React from 'react';
2+
import { Switch } from '@patternfly/react-core';
3+
4+
class UncontrolledSwitch extends React.Component {
5+
static title = 'Uncontrolled Switch';
6+
render() {
7+
return (
8+
<React.Fragment>
9+
<Switch id="uncontrolled-switch-on" aria-label="uncontrolled checked switch example" isChecked />
10+
<br />
11+
<Switch id="uncontrolled-switch-off" aria-label="uncontrolled switch example" isChecked={false} />
12+
</React.Fragment>
13+
);
14+
}
15+
}
16+
17+
export default UncontrolledSwitch;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as Switch } from './Switch';

0 commit comments

Comments
 (0)