@transferwise/components 46.158.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 (201) hide show
  1. package/build/FlowNavigation/FlowNavigation.js +5 -14
  2. package/build/FlowNavigation/FlowNavigation.js.map +1 -1
  3. package/build/FlowNavigation/FlowNavigation.mjs +5 -14
  4. package/build/FlowNavigation/FlowNavigation.mjs.map +1 -1
  5. package/build/_deprecated/OverlayHeader/OverlayHeader.js +6 -41
  6. package/build/_deprecated/OverlayHeader/OverlayHeader.js.map +1 -1
  7. package/build/_deprecated/OverlayHeader/OverlayHeader.mjs +6 -41
  8. package/build/_deprecated/OverlayHeader/OverlayHeader.mjs.map +1 -1
  9. package/build/i18n/cs.json +5 -0
  10. package/build/i18n/cs.json.js +5 -0
  11. package/build/i18n/cs.json.js.map +1 -1
  12. package/build/i18n/cs.json.mjs +5 -0
  13. package/build/i18n/cs.json.mjs.map +1 -1
  14. package/build/i18n/de.json +5 -0
  15. package/build/i18n/de.json.js +5 -0
  16. package/build/i18n/de.json.js.map +1 -1
  17. package/build/i18n/de.json.mjs +5 -0
  18. package/build/i18n/de.json.mjs.map +1 -1
  19. package/build/i18n/es.json +5 -0
  20. package/build/i18n/es.json.js +5 -0
  21. package/build/i18n/es.json.js.map +1 -1
  22. package/build/i18n/es.json.mjs +5 -0
  23. package/build/i18n/es.json.mjs.map +1 -1
  24. package/build/i18n/fr.json +5 -0
  25. package/build/i18n/fr.json.js +5 -0
  26. package/build/i18n/fr.json.js.map +1 -1
  27. package/build/i18n/fr.json.mjs +5 -0
  28. package/build/i18n/fr.json.mjs.map +1 -1
  29. package/build/i18n/hu.json +5 -0
  30. package/build/i18n/hu.json.js +5 -0
  31. package/build/i18n/hu.json.js.map +1 -1
  32. package/build/i18n/hu.json.mjs +5 -0
  33. package/build/i18n/hu.json.mjs.map +1 -1
  34. package/build/i18n/id.json +5 -0
  35. package/build/i18n/id.json.js +5 -0
  36. package/build/i18n/id.json.js.map +1 -1
  37. package/build/i18n/id.json.mjs +5 -0
  38. package/build/i18n/id.json.mjs.map +1 -1
  39. package/build/i18n/it.json +5 -0
  40. package/build/i18n/it.json.js +5 -0
  41. package/build/i18n/it.json.js.map +1 -1
  42. package/build/i18n/it.json.mjs +5 -0
  43. package/build/i18n/it.json.mjs.map +1 -1
  44. package/build/i18n/ja.json +5 -0
  45. package/build/i18n/ja.json.js +5 -0
  46. package/build/i18n/ja.json.js.map +1 -1
  47. package/build/i18n/ja.json.mjs +5 -0
  48. package/build/i18n/ja.json.mjs.map +1 -1
  49. package/build/i18n/nl.json +5 -0
  50. package/build/i18n/nl.json.js +5 -0
  51. package/build/i18n/nl.json.js.map +1 -1
  52. package/build/i18n/nl.json.mjs +5 -0
  53. package/build/i18n/nl.json.mjs.map +1 -1
  54. package/build/i18n/pl.json +5 -0
  55. package/build/i18n/pl.json.js +5 -0
  56. package/build/i18n/pl.json.js.map +1 -1
  57. package/build/i18n/pl.json.mjs +5 -0
  58. package/build/i18n/pl.json.mjs.map +1 -1
  59. package/build/i18n/pt.json +5 -0
  60. package/build/i18n/pt.json.js +5 -0
  61. package/build/i18n/pt.json.js.map +1 -1
  62. package/build/i18n/pt.json.mjs +5 -0
  63. package/build/i18n/pt.json.mjs.map +1 -1
  64. package/build/i18n/ro.json +5 -0
  65. package/build/i18n/ro.json.js +5 -0
  66. package/build/i18n/ro.json.js.map +1 -1
  67. package/build/i18n/ro.json.mjs +5 -0
  68. package/build/i18n/ro.json.mjs.map +1 -1
  69. package/build/i18n/ru.json +5 -0
  70. package/build/i18n/ru.json.js +5 -0
  71. package/build/i18n/ru.json.js.map +1 -1
  72. package/build/i18n/ru.json.mjs +5 -0
  73. package/build/i18n/ru.json.mjs.map +1 -1
  74. package/build/i18n/th.json +5 -0
  75. package/build/i18n/th.json.js +5 -0
  76. package/build/i18n/th.json.js.map +1 -1
  77. package/build/i18n/th.json.mjs +5 -0
  78. package/build/i18n/th.json.mjs.map +1 -1
  79. package/build/i18n/uk.json +5 -0
  80. package/build/i18n/uk.json.js +5 -0
  81. package/build/i18n/uk.json.js.map +1 -1
  82. package/build/i18n/uk.json.mjs +5 -0
  83. package/build/i18n/uk.json.mjs.map +1 -1
  84. package/build/i18n/zh-HK.json +5 -0
  85. package/build/i18n/zh-HK.json.js +5 -0
  86. package/build/i18n/zh-HK.json.js.map +1 -1
  87. package/build/i18n/zh-HK.json.mjs +5 -0
  88. package/build/i18n/zh-HK.json.mjs.map +1 -1
  89. package/build/main.css +19 -4145
  90. package/build/styles/FlowNavigation/FlowNavigation.css +7 -13
  91. package/build/styles/ListItem/ListItem.css +1 -0
  92. package/build/styles/PocketSurface/PocketSurface.css +2 -11
  93. package/build/styles/SentimentSurface/SentimentSurface.css +0 -23
  94. package/build/styles/css/neptune.css +0 -2821
  95. package/build/styles/main.css +19 -4145
  96. package/build/styles/styles/less/neptune.css +0 -2821
  97. package/build/types/FlowNavigation/FlowNavigation.d.ts +2 -9
  98. package/build/types/FlowNavigation/FlowNavigation.d.ts.map +1 -1
  99. package/build/types/ListItem/_stories/variants/helpers.d.ts.map +1 -1
  100. package/build/types/_deprecated/OverlayHeader/OverlayHeader.d.ts.map +1 -1
  101. package/package.json +10 -10
  102. package/src/Accordion/_stories/Accordion.test.story.tsx +71 -0
  103. package/src/AvatarLayout/_stories/AvatarLayout.test.story.tsx +64 -0
  104. package/src/AvatarView/_stories/AvatarView.test.story.tsx +151 -0
  105. package/src/Button/LegacyButton/_stories/LegacyButton.test.story.tsx +22 -0
  106. package/src/Button/_stories/Button.test.story.tsx +65 -0
  107. package/src/Calendar/_stories/Calendar.test.story.tsx +73 -24
  108. package/src/Carousel/_stories/Carousel.test.story.tsx +59 -0
  109. package/src/Checkbox/_stories/Checkbox.test.story.tsx +20 -0
  110. package/src/CheckboxButton/_stories/CheckboxButton.test.story.tsx +17 -37
  111. package/src/Chevron/_stories/Chevron.test.story.tsx +26 -0
  112. package/src/Chips/_stories/Chips.test.story.tsx +39 -34
  113. package/src/CircularButton/_stories/CircularButton.test.story.tsx +0 -68
  114. package/src/DateInput/_stories/DateInput.test.story.tsx +13 -0
  115. package/src/DateLookup/_stories/DateLookup.rtl.test.story.tsx +88 -0
  116. package/src/Decision/_stories/Decision.test.story.tsx +79 -0
  117. package/src/DefinitionList/_stories/DefinitionList.test.story.tsx +54 -1
  118. package/src/Drawer/_stories/Drawer.rtl.test.story.tsx +58 -0
  119. package/src/ExpressiveMoneyInput/_stories/ExpressiveMoneyInput.rtl.test.story.tsx +118 -0
  120. package/src/Field/_stories/Field.test.story.tsx +46 -0
  121. package/src/FlowNavigation/FlowNavigation.css +7 -13
  122. package/src/FlowNavigation/FlowNavigation.less +6 -15
  123. package/src/FlowNavigation/FlowNavigation.tsx +6 -27
  124. package/src/FlowNavigation/_stories/FlowNavigation.story.tsx +0 -86
  125. package/src/FlowNavigation/_stories/FlowNavigation.test.story.tsx +44 -0
  126. package/src/Header/_stories/Header.test.story.tsx +27 -0
  127. package/src/Info/_stories/Info.rtl.test.story.tsx +64 -0
  128. package/src/Inputs/SelectInput/_stories/SelectInput.rtl.test.story.tsx +135 -0
  129. package/src/Inputs/_stories/InputGroup.test.story.tsx +69 -0
  130. package/src/Inputs/_stories/SearchInput.test.story.tsx +32 -0
  131. package/src/Inputs/_stories/TextArea.test.story.tsx +27 -0
  132. package/src/InstructionsList/_stories/InstructionsList.test.story.tsx +30 -0
  133. package/src/Label/_stories/Label.test.story.tsx +36 -0
  134. package/src/Link/_stories/Link.test.story.tsx +26 -0
  135. package/src/ListItem/ListItem.css +1 -0
  136. package/src/ListItem/_stories/{variants/ListItem.rtl.test.story.tsx → ListItem.rtl.test.story.tsx} +6 -10
  137. package/src/ListItem/_stories/variants/helpers.tsx +2 -6
  138. package/src/Logo/_stories/Logo.test.story.tsx +44 -0
  139. package/src/Modal/_stories/Modal.rtl.test.story.tsx +59 -0
  140. package/src/MoneyInput/_stories/MoneyInput.rtl.test.story.tsx +88 -0
  141. package/src/Nudge/_stories/Nudge.test.story.tsx +37 -0
  142. package/src/PhoneNumberInput/_stories/PhoneNumberInput.test.story.tsx +44 -0
  143. package/src/PocketSurface/PocketSurface.css +2 -11
  144. package/src/PocketSurface/PocketSurface.less +1 -1
  145. package/src/Popover/_stories/Popover.rtl.test.story.tsx +96 -0
  146. package/src/Progress/_stories/Progress.test.story.tsx +27 -0
  147. package/src/ProgressBar/_stories/ProgressBar.test.story.tsx +33 -0
  148. package/src/PromoCard/_stories/PromoCard.test.story.tsx +42 -0
  149. package/src/PromoCard/_stories/PromoCardGroup.test.story.tsx +51 -0
  150. package/src/Prompt/ActionPrompt/_stories/ActionPrompt.test.story.tsx +42 -1
  151. package/src/Prompt/CriticalBanner/_stories/CriticalBanner.test.story.tsx +34 -31
  152. package/src/Prompt/InfoPrompt/_stories/InfoPrompt.test.story.tsx +25 -0
  153. package/src/Prompt/InlinePrompt/_stories/InlinePrompt.test.story.tsx +27 -0
  154. package/src/Radio/_stories/Radio.test.story.tsx +61 -0
  155. package/src/RadioGroup/_stories/RadioGroup.test.story.tsx +56 -0
  156. package/src/Section/_stories/Section.test.story.tsx +29 -0
  157. package/src/SegmentedControl/_stories/SegmentedControl.test.story.tsx +45 -0
  158. package/src/SentimentSurface/SentimentSurface.css +0 -23
  159. package/src/SlidingPanel/_stories/SlidingPanel.rtl.test.story.tsx +70 -0
  160. package/src/Snackbar/_stories/Snackbar.rtl.test.story.tsx +45 -0
  161. package/src/Snackbar/_stories/Snackbar.test.story.tsx +0 -31
  162. package/src/Stepper/_stories/Stepper.test.story.tsx +17 -0
  163. package/src/Switch/_stories/Switch.test.story.tsx +20 -26
  164. package/src/Table/_stories/Table.test.story.tsx +104 -0
  165. package/src/Tabs/_stories/Tabs.test.story.tsx +72 -0
  166. package/src/TextareaWithDisplayFormat/_stories/TextareaWithDisplayFormat.test.story.tsx +48 -0
  167. package/src/Tooltip/_stories/Tooltip.rtl.test.story.tsx +79 -0
  168. package/src/Typeahead/_stories/Typeahead.rtl.test.story.tsx +90 -0
  169. package/src/Upload/_stories/Upload.rtl.test.story.tsx +53 -0
  170. package/src/UploadInput/_stories/UploadInput.test.story.tsx +47 -0
  171. package/src/_deprecated/Alert/_stories/Alert.test.story.tsx +28 -1
  172. package/src/_deprecated/Card/_stories/Card.test.story.tsx +38 -0
  173. package/src/_deprecated/CriticalBanner/_stories/CriticalCommsBanner.test.story.tsx +18 -0
  174. package/src/_deprecated/InlineAlert/_stories/InlineAlert.test.story.tsx +26 -0
  175. package/src/_deprecated/OverlayHeader/OverlayHeader.tsx +2 -21
  176. package/src/_deprecated/OverlayHeader/_stories/OverlayHeader.test.story.tsx +42 -0
  177. package/src/_deprecated/Select/_stories/Select.rtl.test.story.tsx +71 -0
  178. package/src/common/BottomSheet/_stories/BottomSheet.test.story.tsx +23 -0
  179. package/src/common/Panel/_stories/Panel.story.tsx +107 -36
  180. package/src/i18n/cs.json +5 -0
  181. package/src/i18n/de.json +5 -0
  182. package/src/i18n/es.json +5 -0
  183. package/src/i18n/fr.json +5 -0
  184. package/src/i18n/hu.json +5 -0
  185. package/src/i18n/id.json +5 -0
  186. package/src/i18n/it.json +5 -0
  187. package/src/i18n/ja.json +5 -0
  188. package/src/i18n/nl.json +5 -0
  189. package/src/i18n/pl.json +5 -0
  190. package/src/i18n/pt.json +5 -0
  191. package/src/i18n/ro.json +5 -0
  192. package/src/i18n/ru.json +5 -0
  193. package/src/i18n/th.json +5 -0
  194. package/src/i18n/uk.json +5 -0
  195. package/src/i18n/zh-HK.json +5 -0
  196. package/src/main.css +19 -4145
  197. package/src/main.less +0 -1
  198. package/src/styles/less/neptune.css +0 -2821
  199. package/build/styles/_deprecated/OverlayHeader/OverlayHeader.css +0 -15
  200. package/src/_deprecated/OverlayHeader/OverlayHeader.css +0 -15
  201. package/src/_deprecated/OverlayHeader/OverlayHeader.less +0 -24
@@ -0,0 +1,118 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
+ import { fn, userEvent, within } from 'storybook/test';
3
+ import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
4
+ import ExpressiveMoneyInput from '..';
5
+ import { Rewards } from '@transferwise/icons';
6
+
7
+ export default {
8
+ component: ExpressiveMoneyInput,
9
+ title: 'Forms/ExpressiveMoneyInput/Tests/RTL Diff',
10
+ tags: ['!autodocs', '!manifest'],
11
+ } satisfies Meta<typeof ExpressiveMoneyInput>;
12
+
13
+ type Story = StoryObj<typeof ExpressiveMoneyInput>;
14
+
15
+ const currencySelectorOptions = [
16
+ {
17
+ title: 'Popular',
18
+ currencies: [
19
+ { code: 'GBP', label: 'British Pound', keywords: ['british'] },
20
+ { code: 'EUR', label: 'Euro', keywords: ['euro'] },
21
+ { code: 'USD', label: 'US Dollar', keywords: ['dollar'] },
22
+ ],
23
+ },
24
+ ];
25
+
26
+ export const TriggerVariants: Story = {
27
+ render: () => (
28
+ <>
29
+ {/* Currency selector on leading side — flips in RTL */}
30
+ <ExpressiveMoneyInput
31
+ label="You send"
32
+ currency="GBP"
33
+ amount={1234.56}
34
+ currencySelector={{
35
+ options: currencySelectorOptions,
36
+ onChange: fn(),
37
+ onSearchChange: fn(),
38
+ onOpen: fn(),
39
+ }}
40
+ onAmountChange={fn()}
41
+ />
42
+
43
+ {/* Chevron on trailing side — flips in RTL */}
44
+ <ExpressiveMoneyInput
45
+ label="You send"
46
+ currency="EUR"
47
+ amount={0}
48
+ showChevron
49
+ currencySelector={{
50
+ options: currencySelectorOptions,
51
+ onChange: fn(),
52
+ onSearchChange: fn(),
53
+ onOpen: fn(),
54
+ }}
55
+ onAmountChange={fn()}
56
+ />
57
+
58
+ {/* InlinePrompt with media icon — icon on leading end of prompt */}
59
+ <ExpressiveMoneyInput
60
+ label="You send"
61
+ currency="USD"
62
+ amount={500}
63
+ currencySelector={{
64
+ options: currencySelectorOptions,
65
+ onChange: fn(),
66
+ onSearchChange: fn(),
67
+ onOpen: fn(),
68
+ }}
69
+ inlinePrompt={{
70
+ message: 'Great rate available',
71
+ sentiment: 'positive',
72
+ media: <Rewards />,
73
+ }}
74
+ onAmountChange={fn()}
75
+ />
76
+
77
+ {/* Secondary avatar addon in currency selector */}
78
+ <ExpressiveMoneyInput
79
+ label="You send"
80
+ currency="GBP"
81
+ amount={750}
82
+ currencySelector={{
83
+ options: currencySelectorOptions,
84
+ addons: [{ profileName: 'Mikkael Jordan' }],
85
+ onChange: fn(),
86
+ onSearchChange: fn(),
87
+ onOpen: fn(),
88
+ }}
89
+ onAmountChange={fn()}
90
+ />
91
+ </>
92
+ ),
93
+ ...withRTLDiff({ width: 'stretch' }),
94
+ };
95
+
96
+ export const OpenDropdown: Story = {
97
+ render: () => (
98
+ <ExpressiveMoneyInput
99
+ label="You send"
100
+ currency="GBP"
101
+ amount={1234.56}
102
+ currencySelector={{
103
+ options: currencySelectorOptions,
104
+ onChange: fn(),
105
+ onSearchChange: fn(),
106
+ onOpen: fn(),
107
+ }}
108
+ onAmountChange={fn()}
109
+ />
110
+ ),
111
+ play: async ({ canvasElement }) => {
112
+ const canvas = within(canvasElement);
113
+ const trigger = canvas.queryByRole('combobox');
114
+ if (!trigger) return;
115
+ await userEvent.click(trigger);
116
+ },
117
+ ...withRTLDiff({ renderAs: 'iframe', width: '80%' }),
118
+ };
@@ -1,6 +1,9 @@
1
1
  import { useState } from 'react';
2
2
  import { Meta, StoryObj } from '@storybook/react-webpack5';
3
+ import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
3
4
  import { Input } from '../../Inputs/Input/Input';
5
+ import { TextArea } from '../../Inputs/TextArea/TextArea';
6
+ import { lorem10 } from '../../test-utils';
4
7
  import Field, { FieldProps } from '..';
5
8
  import { Sentiment } from '../../common';
6
9
 
@@ -54,3 +57,46 @@ export const DeprecatedProps: Story = {
54
57
  );
55
58
  },
56
59
  };
60
+
61
+ export const RTLDiff: Story = {
62
+ render: () => (
63
+ <>
64
+ {/* Required label (default) — label text aligns to start */}
65
+ <Field label="Required field">
66
+ <Input defaultValue="Input value" />
67
+ </Field>
68
+
69
+ {/* Optional label — "(optional)" suffix uses directional margin-left */}
70
+ <Field label="Optional field" required={false}>
71
+ <Input defaultValue="Input value" />
72
+ </Field>
73
+
74
+ {/* Label + description + message — full vertical layout with directional icon */}
75
+ <Field
76
+ label="Field with description and message"
77
+ required={false}
78
+ description={lorem10}
79
+ message="This is a validation message"
80
+ sentiment="negative"
81
+ >
82
+ <Input defaultValue="Input value" />
83
+ </Field>
84
+
85
+ {/* Message only (no label) — InlinePrompt icon+text layout visible */}
86
+ <Field message="A helpful message" sentiment="positive">
87
+ <Input defaultValue="Input value" />
88
+ </Field>
89
+
90
+ {/* Loading message — spinner replaces icon but layout structure is identical */}
91
+ <Field label="Field with loading message" message="Saving…" messageLoading>
92
+ <Input defaultValue="Input value" />
93
+ </Field>
94
+
95
+ {/* Textarea with char counter — counter uses text-align:right + margin-left:auto */}
96
+ <Field label="Textarea with char counter" required={false} description="Max 100 characters">
97
+ <TextArea maxLength={100} defaultValue="Textarea value" />
98
+ </Field>
99
+ </>
100
+ ),
101
+ ...withRTLDiff(),
102
+ };
@@ -4,7 +4,12 @@
4
4
  justify-content: center;
5
5
  width: 100%;
6
6
  box-sizing: border-box;
7
- min-height: 96px;
7
+ min-height: 80px;
8
+ }
9
+ @media (min-width: 320.02px) {
10
+ .np-flow-navigation {
11
+ min-height: 128px;
12
+ }
8
13
  }
9
14
  .np-flow-navigation--border-bottom {
10
15
  border-bottom: 1px solid rgba(0,0,0,0.10196);
@@ -13,7 +18,7 @@
13
18
  .np-flow-navigation__content {
14
19
  width: 100%;
15
20
  min-width: 320px;
16
- max-width: calc(1160px - 36px);
21
+ max-width: none;
17
22
  }
18
23
  .np-flow-navigation__stepper {
19
24
  padding-bottom: 0 !important;
@@ -72,17 +77,6 @@ html:not([dir="rtl"]) .np-flow-navigation--sm .np-flow-navigation__stepper {
72
77
  .np-flow-navigation--hidden {
73
78
  visibility: hidden;
74
79
  }
75
- .np-flow-navigation--composable {
76
- min-height: 80px;
77
- }
78
- @media (min-width: 320.02px) {
79
- .np-flow-navigation--composable {
80
- min-height: 128px;
81
- }
82
- }
83
- .np-flow-navigation--composable .np-flow-navigation__content {
84
- max-width: none;
85
- }
86
80
  .np-theme-personal--forest-green .np-flow-navigation .np-flow-header__left path,
87
81
  .np-theme-personal--bright-green .np-flow-navigation .np-flow-header__left path,
88
82
  .np-theme-personal--dark .np-flow-navigation .np-flow-header__left path {
@@ -9,7 +9,11 @@
9
9
  box-sizing: border-box;
10
10
 
11
11
  // This is the natural height of FlowNavigation when the Avatar is displayed.
12
- min-height: 96px;
12
+ min-height: 80px;
13
+
14
+ @media (--screen-xs) {
15
+ min-height: 128px;
16
+ }
13
17
 
14
18
  &--border-bottom {
15
19
  border-bottom: 1px solid var(--color-border-neutral);
@@ -18,7 +22,7 @@
18
22
  &__content {
19
23
  width: 100%;
20
24
  min-width: 320px;
21
- max-width: calc(@screen-lg-min - 36px);
25
+ max-width: none;
22
26
  }
23
27
 
24
28
  &__stepper {
@@ -69,19 +73,6 @@
69
73
  visibility: hidden;
70
74
  }
71
75
 
72
- &--composable {
73
- min-height: 80px;
74
-
75
- @media (--screen-xs) {
76
- min-height: 128px;
77
- }
78
-
79
- .np-flow-navigation__content {
80
- // Remove max-width constraint for fluid layout
81
- max-width: none;
82
- }
83
- }
84
-
85
76
  .np-theme-personal--forest-green &,
86
77
  .np-theme-personal--bright-green &,
87
78
  .np-theme-personal--dark & {
@@ -26,20 +26,13 @@ export interface FlowNavigationProps {
26
26
  /** @default false */
27
27
  done?: boolean;
28
28
  /** Called when the close button is clicked. If not provided the close button won't show */
29
- onClose?: () => void;
29
+ onClose?: (() => void) | React.MouseEventHandler<HTMLButtonElement>;
30
30
  /** Called when the back button is clicked. If not provided the back button won't show. The back button only shows on small screens */
31
31
  onGoBack?: () => void;
32
32
  /** Steps to be displayed in stepper. If not provided, the stepper won't show. */
33
33
  steps?: readonly Step[];
34
- /**
35
- * When true, renders in composable mode using a fluid Container.
36
- * This allows the FlowNavigation to be used within custom layout containers.
37
- * @default false
38
- */
39
- composable?: boolean;
40
34
  /**
41
35
  * Controls whether the bottom border is displayed.
42
- * Only applies to the composable variant. Non-composable variant always uses the done state.
43
36
  * @default true
44
37
  */
45
38
  showBottomBorder?: boolean;
@@ -53,7 +46,6 @@ const FlowNavigation = ({
53
46
  onClose,
54
47
  onGoBack,
55
48
  steps,
56
- composable = false,
57
49
  showBottomBorder = true,
58
50
  }: FlowNavigationProps) => {
59
51
  const intl = useIntl();
@@ -69,7 +61,6 @@ const FlowNavigation = ({
69
61
  <FlowHeader
70
62
  className={clsx(
71
63
  'np-flow-navigation__content',
72
- !composable && 'p-x-3',
73
64
  screenSm == null
74
65
  ? 'np-flow-navigation--hidden'
75
66
  : {
@@ -119,27 +110,15 @@ const FlowNavigation = ({
119
110
  />
120
111
  );
121
112
 
122
- if (composable) {
123
- return (
124
- <Container
125
- size="fluid"
126
- className={clsx('np-flow-navigation np-flow-navigation--composable', {
127
- 'np-flow-navigation--border-bottom': showBottomBorder,
128
- })}
129
- >
130
- {flowHeaderContent}
131
- </Container>
132
- );
133
- }
134
-
135
113
  return (
136
- <div
137
- className={clsx('np-flow-navigation p-y-3', {
138
- 'np-flow-navigation--border-bottom': !done,
114
+ <Container
115
+ size="fluid"
116
+ className={clsx('np-flow-navigation', {
117
+ 'np-flow-navigation--border-bottom': showBottomBorder,
139
118
  })}
140
119
  >
141
120
  {flowHeaderContent}
142
- </div>
121
+ </Container>
143
122
  );
144
123
  };
145
124
 
@@ -384,89 +384,6 @@ export const WithOverlayHeaderComparison: Story = {
384
384
  },
385
385
  };
386
386
 
387
- export const ComposableVariant: Story = {
388
- args: {
389
- profileType: ProfileType.PERSONAL,
390
- showCloseButton: true,
391
- showMobileBackButton: true,
392
- done: false,
393
- avatarURL: '../tapestry-01.png',
394
- },
395
- parameters: {
396
- padding: '0',
397
- chromatic: {
398
- viewports,
399
- },
400
- },
401
- render: (args) => {
402
- const [activeStep, setActiveStep] = useState(2);
403
- const steps = [
404
- {
405
- label: 'Recipient',
406
- onClick: () => setActiveStep(0),
407
- },
408
- {
409
- label: 'Amount',
410
- hoverLabel: (
411
- <>
412
- You send 100 GBP <br />
413
- You get 99.39 GBP{' '}
414
- </>
415
- ),
416
- ...(activeStep > 1 && { onClick: () => setActiveStep(1) }),
417
- },
418
- {
419
- label: 'Review',
420
- ...(activeStep > 2 && { onClick: () => setActiveStep(2) }),
421
- },
422
- {
423
- label: 'Pay',
424
- ...(activeStep > 3 && { onClick: () => setActiveStep(3) }),
425
- },
426
- ];
427
- return (
428
- <>
429
- <FlowNavigation
430
- composable
431
- avatar={<AvatarView profileType={args.profileType} />}
432
- logo={<Logo />}
433
- activeStep={activeStep}
434
- steps={steps}
435
- onClose={args.showCloseButton ? () => alert('close') : undefined}
436
- onGoBack={
437
- args.showMobileBackButton
438
- ? () => setActiveStep(activeStep > 0 ? activeStep - 1 : 0)
439
- : undefined
440
- }
441
- />
442
- <Container size="narrow">
443
- <Body className="m-a-3">
444
- <Display type={Typography.DISPLAY_SMALL}>{steps[activeStep].label} Step</Display>
445
- <br />
446
- {lorem10}
447
- </Body>
448
- </Container>
449
-
450
- <Sticky>
451
- <Container
452
- size="narrow"
453
- className="d-flex justify-content-center align-items-center p-y-3"
454
- >
455
- <Button
456
- v2
457
- disabled={activeStep === 3}
458
- block
459
- onClick={() => setActiveStep(activeStep + 1)}
460
- >
461
- Continue
462
- </Button>
463
- </Container>
464
- </Sticky>
465
- </>
466
- );
467
- },
468
- };
469
-
470
387
  export const WithoutStepper: Story = {
471
388
  args: {
472
389
  profileType: ProfileType.PERSONAL,
@@ -575,7 +492,6 @@ export const BorderControl: Story = {
575
492
 
576
493
  {/* Composable: showBottomBorder=true, done=false - SHOWS BORDER */}
577
494
  <FlowNavigation
578
- composable
579
495
  avatar={<AvatarView profileType={args.profileType} />}
580
496
  logo={<Logo />}
581
497
  activeStep={activeStep}
@@ -591,7 +507,6 @@ export const BorderControl: Story = {
591
507
 
592
508
  {/* Composable: showBottomBorder=true, done=true - SHOWS BORDER */}
593
509
  <FlowNavigation
594
- composable
595
510
  avatar={<AvatarView profileType={args.profileType} />}
596
511
  logo={<Logo />}
597
512
  activeStep={activeStep}
@@ -607,7 +522,6 @@ export const BorderControl: Story = {
607
522
 
608
523
  {/* Composable: showBottomBorder=false, done=false - HIDES BORDER */}
609
524
  <FlowNavigation
610
- composable
611
525
  avatar={<AvatarView profileType={args.profileType} />}
612
526
  logo={<Logo />}
613
527
  activeStep={activeStep}
@@ -1,5 +1,6 @@
1
1
  import { Meta, StoryObj } from '@storybook/react-webpack5';
2
2
 
3
+ import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
3
4
  import AvatarView from '../../AvatarView';
4
5
  import { ProfileType } from '../../common';
5
6
  import Logo from '../../Logo';
@@ -76,3 +77,46 @@ export const LongLabel: Story = {
76
77
  />
77
78
  ),
78
79
  };
80
+
81
+ const rtlSteps = [
82
+ { label: 'Amount', hoverLabel: '100 GBP', onClick: noop },
83
+ { label: 'You', hoverLabel: 'Elena Durante', onClick: noop },
84
+ { label: 'Review', onClick: noop },
85
+ { label: 'Pay', onClick: noop },
86
+ ];
87
+
88
+ /**
89
+ * FlowNavigation has directional layout: back button on inline-start,
90
+ * close button and avatar on inline-end, and a stepper progress bar that
91
+ * flows in the reading direction. All of these flip in RTL.
92
+ */
93
+ export const RTLDiff: Story = {
94
+ render: () => (
95
+ <>
96
+ {/* With stepper, back button, close button, and avatar */}
97
+ <FlowNavigation
98
+ activeStep={2}
99
+ avatar={<AvatarView profileType={ProfileType.PERSONAL} />}
100
+ logo={<Logo />}
101
+ steps={rtlSteps}
102
+ onClose={noop}
103
+ onGoBack={noop}
104
+ />
105
+ {/* Without stepper — logo left, close button right */}
106
+ <FlowNavigation
107
+ avatar={<AvatarView profileType={ProfileType.PERSONAL} />}
108
+ logo={<Logo />}
109
+ onClose={noop}
110
+ />
111
+ {/* Done state — no stepper, logo and close button only */}
112
+ <FlowNavigation
113
+ done
114
+ avatar={<AvatarView profileType={ProfileType.PERSONAL} />}
115
+ logo={<Logo />}
116
+ steps={rtlSteps}
117
+ onClose={noop}
118
+ />
119
+ </>
120
+ ),
121
+ ...withRTLDiff(),
122
+ };
@@ -1,4 +1,5 @@
1
1
  import { Meta, StoryObj } from '@storybook/react-webpack5';
2
+ import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
2
3
  import Header, { type HeaderProps } from '../Header';
3
4
  import { withVariantConfig } from '../../../.storybook/helpers';
4
5
 
@@ -122,3 +123,29 @@ export const AllVariants: Story = {
122
123
  </div>
123
124
  ),
124
125
  };
126
+
127
+ /**
128
+ * The Header uses a CSS grid layout (1fr auto) that places the action on the
129
+ * inline-end side. In RTL the action should appear on the left instead of the
130
+ * right. Both level variants are included to cover the border-bottom alignment
131
+ * difference.
132
+ */
133
+ export const RTLDiff: Story = {
134
+ render: () => (
135
+ <>
136
+ <Header title="Group level without action" level="group" />
137
+ <Header
138
+ title="Group level with action"
139
+ level="group"
140
+ action={{ 'aria-label': 'View all', text: 'View all', href: '#' }}
141
+ />
142
+ <Header title="Section level without action" level="section" />
143
+ <Header
144
+ title="Section level with action"
145
+ level="section"
146
+ action={{ 'aria-label': 'Learn more', text: 'Learn more', href: '#' }}
147
+ />
148
+ </>
149
+ ),
150
+ ...withRTLDiff(),
151
+ };
@@ -0,0 +1,64 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
+ import { userEvent, within } from 'storybook/test';
3
+
4
+ import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
5
+ import Info from '..';
6
+
7
+ export default {
8
+ component: Info,
9
+ title: 'Dialogs/Info/Tests/RTL Diff',
10
+ tags: ['!autodocs', '!manifest'],
11
+ } satisfies Meta<typeof Info>;
12
+
13
+ type Story = StoryObj<typeof Info>;
14
+
15
+ const iframeDiff = withRTLDiff({ renderAs: 'iframe' });
16
+
17
+ const openInfo = async ({ canvasElement }: { canvasElement: HTMLElement }) => {
18
+ const canvas = within(canvasElement);
19
+ const button = canvas.queryByRole('button');
20
+ if (!button) return;
21
+ await userEvent.click(button);
22
+ };
23
+
24
+ export const Popover: Story = {
25
+ render: () => (
26
+ <Info
27
+ aria-label="Info trigger"
28
+ title="Information"
29
+ content="This is some descriptive content inside the info component."
30
+ presentation="POPOVER"
31
+ size="sm"
32
+ />
33
+ ),
34
+ play: openInfo,
35
+ ...iframeDiff,
36
+ };
37
+
38
+ export const PopoverLarge: Story = {
39
+ render: () => (
40
+ <Info
41
+ aria-label="Info trigger"
42
+ title="Information"
43
+ content="This is some descriptive content inside the info component."
44
+ presentation="POPOVER"
45
+ size="lg"
46
+ />
47
+ ),
48
+ play: openInfo,
49
+ ...iframeDiff,
50
+ };
51
+
52
+ export const Modal: Story = {
53
+ render: () => (
54
+ <Info
55
+ aria-label="Info trigger"
56
+ title="Information"
57
+ content="This is some descriptive content inside the info component."
58
+ presentation="MODAL"
59
+ size="sm"
60
+ />
61
+ ),
62
+ play: openInfo,
63
+ ...iframeDiff,
64
+ };