@shopgate/pwa-common
Version:
Common library for the Shopgate Connect PWA.
153 lines (147 loc) • 4.21 kB
JavaScript
import _inheritsLoose from "@babel/runtime/helpers/inheritsLoose";
import React, { PureComponent, Suspense } from 'react';
import PropTypes from 'prop-types';
import { logger } from '@shopgate/pwa-core/helpers';
import Loading from "../Loading";
import portalCollection from "../../helpers/portals/portalCollection";
import { componentsConfig } from "../../helpers/config";
/**
* The Portal component.
*/
import { jsx as _jsx } from "react/jsx-runtime";
let Portal = /*#__PURE__*/function (_PureComponent) {
/**
* Constructor.
* @param {Object} props The component props.
*/
function Portal(_props) {
var _this;
_this = _PureComponent.call(this, _props) || this;
/**
* Returns the portal components.
* @param {Object} props - The props to pass to the component.
* @return {Array}
*/
_this.getRenderedComponents = props => {
const {
props: propsFromProps,
...reducedProps
} = props;
const componentProps = {
...propsFromProps,
...reducedProps
};
return _this.components.map(({
PortalComponent,
key
}) => /*#__PURE__*/_jsx(Suspense, {
fallback: /*#__PURE__*/_jsx(Loading, {}),
children: /*#__PURE__*/_jsx(PortalComponent, {
...componentProps
})
}, key));
};
/**
* Returns the portal components.
* @param {string} name Name of the portal position
* @return {Array}
*/
_this.getPortalComponents = name => {
const components = [];
const portals = portalCollection.getPortals();
if (!portals) {
return components;
}
let config = portalCollection.getConfig();
if (!config) {
config = componentsConfig.portals;
}
// Loop over the portal keys.
Object.keys(config).forEach((key, index) => {
const {
target: sourceTarget
} = config[key];
const portalTarget = Array.isArray(sourceTarget) ? sourceTarget : [sourceTarget];
if (portalTarget.length === 0) {
return;
}
portalTarget.forEach(target => {
// Stop if there is no key that matches the given name (prop).
if (target !== name) {
return;
}
const PortalComponent = portals[key];
// Check that the component is valid.
if (PortalComponent) {
const componentKey = `${key}-${index}`;
components.push({
key: componentKey,
PortalComponent
});
}
});
});
return components;
};
_this.state = {
hasError: false
};
_this.components = _this.getPortalComponents(_props.name);
return _this;
}
/**
* Catches errors.
* @param {Error} error The caught error.
* @param {Object} info The stacktrace info.
*/
_inheritsLoose(Portal, _PureComponent);
var _proto = Portal.prototype;
_proto.componentDidCatch = function componentDidCatch(error, info) {
this.setState({
hasError: true
});
logger.error(error, info);
};
/**
* Renders the component.
* @return {JSX}
*/
_proto.render = function render() {
const {
children
} = this.props;
const {
hasError
} = this.state;
const renderedComponents = this.getRenderedComponents(this.props);
const hasComponents = renderedComponents.length > 0;
/**
* Render nothing if there are no children, matching components
* via name or an error occurred.
*/
if (hasError || !(hasComponents || children)) {
return null;
}
/**
* If there is a child component then we treat the match as an override
* and we render the last match only.
*/
if (hasComponents) {
/**
* If there is a child component then we treat the match as an override
* and we render the last match only.
*/
if (children) {
return renderedComponents[renderedComponents.length - 1];
}
return renderedComponents;
}
return children;
};
return Portal;
}(PureComponent);
Portal.defaultProps = {
children: null,
props: null
};
export default Portal;