diff --git a/.babelrc b/.babelrc
index facd1809..e68d2fea 100644
--- a/.babelrc
+++ b/.babelrc
@@ -1,3 +1,3 @@
{
- "presets": ["es2015", "react"]
-}
\ No newline at end of file
+ "presets": ["es2015", "stage-2", "react"]
+}
diff --git a/examples/basic/app.js b/examples/basic/app.js
index d0988f8f..f2953dbe 100644
--- a/examples/basic/app.js
+++ b/examples/basic/app.js
@@ -1,64 +1,57 @@
-var React = require('react');
-var ReactDOM = require('react-dom');
-var Modal = require('../../lib/index');
-var createReactClass = require('create-react-class');
+import React, { Component } from 'react';
+import ReactDOM from 'react-dom';
+import Modal from '../../lib/index';
-var appElement = document.getElementById('example');
+const appElement = document.getElementById('example');
Modal.setAppElement('#example');
-var App = createReactClass({
-
- getInitialState: function() {
- return { modalIsOpen: false, modal2: false };
- },
-
- openModal: function() {
- this.setState(Object.assign({}, this.state, { modalIsOpen: true }));
- },
+class App extends Component {
+ constructor(props) {
+ super(props);
+ this.state = { modal1: false, modal2: false };
+ }
- closeModal: function() {
- this.setState(Object.assign({}, this.state, { modalIsOpen: false }));
- },
+ toggleModal_1 = () => {
+ this.setState({ ...this.state, modal1: !this.state.modal1 });
+ }
- openSecondModal: function(event) {
+ toggleModal_2 = event => {
event.preventDefault();
- this.setState(Object.assign ({}, this.state, { modal2: true }));
- },
-
- closeSecondModal: function() {
- this.setState(Object.assign ({}, this.state, { modal2: false }));
- },
+ this.setState({ ...this.state, modal2: !this.state.modal2 });
+ }
- handleModalCloseRequest: function() {
+ handleModalCloseRequest = () => {
// opportunity to validate something and keep the modal open even if it
// requested to be closed
- this.setState(Object.assign ({}, this.state, { modalIsOpen: false }));
- },
+ this.setState({ ...this.state, modal1: false });
+ }
- handleInputChange: function() {
- this.setState({ foo: 'bar' });
- },
+ handleInputChange = () => {
+ this.setState({ ...this.state, foo: 'bar' });
+ }
- handleOnAfterOpenModal: function() {
+ handleOnAfterOpenModal = () => {
// when ready, we can access the available refs.
this.refs.title.style.color = '#F00';
- },
+ }
- render: function() {
+ render() {
+ const { modal1, modal2 } = this.state;
return (
-
-
+
+
Hello
-
+
I am a modal
{}}
- onRequestClose={this.closeSecondModal}>
+ onRequestClose={this.toggleModal_2}>
test
);
}
-});
+}
ReactDOM.render(, appElement);
diff --git a/lib/components/Modal.js b/lib/components/Modal.js
index a9d017e1..33d613fd 100644
--- a/lib/components/Modal.js
+++ b/lib/components/Modal.js
@@ -1,38 +1,33 @@
-var React = require('react');
-var ReactDOM = require('react-dom');
-var DOMFactories = require('react-dom-factories');
-var PropTypes = require('prop-types');
-var ExecutionEnvironment = require('exenv');
-var ModalPortal = React.createFactory(require('./ModalPortal'));
-var ariaAppHider = require('../helpers/ariaAppHider');
-var refCount = require('../helpers/refCount');
-var elementClass = require('element-class');
-var renderSubtreeIntoContainer = require("react-dom").unstable_renderSubtreeIntoContainer;
-var Assign = require('lodash.assign');
-var createReactClass = require('create-react-class');
-
-var SafeHTMLElement = ExecutionEnvironment.canUseDOM ? window.HTMLElement : {};
-var AppElement = ExecutionEnvironment.canUseDOM ? document.body : {appendChild: function() {}};
+import React, { Component } from 'react';
+import ReactDOM from 'react-dom';
+import PropTypes from 'prop-types';
+import ExecutionEnvironment from 'exenv';
+import ModalPortal from './ModalPortal';
+import elementClass from 'element-class';
+import * as ariaAppHider from '../helpers/ariaAppHider';
+import * as refCount from '../helpers/refCount';
+
+const renderSubtreeIntoContainer = ReactDOM.unstable_renderSubtreeIntoContainer;
+
+const SafeHTMLElement = ExecutionEnvironment.canUseDOM ? window.HTMLElement : {};
+let AppElement = ExecutionEnvironment.canUseDOM ? document.body : {appendChild: function() {}};
function getParentElement(parentSelector) {
return parentSelector();
}
-var Modal = createReactClass({
+export default class Modal extends Component {
+ static setAppElement = function(element) {
+ AppElement = ariaAppHider.setElement(element);
+ };
- displayName: 'Modal',
- statics: {
- setAppElement: function(element) {
- AppElement = ariaAppHider.setElement(element);
- },
- injectCSS: function() {
- "production" !== process.env.NODE_ENV
- && console.warn('React-Modal: injectCSS has been deprecated ' +
- 'and no longer has any effect. It will be removed in a later version');
- }
- },
+ static injectCSS = function() {
+ "production" !== process.env.NODE_ENV
+ && console.warn('React-Modal: injectCSS has been deprecated ' +
+ 'and no longer has any effect. It will be removed in a later version');
+ };
- propTypes: {
+ static propTypes = {
isOpen: PropTypes.bool.isRequired,
style: PropTypes.shape({
content: PropTypes.object,
@@ -49,52 +44,75 @@ var Modal = createReactClass({
parentSelector: PropTypes.func,
role: PropTypes.string,
contentLabel: PropTypes.string.isRequired
- },
-
- getDefaultProps: function () {
- return {
- isOpen: false,
- portalClassName: 'ReactModalPortal',
- bodyOpenClassName: 'ReactModal__Body--open',
- ariaHideApp: true,
- closeTimeoutMS: 0,
- shouldCloseOnOverlayClick: true,
- parentSelector: function () { return document.body; }
- };
- },
-
- componentDidMount: function() {
+ };
+
+ static defaultProps = {
+ isOpen: false,
+ portalClassName: 'ReactModalPortal',
+ bodyOpenClassName: 'ReactModal__Body--open',
+ ariaHideApp: true,
+ closeTimeoutMS: 0,
+ shouldCloseOnOverlayClick: true,
+ parentSelector: function () { return document.body; }
+ };
+
+ static defaultStyles = {
+ overlay: {
+ position : 'fixed',
+ top : 0,
+ left : 0,
+ right : 0,
+ bottom : 0,
+ backgroundColor : 'rgba(255, 255, 255, 0.75)'
+ },
+ content: {
+ position : 'absolute',
+ top : '40px',
+ left : '40px',
+ right : '40px',
+ bottom : '40px',
+ border : '1px solid #ccc',
+ background : '#fff',
+ overflow : 'auto',
+ WebkitOverflowScrolling : 'touch',
+ borderRadius : '4px',
+ outline : 'none',
+ padding : '20px'
+ }
+ };
+
+ componentDidMount() {
this.node = document.createElement('div');
this.node.className = this.props.portalClassName;
if (this.props.isOpen) refCount.add(this);
- var parent = getParentElement(this.props.parentSelector);
+ const parent = getParentElement(this.props.parentSelector);
parent.appendChild(this.node);
this.renderPortal(this.props);
- },
+ }
- componentWillUpdate: function(newProps) {
+ componentWillUpdate(newProps) {
if(newProps.portalClassName !== this.props.portalClassName) {
this.node.className = newProps.portalClassName;
}
- },
+ }
- componentWillReceiveProps: function(newProps) {
+ componentWillReceiveProps(newProps) {
if (newProps.isOpen) refCount.add(this);
if (!newProps.isOpen) refCount.remove(this);
- var currentParent = getParentElement(this.props.parentSelector);
- var newParent = getParentElement(newProps.parentSelector);
+ const currentParent = getParentElement(this.props.parentSelector);
+ const newParent = getParentElement(newProps.parentSelector);
- if(newParent !== currentParent) {
+ if (newParent !== currentParent) {
currentParent.removeChild(this.node);
newParent.appendChild(this.node);
}
this.renderPortal(newProps);
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
if (!this.node) return;
refCount.remove(this);
@@ -103,9 +121,9 @@ var Modal = createReactClass({
ariaAppHider.show(this.props.appElement);
}
- var state = this.portal.state;
- var now = Date.now();
- var closesAt = state.isOpen && this.props.closeTimeoutMS
+ const state = this.portal.state;
+ const now = Date.now();
+ const closesAt = state.isOpen && this.props.closeTimeoutMS
&& (state.closesAt
|| now + this.props.closeTimeoutMS);
@@ -114,24 +132,24 @@ var Modal = createReactClass({
this.portal.closeWithTimeout();
}
- var that = this;
+ const that = this;
setTimeout(function() { that.removePortal(); }, closesAt - now);
} else {
this.removePortal();
}
- },
+ }
- removePortal: function() {
+ removePortal = () => {
ReactDOM.unmountComponentAtNode(this.node);
- var parent = getParentElement(this.props.parentSelector);
+ const parent = getParentElement(this.props.parentSelector);
parent.removeChild(this.node);
if (refCount.count() === 0) {
elementClass(document.body).remove(this.props.bodyOpenClassName);
}
- },
+ }
- renderPortal: function(props) {
+ renderPortal = props => {
if (props.isOpen || refCount.count() > 0) {
elementClass(document.body).add(this.props.bodyOpenClassName);
} else {
@@ -142,37 +160,12 @@ var Modal = createReactClass({
ariaAppHider.toggle(props.isOpen, props.appElement);
}
- this.portal = renderSubtreeIntoContainer(this, ModalPortal(Assign({}, props, {defaultStyles: Modal.defaultStyles})), this.node);
- },
-
- render: function () {
- return DOMFactories.noscript();
+ this.portal = renderSubtreeIntoContainer(this, (
+
+ ), this.node);
}
-});
-
-Modal.defaultStyles = {
- overlay: {
- position : 'fixed',
- top : 0,
- left : 0,
- right : 0,
- bottom : 0,
- backgroundColor : 'rgba(255, 255, 255, 0.75)'
- },
- content: {
- position : 'absolute',
- top : '40px',
- left : '40px',
- right : '40px',
- bottom : '40px',
- border : '1px solid #ccc',
- background : '#fff',
- overflow : 'auto',
- WebkitOverflowScrolling : 'touch',
- borderRadius : '4px',
- outline : 'none',
- padding : '20px'
+
+ render() {
+ return null;
}
}
-
-module.exports = Modal
diff --git a/lib/components/ModalPortal.js b/lib/components/ModalPortal.js
index ec91d852..19f2bed6 100644
--- a/lib/components/ModalPortal.js
+++ b/lib/components/ModalPortal.js
@@ -1,52 +1,48 @@
-var React = require('react');
-var DOMFactories = require('react-dom-factories');
-var focusManager = require('../helpers/focusManager');
-var scopeTab = require('../helpers/scopeTab');
-var Assign = require('lodash.assign');
-var createReactClass = require('create-react-class');
-
-var div = DOMFactories.div;
+import React, { Component } from 'react';
+import * as focusManager from '../helpers/focusManager';
+import { scopeTab } from '../helpers/scopeTab';
// so that our CSS is statically analyzable
-var CLASS_NAMES = {
+const CLASS_NAMES = {
overlay: 'ReactModal__Overlay',
content: 'ReactModal__Content'
};
-var ModalPortal = module.exports = createReactClass({
+const TAB_KEY = 9;
+const ESC_KEY = 27;
- displayName: 'ModalPortal',
- shouldClose: null,
+export default class ModalPortal extends Component {
+ static defaultProps = {
+ style: {
+ overlay: {},
+ content: {}
+ }
+ };
- getDefaultProps: function() {
- return {
- style: {
- overlay: {},
- content: {}
- }
- };
- },
+ constructor(props) {
+ super(props);
- getInitialState: function() {
- return {
+ this.state = {
afterOpen: false,
beforeClose: false
};
- },
- componentDidMount: function() {
+ this.shouldClose = null;
+ }
+
+ componentDidMount() {
// Focus needs to be set when mounting and already open
if (this.props.isOpen) {
this.setFocusAfterRender(true);
this.open();
}
- },
+ }
- componentWillUnmount: function() {
+ componentWillUnmount() {
clearTimeout(this.closeTimer);
- },
+ }
- componentWillReceiveProps: function(newProps) {
+ componentWillReceiveProps(newProps) {
// Focus only needs to be set once when the modal is being opened
if (!this.props.isOpen && newProps.isOpen) {
this.setFocusAfterRender(true);
@@ -54,150 +50,151 @@ var ModalPortal = module.exports = createReactClass({
} else if (this.props.isOpen && !newProps.isOpen) {
this.close();
}
- },
+ }
- componentDidUpdate: function () {
+ componentDidUpdate() {
if (this.focusAfterRender) {
this.focusContent();
this.setFocusAfterRender(false);
}
- },
+ }
- setFocusAfterRender: function (focus) {
+ setFocusAfterRender = focus => {
this.focusAfterRender = focus;
- },
+ }
- afterClose: function () {
+ afterClose = () => {
focusManager.returnFocus();
focusManager.teardownScopedFocus();
- },
+ }
- open: function () {
+ open = () => {
if (this.state.afterOpen && this.state.beforeClose) {
clearTimeout(this.closeTimer);
this.setState({ beforeClose: false });
} else {
focusManager.setupScopedFocus(this.node);
focusManager.markForFocusLater();
- this.setState({isOpen: true}, function() {
- this.setState({afterOpen: true});
+ this.setState({ isOpen: true }, () => {
+ this.setState({ afterOpen: true });
if (this.props.isOpen && this.props.onAfterOpen) {
this.props.onAfterOpen();
}
- }.bind(this));
+ });
}
- },
+ }
- close: function() {
- if (this.props.closeTimeoutMS > 0)
+ close = () => {
+ if (this.props.closeTimeoutMS > 0) {
this.closeWithTimeout();
- else
+ } else {
this.closeWithoutTimeout();
- },
+ }
+ }
- focusContent: function() {
+ focusContent = () => {
// Don't steal focus from inner elements
if (!this.contentHasFocus()) {
this.refs.content.focus();
}
- },
+ }
- closeWithTimeout: function() {
- var closesAt = Date.now() + this.props.closeTimeoutMS;
- this.setState({beforeClose: true, closesAt: closesAt}, function() {
+ closeWithTimeout = () => {
+ const closesAt = Date.now() + this.props.closeTimeoutMS;
+ this.setState({ beforeClose: true, closesAt: closesAt }, () => {
this.closeTimer = setTimeout(this.closeWithoutTimeout, this.state.closesAt - Date.now());
- }.bind(this));
- },
+ });
+ }
- closeWithoutTimeout: function() {
+ closeWithoutTimeout = () => {
this.setState({
beforeClose: false,
isOpen: false,
afterOpen: false,
closesAt: null
}, this.afterClose);
- },
+ }
- handleKeyDown: function(event) {
- if (event.keyCode == 9 /*tab*/) scopeTab(this.refs.content, event);
- if (event.keyCode == 27 /*esc*/) {
+ handleKeyDown = event => {
+ if (event.keyCode == TAB_KEY) {
+ scopeTab(this.refs.content, event);
+ }
+ if (event.keyCode == ESC_KEY) {
event.preventDefault();
this.requestClose(event);
}
- },
+ }
- handleOverlayOnClick: function (event) {
+ handleOverlayOnClick = event => {
if (this.shouldClose === null) {
this.shouldClose = true;
}
if (this.shouldClose && this.props.shouldCloseOnOverlayClick) {
- if (this.ownerHandlesClose())
+ if (this.ownerHandlesClose()) {
this.requestClose(event);
- else
+ } else {
this.focusContent();
+ }
}
this.shouldClose = null;
- },
+ }
- handleContentOnClick: function () {
+ handleContentOnClick = () => {
this.shouldClose = false;
- },
+ }
- requestClose: function(event) {
- if (this.ownerHandlesClose())
+ requestClose = event => {
+ if (this.ownerHandlesClose()) {
this.props.onRequestClose(event);
- },
+ }
+ }
- ownerHandlesClose: function() {
+ ownerHandlesClose = () => {
return this.props.onRequestClose;
- },
+ }
- shouldBeClosed: function() {
+ shouldBeClosed = () => {
return !this.state.isOpen && !this.state.beforeClose;
- },
+ }
- contentHasFocus: function() {
+ contentHasFocus = () => {
return document.activeElement === this.refs.content || this.refs.content.contains(document.activeElement);
- },
+ }
- buildClassName: function(which, additional) {
- var classNames = (typeof additional === 'object') ? additional : {
+ buildClassName = (which, additional) => {
+ const classNames = (typeof additional === 'object') ? additional : {
base: CLASS_NAMES[which],
afterOpen: CLASS_NAMES[which] + "--after-open",
beforeClose: CLASS_NAMES[which] + "--before-close"
};
- var className = classNames.base;
+ let className = classNames.base;
if (this.state.afterOpen) { className += " " + classNames.afterOpen; }
if (this.state.beforeClose) { className += " " + classNames.beforeClose; }
return (typeof additional === 'string' && additional) ? [className, additional].join(" ") : className;
- },
-
- render: function() {
- var contentStyles = (this.props.className) ? {} : this.props.defaultStyles.content;
- var overlayStyles = (this.props.overlayClassName) ? {} : this.props.defaultStyles.overlay;
-
- return this.shouldBeClosed() ? div() : (
- div({
- ref: "overlay",
- className: this.buildClassName('overlay', this.props.overlayClassName),
- style: Assign({}, overlayStyles, this.props.style.overlay || {}),
- onClick: this.handleOverlayOnClick
- },
- div({
- ref: "content",
- style: Assign({}, contentStyles, this.props.style.content || {}),
- className: this.buildClassName('content', this.props.className),
- tabIndex: "-1",
- onKeyDown: this.handleKeyDown,
- onClick: this.handleContentOnClick,
- role: this.props.role,
- "aria-label": this.props.contentLabel
- },
- this.props.children
- )
- )
+ }
+
+ render() {
+ const contentStyles = this.props.className ? {} : this.props.defaultStyles.content;
+ const overlayStyles = this.props.overlayClassName ? {} : this.props.defaultStyles.overlay;
+
+ return this.shouldBeClosed() ? : (
+
+
+ {this.props.children}
+
+
);
}
-});
+}
diff --git a/lib/helpers/ariaAppHider.js b/lib/helpers/ariaAppHider.js
index 05b4c128..8ade7473 100644
--- a/lib/helpers/ariaAppHider.js
+++ b/lib/helpers/ariaAppHider.js
@@ -1,42 +1,37 @@
-var _element = typeof document !== 'undefined' ? document.body : null;
+let _element = typeof document !== 'undefined' ? document.body : null;
-function setElement(element) {
+export function setElement(element) {
if (typeof element === 'string') {
- var el = document.querySelectorAll(element);
+ const el = document.querySelectorAll(element);
element = 'length' in el ? el[0] : el;
}
_element = element || _element;
return _element;
}
-function hide(appElement) {
+export function hide(appElement) {
validateElement(appElement);
(appElement || _element).setAttribute('aria-hidden', 'true');
}
-function show(appElement) {
+export function show(appElement) {
validateElement(appElement);
(appElement || _element).removeAttribute('aria-hidden');
}
-function toggle(shouldHide, appElement) {
- if (shouldHide)
- hide(appElement);
- else
- show(appElement);
+export function toggle(shouldHide, appElement) {
+ const apply = shouldHide ? hide : show;
+ apply(appElement);
}
-function validateElement(appElement) {
- if (!appElement && !_element)
+export function validateElement(appElement) {
+ if (!appElement && !_element) {
throw new Error('react-modal: You must set an element with `Modal.setAppElement(el)` to make this accessible');
+ }
}
-function resetForTesting() {
+export function resetForTesting() {
_element = document.body;
}
-exports.toggle = toggle;
-exports.setElement = setElement;
-exports.show = show;
-exports.hide = hide;
-exports.resetForTesting = resetForTesting;
+
diff --git a/lib/helpers/focusManager.js b/lib/helpers/focusManager.js
index 5d32db60..3e8a2564 100644
--- a/lib/helpers/focusManager.js
+++ b/lib/helpers/focusManager.js
@@ -1,13 +1,14 @@
-var findTabbable = require('../helpers/tabbable');
-var focusLaterElements = [];
-var modalElement = null;
-var needToFocus = false;
+import findTabbable from '../helpers/tabbable';
-function handleBlur(event) {
+let focusLaterElements = [];
+let modalElement = null;
+let needToFocus = false;
+
+export function handleBlur(event) {
needToFocus = true;
}
-function handleFocus(event) {
+export function handleFocus(event) {
if (needToFocus) {
needToFocus = false;
if (!modalElement) {
@@ -19,20 +20,21 @@ function handleFocus(event) {
// is that the document.body gets focus, and then we focus our element right
// after, seems fine.
setTimeout(function() {
- if (modalElement.contains(document.activeElement))
+ if (modalElement.contains(document.activeElement)) {
return;
- var el = (findTabbable(modalElement)[0] || modalElement);
+ }
+ const el = (findTabbable(modalElement)[0] || modalElement);
el.focus();
}, 0);
}
}
-exports.markForFocusLater = function() {
+export function markForFocusLater() {
focusLaterElements.push(document.activeElement);
-};
+}
-exports.returnFocus = function() {
- var toFocus = null;
+export function returnFocus() {
+ let toFocus = null;
try {
toFocus = focusLaterElements.pop();
toFocus.focus();
@@ -41,9 +43,9 @@ exports.returnFocus = function() {
catch (e) {
console.warn('You tried to return focus to '+toFocus+' but it is not in the DOM anymore');
}
-};
+}
-exports.setupScopedFocus = function(element) {
+export function setupScopedFocus(element) {
modalElement = element;
if (window.addEventListener) {
@@ -53,9 +55,9 @@ exports.setupScopedFocus = function(element) {
window.attachEvent('onBlur', handleBlur);
document.attachEvent('onFocus', handleFocus);
}
-};
+}
-exports.teardownScopedFocus = function() {
+export function teardownScopedFocus() {
modalElement = null;
if (window.addEventListener) {
@@ -65,4 +67,4 @@ exports.teardownScopedFocus = function() {
window.detachEvent('onBlur', handleBlur);
document.detachEvent('onFocus', handleFocus);
}
-};
+}
diff --git a/lib/helpers/refCount.js b/lib/helpers/refCount.js
index 1b8c4cc6..21df32b4 100644
--- a/lib/helpers/refCount.js
+++ b/lib/helpers/refCount.js
@@ -1,19 +1,19 @@
-var modals = [];
+let modals = [];
-module.exports = {
- add: function (element) {
- if (modals.indexOf(element) === -1) {
- modals.push(element);
- }
- },
- remove: function (element) {
- var index = modals.indexOf(element);
- if (index === -1) {
- return;
- }
- modals.splice(index, 1);
- },
- count: function () {
- return modals.length;
+export function add(element) {
+ if (modals.indexOf(element) === -1) {
+ modals.push(element);
}
-};
+}
+
+export function remove(element) {
+ const index = modals.indexOf(element);
+ if (index === -1) {
+ return;
+ }
+ modals.splice(index, 1);
+}
+
+export function count() {
+ return modals.length;
+}
diff --git a/lib/helpers/scopeTab.js b/lib/helpers/scopeTab.js
index d368bd8f..e4b21d6f 100644
--- a/lib/helpers/scopeTab.js
+++ b/lib/helpers/scopeTab.js
@@ -1,19 +1,19 @@
-var findTabbable = require('../helpers/tabbable');
+import findTabbable from './tabbable';
-module.exports = function(node, event) {
- var tabbable = findTabbable(node);
+export function scopeTab(node, event) {
+ const tabbable = findTabbable(node);
if (!tabbable.length) {
event.preventDefault();
return;
}
- var finalTabbable = tabbable[event.shiftKey ? 0 : tabbable.length - 1];
- var leavingFinalTabbable = (
+ const finalTabbable = tabbable[event.shiftKey ? 0 : tabbable.length - 1];
+ const leavingFinalTabbable = (
finalTabbable === document.activeElement ||
// handle immediate shift+tab after opening with mouse
node === document.activeElement
);
if (!leavingFinalTabbable) return;
event.preventDefault();
- var target = tabbable[event.shiftKey ? tabbable.length - 1 : 0];
+ const target = tabbable[event.shiftKey ? tabbable.length - 1 : 0];
target.focus();
-};
+}
diff --git a/lib/helpers/tabbable.js b/lib/helpers/tabbable.js
index 4b04f88b..e10d0d75 100644
--- a/lib/helpers/tabbable.js
+++ b/lib/helpers/tabbable.js
@@ -11,7 +11,7 @@
*/
function focusable(element, isTabIndexNotNaN) {
- var nodeName = element.nodeName.toLowerCase();
+ const nodeName = element.nodeName.toLowerCase();
return (/input|select|textarea|button|object/.test(nodeName) ?
!element.disabled :
"a" === nodeName ?
@@ -34,17 +34,16 @@ function visible(element) {
}
function tabbable(element) {
- var tabIndex = element.getAttribute('tabindex');
+ let tabIndex = element.getAttribute('tabindex');
if (tabIndex === null) tabIndex = undefined;
- var isTabIndexNaN = isNaN(tabIndex);
+ const isTabIndexNaN = isNaN(tabIndex);
return (isTabIndexNaN || tabIndex >= 0) && focusable(element, !isTabIndexNaN);
}
-function findTabbableDescendants(element) {
+export default function findTabbableDescendants(element) {
return [].slice.call(element.querySelectorAll('*'), 0).filter(function(el) {
return tabbable(el);
});
}
-module.exports = findTabbableDescendants;
diff --git a/package.json b/package.json
index 738ccf78..bac6098f 100644
--- a/package.json
+++ b/package.json
@@ -25,6 +25,7 @@
"babel-loader": "^6.2.4",
"babel-preset-es2015": "^6.6.0",
"babel-preset-react": "^6.5.0",
+ "babel-preset-stage-2": "^6.24.1",
"cross-env": "^5.0.1",
"envify": "^3.4.1",
"expect": "^1.20.2",
diff --git a/yarn.lock b/yarn.lock
index b9a43374..4d176502 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -211,6 +211,14 @@ babel-code-frame@^6.20.0:
esutils "^2.0.2"
js-tokens "^2.0.0"
+babel-code-frame@^6.22.0:
+ version "6.22.0"
+ resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4"
+ dependencies:
+ chalk "^1.1.0"
+ esutils "^2.0.2"
+ js-tokens "^3.0.0"
+
babel-core@^6.18.0, babel-core@^6.7.4:
version "6.21.0"
resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.21.0.tgz#75525480c21c803f826ef3867d22c19f080a3724"
@@ -247,6 +255,22 @@ babel-generator@^6.21.0:
lodash "^4.2.0"
source-map "^0.5.0"
+babel-helper-bindify-decorators@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz#14c19e5f142d7b47f19a52431e52b1ccbc40a330"
+ dependencies:
+ babel-runtime "^6.22.0"
+ babel-traverse "^6.24.1"
+ babel-types "^6.24.1"
+
+babel-helper-builder-binary-assignment-operator-visitor@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664"
+ dependencies:
+ babel-helper-explode-assignable-expression "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-types "^6.24.1"
+
babel-helper-builder-react-jsx@^6.8.0:
version "6.21.1"
resolved "https://registry.yarnpkg.com/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.21.1.tgz#c4a24208655be9dc1cccf14d366da176f20645e4"
@@ -274,6 +298,23 @@ babel-helper-define-map@^6.18.0, babel-helper-define-map@^6.8.0:
babel-types "^6.18.0"
lodash "^4.2.0"
+babel-helper-explode-assignable-expression@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa"
+ dependencies:
+ babel-runtime "^6.22.0"
+ babel-traverse "^6.24.1"
+ babel-types "^6.24.1"
+
+babel-helper-explode-class@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz#7dc2a3910dee007056e1e31d640ced3d54eaa9eb"
+ dependencies:
+ babel-helper-bindify-decorators "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-traverse "^6.24.1"
+ babel-types "^6.24.1"
+
babel-helper-function-name@^6.18.0, babel-helper-function-name@^6.8.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.18.0.tgz#68ec71aeba1f3e28b2a6f0730190b754a9bf30e6"
@@ -284,6 +325,16 @@ babel-helper-function-name@^6.18.0, babel-helper-function-name@^6.8.0:
babel-traverse "^6.18.0"
babel-types "^6.18.0"
+babel-helper-function-name@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9"
+ dependencies:
+ babel-helper-get-function-arity "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+ babel-traverse "^6.24.1"
+ babel-types "^6.24.1"
+
babel-helper-get-function-arity@^6.18.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.18.0.tgz#a5b19695fd3f9cdfc328398b47dafcd7094f9f24"
@@ -291,6 +342,13 @@ babel-helper-get-function-arity@^6.18.0:
babel-runtime "^6.0.0"
babel-types "^6.18.0"
+babel-helper-get-function-arity@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d"
+ dependencies:
+ babel-runtime "^6.22.0"
+ babel-types "^6.24.1"
+
babel-helper-hoist-variables@^6.18.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.18.0.tgz#a835b5ab8b46d6de9babefae4d98ea41e866b82a"
@@ -313,6 +371,16 @@ babel-helper-regex@^6.8.0:
babel-types "^6.18.0"
lodash "^4.2.0"
+babel-helper-remap-async-to-generator@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b"
+ dependencies:
+ babel-helper-function-name "^6.24.1"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+ babel-traverse "^6.24.1"
+ babel-types "^6.24.1"
+
babel-helper-replace-supers@^6.18.0, babel-helper-replace-supers@^6.8.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.18.0.tgz#28ec69877be4144dbd64f4cc3a337e89f29a924e"
@@ -340,6 +408,12 @@ babel-loader@^6.2.4:
mkdirp "^0.5.1"
object-assign "^4.0.1"
+babel-messages@^6.23.0:
+ version "6.23.0"
+ resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e"
+ dependencies:
+ babel-runtime "^6.22.0"
+
babel-messages@^6.8.0:
version "6.8.0"
resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.8.0.tgz#bf504736ca967e6d65ef0adb5a2a5f947c8e0eb9"
@@ -352,6 +426,30 @@ babel-plugin-check-es2015-constants@^6.3.13:
dependencies:
babel-runtime "^6.0.0"
+babel-plugin-syntax-async-functions@^6.8.0:
+ version "6.13.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95"
+
+babel-plugin-syntax-async-generators@^6.5.0:
+ version "6.13.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz#6bc963ebb16eccbae6b92b596eb7f35c342a8b9a"
+
+babel-plugin-syntax-class-properties@^6.8.0:
+ version "6.13.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de"
+
+babel-plugin-syntax-decorators@^6.13.0:
+ version "6.13.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b"
+
+babel-plugin-syntax-dynamic-import@^6.18.0:
+ version "6.18.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da"
+
+babel-plugin-syntax-exponentiation-operator@^6.8.0:
+ version "6.13.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de"
+
babel-plugin-syntax-flow@^6.18.0, babel-plugin-syntax-flow@^6.3.13:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d"
@@ -360,6 +458,49 @@ babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946"
+babel-plugin-syntax-object-rest-spread@^6.8.0:
+ version "6.13.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5"
+
+babel-plugin-syntax-trailing-function-commas@^6.22.0:
+ version "6.22.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3"
+
+babel-plugin-transform-async-generator-functions@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz#f058900145fd3e9907a6ddf28da59f215258a5db"
+ dependencies:
+ babel-helper-remap-async-to-generator "^6.24.1"
+ babel-plugin-syntax-async-generators "^6.5.0"
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-async-to-generator@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761"
+ dependencies:
+ babel-helper-remap-async-to-generator "^6.24.1"
+ babel-plugin-syntax-async-functions "^6.8.0"
+ babel-runtime "^6.22.0"
+
+babel-plugin-transform-class-properties@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac"
+ dependencies:
+ babel-helper-function-name "^6.24.1"
+ babel-plugin-syntax-class-properties "^6.8.0"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+
+babel-plugin-transform-decorators@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz#788013d8f8c6b5222bdf7b344390dfd77569e24d"
+ dependencies:
+ babel-helper-explode-class "^6.24.1"
+ babel-plugin-syntax-decorators "^6.13.0"
+ babel-runtime "^6.22.0"
+ babel-template "^6.24.1"
+ babel-types "^6.24.1"
+
babel-plugin-transform-es2015-arrow-functions@^6.3.13:
version "6.8.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.8.0.tgz#5b63afc3181bdc9a8c4d481b5a4f3f7d7fef3d9d"
@@ -529,6 +670,14 @@ babel-plugin-transform-es2015-unicode-regex@^6.3.13:
babel-runtime "^6.0.0"
regexpu-core "^2.0.0"
+babel-plugin-transform-exponentiation-operator@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e"
+ dependencies:
+ babel-helper-builder-binary-assignment-operator-visitor "^6.24.1"
+ babel-plugin-syntax-exponentiation-operator "^6.8.0"
+ babel-runtime "^6.22.0"
+
babel-plugin-transform-flow-strip-types@^6.3.13:
version "6.21.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.21.0.tgz#2eea3f8b5bb234339b47283feac155cfb237b948"
@@ -536,6 +685,13 @@ babel-plugin-transform-flow-strip-types@^6.3.13:
babel-plugin-syntax-flow "^6.18.0"
babel-runtime "^6.0.0"
+babel-plugin-transform-object-rest-spread@^6.22.0:
+ version "6.23.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.23.0.tgz#875d6bc9be761c58a2ae3feee5dc4895d8c7f921"
+ dependencies:
+ babel-plugin-syntax-object-rest-spread "^6.8.0"
+ babel-runtime "^6.22.0"
+
babel-plugin-transform-react-display-name@^6.3.13:
version "6.8.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.8.0.tgz#f7a084977383d728bdbdc2835bba0159577f660e"
@@ -618,6 +774,25 @@ babel-preset-react@^6.5.0:
babel-plugin-transform-react-jsx-self "^6.11.0"
babel-plugin-transform-react-jsx-source "^6.3.13"
+babel-preset-stage-2:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz#d9e2960fb3d71187f0e64eec62bc07767219bdc1"
+ dependencies:
+ babel-plugin-syntax-dynamic-import "^6.18.0"
+ babel-plugin-transform-class-properties "^6.24.1"
+ babel-plugin-transform-decorators "^6.24.1"
+ babel-preset-stage-3 "^6.24.1"
+
+babel-preset-stage-3@^6.24.1:
+ version "6.24.1"
+ resolved "https://registry.yarnpkg.com/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz#836ada0a9e7a7fa37cb138fb9326f87934a48395"
+ dependencies:
+ babel-plugin-syntax-trailing-function-commas "^6.22.0"
+ babel-plugin-transform-async-generator-functions "^6.24.1"
+ babel-plugin-transform-async-to-generator "^6.24.1"
+ babel-plugin-transform-exponentiation-operator "^6.24.1"
+ babel-plugin-transform-object-rest-spread "^6.22.0"
+
babel-register@^6.18.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.18.0.tgz#892e2e03865078dd90ad2c715111ec4449b32a68"
@@ -630,13 +805,20 @@ babel-register@^6.18.0:
mkdirp "^0.5.1"
source-map-support "^0.4.2"
-babel-runtime@^6.0.0, babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.20.0, babel-runtime@^6.9.0:
+babel-runtime@^6.0.0, babel-runtime@^6.11.6, babel-runtime@^6.20.0, babel-runtime@^6.9.0:
version "6.20.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.20.0.tgz#87300bdcf4cd770f09bf0048c64204e17806d16f"
dependencies:
core-js "^2.4.0"
regenerator-runtime "^0.10.0"
+babel-runtime@^6.18.0, babel-runtime@^6.22.0:
+ version "6.23.0"
+ resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b"
+ dependencies:
+ core-js "^2.4.0"
+ regenerator-runtime "^0.10.0"
+
babel-template@^6.14.0, babel-template@^6.15.0, babel-template@^6.16.0, babel-template@^6.8.0:
version "6.16.0"
resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.16.0.tgz#e149dd1a9f03a35f817ddbc4d0481988e7ebc8ca"
@@ -647,6 +829,16 @@ babel-template@^6.14.0, babel-template@^6.15.0, babel-template@^6.16.0, babel-te
babylon "^6.11.0"
lodash "^4.2.0"
+babel-template@^6.24.1:
+ version "6.25.0"
+ resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.25.0.tgz#665241166b7c2aa4c619d71e192969552b10c071"
+ dependencies:
+ babel-runtime "^6.22.0"
+ babel-traverse "^6.25.0"
+ babel-types "^6.25.0"
+ babylon "^6.17.2"
+ lodash "^4.2.0"
+
babel-traverse@^6.16.0, babel-traverse@^6.18.0, babel-traverse@^6.21.0:
version "6.21.0"
resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.21.0.tgz#69c6365804f1a4f69eb1213f85b00a818b8c21ad"
@@ -661,7 +853,21 @@ babel-traverse@^6.16.0, babel-traverse@^6.18.0, babel-traverse@^6.21.0:
invariant "^2.2.0"
lodash "^4.2.0"
-babel-types@^6.16.0, babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.21.0, babel-types@^6.8.0, babel-types@^6.9.0:
+babel-traverse@^6.24.1, babel-traverse@^6.25.0:
+ version "6.25.0"
+ resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.25.0.tgz#2257497e2fcd19b89edc13c4c91381f9512496f1"
+ dependencies:
+ babel-code-frame "^6.22.0"
+ babel-messages "^6.23.0"
+ babel-runtime "^6.22.0"
+ babel-types "^6.25.0"
+ babylon "^6.17.2"
+ debug "^2.2.0"
+ globals "^9.0.0"
+ invariant "^2.2.0"
+ lodash "^4.2.0"
+
+babel-types@^6.16.0, babel-types@^6.18.0, babel-types@^6.21.0, babel-types@^6.8.0, babel-types@^6.9.0:
version "6.21.0"
resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.21.0.tgz#314b92168891ef6d3806b7f7a917fdf87c11a4b2"
dependencies:
@@ -670,10 +876,23 @@ babel-types@^6.16.0, babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.21
lodash "^4.2.0"
to-fast-properties "^1.0.1"
+babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.25.0:
+ version "6.25.0"
+ resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.25.0.tgz#70afb248d5660e5d18f811d91c8303b54134a18e"
+ dependencies:
+ babel-runtime "^6.22.0"
+ esutils "^2.0.2"
+ lodash "^4.2.0"
+ to-fast-properties "^1.0.1"
+
babylon@^6.11.0:
version "6.14.1"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.14.1.tgz#956275fab72753ad9b3435d7afe58f8bf0a29815"
+babylon@^6.17.2:
+ version "6.17.3"
+ resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.17.3.tgz#1327d709950b558f204e5352587fd0290f8d8e48"
+
backo2@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947"
@@ -2290,6 +2509,10 @@ js-tokens@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-2.0.0.tgz#79903f5563ee778cc1162e6dcf1a0027c97f9cb5"
+js-tokens@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7"
+
jsbn@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.0.tgz#650987da0dd74f4ebf5a11377a2aa2d273e97dfd"