Skip to content

Commit 3853c6d

Browse files
committed
fix: 🐛 Fixed misc issues and formatting
Added setOption updates to virtualizer, and misc changes to formatting
1 parent d27dc1a commit 3853c6d

File tree

1 file changed

+114
-107
lines changed

1 file changed

+114
-107
lines changed

src/createVirtualizedList.ts

Lines changed: 114 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,35 @@
1-
import { createVirtualizer, VirtualItem, VirtualizerOptions } from "@tanstack/solid-virtual";
2-
import { createUniqueId, mergeProps, createMemo, createSignal, onMount, untrack } from "solid-js";
3-
import { mergeRefs, createGenerateId } from "@kobalte/utils";
4-
import { isServer } from "solid-js/web";
1+
import { createVirtualizer, VirtualItem, VirtualizerOptions } from "@tanstack/solid-virtual"
2+
import { createUniqueId, mergeProps, createMemo, createSignal, onMount, untrack, createEffect, on } from "solid-js"
3+
import { mergeRefs, createGenerateId } from "@kobalte/utils"
4+
import { isServer } from "solid-js/web"
55

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

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

1111

1212
export interface VirtualizedListArgs<T, ScrollElement extends Element = Element, ItemElement extends Element = Element> extends Partial<VirtualizerOptions<ScrollElement, ItemElement>> {
13-
id?: string;
14-
data: () => T[];
15-
determineKey?: KeyFunction<T>;
16-
itemHeight?: number;
17-
width?: number;
18-
height?: number;
19-
rootProps?: Record<string, any>;
20-
containerProps?: Record<string, any>;
21-
itemProps?: Record<string, any>;
13+
id?: string
14+
data: () => T[]
15+
determineKey?: KeyFunction<T>
16+
itemHeight?: number
17+
width?: number
18+
height?: number
19+
rootProps?: Record<string, any>
20+
containerProps?: Record<string, any>
21+
itemProps?: Record<string, any>
2222
}
2323

2424
export interface VirtualItemWithExtras extends VirtualItem {
25-
isLast: boolean;
26-
isEven: boolean;
25+
isLast: boolean
26+
isEven: boolean
2727
}
2828

2929
export interface ItemArgs<T> {
30-
data: T;
31-
props: Record<string, any>;
32-
virtualItem: VirtualItemWithExtras;
30+
data: T
31+
props: Record<string, any>
32+
virtualItem: VirtualItemWithExtras
3333
}
3434

3535
/**
@@ -49,13 +49,13 @@ export interface ItemArgs<T> {
4949
*
5050
* @example
5151
* const MyList = () => {
52-
* const items = () => ['Item 1', 'Item 2', 'Item 3'];
52+
* const items = () => ['Item 1', 'Item 2', 'Item 3']
5353
* const virtualList = createVirtualizedList({
5454
* data: items,
5555
* itemHeight: 30,
5656
* height: 300,
5757
* width: 500,
58-
* });
58+
* })
5959
*
6060
* return (
6161
* <div {...virtualList.root}>
@@ -67,62 +67,62 @@ export interface ItemArgs<T> {
6767
* </For>
6868
* </div>
6969
* </div>
70-
* );
71-
* };
70+
* )
71+
* }
7272
*/
7373
export function createVirtualizedList<T extends Primitive | ObjectWithKey>(args: VirtualizedListArgs<T>) {
74-
const id = args.id || createUniqueId();
75-
const generateId = createGenerateId(() => id);
74+
const id = () => args.id || createUniqueId()
75+
const generateId = () => createGenerateId(() => id())
76+
77+
const data = args.data
78+
const count = createMemo(() => args?.count ?? data()?.length ?? 0)
7679

77-
const data = args.data;
78-
const count = createMemo(() => args.count || data()?.length || 0);
79-
8080
// @ts-expect-error
81-
const determineKey: KeyFunction<T> = args.determineKey || args.getItemKey || ((item: T, index?: number) => {
81+
const determineKey: () => KeyFunction<T> = createMemo(() => args?.determineKey ?? args?.getItemKey ?? ((item: T, index?: number) => {
8282
if (typeof item === 'object' && item !== null) {
83-
return (item as ObjectWithKey)?.id ??
84-
(item as ObjectWithKey)?.Id ??
85-
(item as ObjectWithKey)?.ID ??
86-
(item as ObjectWithKey)?.uuid ??
87-
(item as ObjectWithKey)?.UUID ??
88-
(item as ObjectWithKey)?.key ??
89-
(item as ObjectWithKey)?.sku ??
90-
index!;
83+
return (item as ObjectWithKey)?.id ??
84+
(item as ObjectWithKey)?.Id ??
85+
(item as ObjectWithKey)?.ID ??
86+
(item as ObjectWithKey)?.uuid ??
87+
(item as ObjectWithKey)?.UUID ??
88+
(item as ObjectWithKey)?.key ??
89+
(item as ObjectWithKey)?.sku ??
90+
index!
9191
}
92-
return item as unknown as string | number;
93-
});
92+
return item as unknown as string | number
93+
}))
9494

95-
const horizontal = () => args?.horizontal ?? false;
95+
const horizontal = () => args?.horizontal ?? false
9696

97-
const [rootElement, setRootElement] = createSignal<Element | null>(null);
97+
const [rootElement, setRootElement] = createSignal<Element | null>(null)
9898

99-
const getScrollElement = () => rootElement();
99+
const getScrollElement = () => rootElement()
100100

101-
const estimateSize = createMemo(() => args?.estimateSize || ((index: number) => args.itemHeight || 50));
101+
const estimateSize = createMemo(() => args?.estimateSize || ((index: number) => args.itemHeight || 50))
102102

103103
const initialRect = () => ({
104104
width: args?.width ?? args.initialRect?.width ?? 600,
105105
height: args?.height ?? args.initialRect?.height ?? 400,
106-
});
106+
})
107107

108108
const measureElement = createMemo(() => {
109-
if (isServer) return undefined;
109+
if (isServer) return undefined
110110

111-
if (args.measureElement) return args.measureElement;
111+
if (args.measureElement) return args.measureElement
112112
if (navigator.userAgent.indexOf('Firefox') === -1) {
113113
return (element: Element) => {
114-
return element?.getBoundingClientRect()[horizontal() ? 'width' : 'height'];
115-
};
114+
return element?.getBoundingClientRect()[horizontal() ? 'width' : 'height']
115+
}
116116
}
117117

118-
return undefined;
119-
});
118+
return undefined
119+
})
120120

121121
const reactiveArgs = createMemo(() => args)
122122

123123
const options: () => VirtualizerOptions<Element, Element> = createMemo(() => {
124124
const currentArgs = reactiveArgs()
125-
125+
126126
return mergeProps({
127127
get count() {
128128
return count()
@@ -139,47 +139,47 @@ export function createVirtualizedList<T extends Primitive | ObjectWithKey>(args:
139139
initialOffset: currentArgs?.initialOffset ?? 0,
140140
onChange: currentArgs.onChange,
141141
scrollToFn: currentArgs?.scrollToFn ?? ((offset, { behavior }) => {
142-
const scrollElement = getScrollElement();
142+
const scrollElement = getScrollElement()
143143
if (scrollElement) {
144144
scrollElement.scrollTo({
145145
[horizontal() ? 'left' : 'top']: offset,
146146
behavior,
147-
});
147+
})
148148
}
149149
}),
150150
observeElementRect: currentArgs?.observeElementRect ?? ((instance, cb) => {
151-
const scrollElement = getScrollElement();
152-
if (!scrollElement) return;
153-
151+
const scrollElement = getScrollElement()
152+
if (!scrollElement) return
153+
154154
const resizeObserver = new ResizeObserver(() => {
155-
const rect = scrollElement.getBoundingClientRect();
156-
cb(rect);
157-
});
158-
159-
resizeObserver.observe(scrollElement);
160-
161-
return () => resizeObserver.disconnect();
155+
const rect = scrollElement.getBoundingClientRect()
156+
cb(rect)
157+
})
158+
159+
resizeObserver.observe(scrollElement)
160+
161+
return () => resizeObserver.disconnect()
162162
}),
163163
observeElementOffset: currentArgs?.observeElementOffset ?? ((instance, cb) => {
164-
const scrollElement = getScrollElement();
165-
if (!scrollElement) return;
166-
164+
const scrollElement = getScrollElement()
165+
if (!scrollElement) return
166+
167167
const handleScroll = () => {
168168
const offset = horizontal()
169169
? scrollElement.scrollLeft
170-
: scrollElement.scrollTop;
171-
cb(offset, true);
172-
};
173-
170+
: scrollElement.scrollTop
171+
cb(offset, true)
172+
}
173+
174174
scrollElement.addEventListener('scroll', handleScroll, {
175175
passive: true,
176-
});
177-
178-
return () => scrollElement.removeEventListener('scroll', handleScroll);
176+
})
177+
178+
return () => scrollElement.removeEventListener('scroll', handleScroll)
179179
}),
180180
debug: currentArgs?.debug,
181181
measureElement: measureElement(),
182-
getItemKey: (index: number) => determineKey(data()[index], index),
182+
getItemKey: (index: number) => { return determineKey()(data()[index], index) },
183183
rangeExtractor: currentArgs?.rangeExtractor,
184184
scrollMargin: currentArgs?.scrollMargin,
185185
gap: currentArgs?.gap,
@@ -191,67 +191,72 @@ export function createVirtualizedList<T extends Primitive | ObjectWithKey>(args:
191191
isRtl: currentArgs?.isRtl,
192192
}, currentArgs)
193193
}
194-
)
194+
)
195195

196-
const virtualizer = createMemo(() => createVirtualizer(options()))
196+
const virtualizer = (createVirtualizer(options()))
197+
198+
createEffect(on(options, () => {
199+
virtualizer.setOptions(options())
200+
}, { defer: true }))
197201

198202
const rootProps = createMemo(() => {
199203
const defaultStyle = {
200204
'overflow-y': horizontal() ? 'hidden' : 'auto',
201205
'overflow-x': horizontal() ? 'auto' : 'hidden',
202206
position: 'relative',
203207
height: args?.height ? `${args.height}px` : '400px',
204-
width: args?.width ? `${args.width}px`: '100%',
205-
};
206-
const horizontalAttr = horizontal() ? "" : undefined;
208+
width: args?.width ? `${args.width}px` : '100%',
209+
}
210+
const horizontalAttr = horizontal() ? "" : undefined
207211

208212
return mergeProps({
209213
id: id,
210214
style: defaultStyle,
211215
"data-horizontal": horizontalAttr,
212216
"data-list-id": id,
213217
ref: mergeRefs((el: Element) => setRootElement(el), args.rootProps?.ref),
214-
}, args.rootProps || {});
215-
});
218+
}, args.rootProps || {})
219+
})
216220

217221
const containerProps = createMemo(() => {
218-
const containerId = generateId('list');
222+
const containerId = generateId()('list')
219223
const defaultStyle = {
220224
position: 'relative',
221-
height: horizontal() ? '100%' : `${virtualizer().getTotalSize()}px`,
222-
width: horizontal() ? `${virtualizer().getTotalSize()}px` : '100%',
223-
};
225+
height: horizontal() ? '100%' : `${virtualizer.getTotalSize()}px`,
226+
width: horizontal() ? `${virtualizer.getTotalSize()}px` : '100%',
227+
}
224228

225229
return mergeProps({
226230
style: defaultStyle,
227231
"data-list-container": containerId,
228-
}, args.containerProps || {});
229-
});
232+
}, args.containerProps || {})
233+
})
230234

231-
const itemWrapper = (itemCreator: (args: ItemArgs<T>) => any, trackChanges = false) =>
235+
const itemWrapper = (itemCreator: (args: ItemArgs<T>) => any, trackChanges = false) =>
232236
(virtualItem: VirtualItem, virtualItemIndex: () => number) => {
233237
const createItem = () => {
234-
const itemData = data()[virtualItem.index];
238+
const itemData = data()[virtualItem.index]
235239
const style = {
236240
position: 'absolute',
237241
top: horizontal() ? 0 : `${virtualItem.start}px`,
238242
left: horizontal() ? `${virtualItem.start}px` : 0,
239243
width: horizontal() ? `${virtualItem.size}px` : '100%',
240244
height: horizontal() ? '100%' : `${virtualItem.size}px`,
241-
};
242-
const key = determineKey(itemData, virtualItem.index);
245+
}
246+
247+
const key = determineKey()(itemData, virtualItem.index)
243248
const itemProps = mergeProps({
244249
style,
245250
'data-list-item': 'true',
246251
'data-index': virtualItem.index,
247252
key,
248-
ref: mergeRefs((el: Element) => {
249-
if (el) virtualizer().measureElement(el);
253+
ref: mergeRefs((el: Element) => {
254+
if (el) virtualizer.measureElement(el)
250255
}, args.itemProps?.ref),
251-
}, args?.itemProps ?? {});
256+
}, args?.itemProps ?? {})
252257

253-
const isLast = virtualItem.index === count() - 1;
254-
const isEven = virtualItem.index % 2 === 0;
258+
const isLast = virtualItem.index === count() - 1
259+
const isEven = virtualItem.index % 2 === 0
255260
const itemArgs: ItemArgs<T> = {
256261
data: itemData,
257262
props: itemProps,
@@ -260,31 +265,33 @@ export function createVirtualizedList<T extends Primitive | ObjectWithKey>(args:
260265
isLast,
261266
isEven,
262267
},
263-
};
264-
265-
return itemCreator(itemArgs);
268+
}
269+
270+
return itemCreator(itemArgs)
266271
}
267272

268-
return trackChanges ? createMemo(createItem) : untrack(createItem)
273+
return trackChanges ? createMemo(createItem)() : untrack(createItem)
269274
}
270275

271276
return {
272277
id,
273-
virtualizer,
278+
get virtualizer() {
279+
return virtualizer
280+
},
274281
get root() {
275282
return rootProps()
276283
},
277284
get count() {
278285
return count()
279286
},
280-
get container(){
287+
get container() {
281288
return containerProps()
282289
},
283290
items: itemWrapper,
284291
get item() {
285-
return virtualizer().getVirtualItems()
292+
return virtualizer.getVirtualItems()
286293
}
287-
};
294+
}
288295
}
289296

290-
export default createVirtualizedList;
297+
export default createVirtualizedList

0 commit comments

Comments
 (0)