@web3auth/modal 10.0.0-alpha.2 → 10.0.0-beta.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/lib.cjs/packages/modal/src/config.js +3 -57
- package/dist/lib.cjs/packages/modal/src/index.js +1 -5
- package/dist/lib.cjs/packages/modal/src/modalManager.js +132 -89
- package/dist/lib.cjs/packages/modal/src/react/context/Web3AuthInnerContext.js +1 -12
- package/dist/lib.cjs/packages/modal/src/ui/components/ExternalWallets.js +10 -5
- package/dist/lib.cjs/packages/modal/src/ui/components/Modal.js +36 -2
- package/dist/lib.cjs/packages/modal/src/ui/components/SocialLoginPasswordless.js +8 -6
- package/dist/lib.cjs/packages/modal/src/ui/components/SocialLogins.js +2 -1
- package/dist/lib.cjs/packages/modal/src/ui/config.js +1 -2
- package/dist/lib.cjs/packages/modal/src/ui/css/web3auth.css.js +1 -1
- package/dist/lib.cjs/packages/modal/src/ui/i18n/dutch.json.js +1 -0
- package/dist/lib.cjs/packages/modal/src/ui/i18n/english.json.js +1 -0
- package/dist/lib.cjs/packages/modal/src/ui/i18n/french.json.js +1 -0
- package/dist/lib.cjs/packages/modal/src/ui/i18n/german.json.js +1 -0
- package/dist/lib.cjs/packages/modal/src/ui/i18n/japanese.json.js +1 -0
- package/dist/lib.cjs/packages/modal/src/ui/i18n/korean.json.js +1 -0
- package/dist/lib.cjs/packages/modal/src/ui/i18n/mandarin.json.js +1 -0
- package/dist/lib.cjs/packages/modal/src/ui/i18n/portuguese.json.js +1 -0
- package/dist/lib.cjs/packages/modal/src/ui/i18n/spanish.json.js +1 -0
- package/dist/lib.cjs/packages/modal/src/ui/i18n/turkish.json.js +1 -0
- package/dist/lib.cjs/packages/modal/src/ui/loginModal.js +2 -1
- package/dist/lib.cjs/packages/modal/src/ui/utils.js +0 -21
- package/dist/lib.cjs/packages/modal/src/vue/Web3AuthProvider.js +1 -12
- package/dist/lib.cjs/types/config.d.ts +1 -5
- package/dist/lib.cjs/types/interface.d.ts +2 -6
- package/dist/lib.cjs/types/modalManager.d.ts +7 -3
- package/dist/lib.cjs/types/react/interfaces.d.ts +1 -6
- package/dist/lib.cjs/types/ui/interfaces.d.ts +2 -2
- package/dist/lib.cjs/types/ui/utils.d.ts +1 -3
- package/dist/lib.cjs/types/vue/interfaces.d.ts +1 -6
- package/dist/lib.esm/packages/modal/src/config.js +4 -54
- package/dist/lib.esm/packages/modal/src/index.js +1 -1
- package/dist/lib.esm/packages/modal/src/modalManager.js +144 -93
- package/dist/lib.esm/packages/modal/src/react/context/Web3AuthInnerContext.js +1 -12
- package/dist/lib.esm/packages/modal/src/ui/components/ExternalWallets.js +10 -5
- package/dist/lib.esm/packages/modal/src/ui/components/Modal.js +37 -3
- package/dist/lib.esm/packages/modal/src/ui/components/SocialLoginPasswordless.js +8 -6
- package/dist/lib.esm/packages/modal/src/ui/components/SocialLogins.js +2 -1
- package/dist/lib.esm/packages/modal/src/ui/config.js +2 -2
- package/dist/lib.esm/packages/modal/src/ui/css/web3auth.css.js +1 -1
- package/dist/lib.esm/packages/modal/src/ui/i18n/dutch.json.js +1 -0
- package/dist/lib.esm/packages/modal/src/ui/i18n/english.json.js +1 -0
- package/dist/lib.esm/packages/modal/src/ui/i18n/french.json.js +1 -0
- package/dist/lib.esm/packages/modal/src/ui/i18n/german.json.js +1 -0
- package/dist/lib.esm/packages/modal/src/ui/i18n/japanese.json.js +1 -0
- package/dist/lib.esm/packages/modal/src/ui/i18n/korean.json.js +1 -0
- package/dist/lib.esm/packages/modal/src/ui/i18n/mandarin.json.js +1 -0
- package/dist/lib.esm/packages/modal/src/ui/i18n/portuguese.json.js +1 -0
- package/dist/lib.esm/packages/modal/src/ui/i18n/spanish.json.js +1 -0
- package/dist/lib.esm/packages/modal/src/ui/i18n/turkish.json.js +1 -0
- package/dist/lib.esm/packages/modal/src/ui/loginModal.js +2 -1
- package/dist/lib.esm/packages/modal/src/ui/utils.js +2 -22
- package/dist/lib.esm/packages/modal/src/vue/Web3AuthProvider.js +1 -12
- package/dist/modal.umd.min.js +1 -1
- package/package.json +3 -3
|
@@ -1,44 +1,50 @@
|
|
|
1
1
|
import _objectSpread from '@babel/runtime/helpers/objectSpread2';
|
|
2
2
|
import _defineProperty from '@babel/runtime/helpers/defineProperty';
|
|
3
|
-
import { Web3AuthNoModal, cloneDeep, CONNECTOR_EVENTS, WalletInitializationError, CONNECTOR_STATUS, fetchProjectConfig,
|
|
3
|
+
import { Web3AuthNoModal, cloneDeep, log, CONNECTOR_EVENTS, WalletInitializationError, CONNECTOR_STATUS, fetchProjectConfig, fetchWalletRegistry, WALLET_CONNECTORS, CONNECTOR_NAMES, CONNECTOR_CATEGORY } from '@web3auth/no-modal';
|
|
4
4
|
import deepmerge from 'deepmerge';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { defaultConnectorsModalConfig, walletRegistryUrl } from './config.js';
|
|
6
|
+
import { AUTH_PROVIDERS, capitalizeFirstLetter } from './ui/config.js';
|
|
7
7
|
import { LOGIN_MODAL_EVENTS } from './ui/interfaces.js';
|
|
8
8
|
import { LoginModal } from './ui/loginModal.js';
|
|
9
|
-
import { getUserLanguage
|
|
9
|
+
import { getUserLanguage } from './ui/utils.js';
|
|
10
10
|
|
|
11
11
|
class Web3Auth extends Web3AuthNoModal {
|
|
12
12
|
constructor(options) {
|
|
13
13
|
super(options);
|
|
14
14
|
_defineProperty(this, "loginModal", void 0);
|
|
15
15
|
_defineProperty(this, "options", void 0);
|
|
16
|
-
_defineProperty(this, "modalConfig", cloneDeep(
|
|
16
|
+
_defineProperty(this, "modalConfig", cloneDeep(defaultConnectorsModalConfig));
|
|
17
17
|
this.options = _objectSpread({}, options);
|
|
18
18
|
if (!this.options.uiConfig) this.options.uiConfig = {};
|
|
19
|
+
if (this.options.modalConfig) this.modalConfig = this.options.modalConfig;
|
|
20
|
+
log.info("modalConfig", this.modalConfig);
|
|
19
21
|
}
|
|
20
|
-
|
|
21
|
-
super.checkInitRequirements();
|
|
22
|
-
this.modalConfig = modalConfig;
|
|
23
|
-
}
|
|
24
|
-
async initModal(params) {
|
|
22
|
+
async initModal() {
|
|
25
23
|
var _this$coreOptions$cha;
|
|
26
24
|
super.checkInitRequirements();
|
|
27
|
-
super.initCachedConnectorAndChainId();
|
|
28
25
|
// get project config and wallet registry
|
|
29
26
|
const {
|
|
30
27
|
projectConfig,
|
|
31
28
|
walletRegistry
|
|
32
|
-
} = await this.getProjectAndWalletConfig(
|
|
29
|
+
} = await this.getProjectAndWalletConfig();
|
|
33
30
|
this.options.uiConfig = deepmerge(cloneDeep(projectConfig.whitelabel || {}), this.options.uiConfig || {});
|
|
34
31
|
if (!this.options.uiConfig.defaultLanguage) this.options.uiConfig.defaultLanguage = getUserLanguage(this.options.uiConfig.defaultLanguage);
|
|
35
32
|
if (!this.options.uiConfig.mode) this.options.uiConfig.mode = "light";
|
|
36
33
|
|
|
34
|
+
// init config
|
|
35
|
+
super.initAccountAbstractionConfig(projectConfig);
|
|
36
|
+
super.initChainsConfig(projectConfig);
|
|
37
|
+
super.initCachedConnectorAndChainId();
|
|
38
|
+
|
|
37
39
|
// init login modal
|
|
40
|
+
const {
|
|
41
|
+
filteredWalletRegistry,
|
|
42
|
+
disabledExternalWallets
|
|
43
|
+
} = this.filterWalletRegistry(walletRegistry, projectConfig);
|
|
38
44
|
this.loginModal = new LoginModal(_objectSpread(_objectSpread({}, this.options.uiConfig), {}, {
|
|
39
45
|
connectorListener: this,
|
|
40
46
|
chainNamespaces: [...new Set(((_this$coreOptions$cha = this.coreOptions.chains) === null || _this$coreOptions$cha === void 0 ? void 0 : _this$coreOptions$cha.map(x => x.chainNamespace)) || [])],
|
|
41
|
-
walletRegistry
|
|
47
|
+
walletRegistry: filteredWalletRegistry
|
|
42
48
|
}));
|
|
43
49
|
this.subscribeToLoginModalEvents();
|
|
44
50
|
await this.loginModal.initModal();
|
|
@@ -52,7 +58,7 @@ class Web3Auth extends Web3AuthNoModal {
|
|
|
52
58
|
}) => this.initConnectors({
|
|
53
59
|
connectors: newConnectors,
|
|
54
60
|
projectConfig,
|
|
55
|
-
|
|
61
|
+
disabledExternalWallets
|
|
56
62
|
}));
|
|
57
63
|
await this.loadConnectors({
|
|
58
64
|
projectConfig
|
|
@@ -81,7 +87,35 @@ class Web3Auth extends Web3AuthNoModal {
|
|
|
81
87
|
});
|
|
82
88
|
});
|
|
83
89
|
}
|
|
84
|
-
|
|
90
|
+
filterWalletRegistry(walletRegistry, projectConfig) {
|
|
91
|
+
const {
|
|
92
|
+
disableAllRecommendedWallets,
|
|
93
|
+
disableAllOtherWallets,
|
|
94
|
+
disabledWallets
|
|
95
|
+
} = projectConfig.externalWalletAuth || {};
|
|
96
|
+
|
|
97
|
+
// add disabled wallets to set
|
|
98
|
+
const disabledExternalWallets = new Set(disabledWallets || []);
|
|
99
|
+
if (disableAllRecommendedWallets) {
|
|
100
|
+
Object.keys(walletRegistry.default).forEach(wallet => disabledExternalWallets.add(wallet));
|
|
101
|
+
}
|
|
102
|
+
if (disableAllOtherWallets) {
|
|
103
|
+
Object.keys(walletRegistry.others).forEach(wallet => disabledExternalWallets.add(wallet));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// remove wallets that are disabled in project config from wallet registry
|
|
107
|
+
const filteredWalletRegistry = cloneDeep(walletRegistry);
|
|
108
|
+
disabledExternalWallets.forEach(wallet => {
|
|
109
|
+
delete filteredWalletRegistry.default[wallet];
|
|
110
|
+
delete filteredWalletRegistry.others[wallet];
|
|
111
|
+
});
|
|
112
|
+
return {
|
|
113
|
+
disabledExternalWallets,
|
|
114
|
+
filteredWalletRegistry
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
async getProjectAndWalletConfig() {
|
|
118
|
+
var _this$modalConfig;
|
|
85
119
|
// get project config
|
|
86
120
|
let projectConfig;
|
|
87
121
|
try {
|
|
@@ -97,7 +131,8 @@ class Web3Auth extends Web3AuthNoModal {
|
|
|
97
131
|
others: {},
|
|
98
132
|
default: {}
|
|
99
133
|
};
|
|
100
|
-
|
|
134
|
+
const isExternalWalletEnabled = Boolean(projectConfig.externalWalletAuth);
|
|
135
|
+
if (isExternalWalletEnabled && !((_this$modalConfig = this.modalConfig) !== null && _this$modalConfig !== void 0 && _this$modalConfig.hideWalletDiscovery)) {
|
|
101
136
|
try {
|
|
102
137
|
walletRegistry = await fetchWalletRegistry(walletRegistryUrl);
|
|
103
138
|
} catch (e) {
|
|
@@ -112,16 +147,19 @@ class Web3Auth extends Web3AuthNoModal {
|
|
|
112
147
|
async initConnectors({
|
|
113
148
|
connectors,
|
|
114
149
|
projectConfig,
|
|
115
|
-
|
|
150
|
+
disabledExternalWallets
|
|
116
151
|
}) {
|
|
117
152
|
// filter connectors based on config
|
|
118
|
-
const filteredConnectorNames = await this.filterConnectors(
|
|
153
|
+
const filteredConnectorNames = await this.filterConnectors({
|
|
154
|
+
projectConfig,
|
|
155
|
+
disabledExternalWallets
|
|
156
|
+
});
|
|
119
157
|
|
|
120
158
|
// initialize connectors based on availability
|
|
121
159
|
const {
|
|
122
160
|
hasInAppConnectors,
|
|
123
161
|
hasExternalConnectors
|
|
124
|
-
} = await this.checkConnectorAvailability(filteredConnectorNames
|
|
162
|
+
} = await this.checkConnectorAvailability(filteredConnectorNames);
|
|
125
163
|
if (hasInAppConnectors) {
|
|
126
164
|
await this.initInAppAndCachedConnectors(connectors, filteredConnectorNames);
|
|
127
165
|
// show connect button if external wallets are available
|
|
@@ -139,106 +177,119 @@ class Web3Auth extends Web3AuthNoModal {
|
|
|
139
177
|
this.emit(CONNECTOR_EVENTS.READY);
|
|
140
178
|
}
|
|
141
179
|
}
|
|
142
|
-
async filterConnectors(
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
180
|
+
async filterConnectors({
|
|
181
|
+
projectConfig,
|
|
182
|
+
disabledExternalWallets
|
|
183
|
+
}) {
|
|
184
|
+
var _this$modalConfig2, _this$modalConfig3, _projectConfig$loginM, _projectConfig$loginM2;
|
|
185
|
+
// Auth connector config: merge code config with config from dashboard
|
|
186
|
+
const loginMethods = {};
|
|
187
|
+
for (const authConnectionConfig of projectConfig.embeddedWalletAuth || []) {
|
|
188
|
+
const {
|
|
189
|
+
isDefault,
|
|
190
|
+
authConnectionId,
|
|
191
|
+
groupedAuthConnectionId,
|
|
192
|
+
authConnection
|
|
193
|
+
} = authConnectionConfig;
|
|
194
|
+
// for custom auth connections, authConnectionId or groupedAuthConnectionId are required.
|
|
195
|
+
if (!isDefault && (!authConnectionId || !groupedAuthConnectionId)) return;
|
|
196
|
+
loginMethods[authConnection] = _objectSpread(_objectSpread({
|
|
197
|
+
name: authConnection
|
|
198
|
+
}, authConnectionConfig), {}, {
|
|
199
|
+
showOnModal: true,
|
|
200
|
+
showOnDesktop: true,
|
|
201
|
+
showOnMobile: true
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
const dashboardConnectorConfig = {
|
|
205
|
+
[WALLET_CONNECTORS.AUTH]: {
|
|
206
|
+
label: WALLET_CONNECTORS.AUTH,
|
|
207
|
+
loginMethods
|
|
169
208
|
}
|
|
170
|
-
|
|
209
|
+
};
|
|
210
|
+
if ((_this$modalConfig2 = this.modalConfig) !== null && _this$modalConfig2 !== void 0 && (_this$modalConfig2 = _this$modalConfig2.connectors) !== null && _this$modalConfig2 !== void 0 && _this$modalConfig2[WALLET_CONNECTORS.AUTH]) {
|
|
211
|
+
if (!this.modalConfig.connectors[WALLET_CONNECTORS.AUTH].loginMethods) this.modalConfig.connectors[WALLET_CONNECTORS.AUTH].loginMethods = {};
|
|
171
212
|
}
|
|
213
|
+
this.modalConfig.connectors = deepmerge(dashboardConnectorConfig, cloneDeep(this.modalConfig.connectors || {}));
|
|
214
|
+
// TODO: validate modal connector config here.!!
|
|
215
|
+
|
|
216
|
+
if ((_this$modalConfig3 = this.modalConfig) !== null && _this$modalConfig3 !== void 0 && (_this$modalConfig3 = _this$modalConfig3.connectors) !== null && _this$modalConfig3 !== void 0 && (_this$modalConfig3 = _this$modalConfig3[WALLET_CONNECTORS.AUTH]) !== null && _this$modalConfig3 !== void 0 && _this$modalConfig3.loginMethods) {
|
|
217
|
+
const authProviders = new Set(AUTH_PROVIDERS);
|
|
218
|
+
Object.keys(this.modalConfig.connectors[WALLET_CONNECTORS.AUTH].loginMethods).forEach(key => {
|
|
219
|
+
if (!authProviders.has(key)) {
|
|
220
|
+
throw WalletInitializationError.invalidParams(`Invalid auth connection: ${key}`);
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// external wallets config
|
|
226
|
+
const isExternalWalletEnabled = Boolean(projectConfig.externalWalletAuth);
|
|
227
|
+
const isInstalledWalletWalletDisplayed = Boolean((_projectConfig$loginM = (_projectConfig$loginM2 = projectConfig.loginModal) === null || _projectConfig$loginM2 === void 0 ? void 0 : _projectConfig$loginM2.displayInstalledExternalWallets) !== null && _projectConfig$loginM !== void 0 ? _projectConfig$loginM : true);
|
|
172
228
|
|
|
173
229
|
// merge default connectors with the custom configured connectors.
|
|
174
230
|
const allConnectorNames = [...new Set([...Object.keys(this.modalConfig.connectors || {}), ...this.connectors.map(connector => connector.name)])];
|
|
175
|
-
const
|
|
176
|
-
var _this$
|
|
231
|
+
const connectorNames = allConnectorNames.map(connectorName => {
|
|
232
|
+
var _this$modalConfig4, _this$modalConfig$con, _this$modalConfig$con2;
|
|
177
233
|
// start with the default config of connector.
|
|
178
|
-
|
|
234
|
+
const defaultConnectorConfig = {
|
|
179
235
|
label: CONNECTOR_NAMES[connectorName] || connectorName.split("-").map(capitalizeFirstLetter).join(" "),
|
|
180
236
|
showOnModal: true,
|
|
181
237
|
showOnMobile: true,
|
|
182
238
|
showOnDesktop: true
|
|
183
239
|
};
|
|
184
|
-
|
|
185
|
-
if ((_params2 = params) !== null && _params2 !== void 0 && (_params2 = _params2.modalConfig) !== null && _params2 !== void 0 && _params2[connectorName]) {
|
|
186
|
-
connectorConfig = _objectSpread(_objectSpread({}, connectorConfig), params.modalConfig[connectorName]);
|
|
187
|
-
}
|
|
188
|
-
this.modalConfig.connectors[connectorName] = connectorConfig;
|
|
240
|
+
this.modalConfig.connectors[connectorName] = _objectSpread(_objectSpread({}, defaultConnectorConfig), ((_this$modalConfig4 = this.modalConfig) === null || _this$modalConfig4 === void 0 || (_this$modalConfig4 = _this$modalConfig4.connectors) === null || _this$modalConfig4 === void 0 ? void 0 : _this$modalConfig4[connectorName]) || {});
|
|
189
241
|
|
|
190
242
|
// check if connector is configured/added by user and exist in connectors map.
|
|
191
243
|
const connector = this.getConnector(connectorName);
|
|
192
|
-
log.debug("connector config", connectorName, (_this$modalConfig$
|
|
244
|
+
log.debug("connector config", connectorName, (_this$modalConfig$con = this.modalConfig.connectors) === null || _this$modalConfig$con === void 0 || (_this$modalConfig$con = _this$modalConfig$con[connectorName]) === null || _this$modalConfig$con === void 0 ? void 0 : _this$modalConfig$con.showOnModal, connector);
|
|
193
245
|
|
|
194
|
-
// if connector is
|
|
195
|
-
|
|
196
|
-
if (!connector
|
|
197
|
-
throw WalletInitializationError.invalidParams(`Connector ${connectorName} is not configured`);
|
|
198
|
-
|
|
199
|
-
var _this$modalConfig$con4;
|
|
200
|
-
if (!((_this$modalConfig$con4 = this.modalConfig.connectors) !== null && _this$modalConfig$con4 !== void 0 && _this$modalConfig$con4[connectorName].showOnModal)) return;
|
|
201
|
-
if (connectorName === WALLET_CONNECTORS.WALLET_CONNECT_V2) {
|
|
202
|
-
const {
|
|
203
|
-
wallet_connect_enabled: walletConnectEnabled
|
|
204
|
-
} = projectConfig;
|
|
205
|
-
if (walletConnectEnabled === false) {
|
|
206
|
-
var _this$modalConfig$con5, _this$modalConfig$con6, _this$modalConfig$con7;
|
|
207
|
-
// override user specified config by hiding wallet connect
|
|
208
|
-
this.modalConfig.connectors = _objectSpread(_objectSpread({}, (_this$modalConfig$con5 = this.modalConfig.connectors) !== null && _this$modalConfig$con5 !== void 0 ? _this$modalConfig$con5 : {}), {}, {
|
|
209
|
-
[WALLET_CONNECTORS.WALLET_CONNECT_V2]: _objectSpread(_objectSpread({}, (_this$modalConfig$con6 = (_this$modalConfig$con7 = this.modalConfig.connectors) === null || _this$modalConfig$con7 === void 0 ? void 0 : _this$modalConfig$con7[WALLET_CONNECTORS.WALLET_CONNECT_V2]) !== null && _this$modalConfig$con6 !== void 0 ? _this$modalConfig$con6 : {}), {}, {
|
|
210
|
-
showOnModal: false
|
|
211
|
-
})
|
|
212
|
-
});
|
|
213
|
-
this.modalConfig.connectors[WALLET_CONNECTORS.WALLET_CONNECT_V2].showOnModal = false;
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
return connectorName;
|
|
246
|
+
// check if connector is configured/added by user and exist in connectors map.
|
|
247
|
+
const connectorConfig = (_this$modalConfig$con2 = this.modalConfig.connectors) === null || _this$modalConfig$con2 === void 0 ? void 0 : _this$modalConfig$con2[connectorName];
|
|
248
|
+
if (!connector) {
|
|
249
|
+
if (connectorConfig.showOnModal) throw WalletInitializationError.invalidParams(`Connector ${connectorName} is not configured`);
|
|
250
|
+
return;
|
|
217
251
|
}
|
|
252
|
+
|
|
253
|
+
// skip connector if it is hidden by user
|
|
254
|
+
if (!connectorConfig.showOnModal) return;
|
|
255
|
+
|
|
256
|
+
// skip external connector if external wallets are disabled or it is disabled or displayInstalledExternalWallets is false
|
|
257
|
+
if (connector.type === CONNECTOR_CATEGORY.EXTERNAL) {
|
|
258
|
+
if (!isExternalWalletEnabled) return;
|
|
259
|
+
if (disabledExternalWallets.has(connectorName)) return;
|
|
260
|
+
if (!isInstalledWalletWalletDisplayed) return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// skip WC connector if external wallets are disabled or hideWalletDiscovery is true
|
|
264
|
+
if (connectorName === WALLET_CONNECTORS.WALLET_CONNECT_V2) {
|
|
265
|
+
var _this$modalConfig5;
|
|
266
|
+
if (!isExternalWalletEnabled) return;
|
|
267
|
+
if ((_this$modalConfig5 = this.modalConfig) !== null && _this$modalConfig5 !== void 0 && _this$modalConfig5.hideWalletDiscovery) return;
|
|
268
|
+
}
|
|
269
|
+
this.modalConfig.connectors[connectorName] = connectorConfig;
|
|
270
|
+
return connectorName;
|
|
218
271
|
});
|
|
219
|
-
const connectorNames = await Promise.all(connectorConfigurationPromises);
|
|
272
|
+
// const connectorNames = await Promise.all(connectorConfigurationPromises);
|
|
220
273
|
return connectorNames.filter(name => name !== undefined);
|
|
221
274
|
}
|
|
222
|
-
async checkConnectorAvailability(connectorNames
|
|
275
|
+
async checkConnectorAvailability(connectorNames) {
|
|
223
276
|
// currently all default in app and external wallets can be hidden or shown based on config.
|
|
224
277
|
// check if in app connectors are available
|
|
225
278
|
const hasInAppConnectors = this.connectors.some(connector => {
|
|
226
|
-
var _this$modalConfig$
|
|
279
|
+
var _this$modalConfig$con3, _this$modalConfig$con4;
|
|
227
280
|
if (connector.type !== CONNECTOR_CATEGORY.IN_APP) return false;
|
|
228
|
-
if (((_this$modalConfig$
|
|
229
|
-
if (!((_this$modalConfig$
|
|
230
|
-
|
|
231
|
-
if (Object.values(mergedLoginMethods).some(method => method.showOnModal)) return true;
|
|
281
|
+
if (((_this$modalConfig$con3 = this.modalConfig.connectors) === null || _this$modalConfig$con3 === void 0 || (_this$modalConfig$con3 = _this$modalConfig$con3[connector.name]) === null || _this$modalConfig$con3 === void 0 ? void 0 : _this$modalConfig$con3.showOnModal) !== true) return false;
|
|
282
|
+
if (!((_this$modalConfig$con4 = this.modalConfig.connectors) !== null && _this$modalConfig$con4 !== void 0 && (_this$modalConfig$con4 = _this$modalConfig$con4[connector.name]) !== null && _this$modalConfig$con4 !== void 0 && _this$modalConfig$con4.loginMethods)) return true;
|
|
283
|
+
if (Object.values(this.modalConfig.connectors[connector.name].loginMethods).some(method => method.showOnModal)) return true;
|
|
232
284
|
return false;
|
|
233
285
|
});
|
|
234
286
|
log.debug(hasInAppConnectors, this.connectors, connectorNames, "hasInAppWallets");
|
|
235
287
|
|
|
236
288
|
// check if external connectors are available
|
|
237
289
|
const hasExternalConnectors = connectorNames.some(connectorName => {
|
|
238
|
-
var _this$getConnector, _this$modalConfig$
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
return ((_this$getConnector = this.getConnector(connectorName)) === null || _this$getConnector === void 0 ? void 0 : _this$getConnector.type) === CONNECTOR_CATEGORY.EXTERNAL && ((_this$modalConfig$con10 = this.modalConfig.connectors) === null || _this$modalConfig$con10 === void 0 ? void 0 : _this$modalConfig$con10[connectorName].showOnModal);
|
|
290
|
+
var _this$getConnector, _this$modalConfig$con5;
|
|
291
|
+
if (connectorName === WALLET_CONNECTORS.WALLET_CONNECT_V2) return true;
|
|
292
|
+
return ((_this$getConnector = this.getConnector(connectorName)) === null || _this$getConnector === void 0 ? void 0 : _this$getConnector.type) === CONNECTOR_CATEGORY.EXTERNAL && ((_this$modalConfig$con5 = this.modalConfig.connectors) === null || _this$modalConfig$con5 === void 0 ? void 0 : _this$modalConfig$con5[connectorName].showOnModal);
|
|
242
293
|
});
|
|
243
294
|
return {
|
|
244
295
|
hasInAppConnectors,
|
|
@@ -254,7 +305,7 @@ class Web3Auth extends Web3AuthNoModal {
|
|
|
254
305
|
if (connector.status !== CONNECTOR_STATUS.NOT_READY) return;
|
|
255
306
|
|
|
256
307
|
// only initialize a external connectors here if it is a cached connector.
|
|
257
|
-
if (this.cachedConnector !== connectorName && connector.type === CONNECTOR_CATEGORY.EXTERNAL) return;
|
|
308
|
+
if (this.cachedConnector !== connectorName && connectorName !== WALLET_CONNECTORS.METAMASK && connector.type === CONNECTOR_CATEGORY.EXTERNAL) return;
|
|
258
309
|
|
|
259
310
|
// in-app wallets or cached wallet (being connected or already connected) are initialized first.
|
|
260
311
|
// if connector is configured then only initialize in app or cached connector.
|
|
@@ -269,9 +320,9 @@ class Web3Auth extends Web3AuthNoModal {
|
|
|
269
320
|
// note: not adding cachedWallet to modal if it is external wallet.
|
|
270
321
|
// adding it later if no in-app wallets are available.
|
|
271
322
|
if (connector.type === CONNECTOR_CATEGORY.IN_APP) {
|
|
272
|
-
var
|
|
323
|
+
var _this$modalConfig$con6, _this$options$uiConfi, _this$options$uiConfi2, _this$options$uiConfi3;
|
|
273
324
|
log.info("connectorInitResults", connectorName);
|
|
274
|
-
const loginMethods =
|
|
325
|
+
const loginMethods = ((_this$modalConfig$con6 = this.modalConfig.connectors[connectorName]) === null || _this$modalConfig$con6 === void 0 ? void 0 : _this$modalConfig$con6.loginMethods) || {};
|
|
275
326
|
this.loginModal.addSocialLogins(connectorName, loginMethods, ((_this$options$uiConfi = this.options.uiConfig) === null || _this$options$uiConfi === void 0 ? void 0 : _this$options$uiConfi.loginMethodsOrder) || AUTH_PROVIDERS, _objectSpread(_objectSpread({}, this.options.uiConfig), {}, {
|
|
276
327
|
loginGridCol: ((_this$options$uiConfi2 = this.options.uiConfig) === null || _this$options$uiConfi2 === void 0 ? void 0 : _this$options$uiConfi2.loginGridCol) || 3,
|
|
277
328
|
primaryButton: ((_this$options$uiConfi3 = this.options.uiConfig) === null || _this$options$uiConfi3 === void 0 ? void 0 : _this$options$uiConfi3.primaryButton) || "socialLogin"
|
|
@@ -85,18 +85,7 @@ function Web3AuthInnerProvider(params) {
|
|
|
85
85
|
try {
|
|
86
86
|
setInitError(null);
|
|
87
87
|
setIsInitializing(true);
|
|
88
|
-
|
|
89
|
-
modalConfig,
|
|
90
|
-
hideWalletDiscovery
|
|
91
|
-
} = config;
|
|
92
|
-
if (modalConfig) {
|
|
93
|
-
await web3Auth.initModal({
|
|
94
|
-
modalConfig,
|
|
95
|
-
hideWalletDiscovery
|
|
96
|
-
});
|
|
97
|
-
} else {
|
|
98
|
-
await web3Auth.initModal();
|
|
99
|
-
}
|
|
88
|
+
await web3Auth.initModal();
|
|
100
89
|
} catch (error) {
|
|
101
90
|
setInitError(error);
|
|
102
91
|
} finally {
|
|
@@ -36,7 +36,7 @@ function ExternalWallets(props) {
|
|
|
36
36
|
i18n: i18nInstance
|
|
37
37
|
});
|
|
38
38
|
const walletDiscoverySupported = useMemo(() => {
|
|
39
|
-
const supported = walletRegistry && Object.keys(walletRegistry.default).length > 0
|
|
39
|
+
const supported = walletRegistry && (Object.keys(walletRegistry.default).length > 0 || Object.keys(walletRegistry.others).length > 0);
|
|
40
40
|
return supported;
|
|
41
41
|
}, [walletRegistry]);
|
|
42
42
|
const deviceDetails = useMemo(() => {
|
|
@@ -84,11 +84,12 @@ function ExternalWallets(props) {
|
|
|
84
84
|
useEffect(() => {
|
|
85
85
|
if (walletDiscoverySupported) {
|
|
86
86
|
const isWalletConnectAdapterIncluded = Object.keys(config).some(adapter => adapter === WALLET_CONNECTORS.WALLET_CONNECT_V2);
|
|
87
|
-
const defaultButtonKeys = new Set(Object.keys(walletRegistry.default));
|
|
88
87
|
const generateWalletButtons = wallets => {
|
|
89
88
|
return Object.keys(wallets).reduce((acc, wallet) => {
|
|
90
89
|
var _walletRegistryItem$c, _walletRegistryItem$i, _config$wallet, _walletRegistryItem$w;
|
|
91
90
|
if (adapterVisibilityMap[wallet] === false) return acc;
|
|
91
|
+
// Metamask is always visible in the main screen, no need to show it in the external wallets list
|
|
92
|
+
if (wallet === WALLET_CONNECTORS.METAMASK) return acc;
|
|
92
93
|
const walletRegistryItem = wallets[wallet];
|
|
93
94
|
let href = "";
|
|
94
95
|
if (deviceDetails.platform === Bowser.PLATFORMS_MAP.mobile) {
|
|
@@ -125,6 +126,8 @@ function ExternalWallets(props) {
|
|
|
125
126
|
|
|
126
127
|
// Generate custom adapter buttons
|
|
127
128
|
const customAdapterButtons = Object.keys(config).reduce((acc, adapter) => {
|
|
129
|
+
// Metamask is always visible in the main screen, no need to show it in the external wallets list
|
|
130
|
+
if (adapter === WALLET_CONNECTORS.METAMASK) return acc;
|
|
128
131
|
if (![WALLET_CONNECTORS.WALLET_CONNECT_V2].includes(adapter) && !config[adapter].isInjected && adapterVisibilityMap[adapter]) {
|
|
129
132
|
log.debug("custom adapter", adapter, config[adapter]);
|
|
130
133
|
acc.push({
|
|
@@ -145,6 +148,8 @@ function ExternalWallets(props) {
|
|
|
145
148
|
log.debug("filteredLists", filteredList);
|
|
146
149
|
setExternalButtons(filteredList);
|
|
147
150
|
} else {
|
|
151
|
+
const finalDefaultButtons = defaultButtons.length > 0 ? defaultButtons : allButtons.slice(0, 10);
|
|
152
|
+
const defaultButtonKeys = new Set(finalDefaultButtons.map(button => button.name));
|
|
148
153
|
const sortedButtons = [...allButtons.filter(button => button.hasInjectedWallet && defaultButtonKeys.has(button.name)), ...customAdapterButtons, ...allButtons.filter(button => !button.hasInjectedWallet && defaultButtonKeys.has(button.name))];
|
|
149
154
|
setExternalButtons(sortedButtons);
|
|
150
155
|
}
|
|
@@ -200,7 +205,7 @@ function ExternalWallets(props) {
|
|
|
200
205
|
}), totalExternalWallets > 15 && /*#__PURE__*/jsx("div", {
|
|
201
206
|
className: "w3a--py-4",
|
|
202
207
|
children: /*#__PURE__*/jsx("input", {
|
|
203
|
-
className: "w3a--w-full
|
|
208
|
+
className: "w3a-text-field w3a--w-full",
|
|
204
209
|
name: "passwordless-input",
|
|
205
210
|
required: true,
|
|
206
211
|
value: walletSearch,
|
|
@@ -218,7 +223,7 @@ function ExternalWallets(props) {
|
|
|
218
223
|
onChange: e => handleWalletSearch(e)
|
|
219
224
|
})
|
|
220
225
|
}), externalButtons.length === 0 ? /*#__PURE__*/jsx("div", {
|
|
221
|
-
className: "w3a--w-full w3a--text-center w3a--text-app-gray-400 dark:w3a--text-app-gray-500
|
|
226
|
+
className: "w3a--flex w3a--w-full w3a--items-center w3a--justify-center w3a--py-6 w3a--text-center w3a--text-app-gray-400 dark:w3a--text-app-gray-500",
|
|
222
227
|
children: t("modal.external.no-wallets-found")
|
|
223
228
|
}) : /*#__PURE__*/jsx("div", {
|
|
224
229
|
className: `w3a-adapter-list-container ${totalExternalWallets < 15 ? "w3a--py-4" : ""}`,
|
|
@@ -248,7 +253,7 @@ function ExternalWallets(props) {
|
|
|
248
253
|
}))]
|
|
249
254
|
}, button.name + button.displayName);
|
|
250
255
|
}), totalExternalWallets > 10 && !walletSearch && /*#__PURE__*/jsxs("li", {
|
|
251
|
-
className: "w3a--
|
|
256
|
+
className: "w3a-adapter-item--full w3a--mx-auto w3a--my-4 w3a--flex w3a--w-full w3a--flex-col w3a--items-center w3a--justify-center w3a--gap-y-0.5",
|
|
252
257
|
children: [/*#__PURE__*/jsx("p", {
|
|
253
258
|
className: "w3a--text-xs w3a--text-app-gray-500 dark:w3a--text-app-gray-400",
|
|
254
259
|
children: t("modal.external.search-text")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import _objectSpread from '@babel/runtime/helpers/objectSpread2';
|
|
2
2
|
import { AUTH_CONNECTION } from '@web3auth/auth';
|
|
3
|
-
import { log, cloneDeep, CONNECTOR_NAMES } from '@web3auth/no-modal';
|
|
3
|
+
import { log, cloneDeep, CONNECTOR_NAMES, WALLET_CONNECTORS } from '@web3auth/no-modal';
|
|
4
4
|
import deepmerge from 'deepmerge';
|
|
5
5
|
import { useState, useEffect, useCallback, useMemo } from 'react';
|
|
6
6
|
import { useTranslation } from 'react-i18next';
|
|
@@ -11,6 +11,7 @@ import Button from './Button/Button.js';
|
|
|
11
11
|
import ExternalWallets from './ExternalWallets.js';
|
|
12
12
|
import Footer from './Footer.js';
|
|
13
13
|
import memoizedHeader from './Header.js';
|
|
14
|
+
import Image from './Image.js';
|
|
14
15
|
import SocialLoginPasswordless from './SocialLoginPasswordless.js';
|
|
15
16
|
import SocialLogins from './SocialLogins.js';
|
|
16
17
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -138,7 +139,7 @@ function Modal(props) {
|
|
|
138
139
|
children: /*#__PURE__*/jsx(Button, {
|
|
139
140
|
variant: isExternalPrimary ? "primary" : "tertiary",
|
|
140
141
|
type: "button",
|
|
141
|
-
className: "w3a--w-full
|
|
142
|
+
className: "w3ajs-external-toggle__button w3a--w-full",
|
|
142
143
|
style: {
|
|
143
144
|
width: "100%"
|
|
144
145
|
},
|
|
@@ -158,6 +159,39 @@ function Modal(props) {
|
|
|
158
159
|
})
|
|
159
160
|
})
|
|
160
161
|
});
|
|
162
|
+
const metamaskWalletButton = /*#__PURE__*/jsx("div", {
|
|
163
|
+
className: "w3ajs-external-wallet w3a-group w3a--w-full",
|
|
164
|
+
children: /*#__PURE__*/jsx("div", {
|
|
165
|
+
className: "w3a-external-toggle w3ajs-external-toggle",
|
|
166
|
+
children: /*#__PURE__*/jsxs(Button, {
|
|
167
|
+
variant: isExternalPrimary ? "primary" : "tertiary",
|
|
168
|
+
type: "button",
|
|
169
|
+
className: "w3a--w-full w3ajs-external-toggle__button",
|
|
170
|
+
style: {
|
|
171
|
+
width: "100%"
|
|
172
|
+
},
|
|
173
|
+
onClick: () => {
|
|
174
|
+
preHandleExternalWalletClick({
|
|
175
|
+
connector: WALLET_CONNECTORS.METAMASK
|
|
176
|
+
});
|
|
177
|
+
},
|
|
178
|
+
children: [/*#__PURE__*/jsx(Image, {
|
|
179
|
+
imageId: "login-metamask",
|
|
180
|
+
hoverImageId: "login-metamask",
|
|
181
|
+
fallbackImageId: "wallet",
|
|
182
|
+
height: "24",
|
|
183
|
+
width: "24",
|
|
184
|
+
isButton: true,
|
|
185
|
+
extension: "svg"
|
|
186
|
+
}), /*#__PURE__*/jsx("span", {
|
|
187
|
+
className: "ml-2",
|
|
188
|
+
children: t("modal.external.continue-custom", {
|
|
189
|
+
wallet: "MetaMask"
|
|
190
|
+
})
|
|
191
|
+
})]
|
|
192
|
+
})
|
|
193
|
+
})
|
|
194
|
+
});
|
|
161
195
|
const areSocialLoginsVisible = useMemo(() => {
|
|
162
196
|
var _modalState$socialLog3, _modalState$socialLog4;
|
|
163
197
|
if (modalState.showExternalWalletsOnly) return false;
|
|
@@ -215,7 +249,7 @@ function Modal(props) {
|
|
|
215
249
|
handleSocialLoginClick: params => preHandleSocialWalletClick(params),
|
|
216
250
|
socialLoginsConfig: modalState.socialLoginsConfig,
|
|
217
251
|
isPrimaryBtn: isEmailPrimary
|
|
218
|
-
}), modalState.hasExternalWallets && externalWalletButton]
|
|
252
|
+
}), metamaskWalletButton, modalState.hasExternalWallets && externalWalletButton]
|
|
219
253
|
})]
|
|
220
254
|
}) : /*#__PURE__*/jsx("div", {
|
|
221
255
|
className: "w3a-modal__content_external_wallet w3ajs-content",
|
|
@@ -34,7 +34,8 @@ function SocialLoginPasswordless(props) {
|
|
|
34
34
|
loginParams: {
|
|
35
35
|
authConnection: AUTH_CONNECTION.EMAIL_PASSWORDLESS,
|
|
36
36
|
authConnectionId: emailConfig.authConnectionId,
|
|
37
|
-
groupedAuthConnectionId:
|
|
37
|
+
groupedAuthConnectionId: emailConfig.groupedAuthConnectionId,
|
|
38
|
+
extraLoginOptions: emailConfig.extraLoginOptions,
|
|
38
39
|
login_hint: value,
|
|
39
40
|
name: "Email"
|
|
40
41
|
}
|
|
@@ -52,6 +53,7 @@ function SocialLoginPasswordless(props) {
|
|
|
52
53
|
authConnection: AUTH_CONNECTION.SMS_PASSWORDLESS,
|
|
53
54
|
authConnectionId: smsConfig.authConnectionId,
|
|
54
55
|
groupedAuthConnectionId: smsConfig.groupedAuthConnectionId,
|
|
56
|
+
extraLoginOptions: smsConfig.extraLoginOptions,
|
|
55
57
|
login_hint: typeof result === "string" ? result : number,
|
|
56
58
|
name: "Mobile"
|
|
57
59
|
}
|
|
@@ -94,16 +96,16 @@ function SocialLoginPasswordless(props) {
|
|
|
94
96
|
children: [/*#__PURE__*/jsxs("div", {
|
|
95
97
|
className: "w3a-group__title",
|
|
96
98
|
children: [t(title), isSmsVisible && /*#__PURE__*/jsxs("div", {
|
|
97
|
-
className: "w3a--
|
|
99
|
+
className: "w3a--group w3a--relative w3a--flex w3a--cursor-pointer w3a--flex-col w3a--items-center",
|
|
98
100
|
children: [/*#__PURE__*/jsx(Icon, {
|
|
99
101
|
iconName: "information-circle-light",
|
|
100
102
|
darkIconName: "information-circle"
|
|
101
103
|
}), /*#__PURE__*/jsxs("div", {
|
|
102
|
-
className: "w3a--absolute w3a--
|
|
104
|
+
className: "w3a--absolute w3a--top-4 w3a--z-20 w3a--mb-5 w3a--hidden w3a--flex-col w3a--items-center group-hover:w3a--flex",
|
|
103
105
|
children: [/*#__PURE__*/jsx("div", {
|
|
104
|
-
className: "
|
|
106
|
+
className: "-w3a--mb-2 w3a--ml-[3px] w3a--size-3 w3a--rotate-45 w3a--bg-app-gray-50 dark:w3a--bg-app-gray-600"
|
|
105
107
|
}), /*#__PURE__*/jsxs("div", {
|
|
106
|
-
className: `w3a--relative w3a--
|
|
108
|
+
className: `w3a--relative w3a--w-[300px] w3a--rounded-md w3a--bg-app-gray-50 w3a--p-4 w3a--text-xs w3a--leading-none w3a--text-app-white w3a--shadow-lg dark:w3a--bg-app-gray-600 ${isSmsVisible && !isEmailVisible ? "w3a--left-20" : "w3a--left-8"}`,
|
|
107
109
|
children: [/*#__PURE__*/jsx("div", {
|
|
108
110
|
className: "w3a--mb-1 w3a--text-xs w3a--font-medium w3a--text-app-gray-900 dark:w3a--text-app-white",
|
|
109
111
|
children: t("modal.popup.phone-header")
|
|
@@ -118,7 +120,7 @@ function SocialLoginPasswordless(props) {
|
|
|
118
120
|
className: "w3ajs-passwordless-form",
|
|
119
121
|
onSubmit: e => handleFormSubmit(e),
|
|
120
122
|
children: [/*#__PURE__*/jsx("input", {
|
|
121
|
-
className: "w3a
|
|
123
|
+
className: "w3a-text-field w3a--mb-4 w3a--w-full",
|
|
122
124
|
name: "passwordless-input",
|
|
123
125
|
required: true,
|
|
124
126
|
placeholder: `${t("modal.social.sms-placeholder-text")} ${placeholder}`,
|
|
@@ -80,7 +80,7 @@ function SocialLogins(props) {
|
|
|
80
80
|
const loginMethodSpan = classNames("w3a-adapter-item", (socialLoginsConfig === null || socialLoginsConfig === void 0 || (_socialLoginsConfig$u2 = socialLoginsConfig.uiConfig) === null || _socialLoginsConfig$u2 === void 0 ? void 0 : _socialLoginsConfig$u2.loginGridCol) === 2 ? "w3a--col-span-3" : "w3a--col-span-2");
|
|
81
81
|
if (isMainOption || order === 1) {
|
|
82
82
|
return /*#__PURE__*/jsx("li", {
|
|
83
|
-
className: "w3a--col-span-6
|
|
83
|
+
className: "w3a-adapter-item w3a--col-span-6",
|
|
84
84
|
style: {
|
|
85
85
|
order
|
|
86
86
|
},
|
|
@@ -93,6 +93,7 @@ function SocialLogins(props) {
|
|
|
93
93
|
name: socialLoginConfig.name,
|
|
94
94
|
authConnectionId: socialLoginConfig.authConnectionId,
|
|
95
95
|
groupedAuthConnectionId: socialLoginConfig.groupedAuthConnectionId,
|
|
96
|
+
extraLoginOptions: socialLoginConfig.extraLoginOptions,
|
|
96
97
|
login_hint: ""
|
|
97
98
|
}
|
|
98
99
|
}),
|
|
@@ -5,9 +5,9 @@ function capitalizeFirstLetter(string) {
|
|
|
5
5
|
}
|
|
6
6
|
const restrictedLoginMethods = new Set([AUTH_CONNECTION.CUSTOM, AUTH_CONNECTION.PASSKEYS, AUTH_CONNECTION.TELEGRAM, AUTH_CONNECTION.AUTHENTICATOR]);
|
|
7
7
|
const AUTH_PROVIDERS = Object.values(AUTH_CONNECTION).filter(x => !restrictedLoginMethods.has(x));
|
|
8
|
-
|
|
8
|
+
AUTH_PROVIDERS.reduce((acc, x) => {
|
|
9
9
|
if (x === "email_passwordless") acc[x] = "Email";else if (x === "sms_passwordless") acc[x] = "Mobile";else acc[x] = capitalizeFirstLetter(x);
|
|
10
10
|
return acc;
|
|
11
11
|
}, {});
|
|
12
12
|
|
|
13
|
-
export { AUTH_PROVIDERS,
|
|
13
|
+
export { AUTH_PROVIDERS, capitalizeFirstLetter };
|