Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[New Utility]: Virtualizer #7

Open
junwen-k opened this issue Nov 17, 2024 · 0 comments
Open

[New Utility]: Virtualizer #7

junwen-k opened this issue Nov 17, 2024 · 0 comments
Labels
api-design API needs more thorough consideration enhancement New feature or request

Comments

@junwen-k
Copy link
Owner

Virtualizer

Apply virtualization to a long lists (horizontal, vertical, maybe grid) of elements.

Description

I've built virtualization using react-virtual previously. The component exports parts that apply the required styles to make virtualization work, which look something like:

interface VirtualizerItemProps
  extends Pick<VirtualItem, 'size' | 'start'>,
    ComponentProps<'div'> {
  asChild?: boolean;
  disableDynamicSize?: boolean;
}

export const RowVirtualizerItem = forwardRef<
  ElementRef<'div'>,
  VirtualizerItemProps
>(({ asChild, disableDynamicSize, size, start, className, ...props }, ref) => {
  const Comp = asChild ? Slot : 'div';

  return (
    <Comp
      ref={ref}
      style={{
        height: disableDynamicSize ? `${size}px` : undefined,
        transform: `translateY(${start}px)`,
      }}
      className={cn('absolute left-0 top-0 w-full', className)}
      {...props}
    />
  );
});
RowVirtualizerItem.displayName = 'RowVirtualizerItem';

// ...

export const SelectScrollAreaVirtualizedViewport = ({
  children,
  position = 'popper',
  virtualizerProps,
  ...props
}: SelectScrollAreaVirtualizedViewportProps) => {
  const parentRef =
    React.useRef<React.ElementRef<typeof SelectScrollAreaViewport>>(null);

  const virtualizer = useVirtualizer({
    getScrollElement: () => parentRef.current,
    ...virtualizerProps,
  });

  return (
    <SelectScrollAreaViewport ref={parentRef} position={position} {...props}>
      <RowVirtualizerContainer size={virtualizer.getTotalSize()}>
        {virtualizer.getVirtualItems().map((virtualItem) => (
          <RowVirtualizerItem
            asChild
            key={virtualItem.key}
            size={virtualItem.size}
            start={virtualItem.start}
            // Dyanmic row height implementation. For more information, see https://tanstack.com/virtual/latest/docs/api/virtualizer#measureelement-1.
            data-index={virtualItem.index}
            ref={virtualizer.measureElement}
          >
            {children(virtualItem, virtualizer)}
          </RowVirtualizerItem>
        ))}
      </RowVirtualizerContainer>
    </SelectScrollAreaViewport>
  );
};

However, I thought we can make the API better. Currently was thinking to wrap Virtual Grid to provide a more declarative and elegant API, which supports Horizontal, Vertical, or both using Grid.

The component should also support composition via asChild so that we can compose it with Select and Combobox later if needed.

Anatomy

<Virtualizer.Root>
    <Virtualizer.Grid>
        <Virtualizer.GridItem />
    </Virtualizer.Grid>
    <Virtualizer.Column>
        <Virtualizer.ColumnItem />
    </Virtualizer.Column>
    <Virtualizer.Row>
        <Virtualizer.RowItem />
    </Virtualizer.Row>
</Virtualizer.Root>

Libraries / Hooks

  • react-virtual
  • Virtual Grid - This looks interesting as it seem to provide a higher level of abstraction on top of react-virtual.
@junwen-k junwen-k added enhancement New feature or request api-design API needs more thorough consideration labels Nov 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-design API needs more thorough consideration enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant