Commit 507a29af authored by tom's avatar tom

Merge branch 'main' of github.com:blockscout/frontend into tx-page-api

parents 1862b8e5 1b704fec
...@@ -72,7 +72,7 @@ ...@@ -72,7 +72,7 @@
"github": "https://github.com/mikhin" "github": "https://github.com/mikhin"
}, },
{ {
"chainId": 1, "chainId": 100,
"author": "xDaichain", "author": "xDaichain",
"id": "bao-finance", "id": "bao-finance",
"title": "Bao Finance", "title": "Bao Finance",
......
import { formAnatomy as parts } from '@chakra-ui/anatomy'; import { formAnatomy as parts } from '@chakra-ui/anatomy';
import { import { createMultiStyleConfigHelpers } from '@chakra-ui/styled-system';
createMultiStyleConfigHelpers, import type { StyleFunctionProps } from '@chakra-ui/theme-tools';
} from '@chakra-ui/styled-system';
import { getColor, mode } from '@chakra-ui/theme-tools'; import { getColor, mode } from '@chakra-ui/theme-tools';
import type { Dict } from '@chakra-ui/utils';
import getDefaultFormColors from '../utils/getDefaultFormColors'; import getDefaultFormColors from '../utils/getDefaultFormColors';
import FormLabel from './FormLabel';
import Input from './Input';
import Textarea from './Textarea';
const { definePartsStyle, defineMultiStyleConfig } = const { definePartsStyle, defineMultiStyleConfig } =
createMultiStyleConfigHelpers(parts.keys); createMultiStyleConfigHelpers(parts.keys);
const getActiveLabelStyles = (theme: Dict, fc: string, bc: string, size: 'md' | 'lg') => { function getFloatingVariantStylesForSize(size: 'md' | 'lg', props: StyleFunctionProps) {
const baseStyles = { const { theme } = props;
backgroundColor: bc, const { focusColor: fc, errorColor: ec } = getDefaultFormColors(props);
color: getColor(theme, fc),
fontSize: 'xs',
lineHeight: '16px',
borderTopRightRadius: 'none',
};
switch (size) {
case 'md': {
return {
...baseStyles,
padding: '10px 16px 2px 16px',
};
}
case 'lg': {
return {
...baseStyles,
padding: '16px 24px 2px 24px',
};
}
}
};
const getDefaultLabelStyles = (size: 'md' | 'lg') => {
switch (size) {
case 'md': {
return {
fontSize: 'md',
lineHeight: '20px',
padding: '18px 16px',
right: '18px',
};
}
case 'lg': {
return {
fontSize: 'md',
lineHeight: '24px',
padding: '28px 24px',
right: '26px',
};
}
}
};
const getPaddingX = (size: 'md' | 'lg') => {
switch (size) {
case 'md': {
return '16px';
}
case 'lg': { const activeLabelStyles = {
return '24px'; ...FormLabel.variants?.floating?.(props)._focusWithin,
...FormLabel.sizes?.[size](props)._focusWithin,
} || {};
const activeInputStyles = (() => {
switch (size) {
case 'md': {
return {
paddingTop: '26px',
paddingBottom: '10px',
};
}
case 'lg': {
return {
paddingTop: '38px',
paddingBottom: '18px',
};
}
} }
} })();
};
const getActiveInputStyles = (size: 'md' | 'lg') => { const inputPx = (() => {
switch (size) { switch (size) {
case 'md': { case 'md': {
return { return '16px';
paddingTop: '26px', }
paddingBottom: '10px',
};
}
case 'lg': { case 'lg': {
return { return '24px';
paddingTop: '38px', }
paddingBottom: '18px',
};
} }
} })();
};
const variantFloating = definePartsStyle((props) => {
const { theme, backgroundColor, size = 'md' } = props;
const { focusColor: fc, errorColor: ec } = getDefaultFormColors(props);
const bc = backgroundColor || mode('white', 'black')(props);
const px = getPaddingX(size);
const activeInputStyles = getActiveInputStyles(size);
const activeLabelStyles = getActiveLabelStyles(theme, fc, bc, size);
return { return {
container: { container: {
// active styles
_focusWithin: { _focusWithin: {
label: { label: activeLabelStyles,
...activeLabelStyles, 'input, textarea': activeInputStyles,
},
'input, textarea': {
...activeInputStyles,
},
'label .chakra-form__required-indicator': {
color: getColor(theme, fc),
},
},
// label's styles
label: {
...getDefaultLabelStyles(size),
left: '2px',
top: '2px',
zIndex: 2,
position: 'absolute',
borderRadius: 'base',
boxSizing: 'border-box',
color: 'gray.500',
backgroundColor: 'transparent',
pointerEvents: 'none',
margin: 0,
transformOrigin: 'top left',
transitionProperty: 'font-size, line-height, padding, top, background-color',
overflow: 'hidden',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
},
'input:not(:placeholder-shown) + label, textarea:not(:placeholder-shown) + label': {
...activeLabelStyles,
}, },
// label styles
label: FormLabel.sizes?.[size](props) || {},
'input:not(:placeholder-shown) + label, textarea:not(:placeholder-shown) + label': activeLabelStyles,
'input[aria-invalid=true] + label, textarea[aria-invalid=true] + label': { 'input[aria-invalid=true] + label, textarea[aria-invalid=true] + label': {
color: getColor(theme, ec), color: getColor(theme, ec),
}, },
// input's styles
// input styles
input: Input.sizes?.[size].field,
textarea: Textarea.sizes?.[size],
'input, textarea': { 'input, textarea': {
padding: px, padding: inputPx,
}, },
'input:not(:placeholder-shown), textarea:not(:placeholder-shown)': activeInputStyles,
'input[disabled] + label, textarea[disabled] + label': { 'input[disabled] + label, textarea[disabled] + label': {
backgroundColor: 'transparent', backgroundColor: 'transparent',
}, },
'input:not(:placeholder-shown), textarea:not(:placeholder-shown)': {
...activeInputStyles, // indicator styles
},
// indicator's styles
'input:not(:placeholder-shown) + label .chakra-form__required-indicator, textarea:not(:placeholder-shown) + label .chakra-form__required-indicator': { 'input:not(:placeholder-shown) + label .chakra-form__required-indicator, textarea:not(:placeholder-shown) + label .chakra-form__required-indicator': {
color: getColor(theme, fc), color: getColor(theme, fc),
}, },
...@@ -153,6 +84,11 @@ const variantFloating = definePartsStyle((props) => { ...@@ -153,6 +84,11 @@ const variantFloating = definePartsStyle((props) => {
color: getColor(theme, ec), color: getColor(theme, ec),
}, },
}, },
};
}
const baseStyle = definePartsStyle((props) => {
return {
requiredIndicator: { requiredIndicator: {
marginStart: 0, marginStart: 0,
color: mode('gray.500', 'whiteAlpha.400')(props), color: mode('gray.500', 'whiteAlpha.400')(props),
...@@ -160,12 +96,42 @@ const variantFloating = definePartsStyle((props) => { ...@@ -160,12 +96,42 @@ const variantFloating = definePartsStyle((props) => {
}; };
}); });
const variantFloating = definePartsStyle((props) => {
return {
container: {
label: FormLabel.variants?.floating(props) || {},
},
};
});
const sizes = {
lg: definePartsStyle((props) => {
if (props.variant === 'floating') {
return getFloatingVariantStylesForSize('lg', props);
}
return {};
}),
md: definePartsStyle((props) => {
if (props.variant === 'floating') {
return getFloatingVariantStylesForSize('md', props);
}
return {};
}),
};
const variants = { const variants = {
floating: variantFloating, floating: variantFloating,
}; };
const Form = defineMultiStyleConfig({ const Form = defineMultiStyleConfig({
baseStyle,
variants, variants,
sizes,
defaultProps: {
size: 'md',
},
}); });
export default Form; export default Form;
import { defineStyle, defineStyleConfig } from '@chakra-ui/styled-system';
import { getColor, mode } from '@chakra-ui/theme-tools';
import getDefaultFormColors from '../utils/getDefaultFormColors';
const baseStyle = defineStyle({
fontSize: 'md',
marginEnd: '3',
mb: '2',
fontWeight: 'medium',
transitionProperty: 'common',
transitionDuration: 'normal',
opacity: 1,
_disabled: {
opacity: 0.4,
},
});
const variantFloating = defineStyle((props) => {
const { theme, backgroundColor } = props;
const { focusColor: fc } = getDefaultFormColors(props);
const bc = backgroundColor || mode('white', 'black')(props);
return {
left: '2px',
top: '2px',
zIndex: 2,
position: 'absolute',
borderRadius: 'base',
boxSizing: 'border-box',
color: 'gray.500',
backgroundColor: 'transparent',
pointerEvents: 'none',
margin: 0,
transformOrigin: 'top left',
transitionProperty: 'font-size, line-height, padding, top, background-color',
overflow: 'hidden',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
_focusWithin: {
backgroundColor: bc,
color: getColor(theme, fc),
fontSize: 'xs',
lineHeight: '16px',
borderTopRightRadius: 'none',
},
};
});
const variants = {
floating: variantFloating,
};
const sizes = {
lg: defineStyle((props) => {
if (props.variant === 'floating') {
return {
fontSize: 'md',
lineHeight: '24px',
padding: '28px 24px',
right: '26px',
_focusWithin: {
padding: '16px 24px 2px 24px',
},
};
}
return {};
}),
md: defineStyle((props) => {
if (props.variant === 'floating') {
return {
fontSize: 'md',
lineHeight: '20px',
padding: '18px 16px',
right: '18px',
_focusWithin: {
padding: '10px 16px 2px 16px',
},
};
}
return {};
}),
};
const FormLabel = defineStyleConfig({
variants,
baseStyle,
sizes,
});
export default FormLabel;
...@@ -4,6 +4,7 @@ import Button from './Button'; ...@@ -4,6 +4,7 @@ import Button from './Button';
import Checkbox from './Checkbox'; import Checkbox from './Checkbox';
import Drawer from './Drawer'; import Drawer from './Drawer';
import Form from './Form'; import Form from './Form';
import FormLabel from './FormLabel';
import Heading from './Heading'; import Heading from './Heading';
import Input from './Input'; import Input from './Input';
import Link from './Link'; import Link from './Link';
...@@ -27,6 +28,7 @@ const components = { ...@@ -27,6 +28,7 @@ const components = {
Heading, Heading,
Input, Input,
Form, Form,
FormLabel,
Link, Link,
Modal, Modal,
Popover, Popover,
......
...@@ -3,7 +3,7 @@ import type { AddressParam } from './addressParams'; ...@@ -3,7 +3,7 @@ import type { AddressParam } from './addressParams';
export type TxInternalsType = 'call' | 'delegatecall' | 'staticcall' | 'create' | 'create2' | 'selfdestruct' | 'reward' export type TxInternalsType = 'call' | 'delegatecall' | 'staticcall' | 'create' | 'create2' | 'selfdestruct' | 'reward'
export interface InternalTransaction { export interface InternalTransaction {
error?: string; error: string | null;
success: boolean; success: boolean;
type: TxInternalsType; type: TxInternalsType;
transaction_hash: string; transaction_hash: string;
......
...@@ -6,7 +6,7 @@ export interface Log { ...@@ -6,7 +6,7 @@ export interface Log {
topics: Array<string>; topics: Array<string>;
data: string; data: string;
index: number; index: number;
decoded?: DecodedInput; decoded: DecodedInput | null;
} }
export interface LogsResponse { export interface LogsResponse {
......
...@@ -11,7 +11,7 @@ export interface RawTrace { ...@@ -11,7 +11,7 @@ export interface RawTrace {
gasUsed: string; gasUsed: string;
output: string; output: string;
}; };
error?: string; error: string | null;
subtraces: number; subtraces: number;
traceAddress: Array<number>; traceAddress: Array<number>;
type: string; type: string;
......
...@@ -6,7 +6,7 @@ export type Tokenlist = { ...@@ -6,7 +6,7 @@ export type Tokenlist = {
export type TokenlistItem = { export type TokenlistItem = {
balance: number; balance: number;
contractAddress: string; contractAddress: string;
decimals?: number; decimals: number | null;
id: number; id: number;
name: string; name: string;
symbol: string; symbol: string;
......
...@@ -20,20 +20,20 @@ export interface Transaction { ...@@ -20,20 +20,20 @@ export interface Transaction {
type: number; type: number;
gas_used: string; gas_used: string;
gas_limit: string; gas_limit: string;
max_fee_per_gas?: number; max_fee_per_gas: number | null;
max_priority_fee_per_gas?: number; max_priority_fee_per_gas: number | null;
priority_fee?: number; priority_fee: number | null;
base_fee_per_gas?: number; base_fee_per_gas: number | null;
tx_burnt_fee?: number; tx_burnt_fee: number | null;
nonce: number; nonce: number;
position: number; position: number;
revert_reason?: { revert_reason: {
raw: string; raw: string;
decoded: string; decoded: string;
}; } | null;
raw_input: string; raw_input: string;
decoded_input?: DecodedInput; decoded_input: DecodedInput | null;
token_transfers?: Array<TokenTransfer>; token_transfers: Array<TokenTransfer> | null;
token_transfers_overflow: boolean; token_transfers_overflow: boolean;
exchange_rate: string; exchange_rate: string;
} }
......
...@@ -23,7 +23,7 @@ const Apps = () => { ...@@ -23,7 +23,7 @@ const Apps = () => {
setDisplayedAppId(id); setDisplayedAppId(id);
}, []); }, []);
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
const debounceFilterApps = useCallback(debounce(q => filterApps(q), 500), []); const debounceFilterApps = useCallback(debounce(q => filterApps(q), 500), [ defaultAppList ]);
const clearDisplayedAppId = useCallback(() => setDisplayedAppId(null), []); const clearDisplayedAppId = useCallback(() => setDisplayedAppId(null), []);
function filterApps(q: string) { function filterApps(q: string) {
......
...@@ -27,10 +27,10 @@ const MarketplaceApp = ({ app, isLoading }: Props) => { ...@@ -27,10 +27,10 @@ const MarketplaceApp = ({ app, isLoading }: Props) => {
'allow-top-navigation-by-user-activation'; 'allow-top-navigation-by-user-activation';
useEffect(() => { useEffect(() => {
if (app) { if (app && !isFrameLoading) {
ref?.current?.contentWindow?.postMessage({ colorMode, chaindId: network?.chainId }, app.url); ref?.current?.contentWindow?.postMessage({ blockscoutColorMode: colorMode, blockscoutChainId: network?.chainId }, app.url);
} }
}, [ app, colorMode, network, ref ]); }, [ isFrameLoading, app, colorMode, network, ref ]);
return ( return (
<Page wrapChildren={ false }> <Page wrapChildren={ false }>
......
...@@ -25,7 +25,6 @@ const MyProfile = () => { ...@@ -25,7 +25,6 @@ const MyProfile = () => {
<UserAvatar size={ 64 } data={ data }/> <UserAvatar size={ 64 } data={ data }/>
<FormControl variant="floating" id="name" isRequired size="lg"> <FormControl variant="floating" id="name" isRequired size="lg">
<Input <Input
size="lg"
required required
disabled disabled
value={ data.name || '' } value={ data.name || '' }
...@@ -34,7 +33,6 @@ const MyProfile = () => { ...@@ -34,7 +33,6 @@ const MyProfile = () => {
</FormControl> </FormControl>
<FormControl variant="floating" id="nickname" isRequired size="lg"> <FormControl variant="floating" id="nickname" isRequired size="lg">
<Input <Input
size="lg"
required required
disabled disabled
value={ data.nickname || '' } value={ data.nickname || '' }
...@@ -43,7 +41,6 @@ const MyProfile = () => { ...@@ -43,7 +41,6 @@ const MyProfile = () => {
</FormControl> </FormControl>
<FormControl variant="floating" id="email" isRequired size="lg"> <FormControl variant="floating" id="email" isRequired size="lg">
<Input <Input
size="lg"
required required
disabled disabled
value={ data.email } value={ data.email }
......
import type { InputProps } from '@chakra-ui/react';
import { IconButton, Icon, Flex } from '@chakra-ui/react'; import { IconButton, Icon, Flex } from '@chakra-ui/react';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import type { ControllerRenderProps, Control, FieldError } from 'react-hook-form'; import type { ControllerRenderProps, Control, FieldError } from 'react-hook-form';
...@@ -17,7 +18,7 @@ interface Props { ...@@ -17,7 +18,7 @@ interface Props {
error?: FieldError; error?: FieldError;
onAddFieldClick: (e: React.SyntheticEvent) => void; onAddFieldClick: (e: React.SyntheticEvent) => void;
onRemoveFieldClick: (index: number) => (e: React.SyntheticEvent) => void; onRemoveFieldClick: (index: number) => (e: React.SyntheticEvent) => void;
size?: string; size?: InputProps['size'];
} }
const MAX_INPUTS_NUM = 10; const MAX_INPUTS_NUM = 10;
......
import type { InputProps } from '@chakra-ui/react';
import { FormControl, FormLabel, Textarea } from '@chakra-ui/react'; import { FormControl, FormLabel, Textarea } from '@chakra-ui/react';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import type { ControllerRenderProps, Control, FieldError } from 'react-hook-form'; import type { ControllerRenderProps, Control, FieldError } from 'react-hook-form';
...@@ -12,7 +13,7 @@ const TEXT_INPUT_MAX_LENGTH = 255; ...@@ -12,7 +13,7 @@ const TEXT_INPUT_MAX_LENGTH = 255;
interface Props { interface Props {
control: Control<Inputs>; control: Control<Inputs>;
error?: FieldError; error?: FieldError;
size?: string; size?: InputProps['size'];
} }
export default function PublicTagFormComment({ control, error, size }: Props) { export default function PublicTagFormComment({ control, error, size }: Props) {
...@@ -22,7 +23,6 @@ export default function PublicTagFormComment({ control, error, size }: Props) { ...@@ -22,7 +23,6 @@ export default function PublicTagFormComment({ control, error, size }: Props) {
<Textarea <Textarea
{ ...field } { ...field }
isInvalid={ Boolean(error) } isInvalid={ Boolean(error) }
size={ size }
/> />
<FormLabel> <FormLabel>
{ getPlaceholderWithError('Specify the reason for adding tags and color preference(s)', error?.message) } { getPlaceholderWithError('Specify the reason for adding tags and color preference(s)', error?.message) }
......
...@@ -16,7 +16,6 @@ import type { PublicTags, PublicTag, PublicTagNew, PublicTagErrors } from 'types ...@@ -16,7 +16,6 @@ import type { PublicTags, PublicTag, PublicTagNew, PublicTagErrors } from 'types
import getErrorMessage from 'lib/getErrorMessage'; import getErrorMessage from 'lib/getErrorMessage';
import type { ErrorType } from 'lib/hooks/useFetch'; import type { ErrorType } from 'lib/hooks/useFetch';
import useFetch from 'lib/hooks/useFetch'; import useFetch from 'lib/hooks/useFetch';
import useIsMobile from 'lib/hooks/useIsMobile';
import { EMAIL_REGEXP } from 'lib/validations/email'; import { EMAIL_REGEXP } from 'lib/validations/email';
import FormSubmitAlert from 'ui/shared/FormSubmitAlert'; import FormSubmitAlert from 'ui/shared/FormSubmitAlert';
...@@ -57,9 +56,8 @@ const ADDRESS_INPUT_BUTTONS_WIDTH = 100; ...@@ -57,9 +56,8 @@ const ADDRESS_INPUT_BUTTONS_WIDTH = 100;
const PublicTagsForm = ({ changeToDataScreen, data }: Props) => { const PublicTagsForm = ({ changeToDataScreen, data }: Props) => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const isMobile = useIsMobile();
const fetch = useFetch(); const fetch = useFetch();
const inputSize = isMobile ? 'md' : 'lg'; const inputSize = { base: 'md', lg: 'lg' };
const { control, handleSubmit, formState: { errors, isValid }, setError } = useForm<Inputs>({ const { control, handleSubmit, formState: { errors, isValid }, setError } = useForm<Inputs>({
defaultValues: { defaultValues: {
......
import type { InputProps } from '@chakra-ui/react';
import { FormControl, FormLabel, Input } from '@chakra-ui/react'; import { FormControl, FormLabel, Input } from '@chakra-ui/react';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import type { ControllerRenderProps, FieldError, FieldValues, Path, Control } from 'react-hook-form'; import type { ControllerRenderProps, FieldError, FieldValues, Path, Control } from 'react-hook-form';
...@@ -14,7 +15,7 @@ interface Props<TInputs extends FieldValues> { ...@@ -14,7 +15,7 @@ interface Props<TInputs extends FieldValues> {
control: Control<TInputs, object>; control: Control<TInputs, object>;
pattern?: RegExp; pattern?: RegExp;
error?: FieldError; error?: FieldError;
size?: string; size?: InputProps['size'];
} }
export default function PublicTagsFormInput<Inputs extends FieldValues>({ export default function PublicTagsFormInput<Inputs extends FieldValues>({
...@@ -31,7 +32,6 @@ export default function PublicTagsFormInput<Inputs extends FieldValues>({ ...@@ -31,7 +32,6 @@ export default function PublicTagsFormInput<Inputs extends FieldValues>({
<FormControl variant="floating" id={ field.name } isRequired={ required } size={ size }> <FormControl variant="floating" id={ field.name } isRequired={ required } size={ size }>
<Input <Input
{ ...field } { ...field }
size={ size }
required={ required } required={ required }
isInvalid={ Boolean(error) } isInvalid={ Boolean(error) }
maxLength={ TEXT_INPUT_MAX_LENGTH } maxLength={ TEXT_INPUT_MAX_LENGTH }
......
import type { InputProps } from '@chakra-ui/react';
import { import {
Input, Input,
FormControl, FormControl,
...@@ -11,7 +12,7 @@ import { ADDRESS_LENGTH } from 'lib/validations/address'; ...@@ -11,7 +12,7 @@ import { ADDRESS_LENGTH } from 'lib/validations/address';
type Props<TInputs extends FieldValues, TInputName extends Path<TInputs>> = { type Props<TInputs extends FieldValues, TInputName extends Path<TInputs>> = {
field: ControllerRenderProps<TInputs, TInputName>; field: ControllerRenderProps<TInputs, TInputName>;
size?: string; size?: InputProps['size'];
placeholder?: string; placeholder?: string;
backgroundColor?: string; backgroundColor?: string;
error?: FieldError; error?: FieldError;
...@@ -31,7 +32,6 @@ export default function AddressInput<Inputs extends FieldValues, Name extends Pa ...@@ -31,7 +32,6 @@ export default function AddressInput<Inputs extends FieldValues, Name extends Pa
{ ...field } { ...field }
isInvalid={ Boolean(error) } isInvalid={ Boolean(error) }
maxLength={ ADDRESS_LENGTH } maxLength={ ADDRESS_LENGTH }
size={ size }
/> />
<FormLabel>{ getPlaceholderWithError(placeholder, error?.message) }</FormLabel> <FormLabel>{ getPlaceholderWithError(placeholder, error?.message) }</FormLabel>
</FormControl> </FormControl>
......
...@@ -9,7 +9,7 @@ import successIcon from 'icons/status/success.svg'; ...@@ -9,7 +9,7 @@ import successIcon from 'icons/status/success.svg';
export interface Props { export interface Props {
status: Transaction['status']; status: Transaction['status'];
errorText?: string; errorText?: string | null;
} }
const TxStatus = ({ status, errorText }: Props) => { const TxStatus = ({ status, errorText }: Props) => {
......
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