cpui-components
Version:
344 lines (284 loc) • 13.3 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Modal = undefined;
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
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; }; }();
var _react = require("react");
var _react2 = _interopRequireDefault(_react);
var _propTypes = require("prop-types");
var _propTypes2 = _interopRequireDefault(_propTypes);
var _classnames = require("classnames");
var _classnames2 = _interopRequireDefault(_classnames);
var _blacklist = require("blacklist");
var _blacklist2 = _interopRequireDefault(_blacklist);
var _reactDom = require("react-dom");
var _reactDom2 = _interopRequireDefault(_reactDom);
var _Transition = require("react-transition-group/Transition");
var _Transition2 = _interopRequireDefault(_Transition);
var _constants = require("./../../constants");
var _ModalBody = require("./../ModalBody");
var _ModalBody2 = _interopRequireDefault(_ModalBody);
var _ModalFooter = require("./../ModalFooter");
var _ModalFooter2 = _interopRequireDefault(_ModalFooter);
var _ModalHeader = require("./../ModalHeader");
var _ModalHeader2 = _interopRequireDefault(_ModalHeader);
var _ally = require("ally.js");
var _ally2 = _interopRequireDefault(_ally);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: 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 _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; }
var TransitionPortal = function (_Component) {
_inherits(TransitionPortal, _Component);
function TransitionPortal() {
var _ref;
var _temp, _this, _ret;
_classCallCheck(this, TransitionPortal);
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = TransitionPortal.__proto__ || Object.getPrototypeOf(TransitionPortal)).call.apply(_ref, [this].concat(args))), _this), _this.componentDidMount = function () {
if (!_constants.canUseDOM) {
return;
}
var p = document.createElement("div");
if (_this.props.className != null) {
p.className = _this.props.className;
}
document.body.appendChild(p);
_this.portalElement = p;
_this.componentDidUpdate();
}, _this.componentDidUpdate = function () {
if (!_constants.canUseDOM) {
return;
}
if (_this.props.className != null) {
_this.portalElement.className = _this.props.className;
}
_reactDom2.default.render(_react2.default.createElement(
_Transition2.default,
_this.props,
_this.props.children
), _this.portalElement);
}, _this.componentWillUnmount = function () {
if (!_constants.canUseDOM) {
return;
}
document.body.removeChild(_this.portalElement);
}, _this.portalElement = null, _this.render = function () {
return null;
}, _temp), _possibleConstructorReturn(_this, _ret);
}
return TransitionPortal;
}(_react.Component);
var Modal = exports.Modal = function (_Component2) {
_inherits(Modal, _Component2);
function Modal() {
var _ref2;
var _temp2, _this2, _ret2;
_classCallCheck(this, Modal);
for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
return _ret2 = (_temp2 = (_this2 = _possibleConstructorReturn(this, (_ref2 = Modal.__proto__ || Object.getPrototypeOf(Modal)).call.apply(_ref2, [this].concat(args))), _this2), _this2.componentWillReceiveProps = function (nextProps) {
if (!_constants.canUseDOM) {
return;
}
var target = document.body;
var scrollbarWidth = window.innerWidth - document.body.clientWidth; // 1.
if (!_this2.props.in && nextProps.in) {
setTimeout(function () {
return _this2.handleAccessibility();
});
target.style.overflow = "hidden";
target.style.paddingRight = scrollbarWidth + "px";
} else if (_this2.props.in && !nextProps.in) {
setTimeout(function () {
return _this2.removeAccessibilityHandlers();
});
target.style.overflow = "";
target.style.paddingRight = "";
}
}, _this2.handleClose = function () {
var _this2$props = _this2.props,
backdropClosesModal = _this2$props.backdropClosesModal,
onCancel = _this2$props.onCancel;
if (backdropClosesModal) {
onCancel();
}
}, _this2.handleDialogClick = function (event) {
event.stopPropagation();
}, _this2.renderDialog = function (transitionState) {
var _this2$props2 = _this2.props,
children = _this2$props2.children,
width = _this2$props2.width,
transitionTimeout = _this2$props2.transitionTimeout;
var thisStateTimeout = transitionTimeout;
if ((typeof transitionTimeout === "undefined" ? "undefined" : _typeof(transitionTimeout)) === "object" && transitionTimeout !== null) {
//transitionTimeout is object
switch (transitionState) {
case "entering":
case "entered":
if (transitionTimeout.enter != null) {
thisStateTimeout = transitionTimeout.enter;
}
break;
case "exiting":
case "exited":
if (transitionTimeout.exit != null) {
thisStateTimeout = transitionTimeout.exit;
}
break;
default:
break;
}
}
var defaultStyle = {
transition: "opacity " + thisStateTimeout + "ms ease-in-out",
opacity: 0
};
var transitionStyles = {
entering: { opacity: 1 },
entered: { opacity: 1 }
};
var style = width && !isNaN(width) ? { width: width + 20 } : null;
var dialogClassname = (0, _classnames2.default)("cp-PopOver", "cp-PopOver--modal", "Modal-fade-" + transitionState, width && isNaN(width) ? "cp-PopOver--" + width : null);
return _react2.default.createElement(
"div",
{
className: dialogClassname,
style: _extends({}, defaultStyle, transitionStyles[transitionState], { style: style }),
onClick: _this2.handleDialogClick,
ref: function ref(element) {
_this2.modalElement = element;
}
},
_react2.default.createElement(
"div",
{ className: "Modal-content" },
children
)
);
}, _this2.renderBackdrop = function () {
var isOpen = _this2.props.in;
if (!isOpen) {
return null;
}
return _react2.default.createElement("div", { className: "cp-PopOver-backdrop" });
}, _this2.render = function () {
// cp-AdminWrap class may cause some issues if this component is ever used outside the admin context within CivicEngage.
var className = (0, _classnames2.default)("cp-PopOverWrapper", "cp-AdminWrap", {
"is-open": _this2.props.in
}, _this2.props.className);
var props = (0, _blacklist2.default)(_this2.props, "backdropClosesModal", "className", "onCancel", "transitionTimeout");
return _react2.default.createElement(
"div",
null,
_react2.default.createElement(
TransitionPortal,
_extends({}, props, {
className: className,
"data-modal": "true",
onClick: _this2.handleClose,
timeout: _this2.props.transitionTimeout
}),
function (state) {
return _this2.renderDialog(state);
}
),
_react2.default.createElement(
TransitionPortal,
{ timeout: _this2.props.transitionTimeout },
function (state) {
return _this2.renderBackdrop(state);
}
)
);
}, _temp2), _possibleConstructorReturn(_this2, _ret2);
}
_createClass(Modal, [{
key: "handleAccessibility",
value: function handleAccessibility() {
// Remember the element that was focused before we opened the modal
// so we can return focus to it once we close the modal.
this.focusedElementBeforeModalOpened = document.activeElement;
// We're using a transition to reveal the modal,
// so wait until the element is visible, before
// finding the first keyboard focusable element
// and passing focus to it, otherwise the browser
// might scroll the document to reveal the element
// receiving focus
if (this.props.autoFocusFirstElement) {
_ally2.default.when.visibleArea({
context: this.modalElement,
callback: function callback(context) {
// the modal is visible on screen, so find the first
// keyboard focusable element (giving any element with
// autoFocus attribute precendence). If the modal does
// not contain any keyboard focusabe elements, focus will
// be given to the modal itself.
var element = _ally2.default.query.firstTabbable({
context: context,
defaultToContext: true
});
element.focus();
}
});
}
// Make sure that no element outside of the modal
// can be interacted with while the modal is visible.
this.disabledHandle = _ally2.default.maintain.disabled({
filter: this.modalElement
});
// Make sure that no element outside of the modal
// is exposed via the Accessibility Tree, to prevent
// screen readers from navigating to content it shouldn't
// be seeing while the modal is open.
this.hiddenHandle = _ally2.default.maintain.hidden({
filter: this.modalElement
});
// React to escape keys as mandated by ARIA Practices
this.keyHandle = _ally2.default.when.key({
escape: this.handleClose
});
}
}, {
key: "removeAccessibilityHandlers",
value: function removeAccessibilityHandlers() {
// undo listening to keyboard
this.keyHandle && this.keyHandle.disengage();
// undo hiding elements outside of the modal
this.hiddenHandle && this.hiddenHandle.disengage();
// undo disabling elements outside of the modal
this.disabledHandle && this.disabledHandle.disengage();
// return focus to where it was before we opened the modal
this.focusedElementBeforeModalOpened && this.focusedElementBeforeModalOpened.focus();
}
}, {
key: "handleModalClick",
value: function handleModalClick(event) {
if (event.target.dataset.modal) this.handleClose();
}
}]);
return Modal;
}(_react.Component);
Modal.propTypes = {
autoFocusFirstElement: _propTypes2.default.bool,
backdropClosesModal: _propTypes2.default.bool,
className: _propTypes2.default.string,
in: _propTypes2.default.bool,
onCancel: _propTypes2.default.func,
width: _propTypes2.default.oneOfType([_propTypes2.default.oneOf(["small", "medium", "large"]), _propTypes2.default.number]),
transitionTimeout: _propTypes2.default.oneOfType([_propTypes2.default.shape({ enter: _propTypes2.default.number, exit: _propTypes2.default.number }), _propTypes2.default.number])
};
Modal.defaultProps = {
width: "medium",
transitionTimeout: 333
};
Modal.Body = _ModalBody2.default;
Modal.Footer = _ModalFooter2.default;
Modal.Header = _ModalHeader2.default;
exports.default = Modal;
;