bring theme and codec-components library
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import js from "@eslint/js";
|
||||
import globals from "globals";
|
||||
import reactHooks from "eslint-plugin-react-hooks";
|
||||
import reactRefresh from "eslint-plugin-react-refresh";
|
||||
import tseslint from "typescript-eslint";
|
||||
import js from "@eslint/js"
|
||||
import globals from "globals"
|
||||
import reactHooks from "eslint-plugin-react-hooks"
|
||||
import reactRefresh from "eslint-plugin-react-refresh"
|
||||
import tseslint from "typescript-eslint"
|
||||
|
||||
export default tseslint.config(
|
||||
{ ignores: ["dist"] },
|
||||
@@ -25,6 +25,7 @@ export default tseslint.config(
|
||||
],
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-unnecessary-type-constraint": "off",
|
||||
"@typescript-eslint/no-empty-object-type": "off",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"warn",
|
||||
{
|
||||
@@ -38,5 +39,5 @@ export default tseslint.config(
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
);
|
||||
},
|
||||
)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>PAPI Console</title>
|
||||
</head>
|
||||
<body>
|
||||
<body class="bg-polkadot-950 text-polkadot-100">
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"prettier": {
|
||||
"semi": false
|
||||
},
|
||||
"dependencies": {
|
||||
"@polkadot-api/metadata-builders": "^0.8.2",
|
||||
"@polkadot-api/substrate-bindings": "^0.9.2",
|
||||
@@ -28,6 +31,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.11.1",
|
||||
"@types/node": "^22.7.8",
|
||||
"@types/react": "^18.3.10",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@vitejs/plugin-react": "^4.3.2",
|
||||
|
||||
20
pnpm-lock.yaml
generated
20
pnpm-lock.yaml
generated
@@ -55,6 +55,9 @@ devDependencies:
|
||||
'@eslint/js':
|
||||
specifier: ^9.11.1
|
||||
version: 9.13.0
|
||||
'@types/node':
|
||||
specifier: ^22.7.8
|
||||
version: 22.7.8
|
||||
'@types/react':
|
||||
specifier: ^18.3.10
|
||||
version: 18.3.11
|
||||
@@ -96,7 +99,7 @@ devDependencies:
|
||||
version: 8.11.0(eslint@9.13.0)(typescript@5.6.3)
|
||||
vite:
|
||||
specifier: ^5.4.8
|
||||
version: 5.4.9
|
||||
version: 5.4.9(@types/node@22.7.8)
|
||||
|
||||
packages:
|
||||
|
||||
@@ -926,6 +929,12 @@ packages:
|
||||
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
||||
dev: true
|
||||
|
||||
/@types/node@22.7.8:
|
||||
resolution: {integrity: sha512-a922jJy31vqR5sk+kAdIENJjHblqcZ4RmERviFsER4WJcEONqxKcjNOlk0q7OUfrF5sddT+vng070cdfMlrPLg==}
|
||||
dependencies:
|
||||
undici-types: 6.19.8
|
||||
dev: true
|
||||
|
||||
/@types/prop-types@15.7.13:
|
||||
resolution: {integrity: sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==}
|
||||
|
||||
@@ -1079,7 +1088,7 @@ packages:
|
||||
'@babel/plugin-transform-react-jsx-source': 7.25.7(@babel/core@7.25.8)
|
||||
'@types/babel__core': 7.20.5
|
||||
react-refresh: 0.14.2
|
||||
vite: 5.4.9
|
||||
vite: 5.4.9(@types/node@22.7.8)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
@@ -2508,6 +2517,10 @@ packages:
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/undici-types@6.19.8:
|
||||
resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==}
|
||||
dev: true
|
||||
|
||||
/update-browserslist-db@1.1.1(browserslist@4.24.2):
|
||||
resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==}
|
||||
hasBin: true
|
||||
@@ -2537,7 +2550,7 @@ packages:
|
||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||
dev: true
|
||||
|
||||
/vite@5.4.9:
|
||||
/vite@5.4.9(@types/node@22.7.8):
|
||||
resolution: {integrity: sha512-20OVpJHh0PAM0oSOELa5GaZNWeDjcAvQjGXy2Uyr+Tp+/D2/Hdz6NLgpJLsarPTA2QJ6v8mX2P1ZfbsSKvdMkg==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
hasBin: true
|
||||
@@ -2568,6 +2581,7 @@ packages:
|
||||
terser:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@types/node': 22.7.8
|
||||
esbuild: 0.21.5
|
||||
postcss: 8.4.47
|
||||
rollup: 4.24.0
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export default function App() {
|
||||
return <div className="bg-red-300">App</div>;
|
||||
return <div>App</div>
|
||||
}
|
||||
|
||||
961
src/lib/codecComponents/get-codec-component.tsx
Normal file
961
src/lib/codecComponents/get-codec-component.tsx
Normal file
@@ -0,0 +1,961 @@
|
||||
/* eslint-disable react-hooks/rules-of-hooks */
|
||||
import {
|
||||
V15,
|
||||
V14,
|
||||
HexString,
|
||||
Encoder,
|
||||
Bytes,
|
||||
} from "@polkadot-api/substrate-bindings"
|
||||
import * as scale from "@polkadot-api/substrate-bindings"
|
||||
import {
|
||||
getDynamicBuilder,
|
||||
getLookupFn,
|
||||
LookupEntry,
|
||||
MetadataLookup,
|
||||
Var,
|
||||
} from "@polkadot-api/metadata-builders"
|
||||
import React, { FC, useRef } from "react"
|
||||
import { fromHex, mapObject, mergeUint8 } from "@polkadot-api/utils"
|
||||
import type {
|
||||
EditAccountId,
|
||||
EditBigNumber,
|
||||
EditBool,
|
||||
EditComponents,
|
||||
EditEthAccount,
|
||||
EditNumber,
|
||||
EditStr,
|
||||
ViewAccountId,
|
||||
ViewBigNumber,
|
||||
ViewBool,
|
||||
ViewComponents,
|
||||
ViewEthAccount,
|
||||
ViewNumber,
|
||||
ViewStr,
|
||||
} from "./types"
|
||||
import { NOTIN } from "./types"
|
||||
|
||||
export type MetadataType = V14 | V15
|
||||
|
||||
export const enum CodecComponentType {
|
||||
Initial,
|
||||
Updated,
|
||||
}
|
||||
|
||||
export type CodecComponentInitial = Uint8Array | HexString
|
||||
export type CodecComponentUpdate =
|
||||
| { empty: true }
|
||||
| { empty: false; decoded: any; encoded?: Uint8Array }
|
||||
export type CodecComponentValue =
|
||||
| { type: CodecComponentType.Initial; value?: CodecComponentInitial }
|
||||
| { type: CodecComponentType.Updated; value: CodecComponentUpdate }
|
||||
|
||||
export type LookupType = Var["type"]
|
||||
|
||||
const detectNotin: <T>(x: T) => boolean = (x) => {
|
||||
if (x === NOTIN) return true
|
||||
return x != null && typeof x === "object"
|
||||
? Object.values(x).some(detectNotin)
|
||||
: false
|
||||
}
|
||||
|
||||
const withNotin: <T>(
|
||||
encoder: Encoder<T>,
|
||||
) => (input: T) => Uint8Array | undefined = (encoder) => (input) =>
|
||||
detectNotin(input) ? undefined : encoder(input)
|
||||
|
||||
const getInnerEnumCodec = (
|
||||
input: scale.Codec<{ type: string; value: any }>,
|
||||
idx: number,
|
||||
type: string,
|
||||
) => {
|
||||
return scale.createCodec(
|
||||
(value: any) => input.enc({ type, value }).slice(1),
|
||||
(value) => {
|
||||
const val: Uint8Array =
|
||||
value instanceof Uint8Array
|
||||
? value
|
||||
: typeof value === "string"
|
||||
? fromHex(value)
|
||||
: new Uint8Array(value)
|
||||
return input.dec(mergeUint8(new Uint8Array([idx]), val)).value
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
export function getViewCodecComponent(
|
||||
baseComponents: ViewComponents,
|
||||
): React.FC<{
|
||||
metadata: MetadataType
|
||||
codecType: number
|
||||
value: Uint8Array | HexString
|
||||
}> {
|
||||
const {
|
||||
CVoid,
|
||||
CAccountId,
|
||||
CBigNumber,
|
||||
CNumber,
|
||||
CBool,
|
||||
CStr,
|
||||
CBytes,
|
||||
CEthAccount,
|
||||
CEnum,
|
||||
CSequence,
|
||||
CArray,
|
||||
CTuple,
|
||||
CStruct,
|
||||
COption,
|
||||
CResult,
|
||||
} = baseComponents as ViewComponents
|
||||
|
||||
const CodecComponent: React.FC<{
|
||||
path: string[]
|
||||
dynCodecs: ReturnType<typeof getDynamicBuilder>["buildDefinition"]
|
||||
entry: LookupEntry
|
||||
parent?: { id: number; variantIdx: number; variantTag: string }
|
||||
value:
|
||||
| {
|
||||
empty: true
|
||||
}
|
||||
| { empty: false; decoded: any; encoded?: Uint8Array }
|
||||
}> = ({ entry, value, dynCodecs, parent, path }) => {
|
||||
if (value.empty) return <></>
|
||||
|
||||
const codec =
|
||||
"id" in entry
|
||||
? dynCodecs(entry.id)
|
||||
: getInnerEnumCodec(
|
||||
dynCodecs(parent!.id),
|
||||
parent!.variantIdx,
|
||||
parent!.variantTag,
|
||||
)
|
||||
|
||||
const encodedValue = value.encoded || codec.enc(value.decoded)
|
||||
const valueProps = { value: value.decoded, encodedValue: encodedValue }
|
||||
|
||||
if (entry.type === "struct") {
|
||||
const latestValue = value.decoded
|
||||
return (
|
||||
<CStruct
|
||||
{...valueProps}
|
||||
shape={entry}
|
||||
path={path}
|
||||
innerComponents={mapObject(entry.value, (entry, key) => (
|
||||
<CodecComponent
|
||||
path={path.concat(key as string)}
|
||||
dynCodecs={dynCodecs}
|
||||
entry={entry}
|
||||
value={
|
||||
latestValue[key] === NOTIN
|
||||
? { empty: true }
|
||||
: {
|
||||
empty: false,
|
||||
decoded: latestValue[key],
|
||||
}
|
||||
}
|
||||
/>
|
||||
))}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
if (entry.type === "tuple") {
|
||||
return (
|
||||
<CTuple
|
||||
{...{
|
||||
...valueProps,
|
||||
shape: entry,
|
||||
path,
|
||||
innerComponents: entry.value.map((entry, idx) => (
|
||||
<CodecComponent
|
||||
path={path.concat(idx.toString())}
|
||||
dynCodecs={dynCodecs}
|
||||
entry={entry}
|
||||
value={
|
||||
value.empty
|
||||
? value
|
||||
: value.decoded[idx] === NOTIN
|
||||
? { empty: true }
|
||||
: {
|
||||
empty: false,
|
||||
decoded: value.decoded[idx],
|
||||
}
|
||||
}
|
||||
/>
|
||||
)),
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
if (entry.type === "enum") {
|
||||
let innerEntry
|
||||
if (!value.empty) {
|
||||
innerEntry = entry.value[value.decoded.type as string]
|
||||
if (innerEntry.type === "lookupEntry")
|
||||
innerEntry = innerEntry.value as any
|
||||
}
|
||||
return (
|
||||
<CEnum
|
||||
{...{
|
||||
...valueProps,
|
||||
path,
|
||||
tags: Object.entries(entry.value).map(([tag, { idx }]) => ({
|
||||
tag,
|
||||
idx,
|
||||
})),
|
||||
shape: entry,
|
||||
inner: value.empty ? null : (
|
||||
<CodecComponent
|
||||
path={path.concat(value.decoded.type)}
|
||||
dynCodecs={dynCodecs}
|
||||
entry={innerEntry}
|
||||
parent={{
|
||||
id: entry.id,
|
||||
variantTag: value.decoded.type,
|
||||
variantIdx:
|
||||
entry.value[value.decoded.type as keyof typeof entry.value]
|
||||
.idx,
|
||||
}}
|
||||
value={
|
||||
value.decoded.value === NOTIN
|
||||
? { empty: true }
|
||||
: {
|
||||
empty: false,
|
||||
decoded: value.decoded.value,
|
||||
encoded:
|
||||
(valueProps as any).encodedValue &&
|
||||
(valueProps as any).encodedValue.slice(1),
|
||||
}
|
||||
}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
if (entry.type === "result") {
|
||||
return (
|
||||
<CResult
|
||||
{...{
|
||||
...valueProps,
|
||||
path,
|
||||
shape: entry,
|
||||
inner: value.empty ? null : (
|
||||
<CodecComponent
|
||||
path={path.concat(
|
||||
`Result(${value.decoded.success ? "Success" : "Failure"})`,
|
||||
)}
|
||||
dynCodecs={dynCodecs}
|
||||
entry={entry.value[value.decoded.success ? "ok" : "ko"]}
|
||||
value={
|
||||
value.decoded.value === NOTIN
|
||||
? { empty: true }
|
||||
: {
|
||||
empty: false,
|
||||
decoded: value.decoded.value,
|
||||
}
|
||||
}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
if (entry.type === "option") {
|
||||
return (
|
||||
<COption
|
||||
{...{
|
||||
...valueProps,
|
||||
path,
|
||||
shape: entry,
|
||||
inner:
|
||||
!value.empty && value.decoded === undefined ? (
|
||||
<CVoid />
|
||||
) : (
|
||||
<CodecComponent
|
||||
path={path.concat(
|
||||
`Option(${value.empty ? "Void" : value.decoded === NOTIN ? "" : "Value"})`,
|
||||
)}
|
||||
dynCodecs={dynCodecs}
|
||||
entry={entry.value}
|
||||
value={
|
||||
value.empty || value.decoded === NOTIN
|
||||
? { empty: true }
|
||||
: {
|
||||
empty: false,
|
||||
decoded: value.decoded,
|
||||
}
|
||||
}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
if (entry.type === "void") return <CVoid />
|
||||
|
||||
if (entry.type === "array") {
|
||||
if (entry.value.type === "primitive" && entry.value.value === "u8") {
|
||||
return <CBytes len={entry.len} path={path} {...(valueProps as any)} />
|
||||
}
|
||||
|
||||
const latestValue = value.empty
|
||||
? Array(entry.len).fill(NOTIN)
|
||||
: (value.decoded as Array<any>)
|
||||
return (
|
||||
<CArray
|
||||
{...{
|
||||
...valueProps,
|
||||
path,
|
||||
shape: entry,
|
||||
innerComponents: latestValue.map((decoded, idx) => (
|
||||
<CodecComponent
|
||||
dynCodecs={dynCodecs}
|
||||
entry={entry.value}
|
||||
path={path.concat(idx.toString())}
|
||||
value={
|
||||
decoded === NOTIN
|
||||
? { empty: true }
|
||||
: { empty: false, decoded }
|
||||
}
|
||||
/>
|
||||
)),
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
if (entry.type === "sequence") {
|
||||
if (entry.value.type === "primitive" && entry.value.value === "u8") {
|
||||
return <CBytes {...(valueProps as any)} path={path} />
|
||||
}
|
||||
|
||||
const latestValue = value.empty ? [] : (value.decoded as Array<any>)
|
||||
return (
|
||||
<CSequence
|
||||
{...{
|
||||
...valueProps,
|
||||
path,
|
||||
shape: entry,
|
||||
innerComponents: latestValue.map((decoded, idx) => (
|
||||
<CodecComponent
|
||||
path={path.concat(idx.toString())}
|
||||
dynCodecs={dynCodecs}
|
||||
entry={entry.value}
|
||||
value={
|
||||
decoded === NOTIN
|
||||
? { empty: true }
|
||||
: { empty: false, decoded }
|
||||
}
|
||||
/>
|
||||
)),
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
let type: any = undefined
|
||||
let ResultComponent:
|
||||
| ViewBigNumber
|
||||
| ViewNumber
|
||||
| ViewBool
|
||||
| ViewStr
|
||||
| ViewAccountId
|
||||
| ViewEthAccount = null as any
|
||||
|
||||
switch (entry.type) {
|
||||
case "compact": {
|
||||
ResultComponent = entry.isBig ? CBigNumber : CNumber
|
||||
type = (entry as any).size
|
||||
break
|
||||
}
|
||||
case "primitive": {
|
||||
if (entry.value === "str" || entry.value === "char")
|
||||
ResultComponent = CStr
|
||||
else if (entry.value === "bool") ResultComponent = CBool
|
||||
else {
|
||||
const nBits = Number(entry.value.slice(1))
|
||||
ResultComponent = nBits < 64 ? CNumber : CBigNumber
|
||||
type = entry.value
|
||||
}
|
||||
break
|
||||
}
|
||||
case "bitSequence": {
|
||||
return null
|
||||
}
|
||||
case "AccountId32": {
|
||||
ResultComponent = CAccountId
|
||||
break
|
||||
}
|
||||
case "AccountId20": {
|
||||
ResultComponent = CEthAccount
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const Result = ResultComponent as FC<any>
|
||||
return <Result {...valueProps} path={path} numType={type} />
|
||||
}
|
||||
|
||||
const result: FC<{
|
||||
metadata: V14 | V15
|
||||
codecType: number
|
||||
value: Uint8Array | HexString
|
||||
}> = ({ metadata, codecType, value: propsValue }) => {
|
||||
const lookupRef = useRef<{
|
||||
metadata: V14 | V15
|
||||
lookup: MetadataLookup
|
||||
dynCodecs: ReturnType<typeof getDynamicBuilder>["buildDefinition"]
|
||||
refresh: (
|
||||
codecType: number,
|
||||
value: Uint8Array | HexString,
|
||||
) => { empty: true } | { empty: false; decoded: any; encoded: Uint8Array }
|
||||
}>({
|
||||
metadata: null as any,
|
||||
lookup: null as any,
|
||||
dynCodecs: null as any,
|
||||
refresh: () => ({ empty: true }),
|
||||
})
|
||||
|
||||
if (lookupRef.current.metadata !== metadata) {
|
||||
const lookup = getLookupFn(metadata)
|
||||
lookupRef.current = {
|
||||
metadata,
|
||||
lookup,
|
||||
dynCodecs: getDynamicBuilder(lookup).buildDefinition,
|
||||
refresh: (codecType, val) => {
|
||||
try {
|
||||
const decoded = lookupRef.current.dynCodecs(codecType).dec(val)
|
||||
return {
|
||||
empty: false,
|
||||
decoded,
|
||||
encoded: typeof val === "string" ? fromHex(val) : val,
|
||||
}
|
||||
} catch (_error) {
|
||||
console.error("invalid hex for the codec")
|
||||
return { empty: true }
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const value = lookupRef.current.refresh(codecType, propsValue)
|
||||
|
||||
return (
|
||||
<CodecComponent
|
||||
path={[]}
|
||||
{...{
|
||||
dynCodecs: lookupRef.current.dynCodecs,
|
||||
entry: lookupRef.current.lookup(codecType),
|
||||
value: value,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return result as any
|
||||
}
|
||||
|
||||
export function getCodecComponent(baseComponent: ViewComponents): React.FC<{
|
||||
metadata: V14 | V15
|
||||
codecType: number
|
||||
value: CodecComponentValue
|
||||
}>
|
||||
export function getCodecComponent(baseComponent: EditComponents): React.FC<{
|
||||
metadata: V14 | V15
|
||||
codecType: number
|
||||
value: CodecComponentValue
|
||||
onUpdate?: (newValue: CodecComponentUpdate) => void
|
||||
}>
|
||||
export function getCodecComponent(
|
||||
_baseComponents: EditComponents | ViewComponents,
|
||||
) {
|
||||
const {
|
||||
CVoid,
|
||||
CAccountId,
|
||||
CBigNumber,
|
||||
CNumber,
|
||||
CBool,
|
||||
CStr,
|
||||
CBytes,
|
||||
CEthAccount,
|
||||
CEnum,
|
||||
CSequence,
|
||||
CArray,
|
||||
CTuple,
|
||||
CStruct,
|
||||
COption,
|
||||
CResult,
|
||||
} = _baseComponents as EditComponents
|
||||
const CodecComponent: React.FC<{
|
||||
path: string[]
|
||||
dynCodecs: ReturnType<typeof getDynamicBuilder>["buildDefinition"]
|
||||
entry: LookupEntry
|
||||
parent?: { id: number; variantIdx: number; variantTag: string }
|
||||
value:
|
||||
| {
|
||||
empty: true
|
||||
}
|
||||
| { empty: false; decoded: any; encoded?: Uint8Array }
|
||||
onChange: (value: any) => boolean
|
||||
}> = ({ entry, value, dynCodecs, onChange, parent, path }) => {
|
||||
const codec =
|
||||
"id" in entry
|
||||
? dynCodecs(entry.id)
|
||||
: getInnerEnumCodec(
|
||||
dynCodecs(parent!.id),
|
||||
parent!.variantIdx,
|
||||
parent!.variantTag,
|
||||
)
|
||||
|
||||
const createDecode = (decoder: scale.Decoder<any>) =>
|
||||
scale.createDecoder((bytes) => {
|
||||
try {
|
||||
const result = decoder(bytes)
|
||||
return bytes.length === (bytes as Uint8Array & { i: number }).i
|
||||
? result
|
||||
: NOTIN
|
||||
} catch {
|
||||
return NOTIN
|
||||
}
|
||||
})
|
||||
const decode = createDecode(codec.dec)
|
||||
|
||||
let valueProps:
|
||||
| { type: "blank"; value: NOTIN; encodedValue: undefined }
|
||||
| { type: "partial"; value: any; encodedValue: undefined }
|
||||
| { type: "complete"; value: any; encodedValue: Uint8Array } = {
|
||||
type: "blank" as const,
|
||||
value: NOTIN,
|
||||
encodedValue: undefined,
|
||||
}
|
||||
if (!value.empty) {
|
||||
const encodedValue = value.encoded || withNotin(codec.enc)(value.decoded)
|
||||
valueProps = encodedValue
|
||||
? { type: "complete", value: value.decoded, encodedValue }
|
||||
: { type: "partial", value: value.decoded, encodedValue: undefined }
|
||||
}
|
||||
|
||||
if (entry.type === "struct") {
|
||||
const latestValue = value.empty
|
||||
? mapObject(entry.value, () => NOTIN)
|
||||
: value.decoded
|
||||
return (
|
||||
<CStruct
|
||||
{...valueProps}
|
||||
decode={decode}
|
||||
shape={entry}
|
||||
onValueChanged={onChange}
|
||||
path={path}
|
||||
innerComponents={mapObject(entry.value, (entry, key) => (
|
||||
<CodecComponent
|
||||
path={path.concat(key as string)}
|
||||
dynCodecs={dynCodecs}
|
||||
entry={entry}
|
||||
onChange={(x) => {
|
||||
const value = { ...latestValue }
|
||||
value[key] = x
|
||||
return onChange(value)
|
||||
}}
|
||||
value={
|
||||
latestValue[key] === NOTIN
|
||||
? { empty: true }
|
||||
: {
|
||||
empty: false,
|
||||
decoded: latestValue[key],
|
||||
}
|
||||
}
|
||||
/>
|
||||
))}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
if (entry.type === "tuple") {
|
||||
const latestValue = value.empty
|
||||
? entry.value.map(() => NOTIN)
|
||||
: value.decoded
|
||||
return (
|
||||
<CTuple
|
||||
{...{
|
||||
...valueProps,
|
||||
shape: entry,
|
||||
onValueChanged: onChange,
|
||||
decode,
|
||||
path,
|
||||
innerComponents: entry.value.map((entry, idx) => (
|
||||
<CodecComponent
|
||||
path={path.concat(idx.toString())}
|
||||
dynCodecs={dynCodecs}
|
||||
entry={entry}
|
||||
onChange={(x) => {
|
||||
const value = [...latestValue]
|
||||
value[idx] = x
|
||||
return onChange(value)
|
||||
}}
|
||||
value={
|
||||
value.empty
|
||||
? value
|
||||
: value.decoded[idx] === NOTIN
|
||||
? { empty: true }
|
||||
: {
|
||||
empty: false,
|
||||
decoded: value.decoded[idx],
|
||||
}
|
||||
}
|
||||
/>
|
||||
)),
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
if (entry.type === "enum") {
|
||||
let innerEntry
|
||||
if (!value.empty) {
|
||||
innerEntry = entry.value[value.decoded.type as string]
|
||||
if (innerEntry.type === "lookupEntry")
|
||||
innerEntry = innerEntry.value as any
|
||||
}
|
||||
return (
|
||||
<CEnum
|
||||
{...{
|
||||
...valueProps,
|
||||
decode,
|
||||
onValueChanged: onChange,
|
||||
path,
|
||||
tags: Object.entries(entry.value).map(([tag, { idx }]) => ({
|
||||
tag,
|
||||
idx,
|
||||
})),
|
||||
shape: entry,
|
||||
inner: value.empty ? null : (
|
||||
<CodecComponent
|
||||
path={path.concat(value.decoded.type)}
|
||||
dynCodecs={dynCodecs}
|
||||
entry={innerEntry}
|
||||
onChange={(x) =>
|
||||
onChange({ type: value.decoded.type, value: x })
|
||||
}
|
||||
parent={{
|
||||
id: entry.id,
|
||||
variantTag: value.decoded.type,
|
||||
variantIdx:
|
||||
entry.value[value.decoded.type as keyof typeof entry.value]
|
||||
.idx,
|
||||
}}
|
||||
value={
|
||||
value.decoded.value === NOTIN
|
||||
? { empty: true }
|
||||
: {
|
||||
empty: false,
|
||||
decoded: value.decoded.value,
|
||||
encoded:
|
||||
(valueProps as any).encodedValue &&
|
||||
(valueProps as any).encodedValue.slice(1),
|
||||
}
|
||||
}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
if (entry.type === "result") {
|
||||
return (
|
||||
<CResult
|
||||
{...{
|
||||
...valueProps,
|
||||
onValueChanged: onChange,
|
||||
path,
|
||||
decode,
|
||||
shape: entry,
|
||||
inner: value.empty ? null : (
|
||||
<CodecComponent
|
||||
path={path.concat(
|
||||
`Result(${value.decoded.success ? "Success" : "Failure"})`,
|
||||
)}
|
||||
onChange={(x) =>
|
||||
onChange({ success: value.decoded.success, value: x })
|
||||
}
|
||||
dynCodecs={dynCodecs}
|
||||
entry={entry.value[value.decoded.success ? "ok" : "ko"]}
|
||||
value={
|
||||
value.decoded.value === NOTIN
|
||||
? { empty: true }
|
||||
: { empty: false, decoded: value.decoded.value }
|
||||
}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
if (entry.type === "option") {
|
||||
return (
|
||||
<COption
|
||||
{...{
|
||||
...valueProps,
|
||||
path,
|
||||
shape: entry,
|
||||
onValueChanged: onChange,
|
||||
decode,
|
||||
inner:
|
||||
!value.empty && value.decoded === undefined ? (
|
||||
<CVoid />
|
||||
) : (
|
||||
<CodecComponent
|
||||
path={path.concat(
|
||||
`Option(${value.empty ? "Void" : value.decoded === NOTIN ? "" : "Value"})`,
|
||||
)}
|
||||
dynCodecs={dynCodecs}
|
||||
entry={entry.value}
|
||||
onChange={onChange}
|
||||
value={
|
||||
value.empty || value.decoded === NOTIN
|
||||
? { empty: true }
|
||||
: { empty: false, decoded: value.decoded }
|
||||
}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
if (entry.type === "void") return <CVoid />
|
||||
|
||||
if (entry.type === "array") {
|
||||
if (entry.value.type === "primitive" && entry.value.value === "u8") {
|
||||
const decoder = Bytes(entry.len)[1]
|
||||
return (
|
||||
<CBytes
|
||||
decode={scale.createDecoder(decoder)}
|
||||
onValueChanged={onChange}
|
||||
len={entry.len}
|
||||
path={path}
|
||||
{...(valueProps as any)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const latestValue = value.empty
|
||||
? Array(entry.len).fill(NOTIN)
|
||||
: (value.decoded as Array<any>)
|
||||
return (
|
||||
<CArray
|
||||
{...{
|
||||
...valueProps,
|
||||
path,
|
||||
shape: entry,
|
||||
decode,
|
||||
onValueChanged: onChange,
|
||||
innerComponents: latestValue.map((decoded, idx) => (
|
||||
<CodecComponent
|
||||
dynCodecs={dynCodecs}
|
||||
entry={entry.value}
|
||||
path={path.concat(idx.toString())}
|
||||
onChange={(x) => {
|
||||
const value = [...latestValue]
|
||||
value[idx] = x
|
||||
return onChange(value)
|
||||
}}
|
||||
value={
|
||||
decoded === NOTIN
|
||||
? { empty: true }
|
||||
: { empty: false, decoded }
|
||||
}
|
||||
/>
|
||||
)),
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
if (entry.type === "sequence") {
|
||||
if (entry.value.type === "primitive" && entry.value.value === "u8") {
|
||||
const decoder = Bytes()[1]
|
||||
return (
|
||||
<CBytes
|
||||
{...(valueProps as any)}
|
||||
path={path}
|
||||
decode={createDecode(decoder)}
|
||||
onValueChanged={onChange}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const latestValue = value.empty ? [] : (value.decoded as Array<any>)
|
||||
return (
|
||||
<CSequence
|
||||
{...{
|
||||
...valueProps,
|
||||
path,
|
||||
shape: entry,
|
||||
onValueChanged: onChange,
|
||||
decode,
|
||||
innerComponents: latestValue.map((decoded, idx) => (
|
||||
<CodecComponent
|
||||
path={path.concat(idx.toString())}
|
||||
dynCodecs={dynCodecs}
|
||||
entry={entry.value}
|
||||
onChange={(x) => {
|
||||
const value = [...latestValue]
|
||||
value[idx] = x
|
||||
return onChange(value)
|
||||
}}
|
||||
value={
|
||||
decoded === NOTIN
|
||||
? { empty: true }
|
||||
: { empty: false, decoded }
|
||||
}
|
||||
/>
|
||||
)),
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
let type: any = undefined
|
||||
let ResultComponent:
|
||||
| EditBigNumber
|
||||
| EditNumber
|
||||
| EditBool
|
||||
| EditStr
|
||||
| EditAccountId
|
||||
| EditEthAccount = null as any
|
||||
|
||||
switch (entry.type) {
|
||||
case "compact": {
|
||||
ResultComponent = entry.isBig ? CBigNumber : CNumber
|
||||
type = (entry as any).size
|
||||
break
|
||||
}
|
||||
case "primitive": {
|
||||
if (entry.value === "str" || entry.value === "char")
|
||||
ResultComponent = CStr
|
||||
else if (entry.value === "bool") ResultComponent = CBool
|
||||
else {
|
||||
const nBits = Number(entry.value.slice(1))
|
||||
ResultComponent = nBits < 64 ? CNumber : CBigNumber
|
||||
type = entry.value
|
||||
}
|
||||
break
|
||||
}
|
||||
case "bitSequence": {
|
||||
return null
|
||||
}
|
||||
case "AccountId32": {
|
||||
ResultComponent = CAccountId
|
||||
break
|
||||
}
|
||||
case "AccountId20": {
|
||||
ResultComponent = CEthAccount
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const Result = ResultComponent as FC<any>
|
||||
return (
|
||||
<Result
|
||||
{...valueProps}
|
||||
path={path}
|
||||
decode={decode}
|
||||
onValueChanged={onChange}
|
||||
numType={type}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const result: FC<{
|
||||
metadata: V14 | V15
|
||||
codecType: number
|
||||
value: CodecComponentValue
|
||||
onUpdate: (newValue: CodecComponentUpdate) => void
|
||||
}> = ({ metadata, codecType, value: propsValue, onUpdate }) => {
|
||||
const lookupRef = useRef<{
|
||||
metadata: V14 | V15
|
||||
lookup: MetadataLookup
|
||||
dynCodecs: ReturnType<typeof getDynamicBuilder>["buildDefinition"]
|
||||
refresh: (
|
||||
codecType: number,
|
||||
value?: Uint8Array | HexString,
|
||||
) =>
|
||||
| { empty: true }
|
||||
| { empty: false; decoded: any; encoded?: Uint8Array }
|
||||
}>({
|
||||
metadata: null as any,
|
||||
lookup: null as any,
|
||||
dynCodecs: null as any,
|
||||
refresh: () => ({ empty: true }),
|
||||
})
|
||||
|
||||
if (lookupRef.current.metadata !== metadata) {
|
||||
const lookup = getLookupFn(metadata)
|
||||
lookupRef.current = {
|
||||
metadata,
|
||||
lookup,
|
||||
dynCodecs: getDynamicBuilder(lookup).buildDefinition,
|
||||
refresh: (codecType, val) => {
|
||||
try {
|
||||
return val
|
||||
? {
|
||||
empty: false,
|
||||
decoded: lookupRef.current.dynCodecs(codecType).dec(val),
|
||||
encoded: typeof val === "string" ? fromHex(val) : val,
|
||||
}
|
||||
: { empty: true }
|
||||
} catch (_error) {
|
||||
console.error("invalid hex for the codec")
|
||||
return { empty: true }
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const value =
|
||||
propsValue.type === CodecComponentType.Initial
|
||||
? lookupRef.current.refresh(
|
||||
codecType,
|
||||
propsValue.value as CodecComponentInitial,
|
||||
)
|
||||
: propsValue.value
|
||||
|
||||
return (
|
||||
<CodecComponent
|
||||
path={[]}
|
||||
onChange={(x) => {
|
||||
if (x === NOTIN) {
|
||||
onUpdate({ empty: true })
|
||||
return true
|
||||
}
|
||||
|
||||
let encoded = undefined
|
||||
const hasNotin = detectNotin(x)
|
||||
if (!hasNotin) {
|
||||
try {
|
||||
encoded = lookupRef.current.dynCodecs(codecType).enc(x)
|
||||
} catch (_e) {
|
||||
console.warn("Error encoding", x)
|
||||
return false
|
||||
}
|
||||
}
|
||||
onUpdate({ empty: false, decoded: x, encoded })
|
||||
return true
|
||||
}}
|
||||
{...{
|
||||
dynCodecs: lookupRef.current.dynCodecs,
|
||||
entry: lookupRef.current.lookup(codecType),
|
||||
value: value,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return result as any
|
||||
}
|
||||
2
src/lib/codecComponents/index.ts
Normal file
2
src/lib/codecComponents/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./types"
|
||||
export * from "./get-codec-component"
|
||||
144
src/lib/codecComponents/types/edit-component-types.ts
Normal file
144
src/lib/codecComponents/types/edit-component-types.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
import type {
|
||||
ArrayVar,
|
||||
EnumVar,
|
||||
OptionVar,
|
||||
ResultVar,
|
||||
SequenceVar,
|
||||
StructVar,
|
||||
TupleVar,
|
||||
} from "@polkadot-api/metadata-builders"
|
||||
import type {
|
||||
Binary,
|
||||
HexString,
|
||||
SS58String,
|
||||
} from "@polkadot-api/substrate-bindings"
|
||||
import type { ReactNode, FC } from "react"
|
||||
|
||||
export const NOTIN = Symbol("Notin")
|
||||
export type NOTIN = typeof NOTIN
|
||||
|
||||
export type EditComplexCodecComponentProps<T> = (
|
||||
| { type: "blank"; value: NOTIN; encodedValue: undefined }
|
||||
| { type: "partial"; value: T; encodedValue: undefined }
|
||||
| { type: "complete"; value: T; encodedValue: Uint8Array }
|
||||
) & {
|
||||
path: string[]
|
||||
onValueChanged: (newValue: T | NOTIN) => boolean
|
||||
decode: (value: Uint8Array | HexString) => T | NOTIN
|
||||
}
|
||||
|
||||
export type EditPrimitiveComponentProps<T = any> = (
|
||||
| { type: "blank"; value: NOTIN; encodedValue: undefined }
|
||||
| { type: "complete"; value: T; encodedValue: Uint8Array }
|
||||
) & {
|
||||
path: string[]
|
||||
onValueChanged: (newValue: T | NOTIN) => boolean
|
||||
decode: (value: Uint8Array | HexString) => T | NOTIN
|
||||
}
|
||||
|
||||
export type EditVoidInterface = {}
|
||||
export type EditVoid = FC<EditVoidInterface>
|
||||
|
||||
export type EditAccountIdInterface = EditPrimitiveComponentProps<SS58String>
|
||||
export type EditAccountId = FC<EditAccountIdInterface>
|
||||
|
||||
export type EditBigNumberInterface = EditPrimitiveComponentProps<bigint> & {
|
||||
numType: "u64" | "u128" | "u256" | "i64" | "i128" | "i256"
|
||||
}
|
||||
export type EditBigNumber = FC<EditBigNumberInterface>
|
||||
|
||||
export type EditNumberInterface = EditPrimitiveComponentProps<number> & {
|
||||
numType: "u8" | "u16" | "u32" | "i8" | "i16" | "i32"
|
||||
}
|
||||
export type EditNumber = FC<EditNumberInterface>
|
||||
|
||||
export type EditBoolInterface = EditPrimitiveComponentProps<boolean>
|
||||
export type EditBool = FC<EditBoolInterface>
|
||||
|
||||
export type EditStrInterface = EditPrimitiveComponentProps<string>
|
||||
export type EditStr = FC<EditStrInterface>
|
||||
|
||||
export type EditBytesInterface = EditPrimitiveComponentProps<Binary> & {
|
||||
len?: number
|
||||
}
|
||||
export type EditBytes = FC<EditBytesInterface>
|
||||
|
||||
export type EditEthAccountInterface = EditPrimitiveComponentProps<HexString>
|
||||
export type EditEthAccount = FC<EditEthAccountInterface>
|
||||
|
||||
export type EditEnumInterface = EditComplexCodecComponentProps<{
|
||||
type: string
|
||||
value: any
|
||||
}> & {
|
||||
tags: Array<{ idx: number; tag: string }>
|
||||
inner: ReactNode
|
||||
shape: EnumVar
|
||||
}
|
||||
export type EditEnum = FC<EditEnumInterface>
|
||||
|
||||
export type EditSequenceInterface<T = any> = EditComplexCodecComponentProps<
|
||||
Array<T>
|
||||
> & {
|
||||
innerComponents: Array<ReactNode>
|
||||
shape: SequenceVar
|
||||
}
|
||||
export type EditSequence = FC<EditSequenceInterface>
|
||||
|
||||
export type EditArrayInterface<T = any> = EditComplexCodecComponentProps<
|
||||
Array<T>
|
||||
> & {
|
||||
innerComponents: Array<ReactNode>
|
||||
shape: ArrayVar
|
||||
}
|
||||
export type EditArray = FC<EditArrayInterface>
|
||||
|
||||
export type EditTupleInterface<T = any> = EditComplexCodecComponentProps<
|
||||
Array<T>
|
||||
> & {
|
||||
innerComponents: Array<ReactNode>
|
||||
shape: TupleVar
|
||||
}
|
||||
export type EditTuple = FC<EditTupleInterface>
|
||||
|
||||
export type EditStructInterface = EditComplexCodecComponentProps<
|
||||
Record<string, any>
|
||||
> & {
|
||||
innerComponents: Record<string, ReactNode>
|
||||
shape: StructVar
|
||||
}
|
||||
export type EditStruct = FC<EditStructInterface>
|
||||
|
||||
export type EditOptionInterface<T = any> = EditComplexCodecComponentProps<
|
||||
T | undefined
|
||||
> & {
|
||||
inner: ReactNode
|
||||
shape: OptionVar
|
||||
}
|
||||
export type EditOption = FC<EditOptionInterface>
|
||||
|
||||
export type EditResultInterface = EditComplexCodecComponentProps<{
|
||||
success: boolean
|
||||
value: any
|
||||
}> & {
|
||||
shape: ResultVar
|
||||
inner: ReactNode
|
||||
}
|
||||
export type EditResult = FC<EditResultInterface>
|
||||
|
||||
export interface EditComponents {
|
||||
CVoid: EditVoid
|
||||
CAccountId: EditAccountId
|
||||
CBigNumber: EditBigNumber
|
||||
CNumber: EditNumber
|
||||
CBool: EditBool
|
||||
CStr: EditStr
|
||||
CBytes: EditBytes
|
||||
CEthAccount: EditEthAccount
|
||||
CEnum: EditEnum
|
||||
CSequence: EditSequence
|
||||
CArray: EditArray
|
||||
CTuple: EditTuple
|
||||
CStruct: EditStruct
|
||||
COption: EditOption
|
||||
CResult: EditResult
|
||||
}
|
||||
2
src/lib/codecComponents/types/index.ts
Normal file
2
src/lib/codecComponents/types/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./edit-component-types"
|
||||
export * from "./view-component-types"
|
||||
126
src/lib/codecComponents/types/view-component-types.ts
Normal file
126
src/lib/codecComponents/types/view-component-types.ts
Normal file
@@ -0,0 +1,126 @@
|
||||
import type {
|
||||
ArrayVar,
|
||||
EnumVar,
|
||||
OptionVar,
|
||||
ResultVar,
|
||||
SequenceVar,
|
||||
StructVar,
|
||||
TupleVar,
|
||||
} from "@polkadot-api/metadata-builders"
|
||||
import type {
|
||||
Binary,
|
||||
HexString,
|
||||
SS58String,
|
||||
} from "@polkadot-api/substrate-bindings"
|
||||
import type { ReactNode, FC } from "react"
|
||||
|
||||
export type ViewCodecComponentProps<T = any> = {
|
||||
value: T
|
||||
encodedValue: Uint8Array
|
||||
path: string[]
|
||||
}
|
||||
|
||||
export type ViewPrimitiveComponentProps<T = any> = ViewCodecComponentProps<T>
|
||||
|
||||
export type ViewVoidInterface = {}
|
||||
export type ViewVoid = FC<ViewVoidInterface>
|
||||
|
||||
export type ViewAccountIdInterface = ViewPrimitiveComponentProps<SS58String>
|
||||
export type ViewAccountId = FC<ViewAccountIdInterface>
|
||||
|
||||
export type ViewBigNumberInterface = ViewPrimitiveComponentProps<bigint> & {
|
||||
numType: "u64" | "u128" | "u256" | "i64" | "i128" | "i256"
|
||||
}
|
||||
export type ViewBigNumber = FC<ViewBigNumberInterface>
|
||||
|
||||
export type ViewNumberInterface = ViewPrimitiveComponentProps<number> & {
|
||||
numType: "u8" | "u16" | "u32" | "i8" | "i16" | "i32"
|
||||
}
|
||||
export type ViewNumber = FC<ViewNumberInterface>
|
||||
|
||||
export type ViewBoolInterface = ViewPrimitiveComponentProps<boolean>
|
||||
export type ViewBool = FC<ViewBoolInterface>
|
||||
|
||||
export type ViewStrInterface = ViewPrimitiveComponentProps<string>
|
||||
export type ViewStr = FC<ViewStrInterface>
|
||||
|
||||
export type ViewBytesInterface = ViewPrimitiveComponentProps<Binary> & {
|
||||
len?: number
|
||||
}
|
||||
export type ViewBytes = FC<ViewBytesInterface>
|
||||
|
||||
export type ViewEthAccountInterface = ViewPrimitiveComponentProps<HexString>
|
||||
export type ViewEthAccount = FC<ViewEthAccountInterface>
|
||||
|
||||
export type ViewEnumInterface = ViewCodecComponentProps<{
|
||||
type: string
|
||||
value: any
|
||||
}> & {
|
||||
tags: Array<{ idx: number; tag: string }>
|
||||
inner: ReactNode
|
||||
shape: EnumVar
|
||||
}
|
||||
export type ViewEnum = FC<ViewEnumInterface>
|
||||
|
||||
export type ViewSequenceInterface<T = any> = ViewCodecComponentProps<
|
||||
Array<T>
|
||||
> & {
|
||||
innerComponents: Array<ReactNode>
|
||||
shape: SequenceVar
|
||||
}
|
||||
export type ViewSequence = FC<ViewSequenceInterface>
|
||||
|
||||
export type ViewArrayInterface<T = any> = ViewCodecComponentProps<Array<T>> & {
|
||||
innerComponents: Array<ReactNode>
|
||||
shape: ArrayVar
|
||||
}
|
||||
export type ViewArray = FC<ViewArrayInterface>
|
||||
|
||||
export type ViewTupleInterface<T = any> = ViewCodecComponentProps<Array<T>> & {
|
||||
innerComponents: Array<ReactNode>
|
||||
shape: TupleVar
|
||||
}
|
||||
export type ViewTuple = FC<ViewTupleInterface>
|
||||
|
||||
export type ViewStructInterface = ViewCodecComponentProps<
|
||||
Record<string, any>
|
||||
> & {
|
||||
innerComponents: Record<string, ReactNode>
|
||||
shape: StructVar
|
||||
}
|
||||
export type ViewStruct = FC<ViewStructInterface>
|
||||
|
||||
export type ViewOptionInterface<T = any> = ViewCodecComponentProps<
|
||||
T | undefined
|
||||
> & {
|
||||
inner: ReactNode
|
||||
shape: OptionVar
|
||||
}
|
||||
export type ViewOption = FC<ViewOptionInterface>
|
||||
|
||||
export type ViewResultInterface = ViewCodecComponentProps<{
|
||||
success: boolean
|
||||
value: any
|
||||
}> & {
|
||||
shape: ResultVar
|
||||
inner: ReactNode
|
||||
}
|
||||
export type ViewResult = FC<ViewResultInterface>
|
||||
|
||||
export interface ViewComponents {
|
||||
CVoid: ViewVoid
|
||||
CAccountId: ViewAccountId
|
||||
CBigNumber: ViewBigNumber
|
||||
CNumber: ViewNumber
|
||||
CBool: ViewBool
|
||||
CStr: ViewStr
|
||||
CBytes: ViewBytes
|
||||
CEthAccount: ViewEthAccount
|
||||
CEnum: ViewEnum
|
||||
CSequence: ViewSequence
|
||||
CArray: ViewArray
|
||||
CTuple: ViewTuple
|
||||
CStruct: ViewStruct
|
||||
COption: ViewOption
|
||||
CResult: ViewResult
|
||||
}
|
||||
@@ -7,23 +7,25 @@ export default {
|
||||
extend: {
|
||||
colors: {
|
||||
polkadot: {
|
||||
0: "#FFFFFF",
|
||||
100: "#E1DDFF",
|
||||
200: "#D6BBFF",
|
||||
300: "#DF98FF",
|
||||
400: "#FC76FF",
|
||||
500: "#E6007A",
|
||||
950: "#030110",
|
||||
900: "#0C052C",
|
||||
800: "#23126D",
|
||||
700: "#4027AE",
|
||||
650: "#6543EF",
|
||||
600: "#5E39F2",
|
||||
700: "#472FA7",
|
||||
800: "#0F1750",
|
||||
900: "#01050C",
|
||||
500: "#E6007A",
|
||||
400: "#FC76FF",
|
||||
300: "#DB9EFF",
|
||||
200: "#E4DAFF",
|
||||
100: "#F2F3FF",
|
||||
0: "#FBFCFF",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
function ({ addVariant }) {
|
||||
addVariant("group-state-open", ':merge(.group)[data-state="open"] &')
|
||||
addVariant("group-state-open", ':merge(.group)[data-state="open"] &');
|
||||
},
|
||||
],
|
||||
}
|
||||
};
|
||||
|
||||
@@ -18,7 +18,12 @@
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
|
||||
"paths": {
|
||||
"@/*": ["./src/*"],
|
||||
"@codec-components": ["./src/lib/codecComponents"]
|
||||
}
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import { defineConfig } from "vite"
|
||||
import react from "@vitejs/plugin-react"
|
||||
import path from "node:path"
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
"@codec-components": path.resolve(__dirname, "./src/lib/codecComponents"),
|
||||
},
|
||||
},
|
||||
plugins: [react()],
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user