Skip to content

Commit

Permalink
refactor: Use rc-util to mini final antd dist size (#49)
Browse files Browse the repository at this point in the history
* refactor: Use rc-util to min fianl dist size

* fix lint

* update eslint

* rm autoFocus logic
  • Loading branch information
zombieJ committed May 18, 2020
1 parent ae6e547 commit addaf3d
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 116 deletions.
2 changes: 2 additions & 0 deletions .eslintrc.js
Expand Up @@ -8,5 +8,7 @@ module.exports = {
'prefer-promise-reject-errors': 0,
'react/no-array-index-key': 0,
'react/sort-comp': 0,
'import/no-named-as-default': 0,
'import/no-named-as-default-member': 0,
},
};
2 changes: 1 addition & 1 deletion examples/simple.js
@@ -1,6 +1,6 @@
import '../assets/index.less';
import React from 'react';
import Switch from '../src/index';
import Switch from '../src';

function onChange(value, event) {
// eslint-disable-next-line no-console
Expand Down
5 changes: 4 additions & 1 deletion package.json
Expand Up @@ -35,6 +35,8 @@
"coverage": "father test --coverage"
},
"devDependencies": {
"@types/classnames": "^2.2.10",
"@types/jest": "^25.2.2",
"coveralls": "^3.0.6",
"enzyme": "^3.0.0",
"enzyme-adapter-react-16": "^1.0.1",
Expand All @@ -52,6 +54,7 @@
"react-dom": "^16.0.0"
},
"dependencies": {
"classnames": "^2.2.1"
"classnames": "^2.2.1",
"rc-util": "^4.20.5"
}
}
187 changes: 81 additions & 106 deletions src/index.tsx
@@ -1,136 +1,111 @@
import * as React from 'react';
import classNames from 'classnames';
import useMergedState from 'rc-util/lib/hooks/useMergedState';
import KeyCode from 'rc-util/lib/KeyCode';

export type SwitchChangeEventHandler = (checked: boolean, event: MouseEvent) => void;
export type SwitchChangeEventHandler = (
checked: boolean,
event: React.MouseEvent<HTMLButtonElement> | React.KeyboardEvent<HTMLButtonElement>,
) => void;
export type SwitchClickEventHandler = SwitchChangeEventHandler;

interface SwitchProps {
interface SwitchProps
extends Omit<React.HTMLAttributes<HTMLButtonElement>, 'onChange' | 'onClick'> {
className?: string;
prefixCls?: string;
disabled?: boolean;
checkedChildren?: React.ReactNode;
unCheckedChildren?: React.ReactNode;
onChange?: SwitchChangeEventHandler;
onMouseUp: React.MouseEventHandler<HTMLButtonElement>;
onKeyDown?: React.KeyboardEventHandler<HTMLButtonElement>;
onClick?: SwitchClickEventHandler;
tabIndex?: number;
checked?: boolean;
defaultChecked?: boolean;
autoFocus?: boolean;
loadingIcon: React.ReactNode;
style?: React.CSSProperties;
title?: string;
}

const Switch = React.forwardRef<HTMLButtonElement, SwitchProps>((props, ref) => {
const mergedRef = (ref as any) || React.createRef<HTMLButtonElement>();

let initChecked = false;
if ('checked' in props) {
initChecked = !!props.checked;
} else {
initChecked = !!props.defaultChecked;
}
const [checked, setChecked] = React.useState(initChecked);

React.useEffect(() => {
const { autoFocus, disabled } = props;
if (autoFocus && !disabled) {
(mergedRef.current as any).focus();
const Switch = React.forwardRef<HTMLButtonElement, SwitchProps>(
(
{
prefixCls = 'rc-switch',
className,
checked,
defaultChecked,
disabled,
loadingIcon,
checkedChildren,
unCheckedChildren,
onClick,
onChange,
onKeyDown,
...restProps
},
ref,
) => {
const [innerChecked, setInnerChecked] = useMergedState<boolean>(false, {
value: checked,
defaultValue: defaultChecked,
});

function triggerChange(
newChecked: boolean,
event: React.MouseEvent<HTMLButtonElement> | React.KeyboardEvent<HTMLButtonElement>,
) {
let mergedChecked = innerChecked;

if (!disabled) {
mergedChecked = newChecked;
setInnerChecked(mergedChecked);
onChange?.(mergedChecked, event);
}

return mergedChecked;
}
}, [props.autoFocus]);

React.useEffect(() => {
if ('checked' in props) {
setChecked(!!props.checked);
function onInternalKeyDown(e: React.KeyboardEvent<HTMLButtonElement>) {
if (e.which === KeyCode.LEFT) {
triggerChange(false, e);
} else if (e.which === KeyCode.RIGHT) {
triggerChange(true, e);
}
onKeyDown?.(e);
}
}, [props.checked]);

const setInternalChecked = (checked, e) => {
const { disabled, onChange } = props;
if (disabled) {
return;
}
if (!('checked' in props)) {
setChecked(checked);
}
if (onChange) {
onChange(checked, e);
function onInternalClick(e: React.MouseEvent<HTMLButtonElement>) {
const ret = triggerChange(!innerChecked, e);
// [Legacy] trigger onClick with value
onClick?.(ret, e);
}
};

const handleClick = e => {
const { onClick } = props;
const newChecked = !checked;
setInternalChecked(newChecked, e);
if (onClick) {
onClick(newChecked, e);
}
};

const handleKeyDown = e => {
if (e.keyCode === 37) {
// Left
setInternalChecked(false, e);
} else if (e.keyCode === 39) {
// Right
setInternalChecked(true, e);
}
};

// Handle auto focus when click switch in Chrome
const handleMouseUp = e => {
(mergedRef.current as any).blur();
if (props.onMouseUp) {
props.onMouseUp(e);
}
};

const {
className,
prefixCls,
disabled,
loadingIcon,
checkedChildren,
unCheckedChildren,
onChange,
...restProps
} = props;

const switchClassName = classNames({
[className]: !!className,
[prefixCls]: true,
[`${prefixCls}-checked`]: checked,
[`${prefixCls}-disabled`]: disabled,
});

return (
<button
{...restProps}
type="button"
role="switch"
aria-checked={checked}
disabled={disabled}
className={switchClassName}
ref={mergedRef}
onKeyDown={handleKeyDown}
onClick={handleClick}
onMouseUp={handleMouseUp}
>
{loadingIcon}
<span className={`${prefixCls}-inner`}>{checked ? checkedChildren : unCheckedChildren}</span>
</button>
);
});
const switchClassName = classNames(prefixCls, className, {
[`${prefixCls}-checked`]: innerChecked,
[`${prefixCls}-disabled`]: disabled,
});

return (
<button
{...restProps}
type="button"
role="switch"
aria-checked={innerChecked}
disabled={disabled}
className={switchClassName}
ref={ref}
onKeyDown={onInternalKeyDown}
onClick={onInternalClick}
>
{loadingIcon}
<span className={`${prefixCls}-inner`}>
{innerChecked ? checkedChildren : unCheckedChildren}
</span>
</button>
);
},
);

Switch.displayName = 'Switch';

Switch.defaultProps = {
prefixCls: 'rc-switch',
checkedChildren: null,
unCheckedChildren: null,
className: '',
defaultChecked: false,
};

export default Switch;
36 changes: 28 additions & 8 deletions tests/index.spec.js
@@ -1,4 +1,5 @@
import React from 'react';
import KeyCode from 'rc-util/lib/KeyCode';
// eslint-disable-next-line import/no-extraneous-dependencies
import { mount } from 'enzyme';
import Switch from '../index';
Expand All @@ -24,9 +25,9 @@ describe('rc-switch', () => {
it('should be checked upon right key and unchecked on left key', () => {
const wrapper = createSwitch();
expect(wrapper.exists('.unchecked')).toBeTruthy();
wrapper.simulate('keydown', { keyCode: 39 });
wrapper.simulate('keydown', { which: KeyCode.RIGHT });
expect(wrapper.exists('.checked')).toBeTruthy();
wrapper.simulate('keydown', { keyCode: 37 });
wrapper.simulate('keydown', { which: KeyCode.LEFT });
expect(wrapper.exists('.unchecked')).toBeTruthy();
});

Expand Down Expand Up @@ -89,12 +90,22 @@ describe('rc-switch', () => {
expect(handleBlur).toHaveBeenCalled();
});

it('autoFocus', () => {
const container = document.createElement('div');
document.body.appendChild(container);
const handleFocus = jest.fn();
mount(<Switch autoFocus onFocus={handleFocus} />, { attachTo: container });
expect(handleFocus).toHaveBeenCalled();
describe('autoFocus', () => {
it('basic', () => {
const container = document.createElement('div');
document.body.appendChild(container);
const handleFocus = jest.fn();
mount(<Switch autoFocus onFocus={handleFocus} />, { attachTo: container });
expect(handleFocus).toHaveBeenCalled();
});

it('not work when disabled', () => {
const container = document.createElement('div');
document.body.appendChild(container);
const handleFocus = jest.fn();
mount(<Switch autoFocus disabled onFocus={handleFocus} />, { attachTo: container });
expect(handleFocus).not.toHaveBeenCalled();
});
});

it('disabled', () => {
Expand All @@ -110,4 +121,13 @@ describe('rc-switch', () => {
wrapper.simulate('mouseup');
expect(onMouseUp).toHaveBeenCalled();
});

it('disabled should click not to change', () => {
const onChange = jest.fn();
const onClick = jest.fn();
const wrapper = createSwitch({ disabled: true, onChange, onClick, checked: true });

wrapper.simulate('click');
expect(onChange).not.toHaveBeenCalled();
});
});

0 comments on commit addaf3d

Please sign in to comment.