Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(select): add adapter #3233

Merged
merged 13 commits into from
Jul 30, 2018
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@
"mdc-notched-outline",
"mdc-radio",
"mdc-ripple",
"mdc-select",
"mdc-selection-control",
"mdc-slider",
"mdc-switch",
Expand Down
9 changes: 8 additions & 1 deletion packages/mdc-select/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -244,10 +244,17 @@ If you are using a JavaScript framework, such as React or Angular, you can creat
| --- | --- |
| `addClass(className: string) => void` | Adds a class to the root element. |
| `removeClass(className: string) => void` | Removes a class from the root element. |
| `floatLabel(value: boolean) => void` | Floats or defloats label. |
| `hasClass(className: string) => boolean` | Returns true if the root element has the className in its classList. |
| `activateBottomLine() => void` | Activates the bottom line component. |
| `deactivateBottomLine() => void` | Deactivates the bottom line component. |
| `getValue() => string` | Returns the value selected on the `select` element. |
| `isRtl() => boolean` | Returns true if a parent of the root element is in RTL. |
| `hasLabel() => boolean` | Returns true if the `select` has a label associated with it. |
| `floatLabel(value: boolean) => void` | Floats or defloats label. |
| `getLabelWidth() => number` | Returns the offsetWidth of the label element. |
| `hasOutline() => boolean` | Returns true if the `select` has the notched outline element. |
| `notchOutline(labelWidth: number, isRtl, boolean) => void` | Switches the notched outline element to its "notched state." |
| `closeOutline() => void` | Switches the notched outline element to its closed state. |

### `MDCSelectFoundation`

Expand Down
117 changes: 117 additions & 0 deletions packages/mdc-select/adapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/**
* @license
* Copyright 2018 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 Select. Provides an interface for managing
* - classes
* - dom
* - event handlers
*
* Additionally, provides type information for the adapter to the Closure
* compiler.
*
* Implement this adapter for your framework of choice to delegate updates to
* the component in your framework of choice. See architecture documentation
* for more details.
* https://github.com/material-components/material-components-web/blob/master/docs/code/architecture.md
*
* @record
*/

class MDCSelectAdapter {
/**
* Adds class to root element.
* @param {string} className
*/
addClass(className) {}

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

/**
* Returns true if the root element contains the given class name.
* @param {string} className
* @return {boolean}
*/
hasClass(className) {}

/**
* Activates the bottom line, showing a focused state.
*/
activateBottomLine() {}

/**
* Deactivates the bottom line.
*/
deactivateBottomLine() {}

/**
* Returns the selected value of the select element.
* @return {string}
*/
getValue() {}

/**
* Returns true if the direction of the root element is set to RTL.
* @return {boolean}
*/
isRtl() {}

/**
* Returns true if label element exists, false if it doesn't.
* @return {boolean}
*/
hasLabel() {}

/**
* Floats label determined based off of the shouldFloat argument.
* @param {boolean} shouldFloat
*/
floatLabel(shouldFloat) {}

/**
* Returns width of label in pixels, if the label exists.
* @return {number}
*/
getLabelWidth() {}

/**
* Returns true if outline element exists, false if it doesn't.
* @return {boolean}
*/
hasOutline() {}

/**
* Updates SVG Path and outline element based on the
* label element width and RTL context, if the outline exists.
* @param {number} labelWidth
* @param {boolean=} isRtl
*/
notchOutline(labelWidth, isRtl) {}

/**
* Closes notch in outline element, if the outline exists.
*/
closeOutline() {}
}

export default MDCSelectAdapter;
4 changes: 4 additions & 0 deletions packages/mdc-select/constants.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/**
* @license
* Copyright 2016 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -13,13 +14,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/** @enum {string} */
const cssClasses = {
BOX: 'mdc-select--box',
DISABLED: 'mdc-select--disabled',
ROOT: 'mdc-select',
OUTLINED: 'mdc-select--outlined',
};

/** @enum {string} */
const strings = {
CHANGE_EVENT: 'MDCSelect:change',
LINE_RIPPLE_SELECTOR: '.mdc-line-ripple',
Expand Down
50 changes: 40 additions & 10 deletions packages/mdc-select/foundation.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,46 +15,65 @@
*/

import {MDCFoundation} from '@material/base/index';
/* eslint-disable no-unused-vars */
import MDCSelectAdapter from './adapter';
/* eslint-enable no-unused-vars */
import {cssClasses, strings, numbers} from './constants';

export default class MDCSelectFoundation extends MDCFoundation {
/**
* @extends {MDCFoundation<!MDCSelectAdapter>}
* @final
*/
class MDCSelectFoundation extends MDCFoundation {
/** @return enum {string} */
static get cssClasses() {
return cssClasses;
}

/** @return enum {number} */
static get numbers() {
return numbers;
}

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

/**
* {@see MDCSelectAdapter} for typing information on parameters and return
* types.
* @return {!MDCSelectAdapter}
*/
static get defaultAdapter() {
return {
return /** @type {!MDCSelectAdapter} */ ({
addClass: (/* className: string */) => {},
removeClass: (/* className: string */) => {},
hasClass: (/* className: string */) => false,
floatLabel: (/* value: boolean */) => {},
activateBottomLine: () => {},
deactivateBottomLine: () => {},
getValue: () => {},
isRtl: () => false,
hasLabel: () => {},
hasLabel: () => false,
floatLabel: (/* value: boolean */) => {},
getLabelWidth: () => {},
hasOutline: () => {},
notchOutline: () => {},
hasOutline: () => false,
notchOutline: (/* labelWidth: number, isRtl: boolean */) => {},
closeOutline: () => {},
};
});
}

/**
* @param {!MDCSelectAdapter} adapter
*/
constructor(adapter) {
super(Object.assign(MDCSelectFoundation.defaultAdapter, adapter));

this.focusHandler_ = (evt) => this.handleFocus_(evt);
this.blurHandler_ = (evt) => this.handleBlur_(evt);
}

/**
* Updates the styles of the select to show the disasbled state.
* @param {boolean} disabled
*/
updateDisabledStyle(disabled) {
const {DISABLED} = MDCSelectFoundation.cssClasses;
if (disabled) {
Expand All @@ -64,18 +83,27 @@ export default class MDCSelectFoundation extends MDCFoundation {
}
}

/**
* Handles value changes, via change event or programmatic updates.
*/
handleChange() {
const optionHasValue = this.adapter_.getValue().length > 0;
this.adapter_.floatLabel(optionHasValue);
this.notchOutline(optionHasValue);
}

/**
* Handles focus events from root element.
*/
handleFocus() {
this.adapter_.floatLabel(true);
this.notchOutline(true);
this.adapter_.activateBottomLine();
}

/**
* Handles blur events from root element.
*/
handleBlur() {
this.handleChange();
this.adapter_.deactivateBottomLine();
Expand All @@ -100,3 +128,5 @@ export default class MDCSelectFoundation extends MDCFoundation {
}
}
}

export default MDCSelectFoundation;
Loading