diff --git a/demos/chips.html b/demos/chips.html new file mode 100644 index 00000000000..749a097a559 --- /dev/null +++ b/demos/chips.html @@ -0,0 +1,84 @@ + + + + + + Chips - Material Components Catalog + + + + + + + + + +
+
+
+ + + + Chips +
+
+
+ +
+
+
+
+
Chip One
+
+
+
Chip Two
+
+
+
Chip Three
+
+
+
Chip Four
+
+
+
+ +
+
+
+
Add to Calendar
+
+
+
Bookmark
+
+
+
Set Alarm
+
+
+
Get Directions
+
+
+
+
+ + + + + diff --git a/demos/chips.scss b/demos/chips.scss new file mode 100644 index 00000000000..954ffe760b1 --- /dev/null +++ b/demos/chips.scss @@ -0,0 +1,18 @@ +// +// 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 "./common"; +@import "../packages/mdc-chips/mdc-chips"; diff --git a/demos/images/ic_chips_24dp.svg b/demos/images/ic_chips_24dp.svg new file mode 100644 index 00000000000..6fb22c85aec --- /dev/null +++ b/demos/images/ic_chips_24dp.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/demos/index.html b/demos/index.html index 5ee0b9a42cf..0bf64e1c46a 100644 --- a/demos/index.html +++ b/demos/index.html @@ -59,6 +59,13 @@ Multi-selection controls + + + + Chips + Chips for actions, selection, and input + + diff --git a/package.json b/package.json index 4b105925c3a..80485aa19be 100644 --- a/package.json +++ b/package.json @@ -126,6 +126,7 @@ "button", "card", "checkbox", + "chips", "dialog", "drawer", "elevation", @@ -166,6 +167,7 @@ "mdc-base", "mdc-line-ripple", "mdc-checkbox", + "mdc-chips", "mdc-form-field", "mdc-icon-toggle", "mdc-menu", diff --git a/packages/material-components-web/index.js b/packages/material-components-web/index.js index f40011e5e90..6fe16e86a5e 100644 --- a/packages/material-components-web/index.js +++ b/packages/material-components-web/index.js @@ -17,6 +17,7 @@ import autoInit from '@material/auto-init/index'; import * as base from '@material/base/index'; import * as checkbox from '@material/checkbox/index'; +import * as chips from '@material/chips/index'; import * as dialog from '@material/dialog/index'; import * as drawer from '@material/drawer/index'; import * as formField from '@material/form-field/index'; @@ -38,6 +39,8 @@ import * as toolbar from '@material/toolbar/index'; // Register all components autoInit.register('MDCLineRipple', lineRipple.MDCLineRipple); autoInit.register('MDCCheckbox', checkbox.MDCCheckbox); +autoInit.register('MDCChip', chips.MDCChip); +autoInit.register('MDCChipSet', chips.MDCChipSet); autoInit.register('MDCDialog', dialog.MDCDialog); autoInit.register('MDCPersistentDrawer', drawer.MDCPersistentDrawer); autoInit.register('MDCTemporaryDrawer', drawer.MDCTemporaryDrawer); @@ -62,6 +65,7 @@ export { base, lineRipple, checkbox, + chips, dialog, drawer, formField, diff --git a/packages/material-components-web/material-components-web.scss b/packages/material-components-web/material-components-web.scss index 71626ecb0cb..d791151ceb0 100644 --- a/packages/material-components-web/material-components-web.scss +++ b/packages/material-components-web/material-components-web.scss @@ -18,6 +18,7 @@ @import "@material/button/mdc-button"; @import "@material/card/mdc-card"; @import "@material/checkbox/mdc-checkbox"; +@import "@material/chips/mdc-chips"; @import "@material/dialog/mdc-dialog"; @import "@material/drawer/mdc-drawer"; @import "@material/elevation/mdc-elevation"; diff --git a/packages/material-components-web/package.json b/packages/material-components-web/package.json index 173f2839e7f..77a7bdbda74 100644 --- a/packages/material-components-web/package.json +++ b/packages/material-components-web/package.json @@ -20,6 +20,7 @@ "@material/button": "^0.29.0", "@material/card": "^0.29.0", "@material/checkbox": "^0.29.0", + "@material/chips": "^0.0.0", "@material/dialog": "^0.29.0", "@material/drawer": "^0.29.0", "@material/elevation": "^0.28.0", diff --git a/packages/mdc-chips/README.md b/packages/mdc-chips/README.md new file mode 100644 index 00000000000..5bec5300dfa --- /dev/null +++ b/packages/mdc-chips/README.md @@ -0,0 +1,105 @@ + + +# Chips + + + +Chips are compact elements that allow users to enter information, select a choice, filter content, or trigger an action. + +## Design & API Documentation + + + +## Installation +``` +npm install --save @material/chips +``` + +## Usage + +### HTML Structure + +```html +
+
+
Chip content
+
+
+
Chip content
+
+
+
Chip content
+
+
+``` + +### CSS Classes + +CSS Class | Description +--- | --- +`mdc-chip` | Mandatory. +`mdc-chip__text` | Mandatory. Indicates the text content of the chip. +`mdc-chip-set` | Mandatory. Indicates the set that the chip belongs to. + +### `MDCChip` and `MDCChipSet` + +The MDC Chips module is comprised of two JavaScript classes: +* `MDCChip` defines the behavior of a single chip +* `MDCChipSet` defines the behavior of chips within a specific set. For example, chips in an entry chip set behave differently from those in a filter chip set. + +To use the `MDCChip` and `MDCChipSet` classes, [import](../../docs/importing-js.md) both classes from `@material/chips`. + +#### `MDCChip` + +Property | Value Type | Description +--- | --- | --- +`ripple` | `MDCRipple` | The `MDCRipple` instance for the root element that `MDCChip` initializes + +#### `MDCChipSet` + +Property | Value Type | Description +--- | --- | --- +`chips` | Array<`MDCChip`> | An array of the `MDCChip` objects that represent chips in the set + +### Adapters: `MDCChipAdapter` and `MDCChipSetAdapter` + +#### `MDCChipAdapter` + +Method Signature | Description +--- | --- +`registerInteractionHandler(evtType: string, handler: EventListener) => void` | Registers an event listener on the root element +`deregisterInteractionHandler(evtType: string, handler: EventListener) => void` | Deregisters an event listener on the root element +`notifyInteraction() => void` | Emits a custom event "MDCChip:interaction" denoting the chip has been interacted with, which bubbles to the parent `mdc-chip-set` element + +#### `MDCChipSetAdapter` + +Method Signature | Description +--- | --- +`hasClass(className: string) => boolean` | Returns whether the chip set element has the given class + +### Foundations: `MDCChipFoundation` and `MDCChipSetFoundation` + +#### `MDCChipFoundation` +None yet, coming soon. + +#### `MDCChipSetFoundation` +None yet, coming soon. diff --git a/packages/mdc-chips/chip-set/adapter.js b/packages/mdc-chips/chip-set/adapter.js new file mode 100644 index 00000000000..0701a37c9c1 --- /dev/null +++ b/packages/mdc-chips/chip-set/adapter.js @@ -0,0 +1,38 @@ +/** + * @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 Chip Set. + * + * Defines the shape of the adapter expected by the foundation. Implement this + * adapter to integrate the Chip Set into your framework. See + * https://github.com/material-components/material-components-web/blob/master/docs/authoring-components.md + * for more information. + * + * @record + */ +class MDCChipSetAdapter { + /** + * Returns true if the root element contains the given class name. + * @param {string} className + */ + hasClass(className) {} +} + +export default MDCChipSetAdapter; diff --git a/packages/mdc-chips/chip-set/constants.js b/packages/mdc-chips/chip-set/constants.js new file mode 100644 index 00000000000..f64933703a0 --- /dev/null +++ b/packages/mdc-chips/chip-set/constants.js @@ -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 = { + CHIP_SELECTOR: '.mdc-chip', +}; + +export {strings}; diff --git a/packages/mdc-chips/chip-set/foundation.js b/packages/mdc-chips/chip-set/foundation.js new file mode 100644 index 00000000000..5203d610788 --- /dev/null +++ b/packages/mdc-chips/chip-set/foundation.js @@ -0,0 +1,51 @@ +/** + * @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 MDCChipSetAdapter from './adapter'; +import {strings} from './constants'; + +/** + * @extends {MDCFoundation} + * @final + */ +class MDCChipSetFoundation extends MDCFoundation { + /** @return enum {string} */ + static get strings() { + return strings; + } + + /** + * {@see MDCChipSetAdapter} for typing information on parameters and return + * types. + * @return {!MDCChipSetAdapter} + */ + static get defaultAdapter() { + return /** @type {!MDCChipSetAdapter} */ ({ + hasClass: () => {}, + }); + } + + /** + * @param {!MDCChipSetAdapter} adapter + */ + constructor(adapter) { + super(Object.assign(MDCChipSetFoundation.defaultAdapter, adapter)); + } +} + +export default MDCChipSetFoundation; diff --git a/packages/mdc-chips/chip-set/index.js b/packages/mdc-chips/chip-set/index.js new file mode 100644 index 00000000000..3c3e590ac85 --- /dev/null +++ b/packages/mdc-chips/chip-set/index.js @@ -0,0 +1,81 @@ +/** + * @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. + */ + +import MDCComponent from '@material/base/component'; + +import MDCChipSetAdapter from './adapter'; +import MDCChipSetFoundation from './foundation'; +import {MDCChip} from '../chip/index'; + +/** + * @extends {MDCComponent} + * @final + */ +class MDCChipSet extends MDCComponent { + /** + * @param {...?} args + */ + constructor(...args) { + super(...args); + + /** @private {!Array} */ + this.chips; + } + + /** + * @param {!Element} root + * @return {!MDCChipSet} + */ + static attachTo(root) { + return new MDCChipSet(root); + } + + /** + * @param {(function(!Element): !MDCChip)=} chipFactory A function which + * creates a new MDCChip. + */ + initialize(chipFactory = (el) => new MDCChip(el)) { + this.chips = this.instantiateChips_(chipFactory); + } + + destroy() { + this.chips.forEach((chip) => { + chip.destroy(); + }); + } + + /** + * @return {!MDCChipSetFoundation} + */ + getDefaultFoundation() { + return new MDCChipSetFoundation(/** @type {!MDCChipSetAdapter} */ (Object.assign({ + hasClass: (className) => this.root_.classList.contains(className), + }))); + } + + /** + * Instantiates chip components on all of the chip set's child chip elements. + * @param {(function(!Element): !MDCChip)} chipFactory + * @return {!Array} + */ + instantiateChips_(chipFactory) { + const chipElements = [].slice.call(this.root_.querySelectorAll(MDCChipSetFoundation.strings.CHIP_SELECTOR)); + return chipElements.map((el) => chipFactory(el)); + } +} + +export {MDCChipSet, MDCChipSetFoundation}; diff --git a/packages/mdc-chips/chip/adapter.js b/packages/mdc-chips/chip/adapter.js new file mode 100644 index 00000000000..70c7d4e175f --- /dev/null +++ b/packages/mdc-chips/chip/adapter.js @@ -0,0 +1,52 @@ +/** + * @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 Chip. + * + * Defines the shape of the adapter expected by the foundation. Implement this + * adapter to integrate the Chip into your framework. See + * https://github.com/material-components/material-components-web/blob/master/docs/authoring-components.md + * for more information. + * + * @record + */ +class MDCChipAdapter { + /** + * Registers an event listener on the root element for a given event. + * @param {string} evtType + * @param {function(!Event): undefined} handler + */ + registerInteractionHandler(evtType, handler) {} + + /** + * Deregisters an event listener on the root element for a given event. + * @param {string} evtType + * @param {function(!Event): undefined} handler + */ + deregisterInteractionHandler(evtType, handler) {} + + /** + * Emits a custom "MDCChip:interaction" event denoting the chip has been + * interacted with (typically on click or keydown). + */ + notifyInteraction() {} +} + +export default MDCChipAdapter; diff --git a/packages/mdc-chips/chip/constants.js b/packages/mdc-chips/chip/constants.js new file mode 100644 index 00000000000..dd4b646375c --- /dev/null +++ b/packages/mdc-chips/chip/constants.js @@ -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 = { + INTERACTION_EVENT: 'MDCChip:interaction', +}; + +export {strings}; diff --git a/packages/mdc-chips/chip/foundation.js b/packages/mdc-chips/chip/foundation.js new file mode 100644 index 00000000000..02773776642 --- /dev/null +++ b/packages/mdc-chips/chip/foundation.js @@ -0,0 +1,79 @@ +/** + * @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. + */ + +import MDCFoundation from '@material/base/foundation'; +import MDCChipAdapter from './adapter'; +import {strings} from './constants'; + + +/** + * @extends {MDCFoundation} + * @final + */ +class MDCChipFoundation extends MDCFoundation { + /** @return enum {string} */ + static get strings() { + return strings; + } + + /** + * {@see MDCChipAdapter} for typing information on parameters and return + * types. + * @return {!MDCChipAdapter} + */ + static get defaultAdapter() { + return /** @type {!MDCChipAdapter} */ ({ + registerInteractionHandler: () => {}, + deregisterInteractionHandler: () => {}, + notifyInteraction: () => {}, + }); + } + + /** + * @param {!MDCChipAdapter} adapter + */ + constructor(adapter) { + super(Object.assign(MDCChipFoundation.defaultAdapter, adapter)); + + /** @private {function(!Event): undefined} */ + this.interactionHandler_ = (evt) => this.handleInteraction_(evt); + } + + init() { + ['click', 'keydown'].forEach((evtType) => { + this.adapter_.registerInteractionHandler(evtType, this.interactionHandler_); + }); + } + + destroy() { + ['click', 'keydown'].forEach((evtType) => { + this.adapter_.deregisterInteractionHandler(evtType, this.interactionHandler_); + }); + } + + /** + * Handles an interaction event on the root element. + * @param {!Event} evt + */ + handleInteraction_(evt) { + if (evt.type === 'click' || evt.key === 'Enter' || evt.keyCode === 13) { + this.adapter_.notifyInteraction(); + } + } +} + +export default MDCChipFoundation; diff --git a/packages/mdc-chips/chip/index.js b/packages/mdc-chips/chip/index.js new file mode 100644 index 00000000000..beae32df32e --- /dev/null +++ b/packages/mdc-chips/chip/index.js @@ -0,0 +1,70 @@ +/** + * @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. + */ + +import MDCComponent from '@material/base/component'; +import {MDCRipple} from '@material/ripple/index'; + +import MDCChipAdapter from './adapter'; +import MDCChipFoundation from './foundation'; +import {strings} from './constants'; + +/** + * @extends {MDCComponent} + * @final + */ +class MDCChip extends MDCComponent { + /** + * @param {...?} args + */ + constructor(...args) { + super(...args); + + /** @private {!MDCRipple} */ + this.ripple_ = new MDCRipple(this.root_); + } + + /** + * @param {!Element} root + * @return {!MDCChip} + */ + static attachTo(root) { + return new MDCChip(root); + } + + destroy() { + this.ripple_.destroy(); + super.destroy(); + } + + /** + * @return {!MDCChipFoundation} + */ + getDefaultFoundation() { + return new MDCChipFoundation(/** @type {!MDCChipAdapter} */ (Object.assign({ + registerInteractionHandler: (evtType, handler) => this.root_.addEventListener(evtType, handler), + deregisterInteractionHandler: (evtType, handler) => this.root_.removeEventListener(evtType, handler), + notifyInteraction: () => this.emit(strings.INTERACTION_EVENT, {chip: this}, true /* shouldBubble */), + }))); + } + + /** @return {!MDCRipple} */ + get ripple() { + return this.ripple_; + } +} + +export {MDCChip, MDCChipFoundation}; diff --git a/packages/mdc-chips/chip/mdc-chip.scss b/packages/mdc-chips/chip/mdc-chip.scss new file mode 100644 index 00000000000..f5ac8334de2 --- /dev/null +++ b/packages/mdc-chips/chip/mdc-chip.scss @@ -0,0 +1,40 @@ +// +// 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 "@material/ripple/common"; +@import "@material/ripple/mixins"; + +.mdc-chip { + @include mdc-ripple-surface; + @include mdc-ripple-radius-bounded; + @include mdc-states; + + display: inline-block; + border-radius: 16px; + background: rgba(0, 0, 0, 0.08); + color: rgba(0, 0, 0, 0.87); + padding: 7px 12px; + margin: 5px; + cursor: pointer; + overflow: hidden; +} + +.mdc-chip__text { + display: inline-block; + vertical-align: middle; + // Set line-height to be <18px to force the content height of mdc-chip to be 18px. + line-height: 17px; +} diff --git a/packages/mdc-chips/index.js b/packages/mdc-chips/index.js new file mode 100644 index 00000000000..293de597216 --- /dev/null +++ b/packages/mdc-chips/index.js @@ -0,0 +1,20 @@ +/** + * 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 {MDCChipFoundation, MDCChip} from './chip/index'; +import {MDCChipSetFoundation, MDCChipSet} from './chip-set/index'; + +export {MDCChipFoundation, MDCChip, MDCChipSetFoundation, MDCChipSet}; diff --git a/packages/mdc-chips/mdc-chips.scss b/packages/mdc-chips/mdc-chips.scss new file mode 100644 index 00000000000..2bab79f7f6a --- /dev/null +++ b/packages/mdc-chips/mdc-chips.scss @@ -0,0 +1,18 @@ + +// +// 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 "./chip/mdc-chip"; diff --git a/packages/mdc-chips/package.json b/packages/mdc-chips/package.json new file mode 100644 index 00000000000..04a18c6ac78 --- /dev/null +++ b/packages/mdc-chips/package.json @@ -0,0 +1,22 @@ +{ + "name": "@material/chips", + "description": "The Material Components for the Web chips component", + "version": "0.0.0", + "license": "Apache 2.0", + "keywords": [ + "material components", + "material design", + "chips" + ], + "repository": { + "type": "git", + "url": "https://github.com/material-components/material-components-web.git" + }, + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@material/base": "^0.29.0", + "@material/ripple": "^0.29.0" + } +} diff --git a/test/unit/mdc-chips/mdc-chip-set.foundation.test.js b/test/unit/mdc-chips/mdc-chip-set.foundation.test.js new file mode 100644 index 00000000000..02a52d1c360 --- /dev/null +++ b/test/unit/mdc-chips/mdc-chip-set.foundation.test.js @@ -0,0 +1,32 @@ +/** + * 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 {assert} from 'chai'; + +import {verifyDefaultAdapter} from '../helpers/foundation'; +import MDCChipSetFoundation from '../../../packages/mdc-chips/chip-set/foundation'; + +suite('MDCChipSetFoundation'); + +test('exports strings', () => { + assert.isOk('strings' in MDCChipSetFoundation); +}); + +test('defaultAdapter returns a complete adapter implementation', () => { + verifyDefaultAdapter(MDCChipSetFoundation, [ + 'hasClass', + ]); +}); diff --git a/test/unit/mdc-chips/mdc-chip-set.test.js b/test/unit/mdc-chips/mdc-chip-set.test.js new file mode 100644 index 00000000000..1b0b3c9d318 --- /dev/null +++ b/test/unit/mdc-chips/mdc-chip-set.test.js @@ -0,0 +1,77 @@ +/** + * 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 bel from 'bel'; +import {assert} from 'chai'; +import td from 'testdouble'; + +import {MDCChipSet} from '../../../packages/mdc-chips/chip-set'; + +const getFixture = () => bel` +
+
+
Chip content
+
+
+
Chip content
+
+
+
Chip content
+
+
+`; + +suite('MDCChipSet'); + +test('attachTo returns an MDCChipSet instance', () => { + assert.isOk(MDCChipSet.attachTo(getFixture()) instanceof MDCChipSet); +}); + +class FakeChip { + constructor() { + this.destroy = td.func('.destroy'); + } +} + +test('#constructor instantiates child chip components', () => { + const root = getFixture(); + const component = new MDCChipSet(root, undefined, (el) => new FakeChip(el)); + assert.isOk(component.chips.length === 3 && + component.chips[0] instanceof FakeChip && + component.chips[1] instanceof FakeChip && + component.chips[2] instanceof FakeChip); +}); + +test('#destroy cleans up child chip components', () => { + const root = getFixture(); + const component = new MDCChipSet(root, undefined, (el) => new FakeChip(el)); + component.destroy(); + td.verify(component.chips[0].destroy()); + td.verify(component.chips[1].destroy()); + td.verify(component.chips[2].destroy()); +}); + +function setupTest() { + const root = getFixture(); + const component = new MDCChipSet(root); + return {root, component}; +} + +test('#adapter.hasClass returns true if class is set on chip set element', () => { + const {root, component} = setupTest(); + root.classList.add('foo'); + assert.isTrue(component.getDefaultFoundation().adapter_.hasClass('foo')); +}); diff --git a/test/unit/mdc-chips/mdc-chip.foundation.test.js b/test/unit/mdc-chips/mdc-chip.foundation.test.js new file mode 100644 index 00000000000..b9de70e5e6d --- /dev/null +++ b/test/unit/mdc-chips/mdc-chip.foundation.test.js @@ -0,0 +1,69 @@ +/** + * 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 {assert} from 'chai'; +import td from 'testdouble'; + +import {verifyDefaultAdapter} from '../helpers/foundation'; +import {setupFoundationTest} from '../helpers/setup'; +import MDCChipFoundation from '../../../packages/mdc-chips/chip/foundation'; + +suite('MDCChipFoundation'); + +test('exports strings', () => { + assert.isOk('strings' in MDCChipFoundation); +}); + +test('defaultAdapter returns a complete adapter implementation', () => { + verifyDefaultAdapter(MDCChipFoundation, [ + 'registerInteractionHandler', 'deregisterInteractionHandler', 'notifyInteraction', + ]); +}); + +const setupTest = () => setupFoundationTest(MDCChipFoundation); + +test('#init adds event listeners', () => { + const {foundation, mockAdapter} = setupTest(); + foundation.init(); + + td.verify(mockAdapter.registerInteractionHandler('click', td.matchers.isA(Function))); + td.verify(mockAdapter.registerInteractionHandler('keydown', td.matchers.isA(Function))); +}); + +test('#destroy removes event listeners', () => { + const {foundation, mockAdapter} = setupTest(); + foundation.destroy(); + + td.verify(mockAdapter.deregisterInteractionHandler('click', td.matchers.isA(Function))); + td.verify(mockAdapter.deregisterInteractionHandler('keydown', td.matchers.isA(Function))); +}); + +test('on click, emit custom event', () => { + const {foundation, mockAdapter} = setupTest(); + const mockEvt = { + type: 'click', + }; + let click; + + td.when(mockAdapter.registerInteractionHandler('click', td.matchers.isA(Function))).thenDo((evtType, handler) => { + click = handler; + }); + + foundation.init(); + click(mockEvt); + + td.verify(mockAdapter.notifyInteraction()); +}); diff --git a/test/unit/mdc-chips/mdc-chip.test.js b/test/unit/mdc-chips/mdc-chip.test.js new file mode 100644 index 00000000000..0667ccfc56f --- /dev/null +++ b/test/unit/mdc-chips/mdc-chip.test.js @@ -0,0 +1,72 @@ +/** + * 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 bel from 'bel'; +import {assert} from 'chai'; +import td from 'testdouble'; +import domEvents from 'dom-events'; + +import {MDCChip, MDCChipFoundation} from '../../../packages/mdc-chips/chip'; + +const getFixture = () => bel` +
+
Chip content
+
+`; + +suite('MDCChip'); + +test('attachTo returns an MDCChip instance', () => { + assert.isOk(MDCChip.attachTo(getFixture()) instanceof MDCChip); +}); + +function setupTest() { + const root = getFixture(); + const component = new MDCChip(root); + return {root, component}; +} + +test('#adapter.registerInteractionHandler adds event listener for a given event to the root element', () => { + const {root, component} = setupTest(); + const handler = td.func('click handler'); + component.getDefaultFoundation().adapter_.registerInteractionHandler('click', handler); + domEvents.emit(root, 'click'); + + td.verify(handler(td.matchers.anything())); +}); + +test('#adapter.deregisterInteractionHandler removes event listener for a given event from the root element', () => { + const {root, component} = setupTest(); + const handler = td.func('click handler'); + + root.addEventListener('click', handler); + component.getDefaultFoundation().adapter_.deregisterInteractionHandler('click', handler); + domEvents.emit(root, 'click'); + + td.verify(handler(td.matchers.anything()), {times: 0}); +}); + +test('#adapter.notifyInteraction emits ' + + `${MDCChipFoundation.strings.INTERACTION_EVENT}`, () => { + const {component} = setupTest(); + const handler = td.func('interaction handler'); + + component.listen( + MDCChipFoundation.strings.INTERACTION_EVENT, handler); + component.getDefaultFoundation().adapter_.notifyInteraction(); + + td.verify(handler(td.matchers.anything())); +}); diff --git a/webpack.config.js b/webpack.config.js index 06cda17da35..2126f503a0f 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -187,6 +187,7 @@ if (!IS_DEV) { base: [path.resolve('./packages/mdc-base/index.js')], lineRipple: [path.resolve('./packages/mdc-line-ripple/index.js')], checkbox: [path.resolve('./packages/mdc-checkbox/index.js')], + chips: [path.resolve('./packages/mdc-chips/index.js')], dialog: [path.resolve('./packages/mdc-dialog/index.js')], drawer: [path.resolve('./packages/mdc-drawer/index.js')], formField: [path.resolve('./packages/mdc-form-field/index.js')], @@ -234,6 +235,7 @@ if (!IS_DEV) { 'mdc.line-ripple': path.resolve('./packages/mdc-line-ripple/mdc-line-ripple.scss'), 'mdc.card': path.resolve('./packages/mdc-card/mdc-card.scss'), 'mdc.checkbox': path.resolve('./packages/mdc-checkbox/mdc-checkbox.scss'), + 'mdc.chips': path.resolve('./packages/mdc-chips/mdc-chips.scss'), 'mdc.dialog': path.resolve('./packages/mdc-dialog/mdc-dialog.scss'), 'mdc.drawer': path.resolve('./packages/mdc-drawer/mdc-drawer.scss'), 'mdc.elevation': path.resolve('./packages/mdc-elevation/mdc-elevation.scss'),