@shopify/app-bridge-react 4.1.7 → 4.1.9

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.
Files changed (49) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/build/cjs/components/Modal.cjs +104 -0
  3. package/build/cjs/components/NavMenu.cjs +13 -0
  4. package/build/cjs/components/SaveBar.cjs +67 -0
  5. package/build/cjs/components/TitleBar.cjs +14 -0
  6. package/build/cjs/hooks/useAppBridge.cjs +49 -0
  7. package/build/cjs/index.cjs +17 -0
  8. package/build/esm/components/Modal.js +96 -0
  9. package/build/esm/components/NavMenu.js +9 -0
  10. package/build/esm/components/SaveBar.js +63 -0
  11. package/build/esm/components/TitleBar.js +10 -0
  12. package/build/esm/hooks/useAppBridge.js +45 -0
  13. package/build/esm/index.js +5 -0
  14. package/build/esnext/components/Modal.esnext +96 -0
  15. package/build/esnext/components/NavMenu.esnext +9 -0
  16. package/build/esnext/components/SaveBar.esnext +63 -0
  17. package/build/esnext/components/TitleBar.esnext +10 -0
  18. package/build/esnext/hooks/useAppBridge.esnext +45 -0
  19. package/build/esnext/index.esnext +5 -0
  20. package/build/types/cjs/components/Modal.d.cts +38 -0
  21. package/build/types/cjs/components/Modal.d.cts.map +1 -0
  22. package/build/types/cjs/components/NavMenu.d.cts +23 -0
  23. package/build/types/cjs/components/NavMenu.d.cts.map +1 -0
  24. package/build/types/cjs/components/SaveBar.d.cts +37 -0
  25. package/build/types/cjs/components/SaveBar.d.cts.map +1 -0
  26. package/build/types/cjs/components/TitleBar.d.cts +24 -0
  27. package/build/types/cjs/components/TitleBar.d.cts.map +1 -0
  28. package/build/types/cjs/hooks/useAppBridge.d.cts +28 -0
  29. package/build/types/cjs/hooks/useAppBridge.d.cts.map +1 -0
  30. package/build/types/cjs/index.d.cts +12 -0
  31. package/build/types/cjs/index.d.cts.map +1 -0
  32. package/build/types/esm/components/Modal.d.ts +38 -0
  33. package/build/types/esm/components/Modal.d.ts.map +1 -0
  34. package/build/types/esm/components/NavMenu.d.ts +23 -0
  35. package/build/types/esm/components/NavMenu.d.ts.map +1 -0
  36. package/build/types/esm/components/SaveBar.d.ts +37 -0
  37. package/build/types/esm/components/SaveBar.d.ts.map +1 -0
  38. package/build/types/esm/components/TitleBar.d.ts +24 -0
  39. package/build/types/esm/components/TitleBar.d.ts.map +1 -0
  40. package/build/types/esm/hooks/useAppBridge.d.ts +28 -0
  41. package/build/types/esm/hooks/useAppBridge.d.ts.map +1 -0
  42. package/build/types/esm/index.d.ts +12 -0
  43. package/build/types/esm/index.d.ts.map +1 -0
  44. package/package.json +44 -33
  45. package/dist/index.cjs +0 -28
  46. package/dist/index.cjs.map +0 -1
  47. package/dist/index.d.ts +0 -115
  48. package/dist/index.js +0 -740
  49. package/dist/index.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.1.9
4
+
5
+ ### Patch Changes
6
+
7
+ - [#383](https://github.com/Shopify/extensibility/pull/383) [`699da8fa064a60883caea326804b0a5b309e5c00`](https://github.com/Shopify/extensibility/commit/699da8fa064a60883caea326804b0a5b309e5c00) Thanks [@henrytao-me](https://github.com/henrytao-me)! - Fix build tools for app-bridge-react and all extensibility packages to support both ESM and CommonJS build output
8
+
9
+ ## 4.1.8
10
+
11
+ ### Patch Changes
12
+
13
+ - [#325](https://github.com/Shopify/extensibility/pull/325) [`dfac2e4a775102b81488155dc4b00c8132988a22`](https://github.com/Shopify/extensibility/commit/dfac2e4a775102b81488155dc4b00c8132988a22) Thanks [@elanalynn](https://github.com/elanalynn)! - Expose ResourcePicker and Toast types
14
+
15
+ - Updated dependencies [[`dfac2e4a775102b81488155dc4b00c8132988a22`](https://github.com/Shopify/extensibility/commit/dfac2e4a775102b81488155dc4b00c8132988a22)]:
16
+ - @shopify/app-bridge-types@0.0.18
17
+
3
18
  ## 4.1.7
4
19
 
5
20
  ### Patch Changes
@@ -0,0 +1,104 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var react = require('react');
6
+ var ReactDOM = require('react-dom');
7
+ var jsxRuntime = require('react/jsx-runtime');
8
+
9
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
+
11
+ var ReactDOM__default = /*#__PURE__*/_interopDefault(ReactDOM);
12
+
13
+ /**
14
+ * This component is a wrapper around the App Bridge `ui-modal` element.
15
+ * It is used to display an overlay that prevents interaction with the
16
+ * rest of the app until dismissed.
17
+ *
18
+ * @see {@link https://shopify.dev/docs/api/app-bridge-library/react-components/modal}
19
+ */
20
+ const Modal = /*#__PURE__*/react.forwardRef(function InternalModal({
21
+ open,
22
+ onShow,
23
+ onHide,
24
+ children,
25
+ ...rest
26
+ }, forwardedRef) {
27
+ const [modal, setModal] = react.useState();
28
+ const {
29
+ titleBar,
30
+ saveBar,
31
+ modalContent
32
+ } = react.Children.toArray(children).reduce((acc, node) => {
33
+ const nodeName = getNodeName(node);
34
+ const isTitleBar = nodeName === 'ui-title-bar';
35
+ const isSaveBar = nodeName === 'ui-save-bar';
36
+ const belongToModalContent = !isTitleBar && !isSaveBar;
37
+ if (belongToModalContent) {
38
+ acc.modalContent.push(node);
39
+ }
40
+ return {
41
+ ...acc,
42
+ titleBar: isTitleBar ? node : acc.titleBar,
43
+ saveBar: isSaveBar ? node : acc.saveBar
44
+ };
45
+ }, {
46
+ modalContent: []
47
+ });
48
+ const contentPortal = modal && modal.content ? /*#__PURE__*/ReactDOM__default.default.createPortal(modalContent, modal.content) : null;
49
+ react.useEffect(() => {
50
+ if (!modal) return;
51
+ if (open) {
52
+ modal.show();
53
+ } else {
54
+ modal.hide();
55
+ }
56
+ }, [modal, open]);
57
+ react.useEffect(() => {
58
+ if (!modal || !onShow) return;
59
+ modal.addEventListener('show', onShow);
60
+ return () => {
61
+ modal.removeEventListener('show', onShow);
62
+ };
63
+ }, [modal, onShow]);
64
+ react.useEffect(() => {
65
+ if (!modal || !onHide) return;
66
+ modal.addEventListener('hide', onHide);
67
+ return () => {
68
+ modal.removeEventListener('hide', onHide);
69
+ };
70
+ }, [modal, onHide]);
71
+ react.useEffect(() => {
72
+ if (!modal) return;
73
+ return () => {
74
+ modal.hide();
75
+ };
76
+ }, [modal]);
77
+ return /*#__PURE__*/jsxRuntime.jsxs("ui-modal", {
78
+ ...rest,
79
+ ref: modal => {
80
+ setModal(modal);
81
+ if (forwardedRef) {
82
+ if (typeof forwardedRef === 'function') {
83
+ forwardedRef(modal);
84
+ } else {
85
+ forwardedRef.current = modal;
86
+ }
87
+ }
88
+ },
89
+ children: [titleBar, saveBar, /*#__PURE__*/jsxRuntime.jsx("div", {
90
+ children: contentPortal
91
+ })]
92
+ });
93
+ });
94
+ Modal.displayName = 'ui-modal';
95
+ function getNodeName(node) {
96
+ if (!node) return;
97
+ const rawNodeType = typeof node === 'object' && 'type' in node ? node.type : undefined;
98
+ const nodeType = typeof rawNodeType === 'string' ? rawNodeType : undefined;
99
+ const rawDisplayName = typeof rawNodeType === 'object' ? rawNodeType.displayName : undefined;
100
+ const displayName = typeof rawDisplayName === 'string' ? rawDisplayName : undefined;
101
+ return nodeType || displayName;
102
+ }
103
+
104
+ exports.Modal = Modal;
@@ -0,0 +1,13 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ /**
6
+ * This component is a wrapper around the App Bridge `ui-nav-menu` element.
7
+ * It is used to create a navigation menu for your app.
8
+ *
9
+ * @see {@link https://shopify.dev/docs/api/app-bridge-library/react-components/navmenu}
10
+ */
11
+ const NavMenu = 'ui-nav-menu';
12
+
13
+ exports.NavMenu = NavMenu;
@@ -0,0 +1,67 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var react = require('react');
6
+ var jsxRuntime = require('react/jsx-runtime');
7
+
8
+ /**
9
+ * This component is a wrapper around the App Bridge `ui-save-bar` element.
10
+ * It is used to display a contextual save bar to signal dirty state in the app.
11
+ *
12
+ * @see {@link https://shopify.dev/docs/api/app-bridge-library/react-components/save-bar}
13
+ */
14
+ const SaveBar = /*#__PURE__*/react.forwardRef(function InternalSaveBar({
15
+ open,
16
+ onShow,
17
+ onHide,
18
+ children,
19
+ ...rest
20
+ }, forwardedRef) {
21
+ const [saveBar, setSaveBar] = react.useState();
22
+ react.useEffect(() => {
23
+ if (!saveBar) return;
24
+ if (open) {
25
+ saveBar.show();
26
+ } else {
27
+ saveBar.hide();
28
+ }
29
+ }, [saveBar, open]);
30
+ react.useEffect(() => {
31
+ if (!saveBar || !onShow) return;
32
+ saveBar.addEventListener('show', onShow);
33
+ return () => {
34
+ saveBar.removeEventListener('show', onShow);
35
+ };
36
+ }, [saveBar, onShow]);
37
+ react.useEffect(() => {
38
+ if (!saveBar || !onHide) return;
39
+ saveBar.addEventListener('hide', onHide);
40
+ return () => {
41
+ saveBar.removeEventListener('hide', onHide);
42
+ };
43
+ }, [saveBar, onHide]);
44
+ react.useEffect(() => {
45
+ if (!saveBar) return;
46
+ return () => {
47
+ saveBar.hide();
48
+ };
49
+ }, [saveBar]);
50
+ return /*#__PURE__*/jsxRuntime.jsx("ui-save-bar", {
51
+ ...rest,
52
+ ref: saveBar => {
53
+ setSaveBar(saveBar);
54
+ if (forwardedRef) {
55
+ if (typeof forwardedRef === 'function') {
56
+ forwardedRef(saveBar);
57
+ } else {
58
+ forwardedRef.current = saveBar;
59
+ }
60
+ }
61
+ },
62
+ children: children
63
+ });
64
+ });
65
+ SaveBar.displayName = 'ui-save-bar';
66
+
67
+ exports.SaveBar = SaveBar;
@@ -0,0 +1,14 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ /**
6
+ * This component is a wrapper around the App Bridge `ui-title-bar` element.
7
+ * It is used to to populate the app title bar with button actions or the
8
+ * modal header and footer when used within the Modal component.
9
+ *
10
+ * @see {@link https://shopify.dev/docs/api/app-bridge-library/react-components/titlebar}
11
+ */
12
+ const TitleBar = 'ui-title-bar';
13
+
14
+ exports.TitleBar = TitleBar;
@@ -0,0 +1,49 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ /**
6
+ * This proxy is used to throw a helpful error message when trying to access
7
+ * the `shopify` global in a server environment.
8
+ */
9
+ const serverProxy = new Proxy({}, {
10
+ get(_, prop) {
11
+ throw Error(`shopify.${String(prop)} can't be used in a server environment. You likely need to move this code into an Effect.`);
12
+ }
13
+ });
14
+
15
+ /**
16
+ *
17
+ * This hook returns the `shopify` global variable to use
18
+ * App Bridge APIs such as `toast` and `resourcePicker`.
19
+ *
20
+ * @see {@link https://shopify.dev/docs/api/app-bridge-library/react-hooks/useappbridge}
21
+ *
22
+ * @example
23
+ * ```jsx
24
+ * import {useAppBridge} from '@shopify/app-bridge-react';
25
+ * function GenerateBlogPostButton() {
26
+ * const shopify = useAppBridge();
27
+ *
28
+ * function generateBlogPost() {
29
+ * // Handle generating
30
+ * shopify.toast.show('Blog post template generated');
31
+ * }
32
+ *
33
+ * return <button onClick={generateBlogPost}>Generate Blog Post</button>;
34
+ * }
35
+ * ```
36
+ *
37
+ * @returns `shopify` variable or a Proxy that throws when incorrectly accessed when not in a browser context
38
+ */
39
+ function useAppBridge() {
40
+ if (typeof window === 'undefined') {
41
+ return serverProxy;
42
+ }
43
+ if (!window.shopify) {
44
+ throw Error('The shopify global is not defined. This likely means the App Bridge script tag was not added correctly to this page');
45
+ }
46
+ return window.shopify;
47
+ }
48
+
49
+ exports.useAppBridge = useAppBridge;
@@ -0,0 +1,17 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var components_Modal = require('./components/Modal.cjs');
6
+ var components_NavMenu = require('./components/NavMenu.cjs');
7
+ var components_TitleBar = require('./components/TitleBar.cjs');
8
+ var components_SaveBar = require('./components/SaveBar.cjs');
9
+ var hooks_useAppBridge = require('./hooks/useAppBridge.cjs');
10
+
11
+
12
+
13
+ exports.Modal = components_Modal.Modal;
14
+ exports.NavMenu = components_NavMenu.NavMenu;
15
+ exports.TitleBar = components_TitleBar.TitleBar;
16
+ exports.SaveBar = components_SaveBar.SaveBar;
17
+ exports.useAppBridge = hooks_useAppBridge.useAppBridge;
@@ -0,0 +1,96 @@
1
+ import { forwardRef, useState, Children, useEffect } from 'react';
2
+ import ReactDOM from 'react-dom';
3
+ import { jsxs, jsx } from 'react/jsx-runtime';
4
+
5
+ /**
6
+ * This component is a wrapper around the App Bridge `ui-modal` element.
7
+ * It is used to display an overlay that prevents interaction with the
8
+ * rest of the app until dismissed.
9
+ *
10
+ * @see {@link https://shopify.dev/docs/api/app-bridge-library/react-components/modal}
11
+ */
12
+ const Modal = /*#__PURE__*/forwardRef(function InternalModal({
13
+ open,
14
+ onShow,
15
+ onHide,
16
+ children,
17
+ ...rest
18
+ }, forwardedRef) {
19
+ const [modal, setModal] = useState();
20
+ const {
21
+ titleBar,
22
+ saveBar,
23
+ modalContent
24
+ } = Children.toArray(children).reduce((acc, node) => {
25
+ const nodeName = getNodeName(node);
26
+ const isTitleBar = nodeName === 'ui-title-bar';
27
+ const isSaveBar = nodeName === 'ui-save-bar';
28
+ const belongToModalContent = !isTitleBar && !isSaveBar;
29
+ if (belongToModalContent) {
30
+ acc.modalContent.push(node);
31
+ }
32
+ return {
33
+ ...acc,
34
+ titleBar: isTitleBar ? node : acc.titleBar,
35
+ saveBar: isSaveBar ? node : acc.saveBar
36
+ };
37
+ }, {
38
+ modalContent: []
39
+ });
40
+ const contentPortal = modal && modal.content ? /*#__PURE__*/ReactDOM.createPortal(modalContent, modal.content) : null;
41
+ useEffect(() => {
42
+ if (!modal) return;
43
+ if (open) {
44
+ modal.show();
45
+ } else {
46
+ modal.hide();
47
+ }
48
+ }, [modal, open]);
49
+ useEffect(() => {
50
+ if (!modal || !onShow) return;
51
+ modal.addEventListener('show', onShow);
52
+ return () => {
53
+ modal.removeEventListener('show', onShow);
54
+ };
55
+ }, [modal, onShow]);
56
+ useEffect(() => {
57
+ if (!modal || !onHide) return;
58
+ modal.addEventListener('hide', onHide);
59
+ return () => {
60
+ modal.removeEventListener('hide', onHide);
61
+ };
62
+ }, [modal, onHide]);
63
+ useEffect(() => {
64
+ if (!modal) return;
65
+ return () => {
66
+ modal.hide();
67
+ };
68
+ }, [modal]);
69
+ return /*#__PURE__*/jsxs("ui-modal", {
70
+ ...rest,
71
+ ref: modal => {
72
+ setModal(modal);
73
+ if (forwardedRef) {
74
+ if (typeof forwardedRef === 'function') {
75
+ forwardedRef(modal);
76
+ } else {
77
+ forwardedRef.current = modal;
78
+ }
79
+ }
80
+ },
81
+ children: [titleBar, saveBar, /*#__PURE__*/jsx("div", {
82
+ children: contentPortal
83
+ })]
84
+ });
85
+ });
86
+ Modal.displayName = 'ui-modal';
87
+ function getNodeName(node) {
88
+ if (!node) return;
89
+ const rawNodeType = typeof node === 'object' && 'type' in node ? node.type : undefined;
90
+ const nodeType = typeof rawNodeType === 'string' ? rawNodeType : undefined;
91
+ const rawDisplayName = typeof rawNodeType === 'object' ? rawNodeType.displayName : undefined;
92
+ const displayName = typeof rawDisplayName === 'string' ? rawDisplayName : undefined;
93
+ return nodeType || displayName;
94
+ }
95
+
96
+ export { Modal };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * This component is a wrapper around the App Bridge `ui-nav-menu` element.
3
+ * It is used to create a navigation menu for your app.
4
+ *
5
+ * @see {@link https://shopify.dev/docs/api/app-bridge-library/react-components/navmenu}
6
+ */
7
+ const NavMenu = 'ui-nav-menu';
8
+
9
+ export { NavMenu };
@@ -0,0 +1,63 @@
1
+ import { forwardRef, useState, useEffect } from 'react';
2
+ import { jsx } from 'react/jsx-runtime';
3
+
4
+ /**
5
+ * This component is a wrapper around the App Bridge `ui-save-bar` element.
6
+ * It is used to display a contextual save bar to signal dirty state in the app.
7
+ *
8
+ * @see {@link https://shopify.dev/docs/api/app-bridge-library/react-components/save-bar}
9
+ */
10
+ const SaveBar = /*#__PURE__*/forwardRef(function InternalSaveBar({
11
+ open,
12
+ onShow,
13
+ onHide,
14
+ children,
15
+ ...rest
16
+ }, forwardedRef) {
17
+ const [saveBar, setSaveBar] = useState();
18
+ useEffect(() => {
19
+ if (!saveBar) return;
20
+ if (open) {
21
+ saveBar.show();
22
+ } else {
23
+ saveBar.hide();
24
+ }
25
+ }, [saveBar, open]);
26
+ useEffect(() => {
27
+ if (!saveBar || !onShow) return;
28
+ saveBar.addEventListener('show', onShow);
29
+ return () => {
30
+ saveBar.removeEventListener('show', onShow);
31
+ };
32
+ }, [saveBar, onShow]);
33
+ useEffect(() => {
34
+ if (!saveBar || !onHide) return;
35
+ saveBar.addEventListener('hide', onHide);
36
+ return () => {
37
+ saveBar.removeEventListener('hide', onHide);
38
+ };
39
+ }, [saveBar, onHide]);
40
+ useEffect(() => {
41
+ if (!saveBar) return;
42
+ return () => {
43
+ saveBar.hide();
44
+ };
45
+ }, [saveBar]);
46
+ return /*#__PURE__*/jsx("ui-save-bar", {
47
+ ...rest,
48
+ ref: saveBar => {
49
+ setSaveBar(saveBar);
50
+ if (forwardedRef) {
51
+ if (typeof forwardedRef === 'function') {
52
+ forwardedRef(saveBar);
53
+ } else {
54
+ forwardedRef.current = saveBar;
55
+ }
56
+ }
57
+ },
58
+ children: children
59
+ });
60
+ });
61
+ SaveBar.displayName = 'ui-save-bar';
62
+
63
+ export { SaveBar };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * This component is a wrapper around the App Bridge `ui-title-bar` element.
3
+ * It is used to to populate the app title bar with button actions or the
4
+ * modal header and footer when used within the Modal component.
5
+ *
6
+ * @see {@link https://shopify.dev/docs/api/app-bridge-library/react-components/titlebar}
7
+ */
8
+ const TitleBar = 'ui-title-bar';
9
+
10
+ export { TitleBar };
@@ -0,0 +1,45 @@
1
+ /**
2
+ * This proxy is used to throw a helpful error message when trying to access
3
+ * the `shopify` global in a server environment.
4
+ */
5
+ const serverProxy = new Proxy({}, {
6
+ get(_, prop) {
7
+ throw Error(`shopify.${String(prop)} can't be used in a server environment. You likely need to move this code into an Effect.`);
8
+ }
9
+ });
10
+
11
+ /**
12
+ *
13
+ * This hook returns the `shopify` global variable to use
14
+ * App Bridge APIs such as `toast` and `resourcePicker`.
15
+ *
16
+ * @see {@link https://shopify.dev/docs/api/app-bridge-library/react-hooks/useappbridge}
17
+ *
18
+ * @example
19
+ * ```jsx
20
+ * import {useAppBridge} from '@shopify/app-bridge-react';
21
+ * function GenerateBlogPostButton() {
22
+ * const shopify = useAppBridge();
23
+ *
24
+ * function generateBlogPost() {
25
+ * // Handle generating
26
+ * shopify.toast.show('Blog post template generated');
27
+ * }
28
+ *
29
+ * return <button onClick={generateBlogPost}>Generate Blog Post</button>;
30
+ * }
31
+ * ```
32
+ *
33
+ * @returns `shopify` variable or a Proxy that throws when incorrectly accessed when not in a browser context
34
+ */
35
+ function useAppBridge() {
36
+ if (typeof window === 'undefined') {
37
+ return serverProxy;
38
+ }
39
+ if (!window.shopify) {
40
+ throw Error('The shopify global is not defined. This likely means the App Bridge script tag was not added correctly to this page');
41
+ }
42
+ return window.shopify;
43
+ }
44
+
45
+ export { useAppBridge };
@@ -0,0 +1,5 @@
1
+ export { Modal } from './components/Modal.js';
2
+ export { NavMenu } from './components/NavMenu.js';
3
+ export { TitleBar } from './components/TitleBar.js';
4
+ export { SaveBar } from './components/SaveBar.js';
5
+ export { useAppBridge } from './hooks/useAppBridge.js';
@@ -0,0 +1,96 @@
1
+ import { forwardRef, useState, Children, useEffect } from 'react';
2
+ import ReactDOM from 'react-dom';
3
+ import { jsxs, jsx } from 'react/jsx-runtime';
4
+
5
+ /**
6
+ * This component is a wrapper around the App Bridge `ui-modal` element.
7
+ * It is used to display an overlay that prevents interaction with the
8
+ * rest of the app until dismissed.
9
+ *
10
+ * @see {@link https://shopify.dev/docs/api/app-bridge-library/react-components/modal}
11
+ */
12
+ const Modal = /*#__PURE__*/forwardRef(function InternalModal({
13
+ open,
14
+ onShow,
15
+ onHide,
16
+ children,
17
+ ...rest
18
+ }, forwardedRef) {
19
+ const [modal, setModal] = useState();
20
+ const {
21
+ titleBar,
22
+ saveBar,
23
+ modalContent
24
+ } = Children.toArray(children).reduce((acc, node) => {
25
+ const nodeName = getNodeName(node);
26
+ const isTitleBar = nodeName === 'ui-title-bar';
27
+ const isSaveBar = nodeName === 'ui-save-bar';
28
+ const belongToModalContent = !isTitleBar && !isSaveBar;
29
+ if (belongToModalContent) {
30
+ acc.modalContent.push(node);
31
+ }
32
+ return {
33
+ ...acc,
34
+ titleBar: isTitleBar ? node : acc.titleBar,
35
+ saveBar: isSaveBar ? node : acc.saveBar
36
+ };
37
+ }, {
38
+ modalContent: []
39
+ });
40
+ const contentPortal = modal && modal.content ? /*#__PURE__*/ReactDOM.createPortal(modalContent, modal.content) : null;
41
+ useEffect(() => {
42
+ if (!modal) return;
43
+ if (open) {
44
+ modal.show();
45
+ } else {
46
+ modal.hide();
47
+ }
48
+ }, [modal, open]);
49
+ useEffect(() => {
50
+ if (!modal || !onShow) return;
51
+ modal.addEventListener('show', onShow);
52
+ return () => {
53
+ modal.removeEventListener('show', onShow);
54
+ };
55
+ }, [modal, onShow]);
56
+ useEffect(() => {
57
+ if (!modal || !onHide) return;
58
+ modal.addEventListener('hide', onHide);
59
+ return () => {
60
+ modal.removeEventListener('hide', onHide);
61
+ };
62
+ }, [modal, onHide]);
63
+ useEffect(() => {
64
+ if (!modal) return;
65
+ return () => {
66
+ modal.hide();
67
+ };
68
+ }, [modal]);
69
+ return /*#__PURE__*/jsxs("ui-modal", {
70
+ ...rest,
71
+ ref: modal => {
72
+ setModal(modal);
73
+ if (forwardedRef) {
74
+ if (typeof forwardedRef === 'function') {
75
+ forwardedRef(modal);
76
+ } else {
77
+ forwardedRef.current = modal;
78
+ }
79
+ }
80
+ },
81
+ children: [titleBar, saveBar, /*#__PURE__*/jsx("div", {
82
+ children: contentPortal
83
+ })]
84
+ });
85
+ });
86
+ Modal.displayName = 'ui-modal';
87
+ function getNodeName(node) {
88
+ if (!node) return;
89
+ const rawNodeType = typeof node === 'object' && 'type' in node ? node.type : undefined;
90
+ const nodeType = typeof rawNodeType === 'string' ? rawNodeType : undefined;
91
+ const rawDisplayName = typeof rawNodeType === 'object' ? rawNodeType.displayName : undefined;
92
+ const displayName = typeof rawDisplayName === 'string' ? rawDisplayName : undefined;
93
+ return nodeType || displayName;
94
+ }
95
+
96
+ export { Modal };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * This component is a wrapper around the App Bridge `ui-nav-menu` element.
3
+ * It is used to create a navigation menu for your app.
4
+ *
5
+ * @see {@link https://shopify.dev/docs/api/app-bridge-library/react-components/navmenu}
6
+ */
7
+ const NavMenu = 'ui-nav-menu';
8
+
9
+ export { NavMenu };