@shopify/app-bridge-host
Version:
App Bridge Host contains components and middleware to be consumed by the app's host, as well as the host itself. The middleware and `Frame` component are responsible for facilitating communication between the client and host, and used to act on actions se
163 lines (156 loc) • 6.39 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var tslib = require('tslib');
var React = require('react');
var compose = require('@shopify/react-compose');
var polarisInternal = require('@shopify/polaris-internal');
var appBridgeCore = require('@shopify/app-bridge-core');
var Actions = require('@shopify/app-bridge-core/actions');
var store_reducers_embeddedApp_modal_index = require('../store/reducers/embeddedApp/modal/index.js');
var withFeature = require('../withFeature.js');
var Frame = require('../Frame.js');
var useHostContext = require('../hooks/useHostContext.js');
require('@shopify/app-bridge-core/actions/Error');
var components_utilities_appUrl = require('./utilities/appUrl.js');
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
var React__default = /*#__PURE__*/_interopDefault(React);
var compose__default = /*#__PURE__*/_interopDefault(compose);
var style = {
border: 'none',
width: '100%',
flex: '1',
display: 'flex',
};
var spinnerStyle = {
position: 'absolute',
width: '100%',
height: '100%',
backgroundColor: 'white',
justifyContent: 'center',
alignItems: 'center',
display: 'flex',
};
var DEFAULT_IFRAME_CONTENT_HEIGHT = 400;
var SMALL_IFRAME_CONTENT_HEIGHT = 150;
var allowedProtocols = ['https:', 'http:'];
/**
* Renders a Polaris Modal with the Context set to `Modal`
* When the `location` is defined, renders Frame component as the modal content
* @public
* @requires HostContext
* */
function Modal(props) {
var _a = useHostContext.useHostContext(), app = _a.app, config = _a.config;
var _b = props.actions, close = _b.close, clickFooterButton = _b.clickFooterButton, _c = props.store, _d = _c.content, content = _d === void 0 ? null : _d, height = _c.height, id = _c.id, location = _c.location, open = _c.open, primaryAction = _c.primaryAction, secondaryActions = _c.secondaryActions, size = _c.size, _e = _c.title, title = _e === void 0 ? '' : _e, loading = _c.loading, extraProps = tslib.__rest(props, ["actions", "store"]);
var modalRef = React.useCallback(function (node) {
if (node) {
var modalElement = document.querySelector("[class^='Polaris-Modal-Dialog__Modal']");
if (modalElement) {
modalElement.style.overflow = 'hidden';
}
}
}, []);
var modalStyles = tslib.__assign(tslib.__assign({}, style), { height: "".concat(height || getIframeHeight(size), "px"), maxHeight: loading ? '100%' : undefined });
var url = React.useMemo(function () {
if (!location) {
// needed to handle basic case of title & content
return;
}
var apiKey = config.apiKey, handle = config.handle, url = config.url;
return components_utilities_appUrl.buildAppUrl({
handle: handle,
apiKey: apiKey,
url: url,
pathname: location,
search: takeSearch(location),
});
}, [location]);
try {
if (!allowedProtocols.includes(new URL(location || '').protocol)) {
return null;
}
}
catch (error) {
// Noop
}
// There is a bug in Polaris for the iframe height calculation
// It returns null when the modal is not opened and is never re-calculated
if (!open) {
return null;
}
var frameContent = url ? (React__default.default.createElement(Frame, tslib.__assign({}, extraProps, { config: config, style: modalStyles, context: appBridgeCore.Context.Modal, app: app, title: title, url: url.href, onUrlChange: updateIframeUrl }))) : (content);
var isSectioned = url === undefined;
var isTitleHidden = (title || '').trim() === '';
var polarisPrimaryAction = primaryAction ? createButton(primaryAction) : undefined;
var polarisSecondaryActions = modalSecondaryActions(secondaryActions);
var polarisModalSize = getPolarisModalSize(size);
function handleClose() {
close({ id: id });
}
var loadingSpinner = loading ? (React__default.default.createElement("div", { style: spinnerStyle },
React__default.default.createElement(polarisInternal.Spinner, null))) : null;
return (React__default.default.createElement(polarisInternal.Modal, { size: polarisModalSize, title: title, open: open, onClose: handleClose, primaryAction: polarisPrimaryAction, secondaryActions: polarisSecondaryActions, sectioned: isSectioned, titleHidden: isTitleHidden },
React__default.default.createElement("div", { ref: modalRef },
loadingSpinner,
frameContent)));
function createButton(button) {
var label = button.label, id = button.id, disabled = button.disabled, style = button.style, loading = button.loading;
var onAction = function () { return clickFooterButton(id); };
return {
content: label,
disabled: disabled,
destructive: style === Actions.Button.Style.Danger,
onAction: onAction,
loading: loading,
};
}
function modalSecondaryActions(actions) {
if (!Array.isArray(actions) || !actions.length) {
return;
}
return actions.map(createButton);
}
}
function getPolarisModalSize(size) {
switch (size) {
case Actions.Modal.Size.Large:
return 'large';
case Actions.Modal.Size.Small:
return 'small';
default:
return undefined;
}
}
function getIframeHeight(size) {
var isFullScreen = size === Actions.Modal.Size.Full;
if (isFullScreen) {
return;
}
if (size === Actions.Modal.Size.Small) {
return SMALL_IFRAME_CONTENT_HEIGHT;
}
return DEFAULT_IFRAME_CONTENT_HEIGHT;
}
/**
* Take the search parameters from a given URL
*/
function takeSearch(url) {
var match = url.match(/\?[^#]+/);
if (match === null) {
return undefined;
}
return match[0];
}
function updateIframeUrl(iframe, newUrl) {
if (!iframe || !iframe.contentWindow) {
return;
}
iframe.contentWindow.location.replace(newUrl);
}
/**
* The Modal feature with its reducer, actions and UI component
* @public
* */
var Modal$1 = compose__default.default(withFeature.default(store_reducers_embeddedApp_modal_index.feature))(Modal);
exports.Modal = Modal;
exports.default = Modal$1;