From cae6b6d40cc01956dd02a32243f19c3a29d2ec67 Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Thu, 14 Mar 2019 16:53:42 -0700 Subject: [PATCH 01/31] WIP: menu --- packages/menu/index.tsx | 124 +++++++++++++++++++++++++++++++++++++ packages/menu/package.json | 26 ++++++++ 2 files changed, 150 insertions(+) create mode 100644 packages/menu/index.tsx create mode 100644 packages/menu/package.json diff --git a/packages/menu/index.tsx b/packages/menu/index.tsx new file mode 100644 index 000000000..6ef75c515 --- /dev/null +++ b/packages/menu/index.tsx @@ -0,0 +1,124 @@ +// The MIT License +// +// Copyright (c) 2018 Google, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import * as React from 'react'; +import * as classnames from 'classnames'; +import {MDCMenuFoundation} from '@material/menu/foundation'; +import {MDCMenuAdapter} from '@material/menu/adapter'; + +export interface MenuSurfaceProps extends React.HTMLProps { + className?: string; + anchorElement?: HTMLElement; + anchorCorner?: number; + anchorMargin?: { + top?: number; + left?: number; + bottom?: number; + right?: number; + }; + styles?: React.CSSProperties; + coordinates?: { + x: number; + y: number; + }; + onClose?: () => void; + onOpen?: () => void; + onKeyDown?: (event: React.KeyboardEvent) => void; + quickOpen?: boolean; + open?: boolean; + fixed?: boolean; +}; + +export interface MenuSurfaceState { + transformOrigin: string; + maxHeight?: number; + styleLeft?: number; + styleRight?: number; + styleTop?: number; + styleBottom?: number; + classList: Set; +}; + +class MenuSurface extends React.Component { + menuSurfaceElement: React.RefObject = React.createRef(); + previousFocus: HTMLElement | null = null; + foundation: MDCMenuSurfaceFoundation; + handleWindowClick?: EventListener; + registerWindowClickListener?: () => void; + deregisterWindowClickListener?: () => void; + firstFocusableElement: HTMLElement | null = null; + lastFocusableElement: HTMLElement | null = null; + + state: MenuSurfaceState = { + transformOrigin: '', + maxHeight: undefined, + styleLeft: undefined, + styleRight: undefined, + styleTop: undefined, + styleBottom: undefined, + classList: new Set(), + }; + + static defaultProps: Partial = { + className: '', + styles: {}, + anchorCorner: 0, + anchorMargin: {}, + onClose: () => {}, + onOpen: () => {}, + onKeyDown: () => {}, + quickOpen: false, + open: false, + fixed: false, + }; + + componentDidMount() { + + } + + componentDidUpdate(prevProps: MenuSurfaceProps) { + + } + + componentWillUnmount() { + if (this.foundation) { + this.foundation.destroy(); + } + } + render() { + + return ( +
+ {children} +
+ ); + } +} + +export default MenuSurface; +export {Corner}; diff --git a/packages/menu/package.json b/packages/menu/package.json new file mode 100644 index 000000000..4d5385fe9 --- /dev/null +++ b/packages/menu/package.json @@ -0,0 +1,26 @@ +{ + "name": "@material/react-menu", + "version": "0.0.0", + "description": "Material Components React Menu", + "license": "MIT", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "keywords": [ + "mdc web react", + "material components react", + "material design", + "menu" + ], + "repository": { + "type": "git", + "url": "https://github.com/material-components/material-components-web-react.git" + }, + "dependencies": { + "@material/menu": "^1.0.1", + "classnames": "^2.2.5", + "react": "^16.4.2" + }, + "publishConfig": { + "access": "public" + } +} From e237d30a53aea6602b186bc9b75174bbc2d6ac2e Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Fri, 15 Mar 2019 09:39:20 -0700 Subject: [PATCH 02/31] WIP: Menu --- packages/menu/index.scss | 23 +++++++++++++++++ packages/menu/index.tsx | 54 ++++++++-------------------------------- 2 files changed, 33 insertions(+), 44 deletions(-) create mode 100644 packages/menu/index.scss diff --git a/packages/menu/index.scss b/packages/menu/index.scss new file mode 100644 index 000000000..78eea0d14 --- /dev/null +++ b/packages/menu/index.scss @@ -0,0 +1,23 @@ +// The MIT License +// +// Copyright (c) 2019 Google, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +@import "@material/menu/mdc-menu"; diff --git a/packages/menu/index.tsx b/packages/menu/index.tsx index 6ef75c515..09db954c9 100644 --- a/packages/menu/index.tsx +++ b/packages/menu/index.tsx @@ -1,6 +1,6 @@ // The MIT License // -// Copyright (c) 2018 Google, Inc. +// Copyright (c) 2019 Google, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -21,54 +21,20 @@ // THE SOFTWARE. import * as React from 'react'; -import * as classnames from 'classnames'; +import classnames from 'classnames'; import {MDCMenuFoundation} from '@material/menu/foundation'; import {MDCMenuAdapter} from '@material/menu/adapter'; -export interface MenuSurfaceProps extends React.HTMLProps { - className?: string; - anchorElement?: HTMLElement; - anchorCorner?: number; - anchorMargin?: { - top?: number; - left?: number; - bottom?: number; - right?: number; - }; - styles?: React.CSSProperties; - coordinates?: { - x: number; - y: number; - }; - onClose?: () => void; - onOpen?: () => void; - onKeyDown?: (event: React.KeyboardEvent) => void; - quickOpen?: boolean; - open?: boolean; - fixed?: boolean; +export interface MenuProps extends React.HTMLProps { + }; -export interface MenuSurfaceState { - transformOrigin: string; - maxHeight?: number; - styleLeft?: number; - styleRight?: number; - styleTop?: number; - styleBottom?: number; - classList: Set; +export interface MenuState { + }; -class MenuSurface extends React.Component { - menuSurfaceElement: React.RefObject = React.createRef(); - previousFocus: HTMLElement | null = null; - foundation: MDCMenuSurfaceFoundation; - handleWindowClick?: EventListener; - registerWindowClickListener?: () => void; - deregisterWindowClickListener?: () => void; - firstFocusableElement: HTMLElement | null = null; - lastFocusableElement: HTMLElement | null = null; - - state: MenuSurfaceState = { +class MenuSurface extends React.Component { + state: MenuState = { transformOrigin: '', maxHeight: undefined, styleLeft: undefined, @@ -78,7 +44,7 @@ class MenuSurface extends React.Component { classList: new Set(), }; - static defaultProps: Partial = { + static defaultProps: Partial = { className: '', styles: {}, anchorCorner: 0, @@ -95,7 +61,7 @@ class MenuSurface extends React.Component { } - componentDidUpdate(prevProps: MenuSurfaceProps) { + componentDidUpdate(prevProps: MenuProps) { } From f6cadefeb0f1e7d8e6434591372c7e7245e90939 Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Wed, 20 Mar 2019 15:48:22 -0700 Subject: [PATCH 03/31] fix: menu with seenshot --- packages/list/index.tsx | 2 +- packages/menu-surface/index.tsx | 1 - packages/menu/MenuList.tsx | 99 ++++++++++++++++ packages/menu/MenuListItem.tsx | 51 ++++++++ packages/menu/index.tsx | 142 ++++++++++++++++++----- packages/menu/package.json | 4 +- test/screenshot/menu/index.scss | 0 test/screenshot/menu/index.tsx | 35 ++++++ test/screenshot/screenshot-test-urls.tsx | 1 + test/unit/menu-surface/index.test.tsx | 2 +- 10 files changed, 305 insertions(+), 32 deletions(-) create mode 100644 packages/menu/MenuList.tsx create mode 100644 packages/menu/MenuListItem.tsx create mode 100644 test/screenshot/menu/index.scss create mode 100644 test/screenshot/menu/index.tsx diff --git a/packages/list/index.tsx b/packages/list/index.tsx index 3b598b7f0..bfa1bb933 100644 --- a/packages/list/index.tsx +++ b/packages/list/index.tsx @@ -68,7 +68,7 @@ export default class List extends React.Com foundation!: MDCListFoundation; hasInitializedListItem = false; - private listElement = React.createRef(); + private listElement = React.createRef(); static defaultProps: Partial> = { 'className': '', diff --git a/packages/menu-surface/index.tsx b/packages/menu-surface/index.tsx index fcd1e6ec5..d4279b9c1 100644 --- a/packages/menu-surface/index.tsx +++ b/packages/menu-surface/index.tsx @@ -45,7 +45,6 @@ export interface MenuSurfaceProps extends React.HTMLProps { }; onClose?: () => void; onOpen?: () => void; - onKeyDown?: (event: React.KeyboardEvent) => void; quickOpen?: boolean; open?: boolean; fixed?: boolean; diff --git a/packages/menu/MenuList.tsx b/packages/menu/MenuList.tsx new file mode 100644 index 000000000..20aee663a --- /dev/null +++ b/packages/menu/MenuList.tsx @@ -0,0 +1,99 @@ +// The MIT License +// +// Copyright (c) 2019 Google, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import * as React from 'react'; +import List, {ListProps} from '@material/react-list'; +import {MDCMenuFoundation} from '@material/menu/foundation'; + +export interface MenuListProps extends Exclude, 'ref'> { + innerRef?: React.Ref>; + handleItemAction?: MDCMenuFoundation['handleItemAction']; +}; + +class MenuList + extends React.Component, {}> { + private listInstance = React.createRef(); + + static defaultProps: Partial> = { + className: '', + handleSelect: () => {}, + handleItemAction: () => {}, + }; + + get listElements(): Element[] { + if (!this.listInstance.current) { + return []; + } + return this.listInstance.current.listElements; + } + + handleSelect: ListProps['handleSelect'] = (activatedItemIndex, selected) => { + this.props.handleSelect!(activatedItemIndex, selected); + this.props.handleItemAction!(this.listElements[activatedItemIndex]); + } + + + attachRef: React.Ref> = (node) => { + const {innerRef} = this.props; + + // https://github.com/facebook/react/issues/13029#issuecomment-410002316 + // @ts-ignore this is acceptable according to the comment above + this.listInstance.current = node; + + if (!innerRef) { + return; + } + + if (typeof innerRef !== 'function') { + // @ts-ignore same as above + innerRef.current = node; + } else { + innerRef(node); + } + } + + render() { + const { + 'aria-hidden': ariaHidden, + handleSelect, + role, + children, + ...otherProps + } = this.props; + + + return ( + + {children} + + ); + } + +} + +export default MenuList; diff --git a/packages/menu/MenuListItem.tsx b/packages/menu/MenuListItem.tsx new file mode 100644 index 000000000..6fc33232a --- /dev/null +++ b/packages/menu/MenuListItem.tsx @@ -0,0 +1,51 @@ +// The MIT License +// +// Copyright (c) 2019 Google, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import * as React from 'react'; +import {ListItem, ListItemProps} from '@material/react-list'; + +export interface MenuListItemProps extends ListItemProps { + children?: React.ReactNode; + ref?: React.Ref; +} + +const MenuListItem + = ( + props: MenuListItemProps +): React.ReactElement> => { + const { + role = 'menuitem', + children, + ...otherProps + } = props; + + return ( + + {children} + + ); +} + +export default MenuListItem; diff --git a/packages/menu/index.tsx b/packages/menu/index.tsx index 09db954c9..7cd79b9f0 100644 --- a/packages/menu/index.tsx +++ b/packages/menu/index.tsx @@ -24,45 +24,49 @@ import * as React from 'react'; import classnames from 'classnames'; import {MDCMenuFoundation} from '@material/menu/foundation'; import {MDCMenuAdapter} from '@material/menu/adapter'; +import MenuSurface, {MenuSurfaceProps} from '@material/react-menu-surface'; +import MenuList from './MenuList'; +import MenuListItem from './MenuListItem'; -export interface MenuProps extends React.HTMLProps { - +const {cssClasses} = MDCMenuFoundation; + +export interface MenuProps extends Exclude { + children: React.ReactElement; + handleSelected?: (index: number, item: Element) => void; }; export interface MenuState { - + classList: Set; + open: boolean; }; -class MenuSurface extends React.Component { +class Menu extends React.Component { + + foundation!: MDCMenuFoundation; + state: MenuState = { - transformOrigin: '', - maxHeight: undefined, - styleLeft: undefined, - styleRight: undefined, - styleTop: undefined, - styleBottom: undefined, classList: new Set(), + open: false, }; static defaultProps: Partial = { className: '', - styles: {}, - anchorCorner: 0, - anchorMargin: {}, - onClose: () => {}, - onOpen: () => {}, - onKeyDown: () => {}, - quickOpen: false, open: false, - fixed: false, + onKeyDown: () => {}, + handleSelected: () => {}, }; componentDidMount() { - + this.foundation = new MDCMenuFoundation(this.adapter); + // if (!isList(this.props.children)) { + // throw new Error('child passed to menu must be of type List'); + // } } componentDidUpdate(prevProps: MenuProps) { - + if (this.props.open !== prevProps.open) { + this.setState({open: this.props.open!}); + } } componentWillUnmount() { @@ -70,21 +74,103 @@ class MenuSurface extends React.Component { this.foundation.destroy(); } } + + get listElements(): Element[] { + // TODO: do a find of .mdc-list so that people using styled-components can style the list + return []; + // return this.props.children.listElements; + } + + get classes() { + const {className} = this.props; + const {classList} = this.state; + return classnames('mdc-menu', Array.from(classList), className); + } + + get adapter(): MDCMenuAdapter { + return { + addClassToElementAtIndex: (index, className) => { + const list = this.listElements; + list[index].classList.add(className); + }, + removeClassFromElementAtIndex: (index, className) => { + const list = this.listElements; + list[index].classList.remove(className); + }, + addAttributeToElementAtIndex: (index, attr, value) => { + const list = this.listElements; + list[index].setAttribute(attr, value); + }, + removeAttributeFromElementAtIndex: (index, attr) => { + const list = this.listElements; + list[index].removeAttribute(attr); + }, + elementContainsClass: (element, className) => element.classList.contains(className), + closeSurface: () => this.setState({open: false}), + getElementIndex: (element) => this.listElements.indexOf(element), + getParentElement: (element) => element.parentElement, + getSelectedElementIndex: (selectionGroup) => { + const selectedListItem = selectionGroup.querySelector(`.${cssClasses.MENU_SELECTED_LIST_ITEM}`); + return selectedListItem ? this.listElements.indexOf(selectedListItem) : -1; + }, + notifySelected: (evtData) => this.props.handleSelected!( + evtData.index, + this.listElements[evtData.index], + ), + }; + } + + handleKeyDown: React.KeyboardEventHandler = (evt) => { + const {onKeyDown} = this.props; + if (onKeyDown) { + onKeyDown(evt); + } + this.foundation.handleKeydown(evt.nativeEvent); + } + + handleOpen: MenuSurfaceProps['onOpen'] = () => { + const {onOpen} = this.props; + if (onOpen) { + onOpen(); + } + if (this.listElements.length > 0) { + (this.listElements[0] as HTMLElement).focus(); + } + } + render() { + const { + open, + onKeyDown, + onOpen, + children, + ref, + ...otherProps + } = this.props; return ( -
- {children} -
+ {this.renderChild()} + ); } + + + renderChild() { + const {children} = this.props; + const updatedProps = { + handleItemAction: this.foundation.handleItemAction, + ...children.props, + } + return React.cloneElement(children, updatedProps); + } } -export default MenuSurface; -export {Corner}; +export default Menu; +export {MenuList, MenuListItem}; \ No newline at end of file diff --git a/packages/menu/package.json b/packages/menu/package.json index 4d5385fe9..40e891e60 100644 --- a/packages/menu/package.json +++ b/packages/menu/package.json @@ -17,7 +17,9 @@ }, "dependencies": { "@material/menu": "^1.0.1", - "classnames": "^2.2.5", + "@material/react-list": "^0.11.0", + "@material/react-menu-surface": "^0.11.0", + "classnames": "^2.2.6", "react": "^16.4.2" }, "publishConfig": { diff --git a/test/screenshot/menu/index.scss b/test/screenshot/menu/index.scss new file mode 100644 index 000000000..e69de29bb diff --git a/test/screenshot/menu/index.tsx b/test/screenshot/menu/index.tsx new file mode 100644 index 000000000..5a706c79a --- /dev/null +++ b/test/screenshot/menu/index.tsx @@ -0,0 +1,35 @@ +import * as React from 'react'; +import '../../../packages/menu/index.scss'; +import './index.scss'; +import Menu, {MenuList, MenuListItem} from '../../../packages/menu/index'; +import {ListItemText} from '../../../packages/list/index'; + +// type MenuButtonProps = { + +// }; + +// type MenuButtonState = { +// }; + +const MenuScreenshotTest = () => { + const menuOptions = [ + 'Save', + 'Edit', + 'Cut', + 'Copy', + 'Paste', + ]; + + return ( + + + {menuOptions.map((option, index) => ( + + {option} + + ))} + + + ); +} +export default MenuScreenshotTest; diff --git a/test/screenshot/screenshot-test-urls.tsx b/test/screenshot/screenshot-test-urls.tsx index 672044b87..2396f1fe8 100644 --- a/test/screenshot/screenshot-test-urls.tsx +++ b/test/screenshot/screenshot-test-urls.tsx @@ -15,6 +15,7 @@ const urls = [ 'icon-button', 'layout-grid', 'material-icon', + 'menu', 'menu-surface', 'notched-outline', 'radio', diff --git a/test/unit/menu-surface/index.test.tsx b/test/unit/menu-surface/index.test.tsx index 376b39a21..3d83fe734 100644 --- a/test/unit/menu-surface/index.test.tsx +++ b/test/unit/menu-surface/index.test.tsx @@ -497,7 +497,7 @@ test('onKeyDown calls props.onKeyDown', () => { test('onKeyDown calls foundation.handleKeydown', () => { const wrapper = shallow(hello); - wrapper.instance().foundation.handleKeydown = td.func<(event: KeyboardEvent) => {}>(); + wrapper.instance().foundation.handleKeydown = td.func() as (event: React.KeyboardEvent) => {}; const evt = {nativeEvent: ({} as KeyboardEvent)} as React.KeyboardEvent; wrapper.instance().handleKeydown(evt); td.verify(wrapper.instance().foundation.handleKeydown(evt.nativeEvent), {times: 1}); From 14a1183ef2df7b134ae196a94dd160ed60ece32f Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Thu, 21 Mar 2019 16:53:39 -0700 Subject: [PATCH 04/31] WIP: selection menu --- packages/list/index.tsx | 2 +- packages/menu/MenuList.tsx | 4 +- packages/menu/index.tsx | 31 +++++++++---- test/screenshot/menu/index.tsx | 79 ++++++++++++++++++++++++---------- 4 files changed, 84 insertions(+), 32 deletions(-) diff --git a/packages/list/index.tsx b/packages/list/index.tsx index bfa1bb933..7e79bd904 100644 --- a/packages/list/index.tsx +++ b/packages/list/index.tsx @@ -122,7 +122,7 @@ export default class List extends React.Com } componentWillUnmount() { - this.foundation.destroy(); + this.foundation.destroy(); } initializeListType = () => { diff --git a/packages/menu/MenuList.tsx b/packages/menu/MenuList.tsx index 20aee663a..e7e73d192 100644 --- a/packages/menu/MenuList.tsx +++ b/packages/menu/MenuList.tsx @@ -47,6 +47,7 @@ class MenuList } handleSelect: ListProps['handleSelect'] = (activatedItemIndex, selected) => { + debugger this.props.handleSelect!(activatedItemIndex, selected); this.props.handleItemAction!(this.listElements[activatedItemIndex]); } @@ -75,8 +76,10 @@ class MenuList const { 'aria-hidden': ariaHidden, handleSelect, + handleItemAction, role, children, + ref, ...otherProps } = this.props; @@ -84,7 +87,6 @@ class MenuList return ( { - + menuListElement = React.createRef(); foundation!: MDCMenuFoundation; state: MenuState = { classList: new Set(), - open: false, + open: this.props.open || false, }; static defaultProps: Partial = { @@ -77,8 +77,13 @@ class Menu extends React.Component { get listElements(): Element[] { // TODO: do a find of .mdc-list so that people using styled-components can style the list - return []; - // return this.props.children.listElements; + if (!(this.menuListElement + && this.menuListElement.current + && this.menuListElement.current.listElements.length < 0)) { + return []; + } + console.log('hi', this.menuListElement.current.listElements) + return this.menuListElement.current.listElements; } get classes() { @@ -144,12 +149,15 @@ class Menu extends React.Component { onKeyDown, onOpen, children, + className, + handleSelected, ref, ...otherProps } = this.props; return ( { renderChild() { const {children} = this.props; - const updatedProps = { - handleItemAction: this.foundation.handleItemAction, - ...children.props, + let handleItemAction: MDCMenuFoundation['handleItemAction'] = () => {}; + if (this.foundation) { + handleItemAction = this.foundation.handleItemAction; } + const updatedProps: MenuListProps = { + handleItemAction, + ref: this.menuListElement, + wrapFocus: true, + ...children.props, + }; + return React.cloneElement(children, updatedProps); } } diff --git a/test/screenshot/menu/index.tsx b/test/screenshot/menu/index.tsx index 5a706c79a..0ac22c84f 100644 --- a/test/screenshot/menu/index.tsx +++ b/test/screenshot/menu/index.tsx @@ -8,28 +8,63 @@ import {ListItemText} from '../../../packages/list/index'; // }; -// type MenuButtonState = { -// }; +interface MenuState { + coordinates?: {x: number, y: number}; + open: boolean; +}; + +class MenuScreenshotTest extends React.Component<{}, MenuState> { + + state = { + open: true, + coordinates: undefined, + }; + + componentDidMount() { + // @ts-ignore + window.addEventListener('contextmenu', this.rightClickCallback); + } + + componentWillUnmount() { + // @ts-ignore + window.removeEventListener('contextmenu', this.rightClickCallback); + } + + private rightClickCallback: React.MouseEventHandler = (event: React.MouseEvent) => { + this.setState({ + open: !this.state.open, + coordinates: {x: event.clientX, y: event.clientY}, + }); + event.preventDefault(); + } + private onClose = () => { + this.setState({open: false}); + } + + render() { + const menuOptions = [ + 'Save', + 'Edit', + 'Cut', + 'Copy', + 'Paste', + ]; -const MenuScreenshotTest = () => { - const menuOptions = [ - 'Save', - 'Edit', - 'Cut', - 'Copy', - 'Paste', - ]; - - return ( - - - {menuOptions.map((option, index) => ( - - {option} - - ))} - - - ); + return ( + + + {menuOptions.map((option, index) => ( + + + + ))} + + + ); + } } export default MenuScreenshotTest; From e80d45813c2954ad1f1f5ac207e0da18086b218c Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Wed, 27 Mar 2019 16:08:39 -0700 Subject: [PATCH 05/31] WIP: menu --- packages/list/ListItem.tsx | 1 + packages/list/index.tsx | 1 + packages/menu/MenuList.tsx | 8 +++++--- packages/menu/MenuListItem.tsx | 1 - packages/menu/index.tsx | 3 +-- test/unit/menu-surface/index.test.tsx | 2 +- 6 files changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/list/ListItem.tsx b/packages/list/ListItem.tsx index b0f75abea..4d4f010f6 100644 --- a/packages/list/ListItem.tsx +++ b/packages/list/ListItem.tsx @@ -34,6 +34,7 @@ export interface ListItemProps extends React.HTMLProps { tag?: string; activated?: boolean; selected?: boolean; + ref?: React.Ref; }; // TODO: convert to functional component diff --git a/packages/list/index.tsx b/packages/list/index.tsx index 7e79bd904..9813a0601 100644 --- a/packages/list/index.tsx +++ b/packages/list/index.tsx @@ -49,6 +49,7 @@ export interface ListProps extends React.HTMLProps | ListItem[] | React.ReactNode; + ref?: React.Ref; }; function isReactText(element: any): element is React.ReactText { diff --git a/packages/menu/MenuList.tsx b/packages/menu/MenuList.tsx index e7e73d192..e650b4d1d 100644 --- a/packages/menu/MenuList.tsx +++ b/packages/menu/MenuList.tsx @@ -24,8 +24,10 @@ import * as React from 'react'; import List, {ListProps} from '@material/react-list'; import {MDCMenuFoundation} from '@material/menu/foundation'; +type RefCallback = (node: T | null) => void; + export interface MenuListProps extends Exclude, 'ref'> { - innerRef?: React.Ref>; + innerRef?: RefCallback | React.RefObject; handleItemAction?: MDCMenuFoundation['handleItemAction']; }; @@ -47,13 +49,12 @@ class MenuList } handleSelect: ListProps['handleSelect'] = (activatedItemIndex, selected) => { - debugger this.props.handleSelect!(activatedItemIndex, selected); this.props.handleItemAction!(this.listElements[activatedItemIndex]); } - attachRef: React.Ref> = (node) => { + attachRef = (node: List | null) => { const {innerRef} = this.props; // https://github.com/facebook/react/issues/13029#issuecomment-410002316 @@ -89,6 +90,7 @@ class MenuList aria-hidden={ariaHidden !== undefined ? ariaHidden : 'true'} role={role || 'menu'} handleSelect={this.handleSelect} + ref={this.listInstance} {...otherProps} > {children} diff --git a/packages/menu/MenuListItem.tsx b/packages/menu/MenuListItem.tsx index 6fc33232a..f33747283 100644 --- a/packages/menu/MenuListItem.tsx +++ b/packages/menu/MenuListItem.tsx @@ -25,7 +25,6 @@ import {ListItem, ListItemProps} from '@material/react-list'; export interface MenuListItemProps extends ListItemProps { children?: React.ReactNode; - ref?: React.Ref; } const MenuListItem diff --git a/packages/menu/index.tsx b/packages/menu/index.tsx index cd0689633..d07ed59aa 100644 --- a/packages/menu/index.tsx +++ b/packages/menu/index.tsx @@ -79,10 +79,9 @@ class Menu extends React.Component { // TODO: do a find of .mdc-list so that people using styled-components can style the list if (!(this.menuListElement && this.menuListElement.current - && this.menuListElement.current.listElements.length < 0)) { + && this.menuListElement.current.listElements.length >= 0 )) { return []; } - console.log('hi', this.menuListElement.current.listElements) return this.menuListElement.current.listElements; } diff --git a/test/unit/menu-surface/index.test.tsx b/test/unit/menu-surface/index.test.tsx index 3d83fe734..1f4799d98 100644 --- a/test/unit/menu-surface/index.test.tsx +++ b/test/unit/menu-surface/index.test.tsx @@ -497,7 +497,7 @@ test('onKeyDown calls props.onKeyDown', () => { test('onKeyDown calls foundation.handleKeydown', () => { const wrapper = shallow(hello); - wrapper.instance().foundation.handleKeydown = td.func() as (event: React.KeyboardEvent) => {}; + wrapper.instance().foundation.handleKeydown = td.func() as (event: KeyboardEvent) => {}; const evt = {nativeEvent: ({} as KeyboardEvent)} as React.KeyboardEvent; wrapper.instance().handleKeydown(evt); td.verify(wrapper.instance().foundation.handleKeydown(evt.nativeEvent), {times: 1}); From 8d0b52a514739f1f162a53adb62b8a91edfa2ddf Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Wed, 27 Mar 2019 17:28:14 -0700 Subject: [PATCH 06/31] WIP: getting menulistitem to be interpretted as a listitem --- packages/list/ListItem.tsx | 4 +++- packages/list/index.tsx | 10 ++++++++-- packages/menu/MenuList.tsx | 24 ++++++++++++------------ packages/menu/MenuListItem.tsx | 1 + 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/packages/list/ListItem.tsx b/packages/list/ListItem.tsx index 4d4f010f6..8fc92b041 100644 --- a/packages/list/ListItem.tsx +++ b/packages/list/ListItem.tsx @@ -35,6 +35,7 @@ export interface ListItemProps extends React.HTMLProps { activated?: boolean; selected?: boolean; ref?: React.Ref; + renderAsListItem?: boolean; }; // TODO: convert to functional component @@ -48,6 +49,7 @@ export default class ListItem extends React static defaultProps: Partial> = { checkboxList: false, radioList: false, + renderAsListItem: false, className: '', tabIndex: -1, onKeyDown: () => {}, @@ -85,9 +87,9 @@ export default class ListItem extends React role, checkboxList, radioList, + renderAsListItem, /* eslint-enable no-unused-vars */ tag: Tag, - ...otherProps } = this.props; return ( diff --git a/packages/list/index.tsx b/packages/list/index.tsx index 9813a0601..62b530110 100644 --- a/packages/list/index.tsx +++ b/packages/list/index.tsx @@ -317,8 +317,13 @@ export default class List extends React.Com } renderChild = (child: React.ReactElement> | React.ReactChild) => { - if (!isReactText(child) && isListItem(child)) { - return this.renderListItem(child, this.listItemCount++); + if (!isReactText(child)) { + const {renderAsListItem} = child.props; + debugger + if (renderAsListItem || isListItem(child)) { + console.log('MEOW') + return this.renderListItem(child, this.listItemCount++); + } } return child; }; @@ -359,6 +364,7 @@ export default class List extends React.Com checkboxList, radioList, onKeyDown: (e: React.KeyboardEvent) => { + console.log('meow') onKeyDown!(e); this.handleKeyDown(e, index); }, diff --git a/packages/menu/MenuList.tsx b/packages/menu/MenuList.tsx index e650b4d1d..af7f7d5b1 100644 --- a/packages/menu/MenuList.tsx +++ b/packages/menu/MenuList.tsx @@ -49,6 +49,7 @@ class MenuList } handleSelect: ListProps['handleSelect'] = (activatedItemIndex, selected) => { + console.log('SELECTION') this.props.handleSelect!(activatedItemIndex, selected); this.props.handleItemAction!(this.listElements[activatedItemIndex]); } @@ -84,18 +85,17 @@ class MenuList ...otherProps } = this.props; - - return ( - - {children} - - ); + return ( + + {children} + + ); } } diff --git a/packages/menu/MenuListItem.tsx b/packages/menu/MenuListItem.tsx index f33747283..828ce34c5 100644 --- a/packages/menu/MenuListItem.tsx +++ b/packages/menu/MenuListItem.tsx @@ -40,6 +40,7 @@ const MenuListItem return ( {children} From cb1694b6639a2872063535af699e1dbdd06c455f Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Thu, 28 Mar 2019 14:01:47 -0700 Subject: [PATCH 07/31] fix: menu list handleActionitem --- package-lock.json | 2 +- packages/list/index.tsx | 3 --- packages/menu/MenuList.tsx | 4 +--- packages/menu/MenuListItem.tsx | 39 ++++++++++++++++++---------------- packages/menu/index.tsx | 37 ++++++++++++++++++++++---------- test/screenshot/menu/index.tsx | 5 +---- 6 files changed, 50 insertions(+), 40 deletions(-) diff --git a/package-lock.json b/package-lock.json index a88834b7c..67fbae738 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17791,7 +17791,7 @@ }, "ts-loader": { "version": "3.5.0", - "resolved": "http://registry.npmjs.org/ts-loader/-/ts-loader-3.5.0.tgz", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-3.5.0.tgz", "integrity": "sha512-JTia3kObhTk36wPFgy0RnkZReiusYx7Le9IhcUWRrCTcFcr6Dy1zGsFd3x8DG4gevlbN65knI8W50FfoykXcng==", "dev": true, "requires": { diff --git a/packages/list/index.tsx b/packages/list/index.tsx index 62b530110..9e10962c6 100644 --- a/packages/list/index.tsx +++ b/packages/list/index.tsx @@ -319,9 +319,7 @@ export default class List extends React.Com renderChild = (child: React.ReactElement> | React.ReactChild) => { if (!isReactText(child)) { const {renderAsListItem} = child.props; - debugger if (renderAsListItem || isListItem(child)) { - console.log('MEOW') return this.renderListItem(child, this.listItemCount++); } } @@ -364,7 +362,6 @@ export default class List extends React.Com checkboxList, radioList, onKeyDown: (e: React.KeyboardEvent) => { - console.log('meow') onKeyDown!(e); this.handleKeyDown(e, index); }, diff --git a/packages/menu/MenuList.tsx b/packages/menu/MenuList.tsx index af7f7d5b1..22707c3bc 100644 --- a/packages/menu/MenuList.tsx +++ b/packages/menu/MenuList.tsx @@ -31,8 +31,7 @@ export interface MenuListProps extends Exclude - extends React.Component, {}> { +class MenuList extends React.Component, {}> { private listInstance = React.createRef(); static defaultProps: Partial> = { @@ -49,7 +48,6 @@ class MenuList } handleSelect: ListProps['handleSelect'] = (activatedItemIndex, selected) => { - console.log('SELECTION') this.props.handleSelect!(activatedItemIndex, selected); this.props.handleItemAction!(this.listElements[activatedItemIndex]); } diff --git a/packages/menu/MenuListItem.tsx b/packages/menu/MenuListItem.tsx index 828ce34c5..ea05adccf 100644 --- a/packages/menu/MenuListItem.tsx +++ b/packages/menu/MenuListItem.tsx @@ -27,25 +27,28 @@ export interface MenuListItemProps extends ListItemProps { children?: React.ReactNode; } -const MenuListItem - = ( - props: MenuListItemProps -): React.ReactElement> => { - const { - role = 'menuitem', - children, - ...otherProps - } = props; +class MenuListItem extends React.Component, {}> { + static defaultProps: Partial> = { + ...ListItem.defaultProps, + renderAsListItem: true, + }; - return ( - - {children} - - ); + render() { + const { + role = 'menuitem', + children, + ...otherProps + } = this.props; + + return ( + + {children} + + ); + } } export default MenuListItem; diff --git a/packages/menu/index.tsx b/packages/menu/index.tsx index d07ed59aa..acc141966 100644 --- a/packages/menu/index.tsx +++ b/packages/menu/index.tsx @@ -38,13 +38,16 @@ export interface MenuProps extends Exclude { export interface MenuState { classList: Set; open: boolean; + foundation?: MDCMenuFoundation; }; class Menu extends React.Component { menuListElement = React.createRef(); - foundation!: MDCMenuFoundation; - + + // need foundation on state so that it initializes MenuList with + // foundation.handleItemAction state: MenuState = { + foundation: undefined, classList: new Set(), open: this.props.open || false, }; @@ -57,7 +60,9 @@ class Menu extends React.Component { }; componentDidMount() { - this.foundation = new MDCMenuFoundation(this.adapter); + const foundation = new MDCMenuFoundation(this.adapter); + foundation.init(); + this.setState({foundation}); // if (!isList(this.props.children)) { // throw new Error('child passed to menu must be of type List'); // } @@ -70,8 +75,8 @@ class Menu extends React.Component { } componentWillUnmount() { - if (this.foundation) { - this.foundation.destroy(); + if (this.state.foundation) { + this.state.foundation.destroy(); } } @@ -129,7 +134,7 @@ class Menu extends React.Component { if (onKeyDown) { onKeyDown(evt); } - this.foundation.handleKeydown(evt.nativeEvent); + this.state.foundation && this.state.foundation.handleKeydown(evt.nativeEvent); } handleOpen: MenuSurfaceProps['onOpen'] = () => { @@ -171,20 +176,30 @@ class Menu extends React.Component { renderChild() { const {children} = this.props; + const {foundation} = this.state; let handleItemAction: MDCMenuFoundation['handleItemAction'] = () => {}; - if (this.foundation) { - handleItemAction = this.foundation.handleItemAction; + if (foundation) { + // this is to avoid a `handleItemAction` of undefined error + handleItemAction = foundation.handleItemAction.bind(foundation); } const updatedProps: MenuListProps = { + // children.props must appear first + ...children.props, handleItemAction, ref: this.menuListElement, wrapFocus: true, - ...children.props, }; - return React.cloneElement(children, updatedProps); } } export default Menu; -export {MenuList, MenuListItem}; \ No newline at end of file +export {MenuList, MenuListItem}; +export { + ListDivider as MenuListDivider, + ListGroup as MenuListGroup, + ListGroupSubheader as MenuListGroupSubheader, + ListItemGraphic as MenuListGraphic, + ListItemMeta as MenuListMeta, + ListItemText as MenuListItemText, +} from '@material/react-list'; diff --git a/test/screenshot/menu/index.tsx b/test/screenshot/menu/index.tsx index 0ac22c84f..a82c03040 100644 --- a/test/screenshot/menu/index.tsx +++ b/test/screenshot/menu/index.tsx @@ -4,10 +4,6 @@ import './index.scss'; import Menu, {MenuList, MenuListItem} from '../../../packages/menu/index'; import {ListItemText} from '../../../packages/list/index'; -// type MenuButtonProps = { - -// }; - interface MenuState { coordinates?: {x: number, y: number}; open: boolean; @@ -55,6 +51,7 @@ class MenuScreenshotTest extends React.Component<{}, MenuState> { open={this.state.open} onClose={this.onClose} coordinates={this.state.coordinates} + handleSelected={() => console.log('select')} > {menuOptions.map((option, index) => ( From aafb2d1f1b7fe214d640c4f8db37adb9cda5b50c Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Thu, 28 Mar 2019 16:21:30 -0700 Subject: [PATCH 08/31] fix: add readme --- packages/menu/README.md | 210 +++++++++++++++++++++++++++++++++ packages/menu/index.tsx | 3 - packages/menu/package.json | 2 +- test/screenshot/menu/index.tsx | 8 +- 4 files changed, 215 insertions(+), 8 deletions(-) create mode 100644 packages/menu/README.md diff --git a/packages/menu/README.md b/packages/menu/README.md new file mode 100644 index 000000000..d5cb6d59d --- /dev/null +++ b/packages/menu/README.md @@ -0,0 +1,210 @@ +# React Menu + +A React version of an [MDC Menu](https://github.com/material-components/material-components-web/tree/master/packages/mdc-menu). + +## Installation + +``` +npm install @material/react-menu +``` + +## Usage + +### Styles + +with Sass: +```js +import '@material/react-menu/index.scss'; +``` + +with CSS: +```js +import '@material/react-menu/dist/menu.css'; +``` + +### Javascript Instantiation + +```js +import React from 'react'; +import Menu, {MenuList, MenuListItem, MenuListItemText} from '@material/react-menu'; + +class MyApp extends React.Component { + state = { + open: true, + coordinates: undefined, + }; + + componentDidMount() { + window.addEventListener('contextmenu', this.rightClickCallback); + } + + componentWillUnmount() { + window.removeEventListener('contextmenu', this.rightClickCallback); + } + + rightClickCallback = (event) => { + this.setState({ + open: !this.state.open, + coordinates: {x: event.clientX, y: event.clientY}, + }); + // Must preventDefault so the system context menu doesn't appear. + // This won't be needed in other cases besides right click. + event.preventDefault(); + } + + // Must set open to false to keep menu in the correct state. + // This does not follow the controlled component pattern + // (see https://reactjs.org/docs/forms.html#controlled-components). + // Follow https://github.com/material-components/material-components-web-react/issues/785 + // to get any updates. + onClose = () => { + this.setState({open: false}); + } + + render() { + const menuOptions = [ + 'Save', + 'Edit', + 'Cut', + 'Copy', + 'Paste', + ]; + + return ( + console.log(index, item)} + > + + {menuOptions.map((option, index) => ( + + + {/* You can also use other components from list, which are documented below */} + + ))} + + + ); + } +} +``` + +### Usage with HOC's + +You may want to use Menu or other auxilary components with an HOC, such as [styled-components](https://www.styled-components.com). The only component that requires special handling is MenuListItem, since it contains a prop that needs to be passed to List. Please follow below: + +```js +import React from 'react'; +import Menu, {MenuList, MenuListItem, MenuListItemText} from '@material/react-menu'; +import styled from 'styled-components'; + +const StyledMenuListItem = styled(MenuListItem)` + color: blue; +`; + +// Ensure that you set the HOC's defaultProps to MenuListItem's defaultProps. +StyledMenuListItem.defaultProps = MenuListItem.defaultProps; + +class MenuScreenshotTest extends React.Component<{}, MenuState> { + + state = { + open: true, + }; + + onClose = () => { + this.setState({open: false}); + } + + render() { + const menuOptions = [ + 'Save', + 'Edit', + 'Cut', + 'Copy', + 'Paste', + ]; + + return ( + console.log('select')} + > + + {menuOptions.map((option, index) => ( + + + + ))} + + + ); + } +} +``` + + + +## Props + + +### Menu + +Prop Name | Type | Description +--- | --- | --- +handleSelected | (index: number, item: Element) => void | Callback that is triggered when a menu list item is selected. +onClose | () => void | Callback that is triggered when the menu closes. +open | boolean | If true, will open the menu. If false, will hide menu. + +> NOTE: onClose and open are a subset of props from Menu Surface. See [Menu Surface Props](../menu-surface/README.md#props) for other props you can pass to Menu + +### MenuList + +Prop Name | Type | Description +--- | --- | --- +innerRef | RefObject | Root Menu List element ref. +handleSelect | (activatedItemIndex: Number, selected: Number | Array) => void | Callback for handling a list item selection event. `selected` will be an Array,Number> for checkbox lists. + +> NOTE: handleSelect is a subset of props from List. See [List Props](../list/README.md#list) for other props you can pass to MenuList. + +### MenuListItem + +See [List Props](../list/README.md#listitem) for other props you can pass to MenuListItem. + +### MenuListItemText + +See [List Item Text Props](../list/README.md#listitemtext) for other props you can pass to MenuListItemText. + +### MenuListItemGraphic + +See [List Item Graphic Props](../list/README.md#listitemgraphic) for other props you can pass to MenuListItemGraphic. + +### MenuListItemMeta + +See [List Item Meta Props](../list/README.md#listitemmeta) for other props you can pass to MenuListItemMeta. + +### MenuListDivider + +See [List Divider Props](../list/README.md#listdivider) for other props you can pass to MenuListDivider. + +### MenuListGroup + +See [List Group Props](../list/README.md#listgroup) for other props you can pass to MenuListGroup. + +### MenuListGroupSubheader + +See [List Group Props](../list/README.md#listgroupsubheader) for other props you can pass to MenuListGroupSubheader. + + +## Sass Mixins + +Sass mixins may be available to customize various aspects of the components. Please refer to the +MDC Web repository for more information on what mixins are available, and how to use them. + +[Advanced Sass Mixins](https://github.com/material-components/material-components-web/blob/master/packages/mdc-menu/README.md#advanced-sass-mixins) + +## Usage with Icons + +Please see our [Best Practices doc](../../docs/best-practices.md#importing-font-icons) when importing or using icon fonts. diff --git a/packages/menu/index.tsx b/packages/menu/index.tsx index acc141966..a8b67fae6 100644 --- a/packages/menu/index.tsx +++ b/packages/menu/index.tsx @@ -63,9 +63,6 @@ class Menu extends React.Component { const foundation = new MDCMenuFoundation(this.adapter); foundation.init(); this.setState({foundation}); - // if (!isList(this.props.children)) { - // throw new Error('child passed to menu must be of type List'); - // } } componentDidUpdate(prevProps: MenuProps) { diff --git a/packages/menu/package.json b/packages/menu/package.json index 40e891e60..9f94b9fb2 100644 --- a/packages/menu/package.json +++ b/packages/menu/package.json @@ -16,7 +16,7 @@ "url": "https://github.com/material-components/material-components-web-react.git" }, "dependencies": { - "@material/menu": "^1.0.1", + "@material/menu": "^1.1.0", "@material/react-list": "^0.11.0", "@material/react-menu-surface": "^0.11.0", "classnames": "^2.2.6", diff --git a/test/screenshot/menu/index.tsx b/test/screenshot/menu/index.tsx index a82c03040..91f15d648 100644 --- a/test/screenshot/menu/index.tsx +++ b/test/screenshot/menu/index.tsx @@ -1,8 +1,7 @@ import * as React from 'react'; import '../../../packages/menu/index.scss'; import './index.scss'; -import Menu, {MenuList, MenuListItem} from '../../../packages/menu/index'; -import {ListItemText} from '../../../packages/list/index'; +import Menu, {MenuList, MenuListItem, MenuListItemText} from '../../../packages/menu/index'; interface MenuState { coordinates?: {x: number, y: number}; @@ -51,12 +50,12 @@ class MenuScreenshotTest extends React.Component<{}, MenuState> { open={this.state.open} onClose={this.onClose} coordinates={this.state.coordinates} - handleSelected={() => console.log('select')} + handleSelected={(index: number, item: Element) => console.log(index, item)} > {menuOptions.map((option, index) => ( - + ))} @@ -64,4 +63,5 @@ class MenuScreenshotTest extends React.Component<{}, MenuState> { ); } } + export default MenuScreenshotTest; From 4900f4d8829e36945c4b770c9c74e2ac537ab246 Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Thu, 28 Mar 2019 18:30:37 -0700 Subject: [PATCH 09/31] feat: add tests --- package-lock.json | 126 ++++++++++++++++++++++++++++++++ package.json | 1 + packages/list/ListItem.tsx | 6 +- packages/list/index.tsx | 10 +-- packages/menu-surface/index.tsx | 1 - packages/menu/MenuListItem.tsx | 2 +- packages/menu/README.md | 2 +- packages/menu/index.tsx | 17 ++--- test/unit/list/index.test.tsx | 14 +++- test/unit/menu/index.test.tsx | 79 ++++++++++++++++++++ 10 files changed, 235 insertions(+), 23 deletions(-) create mode 100644 test/unit/menu/index.test.tsx diff --git a/package-lock.json b/package-lock.json index 67fbae738..093a2e721 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1022,6 +1022,132 @@ } } }, + "@material/menu": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@material/menu/-/menu-1.1.0.tgz", + "integrity": "sha512-oEubeu4h5EWeaOWbDwstmWkzBSq/2qVtu476CLmaAI5joUilXaPBKpryv4F+ZRIDlVQjs5Ey7uBotxDwDELPQA==", + "dev": true, + "requires": { + "@material/base": "^1.0.0", + "@material/feature-targeting": "^0.44.1", + "@material/list": "^1.1.0", + "@material/menu-surface": "^1.1.0", + "@material/ripple": "^1.1.0", + "@material/rtl": "^0.42.0", + "tslib": "^1.9.3" + }, + "dependencies": { + "@material/animation": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-1.0.0.tgz", + "integrity": "sha512-Ed5/vggn6ZhSJ87yn3ZS1d826VJNFz73jHF2bSsgRtHDoB8KCuOwQMfdgAgDa4lKDF6CDIPCKBZPKrs2ubehdw==", + "dev": true, + "requires": { + "tslib": "^1.9.3" + } + }, + "@material/dom": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@material/dom/-/dom-1.1.0.tgz", + "integrity": "sha512-+HWW38ZaM2UBPu4+7QCusLDSf4tFT31rsEXHkTkxYSg/QpDivfPx6YDz4OmYtafmhPR1d1YjqB3MYysUHdodyw==", + "dev": true, + "requires": { + "tslib": "^1.9.3" + } + }, + "@material/elevation": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@material/elevation/-/elevation-1.1.0.tgz", + "integrity": "sha512-m4eATJvDhWK1BT+yA1iHz5mhAk8cV9olC4mjVzm4PTAqhDH2yya4WzjN1HPVHE/a65ObyZ7V4qopxu9MRocm3A==", + "dev": true, + "requires": { + "@material/animation": "^1.0.0", + "@material/feature-targeting": "^0.44.1", + "@material/theme": "^1.1.0" + } + }, + "@material/list": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@material/list/-/list-1.1.0.tgz", + "integrity": "sha512-+NqVwqhRX08kjDatwZRO/LiiOw9gl7eq2Ogi8hrWkXqYn9ARfUq3K74MeTIit9f7BGPobs86dXBaQ/mjI5HSXg==", + "dev": true, + "requires": { + "@material/base": "^1.0.0", + "@material/dom": "^1.1.0", + "@material/feature-targeting": "^0.44.1", + "@material/ripple": "^1.1.0", + "@material/rtl": "^0.42.0", + "@material/shape": "^1.0.0", + "@material/theme": "^1.1.0", + "@material/typography": "^1.0.0", + "tslib": "^1.9.3" + } + }, + "@material/menu-surface": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@material/menu-surface/-/menu-surface-1.1.0.tgz", + "integrity": "sha512-FjCA6TBgeY+mwNcjfeq5/3TCSyhtXxHrT/xQrz1LyrztuHI4Qu7bTb496pXlfPsZHQuwmo9PqW+pwP78noDf9A==", + "dev": true, + "requires": { + "@material/animation": "^1.0.0", + "@material/base": "^1.0.0", + "@material/elevation": "^1.1.0", + "@material/feature-targeting": "^0.44.1", + "@material/rtl": "^0.42.0", + "@material/shape": "^1.0.0", + "@material/theme": "^1.1.0", + "tslib": "^1.9.3" + } + }, + "@material/ripple": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-1.1.0.tgz", + "integrity": "sha512-mkfDBZAmxjpRG7V9TrfOmLxt1g/wvGHCXtYPgvH7W8ozjf53edqxLOFENEdvHbie27y9nyixzXn0gzU0HnxSeA==", + "dev": true, + "requires": { + "@material/animation": "^1.0.0", + "@material/base": "^1.0.0", + "@material/dom": "^1.1.0", + "@material/feature-targeting": "^0.44.1", + "@material/theme": "^1.1.0", + "tslib": "^1.9.3" + } + }, + "@material/rtl": { + "version": "0.42.0", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-0.42.0.tgz", + "integrity": "sha512-VrnrKJzhmspsN8WXHuxxBZ69yM5IwhCUqWr1t1eNfw3ZEvEj7i1g3P31HGowKThIN1dc1Wh4LE14rCISWCtv5w==", + "dev": true + }, + "@material/shape": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@material/shape/-/shape-1.0.0.tgz", + "integrity": "sha512-zfXEacPQZmH+ujVtaFyfAsYiF46j1QCcFzJeZVouG4pznrbA7XD6614Ywg0wbyWX5iB6hD52ld/IN+R/6oxKqA==", + "dev": true, + "requires": { + "@material/feature-targeting": "^0.44.1" + } + }, + "@material/theme": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-1.1.0.tgz", + "integrity": "sha512-YYUV9Rhbx4r/EMb/zoOYJUWjhXChNaLlH1rqt3vpNVyxRcxGqoVMGp5u1XALBCFiD9dACPKLIkKyRYa928nmPQ==", + "dev": true, + "requires": { + "@material/feature-targeting": "^0.44.1" + } + }, + "@material/typography": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@material/typography/-/typography-1.0.0.tgz", + "integrity": "sha512-Oeqbjci1cC7jTE8/n3dwnkqKe9ZeWiaE+rgMtRYtRFw1HvAw14SpGA5EEAS/Li2Hu2KZ50FYCe3HYqShfxtChA==", + "dev": true, + "requires": { + "@material/feature-targeting": "^0.44.1" + } + } + } + }, "@material/menu-surface": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@material/menu-surface/-/menu-surface-1.0.1.tgz", diff --git a/package.json b/package.json index 56211ef27..6c55cb3fe 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,7 @@ "@material/line-ripple": "^1.0.0", "@material/linear-progress": "^0.41.0", "@material/list": "^1.0.0", + "@material/menu": "^1.1.0", "@material/menu-surface": "^1.0.1", "@material/notched-outline": "^0.41.0", "@material/radio": "^0.41.0", diff --git a/packages/list/ListItem.tsx b/packages/list/ListItem.tsx index 8fc92b041..eec13c360 100644 --- a/packages/list/ListItem.tsx +++ b/packages/list/ListItem.tsx @@ -35,7 +35,7 @@ export interface ListItemProps extends React.HTMLProps { activated?: boolean; selected?: boolean; ref?: React.Ref; - renderAsListItem?: boolean; + renderWithListItemProps?: boolean; }; // TODO: convert to functional component @@ -49,7 +49,7 @@ export default class ListItem extends React static defaultProps: Partial> = { checkboxList: false, radioList: false, - renderAsListItem: false, + renderWithListItemProps: false, className: '', tabIndex: -1, onKeyDown: () => {}, @@ -87,7 +87,7 @@ export default class ListItem extends React role, checkboxList, radioList, - renderAsListItem, + renderWithListItemProps, /* eslint-enable no-unused-vars */ tag: Tag, ...otherProps diff --git a/packages/list/index.tsx b/packages/list/index.tsx index 9e10962c6..79243aeb9 100644 --- a/packages/list/index.tsx +++ b/packages/list/index.tsx @@ -53,7 +53,7 @@ export interface ListProps extends React.HTMLProps extends React.Com foundation!: MDCListFoundation; hasInitializedListItem = false; - private listElement = React.createRef(); + private listElement = React.createRef(); static defaultProps: Partial> = { 'className': '', @@ -123,7 +123,7 @@ export default class List extends React.Com } componentWillUnmount() { - this.foundation.destroy(); + this.foundation.destroy(); } initializeListType = () => { @@ -318,8 +318,8 @@ export default class List extends React.Com renderChild = (child: React.ReactElement> | React.ReactChild) => { if (!isReactText(child)) { - const {renderAsListItem} = child.props; - if (renderAsListItem || isListItem(child)) { + const {renderWithListItemProps} = child.props; + if (renderWithListItemProps || isListItem(child)) { return this.renderListItem(child, this.listItemCount++); } } diff --git a/packages/menu-surface/index.tsx b/packages/menu-surface/index.tsx index d4279b9c1..f3ec48c4f 100644 --- a/packages/menu-surface/index.tsx +++ b/packages/menu-surface/index.tsx @@ -29,7 +29,6 @@ import {Corner} from '@material/menu-surface/index'; import {MDCMenuDistance} from '@material/menu-surface/types'; export interface MenuSurfaceProps extends React.HTMLProps { - className?: string; anchorElement?: HTMLElement; anchorCorner?: number; anchorMargin?: { diff --git a/packages/menu/MenuListItem.tsx b/packages/menu/MenuListItem.tsx index ea05adccf..ec6fa153e 100644 --- a/packages/menu/MenuListItem.tsx +++ b/packages/menu/MenuListItem.tsx @@ -30,7 +30,7 @@ export interface MenuListItemProps extends ListItemProps { class MenuListItem extends React.Component, {}> { static defaultProps: Partial> = { ...ListItem.defaultProps, - renderAsListItem: true, + renderWithListItemProps: true, }; render() { diff --git a/packages/menu/README.md b/packages/menu/README.md index d5cb6d59d..e865bf818 100644 --- a/packages/menu/README.md +++ b/packages/menu/README.md @@ -195,7 +195,7 @@ See [List Group Props](../list/README.md#listgroup) for other props you can pass ### MenuListGroupSubheader -See [List Group Props](../list/README.md#listgroupsubheader) for other props you can pass to MenuListGroupSubheader. +See [List Group Subheader Props](../list/README.md#listgroupsubheader) for other props you can pass to MenuListGroupSubheader. ## Sass Mixins diff --git a/packages/menu/index.tsx b/packages/menu/index.tsx index a8b67fae6..d9a3c876d 100644 --- a/packages/menu/index.tsx +++ b/packages/menu/index.tsx @@ -25,7 +25,7 @@ import classnames from 'classnames'; import {MDCMenuFoundation} from '@material/menu/foundation'; import {MDCMenuAdapter} from '@material/menu/adapter'; import MenuSurface, {MenuSurfaceProps} from '@material/react-menu-surface'; -import MenuList, { MenuListProps } from './MenuList'; +import MenuList, {MenuListProps} from './MenuList'; import MenuListItem from './MenuListItem'; const {cssClasses} = MDCMenuFoundation; @@ -36,7 +36,6 @@ export interface MenuProps extends Exclude { }; export interface MenuState { - classList: Set; open: boolean; foundation?: MDCMenuFoundation; }; @@ -48,7 +47,6 @@ class Menu extends React.Component { // foundation.handleItemAction state: MenuState = { foundation: undefined, - classList: new Set(), open: this.props.open || false, }; @@ -78,7 +76,6 @@ class Menu extends React.Component { } get listElements(): Element[] { - // TODO: do a find of .mdc-list so that people using styled-components can style the list if (!(this.menuListElement && this.menuListElement.current && this.menuListElement.current.listElements.length >= 0 )) { @@ -87,14 +84,10 @@ class Menu extends React.Component { return this.menuListElement.current.listElements; } - get classes() { - const {className} = this.props; - const {classList} = this.state; - return classnames('mdc-menu', Array.from(classList), className); - } - get adapter(): MDCMenuAdapter { return { + // TODO: update to new class management system from + // https://github.com/material-components/material-components-web-react/pull/776/files addClassToElementAtIndex: (index, className) => { const list = this.listElements; list[index].classList.add(className); @@ -160,7 +153,7 @@ class Menu extends React.Component { { renderChild() { const {children} = this.props; const {foundation} = this.state; + if (!children) return; + let handleItemAction: MDCMenuFoundation['handleItemAction'] = () => {}; if (foundation) { // this is to avoid a `handleItemAction` of undefined error diff --git a/test/unit/list/index.test.tsx b/test/unit/list/index.test.tsx index 5209798af..2c2619897 100644 --- a/test/unit/list/index.test.tsx +++ b/test/unit/list/index.test.tsx @@ -454,7 +454,7 @@ test('renders a list with a nav tag', () => { assert.equal(wrapper.type(), 'nav'); }); -test('renders a list with children which is not DOM', () => { +test('renders a list with children of non-DOM elements', () => { const wrapper = shallow( {} {false} @@ -464,3 +464,15 @@ test('renders a list with children which is not DOM', () => { ); assert.isTrue(wrapper.children().length === 1); }); + +test('renderWithListItemProps renders passes props to element', () => { + const CustomComponent: React.FunctionComponent> + = () => ; + const wrapper = mount( + + ); + const list = wrapper.childAt(0); + const listItem = list.childAt(0); + assert.isTrue(listItem.props().radioList); + assert.isFalse(listItem.props().checkboxList); +}); \ No newline at end of file diff --git a/test/unit/menu/index.test.tsx b/test/unit/menu/index.test.tsx new file mode 100644 index 000000000..2ad1cb979 --- /dev/null +++ b/test/unit/menu/index.test.tsx @@ -0,0 +1,79 @@ +import * as React from 'react'; +import {assert} from 'chai'; +import * as td from 'testdouble'; +import {shallow, mount, ShallowWrapper, ReactWrapper} from 'enzyme'; +import Menu, {MenuState, MenuList} from '../../../packages/menu/index'; +import { coerceForTesting } from '../helpers/types'; +// import {MDCMenuFoundation} from '@material/menu/foundation'; + +suite.only('Menu'); + +function getFoundation(wrapper: ReactWrapper | ShallowWrapper) { + return coerceForTesting(wrapper.state()).foundation!; +} + +function getAdapter(wrapper: ReactWrapper | ShallowWrapper) { + // @ts-ignore adapter_ property is protected and we need to override this + return getFoundation(wrapper).adapter_; +} + +test('classNames adds classes', () => { + const wrapper = shallow(); + assert.isTrue(wrapper.hasClass('test-class-name')); + assert.isTrue(wrapper.hasClass('mdc-menu')); +}); + +test('has state.foundation', () => { + const wrapper = shallow(); + const foundation = coerceForTesting(wrapper.state()).foundation; + assert.exists(foundation); +}); + +test('calls foundation.destroy on unmount', () => { + const wrapper = shallow(); + const destroy = getFoundation(wrapper).destroy = td.func<() => void>(); + wrapper.unmount(); + td.verify(destroy(), {times: 1}); +}); + +test('props.open updates from true to false, will set state.open to false', () => { + const wrapper = shallow(); + wrapper.setProps({open: false}); + assert.isFalse(coerceForTesting(wrapper.state()).open); +}); + +test('props.open updates from false to true, will set state.open to true', () => { + const wrapper = shallow(); + wrapper.setProps({open: true}); + assert.isTrue(coerceForTesting(wrapper.state()).open); +}); + +// TODO: +// test('adapter.addClassToElementAtIndex adds a class to a listItem', () => { +// }); +// test('adapter.removeClassToElementAtIndex adds a class to a listItem', () => { +// }); + +test('adapter.addAttributeToElementAtIndex adds a class to a listItem', () => { + const wrapper = mount( + + + + ); + getAdapter(wrapper).addAttributeToElementAtIndex(0, 'tabindex', '12'); + const listItem = wrapper.find('.mdc-list-item').getDOMNode(); + assert.equal(coerceForTesting(listItem).tabIndex, 12); + wrapper.unmount(); +}); + +test('adapter.removeAttributeToElementAtIndex adds a class to a listItem', () => { + const wrapper = mount( + + + + ); + getAdapter(wrapper).removeAttributeFromElementAtIndex(0, 'tabindex'); + const listItem = wrapper.find('.mdc-list-item').getDOMNode(); + assert.notEqual(coerceForTesting(listItem).tabIndex, 12); + wrapper.unmount(); +}); \ No newline at end of file From 3abb5f4e7da547c95983318ef6d177cad2c6101d Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Fri, 29 Mar 2019 11:54:35 -0700 Subject: [PATCH 10/31] fix: lint and test --- package-lock.json | 2 +- packages/menu/MenuList.tsx | 7 +- packages/menu/index.tsx | 13 +- test/screenshot/menu/index.tsx | 1 - test/unit/list/index.test.tsx | 2 +- test/unit/menu/MenuList.test.tsx | 68 ++++++++++ test/unit/menu/MenuListItem.test.tsx | 27 ++++ test/unit/menu/index.test.tsx | 182 ++++++++++++++++++++++++++- 8 files changed, 288 insertions(+), 14 deletions(-) create mode 100644 test/unit/menu/MenuList.test.tsx create mode 100644 test/unit/menu/MenuListItem.test.tsx diff --git a/package-lock.json b/package-lock.json index 093a2e721..fe8b32f37 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17917,7 +17917,7 @@ }, "ts-loader": { "version": "3.5.0", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-3.5.0.tgz", + "resolved": "http://registry.npmjs.org/ts-loader/-/ts-loader-3.5.0.tgz", "integrity": "sha512-JTia3kObhTk36wPFgy0RnkZReiusYx7Le9IhcUWRrCTcFcr6Dy1zGsFd3x8DG4gevlbN65knI8W50FfoykXcng==", "dev": true, "requires": { diff --git a/packages/menu/MenuList.tsx b/packages/menu/MenuList.tsx index 22707c3bc..0b70c06c2 100644 --- a/packages/menu/MenuList.tsx +++ b/packages/menu/MenuList.tsx @@ -22,6 +22,7 @@ import * as React from 'react'; import List, {ListProps} from '@material/react-list'; +// eslint-disable-next-line no-unused-vars import {MDCMenuFoundation} from '@material/menu/foundation'; type RefCallback = (node: T | null) => void; @@ -75,14 +76,17 @@ class MenuList extends React.Component extends React.Component ); } - } export default MenuList; diff --git a/packages/menu/index.tsx b/packages/menu/index.tsx index d9a3c876d..1549ff084 100644 --- a/packages/menu/index.tsx +++ b/packages/menu/index.tsx @@ -42,7 +42,7 @@ export interface MenuState { class Menu extends React.Component { menuListElement = React.createRef(); - + // need foundation on state so that it initializes MenuList with // foundation.handleItemAction state: MenuState = { @@ -78,8 +78,9 @@ class Menu extends React.Component { get listElements(): Element[] { if (!(this.menuListElement && this.menuListElement.current + && this.menuListElement.current.listElements && this.menuListElement.current.listElements.length >= 0 )) { - return []; + return []; } return this.menuListElement.current.listElements; } @@ -139,13 +140,15 @@ class Menu extends React.Component { render() { const { + className, + /* eslint-disable no-unused-vars */ open, onKeyDown, onOpen, children, - className, handleSelected, ref, + /* eslint-enable no-unused-vars */ ...otherProps } = this.props; @@ -163,7 +166,7 @@ class Menu extends React.Component { ); } - + renderChild() { const {children} = this.props; const {foundation} = this.state; @@ -195,3 +198,5 @@ export { ListItemMeta as MenuListMeta, ListItemText as MenuListItemText, } from '@material/react-list'; +export {MenuListProps} from './MenuList'; +export {MenuListItemProps} from './MenuListItem'; diff --git a/test/screenshot/menu/index.tsx b/test/screenshot/menu/index.tsx index 91f15d648..8aab62c08 100644 --- a/test/screenshot/menu/index.tsx +++ b/test/screenshot/menu/index.tsx @@ -9,7 +9,6 @@ interface MenuState { }; class MenuScreenshotTest extends React.Component<{}, MenuState> { - state = { open: true, coordinates: undefined, diff --git a/test/unit/list/index.test.tsx b/test/unit/list/index.test.tsx index 2c2619897..bd605b10c 100644 --- a/test/unit/list/index.test.tsx +++ b/test/unit/list/index.test.tsx @@ -475,4 +475,4 @@ test('renderWithListItemProps renders passes props to element', () => { const listItem = list.childAt(0); assert.isTrue(listItem.props().radioList); assert.isFalse(listItem.props().checkboxList); -}); \ No newline at end of file +}); diff --git a/test/unit/menu/MenuList.test.tsx b/test/unit/menu/MenuList.test.tsx new file mode 100644 index 000000000..f8aea8d9b --- /dev/null +++ b/test/unit/menu/MenuList.test.tsx @@ -0,0 +1,68 @@ +import * as React from 'react'; +import {assert} from 'chai'; +import * as td from 'testdouble'; +import {shallow, mount} from 'enzyme'; +import {MenuList} from '../../../packages/menu/index'; +import List from '../../../packages/list/index'; +import {MDCListIndex} from '@material/list/types'; +import {coerceForTesting} from '../helpers/types'; + +suite('MenuList'); + +test('classNames adds classes', () => { + const wrapper = mount(); + assert.isTrue(wrapper.getDOMNode().classList.contains('mdc-list')); + assert.isTrue(wrapper.getDOMNode().classList.contains('test-class-name')); +}); + +test('role is defaulted to menu', () => { + const wrapper = mount(); + assert.equal(wrapper.getDOMNode().getAttribute('role'), 'menu'); +}); + +test('role is set to props.role', () => { + const wrapper = mount(); + assert.equal(wrapper.getDOMNode().getAttribute('role'), 'menuitem'); +}); + +test('aria-hidden is defaulted to true', () => { + const wrapper = mount(); + assert.equal(wrapper.getDOMNode().getAttribute('aria-hidden'), 'true'); +}); + +test('aria-hidden is set to props.ariaHidden', () => { + const wrapper = mount(); + assert.equal(wrapper.getDOMNode().getAttribute('aria-hidden'), 'false'); +}); + +test('#handleSelect calls props.handleSelect', () => { + const handleSelect = td.func<(activatedItemIndex: number, selected: MDCListIndex) => void>(); + const wrapper = shallow(); + coerceForTesting(wrapper.instance()).handleSelect!(0, 0); + td.verify(handleSelect(0, 0), {times: 1}); +}); + +test('#handleSelect calls props.handleItemAction', () => { + const handleItemAction = td.func<(listItem: Element) => void>(); + const wrapper = mount( + + ); + coerceForTesting(wrapper.instance()).handleSelect!(0, 0); + td.verify(handleItemAction(wrapper.find('.mdc-list-item').getDOMNode()), {times: 1}); +}); + +// These tests with innerRef could be a global set of tests for an HOC +test('innerRef as function as function gets called with List', () => { + const innerRef = td.func<(list: List | null) => void>(); + const wrapper = mount(); + const list = coerceForTesting(wrapper.childAt(0).instance()); + td.verify(innerRef(list), {times: 1}); +}); + + +test('innerRef as refObject gets called with List', () => { + const innerRef = React.createRef(); + const wrapper = mount(); + const list = coerceForTesting(wrapper.childAt(0).instance()); + assert.equal(innerRef.current, list); +}); diff --git a/test/unit/menu/MenuListItem.test.tsx b/test/unit/menu/MenuListItem.test.tsx new file mode 100644 index 000000000..b40ca0898 --- /dev/null +++ b/test/unit/menu/MenuListItem.test.tsx @@ -0,0 +1,27 @@ +import * as React from 'react'; +import {assert} from 'chai'; +import {mount} from 'enzyme'; +import {MenuListItem} from '../../../packages/menu/index'; + +suite('MenuListItem'); + +test('classNames adds classes', () => { + const wrapper = mount(); + assert.isTrue(wrapper.getDOMNode().classList.contains('mdc-list-item')); + assert.isTrue(wrapper.getDOMNode().classList.contains('test-class-name')); +}); + +test('role is defaulted to menuitem', () => { + const wrapper = mount(); + assert.equal(wrapper.getDOMNode().getAttribute('role'), 'menuitem'); +}); + +test('role is set to props.role', () => { + const wrapper = mount(); + assert.equal(wrapper.getDOMNode().getAttribute('role'), 'menu'); +}); + +test('menuListItem has props.renderWithListItemProps set to true', () => { + const wrapper = mount(); + assert.isTrue(wrapper.props().renderWithListItemProps); +}); diff --git a/test/unit/menu/index.test.tsx b/test/unit/menu/index.test.tsx index 2ad1cb979..bebbea780 100644 --- a/test/unit/menu/index.test.tsx +++ b/test/unit/menu/index.test.tsx @@ -2,11 +2,10 @@ import * as React from 'react'; import {assert} from 'chai'; import * as td from 'testdouble'; import {shallow, mount, ShallowWrapper, ReactWrapper} from 'enzyme'; -import Menu, {MenuState, MenuList} from '../../../packages/menu/index'; -import { coerceForTesting } from '../helpers/types'; -// import {MDCMenuFoundation} from '@material/menu/foundation'; +import Menu, {MenuState, MenuList, MenuListItem, MenuListProps} from '../../../packages/menu/index'; +import {coerceForTesting} from '../helpers/types'; -suite.only('Menu'); +suite('Menu'); function getFoundation(wrapper: ReactWrapper | ShallowWrapper) { return coerceForTesting(wrapper.state()).foundation!; @@ -76,4 +75,177 @@ test('adapter.removeAttributeToElementAtIndex adds a class to a listItem', () => const listItem = wrapper.find('.mdc-list-item').getDOMNode(); assert.notEqual(coerceForTesting(listItem).tabIndex, 12); wrapper.unmount(); -}); \ No newline at end of file +}); + +test('adapter.elementContainsClass returns true if element contains class', () => { + class Div extends React.Component { + render() { + return (
Meow
); + } + } + const wrapper = mount(
); + const contains = getAdapter(wrapper).elementContainsClass( + wrapper.find('div').last().getDOMNode(), 'test-class-name-1'); + assert.isTrue(contains); + wrapper.unmount(); +}); + +test('adapter.elementContainsClass returns FALSE if element does not contains class', () => { + class Div extends React.Component { + render() { + return (
Meow
); + } + } + const wrapper = mount(
); + const contains = getAdapter(wrapper).elementContainsClass( + wrapper.find('div').first().getDOMNode(), 'test-class-name-1'); + assert.isFalse(contains); + wrapper.unmount(); +}); + +test('adapter.closeSurface sets state.open to false', () => { + const wrapper = shallow(); + assert.isTrue(coerceForTesting(wrapper.state()).open); + getAdapter(wrapper).closeSurface(); + assert.isFalse(coerceForTesting(wrapper.state()).open); +}); + +test('adapter.getElementIndex returns index of list item', () => { + const wrapper = mount( + + + + + ); + const lastListItem = wrapper.find('.mdc-list-item').last().getDOMNode(); + const index = getAdapter(wrapper).getElementIndex(lastListItem); + assert.equal(index, 1); + wrapper.unmount(); +}); + +test('adapter.getParentElement returns MenuList if called on list item', () => { + const wrapper = mount( + + + + + ); + const lastListItem = wrapper.find('.mdc-list-item').last().getDOMNode(); + const menuList = getAdapter(wrapper).getParentElement(lastListItem); + assert.equal(menuList, wrapper.find('.mdc-list').getDOMNode()); + wrapper.unmount(); +}); + +test('adapter.getSelectedElementIndex returns selected list item\'s index', () => { + const wrapper = mount( + + + + + ); + const menuList = wrapper.find('.mdc-list').getDOMNode(); + const selectedListItem = getAdapter(wrapper).getSelectedElementIndex(menuList); + assert.equal(selectedListItem, 0); + wrapper.unmount(); +}); + +test('adapter.getSelectedElementIndex returns -1 if no list item is selected', () => { + const wrapper = mount( + + + + + ); + const menuList = wrapper.find('.mdc-list').getDOMNode(); + const selectedListItem = getAdapter(wrapper).getSelectedElementIndex(menuList); + assert.equal(selectedListItem, -1); + wrapper.unmount(); +}); + +test('adapter.notifySelected calls props.handleSelected with the selectedindex and listElement DOM node', () => { + const handleSelected = td.func<(index: number, element: Element) => void>(); + const wrapper = mount( + + + + + ); + const evtData = {index: 0}; + getAdapter(wrapper).notifySelected(evtData); + td.verify(handleSelected(0, wrapper.find('.mdc-list-item').first().getDOMNode()), {times: 1}); + wrapper.unmount(); +}); + +test('onKeyDown calls foundation.handleKeydown', () => { + const wrapper = shallow(); + getFoundation(wrapper).handleKeydown = td.func<(evt: Event) => void>(); + const evt = coerceForTesting({ + nativeEvent: {}, + }); + wrapper.simulate('keydown', evt); + td.verify(getFoundation(wrapper).handleKeydown(evt.nativeEvent), {times: 1}); +}); + +test('onKeyDown calls props.onKeyDown', () => { + const onKeyDown = td.func<(evt: React.KeyboardEvent) => void>(); + const wrapper = shallow(); + const evt = coerceForTesting({ + nativeEvent: {}, + }); + wrapper.simulate('keydown', evt); + td.verify(onKeyDown(evt), {times: 1}); +}); + +test('handleOpen calls props.onOpen', () => { + const onOpen = td.func<() => void>(); + const wrapper = mount(); + coerceForTesting(wrapper.instance()).handleOpen!(); + td.verify(onOpen(), {times: 1}); +}); + +test('handleOpen calls focuses on first list element', () => { + const div = document.createElement('div'); + document.body.append(div); + const options = {attachTo: div}; + const wrapper = mount( + + + + + , options); + coerceForTesting(wrapper.instance()).handleOpen!(); + assert.equal(document.activeElement, wrapper.find('.mdc-list-item').first().getDOMNode()); + wrapper.unmount(); + div.remove(); +}); + +test('menu renders with tabindex=-1', () => { + const wrapper = shallow(); + assert.equal(wrapper.props().tabIndex, -1); +}); + +test('menu renders child with handleItemAction', () => { + class Div extends React.Component { + render() { + return (
Meow
); + } + } + const wrapper = mount(
); + const {handleItemAction} = coerceForTesting>( + wrapper.childAt(0).childAt(0).childAt(0).props()); + assert.isTrue(typeof handleItemAction === 'function'); + wrapper.unmount(); +}); + +test('menu renders child with wrapFocus', () => { + class Div extends React.Component { + render() { + return (
Meow
); + } + } + const wrapper = mount(
); + const {wrapFocus} = coerceForTesting>( + wrapper.childAt(0).childAt(0).childAt(0).props()); + assert.isTrue(wrapFocus); + wrapper.unmount(); +}); From 61b076b7c1166f6b6c74613aae2421c8f635e2a7 Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Fri, 29 Mar 2019 13:01:17 -0700 Subject: [PATCH 11/31] fix: add golden --- test/screenshot/golden.json | 1 + 1 file changed, 1 insertion(+) diff --git a/test/screenshot/golden.json b/test/screenshot/golden.json index 6d7f1e41c..0d7e49028 100644 --- a/test/screenshot/golden.json +++ b/test/screenshot/golden.json @@ -11,6 +11,7 @@ "linear-progress": "f7a23058842b37875a02b3562e0b9c82f7fb24f9b88e9727d10b921b001d115e", "list": "4dcdfeb03d781eca5367f6cbf4c7ebd13d1fe8932ca5758520b994d541f49095", "material-icon": "442b39fb22d2c7a74efb23ca098429b471501ce21df8662327bbf9871fe0bcb0", + "menu": "e01ad23051bc9e7c3c574f129fb591b393368c13c7ab9a64dfe6aff22b09bdb2", "menu-surface": "f5face1a24fe166e86e8a3dc35ea85b2d4431469a3d06bf6fc1a30fbdc175aff", "notched-outline": "7770dd381c27608a1f43b6f83da92507fe53963f5e4409bd73184b86275538fe", "radio": "adfce0bbfa2711c67a52e1c3c3c7e980314be0147e340dac733152c80c385765", From 05c48ddf5d9eb4c28fc58434fab5b18c0ecac5f9 Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Mon, 1 Apr 2019 10:21:38 -0700 Subject: [PATCH 12/31] fix: Pr changes --- packages/menu/README.md | 6 +++--- packages/menu/index.tsx | 11 +++++------ test/screenshot/menu/index.tsx | 2 +- test/unit/menu/index.test.tsx | 8 ++++---- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/packages/menu/README.md b/packages/menu/README.md index e865bf818..86411d160 100644 --- a/packages/menu/README.md +++ b/packages/menu/README.md @@ -75,7 +75,7 @@ class MyApp extends React.Component { open={this.state.open} onClose={this.onClose} coordinates={this.state.coordinates} - handleSelected={(index, item) => console.log(index, item)} + onSelected={(index, item) => console.log(index, item)} > {menuOptions.map((option, index) => ( @@ -130,7 +130,7 @@ class MenuScreenshotTest extends React.Component<{}, MenuState> { console.log('select')} + onSelected={() => console.log('select')} > {menuOptions.map((option, index) => ( @@ -154,7 +154,7 @@ class MenuScreenshotTest extends React.Component<{}, MenuState> { Prop Name | Type | Description --- | --- | --- -handleSelected | (index: number, item: Element) => void | Callback that is triggered when a menu list item is selected. +onSelected | (index: number, item: Element) => void | Callback that is triggered when a menu list item is selected. onClose | () => void | Callback that is triggered when the menu closes. open | boolean | If true, will open the menu. If false, will hide menu. diff --git a/packages/menu/index.tsx b/packages/menu/index.tsx index 1549ff084..c3928cff6 100644 --- a/packages/menu/index.tsx +++ b/packages/menu/index.tsx @@ -32,7 +32,7 @@ const {cssClasses} = MDCMenuFoundation; export interface MenuProps extends Exclude { children: React.ReactElement; - handleSelected?: (index: number, item: Element) => void; + onSelected?: (index: number, item: Element) => void; }; export interface MenuState { @@ -54,7 +54,7 @@ class Menu extends React.Component { className: '', open: false, onKeyDown: () => {}, - handleSelected: () => {}, + onSelected: () => {}, }; componentDidMount() { @@ -76,8 +76,7 @@ class Menu extends React.Component { } get listElements(): Element[] { - if (!(this.menuListElement - && this.menuListElement.current + if (!(this.menuListElement.current && this.menuListElement.current.listElements && this.menuListElement.current.listElements.length >= 0 )) { return []; @@ -113,7 +112,7 @@ class Menu extends React.Component { const selectedListItem = selectionGroup.querySelector(`.${cssClasses.MENU_SELECTED_LIST_ITEM}`); return selectedListItem ? this.listElements.indexOf(selectedListItem) : -1; }, - notifySelected: (evtData) => this.props.handleSelected!( + notifySelected: (evtData) => this.props.onSelected!( evtData.index, this.listElements[evtData.index], ), @@ -146,7 +145,7 @@ class Menu extends React.Component { onKeyDown, onOpen, children, - handleSelected, + onSelected, ref, /* eslint-enable no-unused-vars */ ...otherProps diff --git a/test/screenshot/menu/index.tsx b/test/screenshot/menu/index.tsx index 8aab62c08..04cbe746b 100644 --- a/test/screenshot/menu/index.tsx +++ b/test/screenshot/menu/index.tsx @@ -49,7 +49,7 @@ class MenuScreenshotTest extends React.Component<{}, MenuState> { open={this.state.open} onClose={this.onClose} coordinates={this.state.coordinates} - handleSelected={(index: number, item: Element) => console.log(index, item)} + onSelected={(index: number, item: Element) => console.log(index, item)} > {menuOptions.map((option, index) => ( diff --git a/test/unit/menu/index.test.tsx b/test/unit/menu/index.test.tsx index bebbea780..093b2cde8 100644 --- a/test/unit/menu/index.test.tsx +++ b/test/unit/menu/index.test.tsx @@ -162,9 +162,9 @@ test('adapter.getSelectedElementIndex returns -1 if no list item is selected', ( wrapper.unmount(); }); -test('adapter.notifySelected calls props.handleSelected with the selectedindex and listElement DOM node', () => { - const handleSelected = td.func<(index: number, element: Element) => void>(); - const wrapper = mount( +test('adapter.notifySelected calls props.onSelected with the selectedindex and listElement DOM node', () => { + const onSelected = td.func<(index: number, element: Element) => void>(); + const wrapper = mount( @@ -172,7 +172,7 @@ test('adapter.notifySelected calls props.handleSelected with the selectedindex a ); const evtData = {index: 0}; getAdapter(wrapper).notifySelected(evtData); - td.verify(handleSelected(0, wrapper.find('.mdc-list-item').first().getDOMNode()), {times: 1}); + td.verify(onSelected(0, wrapper.find('.mdc-list-item').first().getDOMNode()), {times: 1}); wrapper.unmount(); }); From 6ee5ad76fd2cdc0af042426b506357b5b9e161c4 Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Tue, 2 Apr 2019 14:32:10 -0700 Subject: [PATCH 13/31] WIP: using context to pass list item --- package-lock.json | 162 +++--- packages/list/ListItem.tsx | 121 ++-- packages/list/index.tsx | 66 ++- packages/menu/MenuList.tsx | 8 +- packages/menu/MenuListItem.tsx | 6 +- packages/menu/index.tsx | 2 +- test/unit/list/ListItem.test.tsx | 114 ++-- test/unit/list/index.test.tsx | 956 +++++++++++++++---------------- test/unit/menu/index.test.tsx | 4 +- 9 files changed, 714 insertions(+), 725 deletions(-) diff --git a/package-lock.json b/package-lock.json index 029ad66b7..917e2e444 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18151,7 +18151,7 @@ }, "ts-loader": { "version": "3.5.0", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-3.5.0.tgz", + "resolved": "http://registry.npmjs.org/ts-loader/-/ts-loader-3.5.0.tgz", "integrity": "sha512-JTia3kObhTk36wPFgy0RnkZReiusYx7Le9IhcUWRrCTcFcr6Dy1zGsFd3x8DG4gevlbN65knI8W50FfoykXcng==", "dev": true, "requires": { @@ -19175,28 +19175,28 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": "", + "resolved": false, "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "resolved": "", + "resolved": false, "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true, "optional": true }, "aproba": { "version": "1.2.0", - "resolved": "", + "resolved": false, "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true, "optional": true }, "are-we-there-yet": { "version": "1.1.4", - "resolved": "", + "resolved": false, "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", "dev": true, "optional": true, @@ -19207,14 +19207,14 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true, "optional": true }, "brace-expansion": { "version": "1.1.11", - "resolved": "", + "resolved": false, "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "optional": true, @@ -19225,28 +19225,28 @@ }, "chownr": { "version": "1.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", "dev": true, "optional": true }, "code-point-at": { "version": "1.1.0", - "resolved": "", + "resolved": false, "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true, "optional": true }, "concat-map": { "version": "0.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true, "optional": true }, "console-control-strings": { "version": "1.1.0", - "resolved": "", + "resolved": false, "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "dev": true, "optional": true @@ -19260,7 +19260,7 @@ }, "debug": { "version": "2.6.9", - "resolved": "", + "resolved": false, "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "optional": true, @@ -19270,28 +19270,28 @@ }, "deep-extend": { "version": "0.5.1", - "resolved": "", + "resolved": false, "integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==", "dev": true, "optional": true }, "delegates": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", - "resolved": "", + "resolved": false, "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "dev": true, "optional": true }, "fs-minipass": { "version": "1.2.5", - "resolved": "", + "resolved": false, "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", "dev": true, "optional": true, @@ -19301,14 +19301,14 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true, "optional": true }, "gauge": { "version": "2.7.4", - "resolved": "", + "resolved": false, "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, "optional": true, @@ -19325,7 +19325,7 @@ }, "glob": { "version": "7.1.2", - "resolved": "", + "resolved": false, "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "optional": true, @@ -19340,14 +19340,14 @@ }, "has-unicode": { "version": "2.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true, "optional": true }, "iconv-lite": { "version": "0.4.21", - "resolved": "", + "resolved": false, "integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==", "dev": true, "optional": true, @@ -19357,7 +19357,7 @@ }, "ignore-walk": { "version": "3.0.1", - "resolved": "", + "resolved": false, "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "dev": true, "optional": true, @@ -19367,7 +19367,7 @@ }, "inflight": { "version": "1.0.6", - "resolved": "", + "resolved": false, "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "optional": true, @@ -19378,21 +19378,21 @@ }, "inherits": { "version": "2.0.3", - "resolved": "", + "resolved": false, "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true, "optional": true }, "ini": { "version": "1.3.5", - "resolved": "", + "resolved": false, "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "optional": true, @@ -19409,7 +19409,7 @@ }, "minimatch": { "version": "3.0.4", - "resolved": "", + "resolved": false, "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "optional": true, @@ -19419,14 +19419,14 @@ }, "minimist": { "version": "0.0.8", - "resolved": "", + "resolved": false, "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true, "optional": true }, "minipass": { "version": "2.2.4", - "resolved": "", + "resolved": false, "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==", "dev": true, "optional": true, @@ -19437,7 +19437,7 @@ }, "minizlib": { "version": "1.1.0", - "resolved": "", + "resolved": false, "integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==", "dev": true, "optional": true, @@ -19447,7 +19447,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "", + "resolved": false, "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "optional": true, @@ -19457,14 +19457,14 @@ }, "ms": { "version": "2.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true, "optional": true }, "needle": { "version": "2.2.0", - "resolved": "", + "resolved": false, "integrity": "sha512-eFagy6c+TYayorXw/qtAdSvaUpEbBsDwDyxYFgLZ0lTojfH7K+OdBqAF7TAFwDokJaGpubpSGG0wO3iC0XPi8w==", "dev": true, "optional": true, @@ -19476,7 +19476,7 @@ }, "node-pre-gyp": { "version": "0.10.0", - "resolved": "", + "resolved": false, "integrity": "sha512-G7kEonQLRbcA/mOoFoxvlMrw6Q6dPf92+t/l0DFSMuSlDoWaI9JWIyPwK0jyE1bph//CUEL65/Fz1m2vJbmjQQ==", "dev": true, "optional": true, @@ -19495,7 +19495,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "dev": true, "optional": true, @@ -19506,14 +19506,14 @@ }, "npm-bundled": { "version": "1.0.3", - "resolved": "", + "resolved": false, "integrity": "sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow==", "dev": true, "optional": true }, "npm-packlist": { "version": "1.1.10", - "resolved": "", + "resolved": false, "integrity": "sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA==", "dev": true, "optional": true, @@ -19524,7 +19524,7 @@ }, "npmlog": { "version": "4.1.2", - "resolved": "", + "resolved": false, "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, "optional": true, @@ -19537,21 +19537,21 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true, "optional": true }, "object-assign": { "version": "4.1.1", - "resolved": "", + "resolved": false, "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true, "optional": true }, "once": { "version": "1.4.0", - "resolved": "", + "resolved": false, "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "optional": true, @@ -19561,21 +19561,21 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true, "optional": true }, "osenv": { "version": "0.1.5", - "resolved": "", + "resolved": false, "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "dev": true, "optional": true, @@ -19586,7 +19586,7 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true, "optional": true @@ -19600,7 +19600,7 @@ }, "rc": { "version": "1.2.7", - "resolved": "", + "resolved": false, "integrity": "sha512-LdLD8xD4zzLsAT5xyushXDNscEjB7+2ulnl8+r1pnESlYtlJtVSoCMBGr30eDRJ3+2Gq89jK9P9e4tCEH1+ywA==", "dev": true, "optional": true, @@ -19613,7 +19613,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "", + "resolved": false, "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true, "optional": true @@ -19638,7 +19638,7 @@ }, "rimraf": { "version": "2.6.2", - "resolved": "", + "resolved": false, "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "optional": true, @@ -19648,49 +19648,49 @@ }, "safe-buffer": { "version": "5.1.1", - "resolved": "", + "resolved": false, "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", "dev": true, "optional": true }, "safer-buffer": { "version": "2.1.2", - "resolved": "", + "resolved": false, "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, "optional": true }, "sax": { "version": "1.2.4", - "resolved": "", + "resolved": false, "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true, "optional": true }, "semver": { "version": "5.5.0", - "resolved": "", + "resolved": false, "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", "dev": true, "optional": true }, "set-blocking": { "version": "2.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true, "optional": true }, "string-width": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "optional": true, @@ -19712,7 +19712,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "optional": true, @@ -19722,14 +19722,14 @@ }, "strip-json-comments": { "version": "2.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true, "optional": true }, "tar": { "version": "4.4.1", - "resolved": "", + "resolved": false, "integrity": "sha512-O+v1r9yN4tOsvl90p5HAP4AEqbYhx4036AGMm075fH9F8Qwi3oJ+v4u50FkT/KkvywNGtwkk0zRI+8eYm1X/xg==", "dev": true, "optional": true, @@ -19752,7 +19752,7 @@ }, "wide-align": { "version": "1.1.2", - "resolved": "", + "resolved": false, "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", "dev": true, "optional": true, @@ -19762,14 +19762,14 @@ }, "wrappy": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true, "optional": true }, "yallist": { "version": "3.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", "dev": true, "optional": true @@ -20232,21 +20232,21 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": "", + "resolved": false, "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "resolved": "", + "resolved": false, "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true, "optional": true }, "aproba": { "version": "1.2.0", - "resolved": "", + "resolved": false, "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true, "optional": true @@ -20264,14 +20264,14 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true, "optional": true }, "brace-expansion": { "version": "1.1.11", - "resolved": "", + "resolved": false, "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "optional": true, @@ -20282,35 +20282,35 @@ }, "chownr": { "version": "1.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", "dev": true, "optional": true }, "code-point-at": { "version": "1.1.0", - "resolved": "", + "resolved": false, "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true, "optional": true }, "concat-map": { "version": "0.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true, "optional": true }, "console-control-strings": { "version": "1.1.0", - "resolved": "", + "resolved": false, "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "dev": true, "optional": true }, "core-util-is": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true, "optional": true @@ -20327,21 +20327,21 @@ }, "deep-extend": { "version": "0.5.1", - "resolved": "", + "resolved": false, "integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==", "dev": true, "optional": true }, "delegates": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", - "resolved": "", + "resolved": false, "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "dev": true, "optional": true @@ -20358,7 +20358,7 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true, "optional": true @@ -20397,7 +20397,7 @@ }, "has-unicode": { "version": "2.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true, "optional": true @@ -20414,7 +20414,7 @@ }, "ignore-walk": { "version": "3.0.1", - "resolved": "", + "resolved": false, "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "dev": true, "optional": true, @@ -20435,14 +20435,14 @@ }, "inherits": { "version": "2.0.3", - "resolved": "", + "resolved": false, "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true, "optional": true }, "ini": { "version": "1.3.5", - "resolved": "", + "resolved": false, "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true, "optional": true @@ -20459,14 +20459,14 @@ }, "isarray": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true, "optional": true }, "minimatch": { "version": "3.0.4", - "resolved": "", + "resolved": false, "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "optional": true, diff --git a/packages/list/ListItem.tsx b/packages/list/ListItem.tsx index eec13c360..aed2243b6 100644 --- a/packages/list/ListItem.tsx +++ b/packages/list/ListItem.tsx @@ -23,86 +23,75 @@ import * as React from 'react'; import classnames from 'classnames'; import {MDCListFoundation} from '@material/list/foundation'; +import {ListItemContext} from './index'; -export interface ListItemProps extends React.HTMLProps { +export interface ListItemProps extends React.HTMLProps { checkboxList?: boolean; radioList?: boolean; - onKeyDown?: React.KeyboardEventHandler; - onClick?: React.MouseEventHandler; - onFocus?: React.FocusEventHandler; - onBlur?: React.FocusEventHandler; tag?: string; activated?: boolean; selected?: boolean; ref?: React.Ref; - renderWithListItemProps?: boolean; }; -// TODO: convert to functional component -// https://github.com/material-components/material-components-web-react/issues/729 -export default class ListItem extends React.Component< - ListItemProps, - {} - > { - private listItemElement = React.createRef(); - - static defaultProps: Partial> = { - checkboxList: false, - radioList: false, - renderWithListItemProps: false, - className: '', - tabIndex: -1, - onKeyDown: () => {}, - onClick: () => {}, - onFocus: () => {}, - onBlur: () => {}, - tag: 'li', - }; - - get classes() { - const {className, activated, selected} = this.props; - return classnames('mdc-list-item', className, { - [MDCListFoundation.cssClasses.LIST_ITEM_ACTIVATED_CLASS]: activated, - [MDCListFoundation.cssClasses.LIST_ITEM_SELECTED_CLASS]: selected, - }); +const getRole = (checkboxList?: boolean, radioList?: boolean, role?: string) => { + if (role) { + return role; + } else if (checkboxList) { + return 'checkbox'; + } else if (radioList) { + return 'radio'; } + return null; +} - get role() { - const {checkboxList, radioList, role} = this.props; - if (role) { - return role; - } else if (checkboxList) { - return 'checkbox'; - } else if (radioList) { - return 'radio'; - } - return null; - } +const getClasses = (activated: boolean, selected: boolean, className: string) => { + return classnames('mdc-list-item', className, { + [MDCListFoundation.cssClasses.LIST_ITEM_ACTIVATED_CLASS]: activated, + [MDCListFoundation.cssClasses.LIST_ITEM_SELECTED_CLASS]: selected, + }); +} + +// TODO: convert to functional component +// https://github.com/material-components/material-components-web-react/issues/729 +const ListItemBase: React.FunctionComponent = ({ + checkboxList = false, + radioList = false, + className = '', + tabIndex = -1, + tag: Tag = 'li', + children, + activated = false, + selected = false, + role, + ...otherProps +}) => { + console.log(otherProps) + return ( + // https://github.com/Microsoft/TypeScript/issues/28892 + // @ts-ignore + + {children} + + ); +} +class ListItem extends React.Component { + updatedProps?: ListItemProps; render() { - const { - /* eslint-disable no-unused-vars */ - className, - children, - role, - checkboxList, - radioList, - renderWithListItemProps, - /* eslint-enable no-unused-vars */ - tag: Tag, - ...otherProps - } = this.props; return ( - // https://github.com/Microsoft/TypeScript/issues/28892 - // @ts-ignore - - {this.props.children} - + + {(getNewProps) => { + this.updatedProps = this.updatedProps || getNewProps(this.props); + return (); + }} + ); } } + +export default ListItem; \ No newline at end of file diff --git a/packages/list/index.tsx b/packages/list/index.tsx index 79243aeb9..30e22c431 100644 --- a/packages/list/index.tsx +++ b/packages/list/index.tsx @@ -35,7 +35,7 @@ import ListGroupSubheader from './ListGroupSubheader'; const ARIA_ORIENTATION = 'aria-orientation'; const VERTICAL = 'vertical'; -export interface ListProps extends React.HTMLProps { +export interface ListProps extends React.HTMLProps { className?: string; checkboxList?: boolean; radioList?: boolean; @@ -48,30 +48,34 @@ export interface ListProps extends React.HTMLProps void; wrapFocus?: boolean; tag?: string; - children: ListItem | ListItem[] | React.ReactNode; + // children: ListItem | ListItem[] | React.ReactNode; ref?: React.Ref; }; -function isReactText(element: any): element is React.ReactText { - return typeof element === 'string' || typeof element === 'number' || !element; -} +// function isReactText(element: any): element is React.ReactText { +// return typeof element === 'string' || typeof element === 'number' || !element; +// } -function isListItem(element: any): element is ListItem { - return element && element.type === ListItem; -} +// function isListItem(element: any): element is ListItem { +// return element && element.type === ListItem; +// } function isSelectedIndexType(selectedIndex: unknown): selectedIndex is MDCListIndex { return typeof selectedIndex === 'number' && !isNaN(selectedIndex) || Array.isArray(selectedIndex); } -export default class List extends React.Component, {}> { +const getDefaultListItemProps: (listItemProps: ListItemProps) => ListItemProps + = () => ({}); +export const ListItemContext = React.createContext(getDefaultListItemProps); + +export default class List extends React.Component { listItemCount = 0; foundation!: MDCListFoundation; hasInitializedListItem = false; private listElement = React.createRef(); - static defaultProps: Partial> = { + static defaultProps: Partial = { 'className': '', 'checkboxList': false, 'radioList': false, @@ -103,7 +107,7 @@ export default class List extends React.Com this.initializeListType(); } - componentDidUpdate(prevProps: ListProps) { + componentDidUpdate(prevProps: ListProps) { const {singleSelection, wrapFocus, selectedIndex} = this.props; const hasSelectedIndexUpdated = selectedIndex !== prevProps.selectedIndex; if (singleSelection !== prevProps.singleSelection) { @@ -311,31 +315,24 @@ export default class List extends React.Com role={this.role} {...otherProps} > - {React.Children.map(children, this.renderChild)} + + {children} + ); } - renderChild = (child: React.ReactElement> | React.ReactChild) => { - if (!isReactText(child)) { - const {renderWithListItemProps} = child.props; - if (renderWithListItemProps || isListItem(child)) { - return this.renderListItem(child, this.listItemCount++); - } - } - return child; - }; - - renderListItem = (listItem: React.ReactElement>, index: number) => { + getListItemProps = (listItemProps: ListItemProps) => { const {checkboxList, radioList, selectedIndex} = this.props; let tabIndex = {}; + const index = this.listItemCount++; const { onKeyDown, onClick, onFocus, onBlur, ...otherProps - } = listItem.props; + } = listItemProps; if (!this.hasInitializedListItem) { const isSelectedIndexArray = Array.isArray(selectedIndex) && selectedIndex.length > 0; @@ -355,31 +352,38 @@ export default class List extends React.Com } } - - const props = { + return { // otherProps must come first ...otherProps, checkboxList, radioList, onKeyDown: (e: React.KeyboardEvent) => { - onKeyDown!(e); + if (onKeyDown) { + onKeyDown(e); + } this.handleKeyDown(e, index); }, onClick: (e: React.MouseEvent) => { - onClick!(e); + if (onClick) { + onClick(e); + } + console.log('CLICK') this.handleClick(e, index); }, onFocus: (e: React.FocusEvent) => { - onFocus!(e); + if (onFocus) { + onFocus(e); + } this.handleFocus(e, index); }, onBlur: (e: React.FocusEvent) => { - onBlur!(e); + if (onBlur) { + onBlur(e); + } this.handleBlur(e, index); }, ...tabIndex, }; - return React.cloneElement(listItem, props); }; } diff --git a/packages/menu/MenuList.tsx b/packages/menu/MenuList.tsx index 0b70c06c2..7a999d40e 100644 --- a/packages/menu/MenuList.tsx +++ b/packages/menu/MenuList.tsx @@ -27,15 +27,15 @@ import {MDCMenuFoundation} from '@material/menu/foundation'; type RefCallback = (node: T | null) => void; -export interface MenuListProps extends Exclude, 'ref'> { +export interface MenuListProps extends Exclude { innerRef?: RefCallback | React.RefObject; handleItemAction?: MDCMenuFoundation['handleItemAction']; }; -class MenuList extends React.Component, {}> { +class MenuList extends React.Component { private listInstance = React.createRef(); - static defaultProps: Partial> = { + static defaultProps: Partial = { className: '', handleSelect: () => {}, handleItemAction: () => {}, @@ -48,7 +48,7 @@ class MenuList extends React.Component['handleSelect'] = (activatedItemIndex, selected) => { + handleSelect: ListProps['handleSelect'] = (activatedItemIndex, selected) => { this.props.handleSelect!(activatedItemIndex, selected); this.props.handleItemAction!(this.listElements[activatedItemIndex]); } diff --git a/packages/menu/MenuListItem.tsx b/packages/menu/MenuListItem.tsx index ec6fa153e..580eb408f 100644 --- a/packages/menu/MenuListItem.tsx +++ b/packages/menu/MenuListItem.tsx @@ -23,15 +23,11 @@ import * as React from 'react'; import {ListItem, ListItemProps} from '@material/react-list'; -export interface MenuListItemProps extends ListItemProps { +export interface MenuListItemProps extends ListItemProps { children?: React.ReactNode; } class MenuListItem extends React.Component, {}> { - static defaultProps: Partial> = { - ...ListItem.defaultProps, - renderWithListItemProps: true, - }; render() { const { diff --git a/packages/menu/index.tsx b/packages/menu/index.tsx index c3928cff6..39a73eb18 100644 --- a/packages/menu/index.tsx +++ b/packages/menu/index.tsx @@ -176,7 +176,7 @@ class Menu extends React.Component { // this is to avoid a `handleItemAction` of undefined error handleItemAction = foundation.handleItemAction.bind(foundation); } - const updatedProps: MenuListProps = { + const updatedProps: MenuListProps = { // children.props must appear first ...children.props, handleItemAction, diff --git a/test/unit/list/ListItem.test.tsx b/test/unit/list/ListItem.test.tsx index 9e4292049..38138bec6 100644 --- a/test/unit/list/ListItem.test.tsx +++ b/test/unit/list/ListItem.test.tsx @@ -1,71 +1,71 @@ -import * as React from 'react'; -import {assert} from 'chai'; -import {mount, shallow} from 'enzyme'; -import {ListItem} from '../../../packages/list/index'; +// import * as React from 'react'; +// import {assert} from 'chai'; +// import {mount, shallow} from 'enzyme'; +// import {ListItem} from '../../../packages/list/index'; -suite('ListItem'); +// suite('ListItem'); -test('classNames adds classes', () => { - const wrapper = shallow(
meow
); - assert.isTrue(wrapper.hasClass('test-class-name')); -}); +// test('classNames adds classes', () => { +// const wrapper = shallow(
meow
); +// assert.isTrue(wrapper.hasClass('test-class-name')); +// }); -test('has mdc-list-item classname', () => { - const wrapper = shallow(
meow
); - assert.isTrue(wrapper.hasClass('mdc-list-item')); -}); +// test('has mdc-list-item classname', () => { +// const wrapper = shallow(
meow
); +// assert.isTrue(wrapper.hasClass('mdc-list-item')); +// }); -test('has activated class if props.activated = true', () => { - const wrapper = shallow(
meow
); - assert.isTrue(wrapper.hasClass('mdc-list-item--activated')); -}); +// test('has activated class if props.activated = true', () => { +// const wrapper = shallow(
meow
); +// assert.isTrue(wrapper.hasClass('mdc-list-item--activated')); +// }); -test('has selected class if props.selected = true', () => { - const wrapper = shallow(
meow
); - assert.isTrue(wrapper.hasClass('mdc-list-item--selected')); -}); +// test('has selected class if props.selected = true', () => { +// const wrapper = shallow(
meow
); +// assert.isTrue(wrapper.hasClass('mdc-list-item--selected')); +// }); -test('has role=checkbox if props.checkboxList = true', () => { - const wrapper = shallow(
meow
); - assert.equal(wrapper.props().role, 'checkbox'); -}); +// test('has role=checkbox if props.checkboxList = true', () => { +// const wrapper = shallow(
meow
); +// assert.equal(wrapper.props().role, 'checkbox'); +// }); -test('has role=radio if props.radioList = true', () => { - const wrapper = shallow(
meow
); - assert.equal(wrapper.props().role, 'radio'); -}); +// test('has role=radio if props.radioList = true', () => { +// const wrapper = shallow(
meow
); +// assert.equal(wrapper.props().role, 'radio'); +// }); -test('has role=menu if props.role = menu', () => { - const wrapper = shallow(
meow
); - assert.equal(wrapper.props().role, 'menu'); -}); +// test('has role=menu if props.role = menu', () => { +// const wrapper = shallow(
meow
); +// assert.equal(wrapper.props().role, 'menu'); +// }); -test('is anchor tag if tag=a', () => { - const wrapper = mount>(
meow
); - assert.equal(wrapper.find('a').length, 1); -}); +// test('is anchor tag if tag=a', () => { +// const wrapper = mount>(
meow
); +// assert.equal(wrapper.find('a').length, 1); +// }); -test('listitem can have href tag', () => { - const wrapper = mount>(
meow
); - assert.equal(wrapper.props().href, 'google.com'); -}); +// test('listitem can have href tag', () => { +// const wrapper = mount>(
meow
); +// assert.equal(wrapper.props().href, 'google.com'); +// }); -test('renders a list item with default tag', () => { - const wrapper = shallow(
Test
); - assert.equal(wrapper.type(), 'li'); -}); +// test('renders a list item with default tag', () => { +// const wrapper = shallow(
Test
); +// assert.equal(wrapper.type(), 'li'); +// }); -test('renders a list item with text content', () => { - const wrapper = shallow(Test); - assert.equal(wrapper.type(), 'li'); -}); +// test('renders a list item with text content', () => { +// const wrapper = shallow(Test); +// assert.equal(wrapper.type(), 'li'); +// }); -test('renders a list item with null as a child', () => { - const wrapper = shallow(
Test
{null}
); - assert.equal(wrapper.type(), 'li'); -}); +// test('renders a list item with null as a child', () => { +// const wrapper = shallow(
Test
{null}
); +// assert.equal(wrapper.type(), 'li'); +// }); -test('renders a list item with an anchor tag', () => { - const wrapper = shallow(
Test
); - assert.equal(wrapper.type(), 'a'); -}); +// test('renders a list item with an anchor tag', () => { +// const wrapper = shallow(
Test
); +// assert.equal(wrapper.type(), 'a'); +// }); diff --git a/test/unit/list/index.test.tsx b/test/unit/list/index.test.tsx index bd605b10c..81fb88520 100644 --- a/test/unit/list/index.test.tsx +++ b/test/unit/list/index.test.tsx @@ -1,478 +1,478 @@ -import * as React from 'react'; -import {assert} from 'chai'; -import * as td from 'testdouble'; -import {shallow, mount} from 'enzyme'; -import List, { - ListItem, ListItemProps, // eslint-disable-line no-unused-vars -} from '../../../packages/list/index'; -import {coerceForTesting} from '../helpers/types'; -import {MDCListIndex} from '@material/list/types'; - -suite('List'); - -const children = (opts?: { - key?: number, - hasCheckbox?: boolean - }): React.ReactElement> => ( - -
meow
- {opts && opts.hasCheckbox ? : null} -
-); - -const threeChildren = (): React.ReactElement>[] => ( - [0, 1, 2].map((key) => children({key})) -); - -test('creates foundation', () => { - const wrapper = shallow( - {children()} - ); - assert.exists(wrapper.instance().foundation); -}); - -test('#componentWillUnmount destroys foundation', () => { - const wrapper = shallow({children()}); - const foundation = wrapper.instance().foundation; - foundation.destroy = coerceForTesting<() => void>(td.func()); - wrapper.unmount(); - td.verify(foundation.destroy()); -}); - -test('calls foundation.setSingleSelection when props.singleSelection changes from false to true', () => { - const wrapper = mount({children()}); - wrapper.instance().foundation.setSingleSelection = coerceForTesting<(arg: boolean) => void>(td.func()); - wrapper.setProps({singleSelection: true}); - td.verify(wrapper.instance().foundation.setSingleSelection(true), { - times: 1, - }); -}); - -test('calls foundation.setSingleSelection when props.singleSelection changes from true to false', () => { - const wrapper = mount({children()}); - wrapper.instance().foundation.setSingleSelection = coerceForTesting<(arg: boolean) => void>(td.func()); - wrapper.setProps({singleSelection: false}); - td.verify(wrapper.instance().foundation.setSingleSelection(false), { - times: 1, - }); -}); - -test('calls foundation.setWrapFocus when props.wrapFocus changes from false to true', () => { - const wrapper = mount({children()}); - wrapper.instance().foundation.setWrapFocus = coerceForTesting<(arg: boolean) => void>(td.func()); - wrapper.setProps({wrapFocus: true}); - td.verify(wrapper.instance().foundation.setWrapFocus(true), {times: 1}); -}); - -test('calls foundation.setWrapFocus when props.wrapFocus changes from true to false', () => { - const wrapper = mount({children()}); - wrapper.instance().foundation.setWrapFocus = coerceForTesting<(arg: boolean) => void>(td.func()); - wrapper.setProps({wrapFocus: false}); - td.verify(wrapper.instance().foundation.setWrapFocus(false), {times: 1}); -}); - -test('calls foundation.setSelectedIndex when props.selectedIndex changes', () => { - const wrapper = mount({children()}); - wrapper.instance().foundation.setSelectedIndex = coerceForTesting<(arg: MDCListIndex) => void>(td.func()); - wrapper.setProps({selectedIndex: 1}); - td.verify(wrapper.instance().foundation.setSelectedIndex(1), {times: 1}); -}); - -test('calls foundation.setVerticalOrientation when \'aria-orientation\' changes from vertical to horizontal', () => { - const wrapper = mount({children()}); - wrapper.instance().foundation.setVerticalOrientation = coerceForTesting<(arg: boolean) => void>(td.func()); - wrapper.setProps({'aria-orientation': 'horizontal'}); - td.verify(wrapper.instance().foundation.setVerticalOrientation(false), { - times: 1, - }); -}); - -test('calls foundation.setVerticalOrientation when \'aria-orientation\' changes from horizontal to vertical', () => { - const wrapper = mount({children()}); - wrapper.instance().foundation.setVerticalOrientation = coerceForTesting<(arg: boolean) => void>(td.func()); - wrapper.setProps({'aria-orientation': 'vertical'}); - td.verify(wrapper.instance().foundation.setVerticalOrientation(true), { - times: 1, - }); -}); - -test('classNames adds classes', () => { - const wrapper = shallow({children()}); - assert.isTrue(wrapper.hasClass('test-class-name')); -}); - -test('has mdc-list--non-interactive class if props.nonInteractive is true', () => { - const wrapper = shallow({children()}); - assert.isTrue(wrapper.hasClass('mdc-list--non-interactive')); -}); - -test('has mdc-list--dense class if props.dense is true', () => { - const wrapper = shallow({children()}); - assert.isTrue(wrapper.hasClass('mdc-list--dense')); -}); - -test('has mdc-list--avatar-list class if props.avatarList is true', () => { - const wrapper = shallow({children()}); - assert.isTrue(wrapper.hasClass('mdc-list--avatar-list')); -}); - -test('has mdc-list--two-line class if props.twoLine is true', () => { - const wrapper = shallow({children()}); - assert.isTrue(wrapper.hasClass('mdc-list--two-line')); -}); - -test('#adapter.getListItemCount returns number of list items', () => { - const wrapper = mount( - - {threeChildren()} - - ); - assert.equal(wrapper.instance().adapter.getListItemCount(), 3); -}); - -test('#adapter.getListItemCount returns correct number of list items if List has a non-item child', () => { - const wrapper = mount( - -
meow
-
meow
-
meow
-
- ); - assert.equal(wrapper.instance().adapter.getListItemCount(), 3); -}); - -test('#adapter.setAttributeForElementIndex calls setAttribute on listItem', () => { - const wrapper = mount({children()}); - wrapper.instance().listElements[0].setAttribute = coerceForTesting<(key: string, value: string) => void>(td.func()); - wrapper.instance().adapter.setAttributeForElementIndex(0, 'role', 'menu'); - td.verify(wrapper.instance().listElements[0].setAttribute('role', 'menu'), {times: 1}); -}); - -test('#adapter.setAttributeForElementIndex call nothing when no children exist', () => { - const wrapper = mount(); - assert.doesNotThrow(() => wrapper.instance().adapter.setAttributeForElementIndex(0, 'role', 'menu')); -}); - -test('#adapter.addClassForElementIndex adds class to classList', () => { - const wrapper = mount({children()}); - wrapper.instance().adapter.addClassForElementIndex = - coerceForTesting<(index: number, className: string) => void>(td.func()); - wrapper.instance().adapter.addClassForElementIndex(0, 'class4321'); - const listItem = wrapper.childAt(0).childAt(0); - assert.isTrue(listItem.html().includes('class4321')); - assert.isTrue(listItem.html().includes('mdc-list-item')); -}); - -test('#adapter.addClassForElementIndex adds class to classList and keeps props.className', () => { - const wrapper = mount( -
meow
-
); - wrapper.instance().adapter.addClassForElementIndex = - coerceForTesting<(index: number, className: string) => void>(td.func()); - wrapper.instance().adapter.addClassForElementIndex(0, 'class4321'); - const listItem = wrapper.childAt(0).childAt(0); - assert.isTrue(listItem.html().includes('class4321')); - assert.isTrue(listItem.html().includes('class987')); - assert.isTrue(listItem.html().includes('mdc-list-item')); -}); - -test('#adapter.removeClassForElementIndex adds class to classList and keeps props.className', () => { - const wrapper = mount( -
meow
-
); - wrapper.instance().adapter.removeClassForElementIndex = - coerceForTesting<(index: number, className: string) => void>(td.func()); - wrapper.instance().adapter.removeClassForElementIndex(0, 'class4321'); - const listItem = wrapper.childAt(0).childAt(0); - assert.isFalse(listItem.html().includes('class4321')); - assert.isTrue(listItem.html().includes('class987')); - assert.isTrue(listItem.html().includes('mdc-list-item')); -}); - -test('#adapter.setTabIndexForListItemChildren updates the button and anchor tag to have tabindex=0', () => { - const wrapper = mount( - - - link - - ); - wrapper.instance().adapter.setTabIndexForListItemChildren(0, '0'); - const listItem = wrapper.childAt(0).childAt(0); - assert.isTrue(listItem.find('a').html().includes('tabindex="0"')); - assert.isTrue(listItem.find('button').html().includes('tabindex="0"')); -}); - -test('#adapter.focusItemAtIndex calls focus on the listitem', () => { - const wrapper = mount({children()}); - (wrapper.instance().listElements[0] as HTMLElement).focus - = coerceForTesting<(opts?: any) => void>(td.func()); - wrapper.instance().adapter.focusItemAtIndex(0); - td.verify((wrapper.instance().listElements[0] as HTMLElement).focus(), {times: 1}); -}); - -test('#adapter.focusItemAtIndex call nothing when no children exist', () => { - const wrapper = mount(); - assert.doesNotThrow(() => wrapper.instance().adapter.focusItemAtIndex(0)); -}); - -test('#adapter.setCheckedCheckboxOrRadioAtIndex does not throw', () => { - const wrapper = shallow({children()}); - assert.doesNotThrow(() => wrapper.instance().adapter.setCheckedCheckboxOrRadioAtIndex(0, true)); -}); - -test('#adapter.hasCheckboxAtIndex returns false with no checkbox', () => { - const wrapper = mount({children()}); - assert.isFalse(wrapper.instance().adapter.hasCheckboxAtIndex(0)); -}); - -test('#adapter.hasCheckboxAtIndex returns true with checkbox', () => { - const wrapper = mount( - - - - ); - assert.isTrue(wrapper.instance().adapter.hasCheckboxAtIndex(0)); -}); - -test('#adapter.hasRadioAtIndex returns false with no checkbox', () => { - const wrapper = mount({children()}); - assert.isFalse(wrapper.instance().adapter.hasRadioAtIndex(0)); -}); - -test('#adapter.hasRadioAtIndex returns true with checkbox', () => { - const wrapper = mount( - - - - ); - assert.isTrue(wrapper.instance().adapter.hasRadioAtIndex(0)); -}); - -test('#adapter.isCheckboxCheckedAtIndex returns false with a non-checked checkbox', () => { - const wrapper = mount( - - - - ); - assert.isFalse(wrapper.instance().adapter.isCheckboxCheckedAtIndex(0)); -}); - -test('#adapter.isCheckboxCheckedAtIndex returns true with a checked checkbox', () => { - const wrapper = mount( - - {/* empty onChange to avoid a warning */} - {}} /> - - ); - assert.isTrue(wrapper.instance().adapter.isCheckboxCheckedAtIndex(0)); -}); - -test('#adapter.isFocusInsideList returns true if the list element has focus inside', () => { - const div = document.createElement('div'); - // needs to be attached to real DOM to get width - // https://github.com/airbnb/enzyme/issues/1525 - document.body.append(div); - const options = {attachTo: div}; - const wrapper = mount( - - - - , options); - wrapper.instance().listElements[0].querySelector('button')!.focus(); - assert.isTrue(wrapper.instance().adapter.isFocusInsideList()); - div.remove(); -}); - -test('#adapter.isFocusInsideList returns true if the list element has focus inside', () => { - const wrapper = mount( - - - - ); - assert.isFalse(wrapper.instance().adapter.isFocusInsideList()); -}); - -test('#adapter.notifyAction calls props.handleSelect with args', () => { - const handleSelect = coerceForTesting<(selectedIndex: number, selected: MDCListIndex) => void>(td.func()); - const wrapper = mount({children}); - wrapper.instance().adapter.notifyAction(0); - td.verify(handleSelect(0, -1), {times: 1}); -}); - -test('renders with mdc-list class', () => { - const wrapper = shallow({children}); - assert.isTrue(wrapper.hasClass('mdc-list')); -}); - -test('renders with className', () => { - const wrapper = shallow({children}); - assert.isTrue(wrapper.hasClass('test-class')); - assert.isTrue(wrapper.hasClass('mdc-list')); -}); - -test('renders with mdc-list--non-interactive when non-interactive', () => { - const wrapper = shallow({children}); - assert.isTrue(wrapper.hasClass('mdc-list--non-interactive')); - assert.isTrue(wrapper.hasClass('mdc-list')); -}); - -test('renders with mdc-list--dense when dense', () => { - const wrapper = shallow({children}); - assert.isTrue(wrapper.hasClass('mdc-list--dense')); - assert.isTrue(wrapper.hasClass('mdc-list')); -}); - -test('renders with mdc-list--avatar-list when avatar-list', () => { - const wrapper = shallow({children}); - assert.isTrue(wrapper.hasClass('mdc-list--avatar-list')); - assert.isTrue(wrapper.hasClass('mdc-list')); -}); - -test('renders with mdc-list--two-line when two-line', () => { - const wrapper = shallow({children}); - assert.isTrue(wrapper.hasClass('mdc-list--two-line')); - assert.isTrue(wrapper.hasClass('mdc-list')); -}); - -test('renders with role=group if props.checkboxList', () => { - const wrapper = shallow({children}); - assert.equal(wrapper.props().role, 'group'); -}); - -test('renders with role=radiogroup if props.radioList', () => { - const wrapper = shallow({children}); - assert.equal(wrapper.props().role, 'radiogroup'); -}); - -test('renders with role=menu if props.role=menu', () => { - const wrapper = shallow({children}); - assert.equal(wrapper.props().role, 'menu'); -}); - -test('renders with role=menu if props.role=menu and props.checkboxList', () => { - const wrapper = shallow({children}); - assert.equal(wrapper.props().role, 'menu'); -}); - - -test('#handleKeyDown calls #foudation.handleKeydown', () => { - const wrapper = shallow({children()}); - wrapper.instance().foundation.handleKeydown - = coerceForTesting<(evt: KeyboardEvent, isItem: boolean, itemIndex: number) => void>(td.func()); - const evt = coerceForTesting({persist: () => {}}); - wrapper.instance().handleKeyDown(evt, 1); - td.verify(wrapper.instance().foundation.handleKeydown(evt.nativeEvent, true, 1), { - times: 1, - }); -}); - -test('#handleClick calls #foudation.handleClick', () => { - const wrapper = shallow({children()}); - const target = {type: 'span'}; - const evt = coerceForTesting>({target}); - wrapper.instance().foundation.handleClick - = coerceForTesting<(index: number, toggleCheckbox: boolean) => void>(td.func()); - wrapper.instance().handleClick(evt, 1); - td.verify(wrapper.instance().foundation.handleClick(1, false), {times: 1}); -}); - -test('#handleFocus calls #foudation.handleFocusIn', () => { - const wrapper = shallow({children()}); - wrapper.instance().foundation.handleFocusIn - = coerceForTesting<(e: FocusEvent, itemIndex: number) => void>(td.func()); - const evt = coerceForTesting({}); - wrapper.instance().handleFocus(evt, 1); - td.verify(wrapper.instance().foundation.handleFocusIn(evt.nativeEvent, 1), {times: 1}); -}); - -test('#handleBlur calls #foudation.handleFocusOut', () => { - const wrapper = shallow({children()}); - wrapper.instance().foundation.handleFocusOut - = coerceForTesting<(e: FocusEvent, itemIndex: number) => void>(td.func()); - const evt = coerceForTesting({}); - wrapper.instance().handleBlur(evt, 1); - td.verify(wrapper.instance().foundation.handleFocusOut(evt.nativeEvent, 1), { - times: 1, - }); -}); - -test('renders 3 list items', () => { - const wrapper = mount( - - {threeChildren()} - - ); - assert.equal(wrapper.childAt(0).children().length, 3); -}); - -test('renders list items with tabindex=-1 and first with tabindex=0', () => { - const wrapper = mount( - - {threeChildren()} - - ); - const list = wrapper.childAt(0); - assert.equal(list.childAt(0).props().tabIndex, 0); - assert.equal(list.childAt(1).props().tabIndex, -1); - assert.equal(list.childAt(2).props().tabIndex, -1); -}); - -test('renders list items with tabindex=-1 and child at props.selectedIndex tabindex=0', () => { - const wrapper = mount( - - {threeChildren()} - - ); - const list = wrapper.childAt(0); - assert.equal(list.childAt(0).props().tabIndex, -1); - assert.equal(list.childAt(1).props().tabIndex, 0); - assert.equal(list.childAt(2).props().tabIndex, -1); -}); - -test('renders list items with tabindex=-1 and child at props.selectedIndex tabindex=0 as an array', - () => { - const wrapper = mount( - - {children({key: 0, hasCheckbox: true})} - {children({key: 1, hasCheckbox: true})} - {children({key: 2, hasCheckbox: true})} - - ); - const list = wrapper.childAt(0); - assert.equal(list.childAt(0).props().tabIndex, -1); - assert.equal(list.childAt(1).props().tabIndex, 0); - assert.equal(list.childAt(2).props().tabIndex, -1); - }); - -test('renders a list with default tag', () => { - const wrapper = shallow({children()}); - assert.equal(wrapper.type(), 'ul'); -}); - -test('renders a list with a nav tag', () => { - const wrapper = shallow({children()}); - assert.equal(wrapper.type(), 'nav'); -}); - -test('renders a list with children of non-DOM elements', () => { - const wrapper = shallow( - {} - {false} - {'text'} - {null} - {undefined} - ); - assert.isTrue(wrapper.children().length === 1); -}); - -test('renderWithListItemProps renders passes props to element', () => { - const CustomComponent: React.FunctionComponent> - = () => ; - const wrapper = mount( - - ); - const list = wrapper.childAt(0); - const listItem = list.childAt(0); - assert.isTrue(listItem.props().radioList); - assert.isFalse(listItem.props().checkboxList); -}); +// import * as React from 'react'; +// import {assert} from 'chai'; +// import * as td from 'testdouble'; +// import {shallow, mount} from 'enzyme'; +// import List, { +// ListItem, ListItemProps, // eslint-disable-line no-unused-vars +// } from '../../../packages/list/index'; +// import {coerceForTesting} from '../helpers/types'; +// import {MDCListIndex} from '@material/list/types'; + +// suite('List'); + +// const children = (opts?: { +// key?: number, +// hasCheckbox?: boolean +// }): React.ReactElement> => ( +// +//
meow
+// {opts && opts.hasCheckbox ? : null} +//
+// ); + +// const threeChildren = (): React.ReactElement>[] => ( +// [0, 1, 2].map((key) => children({key})) +// ); + +// test('creates foundation', () => { +// const wrapper = shallow( +// {children()} +// ); +// assert.exists(wrapper.instance().foundation); +// }); + +// test('#componentWillUnmount destroys foundation', () => { +// const wrapper = shallow({children()}); +// const foundation = wrapper.instance().foundation; +// foundation.destroy = coerceForTesting<() => void>(td.func()); +// wrapper.unmount(); +// td.verify(foundation.destroy()); +// }); + +// test('calls foundation.setSingleSelection when props.singleSelection changes from false to true', () => { +// const wrapper = mount({children()}); +// wrapper.instance().foundation.setSingleSelection = coerceForTesting<(arg: boolean) => void>(td.func()); +// wrapper.setProps({singleSelection: true}); +// td.verify(wrapper.instance().foundation.setSingleSelection(true), { +// times: 1, +// }); +// }); + +// test('calls foundation.setSingleSelection when props.singleSelection changes from true to false', () => { +// const wrapper = mount({children()}); +// wrapper.instance().foundation.setSingleSelection = coerceForTesting<(arg: boolean) => void>(td.func()); +// wrapper.setProps({singleSelection: false}); +// td.verify(wrapper.instance().foundation.setSingleSelection(false), { +// times: 1, +// }); +// }); + +// test('calls foundation.setWrapFocus when props.wrapFocus changes from false to true', () => { +// const wrapper = mount({children()}); +// wrapper.instance().foundation.setWrapFocus = coerceForTesting<(arg: boolean) => void>(td.func()); +// wrapper.setProps({wrapFocus: true}); +// td.verify(wrapper.instance().foundation.setWrapFocus(true), {times: 1}); +// }); + +// test('calls foundation.setWrapFocus when props.wrapFocus changes from true to false', () => { +// const wrapper = mount({children()}); +// wrapper.instance().foundation.setWrapFocus = coerceForTesting<(arg: boolean) => void>(td.func()); +// wrapper.setProps({wrapFocus: false}); +// td.verify(wrapper.instance().foundation.setWrapFocus(false), {times: 1}); +// }); + +// test('calls foundation.setSelectedIndex when props.selectedIndex changes', () => { +// const wrapper = mount({children()}); +// wrapper.instance().foundation.setSelectedIndex = coerceForTesting<(arg: MDCListIndex) => void>(td.func()); +// wrapper.setProps({selectedIndex: 1}); +// td.verify(wrapper.instance().foundation.setSelectedIndex(1), {times: 1}); +// }); + +// test('calls foundation.setVerticalOrientation when \'aria-orientation\' changes from vertical to horizontal', () => { +// const wrapper = mount({children()}); +// wrapper.instance().foundation.setVerticalOrientation = coerceForTesting<(arg: boolean) => void>(td.func()); +// wrapper.setProps({'aria-orientation': 'horizontal'}); +// td.verify(wrapper.instance().foundation.setVerticalOrientation(false), { +// times: 1, +// }); +// }); + +// test('calls foundation.setVerticalOrientation when \'aria-orientation\' changes from horizontal to vertical', () => { +// const wrapper = mount({children()}); +// wrapper.instance().foundation.setVerticalOrientation = coerceForTesting<(arg: boolean) => void>(td.func()); +// wrapper.setProps({'aria-orientation': 'vertical'}); +// td.verify(wrapper.instance().foundation.setVerticalOrientation(true), { +// times: 1, +// }); +// }); + +// test('classNames adds classes', () => { +// const wrapper = shallow({children()}); +// assert.isTrue(wrapper.hasClass('test-class-name')); +// }); + +// test('has mdc-list--non-interactive class if props.nonInteractive is true', () => { +// const wrapper = shallow({children()}); +// assert.isTrue(wrapper.hasClass('mdc-list--non-interactive')); +// }); + +// test('has mdc-list--dense class if props.dense is true', () => { +// const wrapper = shallow({children()}); +// assert.isTrue(wrapper.hasClass('mdc-list--dense')); +// }); + +// test('has mdc-list--avatar-list class if props.avatarList is true', () => { +// const wrapper = shallow({children()}); +// assert.isTrue(wrapper.hasClass('mdc-list--avatar-list')); +// }); + +// test('has mdc-list--two-line class if props.twoLine is true', () => { +// const wrapper = shallow({children()}); +// assert.isTrue(wrapper.hasClass('mdc-list--two-line')); +// }); + +// test('#adapter.getListItemCount returns number of list items', () => { +// const wrapper = mount( +// +// {threeChildren()} +// +// ); +// assert.equal(wrapper.instance().adapter.getListItemCount(), 3); +// }); + +// test('#adapter.getListItemCount returns correct number of list items if List has a non-item child', () => { +// const wrapper = mount( +// +//
meow
+//
meow
+//
meow
+//
+// ); +// assert.equal(wrapper.instance().adapter.getListItemCount(), 3); +// }); + +// test('#adapter.setAttributeForElementIndex calls setAttribute on listItem', () => { +// const wrapper = mount({children()}); +// wrapper.instance().listElements[0].setAttribute = coerceForTesting<(key: string, value: string) => void>(td.func()); +// wrapper.instance().adapter.setAttributeForElementIndex(0, 'role', 'menu'); +// td.verify(wrapper.instance().listElements[0].setAttribute('role', 'menu'), {times: 1}); +// }); + +// test('#adapter.setAttributeForElementIndex call nothing when no children exist', () => { +// const wrapper = mount(); +// assert.doesNotThrow(() => wrapper.instance().adapter.setAttributeForElementIndex(0, 'role', 'menu')); +// }); + +// test('#adapter.addClassForElementIndex adds class to classList', () => { +// const wrapper = mount({children()}); +// wrapper.instance().adapter.addClassForElementIndex = +// coerceForTesting<(index: number, className: string) => void>(td.func()); +// wrapper.instance().adapter.addClassForElementIndex(0, 'class4321'); +// const listItem = wrapper.childAt(0).childAt(0); +// assert.isTrue(listItem.html().includes('class4321')); +// assert.isTrue(listItem.html().includes('mdc-list-item')); +// }); + +// test('#adapter.addClassForElementIndex adds class to classList and keeps props.className', () => { +// const wrapper = mount( +//
meow
+//
); +// wrapper.instance().adapter.addClassForElementIndex = +// coerceForTesting<(index: number, className: string) => void>(td.func()); +// wrapper.instance().adapter.addClassForElementIndex(0, 'class4321'); +// const listItem = wrapper.childAt(0).childAt(0); +// assert.isTrue(listItem.html().includes('class4321')); +// assert.isTrue(listItem.html().includes('class987')); +// assert.isTrue(listItem.html().includes('mdc-list-item')); +// }); + +// test('#adapter.removeClassForElementIndex adds class to classList and keeps props.className', () => { +// const wrapper = mount( +//
meow
+//
); +// wrapper.instance().adapter.removeClassForElementIndex = +// coerceForTesting<(index: number, className: string) => void>(td.func()); +// wrapper.instance().adapter.removeClassForElementIndex(0, 'class4321'); +// const listItem = wrapper.childAt(0).childAt(0); +// assert.isFalse(listItem.html().includes('class4321')); +// assert.isTrue(listItem.html().includes('class987')); +// assert.isTrue(listItem.html().includes('mdc-list-item')); +// }); + +// test('#adapter.setTabIndexForListItemChildren updates the button and anchor tag to have tabindex=0', () => { +// const wrapper = mount( +// +// +// link +// +// ); +// wrapper.instance().adapter.setTabIndexForListItemChildren(0, '0'); +// const listItem = wrapper.childAt(0).childAt(0); +// assert.isTrue(listItem.find('a').html().includes('tabindex="0"')); +// assert.isTrue(listItem.find('button').html().includes('tabindex="0"')); +// }); + +// test('#adapter.focusItemAtIndex calls focus on the listitem', () => { +// const wrapper = mount({children()}); +// (wrapper.instance().listElements[0] as HTMLElement).focus +// = coerceForTesting<(opts?: any) => void>(td.func()); +// wrapper.instance().adapter.focusItemAtIndex(0); +// td.verify((wrapper.instance().listElements[0] as HTMLElement).focus(), {times: 1}); +// }); + +// test('#adapter.focusItemAtIndex call nothing when no children exist', () => { +// const wrapper = mount(); +// assert.doesNotThrow(() => wrapper.instance().adapter.focusItemAtIndex(0)); +// }); + +// test('#adapter.setCheckedCheckboxOrRadioAtIndex does not throw', () => { +// const wrapper = shallow({children()}); +// assert.doesNotThrow(() => wrapper.instance().adapter.setCheckedCheckboxOrRadioAtIndex(0, true)); +// }); + +// test('#adapter.hasCheckboxAtIndex returns false with no checkbox', () => { +// const wrapper = mount({children()}); +// assert.isFalse(wrapper.instance().adapter.hasCheckboxAtIndex(0)); +// }); + +// test('#adapter.hasCheckboxAtIndex returns true with checkbox', () => { +// const wrapper = mount( +// +// +// +// ); +// assert.isTrue(wrapper.instance().adapter.hasCheckboxAtIndex(0)); +// }); + +// test('#adapter.hasRadioAtIndex returns false with no checkbox', () => { +// const wrapper = mount({children()}); +// assert.isFalse(wrapper.instance().adapter.hasRadioAtIndex(0)); +// }); + +// test('#adapter.hasRadioAtIndex returns true with checkbox', () => { +// const wrapper = mount( +// +// +// +// ); +// assert.isTrue(wrapper.instance().adapter.hasRadioAtIndex(0)); +// }); + +// test('#adapter.isCheckboxCheckedAtIndex returns false with a non-checked checkbox', () => { +// const wrapper = mount( +// +// +// +// ); +// assert.isFalse(wrapper.instance().adapter.isCheckboxCheckedAtIndex(0)); +// }); + +// test('#adapter.isCheckboxCheckedAtIndex returns true with a checked checkbox', () => { +// const wrapper = mount( +// +// {/* empty onChange to avoid a warning */} +// {}} /> +// +// ); +// assert.isTrue(wrapper.instance().adapter.isCheckboxCheckedAtIndex(0)); +// }); + +// test('#adapter.isFocusInsideList returns true if the list element has focus inside', () => { +// const div = document.createElement('div'); +// // needs to be attached to real DOM to get width +// // https://github.com/airbnb/enzyme/issues/1525 +// document.body.append(div); +// const options = {attachTo: div}; +// const wrapper = mount( +// +// +// +// , options); +// wrapper.instance().listElements[0].querySelector('button')!.focus(); +// assert.isTrue(wrapper.instance().adapter.isFocusInsideList()); +// div.remove(); +// }); + +// test('#adapter.isFocusInsideList returns true if the list element has focus inside', () => { +// const wrapper = mount( +// +// +// +// ); +// assert.isFalse(wrapper.instance().adapter.isFocusInsideList()); +// }); + +// test('#adapter.notifyAction calls props.handleSelect with args', () => { +// const handleSelect = coerceForTesting<(selectedIndex: number, selected: MDCListIndex) => void>(td.func()); +// const wrapper = mount({children}); +// wrapper.instance().adapter.notifyAction(0); +// td.verify(handleSelect(0, -1), {times: 1}); +// }); + +// test('renders with mdc-list class', () => { +// const wrapper = shallow({children}); +// assert.isTrue(wrapper.hasClass('mdc-list')); +// }); + +// test('renders with className', () => { +// const wrapper = shallow({children}); +// assert.isTrue(wrapper.hasClass('test-class')); +// assert.isTrue(wrapper.hasClass('mdc-list')); +// }); + +// test('renders with mdc-list--non-interactive when non-interactive', () => { +// const wrapper = shallow({children}); +// assert.isTrue(wrapper.hasClass('mdc-list--non-interactive')); +// assert.isTrue(wrapper.hasClass('mdc-list')); +// }); + +// test('renders with mdc-list--dense when dense', () => { +// const wrapper = shallow({children}); +// assert.isTrue(wrapper.hasClass('mdc-list--dense')); +// assert.isTrue(wrapper.hasClass('mdc-list')); +// }); + +// test('renders with mdc-list--avatar-list when avatar-list', () => { +// const wrapper = shallow({children}); +// assert.isTrue(wrapper.hasClass('mdc-list--avatar-list')); +// assert.isTrue(wrapper.hasClass('mdc-list')); +// }); + +// test('renders with mdc-list--two-line when two-line', () => { +// const wrapper = shallow({children}); +// assert.isTrue(wrapper.hasClass('mdc-list--two-line')); +// assert.isTrue(wrapper.hasClass('mdc-list')); +// }); + +// test('renders with role=group if props.checkboxList', () => { +// const wrapper = shallow({children}); +// assert.equal(wrapper.props().role, 'group'); +// }); + +// test('renders with role=radiogroup if props.radioList', () => { +// const wrapper = shallow({children}); +// assert.equal(wrapper.props().role, 'radiogroup'); +// }); + +// test('renders with role=menu if props.role=menu', () => { +// const wrapper = shallow({children}); +// assert.equal(wrapper.props().role, 'menu'); +// }); + +// test('renders with role=menu if props.role=menu and props.checkboxList', () => { +// const wrapper = shallow({children}); +// assert.equal(wrapper.props().role, 'menu'); +// }); + + +// test('#handleKeyDown calls #foudation.handleKeydown', () => { +// const wrapper = shallow({children()}); +// wrapper.instance().foundation.handleKeydown +// = coerceForTesting<(evt: KeyboardEvent, isItem: boolean, itemIndex: number) => void>(td.func()); +// const evt = coerceForTesting({persist: () => {}}); +// wrapper.instance().handleKeyDown(evt, 1); +// td.verify(wrapper.instance().foundation.handleKeydown(evt.nativeEvent, true, 1), { +// times: 1, +// }); +// }); + +// test('#handleClick calls #foudation.handleClick', () => { +// const wrapper = shallow({children()}); +// const target = {type: 'span'}; +// const evt = coerceForTesting>({target}); +// wrapper.instance().foundation.handleClick +// = coerceForTesting<(index: number, toggleCheckbox: boolean) => void>(td.func()); +// wrapper.instance().handleClick(evt, 1); +// td.verify(wrapper.instance().foundation.handleClick(1, false), {times: 1}); +// }); + +// test('#handleFocus calls #foudation.handleFocusIn', () => { +// const wrapper = shallow({children()}); +// wrapper.instance().foundation.handleFocusIn +// = coerceForTesting<(e: FocusEvent, itemIndex: number) => void>(td.func()); +// const evt = coerceForTesting({}); +// wrapper.instance().handleFocus(evt, 1); +// td.verify(wrapper.instance().foundation.handleFocusIn(evt.nativeEvent, 1), {times: 1}); +// }); + +// test('#handleBlur calls #foudation.handleFocusOut', () => { +// const wrapper = shallow({children()}); +// wrapper.instance().foundation.handleFocusOut +// = coerceForTesting<(e: FocusEvent, itemIndex: number) => void>(td.func()); +// const evt = coerceForTesting({}); +// wrapper.instance().handleBlur(evt, 1); +// td.verify(wrapper.instance().foundation.handleFocusOut(evt.nativeEvent, 1), { +// times: 1, +// }); +// }); + +// test('renders 3 list items', () => { +// const wrapper = mount( +// +// {threeChildren()} +// +// ); +// assert.equal(wrapper.childAt(0).children().length, 3); +// }); + +// test('renders list items with tabindex=-1 and first with tabindex=0', () => { +// const wrapper = mount( +// +// {threeChildren()} +// +// ); +// const list = wrapper.childAt(0); +// assert.equal(list.childAt(0).props().tabIndex, 0); +// assert.equal(list.childAt(1).props().tabIndex, -1); +// assert.equal(list.childAt(2).props().tabIndex, -1); +// }); + +// test('renders list items with tabindex=-1 and child at props.selectedIndex tabindex=0', () => { +// const wrapper = mount( +// +// {threeChildren()} +// +// ); +// const list = wrapper.childAt(0); +// assert.equal(list.childAt(0).props().tabIndex, -1); +// assert.equal(list.childAt(1).props().tabIndex, 0); +// assert.equal(list.childAt(2).props().tabIndex, -1); +// }); + +// test('renders list items with tabindex=-1 and child at props.selectedIndex tabindex=0 as an array', +// () => { +// const wrapper = mount( +// +// {children({key: 0, hasCheckbox: true})} +// {children({key: 1, hasCheckbox: true})} +// {children({key: 2, hasCheckbox: true})} +// +// ); +// const list = wrapper.childAt(0); +// assert.equal(list.childAt(0).props().tabIndex, -1); +// assert.equal(list.childAt(1).props().tabIndex, 0); +// assert.equal(list.childAt(2).props().tabIndex, -1); +// }); + +// test('renders a list with default tag', () => { +// const wrapper = shallow({children()}); +// assert.equal(wrapper.type(), 'ul'); +// }); + +// test('renders a list with a nav tag', () => { +// const wrapper = shallow({children()}); +// assert.equal(wrapper.type(), 'nav'); +// }); + +// test('renders a list with children of non-DOM elements', () => { +// const wrapper = shallow( +// {} +// {false} +// {'text'} +// {null} +// {undefined} +// ); +// assert.isTrue(wrapper.children().length === 1); +// }); + +// test('renderWithListItemProps renders passes props to element', () => { +// const CustomComponent: React.FunctionComponent> +// = () => ; +// const wrapper = mount( +// +// ); +// const list = wrapper.childAt(0); +// const listItem = list.childAt(0); +// assert.isTrue(listItem.props().radioList); +// assert.isFalse(listItem.props().checkboxList); +// }); diff --git a/test/unit/menu/index.test.tsx b/test/unit/menu/index.test.tsx index 093b2cde8..5aabf8013 100644 --- a/test/unit/menu/index.test.tsx +++ b/test/unit/menu/index.test.tsx @@ -231,7 +231,7 @@ test('menu renders child with handleItemAction', () => { } } const wrapper = mount(
); - const {handleItemAction} = coerceForTesting>( + const {handleItemAction} = coerceForTesting( wrapper.childAt(0).childAt(0).childAt(0).props()); assert.isTrue(typeof handleItemAction === 'function'); wrapper.unmount(); @@ -244,7 +244,7 @@ test('menu renders child with wrapFocus', () => { } } const wrapper = mount(
); - const {wrapFocus} = coerceForTesting>( + const {wrapFocus} = coerceForTesting( wrapper.childAt(0).childAt(0).childAt(0).props()); assert.isTrue(wrapFocus); wrapper.unmount(); From c605cef9d080036f5335e33ef144bf9e44947a49 Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Tue, 2 Apr 2019 18:37:00 -0700 Subject: [PATCH 14/31] fix: using context instead --- packages/list/ListItem.tsx | 122 +++++++++++++++++------ packages/list/index.tsx | 138 +++++++++++--------------- test/screenshot/list/index.tsx | 1 + test/unit/list/ListItem.test.tsx | 38 +++---- test/unit/list/index.test.tsx | 164 +++++++++++++++---------------- 5 files changed, 253 insertions(+), 210 deletions(-) diff --git a/packages/list/ListItem.tsx b/packages/list/ListItem.tsx index b76cfa310..fddc72bed 100644 --- a/packages/list/ListItem.tsx +++ b/packages/list/ListItem.tsx @@ -23,28 +23,25 @@ import * as React from 'react'; import classnames from 'classnames'; import {MDCListFoundation} from '@material/list/foundation'; -import {ListItemContext} from './index'; +import {ListItemContext, ListItemContextShape} from './index'; -export interface ListItemProps extends React.HTMLProps { +export interface ListItemProps extends React.HTMLProps, ListItemContextShape { checkboxList?: boolean; radioList?: boolean; tag?: string; activated?: boolean; selected?: boolean; - onDestroy?: () => void; ref?: React.Ref; }; -export default class ListItem extends React.Component< - ListItemProps, - {} - > { +class ListItemBase extends React.Component< + ListItemProps, {tabIndex?: number}> { + private listItemElement = React.createRef(); static defaultProps: Partial> = { checkboxList: false, radioList: false, - renderWithListItemProps: false, className: '', tabIndex: -1, onKeyDown: () => {}, @@ -55,13 +52,37 @@ export default class ListItem extends React tag: 'li', }; + state = { + tabIndex: this.props.tabIndex, + }; + + componentDidMount() { + if (this.listItemElement.current) { + const index = this.getIndex(this.listItemElement.current); + const tabIndex = this.props.getListItemInitialTabIndex!(index); + console.log(tabIndex, index) + this.setState({tabIndex}); + } + } + + componentDidUpdate(prevProps: ListItemProps) { + if(prevProps.tabIndex !== this.props.tabIndex) { + this.setState({tabIndex: this.props.tabIndex}); + } + } + componentWillUnmount() { - this.props.onDestroy!(); + this.props.onDestroy!(0); } get classes() { - const {className, activated, disabled, selected} = this.props; - return classnames('mdc-list-item', className, { + const {className, activated, disabled, selected, getClassNamesFromList} = this.props; + let classesFromList = ['']; + if (this.listItemElement.current) { + const index = this.getIndex(this.listItemElement.current); + classesFromList = getClassNamesFromList!()[index]; + } + return classnames('mdc-list-item', className, classesFromList, { [MDCListFoundation.cssClasses.LIST_ITEM_ACTIVATED_CLASS]: activated, [MDCListFoundation.cssClasses.LIST_ITEM_SELECTED_CLASS]: selected, 'mdc-list-item--disabled': disabled, @@ -80,6 +101,35 @@ export default class ListItem extends React return null; } + getIndex = (listElement: Element) => { + debugger + return this.props.getListElements!().indexOf(listElement); + } + + handleClick = (e: React.MouseEvent) => { + const {onClick} = this.props; + onClick!(e); + this.props.handleClick!(e, this.getIndex(e.currentTarget)); + } + + handleKeyDown = (e: React.KeyboardEvent) => { + const {onKeyDown} = this.props; + onKeyDown!(e); + this.props.handleKeyDown!(e, this.getIndex(e.currentTarget)); + } + + handleFocus = (e: React.FocusEvent) => { + const {onFocus} = this.props; + onFocus!(e); + this.props.handleFocus!(e, this.getIndex(e.currentTarget)); + } + + handleBlur = (e: React.FocusEvent) => { + const {onBlur} = this.props; + onBlur!(e); + this.props.handleBlur!(e, this.getIndex(e.currentTarget)); + } + render() { const { /* eslint-disable no-unused-vars */ @@ -89,40 +139,54 @@ export default class ListItem extends React checkboxList, radioList, onDestroy, - renderWithListItemProps, + onClick, + onKeyDown, + onFocus, + onBlur, + handleClick, + handleKeyDown, + handleFocus, + handleBlur, + getListItemInitialTabIndex, + getListElements, + getClassNamesFromList, + tabIndex, /* eslint-enable no-unused-vars */ tag: Tag, ...otherProps } = this.props; + return ( // https://github.com/Microsoft/TypeScript/issues/28892 // @ts-ignore - {this.props.children} + {children} ); } } -class ListItem extends React.Component { - updatedProps?: ListItemProps; - render() { - return ( - - {(getNewProps) => { - this.updatedProps = this.updatedProps || getNewProps(this.props); - return (); - }} - - ); - } -} - -export default ListItem; +const ListItem: React.FunctionComponent = (props) => { + return ( + + {(context) => { + return ( + + ); + }} + + ) +}; export default ListItem; \ No newline at end of file diff --git a/packages/list/index.tsx b/packages/list/index.tsx index 66f64fe8e..9cae3b87c 100644 --- a/packages/list/index.tsx +++ b/packages/list/index.tsx @@ -48,31 +48,45 @@ export interface ListProps extends React.HTMLProps { handleSelect?: (activatedItemIndex: number, selected: MDCListIndex) => void; wrapFocus?: boolean; tag?: string; - // children: ListItem | ListItem[] | React.ReactNode; ref?: React.Ref; }; - interface ListState { listItemClassNames: {[listItemIndex: number]: string[]}, } -// function isReactText(element: any): element is React.ReactText { -// return typeof element === 'string' || typeof element === 'number' || !element; -// } - -// function isListItem(element: any): element is ListItem { -// return element && element.type === ListItem; -// } +export interface ListItemContextShape { + checkboxList?: boolean; + radioList?: boolean; + handleClick?: (e: React.MouseEvent, index: number) => void; + handleKeyDown?: (e: React.KeyboardEvent, index: number) => void; + handleBlur?: (e: React.FocusEvent, index: number) => void; + handleFocus?: (e: React.FocusEvent, index: number) => void; + onDestroy?: (index: number) => void; + getListItemInitialTabIndex?: (index: number) => number; + getClassNamesFromList?: () => ListState['listItemClassNames']; + getListElements?: () => Element[]; + tabIndex?: number +} function isSelectedIndexType(selectedIndex: unknown): selectedIndex is MDCListIndex { return typeof selectedIndex === 'number' && !isNaN(selectedIndex) || Array.isArray(selectedIndex); } -const getDefaultListItemProps: (listItemProps: ListItemProps) => ListItemProps - = () => ({}); -export const ListItemContext = React.createContext(getDefaultListItemProps); -export default class List extends React.Component, ListState> { +const defaultListItemContext: ListItemContextShape = { + handleClick: () => {}, + handleKeyDown: () => {}, + handleBlur: () => {}, + handleFocus: () => {}, + onDestroy: () => {}, + getListItemInitialTabIndex: () => -1, + getClassNamesFromList: () => ({}), + getListElements: () => [], +}; + +export const ListItemContext = React.createContext(defaultListItemContext); + +export default class List extends React.Component { listItemCount = 0; foundation!: MDCListFoundation; hasInitializedListItemTabIndex = false; @@ -178,6 +192,11 @@ export default class List extends React.Com return []; } + // this is a method for ListItem + getListElements = () => { + return this.listElements; + } + get classes() { const { className, @@ -290,15 +309,15 @@ export default class List extends React.Com * 2. if selectedIndex is a number, and the the index === selectedIndex * 3. if there is no selectedIndex */ - private getListItemInitialTabIndex = (index: number) => { + getListItemInitialTabIndex = (index: number) => { const {selectedIndex} = this.props; - let tabIndex = {}; + let tabIndex = -1; if (this.hasInitializedList && !this.hasInitializedListItemTabIndex) { const isSelectedIndexArray = Array.isArray(selectedIndex) && selectedIndex.length > 0 && index === selectedIndex[0]; const isSelected = selectedIndex === index; if (isSelectedIndexArray || isSelected || selectedIndex === -1) { - tabIndex = {tabIndex: 0}; + tabIndex = 0; this.hasInitializedListItemTabIndex = true; } } @@ -311,15 +330,9 @@ export default class List extends React.Com * method merges state.listItemClassNames[index] with listItem.props.className. * The return value is used as the listItem's className. */ - private getListItemClassNames = (index: number, listItem: React.ReactElement>) => { - let {className = ''} = listItem.props; + private getListItemClassNames = () => { const {listItemClassNames} = this.state; - if (listItemClassNames[index]) { - listItemClassNames[index]; - className = classnames(className, listItemClassNames[index]); - } - - return className; + return listItemClassNames; } handleKeyDown = (e: React.KeyboardEvent, index: number) => { @@ -351,6 +364,25 @@ export default class List extends React.Com this.foundation.handleFocusOut(e.nativeEvent, index); }; + onDestroy = (index: number) => { + const {listItemClassNames} = this.state; + delete listItemClassNames[index]; + this.setState({listItemClassNames}); + }; + + listItemProps = { + checkboxList: this.props.checkboxList, + radioList: this.props.radioList, + handleKeyDown: this.handleKeyDown, + handleClick: this.handleClick, + handleFocus: this.handleFocus, + handleBlur: this.handleBlur, + onDestroy: this.onDestroy, + getClassNamesFromList: this.getListItemClassNames, + getListElements: this.getListElements, + getListItemInitialTabIndex: this.getListItemInitialTabIndex, + } + render() { const { /* eslint-disable no-unused-vars */ @@ -372,6 +404,7 @@ export default class List extends React.Com ...otherProps } = this.props; this.listItemCount = 0; + return ( // https://github.com/Microsoft/TypeScript/issues/28892 // @ts-ignore @@ -381,67 +414,12 @@ export default class List extends React.Com role={this.role} {...otherProps} > - + {children} ); } - - getListItemProps = (listItemProps: ListItemProps) => { - const {checkboxList, radioList, selectedIndex} = this.props; - let tabIndex = {}; - const index = this.listItemCount++; - const { - onKeyDown, - onClick, - onFocus, - onBlur, - /* eslint-disable no-unused-vars */ - className: _classNames, - /* eslint-enable no-unused-vars */ - ...otherProps - } = listItemProps; - - const props = { - // otherProps must be first - ...otherProps, - checkboxList, - radioList, - className, - onKeyDown: (e: React.KeyboardEvent) => { - if (onKeyDown) { - onKeyDown(e); - } - this.handleKeyDown(e, index); - }, - onClick: (e: React.MouseEvent) => { - if (onClick) { - onClick(e); - } - console.log('CLICK') - this.handleClick(e, index); - }, - onFocus: (e: React.FocusEvent) => { - if (onFocus) { - onFocus(e); - } - this.handleFocus(e, index); - }, - onBlur: (e: React.FocusEvent) => { - if (onBlur) { - onBlur(e); - } - this.handleBlur(e, index); - }, - onDestroy: () => { - const {listItemClassNames} = this.state; - delete listItemClassNames[index]; - this.setState({listItemClassNames}); - }, - ...tabIndex, - }; - }; } /* eslint-enable quote-props */ diff --git a/test/screenshot/list/index.tsx b/test/screenshot/list/index.tsx index 908c52618..5088052c8 100644 --- a/test/screenshot/list/index.tsx +++ b/test/screenshot/list/index.tsx @@ -205,4 +205,5 @@ const ListScreenshotTest = () => { ); }; + export default ListScreenshotTest; diff --git a/test/unit/list/ListItem.test.tsx b/test/unit/list/ListItem.test.tsx index 08503de50..98301d72f 100644 --- a/test/unit/list/ListItem.test.tsx +++ b/test/unit/list/ListItem.test.tsx @@ -1,8 +1,8 @@ -import * as React from 'react'; -import {assert} from 'chai'; -import * as td from 'testdouble'; -import {mount, shallow} from 'enzyme'; -import {ListItem} from '../../../packages/list/index'; +// import * as React from 'react'; +// import {assert} from 'chai'; +// import * as td from 'testdouble'; +// import {mount, shallow} from 'enzyme'; +// import {ListItem} from '../../../packages/list/index'; // suite('ListItem'); @@ -21,15 +21,15 @@ import {ListItem} from '../../../packages/list/index'; // assert.isTrue(wrapper.hasClass('mdc-list-item--activated')); // }); -test('has activated class if props.disabled = true', () => { - const wrapper = shallow(
meow
); - assert.isTrue(wrapper.hasClass('mdc-list-item--disabled')); -}); +// test('has activated class if props.disabled = true', () => { +// const wrapper = shallow(
meow
); +// assert.isTrue(wrapper.hasClass('mdc-list-item--disabled')); +// }); -test('has selected class if props.selected = true', () => { - const wrapper = shallow(
meow
); - assert.isTrue(wrapper.hasClass('mdc-list-item--selected')); -}); +// test('has selected class if props.selected = true', () => { +// const wrapper = shallow(
meow
); +// assert.isTrue(wrapper.hasClass('mdc-list-item--selected')); +// }); // test('has role=checkbox if props.checkboxList = true', () => { // const wrapper = shallow(
meow
); @@ -76,9 +76,9 @@ test('has selected class if props.selected = true', () => { // assert.equal(wrapper.type(), 'a'); // }); -test('componentWillUnmount calls props.onDestroy()', () => { - const onDestroy = td.func<() => void>(); - const wrapper = shallow(
Test
); - wrapper.unmount(); - td.verify(onDestroy(), {times: 1}); -}); +// test('componentWillUnmount calls props.onDestroy()', () => { +// const onDestroy = td.func<() => void>(); +// const wrapper = shallow(
Test
); +// wrapper.unmount(); +// td.verify(onDestroy(), {times: 1}); +// }); diff --git a/test/unit/list/index.test.tsx b/test/unit/list/index.test.tsx index 3ce7d6fec..029dd55fe 100644 --- a/test/unit/list/index.test.tsx +++ b/test/unit/list/index.test.tsx @@ -153,15 +153,15 @@ // assert.doesNotThrow(() => wrapper.instance().adapter.setAttributeForElementIndex(0, 'role', 'menu')); // }); -test('#adapter.addClassForElementIndex adds classes to listitem', () => { - const wrapper = mount({children()}); - wrapper.instance().adapter.addClassForElementIndex = - coerceForTesting<(index: number, className: string) => void>(td.func()); - wrapper.instance().adapter.addClassForElementIndex(0, 'class4321'); - const listItem = wrapper.childAt(0).childAt(0); - assert.isTrue(listItem.html().includes('class4321')); - assert.isTrue(listItem.html().includes('mdc-list-item')); -}); +// test('#adapter.addClassForElementIndex adds classes to listitem', () => { +// const wrapper = mount({children()}); +// wrapper.instance().adapter.addClassForElementIndex = +// coerceForTesting<(index: number, className: string) => void>(td.func()); +// wrapper.instance().adapter.addClassForElementIndex(0, 'class4321'); +// const listItem = wrapper.childAt(0).childAt(0); +// assert.isTrue(listItem.html().includes('class4321')); +// assert.isTrue(listItem.html().includes('mdc-list-item')); +// }); // test('#adapter.addClassForElementIndex adds class to classList and keeps props.className', () => { // const wrapper = mount( @@ -176,21 +176,21 @@ test('#adapter.addClassForElementIndex adds classes to listitem', () => { // assert.isTrue(listItem.html().includes('mdc-list-item')); // }); -test('#adapter.removeClassForElementIndex removes classname from state.listItemClassNames', () => { - const wrapper = mount( -
meow
-
); - wrapper.setState({listItemClassNames: { - 0: ['class987', 'class4321'], - }}); - wrapper.instance().adapter.removeClassForElementIndex = - coerceForTesting<(index: number, className: string) => void>(td.func()); - wrapper.instance().adapter.removeClassForElementIndex(0, 'class4321'); - const listItem = wrapper.childAt(0).childAt(0); - assert.isFalse(listItem.html().includes('class4321')); - assert.isTrue(listItem.html().includes('class987')); - assert.isTrue(listItem.html().includes('mdc-list-item')); -}); +// test('#adapter.removeClassForElementIndex removes classname from state.listItemClassNames', () => { +// const wrapper = mount( +//
meow
+//
); +// wrapper.setState({listItemClassNames: { +// 0: ['class987', 'class4321'], +// }}); +// wrapper.instance().adapter.removeClassForElementIndex = +// coerceForTesting<(index: number, className: string) => void>(td.func()); +// wrapper.instance().adapter.removeClassForElementIndex(0, 'class4321'); +// const listItem = wrapper.childAt(0).childAt(0); +// assert.isFalse(listItem.html().includes('class4321')); +// assert.isTrue(listItem.html().includes('class987')); +// assert.isTrue(listItem.html().includes('mdc-list-item')); +// }); // test('#adapter.setTabIndexForListItemChildren updates the button and anchor tag to have tabindex=0', () => { // const wrapper = mount( @@ -357,14 +357,14 @@ test('#adapter.removeClassForElementIndex removes classname from state.listItemC // assert.equal(wrapper.props().role, 'menu'); // }); -test('#listItem.props.onDestroy removes class name from state.listItemClassNames', () => { - const wrapper = mount( -
meow
-
); - wrapper.setState({listItemClassNames: {0: ['test']}}); - wrapper.childAt(0).childAt(0).props().onDestroy(); - console.log(wrapper.state().listItemClassNames[0]); -}); +// test('#listItem.props.onDestroy removes class name from state.listItemClassNames', () => { +// const wrapper = mount( +//
meow
+//
); +// wrapper.setState({listItemClassNames: {0: ['test']}}); +// wrapper.childAt(0).childAt(0).props().onDestroy(); +// console.log(wrapper.state().listItemClassNames[0]); +// }); // test('#handleKeyDown calls #foudation.handleKeydown', () => { // const wrapper = shallow({children()}); @@ -416,17 +416,17 @@ test('#listItem.props.onDestroy removes class name from state.listItemClassNames // assert.equal(wrapper.childAt(0).children().length, 3); // }); -test('renders list items with tabindex=-1 and first with tabindex=0', () => { - const wrapper = mount( - - {threeChildren()} - - ); - const list = wrapper.childAt(0); - assert.equal(list.childAt(0).props().tabIndex, 0); - assert.equal(list.childAt(1).props().tabIndex, -1); - assert.equal(list.childAt(2).props().tabIndex, -1); -}); +// test('renders list items with tabindex=-1 and first with tabindex=0', () => { +// const wrapper = mount( +// +// {threeChildren()} +// +// ); +// const list = wrapper.childAt(0); +// assert.equal(list.childAt(0).props().tabIndex, 0); +// assert.equal(list.childAt(1).props().tabIndex, -1); +// assert.equal(list.childAt(2).props().tabIndex, -1); +// }); // test('renders list items with tabindex=-1 and child at props.selectedIndex tabindex=0', () => { // const wrapper = mount( @@ -476,42 +476,42 @@ test('renders list items with tabindex=-1 and first with tabindex=0', () => { // assert.isTrue(wrapper.children().length === 1); // }); -test('renders listItemCount of 2 when 1 disabled and 2 enabled list items', () => { - const wrapper = mount( - - - - - - ); - assert.equal(coerceForTesting(wrapper.instance()).listItemCount, 2); -}); - -test('renders listItemCount of 3 when 1 of the list items changes from disabled to enabled', () => { - const TestComponent = (props: {disabled?: boolean}) => { - const {disabled = true} = props; - return ( - - - - - - ); - }; - const wrapper = mount(); - assert.equal(coerceForTesting(wrapper.childAt(0).instance()).listItemCount, 2); - wrapper.setProps({disabled: false}); - assert.equal(coerceForTesting(wrapper.childAt(0).instance()).listItemCount, 3); -}); - -test('renderWithListItemProps renders passes props to element', () => { - const CustomComponent: React.FunctionComponent> - = () => ; - const wrapper = mount( - - ); - const list = wrapper.childAt(0); - const listItem = list.childAt(0); - assert.isTrue(listItem.props().radioList); - assert.isFalse(listItem.props().checkboxList); -}); +// test('renders listItemCount of 2 when 1 disabled and 2 enabled list items', () => { +// const wrapper = mount( +// +// +// +// +// +// ); +// assert.equal(coerceForTesting(wrapper.instance()).listItemCount, 2); +// }); + +// test('renders listItemCount of 3 when 1 of the list items changes from disabled to enabled', () => { +// const TestComponent = (props: {disabled?: boolean}) => { +// const {disabled = true} = props; +// return ( +// +// +// +// +// +// ); +// }; +// const wrapper = mount(); +// assert.equal(coerceForTesting(wrapper.childAt(0).instance()).listItemCount, 2); +// wrapper.setProps({disabled: false}); +// assert.equal(coerceForTesting(wrapper.childAt(0).instance()).listItemCount, 3); +// }); + +// test('renderWithListItemProps renders passes props to element', () => { +// const CustomComponent: React.FunctionComponent> +// = () => ; +// const wrapper = mount( +// +// ); +// const list = wrapper.childAt(0); +// const listItem = list.childAt(0); +// assert.isTrue(listItem.props().radioList); +// assert.isFalse(listItem.props().checkboxList); +// }); From bb4c79b5e01ec1be1a0933e7760d862476ad00dc Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Wed, 3 Apr 2019 14:00:00 -0700 Subject: [PATCH 15/31] fix: context is working --- packages/list/ListItem.tsx | 33 ++++++++------ packages/list/index.tsx | 88 ++++++++++++++++++++------------------ 2 files changed, 67 insertions(+), 54 deletions(-) diff --git a/packages/list/ListItem.tsx b/packages/list/ListItem.tsx index fddc72bed..7c4d81b8f 100644 --- a/packages/list/ListItem.tsx +++ b/packages/list/ListItem.tsx @@ -57,11 +57,8 @@ class ListItemBase extends React.Component< }; componentDidMount() { - if (this.listItemElement.current) { - const index = this.getIndex(this.listItemElement.current); - const tabIndex = this.props.getListItemInitialTabIndex!(index); - console.log(tabIndex, index) - this.setState({tabIndex}); + if (this.props.hasInitializedList) { + this.initializeTabIndex(); } } @@ -69,6 +66,9 @@ class ListItemBase extends React.Component< if(prevProps.tabIndex !== this.props.tabIndex) { this.setState({tabIndex: this.props.tabIndex}); } + if (!prevProps.hasInitializedList && this.props.hasInitializedList) { + this.initializeTabIndex(); + } } componentWillUnmount() { @@ -101,8 +101,16 @@ class ListItemBase extends React.Component< return null; } + initializeTabIndex = () => { + if (this.listItemElement.current) { + const index = this.getIndex(this.listItemElement.current); + const tabIndex = this.props.getListItemInitialTabIndex!(index); + + this.setState({tabIndex}); + } + } + getIndex = (listElement: Element) => { - debugger return this.props.getListElements!().indexOf(listElement); } @@ -147,9 +155,10 @@ class ListItemBase extends React.Component< handleKeyDown, handleFocus, handleBlur, + hasInitializedList, getListItemInitialTabIndex, - getListElements, getClassNamesFromList, + getListElements, tabIndex, /* eslint-enable no-unused-vars */ tag: Tag, @@ -180,13 +189,11 @@ class ListItemBase extends React.Component< const ListItem: React.FunctionComponent = (props) => { return ( - {(context) => { - return ( - - ); - }} + {(context) => ( + + )} ) }; -export default ListItem; \ No newline at end of file +export default ListItem; diff --git a/packages/list/index.tsx b/packages/list/index.tsx index 9cae3b87c..26a4c2dbf 100644 --- a/packages/list/index.tsx +++ b/packages/list/index.tsx @@ -52,7 +52,8 @@ export interface ListProps extends React.HTMLProps { }; interface ListState { - listItemClassNames: {[listItemIndex: number]: string[]}, + listItemClassNames: {[listItemIndex: number]: string[]}; + listItemProps: ListItemContextShape; } export interface ListItemContextShape { @@ -66,6 +67,7 @@ export interface ListItemContextShape { getListItemInitialTabIndex?: (index: number) => number; getClassNamesFromList?: () => ListState['listItemClassNames']; getListElements?: () => Element[]; + hasInitializedList?: boolean; tabIndex?: number } @@ -82,21 +84,37 @@ const defaultListItemContext: ListItemContextShape = { getListItemInitialTabIndex: () => -1, getClassNamesFromList: () => ({}), getListElements: () => [], + hasInitializedList: false, }; export const ListItemContext = React.createContext(defaultListItemContext); export default class List extends React.Component { - listItemCount = 0; foundation!: MDCListFoundation; hasInitializedListItemTabIndex = false; - hasInitializedList = false; private listElement = React.createRef(); - state: ListState = { - listItemClassNames: {}, - }; + constructor(props: ListItemProps) { + super(props); + + this.state = { + listItemClassNames: {}, + listItemProps: { + checkboxList: props.checkboxList, + radioList: props.radioList, + handleKeyDown: this.handleKeyDown, + handleClick: this.handleClick, + handleFocus: this.handleFocus, + handleBlur: this.handleBlur, + onDestroy: this.onDestroy, + getClassNamesFromList: this.getListItemClassNames, + getListElements: this.getListElements, + hasInitializedList: false, + getListItemInitialTabIndex: this.getListItemInitialTabIndex, + } + }; + } static defaultProps: Partial = { 'className': '', @@ -115,24 +133,26 @@ export default class List extends React.Component { }; componentDidMount() { - const {singleSelection, wrapFocus, selectedIndex} = this.props; - this.foundation = new MDCListFoundation(this.adapter); - this.foundation.init(); - this.foundation.setSingleSelection(singleSelection!); - this.foundation.layout(); - if (isSelectedIndexType(selectedIndex)) { - this.foundation.setSelectedIndex(selectedIndex); - } - this.foundation.setWrapFocus(wrapFocus!); - this.foundation.setVerticalOrientation( - this.props[ARIA_ORIENTATION] === VERTICAL - ); - this.initializeListType(); - // tabIndex for the list items can only be initialized after // the above logic has executed. Once this is true, we need to call forceUpdate. - this.hasInitializedList = true; - this.forceUpdate(); + const listItemProps: ListItemContextShape = Object.assign({}, this.state.listItemProps); + listItemProps.hasInitializedList = true; + this.setState({listItemProps}, () => { + const {singleSelection, wrapFocus, selectedIndex} = this.props; + this.foundation = new MDCListFoundation(this.adapter); + this.foundation.init(); + this.foundation.setSingleSelection(singleSelection!); + this.foundation.layout(); + if (isSelectedIndexType(selectedIndex)) { + this.foundation.setSelectedIndex(selectedIndex); + } + this.foundation.setWrapFocus(wrapFocus!); + this.foundation.setVerticalOrientation( + this.props[ARIA_ORIENTATION] === VERTICAL + ); + this.initializeListType(); + }); + } componentDidUpdate(prevProps: ListProps) { @@ -192,7 +212,7 @@ export default class List extends React.Component { return []; } - // this is a method for ListItem + // this is a proxy for ListItem getListElements = () => { return this.listElements; } @@ -304,6 +324,7 @@ export default class List extends React.Component { } /** + * Called from ListItem. * Initializes the tabIndex prop for the listItems. tabIndex is determined by: * 1. if selectedIndex is an array, and the index === selectedIndex[0] * 2. if selectedIndex is a number, and the the index === selectedIndex @@ -312,7 +333,7 @@ export default class List extends React.Component { getListItemInitialTabIndex = (index: number) => { const {selectedIndex} = this.props; let tabIndex = -1; - if (this.hasInitializedList && !this.hasInitializedListItemTabIndex) { + if (!this.hasInitializedListItemTabIndex) { const isSelectedIndexArray = Array.isArray(selectedIndex) && selectedIndex.length > 0 && index === selectedIndex[0]; const isSelected = selectedIndex === index; @@ -370,19 +391,6 @@ export default class List extends React.Component { this.setState({listItemClassNames}); }; - listItemProps = { - checkboxList: this.props.checkboxList, - radioList: this.props.radioList, - handleKeyDown: this.handleKeyDown, - handleClick: this.handleClick, - handleFocus: this.handleFocus, - handleBlur: this.handleBlur, - onDestroy: this.onDestroy, - getClassNamesFromList: this.getListItemClassNames, - getListElements: this.getListElements, - getListItemInitialTabIndex: this.getListItemInitialTabIndex, - } - render() { const { /* eslint-disable no-unused-vars */ @@ -403,8 +411,6 @@ export default class List extends React.Component { tag: Tag, ...otherProps } = this.props; - this.listItemCount = 0; - return ( // https://github.com/Microsoft/TypeScript/issues/28892 // @ts-ignore @@ -414,8 +420,8 @@ export default class List extends React.Component { role={this.role} {...otherProps} > - - {children} + + {this.state.listItemProps.hasInitializedList ? children : null} ); From 06e2ba6194de59b681d8dad1daa8b07040f12f94 Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Wed, 3 Apr 2019 15:07:42 -0700 Subject: [PATCH 16/31] fix: remove context from state --- packages/list/ListItem.tsx | 29 ++++++++------ packages/list/index.tsx | 77 +++++++++++++++----------------------- packages/list/package.json | 1 + 3 files changed, 49 insertions(+), 58 deletions(-) diff --git a/packages/list/ListItem.tsx b/packages/list/ListItem.tsx index 7c4d81b8f..a05daace8 100644 --- a/packages/list/ListItem.tsx +++ b/packages/list/ListItem.tsx @@ -24,6 +24,7 @@ import * as React from 'react'; import classnames from 'classnames'; import {MDCListFoundation} from '@material/list/foundation'; import {ListItemContext, ListItemContextShape} from './index'; +import {closest} from '@material/dom/ponyfill'; export interface ListItemProps extends React.HTMLProps, ListItemContextShape { checkboxList?: boolean; @@ -56,23 +57,32 @@ class ListItemBase extends React.Component< tabIndex: this.props.tabIndex, }; - componentDidMount() { - if (this.props.hasInitializedList) { - this.initializeTabIndex(); + get listElements(): Element[] { + if (this.listItemElement.current) { + const listElement = closest(this.listItemElement.current, `.${MDCListFoundation.cssClasses.ROOT}`); + if (!listElement)return []; + return [].slice.call( + listElement.querySelectorAll(MDCListFoundation.strings.ENABLED_ITEMS_SELECTOR) + ); } + return []; + } + + componentDidMount() { + this.initializeTabIndex(); } componentDidUpdate(prevProps: ListItemProps) { if(prevProps.tabIndex !== this.props.tabIndex) { this.setState({tabIndex: this.props.tabIndex}); } - if (!prevProps.hasInitializedList && this.props.hasInitializedList) { - this.initializeTabIndex(); - } } componentWillUnmount() { - this.props.onDestroy!(0); + if (this.listItemElement.current) { + const index = this.getIndex(this.listItemElement.current); + this.props.onDestroy!(index); + } } get classes() { @@ -105,13 +115,12 @@ class ListItemBase extends React.Component< if (this.listItemElement.current) { const index = this.getIndex(this.listItemElement.current); const tabIndex = this.props.getListItemInitialTabIndex!(index); - this.setState({tabIndex}); } } getIndex = (listElement: Element) => { - return this.props.getListElements!().indexOf(listElement); + return this.listElements.indexOf(listElement); } handleClick = (e: React.MouseEvent) => { @@ -155,10 +164,8 @@ class ListItemBase extends React.Component< handleKeyDown, handleFocus, handleBlur, - hasInitializedList, getListItemInitialTabIndex, getClassNamesFromList, - getListElements, tabIndex, /* eslint-enable no-unused-vars */ tag: Tag, diff --git a/packages/list/index.tsx b/packages/list/index.tsx index 26a4c2dbf..b139d6bc4 100644 --- a/packages/list/index.tsx +++ b/packages/list/index.tsx @@ -53,7 +53,6 @@ export interface ListProps extends React.HTMLProps { interface ListState { listItemClassNames: {[listItemIndex: number]: string[]}; - listItemProps: ListItemContextShape; } export interface ListItemContextShape { @@ -66,8 +65,6 @@ export interface ListItemContextShape { onDestroy?: (index: number) => void; getListItemInitialTabIndex?: (index: number) => number; getClassNamesFromList?: () => ListState['listItemClassNames']; - getListElements?: () => Element[]; - hasInitializedList?: boolean; tabIndex?: number } @@ -83,8 +80,6 @@ const defaultListItemContext: ListItemContextShape = { onDestroy: () => {}, getListItemInitialTabIndex: () => -1, getClassNamesFromList: () => ({}), - getListElements: () => [], - hasInitializedList: false, }; export const ListItemContext = React.createContext(defaultListItemContext); @@ -95,26 +90,9 @@ export default class List extends React.Component { private listElement = React.createRef(); - constructor(props: ListItemProps) { - super(props); - - this.state = { - listItemClassNames: {}, - listItemProps: { - checkboxList: props.checkboxList, - radioList: props.radioList, - handleKeyDown: this.handleKeyDown, - handleClick: this.handleClick, - handleFocus: this.handleFocus, - handleBlur: this.handleBlur, - onDestroy: this.onDestroy, - getClassNamesFromList: this.getListItemClassNames, - getListElements: this.getListElements, - hasInitializedList: false, - getListItemInitialTabIndex: this.getListItemInitialTabIndex, - } - }; - } + state: ListState = { + listItemClassNames: {}, + }; static defaultProps: Partial = { 'className': '', @@ -133,26 +111,19 @@ export default class List extends React.Component { }; componentDidMount() { - // tabIndex for the list items can only be initialized after - // the above logic has executed. Once this is true, we need to call forceUpdate. - const listItemProps: ListItemContextShape = Object.assign({}, this.state.listItemProps); - listItemProps.hasInitializedList = true; - this.setState({listItemProps}, () => { - const {singleSelection, wrapFocus, selectedIndex} = this.props; - this.foundation = new MDCListFoundation(this.adapter); - this.foundation.init(); - this.foundation.setSingleSelection(singleSelection!); - this.foundation.layout(); - if (isSelectedIndexType(selectedIndex)) { - this.foundation.setSelectedIndex(selectedIndex); - } - this.foundation.setWrapFocus(wrapFocus!); - this.foundation.setVerticalOrientation( - this.props[ARIA_ORIENTATION] === VERTICAL - ); - this.initializeListType(); - }); - + const {singleSelection, wrapFocus, selectedIndex} = this.props; + this.foundation = new MDCListFoundation(this.adapter); + this.foundation.init(); + this.foundation.setSingleSelection(singleSelection!); + this.foundation.layout(); + if (isSelectedIndexType(selectedIndex)) { + this.foundation.setSelectedIndex(selectedIndex); + } + this.foundation.setWrapFocus(wrapFocus!); + this.foundation.setVerticalOrientation( + this.props[ARIA_ORIENTATION] === VERTICAL + ); + this.initializeListType(); } componentDidUpdate(prevProps: ListProps) { @@ -391,6 +362,18 @@ export default class List extends React.Component { this.setState({listItemClassNames}); }; + listItemProps = { + checkboxList: this.props.checkboxList, + radioList: this.props.radioList, + handleKeyDown: this.handleKeyDown, + handleClick: this.handleClick, + handleFocus: this.handleFocus, + handleBlur: this.handleBlur, + onDestroy: this.onDestroy, + getClassNamesFromList: this.getListItemClassNames, + getListItemInitialTabIndex: this.getListItemInitialTabIndex, + } + render() { const { /* eslint-disable no-unused-vars */ @@ -420,8 +403,8 @@ export default class List extends React.Component { role={this.role} {...otherProps} > - - {this.state.listItemProps.hasInitializedList ? children : null} + + {children} ); diff --git a/packages/list/package.json b/packages/list/package.json index 4368d69b9..a3091e2f3 100644 --- a/packages/list/package.json +++ b/packages/list/package.json @@ -16,6 +16,7 @@ "url": "https://github.com/material-components/material-components-web-react.git" }, "dependencies": { + "@material/dpm": "^1.1.0", "@material/list": "^1.0.0", "@material/react-checkbox": "^0.10.0", "@material/react-radio": "^0.10.0", From 8ff2d9fef1ced4eefc8c0298b5be153bfb716dd9 Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Wed, 3 Apr 2019 17:10:05 -0700 Subject: [PATCH 17/31] WIP: tests --- package-lock.json | 673 ++++++++++++++++------ package.json | 4 +- packages/list/ListItem.tsx | 16 +- packages/list/index.tsx | 2 +- packages/list/package.json | 2 +- test/unit/list/ListItem.test.tsx | 222 ++++--- test/unit/list/index.test.tsx | 953 +++++++++++++++---------------- 7 files changed, 1131 insertions(+), 741 deletions(-) diff --git a/package-lock.json b/package-lock.json index 917e2e444..84a70609f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2480,7 +2480,6 @@ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", "dev": true, - "optional": true, "requires": { "es6-promisify": "^5.0.0" } @@ -2972,6 +2971,12 @@ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", "dev": true }, + "array-filter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz", + "integrity": "sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=", + "dev": true + }, "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", @@ -3027,6 +3032,17 @@ "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", "dev": true }, + "array.prototype.flat": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.1.tgz", + "integrity": "sha512-rVqIs330nLJvfC7JqYvEWwqVr5QjYF1ib02i3YJtR/fICO6527Tjpc/e4Mvmxh3GIePPreRXMdaGyC99YphWEw==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.10.0", + "function-bind": "^1.1.1" + } + }, "arraybuffer.slice": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", @@ -4610,8 +4626,7 @@ "version": "0.0.2", "resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-0.0.2.tgz", "integrity": "sha1-JrOIXRD6E9t/wBquOquHAZngEkw=", - "dev": true, - "optional": true + "dev": true }, "buffer-xor": { "version": "1.0.3", @@ -6992,9 +7007,9 @@ } }, "css-what": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz", - "integrity": "sha1-lGfQMsOM+u+58teVASUwYvh/ob0=", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", + "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==", "dev": true }, "cssesc": { @@ -7412,21 +7427,13 @@ } }, "dom-serializer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", - "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", + "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", "dev": true, "requires": { - "domelementtype": "~1.1.1", - "entities": "~1.1.1" - }, - "dependencies": { - "domelementtype": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", - "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", - "dev": true - } + "domelementtype": "^1.3.0", + "entities": "^1.1.1" } }, "domain-browser": { @@ -7436,15 +7443,15 @@ "dev": true }, "domelementtype": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", - "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", "dev": true }, "domhandler": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.1.tgz", - "integrity": "sha1-iS5HAAqZvlW783dP/qBWHYh5wlk=", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", "dev": true, "requires": { "domelementtype": "1" @@ -7695,53 +7702,133 @@ "dev": true }, "enzyme": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/enzyme/-/enzyme-3.3.0.tgz", - "integrity": "sha512-l8csyPyLmtxskTz6pX9W8eDOyH1ckEtDttXk/vlFWCjv00SkjTjtoUrogqp4yEvMyneU9dUJoOLnqFoiHb8IHA==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/enzyme/-/enzyme-3.9.0.tgz", + "integrity": "sha512-JqxI2BRFHbmiP7/UFqvsjxTirWoM1HfeaJrmVSZ9a1EADKkZgdPcAuISPMpoUiHlac9J4dYt81MC5BBIrbJGMg==", "dev": true, "requires": { + "array.prototype.flat": "^1.2.1", "cheerio": "^1.0.0-rc.2", - "function.prototype.name": "^1.0.3", - "has": "^1.0.1", + "function.prototype.name": "^1.1.0", + "has": "^1.0.3", + "html-element-map": "^1.0.0", "is-boolean-object": "^1.0.0", - "is-callable": "^1.1.3", + "is-callable": "^1.1.4", "is-number-object": "^1.0.3", + "is-regex": "^1.0.4", "is-string": "^1.0.4", "is-subset": "^0.1.1", - "lodash": "^4.17.4", - "object-inspect": "^1.5.0", + "lodash.escape": "^4.0.1", + "lodash.isequal": "^4.5.0", + "object-inspect": "^1.6.0", "object-is": "^1.0.1", "object.assign": "^4.1.0", "object.entries": "^1.0.4", "object.values": "^1.0.4", "raf": "^3.4.0", - "rst-selector-parser": "^2.2.3" + "rst-selector-parser": "^2.2.3", + "string.prototype.trim": "^1.1.2" + }, + "dependencies": { + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + } } }, "enzyme-adapter-react-16": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.1.1.tgz", - "integrity": "sha512-kC8pAtU2Jk3OJ0EG8Y2813dg9Ol0TXi7UNxHzHiWs30Jo/hj7alc//G1YpKUsPP1oKl9X+Lkx+WlGJpPYA+nvw==", + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.11.2.tgz", + "integrity": "sha512-2ruTTCPRb0lPuw/vKTXGVZVBZqh83MNDnakMhzxhpJcIbneEwNy2Cv0KvL97pl57/GOazJHflWNLjwWhex5AAA==", "dev": true, "requires": { - "enzyme-adapter-utils": "^1.3.0", - "lodash": "^4.17.4", - "object.assign": "^4.0.4", - "object.values": "^1.0.4", - "prop-types": "^15.6.0", - "react-reconciler": "^0.7.0", - "react-test-renderer": "^16.0.0-0" + "enzyme-adapter-utils": "^1.10.1", + "object.assign": "^4.1.0", + "object.values": "^1.1.0", + "prop-types": "^15.7.2", + "react-is": "^16.8.4", + "react-test-renderer": "^16.0.0-0", + "semver": "^5.6.0" + }, + "dependencies": { + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "dev": true, + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true + } } }, "enzyme-adapter-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/enzyme-adapter-utils/-/enzyme-adapter-utils-1.3.0.tgz", - "integrity": "sha512-vVXSt6uDv230DIv+ebCG66T1Pm36Kv+m74L1TrF4kaE7e1V7Q/LcxO0QRkajk5cA6R3uu9wJf5h13wOTezTbjA==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/enzyme-adapter-utils/-/enzyme-adapter-utils-1.10.1.tgz", + "integrity": "sha512-oasinhhLoBuZsIkTe8mx0HiudtfErUtG0Ooe1FOplu/t4c9rOmyG5gtrBASK6u4whHIRWvv0cbZMElzNTR21SA==", "dev": true, "requires": { - "lodash": "^4.17.4", - "object.assign": "^4.0.4", - "prop-types": "^15.6.0" + "function.prototype.name": "^1.1.0", + "object.assign": "^4.1.0", + "object.fromentries": "^2.0.0", + "prop-types": "^15.7.2", + "semver": "^5.6.0" + }, + "dependencies": { + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "dev": true, + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true + } } }, "errno": { @@ -10146,6 +10233,15 @@ "integrity": "sha1-ZouTd26q5V696POtRkswekljYl4=", "dev": true }, + "html-element-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/html-element-map/-/html-element-map-1.0.1.tgz", + "integrity": "sha512-BZSfdEm6n706/lBfXKWa4frZRZcT5k1cOusw95ijZsHlI+GdgY0v95h6IzO3iIDf2ROwq570YTwqNPqHcNMozw==", + "dev": true, + "requires": { + "array-filter": "^1.0.0" + } + }, "html-entities": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", @@ -10153,17 +10249,39 @@ "dev": true }, "htmlparser2": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz", - "integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", "dev": true, "requires": { - "domelementtype": "^1.3.0", + "domelementtype": "^1.3.1", "domhandler": "^2.3.0", "domutils": "^1.5.1", "entities": "^1.1.1", "inherits": "^2.0.1", - "readable-stream": "^2.0.2" + "readable-stream": "^3.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.3.0.tgz", + "integrity": "sha512-EsI+s3k3XsW+fU8fQACLN59ky34AZ14LoeVZpYwmZvldCFo0r0gnelwF2TcMjLor/BTL5aDJVBMkss0dthToPw==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "string_decoder": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", + "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } } }, "http-deceiver": { @@ -10213,7 +10331,6 @@ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", "dev": true, - "optional": true, "requires": { "agent-base": "4", "debug": "3.1.0" @@ -10224,7 +10341,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, - "optional": true, "requires": { "ms": "2.0.0" } @@ -10276,7 +10392,6 @@ "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.6.1.tgz", "integrity": "sha1-rQFScUOi6Hc8+uapb1hla7UqNLI=", "dev": true, - "optional": true, "requires": { "httpreq": ">=0.4.22", "underscore": "~1.7.0" @@ -10286,8 +10401,7 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/httpreq/-/httpreq-0.4.24.tgz", "integrity": "sha1-QzX/2CzZaWaKOUZckprGHWOTYn8=", - "dev": true, - "optional": true + "dev": true }, "https-browserify": { "version": "1.0.0", @@ -10300,7 +10414,6 @@ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", "dev": true, - "optional": true, "requires": { "agent-base": "^4.1.0", "debug": "^3.1.0" @@ -10311,7 +10424,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, - "optional": true, "requires": { "ms": "2.0.0" } @@ -10658,8 +10770,7 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", - "dev": true, - "optional": true + "dev": true }, "ipaddr.js": { "version": "1.6.0", @@ -12266,15 +12377,13 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-0.1.0.tgz", "integrity": "sha1-YjUag5VjrF/1vSbxL2Dpgwu3UeY=", - "dev": true, - "optional": true + "dev": true }, "libmime": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/libmime/-/libmime-3.0.0.tgz", "integrity": "sha1-UaGp50SOy9Ms2lRCFnW7IbwJPaY=", "dev": true, - "optional": true, "requires": { "iconv-lite": "0.4.15", "libbase64": "0.1.0", @@ -12285,8 +12394,7 @@ "version": "0.4.15", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz", "integrity": "sha1-/iZaIYrGpXz+hUkn6dBMGYJe3es=", - "dev": true, - "optional": true + "dev": true } } }, @@ -12294,8 +12402,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/libqp/-/libqp-1.1.0.tgz", "integrity": "sha1-9ebgatdLeU+1tbZpiL9yjvHe2+g=", - "dev": true, - "optional": true + "dev": true }, "load-json-file": { "version": "1.1.0", @@ -12390,12 +12497,24 @@ "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", "dev": true }, + "lodash.escape": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-4.0.1.tgz", + "integrity": "sha1-yQRGkMIeBClL6qUXcS/e0fqI3pg=", + "dev": true + }, "lodash.flattendeep": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", "dev": true }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=", + "dev": true + }, "lodash.isstring": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", @@ -12558,7 +12677,6 @@ "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", "dev": true, - "optional": true, "requires": { "hoek": "2.x.x" } @@ -12622,8 +12740,7 @@ "version": "2.16.3", "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", - "dev": true, - "optional": true + "dev": true }, "http-signature": { "version": "1.1.1", @@ -13188,6 +13305,12 @@ "integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=", "dev": true }, + "moo": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.4.3.tgz", + "integrity": "sha512-gFD2xGCl8YFgGHsqJ9NKRVdwlioeW3mI1iqfLNYQOv0+6JRwG58Zk9DIGQgyIaffSYaO1xsKnMaYzzNr1KyIAw==", + "dev": true + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -13270,15 +13393,24 @@ "dev": true }, "nearley": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.13.0.tgz", - "integrity": "sha512-ioYYogSaZhFlCpRizQgY3UT3G1qFXmHGY/5ozoFE3dMfiCRAeJfh+IPE3/eh9gCZvqLhPCWb4bLt7Bqzo+1mLQ==", + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.16.0.tgz", + "integrity": "sha512-Tr9XD3Vt/EujXbZBv6UAHYoLUSMQAxSsTnm9K3koXzjzNWY195NqALeyrzLZBKzAkL3gl92BcSogqrHjD8QuUg==", "dev": true, "requires": { - "nomnom": "~1.6.2", + "commander": "^2.19.0", + "moo": "^0.4.3", "railroad-diagrams": "^1.0.0", "randexp": "0.4.6", "semver": "^5.4.1" + }, + "dependencies": { + "commander": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", + "dev": true + } } }, "needle": { @@ -13727,15 +13859,13 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/nodemailer-fetch/-/nodemailer-fetch-1.6.0.tgz", "integrity": "sha1-ecSQihwPXzdbc/6IjamCj23JY6Q=", - "dev": true, - "optional": true + "dev": true }, "nodemailer-shared": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/nodemailer-shared/-/nodemailer-shared-1.1.0.tgz", "integrity": "sha1-z1mU4v0mjQD1zw+nZ6CBae2wfsA=", "dev": true, - "optional": true, "requires": { "nodemailer-fetch": "1.6.0" } @@ -13768,32 +13898,7 @@ "version": "0.1.10", "resolved": "https://registry.npmjs.org/nodemailer-wellknown/-/nodemailer-wellknown-0.1.10.tgz", "integrity": "sha1-WG24EB2zDLRDjrVGc3pBqtDPE9U=", - "dev": true, - "optional": true - }, - "nomnom": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.6.2.tgz", - "integrity": "sha1-hKZqJgF0QI/Ft3oY+IjszET7aXE=", - "dev": true, - "requires": { - "colors": "0.5.x", - "underscore": "~1.4.4" - }, - "dependencies": { - "colors": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/colors/-/colors-0.5.1.tgz", - "integrity": "sha1-fQAj6usVTo7p/Oddy5I9DtFmd3Q=", - "dev": true - }, - "underscore": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", - "integrity": "sha1-YaajIBBiKvoHljvzJSA88SI51gQ=", - "dev": true - } - } + "dev": true }, "nopt": { "version": "3.0.6", @@ -13878,9 +13983,9 @@ } }, "nth-check": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz", - "integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", "dev": true, "requires": { "boolbase": "~1.0.0" @@ -13982,9 +14087,9 @@ } }, "object-inspect": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.5.0.tgz", - "integrity": "sha512-UmOFbHbwvv+XHj7BerrhVq+knjceBdkvU5AriwLMvhv2qi+e7DJzxfBeFpILEjVzCp+xA+W/pIf06RGPWlZNfw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", + "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", "dev": true }, "object-is": { @@ -14029,15 +14134,152 @@ } }, "object.entries": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.0.4.tgz", - "integrity": "sha1-G/mk3SKI9bM/Opk9JXZh8F0WGl8=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.0.tgz", + "integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" + }, + "dependencies": { + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "es-abstract": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, + "object-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz", + "integrity": "sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg==", + "dev": true + } + } + }, + "object.fromentries": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.0.tgz", + "integrity": "sha512-9iLiI6H083uiqUuvzyY6qrlmc/Gz8hLQFOcb/Ri/0xXFkSNS3ctV+CbE6yM2+AnkYfOB3dGjdzC0wrMLIhQICA==", "dev": true, "requires": { "define-properties": "^1.1.2", - "es-abstract": "^1.6.1", - "function-bind": "^1.1.0", + "es-abstract": "^1.11.0", + "function-bind": "^1.1.1", "has": "^1.0.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" + }, + "dependencies": { + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + } + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, + "object-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz", + "integrity": "sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg==", + "dev": true + } } }, "object.omit": { @@ -14068,15 +14310,81 @@ } }, "object.values": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.0.4.tgz", - "integrity": "sha1-5STaCbT2b/Bd9FdUbscqyZ8TBpo=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", + "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.6.1", - "function-bind": "^1.1.0", - "has": "^1.0.1" + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" + }, + "dependencies": { + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "es-abstract": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, + "object-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz", + "integrity": "sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg==", + "dev": true + } } }, "obuf": { @@ -15624,9 +15932,9 @@ "dev": true }, "raf": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.0.tgz", - "integrity": "sha512-pDP/NMRAXoTfrhCfyfSEwJAKLaxBU9eApMeBPB1TkDouZmvPerIClV8lTAd+uF8ZiTaVl69e1FCxQrAd/VTjGw==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", "dev": true, "requires": { "performance-now": "^2.1.0" @@ -15754,17 +16062,11 @@ "prop-types": "^15.6.0" } }, - "react-reconciler": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.7.0.tgz", - "integrity": "sha512-50JwZ3yNyMS8fchN+jjWEJOH3Oze7UmhxeoJLn2j6f3NjpfCRbcmih83XTWmzqtar/ivd5f7tvQhvvhism2fgg==", - "dev": true, - "requires": { - "fbjs": "^0.8.16", - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.0" - } + "react-is": { + "version": "16.8.6", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz", + "integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==", + "dev": true }, "react-router": { "version": "4.3.1", @@ -15813,14 +16115,37 @@ } }, "react-test-renderer": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.2.0.tgz", - "integrity": "sha512-Kd4gJFtpNziR9ElOE/C23LeflKLZPRpNQYWP3nQBY43SJ5a+xyEGSeMrm2zxNKXcnCbBS/q1UpD9gqd5Dv+rew==", + "version": "16.8.6", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.8.6.tgz", + "integrity": "sha512-H2srzU5IWYT6cZXof6AhUcx/wEyJddQ8l7cLM/F7gDXYyPr4oq+vCIxJYXVGhId1J706sqziAjuOEjyNkfgoEw==", "dev": true, "requires": { - "fbjs": "^0.8.16", "object-assign": "^4.1.1", - "prop-types": "^15.6.0" + "prop-types": "^15.6.2", + "react-is": "^16.8.6", + "scheduler": "^0.13.6" + }, + "dependencies": { + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "dev": true, + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + } } }, "read-cmd-shim": { @@ -16517,6 +16842,16 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true }, + "scheduler": { + "version": "0.13.6", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.6.tgz", + "integrity": "sha512-IWnObHt413ucAYKsD9J1QShUKkbKLQQHdxRyw73sw4FN26iWr3DY/H34xGPe4nmL1DwXyWmSWmMrA9TfQbE/XQ==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, "schema-utils": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", @@ -16801,7 +17136,6 @@ "resolved": "https://registry.npmjs.org/smtp-connection/-/smtp-connection-2.12.0.tgz", "integrity": "sha1-1275EnyyPCJZ7bHoNJwujV4tdME=", "dev": true, - "optional": true, "requires": { "httpntlm": "1.6.1", "nodemailer-shared": "1.1.0" @@ -17435,6 +17769,17 @@ "strip-ansi": "^3.0.0" } }, + "string.prototype.trim": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz", + "integrity": "sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.0", + "function-bind": "^1.0.2" + } + }, "string_decoder": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", @@ -18682,8 +19027,7 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=", - "dev": true, - "optional": true + "dev": true }, "union-value": { "version": "1.0.0", @@ -20241,8 +20585,7 @@ "version": "2.1.1", "resolved": false, "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -20274,7 +20617,6 @@ "resolved": false, "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -20291,8 +20633,7 @@ "version": "1.1.0", "resolved": false, "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", @@ -20305,8 +20646,7 @@ "version": "1.1.0", "resolved": false, "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -20437,8 +20777,7 @@ "version": "2.0.3", "resolved": false, "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -20452,7 +20791,6 @@ "resolved": false, "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -20469,7 +20807,6 @@ "resolved": false, "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -20478,15 +20815,13 @@ "version": "0.0.8", "resolved": false, "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.2.4", "resolved": false, "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==", "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -20507,7 +20842,6 @@ "resolved": false, "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -20596,8 +20930,7 @@ "version": "1.0.1", "resolved": false, "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -20611,7 +20944,6 @@ "resolved": false, "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -20707,8 +21039,7 @@ "version": "5.1.1", "resolved": false, "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -20750,7 +21081,6 @@ "resolved": false, "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -20772,7 +21102,6 @@ "resolved": false, "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -20821,15 +21150,13 @@ "version": "1.0.2", "resolved": false, "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.2", "resolved": false, "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", - "dev": true, - "optional": true + "dev": true } } }, diff --git a/package.json b/package.json index 0102ff74e..c768ec816 100644 --- a/package.json +++ b/package.json @@ -122,8 +122,8 @@ "cp-file": "^6.0.0", "cross-env": "^5.2.0", "css-loader": "^0.28.10", - "enzyme": "^3.3.0", - "enzyme-adapter-react-16": "^1.1.1", + "enzyme": "^3.9.0", + "enzyme-adapter-react-16": "^1.11.2", "eslint": "^5.9.0", "eslint-config-google": "^0.9.1", "eslint-plugin-react": "^7.7.0", diff --git a/packages/list/ListItem.tsx b/packages/list/ListItem.tsx index a05daace8..9f487998e 100644 --- a/packages/list/ListItem.tsx +++ b/packages/list/ListItem.tsx @@ -35,8 +35,12 @@ export interface ListItemProps extends Reac ref?: React.Ref; }; -class ListItemBase extends React.Component< - ListItemProps, {tabIndex?: number}> { +export interface ListItemState { + tabIndex?: number; +} + +export class ListItemBase extends React.Component< + ListItemProps, ListItemState> { private listItemElement = React.createRef(); @@ -51,6 +55,12 @@ class ListItemBase extends React.Component< onBlur: () => {}, onDestroy: () => {}, tag: 'li', + handleClick: () => {}, + handleKeyDown: () => {}, + handleBlur: () => {}, + handleFocus: () => {}, + getListItemInitialTabIndex: () => -1, + getClassNamesFromList: () => ({}), }; state = { @@ -111,7 +121,7 @@ class ListItemBase extends React.Component< return null; } - initializeTabIndex = () => { + private initializeTabIndex = () => { if (this.listItemElement.current) { const index = this.getIndex(this.listItemElement.current); const tabIndex = this.props.getListItemInitialTabIndex!(index); diff --git a/packages/list/index.tsx b/packages/list/index.tsx index b139d6bc4..58b797ba2 100644 --- a/packages/list/index.tsx +++ b/packages/list/index.tsx @@ -72,7 +72,7 @@ function isSelectedIndexType(selectedIndex: unknown): selectedIndex is MDCListIn return typeof selectedIndex === 'number' && !isNaN(selectedIndex) || Array.isArray(selectedIndex); } -const defaultListItemContext: ListItemContextShape = { +export const defaultListItemContext: ListItemContextShape = { handleClick: () => {}, handleKeyDown: () => {}, handleBlur: () => {}, diff --git a/packages/list/package.json b/packages/list/package.json index a3091e2f3..52a2843f1 100644 --- a/packages/list/package.json +++ b/packages/list/package.json @@ -16,7 +16,7 @@ "url": "https://github.com/material-components/material-components-web-react.git" }, "dependencies": { - "@material/dpm": "^1.1.0", + "@material/dom": "^1.1.0", "@material/list": "^1.0.0", "@material/react-checkbox": "^0.10.0", "@material/react-radio": "^0.10.0", diff --git a/test/unit/list/ListItem.test.tsx b/test/unit/list/ListItem.test.tsx index 98301d72f..be62b0029 100644 --- a/test/unit/list/ListItem.test.tsx +++ b/test/unit/list/ListItem.test.tsx @@ -1,84 +1,138 @@ -// import * as React from 'react'; -// import {assert} from 'chai'; -// import * as td from 'testdouble'; -// import {mount, shallow} from 'enzyme'; -// import {ListItem} from '../../../packages/list/index'; - -// suite('ListItem'); - -// test('classNames adds classes', () => { -// const wrapper = shallow(
meow
); -// assert.isTrue(wrapper.hasClass('test-class-name')); -// }); - -// test('has mdc-list-item classname', () => { -// const wrapper = shallow(
meow
); -// assert.isTrue(wrapper.hasClass('mdc-list-item')); -// }); - -// test('has activated class if props.activated = true', () => { -// const wrapper = shallow(
meow
); -// assert.isTrue(wrapper.hasClass('mdc-list-item--activated')); -// }); - -// test('has activated class if props.disabled = true', () => { -// const wrapper = shallow(
meow
); -// assert.isTrue(wrapper.hasClass('mdc-list-item--disabled')); -// }); - -// test('has selected class if props.selected = true', () => { -// const wrapper = shallow(
meow
); -// assert.isTrue(wrapper.hasClass('mdc-list-item--selected')); -// }); - -// test('has role=checkbox if props.checkboxList = true', () => { -// const wrapper = shallow(
meow
); -// assert.equal(wrapper.props().role, 'checkbox'); -// }); - -// test('has role=radio if props.radioList = true', () => { -// const wrapper = shallow(
meow
); -// assert.equal(wrapper.props().role, 'radio'); -// }); - -// test('has role=menu if props.role = menu', () => { -// const wrapper = shallow(
meow
); -// assert.equal(wrapper.props().role, 'menu'); -// }); - -// test('is anchor tag if tag=a', () => { -// const wrapper = mount>(
meow
); -// assert.equal(wrapper.find('a').length, 1); -// }); - -// test('listitem can have href tag', () => { -// const wrapper = mount>(
meow
); -// assert.equal(wrapper.props().href, 'google.com'); -// }); - -// test('renders a list item with default tag', () => { -// const wrapper = shallow(
Test
); -// assert.equal(wrapper.type(), 'li'); -// }); - -// test('renders a list item with text content', () => { -// const wrapper = shallow(Test); -// assert.equal(wrapper.type(), 'li'); -// }); - -// test('renders a list item with null as a child', () => { -// const wrapper = shallow(
Test
{null}
); -// assert.equal(wrapper.type(), 'li'); -// }); - -// test('renders a list item with an anchor tag', () => { -// const wrapper = shallow(
Test
); -// assert.equal(wrapper.type(), 'a'); -// }); - -// test('componentWillUnmount calls props.onDestroy()', () => { -// const onDestroy = td.func<() => void>(); -// const wrapper = shallow(
Test
); -// wrapper.unmount(); -// td.verify(onDestroy(), {times: 1}); -// }); +import * as React from 'react'; +import {assert} from 'chai'; +import * as td from 'testdouble'; +import {mount, shallow} from 'enzyme'; +import {ListItemBase as ListItem, ListItemState} from '../../../packages/list/ListItem'; +import { coerceForTesting } from '../helpers/types'; + +suite.only('ListItem'); + +test('classNames adds classes', () => { + const wrapper = shallow(
meow
); + assert.isTrue(wrapper.hasClass('test-class-name')); +}); + +test('has mdc-list-item classname', () => { + const wrapper = shallow(
meow
); + assert.isTrue(wrapper.hasClass('mdc-list-item')); +}); + +test('has activated class if props.activated = true', () => { + const wrapper = shallow(
meow
); + assert.isTrue(wrapper.hasClass('mdc-list-item--activated')); +}); + +test('has activated class if props.disabled = true', () => { + const wrapper = shallow(
meow
); + assert.isTrue(wrapper.hasClass('mdc-list-item--disabled')); +}); + +test('has selected class if props.selected = true', () => { + const wrapper = shallow(
meow
); + assert.isTrue(wrapper.hasClass('mdc-list-item--selected')); +}); + +test('has role=checkbox if props.checkboxList = true', () => { + const wrapper = shallow(
meow
); + assert.equal(wrapper.props().role, 'checkbox'); +}); + +test('has role=radio if props.radioList = true', () => { + const wrapper = shallow(
meow
); + assert.equal(wrapper.props().role, 'radio'); +}); + +test('has role=menu if props.role = menu', () => { + const wrapper = shallow(
meow
); + assert.equal(wrapper.props().role, 'menu'); +}); + +test('is anchor tag if tag=a', () => { + const wrapper = mount>(
meow
); + assert.equal(wrapper.find('a').length, 1); +}); + +test('listitem can have href tag', () => { + const wrapper = mount>(
meow
); + assert.equal(wrapper.props().href, 'google.com'); +}); + +test('renders a list item with default tag', () => { + const wrapper = shallow(
Test
); + assert.equal(wrapper.type(), 'li'); +}); + +test('renders a list item with text content', () => { + const wrapper = shallow(Test); + assert.equal(wrapper.type(), 'li'); +}); + +test('renders a list item with null as a child', () => { + const wrapper = shallow(
Test
{null}
); + assert.equal(wrapper.type(), 'li'); +}); + +test('renders a list item with an anchor tag', () => { + const wrapper = shallow(
Test
); + assert.equal(wrapper.type(), 'a'); +}); + +test('componentWillUnmount calls props.onDestroy()', () => { + const onDestroy = td.func<(index: number) => void>(); + const wrapper = mount(
Test
); + wrapper.unmount(); + td.verify(onDestroy(-1), {times: 1}); +}); + +test('handleClick calls props.handleClick and props.onClick', () => { + const onClick = td.func<(evt: {}) => void>(); + const handleClick = td.func<(evt: {}, index: number) => void>(); + const wrapper = shallow(
Test
); + const evt = {}; + wrapper.simulate('click', evt); + td.verify(onClick(evt), {times: 1}); + td.verify(handleClick(evt, -1), {times: 1}); +}); + +test('handleKeyDown calls props.handleKeyDown and props.onKeyDown', () => { + const onKeyDown = td.func<(evt: {}) => void>(); + const handleKeyDown = td.func<(evt: {}, index: number) => void>(); + const wrapper = shallow(
Test
); + const evt = {}; + wrapper.simulate('keydown', evt); + td.verify(onKeyDown(evt), {times: 1}); + td.verify(handleKeyDown(evt, -1), {times: 1}); +}); + +test('handleFocus calls props.handleFocus and props.onFocus', () => { + const onFocus = td.func<(evt: {}) => void>(); + const handleFocus = td.func<(evt: {}, index: number) => void>(); + const wrapper = shallow(
Test
); + const evt = {}; + wrapper.simulate('focus', evt); + td.verify(onFocus(evt), {times: 1}); + td.verify(handleFocus(evt, -1), {times: 1}); +}); + +test('handleBlur calls props.handleBlur and props.onBlur', () => { + const onBlur = td.func<(evt: {}) => void>(); + const handleBlur = td.func<(evt: {}, index: number) => void>(); + const wrapper = shallow(
Test
); + const evt = {}; + wrapper.simulate('blur', evt); + td.verify(onBlur(evt), {times: 1}); + td.verify(handleBlur(evt, -1), {times: 1}); +}); + +test('renders with tabIndex based off of props.getListItemInitialTabIndex', () => { + const getListItemInitialTabIndex = td.func<(index: number) => number>(); + td.when(getListItemInitialTabIndex(-1)).thenReturn(2); + const wrapper = mount(Test); + assert.equal(coerceForTesting(wrapper.state()).tabIndex, 2) +}); + +test('if props.tabIndex updates, then it changes state.tabIndex', () => { + const wrapper = mount(Test); + + +}); \ No newline at end of file diff --git a/test/unit/list/index.test.tsx b/test/unit/list/index.test.tsx index 029dd55fe..a80387c2f 100644 --- a/test/unit/list/index.test.tsx +++ b/test/unit/list/index.test.tsx @@ -1,480 +1,479 @@ -// import * as React from 'react'; -// import {assert} from 'chai'; -// import * as td from 'testdouble'; -// import {shallow, mount} from 'enzyme'; -// import List, { -// ListItem, ListItemProps, // eslint-disable-line no-unused-vars -// } from '../../../packages/list/index'; -// import {coerceForTesting} from '../helpers/types'; -// import {MDCListIndex} from '@material/list/types'; - -// suite('List'); - -// const children = (opts?: { -// key?: number, -// hasCheckbox?: boolean -// }): React.ReactElement> => ( -// -//
meow
-// {opts && opts.hasCheckbox ? : null} -//
-// ); - -// const threeChildren = (): React.ReactElement>[] => ( -// [0, 1, 2].map((key) => children({key})) -// ); - -// test('creates foundation', () => { -// const wrapper = shallow( -// {children()} -// ); -// assert.exists(wrapper.instance().foundation); -// }); - -// test('#componentWillUnmount destroys foundation', () => { -// const wrapper = shallow({children()}); -// const foundation = wrapper.instance().foundation; -// foundation.destroy = coerceForTesting<() => void>(td.func()); -// wrapper.unmount(); -// td.verify(foundation.destroy()); -// }); - -// test('calls foundation.setSingleSelection when props.singleSelection changes from false to true', () => { -// const wrapper = mount({children()}); -// wrapper.instance().foundation.setSingleSelection = coerceForTesting<(arg: boolean) => void>(td.func()); -// wrapper.setProps({singleSelection: true}); -// td.verify(wrapper.instance().foundation.setSingleSelection(true), { -// times: 1, -// }); -// }); - -// test('calls foundation.setSingleSelection when props.singleSelection changes from true to false', () => { -// const wrapper = mount({children()}); -// wrapper.instance().foundation.setSingleSelection = coerceForTesting<(arg: boolean) => void>(td.func()); -// wrapper.setProps({singleSelection: false}); -// td.verify(wrapper.instance().foundation.setSingleSelection(false), { -// times: 1, -// }); -// }); - -// test('calls foundation.setWrapFocus when props.wrapFocus changes from false to true', () => { -// const wrapper = mount({children()}); -// wrapper.instance().foundation.setWrapFocus = coerceForTesting<(arg: boolean) => void>(td.func()); -// wrapper.setProps({wrapFocus: true}); -// td.verify(wrapper.instance().foundation.setWrapFocus(true), {times: 1}); -// }); - -// test('calls foundation.setWrapFocus when props.wrapFocus changes from true to false', () => { -// const wrapper = mount({children()}); -// wrapper.instance().foundation.setWrapFocus = coerceForTesting<(arg: boolean) => void>(td.func()); -// wrapper.setProps({wrapFocus: false}); -// td.verify(wrapper.instance().foundation.setWrapFocus(false), {times: 1}); -// }); - -// test('calls foundation.setSelectedIndex when props.selectedIndex changes', () => { -// const wrapper = mount({children()}); -// wrapper.instance().foundation.setSelectedIndex = coerceForTesting<(arg: MDCListIndex) => void>(td.func()); -// wrapper.setProps({selectedIndex: 1}); -// td.verify(wrapper.instance().foundation.setSelectedIndex(1), {times: 1}); -// }); - -// test('calls foundation.setVerticalOrientation when \'aria-orientation\' changes from vertical to horizontal', () => { -// const wrapper = mount({children()}); -// wrapper.instance().foundation.setVerticalOrientation = coerceForTesting<(arg: boolean) => void>(td.func()); -// wrapper.setProps({'aria-orientation': 'horizontal'}); -// td.verify(wrapper.instance().foundation.setVerticalOrientation(false), { -// times: 1, -// }); -// }); - -// test('calls foundation.setVerticalOrientation when \'aria-orientation\' changes from horizontal to vertical', () => { -// const wrapper = mount({children()}); -// wrapper.instance().foundation.setVerticalOrientation = coerceForTesting<(arg: boolean) => void>(td.func()); -// wrapper.setProps({'aria-orientation': 'vertical'}); -// td.verify(wrapper.instance().foundation.setVerticalOrientation(true), { -// times: 1, -// }); -// }); - -// test('classNames adds classes', () => { -// const wrapper = shallow({children()}); -// assert.isTrue(wrapper.hasClass('test-class-name')); -// }); - -// test('has mdc-list--non-interactive class if props.nonInteractive is true', () => { -// const wrapper = shallow({children()}); -// assert.isTrue(wrapper.hasClass('mdc-list--non-interactive')); -// }); - -// test('has mdc-list--dense class if props.dense is true', () => { -// const wrapper = shallow({children()}); -// assert.isTrue(wrapper.hasClass('mdc-list--dense')); -// }); - -// test('has mdc-list--avatar-list class if props.avatarList is true', () => { -// const wrapper = shallow({children()}); -// assert.isTrue(wrapper.hasClass('mdc-list--avatar-list')); -// }); - -// test('has mdc-list--two-line class if props.twoLine is true', () => { -// const wrapper = shallow({children()}); -// assert.isTrue(wrapper.hasClass('mdc-list--two-line')); -// }); - -// test('#adapter.getListItemCount returns number of list items', () => { -// const wrapper = mount( -// -// {threeChildren()} -// -// ); -// assert.equal(wrapper.instance().adapter.getListItemCount(), 3); -// }); - -// test('#adapter.getListItemCount returns correct number of list items if List has a non-item child', () => { -// const wrapper = mount( -// -//
meow
-//
meow
-//
meow
-//
-// ); -// assert.equal(wrapper.instance().adapter.getListItemCount(), 3); -// }); - -// test('#adapter.setAttributeForElementIndex calls setAttribute on listItem', () => { -// const wrapper = mount({children()}); -// wrapper.instance().listElements[0].setAttribute = coerceForTesting<(key: string, value: string) => void>(td.func()); -// wrapper.instance().adapter.setAttributeForElementIndex(0, 'role', 'menu'); -// td.verify(wrapper.instance().listElements[0].setAttribute('role', 'menu'), {times: 1}); -// }); - -// test('#adapter.setAttributeForElementIndex call nothing when no children exist', () => { -// const wrapper = mount(); -// assert.doesNotThrow(() => wrapper.instance().adapter.setAttributeForElementIndex(0, 'role', 'menu')); -// }); - -// test('#adapter.addClassForElementIndex adds classes to listitem', () => { -// const wrapper = mount({children()}); -// wrapper.instance().adapter.addClassForElementIndex = -// coerceForTesting<(index: number, className: string) => void>(td.func()); -// wrapper.instance().adapter.addClassForElementIndex(0, 'class4321'); -// const listItem = wrapper.childAt(0).childAt(0); -// assert.isTrue(listItem.html().includes('class4321')); -// assert.isTrue(listItem.html().includes('mdc-list-item')); -// }); - -// test('#adapter.addClassForElementIndex adds class to classList and keeps props.className', () => { -// const wrapper = mount( -//
meow
-//
); -// wrapper.instance().adapter.addClassForElementIndex = -// coerceForTesting<(index: number, className: string) => void>(td.func()); -// wrapper.instance().adapter.addClassForElementIndex(0, 'class4321'); -// const listItem = wrapper.childAt(0).childAt(0); -// assert.isTrue(listItem.html().includes('class4321')); -// assert.isTrue(listItem.html().includes('class987')); -// assert.isTrue(listItem.html().includes('mdc-list-item')); -// }); - -// test('#adapter.removeClassForElementIndex removes classname from state.listItemClassNames', () => { -// const wrapper = mount( -//
meow
-//
); -// wrapper.setState({listItemClassNames: { -// 0: ['class987', 'class4321'], -// }}); -// wrapper.instance().adapter.removeClassForElementIndex = -// coerceForTesting<(index: number, className: string) => void>(td.func()); -// wrapper.instance().adapter.removeClassForElementIndex(0, 'class4321'); -// const listItem = wrapper.childAt(0).childAt(0); -// assert.isFalse(listItem.html().includes('class4321')); -// assert.isTrue(listItem.html().includes('class987')); -// assert.isTrue(listItem.html().includes('mdc-list-item')); -// }); - -// test('#adapter.setTabIndexForListItemChildren updates the button and anchor tag to have tabindex=0', () => { -// const wrapper = mount( -// -// -// link -// -// ); -// wrapper.instance().adapter.setTabIndexForListItemChildren(0, '0'); -// const listItem = wrapper.childAt(0).childAt(0); -// assert.isTrue(listItem.find('a').html().includes('tabindex="0"')); -// assert.isTrue(listItem.find('button').html().includes('tabindex="0"')); -// }); - -// test('#adapter.focusItemAtIndex calls focus on the listitem', () => { -// const wrapper = mount({children()}); -// (wrapper.instance().listElements[0] as HTMLElement).focus -// = coerceForTesting<(opts?: any) => void>(td.func()); -// wrapper.instance().adapter.focusItemAtIndex(0); -// td.verify((wrapper.instance().listElements[0] as HTMLElement).focus(), {times: 1}); -// }); - -// test('#adapter.focusItemAtIndex call nothing when no children exist', () => { -// const wrapper = mount(); -// assert.doesNotThrow(() => wrapper.instance().adapter.focusItemAtIndex(0)); -// }); - -// test('#adapter.setCheckedCheckboxOrRadioAtIndex does not throw', () => { -// const wrapper = shallow({children()}); -// assert.doesNotThrow(() => wrapper.instance().adapter.setCheckedCheckboxOrRadioAtIndex(0, true)); -// }); - -// test('#adapter.hasCheckboxAtIndex returns false with no checkbox', () => { -// const wrapper = mount({children()}); -// assert.isFalse(wrapper.instance().adapter.hasCheckboxAtIndex(0)); -// }); - -// test('#adapter.hasCheckboxAtIndex returns true with checkbox', () => { -// const wrapper = mount( -// -// -// -// ); -// assert.isTrue(wrapper.instance().adapter.hasCheckboxAtIndex(0)); -// }); - -// test('#adapter.hasRadioAtIndex returns false with no checkbox', () => { -// const wrapper = mount({children()}); -// assert.isFalse(wrapper.instance().adapter.hasRadioAtIndex(0)); -// }); - -// test('#adapter.hasRadioAtIndex returns true with checkbox', () => { -// const wrapper = mount( -// -// -// -// ); -// assert.isTrue(wrapper.instance().adapter.hasRadioAtIndex(0)); -// }); - -// test('#adapter.isCheckboxCheckedAtIndex returns false with a non-checked checkbox', () => { -// const wrapper = mount( -// -// -// -// ); -// assert.isFalse(wrapper.instance().adapter.isCheckboxCheckedAtIndex(0)); -// }); - -// test('#adapter.isCheckboxCheckedAtIndex returns true with a checked checkbox', () => { -// const wrapper = mount( -// -// {/* empty onChange to avoid a warning */} -// {}} /> -// -// ); -// assert.isTrue(wrapper.instance().adapter.isCheckboxCheckedAtIndex(0)); -// }); - -// test('#adapter.isFocusInsideList returns true if the list element has focus inside', () => { -// const div = document.createElement('div'); -// // needs to be attached to real DOM to get width -// // https://github.com/airbnb/enzyme/issues/1525 -// document.body.append(div); -// const options = {attachTo: div}; -// const wrapper = mount( -// -// -// -// , options); -// wrapper.instance().listElements[0].querySelector('button')!.focus(); -// assert.isTrue(wrapper.instance().adapter.isFocusInsideList()); -// div.remove(); -// }); - -// test('#adapter.isFocusInsideList returns true if the list element has focus inside', () => { -// const wrapper = mount( -// -// -// -// ); -// assert.isFalse(wrapper.instance().adapter.isFocusInsideList()); -// }); - -// test('#adapter.notifyAction calls props.handleSelect with args', () => { -// const handleSelect = coerceForTesting<(selectedIndex: number, selected: MDCListIndex) => void>(td.func()); -// const wrapper = mount({children}); -// wrapper.instance().adapter.notifyAction(0); -// td.verify(handleSelect(0, -1), {times: 1}); -// }); - -// test('renders with mdc-list class', () => { -// const wrapper = shallow({children}); -// assert.isTrue(wrapper.hasClass('mdc-list')); -// }); - -// test('renders with className', () => { -// const wrapper = shallow({children}); -// assert.isTrue(wrapper.hasClass('test-class')); -// assert.isTrue(wrapper.hasClass('mdc-list')); -// }); - -// test('renders with mdc-list--non-interactive when non-interactive', () => { -// const wrapper = shallow({children}); -// assert.isTrue(wrapper.hasClass('mdc-list--non-interactive')); -// assert.isTrue(wrapper.hasClass('mdc-list')); -// }); - -// test('renders with mdc-list--dense when dense', () => { -// const wrapper = shallow({children}); -// assert.isTrue(wrapper.hasClass('mdc-list--dense')); -// assert.isTrue(wrapper.hasClass('mdc-list')); -// }); - -// test('renders with mdc-list--avatar-list when avatar-list', () => { -// const wrapper = shallow({children}); -// assert.isTrue(wrapper.hasClass('mdc-list--avatar-list')); -// assert.isTrue(wrapper.hasClass('mdc-list')); -// }); - -// test('renders with mdc-list--two-line when two-line', () => { -// const wrapper = shallow({children}); -// assert.isTrue(wrapper.hasClass('mdc-list--two-line')); -// assert.isTrue(wrapper.hasClass('mdc-list')); -// }); - -// test('renders with role=group if props.checkboxList', () => { -// const wrapper = shallow({children}); -// assert.equal(wrapper.props().role, 'group'); -// }); - -// test('renders with role=radiogroup if props.radioList', () => { -// const wrapper = shallow({children}); -// assert.equal(wrapper.props().role, 'radiogroup'); -// }); - -// test('renders with role=menu if props.role=menu', () => { -// const wrapper = shallow({children}); -// assert.equal(wrapper.props().role, 'menu'); -// }); - -// test('renders with role=menu if props.role=menu and props.checkboxList', () => { -// const wrapper = shallow({children}); -// assert.equal(wrapper.props().role, 'menu'); -// }); - -// test('#listItem.props.onDestroy removes class name from state.listItemClassNames', () => { -// const wrapper = mount( -//
meow
-//
); -// wrapper.setState({listItemClassNames: {0: ['test']}}); -// wrapper.childAt(0).childAt(0).props().onDestroy(); -// console.log(wrapper.state().listItemClassNames[0]); -// }); - -// test('#handleKeyDown calls #foudation.handleKeydown', () => { -// const wrapper = shallow({children()}); -// wrapper.instance().foundation.handleKeydown -// = coerceForTesting<(evt: KeyboardEvent, isItem: boolean, itemIndex: number) => void>(td.func()); -// const evt = coerceForTesting({persist: () => {}}); -// wrapper.instance().handleKeyDown(evt, 1); -// td.verify(wrapper.instance().foundation.handleKeydown(evt.nativeEvent, true, 1), { -// times: 1, -// }); -// }); - -// test('#handleClick calls #foudation.handleClick', () => { -// const wrapper = shallow({children()}); -// const target = {type: 'span'}; -// const evt = coerceForTesting>({target}); -// wrapper.instance().foundation.handleClick -// = coerceForTesting<(index: number, toggleCheckbox: boolean) => void>(td.func()); -// wrapper.instance().handleClick(evt, 1); -// td.verify(wrapper.instance().foundation.handleClick(1, false), {times: 1}); -// }); - -// test('#handleFocus calls #foudation.handleFocusIn', () => { -// const wrapper = shallow({children()}); -// wrapper.instance().foundation.handleFocusIn -// = coerceForTesting<(e: FocusEvent, itemIndex: number) => void>(td.func()); -// const evt = coerceForTesting({}); -// wrapper.instance().handleFocus(evt, 1); -// td.verify(wrapper.instance().foundation.handleFocusIn(evt.nativeEvent, 1), {times: 1}); -// }); - -// test('#handleBlur calls #foudation.handleFocusOut', () => { -// const wrapper = shallow({children()}); -// wrapper.instance().foundation.handleFocusOut -// = coerceForTesting<(e: FocusEvent, itemIndex: number) => void>(td.func()); -// const evt = coerceForTesting({}); -// wrapper.instance().handleBlur(evt, 1); -// td.verify(wrapper.instance().foundation.handleFocusOut(evt.nativeEvent, 1), { -// times: 1, -// }); -// }); - -// test('renders 3 list items', () => { -// const wrapper = mount( -// -// {threeChildren()} -// -// ); -// assert.equal(wrapper.childAt(0).children().length, 3); -// }); - -// test('renders list items with tabindex=-1 and first with tabindex=0', () => { -// const wrapper = mount( -// -// {threeChildren()} -// -// ); -// const list = wrapper.childAt(0); -// assert.equal(list.childAt(0).props().tabIndex, 0); -// assert.equal(list.childAt(1).props().tabIndex, -1); -// assert.equal(list.childAt(2).props().tabIndex, -1); -// }); - -// test('renders list items with tabindex=-1 and child at props.selectedIndex tabindex=0', () => { -// const wrapper = mount( -// -// {threeChildren()} -// -// ); -// const list = wrapper.childAt(0); -// assert.equal(list.childAt(0).props().tabIndex, -1); -// assert.equal(list.childAt(1).props().tabIndex, 0); -// assert.equal(list.childAt(2).props().tabIndex, -1); -// }); - -// test('renders list items with tabindex=-1 and child at props.selectedIndex tabindex=0 as an array', -// () => { -// const wrapper = mount( -// -// {children({key: 0, hasCheckbox: true})} -// {children({key: 1, hasCheckbox: true})} -// {children({key: 2, hasCheckbox: true})} -// -// ); -// const list = wrapper.childAt(0); -// assert.equal(list.childAt(0).props().tabIndex, -1); -// assert.equal(list.childAt(1).props().tabIndex, 0); -// assert.equal(list.childAt(2).props().tabIndex, -1); -// }); - -// test('renders a list with default tag', () => { -// const wrapper = shallow({children()}); -// assert.equal(wrapper.type(), 'ul'); -// }); - -// test('renders a list with a nav tag', () => { -// const wrapper = shallow({children()}); -// assert.equal(wrapper.type(), 'nav'); -// }); - -// test('renders a list with children of non-DOM elements', () => { -// const wrapper = shallow( -// {} -// {false} -// {'text'} -// {null} -// {undefined} -// ); -// assert.isTrue(wrapper.children().length === 1); -// }); +import * as React from 'react'; +import {assert} from 'chai'; +import * as td from 'testdouble'; +import {shallow, mount} from 'enzyme'; +import List, { + ListItem, ListItemProps, // eslint-disable-line no-unused-vars +} from '../../../packages/list/index'; +import {coerceForTesting} from '../helpers/types'; +import {MDCListIndex} from '@material/list/types'; + +suite('List'); + +const children = (opts?: { + key?: number, + hasCheckbox?: boolean + }): React.ReactElement> => ( + +
meow
+ {opts && opts.hasCheckbox ? : null} +
+); + +const threeChildren = (): React.ReactElement>[] => ( + [0, 1, 2].map((key) => children({key})) +); + +test('creates foundation', () => { + const wrapper = shallow( + {children()} + ); + assert.exists(wrapper.instance().foundation); +}); + +test('#componentWillUnmount destroys foundation', () => { + const wrapper = shallow({children()}); + const foundation = wrapper.instance().foundation; + foundation.destroy = coerceForTesting<() => void>(td.func()); + wrapper.unmount(); + td.verify(foundation.destroy()); +}); + +test('calls foundation.setSingleSelection when props.singleSelection changes from false to true', () => { + const wrapper = mount({children()}); + wrapper.instance().foundation.setSingleSelection = coerceForTesting<(arg: boolean) => void>(td.func()); + wrapper.setProps({singleSelection: true}); + td.verify(wrapper.instance().foundation.setSingleSelection(true), { + times: 1, + }); +}); + +test('calls foundation.setSingleSelection when props.singleSelection changes from true to false', () => { + const wrapper = mount({children()}); + wrapper.instance().foundation.setSingleSelection = coerceForTesting<(arg: boolean) => void>(td.func()); + wrapper.setProps({singleSelection: false}); + td.verify(wrapper.instance().foundation.setSingleSelection(false), { + times: 1, + }); +}); + +test('calls foundation.setWrapFocus when props.wrapFocus changes from false to true', () => { + const wrapper = mount({children()}); + wrapper.instance().foundation.setWrapFocus = coerceForTesting<(arg: boolean) => void>(td.func()); + wrapper.setProps({wrapFocus: true}); + td.verify(wrapper.instance().foundation.setWrapFocus(true), {times: 1}); +}); + +test('calls foundation.setWrapFocus when props.wrapFocus changes from true to false', () => { + const wrapper = mount({children()}); + wrapper.instance().foundation.setWrapFocus = coerceForTesting<(arg: boolean) => void>(td.func()); + wrapper.setProps({wrapFocus: false}); + td.verify(wrapper.instance().foundation.setWrapFocus(false), {times: 1}); +}); + +test('calls foundation.setSelectedIndex when props.selectedIndex changes', () => { + const wrapper = mount({children()}); + wrapper.instance().foundation.setSelectedIndex = coerceForTesting<(arg: MDCListIndex) => void>(td.func()); + wrapper.setProps({selectedIndex: 1}); + td.verify(wrapper.instance().foundation.setSelectedIndex(1), {times: 1}); +}); + +test('calls foundation.setVerticalOrientation when \'aria-orientation\' changes from vertical to horizontal', () => { + const wrapper = mount({children()}); + wrapper.instance().foundation.setVerticalOrientation = coerceForTesting<(arg: boolean) => void>(td.func()); + wrapper.setProps({'aria-orientation': 'horizontal'}); + td.verify(wrapper.instance().foundation.setVerticalOrientation(false), { + times: 1, + }); +}); + +test('calls foundation.setVerticalOrientation when \'aria-orientation\' changes from horizontal to vertical', () => { + const wrapper = mount({children()}); + wrapper.instance().foundation.setVerticalOrientation = coerceForTesting<(arg: boolean) => void>(td.func()); + wrapper.setProps({'aria-orientation': 'vertical'}); + td.verify(wrapper.instance().foundation.setVerticalOrientation(true), { + times: 1, + }); +}); + +test('classNames adds classes', () => { + const wrapper = shallow({children()}); + assert.isTrue(wrapper.hasClass('test-class-name')); +}); + +test('has mdc-list--non-interactive class if props.nonInteractive is true', () => { + const wrapper = shallow({children()}); + assert.isTrue(wrapper.hasClass('mdc-list--non-interactive')); +}); + +test('has mdc-list--dense class if props.dense is true', () => { + const wrapper = shallow({children()}); + assert.isTrue(wrapper.hasClass('mdc-list--dense')); +}); + +test('has mdc-list--avatar-list class if props.avatarList is true', () => { + const wrapper = shallow({children()}); + assert.isTrue(wrapper.hasClass('mdc-list--avatar-list')); +}); + +test('has mdc-list--two-line class if props.twoLine is true', () => { + const wrapper = shallow({children()}); + assert.isTrue(wrapper.hasClass('mdc-list--two-line')); +}); + +test('#adapter.getListItemCount returns number of list items', () => { + const wrapper = mount( + + {threeChildren()} + + ); + assert.equal(wrapper.instance().adapter.getListItemCount(), 3); +}); + +test('#adapter.getListItemCount returns correct number of list items if List has a non-item child', () => { + const wrapper = mount( + +
meow
+
meow
+
meow
+
+ ); + assert.equal(wrapper.instance().adapter.getListItemCount(), 3); +}); + +test('#adapter.setAttributeForElementIndex calls setAttribute on listItem', () => { + const wrapper = mount({children()}); + wrapper.instance().listElements[0].setAttribute = coerceForTesting<(key: string, value: string) => void>(td.func()); + wrapper.instance().adapter.setAttributeForElementIndex(0, 'role', 'menu'); + td.verify(wrapper.instance().listElements[0].setAttribute('role', 'menu'), {times: 1}); +}); + +test('#adapter.setAttributeForElementIndex call nothing when no children exist', () => { + const wrapper = mount(); + assert.doesNotThrow(() => wrapper.instance().adapter.setAttributeForElementIndex(0, 'role', 'menu')); +}); + +test('#adapter.addClassForElementIndex adds classes to state', () => { + const wrapper = mount({children()}); + wrapper.instance().adapter.addClassForElementIndex = + coerceForTesting<(index: number, className: string) => void>(td.func()); + wrapper.instance().adapter.addClassForElementIndex(0, 'class4321'); + assert.isTrue(wrapper.state().listItemClassNames[0].includes('class4321')); +}); + +test('#adapter.addClassForElementIndex adds multiple classes to state', () => { + const wrapper = mount( +
meow
+
); + wrapper.instance().adapter.addClassForElementIndex = + coerceForTesting<(index: number, className: string) => void>(td.func()); + wrapper.instance().adapter.addClassForElementIndex(0, 'class4321'); + wrapper.instance().adapter.addClassForElementIndex(0, 'class987'); + assert.isTrue(wrapper.state().listItemClassNames[0].includes('class4321')); + assert.isTrue(wrapper.state().listItemClassNames[0].includes('class987')); +}); + +test('#adapter.removeClassForElementIndex removes classname from state.listItemClassNames', () => { + const wrapper = mount( +
meow
+
); + wrapper.setState({listItemClassNames: { + 0: ['class987', 'class4321'], + }}); + wrapper.instance().adapter.removeClassForElementIndex = + coerceForTesting<(index: number, className: string) => void>(td.func()); + wrapper.instance().adapter.removeClassForElementIndex(0, 'class4321'); + assert.isFalse(wrapper.state().listItemClassNames[0].includes('class4321')); + assert.isTrue(wrapper.state().listItemClassNames[0].includes('class987')); +}); + +test('#adapter.setTabIndexForListItemChildren updates the button and anchor tag to have tabindex=0', () => { + const wrapper = mount( + + + link + + ); + wrapper.instance().adapter.setTabIndexForListItemChildren(0, '0'); + const listItem = wrapper.childAt(0).childAt(0); + assert.isTrue(listItem.find('a').html().includes('tabindex="0"')); + assert.isTrue(listItem.find('button').html().includes('tabindex="0"')); +}); + +test('#adapter.focusItemAtIndex calls focus on the listitem', () => { + const wrapper = mount({children()}); + (wrapper.instance().listElements[0] as HTMLElement).focus + = coerceForTesting<(opts?: any) => void>(td.func()); + wrapper.instance().adapter.focusItemAtIndex(0); + td.verify((wrapper.instance().listElements[0] as HTMLElement).focus(), {times: 1}); +}); + +test('#adapter.focusItemAtIndex call nothing when no children exist', () => { + const wrapper = mount(); + assert.doesNotThrow(() => wrapper.instance().adapter.focusItemAtIndex(0)); +}); + +test('#adapter.setCheckedCheckboxOrRadioAtIndex does not throw', () => { + const wrapper = shallow({children()}); + assert.doesNotThrow(() => wrapper.instance().adapter.setCheckedCheckboxOrRadioAtIndex(0, true)); +}); + +test('#adapter.hasCheckboxAtIndex returns false with no checkbox', () => { + const wrapper = mount({children()}); + assert.isFalse(wrapper.instance().adapter.hasCheckboxAtIndex(0)); +}); + +test('#adapter.hasCheckboxAtIndex returns true with checkbox', () => { + const wrapper = mount( + + + + ); + assert.isTrue(wrapper.instance().adapter.hasCheckboxAtIndex(0)); +}); + +test('#adapter.hasRadioAtIndex returns false with no checkbox', () => { + const wrapper = mount({children()}); + assert.isFalse(wrapper.instance().adapter.hasRadioAtIndex(0)); +}); + +test('#adapter.hasRadioAtIndex returns true with checkbox', () => { + const wrapper = mount( + + + + ); + assert.isTrue(wrapper.instance().adapter.hasRadioAtIndex(0)); +}); + +test('#adapter.isCheckboxCheckedAtIndex returns false with a non-checked checkbox', () => { + const wrapper = mount( + + + + ); + assert.isFalse(wrapper.instance().adapter.isCheckboxCheckedAtIndex(0)); +}); + +test('#adapter.isCheckboxCheckedAtIndex returns true with a checked checkbox', () => { + const wrapper = mount( + + {/* empty onChange to avoid a warning */} + {}} /> + + ); + assert.isTrue(wrapper.instance().adapter.isCheckboxCheckedAtIndex(0)); +}); + +test('#adapter.isFocusInsideList returns true if the list element has focus inside', () => { + const div = document.createElement('div'); + // needs to be attached to real DOM to get width + // https://github.com/airbnb/enzyme/issues/1525 + document.body.append(div); + const options = {attachTo: div}; + const wrapper = mount( + + + + , options); + wrapper.instance().listElements[0].querySelector('button')!.focus(); + assert.isTrue(wrapper.instance().adapter.isFocusInsideList()); + div.remove(); +}); + +test('#adapter.isFocusInsideList returns true if the list element has focus inside', () => { + const wrapper = mount( + + + + ); + assert.isFalse(wrapper.instance().adapter.isFocusInsideList()); +}); + +test('#adapter.notifyAction calls props.handleSelect with args', () => { + const handleSelect = td.func<(selectedIndex: number, selected: MDCListIndex) => void>(); + const wrapper = mount( + + + + ); + wrapper.instance().adapter.notifyAction(0); + td.verify(handleSelect(0, -1), {times: 1}); +}); + +test('renders with mdc-list class', () => { + const wrapper = shallow({children}); + assert.isTrue(wrapper.hasClass('mdc-list')); +}); + +test('renders with className', () => { + const wrapper = shallow({children}); + assert.isTrue(wrapper.hasClass('test-class')); + assert.isTrue(wrapper.hasClass('mdc-list')); +}); + +test('renders with mdc-list--non-interactive when non-interactive', () => { + const wrapper = shallow({children}); + assert.isTrue(wrapper.hasClass('mdc-list--non-interactive')); + assert.isTrue(wrapper.hasClass('mdc-list')); +}); + +test('renders with mdc-list--dense when dense', () => { + const wrapper = shallow({children}); + assert.isTrue(wrapper.hasClass('mdc-list--dense')); + assert.isTrue(wrapper.hasClass('mdc-list')); +}); + +test('renders with mdc-list--avatar-list when avatar-list', () => { + const wrapper = shallow({children}); + assert.isTrue(wrapper.hasClass('mdc-list--avatar-list')); + assert.isTrue(wrapper.hasClass('mdc-list')); +}); + +test('renders with mdc-list--two-line when two-line', () => { + const wrapper = shallow({children}); + assert.isTrue(wrapper.hasClass('mdc-list--two-line')); + assert.isTrue(wrapper.hasClass('mdc-list')); +}); + +test('renders with role=group if props.checkboxList', () => { + const wrapper = shallow({children}); + assert.equal(wrapper.props().role, 'group'); +}); + +test('renders with role=radiogroup if props.radioList', () => { + const wrapper = shallow({children}); + assert.equal(wrapper.props().role, 'radiogroup'); +}); + +test('renders with role=menu if props.role=menu', () => { + const wrapper = shallow({children}); + assert.equal(wrapper.props().role, 'menu'); +}); + +test('renders with role=menu if props.role=menu and props.checkboxList', () => { + const wrapper = shallow({children}); + assert.equal(wrapper.props().role, 'menu'); +}); + +test('#onDestroy removes item from state.listItemClassNames', () => { + const wrapper = mount( +
meow
+
); + wrapper.setState({listItemClassNames: {0: ['test']}}); + wrapper.instance().onDestroy(0); + assert.notExists(wrapper.state().listItemClassNames[0]); +}); + +test('#handleKeyDown calls #foudation.handleKeydown', () => { + const wrapper = shallow({children()}); + wrapper.instance().foundation.handleKeydown + = coerceForTesting<(evt: KeyboardEvent, isItem: boolean, itemIndex: number) => void>(td.func()); + const evt = coerceForTesting({persist: () => {}}); + wrapper.instance().handleKeyDown(evt, 1); + td.verify(wrapper.instance().foundation.handleKeydown(evt.nativeEvent, true, 1), { + times: 1, + }); +}); + +test('#handleClick calls #foudation.handleClick', () => { + const wrapper = shallow({children()}); + const target = {type: 'span'}; + const evt = coerceForTesting>({target}); + wrapper.instance().foundation.handleClick + = coerceForTesting<(index: number, toggleCheckbox: boolean) => void>(td.func()); + wrapper.instance().handleClick(evt, 1); + td.verify(wrapper.instance().foundation.handleClick(1, false), {times: 1}); +}); + +test('#handleFocus calls #foudation.handleFocusIn', () => { + const wrapper = shallow({children()}); + wrapper.instance().foundation.handleFocusIn + = coerceForTesting<(e: FocusEvent, itemIndex: number) => void>(td.func()); + const evt = coerceForTesting({}); + wrapper.instance().handleFocus(evt, 1); + td.verify(wrapper.instance().foundation.handleFocusIn(evt.nativeEvent, 1), {times: 1}); +}); + +test('#handleBlur calls #foudation.handleFocusOut', () => { + const wrapper = shallow({children()}); + wrapper.instance().foundation.handleFocusOut + = coerceForTesting<(e: FocusEvent, itemIndex: number) => void>(td.func()); + const evt = coerceForTesting({}); + wrapper.instance().handleBlur(evt, 1); + td.verify(wrapper.instance().foundation.handleFocusOut(evt.nativeEvent, 1), { + times: 1, + }); +}); + +test('renders 3 list items', () => { + const wrapper = mount( + + {threeChildren()} + + ); + assert.equal(wrapper.childAt(0).children().length, 3); +}); + +test('renders list items with tabindex=-1 and first with tabindex=0', () => { + const wrapper = mount( + + {threeChildren()} + + ); + const list = wrapper.childAt(0); + assert.equal(coerceForTesting(list.childAt(0).getDOMNode()).tabIndex, 0); + assert.equal(coerceForTesting(list.childAt(1).getDOMNode()).tabIndex, -1); + assert.equal(coerceForTesting(list.childAt(2).getDOMNode()).tabIndex, -1); +}); + +test('renders list items with tabindex=-1 and child at props.selectedIndex tabindex=0', () => { + const wrapper = mount( + + {threeChildren()} + + ); + const list = wrapper.childAt(0); + assert.equal(coerceForTesting(list.childAt(0).getDOMNode()).tabIndex, -1); + assert.equal(coerceForTesting(list.childAt(1).getDOMNode()).tabIndex, 0); + assert.equal(coerceForTesting(list.childAt(2).getDOMNode()).tabIndex, -1); +}); + +test('renders list items with tabindex=-1 and child at props.selectedIndex tabindex=0 as an array', + () => { + const wrapper = mount( + + {children({key: 0, hasCheckbox: true})} + {children({key: 1, hasCheckbox: true})} + {children({key: 2, hasCheckbox: true})} + + ); + const list = wrapper.childAt(0); + assert.equal(coerceForTesting(list.childAt(0).getDOMNode()).tabIndex, -1); + assert.equal(coerceForTesting(list.childAt(1).getDOMNode()).tabIndex, 0); + assert.equal(coerceForTesting(list.childAt(2).getDOMNode()).tabIndex, -1); + }); + +test('renders a list with default tag', () => { + const wrapper = shallow({children()}); + assert.equal(wrapper.type(), 'ul'); +}); + +test('renders a list with a nav tag', () => { + const wrapper = shallow({children()}); + assert.equal(wrapper.type(), 'nav'); +}); + +test('renders a list with children of non-DOM elements', () => { + const wrapper = shallow( + {} + {false} + {'text'} + {null} + {undefined} + ); + assert.isTrue(wrapper.children().length === 1); +}); // test('renders listItemCount of 2 when 1 disabled and 2 enabled list items', () => { // const wrapper = mount( From 667ed80c811c20c4d721fe345d183cfc29adb4c4 Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Fri, 5 Apr 2019 10:23:06 -0700 Subject: [PATCH 18/31] fix: tests --- packages/list/ListItem.tsx | 7 +++---- packages/menu/MenuListItem.tsx | 1 - test/unit/list/ListItem.test.tsx | 22 ++++++++++++++++------ 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/packages/list/ListItem.tsx b/packages/list/ListItem.tsx index 9f487998e..a825b48fa 100644 --- a/packages/list/ListItem.tsx +++ b/packages/list/ListItem.tsx @@ -41,7 +41,6 @@ export interface ListItemState { export class ListItemBase extends React.Component< ListItemProps, ListItemState> { - private listItemElement = React.createRef(); static defaultProps: Partial> = { @@ -70,7 +69,7 @@ export class ListItemBase extends React.Com get listElements(): Element[] { if (this.listItemElement.current) { const listElement = closest(this.listItemElement.current, `.${MDCListFoundation.cssClasses.ROOT}`); - if (!listElement)return []; + if (!listElement) return []; return [].slice.call( listElement.querySelectorAll(MDCListFoundation.strings.ENABLED_ITEMS_SELECTOR) ); @@ -83,7 +82,7 @@ export class ListItemBase extends React.Com } componentDidUpdate(prevProps: ListItemProps) { - if(prevProps.tabIndex !== this.props.tabIndex) { + if (prevProps.tabIndex !== this.props.tabIndex) { this.setState({tabIndex: this.props.tabIndex}); } } @@ -210,7 +209,7 @@ const ListItem: React.FunctionComponent = (props) => { )} - ) + ); }; export default ListItem; diff --git a/packages/menu/MenuListItem.tsx b/packages/menu/MenuListItem.tsx index 580eb408f..66ce8d577 100644 --- a/packages/menu/MenuListItem.tsx +++ b/packages/menu/MenuListItem.tsx @@ -28,7 +28,6 @@ export interface MenuListItemProps extends } class MenuListItem extends React.Component, {}> { - render() { const { role = 'menuitem', diff --git a/test/unit/list/ListItem.test.tsx b/test/unit/list/ListItem.test.tsx index be62b0029..a5279129c 100644 --- a/test/unit/list/ListItem.test.tsx +++ b/test/unit/list/ListItem.test.tsx @@ -3,9 +3,9 @@ import {assert} from 'chai'; import * as td from 'testdouble'; import {mount, shallow} from 'enzyme'; import {ListItemBase as ListItem, ListItemState} from '../../../packages/list/ListItem'; -import { coerceForTesting } from '../helpers/types'; +import {coerceForTesting} from '../helpers/types'; -suite.only('ListItem'); +suite('ListItem'); test('classNames adds classes', () => { const wrapper = shallow(
meow
); @@ -128,11 +128,21 @@ test('renders with tabIndex based off of props.getListItemInitialTabIndex', () = const getListItemInitialTabIndex = td.func<(index: number) => number>(); td.when(getListItemInitialTabIndex(-1)).thenReturn(2); const wrapper = mount(Test); - assert.equal(coerceForTesting(wrapper.state()).tabIndex, 2) + assert.equal(coerceForTesting(wrapper.state()).tabIndex, 2); }); test('if props.tabIndex updates, then it changes state.tabIndex', () => { - const wrapper = mount(Test); - + const wrapper = mount(Test); + wrapper.setProps({tabIndex: 1}); + assert.equal(coerceForTesting(wrapper.state()).tabIndex, 1); +}); -}); \ No newline at end of file +test('get listElements', () => { + const wrapper = mount(
+ Test + Test + Test +
); + const {listElements} = coerceForTesting(wrapper.childAt(0).instance()); + assert.equal(listElements.length, 3); +}); From 7521f675bcfc2190d2148cc45977db34414a63c7 Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Fri, 5 Apr 2019 11:13:54 -0700 Subject: [PATCH 19/31] fix: commented tests --- packages/menu/README.md | 11 +++++--- packages/menu/index.tsx | 3 +- test/unit/list/index.test.tsx | 40 --------------------------- test/unit/menu-surface/index.test.tsx | 12 ++++---- test/unit/menu/MenuListItem.test.tsx | 5 ---- test/unit/menu/index.test.tsx | 13 ++++----- 6 files changed, 20 insertions(+), 64 deletions(-) diff --git a/packages/menu/README.md b/packages/menu/README.md index 86411d160..4014ecce8 100644 --- a/packages/menu/README.md +++ b/packages/menu/README.md @@ -93,20 +93,23 @@ class MyApp extends React.Component { ### Usage with HOC's -You may want to use Menu or other auxilary components with an HOC, such as [styled-components](https://www.styled-components.com). The only component that requires special handling is MenuListItem, since it contains a prop that needs to be passed to List. Please follow below: +You may want to use Menu or other auxilary components with an HOC, such as [styled-components](https://www.styled-components.com). You can wrap Menu using the following: + ```js import React from 'react'; import Menu, {MenuList, MenuListItem, MenuListItemText} from '@material/react-menu'; import styled from 'styled-components'; +interface MenuState { + coordinates?: {x: number, y: number}; + open: boolean; +}; + const StyledMenuListItem = styled(MenuListItem)` color: blue; `; -// Ensure that you set the HOC's defaultProps to MenuListItem's defaultProps. -StyledMenuListItem.defaultProps = MenuListItem.defaultProps; - class MenuScreenshotTest extends React.Component<{}, MenuState> { state = { diff --git a/packages/menu/index.tsx b/packages/menu/index.tsx index 39a73eb18..dd3224180 100644 --- a/packages/menu/index.tsx +++ b/packages/menu/index.tsx @@ -30,7 +30,7 @@ import MenuListItem from './MenuListItem'; const {cssClasses} = MDCMenuFoundation; -export interface MenuProps extends Exclude { +export interface MenuProps extends MenuSurfaceProps { children: React.ReactElement; onSelected?: (index: number, item: Element) => void; }; @@ -88,6 +88,7 @@ class Menu extends React.Component { return { // TODO: update to new class management system from // https://github.com/material-components/material-components-web-react/pull/776/files + // https://github.com/material-components/material-components-web-react/issues/796 addClassToElementAtIndex: (index, className) => { const list = this.listElements; list[index].classList.add(className); diff --git a/test/unit/list/index.test.tsx b/test/unit/list/index.test.tsx index a80387c2f..ec5b80c5b 100644 --- a/test/unit/list/index.test.tsx +++ b/test/unit/list/index.test.tsx @@ -474,43 +474,3 @@ test('renders a list with children of non-DOM elements', () => {
); assert.isTrue(wrapper.children().length === 1); }); - -// test('renders listItemCount of 2 when 1 disabled and 2 enabled list items', () => { -// const wrapper = mount( -// -// -// -// -// -// ); -// assert.equal(coerceForTesting(wrapper.instance()).listItemCount, 2); -// }); - -// test('renders listItemCount of 3 when 1 of the list items changes from disabled to enabled', () => { -// const TestComponent = (props: {disabled?: boolean}) => { -// const {disabled = true} = props; -// return ( -// -// -// -// -// -// ); -// }; -// const wrapper = mount(); -// assert.equal(coerceForTesting(wrapper.childAt(0).instance()).listItemCount, 2); -// wrapper.setProps({disabled: false}); -// assert.equal(coerceForTesting(wrapper.childAt(0).instance()).listItemCount, 3); -// }); - -// test('renderWithListItemProps renders passes props to element', () => { -// const CustomComponent: React.FunctionComponent> -// = () => ; -// const wrapper = mount( -// -// ); -// const list = wrapper.childAt(0); -// const listItem = list.childAt(0); -// assert.isTrue(listItem.props().radioList); -// assert.isFalse(listItem.props().checkboxList); -// }); diff --git a/test/unit/menu-surface/index.test.tsx b/test/unit/menu-surface/index.test.tsx index 1f4799d98..87062fe7b 100644 --- a/test/unit/menu-surface/index.test.tsx +++ b/test/unit/menu-surface/index.test.tsx @@ -14,21 +14,21 @@ function getAdapter(instance: MenuSurface) { test('classNames adds classes', () => { const wrapper = mount(); - assert.isTrue(wrapper.childAt(0).hasClass('test-class-name')); - assert.isTrue(wrapper.childAt(0).hasClass('mdc-menu-surface')); + assert.isTrue(wrapper.getDOMNode().classList.contains('test-class-name')); + assert.isTrue(wrapper.getDOMNode().classList.contains('mdc-menu-surface')); wrapper.unmount(); }); test('classList adds classes', () => { const wrapper = mount(); wrapper.setState({classList: new Set(['test-class-name'])}); - assert.isTrue(wrapper.childAt(0).hasClass('test-class-name')); + assert.isTrue(wrapper.getDOMNode().classList.contains('test-class-name')); wrapper.unmount(); }); test('props.fixed adds fixed class', () => { const wrapper = mount(); - assert.isTrue(wrapper.childAt(0).hasClass('mdc-menu-surface--fixed')); + assert.isTrue(wrapper.getDOMNode().classList.contains('mdc-menu-surface--fixed')); wrapper.unmount(); }); @@ -509,8 +509,8 @@ test('component styles is applied from this.styles', () => { maxHeight: '200', styleLeft: 50, }); - assert.equal(wrapper.childAt(0).props().style!.maxHeight, 200); - assert.equal(wrapper.childAt(0).props().style!.left, 50); + assert.equal(wrapper.instance().styles.maxHeight, 200); + assert.equal(wrapper.instance().styles.left, 50); wrapper.unmount(); }); diff --git a/test/unit/menu/MenuListItem.test.tsx b/test/unit/menu/MenuListItem.test.tsx index b40ca0898..b63375e51 100644 --- a/test/unit/menu/MenuListItem.test.tsx +++ b/test/unit/menu/MenuListItem.test.tsx @@ -20,8 +20,3 @@ test('role is set to props.role', () => { const wrapper = mount(); assert.equal(wrapper.getDOMNode().getAttribute('role'), 'menu'); }); - -test('menuListItem has props.renderWithListItemProps set to true', () => { - const wrapper = mount(); - assert.isTrue(wrapper.props().renderWithListItemProps); -}); diff --git a/test/unit/menu/index.test.tsx b/test/unit/menu/index.test.tsx index 5aabf8013..c4d4a10e7 100644 --- a/test/unit/menu/index.test.tsx +++ b/test/unit/menu/index.test.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import {assert} from 'chai'; import * as td from 'testdouble'; import {shallow, mount, ShallowWrapper, ReactWrapper} from 'enzyme'; -import Menu, {MenuState, MenuList, MenuListItem, MenuListProps} from '../../../packages/menu/index'; +import Menu, {MenuState, MenuList, MenuListItem} from '../../../packages/menu/index'; import {coerceForTesting} from '../helpers/types'; suite('Menu'); @@ -47,7 +47,7 @@ test('props.open updates from false to true, will set state.open to true', () => assert.isTrue(coerceForTesting(wrapper.state()).open); }); -// TODO: +// TODO: implement with https://github.com/material-components/material-components-web-react/issues/796 // test('adapter.addClassToElementAtIndex adds a class to a listItem', () => { // }); // test('adapter.removeClassToElementAtIndex adds a class to a listItem', () => { @@ -231,9 +231,8 @@ test('menu renders child with handleItemAction', () => { } } const wrapper = mount(
); - const {handleItemAction} = coerceForTesting( - wrapper.childAt(0).childAt(0).childAt(0).props()); - assert.isTrue(typeof handleItemAction === 'function'); + assert.equal( + typeof coerceForTesting(wrapper.instance()).menuListElement.current!.props.handleItemAction, 'function'); wrapper.unmount(); }); @@ -244,8 +243,6 @@ test('menu renders child with wrapFocus', () => { } } const wrapper = mount(
); - const {wrapFocus} = coerceForTesting( - wrapper.childAt(0).childAt(0).childAt(0).props()); - assert.isTrue(wrapFocus); + assert.isTrue(coerceForTesting(wrapper.instance()).menuListElement.current!.props.wrapFocus); wrapper.unmount(); }); From b10563cbb2dc2dbc00b9bde0e4149d321633f0ee Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Fri, 5 Apr 2019 11:23:06 -0700 Subject: [PATCH 20/31] fix: drawer test --- test/unit/drawer/index.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/drawer/index.test.tsx b/test/unit/drawer/index.test.tsx index b029a673b..917c802b7 100644 --- a/test/unit/drawer/index.test.tsx +++ b/test/unit/drawer/index.test.tsx @@ -280,7 +280,7 @@ test('event transitionend triggers foundation.handleTransitionEnd', () => { test('does not render scrim when props.modal is false', () => { const wrapper = shallow(); - assert.equal(wrapper.childAt(1).type(), null); + assert.equal(wrapper.children().length, 1); }); test('renders scrim when props.modal is true', () => { From 1b9b7a1300c69c75b577113fb09d8a25217a5e4f Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Fri, 19 Apr 2019 16:13:08 -0700 Subject: [PATCH 21/31] fix: memoize listProps --- package-lock.json | 512 ++++++++++++++++++-------------- packages/list/index.tsx | 33 +- packages/list/package.json | 4 + test/screenshot/chips/index.tsx | 4 +- test/screenshot/screenshot.tsx | 2 +- test/unit/index.tsx | 4 +- tsconfig.json | 1 + 7 files changed, 313 insertions(+), 247 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0f8fb16c9..70db1701a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2540,6 +2540,7 @@ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", "dev": true, + "optional": true, "requires": { "es6-promisify": "^5.0.0" } @@ -4686,7 +4687,8 @@ "version": "0.0.2", "resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-0.0.2.tgz", "integrity": "sha1-JrOIXRD6E9t/wBquOquHAZngEkw=", - "dev": true + "dev": true, + "optional": true }, "buffer-xor": { "version": "1.0.3", @@ -5011,27 +5013,28 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": false, + "resolved": "", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "resolved": false, + "resolved": "", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", - "resolved": false, + "resolved": "", "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true, "optional": true }, "are-we-there-yet": { "version": "1.1.4", - "resolved": false, + "resolved": "", "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", "dev": true, "optional": true, @@ -5042,15 +5045,17 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", - "resolved": false, + "resolved": "", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5058,39 +5063,42 @@ }, "chownr": { "version": "1.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", "dev": true, "optional": true }, "code-point-at": { "version": "1.1.0", - "resolved": false, + "resolved": "", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", - "resolved": false, + "resolved": "", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true, "optional": true }, "debug": { "version": "2.6.9", - "resolved": false, + "resolved": "", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "optional": true, @@ -5100,28 +5108,28 @@ }, "deep-extend": { "version": "0.5.1", - "resolved": false, + "resolved": "", "integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==", "dev": true, "optional": true }, "delegates": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", - "resolved": false, + "resolved": "", "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "dev": true, "optional": true }, "fs-minipass": { "version": "1.2.5", - "resolved": false, + "resolved": "", "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", "dev": true, "optional": true, @@ -5131,14 +5139,14 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true, "optional": true }, "gauge": { "version": "2.7.4", - "resolved": false, + "resolved": "", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, "optional": true, @@ -5155,7 +5163,7 @@ }, "glob": { "version": "7.1.2", - "resolved": false, + "resolved": "", "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "optional": true, @@ -5170,14 +5178,14 @@ }, "has-unicode": { "version": "2.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true, "optional": true }, "iconv-lite": { "version": "0.4.21", - "resolved": false, + "resolved": "", "integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==", "dev": true, "optional": true, @@ -5187,7 +5195,7 @@ }, "ignore-walk": { "version": "3.0.1", - "resolved": false, + "resolved": "", "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "dev": true, "optional": true, @@ -5197,7 +5205,7 @@ }, "inflight": { "version": "1.0.6", - "resolved": false, + "resolved": "", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "optional": true, @@ -5208,53 +5216,58 @@ }, "inherits": { "version": "2.0.3", - "resolved": false, + "resolved": "", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", - "resolved": false, + "resolved": "", "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } }, "isarray": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true, "optional": true }, "minimatch": { "version": "3.0.4", - "resolved": false, + "resolved": "", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "resolved": false, + "resolved": "", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.2.4", - "resolved": false, + "resolved": "", "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==", "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -5262,7 +5275,7 @@ }, "minizlib": { "version": "1.1.0", - "resolved": false, + "resolved": "", "integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==", "dev": true, "optional": true, @@ -5272,23 +5285,24 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": false, + "resolved": "", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } }, "ms": { "version": "2.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true, "optional": true }, "needle": { "version": "2.2.0", - "resolved": false, + "resolved": "", "integrity": "sha512-eFagy6c+TYayorXw/qtAdSvaUpEbBsDwDyxYFgLZ0lTojfH7K+OdBqAF7TAFwDokJaGpubpSGG0wO3iC0XPi8w==", "dev": true, "optional": true, @@ -5300,7 +5314,7 @@ }, "node-pre-gyp": { "version": "0.10.0", - "resolved": false, + "resolved": "", "integrity": "sha512-G7kEonQLRbcA/mOoFoxvlMrw6Q6dPf92+t/l0DFSMuSlDoWaI9JWIyPwK0jyE1bph//CUEL65/Fz1m2vJbmjQQ==", "dev": true, "optional": true, @@ -5319,7 +5333,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "dev": true, "optional": true, @@ -5330,14 +5344,14 @@ }, "npm-bundled": { "version": "1.0.3", - "resolved": false, + "resolved": "", "integrity": "sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow==", "dev": true, "optional": true }, "npm-packlist": { "version": "1.1.10", - "resolved": false, + "resolved": "", "integrity": "sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA==", "dev": true, "optional": true, @@ -5348,7 +5362,7 @@ }, "npmlog": { "version": "4.1.2", - "resolved": false, + "resolved": "", "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, "optional": true, @@ -5361,43 +5375,45 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", - "resolved": false, + "resolved": "", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true, "optional": true }, "once": { "version": "1.4.0", - "resolved": false, + "resolved": "", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, + "optional": true, "requires": { "wrappy": "1" } }, "os-homedir": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true, "optional": true }, "osenv": { "version": "0.1.5", - "resolved": false, + "resolved": "", "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "dev": true, "optional": true, @@ -5408,21 +5424,21 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true, "optional": true }, "process-nextick-args": { "version": "2.0.0", - "resolved": false, + "resolved": "", "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true, "optional": true }, "rc": { "version": "1.2.7", - "resolved": false, + "resolved": "", "integrity": "sha512-LdLD8xD4zzLsAT5xyushXDNscEjB7+2ulnl8+r1pnESlYtlJtVSoCMBGr30eDRJ3+2Gq89jK9P9e4tCEH1+ywA==", "dev": true, "optional": true, @@ -5435,7 +5451,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": false, + "resolved": "", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true, "optional": true @@ -5444,7 +5460,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": false, + "resolved": "", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "optional": true, @@ -5460,7 +5476,7 @@ }, "rimraf": { "version": "2.6.2", - "resolved": false, + "resolved": "", "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "optional": true, @@ -5470,50 +5486,52 @@ }, "safe-buffer": { "version": "5.1.1", - "resolved": false, + "resolved": "", "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", - "resolved": false, + "resolved": "", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, "optional": true }, "sax": { "version": "1.2.4", - "resolved": false, + "resolved": "", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true, "optional": true }, "semver": { "version": "5.5.0", - "resolved": false, + "resolved": "", "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", "dev": true, "optional": true }, "set-blocking": { "version": "2.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true, "optional": true }, "string-width": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -5522,7 +5540,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": false, + "resolved": "", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "optional": true, @@ -5532,23 +5550,24 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } }, "strip-json-comments": { "version": "2.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true, "optional": true }, "tar": { "version": "4.4.1", - "resolved": false, + "resolved": "", "integrity": "sha512-O+v1r9yN4tOsvl90p5HAP4AEqbYhx4036AGMm075fH9F8Qwi3oJ+v4u50FkT/KkvywNGtwkk0zRI+8eYm1X/xg==", "dev": true, "optional": true, @@ -5564,14 +5583,14 @@ }, "util-deprecate": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true, "optional": true }, "wide-align": { "version": "1.1.2", - "resolved": false, + "resolved": "", "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", "dev": true, "optional": true, @@ -5581,15 +5600,17 @@ }, "wrappy": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", - "dev": true + "dev": true, + "optional": true } } }, @@ -10372,6 +10393,7 @@ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", "dev": true, + "optional": true, "requires": { "agent-base": "4", "debug": "3.1.0" @@ -10382,6 +10404,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, + "optional": true, "requires": { "ms": "2.0.0" } @@ -10433,6 +10456,7 @@ "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.6.1.tgz", "integrity": "sha1-rQFScUOi6Hc8+uapb1hla7UqNLI=", "dev": true, + "optional": true, "requires": { "httpreq": ">=0.4.22", "underscore": "~1.7.0" @@ -10442,7 +10466,8 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/httpreq/-/httpreq-0.4.24.tgz", "integrity": "sha1-QzX/2CzZaWaKOUZckprGHWOTYn8=", - "dev": true + "dev": true, + "optional": true }, "https-browserify": { "version": "1.0.0", @@ -10455,6 +10480,7 @@ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", "dev": true, + "optional": true, "requires": { "agent-base": "^4.1.0", "debug": "^3.1.0" @@ -10465,6 +10491,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, + "optional": true, "requires": { "ms": "2.0.0" } @@ -10811,7 +10838,8 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", - "dev": true + "dev": true, + "optional": true }, "ipaddr.js": { "version": "1.6.0", @@ -12418,13 +12446,15 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-0.1.0.tgz", "integrity": "sha1-YjUag5VjrF/1vSbxL2Dpgwu3UeY=", - "dev": true + "dev": true, + "optional": true }, "libmime": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/libmime/-/libmime-3.0.0.tgz", "integrity": "sha1-UaGp50SOy9Ms2lRCFnW7IbwJPaY=", "dev": true, + "optional": true, "requires": { "iconv-lite": "0.4.15", "libbase64": "0.1.0", @@ -12435,7 +12465,8 @@ "version": "0.4.15", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz", "integrity": "sha1-/iZaIYrGpXz+hUkn6dBMGYJe3es=", - "dev": true + "dev": true, + "optional": true } } }, @@ -12443,7 +12474,8 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/libqp/-/libqp-1.1.0.tgz", "integrity": "sha1-9ebgatdLeU+1tbZpiL9yjvHe2+g=", - "dev": true + "dev": true, + "optional": true }, "load-json-file": { "version": "1.1.0", @@ -12718,6 +12750,7 @@ "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", "dev": true, + "optional": true, "requires": { "hoek": "2.x.x" } @@ -12781,7 +12814,8 @@ "version": "2.16.3", "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", - "dev": true + "dev": true, + "optional": true }, "http-signature": { "version": "1.1.1", @@ -13900,13 +13934,15 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/nodemailer-fetch/-/nodemailer-fetch-1.6.0.tgz", "integrity": "sha1-ecSQihwPXzdbc/6IjamCj23JY6Q=", - "dev": true + "dev": true, + "optional": true }, "nodemailer-shared": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/nodemailer-shared/-/nodemailer-shared-1.1.0.tgz", "integrity": "sha1-z1mU4v0mjQD1zw+nZ6CBae2wfsA=", "dev": true, + "optional": true, "requires": { "nodemailer-fetch": "1.6.0" } @@ -13939,7 +13975,8 @@ "version": "0.1.10", "resolved": "https://registry.npmjs.org/nodemailer-wellknown/-/nodemailer-wellknown-0.1.10.tgz", "integrity": "sha1-WG24EB2zDLRDjrVGc3pBqtDPE9U=", - "dev": true + "dev": true, + "optional": true }, "nopt": { "version": "3.0.6", @@ -17177,6 +17214,7 @@ "resolved": "https://registry.npmjs.org/smtp-connection/-/smtp-connection-2.12.0.tgz", "integrity": "sha1-1275EnyyPCJZ7bHoNJwujV4tdME=", "dev": true, + "optional": true, "requires": { "httpntlm": "1.6.1", "nodemailer-shared": "1.1.0" @@ -19068,7 +19106,8 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=", - "dev": true + "dev": true, + "optional": true }, "union-value": { "version": "1.0.0", @@ -19560,28 +19599,28 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": false, + "resolved": "", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "resolved": false, + "resolved": "", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true, "optional": true }, "aproba": { "version": "1.2.0", - "resolved": false, + "resolved": "", "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true, "optional": true }, "are-we-there-yet": { "version": "1.1.4", - "resolved": false, + "resolved": "", "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", "dev": true, "optional": true, @@ -19592,14 +19631,14 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true, "optional": true }, "brace-expansion": { "version": "1.1.11", - "resolved": false, + "resolved": "", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "optional": true, @@ -19610,42 +19649,42 @@ }, "chownr": { "version": "1.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", "dev": true, "optional": true }, "code-point-at": { "version": "1.1.0", - "resolved": false, + "resolved": "", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true, "optional": true }, "concat-map": { "version": "0.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true, "optional": true }, "console-control-strings": { "version": "1.1.0", - "resolved": false, + "resolved": "", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "dev": true, "optional": true }, "core-util-is": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true, "optional": true }, "debug": { "version": "2.6.9", - "resolved": false, + "resolved": "", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "optional": true, @@ -19655,28 +19694,28 @@ }, "deep-extend": { "version": "0.5.1", - "resolved": false, + "resolved": "", "integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==", "dev": true, "optional": true }, "delegates": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", - "resolved": false, + "resolved": "", "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "dev": true, "optional": true }, "fs-minipass": { "version": "1.2.5", - "resolved": false, + "resolved": "", "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", "dev": true, "optional": true, @@ -19686,14 +19725,14 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true, "optional": true }, "gauge": { "version": "2.7.4", - "resolved": false, + "resolved": "", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, "optional": true, @@ -19710,7 +19749,7 @@ }, "glob": { "version": "7.1.2", - "resolved": false, + "resolved": "", "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "optional": true, @@ -19725,14 +19764,14 @@ }, "has-unicode": { "version": "2.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true, "optional": true }, "iconv-lite": { "version": "0.4.21", - "resolved": false, + "resolved": "", "integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==", "dev": true, "optional": true, @@ -19742,7 +19781,7 @@ }, "ignore-walk": { "version": "3.0.1", - "resolved": false, + "resolved": "", "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "dev": true, "optional": true, @@ -19752,7 +19791,7 @@ }, "inflight": { "version": "1.0.6", - "resolved": false, + "resolved": "", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "optional": true, @@ -19763,21 +19802,21 @@ }, "inherits": { "version": "2.0.3", - "resolved": false, + "resolved": "", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true, "optional": true }, "ini": { "version": "1.3.5", - "resolved": false, + "resolved": "", "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "optional": true, @@ -19787,14 +19826,14 @@ }, "isarray": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true, "optional": true }, "minimatch": { "version": "3.0.4", - "resolved": false, + "resolved": "", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "optional": true, @@ -19804,14 +19843,14 @@ }, "minimist": { "version": "0.0.8", - "resolved": false, + "resolved": "", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true, "optional": true }, "minipass": { "version": "2.2.4", - "resolved": false, + "resolved": "", "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==", "dev": true, "optional": true, @@ -19822,7 +19861,7 @@ }, "minizlib": { "version": "1.1.0", - "resolved": false, + "resolved": "", "integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==", "dev": true, "optional": true, @@ -19832,7 +19871,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": false, + "resolved": "", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "optional": true, @@ -19842,14 +19881,14 @@ }, "ms": { "version": "2.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true, "optional": true }, "needle": { "version": "2.2.0", - "resolved": false, + "resolved": "", "integrity": "sha512-eFagy6c+TYayorXw/qtAdSvaUpEbBsDwDyxYFgLZ0lTojfH7K+OdBqAF7TAFwDokJaGpubpSGG0wO3iC0XPi8w==", "dev": true, "optional": true, @@ -19861,7 +19900,7 @@ }, "node-pre-gyp": { "version": "0.10.0", - "resolved": false, + "resolved": "", "integrity": "sha512-G7kEonQLRbcA/mOoFoxvlMrw6Q6dPf92+t/l0DFSMuSlDoWaI9JWIyPwK0jyE1bph//CUEL65/Fz1m2vJbmjQQ==", "dev": true, "optional": true, @@ -19880,7 +19919,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "dev": true, "optional": true, @@ -19891,14 +19930,14 @@ }, "npm-bundled": { "version": "1.0.3", - "resolved": false, + "resolved": "", "integrity": "sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow==", "dev": true, "optional": true }, "npm-packlist": { "version": "1.1.10", - "resolved": false, + "resolved": "", "integrity": "sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA==", "dev": true, "optional": true, @@ -19909,7 +19948,7 @@ }, "npmlog": { "version": "4.1.2", - "resolved": false, + "resolved": "", "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, "optional": true, @@ -19922,21 +19961,21 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true, "optional": true }, "object-assign": { "version": "4.1.1", - "resolved": false, + "resolved": "", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true, "optional": true }, "once": { "version": "1.4.0", - "resolved": false, + "resolved": "", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "optional": true, @@ -19946,21 +19985,21 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true, "optional": true }, "osenv": { "version": "0.1.5", - "resolved": false, + "resolved": "", "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "dev": true, "optional": true, @@ -19971,21 +20010,21 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true, "optional": true }, "process-nextick-args": { "version": "2.0.0", - "resolved": false, + "resolved": "", "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true, "optional": true }, "rc": { "version": "1.2.7", - "resolved": false, + "resolved": "", "integrity": "sha512-LdLD8xD4zzLsAT5xyushXDNscEjB7+2ulnl8+r1pnESlYtlJtVSoCMBGr30eDRJ3+2Gq89jK9P9e4tCEH1+ywA==", "dev": true, "optional": true, @@ -19998,7 +20037,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": false, + "resolved": "", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true, "optional": true @@ -20007,7 +20046,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": false, + "resolved": "", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "optional": true, @@ -20023,7 +20062,7 @@ }, "rimraf": { "version": "2.6.2", - "resolved": false, + "resolved": "", "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "optional": true, @@ -20033,49 +20072,49 @@ }, "safe-buffer": { "version": "5.1.1", - "resolved": false, + "resolved": "", "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", "dev": true, "optional": true }, "safer-buffer": { "version": "2.1.2", - "resolved": false, + "resolved": "", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, "optional": true }, "sax": { "version": "1.2.4", - "resolved": false, + "resolved": "", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true, "optional": true }, "semver": { "version": "5.5.0", - "resolved": false, + "resolved": "", "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", "dev": true, "optional": true }, "set-blocking": { "version": "2.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true, "optional": true }, "string-width": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "optional": true, @@ -20087,7 +20126,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": false, + "resolved": "", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "optional": true, @@ -20097,7 +20136,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "optional": true, @@ -20107,14 +20146,14 @@ }, "strip-json-comments": { "version": "2.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true, "optional": true }, "tar": { "version": "4.4.1", - "resolved": false, + "resolved": "", "integrity": "sha512-O+v1r9yN4tOsvl90p5HAP4AEqbYhx4036AGMm075fH9F8Qwi3oJ+v4u50FkT/KkvywNGtwkk0zRI+8eYm1X/xg==", "dev": true, "optional": true, @@ -20130,14 +20169,14 @@ }, "util-deprecate": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true, "optional": true }, "wide-align": { "version": "1.1.2", - "resolved": false, + "resolved": "", "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", "dev": true, "optional": true, @@ -20147,14 +20186,14 @@ }, "wrappy": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true, "optional": true }, "yallist": { "version": "3.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", "dev": true, "optional": true @@ -20617,27 +20656,28 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": false, + "resolved": "", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "resolved": false, + "resolved": "", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", - "resolved": false, + "resolved": "", "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true, "optional": true }, "are-we-there-yet": { "version": "1.1.4", - "resolved": false, + "resolved": "", "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", "dev": true, "optional": true, @@ -20648,16 +20688,17 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true, "optional": true }, "brace-expansion": { "version": "1.1.11", - "resolved": false, + "resolved": "", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -20665,40 +20706,42 @@ }, "chownr": { "version": "1.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", "dev": true, "optional": true }, "code-point-at": { "version": "1.1.0", - "resolved": false, + "resolved": "", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true, "optional": true }, "console-control-strings": { "version": "1.1.0", - "resolved": false, + "resolved": "", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true, "optional": true }, "debug": { "version": "2.6.9", - "resolved": false, + "resolved": "", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "optional": true, @@ -20708,28 +20751,28 @@ }, "deep-extend": { "version": "0.5.1", - "resolved": false, + "resolved": "", "integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==", "dev": true, "optional": true }, "delegates": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", - "resolved": false, + "resolved": "", "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "dev": true, "optional": true }, "fs-minipass": { "version": "1.2.5", - "resolved": false, + "resolved": "", "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", "dev": true, "optional": true, @@ -20739,14 +20782,14 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true, "optional": true }, "gauge": { "version": "2.7.4", - "resolved": false, + "resolved": "", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, "optional": true, @@ -20763,7 +20806,7 @@ }, "glob": { "version": "7.1.2", - "resolved": false, + "resolved": "", "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "optional": true, @@ -20778,14 +20821,14 @@ }, "has-unicode": { "version": "2.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true, "optional": true }, "iconv-lite": { "version": "0.4.21", - "resolved": false, + "resolved": "", "integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==", "dev": true, "optional": true, @@ -20795,7 +20838,7 @@ }, "ignore-walk": { "version": "3.0.1", - "resolved": false, + "resolved": "", "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "dev": true, "optional": true, @@ -20805,7 +20848,7 @@ }, "inflight": { "version": "1.0.6", - "resolved": false, + "resolved": "", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "optional": true, @@ -20816,53 +20859,58 @@ }, "inherits": { "version": "2.0.3", - "resolved": false, + "resolved": "", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", - "resolved": false, + "resolved": "", "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } }, "isarray": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true, "optional": true }, "minimatch": { "version": "3.0.4", - "resolved": false, + "resolved": "", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "resolved": false, + "resolved": "", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.2.4", - "resolved": false, + "resolved": "", "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==", "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -20870,7 +20918,7 @@ }, "minizlib": { "version": "1.1.0", - "resolved": false, + "resolved": "", "integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==", "dev": true, "optional": true, @@ -20880,23 +20928,24 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": false, + "resolved": "", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } }, "ms": { "version": "2.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true, "optional": true }, "needle": { "version": "2.2.0", - "resolved": false, + "resolved": "", "integrity": "sha512-eFagy6c+TYayorXw/qtAdSvaUpEbBsDwDyxYFgLZ0lTojfH7K+OdBqAF7TAFwDokJaGpubpSGG0wO3iC0XPi8w==", "dev": true, "optional": true, @@ -20908,7 +20957,7 @@ }, "node-pre-gyp": { "version": "0.10.0", - "resolved": false, + "resolved": "", "integrity": "sha512-G7kEonQLRbcA/mOoFoxvlMrw6Q6dPf92+t/l0DFSMuSlDoWaI9JWIyPwK0jyE1bph//CUEL65/Fz1m2vJbmjQQ==", "dev": true, "optional": true, @@ -20927,7 +20976,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "dev": true, "optional": true, @@ -20938,14 +20987,14 @@ }, "npm-bundled": { "version": "1.0.3", - "resolved": false, + "resolved": "", "integrity": "sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow==", "dev": true, "optional": true }, "npm-packlist": { "version": "1.1.10", - "resolved": false, + "resolved": "", "integrity": "sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA==", "dev": true, "optional": true, @@ -20956,7 +21005,7 @@ }, "npmlog": { "version": "4.1.2", - "resolved": false, + "resolved": "", "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, "optional": true, @@ -20969,43 +21018,45 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", - "resolved": false, + "resolved": "", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true, "optional": true }, "once": { "version": "1.4.0", - "resolved": false, + "resolved": "", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, + "optional": true, "requires": { "wrappy": "1" } }, "os-homedir": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true, "optional": true }, "osenv": { "version": "0.1.5", - "resolved": false, + "resolved": "", "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "dev": true, "optional": true, @@ -21016,21 +21067,21 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true, "optional": true }, "process-nextick-args": { "version": "2.0.0", - "resolved": false, + "resolved": "", "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true, "optional": true }, "rc": { "version": "1.2.7", - "resolved": false, + "resolved": "", "integrity": "sha512-LdLD8xD4zzLsAT5xyushXDNscEjB7+2ulnl8+r1pnESlYtlJtVSoCMBGr30eDRJ3+2Gq89jK9P9e4tCEH1+ywA==", "dev": true, "optional": true, @@ -21043,7 +21094,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": false, + "resolved": "", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true, "optional": true @@ -21052,7 +21103,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": false, + "resolved": "", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "optional": true, @@ -21068,7 +21119,7 @@ }, "rimraf": { "version": "2.6.2", - "resolved": false, + "resolved": "", "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "optional": true, @@ -21078,50 +21129,52 @@ }, "safe-buffer": { "version": "5.1.1", - "resolved": false, + "resolved": "", "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", - "resolved": false, + "resolved": "", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, "optional": true }, "sax": { "version": "1.2.4", - "resolved": false, + "resolved": "", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true, "optional": true }, "semver": { "version": "5.5.0", - "resolved": false, + "resolved": "", "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", "dev": true, "optional": true }, "set-blocking": { "version": "2.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true, "optional": true }, "string-width": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -21130,7 +21183,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": false, + "resolved": "", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "optional": true, @@ -21140,23 +21193,24 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } }, "strip-json-comments": { "version": "2.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true, "optional": true }, "tar": { "version": "4.4.1", - "resolved": false, + "resolved": "", "integrity": "sha512-O+v1r9yN4tOsvl90p5HAP4AEqbYhx4036AGMm075fH9F8Qwi3oJ+v4u50FkT/KkvywNGtwkk0zRI+8eYm1X/xg==", "dev": true, "optional": true, @@ -21172,14 +21226,14 @@ }, "util-deprecate": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true, "optional": true }, "wide-align": { "version": "1.1.2", - "resolved": false, + "resolved": "", "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", "dev": true, "optional": true, @@ -21189,15 +21243,17 @@ }, "wrappy": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", - "dev": true + "dev": true, + "optional": true } } }, diff --git a/packages/list/index.tsx b/packages/list/index.tsx index 58b797ba2..8f12e5b78 100644 --- a/packages/list/index.tsx +++ b/packages/list/index.tsx @@ -25,6 +25,8 @@ import classnames from 'classnames'; import {MDCListFoundation} from '@material/list/foundation'; import {MDCListIndex} from '@material/list/types'; import {MDCListAdapter} from '@material/list/adapter'; +import memoizeOne from 'memoize-one'; + import ListItem, {ListItemProps} from './ListItem'; // eslint-disable-line no-unused-vars import ListItemGraphic from './ListItemGraphic'; import ListItemText from './ListItemText'; @@ -362,18 +364,6 @@ export default class List extends React.Component { this.setState({listItemClassNames}); }; - listItemProps = { - checkboxList: this.props.checkboxList, - radioList: this.props.radioList, - handleKeyDown: this.handleKeyDown, - handleClick: this.handleClick, - handleFocus: this.handleFocus, - handleBlur: this.handleBlur, - onDestroy: this.onDestroy, - getClassNamesFromList: this.getListItemClassNames, - getListItemInitialTabIndex: this.getListItemInitialTabIndex, - } - render() { const { /* eslint-disable no-unused-vars */ @@ -394,6 +384,23 @@ export default class List extends React.Component { tag: Tag, ...otherProps } = this.props; + + const getListProps = (checkboxList?: boolean, radioList?: boolean) => ({ + checkboxList: Boolean(checkboxList), + radioList: Boolean(radioList), + handleKeyDown: this.handleKeyDown, + handleClick: this.handleClick, + handleFocus: this.handleFocus, + handleBlur: this.handleBlur, + onDestroy: this.onDestroy, + getClassNamesFromList: this.getListItemClassNames, + getListItemInitialTabIndex: this.getListItemInitialTabIndex, + }); + + // decreases rerenders + // https://overreacted.io/writing-resilient-components/#dont-stop-the-data-flow-in-rendering + const getMemoizedListProps = memoizeOne(getListProps); + return ( // https://github.com/Microsoft/TypeScript/issues/28892 // @ts-ignore @@ -403,7 +410,7 @@ export default class List extends React.Component { role={this.role} {...otherProps} > - + {children} diff --git a/packages/list/package.json b/packages/list/package.json index 52a2843f1..f6ec35a83 100644 --- a/packages/list/package.json +++ b/packages/list/package.json @@ -21,9 +21,13 @@ "@material/react-checkbox": "^0.10.0", "@material/react-radio": "^0.10.0", "classnames": "^2.2.6", + "memoize-one": "^5.0.4", "react": "^16.4.2" }, "publishConfig": { "access": "public" + }, + "devDependencies": { + "@types/memoize-one": "^4.1.1" } } diff --git a/test/screenshot/chips/index.tsx b/test/screenshot/chips/index.tsx index 7c5c3df95..4beda7001 100644 --- a/test/screenshot/chips/index.tsx +++ b/test/screenshot/chips/index.tsx @@ -3,9 +3,7 @@ import './index.scss'; import '../../../packages/chips/index.scss'; import MaterialIcon from '../../../packages/material-icon'; import {ChipProps, Chip, ChipSet} from '../../../packages/chips/index'; // eslint-disable-line no-unused-vars -// no .d.ts file -// @ts-ignore -import * as uuidv1 from 'uuid/v1'; +import uuidv1 from 'uuid/v1'; interface ChipsTestProps { selectedChipIds: string[]; diff --git a/test/screenshot/screenshot.tsx b/test/screenshot/screenshot.tsx index 9c6d98eb0..7407072a8 100644 --- a/test/screenshot/screenshot.tsx +++ b/test/screenshot/screenshot.tsx @@ -7,7 +7,7 @@ import * as puppeteer from 'puppeteer'; import * as compareImages from 'resemblejs/compareImages'; import {test} from 'mocha'; import {assert} from 'chai'; -import * as Storage from '@google-cloud/storage'; +import Storage from '@google-cloud/storage'; import comparisonOptions from './screenshot-comparison-options'; import axios from 'axios'; import * as path from 'path'; diff --git a/test/unit/index.tsx b/test/unit/index.tsx index 033748dab..c9122d458 100644 --- a/test/unit/index.tsx +++ b/test/unit/index.tsx @@ -1,5 +1,5 @@ -import * as Enzyme from 'enzyme'; -import * as Adapter from 'enzyme-adapter-react-16'; +import Enzyme from 'enzyme'; +import Adapter from 'enzyme-adapter-react-16'; Enzyme.configure({adapter: new Adapter()}); const context = require.context('.', true, /\.test\.(j|t)sx?$/); context.keys().forEach(context); diff --git a/tsconfig.json b/tsconfig.json index 7cb7824dc..59f75ef5a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,6 +9,7 @@ "target": "es5", "noUnusedLocals": true, "noUnusedParameters": true, + "esModuleInterop": true, }, "compileOnSave": true, "exclude": [ From 8ac8668f04ac0e5c5db647a6684763dbfdd2380b Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Fri, 19 Apr 2019 16:23:15 -0700 Subject: [PATCH 22/31] fix: revert esmoduleinterop --- packages/list/index.tsx | 2 +- test/screenshot/chips/index.tsx | 2 +- test/screenshot/screenshot.tsx | 2 +- tsconfig.json | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/list/index.tsx b/packages/list/index.tsx index 8f12e5b78..70267b54c 100644 --- a/packages/list/index.tsx +++ b/packages/list/index.tsx @@ -25,7 +25,7 @@ import classnames from 'classnames'; import {MDCListFoundation} from '@material/list/foundation'; import {MDCListIndex} from '@material/list/types'; import {MDCListAdapter} from '@material/list/adapter'; -import memoizeOne from 'memoize-one'; +import * as memoizeOne from 'memoize-one'; import ListItem, {ListItemProps} from './ListItem'; // eslint-disable-line no-unused-vars import ListItemGraphic from './ListItemGraphic'; diff --git a/test/screenshot/chips/index.tsx b/test/screenshot/chips/index.tsx index 4beda7001..438b02bd3 100644 --- a/test/screenshot/chips/index.tsx +++ b/test/screenshot/chips/index.tsx @@ -3,7 +3,7 @@ import './index.scss'; import '../../../packages/chips/index.scss'; import MaterialIcon from '../../../packages/material-icon'; import {ChipProps, Chip, ChipSet} from '../../../packages/chips/index'; // eslint-disable-line no-unused-vars -import uuidv1 from 'uuid/v1'; +import * as uuidv1 from 'uuid/v1'; interface ChipsTestProps { selectedChipIds: string[]; diff --git a/test/screenshot/screenshot.tsx b/test/screenshot/screenshot.tsx index 7407072a8..9c6d98eb0 100644 --- a/test/screenshot/screenshot.tsx +++ b/test/screenshot/screenshot.tsx @@ -7,7 +7,7 @@ import * as puppeteer from 'puppeteer'; import * as compareImages from 'resemblejs/compareImages'; import {test} from 'mocha'; import {assert} from 'chai'; -import Storage from '@google-cloud/storage'; +import * as Storage from '@google-cloud/storage'; import comparisonOptions from './screenshot-comparison-options'; import axios from 'axios'; import * as path from 'path'; diff --git a/tsconfig.json b/tsconfig.json index 59f75ef5a..7cb7824dc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,7 +9,6 @@ "target": "es5", "noUnusedLocals": true, "noUnusedParameters": true, - "esModuleInterop": true, }, "compileOnSave": true, "exclude": [ From a5fe91efc9ab4ecac5f5c765396a87255cb549ba Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Fri, 19 Apr 2019 16:51:50 -0700 Subject: [PATCH 23/31] Update index.tsx --- test/unit/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/index.tsx b/test/unit/index.tsx index c9122d458..033748dab 100644 --- a/test/unit/index.tsx +++ b/test/unit/index.tsx @@ -1,5 +1,5 @@ -import Enzyme from 'enzyme'; -import Adapter from 'enzyme-adapter-react-16'; +import * as Enzyme from 'enzyme'; +import * as Adapter from 'enzyme-adapter-react-16'; Enzyme.configure({adapter: new Adapter()}); const context = require.context('.', true, /\.test\.(j|t)sx?$/); context.keys().forEach(context); From cb75d24a9e07e1c11a4b920fb3e7a642bbfeba54 Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Mon, 22 Apr 2019 17:01:12 -0700 Subject: [PATCH 24/31] fix: esmoduleinterop --- packages/list/index.tsx | 29 +++++++++++++++-------------- test/screenshot/chips/index.tsx | 2 +- test/screenshot/screenshot.tsx | 2 +- test/unit/index.tsx | 4 ++-- tsconfig.json | 3 ++- 5 files changed, 21 insertions(+), 19 deletions(-) diff --git a/packages/list/index.tsx b/packages/list/index.tsx index 70267b54c..c9d901c69 100644 --- a/packages/list/index.tsx +++ b/packages/list/index.tsx @@ -25,7 +25,7 @@ import classnames from 'classnames'; import {MDCListFoundation} from '@material/list/foundation'; import {MDCListIndex} from '@material/list/types'; import {MDCListAdapter} from '@material/list/adapter'; -import * as memoizeOne from 'memoize-one'; +import memoizeOne from 'memoize-one'; import ListItem, {ListItemProps} from './ListItem'; // eslint-disable-line no-unused-vars import ListItemGraphic from './ListItemGraphic'; @@ -364,6 +364,19 @@ export default class List extends React.Component { this.setState({listItemClassNames}); }; + + getListProps = (checkboxList?: boolean, radioList?: boolean) => ({ + checkboxList: Boolean(checkboxList), + radioList: Boolean(radioList), + handleKeyDown: this.handleKeyDown, + handleClick: this.handleClick, + handleFocus: this.handleFocus, + handleBlur: this.handleBlur, + onDestroy: this.onDestroy, + getClassNamesFromList: this.getListItemClassNames, + getListItemInitialTabIndex: this.getListItemInitialTabIndex, + }); + render() { const { /* eslint-disable no-unused-vars */ @@ -385,21 +398,9 @@ export default class List extends React.Component { ...otherProps } = this.props; - const getListProps = (checkboxList?: boolean, radioList?: boolean) => ({ - checkboxList: Boolean(checkboxList), - radioList: Boolean(radioList), - handleKeyDown: this.handleKeyDown, - handleClick: this.handleClick, - handleFocus: this.handleFocus, - handleBlur: this.handleBlur, - onDestroy: this.onDestroy, - getClassNamesFromList: this.getListItemClassNames, - getListItemInitialTabIndex: this.getListItemInitialTabIndex, - }); - // decreases rerenders // https://overreacted.io/writing-resilient-components/#dont-stop-the-data-flow-in-rendering - const getMemoizedListProps = memoizeOne(getListProps); + const getMemoizedListProps = memoizeOne(this.getListProps); return ( // https://github.com/Microsoft/TypeScript/issues/28892 diff --git a/test/screenshot/chips/index.tsx b/test/screenshot/chips/index.tsx index 438b02bd3..4beda7001 100644 --- a/test/screenshot/chips/index.tsx +++ b/test/screenshot/chips/index.tsx @@ -3,7 +3,7 @@ import './index.scss'; import '../../../packages/chips/index.scss'; import MaterialIcon from '../../../packages/material-icon'; import {ChipProps, Chip, ChipSet} from '../../../packages/chips/index'; // eslint-disable-line no-unused-vars -import * as uuidv1 from 'uuid/v1'; +import uuidv1 from 'uuid/v1'; interface ChipsTestProps { selectedChipIds: string[]; diff --git a/test/screenshot/screenshot.tsx b/test/screenshot/screenshot.tsx index 9c6d98eb0..7407072a8 100644 --- a/test/screenshot/screenshot.tsx +++ b/test/screenshot/screenshot.tsx @@ -7,7 +7,7 @@ import * as puppeteer from 'puppeteer'; import * as compareImages from 'resemblejs/compareImages'; import {test} from 'mocha'; import {assert} from 'chai'; -import * as Storage from '@google-cloud/storage'; +import Storage from '@google-cloud/storage'; import comparisonOptions from './screenshot-comparison-options'; import axios from 'axios'; import * as path from 'path'; diff --git a/test/unit/index.tsx b/test/unit/index.tsx index 033748dab..c9122d458 100644 --- a/test/unit/index.tsx +++ b/test/unit/index.tsx @@ -1,5 +1,5 @@ -import * as Enzyme from 'enzyme'; -import * as Adapter from 'enzyme-adapter-react-16'; +import Enzyme from 'enzyme'; +import Adapter from 'enzyme-adapter-react-16'; Enzyme.configure({adapter: new Adapter()}); const context = require.context('.', true, /\.test\.(j|t)sx?$/); context.keys().forEach(context); diff --git a/tsconfig.json b/tsconfig.json index 7cb7824dc..f786f7a59 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,7 +8,8 @@ "jsx": "react", "target": "es5", "noUnusedLocals": true, - "noUnusedParameters": true, + "noUnusedParameters": true, + "esModuleInterop": true, }, "compileOnSave": true, "exclude": [ From 949fd9e1eb7976962667478bdc12ae53cc0c5396 Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Mon, 22 Apr 2019 17:09:54 -0700 Subject: [PATCH 25/31] fix: remove * as --- test/screenshot/screenshot.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/screenshot/screenshot.tsx b/test/screenshot/screenshot.tsx index 7407072a8..59a7c328a 100644 --- a/test/screenshot/screenshot.tsx +++ b/test/screenshot/screenshot.tsx @@ -2,7 +2,7 @@ import {Readable} from 'stream'; import {createHash} from 'crypto'; import {readFile, writeFile} from 'fs'; import {promisify} from 'util'; -import * as puppeteer from 'puppeteer'; +import puppeteer from 'puppeteer'; // @ts-ignore import * as compareImages from 'resemblejs/compareImages'; import {test} from 'mocha'; From e70dee4275ce9c44062c8be38913143803b457d3 Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Mon, 22 Apr 2019 18:15:37 -0700 Subject: [PATCH 26/31] fix: screenshots --- test/screenshot/screenshot.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/screenshot/screenshot.tsx b/test/screenshot/screenshot.tsx index 59a7c328a..4059a1683 100644 --- a/test/screenshot/screenshot.tsx +++ b/test/screenshot/screenshot.tsx @@ -3,15 +3,14 @@ import {createHash} from 'crypto'; import {readFile, writeFile} from 'fs'; import {promisify} from 'util'; import puppeteer from 'puppeteer'; -// @ts-ignore -import * as compareImages from 'resemblejs/compareImages'; +import compareImages from 'resemblejs/compareImages'; import {test} from 'mocha'; import {assert} from 'chai'; import Storage from '@google-cloud/storage'; import comparisonOptions from './screenshot-comparison-options'; import axios from 'axios'; -import * as path from 'path'; -import * as mkdirp from 'mkdirp'; +import path from 'path'; +import mkdirp from 'mkdirp'; const readFilePromise = promisify(readFile); const writeFilePromise = promisify(writeFile); From 3a8a01e1a02c64b00ac54522e79ece510c3d5afa Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Tue, 23 Apr 2019 10:18:40 -0700 Subject: [PATCH 27/31] fix: move memoizeone --- packages/list/index.tsx | 13 +++++++------ test/screenshot/screenshot.tsx | 1 + 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/list/index.tsx b/packages/list/index.tsx index c9d901c69..dfeec49a2 100644 --- a/packages/list/index.tsx +++ b/packages/list/index.tsx @@ -365,7 +365,7 @@ export default class List extends React.Component { }; - getListProps = (checkboxList?: boolean, radioList?: boolean) => ({ + private getListProps = (checkboxList?: boolean, radioList?: boolean) => ({ checkboxList: Boolean(checkboxList), radioList: Boolean(radioList), handleKeyDown: this.handleKeyDown, @@ -377,6 +377,11 @@ export default class List extends React.Component { getListItemInitialTabIndex: this.getListItemInitialTabIndex, }); + + // decreases rerenders + // https://overreacted.io/writing-resilient-components/#dont-stop-the-data-flow-in-rendering + getListPropsMemoized = memoizeOne(this.getListProps); + render() { const { /* eslint-disable no-unused-vars */ @@ -398,10 +403,6 @@ export default class List extends React.Component { ...otherProps } = this.props; - // decreases rerenders - // https://overreacted.io/writing-resilient-components/#dont-stop-the-data-flow-in-rendering - const getMemoizedListProps = memoizeOne(this.getListProps); - return ( // https://github.com/Microsoft/TypeScript/issues/28892 // @ts-ignore @@ -411,7 +412,7 @@ export default class List extends React.Component { role={this.role} {...otherProps} > - + {children} diff --git a/test/screenshot/screenshot.tsx b/test/screenshot/screenshot.tsx index 4059a1683..bc455df22 100644 --- a/test/screenshot/screenshot.tsx +++ b/test/screenshot/screenshot.tsx @@ -3,6 +3,7 @@ import {createHash} from 'crypto'; import {readFile, writeFile} from 'fs'; import {promisify} from 'util'; import puppeteer from 'puppeteer'; +// @ts-ignore no typings import compareImages from 'resemblejs/compareImages'; import {test} from 'mocha'; import {assert} from 'chai'; From ed4054f7305dd96cff82b9f6dfa66f57f32ebe1c Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Fri, 26 Apr 2019 10:14:58 -0700 Subject: [PATCH 28/31] fix: packagelock --- package-lock.json | 1196 +++++++++++++++++++++++++++++++++------------ 1 file changed, 877 insertions(+), 319 deletions(-) diff --git a/package-lock.json b/package-lock.json index 52419cd16..5df609cb9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1216,6 +1216,112 @@ } } }, + "@material/menu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@material/menu/-/menu-1.1.1.tgz", + "integrity": "sha512-bfsZ4Uexm02ey665SukjMK+3HtQVu7Bbc/q5chvPmLoMbSQ4PYE19C/p8cXKeNxkhd3S0h/gJDPw/cTbB9mrhg==", + "dev": true, + "requires": { + "@material/base": "^1.0.0", + "@material/feature-targeting": "^0.44.1", + "@material/list": "^1.1.1", + "@material/menu-surface": "^1.1.1", + "@material/ripple": "^1.1.0", + "@material/rtl": "^0.42.0", + "tslib": "^1.9.3" + }, + "dependencies": { + "@material/animation": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-1.0.0.tgz", + "integrity": "sha512-Ed5/vggn6ZhSJ87yn3ZS1d826VJNFz73jHF2bSsgRtHDoB8KCuOwQMfdgAgDa4lKDF6CDIPCKBZPKrs2ubehdw==", + "dev": true, + "requires": { + "tslib": "^1.9.3" + } + }, + "@material/dom": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@material/dom/-/dom-1.1.0.tgz", + "integrity": "sha512-+HWW38ZaM2UBPu4+7QCusLDSf4tFT31rsEXHkTkxYSg/QpDivfPx6YDz4OmYtafmhPR1d1YjqB3MYysUHdodyw==", + "dev": true, + "requires": { + "tslib": "^1.9.3" + } + }, + "@material/list": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@material/list/-/list-1.1.1.tgz", + "integrity": "sha512-YqX2A5qagoBolla6WHzP2BIUid/ufot5rVP2yrTz3DFvmswJMXU3HV2XU9NbiVOiefCjkra9ljtimiTlHUrAEg==", + "dev": true, + "requires": { + "@material/base": "^1.0.0", + "@material/dom": "^1.1.0", + "@material/feature-targeting": "^0.44.1", + "@material/ripple": "^1.1.0", + "@material/rtl": "^0.42.0", + "@material/shape": "^1.1.1", + "@material/theme": "^1.1.0", + "@material/typography": "^1.0.0", + "tslib": "^1.9.3" + } + }, + "@material/menu-surface": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@material/menu-surface/-/menu-surface-1.1.1.tgz", + "integrity": "sha512-bOY3LsVamovl/yb4hMBDi3gh8UFEYyP3GHNpTt+X5KBPDehoFhXG9s21aNvGbHZbwURhhWiRzy/OUC3MLE/hKA==", + "dev": true, + "requires": { + "@material/animation": "^1.0.0", + "@material/base": "^1.0.0", + "@material/elevation": "^1.1.0", + "@material/feature-targeting": "^0.44.1", + "@material/rtl": "^0.42.0", + "@material/shape": "^1.1.1", + "@material/theme": "^1.1.0", + "tslib": "^1.9.3" + } + }, + "@material/ripple": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-1.1.0.tgz", + "integrity": "sha512-mkfDBZAmxjpRG7V9TrfOmLxt1g/wvGHCXtYPgvH7W8ozjf53edqxLOFENEdvHbie27y9nyixzXn0gzU0HnxSeA==", + "dev": true, + "requires": { + "@material/animation": "^1.0.0", + "@material/base": "^1.0.0", + "@material/dom": "^1.1.0", + "@material/feature-targeting": "^0.44.1", + "@material/theme": "^1.1.0", + "tslib": "^1.9.3" + } + }, + "@material/rtl": { + "version": "0.42.0", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-0.42.0.tgz", + "integrity": "sha512-VrnrKJzhmspsN8WXHuxxBZ69yM5IwhCUqWr1t1eNfw3ZEvEj7i1g3P31HGowKThIN1dc1Wh4LE14rCISWCtv5w==", + "dev": true + }, + "@material/shape": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@material/shape/-/shape-1.1.1.tgz", + "integrity": "sha512-Jge/h1XBLjdLlam4QMSzVgM99e/N8+elQROPkltqVP7eyLc17BwM3aP5cLVfZDgrJgvsjUxbgAP1H1j8sqmUyg==", + "dev": true, + "requires": { + "@material/feature-targeting": "^0.44.1" + } + }, + "@material/theme": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-1.1.0.tgz", + "integrity": "sha512-YYUV9Rhbx4r/EMb/zoOYJUWjhXChNaLlH1rqt3vpNVyxRcxGqoVMGp5u1XALBCFiD9dACPKLIkKyRYa928nmPQ==", + "dev": true, + "requires": { + "@material/feature-targeting": "^0.44.1" + } + } + } + }, "@material/menu-surface": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@material/menu-surface/-/menu-surface-1.0.1.tgz", @@ -2419,6 +2525,55 @@ "es6-promisify": "^5.0.0" } }, + "airbnb-prop-types": { + "version": "2.13.2", + "resolved": "https://registry.npmjs.org/airbnb-prop-types/-/airbnb-prop-types-2.13.2.tgz", + "integrity": "sha512-2FN6DlHr6JCSxPPi25EnqGaXC4OC3/B3k1lCd6MMYrZ51/Gf/1qDfaR+JElzWa+Tl7cY2aYOlsYJGFeQyVHIeQ==", + "dev": true, + "requires": { + "array.prototype.find": "^2.0.4", + "function.prototype.name": "^1.1.0", + "has": "^1.0.3", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object.assign": "^4.1.0", + "object.entries": "^1.1.0", + "prop-types": "^15.7.2", + "prop-types-exact": "^1.2.0", + "react-is": "^16.8.6" + }, + "dependencies": { + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "dev": true, + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + } + } + }, "ajv": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", @@ -2906,6 +3061,12 @@ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", "dev": true }, + "array-filter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz", + "integrity": "sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=", + "dev": true + }, "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", @@ -2961,6 +3122,27 @@ "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", "dev": true }, + "array.prototype.find": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/array.prototype.find/-/array.prototype.find-2.0.4.tgz", + "integrity": "sha1-VWpcU2LAhkgyPdrrnenRS8GGTJA=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.7.0" + } + }, + "array.prototype.flat": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.1.tgz", + "integrity": "sha512-rVqIs330nLJvfC7JqYvEWwqVr5QjYF1ib02i3YJtR/fICO6527Tjpc/e4Mvmxh3GIePPreRXMdaGyC99YphWEw==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.10.0", + "function-bind": "^1.1.1" + } + }, "arraybuffer.slice": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", @@ -4778,13 +4960,13 @@ "dev": true }, "cheerio": { - "version": "1.0.0-rc.2", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.2.tgz", - "integrity": "sha1-S59TqBsn5NXawxwP/Qz6A8xoMNs=", + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.3.tgz", + "integrity": "sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA==", "dev": true, "requires": { "css-select": "~1.2.0", - "dom-serializer": "~0.1.0", + "dom-serializer": "~0.1.1", "entities": "~1.1.1", "htmlparser2": "^3.9.1", "lodash": "^4.15.0", @@ -4870,28 +5052,28 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": "", + "resolved": false, "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "resolved": "", + "resolved": false, "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true, "optional": true }, "aproba": { "version": "1.2.0", - "resolved": "", + "resolved": false, "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true, "optional": true }, "are-we-there-yet": { "version": "1.1.4", - "resolved": "", + "resolved": false, "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", "dev": true, "optional": true, @@ -4902,14 +5084,14 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true, "optional": true }, "brace-expansion": { "version": "1.1.11", - "resolved": "", + "resolved": false, "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "optional": true, @@ -4920,42 +5102,42 @@ }, "chownr": { "version": "1.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", "dev": true, "optional": true }, "code-point-at": { "version": "1.1.0", - "resolved": "", + "resolved": false, "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true, "optional": true }, "concat-map": { "version": "0.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true, "optional": true }, "console-control-strings": { "version": "1.1.0", - "resolved": "", + "resolved": false, "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "dev": true, "optional": true }, "core-util-is": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true, "optional": true }, "debug": { "version": "2.6.9", - "resolved": "", + "resolved": false, "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "optional": true, @@ -4965,28 +5147,28 @@ }, "deep-extend": { "version": "0.5.1", - "resolved": "", + "resolved": false, "integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==", "dev": true, "optional": true }, "delegates": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", - "resolved": "", + "resolved": false, "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "dev": true, "optional": true }, "fs-minipass": { "version": "1.2.5", - "resolved": "", + "resolved": false, "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", "dev": true, "optional": true, @@ -4996,14 +5178,14 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true, "optional": true }, "gauge": { "version": "2.7.4", - "resolved": "", + "resolved": false, "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, "optional": true, @@ -5020,7 +5202,7 @@ }, "glob": { "version": "7.1.2", - "resolved": "", + "resolved": false, "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "optional": true, @@ -5035,14 +5217,14 @@ }, "has-unicode": { "version": "2.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true, "optional": true }, "iconv-lite": { "version": "0.4.21", - "resolved": "", + "resolved": false, "integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==", "dev": true, "optional": true, @@ -5052,7 +5234,7 @@ }, "ignore-walk": { "version": "3.0.1", - "resolved": "", + "resolved": false, "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "dev": true, "optional": true, @@ -5062,7 +5244,7 @@ }, "inflight": { "version": "1.0.6", - "resolved": "", + "resolved": false, "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "optional": true, @@ -5073,21 +5255,21 @@ }, "inherits": { "version": "2.0.3", - "resolved": "", + "resolved": false, "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true, "optional": true }, "ini": { "version": "1.3.5", - "resolved": "", + "resolved": false, "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "optional": true, @@ -5097,14 +5279,14 @@ }, "isarray": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true, "optional": true }, "minimatch": { "version": "3.0.4", - "resolved": "", + "resolved": false, "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "optional": true, @@ -5114,14 +5296,14 @@ }, "minimist": { "version": "0.0.8", - "resolved": "", + "resolved": false, "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true, "optional": true }, "minipass": { "version": "2.2.4", - "resolved": "", + "resolved": false, "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==", "dev": true, "optional": true, @@ -5132,7 +5314,7 @@ }, "minizlib": { "version": "1.1.0", - "resolved": "", + "resolved": false, "integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==", "dev": true, "optional": true, @@ -5142,7 +5324,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "", + "resolved": false, "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "optional": true, @@ -5152,14 +5334,14 @@ }, "ms": { "version": "2.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true, "optional": true }, "needle": { "version": "2.2.0", - "resolved": "", + "resolved": false, "integrity": "sha512-eFagy6c+TYayorXw/qtAdSvaUpEbBsDwDyxYFgLZ0lTojfH7K+OdBqAF7TAFwDokJaGpubpSGG0wO3iC0XPi8w==", "dev": true, "optional": true, @@ -5171,7 +5353,7 @@ }, "node-pre-gyp": { "version": "0.10.0", - "resolved": "", + "resolved": false, "integrity": "sha512-G7kEonQLRbcA/mOoFoxvlMrw6Q6dPf92+t/l0DFSMuSlDoWaI9JWIyPwK0jyE1bph//CUEL65/Fz1m2vJbmjQQ==", "dev": true, "optional": true, @@ -5190,7 +5372,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "dev": true, "optional": true, @@ -5201,14 +5383,14 @@ }, "npm-bundled": { "version": "1.0.3", - "resolved": "", + "resolved": false, "integrity": "sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow==", "dev": true, "optional": true }, "npm-packlist": { "version": "1.1.10", - "resolved": "", + "resolved": false, "integrity": "sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA==", "dev": true, "optional": true, @@ -5219,7 +5401,7 @@ }, "npmlog": { "version": "4.1.2", - "resolved": "", + "resolved": false, "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, "optional": true, @@ -5232,21 +5414,21 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true, "optional": true }, "object-assign": { "version": "4.1.1", - "resolved": "", + "resolved": false, "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true, "optional": true }, "once": { "version": "1.4.0", - "resolved": "", + "resolved": false, "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "optional": true, @@ -5256,21 +5438,21 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true, "optional": true }, "osenv": { "version": "0.1.5", - "resolved": "", + "resolved": false, "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "dev": true, "optional": true, @@ -5281,21 +5463,21 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true, "optional": true }, "process-nextick-args": { "version": "2.0.0", - "resolved": "", + "resolved": false, "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true, "optional": true }, "rc": { "version": "1.2.7", - "resolved": "", + "resolved": false, "integrity": "sha512-LdLD8xD4zzLsAT5xyushXDNscEjB7+2ulnl8+r1pnESlYtlJtVSoCMBGr30eDRJ3+2Gq89jK9P9e4tCEH1+ywA==", "dev": true, "optional": true, @@ -5308,7 +5490,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "", + "resolved": false, "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true, "optional": true @@ -5317,7 +5499,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "", + "resolved": false, "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "optional": true, @@ -5333,7 +5515,7 @@ }, "rimraf": { "version": "2.6.2", - "resolved": "", + "resolved": false, "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "optional": true, @@ -5343,49 +5525,49 @@ }, "safe-buffer": { "version": "5.1.1", - "resolved": "", + "resolved": false, "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", "dev": true, "optional": true }, "safer-buffer": { "version": "2.1.2", - "resolved": "", + "resolved": false, "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, "optional": true }, "sax": { "version": "1.2.4", - "resolved": "", + "resolved": false, "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true, "optional": true }, "semver": { "version": "5.5.0", - "resolved": "", + "resolved": false, "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", "dev": true, "optional": true }, "set-blocking": { "version": "2.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true, "optional": true }, "string-width": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "optional": true, @@ -5397,7 +5579,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "", + "resolved": false, "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "optional": true, @@ -5407,7 +5589,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "optional": true, @@ -5417,14 +5599,14 @@ }, "strip-json-comments": { "version": "2.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true, "optional": true }, "tar": { "version": "4.4.1", - "resolved": "", + "resolved": false, "integrity": "sha512-O+v1r9yN4tOsvl90p5HAP4AEqbYhx4036AGMm075fH9F8Qwi3oJ+v4u50FkT/KkvywNGtwkk0zRI+8eYm1X/xg==", "dev": true, "optional": true, @@ -5440,14 +5622,14 @@ }, "util-deprecate": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true, "optional": true }, "wide-align": { "version": "1.1.2", - "resolved": "", + "resolved": false, "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", "dev": true, "optional": true, @@ -5457,14 +5639,14 @@ }, "wrappy": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true, "optional": true }, "yallist": { "version": "3.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", "dev": true, "optional": true @@ -6926,9 +7108,9 @@ } }, "css-what": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz", - "integrity": "sha1-lGfQMsOM+u+58teVASUwYvh/ob0=", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", + "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==", "dev": true }, "cssesc": { @@ -7346,21 +7528,13 @@ } }, "dom-serializer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", - "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", + "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", "dev": true, "requires": { - "domelementtype": "~1.1.1", - "entities": "~1.1.1" - }, - "dependencies": { - "domelementtype": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", - "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", - "dev": true - } + "domelementtype": "^1.3.0", + "entities": "^1.1.1" } }, "domain-browser": { @@ -7370,15 +7544,15 @@ "dev": true }, "domelementtype": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", - "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", "dev": true }, "domhandler": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.1.tgz", - "integrity": "sha1-iS5HAAqZvlW783dP/qBWHYh5wlk=", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", "dev": true, "requires": { "domelementtype": "1" @@ -7629,53 +7803,134 @@ "dev": true }, "enzyme": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/enzyme/-/enzyme-3.3.0.tgz", - "integrity": "sha512-l8csyPyLmtxskTz6pX9W8eDOyH1ckEtDttXk/vlFWCjv00SkjTjtoUrogqp4yEvMyneU9dUJoOLnqFoiHb8IHA==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/enzyme/-/enzyme-3.9.0.tgz", + "integrity": "sha512-JqxI2BRFHbmiP7/UFqvsjxTirWoM1HfeaJrmVSZ9a1EADKkZgdPcAuISPMpoUiHlac9J4dYt81MC5BBIrbJGMg==", "dev": true, "requires": { + "array.prototype.flat": "^1.2.1", "cheerio": "^1.0.0-rc.2", - "function.prototype.name": "^1.0.3", - "has": "^1.0.1", + "function.prototype.name": "^1.1.0", + "has": "^1.0.3", + "html-element-map": "^1.0.0", "is-boolean-object": "^1.0.0", - "is-callable": "^1.1.3", + "is-callable": "^1.1.4", "is-number-object": "^1.0.3", + "is-regex": "^1.0.4", "is-string": "^1.0.4", "is-subset": "^0.1.1", - "lodash": "^4.17.4", - "object-inspect": "^1.5.0", + "lodash.escape": "^4.0.1", + "lodash.isequal": "^4.5.0", + "object-inspect": "^1.6.0", "object-is": "^1.0.1", "object.assign": "^4.1.0", "object.entries": "^1.0.4", "object.values": "^1.0.4", "raf": "^3.4.0", - "rst-selector-parser": "^2.2.3" + "rst-selector-parser": "^2.2.3", + "string.prototype.trim": "^1.1.2" + }, + "dependencies": { + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + } } }, "enzyme-adapter-react-16": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.1.1.tgz", - "integrity": "sha512-kC8pAtU2Jk3OJ0EG8Y2813dg9Ol0TXi7UNxHzHiWs30Jo/hj7alc//G1YpKUsPP1oKl9X+Lkx+WlGJpPYA+nvw==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.12.1.tgz", + "integrity": "sha512-GB61gvY97XvrA6qljExGY+lgI6BBwz+ASLaRKct9VQ3ozu0EraqcNn3CcrUckSGIqFGa1+CxO5gj5is5t3lwrw==", "dev": true, "requires": { - "enzyme-adapter-utils": "^1.3.0", - "lodash": "^4.17.4", - "object.assign": "^4.0.4", - "object.values": "^1.0.4", - "prop-types": "^15.6.0", - "react-reconciler": "^0.7.0", - "react-test-renderer": "^16.0.0-0" + "enzyme-adapter-utils": "^1.11.0", + "object.assign": "^4.1.0", + "object.values": "^1.1.0", + "prop-types": "^15.7.2", + "react-is": "^16.8.6", + "react-test-renderer": "^16.0.0-0", + "semver": "^5.6.0" + }, + "dependencies": { + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "dev": true, + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true + } } }, "enzyme-adapter-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/enzyme-adapter-utils/-/enzyme-adapter-utils-1.3.0.tgz", - "integrity": "sha512-vVXSt6uDv230DIv+ebCG66T1Pm36Kv+m74L1TrF4kaE7e1V7Q/LcxO0QRkajk5cA6R3uu9wJf5h13wOTezTbjA==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/enzyme-adapter-utils/-/enzyme-adapter-utils-1.11.0.tgz", + "integrity": "sha512-0VZeoE9MNx+QjTfsjmO1Mo+lMfunucYB4wt5ficU85WB/LoetTJrbuujmHP3PJx6pSoaAuLA+Mq877x4LoxdNg==", "dev": true, "requires": { - "lodash": "^4.17.4", - "object.assign": "^4.0.4", - "prop-types": "^15.6.0" + "airbnb-prop-types": "^2.12.0", + "function.prototype.name": "^1.1.0", + "object.assign": "^4.1.0", + "object.fromentries": "^2.0.0", + "prop-types": "^15.7.2", + "semver": "^5.6.0" + }, + "dependencies": { + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "dev": true, + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true + } } }, "errno": { @@ -10080,6 +10335,15 @@ "integrity": "sha1-ZouTd26q5V696POtRkswekljYl4=", "dev": true }, + "html-element-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/html-element-map/-/html-element-map-1.0.1.tgz", + "integrity": "sha512-BZSfdEm6n706/lBfXKWa4frZRZcT5k1cOusw95ijZsHlI+GdgY0v95h6IzO3iIDf2ROwq570YTwqNPqHcNMozw==", + "dev": true, + "requires": { + "array-filter": "^1.0.0" + } + }, "html-entities": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", @@ -10087,17 +10351,39 @@ "dev": true }, "htmlparser2": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz", - "integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", "dev": true, "requires": { - "domelementtype": "^1.3.0", + "domelementtype": "^1.3.1", "domhandler": "^2.3.0", "domutils": "^1.5.1", "entities": "^1.1.1", "inherits": "^2.0.1", - "readable-stream": "^2.0.2" + "readable-stream": "^3.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.3.0.tgz", + "integrity": "sha512-EsI+s3k3XsW+fU8fQACLN59ky34AZ14LoeVZpYwmZvldCFo0r0gnelwF2TcMjLor/BTL5aDJVBMkss0dthToPw==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "string_decoder": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", + "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } } }, "http-deceiver": { @@ -12324,12 +12610,24 @@ "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", "dev": true }, + "lodash.escape": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-4.0.1.tgz", + "integrity": "sha1-yQRGkMIeBClL6qUXcS/e0fqI3pg=", + "dev": true + }, "lodash.flattendeep": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", "dev": true }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=", + "dev": true + }, "lodash.isstring": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", @@ -13122,6 +13420,12 @@ "integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=", "dev": true }, + "moo": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.4.3.tgz", + "integrity": "sha512-gFD2xGCl8YFgGHsqJ9NKRVdwlioeW3mI1iqfLNYQOv0+6JRwG58Zk9DIGQgyIaffSYaO1xsKnMaYzzNr1KyIAw==", + "dev": true + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -13204,15 +13508,24 @@ "dev": true }, "nearley": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.13.0.tgz", - "integrity": "sha512-ioYYogSaZhFlCpRizQgY3UT3G1qFXmHGY/5ozoFE3dMfiCRAeJfh+IPE3/eh9gCZvqLhPCWb4bLt7Bqzo+1mLQ==", + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.16.0.tgz", + "integrity": "sha512-Tr9XD3Vt/EujXbZBv6UAHYoLUSMQAxSsTnm9K3koXzjzNWY195NqALeyrzLZBKzAkL3gl92BcSogqrHjD8QuUg==", "dev": true, "requires": { - "nomnom": "~1.6.2", + "commander": "^2.19.0", + "moo": "^0.4.3", "railroad-diagrams": "^1.0.0", "randexp": "0.4.6", "semver": "^5.4.1" + }, + "dependencies": { + "commander": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", + "dev": true + } } }, "needle": { @@ -13705,30 +14018,6 @@ "dev": true, "optional": true }, - "nomnom": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.6.2.tgz", - "integrity": "sha1-hKZqJgF0QI/Ft3oY+IjszET7aXE=", - "dev": true, - "requires": { - "colors": "0.5.x", - "underscore": "~1.4.4" - }, - "dependencies": { - "colors": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/colors/-/colors-0.5.1.tgz", - "integrity": "sha1-fQAj6usVTo7p/Oddy5I9DtFmd3Q=", - "dev": true - }, - "underscore": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.4.4.tgz", - "integrity": "sha1-YaajIBBiKvoHljvzJSA88SI51gQ=", - "dev": true - } - } - }, "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", @@ -13812,9 +14101,9 @@ } }, "nth-check": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz", - "integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", "dev": true, "requires": { "boolbase": "~1.0.0" @@ -13916,9 +14205,9 @@ } }, "object-inspect": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.5.0.tgz", - "integrity": "sha512-UmOFbHbwvv+XHj7BerrhVq+knjceBdkvU5AriwLMvhv2qi+e7DJzxfBeFpILEjVzCp+xA+W/pIf06RGPWlZNfw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", + "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", "dev": true }, "object-is": { @@ -13963,15 +14252,152 @@ } }, "object.entries": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.0.4.tgz", - "integrity": "sha1-G/mk3SKI9bM/Opk9JXZh8F0WGl8=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.0.tgz", + "integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" + }, + "dependencies": { + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "es-abstract": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + } + } + }, + "object.fromentries": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.0.tgz", + "integrity": "sha512-9iLiI6H083uiqUuvzyY6qrlmc/Gz8hLQFOcb/Ri/0xXFkSNS3ctV+CbE6yM2+AnkYfOB3dGjdzC0wrMLIhQICA==", "dev": true, "requires": { "define-properties": "^1.1.2", - "es-abstract": "^1.6.1", - "function-bind": "^1.1.0", + "es-abstract": "^1.11.0", + "function-bind": "^1.1.1", "has": "^1.0.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" + }, + "dependencies": { + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + } + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + } } }, "object.omit": { @@ -14002,15 +14428,81 @@ } }, "object.values": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.0.4.tgz", - "integrity": "sha1-5STaCbT2b/Bd9FdUbscqyZ8TBpo=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", + "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.6.1", - "function-bind": "^1.1.0", - "has": "^1.0.1" + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" + }, + "dependencies": { + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "es-abstract": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + } } }, "obuf": { @@ -15344,6 +15836,28 @@ "object-assign": "^4.1.1" } }, + "prop-types-exact": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/prop-types-exact/-/prop-types-exact-1.2.0.tgz", + "integrity": "sha512-K+Tk3Kd9V0odiXFP9fwDHUYRyvK3Nun3GVyPapSIs5OBkITAm15W0CPFD/YKTkMUAbc0b9CUwRQp2ybiBIq+eA==", + "dev": true, + "requires": { + "has": "^1.0.3", + "object.assign": "^4.1.0", + "reflect.ownkeys": "^0.2.0" + }, + "dependencies": { + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + } + } + }, "proxy-addr": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.3.tgz", @@ -15558,9 +16072,9 @@ "dev": true }, "raf": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.0.tgz", - "integrity": "sha512-pDP/NMRAXoTfrhCfyfSEwJAKLaxBU9eApMeBPB1TkDouZmvPerIClV8lTAd+uF8ZiTaVl69e1FCxQrAd/VTjGw==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", "dev": true, "requires": { "performance-now": "^2.1.0" @@ -15688,17 +16202,11 @@ "prop-types": "^15.6.0" } }, - "react-reconciler": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.7.0.tgz", - "integrity": "sha512-50JwZ3yNyMS8fchN+jjWEJOH3Oze7UmhxeoJLn2j6f3NjpfCRbcmih83XTWmzqtar/ivd5f7tvQhvvhism2fgg==", - "dev": true, - "requires": { - "fbjs": "^0.8.16", - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.0" - } + "react-is": { + "version": "16.8.6", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz", + "integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==", + "dev": true }, "react-router": { "version": "4.3.1", @@ -15747,14 +16255,37 @@ } }, "react-test-renderer": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.2.0.tgz", - "integrity": "sha512-Kd4gJFtpNziR9ElOE/C23LeflKLZPRpNQYWP3nQBY43SJ5a+xyEGSeMrm2zxNKXcnCbBS/q1UpD9gqd5Dv+rew==", + "version": "16.8.6", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.8.6.tgz", + "integrity": "sha512-H2srzU5IWYT6cZXof6AhUcx/wEyJddQ8l7cLM/F7gDXYyPr4oq+vCIxJYXVGhId1J706sqziAjuOEjyNkfgoEw==", "dev": true, "requires": { - "fbjs": "^0.8.16", "object-assign": "^4.1.1", - "prop-types": "^15.6.0" + "prop-types": "^15.6.2", + "react-is": "^16.8.6", + "scheduler": "^0.13.6" + }, + "dependencies": { + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "dev": true, + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + } } }, "read-cmd-shim": { @@ -15918,6 +16449,12 @@ } } }, + "reflect.ownkeys": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/reflect.ownkeys/-/reflect.ownkeys-0.2.0.tgz", + "integrity": "sha1-dJrO7H8/34tj+SegSAnpDFwLNGA=", + "dev": true + }, "regenerate": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz", @@ -16451,6 +16988,16 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true }, + "scheduler": { + "version": "0.13.6", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.6.tgz", + "integrity": "sha512-IWnObHt413ucAYKsD9J1QShUKkbKLQQHdxRyw73sw4FN26iWr3DY/H34xGPe4nmL1DwXyWmSWmMrA9TfQbE/XQ==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, "schema-utils": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", @@ -17369,6 +17916,17 @@ "strip-ansi": "^3.0.0" } }, + "string.prototype.trim": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz", + "integrity": "sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.0", + "function-bind": "^1.0.2" + } + }, "string_decoder": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", @@ -19109,28 +19667,28 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": "", + "resolved": false, "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "resolved": "", + "resolved": false, "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true, "optional": true }, "aproba": { "version": "1.2.0", - "resolved": "", + "resolved": false, "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true, "optional": true }, "are-we-there-yet": { "version": "1.1.4", - "resolved": "", + "resolved": false, "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", "dev": true, "optional": true, @@ -19141,14 +19699,14 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true, "optional": true }, "brace-expansion": { "version": "1.1.11", - "resolved": "", + "resolved": false, "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "optional": true, @@ -19159,42 +19717,42 @@ }, "chownr": { "version": "1.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", "dev": true, "optional": true }, "code-point-at": { "version": "1.1.0", - "resolved": "", + "resolved": false, "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true, "optional": true }, "concat-map": { "version": "0.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true, "optional": true }, "console-control-strings": { "version": "1.1.0", - "resolved": "", + "resolved": false, "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "dev": true, "optional": true }, "core-util-is": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true, "optional": true }, "debug": { "version": "2.6.9", - "resolved": "", + "resolved": false, "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "optional": true, @@ -19204,28 +19762,28 @@ }, "deep-extend": { "version": "0.5.1", - "resolved": "", + "resolved": false, "integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==", "dev": true, "optional": true }, "delegates": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", - "resolved": "", + "resolved": false, "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "dev": true, "optional": true }, "fs-minipass": { "version": "1.2.5", - "resolved": "", + "resolved": false, "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", "dev": true, "optional": true, @@ -19235,14 +19793,14 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true, "optional": true }, "gauge": { "version": "2.7.4", - "resolved": "", + "resolved": false, "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, "optional": true, @@ -19259,7 +19817,7 @@ }, "glob": { "version": "7.1.2", - "resolved": "", + "resolved": false, "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "optional": true, @@ -19274,14 +19832,14 @@ }, "has-unicode": { "version": "2.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true, "optional": true }, "iconv-lite": { "version": "0.4.21", - "resolved": "", + "resolved": false, "integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==", "dev": true, "optional": true, @@ -19291,7 +19849,7 @@ }, "ignore-walk": { "version": "3.0.1", - "resolved": "", + "resolved": false, "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "dev": true, "optional": true, @@ -19301,7 +19859,7 @@ }, "inflight": { "version": "1.0.6", - "resolved": "", + "resolved": false, "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "optional": true, @@ -19312,21 +19870,21 @@ }, "inherits": { "version": "2.0.3", - "resolved": "", + "resolved": false, "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true, "optional": true }, "ini": { "version": "1.3.5", - "resolved": "", + "resolved": false, "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "optional": true, @@ -19336,14 +19894,14 @@ }, "isarray": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true, "optional": true }, "minimatch": { "version": "3.0.4", - "resolved": "", + "resolved": false, "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "optional": true, @@ -19353,14 +19911,14 @@ }, "minimist": { "version": "0.0.8", - "resolved": "", + "resolved": false, "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true, "optional": true }, "minipass": { "version": "2.2.4", - "resolved": "", + "resolved": false, "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==", "dev": true, "optional": true, @@ -19371,7 +19929,7 @@ }, "minizlib": { "version": "1.1.0", - "resolved": "", + "resolved": false, "integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==", "dev": true, "optional": true, @@ -19381,7 +19939,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "", + "resolved": false, "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "optional": true, @@ -19391,14 +19949,14 @@ }, "ms": { "version": "2.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true, "optional": true }, "needle": { "version": "2.2.0", - "resolved": "", + "resolved": false, "integrity": "sha512-eFagy6c+TYayorXw/qtAdSvaUpEbBsDwDyxYFgLZ0lTojfH7K+OdBqAF7TAFwDokJaGpubpSGG0wO3iC0XPi8w==", "dev": true, "optional": true, @@ -19410,7 +19968,7 @@ }, "node-pre-gyp": { "version": "0.10.0", - "resolved": "", + "resolved": false, "integrity": "sha512-G7kEonQLRbcA/mOoFoxvlMrw6Q6dPf92+t/l0DFSMuSlDoWaI9JWIyPwK0jyE1bph//CUEL65/Fz1m2vJbmjQQ==", "dev": true, "optional": true, @@ -19429,7 +19987,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "dev": true, "optional": true, @@ -19440,14 +19998,14 @@ }, "npm-bundled": { "version": "1.0.3", - "resolved": "", + "resolved": false, "integrity": "sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow==", "dev": true, "optional": true }, "npm-packlist": { "version": "1.1.10", - "resolved": "", + "resolved": false, "integrity": "sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA==", "dev": true, "optional": true, @@ -19458,7 +20016,7 @@ }, "npmlog": { "version": "4.1.2", - "resolved": "", + "resolved": false, "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, "optional": true, @@ -19471,21 +20029,21 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true, "optional": true }, "object-assign": { "version": "4.1.1", - "resolved": "", + "resolved": false, "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true, "optional": true }, "once": { "version": "1.4.0", - "resolved": "", + "resolved": false, "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "optional": true, @@ -19495,21 +20053,21 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true, "optional": true }, "osenv": { "version": "0.1.5", - "resolved": "", + "resolved": false, "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "dev": true, "optional": true, @@ -19520,21 +20078,21 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true, "optional": true }, "process-nextick-args": { "version": "2.0.0", - "resolved": "", + "resolved": false, "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true, "optional": true }, "rc": { "version": "1.2.7", - "resolved": "", + "resolved": false, "integrity": "sha512-LdLD8xD4zzLsAT5xyushXDNscEjB7+2ulnl8+r1pnESlYtlJtVSoCMBGr30eDRJ3+2Gq89jK9P9e4tCEH1+ywA==", "dev": true, "optional": true, @@ -19547,7 +20105,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "", + "resolved": false, "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true, "optional": true @@ -19556,7 +20114,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "", + "resolved": false, "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "optional": true, @@ -19572,7 +20130,7 @@ }, "rimraf": { "version": "2.6.2", - "resolved": "", + "resolved": false, "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "optional": true, @@ -19582,49 +20140,49 @@ }, "safe-buffer": { "version": "5.1.1", - "resolved": "", + "resolved": false, "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", "dev": true, "optional": true }, "safer-buffer": { "version": "2.1.2", - "resolved": "", + "resolved": false, "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, "optional": true }, "sax": { "version": "1.2.4", - "resolved": "", + "resolved": false, "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true, "optional": true }, "semver": { "version": "5.5.0", - "resolved": "", + "resolved": false, "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", "dev": true, "optional": true }, "set-blocking": { "version": "2.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true, "optional": true }, "string-width": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "optional": true, @@ -19636,7 +20194,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "", + "resolved": false, "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "optional": true, @@ -19646,7 +20204,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "optional": true, @@ -19656,14 +20214,14 @@ }, "strip-json-comments": { "version": "2.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true, "optional": true }, "tar": { "version": "4.4.1", - "resolved": "", + "resolved": false, "integrity": "sha512-O+v1r9yN4tOsvl90p5HAP4AEqbYhx4036AGMm075fH9F8Qwi3oJ+v4u50FkT/KkvywNGtwkk0zRI+8eYm1X/xg==", "dev": true, "optional": true, @@ -19679,14 +20237,14 @@ }, "util-deprecate": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true, "optional": true }, "wide-align": { "version": "1.1.2", - "resolved": "", + "resolved": false, "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", "dev": true, "optional": true, @@ -19696,14 +20254,14 @@ }, "wrappy": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true, "optional": true }, "yallist": { "version": "3.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", "dev": true, "optional": true @@ -20166,28 +20724,28 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": "", + "resolved": false, "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "resolved": "", + "resolved": false, "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true, "optional": true }, "aproba": { "version": "1.2.0", - "resolved": "", + "resolved": false, "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true, "optional": true }, "are-we-there-yet": { "version": "1.1.4", - "resolved": "", + "resolved": false, "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", "dev": true, "optional": true, @@ -20198,14 +20756,14 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true, "optional": true }, "brace-expansion": { "version": "1.1.11", - "resolved": "", + "resolved": false, "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "optional": true, @@ -20216,42 +20774,42 @@ }, "chownr": { "version": "1.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", "dev": true, "optional": true }, "code-point-at": { "version": "1.1.0", - "resolved": "", + "resolved": false, "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true, "optional": true }, "concat-map": { "version": "0.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true, "optional": true }, "console-control-strings": { "version": "1.1.0", - "resolved": "", + "resolved": false, "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "dev": true, "optional": true }, "core-util-is": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true, "optional": true }, "debug": { "version": "2.6.9", - "resolved": "", + "resolved": false, "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "optional": true, @@ -20261,28 +20819,28 @@ }, "deep-extend": { "version": "0.5.1", - "resolved": "", + "resolved": false, "integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==", "dev": true, "optional": true }, "delegates": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", - "resolved": "", + "resolved": false, "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "dev": true, "optional": true }, "fs-minipass": { "version": "1.2.5", - "resolved": "", + "resolved": false, "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", "dev": true, "optional": true, @@ -20292,14 +20850,14 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true, "optional": true }, "gauge": { "version": "2.7.4", - "resolved": "", + "resolved": false, "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, "optional": true, @@ -20316,7 +20874,7 @@ }, "glob": { "version": "7.1.2", - "resolved": "", + "resolved": false, "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "optional": true, @@ -20331,14 +20889,14 @@ }, "has-unicode": { "version": "2.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true, "optional": true }, "iconv-lite": { "version": "0.4.21", - "resolved": "", + "resolved": false, "integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==", "dev": true, "optional": true, @@ -20348,7 +20906,7 @@ }, "ignore-walk": { "version": "3.0.1", - "resolved": "", + "resolved": false, "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "dev": true, "optional": true, @@ -20358,7 +20916,7 @@ }, "inflight": { "version": "1.0.6", - "resolved": "", + "resolved": false, "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "optional": true, @@ -20369,21 +20927,21 @@ }, "inherits": { "version": "2.0.3", - "resolved": "", + "resolved": false, "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true, "optional": true }, "ini": { "version": "1.3.5", - "resolved": "", + "resolved": false, "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "optional": true, @@ -20393,14 +20951,14 @@ }, "isarray": { "version": "1.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true, "optional": true }, "minimatch": { "version": "3.0.4", - "resolved": "", + "resolved": false, "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "optional": true, @@ -20410,14 +20968,14 @@ }, "minimist": { "version": "0.0.8", - "resolved": "", + "resolved": false, "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true, "optional": true }, "minipass": { "version": "2.2.4", - "resolved": "", + "resolved": false, "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==", "dev": true, "optional": true, @@ -20428,7 +20986,7 @@ }, "minizlib": { "version": "1.1.0", - "resolved": "", + "resolved": false, "integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==", "dev": true, "optional": true, @@ -20438,7 +20996,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "", + "resolved": false, "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "optional": true, @@ -20448,14 +21006,14 @@ }, "ms": { "version": "2.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true, "optional": true }, "needle": { "version": "2.2.0", - "resolved": "", + "resolved": false, "integrity": "sha512-eFagy6c+TYayorXw/qtAdSvaUpEbBsDwDyxYFgLZ0lTojfH7K+OdBqAF7TAFwDokJaGpubpSGG0wO3iC0XPi8w==", "dev": true, "optional": true, @@ -20467,7 +21025,7 @@ }, "node-pre-gyp": { "version": "0.10.0", - "resolved": "", + "resolved": false, "integrity": "sha512-G7kEonQLRbcA/mOoFoxvlMrw6Q6dPf92+t/l0DFSMuSlDoWaI9JWIyPwK0jyE1bph//CUEL65/Fz1m2vJbmjQQ==", "dev": true, "optional": true, @@ -20486,7 +21044,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "dev": true, "optional": true, @@ -20497,14 +21055,14 @@ }, "npm-bundled": { "version": "1.0.3", - "resolved": "", + "resolved": false, "integrity": "sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow==", "dev": true, "optional": true }, "npm-packlist": { "version": "1.1.10", - "resolved": "", + "resolved": false, "integrity": "sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA==", "dev": true, "optional": true, @@ -20515,7 +21073,7 @@ }, "npmlog": { "version": "4.1.2", - "resolved": "", + "resolved": false, "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, "optional": true, @@ -20528,21 +21086,21 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true, "optional": true }, "object-assign": { "version": "4.1.1", - "resolved": "", + "resolved": false, "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true, "optional": true }, "once": { "version": "1.4.0", - "resolved": "", + "resolved": false, "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "optional": true, @@ -20552,21 +21110,21 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true, "optional": true }, "osenv": { "version": "0.1.5", - "resolved": "", + "resolved": false, "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "dev": true, "optional": true, @@ -20577,21 +21135,21 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true, "optional": true }, "process-nextick-args": { "version": "2.0.0", - "resolved": "", + "resolved": false, "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true, "optional": true }, "rc": { "version": "1.2.7", - "resolved": "", + "resolved": false, "integrity": "sha512-LdLD8xD4zzLsAT5xyushXDNscEjB7+2ulnl8+r1pnESlYtlJtVSoCMBGr30eDRJ3+2Gq89jK9P9e4tCEH1+ywA==", "dev": true, "optional": true, @@ -20604,7 +21162,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "", + "resolved": false, "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true, "optional": true @@ -20613,7 +21171,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "", + "resolved": false, "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "optional": true, @@ -20629,7 +21187,7 @@ }, "rimraf": { "version": "2.6.2", - "resolved": "", + "resolved": false, "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "optional": true, @@ -20639,49 +21197,49 @@ }, "safe-buffer": { "version": "5.1.1", - "resolved": "", + "resolved": false, "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", "dev": true, "optional": true }, "safer-buffer": { "version": "2.1.2", - "resolved": "", + "resolved": false, "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, "optional": true }, "sax": { "version": "1.2.4", - "resolved": "", + "resolved": false, "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true, "optional": true }, "semver": { "version": "5.5.0", - "resolved": "", + "resolved": false, "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", "dev": true, "optional": true }, "set-blocking": { "version": "2.0.0", - "resolved": "", + "resolved": false, "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true, "optional": true }, "string-width": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "optional": true, @@ -20693,7 +21251,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "", + "resolved": false, "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "optional": true, @@ -20703,7 +21261,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "optional": true, @@ -20713,14 +21271,14 @@ }, "strip-json-comments": { "version": "2.0.1", - "resolved": "", + "resolved": false, "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true, "optional": true }, "tar": { "version": "4.4.1", - "resolved": "", + "resolved": false, "integrity": "sha512-O+v1r9yN4tOsvl90p5HAP4AEqbYhx4036AGMm075fH9F8Qwi3oJ+v4u50FkT/KkvywNGtwkk0zRI+8eYm1X/xg==", "dev": true, "optional": true, @@ -20736,14 +21294,14 @@ }, "util-deprecate": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true, "optional": true }, "wide-align": { "version": "1.1.2", - "resolved": "", + "resolved": false, "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", "dev": true, "optional": true, @@ -20753,14 +21311,14 @@ }, "wrappy": { "version": "1.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true, "optional": true }, "yallist": { "version": "3.0.2", - "resolved": "", + "resolved": false, "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", "dev": true, "optional": true From d0746191a04e1a83925694adb932745e7a7f805c Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Fri, 26 Apr 2019 10:19:01 -0700 Subject: [PATCH 29/31] fix: remove menu/index.scss --- test/screenshot/menu/index.scss | 0 test/screenshot/menu/index.tsx | 1 - 2 files changed, 1 deletion(-) delete mode 100644 test/screenshot/menu/index.scss diff --git a/test/screenshot/menu/index.scss b/test/screenshot/menu/index.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/test/screenshot/menu/index.tsx b/test/screenshot/menu/index.tsx index 04cbe746b..3cf6fd58c 100644 --- a/test/screenshot/menu/index.tsx +++ b/test/screenshot/menu/index.tsx @@ -1,6 +1,5 @@ import * as React from 'react'; import '../../../packages/menu/index.scss'; -import './index.scss'; import Menu, {MenuList, MenuListItem, MenuListItemText} from '../../../packages/menu/index'; interface MenuState { From 9c50842009bf450f1b969e3803b2e750f875a845 Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Fri, 26 Apr 2019 12:08:15 -0700 Subject: [PATCH 30/31] fix: add a postinstall to fix react adapter --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 14c8d9e4d..7d5572687 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "pretest": "npm stop", "test": "npm run lint && npm run test:unit && npm run test:screenshots", "posttest": "npm stop && istanbul report --root coverage text-summary && istanbul check-coverage --lines 95 --statements 95 --branches 95 --functions 95", - "postinstall": "lerna bootstrap", + "postinstall": "lerna bootstrap && rm node_modules/**/.babelrc && rm packages/**/node_modules/.babelrc", "test:watch": "karma start karma.local.js --auto-watch", "test:unit": "npm run clean && cross-env NODE_ENV=test karma start karma.local.js --single-run", "test:unit-ci": "karma start karma.ci.js --single-run", From f93bcdf660f50ff5a4ce61e65287b25520df2d1c Mon Sep 17 00:00:00 2001 From: Matt Goo Date: Fri, 26 Apr 2019 12:26:27 -0700 Subject: [PATCH 31/31] fix: add -f so postinstall doesn't fail --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7d5572687..e5fd7650c 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "pretest": "npm stop", "test": "npm run lint && npm run test:unit && npm run test:screenshots", "posttest": "npm stop && istanbul report --root coverage text-summary && istanbul check-coverage --lines 95 --statements 95 --branches 95 --functions 95", - "postinstall": "lerna bootstrap && rm node_modules/**/.babelrc && rm packages/**/node_modules/.babelrc", + "postinstall": "lerna bootstrap && rm node_modules/**/.babelrc -f && rm packages/**/node_modules/.babelrc -f", "test:watch": "karma start karma.local.js --auto-watch", "test:unit": "npm run clean && cross-env NODE_ENV=test karma start karma.local.js --single-run", "test:unit-ci": "karma start karma.ci.js --single-run",