@shopify/app-bridge-react 2.0.24 → 2.0.27
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 +43 -0
- package/components/Modal/Modal.d.ts +3 -14
- package/components/Modal/Modal.js +101 -94
- package/components/NavigationMenu/NavigationMenu.js +29 -44
- package/components/Provider/Provider.d.ts +57 -11
- package/components/Provider/Provider.js +23 -49
- package/components/ResourcePicker/ResourcePicker.d.ts +7 -16
- package/components/ResourcePicker/ResourcePicker.js +77 -94
- package/components/TitleBar/TitleBar.d.ts +3 -14
- package/components/TitleBar/TitleBar.js +101 -73
- package/hooks/index.d.ts +3 -0
- package/hooks/index.js +5 -1
- package/hooks/useAppBridgeState/useAppBridgeState.js +18 -4
- package/hooks/useFeatureRequest/index.d.ts +1 -0
- package/hooks/useFeatureRequest/index.js +13 -0
- package/hooks/useFeatureRequest/useFeatureRequest.d.ts +13 -0
- package/hooks/useFeatureRequest/useFeatureRequest.js +49 -0
- package/hooks/useFeaturesAvailable/index.d.ts +2 -0
- package/hooks/useFeaturesAvailable/index.js +5 -0
- package/hooks/useFeaturesAvailable/useFeaturesAvailable.d.ts +12 -0
- package/hooks/useFeaturesAvailable/useFeaturesAvailable.js +101 -0
- package/package.json +3 -3
- package/types.d.ts +2 -0
- package/types.js +3 -0
- package/umd/index.js +3 -3
- package/utilities/transformers.d.ts +3 -2
- package/utilities/transformers.js +30 -9
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,49 @@
|
|
|
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.27](https://github.com/Shopify/app-bridge/compare/v2.0.26...v2.0.27) (2022-05-12)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @shopify/app-bridge-react
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## [2.0.26](https://github.com/Shopify/app-bridge/compare/v2.0.25...v2.0.26) (2022-04-28)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Bug Fixes
|
|
18
|
+
|
|
19
|
+
* **app-bridge:** creating a title bar with empty options should not dispatch an update action ([c31f135](https://github.com/Shopify/app-bridge/commit/c31f135ffb78b3c69278cef0ce0674eb55aa7837))
|
|
20
|
+
* **app-bridge-react:** ensure Modal component only dispatch UPDATE action when necessary ([3f6bd1a](https://github.com/Shopify/app-bridge/commit/3f6bd1ae4c7475b2cccad646e0e4b5c17f681693))
|
|
21
|
+
* **app-bridge-react:** stop sending unnecessary updates when Navigation Menu props have not changed ([5d57495](https://github.com/Shopify/app-bridge/commit/5d57495bda42b37913f1c582159f04aab97d478a))
|
|
22
|
+
* **app-bridge-react:** update redirect callbacks for title bar when onAction changes ([68cd7ac](https://github.com/Shopify/app-bridge/commit/68cd7ace44b3cf92c4adb76e3d975e7a63b61b59))
|
|
23
|
+
* **app-bridge-react:** update title bar callbacks when they change ([617f900](https://github.com/Shopify/app-bridge/commit/617f900a6c4c8826e931ab20a6cb892e1ada98cf))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
## [2.0.25](https://github.com/Shopify/app-bridge/compare/v2.0.24...v2.0.25) (2022-04-20)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
### Bug Fixes
|
|
33
|
+
|
|
34
|
+
* **app-bridge-react:** prevent Resource Picker from sending unecessary updates ([62abe7f](https://github.com/Shopify/app-bridge/commit/62abe7f4116bf4c78934b8eb86e9a74fc0ea03d5))
|
|
35
|
+
* refactor useFeaturesAvailable to always return state ([2634016](https://github.com/Shopify/app-bridge/commit/2634016ccc9b883dd979c82585833b0fdf73d6d0))
|
|
36
|
+
* **app-bridge-react:** ensure useAppState only modifies the state when it has actually changed ([0a2f017](https://github.com/Shopify/app-bridge/commit/0a2f017c35e7d5dda8642eb68801d25158cb7539))
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
### Features
|
|
40
|
+
|
|
41
|
+
* Add optional router prop to Provider ([4d032b1](https://github.com/Shopify/app-bridge/commit/4d032b1e0cc940ab02a07339ed48cc23e21e26ae))
|
|
42
|
+
* **app-bridge-react:** add useFeatureRequest hook ([adc03c9](https://github.com/Shopify/app-bridge/commit/adc03c9c4d1b2b9e3a2ea44a9ed2eaf4b75b99bf))
|
|
43
|
+
* useFeature hook, refactor React playground ([e1b7c71](https://github.com/Shopify/app-bridge/commit/e1b7c71a4e3f3fb3a6b0373ea6aedc05a34baaea))
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
6
49
|
## [2.0.24](https://github.com/Shopify/app-bridge/compare/v2.0.23...v2.0.24) (2022-04-08)
|
|
7
50
|
|
|
8
51
|
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import
|
|
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
|
|
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
|
|
29
|
-
|
|
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 =
|
|
33
|
-
var
|
|
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
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
82
|
+
modal.set(transformedProps, shouldSendUpdate);
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
|
-
if (
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
-
|
|
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
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
|
24
|
-
var
|
|
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,
|
|
11
|
+
var navigationLinks = _a.navigationLinks, _b = _a.matcher, matcher = _b === void 0 ? defaultMatcher : _b;
|
|
28
12
|
var app = useAppBridge_1.useAppBridge();
|
|
29
|
-
var
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
return
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
52
|
-
|
|
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
|
|
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 =
|
|
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
|
-
|
|
57
|
-
|
|
58
|
-
function
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
|
2
|
-
import {
|
|
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:
|
|
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?:
|
|
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
|
|
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 };
|