Skip to content

Commit

Permalink
feat(floating-label): update mdc web to v1.0.0 (#741)
Browse files Browse the repository at this point in the history
  • Loading branch information
Matt Goo committed Apr 30, 2019
1 parent dd95b60 commit 38e9886
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 25 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
"@material/dom": "^0.41.0",
"@material/drawer": "^1.0.1",
"@material/fab": "^0.41.0",
"@material/floating-label": "^0.41.0",
"@material/floating-label": "^1.0.0",
"@material/icon-button": "^0.41.0",
"@material/layout-grid": "^0.41.0",
"@material/line-ripple": "^1.0.0",
Expand Down
38 changes: 23 additions & 15 deletions packages/floating-label/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 mdc .d.ts
import {MDCFloatingLabelFoundation} from '@material/floating-label/dist/mdc.floatingLabel';
import {MDCFloatingLabelFoundation} from '@material/floating-label/foundation';
import {MDCFloatingLabelAdapter} from '@material/floating-label/adapter';

export interface FloatingLabelProps extends React.LabelHTMLAttributes<HTMLLabelElement> {
className?: string;
Expand All @@ -39,8 +39,8 @@ export default class FloatingLabel extends React.Component<
FloatingLabelProps,
FloatingLabelState
> {
foundation_?: MDCFloatingLabelFoundation;
labelElement_: React.RefObject<HTMLLabelElement> = React.createRef();
foundation!: MDCFloatingLabelFoundation;
labelElement: React.RefObject<HTMLLabelElement> = React.createRef();

static defaultProps: Partial<FloatingLabelProps> = {
className: '',
Expand All @@ -55,26 +55,26 @@ export default class FloatingLabel extends React.Component<
this.initializeFoundation();
this.handleWidthChange();
if (this.props.float) {
this.foundation_.float(true);
this.foundation.float(true);
}
}

componentWillUnmount() {
this.foundation_.destroy();
this.foundation.destroy();
}

componentDidUpdate(prevProps: FloatingLabelProps) {
if (this.props.children !== prevProps.children) {
this.handleWidthChange();
}
if (this.props.float !== prevProps.float) {
this.foundation_.float(this.props.float);
this.foundation.float(this.props.float!);
}
}

initializeFoundation = () => {
this.foundation_ = new MDCFloatingLabelFoundation(this.adapter);
this.foundation_.init();
this.foundation = new MDCFloatingLabelFoundation(this.adapter);
this.foundation.init();
};

get classes() {
Expand All @@ -83,17 +83,26 @@ export default class FloatingLabel extends React.Component<
return classnames('mdc-floating-label', Array.from(classList), className);
}

get adapter() {
get adapter(): MDCFloatingLabelAdapter {
return {
addClass: (className: string) =>
this.setState({classList: this.state.classList.add(className)}),
removeClass: this.removeClassFromClassList,
// the adapter methods below are effectively useless since React
// handles events and width differently
registerInteractionHandler: () => undefined,
deregisterInteractionHandler: () => undefined,
// Always returns 0 beacuse MDC Web component does
// only proxies to foundation.getWidth.
// MDC React instead passes it from the text-field
// component to floating-label component.
getWidth: () => 0,
};
}

// must be called via ref
shake = () => {
this.foundation_.shake(true);
this.foundation.shake(true);
};

removeClassFromClassList = (className: string) => {
Expand All @@ -103,9 +112,8 @@ export default class FloatingLabel extends React.Component<
};

handleWidthChange = () => {
const {handleWidthChange} = this.props;
if (handleWidthChange && this.labelElement_.current) {
handleWidthChange(this.labelElement_.current.offsetWidth);
if (this.props.handleWidthChange && this.labelElement.current) {
this.props.handleWidthChange(this.labelElement.current.offsetWidth);
}
};

Expand All @@ -126,7 +134,7 @@ export default class FloatingLabel extends React.Component<
return (
<label
className={this.classes}
ref={this.labelElement_}
ref={this.labelElement}
onAnimationEnd={this.onShakeEnd}
{...otherProps}
>
Expand Down
2 changes: 1 addition & 1 deletion packages/floating-label/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"url": "https://github.com/material-components/material-components-web-react.git"
},
"dependencies": {
"@material/floating-label": "^0.41.0",
"@material/floating-label": "^1.0.0",
"classnames": "^2.2.6",
"react": "^16.4.2"
},
Expand Down
22 changes: 14 additions & 8 deletions test/unit/floating-label/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,16 @@ import {suite, test} from 'mocha';
import {assert} from 'chai';
import {mount, shallow} from 'enzyme';
import FloatingLabel from '../../../packages/floating-label/index';
import {MDCFloatingLabelAdapter} from '@material/floating-label/adapter';
import {coerceForTesting} from '../helpers/types';

suite('Floating Label');

function getAdapter(instance: FloatingLabel): MDCFloatingLabelAdapter {
// @ts-ignore adapter_ property is protected, we need to bypass this check for testing purposes
return instance.foundation.adapter_;
}

test('classNames adds classes', () => {
const wrapper = shallow(
<FloatingLabel className='test-class-name'>Test</FloatingLabel>
Expand All @@ -21,22 +27,22 @@ test('adds text to children', () => {
assert.equal(wrapper.text(), 'Test');
});

test('creates labelElement_', () => {
test('creates labelElement', () => {
const wrapper = mount<FloatingLabel>(<FloatingLabel />);
assert.exists(wrapper.instance().labelElement_.current);
assert.exists(wrapper.instance().labelElement.current);
});

test('#initializeFoundation creates foundation', () => {
const wrapper = shallow<FloatingLabel>(<FloatingLabel />);
assert.exists(wrapper.instance().foundation_);
assert.exists(wrapper.instance().foundation);
});

test('initializing with float to true floats the label', () => {
const wrapper = shallow(<FloatingLabel float />);
assert.isTrue(wrapper.hasClass('mdc-floating-label--float-above'));
});

test('calls handleWidthChange with the offhandleWidthChange of the labelElement_', () => {
test('calls handleWidthChange with the offhandleWidthChange of the labelElement', () => {
const handleWidthChange = coerceForTesting<(width: number) => void>(td.func());
const div = document.createElement('div');
// needs to be attached to real DOM to get width
Expand Down Expand Up @@ -95,7 +101,7 @@ test('on animationend should remove the shake class', () => {

test('#adapter.addClass', () => {
const wrapper = mount<FloatingLabel>(<FloatingLabel />);
wrapper.instance().foundation_.adapter_.addClass('test-class-name');
getAdapter(wrapper.instance()).addClass('test-class-name');
assert.isTrue(wrapper.state().classList.has('test-class-name'));
});

Expand All @@ -105,14 +111,14 @@ test('#adapter.removeClass', () => {
classList.add('test-class-name');
wrapper.setState({classList});
assert.isTrue(wrapper.state().classList.has('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('#componentWillUnmount destroys foundation', () => {
const wrapper = shallow<FloatingLabel>(<FloatingLabel />);
const foundation = wrapper.instance().foundation_;
foundation.destroy = td.func();
const foundation = wrapper.instance().foundation;
foundation.destroy = coerceForTesting<() => void>(td.func());
wrapper.unmount();
td.verify(foundation.destroy());
});

0 comments on commit 38e9886

Please sign in to comment.