Commit adb1a307 authored by tom's avatar tom

fix input group paddings calculation

parent bb9842bc
import type { BoxProps, InputElementProps } from '@chakra-ui/react'; import type { BoxProps, InputElementProps } from '@chakra-ui/react';
import { Group, InputElement } from '@chakra-ui/react'; import { Group, InputElement } from '@chakra-ui/react';
import { debounce } from 'es-toolkit';
import * as React from 'react'; import * as React from 'react';
import getComponentDisplayName from '../utils/getComponentDisplayName'; import getComponentDisplayName from '../utils/getComponentDisplayName';
...@@ -31,12 +32,9 @@ export const InputGroup = React.forwardRef<HTMLDivElement, InputGroupProps>( ...@@ -31,12 +32,9 @@ export const InputGroup = React.forwardRef<HTMLDivElement, InputGroupProps>(
const startElementRef = React.useRef<HTMLDivElement>(null); const startElementRef = React.useRef<HTMLDivElement>(null);
const endElementRef = React.useRef<HTMLDivElement>(null); const endElementRef = React.useRef<HTMLDivElement>(null);
const [ inlinePaddings, setInlinePaddings ] = React.useState({ const [ inlinePaddings, setInlinePaddings ] = React.useState<{ start?: number; end?: number }>();
start: 0,
end: 0,
});
React.useEffect(() => { const calculateInlinePaddings = React.useCallback(() => {
const { width: endWidth } = endElementRef?.current?.getBoundingClientRect() ?? {}; const { width: endWidth } = endElementRef?.current?.getBoundingClientRect() ?? {};
const { width: startWidth } = startElementRef?.current?.getBoundingClientRect() ?? {}; const { width: startWidth } = startElementRef?.current?.getBoundingClientRect() ?? {};
...@@ -46,10 +44,22 @@ export const InputGroup = React.forwardRef<HTMLDivElement, InputGroupProps>( ...@@ -46,10 +44,22 @@ export const InputGroup = React.forwardRef<HTMLDivElement, InputGroupProps>(
}); });
}, []); }, []);
React.useEffect(() => {
calculateInlinePaddings();
const resizeHandler = debounce(calculateInlinePaddings, 300);
const resizeObserver = new ResizeObserver(resizeHandler);
resizeObserver.observe(window.document.body);
return function cleanup() {
resizeObserver.unobserve(window.document.body);
};
}, [ calculateInlinePaddings ]);
return ( return (
<Group ref={ ref } w="100%" { ...rest }> <Group ref={ ref } w="100%" { ...rest }>
{ startElement && ( { startElement && (
<InputElement pointerEvents="none" ref={ startElementRef } { ...startElementProps }> <InputElement pointerEvents="none" ref={ startElementRef } px={ 0 } { ...startElementProps }>
{ startElement } { startElement }
</InputElement> </InputElement>
) } ) }
...@@ -58,12 +68,15 @@ export const InputGroup = React.forwardRef<HTMLDivElement, InputGroupProps>( ...@@ -58,12 +68,15 @@ export const InputGroup = React.forwardRef<HTMLDivElement, InputGroupProps>(
return child; return child;
} }
return React.cloneElement(child, { return React.cloneElement(child, {
...(startElement && { ps: startOffset ?? `${ inlinePaddings.start }px` }), ...(startElement && { ps: startOffset ?? (inlinePaddings?.start ? `${ inlinePaddings.start }px` : undefined) }),
...(endElement && { pe: endOffset ?? `${ inlinePaddings.end }px` }), ...(endElement && { pe: endOffset ?? (inlinePaddings?.end ? `${ inlinePaddings.end }px` : undefined) }),
// hide input value and placeholder for the first render
value: inlinePaddings ? child.props.value : undefined,
placeholder: inlinePaddings ? child.props.placeholder : undefined,
}); });
}) } }) }
{ endElement && ( { endElement && (
<InputElement placement="end" ref={ endElementRef } { ...endElementProps }> <InputElement placement="end" ref={ endElementRef } px={ 0 } { ...endElementProps }>
{ endElement } { endElement }
</InputElement> </InputElement>
) } ) }
......
...@@ -18,6 +18,11 @@ export const recipe = defineRecipe({ ...@@ -18,6 +18,11 @@ export const recipe = defineRecipe({
focusRingColor: 'var(--error-color)', focusRingColor: 'var(--error-color)',
borderColor: 'var(--error-color)', borderColor: 'var(--error-color)',
}, },
_readOnly: {
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
},
_autofill: { _autofill: {
// FIXME: this is not working // FIXME: this is not working
// WebkitTextFillColor: '{colors.input.fg}', // WebkitTextFillColor: '{colors.input.fg}',
......
...@@ -17,7 +17,7 @@ const ContractMethodAddressButton = ({ onClick, isDisabled }: Props) => { ...@@ -17,7 +17,7 @@ const ContractMethodAddressButton = ({ onClick, isDisabled }: Props) => {
}, [ address, onClick ]); }, [ address, onClick ]);
return ( return (
<Tooltip content={ !address ? 'Connect your wallet to enter your address.' : undefined }> <Tooltip content="Connect your wallet to enter your address." disabled={ Boolean(address) }>
<Button <Button
variant="subtle" variant="subtle"
size="xs" size="xs"
......
...@@ -131,7 +131,7 @@ const ContractMethodFieldInput = ({ data, hideLabel, path: name, className, isDi ...@@ -131,7 +131,7 @@ const ContractMethodFieldInput = ({ data, hideLabel, path: name, className, isDi
const inputEndElement = ( const inputEndElement = (
<Flex alignItems="center"> <Flex alignItems="center">
<ClearButton onClick={ handleClear } isDisabled={ isDisabled } boxSize={ 6 } isVisible={ field.value !== undefined && field.value !== '' }/> <ClearButton onClick={ handleClear } isDisabled={ isDisabled } minW={ 6 } isVisible={ field.value !== undefined && field.value !== '' }/>
{ data.type === 'address' && <ContractMethodAddressButton onClick={ handleAddressButtonClick } isDisabled={ isDisabled }/> } { data.type === 'address' && <ContractMethodAddressButton onClick={ handleAddressButtonClick } isDisabled={ isDisabled }/> }
{ argTypeMatchInt && !isNativeCoin && (hasTimestampButton ? ( { argTypeMatchInt && !isNativeCoin && (hasTimestampButton ? (
<Button <Button
......
import { Text, Box, Input, Flex } from '@chakra-ui/react'; import { Text, Box, Flex } from '@chakra-ui/react';
import { sumBy } from 'es-toolkit'; import { sumBy } from 'es-toolkit';
import type { ChangeEvent } from 'react';
import React from 'react'; import React from 'react';
import type { FormattedData } from './types'; import type { FormattedData } from './types';
import type { TokenType } from 'types/api/token'; import type { TokenType } from 'types/api/token';
import { getTokenTypeName } from 'lib/token/tokenTypes'; import { getTokenTypeName } from 'lib/token/tokenTypes';
import { InputGroup } from 'toolkit/chakra/input-group';
import { Link } from 'toolkit/chakra/link'; import { Link } from 'toolkit/chakra/link';
import FilterInput from 'ui/shared/filters/FilterInput';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
import type { Sort } from '../utils/tokenUtils'; import type { Sort } from '../utils/tokenUtils';
...@@ -21,7 +20,7 @@ interface Props { ...@@ -21,7 +20,7 @@ interface Props {
erc1155sort: Sort; erc1155sort: Sort;
erc404sort: Sort; erc404sort: Sort;
filteredData: FormattedData; filteredData: FormattedData;
onInputChange: (event: ChangeEvent<HTMLInputElement>) => void; onInputChange: (searchTerm: string) => void;
onSortClick: (event: React.SyntheticEvent) => void; onSortClick: (event: React.SyntheticEvent) => void;
} }
...@@ -30,12 +29,13 @@ const TokenSelectMenu = ({ erc20sort, erc1155sort, erc404sort, filteredData, onI ...@@ -30,12 +29,13 @@ const TokenSelectMenu = ({ erc20sort, erc1155sort, erc404sort, filteredData, onI
return ( return (
<> <>
<InputGroup <FilterInput
startElement={ <IconSvg name="search" boxSize={ 4 } color={{ _light: 'blackAlpha.600', _dark: 'whiteAlpha.600' }}/> } placeholder="Search by token name"
size="sm"
inputProps={{ bgColor: 'dialog.bg' }}
mb={ 5 } mb={ 5 }
> onChange={ onInputChange }
<Input placeholder="Search by token name" onChange={ onInputChange } size="sm" bgColor="dialog.bg"/> />
</InputGroup>
<Flex flexDir="column" rowGap={ 6 }> <Flex flexDir="column" rowGap={ 6 }>
{ Object.entries(filteredData).sort(sortTokenGroups).map(([ tokenType, tokenInfo ]) => { { Object.entries(filteredData).sort(sortTokenGroups).map(([ tokenType, tokenInfo ]) => {
if (tokenInfo.items.length === 0) { if (tokenInfo.items.length === 0) {
......
import { mapValues } from 'es-toolkit'; import { mapValues } from 'es-toolkit';
import type { ChangeEvent } from 'react';
import React from 'react'; import React from 'react';
import type { FormattedData } from './types'; import type { FormattedData } from './types';
...@@ -13,8 +12,8 @@ export default function useTokenSelect(data: FormattedData) { ...@@ -13,8 +12,8 @@ export default function useTokenSelect(data: FormattedData) {
const [ erc404sort, setErc404Sort ] = React.useState<Sort>('desc'); const [ erc404sort, setErc404Sort ] = React.useState<Sort>('desc');
const [ erc20sort, setErc20Sort ] = React.useState<Sort>('desc'); const [ erc20sort, setErc20Sort ] = React.useState<Sort>('desc');
const onInputChange = React.useCallback((event: ChangeEvent<HTMLInputElement>) => { const onInputChange = React.useCallback((searchTerm: string) => {
setSearchTerm(event.target.value); setSearchTerm(searchTerm);
}, []); }, []);
const onSortClick = React.useCallback((event: React.SyntheticEvent) => { const onSortClick = React.useCallback((event: React.SyntheticEvent) => {
......
...@@ -18,8 +18,8 @@ const RewardsReadOnlyInputWithCopy = ({ label, value, className, isLoading }: Pr ...@@ -18,8 +18,8 @@ const RewardsReadOnlyInputWithCopy = ({ label, value, className, isLoading }: Pr
return ( return (
<Skeleton loading={ isLoading } className={ className }> <Skeleton loading={ isLoading } className={ className }>
<Field label={ label } floating size="xl" readOnly> <Field label={ label } floating size="xl" readOnly>
<InputGroup endElement={ <CopyToClipboard text={ value }/> }> <InputGroup endElement={ <CopyToClipboard text={ value }/> } endElementProps={{ px: 3 }}>
<Input value={ value } fontWeight="500" overflow="hidden" textOverflow="ellipsis"/> <Input value={ value } fontWeight="500"/>
</InputGroup> </InputGroup>
</Field> </Field>
</Skeleton> </Skeleton>
......
import type { ChangeEvent } from 'react'; import type { ChangeEvent } from 'react';
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
import type { InputProps } from 'toolkit/chakra/input';
import { Input } from 'toolkit/chakra/input'; import { Input } from 'toolkit/chakra/input';
import { InputGroup } from 'toolkit/chakra/input-group'; import { InputGroup } from 'toolkit/chakra/input-group';
import type { SkeletonProps } from 'toolkit/chakra/skeleton'; import type { SkeletonProps } from 'toolkit/chakra/skeleton';
...@@ -18,9 +19,10 @@ interface Props extends Omit<SkeletonProps, 'onChange' | 'loading'> { ...@@ -18,9 +19,10 @@ interface Props extends Omit<SkeletonProps, 'onChange' | 'loading'> {
initialValue?: string; initialValue?: string;
type?: React.HTMLInputTypeAttribute; type?: React.HTMLInputTypeAttribute;
name?: string; name?: string;
inputProps?: InputProps;
}; };
const FilterInput = ({ onChange, size = 'sm', placeholder, initialValue, type, name, loading = false, onFocus, onBlur, ...rest }: Props) => { const FilterInput = ({ onChange, size = 'sm', placeholder, initialValue, type, name, loading = false, onFocus, onBlur, inputProps, ...rest }: Props) => {
const [ filterQuery, setFilterQuery ] = useState(initialValue || ''); const [ filterQuery, setFilterQuery ] = useState(initialValue || '');
const inputRef = React.useRef<HTMLInputElement>(null); const inputRef = React.useRef<HTMLInputElement>(null);
...@@ -52,7 +54,7 @@ const FilterInput = ({ onChange, size = 'sm', placeholder, initialValue, type, n ...@@ -52,7 +54,7 @@ const FilterInput = ({ onChange, size = 'sm', placeholder, initialValue, type, n
startElement={ startElement } startElement={ startElement }
startElementProps={{ px: 2 }} startElementProps={{ px: 2 }}
endElement={ endElement } endElement={ endElement }
endElementProps={{ px: 0, w: '32px' }} endElementProps={{ w: '32px' }}
> >
<Input <Input
ref={ inputRef } ref={ inputRef }
...@@ -67,6 +69,7 @@ const FilterInput = ({ onChange, size = 'sm', placeholder, initialValue, type, n ...@@ -67,6 +69,7 @@ const FilterInput = ({ onChange, size = 'sm', placeholder, initialValue, type, n
whiteSpace="nowrap" whiteSpace="nowrap"
type={ type } type={ type }
name={ name } name={ name }
{ ...inputProps }
/> />
</InputGroup> </InputGroup>
</Skeleton> </Skeleton>
......
...@@ -205,7 +205,7 @@ const CodeEditorSearch = ({ monaco, data, onFileSelect, isInputStuck, isActive, ...@@ -205,7 +205,7 @@ const CodeEditorSearch = ({ monaco, data, onFileSelect, isInputStuck, isActive,
pb="8px" pb="8px"
boxShadow={ isInputStuck ? '0px 6px 3px 0px rgba(0, 0, 0, 0.05)' : 'none' } boxShadow={ isInputStuck ? '0px 6px 3px 0px rgba(0, 0, 0, 0.05)' : 'none' }
endElement={ inputEndElement } endElement={ inputEndElement }
endElementProps={{ height: '26px', pl: '0', pr: '10px', columnGap: '2px' }} endElementProps={{ height: '26px', pl: '0', right: '10px', columnGap: '2px' }}
> >
<Input <Input
size="xs" size="xs"
......
...@@ -114,13 +114,13 @@ const InputShowcase = () => { ...@@ -114,13 +114,13 @@ const InputShowcase = () => {
<SamplesStack> <SamplesStack>
<Sample label="with end element"> <Sample label="with end element">
<Field label="Referral code" required floating size="xl" w="300px" flexShrink={ 0 }> <Field label="Referral code" required floating size="xl" w="300px" flexShrink={ 0 }>
<InputGroup endElement={ <IconSvg name="copy" boxSize={ 5 }/> }> <InputGroup endElement={ <IconSvg name="copy" boxSize={ 5 }/> } endElementProps={{ px: 3 }}>
<Input/> <Input/>
</InputGroup> </InputGroup>
</Field> </Field>
</Sample> </Sample>
<Sample label="with start element"> <Sample label="with start element">
<InputGroup startElement={ <IconSvg name="collection" boxSize={ 5 }/> }> <InputGroup startElement={ <IconSvg name="collection" boxSize={ 5 }/> } startElementProps={{ px: 2 }}>
<Input placeholder="Type in something"/> <Input placeholder="Type in something"/>
</InputGroup> </InputGroup>
</Sample> </Sample>
......
...@@ -106,6 +106,8 @@ const SearchBarInput = ( ...@@ -106,6 +106,8 @@ const SearchBarInput = (
name="search" name="search"
boxSize={{ base: isHomepage ? 6 : 4, lg: 6 }} boxSize={{ base: isHomepage ? 6 : 4, lg: 6 }}
color={{ _light: 'blackAlpha.600', _dark: 'whiteAlpha.600' }} color={{ _light: 'blackAlpha.600', _dark: 'whiteAlpha.600' }}
ml={{ base: 3, lg: 4 }}
mr="10px"
/> />
); );
...@@ -117,12 +119,11 @@ const SearchBarInput = ( ...@@ -117,12 +119,11 @@ const SearchBarInput = (
<Center <Center
boxSize="20px" boxSize="20px"
my="2px" my="2px"
mr={{ base: 1, lg: isHomepage ? 2 : 1 }} mr={ 3 }
borderRadius="sm" borderRadius="sm"
borderWidth="1px" borderWidth="1px"
borderColor="gray.400" borderColor="gray.400"
color="gray.400" color="gray.400"
display={{ base: 'none', lg: 'flex' }}
> >
/ /
</Center> </Center>
......
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