react-aria-modal
Advanced tools
Comparing version 3.1.0 to 4.0.0
# Changelog | ||
## 4.0.0 | ||
- Update focus-trap (via focus-trap-react), which now includes better handling for nested focus traps (including nested modals). | ||
- Fix bug causing underlay click not to exit when clicked if `scrollDisabled` is set to `false`. | ||
- Allow `escapeExits` prop to be toggled while the component is mounted (i.e. without unmounting & remounting). | ||
## 3.1.0 | ||
@@ -13,3 +19,3 @@ | ||
- Update focus-trap (via focus-trap react), which includes a couple of behavior changes. **Probably this should not change behavior for your use case.** The key change is that focus management has been adjusted so that you can include tricky focusable elements like radio groups, iframes, and shadow DOM components within your modal — as long as the first and last focusable elements in the modal can still be detected by [Tabbable](https://github.com/davidtheclark/tabbable). | ||
- Update focus-trap (via focus-trap-react), which includes a couple of behavior changes. **Probably this should not change behavior for your use case.** The key change is that focus management has been adjusted so that you can include tricky focusable elements like radio groups, iframes, and shadow DOM components within your modal — as long as the first and last focusable elements in the modal can still be detected by [Tabbable](https://github.com/davidtheclark/tabbable). | ||
- An effect of this change is that positive tabindexes within the modal *might* no longer work as expected. You should avoid positive tabindexes. | ||
@@ -16,0 +22,0 @@ |
@@ -1,51 +0,78 @@ | ||
'use strict'; | ||
"use strict"; | ||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); | ||
function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } | ||
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } | ||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } | ||
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } | ||
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } | ||
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } | ||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } | ||
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } | ||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | ||
var React = require('react'); | ||
var FocusTrap = require('focus-trap-react'); | ||
var displace = require('react-displace'); | ||
var noScroll = require('no-scroll'); | ||
var Modal = function (_React$Component) { | ||
var Modal = | ||
/*#__PURE__*/ | ||
function (_React$Component) { | ||
_inherits(Modal, _React$Component); | ||
function Modal() { | ||
var _ref; | ||
var _getPrototypeOf2; | ||
var _temp, _this, _ret; | ||
var _this; | ||
_classCallCheck(this, Modal); | ||
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = Modal.__proto__ || Object.getPrototypeOf(Modal)).call.apply(_ref, [this].concat(args))), _this), _this.getApplicationNode = function () { | ||
_this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(Modal)).call.apply(_getPrototypeOf2, [this].concat(args))); | ||
_defineProperty(_assertThisInitialized(_this), "getApplicationNode", function () { | ||
if (_this.props.getApplicationNode) return _this.props.getApplicationNode(); | ||
return _this.props.applicationNode; | ||
}, _this.checkUnderlayClick = function (event) { | ||
if (_this.dialogNode && _this.dialogNode.contains(event.target) | ||
// If the click is on the scrollbar we don't want to close the modal. | ||
|| event.pageX > event.target.clientWidth || event.pageY > event.target.clientHeight) return; | ||
}); | ||
_defineProperty(_assertThisInitialized(_this), "checkUnderlayClick", function (event) { | ||
if (_this.dialogNode && _this.dialogNode.contains(event.target) || // If the click is on the scrollbar we don't want to close the modal. | ||
event.pageX > event.target.ownerDocument.documentElement.offsetWidth || event.pageY > event.target.ownerDocument.documentElement.offsetHeight) return; | ||
_this.exit(event); | ||
}, _this.checkDocumentKeyDown = function (event) { | ||
if (event.key === 'Escape' || event.key === 'Esc' || event.keyCode === 27) { | ||
}); | ||
_defineProperty(_assertThisInitialized(_this), "checkDocumentKeyDown", function (event) { | ||
if (_this.props.escapeExits && (event.key === 'Escape' || event.key === 'Esc' || event.keyCode === 27)) { | ||
_this.exit(event); | ||
} | ||
}, _this.exit = function (event) { | ||
}); | ||
_defineProperty(_assertThisInitialized(_this), "exit", function (event) { | ||
if (_this.props.onExit) { | ||
_this.props.onExit(event); | ||
} | ||
}, _temp), _possibleConstructorReturn(_this, _ret); | ||
}); | ||
return _this; | ||
} | ||
_createClass(Modal, [{ | ||
key: 'componentWillMount', | ||
key: "componentWillMount", | ||
value: function componentWillMount() { | ||
@@ -57,10 +84,9 @@ if (!this.props.titleText && !this.props.titleId) { | ||
}, { | ||
key: 'componentDidMount', | ||
key: "componentDidMount", | ||
value: function componentDidMount() { | ||
var props = this.props; | ||
if (props.onEnter) { | ||
props.onEnter(); | ||
} | ||
if (this.props.onEnter) { | ||
this.props.onEnter(); | ||
} // Timeout to ensure this happens *after* focus has moved | ||
// Timeout to ensure this happens *after* focus has moved | ||
var applicationNode = this.getApplicationNode(); | ||
@@ -73,4 +99,4 @@ setTimeout(function () { | ||
if (props.escapeExits) { | ||
document.addEventListener('keydown', this.checkDocumentKeyDown); | ||
if (this.props.escapeExits) { | ||
this.addKeyDownListener(); | ||
} | ||
@@ -83,3 +109,3 @@ | ||
}, { | ||
key: 'componentDidUpdate', | ||
key: "componentDidUpdate", | ||
value: function componentDidUpdate(prevProps) { | ||
@@ -91,5 +117,11 @@ if (prevProps.scrollDisabled && !this.props.scrollDisabled) { | ||
} | ||
if (this.props.escapeExits && !prevProps.escapeExits) { | ||
this.addKeyDownListener(); | ||
} else if (!this.props.escapeExits && prevProps.escapeExits) { | ||
this.removeKeyDownListener(); | ||
} | ||
} | ||
}, { | ||
key: 'componentWillUnmount', | ||
key: "componentWillUnmount", | ||
value: function componentWillUnmount() { | ||
@@ -99,14 +131,35 @@ if (this.props.scrollDisabled) { | ||
} | ||
var applicationNode = this.getApplicationNode(); | ||
if (applicationNode) { | ||
applicationNode.setAttribute('aria-hidden', 'false'); | ||
} | ||
document.removeEventListener('keydown', this.checkDocumentKeyDown); | ||
this.removeKeyDownListener(); | ||
} | ||
}, { | ||
key: 'render', | ||
key: "addKeyDownListener", | ||
value: function addKeyDownListener() { | ||
var _this2 = this; | ||
setTimeout(function () { | ||
document.addEventListener('keydown', _this2.checkDocumentKeyDown); | ||
}); | ||
} | ||
}, { | ||
key: "removeKeyDownListener", | ||
value: function removeKeyDownListener() { | ||
var _this3 = this; | ||
setTimeout(function () { | ||
document.removeEventListener('keydown', _this3.checkDocumentKeyDown); | ||
}); | ||
} | ||
}, { | ||
key: "render", | ||
value: function render() { | ||
var props = this.props; | ||
var style = {}; | ||
var style = {}; | ||
if (props.includeDefaultStyles) { | ||
@@ -156,2 +209,3 @@ style = { | ||
var verticalCenterStyle = {}; | ||
if (props.includeDefaultStyles) { | ||
@@ -169,4 +223,4 @@ verticalCenterStyle = { | ||
}; | ||
var dialogStyle = {}; | ||
var dialogStyle = {}; | ||
if (props.includeDefaultStyles) { | ||
@@ -205,2 +259,3 @@ dialogStyle = { | ||
}; | ||
if (props.titleId) { | ||
@@ -211,7 +266,8 @@ dialogProps['aria-labelledby'] = props.titleId; | ||
} | ||
if (props.focusDialog) { | ||
dialogProps.tabIndex = '-1'; | ||
} | ||
} // Apply data- and aria- attributes passed as props | ||
// Apply data- and aria- attributes passed as props | ||
for (var _key3 in props) { | ||
@@ -230,7 +286,8 @@ if (/^(data-|aria-)/.test(_key3)) { | ||
var focusTrapOptions = props.focusTrapOptions || {}; | ||
if (props.focusDialog || props.initialFocus) { | ||
focusTrapOptions.initialFocus = props.focusDialog ? '#' + this.props.dialogId : props.initialFocus; | ||
focusTrapOptions.initialFocus = props.focusDialog ? "#".concat(this.props.dialogId) : props.initialFocus; | ||
} | ||
focusTrapOptions.escapeDeactivates = props.escapeExits; | ||
return React.createElement(FocusTrap, { | ||
@@ -246,3 +303,3 @@ focusTrapOptions: focusTrapOptions, | ||
Modal.defaultProps = { | ||
_defineProperty(Modal, "defaultProps", { | ||
underlayProps: {}, | ||
@@ -256,11 +313,12 @@ dialogId: 'react-aria-modal-dialog', | ||
scrollDisabled: true | ||
}; | ||
}); | ||
var DisplacedModal = displace(Modal); | ||
DisplacedModal.renderTo = function (input) { | ||
return displace(Modal, { renderTo: input }); | ||
return displace(Modal, { | ||
renderTo: input | ||
}); | ||
}; | ||
module.exports = DisplacedModal; |
{ | ||
"name": "react-aria-modal", | ||
"version": "3.1.0", | ||
"version": "4.0.0", | ||
"description": "A fully accessible and flexible React modal built according WAI-ARIA Authoring Practices", | ||
@@ -34,3 +34,3 @@ "main": "dist/react-aria-modal.js", | ||
"dependencies": { | ||
"focus-trap-react": "^4.0.0", | ||
"focus-trap-react": "^6.0.0", | ||
"no-scroll": "^2.1.1", | ||
@@ -40,27 +40,28 @@ "react-displace": "^2.3.0" | ||
"peerDependencies": { | ||
"react": "0.14.x || ^15.0.0 || ^16.0.0" | ||
"react": "^15.0.0 || ^16.0.0" | ||
}, | ||
"devDependencies": { | ||
"babel-cli": "^6.26.0", | ||
"babel-eslint": "^8.2.6", | ||
"babel-plugin-transform-class-properties": "^6.24.1", | ||
"babel-preset-env": "^1.7.0", | ||
"babel-preset-react": "^6.24.1", | ||
"babelify": "^8.0.0", | ||
"browserify": "^16.2.2", | ||
"budo": "^11.3.2", | ||
"eslint": "^5.3.0", | ||
"prettier": "1.14.1", | ||
"react": "^16.4.2", | ||
"react-dom": "^16.4.2" | ||
"@babel/cli": "^7.2.3", | ||
"@babel/core": "^7.3.3", | ||
"@babel/plugin-proposal-class-properties": "^7.3.3", | ||
"@babel/preset-env": "^7.3.1", | ||
"@babel/preset-react": "^7.0.0", | ||
"babel-eslint": "^10.0.1", | ||
"babelify": "^10.0.0", | ||
"browserify": "^16.2.3", | ||
"budo": "^11.6.0", | ||
"eslint": "^5.14.0", | ||
"prettier": "1.16.4", | ||
"react": "^16.8.2", | ||
"react-dom": "^16.8.2" | ||
}, | ||
"babel": { | ||
"presets": [ | ||
"react", | ||
"env" | ||
"@babel/preset-react", | ||
"@babel/preset-env" | ||
], | ||
"plugins": [ | ||
"transform-class-properties" | ||
"@babel/plugin-proposal-class-properties" | ||
] | ||
} | ||
} |
@@ -27,5 +27,4 @@ const React = require('react'); | ||
componentDidMount() { | ||
const props = this.props; | ||
if (props.onEnter) { | ||
props.onEnter(); | ||
if (this.props.onEnter) { | ||
this.props.onEnter(); | ||
} | ||
@@ -35,3 +34,3 @@ | ||
const applicationNode = this.getApplicationNode(); | ||
setTimeout(function() { | ||
setTimeout(() => { | ||
if (applicationNode) { | ||
@@ -42,4 +41,4 @@ applicationNode.setAttribute('aria-hidden', 'true'); | ||
if (props.escapeExits) { | ||
document.addEventListener('keydown', this.checkDocumentKeyDown); | ||
if (this.props.escapeExits) { | ||
this.addKeyDownListener(); | ||
} | ||
@@ -58,2 +57,8 @@ | ||
} | ||
if (this.props.escapeExits && !prevProps.escapeExits) { | ||
this.addKeyDownListener(); | ||
} else if (!this.props.escapeExits && prevProps.escapeExits) { | ||
this.removeKeyDownListener(); | ||
} | ||
} | ||
@@ -69,5 +74,17 @@ | ||
} | ||
document.removeEventListener('keydown', this.checkDocumentKeyDown); | ||
this.removeKeyDownListener(); | ||
} | ||
addKeyDownListener() { | ||
setTimeout(() => { | ||
document.addEventListener('keydown', this.checkDocumentKeyDown); | ||
}); | ||
} | ||
removeKeyDownListener() { | ||
setTimeout(() => { | ||
document.removeEventListener('keydown', this.checkDocumentKeyDown); | ||
}); | ||
} | ||
getApplicationNode = () => { | ||
@@ -80,7 +97,8 @@ if (this.props.getApplicationNode) return this.props.getApplicationNode(); | ||
if ( | ||
this.dialogNode && this.dialogNode.contains(event.target) | ||
(this.dialogNode && this.dialogNode.contains(event.target)) || | ||
// If the click is on the scrollbar we don't want to close the modal. | ||
|| event.pageX > event.target.clientWidth | ||
|| event.pageY > event.target.clientHeight | ||
) return; | ||
event.pageX > event.target.ownerDocument.documentElement.offsetWidth || | ||
event.pageY > event.target.ownerDocument.documentElement.offsetHeight | ||
) | ||
return; | ||
this.exit(event); | ||
@@ -90,3 +108,6 @@ }; | ||
checkDocumentKeyDown = event => { | ||
if (event.key === 'Escape' || event.key === 'Esc' || event.keyCode === 27) { | ||
if ( | ||
this.props.escapeExits && | ||
(event.key === 'Escape' || event.key === 'Esc' || event.keyCode === 27) | ||
) { | ||
this.exit(event); | ||
@@ -93,0 +114,0 @@ } |
41909
477
13
+ Addedfocus-trap@4.0.2(transitive)
+ Addedfocus-trap-react@6.0.0(transitive)
- Removedfocus-trap@3.0.0(transitive)
- Removedfocus-trap-react@4.0.1(transitive)
Updatedfocus-trap-react@^6.0.0