@transferwise/components 0.0.0-experimental-cdb8834 → 0.0.0-experimental-2b6c540
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/main.css +5 -11
- package/build/prompt/ActionPrompt/ActionPrompt.js +0 -2
- package/build/prompt/ActionPrompt/ActionPrompt.js.map +1 -1
- package/build/prompt/ActionPrompt/ActionPrompt.mjs +0 -2
- package/build/prompt/ActionPrompt/ActionPrompt.mjs.map +1 -1
- package/build/prompt/InfoPrompt/InfoPrompt.js.map +1 -1
- package/build/prompt/InfoPrompt/InfoPrompt.mjs.map +1 -1
- package/build/prompt/InlinePrompt/InlinePrompt.js +1 -1
- package/build/prompt/InlinePrompt/InlinePrompt.js.map +1 -1
- package/build/prompt/InlinePrompt/InlinePrompt.mjs +1 -1
- package/build/prompt/InlinePrompt/InlinePrompt.mjs.map +1 -1
- package/build/styles/main.css +5 -11
- package/build/styles/prompt/ActionPrompt/ActionPrompt.css +0 -4
- package/build/styles/prompt/InfoPrompt/InfoPrompt.css +3 -3
- package/build/styles/prompt/InlinePrompt/InlinePrompt.css +2 -3
- package/build/styles/prompt/PrimitivePrompt/PrimitivePrompt.css +0 -1
- package/build/types/prompt/ActionPrompt/ActionPrompt.d.ts +7 -0
- package/build/types/prompt/ActionPrompt/ActionPrompt.d.ts.map +1 -1
- package/build/types/prompt/InfoPrompt/InfoPrompt.d.ts +4 -2
- package/build/types/prompt/InfoPrompt/InfoPrompt.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/iconButton/IconButton.story.tsx +173 -48
- package/src/iconButton/IconButton.test.story.tsx +194 -0
- package/src/listItem/_stories/ListItem.story.tsx +0 -1
- package/src/main.css +5 -11
- package/src/prompt/ActionPrompt/ActionPrompt.accessibility.docs.mdx +1 -17
- package/src/prompt/ActionPrompt/ActionPrompt.css +0 -4
- package/src/prompt/ActionPrompt/ActionPrompt.less +1 -5
- package/src/prompt/ActionPrompt/ActionPrompt.story.tsx +262 -119
- package/src/prompt/ActionPrompt/ActionPrompt.test.story.tsx +86 -3
- package/src/prompt/ActionPrompt/ActionPrompt.tsx +9 -6
- package/src/prompt/InfoPrompt/InfoPrompt.accessibility.docs.mdx +79 -0
- package/src/prompt/InfoPrompt/InfoPrompt.css +3 -3
- package/src/prompt/InfoPrompt/InfoPrompt.less +3 -4
- package/src/prompt/InfoPrompt/InfoPrompt.story.tsx +80 -109
- package/src/prompt/InfoPrompt/InfoPrompt.test.story.tsx +54 -1
- package/src/prompt/InfoPrompt/InfoPrompt.tsx +4 -2
- package/src/prompt/InlinePrompt/InlinePrompt.accessibility.docs.mdx +63 -0
- package/src/prompt/InlinePrompt/InlinePrompt.css +2 -3
- package/src/prompt/InlinePrompt/InlinePrompt.less +2 -2
- package/src/prompt/InlinePrompt/InlinePrompt.story.tsx +25 -30
- package/src/prompt/InlinePrompt/InlinePrompt.test.story.tsx +21 -0
- package/src/prompt/InlinePrompt/InlinePrompt.test.tsx +3 -10
- package/src/prompt/InlinePrompt/InlinePrompt.tsx +1 -1
- package/src/prompt/PrimitivePrompt/PrimitivePrompt.css +0 -1
- package/src/prompt/PrimitivePrompt/PrimitivePrompt.less +1 -2
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
.wds-info-prompt {
|
|
2
2
|
--Prompt-gap: var(--size-8);
|
|
3
|
-
--Prompt-padding:
|
|
3
|
+
--Prompt-padding: var(--size-12);
|
|
4
4
|
}
|
|
5
5
|
.wds-info-prompt__content {
|
|
6
6
|
display: flex;
|
|
7
7
|
flex-direction: column;
|
|
8
8
|
justify-content: center;
|
|
9
|
-
max-width: calc(48px * 10);
|
|
10
|
-
max-width: calc(var(--size-48) * 10);
|
|
11
9
|
}
|
|
12
10
|
.wds-info-prompt__content:has(.wds-info-prompt__title) {
|
|
13
11
|
justify-content: flex-start;
|
|
@@ -26,7 +24,9 @@
|
|
|
26
24
|
}
|
|
27
25
|
.wds-info-prompt__media svg {
|
|
28
26
|
width: 24px;
|
|
27
|
+
width: var(--size-24);
|
|
29
28
|
height: 24px;
|
|
29
|
+
height: var(--size-24);
|
|
30
30
|
}
|
|
31
31
|
.wds-info-prompt .wds-prompt__media-wrapper {
|
|
32
32
|
padding: 0;
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
.wds-info-prompt {
|
|
2
2
|
--Prompt-gap: var(--size-8);
|
|
3
|
-
--Prompt-padding:
|
|
3
|
+
--Prompt-padding: var(--size-12);
|
|
4
4
|
|
|
5
5
|
&__content {
|
|
6
6
|
display: flex;
|
|
7
7
|
flex-direction: column;
|
|
8
8
|
justify-content: center;
|
|
9
|
-
max-width: calc(var(--size-48) * 10);
|
|
10
9
|
|
|
11
10
|
&:has(.wds-info-prompt__title) {
|
|
12
11
|
justify-content: flex-start; /* Top align when title exists */
|
|
@@ -27,8 +26,8 @@
|
|
|
27
26
|
display: flex;
|
|
28
27
|
|
|
29
28
|
svg {
|
|
30
|
-
width:
|
|
31
|
-
height:
|
|
29
|
+
width: var(--size-24);
|
|
30
|
+
height: var(--size-24);
|
|
32
31
|
}
|
|
33
32
|
}
|
|
34
33
|
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { ReactElement } from 'react';
|
|
2
|
+
import { useState } from 'react';
|
|
2
3
|
import type { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
3
4
|
import { action } from 'storybook/actions';
|
|
4
|
-
import { Confetti, GiftBox, Star, Travel } from '@transferwise/icons';
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
5
|
+
import { Confetti, GiftBox, Star, Travel, Briefcase, Plane } from '@transferwise/icons';
|
|
6
|
+
import { InfoPrompt, InfoPromptProps, InfoPromptMedia } from './InfoPrompt';
|
|
7
|
+
import Button from '../../button';
|
|
8
|
+
import Title from '../../title';
|
|
7
9
|
|
|
8
10
|
const withComponentGrid =
|
|
9
11
|
({ maxWidth = 'auto', gap = '1rem' } = {}) =>
|
|
@@ -62,7 +64,7 @@ export default {
|
|
|
62
64
|
* not otherwise possible via Storybook
|
|
63
65
|
*/
|
|
64
66
|
type PreviewStoryArgs = InfoPromptProps & {
|
|
65
|
-
previewMedia:
|
|
67
|
+
previewMedia: InfoPromptMedia | undefined;
|
|
66
68
|
previewOnDismiss: boolean;
|
|
67
69
|
previewAction: boolean;
|
|
68
70
|
};
|
|
@@ -74,10 +76,22 @@ const previewArgGroup = {
|
|
|
74
76
|
},
|
|
75
77
|
};
|
|
76
78
|
|
|
79
|
+
const MEDIA_OPTIONS: Record<string, { asset: ReactElement } | undefined> = {
|
|
80
|
+
undefined,
|
|
81
|
+
star: { asset: <Star title="Starred" /> },
|
|
82
|
+
confetti: { asset: <Confetti size={24} title="Celebration" /> },
|
|
83
|
+
giftbox: { asset: <GiftBox title="Gift" /> },
|
|
84
|
+
travel: { asset: <Travel title="Travel" /> },
|
|
85
|
+
briefcase: { asset: <Briefcase title="Business" /> },
|
|
86
|
+
plane: { asset: <Plane title="Travel" /> },
|
|
87
|
+
};
|
|
88
|
+
|
|
77
89
|
const previewArgTypes = {
|
|
78
90
|
previewMedia: {
|
|
79
91
|
name: 'Preview with `media`',
|
|
80
|
-
control: '
|
|
92
|
+
control: 'select',
|
|
93
|
+
options: ['undefined', 'star', 'confetti', 'giftbox', 'travel', 'briefcase', 'plane'],
|
|
94
|
+
mapping: MEDIA_OPTIONS,
|
|
81
95
|
table: previewArgGroup,
|
|
82
96
|
},
|
|
83
97
|
previewOnDismiss: {
|
|
@@ -100,7 +114,7 @@ const getPropsForPreview = (
|
|
|
100
114
|
return [
|
|
101
115
|
props,
|
|
102
116
|
{
|
|
103
|
-
media: previewMedia
|
|
117
|
+
media: previewMedia,
|
|
104
118
|
onDismiss: previewOnDismiss ? action('onDismiss') : undefined,
|
|
105
119
|
action: previewAction
|
|
106
120
|
? { label: 'Learn more', onClick: action('action.onClick') }
|
|
@@ -110,12 +124,19 @@ const getPropsForPreview = (
|
|
|
110
124
|
};
|
|
111
125
|
|
|
112
126
|
export const Playground: StoryObj<PreviewStoryArgs> = {
|
|
113
|
-
|
|
114
|
-
|
|
127
|
+
argTypes: {
|
|
128
|
+
sentiment: {
|
|
129
|
+
control: 'radio',
|
|
130
|
+
options: ['success', 'negative', 'neutral', 'warning', 'proposition'],
|
|
131
|
+
},
|
|
132
|
+
...previewArgTypes,
|
|
133
|
+
},
|
|
115
134
|
args: {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
135
|
+
title: 'Payment successful',
|
|
136
|
+
description: 'Your payment is being processed.',
|
|
137
|
+
previewMedia: { asset: <Star title="Starred" /> },
|
|
138
|
+
previewOnDismiss: true,
|
|
139
|
+
previewAction: true,
|
|
119
140
|
},
|
|
120
141
|
render: (args: PreviewStoryArgs) => {
|
|
121
142
|
const [props, previewProps] = getPropsForPreview(args);
|
|
@@ -141,7 +162,6 @@ export const Sentiments: StoryObj<InfoPromptProps> = {
|
|
|
141
162
|
<InfoPrompt {...args} sentiment="proposition" description="Check out our new features!" />
|
|
142
163
|
</>
|
|
143
164
|
),
|
|
144
|
-
decorators: [withComponentGrid()],
|
|
145
165
|
};
|
|
146
166
|
|
|
147
167
|
/**
|
|
@@ -170,32 +190,6 @@ export const WithTitle: StoryObj<InfoPromptProps> = {
|
|
|
170
190
|
/>
|
|
171
191
|
</>
|
|
172
192
|
),
|
|
173
|
-
decorators: [withComponentGrid()],
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* When `onDismiss` is provided, a close button appears allowing users to dismiss the prompt.
|
|
178
|
-
* Note: The component itself is not automatically removed - you must handle state management.
|
|
179
|
-
*/
|
|
180
|
-
export const Dismissible: StoryObj<InfoPromptProps> = {
|
|
181
|
-
render: (args: InfoPromptProps) => (
|
|
182
|
-
<>
|
|
183
|
-
<InfoPrompt
|
|
184
|
-
{...args}
|
|
185
|
-
sentiment="success"
|
|
186
|
-
title="Success"
|
|
187
|
-
description="Your payment was successful."
|
|
188
|
-
onDismiss={action('onDismiss')}
|
|
189
|
-
/>
|
|
190
|
-
<InfoPrompt
|
|
191
|
-
{...args}
|
|
192
|
-
sentiment="neutral"
|
|
193
|
-
description="This message can be dismissed."
|
|
194
|
-
onDismiss={action('onDismiss')}
|
|
195
|
-
/>
|
|
196
|
-
</>
|
|
197
|
-
),
|
|
198
|
-
decorators: [withComponentGrid()],
|
|
199
193
|
};
|
|
200
194
|
|
|
201
195
|
/**
|
|
@@ -227,109 +221,86 @@ export const WithAction: StoryObj<InfoPromptProps> = {
|
|
|
227
221
|
/>
|
|
228
222
|
</>
|
|
229
223
|
),
|
|
230
|
-
decorators: [withComponentGrid()],
|
|
231
224
|
};
|
|
232
225
|
|
|
233
226
|
/**
|
|
234
|
-
*
|
|
235
|
-
*
|
|
227
|
+
* When `onDismiss` is provided, a close button appears allowing users to dismiss the prompt.
|
|
228
|
+
* Note: The component itself is not automatically removed - you must handle state management.
|
|
229
|
+
*/
|
|
230
|
+
export const Dismissible: StoryObj<InfoPromptProps> = {
|
|
231
|
+
render: function Render() {
|
|
232
|
+
const [showPrompt, setShowPrompt] = useState(true);
|
|
233
|
+
|
|
234
|
+
return (
|
|
235
|
+
<>
|
|
236
|
+
{showPrompt ? (
|
|
237
|
+
<InfoPrompt
|
|
238
|
+
sentiment="success"
|
|
239
|
+
title="Payment successful"
|
|
240
|
+
description="Your payment was successful."
|
|
241
|
+
onDismiss={() => setShowPrompt(false)}
|
|
242
|
+
/>
|
|
243
|
+
) : (
|
|
244
|
+
<Button v2 onClick={() => setShowPrompt(true)}>
|
|
245
|
+
Show prompt again
|
|
246
|
+
</Button>
|
|
247
|
+
)}
|
|
248
|
+
</>
|
|
249
|
+
);
|
|
250
|
+
},
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* InfoPrompt supports various media types to enhance visual communication.
|
|
255
|
+
*
|
|
256
|
+
* **Default**: Each sentiment has a default status icon that appears when no media is provided.
|
|
236
257
|
*
|
|
258
|
+
* **Icon Overrides**: Replace default icons with custom icons to match the prompt's visual language to its content.
|
|
237
259
|
* Success and proposition sentiments support both standard checkmark and confetti variations.
|
|
238
260
|
*/
|
|
239
|
-
export const
|
|
240
|
-
render: (args
|
|
261
|
+
export const MediaTypes: StoryObj<InfoPromptProps> = {
|
|
262
|
+
render: (args) => (
|
|
241
263
|
<>
|
|
264
|
+
<Title type="title-body">Default</Title>
|
|
265
|
+
<InfoPrompt
|
|
266
|
+
sentiment="success"
|
|
267
|
+
description="When no media is provided, the sentiment's default status icon is displayed."
|
|
268
|
+
/>
|
|
269
|
+
|
|
270
|
+
<Title type="title-body">Icon Overrides</Title>
|
|
242
271
|
<InfoPrompt
|
|
243
|
-
{...args}
|
|
244
272
|
sentiment="success"
|
|
245
273
|
description="Saved to favorites!"
|
|
246
274
|
media={{ asset: <Star title="Starred" /> }}
|
|
247
275
|
/>
|
|
248
276
|
<InfoPrompt
|
|
249
|
-
{...args}
|
|
250
277
|
sentiment="success"
|
|
251
278
|
title="Congratulations!"
|
|
252
279
|
description="You've completed all the steps."
|
|
253
280
|
media={{ asset: <Confetti size={24} title="Celebration" /> }}
|
|
254
281
|
/>
|
|
255
282
|
<InfoPrompt
|
|
256
|
-
{...args}
|
|
257
283
|
sentiment="proposition"
|
|
258
|
-
title="
|
|
284
|
+
title="Special offer"
|
|
259
285
|
description="New ways to send money with Wise!"
|
|
260
286
|
media={{ asset: <GiftBox title="Gift" /> }}
|
|
261
287
|
/>
|
|
262
288
|
<InfoPrompt
|
|
263
|
-
{...args}
|
|
264
289
|
sentiment="success"
|
|
265
290
|
description="Your travel account is ready!"
|
|
266
291
|
media={{ asset: <Travel title="Travel" /> }}
|
|
267
292
|
/>
|
|
268
|
-
</>
|
|
269
|
-
),
|
|
270
|
-
decorators: [withComponentGrid()],
|
|
271
|
-
};
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* InfoPrompt fully supports accessibility attributes through spread props.
|
|
275
|
-
* Use `role="status"` for non-critical updates or `role="alert"` for important messages.
|
|
276
|
-
*/
|
|
277
|
-
export const Accessibility: StoryObj<InfoPromptProps> = {
|
|
278
|
-
render: (args: InfoPromptProps) => (
|
|
279
|
-
<>
|
|
280
293
|
<InfoPrompt
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
description="
|
|
284
|
-
|
|
294
|
+
sentiment="warning"
|
|
295
|
+
title="Business travel"
|
|
296
|
+
description="Book your business trip with Wise."
|
|
297
|
+
media={{ asset: <Briefcase title="Business" /> }}
|
|
285
298
|
/>
|
|
286
299
|
<InfoPrompt
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
title="
|
|
290
|
-
description="Your session has expired. Please log in again."
|
|
291
|
-
role="alert"
|
|
300
|
+
sentiment="neutral"
|
|
301
|
+
description="Your flight is scheduled."
|
|
302
|
+
media={{ asset: <Plane title="Flight" /> }}
|
|
292
303
|
/>
|
|
293
304
|
</>
|
|
294
305
|
),
|
|
295
|
-
decorators: [withComponentGrid()],
|
|
296
|
-
};
|
|
297
|
-
|
|
298
|
-
/**
|
|
299
|
-
* While the component itself will stretch to the full available width, the text container will be
|
|
300
|
-
* capped at `480px` to ensure optimal readability.
|
|
301
|
-
*
|
|
302
|
-
* [Visit wise.design](https://wise.design/components/info-prompt#writing-an-info-prompt) for guidance on writing effective prompt messages that are concise and easy to understand.
|
|
303
|
-
*/
|
|
304
|
-
export const ParagraphWidth: StoryObj<PreviewStoryArgs> = {
|
|
305
|
-
parameters: {
|
|
306
|
-
docs: {
|
|
307
|
-
canvas: {
|
|
308
|
-
sourceState: 'hidden',
|
|
309
|
-
},
|
|
310
|
-
},
|
|
311
|
-
},
|
|
312
|
-
args: {
|
|
313
|
-
title: lorem10,
|
|
314
|
-
description: lorem20,
|
|
315
|
-
sentiment: 'success',
|
|
316
|
-
onDismiss: () => {},
|
|
317
|
-
},
|
|
318
|
-
};
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
* Complete example showing all features combined:
|
|
322
|
-
* sentiment, title, description, action, onDismiss, and custom media.
|
|
323
|
-
*/
|
|
324
|
-
export const CompleteExample: StoryObj<InfoPromptProps> = {
|
|
325
|
-
render: () => (
|
|
326
|
-
<InfoPrompt
|
|
327
|
-
sentiment="proposition"
|
|
328
|
-
title="Invite Friends & Earn"
|
|
329
|
-
description="Share Wise with friends and get £50 for each friend who makes their first transfer."
|
|
330
|
-
media={{ asset: <GiftBox title="Gift" /> }}
|
|
331
|
-
action={{ label: 'Invite friends', onClick: action('invite') }}
|
|
332
|
-
onDismiss={action('onDismiss')}
|
|
333
|
-
/>
|
|
334
|
-
),
|
|
335
306
|
};
|
|
@@ -1,7 +1,19 @@
|
|
|
1
|
-
import { useState, MouseEvent } from 'react';
|
|
1
|
+
import { useState, MouseEvent, ReactElement } from 'react';
|
|
2
2
|
import { userEvent, within, expect, waitFor } from 'storybook/test';
|
|
3
3
|
import { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
4
|
+
import { action } from 'storybook/actions';
|
|
5
|
+
import { Star } from '@transferwise/icons';
|
|
4
6
|
import { InfoPrompt, type InfoPromptProps } from './InfoPrompt';
|
|
7
|
+
import { allModes } from '../../../.storybook/modes';
|
|
8
|
+
import { withVariantConfig } from '../../../.storybook/helpers';
|
|
9
|
+
|
|
10
|
+
const withComponentGrid =
|
|
11
|
+
({ gap = '1rem' } = {}) =>
|
|
12
|
+
(Story: () => ReactElement) => (
|
|
13
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap }}>
|
|
14
|
+
<Story />
|
|
15
|
+
</div>
|
|
16
|
+
);
|
|
5
17
|
|
|
6
18
|
const meta = {
|
|
7
19
|
title: 'Prompts/InfoPrompt/Tests',
|
|
@@ -244,3 +256,44 @@ export const TouchInteraction: Story = {
|
|
|
244
256
|
);
|
|
245
257
|
},
|
|
246
258
|
};
|
|
259
|
+
|
|
260
|
+
export const AllThemesAndSentiments: Story = {
|
|
261
|
+
render: () => (
|
|
262
|
+
<>
|
|
263
|
+
{(['success', 'warning', 'negative', 'neutral', 'proposition'] as const).map((sentiment) => (
|
|
264
|
+
<InfoPrompt
|
|
265
|
+
key={sentiment}
|
|
266
|
+
sentiment={sentiment}
|
|
267
|
+
title={`${sentiment.charAt(0).toUpperCase() + sentiment.slice(1)} prompt`}
|
|
268
|
+
description="This demonstrates the prompt appearance in different themes."
|
|
269
|
+
media={sentiment === 'success' ? { asset: <Star title="Star" /> } : undefined}
|
|
270
|
+
action={{ label: 'Action', onClick: action('action') }}
|
|
271
|
+
onDismiss={action('dismiss')}
|
|
272
|
+
/>
|
|
273
|
+
))}
|
|
274
|
+
</>
|
|
275
|
+
),
|
|
276
|
+
decorators: [withComponentGrid({ gap: '1.5rem' })],
|
|
277
|
+
parameters: {
|
|
278
|
+
padding: '16px',
|
|
279
|
+
variants: ['default', 'dark', 'bright-green', 'forest-green'],
|
|
280
|
+
chromatic: {
|
|
281
|
+
dark: allModes.dark,
|
|
282
|
+
brightGreen: allModes.brightGreen,
|
|
283
|
+
forestGreen: allModes.forestGreen,
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
export const TinyScreen: Story = {
|
|
289
|
+
render: () => (
|
|
290
|
+
<InfoPrompt
|
|
291
|
+
sentiment="success"
|
|
292
|
+
title="Payment received"
|
|
293
|
+
description="Your transfer of 500 GBP has been successfully received and is now available in your account."
|
|
294
|
+
action={{ label: 'View details', onClick: action('view-details') }}
|
|
295
|
+
onDismiss={action('dismiss')}
|
|
296
|
+
/>
|
|
297
|
+
),
|
|
298
|
+
...withVariantConfig(['400%']),
|
|
299
|
+
};
|
|
@@ -18,8 +18,7 @@ export type InfoPromptAction = Pick<LinkProps, 'href' | 'target' | 'onClick'> &
|
|
|
18
18
|
export type InfoPromptMedia = {
|
|
19
19
|
/**
|
|
20
20
|
* The icon/image asset to display.
|
|
21
|
-
* The asset should include its own accessibility attributes (e.g. title, aria-label)
|
|
22
|
-
* if it conveys meaning, or aria-hidden="true" if decorative.
|
|
21
|
+
* The asset should include its own accessibility attributes (e.g. title, aria-label) if it conveys meaning.
|
|
23
22
|
*/
|
|
24
23
|
asset: ReactNode;
|
|
25
24
|
};
|
|
@@ -53,6 +52,7 @@ export type InfoPromptProps = Omit<HTMLAttributes<HTMLDivElement>, 'title'> &
|
|
|
53
52
|
* Description text for the prompt (required)
|
|
54
53
|
*/
|
|
55
54
|
description: string;
|
|
55
|
+
className?: string;
|
|
56
56
|
};
|
|
57
57
|
|
|
58
58
|
/**
|
|
@@ -61,6 +61,8 @@ export type InfoPromptProps = Omit<HTMLAttributes<HTMLDivElement>, 'title'> &
|
|
|
61
61
|
* or positive feedback with optional actions and dismissal capabilities.
|
|
62
62
|
*
|
|
63
63
|
* Use this component to replace the deprecated Alert component.
|
|
64
|
+
*
|
|
65
|
+
* Guidance can be found in the [design system](https://wise.design/components/info-prompt).
|
|
64
66
|
*/
|
|
65
67
|
export const InfoPrompt = ({
|
|
66
68
|
sentiment = 'neutral',
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Meta, Source } from '@storybook/addon-docs/blocks';
|
|
2
|
+
|
|
3
|
+
<Meta title="Prompts/InlinePrompt/Accessibility" />
|
|
4
|
+
|
|
5
|
+
# Accessibility
|
|
6
|
+
|
|
7
|
+
Under the hood, `InlinePrompt` is marked as `role="region"` for a section of content that users might want to navigate to directly.
|
|
8
|
+
|
|
9
|
+
By default, it's labelled by the `media` icon and the prompt's text content.
|
|
10
|
+
|
|
11
|
+
## Announcement Behaviour
|
|
12
|
+
|
|
13
|
+
`InlinePrompt` appears alongside a specific component on the screen (e.g., input fields, list items). It should not be announced via screen reader—neither assertively (`role="alert"`) nor politely (`role="status"`).
|
|
14
|
+
|
|
15
|
+
**Note:** For immediate user feedback that requires announcement, use [InfoPrompt](?path=/docs/prompts-infoprompt--docs) instead.
|
|
16
|
+
|
|
17
|
+
## Media Label
|
|
18
|
+
|
|
19
|
+
You can use the `mediaLabel` prop to override the icon's accessible name announced by screen readers. This is especially useful for custom icons or when you want to provide more context than the default sentiment label.
|
|
20
|
+
|
|
21
|
+
By default, sentiment icons have these labels:
|
|
22
|
+
|
|
23
|
+
- `positive`: "Success:"
|
|
24
|
+
- `negative`: "Error:"
|
|
25
|
+
- `warning`: "Warning:"
|
|
26
|
+
- `neutral`: "Information:"
|
|
27
|
+
- `proposition`: No label (GiftBox icon is decorative by default)
|
|
28
|
+
|
|
29
|
+
<Source
|
|
30
|
+
dark
|
|
31
|
+
code={`
|
|
32
|
+
<InlinePrompt
|
|
33
|
+
media={<Travel />}
|
|
34
|
+
sentiment="positive"
|
|
35
|
+
mediaLabel="Travel feature enabled: "
|
|
36
|
+
>
|
|
37
|
+
Your travel account is set up and ready to use.
|
|
38
|
+
</InlinePrompt>
|
|
39
|
+
|
|
40
|
+
<InlinePrompt
|
|
41
|
+
media={<Clock />}
|
|
42
|
+
sentiment="warning"
|
|
43
|
+
mediaLabel="Delayed processing: "
|
|
44
|
+
>
|
|
45
|
+
The account verification is taking longer than usual.
|
|
46
|
+
</InlinePrompt>
|
|
47
|
+
`}
|
|
48
|
+
/>
|
|
49
|
+
|
|
50
|
+
## Muted State
|
|
51
|
+
|
|
52
|
+
When a prompt is associated with a disabled component, use the `muted` prop to visually indicate the relationship while keeping the prompt accessible and interactive. The prompt remains keyboard accessible and can include interactive elements like links.
|
|
53
|
+
|
|
54
|
+
<Source
|
|
55
|
+
dark
|
|
56
|
+
code={`
|
|
57
|
+
<InlinePrompt muted sentiment="warning" mediaLabel="Feature locked: ">
|
|
58
|
+
Please <Link href="#">confirm your residential address</Link> to activate this feature.
|
|
59
|
+
</InlinePrompt>
|
|
60
|
+
`}
|
|
61
|
+
/>
|
|
62
|
+
|
|
63
|
+
The muted state uses a special backslash circle icon to indicate the disabled relationship, but the prompt itself remains fully accessible to screen readers and keyboard users.
|
|
@@ -18,9 +18,8 @@
|
|
|
18
18
|
.wds-inline-prompt:has(button):active {
|
|
19
19
|
background-color: var(--color-sentiment-background-surface-active);
|
|
20
20
|
}
|
|
21
|
-
.wds-inline-prompt--
|
|
22
|
-
width:
|
|
23
|
-
width: initial;
|
|
21
|
+
.wds-inline-prompt--full-width {
|
|
22
|
+
width: 100%;
|
|
24
23
|
}
|
|
25
24
|
.wds-inline-prompt--muted {
|
|
26
25
|
opacity: 0.93;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ReactElement } from 'react';
|
|
2
2
|
import type { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
3
3
|
import { action } from 'storybook/actions';
|
|
4
|
-
import { Clock, Taxi, Travel } from '@transferwise/icons';
|
|
4
|
+
import { Clock, Id, Taxi, Travel } from '@transferwise/icons';
|
|
5
5
|
import { lorem5 } from '../../test-utils';
|
|
6
6
|
import Link from '../../link';
|
|
7
7
|
import { InlinePrompt, InlinePromptProps } from './InlinePrompt';
|
|
@@ -144,7 +144,6 @@ export const Sentiments: StoryObj<PreviewStoryArgs> = {
|
|
|
144
144
|
</>
|
|
145
145
|
);
|
|
146
146
|
},
|
|
147
|
-
decorators: [withComponentGrid()],
|
|
148
147
|
};
|
|
149
148
|
|
|
150
149
|
/**
|
|
@@ -164,6 +163,30 @@ export const Loading: StoryObj<PreviewStoryArgs> = {
|
|
|
164
163
|
},
|
|
165
164
|
};
|
|
166
165
|
|
|
166
|
+
/**
|
|
167
|
+
* Inline prompt is usually associated with a different component, such as `Input` or `ListItem`.
|
|
168
|
+
* When those components are disabled, the prompt is often used to communicate to the user why they
|
|
169
|
+
* cannot interact with them. For that reason, the prompt cannot inherit the usual disabled visual
|
|
170
|
+
* style, and it must retain its interactivity. To bring these 2 components visually closer to each
|
|
171
|
+
* other, `muted` prop introduces slightly reduced opacity and luminosity as well as a special
|
|
172
|
+
* backslash circle icon.
|
|
173
|
+
*/
|
|
174
|
+
export const Muted: StoryObj<PreviewStoryArgs> = {
|
|
175
|
+
argTypes: previewArgTypes,
|
|
176
|
+
args: {
|
|
177
|
+
muted: true,
|
|
178
|
+
previewMedia: false,
|
|
179
|
+
},
|
|
180
|
+
render: (args: PreviewStoryArgs) => {
|
|
181
|
+
const [props, previewProps] = getPropsForPreview(args);
|
|
182
|
+
return (
|
|
183
|
+
<InlinePrompt {...props} {...previewProps}>
|
|
184
|
+
Please <Link href="#">confirm your residential address</Link> to activate this feature.
|
|
185
|
+
</InlinePrompt>
|
|
186
|
+
);
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
|
|
167
190
|
/**
|
|
168
191
|
* `InlinePrompt` can include a single instance of the `Link` component, which can be rendered as
|
|
169
192
|
* either HTML anchor or button. That element will spread across the whole surface of the Prompt
|
|
@@ -194,31 +217,6 @@ export const Interactivity: StoryObj<PreviewStoryArgs> = {
|
|
|
194
217
|
</InlinePrompt>
|
|
195
218
|
</>
|
|
196
219
|
),
|
|
197
|
-
decorators: [withComponentGrid()],
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Inline prompt is usually associated with a different component, such as `Input` or `ListItem`.
|
|
202
|
-
* When those components are disabled, the prompt is often used to communicate to the user why they
|
|
203
|
-
* cannot interact with them. For that reason, the prompt cannot inherit the usual disabled visual
|
|
204
|
-
* style, and it must retain its interactivity. To bring these 2 components visually closer to each
|
|
205
|
-
* other, `muted` prop introduces slightly reduced opacity and luminosity as well as a special
|
|
206
|
-
* backslash circle icon.
|
|
207
|
-
*/
|
|
208
|
-
export const Muted: StoryObj<PreviewStoryArgs> = {
|
|
209
|
-
argTypes: previewArgTypes,
|
|
210
|
-
args: {
|
|
211
|
-
muted: true,
|
|
212
|
-
previewMedia: false,
|
|
213
|
-
},
|
|
214
|
-
render: (args: PreviewStoryArgs) => {
|
|
215
|
-
const [props, previewProps] = getPropsForPreview(args);
|
|
216
|
-
return (
|
|
217
|
-
<InlinePrompt {...props} {...previewProps}>
|
|
218
|
-
Please <Link href="#">confirm your residential address</Link> to activate this feature.
|
|
219
|
-
</InlinePrompt>
|
|
220
|
-
);
|
|
221
|
-
},
|
|
222
220
|
};
|
|
223
221
|
|
|
224
222
|
/**
|
|
@@ -250,7 +248,6 @@ export const IconOverrides: StoryObj<PreviewStoryArgs> = {
|
|
|
250
248
|
</>
|
|
251
249
|
);
|
|
252
250
|
},
|
|
253
|
-
decorators: [withComponentGrid()],
|
|
254
251
|
};
|
|
255
252
|
|
|
256
253
|
/**
|
|
@@ -281,7 +278,6 @@ export const SizingStrategies: StoryObj<PreviewStoryArgs> = {
|
|
|
281
278
|
</>
|
|
282
279
|
);
|
|
283
280
|
},
|
|
284
|
-
decorators: [withComponentGrid()],
|
|
285
281
|
};
|
|
286
282
|
|
|
287
283
|
/**
|
|
@@ -309,5 +305,4 @@ export const SentimentAwareness: StoryObj<PreviewStoryArgs> = {
|
|
|
309
305
|
</>
|
|
310
306
|
);
|
|
311
307
|
},
|
|
312
|
-
decorators: [withComponentGrid()],
|
|
313
308
|
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { StoryObj } from '@storybook/react-webpack5';
|
|
2
|
+
import { Travel } from '@transferwise/icons';
|
|
3
|
+
import { InlinePrompt } from './InlinePrompt';
|
|
4
|
+
import { withVariantConfig } from '../../../.storybook/helpers';
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
title: 'Prompts/InlinePrompt/Tests',
|
|
8
|
+
component: InlinePrompt,
|
|
9
|
+
tags: ['!autodocs'],
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
type Story = StoryObj<typeof InlinePrompt>;
|
|
13
|
+
|
|
14
|
+
export const TinyScreen: Story = {
|
|
15
|
+
render: () => (
|
|
16
|
+
<InlinePrompt sentiment="positive" media={<Travel />}>
|
|
17
|
+
Your travel money account is now active and ready to use for international transactions.
|
|
18
|
+
</InlinePrompt>
|
|
19
|
+
),
|
|
20
|
+
...withVariantConfig(['400%']),
|
|
21
|
+
};
|
|
@@ -136,16 +136,9 @@ describe('InlinePrompt', () => {
|
|
|
136
136
|
expect(screen.getByTestId('prompt')).not.toHaveClass('wds-inline-prompt--full-width');
|
|
137
137
|
});
|
|
138
138
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
expect(screen.getByTestId('prompt')).toHaveClass('wds-inline-prompt--auto-width');
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
it('strips the class if `width` is set to `full`', () => {
|
|
146
|
-
render(<InlinePrompt {...defaultProps} width="full" data-testid="prompt" />);
|
|
147
|
-
expect(screen.getByTestId('prompt')).not.toHaveClass('wds-inline-prompt--auto-width');
|
|
148
|
-
});
|
|
139
|
+
it('applies full width class when set to full', () => {
|
|
140
|
+
render(<InlinePrompt {...defaultProps} width="full" data-testid="prompt" />);
|
|
141
|
+
expect(screen.getByTestId('prompt')).toHaveClass('wds-inline-prompt--full-width');
|
|
149
142
|
});
|
|
150
143
|
});
|
|
151
144
|
});
|
|
@@ -94,7 +94,7 @@ export const InlinePrompt = ({
|
|
|
94
94
|
className={clsx(
|
|
95
95
|
'wds-inline-prompt',
|
|
96
96
|
{
|
|
97
|
-
'wds-inline-prompt--
|
|
97
|
+
'wds-inline-prompt--full-width': width === 'full',
|
|
98
98
|
'wds-inline-prompt--muted': muted,
|
|
99
99
|
'wds-inline-prompt--loading': loading,
|
|
100
100
|
},
|