Commit 078a5626 authored by tom's avatar tom

[skip ci] special style for native coin value field

parent 24b0f112
...@@ -89,6 +89,7 @@ export interface SmartContractMethodInput { ...@@ -89,6 +89,7 @@ export interface SmartContractMethodInput {
name: string; name: string;
type: SmartContractMethodArgType; type: SmartContractMethodArgType;
components?: Array<SmartContractMethodInput>; components?: Array<SmartContractMethodInput>;
fieldType?: 'native_coin';
} }
export interface SmartContractMethodOutput extends SmartContractMethodInput { export interface SmartContractMethodOutput extends SmartContractMethodInput {
......
...@@ -6,6 +6,7 @@ import { useForm, FormProvider } from 'react-hook-form'; ...@@ -6,6 +6,7 @@ import { useForm, FormProvider } from 'react-hook-form';
import type { MethodFormFields, ContractMethodCallResult } from './types'; import type { MethodFormFields, ContractMethodCallResult } from './types';
import type { SmartContractMethodInput, SmartContractMethod } from 'types/api/contract'; import type { SmartContractMethodInput, SmartContractMethod } from 'types/api/contract';
import config from 'configs/app';
import arrowIcon from 'icons/arrows/down-right.svg'; import arrowIcon from 'icons/arrows/down-right.svg';
import * as mixpanel from 'lib/mixpanel/index'; import * as mixpanel from 'lib/mixpanel/index';
...@@ -38,9 +39,10 @@ const ContractMethodCallable = <T extends SmartContractMethod>({ data, onSubmit, ...@@ -38,9 +39,10 @@ const ContractMethodCallable = <T extends SmartContractMethod>({ data, onSubmit,
return [ return [
...('inputs' in data ? data.inputs : []), ...('inputs' in data ? data.inputs : []),
...('stateMutability' in data && data.stateMutability === 'payable' ? [ { ...('stateMutability' in data && data.stateMutability === 'payable' ? [ {
name: 'value', name: `Send native ${ config.chain.currency.symbol }`,
type: 'uint256' as const, type: 'uint256' as const,
internalType: 'uint256' as const, internalType: 'uint256' as const,
fieldType: 'native_coin' as const,
} ] : []), } ] : []),
]; ];
}, [ data ]); }, [ data ]);
...@@ -139,9 +141,11 @@ const ContractMethodCallable = <T extends SmartContractMethod>({ data, onSubmit, ...@@ -139,9 +141,11 @@ const ContractMethodCallable = <T extends SmartContractMethod>({ data, onSubmit,
<ContractMethodCallableRow <ContractMethodCallableRow
key={ fieldName } key={ fieldName }
fieldName={ fieldName } fieldName={ fieldName }
fieldType={ input.fieldType }
argName={ input.name } argName={ input.name }
argType={ input.type } argType={ input.type }
isDisabled={ isLoading } isDisabled={ isLoading }
isOptional={ input.fieldType === 'native_coin' && inputs.length > 1 }
onChange={ handleFormChange } onChange={ handleFormChange }
/> />
); );
......
import { Box } from '@chakra-ui/react'; import { Box, useColorModeValue } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import { useFormContext } from 'react-hook-form'; import { useFormContext } from 'react-hook-form';
import type { MethodFormFields } from './types'; import type { MethodFormFields } from './types';
import type { SmartContractMethodArgType } from 'types/api/contract'; import type { SmartContractMethodArgType, SmartContractMethodInput } from 'types/api/contract';
import ContractMethodField from './ContractMethodField'; import ContractMethodField from './ContractMethodField';
import ContractMethodFieldArray from './ContractMethodFieldArray'; import ContractMethodFieldArray from './ContractMethodFieldArray';
...@@ -11,16 +11,19 @@ import { ARRAY_REGEXP } from './utils'; ...@@ -11,16 +11,19 @@ import { ARRAY_REGEXP } from './utils';
interface Props { interface Props {
fieldName: string; fieldName: string;
fieldType?: SmartContractMethodInput['fieldType'];
argName: string; argName: string;
argType: SmartContractMethodArgType; argType: SmartContractMethodArgType;
onChange: () => void; onChange: () => void;
isDisabled: boolean; isDisabled: boolean;
isGrouped?: boolean; isGrouped?: boolean;
isOptional?: boolean;
} }
const ContractMethodCallableRow = ({ argName, fieldName, argType, onChange, isDisabled, isGrouped }: Props) => { const ContractMethodCallableRow = ({ argName, fieldName, fieldType, argType, onChange, isDisabled, isGrouped, isOptional }: Props) => {
const { control, getValues, setValue } = useFormContext<MethodFormFields>(); const { control, getValues, setValue } = useFormContext<MethodFormFields>();
const arrayTypeMatch = argType.match(ARRAY_REGEXP); const arrayTypeMatch = argType.match(ARRAY_REGEXP);
const nativeCoinFieldBgColor = useColorModeValue('blackAlpha.50', 'whiteAlpha.100');
const content = arrayTypeMatch ? ( const content = arrayTypeMatch ? (
<ContractMethodFieldArray <ContractMethodFieldArray
...@@ -36,27 +39,47 @@ const ContractMethodCallableRow = ({ argName, fieldName, argType, onChange, isDi ...@@ -36,27 +39,47 @@ const ContractMethodCallableRow = ({ argName, fieldName, argType, onChange, isDi
) : ( ) : (
<ContractMethodField <ContractMethodField
name={ fieldName } name={ fieldName }
type={ fieldType }
argType={ argType } argType={ argType }
placeholder={ argType } placeholder={ argType }
control={ control } control={ control }
setValue={ setValue } setValue={ setValue }
getValues={ getValues } getValues={ getValues }
isDisabled={ isDisabled } isDisabled={ isDisabled }
isOptional={ isOptional }
onChange={ onChange } onChange={ onChange }
/> />
); );
const isNativeCoinField = fieldType === 'native_coin';
return ( return (
<> <>
<Box <Box
position="relative"
fontWeight={ 500 } fontWeight={ 500 }
lineHeight="20px" lineHeight="20px"
py={{ lg: '6px' }} pt={{ base: isNativeCoinField ? '6px' : 0, lg: isNativeCoinField ? '10px' : '6px' }}
pb={{ lg: isNativeCoinField ? '10px' : '6px' }}
fontSize="sm" fontSize="sm"
color={ isGrouped ? 'text_secondary' : 'initial' } color={ isGrouped ? 'text_secondary' : 'initial' }
wordBreak="break-word" wordBreak="break-word"
_before={ isNativeCoinField ? {
content: `" "`,
position: 'absolute',
top: 0,
left: '-6px',
width: { base: 'calc(100% + 12px)', lg: 'calc(100% + 18px)' },
height: { base: 'calc(100% + 8px)', lg: '100%' },
bgColor: nativeCoinFieldBgColor,
borderTopLeftRadius: 'base',
borderTopRightRadius: { base: 'base', lg: 'none' },
borderBottomRightRadius: 'none',
borderBottomLeftRadius: { base: 'none', lg: 'base' },
zIndex: -1,
} : undefined }
> >
{ argName } ({ argType }) { argName }{ isOptional ? '' : '*' } ({ argType })
</Box> </Box>
{ content } { content }
</> </>
......
...@@ -4,6 +4,7 @@ import { ...@@ -4,6 +4,7 @@ import {
Input, Input,
InputGroup, InputGroup,
InputRightElement, InputRightElement,
useColorModeValue,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { Control, ControllerRenderProps, FieldError, UseFormGetValues, UseFormSetValue, UseFormStateReturn } from 'react-hook-form'; import type { Control, ControllerRenderProps, FieldError, UseFormGetValues, UseFormSetValue, UseFormStateReturn } from 'react-hook-form';
...@@ -12,7 +13,7 @@ import { NumericFormat } from 'react-number-format'; ...@@ -12,7 +13,7 @@ import { NumericFormat } from 'react-number-format';
import { isAddress, isHex, getAddress } from 'viem'; import { isAddress, isHex, getAddress } from 'viem';
import type { MethodFormFields } from './types'; import type { MethodFormFields } from './types';
import type { SmartContractMethodArgType } from 'types/api/contract'; import type { SmartContractMethodArgType, SmartContractMethodInput } from 'types/api/contract';
import ClearButton from 'ui/shared/ClearButton'; import ClearButton from 'ui/shared/ClearButton';
...@@ -21,6 +22,7 @@ import { INT_REGEXP, BYTES_REGEXP, getIntBoundaries, formatBooleanValue } from ' ...@@ -21,6 +22,7 @@ import { INT_REGEXP, BYTES_REGEXP, getIntBoundaries, formatBooleanValue } from '
interface Props { interface Props {
name: string; name: string;
type?: SmartContractMethodInput['fieldType'];
index?: number; index?: number;
groupName?: string; groupName?: string;
placeholder: string; placeholder: string;
...@@ -29,11 +31,14 @@ interface Props { ...@@ -29,11 +31,14 @@ interface Props {
setValue: UseFormSetValue<MethodFormFields>; setValue: UseFormSetValue<MethodFormFields>;
getValues: UseFormGetValues<MethodFormFields>; getValues: UseFormGetValues<MethodFormFields>;
isDisabled: boolean; isDisabled: boolean;
isOptional?: boolean;
onChange: () => void; onChange: () => void;
} }
const ContractMethodField = ({ control, name, groupName, index, argType, placeholder, setValue, getValues, isDisabled, onChange }: Props) => { const ContractMethodField = ({ control, name, type, groupName, index, argType, placeholder, setValue, getValues, isDisabled, isOptional, onChange }: Props) => {
const ref = React.useRef<HTMLInputElement>(null); const ref = React.useRef<HTMLInputElement>(null);
const nativeCoinFieldBgColor = useColorModeValue('blackAlpha.50', 'whiteAlpha.100');
const bgColor = useColorModeValue('white', 'black');
const handleClear = React.useCallback(() => { const handleClear = React.useCallback(() => {
setValue(name, ''); setValue(name, '');
...@@ -76,10 +81,28 @@ const ContractMethodField = ({ control, name, groupName, index, argType, placeho ...@@ -76,10 +81,28 @@ const ContractMethodField = ({ control, name, groupName, index, argType, placeho
const hasZerosControl = intMatch && Number(intMatch.power) >= 64; const hasZerosControl = intMatch && Number(intMatch.power) >= 64;
return ( return (
<Box w="100%"> <Box
w="100%"
pt={{ lg: type === 'native_coin' ? 1 : 0 }}
pb={{ base: type === 'native_coin' ? '6px' : 0, lg: type === 'native_coin' ? 1 : 0 }}
position="relative"
_before={ type === 'native_coin' ? {
content: `" "`,
position: 'absolute',
top: 0,
right: '-6px',
width: { base: 'calc(100% + 12px)', lg: 'calc(100% + 6px)' },
height: '100%',
bgColor: nativeCoinFieldBgColor,
borderTopLeftRadius: 'none',
borderTopRightRadius: { lg: 'base' },
borderBottomRightRadius: 'base',
borderBottomLeftRadius: { base: 'base', lg: 'none' },
zIndex: -1,
} : undefined }
>
<FormControl <FormControl
id={ name } id={ name }
mb={{ base: 1, lg: 0 }}
isDisabled={ isDisabled } isDisabled={ isDisabled }
> >
<InputGroup size="xs"> <InputGroup size="xs">
...@@ -93,10 +116,11 @@ const ContractMethodField = ({ control, name, groupName, index, argType, placeho ...@@ -93,10 +116,11 @@ const ContractMethodField = ({ control, name, groupName, index, argType, placeho
} : {}) } } : {}) }
ref={ ref } ref={ ref }
isInvalid={ Boolean(error) } isInvalid={ Boolean(error) }
required required={ !isOptional }
placeholder={ placeholder } placeholder={ placeholder }
paddingRight={ hasZerosControl ? '120px' : '40px' } paddingRight={ hasZerosControl ? '120px' : '40px' }
autoComplete="off" autoComplete="off"
bgColor={ bgColor }
/> />
<InputRightElement w="auto" right={ 1 }> <InputRightElement w="auto" right={ 1 }>
{ typeof field.value === 'string' && field.value.replace('\n', '') && <ClearButton onClick={ handleClear } isDisabled={ isDisabled }/> } { typeof field.value === 'string' && field.value.replace('\n', '') && <ClearButton onClick={ handleClear } isDisabled={ isDisabled }/> }
...@@ -107,7 +131,7 @@ const ContractMethodField = ({ control, name, groupName, index, argType, placeho ...@@ -107,7 +131,7 @@ const ContractMethodField = ({ control, name, groupName, index, argType, placeho
{ error && <Box color="error" fontSize="sm" mt={ 1 }>{ error.message }</Box> } { error && <Box color="error" fontSize="sm" mt={ 1 }>{ error.message }</Box> }
</Box> </Box>
); );
}, [ index, groupName, name, intMatch, isDisabled, placeholder, handleClear, handleAddZeroesClick ]); }, [ index, groupName, name, intMatch, type, nativeCoinFieldBgColor, isDisabled, isOptional, placeholder, bgColor, handleClear, handleAddZeroesClick ]);
const validate = React.useCallback((_value: string | Array<string>) => { const validate = React.useCallback((_value: string | Array<string>) => {
if (typeof _value === 'object') { if (typeof _value === 'object') {
...@@ -116,7 +140,7 @@ const ContractMethodField = ({ control, name, groupName, index, argType, placeho ...@@ -116,7 +140,7 @@ const ContractMethodField = ({ control, name, groupName, index, argType, placeho
const value = _value.replace('\n', ''); const value = _value.replace('\n', '');
if (!value) { if (!value && !isOptional) {
return 'Field is required'; return 'Field is required';
} }
...@@ -174,14 +198,14 @@ const ContractMethodField = ({ control, name, groupName, index, argType, placeho ...@@ -174,14 +198,14 @@ const ContractMethodField = ({ control, name, groupName, index, argType, placeho
} }
return true; return true;
}, [ bytesMatch, intMatch, argType ]); }, [ isOptional, argType, intMatch, bytesMatch ]);
return ( return (
<Controller <Controller
name={ name } name={ name }
control={ control } control={ control }
render={ renderInput } render={ renderInput }
rules={{ required: 'Field is required', validate }} rules={{ required: isOptional ? false : 'Field is required', validate }}
/> />
); );
}; };
......
...@@ -86,7 +86,7 @@ const ContractMethodsAccordionItem = <T extends SmartContractMethod>({ data, ind ...@@ -86,7 +86,7 @@ const ContractMethodsAccordionItem = <T extends SmartContractMethod>({ data, ind
<AccordionIcon/> <AccordionIcon/>
</AccordionButton> </AccordionButton>
</Element> </Element>
<AccordionPanel pb={ 4 } pr={ 0 } pl="28px"> <AccordionPanel pb={ 4 } pr={ 0 } pl="28px" w="calc(100% - 6px)">
{ renderContent(data, index, id) } { renderContent(data, index, id) }
</AccordionPanel> </AccordionPanel>
</AccordionItem> </AccordionItem>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment