@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.
- package/build/i18n/cs.json +5 -0
- package/build/i18n/cs.json.js +5 -0
- package/build/i18n/cs.json.js.map +1 -1
- package/build/i18n/cs.json.mjs +5 -0
- package/build/i18n/cs.json.mjs.map +1 -1
- package/build/i18n/de.json +5 -0
- package/build/i18n/de.json.js +5 -0
- package/build/i18n/de.json.js.map +1 -1
- package/build/i18n/de.json.mjs +5 -0
- package/build/i18n/de.json.mjs.map +1 -1
- package/build/i18n/es.json +5 -0
- package/build/i18n/es.json.js +5 -0
- package/build/i18n/es.json.js.map +1 -1
- package/build/i18n/es.json.mjs +5 -0
- package/build/i18n/es.json.mjs.map +1 -1
- package/build/i18n/fr.json +5 -0
- package/build/i18n/fr.json.js +5 -0
- package/build/i18n/fr.json.js.map +1 -1
- package/build/i18n/fr.json.mjs +5 -0
- package/build/i18n/fr.json.mjs.map +1 -1
- package/build/i18n/hu.json +5 -0
- package/build/i18n/hu.json.js +5 -0
- package/build/i18n/hu.json.js.map +1 -1
- package/build/i18n/hu.json.mjs +5 -0
- package/build/i18n/hu.json.mjs.map +1 -1
- package/build/i18n/id.json +5 -0
- package/build/i18n/id.json.js +5 -0
- package/build/i18n/id.json.js.map +1 -1
- package/build/i18n/id.json.mjs +5 -0
- package/build/i18n/id.json.mjs.map +1 -1
- package/build/i18n/it.json +5 -0
- package/build/i18n/it.json.js +5 -0
- package/build/i18n/it.json.js.map +1 -1
- package/build/i18n/it.json.mjs +5 -0
- package/build/i18n/it.json.mjs.map +1 -1
- package/build/i18n/ja.json +5 -0
- package/build/i18n/ja.json.js +5 -0
- package/build/i18n/ja.json.js.map +1 -1
- package/build/i18n/ja.json.mjs +5 -0
- package/build/i18n/ja.json.mjs.map +1 -1
- package/build/i18n/nl.json +5 -0
- package/build/i18n/nl.json.js +5 -0
- package/build/i18n/nl.json.js.map +1 -1
- package/build/i18n/nl.json.mjs +5 -0
- package/build/i18n/nl.json.mjs.map +1 -1
- package/build/i18n/pl.json +5 -0
- package/build/i18n/pl.json.js +5 -0
- package/build/i18n/pl.json.js.map +1 -1
- package/build/i18n/pl.json.mjs +5 -0
- package/build/i18n/pl.json.mjs.map +1 -1
- package/build/i18n/pt.json +5 -0
- package/build/i18n/pt.json.js +5 -0
- package/build/i18n/pt.json.js.map +1 -1
- package/build/i18n/pt.json.mjs +5 -0
- package/build/i18n/pt.json.mjs.map +1 -1
- package/build/i18n/ro.json +5 -0
- package/build/i18n/ro.json.js +5 -0
- package/build/i18n/ro.json.js.map +1 -1
- package/build/i18n/ro.json.mjs +5 -0
- package/build/i18n/ro.json.mjs.map +1 -1
- package/build/i18n/ru.json +5 -0
- package/build/i18n/ru.json.js +5 -0
- package/build/i18n/ru.json.js.map +1 -1
- package/build/i18n/ru.json.mjs +5 -0
- package/build/i18n/ru.json.mjs.map +1 -1
- package/build/i18n/th.json +5 -0
- package/build/i18n/th.json.js +5 -0
- package/build/i18n/th.json.js.map +1 -1
- package/build/i18n/th.json.mjs +5 -0
- package/build/i18n/th.json.mjs.map +1 -1
- package/build/i18n/uk.json +5 -0
- package/build/i18n/uk.json.js +5 -0
- package/build/i18n/uk.json.js.map +1 -1
- package/build/i18n/uk.json.mjs +5 -0
- package/build/i18n/uk.json.mjs.map +1 -1
- package/build/i18n/zh-HK.json +5 -0
- package/build/i18n/zh-HK.json.js +5 -0
- package/build/i18n/zh-HK.json.js.map +1 -1
- package/build/i18n/zh-HK.json.mjs +5 -0
- package/build/i18n/zh-HK.json.mjs.map +1 -1
- package/build/main.css +4 -4104
- package/build/styles/ListItem/ListItem.css +1 -0
- package/build/styles/PocketSurface/PocketSurface.css +2 -11
- package/build/styles/SentimentSurface/SentimentSurface.css +0 -23
- package/build/styles/css/neptune.css +0 -2821
- package/build/styles/main.css +4 -4104
- package/build/styles/styles/less/neptune.css +0 -2821
- package/build/types/ListItem/_stories/variants/helpers.d.ts.map +1 -1
- package/package.json +10 -10
- package/src/Accordion/_stories/Accordion.test.story.tsx +71 -0
- package/src/AvatarLayout/_stories/AvatarLayout.test.story.tsx +64 -0
- package/src/AvatarView/_stories/AvatarView.test.story.tsx +151 -0
- package/src/Button/LegacyButton/_stories/LegacyButton.test.story.tsx +22 -0
- package/src/Button/_stories/Button.test.story.tsx +65 -0
- package/src/Calendar/_stories/Calendar.test.story.tsx +73 -24
- package/src/Carousel/_stories/Carousel.test.story.tsx +59 -0
- package/src/Checkbox/_stories/Checkbox.test.story.tsx +20 -0
- package/src/CheckboxButton/_stories/CheckboxButton.test.story.tsx +17 -37
- package/src/Chevron/_stories/Chevron.test.story.tsx +26 -0
- package/src/Chips/_stories/Chips.test.story.tsx +39 -34
- package/src/CircularButton/_stories/CircularButton.test.story.tsx +0 -68
- package/src/DateInput/_stories/DateInput.test.story.tsx +13 -0
- package/src/DateLookup/_stories/DateLookup.rtl.test.story.tsx +88 -0
- package/src/Decision/_stories/Decision.test.story.tsx +79 -0
- package/src/DefinitionList/_stories/DefinitionList.test.story.tsx +54 -1
- package/src/Drawer/_stories/Drawer.rtl.test.story.tsx +58 -0
- package/src/ExpressiveMoneyInput/_stories/ExpressiveMoneyInput.rtl.test.story.tsx +118 -0
- package/src/Field/_stories/Field.test.story.tsx +46 -0
- package/src/FlowNavigation/_stories/FlowNavigation.test.story.tsx +44 -0
- package/src/Header/_stories/Header.test.story.tsx +27 -0
- package/src/Info/_stories/Info.rtl.test.story.tsx +64 -0
- package/src/Inputs/SelectInput/_stories/SelectInput.rtl.test.story.tsx +135 -0
- package/src/Inputs/_stories/InputGroup.test.story.tsx +69 -0
- package/src/Inputs/_stories/SearchInput.test.story.tsx +32 -0
- package/src/Inputs/_stories/TextArea.test.story.tsx +27 -0
- package/src/InstructionsList/_stories/InstructionsList.test.story.tsx +30 -0
- package/src/Label/_stories/Label.test.story.tsx +36 -0
- package/src/Link/_stories/Link.test.story.tsx +26 -0
- package/src/ListItem/ListItem.css +1 -0
- package/src/ListItem/_stories/{variants/ListItem.rtl.test.story.tsx → ListItem.rtl.test.story.tsx} +6 -10
- package/src/ListItem/_stories/variants/helpers.tsx +2 -6
- package/src/Logo/_stories/Logo.test.story.tsx +44 -0
- package/src/Modal/_stories/Modal.rtl.test.story.tsx +59 -0
- package/src/MoneyInput/_stories/MoneyInput.rtl.test.story.tsx +88 -0
- package/src/Nudge/_stories/Nudge.test.story.tsx +37 -0
- package/src/PhoneNumberInput/_stories/PhoneNumberInput.test.story.tsx +44 -0
- package/src/PocketSurface/PocketSurface.css +2 -11
- package/src/PocketSurface/PocketSurface.less +1 -1
- package/src/Popover/_stories/Popover.rtl.test.story.tsx +96 -0
- package/src/Progress/_stories/Progress.test.story.tsx +27 -0
- package/src/ProgressBar/_stories/ProgressBar.test.story.tsx +33 -0
- package/src/PromoCard/_stories/PromoCard.test.story.tsx +42 -0
- package/src/PromoCard/_stories/PromoCardGroup.test.story.tsx +51 -0
- package/src/Prompt/ActionPrompt/_stories/ActionPrompt.test.story.tsx +42 -1
- package/src/Prompt/CriticalBanner/_stories/CriticalBanner.test.story.tsx +34 -31
- package/src/Prompt/InfoPrompt/_stories/InfoPrompt.test.story.tsx +25 -0
- package/src/Prompt/InlinePrompt/_stories/InlinePrompt.test.story.tsx +27 -0
- package/src/Radio/_stories/Radio.test.story.tsx +61 -0
- package/src/RadioGroup/_stories/RadioGroup.test.story.tsx +56 -0
- package/src/Section/_stories/Section.test.story.tsx +29 -0
- package/src/SegmentedControl/_stories/SegmentedControl.test.story.tsx +45 -0
- package/src/SentimentSurface/SentimentSurface.css +0 -23
- package/src/SlidingPanel/_stories/SlidingPanel.rtl.test.story.tsx +70 -0
- package/src/Snackbar/_stories/Snackbar.rtl.test.story.tsx +45 -0
- package/src/Snackbar/_stories/Snackbar.test.story.tsx +0 -31
- package/src/Stepper/_stories/Stepper.test.story.tsx +17 -0
- package/src/Switch/_stories/Switch.test.story.tsx +20 -26
- package/src/Table/_stories/Table.test.story.tsx +104 -0
- package/src/Tabs/_stories/Tabs.test.story.tsx +72 -0
- package/src/TextareaWithDisplayFormat/_stories/TextareaWithDisplayFormat.test.story.tsx +48 -0
- package/src/Tooltip/_stories/Tooltip.rtl.test.story.tsx +79 -0
- package/src/Typeahead/_stories/Typeahead.rtl.test.story.tsx +90 -0
- package/src/Upload/_stories/Upload.rtl.test.story.tsx +53 -0
- package/src/UploadInput/_stories/UploadInput.test.story.tsx +47 -0
- package/src/_deprecated/Alert/_stories/Alert.test.story.tsx +28 -1
- package/src/_deprecated/Card/_stories/Card.test.story.tsx +38 -0
- package/src/_deprecated/CriticalBanner/_stories/CriticalCommsBanner.test.story.tsx +18 -0
- package/src/_deprecated/InlineAlert/_stories/InlineAlert.test.story.tsx +26 -0
- package/src/_deprecated/OverlayHeader/_stories/OverlayHeader.test.story.tsx +42 -0
- package/src/_deprecated/Select/_stories/Select.rtl.test.story.tsx +71 -0
- package/src/common/BottomSheet/_stories/BottomSheet.test.story.tsx +23 -0
- package/src/i18n/cs.json +5 -0
- package/src/i18n/de.json +5 -0
- package/src/i18n/es.json +5 -0
- package/src/i18n/fr.json +5 -0
- package/src/i18n/hu.json +5 -0
- package/src/i18n/id.json +5 -0
- package/src/i18n/it.json +5 -0
- package/src/i18n/ja.json +5 -0
- package/src/i18n/nl.json +5 -0
- package/src/i18n/pl.json +5 -0
- package/src/i18n/pt.json +5 -0
- package/src/i18n/ro.json +5 -0
- package/src/i18n/ru.json +5 -0
- package/src/i18n/th.json +5 -0
- package/src/i18n/uk.json +5 -0
- package/src/i18n/zh-HK.json +5 -0
- package/src/main.css +4 -4104
- package/src/styles/less/neptune.css +0 -2821
|
@@ -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
|
+
};
|
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
2
|
+
import { userEvent, within } from 'storybook/test';
|
|
3
|
+
import { Flag } from '@wise/art';
|
|
4
|
+
|
|
5
|
+
import { withRTLDiff } from '../../../../.storybook/decorators/RtlDiffDecorator';
|
|
6
|
+
import { SelectInput, SelectInputOptionContent } from '..';
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
component: SelectInput,
|
|
10
|
+
title: 'Forms/SelectInput/Tests/RTL Diff',
|
|
11
|
+
tags: ['!autodocs', '!manifest'],
|
|
12
|
+
} satisfies Meta<typeof SelectInput>;
|
|
13
|
+
|
|
14
|
+
type Story = StoryObj<typeof SelectInput>;
|
|
15
|
+
|
|
16
|
+
interface RtlCurrency {
|
|
17
|
+
code: string;
|
|
18
|
+
name: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const rtlCurrencies: RtlCurrency[] = [
|
|
22
|
+
{ code: 'USD', name: 'United States Dollar' },
|
|
23
|
+
{ code: 'EUR', name: 'Euro' },
|
|
24
|
+
{ code: 'GBP', name: 'British pound' },
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
export const TriggerVariants: Story = {
|
|
28
|
+
render: () => (
|
|
29
|
+
<>
|
|
30
|
+
{/* sm — chevron position flips in RTL */}
|
|
31
|
+
<SelectInput
|
|
32
|
+
size="sm"
|
|
33
|
+
placeholder="Select currency"
|
|
34
|
+
items={rtlCurrencies.map((currency) => ({ type: 'option', value: currency }))}
|
|
35
|
+
renderValue={(currency) => <SelectInputOptionContent title={currency.code} />}
|
|
36
|
+
/>
|
|
37
|
+
|
|
38
|
+
{/* md — chevron position flips in RTL */}
|
|
39
|
+
<SelectInput
|
|
40
|
+
size="md"
|
|
41
|
+
placeholder="Select currency"
|
|
42
|
+
items={rtlCurrencies.map((currency) => ({ type: 'option', value: currency }))}
|
|
43
|
+
renderValue={(currency) => <SelectInputOptionContent title={currency.code} />}
|
|
44
|
+
/>
|
|
45
|
+
|
|
46
|
+
{/* lg with value and leading icon — icon side and chevron flip in RTL */}
|
|
47
|
+
<SelectInput
|
|
48
|
+
size="lg"
|
|
49
|
+
placeholder="Select currency"
|
|
50
|
+
defaultValue={rtlCurrencies[0]}
|
|
51
|
+
items={rtlCurrencies.map((currency) => ({ type: 'option', value: currency }))}
|
|
52
|
+
renderValue={(currency) => (
|
|
53
|
+
<SelectInputOptionContent
|
|
54
|
+
title={currency.code}
|
|
55
|
+
note={currency.name}
|
|
56
|
+
icon={<Flag code={currency.code} intrinsicSize={24} />}
|
|
57
|
+
/>
|
|
58
|
+
)}
|
|
59
|
+
/>
|
|
60
|
+
|
|
61
|
+
{/* multiple — selected values on leading side, chevron on trailing side, both flip in RTL */}
|
|
62
|
+
<SelectInput
|
|
63
|
+
size="lg"
|
|
64
|
+
multiple
|
|
65
|
+
placeholder="Choose currencies"
|
|
66
|
+
defaultValue={[rtlCurrencies[0], rtlCurrencies[1]]}
|
|
67
|
+
items={rtlCurrencies.map((currency) => ({ type: 'option', value: currency }))}
|
|
68
|
+
renderValue={(currency, withinTrigger) =>
|
|
69
|
+
withinTrigger ? (
|
|
70
|
+
currency.code
|
|
71
|
+
) : (
|
|
72
|
+
<SelectInputOptionContent title={currency.code} note={currency.name} />
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
/>
|
|
76
|
+
</>
|
|
77
|
+
),
|
|
78
|
+
...withRTLDiff(),
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const otherCurrencies: RtlCurrency[] = [
|
|
82
|
+
{ code: 'CAD', name: 'Canadian dollar' },
|
|
83
|
+
{ code: 'AUD', name: 'Australian dollar' },
|
|
84
|
+
{ code: 'JPY', name: 'Japanese yen' },
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
const groupedItems = [
|
|
88
|
+
{
|
|
89
|
+
type: 'group' as const,
|
|
90
|
+
label: 'Popular currencies',
|
|
91
|
+
options: rtlCurrencies.map((currency) => ({
|
|
92
|
+
type: 'option' as const,
|
|
93
|
+
value: currency,
|
|
94
|
+
filterMatchers: [currency.code, currency.name],
|
|
95
|
+
})),
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
type: 'group' as const,
|
|
99
|
+
label: 'All currencies',
|
|
100
|
+
options: [...rtlCurrencies, ...otherCurrencies]
|
|
101
|
+
.sort((a, b) => a.code.localeCompare(b.code))
|
|
102
|
+
.map((currency) => ({
|
|
103
|
+
type: 'option' as const,
|
|
104
|
+
value: currency,
|
|
105
|
+
filterMatchers: [currency.code, currency.name],
|
|
106
|
+
})),
|
|
107
|
+
},
|
|
108
|
+
];
|
|
109
|
+
|
|
110
|
+
export const OpenDropdown: Story = {
|
|
111
|
+
render: () => (
|
|
112
|
+
<SelectInput
|
|
113
|
+
size="lg"
|
|
114
|
+
filterable
|
|
115
|
+
filterPlaceholder="Type a currency / country"
|
|
116
|
+
placeholder="Select currency"
|
|
117
|
+
defaultValue={rtlCurrencies[0]}
|
|
118
|
+
items={groupedItems}
|
|
119
|
+
renderValue={(currency, withinTrigger) => (
|
|
120
|
+
<SelectInputOptionContent
|
|
121
|
+
title={currency.code}
|
|
122
|
+
note={withinTrigger ? undefined : currency.name}
|
|
123
|
+
icon={<Flag code={currency.code} intrinsicSize={24} />}
|
|
124
|
+
/>
|
|
125
|
+
)}
|
|
126
|
+
/>
|
|
127
|
+
),
|
|
128
|
+
play: async ({ canvasElement }) => {
|
|
129
|
+
const canvas = within(canvasElement);
|
|
130
|
+
const trigger = canvas.queryByRole('combobox');
|
|
131
|
+
if (!trigger) return;
|
|
132
|
+
await userEvent.click(trigger);
|
|
133
|
+
},
|
|
134
|
+
...withRTLDiff({ renderAs: 'iframe', width: '80%' }),
|
|
135
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
2
|
+
import { Search } from '@transferwise/icons';
|
|
3
|
+
|
|
4
|
+
import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
|
|
5
|
+
import Button from '../../Button';
|
|
6
|
+
import { Input } from '../Input/Input';
|
|
7
|
+
import { InputGroup } from '../InputGroup/InputGroup';
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
component: InputGroup,
|
|
11
|
+
title: 'Forms/InputGroup/Tests',
|
|
12
|
+
tags: ['!autodocs', '!manifest'],
|
|
13
|
+
} satisfies Meta<typeof InputGroup>;
|
|
14
|
+
|
|
15
|
+
type Story = StoryObj<typeof InputGroup>;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* InputGroup positions addons at the logical start or end of an input.
|
|
19
|
+
* In RTL mode the start and end sides are mirrored, so an addonStart icon
|
|
20
|
+
* should appear on the right and an addonEnd button should appear on the left.
|
|
21
|
+
* All three placement combinations are included to verify each case.
|
|
22
|
+
*/
|
|
23
|
+
export const RTLDiff: Story = {
|
|
24
|
+
render: () => (
|
|
25
|
+
<>
|
|
26
|
+
<InputGroup
|
|
27
|
+
addonStart={{
|
|
28
|
+
content: <Search size={24} />,
|
|
29
|
+
initialContentWidth: 24,
|
|
30
|
+
}}
|
|
31
|
+
>
|
|
32
|
+
<Input placeholder="addonStart only" />
|
|
33
|
+
</InputGroup>
|
|
34
|
+
|
|
35
|
+
<InputGroup
|
|
36
|
+
addonEnd={{
|
|
37
|
+
content: (
|
|
38
|
+
<Button v2 size="sm">
|
|
39
|
+
Copy
|
|
40
|
+
</Button>
|
|
41
|
+
),
|
|
42
|
+
interactive: true,
|
|
43
|
+
padding: 'sm',
|
|
44
|
+
}}
|
|
45
|
+
>
|
|
46
|
+
<Input placeholder="addonEnd only" />
|
|
47
|
+
</InputGroup>
|
|
48
|
+
|
|
49
|
+
<InputGroup
|
|
50
|
+
addonStart={{
|
|
51
|
+
content: <Search size={24} />,
|
|
52
|
+
initialContentWidth: 24,
|
|
53
|
+
}}
|
|
54
|
+
addonEnd={{
|
|
55
|
+
content: (
|
|
56
|
+
<Button v2 size="sm">
|
|
57
|
+
Clear
|
|
58
|
+
</Button>
|
|
59
|
+
),
|
|
60
|
+
interactive: true,
|
|
61
|
+
padding: 'sm',
|
|
62
|
+
}}
|
|
63
|
+
>
|
|
64
|
+
<Input placeholder="addonStart and addonEnd" />
|
|
65
|
+
</InputGroup>
|
|
66
|
+
</>
|
|
67
|
+
),
|
|
68
|
+
...withRTLDiff(),
|
|
69
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
2
|
+
|
|
3
|
+
import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
|
|
4
|
+
import { Size } from '../../common';
|
|
5
|
+
import { SearchInput } from '../SearchInput/SearchInput';
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
component: SearchInput,
|
|
9
|
+
title: 'Forms/SearchInput/Tests',
|
|
10
|
+
tags: ['!autodocs', '!manifest'],
|
|
11
|
+
} satisfies Meta<typeof SearchInput>;
|
|
12
|
+
|
|
13
|
+
type Story = StoryObj<typeof SearchInput>;
|
|
14
|
+
|
|
15
|
+
export const RTLDiff: Story = {
|
|
16
|
+
render: () => (
|
|
17
|
+
<>
|
|
18
|
+
{/* sm — search icon (addonStart) position flips to trailing side in RTL */}
|
|
19
|
+
<SearchInput size={Size.SMALL} shape="pill" placeholder="Search" />
|
|
20
|
+
|
|
21
|
+
{/* md — search icon (addonStart) position flips to trailing side in RTL */}
|
|
22
|
+
<SearchInput size={Size.MEDIUM} shape="pill" placeholder="Search" />
|
|
23
|
+
|
|
24
|
+
{/* sm rectangle — icon flip with rectangle shape */}
|
|
25
|
+
<SearchInput size={Size.SMALL} shape="rectangle" placeholder="Search" />
|
|
26
|
+
|
|
27
|
+
{/* md rectangle — icon flip with rectangle shape */}
|
|
28
|
+
<SearchInput size={Size.MEDIUM} shape="rectangle" placeholder="Search" />
|
|
29
|
+
</>
|
|
30
|
+
),
|
|
31
|
+
...withRTLDiff(),
|
|
32
|
+
};
|
|
@@ -2,7 +2,9 @@ import { useState } from 'react';
|
|
|
2
2
|
import { userEvent, within } from 'storybook/test';
|
|
3
3
|
import { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
4
4
|
|
|
5
|
+
import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
|
|
5
6
|
import Field from '../../Field';
|
|
7
|
+
import { Sentiment } from '../../common';
|
|
6
8
|
import { TextArea } from '../TextArea/TextArea';
|
|
7
9
|
|
|
8
10
|
const meta: Meta<typeof TextArea> = {
|
|
@@ -140,3 +142,28 @@ export const CJKTypingBlocked: Story = {
|
|
|
140
142
|
await userEvent.paste('吉𣘺吉𣘺吉𣘺');
|
|
141
143
|
},
|
|
142
144
|
};
|
|
145
|
+
|
|
146
|
+
export const RTLDiff: Story = {
|
|
147
|
+
render: () => (
|
|
148
|
+
<>
|
|
149
|
+
<Field label="Message" required={false}>
|
|
150
|
+
<TextArea placeholder="Type something..." />
|
|
151
|
+
</Field>
|
|
152
|
+
<Field label="Message" required={false}>
|
|
153
|
+
<TextArea value="This is some entered text content in the textarea field." readOnly />
|
|
154
|
+
</Field>
|
|
155
|
+
<Field
|
|
156
|
+
label="Message"
|
|
157
|
+
required={false}
|
|
158
|
+
sentiment={Sentiment.NEGATIVE}
|
|
159
|
+
message="This field has an error message"
|
|
160
|
+
>
|
|
161
|
+
<TextArea value="Invalid input text" readOnly />
|
|
162
|
+
</Field>
|
|
163
|
+
<Field label="Message with character count" required={false}>
|
|
164
|
+
<TextArea maxLength={200} value="Text with a character counter displayed below." readOnly />
|
|
165
|
+
</Field>
|
|
166
|
+
</>
|
|
167
|
+
),
|
|
168
|
+
...withRTLDiff(),
|
|
169
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
2
|
+
|
|
3
|
+
import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
|
|
4
|
+
import InstructionsList from '..';
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
component: InstructionsList,
|
|
8
|
+
title: 'Typography/InstructionsList/Tests',
|
|
9
|
+
tags: ['!autodocs', '!manifest'],
|
|
10
|
+
} satisfies Meta<typeof InstructionsList>;
|
|
11
|
+
|
|
12
|
+
type Story = StoryObj<typeof InstructionsList>;
|
|
13
|
+
|
|
14
|
+
export const RTLDiff: Story = {
|
|
15
|
+
render: () => (
|
|
16
|
+
<>
|
|
17
|
+
<InstructionsList
|
|
18
|
+
dos={['Do an initial money transfer', 'Invite at least 3 friends to join']}
|
|
19
|
+
donts={['Paying extra hidden fees for transfers', 'Use bad exchange rate']}
|
|
20
|
+
sort="dosFirst"
|
|
21
|
+
/>
|
|
22
|
+
<InstructionsList
|
|
23
|
+
dos={['Complete your profile verification']}
|
|
24
|
+
donts={['Share your login credentials with others']}
|
|
25
|
+
sort="dontsFirst"
|
|
26
|
+
/>
|
|
27
|
+
</>
|
|
28
|
+
),
|
|
29
|
+
...withRTLDiff(),
|
|
30
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
2
|
+
import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
|
|
3
|
+
import Info from '../../Info';
|
|
4
|
+
import Label from '..';
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
component: Label,
|
|
8
|
+
title: 'Forms/Label/Tests',
|
|
9
|
+
tags: ['!autodocs', '!manifest'],
|
|
10
|
+
} satisfies Meta<typeof Label>;
|
|
11
|
+
|
|
12
|
+
type Story = StoryObj<typeof Label>;
|
|
13
|
+
|
|
14
|
+
export const RTLDiff: Story = {
|
|
15
|
+
render: () => (
|
|
16
|
+
<>
|
|
17
|
+
<Label>Plain label text</Label>
|
|
18
|
+
<Label>
|
|
19
|
+
<Label.Optional>Label with optional marker</Label.Optional>
|
|
20
|
+
</Label>
|
|
21
|
+
<Label>
|
|
22
|
+
<div>
|
|
23
|
+
Label with info icon{' '}
|
|
24
|
+
<Info content="Helpful tooltip content" aria-label="More information" />
|
|
25
|
+
</div>
|
|
26
|
+
</Label>
|
|
27
|
+
<Label>
|
|
28
|
+
<Label.Optional>
|
|
29
|
+
Label with optional and info icon{' '}
|
|
30
|
+
<Info content="Helpful tooltip content" aria-label="More information" />
|
|
31
|
+
</Label.Optional>
|
|
32
|
+
</Label>
|
|
33
|
+
</>
|
|
34
|
+
),
|
|
35
|
+
...withRTLDiff(),
|
|
36
|
+
};
|