@transferwise/components 0.0.0-experimental-58e9ef8 → 0.0.0-experimental-791acf3
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/preventScroll/PreventScroll.js +1 -8
- package/build/common/preventScroll/PreventScroll.js.map +1 -1
- package/build/common/preventScroll/PreventScroll.mjs +1 -8
- package/build/common/preventScroll/PreventScroll.mjs.map +1 -1
- package/build/inputs/SelectInput.js +40 -12
- package/build/inputs/SelectInput.js.map +1 -1
- package/build/inputs/SelectInput.mjs +40 -12
- package/build/inputs/SelectInput.mjs.map +1 -1
- package/build/inputs/_BottomSheet.js +1 -29
- package/build/inputs/_BottomSheet.js.map +1 -1
- package/build/inputs/_BottomSheet.mjs +2 -30
- package/build/inputs/_BottomSheet.mjs.map +1 -1
- package/build/main.css +9 -13
- package/build/slidingPanel/SlidingPanel.js +20 -23
- package/build/slidingPanel/SlidingPanel.js.map +1 -1
- package/build/slidingPanel/SlidingPanel.mjs +21 -24
- package/build/slidingPanel/SlidingPanel.mjs.map +1 -1
- package/build/styles/dimmer/Dimmer.css +0 -1
- package/build/styles/inputs/SelectInput.css +9 -12
- package/build/styles/main.css +9 -13
- package/build/types/common/preventScroll/PreventScroll.d.ts +1 -1
- package/build/types/common/preventScroll/PreventScroll.d.ts.map +1 -1
- package/build/types/inputs/SelectInput.d.ts.map +1 -1
- package/build/types/inputs/_BottomSheet.d.ts.map +1 -1
- package/build/types/slidingPanel/SlidingPanel.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/common/bottomSheet/__snapshots__/BottomSheet.test.tsx.snap +0 -6
- package/src/common/preventScroll/PreventScroll.tsx +1 -11
- package/src/dimmer/Dimmer.css +0 -1
- package/src/dimmer/Dimmer.less +0 -1
- package/src/inputs/SelectInput.css +9 -12
- package/src/inputs/SelectInput.story.tsx +4735 -21
- package/src/inputs/SelectInput.tsx +45 -15
- package/src/inputs/_BottomSheet.less +6 -12
- package/src/inputs/_BottomSheet.tsx +5 -19
- package/src/main.css +9 -13
- package/src/slidingPanel/SlidingPanel.tsx +24 -29
- package/src/common/bottomSheet/BottomSheet.test.story.tsx +0 -94
- package/src/inputs/SelectInput.test.story.tsx +0 -83
- package/src/moneyInput/MoneyInput.test.story.tsx +0 -101
|
@@ -741,15 +741,35 @@ function SelectInputOptions<T = string>({
|
|
|
741
741
|
return items;
|
|
742
742
|
}
|
|
743
743
|
|
|
744
|
-
const
|
|
745
|
-
selectInputOptionItemIncludesNeedle(item, needle),
|
|
746
|
-
);
|
|
744
|
+
const dedupedItems = dedupeSelectInputItems(items, compareValues);
|
|
747
745
|
|
|
748
746
|
if (sortFilteredOptions) {
|
|
747
|
+
// When sorting, filter out non-matching items completely to avoid ghost items
|
|
748
|
+
const filtered = dedupedItems.map((item) => {
|
|
749
|
+
if (item.type === 'option') {
|
|
750
|
+
return selectInputOptionItemIncludesNeedle(item, needle)
|
|
751
|
+
? item
|
|
752
|
+
: { ...item, value: undefined };
|
|
753
|
+
}
|
|
754
|
+
if (item.type === 'group') {
|
|
755
|
+
return {
|
|
756
|
+
...item,
|
|
757
|
+
options: item.options.map((option) =>
|
|
758
|
+
selectInputOptionItemIncludesNeedle(option, needle)
|
|
759
|
+
? option
|
|
760
|
+
: { ...option, value: undefined },
|
|
761
|
+
),
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
return item;
|
|
765
|
+
});
|
|
766
|
+
|
|
749
767
|
return sortSelectInputItems(filtered, sortFilteredOptions, filterQuery);
|
|
750
768
|
}
|
|
751
769
|
|
|
752
|
-
return
|
|
770
|
+
return filterSelectInputItems(dedupedItems, (item) =>
|
|
771
|
+
selectInputOptionItemIncludesNeedle(item, needle),
|
|
772
|
+
);
|
|
753
773
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
754
774
|
}, [needle, items, compareValues]);
|
|
755
775
|
const resultsEmpty = needle != null && filteredItems.length === 0;
|
|
@@ -760,17 +780,28 @@ function SelectInputOptions<T = string>({
|
|
|
760
780
|
// the scroll position may jump around inadvertently. Pattern adopted from:
|
|
761
781
|
// https://inokawa.github.io/virtua/?path=/story/advanced-keep-offscreen-items--append-only
|
|
762
782
|
const [mountedIndexes, setMountedIndexes] = useState<number[]>([]);
|
|
783
|
+
|
|
784
|
+
// Track if this is the initial render after a search change
|
|
785
|
+
const isInitialSearchRender = useRef(true);
|
|
786
|
+
|
|
763
787
|
useEffect(() => {
|
|
764
|
-
//
|
|
765
|
-
setMountedIndexes(
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
filteredItems.length
|
|
773
|
-
|
|
788
|
+
// Reset mounted indexes and flag when search changes
|
|
789
|
+
setMountedIndexes([]);
|
|
790
|
+
isInitialSearchRender.current = true;
|
|
791
|
+
}, [needle]);
|
|
792
|
+
|
|
793
|
+
useEffect(() => {
|
|
794
|
+
// Only add the last item to mountedIndexes after the initial render
|
|
795
|
+
// This prevents auto-scrolling on search while still supporting the 'End' key
|
|
796
|
+
if (!isInitialSearchRender.current && filteredItems.length > 0) {
|
|
797
|
+
setMountedIndexes((prevMountedIndexes) => {
|
|
798
|
+
const indexes = new Set(prevMountedIndexes);
|
|
799
|
+
indexes.add(filteredItems.length - 1);
|
|
800
|
+
return [...indexes]; // Sorting is redundant by nature here
|
|
801
|
+
});
|
|
802
|
+
}
|
|
803
|
+
isInitialSearchRender.current = false;
|
|
804
|
+
}, [filteredItems.length]);
|
|
774
805
|
|
|
775
806
|
const listboxContainerRef = useRef<HTMLDivElement>(null);
|
|
776
807
|
useEffect(() => {
|
|
@@ -927,7 +958,6 @@ function SelectInputOptions<T = string>({
|
|
|
927
958
|
) : (
|
|
928
959
|
<Virtualizer
|
|
929
960
|
ref={virtualiserHandlerRef}
|
|
930
|
-
key={needle}
|
|
931
961
|
data={filteredItems}
|
|
932
962
|
keepMounted={mountedIndexes}
|
|
933
963
|
scrollRef={listboxRef} // `VList` doesn't expose this
|
|
@@ -11,8 +11,6 @@
|
|
|
11
11
|
transition-property: opacity;
|
|
12
12
|
transition-timing-function: ease-out;
|
|
13
13
|
transition-duration: 300ms;
|
|
14
|
-
height: 100vh;
|
|
15
|
-
min-height: -webkit-fill-available;
|
|
16
14
|
|
|
17
15
|
&--closed {
|
|
18
16
|
opacity: 0;
|
|
@@ -21,28 +19,24 @@
|
|
|
21
19
|
|
|
22
20
|
.np-bottom-sheet-v2 {
|
|
23
21
|
position: fixed;
|
|
24
|
-
inset:
|
|
22
|
+
inset: 0px;
|
|
25
23
|
bottom: env(keyboard-inset-height, 0px);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
padding-bottom: min(env(safe-area-inset-bottom, var(--size-16)));
|
|
24
|
+
margin-left: var(--size-8);
|
|
25
|
+
margin-right: var(--size-8);
|
|
26
|
+
margin-top: var(--size-64);
|
|
30
27
|
display: flex;
|
|
31
28
|
flex-direction: column;
|
|
32
29
|
justify-content: flex-end;
|
|
33
|
-
height: 100%;
|
|
34
|
-
min-height: -webkit-fill-available;
|
|
35
30
|
}
|
|
36
31
|
|
|
37
32
|
.np-bottom-sheet-v2-content {
|
|
38
33
|
display: flex;
|
|
39
34
|
flex-direction: column;
|
|
40
35
|
overflow: auto;
|
|
41
|
-
border-top-left-radius:
|
|
42
|
-
border-top-right-radius:
|
|
36
|
+
border-top-left-radius: 32px; /* TODO: Tokenize */
|
|
37
|
+
border-top-right-radius: 32px; /* TODO: Tokenize */
|
|
43
38
|
background-color: var(--color-background-elevated);
|
|
44
39
|
box-shadow: 0 0 40px rgb(69 71 69 / 0.2);
|
|
45
|
-
will-change: transform;
|
|
46
40
|
|
|
47
41
|
&:focus {
|
|
48
42
|
outline: none;
|
|
@@ -10,11 +10,12 @@ import { Transition, TransitionChild } from '@headlessui/react';
|
|
|
10
10
|
import { FocusScope } from '@react-aria/focus';
|
|
11
11
|
import { ThemeProvider, useTheme } from '@wise/components-theming';
|
|
12
12
|
import { clsx } from 'clsx';
|
|
13
|
-
import { Fragment, useState
|
|
13
|
+
import { Fragment, useState } from 'react';
|
|
14
14
|
|
|
15
|
-
import { CloseButton
|
|
15
|
+
import { CloseButton } from '../common/closeButton';
|
|
16
16
|
import { useVirtualKeyboard } from '../common/hooks/useVirtualKeyboard';
|
|
17
17
|
import { PreventScroll } from '../common/preventScroll/PreventScroll';
|
|
18
|
+
import { Size } from '../common/propsValues/size';
|
|
18
19
|
|
|
19
20
|
export interface BottomSheetProps {
|
|
20
21
|
open: boolean;
|
|
@@ -32,19 +33,6 @@ export interface BottomSheetProps {
|
|
|
32
33
|
onCloseEnd?: () => void;
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
/**
|
|
36
|
-
* App pages set scroll-behavior to 'smooth' which causes mobile Safari to
|
|
37
|
-
* slow-scroll and glitch. This function temporarily disables that behaviour
|
|
38
|
-
* while the BottomSheet is open.
|
|
39
|
-
*/
|
|
40
|
-
const freezeScroll = (shouldFreeze = true) => {
|
|
41
|
-
if (shouldFreeze) {
|
|
42
|
-
document.documentElement.style.scrollBehavior = 'unset';
|
|
43
|
-
} else {
|
|
44
|
-
document.documentElement.style.removeProperty('scroll-behavior');
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
|
|
48
36
|
export function BottomSheet({
|
|
49
37
|
open,
|
|
50
38
|
renderTrigger,
|
|
@@ -66,14 +54,12 @@ export function BottomSheet({
|
|
|
66
54
|
},
|
|
67
55
|
});
|
|
68
56
|
|
|
69
|
-
useEffect(() => {
|
|
70
|
-
freezeScroll(open);
|
|
71
|
-
}, [open]);
|
|
72
|
-
|
|
73
57
|
const dismiss = useDismiss(context);
|
|
74
58
|
const role = useRole(context);
|
|
75
59
|
const { getReferenceProps, getFloatingProps } = useInteractions([dismiss, role]);
|
|
60
|
+
|
|
76
61
|
const [floatingKey, setFloatingKey] = useState(0);
|
|
62
|
+
|
|
77
63
|
const { theme, screenMode } = useTheme();
|
|
78
64
|
|
|
79
65
|
return (
|
package/src/main.css
CHANGED
|
@@ -2574,7 +2574,6 @@ button.np-option {
|
|
|
2574
2574
|
}
|
|
2575
2575
|
.no-scroll {
|
|
2576
2576
|
overflow: hidden;
|
|
2577
|
-
scroll-behavior: unset;
|
|
2578
2577
|
}
|
|
2579
2578
|
.dimmer {
|
|
2580
2579
|
position: fixed;
|
|
@@ -3840,38 +3839,35 @@ html:not([dir="rtl"]) .np-flow-navigation--sm .np-flow-navigation__stepper {
|
|
|
3840
3839
|
transition-property: opacity;
|
|
3841
3840
|
transition-timing-function: ease-out;
|
|
3842
3841
|
transition-duration: 300ms;
|
|
3843
|
-
height: 100vh;
|
|
3844
|
-
min-height: -webkit-fill-available;
|
|
3845
3842
|
}
|
|
3846
3843
|
.np-bottom-sheet-v2-backdrop--closed {
|
|
3847
3844
|
opacity: 0;
|
|
3848
3845
|
}
|
|
3849
3846
|
.np-bottom-sheet-v2 {
|
|
3850
3847
|
position: fixed;
|
|
3851
|
-
inset:
|
|
3848
|
+
inset: 0px;
|
|
3852
3849
|
bottom: env(keyboard-inset-height, 0px);
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3850
|
+
margin-left: 8px;
|
|
3851
|
+
margin-left: var(--size-8);
|
|
3852
|
+
margin-right: 8px;
|
|
3853
|
+
margin-right: var(--size-8);
|
|
3854
|
+
margin-top: 64px;
|
|
3855
|
+
margin-top: var(--size-64);
|
|
3857
3856
|
display: flex;
|
|
3858
3857
|
flex-direction: column;
|
|
3859
3858
|
justify-content: flex-end;
|
|
3860
|
-
height: 100%;
|
|
3861
|
-
min-height: -webkit-fill-available;
|
|
3862
3859
|
}
|
|
3863
3860
|
.np-bottom-sheet-v2-content {
|
|
3864
3861
|
display: flex;
|
|
3865
3862
|
flex-direction: column;
|
|
3866
3863
|
overflow: auto;
|
|
3867
3864
|
border-top-left-radius: 32px;
|
|
3868
|
-
|
|
3865
|
+
/* TODO: Tokenize */
|
|
3869
3866
|
border-top-right-radius: 32px;
|
|
3870
|
-
|
|
3867
|
+
/* TODO: Tokenize */
|
|
3871
3868
|
background-color: #ffffff;
|
|
3872
3869
|
background-color: var(--color-background-elevated);
|
|
3873
3870
|
box-shadow: 0 0 40px rgba(69, 71, 69, 0.2);
|
|
3874
|
-
will-change: transform;
|
|
3875
3871
|
}
|
|
3876
3872
|
.np-bottom-sheet-v2-content:focus {
|
|
3877
3873
|
outline: none;
|
|
@@ -3,7 +3,6 @@ import { forwardRef, useImperativeHandle, useRef } from 'react';
|
|
|
3
3
|
import { CSSTransition } from 'react-transition-group';
|
|
4
4
|
|
|
5
5
|
import { Position } from '../common';
|
|
6
|
-
import { PreventScroll } from '../common/preventScroll/PreventScroll';
|
|
7
6
|
|
|
8
7
|
export const EXIT_ANIMATION = 350;
|
|
9
8
|
|
|
@@ -34,35 +33,31 @@ const SlidingPanel = forwardRef(
|
|
|
34
33
|
useImperativeHandle(reference, () => localReference.current, []);
|
|
35
34
|
|
|
36
35
|
return (
|
|
37
|
-
|
|
38
|
-
{
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
36
|
+
<CSSTransition
|
|
37
|
+
{...rest}
|
|
38
|
+
key={`sliding-panel--open-${position}`}
|
|
39
|
+
nodeRef={localReference}
|
|
40
|
+
in={open}
|
|
41
|
+
// Wait for animation to finish before unmount.
|
|
42
|
+
timeout={{ enter: 0, exit: EXIT_ANIMATION }}
|
|
43
|
+
classNames="sliding-panel"
|
|
44
|
+
appear
|
|
45
|
+
unmountOnExit
|
|
46
|
+
>
|
|
47
|
+
<div
|
|
48
|
+
ref={localReference}
|
|
49
|
+
data-testid={testId}
|
|
50
|
+
className={clsx(
|
|
51
|
+
'sliding-panel',
|
|
52
|
+
`sliding-panel--open-${position}`,
|
|
53
|
+
showSlidingPanelBorder && `sliding-panel--border-${position}`,
|
|
54
|
+
slidingPanelPositionFixed && 'sliding-panel--fixed',
|
|
55
|
+
className,
|
|
56
|
+
)}
|
|
50
57
|
>
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
className={clsx(
|
|
55
|
-
'sliding-panel',
|
|
56
|
-
`sliding-panel--open-${position}`,
|
|
57
|
-
showSlidingPanelBorder && `sliding-panel--border-${position}`,
|
|
58
|
-
slidingPanelPositionFixed && 'sliding-panel--fixed',
|
|
59
|
-
className,
|
|
60
|
-
)}
|
|
61
|
-
>
|
|
62
|
-
{children}
|
|
63
|
-
</div>
|
|
64
|
-
</CSSTransition>
|
|
65
|
-
</>
|
|
58
|
+
{children}
|
|
59
|
+
</div>
|
|
60
|
+
</CSSTransition>
|
|
66
61
|
);
|
|
67
62
|
},
|
|
68
63
|
);
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { useState } from 'react';
|
|
2
|
-
import { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
3
|
-
import { userEvent, within } from 'storybook/test';
|
|
4
|
-
import { lorem100, lorem500 } from '../../test-utils';
|
|
5
|
-
import { Typography } from '../propsValues/typography';
|
|
6
|
-
import Alert from '../../alert';
|
|
7
|
-
import Body from '../../body';
|
|
8
|
-
import Button from '../../button';
|
|
9
|
-
import Title from '../../title';
|
|
10
|
-
import BottomSheet from './BottomSheet';
|
|
11
|
-
|
|
12
|
-
const wait = async (duration = 500) =>
|
|
13
|
-
new Promise<void>((resolve) => {
|
|
14
|
-
setTimeout(resolve, duration);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
export default {
|
|
18
|
-
component: BottomSheet,
|
|
19
|
-
title: 'Dialogs/BottomSheet/tests',
|
|
20
|
-
tags: ['!autodocs'],
|
|
21
|
-
args: {
|
|
22
|
-
open: false,
|
|
23
|
-
},
|
|
24
|
-
} satisfies Meta<typeof BottomSheet>;
|
|
25
|
-
|
|
26
|
-
type Story = StoryObj<typeof BottomSheet>;
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* This test ensures that when the SelectInput is used within a scrollable page,
|
|
30
|
-
* opening the dropdown does not cause any unwanted scrolling or layout shifts.
|
|
31
|
-
* Expected preview should start with green bar at the top, with yellow section
|
|
32
|
-
* not in the viewport.
|
|
33
|
-
*
|
|
34
|
-
* NB: This test is disabled in Chromatic as there's no obvious way to control <html/> element of a snapshot.
|
|
35
|
-
*/
|
|
36
|
-
export const SmoothScrollReset: Story = {
|
|
37
|
-
args: {
|
|
38
|
-
children: (
|
|
39
|
-
<>
|
|
40
|
-
<Title type={Typography.TITLE_SECTION}>Observe the document</Title>
|
|
41
|
-
<Alert className="m-t-2" type="warning">
|
|
42
|
-
Once the <code>BottomSheet</code> opens, the document underneath should be static and
|
|
43
|
-
should not scroll.
|
|
44
|
-
</Alert>
|
|
45
|
-
<Body as="p">{lorem100}</Body>
|
|
46
|
-
<Body as="p">{lorem100}</Body>
|
|
47
|
-
</>
|
|
48
|
-
),
|
|
49
|
-
},
|
|
50
|
-
decorators: [
|
|
51
|
-
(Story) => (
|
|
52
|
-
<>
|
|
53
|
-
<style>{'html { scroll-behavior: smooth; }'}</style>
|
|
54
|
-
<div style={{ maxWidth: 500 }}>
|
|
55
|
-
<Body>
|
|
56
|
-
<p>{lorem100}</p>
|
|
57
|
-
<p>{lorem100}</p>
|
|
58
|
-
</Body>
|
|
59
|
-
<Story />
|
|
60
|
-
<Body as="p" className="m-t-5 disabled">
|
|
61
|
-
{lorem500}
|
|
62
|
-
</Body>
|
|
63
|
-
</div>
|
|
64
|
-
</>
|
|
65
|
-
),
|
|
66
|
-
],
|
|
67
|
-
parameters: {
|
|
68
|
-
chromatic: {
|
|
69
|
-
disableSnapshot: true,
|
|
70
|
-
},
|
|
71
|
-
},
|
|
72
|
-
play: async ({ canvasElement }) => {
|
|
73
|
-
document.documentElement.scrollTop = 400;
|
|
74
|
-
await wait(500);
|
|
75
|
-
const canvas = within(canvasElement);
|
|
76
|
-
await userEvent.click(canvas.getByRole('button'));
|
|
77
|
-
},
|
|
78
|
-
render: ({ open, ...args }) => {
|
|
79
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
80
|
-
|
|
81
|
-
return (
|
|
82
|
-
<div>
|
|
83
|
-
<Button onClick={() => setIsOpen(true)}>Open BottomSheet</Button>
|
|
84
|
-
<BottomSheet
|
|
85
|
-
{...args}
|
|
86
|
-
open={isOpen}
|
|
87
|
-
onClose={() => {
|
|
88
|
-
setIsOpen(false);
|
|
89
|
-
}}
|
|
90
|
-
/>
|
|
91
|
-
</div>
|
|
92
|
-
);
|
|
93
|
-
},
|
|
94
|
-
};
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
2
|
-
import { fn, type Mock, userEvent, within } from 'storybook/test';
|
|
3
|
-
import { allModes } from '../../.storybook/modes';
|
|
4
|
-
import { lorem5, lorem500 } from '../test-utils';
|
|
5
|
-
import { Field } from '../field/Field';
|
|
6
|
-
import Body from '../body';
|
|
7
|
-
import { SelectInput, type SelectInputProps } from './SelectInput';
|
|
8
|
-
|
|
9
|
-
const meta = {
|
|
10
|
-
title: 'Forms/SelectInput/tests',
|
|
11
|
-
component: SelectInput,
|
|
12
|
-
args: {
|
|
13
|
-
onFilterChange: fn() satisfies Mock,
|
|
14
|
-
onChange: fn() satisfies Mock,
|
|
15
|
-
onClose: fn() satisfies Mock,
|
|
16
|
-
onOpen: fn() satisfies Mock,
|
|
17
|
-
},
|
|
18
|
-
tags: ['!autodocs'],
|
|
19
|
-
} satisfies Meta<typeof SelectInput>;
|
|
20
|
-
export default meta;
|
|
21
|
-
|
|
22
|
-
type Story<T, M extends boolean = false> = StoryObj<SelectInputProps<T, M>>;
|
|
23
|
-
|
|
24
|
-
const wait = async (duration = 500) =>
|
|
25
|
-
new Promise<void>((resolve) => {
|
|
26
|
-
setTimeout(resolve, duration);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* This test ensures that when the SelectInput is used within a scrollable page,
|
|
31
|
-
* opening the dropdown does not cause any unwanted scrolling or layout shifts.
|
|
32
|
-
* Expected preview should start with green bar at the top, with yellow section
|
|
33
|
-
* not in the viewport.
|
|
34
|
-
*
|
|
35
|
-
* NB: This test is disabled in Chromatic as there's no obvious way to control <html/> element of a snapshot.
|
|
36
|
-
*/
|
|
37
|
-
export const SmoothScrollReset: Story<string> = {
|
|
38
|
-
args: {
|
|
39
|
-
items: Array.from({ length: 15 }).map((_, id) => ({
|
|
40
|
-
type: 'option',
|
|
41
|
-
value: `option ${id + 1}`,
|
|
42
|
-
})),
|
|
43
|
-
placeholder: 'Select option',
|
|
44
|
-
},
|
|
45
|
-
decorators: [
|
|
46
|
-
(Story) => (
|
|
47
|
-
<>
|
|
48
|
-
<style>{`html { scroll-behavior: smooth; }`}</style>
|
|
49
|
-
<div>
|
|
50
|
-
<div
|
|
51
|
-
className="d-flex align-items-center justify-content-center"
|
|
52
|
-
style={{
|
|
53
|
-
backgroundColor: 'var(--color-bright-yellow)',
|
|
54
|
-
height: 400,
|
|
55
|
-
}}
|
|
56
|
-
>
|
|
57
|
-
This block should not be in the viewport.
|
|
58
|
-
</div>
|
|
59
|
-
<div style={{ height: 10, backgroundColor: 'var(--color-bright-green)' }} />
|
|
60
|
-
<Field id="el1" label={lorem5}>
|
|
61
|
-
<Story />
|
|
62
|
-
</Field>
|
|
63
|
-
<Body as="p">{lorem500}</Body>
|
|
64
|
-
</div>
|
|
65
|
-
</>
|
|
66
|
-
),
|
|
67
|
-
],
|
|
68
|
-
play: async ({ canvasElement }) => {
|
|
69
|
-
document.documentElement.scrollTop = 400;
|
|
70
|
-
await wait();
|
|
71
|
-
const canvas = within(canvasElement);
|
|
72
|
-
const triggerButton = canvas.getByRole('combobox');
|
|
73
|
-
await userEvent.click(triggerButton);
|
|
74
|
-
},
|
|
75
|
-
globals: {
|
|
76
|
-
viewport: { value: allModes.largeMobile.viewport, isRotated: false },
|
|
77
|
-
},
|
|
78
|
-
parameters: {
|
|
79
|
-
chromatic: {
|
|
80
|
-
disableSnapshot: true,
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
};
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
2
|
-
import { fn, type Mock, userEvent, within } from 'storybook/test';
|
|
3
|
-
import { allModes } from '../../.storybook/modes';
|
|
4
|
-
import { lorem500 } from '../test-utils';
|
|
5
|
-
import { Field } from '../field/Field';
|
|
6
|
-
import Body from '../body';
|
|
7
|
-
import MoneyInput from './MoneyInput';
|
|
8
|
-
|
|
9
|
-
const meta = {
|
|
10
|
-
title: 'Forms/MoneyInput/tests',
|
|
11
|
-
component: MoneyInput,
|
|
12
|
-
args: {
|
|
13
|
-
amount: 1000,
|
|
14
|
-
id: 'moneyInput',
|
|
15
|
-
currencies: [
|
|
16
|
-
{
|
|
17
|
-
value: 'EUR',
|
|
18
|
-
label: 'EUR',
|
|
19
|
-
note: 'Euro',
|
|
20
|
-
currency: 'eur',
|
|
21
|
-
searchable: 'Spain, Germany, France, Austria',
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
value: 'GBP',
|
|
25
|
-
label: 'GBP',
|
|
26
|
-
note: 'British pound',
|
|
27
|
-
currency: 'gbp',
|
|
28
|
-
searchable: 'England, Scotland, Wales',
|
|
29
|
-
},
|
|
30
|
-
],
|
|
31
|
-
selectedCurrency: {
|
|
32
|
-
value: 'EUR',
|
|
33
|
-
label: 'EUR',
|
|
34
|
-
note: 'Euro',
|
|
35
|
-
currency: 'eur',
|
|
36
|
-
searchable: 'Spain, Germany, France, Austria',
|
|
37
|
-
},
|
|
38
|
-
searchPlaceholder: '',
|
|
39
|
-
onAmountChange: () => {},
|
|
40
|
-
onCurrencyChange: () => {},
|
|
41
|
-
},
|
|
42
|
-
tags: ['!autodocs'],
|
|
43
|
-
} satisfies Meta<typeof MoneyInput>;
|
|
44
|
-
export default meta;
|
|
45
|
-
|
|
46
|
-
type Story = StoryObj<typeof MoneyInput>;
|
|
47
|
-
|
|
48
|
-
const wait = async (duration = 500) =>
|
|
49
|
-
new Promise<void>((resolve) => {
|
|
50
|
-
setTimeout(resolve, duration);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* This test ensures that when the SelectInput is used within a scrollable page,
|
|
55
|
-
* opening the dropdown does not cause any unwanted scrolling or layout shifts.
|
|
56
|
-
* Expected preview should start with green bar at the top, with yellow section
|
|
57
|
-
* not in the viewport.
|
|
58
|
-
*
|
|
59
|
-
* NB: This test is disabled in Chromatic as there's no obvious way to control <html/> element of a snapshot.
|
|
60
|
-
*/
|
|
61
|
-
export const SmoothScrollReset: Story = {
|
|
62
|
-
decorators: [
|
|
63
|
-
(Story) => (
|
|
64
|
-
<>
|
|
65
|
-
<style>{`html { scroll-behavior: smooth; }`}</style>
|
|
66
|
-
<div>
|
|
67
|
-
<div
|
|
68
|
-
className="d-flex align-items-center justify-content-center"
|
|
69
|
-
style={{
|
|
70
|
-
backgroundColor: 'var(--color-bright-yellow)',
|
|
71
|
-
height: 400,
|
|
72
|
-
}}
|
|
73
|
-
>
|
|
74
|
-
This block should not be in the viewport.
|
|
75
|
-
</div>
|
|
76
|
-
<div style={{ height: 10, backgroundColor: 'var(--color-bright-green)' }} />
|
|
77
|
-
<Field id="el1" label="Select currency">
|
|
78
|
-
<Story />
|
|
79
|
-
</Field>
|
|
80
|
-
<Body as="p">{lorem500}</Body>
|
|
81
|
-
</div>
|
|
82
|
-
</>
|
|
83
|
-
),
|
|
84
|
-
],
|
|
85
|
-
play: async ({ canvasElement }) => {
|
|
86
|
-
await wait(2000);
|
|
87
|
-
document.documentElement.scrollTop = 400;
|
|
88
|
-
await wait(2000);
|
|
89
|
-
const canvas = within(canvasElement);
|
|
90
|
-
const triggerButton = canvas.getByRole('combobox');
|
|
91
|
-
await userEvent.click(triggerButton);
|
|
92
|
-
},
|
|
93
|
-
globals: {
|
|
94
|
-
viewport: { value: allModes.largeMobile.viewport, isRotated: false },
|
|
95
|
-
},
|
|
96
|
-
parameters: {
|
|
97
|
-
chromatic: {
|
|
98
|
-
disableSnapshot: true,
|
|
99
|
-
},
|
|
100
|
-
},
|
|
101
|
-
};
|