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

118 lines (111 loc) 5.17 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var tslib = require('tslib'); var React = require('react'); var appBridgeCore = require('@shopify/app-bridge-core'); var Actions = require('@shopify/app-bridge-core/actions'); var compose = require('@shopify/react-compose'); var Frame = require('../Frame.js'); var withFeature = require('../withFeature.js'); var store_reducers_embeddedApp_navigation_index = require('../store/reducers/embeddedApp/navigation/index.js'); require('../store/reducers/embeddedApp/appBridge/reducer.js'); var actionCreators = require('../store/reducers/embeddedApp/appBridge/actionCreators.js'); var useHostContext = require('../hooks/useHostContext.js'); var useRouterContext = require('../hooks/useRouterContext.js'); 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 = { position: 'relative', border: 'none', width: '100%', flex: '1', display: 'flex', }; /** * Renders a Frame component with the Context set to `Main` * Handles updating the iframe url for all app-related Navigation actions * @public * @requires RouterContext * @requires HostContext * */ function MainFrame(props) { var hostContext = useHostContext.useHostContext(); var routerContext = useRouterContext.useRouterContext(); var iframe = React.useRef(); var app = hostContext.app, config = hostContext.config; var location = routerContext.location; var pathname = location.pathname, search = location.search; var apiKey = config.apiKey, handle = config.handle, url = config.url; var appURLRef = React.useRef(components_utilities_appUrl.buildAppUrl({ handle: handle, apiKey: apiKey, url: url, pathname: pathname })); var actions = props.actions, onInit = props.onInit, onLocationUpdate = props.onLocationUpdate, extraProps = tslib.__rest(props, ["actions", "onInit", "onLocationUpdate"]); var appControlledRedirect = app.isTransportSubscribed(appBridgeCore.Context.Main, Actions.Redirect.Action.APP); var routeChangeRef = React.useRef(); var addRouteChangeListener = hostContext.addRouteChangeListener; React.useEffect(function () { return addRouteChangeListener(function (options) { routeChangeRef.current = options; }); }, [addRouteChangeListener]); var initHandler = React.useCallback(function (frame) { iframe.current = frame.iframe; if (onInit) { onInit(frame); } }, [onInit]); /** * Reload the iframe for apps that don't handle their own redirects * We only update the iframe url after the config change * because we need to refetch the app url from the server * */ React.useEffect(function () { if (appControlledRedirect) { return; } var iframeUrl = components_utilities_appUrl.buildAppUrl({ handle: handle, apiKey: apiKey, url: url, pathname: pathname }); app.dispatch(actionCreators.reset()); if (iframeUrl.href === appURLRef.current.href) return; updateIframeUrl(iframe.current, iframeUrl.href); }, [apiKey, handle, url]); /** * Notify the app of location changes if app is handling their own redirects. * This should not be called on the initial load. * */ var skipInitialLocation = React.useRef(true); React.useEffect(function () { if (skipInitialLocation.current) { skipInitialLocation.current = false; return; } var _a = routeChangeRef.current || {}, newUrl = _a.newUrl, _b = _a.shouldNotifyClient, shouldNotifyClient = _b === void 0 ? true : _b; var currentUrl = "".concat(pathname).concat(search); if (newUrl === currentUrl) { routeChangeRef.current = undefined; } if (!shouldNotifyClient) return; var iframeUrl = components_utilities_appUrl.buildAppUrl({ handle: handle, apiKey: apiKey, url: url, pathname: pathname }); if (appControlledRedirect) { actions.handleRedirectApp({ path: "".concat(iframeUrl.pathname).concat(search) }); } else { onLocationUpdate === null || onLocationUpdate === void 0 ? void 0 : onLocationUpdate(location); } }, [pathname, search]); return (React__default.default.createElement(Frame, tslib.__assign({}, extraProps, { config: config, style: style, context: appBridgeCore.Context.Main, app: app, title: config.name, url: appURLRef.current.href, onInit: initHandler }))); } function updateIframeUrl(iframe, newUrl) { if (!iframe || !iframe.contentWindow) { return; } iframe.contentWindow.location.replace(newUrl); } /** * The MainFrame component with the Navigation feature * @public * */ var MainFrame$1 = compose__default.default(withFeature.default(store_reducers_embeddedApp_navigation_index.feature))(MainFrame); exports.MainFrame = MainFrame; exports.default = MainFrame$1;