diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 0000000..82a9a73
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1 @@
+.eslintrc.js
\ No newline at end of file
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..f307fb1
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,8 @@
+{
+ "endOfLine": "lf",
+ "semi": true,
+ "singleQuote": true,
+ "tabWidth": 2,
+ "trailingComma": "all",
+ "printWidth": 100
+}
diff --git a/examples/simple.js b/examples/simple.js
index 7b944b2..e7c87dc 100644
--- a/examples/simple.js
+++ b/examples/simple.js
@@ -25,7 +25,6 @@ export default class Simple extends React.Component {
void;
@@ -11,7 +11,7 @@ interface SwitchProps {
checkedChildren?: React.ReactNode;
unCheckedChildren?: React.ReactNode;
onChange?: SwitchChangeEventHandler;
- onMouseUp: MouseEventHandler;
+ onMouseUp: React.MouseEventHandler;
onClick?: SwitchClickEventHandler;
tabIndex?: number;
checked?: boolean;
@@ -22,143 +22,115 @@ interface SwitchProps {
title?: string;
}
-interface SwitchState {
- checked: boolean;
-}
-
-class Switch extends Component {
- private node: React.RefObject;
+const Switch = React.forwardRef((props, ref) => {
+ const mergedRef = (ref as any) || React.createRef();
- static defaultProps = {
- prefixCls: 'rc-switch',
- checkedChildren: null,
- unCheckedChildren: null,
- className: '',
- defaultChecked: false,
- };
-
- constructor(props) {
- super(props);
- let checked = false;
- if ('checked' in props) {
- checked = !!props.checked;
- } else {
- checked = !!props.defaultChecked;
- }
- this.state = { checked };
- this.node = React.createRef();
+ let initChecked = false;
+ if ('checked' in props) {
+ initChecked = !!props.checked;
+ } else {
+ initChecked = !!props.defaultChecked;
}
+ const [checked, setChecked] = React.useState(initChecked);
- componentDidMount() {
- const { autoFocus, disabled } = this.props;
+ React.useEffect(() => {
+ const { autoFocus, disabled } = props;
if (autoFocus && !disabled) {
- this.focus();
+ focus();
}
- }
+ }, [props.autoFocus, props.disabled]);
- static getDerivedStateFromProps(nextProps) {
- const { checked } = nextProps;
- const newState: Partial = {};
- if ('checked' in nextProps) {
- newState.checked = !!checked;
+ React.useEffect(() => {
+ if ('checked' in props) {
+ setChecked(!!props.checked);
}
- return newState;
- }
+ }, [props.checked]);
- setChecked(checked, e) {
- const { disabled, onChange } = this.props;
+ const setInternalChecked = (checked, e) => {
+ const { disabled, onChange } = props;
if (disabled) {
return;
}
- if (!('checked' in this.props)) {
- this.setState({
- checked,
- });
+ if (!('checked' in props)) {
+ setChecked(checked);
}
if (onChange) {
onChange(checked, e);
}
- }
+ };
- handleClick = e => {
- const { checked } = this.state;
- const { onClick } = this.props;
+ const handleClick = e => {
+ const { onClick } = props;
const newChecked = !checked;
- this.setChecked(newChecked, e);
+ setInternalChecked(newChecked, e);
if (onClick) {
onClick(newChecked, e);
}
};
- handleKeyDown = e => {
+ const handleKeyDown = e => {
if (e.keyCode === 37) {
// Left
- this.setChecked(false, e);
+ setInternalChecked(false, e);
} else if (e.keyCode === 39) {
// Right
- this.setChecked(true, e);
+ setInternalChecked(true, e);
}
};
// Handle auto focus when click switch in Chrome
- handleMouseUp = e => {
- const { onMouseUp } = this.props;
- this.blur();
- if (onMouseUp) {
- onMouseUp(e);
+ const handleMouseUp = e => {
+ (mergedRef.current as any).blur();
+ if (props.onMouseUp) {
+ props.onMouseUp(e);
}
};
- focus() {
- if (this.node.current) {
- this.node.current.focus();
- }
- }
-
- blur() {
- if (this.node.current) {
- this.node.current.blur();
- }
- }
-
- render() {
- const {
- className,
- prefixCls,
- disabled,
- loadingIcon,
- checkedChildren,
- unCheckedChildren,
- onChange,
- ...restProps
- } = this.props;
- const { checked } = this.state;
- const switchClassName = classNames({
- [className]: !!className,
- [prefixCls]: true,
- [`${prefixCls}-checked`]: checked,
- [`${prefixCls}-disabled`]: disabled,
- });
- return (
-
- );
- }
-}
+ const {
+ className,
+ prefixCls,
+ disabled,
+ loadingIcon,
+ checkedChildren,
+ unCheckedChildren,
+ onChange,
+ ...restProps
+ } = props;
+
+ const switchClassName = classNames({
+ [className]: !!className,
+ [prefixCls]: true,
+ [`${prefixCls}-checked`]: checked,
+ [`${prefixCls}-disabled`]: disabled,
+ });
+
+ return (
+
+ );
+});
+
+Switch.displayName = 'Switch';
+
+Switch.defaultProps = {
+ prefixCls: 'rc-switch',
+ checkedChildren: null,
+ unCheckedChildren: null,
+ className: '',
+ defaultChecked: false,
+};
export default Switch;
diff --git a/tests/index.spec.js b/tests/index.spec.js
index 575aaa7..c88692d 100644
--- a/tests/index.spec.js
+++ b/tests/index.spec.js
@@ -4,35 +4,44 @@ import { mount } from 'enzyme';
import Switch from '../index';
describe('rc-switch', () => {
- let switcher;
- beforeEach(() => {
- switcher = mount();
- });
+ function createSwitch(props = {}) {
+ return mount(
+ }
+ unCheckedChildren={}
+ {...props}
+ />,
+ );
+ }
it('works', () => {
- expect(switcher.state().checked).toBe(false);
- switcher.simulate('click');
- expect(switcher.state().checked).toBe(true);
+ const wrapper = createSwitch();
+ expect(wrapper.exists('.unchecked')).toBeTruthy();
+ wrapper.simulate('click');
+ expect(wrapper.exists('.checked')).toBeTruthy();
});
it('should be checked upon right key and unchecked on left key', () => {
- expect(switcher.state().checked).toBe(false);
- switcher.simulate('keydown', { keyCode: 39 });
- expect(switcher.state().checked).toBe(true);
- switcher.simulate('keydown', { keyCode: 37 });
- expect(switcher.state().checked).toBe(false);
+ const wrapper = createSwitch();
+ expect(wrapper.exists('.unchecked')).toBeTruthy();
+ wrapper.simulate('keydown', { keyCode: 39 });
+ expect(wrapper.exists('.checked')).toBeTruthy();
+ wrapper.simulate('keydown', { keyCode: 37 });
+ expect(wrapper.exists('.unchecked')).toBeTruthy();
});
it('should change from an initial checked state of true to false on click', () => {
- const wrapper = mount();
- expect(wrapper.state().checked).toBe(true);
+ const onChange = jest.fn();
+ const wrapper = createSwitch({ defaultChecked: true, onChange });
+ expect(wrapper.exists('.checked')).toBeTruthy();
wrapper.simulate('click');
- expect(wrapper.state().checked).toBe(false);
+ expect(wrapper.exists('.unchecked')).toBeTruthy();
+ expect(onChange.mock.calls.length).toBe(1);
});
it('should support onClick', () => {
const onClick = jest.fn();
- const wrapper = mount();
+ const wrapper = createSwitch({ onClick });
wrapper.simulate('click');
expect(onClick).toHaveBeenCalledWith(true, expect.objectContaining({ type: 'click' }));
expect(onClick.mock.calls.length).toBe(1);
@@ -43,10 +52,10 @@ describe('rc-switch', () => {
it('should not toggle when clicked in a disabled state', () => {
const onChange = jest.fn();
- const wrapper = mount();
- expect(wrapper.state().checked).toBe(true);
+ const wrapper = createSwitch({ disabled: true, checked: true, onChange });
+ expect(wrapper.exists('.checked')).toBeTruthy();
wrapper.simulate('click');
- expect(wrapper.state().checked).toBe(true);
+ expect(wrapper.exists('.checked')).toBeTruthy();
expect(onChange.mock.calls.length).toBe(0);
});
@@ -59,8 +68,11 @@ describe('rc-switch', () => {
const container = document.createElement('div');
document.body.appendChild(container);
const handleFocus = jest.fn();
- const wrapper = mount(, { attachTo: container });
- wrapper.instance().focus();
+ const ref = React.createRef();
+ mount(, {
+ attachTo: container,
+ });
+ ref.current.focus();
expect(handleFocus).toHaveBeenCalled();
});
@@ -68,9 +80,12 @@ describe('rc-switch', () => {
const container = document.createElement('div');
document.body.appendChild(container);
const handleBlur = jest.fn();
- const wrapper = mount(, { attachTo: container });
- wrapper.instance().focus();
- wrapper.instance().blur();
+ const ref = React.createRef();
+ mount(, {
+ attachTo: container,
+ });
+ ref.current.focus();
+ ref.current.blur();
expect(handleBlur).toHaveBeenCalled();
});
@@ -81,4 +96,18 @@ describe('rc-switch', () => {
mount(, { attachTo: container });
expect(handleFocus).toHaveBeenCalled();
});
+
+ it('disabled', () => {
+ const wrapper = createSwitch({ disabled: true });
+ expect(wrapper.exists('.unchecked')).toBeTruthy();
+ wrapper.simulate('keydown', { keyCode: 39 });
+ expect(wrapper.exists('.unchecked')).toBeTruthy();
+ });
+
+ it('onMouseUp', () => {
+ const onMouseUp = jest.fn();
+ const wrapper = createSwitch({ onMouseUp });
+ wrapper.simulate('mouseup');
+ expect(onMouseUp).toHaveBeenCalled();
+ });
});