@salesforce/design-system-react
Version:
Salesforce Lightning Design System for React
292 lines (239 loc) • 11.4 kB
JavaScript
function _typeof(obj) { "@babel/helpers - typeof"; 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 _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
function _iterableToArrayLimit(arr, i) { var _i = arr && (typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]); if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a 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); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
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 _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
/* Copyright (c) 2015-present, salesforce.com, inc. All rights reserved */
/* Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license */
import { Component, Children } from 'react';
import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
import { PortalSettingsContext } from '../../portal-settings';
/*
* This component mounts its children within a disconnected render tree (portal).
*/
var documentDefined = typeof document !== 'undefined';
var Portal = /*#__PURE__*/function (_Component) {
_inherits(Portal, _Component);
var _super = _createSuper(Portal);
function Portal(props) {
var _this;
_classCallCheck(this, Portal);
_this = _super.call(this, props);
_this.portalNode = null;
_this.state = {
isOpen: false
};
return _this;
}
_createClass(Portal, [{
key: "componentDidMount",
value: function componentDidMount() {
this.renderPortal();
}
}, {
key: "componentDidUpdate",
value: function componentDidUpdate() {
this.renderPortal();
}
}, {
key: "componentWillUnmount",
value: function componentWillUnmount() {
this.unmountPortal();
}
}, {
key: "getChildren",
value: function getChildren() {
return Children.only(this.props.children);
}
}, {
key: "getPortalParentNode",
value: function getPortalParentNode() {
var element;
if (typeof this.props.renderTo === 'string') {
element = document.querySelector(this.props.renderTo);
} else if (this.context && typeof this.context.renderTo === 'string' && document.querySelectorAll(this.context.renderTo) && document.querySelectorAll(this.context.renderTo)[0]) {
var _document$querySelect = document.querySelectorAll(this.context.renderTo);
var _document$querySelect2 = _slicedToArray(_document$querySelect, 1);
element = _document$querySelect2[0];
} else {
element = this.props.renderTo || documentDefined && document.body;
}
return element;
}
}, {
key: "setupPortalNode",
value: function setupPortalNode() {
var parentParentNode = this.getPortalParentNode();
this.portalNode = {};
if (documentDefined) {
this.portalNode = document.createElement(this.props.renderTag);
this.portalNode.setAttribute('style', 'display: block; height: 0px; width: 0px;');
this.portalNode.setAttribute('className', 'design-system-react-portal');
parentParentNode.appendChild(this.portalNode);
this.portalNodeInstance = this.props.onMount ? this.props.onMount(undefined, {
portal: this.portalNode
}) : this.portalNode;
}
}
}, {
key: "unmountPortal",
value: function unmountPortal() {
if (this.portalNode) {
ReactDOM.unmountComponentAtNode(this.portalNode);
this.portalNode.parentNode.removeChild(this.portalNode);
}
this.portalNode = null;
}
}, {
key: "updatePortal",
value: function updatePortal() {
var _this2 = this;
if (this.props.id) {
this.portalNode.id = this.props.id;
}
if (this.props.className) {
this.portalNode.className = this.props.className;
}
if (this.props.style) {
Object.keys(this.props.style).forEach(function (key) {
_this2.portalNode.style[key] = _this2.props.style[key];
});
}
if (this.props.onUpdate) {
this.portalNodeInstance = this.props.onUpdate(this.portalNodeInstance);
}
}
}, {
key: "renderPortal",
value: function renderPortal() {
var _this3 = this;
// if no portal contents, then unmount
if (!this.getChildren() || !documentDefined) {
this.unmountPortal();
return;
}
if (!this.portalNode) {
this.setupPortalNode();
}
if (this.props.portalMount) {
this.props.portalMount({
instance: this,
reactElement: this.getChildren(),
domContainerNode: this.portalNode,
updateCallback: function updateCallback() {
_this3.updatePortal(); // update after subtree renders
}
});
} else {
// actual render
ReactDOM.unstable_renderSubtreeIntoContainer(this, this.getChildren(), this.portalNode, function () {
_this3.updatePortal(); // update after subtree renders
if (_this3.state.isOpen === false) {
if (_this3.props.onOpen) {
_this3.props.onOpen(undefined, {
portal: _this3.getChildren()
});
}
_this3.setState({
isOpen: true
});
}
});
}
}
}, {
key: "render",
value: function render() {
return null;
}
}]);
return Portal;
}(Component);
Portal.displayName = 'Portal';
Portal.propTypes = {
/*
* What tag to use for the portal, defaults to `div`.
*/
renderTag: PropTypes.string,
/*
* What node the portal is rendered to, defaults to `document.body`.
*/
renderTo: PropTypes.any,
/*
* React id prop.
*/
id: PropTypes.string,
/*
* Accepts a _single_ element or component.
*/
children: PropTypes.node,
/*
* ClassName added to .
*/
className: PropTypes.any,
/*
* An object of styles that are applied to the portal.
*/
style: PropTypes.object,
/*
* Triggers when Portal render tree mounts. Pass in an undefined event and `{ portal: [node] }``
*/
onMount: PropTypes.func,
/*
* Triggers when the portal is mounted.
*/
onOpen: PropTypes.func,
/*
* Triggers when Portal re-renders its tree.
*/
onUpdate: PropTypes.func,
/**
* If a dialog is `positione="overflowBoundaryElement"`, it will be rendered in a portal or separate render tree. This `portalMount` callback will be triggered instead of the the default `ReactDOM.unstable_renderSubtreeIntoContainer` and the function will mount the portal itself. Consider the following code that bypasses the internal mount and uses an Enzyme wrapper to mount the React root tree to the DOM.
*
* ```
* <Popover
* isOpen
* portalMount={({ instance, reactElement, domContainerNode }) => {
* portalWrapper = Enzyme.mount(reactElement, { attachTo: domContainerNode });
* }}
* onOpen={() => {
* expect(portalWrapper.find(`#my-heading`)).to.exist;
* done();
* }}
* />
* ```
*/
portalMount: PropTypes.func
};
Portal.defaultProps = {
renderTag: 'span',
renderTo: null,
onMount: function onMount() {
return null;
},
onOpen: function onOpen() {
return null;
},
onUpdate: function onUpdate() {
return null;
},
onUnmount: function onUnmount() {
return null;
}
};
Portal.contextType = PortalSettingsContext;
export default Portal;
//# sourceMappingURL=portal.js.map