@transferwise/components 46.159.0 → 46.159.1

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 (179) hide show
  1. package/build/i18n/cs.json +5 -0
  2. package/build/i18n/cs.json.js +5 -0
  3. package/build/i18n/cs.json.js.map +1 -1
  4. package/build/i18n/cs.json.mjs +5 -0
  5. package/build/i18n/cs.json.mjs.map +1 -1
  6. package/build/i18n/de.json +5 -0
  7. package/build/i18n/de.json.js +5 -0
  8. package/build/i18n/de.json.js.map +1 -1
  9. package/build/i18n/de.json.mjs +5 -0
  10. package/build/i18n/de.json.mjs.map +1 -1
  11. package/build/i18n/es.json +5 -0
  12. package/build/i18n/es.json.js +5 -0
  13. package/build/i18n/es.json.js.map +1 -1
  14. package/build/i18n/es.json.mjs +5 -0
  15. package/build/i18n/es.json.mjs.map +1 -1
  16. package/build/i18n/fr.json +5 -0
  17. package/build/i18n/fr.json.js +5 -0
  18. package/build/i18n/fr.json.js.map +1 -1
  19. package/build/i18n/fr.json.mjs +5 -0
  20. package/build/i18n/fr.json.mjs.map +1 -1
  21. package/build/i18n/hu.json +5 -0
  22. package/build/i18n/hu.json.js +5 -0
  23. package/build/i18n/hu.json.js.map +1 -1
  24. package/build/i18n/hu.json.mjs +5 -0
  25. package/build/i18n/hu.json.mjs.map +1 -1
  26. package/build/i18n/id.json +5 -0
  27. package/build/i18n/id.json.js +5 -0
  28. package/build/i18n/id.json.js.map +1 -1
  29. package/build/i18n/id.json.mjs +5 -0
  30. package/build/i18n/id.json.mjs.map +1 -1
  31. package/build/i18n/it.json +5 -0
  32. package/build/i18n/it.json.js +5 -0
  33. package/build/i18n/it.json.js.map +1 -1
  34. package/build/i18n/it.json.mjs +5 -0
  35. package/build/i18n/it.json.mjs.map +1 -1
  36. package/build/i18n/ja.json +5 -0
  37. package/build/i18n/ja.json.js +5 -0
  38. package/build/i18n/ja.json.js.map +1 -1
  39. package/build/i18n/ja.json.mjs +5 -0
  40. package/build/i18n/ja.json.mjs.map +1 -1
  41. package/build/i18n/nl.json +5 -0
  42. package/build/i18n/nl.json.js +5 -0
  43. package/build/i18n/nl.json.js.map +1 -1
  44. package/build/i18n/nl.json.mjs +5 -0
  45. package/build/i18n/nl.json.mjs.map +1 -1
  46. package/build/i18n/pl.json +5 -0
  47. package/build/i18n/pl.json.js +5 -0
  48. package/build/i18n/pl.json.js.map +1 -1
  49. package/build/i18n/pl.json.mjs +5 -0
  50. package/build/i18n/pl.json.mjs.map +1 -1
  51. package/build/i18n/pt.json +5 -0
  52. package/build/i18n/pt.json.js +5 -0
  53. package/build/i18n/pt.json.js.map +1 -1
  54. package/build/i18n/pt.json.mjs +5 -0
  55. package/build/i18n/pt.json.mjs.map +1 -1
  56. package/build/i18n/ro.json +5 -0
  57. package/build/i18n/ro.json.js +5 -0
  58. package/build/i18n/ro.json.js.map +1 -1
  59. package/build/i18n/ro.json.mjs +5 -0
  60. package/build/i18n/ro.json.mjs.map +1 -1
  61. package/build/i18n/ru.json +5 -0
  62. package/build/i18n/ru.json.js +5 -0
  63. package/build/i18n/ru.json.js.map +1 -1
  64. package/build/i18n/ru.json.mjs +5 -0
  65. package/build/i18n/ru.json.mjs.map +1 -1
  66. package/build/i18n/th.json +5 -0
  67. package/build/i18n/th.json.js +5 -0
  68. package/build/i18n/th.json.js.map +1 -1
  69. package/build/i18n/th.json.mjs +5 -0
  70. package/build/i18n/th.json.mjs.map +1 -1
  71. package/build/i18n/uk.json +5 -0
  72. package/build/i18n/uk.json.js +5 -0
  73. package/build/i18n/uk.json.js.map +1 -1
  74. package/build/i18n/uk.json.mjs +5 -0
  75. package/build/i18n/uk.json.mjs.map +1 -1
  76. package/build/i18n/zh-HK.json +5 -0
  77. package/build/i18n/zh-HK.json.js +5 -0
  78. package/build/i18n/zh-HK.json.js.map +1 -1
  79. package/build/i18n/zh-HK.json.mjs +5 -0
  80. package/build/i18n/zh-HK.json.mjs.map +1 -1
  81. package/build/main.css +4 -4104
  82. package/build/styles/ListItem/ListItem.css +1 -0
  83. package/build/styles/PocketSurface/PocketSurface.css +2 -11
  84. package/build/styles/SentimentSurface/SentimentSurface.css +0 -23
  85. package/build/styles/css/neptune.css +0 -2821
  86. package/build/styles/main.css +4 -4104
  87. package/build/styles/styles/less/neptune.css +0 -2821
  88. package/build/types/ListItem/_stories/variants/helpers.d.ts.map +1 -1
  89. package/package.json +10 -10
  90. package/src/Accordion/_stories/Accordion.test.story.tsx +71 -0
  91. package/src/AvatarLayout/_stories/AvatarLayout.test.story.tsx +64 -0
  92. package/src/AvatarView/_stories/AvatarView.test.story.tsx +151 -0
  93. package/src/Button/LegacyButton/_stories/LegacyButton.test.story.tsx +22 -0
  94. package/src/Button/_stories/Button.test.story.tsx +65 -0
  95. package/src/Calendar/_stories/Calendar.test.story.tsx +73 -24
  96. package/src/Carousel/_stories/Carousel.test.story.tsx +59 -0
  97. package/src/Checkbox/_stories/Checkbox.test.story.tsx +20 -0
  98. package/src/CheckboxButton/_stories/CheckboxButton.test.story.tsx +17 -37
  99. package/src/Chevron/_stories/Chevron.test.story.tsx +26 -0
  100. package/src/Chips/_stories/Chips.test.story.tsx +39 -34
  101. package/src/CircularButton/_stories/CircularButton.test.story.tsx +0 -68
  102. package/src/DateInput/_stories/DateInput.test.story.tsx +13 -0
  103. package/src/DateLookup/_stories/DateLookup.rtl.test.story.tsx +88 -0
  104. package/src/Decision/_stories/Decision.test.story.tsx +79 -0
  105. package/src/DefinitionList/_stories/DefinitionList.test.story.tsx +54 -1
  106. package/src/Drawer/_stories/Drawer.rtl.test.story.tsx +58 -0
  107. package/src/ExpressiveMoneyInput/_stories/ExpressiveMoneyInput.rtl.test.story.tsx +118 -0
  108. package/src/Field/_stories/Field.test.story.tsx +46 -0
  109. package/src/FlowNavigation/_stories/FlowNavigation.test.story.tsx +44 -0
  110. package/src/Header/_stories/Header.test.story.tsx +27 -0
  111. package/src/Info/_stories/Info.rtl.test.story.tsx +64 -0
  112. package/src/Inputs/SelectInput/_stories/SelectInput.rtl.test.story.tsx +135 -0
  113. package/src/Inputs/_stories/InputGroup.test.story.tsx +69 -0
  114. package/src/Inputs/_stories/SearchInput.test.story.tsx +32 -0
  115. package/src/Inputs/_stories/TextArea.test.story.tsx +27 -0
  116. package/src/InstructionsList/_stories/InstructionsList.test.story.tsx +30 -0
  117. package/src/Label/_stories/Label.test.story.tsx +36 -0
  118. package/src/Link/_stories/Link.test.story.tsx +26 -0
  119. package/src/ListItem/ListItem.css +1 -0
  120. package/src/ListItem/_stories/{variants/ListItem.rtl.test.story.tsx → ListItem.rtl.test.story.tsx} +6 -10
  121. package/src/ListItem/_stories/variants/helpers.tsx +2 -6
  122. package/src/Logo/_stories/Logo.test.story.tsx +44 -0
  123. package/src/Modal/_stories/Modal.rtl.test.story.tsx +59 -0
  124. package/src/MoneyInput/_stories/MoneyInput.rtl.test.story.tsx +88 -0
  125. package/src/Nudge/_stories/Nudge.test.story.tsx +37 -0
  126. package/src/PhoneNumberInput/_stories/PhoneNumberInput.test.story.tsx +44 -0
  127. package/src/PocketSurface/PocketSurface.css +2 -11
  128. package/src/PocketSurface/PocketSurface.less +1 -1
  129. package/src/Popover/_stories/Popover.rtl.test.story.tsx +96 -0
  130. package/src/Progress/_stories/Progress.test.story.tsx +27 -0
  131. package/src/ProgressBar/_stories/ProgressBar.test.story.tsx +33 -0
  132. package/src/PromoCard/_stories/PromoCard.test.story.tsx +42 -0
  133. package/src/PromoCard/_stories/PromoCardGroup.test.story.tsx +51 -0
  134. package/src/Prompt/ActionPrompt/_stories/ActionPrompt.test.story.tsx +42 -1
  135. package/src/Prompt/CriticalBanner/_stories/CriticalBanner.test.story.tsx +34 -31
  136. package/src/Prompt/InfoPrompt/_stories/InfoPrompt.test.story.tsx +25 -0
  137. package/src/Prompt/InlinePrompt/_stories/InlinePrompt.test.story.tsx +27 -0
  138. package/src/Radio/_stories/Radio.test.story.tsx +61 -0
  139. package/src/RadioGroup/_stories/RadioGroup.test.story.tsx +56 -0
  140. package/src/Section/_stories/Section.test.story.tsx +29 -0
  141. package/src/SegmentedControl/_stories/SegmentedControl.test.story.tsx +45 -0
  142. package/src/SentimentSurface/SentimentSurface.css +0 -23
  143. package/src/SlidingPanel/_stories/SlidingPanel.rtl.test.story.tsx +70 -0
  144. package/src/Snackbar/_stories/Snackbar.rtl.test.story.tsx +45 -0
  145. package/src/Snackbar/_stories/Snackbar.test.story.tsx +0 -31
  146. package/src/Stepper/_stories/Stepper.test.story.tsx +17 -0
  147. package/src/Switch/_stories/Switch.test.story.tsx +20 -26
  148. package/src/Table/_stories/Table.test.story.tsx +104 -0
  149. package/src/Tabs/_stories/Tabs.test.story.tsx +72 -0
  150. package/src/TextareaWithDisplayFormat/_stories/TextareaWithDisplayFormat.test.story.tsx +48 -0
  151. package/src/Tooltip/_stories/Tooltip.rtl.test.story.tsx +79 -0
  152. package/src/Typeahead/_stories/Typeahead.rtl.test.story.tsx +90 -0
  153. package/src/Upload/_stories/Upload.rtl.test.story.tsx +53 -0
  154. package/src/UploadInput/_stories/UploadInput.test.story.tsx +47 -0
  155. package/src/_deprecated/Alert/_stories/Alert.test.story.tsx +28 -1
  156. package/src/_deprecated/Card/_stories/Card.test.story.tsx +38 -0
  157. package/src/_deprecated/CriticalBanner/_stories/CriticalCommsBanner.test.story.tsx +18 -0
  158. package/src/_deprecated/InlineAlert/_stories/InlineAlert.test.story.tsx +26 -0
  159. package/src/_deprecated/OverlayHeader/_stories/OverlayHeader.test.story.tsx +42 -0
  160. package/src/_deprecated/Select/_stories/Select.rtl.test.story.tsx +71 -0
  161. package/src/common/BottomSheet/_stories/BottomSheet.test.story.tsx +23 -0
  162. package/src/i18n/cs.json +5 -0
  163. package/src/i18n/de.json +5 -0
  164. package/src/i18n/es.json +5 -0
  165. package/src/i18n/fr.json +5 -0
  166. package/src/i18n/hu.json +5 -0
  167. package/src/i18n/id.json +5 -0
  168. package/src/i18n/it.json +5 -0
  169. package/src/i18n/ja.json +5 -0
  170. package/src/i18n/nl.json +5 -0
  171. package/src/i18n/pl.json +5 -0
  172. package/src/i18n/pt.json +5 -0
  173. package/src/i18n/ro.json +5 -0
  174. package/src/i18n/ru.json +5 -0
  175. package/src/i18n/th.json +5 -0
  176. package/src/i18n/uk.json +5 -0
  177. package/src/i18n/zh-HK.json +5 -0
  178. package/src/main.css +4 -4104
  179. package/src/styles/less/neptune.css +0 -2821
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../../../src/ListItem/_stories/variants/helpers.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAGrD,OAAO,EAML,uBAAuB,IAAI,WAAW,EACvC,MAAM,kBAAkB,CAAC;AAG1B,KAAK,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,KAAK,GAAG,cAAc,GAAG,cAAc,GAAG,QAAQ,GAAG,MAAM,CAAC;AAOhG,KAAK,iBAAiB,GAAG;IACvB,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,KAAK,YAAY,GAAG,QAAQ,CAAC,iBAAiB,CAAC,CAAC;AAEhD,eAAO,MAAM,YAAY,EAAE,YAiI1B,CAAC"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../../../src/ListItem/_stories/variants/helpers.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAGrD,OAAO,EAML,uBAAuB,IAAI,WAAW,EACvC,MAAM,kBAAkB,CAAC;AAG1B,KAAK,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,KAAK,GAAG,cAAc,GAAG,cAAc,GAAG,QAAQ,GAAG,MAAM,CAAC;AAOhG,KAAK,iBAAiB,GAAG;IACvB,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,KAAK,YAAY,GAAG,QAAQ,CAAC,iBAAiB,CAAC,CAAC;AAEhD,eAAO,MAAM,YAAY,EAAE,YA6H1B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@transferwise/components",
3
- "version": "46.159.0",
3
+ "version": "46.159.1",
4
4
  "description": "Neptune React components",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -44,17 +44,17 @@
44
44
  "@babel/preset-env": "^7.29.7",
45
45
  "@babel/preset-react": "^7.29.7",
46
46
  "@babel/preset-typescript": "^7.29.7",
47
- "@formatjs/cli": "^6.16.11",
47
+ "@formatjs/cli": "^6.16.14",
48
48
  "@rollup/plugin-babel": "^7.1.0",
49
49
  "@rollup/plugin-json": "^6.1.0",
50
50
  "@rollup/plugin-node-resolve": "^16.0.3",
51
51
  "@rollup/plugin-typescript": "^12.3.0",
52
52
  "@rollup/plugin-url": "^8.0.2",
53
- "@storybook/addon-a11y": "^10.4.6",
54
- "@storybook/addon-docs": "^10.4.6",
53
+ "@storybook/addon-a11y": "^10.5.4",
54
+ "@storybook/addon-docs": "^10.5.4",
55
55
  "@storybook/addon-mcp": "^0.6.0",
56
56
  "@storybook/addon-webpack5-compiler-babel": "^4.0.1",
57
- "@storybook/react-webpack5": "^10.4.6",
57
+ "@storybook/react-webpack5": "^10.5.4",
58
58
  "@testing-library/dom": "^10.4.1",
59
59
  "@testing-library/jest-dom": "^6.9.1",
60
60
  "@testing-library/react": "^16.3.2",
@@ -75,22 +75,22 @@
75
75
  "monaco-editor-webpack-plugin": "^7.1.1",
76
76
  "@wise/art": "^2.31.1",
77
77
  "@wise/eslint-config": "^14.2.1",
78
- "babel-plugin-formatjs": "^11.3.14",
78
+ "babel-plugin-formatjs": "^11.3.16",
79
79
  "eslint": "^9.39.4",
80
- "eslint-plugin-storybook": "^10.4.6",
80
+ "eslint-plugin-storybook": "^10.5.4",
81
81
  "gulp": "^5.0.1",
82
82
  "jest": "^29.7.0",
83
83
  "jest-environment-jsdom": "^29.7.0",
84
- "jest-fetch-mock": "^3.0.3",
84
+ "jest-fetch-mock": "^3.2.0",
85
85
  "jsdom-testing-mocks": "^1.16.0",
86
86
  "lodash.times": "^4.3.2",
87
87
  "react-intl": "^7.1.14",
88
88
  "react-live": "^4.1.8",
89
89
  "rollup": "^4.62.2",
90
90
  "rollup-preserve-directives": "^1.1.3",
91
- "storybook": "^10.4.6",
91
+ "storybook": "^10.5.4",
92
92
  "storybook-addon-tag-badges": "^3.1.0",
93
- "storybook-addon-test-codegen": "^3.0.1",
93
+ "storybook-addon-test-codegen": "^3.0.4",
94
94
  "@transferwise/less-config": "3.1.2",
95
95
  "@wise/components-theming": "1.10.3",
96
96
  "@wise/wds-configs": "0.0.0"
@@ -0,0 +1,71 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
+ import { userEvent, within } from 'storybook/test';
3
+ import { FastFlag as FastFlagIcon } from '@transferwise/icons';
4
+
5
+ import { forEachColumn, withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
6
+ import Accordion from '../Accordion';
7
+
8
+ const items = [
9
+ {
10
+ title: 'Item with icon',
11
+ subtitle: 'Subtitle text',
12
+ content: 'Content for item with icon.',
13
+ id: 'icon',
14
+ icon: <FastFlagIcon size={24} />,
15
+ },
16
+ {
17
+ title: 'Plain item without icon',
18
+ content: 'Content for item without icon.',
19
+ id: 'no-icon',
20
+ },
21
+ {
22
+ title: 'Media with circle',
23
+ subtitle: 'Shows media in a circle',
24
+ content: 'Expanded content with media circle.',
25
+ id: 'media-circle',
26
+ media: (
27
+ <img
28
+ src="https://wise.com/public-resources/assets/spend/card/asset//digital_card_2023.png"
29
+ alt=""
30
+ />
31
+ ),
32
+ showMediaCircle: true,
33
+ showMediaAtAllSizes: true,
34
+ isContainerAligned: true,
35
+ },
36
+ {
37
+ title: 'Media without circle',
38
+ subtitle: 'Not container aligned',
39
+ content: 'Expanded content with plain media.',
40
+ id: 'media-no-circle',
41
+ media: (
42
+ <img
43
+ src="https://wise.com/public-resources/assets/spend/card/asset//digital_card_2023.png"
44
+ alt=""
45
+ />
46
+ ),
47
+ showMediaCircle: false,
48
+ showMediaAtAllSizes: false,
49
+ isContainerAligned: false,
50
+ },
51
+ ];
52
+
53
+ export default {
54
+ component: Accordion,
55
+ title: 'Content/Accordion/Tests',
56
+ tags: ['!autodocs', '!manifest'],
57
+ } satisfies Meta<typeof Accordion>;
58
+
59
+ type Story = StoryObj<typeof Accordion>;
60
+
61
+ export const RTLDiff: Story = {
62
+ render: () => <Accordion items={items} indexOpen={0} />,
63
+ play: async ({ canvasElement }) => {
64
+ await forEachColumn(canvasElement, async (column) => {
65
+ const scope = within(column);
66
+ const buttons = scope.getAllByRole('button');
67
+ await userEvent.click(buttons[1]);
68
+ });
69
+ },
70
+ ...withRTLDiff(),
71
+ };
@@ -2,6 +2,7 @@ import { Meta, StoryObj } from '@storybook/react-webpack5';
2
2
  import AvatarLayout from '..';
3
3
  import { Freeze, Plane } from '@transferwise/icons';
4
4
  import { Flag } from '@wise/art';
5
+ import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
5
6
 
6
7
  const meta: Meta<typeof AvatarLayout> = {
7
8
  component: AvatarLayout,
@@ -115,3 +116,66 @@ export const EdgeInstances: Story = {
115
116
  </div>
116
117
  ),
117
118
  };
119
+
120
+ export const RTLDiff: Story = {
121
+ render: () => (
122
+ <>
123
+ <AvatarLayout
124
+ orientation="horizontal"
125
+ size={48}
126
+ avatars={[{ asset: <Flag code="br" /> }, { asset: <Flag code="jp" /> }]}
127
+ />
128
+
129
+ <AvatarLayout
130
+ orientation="horizontal"
131
+ size={48}
132
+ interactive
133
+ avatars={[{ asset: <Freeze /> }, { asset: <Freeze /> }]}
134
+ />
135
+
136
+ <AvatarLayout
137
+ orientation="horizontal"
138
+ size={48}
139
+ avatars={[{ profileName: 'Jay Jay' }, { profileName: 'Amy Amy' }]}
140
+ />
141
+
142
+ <AvatarLayout
143
+ orientation="horizontal"
144
+ size={48}
145
+ interactive
146
+ avatars={[{ asset: <Flag code="gb" /> }, { asset: <Flag code="br" /> }, { asset: '3+' }]}
147
+ />
148
+
149
+ <AvatarLayout
150
+ orientation="horizontal"
151
+ size={32}
152
+ avatars={[{ asset: <Flag code="eu" /> }, { asset: <Flag code="gb" /> }]}
153
+ />
154
+
155
+ <AvatarLayout
156
+ orientation="horizontal"
157
+ size={72}
158
+ avatars={[{ asset: <Freeze /> }, { asset: <Freeze /> }, { asset: <Freeze /> }]}
159
+ />
160
+
161
+ <AvatarLayout
162
+ orientation="diagonal"
163
+ size={48}
164
+ avatars={[{ asset: <Flag code="br" /> }, { asset: <Flag code="jp" /> }]}
165
+ />
166
+
167
+ <AvatarLayout
168
+ orientation="diagonal"
169
+ size={48}
170
+ avatars={[{ profileName: 'Jay Jay' }, { profileName: 'Amy Amy' }]}
171
+ />
172
+
173
+ <AvatarLayout
174
+ orientation="diagonal"
175
+ size={72}
176
+ avatars={[{ asset: <Freeze /> }, { asset: <Freeze /> }]}
177
+ />
178
+ </>
179
+ ),
180
+ ...withRTLDiff(),
181
+ };
@@ -3,6 +3,7 @@ import {
3
3
  Camera,
4
4
  Convert,
5
5
  FastFlag,
6
+ Freeze,
6
7
  Graph,
7
8
  Leaf,
8
9
  Money,
@@ -13,6 +14,7 @@ import {
13
14
  import AvatarView from '..';
14
15
  import { getBrandColorFromSeed, getInitials, ProfileType } from '../../common';
15
16
  import Display from '../../Display';
17
+ import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
16
18
  import { withVariantConfig } from '../../../.storybook/helpers';
17
19
 
18
20
  const meta: Meta<typeof AvatarView> = {
@@ -220,3 +222,152 @@ export const BadgeVariants: Story = {
220
222
  },
221
223
  ...withVariantConfig(['default', 'dark']),
222
224
  };
225
+
226
+ const sizes = [24, 32, 40, 48, 56, 72] as const;
227
+
228
+ export const RTLDiff: Story = {
229
+ render: () => (
230
+ <>
231
+ {/* Badge positioning: bottom-right dot (notification/online) — key RTL indicator */}
232
+ <div
233
+ style={{
234
+ display: 'grid',
235
+ gridTemplateColumns: `repeat(${sizes.length}, min-content)`,
236
+ gap: '1rem',
237
+ alignItems: 'center',
238
+ }}
239
+ >
240
+ {sizes.map((size) => (
241
+ <AvatarView key={`notif-${size}`} size={size} badge={{ type: 'notification' }}>
242
+ <Freeze />
243
+ </AvatarView>
244
+ ))}
245
+ </div>
246
+
247
+ {/* Online dot */}
248
+ <div
249
+ style={{
250
+ display: 'grid',
251
+ gridTemplateColumns: `repeat(${sizes.length}, min-content)`,
252
+ gap: '1rem',
253
+ alignItems: 'center',
254
+ }}
255
+ >
256
+ {sizes.map((size) => (
257
+ <AvatarView key={`online-${size}`} size={size} badge={{ type: 'online' }}>
258
+ <Freeze />
259
+ </AvatarView>
260
+ ))}
261
+ </div>
262
+
263
+ {/* Badge with flag (bottom-right corner badge) */}
264
+ <div
265
+ style={{
266
+ display: 'grid',
267
+ gridTemplateColumns: `repeat(${sizes.length}, min-content)`,
268
+ gap: '1rem',
269
+ alignItems: 'center',
270
+ }}
271
+ >
272
+ {sizes.map((size) => (
273
+ <AvatarView key={`flag-${size}`} size={size} badge={{ flagCode: 'GBP' }}>
274
+ <Freeze />
275
+ </AvatarView>
276
+ ))}
277
+ </div>
278
+
279
+ {/* Badge with icon */}
280
+ <div
281
+ style={{
282
+ display: 'grid',
283
+ gridTemplateColumns: `repeat(${sizes.length}, min-content)`,
284
+ gap: '1rem',
285
+ alignItems: 'center',
286
+ }}
287
+ >
288
+ {sizes.map((size) => (
289
+ <AvatarView key={`icon-badge-${size}`} size={size} badge={{ icon: <FastFlag /> }}>
290
+ <Freeze />
291
+ </AvatarView>
292
+ ))}
293
+ </div>
294
+
295
+ {/* Badge type action with icon (camera) */}
296
+ <div
297
+ style={{
298
+ display: 'grid',
299
+ gridTemplateColumns: `repeat(${sizes.length}, min-content)`,
300
+ gap: '1rem',
301
+ alignItems: 'center',
302
+ }}
303
+ >
304
+ {sizes.map((size) => (
305
+ <AvatarView
306
+ key={`action-${size}`}
307
+ size={size}
308
+ imgSrc="../avatar-square-dude.webp"
309
+ badge={{ type: 'action', icon: <Camera /> }}
310
+ />
311
+ ))}
312
+ </div>
313
+
314
+ {/* Badge type reference with icon */}
315
+ <div
316
+ style={{
317
+ display: 'grid',
318
+ gridTemplateColumns: `repeat(${sizes.length}, min-content)`,
319
+ gap: '1rem',
320
+ alignItems: 'center',
321
+ }}
322
+ >
323
+ {sizes.map((size) => (
324
+ <AvatarView
325
+ key={`ref-${size}`}
326
+ size={size}
327
+ imgSrc="../avatar-square-dude.webp"
328
+ badge={{ type: 'reference', icon: <Convert /> }}
329
+ />
330
+ ))}
331
+ </div>
332
+
333
+ {/* Selected state (border highlight) */}
334
+ <div
335
+ style={{
336
+ display: 'grid',
337
+ gridTemplateColumns: `repeat(${sizes.length}, min-content)`,
338
+ gap: '1rem',
339
+ alignItems: 'center',
340
+ }}
341
+ >
342
+ {sizes.map((size) => (
343
+ <AvatarView key={`selected-${size}`} size={size} selected interactive>
344
+ <Freeze />
345
+ </AvatarView>
346
+ ))}
347
+ </div>
348
+
349
+ {/* Selected + badge combined */}
350
+ <div
351
+ style={{
352
+ display: 'grid',
353
+ gridTemplateColumns: `repeat(${sizes.length}, min-content)`,
354
+ gap: '1rem',
355
+ alignItems: 'center',
356
+ }}
357
+ >
358
+ {sizes.map((size) => (
359
+ <AvatarView
360
+ key={`selected-badge-${size}`}
361
+ size={size}
362
+ selected
363
+ interactive
364
+ badge={{ flagCode: 'USD' }}
365
+ >
366
+ <Freeze />
367
+ </AvatarView>
368
+ ))}
369
+ </div>
370
+ </>
371
+ ),
372
+ ...withRTLDiff(),
373
+ };
@@ -4,6 +4,7 @@ import { useState } from 'react';
4
4
 
5
5
  import Button from '../..';
6
6
  import LegacyButton from '../LegacyButton';
7
+ import { withRTLDiff } from '../../../../.storybook/decorators/RtlDiffDecorator';
7
8
 
8
9
  LegacyButton.displayName = 'Button';
9
10
 
@@ -35,3 +36,24 @@ export const Focused: Story = {
35
36
  );
36
37
  },
37
38
  };
39
+
40
+ export const RTLDiff: Story = {
41
+ render: () => (
42
+ <>
43
+ {/* default (inline) layout */}
44
+ <LegacyButton>Default button</LegacyButton>
45
+
46
+ {/* block layout — full width */}
47
+ <LegacyButton block>Block button</LegacyButton>
48
+
49
+ {/* loading state — appends ProcessIndicator inside button */}
50
+ <LegacyButton loading>Loading button</LegacyButton>
51
+
52
+ {/* loading + block combined */}
53
+ <LegacyButton loading block>
54
+ Loading block button
55
+ </LegacyButton>
56
+ </>
57
+ ),
58
+ ...withRTLDiff(),
59
+ };
@@ -5,6 +5,7 @@ import { expect, userEvent, within } from 'storybook/test';
5
5
  import Button from '../Button.resolver';
6
6
  import { ButtonPriority } from '../Button.types';
7
7
  import { withVariantConfig } from '../../../.storybook/helpers';
8
+ import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
8
9
 
9
10
  const meta: Meta<typeof Button> = {
10
11
  component: Button,
@@ -165,3 +166,67 @@ export const AccessibilityAddons: Story = {
165
166
  size: 'md',
166
167
  },
167
168
  };
169
+
170
+ export const RTLDiff: Story = {
171
+ render: () => (
172
+ <>
173
+ <Button v2 size="md" addonStart={{ type: 'icon', value: <Freeze /> }}>
174
+ Start icon
175
+ </Button>
176
+
177
+ <Button v2 size="md" addonEnd={{ type: 'icon', value: <ArrowRight /> }}>
178
+ End icon
179
+ </Button>
180
+
181
+ <Button
182
+ v2
183
+ size="md"
184
+ addonStart={{ type: 'icon', value: <Freeze /> }}
185
+ addonEnd={{ type: 'icon', value: <ArrowRight /> }}
186
+ >
187
+ Both icons
188
+ </Button>
189
+
190
+ <Button v2 size="md" addonStart={{ type: 'avatar', value: [{ asset: <Flag code="pl" /> }] }}>
191
+ Avatar start
192
+ </Button>
193
+
194
+ <Button
195
+ v2
196
+ size="md"
197
+ addonStart={{
198
+ type: 'avatar',
199
+ value: [{ asset: <Flag code="gb" /> }, { asset: <Flag code="br" /> }],
200
+ }}
201
+ >
202
+ Double avatar
203
+ </Button>
204
+
205
+ <Button v2 size="sm" addonStart={{ type: 'icon', value: <Freeze /> }}>
206
+ Sm start icon
207
+ </Button>
208
+
209
+ <Button v2 size="sm" addonEnd={{ type: 'icon', value: <ArrowRight /> }}>
210
+ Sm end icon
211
+ </Button>
212
+
213
+ <Button
214
+ v2
215
+ size="sm"
216
+ addonStart={{ type: 'icon', value: <Freeze /> }}
217
+ addonEnd={{ type: 'icon', value: <ArrowRight /> }}
218
+ >
219
+ Sm both icons
220
+ </Button>
221
+
222
+ <Button v2 size="md" loading addonEnd={{ type: 'icon', value: <ArrowRight /> }}>
223
+ Loading
224
+ </Button>
225
+
226
+ <Button v2 size="md" block addonStart={{ type: 'icon', value: <Freeze /> }}>
227
+ Block with start icon
228
+ </Button>
229
+ </>
230
+ ),
231
+ ...withRTLDiff(),
232
+ };
@@ -3,6 +3,7 @@ import { expect, waitFor, within, userEvent } from 'storybook/test';
3
3
 
4
4
  import Calendar from '../Calendar';
5
5
  import type { DisabledRules } from '../Calendar.types';
6
+ import { forEachColumn, withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
6
7
 
7
8
  export default {
8
9
  component: Calendar,
@@ -28,17 +29,19 @@ export const YearViewBoundaries: Story = {
28
29
  await userEvent.click(canvas.getByRole('button', { name: /year view/iu }));
29
30
 
30
31
  // Selected year (within range) is enabled
31
- await expect(
32
- canvas.getByRole('button', { name: /2024.*selected year/iu }),
33
- ).not.toHaveAttribute('aria-disabled');
32
+ await expect(canvas.getByRole('button', { name: /2024.*selected year/iu })).not.toHaveAttribute(
33
+ 'aria-disabled',
34
+ );
34
35
 
35
36
  // Adjacent years outside range are disabled
36
- await expect(
37
- canvas.getByRole('button', { name: /^2023.*not available/iu }),
38
- ).toHaveAttribute('aria-disabled', 'true');
39
- await expect(
40
- canvas.getByRole('button', { name: /^2025.*not available/iu }),
41
- ).toHaveAttribute('aria-disabled', 'true');
37
+ await expect(canvas.getByRole('button', { name: /^2023.*not available/iu })).toHaveAttribute(
38
+ 'aria-disabled',
39
+ 'true',
40
+ );
41
+ await expect(canvas.getByRole('button', { name: /^2025.*not available/iu })).toHaveAttribute(
42
+ 'aria-disabled',
43
+ 'true',
44
+ );
42
45
 
43
46
  // Both nav arrows disabled — min and max are both in the 2020–2039 block
44
47
  await expect(canvas.getByRole('button', { name: /previous 20 years/iu })).toBeDisabled();
@@ -73,12 +76,14 @@ export const MonthViewBoundaries: Story = {
73
76
  ).not.toHaveAttribute('aria-disabled');
74
77
 
75
78
  // Months outside range are disabled
76
- await expect(
77
- canvas.getByRole('button', { name: /^Feb.*not available/iu }),
78
- ).toHaveAttribute('aria-disabled', 'true');
79
- await expect(
80
- canvas.getByRole('button', { name: /^Nov.*not available/iu }),
81
- ).toHaveAttribute('aria-disabled', 'true');
79
+ await expect(canvas.getByRole('button', { name: /^Feb.*not available/iu })).toHaveAttribute(
80
+ 'aria-disabled',
81
+ 'true',
82
+ );
83
+ await expect(canvas.getByRole('button', { name: /^Nov.*not available/iu })).toHaveAttribute(
84
+ 'aria-disabled',
85
+ 'true',
86
+ );
82
87
 
83
88
  // Both nav arrows disabled — min and max are both in 2024
84
89
  await expect(canvas.getByRole('button', { name: /previous year/iu })).toBeDisabled();
@@ -92,23 +97,67 @@ const disabledRules: DisabledRules = {
92
97
  };
93
98
 
94
99
  /**
95
- * When a disabled cell receives direct DOM focus (e.g. screen reader virtual cursor),
100
+ * When a disabled cell receives focus via keyboard navigation,
96
101
  * the inline prompt updates to negative sentiment showing the disabled reason.
97
102
  */
98
103
  export const DisabledDateFocusUpdatesPrompt: Story = {
99
104
  render: () => <Calendar value={new Date(2024, 6, 5)} disabledRules={disabledRules} />,
100
105
  play: async ({ canvasElement }) => {
101
- const canvas = within(canvasElement);
102
-
103
- // Initially prompt is neutral (focused date is enabled)
106
+ // Initially prompt is neutral (focused date is enabled — July 5 is a Friday)
104
107
  const prompt = canvasElement.querySelector('.wds-inline-prompt')!;
105
108
  await expect(prompt).toHaveClass('wds-prompt--neutral');
106
109
 
107
- // Simulate screen reader focus on a disabled Saturday (matches both "6 July 2024" and "July 6, 2024")
108
- const saturday = canvas.getByLabelText(/(?:6 July|July 6).*2024/u);
109
- saturday.focus();
110
+ // Tab into the calendar grid (past month nav buttons), then arrow right to Saturday (disabled)
111
+ await userEvent.tab();
112
+ await userEvent.tab();
113
+ await userEvent.tab();
114
+ await userEvent.keyboard('{ArrowRight}');
110
115
 
111
- // Prompt should switch to negative after React re-render
112
- await waitFor(() => expect(prompt).toHaveClass('wds-prompt--negative'));
116
+ // Prompt should switch to negative after navigating to the disabled date
117
+ await waitFor(async () => expect(prompt).toHaveClass('wds-prompt--negative'));
118
+ },
119
+ };
120
+
121
+ const selectedDate = new Date(2024, 5, 15);
122
+ const minDate = new Date(2024, 2, 1);
123
+ const maxDate = new Date(2024, 9, 31);
124
+
125
+ const disabledRulesRtl = {
126
+ weekdays: ['sat', 'sun'] as ('sat' | 'sun')[],
127
+ dates: [new Date(2024, 5, 10)],
128
+ reason: 'Weekends and specific dates are unavailable.',
129
+ };
130
+
131
+ export const RTLDiff: Story = {
132
+ render: () => (
133
+ <>
134
+ <div data-testid="day-view">
135
+ <Calendar
136
+ value={selectedDate}
137
+ min={minDate}
138
+ max={maxDate}
139
+ disabledRules={disabledRulesRtl}
140
+ />
141
+ </div>
142
+ <div data-testid="month-view">
143
+ <Calendar value={selectedDate} min={minDate} max={maxDate} />
144
+ </div>
145
+ <div data-testid="year-view">
146
+ <Calendar value={selectedDate} min={minDate} max={maxDate} />
147
+ </div>
148
+ </>
149
+ ),
150
+ play: async ({ canvasElement }) => {
151
+ await forEachColumn(canvasElement, async (column) => {
152
+ const monthContainer = column.querySelector('[data-testid="month-view"]')!;
153
+ const monthScope = within(monthContainer as HTMLElement);
154
+ await userEvent.click(monthScope.getByRole('button', { name: /year view/iu }));
155
+ await userEvent.click(monthScope.getByRole('button', { name: /2024.*selected year/iu }));
156
+
157
+ const yearContainer = column.querySelector('[data-testid="year-view"]')!;
158
+ const yearScope = within(yearContainer as HTMLElement);
159
+ await userEvent.click(yearScope.getByRole('button', { name: /year view/iu }));
160
+ });
113
161
  },
162
+ ...withRTLDiff(),
114
163
  };
@@ -0,0 +1,59 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
+
3
+ import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
4
+ import Display from '../../Display';
5
+ import Carousel, { type CarouselCard } from '..';
6
+
7
+ export default {
8
+ component: Carousel,
9
+ title: 'Navigation/Carousel/Tests',
10
+ tags: ['!autodocs', '!manifest'],
11
+ } satisfies Meta<typeof Carousel>;
12
+
13
+ type Story = StoryObj<typeof Carousel>;
14
+
15
+ const sampleCards: CarouselCard[] = [
16
+ {
17
+ id: 'card-1',
18
+ type: 'button',
19
+ content: (
20
+ <div className="d-flex p-a-1 flex-column align-items-center">
21
+ <Display type="display-small">Card one</Display>
22
+ </div>
23
+ ),
24
+ },
25
+ {
26
+ id: 'card-2',
27
+ type: 'promo',
28
+ href: '#',
29
+ title: 'Promo card',
30
+ description: 'Description for promo card',
31
+ },
32
+ {
33
+ id: 'card-3',
34
+ type: 'anchor',
35
+ href: '#',
36
+ hrefTarget: '_blank',
37
+ content: <Display type="display-small">Anchor card</Display>,
38
+ },
39
+ {
40
+ id: 'card-4',
41
+ type: 'button',
42
+ content: (
43
+ <div className="d-flex p-a-1 flex-column align-items-center">
44
+ <Display type="display-small">Card four</Display>
45
+ </div>
46
+ ),
47
+ },
48
+ {
49
+ id: 'card-5',
50
+ type: 'anchor',
51
+ href: '#',
52
+ content: <Display type="display-small">Card five</Display>,
53
+ },
54
+ ];
55
+
56
+ export const RTLDiff: Story = {
57
+ render: () => <Carousel header="Carousel with navigation arrows" cards={sampleCards} />,
58
+ ...withRTLDiff(),
59
+ };