@transferwise/components 0.0.0-experimental-47ae02a → 0.0.0-experimental-da6dbbf

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 (89) hide show
  1. package/build/index.js +940 -642
  2. package/build/index.js.map +1 -1
  3. package/build/index.mjs +930 -633
  4. package/build/index.mjs.map +1 -1
  5. package/build/main.css +135 -0
  6. package/build/styles/carousel/Carousel.css +135 -0
  7. package/build/styles/main.css +135 -0
  8. package/build/types/accordion/AccordionItem/AccordionItem.d.ts.map +1 -1
  9. package/build/types/carousel/Carousel.d.ts +26 -0
  10. package/build/types/carousel/Carousel.d.ts.map +1 -0
  11. package/build/types/carousel/index.d.ts +3 -0
  12. package/build/types/carousel/index.d.ts.map +1 -0
  13. package/build/types/common/card/Card.d.ts +2 -2
  14. package/build/types/common/card/Card.d.ts.map +1 -1
  15. package/build/types/common/hooks/useMedia.d.ts.map +1 -1
  16. package/build/types/common/panel/Panel.d.ts.map +1 -1
  17. package/build/types/common/responsivePanel/ResponsivePanel.d.ts.map +1 -1
  18. package/build/types/dimmer/Dimmer.d.ts +11 -1
  19. package/build/types/dimmer/Dimmer.d.ts.map +1 -1
  20. package/build/types/drawer/Drawer.d.ts +4 -4
  21. package/build/types/index.d.ts +4 -3
  22. package/build/types/index.d.ts.map +1 -1
  23. package/build/types/inputWithDisplayFormat/InputWithDisplayFormat.d.ts +1 -2
  24. package/build/types/inputWithDisplayFormat/InputWithDisplayFormat.d.ts.map +1 -1
  25. package/build/types/inputs/SelectInput.d.ts.map +1 -1
  26. package/build/types/modal/Modal.d.ts.map +1 -1
  27. package/build/types/processIndicator/ProcessIndicator.d.ts +19 -36
  28. package/build/types/processIndicator/ProcessIndicator.d.ts.map +1 -1
  29. package/build/types/processIndicator/index.d.ts +2 -2
  30. package/build/types/processIndicator/index.d.ts.map +1 -1
  31. package/build/types/promoCard/PromoCard.d.ts +16 -5
  32. package/build/types/promoCard/PromoCard.d.ts.map +1 -1
  33. package/build/types/select/searchBox/SearchBox.d.ts +1 -1
  34. package/build/types/textareaWithDisplayFormat/TextareaWithDisplayFormat.d.ts +1 -2
  35. package/build/types/textareaWithDisplayFormat/TextareaWithDisplayFormat.d.ts.map +1 -1
  36. package/build/types/tooltip/Tooltip.d.ts +1 -1
  37. package/build/types/tooltip/Tooltip.d.ts.map +1 -1
  38. package/build/types/uploadInput/uploadItem/UploadItem.d.ts.map +1 -1
  39. package/build/types/withDisplayFormat/WithDisplayFormat.d.ts +14 -14
  40. package/build/types/withDisplayFormat/WithDisplayFormat.d.ts.map +1 -1
  41. package/package.json +11 -7
  42. package/src/accordion/AccordionItem/AccordionItem.tsx +4 -2
  43. package/src/avatarWrapper/AvatarWrapper.story.tsx +3 -1
  44. package/src/button/Button.tsx +1 -1
  45. package/src/carousel/Carousel.css +135 -0
  46. package/src/carousel/Carousel.less +133 -0
  47. package/src/carousel/Carousel.spec.tsx +221 -0
  48. package/src/carousel/Carousel.story.tsx +63 -0
  49. package/src/carousel/Carousel.tsx +345 -0
  50. package/src/carousel/index.ts +3 -0
  51. package/src/common/card/Card.tsx +51 -43
  52. package/src/common/hooks/useConditionalListener/useConditionalListener.spec.js +1 -1
  53. package/src/common/hooks/useHasIntersected/useHasIntersected.spec.js +3 -3
  54. package/src/common/hooks/useMedia.spec.ts +1 -1
  55. package/src/common/hooks/useMedia.ts +2 -1
  56. package/src/common/panel/Panel.tsx +92 -90
  57. package/src/common/responsivePanel/ResponsivePanel.tsx +38 -34
  58. package/src/dateLookup/DateLookup.keyboardEvents.spec.js +180 -0
  59. package/src/dateLookup/DateLookup.rtl.spec.tsx +5 -181
  60. package/src/dateLookup/DateLookup.testingLibrary.spec.js +124 -171
  61. package/src/drawer/Drawer.js +3 -3
  62. package/src/field/Field.tsx +3 -3
  63. package/src/index.ts +4 -3
  64. package/src/inputWithDisplayFormat/InputWithDisplayFormat.tsx +1 -2
  65. package/src/inputs/SelectInput.story.tsx +0 -1
  66. package/src/inputs/SelectInput.tsx +2 -10
  67. package/src/main.css +135 -0
  68. package/src/main.less +1 -0
  69. package/src/modal/Modal.tsx +2 -1
  70. package/src/processIndicator/ProcessIndicator.js +117 -0
  71. package/src/processIndicator/ProcessIndicator.spec.js +101 -0
  72. package/src/promoCard/PromoCard.story.tsx +2 -2
  73. package/src/promoCard/PromoCard.tsx +31 -9
  74. package/src/radio/__snapshots__/Radio.rtl.spec.tsx.snap +1 -0
  75. package/src/snackbar/Snackbar.spec.js +1 -4
  76. package/src/tabs/Tabs.spec.js +27 -46
  77. package/src/test-utils/index.js +7 -5
  78. package/src/test-utils/jest.setup.js +3 -9
  79. package/src/textareaWithDisplayFormat/TextareaWithDisplayFormat.tsx +1 -2
  80. package/src/tooltip/Tooltip.tsx +46 -44
  81. package/src/tooltip/__snapshots__/Tooltip.spec.tsx.snap +2 -2
  82. package/src/upload/Upload.spec.js +13 -34
  83. package/src/uploadInput/UploadInput.spec.tsx +23 -21
  84. package/src/uploadInput/uploadItem/UploadItem.tsx +3 -1
  85. package/src/withDisplayFormat/WithDisplayFormat.spec.js +32 -63
  86. package/src/withDisplayFormat/WithDisplayFormat.tsx +28 -28
  87. package/src/processIndicator/ProcessIndicator.rtl.spec.tsx +0 -45
  88. package/src/processIndicator/ProcessIndicator.tsx +0 -110
  89. /package/src/processIndicator/{index.ts → index.js} +0 -0
@@ -25,12 +25,12 @@ export type EventType =
25
25
  | 'Delete'
26
26
  | 'Initial';
27
27
 
28
- interface WithDisplayFormatState<T extends HTMLTextElement> {
28
+ interface WithDisplayFormatState {
29
29
  value: string;
30
30
  historyNavigator: HistoryNavigator;
31
31
  prevDisplayPattern: string;
32
32
  triggerType: EventType;
33
- triggerEvent: React.KeyboardEvent<T> | null;
33
+ triggerEvent: React.KeyboardEvent<HTMLTextElement> | null;
34
34
  pastedLength: number;
35
35
  selectionStart: number;
36
36
  selectionEnd: number;
@@ -38,7 +38,7 @@ interface WithDisplayFormatState<T extends HTMLTextElement> {
38
38
 
39
39
  export interface WithDisplayFormatProps<T extends TextElementProps = TextElementProps>
40
40
  extends Pick<
41
- T,
41
+ TextElementProps,
42
42
  | 'className'
43
43
  | 'disabled'
44
44
  | 'id'
@@ -64,21 +64,19 @@ export interface WithDisplayFormatProps<T extends TextElementProps = TextElement
64
64
  render: (renderProps: T) => JSX.Element;
65
65
  }
66
66
 
67
- class WithDisplayFormat<
68
- T extends TextElementProps = TextElementProps,
69
- U extends HTMLTextElement = HTMLTextElement,
70
- > extends Component<WithDisplayFormatProps<T>, WithDisplayFormatState<U>> {
67
+ class WithDisplayFormat<T extends TextElementProps> extends Component<
68
+ WithDisplayFormatProps<T>,
69
+ WithDisplayFormatState
70
+ > {
71
71
  declare props: WithDisplayFormatProps<T> &
72
- Required<
73
- Pick<WithDisplayFormatProps<T>, keyof (typeof WithDisplayFormat<T, U>)['defaultProps']>
74
- >;
72
+ Required<Pick<WithDisplayFormatProps<T>, keyof typeof WithDisplayFormat.defaultProps>>;
75
73
  static defaultProps = {
76
74
  autoComplete: 'off',
77
75
  displayPattern: '',
78
76
  value: '',
79
- } satisfies Partial<WithDisplayFormatProps>;
77
+ };
80
78
 
81
- constructor(props: WithDisplayFormat<T, U>['props']) {
79
+ constructor(props: WithDisplayFormatProps) {
82
80
  super(props);
83
81
  const unformattedValue = unformatWithPattern(props.value ?? '', props.displayPattern);
84
82
  this.state = {
@@ -94,8 +92,8 @@ class WithDisplayFormat<
94
92
  }
95
93
 
96
94
  static getDerivedStateFromProps(
97
- { displayPattern }: WithDisplayFormat['props'],
98
- { prevDisplayPattern = displayPattern, value, historyNavigator }: WithDisplayFormat['state'],
95
+ { displayPattern }: WithDisplayFormatProps,
96
+ { prevDisplayPattern = displayPattern, value, historyNavigator }: WithDisplayFormatState,
99
97
  ) {
100
98
  if (prevDisplayPattern !== displayPattern) {
101
99
  const unFormattedValue = unformatWithPattern(value, prevDisplayPattern);
@@ -139,9 +137,10 @@ class WithDisplayFormat<
139
137
  return 'Backspace';
140
138
  }
141
139
  return triggerEvent.key;
140
+ } else {
141
+ // triggerEvent can be null only in case of "autofilling" (via password manager extension or browser build-in one) events
142
+ return 'Paste';
142
143
  }
143
- // triggerEvent can be null only in case of "autofilling" (via password manager extension or browser build-in one) events
144
- return 'Paste';
145
144
  };
146
145
 
147
146
  resetEvent = () => {
@@ -152,7 +151,7 @@ class WithDisplayFormat<
152
151
  });
153
152
  };
154
153
 
155
- detectUndoRedo = (event: React.KeyboardEvent<U>) => {
154
+ detectUndoRedo = (event: React.KeyboardEvent<HTMLTextElement>) => {
156
155
  const charCode = String.fromCharCode(event.which).toLowerCase();
157
156
  if ((event.ctrlKey || event.metaKey) && charCode === 'z') {
158
157
  return event.shiftKey ? 'Redo' : 'Undo';
@@ -160,7 +159,7 @@ class WithDisplayFormat<
160
159
  return null;
161
160
  };
162
161
 
163
- handleOnKeyDown: React.KeyboardEventHandler<U> = (event) => {
162
+ handleOnKeyDown: React.KeyboardEventHandler<HTMLTextElement> = (event) => {
164
163
  event.persist();
165
164
  const { selectionStart, selectionEnd } = event.currentTarget;
166
165
  const { historyNavigator } = this.state;
@@ -185,7 +184,7 @@ class WithDisplayFormat<
185
184
  }
186
185
  };
187
186
 
188
- handleOnPaste: React.ClipboardEventHandler<U> = (event) => {
187
+ handleOnPaste: React.ClipboardEventHandler<HTMLTextElement> = (event) => {
189
188
  const { displayPattern } = this.props;
190
189
  const pastedLength = unformatWithPattern(
191
190
  event.clipboardData.getData('Text'),
@@ -195,7 +194,7 @@ class WithDisplayFormat<
195
194
  this.setState({ triggerType: 'Paste', pastedLength });
196
195
  };
197
196
 
198
- handleOnCut: React.ClipboardEventHandler<U> = () => {
197
+ handleOnCut: React.ClipboardEventHandler<HTMLTextElement> = () => {
199
198
  this.setState({ triggerType: 'Cut' });
200
199
  };
201
200
 
@@ -206,7 +205,7 @@ class WithDisplayFormat<
206
205
  return !symbolsInPattern.includes(action);
207
206
  };
208
207
 
209
- handleOnChange: React.ChangeEventHandler<U> = (event) => {
208
+ handleOnChange: React.ChangeEventHandler<HTMLTextElement> = (event) => {
210
209
  const { historyNavigator, triggerType } = this.state;
211
210
  const { displayPattern, onChange } = this.props;
212
211
  const { value } = event.target;
@@ -234,11 +233,11 @@ class WithDisplayFormat<
234
233
  });
235
234
  };
236
235
 
237
- handleOnBlur: React.FocusEventHandler<U> = (event) => {
236
+ handleOnBlur: React.FocusEventHandler<HTMLTextElement> = (event) => {
238
237
  this.props.onBlur?.(unformatWithPattern(event.target.value, this.props.displayPattern));
239
238
  };
240
239
 
241
- handleOnFocus: React.FocusEventHandler<U> = (event) => {
240
+ handleOnFocus: React.FocusEventHandler<HTMLTextElement> = (event) => {
242
241
  const { displayPattern, onFocus } = this.props;
243
242
  if (onFocus) {
244
243
  this.handleOnChange(event);
@@ -274,7 +273,6 @@ class WithDisplayFormat<
274
273
  handleCursorPositioning = (action: string) => {
275
274
  const { displayPattern } = this.props;
276
275
  const { triggerEvent, selectionStart, selectionEnd, pastedLength } = this.state;
277
- const target = triggerEvent?.currentTarget;
278
276
 
279
277
  const cursorPosition = getCursorPositionAfterKeystroke(
280
278
  action,
@@ -285,7 +283,9 @@ class WithDisplayFormat<
285
283
  );
286
284
 
287
285
  setTimeout(() => {
288
- target?.setSelectionRange(cursorPosition, cursorPosition);
286
+ if (triggerEvent) {
287
+ (triggerEvent.target as HTMLTextElement).setSelectionRange(cursorPosition, cursorPosition);
288
+ }
289
289
  this.setState({ selectionStart: cursorPosition, selectionEnd: cursorPosition });
290
290
  }, 0);
291
291
  };
@@ -305,7 +305,7 @@ class WithDisplayFormat<
305
305
  autoComplete,
306
306
  } = this.props;
307
307
  const { value } = this.state;
308
- const renderProps = {
308
+ const renderProps: TextElementProps = {
309
309
  inputMode,
310
310
  className,
311
311
  id,
@@ -324,8 +324,8 @@ class WithDisplayFormat<
324
324
  onKeyDown: this.handleOnKeyDown,
325
325
  onChange: this.handleOnChange,
326
326
  onCut: this.handleOnCut,
327
- } as T;
328
- return this.props.render(renderProps);
327
+ };
328
+ return this.props.render(renderProps as T);
329
329
  }
330
330
  }
331
331
 
@@ -1,45 +0,0 @@
1
- import { act } from 'react';
2
-
3
- import { render, screen } from '../test-utils';
4
- import ProcessIndicator, { ProcessIndicatorProps } from './ProcessIndicator';
5
-
6
- describe('ProcessIndicator', () => {
7
- beforeEach(() => {
8
- jest.useFakeTimers();
9
- });
10
-
11
- afterEach(async () => {
12
- await jest.runOnlyPendingTimersAsync();
13
- jest.useRealTimers();
14
- });
15
-
16
- it('supports transitioning between states', async () => {
17
- const handleAnimationCompleted = jest.fn();
18
- const initialProps = {
19
- 'data-testid': 'process-indicator',
20
- onAnimationCompleted: handleAnimationCompleted,
21
- } satisfies ProcessIndicatorProps;
22
- const view = render(<ProcessIndicator {...initialProps} />);
23
-
24
- expect(screen.getByTestId('process-indicator')).not.toHaveClass('process-success');
25
- expect(screen.getByTestId('process-indicator')).not.toHaveClass('process-xl');
26
-
27
- const updatedProps = {
28
- status: 'succeeded',
29
- size: 'xl',
30
- } satisfies ProcessIndicatorProps;
31
- view.rerender(<ProcessIndicator {...initialProps} {...updatedProps} />);
32
- await act(async () => {
33
- await jest.runOnlyPendingTimersAsync();
34
- });
35
-
36
- expect(screen.getByTestId('process-indicator')).toHaveClass('process-success');
37
- expect(screen.getByTestId('process-indicator')).toHaveClass('process-xl');
38
- expect(handleAnimationCompleted).not.toHaveBeenCalled();
39
-
40
- await jest.runOnlyPendingTimersAsync();
41
-
42
- expect(handleAnimationCompleted).toHaveBeenCalledWith(updatedProps.status);
43
- expect(handleAnimationCompleted).toHaveBeenCalledTimes(1);
44
- });
45
- });
@@ -1,110 +0,0 @@
1
- import classNames from 'classnames';
2
- import { Component } from 'react';
3
-
4
- import { Status, Size } from '../common';
5
-
6
- const radius = { xxs: 6, xs: 11, sm: 22, xl: 61 };
7
-
8
- const ANIMATION_DURATION_IN_MS = 1500;
9
-
10
- type ProcessIndicatorStatus =
11
- `${Status.PROCESSING | Status.FAILED | Status.SUCCEEDED | Status.HIDDEN}`;
12
-
13
- export interface ProcessIndicatorProps {
14
- status?: ProcessIndicatorStatus;
15
- size?: 'xxs' | `${Size.EXTRA_SMALL | Size.SMALL | Size.EXTRA_LARGE}`;
16
- className?: string;
17
- 'data-testid'?: string;
18
- onAnimationCompleted?: (status: ProcessIndicatorStatus) => void;
19
- }
20
-
21
- type ProcessIndicatorState = Required<Pick<ProcessIndicatorProps, 'status' | 'size'>>;
22
-
23
- export default class ProcessIndicator extends Component<
24
- ProcessIndicatorProps,
25
- ProcessIndicatorState
26
- > {
27
- declare props: ProcessIndicatorProps &
28
- Required<Pick<ProcessIndicatorProps, keyof typeof ProcessIndicator.defaultProps>>;
29
-
30
- static defaultProps = {
31
- status: 'processing',
32
- size: 'sm',
33
- } satisfies Partial<ProcessIndicatorProps>;
34
-
35
- interval = 0;
36
- timeout = 0;
37
-
38
- constructor(props: ProcessIndicator['props']) {
39
- super(props);
40
- this.state = {
41
- status: props.status,
42
- size: props.size,
43
- };
44
- }
45
-
46
- /**
47
- * Create interval for animation duration (1500ms)
48
- * Update state only at the end of every interval
49
- * (end of animation loop) if props changed before end of animation
50
- */
51
- componentDidMount() {
52
- this.interval = window.setInterval(() => {
53
- const { status: targetStatus, size: targetSize, onAnimationCompleted } = this.props;
54
- const { status: currentStatus, size: currentSize } = this.state;
55
-
56
- if (currentStatus !== targetStatus) {
57
- this.setState({ status: targetStatus }, () => {
58
- if (onAnimationCompleted) {
59
- this.timeout = window.setTimeout(() => {
60
- onAnimationCompleted(targetStatus);
61
- }, ANIMATION_DURATION_IN_MS);
62
- }
63
- });
64
- }
65
-
66
- if (currentSize !== targetSize) {
67
- this.setState({ size: targetSize });
68
- }
69
- }, ANIMATION_DURATION_IN_MS);
70
- }
71
-
72
- /**
73
- * Only trigger render if comopnent's state got
74
- * updated from interval callback
75
- */
76
- shouldComponentUpdate(nextProps: ProcessIndicator['props'], nextState: ProcessIndicatorState) {
77
- const isSameStatus = nextProps.status === nextState.status;
78
- const isSameSize = nextProps.size === nextState.size;
79
-
80
- return isSameStatus && isSameSize;
81
- }
82
-
83
- // Clear interval before destroying component
84
- componentWillUnmount() {
85
- window.clearInterval(this.interval);
86
- window.clearTimeout(this.timeout);
87
- }
88
-
89
- render() {
90
- const { className, 'data-testid': dataTestId } = this.props;
91
- const { size, status } = this.state;
92
- const classes = classNames(`process process-${size}`, className, {
93
- [`process-danger`]: status === Status.FAILED,
94
- [`process-stopped`]: status === Status.HIDDEN,
95
- [`process-success`]: status === Status.SUCCEEDED,
96
- });
97
-
98
- return (
99
- <span className={classes} data-testid={dataTestId}>
100
- <span className="process-icon-container">
101
- <span className="process-icon-horizontal" />
102
- <span className="process-icon-vertical" />
103
- </span>
104
- <svg xmlns="http://www.w3.org/2000/svg">
105
- <circle className="process-circle" cx="50%" cy="50%" r={radius[size]} fillOpacity="0.0" />
106
- </svg>
107
- </span>
108
- );
109
- }
110
- }
File without changes