Skip to content

Commit

Permalink
move shared CSS into useVirtualScroll (#2165)
Browse files Browse the repository at this point in the history
  • Loading branch information
mayank99 authored Jul 23, 2024
1 parent d5bc69c commit ba6811b
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 43 deletions.
12 changes: 4 additions & 8 deletions packages/itwinui-react/src/core/ComboBox/ComboBoxMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const VirtualizedComboBoxMenu = (props: React.ComponentProps<'div'>) => {
);
}, [focusedIndex, menuRef]);

const virtualizer = useVirtualScroll({
const { virtualizer, css: virtualizerCss } = useVirtualScroll({
// 'Fool' useVirtualScroll by passing length 1
// whenever there is no elements, to show empty state message
count: filteredOptions.length || 1,
Expand All @@ -80,10 +80,8 @@ const VirtualizedComboBoxMenu = (props: React.ComponentProps<'div'>) => {
return React.cloneElement(menuItem, {
key: virtualItem.key,
ref: virtualizer.measureElement,
'data-iui-virtualizer': 'item',
style: {
position: 'absolute',
top: 0,
left: 0,
width: '100%',
transform: `translateY(${virtualItem.start}px)`,
},
Expand All @@ -94,15 +92,13 @@ const VirtualizedComboBoxMenu = (props: React.ComponentProps<'div'>) => {

return (
<>
<ShadowRoot>
<ShadowRoot css={virtualizerCss}>
<Box
as='div'
data-iui-virtualizer='root'
{...rest}
style={{
minBlockSize: virtualizer.getTotalSize(),
minInlineSize: '100%',
contain: 'layout',
position: 'relative',
...props.style,
}}
>
Expand Down
12 changes: 4 additions & 8 deletions packages/itwinui-react/src/core/Table/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -829,7 +829,7 @@ export const Table = <
}
});

const virtualizer = useVirtualScroll({
const { virtualizer, css: virtualizerCss } = useVirtualScroll({
count: page.length,
getScrollElement: () => tableRef.current,
estimateSize: () => rowHeight,
Expand Down Expand Up @@ -1152,15 +1152,11 @@ export const Table = <
(isSelectable && selectionMode === 'multi') || undefined
}
>
<ShadowRoot>
<ShadowRoot css={virtualizerCss}>
{enableVirtualization && data.length !== 0 ? (
<div
style={{
minBlockSize: virtualizer.getTotalSize(),
minInlineSize: '100%',
contain: 'layout',
position: 'relative',
}}
data-iui-virtualizer='root'
style={{ minBlockSize: virtualizer.getTotalSize() }}
>
<slot />
</div>
Expand Down
8 changes: 2 additions & 6 deletions packages/itwinui-react/src/core/Table/TableRowMemoized.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,7 @@ export const TableRow = <T extends Record<string, unknown>>(props: {
flex: `0 0 auto`,
minWidth: '100%',
...(virtualItem != null
? {
position: 'absolute',
top: 0,
left: 0,
transform: `translateY(${virtualItem.start}px)`,
}
? { transform: `translateY(${virtualItem.start}px)` }
: {}),
},
}),
Expand All @@ -122,6 +117,7 @@ export const TableRow = <T extends Record<string, unknown>>(props: {
'aria-disabled': isDisabled || undefined,
'data-iui-status': status,
'data-iui-index': virtualItem?.index,
...(virtualItem != null && { 'data-iui-virtualizer': 'item' }),
},
};

Expand Down
15 changes: 5 additions & 10 deletions packages/itwinui-react/src/core/Tree/Tree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -294,11 +294,9 @@ export const Tree = <T,>(props: TreeProps<T>) => {
...children.props,
key: virtualItem.key,
'data-iui-index': virtualItem.index,
'data-iui-virtualizer': 'item',
ref: virtualizer.measureElement,
style: {
position: 'absolute',
top: 0,
left: 0,
width: '100%',
transform: `translateY(${virtualItem.start}px)`,
},
Expand Down Expand Up @@ -414,7 +412,7 @@ const VirtualizedTree = React.forwardRef(
[flatNodesList],
);

const virtualizer = useVirtualScroll({
const { virtualizer, css: virtualizerCss } = useVirtualScroll({
count: flatNodesList.length,
getScrollElement: () => parentRef.current,
estimateSize: () => 39, //Set to 39px since that is the height of a treeNode with a sub label with the default font size.
Expand All @@ -429,13 +427,10 @@ const VirtualizedTree = React.forwardRef(

return (
<TreeElement {...rest} ref={useMergedRefs(ref, parentRef)}>
<ShadowRoot>
<ShadowRoot css={virtualizerCss}>
<div
style={{
minBlockSize: virtualizer.getTotalSize(),
contain: 'layout',
position: 'relative',
}}
data-iui-virtualizer='root'
style={{ minBlockSize: virtualizer.getTotalSize() }}
>
<slot />
</div>
Expand Down
55 changes: 44 additions & 11 deletions packages/itwinui-react/src/utils/hooks/useVirtualScroll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,53 @@ import { useVirtualizer } from '@tanstack/react-virtual';
import type { ScrollToOptions, Virtualizer } from '@tanstack/react-virtual';
import React from 'react';

const css = /*css*/ `
[data-iui-virtualizer='root'] {
min-inline-size: 100%;
contain: layout;
position: relative;
}
::slotted([data-iui-virtualizer='item']) {
position: absolute !important;
top: 0 !important;
left: 0 !important;
}
`;

/**
* Wrapper over `useVirtualizer` from `@tanstack/react-virtual` that sets the index attribute to
* `data-iui-index` and adds wraps the `scrollToIndex` function in a `setTimeout` so it can be used in `useLayoutEffect`.
*
* @example
* const virtualizer = useVirtualScroll({
* count: item.length,
* getScrollElement: () => parentRef.current,
* estimateSize: () => 30,
* const { virtualizer, css } = useVirtualScroll({
* count: item.length,
* getScrollElement: () => parentRef.current,
* estimateSize: () => 30,
* });
*
* <Parent ref={parentRef}>
* <ShadowRoot css={css}>
* <div data-iui-virtualizer="root" style={{ height: virtualizer.getTotalSize() }}>
* <slot />
* </div>
* </ShadowRoot>
*
* {virtualizer.getVirtualItems().map((item) => (
* <Item
* data-iui-virtualizer="item"
* data-iui-index={item.index}
* style={{ transform: `translateY(${item.start}px)`}}
* ref={virtualizer.measureElement}
* />
* ))}
* </Parent>
*/
export const useVirtualScroll = (
params: Parameters<typeof useVirtualizer>[0],
): Virtualizer<Element, Element> => {
) => {
const { ...rest } = params;

const virtualizer = useVirtualizer({
const _virtualizer = useVirtualizer({
indexAttribute: 'data-iui-index',
overscan: 10,
...rest,
Expand All @@ -32,13 +62,16 @@ export const useVirtualScroll = (
const scrollToIndex = React.useCallback(
(index: number, options: ScrollToOptions) => {
setTimeout(() => {
virtualizer.scrollToIndex(index, { align: 'auto', ...options });
_virtualizer.scrollToIndex(index, { align: 'auto', ...options });
});
},
[virtualizer],
[_virtualizer],
);

return React.useMemo(() => {
return { ...virtualizer, scrollToIndex };
}, [virtualizer, scrollToIndex]) as Virtualizer<Element, Element>;
const virtualizer = React.useMemo(
() => ({ ..._virtualizer, scrollToIndex }),
[_virtualizer, scrollToIndex],
) as Virtualizer<Element, Element>;

return React.useMemo(() => ({ virtualizer, css }), [virtualizer]);
};

0 comments on commit ba6811b

Please sign in to comment.