diff --git a/README.md b/README.md index 00f9bc8..5eaaf12 100755 --- a/README.md +++ b/README.md @@ -251,15 +251,16 @@ paired with the [`useVirtualize()`](#usevirtualize) hook. --- -### useNodeProps() +### useNode() -A hook that creates and memoizes node-specific props from a set of input props. +A plugin that creates and memoizes node-specific props. #### Arguments -| Name | Type | Required? | Description | -| ------ | -------------------------- | --------- | -------------------------------------------- | -| config | [`NodeProps`](#node-props) | Yes | Options to generate node-specific props from | +| Name | Type | Required? | Description | +| -------- | ----------------------------------------------------- | --------- | -------------------------------------------- | +| fileTree | `FileTree` | Yes | A file tree | +| config | `Pick, "node" \| "index" \| "style">` | Yes | Options to generate node-specific props from | --- diff --git a/src/index.ts b/src/index.ts index 160f8f5..8096f6f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,8 +15,8 @@ export type { FileTreeFactory, GetNodes, } from "./file-tree"; -export { Node } from "./node"; -export type { NodeProps } from "./node"; +export { Node, useNode } from "./node"; +export type { NodeProps, UseNodeConfig } from "./node"; export { SubjectMap, SubjectSet } from "./observable-data"; export * as pathFx from "./path-fx"; export { subject } from "./tree/subject"; diff --git a/src/node.tsx b/src/node.tsx index 814d11b..8df2d37 100644 --- a/src/node.tsx +++ b/src/node.tsx @@ -13,33 +13,29 @@ import { retryWithBackoff } from "./utils"; * @param props - Node props */ export function Node(props: NodeProps) { - const nodeProps = useNodeProps(props); - const elementProps = useNodePlugins(props.node.id, [ ...(props.plugins ?? empty), - { - didChange: noopSubject, - getProps() { - return nodeProps; - }, - }, + useNode(props.tree, props), ]); return React.createElement(props.as ?? "div", elementProps, props.children); } /** - * A hook that creates and memoizes node-specific props from a set of input props. + * A plugin that creates and memoizes node-specific props. * + * @param fileTree - A file tree * @param config - Props to generate exploration node-specific props from */ -export function useNodeProps(config: Omit, "as">) { - const { node, tree, index, style } = config; +export function useNode( + fileTree: FileTree, + config: UseNodeConfig +) { + const { node, index, style } = config; const type = isDir(node) ? "dir" : isFile(node) ? "file" : "prompt"; const expanded = isDir(node) ? node.expanded : undefined; const { id, depth } = node; - - return React.useMemo>(() => { + const props = React.useMemo>(() => { return { role: "button", style, @@ -63,18 +59,25 @@ export function useNodeProps(config: Omit, "as">) { if (isDir(node)) { if (expanded) { - tree.collapse(node); + fileTree.collapse(node); } else { - retryWithBackoff(() => tree.expand(node), { + retryWithBackoff(() => fileTree.expand(node), { shouldRetry() { - return node.expanded && !tree.isExpanded(node); + return node.expanded && !fileTree.isExpanded(node); }, }).catch(() => {}); } } }, }; - }, [index, depth, expanded, style, type, node, tree, id]); + }, [index, depth, expanded, style, type, node, fileTree, id]); + + return { + didChange: noopSubject, + getProps() { + return props; + }, + }; } const empty: [] = []; @@ -112,3 +115,8 @@ export interface NodeProps { */ children: React.ReactNode; } + +export type UseNodeConfig = Pick< + NodeProps, + "node" | "index" | "style" +>; diff --git a/src/use-virtualize.ts b/src/use-virtualize.ts index 2ff2fed..941872b 100644 --- a/src/use-virtualize.ts +++ b/src/use-virtualize.ts @@ -163,12 +163,12 @@ const createStyle = trieMemoize( [Map, Map], (height: number, top: number): React.CSSProperties => ({ position: "absolute", - width: "100%", - height, contain: "strict", userSelect: "none", - top, + width: "100%", left: 0, + height, + top, }) );