@ledgerhq/lumen-ui-rnative 0.1.34 → 0.1.35
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/dist/module/index.js +1 -0
- package/dist/module/index.js.map +1 -1
- package/dist/module/lib/Animations/Pulse/Pulse.js +17 -7
- package/dist/module/lib/Animations/Pulse/Pulse.js.map +1 -1
- package/dist/module/lib/Components/BottomSheet/BottomSheet.js +12 -7
- package/dist/module/lib/Components/BottomSheet/BottomSheet.js.map +1 -1
- package/dist/module/lib/Components/BottomSheet/BottomSheet.stories.js +220 -1
- package/dist/module/lib/Components/BottomSheet/BottomSheet.stories.js.map +1 -1
- package/dist/module/lib/Components/BottomSheet/BottomSheet.test.js +73 -0
- package/dist/module/lib/Components/BottomSheet/BottomSheet.test.js.map +1 -1
- package/dist/module/lib/Components/BottomSheet/BottomSheetHeader.js +1 -1
- package/dist/module/lib/Components/BottomSheet/BottomSheetHeader.js.map +1 -1
- package/dist/module/lib/Components/BottomSheet/CustomHandle.js +15 -2
- package/dist/module/lib/Components/BottomSheet/CustomHandle.js.map +1 -1
- package/dist/module/lib/Components/Card/Card.js.map +1 -1
- package/dist/module/lib/Components/ListItem/ListItem.js.map +1 -1
- package/dist/module/lib/Components/MediaImage/MediaImage.js +5 -1
- package/dist/module/lib/Components/MediaImage/MediaImage.js.map +1 -1
- package/dist/module/lib/Components/OptionList/OptionList.js +45 -4
- package/dist/module/lib/Components/OptionList/OptionList.js.map +1 -1
- package/dist/module/lib/Components/OptionList/OptionList.mdx +19 -0
- package/dist/module/lib/Components/OptionList/OptionList.stories.js +254 -1
- package/dist/module/lib/Components/OptionList/OptionList.stories.js.map +1 -1
- package/dist/module/lib/Components/OptionList/OptionList.test.js +136 -1
- package/dist/module/lib/Components/OptionList/OptionList.test.js.map +1 -1
- package/dist/module/lib/Components/OptionList/useOptionList/useOptionListItems.js +39 -13
- package/dist/module/lib/Components/OptionList/useOptionList/useOptionListItems.js.map +1 -1
- package/dist/module/lib/Components/OptionList/useOptionList/useOptionListItems.test.js +117 -2
- package/dist/module/lib/Components/OptionList/useOptionList/useOptionListItems.test.js.map +1 -1
- package/dist/module/lib/Components/PageIndicator/PageIndicator.test.js.map +1 -1
- package/dist/module/lib/Components/Skeleton/Skeleton.js +10 -3
- package/dist/module/lib/Components/Skeleton/Skeleton.js.map +1 -1
- package/dist/module/lib/Components/TabBar/TabBar.js +7 -6
- package/dist/module/lib/Components/TabBar/TabBar.js.map +1 -1
- package/dist/module/styles/lx/resolveStyle.js.map +1 -1
- package/dist/typescript/src/index.d.ts +1 -0
- package/dist/typescript/src/index.d.ts.map +1 -1
- package/dist/typescript/src/lib/Animations/Pulse/Pulse.d.ts +1 -1
- package/dist/typescript/src/lib/Animations/Pulse/Pulse.d.ts.map +1 -1
- package/dist/typescript/src/lib/Animations/Pulse/types.d.ts +2 -1
- package/dist/typescript/src/lib/Animations/Pulse/types.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/BottomSheet/BottomSheet.d.ts +1 -1
- package/dist/typescript/src/lib/Components/BottomSheet/BottomSheet.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/BottomSheet/CustomHandle.d.ts +5 -2
- package/dist/typescript/src/lib/Components/BottomSheet/CustomHandle.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/BottomSheet/types.d.ts +16 -3
- package/dist/typescript/src/lib/Components/BottomSheet/types.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/Card/Card.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/ListItem/ListItem.d.ts +3 -3
- package/dist/typescript/src/lib/Components/ListItem/ListItem.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/MediaImage/MediaImage.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/OptionList/OptionList.d.ts +3 -2
- package/dist/typescript/src/lib/Components/OptionList/OptionList.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/OptionList/types.d.ts +42 -5
- package/dist/typescript/src/lib/Components/OptionList/types.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/OptionList/useOptionList/useOptionListItems.d.ts +9 -1
- package/dist/typescript/src/lib/Components/OptionList/useOptionList/useOptionListItems.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/Skeleton/Skeleton.d.ts +1 -1
- package/dist/typescript/src/lib/Components/Skeleton/Skeleton.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/TabBar/TabBar.d.ts.map +1 -1
- package/dist/typescript/src/lib/types/index.d.ts +3 -3
- package/dist/typescript/src/lib/types/index.d.ts.map +1 -1
- package/dist/typescript/src/styles/lx/resolveStyle.d.ts +3 -3
- package/dist/typescript/src/styles/lx/resolveStyle.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/lib/Animations/Pulse/Pulse.tsx +34 -29
- package/src/lib/Animations/Pulse/types.ts +2 -1
- package/src/lib/Components/BottomSheet/BottomSheet.stories.tsx +174 -1
- package/src/lib/Components/BottomSheet/BottomSheet.test.tsx +59 -0
- package/src/lib/Components/BottomSheet/BottomSheet.tsx +19 -7
- package/src/lib/Components/BottomSheet/BottomSheetHeader.tsx +1 -1
- package/src/lib/Components/BottomSheet/CustomHandle.tsx +26 -5
- package/src/lib/Components/BottomSheet/types.ts +24 -3
- package/src/lib/Components/Card/Card.tsx +3 -3
- package/src/lib/Components/ListItem/ListItem.tsx +3 -3
- package/src/lib/Components/MediaImage/MediaImage.tsx +5 -1
- package/src/lib/Components/OptionList/OptionList.mdx +19 -0
- package/src/lib/Components/OptionList/OptionList.stories.tsx +254 -0
- package/src/lib/Components/OptionList/OptionList.test.tsx +143 -0
- package/src/lib/Components/OptionList/OptionList.tsx +49 -3
- package/src/lib/Components/OptionList/types.ts +46 -5
- package/src/lib/Components/OptionList/useOptionList/useOptionListItems.test.ts +124 -2
- package/src/lib/Components/OptionList/useOptionList/useOptionListItems.ts +53 -10
- package/src/lib/Components/PageIndicator/PageIndicator.test.tsx +2 -1
- package/src/lib/Components/Skeleton/Skeleton.tsx +9 -5
- package/src/lib/Components/TabBar/TabBar.tsx +3 -2
- package/src/lib/types/index.ts +3 -3
- package/src/styles/lx/resolveStyle.ts +4 -3
|
@@ -6,7 +6,7 @@ import { StyleSheet } from 'react-native';
|
|
|
6
6
|
import { useStyleSheet } from '../../../styles';
|
|
7
7
|
import { RuntimeConstants } from '../../utils';
|
|
8
8
|
import { CustomBackdrop } from './CustomBackdrop';
|
|
9
|
-
import { CustomHandle } from './CustomHandle';
|
|
9
|
+
import { CustomHandle, HiddenHandle } from './CustomHandle';
|
|
10
10
|
import type { BottomSheetProps } from './types';
|
|
11
11
|
|
|
12
12
|
const OFFSET_TOP = 25;
|
|
@@ -25,7 +25,13 @@ const MAX_DYNAMIC_CONTENT_SIZE = {
|
|
|
25
25
|
fullWithOffset: FULL_WITH_OFFSET,
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
const useStyles = ({
|
|
28
|
+
const useStyles = ({
|
|
29
|
+
shadow,
|
|
30
|
+
hasCustomBackground,
|
|
31
|
+
}: {
|
|
32
|
+
shadow: boolean;
|
|
33
|
+
hasCustomBackground: boolean;
|
|
34
|
+
}) => {
|
|
29
35
|
return useStyleSheet(
|
|
30
36
|
(t) => ({
|
|
31
37
|
root: StyleSheet.flatten([
|
|
@@ -35,7 +41,7 @@ const useStyles = ({ shadow }: { shadow: boolean }) => {
|
|
|
35
41
|
flex: 1,
|
|
36
42
|
borderTopLeftRadius: t.borderRadius.xl,
|
|
37
43
|
borderTopRightRadius: t.borderRadius.xl,
|
|
38
|
-
|
|
44
|
+
overflow: 'hidden',
|
|
39
45
|
},
|
|
40
46
|
shadow && {
|
|
41
47
|
boxShadow: t.shadows.lg,
|
|
@@ -46,7 +52,7 @@ const useStyles = ({ shadow }: { shadow: boolean }) => {
|
|
|
46
52
|
backgroundColor: t.colors.bg.canvasSheet,
|
|
47
53
|
},
|
|
48
54
|
}),
|
|
49
|
-
[shadow],
|
|
55
|
+
[shadow, hasCustomBackground],
|
|
50
56
|
);
|
|
51
57
|
};
|
|
52
58
|
|
|
@@ -74,6 +80,8 @@ export const BottomSheet = ({
|
|
|
74
80
|
onBackdropPress,
|
|
75
81
|
onChange,
|
|
76
82
|
snapPoints = 'fullWithOffset',
|
|
83
|
+
backgroundComponent,
|
|
84
|
+
hideHandle = false,
|
|
77
85
|
ref,
|
|
78
86
|
...props
|
|
79
87
|
}: BottomSheetProps) => {
|
|
@@ -82,7 +90,10 @@ export const BottomSheet = ({
|
|
|
82
90
|
const mergedRefs = useMergedRef<GorhomBottomSheetModal>(ref, innerRef);
|
|
83
91
|
const [isOpen, setIsOpen] = useState(false);
|
|
84
92
|
|
|
85
|
-
const styles = useStyles({
|
|
93
|
+
const styles = useStyles({
|
|
94
|
+
shadow: hideBackdrop && isOpen,
|
|
95
|
+
hasCustomBackground: Boolean(backgroundComponent),
|
|
96
|
+
});
|
|
86
97
|
|
|
87
98
|
/**
|
|
88
99
|
* Match the snap points to the preset or the custom snap points array
|
|
@@ -163,7 +174,8 @@ export const BottomSheet = ({
|
|
|
163
174
|
{...props}
|
|
164
175
|
ref={mergedRefs}
|
|
165
176
|
style={styles.root}
|
|
166
|
-
backgroundStyle={styles.background}
|
|
177
|
+
backgroundStyle={backgroundComponent ? undefined : styles.background}
|
|
178
|
+
backgroundComponent={backgroundComponent}
|
|
167
179
|
onChange={handleChange}
|
|
168
180
|
onAnimate={handleAnimate}
|
|
169
181
|
/**
|
|
@@ -188,7 +200,7 @@ export const BottomSheet = ({
|
|
|
188
200
|
/**
|
|
189
201
|
* Components
|
|
190
202
|
*/
|
|
191
|
-
handleComponent={CustomHandle}
|
|
203
|
+
handleComponent={hideHandle ? HiddenHandle : CustomHandle}
|
|
192
204
|
backdropComponent={hideBackdrop ? undefined : renderBackdrop}
|
|
193
205
|
>
|
|
194
206
|
<BottomSheetProvider value={{ onBack, hideCloseButton }}>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BottomSheetVariables } from '@gorhom/bottom-sheet/lib/typescript/types';
|
|
2
|
-
import type { Ref } from 'react';
|
|
2
|
+
import type { ComponentRef, Ref } from 'react';
|
|
3
3
|
import { View } from 'react-native';
|
|
4
4
|
import { useStyleSheet } from '../../../styles';
|
|
5
5
|
|
|
@@ -12,13 +12,13 @@ const useStyles = () => {
|
|
|
12
12
|
alignItems: 'center',
|
|
13
13
|
justifyContent: 'center',
|
|
14
14
|
alignSelf: 'center',
|
|
15
|
-
backgroundColor:
|
|
15
|
+
backgroundColor: 'transparent',
|
|
16
16
|
},
|
|
17
17
|
handle: {
|
|
18
18
|
height: t.spacings.s4,
|
|
19
19
|
width: t.sizes.s36,
|
|
20
20
|
borderRadius: t.borderRadius.full,
|
|
21
|
-
backgroundColor: t.colors.bg.
|
|
21
|
+
backgroundColor: t.colors.bg.mutedTransparentPressed,
|
|
22
22
|
},
|
|
23
23
|
}),
|
|
24
24
|
[],
|
|
@@ -28,12 +28,33 @@ const useStyles = () => {
|
|
|
28
28
|
export const CustomHandle = ({
|
|
29
29
|
ref,
|
|
30
30
|
...props
|
|
31
|
-
}: BottomSheetVariables & { ref?: Ref<
|
|
31
|
+
}: BottomSheetVariables & { ref?: Ref<ComponentRef<typeof View>> }) => {
|
|
32
32
|
const styles = useStyles();
|
|
33
33
|
|
|
34
34
|
return (
|
|
35
|
-
<View
|
|
35
|
+
<View
|
|
36
|
+
{...props}
|
|
37
|
+
ref={ref}
|
|
38
|
+
style={styles.container}
|
|
39
|
+
testID='bottom-sheet-handle'
|
|
40
|
+
>
|
|
36
41
|
<View style={styles.handle} />
|
|
37
42
|
</View>
|
|
38
43
|
);
|
|
39
44
|
};
|
|
45
|
+
|
|
46
|
+
export const HiddenHandle = ({
|
|
47
|
+
ref,
|
|
48
|
+
...props
|
|
49
|
+
}: BottomSheetVariables & { ref?: Ref<ComponentRef<typeof View>> }) => {
|
|
50
|
+
const styles = useStyles();
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<View
|
|
54
|
+
{...props}
|
|
55
|
+
ref={ref}
|
|
56
|
+
style={styles.container}
|
|
57
|
+
testID='bottom-sheet-handle-hidden'
|
|
58
|
+
/>
|
|
59
|
+
);
|
|
60
|
+
};
|
|
@@ -5,16 +5,23 @@ import type {
|
|
|
5
5
|
BottomSheetSectionList as GorhomBottomSheetSectionList,
|
|
6
6
|
BottomSheetScrollView as GorhomBottomSheetScrollView,
|
|
7
7
|
BottomSheetVirtualizedList as GorhomBottomSheetVirtualizedList,
|
|
8
|
+
BottomSheetBackgroundProps,
|
|
8
9
|
} from '@gorhom/bottom-sheet';
|
|
9
|
-
|
|
10
10
|
import type { Density } from '@ledgerhq/lumen-utils-shared';
|
|
11
|
-
import type {
|
|
11
|
+
import type {
|
|
12
|
+
ComponentRef,
|
|
13
|
+
FC,
|
|
14
|
+
PropsWithChildren,
|
|
15
|
+
ReactNode,
|
|
16
|
+
Ref,
|
|
17
|
+
} from 'react';
|
|
18
|
+
|
|
12
19
|
import type { StyledViewProps } from '../../../styles';
|
|
13
20
|
export type BottomSheetProps = PropsWithChildren & {
|
|
14
21
|
/**
|
|
15
22
|
* Ref to the bottom sheet component.
|
|
16
23
|
*/
|
|
17
|
-
ref?: Ref<
|
|
24
|
+
ref?: Ref<ComponentRef<typeof GorhomBottomSheetModal>>;
|
|
18
25
|
/**
|
|
19
26
|
* Used to locate this view in end-to-end tests.
|
|
20
27
|
*/
|
|
@@ -131,8 +138,22 @@ export type BottomSheetProps = PropsWithChildren & {
|
|
|
131
138
|
* @default true
|
|
132
139
|
*/
|
|
133
140
|
enableBlurKeyboardOnGesture?: boolean;
|
|
141
|
+
/**
|
|
142
|
+
* Custom background component rendered behind the sheet content and handle.
|
|
143
|
+
* Use to render gradients or other effects that should span the full sheet area,
|
|
144
|
+
* including the handle strip. When provided, the default sheet background is removed.
|
|
145
|
+
* @default undefined
|
|
146
|
+
*/
|
|
147
|
+
backgroundComponent?: FC<BottomSheetBackgroundProps> | null;
|
|
148
|
+
/**
|
|
149
|
+
* If true, the drag handle (grabber) at the top of the sheet is hidden.
|
|
150
|
+
* @default false
|
|
151
|
+
*/
|
|
152
|
+
hideHandle?: boolean;
|
|
134
153
|
};
|
|
135
154
|
|
|
155
|
+
export type { BottomSheetBackgroundProps };
|
|
156
|
+
|
|
136
157
|
export type BottomSheetHeaderProps = {
|
|
137
158
|
/**
|
|
138
159
|
* The density of the header.
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
DisabledProvider,
|
|
4
4
|
isTextChildren,
|
|
5
5
|
} from '@ledgerhq/lumen-utils-shared';
|
|
6
|
-
import type { ReactNode, Ref } from 'react';
|
|
6
|
+
import type { ComponentRef, ReactNode, Ref } from 'react';
|
|
7
7
|
import { useCallback, useEffect, useMemo } from 'react';
|
|
8
8
|
import type { LayoutChangeEvent, ViewStyle } from 'react-native';
|
|
9
9
|
import { StyleSheet, View } from 'react-native';
|
|
@@ -486,7 +486,7 @@ export const CardContentTitle = ({
|
|
|
486
486
|
if (isTextChildren(children)) {
|
|
487
487
|
return (
|
|
488
488
|
<Text
|
|
489
|
-
ref={ref as Ref<
|
|
489
|
+
ref={ref as Ref<ComponentRef<typeof Text>>}
|
|
490
490
|
lx={lx}
|
|
491
491
|
style={StyleSheet.flatten([styles.asText, style])}
|
|
492
492
|
numberOfLines={1}
|
|
@@ -553,7 +553,7 @@ export const CardContentDescription = ({
|
|
|
553
553
|
if (isTextChildren(children)) {
|
|
554
554
|
return (
|
|
555
555
|
<Text
|
|
556
|
-
ref={ref as Ref<
|
|
556
|
+
ref={ref as Ref<ComponentRef<typeof Text>>}
|
|
557
557
|
lx={lx}
|
|
558
558
|
style={StyleSheet.flatten([styles.asText, style])}
|
|
559
559
|
numberOfLines={1}
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
DisabledProvider,
|
|
5
5
|
useDisabledContext,
|
|
6
6
|
} from '@ledgerhq/lumen-utils-shared';
|
|
7
|
-
import type {
|
|
7
|
+
import type { ComponentRef, ReactNode, Ref } from 'react';
|
|
8
8
|
import type { ViewStyle } from 'react-native';
|
|
9
9
|
import { StyleSheet, View } from 'react-native';
|
|
10
10
|
import { useStyleSheet } from '../../../styles';
|
|
@@ -286,7 +286,7 @@ export const ListItemTitle = ({
|
|
|
286
286
|
style,
|
|
287
287
|
ref,
|
|
288
288
|
...props
|
|
289
|
-
}: ListItemTitleProps & { ref?: Ref<
|
|
289
|
+
}: ListItemTitleProps & { ref?: Ref<ComponentRef<typeof Text>> }) => {
|
|
290
290
|
const disabled = useDisabledContext({
|
|
291
291
|
consumerName: 'ListItemTitle',
|
|
292
292
|
contextRequired: true,
|
|
@@ -336,7 +336,7 @@ export const ListItemDescription = ({
|
|
|
336
336
|
style,
|
|
337
337
|
ref,
|
|
338
338
|
...props
|
|
339
|
-
}: ListItemDescriptionProps & { ref?: Ref<
|
|
339
|
+
}: ListItemDescriptionProps & { ref?: Ref<ComponentRef<typeof Text>> }) => {
|
|
340
340
|
const disabled = useDisabledContext({
|
|
341
341
|
consumerName: 'ListItemDescription',
|
|
342
342
|
contextRequired: true,
|
|
@@ -66,6 +66,10 @@ const useStyles = ({
|
|
|
66
66
|
width: '100%',
|
|
67
67
|
height: '100%',
|
|
68
68
|
},
|
|
69
|
+
skeleton: {
|
|
70
|
+
width: '100%',
|
|
71
|
+
height: '100%',
|
|
72
|
+
},
|
|
69
73
|
};
|
|
70
74
|
},
|
|
71
75
|
[size, shape],
|
|
@@ -117,7 +121,7 @@ export const MediaImage = ({
|
|
|
117
121
|
accessibilityLabel={alt}
|
|
118
122
|
{...props}
|
|
119
123
|
>
|
|
120
|
-
{loading && <Skeleton style={
|
|
124
|
+
{loading && <Skeleton style={styles.skeleton} />}
|
|
121
125
|
{!loading && shouldFallback && fallback && (
|
|
122
126
|
<Text
|
|
123
127
|
style={{
|
|
@@ -36,6 +36,7 @@ It handles **selection state**, **automatic grouping** (via a `group` field on i
|
|
|
36
36
|
- **OptionListItemContentRow**: Horizontal row for placing elements side-by-side (e.g. title + tag)
|
|
37
37
|
- **OptionListItemText**: Styled title text
|
|
38
38
|
- **OptionListItemDescription**: Styled description text
|
|
39
|
+
- **OptionListSearch**: Search input that filters items by label (default) or via a custom `filter` function
|
|
39
40
|
|
|
40
41
|
## Properties
|
|
41
42
|
|
|
@@ -63,6 +64,24 @@ Combining grouping with rich item content:
|
|
|
63
64
|
|
|
64
65
|
<Canvas of={OptionListStories.GroupedWithContentRow} />
|
|
65
66
|
|
|
67
|
+
### Search
|
|
68
|
+
|
|
69
|
+
Drop `OptionListSearch` inside the list to enable case-insensitive filtering on item labels. Pair with `OptionListEmptyState` to handle no-match scenarios. Pass a custom `filter` to match against meta (or anything else), or `filter={null}` to disable filtering. Use `filteredItems` + `onSearchValueChange` for async/server-side search.
|
|
70
|
+
|
|
71
|
+
<Canvas of={OptionListStories.WithSearch} />
|
|
72
|
+
|
|
73
|
+
Search works within grouped items too. Empty groups are hidden automatically:
|
|
74
|
+
|
|
75
|
+
<Canvas of={OptionListStories.WithSearchAndGroups} />
|
|
76
|
+
|
|
77
|
+
Pass a custom `filter` to match against fields beyond the label. Here, the query also matches each item's ticker via `meta`:
|
|
78
|
+
|
|
79
|
+
<Canvas of={OptionListStories.WithCustomSearchFilter} />
|
|
80
|
+
|
|
81
|
+
Drive the search input from the outside with `searchValue` + `onSearchValueChange`. This is useful for syncing search state with other UI or kicking off async fetches:
|
|
82
|
+
|
|
83
|
+
<Canvas of={OptionListStories.WithControlledSearch} />
|
|
84
|
+
|
|
66
85
|
### Trigger showcase
|
|
67
86
|
|
|
68
87
|
OptionList can be opened from any trigger. `MediaButton` supports multiple appearances (`gray`, `transparent`, `no-background`), optional icons (`flat` / `rounded`), and disabled state:
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
OptionListItemContent,
|
|
23
23
|
OptionListItemDescription,
|
|
24
24
|
OptionListItemContentRow,
|
|
25
|
+
OptionListSearch,
|
|
25
26
|
OptionListTrigger,
|
|
26
27
|
OptionListItemText,
|
|
27
28
|
} from './OptionList';
|
|
@@ -38,6 +39,7 @@ const meta = {
|
|
|
38
39
|
OptionListItemText,
|
|
39
40
|
OptionListItemDescription,
|
|
40
41
|
OptionListItemContentRow,
|
|
42
|
+
OptionListSearch,
|
|
41
43
|
OptionListTrigger,
|
|
42
44
|
},
|
|
43
45
|
decorators: [
|
|
@@ -477,6 +479,258 @@ export const GroupedWithContentRow: Story = {
|
|
|
477
479
|
},
|
|
478
480
|
};
|
|
479
481
|
|
|
482
|
+
export const WithSearch: Story = {
|
|
483
|
+
render: () => {
|
|
484
|
+
const [value, setValue] = useState<string | null>(null);
|
|
485
|
+
const bottomSheetRef = useBottomSheetRef();
|
|
486
|
+
const selected = CURRENCIES.find((c) => c.value === value);
|
|
487
|
+
|
|
488
|
+
return (
|
|
489
|
+
<>
|
|
490
|
+
<OptionListTrigger
|
|
491
|
+
label='Currency'
|
|
492
|
+
onPress={() => bottomSheetRef.current?.present()}
|
|
493
|
+
>
|
|
494
|
+
{selected && <Text lx={{ color: 'base' }}>{selected.label}</Text>}
|
|
495
|
+
</OptionListTrigger>
|
|
496
|
+
<BottomSheet
|
|
497
|
+
ref={bottomSheetRef}
|
|
498
|
+
enableDynamicSizing
|
|
499
|
+
snapPoints={null}
|
|
500
|
+
onClose={() => bottomSheetRef.current?.dismiss()}
|
|
501
|
+
>
|
|
502
|
+
<BottomSheetView>
|
|
503
|
+
<BottomSheetHeader title='Select currency' />
|
|
504
|
+
<OptionList
|
|
505
|
+
items={CURRENCIES}
|
|
506
|
+
value={value}
|
|
507
|
+
onValueChange={(v) => {
|
|
508
|
+
setValue(v);
|
|
509
|
+
bottomSheetRef.current?.dismiss();
|
|
510
|
+
}}
|
|
511
|
+
>
|
|
512
|
+
<OptionListSearch placeholder='Search currencies' />
|
|
513
|
+
<OptionListContent
|
|
514
|
+
renderItem={(item) => {
|
|
515
|
+
const ticker = (item.meta as { ticker: string }).ticker;
|
|
516
|
+
return (
|
|
517
|
+
<OptionListItem value={item.value}>
|
|
518
|
+
<OptionListItemLeading>
|
|
519
|
+
<CryptoIcon
|
|
520
|
+
ledgerId={(item.meta?.ledgerId as string) ?? ''}
|
|
521
|
+
ticker={ticker}
|
|
522
|
+
size={32}
|
|
523
|
+
/>
|
|
524
|
+
</OptionListItemLeading>
|
|
525
|
+
<OptionListItemContent>
|
|
526
|
+
<OptionListItemText>{item.label}</OptionListItemText>
|
|
527
|
+
<OptionListItemDescription>
|
|
528
|
+
{ticker}
|
|
529
|
+
</OptionListItemDescription>
|
|
530
|
+
</OptionListItemContent>
|
|
531
|
+
</OptionListItem>
|
|
532
|
+
);
|
|
533
|
+
}}
|
|
534
|
+
/>
|
|
535
|
+
<OptionListEmptyState
|
|
536
|
+
title='No currencies found'
|
|
537
|
+
description='Try a different search term'
|
|
538
|
+
/>
|
|
539
|
+
</OptionList>
|
|
540
|
+
</BottomSheetView>
|
|
541
|
+
</BottomSheet>
|
|
542
|
+
</>
|
|
543
|
+
);
|
|
544
|
+
},
|
|
545
|
+
};
|
|
546
|
+
|
|
547
|
+
export const WithSearchAndGroups: Story = {
|
|
548
|
+
render: () => {
|
|
549
|
+
const [value, setValue] = useState<string | null>(null);
|
|
550
|
+
const bottomSheetRef = useBottomSheetRef();
|
|
551
|
+
const selected = GROUPED_NETWORKS.find((n) => n.value === value);
|
|
552
|
+
|
|
553
|
+
return (
|
|
554
|
+
<>
|
|
555
|
+
<OptionListTrigger
|
|
556
|
+
label='Network'
|
|
557
|
+
onPress={() => bottomSheetRef.current?.present()}
|
|
558
|
+
>
|
|
559
|
+
{selected && <Text lx={{ color: 'base' }}>{selected.label}</Text>}
|
|
560
|
+
</OptionListTrigger>
|
|
561
|
+
<BottomSheet
|
|
562
|
+
ref={bottomSheetRef}
|
|
563
|
+
enableDynamicSizing
|
|
564
|
+
snapPoints={null}
|
|
565
|
+
onClose={() => bottomSheetRef.current?.dismiss()}
|
|
566
|
+
>
|
|
567
|
+
<BottomSheetScrollView>
|
|
568
|
+
<BottomSheetHeader title='Select network' />
|
|
569
|
+
<OptionList
|
|
570
|
+
items={GROUPED_NETWORKS}
|
|
571
|
+
value={value}
|
|
572
|
+
onValueChange={(v) => {
|
|
573
|
+
setValue(v);
|
|
574
|
+
bottomSheetRef.current?.dismiss();
|
|
575
|
+
}}
|
|
576
|
+
>
|
|
577
|
+
<OptionListSearch placeholder='Search networks' />
|
|
578
|
+
<OptionListContent
|
|
579
|
+
renderItem={(item) => (
|
|
580
|
+
<OptionListItem value={item.value}>
|
|
581
|
+
<OptionListItemContent>
|
|
582
|
+
<OptionListItemText>{item.label}</OptionListItemText>
|
|
583
|
+
</OptionListItemContent>
|
|
584
|
+
</OptionListItem>
|
|
585
|
+
)}
|
|
586
|
+
/>
|
|
587
|
+
<OptionListEmptyState title='No networks found' />
|
|
588
|
+
</OptionList>
|
|
589
|
+
</BottomSheetScrollView>
|
|
590
|
+
</BottomSheet>
|
|
591
|
+
</>
|
|
592
|
+
);
|
|
593
|
+
},
|
|
594
|
+
};
|
|
595
|
+
|
|
596
|
+
export const WithCustomSearchFilter: Story = {
|
|
597
|
+
render: () => {
|
|
598
|
+
const [value, setValue] = useState<string | null>(null);
|
|
599
|
+
const bottomSheetRef = useBottomSheetRef();
|
|
600
|
+
const selected = CURRENCIES.find((c) => c.value === value);
|
|
601
|
+
|
|
602
|
+
return (
|
|
603
|
+
<>
|
|
604
|
+
<OptionListTrigger
|
|
605
|
+
label='Currency'
|
|
606
|
+
onPress={() => bottomSheetRef.current?.present()}
|
|
607
|
+
>
|
|
608
|
+
{selected && <Text lx={{ color: 'base' }}>{selected.label}</Text>}
|
|
609
|
+
</OptionListTrigger>
|
|
610
|
+
<BottomSheet
|
|
611
|
+
ref={bottomSheetRef}
|
|
612
|
+
enableDynamicSizing
|
|
613
|
+
snapPoints={null}
|
|
614
|
+
onClose={() => bottomSheetRef.current?.dismiss()}
|
|
615
|
+
>
|
|
616
|
+
<BottomSheetView>
|
|
617
|
+
<BottomSheetHeader title='Select currency' />
|
|
618
|
+
<OptionList
|
|
619
|
+
items={CURRENCIES}
|
|
620
|
+
value={value}
|
|
621
|
+
onValueChange={(v) => {
|
|
622
|
+
setValue(v);
|
|
623
|
+
bottomSheetRef.current?.dismiss();
|
|
624
|
+
}}
|
|
625
|
+
filter={(item, query) => {
|
|
626
|
+
const q = query.toLowerCase();
|
|
627
|
+
const ticker = (item.meta as { ticker: string }).ticker;
|
|
628
|
+
return (
|
|
629
|
+
item.label.toLowerCase().includes(q) ||
|
|
630
|
+
ticker.toLowerCase().includes(q)
|
|
631
|
+
);
|
|
632
|
+
}}
|
|
633
|
+
>
|
|
634
|
+
<OptionListSearch placeholder='Search by name or ticker' />
|
|
635
|
+
<OptionListContent
|
|
636
|
+
renderItem={(item) => {
|
|
637
|
+
const ticker = (item.meta as { ticker: string }).ticker;
|
|
638
|
+
return (
|
|
639
|
+
<OptionListItem value={item.value}>
|
|
640
|
+
<OptionListItemLeading>
|
|
641
|
+
<CryptoIcon
|
|
642
|
+
ledgerId={(item.meta?.ledgerId as string) ?? ''}
|
|
643
|
+
ticker={ticker}
|
|
644
|
+
size={32}
|
|
645
|
+
/>
|
|
646
|
+
</OptionListItemLeading>
|
|
647
|
+
<OptionListItemContent>
|
|
648
|
+
<OptionListItemText>{item.label}</OptionListItemText>
|
|
649
|
+
<OptionListItemDescription>
|
|
650
|
+
{ticker}
|
|
651
|
+
</OptionListItemDescription>
|
|
652
|
+
</OptionListItemContent>
|
|
653
|
+
</OptionListItem>
|
|
654
|
+
);
|
|
655
|
+
}}
|
|
656
|
+
/>
|
|
657
|
+
<OptionListEmptyState title='No currencies found' />
|
|
658
|
+
</OptionList>
|
|
659
|
+
</BottomSheetView>
|
|
660
|
+
</BottomSheet>
|
|
661
|
+
</>
|
|
662
|
+
);
|
|
663
|
+
},
|
|
664
|
+
};
|
|
665
|
+
|
|
666
|
+
export const WithControlledSearch: Story = {
|
|
667
|
+
render: () => {
|
|
668
|
+
const [value, setValue] = useState<string | null>(null);
|
|
669
|
+
const [searchValue, setSearchValue] = useState('');
|
|
670
|
+
const bottomSheetRef = useBottomSheetRef();
|
|
671
|
+
const selected = CURRENCIES.find((c) => c.value === value);
|
|
672
|
+
|
|
673
|
+
return (
|
|
674
|
+
<>
|
|
675
|
+
<OptionListTrigger
|
|
676
|
+
label='Currency'
|
|
677
|
+
onPress={() => bottomSheetRef.current?.present()}
|
|
678
|
+
>
|
|
679
|
+
{selected && <Text lx={{ color: 'base' }}>{selected.label}</Text>}
|
|
680
|
+
</OptionListTrigger>
|
|
681
|
+
<BottomSheet
|
|
682
|
+
ref={bottomSheetRef}
|
|
683
|
+
enableDynamicSizing
|
|
684
|
+
snapPoints={null}
|
|
685
|
+
onClose={() => bottomSheetRef.current?.dismiss()}
|
|
686
|
+
>
|
|
687
|
+
<BottomSheetView>
|
|
688
|
+
<BottomSheetHeader title='Select currency' />
|
|
689
|
+
<Box lx={{ padding: 's8' }}>
|
|
690
|
+
<Text lx={{ color: 'muted' }}>Search: "{searchValue}"</Text>
|
|
691
|
+
</Box>
|
|
692
|
+
<OptionList
|
|
693
|
+
items={CURRENCIES}
|
|
694
|
+
value={value}
|
|
695
|
+
onValueChange={(v) => {
|
|
696
|
+
setValue(v);
|
|
697
|
+
bottomSheetRef.current?.dismiss();
|
|
698
|
+
}}
|
|
699
|
+
searchValue={searchValue}
|
|
700
|
+
onSearchValueChange={setSearchValue}
|
|
701
|
+
>
|
|
702
|
+
<OptionListSearch placeholder='Search currencies' />
|
|
703
|
+
<OptionListContent
|
|
704
|
+
renderItem={(item) => {
|
|
705
|
+
const ticker = (item.meta as { ticker: string }).ticker;
|
|
706
|
+
return (
|
|
707
|
+
<OptionListItem value={item.value}>
|
|
708
|
+
<OptionListItemLeading>
|
|
709
|
+
<CryptoIcon
|
|
710
|
+
ledgerId={(item.meta?.ledgerId as string) ?? ''}
|
|
711
|
+
ticker={ticker}
|
|
712
|
+
size={32}
|
|
713
|
+
/>
|
|
714
|
+
</OptionListItemLeading>
|
|
715
|
+
<OptionListItemContent>
|
|
716
|
+
<OptionListItemText>{item.label}</OptionListItemText>
|
|
717
|
+
<OptionListItemDescription>
|
|
718
|
+
{ticker}
|
|
719
|
+
</OptionListItemDescription>
|
|
720
|
+
</OptionListItemContent>
|
|
721
|
+
</OptionListItem>
|
|
722
|
+
);
|
|
723
|
+
}}
|
|
724
|
+
/>
|
|
725
|
+
<OptionListEmptyState title='No currencies found' />
|
|
726
|
+
</OptionList>
|
|
727
|
+
</BottomSheetView>
|
|
728
|
+
</BottomSheet>
|
|
729
|
+
</>
|
|
730
|
+
);
|
|
731
|
+
},
|
|
732
|
+
};
|
|
733
|
+
|
|
480
734
|
export const EmptyState: Story = {
|
|
481
735
|
render: () => {
|
|
482
736
|
const bottomSheetRef = useBottomSheetRef();
|