@shopify/app-bridge-react 3.1.2 → 3.1.4-alpha.0

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,26 @@
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
+ ## [3.1.4-alpha.0](https://github.com/Shopify/app-bridge/compare/v3.1.3...v3.1.4-alpha.0) (2022-07-21)
7
+
8
+ **Note:** Version bump only for package @shopify/app-bridge-react
9
+
10
+
11
+
12
+
13
+
14
+ ## [3.1.3](https://github.com/Shopify/app-bridge/compare/v3.1.2...v3.1.3) (2022-07-19)
15
+
16
+
17
+ ### Bug Fixes
18
+
19
+ * fix ResourcePicker open state ([78dd608](https://github.com/Shopify/app-bridge/commit/78dd6080643fb9d34ca1f11ab874b88aea45ee78))
20
+ * fix unstable Picker react open state ([3ed048a](https://github.com/Shopify/app-bridge/commit/3ed048ab29a7dbded57f776bd37538b8590af640))
21
+
22
+
23
+
24
+
25
+
6
26
  ## [3.1.2](https://github.com/Shopify/app-bridge/compare/v3.1.1...v3.1.2) (2022-07-13)
7
27
 
8
28
 
@@ -1,56 +1,24 @@
1
1
  import { ActionVerb, ResourceType } from '@shopify/app-bridge/actions/ResourcePicker';
2
2
  import type { BaseResource, Options, ResourceSelection, ProductOptions } from '@shopify/app-bridge/actions/ResourcePicker';
3
3
  export interface SelectPayload {
4
- /** The selected resources
5
- * @see {@link https://help.shopify.com/en/api/embedded-apps/app-bridge/actions/resourcepicker|resource picker documentation} for more information
6
- */
7
4
  selection: ResourceSelection[];
8
5
  }
9
- interface BaseProps {
10
- /** Whether the picker is open or not */
6
+ interface BaseProps extends Options {
11
7
  open: boolean;
12
- /** GraphQL initial search query for filtering resources available in the picker
13
- * @see {@link https://help.shopify.com/en/api/getting-started/search-syntax|search syntax} for more information
14
- */
15
- initialQuery?: string;
16
- /** Resources that should already be selected when the picker is opened */
17
- initialSelectionIds?: BaseResource[];
18
- /** Show products that are not published on the Online Store */
19
- showHidden?: boolean;
20
8
  /**
21
9
  * @deprecated as of 1.28.0
22
10
  */
23
- /** Whether to allow selection of multiple items */
24
11
  allowMultiple?: boolean;
25
- /** Whether to allow selection of multiple items, or the maximum number of selected items */
26
- selectMultiple?: boolean | number;
27
- /** Override default action verb `Add`. The actionVerb appears in the title `<actionVerb>` `<resourceType>` and as the primary action of the resource picker. */
28
- actionVerb?: ActionVerb;
29
- /** Callback when a selection has been made */
30
12
  onSelection?(selectPayload: SelectPayload): void;
31
- /** Callback when the picker is closed without selection */
32
13
  onCancel?(): void;
33
14
  }
34
- export interface ProductPickerProps extends BaseProps {
35
- /** The type of resource you want to pick */
15
+ export interface ProductPickerProps extends BaseProps, ProductOptions {
36
16
  resourceType: 'Product';
37
- /** Whether to show product variants or not. Only applies to the product resource type picker */
38
- showVariants?: boolean;
39
- /** Whether to show draft products or not. Only applies to the product resource type picker */
40
- showDraft?: boolean;
41
- /** Whether to show archived products or not. Only applies to the product resource type picker */
42
- showArchived?: boolean;
43
- /** Whether to show draft badge for draft products or not. Only works when `showDraft` prop is set, and only applies to the product resource type picker */
44
- showDraftBadge?: boolean;
45
- /** Whether to show archived badge for archived products or not. Only works when `showArchived` prop is set, and only applies to the product resource type picker */
46
- showArchivedBadge?: boolean;
47
17
  }
48
18
  export interface ProductVariantProps extends BaseProps {
49
- /** The type of resource you want to pick */
50
19
  resourceType: 'ProductVariant';
51
20
  }
52
21
  export interface CollectionPickerProps extends BaseProps {
53
- /** The type of resource you want to pick */
54
22
  resourceType: 'Collection';
55
23
  }
56
24
  export declare type Props = ProductPickerProps | ProductVariantProps | CollectionPickerProps;
@@ -62,7 +30,7 @@ export declare type Props = ProductPickerProps | ProductVariantProps | Collectio
62
30
  *
63
31
  * @public
64
32
  */
65
- declare function ResourcePicker(props: Props): null;
33
+ declare function ResourcePicker({ open, resourceType, onSelection, onCancel, allowMultiple, selectMultiple, ...props }: Props): null;
66
34
  export default ResourcePicker;
67
35
  export type { BaseResource, Options, ProductOptions };
68
36
  export { ActionVerb, ResourceType };
@@ -10,6 +10,17 @@ var __assign = (this && this.__assign) || function () {
10
10
  };
11
11
  return __assign.apply(this, arguments);
12
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
+ };
13
24
  Object.defineProperty(exports, "__esModule", { value: true });
14
25
  exports.ResourceType = exports.ActionVerb = void 0;
15
26
  var react_1 = require("react");
@@ -25,90 +36,85 @@ var useAppBridge_1 = require("../../useAppBridge");
25
36
  *
26
37
  * @public
27
38
  */
28
- function ResourcePicker(props) {
39
+ function ResourcePicker(_a) {
40
+ var open = _a.open, resourceType = _a.resourceType, onSelection = _a.onSelection, onCancel = _a.onCancel, allowMultiple = _a.allowMultiple, selectMultiple = _a.selectMultiple, props = __rest(_a, ["open", "resourceType", "onSelection", "onCancel", "allowMultiple", "selectMultiple"]);
41
+ var options = react_1.useMemo(function () { return (__assign(__assign({}, props), { selectMultiple: selectMultiple !== null && selectMultiple !== void 0 ? selectMultiple : allowMultiple })); }, [allowMultiple, props, selectMultiple]);
29
42
  var app = useAppBridge_1.useAppBridge();
30
- var focusReturnPoint = react_1.useRef(null);
31
- var resourceType = props.resourceType, onSelection = props.onSelection, onCancel = props.onCancel, open = props.open;
32
- // Initialize with open: false so the open action will dispatch on initial load
33
- var prevProps = react_1.useRef({ open: false });
43
+ var isUnmountedRef = react_1.useRef(false);
44
+ react_1.useEffect(function () { return function () {
45
+ isUnmountedRef.current = true;
46
+ }; }, []);
47
+ var openRef = react_1.useRef(false);
48
+ var optionsRef = react_1.useRef(options);
34
49
  var picker = react_1.useMemo(function () {
35
50
  return ResourcePicker_1.create(app, {
36
51
  resourceType: ResourcePicker_1.ResourceType[resourceType],
37
- options: getActionOptions(props),
52
+ options: optionsRef.current,
38
53
  });
39
- // We purposely want to reuse the same picker instance
40
- // and use a useEffect to call `picker.set` when needed
41
- }, [app]);
54
+ }, [app, resourceType]);
42
55
  react_1.useEffect(function () {
43
- var _a;
44
- var wasOpen = (_a = prevProps.current) === null || _a === void 0 ? void 0 : _a.open;
45
- if (wasOpen !== open) {
46
- if (open) {
47
- picker.dispatch(ResourcePicker_1.Action.OPEN);
48
- }
49
- else {
50
- picker.dispatch(ResourcePicker_1.Action.CLOSE);
56
+ openRef.current = false;
57
+ return function () {
58
+ if (openRef.current && isUnmountedRef.current) {
59
+ picker.dispatch(ResourcePicker_1.Action.CANCEL);
51
60
  }
61
+ };
62
+ }, [picker]);
63
+ var focusReturnPointRef = react_1.useRef(null);
64
+ var storeFocusReturnPoint = react_1.useCallback(function () {
65
+ if (document.activeElement instanceof HTMLElement) {
66
+ focusReturnPointRef.current = document.activeElement;
52
67
  }
53
- if (!wasOpen && open) {
54
- focusReturnPoint.current = document.activeElement;
55
- }
56
- else if (wasOpen &&
57
- !open &&
58
- focusReturnPoint.current != null &&
59
- document.contains(focusReturnPoint.current)) {
60
- focusReturnPoint.current.focus();
61
- focusReturnPoint.current = null;
68
+ }, []);
69
+ var applyFocusReturnPoint = react_1.useCallback(function () {
70
+ var focusReturnPoint = focusReturnPointRef.current;
71
+ focusReturnPointRef.current = null;
72
+ if (focusReturnPoint && document.contains(focusReturnPoint)) {
73
+ focusReturnPoint.focus();
62
74
  }
63
- }, [open]);
75
+ }, []);
64
76
  react_1.useEffect(function () {
65
- var unsubscribeList = [];
66
- if (onSelection != null) {
67
- unsubscribeList.push(picker.subscribe(ResourcePicker_1.Action.SELECT, onSelection));
77
+ if (open === openRef.current)
78
+ return;
79
+ openRef.current = open;
80
+ if (open) {
81
+ picker.dispatch(ResourcePicker_1.Action.OPEN);
82
+ storeFocusReturnPoint();
68
83
  }
69
- if (onCancel != null) {
70
- unsubscribeList.push(picker.subscribe(ResourcePicker_1.Action.CANCEL, onCancel));
84
+ else {
85
+ picker.dispatch(ResourcePicker_1.Action.CLOSE);
86
+ applyFocusReturnPoint();
71
87
  }
72
- return function () {
73
- var unsubscribe = unsubscribeList.pop();
74
- while (unsubscribe) {
75
- unsubscribe();
76
- unsubscribe = unsubscribeList.pop();
88
+ }, [picker, open, storeFocusReturnPoint, applyFocusReturnPoint]);
89
+ react_1.useEffect(function () {
90
+ if (!onSelection)
91
+ return;
92
+ return picker.subscribe(ResourcePicker_1.Action.SELECT, function () {
93
+ var args = [];
94
+ for (var _i = 0; _i < arguments.length; _i++) {
95
+ args[_i] = arguments[_i];
77
96
  }
78
- };
79
- }, [onSelection, onCancel]);
97
+ openRef.current = false;
98
+ applyFocusReturnPoint();
99
+ return onSelection.apply(void 0, args);
100
+ });
101
+ }, [picker, onSelection, applyFocusReturnPoint]);
80
102
  react_1.useEffect(function () {
81
- var shouldUpdate = JSON.stringify(__assign(__assign({}, prevProps.current), { open: undefined })) !==
82
- JSON.stringify(__assign(__assign({}, props), { open: undefined }));
83
- if (!shouldUpdate) {
103
+ if (!onCancel)
84
104
  return;
85
- }
86
- picker.set(getActionOptions(props));
87
- prevProps.current = props;
88
- }, [props]);
105
+ return picker.subscribe(ResourcePicker_1.Action.CANCEL, function () {
106
+ openRef.current = false;
107
+ applyFocusReturnPoint();
108
+ return onCancel();
109
+ });
110
+ }, [picker, onCancel, applyFocusReturnPoint]);
111
+ react_1.useEffect(function () {
112
+ var shouldUpdate = JSON.stringify(options) !== JSON.stringify(optionsRef.current);
113
+ if (!shouldUpdate)
114
+ return;
115
+ optionsRef.current = options;
116
+ picker.set(options);
117
+ }, [picker, options]);
89
118
  return null;
90
119
  }
91
- function getActionOptions(props) {
92
- var initialQuery = props.initialQuery, initialSelectionIds = props.initialSelectionIds, showHidden = props.showHidden, allowMultiple = props.allowMultiple, selectMultiple = props.selectMultiple, actionVerb = props.actionVerb;
93
- var sharedOptions = {
94
- initialQuery: initialQuery,
95
- initialSelectionIds: initialSelectionIds,
96
- showHidden: showHidden,
97
- selectMultiple: selectMultiple !== null && selectMultiple !== void 0 ? selectMultiple : allowMultiple,
98
- actionVerb: actionVerb,
99
- };
100
- var result = sharedOptions;
101
- if (props.resourceType === 'Product') {
102
- var showVariants = props.showVariants, showDraft = props.showDraft, showArchived = props.showArchived, showDraftBadge = props.showDraftBadge, showArchivedBadge = props.showArchivedBadge;
103
- var productSpecificOptions = {
104
- showVariants: showVariants,
105
- showDraft: showDraft,
106
- showArchived: showArchived,
107
- showDraftBadge: showDraftBadge,
108
- showArchivedBadge: showArchivedBadge,
109
- };
110
- result = __assign(__assign({}, sharedOptions), productSpecificOptions);
111
- }
112
- return result;
113
- }
114
120
  exports.default = ResourcePicker;
@@ -1,23 +1,13 @@
1
- import { SearchPayload, SelectPayload, EmptySearchLabel } from '@shopify/app-bridge/actions/Picker';
2
- import type { BaseResource } from '@shopify/app-bridge/actions/Picker';
1
+ import { SearchPayload, SelectPayload } from '@shopify/app-bridge/actions/Picker';
2
+ import type { Options } from '@shopify/app-bridge/actions/Picker';
3
3
  /**
4
4
  * @unstable This API may be updated without warning in the future
5
5
  */
6
- export interface Props {
6
+ export interface Props extends Options {
7
7
  open: boolean;
8
- items: BaseResource[];
9
- selectedItems?: BaseResource[];
10
- maxSelectable?: number;
11
- title?: string;
12
- loading?: boolean;
13
- searchQueryPlaceholder?: string;
14
- searchQuery?: string;
15
- primaryActionLabel?: string;
16
- secondaryActionLabel?: string;
17
- emptySearchLabel?: EmptySearchLabel;
18
8
  onCancel?(): void;
19
9
  onSelect?(selectPayload: SelectPayload): void;
20
10
  onSearch?(searchPayload: SearchPayload): void;
21
11
  onLoadMore?(): void;
22
12
  }
23
- export default function Picker(props: Props): null;
13
+ export default function Picker({ open, onCancel, onSelect, onSearch, onLoadMore, ...options }: Props): null;
@@ -1,85 +1,85 @@
1
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];
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
8
10
  }
9
- return t;
10
- };
11
- return __assign.apply(this, arguments);
11
+ return t;
12
12
  };
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
14
  var react_1 = require("react");
15
15
  var Picker_1 = require("@shopify/app-bridge/actions/Picker");
16
16
  var useAppBridge_1 = require("../../useAppBridge");
17
- function Picker(props) {
17
+ function Picker(_a) {
18
+ var open = _a.open, onCancel = _a.onCancel, onSelect = _a.onSelect, onSearch = _a.onSearch, onLoadMore = _a.onLoadMore, options = __rest(_a, ["open", "onCancel", "onSelect", "onSearch", "onLoadMore"]);
18
19
  var app = useAppBridge_1.useAppBridge();
19
- var prevProps = react_1.useRef({ open: false });
20
- var picker = react_1.useMemo(function () { return Picker_1.create(app, getActionOptions(props)); }, [app]);
20
+ var isUnmountedRef = react_1.useRef(false);
21
+ react_1.useEffect(function () { return function () {
22
+ isUnmountedRef.current = true;
23
+ }; }, []);
24
+ var openRef = react_1.useRef(false);
25
+ var optionsRef = react_1.useRef(options);
26
+ var picker = react_1.useMemo(function () { return Picker_1.create(app, optionsRef.current); }, [app]);
21
27
  react_1.useEffect(function () {
22
- var _a;
23
- if (!props.open && ((_a = prevProps.current) === null || _a === void 0 ? void 0 : _a.open) === props.open) {
28
+ openRef.current = false;
29
+ return function () {
30
+ if (openRef.current && isUnmountedRef.current) {
31
+ picker.dispatch(Picker_1.Action.CANCEL);
32
+ }
33
+ };
34
+ }, [picker]);
35
+ react_1.useEffect(function () {
36
+ if (open === openRef.current)
24
37
  return;
25
- }
26
- if (props.open) {
38
+ openRef.current = open;
39
+ if (open) {
27
40
  picker.dispatch(Picker_1.Action.OPEN);
28
41
  }
29
42
  else {
30
43
  picker.dispatch(Picker_1.Action.CANCEL);
31
44
  }
32
- }, [props.open]);
45
+ }, [picker, open]);
33
46
  react_1.useEffect(function () {
34
- var unsubscribeList = [];
35
- if (props.onSelect) {
36
- unsubscribeList.push(picker.subscribe(Picker_1.Action.SELECT, props.onSelect));
37
- }
38
- if (props.onCancel) {
39
- unsubscribeList.push(picker.subscribe(Picker_1.Action.CANCEL, props.onCancel));
40
- }
41
- if (props.onSearch) {
42
- unsubscribeList.push(picker.subscribe(Picker_1.Action.SEARCH, props.onSearch));
43
- }
44
- if (props.onLoadMore) {
45
- unsubscribeList.push(picker.subscribe(Picker_1.Action.LOAD_MORE, props.onLoadMore));
46
- }
47
- return function () {
48
- unsubscribeList.forEach(function (unsubscribe) { return unsubscribe(); });
49
- };
50
- }, [props.onSelect, props.onCancel, props.onSearch]);
47
+ if (!onSelect)
48
+ return;
49
+ return picker.subscribe(Picker_1.Action.SELECT, function () {
50
+ var args = [];
51
+ for (var _i = 0; _i < arguments.length; _i++) {
52
+ args[_i] = arguments[_i];
53
+ }
54
+ openRef.current = false;
55
+ return onSelect.apply(void 0, args);
56
+ });
57
+ }, [picker, onSelect]);
51
58
  react_1.useEffect(function () {
52
- var shouldUpdate = JSON.stringify(__assign(__assign({}, prevProps.current), { open: undefined })) !==
53
- JSON.stringify(__assign(__assign({}, props), { open: undefined }));
54
- if (!shouldUpdate) {
59
+ if (!onCancel)
55
60
  return;
56
- }
57
- picker.set(getActionOptions(props));
58
- prevProps.current = props;
59
- }, [props]);
61
+ return picker.subscribe(Picker_1.Action.CANCEL, function () {
62
+ openRef.current = false;
63
+ return onCancel();
64
+ });
65
+ }, [picker, onCancel]);
60
66
  react_1.useEffect(function () {
61
- return function () {
62
- if (prevProps.current.open) {
63
- picker.dispatch(Picker_1.Action.CANCEL);
64
- }
65
- };
66
- }, []);
67
+ if (!onSearch)
68
+ return;
69
+ return picker.subscribe(Picker_1.Action.SEARCH, onSearch);
70
+ }, [picker, onSearch]);
71
+ react_1.useEffect(function () {
72
+ if (!onLoadMore)
73
+ return;
74
+ return picker.subscribe(Picker_1.Action.LOAD_MORE, onLoadMore);
75
+ }, [picker, onLoadMore]);
76
+ react_1.useEffect(function () {
77
+ var shouldUpdate = JSON.stringify(options) !== JSON.stringify(optionsRef.current);
78
+ if (!shouldUpdate)
79
+ return;
80
+ optionsRef.current = options;
81
+ picker.set(options);
82
+ }, [picker, options]);
67
83
  return null;
68
84
  }
69
85
  exports.default = Picker;
70
- function getActionOptions(_a) {
71
- var items = _a.items, selectedItems = _a.selectedItems, maxSelectable = _a.maxSelectable, title = _a.title, loading = _a.loading, searchQueryPlaceholder = _a.searchQueryPlaceholder, searchQuery = _a.searchQuery, primaryActionLabel = _a.primaryActionLabel, secondaryActionLabel = _a.secondaryActionLabel, emptySearchLabel = _a.emptySearchLabel;
72
- var result = {
73
- items: items,
74
- selectedItems: selectedItems,
75
- maxSelectable: maxSelectable,
76
- title: title,
77
- loading: loading,
78
- searchQueryPlaceholder: searchQueryPlaceholder,
79
- searchQuery: searchQuery,
80
- primaryActionLabel: primaryActionLabel,
81
- secondaryActionLabel: secondaryActionLabel,
82
- emptySearchLabel: emptySearchLabel,
83
- };
84
- return result;
85
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shopify/app-bridge-react",
3
- "version": "3.1.2",
3
+ "version": "3.1.4-alpha.0",
4
4
  "types": "index.d.ts",
5
5
  "main": "index.js",
6
6
  "unpkg": "umd/index.js",
@@ -45,7 +45,7 @@
45
45
  }
46
46
  ],
47
47
  "dependencies": {
48
- "@shopify/app-bridge": "^3.1.2"
48
+ "@shopify/app-bridge": "^3.1.4-alpha.0"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@types/react": "^17.0.38",
@@ -55,5 +55,5 @@
55
55
  "peerDependencies": {
56
56
  "react": "^16.0.0 || ^17.0.0 || ^18.0.0"
57
57
  },
58
- "gitHead": "a5386e7e082545c893966de5cbf914cc5883a1f1"
58
+ "gitHead": "227b25159a74682d8606fe3591760d886116d286"
59
59
  }