Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/token input decimal undefined #93

Merged
merged 3 commits into from
May 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/six-weeks-hammer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@interlay/ui": patch
"@interlay/hooks": patch
---

Fix/token input decimal undefined
46 changes: 20 additions & 26 deletions packages/components/src/TokenInput/BaseTokenInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useCurrencyFormatter, useDOMRef } from '@interlay/hooks';
import { Spacing, TokenInputSize } from '@interlay/theme';
import { AriaTextFieldOptions, useTextField } from '@react-aria/textfield';
import { mergeProps } from '@react-aria/utils';
import { ChangeEventHandler, FocusEvent, forwardRef, ReactNode, useCallback, useEffect, useState } from 'react';
import { ChangeEventHandler, FocusEvent, forwardRef, ReactNode, useCallback } from 'react';

import { HelperTextProps } from '../HelperText';
import { LabelProps } from '../Label';
Expand Down Expand Up @@ -42,7 +42,7 @@ type Props = {
value?: string;
defaultValue?: string;
// TODO: use Currency from bob-ui
currency: { decimals: number };
currency?: { decimals: number };
onValueChange?: (value: string | number) => void;
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
onFocus?: (e: FocusEvent<Element>) => void;
Expand Down Expand Up @@ -75,7 +75,7 @@ const BaseTokenInput = forwardRef<HTMLInputElement, BaseTokenInputProps>(
size = 'md',
defaultValue,
inputMode,
value: valueProp,
value,
endAdornment,
currency,
onChange,
Expand All @@ -84,49 +84,43 @@ const BaseTokenInput = forwardRef<HTMLInputElement, BaseTokenInputProps>(
},
ref
): JSX.Element => {
const [value, setValue] = useState<string | undefined>(defaultValue?.toString());
const inputRef = useDOMRef(ref);

const format = useCurrencyFormatter();

const { inputProps, descriptionProps, errorMessageProps, labelProps } = useTextField(
{
...props,
label,
inputMode,
isInvalid: isInvalid || !!props.errorMessage,
value,
onChange: () => {},
defaultValue,
placeholder,
autoComplete: 'off'
},
inputRef
);

const handleChange: ChangeEventHandler<HTMLInputElement> = useCallback(
(e) => {
const value = e.target.value;

const isEmpty = value === '';
const hasValidDecimalFormat = RegExp(`^\\d*(?:\\\\[.])?\\d*$`).test(escapeRegExp(value));
const hasValidDecimalsAmount = hasCorrectDecimals(value, currency.decimals);
const hasValidDecimalsAmount = currency ? hasCorrectDecimals(value, currency.decimals) : true;

const isValid = hasValidDecimalFormat && hasValidDecimalsAmount;

if (isEmpty || isValid) {
onChange?.(e);
onValueChange?.(value);
setValue(value);
}
},
[onChange, onValueChange]
);

const { inputProps, descriptionProps, errorMessageProps, labelProps } = useTextField(
{
...props,
label,
inputMode,
isInvalid: isInvalid || !!props.errorMessage,
value: value,
placeholder,
autoComplete: 'off'
},
inputRef
[onChange, onValueChange, currency]
);

useEffect(() => {
if (valueProp === undefined) return;

setValue(valueProp.toString());
}, [valueProp]);

const hasLabel = !!label || !!balance;

// FIXME: move this into Field
Expand Down
6 changes: 3 additions & 3 deletions packages/components/src/TokenInput/FixedTokenInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import { BaseTokenInput, BaseTokenInputProps } from './BaseTokenInput';
import { TokenInputBalance } from './TokenInputBalance';

type Props = {
currency: any;
balance?: string;
humanBalance?: string | number;
balanceLabel?: ReactNode;
onClickBalance?: (balance: string | number) => void;
ticker: string;
logoUrl: string;
};

Expand All @@ -24,11 +24,11 @@ const FixedTokenInput = forwardRef<HTMLInputElement, FixedTokenInputProps>(
humanBalance,
balanceLabel,
onClickBalance,
ticker: tickerProp,
logoUrl,
isDisabled,
id,
size = 'md',
currency,
...props
},
ref
Expand All @@ -49,7 +49,7 @@ const FixedTokenInput = forwardRef<HTMLInputElement, FixedTokenInputProps>(
{...props}
ref={ref}
balance={balance}
endAdornment={<TokenAdornment logoUrl={logoUrl} size={size} ticker={tickerProp} />}
endAdornment={<TokenAdornment logoUrl={logoUrl} size={size} ticker={currency.symbol} />}
id={id}
isDisabled={isDisabled}
size={size}
Expand Down
43 changes: 28 additions & 15 deletions packages/components/src/TokenInput/SelectableTokenInput.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import { chain, useId } from '@react-aria/utils';
import { Key, ReactNode, forwardRef, useEffect, useState } from 'react';
import { Key, ReactNode, forwardRef, useCallback, useEffect } from 'react';

import { HelperText } from '../HelperText';

import { BaseTokenInput, BaseTokenInputProps } from './BaseTokenInput';
import { TokenInputBalance } from './TokenInputBalance';
import { TokenSelect, TokenSelectProps } from './TokenSelect';
import { TokenData, TokenSelect, TokenSelectProps } from './TokenSelect';

type Props = {
balance?: string;
humanBalance?: string | number;
balanceLabel?: ReactNode;
currency?: any;
items?: TokenData[];
onClickBalance?: (balance: string) => void;
selectProps: Omit<TokenSelectProps, 'label' | 'helperTextId'>;
onChangeCurrency?: (currency?: any) => void;
selectProps?: Omit<TokenSelectProps, 'label' | 'helperTextId' | 'items'>;
};

type InheritAttrs = Omit<BaseTokenInputProps, keyof Props | 'endAdornment'>;
Expand All @@ -31,25 +34,33 @@ const SelectableTokenInput = forwardRef<HTMLInputElement, SelectableTokenInputPr
isDisabled,
balanceLabel,
humanBalance,
currency,
items,
onClickBalance,
onChangeCurrency,
size,
...props
},
ref
): JSX.Element => {
const selectHelperTextId = useId();

const [ticker, setTicker] = useState<string | undefined>(selectProps?.defaultValue?.toString());

useEffect(() => {
const value = selectProps?.value;
if (selectProps?.value === undefined) return;

const item = (items as TokenData[]).find((item) => item.currency.symbol === selectProps?.value);

if (value === undefined) return;
onChangeCurrency?.(item?.currency);
}, [selectProps?.value, onChangeCurrency]);

setTicker(value.toString());
}, [selectProps?.value]);
const handleSelectionChange = useCallback(
(ticker: Key) => {
const tokenData = (items as TokenData[]).find((item) => item.currency.symbol === ticker);

const handleTokenChange = (ticker: Key) => setTicker(ticker as string);
onChangeCurrency?.(tokenData?.currency);
},
[selectProps]
);

// Prioritise Number Input description and error message
const hasNumberFieldMessages = !!(errorMessage || description);
Expand All @@ -58,7 +69,7 @@ const SelectableTokenInput = forwardRef<HTMLInputElement, SelectableTokenInputPr

const isInvalid = !hasNumberFieldMessages && !!selectProps?.errorMessage;

const { onSelectionChange, ...restSelectProps } = selectProps;
const { onSelectionChange, ...restSelectProps } = selectProps || {};

const endAdornment = (
<TokenSelect
Expand All @@ -67,18 +78,19 @@ const SelectableTokenInput = forwardRef<HTMLInputElement, SelectableTokenInputPr
description={undefined}
errorMessage={undefined}
isInvalid={isInvalid}
items={items}
size={size}
value={ticker}
onSelectionChange={chain(onSelectionChange, handleTokenChange)}
value={currency?.symbol}
onSelectionChange={chain(onSelectionChange, handleSelectionChange)}
/>
);

const balance = balanceProp !== undefined && (
<TokenInputBalance
balance={ticker ? balanceProp : '0'}
balance={currency ? balanceProp : '0'}
balanceHuman={humanBalance}
inputId={id}
isDisabled={isDisabled || !ticker}
isDisabled={isDisabled || !currency}
label={balanceLabel}
onClickBalance={onClickBalance}
/>
Expand All @@ -88,6 +100,7 @@ const SelectableTokenInput = forwardRef<HTMLInputElement, SelectableTokenInputPr
<BaseTokenInput
ref={ref}
balance={balance}
currency={currency}
description={description}
endAdornment={endAdornment}
errorMessage={errorMessage}
Expand Down
Loading
Loading