@shopify/app-bridge-react 0.0.0-snapshot-20221220002610
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/README.md +171 -0
- package/components/ClientRouter/ClientRouter.d.ts +23 -0
- package/components/ClientRouter/ClientRouter.js +52 -0
- package/components/ClientRouter/hook.d.ts +10 -0
- package/components/ClientRouter/hook.js +20 -0
- package/components/ClientRouter/index.d.ts +3 -0
- package/components/ClientRouter/index.js +10 -0
- package/components/ClientRouter/router.d.ts +5 -0
- package/components/ClientRouter/router.js +11 -0
- package/components/ContextualSaveBar/ContextualSaveBar.d.ts +9 -0
- package/components/ContextualSaveBar/ContextualSaveBar.js +24 -0
- package/components/ContextualSaveBar/index.d.ts +3 -0
- package/components/ContextualSaveBar/index.js +7 -0
- package/components/Loading/Loading.d.ts +19 -0
- package/components/Loading/Loading.js +55 -0
- package/components/Loading/index.d.ts +2 -0
- package/components/Loading/index.js +7 -0
- package/components/Modal/Modal.d.ts +32 -0
- package/components/Modal/Modal.js +139 -0
- package/components/Modal/ModalContent/ModalContent.d.ts +24 -0
- package/components/Modal/ModalContent/ModalContent.js +61 -0
- package/components/Modal/ModalContent/index.d.ts +2 -0
- package/components/Modal/ModalContent/index.js +7 -0
- package/components/Modal/index.d.ts +4 -0
- package/components/Modal/index.js +10 -0
- package/components/NavigationMenu/NavigationMenu.d.ts +17 -0
- package/components/NavigationMenu/NavigationMenu.js +40 -0
- package/components/NavigationMenu/index.d.ts +3 -0
- package/components/NavigationMenu/index.js +7 -0
- package/components/Provider/Provider.d.ts +81 -0
- package/components/Provider/Provider.js +78 -0
- package/components/Provider/index.d.ts +3 -0
- package/components/Provider/index.js +7 -0
- package/components/ResourcePicker/ResourcePicker.d.ts +36 -0
- package/components/ResourcePicker/ResourcePicker.js +120 -0
- package/components/ResourcePicker/index.d.ts +3 -0
- package/components/ResourcePicker/index.js +7 -0
- package/components/RoutePropagator/RoutePropagator.d.ts +22 -0
- package/components/RoutePropagator/RoutePropagator.js +54 -0
- package/components/RoutePropagator/globals.d.ts +3 -0
- package/components/RoutePropagator/globals.js +15 -0
- package/components/RoutePropagator/hook.d.ts +10 -0
- package/components/RoutePropagator/hook.js +20 -0
- package/components/RoutePropagator/index.d.ts +3 -0
- package/components/RoutePropagator/index.js +10 -0
- package/components/RoutePropagator/route-propagator.d.ts +7 -0
- package/components/RoutePropagator/route-propagator.js +91 -0
- package/components/TitleBar/TitleBar.d.ts +27 -0
- package/components/TitleBar/TitleBar.js +107 -0
- package/components/TitleBar/index.d.ts +3 -0
- package/components/TitleBar/index.js +7 -0
- package/components/Toast/Toast.d.ts +38 -0
- package/components/Toast/Toast.js +67 -0
- package/components/Toast/index.d.ts +3 -0
- package/components/Toast/index.js +7 -0
- package/components/index.d.ts +11 -0
- package/components/index.js +37 -0
- package/components/unstable_Picker/index.d.ts +3 -0
- package/components/unstable_Picker/index.js +7 -0
- package/components/unstable_Picker/unstable_Picker.d.ts +13 -0
- package/components/unstable_Picker/unstable_Picker.js +85 -0
- package/context.d.ts +14 -0
- package/context.js +10 -0
- package/hooks/index.d.ts +9 -0
- package/hooks/index.js +19 -0
- package/hooks/useAppBridgeState/index.d.ts +1 -0
- package/hooks/useAppBridgeState/index.js +13 -0
- package/hooks/useAppBridgeState/useAppBridgeState.d.ts +10 -0
- package/hooks/useAppBridgeState/useAppBridgeState.js +89 -0
- package/hooks/useContextualSaveBar/index.d.ts +1 -0
- package/hooks/useContextualSaveBar/index.js +5 -0
- package/hooks/useContextualSaveBar/useContextualSaveBar.d.ts +10 -0
- package/hooks/useContextualSaveBar/useContextualSaveBar.js +87 -0
- 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/hooks/useLocale/index.d.ts +1 -0
- package/hooks/useLocale/index.js +5 -0
- package/hooks/useLocale/useLocale.d.ts +1 -0
- package/hooks/useLocale/useLocale.js +8 -0
- package/hooks/useNavigate/index.d.ts +1 -0
- package/hooks/useNavigate/index.js +5 -0
- package/hooks/useNavigate/useNavigate.d.ts +3 -0
- package/hooks/useNavigate/useNavigate.js +63 -0
- package/hooks/useNavigationHistory/index.d.ts +1 -0
- package/hooks/useNavigationHistory/index.js +5 -0
- package/hooks/useNavigationHistory/useNavigationHistory.d.ts +16 -0
- package/hooks/useNavigationHistory/useNavigationHistory.js +28 -0
- package/hooks/useToast/index.d.ts +1 -0
- package/hooks/useToast/index.js +5 -0
- package/hooks/useToast/useToast.d.ts +20 -0
- package/hooks/useToast/useToast.js +46 -0
- package/index.d.ts +4 -0
- package/index.js +19 -0
- package/package.json +58 -0
- package/types.d.ts +35 -0
- package/types.js +5 -0
- package/umd/index.js +10 -0
- package/useAppBridge.d.ts +1 -0
- package/useAppBridge.js +13 -0
- package/utilities/transformers.d.ts +20 -0
- package/utilities/transformers.js +105 -0
package/README.md
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# `@shopify/app-bridge-react`
|
|
2
|
+
|
|
3
|
+
**[Join our team and work on libraries like this one.](https://www.shopify.ca/careers)**
|
|
4
|
+
|
|
5
|
+
[](LICENSE.md)
|
|
6
|
+
[](https://badge.fury.io/js/%40shopify%2Fapp-bridge-react.svg)
|
|
7
|
+
[](https://img.shields.io/bundlephobia/minzip/@shopify/app-bridge-react.svg)
|
|
8
|
+
|
|
9
|
+
Shopify App Bridge offers React component wrappers for some App Bridge actions. This is a great option if you are already using React and want to follow familiar patterns.
|
|
10
|
+
|
|
11
|
+
Instead of using App Bridge actions directly:
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
import createApp from '@shopify/app-bridge';
|
|
15
|
+
import * as TitleBar from '@shopify/app-bridge/actions/TitleBar';
|
|
16
|
+
|
|
17
|
+
const app = createApp({
|
|
18
|
+
apiKey: 'API key from Shopify Partner Dashboard',
|
|
19
|
+
host: 'host from URL search parameter',
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const titleBarOptions = {
|
|
23
|
+
title: 'My page title',
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const myTitleBar = TitleBar.create(app, titleBarOptions);
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Use the React component wrappers:
|
|
30
|
+
|
|
31
|
+
> **Note**: only one `Provider` is needed for your application.
|
|
32
|
+
|
|
33
|
+
```jsx
|
|
34
|
+
// MyApp.jsx
|
|
35
|
+
import React from 'react';
|
|
36
|
+
import ReactDOM from 'react-dom/client';
|
|
37
|
+
import {Provider} from '@shopify/app-bridge-react';
|
|
38
|
+
import {RedirectButton} from './RedirectButton';
|
|
39
|
+
|
|
40
|
+
function MyApp() {
|
|
41
|
+
const config = {
|
|
42
|
+
apiKey: 'API key from Shopify Partner Dashboard',
|
|
43
|
+
host: 'host from URL search parameter',
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<Provider config={config}>
|
|
48
|
+
<RedirectButton />
|
|
49
|
+
</Provider>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const root = document.createElement('div');
|
|
54
|
+
document.body.appendChild(root);
|
|
55
|
+
ReactDOM.createRoot(root).render(<MyApp />);
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
To access an `app` from the Provider, use the `useAppBridge` hook (since `v1.25.0`):
|
|
59
|
+
|
|
60
|
+
```jsx
|
|
61
|
+
// RedirectButton.jsx
|
|
62
|
+
import {Button, Redirect} from '@shopify/app-bridge/actions';
|
|
63
|
+
import {useAppBridge} from '@shopify/app-bridge-react';
|
|
64
|
+
|
|
65
|
+
function RedirectButton() {
|
|
66
|
+
const app = useAppBridge();
|
|
67
|
+
const redirect = Redirect.create(app);
|
|
68
|
+
|
|
69
|
+
const handleClick = () => {
|
|
70
|
+
// Go to {shopUrl}/admin/customers with newContext
|
|
71
|
+
redirect.dispatch(Redirect.Action.ADMIN_PATH, {
|
|
72
|
+
path: '/customers',
|
|
73
|
+
newContext: true,
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
return <Button onClick={handleClick}>Activate Lasers for Customers</Button>;
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Migrating from 2.x.x to 3.0.0
|
|
82
|
+
|
|
83
|
+
There are two breaking API changes in version 3.0.0.
|
|
84
|
+
|
|
85
|
+
- `useContextualSaveBar`
|
|
86
|
+
- `useToast`
|
|
87
|
+
|
|
88
|
+
### useContextualSaveBar
|
|
89
|
+
|
|
90
|
+
In version 2.x.x, `useContextualSaveBar` was called with all of its options. It then created the contextual save bar and dispatched show and hide functions as an internal side effect based on the `visible` prop and any changes in options. It did not return anything.
|
|
91
|
+
|
|
92
|
+
#### Example code
|
|
93
|
+
|
|
94
|
+
```tsx
|
|
95
|
+
useContextualSaveBar({
|
|
96
|
+
discardAction,
|
|
97
|
+
saveAction,
|
|
98
|
+
fullWidth,
|
|
99
|
+
leaveConfirmationDisable,
|
|
100
|
+
visible,
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
In version 3.0.0, `useContextualSaveBar` becomes more declarative. The hook is called without any props and it returns several objects and methods that can be used to update contextual save bar options, as well as to show and hide the component.
|
|
105
|
+
|
|
106
|
+
#### Example code
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
const {show, hide, saveAction, discardAction} = useContextualSaveBar();
|
|
110
|
+
const fullWidth = true;
|
|
111
|
+
const leaveConfirmationDisabled = false;
|
|
112
|
+
|
|
113
|
+
<Button
|
|
114
|
+
primary
|
|
115
|
+
onClick={() => {
|
|
116
|
+
show(fullWidth, leaveConfirmationDisabled);
|
|
117
|
+
discardAction.setOptions({onAction: () => console.log('On discard')});
|
|
118
|
+
saveAction.setOptions({onAction: () => console.log('On save')});
|
|
119
|
+
}}
|
|
120
|
+
>
|
|
121
|
+
Show ContextualSaveBar
|
|
122
|
+
</Button>
|
|
123
|
+
<Button onClick={hide}>Hide ContextualSaveBar</Button>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
See [useContextualSaveBar docs](https://shopify.dev/apps/tools/app-bridge/react-components/contextual-save-bar) for more details.
|
|
127
|
+
|
|
128
|
+
### useToast
|
|
129
|
+
|
|
130
|
+
In version 2.x.x, `useToast` returns a `show` method that accepts one prop - an object with the following properties:
|
|
131
|
+
|
|
132
|
+
- `content`
|
|
133
|
+
- `duration`
|
|
134
|
+
- `isError`
|
|
135
|
+
- `onDismiss`
|
|
136
|
+
|
|
137
|
+
All the props except `content` are optional.
|
|
138
|
+
|
|
139
|
+
#### Example code
|
|
140
|
+
|
|
141
|
+
```tsx
|
|
142
|
+
const {show} = useToast
|
|
143
|
+
|
|
144
|
+
show({
|
|
145
|
+
content: 'Success!,
|
|
146
|
+
duration: 2000,
|
|
147
|
+
isError: false,
|
|
148
|
+
onDismiss: () => console.log('Dismissed'),
|
|
149
|
+
})
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
In version 3.0.0, the `content` moves to a top-level prop and the remaining properties are passed in as an optional options prop (all properties in the options object remain optional).
|
|
153
|
+
`
|
|
154
|
+
|
|
155
|
+
#### Example code
|
|
156
|
+
|
|
157
|
+
```tsx
|
|
158
|
+
const {show} = useToast;
|
|
159
|
+
|
|
160
|
+
show('Success!', {
|
|
161
|
+
duration: 2000,
|
|
162
|
+
isError: false,
|
|
163
|
+
onDismiss: () => console.log('Dismissed'),
|
|
164
|
+
});
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
See [useToast docs](https://shopify.dev/apps/tools/app-bridge/react-components/toast) for more details.
|
|
168
|
+
|
|
169
|
+
## Legacy support
|
|
170
|
+
|
|
171
|
+
If you are using App Bridge `v1.24.0` and below, or your project does not support React hooks, alternative methods on how to access `app` can be found in the [Provider docs](https://shopify.dev/tools/app-bridge/react-components/provider#accessing-the-app-bridge-client-directly).
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Unsubscribe } from '@shopify/app-bridge';
|
|
3
|
+
import { AppBridgeContext } from '../../context';
|
|
4
|
+
import { History } from './router';
|
|
5
|
+
export interface Props {
|
|
6
|
+
history: History;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* ClientRouter component
|
|
10
|
+
*
|
|
11
|
+
* @remarks
|
|
12
|
+
* React component which keeps the Shopify admin url in sync with the app url
|
|
13
|
+
*
|
|
14
|
+
* @public
|
|
15
|
+
*/
|
|
16
|
+
export default class ClientRouter extends React.Component<Props, never> {
|
|
17
|
+
static contextType: React.Context<import("../../context").IAppBridgeContext>;
|
|
18
|
+
context: React.ContextType<typeof AppBridgeContext>;
|
|
19
|
+
unsubscribe?: Unsubscribe;
|
|
20
|
+
componentDidMount(): void;
|
|
21
|
+
componentWillUnmount(): void;
|
|
22
|
+
render(): null;
|
|
23
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
18
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
var react_1 = __importDefault(require("react"));
|
|
22
|
+
var context_1 = require("../../context");
|
|
23
|
+
var router_1 = require("./router");
|
|
24
|
+
/**
|
|
25
|
+
* ClientRouter component
|
|
26
|
+
*
|
|
27
|
+
* @remarks
|
|
28
|
+
* React component which keeps the Shopify admin url in sync with the app url
|
|
29
|
+
*
|
|
30
|
+
* @public
|
|
31
|
+
*/
|
|
32
|
+
var ClientRouter = /** @class */ (function (_super) {
|
|
33
|
+
__extends(ClientRouter, _super);
|
|
34
|
+
function ClientRouter() {
|
|
35
|
+
return _super !== null && _super.apply(this, arguments) || this;
|
|
36
|
+
}
|
|
37
|
+
ClientRouter.prototype.componentDidMount = function () {
|
|
38
|
+
var history = this.props.history;
|
|
39
|
+
this.unsubscribe = router_1.handleRouteChange(this.context, history);
|
|
40
|
+
};
|
|
41
|
+
ClientRouter.prototype.componentWillUnmount = function () {
|
|
42
|
+
if (this.unsubscribe) {
|
|
43
|
+
this.unsubscribe();
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
ClientRouter.prototype.render = function () {
|
|
47
|
+
return null;
|
|
48
|
+
};
|
|
49
|
+
ClientRouter.contextType = context_1.AppBridgeContext;
|
|
50
|
+
return ClientRouter;
|
|
51
|
+
}(react_1.default.Component));
|
|
52
|
+
exports.default = ClientRouter;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
var react_1 = require("react");
|
|
4
|
+
var useAppBridge_1 = require("../../useAppBridge");
|
|
5
|
+
var router_1 = require("./router");
|
|
6
|
+
/**
|
|
7
|
+
* useRoutePropagation
|
|
8
|
+
*
|
|
9
|
+
* @remarks
|
|
10
|
+
* A hook which keeps the Shopify admin url in sync with the app url
|
|
11
|
+
*
|
|
12
|
+
* @public
|
|
13
|
+
*/
|
|
14
|
+
function useClientRouting(history) {
|
|
15
|
+
var app = useAppBridge_1.useAppBridge();
|
|
16
|
+
react_1.useEffect(function () {
|
|
17
|
+
return router_1.handleRouteChange(app, history);
|
|
18
|
+
}, [app, history]);
|
|
19
|
+
}
|
|
20
|
+
exports.default = useClientRouting;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.useClientRouting = exports.ClientRouter = void 0;
|
|
7
|
+
var ClientRouter_1 = require("./ClientRouter");
|
|
8
|
+
Object.defineProperty(exports, "ClientRouter", { enumerable: true, get: function () { return __importDefault(ClientRouter_1).default; } });
|
|
9
|
+
var hook_1 = require("./hook");
|
|
10
|
+
Object.defineProperty(exports, "useClientRouting", { enumerable: true, get: function () { return __importDefault(hook_1).default; } });
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleRouteChange = void 0;
|
|
4
|
+
var actions_1 = require("@shopify/app-bridge/actions");
|
|
5
|
+
function handleRouteChange(app, history) {
|
|
6
|
+
return app.subscribe(actions_1.Redirect.Action.APP, function (_a) {
|
|
7
|
+
var path = _a.path;
|
|
8
|
+
history.replace(path);
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
exports.handleRouteChange = handleRouteChange;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { DiscardActionOptions, SaveActionOptions } from '@shopify/app-bridge/actions/ContextualSaveBar';
|
|
2
|
+
export interface Props {
|
|
3
|
+
discardAction?: DiscardActionOptions;
|
|
4
|
+
saveAction?: SaveActionOptions;
|
|
5
|
+
fullWidth?: boolean;
|
|
6
|
+
leaveConfirmationDisable?: boolean;
|
|
7
|
+
visible?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export default function ContextualSaveBar({ discardAction, saveAction, fullWidth, leaveConfirmationDisable, visible, }: Props): null;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
var react_1 = require("react");
|
|
4
|
+
var hooks_1 = require("../../hooks");
|
|
5
|
+
function ContextualSaveBar(_a) {
|
|
6
|
+
var _b = _a.discardAction, discardAction = _b === void 0 ? {} : _b, _c = _a.saveAction, saveAction = _c === void 0 ? {} : _c, fullWidth = _a.fullWidth, leaveConfirmationDisable = _a.leaveConfirmationDisable, visible = _a.visible;
|
|
7
|
+
var _d = hooks_1.useContextualSaveBar(), show = _d.show, hide = _d.hide, saveActionSetOptions = _d.saveAction.setOptions, discardActionSetOptions = _d.discardAction.setOptions;
|
|
8
|
+
react_1.useEffect(function () {
|
|
9
|
+
saveActionSetOptions(saveAction);
|
|
10
|
+
}, [saveAction]);
|
|
11
|
+
react_1.useEffect(function () {
|
|
12
|
+
discardActionSetOptions(discardAction);
|
|
13
|
+
}, [discardAction]);
|
|
14
|
+
react_1.useEffect(function () {
|
|
15
|
+
if (visible) {
|
|
16
|
+
show({ fullWidth: fullWidth, leaveConfirmationDisable: leaveConfirmationDisable });
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
hide();
|
|
20
|
+
}
|
|
21
|
+
}, [fullWidth, leaveConfirmationDisable, visible]);
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
exports.default = ContextualSaveBar;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
var ContextualSaveBar_1 = __importDefault(require("./ContextualSaveBar"));
|
|
7
|
+
exports.default = ContextualSaveBar_1.default;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { AppBridgeContext } from '../../context';
|
|
3
|
+
/**
|
|
4
|
+
* Loading component
|
|
5
|
+
*
|
|
6
|
+
* @remarks
|
|
7
|
+
* React component which wraps the Shopify App Bridge Loading action.
|
|
8
|
+
*
|
|
9
|
+
* @public
|
|
10
|
+
*/
|
|
11
|
+
declare class Loading extends React.Component {
|
|
12
|
+
static contextType: React.Context<import("../../context").IAppBridgeContext>;
|
|
13
|
+
context: React.ContextType<typeof AppBridgeContext>;
|
|
14
|
+
private loading;
|
|
15
|
+
componentDidMount(): void;
|
|
16
|
+
componentWillUnmount(): void;
|
|
17
|
+
render(): null;
|
|
18
|
+
}
|
|
19
|
+
export default Loading;
|
|
@@ -0,0 +1,55 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
18
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
var react_1 = __importDefault(require("react"));
|
|
22
|
+
var actions_1 = require("@shopify/app-bridge/actions");
|
|
23
|
+
var context_1 = require("../../context");
|
|
24
|
+
/**
|
|
25
|
+
* Loading component
|
|
26
|
+
*
|
|
27
|
+
* @remarks
|
|
28
|
+
* React component which wraps the Shopify App Bridge Loading action.
|
|
29
|
+
*
|
|
30
|
+
* @public
|
|
31
|
+
*/
|
|
32
|
+
var Loading = /** @class */ (function (_super) {
|
|
33
|
+
__extends(Loading, _super);
|
|
34
|
+
function Loading() {
|
|
35
|
+
return _super !== null && _super.apply(this, arguments) || this;
|
|
36
|
+
}
|
|
37
|
+
Loading.prototype.componentDidMount = function () {
|
|
38
|
+
var app = this.context;
|
|
39
|
+
this.loading = actions_1.Loading.create(app);
|
|
40
|
+
if (this.loading != null) {
|
|
41
|
+
this.loading.dispatch(actions_1.Loading.Action.START);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
Loading.prototype.componentWillUnmount = function () {
|
|
45
|
+
if (this.loading != null) {
|
|
46
|
+
this.loading.dispatch(actions_1.Loading.Action.STOP);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
Loading.prototype.render = function () {
|
|
50
|
+
return null;
|
|
51
|
+
};
|
|
52
|
+
Loading.contextType = context_1.AppBridgeContext;
|
|
53
|
+
return Loading;
|
|
54
|
+
}(react_1.default.Component));
|
|
55
|
+
exports.default = Loading;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
var Loading_1 = __importDefault(require("./Loading"));
|
|
7
|
+
exports.default = Loading_1.default;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Size } from '@shopify/app-bridge/actions/Modal';
|
|
2
|
+
import { ActionProps } from '../../types';
|
|
3
|
+
export interface Props {
|
|
4
|
+
/** Whether the modal is open or not */
|
|
5
|
+
open: boolean;
|
|
6
|
+
/** The url that will be loaded as the content of the modal */
|
|
7
|
+
src?: string;
|
|
8
|
+
/** The content for the title of the modal */
|
|
9
|
+
title?: string;
|
|
10
|
+
/** Controls the size of the modal */
|
|
11
|
+
size?: keyof typeof Size;
|
|
12
|
+
/** Message to display inside modal */
|
|
13
|
+
message?: string;
|
|
14
|
+
/** Primary action */
|
|
15
|
+
primaryAction?: ActionProps;
|
|
16
|
+
/** Collection of secondary actions */
|
|
17
|
+
secondaryActions?: ActionProps[];
|
|
18
|
+
/** Callback when the modal is closed */
|
|
19
|
+
onClose?(): void;
|
|
20
|
+
/** Enable loading behaviour, when `true` bear in mind you will need to use `Modal Content` to dismiss the loading after the iframe page is fully loaded */
|
|
21
|
+
loading?: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Modal component
|
|
25
|
+
*
|
|
26
|
+
* @remarks
|
|
27
|
+
* React component which wraps the Shopify App Bridge Modal action.
|
|
28
|
+
*
|
|
29
|
+
* @public
|
|
30
|
+
*/
|
|
31
|
+
declare function Modal(props: Props): null;
|
|
32
|
+
export default Modal;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
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;
|
|
23
|
+
};
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
var react_1 = require("react");
|
|
26
|
+
var Modal_1 = require("@shopify/app-bridge/actions/Modal");
|
|
27
|
+
var transformers_1 = require("../../utilities/transformers");
|
|
28
|
+
var useAppBridge_1 = require("../../useAppBridge");
|
|
29
|
+
/**
|
|
30
|
+
* Modal component
|
|
31
|
+
*
|
|
32
|
+
* @remarks
|
|
33
|
+
* React component which wraps the Shopify App Bridge Modal action.
|
|
34
|
+
*
|
|
35
|
+
* @public
|
|
36
|
+
*/
|
|
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;
|
|
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
|
+
*/
|
|
71
|
+
if (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
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
modal.set(transformedProps, shouldSendUpdate);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (openUpdated) {
|
|
86
|
+
if (open) {
|
|
87
|
+
modal.dispatch(Modal_1.Action.OPEN);
|
|
88
|
+
focusReturnPoint.current = document.activeElement;
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
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
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
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
|
+
}
|
|
116
|
+
function isIframeModal(options) {
|
|
117
|
+
return (typeof options.url === 'string' ||
|
|
118
|
+
typeof options.path === 'string');
|
|
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
|
+
}
|
|
139
|
+
exports.default = Modal;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { AppBridgeContext } from '../../../context';
|
|
3
|
+
export interface Props {
|
|
4
|
+
/** Show/Dismiss loading spinner */
|
|
5
|
+
loading: boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Modal Content component
|
|
9
|
+
*
|
|
10
|
+
* @remarks
|
|
11
|
+
* React component which wraps the Shopify App Bridge Modal Content action.
|
|
12
|
+
*
|
|
13
|
+
* @public
|
|
14
|
+
*/
|
|
15
|
+
declare class ModalContent extends React.Component<Props> {
|
|
16
|
+
static contextType: React.Context<import("../../../context").IAppBridgeContext>;
|
|
17
|
+
context: React.ContextType<typeof AppBridgeContext>;
|
|
18
|
+
private modalContent;
|
|
19
|
+
componentDidMount(): void;
|
|
20
|
+
componentDidUpdate(): void;
|
|
21
|
+
syncLoadingStatus(): void;
|
|
22
|
+
render(): null;
|
|
23
|
+
}
|
|
24
|
+
export default ModalContent;
|