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

Commit

Permalink
chore(text-field): Split out icon into subelement (#1697)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Remove `setIconAttr`, `eventTargetHasClass` and `notifyIconAction` from `MDCTextFieldAdapter` implementations.
  • Loading branch information
bonniezhou authored Dec 14, 2017
1 parent 7c68674 commit 4e7fa3e
Show file tree
Hide file tree
Showing 16 changed files with 647 additions and 220 deletions.
36 changes: 7 additions & 29 deletions packages/mdc-textfield/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,36 +117,16 @@ By default an input's validity is checked via `checkValidity()` on blur, and the
accordingly. Set the MDCTextField.valid field to set the input's validity explicitly. MDC Text Field
automatically appends an asterisk to the label text if the required attribute is set.

### Leading and Trailing Icons
Leading and trailing icons can be added to MDC Text Fields as visual indicators
as well as interaction targets. To do so, add the relevant classes
(`mdc-text-field--with-leading-icon` or `mdc-text-field--with-trailing-icon`) to the root element, add
an `i` element with your preferred icon, and give it a class of `mdc-text-field__icon`.
### Using Helper Text

#### Leading:
```html
<div class="mdc-text-field mdc-text-field--box mdc-text-field--with-leading-icon">
<i class="material-icons mdc-text-field__icon" tabindex="0">event</i>
<input type="text" id="my-input" class="mdc-text-field__input">
<label for="my-input" class="mdc-text-field__label">Your Name</label>
<div class="mdc-text-field__bottom-line"></div>
</div>
```
The helper text provides supplemental information and/or validation messages to users. It appears on input field focus
and disappears on input field blur by default, or it can be persistent.
See [here](helper-text/) for more information on using helper text.

#### Trailing:
```html
<div class="mdc-text-field mdc-text-field--box mdc-text-field--with-trailing-icon">
<input type="text" id="my-input" class="mdc-text-field__input">
<label for="my-input" class="mdc-text-field__label">Your Name</label>
<i class="material-icons mdc-text-field__icon" tabindex="0">event</i>
<div class="mdc-text-field__bottom-line"></div>
</div>
```

>**NOTE:** if you would like to display un-clickable icons, simply remove `tabindex="0"`,
and the css will ensure the cursor is set to default, and that actioning on an icon doesn't
do anything unexpected.
### Leading and Trailing Icons

Leading and trailing icons can be added to MDC Text Fields as visual indicators as well as interaction targets.
See [here](icon/) for more information on using icons.

### Textarea

Expand Down Expand Up @@ -325,10 +305,8 @@ complicated.
| --- | --- |
| addClass(className: string) => void | Adds a class to the root element |
| removeClass(className: string) => void | Removes a class from the root element |
| eventTargetHasClass(target: HTMLElement, className: string) => boolean | Returns true if classname exists for a given target element |
| registerTextFieldInteractionHandler(evtType: string, handler: EventListener) => void | Registers an event handler on the root element for a given event |
| deregisterTextFieldInteractionHandler(evtType: string, handler: EventListener) => void | Deregisters an event handler on the root element for a given event |
| notifyIconAction() => void | Emits a custom event "MDCTextField:icon" denoting a user has clicked the icon |
| 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 |
| registerBottomLineEventHandler(evtType: string, handler: EventListener) => void | Registers an event listener on the bottom line element for a given event |
Expand Down
22 changes: 2 additions & 20 deletions packages/mdc-textfield/adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
/* eslint-disable no-unused-vars */
import MDCTextFieldBottomLineFoundation from './bottom-line/foundation';
import MDCTextFieldHelperTextFoundation from './helper-text/foundation';
import MDCTextFieldIconFoundation from './icon/foundation';
import MDCTextFieldLabelFoundation from './label/foundation';

/* eslint no-unused-vars: [2, {"args": "none"}] */
Expand All @@ -36,6 +37,7 @@ let NativeInputType;
* @typedef {{
* bottomLine: (!MDCTextFieldBottomLineFoundation|undefined),
* helperText: (!MDCTextFieldHelperTextFoundation|undefined),
* icon: (!MDCTextFieldIconFoundation|undefined),
* label: (!MDCTextFieldLabelFoundation|undefined)
* }}
*/
Expand Down Expand Up @@ -64,21 +66,6 @@ class MDCTextFieldAdapter {
*/
removeClass(className) {}

/**
* Sets an attribute on the icon Element.
* @param {string} name
* @param {string} value
*/
setIconAttr(name, value) {}

/**
* Returns true if classname exists for a given target element.
* @param {?EventTarget} target
* @param {string} className
* @return {boolean}
*/
eventTargetHasClass(target, className) {}

/**
* Registers an event handler on the root element for a given event.
* @param {string} type
Expand All @@ -93,11 +80,6 @@ class MDCTextFieldAdapter {
*/
deregisterTextFieldInteractionHandler(type, handler) {}

/**
* Emits a custom event "MDCTextField:icon" denoting a user has clicked the icon.
*/
notifyIconAction() {}

/**
* Registers an event listener on the native input element for a given event.
* @param {string} evtType
Expand Down
3 changes: 0 additions & 3 deletions packages/mdc-textfield/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ const strings = {
INPUT_SELECTOR: '.mdc-text-field__input',
LABEL_SELECTOR: '.mdc-text-field__label',
ICON_SELECTOR: '.mdc-text-field__icon',
ICON_EVENT: 'MDCTextField:icon',
BOTTOM_LINE_SELECTOR: '.mdc-text-field__bottom-line',
};

Expand All @@ -33,8 +32,6 @@ const cssClasses = {
FOCUSED: 'mdc-text-field--focused',
INVALID: 'mdc-text-field--invalid',
BOX: 'mdc-text-field--box',
TEXT_FIELD_ICON: 'mdc-text-field__icon',
TEXTAREA: 'mdc-text-field--textarea',
};

export {cssClasses, strings};
28 changes: 9 additions & 19 deletions packages/mdc-textfield/foundation.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {MDCTextFieldAdapter, NativeInputType, FoundationMapType} from './adapter
import MDCTextFieldBottomLineFoundation from './bottom-line/foundation';
/* eslint-disable no-unused-vars */
import MDCTextFieldHelperTextFoundation from './helper-text/foundation';
import MDCTextFieldIconFoundation from './icon/foundation';
import MDCTextFieldLabelFoundation from './label/foundation';
/* eslint-enable no-unused-vars */
import {cssClasses, strings} from './constants';
Expand Down Expand Up @@ -49,11 +50,8 @@ class MDCTextFieldFoundation extends MDCFoundation {
return /** @type {!MDCTextFieldAdapter} */ ({
addClass: () => {},
removeClass: () => {},
setIconAttr: () => {},
eventTargetHasClass: () => {},
registerTextFieldInteractionHandler: () => {},
deregisterTextFieldInteractionHandler: () => {},
notifyIconAction: () => {},
registerInputInteractionHandler: () => {},
deregisterInputInteractionHandler: () => {},
registerBottomLineEventHandler: () => {},
Expand All @@ -74,6 +72,8 @@ class MDCTextFieldFoundation extends MDCFoundation {
this.bottomLine_ = foundationMap.bottomLine;
/** @type {!MDCTextFieldHelperTextFoundation|undefined} */
this.helperText_ = foundationMap.helperText;
/** @type {!MDCTextFieldIconFoundation|undefined} */
this.icon_ = foundationMap.icon;
/** @type {!MDCTextFieldLabelFoundation|undefined} */
this.label_ = foundationMap.label;

Expand All @@ -92,7 +92,7 @@ class MDCTextFieldFoundation extends MDCFoundation {
/** @private {function(!Event): undefined} */
this.setPointerXOffset_ = (evt) => this.setBottomLineTransformOrigin(evt);
/** @private {function(!Event): undefined} */
this.textFieldInteractionHandler_ = (evt) => this.handleTextFieldInteraction(evt);
this.textFieldInteractionHandler_ = () => this.handleTextFieldInteraction();
/** @private {function(!Event): undefined} */
this.bottomLineAnimationEndHandler_ = () => this.handleBottomLineAnimationEnd();
}
Expand Down Expand Up @@ -133,24 +133,13 @@ class MDCTextFieldFoundation extends MDCFoundation {
}

/**
* Handles all user interactions with the Text Field.
* @param {!Event} evt
* Handles user interactions with the Text Field.
*/
handleTextFieldInteraction(evt) {
handleTextFieldInteraction() {
if (this.adapter_.getNativeInput().disabled) {
return;
}

this.receivedUserInput_ = true;

const {target, type} = evt;
const {TEXT_FIELD_ICON} = MDCTextFieldFoundation.cssClasses;
const targetIsIcon = this.adapter_.eventTargetHasClass(target, TEXT_FIELD_ICON);
const eventTriggersNotification = type === 'click' || evt.key === 'Enter' || evt.keyCode === 13;

if (targetIsIcon && eventTriggersNotification) {
this.adapter_.notifyIconAction();
}
}

/**
Expand Down Expand Up @@ -272,10 +261,11 @@ class MDCTextFieldFoundation extends MDCFoundation {
if (disabled) {
this.adapter_.addClass(DISABLED);
this.adapter_.removeClass(INVALID);
this.adapter_.setIconAttr('tabindex', '-1');
} else {
this.adapter_.removeClass(DISABLED);
this.adapter_.setIconAttr('tabindex', '0');
}
if (this.icon_) {
this.icon_.setDisabled(disabled);
}
}

Expand Down
77 changes: 77 additions & 0 deletions packages/mdc-textfield/icon/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<!--docs:
title: "Text Field Icon"
layout: detail
section: components
excerpt: "Icons describe the type of input a text field requires"
iconId: text_field
path: /catalog/input-controls/text-fields/icon/
-->

# Text Field Icon

Icons describe the type of input a text field requires. They can also be interaction targets.

## 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

### Leading and Trailing Icons
Leading and trailing icons can be added to MDC Text Fields as visual indicators
as well as interaction targets. To do so, add the relevant classes
(`mdc-text-field--with-leading-icon` or `mdc-text-field--with-trailing-icon`) to the root element, add
an `i` element with your preferred icon, and give it a class of `mdc-text-field__icon`.

#### Leading:
```html
<div class="mdc-text-field mdc-text-field--box mdc-text-field--with-leading-icon">
<i class="material-icons mdc-text-field__icon" tabindex="0">event</i>
<input type="text" id="my-input" class="mdc-text-field__input">
<label for="my-input" class="mdc-text-field__label">Your Name</label>
<div class="mdc-text-field__bottom-line"></div>
</div>
```

#### Trailing:
```html
<div class="mdc-text-field mdc-text-field--box mdc-text-field--with-trailing-icon">
<input type="text" id="my-input" class="mdc-text-field__input">
<label for="my-input" class="mdc-text-field__label">Your Name</label>
<i class="material-icons mdc-text-field__icon" tabindex="0">event</i>
<div class="mdc-text-field__bottom-line"></div>
</div>
```

>**NOTE:** if you would like to display un-clickable icons, simply remove `tabindex="0"`,
and the css will ensure the cursor is set to default, and that actioning on an icon doesn't
do anything unexpected.

#### MDCTextFieldIcon API

##### MDCTextFieldIcon.foundation

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

### Using the foundation class

Method Signature | Description
--- | ---
setAttr(attr: string, value: string) => void | Sets an attribute with a given value on the icon element
registerInteractionHandler(evtType: string, handler: EventListener) => void | Registers an event listener for a given event
deregisterInteractionHandler(evtType: string, handler: EventListener) => void | Deregisters an event listener for a given event
notifyIconAction() => void | Emits a custom event "MDCTextField:icon" denoting a user has clicked the icon, which bubbles to the top-level text field element

#### The full foundation API

##### MDCTextFieldIconFoundation.setDisabled(disabled: boolean)

Updates the icon's disabled state.

##### MDCTextFieldIconFoundation.handleInteraction(evt: Event)

Handles a text field interaction event.
58 changes: 58 additions & 0 deletions packages/mdc-textfield/icon/adapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* @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 Text Field Icon.
*
* Defines the shape of the adapter expected by the foundation. Implement this
* adapter to integrate the text field icon into your framework. See
* https://github.com/material-components/material-components-web/blob/master/docs/authoring-components.md
* for more information.
*
* @record
*/
class MDCTextFieldIconAdapter {
/**
* Sets an attribute on the icon element.
* @param {string} attr
* @param {string} value
*/
setAttr(attr, value) {}

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

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

/**
* Emits a custom event "MDCTextField:icon" denoting a user has clicked the icon.
*/
notifyIconAction() {}
}

export default MDCTextFieldIconAdapter;
23 changes: 23 additions & 0 deletions packages/mdc-textfield/icon/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* @license
* Copyright 2016 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 = {
ICON_EVENT: 'MDCTextField:icon',
};

export {strings};
Loading

0 comments on commit 4e7fa3e

Please sign in to comment.