@transferwise/components 46.42.0 → 46.43.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/index.js +73 -40
- package/build/index.js.map +1 -1
- package/build/index.mjs +74 -41
- package/build/index.mjs.map +1 -1
- package/build/main.css +41 -51
- package/build/styles/inputs/SelectInput.css +41 -51
- package/build/styles/main.css +41 -51
- package/build/types/common/hooks/useVirtualKeyboard.d.ts +7 -0
- package/build/types/common/hooks/useVirtualKeyboard.d.ts.map +1 -0
- package/build/types/inputs/InputGroup.d.ts.map +1 -1
- package/build/types/inputs/SelectInput.d.ts +3 -1
- package/build/types/inputs/SelectInput.d.ts.map +1 -1
- package/build/types/inputs/_BottomSheet.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/circularButton/CircularButton.story.tsx +53 -84
- package/src/common/hooks/useVirtualKeyboard.ts +21 -0
- package/src/inputs/InputGroup.spec.tsx +26 -0
- package/src/inputs/InputGroup.tsx +35 -13
- package/src/inputs/SearchInput.spec.tsx +16 -0
- package/src/inputs/SelectInput.css +41 -51
- package/src/inputs/SelectInput.spec.tsx +1 -1
- package/src/inputs/SelectInput.tsx +4 -1
- package/src/inputs/_BottomSheet.less +35 -49
- package/src/inputs/_BottomSheet.tsx +22 -27
- package/src/inputs/_Popover.less +2 -2
- package/src/main.css +41 -51
|
@@ -1,97 +1,66 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { boolean, select, text } from '@storybook/addon-knobs';
|
|
3
|
-
import { Freeze, Plus, Whatsapp } from '@transferwise/icons';
|
|
1
|
+
import * as Icons from '@transferwise/icons';
|
|
4
2
|
|
|
5
|
-
import {
|
|
3
|
+
import { ControlType, Priority } from '../common';
|
|
6
4
|
|
|
5
|
+
import { Meta, StoryObj } from '@storybook/react';
|
|
7
6
|
import CircularButton from './CircularButton';
|
|
8
7
|
|
|
9
8
|
export default {
|
|
10
9
|
component: CircularButton,
|
|
11
10
|
title: 'Actions/CircularButton',
|
|
12
|
-
|
|
11
|
+
args: {
|
|
12
|
+
children: 'Button text',
|
|
13
|
+
// Needs to be cast because we're mapping icon names to components
|
|
14
|
+
icon: 'Freeze' as unknown as React.ReactElement,
|
|
15
|
+
},
|
|
16
|
+
argTypes: {
|
|
17
|
+
icon: {
|
|
18
|
+
options: Object.keys(Icons),
|
|
19
|
+
mapping: Object.fromEntries(
|
|
20
|
+
Object.entries(Icons).map(([name, Icon]) => [name, <Icon key={name} />]),
|
|
21
|
+
),
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
} satisfies Meta<typeof CircularButton>;
|
|
13
25
|
|
|
14
|
-
|
|
15
|
-
plus: <Plus />,
|
|
16
|
-
freeze: <Freeze />,
|
|
17
|
-
whatsapp: <Whatsapp />,
|
|
18
|
-
};
|
|
26
|
+
type Story = StoryObj<typeof CircularButton>;
|
|
19
27
|
|
|
20
|
-
export const Basic =
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const background = select('theme', ['light', 'blue'], 'light');
|
|
27
|
-
return (
|
|
28
|
-
<div className={background === 'blue' ? 'bg--dark p-a-3' : ''}>
|
|
29
|
-
<CircularButton
|
|
30
|
-
icon={icons[icon]}
|
|
31
|
-
priority={priority}
|
|
32
|
-
type={type}
|
|
33
|
-
disabled={disabled}
|
|
34
|
-
onClick={action('Button Clicked')}
|
|
35
|
-
>
|
|
36
|
-
{label}
|
|
37
|
-
</CircularButton>
|
|
38
|
-
</div>
|
|
39
|
-
);
|
|
28
|
+
export const Basic: Story = {
|
|
29
|
+
args: {
|
|
30
|
+
priority: Priority.PRIMARY,
|
|
31
|
+
type: ControlType.ACCENT,
|
|
32
|
+
disabled: false,
|
|
33
|
+
},
|
|
40
34
|
};
|
|
41
35
|
|
|
42
|
-
export const
|
|
43
|
-
|
|
44
|
-
const disabled = boolean('disabled', false);
|
|
45
|
-
const label = text('label', 'Button text');
|
|
46
|
-
const background = select('theme', ['light', 'blue'], 'light');
|
|
47
|
-
|
|
48
|
-
const commonProps = {
|
|
49
|
-
label,
|
|
36
|
+
export const All: Story = {
|
|
37
|
+
args: {
|
|
50
38
|
className: 'm-r-2',
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
<
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
<div className="title-4 m-b-1">Negative</div>
|
|
79
|
-
<CircularButton priority={Priority.PRIMARY} type={ControlType.NEGATIVE} {...commonProps}>
|
|
80
|
-
{label}
|
|
81
|
-
</CircularButton>
|
|
82
|
-
<CircularButton priority={Priority.SECONDARY} type={ControlType.NEGATIVE} {...commonProps}>
|
|
83
|
-
{label}
|
|
84
|
-
</CircularButton>
|
|
85
|
-
</div>
|
|
86
|
-
<div className="m-b-2">
|
|
87
|
-
<div className="title-4 m-b-1">Disabled</div>
|
|
88
|
-
<CircularButton {...commonProps} disabled>
|
|
89
|
-
{label}
|
|
90
|
-
</CircularButton>
|
|
91
|
-
<CircularButton {...commonProps} priority={Priority.SECONDARY} disabled>
|
|
92
|
-
{label}
|
|
93
|
-
</CircularButton>
|
|
94
|
-
</div>
|
|
95
|
-
</div>
|
|
96
|
-
);
|
|
39
|
+
},
|
|
40
|
+
render: (props) => {
|
|
41
|
+
return (
|
|
42
|
+
<>
|
|
43
|
+
<div className="m-b-2">
|
|
44
|
+
<div className="title-4 m-b-1">Accent</div>
|
|
45
|
+
<CircularButton {...props} priority={Priority.PRIMARY} type={ControlType.ACCENT} />
|
|
46
|
+
<CircularButton {...props} priority={Priority.SECONDARY} type={ControlType.ACCENT} />
|
|
47
|
+
</div>
|
|
48
|
+
<div className="m-b-2">
|
|
49
|
+
<div className="title-4 m-b-1">Positive</div>
|
|
50
|
+
<CircularButton {...props} priority={Priority.PRIMARY} type={ControlType.POSITIVE} />
|
|
51
|
+
<CircularButton {...props} priority={Priority.SECONDARY} type={ControlType.POSITIVE} />
|
|
52
|
+
</div>
|
|
53
|
+
<div className="m-b-2">
|
|
54
|
+
<div className="title-4 m-b-1">Negative</div>
|
|
55
|
+
<CircularButton {...props} priority={Priority.PRIMARY} type={ControlType.NEGATIVE} />
|
|
56
|
+
<CircularButton {...props} priority={Priority.SECONDARY} type={ControlType.NEGATIVE} />
|
|
57
|
+
</div>
|
|
58
|
+
<div className="m-b-2">
|
|
59
|
+
<div className="title-4 m-b-1">Disabled</div>
|
|
60
|
+
<CircularButton {...props} disabled />
|
|
61
|
+
<CircularButton {...props} priority={Priority.SECONDARY} disabled />
|
|
62
|
+
</div>
|
|
63
|
+
</>
|
|
64
|
+
);
|
|
65
|
+
},
|
|
97
66
|
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* This progressive enhancement uses an experimental API, it might change,
|
|
5
|
+
* and at the time of authoring is not supported on iOS or mobile Firefox.
|
|
6
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/VirtualKeyboard
|
|
7
|
+
*/
|
|
8
|
+
export function useVirtualKeyboard() {
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
/* eslint-disable @typescript-eslint/no-unsafe-member-access, functional/immutable-data */
|
|
11
|
+
if ('virtualKeyboard' in navigator) {
|
|
12
|
+
const virtualKeyboard: any = navigator.virtualKeyboard;
|
|
13
|
+
const initialOverlaysContent: unknown = virtualKeyboard.overlaysContent;
|
|
14
|
+
virtualKeyboard.overlaysContent = true;
|
|
15
|
+
return () => {
|
|
16
|
+
virtualKeyboard.overlaysContent = initialOverlaysContent;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/* eslint-enable @typescript-eslint/no-unsafe-member-access, functional/immutable-data */
|
|
20
|
+
}, []);
|
|
21
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Search } from '@transferwise/icons';
|
|
2
|
+
|
|
3
|
+
import { Field } from '../field/Field';
|
|
4
|
+
import { mockResizeObserver, render, screen } from '../test-utils';
|
|
5
|
+
import { Input } from './Input';
|
|
6
|
+
import { InputGroup } from './InputGroup';
|
|
7
|
+
|
|
8
|
+
mockResizeObserver();
|
|
9
|
+
|
|
10
|
+
describe('InputGroup', () => {
|
|
11
|
+
it('supports `Field` for labeling', () => {
|
|
12
|
+
render(
|
|
13
|
+
<Field label="Search…">
|
|
14
|
+
<InputGroup
|
|
15
|
+
addonStart={{
|
|
16
|
+
content: <Search size={24} />,
|
|
17
|
+
initialContentWidth: 24,
|
|
18
|
+
}}
|
|
19
|
+
>
|
|
20
|
+
<Input />
|
|
21
|
+
</InputGroup>
|
|
22
|
+
</Field>,
|
|
23
|
+
);
|
|
24
|
+
expect(screen.getAllByRole('group')[0]).toHaveAccessibleName(/^Search…/);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -3,6 +3,13 @@ import { createContext, useContext, useMemo, useRef, useState } from 'react';
|
|
|
3
3
|
|
|
4
4
|
import { useResizeObserver } from '../common/hooks/useResizeObserver';
|
|
5
5
|
import { cssValueWithUnit } from '../utilities/cssValueWithUnit';
|
|
6
|
+
import {
|
|
7
|
+
FieldLabelIdContextProvider,
|
|
8
|
+
InputDescribedByProvider,
|
|
9
|
+
InputIdContextProvider,
|
|
10
|
+
InputInvalidProvider,
|
|
11
|
+
useInputAttributes,
|
|
12
|
+
} from './contexts';
|
|
6
13
|
|
|
7
14
|
type InputPaddingContextType = [
|
|
8
15
|
number | string | undefined,
|
|
@@ -60,23 +67,38 @@ export function InputGroup({
|
|
|
60
67
|
className,
|
|
61
68
|
children,
|
|
62
69
|
}: InputGroupProps) {
|
|
70
|
+
const inputAttributes = useInputAttributes({ nonLabelable: true });
|
|
71
|
+
|
|
63
72
|
const [paddingStart, setPaddingStart] = useState(inputPaddingInitialState(addonStart));
|
|
64
73
|
const [paddingEnd, setPaddingEnd] = useState(inputPaddingInitialState(addonEnd));
|
|
65
74
|
|
|
66
75
|
return (
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
/* Prevent nested controls from being labeled redundantly */
|
|
77
|
+
<FieldLabelIdContextProvider value={undefined}>
|
|
78
|
+
<InputIdContextProvider value={undefined}>
|
|
79
|
+
<InputDescribedByProvider value={undefined}>
|
|
80
|
+
<InputInvalidProvider value={undefined}>
|
|
81
|
+
<InputPaddingStartContext.Provider
|
|
82
|
+
value={useMemo(() => [paddingStart, setPaddingStart], [paddingStart])}
|
|
83
|
+
>
|
|
84
|
+
<InputPaddingEndContext.Provider
|
|
85
|
+
value={useMemo(() => [paddingEnd, setPaddingEnd], [paddingEnd])}
|
|
86
|
+
>
|
|
87
|
+
<fieldset
|
|
88
|
+
{...inputAttributes}
|
|
89
|
+
disabled={disabled}
|
|
90
|
+
className={classNames(className, 'np-input-group')}
|
|
91
|
+
>
|
|
92
|
+
{addonStart != null ? <InputAddon placement="start" {...addonStart} /> : null}
|
|
93
|
+
{children}
|
|
94
|
+
{addonEnd != null ? <InputAddon placement="end" {...addonEnd} /> : null}
|
|
95
|
+
</fieldset>
|
|
96
|
+
</InputPaddingEndContext.Provider>
|
|
97
|
+
</InputPaddingStartContext.Provider>
|
|
98
|
+
</InputInvalidProvider>
|
|
99
|
+
</InputDescribedByProvider>
|
|
100
|
+
</InputIdContextProvider>
|
|
101
|
+
</FieldLabelIdContextProvider>
|
|
80
102
|
);
|
|
81
103
|
}
|
|
82
104
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Field } from '../field/Field';
|
|
2
|
+
import { mockResizeObserver, render, screen } from '../test-utils';
|
|
3
|
+
import { SearchInput } from './SearchInput';
|
|
4
|
+
|
|
5
|
+
mockResizeObserver();
|
|
6
|
+
|
|
7
|
+
describe('SearchInput', () => {
|
|
8
|
+
it('supports `Field` for labeling', () => {
|
|
9
|
+
render(
|
|
10
|
+
<Field label="Search…">
|
|
11
|
+
<SearchInput />
|
|
12
|
+
</Field>,
|
|
13
|
+
);
|
|
14
|
+
expect(screen.getAllByRole('group')[0]).toHaveAccessibleName(/^Search…/);
|
|
15
|
+
});
|
|
16
|
+
});
|
|
@@ -2,67 +2,37 @@
|
|
|
2
2
|
position: relative;
|
|
3
3
|
z-index: 1060;
|
|
4
4
|
}
|
|
5
|
-
.np-bottom-sheet-v2-backdrop-container--enter,
|
|
6
|
-
.np-bottom-sheet-v2-backdrop-container--leave {
|
|
7
|
-
transition-property: opacity;
|
|
8
|
-
transition-timing-function: ease-out;
|
|
9
|
-
transition-duration: 300ms;
|
|
10
|
-
}
|
|
11
|
-
.np-bottom-sheet-v2-backdrop-container--enter-from,
|
|
12
|
-
.np-bottom-sheet-v2-backdrop-container--leave-to {
|
|
13
|
-
opacity: 0;
|
|
14
|
-
}
|
|
15
5
|
.np-bottom-sheet-v2-backdrop {
|
|
16
6
|
position: fixed;
|
|
17
7
|
inset: 0px;
|
|
18
8
|
background-color: #37517e;
|
|
19
9
|
background-color: var(--color-content-primary);
|
|
20
10
|
opacity: 0.4;
|
|
11
|
+
transition-property: opacity;
|
|
12
|
+
transition-timing-function: ease-out;
|
|
13
|
+
transition-duration: 300ms;
|
|
14
|
+
}
|
|
15
|
+
.np-bottom-sheet-v2-backdrop--closed {
|
|
16
|
+
opacity: 0;
|
|
21
17
|
}
|
|
22
18
|
.np-bottom-sheet-v2 {
|
|
23
19
|
position: fixed;
|
|
24
20
|
inset: 0px;
|
|
21
|
+
bottom: env(keyboard-inset-height, 0px);
|
|
22
|
+
margin-left: 8px;
|
|
23
|
+
margin-left: var(--size-8);
|
|
24
|
+
margin-right: 8px;
|
|
25
|
+
margin-right: var(--size-8);
|
|
26
|
+
margin-top: 64px;
|
|
27
|
+
margin-top: var(--size-64);
|
|
25
28
|
display: flex;
|
|
26
29
|
flex-direction: column;
|
|
27
30
|
justify-content: flex-end;
|
|
28
|
-
padding-left: 8px;
|
|
29
|
-
padding-left: var(--size-8);
|
|
30
|
-
padding-right: 8px;
|
|
31
|
-
padding-right: var(--size-8);
|
|
32
|
-
padding-top: 64px;
|
|
33
|
-
padding-top: var(--size-64);
|
|
34
31
|
}
|
|
35
32
|
.np-bottom-sheet-v2-content {
|
|
36
|
-
max-height: 100%;
|
|
37
|
-
}
|
|
38
|
-
.np-bottom-sheet-v2-content--enter,
|
|
39
|
-
.np-bottom-sheet-v2-content--leave {
|
|
40
|
-
transition-property: transform;
|
|
41
|
-
transition-timing-function: ease-out;
|
|
42
|
-
transition-duration: 300ms;
|
|
43
|
-
}
|
|
44
|
-
@media (prefers-reduced-motion: reduce) {
|
|
45
|
-
.np-bottom-sheet-v2-content--enter,
|
|
46
|
-
.np-bottom-sheet-v2-content--leave {
|
|
47
|
-
transition-property: opacity;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
@media (prefers-reduced-motion: no-preference) {
|
|
51
|
-
.np-bottom-sheet-v2-content--enter-from,
|
|
52
|
-
.np-bottom-sheet-v2-content--leave-to {
|
|
53
|
-
transform: translateY(100%);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
@media (prefers-reduced-motion: reduce) {
|
|
57
|
-
.np-bottom-sheet-v2-content--enter-from,
|
|
58
|
-
.np-bottom-sheet-v2-content--leave-to {
|
|
59
|
-
opacity: 0;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
.np-bottom-sheet-v2-content-inner-container {
|
|
63
33
|
display: flex;
|
|
64
|
-
height: 100%;
|
|
65
34
|
flex-direction: column;
|
|
35
|
+
overflow: auto;
|
|
66
36
|
border-top-left-radius: 32px;
|
|
67
37
|
/* TODO: Tokenize */
|
|
68
38
|
border-top-right-radius: 32px;
|
|
@@ -71,30 +41,50 @@
|
|
|
71
41
|
background-color: var(--color-background-elevated);
|
|
72
42
|
box-shadow: 0 0 40px rgba(69, 71, 69, 0.2);
|
|
73
43
|
}
|
|
74
|
-
.np-bottom-sheet-v2-content
|
|
44
|
+
.np-bottom-sheet-v2-content:focus {
|
|
75
45
|
outline: none;
|
|
76
46
|
}
|
|
47
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
48
|
+
.np-bottom-sheet-v2-content {
|
|
49
|
+
transition-property: transform;
|
|
50
|
+
transition-timing-function: ease-out;
|
|
51
|
+
transition-duration: 300ms;
|
|
52
|
+
}
|
|
53
|
+
.np-bottom-sheet-v2-content--closed {
|
|
54
|
+
transform: translateY(100%);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
@media (prefers-reduced-motion: reduce) {
|
|
58
|
+
.np-bottom-sheet-v2-content {
|
|
59
|
+
transition-property: opacity;
|
|
60
|
+
transition-timing-function: ease-out;
|
|
61
|
+
transition-duration: 300ms;
|
|
62
|
+
}
|
|
63
|
+
.np-bottom-sheet-v2-content--closed {
|
|
64
|
+
opacity: 0;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
77
67
|
.np-bottom-sheet-v2-header {
|
|
78
68
|
align-self: flex-end;
|
|
79
69
|
padding: 16px;
|
|
80
70
|
padding: var(--size-16);
|
|
81
71
|
}
|
|
82
72
|
.np-bottom-sheet-v2-content-inner {
|
|
83
|
-
padding-top: 0px;
|
|
84
73
|
display: grid;
|
|
74
|
+
grid-template-rows: minmax(0, 1fr);
|
|
85
75
|
grid-row-gap: 8px;
|
|
86
76
|
grid-row-gap: var(--size-8);
|
|
87
77
|
row-gap: 8px;
|
|
88
78
|
row-gap: var(--size-8);
|
|
89
|
-
overflow
|
|
90
|
-
grid-template-rows: repeat(1, minmax(0, 1fr));
|
|
79
|
+
overflow: auto;
|
|
91
80
|
}
|
|
92
81
|
.np-bottom-sheet-v2-content-inner--has-title {
|
|
93
|
-
grid-template-rows: auto 1fr;
|
|
82
|
+
grid-template-rows: auto minmax(0, 1fr);
|
|
94
83
|
}
|
|
95
84
|
.np-bottom-sheet-v2-content-inner--padding-md {
|
|
96
85
|
padding: 16px;
|
|
97
86
|
padding: var(--size-16);
|
|
87
|
+
padding-top: 0px;
|
|
98
88
|
}
|
|
99
89
|
.np-bottom-sheet-v2-title {
|
|
100
90
|
color: #37517e;
|
|
@@ -141,10 +131,10 @@
|
|
|
141
131
|
row-gap: 8px;
|
|
142
132
|
row-gap: var(--size-8);
|
|
143
133
|
overflow-y: auto;
|
|
144
|
-
grid-template-rows:
|
|
134
|
+
grid-template-rows: minmax(0, 1fr);
|
|
145
135
|
}
|
|
146
136
|
.np-popover-v2--has-title {
|
|
147
|
-
grid-template-rows: auto 1fr;
|
|
137
|
+
grid-template-rows: auto minmax(0, 1fr);
|
|
148
138
|
}
|
|
149
139
|
.np-popover-v2--padding-md {
|
|
150
140
|
padding: 16px;
|
|
@@ -214,6 +214,6 @@ describe('SelectInput', () => {
|
|
|
214
214
|
<SelectInput items={[{ type: 'option', value: 'USD' }]} value="USD" />
|
|
215
215
|
</Field>,
|
|
216
216
|
);
|
|
217
|
-
expect(screen.
|
|
217
|
+
expect(screen.getAllByRole('group')[0]).toHaveAccessibleName(/^Currency/);
|
|
218
218
|
});
|
|
219
219
|
});
|
|
@@ -24,7 +24,7 @@ import { Merge } from '../utils';
|
|
|
24
24
|
import { BottomSheet } from './_BottomSheet';
|
|
25
25
|
import { ButtonInput } from './_ButtonInput';
|
|
26
26
|
import { Popover } from './_Popover';
|
|
27
|
-
import { useInputAttributes } from './contexts';
|
|
27
|
+
import { useInputAttributes, WithInputAttributesProps } from './contexts';
|
|
28
28
|
import { InputGroup } from './InputGroup';
|
|
29
29
|
import { SearchInput } from './SearchInput';
|
|
30
30
|
import messages from './SelectInput.messages';
|
|
@@ -162,6 +162,7 @@ export interface SelectInputProps<T = string, M extends boolean = false> {
|
|
|
162
162
|
disabled?: boolean;
|
|
163
163
|
size?: 'sm' | 'md' | 'lg';
|
|
164
164
|
className?: string;
|
|
165
|
+
UNSAFE_triggerButtonProps?: WithInputAttributesProps['inputAttributes'];
|
|
165
166
|
onFilterChange?: (args: { query: string; queryNormalized: string | null }) => void;
|
|
166
167
|
onChange?: (value: M extends true ? T[] : T) => void;
|
|
167
168
|
onClose?: () => void;
|
|
@@ -246,6 +247,7 @@ export function SelectInput<T = string, M extends boolean = false>({
|
|
|
246
247
|
disabled,
|
|
247
248
|
size = 'md',
|
|
248
249
|
className,
|
|
250
|
+
UNSAFE_triggerButtonProps,
|
|
249
251
|
onFilterChange = noop,
|
|
250
252
|
onChange,
|
|
251
253
|
onClose,
|
|
@@ -321,6 +323,7 @@ export function SelectInput<T = string, M extends boolean = false>({
|
|
|
321
323
|
triggerRef.current = node;
|
|
322
324
|
},
|
|
323
325
|
...inputAttributes,
|
|
326
|
+
...UNSAFE_triggerButtonProps,
|
|
324
327
|
id,
|
|
325
328
|
...mergeProps(
|
|
326
329
|
{
|
|
@@ -3,98 +3,84 @@
|
|
|
3
3
|
z-index: 1060;
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
-
.np-bottom-sheet-v2-backdrop-container {
|
|
7
|
-
&--enter, &--leave {
|
|
8
|
-
transition-property: opacity;
|
|
9
|
-
transition-timing-function: ease-out;
|
|
10
|
-
transition-duration: 300ms;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
&--enter-from, &--leave-to {
|
|
14
|
-
opacity: 0;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
6
|
.np-bottom-sheet-v2-backdrop {
|
|
19
7
|
position: fixed;
|
|
20
8
|
inset: 0px;
|
|
21
9
|
background-color: var(--color-content-primary);
|
|
22
10
|
opacity: 0.4;
|
|
11
|
+
transition-property: opacity;
|
|
12
|
+
transition-timing-function: ease-out;
|
|
13
|
+
transition-duration: 300ms;
|
|
14
|
+
|
|
15
|
+
&--closed {
|
|
16
|
+
opacity: 0;
|
|
17
|
+
}
|
|
23
18
|
}
|
|
24
19
|
|
|
25
20
|
.np-bottom-sheet-v2 {
|
|
26
21
|
position: fixed;
|
|
27
22
|
inset: 0px;
|
|
23
|
+
bottom: env(keyboard-inset-height, 0px);
|
|
24
|
+
margin-left: var(--size-8);
|
|
25
|
+
margin-right: var(--size-8);
|
|
26
|
+
margin-top: var(--size-64);
|
|
28
27
|
display: flex;
|
|
29
28
|
flex-direction: column;
|
|
30
29
|
justify-content: flex-end;
|
|
31
|
-
padding-left: var(--size-8);
|
|
32
|
-
padding-right: var(--size-8);
|
|
33
|
-
padding-top: var(--size-64);
|
|
34
30
|
}
|
|
35
31
|
|
|
36
32
|
.np-bottom-sheet-v2-content {
|
|
37
|
-
|
|
33
|
+
display: flex;
|
|
34
|
+
flex-direction: column;
|
|
35
|
+
overflow: auto;
|
|
36
|
+
border-top-left-radius: 32px; /* TODO: Tokenize */
|
|
37
|
+
border-top-right-radius: 32px; /* TODO: Tokenize */
|
|
38
|
+
background-color: var(--color-background-elevated);
|
|
39
|
+
box-shadow: 0 0 40px rgb(69 71 69 / 0.2);
|
|
40
|
+
|
|
41
|
+
&:focus {
|
|
42
|
+
outline: none;
|
|
43
|
+
}
|
|
38
44
|
|
|
39
|
-
|
|
45
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
40
46
|
transition-property: transform;
|
|
41
47
|
transition-timing-function: ease-out;
|
|
42
48
|
transition-duration: 300ms;
|
|
43
49
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
transition-property: opacity;
|
|
47
|
-
}
|
|
50
|
+
&--closed {
|
|
51
|
+
transform: translateY(100%);
|
|
48
52
|
}
|
|
49
53
|
}
|
|
50
54
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
}
|
|
55
|
+
@media (prefers-reduced-motion: reduce) {
|
|
56
|
+
transition-property: opacity;
|
|
57
|
+
transition-timing-function: ease-out;
|
|
58
|
+
transition-duration: 300ms;
|
|
57
59
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
opacity: 0;
|
|
61
|
-
}
|
|
60
|
+
&--closed {
|
|
61
|
+
opacity: 0;
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
.np-bottom-sheet-v2-content-inner-container {
|
|
67
|
-
display: flex;
|
|
68
|
-
height: 100%;
|
|
69
|
-
flex-direction: column;
|
|
70
|
-
border-top-left-radius: 32px; /* TODO: Tokenize */
|
|
71
|
-
border-top-right-radius: 32px; /* TODO: Tokenize */
|
|
72
|
-
background-color: var(--color-background-elevated);
|
|
73
|
-
box-shadow: 0 0 40px rgb(69 71 69 / 0.2);
|
|
74
|
-
|
|
75
|
-
&:focus {
|
|
76
|
-
outline: none;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
66
|
.np-bottom-sheet-v2-header {
|
|
81
67
|
align-self: flex-end;
|
|
82
68
|
padding: var(--size-16);
|
|
83
69
|
}
|
|
84
70
|
|
|
85
71
|
.np-bottom-sheet-v2-content-inner {
|
|
86
|
-
padding-top: 0px;
|
|
87
72
|
display: grid;
|
|
73
|
+
grid-template-rows: minmax(0, 1fr);
|
|
88
74
|
row-gap: var(--size-8);
|
|
89
|
-
overflow
|
|
90
|
-
grid-template-rows: repeat(1, minmax(0, 1fr));
|
|
75
|
+
overflow: auto;
|
|
91
76
|
|
|
92
77
|
&--has-title {
|
|
93
|
-
grid-template-rows: auto 1fr;
|
|
78
|
+
grid-template-rows: auto minmax(0, 1fr);
|
|
94
79
|
}
|
|
95
80
|
|
|
96
81
|
&--padding-md {
|
|
97
82
|
padding: var(--size-16);
|
|
83
|
+
padding-top: 0px;
|
|
98
84
|
}
|
|
99
85
|
}
|
|
100
86
|
|