feat: automatically set default values when editing a lookup type

This commit is contained in:
Victor Oliva
2026-05-14 12:39:42 +02:00
parent d5ee5bb463
commit 7dfc370011
4 changed files with 59 additions and 12 deletions

View File

@@ -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 = ({
<SearchableSelect
setValue={(selected: string | null) => {
if (selected && options.includes(selected)) {
const value = isEnumVoid(shape, selected) ? null : NOTIN
const value = getEnumDefaultValue(shape, selected)
onValueChanged({ type: selected, value })
}
}}

View File

@@ -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])
}

View File

@@ -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 (
<div>
@@ -69,7 +74,9 @@ export const COption: EditOption = ({ value, inner, onValueChanged }) => {
<SliderToggle
isToggled={selected}
toggle={() =>
!selected ? onValueChanged(NOTIN) : onValueChanged(undefined)
!selected
? onValueChanged(getDefaultValue(shape.value))
: onValueChanged(undefined)
}
/>
<span className="text-base">

View File

@@ -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<Var["type"]>([
"tuple",
@@ -40,14 +43,49 @@ export const getStructInnerType = <T extends StructVar>(
return shape.value[key].type
}
export const isEnumVoid = <T extends EnumVar>(
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 = <T extends EnumVar>(
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) => {