Skip to content

Commit

Permalink
Upgrade to react-virtual 3.1.3
Browse files Browse the repository at this point in the history
react-virtual is now available as v3 and published under
@tanstack/react-virtual. The old version will not receive updates
anymore, see cloudscape-design/components#1765 (comment).

Fixes timc1#330
  • Loading branch information
iFreilicht committed Mar 2, 2024
1 parent 952d7c6 commit b7da1ca
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 64 deletions.
76 changes: 41 additions & 35 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@
},
"dependencies": {
"@radix-ui/react-portal": "^1.0.1",
"@tanstack/react-virtual": "^3.1.3",
"fast-equals": "^2.0.3",
"fuse.js": "^6.6.2",
"react-virtual": "^2.8.2",
"tiny-invariant": "^1.2.0"
},
"peerDependencies": {
Expand Down
63 changes: 35 additions & 28 deletions src/KBarResults.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react";
import { useVirtual } from "react-virtual";
import { useVirtualizer } from "@tanstack/react-virtual";
import { ActionImpl } from "./action/ActionImpl";
import { getListboxItemId, KBAR_LISTBOX } from "./KBarSearch";
import { useKBar } from "./useKBar";
Expand All @@ -19,17 +19,19 @@ interface KBarResultsProps {
}

export const KBarResults: React.FC<KBarResultsProps> = (props) => {
const activeRef = React.useRef<HTMLDivElement>(null);
const activeRef = React.useRef<HTMLDivElement | null>(null);
const parentRef = React.useRef(null);

// store a ref to all items so we do not have to pass
// them as a dependency when setting up event listeners.
const itemsRef = React.useRef(props.items);
itemsRef.current = props.items;

const rowVirtualizer = useVirtual({
size: itemsRef.current.length,
parentRef,
const rowVirtualizer = useVirtualizer({
count: itemsRef.current.length,
estimateSize: () => 66,
measureElement: (element) => element.clientHeight,
getScrollElement: () => parentRef.current,
});

const { query, search, currentRootActionId, activeIndex, options } = useKBar(
Expand All @@ -45,7 +47,7 @@ export const KBarResults: React.FC<KBarResultsProps> = (props) => {
if (event.isComposing) {
return;
}

if (event.key === "ArrowUp" || (event.ctrlKey && event.key === "p")) {
event.preventDefault();
event.stopPropagation();
Expand Down Expand Up @@ -84,21 +86,27 @@ export const KBarResults: React.FC<KBarResultsProps> = (props) => {
activeRef.current?.click();
}
};
window.addEventListener("keydown", handler, {capture: true});
return () => window.removeEventListener("keydown", handler, {capture: true});
window.addEventListener("keydown", handler, { capture: true });
return () =>
window.removeEventListener("keydown", handler, { capture: true });
}, [query]);

// destructuring here to prevent linter warning to pass
// entire rowVirtualizer in the dependencies array.
const { scrollToIndex } = rowVirtualizer;
const { scrollToIndex, scrollToOffset } = rowVirtualizer;
React.useEffect(() => {
scrollToIndex(activeIndex, {
// ensure that if the first item in the list is a group
// name and we are focused on the second item, to not
// scroll past that group, hiding it.
align: activeIndex <= 1 ? "end" : "auto",
});
}, [activeIndex, scrollToIndex]);
if (itemsRef.current.length < 1) return;
// ensure that if the first item in the list is a group
// name and we are focused on the second item, to not
// scroll past that group, hiding it.
const targetIndex = activeIndex <= 1 ? 0 : activeIndex;
// Defer scrolling until after animations start, otherwise it will
// fail if the height animation starts from 0
// The divisor of 16 was chosen based on experimentation.
setTimeout(() => {
scrollToIndex(targetIndex)
}, (options.animations?.enterMs ?? 0) / 16)
}, [activeIndex, scrollToIndex, options.animations?.enterMs]);

React.useEffect(() => {
// TODO(tim): fix scenario where async actions load in
Expand Down Expand Up @@ -144,11 +152,11 @@ export const KBarResults: React.FC<KBarResultsProps> = (props) => {
role="listbox"
id={KBAR_LISTBOX}
style={{
height: `${rowVirtualizer.totalSize}px`,
height: `${rowVirtualizer.getTotalSize()}px`,
width: "100%",
}}
>
{rowVirtualizer.virtualItems.map((virtualRow) => {
{rowVirtualizer.getVirtualItems().map((virtualRow) => {
const item = itemsRef.current[virtualRow.index];
const handlers = typeof item !== "string" && {
onPointerMove: () =>
Expand All @@ -162,7 +170,11 @@ export const KBarResults: React.FC<KBarResultsProps> = (props) => {

return (
<div
ref={active ? activeRef : null}
ref={(elem) => {
rowVirtualizer.measureElement(elem);
if (active) activeRef.current = elem;
}}
data-index={virtualRow.index}
id={getListboxItemId(virtualRow.index)}
role="option"
aria-selected={active}
Expand All @@ -176,15 +188,10 @@ export const KBarResults: React.FC<KBarResultsProps> = (props) => {
}}
{...handlers}
>
{React.cloneElement(
props.onRender({
item,
active,
}),
{
ref: virtualRow.measureRef,
}
)}
{props.onRender({
item,
active,
})}
</div>
);
})}
Expand Down

0 comments on commit b7da1ca

Please sign in to comment.