@delightui/components 0.1.104 → 0.1.106
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/README.md +104 -1
- package/dist/cjs/components/molecules/Modal/DemoModal.d.ts +8 -0
- package/dist/cjs/components/molecules/Modal/ModalContext/ModalContext.d.ts +41 -0
- package/dist/cjs/components/molecules/Modal/ModalContext/ModalContext.types.d.ts +87 -0
- package/dist/cjs/components/molecules/Modal/ModalContext/index.d.ts +3 -0
- package/dist/cjs/components/molecules/Modal/ModalContext/useModal.d.ts +34 -0
- package/dist/cjs/components/molecules/Modal/index.d.ts +2 -0
- package/dist/cjs/components/molecules/Popover/Popover.presenter.d.ts +26 -0
- package/dist/cjs/components/molecules/Select/Option/Option.types.d.ts +6 -0
- package/dist/cjs/components/molecules/Select/Select.Context.d.ts +1 -1
- package/dist/cjs/components/molecules/Select/Select.d.ts +5 -5
- package/dist/cjs/components/molecules/Select/Select.presenter.d.ts +1 -0
- package/dist/cjs/components/molecules/Select/Select.types.d.ts +5 -0
- package/dist/cjs/components/molecules/Select/index.d.ts +2 -9
- package/dist/cjs/components/molecules/index.d.ts +2 -0
- package/dist/cjs/components/utils/accessibilityUtils.d.ts +41 -0
- package/dist/cjs/components/utils/index.d.ts +2 -0
- package/dist/cjs/library.css +13 -0
- package/dist/cjs/library.js +2 -2
- package/dist/cjs/library.js.map +1 -1
- package/dist/esm/components/molecules/Modal/DemoModal.d.ts +8 -0
- package/dist/esm/components/molecules/Modal/ModalContext/ModalContext.d.ts +41 -0
- package/dist/esm/components/molecules/Modal/ModalContext/ModalContext.types.d.ts +87 -0
- package/dist/esm/components/molecules/Modal/ModalContext/index.d.ts +3 -0
- package/dist/esm/components/molecules/Modal/ModalContext/useModal.d.ts +34 -0
- package/dist/esm/components/molecules/Modal/index.d.ts +2 -0
- package/dist/esm/components/molecules/Popover/Popover.presenter.d.ts +26 -0
- package/dist/esm/components/molecules/Select/Option/Option.types.d.ts +6 -0
- package/dist/esm/components/molecules/Select/Select.Context.d.ts +1 -1
- package/dist/esm/components/molecules/Select/Select.d.ts +5 -5
- package/dist/esm/components/molecules/Select/Select.presenter.d.ts +1 -0
- package/dist/esm/components/molecules/Select/Select.types.d.ts +5 -0
- package/dist/esm/components/molecules/Select/index.d.ts +2 -9
- package/dist/esm/components/molecules/index.d.ts +2 -0
- package/dist/esm/components/utils/accessibilityUtils.d.ts +41 -0
- package/dist/esm/components/utils/index.d.ts +2 -0
- package/dist/esm/library.css +13 -0
- package/dist/esm/library.js +3 -3
- package/dist/esm/library.js.map +1 -1
- package/dist/index.d.ts +156 -12
- package/docs/README.md +264 -0
- package/docs/components/atoms/ActionImage.md +119 -0
- package/docs/components/atoms/Button.md +197 -0
- package/docs/components/atoms/Checkbox.md +299 -0
- package/docs/components/atoms/CheckboxItem.md +314 -0
- package/docs/components/atoms/Chip.md +380 -0
- package/docs/components/atoms/CustomToggle.md +270 -0
- package/docs/components/atoms/Icon.md +365 -0
- package/docs/components/atoms/IconButton.md +407 -0
- package/docs/components/atoms/Image.md +448 -0
- package/docs/components/atoms/Input.md +430 -0
- package/docs/components/atoms/ListItem.md +502 -0
- package/docs/components/atoms/Password.md +472 -0
- package/docs/components/atoms/RadioButton.md +614 -0
- package/docs/components/atoms/RadioButtonItem.md +588 -0
- package/docs/components/atoms/ResponsiveComponent.md +612 -0
- package/docs/components/atoms/SelectListItem.md +609 -0
- package/docs/components/atoms/Slider.md +605 -0
- package/docs/components/atoms/Spinner.md +605 -0
- package/docs/components/atoms/Text.md +463 -0
- package/docs/components/atoms/TextArea.md +670 -0
- package/docs/components/atoms/ToastNotification.md +668 -0
- package/docs/components/atoms/Toggle.md +737 -0
- package/docs/components/atoms/ToggleButton.md +751 -0
- package/docs/components/atoms/Tooltip.md +391 -0
- package/docs/components/molecules/Accordion.md +440 -0
- package/docs/components/molecules/AccordionGroup.md +547 -0
- package/docs/components/molecules/ActionCard.md +546 -0
- package/docs/components/molecules/Breadcrumb.md +403 -0
- package/docs/components/molecules/Breadcrumbs.md +485 -0
- package/docs/components/molecules/ButtonGroup.md +383 -0
- package/docs/components/molecules/Card.md +298 -0
- package/docs/components/molecules/ChipInput.md +646 -0
- package/docs/components/molecules/ContextMenu.md +768 -0
- package/docs/components/molecules/CustomTimeSelector.md +116 -0
- package/docs/components/molecules/DatePicker.md +516 -0
- package/docs/components/molecules/DateTimeSelector.md +166 -0
- package/docs/components/molecules/FormField.md +312 -0
- package/docs/components/molecules/Grid.md +577 -0
- package/docs/components/molecules/GridItem.md +834 -0
- package/docs/components/molecules/GridList.md +244 -0
- package/docs/components/molecules/List.md +485 -0
- package/docs/components/molecules/Modal.md +470 -0
- package/docs/components/molecules/ModalFooter.md +702 -0
- package/docs/components/molecules/ModalHeader.md +756 -0
- package/docs/components/molecules/ModalProvider.md +205 -0
- package/docs/components/molecules/Nav.md +530 -0
- package/docs/components/molecules/NavItem.md +572 -0
- package/docs/components/molecules/NavLink.md +499 -0
- package/docs/components/molecules/Option.md +521 -0
- package/docs/components/molecules/Pagination.md +592 -0
- package/docs/components/molecules/PaginationNumberField.md +722 -0
- package/docs/components/molecules/Popover.md +516 -0
- package/docs/components/molecules/ProgressBar.md +624 -0
- package/docs/components/molecules/RadioGroup.md +831 -0
- package/docs/components/molecules/RepeaterList.md +185 -0
- package/docs/components/molecules/Select.md +402 -0
- package/docs/components/molecules/SortableTrigger.md +82 -0
- package/docs/components/molecules/useModal.md +379 -0
- package/docs/components/organisms/Dropzone.md +346 -0
- package/docs/components/organisms/DropzoneClear.md +135 -0
- package/docs/components/organisms/DropzoneContent.md +216 -0
- package/docs/components/organisms/DropzoneFilename.md +191 -0
- package/docs/components/organisms/DropzoneSupportedFormats.md +184 -0
- package/docs/components/organisms/DropzoneTrigger.md +209 -0
- package/docs/components/organisms/Form.md +533 -0
- package/docs/components/organisms/SlideOutPanel.md +662 -0
- package/docs/components/organisms/TabContent.md +902 -0
- package/docs/components/organisms/TabItem.md +1091 -0
- package/docs/components/organisms/Table.md +611 -0
- package/docs/components/organisms/TableBody.md +679 -0
- package/docs/components/organisms/TableCell.md +482 -0
- package/docs/components/organisms/TableHeader.md +513 -0
- package/docs/components/organisms/TableHeaderCell.md +661 -0
- package/docs/components/organisms/TableRow.md +715 -0
- package/docs/components/organisms/Tabs.md +1330 -0
- package/docs/components/utils/ConditionalView.md +568 -0
- package/docs/components/utils/RenderStateView.md +726 -0
- package/docs/components/utils/WrapTextNodes.md +614 -0
- package/package.json +3 -2
|
@@ -0,0 +1,485 @@
|
|
|
1
|
+
# List
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
A flexible list component that renders collections of data with support for custom item components, sorting functionality, and both horizontal and vertical layouts. Provides efficient rendering for dynamic data sets with keyboard navigation and accessibility features.
|
|
6
|
+
|
|
7
|
+
## Aliases
|
|
8
|
+
|
|
9
|
+
- List
|
|
10
|
+
- ListView
|
|
11
|
+
- DataList
|
|
12
|
+
- ItemList
|
|
13
|
+
- Collection
|
|
14
|
+
|
|
15
|
+
## Props Breakdown
|
|
16
|
+
|
|
17
|
+
**Extends:** `HTMLAttributes<HTMLUListElement>` (excluding `children`)
|
|
18
|
+
|
|
19
|
+
| Prop | Type | Default | Required | Description |
|
|
20
|
+
|------|------|---------|----------|-------------|
|
|
21
|
+
| `data` | `T[]` | - | No | Array of data items to render |
|
|
22
|
+
| `component` | `React.ComponentType<T>` | - | Yes | Component to render each list item |
|
|
23
|
+
| `keyExtractor` | `(item: T, index: number) => string \| number` | - | No | Function to extract unique keys for items |
|
|
24
|
+
| `wrap` | `boolean` | - | No | Whether list content should wrap |
|
|
25
|
+
| `align` | `'Horizontal' \| 'Vertical'` | `'Vertical'` | No | Layout direction for the list |
|
|
26
|
+
| `sortable` | `boolean` | - | No | Enable drag-and-drop sorting |
|
|
27
|
+
| `updateSortOrder` | `(data: T[]) => void` | - | No | Callback when sort order changes |
|
|
28
|
+
| `className` | `string` | - | No | Additional CSS class names |
|
|
29
|
+
|
|
30
|
+
Plus all standard HTML ul attributes (role, aria-*, data-*, etc.).
|
|
31
|
+
|
|
32
|
+
## Examples
|
|
33
|
+
|
|
34
|
+
### Basic Usage with Data Array
|
|
35
|
+
```tsx
|
|
36
|
+
import { List } from '@delightui/components';
|
|
37
|
+
|
|
38
|
+
const ListItem = ({ children }) => (
|
|
39
|
+
<div className="list-item">
|
|
40
|
+
<span>{children}</span>
|
|
41
|
+
</div>
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
function BasicListExample() {
|
|
45
|
+
const items = [
|
|
46
|
+
{ id: 1, title: 'Apple' },
|
|
47
|
+
{ id: 2, title: 'Banana' },
|
|
48
|
+
{ id: 3, title: 'Cherry' },
|
|
49
|
+
{ id: 4, title: 'Date' }
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
const SimpleItem = ({ title }) => (
|
|
53
|
+
<ListItem>{title}</ListItem>
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<List
|
|
58
|
+
data={items}
|
|
59
|
+
component={SimpleItem}
|
|
60
|
+
className="simple-list"
|
|
61
|
+
/>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### User List with Custom Components
|
|
67
|
+
```tsx
|
|
68
|
+
import { Icon, Text, Chip } from '@delightui/components';
|
|
69
|
+
|
|
70
|
+
function UserListExample() {
|
|
71
|
+
const users = [
|
|
72
|
+
{ id: 1, name: 'John Doe', email: 'john@example.com', role: 'Admin', avatar: '/avatar1.jpg' },
|
|
73
|
+
{ id: 2, name: 'Jane Smith', email: 'jane@example.com', role: 'User', avatar: '/avatar2.jpg' },
|
|
74
|
+
{ id: 3, name: 'Bob Johnson', email: 'bob@example.com', role: 'Editor', avatar: '/avatar3.jpg' }
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
const UserItem = ({ name, email, role, avatar }) => (
|
|
78
|
+
<div className="user-item">
|
|
79
|
+
<img src={avatar} alt={name} className="user-avatar" />
|
|
80
|
+
<div className="user-info">
|
|
81
|
+
<Text type="Body" weight="Medium">{name}</Text>
|
|
82
|
+
<Text type="Caption" color="Secondary">{email}</Text>
|
|
83
|
+
</div>
|
|
84
|
+
<Chip size="Small">{role}</Chip>
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<List
|
|
90
|
+
data={users}
|
|
91
|
+
component={UserItem}
|
|
92
|
+
className="user-list"
|
|
93
|
+
/>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Horizontal Navigation List
|
|
99
|
+
```tsx
|
|
100
|
+
import { Icon, Text } from '@delightui/components';
|
|
101
|
+
|
|
102
|
+
function HorizontalListExample() {
|
|
103
|
+
const categories = [
|
|
104
|
+
{ id: 1, name: 'Technology', icon: 'Computer' },
|
|
105
|
+
{ id: 2, name: 'Design', icon: 'Palette' },
|
|
106
|
+
{ id: 3, name: 'Business', icon: 'Business' },
|
|
107
|
+
{ id: 4, name: 'Marketing', icon: 'Campaign' }
|
|
108
|
+
];
|
|
109
|
+
|
|
110
|
+
const CategoryItem = ({ name, icon }) => (
|
|
111
|
+
<div className="category-item">
|
|
112
|
+
<Icon icon={icon} size="Small" />
|
|
113
|
+
<Text type="Body">{name}</Text>
|
|
114
|
+
</div>
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
return (
|
|
118
|
+
<List
|
|
119
|
+
data={categories}
|
|
120
|
+
component={CategoryItem}
|
|
121
|
+
align="Horizontal"
|
|
122
|
+
className="horizontal-categories"
|
|
123
|
+
/>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Sortable Task List
|
|
129
|
+
```tsx
|
|
130
|
+
import { Icon, Text, Chip } from '@delightui/components';
|
|
131
|
+
|
|
132
|
+
function SortableListExample() {
|
|
133
|
+
const [tasks, setTasks] = useState([
|
|
134
|
+
{ id: 1, title: 'Review designs', priority: 'High' },
|
|
135
|
+
{ id: 2, title: 'Update documentation', priority: 'Medium' },
|
|
136
|
+
{ id: 3, title: 'Fix bug reports', priority: 'High' },
|
|
137
|
+
{ id: 4, title: 'Plan next sprint', priority: 'Low' }
|
|
138
|
+
]);
|
|
139
|
+
|
|
140
|
+
const TaskItem = ({ title, priority }) => (
|
|
141
|
+
<div className="task-item">
|
|
142
|
+
<Icon icon="DragHandle" className="drag-handle" />
|
|
143
|
+
<div className="task-content">
|
|
144
|
+
<Text type="Body" weight="Medium">{title}</Text>
|
|
145
|
+
<Chip size="Small">{priority}</Chip>
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
return (
|
|
151
|
+
<List
|
|
152
|
+
data={tasks}
|
|
153
|
+
component={TaskItem}
|
|
154
|
+
sortable
|
|
155
|
+
updateSortOrder={setTasks}
|
|
156
|
+
keyExtractor={(task) => task.id}
|
|
157
|
+
/>
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Interactive Project List
|
|
163
|
+
```tsx
|
|
164
|
+
import { Checkbox, Text, Button, Icon } from '@delightui/components';
|
|
165
|
+
|
|
166
|
+
function InteractiveListExample() {
|
|
167
|
+
const [selectedItems, setSelectedItems] = useState([]);
|
|
168
|
+
|
|
169
|
+
const projects = [
|
|
170
|
+
{ id: 1, name: 'Project Alpha', status: 'Active' },
|
|
171
|
+
{ id: 2, name: 'Project Beta', status: 'Pending' },
|
|
172
|
+
{ id: 3, name: 'Project Gamma', status: 'Completed' }
|
|
173
|
+
];
|
|
174
|
+
|
|
175
|
+
const toggleSelection = (itemId) => {
|
|
176
|
+
setSelectedItems(prev =>
|
|
177
|
+
prev.includes(itemId)
|
|
178
|
+
? prev.filter(id => id !== itemId)
|
|
179
|
+
: [...prev, itemId]
|
|
180
|
+
);
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const ProjectItem = ({ id, name, status, onToggle, onEdit }) => (
|
|
184
|
+
<div className="project-item" onClick={() => onToggle(id)}>
|
|
185
|
+
<Checkbox
|
|
186
|
+
checked={selectedItems.includes(id)}
|
|
187
|
+
onChange={() => onToggle(id)}
|
|
188
|
+
/>
|
|
189
|
+
<div className="project-info">
|
|
190
|
+
<Text type="Body" weight="Medium">{name}</Text>
|
|
191
|
+
<Text type="Caption" color="Secondary">{status}</Text>
|
|
192
|
+
</div>
|
|
193
|
+
<Button
|
|
194
|
+
type="Ghost"
|
|
195
|
+
size="Small"
|
|
196
|
+
onClick={(e) => {
|
|
197
|
+
e.stopPropagation();
|
|
198
|
+
onEdit(id);
|
|
199
|
+
}}
|
|
200
|
+
>
|
|
201
|
+
<Icon icon="Edit" />
|
|
202
|
+
</Button>
|
|
203
|
+
</div>
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
const handleEdit = (projectId) => {
|
|
207
|
+
console.log('Edit project:', projectId);
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
return (
|
|
211
|
+
<div className="interactive-list">
|
|
212
|
+
<div className="list-header">
|
|
213
|
+
<Text type="Heading" size="Medium">Projects</Text>
|
|
214
|
+
{selectedItems.length > 0 && (
|
|
215
|
+
<Text type="Caption">
|
|
216
|
+
{selectedItems.length} item(s) selected
|
|
217
|
+
</Text>
|
|
218
|
+
)}
|
|
219
|
+
</div>
|
|
220
|
+
|
|
221
|
+
<List
|
|
222
|
+
data={projects.map(project => ({
|
|
223
|
+
...project,
|
|
224
|
+
onToggle: toggleSelection,
|
|
225
|
+
onEdit: handleEdit
|
|
226
|
+
}))}
|
|
227
|
+
component={ProjectItem}
|
|
228
|
+
className="project-list"
|
|
229
|
+
/>
|
|
230
|
+
</div>
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Empty State
|
|
236
|
+
```tsx
|
|
237
|
+
function EmptyStateExample() {
|
|
238
|
+
const [items, setItems] = useState([]);
|
|
239
|
+
|
|
240
|
+
const EmptyState = () => (
|
|
241
|
+
<div className="empty-state">
|
|
242
|
+
<Icon icon="Inbox" size="Large" />
|
|
243
|
+
<Text type="Heading6">No items found</Text>
|
|
244
|
+
<Text type="BodySmall">Add some items to get started</Text>
|
|
245
|
+
<Button onClick={() => setItems([{ id: 1, name: 'New Item' }])}>
|
|
246
|
+
Add Item
|
|
247
|
+
</Button>
|
|
248
|
+
</div>
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
const ItemComponent = ({ item }) => (
|
|
252
|
+
<ListItem>
|
|
253
|
+
<Text>{item.name}</Text>
|
|
254
|
+
</ListItem>
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
return (
|
|
258
|
+
<div className="list-with-empty-state">
|
|
259
|
+
{items.length > 0 ? (
|
|
260
|
+
<List
|
|
261
|
+
data={items}
|
|
262
|
+
component={ItemComponent}
|
|
263
|
+
keyExtractor={(item) => item.id}
|
|
264
|
+
/>
|
|
265
|
+
) : (
|
|
266
|
+
<EmptyState />
|
|
267
|
+
)}
|
|
268
|
+
</div>
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### List with Loading State
|
|
274
|
+
```tsx
|
|
275
|
+
function LoadingListExample() {
|
|
276
|
+
const [items, setItems] = useState([]);
|
|
277
|
+
const [loading, setLoading] = useState(true);
|
|
278
|
+
|
|
279
|
+
useEffect(() => {
|
|
280
|
+
// Simulate API call
|
|
281
|
+
setTimeout(() => {
|
|
282
|
+
setItems([
|
|
283
|
+
{ id: 1, name: 'Item 1' },
|
|
284
|
+
{ id: 2, name: 'Item 2' },
|
|
285
|
+
{ id: 3, name: 'Item 3' }
|
|
286
|
+
]);
|
|
287
|
+
setLoading(false);
|
|
288
|
+
}, 2000);
|
|
289
|
+
}, []);
|
|
290
|
+
|
|
291
|
+
const LoadingItem = () => (
|
|
292
|
+
<ListItem className="loading-item">
|
|
293
|
+
<Spinner size="Small" />
|
|
294
|
+
<Text type="BodyMedium">Loading...</Text>
|
|
295
|
+
</ListItem>
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
const ItemComponent = ({ item }) => (
|
|
299
|
+
<ListItem>
|
|
300
|
+
<Text>{item.name}</Text>
|
|
301
|
+
</ListItem>
|
|
302
|
+
);
|
|
303
|
+
|
|
304
|
+
if (loading) {
|
|
305
|
+
return (
|
|
306
|
+
<List
|
|
307
|
+
data={[1, 2, 3]} // Placeholder data for loading items
|
|
308
|
+
component={LoadingItem}
|
|
309
|
+
/>
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
return (
|
|
314
|
+
<List
|
|
315
|
+
data={items}
|
|
316
|
+
component={ItemComponent}
|
|
317
|
+
keyExtractor={(item) => item.id}
|
|
318
|
+
/>
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### Filterable List
|
|
324
|
+
```tsx
|
|
325
|
+
function FilterableListExample() {
|
|
326
|
+
const [searchTerm, setSearchTerm] = useState('');
|
|
327
|
+
const [filter, setFilter] = useState('all');
|
|
328
|
+
|
|
329
|
+
const allItems = [
|
|
330
|
+
{ id: 1, name: 'Apple', category: 'fruit', color: 'red' },
|
|
331
|
+
{ id: 2, name: 'Banana', category: 'fruit', color: 'yellow' },
|
|
332
|
+
{ id: 3, name: 'Carrot', category: 'vegetable', color: 'orange' },
|
|
333
|
+
{ id: 4, name: 'Broccoli', category: 'vegetable', color: 'green' }
|
|
334
|
+
];
|
|
335
|
+
|
|
336
|
+
const filteredItems = allItems.filter(item => {
|
|
337
|
+
const matchesSearch = item.name.toLowerCase().includes(searchTerm.toLowerCase());
|
|
338
|
+
const matchesFilter = filter === 'all' || item.category === filter;
|
|
339
|
+
return matchesSearch && matchesFilter;
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
const ItemComponent = ({ item }) => (
|
|
343
|
+
<ListItem className="filterable-item">
|
|
344
|
+
<Text type="BodyMedium">{item.name}</Text>
|
|
345
|
+
<Chip size="Small" style="B">{item.category}</Chip>
|
|
346
|
+
</ListItem>
|
|
347
|
+
);
|
|
348
|
+
|
|
349
|
+
return (
|
|
350
|
+
<div className="filterable-list">
|
|
351
|
+
<div className="list-controls">
|
|
352
|
+
<Input
|
|
353
|
+
placeholder="Search items..."
|
|
354
|
+
value={searchTerm}
|
|
355
|
+
onValueChange={setSearchTerm}
|
|
356
|
+
leadingIcon={<Icon icon="Search" />}
|
|
357
|
+
/>
|
|
358
|
+
|
|
359
|
+
<Select value={filter} onValueChange={setFilter}>
|
|
360
|
+
<Option value="all">All Categories</Option>
|
|
361
|
+
<Option value="fruit">Fruits</Option>
|
|
362
|
+
<Option value="vegetable">Vegetables</Option>
|
|
363
|
+
</Select>
|
|
364
|
+
</div>
|
|
365
|
+
|
|
366
|
+
<List
|
|
367
|
+
data={filteredItems}
|
|
368
|
+
component={ItemComponent}
|
|
369
|
+
keyExtractor={(item) => item.id}
|
|
370
|
+
/>
|
|
371
|
+
</div>
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### Pagination List
|
|
377
|
+
```tsx
|
|
378
|
+
function PaginatedListExample() {
|
|
379
|
+
const [currentPage, setCurrentPage] = useState(1);
|
|
380
|
+
const itemsPerPage = 5;
|
|
381
|
+
|
|
382
|
+
const allItems = Array.from({ length: 23 }, (_, i) => ({
|
|
383
|
+
id: i + 1,
|
|
384
|
+
name: `Item ${i + 1}`,
|
|
385
|
+
description: `Description for item ${i + 1}`
|
|
386
|
+
}));
|
|
387
|
+
|
|
388
|
+
const totalPages = Math.ceil(allItems.length / itemsPerPage);
|
|
389
|
+
const startIndex = (currentPage - 1) * itemsPerPage;
|
|
390
|
+
const currentItems = allItems.slice(startIndex, startIndex + itemsPerPage);
|
|
391
|
+
|
|
392
|
+
const ItemComponent = ({ item }) => (
|
|
393
|
+
<ListItem>
|
|
394
|
+
<div className="item-content">
|
|
395
|
+
<Text type="BodyMedium">{item.name}</Text>
|
|
396
|
+
<Text type="BodySmall">{item.description}</Text>
|
|
397
|
+
</div>
|
|
398
|
+
</ListItem>
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
return (
|
|
402
|
+
<div className="paginated-list">
|
|
403
|
+
<List
|
|
404
|
+
data={currentItems}
|
|
405
|
+
component={ItemComponent}
|
|
406
|
+
keyExtractor={(item) => item.id}
|
|
407
|
+
/>
|
|
408
|
+
|
|
409
|
+
<Pagination
|
|
410
|
+
currentPage={currentPage}
|
|
411
|
+
totalPages={totalPages}
|
|
412
|
+
onPageChange={setCurrentPage}
|
|
413
|
+
/>
|
|
414
|
+
</div>
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### Nested Lists
|
|
420
|
+
```tsx
|
|
421
|
+
function NestedListExample() {
|
|
422
|
+
const [expandedCategories, setExpandedCategories] = useState([]);
|
|
423
|
+
|
|
424
|
+
const categories = [
|
|
425
|
+
{
|
|
426
|
+
id: 1,
|
|
427
|
+
name: 'Frontend',
|
|
428
|
+
items: ['React', 'Vue', 'Angular', 'Svelte']
|
|
429
|
+
},
|
|
430
|
+
{
|
|
431
|
+
id: 2,
|
|
432
|
+
name: 'Backend',
|
|
433
|
+
items: ['Node.js', 'Python', 'Java', 'Go']
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
id: 3,
|
|
437
|
+
name: 'Database',
|
|
438
|
+
items: ['PostgreSQL', 'MongoDB', 'MySQL', 'Redis']
|
|
439
|
+
}
|
|
440
|
+
];
|
|
441
|
+
|
|
442
|
+
const toggleCategory = (categoryId) => {
|
|
443
|
+
setExpandedCategories(prev =>
|
|
444
|
+
prev.includes(categoryId)
|
|
445
|
+
? prev.filter(id => id !== categoryId)
|
|
446
|
+
: [...prev, categoryId]
|
|
447
|
+
);
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
const CategoryItem = ({ item: category }) => (
|
|
451
|
+
<div className="category-item">
|
|
452
|
+
<ListItem
|
|
453
|
+
onClick={() => toggleCategory(category.id)}
|
|
454
|
+
className="category-header"
|
|
455
|
+
>
|
|
456
|
+
<Icon
|
|
457
|
+
icon={expandedCategories.includes(category.id) ? 'ExpandLess' : 'ExpandMore'}
|
|
458
|
+
/>
|
|
459
|
+
<Text type="BodyMedium">{category.name}</Text>
|
|
460
|
+
</ListItem>
|
|
461
|
+
|
|
462
|
+
{expandedCategories.includes(category.id) && (
|
|
463
|
+
<div className="nested-items">
|
|
464
|
+
<List
|
|
465
|
+
data={category.items}
|
|
466
|
+
component={({ item }) => (
|
|
467
|
+
<ListItem className="nested-item">
|
|
468
|
+
<Text type="BodySmall">{item}</Text>
|
|
469
|
+
</ListItem>
|
|
470
|
+
)}
|
|
471
|
+
/>
|
|
472
|
+
</div>
|
|
473
|
+
)}
|
|
474
|
+
</div>
|
|
475
|
+
);
|
|
476
|
+
|
|
477
|
+
return (
|
|
478
|
+
<List
|
|
479
|
+
data={categories}
|
|
480
|
+
component={CategoryItem}
|
|
481
|
+
keyExtractor={(category) => category.id}
|
|
482
|
+
/>
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
```
|