@aws-amplify/ui-react-core 1.0.5 → 2.1.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/dist/esm/Authenticator/context/AuthenticatorContext.js +4 -1
- package/dist/esm/Authenticator/context/AuthenticatorProvider.js +8 -4
- package/dist/esm/Authenticator/hooks/constants.js +26 -0
- package/dist/esm/Authenticator/hooks/useAuthenticator/constants.js +3 -13
- package/dist/esm/Authenticator/hooks/useAuthenticator/useAuthenticator.js +13 -12
- package/dist/esm/Authenticator/hooks/useAuthenticator/utils.js +32 -15
- package/dist/esm/Authenticator/hooks/useAuthenticatorInitMachine/useAuthenticatorInitMachine.js +17 -0
- package/dist/esm/Authenticator/hooks/useAuthenticatorRoute/constants.js +73 -0
- package/dist/esm/Authenticator/hooks/useAuthenticatorRoute/useAuthenticatorRoute.js +52 -0
- package/dist/esm/Authenticator/hooks/useAuthenticatorRoute/utils.js +89 -0
- package/dist/esm/Authenticator/hooks/utils.js +24 -0
- package/dist/esm/InAppMessaging/context/InAppMessagingContext/InAppMessagingContext.js +5 -0
- package/dist/esm/InAppMessaging/context/InAppMessagingProvider/InAppMessagingProvider.js +26 -0
- package/dist/esm/InAppMessaging/hooks/useInAppMessaging/useInAppMessaging.js +19 -0
- package/dist/esm/InAppMessaging/hooks/useMessage/useMessage.js +78 -0
- package/dist/esm/InAppMessaging/hooks/useMessage/utils.js +43 -0
- package/dist/esm/InAppMessaging/utils/handleMessageAction.js +16 -0
- package/dist/esm/components/RenderNothing/RenderNothing.js +8 -0
- package/dist/esm/hooks/useHasValueUpdated.js +13 -0
- package/dist/esm/hooks/usePreviousValue.js +13 -0
- package/dist/esm/index.js +13 -1
- package/dist/esm/node_modules/tslib/tslib.es6.js +38 -0
- package/dist/esm/utils/index.js +5 -2
- package/dist/index.js +638 -6
- package/dist/{esm/Authenticator/hooks/useAuthenticator/types.js → types/Authenticator/context/__tests__/AuthenticatorProvider.test.d.ts} +0 -0
- package/dist/types/Authenticator/hooks/__mock__/components.d.ts +7 -0
- package/dist/types/Authenticator/hooks/__tests__/utils.spec.d.ts +1 -0
- package/dist/types/Authenticator/hooks/constants.d.ts +3 -0
- package/dist/types/Authenticator/hooks/index.d.ts +4 -0
- package/dist/types/Authenticator/hooks/types.d.ts +123 -0
- package/dist/types/Authenticator/hooks/useAuthenticator/__mock__/useAuthenticator.d.ts +4 -0
- package/dist/types/Authenticator/hooks/useAuthenticator/__tests__/useAuthenticator.spec.d.ts +1 -0
- package/dist/types/Authenticator/hooks/useAuthenticator/__tests__/utils.spec.d.ts +1 -0
- package/dist/types/Authenticator/hooks/useAuthenticator/constants.d.ts +0 -2
- package/dist/types/Authenticator/hooks/useAuthenticator/index.d.ts +1 -1
- package/dist/types/Authenticator/hooks/useAuthenticator/types.d.ts +3 -11
- package/dist/types/Authenticator/hooks/useAuthenticator/useAuthenticator.d.ts +2 -2
- package/dist/types/Authenticator/hooks/useAuthenticator/utils.d.ts +7 -6
- package/dist/types/Authenticator/hooks/useAuthenticatorInitMachine/__tests__/useAuthenticatorInitMachine.spec.d.ts +1 -0
- package/dist/types/Authenticator/hooks/useAuthenticatorInitMachine/index.d.ts +1 -0
- package/dist/types/Authenticator/hooks/useAuthenticatorInitMachine/useAuthenticatorInitMachine.d.ts +4 -0
- package/dist/types/Authenticator/hooks/useAuthenticatorRoute/__tests__/useAuthenticatorRoute.spec.d.ts +1 -0
- package/dist/types/Authenticator/hooks/useAuthenticatorRoute/__tests__/utils.spec.d.ts +1 -0
- package/dist/types/Authenticator/hooks/useAuthenticatorRoute/constants.d.ts +4 -0
- package/dist/types/Authenticator/hooks/useAuthenticatorRoute/index.d.ts +2 -0
- package/dist/types/Authenticator/hooks/useAuthenticatorRoute/types.d.ts +38 -0
- package/dist/types/Authenticator/hooks/useAuthenticatorRoute/useAuthenticatorRoute.d.ts +11 -0
- package/dist/types/Authenticator/hooks/useAuthenticatorRoute/utils.d.ts +17 -0
- package/dist/types/Authenticator/hooks/utils.d.ts +4 -0
- package/dist/types/Authenticator/index.d.ts +3 -2
- package/dist/types/InAppMessaging/context/InAppMessagingContext/InAppMessagingContext.d.ts +9 -0
- package/dist/types/InAppMessaging/context/InAppMessagingContext/index.d.ts +1 -0
- package/dist/types/InAppMessaging/context/InAppMessagingProvider/InAppMessagingProvider.d.ts +5 -0
- package/dist/types/InAppMessaging/context/InAppMessagingProvider/__tests__/InAppMessagingProvider.spec.d.ts +1 -0
- package/dist/types/InAppMessaging/context/InAppMessagingProvider/index.d.ts +1 -0
- package/dist/types/InAppMessaging/context/index.d.ts +2 -0
- package/dist/types/InAppMessaging/hooks/index.d.ts +2 -0
- package/dist/types/InAppMessaging/hooks/useInAppMessaging/__tests__/useInAppMessaging.spec.d.ts +1 -0
- package/dist/types/InAppMessaging/hooks/useInAppMessaging/index.d.ts +1 -0
- package/dist/types/InAppMessaging/hooks/useInAppMessaging/useInAppMessaging.d.ts +7 -0
- package/dist/types/InAppMessaging/hooks/useMessage/__tests__/useMessage.spec.d.ts +1 -0
- package/dist/types/InAppMessaging/hooks/useMessage/__tests__/utils.spec.d.ts +1 -0
- package/dist/types/InAppMessaging/hooks/useMessage/index.d.ts +1 -0
- package/dist/types/InAppMessaging/hooks/useMessage/types.d.ts +18 -0
- package/dist/types/InAppMessaging/hooks/useMessage/useMessage.d.ts +9 -0
- package/dist/types/InAppMessaging/hooks/useMessage/utils.d.ts +9 -0
- package/dist/{esm/Authenticator/index.js → types/InAppMessaging/index.d.ts} +3 -1
- package/dist/types/InAppMessaging/types.d.ts +52 -0
- package/dist/types/InAppMessaging/utils/__tests__/handleMessageAction.spec.d.ts +1 -0
- package/dist/types/InAppMessaging/utils/handleMessageAction.d.ts +9 -0
- package/dist/types/InAppMessaging/utils/index.d.ts +1 -0
- package/dist/types/__tests__/index.spec.d.ts +1 -0
- package/dist/types/components/RenderNothing/RenderNothing.d.ts +4 -0
- package/dist/types/components/RenderNothing/__tests__/RenderNothing.spec.d.ts +1 -0
- package/dist/types/components/RenderNothing/index.d.ts +1 -0
- package/dist/types/components/index.d.ts +1 -0
- package/dist/types/hooks/__tests__/useHasValueUpdated.spec.d.ts +1 -0
- package/dist/types/hooks/__tests__/usePreviousValue.spec.d.ts +1 -0
- package/dist/types/hooks/index.d.ts +2 -0
- package/dist/types/hooks/useHasValueUpdated.d.ts +1 -0
- package/dist/types/hooks/usePreviousValue.d.ts +1 -0
- package/dist/types/index.d.ts +3 -1
- package/dist/types/utils/__tests__/index.spec.d.ts +1 -0
- package/package.json +13 -8
- package/dist/Authenticator/context/AuthenticatorContext.js +0 -11
- package/dist/Authenticator/context/AuthenticatorProvider.js +0 -26
- package/dist/Authenticator/context/index.js +0 -10
- package/dist/Authenticator/hooks/index.js +0 -4
- package/dist/Authenticator/hooks/useAuthenticator/constants.js +0 -16
- package/dist/Authenticator/hooks/useAuthenticator/index.js +0 -8
- package/dist/Authenticator/hooks/useAuthenticator/types.js +0 -2
- package/dist/Authenticator/hooks/useAuthenticator/useAuthenticator.js +0 -38
- package/dist/Authenticator/hooks/useAuthenticator/utils.js +0 -53
- package/dist/Authenticator/index.js +0 -5
- package/dist/esm/Authenticator/context/index.js +0 -2
- package/dist/esm/Authenticator/hooks/index.js +0 -1
- package/dist/esm/Authenticator/hooks/useAuthenticator/index.js +0 -1
- package/dist/utils/index.js +0 -20
package/dist/index.js
CHANGED
|
@@ -1,6 +1,638 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
var React = require('react');
|
|
7
|
+
var react = require('@xstate/react');
|
|
8
|
+
var ui = require('@aws-amplify/ui');
|
|
9
|
+
var awsAmplify = require('aws-amplify');
|
|
10
|
+
var isString = require('lodash/isString');
|
|
11
|
+
var isEmpty = require('lodash/isEmpty');
|
|
12
|
+
var isObject = require('lodash/isObject');
|
|
13
|
+
var notifications = require('@aws-amplify/notifications');
|
|
14
|
+
var core = require('@aws-amplify/core');
|
|
15
|
+
var isNil = require('lodash/isNil');
|
|
16
|
+
var isUndefined = require('lodash/isUndefined');
|
|
17
|
+
|
|
18
|
+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
19
|
+
|
|
20
|
+
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
|
|
21
|
+
var isString__default = /*#__PURE__*/_interopDefaultLegacy(isString);
|
|
22
|
+
var isEmpty__default = /*#__PURE__*/_interopDefaultLegacy(isEmpty);
|
|
23
|
+
var isObject__default = /*#__PURE__*/_interopDefaultLegacy(isObject);
|
|
24
|
+
var isNil__default = /*#__PURE__*/_interopDefaultLegacy(isNil);
|
|
25
|
+
var isUndefined__default = /*#__PURE__*/_interopDefaultLegacy(isUndefined);
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* AuthenticatorContext serves static reference to the auth machine service.
|
|
29
|
+
*
|
|
30
|
+
* https://xstate.js.org/docs/recipes/react.html#context-provider
|
|
31
|
+
*/
|
|
32
|
+
const AuthenticatorContext = React__default["default"].createContext(null);
|
|
33
|
+
|
|
34
|
+
function AuthenticatorProvider({ children, }) {
|
|
35
|
+
/**
|
|
36
|
+
* Based on use cases, developer might already have added another Provider
|
|
37
|
+
* outside Authenticator. In that case, we sync the two providers by just
|
|
38
|
+
* passing the parent value.
|
|
39
|
+
*
|
|
40
|
+
* TODO(BREAKING): enforce only one provider in App tree
|
|
41
|
+
*/
|
|
42
|
+
const parentProviderVal = React.useContext(AuthenticatorContext);
|
|
43
|
+
const service = react.useInterpret(ui.createAuthenticatorMachine);
|
|
44
|
+
const value = React.useMemo(() => (!parentProviderVal ? { service } : parentProviderVal), [parentProviderVal, service]);
|
|
45
|
+
const { service: activeService } = value;
|
|
46
|
+
React.useEffect(() => {
|
|
47
|
+
const unsubscribe = ui.listenToAuthHub(activeService);
|
|
48
|
+
return unsubscribe;
|
|
49
|
+
}, [activeService]);
|
|
50
|
+
return (jsxRuntime.jsx(AuthenticatorContext.Provider, Object.assign({ value: value }, { children: children })));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/******************************************************************************
|
|
54
|
+
Copyright (c) Microsoft Corporation.
|
|
55
|
+
|
|
56
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
57
|
+
purpose with or without fee is hereby granted.
|
|
58
|
+
|
|
59
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
60
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
61
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
62
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
63
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
64
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
65
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
66
|
+
***************************************************************************** */
|
|
67
|
+
|
|
68
|
+
function __rest(s, e) {
|
|
69
|
+
var t = {};
|
|
70
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
71
|
+
t[p] = s[p];
|
|
72
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
73
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
74
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
75
|
+
t[p[i]] = s[p[i]];
|
|
76
|
+
}
|
|
77
|
+
return t;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function __awaiter(thisArg, _arguments, P, generator) {
|
|
81
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
82
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
83
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
84
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
85
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
86
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const USE_AUTHENTICATOR_ERROR = '`useAuthenticator` must be used inside an `Authenticator.Provider`.';
|
|
91
|
+
|
|
92
|
+
function isEmptyArray(value) {
|
|
93
|
+
return Array.isArray(value) && isEmpty__default["default"](value);
|
|
94
|
+
}
|
|
95
|
+
function areEmptyArrays(...values) {
|
|
96
|
+
return values.every(isEmptyArray);
|
|
97
|
+
}
|
|
98
|
+
function isEmptyObject(value) {
|
|
99
|
+
return isObject__default["default"](value) && !Array.isArray(value) && isEmpty__default["default"](value);
|
|
100
|
+
}
|
|
101
|
+
function areEmptyObjects(...values) {
|
|
102
|
+
return values.every(isEmptyObject);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const COMPONENT_ROUTE_KEYS = [
|
|
106
|
+
'confirmResetPassword',
|
|
107
|
+
'confirmSignIn',
|
|
108
|
+
'confirmSignUp',
|
|
109
|
+
'confirmVerifyUser',
|
|
110
|
+
'forceNewPassword',
|
|
111
|
+
'resetPassword',
|
|
112
|
+
'setupTOTP',
|
|
113
|
+
'signIn',
|
|
114
|
+
'signUp',
|
|
115
|
+
'verifyUser',
|
|
116
|
+
];
|
|
117
|
+
const COMPONENT_ROUTE_NAMES = [
|
|
118
|
+
'ConfirmResetPassword',
|
|
119
|
+
'ConfirmSignIn',
|
|
120
|
+
'ConfirmSignUp',
|
|
121
|
+
'ConfirmVerifyUser',
|
|
122
|
+
'ForceNewPassword',
|
|
123
|
+
'ResetPassword',
|
|
124
|
+
'SetupTOTP',
|
|
125
|
+
'SignIn',
|
|
126
|
+
'SignUp',
|
|
127
|
+
'VerifyUser',
|
|
128
|
+
];
|
|
129
|
+
|
|
130
|
+
const isComponentRouteKey = (route) => COMPONENT_ROUTE_KEYS.some((componentRoute) => componentRoute === route);
|
|
131
|
+
function resolveAuthenticatorComponents(defaults, overrides) {
|
|
132
|
+
if (!overrides) {
|
|
133
|
+
return defaults;
|
|
134
|
+
}
|
|
135
|
+
return COMPONENT_ROUTE_NAMES.reduce((components, route) => {
|
|
136
|
+
const Default = defaults[route];
|
|
137
|
+
const Override = overrides[route];
|
|
138
|
+
if (typeof Override !== 'function') {
|
|
139
|
+
return Object.assign(Object.assign({}, components), { [route]: Default });
|
|
140
|
+
}
|
|
141
|
+
const { Footer, FormFields, Header } = Default;
|
|
142
|
+
// cast to allow assigning of component slots
|
|
143
|
+
const Component = Override;
|
|
144
|
+
Component.Footer = Footer;
|
|
145
|
+
Component.FormFields = FormFields;
|
|
146
|
+
Component.Header = Header;
|
|
147
|
+
return Object.assign(Object.assign({}, components), { [route]: Component });
|
|
148
|
+
}, {});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const defaultComparator = () => false;
|
|
152
|
+
/**
|
|
153
|
+
* Does an ordering and shallow comparison of each array value,
|
|
154
|
+
* plus a value equality check for empty objects and arrays.
|
|
155
|
+
*/
|
|
156
|
+
function areSelectorDepsEqual(currentDeps, nextDeps) {
|
|
157
|
+
if (currentDeps.length !== nextDeps.length) {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
return currentDeps.every((currentDep, index) => {
|
|
161
|
+
const nextDep = nextDeps[index];
|
|
162
|
+
if (areEmptyArrays(currentDep, nextDep) ||
|
|
163
|
+
areEmptyObjects(currentDep, nextDep)) {
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
return currentDep === nextDep;
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
const getComparator = (selector) => (currentFacade, nextFacade) => {
|
|
170
|
+
const currentSelectorDeps = selector(currentFacade);
|
|
171
|
+
const nextSelectorDeps = selector(nextFacade);
|
|
172
|
+
// Shallow compare the array values
|
|
173
|
+
return areSelectorDepsEqual(currentSelectorDeps, nextSelectorDeps);
|
|
174
|
+
};
|
|
175
|
+
const getTotpSecretCodeCallback = (user) => function getTotpSecretCode() {
|
|
176
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
177
|
+
return yield awsAmplify.Auth.setupTOTP(user);
|
|
178
|
+
});
|
|
179
|
+
};
|
|
180
|
+
const flattenFormFields = (fields) => fields.flatMap(([name, options]) => (Object.assign({ name }, options)));
|
|
181
|
+
const convertContactMethodsToFields = (unverifiedContactMethods) => {
|
|
182
|
+
return (unverifiedContactMethods &&
|
|
183
|
+
Object.entries(unverifiedContactMethods).map(([name, value]) => {
|
|
184
|
+
const valueIsString = isString__default["default"](value);
|
|
185
|
+
if (!valueIsString || !name) {
|
|
186
|
+
return {};
|
|
187
|
+
}
|
|
188
|
+
return { name, label: value, type: 'radio', value };
|
|
189
|
+
}));
|
|
190
|
+
};
|
|
191
|
+
/**
|
|
192
|
+
* Retrieves default and custom (RWA only, to be updated) form field values from state machine
|
|
193
|
+
* for subcomponent routes that render fields
|
|
194
|
+
*/
|
|
195
|
+
const getMachineFields = (route, state, unverifiedContactMethods) => {
|
|
196
|
+
if (isComponentRouteKey(route)) {
|
|
197
|
+
return route === 'verifyUser'
|
|
198
|
+
? convertContactMethodsToFields(unverifiedContactMethods)
|
|
199
|
+
: flattenFormFields(ui.getSortedFormFields(route, state));
|
|
200
|
+
}
|
|
201
|
+
return [];
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* [📖 Docs](https://ui.docs.amplify.aws/react/connected-components/authenticator/headless#useauthenticator-hook)
|
|
206
|
+
*/
|
|
207
|
+
function useAuthenticator(selector) {
|
|
208
|
+
const context = React__default["default"].useContext(AuthenticatorContext);
|
|
209
|
+
if (!context) {
|
|
210
|
+
throw new Error(USE_AUTHENTICATOR_ERROR);
|
|
211
|
+
}
|
|
212
|
+
const { service } = context;
|
|
213
|
+
const { send } = service;
|
|
214
|
+
const xstateSelector = React.useCallback((state) => (Object.assign({}, ui.getServiceFacade({ send, state }))), [send]);
|
|
215
|
+
const comparator = selector ? getComparator(selector) : defaultComparator;
|
|
216
|
+
const facade = react.useSelector(service, xstateSelector, comparator);
|
|
217
|
+
const { route, unverifiedContactMethods, user } = facade, rest = __rest(facade, ["route", "unverifiedContactMethods", "user"]);
|
|
218
|
+
// do not memoize output. `service.getSnapshot` reference remains stable preventing
|
|
219
|
+
// `fields` from updating with current form state on value changes
|
|
220
|
+
const serviceSnapshot = service.getSnapshot();
|
|
221
|
+
// legacy `formFields` values required until form state is removed from state machine
|
|
222
|
+
const fields = React.useMemo(() => getMachineFields(route, serviceSnapshot, unverifiedContactMethods), [route, serviceSnapshot, unverifiedContactMethods]);
|
|
223
|
+
return Object.assign(Object.assign({}, rest), { getTotpSecretCode: getTotpSecretCodeCallback(user), route,
|
|
224
|
+
unverifiedContactMethods,
|
|
225
|
+
user,
|
|
226
|
+
/** @deprecated For internal use only */
|
|
227
|
+
fields });
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Utility component for rendering nothing.
|
|
232
|
+
*/
|
|
233
|
+
function RenderNothing(_) {
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const EVENT_HANDLER_KEY_MAP = {
|
|
238
|
+
updateBlur: 'handleBlur',
|
|
239
|
+
updateForm: 'handleChange',
|
|
240
|
+
submitForm: 'handleSubmit',
|
|
241
|
+
};
|
|
242
|
+
const COMMON_ROUTE_MACHINE_KEYS = [
|
|
243
|
+
'error',
|
|
244
|
+
'isPending',
|
|
245
|
+
'submitForm',
|
|
246
|
+
'updateBlur',
|
|
247
|
+
'updateForm',
|
|
248
|
+
];
|
|
249
|
+
const CONFIRM_RESET_PASSWORD_MACHINE_KEYS = [
|
|
250
|
+
...COMMON_ROUTE_MACHINE_KEYS,
|
|
251
|
+
'resendCode',
|
|
252
|
+
'validationErrors',
|
|
253
|
+
];
|
|
254
|
+
const CONFIRM_SIGN_IN_MACHINE_KEYS = [
|
|
255
|
+
...COMMON_ROUTE_MACHINE_KEYS,
|
|
256
|
+
'toSignIn',
|
|
257
|
+
'user',
|
|
258
|
+
];
|
|
259
|
+
const CONFIRM_SIGN_UP_MACHINE_KEYS = [
|
|
260
|
+
...COMMON_ROUTE_MACHINE_KEYS,
|
|
261
|
+
'codeDeliveryDetails',
|
|
262
|
+
'resendCode',
|
|
263
|
+
];
|
|
264
|
+
const CONFIRM_VERIFY_USER_MACHINE_KEYS = [
|
|
265
|
+
...COMMON_ROUTE_MACHINE_KEYS,
|
|
266
|
+
'skipVerification',
|
|
267
|
+
];
|
|
268
|
+
const FORCE_NEW_PASSWORD_MACHINE_KEYS = [
|
|
269
|
+
...COMMON_ROUTE_MACHINE_KEYS,
|
|
270
|
+
'toSignIn',
|
|
271
|
+
'validationErrors',
|
|
272
|
+
];
|
|
273
|
+
const RESET_PASSWORD_MACHINE_KEYS = [
|
|
274
|
+
...COMMON_ROUTE_MACHINE_KEYS,
|
|
275
|
+
'toSignIn',
|
|
276
|
+
];
|
|
277
|
+
const SIGN_IN_MACHINE_KEYS = [
|
|
278
|
+
...COMMON_ROUTE_MACHINE_KEYS,
|
|
279
|
+
'toFederatedSignIn',
|
|
280
|
+
'toResetPassword',
|
|
281
|
+
'toSignUp',
|
|
282
|
+
];
|
|
283
|
+
const SIGN_UP_MACHINE_KEYS = [
|
|
284
|
+
...COMMON_ROUTE_MACHINE_KEYS,
|
|
285
|
+
'toSignIn',
|
|
286
|
+
'validationErrors',
|
|
287
|
+
];
|
|
288
|
+
const SETUP_TOTP_MACHINE_KEYS = [
|
|
289
|
+
...COMMON_ROUTE_MACHINE_KEYS,
|
|
290
|
+
'toSignIn',
|
|
291
|
+
];
|
|
292
|
+
const VERIFY_USER_MACHINE_KEYS = [
|
|
293
|
+
...COMMON_ROUTE_MACHINE_KEYS,
|
|
294
|
+
'skipVerification',
|
|
295
|
+
];
|
|
296
|
+
const MACHINE_PROP_KEYS = {
|
|
297
|
+
confirmResetPassword: CONFIRM_RESET_PASSWORD_MACHINE_KEYS,
|
|
298
|
+
confirmSignIn: CONFIRM_SIGN_IN_MACHINE_KEYS,
|
|
299
|
+
confirmSignUp: CONFIRM_SIGN_UP_MACHINE_KEYS,
|
|
300
|
+
confirmVerifyUser: CONFIRM_VERIFY_USER_MACHINE_KEYS,
|
|
301
|
+
forceNewPassword: FORCE_NEW_PASSWORD_MACHINE_KEYS,
|
|
302
|
+
signIn: SIGN_IN_MACHINE_KEYS,
|
|
303
|
+
signUp: SIGN_UP_MACHINE_KEYS,
|
|
304
|
+
resetPassword: RESET_PASSWORD_MACHINE_KEYS,
|
|
305
|
+
setupTOTP: SETUP_TOTP_MACHINE_KEYS,
|
|
306
|
+
verifyUser: VERIFY_USER_MACHINE_KEYS,
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
// only select `route` from machine context
|
|
310
|
+
const routeSelector$1 = ({ route }) => [route];
|
|
311
|
+
const createSelector = (selectorKeys) => (context) => {
|
|
312
|
+
const dependencies = selectorKeys.map((key) => context[key]);
|
|
313
|
+
// route should always be part of deps, so hook knows when route changes.
|
|
314
|
+
return [...dependencies, context.route];
|
|
315
|
+
};
|
|
316
|
+
const getRouteMachineSelector = (route) => isComponentRouteKey(route)
|
|
317
|
+
? createSelector(MACHINE_PROP_KEYS[route])
|
|
318
|
+
: routeSelector$1;
|
|
319
|
+
const isFormEventHandlerKey = (key) => ['updateBlur', 'updateForm', 'submitForm'].includes(key);
|
|
320
|
+
const convertEventHandlerKey = (key) => EVENT_HANDLER_KEY_MAP[key];
|
|
321
|
+
const getConvertedMachineProps = (route, context) => MACHINE_PROP_KEYS[route].reduce((acc, key) => (Object.assign(Object.assign({}, acc), { [isFormEventHandlerKey(key) ? convertEventHandlerKey(key) : key]: context[key] })), {});
|
|
322
|
+
function resolveConfirmResetPasswordRoute(Component, props) {
|
|
323
|
+
return {
|
|
324
|
+
Component,
|
|
325
|
+
props: Object.assign(Object.assign({}, Component), getConvertedMachineProps('confirmResetPassword', props)),
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
function resolveConfirmSignInRoute(Component, props) {
|
|
329
|
+
const _a = getConvertedMachineProps('confirmSignIn', props), { user } = _a, machineProps = __rest(_a, ["user"]);
|
|
330
|
+
// prior to the `confirmSignIn` route, `user.username` is populated
|
|
331
|
+
const challengeName = user.challengeName;
|
|
332
|
+
return { Component, props: Object.assign(Object.assign(Object.assign({}, Component), machineProps), { challengeName }) };
|
|
333
|
+
}
|
|
334
|
+
function resolveConfirmSignUpRoute(Component, props) {
|
|
335
|
+
return {
|
|
336
|
+
Component,
|
|
337
|
+
props: Object.assign(Object.assign({}, Component), getConvertedMachineProps('confirmSignUp', props)),
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
function resolveConfirmVerifyUserRoute(Component, props) {
|
|
341
|
+
return {
|
|
342
|
+
Component,
|
|
343
|
+
props: Object.assign(Object.assign({}, Component), getConvertedMachineProps('confirmVerifyUser', props)),
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
function resolveForceNewPasswordRoute(Component, props) {
|
|
347
|
+
return {
|
|
348
|
+
Component,
|
|
349
|
+
props: Object.assign(Object.assign({}, Component), getConvertedMachineProps('forceNewPassword', props)),
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
function resolveResetPasswordRoute(Component, props) {
|
|
353
|
+
return {
|
|
354
|
+
Component,
|
|
355
|
+
props: Object.assign(Object.assign({}, Component), getConvertedMachineProps('resetPassword', props)),
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
function resolveSetupTOTPRoute(Component, _a) {
|
|
359
|
+
var { getTotpSecretCode } = _a, props = __rest(_a, ["getTotpSecretCode"]);
|
|
360
|
+
return {
|
|
361
|
+
Component,
|
|
362
|
+
props: Object.assign(Object.assign(Object.assign({}, Component), getConvertedMachineProps('setupTOTP', props)), { getTotpSecretCode }),
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
function resolveSignInRoute(Component, props) {
|
|
366
|
+
// default `hideSignUp` to false
|
|
367
|
+
const hideSignUp = false;
|
|
368
|
+
return {
|
|
369
|
+
Component,
|
|
370
|
+
props: Object.assign(Object.assign(Object.assign({}, Component), getConvertedMachineProps('signIn', props)), { hideSignUp }),
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
function resolveSignUpRoute(Component, props) {
|
|
374
|
+
return {
|
|
375
|
+
Component,
|
|
376
|
+
props: Object.assign(Object.assign({}, Component), getConvertedMachineProps('signUp', props)),
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
function resolveVerifyUserRoute(Component, props) {
|
|
380
|
+
return {
|
|
381
|
+
Component,
|
|
382
|
+
props: Object.assign(Object.assign({}, Component), getConvertedMachineProps('verifyUser', props)),
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
function resolveDefault() {
|
|
386
|
+
return {
|
|
387
|
+
Component: RenderNothing,
|
|
388
|
+
props: {},
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function useAuthenticatorRoute({ components, }) {
|
|
393
|
+
const { route } = useAuthenticator(routeSelector$1);
|
|
394
|
+
const routeMachineSelector = React.useMemo(() => getRouteMachineSelector(route), [route]);
|
|
395
|
+
// `useAuthenticator` exposes both state machine (example: `toSignIn`) and non-state machine
|
|
396
|
+
// props (example: `getTotpSecretCode`). `routeSelector` specifies which state machine props
|
|
397
|
+
// should be returned for a specific route.
|
|
398
|
+
// Only state machine props specified by the current `routeSelector` will have their current value
|
|
399
|
+
// returned by `useAuthenticator`, non-machine props returned will always be the current value
|
|
400
|
+
const routeSelectorProps = useAuthenticator(routeMachineSelector);
|
|
401
|
+
const { ConfirmResetPassword, ConfirmSignIn, ConfirmSignUp, ConfirmVerifyUser, ForceNewPassword, ResetPassword, SetupTOTP, SignIn, SignUp, VerifyUser, } = components;
|
|
402
|
+
switch (route) {
|
|
403
|
+
case 'confirmResetPassword': {
|
|
404
|
+
return resolveConfirmResetPasswordRoute(ConfirmResetPassword, routeSelectorProps);
|
|
405
|
+
}
|
|
406
|
+
case 'confirmSignIn': {
|
|
407
|
+
return resolveConfirmSignInRoute(ConfirmSignIn, routeSelectorProps);
|
|
408
|
+
}
|
|
409
|
+
case 'confirmSignUp': {
|
|
410
|
+
return resolveConfirmSignUpRoute(ConfirmSignUp, routeSelectorProps);
|
|
411
|
+
}
|
|
412
|
+
case 'confirmVerifyUser': {
|
|
413
|
+
return resolveConfirmVerifyUserRoute(ConfirmVerifyUser, routeSelectorProps);
|
|
414
|
+
}
|
|
415
|
+
case 'forceNewPassword': {
|
|
416
|
+
return resolveForceNewPasswordRoute(ForceNewPassword, routeSelectorProps);
|
|
417
|
+
}
|
|
418
|
+
case 'resetPassword': {
|
|
419
|
+
return resolveResetPasswordRoute(ResetPassword, routeSelectorProps);
|
|
420
|
+
}
|
|
421
|
+
case 'setupTOTP': {
|
|
422
|
+
return resolveSetupTOTPRoute(SetupTOTP, routeSelectorProps);
|
|
423
|
+
}
|
|
424
|
+
case 'signIn': {
|
|
425
|
+
return resolveSignInRoute(SignIn, routeSelectorProps);
|
|
426
|
+
}
|
|
427
|
+
case 'signUp': {
|
|
428
|
+
return resolveSignUpRoute(SignUp, routeSelectorProps);
|
|
429
|
+
}
|
|
430
|
+
case 'verifyUser': {
|
|
431
|
+
return resolveVerifyUserRoute(VerifyUser, routeSelectorProps);
|
|
432
|
+
}
|
|
433
|
+
default: {
|
|
434
|
+
return resolveDefault();
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// only select `route` from machine context
|
|
440
|
+
const routeSelector = ({ route }) => [route];
|
|
441
|
+
function useAuthenticatorInitMachine(data) {
|
|
442
|
+
const { route, initializeMachine } = useAuthenticator(routeSelector);
|
|
443
|
+
const hasInitialized = React__default["default"].useRef(false);
|
|
444
|
+
React__default["default"].useEffect(() => {
|
|
445
|
+
if (!hasInitialized.current && route === 'setup') {
|
|
446
|
+
initializeMachine(data);
|
|
447
|
+
hasInitialized.current = true;
|
|
448
|
+
}
|
|
449
|
+
}, [initializeMachine, route, data]);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
const InAppMessagingContext = React.createContext(null);
|
|
453
|
+
|
|
454
|
+
const { InAppMessaging: InAppMessaging$1 } = notifications.Notifications;
|
|
455
|
+
function InAppMessagingProvider({ children, }) {
|
|
456
|
+
const [message, setMessage] = React.useState(null);
|
|
457
|
+
React.useEffect(() => {
|
|
458
|
+
const listener = InAppMessaging$1.onMessageReceived((message) => {
|
|
459
|
+
setMessage(message);
|
|
460
|
+
});
|
|
461
|
+
return listener.remove;
|
|
462
|
+
}, []);
|
|
463
|
+
const clearMessage = React.useCallback(() => {
|
|
464
|
+
setMessage(null);
|
|
465
|
+
}, []);
|
|
466
|
+
const value = React.useMemo(() => ({
|
|
467
|
+
clearMessage,
|
|
468
|
+
displayMessage: setMessage,
|
|
469
|
+
message,
|
|
470
|
+
}), [clearMessage, message]);
|
|
471
|
+
return (jsxRuntime.jsx(InAppMessagingContext.Provider, Object.assign({ value: value }, { children: children })));
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* Utility hook used to access the InAppMessagingContext values
|
|
476
|
+
*
|
|
477
|
+
* @returns {InAppMessagingContextType} InAppMessaging context values
|
|
478
|
+
*/
|
|
479
|
+
function useInAppMessaging() {
|
|
480
|
+
const inAppMessagingContext = React.useContext(InAppMessagingContext);
|
|
481
|
+
if (!inAppMessagingContext) {
|
|
482
|
+
throw new Error('InAppMessagingContext is empty, did you forget the InAppMessagingProvider?');
|
|
483
|
+
}
|
|
484
|
+
return inAppMessagingContext;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
const logger$2 = new core.ConsoleLogger('Notifications.InAppMessaging');
|
|
488
|
+
const positions = {
|
|
489
|
+
BOTTOM_BANNER: 'bottom',
|
|
490
|
+
MIDDLE_BANNER: 'middle',
|
|
491
|
+
TOP_BANNER: 'top',
|
|
492
|
+
};
|
|
493
|
+
const getPositionProp = (layout) => positions[layout];
|
|
494
|
+
const getActionHandler = (actionParams, onMessageAction, onActionCallback) => ({
|
|
495
|
+
onAction() {
|
|
496
|
+
try {
|
|
497
|
+
onMessageAction(actionParams);
|
|
498
|
+
}
|
|
499
|
+
catch (e) {
|
|
500
|
+
logger$2.error(`Message action failure: ${e}`);
|
|
501
|
+
}
|
|
502
|
+
finally {
|
|
503
|
+
onActionCallback();
|
|
504
|
+
}
|
|
505
|
+
},
|
|
506
|
+
});
|
|
507
|
+
const getButtonProps = (_a, onMessageAction, onActionCallback) => {
|
|
508
|
+
var { action, url } = _a, baseButtonProps = __rest(_a, ["action", "url"]);
|
|
509
|
+
return (Object.assign(Object.assign({}, baseButtonProps), getActionHandler({ action, url }, onMessageAction, onActionCallback)));
|
|
510
|
+
};
|
|
511
|
+
const getContentProps = (content, onMessageAction, onActionCallback) => {
|
|
512
|
+
const props = {};
|
|
513
|
+
if (!content) {
|
|
514
|
+
return props;
|
|
515
|
+
}
|
|
516
|
+
const { primaryButton, secondaryButton } = content, restContent = __rest(content, ["primaryButton", "secondaryButton"]);
|
|
517
|
+
if (primaryButton) {
|
|
518
|
+
props.primaryButton = getButtonProps(primaryButton, onMessageAction, onActionCallback);
|
|
519
|
+
}
|
|
520
|
+
if (secondaryButton) {
|
|
521
|
+
props.secondaryButton = getButtonProps(secondaryButton, onMessageAction, onActionCallback);
|
|
522
|
+
}
|
|
523
|
+
return Object.assign(Object.assign({}, props), restContent);
|
|
524
|
+
};
|
|
525
|
+
|
|
526
|
+
const EMPTY_PROPS = Object.freeze({});
|
|
527
|
+
const logger$1 = new core.ConsoleLogger('Notifications.InAppMessaging');
|
|
528
|
+
const { InAppMessaging } = notifications.Notifications;
|
|
529
|
+
/**
|
|
530
|
+
* Utility hook for parsing a message and retrieving its corresponding UI component and props
|
|
531
|
+
*
|
|
532
|
+
* @param {UseMessageParams} props - platform specific UI components, action handler, and styles
|
|
533
|
+
* @returns {UseMessage} message UI component and props
|
|
534
|
+
*/
|
|
535
|
+
function useMessage({ components, onMessageAction, }) {
|
|
536
|
+
const { clearMessage, message } = useInAppMessaging();
|
|
537
|
+
const { BannerMessage, CarouselMessage, FullScreenMessage, ModalMessage } = components;
|
|
538
|
+
if (isNil__default["default"](message)) {
|
|
539
|
+
return {
|
|
540
|
+
Component: RenderNothing,
|
|
541
|
+
props: EMPTY_PROPS,
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
const { content, layout } = message;
|
|
545
|
+
const onActionCallback = () => {
|
|
546
|
+
InAppMessaging.notifyMessageInteraction(message, notifications.InAppMessageInteractionEvent.MESSAGE_ACTION_TAKEN);
|
|
547
|
+
clearMessage();
|
|
548
|
+
};
|
|
549
|
+
const onClose = () => {
|
|
550
|
+
InAppMessaging.notifyMessageInteraction(message, notifications.InAppMessageInteractionEvent.MESSAGE_DISMISSED);
|
|
551
|
+
clearMessage();
|
|
552
|
+
};
|
|
553
|
+
const onDisplay = () => {
|
|
554
|
+
InAppMessaging.notifyMessageInteraction(message, notifications.InAppMessageInteractionEvent.MESSAGE_DISPLAYED);
|
|
555
|
+
};
|
|
556
|
+
switch (layout) {
|
|
557
|
+
case 'BOTTOM_BANNER':
|
|
558
|
+
case 'MIDDLE_BANNER':
|
|
559
|
+
case 'TOP_BANNER': {
|
|
560
|
+
const props = Object.assign(Object.assign({}, getContentProps(content === null || content === void 0 ? void 0 : content[0], onMessageAction, onActionCallback)), { layout,
|
|
561
|
+
onClose,
|
|
562
|
+
onDisplay, position: getPositionProp(layout) });
|
|
563
|
+
return { Component: BannerMessage, props };
|
|
564
|
+
}
|
|
565
|
+
case 'CAROUSEL': {
|
|
566
|
+
const props = {
|
|
567
|
+
data: content === null || content === void 0 ? void 0 : content.map((item) => getContentProps(item, onMessageAction, onActionCallback)),
|
|
568
|
+
layout,
|
|
569
|
+
onClose,
|
|
570
|
+
onDisplay,
|
|
571
|
+
};
|
|
572
|
+
return { Component: CarouselMessage, props };
|
|
573
|
+
}
|
|
574
|
+
case 'FULL_SCREEN': {
|
|
575
|
+
const props = Object.assign(Object.assign({}, getContentProps(content === null || content === void 0 ? void 0 : content[0], onMessageAction, onActionCallback)), { layout,
|
|
576
|
+
onClose,
|
|
577
|
+
onDisplay });
|
|
578
|
+
return { Component: FullScreenMessage, props };
|
|
579
|
+
}
|
|
580
|
+
case 'MODAL': {
|
|
581
|
+
const props = Object.assign(Object.assign({}, getContentProps(content === null || content === void 0 ? void 0 : content[0], onMessageAction, onActionCallback)), { layout,
|
|
582
|
+
onClose,
|
|
583
|
+
onDisplay });
|
|
584
|
+
return { Component: ModalMessage, props };
|
|
585
|
+
}
|
|
586
|
+
default: {
|
|
587
|
+
logger$1.info(`Received unknown InAppMessage layout: ${layout}`);
|
|
588
|
+
return {
|
|
589
|
+
Component: RenderNothing,
|
|
590
|
+
props: EMPTY_PROPS,
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
const logger = new core.ConsoleLogger('Notifications.InAppMessaging');
|
|
597
|
+
const handleMessageAction = ({ action, handleMessageLinkAction, url, }) => {
|
|
598
|
+
logger.info(`Handle action: ${action}`);
|
|
599
|
+
if (action === 'LINK' || action === 'DEEP_LINK') {
|
|
600
|
+
if (!isString__default["default"](url)) {
|
|
601
|
+
logger.warn(`url must be of type string: ${url}`);
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
handleMessageLinkAction(url);
|
|
605
|
+
}
|
|
606
|
+
};
|
|
607
|
+
|
|
608
|
+
function usePreviousValue(value) {
|
|
609
|
+
const previous = React.useRef();
|
|
610
|
+
// update ref post render
|
|
611
|
+
React.useEffect(() => {
|
|
612
|
+
previous.current = value;
|
|
613
|
+
}, [value]);
|
|
614
|
+
// return previous ref
|
|
615
|
+
return previous.current;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
function useHasValueUpdated(value, ignoreFirstRender = false) {
|
|
619
|
+
const previous = usePreviousValue(value);
|
|
620
|
+
const shouldIgnoreChange = isUndefined__default["default"](previous) && ignoreFirstRender;
|
|
621
|
+
if (shouldIgnoreChange) {
|
|
622
|
+
return false;
|
|
623
|
+
}
|
|
624
|
+
return previous !== value;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
exports.AuthenticatorProvider = AuthenticatorProvider;
|
|
628
|
+
exports.InAppMessagingProvider = InAppMessagingProvider;
|
|
629
|
+
exports.handleMessageAction = handleMessageAction;
|
|
630
|
+
exports.isAuthenticatorComponentRouteKey = isComponentRouteKey;
|
|
631
|
+
exports.resolveAuthenticatorComponents = resolveAuthenticatorComponents;
|
|
632
|
+
exports.useAuthenticator = useAuthenticator;
|
|
633
|
+
exports.useAuthenticatorInitMachine = useAuthenticatorInitMachine;
|
|
634
|
+
exports.useAuthenticatorRoute = useAuthenticatorRoute;
|
|
635
|
+
exports.useHasValueUpdated = useHasValueUpdated;
|
|
636
|
+
exports.useInAppMessaging = useInAppMessaging;
|
|
637
|
+
exports.useMessage = useMessage;
|
|
638
|
+
exports.usePreviousValue = usePreviousValue;
|
|
File without changes
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Defaults, Overrides } from '../types';
|
|
2
|
+
declare type DefaultComponents<P> = Defaults<P>;
|
|
3
|
+
export declare const DEFAULTS: DefaultComponents<{}>;
|
|
4
|
+
export declare const OVERRIDES: Overrides;
|
|
5
|
+
export declare const INVALID_SIGN_IN_OVERRIDES: Overrides;
|
|
6
|
+
export declare const INVALID_OVERRIDES: Overrides<{}, {}>;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|