UNPKG

@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
'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;