UNPKG

@web3auth/modal

Version:

Multi chain wallet aggregator for web3Auth

400 lines (394 loc) 17.9 kB
'use client'; import _objectSpread from '@babel/runtime/helpers/objectSpread2'; import _defineProperty from '@babel/runtime/helpers/defineProperty'; import './css/index.css.js'; import { LANGUAGES, applyWhiteLabelTheme, SafeEventEmitter } from '@web3auth/auth'; import { log, WIDGET_TYPE, WalletInitializationError, WALLET_CONNECTORS, ANALYTICS_EVENTS, getWhitelabelAnalyticsProperties, CONNECTOR_EVENTS, LOGIN_MODE } from '@web3auth/no-modal'; import Bowser from 'bowser'; import { createRoot } from 'react-dom/client'; import { getLoginModalAnalyticsProperties } from '../utils.js'; import Widget from './components/Widget/Widget.js'; import { DEFAULT_PRIMARY_COLOR, DEFAULT_ON_PRIMARY_COLOR, DEFAULT_LOGO_DARK, DEFAULT_LOGO_LIGHT } from './constants.js'; import { AnalyticsContext } from './context/AnalyticsContext.js'; import { ThemedContext } from './context/ThemeContext.js'; import { MODAL_STATUS } from './interfaces.js'; import i18nInstance from './localeImport.js'; import { getUserLanguage } from './utils.js'; import { jsx } from 'react/jsx-runtime'; function createWrapperForModal(parentZIndex) { const existingWrapper = document.getElementById("w3a-parent-container"); if (existingWrapper) existingWrapper.remove(); const parent = document.createElement("section"); parent.classList.add("w3a-parent-container"); parent.setAttribute("id", "w3a-parent-container"); parent.style.zIndex = parentZIndex; parent.style.position = "relative"; document.body.appendChild(parent); } function createWrapperForEmbed(targetId) { const targetElement = document.getElementById(targetId); if (!targetElement) { log.error(`Element with ID ${targetId} not found`); return; } targetElement.innerHTML = `<div id="w3a-parent-container" class="w3a-parent-container"></div>`; } class LoginModal { constructor(_uiConfig, callbacks) { _defineProperty(this, "uiConfig", void 0); _defineProperty(this, "stateEmitter", void 0); _defineProperty(this, "chainNamespaces", void 0); _defineProperty(this, "walletRegistry", void 0); _defineProperty(this, "callbacks", void 0); _defineProperty(this, "externalWalletsConfig", void 0); _defineProperty(this, "analytics", void 0); _defineProperty(this, "initModal", async () => { const darkState = { isDark: this.isDark }; const useLang = this.uiConfig.defaultLanguage || LANGUAGES.en; // Load new language resource if (useLang === LANGUAGES.de) { import('./i18n/german.json.js').then(messages => { i18nInstance.addResourceBundle(useLang, "translation", messages.default); return i18nInstance.changeLanguage(useLang); }).catch(error => { log.error(error); }); } else if (useLang === LANGUAGES.ja) { import('./i18n/japanese.json.js').then(messages => { i18nInstance.addResourceBundle(useLang, "translation", messages.default); return i18nInstance.changeLanguage(useLang); }).catch(error => { log.error(error); }); } else if (useLang === LANGUAGES.ko) { import('./i18n/korean.json.js').then(messages => { i18nInstance.addResourceBundle(useLang, "translation", messages.default); return i18nInstance.changeLanguage(useLang); }).catch(error => { log.error(error); }); } else if (useLang === LANGUAGES.zh) { import('./i18n/mandarin.json.js').then(messages => { i18nInstance.addResourceBundle(useLang, "translation", messages.default); return i18nInstance.changeLanguage(useLang); }).catch(error => { log.error(error); }); } else if (useLang === LANGUAGES.es) { import('./i18n/spanish.json.js').then(messages => { i18nInstance.addResourceBundle(useLang, "translation", messages.default); return i18nInstance.changeLanguage(useLang); }).catch(error => { log.error(error); }); } else if (useLang === LANGUAGES.fr) { import('./i18n/french.json.js').then(messages => { i18nInstance.addResourceBundle(useLang, "translation", messages.default); return i18nInstance.changeLanguage(useLang); }).catch(error => { log.error(error); }); } else if (useLang === LANGUAGES.pt) { import('./i18n/portuguese.json.js').then(messages => { i18nInstance.addResourceBundle(useLang, "translation", messages.default); return i18nInstance.changeLanguage(useLang); }).catch(error => { log.error(error); }); } else if (useLang === LANGUAGES.nl) { import('./i18n/dutch.json.js').then(messages => { i18nInstance.addResourceBundle(useLang, "translation", messages.default); return i18nInstance.changeLanguage(useLang); }).catch(error => { log.error(error); }); } else if (useLang === LANGUAGES.tr) { import('./i18n/turkish.json.js').then(messages => { i18nInstance.addResourceBundle(useLang, "translation", messages.default); return i18nInstance.changeLanguage(useLang); }).catch(error => { log.error(error); }); } else if (useLang === LANGUAGES.en) { import('./i18n/english.json.js').then(messages => { i18nInstance.addResourceBundle(useLang, "translation", messages.default); return i18nInstance.changeLanguage(useLang); }).catch(error => { log.error(error); }); } return new Promise(resolve => { var _this$uiConfig, _this$uiConfig$theme, _this$uiConfig2; this.stateEmitter.once("MOUNTED", () => { log.info("rendered"); this.setState({ status: MODAL_STATUS.INITIALIZED, web3authClientId: this.uiConfig.web3authClientId, web3authNetwork: this.uiConfig.web3authNetwork, authBuildEnv: this.uiConfig.authBuildEnv }); return resolve(); }); if (this.uiConfig.widgetType === WIDGET_TYPE.MODAL) { createWrapperForModal(this.uiConfig.modalZIndex); } else if (this.uiConfig.widgetType === WIDGET_TYPE.EMBED) { createWrapperForEmbed(this.uiConfig.targetId); } else { throw WalletInitializationError.invalidParams(`Invalid widget type: ${this.uiConfig.widgetType}`); } const container = document.getElementById("w3a-parent-container"); if (darkState.isDark) { container.classList.add("w3a--dark"); } else { container.classList.remove("w3a--dark"); } const root = createRoot(container); root.render(/*#__PURE__*/jsx(ThemedContext.Provider, { value: darkState, children: /*#__PURE__*/jsx(AnalyticsContext.Provider, { value: { analytics: this.analytics }, children: /*#__PURE__*/jsx(Widget, { stateListener: this.stateEmitter, appLogo: darkState.isDark ? this.uiConfig.logoDark : this.uiConfig.logoLight, appName: this.uiConfig.appName, chainNamespaces: this.chainNamespaces, walletRegistry: this.walletRegistry, deviceDetails: this.deviceDetails, handleShowExternalWallets: this.handleShowExternalWallets, handleExternalWalletClick: this.handleExternalWalletClick, handleSocialLoginClick: this.handleSocialLoginClick, closeModal: this.closeModal, uiConfig: this.uiConfig }) }) })); const isDefaultColors = ((_this$uiConfig = this.uiConfig) === null || _this$uiConfig === void 0 || (_this$uiConfig = _this$uiConfig.theme) === null || _this$uiConfig === void 0 ? void 0 : _this$uiConfig.primary) === DEFAULT_PRIMARY_COLOR && ((_this$uiConfig$theme = this.uiConfig.theme) === null || _this$uiConfig$theme === void 0 ? void 0 : _this$uiConfig$theme.onPrimary) === DEFAULT_ON_PRIMARY_COLOR; if ((_this$uiConfig2 = this.uiConfig) !== null && _this$uiConfig2 !== void 0 && _this$uiConfig2.theme && !isDefaultColors) { import('color').then(({ default: Color }) => { const rootElement = document.getElementById("w3a-parent-container"); applyWhiteLabelTheme(Color, rootElement, this.uiConfig.theme); return; }).catch(error => { log.error(error); }); } }); }); _defineProperty(this, "addSocialLogins", (connector, loginMethods, loginMethodsOrder, uiConfig) => { this.setState({ socialLoginsConfig: { connector, loginMethods, loginMethodsOrder, uiConfig } }); log.info("addSocialLogins", connector, loginMethods, loginMethodsOrder, uiConfig); }); _defineProperty(this, "addWalletLogins", (externalWalletsConfig, options) => { this.externalWalletsConfig = externalWalletsConfig; const isMMAvailable = !!externalWalletsConfig[WALLET_CONNECTORS.METAMASK]; this.setState({ externalWalletsConfig, externalWalletsInitialized: !!options.externalWalletsInitialized, showExternalWalletsOnly: !!options.showExternalWalletsOnly, externalWalletsVisibility: isMMAvailable ? false : !!options.externalWalletsVisibility }); }); _defineProperty(this, "open", () => { var _this$analytics, _this$walletRegistry, _this$walletRegistry2; this.setState({ modalVisibility: true }); (_this$analytics = this.analytics) === null || _this$analytics === void 0 || _this$analytics.track(ANALYTICS_EVENTS.LOGIN_MODAL_OPENED, _objectSpread(_objectSpread({ chain_namespaces: this.chainNamespaces, wallet_registry_count: Object.keys((_this$walletRegistry = this.walletRegistry) === null || _this$walletRegistry === void 0 ? void 0 : _this$walletRegistry.default).length + Object.keys((_this$walletRegistry2 = this.walletRegistry) === null || _this$walletRegistry2 === void 0 ? void 0 : _this$walletRegistry2.others).length, external_wallet_connectors: Object.keys(this.externalWalletsConfig || {}) }, getWhitelabelAnalyticsProperties(this.uiConfig)), getLoginModalAnalyticsProperties(this.uiConfig))); if (this.callbacks.onModalVisibility) { this.callbacks.onModalVisibility(true); } }); _defineProperty(this, "closeModal", () => { var _this$analytics2; this.setState({ modalVisibility: false, externalWalletsVisibility: false }); (_this$analytics2 = this.analytics) === null || _this$analytics2 === void 0 || _this$analytics2.track(ANALYTICS_EVENTS.LOGIN_MODAL_CLOSED); if (this.callbacks.onModalVisibility) { this.callbacks.onModalVisibility(false); } }); _defineProperty(this, "initExternalWalletContainer", () => { this.setState({ hasExternalWallets: true }); }); _defineProperty(this, "handleShowExternalWallets", status => { if (this.callbacks.onInitExternalWallets) { this.callbacks.onInitExternalWallets({ externalWalletsInitialized: status }); } }); _defineProperty(this, "handleExternalWalletClick", params => { log.info("external wallet clicked", params); const { connector, chainNamespace } = params; if (this.callbacks.onExternalWalletLogin) { this.callbacks.onExternalWalletLogin({ connector, loginParams: { chainNamespace } }); } }); _defineProperty(this, "handleSocialLoginClick", params => { var _this$analytics3; log.info("social login clicked", params); const { connector, loginParams } = params; (_this$analytics3 = this.analytics) === null || _this$analytics3 === void 0 || _this$analytics3.track(ANALYTICS_EVENTS.SOCIAL_LOGIN_SELECTED, { connector, auth_connection: loginParams.authConnection, auth_connection_id: loginParams.authConnectionId, group_auth_connection_id: loginParams.groupedAuthConnectionId }); if (this.callbacks.onSocialLogin) { this.callbacks.onSocialLogin({ connector, loginParams }); } }); _defineProperty(this, "setState", newState => { this.stateEmitter.emit("STATE_UPDATED", newState); }); _defineProperty(this, "handleConnectorData", connectorData => { if (connectorData.connectorName === WALLET_CONNECTORS.WALLET_CONNECT_V2) { const walletConnectData = connectorData.data; if (walletConnectData.uri) { this.setState({ walletConnectUri: walletConnectData.uri }); } } if (connectorData.connectorName === WALLET_CONNECTORS.METAMASK) { const metamaskData = connectorData.data; if (metamaskData.uri) { this.setState({ metamaskConnectUri: metamaskData.uri }); } } }); _defineProperty(this, "subscribeCoreEvents", listener => { listener.on(CONNECTOR_EVENTS.CONNECTING, data => { var _this$externalWallets; log.info("connecting with connector", data); // don't show loader in case of wallet connect, because currently it listens for incoming connections without any user interaction if ((data === null || data === void 0 ? void 0 : data.connector) === WALLET_CONNECTORS.WALLET_CONNECT_V2) return; // don't show loader in case of metamask qr code, because currently it listens for incoming connections without any user interaction const isMetamaskInjected = (_this$externalWallets = this.externalWalletsConfig) === null || _this$externalWallets === void 0 || (_this$externalWallets = _this$externalWallets[WALLET_CONNECTORS.METAMASK]) === null || _this$externalWallets === void 0 ? void 0 : _this$externalWallets.isInjected; if ((data === null || data === void 0 ? void 0 : data.connector) === WALLET_CONNECTORS.METAMASK && !isMetamaskInjected && this.deviceDetails.platform === "desktop") return; this.setState({ status: MODAL_STATUS.CONNECTING }); }); listener.on(CONNECTOR_EVENTS.CONNECTED, data => { log.debug("connected with connector", data); // only show success if not being reconnected again. if (!data.reconnected && data.loginMode === LOGIN_MODE.MODAL) { this.setState({ status: MODAL_STATUS.CONNECTED, modalVisibility: true, postLoadingMessage: "modal.post-loading.connected" }); } else { this.setState({ status: MODAL_STATUS.CONNECTED }); } }); // TODO: send connector name in error listener.on(CONNECTOR_EVENTS.ERRORED, (error, loginMode) => { log.error("error", error, error.message); if (loginMode === LOGIN_MODE.NO_MODAL) return; if (error.code === 5000) { if (this.uiConfig.displayErrorsOnModal) this.setState({ modalVisibility: true, postLoadingMessage: error.message || "modal.post-loading.something-wrong", status: MODAL_STATUS.ERRORED });else this.setState({ modalVisibility: false }); } else { this.setState({ modalVisibility: true, status: MODAL_STATUS.INITIALIZED }); } }); listener.on(CONNECTOR_EVENTS.DISCONNECTED, () => { this.setState({ status: MODAL_STATUS.INITIALIZED, externalWalletsVisibility: false }); // this.toggleMessage(""); }); listener.on(CONNECTOR_EVENTS.CONNECTOR_DATA_UPDATED, connectorData => { this.handleConnectorData(connectorData); }); }); this.uiConfig = _uiConfig; if (!_uiConfig.logoDark) this.uiConfig.logoDark = DEFAULT_LOGO_DARK; if (!_uiConfig.logoLight) this.uiConfig.logoLight = DEFAULT_LOGO_LIGHT; if (!_uiConfig.mode) this.uiConfig.mode = "light"; if (!_uiConfig.modalZIndex) this.uiConfig.modalZIndex = "99998"; if (typeof _uiConfig.displayErrorsOnModal === "undefined") this.uiConfig.displayErrorsOnModal = true; if (!_uiConfig.appName) this.uiConfig.appName = "Web3Auth"; if (!_uiConfig.loginGridCol) this.uiConfig.loginGridCol = 3; if (!_uiConfig.primaryButton) this.uiConfig.primaryButton = "socialLogin"; if (!_uiConfig.defaultLanguage) this.uiConfig.defaultLanguage = getUserLanguage(_uiConfig.defaultLanguage); if (!_uiConfig.widgetType) this.uiConfig.widgetType = WIDGET_TYPE.MODAL; if (_uiConfig.widgetType === WIDGET_TYPE.EMBED && !_uiConfig.targetId) { log.error("targetId is required for embed widget"); throw WalletInitializationError.invalidParams("targetId is required for embed widget"); } this.stateEmitter = new SafeEventEmitter(); this.chainNamespaces = _uiConfig.chainNamespaces; this.walletRegistry = _uiConfig.walletRegistry; this.callbacks = callbacks; this.analytics = _uiConfig.analytics; this.subscribeCoreEvents(this.uiConfig.connectorListener); } get isDark() { return this.uiConfig.mode === "dark" || this.uiConfig.mode === "auto" && window.matchMedia("(prefers-color-scheme: dark)").matches; } get deviceDetails() { if (typeof window === "undefined") return { platform: "mobile", browser: "chrome", os: "ios" }; const browserData = Bowser.getParser(window.navigator.userAgent); return { platform: browserData.getPlatformType(), browser: browserData.getBrowserName().toLowerCase(), os: browserData.getOSName() }; } } export { LoginModal };