@1001-digital/components 0.0.1
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/package.json +45 -0
- package/src/base/components/Actions.vue +57 -0
- package/src/base/components/Alert.vue +90 -0
- package/src/base/components/Button.vue +260 -0
- package/src/base/components/Card.vue +78 -0
- package/src/base/components/CardLink.vue +56 -0
- package/src/base/components/Dialog.vue +274 -0
- package/src/base/components/Dropdown.vue +167 -0
- package/src/base/components/DropdownCheckboxItem.vue +30 -0
- package/src/base/components/DropdownGroup.vue +9 -0
- package/src/base/components/DropdownItem.vue +23 -0
- package/src/base/components/DropdownLabel.vue +9 -0
- package/src/base/components/DropdownRadioGroup.vue +15 -0
- package/src/base/components/DropdownRadioItem.vue +29 -0
- package/src/base/components/DropdownSeparator.vue +7 -0
- package/src/base/components/DropdownSub.vue +58 -0
- package/src/base/components/Form.vue +27 -0
- package/src/base/components/FormCheckbox.vue +92 -0
- package/src/base/components/FormGroup.vue +39 -0
- package/src/base/components/FormInputGroup.vue +55 -0
- package/src/base/components/FormItem.vue +89 -0
- package/src/base/components/FormLabel.vue +39 -0
- package/src/base/components/FormRadioGroup.vue +118 -0
- package/src/base/components/FormSelect.vue +160 -0
- package/src/base/components/FormTextarea.vue +38 -0
- package/src/base/components/Icon.vue +29 -0
- package/src/base/components/Loading.vue +81 -0
- package/src/base/components/Popover.vue +182 -0
- package/src/base/components/Tag.vue +56 -0
- package/src/base/components/Tags.vue +13 -0
- package/src/base/components/Toasts.vue +254 -0
- package/src/base/components/Tooltip.vue +100 -0
- package/src/base/composables/time.ts +82 -0
- package/src/base/composables/toast.ts +40 -0
- package/src/base/icons.ts +20 -0
- package/src/base/link.ts +4 -0
- package/src/base/utils/format-number.ts +29 -0
- package/src/base/utils/time.ts +20 -0
- package/src/evm/components/EvmAccount.vue +28 -0
- package/src/evm/components/EvmConnect.vue +254 -0
- package/src/evm/components/EvmConnectorQR.vue +116 -0
- package/src/evm/components/EvmMetaMaskQR.vue +15 -0
- package/src/evm/components/EvmTransactionFlow.vue +327 -0
- package/src/evm/components/EvmWalletConnectQR.vue +13 -0
- package/src/evm/composables/base.ts +7 -0
- package/src/evm/composables/chainId.ts +41 -0
- package/src/evm/config.ts +32 -0
- package/src/evm/index.ts +25 -0
- package/src/evm/utils/addresses.ts +6 -0
- package/src/evm/utils/chains.ts +32 -0
- package/src/evm/utils/format-eth.ts +15 -0
- package/src/index.ts +68 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<slot
|
|
3
|
+
:start="start"
|
|
4
|
+
:step="step"
|
|
5
|
+
:open="open"
|
|
6
|
+
name="start"
|
|
7
|
+
></slot>
|
|
8
|
+
|
|
9
|
+
<Dialog
|
|
10
|
+
v-model:open="open"
|
|
11
|
+
:closable="canDismiss"
|
|
12
|
+
:click-outside="canDismiss"
|
|
13
|
+
:title="text.title[step]"
|
|
14
|
+
class="transaction-flow"
|
|
15
|
+
>
|
|
16
|
+
<slot name="before" />
|
|
17
|
+
|
|
18
|
+
<Loading
|
|
19
|
+
v-if="step === 'requesting'"
|
|
20
|
+
spinner
|
|
21
|
+
stacked
|
|
22
|
+
:txt="text.lead[step] || ''"
|
|
23
|
+
/>
|
|
24
|
+
|
|
25
|
+
<p
|
|
26
|
+
v-if="
|
|
27
|
+
step !== 'requesting' &&
|
|
28
|
+
step !== 'error' &&
|
|
29
|
+
text.lead[step]
|
|
30
|
+
"
|
|
31
|
+
>
|
|
32
|
+
{{ text.lead[step] }}
|
|
33
|
+
</p>
|
|
34
|
+
|
|
35
|
+
<Alert
|
|
36
|
+
v-if="error"
|
|
37
|
+
type="error"
|
|
38
|
+
>
|
|
39
|
+
<p v-if="text.lead[step]">{{ text.lead[step] }}</p>
|
|
40
|
+
<p>{{ error }}</p>
|
|
41
|
+
</Alert>
|
|
42
|
+
|
|
43
|
+
<slot
|
|
44
|
+
:name="step"
|
|
45
|
+
:cancel="cancel"
|
|
46
|
+
></slot>
|
|
47
|
+
|
|
48
|
+
<template #footer>
|
|
49
|
+
<template v-if="step === 'chain'">
|
|
50
|
+
<Button
|
|
51
|
+
@click="cancel"
|
|
52
|
+
class="secondary"
|
|
53
|
+
>Cancel</Button
|
|
54
|
+
>
|
|
55
|
+
</template>
|
|
56
|
+
|
|
57
|
+
<template v-if="step === 'confirm' || step === 'error'">
|
|
58
|
+
<Button
|
|
59
|
+
@click="cancel"
|
|
60
|
+
class="secondary"
|
|
61
|
+
>Cancel</Button
|
|
62
|
+
>
|
|
63
|
+
<Button @click="() => initializeRequest()">
|
|
64
|
+
{{ text.action[step] || 'Execute' }}
|
|
65
|
+
</Button>
|
|
66
|
+
</template>
|
|
67
|
+
|
|
68
|
+
<slot
|
|
69
|
+
name="actions"
|
|
70
|
+
:step="step"
|
|
71
|
+
:cancel="cancel"
|
|
72
|
+
:execute="() => initializeRequest()"
|
|
73
|
+
:tx-link="txLink"
|
|
74
|
+
/>
|
|
75
|
+
</template>
|
|
76
|
+
</Dialog>
|
|
77
|
+
</template>
|
|
78
|
+
|
|
79
|
+
<script setup lang="ts">
|
|
80
|
+
import { ref, computed, watch, onBeforeUnmount } from 'vue'
|
|
81
|
+
import { waitForTransactionReceipt, watchChainId } from '@wagmi/core'
|
|
82
|
+
import { useConfig, type Config } from '@wagmi/vue'
|
|
83
|
+
import type { TransactionReceipt, Hash } from 'viem'
|
|
84
|
+
import Dialog from '../../base/components/Dialog.vue'
|
|
85
|
+
import Loading from '../../base/components/Loading.vue'
|
|
86
|
+
import Alert from '../../base/components/Alert.vue'
|
|
87
|
+
import Button from '../../base/components/Button.vue'
|
|
88
|
+
import { useEnsureChainIdCheck, useBlockExplorer } from '../composables/chainId'
|
|
89
|
+
import { useToast } from '../../base/composables/toast'
|
|
90
|
+
import { delay } from '../../base/utils/time'
|
|
91
|
+
|
|
92
|
+
interface TextConfig {
|
|
93
|
+
title?: Record<string, string>
|
|
94
|
+
lead?: Record<string, string>
|
|
95
|
+
action?: Record<string, string>
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
type Step =
|
|
99
|
+
| 'idle'
|
|
100
|
+
| 'confirm'
|
|
101
|
+
| 'chain'
|
|
102
|
+
| 'requesting'
|
|
103
|
+
| 'waiting'
|
|
104
|
+
| 'complete'
|
|
105
|
+
| 'error'
|
|
106
|
+
|
|
107
|
+
const defaultText = {
|
|
108
|
+
title: {
|
|
109
|
+
confirm: 'Confirm Transaction',
|
|
110
|
+
chain: 'Switch Network',
|
|
111
|
+
requesting: 'Requesting',
|
|
112
|
+
waiting: 'Processing',
|
|
113
|
+
complete: 'Complete',
|
|
114
|
+
error: 'Error',
|
|
115
|
+
},
|
|
116
|
+
lead: {
|
|
117
|
+
confirm: 'Please review and confirm this transaction.',
|
|
118
|
+
chain: 'Please switch to the correct network to continue.',
|
|
119
|
+
requesting: 'Requesting transaction signature...',
|
|
120
|
+
waiting: 'Waiting for transaction confirmation...',
|
|
121
|
+
complete: 'Transaction confirmed successfully.',
|
|
122
|
+
},
|
|
123
|
+
action: {
|
|
124
|
+
confirm: 'Execute',
|
|
125
|
+
error: 'Try Again',
|
|
126
|
+
},
|
|
127
|
+
} satisfies TextConfig
|
|
128
|
+
|
|
129
|
+
const checkChain = useEnsureChainIdCheck()
|
|
130
|
+
|
|
131
|
+
const wagmiConfig = useConfig()
|
|
132
|
+
const blockExplorer = useBlockExplorer()
|
|
133
|
+
const toast = useToast()
|
|
134
|
+
|
|
135
|
+
const props = withDefaults(
|
|
136
|
+
defineProps<{
|
|
137
|
+
text?: TextConfig
|
|
138
|
+
request?: () => Promise<Hash>
|
|
139
|
+
delayAfter?: number
|
|
140
|
+
delayAutoclose?: number
|
|
141
|
+
skipConfirmation?: boolean
|
|
142
|
+
autoCloseSuccess?: boolean
|
|
143
|
+
dismissable?: boolean
|
|
144
|
+
}>(),
|
|
145
|
+
{
|
|
146
|
+
delayAfter: 2000,
|
|
147
|
+
delayAutoclose: 2000,
|
|
148
|
+
skipConfirmation: false,
|
|
149
|
+
autoCloseSuccess: true,
|
|
150
|
+
dismissable: true,
|
|
151
|
+
},
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
const emit = defineEmits<{
|
|
155
|
+
complete: [receipt: TransactionReceipt]
|
|
156
|
+
cancel: []
|
|
157
|
+
}>()
|
|
158
|
+
|
|
159
|
+
const text = computed<Required<TextConfig>>(() => ({
|
|
160
|
+
title: { ...defaultText.title, ...props.text?.title },
|
|
161
|
+
lead: { ...defaultText.lead, ...props.text?.lead },
|
|
162
|
+
action: { ...defaultText.action, ...props.text?.action },
|
|
163
|
+
}))
|
|
164
|
+
|
|
165
|
+
const step = ref<Step>('idle')
|
|
166
|
+
|
|
167
|
+
const open = computed({
|
|
168
|
+
get: () => step.value !== 'idle',
|
|
169
|
+
set: (v) => {
|
|
170
|
+
if (!v) {
|
|
171
|
+
step.value = 'idle'
|
|
172
|
+
error.value = ''
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
watchChainId(wagmiConfig as Config, {
|
|
178
|
+
async onChange() {
|
|
179
|
+
if (step.value !== 'chain') return
|
|
180
|
+
|
|
181
|
+
if (await checkChain()) {
|
|
182
|
+
initializeRequest()
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
const cachedRequest = ref(props.request)
|
|
188
|
+
watch(
|
|
189
|
+
() => props.request,
|
|
190
|
+
(v) => {
|
|
191
|
+
cachedRequest.value = v
|
|
192
|
+
},
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
const error = ref('')
|
|
196
|
+
const tx = ref<Hash | null>(null)
|
|
197
|
+
const receipt = ref<TransactionReceipt | null>(null)
|
|
198
|
+
const txLink = computed(() => `${blockExplorer}/tx/${tx.value}`)
|
|
199
|
+
|
|
200
|
+
let mounted = true
|
|
201
|
+
onBeforeUnmount(() => {
|
|
202
|
+
mounted = false
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
const canDismiss = computed(
|
|
206
|
+
() =>
|
|
207
|
+
props.dismissable &&
|
|
208
|
+
step.value !== 'requesting',
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
const initializeRequest = async (request = cachedRequest.value) => {
|
|
212
|
+
cachedRequest.value = request
|
|
213
|
+
error.value = ''
|
|
214
|
+
tx.value = null
|
|
215
|
+
receipt.value = null
|
|
216
|
+
step.value = 'confirm'
|
|
217
|
+
|
|
218
|
+
if (!(await checkChain())) {
|
|
219
|
+
step.value = 'chain'
|
|
220
|
+
return
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Phase 1: Signing (dialog)
|
|
224
|
+
try {
|
|
225
|
+
step.value = 'requesting'
|
|
226
|
+
tx.value = await request!()
|
|
227
|
+
} catch (e: unknown) {
|
|
228
|
+
const err = e as { cause?: { code?: number }; shortMessage?: string }
|
|
229
|
+
if (err?.cause?.code === 4001) {
|
|
230
|
+
error.value = 'Transaction rejected by user.'
|
|
231
|
+
} else {
|
|
232
|
+
error.value = err.shortMessage || 'Error submitting transaction request.'
|
|
233
|
+
}
|
|
234
|
+
step.value = 'error'
|
|
235
|
+
console.log(e)
|
|
236
|
+
return
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Phase 2: Receipt (toast)
|
|
240
|
+
step.value = 'idle'
|
|
241
|
+
|
|
242
|
+
const link = `${blockExplorer}/tx/${tx.value}`
|
|
243
|
+
const toastId = toast.add({
|
|
244
|
+
variant: 'info',
|
|
245
|
+
title: text.value.title.waiting,
|
|
246
|
+
description: text.value.lead.waiting,
|
|
247
|
+
duration: Infinity,
|
|
248
|
+
action: {
|
|
249
|
+
label: 'View on Block Explorer',
|
|
250
|
+
onClick: () => window.open(link, '_blank'),
|
|
251
|
+
},
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
try {
|
|
255
|
+
const receiptObject = await waitForTransactionReceipt(
|
|
256
|
+
wagmiConfig as Config,
|
|
257
|
+
{ hash: tx.value },
|
|
258
|
+
)
|
|
259
|
+
await delay(props.delayAfter)
|
|
260
|
+
receipt.value = receiptObject
|
|
261
|
+
emit('complete', receiptObject)
|
|
262
|
+
|
|
263
|
+
toast.update(toastId, {
|
|
264
|
+
variant: 'success',
|
|
265
|
+
title: text.value.title.complete,
|
|
266
|
+
description: text.value.lead.complete,
|
|
267
|
+
...(props.autoCloseSuccess && { duration: props.delayAutoclose }),
|
|
268
|
+
})
|
|
269
|
+
} catch (e: unknown) {
|
|
270
|
+
const err = e as { shortMessage?: string }
|
|
271
|
+
if (mounted) {
|
|
272
|
+
toast.dismiss(toastId)
|
|
273
|
+
error.value = err.shortMessage || 'Transaction failed.'
|
|
274
|
+
step.value = 'error'
|
|
275
|
+
} else {
|
|
276
|
+
toast.update(toastId, {
|
|
277
|
+
variant: 'error',
|
|
278
|
+
title: text.value.title.error,
|
|
279
|
+
description: err.shortMessage || 'Transaction failed.',
|
|
280
|
+
})
|
|
281
|
+
}
|
|
282
|
+
console.log(e)
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return receipt.value
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const start = () => {
|
|
289
|
+
if (props.skipConfirmation && step.value === 'idle') {
|
|
290
|
+
initializeRequest()
|
|
291
|
+
return
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
step.value = 'confirm'
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const cancel = () => {
|
|
298
|
+
step.value = 'idle'
|
|
299
|
+
error.value = ''
|
|
300
|
+
emit('cancel')
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
defineExpose({
|
|
304
|
+
initializeRequest,
|
|
305
|
+
})
|
|
306
|
+
</script>
|
|
307
|
+
|
|
308
|
+
<style>
|
|
309
|
+
.transaction-flow > section {
|
|
310
|
+
display: grid;
|
|
311
|
+
gap: var(--spacer);
|
|
312
|
+
|
|
313
|
+
.text {
|
|
314
|
+
width: 100%;
|
|
315
|
+
height: min-content;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
p {
|
|
319
|
+
white-space: pre-wrap;
|
|
320
|
+
width: 100%;
|
|
321
|
+
|
|
322
|
+
a {
|
|
323
|
+
text-decoration: underline;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
</style>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<EvmConnectorQR :uri="uri">
|
|
3
|
+
<template #instruction> Scan the code in your wallet application </template>
|
|
4
|
+
</EvmConnectorQR>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script setup lang="ts">
|
|
8
|
+
import EvmConnectorQR from './EvmConnectorQR.vue'
|
|
9
|
+
|
|
10
|
+
defineProps<{
|
|
11
|
+
uri: string
|
|
12
|
+
}>()
|
|
13
|
+
</script>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { useConnection, useSwitchChain } from '@wagmi/vue'
|
|
2
|
+
import { useEvmConfig } from '../config'
|
|
3
|
+
|
|
4
|
+
interface ChainConfig {
|
|
5
|
+
id: number
|
|
6
|
+
blockExplorer: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const useChainConfig = (key?: string): ChainConfig => {
|
|
10
|
+
const evmConfig = useEvmConfig()
|
|
11
|
+
const resolvedKey = key || evmConfig.defaultChain || 'mainnet'
|
|
12
|
+
const chain = evmConfig.chains[resolvedKey]
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
id: chain?.id ?? 1,
|
|
16
|
+
blockExplorer: chain?.blockExplorer ?? 'https://etherscan.io',
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const useMainChainId = () => useChainConfig().id
|
|
21
|
+
|
|
22
|
+
export const useBlockExplorer = (key?: string) =>
|
|
23
|
+
useChainConfig(key).blockExplorer
|
|
24
|
+
|
|
25
|
+
export const useEnsureChainIdCheck = () => {
|
|
26
|
+
const chainId = useMainChainId()
|
|
27
|
+
const { mutate: switchChain } = useSwitchChain()
|
|
28
|
+
const { chainId: currentChainId } = useConnection()
|
|
29
|
+
|
|
30
|
+
return async () => {
|
|
31
|
+
if (chainId !== currentChainId.value) {
|
|
32
|
+
switchChain({ chainId })
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (chainId === currentChainId.value) {
|
|
36
|
+
return true
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return false
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { inject, type InjectionKey } from 'vue'
|
|
2
|
+
|
|
3
|
+
export interface EvmChainConfig {
|
|
4
|
+
id: number
|
|
5
|
+
blockExplorer?: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface EvmConfig {
|
|
9
|
+
title?: string
|
|
10
|
+
defaultChain?: string
|
|
11
|
+
chains: Record<string, EvmChainConfig>
|
|
12
|
+
ens?: {
|
|
13
|
+
mode?: 'indexer' | 'chain'
|
|
14
|
+
indexerUrls?: string[]
|
|
15
|
+
}
|
|
16
|
+
baseURL?: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const EvmConfigKey: InjectionKey<EvmConfig> = Symbol('EvmConfig')
|
|
20
|
+
|
|
21
|
+
export const defaultEvmConfig: EvmConfig = {
|
|
22
|
+
title: 'EVM Layer',
|
|
23
|
+
defaultChain: 'mainnet',
|
|
24
|
+
chains: {
|
|
25
|
+
mainnet: { id: 1, blockExplorer: 'https://etherscan.io' },
|
|
26
|
+
},
|
|
27
|
+
ens: { mode: 'indexer' },
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const useEvmConfig = (): EvmConfig => {
|
|
31
|
+
return inject(EvmConfigKey, defaultEvmConfig)
|
|
32
|
+
}
|
package/src/evm/index.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Config
|
|
2
|
+
export { EvmConfigKey, defaultEvmConfig, useEvmConfig } from './config'
|
|
3
|
+
export type { EvmConfig, EvmChainConfig } from './config'
|
|
4
|
+
|
|
5
|
+
// Utils
|
|
6
|
+
export { shortAddress } from './utils/addresses'
|
|
7
|
+
export { resolveChain } from './utils/chains'
|
|
8
|
+
export { formatETH } from './utils/format-eth'
|
|
9
|
+
|
|
10
|
+
// Composables
|
|
11
|
+
export { useBaseURL } from './composables/base'
|
|
12
|
+
export {
|
|
13
|
+
useChainConfig,
|
|
14
|
+
useMainChainId,
|
|
15
|
+
useBlockExplorer,
|
|
16
|
+
useEnsureChainIdCheck,
|
|
17
|
+
} from './composables/chainId'
|
|
18
|
+
|
|
19
|
+
// Components
|
|
20
|
+
export { default as EvmAccount } from './components/EvmAccount.vue'
|
|
21
|
+
export { default as EvmConnect } from './components/EvmConnect.vue'
|
|
22
|
+
export { default as EvmConnectorQR } from './components/EvmConnectorQR.vue'
|
|
23
|
+
export { default as EvmMetaMaskQR } from './components/EvmMetaMaskQR.vue'
|
|
24
|
+
export { default as EvmWalletConnectQR } from './components/EvmWalletConnectQR.vue'
|
|
25
|
+
export { default as EvmTransactionFlow } from './components/EvmTransactionFlow.vue'
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { defineChain, type Chain } from 'viem'
|
|
2
|
+
import {
|
|
3
|
+
mainnet,
|
|
4
|
+
sepolia,
|
|
5
|
+
holesky,
|
|
6
|
+
optimism,
|
|
7
|
+
arbitrum,
|
|
8
|
+
base,
|
|
9
|
+
polygon,
|
|
10
|
+
localhost,
|
|
11
|
+
} from 'viem/chains'
|
|
12
|
+
|
|
13
|
+
const KNOWN: Chain[] = [
|
|
14
|
+
mainnet,
|
|
15
|
+
sepolia,
|
|
16
|
+
holesky,
|
|
17
|
+
optimism,
|
|
18
|
+
arbitrum,
|
|
19
|
+
base,
|
|
20
|
+
polygon,
|
|
21
|
+
localhost,
|
|
22
|
+
]
|
|
23
|
+
const byId = new Map<number, Chain>(KNOWN.map((c) => [c.id, c]))
|
|
24
|
+
|
|
25
|
+
export const resolveChain = (id: number): Chain =>
|
|
26
|
+
byId.get(id) ??
|
|
27
|
+
defineChain({
|
|
28
|
+
id,
|
|
29
|
+
name: `Chain ${id}`,
|
|
30
|
+
nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
|
|
31
|
+
rpcUrls: { default: { http: [] } },
|
|
32
|
+
})
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function formatETH(
|
|
2
|
+
value: string | number,
|
|
3
|
+
maxDecimals: number = 3,
|
|
4
|
+
): string {
|
|
5
|
+
const numberValue = typeof value === 'string' ? parseFloat(value) : value
|
|
6
|
+
|
|
7
|
+
if (isNaN(numberValue)) {
|
|
8
|
+
throw new Error('Invalid number input')
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return new Intl.NumberFormat('en-US', {
|
|
12
|
+
minimumFractionDigits: 0,
|
|
13
|
+
maximumFractionDigits: maxDecimals,
|
|
14
|
+
}).format(numberValue)
|
|
15
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Components
|
|
2
|
+
export { default as Actions } from './base/components/Actions.vue'
|
|
3
|
+
export { default as Alert } from './base/components/Alert.vue'
|
|
4
|
+
export { default as Button } from './base/components/Button.vue'
|
|
5
|
+
export { default as Card } from './base/components/Card.vue'
|
|
6
|
+
export { default as CardLink } from './base/components/CardLink.vue'
|
|
7
|
+
export { default as Dialog } from './base/components/Dialog.vue'
|
|
8
|
+
export { default as Dropdown } from './base/components/Dropdown.vue'
|
|
9
|
+
export { default as DropdownCheckboxItem } from './base/components/DropdownCheckboxItem.vue'
|
|
10
|
+
export { default as DropdownGroup } from './base/components/DropdownGroup.vue'
|
|
11
|
+
export { default as DropdownItem } from './base/components/DropdownItem.vue'
|
|
12
|
+
export { default as DropdownLabel } from './base/components/DropdownLabel.vue'
|
|
13
|
+
export { default as DropdownRadioGroup } from './base/components/DropdownRadioGroup.vue'
|
|
14
|
+
export { default as DropdownRadioItem } from './base/components/DropdownRadioItem.vue'
|
|
15
|
+
export { default as DropdownSeparator } from './base/components/DropdownSeparator.vue'
|
|
16
|
+
export { default as DropdownSub } from './base/components/DropdownSub.vue'
|
|
17
|
+
export { default as Form } from './base/components/Form.vue'
|
|
18
|
+
export { default as FormCheckbox } from './base/components/FormCheckbox.vue'
|
|
19
|
+
export { default as FormGroup } from './base/components/FormGroup.vue'
|
|
20
|
+
export { default as FormInputGroup } from './base/components/FormInputGroup.vue'
|
|
21
|
+
export { default as FormItem } from './base/components/FormItem.vue'
|
|
22
|
+
export { default as FormLabel } from './base/components/FormLabel.vue'
|
|
23
|
+
export { default as FormRadioGroup } from './base/components/FormRadioGroup.vue'
|
|
24
|
+
export { default as FormSelect } from './base/components/FormSelect.vue'
|
|
25
|
+
export { default as FormTextarea } from './base/components/FormTextarea.vue'
|
|
26
|
+
export { default as Icon } from './base/components/Icon.vue'
|
|
27
|
+
export { default as Loading } from './base/components/Loading.vue'
|
|
28
|
+
export { default as Popover } from './base/components/Popover.vue'
|
|
29
|
+
export { default as Tag } from './base/components/Tag.vue'
|
|
30
|
+
export { default as Tags } from './base/components/Tags.vue'
|
|
31
|
+
export { default as Toasts } from './base/components/Toasts.vue'
|
|
32
|
+
export { default as Tooltip } from './base/components/Tooltip.vue'
|
|
33
|
+
|
|
34
|
+
// Composables
|
|
35
|
+
export { useToast } from './base/composables/toast'
|
|
36
|
+
export type {
|
|
37
|
+
Toast as ToastType,
|
|
38
|
+
ToastAction,
|
|
39
|
+
ToastVariant,
|
|
40
|
+
} from './base/composables/toast'
|
|
41
|
+
export {
|
|
42
|
+
useSeconds,
|
|
43
|
+
useCountDown,
|
|
44
|
+
useTimeAgo,
|
|
45
|
+
useSecondsAgo,
|
|
46
|
+
} from './base/composables/time'
|
|
47
|
+
|
|
48
|
+
// Utils
|
|
49
|
+
export {
|
|
50
|
+
formatNumber,
|
|
51
|
+
roundAndFormatNumber,
|
|
52
|
+
asPercentageOf,
|
|
53
|
+
formatUSD,
|
|
54
|
+
} from './base/utils/format-number'
|
|
55
|
+
export {
|
|
56
|
+
delay,
|
|
57
|
+
daysInSeconds,
|
|
58
|
+
nowInSeconds,
|
|
59
|
+
asUTCDate,
|
|
60
|
+
} from './base/utils/time'
|
|
61
|
+
|
|
62
|
+
// Injection keys & types
|
|
63
|
+
export { IconAliasesKey, defaultIconAliases } from './base/icons'
|
|
64
|
+
export type { IconAliases } from './base/icons'
|
|
65
|
+
export { LinkComponentKey } from './base/link'
|
|
66
|
+
|
|
67
|
+
// EVM
|
|
68
|
+
export * from './evm/index'
|