Skip to content

Commit

Permalink
feat: example-vue
Browse files Browse the repository at this point in the history
  • Loading branch information
btcSteven committed Sep 19, 2024
1 parent d237efd commit e799aa2
Show file tree
Hide file tree
Showing 37 changed files with 931 additions and 202 deletions.
File renamed without changes.
24 changes: 24 additions & 0 deletions packages/example-vue/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
File renamed without changes.
File renamed without changes.
File renamed without changes.
36 changes: 36 additions & 0 deletions packages/example-vue/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "example-vue",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"test": "vitest run",
"test:watch": "vitest"
},
"dependencies": {
"vue": "^3.4.37",
"vue-router": "4.4.3",
"@cosmos-kit/core": "^2.12.0",
"@cosmos-kit/keplr": "^2.10.1",
"@cosmos-kit/react": "2.12.0",
"@interchain-ui/vue": "^1.2.55",
"@dao-dao/cosmiframe": "^0.1.0",
"@testing-library/jest-dom": "5.14.1",
"vite-plugin-node-polyfills": "^0.22.0",
"element-plus": "^2.8.1"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.1.2",
"@vue/test-utils": "^2.3.3",
"@chain-registry/types": "^0.41.3",
"buffer": "^6.0.3",
"vite": "^5.4.1",
"jsdom": "^21.1.0"
},
"vitest": {
"environment": "jsdom"
}
}
File renamed without changes.
File renamed without changes
5 changes: 2 additions & 3 deletions packages/vue/src/App.vue → packages/example-vue/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div id="app">
<h1>Welcome to My Vue 3 App</h1>
<h1>Welcome to Example-Vue</h1>
<ChainProvider
:chains="chains"
:wallets="wallets"
Expand All @@ -15,11 +15,10 @@
</template>

<script setup>
import ChainProvider from "./providers/ChainProvider.vue";
import { ChainProvider } from "../../vue";
import CustomModal from "./components/CustomModal.vue";
import { assets as _assets, chains as _chains } from "chain-registry";
import { wallets as keplrExtension } from "@cosmos-kit/keplr-extension";
// import { wallets as _wallets } from "@cosmos-kit/keplr";
const chains = [..._chains];
const wallets = [...keplrExtension];
Expand Down
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions packages/example-vue/src/types/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./provider";
32 changes: 32 additions & 0 deletions packages/example-vue/src/types/provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { WalletManager } from "@cosmos-kit/core";
import { Ref } from "vue";

import {
ConnectModal,
ThemeProvider,
ThemeProviderProps,
} from "@interchain-ui/react";

export type ModalViewImpl = {
head: React.ReactNode;
content: React.ReactNode;
};

export type WalletManagerContext = {
walletManager: WalletManager;
isViewOpen: Ref<boolean>;
modalProvided: boolean;
};

export type ModalCustomizationProps = {
modalContainerClassName?: string;
modalContentClassName?: string;
modalChildrenClassName?: string;
modalContentStyles?: React.CSSProperties;
};

export type ThemeCustomizationProps = ModalCustomizationProps &
Pick<
ThemeProviderProps,
"defaultTheme" | "overrides" | "themeDefs" | "customTheme"
>;
238 changes: 238 additions & 0 deletions packages/example-vue/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
import {
ChainWalletBase,
ChainWalletContext,
DisconnectOptions,
WalletStatus,
} from "@cosmos-kit/core";

export function getChainWalletContext(
chainId: string,
wallet?: ChainWalletBase,
sync = true
): ChainWalletContext {
const walletAssert = (
func: ((...params: any[]) => any | undefined) | undefined,
params: any[] = [],
name: string
) => {
if (!wallet) {
throw new Error(
`Wallet is undefined. Please choose a wallet to connect first.`
);
}

if (!func) {
throw new Error(
`Function ${name} not implemented by ${wallet?.walletInfo.prettyName} yet.`
);
}

return func(...params);
};

function clientMethodAssert(
func: ((...params: any[]) => any | undefined) | undefined,
params: any[] = [],
name: string
) {
if (!wallet) {
throw new Error(
`Wallet is undefined. Please choose a wallet to connect first.`
);
}

if (!wallet?.client) {
throw new Error(`Wallet Client is undefined.`);
}

if (!func) {
throw new Error(
`Function ${name} not implemented by ${wallet?.walletInfo.prettyName} Client yet.`
);
}

return func(...params);
}

const status = wallet?.walletStatus || WalletStatus.Disconnected;

return {
chainWallet: wallet,

chain: wallet?.chainRecord.chain,
assets: wallet?.chainRecord.assetList,
logoUrl: wallet?.chainLogoUrl,
wallet: wallet?.walletInfo,
address: wallet?.address,
username: wallet?.username,
message: wallet ? wallet.message : "No wallet is connected walletly.",
status,

isWalletDisconnected: status === "Disconnected",
isWalletConnecting: status === "Connecting",
isWalletConnected: status === "Connected",
isWalletRejected: status === "Rejected",
isWalletNotExist: status === "NotExist",
isWalletError: status === "Error",

connect: () => walletAssert(wallet?.connect, [void 0, sync], "connect"),
disconnect: (options?: DisconnectOptions) =>
walletAssert(wallet?.disconnect, [void 0, sync, options], "disconnect"),
getRpcEndpoint: (isLazy?: boolean) =>
walletAssert(wallet?.getRpcEndpoint, [isLazy], "getRpcEndpoint"),
getRestEndpoint: (isLazy?: boolean) =>
walletAssert(wallet?.getRestEndpoint, [isLazy], "getRestEndpoint"),
getStargateClient: () =>
walletAssert(wallet?.getStargateClient, [], "getStargateClient"),
getCosmWasmClient: () =>
walletAssert(wallet?.getCosmWasmClient, [], "getCosmWasmClient"),
getSigningStargateClient: () =>
walletAssert(
wallet?.getSigningStargateClient,
[],
"getSigningStargateClient"
),
getSigningCosmWasmClient: () =>
walletAssert(
wallet?.getSigningCosmWasmClient,
[],
"getSigningCosmWasmClient"
),
getNameService: () =>
walletAssert(wallet?.getNameService, [], "getNameService"),

estimateFee: (...params: Parameters<ChainWalletContext["estimateFee"]>) =>
walletAssert(wallet?.estimateFee, params, "estimateFee"),
sign: (...params: Parameters<ChainWalletContext["sign"]>) =>
walletAssert(wallet?.sign, params, "sign"),
broadcast: (...params: Parameters<ChainWalletContext["broadcast"]>) =>
walletAssert(wallet?.broadcast, params, "broadcast"),
signAndBroadcast: (
...params: Parameters<ChainWalletContext["signAndBroadcast"]>
) => walletAssert(wallet?.signAndBroadcast, params, "signAndBroadcast"),

qrUrl: wallet?.client?.qrUrl,
appUrl: wallet?.client?.appUrl,

defaultSignOptions: wallet?.client?.defaultSignOptions,
setDefaultSignOptions: (
...params: Parameters<ChainWalletContext["setDefaultSignOptions"]>
) =>
clientMethodAssert(
wallet?.client?.setDefaultSignOptions.bind(wallet.client),
[...params],
"setDefaultSignOptions"
),
enable: () =>
clientMethodAssert(
wallet?.client?.enable.bind(wallet.client),
[chainId],
"enable"
),
suggestToken: (...params: Parameters<ChainWalletContext["suggestToken"]>) =>
clientMethodAssert(
wallet?.client?.suggestToken.bind(wallet.client),
[...params],
"suggestToken"
),
getAccount: () =>
clientMethodAssert(
wallet?.client?.getAccount.bind(wallet.client),
[chainId],
"getAccount"
),
getOfflineSigner: () =>
clientMethodAssert(
wallet?.client?.getOfflineSigner.bind(wallet.client),
[chainId, wallet?.preferredSignType],
"getOfflineSigner"
),
getOfflineSignerAmino: () =>
clientMethodAssert(
wallet?.client?.getOfflineSignerAmino.bind(wallet.client),
[chainId],
"getOfflineSignerAmino"
),
getOfflineSignerDirect: () =>
clientMethodAssert(
wallet?.client?.getOfflineSignerDirect.bind(wallet.client),
[chainId],
"getOfflineSignerDirect"
),
signAmino: (...params: Parameters<ChainWalletContext["signAmino"]>) =>
clientMethodAssert(
wallet?.client?.signAmino.bind(wallet.client),
[chainId, ...params],
"signAmino"
),
signDirect: (...params: Parameters<ChainWalletContext["signDirect"]>) =>
clientMethodAssert(
wallet?.client?.signDirect.bind(wallet.client),
[chainId, ...params],
"signDirect"
),
signArbitrary: (
...params: Parameters<ChainWalletContext["signArbitrary"]>
) =>
clientMethodAssert(
wallet?.client?.signArbitrary.bind(wallet.client),
[chainId, ...params],
"signArbitrary"
),
sendTx: (...params: Parameters<ChainWalletContext["sendTx"]>) =>
clientMethodAssert(
wallet?.client?.sendTx.bind(wallet.client),
[chainId, ...params],
"sendTx"
),
};
}

// Listen for a message and remove the listener if the callback returns true or
// if it throws an error.
export const listenOnce = (
callback: (message: unknown) => boolean | Promise<boolean>
) => {
const listener = async ({ data }: MessageEvent) => {
let remove;
try {
remove = await callback(data);
} catch (error) {
console.error(error);
remove = true;
}

if (remove) {
window.removeEventListener("message", listener);
}
};

window.addEventListener("message", listener);
};

// Send message to iframe and listen for a response. Returns a promise that
// resolves when the callback returns true and rejects if it throws an error.
export const sendAndListenOnce = (
iframe: HTMLIFrameElement,
message: unknown,
callback: (message: unknown) => boolean | Promise<boolean>
): Promise<void> =>
new Promise<void>((resolve, reject) => {
// Add one-time listener that waits for a response.
listenOnce(async (data) => {
try {
if (await callback(data)) {
resolve();
return true;
} else {
return false;
}
} catch (err) {
reject(err);
return true;
}
});

// Send the message to the iframe.
iframe.contentWindow.postMessage(message);
});
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import {
useWalletClient,
useIframe,
useModalTheme,
} from "./../composables";
} from "../../../vue";
const { modalTheme, setModalTheme } = useModalTheme();
const resolvedName = ref<any>(null);
Expand Down
19 changes: 19 additions & 0 deletions packages/example-vue/vite.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
import { nodePolyfills } from 'vite-plugin-node-polyfills';

export default defineConfig({
plugins: [vue(), nodePolyfills({
buffer: true,
}),],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
buffer: 'buffer',
},
},
optimizeDeps: {
include: ['buffer'],
},
})
7 changes: 7 additions & 0 deletions packages/vue/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
node_modules/
dist/
main/
module/
types/
coverage/
/index.ts
Loading

0 comments on commit e799aa2

Please sign in to comment.