Commit abf8a445 authored by tom goriunov's avatar tom goriunov Committed by GitHub

Update styles of form inputs (#1914)

* Update styles of form inputs

* update token info form

* update demo values

* fix preset for sepolia

* update screenshots
parent 8796abbf
...@@ -24,8 +24,8 @@ NEXT_PUBLIC_API_BASE_PATH=/ ...@@ -24,8 +24,8 @@ NEXT_PUBLIC_API_BASE_PATH=/
# ui config # ui config
## homepage ## homepage
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs'] NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs']
NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND='rgba(51, 53, 67, 1)' NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND=rgba(51,53,67,1)
NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR='rgba(165, 252, 122, 1)' NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR=rgba(165,252,122,1)
## sidebar ## sidebar
NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/featured-networks/eth-sepolia.json NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/featured-networks/eth-sepolia.json
NEXT_PUBLIC_NETWORK_LOGO=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-logos/sepolia.svg NEXT_PUBLIC_NETWORK_LOGO=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-logos/sepolia.svg
......
...@@ -94,7 +94,6 @@ frontend: ...@@ -94,7 +94,6 @@ frontend:
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE: "{ \"id\": \"632018\", \"width\": \"320\", \"height\": \"100\" }" NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE: "{ \"id\": \"632018\", \"width\": \"320\", \"height\": \"100\" }"
NEXT_PUBLIC_DATA_AVAILABILITY_ENABLED: true NEXT_PUBLIC_DATA_AVAILABILITY_ENABLED: true
NEXT_PUBLIC_OG_ENHANCED_DATA_ENABLED: true NEXT_PUBLIC_OG_ENHANCED_DATA_ENABLED: true
NEXT_PUBLIC_COLOR_THEME_DEFAULT: "dim"
envFromSecret: envFromSecret:
NEXT_PUBLIC_SENTRY_DSN: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_SENTRY_DSN NEXT_PUBLIC_SENTRY_DSN: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_SENTRY_DSN
SENTRY_CSP_REPORT_URI: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/SENTRY_CSP_REPORT_URI SENTRY_CSP_REPORT_URI: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/SENTRY_CSP_REPORT_URI
......
import { formAnatomy as parts } from '@chakra-ui/anatomy'; import { formAnatomy as parts } from '@chakra-ui/anatomy';
import { createMultiStyleConfigHelpers } from '@chakra-ui/styled-system'; import { createMultiStyleConfigHelpers } from '@chakra-ui/styled-system';
import type { StyleFunctionProps } from '@chakra-ui/theme-tools'; import type { StyleFunctionProps } from '@chakra-ui/theme-tools';
import { getColor, mode } from '@chakra-ui/theme-tools';
import getDefaultFormColors from '../utils/getDefaultFormColors'; import getFormStyles from '../utils/getFormStyles';
import FancySelect from './FancySelect'; import FancySelect from './FancySelect';
import FormLabel from './FormLabel'; import FormLabel from './FormLabel';
import Input from './Input'; import Input from './Input';
...@@ -13,8 +12,7 @@ const { definePartsStyle, defineMultiStyleConfig } = ...@@ -13,8 +12,7 @@ const { definePartsStyle, defineMultiStyleConfig } =
createMultiStyleConfigHelpers(parts.keys); createMultiStyleConfigHelpers(parts.keys);
function getFloatingVariantStylesForSize(size: 'md' | 'lg', props: StyleFunctionProps) { function getFloatingVariantStylesForSize(size: 'md' | 'lg', props: StyleFunctionProps) {
const { theme } = props; const formStyles = getFormStyles(props);
const { focusPlaceholderColor, errorColor } = getDefaultFormColors(props);
const activeLabelStyles = { const activeLabelStyles = {
...FormLabel.variants?.floating?.(props)._focusWithin, ...FormLabel.variants?.floating?.(props)._focusWithin,
...@@ -63,12 +61,29 @@ function getFloatingVariantStylesForSize(size: 'md' | 'lg', props: StyleFunction ...@@ -63,12 +61,29 @@ function getFloatingVariantStylesForSize(size: 'md' | 'lg', props: StyleFunction
// label styles // label styles
label: FormLabel.sizes?.[size](props) || {}, label: FormLabel.sizes?.[size](props) || {},
'input:not(:placeholder-shown) + label, textarea:not(:placeholder-shown) + label': activeLabelStyles, 'input:not(:placeholder-shown) + label, textarea:not(:placeholder-shown) + label': activeLabelStyles,
'textarea:not(:placeholder-shown) + label': {
bgColor: formStyles.input.filled.bgColor,
},
[`
input[readonly] + label,
textarea[readonly] + label,
&[aria-readonly=true] label
`]: {
bgColor: formStyles.input.readOnly.bgColor,
},
[` [`
input[aria-invalid=true] + label, input[aria-invalid=true] + label,
textarea[aria-invalid=true] + label, textarea[aria-invalid=true] + label,
&[aria-invalid=true] label &[aria-invalid=true] label
`]: { `]: {
color: getColor(theme, errorColor), color: formStyles.placeholder.error.color,
},
[`
input[disabled] + label,
textarea[disabled] + label,
&[aria-disabled=true] label
`]: {
color: formStyles.placeholder.disabled.color,
}, },
// input styles // input styles
...@@ -79,31 +94,24 @@ function getFloatingVariantStylesForSize(size: 'md' | 'lg', props: StyleFunction ...@@ -79,31 +94,24 @@ function getFloatingVariantStylesForSize(size: 'md' | 'lg', props: StyleFunction
padding: inputPx, padding: inputPx,
}, },
'input:not(:placeholder-shown), textarea:not(:placeholder-shown)': activeInputStyles, 'input:not(:placeholder-shown), textarea:not(:placeholder-shown)': activeInputStyles,
[`
input[disabled] + label,
&[aria-disabled=true] label
`]: {
backgroundColor: 'transparent',
},
// in textarea bg of label could not be transparent; it should match the background color of input but without alpha
// so we have to use non-standard colors here
'textarea[disabled] + label': {
backgroundColor: mode('#ececec', '#232425')(props),
},
'textarea[disabled] + label[data-in-modal=true]': {
backgroundColor: mode('#ececec', '#292b34')(props),
},
// indicator styles // indicator 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, focusPlaceholderColor), color: formStyles.placeholder.default.color,
}, },
[` [`
input[aria-invalid=true] + label .chakra-form__required-indicator, input[aria-invalid=true] + label .chakra-form__required-indicator,
textarea[aria-invalid=true] + label .chakra-form__required-indicator, textarea[aria-invalid=true] + label .chakra-form__required-indicator,
&[aria-invalid=true] .chakra-form__required-indicator &[aria-invalid=true] .chakra-form__required-indicator
`]: { `]: {
color: getColor(theme, errorColor), color: formStyles.placeholder.error.color,
},
[`
input[disabled] + label .chakra-form__required-indicator,
textarea[disabled] + label .chakra-form__required-indicator,
&[aria-disabled=true] .chakra-form__required-indicator
`]: {
color: formStyles.placeholder.disabled.color,
}, },
}, },
}; };
......
...@@ -65,6 +65,19 @@ test.describe('floating label size md +@dark-mode', () => { ...@@ -65,6 +65,19 @@ test.describe('floating label size md +@dark-mode', () => {
await expect(component).toHaveScreenshot(); await expect(component).toHaveScreenshot();
}); });
test('filled read-only', async({ mount }) => {
const component = await mount(
<TestApp>
<FormControl variant="floating" id="name" isRequired size="md">
<Input required value="foo" isReadOnly/>
<FormLabel>Smart contract / Address (0x...)</FormLabel>
</FormControl>
</TestApp>,
);
await expect(component).toHaveScreenshot();
});
test('filled error', async({ mount }) => { test('filled error', async({ mount }) => {
const component = await mount( const component = await mount(
<TestApp> <TestApp>
......
import { defineStyle, defineStyleConfig } from '@chakra-ui/styled-system'; import { defineStyle, defineStyleConfig } from '@chakra-ui/styled-system';
import { getColor } from '@chakra-ui/theme-tools';
import getDefaultFormColors from '../utils/getDefaultFormColors'; import getFormStyles from '../utils/getFormStyles';
const baseStyle = defineStyle({ const baseStyle = defineStyle({
display: 'flex', display: 'flex',
...@@ -13,14 +12,12 @@ const baseStyle = defineStyle({ ...@@ -13,14 +12,12 @@ const baseStyle = defineStyle({
transitionDuration: 'normal', transitionDuration: 'normal',
opacity: 1, opacity: 1,
_disabled: { _disabled: {
opacity: 0.4, opacity: 0.2,
}, },
}); });
const variantFloating = defineStyle((props) => { const variantFloating = defineStyle((props) => {
const { theme, backgroundColor } = props; const formStyles = getFormStyles(props);
const { focusPlaceholderColor } = getDefaultFormColors(props);
const bc = backgroundColor || 'transparent';
return { return {
left: '2px', left: '2px',
...@@ -29,8 +26,8 @@ const variantFloating = defineStyle((props) => { ...@@ -29,8 +26,8 @@ const variantFloating = defineStyle((props) => {
position: 'absolute', position: 'absolute',
borderRadius: 'base', borderRadius: 'base',
boxSizing: 'border-box', boxSizing: 'border-box',
color: 'gray.500', color: formStyles.placeholder.default.color,
backgroundColor: 'transparent', backgroundColor: props.bgColor || props.backgroundColor || 'transparent',
pointerEvents: 'none', pointerEvents: 'none',
margin: 0, margin: 0,
transformOrigin: 'top left', transformOrigin: 'top left',
...@@ -39,8 +36,8 @@ const variantFloating = defineStyle((props) => { ...@@ -39,8 +36,8 @@ const variantFloating = defineStyle((props) => {
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
textOverflow: 'ellipsis', textOverflow: 'ellipsis',
_focusWithin: { _focusWithin: {
backgroundColor: bc, backgroundColor: props.bgColor || props.backgroundColor || 'transparent',
color: getColor(theme, focusPlaceholderColor), color: formStyles.placeholder.default.color,
fontSize: 'xs', fontSize: 'xs',
lineHeight: '16px', lineHeight: '16px',
borderTopRightRadius: 'none', borderTopRightRadius: 'none',
...@@ -70,7 +67,7 @@ const sizes = { ...@@ -70,7 +67,7 @@ const sizes = {
return { return {
fontSize: 'md', fontSize: 'md',
lineHeight: '24px', lineHeight: '24px',
padding: '28px 4px 28px 24px', padding: '26px 4px 26px 24px',
right: '22px', right: '22px',
_focusWithin: { _focusWithin: {
padding: '16px 0 2px 24px', padding: '16px 0 2px 24px',
......
...@@ -10,11 +10,11 @@ import { runIfFn } from '@chakra-ui/utils'; ...@@ -10,11 +10,11 @@ import { runIfFn } from '@chakra-ui/utils';
const { defineMultiStyleConfig, definePartsStyle } = const { defineMultiStyleConfig, definePartsStyle } =
createMultiStyleConfigHelpers(parts.keys); createMultiStyleConfigHelpers(parts.keys);
const baseStyleDialog = defineStyle((props) => { const baseStyleDialog = defineStyle(() => {
return { return {
padding: 8, padding: 8,
borderRadius: 'lg', borderRadius: 'lg',
bg: mode('white', 'gray.900')(props), bg: 'dialog_bg',
margin: 'auto', margin: 'auto',
}; };
}); });
...@@ -61,7 +61,7 @@ const baseStyleOverlay = defineStyle({ ...@@ -61,7 +61,7 @@ const baseStyleOverlay = defineStyle({
}); });
const baseStyle = definePartsStyle((props) => ({ const baseStyle = definePartsStyle((props) => ({
dialog: runIfFn(baseStyleDialog, props), dialog: runIfFn(baseStyleDialog),
dialogContainer: baseStyleDialogContainer, dialogContainer: baseStyleDialogContainer,
header: runIfFn(baseStyleHeader, props), header: runIfFn(baseStyleHeader, props),
......
import { Textarea as TextareaComponent } from '@chakra-ui/react'; import { Textarea as TextareaComponent } from '@chakra-ui/react';
import { defineStyle, defineStyleConfig } from '@chakra-ui/styled-system'; import { defineStyle, defineStyleConfig } from '@chakra-ui/styled-system';
import { mode } from '@chakra-ui/theme-tools';
import getOutlinedFieldStyles from '../utils/getOutlinedFieldStyles'; import getOutlinedFieldStyles from '../utils/getOutlinedFieldStyles';
const variantFilledInactive = defineStyle((props) => {
return {
// https://bugs.chromium.org/p/chromium/issues/detail?id=1362573
// there is a problem with scrollbar color in chromium
// so blackAlpha.50 here is replaced with #f5f5f6
// and whiteAlpha.50 is replaced with #1a1b1b
// bgColor: mode('blackAlpha.50', 'whiteAlpha.50')(props),
bgColor: mode('#f5f5f6', '#1a1b1b')(props),
};
});
const sizes = { const sizes = {
md: defineStyle({ md: defineStyle({
fontSize: 'md', fontSize: 'md',
...@@ -38,7 +24,6 @@ const Textarea = defineStyleConfig({ ...@@ -38,7 +24,6 @@ const Textarea = defineStyleConfig({
sizes, sizes,
variants: { variants: {
outline: defineStyle(getOutlinedFieldStyles), outline: defineStyle(getOutlinedFieldStyles),
filledInactive: variantFilledInactive,
}, },
defaultProps: { defaultProps: {
variant: 'outline', variant: 'outline',
......
...@@ -23,6 +23,10 @@ const semanticTokens = { ...@@ -23,6 +23,10 @@ const semanticTokens = {
'default': 'red.400', 'default': 'red.400',
_dark: 'red.300', _dark: 'red.300',
}, },
dialog_bg: {
'default': 'white',
_dark: 'gray.900',
},
}, },
shadows: { shadows: {
action_bar: '0 4px 4px -4px rgb(0 0 0 / 10%), 0 2px 4px -4px rgb(0 0 0 / 6%)', action_bar: '0 4px 4px -4px rgb(0 0 0 / 10%), 0 2px 4px -4px rgb(0 0 0 / 6%)',
......
import type { StyleFunctionProps } from '@chakra-ui/theme-tools';
import { mode } from '@chakra-ui/theme-tools';
export default function getDefaultFormColors(props: StyleFunctionProps) {
const { focusBorderColor: fc, errorBorderColor: ec, filledBorderColor: flc } = props;
return {
focusBorderColor: fc || mode('blue.500', 'blue.300')(props),
focusPlaceholderColor: fc || 'gray.500',
errorColor: ec || mode('red.400', 'red.300')(props),
filledColor: flc || mode('gray.300', 'gray.600')(props),
};
}
import type { StyleFunctionProps } from '@chakra-ui/theme-tools';
import { mode, transparentize } from '@chakra-ui/theme-tools';
export default function getFormStyles(props: StyleFunctionProps) {
return {
input: {
empty: {
// there is no text in the empty input
// color: ???,
bgColor: props.bgColor || mode('white', 'black')(props),
borderColor: mode('gray.100', 'gray.700')(props),
},
hover: {
color: mode('gray.800', 'gray.50')(props),
bgColor: props.bgColor || mode('white', 'black')(props),
borderColor: mode('gray.200', 'gray.500')(props),
},
focus: {
color: mode('gray.800', 'gray.50')(props),
bgColor: props.bgColor || mode('white', 'black')(props),
borderColor: mode('blue.400', 'blue.400')(props),
},
filled: {
color: mode('gray.800', 'gray.50')(props),
bgColor: props.bgColor || mode('white', 'black')(props),
borderColor: mode('gray.300', 'gray.600')(props),
},
readOnly: {
color: mode('gray.800', 'gray.50')(props),
bgColor: mode('gray.200', 'gray.800')(props),
borderColor: mode('gray.200', 'gray.800')(props),
},
// we use opacity to show the disabled state
disabled: {
opacity: 0.2,
},
error: {
color: mode('gray.800', 'gray.50')(props),
bgColor: props.bgColor || mode('white', 'black')(props),
borderColor: mode('red.500', 'red.500')(props),
},
},
placeholder: {
'default': {
color: mode('gray.500', 'gray.500')(props),
},
disabled: {
color: transparentize('gray.500', 0.2)(props.theme),
},
error: {
color: mode('red.500', 'red.500')(props),
},
},
};
}
import type { StyleFunctionProps } from '@chakra-ui/theme-tools'; import type { StyleFunctionProps } from '@chakra-ui/theme-tools';
import { mode, getColor } from '@chakra-ui/theme-tools'; import { mode } from '@chakra-ui/theme-tools';
import getDefaultFormColors from './getDefaultFormColors';
import getDefaultTransitionProps from './getDefaultTransitionProps'; import getDefaultTransitionProps from './getDefaultTransitionProps';
import getFormStyles from './getFormStyles';
export default function getOutlinedFieldStyles(props: StyleFunctionProps) { export default function getOutlinedFieldStyles(props: StyleFunctionProps) {
const { theme, borderColor } = props; const formStyles = getFormStyles(props);
const { focusBorderColor, errorColor } = getDefaultFormColors(props);
const transitionProps = getDefaultTransitionProps(); const transitionProps = getDefaultTransitionProps();
return { return {
border: '2px solid', border: '2px solid',
// filled input // filled input
backgroundColor: 'transparent', ...formStyles.input.filled,
borderColor: mode('gray.300', 'gray.600')(props),
...transitionProps, ...transitionProps,
_hover: { _hover: {
borderColor: mode('gray.200', 'gray.500')(props), ...formStyles.input.hover,
}, },
_readOnly: { _readOnly: {
boxShadow: 'none !important', boxShadow: 'none !important',
userSelect: 'all', userSelect: 'all',
pointerEvents: 'none',
...formStyles.input.readOnly,
_hover: {
...formStyles.input.readOnly,
},
_focus: {
...formStyles.input.readOnly,
},
}, },
_disabled: { _disabled: {
opacity: 1, ...formStyles.input.disabled,
backgroundColor: mode('blackAlpha.200', 'whiteAlpha.200')(props),
borderColor: 'transparent',
cursor: 'not-allowed', cursor: 'not-allowed',
_hover: {
borderColor: 'transparent',
},
':-webkit-autofill': { ':-webkit-autofill': {
// background color for disabled input which value was selected from browser autocomplete popup // background color for disabled input which value was selected from browser autocomplete popup
'-webkit-box-shadow': `0 0 0px 1000px ${ mode('rgba(16, 17, 18, 0.08)', 'rgba(255, 255, 255, 0.08)')(props) } inset`, '-webkit-box-shadow': `0 0 0px 1000px ${ mode('rgba(16, 17, 18, 0.08)', 'rgba(255, 255, 255, 0.08)')(props) } inset`,
}, },
}, },
_invalid: { _invalid: {
borderColor: getColor(theme, errorColor), ...formStyles.input.error,
boxShadow: `none`, boxShadow: `none`,
_placeholder: {
color: formStyles.placeholder.error.color,
},
}, },
_focusVisible: { _focusVisible: {
...formStyles.input.focus,
zIndex: 1, zIndex: 1,
borderColor: getColor(theme, focusBorderColor),
boxShadow: 'md', boxShadow: 'md',
}, },
_placeholder: { _placeholder: {
color: mode('blackAlpha.600', 'whiteAlpha.600')(props), color: formStyles.placeholder.default.color,
}, },
// not filled input // not filled input
':placeholder-shown:not(:focus-visible):not(:hover):not([aria-invalid=true])': { borderColor: borderColor || mode('gray.100', 'gray.700')(props) }, ':placeholder-shown:not(:focus-visible):not(:hover):not([aria-invalid=true]):not([aria-readonly=true])': {
...formStyles.input.empty,
},
// not filled input with type="date" // not filled input with type="date"
':not(:placeholder-shown)[value=""]:not(:focus-visible):not(:hover):not([aria-invalid=true])': { ':not(:placeholder-shown)[value=""]:not(:focus-visible):not(:hover):not([aria-invalid=true]):not([aria-readonly=true])': {
borderColor: borderColor || mode('gray.100', 'gray.700')(props), ...formStyles.input.empty,
color: 'gray.500',
}, },
':-webkit-autofill': { transition: 'background-color 5000s ease-in-out 0s' }, ':-webkit-autofill': { transition: 'background-color 5000s ease-in-out 0s' },
......
...@@ -128,7 +128,6 @@ const ContractSourceCode = ({ address, implementationAddress }: Props) => { ...@@ -128,7 +128,6 @@ const ContractSourceCode = ({ address, implementationAddress }: Props) => {
size="xs" size="xs"
value={ sourceType } value={ sourceType }
onChange={ handleSelectChange } onChange={ handleSelectChange }
focusBorderColor="none"
w="auto" w="auto"
fontWeight={ 600 } fontWeight={ 600 }
borderRadius="base" borderRadius="base"
......
...@@ -24,7 +24,6 @@ interface Props { ...@@ -24,7 +24,6 @@ interface Props {
const TokenSelectMenu = ({ erc20sort, erc1155sort, erc404sort, filteredData, onInputChange, onSortClick, searchTerm }: Props) => { const TokenSelectMenu = ({ erc20sort, erc1155sort, erc404sort, filteredData, onInputChange, onSortClick, searchTerm }: Props) => {
const searchIconColor = useColorModeValue('blackAlpha.600', 'whiteAlpha.600'); const searchIconColor = useColorModeValue('blackAlpha.600', 'whiteAlpha.600');
const inputBorderColor = useColorModeValue('blackAlpha.100', 'whiteAlpha.200');
const hasFilteredResult = _sumBy(Object.values(filteredData), ({ items }) => items.length) > 0; const hasFilteredResult = _sumBy(Object.values(filteredData), ({ items }) => items.length) > 0;
...@@ -39,7 +38,7 @@ const TokenSelectMenu = ({ erc20sort, erc1155sort, erc404sort, filteredData, onI ...@@ -39,7 +38,7 @@ const TokenSelectMenu = ({ erc20sort, erc1155sort, erc404sort, filteredData, onI
placeholder="Search by token name" placeholder="Search by token name"
ml="1px" ml="1px"
onChange={ onInputChange } onChange={ onInputChange }
borderColor={ inputBorderColor } bgColor="dialog_bg"
/> />
</InputGroup> </InputGroup>
<Flex flexDir="column" rowGap={ 6 }> <Flex flexDir="column" rowGap={ 6 }>
......
import { FormControl, Input, useColorModeValue } from '@chakra-ui/react'; import { FormControl, Input } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { Control, ControllerRenderProps, FormState } from 'react-hook-form'; import type { Control, ControllerRenderProps, FormState } from 'react-hook-form';
import { Controller } from 'react-hook-form'; import { Controller } from 'react-hook-form';
...@@ -15,13 +15,11 @@ interface Props { ...@@ -15,13 +15,11 @@ interface Props {
} }
const AddressVerificationFieldAddress = ({ formState, control }: Props) => { const AddressVerificationFieldAddress = ({ formState, control }: Props) => {
const backgroundColor = useColorModeValue('white', 'gray.900');
const renderControl = React.useCallback(({ field }: {field: ControllerRenderProps<Fields, 'address'>}) => { const renderControl = React.useCallback(({ field }: {field: ControllerRenderProps<Fields, 'address'>}) => {
const error = 'address' in formState.errors ? formState.errors.address : undefined; const error = 'address' in formState.errors ? formState.errors.address : undefined;
return ( return (
<FormControl variant="floating" id={ field.name } isRequired size="md" backgroundColor={ backgroundColor } mt={ 8 }> <FormControl variant="floating" id={ field.name } isRequired size="md" bgColor="dialog_bg" mt={ 8 }>
<Input <Input
{ ...field } { ...field }
required required
...@@ -29,11 +27,12 @@ const AddressVerificationFieldAddress = ({ formState, control }: Props) => { ...@@ -29,11 +27,12 @@ const AddressVerificationFieldAddress = ({ formState, control }: Props) => {
maxLength={ ADDRESS_LENGTH } maxLength={ ADDRESS_LENGTH }
isDisabled={ formState.isSubmitting } isDisabled={ formState.isSubmitting }
autoComplete="off" autoComplete="off"
bgColor="dialog_bg"
/> />
<InputPlaceholder text="Smart contract address (0x...)" error={ error }/> <InputPlaceholder text="Smart contract address (0x...)" error={ error }/>
</FormControl> </FormControl>
); );
}, [ formState.errors, formState.isSubmitting, backgroundColor ]); }, [ formState.errors, formState.isSubmitting ]);
return ( return (
<Controller <Controller
......
import { FormControl, Textarea, useColorModeValue } from '@chakra-ui/react'; import { FormControl, Textarea } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { Control, ControllerRenderProps, FormState } from 'react-hook-form'; import type { Control, ControllerRenderProps, FormState } from 'react-hook-form';
import { Controller } from 'react-hook-form'; import { Controller } from 'react-hook-form';
...@@ -15,25 +15,24 @@ interface Props { ...@@ -15,25 +15,24 @@ interface Props {
} }
const AddressVerificationFieldMessage = ({ formState, control }: Props) => { const AddressVerificationFieldMessage = ({ formState, control }: Props) => {
const backgroundColor = useColorModeValue('white', 'gray.900');
const renderControl = React.useCallback(({ field }: {field: ControllerRenderProps<Fields, 'message'>}) => { const renderControl = React.useCallback(({ field }: {field: ControllerRenderProps<Fields, 'message'>}) => {
const error = 'message' in formState.errors ? formState.errors.message : undefined; const error = 'message' in formState.errors ? formState.errors.message : undefined;
return ( return (
<FormControl variant="floating" id={ field.name } isRequired size="md" backgroundColor={ backgroundColor }> <FormControl variant="floating" id={ field.name } isRequired size="md" bgColor="dialog_bg">
<Textarea <Textarea
{ ...field } { ...field }
required required
isInvalid={ Boolean(error) } isInvalid={ Boolean(error) }
isDisabled isReadOnly
autoComplete="off" autoComplete="off"
maxH={{ base: '140px', lg: '80px' }} maxH={{ base: '140px', lg: '80px' }}
bgColor="dialog_bg"
/> />
<InputPlaceholder text="Message to sign" error={ error } isInModal/> <InputPlaceholder text="Message to sign" error={ error }/>
</FormControl> </FormControl>
); );
}, [ formState.errors, backgroundColor ]); }, [ formState.errors ]);
return ( return (
<Controller <Controller
......
import { FormControl, Input, useColorModeValue } from '@chakra-ui/react'; import { FormControl, Input } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { Control, ControllerRenderProps, FormState } from 'react-hook-form'; import type { Control, ControllerRenderProps, FormState } from 'react-hook-form';
import { Controller } from 'react-hook-form'; import { Controller } from 'react-hook-form';
...@@ -16,24 +16,23 @@ interface Props { ...@@ -16,24 +16,23 @@ interface Props {
} }
const AddressVerificationFieldSignature = ({ formState, control }: Props) => { const AddressVerificationFieldSignature = ({ formState, control }: Props) => {
const backgroundColor = useColorModeValue('white', 'gray.900');
const renderControl = React.useCallback(({ field }: {field: ControllerRenderProps<Fields, 'signature'>}) => { const renderControl = React.useCallback(({ field }: {field: ControllerRenderProps<Fields, 'signature'>}) => {
const error = 'signature' in formState.errors ? formState.errors.signature : undefined; const error = 'signature' in formState.errors ? formState.errors.signature : undefined;
return ( return (
<FormControl variant="floating" id={ field.name } isRequired size="md" backgroundColor={ backgroundColor }> <FormControl variant="floating" id={ field.name } isRequired size="md" bgColor="dialog_bg">
<Input <Input
{ ...field } { ...field }
required required
isInvalid={ Boolean(error) } isInvalid={ Boolean(error) }
isDisabled={ formState.isSubmitting } isDisabled={ formState.isSubmitting }
autoComplete="off" autoComplete="off"
bgColor="dialog_bg"
/> />
<InputPlaceholder text="Signature hash" error={ error }/> <InputPlaceholder text="Signature hash" error={ error }/>
</FormControl> </FormControl>
); );
}, [ formState.errors, formState.isSubmitting, backgroundColor ]); }, [ formState.errors, formState.isSubmitting ]);
return ( return (
<Controller <Controller
......
...@@ -105,7 +105,7 @@ const AddressVerificationStepAddress = ({ defaultAddress, onContinue }: Props) = ...@@ -105,7 +105,7 @@ const AddressVerificationStepAddress = ({ defaultAddress, onContinue }: Props) =
{ rootError && <Alert status="warning" mt={ 3 }>{ rootError }</Alert> } { rootError && <Alert status="warning" mt={ 3 }>{ rootError }</Alert> }
<AddressVerificationFieldAddress formState={ formState } control={ control }/> <AddressVerificationFieldAddress formState={ formState } control={ control }/>
<Flex alignItems={{ base: 'flex-start', lg: 'center' }} mt={ 8 } columnGap={ 5 } rowGap={ 2 } flexDir={{ base: 'column', lg: 'row' }}> <Flex alignItems={{ base: 'flex-start', lg: 'center' }} mt={ 8 } columnGap={ 5 } rowGap={ 2 } flexDir={{ base: 'column', lg: 'row' }}>
<Button size="lg" type="submit" isDisabled={ formState.isSubmitting } flexShrink={ 0 }> <Button size="lg" type="submit" isLoading={ formState.isSubmitting } loadingText="Continue" flexShrink={ 0 }>
Continue Continue
</Button> </Button>
<AdminSupportText/> <AdminSupportText/>
......
...@@ -4,7 +4,6 @@ import { ...@@ -4,7 +4,6 @@ import {
FormControl, FormControl,
FormLabel, FormLabel,
Input, Input,
useColorModeValue,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
...@@ -42,7 +41,6 @@ const ApiKeyForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => { ...@@ -42,7 +41,6 @@ const ApiKeyForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {
}); });
const apiFetch = useApiFetch(); const apiFetch = useApiFetch();
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const formBackgroundColor = useColorModeValue('white', 'gray.900');
const updateApiKey = (data: Inputs) => { const updateApiKey = (data: Inputs) => {
const body = { name: data.name }; const body = { name: data.name };
...@@ -102,25 +100,27 @@ const ApiKeyForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => { ...@@ -102,25 +100,27 @@ const ApiKeyForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {
<FormControl variant="floating" id="address"> <FormControl variant="floating" id="address">
<Input <Input
{ ...field } { ...field }
isDisabled={ true } bgColor="dialog_bg"
isReadOnly
/> />
<FormLabel data-in-modal="true">Auto-generated API key token</FormLabel> <FormLabel>Auto-generated API key token</FormLabel>
</FormControl> </FormControl>
); );
}, []); }, []);
const renderNameInput = useCallback(({ field }: {field: ControllerRenderProps<Inputs, 'name'>}) => { const renderNameInput = useCallback(({ field }: {field: ControllerRenderProps<Inputs, 'name'>}) => {
return ( return (
<FormControl variant="floating" id="name" isRequired backgroundColor={ formBackgroundColor }> <FormControl variant="floating" id="name" isRequired bgColor="dialog_bg">
<Input <Input
{ ...field } { ...field }
isInvalid={ Boolean(errors.name) } isInvalid={ Boolean(errors.name) }
maxLength={ NAME_MAX_LENGTH } maxLength={ NAME_MAX_LENGTH }
bgColor="dialog_bg"
/> />
<InputPlaceholder text="Application name for API key (e.g Web3 project)" error={ errors.name }/> <InputPlaceholder text="Application name for API key (e.g Web3 project)" error={ errors.name }/>
</FormControl> </FormControl>
); );
}, [ errors, formBackgroundColor ]); }, [ errors ]);
return ( return (
<form noValidate onSubmit={ handleSubmit(onSubmit) }> <form noValidate onSubmit={ handleSubmit(onSubmit) }>
......
...@@ -108,7 +108,6 @@ const BlobData = ({ data, isLoading, hash }: Props) => { ...@@ -108,7 +108,6 @@ const BlobData = ({ data, isLoading, hash }: Props) => {
borderRadius="base" borderRadius="base"
value={ format } value={ format }
onChange={ handleSelectChange } onChange={ handleSelectChange }
focusBorderColor="none"
w="auto" w="auto"
> >
{ formats.map((format) => ( { formats.map((format) => (
......
...@@ -4,7 +4,6 @@ import { ...@@ -4,7 +4,6 @@ import {
FormControl, FormControl,
Input, Input,
Textarea, Textarea,
useColorModeValue,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
...@@ -61,8 +60,6 @@ const CustomAbiForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => { ...@@ -61,8 +60,6 @@ const CustomAbiForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {
}); });
}; };
const formBackgroundColor = useColorModeValue('white', 'gray.900');
const mutation = useMutation({ const mutation = useMutation({
mutationFn: customAbiKey, mutationFn: customAbiKey,
onSuccess: (data) => { onSuccess: (data) => {
...@@ -109,38 +106,40 @@ const CustomAbiForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => { ...@@ -109,38 +106,40 @@ const CustomAbiForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {
<AddressInput<Inputs, 'contract_address_hash'> <AddressInput<Inputs, 'contract_address_hash'>
field={ field } field={ field }
error={ errors.contract_address_hash } error={ errors.contract_address_hash }
backgroundColor={ formBackgroundColor } bgColor="dialog_bg"
placeholder="Smart contract address (0x...)" placeholder="Smart contract address (0x...)"
/> />
); );
}, [ errors, formBackgroundColor ]); }, [ errors ]);
const renderNameInput = useCallback(({ field }: {field: ControllerRenderProps<Inputs, 'name'>}) => { const renderNameInput = useCallback(({ field }: {field: ControllerRenderProps<Inputs, 'name'>}) => {
return ( return (
<FormControl variant="floating" id="name" isRequired backgroundColor={ formBackgroundColor }> <FormControl variant="floating" id="name" isRequired bgColor="dialog_bg">
<Input <Input
{ ...field } { ...field }
isInvalid={ Boolean(errors.name) } isInvalid={ Boolean(errors.name) }
maxLength={ NAME_MAX_LENGTH } maxLength={ NAME_MAX_LENGTH }
bgColor="dialog_bg"
/> />
<InputPlaceholder text="Project name" error={ errors.name }/> <InputPlaceholder text="Project name" error={ errors.name }/>
</FormControl> </FormControl>
); );
}, [ errors, formBackgroundColor ]); }, [ errors ]);
const renderAbiInput = useCallback(({ field }: {field: ControllerRenderProps<Inputs, 'abi'>}) => { const renderAbiInput = useCallback(({ field }: {field: ControllerRenderProps<Inputs, 'abi'>}) => {
return ( return (
<FormControl variant="floating" id="abi" isRequired backgroundColor={ formBackgroundColor }> <FormControl variant="floating" id="abi" isRequired bgColor="dialog_bg">
<Textarea <Textarea
{ ...field } { ...field }
size="lg" size="lg"
minH="300px" minH="300px"
isInvalid={ Boolean(errors.abi) } isInvalid={ Boolean(errors.abi) }
bgColor="dialog_bg"
/> />
<InputPlaceholder text="Custom ABI [{...}] (JSON format)" error={ errors.abi }/> <InputPlaceholder text="Custom ABI [{...}] (JSON format)" error={ errors.abi }/>
</FormControl> </FormControl>
); );
}, [ errors, formBackgroundColor ]); }, [ errors ]);
return ( return (
<form noValidate onSubmit={ handleSubmit(onSubmit) }> <form noValidate onSubmit={ handleSubmit(onSubmit) }>
......
...@@ -27,7 +27,7 @@ const MyProfile = () => { ...@@ -27,7 +27,7 @@ const MyProfile = () => {
<FormControl variant="floating" id="name" isRequired size="lg"> <FormControl variant="floating" id="name" isRequired size="lg">
<Input <Input
required required
disabled readOnly
value={ data.name || '' } value={ data.name || '' }
/> />
<FormLabel>Name</FormLabel> <FormLabel>Name</FormLabel>
...@@ -35,7 +35,7 @@ const MyProfile = () => { ...@@ -35,7 +35,7 @@ const MyProfile = () => {
<FormControl variant="floating" id="nickname" isRequired size="lg"> <FormControl variant="floating" id="nickname" isRequired size="lg">
<Input <Input
required required
disabled readOnly
value={ data.nickname || '' } value={ data.nickname || '' }
/> />
<FormLabel>Nickname</FormLabel> <FormLabel>Nickname</FormLabel>
...@@ -43,7 +43,7 @@ const MyProfile = () => { ...@@ -43,7 +43,7 @@ const MyProfile = () => {
<FormControl variant="floating" id="email" isRequired size="lg"> <FormControl variant="floating" id="email" isRequired size="lg">
<Input <Input
required required
disabled readOnly
value={ data.email || '' } value={ data.email || '' }
/> />
<FormLabel>Email</FormLabel> <FormLabel>Email</FormLabel>
......
import { import {
Box, Box,
Button, Button,
useColorModeValue,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useMutation } from '@tanstack/react-query'; import { useMutation } from '@tanstack/react-query';
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
...@@ -42,8 +41,6 @@ const AddressForm: React.FC<Props> = ({ data, onClose, onSuccess, setAlertVisibl ...@@ -42,8 +41,6 @@ const AddressForm: React.FC<Props> = ({ data, onClose, onSuccess, setAlertVisibl
}, },
}); });
const formBackgroundColor = useColorModeValue('white', 'gray.900');
const { mutate } = useMutation({ const { mutate } = useMutation({
mutationFn: (formData: Inputs) => { mutationFn: (formData: Inputs) => {
const body = { const body = {
...@@ -87,12 +84,12 @@ const AddressForm: React.FC<Props> = ({ data, onClose, onSuccess, setAlertVisibl ...@@ -87,12 +84,12 @@ const AddressForm: React.FC<Props> = ({ data, onClose, onSuccess, setAlertVisibl
}; };
const renderAddressInput = useCallback(({ field }: {field: ControllerRenderProps<Inputs, 'address'>}) => { const renderAddressInput = useCallback(({ field }: {field: ControllerRenderProps<Inputs, 'address'>}) => {
return <AddressInput<Inputs, 'address'> field={ field } error={ errors.address } backgroundColor={ formBackgroundColor }/>; return <AddressInput<Inputs, 'address'> field={ field } error={ errors.address } bgColor="dialog_bg"/>;
}, [ errors, formBackgroundColor ]); }, [ errors ]);
const renderTagInput = useCallback(({ field }: {field: ControllerRenderProps<Inputs, 'tag'>}) => { const renderTagInput = useCallback(({ field }: {field: ControllerRenderProps<Inputs, 'tag'>}) => {
return <TagInput<Inputs, 'tag'> field={ field } error={ errors.tag } backgroundColor={ formBackgroundColor }/>; return <TagInput<Inputs, 'tag'> field={ field } error={ errors.tag } bgColor="dialog_bg"/>;
}, [ errors, formBackgroundColor ]); }, [ errors ]);
return ( return (
<form noValidate onSubmit={ handleSubmit(onSubmit) }> <form noValidate onSubmit={ handleSubmit(onSubmit) }>
......
import { import {
Box, Box,
Button, Button,
useColorModeValue,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query';
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
...@@ -34,7 +33,6 @@ type Inputs = { ...@@ -34,7 +33,6 @@ type Inputs = {
const TransactionForm: React.FC<Props> = ({ data, onClose, onSuccess, setAlertVisible }) => { const TransactionForm: React.FC<Props> = ({ data, onClose, onSuccess, setAlertVisible }) => {
const [ pending, setPending ] = useState(false); const [ pending, setPending ] = useState(false);
const formBackgroundColor = useColorModeValue('white', 'gray.900');
const { control, handleSubmit, formState: { errors, isDirty }, setError } = useForm<Inputs>({ const { control, handleSubmit, formState: { errors, isDirty }, setError } = useForm<Inputs>({
mode: 'onTouched', mode: 'onTouched',
...@@ -90,12 +88,12 @@ const TransactionForm: React.FC<Props> = ({ data, onClose, onSuccess, setAlertVi ...@@ -90,12 +88,12 @@ const TransactionForm: React.FC<Props> = ({ data, onClose, onSuccess, setAlertVi
}; };
const renderTransactionInput = useCallback(({ field }: {field: ControllerRenderProps<Inputs, 'transaction'>}) => { const renderTransactionInput = useCallback(({ field }: {field: ControllerRenderProps<Inputs, 'transaction'>}) => {
return <TransactionInput field={ field } error={ errors.transaction } backgroundColor={ formBackgroundColor }/>; return <TransactionInput field={ field } error={ errors.transaction } bgColor="dialog_bg"/>;
}, [ errors, formBackgroundColor ]); }, [ errors ]);
const renderTagInput = useCallback(({ field }: {field: ControllerRenderProps<Inputs, 'tag'>}) => { const renderTagInput = useCallback(({ field }: {field: ControllerRenderProps<Inputs, 'tag'>}) => {
return <TagInput<Inputs, 'tag'> field={ field } error={ errors.tag } backgroundColor={ formBackgroundColor }/>; return <TagInput<Inputs, 'tag'> field={ field } error={ errors.tag } bgColor="dialog_bg"/>;
}, [ errors, formBackgroundColor ]); }, [ errors ]);
return ( return (
<form noValidate onSubmit={ handleSubmit(onSubmit) }> <form noValidate onSubmit={ handleSubmit(onSubmit) }>
......
...@@ -13,7 +13,7 @@ type Props<TInputs extends FieldValues, TInputName extends Path<TInputs>> = { ...@@ -13,7 +13,7 @@ type Props<TInputs extends FieldValues, TInputName extends Path<TInputs>> = {
field: ControllerRenderProps<TInputs, TInputName>; field: ControllerRenderProps<TInputs, TInputName>;
size?: InputProps['size']; size?: InputProps['size'];
placeholder?: string; placeholder?: string;
backgroundColor?: string; bgColor?: string;
error?: FieldError; error?: FieldError;
} }
...@@ -23,14 +23,15 @@ export default function AddressInput<Inputs extends FieldValues, Name extends Pa ...@@ -23,14 +23,15 @@ export default function AddressInput<Inputs extends FieldValues, Name extends Pa
field, field,
size, size,
placeholder = 'Address (0x...)', placeholder = 'Address (0x...)',
backgroundColor, bgColor,
}: Props<Inputs, Name>) { }: Props<Inputs, Name>) {
return ( return (
<FormControl variant="floating" id="address" isRequired backgroundColor={ backgroundColor } size={ size }> <FormControl variant="floating" id="address" isRequired size={ size } bgColor={ bgColor }>
<Input <Input
{ ...field } { ...field }
isInvalid={ Boolean(error) } isInvalid={ Boolean(error) }
maxLength={ ADDRESS_LENGTH } maxLength={ ADDRESS_LENGTH }
bgColor={ bgColor }
/> />
<InputPlaceholder text={ placeholder } error={ error }/> <InputPlaceholder text={ placeholder } error={ error }/>
</FormControl> </FormControl>
......
...@@ -92,5 +92,20 @@ const defaultProps = { ...@@ -92,5 +92,20 @@ const defaultProps = {
await expect(component).toHaveScreenshot(); await expect(component).toHaveScreenshot();
}); });
test('read-only', async({ mount }) => {
const component = await mount(
<TestApp>
<FancySelect
{ ...defaultProps }
size={ size }
value={ OPTIONS[0] }
isReadOnly
/>
</TestApp>,
);
await expect(component).toHaveScreenshot();
});
}); });
}); });
...@@ -3,6 +3,9 @@ import type { Size, ChakraStylesConfig } from 'chakra-react-select'; ...@@ -3,6 +3,9 @@ import type { Size, ChakraStylesConfig } from 'chakra-react-select';
import type { Option } from './types'; import type { Option } from './types';
import theme from 'theme';
import getFormStyles from 'theme/utils/getFormStyles';
function getValueContainerStyles(size?: Size) { function getValueContainerStyles(size?: Size) {
switch (size) { switch (size) {
case 'sm': case 'sm':
...@@ -42,13 +45,12 @@ function getSingleValueStyles(size?: Size) { ...@@ -42,13 +45,12 @@ function getSingleValueStyles(size?: Size) {
} }
const getChakraStyles: (colorMode: ColorMode) => ChakraStylesConfig<Option> = (colorMode) => { const getChakraStyles: (colorMode: ColorMode) => ChakraStylesConfig<Option> = (colorMode) => {
const emptyInputBorderColor = colorMode === 'dark' ? 'gray.700' : 'gray.100'; const formColor = getFormStyles({ colorMode, colorScheme: 'blue', theme });
const filledInputBorderColor = colorMode === 'dark' ? 'gray.600' : 'gray.300';
return { return {
control: (provided, state) => ({ control: (provided, state) => ({
...provided, ...provided,
borderColor: state.hasValue ? filledInputBorderColor : emptyInputBorderColor, borderColor: state.hasValue ? formColor.input.filled.borderColor : formColor.input.empty.borderColor,
}), }),
inputContainer: (provided) => ({ inputContainer: (provided) => ({
...provided, ...provided,
......
...@@ -6,12 +6,10 @@ interface Props { ...@@ -6,12 +6,10 @@ interface Props {
text: string; text: string;
icon?: React.ReactNode; icon?: React.ReactNode;
error?: Partial<FieldError>; error?: Partial<FieldError>;
className?: string;
isFancy?: boolean; isFancy?: boolean;
isInModal?: boolean;
} }
const InputPlaceholder = ({ text, icon, error, className, isFancy, isInModal }: Props) => { const InputPlaceholder = ({ text, icon, error, isFancy }: Props) => {
let errorMessage = error?.message; let errorMessage = error?.message;
if (!errorMessage && error?.type === 'pattern') { if (!errorMessage && error?.type === 'pattern') {
...@@ -20,10 +18,10 @@ const InputPlaceholder = ({ text, icon, error, className, isFancy, isInModal }: ...@@ -20,10 +18,10 @@ const InputPlaceholder = ({ text, icon, error, className, isFancy, isInModal }:
return ( return (
<FormLabel <FormLabel
className={ className }
alignItems="center" alignItems="center"
{ ...(isFancy ? { 'data-fancy': true } : {}) } { ...(isFancy ? { 'data-fancy': true } : {}) }
{ ...(isInModal ? { 'data-in-modal': true } : {}) } variant="floating"
bgColor="deeppink"
> >
{ icon } { icon }
<chakra.span>{ text }</chakra.span> <chakra.span>{ text }</chakra.span>
...@@ -32,4 +30,4 @@ const InputPlaceholder = ({ text, icon, error, className, isFancy, isInModal }: ...@@ -32,4 +30,4 @@ const InputPlaceholder = ({ text, icon, error, className, isFancy, isInModal }:
); );
}; };
export default chakra(InputPlaceholder); export default React.memo(InputPlaceholder);
...@@ -11,13 +11,29 @@ interface Props { ...@@ -11,13 +11,29 @@ interface Props {
rightSlot?: React.ReactNode; rightSlot?: React.ReactNode;
beforeSlot?: React.ReactNode; beforeSlot?: React.ReactNode;
textareaMaxHeight?: string; textareaMaxHeight?: string;
textareaMinHeight?: string;
showCopy?: boolean; showCopy?: boolean;
isLoading?: boolean; isLoading?: boolean;
contentProps?: ChakraProps; contentProps?: ChakraProps;
} }
const RawDataSnippet = ({ data, className, title, rightSlot, beforeSlot, textareaMaxHeight, showCopy = true, isLoading, contentProps }: Props) => { const RawDataSnippet = ({
// see issue in theme/components/Textarea.ts data,
className,
title,
rightSlot,
beforeSlot,
textareaMaxHeight,
textareaMinHeight,
showCopy = true,
isLoading,
contentProps,
}: Props) => {
// https://bugs.chromium.org/p/chromium/issues/detail?id=1362573
// there is a problem with scrollbar color in chromium
// so blackAlpha.50 here is replaced with #f5f5f6
// and whiteAlpha.50 is replaced with #1a1b1b
// const bgColor = useColorModeValue('blackAlpha.50', 'whiteAlpha.50');
const bgColor = useColorModeValue('#f5f5f6', '#1a1b1b'); const bgColor = useColorModeValue('#f5f5f6', '#1a1b1b');
return ( return (
<Box className={ className } as="section" title={ title }> <Box className={ className } as="section" title={ title }>
...@@ -33,7 +49,7 @@ const RawDataSnippet = ({ data, className, title, rightSlot, beforeSlot, textare ...@@ -33,7 +49,7 @@ const RawDataSnippet = ({ data, className, title, rightSlot, beforeSlot, textare
p={ 4 } p={ 4 }
bgColor={ isLoading ? 'inherit' : bgColor } bgColor={ isLoading ? 'inherit' : bgColor }
maxH={ textareaMaxHeight || '400px' } maxH={ textareaMaxHeight || '400px' }
minH={ isLoading ? '200px' : undefined } minH={ textareaMinHeight || (isLoading ? '200px' : undefined) }
fontSize="sm" fontSize="sm"
borderRadius="md" borderRadius="md"
wordBreak="break-all" wordBreak="break-all"
......
import { Box, Flex, Select, Textarea } from '@chakra-ui/react'; import { Select } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import hexToUtf8 from 'lib/hexToUtf8'; import hexToUtf8 from 'lib/hexToUtf8';
import CopyToClipboard from 'ui/shared/CopyToClipboard'; import RawDataSnippet from 'ui/shared/RawDataSnippet';
type DataType = 'Hex' | 'UTF-8' type DataType = 'Hex' | 'UTF-8'
const OPTIONS: Array<DataType> = [ 'Hex', 'UTF-8' ]; const OPTIONS: Array<DataType> = [ 'Hex', 'UTF-8' ];
...@@ -18,24 +18,20 @@ const RawInputData = ({ hex }: Props) => { ...@@ -18,24 +18,20 @@ const RawInputData = ({ hex }: Props) => {
setSelectedDataType(event.target.value as DataType); setSelectedDataType(event.target.value as DataType);
}, []); }, []);
return ( const select = (
<Box w="100%"> <Select size="xs" borderRadius="base" value={ selectedDataType } onChange={ handleSelectChange } w="auto" mr="auto">
<Flex justifyContent="space-between" alignItems="center">
<Select size="xs" borderRadius="base" value={ selectedDataType } onChange={ handleSelectChange } focusBorderColor="none" w="auto">
{ OPTIONS.map((option) => <option key={ option } value={ option }>{ option }</option>) } { OPTIONS.map((option) => <option key={ option } value={ option }>{ option }</option>) }
</Select> </Select>
<CopyToClipboard text={ hex }/> );
</Flex>
<Textarea return (
value={ selectedDataType === 'Hex' ? hex : hexToUtf8(hex) } <RawDataSnippet
data={ selectedDataType === 'Hex' ? hex : hexToUtf8(hex) }
rightSlot={ select }
textareaMaxHeight="220px"
textareaMinHeight="160px"
w="100%" w="100%"
maxH="220px"
mt={ 2 }
p={ 4 }
variant="filledInactive"
fontSize="sm"
/> />
</Box>
); );
}; };
......
...@@ -12,16 +12,17 @@ const TAG_MAX_LENGTH = 35; ...@@ -12,16 +12,17 @@ const TAG_MAX_LENGTH = 35;
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>;
error?: FieldError; error?: FieldError;
backgroundColor?: string; bgColor?: string;
} }
function TagInput<Inputs extends FieldValues, Name extends Path<Inputs>>({ field, error, backgroundColor }: Props<Inputs, Name>) { function TagInput<Inputs extends FieldValues, Name extends Path<Inputs>>({ field, error, bgColor }: Props<Inputs, Name>) {
return ( return (
<FormControl variant="floating" id="tag" isRequired backgroundColor={ backgroundColor }> <FormControl variant="floating" id="tag" isRequired bgColor={ bgColor }>
<Input <Input
{ ...field } { ...field }
isInvalid={ Boolean(error) } isInvalid={ Boolean(error) }
maxLength={ TAG_MAX_LENGTH } maxLength={ TAG_MAX_LENGTH }
bgColor={ bgColor }
/> />
<InputPlaceholder text="Private tag (max 35 characters)" error={ error }/> <InputPlaceholder text="Private tag (max 35 characters)" error={ error }/>
</FormControl> </FormControl>
......
...@@ -11,16 +11,17 @@ import InputPlaceholder from 'ui/shared/InputPlaceholder'; ...@@ -11,16 +11,17 @@ import InputPlaceholder from 'ui/shared/InputPlaceholder';
type Props<Field> = { type Props<Field> = {
field: Field; field: Field;
error?: FieldError; error?: FieldError;
backgroundColor?: string; bgColor?: string;
} }
function TransactionInput<Field extends Partial<ControllerRenderProps<FieldValues, 'transaction'>>>({ field, error, backgroundColor }: Props<Field>) { function TransactionInput<Field extends Partial<ControllerRenderProps<FieldValues, 'transaction'>>>({ field, error, bgColor }: Props<Field>) {
return ( return (
<FormControl variant="floating" id="transaction" isRequired backgroundColor={ backgroundColor }> <FormControl variant="floating" id="transaction" isRequired bgColor={ bgColor }>
<Input <Input
{ ...field } { ...field }
isInvalid={ Boolean(error) } isInvalid={ Boolean(error) }
maxLength={ TRANSACTION_HASH_LENGTH } maxLength={ TRANSACTION_HASH_LENGTH }
bgColor={ bgColor }
/> />
<InputPlaceholder text="Transaction hash (0x...)" error={ error }/> <InputPlaceholder text="Transaction hash (0x...)" error={ error }/>
</FormControl> </FormControl>
......
...@@ -46,7 +46,7 @@ const NetworkMenuContentMobile = ({ items, tabs }: Props) => { ...@@ -46,7 +46,7 @@ const NetworkMenuContentMobile = ({ items, tabs }: Props) => {
) : ( ) : (
<> <>
{ tabs.length > 1 && ( { tabs.length > 1 && (
<Select size="xs" borderRadius="base" value={ selectedTab } onChange={ handleSelectChange } focusBorderColor="none" mb={ 6 }> <Select size="xs" borderRadius="base" value={ selectedTab } onChange={ handleSelectChange } mb={ 6 }>
{ tabs.map((tab) => <option key={ tab } value={ tab }>{ capitalize(tab) }</option>) } { tabs.map((tab) => <option key={ tab } value={ tab }>{ capitalize(tab) }</option>) }
</Select> </Select>
) } ) }
......
...@@ -18,7 +18,7 @@ const TokenInfoFieldAddress = ({ control }: Props) => { ...@@ -18,7 +18,7 @@ const TokenInfoFieldAddress = ({ control }: Props) => {
<Input <Input
{ ...field } { ...field }
required required
isDisabled isReadOnly
/> />
<InputPlaceholder text="Token contract address"/> <InputPlaceholder text="Token contract address"/>
</FormControl> </FormControl>
......
...@@ -19,7 +19,8 @@ const TokenInfoFieldComment = ({ control, isReadOnly }: Props) => { ...@@ -19,7 +19,8 @@ const TokenInfoFieldComment = ({ control, isReadOnly }: Props) => {
<Textarea <Textarea
{ ...field } { ...field }
isInvalid={ Boolean(fieldState.error) } isInvalid={ Boolean(fieldState.error) }
isDisabled={ formState.isSubmitting || isReadOnly } isDisabled={ formState.isSubmitting }
isReadOnly={ isReadOnly }
autoComplete="off" autoComplete="off"
maxH="160px" maxH="160px"
maxLength={ 300 } maxLength={ 300 }
......
...@@ -20,7 +20,8 @@ const TokenInfoFieldDocs = ({ control, isReadOnly }: Props) => { ...@@ -20,7 +20,8 @@ const TokenInfoFieldDocs = ({ control, isReadOnly }: Props) => {
<Input <Input
{ ...field } { ...field }
isInvalid={ Boolean(fieldState.error) } isInvalid={ Boolean(fieldState.error) }
isDisabled={ formState.isSubmitting || isReadOnly } isDisabled={ formState.isSubmitting }
isReadOnly={ isReadOnly }
autoComplete="off" autoComplete="off"
/> />
<InputPlaceholder text="Docs" error={ fieldState.error }/> <InputPlaceholder text="Docs" error={ fieldState.error }/>
......
...@@ -58,7 +58,8 @@ const TokenInfoFieldIconUrl = ({ control, isReadOnly, trigger }: Props) => { ...@@ -58,7 +58,8 @@ const TokenInfoFieldIconUrl = ({ control, isReadOnly, trigger }: Props) => {
{ ...field } { ...field }
onBlur={ handleBlur } onBlur={ handleBlur }
isInvalid={ Boolean(fieldState.error) } isInvalid={ Boolean(fieldState.error) }
isDisabled={ formState.isSubmitting || isReadOnly } isDisabled={ formState.isSubmitting }
isReadOnly={ isReadOnly }
autoComplete="off" autoComplete="off"
required required
/> />
......
...@@ -22,7 +22,8 @@ const TokenInfoFieldPriceTicker = ({ control, isReadOnly, name, label }: Props) ...@@ -22,7 +22,8 @@ const TokenInfoFieldPriceTicker = ({ control, isReadOnly, name, label }: Props)
<Input <Input
{ ...field } { ...field }
isInvalid={ Boolean(fieldState.error) } isInvalid={ Boolean(fieldState.error) }
isDisabled={ formState.isSubmitting || isReadOnly } isDisabled={ formState.isSubmitting }
isReadOnly={ isReadOnly }
autoComplete="off" autoComplete="off"
/> />
<InputPlaceholder text={ label } error={ fieldState.error }/> <InputPlaceholder text={ label } error={ fieldState.error }/>
......
...@@ -20,7 +20,8 @@ const TokenInfoFieldProjectDescription = ({ control, isReadOnly }: Props) => { ...@@ -20,7 +20,8 @@ const TokenInfoFieldProjectDescription = ({ control, isReadOnly }: Props) => {
{ ...field } { ...field }
required required
isInvalid={ Boolean(fieldState.error) } isInvalid={ Boolean(fieldState.error) }
isDisabled={ formState.isSubmitting || isReadOnly } isDisabled={ formState.isSubmitting }
isReadOnly={ isReadOnly }
autoComplete="off" autoComplete="off"
maxH="160px" maxH="160px"
maxLength={ 300 } maxLength={ 300 }
......
...@@ -21,7 +21,8 @@ const TokenInfoFieldProjectEmail = ({ control, isReadOnly }: Props) => { ...@@ -21,7 +21,8 @@ const TokenInfoFieldProjectEmail = ({ control, isReadOnly }: Props) => {
{ ...field } { ...field }
required required
isInvalid={ Boolean(fieldState.error) } isInvalid={ Boolean(fieldState.error) }
isDisabled={ formState.isSubmitting || isReadOnly } isDisabled={ formState.isSubmitting }
isReadOnly={ isReadOnly }
autoComplete="off" autoComplete="off"
/> />
<InputPlaceholder text="Official project email address" error={ fieldState.error }/> <InputPlaceholder text="Official project email address" error={ fieldState.error }/>
......
...@@ -20,7 +20,8 @@ const TokenInfoFieldProjectName = ({ control, isReadOnly }: Props) => { ...@@ -20,7 +20,8 @@ const TokenInfoFieldProjectName = ({ control, isReadOnly }: Props) => {
<Input <Input
{ ...field } { ...field }
isInvalid={ Boolean(fieldState.error) } isInvalid={ Boolean(fieldState.error) }
isDisabled={ formState.isSubmitting || isReadOnly } isDisabled={ formState.isSubmitting }
isReadOnly={ isReadOnly }
autoComplete="off" autoComplete="off"
/> />
<InputPlaceholder text="Project name" error={ fieldState.error }/> <InputPlaceholder text="Project name" error={ fieldState.error }/>
......
...@@ -29,7 +29,8 @@ const TokenInfoFieldProjectSector = ({ control, isReadOnly, config }: Props) => ...@@ -29,7 +29,8 @@ const TokenInfoFieldProjectSector = ({ control, isReadOnly, config }: Props) =>
options={ options } options={ options }
size={ isMobile ? 'md' : 'lg' } size={ isMobile ? 'md' : 'lg' }
placeholder="Project industry" placeholder="Project industry"
isDisabled={ formState.isSubmitting || isReadOnly } isDisabled={ formState.isSubmitting }
isReadOnly={ isReadOnly }
error={ fieldState.error } error={ fieldState.error }
/> />
); );
......
...@@ -20,7 +20,8 @@ const TokenInfoFieldProjectWebsite = ({ control, isReadOnly }: Props) => { ...@@ -20,7 +20,8 @@ const TokenInfoFieldProjectWebsite = ({ control, isReadOnly }: Props) => {
<Input <Input
{ ...field } { ...field }
isInvalid={ Boolean(fieldState.error) } isInvalid={ Boolean(fieldState.error) }
isDisabled={ formState.isSubmitting || isReadOnly } isDisabled={ formState.isSubmitting }
isReadOnly={ isReadOnly }
autoComplete="off" autoComplete="off"
required required
/> />
......
...@@ -21,7 +21,8 @@ const TokenInfoFieldRequesterEmail = ({ control, isReadOnly }: Props) => { ...@@ -21,7 +21,8 @@ const TokenInfoFieldRequesterEmail = ({ control, isReadOnly }: Props) => {
{ ...field } { ...field }
required required
isInvalid={ Boolean(fieldState.error) } isInvalid={ Boolean(fieldState.error) }
isDisabled={ formState.isSubmitting || isReadOnly } isDisabled={ formState.isSubmitting }
isReadOnly={ isReadOnly }
autoComplete="off" autoComplete="off"
/> />
<InputPlaceholder text="Requester email" error={ fieldState.error }/> <InputPlaceholder text="Requester email" error={ fieldState.error }/>
......
...@@ -20,7 +20,8 @@ const TokenInfoFieldRequesterName = ({ control, isReadOnly }: Props) => { ...@@ -20,7 +20,8 @@ const TokenInfoFieldRequesterName = ({ control, isReadOnly }: Props) => {
{ ...field } { ...field }
required required
isInvalid={ Boolean(fieldState.error) } isInvalid={ Boolean(fieldState.error) }
isDisabled={ formState.isSubmitting || isReadOnly } isDisabled={ formState.isSubmitting }
isReadOnly={ isReadOnly }
autoComplete="off" autoComplete="off"
/> />
<InputPlaceholder text="Requester name" error={ fieldState.error }/> <InputPlaceholder text="Requester name" error={ fieldState.error }/>
......
...@@ -42,7 +42,8 @@ const TokenInfoFieldSocialLink = ({ control, isReadOnly, name }: Props) => { ...@@ -42,7 +42,8 @@ const TokenInfoFieldSocialLink = ({ control, isReadOnly, name }: Props) => {
<Input <Input
{ ...field } { ...field }
isInvalid={ Boolean(fieldState.error) } isInvalid={ Boolean(fieldState.error) }
isDisabled={ formState.isSubmitting || isReadOnly } isDisabled={ formState.isSubmitting }
isReadOnly={ isReadOnly }
autoComplete="off" autoComplete="off"
/> />
<InputPlaceholder text={ SETTINGS[name].label } error={ fieldState.error }/> <InputPlaceholder text={ SETTINGS[name].label } error={ fieldState.error }/>
......
...@@ -22,7 +22,8 @@ const TokenInfoFieldSupport = ({ control, isReadOnly }: Props) => { ...@@ -22,7 +22,8 @@ const TokenInfoFieldSupport = ({ control, isReadOnly }: Props) => {
<Input <Input
{ ...field } { ...field }
isInvalid={ Boolean(fieldState.error) } isInvalid={ Boolean(fieldState.error) }
isDisabled={ formState.isSubmitting || isReadOnly } isDisabled={ formState.isSubmitting }
isReadOnly={ isReadOnly }
autoComplete="off" autoComplete="off"
/> />
<InputPlaceholder text="Support URL or email" error={ fieldState.error }/> <InputPlaceholder text="Support URL or email" error={ fieldState.error }/>
......
...@@ -18,7 +18,7 @@ const TokenInfoFieldTokenName = ({ control }: Props) => { ...@@ -18,7 +18,7 @@ const TokenInfoFieldTokenName = ({ control }: Props) => {
<Input <Input
{ ...field } { ...field }
required required
isDisabled isReadOnly
/> />
<InputPlaceholder text="Token name"/> <InputPlaceholder text="Token name"/>
</FormControl> </FormControl>
......
...@@ -39,7 +39,7 @@ const TokenInstanceMetadata = ({ data, isPlaceholderData }: Props) => { ...@@ -39,7 +39,7 @@ const TokenInstanceMetadata = ({ data, isPlaceholderData }: Props) => {
<Box> <Box>
<Flex alignItems="center" mb={ 6 }> <Flex alignItems="center" mb={ 6 }>
<chakra.span fontWeight={ 500 }>Metadata</chakra.span> <chakra.span fontWeight={ 500 }>Metadata</chakra.span>
<Select size="xs" borderRadius="base" value={ format } onChange={ handleSelectChange } focusBorderColor="none" w="auto" ml={ 5 }> <Select size="xs" borderRadius="base" value={ format } onChange={ handleSelectChange } w="auto" ml={ 5 }>
<option value="Table">Table</option> <option value="Table">Table</option>
<option value="JSON">JSON</option> <option value="JSON">JSON</option>
</Select> </Select>
......
...@@ -2,7 +2,6 @@ import { ...@@ -2,7 +2,6 @@ import {
Box, Box,
Button, Button,
Text, Text,
useColorModeValue,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useMutation } from '@tanstack/react-query'; import { useMutation } from '@tanstack/react-query';
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
...@@ -69,7 +68,6 @@ type Checkboxes = 'notification' | ...@@ -69,7 +68,6 @@ type Checkboxes = 'notification' |
const AddressForm: React.FC<Props> = ({ data, onSuccess, setAlertVisible, isAdd }) => { const AddressForm: React.FC<Props> = ({ data, onSuccess, setAlertVisible, isAdd }) => {
const [ pending, setPending ] = useState(false); const [ pending, setPending ] = useState(false);
const formBackgroundColor = useColorModeValue('white', 'gray.900');
let notificationsDefault = {} as Inputs['notification_settings']; let notificationsDefault = {} as Inputs['notification_settings'];
if (!data?.notification_settings) { if (!data?.notification_settings) {
...@@ -142,15 +140,15 @@ const AddressForm: React.FC<Props> = ({ data, onSuccess, setAlertVisible, isAdd ...@@ -142,15 +140,15 @@ const AddressForm: React.FC<Props> = ({ data, onSuccess, setAlertVisible, isAdd
return ( return (
<AddressInput<Inputs, 'address'> <AddressInput<Inputs, 'address'>
field={ field } field={ field }
backgroundColor={ formBackgroundColor } bgColor="dialog_bg"
error={ errors.address } error={ errors.address }
/> />
); );
}, [ errors, formBackgroundColor ]); }, [ errors ]);
const renderTagInput = useCallback(({ field }: {field: ControllerRenderProps<Inputs, 'tag'>}) => { const renderTagInput = useCallback(({ field }: {field: ControllerRenderProps<Inputs, 'tag'>}) => {
return <TagInput<Inputs, 'tag'> field={ field } error={ errors.tag } backgroundColor={ formBackgroundColor }/>; return <TagInput<Inputs, 'tag'> field={ field } error={ errors.tag } bgColor="dialog_bg"/>;
}, [ errors, formBackgroundColor ]); }, [ errors ]);
// eslint-disable-next-line react/display-name // eslint-disable-next-line react/display-name
const renderCheckbox = useCallback((text: string) => ({ field }: {field: ControllerRenderProps<Inputs, Checkboxes>}) => ( const renderCheckbox = useCallback((text: string) => ({ field }: {field: ControllerRenderProps<Inputs, Checkboxes>}) => (
......
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