Skip to content
This repository was archived by the owner on Sep 14, 2021. It is now read-only.

Commit f8e3e2b

Browse files
committed
fix(checkbox): upgrade mdc-web to v1 (material-components#769)
1 parent 2b63a8b commit f8e3e2b

File tree

5 files changed

+114
-54
lines changed

5 files changed

+114
-54
lines changed

package-lock.json

Lines changed: 52 additions & 20 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
"@material/base": "^1.0.0",
6565
"@material/button": "^0.43.0",
6666
"@material/card": "^0.41.0",
67-
"@material/checkbox": "^0.41.0",
67+
"@material/checkbox": "^1.0.0",
6868
"@material/chips": "^1.0.0",
6969
"@material/dialog": "^1.0.0",
7070
"@material/dom": "^0.41.0",

packages/checkbox/index.tsx

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@
2222

2323
import * as React from 'react';
2424
import classnames from 'classnames';
25-
// @ts-ignore no mdc .d.ts file
26-
import {MDCCheckboxFoundation, MDCCheckboxAdapter} from '@material/checkbox/dist/mdc.checkbox';
25+
import {MDCCheckboxFoundation} from '@material/checkbox/foundation';
26+
import {MDCCheckboxAdapter} from '@material/checkbox/adapter';
27+
import {cssClasses} from '@material/checkbox/constants';
2728
import * as Ripple from '@material/react-ripple';
2829

2930
import NativeControl from './NativeControl';
@@ -45,20 +46,22 @@ interface CheckboxState {
4546
checked?: boolean;
4647
indeterminate?: boolean;
4748
classList: Set<string>;
48-
'aria-checked': boolean;
49+
'aria-checked': string;
50+
disabled: boolean;
4951
};
5052

5153
export class Checkbox extends React.Component<CheckboxProps, CheckboxState> {
5254
inputElement: React.RefObject<HTMLInputElement> = React.createRef();
53-
foundation = MDCCheckboxFoundation;
55+
foundation!: MDCCheckboxFoundation;
5456

5557
constructor(props: CheckboxProps) {
5658
super(props);
5759
this.state = {
5860
'checked': props.checked,
5961
'indeterminate': props.indeterminate,
6062
'classList': new Set(),
61-
'aria-checked': false,
63+
'aria-checked': 'false',
64+
'disabled': props.disabled!,
6265
};
6366
}
6467

@@ -74,7 +77,7 @@ export class Checkbox extends React.Component<CheckboxProps, CheckboxState> {
7477
componentDidMount() {
7578
this.foundation = new MDCCheckboxFoundation(this.adapter);
7679
this.foundation.init();
77-
this.foundation.setDisabled(this.props.disabled);
80+
this.foundation.setDisabled(this.props.disabled!);
7881
// indeterminate property on checkboxes is not supported:
7982
// https://github.com/facebook/react/issues/1798#issuecomment-333414857
8083
if (this.inputElement.current) {
@@ -91,7 +94,7 @@ export class Checkbox extends React.Component<CheckboxProps, CheckboxState> {
9194
this.handleChange(checked!, indeterminate!);
9295
}
9396
if (disabled !== prevProps.disabled) {
94-
this.foundation.setDisabled(disabled);
97+
this.foundation.setDisabled(disabled!);
9598
}
9699
}
97100

@@ -118,7 +121,9 @@ export class Checkbox extends React.Component<CheckboxProps, CheckboxState> {
118121
get classes(): string {
119122
const {classList} = this.state;
120123
const {className} = this.props;
121-
return classnames('mdc-checkbox', Array.from(classList), className);
124+
return classnames(
125+
'mdc-checkbox', Array.from(classList),
126+
this.state.disabled ? cssClasses.DISABLED : null, className);
122127
}
123128

124129
updateState = (key: keyof CheckboxState, value: string | boolean) => {
@@ -146,10 +151,14 @@ export class Checkbox extends React.Component<CheckboxProps, CheckboxState> {
146151
// isAttachedToDOM will likely be removed
147152
// https://github.com/material-components/material-components-web/issues/3691
148153
isAttachedToDOM: () => true,
149-
isChecked: () => this.state.checked,
150-
isIndeterminate: () => this.state.indeterminate,
154+
isChecked: () => this.state.checked!,
155+
isIndeterminate: () => this.state.indeterminate!,
151156
setNativeControlAttr: this.updateState,
157+
setNativeControlDisabled: (disabled) => {
158+
this.updateState('disabled', disabled);
159+
},
152160
removeNativeControlAttr: this.removeState,
161+
forceLayout: () => null,
153162
};
154163
}
155164

@@ -169,8 +178,8 @@ export class Checkbox extends React.Component<CheckboxProps, CheckboxState> {
169178
initRipple,
170179
onChange,
171180
unbounded,
172-
/* eslint-enable no-unused-vars */
173181
disabled,
182+
/* eslint-enable no-unused-vars */
174183
nativeControlId,
175184
name,
176185
...otherProps
@@ -186,8 +195,8 @@ export class Checkbox extends React.Component<CheckboxProps, CheckboxState> {
186195
<NativeControl
187196
id={nativeControlId}
188197
checked={this.state.checked}
189-
disabled={disabled}
190-
aria-checked={this.state['aria-checked'] || this.state.checked}
198+
disabled={this.state.disabled}
199+
aria-checked={(this.state['aria-checked'] || this.state.checked!.toString()) as ('true' | 'false')}
191200
name={name}
192201
onChange={this.onChange}
193202
rippleActivatorRef={this.inputElement}

packages/checkbox/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"url": "https://github.com/material-components/material-components-web-react.git"
1717
},
1818
"dependencies": {
19-
"@material/checkbox": "^0.41.0",
19+
"@material/checkbox": "^1.1.0",
2020
"@material/react-ripple": "^0.11.0",
2121
"classnames": "^2.2.6",
2222
"react": "^16.3.2"

test/unit/checkbox/index.test.tsx

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,16 @@ import {assert} from 'chai';
33
import {shallow} from 'enzyme';
44
import * as td from 'testdouble';
55
import {Checkbox} from '../../../packages/checkbox/index';
6+
import {MDCCheckboxAdapter} from '@material/checkbox/adapter';
67
import {coerceForTesting} from '../helpers/types';
78

89
suite('Checkbox');
910

11+
const getAdapter = (instance: Checkbox): MDCCheckboxAdapter => {
12+
// @ts-ignore adapter_ is a protected property, we need to override it
13+
return instance.foundation.adapter_;
14+
};
15+
1016
test('creates foundation', () => {
1117
const wrapper = shallow<Checkbox>(<Checkbox />);
1218
assert.exists(wrapper.instance().foundation);
@@ -34,12 +40,29 @@ test('has disabled class when props.disabled is true', () => {
3440
);
3541
});
3642

43+
test('has disabled class when foundation calls setDisabled is true', () => {
44+
const wrapper = shallow<Checkbox>(<Checkbox />);
45+
getAdapter(wrapper.instance()).setNativeControlDisabled(true);
46+
wrapper.update();
47+
assert.isTrue(
48+
wrapper.find('.mdc-checkbox').hasClass('mdc-checkbox--disabled')
49+
);
50+
});
51+
3752
test('native control props.disabled is true when props.disabled is true', () => {
3853
const wrapper = shallow(<Checkbox disabled />);
3954
const nativeControl = wrapper.childAt(0);
4055
assert.isTrue(nativeControl.props().disabled);
4156
});
4257

58+
test('native control props.disabled when foundation calls setDisabled is true', () => {
59+
const wrapper = shallow<Checkbox>(<Checkbox />);
60+
getAdapter(wrapper.instance()).setNativeControlDisabled(true);
61+
wrapper.update();
62+
const nativeControl = wrapper.childAt(0);
63+
assert.isTrue(nativeControl.props().disabled);
64+
});
65+
4366
test('native control props.checked is true when props.checked is true', () => {
4467
const wrapper = shallow(<Checkbox checked />);
4568
const nativeControl = wrapper.childAt(0);
@@ -48,84 +71,80 @@ test('native control props.checked is true when props.checked is true', () => {
4871

4972
test('#foundation.handleChange gets called when prop.checked updates', () => {
5073
const wrapper = shallow<Checkbox>(<Checkbox />);
51-
wrapper.instance().foundation.handleChange = td.func();
74+
wrapper.instance().foundation.handleChange = td.func<() => null>();
5275
wrapper.setProps({checked: true});
5376
td.verify(wrapper.instance().foundation.handleChange(), {times: 1});
5477
});
5578

5679
test('#foundation.handleChange gets called when prop.indeterminate updates', () => {
5780
const wrapper = shallow<Checkbox>(<Checkbox />);
58-
wrapper.instance().foundation.handleChange = td.func();
81+
wrapper.instance().foundation.handleChange = td.func<() => null>();
5982
wrapper.setProps({indeterminate: true});
6083
td.verify(wrapper.instance().foundation.handleChange(), {times: 1});
6184
});
6285

6386
test('#foundation.setDisabled gets called when prop.disabled updates', () => {
6487
const wrapper = shallow<Checkbox>(<Checkbox />);
65-
wrapper.instance().foundation.setDisabled = td.func();
88+
wrapper.instance().foundation.setDisabled = td.func<(disabled: boolean) => null>();
6689
wrapper.setProps({disabled: true});
6790
td.verify(wrapper.instance().foundation.setDisabled(true), {times: 1});
6891
});
6992

7093
test('#componentWillUnmount destroys foundation', () => {
7194
const wrapper = shallow<Checkbox>(<Checkbox />);
7295
const foundation = wrapper.instance().foundation;
73-
foundation.destroy = td.func();
96+
foundation.destroy = td.func<() => void>();
7497
wrapper.unmount();
7598
td.verify(foundation.destroy(), {times: 1});
7699
});
77100

78101
test('#adapter.addClass adds class to state.classList', () => {
79102
const wrapper = shallow<Checkbox>(<Checkbox />);
80-
wrapper.instance().foundation.adapter_.addClass('test-class-name');
103+
getAdapter(wrapper.instance()).addClass('test-class-name');
81104
assert.isTrue(wrapper.state().classList.has('test-class-name'));
82105
});
83106

84107
test('#adapter.removeClass removes class from state.classList', () => {
85108
const wrapper = shallow<Checkbox>(<Checkbox />);
86109
wrapper.setState({classList: new Set(['test-class-name'])});
87-
wrapper.instance().foundation.adapter_.removeClass('test-class-name');
110+
getAdapter(wrapper.instance()).removeClass('test-class-name');
88111
assert.isFalse(wrapper.state().classList.has('test-class-name'));
89112
});
90113

91114
test('#adapter.isChecked returns state.checked if true', () => {
92115
const wrapper = shallow<Checkbox>(<Checkbox />);
93116
wrapper.setState({checked: true});
94-
assert.isTrue(wrapper.instance().foundation.adapter_.isChecked());
117+
assert.isTrue(getAdapter(wrapper.instance()).isChecked());
95118
});
96119

97120
test('#adapter.isChecked returns state.checked if false', () => {
98121
const wrapper = shallow<Checkbox>(<Checkbox />);
99122
wrapper.setState({checked: false});
100-
assert.isFalse(wrapper.instance().foundation.adapter_.isChecked());
123+
assert.isFalse(getAdapter(wrapper.instance()).isChecked());
101124
});
102125

103126
test('#adapter.isIndeterminate returns state.indeterminate if true', () => {
104127
const wrapper = shallow<Checkbox>(<Checkbox />);
105128
wrapper.setState({indeterminate: true});
106-
assert.isTrue(wrapper.instance().foundation.adapter_.isIndeterminate());
129+
assert.isTrue(getAdapter(wrapper.instance()).isIndeterminate());
107130
});
108131

109132
test('#adapter.isIndeterminate returns state.indeterminate if false', () => {
110133
const wrapper = shallow<Checkbox>(<Checkbox />);
111134
wrapper.setState({indeterminate: false});
112-
assert.isFalse(wrapper.instance().foundation.adapter_.isIndeterminate());
135+
assert.isFalse(getAdapter(wrapper.instance()).isIndeterminate());
113136
});
114137

115138
test('#adapter.setNativeControlAttr sets aria-checked state', () => {
116139
const wrapper = shallow<Checkbox>(<Checkbox />);
117-
wrapper
118-
.instance()
119-
.foundation.adapter_.setNativeControlAttr('aria-checked', true);
120-
assert.isTrue(wrapper.state()['aria-checked']);
140+
getAdapter(wrapper.instance()).setNativeControlAttr('aria-checked', 'true');
141+
assert.equal(wrapper.state()['aria-checked'], 'true');
121142
});
122143

123144
test('#adapter.removeNativeControlAttr sets aria-checked state as false', () => {
124145
const wrapper = shallow<Checkbox>(<Checkbox />);
125-
wrapper.setState({'aria-checked': true});
126-
wrapper
127-
.instance()
128-
.foundation.adapter_.removeNativeControlAttr('aria-checked');
146+
wrapper.setState({'aria-checked': 'true'});
147+
getAdapter(wrapper.instance()).removeNativeControlAttr('aria-checked');
129148
assert.isFalse(wrapper.state()['aria-checked']);
130149
});
131150

@@ -148,7 +167,7 @@ test('calls foundation.handleChange in native control props.onChange', () => {
148167
indeterminate: false,
149168
},
150169
};
151-
wrapper.instance().foundation.handleChange = td.func();
170+
wrapper.instance().foundation.handleChange = td.func<() => void>();
152171
nativeControl.simulate('change', mockEvt);
153172
td.verify(wrapper.instance().foundation.handleChange(), {times: 1});
154173
});

0 commit comments

Comments
 (0)