@transferwise/components 0.0.0-experimental-1d00fb5 → 0.0.0-experimental-d44dcb8

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 (99) hide show
  1. package/build/alert/Alert.js +1 -1
  2. package/build/alert/Alert.js.map +1 -1
  3. package/build/alert/Alert.mjs +1 -1
  4. package/build/alert/Alert.mjs.map +1 -1
  5. package/build/checkbox/Checkbox.js +1 -1
  6. package/build/checkbox/Checkbox.js.map +1 -1
  7. package/build/checkbox/Checkbox.mjs +1 -1
  8. package/build/checkbox/Checkbox.mjs.map +1 -1
  9. package/build/field/Field.js +8 -4
  10. package/build/field/Field.js.map +1 -1
  11. package/build/field/Field.mjs +8 -4
  12. package/build/field/Field.mjs.map +1 -1
  13. package/build/inlineAlert/InlineAlert.js +1 -7
  14. package/build/inlineAlert/InlineAlert.js.map +1 -1
  15. package/build/inlineAlert/InlineAlert.mjs +1 -7
  16. package/build/inlineAlert/InlineAlert.mjs.map +1 -1
  17. package/build/main.css +27 -12
  18. package/build/nudge/Nudge.js +8 -12
  19. package/build/nudge/Nudge.js.map +1 -1
  20. package/build/nudge/Nudge.mjs +8 -12
  21. package/build/nudge/Nudge.mjs.map +1 -1
  22. package/build/prompt/InlinePrompt/InlinePrompt.js +2 -0
  23. package/build/prompt/InlinePrompt/InlinePrompt.js.map +1 -1
  24. package/build/prompt/InlinePrompt/InlinePrompt.mjs +2 -0
  25. package/build/prompt/InlinePrompt/InlinePrompt.mjs.map +1 -1
  26. package/build/radioGroup/RadioGroup.js +1 -0
  27. package/build/radioGroup/RadioGroup.js.map +1 -1
  28. package/build/radioGroup/RadioGroup.mjs +1 -0
  29. package/build/radioGroup/RadioGroup.mjs.map +1 -1
  30. package/build/styles/field/Field.css +10 -1
  31. package/build/styles/main.css +27 -12
  32. package/build/styles/nudge/Nudge.css +7 -11
  33. package/build/styles/prompt/InlinePrompt/InlinePrompt.css +3 -0
  34. package/build/styles/radioGroup/RadioGroup.css +3 -0
  35. package/build/styles/typeahead/Typeahead.css +4 -0
  36. package/build/typeahead/Typeahead.js +20 -7
  37. package/build/typeahead/Typeahead.js.map +1 -1
  38. package/build/typeahead/Typeahead.mjs +20 -7
  39. package/build/typeahead/Typeahead.mjs.map +1 -1
  40. package/build/types/components/src/alert/Alert.d.ts +1 -1
  41. package/build/types/components/src/alert/Alert.d.ts.map +1 -1
  42. package/build/types/components/src/field/Field.d.ts +8 -4
  43. package/build/types/components/src/field/Field.d.ts.map +1 -1
  44. package/build/types/components/src/inlineAlert/InlineAlert.d.ts +1 -7
  45. package/build/types/components/src/inlineAlert/InlineAlert.d.ts.map +1 -1
  46. package/build/types/components/src/nudge/Nudge.d.ts +2 -2
  47. package/build/types/components/src/nudge/Nudge.d.ts.map +1 -1
  48. package/build/types/components/src/prompt/InlinePrompt/InlinePrompt.d.ts +6 -1
  49. package/build/types/components/src/prompt/InlinePrompt/InlinePrompt.d.ts.map +1 -1
  50. package/build/types/components/src/radioGroup/RadioGroup.d.ts.map +1 -1
  51. package/build/types/components/src/typeahead/Typeahead.d.ts +8 -4
  52. package/build/types/components/src/typeahead/Typeahead.d.ts.map +1 -1
  53. package/build/types/components/src/upload/Upload.d.ts +1 -1
  54. package/build/types/components/src/upload/steps/uploadImageStep/uploadImageStep.d.ts.map +1 -1
  55. package/build/upload/Upload.js.map +1 -1
  56. package/build/upload/Upload.mjs.map +1 -1
  57. package/build/upload/steps/uploadImageStep/uploadImageStep.js +5 -4
  58. package/build/upload/steps/uploadImageStep/uploadImageStep.js.map +1 -1
  59. package/build/upload/steps/uploadImageStep/uploadImageStep.mjs +5 -4
  60. package/build/upload/steps/uploadImageStep/uploadImageStep.mjs.map +1 -1
  61. package/package.json +3 -3
  62. package/src/alert/Alert.spec.tsx +1 -1
  63. package/src/alert/Alert.tsx +2 -2
  64. package/src/checkbox/Checkbox.story.tsx +11 -3
  65. package/src/checkbox/Checkbox.tsx +1 -1
  66. package/src/checkbox/__snapshots__/Checkbox.spec.tsx.snap +1 -1
  67. package/src/field/Field.css +10 -1
  68. package/src/field/Field.less +13 -2
  69. package/src/field/Field.spec.tsx +19 -3
  70. package/src/field/Field.story.tsx +18 -0
  71. package/src/field/Field.tsx +17 -5
  72. package/src/inlineAlert/InlineAlert.story.tsx +4 -0
  73. package/src/inlineAlert/InlineAlert.tsx +1 -7
  74. package/src/main.css +27 -12
  75. package/src/main.less +1 -0
  76. package/src/nudge/Nudge.css +7 -11
  77. package/src/nudge/Nudge.less +13 -10
  78. package/src/nudge/Nudge.spec.tsx +6 -5
  79. package/src/nudge/Nudge.story.tsx +0 -9
  80. package/src/nudge/Nudge.tsx +3 -14
  81. package/src/prompt/InlinePrompt/InlinePrompt.css +3 -0
  82. package/src/prompt/InlinePrompt/InlinePrompt.less +5 -1
  83. package/src/prompt/InlinePrompt/InlinePrompt.spec.tsx +17 -0
  84. package/src/prompt/InlinePrompt/InlinePrompt.story.tsx +35 -0
  85. package/src/prompt/InlinePrompt/InlinePrompt.tsx +7 -0
  86. package/src/radioGroup/RadioGroup.css +3 -0
  87. package/src/radioGroup/RadioGroup.less +3 -0
  88. package/src/radioGroup/RadioGroup.story.tsx +2 -0
  89. package/src/radioGroup/RadioGroup.test.story.tsx +62 -0
  90. package/src/radioGroup/RadioGroup.tsx +6 -1
  91. package/src/typeahead/Typeahead.css +4 -0
  92. package/src/typeahead/Typeahead.less +5 -1
  93. package/src/typeahead/Typeahead.spec.tsx +1 -1
  94. package/src/typeahead/Typeahead.story.tsx +151 -3
  95. package/src/typeahead/Typeahead.tsx +33 -9
  96. package/src/upload/Upload.story.tsx +1 -1
  97. package/src/upload/Upload.tests.story.tsx +36 -1
  98. package/src/upload/Upload.tsx +1 -1
  99. package/src/upload/steps/uploadImageStep/uploadImageStep.tsx +7 -3
@@ -103,6 +103,10 @@
103
103
  padding: 0;
104
104
  margin: 0;
105
105
  }
106
+ .typeahead--prompt {
107
+ margin-top: 4px;
108
+ margin-top: var(--size-4);
109
+ }
106
110
  .typeahead-sm.typeahead--multiple .typeahead__input-container {
107
111
  min-height: 32px;
108
112
  }
@@ -122,6 +122,10 @@
122
122
  }
123
123
  }
124
124
 
125
+ &--prompt {
126
+ margin-top: var(--size-4);
127
+ }
128
+
125
129
  // SIZES
126
130
  &-sm {
127
131
  &.typeahead--multiple {
@@ -207,7 +211,7 @@
207
211
  }
208
212
 
209
213
  .np-theme-personal & {
210
- .input-group:not(.disabled,:disabled,.input-group--has-error):focus-within .tw-icon-search {
214
+ .input-group:not(.disabled, :disabled, .input-group--has-error):focus-within .tw-icon-search {
211
215
  color: var(--color-interactive-primary);
212
216
  }
213
217
  .tw-icon-search {
@@ -102,7 +102,7 @@ describe('Typeahead', () => {
102
102
  expect(onChange).toHaveBeenCalledWith([]);
103
103
  });
104
104
 
105
- it('shows InlineAlert when alert prop is provided', () => {
105
+ it('shows InlinePrompt when alert prop is provided', () => {
106
106
  render(
107
107
  <Typeahead
108
108
  id="test"
@@ -1,15 +1,18 @@
1
1
  import { Meta, StoryObj } from '@storybook/react-webpack5';
2
2
  import { Search as SearchIcon } from '@transferwise/icons';
3
3
  import { userEvent, within, fn } from 'storybook/test';
4
-
5
- import Typeahead, { type TypeaheadOption } from './Typeahead';
6
- import { Size } from '../common';
7
4
  import { useState } from 'react';
5
+
6
+ import { Sentiment, Size } from '../common';
8
7
  import { Input } from '../inputs/Input';
9
8
  import { Field } from '../field/Field';
10
9
  import Button from '../button';
11
10
  import Modal from '../modal';
11
+ import { InlinePromptProps } from '../prompt';
12
+ import Typeahead, { type TypeaheadOption } from './Typeahead';
12
13
 
14
+ // needed for SB to display correct name in the docs
15
+ (Typeahead as React.FC).displayName = 'Typeahead';
13
16
  type Story = StoryObj<typeof Typeahead>;
14
17
 
15
18
  /**
@@ -37,6 +40,7 @@ const meta: Meta<typeof Typeahead> = {
37
40
  searchDelay: 200,
38
41
  showSuggestions: true,
39
42
  showNewEntry: true,
43
+ alert: undefined,
40
44
  size: Size.MEDIUM,
41
45
  initialValue: [],
42
46
  id: 'myTypeahead',
@@ -54,6 +58,17 @@ const meta: Meta<typeof Typeahead> = {
54
58
  control: 'inline-radio',
55
59
  options: [Size.MEDIUM, Size.LARGE],
56
60
  },
61
+ alert: {
62
+ description:
63
+ 'Displays an [InlinePrompt](?path=/docs/prompts-inlineprompt--docs) below the input when provided. <blockquote class="m-0">**⚠️ DEPRECATED:** Please use [&lt;Field />](?path=/docs/forms-field--docs) component and its `message` and `sentiment` props instead. `error`, `info` and `success` alert types are no longer supported and will be soon removed.**</blockquote>',
64
+ control: 'object',
65
+ table: {
66
+ type: {
67
+ summary:
68
+ '{ message: ReactNode; type?: "negative" | "neutral" | "positive" | "warning" | "proposition" }',
69
+ },
70
+ },
71
+ },
57
72
  },
58
73
  };
59
74
  export default meta;
@@ -237,6 +252,14 @@ export const Search: Story = {
237
252
  };
238
253
 
239
254
  export const AutoFocusInModal: Story = {
255
+ parameters: {
256
+ docs: {
257
+ story: {
258
+ inline: false,
259
+ iframeHeight: 500,
260
+ },
261
+ },
262
+ },
240
263
  render: function Render() {
241
264
  const [open, setOpen] = useState<boolean>(true);
242
265
  return (
@@ -279,3 +302,128 @@ export const AutoFocusInModal: Story = {
279
302
  );
280
303
  },
281
304
  };
305
+
306
+ export const WithField: Story = {
307
+ args: {
308
+ autoFillOnBlur: undefined,
309
+ chipSeparators: undefined,
310
+ clearable: undefined,
311
+ initialValue: undefined,
312
+ inputAutoComplete: undefined,
313
+ minQueryLength: undefined,
314
+ onBlur: undefined,
315
+ onFocus: undefined,
316
+ onInputChange: undefined,
317
+ onSearch: undefined,
318
+ placeholder: undefined,
319
+ searchDelay: undefined,
320
+ showSuggestions: undefined,
321
+ showNewEntry: undefined,
322
+ size: undefined,
323
+ },
324
+ render: function Render(args) {
325
+ const options = [{ label: 'Option 1' }];
326
+
327
+ const alertTypes: InlinePromptProps['sentiment'][] = [
328
+ Sentiment.NEGATIVE,
329
+ Sentiment.WARNING,
330
+ Sentiment.NEUTRAL,
331
+ Sentiment.POSITIVE,
332
+ 'proposition',
333
+ ];
334
+
335
+ return (
336
+ <>
337
+ <Field
338
+ id="typeahead"
339
+ label="Field label"
340
+ description="Additional information about the field"
341
+ required
342
+ >
343
+ <Typeahead {...args} name="typeahead" options={options} />
344
+ </Field>
345
+ {alertTypes.map((sentiment) => (
346
+ <Field
347
+ key={sentiment}
348
+ label="Field label"
349
+ id={`typeahead-${sentiment}`}
350
+ message={`This is a ${sentiment} message`}
351
+ sentiment={sentiment}
352
+ >
353
+ <Typeahead {...args} name={`typeahead-${sentiment}`} options={options} />
354
+ </Field>
355
+ ))}
356
+ </>
357
+ );
358
+ },
359
+ decorators: (Story) => (
360
+ <div className="d-flex flex-column">
361
+ <Story />
362
+ </div>
363
+ ),
364
+ };
365
+
366
+ /**
367
+ * > Please use [&lt;Field />](?path=/docs/forms-field--docs) component and its `message` and `sentiment` props instead. <br/>`error`, `info` and `success` alert types are no longer supported and will be soon removed.**
368
+ */
369
+ export const WithAlert: Story = {
370
+ name: 'With Alert (deprecated)',
371
+ args: {
372
+ autoFillOnBlur: undefined,
373
+ chipSeparators: undefined,
374
+ clearable: undefined,
375
+ initialValue: undefined,
376
+ inputAutoComplete: undefined,
377
+ minQueryLength: undefined,
378
+ onBlur: undefined,
379
+ onFocus: undefined,
380
+ onInputChange: undefined,
381
+ onSearch: undefined,
382
+ placeholder: undefined,
383
+ searchDelay: undefined,
384
+ showSuggestions: undefined,
385
+ showNewEntry: undefined,
386
+ size: undefined,
387
+ },
388
+ parameters: {
389
+ docs: {
390
+ canvas: {
391
+ sourceState: 'hidden',
392
+ },
393
+ },
394
+ },
395
+ render: function Render(args) {
396
+ const options = [{ label: 'Option 1' }];
397
+
398
+ const alertTypes: InlinePromptProps['sentiment'][] = [
399
+ Sentiment.NEGATIVE,
400
+ Sentiment.WARNING,
401
+ Sentiment.NEUTRAL,
402
+ Sentiment.POSITIVE,
403
+ 'proposition',
404
+ ];
405
+
406
+ return (
407
+ <>
408
+ {alertTypes.map((sentiment) => (
409
+ <Typeahead
410
+ key={sentiment}
411
+ {...args}
412
+ id={`typeahead-${sentiment}`}
413
+ name={`typeahead-${sentiment}`}
414
+ options={options}
415
+ alert={{
416
+ message: `This is a ${sentiment} message`,
417
+ type: sentiment,
418
+ }}
419
+ />
420
+ ))}
421
+ </>
422
+ );
423
+ },
424
+ decorators: (Story) => (
425
+ <div className="d-flex flex-column">
426
+ <Story />
427
+ </div>
428
+ ),
429
+ };
@@ -16,8 +16,7 @@ import {
16
16
  removeClickClassFromDocumentOnIos,
17
17
  stopPropagation,
18
18
  } from '../common';
19
- import InlineAlert from '../inlineAlert';
20
- import { InlineAlertProps } from '../inlineAlert/InlineAlert';
19
+ import { InlinePrompt, InlinePromptProps } from '../prompt';
21
20
  import { withInputAttributes, WithInputAttributesProps } from '../inputs/contexts';
22
21
 
23
22
  import TypeaheadInput from './typeaheadInput/TypeaheadInput';
@@ -40,9 +39,17 @@ export interface TypeaheadProps<T> extends Partial<WrappedComponentProps> {
40
39
  id: string;
41
40
  name: string;
42
41
  addon?: ReactNode;
42
+ /**
43
+ * @deprecated Please use [`Field`](?path=/docs/forms-field--docs) component and its `message` and `sentiment` props instead.
44
+ * @deprecated `error`, `info` and `success` are deprecated as alert types and will be soon removed.
45
+ */
43
46
  alert?: {
44
- message: InlineAlertProps['children'];
45
- type?: InlineAlertProps['type'];
47
+ message: InlinePromptProps['children'];
48
+ type?:
49
+ | InlinePromptProps['sentiment']
50
+ | `${Sentiment.ERROR}`
51
+ | `${Sentiment.INFO}`
52
+ | `${Sentiment.SUCCESS}`;
46
53
  };
47
54
  allowNew?: boolean;
48
55
  autoFillOnBlur?: boolean;
@@ -474,9 +481,20 @@ class Typeahead<T> extends Component<TypeaheadPropsWithInputAttributes<T>, Typea
474
481
  dropdownOpen,
475
482
  });
476
483
 
477
- const alertType = alert?.type ?? Sentiment.NEUTRAL;
478
- const hasError = errorState || (alert && alertType === Sentiment.ERROR);
479
- const displayAlert = (!errorState && alert) || (alert && alertType === Sentiment.ERROR);
484
+ const alertType = (() => {
485
+ if (!alert?.type || alert.type === Sentiment.INFO) {
486
+ return Sentiment.NEUTRAL;
487
+ }
488
+ if (alert.type === Sentiment.ERROR) {
489
+ return Sentiment.NEGATIVE;
490
+ }
491
+ if (alert.type === Sentiment.SUCCESS) {
492
+ return Sentiment.POSITIVE;
493
+ }
494
+ return alert.type;
495
+ })();
496
+ const hasError = errorState || (alert && alertType === Sentiment.NEGATIVE);
497
+ const displayAlert = (!errorState && alert) || (alert && alertType === Sentiment.NEGATIVE);
480
498
  const hasWarning = displayAlert && alertType === Sentiment.WARNING;
481
499
  const hasInfo = displayAlert && alertType === Sentiment.NEUTRAL;
482
500
  return (
@@ -494,7 +512,7 @@ class Typeahead<T> extends Component<TypeaheadPropsWithInputAttributes<T>, Typea
494
512
  onClick={stopPropagation}
495
513
  >
496
514
  <div
497
- className={clsx('form-group', {
515
+ className={clsx('form-group', 'form-group--typeahead', {
498
516
  'has-error': hasError,
499
517
  'has-warning': hasWarning,
500
518
  'has-info': hasInfo,
@@ -546,7 +564,13 @@ class Typeahead<T> extends Component<TypeaheadPropsWithInputAttributes<T>, Typea
546
564
  </div>
547
565
  )}
548
566
  </div>
549
- {displayAlert ? <InlineAlert type={alert.type}>{alert.message}</InlineAlert> : menu}
567
+ {displayAlert ? (
568
+ <InlinePrompt sentiment={alertType} className="typeahead--prompt" width="full">
569
+ {alert.message}
570
+ </InlinePrompt>
571
+ ) : (
572
+ menu
573
+ )}
550
574
  </div>
551
575
  </div>
552
576
  );
@@ -71,7 +71,7 @@ const meta = {
71
71
  },
72
72
  errorIconLabel: {
73
73
  description:
74
- "Override for the InlineAlert icon's default, accessible name announced by the screen readers",
74
+ "Override for the InlinePrompt icon's default, accessible name announced by the screen readers",
75
75
  },
76
76
  usHelpImage: {
77
77
  control: false,
@@ -1,4 +1,5 @@
1
- import type { Meta } from '@storybook/react-webpack5';
1
+ import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
+ import { userEvent, within, waitFor } from 'storybook/test';
2
3
 
3
4
  import Upload from '.';
4
5
  import { Field } from '../field/Field';
@@ -73,6 +74,40 @@ export const MaxSizes = () => {
73
74
  );
74
75
  };
75
76
 
77
+ export const WithError: StoryObj<typeof meta> = {
78
+ render: () => (
79
+ <Field label="Upload a file">
80
+ <Upload
81
+ usAccept="*"
82
+ usLabel="Upload a file"
83
+ usPlaceholder="Maximum filesize is 1B"
84
+ usDisabled={false}
85
+ maxSize={1}
86
+ errorIconLabel="File too large error"
87
+ httpOptions={{
88
+ url: 'https://httpbin.org/post',
89
+ method: 'POST',
90
+ }}
91
+ />
92
+ </Field>
93
+ ),
94
+ play: async ({ canvasElement }) => {
95
+ const canvas = within(canvasElement);
96
+ const fileInput = canvasElement.querySelector<HTMLInputElement>('input[type="file"]');
97
+
98
+ if (!fileInput) {
99
+ throw new Error('File input not found');
100
+ }
101
+
102
+ const file = new File(['This file content is definitely more than 1 byte'], 'test-file.txt', {
103
+ type: 'text/plain',
104
+ });
105
+
106
+ await userEvent.upload(fileInput, file);
107
+ await waitFor(async () => canvas.findByText(/Maximum filesize is/i), { timeout: 3000 });
108
+ },
109
+ };
110
+
76
111
  export const AllVariants = () => {
77
112
  return (
78
113
  <div style={{ display: 'flex', gap: '1rem' }}>
@@ -55,7 +55,7 @@ export interface UploadProps extends WrappedComponentProps {
55
55
  usLabel?: string;
56
56
  usPlaceholder?: string;
57
57
  /**
58
- * Override for the [InlineAlert icon's default, accessible name](/?path=/docs/other-statusicon-accessibility--docs)
58
+ * Override for the [InlinePrompt icon's default, accessible name](/?path=/docs/other-statusicon-accessibility--docs)
59
59
  * announced by the screen readers
60
60
  * */
61
61
  errorIconLabel?: string;
@@ -2,7 +2,7 @@ import { Upload as UploadIcon } from '@transferwise/icons';
2
2
  import { createRef, PureComponent } from 'react';
3
3
  import StatusIcon from '../../../statusIcon';
4
4
  import { Sentiment, Size } from '../../../common';
5
- import InlineAlert from '../../../inlineAlert';
5
+ import { InlinePrompt } from '../../../prompt/InlinePrompt/InlinePrompt';
6
6
 
7
7
  export interface UploadImageStepProps {
8
8
  fileDropped: (file: File) => void;
@@ -105,9 +105,13 @@ export default class UploadImageStep extends PureComponent<UploadImageStepProps>
105
105
  {errorMessage && (
106
106
  <div className="upload-error-message">
107
107
  <div className="m-t-3 has-error">
108
- <InlineAlert type={Sentiment.NEGATIVE} iconLabel={errorIconLabel}>
108
+ <InlinePrompt
109
+ sentiment={Sentiment.NEGATIVE}
110
+ mediaLabel={errorIconLabel}
111
+ width="full"
112
+ >
109
113
  {errorMessage}
110
- </InlineAlert>
114
+ </InlinePrompt>
111
115
  </div>
112
116
  </div>
113
117
  )}