ui: add support for lazily loading menu items

This commit is contained in:
Abdullah Atta
2023-10-24 11:41:10 +05:00
parent e4ed811a2d
commit b31486740e
2 changed files with 34 additions and 5 deletions

View File

@@ -21,11 +21,12 @@ import React, {
useCallback,
useRef,
useEffect,
PropsWithChildren
PropsWithChildren,
useState
} from "react";
import { Box, FlexProps, Text } from "@theme-ui/components";
import { getPosition } from "../../utils/position";
import { MenuButtonItem, MenuItem } from "./types";
import { LazyMenuItemsLoader, MenuButtonItem, MenuItem } from "./types";
import { useFocus } from "./use-focus";
import { MenuSeparator } from "./menu-separator";
import { MenuButton } from "./menu-button";
@@ -90,10 +91,12 @@ export function Menu(props: MenuProps) {
return (
<>
<MenuContainer {...containerProps}>
{items.map((item, index) => {
{items.map(function mapper(item, index) {
if (item.isHidden) return null;
switch (item.type) {
case "lazy-loader":
return <LazyLoader key={item.key} item={item} mapper={mapper} />;
case "separator":
return <MenuSeparator key={item.key} />;
case "button":
@@ -246,6 +249,24 @@ export function MenuPresenter(props: PropsWithChildren<MenuPresenterProps>) {
);
}
function LazyLoader(props: {
item: LazyMenuItemsLoader;
mapper: (item: MenuItem, index: number) => JSX.Element | null;
}) {
const { item, mapper } = props;
const [isLoading, setIsLoading] = useState(true);
const [items, setItems] = useState<MenuItem[]>([]);
useEffect(() => {
(async function () {
setItems(await item.items());
setIsLoading(false);
})();
}, [item]);
return isLoading ? <></> : <>{items.map(mapper)}</>;
}
export * from "./types";
export * from "./menu-button";
export * from "./menu-separator";

View File

@@ -23,7 +23,7 @@ export type MenuItemComponentProps = {
onClick?: (e?: Event) => void;
};
export type MenuItemTypes = "button" | "separator" | "popup";
export type MenuItemTypes = "button" | "separator" | "popup" | "lazy-loader";
export type BaseMenuItem<TType extends MenuItemTypes> = {
type: TType;
key: string;
@@ -37,6 +37,10 @@ export type MenuPopupItem = BaseMenuItem<"popup"> & {
component: (props: MenuItemComponentProps) => JSX.Element;
};
export type LazyMenuItemsLoader = BaseMenuItem<"lazy-loader"> & {
items: () => Promise<MenuItem[]>;
};
export type MenuButtonItem = BaseMenuItem<"button"> & {
onClick?: () => void;
title: string;
@@ -54,4 +58,8 @@ export type MenuButtonItem = BaseMenuItem<"button"> & {
};
};
export type MenuItem = MenuButtonItem | MenuSeperatorItem | MenuPopupItem;
export type MenuItem =
| MenuButtonItem
| MenuSeperatorItem
| MenuPopupItem
| LazyMenuItemsLoader;