@transferwise/components 46.160.0 → 46.160.2
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/Calendar/Calendar.js +9 -3
- package/build/Calendar/Calendar.js.map +1 -1
- package/build/Calendar/Calendar.mjs +9 -3
- package/build/Calendar/Calendar.mjs.map +1 -1
- package/build/Carousel/Carousel.js +17 -10
- package/build/Carousel/Carousel.js.map +1 -1
- package/build/Carousel/Carousel.mjs +17 -10
- package/build/Carousel/Carousel.mjs.map +1 -1
- package/build/ExpressiveMoneyInput/Chevron/Chevron.js +10 -2
- package/build/ExpressiveMoneyInput/Chevron/Chevron.js.map +1 -1
- package/build/ExpressiveMoneyInput/Chevron/Chevron.mjs +11 -3
- package/build/ExpressiveMoneyInput/Chevron/Chevron.mjs.map +1 -1
- package/build/ProcessIndicator/ProcessIndicator.js +1 -1
- package/build/ProcessIndicator/ProcessIndicator.js.map +1 -1
- package/build/ProcessIndicator/ProcessIndicator.mjs +1 -1
- package/build/ProcessIndicator/ProcessIndicator.mjs.map +1 -1
- package/build/Prompt/CriticalBanner/CriticalBanner.js +10 -1
- package/build/Prompt/CriticalBanner/CriticalBanner.js.map +1 -1
- package/build/Prompt/CriticalBanner/CriticalBanner.mjs +10 -1
- package/build/Prompt/CriticalBanner/CriticalBanner.mjs.map +1 -1
- package/build/SegmentedControl/SegmentedControl.js +9 -2
- package/build/SegmentedControl/SegmentedControl.js.map +1 -1
- package/build/SegmentedControl/SegmentedControl.mjs +9 -2
- package/build/SegmentedControl/SegmentedControl.mjs.map +1 -1
- package/build/Tooltip/Tooltip.js +6 -1
- package/build/Tooltip/Tooltip.js.map +1 -1
- package/build/Tooltip/Tooltip.mjs +6 -1
- package/build/Tooltip/Tooltip.mjs.map +1 -1
- package/build/common/Panel/Panel.js +13 -25
- package/build/common/Panel/Panel.js.map +1 -1
- package/build/common/Panel/Panel.mjs +10 -22
- package/build/common/Panel/Panel.mjs.map +1 -1
- package/build/common/Panel/Panel.positionUtils.js +68 -0
- package/build/common/Panel/Panel.positionUtils.js.map +1 -0
- package/build/common/Panel/Panel.positionUtils.mjs +63 -0
- package/build/common/Panel/Panel.positionUtils.mjs.map +1 -0
- package/build/common/PropsValues/position.js +0 -25
- package/build/common/PropsValues/position.js.map +1 -1
- package/build/common/PropsValues/position.mjs +1 -24
- package/build/common/PropsValues/position.mjs.map +1 -1
- package/build/i18n/tr.json +5 -0
- package/build/i18n/tr.json.js +5 -0
- package/build/i18n/tr.json.js.map +1 -1
- package/build/i18n/tr.json.mjs +5 -0
- package/build/i18n/tr.json.mjs.map +1 -1
- package/build/i18n/zh-CN.json +5 -0
- package/build/i18n/zh-CN.json.js +5 -0
- package/build/i18n/zh-CN.json.js.map +1 -1
- package/build/i18n/zh-CN.json.mjs +5 -0
- package/build/i18n/zh-CN.json.mjs.map +1 -1
- package/build/main.css +134 -88
- package/build/styles/AvatarLayout/AvatarLayout.css +26 -9
- package/build/styles/AvatarView/AvatarView.css +8 -0
- package/build/styles/AvatarView/Dot/Dot.css +8 -0
- package/build/styles/CheckboxButton/CheckboxButton.css +3 -0
- package/build/styles/Nudge/Nudge.css +4 -38
- package/build/styles/Prompt/CriticalBanner/CriticalBanner.css +34 -0
- package/build/styles/SegmentedControl/SegmentedControl.css +2 -1
- package/build/styles/SlidingPanel/SlidingPanel.css +8 -0
- package/build/styles/Tooltip/Tooltip.css +0 -6
- package/build/styles/UploadInput/UploadItem/UploadItem.css +4 -5
- package/build/styles/_deprecated/Badge/Badge.css +4 -2
- package/build/styles/common/Panel/Panel.css +16 -8
- package/build/styles/css/accordion.css +3 -0
- package/build/styles/css/buttons.css +1 -7
- package/build/styles/css/chevron.css +3 -0
- package/build/styles/css/neptune.css +25 -19
- package/build/styles/css/process.css +15 -9
- package/build/styles/css/tick.css +6 -3
- package/build/styles/main.css +134 -88
- package/build/styles/styles/less/accordion.css +3 -0
- package/build/styles/styles/less/buttons.css +1 -7
- package/build/styles/styles/less/chevron.css +3 -0
- package/build/styles/styles/less/neptune.css +25 -19
- package/build/styles/styles/less/process.css +15 -9
- package/build/styles/styles/less/tick.css +6 -3
- package/build/types/Calendar/Calendar.d.ts.map +1 -1
- package/build/types/Carousel/Carousel.d.ts.map +1 -1
- package/build/types/Carousel/_stories/constants.d.ts +3 -0
- package/build/types/Carousel/_stories/constants.d.ts.map +1 -0
- package/build/types/ExpressiveMoneyInput/Chevron/Chevron.d.ts.map +1 -1
- package/build/types/Prompt/CriticalBanner/CriticalBanner.d.ts +6 -1
- package/build/types/Prompt/CriticalBanner/CriticalBanner.d.ts.map +1 -1
- package/build/types/SegmentedControl/SegmentedControl.d.ts.map +1 -1
- package/build/types/Tooltip/Tooltip.d.ts.map +1 -1
- package/build/types/common/Panel/Panel.d.ts +1 -1
- package/build/types/common/Panel/Panel.d.ts.map +1 -1
- package/build/types/common/Panel/Panel.positionUtils.d.ts +7 -0
- package/build/types/common/Panel/Panel.positionUtils.d.ts.map +1 -0
- package/build/types/common/PropsValues/position.d.ts +0 -13
- package/build/types/common/PropsValues/position.d.ts.map +1 -1
- package/build/types/common/ResponsivePanel/ResponsivePanel.d.ts +1 -1
- package/package.json +8 -8
- package/src/AvatarLayout/AvatarLayout.css +26 -9
- package/src/AvatarLayout/AvatarLayout.less +46 -22
- package/src/AvatarLayout/_stories/AvatarLayout.test.story.tsx +17 -42
- package/src/AvatarView/AvatarView.css +8 -0
- package/src/AvatarView/Dot/Dot.css +8 -0
- package/src/AvatarView/Dot/Dot.less +7 -1
- package/src/Button/_stories/Button.test.story.tsx +1 -1
- package/src/Calendar/Calendar.test.tsx +82 -0
- package/src/Calendar/Calendar.tsx +6 -3
- package/src/Carousel/Carousel.test.tsx +50 -2
- package/src/Carousel/Carousel.tsx +13 -10
- package/src/Carousel/_stories/Carousel.story.tsx +12 -52
- package/src/Carousel/_stories/Carousel.test.story.tsx +7 -43
- package/src/Carousel/_stories/constants.tsx +46 -0
- package/src/Checkbox/_stories/Checkbox.story.tsx +1 -1
- package/src/Checkbox/_stories/Checkbox.test.story.tsx +3 -2
- package/src/CheckboxButton/CheckboxButton.css +3 -0
- package/src/CheckboxButton/CheckboxButton.less +4 -0
- package/src/Chevron/_stories/Chevron.test.story.tsx +2 -2
- package/src/DateLookup/_stories/DateLookup.rtl.test.story.tsx +59 -48
- package/src/ExpressiveMoneyInput/Chevron/Chevron.tsx +8 -3
- package/src/Field/_stories/Field.test.story.tsx +48 -37
- package/src/FlowNavigation/_stories/FlowNavigation.rtl.test.story.tsx +78 -0
- package/src/FlowNavigation/_stories/FlowNavigation.test.story.tsx +0 -44
- package/src/Header/_stories/Header.test.story.tsx +1 -1
- package/src/Info/_stories/Info.rtl.test.story.tsx +35 -10
- package/src/Info/_stories/Info.story.tsx +1 -1
- package/src/Inputs/SelectInput/_stories/SelectInput.test.story.tsx +1 -1
- package/src/Label/_stories/Label.test.story.tsx +35 -22
- package/src/ListItem/_stories/subcomponents.tsx +1 -1
- package/src/Loader/_stories/Loader.test.story.tsx +23 -0
- package/src/MoneyInput/_stories/MoneyInput.rtl.test.story.tsx +1 -1
- package/src/Nudge/Nudge.css +4 -38
- package/src/Nudge/Nudge.less +4 -4
- package/src/Nudge/_stories/Nudge.test.story.tsx +29 -12
- package/src/PhoneNumberInput/_stories/{PhoneNumberInput.test.story.tsx → PhoneNumberInput.rtl.test.story.tsx} +18 -10
- package/src/Popover/_stories/Popover.rtl.test.story.tsx +40 -50
- package/src/ProcessIndicator/ProcessIndicator.tsx +1 -1
- package/src/ProcessIndicator/_stories/ProcessIndicator.test.story.tsx +32 -0
- package/src/ProgressBar/_stories/ProgressBar.test.story.tsx +33 -19
- package/src/Prompt/CriticalBanner/CriticalBanner.css +34 -0
- package/src/Prompt/CriticalBanner/CriticalBanner.less +45 -0
- package/src/Prompt/CriticalBanner/CriticalBanner.test.tsx +26 -3
- package/src/Prompt/CriticalBanner/CriticalBanner.tsx +15 -1
- package/src/Prompt/CriticalBanner/_stories/CriticalBanner.accessibility.docs.mdx +4 -1
- package/src/Prompt/CriticalBanner/_stories/CriticalBanner.story.tsx +52 -0
- package/src/Prompt/CriticalBanner/_stories/CriticalBanner.test.story.tsx +22 -1
- package/src/SegmentedControl/SegmentedControl.css +2 -1
- package/src/SegmentedControl/SegmentedControl.less +4 -2
- package/src/SegmentedControl/SegmentedControl.tsx +8 -2
- package/src/SegmentedControl/_stories/SegmentedControl.test.story.tsx +16 -8
- package/src/SlidingPanel/SlidingPanel.css +8 -0
- package/src/SlidingPanel/SlidingPanel.less +8 -0
- package/src/SlidingPanel/_stories/SlidingPanel.rtl.test.story.tsx +4 -3
- package/src/Snackbar/_stories/Snackbar.rtl.test.story.tsx +14 -16
- package/src/Snackbar/_stories/Snackbar.story.tsx +1 -1
- package/src/Snackbar/_stories/Snackbar.test.story.tsx +1 -1
- package/src/StatusIcon/_stories/StatusIcon.test.story.tsx +12 -4
- package/src/Tooltip/Tooltip.css +0 -6
- package/src/Tooltip/Tooltip.less +0 -12
- package/src/Tooltip/Tooltip.test.tsx +51 -0
- package/src/Tooltip/Tooltip.tsx +11 -1
- package/src/Tooltip/_stories/Tooltip.rtl.test.story.tsx +16 -34
- package/src/UploadInput/UploadItem/UploadItem.css +4 -5
- package/src/UploadInput/UploadItem/UploadItem.less +7 -6
- package/src/UploadInput/_stories/UploadInput.test.story.tsx +1 -1
- package/src/_deprecated/Badge/Badge.css +4 -2
- package/src/_deprecated/Badge/Badge.less +7 -14
- package/src/_deprecated/CriticalBanner/_stories/CriticalCommsBanner.test.story.tsx +0 -16
- package/src/_deprecated/OverlayHeader/_stories/OverlayHeader.test.story.tsx +15 -0
- package/src/common/Panel/Panel.css +16 -8
- package/src/common/Panel/Panel.less +31 -13
- package/src/common/Panel/Panel.positionUtils.ts +79 -0
- package/src/common/Panel/Panel.test.tsx +40 -0
- package/src/common/Panel/Panel.tsx +13 -24
- package/src/common/Panel/_stories/Panel.rtl.test.story.tsx +110 -0
- package/src/common/PropsValues/position.ts +0 -50
- package/src/i18n/tr.json +5 -0
- package/src/i18n/zh-CN.json +5 -0
- package/src/main.css +134 -88
- package/src/styles/less/accordion.css +3 -0
- package/src/styles/less/buttons.css +1 -7
- package/src/styles/less/buttons.less +3 -11
- package/src/styles/less/chevron.css +3 -0
- package/src/styles/less/chevron.less +4 -0
- package/src/styles/less/neptune.css +25 -19
- package/src/styles/less/process.css +15 -9
- package/src/styles/less/process.less +13 -6
- package/src/styles/less/tick.css +6 -3
- package/src/styles/less/tick.less +7 -3
|
@@ -28,6 +28,7 @@ const meta = {
|
|
|
28
28
|
action: { label: 'Verify now', onClick: fn() },
|
|
29
29
|
actionSecondary: undefined,
|
|
30
30
|
media: undefined,
|
|
31
|
+
animateEntry: true,
|
|
31
32
|
id: undefined,
|
|
32
33
|
className: undefined,
|
|
33
34
|
'data-testid': undefined,
|
|
@@ -47,6 +48,7 @@ const meta = {
|
|
|
47
48
|
table: { type: { summary: 'ReactNode' } },
|
|
48
49
|
},
|
|
49
50
|
expanded: { control: 'boolean' },
|
|
51
|
+
animateEntry: { control: 'boolean' },
|
|
50
52
|
media: {
|
|
51
53
|
control: false,
|
|
52
54
|
description: 'Replaces the default Status Icon with a custom image or AvatarView.',
|
|
@@ -131,12 +133,28 @@ const hiddenArgTypes = {
|
|
|
131
133
|
actionSecondary: { table: { disable: true } },
|
|
132
134
|
media: { table: { disable: true } },
|
|
133
135
|
expanded: { table: { disable: true } },
|
|
136
|
+
animateEntry: { table: { disable: true } },
|
|
134
137
|
onToggle: { table: { disable: true } },
|
|
135
138
|
id: { table: { disable: true } },
|
|
136
139
|
className: { table: { disable: true } },
|
|
137
140
|
'data-testid': { table: { disable: true } },
|
|
138
141
|
} as const;
|
|
139
142
|
|
|
143
|
+
const AnimatedEntryPreview = (args: CriticalBannerProps) => {
|
|
144
|
+
const [bannerInstance, setBannerInstance] = useState(0);
|
|
145
|
+
|
|
146
|
+
return (
|
|
147
|
+
<>
|
|
148
|
+
<CriticalBanner key={bannerInstance} {...args} />
|
|
149
|
+
<div className="p-t-3">
|
|
150
|
+
<Button block v2 onClick={() => setBannerInstance((current) => current + 1)}>
|
|
151
|
+
Replay
|
|
152
|
+
</Button>
|
|
153
|
+
</div>
|
|
154
|
+
</>
|
|
155
|
+
);
|
|
156
|
+
};
|
|
157
|
+
|
|
140
158
|
/** Renders children inside an iframe that inherits the parent page's stylesheets. */
|
|
141
159
|
function IframeContainer({ width, children }: { width: number; children: ReactNode }) {
|
|
142
160
|
const iframeRef = useRef<HTMLIFrameElement>(null);
|
|
@@ -585,6 +603,40 @@ export const MobileOverhang: Story = {
|
|
|
585
603
|
},
|
|
586
604
|
};
|
|
587
605
|
|
|
606
|
+
/** The banner waits 500ms, then reveals from above when it enters the page. */
|
|
607
|
+
export const AnimatedEntry: Story = {
|
|
608
|
+
args: {
|
|
609
|
+
title: 'Your account is restricted.',
|
|
610
|
+
description: 'Review your personal details to get your account active again.',
|
|
611
|
+
action: { label: 'Review details', onClick: fn() },
|
|
612
|
+
},
|
|
613
|
+
argTypes: hiddenArgTypes,
|
|
614
|
+
render: (args) => <AnimatedEntryPreview {...args} />,
|
|
615
|
+
parameters: {
|
|
616
|
+
layout: 'fullscreen',
|
|
617
|
+
docs: {
|
|
618
|
+
canvas: { sourceState: 'hidden' },
|
|
619
|
+
},
|
|
620
|
+
},
|
|
621
|
+
};
|
|
622
|
+
|
|
623
|
+
/** The banner can mount immediately without replaying its entry animation. */
|
|
624
|
+
export const WithoutEntryAnimation: Story = {
|
|
625
|
+
args: {
|
|
626
|
+
animateEntry: false,
|
|
627
|
+
title: 'Your account is restricted.',
|
|
628
|
+
description: 'Review your personal details to get your account active again.',
|
|
629
|
+
action: { label: 'Review details', onClick: fn() },
|
|
630
|
+
},
|
|
631
|
+
argTypes: hiddenArgTypes,
|
|
632
|
+
parameters: {
|
|
633
|
+
layout: 'fullscreen',
|
|
634
|
+
docs: {
|
|
635
|
+
canvas: { sourceState: 'hidden' },
|
|
636
|
+
},
|
|
637
|
+
},
|
|
638
|
+
};
|
|
639
|
+
|
|
588
640
|
/**
|
|
589
641
|
* The text container is capped at 480px for optimal readability, even though
|
|
590
642
|
* the banner itself stretches to the full available width.
|
|
@@ -22,6 +22,7 @@ const wait = async (ms: number) =>
|
|
|
22
22
|
});
|
|
23
23
|
|
|
24
24
|
const ANIMATION_DURATION = 200; // 150ms animation + 50ms buffer
|
|
25
|
+
const ENTRY_ANIMATION_DURATION = 950; // 500ms delay + 400ms animation + 50ms buffer
|
|
25
26
|
|
|
26
27
|
const longDescription =
|
|
27
28
|
'We have detected unusual activity on your account that does not match your typical usage patterns. To protect your funds and personal information, we have temporarily restricted access. Please verify your identity to restore full access to your account.';
|
|
@@ -151,7 +152,7 @@ export const MobileVariants: Story = {
|
|
|
151
152
|
...withVariantConfig(['mobile']),
|
|
152
153
|
};
|
|
153
154
|
|
|
154
|
-
/** Neutral background regression test with page content scrolled under the
|
|
155
|
+
/** Neutral background regression test with page content scrolled under the sticky banner. */
|
|
155
156
|
export const BackgroundIsNotTransparent: Story = {
|
|
156
157
|
args: {
|
|
157
158
|
sentiment: 'neutral',
|
|
@@ -198,6 +199,7 @@ export const BackgroundIsNotTransparent: Story = {
|
|
|
198
199
|
|
|
199
200
|
if (scrollContainer) {
|
|
200
201
|
scrollContainer.scrollTop = 250;
|
|
202
|
+
await wait(ENTRY_ANIMATION_DURATION);
|
|
201
203
|
}
|
|
202
204
|
},
|
|
203
205
|
...withVariantConfig(['mobile'], {
|
|
@@ -207,6 +209,25 @@ export const BackgroundIsNotTransparent: Story = {
|
|
|
207
209
|
}),
|
|
208
210
|
};
|
|
209
211
|
|
|
212
|
+
/** Mobile entry animation visual regression test. */
|
|
213
|
+
export const AnimatedEntryMobile: Story = {
|
|
214
|
+
render: function Render() {
|
|
215
|
+
return (
|
|
216
|
+
<CriticalBanner
|
|
217
|
+
sentiment="negative"
|
|
218
|
+
title="Your account is restricted."
|
|
219
|
+
description="Review your personal details to get your account active again."
|
|
220
|
+
action={{ label: 'Review details', onClick: fn() }}
|
|
221
|
+
/>
|
|
222
|
+
);
|
|
223
|
+
},
|
|
224
|
+
...withVariantConfig(['mobile'], {
|
|
225
|
+
parameters: {
|
|
226
|
+
chromatic: { pauseAnimationAtEnd: true },
|
|
227
|
+
},
|
|
228
|
+
}),
|
|
229
|
+
};
|
|
230
|
+
|
|
210
231
|
/**
|
|
211
232
|
* Tests keyboard navigation and interaction:
|
|
212
233
|
* - Tab focuses the first chevron toggle button
|
|
@@ -35,7 +35,8 @@
|
|
|
35
35
|
background: var(--color-background-screen);
|
|
36
36
|
border-radius: 24px;
|
|
37
37
|
border-radius: var(--size-24);
|
|
38
|
-
transition: left 300ms
|
|
38
|
+
transition: left 300ms,
|
|
39
|
+
right 300ms;
|
|
39
40
|
}
|
|
40
41
|
.segmented-control__segments--no-animate::after {
|
|
41
42
|
transition: none !important;
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
justify-content: center;
|
|
13
13
|
align-items: center;
|
|
14
14
|
background: var(--color-background-neutral);
|
|
15
|
-
border-radius: var(--size-24);
|
|
15
|
+
border-radius: var(--size-24);
|
|
16
16
|
transition: outline 300ms;
|
|
17
17
|
outline: 2px solid transparent;
|
|
18
18
|
}
|
|
@@ -31,7 +31,9 @@
|
|
|
31
31
|
z-index: 0;
|
|
32
32
|
background: var(--color-background-screen);
|
|
33
33
|
border-radius: var(--size-24);
|
|
34
|
-
transition:
|
|
34
|
+
transition:
|
|
35
|
+
left 300ms,
|
|
36
|
+
right 300ms;
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
.segmented-control__segments--no-animate::after {
|
|
@@ -3,6 +3,7 @@ import { createRef, useEffect, useRef, useState } from 'react';
|
|
|
3
3
|
|
|
4
4
|
import Body from '../Body';
|
|
5
5
|
import { Typography } from '../common';
|
|
6
|
+
import { useDirection } from '../common/hooks';
|
|
6
7
|
|
|
7
8
|
type SegmentBase = { id: string; label: string; value: string };
|
|
8
9
|
|
|
@@ -40,6 +41,7 @@ const SegmentedControl = ({
|
|
|
40
41
|
}: SegmentedControlProps) => {
|
|
41
42
|
const isMountedRef = useRef(false);
|
|
42
43
|
const [animate, setAnimate] = useState(false);
|
|
44
|
+
const { isRTL } = useDirection();
|
|
43
45
|
|
|
44
46
|
const segmentsRef = useRef<HTMLDivElement>(null);
|
|
45
47
|
|
|
@@ -62,8 +64,12 @@ const SegmentedControl = ({
|
|
|
62
64
|
// This is so we can animate the highlight to the selected segment
|
|
63
65
|
if (selectedSegmentRef?.current && segmentsRef.current) {
|
|
64
66
|
const { style } = segmentsRef.current;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
+
const segment = selectedSegmentRef.current;
|
|
68
|
+
const inlineOffset = isRTL
|
|
69
|
+
? segmentsRef.current.offsetWidth - segment.offsetLeft - segment.offsetWidth
|
|
70
|
+
: segment.offsetLeft;
|
|
71
|
+
style.setProperty('--segment-highlight-width', `${segment.offsetWidth}px`);
|
|
72
|
+
style.setProperty('--segment-highlight-x', `${inlineOffset}px`);
|
|
67
73
|
}
|
|
68
74
|
};
|
|
69
75
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
1
2
|
import type { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
2
3
|
import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
|
|
3
4
|
import SegmentedControl from '../SegmentedControl';
|
|
@@ -22,24 +23,31 @@ const viewSegments = [
|
|
|
22
23
|
{ id: 'seg-gamma', label: 'Gamma', value: 'gamma', controls: 'panel-gamma' },
|
|
23
24
|
] as const;
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
function InteractiveSegmentedControl() {
|
|
27
|
+
const [inputValue, setInputValue] = useState('one');
|
|
28
|
+
const [viewValue, setViewValue] = useState('beta');
|
|
29
|
+
|
|
30
|
+
return (
|
|
27
31
|
<>
|
|
28
32
|
<SegmentedControl
|
|
29
33
|
name="rtl-input"
|
|
30
34
|
mode="input"
|
|
31
35
|
segments={inputSegments}
|
|
32
|
-
value=
|
|
33
|
-
onChange={
|
|
36
|
+
value={inputValue}
|
|
37
|
+
onChange={setInputValue}
|
|
34
38
|
/>
|
|
35
39
|
<SegmentedControl
|
|
36
40
|
name="rtl-view"
|
|
37
41
|
mode="view"
|
|
38
42
|
segments={viewSegments}
|
|
39
|
-
value=
|
|
40
|
-
onChange={
|
|
43
|
+
value={viewValue}
|
|
44
|
+
onChange={setViewValue}
|
|
41
45
|
/>
|
|
42
46
|
</>
|
|
43
|
-
)
|
|
44
|
-
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const RTLDiff: Story = {
|
|
51
|
+
render: () => <InteractiveSegmentedControl />,
|
|
52
|
+
...withRTLDiff({ width: 'stretch', renderAs: 'iframe' }),
|
|
45
53
|
};
|
|
@@ -73,6 +73,10 @@
|
|
|
73
73
|
box-shadow: inset 1px 0 0 0 rgba(0,0,0,0.10196);
|
|
74
74
|
box-shadow: inset 1px 0 0 0 var(--color-border-neutral);
|
|
75
75
|
}
|
|
76
|
+
[dir="rtl"] .np-theme-personal .sliding-panel.sliding-panel--border-right {
|
|
77
|
+
box-shadow: inset -1px 0 0 0 rgba(0,0,0,0.10196);
|
|
78
|
+
box-shadow: inset -1px 0 0 0 var(--color-border-neutral);
|
|
79
|
+
}
|
|
76
80
|
.np-theme-personal .sliding-panel.sliding-panel--border-bottom {
|
|
77
81
|
box-shadow: inset 0 1px 0 0 rgba(0,0,0,0.10196);
|
|
78
82
|
box-shadow: inset 0 1px 0 0 var(--color-border-neutral);
|
|
@@ -81,3 +85,7 @@
|
|
|
81
85
|
box-shadow: inset -1px 0 0 0 rgba(0,0,0,0.10196);
|
|
82
86
|
box-shadow: inset -1px 0 0 0 var(--color-border-neutral);
|
|
83
87
|
}
|
|
88
|
+
[dir="rtl"] .np-theme-personal .sliding-panel.sliding-panel--border-left {
|
|
89
|
+
box-shadow: inset 1px 0 0 0 rgba(0,0,0,0.10196);
|
|
90
|
+
box-shadow: inset 1px 0 0 0 var(--color-border-neutral);
|
|
91
|
+
}
|
|
@@ -85,6 +85,10 @@
|
|
|
85
85
|
|
|
86
86
|
&.sliding-panel--border-right {
|
|
87
87
|
box-shadow: inset 1px 0 0 0 var(--color-border-neutral);
|
|
88
|
+
|
|
89
|
+
[dir="rtl"] & {
|
|
90
|
+
box-shadow: inset -1px 0 0 0 var(--color-border-neutral);
|
|
91
|
+
}
|
|
88
92
|
}
|
|
89
93
|
|
|
90
94
|
&.sliding-panel--border-bottom {
|
|
@@ -93,6 +97,10 @@
|
|
|
93
97
|
|
|
94
98
|
&.sliding-panel--border-left {
|
|
95
99
|
box-shadow: inset -1px 0 0 0 var(--color-border-neutral);
|
|
100
|
+
|
|
101
|
+
[dir="rtl"] & {
|
|
102
|
+
box-shadow: inset 1px 0 0 0 var(--color-border-neutral);
|
|
103
|
+
}
|
|
96
104
|
}
|
|
97
105
|
}
|
|
98
106
|
}
|
|
@@ -11,14 +11,15 @@ export default {
|
|
|
11
11
|
|
|
12
12
|
type Story = StoryObj<typeof SlidingPanel>;
|
|
13
13
|
|
|
14
|
-
const iframeDiff = withRTLDiff({ renderAs: 'iframe' });
|
|
14
|
+
const iframeDiff = withRTLDiff({ renderAs: 'iframe', width: 'stretch' });
|
|
15
15
|
|
|
16
16
|
const containerStyle: React.CSSProperties = {
|
|
17
17
|
position: 'relative',
|
|
18
|
-
width:
|
|
18
|
+
width: '100%',
|
|
19
19
|
height: 120,
|
|
20
20
|
overflow: 'hidden',
|
|
21
|
-
border: '1px
|
|
21
|
+
border: '1px solid #f5f5f5',
|
|
22
|
+
background: '#f5f5f5',
|
|
22
23
|
};
|
|
23
24
|
|
|
24
25
|
const panelContentStyle: React.CSSProperties = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState } from 'react';
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
2
|
import type { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
3
3
|
|
|
4
4
|
import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
|
|
@@ -6,40 +6,38 @@ import { Snackbar } from '../Snackbar';
|
|
|
6
6
|
|
|
7
7
|
export default {
|
|
8
8
|
component: Snackbar,
|
|
9
|
-
title: '
|
|
9
|
+
title: 'Prompts/Snackbar/Tests/RTL Diff',
|
|
10
10
|
tags: ['!autodocs', '!manifest'],
|
|
11
11
|
} satisfies Meta<typeof Snackbar>;
|
|
12
12
|
|
|
13
13
|
type Story = StoryObj<typeof Snackbar>;
|
|
14
14
|
|
|
15
15
|
const TIMEOUT = 10_000_000;
|
|
16
|
-
const iframeDiff = withRTLDiff({ renderAs: 'iframe' });
|
|
17
16
|
|
|
18
|
-
function
|
|
19
|
-
const [timestamp] = useState(
|
|
17
|
+
function SnackbarStory({ action }: { action?: { label: string } }) {
|
|
18
|
+
const [timestamp, setTimestamp] = useState(0);
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
// eslint-disable-next-line react-hooks/set-state-in-effect
|
|
22
|
+
setTimestamp(1);
|
|
23
|
+
}, []);
|
|
20
24
|
|
|
21
25
|
return (
|
|
22
26
|
<Snackbar
|
|
23
27
|
text={<span>Transfer completed successfully</span>}
|
|
24
28
|
timestamp={timestamp}
|
|
25
29
|
timeout={TIMEOUT}
|
|
26
|
-
action={
|
|
30
|
+
action={action}
|
|
27
31
|
/>
|
|
28
32
|
);
|
|
29
33
|
}
|
|
30
34
|
|
|
31
|
-
function RenderWithoutAction() {
|
|
32
|
-
const [timestamp] = useState(() => Date.now());
|
|
33
|
-
|
|
34
|
-
return <Snackbar text={<span>Settings saved</span>} timestamp={timestamp} timeout={TIMEOUT} />;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
35
|
export const WithAction: Story = {
|
|
38
|
-
render: () => <
|
|
39
|
-
...
|
|
36
|
+
render: () => <SnackbarStory action={{ label: 'View' }} />,
|
|
37
|
+
...withRTLDiff({ renderAs: 'iframe' }),
|
|
40
38
|
};
|
|
41
39
|
|
|
42
40
|
export const WithoutAction: Story = {
|
|
43
|
-
render: () => <
|
|
44
|
-
...
|
|
41
|
+
render: () => <SnackbarStory />,
|
|
42
|
+
...withRTLDiff({ renderAs: 'iframe' }),
|
|
45
43
|
};
|
|
@@ -9,7 +9,7 @@ import { SnackbarConsumer } from '../SnackbarContext';
|
|
|
9
9
|
import SnackbarProvider from '../SnackbarProvider';
|
|
10
10
|
|
|
11
11
|
export default {
|
|
12
|
-
title: '
|
|
12
|
+
title: 'Prompts/Snackbar/Tests',
|
|
13
13
|
component: Snackbar,
|
|
14
14
|
argTypes: {},
|
|
15
15
|
tags: ['!autodocs', '!manifest'],
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
2
2
|
|
|
3
|
+
import { withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
|
|
3
4
|
import { Sentiment, Size } from '../../common';
|
|
4
5
|
import SentimentSurface from '../../SentimentSurface';
|
|
5
|
-
import { withVariantConfig } from '../../../.storybook/helpers';
|
|
6
6
|
|
|
7
7
|
import StatusIcon, { StatusIconSentiment } from '../StatusIcon';
|
|
8
8
|
|
|
@@ -90,9 +90,17 @@ export const Variants: Story = {
|
|
|
90
90
|
},
|
|
91
91
|
};
|
|
92
92
|
|
|
93
|
-
export const
|
|
94
|
-
render:
|
|
95
|
-
|
|
93
|
+
export const RTLDiff: Story = {
|
|
94
|
+
render: () => (
|
|
95
|
+
<>
|
|
96
|
+
<StatusIcon sentiment="positive" />
|
|
97
|
+
<StatusIcon sentiment="negative" />
|
|
98
|
+
<StatusIcon sentiment="warning" />
|
|
99
|
+
<StatusIcon sentiment="neutral" />
|
|
100
|
+
<StatusIcon sentiment="pending" />
|
|
101
|
+
</>
|
|
102
|
+
),
|
|
103
|
+
...withRTLDiff(),
|
|
96
104
|
};
|
|
97
105
|
|
|
98
106
|
/**
|
package/src/Tooltip/Tooltip.css
CHANGED
|
@@ -42,9 +42,3 @@
|
|
|
42
42
|
visibility: visible;
|
|
43
43
|
visibility: initial;
|
|
44
44
|
}
|
|
45
|
-
.np-panel[data-popper-placement^="right"] > .np-panel__content.tooltip-inner .np-panel__arrow {
|
|
46
|
-
inset-inline-start: -7px;
|
|
47
|
-
}
|
|
48
|
-
.np-panel[data-popper-placement^="left"] > .np-panel__content.tooltip-inner .np-panel__arrow {
|
|
49
|
-
inset-inline-end: -7px;
|
|
50
|
-
}
|
package/src/Tooltip/Tooltip.less
CHANGED
|
@@ -48,15 +48,3 @@
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
-
|
|
52
|
-
.np-panel[data-popper-placement^="right"] > .np-panel__content.tooltip-inner {
|
|
53
|
-
.np-panel__arrow {
|
|
54
|
-
left: -7px;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
.np-panel[data-popper-placement^="left"] > .np-panel__content.tooltip-inner {
|
|
59
|
-
.np-panel__arrow {
|
|
60
|
-
right: -7px;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { render, screen } from '@testing-library/react';
|
|
2
2
|
import { userEvent } from '@testing-library/user-event';
|
|
3
3
|
|
|
4
|
+
import { DirectionProvider } from '../Provider/Direction/DirectionProvider';
|
|
4
5
|
import Tooltip from '.';
|
|
5
6
|
|
|
6
7
|
describe('Tooltip Component', () => {
|
|
@@ -102,4 +103,54 @@ describe('Tooltip Component', () => {
|
|
|
102
103
|
const tooltipElement = screen.getByRole('tooltip', { hidden: true });
|
|
103
104
|
expect(tooltipElement).toBeVisible();
|
|
104
105
|
});
|
|
106
|
+
|
|
107
|
+
describe('RTL position mirroring', () => {
|
|
108
|
+
it('mirrors position="left" to right in RTL', async () => {
|
|
109
|
+
render(
|
|
110
|
+
<DirectionProvider direction="rtl">
|
|
111
|
+
<Tooltip label="Test Tooltip" position="left">
|
|
112
|
+
<span>Hover me</span>
|
|
113
|
+
</Tooltip>
|
|
114
|
+
</DirectionProvider>,
|
|
115
|
+
);
|
|
116
|
+
const triggerElement = screen.getByText('Hover me');
|
|
117
|
+
await userEvent.hover(triggerElement);
|
|
118
|
+
|
|
119
|
+
const tooltip = screen.getByRole('tooltip', { hidden: true });
|
|
120
|
+
expect(tooltip).toHaveAttribute('data-popper-placement', 'right');
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('mirrors position="right" to left in RTL', async () => {
|
|
124
|
+
render(
|
|
125
|
+
<DirectionProvider direction="rtl">
|
|
126
|
+
<Tooltip label="Test Tooltip" position="right">
|
|
127
|
+
<span>Hover me</span>
|
|
128
|
+
</Tooltip>
|
|
129
|
+
</DirectionProvider>,
|
|
130
|
+
);
|
|
131
|
+
const triggerElement = screen.getByText('Hover me');
|
|
132
|
+
await userEvent.hover(triggerElement);
|
|
133
|
+
|
|
134
|
+
const tooltip = screen.getByRole('tooltip', { hidden: true });
|
|
135
|
+
expect(tooltip).toHaveAttribute('data-popper-placement', 'left');
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it.each(['top', 'bottom'] as const)(
|
|
139
|
+
'does not mirror position="%s" in RTL',
|
|
140
|
+
async (position) => {
|
|
141
|
+
render(
|
|
142
|
+
<DirectionProvider direction="rtl">
|
|
143
|
+
<Tooltip label="Test Tooltip" position={position}>
|
|
144
|
+
<span>Hover me</span>
|
|
145
|
+
</Tooltip>
|
|
146
|
+
</DirectionProvider>,
|
|
147
|
+
);
|
|
148
|
+
const triggerElement = screen.getByText('Hover me');
|
|
149
|
+
await userEvent.hover(triggerElement);
|
|
150
|
+
|
|
151
|
+
const tooltip = screen.getByRole('tooltip', { hidden: true });
|
|
152
|
+
expect(tooltip).toHaveAttribute('data-popper-placement', position);
|
|
153
|
+
},
|
|
154
|
+
);
|
|
155
|
+
});
|
|
105
156
|
});
|
package/src/Tooltip/Tooltip.tsx
CHANGED
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
} from 'react';
|
|
20
20
|
|
|
21
21
|
import { CommonProps, Position } from '../common';
|
|
22
|
+
import useDirection from '../common/hooks/useDirection';
|
|
22
23
|
import {
|
|
23
24
|
PositionBottom,
|
|
24
25
|
PositionLeft,
|
|
@@ -42,12 +43,21 @@ const Tooltip = ({
|
|
|
42
43
|
}: TooltipProps) => {
|
|
43
44
|
const [open, setOpen] = useState(false);
|
|
44
45
|
const arrowRef = useRef<HTMLDivElement | null>(null);
|
|
46
|
+
const { isRTL } = useDirection();
|
|
47
|
+
|
|
48
|
+
const resolvedPosition = isRTL
|
|
49
|
+
? position === 'left'
|
|
50
|
+
? 'right'
|
|
51
|
+
: position === 'right'
|
|
52
|
+
? 'left'
|
|
53
|
+
: position
|
|
54
|
+
: position;
|
|
45
55
|
|
|
46
56
|
const fallbackId = useId();
|
|
47
57
|
const tooltipId = id ?? fallbackId;
|
|
48
58
|
|
|
49
59
|
const { refs, floatingStyles, placement, middlewareData } = useFloating({
|
|
50
|
-
placement:
|
|
60
|
+
placement: resolvedPosition,
|
|
51
61
|
middleware: [
|
|
52
62
|
offset(16),
|
|
53
63
|
flip({ fallbackPlacements: [Position.TOP] }),
|
|
@@ -13,16 +13,6 @@ export default {
|
|
|
13
13
|
|
|
14
14
|
type Story = StoryObj<typeof Tooltip>;
|
|
15
15
|
|
|
16
|
-
const iframeDiff = withRTLDiff({ renderAs: 'iframe' });
|
|
17
|
-
|
|
18
|
-
const containerStyle: React.CSSProperties = {
|
|
19
|
-
display: 'flex',
|
|
20
|
-
justifyContent: 'center',
|
|
21
|
-
alignItems: 'center',
|
|
22
|
-
minHeight: '20rem',
|
|
23
|
-
width: '100%',
|
|
24
|
-
};
|
|
25
|
-
|
|
26
16
|
const hoverTrigger = async ({ canvasElement }: { canvasElement: HTMLElement }) => {
|
|
27
17
|
const canvas = within(canvasElement);
|
|
28
18
|
const button = canvas.queryByRole('button');
|
|
@@ -32,48 +22,40 @@ const hoverTrigger = async ({ canvasElement }: { canvasElement: HTMLElement }) =
|
|
|
32
22
|
|
|
33
23
|
export const PositionTop: Story = {
|
|
34
24
|
render: () => (
|
|
35
|
-
<
|
|
36
|
-
<
|
|
37
|
-
|
|
38
|
-
</Tooltip>
|
|
39
|
-
</div>
|
|
25
|
+
<Tooltip label="Top positioned tooltip" position="top">
|
|
26
|
+
<Button>Top</Button>
|
|
27
|
+
</Tooltip>
|
|
40
28
|
),
|
|
41
29
|
play: hoverTrigger,
|
|
42
|
-
...
|
|
30
|
+
...withRTLDiff({ renderAs: 'iframe', hAlign: 'center', vAlign: 'bottom' }),
|
|
43
31
|
};
|
|
44
32
|
|
|
45
33
|
export const PositionBottom: Story = {
|
|
46
34
|
render: () => (
|
|
47
|
-
<
|
|
48
|
-
<
|
|
49
|
-
|
|
50
|
-
</Tooltip>
|
|
51
|
-
</div>
|
|
35
|
+
<Tooltip label="Bottom positioned tooltip" position="bottom">
|
|
36
|
+
<Button>Bottom</Button>
|
|
37
|
+
</Tooltip>
|
|
52
38
|
),
|
|
53
39
|
play: hoverTrigger,
|
|
54
|
-
...
|
|
40
|
+
...withRTLDiff({ renderAs: 'iframe', hAlign: 'center' }),
|
|
55
41
|
};
|
|
56
42
|
|
|
57
43
|
export const PositionRight: Story = {
|
|
58
44
|
render: () => (
|
|
59
|
-
<
|
|
60
|
-
<
|
|
61
|
-
|
|
62
|
-
</Tooltip>
|
|
63
|
-
</div>
|
|
45
|
+
<Tooltip label="Right positioned tooltip" position="right">
|
|
46
|
+
<Button>Right</Button>
|
|
47
|
+
</Tooltip>
|
|
64
48
|
),
|
|
65
49
|
play: hoverTrigger,
|
|
66
|
-
...
|
|
50
|
+
...withRTLDiff({ renderAs: 'iframe', hAlign: 'left', vAlign: 'center' }),
|
|
67
51
|
};
|
|
68
52
|
|
|
69
53
|
export const PositionLeft: Story = {
|
|
70
54
|
render: () => (
|
|
71
|
-
<
|
|
72
|
-
<
|
|
73
|
-
|
|
74
|
-
</Tooltip>
|
|
75
|
-
</div>
|
|
55
|
+
<Tooltip label="Left positioned tooltip" position="left">
|
|
56
|
+
<Button>Left</Button>
|
|
57
|
+
</Tooltip>
|
|
76
58
|
),
|
|
77
59
|
play: hoverTrigger,
|
|
78
|
-
...
|
|
60
|
+
...withRTLDiff({ renderAs: 'iframe', hAlign: 'right', vAlign: 'center' }),
|
|
79
61
|
};
|
|
@@ -41,8 +41,7 @@
|
|
|
41
41
|
.np-upload-input__item .np-upload-input__title,
|
|
42
42
|
.np-upload-input__item .np-upload-input__text {
|
|
43
43
|
margin: 0;
|
|
44
|
-
|
|
45
|
-
text-align-last: left;
|
|
44
|
+
text-align: start;
|
|
46
45
|
color: #5d7079;
|
|
47
46
|
color: var(--color-content-secondary);
|
|
48
47
|
}
|
|
@@ -98,7 +97,7 @@
|
|
|
98
97
|
justify-content: center;
|
|
99
98
|
}
|
|
100
99
|
.np-upload-input__item .np-upload-input__item-action .np-upload-input__item-button:before {
|
|
101
|
-
content:
|
|
100
|
+
content: "";
|
|
102
101
|
display: block;
|
|
103
102
|
inline-size: var(--clickAreaSize);
|
|
104
103
|
block-size: var(--clickAreaSize);
|
|
@@ -153,8 +152,8 @@
|
|
|
153
152
|
padding-inline-start: var(--size-16);
|
|
154
153
|
}
|
|
155
154
|
.np-upload-input__item .np-upload-input-errors > li::before {
|
|
156
|
-
content:
|
|
157
|
-
content:
|
|
155
|
+
content: "•" ;
|
|
156
|
+
content: "•" / "";
|
|
158
157
|
position: absolute;
|
|
159
158
|
display: block;
|
|
160
159
|
inset-inline-start: 0;
|