Skip to content

Commit

Permalink
chore(text-field): Splitting out bottom line as a sub element (#1585)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Please update implementations of MDCTextFieldAdapter to implement the methods registerBottomLineEventHandler, deregisterBottomLineEventHandler, and getBottomLineFoundation. See the README for mdc-textfield/bottom-line for more information.
  • Loading branch information
lynnmercier authored Nov 15, 2017
1 parent 874a17e commit b12c576
Show file tree
Hide file tree
Showing 17 changed files with 717 additions and 176 deletions.
6 changes: 3 additions & 3 deletions packages/mdc-textfield/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -409,12 +409,12 @@ complicated.
| helperTextHasClass(className: string) => boolean | Returns whether or not the helper text element contains the current class |
| registerInputInteractionHandler(evtType: string, handler: EventListener) => void | Registers an event listener on the native input element for a given event |
| deregisterInputInteractionHandler(evtType: string, handler: EventListener) => void | Deregisters an event listener on the native input element for a given event |
| registerTransitionEndHandler(handler: EventListener) => void | Registers an event listener on the bottom line element for a "transitionend" event |
| deregisterTransitionEndHandler(handler: EventListener) => void | Deregisters an event listener on the bottom line element for a "transitionend" event |
| setBottomLineAttr(attr: string, value: string) => void | Sets an attribute with a given value on the bottom line element |
| registerBottomLineEventHandler(evtType: string, handler: EventListener) => void | Registers an event listener on the bottom line element for a given event |
| deregisterBottomLineEventHandler(evtType: string, handler: EventListener) => void | Deregisters an event listener on the bottom line element for a given event |
| setHelperTextAttr(name: string, value: string) => void | Sets an attribute with a given value on the helper text element |
| removeHelperTextAttr(name: string) => void | Removes an attribute from the helper text element |
| getNativeInput() => {value: string, disabled: boolean, badInput: boolean, checkValidity: () => boolean}? | Returns an object representing the native text input element, with a similar API shape. The object returned should include the `value`, `disabled` and `badInput` properties, as well as the `checkValidity()` function. We _never_ alter the value within our code, however we _do_ update the disabled property, so if you choose to duck-type the return value for this method in your implementation it's important to keep this in mind. Also note that this method can return null, which the foundation will handle gracefully. |
| getBottomLineFoundation() => MDCTextFieldBottomLineFoundation | Returns the instance of the bottom line element's foundation |

#### The full foundation API

Expand Down
19 changes: 19 additions & 0 deletions packages/mdc-textfield/_functions.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

@function mdc-text-field-transition($property) {
@return #{$property} 180ms $mdc-animation-standard-curve-timing-function;
}
39 changes: 16 additions & 23 deletions packages/mdc-textfield/adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
* limitations under the License.
*/

/* eslint-disable no-unused-vars */
import MDCTextFieldBottomLineFoundation from './bottom-line/foundation';

/* eslint no-unused-vars: [2, {"args": "none"}] */

/**
Expand Down Expand Up @@ -99,18 +102,6 @@ class MDCTextFieldAdapter {
*/
notifyIconAction() {}

/**
* Adds a class to the bottom line element.
* @param {string} className
*/
addClassToBottomLine(className) {}

/**
* Removes a class from the bottom line element.
* @param {string} className
*/
removeClassFromBottomLine(className) {}

/**
* Adds a class to the helper text element. Note that in our code we check for
* whether or not we have a helper text element and if we don't, we simply
Expand Down Expand Up @@ -147,23 +138,18 @@ class MDCTextFieldAdapter {
deregisterInputInteractionHandler(evtType, handler) {}

/**
* Registers an event listener on the bottom line element for a "transitionend" event.
* Registers an event listener on the bottom line element for a given event.
* @param {string} evtType
* @param {function(!Event): undefined} handler
*/
registerTransitionEndHandler(handler) {}
registerBottomLineEventHandler(evtType, handler) {}

/**
* Deregisters an event listener on the bottom line element for a "transitionend" event.
* Deregisters an event listener on the bottom line element for a given event.
* @param {string} evtType
* @param {function(!Event): undefined} handler
*/
deregisterTransitionEndHandler(handler) {}

/**
* Sets an attribute with a given value on the bottom line element.
* @param {string} attr
* @param {string} value
*/
setBottomLineAttr(attr, value) {}
deregisterBottomLineEventHandler(evtType, handler) {}

/**
* Sets an attribute with a given value on the helper text element.
Expand All @@ -189,6 +175,13 @@ class MDCTextFieldAdapter {
* @return {?Element|?NativeInputType}
*/
getNativeInput() {}

/**
* Returns the foundation for the bottom line element. Returns undefined if
* there is no bottom line element.
* @return {?MDCTextFieldBottomLineFoundation}
*/
getBottomLineFoundation() {}
}

export {MDCTextFieldAdapter, NativeInputType};
59 changes: 59 additions & 0 deletions packages/mdc-textfield/bottom-line/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<!--docs:
title: "Text Field Bottom Line"
layout: detail
section: components
excerpt: "The bottom line indicates where to enter text, displayed below the label"
iconId: text_field
path: /catalog/input-controls/text-fields/bottom-line/
-->

# Text Field Bottom Line

The bottom line indicates where to enter text, displayed below the label. When a text field is active or contains an error, the line’s color and thickness vary.

## Design & API Documentation

<ul class="icon-list">
<li class="icon-list-item icon-list-item--spec">
<a href="https://material.io/guidelines/components/text-fields.html#text-fields-layout">Material Design guidelines: Text Fields Layout</a>
</li>
</ul>


## Usage

#### MDCTextFieldBottomLine API

##### MDCTextFieldBottomLine.foundation

MDCTextFieldBottomLineFoundation. This allows the parent MDCTextField component to access the public methods on the MDCTextFieldBottomLineFoundation class.

### Using the foundation class


Method Signature | Description
--- | ---
addClass(className: string) => void | Adds a class to the root element
removeClass(className: string) => void | Removes a class from the root element
setAttr(attr: string, value: string) => void | Sets an attribute with a given value on the root element
registerEventHandler(evtType: string, handler: EventListener) => void | Registers an event listener on the root element for a given event
deregisterEventHandler(handler: EventListener) => void | Deregisters an event listener on the root element for a given event
notifyAnimationEnd() => void | Emits a custom event "MDCTextFieldBottomLine:animation-end" denoting the bottom line has finished its animation; either the activate or deactivate animation |

#### The full foundation API

##### MDCTextFieldBottomLineFoundation.activate()

Activates the bottom line

##### MDCTextFieldBottomLineFoundation.deactivate()

Deactivates the bottom line

##### MDCTextFieldBottomLineFoundation.setTransformOrigin(evt: Event)

Sets the transform origin given a user's click location.

##### MDCTextFieldBottomLineFoundation.handleTransitionEnd(evt: Event)

Handles a transition end event
72 changes: 72 additions & 0 deletions packages/mdc-textfield/bottom-line/adapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
* @license
* Copyright 2017 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* eslint no-unused-vars: [2, {"args": "none"}] */

/**
* Adapter for MDC TextField Bottom Line.
*
* Defines the shape of the adapter expected by the foundation. Implement this
* adapter to integrate the TextField bottom line into your framework. See
* https://github.com/material-components/material-components-web/blob/master/docs/authoring-components.md
* for more information.
*
* @record
*/
class MDCTextFieldBottomLineAdapter {
/**
* Adds a class to the bottom line element.
* @param {string} className
*/
addClass(className) {}

/**
* Removes a class from the bottom line element.
* @param {string} className
*/
removeClass(className) {}

/**
* Sets an attribute with a given value on the bottom line element.
* @param {string} attr
* @param {string} value
*/
setAttr(attr, value) {}

/**
* Registers an event listener on the bottom line element for a given event.
* @param {string} evtType
* @param {function(!Event): undefined} handler
*/
registerEventHandler(evtType, handler) {}

/**
* Deregisters an event listener on the bottom line element for a given event.
* @param {string} evtType
* @param {function(!Event): undefined} handler
*/
deregisterEventHandler(evtType, handler) {}

/**
* Emits a custom event "MDCTextFieldBottomLine:animation-end" denoting the
* bottom line has finished its animation; either the activate or
* deactivate animation
*/
notifyAnimationEnd() {}
}

export default MDCTextFieldBottomLineAdapter;
28 changes: 28 additions & 0 deletions packages/mdc-textfield/bottom-line/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* @license
* Copyright 2017 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/** @enum {string} */
const strings = {
ANIMATION_END_EVENT: 'MDCTextFieldBottomLine:animation-end',
};

/** @enum {string} */
const cssClasses = {
BOTTOM_LINE_ACTIVE: 'mdc-text-field__bottom-line--active',
};

export {strings, cssClasses};
113 changes: 113 additions & 0 deletions packages/mdc-textfield/bottom-line/foundation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/**
* @license
* Copyright 2017 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import MDCFoundation from '@material/base/foundation';
import MDCTextFieldBottomLineAdapter from './adapter';
import {cssClasses, strings} from './constants';


/**
* @extends {MDCFoundation<!MDCTextFieldBottomLineAdapter>}
* @final
*/
class MDCTextFieldBottomLineFoundation extends MDCFoundation {
/** @return enum {string} */
static get cssClasses() {
return cssClasses;
}

/** @return enum {string} */
static get strings() {
return strings;
}

/**
* {@see MDCTextFieldBottomLineAdapter} for typing information on parameters and return
* types.
* @return {!MDCTextFieldBottomLineAdapter}
*/
static get defaultAdapter() {
return /** @type {!MDCTextFieldBottomLineAdapter} */ ({
addClass: () => {},
removeClass: () => {},
setAttr: () => {},
registerEventHandler: () => {},
deregisterEventHandler: () => {},
notifyAnimationEnd: () => {},
});
}

/**
* @param {!MDCTextFieldBottomLineAdapter=} adapter
*/
constructor(adapter = /** @type {!MDCTextFieldBottomLineAdapter} */ ({})) {
super(Object.assign(MDCTextFieldBottomLineFoundation.defaultAdapter, adapter));

/** @private {function(!Event): undefined} */
this.transitionEndHandler_ = (evt) => this.handleTransitionEnd(evt);
}

init() {
this.adapter_.registerEventHandler('transitionend', this.transitionEndHandler_);
}

destroy() {
this.adapter_.deregisterEventHandler('transitionend', this.transitionEndHandler_);
}

/**
* Activates the bottom line
*/
activate() {
this.adapter_.addClass(cssClasses.BOTTOM_LINE_ACTIVE);
}

/**
* Sets the transform origin given a user's click location.
* @param {!Event} evt
*/
setTransformOrigin(evt) {
const targetClientRect = evt.target.getBoundingClientRect();
const evtCoords = {x: evt.clientX, y: evt.clientY};
const normalizedX = evtCoords.x - targetClientRect.left;
const attributeString =
`transform-origin: ${normalizedX}px center`;

this.adapter_.setAttr('style', attributeString);
}

/**
* Deactivates the bottom line
*/
deactivate() {
this.adapter_.removeClass(cssClasses.BOTTOM_LINE_ACTIVE);
}

/**
* Handles a transition end event
* @param {!Event} evt
*/
handleTransitionEnd(evt) {
// Wait for the bottom line to be either transparent or opaque
// before emitting the animation end event
if (evt.propertyName === 'opacity') {
this.adapter_.notifyAnimationEnd();
}
}
}

export default MDCTextFieldBottomLineFoundation;
Loading

0 comments on commit b12c576

Please sign in to comment.