Skip to content

Commit

Permalink
Dnd Root Element Prop (#33)
Browse files Browse the repository at this point in the history
The Tree component now has a dndRootElement prop that accepts null, undefined, or an HTML Node. If this prop exists, the drag and drop event handlers that are required by react-dnd will be scoped to that element. Any other native drag and drop listeners will work if they are not contained by the dndRootElement.
  • Loading branch information
jameskerr authored May 28, 2022
1 parent d1bc649 commit 065c431
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 51 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ Unlike other Tree Components, react-arborist is designed as a [controlled compon
| isOpenAccessor | "isOpen" | Used to get a node's openness state if it exists on a property other than "isOpen". |
| openByDefault | true | Choose if the node should be open or closed when it has an undefined openness state. |
| className | undefined | Adds a class to the containing div. |
| dndRootElement | undefined | The element for react-dnd to bind it's events to. Defaults to window. See https://github.com/brimdata/react-arborist/pull/33 |
The only child of the Tree Component must be a NodeRenderer function as described below.
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"./packages/*"
],
"scripts": {
"bump": "yarn workspace react-arborist version"
"bump": "yarn workspace react-arborist version",
"dev": "yarn workspace demo start"
},
"private": true,
"packageManager": "[email protected]",
Expand Down
2 changes: 1 addition & 1 deletion packages/demo/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default function App() {
return (
<div className="example">
<main>
<h1>React Arborist</h1>
<h1 draggable>React Arborist</h1>
<p>
In this demo, we have the Game of Thrones family tree rendered with
the <code>Tree</code> component. You can drag and drop the items in
Expand Down
62 changes: 33 additions & 29 deletions packages/demo/src/got.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,43 @@
import React from "react";
import React, { useRef } from "react";
// @ts-ignore
import AutoSize from "react-virtualized-auto-sizer";
import { Tree, TreeApi } from "react-arborist";
import { Node } from "./node";
import { useBackend } from "./backend";
import { MyData, useBackend } from "./backend";

export function GotLineage() {
const backend = useBackend();
const rootElement = useRef<HTMLDivElement | null>(null);
return (
<AutoSize>
{(props: any) => (
<Tree
ref={(tree: TreeApi) => {
// @ts-ignore
global.tree = tree;
}}
className="react-aborist"
data={backend.data}
getChildren="children"
isOpen="isOpen"
disableDrop={(d) => d.name === "House Arryn"}
hideRoot
indent={24}
onMove={backend.onMove}
onToggle={backend.onToggle}
onEdit={backend.onEdit}
rowHeight={22}
width={props.width}
height={props.height}
onClick={() => console.log("clicked the tree")}
onContextMenu={() => console.log("context menu the tree")}
>
{Node}
</Tree>
)}
</AutoSize>
<div ref={rootElement} style={{ height: "100%", width: "100%" }}>
<AutoSize>
{(props: any) => (
<Tree
ref={(tree) => {
// @ts-ignore
global.tree = tree;
}}
className="react-aborist"
data={backend.data}
getChildren="children"
isOpen="isOpen"
disableDrop={(d: MyData) => d.name === "House Arryn"}
hideRoot
indent={24}
onMove={backend.onMove}
onToggle={backend.onToggle}
onEdit={backend.onEdit}
rowHeight={22}
width={props.width}
height={props.height}
onClick={() => console.log("clicked the tree")}
onContextMenu={() => console.log("context menu the tree")}
dndRootElement={undefined}
>
{Node}
</Tree>
)}
</AutoSize>
</div>
);
}
3 changes: 2 additions & 1 deletion packages/react-arborist/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"scripts": {
"build": "run-p 'build:**'",
"build:js": "parcel build --target main --target module",
"build:types": "tsc --outDir dist"
"build:types": "tsc --outDir dist",
"watch": "yarn build:types --watch"
},
"peerDependencies": {
"react": ">= 16.14",
Expand Down
27 changes: 21 additions & 6 deletions packages/react-arborist/src/components/tree.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { forwardRef, MouseEventHandler, ReactElement, useMemo, useRef } from "react";
import {
forwardRef,
MouseEventHandler,
ReactElement,
useMemo,
useRef,
} from "react";
import { DndProvider } from "react-dnd";
import { HTML5Backend } from "react-dnd-html5-backend";
import { FixedSizeList } from "react-window";
Expand All @@ -20,8 +26,13 @@ const OuterElement = forwardRef(function Outer(
const { children, ...rest } = props;
const tree = useStaticContext();
return (
// @ts-ignore
<div ref={ref} {...rest} onClick={tree.onClick} onContextMenu={tree.onContextMenu}>
<div
// @ts-ignore
ref={ref}
{...rest}
onClick={tree.onClick}
onContextMenu={tree.onContextMenu}
>
<div
style={{
height: tree.api.visibleNodes.length * tree.rowHeight,
Expand All @@ -39,7 +50,7 @@ const OuterElement = forwardRef(function Outer(
);
});

function List(props: { className?: string}) {
function List(props: { className?: string }) {
const tree = useStaticContext();
return (
<div style={{ height: tree.height, width: tree.width, overflow: "hidden" }}>
Expand Down Expand Up @@ -91,6 +102,7 @@ export const Tree = forwardRef(function Tree<T extends IdObj>(
props.openByDefault,
]
);

return (
<TreeViewProvider
imperativeHandle={ref}
Expand All @@ -107,9 +119,12 @@ export const Tree = forwardRef(function Tree<T extends IdObj>(
onClick={props.onClick}
onContextMenu={props.onContextMenu}
>
<DndProvider backend={HTML5Backend}>
<DndProvider
backend={HTML5Backend}
options={{ rootElement: props.dndRootElement || undefined }}
>
<OuterDrop>
<List className={props.className}/>
<List className={props.className} />
</OuterDrop>
<Preview />
</DndProvider>
Expand Down
30 changes: 17 additions & 13 deletions packages/react-arborist/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,26 +102,30 @@ export type StateContext = {
selection: SelectionState;
visibleIds: string[];
};

type BoolFunc<T> = (data: T) => boolean;

export interface TreeProps<T> {
children: NodeRenderer<T>;
className?: string | undefined;
data: T;
disableDrag?: string | boolean | BoolFunc<T>;
disableDrop?: string | boolean | BoolFunc<T>;
dndRootElement?: globalThis.Node | null;
getChildren?: string | ((d: T) => T[]);
handle?: Ref<TreeApi<T>>; // Deprecated
height?: number;
width?: number;
rowHeight?: number;
indent?: number;
hideRoot?: boolean;
onToggle?: ToggleHandler;
onMove?: MoveHandler;
onEdit?: EditHandler;
getChildren?: string | ((d: T) => T[]);
isOpen?: string | ((d: T) => boolean);
disableDrag?: string | boolean | ((d: T) => boolean);
disableDrop?: string | boolean | ((d: T) => boolean);
openByDefault?: boolean;
className?: string | undefined;
handle?: Ref<TreeApi<T>>;
indent?: number;
isOpen?: string | BoolFunc<T>;
onClick?: MouseEventHandler;
onContextMenu?: MouseEventHandler;
onEdit?: EditHandler;
onMove?: MoveHandler;
onToggle?: ToggleHandler;
openByDefault?: boolean;
rowHeight?: number;
width?: number;
}

export type TreeProviderProps<T> = {
Expand Down

0 comments on commit 065c431

Please sign in to comment.