From 409401ebae1b19fb057092beaebfd48c6205d43b Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Tue, 12 Sep 2023 14:30:08 +0700 Subject: [PATCH 01/11] feat: initial abi form --- src/lib/components/abi/AbiForm.tsx | 58 +++++++++++++++++ src/lib/components/abi/index.ts | 1 + .../components/abi/param-form/ParamField.tsx | 35 ++++++++++ src/lib/components/abi/param-form/index.tsx | 65 +++++++++++++++++++ .../abi/type-form/TypeFieldInput.tsx | 44 +++++++++++++ src/lib/components/abi/type-form/index.tsx | 47 ++++++++++++++ src/lib/components/forms/ControllerInput.tsx | 7 +- .../component/form/ExecuteArea.tsx | 22 +++++++ .../interaction/component/form/ViewArea.tsx | 31 +++++++++ .../pages/interaction/component/form/index.ts | 2 + src/lib/pages/interaction/component/index.ts | 1 + .../pages/interaction/component/main/body.tsx | 18 +++-- src/lib/types/abi.ts | 2 +- src/lib/utils/abi.ts | 8 +++ 14 files changed, 334 insertions(+), 7 deletions(-) create mode 100644 src/lib/components/abi/AbiForm.tsx create mode 100644 src/lib/components/abi/index.ts create mode 100644 src/lib/components/abi/param-form/ParamField.tsx create mode 100644 src/lib/components/abi/param-form/index.tsx create mode 100644 src/lib/components/abi/type-form/TypeFieldInput.tsx create mode 100644 src/lib/components/abi/type-form/index.tsx create mode 100644 src/lib/pages/interaction/component/form/ExecuteArea.tsx create mode 100644 src/lib/pages/interaction/component/form/ViewArea.tsx create mode 100644 src/lib/pages/interaction/component/form/index.ts diff --git a/src/lib/components/abi/AbiForm.tsx b/src/lib/components/abi/AbiForm.tsx new file mode 100644 index 000000000..53cd1d7e4 --- /dev/null +++ b/src/lib/components/abi/AbiForm.tsx @@ -0,0 +1,58 @@ +import { Flex } from "@chakra-ui/react"; +import { useForm } from "react-hook-form"; + +import type { ExposedFunction } from "lib/types"; + +import { ParamForm } from "./param-form"; +import { TypeForm } from "./type-form"; + +export interface AbiFormData { + typeArgs: Record; + args: Record; +} + +interface AbiFormProps { + fn: ExposedFunction; + initialData: AbiFormData; + propsOnChange?: (data: AbiFormData) => void; + propsOnErrors?: (errors: [string, string][]) => void; +} + +export const AbiForm = ({ + fn, + initialData, + propsOnChange, + propsOnErrors, +}: AbiFormProps) => { + const { setValue, watch, getValues } = useForm({ + defaultValues: initialData, + mode: "all", + }); + const { typeArgs, args } = watch(); + + return ( + + {Object.keys(typeArgs).length > 0 && ( + { + setValue("typeArgs", value); + propsOnChange?.(getValues()); + }} + /> + )} + {Object.keys(args).length > 0 && ( + { + setValue("args", value); + propsOnChange?.(getValues()); + propsOnErrors?.(errors); + }} + /> + )} + + ); +}; diff --git a/src/lib/components/abi/index.ts b/src/lib/components/abi/index.ts new file mode 100644 index 000000000..46f667e90 --- /dev/null +++ b/src/lib/components/abi/index.ts @@ -0,0 +1 @@ +export * from "./AbiForm"; diff --git a/src/lib/components/abi/param-form/ParamField.tsx b/src/lib/components/abi/param-form/ParamField.tsx new file mode 100644 index 000000000..748b08e35 --- /dev/null +++ b/src/lib/components/abi/param-form/ParamField.tsx @@ -0,0 +1,35 @@ +import { parseInt } from "lodash"; +import type { Control, FieldPath, FieldValues } from "react-hook-form"; + +import { ControllerInput } from "lib/components/forms"; + +interface ParamFieldProps { + index: number; + param: string; + control: Control; + error?: string; +} + +export const ParamField = ({ + index, + param, + control, + error, +}: ParamFieldProps) => { + return ( + } + control={control} + label={param} + variant="floating" + rules={{ + validate: { + positive: (v) => (parseInt(v) > 0 ? undefined : "need positive"), + lessThanTen: (v) => parseInt(v) < 10, + }, + // pattern: { value: /^\d+$/, message: "This input is number only." }, + }} + error={error} + /> + ); +}; diff --git a/src/lib/components/abi/param-form/index.tsx b/src/lib/components/abi/param-form/index.tsx new file mode 100644 index 000000000..9978a632f --- /dev/null +++ b/src/lib/components/abi/param-form/index.tsx @@ -0,0 +1,65 @@ +import { Flex, Heading } from "@chakra-ui/react"; +import { useEffect } from "react"; +import type { FormState } from "react-hook-form"; +import { useForm } from "react-hook-form"; + +import { ParamField } from "./ParamField"; + +interface ParamFormProps { + params: string[]; + initialData: Record; + propsOnChange?: ( + data: Record, + errors: [string, string][] + ) => void; +} + +const formatErrors = ( + errors: FormState>["errors"] +): [string, string][] => + Object.entries(errors).map(([field, error]) => [ + field, + error?.message ?? "invalid input", + ]); + +export const ParamForm = ({ + params, + initialData, + propsOnChange, +}: ParamFormProps) => { + const { + trigger, + control, + getValues, + formState: { errors }, + } = useForm>({ + defaultValues: initialData, + mode: "all", + }); + + useEffect(() => { + trigger(); + }, [trigger]); + + return ( + + + args + + {params.map((param, index) => { + control.register(`${index}`, { + onChange: () => propsOnChange?.(getValues(), formatErrors(errors)), + }); + return ( + + ); + })} + + ); +}; diff --git a/src/lib/components/abi/type-form/TypeFieldInput.tsx b/src/lib/components/abi/type-form/TypeFieldInput.tsx new file mode 100644 index 000000000..4a7febb49 --- /dev/null +++ b/src/lib/components/abi/type-form/TypeFieldInput.tsx @@ -0,0 +1,44 @@ +import { Flex, Input, Text } from "@chakra-ui/react"; +import { capitalize } from "lodash"; + +interface TypeFieldInputProps { + index: number; + value: string; + constraints: string[]; + onChange: (value: string) => void; +} + +export const TypeFieldInput = ({ + index, + value, + constraints, + onChange, +}: TypeFieldInputProps) => { + const placeholder = `Ability : ${ + constraints.length + ? constraints.map((constraint) => capitalize(constraint)).join(" + ") + : "none" + }`; + + return ( + + + {`T${index}:`} + + { + const newValue = e.target.value; + onChange(newValue); + }} + /> + + ); +}; diff --git a/src/lib/components/abi/type-form/index.tsx b/src/lib/components/abi/type-form/index.tsx new file mode 100644 index 000000000..1c7630572 --- /dev/null +++ b/src/lib/components/abi/type-form/index.tsx @@ -0,0 +1,47 @@ +import { Flex, Heading } from "@chakra-ui/react"; +import { useForm } from "react-hook-form"; + +import type { GenericTypeParam } from "lib/types"; + +import { TypeFieldInput } from "./TypeFieldInput"; + +interface TypeFormProps { + genericTypeParams: GenericTypeParam[]; + initialData: Record; + propsOnChange?: (data: Record) => void; +} + +export const TypeForm = ({ + genericTypeParams, + initialData, + propsOnChange, +}: TypeFormProps) => { + const { setValue, getValues } = useForm>({ + defaultValues: initialData, + mode: "all", + }); + + const handleOnChange = (index: number) => { + return (fieldInput: string) => { + setValue(`${index}`, fieldInput); + propsOnChange?.(getValues()); + }; + }; + + return ( + + + type_args + + {genericTypeParams.map(({ constraints }, index) => ( + + ))} + + ); +}; diff --git a/src/lib/components/forms/ControllerInput.tsx b/src/lib/components/forms/ControllerInput.tsx index fca0a4fe8..8a8417255 100644 --- a/src/lib/components/forms/ControllerInput.tsx +++ b/src/lib/components/forms/ControllerInput.tsx @@ -52,13 +52,16 @@ export const ControllerInput = ({ control, }); - const { field } = useController({ + const { + field, + fieldState: { isTouched }, + } = useController({ name, control, rules, }); - const isError = !!error; + const isError = isTouched && !!error; const isRequired = "required" in rules; return ( diff --git a/src/lib/pages/interaction/component/form/ExecuteArea.tsx b/src/lib/pages/interaction/component/form/ExecuteArea.tsx new file mode 100644 index 000000000..4f1a0e666 --- /dev/null +++ b/src/lib/pages/interaction/component/form/ExecuteArea.tsx @@ -0,0 +1,22 @@ +import { useState } from "react"; + +import { AbiForm, type AbiFormData } from "lib/components/abi"; +import type { ExposedFunction } from "lib/types"; +import { getAbiInitialData } from "lib/utils"; + +export const ExecuteArea = ({ fn }: { fn: ExposedFunction }) => { + const [data, setData] = useState({ + typeArgs: getAbiInitialData(fn.generic_type_params.length), + args: getAbiInitialData(fn.params.length), + }); + const [, setErrors] = useState<[string, string][]>([]); + + return ( + + ); +}; diff --git a/src/lib/pages/interaction/component/form/ViewArea.tsx b/src/lib/pages/interaction/component/form/ViewArea.tsx new file mode 100644 index 000000000..d14c62f32 --- /dev/null +++ b/src/lib/pages/interaction/component/form/ViewArea.tsx @@ -0,0 +1,31 @@ +import { SimpleGrid } from "@chakra-ui/react"; +import { useState } from "react"; + +import { AbiForm, type AbiFormData } from "lib/components/abi"; +import type { ExposedFunction } from "lib/types"; +import { getAbiInitialData } from "lib/utils"; + +export const ViewArea = ({ fn }: { fn: ExposedFunction }) => { + const [data, setData] = useState({ + typeArgs: getAbiInitialData(fn.generic_type_params.length), + args: getAbiInitialData(fn.params.length), + }); + const [, setErrors] = useState<[string, string][]>([]); + + return ( + + + + + ); +}; diff --git a/src/lib/pages/interaction/component/form/index.ts b/src/lib/pages/interaction/component/form/index.ts new file mode 100644 index 000000000..414fbdf25 --- /dev/null +++ b/src/lib/pages/interaction/component/form/index.ts @@ -0,0 +1,2 @@ +export * from "./ExecuteArea"; +export * from "./ViewArea"; diff --git a/src/lib/pages/interaction/component/index.ts b/src/lib/pages/interaction/component/index.ts index 6411ec9bc..5c6375a8d 100644 --- a/src/lib/pages/interaction/component/index.ts +++ b/src/lib/pages/interaction/component/index.ts @@ -1,3 +1,4 @@ export * from "./common"; export * from "./drawer"; +export * from "./form"; export * from "./main"; diff --git a/src/lib/pages/interaction/component/main/body.tsx b/src/lib/pages/interaction/component/main/body.tsx index e591a8772..67e7401d4 100644 --- a/src/lib/pages/interaction/component/main/body.tsx +++ b/src/lib/pages/interaction/component/main/body.tsx @@ -1,6 +1,7 @@ import { Button, Flex } from "@chakra-ui/react"; import { ModuleContainer } from "../common"; +import { ExecuteArea, ViewArea } from "../form"; import { CustomIcon } from "lib/components/icon"; import { EmptyState } from "lib/components/state"; import type { IndexedModule } from "lib/services/moduleService"; @@ -18,10 +19,20 @@ export const FunctionSelectBody = ({ module, selectedFn, openDrawer, -}: FunctionSelectBodyProps) => { - return selectedFn ? ( - +}: FunctionSelectBodyProps) => + selectedFn ? ( + + {selectedFn.is_view ? ( + + ) : ( + + )} ) : ( @@ -56,4 +67,3 @@ export const FunctionSelectBody = ({ )} ); -}; diff --git a/src/lib/types/abi.ts b/src/lib/types/abi.ts index a2dc9ca22..4a0dcde58 100644 --- a/src/lib/types/abi.ts +++ b/src/lib/types/abi.ts @@ -73,7 +73,7 @@ interface Struct { fields: Field[]; } -interface GenericTypeParam { +export interface GenericTypeParam { constraints: string[]; } diff --git a/src/lib/utils/abi.ts b/src/lib/utils/abi.ts index ffb62a4b8..2bdbed5ca 100644 --- a/src/lib/utils/abi.ts +++ b/src/lib/utils/abi.ts @@ -40,3 +40,11 @@ export const splitViewExecuteFunctions = (functions: ExposedFunction[]) => { return functionMap; }; + +export const getAbiInitialData = (length: number): Record => + Array(length) + .fill("") + .reduce>( + (prev, _, index) => ({ ...prev, [index.toString()]: "" }), + {} + ); From afb476abae0c153a0271e1be68de5e3cc1f1b9e6 Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Tue, 12 Sep 2023 15:32:51 +0700 Subject: [PATCH 02/11] fix: add return form --- src/lib/components/abi/AbiForm.tsx | 4 +- src/lib/components/abi/index.ts | 1 + .../components/abi/param-form/ParamField.tsx | 34 ++++++++++++---- src/lib/components/abi/param-form/index.tsx | 19 ++++++--- .../interaction/component/form/ViewArea.tsx | 40 +++++++++++-------- 5 files changed, 66 insertions(+), 32 deletions(-) diff --git a/src/lib/components/abi/AbiForm.tsx b/src/lib/components/abi/AbiForm.tsx index 53cd1d7e4..7ec49f437 100644 --- a/src/lib/components/abi/AbiForm.tsx +++ b/src/lib/components/abi/AbiForm.tsx @@ -46,11 +46,11 @@ export const AbiForm = ({ { + propsOnChange={(value) => { setValue("args", value); propsOnChange?.(getValues()); - propsOnErrors?.(errors); }} + propsOnErrors={propsOnErrors} /> )} diff --git a/src/lib/components/abi/index.ts b/src/lib/components/abi/index.ts index 46f667e90..adbb729ac 100644 --- a/src/lib/components/abi/index.ts +++ b/src/lib/components/abi/index.ts @@ -1 +1,2 @@ export * from "./AbiForm"; +export * from "./param-form"; diff --git a/src/lib/components/abi/param-form/ParamField.tsx b/src/lib/components/abi/param-form/ParamField.tsx index 748b08e35..b61ecf042 100644 --- a/src/lib/components/abi/param-form/ParamField.tsx +++ b/src/lib/components/abi/param-form/ParamField.tsx @@ -1,5 +1,10 @@ import { parseInt } from "lodash"; -import type { Control, FieldPath, FieldValues } from "react-hook-form"; +import type { + Control, + FieldPath, + FieldValues, + UseControllerProps, +} from "react-hook-form"; import { ControllerInput } from "lib/components/forms"; @@ -8,13 +13,31 @@ interface ParamFieldProps { param: string; control: Control; error?: string; + isReadOnly?: boolean; } +const getRules = ( + param: string, + isReadOnly: boolean +): UseControllerProps["rules"] => { + if (isReadOnly) return {}; + return { + validate: { + maxLength: (v: string) => + v.length <= 10 ? undefined : `${v.length} more than 10`, + positive: (v) => (parseInt(v) > 0 ? undefined : `${v} need positive`), + lessThanTen: (v) => parseInt(v) < 10, + }, + // pattern: { value: /^\d+$/, message: "This input is number only." }, + }; +}; + export const ParamField = ({ index, param, control, error, + isReadOnly = false, }: ParamFieldProps) => { return ( ({ control={control} label={param} variant="floating" - rules={{ - validate: { - positive: (v) => (parseInt(v) > 0 ? undefined : "need positive"), - lessThanTen: (v) => parseInt(v) < 10, - }, - // pattern: { value: /^\d+$/, message: "This input is number only." }, - }} + rules={getRules(param, isReadOnly)} error={error} + isReadOnly={isReadOnly} /> ); }; diff --git a/src/lib/components/abi/param-form/index.tsx b/src/lib/components/abi/param-form/index.tsx index 9978a632f..8fafd814f 100644 --- a/src/lib/components/abi/param-form/index.tsx +++ b/src/lib/components/abi/param-form/index.tsx @@ -6,12 +6,12 @@ import { useForm } from "react-hook-form"; import { ParamField } from "./ParamField"; interface ParamFormProps { + title?: string; params: string[]; initialData: Record; - propsOnChange?: ( - data: Record, - errors: [string, string][] - ) => void; + propsOnChange?: (data: Record) => void; + propsOnErrors?: (errors: [string, string][]) => void; + isReadOnly?: boolean; } const formatErrors = ( @@ -23,9 +23,12 @@ const formatErrors = ( ]); export const ParamForm = ({ + title = "args", params, initialData, propsOnChange, + propsOnErrors, + isReadOnly = false, }: ParamFormProps) => { const { trigger, @@ -44,11 +47,14 @@ export const ParamForm = ({ return ( - args + {title} {params.map((param, index) => { control.register(`${index}`, { - onChange: () => propsOnChange?.(getValues(), formatErrors(errors)), + onChange: () => { + propsOnChange?.(getValues()); + propsOnErrors?.(formatErrors(errors)); + }, }); return ( ); })} diff --git a/src/lib/pages/interaction/component/form/ViewArea.tsx b/src/lib/pages/interaction/component/form/ViewArea.tsx index d14c62f32..34a2b631f 100644 --- a/src/lib/pages/interaction/component/form/ViewArea.tsx +++ b/src/lib/pages/interaction/component/form/ViewArea.tsx @@ -1,7 +1,7 @@ -import { SimpleGrid } from "@chakra-ui/react"; +import { Grid, GridItem } from "@chakra-ui/react"; import { useState } from "react"; -import { AbiForm, type AbiFormData } from "lib/components/abi"; +import { AbiForm, ParamForm, type AbiFormData } from "lib/components/abi"; import type { ExposedFunction } from "lib/types"; import { getAbiInitialData } from "lib/utils"; @@ -11,21 +11,29 @@ export const ViewArea = ({ fn }: { fn: ExposedFunction }) => { args: getAbiInitialData(fn.params.length), }); const [, setErrors] = useState<[string, string][]>([]); + const [res, setRes] = useState>( + getAbiInitialData(fn.return.length) + ); return ( - - - - + + + + + + + + ); }; From 19bfcc803b8e6ba156e28d739c4ea4cd7e46d25c Mon Sep 17 00:00:00 2001 From: songwongtp <16089160+songwongtp@users.noreply.github.com> Date: Fri, 15 Sep 2023 01:13:18 +0700 Subject: [PATCH 03/11] feat: complete abi form for supported types --- package.json | 1 + src/lib/app-provider/hooks/useAddress.ts | 2 +- src/lib/components/AddressInput.tsx | 2 +- src/lib/components/OffChainForm.tsx | 4 +- src/lib/components/abi/AbiForm.tsx | 15 +- .../abi/args-form/field/ArgFieldWidget.tsx | 88 ++++++++++ .../components/abi/args-form/field/index.tsx | 109 ++++++++++++ .../components/abi/args-form/field/utils.ts | 107 ++++++++++++ .../abi/{param-form => args-form}/index.tsx | 18 +- src/lib/components/abi/index.ts | 2 +- .../components/abi/param-form/ParamField.tsx | 53 ------ .../TypeFieldInput.tsx | 12 +- .../abi/{type-form => types-form}/index.tsx | 14 +- .../components/forms/ControllerTextarea.tsx | 4 +- src/lib/components/forms/TextAreaInput.tsx | 6 +- src/lib/components/forms/index.ts | 2 +- src/lib/components/fund/selectFund.tsx | 2 +- .../modal/code/CodeDetailsTemplate.tsx | 2 +- src/lib/components/modal/code/SaveNewCode.tsx | 6 +- .../modal/contract/SaveNewContract.tsx | 4 +- .../components/modal/list/CreateNewList.tsx | 2 +- .../components/modal/list/EditListName.tsx | 2 +- .../select-code/CodeSelectSection.tsx | 2 +- .../select-contract/AllContractLists.tsx | 2 +- .../select-contract/ContractListDetail.tsx | 2 +- .../upload/InstantiatePermissionRadio.tsx | 2 +- src/lib/components/upload/UploadSection.tsx | 2 +- src/lib/pages/admin/index.tsx | 2 +- src/lib/pages/faucet/index.tsx | 2 +- src/lib/pages/instantiate/instantiate.tsx | 4 +- .../drawer/selector/SelectorInput.tsx | 2 +- .../component/form/ExecuteArea.tsx | 4 +- .../interaction/component/form/ViewArea.tsx | 10 +- src/lib/pages/interaction/index.tsx | 1 - src/lib/pages/proposal/store-code/index.tsx | 12 +- src/lib/pages/proposal/whitelist/index.tsx | 8 +- .../public-project/components/AllProject.tsx | 2 +- .../account/PublicProjectAccountTable.tsx | 2 +- .../table/code/PublicProjectCodeTable.tsx | 2 +- .../contract/PublicProjectContractTable.tsx | 2 +- src/lib/styles/theme/components/form.ts | 95 +++++++---- src/lib/types/abi.ts | 6 + src/lib/utils/abi.ts | 41 ++++- yarn.lock | 157 ++++++++++++++++-- 44 files changed, 640 insertions(+), 179 deletions(-) create mode 100644 src/lib/components/abi/args-form/field/ArgFieldWidget.tsx create mode 100644 src/lib/components/abi/args-form/field/index.tsx create mode 100644 src/lib/components/abi/args-form/field/utils.ts rename src/lib/components/abi/{param-form => args-form}/index.tsx (80%) delete mode 100644 src/lib/components/abi/param-form/ParamField.tsx rename src/lib/components/abi/{type-form => types-form}/TypeFieldInput.tsx (81%) rename src/lib/components/abi/{type-form => types-form}/index.tsx (80%) diff --git a/package.json b/package.json index 4094740c9..aee36c6b5 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "@emotion/styled": "^11", "@graphql-codegen/cli": "^2.13.12", "@graphql-codegen/client-preset": "^1.1.4", + "@initia/initia.js": "^0.1.8", "@rjsf/chakra-ui": "v5.0.0-beta.10", "@rjsf/core": "v5.0.0-beta.10", "@rjsf/utils": "v5.0.0-beta.10", diff --git a/src/lib/app-provider/hooks/useAddress.ts b/src/lib/app-provider/hooks/useAddress.ts index b69e26a93..220475716 100644 --- a/src/lib/app-provider/hooks/useAddress.ts +++ b/src/lib/app-provider/hooks/useAddress.ts @@ -54,7 +54,7 @@ const validateAddress = ( getAddressTypeByLength: GetAddressTypeByLengthFn ) => { if (!bech32Prefix) - return "Can not retrieve bech32 prefix of the current network."; + return "Cannot retrieve bech32 prefix of the current network."; const prefix = getPrefix(bech32Prefix, addressType); diff --git a/src/lib/components/AddressInput.tsx b/src/lib/components/AddressInput.tsx index 630be8527..21b2886f5 100644 --- a/src/lib/components/AddressInput.tsx +++ b/src/lib/components/AddressInput.tsx @@ -67,7 +67,7 @@ export const AddressInput = ({ label={label} placeholder={placeholder ?? exampleUserAddress} type="text" - variant="floating" + variant="fixed-floating" status={status} labelBgColor={labelBgColor} helperText={helperText} diff --git a/src/lib/components/OffChainForm.tsx b/src/lib/components/OffChainForm.tsx index 3e3e42607..a56a333d0 100644 --- a/src/lib/components/OffChainForm.tsx +++ b/src/lib/components/OffChainForm.tsx @@ -46,7 +46,7 @@ export const OffChainForm = ({ label="Name" placeholder={contractLabel} helperText="Set name for your contract" - variant="floating" + variant="fixed-floating" rules={{ maxLength: constants.maxContractNameLength, }} @@ -60,7 +60,7 @@ export const OffChainForm = ({ control={control} label="Description" placeholder="Help understanding what this contract do and how it works ..." - variant="floating" + variant="fixed-floating" rules={{ maxLength: constants.maxContractDescriptionLength, }} diff --git a/src/lib/components/abi/AbiForm.tsx b/src/lib/components/abi/AbiForm.tsx index 7ec49f437..cce57b23e 100644 --- a/src/lib/components/abi/AbiForm.tsx +++ b/src/lib/components/abi/AbiForm.tsx @@ -1,15 +1,10 @@ import { Flex } from "@chakra-ui/react"; import { useForm } from "react-hook-form"; -import type { ExposedFunction } from "lib/types"; +import type { AbiFormData, ExposedFunction } from "lib/types"; -import { ParamForm } from "./param-form"; -import { TypeForm } from "./type-form"; - -export interface AbiFormData { - typeArgs: Record; - args: Record; -} +import { ArgsForm } from "./args-form"; +import { TypesForm } from "./types-form"; interface AbiFormProps { fn: ExposedFunction; @@ -33,7 +28,7 @@ export const AbiForm = ({ return ( {Object.keys(typeArgs).length > 0 && ( - { @@ -43,7 +38,7 @@ export const AbiForm = ({ /> )} {Object.keys(args).length > 0 && ( - { diff --git a/src/lib/components/abi/args-form/field/ArgFieldWidget.tsx b/src/lib/components/abi/args-form/field/ArgFieldWidget.tsx new file mode 100644 index 000000000..aa5446e0d --- /dev/null +++ b/src/lib/components/abi/args-form/field/ArgFieldWidget.tsx @@ -0,0 +1,88 @@ +import { Input, Textarea } from "@chakra-ui/react"; +import { Select } from "chakra-react-select"; +import type { ControllerRenderProps } from "react-hook-form"; + +import type { Option } from "lib/types"; + +import { UintTypes } from "./utils"; + +const getInputPlaceholder = (type: string, isNull: boolean) => { + if (type === "0x1::string::String" && !isNull) + return "Left blank to send as empty string"; + if (type === "&signer") return "Signer is auto-filled when signing a tx"; + return " "; +}; + +const boolOptions = [ + { label: "True", value: "true" }, + { label: "False", value: "false" }, +]; + +interface ArgFieldWidgetProps { + type: string; + watcher: Option; + onChange: ControllerRenderProps["onChange"]; +} + +export const ArgFieldWidget = ({ + type, + watcher, + onChange, +}: ArgFieldWidgetProps) => { + if ( + UintTypes.includes(type) || + type === "address" || + type === "0x1::string::String" || + type === "&signer" + ) + return ( + + ); + + if (type === "bool") + return ( +