Skip to content

Commit 329f6e3

Browse files
committed
feat: ✨ Added a simple VirtualizedList component
This component provides a simple way to create a virtualized list
1 parent 26bdb94 commit 329f6e3

File tree

4 files changed

+287
-7
lines changed

4 files changed

+287
-7
lines changed

README.md

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Solid.js Virtualized List Wrapper
22

3-
A helpful wrapper around `@tanstack/solid-virtual` that simplifies the creation of virtualized lists in Solid.js applications while maintaining full access to the underlying virtualizer's power.
3+
A helpful wrapper around `@tanstack/solid-virtual` that simplifies the creation of virtualized lists in Solid.js apps while maintaining full access to the underlying virtualizer.
44

55
## Features
66

@@ -47,6 +47,36 @@ const MyList = () => {
4747
}
4848
```
4949

50+
## VirtualizedList Component
51+
52+
For simple use cases we provide a `VirtualizedList` component
53+
54+
```jsx
55+
import { VirtualizedList } from '@doeixd/create-virtualized-list-solid';
56+
57+
const MyList = () => {
58+
const items = Array.from({ length: 10000 }, (_, i) => `Item ${i + 1}`);
59+
60+
return (
61+
<VirtualizedList
62+
data={items}
63+
height={400}
64+
width={300}
65+
renderItem={({ item, virtualItem }) => (
66+
<div style={{
67+
padding: '10px',
68+
background: virtualItem.isEven ? '#f0f0f0' : 'white'
69+
}}>
70+
{item}
71+
{virtualItem.isLast && ' (Last Item)'}
72+
</div>
73+
)}
74+
/>
75+
);
76+
};
77+
```
78+
The `VirtualizedList` component simplifies the creation of virtualized lists even further, handling all the setup and providing a clean interface for rendering items.
79+
5080
## Why is this hepful?
5181

5282
### Root and Container Elements
@@ -201,6 +231,21 @@ An object with the following properties:
201231
- `count`: Getter function for total item count (automatically determined)
202232
- `item`: Getter function for virtual items (alias for `virtualizer.getVirtualItems()`)
203233

234+
### `VirtualizedList<T>(props)`
235+
236+
Creates a simple generic virtualized list component.
237+
238+
#### Props
239+
240+
- `data`: Array of items to be rendered
241+
- `renderItem`: Function to render each item
242+
- `height`: Height number of pixels for the list container
243+
- `width`: Width number of pixels for the list container
244+
- `className`: Optional CSS class for the list container
245+
- `style`: Optional inline styles for the list container
246+
247+
All other props from `VirtualizerOptions` are also accepted and passed through to the underlying virtualizer.
248+
204249

205250

206251
## Advanced Usage
@@ -219,9 +264,9 @@ virtualList.virtualizer.scrollToIndex(50)
219264

220265
## TypeScript Support
221266

222-
This wrapper is written in TypeScript and provides full type definitions:
267+
This wrapper is written in TypeScript and provides type definitions:
223268

224-
```typescript
269+
```tsx
225270
interface MyItem {
226271
id: number;
227272
name: string;
@@ -233,6 +278,27 @@ const virtualList = createVirtualizedList<MyItem>({
233278
})
234279
```
235280

281+
```tsx
282+
interface MyItem {
283+
id: number;
284+
name: string;
285+
}
286+
287+
const MyList = () => {
288+
const items: MyItem[] = [/* ... */];
289+
290+
return (
291+
<VirtualizedList<MyItem>
292+
data={items}
293+
height={400}
294+
width={300}
295+
renderItem={({ item }) => <div>{item.name}</div>}
296+
determineKey={(item) => item.id}
297+
/>
298+
);
299+
};
300+
```
301+
236302
## Requirements
237303

238304
- Solid.js

src/VirtualizedList.tsx

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import { Component, JSX, For, createMemo, splitProps } from 'solid-js';
2+
import { createVirtualizedList, VirtualizedListArgs, VirtualItemWithExtras, ObjectWithKey, Primitive } from './createVirtualizedList';
3+
import { mergeProps } from 'solid-js';
4+
5+
/**
6+
* A function type for rendering individual items in the virtualized list.
7+
* @template T The type of the data item.
8+
*/
9+
type RenderItemFunction<T> = (props: {
10+
item: T;
11+
virtualItem: VirtualItemWithExtras;
12+
}) => JSX.Element;
13+
14+
type VirtualListProps<T> = Omit<VirtualizedListArgs<T>, 'data'>;
15+
16+
/**
17+
* Props for the VirtualizedList component.
18+
* @template T The type of the data items in the list.
19+
*/
20+
interface VirtualizedListProps<T> extends Omit<VirtualListProps<T>, 'width' | 'height'> {
21+
/** The array of data items to be rendered in the list. */
22+
data: T[];
23+
/** A function that renders each item in the list. */
24+
renderItem: RenderItemFunction<T>;
25+
/** The height of the virtualized list container. */
26+
height?: number;
27+
/** The width of the virtualized list container. */
28+
width?: number;
29+
/** Optional CSS class name for the list container. */
30+
className?: string;
31+
/** Optional inline styles for the list container. */
32+
style?: JSX.CSSProperties;
33+
}
34+
35+
const defaultProps = {
36+
estimateSize: () => 50,
37+
overscan: 5,
38+
};
39+
40+
/**
41+
* A virtualized list component for Solid.js applications.
42+
* This component efficiently renders large lists by only rendering the items currently in view.
43+
*
44+
* @template T The type of the data items in the list. Must extend Primitive or ObjectWithKey.
45+
* @param {VirtualizedListProps<T>} userProps - The props for the virtualized list.
46+
* @returns {JSX.Element} A JSX element representing the virtualized list.
47+
*
48+
* @example
49+
* // Basic usage with an array of strings
50+
* <VirtualizedList<string>
51+
* data={['Item 1', 'Item 2', 'Item 3']}
52+
* renderItem={({ item }) => <div>{item}</div>}
53+
* height={400}
54+
* width={300}
55+
* />
56+
*
57+
* @example
58+
* // Usage with an array of objects and custom styling
59+
* interface User { id: number; name: string; }
60+
* const users: User[] = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];
61+
*
62+
* <VirtualizedList<User>
63+
* data={users}
64+
* renderItem={({ item, virtualItem }) => (
65+
* <div style={{ background: virtualItem.isEven ? '#f0f0f0' : 'white' }}>
66+
* {item.name}
67+
* </div>
68+
* )}
69+
* height={500}
70+
* width="100%"
71+
* estimateSize={() => 50}
72+
* determineKey={(user) => user.id}
73+
* className="user-list"
74+
* style={{ border: '1px solid #ccc' }}
75+
* />
76+
*
77+
* @example
78+
* // Usage with dynamic item heights
79+
* <VirtualizedList<string>
80+
* data={longTexts}
81+
* renderItem={({ item }) => <div style={{ padding: '10px' }}>{item}</div>}
82+
* estimateSize={(index) => longTexts[index].length > 100 ? 100 : 50}
83+
* height={600}
84+
* width={400}
85+
* />
86+
*/
87+
export function VirtualizedList<T extends Primitive | ObjectWithKey>(userProps: VirtualizedListProps<T>): JSX.Element {
88+
const props = mergeProps(defaultProps, userProps);
89+
const [local, virtualListProps] = splitProps(props, ['data', 'renderItem', 'height', 'width', 'className', 'style']);
90+
91+
const virtualList = createMemo(() => createVirtualizedList<T>({
92+
...virtualListProps,
93+
data: () => local.data,
94+
height: local.height,
95+
width: local.width,
96+
}));
97+
98+
return (
99+
<div
100+
{...virtualList().root}
101+
style={mergeProps(
102+
virtualList().root.style,
103+
local.style
104+
)}
105+
class={local.className}
106+
>
107+
<div {...virtualList().container}>
108+
<For each={virtualList().item}>
109+
{virtualList().items((itemData) => (
110+
local.renderItem({
111+
item: itemData.data,
112+
virtualItem: itemData.virtualItem,
113+
})
114+
))}
115+
</For>
116+
</div>
117+
</div>
118+
);
119+
}

src/createVirtualizedList.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import { createUniqueId, mergeProps, createMemo, createSignal, onMount, untrack
33
import { mergeRefs, createGenerateId } from "@kobalte/utils";
44
import { isServer } from "solid-js/web";
55

6-
type Primitive = string | number | boolean | null | undefined;
7-
type ObjectWithKey = { [key: string]: any };
6+
export type Primitive = string | number | boolean | null | undefined;
7+
export type ObjectWithKey = { [key: string]: any };
88

99
export type KeyFunction<T> = (item: T, index?: number) => string | number;
1010

src/index.ts

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,99 @@
1-
import Mod from './createVirtualizedList';
1+
/**
2+
* @module @doeixd/create-virtualized-list-solid
3+
* A Solid.js library for creating efficient virtualized lists.
4+
*/
25

6+
/**
7+
* Creates a virtualized list with advanced configuration options.
8+
*
9+
* @example
10+
* ```tsx
11+
* import { createVirtualizedList } from '@doeixd/create-virtualized-list-solid';
12+
* import { For } from 'solid-js';
13+
*
14+
* const MyList = () => {
15+
* const items = () => Array.from({ length: 10000 }, (_, i) => `Item ${i + 1}`);
16+
*
17+
* const virtualList = createVirtualizedList({
18+
* data: items,
19+
* estimateSize: () => 30,
20+
* overscan: 5
21+
* });
22+
*
23+
* return (
24+
* <div {...virtualList.root}>
25+
* <div {...virtualList.container}>
26+
* <For each={virtualList.item}>
27+
* {virtualList.items((item) => (
28+
* <div {...item.props}>{item.data}</div>
29+
* ))}
30+
* </For>
31+
* </div>
32+
* </div>
33+
* );
34+
* };
35+
* ```
36+
*/
337
export { createVirtualizedList } from './createVirtualizedList';
4-
export default Mod;
38+
39+
/**
40+
* A ready-to-use virtualized list component with a simplified API.
41+
*
42+
* @example
43+
* ```tsx
44+
* import { VirtualizedList } from '@doeixd/create-virtualized-list-solid';
45+
*
46+
* const MyList = () => {
47+
* const items = Array.from({ length: 10000 }, (_, i) => `Item ${i + 1}`);
48+
*
49+
* return (
50+
* <VirtualizedList
51+
* data={items}
52+
* height={400}
53+
* width={300}
54+
* itemHeight={30}
55+
* renderItem={({ item, index }) => (
56+
* <div>{item}</div>
57+
* )}
58+
* />
59+
* );
60+
* };
61+
* ```
62+
*/
63+
export { VirtualizedList } from './VirtualizedList'
64+
65+
import createVirtualizedList from './createVirtualizedList';
66+
import { VirtualizedList } from './VirtualizedList'
67+
68+
/**
69+
* Default export object containing both the createVirtualizedList function and the VirtualizedList component.
70+
*
71+
* @example
72+
* ```tsx
73+
* import VirtualizedListLib from '@doeixd/create-virtualized-list-solid';
74+
*
75+
* // Using createVirtualizedList
76+
* const MyCustomList = () => {
77+
* const items = () => Array.from({ length: 10000 }, (_, i) => `Item ${i + 1}`);
78+
* const virtualList = VirtualizedListLib.createVirtualizedList({ data: items });
79+
* // ... rest of the component
80+
* };
81+
*
82+
* // Using VirtualizedList component
83+
* const MySimpleList = () => {
84+
* const items = Array.from({ length: 10000 }, (_, i) => `Item ${i + 1}`);
85+
* return (
86+
* <VirtualizedListLib.VirtualizedList
87+
* data={items}
88+
* height={400}
89+
* width={300}
90+
* renderItem={({ item }) => <div>{item}</div>}
91+
* />
92+
* );
93+
* };
94+
* ```
95+
*/
96+
export default {
97+
createVirtualizedList,
98+
VirtualizedList
99+
}

0 commit comments

Comments
 (0)