diff --git a/apps/web/src/components/list-container/index.tsx b/apps/web/src/components/list-container/index.tsx index 570d87a4a..1f9e7b06f 100644 --- a/apps/web/src/components/list-container/index.tsx +++ b/apps/web/src/components/list-container/index.tsx @@ -38,7 +38,7 @@ import { isGroupHeader } from "@notesnook/core"; import { VirtualizedList } from "../virtualized-list"; -import { Virtualizer } from "@tanstack/react-virtual"; +import { ScrollToOptions, Virtualizer } from "@tanstack/react-virtual"; import { useResolvedItem } from "./resolved-item"; type ListContainerProps = { @@ -138,64 +138,18 @@ function ListContainer(props: ListContainerProps) { onFocus: () => onFocus(index), onMouseDown: (e) => onMouseDown(e.nativeEvent, index) })} - renderItem={function ItemRenderer({ index }) { - const resolvedItem = useResolvedItem({ index, items }); - // console.log("Rendering:", index); - if (!resolvedItem) - return
; - - return ( - <> - {resolvedItem.group && group ? ( - { - let endIndex; - for ( - let i = index + 1; - i < props.items.ids.length; - ++i - ) { - if (typeof props.items.ids[i] === "object") { - endIndex = i; - break; - } - } - setSelectedItems([ - ...selectionStore.get().selectedItems, - ...props.items.ids.slice( - index, - endIndex || props.items.ids.length - ) - ]); - }} - groups={async () => - items.groups ? items.groups() : [] - } - onJump={(index) => { - listRef.current?.scrollToIndex(index, { - align: "center", - behavior: "auto" - }); - setFocusedGroupIndex(index); - }} - /> - ) : null} - - - ); + context={{ + items, + group, + refresh, + focusedGroupIndex, + selectItems: setSelectedItems, + scrollToIndex: listRef.current?.scrollToIndex, + focusGroup: setFocusedGroupIndex, + context, + compact }} + renderItem={ItemRenderer} /> @@ -227,6 +181,85 @@ function ListContainer(props: ListContainerProps) { } export default ListContainer; +type ListContext = { + items: VirtualizedGrouping; + group: GroupingKey | undefined; + refresh: () => void; + focusedGroupIndex: number; + selectItems: (items: any) => void; + scrollToIndex?: ( + index: number, + options?: ScrollToOptions | undefined + ) => void; + focusGroup: (index: number) => void; + context?: Context; + compact?: boolean; +}; +function ItemRenderer({ + index, + context +}: { + index: number; + context: ListContext; +}) { + const { + items, + group, + refresh, + focusedGroupIndex, + focusGroup, + selectItems, + scrollToIndex, + context: itemContext, + compact + } = context; + const resolvedItem = useResolvedItem({ index, items }); + if (!resolvedItem) return
; + + return ( + <> + {resolvedItem.group && group ? ( + { + let endIndex; + for (let i = index + 1; i < items.ids.length; ++i) { + if (typeof items.ids[i] === "object") { + endIndex = i; + break; + } + } + selectItems([ + ...selectionStore.get().selectedItems, + ...items.ids.slice(index, endIndex || items.ids.length) + ]); + }} + groups={async () => (items.groups ? items.groups() : [])} + onJump={(index) => { + scrollToIndex?.(index, { + align: "center", + behavior: "auto" + }); + focusGroup(index); + }} + /> + ) : null} + + + ); +} + /** * Scroll the element at the specified index into view and * wait until it renders into the DOM. This function keeps diff --git a/apps/web/src/components/list-container/resolved-item.tsx b/apps/web/src/components/list-container/resolved-item.tsx index 17b5b0901..949d4747c 100644 --- a/apps/web/src/components/list-container/resolved-item.tsx +++ b/apps/web/src/components/list-container/resolved-item.tsx @@ -52,7 +52,7 @@ export function ResolvedItem( [index, items] ); - if (result.status !== "fulfilled" || !result.value) return null; + if (result.status === "rejected" || !result.value) return null; if (result.value.item.type !== type) return null; return <>{children(result.value)}; @@ -67,7 +67,7 @@ export function useResolvedItem( [index, items] ); - if (result.status !== "fulfilled" || !result.value) return null; + if (result.status === "rejected" || !result.value) return null; return result.value; } diff --git a/apps/web/src/components/virtualized-list/index.tsx b/apps/web/src/components/virtualized-list/index.tsx index 242ca0947..8188ce7b8 100644 --- a/apps/web/src/components/virtualized-list/index.tsx +++ b/apps/web/src/components/virtualized-list/index.tsx @@ -21,7 +21,7 @@ import { Virtualizer, useVirtualizer } from "@tanstack/react-virtual"; import { Box, BoxProps } from "@theme-ui/components"; import React, { useRef } from "react"; -export type VirtualizedListProps = { +export type VirtualizedListProps = { virtualizerRef?: React.MutableRefObject< Virtualizer | undefined >; @@ -30,13 +30,18 @@ export type VirtualizedListProps = { estimatedSize: number; getItemKey: (index: number, items: T[]) => string; scrollElement?: Element | null; + context?: C; itemWrapperProps?: (item: T, index: number) => BoxProps; - renderItem: (props: { item: T; index: number }) => JSX.Element | null; + renderItem: (props: { + item: T; + index: number; + context: C; + }) => JSX.Element | null; scrollMargin?: number; itemGap?: number; overscan?: number; } & BoxProps; -export function VirtualizedList(props: VirtualizedListProps) { +export function VirtualizedList(props: VirtualizedListProps) { const { items, getItemKey, @@ -49,6 +54,7 @@ export function VirtualizedList(props: VirtualizedListProps) { itemWrapperProps, itemGap, overscan = 5, + context, ...containerProps } = props; const containerRef = useRef(null); @@ -99,7 +105,12 @@ export function VirtualizedList(props: VirtualizedListProps) { }px)` }} > - + ))} diff --git a/apps/web/src/hooks/use-promise.ts b/apps/web/src/hooks/use-promise.ts index 039e3615c..7f6f8693a 100644 --- a/apps/web/src/hooks/use-promise.ts +++ b/apps/web/src/hooks/use-promise.ts @@ -20,11 +20,12 @@ along with this program. If not, see . import { DependencyList, useEffect, useState } from "react"; export type PromiseResult = - | PromisePendingResult + | PromisePendingResult | (PromiseSettledResult & { refresh: () => void }); -export interface PromisePendingResult { +export interface PromisePendingResult { status: "pending"; + value?: T; } /** @@ -62,7 +63,10 @@ export default function usePromise( useEffect(function effect() { if (result.status !== "pending") { - setResult({ status: "pending" }); + setResult((s) => ({ + ...s, + status: "pending" + })); } const controller = new AbortController();