Skip to content
This repository has been archived by the owner on Jan 14, 2025. It is now read-only.

Commit

Permalink
feat(switch): upgrade to mdc-web v1 (#757)
Browse files Browse the repository at this point in the history
  • Loading branch information
gugu authored and Matt Goo committed Mar 26, 2019
1 parent 9e84ee2 commit f69db2e
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 43 deletions.
85 changes: 64 additions & 21 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
"@material/ripple": "^1.0.0",
"@material/select": "^0.40.1",
"@material/snackbar": "^1.0.0",
"@material/switch": "^0.41.0",
"@material/switch": "^1.0.0",
"@material/tab": "^1.0.0",
"@material/tab-bar": "^1.0.0",
"@material/tab-indicator": "^1.0.0",
Expand Down
18 changes: 9 additions & 9 deletions packages/switch/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@

import * as React from 'react';
import classnames from 'classnames';
// @ts-ignore no .d.ts file
import {MDCSwitchFoundation} from '@material/switch/dist/mdc.switch';
import {MDCSwitchAdapter} from '@material/switch/adapter';
import {MDCSwitchFoundation} from '@material/switch/foundation';
import ThumbUnderlay from './ThumbUnderlay';
import NativeControl from './NativeControl';

Expand All @@ -44,7 +44,7 @@ interface SwitchState {

export default class Switch extends React.Component<SwitchProps, SwitchState> {
rippleActivator: React.RefObject<HTMLInputElement> = React.createRef();
foundation?: MDCSwitchFoundation;
foundation!: MDCSwitchFoundation;

constructor(props: SwitchProps) {
super(props);
Expand All @@ -66,16 +66,16 @@ export default class Switch extends React.Component<SwitchProps, SwitchState> {
componentDidMount() {
this.foundation = new MDCSwitchFoundation(this.adapter);
this.foundation.init();
this.foundation.setChecked(this.props.checked);
this.foundation.setDisabled(this.props.disabled);
this.foundation.setChecked(this.props.checked!);
this.foundation.setDisabled(this.props.disabled!);
}

componentDidUpdate(prevProps: SwitchProps) {
if (this.props.checked !== prevProps.checked) {
this.foundation.setChecked(this.props.checked);
this.foundation.setChecked(this.props.checked!);
}
if (this.props.disabled !== prevProps.disabled) {
this.foundation.setDisabled(this.props.disabled);
this.foundation.setDisabled(this.props.disabled!);
}
}

Expand All @@ -89,7 +89,7 @@ export default class Switch extends React.Component<SwitchProps, SwitchState> {
return classnames('mdc-switch', Array.from(classList), className);
}

get adapter() {
get adapter(): MDCSwitchAdapter {
return {
addClass: (className: string) => {
const {classList} = this.state;
Expand All @@ -112,7 +112,7 @@ export default class Switch extends React.Component<SwitchProps, SwitchState> {

onChange = (evt: React.ChangeEvent<HTMLInputElement>) => {
this.setState({nativeControlChecked: evt.target.checked});
this.foundation && this.foundation.handleChange(evt);
this.foundation && this.foundation.handleChange(evt.nativeEvent);
};

render() {
Expand Down
2 changes: 1 addition & 1 deletion packages/switch/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
},
"dependencies": {
"@material/react-ripple": "^0.11.0",
"@material/switch": "^0.41.0",
"@material/switch": "^1.0.0",
"classnames": "^2.2.6",
"react": "^16.3.2"
},
Expand Down
33 changes: 22 additions & 11 deletions test/unit/switch/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@ import {assert} from 'chai';
import {shallow, mount} from 'enzyme';
import * as td from 'testdouble';
import Switch from '../../../packages/switch/index';
import {coerceForTesting} from '../helpers/types';

suite('Switch');

const getAdapter = (instance: Switch) => {
// @ts-ignore
return instance.foundation.adapter_;
};

test('creates foundation', () => {
const wrapper = shallow<Switch>(<Switch />);
assert.exists(wrapper.instance().foundation);
Expand Down Expand Up @@ -47,42 +53,42 @@ test('has checked class when props.checked is true', () => {

test('#foundation.setChecked gets called when prop.checked updates', () => {
const wrapper = shallow<Switch>(<Switch />);
wrapper.instance().foundation.setChecked = td.func();
wrapper.instance().foundation.setChecked = td.func<(setChecked: boolean) => null>();
wrapper.setProps({checked: true});
td.verify(wrapper.instance().foundation.setChecked(true), {times: 1});
});

test('#foundation.setDisabled gets called when prop.disabled updates', () => {
const wrapper = shallow<Switch>(<Switch />);
wrapper.instance().foundation.setDisabled = td.func();
wrapper.instance().foundation.setDisabled = td.func<(disabled: boolean) => null>();
wrapper.setProps({disabled: true});
td.verify(wrapper.instance().foundation.setDisabled(true), {times: 1});
});

test('#componentWillUnmount destroys foundation', () => {
const wrapper = shallow<Switch>(<Switch />);
const foundation = wrapper.instance().foundation;
foundation.destroy = td.func();
foundation.destroy = td.func<() => null>();
wrapper.unmount();
td.verify(foundation.destroy(), {times: 1});
});

test('#adapter.addClass adds class to state.classList', () => {
const wrapper = shallow<Switch>(<Switch />);
wrapper.instance().foundation.adapter_.addClass('test-class-name');
getAdapter(wrapper.instance()).addClass('test-class-name');
assert.isTrue(wrapper.state().classList.has('test-class-name'));
});

test('#adapter.removeClass removes class from state.classList', () => {
const wrapper = shallow<Switch>(<Switch />);
wrapper.setState({classList: new Set(['test-class-name'])});
wrapper.instance().foundation.adapter_.removeClass('test-class-name');
getAdapter(wrapper.instance()).removeClass('test-class-name');
assert.isFalse(wrapper.state().classList.has('test-class-name'));
});

test('#adapter.setNativeControlChecked updates state.nativeControlChecked', () => {
const wrapper = shallow<Switch>(<Switch />);
wrapper.instance().foundation.adapter_.setNativeControlChecked(true);
getAdapter(wrapper.instance()).setNativeControlChecked(true);
assert.isTrue(wrapper.state().nativeControlChecked);
});

Expand All @@ -94,7 +100,7 @@ test('#state.nativeControlChecked updates NativeControl', () => {

test('#adapter.setNativeControlDisabled updates state.nativeControlDisabled', () => {
const wrapper = shallow<Switch>(<Switch />);
wrapper.instance().foundation.adapter_.setNativeControlDisabled(true);
getAdapter(wrapper.instance()).setNativeControlDisabled(true);
assert.isTrue(wrapper.state().nativeControlDisabled);
});

Expand All @@ -116,12 +122,17 @@ test('calls foundation.handleChange in NativeControl props.onChange', () => {
const onChange = td.func() as React.ChangeEventHandler<HTMLInputElement>;
const wrapper = mount<Switch>(<Switch onChange={onChange} />);
const nativeControl = wrapper.find('.mdc-switch__native-control');
const mockEvt = {
const mockEvt = coerceForTesting<React.ChangeEvent<HTMLInputElement>>({
target: {
checked: true,
},
} as React.ChangeEvent<HTMLInputElement>;
wrapper.instance().foundation.handleChange = td.func();
nativeEvent: {
target: {
checked: true,
},
},
});
wrapper.instance().foundation.handleChange = td.func<(evt: Event) => null>();
nativeControl.props().onChange!(mockEvt);
td.verify(wrapper.instance().foundation.handleChange(mockEvt), {times: 1});
td.verify(wrapper.instance().foundation.handleChange(mockEvt.nativeEvent), {times: 1});
});

0 comments on commit f69db2e

Please sign in to comment.