From c84de09be04ec30bfd6535e4c3e7042987e16abc Mon Sep 17 00:00:00 2001 From: Abdullah Atta Date: Tue, 24 Oct 2023 11:41:10 +0500 Subject: [PATCH] ui: add support for lazily loading menu items --- packages/ui/src/components/menu/index.tsx | 27 ++++++++++++++++++++--- packages/ui/src/components/menu/types.ts | 12 ++++++++-- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/packages/ui/src/components/menu/index.tsx b/packages/ui/src/components/menu/index.tsx index 796bdd4bd..ad79611b7 100644 --- a/packages/ui/src/components/menu/index.tsx +++ b/packages/ui/src/components/menu/index.tsx @@ -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 ( <> - {items.map((item, index) => { + {items.map(function mapper(item, index) { if (item.isHidden) return null; switch (item.type) { + case "lazy-loader": + return ; case "separator": return ; case "button": @@ -246,6 +249,24 @@ export function MenuPresenter(props: PropsWithChildren) { ); } +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([]); + + 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"; diff --git a/packages/ui/src/components/menu/types.ts b/packages/ui/src/components/menu/types.ts index 88a590d8d..baa892a29 100644 --- a/packages/ui/src/components/menu/types.ts +++ b/packages/ui/src/components/menu/types.ts @@ -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 = { 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; +}; + 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;