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

108 lines (105 loc) 4.54 kB
import { __rest, __assign } from 'tslib'; import React, { useRef, useEffect, useCallback } from 'react'; import { Context } from '@shopify/app-bridge-core'; import { Redirect } from '@shopify/app-bridge-core/actions'; import compose from '@shopify/react-compose'; import Frame from '../Frame.js'; import withFeature from '../withFeature.js'; import { feature } from '../store/reducers/embeddedApp/navigation/index.js'; import '../store/reducers/embeddedApp/appBridge/reducer.js'; import { reset } from '../store/reducers/embeddedApp/appBridge/actionCreators.js'; import { useHostContext } from '../hooks/useHostContext.js'; import { useRouterContext } from '../hooks/useRouterContext.js'; import { buildAppUrl } from './utilities/appUrl.js'; 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(); var routerContext = useRouterContext(); var iframe = 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 = useRef(buildAppUrl({ handle: handle, apiKey: apiKey, url: url, pathname: pathname })); var actions = props.actions, onInit = props.onInit, onLocationUpdate = props.onLocationUpdate, extraProps = __rest(props, ["actions", "onInit", "onLocationUpdate"]); var appControlledRedirect = app.isTransportSubscribed(Context.Main, Redirect.Action.APP); var routeChangeRef = useRef(); var addRouteChangeListener = hostContext.addRouteChangeListener; useEffect(function () { return addRouteChangeListener(function (options) { routeChangeRef.current = options; }); }, [addRouteChangeListener]); var initHandler = 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 * */ useEffect(function () { if (appControlledRedirect) { return; } var iframeUrl = buildAppUrl({ handle: handle, apiKey: apiKey, url: url, pathname: pathname }); app.dispatch(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 = useRef(true); 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 = 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.createElement(Frame, __assign({}, extraProps, { config: config, style: style, context: 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(withFeature(feature))(MainFrame); export { MainFrame, MainFrame$1 as default };