diff --git a/src/codec-components/EditCodec/CEnum.tsx b/src/codec-components/EditCodec/CEnum.tsx index 44c4b80..9ee58bb 100644 --- a/src/codec-components/EditCodec/CEnum.tsx +++ b/src/codec-components/EditCodec/CEnum.tsx @@ -1,5 +1,5 @@ import { SearchableSelect } from "@/components/Select" -import { isEnumComplex, isEnumVoid } from "@/utils/shape" +import { getEnumDefaultValue, isEnumComplex } from "@/utils/shape" import { EditEnum, NOTIN } from "@polkadot-api/react-builder" import { Marker } from "../common/Markers" import { useSubtreeFocus } from "../common/SubtreeFocus" @@ -43,7 +43,7 @@ export const CEnum: EditEnum = ({ { if (selected && options.includes(selected)) { - const value = isEnumVoid(shape, selected) ? null : NOTIN + const value = getEnumDefaultValue(shape, selected) onValueChanged({ type: selected, value }) } }} diff --git a/src/codec-components/EditCodec/CSequence.tsx b/src/codec-components/EditCodec/CSequence.tsx index 0d180cb..bb3f511 100644 --- a/src/codec-components/EditCodec/CSequence.tsx +++ b/src/codec-components/EditCodec/CSequence.tsx @@ -3,12 +3,14 @@ import { CirclePlus } from "lucide-react" import { twMerge as clsx } from "tailwind-merge" import { ListItem } from "../common/ListItem" import { useSubtreeFocus } from "../common/SubtreeFocus" +import { getDefaultValue } from "@/utils" export const CSequence: EditSequence = ({ innerComponents, value, onValueChanged, path, + shape, }) => { const focus = useSubtreeFocus() const sub = focus.getNextPath(path) @@ -18,7 +20,7 @@ export const CSequence: EditSequence = ({ const addItem = () => { const curr = value !== NOTIN ? value.slice() : [] - curr.push(NOTIN) + curr.push(getDefaultValue(shape.value)) onValueChanged([...curr]) } diff --git a/src/codec-components/EditCodec/codec-components.tsx b/src/codec-components/EditCodec/codec-components.tsx index 8d1d20c..02d70f8 100644 --- a/src/codec-components/EditCodec/codec-components.tsx +++ b/src/codec-components/EditCodec/codec-components.tsx @@ -1,11 +1,11 @@ import SliderToggle from "@/components/Toggle" +import { getDefaultValue } from "@/utils" import { EditArray, EditBool, EditOption, EditResult, EditVoid, - NOTIN, } from "@polkadot-api/react-builder" import { FC, ReactNode, useState } from "react" import { twMerge } from "tailwind-merge" @@ -61,7 +61,12 @@ export const CArray: EditArray = ({ innerComponents, path }) => { ) } -export const COption: EditOption = ({ value, inner, onValueChanged }) => { +export const COption: EditOption = ({ + value, + inner, + shape, + onValueChanged, +}) => { const selected = value !== undefined return (
@@ -69,7 +74,9 @@ export const COption: EditOption = ({ value, inner, onValueChanged }) => { - !selected ? onValueChanged(NOTIN) : onValueChanged(undefined) + !selected + ? onValueChanged(getDefaultValue(shape.value)) + : onValueChanged(undefined) } /> diff --git a/src/utils/shape.ts b/src/utils/shape.ts index bb77d94..1180792 100644 --- a/src/utils/shape.ts +++ b/src/utils/shape.ts @@ -1,4 +1,7 @@ import { EnumVar, StructVar, Var } from "@polkadot-api/metadata-builders" +import { NOTIN } from "@polkadot-api/react-builder" +import { Enum } from "polkadot-api" +import { mapObject } from "polkadot-api/utils" const complexTypes = new Set([ "tuple", @@ -40,14 +43,49 @@ export const getStructInnerType = ( return shape.value[key].type } -export const isEnumVoid = ( +const MAX_DEPTH = 5 +export const getDefaultValue = (innerVar: Var, depth = 0): any => { + if (depth > MAX_DEPTH) return NOTIN + const nextDefault = (v: Var) => getDefaultValue(v, depth + 1) + + switch (innerVar.type) { + case "void": + return null + case "option": + return undefined + case "sequence": + return [] + case "struct": + return mapObject(innerVar.value, (v) => nextDefault(v)) + case "array": + return new Array(innerVar.len) + .fill(0) + .map(() => nextDefault(innerVar.value)) + case "tuple": + return innerVar.value.map(nextDefault) + case "enum": { + const selected = Object.entries(innerVar.value)[0] + return selected + ? Enum( + selected[0], + nextDefault( + selected[1].type === "lookupEntry" + ? selected[1].value + : selected[1], + ), + ) + : NOTIN + } + } + return NOTIN +} + +export const getEnumDefaultValue = ( shape: T, type: keyof T["value"], -): boolean => { - const innerShape = shape.value[type] - const innerType = - innerShape.type === "lookupEntry" ? innerShape.value.type : innerShape.type - return innerType === "void" +) => { + const innerVar = getEnumInnerVar(shape, type) + return getDefaultValue(innerVar) } export const getFinalType = (shape: any, name: string) => {