Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions packages/patternfly-4/react-core/src/components/Switch/Switch.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { HTMLProps, FormEvent, ReactNode } from 'react';
import { Omit } from '../../typeUtils';

export interface SwitchProps extends Omit<HTMLProps<HTMLInputElement>, 'type' | 'onChange' | 'disabled' | 'label'> {
isDisabled?: boolean;
isChecked?: boolean;
onChange?(checked: boolean, event: FormEvent<HTMLInputElement>): void;
id?: string;
'aria-label': string;
label?: string;
className?: string;
}

declare const Switch: React.SFC<SwitchProps>;

export default Switch;
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Switch } from '@patternfly/react-core';
import SimpleSwitch from './examples/SimpleSwitch';
import NoLabelSwitch from './examples/NoLabelSwitch';
import DisabledSwitch from './examples/DisabledSwitch';
import UncontrolledSwitch from './examples/UncontrolledSwitch';

export default {
title: 'Switch',
components: {
Switch
},
examples: [
{ component: SimpleSwitch, title: 'Simple Switch' },
{ component: NoLabelSwitch, title: 'Switch with no labels' },
{ component: DisabledSwitch, title: 'Disabled Switch' },
{ component: UncontrolledSwitch, title: 'Uncontrolled Switch' }
]
};
68 changes: 68 additions & 0 deletions packages/patternfly-4/react-core/src/components/Switch/Switch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import React from 'react';
import styles from '@patternfly/patternfly-next/components/Switch/switch.css';
import { css } from '@patternfly/react-styles';
import PropTypes from 'prop-types';
import { getUniqueId } from '../../internal/util';

const propTypes = {
/** id for the label. */
id: PropTypes.string,
/** Additional classes added to the Switch */
className: PropTypes.string,
/** Text value for the label */
label: PropTypes.string,
/** Flag to show if the Switch is checked. */
isChecked: PropTypes.bool,
/** Flag to show if the Switch is disabled. */
isDisabled: PropTypes.bool,
/** A callback for when the Switch selection changes. (isChecked, event) => {} */
onChange: PropTypes.func,
/** Adds accessible text to the Switch. */
'aria-label': props => {
if (!props.id && !props['aria-label']) {
return new Error('Switch requires either an id or aria-label to be specified');
}
}
};

const defaultProps = {
id: '',
className: '',
label: '',
isChecked: true,
isDisabled: false,
onChange: () => undefined,
'aria-label': ''
};

class Switch extends React.Component {
id = this.props.id || getUniqueId();

render() {
const { id, className, label, isChecked, isDisabled, onChange, ...props } = this.props;
return (
<label className={css(styles.switch, className)} htmlFor={this.id}>
<input
{...props}
id={this.id}
className={css(styles.switchInput)}
type="checkbox"
onChange={event => onChange(event.currentTarget.checked, event)}
checked={isChecked}
disabled={isDisabled}
/>
<span className={css(styles.switchToggle)} />
{label && (
<span className={css(styles.switchLabel)} aria-hidden="true">
{label}
</span>
)}
</label>
);
}
}

Switch.propTypes = propTypes;
Switch.defaultProps = defaultProps;

export default Switch;
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React from 'react';
import { shallow } from 'enzyme';
import Switch from './Switch';

const props = {
onChange: jest.fn(),
checked: false
};

test('switch label for attribute equals input id attribute', () => {
const view = shallow(<Switch id="foo" />);
expect(view.find('input').prop('id')).toBe('foo');
expect(view.find('label').prop('htmlFor')).toBe('foo');
});

test('switch label id is auto generated', () => {
const view = shallow(<Switch aria-label="..." />);
expect(view.find('input').prop('id')).toBeDefined();
});

test('switch is checked', () => {
const view = shallow(<Switch id="switch-is-checked" label="On" isChecked />);
expect(view).toMatchSnapshot();
});

test('switch is not checked', () => {
const view = shallow(<Switch id="switch-is-not-checked" label="Off" isChecked={false} />);
expect(view).toMatchSnapshot();
});

test('no label switch is checked', () => {
const view = shallow(<Switch id="no-label-switch-is-checked" isChecked />);
expect(view).toMatchSnapshot();
});

test('no label switch is not checked', () => {
const view = shallow(<Switch id="no-label-switch-is-not-checked" isChecked={false} />);
expect(view).toMatchSnapshot();
});

test('switch is checked and disabled', () => {
const view = shallow(<Switch id="switch-is-checked-and-disabled" isChecked isDisabled />);
expect(view).toMatchSnapshot();
});

test('switch is not checked and disabled', () => {
const view = shallow(<Switch id="switch-is-not-checked-and-disabled" isChecked={false} isDisabled />);
expect(view).toMatchSnapshot();
});

test('switch passes value and event to onChange handler', () => {
const newValue = true;
const event = {
currentTarget: { checked: newValue }
};
const view = shallow(<Switch id="onChange-switch" {...props} />);
view.find('input').simulate('change', event);
expect(props.onChange).toBeCalledWith(newValue, event);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`no label switch is checked 1`] = `
.pf-c-switch__input {
display: block;
}
.pf-c-switch__toggle {
display: block;
}
.pf-c-switch {
display: inline-block;
position: relative;
line-height: 1.5;
vertical-align: middle;
cursor: pointer;
}

<label
className="pf-c-switch"
htmlFor="no-label-switch-is-checked"
>
<input
aria-label=""
checked={true}
className="pf-c-switch__input"
disabled={false}
id="no-label-switch-is-checked"
onChange={[Function]}
type="checkbox"
/>
<span
className="pf-c-switch__toggle"
/>
</label>
`;

exports[`no label switch is not checked 1`] = `
.pf-c-switch__input {
display: block;
}
.pf-c-switch__toggle {
display: block;
}
.pf-c-switch {
display: inline-block;
position: relative;
line-height: 1.5;
vertical-align: middle;
cursor: pointer;
}

<label
className="pf-c-switch"
htmlFor="no-label-switch-is-not-checked"
>
<input
aria-label=""
checked={false}
className="pf-c-switch__input"
disabled={false}
id="no-label-switch-is-not-checked"
onChange={[Function]}
type="checkbox"
/>
<span
className="pf-c-switch__toggle"
/>
</label>
`;

exports[`switch is checked 1`] = `
.pf-c-switch__input {
display: block;
}
.pf-c-switch__toggle {
display: block;
}
.pf-c-switch__label {
display: block;
}
.pf-c-switch {
display: inline-block;
position: relative;
line-height: 1.5;
vertical-align: middle;
cursor: pointer;
}

<label
className="pf-c-switch"
htmlFor="switch-is-checked"
>
<input
aria-label=""
checked={true}
className="pf-c-switch__input"
disabled={false}
id="switch-is-checked"
onChange={[Function]}
type="checkbox"
/>
<span
className="pf-c-switch__toggle"
/>
<span
aria-hidden="true"
className="pf-c-switch__label"
>
On
</span>
</label>
`;

exports[`switch is checked and disabled 1`] = `
.pf-c-switch__input {
display: block;
}
.pf-c-switch__toggle {
display: block;
}
.pf-c-switch {
display: inline-block;
position: relative;
line-height: 1.5;
vertical-align: middle;
cursor: pointer;
}

<label
className="pf-c-switch"
htmlFor="switch-is-checked-and-disabled"
>
<input
aria-label=""
checked={true}
className="pf-c-switch__input"
disabled={true}
id="switch-is-checked-and-disabled"
onChange={[Function]}
type="checkbox"
/>
<span
className="pf-c-switch__toggle"
/>
</label>
`;

exports[`switch is not checked 1`] = `
.pf-c-switch__input {
display: block;
}
.pf-c-switch__toggle {
display: block;
}
.pf-c-switch__label {
display: block;
}
.pf-c-switch {
display: inline-block;
position: relative;
line-height: 1.5;
vertical-align: middle;
cursor: pointer;
}

<label
className="pf-c-switch"
htmlFor="switch-is-not-checked"
>
<input
aria-label=""
checked={false}
className="pf-c-switch__input"
disabled={false}
id="switch-is-not-checked"
onChange={[Function]}
type="checkbox"
/>
<span
className="pf-c-switch__toggle"
/>
<span
aria-hidden="true"
className="pf-c-switch__label"
>
Off
</span>
</label>
`;

exports[`switch is not checked and disabled 1`] = `
.pf-c-switch__input {
display: block;
}
.pf-c-switch__toggle {
display: block;
}
.pf-c-switch {
display: inline-block;
position: relative;
line-height: 1.5;
vertical-align: middle;
cursor: pointer;
}

<label
className="pf-c-switch"
htmlFor="switch-is-not-checked-and-disabled"
>
<input
aria-label=""
checked={false}
className="pf-c-switch__input"
disabled={true}
id="switch-is-not-checked-and-disabled"
onChange={[Function]}
type="checkbox"
/>
<span
className="pf-c-switch__toggle"
/>
</label>
`;
Loading