@transferwise/components 46.128.3 → 46.130.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/alert/Alert.js +1 -1
- package/build/alert/Alert.mjs +1 -1
- package/build/card/Card.js.map +1 -1
- package/build/card/Card.mjs.map +1 -1
- package/build/common/{card/Card.js → baseCard/BaseCard.js} +4 -4
- package/build/common/baseCard/BaseCard.js.map +1 -0
- package/build/common/{card/Card.mjs → baseCard/BaseCard.mjs} +4 -4
- package/build/common/baseCard/BaseCard.mjs.map +1 -0
- package/build/common/liveRegion/LiveRegion.js +42 -0
- package/build/common/liveRegion/LiveRegion.js.map +1 -0
- package/build/common/liveRegion/LiveRegion.mjs +40 -0
- package/build/common/liveRegion/LiveRegion.mjs.map +1 -0
- package/build/criticalBanner/CriticalCommsBanner.js +68 -3
- package/build/criticalBanner/CriticalCommsBanner.js.map +1 -1
- package/build/criticalBanner/CriticalCommsBanner.mjs +69 -4
- package/build/criticalBanner/CriticalCommsBanner.mjs.map +1 -1
- package/build/flowNavigation/FlowNavigation.js +1 -1
- package/build/flowNavigation/FlowNavigation.mjs +1 -1
- package/build/index.js +4 -4
- package/build/index.mjs +1 -1
- package/build/inputs/SelectInput.js +1 -1
- package/build/inputs/SelectInput.js.map +1 -1
- package/build/inputs/SelectInput.mjs +1 -1
- package/build/inputs/SelectInput.mjs.map +1 -1
- package/build/inputs/_ButtonInput.js +2 -2
- package/build/inputs/_ButtonInput.js.map +1 -1
- package/build/inputs/_ButtonInput.mjs +2 -2
- package/build/inputs/_ButtonInput.mjs.map +1 -1
- package/build/main.css +191 -165
- package/build/overlayHeader/OverlayHeader.js +1 -1
- package/build/overlayHeader/OverlayHeader.mjs +1 -1
- package/build/promoCard/PromoCard.js +2 -2
- package/build/promoCard/PromoCard.js.map +1 -1
- package/build/promoCard/PromoCard.mjs +2 -2
- package/build/promoCard/PromoCard.mjs.map +1 -1
- package/build/prompt/InfoPrompt/InfoPrompt.js +35 -29
- package/build/prompt/InfoPrompt/InfoPrompt.js.map +1 -1
- package/build/prompt/InfoPrompt/InfoPrompt.mjs +35 -29
- package/build/prompt/InfoPrompt/InfoPrompt.mjs.map +1 -1
- package/build/sentimentSurface/SentimentSurface.js +5 -1
- package/build/sentimentSurface/SentimentSurface.js.map +1 -1
- package/build/sentimentSurface/SentimentSurface.mjs +5 -1
- package/build/sentimentSurface/SentimentSurface.mjs.map +1 -1
- package/build/styles/criticalBanner/CriticalCommsBanner.css +33 -15
- package/build/styles/inputs/SelectInput.css +8 -0
- package/build/styles/listItem/ListItem.css +1 -1
- package/build/styles/main.css +191 -165
- package/build/styles/sentimentSurface/SentimentSurface.css +100 -100
- package/build/types/card/Card.d.ts +1 -1
- package/build/types/common/{card/Card.d.ts → baseCard/BaseCard.d.ts} +8 -8
- package/build/types/common/baseCard/BaseCard.d.ts.map +1 -0
- package/build/types/common/baseCard/index.d.ts +3 -0
- package/build/types/common/baseCard/index.d.ts.map +1 -0
- package/build/types/common/index.d.ts +2 -0
- package/build/types/common/index.d.ts.map +1 -1
- package/build/types/common/liveRegion/LiveRegion.d.ts +23 -0
- package/build/types/common/liveRegion/LiveRegion.d.ts.map +1 -0
- package/build/types/common/liveRegion/index.d.ts +3 -0
- package/build/types/common/liveRegion/index.d.ts.map +1 -0
- package/build/types/criticalBanner/CriticalCommsBanner.d.ts +4 -1
- package/build/types/criticalBanner/CriticalCommsBanner.d.ts.map +1 -1
- package/build/types/criticalBanner/index.d.ts +1 -0
- package/build/types/criticalBanner/index.d.ts.map +1 -1
- package/build/types/index.d.ts +2 -1
- package/build/types/index.d.ts.map +1 -1
- package/build/types/inputs/SelectInput.d.ts.map +1 -1
- package/build/types/promoCard/PromoCard.d.ts +3 -3
- package/build/types/promoCard/PromoCard.d.ts.map +1 -1
- package/build/types/prompt/InfoPrompt/InfoPrompt.d.ts +11 -2
- package/build/types/prompt/InfoPrompt/InfoPrompt.d.ts.map +1 -1
- package/build/types/sentimentSurface/SentimentSurface.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/card/Card.story.tsx +3 -2
- package/src/card/Card.tsx +1 -1
- package/src/common/{card/Card.less → baseCard/BaseCard.less} +1 -1
- package/src/common/{card/Card.story.tsx → baseCard/BaseCard.story.tsx} +5 -5
- package/src/common/{card/Card.test.tsx → baseCard/BaseCard.test.tsx} +11 -12
- package/src/common/{card/Card.tsx → baseCard/BaseCard.tsx} +9 -9
- package/src/common/baseCard/index.ts +2 -0
- package/src/common/index.ts +2 -0
- package/src/common/liveRegion/LiveRegion.test.tsx +56 -0
- package/src/common/liveRegion/LiveRegion.tsx +49 -0
- package/src/common/liveRegion/index.ts +2 -0
- package/src/criticalBanner/CriticalCommsBanner.css +33 -15
- package/src/criticalBanner/CriticalCommsBanner.less +46 -36
- package/src/criticalBanner/CriticalCommsBanner.story.tsx +9 -15
- package/src/criticalBanner/CriticalCommsBanner.test.story.tsx +70 -0
- package/src/criticalBanner/CriticalCommsBanner.test.tsx +66 -0
- package/src/criticalBanner/CriticalCommsBanner.tsx +54 -5
- package/src/criticalBanner/index.ts +1 -0
- package/src/index.ts +2 -1
- package/src/inputs/SelectInput.css +8 -0
- package/src/inputs/SelectInput.story.tsx +2 -2
- package/src/inputs/SelectInput.test.story.tsx +57 -1
- package/src/inputs/SelectInput.test.tsx +33 -1
- package/src/inputs/SelectInput.tsx +2 -1
- package/src/inputs/_ButtonInput.less +8 -0
- package/src/inputs/_ButtonInput.tsx +1 -1
- package/src/listItem/ListItem.css +1 -1
- package/src/listItem/ListItem.less +4 -2
- package/src/listItem/_stories/Breakpoints/ListItem.noMedia.test.story.tsx +62 -0
- package/src/listItem/_stories/Breakpoints/ListItem.sideMedia.test.story.tsx +62 -0
- package/src/listItem/_stories/Breakpoints/ListItem.stackedMedia.test.story.tsx +62 -0
- package/src/listItem/_stories/ListItem.story.tsx +3 -2
- package/src/main.css +191 -165
- package/src/main.less +2 -2
- package/src/promoCard/PromoCard.tsx +6 -5
- package/src/prompt/InfoPrompt/InfoPrompt.test.story.tsx +119 -0
- package/src/prompt/InfoPrompt/InfoPrompt.tsx +47 -34
- package/src/sentimentSurface/SentimentSurface.css +100 -100
- package/src/sentimentSurface/SentimentSurface.less +50 -50
- package/src/sentimentSurface/SentimentSurface.test.story.tsx +19 -0
- package/src/sentimentSurface/SentimentSurface.tsx +3 -0
- package/build/common/card/Card.js.map +0 -1
- package/build/common/card/Card.mjs.map +0 -1
- package/build/types/common/card/Card.d.ts.map +0 -1
- package/build/types/common/card/index.d.ts +0 -3
- package/build/types/common/card/index.d.ts.map +0 -1
- package/src/common/card/index.ts +0 -2
- /package/build/styles/common/{card/Card.css → baseCard/BaseCard.css} +0 -0
- /package/src/common/{card/Card.css → baseCard/BaseCard.css} +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import type { AriaLive } from '../../common';
|
|
2
3
|
import type { Sentiment as SurfaceSentiment } from '../../sentimentSurface';
|
|
3
4
|
import { LinkProps } from '../../link';
|
|
4
5
|
import { PrimitivePromptProps } from '../PrimitivePrompt';
|
|
@@ -15,7 +16,7 @@ export type InfoPromptMedia = {
|
|
|
15
16
|
*/
|
|
16
17
|
asset: ReactNode;
|
|
17
18
|
};
|
|
18
|
-
export type InfoPromptProps = Omit<HTMLAttributes<HTMLDivElement>, 'title'> & Pick<PrimitivePromptProps, 'data-testid'> & {
|
|
19
|
+
export type InfoPromptProps = Omit<HTMLAttributes<HTMLDivElement>, 'title' | 'aria-live' | 'role'> & Pick<PrimitivePromptProps, 'data-testid'> & {
|
|
19
20
|
/**
|
|
20
21
|
* The sentiment determines the colour scheme
|
|
21
22
|
* @default 'neutral'
|
|
@@ -44,6 +45,14 @@ export type InfoPromptProps = Omit<HTMLAttributes<HTMLDivElement>, 'title'> & Pi
|
|
|
44
45
|
*/
|
|
45
46
|
description: string;
|
|
46
47
|
className?: string;
|
|
48
|
+
/**
|
|
49
|
+
* Sets the ARIA live region politeness level.
|
|
50
|
+
* - `'polite'` — announced after the current speech (default)
|
|
51
|
+
* - `'assertive'` — interrupts the current speech immediately
|
|
52
|
+
* - `'off'` — disables the live region entirely
|
|
53
|
+
* @default 'polite'
|
|
54
|
+
*/
|
|
55
|
+
'aria-live'?: AriaLive;
|
|
47
56
|
};
|
|
48
57
|
/**
|
|
49
58
|
* InfoPrompt displays important contextual messages to users within a screen.
|
|
@@ -54,5 +63,5 @@ export type InfoPromptProps = Omit<HTMLAttributes<HTMLDivElement>, 'title'> & Pi
|
|
|
54
63
|
*
|
|
55
64
|
* Guidance can be found in the [design system](https://wise.design/components/info-prompt).
|
|
56
65
|
*/
|
|
57
|
-
export declare const InfoPrompt: ({ sentiment, onDismiss, media, action, title, description, className, "data-testid": dataTestId, ...restProps }: InfoPromptProps) => import("react").JSX.Element;
|
|
66
|
+
export declare const InfoPrompt: ({ sentiment, onDismiss, media, action, title, description, className, "aria-live": ariaLive, "data-testid": dataTestId, ...restProps }: InfoPromptProps) => import("react").JSX.Element;
|
|
58
67
|
//# sourceMappingURL=InfoPrompt.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InfoPrompt.d.ts","sourceRoot":"","sources":["../../../../src/prompt/InfoPrompt/InfoPrompt.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAY,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"InfoPrompt.d.ts","sourceRoot":"","sources":["../../../../src/prompt/InfoPrompt/InfoPrompt.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAY,MAAM,OAAO,CAAC;AAE5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,KAAK,EAAE,SAAS,IAAI,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAI5E,OAAa,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAmB,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE3E,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC,GAAG;IAC9E;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B;;;OAGG;IACH,KAAK,EAAE,SAAS,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,GAAG,WAAW,GAAG,MAAM,CAAC,GAChG,IAAI,CAAC,oBAAoB,EAAE,aAAa,CAAC,GAAG;IAC1C;;;OAGG;IACH,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB;;;OAGG;IACH,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB;;OAEG;IACH,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,QAAQ,CAAC;CACxB,CAAC;AAEJ;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,GAAI,wIAWxB,eAAe,gCA4EjB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SentimentSurface.d.ts","sourceRoot":"","sources":["../../../src/sentimentSurface/SentimentSurface.tsx"],"names":[],"mappings":"AAGA,OAAO,EAEL,yBAAyB,EAC1B,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"SentimentSurface.d.ts","sourceRoot":"","sources":["../../../src/sentimentSurface/SentimentSurface.tsx"],"names":[],"mappings":"AAGA,OAAO,EAEL,yBAAyB,EAC1B,MAAM,0BAA0B,CAAC;AAGlC;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,QAAA,MAAM,gBAAgB,EAAE,yBAwCtB,CAAC;AAIH,eAAe,gBAAgB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@transferwise/components",
|
|
3
|
-
"version": "46.
|
|
3
|
+
"version": "46.130.0",
|
|
4
4
|
"description": "Neptune React components",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -103,7 +103,7 @@
|
|
|
103
103
|
},
|
|
104
104
|
"dependencies": {
|
|
105
105
|
"@babel/runtime": "^7.28.6",
|
|
106
|
-
"@floating-ui/react": "^0.27.
|
|
106
|
+
"@floating-ui/react": "^0.27.18",
|
|
107
107
|
"@headlessui/react": "^2.2.9",
|
|
108
108
|
"@popperjs/core": "^2.11.8",
|
|
109
109
|
"@react-aria/focus": "^3.21.4",
|
package/src/card/Card.story.tsx
CHANGED
|
@@ -8,13 +8,14 @@ import Card from '.';
|
|
|
8
8
|
type Story = StoryObj<typeof Card>;
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
11
|
+
* ⚠️ This component is **deprecated** and superseded by the [new ListItem component](?path=/docs/content-listitem--docs).
|
|
12
12
|
*
|
|
13
13
|
* @see https://transferwise.atlassian.net/wiki/spaces/DS/pages/2387314550/Instructions+for+killing+expanding+cards+on+web+design+pattern
|
|
14
14
|
*/
|
|
15
15
|
const meta: Meta<typeof Card> = {
|
|
16
16
|
component: Card,
|
|
17
|
-
title: 'Layouts/Card
|
|
17
|
+
title: 'Layouts/Card',
|
|
18
|
+
tags: ['deprecated'],
|
|
18
19
|
args: {
|
|
19
20
|
title: 'A card',
|
|
20
21
|
details: 'Some details about this card',
|
package/src/card/Card.tsx
CHANGED
|
@@ -21,7 +21,7 @@ export interface CardProps {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
|
-
* @deprecated
|
|
24
|
+
* @deprecated Use [new ListItem component](?path=/docs/content-listitem--docs) instead.
|
|
25
25
|
* @see https://transferwise.atlassian.net/wiki/spaces/DS/pages/2387314550/Instructions+for+killing+expanding+cards+on+web+design+pattern
|
|
26
26
|
*/
|
|
27
27
|
const Card = forwardRef(function Card(
|
|
@@ -4,15 +4,15 @@ import { lorem10 } from '../../test-utils';
|
|
|
4
4
|
import Title from '../../title';
|
|
5
5
|
import { Typography } from '../propsValues/typography';
|
|
6
6
|
|
|
7
|
-
import
|
|
7
|
+
import BaseCard from '.';
|
|
8
8
|
|
|
9
|
-
const meta: Meta<typeof
|
|
10
|
-
component:
|
|
11
|
-
title: 'Internal/
|
|
9
|
+
const meta: Meta<typeof BaseCard> = {
|
|
10
|
+
component: BaseCard,
|
|
11
|
+
title: 'Internal/BaseCard',
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
export default meta;
|
|
15
|
-
type Story = StoryObj<typeof
|
|
15
|
+
type Story = StoryObj<typeof BaseCard>;
|
|
16
16
|
|
|
17
17
|
export const Default: Story = {
|
|
18
18
|
args: {
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { render, fireEvent, screen } from '@testing-library/react';
|
|
2
|
-
import React from 'react';
|
|
3
2
|
import { IntlProvider } from 'react-intl';
|
|
4
3
|
|
|
5
|
-
import
|
|
4
|
+
import BaseCard from './BaseCard';
|
|
6
5
|
|
|
7
|
-
describe('
|
|
6
|
+
describe('BaseCard', () => {
|
|
8
7
|
const defaultProps = {
|
|
9
8
|
children: 'Test Content',
|
|
10
9
|
testId: 'test-card',
|
|
@@ -15,13 +14,13 @@ describe('Card', () => {
|
|
|
15
14
|
...defaultProps,
|
|
16
15
|
children: 'Test text',
|
|
17
16
|
};
|
|
18
|
-
const { rerender } = render(<
|
|
17
|
+
const { rerender } = render(<BaseCard {...defaultProps}>Test Content</BaseCard>);
|
|
19
18
|
|
|
20
19
|
expect(screen.getByTestId('test-card')).toBeInTheDocument();
|
|
21
20
|
expect(screen.getByTestId('test-card')).toHaveClass('np-Card');
|
|
22
21
|
|
|
23
22
|
// Change props
|
|
24
|
-
rerender(<
|
|
23
|
+
rerender(<BaseCard {...props} />);
|
|
25
24
|
|
|
26
25
|
expect(screen.getByText('Test text')).toBeInTheDocument();
|
|
27
26
|
});
|
|
@@ -31,12 +30,12 @@ describe('Card', () => {
|
|
|
31
30
|
...defaultProps,
|
|
32
31
|
className: 'test-custom',
|
|
33
32
|
};
|
|
34
|
-
const { rerender } = render(<
|
|
33
|
+
const { rerender } = render(<BaseCard {...defaultProps} />);
|
|
35
34
|
|
|
36
35
|
expect(screen.getByTestId('test-card')).not.toHaveClass('test-custom');
|
|
37
36
|
|
|
38
37
|
// Change props
|
|
39
|
-
rerender(<
|
|
38
|
+
rerender(<BaseCard {...props} />);
|
|
40
39
|
|
|
41
40
|
expect(screen.getByTestId('test-card')).toHaveClass('test-custom');
|
|
42
41
|
});
|
|
@@ -46,12 +45,12 @@ describe('Card', () => {
|
|
|
46
45
|
...defaultProps,
|
|
47
46
|
isDisabled: true,
|
|
48
47
|
};
|
|
49
|
-
const { rerender } = render(<
|
|
48
|
+
const { rerender } = render(<BaseCard {...defaultProps} />);
|
|
50
49
|
|
|
51
50
|
expect(screen.getByTestId('test-card')).not.toHaveClass('is-disabled');
|
|
52
51
|
|
|
53
52
|
// Change props
|
|
54
|
-
rerender(<
|
|
53
|
+
rerender(<BaseCard {...props} />);
|
|
55
54
|
|
|
56
55
|
expect(screen.getByTestId('test-card')).toHaveClass('is-disabled');
|
|
57
56
|
});
|
|
@@ -61,12 +60,12 @@ describe('Card', () => {
|
|
|
61
60
|
...defaultProps,
|
|
62
61
|
isSmall: true,
|
|
63
62
|
};
|
|
64
|
-
const { rerender } = render(<
|
|
63
|
+
const { rerender } = render(<BaseCard {...defaultProps} />);
|
|
65
64
|
|
|
66
65
|
expect(screen.getByTestId('test-card')).not.toHaveClass('np-Card--small');
|
|
67
66
|
|
|
68
67
|
// Change props
|
|
69
|
-
rerender(<
|
|
68
|
+
rerender(<BaseCard {...props} />);
|
|
70
69
|
|
|
71
70
|
expect(screen.getByTestId('test-card')).toHaveClass('np-Card--small');
|
|
72
71
|
});
|
|
@@ -79,7 +78,7 @@ describe('Card', () => {
|
|
|
79
78
|
};
|
|
80
79
|
render(
|
|
81
80
|
<IntlProvider locale="en">
|
|
82
|
-
<
|
|
81
|
+
<BaseCard {...props} />
|
|
83
82
|
</IntlProvider>,
|
|
84
83
|
);
|
|
85
84
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { clsx } from 'clsx';
|
|
2
|
-
import {
|
|
2
|
+
import { type ReactNode, forwardRef, useRef } from 'react';
|
|
3
3
|
|
|
4
4
|
import { CloseButton } from '../closeButton';
|
|
5
5
|
import { stopPropagation } from '../domHelpers';
|
|
6
6
|
|
|
7
|
-
export interface
|
|
7
|
+
export interface BaseCardProps {
|
|
8
8
|
/** Content to display inside Card. */
|
|
9
9
|
children: ReactNode;
|
|
10
10
|
|
|
@@ -28,9 +28,9 @@ export interface CardProps {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
|
-
*
|
|
31
|
+
* BaseCard component.
|
|
32
32
|
*
|
|
33
|
-
* A
|
|
33
|
+
* A BaseCard is a container for content that is used to group related information.
|
|
34
34
|
* It can be used to display information in a structured way, and can be
|
|
35
35
|
* customized with various props to suit different use cases.
|
|
36
36
|
*
|
|
@@ -44,11 +44,11 @@ export interface CardProps {
|
|
|
44
44
|
* @param {string} testId - Optional ID to add to the card container for testing purposes.
|
|
45
45
|
* @returns {React.JSX.Element} - The card component.
|
|
46
46
|
* @example
|
|
47
|
-
* <
|
|
47
|
+
* <BaseCard>
|
|
48
48
|
* <p>Hello World!</p>
|
|
49
|
-
* </
|
|
49
|
+
* </BaseCard>
|
|
50
50
|
*/
|
|
51
|
-
const
|
|
51
|
+
const BaseCard = forwardRef<HTMLDivElement, BaseCardProps>(
|
|
52
52
|
(
|
|
53
53
|
{
|
|
54
54
|
className,
|
|
@@ -98,6 +98,6 @@ const Card = forwardRef<HTMLDivElement, CardProps>(
|
|
|
98
98
|
},
|
|
99
99
|
);
|
|
100
100
|
|
|
101
|
-
|
|
101
|
+
BaseCard.displayName = 'Card';
|
|
102
102
|
|
|
103
|
-
export default
|
|
103
|
+
export default BaseCard;
|
package/src/common/index.ts
CHANGED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import { LiveRegion, LiveRegionProps } from './LiveRegion';
|
|
3
|
+
|
|
4
|
+
describe('LiveRegion', () => {
|
|
5
|
+
const renderLiveRegion = (props: Partial<LiveRegionProps> & Pick<LiveRegionProps, 'aria-live'>) =>
|
|
6
|
+
render(<LiveRegion {...props}>{props.children ?? 'Live content'}</LiveRegion>);
|
|
7
|
+
|
|
8
|
+
describe('when aria-live is "polite"', () => {
|
|
9
|
+
it('renders with role="status"', () => {
|
|
10
|
+
renderLiveRegion({ 'aria-live': 'polite' });
|
|
11
|
+
expect(screen.getByRole('status')).toBeInTheDocument();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('sets aria-live="polite"', () => {
|
|
15
|
+
renderLiveRegion({ 'aria-live': 'polite' });
|
|
16
|
+
expect(screen.getByRole('status')).toHaveAttribute('aria-live', 'polite');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('sets aria-atomic="true"', () => {
|
|
20
|
+
renderLiveRegion({ 'aria-live': 'polite' });
|
|
21
|
+
expect(screen.getByRole('status')).toHaveAttribute('aria-atomic', 'true');
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe('when aria-live is "assertive"', () => {
|
|
26
|
+
it('renders with role="alert"', () => {
|
|
27
|
+
renderLiveRegion({ 'aria-live': 'assertive' });
|
|
28
|
+
expect(screen.getByRole('alert')).toBeInTheDocument();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('sets aria-live="assertive"', () => {
|
|
32
|
+
renderLiveRegion({ 'aria-live': 'assertive' });
|
|
33
|
+
expect(screen.getByRole('alert')).toHaveAttribute('aria-live', 'assertive');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('sets aria-atomic="true"', () => {
|
|
37
|
+
renderLiveRegion({ 'aria-live': 'assertive' });
|
|
38
|
+
expect(screen.getByRole('alert')).toHaveAttribute('aria-atomic', 'true');
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('renders children', () => {
|
|
43
|
+
renderLiveRegion({ 'aria-live': 'polite', children: 'Transfer sent' });
|
|
44
|
+
expect(screen.getByText('Transfer sent')).toBeInTheDocument();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('passes additional HTML attributes to the wrapper div', () => {
|
|
48
|
+
renderLiveRegion({ 'aria-live': 'polite', className: 'custom' });
|
|
49
|
+
expect(screen.getByRole('status')).toHaveClass('custom');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('supports data-testid prop', () => {
|
|
53
|
+
renderLiveRegion({ 'aria-live': 'polite', 'data-testid': 'live-region' });
|
|
54
|
+
expect(screen.getByTestId('live-region')).toBeInTheDocument();
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
const ARIA_LIVE_ROLE_MAP = {
|
|
4
|
+
assertive: 'alert',
|
|
5
|
+
polite: 'status',
|
|
6
|
+
} as const;
|
|
7
|
+
|
|
8
|
+
export type AriaLive = 'off' | 'polite' | 'assertive';
|
|
9
|
+
|
|
10
|
+
export interface LiveRegionProps extends Omit<
|
|
11
|
+
HTMLAttributes<HTMLDivElement>,
|
|
12
|
+
'role' | 'aria-live' | 'aria-atomic'
|
|
13
|
+
> {
|
|
14
|
+
/**
|
|
15
|
+
* Determines urgency: 'assertive' interrupts, 'polite' waits for idle, 'off' disables live region.
|
|
16
|
+
*/
|
|
17
|
+
'aria-live': AriaLive;
|
|
18
|
+
/** Test ID for testing tools */
|
|
19
|
+
'data-testid'?: string;
|
|
20
|
+
children?: ReactNode;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Renders an ARIA live region with the correct implicit role.
|
|
25
|
+
*
|
|
26
|
+
* - `aria-live="polite"` → `role="status"`
|
|
27
|
+
* - `aria-live="assertive"` → `role="alert"`
|
|
28
|
+
* - `aria-live="off"` → no live region
|
|
29
|
+
*
|
|
30
|
+
* The `role` prop is intentionally excluded from the public API
|
|
31
|
+
* to prevent mismatches between `aria-live` and `role`.
|
|
32
|
+
*/
|
|
33
|
+
export const LiveRegion = ({ 'aria-live': ariaLive, children, ...props }: LiveRegionProps) => {
|
|
34
|
+
if (ariaLive === 'off') {
|
|
35
|
+
return <>{children}</>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<div
|
|
40
|
+
role={ARIA_LIVE_ROLE_MAP[ariaLive]}
|
|
41
|
+
aria-live={ariaLive}
|
|
42
|
+
aria-atomic="true"
|
|
43
|
+
style={{ display: 'contents' }}
|
|
44
|
+
{...props}
|
|
45
|
+
>
|
|
46
|
+
{children}
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
@@ -1,34 +1,52 @@
|
|
|
1
|
-
.
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
.critical-comms {
|
|
2
|
+
border-radius: 16px;
|
|
3
|
+
border-radius: var(--radius-medium);
|
|
4
|
+
overflow: hidden;
|
|
4
5
|
}
|
|
5
|
-
.
|
|
6
|
-
color: var(--color-
|
|
6
|
+
.critical-comms .alert {
|
|
7
|
+
background-color: var(--color-sentiment-background-surface);
|
|
8
|
+
color: var(--color-sentiment-content-primary);
|
|
9
|
+
margin-bottom: 0;
|
|
7
10
|
}
|
|
8
|
-
.
|
|
11
|
+
.critical-comms .alert .np-text-title-body {
|
|
12
|
+
color: var(--color-sentiment-content-primary);
|
|
13
|
+
}
|
|
14
|
+
.critical-comms .status-circle.negative {
|
|
9
15
|
background-color: #ffffff;
|
|
10
16
|
background-color: var(--color-background-screen);
|
|
11
17
|
}
|
|
12
|
-
.
|
|
13
|
-
color:
|
|
18
|
+
.critical-comms .status-circle.negative .status-icon {
|
|
19
|
+
color: #37517e;
|
|
20
|
+
color: var(--color-content-primary);
|
|
14
21
|
}
|
|
15
|
-
.
|
|
22
|
+
.critical-comms .alert__message .alert__action {
|
|
16
23
|
margin-top: 16px;
|
|
17
24
|
margin-top: var(--size-16);
|
|
18
25
|
}
|
|
19
|
-
.
|
|
20
|
-
--Button-
|
|
21
|
-
--Button-
|
|
22
|
-
--Button-
|
|
26
|
+
.critical-comms .wds-Button {
|
|
27
|
+
--Button-color: var(--color-content-primary);
|
|
28
|
+
--Button-color-hover: var(--color-content-primary);
|
|
29
|
+
--Button-color-active: var(--color-content-primary);
|
|
30
|
+
--Button-background: var(--color-background-screen);
|
|
31
|
+
--Button-background-hover: var(--color-sentiment-interactive-primary-hover);
|
|
32
|
+
--Button-background-active: var(--color-sentiment-interactive-primary-active);
|
|
33
|
+
}
|
|
34
|
+
.critical-comms .alert-warning .wds-Button {
|
|
35
|
+
--Button-background-hover: var(--color-sentiment-interactive-secondary-neutral-hover);
|
|
36
|
+
--Button-background-active: var(--color-sentiment-interactive-secondary-neutral-active);
|
|
23
37
|
}
|
|
24
38
|
@media (min-width: 768px) {
|
|
25
|
-
.
|
|
39
|
+
.critical-comms .alert-warning .alert__message,
|
|
40
|
+
.critical-comms .alert-negative .alert__message,
|
|
41
|
+
.critical-comms .alert-neutral .alert__message {
|
|
26
42
|
flex-direction: row;
|
|
27
43
|
justify-content: space-between;
|
|
28
44
|
align-items: center;
|
|
29
45
|
width: 100%;
|
|
30
46
|
}
|
|
31
|
-
.
|
|
47
|
+
.critical-comms .alert-warning .alert__message .alert__action,
|
|
48
|
+
.critical-comms .alert-negative .alert__message .alert__action,
|
|
49
|
+
.critical-comms .alert-neutral .alert__message .alert__action {
|
|
32
50
|
margin-top: 0;
|
|
33
51
|
margin-left: 16px;
|
|
34
52
|
margin-left: var(--padding-small);
|
|
@@ -1,51 +1,61 @@
|
|
|
1
|
-
.
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
color: var(--color-contrast-overlay);
|
|
5
|
-
background-color: var(--color-sentiment-negative);
|
|
6
|
-
|
|
7
|
-
.np-text-title-body {
|
|
8
|
-
color: var(--color-contrast-overlay);
|
|
9
|
-
}
|
|
10
|
-
}
|
|
1
|
+
.critical-comms {
|
|
2
|
+
border-radius: var(--radius-medium);
|
|
3
|
+
overflow: hidden;
|
|
11
4
|
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
.alert {
|
|
6
|
+
background-color: var(--color-sentiment-background-surface);
|
|
7
|
+
color: var(--color-sentiment-content-primary);
|
|
8
|
+
margin-bottom: 0;
|
|
14
9
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
10
|
+
.np-text-title-body {
|
|
11
|
+
color: var(--color-sentiment-content-primary);
|
|
18
12
|
}
|
|
13
|
+
}
|
|
19
14
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
.status-circle.negative {
|
|
16
|
+
background-color: var(--color-background-screen);
|
|
17
|
+
|
|
18
|
+
.status-icon {
|
|
19
|
+
color: var(--color-content-primary);
|
|
24
20
|
}
|
|
21
|
+
}
|
|
25
22
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
--Button-background-active: var(--color-sentiment-negative-secondary-active);
|
|
23
|
+
.alert__message {
|
|
24
|
+
.alert__action {
|
|
25
|
+
margin-top: var(--size-16);
|
|
30
26
|
}
|
|
31
27
|
}
|
|
32
28
|
|
|
29
|
+
.wds-Button {
|
|
30
|
+
--Button-color: var(--color-content-primary);
|
|
31
|
+
--Button-color-hover: var(--color-content-primary);
|
|
32
|
+
--Button-color-active: var(--color-content-primary);
|
|
33
|
+
|
|
34
|
+
--Button-background: var(--color-background-screen);
|
|
35
|
+
--Button-background-hover: var(--color-sentiment-interactive-primary-hover);
|
|
36
|
+
--Button-background-active: var(--color-sentiment-interactive-primary-active);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.alert-warning .wds-Button {
|
|
40
|
+
--Button-background-hover: var(--color-sentiment-interactive-secondary-neutral-hover);
|
|
41
|
+
--Button-background-active: var(--color-sentiment-interactive-secondary-neutral-active);
|
|
42
|
+
}
|
|
33
43
|
|
|
34
44
|
@media (--screen-md) {
|
|
35
|
-
.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
.alert-warning,
|
|
46
|
+
.alert-negative,
|
|
47
|
+
.alert-neutral {
|
|
48
|
+
.alert__message {
|
|
49
|
+
flex-direction: row;
|
|
50
|
+
justify-content: space-between;
|
|
51
|
+
align-items: center;
|
|
52
|
+
width: 100%;
|
|
53
|
+
|
|
54
|
+
.alert__action {
|
|
55
|
+
margin-top: 0;
|
|
56
|
+
margin-left: var(--padding-small);
|
|
47
57
|
}
|
|
48
58
|
}
|
|
49
59
|
}
|
|
50
60
|
}
|
|
51
|
-
}
|
|
61
|
+
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
2
|
-
|
|
3
2
|
import CriticalCommsBanner from '.';
|
|
4
|
-
import { withVariantConfig } from '../../.storybook/helpers';
|
|
5
3
|
|
|
6
4
|
export default {
|
|
7
5
|
component: CriticalCommsBanner,
|
|
@@ -18,21 +16,17 @@ export const Basic = {
|
|
|
18
16
|
},
|
|
19
17
|
};
|
|
20
18
|
|
|
21
|
-
export const
|
|
19
|
+
export const Sentiments: Story = {
|
|
20
|
+
render: (args) => (
|
|
21
|
+
<>
|
|
22
|
+
<CriticalCommsBanner {...args} sentiment="negative" title="Your account is overdrawn" />
|
|
23
|
+
<CriticalCommsBanner {...args} sentiment="warning" title="Your account needs attention" />
|
|
24
|
+
<CriticalCommsBanner {...args} sentiment="neutral" title="Your transfer is being processed" />
|
|
25
|
+
</>
|
|
26
|
+
),
|
|
22
27
|
args: {
|
|
23
|
-
title: 'Your account is overdrawn',
|
|
24
|
-
subtitle: 'Add money within the next 30 days',
|
|
25
|
-
action: { label: 'Take action', href: 'https://wise.com' },
|
|
26
|
-
},
|
|
27
|
-
...withVariantConfig(['default', 'dark', 'rtl']),
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
export const Mobile: Story = {
|
|
31
|
-
tags: ['!autodocs'],
|
|
32
|
-
args: {
|
|
33
|
-
title: 'Your account is overdrawn',
|
|
34
28
|
subtitle: 'Add money within the next 30 days',
|
|
35
29
|
action: { label: 'Take action', href: 'https://wise.com' },
|
|
30
|
+
className: 'm-b-1',
|
|
36
31
|
},
|
|
37
|
-
...withVariantConfig(['default', 'dark', 'rtl', 'mobile']),
|
|
38
32
|
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
2
|
+
|
|
3
|
+
import CriticalCommsBanner from '.';
|
|
4
|
+
import { withVariantConfig } from '../../.storybook/helpers';
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
component: CriticalCommsBanner,
|
|
8
|
+
title: 'Prompts/CriticalCommsBanner/tests',
|
|
9
|
+
tags: ['!autodocs'],
|
|
10
|
+
} satisfies Meta<typeof CriticalCommsBanner>;
|
|
11
|
+
|
|
12
|
+
type Story = StoryObj<typeof CriticalCommsBanner>;
|
|
13
|
+
|
|
14
|
+
export const Sentiments: Story = {
|
|
15
|
+
render: (args) => (
|
|
16
|
+
<>
|
|
17
|
+
<CriticalCommsBanner {...args} sentiment="negative" />
|
|
18
|
+
<CriticalCommsBanner {...args} sentiment="warning" />
|
|
19
|
+
<CriticalCommsBanner {...args} sentiment="neutral" />
|
|
20
|
+
</>
|
|
21
|
+
),
|
|
22
|
+
args: {
|
|
23
|
+
subtitle: 'Add money within the next 30 days',
|
|
24
|
+
action: { label: 'Take action', href: 'https://wise.com' },
|
|
25
|
+
className: 'm-b-1',
|
|
26
|
+
},
|
|
27
|
+
...withVariantConfig([
|
|
28
|
+
'default',
|
|
29
|
+
'dark',
|
|
30
|
+
'bright-green',
|
|
31
|
+
'forest-green',
|
|
32
|
+
'business',
|
|
33
|
+
'business--forest-green',
|
|
34
|
+
'business--bright-green',
|
|
35
|
+
]),
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const RTL: Story = {
|
|
39
|
+
render: (args) => (
|
|
40
|
+
<>
|
|
41
|
+
<CriticalCommsBanner {...args} sentiment="negative" />
|
|
42
|
+
<CriticalCommsBanner {...args} sentiment="warning" />
|
|
43
|
+
<CriticalCommsBanner {...args} sentiment="neutral" />
|
|
44
|
+
</>
|
|
45
|
+
),
|
|
46
|
+
args: {
|
|
47
|
+
subtitle: 'Add money within the next 30 days',
|
|
48
|
+
action: { label: 'Take action', href: 'https://wise.com' },
|
|
49
|
+
className: 'm-b-1',
|
|
50
|
+
},
|
|
51
|
+
...withVariantConfig(['rtl']),
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const Mobile: Story = {
|
|
55
|
+
args: {
|
|
56
|
+
subtitle: 'Add money within the next 30 days',
|
|
57
|
+
action: { label: 'Take action', href: 'https://wise.com' },
|
|
58
|
+
className: 'm-b-1',
|
|
59
|
+
},
|
|
60
|
+
...withVariantConfig(['mobile']),
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const Zoom: Story = {
|
|
64
|
+
args: {
|
|
65
|
+
subtitle: 'Add money within the next 30 days',
|
|
66
|
+
action: { label: 'Take action', href: 'https://wise.com' },
|
|
67
|
+
className: 'm-b-1',
|
|
68
|
+
},
|
|
69
|
+
...withVariantConfig(['400%']),
|
|
70
|
+
};
|