Skip to content

Commit d500e65

Browse files
committed
feat: calculate input right pading based on suffix width
1 parent 49caaf0 commit d500e65

File tree

11 files changed

+80
-27
lines changed

11 files changed

+80
-27
lines changed

src/@next/CurrencyInput/CurrencyInput.stories.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@ Interactive.args = {
2424
onChange: (value: number) => {
2525
console.log('Currency on changed value: ', value);
2626
},
27-
prefix: '$',
27+
currencyCode: 'USD',
28+
currencySymbol: '',
2829
};

src/@next/CurrencyInput/CurrencyInput.test.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ describe('<Currency />', () => {
66
it('should call onChange with number', async () => {
77
const onChange = jest.fn();
88

9-
const screen = render(<CurrencyInput onChange={onChange} />);
9+
const screen = render(
10+
<CurrencyInput currencyCode="USD" onChange={onChange} />
11+
);
1012
const input = screen.getByRole('textbox');
1113

1214
fireEvent.change(input, { target: { value: 1000 } });

src/@next/CurrencyInput/CurrencyInput.tsx

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,22 @@ export type CurrencyInputProps = Omit<
88
locale?: string;
99
value?: number;
1010
onChange?: (value: number) => void;
11-
prefix?: string;
11+
currencyCode: string;
12+
currencySymbol?: string;
1213
};
1314

1415
export const CurrencyInput = React.forwardRef<
1516
HTMLInputElement,
1617
CurrencyInputProps
1718
>(function CurrencyInput(
18-
{ locale = 'en', value = 0, onChange, prefix, ...props }: CurrencyInputProps,
19+
{
20+
locale = 'en',
21+
value = 0,
22+
onChange,
23+
currencyCode,
24+
currencySymbol,
25+
...props
26+
}: CurrencyInputProps,
1927
ref
2028
) {
2129
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
@@ -47,6 +55,36 @@ export const CurrencyInput = React.forwardRef<
4755
return Number.isNaN(cleanedValue) ? 0 : cleanedValue;
4856
};
4957

58+
const getCurrencySymbol = (
59+
locale: string,
60+
currencyCode: string,
61+
currencySymbol?: string
62+
) => {
63+
if (currencySymbol) {
64+
return currencySymbol;
65+
}
66+
67+
try {
68+
const formatter = new Intl.NumberFormat(locale, {
69+
style: 'currency',
70+
currency: currencyCode,
71+
});
72+
73+
const parts = formatter.formatToParts(0);
74+
const returnedCurrencySymbol = parts.find(
75+
part => part.type === 'currency'
76+
)?.value;
77+
78+
return returnedCurrencySymbol;
79+
} catch (e) {
80+
console.warn(
81+
`Currency code of ${currencyCode} is unsupported, "$" will be used`
82+
);
83+
}
84+
85+
return '$';
86+
};
87+
5088
const [formattedValue, setFormattedValue] = useState(
5189
formatter.format(getRawNumber(value.toString()))
5290
);
@@ -61,7 +99,11 @@ export const CurrencyInput = React.forwardRef<
6199
<Input
62100
ref={ref}
63101
type="text"
64-
prefix={<div>{prefix ?? '$'}</div>}
102+
prefix={
103+
<div>
104+
{getCurrencySymbol(localeValue, currencyCode, currencySymbol)}
105+
</div>
106+
}
65107
{...props}
66108
value={formattedValue === '0' ? '' : formattedValue}
67109
onChange={handleChange}

src/@next/Input/Input.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export const Input = React.forwardRef<HTMLInputElement, InputProps>(
2222
const hasSuffix = !!suffix;
2323

2424
const prefixRef = useRef(null);
25+
const suffixRef = useRef(null);
2526

2627
const Prefix = () =>
2728
hasPrefix ? (
@@ -30,10 +31,11 @@ export const Input = React.forwardRef<HTMLInputElement, InputProps>(
3031

3132
const Suffix = () =>
3233
hasSuffix ? (
33-
<StyledSuffixContainer>{suffix}</StyledSuffixContainer>
34+
<StyledSuffixContainer ref={suffixRef}>{suffix}</StyledSuffixContainer>
3435
) : null;
3536

3637
const [prefixWidth, setPrefixWidth] = React.useState(0);
38+
const [suffixWidth, setSuffixWidth] = React.useState(0);
3739

3840
useEffect(() => {
3941
if (hasPrefix) {
@@ -42,13 +44,22 @@ export const Input = React.forwardRef<HTMLInputElement, InputProps>(
4244
}
4345
}, [hasPrefix, prefix]);
4446

47+
useEffect(() => {
48+
if (hasSuffix) {
49+
const suffixWidth = suffixRef.current.getBoundingClientRect().width;
50+
setSuffixWidth(suffixWidth);
51+
}
52+
}, [hasSuffix, suffix]);
53+
4554
return (
4655
<StyledContainer
4756
ref={ref}
4857
data-prefix={hasPrefix}
58+
data-suffix={hasSuffix}
4959
data-error={error}
5060
data-disabled={disabled}
5161
prefixWidth={prefixWidth}
62+
suffixWidth={suffixWidth}
5263
>
5364
<Prefix />
5465
<StyledInput disabled={disabled} {...props} />

src/@next/Input/InputStyle.ts

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,14 @@ import styled from 'styled-components';
22
import * as Breakpoints from '../utilities/breakpoints';
33
import { Neutral, Red } from '../utilities/colors';
44
import { InputProps } from './Input';
5-
import { space4, space8 } from '../utilities/spacing';
5+
import { space12, space4, space8 } from '../utilities/spacing';
66

7-
export const StyledContainer = styled.div<InputProps & { prefixWidth: number }>`
7+
interface PreffixSuffixWidthProps {
8+
prefixWidth: number;
9+
suffixWidth: number;
10+
}
11+
12+
export const StyledContainer = styled.div<InputProps & PreffixSuffixWidthProps>`
813
position: relative;
914
display: flex;
1015
flex-direction: column;
@@ -21,6 +26,10 @@ export const StyledContainer = styled.div<InputProps & { prefixWidth: number }>`
2126
padding-left: ${props => props.prefixWidth}px;
2227
}
2328
29+
&[data-suffix='true'] input {
30+
padding-right: ${props => props.suffixWidth}px;
31+
}
32+
2433
&[data-error='true'] input {
2534
border: 1px solid ${Red.B93};
2635
}
@@ -50,37 +59,25 @@ export const StyledContainer = styled.div<InputProps & { prefixWidth: number }>`
5059

5160
export const StyledPrefixContainer = styled.div`
5261
position: absolute;
53-
padding: 0;
5462
left: 0;
55-
line-height: 0;
5663
color: ${Neutral.B40};
64+
display: flex;
65+
align-items: center;
66+
height: 36px;
67+
padding: 0px ${space8} 0 ${space12};
5768
5869
svg {
5970
height: 17px;
6071
width: 17px;
61-
margin: 10px 14px;
62-
margin-right: ${space8};
6372
fill: ${Neutral.B40};
6473
}
65-
66-
div {
67-
color: ${Neutral.B40};
68-
margin: 18px 12px;
69-
margin-right: ${space4};
70-
}
7174
`;
7275

7376
export const StyledSuffixContainer = styled(StyledPrefixContainer)`
7477
left: auto;
7578
right: 0;
7679
77-
svg {
78-
margin: 10px 14px;
79-
}
80-
81-
div {
82-
margin: 18px 12px;
83-
}
80+
padding: 0px ${space12} 0 ${space4};
8481
`;
8582

8683
export const StyledInput = styled.input<InputProps>`

src/@next/Popover/popoverStoryHelper/SalarySelector.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ export const SalarySelector = ({ onFromChanged, onToChanged }: Props) => {
2222
IDR
2323
</Typography>
2424
<div>
25-
<CurrencyInput onChange={onFromChanged} />
25+
<CurrencyInput currencyCode="USD" onChange={onFromChanged} />
2626
</div>
2727
<div>-</div>
2828
<div>
29-
<CurrencyInput onChange={onToChanged} />
29+
<CurrencyInput currencyCode="USD" onChange={onToChanged} />
3030
</div>
3131
</div>
3232
</div>
1 Byte
Loading
330 Bytes
Loading
-294 Bytes
Loading
0 Bytes
Loading

0 commit comments

Comments
 (0)