Skip to content

Commit

Permalink
feat: virtualize results (#82)
Browse files Browse the repository at this point in the history
* feat: improved results api

* spike: virtualize/windowing

* fix: keyboard handling adjusted for virtualized

* poc for tom

* alternative virtualization solution

* cleanup, no need for exposing handlers

* cleanup

* cleanup old apis, KBarResults by default virtualized
  • Loading branch information
timc1 authored Oct 24, 2021
1 parent c237b63 commit a9d9aa5
Show file tree
Hide file tree
Showing 10 changed files with 289 additions and 455 deletions.
139 changes: 77 additions & 62 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import "./index.scss";
import * as React from "react";
import { KBarAnimator } from "../../src/KBarAnimator";
import { KBarProvider } from "../../src/KBarContextProvider";
import { Results, useResultItem } from "../../src/Results";
import KBarPortal from "../../src/KBarPortal";
import useMatches, { NO_GROUP } from "../../src/useMatches";
import KBarPositioner from "../../src/KBarPositioner";
import KBarSearch from "../../src/KBarSearch";
import KBarResults from "../../src/KBarResults";
import { Switch, Route, useHistory, Redirect } from "react-router-dom";
import Layout from "./Layout";
import Home from "./Home";
Expand All @@ -15,6 +15,7 @@ import SearchDocsActions from "./SearchDocsActions";
import { createAction } from "../../src/utils";
import { useAnalytics } from "./utils";
import { Action } from "../../src";
import Blog from "./Blog";

const searchStyle = {
padding: "12px 16px",
Expand All @@ -27,11 +28,6 @@ const searchStyle = {
color: "var(--foreground)",
};

const resultsStyle = {
maxHeight: 400,
overflow: "auto",
};

const animatorStyle = {
maxWidth: "600px",
width: "100%",
Expand Down Expand Up @@ -147,6 +143,9 @@ const App = () => {
<Route path="/docs/:slug">
<Docs />
</Route>
<Route path="/blog">
<Blog />
</Route>
<Route path="*">
<Home />
</Route>
Expand All @@ -158,69 +157,85 @@ const App = () => {

function RenderResults() {
const groups = useMatches();
const flattened = React.useMemo(
() =>
groups.reduce((acc, curr) => {
acc.push(curr.name);
acc.push(...curr.actions);
return acc;
}, []),
[groups]
);

return (
<Results>
<div style={resultsStyle}>
{groups.map((group) => (
<div key={group.name}>
{group.name !== NO_GROUP && (
<div style={groupNameStyle}>{group.name}</div>
)}
{group.actions.map((action) => {
return <ResultItem key={action.id} action={action} />;
})}
</div>
))}
</div>
</Results>
<KBarResults
items={flattened.filter((i) => i !== NO_GROUP)}
onRender={({ item, active }) =>
typeof item === "string" ? (
<div style={groupNameStyle}>{item}</div>
) : (
<ResultItem action={item} active={active} />
)
}
/>
);
}

function ResultItem({ action }: { action: Action }) {
const { active, handlers } = useResultItem({ action });

return (
<div
{...handlers}
style={{
padding: "12px 16px",
background: active ? "var(--a1)" : "var(--background)",
borderLeft: `2px solid ${active ? "var(--foreground)" : "transparent"}`,
display: "flex",
alignItems: "center",
justifyContent: "space-between",
cursor: "pointer",
}}
>
<div style={{ display: "flex", gap: "8px", alignItems: "center" }}>
{action.icon && action.icon}
<div style={{ display: "flex", flexDirection: "column" }}>
<span>{action.name}</span>
{action.subtitle && (
<span style={{ fontSize: 12 }}>{action.subtitle}</span>
)}
const ResultItem = React.forwardRef(
(
{
action,
active,
}: {
action: Action;
active: boolean;
},
ref: React.Ref<HTMLDivElement>
) => {
return (
<div
ref={ref}
style={{
padding: "12px 16px",
background: active ? "var(--a1)" : "var(--background)",
borderLeft: `2px solid ${
active ? "var(--foreground)" : "transparent"
}`,
display: "flex",
alignItems: "center",
justifyContent: "space-between",
cursor: "pointer",
}}
>
<div style={{ display: "flex", gap: "8px", alignItems: "center" }}>
{action.icon && action.icon}
<div style={{ display: "flex", flexDirection: "column" }}>
<span>{action.name}</span>
{action.subtitle && (
<span style={{ fontSize: 12 }}>{action.subtitle}</span>
)}
</div>
</div>
{action.shortcut?.length ? (
<div style={{ display: "grid", gridAutoFlow: "column", gap: "4px" }}>
{action.shortcut.map((sc) => (
<kbd
key={sc}
style={{
padding: "4px 6px",
background: "rgba(0 0 0 / .1)",
borderRadius: "4px",
}}
>
{sc}
</kbd>
))}
</div>
) : null}
</div>
{action.shortcut?.length ? (
<div style={{ display: "grid", gridAutoFlow: "column", gap: "4px" }}>
{action.shortcut.map((sc) => (
<kbd
key={sc}
style={{
padding: "4px 6px",
background: "rgba(0 0 0 / .1)",
borderRadius: "4px",
}}
>
{sc}
</kbd>
))}
</div>
) : null}
</div>
);
}
);
}
);

export default App;

Expand Down
55 changes: 39 additions & 16 deletions example/src/Blog.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,46 @@
import * as React from "react";
import useRegisterActions from "../../src/useRegisterActions";
import { createAction } from "../../src/utils";

export default function Blog() {
useRegisterActions([
{
id: "dynamicAction1",
name: "Action only visible in Blog",
shortcut: [],
keywords: "",
perform: () => window.alert("dynamic action"),
},
{
id: "dynamicAction2",
name: "Another action only visible in Blog",
shortcut: [],
keywords: "",
perform: () => window.alert("dynamic action"),
},
]);
const [actions, setActions] = React.useState(
Array.from(Array(4)).map((_, i) =>
createAction({
name: i.toString(),
shortcut: [],
keywords: "",
perform: () => alert(i),
})
)
);

React.useEffect(() => {
setTimeout(() => {
setActions((actions) => [
...actions,
createAction({
name: "Surprise",
shortcut: [],
keywords: "",
perform: () => alert("Surprise"),
}),
createAction({
name: "Surprise 2",
shortcut: [],
keywords: "",
perform: () => alert("Surprise 2"),
}),
createAction({
name: "Surprise 3",
shortcut: [],
keywords: "",
perform: () => alert("Surprise 3"),
}),
]);
}, 2000);
}, []);

useRegisterActions(actions, [actions]);

return <div>Blog</div>;
}
39 changes: 36 additions & 3 deletions package-lock.json

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

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@
"dependencies": {
"@reach/portal": "^0.16.0",
"fast-equals": "^2.0.3",
"match-sorter": "^6.3.0"
"match-sorter": "^6.3.0",
"react-virtual": "^2.8.2"
},
"peerDependencies": {
"react": "^16.0.0 || ^17.0.0",
Expand Down
Loading

1 comment on commit a9d9aa5

@vercel
Copy link

@vercel vercel bot commented on a9d9aa5 Oct 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

Please sign in to comment.