@transferwise/components 0.0.0-experimental-99bbbb3 → 0.0.0-experimental-20085a3

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 (88) hide show
  1. package/build/i18n/id.json +0 -5
  2. package/build/i18n/id.json.js +0 -5
  3. package/build/i18n/id.json.js.map +1 -1
  4. package/build/i18n/id.json.mjs +0 -5
  5. package/build/i18n/id.json.mjs.map +1 -1
  6. package/build/types/Body/Body.d.ts +2 -2
  7. package/build/types/IconButton/IconButton.d.ts +1 -1
  8. package/build/types/ListItem/_stories/variants/helpers.d.ts.map +1 -1
  9. package/build/types/MoneyInput/MoneyInput.d.ts +1 -1
  10. package/build/types/MoneyInput/MoneyInput.d.ts.map +1 -1
  11. package/build/types/Title/Title.d.ts +2 -2
  12. package/build/types/Upload/Steps/UploadImageStep/UploadImageStep.d.ts +1 -1
  13. package/build/types/UploadInput/UploadItem/UploadItemLink.d.ts +1 -1
  14. package/package.json +1 -1
  15. package/src/Accordion/_stories/Accordion.rtl.test.story.tsx +71 -0
  16. package/src/AvatarLayout/_stories/AvatarLayout.rtl.test.story.tsx +77 -0
  17. package/src/AvatarView/_stories/AvatarView.rtl.test.story.tsx +162 -0
  18. package/src/Button/LegacyButton/_stories/LegacyButton.rtl.test.story.tsx +32 -0
  19. package/src/Button/_stories/Button.rtl.test.story.tsx +87 -0
  20. package/src/Calendar/_stories/Calendar.rtl.test.story.tsx +52 -0
  21. package/src/Calendar/_stories/Calendar.test.story.tsx +28 -24
  22. package/src/Carousel/_stories/Carousel.rtl.test.story.tsx +61 -0
  23. package/src/Checkbox/_stories/Checkbox.rtl.test.story.tsx +31 -0
  24. package/src/CheckboxButton/_stories/CheckboxButton.rtl.test.story.tsx +27 -0
  25. package/src/CheckboxButton/_stories/CheckboxButton.test.story.tsx +0 -37
  26. package/src/Chevron/_stories/Chevron.rtl.test.story.tsx +26 -0
  27. package/src/Chips/_stories/Chips.rtl.test.story.tsx +49 -0
  28. package/src/Chips/_stories/Chips.test.story.tsx +0 -34
  29. package/src/CircularButton/_stories/CircularButton.test.story.tsx +0 -68
  30. package/src/DateInput/_stories/DateInput.rtl.test.story.tsx +25 -0
  31. package/src/DateLookup/_stories/DateLookup.rtl.test.story.tsx +88 -0
  32. package/src/Decision/_stories/Decision.rtl.test.story.tsx +79 -0
  33. package/src/DefinitionList/_stories/DefinitionList.rtl.test.story.tsx +63 -0
  34. package/src/Drawer/_stories/Drawer.rtl.test.story.tsx +58 -0
  35. package/src/ExpressiveMoneyInput/_stories/ExpressiveMoneyInput.rtl.test.story.tsx +118 -0
  36. package/src/Field/_stories/Field.rtl.test.story.tsx +58 -0
  37. package/src/FlowNavigation/_stories/FlowNavigation.rtl.test.story.tsx +70 -0
  38. package/src/Header/_stories/Header.rtl.test.story.tsx +37 -0
  39. package/src/Info/_stories/Info.rtl.test.story.tsx +64 -0
  40. package/src/Inputs/SelectInput/_stories/SelectInput.rtl.test.story.tsx +135 -0
  41. package/src/Inputs/_stories/InputGroup.rtl.test.story.tsx +69 -0
  42. package/src/Inputs/_stories/SearchInput.rtl.test.story.tsx +32 -0
  43. package/src/Inputs/_stories/TextArea.rtl.test.story.tsx +38 -0
  44. package/src/InstructionsList/_stories/InstructionsList.rtl.test.story.tsx +30 -0
  45. package/src/Label/_stories/Label.rtl.test.story.tsx +36 -0
  46. package/src/Link/_stories/Link.rtl.test.story.tsx +26 -0
  47. package/src/ListItem/_stories/{variants/ListItem.rtl.test.story.tsx → ListItem.rtl.test.story.tsx} +6 -10
  48. package/src/ListItem/_stories/variants/helpers.tsx +2 -6
  49. package/src/Logo/_stories/Logo.rtl.test.story.tsx +56 -0
  50. package/src/Modal/_stories/Modal.rtl.test.story.tsx +59 -0
  51. package/src/MoneyInput/_stories/MoneyInput.rtl.test.story.tsx +88 -0
  52. package/src/Nudge/_stories/Nudge.rtl.test.story.tsx +37 -0
  53. package/src/PhoneNumberInput/_stories/PhoneNumberInput.rtl.test.story.tsx +44 -0
  54. package/src/Popover/_stories/Popover.rtl.test.story.tsx +96 -0
  55. package/src/Progress/_stories/Progress.rtl.test.story.tsx +27 -0
  56. package/src/ProgressBar/_stories/ProgressBar.rtl.test.story.tsx +33 -0
  57. package/src/PromoCard/_stories/PromoCard.rtl.test.story.tsx +42 -0
  58. package/src/PromoCard/_stories/PromoCardGroup.rtl.test.story.tsx +51 -0
  59. package/src/Prompt/ActionPrompt/_stories/ActionPrompt.rtl.test.story.tsx +53 -0
  60. package/src/Prompt/CriticalBanner/_stories/CriticalBanner.rtl.test.story.tsx +46 -0
  61. package/src/Prompt/CriticalBanner/_stories/CriticalBanner.test.story.tsx +0 -30
  62. package/src/Prompt/InfoPrompt/_stories/InfoPrompt.rtl.test.story.tsx +36 -0
  63. package/src/Prompt/InlinePrompt/_stories/InlinePrompt.rtl.test.story.tsx +38 -0
  64. package/src/Radio/_stories/Radio.rtl.test.story.tsx +61 -0
  65. package/src/RadioGroup/_stories/RadioGroup.rtl.test.story.tsx +66 -0
  66. package/src/Section/_stories/Section.rtl.test.story.tsx +29 -0
  67. package/src/SegmentedControl/_stories/SegmentedControl.rtl.test.story.tsx +45 -0
  68. package/src/SlidingPanel/_stories/SlidingPanel.rtl.test.story.tsx +70 -0
  69. package/src/Snackbar/_stories/Snackbar.rtl.test.story.tsx +45 -0
  70. package/src/Snackbar/_stories/Snackbar.test.story.tsx +0 -31
  71. package/src/Stepper/_stories/Stepper.rtl.test.story.tsx +24 -0
  72. package/src/Switch/_stories/Switch.rtl.test.story.tsx +32 -0
  73. package/src/Switch/_stories/Switch.test.story.tsx +0 -26
  74. package/src/Table/_stories/Table.rtl.test.story.tsx +104 -0
  75. package/src/Tabs/_stories/Tabs.rtl.test.story.tsx +72 -0
  76. package/src/TextareaWithDisplayFormat/_stories/TextareaWithDisplayFormat.rtl.test.story.tsx +48 -0
  77. package/src/Tooltip/_stories/Tooltip.rtl.test.story.tsx +79 -0
  78. package/src/Typeahead/_stories/Typeahead.rtl.test.story.tsx +90 -0
  79. package/src/Upload/_stories/Upload.rtl.test.story.tsx +53 -0
  80. package/src/UploadInput/_stories/UploadInput.rtl.test.story.tsx +59 -0
  81. package/src/_deprecated/Alert/_stories/Alert.rtl.test.story.tsx +37 -0
  82. package/src/_deprecated/Card/_stories/Card.rtl.test.story.tsx +38 -0
  83. package/src/_deprecated/CriticalBanner/_stories/CriticalCommsBanner.rtl.test.story.tsx +28 -0
  84. package/src/_deprecated/InlineAlert/_stories/InlineAlert.rtl.test.story.tsx +26 -0
  85. package/src/_deprecated/OverlayHeader/_stories/OverlayHeader.rtl.test.story.tsx +42 -0
  86. package/src/_deprecated/Select/_stories/Select.rtl.test.story.tsx +71 -0
  87. package/src/common/BottomSheet/_stories/BottomSheet.rtl.test.story.tsx +39 -0
  88. package/src/i18n/id.json +0 -5
@@ -28,17 +28,19 @@ export const YearViewBoundaries: Story = {
28
28
  await userEvent.click(canvas.getByRole('button', { name: /year view/iu }));
29
29
 
30
30
  // Selected year (within range) is enabled
31
- await expect(
32
- canvas.getByRole('button', { name: /2024.*selected year/iu }),
33
- ).not.toHaveAttribute('aria-disabled');
31
+ await expect(canvas.getByRole('button', { name: /2024.*selected year/iu })).not.toHaveAttribute(
32
+ 'aria-disabled',
33
+ );
34
34
 
35
35
  // 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');
36
+ await expect(canvas.getByRole('button', { name: /^2023.*not available/iu })).toHaveAttribute(
37
+ 'aria-disabled',
38
+ 'true',
39
+ );
40
+ await expect(canvas.getByRole('button', { name: /^2025.*not available/iu })).toHaveAttribute(
41
+ 'aria-disabled',
42
+ 'true',
43
+ );
42
44
 
43
45
  // Both nav arrows disabled — min and max are both in the 2020–2039 block
44
46
  await expect(canvas.getByRole('button', { name: /previous 20 years/iu })).toBeDisabled();
@@ -73,12 +75,14 @@ export const MonthViewBoundaries: Story = {
73
75
  ).not.toHaveAttribute('aria-disabled');
74
76
 
75
77
  // 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');
78
+ await expect(canvas.getByRole('button', { name: /^Feb.*not available/iu })).toHaveAttribute(
79
+ 'aria-disabled',
80
+ 'true',
81
+ );
82
+ await expect(canvas.getByRole('button', { name: /^Nov.*not available/iu })).toHaveAttribute(
83
+ 'aria-disabled',
84
+ 'true',
85
+ );
82
86
 
83
87
  // Both nav arrows disabled — min and max are both in 2024
84
88
  await expect(canvas.getByRole('button', { name: /previous year/iu })).toBeDisabled();
@@ -92,23 +96,23 @@ const disabledRules: DisabledRules = {
92
96
  };
93
97
 
94
98
  /**
95
- * When a disabled cell receives direct DOM focus (e.g. screen reader virtual cursor),
99
+ * When a disabled cell receives focus via keyboard navigation,
96
100
  * the inline prompt updates to negative sentiment showing the disabled reason.
97
101
  */
98
102
  export const DisabledDateFocusUpdatesPrompt: Story = {
99
103
  render: () => <Calendar value={new Date(2024, 6, 5)} disabledRules={disabledRules} />,
100
104
  play: async ({ canvasElement }) => {
101
- const canvas = within(canvasElement);
102
-
103
- // Initially prompt is neutral (focused date is enabled)
105
+ // Initially prompt is neutral (focused date is enabled — July 5 is a Friday)
104
106
  const prompt = canvasElement.querySelector('.wds-inline-prompt')!;
105
107
  await expect(prompt).toHaveClass('wds-prompt--neutral');
106
108
 
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();
109
+ // Tab into the calendar grid (past month nav buttons), then arrow right to Saturday (disabled)
110
+ await userEvent.tab();
111
+ await userEvent.tab();
112
+ await userEvent.tab();
113
+ await userEvent.keyboard('{ArrowRight}');
110
114
 
111
- // Prompt should switch to negative after React re-render
112
- await waitFor(() => expect(prompt).toHaveClass('wds-prompt--negative'));
115
+ // Prompt should switch to negative after navigating to the disabled date
116
+ await waitFor(async () => expect(prompt).toHaveClass('wds-prompt--negative'));
113
117
  },
114
118
  };
@@ -0,0 +1,61 @@
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: () => (
58
+ <Carousel header="Carousel with navigation arrows" cards={sampleCards} />
59
+ ),
60
+ ...withRTLDiff(),
61
+ };
@@ -0,0 +1,31 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
+
3
+ import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
4
+ import Checkbox from '..';
5
+
6
+ export default {
7
+ component: Checkbox,
8
+ title: 'Forms/Checkbox/Tests',
9
+ tags: ['!autodocs', '!manifest'],
10
+ } satisfies Meta<typeof Checkbox>;
11
+
12
+ type Story = StoryObj<typeof Checkbox>;
13
+
14
+ /**
15
+ * The checkbox indicator sits to the start of the label: in LTR it appears on the left,
16
+ * in RTL it should appear on the right. The secondary line wraps under the label text,
17
+ * so both single-line and two-line layouts are verified here.
18
+ */
19
+ export const RTLDiff: Story = {
20
+ render: () => (
21
+ <>
22
+ <Checkbox label="Label only" onChange={() => {}} />
23
+ <Checkbox
24
+ label="Label with secondary"
25
+ secondary="Secondary description text"
26
+ onChange={() => {}}
27
+ />
28
+ </>
29
+ ),
30
+ ...withRTLDiff(),
31
+ };
@@ -0,0 +1,27 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
+ import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
3
+ import CheckboxButton from '../CheckboxButton';
4
+
5
+ export default {
6
+ component: CheckboxButton,
7
+ title: 'Actions/CheckboxButton/Tests',
8
+ tags: ['!autodocs', '!manifest'],
9
+ } satisfies Meta<typeof CheckboxButton>;
10
+
11
+ type Story = StoryObj<typeof CheckboxButton>;
12
+
13
+ export const RTLDiff: Story = {
14
+ render: () => (
15
+ <>
16
+ <CheckboxButton aria-label="Unchecked" checked={false} onChange={() => {}} />
17
+ <CheckboxButton aria-label="Checked" checked onChange={() => {}} />
18
+ <CheckboxButton
19
+ aria-label="Indeterminate"
20
+ checked={false}
21
+ indeterminate
22
+ onChange={() => {}}
23
+ />
24
+ </>
25
+ ),
26
+ ...withRTLDiff(),
27
+ };
@@ -181,43 +181,6 @@ export const KeyboardInteraction: Story = {
181
181
  },
182
182
  };
183
183
 
184
- /** Base checkbox states in right-to-left layout. */
185
- export const RTL: Story = {
186
- render: function Render() {
187
- const [unchecked, setUnchecked] = useState(false);
188
- const [checked, setChecked] = useState(true);
189
- const [indeterminate, setIndeterminate] = useState(false);
190
- return (
191
- <div style={{ display: 'flex', gap: '16px', alignItems: 'center', padding: '16px' }}>
192
- <CheckboxButton
193
- aria-label="Unchecked"
194
- checked={unchecked}
195
- onChange={() => setUnchecked((v) => !v)}
196
- />
197
- <CheckboxButton
198
- aria-label="Checked"
199
- checked={checked}
200
- onChange={() => setChecked((v) => !v)}
201
- />
202
- <CheckboxButton
203
- aria-label="Indeterminate"
204
- checked={indeterminate}
205
- indeterminate
206
- onChange={() => setIndeterminate((v) => !v)}
207
- />
208
- <CheckboxButton
209
- aria-label="Disabled unchecked"
210
- checked={false}
211
- disabled
212
- onChange={() => {}}
213
- />
214
- <CheckboxButton aria-label="Disabled checked" checked disabled onChange={() => {}} />
215
- </div>
216
- );
217
- },
218
- ...withVariantConfig(['rtl']),
219
- };
220
-
221
184
  /** Checkbox states at 400% zoom for accessibility testing. */
222
185
  export const Zoom400: Story = {
223
186
  render: () => (
@@ -0,0 +1,26 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
+
3
+ import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
4
+ import Chevron from '..';
5
+
6
+ export default {
7
+ component: Chevron,
8
+ title: 'Other/Chevron/Tests',
9
+ tags: ['!autodocs', '!manifest'],
10
+ } satisfies Meta<typeof Chevron>;
11
+
12
+ type Story = StoryObj<typeof Chevron>;
13
+
14
+ /**
15
+ * Chevrons pointing left or right should mirror their direction in RTL mode.
16
+ * A left-pointing chevron in LTR becomes right-pointing in RTL and vice versa.
17
+ */
18
+ export const RTLDiff: Story = {
19
+ render: () => (
20
+ <div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>
21
+ <Chevron orientation="left" size="md" />
22
+ <Chevron orientation="right" size="md" />
23
+ </div>
24
+ ),
25
+ ...withRTLDiff(),
26
+ };
@@ -0,0 +1,49 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
+ import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
3
+ import Chips from '../Chips';
4
+
5
+ export default {
6
+ component: Chips,
7
+ title: 'Actions/Chips/Tests',
8
+ tags: ['!autodocs', '!manifest'],
9
+ } satisfies Meta<typeof Chips>;
10
+
11
+ type Story = StoryObj<typeof Chips>;
12
+
13
+ const categoryChips = [
14
+ { value: 'all', label: 'All' },
15
+ { value: 'accounting', label: 'Accounting' },
16
+ { value: 'payroll', label: 'Payroll' },
17
+ { value: 'payments', label: 'Payments' },
18
+ ];
19
+
20
+ const amountChips = [
21
+ { value: 100, label: '100 GBP' },
22
+ { value: 200, label: '200 GBP' },
23
+ { value: 300, label: '300 GBP' },
24
+ { value: 500, label: '500 GBP+' },
25
+ ];
26
+
27
+ export const RTLDiff: Story = {
28
+ render: () => (
29
+ <>
30
+ {/* Choice mode: chip row order reverses in RTL */}
31
+ <Chips
32
+ chips={amountChips}
33
+ selected={300}
34
+ multiple={false}
35
+ aria-label="Transfer amount"
36
+ onChange={() => undefined}
37
+ />
38
+ {/* Filter mode: selected chips show close button on trailing end */}
39
+ <Chips
40
+ chips={categoryChips}
41
+ selected={['accounting', 'payments']}
42
+ multiple
43
+ aria-label="Category filter"
44
+ onChange={() => undefined}
45
+ />
46
+ </>
47
+ ),
48
+ ...withRTLDiff(),
49
+ };
@@ -121,40 +121,6 @@ export const FilterKeyboardInteraction: Story = {
121
121
  },
122
122
  };
123
123
 
124
- /** Filter and choice chips in right-to-left layout. */
125
- export const RTL: Story = {
126
- render: function Render() {
127
- const [filterSelected, setFilterSelected] = useState<readonly ChipValue[]>([
128
- 'accounting',
129
- 'payments',
130
- ]);
131
- const [choiceSelected, setChoiceSelected] = useState<ChipValue>(300);
132
-
133
- return (
134
- <div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
135
- <Chips
136
- chips={filterChips}
137
- multiple
138
- selected={filterSelected}
139
- aria-label="Category filter"
140
- onChange={({ selectedValue, isEnabled }) => {
141
- setFilterSelected((prev) =>
142
- isEnabled ? [...prev, selectedValue] : prev.filter((v) => v !== selectedValue),
143
- );
144
- }}
145
- />
146
- <Chips
147
- chips={choiceChips}
148
- selected={choiceSelected}
149
- aria-label="Transfer amount"
150
- onChange={({ selectedValue }) => setChoiceSelected(selectedValue)}
151
- />
152
- </div>
153
- );
154
- },
155
- ...withVariantConfig(['rtl']),
156
- };
157
-
158
124
  /** Filter chips at 400% zoom for accessibility testing. */
159
125
  export const Zoom400: Story = {
160
126
  render: function Render() {
@@ -2,7 +2,6 @@ import { Freeze, Plus, Send, Convert, Card } from '@transferwise/icons';
2
2
 
3
3
  import { Meta, StoryObj } from '@storybook/react-webpack5';
4
4
  import { expect, fn, userEvent, within } from 'storybook/test';
5
- import { useState } from 'react';
6
5
  import CircularButton from '../CircularButton';
7
6
  import Title from '../../Title';
8
7
  import Body from '../../Body';
@@ -135,73 +134,6 @@ export const KeyboardInteraction: Story = {
135
134
  },
136
135
  };
137
136
 
138
- /** Base variants in right-to-left layout. */
139
- export const RTL: Story = {
140
- render: function Render() {
141
- const [clicks, setClicks] = useState(0);
142
- const rowStyle = {
143
- display: 'grid',
144
- gridTemplateColumns: 'repeat(4, minmax(0, 100px))',
145
- gap: '16px',
146
- textAlign: 'center' as const,
147
- };
148
-
149
- return (
150
- <div style={{ display: 'flex', flexDirection: 'column', gap: '24px', padding: '16px' }}>
151
- <div style={rowStyle}>
152
- <CircularButton
153
- priority="primary"
154
- type="default"
155
- icon={<Send />}
156
- onClick={() => setClicks((c) => c + 1)}
157
- >
158
- Primary
159
- </CircularButton>
160
- <CircularButton
161
- priority="secondary"
162
- type="default"
163
- icon={<Plus />}
164
- onClick={() => setClicks((c) => c + 1)}
165
- >
166
- Secondary
167
- </CircularButton>
168
- <CircularButton disabled priority="primary" type="default" icon={<Card />}>
169
- Primary disabled
170
- </CircularButton>
171
- <CircularButton disabled priority="secondary" type="default" icon={<Card />}>
172
- Secondary disabled
173
- </CircularButton>
174
- </div>
175
- <div style={rowStyle}>
176
- <CircularButton
177
- priority="primary"
178
- type="negative"
179
- icon={<Send />}
180
- onClick={() => setClicks((c) => c + 1)}
181
- >
182
- Primary
183
- </CircularButton>
184
- <CircularButton
185
- priority="secondary"
186
- type="negative"
187
- icon={<Convert />}
188
- onClick={() => setClicks((c) => c + 1)}
189
- >
190
- Secondary
191
- </CircularButton>
192
- <CircularButton disabled priority="primary" type="negative" icon={<Card />}>
193
- Primary disabled
194
- </CircularButton>
195
- <CircularButton disabled priority="secondary" type="negative" icon={<Card />}>
196
- Secondary disabled
197
- </CircularButton>
198
- </div>
199
- </div>
200
- );
201
- },
202
- ...withVariantConfig(['rtl']),
203
- };
204
-
205
137
  /** Long labels are centered beneath the icon. */
206
138
  export const CenteredText: Story = {
207
139
  render: () => {
@@ -0,0 +1,25 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
+ import { fn } from 'storybook/test';
3
+
4
+ import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
5
+ import DateInput from '../DateInput';
6
+
7
+ export default {
8
+ component: DateInput,
9
+ title: 'Forms/DateInput/Tests',
10
+ tags: ['!autodocs', '!manifest'],
11
+ } satisfies Meta<typeof DateInput>;
12
+
13
+ type Story = StoryObj<typeof DateInput>;
14
+
15
+ export const RTLDiff: Story = {
16
+ render: () => (
17
+ <>
18
+ <DateInput size="sm" onChange={fn()} />
19
+ <DateInput size="md" onChange={fn()} />
20
+ <DateInput size="lg" onChange={fn()} />
21
+ <DateInput mode="month-year" onChange={fn()} />
22
+ </>
23
+ ),
24
+ ...withRTLDiff(),
25
+ };
@@ -0,0 +1,88 @@
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 DateLookup from '..';
6
+
7
+ export default {
8
+ component: DateLookup,
9
+ title: 'Forms/DateLookup/Tests/RTL Diff',
10
+ tags: ['!autodocs', '!manifest'],
11
+ } satisfies Meta<typeof DateLookup>;
12
+
13
+ type Story = StoryObj<typeof DateLookup>;
14
+
15
+ const selectedDate = new Date(2024, 5, 14);
16
+
17
+ export const TriggerVariants: Story = {
18
+ render: () => (
19
+ <>
20
+ <DateLookup
21
+ label="Select date"
22
+ placeholder="Choose a date"
23
+ value={selectedDate}
24
+ onChange={() => {}}
25
+ />
26
+ <DateLookup
27
+ label="Select date"
28
+ placeholder="Choose a date"
29
+ value={selectedDate}
30
+ clearable
31
+ onChange={() => {}}
32
+ />
33
+ <DateLookup
34
+ label="Select date"
35
+ placeholder="Choose a date"
36
+ size="sm"
37
+ value={selectedDate}
38
+ onChange={() => {}}
39
+ />
40
+ <DateLookup
41
+ label="Select date"
42
+ placeholder="Choose a date"
43
+ size="lg"
44
+ value={selectedDate}
45
+ onChange={() => {}}
46
+ />
47
+ </>
48
+ ),
49
+ ...withRTLDiff(),
50
+ };
51
+
52
+ const containerStyle: React.CSSProperties = {
53
+ display: 'flex',
54
+ justifyContent: 'center',
55
+ alignItems: 'flex-start',
56
+ minHeight: '24rem',
57
+ paddingTop: '2rem',
58
+ width: '100%',
59
+ };
60
+
61
+ export const OpenCalendarPanel: Story = {
62
+ render: () => (
63
+ <div style={containerStyle}>
64
+ <DateLookup
65
+ label="Select date"
66
+ placeholder="Choose a date"
67
+ value={selectedDate}
68
+ onChange={() => {}}
69
+ />
70
+ </div>
71
+ ),
72
+ play: async ({ canvasElement }: { canvasElement: HTMLElement }) => {
73
+ const canvas = within(canvasElement);
74
+ const trigger = canvas.queryByRole('button');
75
+ if (!trigger) return;
76
+ await userEvent.click(trigger);
77
+ // Suppress focus ring on calendar cells — FocusScope traps focus inside the panel
78
+ // and the autofocus cycle causes the selected date's ring to flicker between iframes.
79
+ const style = canvasElement.ownerDocument.createElement('style');
80
+ style.textContent = `
81
+ .np-panel__content *:focus {
82
+ outline: none !important;
83
+ box-shadow: none !important;
84
+ }`;
85
+ canvasElement.ownerDocument.head.appendChild(style);
86
+ },
87
+ ...withRTLDiff({ renderAs: 'iframe' }),
88
+ };
@@ -0,0 +1,79 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
+
3
+ import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
4
+ import { Size } from '../../common';
5
+ import Decision, { DecisionPresentation, DecisionType } from '..';
6
+ import AvatarView from '../../AvatarView';
7
+
8
+ export default {
9
+ component: Decision,
10
+ title: 'Layouts/Decision/Tests',
11
+ tags: ['!autodocs', '!manifest'],
12
+ } satisfies Meta<typeof Decision>;
13
+
14
+ type Story = StoryObj<typeof Decision>;
15
+
16
+ const options = [
17
+ {
18
+ title: 'Send money',
19
+ description: 'Fast international transfers.',
20
+ href: '#',
21
+ 'aria-label': 'Send money',
22
+ media: {
23
+ block: <img src="https://wise.com/public-resources/assets/illustrations/globe.svg" alt="" />,
24
+ list: <AvatarView profileName="Alice Smith" />,
25
+ },
26
+ },
27
+ {
28
+ title: 'Receive money',
29
+ description: 'Get paid from abroad.',
30
+ href: '#',
31
+ 'aria-label': 'Receive money',
32
+ media: {
33
+ block: <img src="https://wise.com/public-resources/assets/illustrations/globe.svg" alt="" />,
34
+ list: <AvatarView profileName="Alice Smith" />,
35
+ },
36
+ },
37
+ ];
38
+
39
+ /**
40
+ * NavigationOption renders media on the inline-start side and a chevron on the
41
+ * inline-end side; these flip in RTL. The LIST_BLOCK and LIST_BLOCK_GRID
42
+ * presentations use flex-row layout that also reverses direction in RTL.
43
+ */
44
+ export const RTLDiff: Story = {
45
+ render: () => (
46
+ <>
47
+ <Decision
48
+ options={options}
49
+ presentation={DecisionPresentation.LIST}
50
+ type={DecisionType.NAVIGATION}
51
+ />
52
+ <Decision
53
+ options={options}
54
+ presentation={DecisionPresentation.LIST}
55
+ type={DecisionType.NAVIGATION}
56
+ isContainerAligned
57
+ />
58
+ <Decision
59
+ options={options}
60
+ presentation={DecisionPresentation.LIST_BLOCK}
61
+ type={DecisionType.NAVIGATION}
62
+ size={Size.MEDIUM}
63
+ />
64
+ <Decision
65
+ options={options}
66
+ presentation={DecisionPresentation.LIST_BLOCK}
67
+ type={DecisionType.NAVIGATION}
68
+ size={Size.SMALL}
69
+ />
70
+ <Decision
71
+ options={[...options, ...options]}
72
+ presentation={DecisionPresentation.LIST_BLOCK_GRID}
73
+ type={DecisionType.NAVIGATION}
74
+ size={Size.MEDIUM}
75
+ />
76
+ </>
77
+ ),
78
+ ...withRTLDiff(),
79
+ };