@transferwise/components 0.0.0-experimental-4ed3f9f → 0.0.0-experimental-643f4d2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/build/i18n/en.json +0 -2
  2. package/build/i18n/en.json.js +0 -2
  3. package/build/i18n/en.json.js.map +1 -1
  4. package/build/i18n/en.json.mjs +0 -2
  5. package/build/i18n/en.json.mjs.map +1 -1
  6. package/build/index.js +0 -2
  7. package/build/index.js.map +1 -1
  8. package/build/index.mjs +0 -1
  9. package/build/index.mjs.map +1 -1
  10. package/build/main.css +15 -65
  11. package/build/prompt/InlinePrompt/InlinePrompt.js +0 -7
  12. package/build/prompt/InlinePrompt/InlinePrompt.js.map +1 -1
  13. package/build/prompt/InlinePrompt/InlinePrompt.mjs +1 -8
  14. package/build/prompt/InlinePrompt/InlinePrompt.mjs.map +1 -1
  15. package/build/styles/main.css +15 -65
  16. package/build/styles/moneyInput/MoneyInput.css +8 -0
  17. package/build/styles/prompt/InlinePrompt/InlinePrompt.css +7 -7
  18. package/build/types/index.d.ts +0 -2
  19. package/build/types/index.d.ts.map +1 -1
  20. package/build/types/prompt/InlinePrompt/InlinePrompt.d.ts +2 -3
  21. package/build/types/prompt/InlinePrompt/InlinePrompt.d.ts.map +1 -1
  22. package/build/types/test-utils/index.d.ts +0 -4
  23. package/build/types/test-utils/index.d.ts.map +1 -1
  24. package/package.json +1 -1
  25. package/src/i18n/en.json +0 -2
  26. package/src/index.ts +0 -2
  27. package/src/main.css +15 -65
  28. package/src/main.less +0 -1
  29. package/src/moneyInput/MoneyInput.css +8 -0
  30. package/src/moneyInput/MoneyInput.less +5 -0
  31. package/src/prompt/InlinePrompt/InlinePrompt.css +7 -7
  32. package/src/prompt/InlinePrompt/InlinePrompt.less +7 -7
  33. package/src/prompt/InlinePrompt/InlinePrompt.spec.tsx +0 -6
  34. package/src/prompt/InlinePrompt/InlinePrompt.tsx +2 -12
  35. package/src/ssr.spec.tsx +0 -1
  36. package/build/expressiveMoneyInput/AmountInput.js +0 -281
  37. package/build/expressiveMoneyInput/AmountInput.js.map +0 -1
  38. package/build/expressiveMoneyInput/AmountInput.mjs +0 -279
  39. package/build/expressiveMoneyInput/AmountInput.mjs.map +0 -1
  40. package/build/expressiveMoneyInput/AnimatedNumber.js +0 -50
  41. package/build/expressiveMoneyInput/AnimatedNumber.js.map +0 -1
  42. package/build/expressiveMoneyInput/AnimatedNumber.mjs +0 -48
  43. package/build/expressiveMoneyInput/AnimatedNumber.mjs.map +0 -1
  44. package/build/expressiveMoneyInput/Chevron.js +0 -31
  45. package/build/expressiveMoneyInput/Chevron.js.map +0 -1
  46. package/build/expressiveMoneyInput/Chevron.mjs +0 -29
  47. package/build/expressiveMoneyInput/Chevron.mjs.map +0 -1
  48. package/build/expressiveMoneyInput/CurrencySelector.js +0 -160
  49. package/build/expressiveMoneyInput/CurrencySelector.js.map +0 -1
  50. package/build/expressiveMoneyInput/CurrencySelector.mjs +0 -157
  51. package/build/expressiveMoneyInput/CurrencySelector.mjs.map +0 -1
  52. package/build/expressiveMoneyInput/ExpressiveMoneyInput.js +0 -114
  53. package/build/expressiveMoneyInput/ExpressiveMoneyInput.js.map +0 -1
  54. package/build/expressiveMoneyInput/ExpressiveMoneyInput.messages.js +0 -17
  55. package/build/expressiveMoneyInput/ExpressiveMoneyInput.messages.js.map +0 -1
  56. package/build/expressiveMoneyInput/ExpressiveMoneyInput.messages.mjs +0 -13
  57. package/build/expressiveMoneyInput/ExpressiveMoneyInput.messages.mjs.map +0 -1
  58. package/build/expressiveMoneyInput/ExpressiveMoneyInput.mjs +0 -110
  59. package/build/expressiveMoneyInput/ExpressiveMoneyInput.mjs.map +0 -1
  60. package/build/expressiveMoneyInput/useFocus.js +0 -37
  61. package/build/expressiveMoneyInput/useFocus.js.map +0 -1
  62. package/build/expressiveMoneyInput/useFocus.mjs +0 -35
  63. package/build/expressiveMoneyInput/useFocus.mjs.map +0 -1
  64. package/build/expressiveMoneyInput/useInputStyle.js +0 -71
  65. package/build/expressiveMoneyInput/useInputStyle.js.map +0 -1
  66. package/build/expressiveMoneyInput/useInputStyle.mjs +0 -69
  67. package/build/expressiveMoneyInput/useInputStyle.mjs.map +0 -1
  68. package/build/expressiveMoneyInput/utils.js +0 -87
  69. package/build/expressiveMoneyInput/utils.js.map +0 -1
  70. package/build/expressiveMoneyInput/utils.mjs +0 -78
  71. package/build/expressiveMoneyInput/utils.mjs.map +0 -1
  72. package/build/styles/expressiveMoneyInput/AmountInput.css +0 -32
  73. package/build/styles/expressiveMoneyInput/Chevron.css +0 -12
  74. package/build/styles/expressiveMoneyInput/CurrencySelector.css +0 -6
  75. package/build/styles/expressiveMoneyInput/ExpressiveMoneyInput.css +0 -58
  76. package/build/types/expressiveMoneyInput/AmountInput.d.ts +0 -13
  77. package/build/types/expressiveMoneyInput/AmountInput.d.ts.map +0 -1
  78. package/build/types/expressiveMoneyInput/AnimatedNumber.d.ts +0 -9
  79. package/build/types/expressiveMoneyInput/AnimatedNumber.d.ts.map +0 -1
  80. package/build/types/expressiveMoneyInput/Chevron.d.ts +0 -6
  81. package/build/types/expressiveMoneyInput/Chevron.d.ts.map +0 -1
  82. package/build/types/expressiveMoneyInput/CurrencySelector.d.ts +0 -30
  83. package/build/types/expressiveMoneyInput/CurrencySelector.d.ts.map +0 -1
  84. package/build/types/expressiveMoneyInput/ExpressiveMoneyInput.d.ts +0 -33
  85. package/build/types/expressiveMoneyInput/ExpressiveMoneyInput.d.ts.map +0 -1
  86. package/build/types/expressiveMoneyInput/ExpressiveMoneyInput.messages.d.ts +0 -12
  87. package/build/types/expressiveMoneyInput/ExpressiveMoneyInput.messages.d.ts.map +0 -1
  88. package/build/types/expressiveMoneyInput/index.d.ts +0 -3
  89. package/build/types/expressiveMoneyInput/index.d.ts.map +0 -1
  90. package/build/types/expressiveMoneyInput/useFocus.d.ts +0 -7
  91. package/build/types/expressiveMoneyInput/useFocus.d.ts.map +0 -1
  92. package/build/types/expressiveMoneyInput/useInputStyle.d.ts +0 -10
  93. package/build/types/expressiveMoneyInput/useInputStyle.d.ts.map +0 -1
  94. package/build/types/expressiveMoneyInput/useSelectionRange.d.ts +0 -10
  95. package/build/types/expressiveMoneyInput/useSelectionRange.d.ts.map +0 -1
  96. package/build/types/expressiveMoneyInput/utils.d.ts +0 -22
  97. package/build/types/expressiveMoneyInput/utils.d.ts.map +0 -1
  98. package/src/expressiveMoneyInput/AmountInput.css +0 -32
  99. package/src/expressiveMoneyInput/AmountInput.less +0 -43
  100. package/src/expressiveMoneyInput/AmountInput.tsx +0 -353
  101. package/src/expressiveMoneyInput/AnimatedNumber.tsx +0 -40
  102. package/src/expressiveMoneyInput/Chevron.css +0 -12
  103. package/src/expressiveMoneyInput/Chevron.less +0 -13
  104. package/src/expressiveMoneyInput/Chevron.tsx +0 -35
  105. package/src/expressiveMoneyInput/CurrencySelector.css +0 -6
  106. package/src/expressiveMoneyInput/CurrencySelector.less +0 -7
  107. package/src/expressiveMoneyInput/CurrencySelector.tsx +0 -218
  108. package/src/expressiveMoneyInput/ExpressiveMoneyInput.css +0 -58
  109. package/src/expressiveMoneyInput/ExpressiveMoneyInput.less +0 -13
  110. package/src/expressiveMoneyInput/ExpressiveMoneyInput.messages.ts +0 -13
  111. package/src/expressiveMoneyInput/ExpressiveMoneyInput.story.tsx +0 -290
  112. package/src/expressiveMoneyInput/ExpressiveMoneyInput.tsx +0 -118
  113. package/src/expressiveMoneyInput/index.ts +0 -2
  114. package/src/expressiveMoneyInput/useFocus.ts +0 -35
  115. package/src/expressiveMoneyInput/useInputStyle.ts +0 -85
  116. package/src/expressiveMoneyInput/useSelectionRange.ts +0 -23
  117. package/src/expressiveMoneyInput/utils.spec.ts +0 -114
  118. package/src/expressiveMoneyInput/utils.ts +0 -116
  119. package/src/prompt/InlinePrompt/InlinePrompt.story.tsx +0 -57
@@ -1,118 +0,0 @@
1
- import Body from '../body';
2
- import { Label } from '../label/Label';
3
- import { clsx } from 'clsx';
4
- import { AnimatePresence, motion } from 'framer-motion';
5
- import { useId, type ReactNode } from 'react';
6
-
7
- import { type Props as CurrencySelectorProps, CurrencySelector } from './CurrencySelector';
8
- import { CommonProps } from '../common';
9
- import { AmountInput } from './AmountInput';
10
- import { Chevron } from './Chevron';
11
- import { InlinePrompt, type InlinePromptProps } from '../prompt/InlinePrompt';
12
-
13
- type AmountType = number | null;
14
- export type CurrencyType = string;
15
-
16
- type DefaultCurrencySelectorInstanceType = Pick<
17
- CurrencySelectorProps,
18
- 'addons' | 'options' | 'onChange' | 'onOpen' | 'onSearchChange'
19
- >;
20
- type CustomCurrencySelectorInstanceType = {
21
- customRender?: (props: { id: string; labelId: string }) => ReactNode;
22
- };
23
- type CurrencySelectorType = DefaultCurrencySelectorInstanceType &
24
- CustomCurrencySelectorInstanceType;
25
-
26
- export type Props = {
27
- label?: ReactNode;
28
- currencySelector?: CurrencySelectorType;
29
- amount?: AmountType;
30
- currency: CurrencyType;
31
- inlinePrompt?: {
32
- sentiment?: InlinePromptProps['sentiment'];
33
- message: InlinePromptProps['children'];
34
- media?: InlinePromptProps['media'];
35
- };
36
- showChevron?: boolean;
37
- autoFocus?: boolean;
38
- loading?: boolean;
39
- onAmountChange: (amount: AmountType) => void;
40
- onFocusChange?: (focused: boolean) => void;
41
- } & CommonProps;
42
-
43
- export default function ExpressiveMoneyInput({
44
- label,
45
- currency,
46
- currencySelector = { options: [] } as DefaultCurrencySelectorInstanceType,
47
- amount,
48
- onAmountChange,
49
- className,
50
- inlinePrompt,
51
- showChevron,
52
- autoFocus,
53
- loading,
54
- onFocusChange,
55
- }: Props) {
56
- const inputId = useId();
57
- const labelId = useId();
58
- const customAlertId = useId();
59
- const currencyId = useId();
60
-
61
- const selector = currencySelector.customRender?.({ id: currencyId, labelId }) ?? (
62
- <CurrencySelector id={currencyId} labelId={labelId} currency={currency} {...currencySelector} />
63
- );
64
-
65
- return (
66
- <div className={clsx('wds-expressive-money-input', className)}>
67
- <Label id={labelId} htmlFor={inputId} className={clsx('m-b-1', 'font-weight-normal')}>
68
- {label}
69
- </Label>
70
- <div
71
- className={clsx('d-flex')}
72
- role="group"
73
- aria-labelledby={labelId}
74
- {...(inlinePrompt ? { 'aria-describedby': customAlertId } : {})}
75
- >
76
- <div className="wds-expressive-money-input-currency-selector">{selector}</div>
77
- <AmountInput
78
- id={inputId}
79
- describedById={currencyId}
80
- amount={amount}
81
- currency={currency}
82
- // eslint-disable-next-line jsx-a11y/no-autofocus
83
- autoFocus={autoFocus}
84
- loading={loading}
85
- onChange={onAmountChange}
86
- onFocusChange={onFocusChange}
87
- />
88
- <div className={clsx('d-flex align-items-center', 'wds-expressive-money-input-chevron')}>
89
- <Chevron shouldShow={Boolean(showChevron)} />
90
- </div>
91
- </div>
92
- <AnimatePresence initial={false}>
93
- {inlinePrompt && (
94
- <div className={clsx('d-flex justify-content-end', inlinePrompt && 'm-t-1')}>
95
- <motion.div
96
- key={customAlertId}
97
- initial={{ opacity: 0, height: 0 }}
98
- animate={{
99
- opacity: 1,
100
- height: 'auto',
101
- transition: { delay: 0.75, duration: 0.3 },
102
- }}
103
- exit={{ opacity: 0, height: 0 }}
104
- >
105
- {inlinePrompt.sentiment ? (
106
- <InlinePrompt id={customAlertId} media={inlinePrompt.media} sentiment={inlinePrompt.sentiment}>
107
- {inlinePrompt.message}
108
- </InlinePrompt>
109
- ) : (
110
- <Body>{inlinePrompt.message}</Body>
111
- )}
112
- </motion.div>
113
- </div>
114
- )}
115
- </AnimatePresence>
116
- </div>
117
- );
118
- }
@@ -1,2 +0,0 @@
1
- export type { Props as ExpressiveMoneyInputProps } from './ExpressiveMoneyInput';
2
- export { default } from './ExpressiveMoneyInput';
@@ -1,35 +0,0 @@
1
- import { useEffect, useState } from 'react';
2
-
3
- const focusTimeout = 5 * 1000;
4
-
5
- export const useFocus = () => {
6
- const [focus, setFocus] = useState(false);
7
- const [visualFocus, setVisualFocus] = useState(false);
8
- const [counter, setCounter] = useState(0);
9
-
10
- useEffect(() => {
11
- if (focus) {
12
- const timeout = setTimeout(() => {
13
- setVisualFocus(false);
14
- }, focusTimeout);
15
- return () => clearTimeout(timeout);
16
- }
17
- }, [focus, counter]);
18
-
19
- return {
20
- focus,
21
- setFocus: (value: boolean) => {
22
- setFocus(value);
23
- if (value) {
24
- setVisualFocus(true);
25
- }
26
- // any call to setFocus should reset the timeout, even if the input was already in focus
27
- // updating the counter will trigger the useEffect to reset the timeout
28
- setCounter((prev) => prev + 1);
29
- },
30
- visualFocus,
31
- setVisualFocus: (value: boolean) => {
32
- setVisualFocus(value);
33
- },
34
- };
35
- };
@@ -1,85 +0,0 @@
1
- import { type CSSProperties, useEffect, useLayoutEffect, useState } from 'react';
2
- import { Props as ExpressiveMoneyInputProps } from './ExpressiveMoneyInput';
3
-
4
- type InputStyleObject = {
5
- value: string;
6
- focus: boolean;
7
- inputElement: HTMLInputElement | null;
8
- } & Pick<ExpressiveMoneyInputProps, 'loading'>;
9
-
10
- export const useInputStyle = ({ value, focus, inputElement, loading }: InputStyleObject) => {
11
- const initialRender = !useTimeout(300);
12
- const inputWidth = useFirstDefinedValue(inputElement?.clientWidth, [inputElement, value]);
13
-
14
- const getStyle = (): CSSProperties => {
15
- const fontSize = getFontSize(value, focus, inputWidth);
16
-
17
- return {
18
- fontSize,
19
- height: fontSize,
20
- // aligns the top of the digit with the currency button
21
- marginTop: fontSize * -0.19,
22
- // if the input loads with a pre-filled value, we don't want to animate the font-size immediately
23
- transition: initialRender ? 'none' : undefined,
24
- color: loading ? 'var(--color-interactive-secondary)' : undefined,
25
- };
26
- };
27
-
28
- const [style, setStyle] = useState(getStyle());
29
-
30
- useLayoutEffect(() => {
31
- setStyle(getStyle());
32
- }, [value, focus, loading, inputWidth]);
33
-
34
- return style;
35
- };
36
-
37
- function getFontSize(inputValue: string, isFocused: boolean, inputWidth: number | undefined) {
38
- const defaultFontSize = 52;
39
- const focusFontSize = 90;
40
- const minimumFontSize = 34;
41
-
42
- let fontSize = isFocused ? focusFontSize : defaultFontSize;
43
-
44
- if (typeof inputWidth === 'undefined') {
45
- return fontSize;
46
- }
47
- const textLength = inputValue.length;
48
- const maxCharactersWithoutShrinking = Math.floor(inputWidth / 40);
49
-
50
- if (textLength > maxCharactersWithoutShrinking) {
51
- const adjustedSize = Math.round((inputWidth / textLength) * 1.9);
52
- fontSize = Math.min(fontSize, adjustedSize);
53
- }
54
-
55
- return Math.max(fontSize, minimumFontSize);
56
- }
57
-
58
- const useFirstDefinedValue = (newValue: number | undefined, dependencies: unknown[]) => {
59
- const [value, setValue] = useState<number | undefined>(newValue);
60
-
61
- useLayoutEffect(() => {
62
- if (typeof newValue !== 'undefined' && typeof value === 'undefined') {
63
- setValue(newValue);
64
- }
65
- // eslint-disable-next-line react-hooks/exhaustive-deps
66
- }, [...dependencies, value]);
67
-
68
- return value;
69
- };
70
-
71
- const useTimeout = (delay: number) => {
72
- const [ready, setReady] = useState(false);
73
-
74
- useEffect(() => {
75
- const timeout = setTimeout(() => {
76
- setReady(true);
77
- }, delay);
78
-
79
- return () => {
80
- clearTimeout(timeout);
81
- };
82
- }, [delay]);
83
-
84
- return ready;
85
- };
@@ -1,23 +0,0 @@
1
- import { type SyntheticEvent, useRef } from 'react';
2
-
3
- export const useSelectionRange = () => {
4
- const selection = useRef<{
5
- selectionStart: number | null;
6
- selectionEnd: number | null;
7
- }>();
8
-
9
- const handleSelect = (e: SyntheticEvent<HTMLInputElement>) => {
10
- const input = e.target as HTMLInputElement;
11
- const { selectionStart, selectionEnd } = input;
12
- selection.current = { selectionStart, selectionEnd };
13
- };
14
- const handleSelectionBlur = () => {
15
- selection.current = undefined;
16
- };
17
-
18
- return {
19
- selection: selection.current,
20
- handleSelect,
21
- handleSelectionBlur,
22
- };
23
- };
@@ -1,114 +0,0 @@
1
- import {
2
- getDecimalSeparator,
3
- getFormattedString,
4
- getGroupSeparator,
5
- getUnformattedNumber,
6
- } from './utils';
7
-
8
- describe('utils', () => {
9
- describe('getDecimalSeparator', () => {
10
- it('gets decimal separator for Spanish', () => {
11
- expect(getDecimalSeparator('EUR', 'es')).toBe(',');
12
- });
13
-
14
- it('gets decimal separator for English', () => {
15
- expect(getDecimalSeparator('EUR', 'en')).toBe('.');
16
- });
17
-
18
- it('gets decimal separator for Spanish in HUF', () => {
19
- expect(getDecimalSeparator('HUF', 'es')).toBe('');
20
- });
21
-
22
- it('gets decimal separator for English in HUF', () => {
23
- expect(getDecimalSeparator('HUF', 'en')).toBe('');
24
- });
25
- });
26
-
27
- describe('getGroupSeparator', () => {
28
- it('gets group separator for Spanish', () => {
29
- expect(getGroupSeparator('EUR', 'es')).toBe('.');
30
- });
31
-
32
- it('gets group separator for English', () => {
33
- expect(getGroupSeparator('EUR', 'en')).toBe(',');
34
- });
35
-
36
- it('gets group separator for French', () => {
37
- expect(getGroupSeparator('EUR', 'fr')).toBe(' ');
38
- });
39
- });
40
-
41
- describe('getUnformattedNumber', () => {
42
- it('can turn a Spanish string into a number', () => {
43
- expect(
44
- getUnformattedNumber({
45
- value: '123.456,00',
46
- currency: 'EUR',
47
- locale: 'es',
48
- }),
49
- ).toBe(123456);
50
- });
51
-
52
- it('can turn a French string into a number', () => {
53
- expect(
54
- getUnformattedNumber({
55
- value: '1 234 567,45',
56
- currency: 'EUR',
57
- locale: 'fr',
58
- }),
59
- ).toBe(1234567.45);
60
- });
61
-
62
- it('can turn a English string into a number', () => {
63
- expect(
64
- getUnformattedNumber({
65
- value: '123,456.78',
66
- currency: 'EUR',
67
- locale: 'en',
68
- }),
69
- ).toBe(123456.78);
70
- });
71
-
72
- it('can turn a Magyar string into a number', () => {
73
- expect(
74
- getUnformattedNumber({
75
- value: '11 000 000',
76
- currency: 'HUF',
77
- locale: 'hu',
78
- }),
79
- ).toBe(11000000);
80
- });
81
- });
82
-
83
- describe('getFormattedString', () => {
84
- it('can turn a number into a Spanish string', () => {
85
- expect(
86
- getFormattedString({
87
- value: 123456.45,
88
- currency: 'EUR',
89
- locale: 'es',
90
- }),
91
- ).toBe('123.456,45');
92
- });
93
-
94
- it('can turn a number into a French string', () => {
95
- expect(
96
- getFormattedString({
97
- value: 1234567.45,
98
- currency: 'EUR',
99
- locale: 'fr',
100
- }),
101
- ).toBe('1 234 567,45');
102
- });
103
-
104
- it('can turn a number into a English string', () => {
105
- expect(
106
- getFormattedString({
107
- value: 123456.78,
108
- currency: 'EUR',
109
- locale: 'en',
110
- }),
111
- ).toBe('123,456.78');
112
- });
113
- });
114
- });
@@ -1,116 +0,0 @@
1
- import { formatAmount } from '@transferwise/formatting';
2
- import type { KeyboardEvent } from 'react';
3
-
4
- export const getDecimalSeparator = (currency: string, locale: string): string | null => {
5
- return formatAmount(1.1, currency, locale).replace(/\p{Number}/gu, '');
6
- };
7
-
8
- export const getGroupSeparator = (currency: string, locale: string): string | null => {
9
- return formatAmount(10000000, currency, locale).replace(/\p{Number}/gu, '')[0];
10
- };
11
-
12
- export const getDecimalCount = (currency: string, locale: string): number => {
13
- const decimalSeparator = getDecimalSeparator(currency, locale);
14
- if (!decimalSeparator) {
15
- return 0;
16
- }
17
- const parts = formatAmount(1.1, currency, locale).split(decimalSeparator);
18
- return parts.length === 2 ? parts[1].length : 0;
19
- };
20
-
21
- export const getEnteredDecimalsCount = (value: string, decimalSeparator: string) => {
22
- return value.split(decimalSeparator)[1]?.length ?? 0;
23
- };
24
-
25
- export const getUnformattedNumber = ({
26
- value: formattedValue,
27
- currency,
28
- locale,
29
- }: {
30
- value: string;
31
- currency: string;
32
- locale: string;
33
- }): number | null => {
34
- const groupSeparator = getGroupSeparator(currency, locale);
35
- const decimalSeparator = getDecimalSeparator(currency, locale);
36
- if (!formattedValue) {
37
- return null;
38
- }
39
-
40
- // parseFloat can't handle thousands separators
41
- const withoutGroupSeparator = groupSeparator
42
- ? formattedValue.replace(/ /gu, '').replace(new RegExp(`\\${groupSeparator}`, 'g'), '')
43
- : formattedValue;
44
-
45
- // parseFloat can only handle . as decimal separator
46
- const withNormalisedDecimalSeparator = decimalSeparator
47
- ? withoutGroupSeparator.replace(decimalSeparator, '.')
48
- : withoutGroupSeparator;
49
-
50
- const parsedValue = Number.parseFloat(withNormalisedDecimalSeparator);
51
- return parsedValue;
52
- };
53
-
54
- export const getFormattedString = ({
55
- value: unformattedValue,
56
- currency,
57
- locale,
58
- alwaysShowDecimals = false,
59
- }: {
60
- value: number;
61
- currency: string;
62
- locale: string;
63
- alwaysShowDecimals?: boolean;
64
- }): string => {
65
- const decimalSeparator = getDecimalSeparator(currency, locale);
66
- // formatAmount rounds extra decimals, so 1.999 will become 2. Instead we will manually strip extra decimals so that it becomes 1.99 after formatting
67
- const decimalCount = getDecimalCount(currency, locale);
68
- const unformattedString = unformattedValue.toString();
69
-
70
- const [integerPart, decimalPart] = decimalSeparator
71
- ? unformattedString.split(decimalSeparator)
72
- : [unformattedString, undefined];
73
-
74
- const formattedDecimalPart = decimalPart ? decimalPart.slice(0, decimalCount) : '';
75
-
76
- const sanitisedUnformattedValue = Number.parseFloat(`${integerPart}.${formattedDecimalPart}`);
77
-
78
- return formatAmount(sanitisedUnformattedValue, currency, locale, {
79
- alwaysShowDecimals,
80
- });
81
- };
82
-
83
- export const isInputPossiblyOverflowing = ({
84
- ref,
85
- value,
86
- }: {
87
- ref: React.RefObject<HTMLInputElement>;
88
- value: string;
89
- }) => {
90
- const textLength = value.length;
91
- const inputWidth = ref.current?.clientWidth;
92
- if (!inputWidth || !textLength) {
93
- return;
94
- }
95
-
96
- const maxCharactersWithoutOverflow = Math.floor(inputWidth / 19);
97
- return textLength > maxCharactersWithoutOverflow;
98
- };
99
-
100
- const allowedInputKeys = new Set([
101
- 'Backspace',
102
- 'Delete',
103
- ',',
104
- '.',
105
- 'ArrowLeft',
106
- 'ArrowRight',
107
- 'Enter',
108
- 'Tab',
109
- ]);
110
-
111
- export const isAllowedInputKey = (e: KeyboardEvent<HTMLInputElement>) => {
112
- const { metaKey, key, ctrlKey } = e;
113
- const isNumberKey = !Number.isNaN(Number.parseInt(key, 10));
114
-
115
- return isNumberKey || metaKey || ctrlKey || allowedInputKeys.has(key);
116
- };
@@ -1,57 +0,0 @@
1
- import { lorem10, lorem5 } from '../../test-utils';
2
- import { InlinePrompt } from './InlinePrompt';
3
- import { CardWise, Rewards } from '@transferwise/icons';
4
-
5
- export default {
6
- title: 'Internal/InlinePrompt',
7
- component: InlinePrompt,
8
- };
9
-
10
- export const AllVariants = () => {
11
- return (
12
- <div
13
- style={{
14
- display: 'grid',
15
- gridAutoFlow: 'row',
16
- rowGap: 'var(--size-12)',
17
- justifyItems: 'start',
18
- width: 'fit-content',
19
- }}
20
- >
21
- <InlinePrompt sentiment="positive">
22
- {lorem5}
23
- </InlinePrompt>
24
- <InlinePrompt media={<Rewards />} sentiment="positive">
25
- {lorem10}
26
- </InlinePrompt>
27
- <InlinePrompt sentiment="negative">
28
- {lorem5}
29
- </InlinePrompt>
30
- <InlinePrompt sentiment="negative">
31
- {lorem10}
32
- </InlinePrompt>
33
- <InlinePrompt sentiment="neutral">
34
- {lorem5}
35
- </InlinePrompt>
36
- <InlinePrompt sentiment="neutral">
37
- {lorem10}
38
- </InlinePrompt>
39
- <InlinePrompt sentiment="warning">
40
- {lorem5}
41
- </InlinePrompt>
42
- <InlinePrompt sentiment="warning">
43
- {lorem10}
44
- </InlinePrompt>
45
- <InlinePrompt sentiment="proposition">
46
- {lorem5}
47
- </InlinePrompt>
48
- <InlinePrompt sentiment="proposition">
49
- {lorem10}
50
- </InlinePrompt>
51
- <InlinePrompt sentiment="proposition" media={<CardWise />}>
52
- {lorem10}
53
- </InlinePrompt>
54
- <InlinePrompt>{lorem5}</InlinePrompt>
55
- </div>
56
- );
57
- };