@transferwise/components 46.116.1 → 46.117.0
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 +60 -131
- package/build/prompt/InlinePrompt/InlinePrompt.js +14 -8
- package/build/prompt/InlinePrompt/InlinePrompt.js.map +1 -1
- package/build/prompt/InlinePrompt/InlinePrompt.mjs +15 -9
- package/build/prompt/InlinePrompt/InlinePrompt.mjs.map +1 -1
- package/build/sentimentSurface/SentimentSurface.js +6 -5
- package/build/sentimentSurface/SentimentSurface.js.map +1 -1
- package/build/sentimentSurface/SentimentSurface.mjs +6 -5
- package/build/sentimentSurface/SentimentSurface.mjs.map +1 -1
- package/build/styles/button/Button.css +17 -17
- package/build/styles/button/Button.vars.css +16 -16
- package/build/styles/iconButton/IconButton.css +8 -8
- package/build/styles/link/Link.css +1 -0
- package/build/styles/main.css +60 -131
- package/build/styles/prompt/InlinePrompt/InlinePrompt.css +26 -105
- package/build/styles/sentimentSurface/SentimentSurface.css +8 -1
- package/build/types/prompt/InlinePrompt/InlinePrompt.d.ts +19 -3
- package/build/types/prompt/InlinePrompt/InlinePrompt.d.ts.map +1 -1
- package/build/types/sentimentSurface/SentimentSurface.d.ts +5 -4
- package/build/types/sentimentSurface/SentimentSurface.d.ts.map +1 -1
- package/build/types/sentimentSurface/SentimentSurface.types.d.ts +4 -16
- package/build/types/sentimentSurface/SentimentSurface.types.d.ts.map +1 -1
- package/build/types/test-utils/story-config.d.ts +24 -0
- package/build/types/test-utils/story-config.d.ts.map +1 -1
- package/package.json +12 -11
- package/src/button/Button.css +17 -17
- package/src/button/Button.less +1 -1
- package/src/button/Button.story.tsx +75 -110
- package/src/button/Button.tests.story.tsx +189 -0
- package/src/button/Button.vars.css +16 -16
- package/src/button/Button.vars.less +58 -18
- package/src/iconButton/IconButton.css +8 -8
- package/src/iconButton/IconButton.less +35 -4
- package/src/iconButton/IconButton.story.tsx +72 -3
- package/src/link/Link.css +1 -0
- package/src/link/Link.less +1 -0
- package/src/link/Link.story.tsx +28 -0
- package/src/main.css +60 -131
- package/src/prompt/InlinePrompt/InlinePrompt.css +26 -105
- package/src/prompt/InlinePrompt/InlinePrompt.less +31 -119
- package/src/prompt/InlinePrompt/InlinePrompt.spec.tsx +87 -29
- package/src/prompt/InlinePrompt/InlinePrompt.story.tsx +223 -31
- package/src/prompt/InlinePrompt/InlinePrompt.tsx +42 -11
- package/src/sentimentSurface/SentimentSurface.css +8 -1
- package/src/sentimentSurface/SentimentSurface.docs.mdx +32 -495
- package/src/sentimentSurface/SentimentSurface.less +121 -114
- package/src/sentimentSurface/SentimentSurface.spec.tsx +31 -11
- package/src/sentimentSurface/SentimentSurface.story.tsx +323 -108
- package/src/sentimentSurface/SentimentSurface.tests.story.tsx +90 -40
- package/src/sentimentSurface/SentimentSurface.tsx +16 -9
- package/src/sentimentSurface/SentimentSurface.types.ts +5 -20
- package/src/test-utils/story-config.ts +0 -1
- package/build/sentimentSurface/classMap.js +0 -17
- package/build/sentimentSurface/classMap.js.map +0 -1
- package/build/sentimentSurface/classMap.mjs +0 -14
- package/build/sentimentSurface/classMap.mjs.map +0 -1
- package/build/types/sentimentSurface/classMap.d.ts +0 -4
- package/build/types/sentimentSurface/classMap.d.ts.map +0 -1
- package/src/sentimentSurface/classMap.ts +0 -15
|
@@ -1,39 +1,231 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import type { ReactElement } from 'react';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
3
|
+
import { Taxi, Travel } from '@transferwise/icons';
|
|
4
|
+
import { lorem5 } from '../../test-utils';
|
|
5
|
+
import Link from '../../link';
|
|
6
|
+
import { InlinePrompt, InlinePromptProps } from './InlinePrompt';
|
|
4
7
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export const AllVariants = () => {
|
|
11
|
-
return (
|
|
8
|
+
const withComponentGrid =
|
|
9
|
+
({ maxWidth = 'auto', gap = '1rem' } = {}) =>
|
|
10
|
+
(Story: () => ReactElement) => (
|
|
12
11
|
<div
|
|
13
12
|
style={{
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
width: '100%',
|
|
14
|
+
display: 'flex',
|
|
15
|
+
flexDirection: 'column',
|
|
16
|
+
gap,
|
|
17
|
+
maxWidth,
|
|
19
18
|
}}
|
|
20
19
|
>
|
|
21
|
-
<
|
|
22
|
-
<InlinePrompt media={<Rewards />} sentiment="positive">
|
|
23
|
-
{lorem10}
|
|
24
|
-
</InlinePrompt>
|
|
25
|
-
<InlinePrompt sentiment="negative">{lorem5}</InlinePrompt>
|
|
26
|
-
<InlinePrompt sentiment="negative">{lorem10}</InlinePrompt>
|
|
27
|
-
<InlinePrompt sentiment="neutral">{lorem5}</InlinePrompt>
|
|
28
|
-
<InlinePrompt sentiment="neutral">{lorem10}</InlinePrompt>
|
|
29
|
-
<InlinePrompt sentiment="warning">{lorem5}</InlinePrompt>
|
|
30
|
-
<InlinePrompt sentiment="warning">{lorem10}</InlinePrompt>
|
|
31
|
-
<InlinePrompt sentiment="proposition">{lorem5}</InlinePrompt>
|
|
32
|
-
<InlinePrompt sentiment="proposition">{lorem10}</InlinePrompt>
|
|
33
|
-
<InlinePrompt sentiment="proposition" media={<CardWise />}>
|
|
34
|
-
{lorem10}
|
|
35
|
-
</InlinePrompt>
|
|
36
|
-
<InlinePrompt>{lorem5}</InlinePrompt>
|
|
20
|
+
<Story />
|
|
37
21
|
</div>
|
|
38
22
|
);
|
|
23
|
+
|
|
24
|
+
export default {
|
|
25
|
+
title: 'Internal/InlinePrompt',
|
|
26
|
+
component: InlinePrompt,
|
|
27
|
+
args: {
|
|
28
|
+
loading: false,
|
|
29
|
+
muted: false,
|
|
30
|
+
children: lorem5,
|
|
31
|
+
},
|
|
32
|
+
argTypes: {
|
|
33
|
+
sentiment: {
|
|
34
|
+
control: 'select',
|
|
35
|
+
options: ['positive', 'negative', 'neutral', 'warning', 'proposition'],
|
|
36
|
+
},
|
|
37
|
+
loading: {
|
|
38
|
+
control: 'boolean',
|
|
39
|
+
},
|
|
40
|
+
muted: {
|
|
41
|
+
control: 'boolean',
|
|
42
|
+
},
|
|
43
|
+
children: {
|
|
44
|
+
control: 'text',
|
|
45
|
+
table: {
|
|
46
|
+
type: { summary: 'ReactNode' },
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
parameters: {
|
|
51
|
+
docs: {
|
|
52
|
+
toc: true,
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
} satisfies Meta<InlinePromptProps>;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Convenience controls for previewing rich markup,
|
|
59
|
+
* not otherwise possible via Storybook
|
|
60
|
+
*/
|
|
61
|
+
type PreviewStoryArgs = InlinePromptProps & {
|
|
62
|
+
previewMedia: InlinePromptProps['media'];
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const previewArgGroup = {
|
|
66
|
+
category: 'Storybook Preview options',
|
|
67
|
+
type: {
|
|
68
|
+
summary: undefined,
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const previewArgTypes = {
|
|
73
|
+
previewMedia: {
|
|
74
|
+
name: 'Preview with `media`',
|
|
75
|
+
control: 'boolean',
|
|
76
|
+
mapping: {
|
|
77
|
+
false: undefined,
|
|
78
|
+
true: <Taxi />,
|
|
79
|
+
},
|
|
80
|
+
table: previewArgGroup,
|
|
81
|
+
},
|
|
82
|
+
} as const;
|
|
83
|
+
|
|
84
|
+
const getPropsForPreview = (
|
|
85
|
+
args: PreviewStoryArgs,
|
|
86
|
+
): [InlinePromptProps, Partial<InlinePromptProps>] => {
|
|
87
|
+
const { previewMedia, ...props } = args;
|
|
88
|
+
|
|
89
|
+
return [
|
|
90
|
+
props,
|
|
91
|
+
{
|
|
92
|
+
media: previewMedia,
|
|
93
|
+
},
|
|
94
|
+
];
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export const Playground: StoryObj<PreviewStoryArgs> = {
|
|
98
|
+
tags: ['!autodocs'],
|
|
99
|
+
argTypes: previewArgTypes,
|
|
100
|
+
args: {
|
|
101
|
+
previewMedia: false,
|
|
102
|
+
},
|
|
103
|
+
render: (args: PreviewStoryArgs) => {
|
|
104
|
+
const [props, previewProps] = getPropsForPreview(args);
|
|
105
|
+
return <InlinePrompt {...props} {...previewProps} />;
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Aside from the known `neutral`, `negative`, `warning` and `positive` sentiments, `InlinePrompt` is the first of the prompts to introduce a new `proposition` sentiment, which can be used to encourage the user to take an action that might benefit them.
|
|
111
|
+
*
|
|
112
|
+
* By default, its associated icon for the prompt is `GiftBox`.
|
|
113
|
+
*/
|
|
114
|
+
export const Sentiments: StoryObj<PreviewStoryArgs> = {
|
|
115
|
+
argTypes: previewArgTypes,
|
|
116
|
+
args: {
|
|
117
|
+
previewMedia: false,
|
|
118
|
+
},
|
|
119
|
+
render: (args: PreviewStoryArgs) => {
|
|
120
|
+
const [props, previewProps] = getPropsForPreview(args);
|
|
121
|
+
return (
|
|
122
|
+
<>
|
|
123
|
+
<InlinePrompt {...props} {...previewProps} sentiment="neutral">
|
|
124
|
+
This is a neutral prompt.
|
|
125
|
+
</InlinePrompt>
|
|
126
|
+
<InlinePrompt {...props} {...previewProps} sentiment="negative">
|
|
127
|
+
This is a negative prompt.
|
|
128
|
+
</InlinePrompt>
|
|
129
|
+
<InlinePrompt {...props} {...previewProps} sentiment="warning">
|
|
130
|
+
This is a warning prompt.
|
|
131
|
+
</InlinePrompt>
|
|
132
|
+
<InlinePrompt {...props} {...previewProps} sentiment="positive">
|
|
133
|
+
This is a positive prompt.
|
|
134
|
+
</InlinePrompt>
|
|
135
|
+
<InlinePrompt {...props} {...previewProps} sentiment="proposition">
|
|
136
|
+
This is a proposition prompt.
|
|
137
|
+
</InlinePrompt>
|
|
138
|
+
</>
|
|
139
|
+
);
|
|
140
|
+
},
|
|
141
|
+
decorators: [withComponentGrid()],
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Inline prompts are also used when forms need to check something in the background, like
|
|
146
|
+
* verifying an account number is real. Turning on the loading state will replace the icon with
|
|
147
|
+
* a spinner while waiting for the check to finish.
|
|
148
|
+
*/
|
|
149
|
+
export const Loading: StoryObj<PreviewStoryArgs> = {
|
|
150
|
+
argTypes: previewArgTypes,
|
|
151
|
+
args: {
|
|
152
|
+
loading: true,
|
|
153
|
+
previewMedia: false,
|
|
154
|
+
},
|
|
155
|
+
render: (args: PreviewStoryArgs) => {
|
|
156
|
+
const [props, previewProps] = getPropsForPreview(args);
|
|
157
|
+
return <InlinePrompt {...props} {...previewProps} />;
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Inline prompt is usually associated with a different component, such as `Input` or `ListItem`.
|
|
163
|
+
* When those components are disabled, the prompt is often used to communicate to the user why they
|
|
164
|
+
* cannot interact with them. For that reason, the prompt cannot inherit the usual disabled visual
|
|
165
|
+
* style, and it must retain its interactivity. To bring these 2 components visually closer to each
|
|
166
|
+
* other, `muted` prop introduces slightly reduced opacity and luminosity as well as a special
|
|
167
|
+
* backslash circle icon.
|
|
168
|
+
*/
|
|
169
|
+
export const Muted: StoryObj<PreviewStoryArgs> = {
|
|
170
|
+
argTypes: previewArgTypes,
|
|
171
|
+
args: {
|
|
172
|
+
muted: true,
|
|
173
|
+
previewMedia: false,
|
|
174
|
+
},
|
|
175
|
+
render: (args: PreviewStoryArgs) => {
|
|
176
|
+
const [props, previewProps] = getPropsForPreview(args);
|
|
177
|
+
return <InlinePrompt {...props} {...previewProps} />;
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* While main sentiments (`warning`, `negative`, `neutral`) must retain their associated
|
|
183
|
+
* `StatusIcons`, the `positive` and `proposition` ones allow for Icon overrides to bring it
|
|
184
|
+
* closer to the prompt's content.
|
|
185
|
+
*/
|
|
186
|
+
export const IconOverrides: StoryObj<PreviewStoryArgs> = {
|
|
187
|
+
render: (args: PreviewStoryArgs) => {
|
|
188
|
+
return (
|
|
189
|
+
<>
|
|
190
|
+
<InlinePrompt {...args} media={<Travel />} sentiment="positive">
|
|
191
|
+
Your travel account is set up and ready to use.
|
|
192
|
+
</InlinePrompt>
|
|
193
|
+
<InlinePrompt {...args} media={<Taxi />} sentiment="proposition">
|
|
194
|
+
Connect Wise with your taxi app to get exclusive discounts.
|
|
195
|
+
</InlinePrompt>
|
|
196
|
+
<InlinePrompt {...args} media={<Taxi />} sentiment="negative">
|
|
197
|
+
This icon override is ignored.
|
|
198
|
+
</InlinePrompt>
|
|
199
|
+
</>
|
|
200
|
+
);
|
|
201
|
+
},
|
|
202
|
+
decorators: [withComponentGrid()],
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* When configured with any of the supported sentiments, the colour scheme of the component will propagate to all of its supported descendants, such as instances of a `Link`, `Icon`, and `StatusIcon`.
|
|
207
|
+
*/
|
|
208
|
+
export const SentimentAwareness: StoryObj<PreviewStoryArgs> = {
|
|
209
|
+
argTypes: previewArgTypes,
|
|
210
|
+
args: {
|
|
211
|
+
previewMedia: false,
|
|
212
|
+
},
|
|
213
|
+
render: (args: PreviewStoryArgs) => {
|
|
214
|
+
const [props, previewProps] = getPropsForPreview(args);
|
|
215
|
+
|
|
216
|
+
return (
|
|
217
|
+
<>
|
|
218
|
+
<InlinePrompt {...props} {...previewProps} sentiment="negative">
|
|
219
|
+
This is a negative prompt with an <Link href="#">inline link</Link>.
|
|
220
|
+
</InlinePrompt>
|
|
221
|
+
<InlinePrompt {...props} {...previewProps} sentiment="positive">
|
|
222
|
+
This is a positive prompt with an <Link href="#">inline link</Link>.
|
|
223
|
+
</InlinePrompt>
|
|
224
|
+
<InlinePrompt {...props} {...previewProps} sentiment="proposition">
|
|
225
|
+
This is a proposition prompt with an <Link href="#">inline link</Link>.
|
|
226
|
+
</InlinePrompt>
|
|
227
|
+
</>
|
|
228
|
+
);
|
|
229
|
+
},
|
|
230
|
+
decorators: [withComponentGrid()],
|
|
39
231
|
};
|
|
@@ -4,23 +4,40 @@ import ProcessIndicator from '../../processIndicator';
|
|
|
4
4
|
import StatusIcon from '../../statusIcon';
|
|
5
5
|
import { clsx } from 'clsx';
|
|
6
6
|
import Body from '../../body';
|
|
7
|
+
import SentimentSurface from '../../sentimentSurface';
|
|
7
8
|
|
|
8
9
|
export type InlinePromptProps = {
|
|
10
|
+
/**
|
|
11
|
+
* The sentiment determines the colour scheme
|
|
12
|
+
*/
|
|
9
13
|
sentiment?:
|
|
10
14
|
| `${Sentiment.POSITIVE | Sentiment.NEGATIVE | Sentiment.NEUTRAL | Sentiment.WARNING}`
|
|
11
15
|
| 'proposition';
|
|
16
|
+
/**
|
|
17
|
+
* Replaces the icon with a spinner while waiting for the short-lived action to finish.
|
|
18
|
+
* @default false
|
|
19
|
+
*/
|
|
12
20
|
loading?: boolean;
|
|
13
21
|
/**
|
|
14
|
-
*
|
|
22
|
+
* While prompts cannot be fully (visually and functionally) disabled, this prop should be enabled
|
|
23
|
+
* they are associated with actually disabled component (e.g. a disabled list item or input).
|
|
24
|
+
* @default false
|
|
15
25
|
*/
|
|
16
26
|
muted?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Icon override for `proposition` and `positive` sentiments. Unsupported for remaining ones.
|
|
29
|
+
*/
|
|
30
|
+
media?: React.ReactNode;
|
|
17
31
|
id?: string;
|
|
18
32
|
className?: string;
|
|
19
33
|
'data-testid'?: string;
|
|
20
34
|
children: React.ReactNode;
|
|
21
|
-
media?: React.ReactNode;
|
|
22
35
|
};
|
|
23
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Inline prompts appear alongside a specific component on the screen. They help the user stay
|
|
39
|
+
* informed, fix something, or get more out of what they're doing.
|
|
40
|
+
*/
|
|
24
41
|
export const InlinePrompt = ({
|
|
25
42
|
sentiment = Sentiment.POSITIVE,
|
|
26
43
|
muted = false,
|
|
@@ -28,26 +45,40 @@ export const InlinePrompt = ({
|
|
|
28
45
|
className,
|
|
29
46
|
children,
|
|
30
47
|
media = null,
|
|
48
|
+
'data-testid': dataTestId,
|
|
31
49
|
...rest
|
|
32
50
|
}: InlinePromptProps) => {
|
|
51
|
+
const surfaceSentiment = sentiment === Sentiment.POSITIVE ? 'success' : sentiment;
|
|
52
|
+
|
|
33
53
|
const renderMedia = () => {
|
|
34
|
-
if (media && ['proposition', 'positive'].includes(sentiment)) {
|
|
35
|
-
return media;
|
|
36
|
-
}
|
|
37
|
-
if (sentiment === 'proposition') {
|
|
38
|
-
return <GiftBox />;
|
|
39
|
-
}
|
|
40
54
|
if (muted) {
|
|
41
55
|
return <BackslashCircle size={16} data-testid="InlinePrompt_Muted" />;
|
|
42
56
|
}
|
|
43
57
|
if (loading) {
|
|
44
|
-
return
|
|
58
|
+
return (
|
|
59
|
+
<ProcessIndicator
|
|
60
|
+
data-testid="InlinePrompt_ProcessIndicator"
|
|
61
|
+
size="xxs"
|
|
62
|
+
className="wds-inline-prompt-process-indicator"
|
|
63
|
+
/>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (sentiment === 'positive' && media) {
|
|
68
|
+
return media;
|
|
45
69
|
}
|
|
70
|
+
|
|
71
|
+
if (sentiment === 'proposition') {
|
|
72
|
+
return media || <GiftBox />;
|
|
73
|
+
}
|
|
74
|
+
|
|
46
75
|
return <StatusIcon size={16} sentiment={sentiment} />;
|
|
47
76
|
};
|
|
48
77
|
|
|
49
78
|
return (
|
|
50
|
-
<
|
|
79
|
+
<SentimentSurface
|
|
80
|
+
sentiment={surfaceSentiment}
|
|
81
|
+
data-testid={dataTestId}
|
|
51
82
|
className={clsx(
|
|
52
83
|
'wds-inline-prompt',
|
|
53
84
|
`wds-inline-prompt--${sentiment}`,
|
|
@@ -61,6 +92,6 @@ export const InlinePrompt = ({
|
|
|
61
92
|
>
|
|
62
93
|
<div className="wds-inline-prompt__media-wrapper">{renderMedia()}</div>
|
|
63
94
|
<Body>{children}</Body>
|
|
64
|
-
</
|
|
95
|
+
</SentimentSurface>
|
|
65
96
|
);
|
|
66
97
|
};
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
.wds-sentiment-surface {
|
|
2
|
+
--ring-outline-color: var(--color-sentiment-content-primary, var(--color-content-primary));
|
|
3
|
+
}
|
|
4
|
+
.wds-sentiment-surface--hasBaseStyles {
|
|
5
|
+
background-color: var(--color-sentiment-background-surface);
|
|
6
|
+
color: var(--color-sentiment-content-primary);
|
|
7
|
+
}
|
|
1
8
|
.np-theme-personal .wds-sentiment-surface-negative-base,
|
|
2
9
|
.np-theme-personal--bright-green .wds-sentiment-surface-negative-base {
|
|
3
10
|
--color-sentiment-content-primary: #CB272F;
|
|
@@ -32,7 +39,7 @@
|
|
|
32
39
|
--color-sentiment-interactive-secondary-active: #A72027;
|
|
33
40
|
--color-sentiment-interactive-secondary-neutral: #9B141B;
|
|
34
41
|
--color-sentiment-interactive-secondary-neutral-hover: #831116;
|
|
35
|
-
--color-sentiment-interactive-secondary-neutral-active: #
|
|
42
|
+
--color-sentiment-interactive-secondary-neutral-active: #6D0e13;
|
|
36
43
|
--color-sentiment-interactive-control: #CB272F;
|
|
37
44
|
--color-sentiment-interactive-control-hover: #B8232B;
|
|
38
45
|
--color-sentiment-interactive-control-active: #A72027;
|