Skip to content

Commit

Permalink
feat: vue.js support (#245)
Browse files Browse the repository at this point in the history
  • Loading branch information
tien authored Oct 18, 2024
1 parent 42a81e7 commit 98bb09e
Show file tree
Hide file tree
Showing 74 changed files with 2,299 additions and 111 deletions.
2 changes: 1 addition & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
{ "repo": "tien/reactive-dot" }
],
"privatePackages": false,
"linked": [["@reactive-dot/core", "@reactive-dot/react"]]
"linked": [["@reactive-dot/core", "@reactive-dot/react", "@reactive-dot/vue"]]
}
7 changes: 7 additions & 0 deletions .changeset/modern-lamps-act.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@reactive-dot/core": minor
"@reactive-dot/utils": minor
"@reactive-dot/vue": minor
---

Added Vue integration.
1 change: 1 addition & 0 deletions apps/docs/docusaurus.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const config: Config = {
},
},
"packages/react",
"packages/vue",
"packages/utils",
],
},
Expand Down
4 changes: 2 additions & 2 deletions examples/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"dev": "vite --port 5173",
"build": "vite build",
"lint": "eslint src",
"preview": "vite preview",
"postinstall": "npx papi"
"postinstall": "papi"
},
"dependencies": {
"@polkadot-api/descriptors": "portal:.papi/descriptors",
Expand Down
6 changes: 1 addition & 5 deletions examples/react/src/mutation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,7 @@ export function Mutation() {
) : (
<article>
<h4>Remark</h4>
<button
type="button"
onClick={() => remark()}
disabled={accounts.length === 0}
>
<button type="button" onClick={() => remark()}>
Hello
</button>
<p>
Expand Down
1 change: 1 addition & 0 deletions examples/vue/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dist
3 changes: 3 additions & 0 deletions examples/vue/.papi/descriptors/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*
!.gitignore
!package.json
24 changes: 24 additions & 0 deletions examples/vue/.papi/descriptors/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"version": "0.1.0-autogenerated.2857293709118977602",
"name": "@polkadot-api/descriptors",
"files": [
"dist"
],
"exports": {
".": {
"types": "./dist/index.d.ts",
"module": "./dist/index.mjs",
"import": "./dist/index.mjs",
"require": "./dist/index.js"
},
"./package.json": "./package.json"
},
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"browser": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"sideEffects": false,
"peerDependencies": {
"polkadot-api": "*"
}
}
Binary file added examples/vue/.papi/metadata/kusama.scale
Binary file not shown.
Binary file added examples/vue/.papi/metadata/polkadot.scale
Binary file not shown.
Binary file added examples/vue/.papi/metadata/westend.scale
Binary file not shown.
18 changes: 18 additions & 0 deletions examples/vue/.papi/polkadot-api.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"version": 0,
"descriptorPath": ".papi/descriptors",
"entries": {
"polkadot": {
"chain": "polkadot",
"metadata": ".papi/metadata/polkadot.scale"
},
"kusama": {
"chain": "ksmcc3",
"metadata": ".papi/metadata/kusama.scale"
},
"westend": {
"chain": "westend2",
"metadata": ".papi/metadata/westend.scale"
}
}
}
4 changes: 4 additions & 0 deletions examples/vue/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import recommended from "@reactive-dot/eslint-config/vue.js";
import tseslint from "typescript-eslint";

export default tseslint.config(...recommended);
12 changes: 12 additions & 0 deletions examples/vue/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>ReactiveDOT demo</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="./src/index.ts"></script>
</body>
</html>
27 changes: 27 additions & 0 deletions examples/vue/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "@reactive-dot/example-vue",
"private": true,
"type": "module",
"scripts": {
"dev": "vite --port 5174",
"build": "vite build",
"lint": "eslint src",
"preview": "vite preview",
"postinstall": "papi"
},
"dependencies": {
"@polkadot-api/descriptors": "portal:.papi/descriptors",
"@reactive-dot/vue": "workspace:^",
"polkadot-api": "^1.4.1",
"vue": "^3.5.12"
},
"devDependencies": {
"@reactive-dot/eslint-config": "workspace:^",
"@tsconfig/recommended": "^1.0.7",
"@tsconfig/strictest": "^2.0.5",
"@vitejs/plugin-vue": "^5.1.4",
"eslint": "^9.12.0",
"typescript": "^5.6.2",
"vite": "^5.4.8"
}
}
58 changes: 58 additions & 0 deletions examples/vue/src/app.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<script setup lang="ts">
import MutationSection from "./mutation-section.vue";
import QuerySection from "./query-section.vue";
import WalletConnection from "./wallet-connection.vue";
import type { ChainId } from "@reactive-dot/core";
import {
provideChain,
useChainIds,
useQueryErrorResetter,
watchMutationEffect,
} from "@reactive-dot/vue";
import { onErrorCaptured, ref } from "vue";
const chainIds = useChainIds();
const selectedChainId = ref<ChainId>("polkadot");
provideChain(selectedChainId);
const hasError = ref(false);
const resetError = useQueryErrorResetter();
onErrorCaptured(() => (hasError.value = true));
// Useful tracking all submitted transaction, i.e. for toast notification
watchMutationEffect((event) => console.log(event));
</script>

<template>
<div>
<label>
Chain
<select v-model="selectedChainId">
<option v-for="chainId in chainIds" :key="chainId" :value="chainId">
{{ chainId }}
</option>
</select>
</label>
</div>
<article v-if="hasError">
<header>
<strong>Oops, something went wrong!</strong>
</header>
<button
@click="
resetError();
hasError = false;
"
>
Retry
</button>
</article>
<Suspense v-else :key="selectedChainId">
<div>
<WalletConnection />
<QuerySection />
<MutationSection />
</div>
<template #fallback>Loading...</template>
</Suspense>
</template>
43 changes: 43 additions & 0 deletions examples/vue/src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { kusama, polkadot, westend } from "@polkadot-api/descriptors";
import type { Config } from "@reactive-dot/core";
import { InjectedWalletAggregator } from "@reactive-dot/core/wallets.js";
import { getSmProvider } from "polkadot-api/sm-provider";
import { startFromWorker } from "polkadot-api/smoldot/from-worker";

const smoldotPromise = startFromWorker(
new Worker(new URL("polkadot-api/smoldot/worker", import.meta.url), {
type: "module",
}),
);

export const config = {
chains: {
polkadot: {
descriptor: polkadot,
provider: getSmProvider(
import("polkadot-api/chains/polkadot").then(({ chainSpec }) =>
smoldotPromise.addChain({ chainSpec }),
),
),
},
kusama: {
descriptor: kusama,
provider: getSmProvider(
import("polkadot-api/chains/ksmcc3").then(({ chainSpec }) =>
smoldotPromise.addChain({ chainSpec }),
),
),
},
westend: {
descriptor: westend,
provider: getSmProvider(
import("polkadot-api/chains/westend2").then(({ chainSpec }) =>
smoldotPromise.addChain({ chainSpec }),
),
),
},
},
wallets: [
new InjectedWalletAggregator({ originName: "ReactiveDOT Vue Example" }),
],
} as const satisfies Config;
6 changes: 6 additions & 0 deletions examples/vue/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import App from "./app.vue";
import { config } from "./config.js";
import { ReactiveDotPlugin } from "@reactive-dot/vue";
import { createApp } from "vue";

createApp(App).use(ReactiveDotPlugin, config).mount("#root");
51 changes: 51 additions & 0 deletions examples/vue/src/mutation-section.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<script setup lang="ts">
import { useAccounts, useMutation } from "@reactive-dot/vue";
import { Binary } from "polkadot-api";
import { computed, ref } from "vue";
const { data: accounts } = await useAccounts();
const selectedAccountIndex = ref(0);
const selectedAccount = computed(() =>
accounts.value.at(selectedAccountIndex.value),
);
const { execute, data, status } = useMutation(
(tx) =>
tx.System.remark({ remark: Binary.fromText("Hello from reactive-dot!") }),
{ signer: computed(() => selectedAccount.value?.polkadotSigner) },
);
</script>

<template>
<section>
<header>
<h3>Mutation</h3>
</header>
<article>
<header><h4>Signer</h4></header>
<p v-if="accounts.length === 0">Please connect a wallet</p>
<select v-else v-model="selectedAccountIndex">
<option
v-for="(account, index) in accounts"
:key="account.id"
:value="index"
>
{{ account.name ?? account.address }}
</option>
</select>
</article>
<template v-if="accounts.length > 0">
<p v-if="selectedAccount === undefined">Please select an account</p>
<article v-else>
<header><h4>Remark</h4></header>
<button @click="execute()">Hello</button>
<p v-if="status === 'pending'">Submitting transaction...</p>
<p v-else-if="status === 'error'">Error submitting transaction</p>
<p v-else-if="status === 'success'">
Submitted tx {{ data?.txHash }} is {{ data?.type }}
</p>
</article>
</template>
</section>
</template>
35 changes: 35 additions & 0 deletions examples/vue/src/query-section.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<script setup lang="ts">
import { useAccounts, useQuery } from "@reactive-dot/vue";
const { data: accounts } = await useAccounts();
const { data } = await useQuery((builder) =>
builder
.readStorage("System", "Number", [])
.readStorage("Balances", "TotalIssuance", [])
.readStorages(
"System",
"Account",
accounts.value?.map((account) => [account.address] as const) ?? [],
),
);
</script>

<template>
<section>
<header>
<h3>Query</h3>
</header>
<dl>
<dt>Height</dt>
<dd>{{ data[0].toLocaleString() }}</dd>

<dt>Total issuance</dt>
<dd>{{ data[1].toLocaleString() }}</dd>

<div v-for="(balance, index) in data[2]" :key="index">
<dt>Balance of: {{ accounts?.at(index)?.address }}</dt>
<dd>{{ balance.data.free.toLocaleString() }}</dd>
</div>
</dl>
</section>
</template>
7 changes: 7 additions & 0 deletions examples/vue/src/reactive-dot.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { config } from "./config.js";
import type { InferChains } from "@reactive-dot/core";

declare module "@reactive-dot/core" {
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
export interface Chains extends InferChains<typeof config> {}
}
1 change: 1 addition & 0 deletions examples/vue/src/vite-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/// <reference types="vite/client" />
Loading

0 comments on commit 98bb09e

Please sign in to comment.