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

feat(floating-label): update mdc web to v1.0.0 #741

Merged
merged 3 commits into from
Mar 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why does this need to always return 0? Add a comment.

};
}

// 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());
});