Skip to content

Commit

Permalink
[skip ci] special style for native coin value field
Browse files Browse the repository at this point in the history
  • Loading branch information
tom2drum committed Dec 26, 2023
1 parent 24b0f11 commit 078a562
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 16 deletions.
1 change: 1 addition & 0 deletions types/api/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export interface SmartContractMethodInput {
name: string;
type: SmartContractMethodArgType;
components?: Array<SmartContractMethodInput>;
fieldType?: 'native_coin';
}

export interface SmartContractMethodOutput extends SmartContractMethodInput {
Expand Down
6 changes: 5 additions & 1 deletion ui/address/contract/ContractMethodCallable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useForm, FormProvider } from 'react-hook-form';
import type { MethodFormFields, ContractMethodCallResult } from './types';
import type { SmartContractMethodInput, SmartContractMethod } from 'types/api/contract';

import config from 'configs/app';
import arrowIcon from 'icons/arrows/down-right.svg';
import * as mixpanel from 'lib/mixpanel/index';

Expand Down Expand Up @@ -38,9 +39,10 @@ const ContractMethodCallable = <T extends SmartContractMethod>({ data, onSubmit,
return [
...('inputs' in data ? data.inputs : []),
...('stateMutability' in data && data.stateMutability === 'payable' ? [ {
name: 'value',
name: `Send native ${ config.chain.currency.symbol }`,
type: 'uint256' as const,
internalType: 'uint256' as const,
fieldType: 'native_coin' as const,
} ] : []),
];
}, [ data ]);
Expand Down Expand Up @@ -139,9 +141,11 @@ const ContractMethodCallable = <T extends SmartContractMethod>({ data, onSubmit,
<ContractMethodCallableRow
key={ fieldName }
fieldName={ fieldName }
fieldType={ input.fieldType }
argName={ input.name }
argType={ input.type }
isDisabled={ isLoading }
isOptional={ input.fieldType === 'native_coin' && inputs.length > 1 }
onChange={ handleFormChange }
/>
);
Expand Down
33 changes: 28 additions & 5 deletions ui/address/contract/ContractMethodCallableRow.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
import { Box } from '@chakra-ui/react';
import { Box, useColorModeValue } from '@chakra-ui/react';
import React from 'react';
import { useFormContext } from 'react-hook-form';

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 ContractMethodFieldArray from './ContractMethodFieldArray';
import { ARRAY_REGEXP } from './utils';

interface Props {
fieldName: string;
fieldType?: SmartContractMethodInput['fieldType'];
argName: string;
argType: SmartContractMethodArgType;
onChange: () => void;
isDisabled: 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 arrayTypeMatch = argType.match(ARRAY_REGEXP);
const nativeCoinFieldBgColor = useColorModeValue('blackAlpha.50', 'whiteAlpha.100');

const content = arrayTypeMatch ? (
<ContractMethodFieldArray
Expand All @@ -36,27 +39,47 @@ const ContractMethodCallableRow = ({ argName, fieldName, argType, onChange, isDi
) : (
<ContractMethodField
name={ fieldName }
type={ fieldType }
argType={ argType }
placeholder={ argType }
control={ control }
setValue={ setValue }
getValues={ getValues }
isDisabled={ isDisabled }
isOptional={ isOptional }
onChange={ onChange }
/>
);

const isNativeCoinField = fieldType === 'native_coin';

return (
<>
<Box
position="relative"
fontWeight={ 500 }
lineHeight="20px"
py={{ lg: '6px' }}
pt={{ base: isNativeCoinField ? '6px' : 0, lg: isNativeCoinField ? '10px' : '6px' }}
pb={{ lg: isNativeCoinField ? '10px' : '6px' }}
fontSize="sm"
color={ isGrouped ? 'text_secondary' : 'initial' }
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>
{ content }
</>
Expand Down
42 changes: 33 additions & 9 deletions ui/address/contract/ContractMethodField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
Input,
InputGroup,
InputRightElement,
useColorModeValue,
} from '@chakra-ui/react';
import React from 'react';
import type { Control, ControllerRenderProps, FieldError, UseFormGetValues, UseFormSetValue, UseFormStateReturn } from 'react-hook-form';
Expand All @@ -12,7 +13,7 @@ import { NumericFormat } from 'react-number-format';
import { isAddress, isHex, getAddress } from 'viem';

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';

Expand All @@ -21,6 +22,7 @@ import { INT_REGEXP, BYTES_REGEXP, getIntBoundaries, formatBooleanValue } from '

interface Props {
name: string;
type?: SmartContractMethodInput['fieldType'];
index?: number;
groupName?: string;
placeholder: string;
Expand All @@ -29,11 +31,14 @@ interface Props {
setValue: UseFormSetValue<MethodFormFields>;
getValues: UseFormGetValues<MethodFormFields>;
isDisabled: boolean;
isOptional?: boolean;
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 nativeCoinFieldBgColor = useColorModeValue('blackAlpha.50', 'whiteAlpha.100');
const bgColor = useColorModeValue('white', 'black');

const handleClear = React.useCallback(() => {
setValue(name, '');
Expand Down Expand Up @@ -76,10 +81,28 @@ const ContractMethodField = ({ control, name, groupName, index, argType, placeho
const hasZerosControl = intMatch && Number(intMatch.power) >= 64;

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
id={ name }
mb={{ base: 1, lg: 0 }}
isDisabled={ isDisabled }
>
<InputGroup size="xs">
Expand All @@ -93,10 +116,11 @@ const ContractMethodField = ({ control, name, groupName, index, argType, placeho
} : {}) }
ref={ ref }
isInvalid={ Boolean(error) }
required
required={ !isOptional }
placeholder={ placeholder }
paddingRight={ hasZerosControl ? '120px' : '40px' }
autoComplete="off"
bgColor={ bgColor }
/>
<InputRightElement w="auto" right={ 1 }>
{ typeof field.value === 'string' && field.value.replace('\n', '') && <ClearButton onClick={ handleClear } isDisabled={ isDisabled }/> }
Expand All @@ -107,7 +131,7 @@ const ContractMethodField = ({ control, name, groupName, index, argType, placeho
{ error && <Box color="error" fontSize="sm" mt={ 1 }>{ error.message }</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>) => {
if (typeof _value === 'object') {
Expand All @@ -116,7 +140,7 @@ const ContractMethodField = ({ control, name, groupName, index, argType, placeho

const value = _value.replace('\n', '');

if (!value) {
if (!value && !isOptional) {
return 'Field is required';
}

Expand Down Expand Up @@ -174,14 +198,14 @@ const ContractMethodField = ({ control, name, groupName, index, argType, placeho
}

return true;
}, [ bytesMatch, intMatch, argType ]);
}, [ isOptional, argType, intMatch, bytesMatch ]);

return (
<Controller
name={ name }
control={ control }
render={ renderInput }
rules={{ required: 'Field is required', validate }}
rules={{ required: isOptional ? false : 'Field is required', validate }}
/>
);
};
Expand Down
2 changes: 1 addition & 1 deletion ui/address/contract/ContractMethodsAccordionItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ const ContractMethodsAccordionItem = <T extends SmartContractMethod>({ data, ind
<AccordionIcon/>
</AccordionButton>
</Element>
<AccordionPanel pb={ 4 } pr={ 0 } pl="28px">
<AccordionPanel pb={ 4 } pr={ 0 } pl="28px" w="calc(100% - 6px)">
{ renderContent(data, index, id) }
</AccordionPanel>
</AccordionItem>
Expand Down

0 comments on commit 078a562

Please sign in to comment.