@shopify/app-bridge-react 2.0.23 → 2.0.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,52 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [2.0.26](https://github.com/Shopify/app-bridge/compare/v2.0.25...v2.0.26) (2022-04-28)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * **app-bridge:** creating a title bar with empty options should not dispatch an update action ([c31f135](https://github.com/Shopify/app-bridge/commit/c31f135ffb78b3c69278cef0ce0674eb55aa7837))
12
+ * **app-bridge-react:** ensure Modal component only dispatch UPDATE action when necessary ([3f6bd1a](https://github.com/Shopify/app-bridge/commit/3f6bd1ae4c7475b2cccad646e0e4b5c17f681693))
13
+ * **app-bridge-react:** stop sending unnecessary updates when Navigation Menu props have not changed ([5d57495](https://github.com/Shopify/app-bridge/commit/5d57495bda42b37913f1c582159f04aab97d478a))
14
+ * **app-bridge-react:** update redirect callbacks for title bar when onAction changes ([68cd7ac](https://github.com/Shopify/app-bridge/commit/68cd7ace44b3cf92c4adb76e3d975e7a63b61b59))
15
+ * **app-bridge-react:** update title bar callbacks when they change ([617f900](https://github.com/Shopify/app-bridge/commit/617f900a6c4c8826e931ab20a6cb892e1ada98cf))
16
+
17
+
18
+
19
+
20
+
21
+ ## [2.0.25](https://github.com/Shopify/app-bridge/compare/v2.0.24...v2.0.25) (2022-04-20)
22
+
23
+
24
+ ### Bug Fixes
25
+
26
+ * **app-bridge-react:** prevent Resource Picker from sending unecessary updates ([62abe7f](https://github.com/Shopify/app-bridge/commit/62abe7f4116bf4c78934b8eb86e9a74fc0ea03d5))
27
+ * refactor useFeaturesAvailable to always return state ([2634016](https://github.com/Shopify/app-bridge/commit/2634016ccc9b883dd979c82585833b0fdf73d6d0))
28
+ * **app-bridge-react:** ensure useAppState only modifies the state when it has actually changed ([0a2f017](https://github.com/Shopify/app-bridge/commit/0a2f017c35e7d5dda8642eb68801d25158cb7539))
29
+
30
+
31
+ ### Features
32
+
33
+ * Add optional router prop to Provider ([4d032b1](https://github.com/Shopify/app-bridge/commit/4d032b1e0cc940ab02a07339ed48cc23e21e26ae))
34
+ * **app-bridge-react:** add useFeatureRequest hook ([adc03c9](https://github.com/Shopify/app-bridge/commit/adc03c9c4d1b2b9e3a2ea44a9ed2eaf4b75b99bf))
35
+ * useFeature hook, refactor React playground ([e1b7c71](https://github.com/Shopify/app-bridge/commit/e1b7c71a4e3f3fb3a6b0373ea6aedc05a34baaea))
36
+
37
+
38
+
39
+
40
+
41
+ ## [2.0.24](https://github.com/Shopify/app-bridge/compare/v2.0.23...v2.0.24) (2022-04-08)
42
+
43
+
44
+ ### Features
45
+
46
+ * **app-bridge-react:** add useNavigate hook ([ae818cb](https://github.com/Shopify/app-bridge/commit/ae818cb7b26e4f416bf9dfa9153940775bdf98df))
47
+
48
+
49
+
50
+
51
+
6
52
  ## [2.0.23](https://github.com/Shopify/app-bridge/compare/v2.0.22...v2.0.23) (2022-04-07)
7
53
 
8
54
 
@@ -1,7 +1,5 @@
1
- import React from 'react';
2
- import { Modal as AppBridgeModal } from '@shopify/app-bridge/actions';
1
+ import { Size } from '@shopify/app-bridge/actions/Modal';
3
2
  import { ActionProps } from '../../types';
4
- declare type Size = keyof typeof AppBridgeModal.Size;
5
3
  export interface Props {
6
4
  /** Whether the modal is open or not */
7
5
  open: boolean;
@@ -10,7 +8,7 @@ export interface Props {
10
8
  /** The content for the title of the modal */
11
9
  title?: string;
12
10
  /** Controls the size of the modal */
13
- size?: Size;
11
+ size?: keyof typeof Size;
14
12
  /** Message to display inside modal */
15
13
  message?: string;
16
14
  /** Primary action */
@@ -30,14 +28,5 @@ export interface Props {
30
28
  *
31
29
  * @public
32
30
  */
33
- declare class Modal extends React.PureComponent<Props, never> {
34
- static contextType: React.Context<import("../../context").IAppBridgeContext>;
35
- private focusReturnPoint;
36
- private modal;
37
- componentDidMount(): void;
38
- componentDidUpdate(prevProps: Props): void;
39
- componentWillUnmount(): void;
40
- render(): null;
41
- private transformProps;
42
- }
31
+ declare function Modal(props: Props): null;
43
32
  export default Modal;
@@ -1,19 +1,4 @@
1
1
  "use strict";
2
- var __extends = (this && this.__extends) || (function () {
3
- var extendStatics = function (d, b) {
4
- extendStatics = Object.setPrototypeOf ||
5
- ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
- function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
7
- return extendStatics(d, b);
8
- };
9
- return function (d, b) {
10
- if (typeof b !== "function" && b !== null)
11
- throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
12
- extendStatics(d, b);
13
- function __() { this.constructor = d; }
14
- d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15
- };
16
- })();
17
2
  var __assign = (this && this.__assign) || function () {
18
3
  __assign = Object.assign || function(t) {
19
4
  for (var s, i = 1, n = arguments.length; i < n; i++) {
@@ -25,14 +10,22 @@ var __assign = (this && this.__assign) || function () {
25
10
  };
26
11
  return __assign.apply(this, arguments);
27
12
  };
28
- var __importDefault = (this && this.__importDefault) || function (mod) {
29
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ var __rest = (this && this.__rest) || function (s, e) {
14
+ var t = {};
15
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
16
+ t[p] = s[p];
17
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
18
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
19
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
20
+ t[p[i]] = s[p[i]];
21
+ }
22
+ return t;
30
23
  };
31
24
  Object.defineProperty(exports, "__esModule", { value: true });
32
- var react_1 = __importDefault(require("react"));
33
- var actions_1 = require("@shopify/app-bridge/actions");
25
+ var react_1 = require("react");
26
+ var Modal_1 = require("@shopify/app-bridge/actions/Modal");
34
27
  var transformers_1 = require("../../utilities/transformers");
35
- var context_1 = require("../../context");
28
+ var useAppBridge_1 = require("../../useAppBridge");
36
29
  /**
37
30
  * Modal component
38
31
  *
@@ -41,92 +34,106 @@ var context_1 = require("../../context");
41
34
  *
42
35
  * @public
43
36
  */
44
- var Modal = /** @class */ (function (_super) {
45
- __extends(Modal, _super);
46
- function Modal() {
47
- var _this = _super !== null && _super.apply(this, arguments) || this;
48
- _this.focusReturnPoint = null;
49
- return _this;
50
- }
51
- Modal.prototype.componentDidMount = function () {
52
- var _a = this.props, open = _a.open, onClose = _a.onClose;
53
- var app = this.context;
54
- this.modal = actions_1.Modal.create(app, this.transformProps());
55
- if (onClose != null) {
56
- this.modal.subscribe(actions_1.Modal.Action.CLOSE, onClose);
37
+ function Modal(props) {
38
+ var app = useAppBridge_1.useAppBridge();
39
+ var focusReturnPoint = react_1.useRef(null);
40
+ // Initialize with open: false so the open action will dispatch on initial load
41
+ var prevProps = react_1.useRef({ open: false });
42
+ var open = props.open;
43
+ var isUnmounted = react_1.useRef(false);
44
+ var modal = react_1.useMemo(function () {
45
+ /**
46
+ * We purposely don't pass buttons here as they will be replaced
47
+ * by the subsequent useEffect to call `set` to update the options.
48
+ * If we pass them in here button subscriptions will be created without
49
+ * being cleaned up.
50
+ */
51
+ var primaryAction = props.primaryAction, secondaryActions = props.secondaryActions, rest = __rest(props, ["primaryAction", "secondaryActions"]);
52
+ return Modal_1.create(app, transformProps(app, rest));
53
+ }, [app]);
54
+ /**
55
+ * All option updates are handled in this useEffect to avoid race conditions.
56
+ * For example, we need to call `modal.unsubscribe` to clean up button subscriptions
57
+ * but we calling it will also unsubscribe the onClose handler. Therefore we want
58
+ * to ensure all callbacks are handled in a single useEffect with a single clean up
59
+ * call to unsubscribe.
60
+ */
61
+ react_1.useEffect(function () {
62
+ if (isUnmounted.current) {
63
+ prevProps.current = props;
64
+ return;
57
65
  }
66
+ var wasOpen = prevProps.current.open;
67
+ var openUpdated = wasOpen !== open;
68
+ /** We only call `set` to update the options if the modal is open.
69
+ * This is because while the modal is closed updates don't take effect on screen.
70
+ */
58
71
  if (open) {
59
- this.focusReturnPoint = document.activeElement;
60
- this.modal.dispatch(actions_1.Modal.Action.OPEN);
61
- }
62
- };
63
- Modal.prototype.componentDidUpdate = function (prevProps) {
64
- var _a = this.props, open = _a.open, onClose = _a.onClose;
65
- var wasOpen = prevProps.open;
66
- var transformedProps = this.transformProps(wasOpen);
67
- this.modal.unsubscribe();
68
- if (isIframeModal(transformedProps)) {
69
- this.modal.set(transformedProps, open);
70
- }
71
- else {
72
- this.modal.set(transformedProps, open);
73
- }
74
- if (onClose != null) {
75
- this.modal.subscribe(actions_1.Modal.Action.CLOSE, onClose);
76
- }
77
- if (wasOpen !== open) {
78
- if (open) {
79
- this.modal.dispatch(actions_1.Modal.Action.OPEN);
72
+ var transformedProps = transformProps(app, props, wasOpen);
73
+ /** We skip dispatching the update action if we're about to update the open state.
74
+ * This is because the OPEN action will always sends the updated options
75
+ * so we don't need to send it twice.
76
+ */
77
+ var shouldSendUpdate = !openUpdated;
78
+ if (isIframeModal(transformedProps)) {
79
+ modal.set(transformedProps, shouldSendUpdate);
80
80
  }
81
81
  else {
82
- this.modal.dispatch(actions_1.Modal.Action.CLOSE);
82
+ modal.set(transformedProps, shouldSendUpdate);
83
83
  }
84
84
  }
85
- if (!wasOpen && open) {
86
- this.focusReturnPoint = document.activeElement;
87
- }
88
- else if (wasOpen &&
89
- !open &&
90
- this.focusReturnPoint != null &&
91
- document.contains(this.focusReturnPoint)) {
92
- this.focusReturnPoint.focus();
93
- this.focusReturnPoint = null;
94
- }
95
- };
96
- Modal.prototype.componentWillUnmount = function () {
97
- this.modal.unsubscribe();
98
- if (this.props.open) {
99
- this.modal.dispatch(actions_1.Modal.Action.CLOSE);
100
- }
101
- };
102
- Modal.prototype.render = function () {
103
- return null;
104
- };
105
- Modal.prototype.transformProps = function (wasOpen) {
106
- var _a = this.props, title = _a.title, size = _a.size, message = _a.message, src = _a.src, primaryAction = _a.primaryAction, secondaryActions = _a.secondaryActions, loading = _a.loading;
107
- var app = this.context;
108
- var safeSize = size == null ? undefined : actions_1.Modal.Size[size];
109
- var srcPayload = {};
110
- if (src != null) {
111
- if (src.match('^https?://')) {
112
- srcPayload.url = src;
85
+ if (openUpdated) {
86
+ if (open) {
87
+ modal.dispatch(Modal_1.Action.OPEN);
88
+ focusReturnPoint.current = document.activeElement;
113
89
  }
114
90
  else {
115
- srcPayload.path = src;
91
+ modal.dispatch(Modal_1.Action.CLOSE);
92
+ if (focusReturnPoint.current != null && document.contains(focusReturnPoint.current)) {
93
+ focusReturnPoint.current.focus();
94
+ focusReturnPoint.current = null;
95
+ }
116
96
  }
117
97
  }
118
- return __assign(__assign({ title: title, message: message, size: safeSize }, srcPayload), { footer: {
119
- buttons: transformers_1.transformActions(app, {
120
- primaryAction: primaryAction,
121
- secondaryActions: secondaryActions,
122
- }),
123
- }, loading: wasOpen ? undefined : loading });
124
- };
125
- Modal.contextType = context_1.AppBridgeContext;
126
- return Modal;
127
- }(react_1.default.PureComponent));
98
+ if (props.onClose != null) {
99
+ modal.subscribe(Modal_1.Action.CLOSE, props.onClose);
100
+ }
101
+ prevProps.current = props;
102
+ return function () {
103
+ // This is important to clean up previous buttons and onClose subscriptions
104
+ modal.unsubscribe();
105
+ };
106
+ }, [props, open]);
107
+ react_1.useEffect(function () {
108
+ return function () {
109
+ if (prevProps.current.open) {
110
+ modal.dispatch(Modal_1.Action.CLOSE);
111
+ }
112
+ };
113
+ }, [modal]);
114
+ return null;
115
+ }
128
116
  function isIframeModal(options) {
129
117
  return (typeof options.url === 'string' ||
130
118
  typeof options.path === 'string');
131
119
  }
120
+ function transformProps(app, props, wasOpen) {
121
+ var title = props.title, size = props.size, message = props.message, src = props.src, primaryAction = props.primaryAction, secondaryActions = props.secondaryActions, loading = props.loading;
122
+ var safeSize = size == null ? undefined : Modal_1.Size[size];
123
+ var srcPayload = {};
124
+ if (src != null) {
125
+ if (src.match('^https?://')) {
126
+ srcPayload.url = src;
127
+ }
128
+ else {
129
+ srcPayload.path = src;
130
+ }
131
+ }
132
+ return __assign(__assign({ title: title, message: message, size: safeSize }, srcPayload), { footer: {
133
+ buttons: transformers_1.transformActions(app, {
134
+ primaryAction: primaryAction,
135
+ secondaryActions: secondaryActions,
136
+ }),
137
+ }, loading: wasOpen ? undefined : loading });
138
+ }
132
139
  exports.default = Modal;
@@ -1,55 +1,40 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
- }) : (function(o, m, k, k2) {
6
- if (k2 === undefined) k2 = k;
7
- o[k2] = m[k];
8
- }));
9
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
- Object.defineProperty(o, "default", { enumerable: true, value: v });
11
- }) : function(o, v) {
12
- o["default"] = v;
13
- });
14
- var __importStar = (this && this.__importStar) || function (mod) {
15
- if (mod && mod.__esModule) return mod;
16
- var result = {};
17
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
- __setModuleDefault(result, mod);
19
- return result;
20
- };
21
2
  Object.defineProperty(exports, "__esModule", { value: true });
22
3
  var react_1 = require("react");
23
- var AppBridgeAppLinks = __importStar(require("@shopify/app-bridge/actions/Link/AppLink"));
24
- var AppBridgeNavigationMenu = __importStar(require("@shopify/app-bridge/actions/Menu/NavigationMenu"));
4
+ var AppLink_1 = require("@shopify/app-bridge/actions/Link/AppLink");
5
+ var NavigationMenu_1 = require("@shopify/app-bridge/actions/Menu/NavigationMenu");
25
6
  var useAppBridge_1 = require("../../useAppBridge");
7
+ function defaultMatcher(link, location) {
8
+ return link.destination.replace(/\/$/, '') === location.pathname.replace(/\/$/, '');
9
+ }
26
10
  function NavigationMenu(_a) {
27
- var navigationLinks = _a.navigationLinks, matcher = _a.matcher;
11
+ var navigationLinks = _a.navigationLinks, _b = _a.matcher, matcher = _b === void 0 ? defaultMatcher : _b;
28
12
  var app = useAppBridge_1.useAppBridge();
29
- var _b = react_1.useState(), activeLink = _b[0], setActiveLink = _b[1];
30
- var items = react_1.useMemo(function () {
31
- return navigationLinks.map(function (link) {
32
- var appLink = AppBridgeAppLinks.create(app, link);
33
- if ((matcher === null || matcher === void 0 ? void 0 : matcher(link, location)) || link.destination === location.pathname) {
34
- setActiveLink(appLink);
35
- }
36
- return appLink;
37
- });
38
- }, [app, location.pathname, matcher, navigationLinks]);
39
- var navigationMenu = react_1.useMemo(function () {
40
- return AppBridgeNavigationMenu.create(app, {
41
- items: items,
42
- active: activeLink,
13
+ var _c = react_1.useState(), items = _c[0], setItems = _c[1];
14
+ react_1.useEffect(function () {
15
+ var items = navigationLinks.map(function (link) { return AppLink_1.create(app, link); });
16
+ setItems(items);
17
+ }, [app, JSON.stringify(navigationLinks)]);
18
+ var activeLink = react_1.useMemo(function () {
19
+ var activeLinkIndex = (items || []).findIndex(function (link) {
20
+ return matcher(link, location);
43
21
  });
44
- /* We want to reuse the same NavigationMenu instance, even when props change
45
- * (so we don't include all the props in the dependency array).
46
- * Instead of recreating the component on every change, we use the set method,
47
- * in the useEffect block below, to dispatch updates when props change.
48
- */
49
- }, [app]);
22
+ if (activeLinkIndex >= 0) {
23
+ return items === null || items === void 0 ? void 0 : items[activeLinkIndex];
24
+ }
25
+ }, [app, location.pathname, matcher, items, location.pathname]);
50
26
  react_1.useEffect(function () {
51
- navigationMenu.set({ items: items, active: activeLink });
52
- }, [activeLink, items]);
27
+ // Skip creating the navigation menu on initial render
28
+ if (!items) {
29
+ return;
30
+ }
31
+ /**
32
+ * There isn't any advantage to keeping around a consistent instance of
33
+ * the navigation menu as when we create a new one it results in
34
+ * the same UPDATE action to be dispatched
35
+ */
36
+ NavigationMenu_1.create(app, { items: items, active: activeLink });
37
+ }, [items, activeLink]);
53
38
  return null;
54
39
  }
55
40
  exports.default = NavigationMenu;
@@ -1,5 +1,7 @@
1
- import React from 'react';
1
+ import React, { PropsWithChildren } from 'react';
2
2
  import type { AppConfigV2, DispatchActionHook } from '@shopify/app-bridge/client';
3
+ import type { History } from '../ClientRouter';
4
+ import type { LocationOrHref } from '../RoutePropagator';
3
5
  /**
4
6
  * Provider props
5
7
  *
@@ -10,26 +12,70 @@ export interface Props {
10
12
  config: AppConfigV2;
11
13
  /** The child elements to render. */
12
14
  children?: React.ReactNode;
15
+ /**
16
+ * Option to set up client routing and route propagation automatically.
17
+ * Passing in a router will allow you to bypass setting these
18
+ * utilities up yourself.
19
+ *
20
+ * If you are using React Router, ensure that the Provider is a child
21
+ * of the router component. For example:
22
+ *
23
+ * import {useMemo} from 'react';
24
+ * import {useLocation, useNavigate, BrowserRouter} from 'react-router-dom';
25
+ * import {Provider} from '@shopify/app-bridge-react';
26
+ * import Routes from './Routes';
27
+ *
28
+ * export function App() {
29
+ * const navigate = useNavigate();
30
+ * const location = useLocation();
31
+ * const history = useMemo(
32
+ * () => ({replace: (path: string) => navigate(path, {replace: true})}),
33
+ * [navigate],
34
+ * );
35
+ * const router = useMemo(
36
+ * () => ({
37
+ * location,
38
+ * history,
39
+ * }),
40
+ * [location, navigate],
41
+ * );
42
+ * return (
43
+ * <Provider
44
+ * apiKey={{
45
+ * apiKey: 'API key from Shopify Partner Dashboard',
46
+ * host: host,
47
+ * }}
48
+ * router={router}
49
+ * >
50
+ * <Routes />
51
+ * </Provider>
52
+ * );
53
+ * }
54
+ *
55
+ * export default function AppWrapper() {
56
+ * return (
57
+ * <BrowserRouter>
58
+ * <App />
59
+ * </BrowserRouter>
60
+ * );
61
+ * }
62
+ */
63
+ router?: {
64
+ location: LocationOrHref;
65
+ history: History;
66
+ };
13
67
  }
14
68
  /**
15
69
  * Create an App Bridge client application from a config and pass it as the
16
70
  * value to the context provider.
17
71
  *
18
- * @remarks
19
- * You'll probably want something a little more robust than storing the current
20
- * app instance in a module-level global.
21
- *
22
72
  * @public
23
73
  */
24
- declare class Provider extends React.Component<Props> {
25
- private app;
26
- private get appInstance();
27
- render(): JSX.Element;
28
- }
29
- export default Provider;
74
+ declare function Provider({ config, router, children }: PropsWithChildren<Props>): JSX.Element;
30
75
  /**
31
76
  * Augment actions with clientInterface metadata, identifying use of this library
32
77
  *
33
78
  * @internal
34
79
  */
35
80
  export declare const setClientInterfaceHook: DispatchActionHook;
81
+ export default Provider;
@@ -1,19 +1,4 @@
1
1
  "use strict";
2
- var __extends = (this && this.__extends) || (function () {
3
- var extendStatics = function (d, b) {
4
- extendStatics = Object.setPrototypeOf ||
5
- ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
- function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
7
- return extendStatics(d, b);
8
- };
9
- return function (d, b) {
10
- if (typeof b !== "function" && b !== null)
11
- throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
12
- extendStatics(d, b);
13
- function __() { this.constructor = d; }
14
- d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15
- };
16
- })();
17
2
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
18
3
  if (k2 === undefined) k2 = k;
19
4
  Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
@@ -33,52 +18,34 @@ var __importStar = (this && this.__importStar) || function (mod) {
33
18
  __setModuleDefault(result, mod);
34
19
  return result;
35
20
  };
36
- var __importDefault = (this && this.__importDefault) || function (mod) {
37
- return (mod && mod.__esModule) ? mod : { "default": mod };
38
- };
39
21
  Object.defineProperty(exports, "__esModule", { value: true });
40
22
  exports.setClientInterfaceHook = void 0;
41
- var react_1 = __importDefault(require("react"));
23
+ var react_1 = __importStar(require("react"));
42
24
  var app_bridge_1 = __importStar(require("@shopify/app-bridge"));
43
25
  var context_1 = require("../../context");
26
+ var ClientRouter_1 = require("../ClientRouter");
27
+ var RoutePropagator_1 = require("../RoutePropagator");
44
28
  // eslint-disable-next-line @typescript-eslint/no-var-requires
45
29
  var packageJson = require('../../package.json');
46
30
  /**
47
31
  * Create an App Bridge client application from a config and pass it as the
48
32
  * value to the context provider.
49
33
  *
50
- * @remarks
51
- * You'll probably want something a little more robust than storing the current
52
- * app instance in a module-level global.
53
- *
54
34
  * @public
55
35
  */
56
- var Provider = /** @class */ (function (_super) {
57
- __extends(Provider, _super);
58
- function Provider() {
59
- var _this = _super !== null && _super.apply(this, arguments) || this;
60
- _this.app = _this.appInstance;
61
- return _this;
62
- }
63
- Object.defineProperty(Provider.prototype, "appInstance", {
64
- get: function () {
65
- if (!this.app) {
66
- this.app = app_bridge_1.default(this.props.config);
67
- if (this.app && this.app.hooks) {
68
- this.app.hooks.set(app_bridge_1.LifecycleHook.DispatchAction, exports.setClientInterfaceHook);
69
- }
70
- }
71
- return this.app;
72
- },
73
- enumerable: false,
74
- configurable: true
75
- });
76
- Provider.prototype.render = function () {
77
- return (react_1.default.createElement(context_1.AppBridgeContext.Provider, { value: this.appInstance }, this.props.children));
78
- };
79
- return Provider;
80
- }(react_1.default.Component));
81
- exports.default = Provider;
36
+ function Provider(_a) {
37
+ var config = _a.config, router = _a.router, children = _a.children;
38
+ var app = react_1.useMemo(function () { return app_bridge_1.default(config); }, [JSON.stringify(config)]);
39
+ react_1.useEffect(function () {
40
+ if (app === null || app === void 0 ? void 0 : app.hooks) {
41
+ app.hooks.set(app_bridge_1.LifecycleHook.DispatchAction, exports.setClientInterfaceHook);
42
+ }
43
+ }, [app]);
44
+ var routerMarkup = (router === null || router === void 0 ? void 0 : router.history) && (router === null || router === void 0 ? void 0 : router.location) ? (react_1.default.createElement(Router, { history: router.history, location: router.location })) : null;
45
+ return (react_1.default.createElement(context_1.AppBridgeContext.Provider, { value: app },
46
+ routerMarkup,
47
+ children));
48
+ }
82
49
  /**
83
50
  * Augment actions with clientInterface metadata, identifying use of this library
84
51
  *
@@ -94,3 +61,10 @@ var setClientInterfaceHook = function (next) {
94
61
  };
95
62
  };
96
63
  exports.setClientInterfaceHook = setClientInterfaceHook;
64
+ function Router(_a) {
65
+ var history = _a.history, location = _a.location;
66
+ ClientRouter_1.useClientRouting(history);
67
+ RoutePropagator_1.useRoutePropagation(location);
68
+ return null;
69
+ }
70
+ exports.default = Provider;
@@ -1,11 +1,10 @@
1
- import React from 'react';
2
- import { ResourcePicker as AppBridgeResourcePicker } from '@shopify/app-bridge/actions';
3
- import { BaseResource } from '@shopify/app-bridge/actions/ResourcePicker';
1
+ import { ActionVerb, ResourceType } from '@shopify/app-bridge/actions/ResourcePicker';
2
+ import type { BaseResource, Options, ResourceSelection, ProductOptions } from '@shopify/app-bridge/actions/ResourcePicker';
4
3
  export interface SelectPayload {
5
4
  /** The selected resources
6
5
  * @see {@link https://help.shopify.com/en/api/embedded-apps/app-bridge/actions/resourcepicker|resource picker documentation} for more information
7
6
  */
8
- selection: AppBridgeResourcePicker.ResourceSelection[];
7
+ selection: ResourceSelection[];
9
8
  }
10
9
  interface BaseProps {
11
10
  /** Whether the picker is open or not */
@@ -26,7 +25,7 @@ interface BaseProps {
26
25
  /** Whether to allow selection of multiple items, or the maximum number of selected items */
27
26
  selectMultiple?: boolean | number;
28
27
  /** Override default action verb `Add`. The actionVerb appears in the title `<actionVerb>` `<resourceType>` and as the primary action of the resource picker. */
29
- actionVerb?: AppBridgeResourcePicker.ActionVerb;
28
+ actionVerb?: ActionVerb;
30
29
  /** Callback when a selection has been made */
31
30
  onSelection?(selectPayload: SelectPayload): void;
32
31
  /** Callback when the picker is closed without selection */
@@ -63,15 +62,7 @@ export declare type Props = ProductPickerProps | ProductVariantProps | Collectio
63
62
  *
64
63
  * @public
65
64
  */
66
- declare class ResourcePicker extends React.PureComponent<Props, never> {
67
- static contextType: React.Context<import("../../context").IAppBridgeContext>;
68
- static ActionVerb: typeof AppBridgeResourcePicker.ActionVerb;
69
- private focusReturnPoint;
70
- private picker;
71
- componentDidMount(): void;
72
- componentDidUpdate(prevProps: Props): void;
73
- componentWillUnmount(): void;
74
- render(): null;
75
- getActionOptions(): AppBridgeResourcePicker.Options | AppBridgeResourcePicker.ProductOptions;
76
- }
65
+ declare function ResourcePicker(props: Props): null;
77
66
  export default ResourcePicker;
67
+ export type { BaseResource, Options, ProductOptions };
68
+ export { ActionVerb, ResourceType };