@transferwise/components 46.71.2 → 46.71.4
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/avatar/Avatar.js +7 -2
- package/build/avatar/Avatar.js.map +1 -1
- package/build/avatar/Avatar.mjs +7 -2
- package/build/avatar/Avatar.mjs.map +1 -1
- package/build/badge/Badge.js +13 -2
- package/build/badge/Badge.js.map +1 -1
- package/build/badge/Badge.mjs +13 -2
- package/build/badge/Badge.mjs.map +1 -1
- package/build/circularButton/CircularButton.js +10 -2
- package/build/circularButton/CircularButton.js.map +1 -1
- package/build/circularButton/CircularButton.mjs +10 -2
- package/build/circularButton/CircularButton.mjs.map +1 -1
- package/build/common/circle/Circle.js +29 -0
- package/build/common/circle/Circle.js.map +1 -0
- package/build/common/circle/Circle.mjs +27 -0
- package/build/common/circle/Circle.mjs.map +1 -0
- package/build/inputs/SelectInput.js +38 -5
- package/build/inputs/SelectInput.js.map +1 -1
- package/build/inputs/SelectInput.mjs +38 -5
- package/build/inputs/SelectInput.mjs.map +1 -1
- package/build/main.css +7 -114
- package/build/moneyInput/MoneyInput.js +1 -1
- package/build/moneyInput/MoneyInput.js.map +1 -1
- package/build/moneyInput/MoneyInput.mjs +1 -1
- package/build/moneyInput/MoneyInput.mjs.map +1 -1
- package/build/statusIcon/StatusIcon.js +16 -3
- package/build/statusIcon/StatusIcon.js.map +1 -1
- package/build/statusIcon/StatusIcon.mjs +16 -3
- package/build/statusIcon/StatusIcon.mjs.map +1 -1
- package/build/styles/avatar/Avatar.css +0 -29
- package/build/styles/badge/Badge.css +0 -10
- package/build/styles/circularButton/CircularButton.css +0 -37
- package/build/styles/common/circle/Circle.css +7 -0
- package/build/styles/main.css +7 -114
- package/build/styles/statusIcon/StatusIcon.css +0 -33
- package/build/types/avatar/Avatar.d.ts.map +1 -1
- package/build/types/badge/Badge.d.ts +9 -2
- package/build/types/badge/Badge.d.ts.map +1 -1
- package/build/types/circularButton/CircularButton.d.ts.map +1 -1
- package/build/types/common/circle/Circle.d.ts +34 -0
- package/build/types/common/circle/Circle.d.ts.map +1 -0
- package/build/types/common/circle/index.d.ts +3 -0
- package/build/types/common/circle/index.d.ts.map +1 -0
- package/build/types/inputs/SelectInput.d.ts.map +1 -1
- package/build/types/statusIcon/StatusIcon.d.ts +1 -1
- package/build/types/statusIcon/StatusIcon.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/alert/Alert.spec.tsx +3 -1
- package/src/avatar/Avatar.css +0 -29
- package/src/avatar/Avatar.less +0 -12
- package/src/avatar/Avatar.tsx +9 -4
- package/src/avatarWrapper/AvatarWrapper.spec.tsx +3 -1
- package/src/avatarWrapper/__snapshots__/AvatarWrapper.spec.tsx.snap +22 -11
- package/src/badge/Badge.css +0 -10
- package/src/badge/Badge.less +0 -13
- package/src/badge/Badge.tsx +23 -3
- package/src/checkbox/Checkbox.spec.tsx +3 -1
- package/src/circularButton/CircularButton.css +0 -37
- package/src/circularButton/CircularButton.less +0 -27
- package/src/circularButton/CircularButton.spec.tsx +3 -1
- package/src/circularButton/CircularButton.tsx +10 -3
- package/src/circularButton/__snapshots__/CircularButton.spec.tsx.snap +20 -10
- package/src/common/circle/Circle.css +7 -0
- package/src/common/circle/Circle.less +6 -0
- package/src/common/circle/Circle.story.tsx +86 -0
- package/src/common/circle/Circle.tsx +46 -0
- package/src/common/circle/index.ts +2 -0
- package/src/flowNavigation/__snapshots__/FlowNavigation.spec.js.snap +8 -4
- package/src/inlineAlert/InlineAlert.spec.tsx +3 -1
- package/src/inputs/SelectInput.docs.mdx +21 -0
- package/src/inputs/SelectInput.spec.tsx +94 -1
- package/src/inputs/SelectInput.story.tsx +4 -4
- package/src/inputs/SelectInput.tsx +45 -4
- package/src/main.css +7 -114
- package/src/main.less +1 -0
- package/src/moneyInput/MoneyInput.rtl.spec.tsx +10 -1
- package/src/moneyInput/MoneyInput.tsx +1 -1
- package/src/overlayHeader/__snapshots__/OverlayHeader.spec.tsx.snap +4 -2
- package/src/radio/__snapshots__/Radio.rtl.spec.tsx.snap +4 -2
- package/src/statusIcon/StatusIcon.css +0 -33
- package/src/statusIcon/StatusIcon.less +0 -24
- package/src/statusIcon/StatusIcon.spec.tsx +5 -3
- package/src/statusIcon/StatusIcon.tsx +17 -6
- package/src/summary/Summary.spec.tsx +3 -1
- package/src/typeahead/Typeahead.spec.js +3 -0
- package/src/upload/Upload.spec.js +3 -0
|
@@ -3,7 +3,7 @@ import { userEvent } from '@testing-library/user-event';
|
|
|
3
3
|
|
|
4
4
|
import { render, mockMatchMedia, mockResizeObserver } from '../test-utils';
|
|
5
5
|
|
|
6
|
-
import { SelectInput } from './SelectInput';
|
|
6
|
+
import { SelectInput, type SelectInputOptionItem, type SelectInputProps } from './SelectInput';
|
|
7
7
|
import { Field } from '../field/Field';
|
|
8
8
|
|
|
9
9
|
mockMatchMedia();
|
|
@@ -216,4 +216,97 @@ describe('SelectInput', () => {
|
|
|
216
216
|
);
|
|
217
217
|
expect(screen.getByLabelText(/Currency/)).toHaveAttribute('aria-haspopup');
|
|
218
218
|
});
|
|
219
|
+
|
|
220
|
+
describe('listbox label', () => {
|
|
221
|
+
const fieldLabel = 'Fruits';
|
|
222
|
+
const triggerLabel = 'Select fruit';
|
|
223
|
+
const options: SelectInputOptionItem[] = [
|
|
224
|
+
{ type: 'option', value: 'Banana' },
|
|
225
|
+
{ type: 'option', value: 'Orange' },
|
|
226
|
+
{ type: 'option', value: 'Olive' },
|
|
227
|
+
];
|
|
228
|
+
const requiredTriggerButtonProps = {
|
|
229
|
+
id: undefined,
|
|
230
|
+
'aria-labelledby': undefined,
|
|
231
|
+
'aria-describedby': undefined,
|
|
232
|
+
'aria-invalid': undefined,
|
|
233
|
+
'aria-label': undefined,
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
const renderSelectInput = (props: Omit<SelectInputProps<string | null>, 'items'> = {}) =>
|
|
237
|
+
render(
|
|
238
|
+
<Field label={fieldLabel} id="selectId">
|
|
239
|
+
<SelectInput {...props} items={options} />
|
|
240
|
+
</Field>,
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
it("should propagate trigger's label if nothing is selected", async () => {
|
|
244
|
+
renderSelectInput({
|
|
245
|
+
UNSAFE_triggerButtonProps: {
|
|
246
|
+
...requiredTriggerButtonProps,
|
|
247
|
+
'aria-label': triggerLabel,
|
|
248
|
+
},
|
|
249
|
+
});
|
|
250
|
+
const trigger = screen.getByRole('combobox');
|
|
251
|
+
await userEvent.click(trigger);
|
|
252
|
+
expect(screen.getByRole('listbox', { name: triggerLabel })).toBeInTheDocument();
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it("should propagate trigger's label if an option is selected", async () => {
|
|
256
|
+
renderSelectInput({
|
|
257
|
+
UNSAFE_triggerButtonProps: {
|
|
258
|
+
...requiredTriggerButtonProps,
|
|
259
|
+
'aria-label': triggerLabel,
|
|
260
|
+
},
|
|
261
|
+
value: options[1].value,
|
|
262
|
+
});
|
|
263
|
+
const trigger = screen.getByRole('combobox');
|
|
264
|
+
await userEvent.click(trigger);
|
|
265
|
+
expect(screen.getByRole('listbox', { name: triggerLabel })).toBeInTheDocument();
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it("should propagate trigger's label by id", async () => {
|
|
269
|
+
const customLabelId = 'customLabelId';
|
|
270
|
+
renderSelectInput({
|
|
271
|
+
UNSAFE_triggerButtonProps: {
|
|
272
|
+
...requiredTriggerButtonProps,
|
|
273
|
+
'aria-labelledby': customLabelId,
|
|
274
|
+
},
|
|
275
|
+
});
|
|
276
|
+
const trigger = screen.getByRole('combobox');
|
|
277
|
+
await userEvent.click(trigger);
|
|
278
|
+
expect(screen.getByRole('listbox')).toHaveAttribute('aria-labelledby', customLabelId);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it("should propagate input's label by id", async () => {
|
|
282
|
+
renderSelectInput();
|
|
283
|
+
const trigger = screen.getByRole('combobox');
|
|
284
|
+
await userEvent.click(trigger);
|
|
285
|
+
expect(screen.getByRole('listbox', { name: fieldLabel })).toBeInTheDocument();
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
it('should prefer explicit label over label ids', async () => {
|
|
289
|
+
const customLabelId = 'customLabelId';
|
|
290
|
+
renderSelectInput({
|
|
291
|
+
UNSAFE_triggerButtonProps: {
|
|
292
|
+
...requiredTriggerButtonProps,
|
|
293
|
+
'aria-labelledby': customLabelId,
|
|
294
|
+
'aria-label': triggerLabel,
|
|
295
|
+
},
|
|
296
|
+
});
|
|
297
|
+
const trigger = screen.getByRole('combobox');
|
|
298
|
+
await userEvent.click(trigger);
|
|
299
|
+
expect(screen.getByRole('listbox', { name: triggerLabel })).toBeInTheDocument();
|
|
300
|
+
expect(screen.getByRole('listbox')).not.toHaveAttribute('aria-labelledby');
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
it('should have no label if none of the above are provided', async () => {
|
|
304
|
+
render(<SelectInput items={options} />);
|
|
305
|
+
const trigger = screen.getByRole('combobox');
|
|
306
|
+
await userEvent.click(trigger);
|
|
307
|
+
const listBox = screen.getByRole('listbox');
|
|
308
|
+
expect(listBox).not.toHaveAttribute('aria-label');
|
|
309
|
+
expect(listBox).not.toHaveAttribute('aria-labelledby');
|
|
310
|
+
});
|
|
311
|
+
});
|
|
219
312
|
});
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
} from './SelectInput';
|
|
21
21
|
|
|
22
22
|
const meta = {
|
|
23
|
-
title: '
|
|
23
|
+
title: 'Forms/SelectInput',
|
|
24
24
|
component: SelectInput,
|
|
25
25
|
tags: ['autodocs'],
|
|
26
26
|
parameters: { actions: { argTypesRegex: '' } },
|
|
@@ -208,8 +208,8 @@ export const Currencies: Story<Currency> = {
|
|
|
208
208
|
await userEvent.type(input, '{Backspace}{Backspace}');
|
|
209
209
|
await expect(within(screen.getByRole('listbox')).queryAllByRole('option')).toHaveLength(2);
|
|
210
210
|
|
|
211
|
-
await userEvent.type(input, '{Backspace}
|
|
212
|
-
await expect(input).toHaveAttribute('aria-activedescendant');
|
|
211
|
+
await userEvent.type(input, '{Backspace}e');
|
|
212
|
+
await expect(input).not.toHaveAttribute('aria-activedescendant');
|
|
213
213
|
});
|
|
214
214
|
},
|
|
215
215
|
};
|
|
@@ -347,7 +347,7 @@ export const WithinField = {
|
|
|
347
347
|
args: Months.args,
|
|
348
348
|
decorators: [
|
|
349
349
|
(Story) => (
|
|
350
|
-
<Field message="Something went wrong" sentiment="negative">
|
|
350
|
+
<Field message="Something went wrong" sentiment="negative" label="Month">
|
|
351
351
|
<Story />
|
|
352
352
|
</Field>
|
|
353
353
|
),
|
|
@@ -258,8 +258,9 @@ export function SelectInput<T = string, M extends boolean = false>({
|
|
|
258
258
|
onClose,
|
|
259
259
|
onClear,
|
|
260
260
|
}: SelectInputProps<T, M>) {
|
|
261
|
-
const inputAttributes = useInputAttributes();
|
|
261
|
+
const inputAttributes = useInputAttributes({ nonLabelable: true });
|
|
262
262
|
const id = idProp ?? inputAttributes.id;
|
|
263
|
+
|
|
263
264
|
const [open, setOpen] = useState(false);
|
|
264
265
|
|
|
265
266
|
const initialized = useRef(false);
|
|
@@ -295,6 +296,35 @@ export function SelectInput<T = string, M extends boolean = false>({
|
|
|
295
296
|
const listboxRef = useRef<HTMLDivElement>(null);
|
|
296
297
|
const controllerRef = filterable ? searchInputRef : listboxRef;
|
|
297
298
|
|
|
299
|
+
/**
|
|
300
|
+
* Attempts to resolve the `listbox` label
|
|
301
|
+
* @see https://storybook.wise.design/?path=/docs/forms-selectinput-accessibility--docs#labelling
|
|
302
|
+
*/
|
|
303
|
+
const getListBoxLabelProps = (): {
|
|
304
|
+
listBoxLabel?: string;
|
|
305
|
+
listBoxLabelledBy?: string;
|
|
306
|
+
} => {
|
|
307
|
+
if (UNSAFE_triggerButtonProps?.['aria-label']) {
|
|
308
|
+
return {
|
|
309
|
+
listBoxLabel: UNSAFE_triggerButtonProps['aria-label'],
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (UNSAFE_triggerButtonProps?.['aria-labelledby']) {
|
|
314
|
+
return {
|
|
315
|
+
listBoxLabelledBy: UNSAFE_triggerButtonProps['aria-labelledby'],
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (inputAttributes['aria-labelledby']) {
|
|
320
|
+
return {
|
|
321
|
+
listBoxLabelledBy: inputAttributes['aria-labelledby'],
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
return {};
|
|
326
|
+
};
|
|
327
|
+
|
|
298
328
|
return (
|
|
299
329
|
<ListboxBase
|
|
300
330
|
name={name}
|
|
@@ -388,7 +418,7 @@ export function SelectInput<T = string, M extends boolean = false>({
|
|
|
388
418
|
}}
|
|
389
419
|
>
|
|
390
420
|
<SelectInputOptions
|
|
391
|
-
id={`${id}Search`}
|
|
421
|
+
id={id ? `${id}Search` : undefined}
|
|
392
422
|
items={items}
|
|
393
423
|
renderValue={renderValue}
|
|
394
424
|
renderFooter={renderFooter}
|
|
@@ -398,6 +428,7 @@ export function SelectInput<T = string, M extends boolean = false>({
|
|
|
398
428
|
listboxRef={listboxRef}
|
|
399
429
|
filterQuery={deferredFilterQuery}
|
|
400
430
|
onFilterChange={setFilterQuery}
|
|
431
|
+
{...getListBoxLabelProps()}
|
|
401
432
|
/>
|
|
402
433
|
</OptionsOverlay>
|
|
403
434
|
);
|
|
@@ -496,6 +527,8 @@ interface SelectInputOptionsProps<T = string>
|
|
|
496
527
|
listboxRef: React.MutableRefObject<HTMLDivElement | null>;
|
|
497
528
|
filterQuery: string;
|
|
498
529
|
onFilterChange: (query: string) => void;
|
|
530
|
+
listBoxLabel?: string;
|
|
531
|
+
listBoxLabelledBy?: string;
|
|
499
532
|
}
|
|
500
533
|
|
|
501
534
|
function SelectInputOptions<T = string>({
|
|
@@ -509,10 +542,12 @@ function SelectInputOptions<T = string>({
|
|
|
509
542
|
listboxRef,
|
|
510
543
|
filterQuery,
|
|
511
544
|
onFilterChange,
|
|
545
|
+
listBoxLabel,
|
|
546
|
+
listBoxLabelledBy,
|
|
512
547
|
}: SelectInputOptionsProps<T>) {
|
|
513
548
|
const intl = useIntl();
|
|
514
|
-
|
|
515
549
|
const controllerRef = filterable ? searchInputRef : listboxRef;
|
|
550
|
+
const [initialRender, setInitialRender] = useState(true);
|
|
516
551
|
|
|
517
552
|
const needle = useMemo(() => {
|
|
518
553
|
if (filterable) {
|
|
@@ -576,6 +611,10 @@ function SelectInputOptions<T = string>({
|
|
|
576
611
|
}
|
|
577
612
|
}, []);
|
|
578
613
|
|
|
614
|
+
useEffect(() => {
|
|
615
|
+
setInitialRender(false);
|
|
616
|
+
}, []);
|
|
617
|
+
|
|
579
618
|
const showStatus = resultsEmpty;
|
|
580
619
|
const statusId = useId();
|
|
581
620
|
const listboxId = useId();
|
|
@@ -600,7 +639,7 @@ function SelectInputOptions<T = string>({
|
|
|
600
639
|
className="np-select-input-options-container"
|
|
601
640
|
onAriaActiveDescendantChange={(value: React.AriaAttributes['aria-activedescendant']) => {
|
|
602
641
|
if (controllerRef.current != null) {
|
|
603
|
-
if (value != null) {
|
|
642
|
+
if (!initialRender && value != null) {
|
|
604
643
|
controllerRef.current.setAttribute('aria-activedescendant', value);
|
|
605
644
|
} else {
|
|
606
645
|
controllerRef.current.removeAttribute('aria-activedescendant');
|
|
@@ -662,6 +701,8 @@ function SelectInputOptions<T = string>({
|
|
|
662
701
|
id={listboxId}
|
|
663
702
|
role="listbox"
|
|
664
703
|
aria-orientation="vertical"
|
|
704
|
+
aria-label={listBoxLabel}
|
|
705
|
+
aria-labelledby={listBoxLabelledBy}
|
|
665
706
|
tabIndex={0}
|
|
666
707
|
className="np-select-input-listbox"
|
|
667
708
|
>
|
package/src/main.css
CHANGED
|
@@ -207,27 +207,18 @@ div.critical-comms .critical-comms-body {
|
|
|
207
207
|
}
|
|
208
208
|
.tw-avatar {
|
|
209
209
|
position: relative;
|
|
210
|
-
border-radius: 50%;
|
|
211
210
|
-webkit-user-select: none;
|
|
212
211
|
-moz-user-select: none;
|
|
213
212
|
user-select: none;
|
|
214
213
|
box-sizing: border-box;
|
|
215
214
|
}
|
|
216
215
|
.tw-avatar .tw-avatar__content {
|
|
217
|
-
align-items: center;
|
|
218
216
|
background-color: rgba(134,167,189,0.10196);
|
|
219
217
|
background-color: #86a7bd1a;
|
|
220
218
|
background-color: var(--color-background-neutral);
|
|
221
|
-
border-radius: 50%;
|
|
222
|
-
color: #37517e;
|
|
223
|
-
color: var(--color-content-primary);
|
|
224
|
-
display: flex;
|
|
225
|
-
height: 100%;
|
|
226
|
-
justify-content: center;
|
|
227
219
|
max-height: 100%;
|
|
228
220
|
max-width: 100%;
|
|
229
221
|
overflow: hidden;
|
|
230
|
-
width: 100%;
|
|
231
222
|
}
|
|
232
223
|
.tw-avatar--outlined {
|
|
233
224
|
border: 1px solid #00a2dd;
|
|
@@ -270,11 +261,6 @@ div.critical-comms .critical-comms-body {
|
|
|
270
261
|
color: var(--color-dark-charcoal);
|
|
271
262
|
line-height: 1;
|
|
272
263
|
}
|
|
273
|
-
.tw-avatar--24 {
|
|
274
|
-
min-width: 24px;
|
|
275
|
-
width: 24px;
|
|
276
|
-
height: 24px;
|
|
277
|
-
}
|
|
278
264
|
.tw-avatar--24.tw-avatar--emoji,
|
|
279
265
|
.tw-avatar--24.tw-avatar--icon {
|
|
280
266
|
font-size: 12px;
|
|
@@ -305,11 +291,6 @@ div.critical-comms .critical-comms-body {
|
|
|
305
291
|
content: "";
|
|
306
292
|
border-radius: 50%;
|
|
307
293
|
}
|
|
308
|
-
.tw-avatar--40 {
|
|
309
|
-
min-width: 40px;
|
|
310
|
-
width: 40px;
|
|
311
|
-
height: 40px;
|
|
312
|
-
}
|
|
313
294
|
.tw-avatar--40.tw-avatar--emoji,
|
|
314
295
|
.tw-avatar--40.tw-avatar--icon {
|
|
315
296
|
font-size: 20px;
|
|
@@ -340,11 +321,6 @@ div.critical-comms .critical-comms-body {
|
|
|
340
321
|
content: "";
|
|
341
322
|
border-radius: 50%;
|
|
342
323
|
}
|
|
343
|
-
.tw-avatar--48 {
|
|
344
|
-
min-width: 48px;
|
|
345
|
-
width: 48px;
|
|
346
|
-
height: 48px;
|
|
347
|
-
}
|
|
348
324
|
.tw-avatar--48.tw-avatar--emoji,
|
|
349
325
|
.tw-avatar--48.tw-avatar--icon {
|
|
350
326
|
font-size: 24px;
|
|
@@ -375,11 +351,6 @@ div.critical-comms .critical-comms-body {
|
|
|
375
351
|
content: "";
|
|
376
352
|
border-radius: 50%;
|
|
377
353
|
}
|
|
378
|
-
.tw-avatar--56 {
|
|
379
|
-
min-width: 56px;
|
|
380
|
-
width: 56px;
|
|
381
|
-
height: 56px;
|
|
382
|
-
}
|
|
383
354
|
.tw-avatar--56.tw-avatar--emoji,
|
|
384
355
|
.tw-avatar--56.tw-avatar--icon {
|
|
385
356
|
font-size: 28px;
|
|
@@ -410,11 +381,6 @@ div.critical-comms .critical-comms-body {
|
|
|
410
381
|
content: "";
|
|
411
382
|
border-radius: 50%;
|
|
412
383
|
}
|
|
413
|
-
.tw-avatar--72 {
|
|
414
|
-
min-width: 72px;
|
|
415
|
-
width: 72px;
|
|
416
|
-
height: 72px;
|
|
417
|
-
}
|
|
418
384
|
.tw-avatar--72.tw-avatar--emoji,
|
|
419
385
|
.tw-avatar--72.tw-avatar--icon {
|
|
420
386
|
font-size: 36px;
|
|
@@ -463,10 +429,6 @@ div.critical-comms .critical-comms-body {
|
|
|
463
429
|
--badge-mask-offset: calc(var(--badge-size) / 2);
|
|
464
430
|
--badge-border-color: rgba(255, 255, 255, 0.08);
|
|
465
431
|
}
|
|
466
|
-
.tw-badge.tw-badge-md {
|
|
467
|
-
--badge-size: 20px;
|
|
468
|
-
--badge-mask: 2px;
|
|
469
|
-
}
|
|
470
432
|
.tw-badge.tw-badge-lg {
|
|
471
433
|
--badge-size: 24px;
|
|
472
434
|
--badge-mask: 3px;
|
|
@@ -484,16 +446,10 @@ div.critical-comms .critical-comms-body {
|
|
|
484
446
|
}
|
|
485
447
|
.tw-badge > .tw-badge__content {
|
|
486
448
|
position: absolute;
|
|
487
|
-
width: var(--badge-size);
|
|
488
|
-
height: var(--badge-size);
|
|
489
449
|
bottom: 0;
|
|
490
450
|
right: 0;
|
|
491
451
|
box-sizing: border-box;
|
|
492
|
-
border-radius: 50%;
|
|
493
452
|
text-align: center;
|
|
494
|
-
display: flex;
|
|
495
|
-
align-items: center;
|
|
496
|
-
justify-content: center;
|
|
497
453
|
overflow: hidden;
|
|
498
454
|
-webkit-user-select: none;
|
|
499
455
|
-moz-user-select: none;
|
|
@@ -1029,36 +985,6 @@ div.critical-comms .critical-comms-body {
|
|
|
1029
985
|
cursor: pointer;
|
|
1030
986
|
position: relative;
|
|
1031
987
|
}
|
|
1032
|
-
.np-circular-btn input[type="button"] {
|
|
1033
|
-
min-height: 40px;
|
|
1034
|
-
min-height: var(--size-40);
|
|
1035
|
-
width: 40px;
|
|
1036
|
-
width: var(--size-40);
|
|
1037
|
-
height: 40px;
|
|
1038
|
-
height: var(--size-40);
|
|
1039
|
-
padding: 0;
|
|
1040
|
-
border-radius: 50%;
|
|
1041
|
-
margin-bottom: 8px;
|
|
1042
|
-
margin-bottom: var(--size-8);
|
|
1043
|
-
}
|
|
1044
|
-
.np-theme-personal .np-circular-btn input[type="button"] {
|
|
1045
|
-
min-height: 56px;
|
|
1046
|
-
min-height: var(--size-56);
|
|
1047
|
-
width: 56px;
|
|
1048
|
-
width: var(--size-56);
|
|
1049
|
-
height: 56px;
|
|
1050
|
-
height: var(--size-56);
|
|
1051
|
-
}
|
|
1052
|
-
@media (max-width: 320px) {
|
|
1053
|
-
.np-theme-personal .np-circular-btn input[type="button"] {
|
|
1054
|
-
min-height: 64px;
|
|
1055
|
-
min-height: var(--size-64);
|
|
1056
|
-
width: 64px;
|
|
1057
|
-
width: var(--size-64);
|
|
1058
|
-
height: 64px;
|
|
1059
|
-
height: var(--size-64);
|
|
1060
|
-
}
|
|
1061
|
-
}
|
|
1062
988
|
.np-circular-btn .tw-icon {
|
|
1063
989
|
position: absolute;
|
|
1064
990
|
top: 16px;
|
|
@@ -1099,13 +1025,6 @@ div.critical-comms .critical-comms-body {
|
|
|
1099
1025
|
.np-theme-personal .np-circular-btn.negative.secondary:not(.disabled):not(:disabled) .tw-icon {
|
|
1100
1026
|
color: var(--color-sentiment-negative) !important;
|
|
1101
1027
|
}
|
|
1102
|
-
.np-circular-btn__label {
|
|
1103
|
-
transition: color 0.15s ease-in-out;
|
|
1104
|
-
font-size: 0.875rem;
|
|
1105
|
-
font-size: var(--font-size-14);
|
|
1106
|
-
font-weight: 600;
|
|
1107
|
-
font-weight: var(--font-weight-semi-bold);
|
|
1108
|
-
}
|
|
1109
1028
|
.np-circular-btn.accent .np-circular-btn__label {
|
|
1110
1029
|
color: #00a2dd;
|
|
1111
1030
|
color: var(--color-interactive-accent);
|
|
@@ -1232,6 +1151,13 @@ div.critical-comms .critical-comms-body {
|
|
|
1232
1151
|
.np-theme-personal .np-circular-btn.negative.secondary:active input[type="button"] + .tw-icon {
|
|
1233
1152
|
color: var(--color-interactive-control);
|
|
1234
1153
|
}
|
|
1154
|
+
.np-circle {
|
|
1155
|
+
border-radius: 9999px;
|
|
1156
|
+
border-radius: var(--radius-full);
|
|
1157
|
+
width: var(--circle-size);
|
|
1158
|
+
height: var(--circle-size);
|
|
1159
|
+
flex-shrink: 0;
|
|
1160
|
+
}
|
|
1235
1161
|
.np-bottom-sheet {
|
|
1236
1162
|
border-radius: 10px 10px 0 0;
|
|
1237
1163
|
}
|
|
@@ -4224,13 +4150,6 @@ html:not([dir="rtl"]) .np-navigation-option {
|
|
|
4224
4150
|
width: 32px;
|
|
4225
4151
|
width: var(--size-32);
|
|
4226
4152
|
}
|
|
4227
|
-
.status-circle {
|
|
4228
|
-
border-radius: 50%;
|
|
4229
|
-
display: flex;
|
|
4230
|
-
align-items: center;
|
|
4231
|
-
justify-content: center;
|
|
4232
|
-
flex-shrink: 0;
|
|
4233
|
-
}
|
|
4234
4153
|
.status-circle .light {
|
|
4235
4154
|
color: var(--color-contrast);
|
|
4236
4155
|
}
|
|
@@ -4246,24 +4165,6 @@ html:not([dir="rtl"]) .np-navigation-option {
|
|
|
4246
4165
|
.np-theme-personal .status-circle.pending .status-icon {
|
|
4247
4166
|
color: var(--color-dark);
|
|
4248
4167
|
}
|
|
4249
|
-
.status-circle-lg {
|
|
4250
|
-
width: 48px;
|
|
4251
|
-
width: var(--size-48);
|
|
4252
|
-
height: 48px;
|
|
4253
|
-
height: var(--size-48);
|
|
4254
|
-
}
|
|
4255
|
-
.status-circle-md {
|
|
4256
|
-
width: 40px;
|
|
4257
|
-
width: var(--size-40);
|
|
4258
|
-
height: 40px;
|
|
4259
|
-
height: var(--size-40);
|
|
4260
|
-
}
|
|
4261
|
-
.status-circle-sm {
|
|
4262
|
-
width: 16px;
|
|
4263
|
-
width: var(--size-16);
|
|
4264
|
-
height: 16px;
|
|
4265
|
-
height: var(--size-16);
|
|
4266
|
-
}
|
|
4267
4168
|
.status-circle-sm .status-icon > svg {
|
|
4268
4169
|
height: 14px;
|
|
4269
4170
|
height: var(--size-14);
|
|
@@ -4278,14 +4179,6 @@ html:not([dir="rtl"]) .np-navigation-option {
|
|
|
4278
4179
|
height: var(--size-24);
|
|
4279
4180
|
}
|
|
4280
4181
|
}
|
|
4281
|
-
@media (max-width: 320px) {
|
|
4282
|
-
.status-circle-sm {
|
|
4283
|
-
width: 32px;
|
|
4284
|
-
width: var(--size-32);
|
|
4285
|
-
height: 32px;
|
|
4286
|
-
height: var(--size-32);
|
|
4287
|
-
}
|
|
4288
|
-
}
|
|
4289
4182
|
.status-circle.negative,
|
|
4290
4183
|
.status-circle.error {
|
|
4291
4184
|
background-color: var(--color-sentiment-negative);
|
package/src/main.less
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
@import "./checkboxButton/CheckboxButton.less";
|
|
10
10
|
@import "./chips/Chip.less";
|
|
11
11
|
@import "./circularButton/CircularButton.less";
|
|
12
|
+
@import "./common/circle/Circle.less";
|
|
12
13
|
@import "./common/bottomSheet/BottomSheet.less";
|
|
13
14
|
@import "./common/card/Card.less";
|
|
14
15
|
@import "./common/closeButton/CloseButton.less";
|
|
@@ -81,7 +81,7 @@ describe('MoneyInput', () => {
|
|
|
81
81
|
</>,
|
|
82
82
|
);
|
|
83
83
|
|
|
84
|
-
expect(screen.
|
|
84
|
+
expect(screen.getAllByLabelText('Prioritized label')[0]).toHaveClass('input-group');
|
|
85
85
|
});
|
|
86
86
|
|
|
87
87
|
it('supports `Field` for labeling', () => {
|
|
@@ -137,4 +137,13 @@ describe('MoneyInput', () => {
|
|
|
137
137
|
messages.selectCurrencyLabel.defaultMessage,
|
|
138
138
|
);
|
|
139
139
|
});
|
|
140
|
+
|
|
141
|
+
it('should have a listbox label', async () => {
|
|
142
|
+
render(<MoneyInput {...props} />);
|
|
143
|
+
const trigger = screen.getByRole('combobox');
|
|
144
|
+
await userEvent.click(trigger);
|
|
145
|
+
const triggerLabel = trigger.getAttribute('aria-label');
|
|
146
|
+
expect(triggerLabel).toBeTruthy();
|
|
147
|
+
expect(screen.getByRole('listbox', { name: triggerLabel ?? '' })).toBeInTheDocument();
|
|
148
|
+
});
|
|
140
149
|
});
|
|
@@ -391,7 +391,7 @@ class MoneyInput extends Component<MoneyInputPropsWithInputAttributes, MoneyInpu
|
|
|
391
391
|
UNSAFE_triggerButtonProps={{
|
|
392
392
|
id: undefined,
|
|
393
393
|
'aria-labelledby': undefined,
|
|
394
|
-
'aria-describedby':
|
|
394
|
+
'aria-describedby': ariaLabelledBy,
|
|
395
395
|
'aria-invalid': undefined,
|
|
396
396
|
'aria-label': this.props.intl.formatMessage(messages.selectCurrencyLabel),
|
|
397
397
|
}}
|
|
@@ -18,10 +18,12 @@ exports[`OverlayHeader renders as expected 1`] = `
|
|
|
18
18
|
class="d-flex align-items-center order-2"
|
|
19
19
|
>
|
|
20
20
|
<div
|
|
21
|
-
class="tw-avatar tw-avatar--48 tw-avatar--initials np-text-title-body"
|
|
21
|
+
class="np-circle d-flex align-items-center justify-content-center tw-avatar tw-avatar--48 tw-avatar--initials np-text-title-body"
|
|
22
|
+
style="--circle-size: 48px;"
|
|
22
23
|
>
|
|
23
24
|
<div
|
|
24
|
-
class="tw-avatar__content"
|
|
25
|
+
class="np-circle d-flex align-items-center justify-content-center tw-avatar__content"
|
|
26
|
+
style="--circle-size: 48px;"
|
|
25
27
|
>
|
|
26
28
|
TM
|
|
27
29
|
</div>
|
|
@@ -34,10 +34,12 @@ exports[`Radio shows the avatar when supplied 1`] = `
|
|
|
34
34
|
class="np-radio__avatar m-l-auto"
|
|
35
35
|
>
|
|
36
36
|
<div
|
|
37
|
-
class="tw-avatar tw-avatar--48 tw-avatar--initials np-text-title-body"
|
|
37
|
+
class="np-circle d-flex align-items-center justify-content-center tw-avatar tw-avatar--48 tw-avatar--initials np-text-title-body"
|
|
38
|
+
style="--circle-size: 48px;"
|
|
38
39
|
>
|
|
39
40
|
<div
|
|
40
|
-
class="tw-avatar__content"
|
|
41
|
+
class="np-circle d-flex align-items-center justify-content-center tw-avatar__content"
|
|
42
|
+
style="--circle-size: 48px;"
|
|
41
43
|
>
|
|
42
44
|
HD
|
|
43
45
|
</div>
|
|
@@ -4,13 +4,6 @@
|
|
|
4
4
|
width: 32px;
|
|
5
5
|
width: var(--size-32);
|
|
6
6
|
}
|
|
7
|
-
.status-circle {
|
|
8
|
-
border-radius: 50%;
|
|
9
|
-
display: flex;
|
|
10
|
-
align-items: center;
|
|
11
|
-
justify-content: center;
|
|
12
|
-
flex-shrink: 0;
|
|
13
|
-
}
|
|
14
7
|
.status-circle .light {
|
|
15
8
|
color: var(--color-contrast);
|
|
16
9
|
}
|
|
@@ -26,24 +19,6 @@
|
|
|
26
19
|
.np-theme-personal .status-circle.pending .status-icon {
|
|
27
20
|
color: var(--color-dark);
|
|
28
21
|
}
|
|
29
|
-
.status-circle-lg {
|
|
30
|
-
width: 48px;
|
|
31
|
-
width: var(--size-48);
|
|
32
|
-
height: 48px;
|
|
33
|
-
height: var(--size-48);
|
|
34
|
-
}
|
|
35
|
-
.status-circle-md {
|
|
36
|
-
width: 40px;
|
|
37
|
-
width: var(--size-40);
|
|
38
|
-
height: 40px;
|
|
39
|
-
height: var(--size-40);
|
|
40
|
-
}
|
|
41
|
-
.status-circle-sm {
|
|
42
|
-
width: 16px;
|
|
43
|
-
width: var(--size-16);
|
|
44
|
-
height: 16px;
|
|
45
|
-
height: var(--size-16);
|
|
46
|
-
}
|
|
47
22
|
.status-circle-sm .status-icon > svg {
|
|
48
23
|
height: 14px;
|
|
49
24
|
height: var(--size-14);
|
|
@@ -58,14 +33,6 @@
|
|
|
58
33
|
height: var(--size-24);
|
|
59
34
|
}
|
|
60
35
|
}
|
|
61
|
-
@media (max-width: 320px) {
|
|
62
|
-
.status-circle-sm {
|
|
63
|
-
width: 32px;
|
|
64
|
-
width: var(--size-32);
|
|
65
|
-
height: 32px;
|
|
66
|
-
height: var(--size-32);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
36
|
.status-circle.negative,
|
|
70
37
|
.status-circle.error {
|
|
71
38
|
background-color: var(--color-sentiment-negative);
|
|
@@ -4,12 +4,6 @@
|
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
.status-circle {
|
|
7
|
-
border-radius: 50%;
|
|
8
|
-
display: flex;
|
|
9
|
-
align-items: center;
|
|
10
|
-
justify-content: center;
|
|
11
|
-
flex-shrink: 0;
|
|
12
|
-
|
|
13
7
|
.light {
|
|
14
8
|
color: var(--color-contrast);
|
|
15
9
|
}
|
|
@@ -29,20 +23,7 @@
|
|
|
29
23
|
}
|
|
30
24
|
}
|
|
31
25
|
|
|
32
|
-
&-lg {
|
|
33
|
-
width: var(--size-48);
|
|
34
|
-
height: var(--size-48);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
&-md {
|
|
38
|
-
width: var(--size-40);
|
|
39
|
-
height: var(--size-40);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
26
|
&-sm {
|
|
43
|
-
width: var(--size-16);
|
|
44
|
-
height: var(--size-16);
|
|
45
|
-
|
|
46
27
|
.status-icon > svg {
|
|
47
28
|
height: var(--size-14);
|
|
48
29
|
width: var(--size-14);
|
|
@@ -52,11 +33,6 @@
|
|
|
52
33
|
height: var(--size-24);
|
|
53
34
|
}
|
|
54
35
|
}
|
|
55
|
-
|
|
56
|
-
@media (--screen-400-zoom) {
|
|
57
|
-
width: var(--size-32);
|
|
58
|
-
height: var(--size-32);
|
|
59
|
-
}
|
|
60
36
|
}
|
|
61
37
|
}
|
|
62
38
|
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { Sentiment, Size, SizeLarge, SizeMedium, SizeSmall } from '../common';
|
|
2
|
-
import { render, cleanup, screen } from '../test-utils';
|
|
2
|
+
import { render, cleanup, screen, mockMatchMedia } from '../test-utils';
|
|
3
3
|
|
|
4
4
|
import StatusIcon from '.';
|
|
5
5
|
|
|
6
|
+
mockMatchMedia();
|
|
7
|
+
|
|
6
8
|
describe('StatusIcon', () => {
|
|
7
9
|
const renderStatusIcon = (props?: {
|
|
8
10
|
sentiment?: Sentiment;
|
|
@@ -33,7 +35,7 @@ describe('StatusIcon', () => {
|
|
|
33
35
|
])(
|
|
34
36
|
"if prop 'size' equals '%s' is passed, renders the status icon with class '%s'",
|
|
35
37
|
(size, expectedClass) => {
|
|
36
|
-
renderStatusIcon({ size
|
|
38
|
+
renderStatusIcon({ size });
|
|
37
39
|
|
|
38
40
|
expect(screen.getByTestId('status-icon')).toHaveClass(expectedClass);
|
|
39
41
|
cleanup();
|
|
@@ -49,7 +51,7 @@ describe('StatusIcon', () => {
|
|
|
49
51
|
])(
|
|
50
52
|
"if prop 'sentiment' equals '%s' is passed, renders the status icon with class '%s'",
|
|
51
53
|
(sentiment, expectedClass) => {
|
|
52
|
-
renderStatusIcon({ sentiment
|
|
54
|
+
renderStatusIcon({ sentiment });
|
|
53
55
|
|
|
54
56
|
expect(screen.getByTestId('status-icon')).toHaveClass(expectedClass);
|
|
55
57
|
cleanup();
|