@transferwise/components 0.0.0-experimental-f727c49 → 0.0.0-experimental-854d710
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/common/hooks/useContainerSize.js +30 -0
- package/build/common/hooks/useContainerSize.js.map +1 -0
- package/build/common/hooks/useContainerSize.mjs +28 -0
- package/build/common/hooks/useContainerSize.mjs.map +1 -0
- package/build/common/hooks/useResizeObserver.js +3 -3
- package/build/common/hooks/useResizeObserver.js.map +1 -1
- package/build/common/hooks/useResizeObserver.mjs +3 -3
- package/build/common/hooks/useResizeObserver.mjs.map +1 -1
- package/build/criticalBanner/CriticalCommsBanner.js +3 -0
- package/build/criticalBanner/CriticalCommsBanner.js.map +1 -1
- package/build/criticalBanner/CriticalCommsBanner.mjs +3 -0
- package/build/criticalBanner/CriticalCommsBanner.mjs.map +1 -1
- package/build/field/Field.js +3 -2
- package/build/field/Field.js.map +1 -1
- package/build/field/Field.mjs +3 -2
- package/build/field/Field.mjs.map +1 -1
- package/build/i18n/en.json +2 -0
- package/build/i18n/en.json.js +2 -0
- package/build/i18n/en.json.js.map +1 -1
- package/build/i18n/en.json.mjs +2 -0
- package/build/i18n/en.json.mjs.map +1 -1
- package/build/index.js +2 -0
- package/build/index.js.map +1 -1
- package/build/index.mjs +1 -0
- package/build/index.mjs.map +1 -1
- package/build/listItem/Prompt/ListItemPrompt.js +3 -2
- package/build/listItem/Prompt/ListItemPrompt.js.map +1 -1
- package/build/listItem/Prompt/ListItemPrompt.mjs +3 -2
- package/build/listItem/Prompt/ListItemPrompt.mjs.map +1 -1
- package/build/main.css +194 -29
- package/build/prompt/ActionPrompt/ActionPrompt.js +8 -40
- package/build/prompt/ActionPrompt/ActionPrompt.js.map +1 -1
- package/build/prompt/ActionPrompt/ActionPrompt.mjs +8 -40
- package/build/prompt/ActionPrompt/ActionPrompt.mjs.map +1 -1
- package/build/prompt/CriticalBanner/CriticalBanner.js +143 -0
- package/build/prompt/CriticalBanner/CriticalBanner.js.map +1 -0
- package/build/prompt/CriticalBanner/CriticalBanner.mjs +141 -0
- package/build/prompt/CriticalBanner/CriticalBanner.mjs.map +1 -0
- package/build/prompt/CriticalBanner/helpers.js +29 -0
- package/build/prompt/CriticalBanner/helpers.js.map +1 -0
- package/build/prompt/CriticalBanner/helpers.mjs +26 -0
- package/build/prompt/CriticalBanner/helpers.mjs.map +1 -0
- package/build/prompt/PrimitivePrompt/PrimitivePrompt.js +11 -4
- package/build/prompt/PrimitivePrompt/PrimitivePrompt.js.map +1 -1
- package/build/prompt/PrimitivePrompt/PrimitivePrompt.mjs +11 -4
- package/build/prompt/PrimitivePrompt/PrimitivePrompt.mjs.map +1 -1
- package/build/prompt/common/Expander/Expander.js +35 -0
- package/build/prompt/common/Expander/Expander.js.map +1 -0
- package/build/prompt/common/Expander/Expander.messages.js +17 -0
- package/build/prompt/common/Expander/Expander.messages.js.map +1 -0
- package/build/prompt/common/Expander/Expander.messages.mjs +13 -0
- package/build/prompt/common/Expander/Expander.messages.mjs.map +1 -0
- package/build/prompt/common/Expander/Expander.mjs +33 -0
- package/build/prompt/common/Expander/Expander.mjs.map +1 -0
- package/build/prompt/helpers/promptMedia.js +52 -0
- package/build/prompt/helpers/promptMedia.js.map +1 -0
- package/build/prompt/helpers/promptMedia.mjs +50 -0
- package/build/prompt/helpers/promptMedia.mjs.map +1 -0
- package/build/styles/main.css +194 -29
- package/build/styles/prompt/CriticalBanner/CriticalBanner.css +134 -0
- package/build/styles/prompt/CriticalBanner/CriticalBanner.vars.css +0 -0
- package/build/styles/prompt/common/Expander/Expander.css +8 -0
- package/build/typeahead/Typeahead.js +3 -2
- package/build/typeahead/Typeahead.js.map +1 -1
- package/build/typeahead/Typeahead.mjs +3 -2
- package/build/typeahead/Typeahead.mjs.map +1 -1
- package/build/types/common/hooks/useContainerSize.d.ts +14 -0
- package/build/types/common/hooks/useContainerSize.d.ts.map +1 -0
- package/build/types/common/hooks/useResizeObserver.d.ts +1 -1
- package/build/types/common/hooks/useResizeObserver.d.ts.map +1 -1
- package/build/types/criticalBanner/CriticalCommsBanner.d.ts +3 -0
- package/build/types/criticalBanner/CriticalCommsBanner.d.ts.map +1 -1
- package/build/types/index.d.ts +2 -2
- package/build/types/index.d.ts.map +1 -1
- package/build/types/prompt/ActionPrompt/ActionPrompt.d.ts +2 -11
- package/build/types/prompt/ActionPrompt/ActionPrompt.d.ts.map +1 -1
- package/build/types/prompt/CriticalBanner/CriticalBanner.d.ts +39 -0
- package/build/types/prompt/CriticalBanner/CriticalBanner.d.ts.map +1 -0
- package/build/types/prompt/CriticalBanner/helpers.d.ts +18 -0
- package/build/types/prompt/CriticalBanner/helpers.d.ts.map +1 -0
- package/build/types/prompt/CriticalBanner/index.d.ts +3 -0
- package/build/types/prompt/CriticalBanner/index.d.ts.map +1 -0
- package/build/types/prompt/PrimitivePrompt/PrimitivePrompt.d.ts +35 -3
- package/build/types/prompt/PrimitivePrompt/PrimitivePrompt.d.ts.map +1 -1
- package/build/types/prompt/common/Expander/Expander.d.ts +20 -0
- package/build/types/prompt/common/Expander/Expander.d.ts.map +1 -0
- package/build/types/prompt/common/Expander/Expander.messages.d.ts +14 -0
- package/build/types/prompt/common/Expander/Expander.messages.d.ts.map +1 -0
- package/build/types/prompt/helpers/promptMedia.d.ts +22 -0
- package/build/types/prompt/helpers/promptMedia.d.ts.map +1 -0
- package/build/types/prompt/index.d.ts +2 -0
- package/build/types/prompt/index.d.ts.map +1 -1
- package/build/types/test-utils/index.d.ts +4 -0
- package/build/types/test-utils/index.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/common/hooks/useContainerSize.test.tsx +125 -0
- package/src/common/hooks/useContainerSize.ts +32 -0
- package/src/common/hooks/useResizeObserver.ts +3 -2
- package/src/criticalBanner/CriticalCommsBanner.story.tsx +4 -0
- package/src/criticalBanner/CriticalCommsBanner.test.story.tsx +1 -1
- package/src/criticalBanner/CriticalCommsBanner.tsx +3 -0
- package/src/i18n/en.json +2 -0
- package/src/index.ts +2 -2
- package/src/main.css +194 -29
- package/src/main.less +3 -1
- package/src/prompt/ActionPrompt/ActionPrompt.tsx +9 -62
- package/src/prompt/CriticalBanner/CriticalBanner.accessibility.docs.mdx +113 -0
- package/src/prompt/CriticalBanner/CriticalBanner.css +134 -0
- package/src/prompt/CriticalBanner/CriticalBanner.less +155 -0
- package/src/prompt/CriticalBanner/CriticalBanner.story.tsx +635 -0
- package/src/prompt/CriticalBanner/CriticalBanner.test.story.tsx +422 -0
- package/src/prompt/CriticalBanner/CriticalBanner.tsx +179 -0
- package/src/prompt/CriticalBanner/CriticalBanner.vars.css +0 -0
- package/src/prompt/CriticalBanner/CriticalBanner.vars.less +6 -0
- package/src/prompt/CriticalBanner/helpers.ts +39 -0
- package/src/prompt/CriticalBanner/index.ts +2 -0
- package/src/prompt/PrimitivePrompt/PrimitivePrompt.tsx +56 -40
- package/src/prompt/common/Expander/Expander.css +8 -0
- package/src/prompt/common/Expander/Expander.less +9 -0
- package/src/prompt/common/Expander/Expander.messages.ts +14 -0
- package/src/prompt/common/Expander/Expander.test.tsx +167 -0
- package/src/prompt/common/Expander/Expander.tsx +83 -0
- package/src/prompt/helpers/promptMedia.tsx +79 -0
- package/src/prompt/index.ts +4 -0
- package/src/sentimentSurface/SentimentSurface.story.tsx +43 -17
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import React, { act } from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
|
|
4
|
+
import { mockResizeObserver } from '../../test-utils/window-mock';
|
|
5
|
+
|
|
6
|
+
import { useContainerSize } from './useContainerSize';
|
|
7
|
+
|
|
8
|
+
mockResizeObserver();
|
|
9
|
+
|
|
10
|
+
describe('useContainerSize', () => {
|
|
11
|
+
let resizeObserverCallback: ResizeObserverCallback | null = null;
|
|
12
|
+
const OriginalResizeObserver = global.ResizeObserver;
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
resizeObserverCallback = null;
|
|
16
|
+
|
|
17
|
+
// Capture the ResizeObserver callback for testing
|
|
18
|
+
global.ResizeObserver = jest.fn().mockImplementation((callback: ResizeObserverCallback) => {
|
|
19
|
+
resizeObserverCallback = callback;
|
|
20
|
+
const instance = new OriginalResizeObserver(callback);
|
|
21
|
+
return instance;
|
|
22
|
+
}) as unknown as typeof ResizeObserver;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
afterEach(() => {
|
|
26
|
+
global.ResizeObserver = OriginalResizeObserver;
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Helper to create a test component
|
|
30
|
+
function TestComponent({
|
|
31
|
+
breakpoint,
|
|
32
|
+
onStateChange,
|
|
33
|
+
}: {
|
|
34
|
+
breakpoint: number;
|
|
35
|
+
onStateChange: (state: boolean) => void;
|
|
36
|
+
}) {
|
|
37
|
+
const [ref, isAboveBreakpoint] = useContainerSize(breakpoint);
|
|
38
|
+
|
|
39
|
+
// Call the callback whenever state changes
|
|
40
|
+
React.useEffect(() => {
|
|
41
|
+
onStateChange(isAboveBreakpoint);
|
|
42
|
+
}, [isAboveBreakpoint, onStateChange]);
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<div ref={ref} data-testid="container">
|
|
46
|
+
Test
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Helper to simulate container resize
|
|
52
|
+
function simulateResize(width: number, options?: { noBorderBoxSize?: boolean }) {
|
|
53
|
+
const container = screen.getByTestId('container');
|
|
54
|
+
|
|
55
|
+
act(() => {
|
|
56
|
+
if (resizeObserverCallback) {
|
|
57
|
+
const entry = {
|
|
58
|
+
target: container,
|
|
59
|
+
borderBoxSize: options?.noBorderBoxSize
|
|
60
|
+
? undefined
|
|
61
|
+
: [{ inlineSize: width, blockSize: 100 }],
|
|
62
|
+
contentRect: {
|
|
63
|
+
width,
|
|
64
|
+
height: 100,
|
|
65
|
+
x: 0,
|
|
66
|
+
y: 0,
|
|
67
|
+
top: 0,
|
|
68
|
+
right: width,
|
|
69
|
+
bottom: 100,
|
|
70
|
+
left: 0,
|
|
71
|
+
toJSON: () => ({}),
|
|
72
|
+
},
|
|
73
|
+
contentBoxSize: [{ inlineSize: width, blockSize: 100 }],
|
|
74
|
+
devicePixelContentBoxSize: [{ inlineSize: width, blockSize: 100 }],
|
|
75
|
+
} as ResizeObserverEntry;
|
|
76
|
+
|
|
77
|
+
resizeObserverCallback([entry], {} as ResizeObserver);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
it('returns initial state as false', () => {
|
|
83
|
+
const onStateChange = jest.fn();
|
|
84
|
+
render(<TestComponent breakpoint={480} onStateChange={onStateChange} />);
|
|
85
|
+
|
|
86
|
+
// Initial call with false
|
|
87
|
+
expect(onStateChange).toHaveBeenCalledWith(false);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('updates to true when container width is above breakpoint', () => {
|
|
91
|
+
const onStateChange = jest.fn();
|
|
92
|
+
render(<TestComponent breakpoint={480} onStateChange={onStateChange} />);
|
|
93
|
+
|
|
94
|
+
simulateResize(600);
|
|
95
|
+
expect(onStateChange).toHaveBeenCalledWith(true);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('remains false when container width is below breakpoint', () => {
|
|
99
|
+
const onStateChange = jest.fn();
|
|
100
|
+
render(<TestComponent breakpoint={480} onStateChange={onStateChange} />);
|
|
101
|
+
|
|
102
|
+
simulateResize(400);
|
|
103
|
+
expect(onStateChange).toHaveBeenCalledWith(false);
|
|
104
|
+
expect(onStateChange).not.toHaveBeenCalledWith(true);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('returns true when container width equals breakpoint', () => {
|
|
108
|
+
const onStateChange = jest.fn();
|
|
109
|
+
render(<TestComponent breakpoint={480} onStateChange={onStateChange} />);
|
|
110
|
+
|
|
111
|
+
simulateResize(480);
|
|
112
|
+
expect(onStateChange).toHaveBeenCalledWith(true);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('updates state when container crosses breakpoint from below to above', () => {
|
|
116
|
+
const onStateChange = jest.fn();
|
|
117
|
+
render(<TestComponent breakpoint={480} onStateChange={onStateChange} />);
|
|
118
|
+
|
|
119
|
+
simulateResize(400);
|
|
120
|
+
expect(onStateChange).toHaveBeenCalledWith(false);
|
|
121
|
+
|
|
122
|
+
simulateResize(600);
|
|
123
|
+
expect(onStateChange).toHaveBeenCalledWith(true);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { useRef, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import { useResizeObserver } from './useResizeObserver';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Hook that returns a ref and a boolean indicating if the container
|
|
7
|
+
* has a width >= the specified breakpoint.
|
|
8
|
+
*
|
|
9
|
+
* Useful for synchronizing React state with CSS container queries.
|
|
10
|
+
*
|
|
11
|
+
* Uses content-box measurements to match CSS container query behavior
|
|
12
|
+
* (excludes padding and border).
|
|
13
|
+
*
|
|
14
|
+
* @param breakpoint - Minimum width in pixels
|
|
15
|
+
* @returns [ref, isAboveBreakpoint] tuple
|
|
16
|
+
*/
|
|
17
|
+
export function useContainerSize(breakpoint: number): [React.RefObject<HTMLDivElement>, boolean] {
|
|
18
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
19
|
+
const [isAboveBreakpoint, setIsAboveBreakpoint] = useState(false);
|
|
20
|
+
|
|
21
|
+
useResizeObserver(
|
|
22
|
+
ref,
|
|
23
|
+
(entry) => {
|
|
24
|
+
// Use contentRect.width to match CSS container query box model (content-box)
|
|
25
|
+
const inlineSize = entry.contentRect.width;
|
|
26
|
+
setIsAboveBreakpoint(inlineSize >= breakpoint);
|
|
27
|
+
},
|
|
28
|
+
'content-box',
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
return [ref, isAboveBreakpoint];
|
|
32
|
+
}
|
|
@@ -5,6 +5,7 @@ import { useEffectEvent } from './useEffectEvent';
|
|
|
5
5
|
export function useResizeObserver(
|
|
6
6
|
ref: React.MutableRefObject<Element | null>,
|
|
7
7
|
callback: (entry: ResizeObserverEntry) => void,
|
|
8
|
+
box: ResizeObserverBoxOptions = 'border-box',
|
|
8
9
|
) {
|
|
9
10
|
const handleCallback = useEffectEvent(callback);
|
|
10
11
|
useEffect(() => {
|
|
@@ -12,11 +13,11 @@ export function useResizeObserver(
|
|
|
12
13
|
const resizeObserver = new ResizeObserver(([entry]) => {
|
|
13
14
|
handleCallback(entry);
|
|
14
15
|
});
|
|
15
|
-
resizeObserver.observe(ref.current, { box
|
|
16
|
+
resizeObserver.observe(ref.current, { box });
|
|
16
17
|
return () => {
|
|
17
18
|
resizeObserver.disconnect();
|
|
18
19
|
};
|
|
19
20
|
}
|
|
20
21
|
return () => {};
|
|
21
|
-
}, [handleCallback, ref]);
|
|
22
|
+
}, [handleCallback, ref, box]);
|
|
22
23
|
}
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
2
2
|
import CriticalCommsBanner from '.';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* @deprecated Use **`CriticalBanner`** component instead.
|
|
6
|
+
*/
|
|
4
7
|
export default {
|
|
5
8
|
component: CriticalCommsBanner,
|
|
6
9
|
title: 'Prompts/CriticalCommsBanner',
|
|
10
|
+
tags: ['deprecated'],
|
|
7
11
|
} satisfies Meta<typeof CriticalCommsBanner>;
|
|
8
12
|
|
|
9
13
|
type Story = StoryObj<typeof CriticalCommsBanner>;
|
|
@@ -6,7 +6,7 @@ import { withVariantConfig } from '../../.storybook/helpers';
|
|
|
6
6
|
export default {
|
|
7
7
|
component: CriticalCommsBanner,
|
|
8
8
|
title: 'Prompts/CriticalCommsBanner/Tests',
|
|
9
|
-
tags: ['!autodocs'],
|
|
9
|
+
tags: ['!autodocs', 'deprecated'],
|
|
10
10
|
} satisfies Meta<typeof CriticalCommsBanner>;
|
|
11
11
|
|
|
12
12
|
type Story = StoryObj<typeof CriticalCommsBanner>;
|
|
@@ -51,6 +51,9 @@ const iconBySentiment: Record<CriticalCommsBannerSentiment, React.ReactNode> = {
|
|
|
51
51
|
),
|
|
52
52
|
};
|
|
53
53
|
|
|
54
|
+
/**
|
|
55
|
+
* @deprecated `CriticalCommsBanner` component is deprecated and now replaced by the `CriticalBanner` component.
|
|
56
|
+
*/
|
|
54
57
|
function CriticalCommsBanner({
|
|
55
58
|
title,
|
|
56
59
|
subtitle,
|
package/src/i18n/en.json
CHANGED
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
"neptune.DateLookup.selected": "selected",
|
|
17
17
|
"neptune.DateLookup.twentyYears": "20 years",
|
|
18
18
|
"neptune.DateLookup.year": "year",
|
|
19
|
+
"neptune.Expander.collapseAriaLabel": "Collapse",
|
|
20
|
+
"neptune.Expander.expandAriaLabel": "Expand",
|
|
19
21
|
"neptune.ExpressiveMoneyInput.currency.search.placeholder": "Type a currency / country",
|
|
20
22
|
"neptune.ExpressiveMoneyInput.currency.select.currency": "Select currency",
|
|
21
23
|
"neptune.FlowNavigation.back": "back to previous step",
|
package/src/index.ts
CHANGED
|
@@ -36,7 +36,7 @@ export type { HeaderProps } from './header';
|
|
|
36
36
|
export type { EmphasisProps } from './emphasis';
|
|
37
37
|
export type { FieldProps } from './field/Field';
|
|
38
38
|
export type { InfoProps } from './info';
|
|
39
|
-
export type { InlinePromptProps, ActionPromptProps } from './prompt';
|
|
39
|
+
export type { InlinePromptProps, ActionPromptProps, CriticalBannerProps } from './prompt';
|
|
40
40
|
export type { InfoPromptProps, InfoPromptAction, InfoPromptMedia } from './prompt';
|
|
41
41
|
export type { InputWithDisplayFormatProps } from './inputWithDisplayFormat';
|
|
42
42
|
export type { InputProps } from './inputs/Input';
|
|
@@ -175,7 +175,7 @@ export { default as Header } from './header';
|
|
|
175
175
|
export { default as Image } from './image';
|
|
176
176
|
export { default as Info } from './info';
|
|
177
177
|
export { default as InlineAlert } from './inlineAlert';
|
|
178
|
-
export { InfoPrompt, InlinePrompt, ActionPrompt } from './prompt';
|
|
178
|
+
export { InfoPrompt, InlinePrompt, ActionPrompt, CriticalBanner } from './prompt';
|
|
179
179
|
export { default as InputWithDisplayFormat } from './inputWithDisplayFormat';
|
|
180
180
|
export { Input } from './inputs/Input';
|
|
181
181
|
export { InputGroup } from './inputs/InputGroup';
|
package/src/main.css
CHANGED
|
@@ -32235,6 +32235,200 @@ html:not([dir="rtl"]) .np-navigation-option {
|
|
|
32235
32235
|
}
|
|
32236
32236
|
}
|
|
32237
32237
|
|
|
32238
|
+
.wds-action-prompt {
|
|
32239
|
+
--Prompt-padding: var(--size-16);
|
|
32240
|
+
--Prompt-actions-gap: var(--size-8);
|
|
32241
|
+
--Prompt-gap: var(--size-10) var(--size-16);
|
|
32242
|
+
--Prompt-border-radius: var(--radius-large);
|
|
32243
|
+
}
|
|
32244
|
+
|
|
32245
|
+
.wds-action-prompt--media-image {
|
|
32246
|
+
width: 48px;
|
|
32247
|
+
width: var(--size-48);
|
|
32248
|
+
height: 48px;
|
|
32249
|
+
height: var(--size-48);
|
|
32250
|
+
-o-object-fit: contain;
|
|
32251
|
+
object-fit: contain;
|
|
32252
|
+
}
|
|
32253
|
+
|
|
32254
|
+
@media (max-width: 767px) {
|
|
32255
|
+
.wds-action-prompt--with-two-actions .wds-prompt__actions-wrapper .wds-Button {
|
|
32256
|
+
flex: 1 1 calc(50% - (var(--Prompt-actions-gap) / 2));
|
|
32257
|
+
min-width: -moz-fit-content;
|
|
32258
|
+
min-width: fit-content;
|
|
32259
|
+
}
|
|
32260
|
+
}
|
|
32261
|
+
|
|
32262
|
+
.wds-action-prompt__content {
|
|
32263
|
+
max-width: calc(48px * 10);
|
|
32264
|
+
max-width: calc(var(--size-48) * 10);
|
|
32265
|
+
}
|
|
32266
|
+
|
|
32267
|
+
.wds-critical-banner {
|
|
32268
|
+
--Prompt-padding: var(--size-16);
|
|
32269
|
+
--Prompt-actions-gap: var(--size-8);
|
|
32270
|
+
--Prompt-gap: var(--size-10) var(--size-16);
|
|
32271
|
+
--Prompt-border-radius: 0;
|
|
32272
|
+
container-type: inline-size;
|
|
32273
|
+
--critical-banner-easing: cubic-bezier(0.9, 0, 0.7, 1);
|
|
32274
|
+
--critical-banner-duration: 150ms;
|
|
32275
|
+
/* Override PrimitivePrompt's --screen-sm-max actions behaviour:
|
|
32276
|
+
actions only go full-width below mobile-max token (container query) */
|
|
32277
|
+
}
|
|
32278
|
+
|
|
32279
|
+
.wds-critical-banner--media-image {
|
|
32280
|
+
width: 48px;
|
|
32281
|
+
width: var(--size-48);
|
|
32282
|
+
height: 48px;
|
|
32283
|
+
height: var(--size-48);
|
|
32284
|
+
-o-object-fit: contain;
|
|
32285
|
+
object-fit: contain;
|
|
32286
|
+
}
|
|
32287
|
+
|
|
32288
|
+
.wds-critical-banner__title {
|
|
32289
|
+
display: -webkit-box;
|
|
32290
|
+
-webkit-line-clamp: 8;
|
|
32291
|
+
line-clamp: 8;
|
|
32292
|
+
-webkit-box-orient: vertical;
|
|
32293
|
+
max-height: 192px;
|
|
32294
|
+
overflow: hidden;
|
|
32295
|
+
transition: max-height var(--critical-banner-duration) var(--critical-banner-easing);
|
|
32296
|
+
}
|
|
32297
|
+
|
|
32298
|
+
.wds-critical-banner--collapsed .wds-critical-banner__title {
|
|
32299
|
+
-webkit-line-clamp: 2;
|
|
32300
|
+
line-clamp: 2;
|
|
32301
|
+
max-height: 48px;
|
|
32302
|
+
}
|
|
32303
|
+
|
|
32304
|
+
.wds-critical-banner__description {
|
|
32305
|
+
max-height: 30vh;
|
|
32306
|
+
opacity: 1;
|
|
32307
|
+
overflow: hidden;
|
|
32308
|
+
transition: max-height var(--critical-banner-duration) var(--critical-banner-easing), opacity var(--critical-banner-duration) var(--critical-banner-easing);
|
|
32309
|
+
}
|
|
32310
|
+
|
|
32311
|
+
.wds-critical-banner--collapsed .wds-critical-banner__description--with-title {
|
|
32312
|
+
max-height: 0;
|
|
32313
|
+
opacity: 0;
|
|
32314
|
+
}
|
|
32315
|
+
|
|
32316
|
+
.wds-critical-banner--collapsed .wds-critical-banner__description:not(.wds-critical-banner__description--with-title) {
|
|
32317
|
+
display: -webkit-box;
|
|
32318
|
+
-webkit-line-clamp: 2;
|
|
32319
|
+
line-clamp: 2;
|
|
32320
|
+
-webkit-box-orient: vertical;
|
|
32321
|
+
overflow: hidden;
|
|
32322
|
+
}
|
|
32323
|
+
|
|
32324
|
+
.wds-critical-banner .wds-prompt__content-wrapper {
|
|
32325
|
+
grid-template-columns: auto 1fr auto;
|
|
32326
|
+
align-items: flex-start;
|
|
32327
|
+
transition: row-gap var(--critical-banner-duration) var(--critical-banner-easing);
|
|
32328
|
+
}
|
|
32329
|
+
|
|
32330
|
+
.wds-critical-banner--collapsed .wds-prompt__content-wrapper {
|
|
32331
|
+
row-gap: 0;
|
|
32332
|
+
}
|
|
32333
|
+
|
|
32334
|
+
.wds-critical-banner__text-wrapper {
|
|
32335
|
+
position: relative;
|
|
32336
|
+
display: flex;
|
|
32337
|
+
flex-direction: column;
|
|
32338
|
+
justify-content: center;
|
|
32339
|
+
align-items: flex-start;
|
|
32340
|
+
text-align: start;
|
|
32341
|
+
min-width: 0;
|
|
32342
|
+
max-width: 480px;
|
|
32343
|
+
height: 100%;
|
|
32344
|
+
padding-top: 3px;
|
|
32345
|
+
}
|
|
32346
|
+
|
|
32347
|
+
@media (max-width: 320px) {
|
|
32348
|
+
.wds-critical-banner__text-wrapper {
|
|
32349
|
+
padding-top: 0;
|
|
32350
|
+
}
|
|
32351
|
+
}
|
|
32352
|
+
|
|
32353
|
+
@container (max-width: 320px) {
|
|
32354
|
+
.wds-critical-banner__text-wrapper {
|
|
32355
|
+
padding-top: 0;
|
|
32356
|
+
}
|
|
32357
|
+
}
|
|
32358
|
+
|
|
32359
|
+
.wds-critical-banner--collapsed .wds-critical-banner__title,
|
|
32360
|
+
.wds-critical-banner--collapsed .wds-critical-banner__description {
|
|
32361
|
+
transform: translateY(0);
|
|
32362
|
+
}
|
|
32363
|
+
|
|
32364
|
+
.wds-critical-banner__toggle {
|
|
32365
|
+
flex-shrink: 0;
|
|
32366
|
+
transition: transform var(--critical-banner-duration) var(--critical-banner-easing);
|
|
32367
|
+
}
|
|
32368
|
+
|
|
32369
|
+
.wds-critical-banner__toggle--collapsed {
|
|
32370
|
+
transform: rotate(180deg);
|
|
32371
|
+
}
|
|
32372
|
+
|
|
32373
|
+
@container (min-width: 768px) {
|
|
32374
|
+
.wds-critical-banner__toggle {
|
|
32375
|
+
display: none;
|
|
32376
|
+
}
|
|
32377
|
+
}
|
|
32378
|
+
|
|
32379
|
+
.wds-critical-banner .wds-prompt__actions-wrapper {
|
|
32380
|
+
grid-column-start: 2;
|
|
32381
|
+
grid-column-end: 3;
|
|
32382
|
+
max-height: 200px;
|
|
32383
|
+
opacity: 1;
|
|
32384
|
+
overflow: visible;
|
|
32385
|
+
}
|
|
32386
|
+
|
|
32387
|
+
@container (max-width: 600px) {
|
|
32388
|
+
.wds-critical-banner .wds-prompt__actions-wrapper {
|
|
32389
|
+
grid-column: span 3;
|
|
32390
|
+
width: 100%;
|
|
32391
|
+
}
|
|
32392
|
+
.wds-critical-banner .wds-prompt__actions-wrapper .wds-Button {
|
|
32393
|
+
flex: 1 1 100%;
|
|
32394
|
+
width: 100%;
|
|
32395
|
+
}
|
|
32396
|
+
}
|
|
32397
|
+
|
|
32398
|
+
.wds-critical-banner--collapsed .wds-prompt__actions-wrapper {
|
|
32399
|
+
max-height: 0;
|
|
32400
|
+
opacity: 0;
|
|
32401
|
+
overflow: hidden;
|
|
32402
|
+
pointer-events: none;
|
|
32403
|
+
}
|
|
32404
|
+
|
|
32405
|
+
@container (max-width: 600px) {
|
|
32406
|
+
.wds-critical-banner--with-two-actions .wds-prompt__actions-wrapper .wds-Button {
|
|
32407
|
+
flex: 1 1 calc(50% - (var(--Prompt-actions-gap) / 2));
|
|
32408
|
+
min-width: -moz-fit-content;
|
|
32409
|
+
min-width: fit-content;
|
|
32410
|
+
}
|
|
32411
|
+
}
|
|
32412
|
+
|
|
32413
|
+
@media (prefers-reduced-motion: reduce) {
|
|
32414
|
+
.wds-critical-banner__description,
|
|
32415
|
+
.wds-critical-banner__title,
|
|
32416
|
+
.wds-critical-banner .wds-prompt__content-wrapper,
|
|
32417
|
+
.wds-critical-banner__toggle {
|
|
32418
|
+
transition: none !important;
|
|
32419
|
+
}
|
|
32420
|
+
}
|
|
32421
|
+
|
|
32422
|
+
.wds-expander-toggle {
|
|
32423
|
+
align-self: flex-start;
|
|
32424
|
+
flex-shrink: 0;
|
|
32425
|
+
transition: transform 0.2s ease-in-out;
|
|
32426
|
+
}
|
|
32427
|
+
|
|
32428
|
+
.wds-expander-toggle--collapsed {
|
|
32429
|
+
transform: rotate(180deg);
|
|
32430
|
+
}
|
|
32431
|
+
|
|
32238
32432
|
.wds-radio-group .np-radio:last-child label {
|
|
32239
32433
|
margin-bottom: 0;
|
|
32240
32434
|
}
|
|
@@ -34660,32 +34854,3 @@ html:not([dir="rtl"]) .np-navigation-option {
|
|
|
34660
34854
|
.np-list-item__action {
|
|
34661
34855
|
flex-shrink: 0;
|
|
34662
34856
|
}
|
|
34663
|
-
|
|
34664
|
-
.wds-action-prompt {
|
|
34665
|
-
--Prompt-padding: var(--size-16);
|
|
34666
|
-
--Prompt-actions-gap: var(--size-8);
|
|
34667
|
-
--Prompt-gap: var(--size-10) var(--size-16);
|
|
34668
|
-
--Prompt-border-radius: var(--radius-large);
|
|
34669
|
-
}
|
|
34670
|
-
|
|
34671
|
-
.wds-action-prompt--media-image {
|
|
34672
|
-
width: 48px;
|
|
34673
|
-
width: var(--size-48);
|
|
34674
|
-
height: 48px;
|
|
34675
|
-
height: var(--size-48);
|
|
34676
|
-
-o-object-fit: contain;
|
|
34677
|
-
object-fit: contain;
|
|
34678
|
-
}
|
|
34679
|
-
|
|
34680
|
-
@media (max-width: 767px) {
|
|
34681
|
-
.wds-action-prompt--with-two-actions .wds-prompt__actions-wrapper .wds-Button {
|
|
34682
|
-
flex: 1 1 calc(50% - (var(--Prompt-actions-gap) / 2));
|
|
34683
|
-
min-width: -moz-fit-content;
|
|
34684
|
-
min-width: fit-content;
|
|
34685
|
-
}
|
|
34686
|
-
}
|
|
34687
|
-
|
|
34688
|
-
.wds-action-prompt__content {
|
|
34689
|
-
max-width: calc(48px * 10);
|
|
34690
|
-
max-width: calc(var(--size-48) * 10);
|
|
34691
|
-
}
|
package/src/main.less
CHANGED
|
@@ -67,6 +67,9 @@
|
|
|
67
67
|
@import "./prompt/PrimitivePrompt/PrimitivePrompt.less";
|
|
68
68
|
@import "./prompt/InlinePrompt/InlinePrompt.less";
|
|
69
69
|
@import "./prompt/InfoPrompt/InfoPrompt.less";
|
|
70
|
+
@import "./prompt/ActionPrompt/ActionPrompt.less";
|
|
71
|
+
@import "./prompt/CriticalBanner/CriticalBanner.less";
|
|
72
|
+
@import "./prompt/common/Expander/Expander.less";
|
|
70
73
|
@import "./radioGroup/RadioGroup.less";
|
|
71
74
|
@import "./section/Section.less";
|
|
72
75
|
@import "./slidingPanel/SlidingPanel.less";
|
|
@@ -91,7 +94,6 @@
|
|
|
91
94
|
@import "./progress/Progress.less";
|
|
92
95
|
@import "./progressBar/ProgressBar.less";
|
|
93
96
|
@import "./legacylistItem/LegacyListItem.less";
|
|
94
|
-
@import "./prompt/ActionPrompt/ActionPrompt.less";
|
|
95
97
|
|
|
96
98
|
// List all less files in src in alphabetical order: find -s src -type f -name '*.less' ! -name 'main.less'
|
|
97
99
|
// Make sure you are not referencing main.less itself in this file!
|
|
@@ -1,31 +1,19 @@
|
|
|
1
1
|
import { AriaAttributes, ReactNode, useId } from 'react';
|
|
2
2
|
import { clsx } from 'clsx';
|
|
3
3
|
|
|
4
|
-
import StatusIcon from '../../statusIcon';
|
|
5
4
|
import Body from '../../body';
|
|
6
5
|
import Button from '../../button';
|
|
7
6
|
import { Breakpoint, Typography } from '../../common';
|
|
8
|
-
import AvatarView, { AvatarViewProps } from '../../avatarView';
|
|
9
|
-
import Image from '../../image';
|
|
10
7
|
import { ButtonProps } from '../../button/Button.types';
|
|
11
8
|
import { PrimitivePrompt, PrimitivePromptProps } from '../PrimitivePrompt';
|
|
12
|
-
import { BadgeAssetsProps } from '../../badge';
|
|
13
|
-
import { GiftBox } from '@transferwise/icons';
|
|
14
9
|
import { useScreenSize } from '../../common/hooks/useScreenSize';
|
|
10
|
+
import { renderPromptMedia, PromptMedia } from '../helpers/promptMedia';
|
|
15
11
|
|
|
16
12
|
export type ActionPromptProps = {
|
|
17
13
|
title: ReactNode;
|
|
18
14
|
description?: ReactNode;
|
|
19
15
|
/** @default {} */
|
|
20
|
-
media?:
|
|
21
|
-
imgSrc?: string;
|
|
22
|
-
avatar?: Pick<AvatarViewProps, 'imgSrc' | 'profileName' | 'profileType'> & {
|
|
23
|
-
asset?: AvatarViewProps['children'];
|
|
24
|
-
badge?: Pick<BadgeAssetsProps, 'flagCode'>;
|
|
25
|
-
};
|
|
26
|
-
'aria-label'?: string;
|
|
27
|
-
'aria-hidden'?: boolean;
|
|
28
|
-
};
|
|
16
|
+
media?: PromptMedia;
|
|
29
17
|
action: Pick<ButtonProps, 'onClick' | 'href' | 'target'> & {
|
|
30
18
|
label: ButtonProps['children'];
|
|
31
19
|
};
|
|
@@ -74,54 +62,13 @@ export const ActionPrompt = ({
|
|
|
74
62
|
.filter(Boolean)
|
|
75
63
|
.join(' ');
|
|
76
64
|
|
|
77
|
-
const renderMedia = () =>
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
alt={media['aria-label'] ?? ''}
|
|
85
|
-
/>
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
if (media?.avatar) {
|
|
89
|
-
const badge = media.avatar.badge
|
|
90
|
-
? media.avatar.badge
|
|
91
|
-
: sentiment === 'proposition'
|
|
92
|
-
? {}
|
|
93
|
-
: { status: sentiment };
|
|
94
|
-
return (
|
|
95
|
-
<AvatarView
|
|
96
|
-
{...media.avatar}
|
|
97
|
-
badge={badge}
|
|
98
|
-
aria-label={media['aria-label']}
|
|
99
|
-
aria-hidden={media['aria-hidden']}
|
|
100
|
-
id={mediaId}
|
|
101
|
-
size={48}
|
|
102
|
-
>
|
|
103
|
-
{media.avatar.asset}
|
|
104
|
-
</AvatarView>
|
|
105
|
-
);
|
|
106
|
-
}
|
|
107
|
-
return sentiment === 'proposition' ? (
|
|
108
|
-
<AvatarView
|
|
109
|
-
id={mediaId}
|
|
110
|
-
size={48}
|
|
111
|
-
aria-label={media['aria-label']}
|
|
112
|
-
aria-hidden={media['aria-hidden']}
|
|
113
|
-
>
|
|
114
|
-
<GiftBox />
|
|
115
|
-
</AvatarView>
|
|
116
|
-
) : (
|
|
117
|
-
<StatusIcon
|
|
118
|
-
id={mediaId}
|
|
119
|
-
size={48}
|
|
120
|
-
sentiment={sentiment}
|
|
121
|
-
iconLabel={media['aria-hidden'] ? null : media['aria-label']}
|
|
122
|
-
/>
|
|
123
|
-
);
|
|
124
|
-
};
|
|
65
|
+
const renderMedia = () =>
|
|
66
|
+
renderPromptMedia({
|
|
67
|
+
media,
|
|
68
|
+
sentiment,
|
|
69
|
+
mediaId,
|
|
70
|
+
imgClassName: 'wds-action-prompt--media-image',
|
|
71
|
+
});
|
|
125
72
|
|
|
126
73
|
return (
|
|
127
74
|
<PrimitivePrompt
|