diff --git a/apps/sample-angular-app/src/app/app.component.ts b/apps/sample-angular-app/src/app/app.component.ts
index 3f3dbf16..4918d532 100644
--- a/apps/sample-angular-app/src/app/app.component.ts
+++ b/apps/sample-angular-app/src/app/app.component.ts
@@ -32,7 +32,7 @@ export class AppComponent implements OnInit {
handleConnected(DAppKitUI.wallet.state.address);
- DAppKitUI.modal.onConnected(handleConnected);
+ DAppKitUI.modal.onConnectionStatusChange(handleConnected);
}
}
diff --git a/apps/sample-next-app/src/app/pages/homepage.tsx b/apps/sample-next-app/src/app/pages/homepage.tsx
index 70883867..894c7776 100644
--- a/apps/sample-next-app/src/app/pages/homepage.tsx
+++ b/apps/sample-next-app/src/app/pages/homepage.tsx
@@ -11,7 +11,7 @@ import type { WalletConnectOptions } from '@vechain/dapp-kit';
const Button = (): ReactElement => {
const { account } = useWallet();
- const { open, onConnected } = useWalletModal();
+ const { open, onConnectionStatusChange } = useWalletModal();
const [buttonText, setButtonText] = useState('Connect Custom Button');
useEffect(() => {
@@ -29,8 +29,8 @@ const Button = (): ReactElement => {
handleConnected(account);
- onConnected(handleConnected);
- }, [account, onConnected]);
+ onConnectionStatusChange(handleConnected);
+ }, [account, onConnectionStatusChange]);
return (
diff --git a/apps/sample-react-app/src/App.tsx b/apps/sample-react-app/src/App.tsx
index 6e403645..752817e5 100644
--- a/apps/sample-react-app/src/App.tsx
+++ b/apps/sample-react-app/src/App.tsx
@@ -7,7 +7,7 @@ import { useEffect, useState } from 'react';
function App() {
const { account } = useWallet();
- const { open, onConnected } = useWalletModal();
+ const { open, onConnectionStatusChange } = useWalletModal();
const [buttonText, setButtonText] = useState('Connect Custom Button');
useEffect(() => {
@@ -25,8 +25,8 @@ function App() {
handleConnected(account);
- onConnected(handleConnected);
- }, [account, onConnected]);
+ onConnectionStatusChange(handleConnected);
+ }, [account, onConnectionStatusChange]);
return (
diff --git a/apps/sample-svelte-app/src/lib/index.ts b/apps/sample-svelte-app/src/lib/index.ts
index a45fda68..98f9f3dd 100644
--- a/apps/sample-svelte-app/src/lib/index.ts
+++ b/apps/sample-svelte-app/src/lib/index.ts
@@ -41,6 +41,6 @@ setTimeout(() => {
handleConnected(DAppKitUI.wallet.state.address);
- DAppKitUI.modal.onConnected(handleConnected);
+ DAppKitUI.modal.onConnectionStatusChange(handleConnected);
}
}, 100);
diff --git a/apps/sample-vanilla-app/index.js b/apps/sample-vanilla-app/index.js
index e53aa5d7..4ed22d3a 100644
--- a/apps/sample-vanilla-app/index.js
+++ b/apps/sample-vanilla-app/index.js
@@ -42,4 +42,4 @@ const handleConnected = (address) => {
handleConnected(DAppKitUI.wallet.state.address);
-DAppKitUI.modal.onConnected(handleConnected);
+DAppKitUI.modal.onConnectionStatusChange(handleConnected);
diff --git a/apps/sample-vue-app/src/App.vue b/apps/sample-vue-app/src/App.vue
index 7f84a5c3..c680a9ea 100644
--- a/apps/sample-vue-app/src/App.vue
+++ b/apps/sample-vue-app/src/App.vue
@@ -54,7 +54,7 @@ setTimeout(() => {
handleConnected(DAppKitUI.wallet.state.address);
- DAppKitUI.modal.onConnected(handleConnected);
+ DAppKitUI.modal.onConnectionStatusChange(handleConnected);
}
}, 100);
diff --git a/packages/dapp-kit-react/src/DAppKitProvider.tsx b/packages/dapp-kit-react/src/DAppKitProvider.tsx
index e5ac8c05..5d7c7ce9 100644
--- a/packages/dapp-kit-react/src/DAppKitProvider.tsx
+++ b/packages/dapp-kit-react/src/DAppKitProvider.tsx
@@ -23,6 +23,7 @@ export const DAppKitProvider: React.FC
= ({
walletConnectOptions,
usePersistence = false,
logLevel,
+ requireCertificate,
themeMode,
themeVariables,
i18n,
@@ -38,6 +39,7 @@ export const DAppKitProvider: React.FC = ({
walletConnectOptions,
usePersistence,
logLevel,
+ requireCertificate,
themeVariables,
themeMode,
i18n,
@@ -51,6 +53,7 @@ export const DAppKitProvider: React.FC = ({
walletConnectOptions,
usePersistence,
logLevel,
+ requireCertificate,
themeVariables,
themeMode,
i18n,
@@ -90,7 +93,7 @@ export const DAppKitProvider: React.FC = ({
}, []);
const onModalConnected = useCallback(
(callback: (address: string | null) => void) =>
- DAppKitUI.modal.onConnected(callback),
+ DAppKitUI.modal.onConnectionStatusChange(callback),
[],
);
@@ -111,7 +114,7 @@ export const DAppKitProvider: React.FC = ({
modal: {
open: openModal,
close: closeModal,
- onConnected: onModalConnected,
+ onConnectionStatusChange: onModalConnected,
},
};
}, [connex, account, source, closeModal, openModal, onModalConnected]);
diff --git a/packages/dapp-kit-react/src/types.ts b/packages/dapp-kit-react/src/types.ts
index e4360227..8a653d38 100644
--- a/packages/dapp-kit-react/src/types.ts
+++ b/packages/dapp-kit-react/src/types.ts
@@ -38,6 +38,8 @@ export interface DAppKitContext {
modal: {
open: () => void;
close: () => void;
- onConnected: (callback: (address: string | null) => void) => void;
+ onConnectionStatusChange: (
+ callback: (address: string | null) => void,
+ ) => void;
};
}
diff --git a/packages/dapp-kit-ui/index.js b/packages/dapp-kit-ui/index.js
index 1a007f35..ae3b1910 100644
--- a/packages/dapp-kit-ui/index.js
+++ b/packages/dapp-kit-ui/index.js
@@ -42,4 +42,4 @@ const handleConnected = (address) => {
handleConnected(DAppKitUI.wallet.state.address);
-DAppKitUI.modal.onConnected(handleConnected);
+DAppKitUI.modal.onConnectionStatusChange(handleConnected);
diff --git a/packages/dapp-kit-ui/src/assets/styles/button.ts b/packages/dapp-kit-ui/src/assets/styles/button.ts
index 68ecfa71..f924698c 100644
--- a/packages/dapp-kit-ui/src/assets/styles/button.ts
+++ b/packages/dapp-kit-ui/src/assets/styles/button.ts
@@ -22,35 +22,42 @@ export const buttonStyle = css`
background: var(--vdk-color-light-primary, ${Colors.Light.Primary});
color: var(--vdk-color-light-tertiary, ${Colors.Light.Tertiary});
}
- button.LIGHT:hover {
+ button.LIGHT:hover:not(:disabled) {
background: var(
--vdk-color-light-primary-hover,
${Colors.Light.PrimaryHover}
);
}
- button.LIGHT:active {
+ button.LIGHT:active:not(:disabled) {
background: var(
--vdk-color-light-primary-active,
${Colors.Light.PrimaryActive}
);
}
+ button.LIGHT:disabled {
+ opacity: 0.8;
+ }
button.DARK {
background: var(--vdk-color-dark-primary, ${Colors.Dark.Primary});
color: var(--vdk-color-dark-tertiary, ${Colors.Dark.Tertiary});
}
- button.DARK:hover {
+ button.DARK:hover:not(:disabled) {
background: var(
--vdk-color-dark-primary-hover,
${Colors.Dark.PrimaryHover}
);
}
- button.DARK:active {
+ button.DARK:active:not(:disabled) {
background: var(
--vdk-color-dark-primary-active,
${Colors.Dark.PrimaryActive}
);
}
+
+ button.DARK:disabled {
+ opacity: 0.8;
+ }
`;
export const iconButtonStyle = css`
@@ -83,4 +90,8 @@ export const iconButtonStyle = css`
.icon-button.DARK:active {
background: var(--vdk-color-dark-primary, ${Colors.Dark.PrimaryActive});
}
+
+ button:disabled {
+ opacity: 0.8;
+ }
`;
diff --git a/packages/dapp-kit-ui/src/class/index.ts b/packages/dapp-kit-ui/src/class/index.ts
deleted file mode 100644
index df34a59e..00000000
--- a/packages/dapp-kit-ui/src/class/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './responsive';
diff --git a/packages/dapp-kit-ui/src/class/responsive.ts b/packages/dapp-kit-ui/src/class/responsive.ts
deleted file mode 100644
index b6727843..00000000
--- a/packages/dapp-kit-ui/src/class/responsive.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import { LitElement } from 'lit';
-import { property } from 'lit/decorators';
-import { addResizeListeners } from '../utils';
-import { Breakpoint } from '../constants';
-
-export enum Media {
- Mobile = 'mobile',
- Tablet = 'tablet',
- Desktop = 'desktop',
-}
-
-export class ResponsiveLitElement extends LitElement {
- @property()
- media = Media.Desktop;
-
- private setCurrentMedia = (): void => {
- if (window.screen.width <= Breakpoint.Mobile) {
- this.media = Media.Mobile;
- return;
- }
- if (window.screen.width <= Breakpoint.Tablet) {
- this.media = Media.Tablet;
- return;
- }
- this.media = Media.Desktop;
- };
-
- constructor() {
- super();
- addResizeListeners(this.setCurrentMedia);
- }
-}
diff --git a/packages/dapp-kit-ui/src/classes/connect-modal-manager.ts b/packages/dapp-kit-ui/src/classes/connect-modal-manager.ts
new file mode 100644
index 00000000..0f5d1300
--- /dev/null
+++ b/packages/dapp-kit-ui/src/classes/connect-modal-manager.ts
@@ -0,0 +1,72 @@
+import type { WalletManager, WalletSource } from '@vechain/dapp-kit';
+import { DAppKitLogger } from '@vechain/dapp-kit';
+import { subscribeKey } from 'valtio/vanilla/utils';
+import { createModalIfNotPresent, dispatchCustomEvent } from '../utils';
+
+export interface ConnectModalManagerOptions {
+ modalParent?: HTMLElement;
+}
+
+export class ConnectModalManager {
+ private static instance: ConnectModalManager | null = null;
+
+ private constructor(
+ private walletManager: WalletManager,
+ options?: ConnectModalManagerOptions,
+ ) {
+ createModalIfNotPresent(options);
+ }
+
+ public static getInstance(
+ walletManager: WalletManager,
+ options?: ConnectModalManagerOptions,
+ ): ConnectModalManager {
+ if (!ConnectModalManager.instance) {
+ ConnectModalManager.instance = new ConnectModalManager(
+ walletManager,
+ options,
+ );
+ }
+
+ return ConnectModalManager.instance;
+ }
+
+ open(): void {
+ DAppKitLogger.debug('ConnectModalManager', 'opening the modal');
+ dispatchCustomEvent('vdk-open-wallet-modal');
+ }
+
+ close(): void {
+ DAppKitLogger.debug('ConnectModalManager', 'closing the modal');
+ dispatchCustomEvent('vdk-close-wallet-modal');
+ }
+
+ closeWalletConnect(): void {
+ DAppKitLogger.debug('ConnectModalManager', 'closing wallet connect');
+ dispatchCustomEvent('vdk-close-wc-qrcode');
+ }
+
+ closeConnectionCertificateRequest(): void {
+ DAppKitLogger.debug(
+ 'ConnectModalManager',
+ 'closing connection certificate request',
+ );
+ dispatchCustomEvent('vdk-close-connection-certificate-request');
+ }
+
+ onConnectionStatusChange(
+ callback: (address: string | null) => void,
+ ): () => void {
+ return subscribeKey(this.walletManager.state, 'address', (address) => {
+ callback(address);
+ });
+ }
+
+ onWalletSelected(
+ callback: (source: WalletSource | null) => void,
+ ): () => void {
+ return subscribeKey(this.walletManager.state, 'source', (source) => {
+ callback(source);
+ });
+ }
+}
diff --git a/packages/dapp-kit-ui/src/classes/custom-wallet-connect-modal.ts b/packages/dapp-kit-ui/src/classes/custom-wallet-connect-modal.ts
new file mode 100644
index 00000000..71a568ab
--- /dev/null
+++ b/packages/dapp-kit-ui/src/classes/custom-wallet-connect-modal.ts
@@ -0,0 +1,85 @@
+import { EventEmitter } from 'events';
+import type {
+ OpenOptions,
+ SubscribeModalState,
+ WCModal,
+} from '@vechain/dapp-kit';
+import { DAppKitLogger } from '@vechain/dapp-kit';
+import { dispatchCustomEvent, subscribeToCustomEvent } from '../utils';
+
+const MODAL_STATE_EVENT = 'vdk-modal-state-change';
+
+export class CustomWalletConnectModal implements WCModal {
+ private static instance: CustomWalletConnectModal | null = null;
+
+ private eventEmitter = new EventEmitter();
+
+ private constructor() {
+ subscribeToCustomEvent('vdk-close-wc-qrcode', () => {
+ this.updateModalState({ open: false });
+ });
+ subscribeToCustomEvent('vdk-open-wc-qrcode', () => {
+ this.updateModalState({ open: true });
+ });
+ }
+
+ static getInstance(): CustomWalletConnectModal {
+ if (!CustomWalletConnectModal.instance) {
+ CustomWalletConnectModal.instance = new CustomWalletConnectModal();
+ }
+
+ return CustomWalletConnectModal.instance;
+ }
+
+ /**
+ * WalletConnect
+ */
+ openModal(options: OpenOptions): Promise {
+ DAppKitLogger.debug('CustomWalletConnectModal', 'opening the wc modal');
+ dispatchCustomEvent('vdk-open-wc-qrcode', options);
+ return Promise.resolve();
+ }
+
+ closeModal(): void {
+ DAppKitLogger.debug('CustomWalletConnectModal', 'closing the modal');
+ dispatchCustomEvent('vdk-close-wc-qrcode');
+ }
+
+ askForConnectionCertificate(): void {
+ DAppKitLogger.debug(
+ 'CustomWalletConnectModal',
+ 'ask for connection certificate',
+ );
+ dispatchCustomEvent('vdk-close-wc-qrcode');
+ dispatchCustomEvent('vdk-request-connection-certificate');
+ }
+
+ onConnectionCertificateSigned(): void {
+ DAppKitLogger.debug(
+ 'CustomWalletConnectModal',
+ 'connection certificate signed',
+ );
+ dispatchCustomEvent('vdk-close-wallet-modal');
+ dispatchCustomEvent('vdk-close-wc-qrcode');
+ dispatchCustomEvent('vdk-close-connection-certificate-request');
+ }
+
+ subscribeModal(
+ callback: (newState: SubscribeModalState) => void,
+ ): () => void {
+ DAppKitLogger.debug(
+ 'CustomWalletConnectModal',
+ 'subscribing to modal state',
+ );
+
+ this.eventEmitter.on(MODAL_STATE_EVENT, callback);
+
+ return () => {
+ this.eventEmitter.off(MODAL_STATE_EVENT, callback);
+ };
+ }
+
+ private updateModalState(state: SubscribeModalState): void {
+ this.eventEmitter.emit(MODAL_STATE_EVENT, state);
+ }
+}
diff --git a/packages/dapp-kit-ui/src/classes/index.ts b/packages/dapp-kit-ui/src/classes/index.ts
new file mode 100644
index 00000000..74211e40
--- /dev/null
+++ b/packages/dapp-kit-ui/src/classes/index.ts
@@ -0,0 +1,2 @@
+export * from './connect-modal-manager';
+export * from './custom-wallet-connect-modal';
diff --git a/packages/dapp-kit-ui/src/client.ts b/packages/dapp-kit-ui/src/client.ts
index 30a5bc2f..7025a3e9 100644
--- a/packages/dapp-kit-ui/src/client.ts
+++ b/packages/dapp-kit-ui/src/client.ts
@@ -1,7 +1,7 @@
///
import type { DAppKitOptions, WalletManager } from '@vechain/dapp-kit';
import { DAppKit } from '@vechain/dapp-kit';
-import { CustomWalletConnectModal, DAppKitModal } from './modal';
+import { CustomWalletConnectModal, ConnectModalManager } from './classes';
import {
type CustomizedStyle,
dispatchCustomEvent,
@@ -34,8 +34,8 @@ export const DAppKitUI = {
dappKitOptions = options;
if (!dappKit) dappKit = new DAppKit(options);
- // init modal so on the first opening it doesn't have to create it
- DAppKitModal.getInstance(this.wallet, {
+ // init modal so that on the first opening it doesn't have to create it
+ ConnectModalManager.getInstance(this.wallet, {
modalParent: options.modalParent,
});
@@ -64,8 +64,8 @@ export const DAppKitUI = {
return this.get().wallet;
},
- get modal(): DAppKitModal {
- return DAppKitModal.getInstance(this.wallet, {
+ get modal(): ConnectModalManager {
+ return ConnectModalManager.getInstance(this.wallet, {
modalParent: dappKitOptions?.modalParent,
});
},
diff --git a/packages/dapp-kit-ui/src/components/modals/address-modal.ts b/packages/dapp-kit-ui/src/components/modals/address-modal.ts
index afa3dc22..3bde7d03 100644
--- a/packages/dapp-kit-ui/src/components/modals/address-modal.ts
+++ b/packages/dapp-kit-ui/src/components/modals/address-modal.ts
@@ -1,7 +1,7 @@
import type { TemplateResult } from 'lit';
import { css, html, LitElement, nothing } from 'lit';
import { customElement, property } from 'lit/decorators.js';
-import type { I18n, SourceInfo } from '../../constants';
+import type { I18n } from '../../constants';
import { defaultI18n, Font } from '../../constants';
import { buttonStyle, iconButtonStyle } from '../../assets/styles';
import type { ThemeMode } from '../../constants/theme';
@@ -112,9 +112,6 @@ export class AddressModal extends LitElement {
@property({ type: String })
address = '';
- @property({ type: Function })
- onSourceClick?: (source?: SourceInfo) => void = undefined;
-
@property({ type: Function })
onDisconnectClick?: () => void = undefined;
diff --git a/packages/dapp-kit-ui/src/components/modals/connect-modal.ts b/packages/dapp-kit-ui/src/components/modals/connect-modal/connect-modal.ts
similarity index 55%
rename from packages/dapp-kit-ui/src/components/modals/connect-modal.ts
rename to packages/dapp-kit-ui/src/components/modals/connect-modal/connect-modal.ts
index afad496f..846eab5e 100644
--- a/packages/dapp-kit-ui/src/components/modals/connect-modal.ts
+++ b/packages/dapp-kit-ui/src/components/modals/connect-modal/connect-modal.ts
@@ -1,7 +1,7 @@
import type { TemplateResult } from 'lit';
import { css, html, LitElement, nothing } from 'lit';
import { customElement, property } from 'lit/decorators.js';
-import type { WalletManager } from '@vechain/dapp-kit';
+import { DAppKitLogger, type WalletManager } from '@vechain/dapp-kit';
import {
type I18n,
type SourceInfo,
@@ -9,16 +9,16 @@ import {
defaultI18n,
Font,
WalletSources,
-} from '../../constants';
+} from '../../../constants';
import {
DarkChevronLeftSvg,
DarkCloseSvg,
LightChevronLeftSvg,
LightCloseSvg,
-} from '../../assets/icons';
-import { isMobile, subscribeToCustomEvent, useTranslate } from '../../utils';
-import { DAppKitUI } from '../../client';
-import { iconButtonStyle } from '../../assets/styles';
+} from '../../../assets/icons';
+import { isMobile, subscribeToCustomEvent, useTranslate } from '../../../utils';
+import { DAppKitUI } from '../../../client';
+import { iconButtonStyle } from '../../../assets/styles';
@customElement('vdk-connect-modal')
export class ConnectModal extends LitElement {
@@ -47,28 +47,10 @@ export class ConnectModal extends LitElement {
`,
];
- @property({ type: Boolean })
- open = false;
-
- @property({ type: Boolean })
- openingVeWorld = false;
-
- @property()
- mode: ThemeMode = 'LIGHT';
-
- @property()
- i18n: I18n = defaultI18n;
-
- @property()
- language = 'en';
-
- @property()
- walletConnectQRcode?: string = undefined;
-
constructor() {
super();
- subscribeToCustomEvent('vdk-open-wc-modal', (options) => {
+ subscribeToCustomEvent('vdk-open-wc-qrcode', (options) => {
if (isMobile()) {
this.openingVeWorld = true;
window.open(
@@ -81,19 +63,25 @@ export class ConnectModal extends LitElement {
this.open = true;
this.walletConnectQRcode = options.uri;
});
-
- subscribeToCustomEvent('vdk-close-wc-modal', () => {
+ subscribeToCustomEvent('vdk-close-wc-qrcode', () => {
this.walletConnectQRcode = undefined;
this.openingVeWorld = false;
});
-
subscribeToCustomEvent('vdk-open-wallet-modal', () => {
this.open = true;
});
-
subscribeToCustomEvent('vdk-close-wallet-modal', () => {
this.open = false;
});
+ subscribeToCustomEvent('vdk-request-connection-certificate', () => {
+ this.requestForConnectionCertificate = true;
+ });
+ subscribeToCustomEvent(
+ 'vdk-close-connection-certificate-request',
+ () => {
+ this.requestForConnectionCertificate = false;
+ },
+ );
}
private get availableSources(): SourceInfo[] {
@@ -109,14 +97,22 @@ export class ConnectModal extends LitElement {
@property({ type: Function })
onSourceClick = (source?: SourceInfo): void => {
if (source) {
+ if (source.id !== 'wallet-connect') {
+ this.setWaitingForTheSignature(true);
+ this.requestForConnectionCertificate = true;
+ }
this.wallet.setSource(source.id);
this.wallet
.connect()
.then(() => {
this.requestUpdate();
})
- .finally(() => {
- DAppKitUI.modal.close();
+ .catch((err): void => {
+ DAppKitLogger.error(
+ 'Connection Attempt',
+ 'error trying to connect',
+ err,
+ );
});
}
};
@@ -124,19 +120,75 @@ export class ConnectModal extends LitElement {
@property({ type: Function })
onClose: () => void = () => nothing;
+ @property({ type: Boolean })
+ open = false;
+
+ @property({ type: Boolean })
+ openingVeWorld = false;
+
+ @property()
+ mode: ThemeMode = 'LIGHT';
+
+ @property()
+ i18n: I18n = defaultI18n;
+
+ @property()
+ language = 'en';
+
+ @property()
+ walletConnectQRcode?: string = undefined;
+
+ @property()
+ requestForConnectionCertificate = false;
+
+ @property()
+ waitingForTheSignature = false;
+
+ private setWaitingForTheSignature = (value: boolean): void => {
+ this.waitingForTheSignature = value;
+ };
+
+ private renderContent(): TemplateResult | TemplateResult[] {
+ if (this.requestForConnectionCertificate) {
+ return html``;
+ }
+ if (this.walletConnectQRcode) {
+ return html` `;
+ }
+ return this.availableSources.map(
+ (source) =>
+ html` `,
+ );
+ }
+
override render(): TemplateResult {
const translate = useTranslate(this.i18n, this.language);
return html`
-
-
+
-
-