@ledgerhq/lumen-ui-rnative 0.1.21 → 0.1.23
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/lib/Components/ListItem/ListItem.js +57 -27
- package/dist/module/lib/Components/ListItem/ListItem.js.map +1 -1
- package/dist/module/lib/Components/ListItem/ListItem.mdx +15 -7
- package/dist/module/lib/Components/ListItem/ListItem.stories.js +497 -283
- package/dist/module/lib/Components/ListItem/ListItem.stories.js.map +1 -1
- package/dist/module/lib/Components/ListItem/ListItem.test.js +153 -0
- package/dist/module/lib/Components/ListItem/ListItem.test.js.map +1 -0
- package/dist/module/lib/Components/{TriggerButton/TriggerButton.js → MediaButton/MediaButton.js} +13 -10
- package/dist/module/lib/Components/MediaButton/MediaButton.js.map +1 -0
- package/{src/lib/Components/TriggerButton/TriggerButton.mdx → dist/module/lib/Components/MediaButton/MediaButton.mdx} +10 -10
- package/dist/module/lib/Components/{TriggerButton/TriggerButton.stories.js → MediaButton/MediaButton.stories.js} +18 -18
- package/dist/module/lib/Components/MediaButton/MediaButton.stories.js.map +1 -0
- package/dist/module/lib/Components/{TriggerButton/TriggerButton.test.js → MediaButton/MediaButton.test.js} +14 -14
- package/dist/module/lib/Components/MediaButton/MediaButton.test.js.map +1 -0
- package/dist/module/lib/Components/MediaButton/index.js +5 -0
- package/dist/module/lib/Components/MediaButton/index.js.map +1 -0
- package/dist/module/lib/Components/MediaButton/types.js.map +1 -0
- package/dist/module/lib/Components/NavBar/NavBar.js +0 -2
- package/dist/module/lib/Components/NavBar/NavBar.js.map +1 -1
- package/dist/module/lib/Components/OptionList/OptionList.figma.js +28 -0
- package/dist/module/lib/Components/OptionList/OptionList.figma.js.map +1 -0
- package/dist/module/lib/Components/OptionList/OptionList.js +452 -0
- package/dist/module/lib/Components/OptionList/OptionList.js.map +1 -0
- package/dist/module/lib/Components/OptionList/OptionList.mdx +304 -0
- package/dist/module/lib/Components/OptionList/OptionList.stories.js +735 -0
- package/dist/module/lib/Components/OptionList/OptionList.stories.js.map +1 -0
- package/dist/module/lib/Components/OptionList/OptionList.test.js +443 -0
- package/dist/module/lib/Components/OptionList/OptionList.test.js.map +1 -0
- package/dist/module/lib/Components/OptionList/index.js +5 -0
- package/dist/module/lib/Components/OptionList/index.js.map +1 -0
- package/dist/module/lib/Components/OptionList/types.js +4 -0
- package/dist/module/lib/Components/OptionList/types.js.map +1 -0
- package/dist/module/lib/Components/OptionList/useOptionList/useOptionListItems.js +36 -0
- package/dist/module/lib/Components/OptionList/useOptionList/useOptionListItems.js.map +1 -0
- package/dist/module/lib/Components/OptionList/useOptionList/useOptionListItems.test.js +84 -0
- package/dist/module/lib/Components/OptionList/useOptionList/useOptionListItems.test.js.map +1 -0
- package/dist/module/lib/Components/index.js +2 -1
- package/dist/module/lib/Components/index.js.map +1 -1
- package/dist/typescript/src/lib/Components/ListItem/ListItem.d.ts +8 -8
- package/dist/typescript/src/lib/Components/ListItem/ListItem.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/ListItem/types.d.ts +11 -7
- package/dist/typescript/src/lib/Components/ListItem/types.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/MediaButton/MediaButton.d.ts +23 -0
- package/dist/typescript/src/lib/Components/MediaButton/MediaButton.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/MediaButton/index.d.ts +3 -0
- package/dist/typescript/src/lib/Components/MediaButton/index.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/{TriggerButton → MediaButton}/types.d.ts +10 -5
- package/dist/typescript/src/lib/Components/MediaButton/types.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/OptionList/OptionList.d.ts +12 -0
- package/dist/typescript/src/lib/Components/OptionList/OptionList.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/OptionList/OptionList.figma.d.ts +2 -0
- package/dist/typescript/src/lib/Components/OptionList/OptionList.figma.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/OptionList/index.d.ts +3 -0
- package/dist/typescript/src/lib/Components/OptionList/index.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/OptionList/types.d.ts +97 -0
- package/dist/typescript/src/lib/Components/OptionList/types.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/OptionList/useOptionList/useOptionListItems.d.ts +12 -0
- package/dist/typescript/src/lib/Components/OptionList/useOptionList/useOptionListItems.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/index.d.ts +2 -1
- package/dist/typescript/src/lib/Components/index.d.ts.map +1 -1
- package/dist/typescript/src/styles/types/theme.types.d.ts +7 -6
- package/dist/typescript/src/styles/types/theme.types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/lib/Components/ListItem/ListItem.mdx +15 -7
- package/src/lib/Components/ListItem/ListItem.stories.tsx +354 -220
- package/src/lib/Components/ListItem/ListItem.test.tsx +152 -0
- package/src/lib/Components/ListItem/ListItem.tsx +63 -28
- package/src/lib/Components/ListItem/types.ts +11 -8
- package/{dist/module/lib/Components/TriggerButton/TriggerButton.mdx → src/lib/Components/MediaButton/MediaButton.mdx} +10 -10
- package/src/lib/Components/{TriggerButton/TriggerButton.stories.tsx → MediaButton/MediaButton.stories.tsx} +28 -28
- package/src/lib/Components/{TriggerButton/TriggerButton.test.tsx → MediaButton/MediaButton.test.tsx} +22 -22
- package/src/lib/Components/{TriggerButton/TriggerButton.tsx → MediaButton/MediaButton.tsx} +27 -21
- package/src/lib/Components/MediaButton/index.ts +2 -0
- package/src/lib/Components/{TriggerButton → MediaButton}/types.ts +10 -5
- package/src/lib/Components/NavBar/NavBar.tsx +0 -3
- package/src/lib/Components/OptionList/OptionList.figma.tsx +37 -0
- package/src/lib/Components/OptionList/OptionList.mdx +304 -0
- package/src/lib/Components/OptionList/OptionList.stories.tsx +755 -0
- package/src/lib/Components/OptionList/OptionList.test.tsx +412 -0
- package/src/lib/Components/OptionList/OptionList.tsx +532 -0
- package/src/lib/Components/OptionList/index.ts +2 -0
- package/src/lib/Components/OptionList/types.ts +115 -0
- package/src/lib/Components/OptionList/useOptionList/useOptionListItems.test.ts +73 -0
- package/src/lib/Components/OptionList/useOptionList/useOptionListItems.ts +49 -0
- package/src/lib/Components/index.ts +2 -1
- package/src/styles/types/theme.types.ts +8 -6
- package/dist/module/lib/Components/TriggerButton/TriggerButton.js.map +0 -1
- package/dist/module/lib/Components/TriggerButton/TriggerButton.stories.js.map +0 -1
- package/dist/module/lib/Components/TriggerButton/TriggerButton.test.js.map +0 -1
- package/dist/module/lib/Components/TriggerButton/index.js +0 -5
- package/dist/module/lib/Components/TriggerButton/index.js.map +0 -1
- package/dist/module/lib/Components/TriggerButton/types.js.map +0 -1
- package/dist/typescript/src/lib/Components/TriggerButton/TriggerButton.d.ts +0 -23
- package/dist/typescript/src/lib/Components/TriggerButton/TriggerButton.d.ts.map +0 -1
- package/dist/typescript/src/lib/Components/TriggerButton/index.d.ts +0 -3
- package/dist/typescript/src/lib/Components/TriggerButton/index.d.ts.map +0 -1
- package/dist/typescript/src/lib/Components/TriggerButton/types.d.ts.map +0 -1
- package/src/lib/Components/TriggerButton/index.ts +0 -2
- /package/dist/module/lib/Components/{TriggerButton → MediaButton}/types.js +0 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import { Meta, Canvas } from '@storybook/addon-docs/blocks';
|
|
2
|
+
import * as OptionListStories from './OptionList.stories';
|
|
3
|
+
import {
|
|
4
|
+
CustomTabs,
|
|
5
|
+
Tab,
|
|
6
|
+
DoVsDontRow,
|
|
7
|
+
DoBlockItem,
|
|
8
|
+
DontBlockItem,
|
|
9
|
+
} from '../../../../.storybook/components';
|
|
10
|
+
|
|
11
|
+
<Meta title='Selection/OptionList' of={OptionListStories} />
|
|
12
|
+
|
|
13
|
+
# OptionList
|
|
14
|
+
|
|
15
|
+
<CustomTabs>
|
|
16
|
+
<Tab label="Overview">
|
|
17
|
+
|
|
18
|
+
## Introduction
|
|
19
|
+
|
|
20
|
+
OptionList is a data-driven, composable selection list designed to be embedded inside a `BottomSheet`, a new screen, or any container. Unlike `Select`, it does not manage its own trigger or modal — consumers compose it within their own layout.
|
|
21
|
+
|
|
22
|
+
It handles **selection state**, **automatic grouping** (via a `group` field on items), and exposes a `renderItem` callback for full control over item rendering.
|
|
23
|
+
|
|
24
|
+
> View in [Figma](https://www.figma.com/design/JxaLVMTWirCpU0rsbZ30k7/2.-Components-Library?node-id=15941-6709&m=dev).
|
|
25
|
+
|
|
26
|
+
## Anatomy
|
|
27
|
+
|
|
28
|
+
<Canvas of={OptionListStories.Base} />
|
|
29
|
+
|
|
30
|
+
- **OptionList**: Root component managing selection state and item processing
|
|
31
|
+
- **OptionListTrigger**: Input-style trigger with floating label and chevron — displays the selected value and opens a BottomSheet on press
|
|
32
|
+
- **OptionListContent**: Iterates items, renders group labels and separators automatically, calls `renderItem`
|
|
33
|
+
- **OptionListItem**: Pressable item with selection check mark
|
|
34
|
+
- **OptionListItemLeading**: Slot for leading visuals (icons, avatars)
|
|
35
|
+
- **OptionListItemContent**: Flex column for title + description
|
|
36
|
+
- **OptionListItemContentRow**: Horizontal row for placing elements side-by-side (e.g. title + tag)
|
|
37
|
+
- **OptionListItemText**: Styled title text
|
|
38
|
+
- **OptionListItemDescription**: Styled description text
|
|
39
|
+
|
|
40
|
+
## Properties
|
|
41
|
+
|
|
42
|
+
### Grouped items
|
|
43
|
+
|
|
44
|
+
Items with a `group` field are automatically grouped with labels and separators:
|
|
45
|
+
|
|
46
|
+
<Canvas of={OptionListStories.WithGroups} />
|
|
47
|
+
|
|
48
|
+
### Complex item layout
|
|
49
|
+
|
|
50
|
+
Use `OptionListItemContentRow` to place a `Tag` next to the title:
|
|
51
|
+
|
|
52
|
+
<Canvas of={OptionListStories.WithContentRow} />
|
|
53
|
+
|
|
54
|
+
### Disabled items
|
|
55
|
+
|
|
56
|
+
Individual items can be disabled:
|
|
57
|
+
|
|
58
|
+
<Canvas of={OptionListStories.WithDisabledItems} />
|
|
59
|
+
|
|
60
|
+
### Groups + complex layout
|
|
61
|
+
|
|
62
|
+
Combining grouping with rich item content:
|
|
63
|
+
|
|
64
|
+
<Canvas of={OptionListStories.GroupedWithContentRow} />
|
|
65
|
+
|
|
66
|
+
### Trigger showcase
|
|
67
|
+
|
|
68
|
+
OptionList can be opened from any trigger. `MediaButton` supports multiple appearances (`gray`, `transparent`, `no-background`), optional icons (`flat` / `rounded`), and disabled state:
|
|
69
|
+
|
|
70
|
+
<Canvas of={OptionListStories.TriggerShowcase} />
|
|
71
|
+
|
|
72
|
+
</Tab>
|
|
73
|
+
<Tab label="Implementation">
|
|
74
|
+
|
|
75
|
+
## Setup
|
|
76
|
+
|
|
77
|
+
Install and set up the library with our [Setup Guide →](?path=/docs/getting-started-setup--docs).
|
|
78
|
+
|
|
79
|
+
## Basic usage
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
import {
|
|
83
|
+
OptionList,
|
|
84
|
+
OptionListContent,
|
|
85
|
+
OptionListItem,
|
|
86
|
+
OptionListItemContent,
|
|
87
|
+
OptionListItemText,
|
|
88
|
+
} from '@ledgerhq/lumen-ui-rnative';
|
|
89
|
+
|
|
90
|
+
const items = [
|
|
91
|
+
{ value: 'a', label: 'Option A' },
|
|
92
|
+
{ value: 'b', label: 'Option B' },
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
function MyList() {
|
|
96
|
+
const [value, setValue] = useState<string | null>(null);
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<OptionList items={items} value={value} onValueChange={setValue}>
|
|
100
|
+
<OptionListContent
|
|
101
|
+
renderItem={(item) => (
|
|
102
|
+
<OptionListItem value={item.value}>
|
|
103
|
+
<OptionListItemContent>
|
|
104
|
+
<OptionListItemText>{item.label}</OptionListItemText>
|
|
105
|
+
</OptionListItemContent>
|
|
106
|
+
</OptionListItem>
|
|
107
|
+
)}
|
|
108
|
+
/>
|
|
109
|
+
</OptionList>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Inside a BottomSheet
|
|
115
|
+
|
|
116
|
+
Use `OptionListTrigger` as the input-style trigger — it provides a floating label that animates up when a value is selected, and a chevron indicator. Pass children only when a value is selected so the label stays centered when empty.
|
|
117
|
+
|
|
118
|
+
```tsx
|
|
119
|
+
import {
|
|
120
|
+
OptionList, OptionListContent, OptionListItem,
|
|
121
|
+
OptionListItemContent, OptionListItemText, OptionListTrigger,
|
|
122
|
+
BottomSheet, BottomSheetHeader, BottomSheetView,
|
|
123
|
+
useBottomSheetRef, Text,
|
|
124
|
+
} from '@ledgerhq/lumen-ui-rnative';
|
|
125
|
+
|
|
126
|
+
function CurrencyPicker() {
|
|
127
|
+
const [value, setValue] = useState<string | null>(null);
|
|
128
|
+
const ref = useBottomSheetRef();
|
|
129
|
+
const selected = items.find((i) => i.value === value);
|
|
130
|
+
|
|
131
|
+
return (
|
|
132
|
+
<>
|
|
133
|
+
<OptionListTrigger
|
|
134
|
+
label='Currency'
|
|
135
|
+
onPress={() => ref.current?.present()}
|
|
136
|
+
>
|
|
137
|
+
{selected && <Text lx={{ color: 'base' }}>{selected.label}</Text>}
|
|
138
|
+
</OptionListTrigger>
|
|
139
|
+
<BottomSheet
|
|
140
|
+
ref={ref}
|
|
141
|
+
enableDynamicSizing
|
|
142
|
+
snapPoints={null}
|
|
143
|
+
onClose={() => ref.current?.dismiss()}
|
|
144
|
+
>
|
|
145
|
+
<BottomSheetView>
|
|
146
|
+
<BottomSheetHeader title='Pick a currency' />
|
|
147
|
+
<OptionList
|
|
148
|
+
items={items}
|
|
149
|
+
value={value}
|
|
150
|
+
onValueChange={(v) => { setValue(v); ref.current?.dismiss(); }}
|
|
151
|
+
>
|
|
152
|
+
<OptionListContent
|
|
153
|
+
renderItem={(item) => (
|
|
154
|
+
<OptionListItem value={item.value}>
|
|
155
|
+
<OptionListItemContent>
|
|
156
|
+
<OptionListItemText>{item.label}</OptionListItemText>
|
|
157
|
+
</OptionListItemContent>
|
|
158
|
+
</OptionListItem>
|
|
159
|
+
)}
|
|
160
|
+
/>
|
|
161
|
+
</OptionList>
|
|
162
|
+
</BottomSheetView>
|
|
163
|
+
</BottomSheet>
|
|
164
|
+
</>
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Grouping
|
|
170
|
+
|
|
171
|
+
Add a `group` field to items — labels and separators are rendered automatically:
|
|
172
|
+
|
|
173
|
+
```tsx
|
|
174
|
+
const items = [
|
|
175
|
+
{ value: 'btc', label: 'Bitcoin', group: 'Crypto' },
|
|
176
|
+
{ value: 'eth', label: 'Ethereum', group: 'Crypto' },
|
|
177
|
+
{ value: 'usd', label: 'US Dollar', group: 'Fiat' },
|
|
178
|
+
];
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Controlled vs uncontrolled
|
|
182
|
+
|
|
183
|
+
Use `value` + `onValueChange` (controlled) when OptionList is inside a BottomSheet — the sheet unmounts children on dismiss, so internal state is lost. Use `defaultValue` (uncontrolled) only when the component stays mounted (e.g. inline in a screen).
|
|
184
|
+
|
|
185
|
+
## Custom item layout with meta
|
|
186
|
+
|
|
187
|
+
Use `meta` for arbitrary data, and sub-components for layout:
|
|
188
|
+
|
|
189
|
+
```tsx
|
|
190
|
+
const items = [
|
|
191
|
+
{ value: 'eth', label: 'Ethereum', meta: { ticker: 'ETH', tag: 'ERC-20' } },
|
|
192
|
+
];
|
|
193
|
+
|
|
194
|
+
<OptionListContent
|
|
195
|
+
renderItem={(item) => {
|
|
196
|
+
const meta = item.meta as { ticker: string; tag: string };
|
|
197
|
+
return (
|
|
198
|
+
<OptionListItem value={item.value}>
|
|
199
|
+
<OptionListItemLeading>
|
|
200
|
+
<Spot appearance='icon' icon={Wallet} />
|
|
201
|
+
</OptionListItemLeading>
|
|
202
|
+
<OptionListItemContent>
|
|
203
|
+
<OptionListItemContentRow>
|
|
204
|
+
<OptionListItemText>{item.label}</OptionListItemText>
|
|
205
|
+
<Tag label={meta.tag} appearance='gray' size='sm' />
|
|
206
|
+
</OptionListItemContentRow>
|
|
207
|
+
<OptionListItemDescription>{meta.ticker}</OptionListItemDescription>
|
|
208
|
+
</OptionListItemContent>
|
|
209
|
+
</OptionListItem>
|
|
210
|
+
);
|
|
211
|
+
}}
|
|
212
|
+
/>
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Do's and Don'ts
|
|
216
|
+
|
|
217
|
+
<div className='flex flex-col gap-24'>
|
|
218
|
+
|
|
219
|
+
<DoVsDontRow>
|
|
220
|
+
<DoBlockItem
|
|
221
|
+
title='Pass items as a flat array'
|
|
222
|
+
description='Use the group field for grouping — the component handles labels and separators automatically.'
|
|
223
|
+
>
|
|
224
|
+
|
|
225
|
+
{/* prettier-ignore */}
|
|
226
|
+
```tsx
|
|
227
|
+
<OptionList
|
|
228
|
+
items={[
|
|
229
|
+
{ value: 'a', label: 'A', group: 'Group 1' },
|
|
230
|
+
{ value: 'b', label: 'B', group: 'Group 2' },
|
|
231
|
+
]}
|
|
232
|
+
value={value}
|
|
233
|
+
onValueChange={setValue}
|
|
234
|
+
>
|
|
235
|
+
<OptionListContent renderItem={...} />
|
|
236
|
+
</OptionList>
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
</DoBlockItem>
|
|
240
|
+
<DontBlockItem
|
|
241
|
+
title="Don't manually render group labels or separators"
|
|
242
|
+
description='OptionListContent handles group rendering internally based on item data.'
|
|
243
|
+
>
|
|
244
|
+
|
|
245
|
+
{/* prettier-ignore */}
|
|
246
|
+
```tsx
|
|
247
|
+
<OptionList
|
|
248
|
+
items={items}
|
|
249
|
+
value={value}
|
|
250
|
+
onValueChange={setValue}
|
|
251
|
+
>
|
|
252
|
+
<Text>Group 1</Text>
|
|
253
|
+
<OptionListContent renderItem={...} />
|
|
254
|
+
<Divider />
|
|
255
|
+
<Text>Group 2</Text>
|
|
256
|
+
<OptionListContent renderItem={...} />
|
|
257
|
+
</OptionList>
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
</DontBlockItem>
|
|
261
|
+
</DoVsDontRow>
|
|
262
|
+
|
|
263
|
+
<DoVsDontRow>
|
|
264
|
+
<DoBlockItem
|
|
265
|
+
title='Compose OptionList inside your own container'
|
|
266
|
+
description='OptionList is display-only — wrap it in a BottomSheet, screen, or any layout.'
|
|
267
|
+
>
|
|
268
|
+
|
|
269
|
+
{/* prettier-ignore */}
|
|
270
|
+
```tsx
|
|
271
|
+
<BottomSheet ref={ref}>
|
|
272
|
+
<BottomSheetView>
|
|
273
|
+
<OptionList items={items} value={value} onValueChange={setValue}>
|
|
274
|
+
<OptionListContent renderItem={...} />
|
|
275
|
+
</OptionList>
|
|
276
|
+
</BottomSheetView>
|
|
277
|
+
</BottomSheet>
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
</DoBlockItem>
|
|
281
|
+
<DontBlockItem
|
|
282
|
+
title="Don't expect OptionList to manage the BottomSheet"
|
|
283
|
+
description='Use OptionListTrigger to open the sheet yourself — OptionList only handles selection state, not the container.'
|
|
284
|
+
>
|
|
285
|
+
|
|
286
|
+
{/* prettier-ignore */}
|
|
287
|
+
```tsx
|
|
288
|
+
<OptionList
|
|
289
|
+
items={items}
|
|
290
|
+
value={value}
|
|
291
|
+
onValueChange={setValue}
|
|
292
|
+
trigger={<Button>Open</Button>}
|
|
293
|
+
>
|
|
294
|
+
<OptionListContent renderItem={...} />
|
|
295
|
+
</OptionList>
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
</DontBlockItem>
|
|
299
|
+
</DoVsDontRow>
|
|
300
|
+
|
|
301
|
+
</div>
|
|
302
|
+
|
|
303
|
+
</Tab>
|
|
304
|
+
</CustomTabs>
|