@transferwise/components 0.0.0-experimental-1f8ed05 → 0.0.0-experimental-d0bd4b4

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 (48) hide show
  1. package/build/index.esm.js +53 -109
  2. package/build/index.esm.js.map +1 -1
  3. package/build/index.js +54 -110
  4. package/build/index.js.map +1 -1
  5. package/build/types/common/textFormat/formatWithPattern/formatWithPattern.d.ts +1 -1
  6. package/build/types/common/textFormat/formatWithPattern/formatWithPattern.d.ts.map +1 -1
  7. package/build/types/common/textFormat/getCursorPositionAfterKeystroke/getCursorPositionAfterKeystroke.d.ts +2 -1
  8. package/build/types/common/textFormat/getCursorPositionAfterKeystroke/getCursorPositionAfterKeystroke.d.ts.map +1 -1
  9. package/build/types/common/textFormat/getSymbolsInPatternWithPosition/getSymbolsInPatternWithPosition.d.ts +5 -1
  10. package/build/types/common/textFormat/getSymbolsInPatternWithPosition/getSymbolsInPatternWithPosition.d.ts.map +1 -1
  11. package/build/types/common/textFormat/unformatWithPattern/unformatWithPattern.d.ts +1 -1
  12. package/build/types/common/textFormat/unformatWithPattern/unformatWithPattern.d.ts.map +1 -1
  13. package/build/types/index.d.ts +2 -0
  14. package/build/types/index.d.ts.map +1 -1
  15. package/build/types/inputWithDisplayFormat/InputWithDisplayFormat.d.ts +5 -11
  16. package/build/types/inputWithDisplayFormat/InputWithDisplayFormat.d.ts.map +1 -1
  17. package/build/types/inputWithDisplayFormat/index.d.ts +2 -1
  18. package/build/types/inputWithDisplayFormat/index.d.ts.map +1 -1
  19. package/build/types/inputs/Input.d.ts +8 -6
  20. package/build/types/inputs/Input.d.ts.map +1 -1
  21. package/build/types/textareaWithDisplayFormat/TextareaWithDisplayFormat.d.ts +5 -11
  22. package/build/types/textareaWithDisplayFormat/TextareaWithDisplayFormat.d.ts.map +1 -1
  23. package/build/types/textareaWithDisplayFormat/index.d.ts +2 -1
  24. package/build/types/textareaWithDisplayFormat/index.d.ts.map +1 -1
  25. package/build/types/withDisplayFormat/WithDisplayFormat.d.ts +55 -82
  26. package/build/types/withDisplayFormat/WithDisplayFormat.d.ts.map +1 -1
  27. package/build/types/withDisplayFormat/index.d.ts +2 -1
  28. package/build/types/withDisplayFormat/index.d.ts.map +1 -1
  29. package/package.json +1 -1
  30. package/src/common/textFormat/formatWithPattern/{formatWithPattern.js → formatWithPattern.ts} +8 -4
  31. package/src/common/textFormat/getCursorPositionAfterKeystroke/{getCursorPositionAfterKeystroke.js → getCursorPositionAfterKeystroke.ts} +7 -6
  32. package/src/common/textFormat/getSymbolsInPatternWithPosition/{getSymbolsInPatternWithPosition.js → getSymbolsInPatternWithPosition.ts} +7 -2
  33. package/src/common/textFormat/unformatWithPattern/{unformatWithPattern.js → unformatWithPattern.ts} +3 -2
  34. package/src/index.ts +2 -0
  35. package/src/inputWithDisplayFormat/InputWithDisplayFormat.tsx +11 -0
  36. package/src/inputWithDisplayFormat/index.ts +2 -0
  37. package/src/inputs/Input.tsx +6 -11
  38. package/src/textareaWithDisplayFormat/TextareaWithDisplayFormat.spec.js +3 -1
  39. package/src/textareaWithDisplayFormat/TextareaWithDisplayFormat.story.tsx +32 -0
  40. package/src/textareaWithDisplayFormat/TextareaWithDisplayFormat.tsx +11 -0
  41. package/src/textareaWithDisplayFormat/index.ts +2 -0
  42. package/src/withDisplayFormat/{WithDisplayFormat.js → WithDisplayFormat.tsx} +111 -104
  43. package/src/withDisplayFormat/index.ts +2 -0
  44. package/src/inputWithDisplayFormat/InputWithDisplayFormat.js +0 -14
  45. package/src/inputWithDisplayFormat/index.js +0 -1
  46. package/src/textareaWithDisplayFormat/TextareaWithDisplayFormat.js +0 -14
  47. package/src/textareaWithDisplayFormat/index.js +0 -1
  48. package/src/withDisplayFormat/index.js +0 -1
@@ -1,5 +1,4 @@
1
- import PropTypes from 'prop-types';
2
- import { Component } from 'react';
1
+ import { Component, KeyboardEvent, ClipboardEvent, ChangeEvent, FocusEvent } from 'react';
3
2
 
4
3
  import { HistoryNavigator } from '../common';
5
4
  import {
@@ -10,14 +9,65 @@ import {
10
9
  getDistanceToPreviousSymbol,
11
10
  getDistanceToNextSymbol,
12
11
  } from '../common/textFormat';
12
+ import { InputProps } from '../inputs/Input';
13
+ import { TextAreaProps } from '../inputs/TextArea';
14
+ import { Merge } from '../utils';
15
+
16
+ export type TextInputProps = Merge<
17
+ InputProps,
18
+ {
19
+ value?: string;
20
+ displayPattern: string;
21
+ /**
22
+ * autocomplete hides our form help so we need to disable it when help text
23
+ * is present. Chrome ignores autocomplete=off, the only way to disable it is
24
+ * to provide an 'invalid' value, for which 'disabled' serves.
25
+ */
26
+ autoComplete?: InputProps['autoComplete'] | 'disabled';
27
+ onChange?: (value: string) => void;
28
+ onBlur?: (value: string) => void;
29
+ onFocus?: (value: string) => void;
30
+ }
31
+ >;
32
+
33
+ export type Props = typeof WithDisplayFormat.defaultProps & {
34
+ render: (renderProps: InputProps | TextAreaProps) => JSX.Element;
35
+ } & TextInputProps;
36
+
37
+ export type EventType =
38
+ | 'KeyDown'
39
+ | 'Paste'
40
+ | 'Cut'
41
+ | 'Undo'
42
+ | 'Redo'
43
+ | 'Backspace'
44
+ | 'Delete'
45
+ | null;
46
+
47
+ type State = {
48
+ value: string;
49
+ historyNavigator: HistoryNavigator;
50
+ prevDisplayPattern?: string;
51
+ triggerType?: EventType;
52
+ triggerEvent?: KeyboardEvent<HTMLInputElement> | null;
53
+ pastedLength?: number;
54
+ selectionStart?: HTMLInputElement['selectionStart'];
55
+ selectionEnd?: HTMLInputElement['selectionEnd'];
56
+ };
57
+
58
+ class WithDisplayFormat extends Component<Props, State> {
59
+ static defaultProps = {
60
+ autoComplete: 'off',
61
+ displayPattern: '',
62
+ type: 'text',
63
+ value: '',
64
+ };
13
65
 
14
- class WithDisplayFormat extends Component {
15
- constructor(props) {
66
+ constructor(props: Props) {
16
67
  super(props);
17
- const { value, displayPattern } = props;
18
- const unformattedValue = unformatWithPattern(value, displayPattern);
68
+ const unformattedValue = unformatWithPattern(props.value, props.displayPattern);
19
69
  this.state = {
20
- value: formatWithPattern(unformattedValue, displayPattern),
70
+ value: formatWithPattern(unformattedValue, props.displayPattern),
21
71
  historyNavigator: new HistoryNavigator(),
22
72
  prevDisplayPattern: props.displayPattern,
23
73
  triggerType: null,
@@ -25,12 +75,11 @@ class WithDisplayFormat extends Component {
25
75
  };
26
76
  }
27
77
 
28
- static getDerivedStateFromProps(nextProps, previousState) {
29
- const { displayPattern } = nextProps;
30
- const { prevDisplayPattern } = previousState;
31
- if (previousState.prevDisplayPattern !== displayPattern) {
32
- const { value, historyNavigator } = previousState;
33
-
78
+ static getDerivedStateFromProps(
79
+ { displayPattern }: Props,
80
+ { prevDisplayPattern = displayPattern, value, historyNavigator }: State,
81
+ ) {
82
+ if (prevDisplayPattern !== displayPattern) {
34
83
  const unFormattedValue = unformatWithPattern(value, prevDisplayPattern);
35
84
  historyNavigator.reset();
36
85
 
@@ -45,32 +94,37 @@ class WithDisplayFormat extends Component {
45
94
  return null;
46
95
  }
47
96
 
48
- getUserAction = (unformattedValue) => {
97
+ getUserAction = (unformattedValue: string): EventType => {
49
98
  const { triggerEvent, triggerType, value } = this.state;
50
99
  const { displayPattern } = this.props;
51
100
 
52
- const charCode = String.fromCharCode(triggerEvent.which).toLowerCase();
101
+ if (triggerEvent) {
102
+ const charCode = String.fromCharCode(triggerEvent.which).toLowerCase();
53
103
 
54
- if (triggerType === 'Paste' || triggerType === 'Cut') {
55
- return triggerType;
56
- }
104
+ if (triggerType === 'Paste' || triggerType === 'Cut') {
105
+ return triggerType;
106
+ }
57
107
 
58
- if ((triggerEvent.ctrlKey || triggerEvent.metaKey) && charCode === 'z') {
59
- return triggerEvent.shiftKey ? 'Redo' : 'Undo';
60
- }
61
- // Detect mouse event redo
62
- if (triggerEvent.ctrlKey && charCode === 'd') {
63
- return 'Delete';
64
- }
108
+ if ((triggerEvent.ctrlKey || triggerEvent.metaKey) && charCode === 'z') {
109
+ return triggerEvent.shiftKey ? 'Redo' : 'Undo';
110
+ }
111
+ // Detect mouse event redo
112
+ if (triggerEvent.ctrlKey && charCode === 'd') {
113
+ return 'Delete';
114
+ }
65
115
 
66
- // Android Fix.
67
- if (typeof triggerEvent.key === 'undefined') {
68
- if (unformattedValue.length <= unformatWithPattern(value, displayPattern).length) {
116
+ // Android Fix.
117
+ if (
118
+ typeof triggerEvent.key === 'undefined' &&
119
+ unformattedValue.length <= unformatWithPattern(value, displayPattern).length
120
+ ) {
69
121
  return 'Backspace';
70
122
  }
123
+ return triggerEvent.key as EventType;
124
+ } else {
125
+ // triggerEvent can be null only in case of "autofilling" (via password manager extension or browser build-in one) events
126
+ return 'Paste';
71
127
  }
72
-
73
- return triggerEvent.key;
74
128
  };
75
129
 
76
130
  resetEvent = () => {
@@ -81,7 +135,7 @@ class WithDisplayFormat extends Component {
81
135
  });
82
136
  };
83
137
 
84
- detectUndoRedo = (event) => {
138
+ detectUndoRedo = (event: KeyboardEvent<HTMLInputElement>) => {
85
139
  const charCode = String.fromCharCode(event.which).toLowerCase();
86
140
  if ((event.ctrlKey || event.metaKey) && charCode === 'z') {
87
141
  return event.shiftKey ? 'Redo' : 'Undo';
@@ -89,9 +143,9 @@ class WithDisplayFormat extends Component {
89
143
  return null;
90
144
  };
91
145
 
92
- handleOnKeyDown = (event) => {
146
+ handleOnKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {
93
147
  event.persist();
94
- const { selectionStart, selectionEnd } = event.target;
148
+ const { selectionStart, selectionEnd } = event.target as HTMLInputElement;
95
149
  const { historyNavigator } = this.state;
96
150
  const { displayPattern } = this.props;
97
151
 
@@ -114,7 +168,7 @@ class WithDisplayFormat extends Component {
114
168
  }
115
169
  };
116
170
 
117
- handleOnPaste = (event) => {
171
+ handleOnPaste = (event: ClipboardEvent<HTMLInputElement>) => {
118
172
  const { displayPattern } = this.props;
119
173
  const pastedLength = unformatWithPattern(
120
174
  event.clipboardData.getData('Text'),
@@ -128,23 +182,19 @@ class WithDisplayFormat extends Component {
128
182
  this.setState({ triggerType: 'Cut' });
129
183
  };
130
184
 
131
- isKeyAllowed = (action) => {
185
+ isKeyAllowed = (action: EventType) => {
132
186
  const { displayPattern } = this.props;
133
187
  const symbolsInPattern = displayPattern.split('').filter((character) => character !== '*');
134
188
 
135
- return !symbolsInPattern.includes(action);
189
+ return !symbolsInPattern.includes(action as string);
136
190
  };
137
191
 
138
- handleOnChange = (event) => {
139
- const { historyNavigator, triggerEvent, triggerType } = this.state;
192
+ handleOnChange = (event: ChangeEvent<HTMLInputElement>) => {
193
+ const { historyNavigator, triggerType } = this.state;
140
194
  const { displayPattern, onChange } = this.props;
141
195
  const { value } = event.target;
142
196
  let unformattedValue = unformatWithPattern(value, displayPattern);
143
- const action =
144
- triggerEvent === null
145
- ? // triggerEvent can be null only in case of "autofilling" (via password manager extension or browser build-in one) events
146
- 'Paste'
147
- : this.getUserAction(unformattedValue);
197
+ const action = this.getUserAction(unformattedValue);
148
198
  if (!this.isKeyAllowed(action) || triggerType === 'Undo' || triggerType === 'Redo') {
149
199
  return;
150
200
  }
@@ -158,19 +208,20 @@ class WithDisplayFormat extends Component {
158
208
 
159
209
  this.handleCursorPositioning(action);
160
210
 
161
- const broadcastValue = unformatWithPattern(newFormattedValue, displayPattern);
162
-
163
- this.setState({ value: newFormattedValue }, this.resetEvent(), onChange(broadcastValue));
211
+ this.setState({ value: newFormattedValue }, () => {
212
+ this.resetEvent();
213
+ if (onChange) {
214
+ const broadcastValue = unformatWithPattern(newFormattedValue, displayPattern);
215
+ onChange(broadcastValue);
216
+ }
217
+ });
164
218
  };
165
219
 
166
- handleOnBlur = (event) => {
167
- const { displayPattern, onBlur } = this.props;
168
- if (onBlur) {
169
- onBlur(unformatWithPattern(event.target.value, displayPattern));
170
- }
220
+ handleOnBlur = (event: FocusEvent<HTMLInputElement>) => {
221
+ this.props.onBlur?.(unformatWithPattern(event.target.value, this.props.displayPattern));
171
222
  };
172
223
 
173
- handleOnFocus = (event) => {
224
+ handleOnFocus = (event: FocusEvent<HTMLInputElement>) => {
174
225
  const { displayPattern, onFocus } = this.props;
175
226
  if (onFocus) {
176
227
  this.handleOnChange(event);
@@ -178,13 +229,14 @@ class WithDisplayFormat extends Component {
178
229
  }
179
230
  };
180
231
 
181
- handleDelete = (unformattedValue, action) => {
232
+ handleDelete = (unformattedValue: string, action: EventType) => {
182
233
  const { displayPattern } = this.props;
183
234
  const { selectionStart, selectionEnd } = this.state;
184
235
  const newStack = [...unformattedValue];
185
236
  if (selectionStart === selectionEnd) {
186
237
  let startPosition =
187
- selectionStart - getCountOfSymbolsInSelection(0, selectionStart, displayPattern);
238
+ (selectionStart as number) -
239
+ getCountOfSymbolsInSelection(0, selectionStart, displayPattern);
188
240
  let toDelete = 0;
189
241
 
190
242
  let count = getDistanceToNextSymbol(selectionStart, displayPattern);
@@ -203,21 +255,21 @@ class WithDisplayFormat extends Component {
203
255
  return newStack.join('');
204
256
  };
205
257
 
206
- handleCursorPositioning = (action) => {
258
+ handleCursorPositioning = (action: EventType) => {
207
259
  const { displayPattern } = this.props;
208
260
  const { triggerEvent, selectionStart, selectionEnd, pastedLength } = this.state;
209
261
 
210
262
  const cursorPosition = getCursorPositionAfterKeystroke(
211
263
  action,
212
- selectionStart,
213
- selectionEnd,
264
+ selectionStart as number,
265
+ selectionEnd as number,
214
266
  displayPattern,
215
- pastedLength,
267
+ pastedLength as number,
216
268
  );
217
269
 
218
270
  setTimeout(() => {
219
271
  if (triggerEvent) {
220
- triggerEvent.target.setSelectionRange(cursorPosition, cursorPosition);
272
+ (triggerEvent.target as HTMLInputElement).setSelectionRange(cursorPosition, cursorPosition);
221
273
  }
222
274
  this.setState({ selectionStart: cursorPosition, selectionEnd: cursorPosition });
223
275
  }, 0);
@@ -264,49 +316,4 @@ class WithDisplayFormat extends Component {
264
316
  }
265
317
  }
266
318
 
267
- WithDisplayFormat.propTypes = {
268
- /**
269
- * autocomplete hides our form help so we need to disable it when help text
270
- * is present. Chrome ignores autocomplete=off, the only way to disable it is
271
- * to provide an 'invalid' value, for which 'disabled' serves.
272
- */
273
- autoComplete: PropTypes.oneOf(['on', 'off', 'disabled']),
274
- className: PropTypes.string,
275
- disabled: PropTypes.bool,
276
- id: PropTypes.string,
277
- maxLength: PropTypes.number,
278
- minLength: PropTypes.number,
279
- name: PropTypes.string,
280
- onFocus: PropTypes.func,
281
- onBlur: PropTypes.func,
282
- onChange: PropTypes.func.isRequired,
283
- placeholder: PropTypes.string,
284
- readOnly: PropTypes.bool,
285
- render: PropTypes.func.isRequired,
286
- required: PropTypes.bool,
287
- displayPattern: PropTypes.string,
288
- type: PropTypes.string,
289
- inputMode: PropTypes.string,
290
- value: PropTypes.string,
291
- };
292
-
293
- WithDisplayFormat.defaultProps = {
294
- autoComplete: 'off',
295
- className: null,
296
- disabled: false,
297
- id: null,
298
- maxLength: null,
299
- minLength: null,
300
- name: null,
301
- placeholder: null,
302
- readOnly: false,
303
- required: false,
304
- displayPattern: '',
305
- type: 'text',
306
- inputMode: null,
307
- value: '',
308
- onFocus: null,
309
- onBlur: null,
310
- };
311
-
312
319
  export default WithDisplayFormat;
@@ -0,0 +1,2 @@
1
+ export { default } from './WithDisplayFormat';
2
+ export type { Props as WithDisplayFormatProps, TextInputProps } from './WithDisplayFormat';
@@ -1,14 +0,0 @@
1
- import PropTypes from 'prop-types';
2
-
3
- import WithDisplayFormat from '../withDisplayFormat';
4
-
5
- const InputWithDisplayFormat = (props) => (
6
- <WithDisplayFormat {...props} render={(renderProps) => <input {...renderProps} />} />
7
- );
8
-
9
- InputWithDisplayFormat.propTypes = {
10
- displayPattern: PropTypes.string.isRequired,
11
- onChange: PropTypes.func.isRequired,
12
- };
13
-
14
- export default InputWithDisplayFormat;
@@ -1 +0,0 @@
1
- export { default } from './InputWithDisplayFormat';
@@ -1,14 +0,0 @@
1
- import PropTypes from 'prop-types';
2
-
3
- import WithDisplayFormat from '../withDisplayFormat';
4
-
5
- const TextareaWithDisplayFormat = (props) => (
6
- <WithDisplayFormat {...props} render={(renderProps) => <textarea {...renderProps} />} />
7
- );
8
-
9
- TextareaWithDisplayFormat.propTypes = {
10
- displayPattern: PropTypes.string.isRequired,
11
- onChange: PropTypes.func.isRequired,
12
- };
13
-
14
- export default TextareaWithDisplayFormat;
@@ -1 +0,0 @@
1
- export { default } from './TextareaWithDisplayFormat';
@@ -1 +0,0 @@
1
- export { default } from './WithDisplayFormat';