@transferwise/components 46.40.0 → 46.41.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/index.js +68 -74
- package/build/index.js.map +1 -1
- package/build/index.mjs +69 -75
- package/build/index.mjs.map +1 -1
- package/build/main.css +69 -14
- package/build/styles/main.css +69 -14
- package/build/styles/statusIcon/StatusIcon.css +4 -2
- package/build/styles/uploadInput/UploadInput.css +18 -1
- package/build/styles/uploadInput/uploadButton/UploadButton.css +4 -0
- package/build/styles/uploadInput/uploadItem/UploadItem.css +43 -11
- package/build/types/dateInput/DateInput.d.ts.map +1 -1
- package/build/types/field/Field.d.ts +6 -1
- package/build/types/field/Field.d.ts.map +1 -1
- package/build/types/inlineAlert/InlineAlert.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/dateInput/DateInput.spec.tsx +220 -0
- package/src/dateInput/DateInput.story.tsx +3 -76
- package/src/dateInput/DateInput.tests.story.tsx +238 -0
- package/src/dateInput/DateInput.tsx +50 -53
- package/src/field/Field.story.tsx +17 -36
- package/src/field/Field.tests.story.tsx +33 -0
- package/src/field/Field.tsx +23 -13
- package/src/inlineAlert/InlineAlert.story.tsx +13 -5
- package/src/inlineAlert/InlineAlert.tsx +13 -6
- package/src/main.css +69 -14
- package/src/statusIcon/StatusIcon.css +4 -2
- package/src/statusIcon/StatusIcon.less +4 -2
- package/src/statusIcon/StatusIcon.tsx +1 -1
- package/src/uploadInput/UploadInput.css +18 -1
- package/src/uploadInput/UploadInput.less +17 -1
- package/src/uploadInput/UploadInput.tests.story.tsx +13 -2
- package/src/uploadInput/uploadButton/UploadButton.css +4 -0
- package/src/uploadInput/uploadButton/UploadButton.less +5 -0
- package/src/uploadInput/uploadItem/UploadItem.css +43 -11
- package/src/uploadInput/uploadItem/UploadItem.less +61 -17
- package/src/dateInput/DateInput.rtl.spec.tsx +0 -17
- package/src/dateInput/DateInput.spec.js +0 -477
|
@@ -2,8 +2,16 @@ import classNames from 'classnames';
|
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import { useIntl } from 'react-intl';
|
|
4
4
|
|
|
5
|
-
import { Input, SelectInput, SelectInputOptionContent, SelectInputProps } from '..';
|
|
6
|
-
import {
|
|
5
|
+
import { Body, Input, SelectInput, SelectInputOptionContent, SelectInputProps } from '..';
|
|
6
|
+
import {
|
|
7
|
+
DateMode,
|
|
8
|
+
MonthFormat,
|
|
9
|
+
Size,
|
|
10
|
+
SizeLarge,
|
|
11
|
+
SizeMedium,
|
|
12
|
+
SizeSmall,
|
|
13
|
+
Typography,
|
|
14
|
+
} from '../common';
|
|
7
15
|
import { MDY, YMD, getMonthNames, isDateValid, isMonthAndYearFormat } from '../common/dateUtils';
|
|
8
16
|
import { useInputAttributes } from '../inputs/contexts';
|
|
9
17
|
import messages from './DateInput.messages';
|
|
@@ -93,8 +101,10 @@ const DateInput = ({
|
|
|
93
101
|
};
|
|
94
102
|
|
|
95
103
|
const [day, setDay] = useState(() => getInitialDate('day'));
|
|
104
|
+
const [displayDay, setDisplayDay] = useState(day?.toString());
|
|
96
105
|
const [month, setMonth] = useState(() => getInitialDate('month'));
|
|
97
106
|
const [year, setYear] = useState(() => getInitialDate('year'));
|
|
107
|
+
const [displayYear, setDisplayYear] = useState(year?.toString());
|
|
98
108
|
const [lastBroadcastedValue, setLastBroadcastedValue] = useState<Date | null | undefined>(
|
|
99
109
|
getDateObject,
|
|
100
110
|
);
|
|
@@ -129,7 +139,7 @@ const DateInput = ({
|
|
|
129
139
|
const getSelectElement = () => {
|
|
130
140
|
return (
|
|
131
141
|
<label className="d-flex flex-column">
|
|
132
|
-
<
|
|
142
|
+
<Body type={Typography.BODY_DEFAULT}>{monthLabel}</Body>
|
|
133
143
|
<SelectInput
|
|
134
144
|
name="month"
|
|
135
145
|
disabled={disabled}
|
|
@@ -147,13 +157,25 @@ const DateInput = ({
|
|
|
147
157
|
);
|
|
148
158
|
};
|
|
149
159
|
|
|
160
|
+
const isDayValid = (newDay: number, newMonth: number, newYear: number) => {
|
|
161
|
+
const maxDay = new Date(newYear, newMonth + 1, 0).getDate();
|
|
162
|
+
return newDay <= maxDay;
|
|
163
|
+
};
|
|
164
|
+
|
|
150
165
|
const handleInternalValue = (newDay = day, newMonth = month, newYear = year) => {
|
|
151
|
-
if (newDay == null || newMonth == null || newYear == null) {
|
|
166
|
+
if (newDay == null || newDay === 0 || newMonth == null || newYear == null || newYear === 0) {
|
|
167
|
+
broadcastNewValue(null);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
if (!isDayValid(newDay, newMonth, newYear)) {
|
|
152
171
|
broadcastNewValue(null);
|
|
153
172
|
return;
|
|
154
173
|
}
|
|
155
174
|
|
|
156
175
|
const dateValue = new Date(newYear, newMonth, newDay);
|
|
176
|
+
if (newYear < 100) {
|
|
177
|
+
dateValue.setFullYear(newYear);
|
|
178
|
+
}
|
|
157
179
|
|
|
158
180
|
if (!isDateValid(dateValue)) {
|
|
159
181
|
broadcastNewValue(null);
|
|
@@ -170,9 +192,12 @@ const DateInput = ({
|
|
|
170
192
|
};
|
|
171
193
|
|
|
172
194
|
const handleDayChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
195
|
+
const newDayString = event.target.value.replace(/\D/g, '');
|
|
196
|
+
const newDayNumber = Number.parseInt(newDayString, 10);
|
|
197
|
+
|
|
198
|
+
setDay(newDayNumber);
|
|
199
|
+
setDisplayDay(newDayString);
|
|
200
|
+
handleInternalValue(newDayNumber, month, year);
|
|
176
201
|
};
|
|
177
202
|
|
|
178
203
|
const handleMonthChange = (selectedMonth: number | null) => {
|
|
@@ -181,30 +206,21 @@ const DateInput = ({
|
|
|
181
206
|
handleInternalValue(day, null, year);
|
|
182
207
|
return;
|
|
183
208
|
}
|
|
184
|
-
const { checkedDay } = checkDate(day, selectedMonth, year);
|
|
185
209
|
setMonth(selectedMonth);
|
|
186
|
-
|
|
187
|
-
setDay(checkedDay);
|
|
188
|
-
}
|
|
189
|
-
handleInternalValue(checkedDay, selectedMonth, year);
|
|
210
|
+
handleInternalValue(day, selectedMonth, year);
|
|
190
211
|
};
|
|
191
212
|
|
|
192
213
|
const handleYearChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
193
|
-
const
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
if (slicedYear.toString().length === 4) {
|
|
197
|
-
// Correct day based on year and month.
|
|
198
|
-
const { checkedDay } = checkDate(day, month, Number.parseInt(newValue, 10));
|
|
199
|
-
|
|
200
|
-
if (day && checkedDay !== day) {
|
|
201
|
-
setDay(checkedDay);
|
|
202
|
-
}
|
|
214
|
+
const newYearString = event.target.value.replace(/\D/g, '');
|
|
215
|
+
const newYearNumber = Number.parseInt(newYearString, 10);
|
|
203
216
|
|
|
204
|
-
|
|
205
|
-
|
|
217
|
+
if (newYearString.length >= 4 && newYearString.length <= 6) {
|
|
218
|
+
setYear(newYearNumber);
|
|
219
|
+
setDisplayYear(newYearString);
|
|
220
|
+
handleInternalValue(day, month, newYearNumber);
|
|
206
221
|
} else {
|
|
207
|
-
setYear(
|
|
222
|
+
setYear(null);
|
|
223
|
+
setDisplayYear(newYearString);
|
|
208
224
|
handleInternalValue(day, month, null);
|
|
209
225
|
}
|
|
210
226
|
};
|
|
@@ -216,29 +232,6 @@ const DateInput = ({
|
|
|
216
232
|
}
|
|
217
233
|
};
|
|
218
234
|
|
|
219
|
-
const checkDate = (
|
|
220
|
-
newDay: number | null = null,
|
|
221
|
-
newMonth: number | null = 0,
|
|
222
|
-
newYear: number | null = null,
|
|
223
|
-
) => {
|
|
224
|
-
let checkedDay = newDay;
|
|
225
|
-
const maxDay = new Date(newYear || 2000, newMonth != null ? newMonth + 1 : 1, 0).getDate();
|
|
226
|
-
|
|
227
|
-
if (!newDay) {
|
|
228
|
-
checkedDay = null;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
if (newDay && newDay < 0) {
|
|
232
|
-
checkedDay = 1;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
if ((newDay && newMonth) || (newDay && newDay > 31)) {
|
|
236
|
-
checkedDay = newDay > maxDay ? maxDay : newDay;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
return { checkedDay, checkedMonth: newMonth, checkedYear: newYear };
|
|
240
|
-
};
|
|
241
|
-
|
|
242
235
|
const monthYearOnly = mode === DateMode.MONTH_YEAR;
|
|
243
236
|
|
|
244
237
|
const monthWidth = classNames({
|
|
@@ -254,7 +247,7 @@ const DateInput = ({
|
|
|
254
247
|
return (
|
|
255
248
|
<div className="col-sm-3">
|
|
256
249
|
<label>
|
|
257
|
-
<
|
|
250
|
+
<Body type={Typography.BODY_DEFAULT}>{dayLabel}</Body>
|
|
258
251
|
<div className={`input-group input-group-${size}`}>
|
|
259
252
|
<Input
|
|
260
253
|
type="text"
|
|
@@ -262,10 +255,12 @@ const DateInput = ({
|
|
|
262
255
|
pattern="[0-9]*"
|
|
263
256
|
name="day"
|
|
264
257
|
autoComplete={dayAutoComplete}
|
|
265
|
-
value={
|
|
258
|
+
value={displayDay || ''}
|
|
266
259
|
placeholder={placeholders?.day}
|
|
267
260
|
disabled={disabled}
|
|
268
261
|
min={1}
|
|
262
|
+
max={31}
|
|
263
|
+
maxLength={2}
|
|
269
264
|
onChange={(event) => handleDayChange(event)}
|
|
270
265
|
/>
|
|
271
266
|
</div>
|
|
@@ -278,7 +273,7 @@ const DateInput = ({
|
|
|
278
273
|
return (
|
|
279
274
|
<div className="col-sm-4">
|
|
280
275
|
<label>
|
|
281
|
-
<
|
|
276
|
+
<Body type={Typography.BODY_DEFAULT}>{yearLabel}</Body>
|
|
282
277
|
<div className={`input-group input-group-${size}`}>
|
|
283
278
|
<Input
|
|
284
279
|
type="text"
|
|
@@ -287,9 +282,11 @@ const DateInput = ({
|
|
|
287
282
|
name="year"
|
|
288
283
|
autoComplete={yearAutoComplete}
|
|
289
284
|
placeholder={placeholders?.year}
|
|
290
|
-
value={
|
|
285
|
+
value={displayYear || ''}
|
|
291
286
|
disabled={disabled}
|
|
292
|
-
min={
|
|
287
|
+
min={0}
|
|
288
|
+
max={9999}
|
|
289
|
+
maxLength={6}
|
|
293
290
|
onChange={(event) => handleYearChange(event)}
|
|
294
291
|
/>
|
|
295
292
|
</div>
|
|
@@ -2,10 +2,12 @@ import { useState } from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { Input } from '../inputs/Input';
|
|
4
4
|
import { Field } from './Field';
|
|
5
|
+
import { Sentiment } from '../common';
|
|
5
6
|
|
|
6
7
|
export default {
|
|
7
8
|
component: Field,
|
|
8
9
|
title: 'Field',
|
|
10
|
+
tags: ['autodocs'],
|
|
9
11
|
};
|
|
10
12
|
|
|
11
13
|
export const Basic = () => {
|
|
@@ -17,43 +19,22 @@ export const Basic = () => {
|
|
|
17
19
|
);
|
|
18
20
|
};
|
|
19
21
|
|
|
20
|
-
export const
|
|
22
|
+
export const WithStatusMessages = () => {
|
|
21
23
|
const [value, setValue] = useState<string | undefined>('This is some text');
|
|
22
24
|
return (
|
|
23
|
-
<
|
|
24
|
-
<
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
<
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
export const WithHelpAndErrorOnBlur = () => {
|
|
39
|
-
const [value, setValue] = useState<string | undefined>('This is some text');
|
|
40
|
-
const [error, setError] = useState<string | undefined>(undefined);
|
|
41
|
-
return (
|
|
42
|
-
<Field label="Phone number" hint="Please include country code" error={error}>
|
|
43
|
-
<Input
|
|
44
|
-
value={value}
|
|
45
|
-
onChange={({ target }) => {
|
|
46
|
-
setValue(target.value);
|
|
47
|
-
setError(undefined);
|
|
48
|
-
}}
|
|
49
|
-
onBlur={() => {
|
|
50
|
-
if (!value) {
|
|
51
|
-
setError('This is a required field');
|
|
52
|
-
} else {
|
|
53
|
-
setError(undefined);
|
|
54
|
-
}
|
|
55
|
-
}}
|
|
56
|
-
/>
|
|
57
|
-
</Field>
|
|
25
|
+
<div>
|
|
26
|
+
<Field label="Phone number" sentiment={Sentiment.POSITIVE} message="Positive message">
|
|
27
|
+
<Input value={value} onChange={({ target }) => setValue(target.value)} />
|
|
28
|
+
</Field>
|
|
29
|
+
<Field label="Phone number" sentiment={Sentiment.WARNING} message="Warning message">
|
|
30
|
+
<Input value={value} onChange={({ target }) => setValue(target.value)} />
|
|
31
|
+
</Field>
|
|
32
|
+
<Field label="Phone number" sentiment={Sentiment.NEGATIVE} message="This is a required field">
|
|
33
|
+
<Input value={value} onChange={({ target }) => setValue(target.value)} />
|
|
34
|
+
</Field>
|
|
35
|
+
<Field label="Phone number" message="This is a helpful message">
|
|
36
|
+
<Input value={value} onChange={({ target }) => setValue(target.value)} />
|
|
37
|
+
</Field>
|
|
38
|
+
</div>
|
|
58
39
|
);
|
|
59
40
|
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import { Input } from '../inputs/Input';
|
|
4
|
+
import { Field } from './Field';
|
|
5
|
+
import { Sentiment } from '../common';
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
component: Field,
|
|
9
|
+
title: 'Field/Tests',
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const WithHelpAndErrorOnBlur = () => {
|
|
13
|
+
const [value, setValue] = useState('This is some text');
|
|
14
|
+
const [error, setError] = useState<string | undefined>(undefined);
|
|
15
|
+
return (
|
|
16
|
+
<Field
|
|
17
|
+
label="Phone number"
|
|
18
|
+
sentiment={error ? Sentiment.NEGATIVE : Sentiment.NEUTRAL}
|
|
19
|
+
message={error || 'Please include country code'}
|
|
20
|
+
>
|
|
21
|
+
<Input
|
|
22
|
+
value={value}
|
|
23
|
+
onChange={({ target }) => {
|
|
24
|
+
setValue(target.value);
|
|
25
|
+
setError(undefined);
|
|
26
|
+
}}
|
|
27
|
+
onBlur={() => {
|
|
28
|
+
setError('Something went wrong');
|
|
29
|
+
}}
|
|
30
|
+
/>
|
|
31
|
+
</Field>
|
|
32
|
+
);
|
|
33
|
+
};
|
package/src/field/Field.tsx
CHANGED
|
@@ -15,15 +15,28 @@ export type FieldProps = {
|
|
|
15
15
|
/** `null` disables auto-generating the `id` attribute, falling back to nesting-based label association over setting `htmlFor` explicitly. */
|
|
16
16
|
id?: string | null;
|
|
17
17
|
label: React.ReactNode;
|
|
18
|
+
/** @deprecated use `message` and `type={Sentiment.NEUTRAL}` prop instead */
|
|
18
19
|
hint?: React.ReactNode;
|
|
20
|
+
message?: React.ReactNode;
|
|
21
|
+
/** @deprecated use `message` and `type={Sentiment.NEGATIVE}` prop instead */
|
|
19
22
|
error?: React.ReactNode;
|
|
23
|
+
sentiment?: `${Sentiment.NEGATIVE | Sentiment.NEUTRAL | Sentiment.POSITIVE | Sentiment.WARNING}`;
|
|
20
24
|
className?: string;
|
|
21
25
|
children?: React.ReactNode;
|
|
22
26
|
};
|
|
23
27
|
|
|
24
|
-
export const Field = ({
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
export const Field = ({
|
|
29
|
+
id,
|
|
30
|
+
label,
|
|
31
|
+
message: propMessage,
|
|
32
|
+
sentiment: propType = Sentiment.NEUTRAL,
|
|
33
|
+
className,
|
|
34
|
+
children,
|
|
35
|
+
...props
|
|
36
|
+
}: FieldProps) => {
|
|
37
|
+
const sentiment = props.error ? Sentiment.NEGATIVE : propType;
|
|
38
|
+
const message = props.error || props.hint || propMessage;
|
|
39
|
+
const hasError = sentiment === Sentiment.NEGATIVE;
|
|
27
40
|
|
|
28
41
|
const labelId = useId();
|
|
29
42
|
|
|
@@ -35,14 +48,16 @@ export const Field = ({ id, label, hint, error, className, children }: FieldProp
|
|
|
35
48
|
return (
|
|
36
49
|
<FieldLabelIdContextProvider value={labelId}>
|
|
37
50
|
<InputIdContextProvider value={inputId}>
|
|
38
|
-
<InputDescribedByProvider value={
|
|
51
|
+
<InputDescribedByProvider value={message ? descriptionId : undefined}>
|
|
39
52
|
<InputInvalidProvider value={hasError}>
|
|
40
53
|
<div
|
|
41
54
|
className={classNames(
|
|
42
55
|
'form-group d-block',
|
|
43
56
|
{
|
|
57
|
+
'has-success': sentiment === Sentiment.POSITIVE,
|
|
58
|
+
'has-warning': sentiment === Sentiment.WARNING,
|
|
44
59
|
'has-error': hasError,
|
|
45
|
-
'has-info':
|
|
60
|
+
'has-info': sentiment === Sentiment.NEUTRAL,
|
|
46
61
|
},
|
|
47
62
|
className,
|
|
48
63
|
)}
|
|
@@ -51,14 +66,9 @@ export const Field = ({ id, label, hint, error, className, children }: FieldProp
|
|
|
51
66
|
{label}
|
|
52
67
|
{children}
|
|
53
68
|
</Label>
|
|
54
|
-
{
|
|
55
|
-
<InlineAlert type={
|
|
56
|
-
{
|
|
57
|
-
</InlineAlert>
|
|
58
|
-
)}
|
|
59
|
-
{hasError && (
|
|
60
|
-
<InlineAlert type={Sentiment.NEGATIVE} id={descriptionId}>
|
|
61
|
-
{error}
|
|
69
|
+
{message && (
|
|
70
|
+
<InlineAlert type={sentiment} id={descriptionId}>
|
|
71
|
+
{message}
|
|
62
72
|
</InlineAlert>
|
|
63
73
|
)}
|
|
64
74
|
</div>
|
|
@@ -51,7 +51,7 @@ export const Basic = () => {
|
|
|
51
51
|
|
|
52
52
|
return (
|
|
53
53
|
<>
|
|
54
|
-
{/*eslint-disable-next-line react/no-adjacent-inline-elements */}
|
|
54
|
+
{/* eslint-disable-next-line react/no-adjacent-inline-elements */}
|
|
55
55
|
<p>
|
|
56
56
|
The styling for the input (the coloured border) and the visibility of the inline alert is
|
|
57
57
|
controlled through the use of <code>has-***</code> classes which are applied to the{' '}
|
|
@@ -60,7 +60,11 @@ export const Basic = () => {
|
|
|
60
60
|
element. The available classes are <code>has-error</code>, <code>has-info</code>,{' '}
|
|
61
61
|
<code>has-warning</code> and <code>has-success</code>.
|
|
62
62
|
</p>
|
|
63
|
-
<p>
|
|
63
|
+
<p>
|
|
64
|
+
Where possible consumers should use{' '}
|
|
65
|
+
<a href="https://storybook.wise.design/?path=/story/field--basic">Field</a> instead of doing
|
|
66
|
+
this manually.
|
|
67
|
+
</p>
|
|
64
68
|
<div className={`form-group ${typeClass}`}>
|
|
65
69
|
<label className="control-label" htmlFor="id0">
|
|
66
70
|
Toggleable
|
|
@@ -73,14 +77,18 @@ export const Basic = () => {
|
|
|
73
77
|
Negative
|
|
74
78
|
</label>
|
|
75
79
|
<Input id="id1" value="Neptune is cool" />
|
|
76
|
-
<InlineAlert type="
|
|
80
|
+
<InlineAlert type="negative">{message}</InlineAlert>
|
|
77
81
|
</div>
|
|
78
|
-
<div className="form-group has-
|
|
82
|
+
<div className="form-group has-success">
|
|
79
83
|
<label className="control-label" htmlFor="id2">
|
|
80
84
|
Positive
|
|
81
85
|
</label>
|
|
82
86
|
<Input id="id2" value="Neptune is cool" />
|
|
83
|
-
<InlineAlert type="positive">
|
|
87
|
+
<InlineAlert type="positive">
|
|
88
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
|
|
89
|
+
ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
|
|
90
|
+
ullamco laboris nisi ut aliquip ex ea commodo consequat.
|
|
91
|
+
</InlineAlert>
|
|
84
92
|
</div>
|
|
85
93
|
<div className="form-group has-neutral">
|
|
86
94
|
<label className="control-label" htmlFor="id3">
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { AlertCircle as AlertCircleIcon } from '@transferwise/icons';
|
|
2
1
|
import classNames from 'classnames';
|
|
3
2
|
import { ReactNode } from 'react';
|
|
4
3
|
|
|
5
|
-
import { Sentiment } from '../common';
|
|
4
|
+
import { Sentiment, Size } from '../common';
|
|
5
|
+
import StatusIcon from '../statusIcon';
|
|
6
6
|
|
|
7
7
|
export interface InlineAlertProps {
|
|
8
8
|
id?: string;
|
|
@@ -17,15 +17,22 @@ export default function InlineAlert({
|
|
|
17
17
|
className,
|
|
18
18
|
children,
|
|
19
19
|
}: InlineAlertProps) {
|
|
20
|
-
const danger = type === 'negative' || type === 'error';
|
|
21
20
|
return (
|
|
22
21
|
<div
|
|
23
22
|
role="alert"
|
|
24
23
|
id={id}
|
|
25
|
-
className={classNames(
|
|
24
|
+
className={classNames(
|
|
25
|
+
'alert alert-detach',
|
|
26
|
+
`alert-${type === Sentiment.NEGATIVE || type === Sentiment.ERROR ? 'danger' : type}`,
|
|
27
|
+
className,
|
|
28
|
+
)}
|
|
26
29
|
>
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
<div className="d-inline-flex">
|
|
31
|
+
{type !== Sentiment.NEUTRAL && type !== Sentiment.PENDING && (
|
|
32
|
+
<StatusIcon sentiment={type} size={Size.SMALL} />
|
|
33
|
+
)}
|
|
34
|
+
<div className="np-text-body-default">{children}</div>
|
|
35
|
+
</div>
|
|
29
36
|
</div>
|
|
30
37
|
);
|
|
31
38
|
}
|
package/src/main.css
CHANGED
|
@@ -4208,14 +4208,16 @@ html:not([dir="rtl"]) .np-navigation-option {
|
|
|
4208
4208
|
height: var(--size-32);
|
|
4209
4209
|
}
|
|
4210
4210
|
}
|
|
4211
|
-
.status-circle.negative
|
|
4211
|
+
.status-circle.negative,
|
|
4212
|
+
.status-circle.error {
|
|
4212
4213
|
background-color: var(--color-sentiment-negative);
|
|
4213
4214
|
}
|
|
4214
4215
|
.status-circle.neutral {
|
|
4215
4216
|
background-color: #5d7079;
|
|
4216
4217
|
background-color: var(--color-content-secondary);
|
|
4217
4218
|
}
|
|
4218
|
-
.status-circle.positive
|
|
4219
|
+
.status-circle.positive,
|
|
4220
|
+
.status-circle.success {
|
|
4219
4221
|
background-color: var(--color-sentiment-positive);
|
|
4220
4222
|
}
|
|
4221
4223
|
.tw-stepper {
|
|
@@ -5400,6 +5402,9 @@ html:not([dir="rtl"]) .np-navigation-option {
|
|
|
5400
5402
|
border-color: #c9cbce !important;
|
|
5401
5403
|
border-color: var(--color-interactive-secondary) !important;
|
|
5402
5404
|
}
|
|
5405
|
+
.np-upload-button-container.droppable-dropping:before {
|
|
5406
|
+
z-index: 2;
|
|
5407
|
+
}
|
|
5403
5408
|
.np-upload-button-container input[type="file"] {
|
|
5404
5409
|
opacity: 0;
|
|
5405
5410
|
z-index: -1;
|
|
@@ -5410,6 +5415,7 @@ html:not([dir="rtl"]) .np-navigation-option {
|
|
|
5410
5415
|
}
|
|
5411
5416
|
.np-upload-button {
|
|
5412
5417
|
width: 100%;
|
|
5418
|
+
border-top: 1px solid transparent;
|
|
5413
5419
|
padding: 16px;
|
|
5414
5420
|
padding: var(--padding-small);
|
|
5415
5421
|
border-radius: 0;
|
|
@@ -5477,8 +5483,25 @@ label.np-upload-button:not(.disabled):active {
|
|
|
5477
5483
|
color: var(--color-sentiment-negative) !important;
|
|
5478
5484
|
}
|
|
5479
5485
|
.np-theme-personal .np-upload-input-errors {
|
|
5486
|
+
list-style: none;
|
|
5480
5487
|
padding-left: 0;
|
|
5481
|
-
|
|
5488
|
+
}
|
|
5489
|
+
.np-theme-personal .np-upload-input-errors li {
|
|
5490
|
+
position: relative;
|
|
5491
|
+
padding-left: 16px;
|
|
5492
|
+
padding-left: var(--size-16);
|
|
5493
|
+
}
|
|
5494
|
+
@media (max-width: 320px) {
|
|
5495
|
+
.np-theme-personal .np-upload-input-errors li {
|
|
5496
|
+
padding-left: 32px;
|
|
5497
|
+
padding-left: var(--size-32);
|
|
5498
|
+
}
|
|
5499
|
+
}
|
|
5500
|
+
.np-theme-personal .np-upload-input-errors li:before {
|
|
5501
|
+
content: '•';
|
|
5502
|
+
position: absolute;
|
|
5503
|
+
display: block;
|
|
5504
|
+
left: 0;
|
|
5482
5505
|
}
|
|
5483
5506
|
.np-theme-personal .np-upload-input .status-circle {
|
|
5484
5507
|
width: 24px;
|
|
@@ -5497,30 +5520,49 @@ label.np-upload-button:not(.disabled):active {
|
|
|
5497
5520
|
.np-upload-item {
|
|
5498
5521
|
border: 1px solid #c9cbce;
|
|
5499
5522
|
border: 1px solid var(--color-interactive-secondary);
|
|
5523
|
+
position: relative;
|
|
5500
5524
|
}
|
|
5501
|
-
.np-upload-item:first-child ~ div:before
|
|
5525
|
+
.np-upload-item:first-child ~ div:not(.np-upload-item__link):before,
|
|
5526
|
+
.np-upload-item:not(:first-child).np-upload-item__link .np-upload-item--link:before,
|
|
5527
|
+
.np-upload-item.np-upload-item__link:hover .np-upload-item--link:after {
|
|
5502
5528
|
display: block;
|
|
5503
|
-
position:
|
|
5529
|
+
position: absolute;
|
|
5504
5530
|
height: 1px;
|
|
5505
5531
|
background-color: rgba(0,0,0,0.10196);
|
|
5506
5532
|
background-color: var(--color-border-neutral);
|
|
5507
5533
|
content: " ";
|
|
5508
|
-
|
|
5509
|
-
|
|
5534
|
+
left: 16px;
|
|
5535
|
+
left: var(--size-16);
|
|
5536
|
+
width: calc(100% - 2 * 16px);
|
|
5537
|
+
width: calc(100% - 2 * var(--size-16));
|
|
5538
|
+
}
|
|
5539
|
+
.np-upload-item:first-child ~ div:not(.np-upload-item__link):before,
|
|
5540
|
+
.np-upload-item:not(:first-child).np-upload-item__link .np-upload-item--link:before {
|
|
5541
|
+
top: 0;
|
|
5542
|
+
}
|
|
5543
|
+
.np-upload-item.np-upload-item__link:hover .np-upload-item--link:after {
|
|
5544
|
+
bottom: -1px;
|
|
5510
5545
|
}
|
|
5511
5546
|
.np-upload-item:first-child ~ div {
|
|
5512
|
-
border-top:
|
|
5547
|
+
border-top: 1px;
|
|
5548
|
+
}
|
|
5549
|
+
.np-upload-item:not(:first-child) .np-upload-item--link:hover {
|
|
5550
|
+
border-top-color: rgba(0,0,0,0.10196);
|
|
5551
|
+
border-top-color: var(--color-border-neutral);
|
|
5513
5552
|
}
|
|
5514
5553
|
.np-upload-item:not(:last-child) {
|
|
5515
5554
|
border-bottom: 0;
|
|
5516
5555
|
}
|
|
5517
|
-
.np-upload-item.np-upload-item__link:hover:before,
|
|
5518
|
-
.np-upload-button-container:
|
|
5519
|
-
|
|
5556
|
+
.np-upload-item.np-upload-item__link:hover + .np-upload-item:before,
|
|
5557
|
+
.np-upload-item.np-upload-item__link:hover + .np-upload-button-container:before,
|
|
5558
|
+
.np-upload-item.np-upload-item__link:hover + .np-upload-item .np-upload-item--link:before,
|
|
5559
|
+
.np-upload-item.np-upload-item__link:hover + .np-upload-button-container .np-upload-item--link:before {
|
|
5560
|
+
display: none;
|
|
5520
5561
|
}
|
|
5521
|
-
.np-upload-
|
|
5522
|
-
.np-upload-button-container:
|
|
5523
|
-
|
|
5562
|
+
.np-upload-button-container:hover:before,
|
|
5563
|
+
.np-upload-button-container.droppable-dropping:before {
|
|
5564
|
+
left: 0 !important;
|
|
5565
|
+
width: 100% !important;
|
|
5524
5566
|
}
|
|
5525
5567
|
.np-upload-button-container:has(:focus-visible) {
|
|
5526
5568
|
outline: var(--ring-outline-color) solid var(--ring-outline-width);
|
|
@@ -5537,17 +5579,29 @@ label.np-upload-button:not(.disabled):active {
|
|
|
5537
5579
|
flex: 1;
|
|
5538
5580
|
-webkit-text-decoration: none;
|
|
5539
5581
|
text-decoration: none;
|
|
5582
|
+
border-top: 1px solid transparent;
|
|
5540
5583
|
border-radius: inherit;
|
|
5541
5584
|
}
|
|
5542
5585
|
.np-upload-item__link a:focus-visible {
|
|
5543
5586
|
outline-offset: -2px;
|
|
5544
5587
|
}
|
|
5588
|
+
.np-upload-item__link a:hover:before {
|
|
5589
|
+
display: none !important;
|
|
5590
|
+
}
|
|
5591
|
+
.np-upload-item__link a:hover:after {
|
|
5592
|
+
left: 0 !important;
|
|
5593
|
+
width: 100% !important;
|
|
5594
|
+
}
|
|
5545
5595
|
.np-upload-item__link a:hover,
|
|
5546
5596
|
.np-upload-item__link a:active {
|
|
5547
5597
|
-webkit-text-decoration: none;
|
|
5548
5598
|
text-decoration: none;
|
|
5599
|
+
}
|
|
5600
|
+
.np-upload-item__link a:hover .np-upload-button,
|
|
5601
|
+
.np-upload-item__link a:active .np-upload-button {
|
|
5549
5602
|
background-color: rgba(134,167,189,0.10196);
|
|
5550
5603
|
background-color: var(--color-background-neutral);
|
|
5604
|
+
border-radius: inherit;
|
|
5551
5605
|
}
|
|
5552
5606
|
.np-upload-item__body {
|
|
5553
5607
|
display: flex;
|
|
@@ -5572,6 +5626,7 @@ label.np-upload-button:not(.disabled):active {
|
|
|
5572
5626
|
outline-offset: 0 !important;
|
|
5573
5627
|
background-color: rgba(134,167,189,0.10196);
|
|
5574
5628
|
background-color: var(--color-background-neutral);
|
|
5629
|
+
border: none;
|
|
5575
5630
|
color: var(--color-interactive-primary);
|
|
5576
5631
|
right: 16px;
|
|
5577
5632
|
right: var(--size-16);
|
|
@@ -66,13 +66,15 @@
|
|
|
66
66
|
height: var(--size-32);
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
|
-
.status-circle.negative
|
|
69
|
+
.status-circle.negative,
|
|
70
|
+
.status-circle.error {
|
|
70
71
|
background-color: var(--color-sentiment-negative);
|
|
71
72
|
}
|
|
72
73
|
.status-circle.neutral {
|
|
73
74
|
background-color: #5d7079;
|
|
74
75
|
background-color: var(--color-content-secondary);
|
|
75
76
|
}
|
|
76
|
-
.status-circle.positive
|
|
77
|
+
.status-circle.positive,
|
|
78
|
+
.status-circle.success {
|
|
77
79
|
background-color: var(--color-sentiment-positive);
|
|
78
80
|
}
|
|
@@ -60,7 +60,8 @@
|
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
.status-circle.negative
|
|
63
|
+
.status-circle.negative,
|
|
64
|
+
.status-circle.error {
|
|
64
65
|
background-color: var(--color-sentiment-negative);
|
|
65
66
|
}
|
|
66
67
|
|
|
@@ -68,6 +69,7 @@
|
|
|
68
69
|
background-color: var(--color-content-secondary);
|
|
69
70
|
}
|
|
70
71
|
|
|
71
|
-
.status-circle.positive
|
|
72
|
+
.status-circle.positive,
|
|
73
|
+
.status-circle.success {
|
|
72
74
|
background-color: var(--color-sentiment-positive);
|
|
73
75
|
}
|
|
@@ -26,7 +26,7 @@ const StatusIcon = ({ sentiment = 'neutral', size = 'md' }: StatusIconProps) =>
|
|
|
26
26
|
return (
|
|
27
27
|
<span
|
|
28
28
|
data-testid="status-icon"
|
|
29
|
-
className={classNames('status-circle',
|
|
29
|
+
className={classNames('status-circle', `status-circle-${size}`, sentiment)}
|
|
30
30
|
>
|
|
31
31
|
<Icon className={classNames('status-icon', iconColor)} />
|
|
32
32
|
</span>
|