@transferwise/components 0.0.0-experimental-e94d625 → 0.0.0-experimental-8e1de95

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 (69) hide show
  1. package/build/Snackbar/Snackbar.js +97 -101
  2. package/build/Snackbar/Snackbar.js.map +1 -1
  3. package/build/Snackbar/Snackbar.mjs +98 -102
  4. package/build/Snackbar/Snackbar.mjs.map +1 -1
  5. package/build/types/Carousel/_stories/constants.d.ts +25 -0
  6. package/build/types/Carousel/_stories/constants.d.ts.map +1 -1
  7. package/build/types/ListItem/_stories/variants/helpers.d.ts +38 -1
  8. package/build/types/ListItem/_stories/variants/helpers.d.ts.map +1 -1
  9. package/build/types/Snackbar/Snackbar.d.ts +1 -15
  10. package/build/types/Snackbar/Snackbar.d.ts.map +1 -1
  11. package/package.json +1 -1
  12. package/src/Accordion/_stories/Accordion.test.story.tsx +74 -48
  13. package/src/AvatarLayout/_stories/AvatarLayout.test.story.tsx +46 -30
  14. package/src/Button/LegacyButton/_stories/LegacyButton.test.story.tsx +29 -19
  15. package/src/Calendar/_stories/Calendar.test.story.tsx +34 -21
  16. package/src/Carousel/_stories/Carousel.test.story.tsx +18 -8
  17. package/src/Carousel/_stories/constants.tsx +29 -4
  18. package/src/Checkbox/_stories/Checkbox.test.story.tsx +22 -13
  19. package/src/CheckboxButton/_stories/CheckboxButton.test.story.tsx +23 -14
  20. package/src/Chips/_stories/Chips.test.story.tsx +51 -36
  21. package/src/DateInput/_stories/DateInput.rtl.test.story.tsx +62 -12
  22. package/src/Decision/_stories/Decision.test.story.tsx +74 -58
  23. package/src/DefinitionList/_stories/DefinitionList.test.story.tsx +58 -42
  24. package/src/Drawer/_stories/Drawer.rtl.test.story.tsx +65 -38
  25. package/src/ExpressiveMoneyInput/_stories/ExpressiveMoneyInput.rtl.test.story.tsx +107 -74
  26. package/src/Field/_stories/Field.test.story.tsx +1 -1
  27. package/src/FlowNavigation/_stories/FlowNavigation.rtl.test.story.tsx +81 -51
  28. package/src/Header/_stories/Header.test.story.tsx +30 -18
  29. package/src/Info/_stories/Info.rtl.test.story.tsx +124 -50
  30. package/src/Inputs/InputGroup/_stories/InputGroup.test.story.tsx +4 -2
  31. package/src/Inputs/SelectInput/_stories/SelectInput.rtl.test.story.tsx +106 -77
  32. package/src/InstructionsList/_stories/InstructionsList.test.story.tsx +43 -16
  33. package/src/Link/_stories/Link.test.story.tsx +27 -13
  34. package/src/ListItem/_stories/ListItem.rtl.test.story.tsx +126 -6
  35. package/src/ListItem/_stories/variants/helpers.tsx +174 -126
  36. package/src/Loader/_stories/Loader.test.story.tsx +17 -10
  37. package/src/Modal/_stories/Modal.rtl.test.story.tsx +58 -39
  38. package/src/MoneyInput/_stories/MoneyInput.rtl.test.story.tsx +14 -2
  39. package/src/Nudge/_stories/Nudge.test.story.tsx +70 -21
  40. package/src/Popover/_stories/Popover.rtl.test.story.tsx +92 -49
  41. package/src/PromoCard/_stories/PromoCard.test.story.tsx +53 -29
  42. package/src/PromoCard/_stories/PromoCardGroup.test.story.tsx +60 -36
  43. package/src/Prompt/ActionPrompt/_stories/ActionPrompt.test.story.tsx +74 -38
  44. package/src/Prompt/CriticalBanner/_stories/CriticalBanner.test.story.tsx +68 -31
  45. package/src/Prompt/InfoPrompt/_stories/InfoPrompt.test.story.tsx +52 -22
  46. package/src/Prompt/InlinePrompt/_stories/InlinePrompt.test.story.tsx +36 -21
  47. package/src/Radio/_stories/Radio.test.story.tsx +60 -46
  48. package/src/RadioGroup/_stories/RadioGroup.test.story.tsx +70 -51
  49. package/src/Section/_stories/Section.test.story.tsx +30 -14
  50. package/src/SegmentedControl/_stories/SegmentedControl.test.story.tsx +38 -15
  51. package/src/SlidingPanel/_stories/SlidingPanel.rtl.test.story.tsx +58 -34
  52. package/src/Snackbar/Snackbar.tsx +90 -88
  53. package/src/Snackbar/_stories/Snackbar.rtl.test.story.tsx +24 -12
  54. package/src/Stepper/_stories/Stepper.test.story.tsx +27 -9
  55. package/src/Switch/_stories/Switch.test.story.tsx +20 -12
  56. package/src/Table/_stories/Table.test.story.tsx +107 -86
  57. package/src/Tabs/_stories/Tabs.test.story.tsx +92 -52
  58. package/src/Tag/_stories/Tag.test.story.tsx +27 -16
  59. package/src/Tooltip/_stories/Tooltip.rtl.test.story.tsx +68 -25
  60. package/src/Typeahead/_stories/Typeahead.rtl.test.story.tsx +3 -3
  61. package/src/Upload/_stories/Upload.rtl.test.story.tsx +49 -26
  62. package/src/UploadInput/_stories/UploadInput.test.story.tsx +63 -41
  63. package/src/_deprecated/Alert/_stories/Alert.test.story.tsx +45 -24
  64. package/src/_deprecated/Card/_stories/Card.test.story.tsx +47 -23
  65. package/src/_deprecated/CriticalBanner/_stories/CriticalCommsBanner.test.story.tsx +21 -15
  66. package/src/_deprecated/InlineAlert/_stories/InlineAlert.test.story.tsx +23 -12
  67. package/src/_deprecated/Select/_stories/Select.rtl.test.story.tsx +76 -40
  68. package/src/common/BottomSheet/_stories/BottomSheet.test.story.tsx +38 -20
  69. package/src/common/Panel/_stories/Panel.rtl.test.story.tsx +135 -51
@@ -1,6 +1,6 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
2
 
3
- import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
3
+ import { useRtlDiffI18n, withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
4
4
  import { Width } from '../../common';
5
5
  import Tabs from '..';
6
6
 
@@ -12,61 +12,101 @@ export default {
12
12
 
13
13
  type Story = StoryObj<typeof Tabs>;
14
14
 
15
- const defaultTabs = [
16
- { title: 'First tab', disabled: false, content: <div className="p-a-2">First content</div> },
17
- { title: 'Second tab', disabled: false, content: <div className="p-a-2">Second content</div> },
18
- { title: 'Third tab', disabled: false, content: <div className="p-a-2">Third content</div> },
19
- ];
20
-
21
15
  /**
22
16
  * The tab list is horizontal: tab order, the active indicator translateX, and
23
17
  * swipe direction all flip between LTR and RTL. The indicator uses a negated
24
18
  * translateX in RTL mode. This diff verifies the layout mirrors correctly.
25
19
  */
26
20
  export const RTLDiff: Story = {
27
- render: () => (
28
- <>
29
- <div style={{ marginBottom: 32 }}>
30
- <h4>Block width — first tab selected</h4>
31
- <Tabs
32
- name="rtl-block-first"
33
- tabs={defaultTabs}
34
- selected={0}
35
- headerWidth={Width.BLOCK}
36
- onTabSelect={() => {}}
37
- />
38
- </div>
39
- <div style={{ marginBottom: 32 }}>
40
- <h4>Block width — second tab selected</h4>
41
- <Tabs
42
- name="rtl-block-second"
43
- tabs={defaultTabs}
44
- selected={1}
45
- headerWidth={Width.BLOCK}
46
- onTabSelect={() => {}}
47
- />
48
- </div>
49
- <div style={{ marginBottom: 32 }}>
50
- <h4>Auto width — first tab selected</h4>
51
- <Tabs
52
- name="rtl-auto-first"
53
- tabs={defaultTabs}
54
- selected={0}
55
- headerWidth={Width.AUTO}
56
- onTabSelect={() => {}}
57
- />
58
- </div>
59
- <div style={{ marginBottom: 32 }}>
60
- <h4>Auto width — second tab selected</h4>
61
- <Tabs
62
- name="rtl-auto-second"
63
- tabs={defaultTabs}
64
- selected={1}
65
- headerWidth={Width.AUTO}
66
- onTabSelect={() => {}}
67
- />
68
- </div>
69
- </>
70
- ),
71
- ...withRTLDiff(),
21
+ render: () => {
22
+ const i18n = useRtlDiffI18n();
23
+ const defaultTabs = [
24
+ {
25
+ title: i18n.firstTab,
26
+ disabled: false,
27
+ content: <div className="p-a-2">{i18n.firstContent}</div>,
28
+ },
29
+ {
30
+ title: i18n.secondTab,
31
+ disabled: false,
32
+ content: <div className="p-a-2">{i18n.secondContent}</div>,
33
+ },
34
+ {
35
+ title: i18n.thirdTab,
36
+ disabled: false,
37
+ content: <div className="p-a-2">{i18n.thirdContent}</div>,
38
+ },
39
+ ];
40
+
41
+ return (
42
+ <>
43
+ <div style={{ marginBottom: 32 }}>
44
+ <h4>{i18n.blockFirstSelected}</h4>
45
+ <Tabs
46
+ name="rtl-block-first"
47
+ tabs={defaultTabs}
48
+ selected={0}
49
+ headerWidth={Width.BLOCK}
50
+ onTabSelect={() => {}}
51
+ />
52
+ </div>
53
+ <div style={{ marginBottom: 32 }}>
54
+ <h4>{i18n.blockSecondSelected}</h4>
55
+ <Tabs
56
+ name="rtl-block-second"
57
+ tabs={defaultTabs}
58
+ selected={1}
59
+ headerWidth={Width.BLOCK}
60
+ onTabSelect={() => {}}
61
+ />
62
+ </div>
63
+ <div style={{ marginBottom: 32 }}>
64
+ <h4>{i18n.autoFirstSelected}</h4>
65
+ <Tabs
66
+ name="rtl-auto-first"
67
+ tabs={defaultTabs}
68
+ selected={0}
69
+ headerWidth={Width.AUTO}
70
+ onTabSelect={() => {}}
71
+ />
72
+ </div>
73
+ <div style={{ marginBottom: 32 }}>
74
+ <h4>{i18n.autoSecondSelected}</h4>
75
+ <Tabs
76
+ name="rtl-auto-second"
77
+ tabs={defaultTabs}
78
+ selected={1}
79
+ headerWidth={Width.AUTO}
80
+ onTabSelect={() => {}}
81
+ />
82
+ </div>
83
+ </>
84
+ );
85
+ },
86
+ ...withRTLDiff({
87
+ i18n: {
88
+ firstTab: { en: 'First tab', ar: 'التبويب الأول' },
89
+ secondTab: { en: 'Second tab', ar: 'التبويب الثاني' },
90
+ thirdTab: { en: 'Third tab', ar: 'التبويب الثالث' },
91
+ firstContent: { en: 'First content', ar: 'المحتوى الأول' },
92
+ secondContent: { en: 'Second content', ar: 'المحتوى الثاني' },
93
+ thirdContent: { en: 'Third content', ar: 'المحتوى الثالث' },
94
+ blockFirstSelected: {
95
+ en: 'Block width — first tab selected',
96
+ ar: 'عرض كامل — التبويب الأول محدد',
97
+ },
98
+ blockSecondSelected: {
99
+ en: 'Block width — second tab selected',
100
+ ar: 'عرض كامل — التبويب الثاني محدد',
101
+ },
102
+ autoFirstSelected: {
103
+ en: 'Auto width — first tab selected',
104
+ ar: 'عرض تلقائي — التبويب الأول محدد',
105
+ },
106
+ autoSecondSelected: {
107
+ en: 'Auto width — second tab selected',
108
+ ar: 'عرض تلقائي — التبويب الثاني محدد',
109
+ },
110
+ },
111
+ }),
72
112
  };
@@ -1,7 +1,7 @@
1
1
  import type { ReactElement } from 'react';
2
2
  import type { Meta, StoryObj } from '@storybook/react-webpack5';
3
3
 
4
- import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
4
+ import { useRtlDiffI18n, withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
5
5
  import { allModes } from '../../../.storybook/modes';
6
6
  import Tag from '..';
7
7
  import type { TagProps } from '..';
@@ -72,21 +72,32 @@ export const AllThemesAndSentiments: Story = {
72
72
  * The tag's horizontal padding is asymmetric and long copy truncates, so both need to mirror.
73
73
  */
74
74
  export const RTLDiff: Story = {
75
- render: () => (
76
- <div
77
- style={{
78
- alignItems: 'flex-start',
79
- display: 'flex',
80
- flexDirection: 'column',
81
- gap: '0.5rem',
82
- }}
83
- >
84
- <Tag label="Tag copy" />
85
- <Tag label="Tag copy" size="large" sentiment="success" emphasis="elevated" />
86
- <Tag label="A tag with copy far too long to fit within its maximum width" />
87
- </div>
88
- ),
89
- ...withRTLDiff(),
75
+ render: () => {
76
+ const i18n = useRtlDiffI18n();
77
+ return (
78
+ <div
79
+ style={{
80
+ alignItems: 'flex-start',
81
+ display: 'flex',
82
+ flexDirection: 'column',
83
+ gap: '0.5rem',
84
+ }}
85
+ >
86
+ <Tag label={i18n.tagCopy} />
87
+ <Tag label={i18n.tagCopy} size="large" sentiment="success" emphasis="elevated" />
88
+ <Tag label={i18n.longCopy} />
89
+ </div>
90
+ );
91
+ },
92
+ ...withRTLDiff({
93
+ i18n: {
94
+ tagCopy: { en: 'Tag copy', ar: 'نص الوسم' },
95
+ longCopy: {
96
+ en: 'A tag with copy far too long to fit within its maximum width',
97
+ ar: 'وسم يحتوي على نص طويل جدًا بحيث لا يتسع داخل الحد الأقصى لعرضه',
98
+ },
99
+ },
100
+ }),
90
101
  };
91
102
 
92
103
  /**
@@ -1,7 +1,7 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
2
  import { userEvent, within } from 'storybook/test';
3
3
 
4
- import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
4
+ import { useRtlDiffI18n, withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
5
5
  import Button from '../../Button';
6
6
  import Tooltip from '../Tooltip';
7
7
 
@@ -21,41 +21,84 @@ const hoverTrigger = async ({ canvasElement }: { canvasElement: HTMLElement }) =
21
21
  };
22
22
 
23
23
  export const PositionTop: Story = {
24
- render: () => (
25
- <Tooltip label="Top positioned tooltip" position="top">
26
- <Button>Top</Button>
27
- </Tooltip>
28
- ),
24
+ render: () => {
25
+ const i18n = useRtlDiffI18n();
26
+ return (
27
+ <Tooltip label={i18n.tooltip} position="top">
28
+ <Button>{i18n.trigger}</Button>
29
+ </Tooltip>
30
+ );
31
+ },
29
32
  play: hoverTrigger,
30
- ...withRTLDiff({ renderAs: 'iframe', hAlign: 'center', vAlign: 'bottom' }),
33
+ ...withRTLDiff({
34
+ renderAs: 'iframe',
35
+ hAlign: 'center',
36
+ vAlign: 'bottom',
37
+ i18n: {
38
+ tooltip: { en: 'Top positioned tooltip', ar: 'تلميح في الأعلى' },
39
+ trigger: { en: 'Top', ar: 'أعلى' },
40
+ },
41
+ }),
31
42
  };
32
43
 
33
44
  export const PositionBottom: Story = {
34
- render: () => (
35
- <Tooltip label="Bottom positioned tooltip" position="bottom">
36
- <Button>Bottom</Button>
37
- </Tooltip>
38
- ),
45
+ render: () => {
46
+ const i18n = useRtlDiffI18n();
47
+ return (
48
+ <Tooltip label={i18n.tooltip} position="bottom">
49
+ <Button>{i18n.trigger}</Button>
50
+ </Tooltip>
51
+ );
52
+ },
39
53
  play: hoverTrigger,
40
- ...withRTLDiff({ renderAs: 'iframe', hAlign: 'center' }),
54
+ ...withRTLDiff({
55
+ renderAs: 'iframe',
56
+ hAlign: 'center',
57
+ i18n: {
58
+ tooltip: { en: 'Bottom positioned tooltip', ar: 'تلميح في الأسفل' },
59
+ trigger: { en: 'Bottom', ar: 'أسفل' },
60
+ },
61
+ }),
41
62
  };
42
63
 
43
64
  export const PositionRight: Story = {
44
- render: () => (
45
- <Tooltip label="Right positioned tooltip" position="right">
46
- <Button>Right</Button>
47
- </Tooltip>
48
- ),
65
+ render: () => {
66
+ const i18n = useRtlDiffI18n();
67
+ return (
68
+ <Tooltip label={i18n.tooltip} position="right">
69
+ <Button>{i18n.trigger}</Button>
70
+ </Tooltip>
71
+ );
72
+ },
49
73
  play: hoverTrigger,
50
- ...withRTLDiff({ renderAs: 'iframe', hAlign: 'left', vAlign: 'center' }),
74
+ ...withRTLDiff({
75
+ renderAs: 'iframe',
76
+ hAlign: 'left',
77
+ vAlign: 'center',
78
+ i18n: {
79
+ tooltip: { en: 'Right positioned tooltip', ar: 'تلميح على اليمين' },
80
+ trigger: { en: 'Right', ar: 'يمين' },
81
+ },
82
+ }),
51
83
  };
52
84
 
53
85
  export const PositionLeft: Story = {
54
- render: () => (
55
- <Tooltip label="Left positioned tooltip" position="left">
56
- <Button>Left</Button>
57
- </Tooltip>
58
- ),
86
+ render: () => {
87
+ const i18n = useRtlDiffI18n();
88
+ return (
89
+ <Tooltip label={i18n.tooltip} position="left">
90
+ <Button>{i18n.trigger}</Button>
91
+ </Tooltip>
92
+ );
93
+ },
59
94
  play: hoverTrigger,
60
- ...withRTLDiff({ renderAs: 'iframe', hAlign: 'right', vAlign: 'center' }),
95
+ ...withRTLDiff({
96
+ renderAs: 'iframe',
97
+ hAlign: 'right',
98
+ vAlign: 'center',
99
+ i18n: {
100
+ tooltip: { en: 'Left positioned tooltip', ar: 'تلميح على اليسار' },
101
+ trigger: { en: 'Left', ar: 'يسار' },
102
+ },
103
+ }),
61
104
  };
@@ -19,9 +19,9 @@ export default {
19
19
  type Story = StoryObj<typeof Typeahead>;
20
20
 
21
21
  const localisedStrings = {
22
- gbp: { en: 'British pound', ar: 'جنيه إسترليني' },
23
- eur: { en: 'Euro', ar: 'يورو' },
24
- usd: { en: 'US Dollar', ar: 'دولار أمريكي' },
22
+ gbp: { en: 'British pound', ar: 'الجنيه الإسترليني' },
23
+ eur: { en: 'Euro', ar: 'اليورو' },
24
+ usd: { en: 'US Dollar', ar: 'الدولار الأمريكي' },
25
25
  placeholder: { en: 'Search currencies…', ar: 'ابحث عن العملات...' },
26
26
  };
27
27
 
@@ -1,7 +1,11 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
- import { userEvent, within } from 'storybook/test';
2
+ import { expect, userEvent, waitFor } from 'storybook/test';
3
3
 
4
- import { forEachColumn, withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
4
+ import {
5
+ forEachColumn,
6
+ useRtlDiffI18n,
7
+ withRTLDiff,
8
+ } from '../../../.storybook/decorators/RtlDiffDecorator';
5
9
  import Upload from '..';
6
10
 
7
11
  export default {
@@ -13,30 +17,42 @@ export default {
13
17
  type Story = StoryObj<typeof Upload>;
14
18
 
15
19
  export const Sizes: Story = {
16
- render: () => (
17
- <>
18
- <Upload usLabel="Small upload" size="sm" />
19
- <Upload usLabel="Medium upload" size="md" />
20
- <Upload usLabel="Large upload" size="lg" />
21
- </>
22
- ),
23
- ...withRTLDiff(),
20
+ render: () => {
21
+ const i18n = useRtlDiffI18n();
22
+ return (
23
+ <>
24
+ <Upload usLabel={i18n.smallUpload} size="sm" />
25
+ <Upload usLabel={i18n.mediumUpload} size="md" />
26
+ <Upload usLabel={i18n.largeUpload} size="lg" />
27
+ </>
28
+ );
29
+ },
30
+ ...withRTLDiff({
31
+ i18n: {
32
+ smallUpload: { en: 'Small upload', ar: 'منطقة رفع صغيرة' },
33
+ mediumUpload: { en: 'Medium upload', ar: 'منطقة رفع متوسطة' },
34
+ largeUpload: { en: 'Large upload', ar: 'منطقة رفع كبيرة' },
35
+ },
36
+ }),
24
37
  };
25
38
 
26
39
  export const WithError: Story = {
27
- render: () => (
28
- <Upload
29
- usAccept="*"
30
- usLabel="Upload a file"
31
- usPlaceholder="Maximum filesize is 1B"
32
- maxSize={1}
33
- size="md"
34
- httpOptions={{
35
- url: 'https://httpbin.org/post',
36
- method: 'POST',
37
- }}
38
- />
39
- ),
40
+ render: () => {
41
+ const i18n = useRtlDiffI18n();
42
+ return (
43
+ <Upload
44
+ usAccept="*"
45
+ usLabel={i18n.label}
46
+ usPlaceholder={i18n.placeholder}
47
+ maxSize={1}
48
+ size="md"
49
+ httpOptions={{
50
+ url: 'https://httpbin.org/post',
51
+ method: 'POST',
52
+ }}
53
+ />
54
+ );
55
+ },
40
56
  play: async ({ canvasElement }) => {
41
57
  await forEachColumn(canvasElement, async (column) => {
42
58
  const fileInput = column.querySelector<HTMLInputElement>('input[type="file"]');
@@ -45,9 +61,16 @@ export const WithError: Story = {
45
61
  type: 'text/plain',
46
62
  });
47
63
  await userEvent.upload(fileInput, file);
48
- const scope = within(column);
49
- await scope.findByText(/Maximum filesize is/i, {}, { timeout: 3000 });
64
+ await waitFor(
65
+ async () => expect(column.querySelector('.upload-error-message')).not.toBeNull(),
66
+ { timeout: 3000 },
67
+ );
50
68
  });
51
69
  },
52
- ...withRTLDiff(),
70
+ ...withRTLDiff({
71
+ i18n: {
72
+ label: { en: 'Upload a file', ar: 'رفع ملف' },
73
+ placeholder: { en: 'Maximum filesize is 1B', ar: 'الحد الأقصى لحجم الملف هو ١ بايت' },
74
+ },
75
+ }),
53
76
  };
@@ -5,7 +5,7 @@ import { Status } from '../../common';
5
5
  import UploadInput, { UploadInputProps } from '../UploadInput';
6
6
  import { UploadedFile, UploadResponse } from '../types';
7
7
  import { userEvent } from 'storybook/test';
8
- import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
8
+ import { useRtlDiffI18n, withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
9
9
 
10
10
  const meta: Meta<typeof UploadInput> = {
11
11
  title: 'Forms/UploadInput/Tests',
@@ -305,45 +305,67 @@ export const DeletingBottom: Story = {
305
305
  const noOpUpload = async () => ({ id: 'upload-1' });
306
306
  const noOpDelete = async () => {};
307
307
 
308
- const mixedFiles = [
309
- { id: 'file-1', filename: 'document-front.pdf', url: '#' },
310
- { id: 'file-2', filename: 'succeeded-file.pdf', url: '#' },
311
- { id: 'file-3', filename: 'failed-file.png', status: Status.FAILED },
312
- { id: 'file-4', filename: 'valid-document.pdf', url: '#' },
313
- {
314
- id: 'file-5',
315
- filename: 'too-large-image.png',
316
- status: Status.FAILED,
317
- errors: [
318
- 'File size exceeds the 5MB limit',
319
- 'Please compress the image or choose a smaller file',
320
- 'Supported formats: JPG, PNG under 5MB',
321
- ],
322
- },
323
- {
324
- id: 'file-6',
325
- filename: 'corrupted-file.pdf',
326
- status: Status.FAILED,
327
- error: 'File could not be processed',
328
- },
329
- ];
330
-
331
308
  export const RTLDiff: Story = {
332
- render: () => (
333
- <>
334
- <UploadInput onUploadFile={noOpUpload} />
335
- <UploadInput
336
- files={[{ id: 'file-s', filename: 'single-upload.pdf', url: '#' }]}
337
- onUploadFile={noOpUpload}
338
- onDeleteFile={noOpDelete}
339
- />
340
- <UploadInput
341
- multiple
342
- files={mixedFiles}
343
- onUploadFile={noOpUpload}
344
- onDeleteFile={noOpDelete}
345
- />
346
- </>
347
- ),
348
- ...withRTLDiff({ renderAs: 'iframe' }),
309
+ render: () => {
310
+ const i18n = useRtlDiffI18n();
311
+ const mixedFiles = [
312
+ { id: 'file-1', filename: i18n.documentFront, url: '#' },
313
+ { id: 'file-2', filename: i18n.succeededFile, url: '#' },
314
+ { id: 'file-3', filename: i18n.failedFile, status: Status.FAILED },
315
+ { id: 'file-4', filename: i18n.validDocument, url: '#' },
316
+ {
317
+ id: 'file-5',
318
+ filename: i18n.tooLargeImage,
319
+ status: Status.FAILED,
320
+ errors: [i18n.sizeLimitError, i18n.compressHint, i18n.supportedFormats],
321
+ },
322
+ {
323
+ id: 'file-6',
324
+ filename: i18n.corruptedFile,
325
+ status: Status.FAILED,
326
+ error: i18n.processingError,
327
+ },
328
+ ];
329
+ return (
330
+ <>
331
+ <UploadInput onUploadFile={noOpUpload} />
332
+ <UploadInput
333
+ files={[{ id: 'file-s', filename: i18n.singleUpload, url: '#' }]}
334
+ onUploadFile={noOpUpload}
335
+ onDeleteFile={noOpDelete}
336
+ />
337
+ <UploadInput
338
+ multiple
339
+ files={mixedFiles}
340
+ onUploadFile={noOpUpload}
341
+ onDeleteFile={noOpDelete}
342
+ />
343
+ </>
344
+ );
345
+ },
346
+ ...withRTLDiff({
347
+ renderAs: 'iframe',
348
+ i18n: {
349
+ singleUpload: { en: 'single-upload.pdf', ar: 'تحميل-واحد.pdf' },
350
+ documentFront: { en: 'document-front.pdf', ar: 'مستند-الوجه-الأمامي.pdf' },
351
+ succeededFile: { en: 'succeeded-file.pdf', ar: 'ملف-ناجح.pdf' },
352
+ failedFile: { en: 'failed-file.png', ar: 'ملف-فاشل.png' },
353
+ validDocument: { en: 'valid-document.pdf', ar: 'مستند-صالح.pdf' },
354
+ tooLargeImage: { en: 'too-large-image.png', ar: 'صورة-كبيرة-جدًا.png' },
355
+ corruptedFile: { en: 'corrupted-file.pdf', ar: 'ملف-تالف.pdf' },
356
+ sizeLimitError: {
357
+ en: 'File size exceeds the 5MB limit',
358
+ ar: 'حجم الملف يتجاوز الحد الأقصى 5 ميغابايت',
359
+ },
360
+ compressHint: {
361
+ en: 'Please compress the image or choose a smaller file',
362
+ ar: 'يُرجى ضغط الصورة أو اختيار ملف أصغر',
363
+ },
364
+ supportedFormats: {
365
+ en: 'Supported formats: JPG, PNG under 5MB',
366
+ ar: 'الصيغ المدعومة: JPG وPNG بحجم أقل من 5 ميغابايت',
367
+ },
368
+ processingError: { en: 'File could not be processed', ar: 'تعذّر معالجة الملف' },
369
+ },
370
+ }),
349
371
  };
@@ -3,7 +3,7 @@ import { Meta, StoryObj } from '@storybook/react-webpack5';
3
3
  import { userEvent, within, expect, waitFor } from 'storybook/test';
4
4
  import { Button, Field, SelectInput, Sentiment } from '../../..';
5
5
  import Alert, { type AlertProps, AlertArrowPosition } from '../Alert';
6
- import { withRTLDiff } from '../../../../.storybook/decorators/RtlDiffDecorator';
6
+ import { useRtlDiffI18n, withRTLDiff } from '../../../../.storybook/decorators/RtlDiffDecorator';
7
7
 
8
8
  const meta = {
9
9
  title: 'Prompts/Alert/Tests',
@@ -134,27 +134,48 @@ export const MultipleDynamicAlerts: Story = {
134
134
  };
135
135
 
136
136
  export const RTLDiff: Story = {
137
- render: () => (
138
- <>
139
- <Alert message="Basic alert without dismiss button." />
140
- <Alert message="Alert with dismiss button." onDismiss={() => {}} />
141
- <Alert
142
- title="With title and link action"
143
- message="Alert with a link action and dismiss."
144
- action={{ href: '#', text: 'Read more' }}
145
- onDismiss={() => {}}
146
- />
147
- <Alert
148
- title="With title and button action"
149
- message="Alert with a button action."
150
- action={{ onClick: () => {}, text: 'Open', as: 'button' }}
151
- onDismiss={() => {}}
152
- />
153
- <Alert message="Arrow top left." arrow={AlertArrowPosition.TOP_LEFT} />
154
- <Alert message="Arrow top right." arrow={AlertArrowPosition.TOP_RIGHT} />
155
- <Alert message="Arrow bottom left." arrow={AlertArrowPosition.BOTTOM_LEFT} />
156
- <Alert message="Arrow bottom right." arrow={AlertArrowPosition.BOTTOM_RIGHT} />
157
- </>
158
- ),
159
- ...withRTLDiff(),
137
+ render: () => {
138
+ const i18n = useRtlDiffI18n();
139
+ return (
140
+ <>
141
+ <Alert message={i18n.basic} />
142
+ <Alert message={i18n.dismissible} onDismiss={() => {}} />
143
+ <Alert
144
+ title={i18n.linkActionTitle}
145
+ message={i18n.linkActionMessage}
146
+ action={{ href: '#', text: i18n.readMore }}
147
+ onDismiss={() => {}}
148
+ />
149
+ <Alert
150
+ title={i18n.buttonActionTitle}
151
+ message={i18n.buttonActionMessage}
152
+ action={{ onClick: () => {}, text: i18n.open, as: 'button' }}
153
+ onDismiss={() => {}}
154
+ />
155
+ <Alert message={i18n.arrowTopLeft} arrow={AlertArrowPosition.TOP_LEFT} />
156
+ <Alert message={i18n.arrowTopRight} arrow={AlertArrowPosition.TOP_RIGHT} />
157
+ <Alert message={i18n.arrowBottomLeft} arrow={AlertArrowPosition.BOTTOM_LEFT} />
158
+ <Alert message={i18n.arrowBottomRight} arrow={AlertArrowPosition.BOTTOM_RIGHT} />
159
+ </>
160
+ );
161
+ },
162
+ ...withRTLDiff({
163
+ i18n: {
164
+ basic: { en: 'Basic alert without dismiss button.', ar: 'تنبيه أساسي بدون زر إغلاق.' },
165
+ dismissible: { en: 'Alert with dismiss button.', ar: 'تنبيه مع زر إغلاق.' },
166
+ linkActionTitle: { en: 'With title and link action', ar: 'مع عنوان وإجراء رابط' },
167
+ linkActionMessage: {
168
+ en: 'Alert with a link action and dismiss.',
169
+ ar: 'تنبيه مع إجراء رابط وزر إغلاق.',
170
+ },
171
+ readMore: { en: 'Read more', ar: 'اقرأ المزيد' },
172
+ buttonActionTitle: { en: 'With title and button action', ar: 'مع عنوان وإجراء زر' },
173
+ buttonActionMessage: { en: 'Alert with a button action.', ar: 'تنبيه مع إجراء زر.' },
174
+ open: { en: 'Open', ar: 'فتح' },
175
+ arrowTopLeft: { en: 'Arrow top left.', ar: 'سهم أعلى اليسار.' },
176
+ arrowTopRight: { en: 'Arrow top right.', ar: 'سهم أعلى اليمين.' },
177
+ arrowBottomLeft: { en: 'Arrow bottom left.', ar: 'سهم أسفل اليسار.' },
178
+ arrowBottomRight: { en: 'Arrow bottom right.', ar: 'سهم أسفل اليمين.' },
179
+ },
180
+ }),
160
181
  };