From b633f0651207a5fc7c1b886f5535e9491a3003e1 Mon Sep 17 00:00:00 2001 From: Matt <63518180+mreid21@users.noreply.github.com> Date: Tue, 5 Nov 2024 07:55:18 -0500 Subject: [PATCH] fix for broken inference on metadata prop (#193) * rfc-fix for broken inference on metadata prop * updated fix to use type assertion instead of custom forward ref. * fixed missing generics on node * fixed missing generics, added default constraints for all generics --------- Co-authored-by: Mike Ellis <39313898+mellis481@users.noreply.github.com> --- src/TreeView/index.tsx | 27 ++++++++++++++++----------- src/TreeView/node.tsx | 25 +++++++++++++------------ src/TreeView/types.ts | 4 ++-- src/TreeView/utils.ts | 10 +++++----- 4 files changed, 36 insertions(+), 30 deletions(-) diff --git a/src/TreeView/index.tsx b/src/TreeView/index.tsx index a0e77f7c..6ae67612 100644 --- a/src/TreeView/index.tsx +++ b/src/TreeView/index.tsx @@ -34,6 +34,7 @@ import { isBranchNotSelectedAndHasOnlySelectedChild, getOnSelectTreeAction, getBranchNodesToExpand, + IFlatMetadata, } from "./utils"; import { Node } from "./node"; import { @@ -502,9 +503,9 @@ export interface ITreeViewOnLoadDataProps { treeState: ITreeViewState; } -export interface ITreeViewProps { +export interface ITreeViewProps { /** Tree data*/ - data: INode[]; + data: INode[]; /** Function called when a node changes its selected state */ onSelect?: (props: ITreeViewOnSelectProps) => void; /** Function called when a single node is manually selected/unselected. */ @@ -517,7 +518,7 @@ export interface ITreeViewProps { /** className to add to the outermost ul */ className?: string; /** Render prop for the node */ - nodeRenderer: (props: INodeRendererProps) => React.ReactNode; + nodeRenderer: (props: INodeRendererProps) => React.ReactNode; /** Indicates what action will be performed on a node which informs the correct aria-* properties to use on the node (aria-checked if using checkboxes, aria-selected if not). */ nodeAction?: NodeAction; /** Array with the ids of the default expanded nodes */ @@ -553,8 +554,8 @@ export interface ITreeViewProps { focusedId?: NodeId; } -const TreeView = React.forwardRef( - function TreeView( +const TreeView = React.forwardRef( +function TreeView( { data, selectedIds, @@ -579,8 +580,8 @@ const TreeView = React.forwardRef( focusedId, onBlur, ...other - }, - ref + }: ITreeViewProps, + ref: React.ForwardedRef ) { validateTreeViewData(data); const nodeRefs = useRef({}); @@ -648,7 +649,7 @@ const TreeView = React.forwardRef( } setsize={getTreeParent(data).children.length} posinset={index + 1} level={1} @@ -669,9 +670,12 @@ const TreeView = React.forwardRef( /> ))} - ); - } -); + ) + }) + + + + const handleKeyDown = ({ data, @@ -975,6 +979,7 @@ const handleKeyDown = ({ } }; + TreeView.propTypes = { /** Tree data*/ data: PropTypes.array.isRequired, diff --git a/src/TreeView/node.tsx b/src/TreeView/node.tsx index e4f6819d..a4f3f1ba 100644 --- a/src/TreeView/node.tsx +++ b/src/TreeView/node.tsx @@ -22,13 +22,14 @@ import { noop, propagatedIds, getOnSelectTreeAction, + IFlatMetadata, } from "./utils"; import { baseClassNames, clickActions, treeTypes } from "./constants"; -export interface INodeProps { - element: INode; +export interface INodeProps { + element: INode; dispatch: React.Dispatch; - data: INode[]; + data: INode[]; nodeAction: NodeAction; selectedIds: Set; tabbableId: NodeId; @@ -40,7 +41,7 @@ export interface INodeProps { nodeRefs: INodeRefs; leafRefs: INodeRefs; baseClassNames: typeof baseClassNames; - nodeRenderer: (props: INodeRendererProps) => React.ReactNode; + nodeRenderer: (props: INodeRendererProps) => React.ReactNode; setsize: number; posinset: number; level: number; @@ -53,8 +54,8 @@ export interface INodeProps { propagateSelectUpwards: boolean; } -export interface INodeGroupProps - extends Omit { +export interface INodeGroupProps + extends Omit, "setsize" | "posinset"> { getClasses: (className: string) => string; /** don't send this. The NodeGroup render function, determines it for you */ setsize?: undefined; @@ -65,15 +66,15 @@ export interface INodeGroupProps /** * It's convenient to pass props down to the child, but we don't want to pass everything since it would create incorrect values for setsize and posinset */ -const removeIrrelevantGroupProps = ( - nodeProps: INodeProps -): Omit => { +const removeIrrelevantGroupProps = ( + nodeProps: INodeProps +): Omit, "getClasses"> => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const { setsize, posinset, ...rest } = nodeProps; return rest; }; -export const Node = (props: INodeProps) => { +export const Node = (props: INodeProps) => { const { element, dispatch, @@ -311,7 +312,7 @@ export const Node = (props: INodeProps) => { ); }; -export const NodeGroup = ({ +export const NodeGroup = ({ data, element, expandedIds, @@ -319,7 +320,7 @@ export const NodeGroup = ({ baseClassNames, level, ...rest -}: INodeGroupProps) => ( +}: INodeGroupProps) => (
    {expandedIds.has(element.id) && element.children.length > 0 && diff --git a/src/TreeView/types.ts b/src/TreeView/types.ts index 54089659..bea0c943 100644 --- a/src/TreeView/types.ts +++ b/src/TreeView/types.ts @@ -33,9 +33,9 @@ export type EventCallback = ( metadata?: M; } - export interface INodeRendererProps { + export interface INodeRendererProps { /** The object that represents the rendered node */ - element: INode; + element: INode; /** A function which gives back the props to pass to the node */ getNodeProps: (args?: { onClick?: EventCallback; diff --git a/src/TreeView/utils.ts b/src/TreeView/utils.ts index 13758605..a7b53c22 100644 --- a/src/TreeView/utils.ts +++ b/src/TreeView/utils.ts @@ -307,7 +307,7 @@ export type IFlatMetadata = Record< string | number | boolean | undefined | null >; -interface ITreeNode { +interface ITreeNode { id?: NodeId; name: string; isBranch?: boolean; @@ -315,7 +315,7 @@ interface ITreeNode { metadata?: M; } -export const flattenTree = ( +export const flattenTree = ( tree: ITreeNode ): INode[] => { let internalCount = 0; @@ -515,8 +515,8 @@ export const getOnSelectTreeAction = ( return treeTypes.toggleSelect; }; -export const getTreeParent = (data: INode[]): INode => { - const parentNode: INode | undefined = data.find( +export const getTreeParent = (data: INode[]): INode => { + const parentNode: INode | undefined = data.find( (node) => node.parent === null ); @@ -527,7 +527,7 @@ export const getTreeParent = (data: INode[]): INode => { return parentNode; }; -export const getTreeNode = (data: INode[], id: NodeId): INode => { +export const getTreeNode = (data: INode[], id: NodeId): INode => { const treeNode = data.find((node) => node.id === id); if (treeNode == null) {