react-arborist 2.2.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,18 +3,27 @@ import { ActionTypes } from "../types/utils";
3
3
  export declare type DndState = {
4
4
  dragId: null | string;
5
5
  cursor: Cursor;
6
+ dragIds: string[];
7
+ parentId: null | string;
8
+ index: number;
6
9
  };
7
10
  export declare const actions: {
8
11
  cursor(cursor: Cursor): {
9
12
  type: "DND_CURSOR";
10
13
  cursor: Cursor;
11
14
  };
12
- dragStart(id: string): {
15
+ dragStart(id: string, dragIds: string[]): {
13
16
  type: "DND_DRAG_START";
14
17
  id: string;
18
+ dragIds: string[];
15
19
  };
16
20
  dragEnd(): {
17
21
  type: "DND_DRAG_END";
18
22
  };
23
+ hovering(parentId: string | null, index: number): {
24
+ type: "DND_HOVERING";
25
+ parentId: string | null;
26
+ index: number;
27
+ };
19
28
  };
20
29
  export declare function reducer(state: DndState | undefined, action: ActionTypes<typeof actions>): DndState;
@@ -4,6 +4,5 @@ export declare type CursorLocation = {
4
4
  parentId: string | null;
5
5
  };
6
6
  export declare type DragItem = {
7
- dragIds: string[];
8
7
  id: string;
9
8
  };
@@ -18,19 +18,25 @@ export interface TreeProps<T> {
18
18
  renderCursor?: ElementType<renderers.CursorProps>;
19
19
  renderContainer?: ElementType<{}>;
20
20
  rowHeight?: number;
21
+ overscanCount?: number;
21
22
  width?: number | string;
22
23
  height?: number;
23
24
  indent?: number;
24
25
  paddingTop?: number;
25
26
  paddingBottom?: number;
26
27
  padding?: number;
28
+ childrenAccessor?: string | ((d: T) => T[] | null);
29
+ idAccessor?: string | ((d: T) => string);
27
30
  openByDefault?: boolean;
28
31
  selectionFollowsFocus?: boolean;
29
32
  disableMultiSelection?: boolean;
33
+ disableEdit?: string | boolean | BoolFunc<T>;
30
34
  disableDrag?: string | boolean | BoolFunc<T>;
31
- disableDrop?: string | boolean | BoolFunc<T>;
32
- childrenAccessor?: string | ((d: T) => T[] | null);
33
- idAccessor?: string | ((d: T) => string);
35
+ disableDrop?: string | boolean | ((args: {
36
+ parentNode: NodeApi<T>;
37
+ dragNodes: NodeApi<T>[];
38
+ index: number;
39
+ }) => boolean);
34
40
  onActivate?: (node: NodeApi<T>) => void;
35
41
  onSelect?: (nodes: NodeApi<T>[]) => void;
36
42
  onScroll?: (props: ListOnScrollProps) => void;
@@ -1,13 +1,9 @@
1
- /// <reference types="react" />
2
1
  import { AnyAction } from "redux";
3
2
  import { NodeApi } from "../interfaces/node-api";
4
3
  export interface IdObj {
5
4
  id: string;
6
5
  }
7
6
  export declare type Identity = string | IdObj | null;
8
- declare module "react" {
9
- function forwardRef<T, P = {}>(render: (props: P, ref: React.Ref<T>) => React.ReactElement | null): (props: P & React.RefAttributes<T>) => React.ReactElement | null;
10
- }
11
7
  export declare type BoolFunc<T> = (data: T) => boolean;
12
8
  export declare type ActionTypes<Actions extends {
13
9
  [name: string]: (...args: any[]) => AnyAction;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-arborist",
3
- "version": "2.2.0",
3
+ "version": "3.0.0",
4
4
  "license": "MIT",
5
5
  "source": "src/index.ts",
6
6
  "main": "dist/index.js",
@@ -137,8 +137,7 @@ export function DefaultContainer() {
137
137
  tree.selectAll();
138
138
  return;
139
139
  }
140
- if (e.key === "a" && !e.metaKey) {
141
- if (!tree.props.onCreate) return;
140
+ if (e.key === "a" && !e.metaKey && tree.props.onCreate) {
142
141
  tree.createLeaf();
143
142
  return;
144
143
  }
@@ -161,9 +160,11 @@ export function DefaultContainer() {
161
160
  return;
162
161
  }
163
162
  if (e.key === "Enter") {
164
- if (!tree.props.onRename) return;
163
+ const node = tree.focusedNode;
164
+ if (!node) return;
165
+ if (!node.isEditable || !tree.props.onRename) return;
165
166
  setTimeout(() => {
166
- if (tree.focusedNode) tree.edit(tree.focusedNode);
167
+ if (node) tree.edit(node);
167
168
  });
168
169
  return;
169
170
  }
@@ -221,6 +222,7 @@ export function DefaultContainer() {
221
222
  height={tree.height}
222
223
  width={tree.width}
223
224
  itemSize={tree.rowHeight}
225
+ overscanCount={tree.overscanCount}
224
226
  itemKey={(index) => tree.visibleNodes[index]?.id || index}
225
227
  outerElementType={ListOuterElement}
226
228
  innerElementType={ListInnerElement}
@@ -19,7 +19,6 @@ export function createRoot<T>(tree: TreeApi<T>): NodeApi<T> {
19
19
  id,
20
20
  children: null,
21
21
  isDraggable: tree.isDraggable(data),
22
- isDroppable: tree.isDroppable(data),
23
22
  rowIndex: null,
24
23
  });
25
24
  const children = tree.accessChildren(data);
@@ -40,7 +39,6 @@ export function createRoot<T>(tree: TreeApi<T>): NodeApi<T> {
40
39
  parent: null,
41
40
  children: null,
42
41
  isDraggable: true,
43
- isDroppable: true,
44
42
  rowIndex: null,
45
43
  });
46
44
 
@@ -78,21 +78,6 @@ function getDropLevel(
78
78
  return bound(hoverLevel, min, max);
79
79
  }
80
80
 
81
- function canDrop(above: NodeApi | null, below: NodeApi | null) {
82
- if (!above) {
83
- return true;
84
- }
85
-
86
- let n: NodeApi | null = above;
87
- if (isClosed(above) && above !== below) n = above.parent;
88
-
89
- while (n) {
90
- if (!n.isDroppable) return false;
91
- n = n.parent;
92
- }
93
- return true;
94
- }
95
-
96
81
  export type ComputedDrop = {
97
82
  drop: DropResult | null;
98
83
  cursor: Cursor | null;
@@ -147,10 +132,6 @@ export function computeDrop(args: Args): ComputedDrop {
147
132
  const { node, nextNode, prevNode } = args;
148
133
  const [above, below] = getNodesAroundCursor(node, prevNode, nextNode, hover);
149
134
 
150
- if (!canDrop(above, below)) {
151
- return { drop: null, cursor: noCursor() };
152
- }
153
-
154
135
  /* Hovering over the middle of a folder */
155
136
  if (node && node.isInternal && hover.inMiddle) {
156
137
  return {
@@ -4,7 +4,6 @@ import { getEmptyImage } from "react-dnd-html5-backend";
4
4
  import { useTreeApi } from "../context";
5
5
  import { NodeApi } from "../interfaces/node-api";
6
6
  import { DragItem } from "../types/dnd";
7
- import { IdObj } from "../types/utils";
8
7
  import { DropResult } from "./drop-hook";
9
8
  import { actions as dnd } from "../state/dnd-slice";
10
9
  import { safeRun } from "../utils";
@@ -17,30 +16,28 @@ export function useDragHook<T>(node: NodeApi<T>): ConnectDragSource {
17
16
  () => ({
18
17
  canDrag: () => node.isDraggable,
19
18
  type: "NODE",
20
- item: () => ({
21
- id: node.id,
22
- dragIds: tree.isSelected(node.id) ? Array.from(ids) : [node.id],
23
- }),
24
- start: () => {
25
- tree.dispatch(dnd.dragStart(node.id));
19
+ item: () => {
20
+ // This is fired once at the begging of a drag operation
21
+ const dragIds = tree.isSelected(node.id) ? Array.from(ids) : [node.id];
22
+ tree.dispatch(dnd.dragStart(node.id, dragIds));
23
+ return { id: node.id };
26
24
  },
27
- end: (item, monitor) => {
28
- tree.dispatch(dnd.dragEnd());
25
+ end: () => {
29
26
  tree.hideCursor();
30
- const drop = monitor.getDropResult();
27
+ let { parentId, index, dragIds } = tree.state.dnd;
31
28
  // If they held down meta, we need to create a copy
32
29
  // if (drop.dropEffect === "copy")
33
- if (drop && drop.parentId) {
34
- const parentId = drop.parentId === ROOT_ID ? null : drop.parentId;
30
+ if (tree.canDrop()) {
35
31
  safeRun(tree.props.onMove, {
36
- dragIds: item.dragIds,
37
- parentId,
38
- index: drop.index,
39
- dragNodes: item.dragIds.map((id) => tree.get(id)!),
40
- parentNode: tree.get(drop.parentId),
32
+ dragIds,
33
+ parentId: parentId === ROOT_ID ? null : parentId,
34
+ index,
35
+ dragNodes: tree.dragNodes,
36
+ parentNode: tree.get(parentId),
41
37
  });
42
- tree.open(drop.parentId);
38
+ tree.open(parentId);
43
39
  }
40
+ tree.dispatch(dnd.dragEnd());
44
41
  },
45
42
  }),
46
43
  [ids, node]
@@ -3,8 +3,8 @@ import { ConnectDropTarget, useDrop } from "react-dnd";
3
3
  import { useTreeApi } from "../context";
4
4
  import { NodeApi } from "../interfaces/node-api";
5
5
  import { DragItem } from "../types/dnd";
6
- import { isDecendent } from "../utils";
7
6
  import { computeDrop } from "./compute-drop";
7
+ import { actions as dnd } from "../state/dnd-slice";
8
8
 
9
9
  export type DropResult = {
10
10
  parentId: string | null;
@@ -19,11 +19,11 @@ export function useDropHook(
19
19
  const [_, dropRef] = useDrop<DragItem, DropResult | null, void>(
20
20
  () => ({
21
21
  accept: "NODE",
22
- canDrop: (item, m) => {
23
- if (node.tree.isFiltered) return false;
22
+ canDrop: () => tree.canDrop(),
23
+ hover: (_item, m) => {
24
24
  const offset = m.getClientOffset();
25
- if (!el.current || !offset) return false;
26
- const { drop } = computeDrop({
25
+ if (!el.current || !offset) return;
26
+ const { cursor, drop } = computeDrop({
27
27
  element: el.current,
28
28
  offset: offset,
29
29
  indent: tree.indent,
@@ -31,46 +31,16 @@ export function useDropHook(
31
31
  prevNode: node.prev,
32
32
  nextNode: node.next,
33
33
  });
34
- if (!drop) return false;
35
- const dropParent = tree.get(drop.parentId) ?? tree.root;
34
+ if (drop) tree.dispatch(dnd.hovering(drop.parentId, drop.index));
36
35
 
37
- for (let id of item.dragIds) {
38
- const drag = tree.get(id);
39
- if (!drag) return false;
40
- if (!dropParent) return false;
41
- if (drag.isInternal && isDecendent(dropParent, drag)) return false;
42
- }
43
- return true;
44
- },
45
- hover: (item, m) => {
46
36
  if (m.canDrop()) {
47
- const offset = m.getClientOffset();
48
- if (!el.current || !offset) return;
49
- const { cursor } = computeDrop({
50
- element: el.current,
51
- offset: offset,
52
- indent: tree.indent,
53
- node: node,
54
- prevNode: node.prev,
55
- nextNode: node.next,
56
- });
57
37
  if (cursor) tree.showCursor(cursor);
58
38
  } else {
59
39
  tree.hideCursor();
60
40
  }
61
41
  },
62
- drop: (item, m): DropResult | undefined | null => {
63
- const offset = m.getClientOffset();
64
- if (!el.current || !offset) return;
65
- const { drop } = computeDrop({
66
- element: el.current,
67
- offset: offset,
68
- indent: tree.indent,
69
- node: node,
70
- prevNode: node.prev,
71
- nextNode: node.next,
72
- });
73
- return drop;
42
+ drop: (_, m) => {
43
+ if (!m.canDrop()) return null;
74
44
  },
75
45
  }),
76
46
  [node, el.current, tree.props]
@@ -1,9 +1,9 @@
1
1
  import { useDrop } from "react-dnd";
2
2
  import { useTreeApi } from "../context";
3
3
  import { DragItem } from "../types/dnd";
4
- import { isDecendent } from "../utils";
5
4
  import { computeDrop } from "./compute-drop";
6
5
  import { DropResult } from "./drop-hook";
6
+ import { actions as dnd } from "../state/dnd-slice";
7
7
 
8
8
  export function useOuterDrop() {
9
9
  const tree = useTreeApi();
@@ -12,53 +12,15 @@ export function useOuterDrop() {
12
12
  const [, drop] = useDrop<DragItem, DropResult | null, { isOver: boolean }>(
13
13
  () => ({
14
14
  accept: "NODE",
15
- hover: (item, m) => {
16
- if (!m.isOver({ shallow: true })) return;
17
- if (m.canDrop()) {
18
- const offset = m.getClientOffset();
19
- if (!tree.listEl.current || !offset) return;
20
- const { cursor } = computeDrop({
21
- element: tree.listEl.current,
22
- offset: offset,
23
- indent: tree.indent,
24
- node: null,
25
- prevNode: tree.visibleNodes[tree.visibleNodes.length - 1],
26
- nextNode: null,
27
- });
28
- if (cursor) tree.showCursor(cursor);
29
- } else {
30
- tree.hideCursor();
31
- }
32
- },
33
- canDrop: (item, m) => {
15
+ canDrop: (_item, m) => {
34
16
  if (!m.isOver({ shallow: true })) return false;
35
- if (tree.isFiltered) return false;
36
- const offset = m.getClientOffset();
37
- if (!tree.listEl.current || !offset) return false;
38
- const { drop } = computeDrop({
39
- element: tree.listEl.current,
40
- offset: offset,
41
- indent: tree.indent,
42
- node: null,
43
- prevNode: tree.visibleNodes[tree.visibleNodes.length - 1],
44
- nextNode: null,
45
- });
46
- if (!drop) return false;
47
- const dropParent = tree.get(drop.parentId) ?? tree.root;
48
-
49
- for (let id of item.dragIds) {
50
- const drag = tree.get(id);
51
- if (!drag) return false;
52
- if (!dropParent) return false;
53
- if (drag.isInternal && isDecendent(dropParent, drag)) return false;
54
- }
55
- return true;
17
+ return tree.canDrop();
56
18
  },
57
- drop: (item, m) => {
58
- if (m.didDrop()) return;
19
+ hover: (_item, m) => {
20
+ if (!m.isOver({ shallow: true })) return;
59
21
  const offset = m.getClientOffset();
60
22
  if (!tree.listEl.current || !offset) return;
61
- const { drop } = computeDrop({
23
+ const { cursor, drop } = computeDrop({
62
24
  element: tree.listEl.current,
63
25
  offset: offset,
64
26
  indent: tree.indent,
@@ -66,7 +28,13 @@ export function useOuterDrop() {
66
28
  prevNode: tree.visibleNodes[tree.visibleNodes.length - 1],
67
29
  nextNode: null,
68
30
  });
69
- return drop;
31
+ if (drop) tree.dispatch(dnd.hovering(drop.parentId, drop.index));
32
+
33
+ if (m.canDrop()) {
34
+ if (cursor) tree.showCursor(cursor);
35
+ } else {
36
+ tree.hideCursor();
37
+ }
70
38
  },
71
39
  }),
72
40
  [tree]
@@ -10,7 +10,6 @@ type Params<T> = {
10
10
  children: NodeApi<T>[] | null;
11
11
  parent: NodeApi<T> | null;
12
12
  isDraggable: boolean;
13
- isDroppable: boolean;
14
13
  rowIndex: number | null;
15
14
  tree: TreeApi<T>;
16
15
  };
@@ -23,7 +22,6 @@ export class NodeApi<T = any> {
23
22
  children: NodeApi<T>[] | null;
24
23
  parent: NodeApi<T> | null;
25
24
  isDraggable: boolean;
26
- isDroppable: boolean;
27
25
  rowIndex: number | null;
28
26
 
29
27
  constructor(params: Params<T>) {
@@ -34,7 +32,6 @@ export class NodeApi<T = any> {
34
32
  this.children = params.children;
35
33
  this.parent = params.parent;
36
34
  this.isDraggable = params.isDraggable;
37
- this.isDroppable = params.isDroppable;
38
35
  this.rowIndex = params.rowIndex;
39
36
  }
40
37
 
@@ -58,6 +55,10 @@ export class NodeApi<T = any> {
58
55
  return this.isLeaf ? false : !this.tree.isOpen(this.id);
59
56
  }
60
57
 
58
+ get isEditable() {
59
+ return this.tree.isEditable(this.data);
60
+ }
61
+
61
62
  get isEditing() {
62
63
  return this.tree.editingId === this.id;
63
64
  }
@@ -83,6 +83,10 @@ export class TreeApi<T> {
83
83
  return this.props.rowHeight ?? 24;
84
84
  }
85
85
 
86
+ get overscanCount() {
87
+ return this.props.overscanCount ?? 1;
88
+ }
89
+
86
90
  get searchTerm() {
87
91
  return (this.props.searchTerm || "").trim();
88
92
  }
@@ -394,6 +398,41 @@ export class TreeApi<T> {
394
398
  return this.state.dnd.cursor.type === "highlight";
395
399
  }
396
400
 
401
+ get dragNodes() {
402
+ return this.state.dnd.dragIds
403
+ .map((id) => this.get(id))
404
+ .filter((n) => !!n) as NodeApi<T>[];
405
+ }
406
+
407
+ canDrop() {
408
+ if (this.isFiltered) return false;
409
+ const parentNode = this.get(this.state.dnd.parentId) ?? this.root;
410
+ const dragNodes = this.dragNodes;
411
+ const check = this.props.disableDrop;
412
+
413
+ for (const drag of dragNodes) {
414
+ if (!drag) return false;
415
+ if (!parentNode) return false;
416
+ if (drag.isInternal && utils.isDecendent(parentNode, drag)) return false;
417
+ }
418
+
419
+ // Allow the user to insert their own logic
420
+ if (typeof check == "function") {
421
+ return check({
422
+ parentNode,
423
+ dragNodes: this.dragNodes,
424
+ index: this.state.dnd.index,
425
+ });
426
+ } else if (typeof check == "string") {
427
+ // @ts-ignore
428
+ return !!parentNode.data[check];
429
+ } else if (typeof check === "boolean") {
430
+ return check;
431
+ } else {
432
+ return true;
433
+ }
434
+ }
435
+
397
436
  hideCursor() {
398
437
  this.dispatch(dnd.cursor({ type: "none" }));
399
438
  }
@@ -525,13 +564,13 @@ export class TreeApi<T> {
525
564
  }
526
565
  }
527
566
 
528
- isDraggable(data: T) {
529
- const check = this.props.disableDrag || (() => false);
567
+ isEditable(data: T) {
568
+ const check = this.props.disableEdit || (() => false);
530
569
  return !utils.access(data, check) ?? true;
531
570
  }
532
571
 
533
- isDroppable(data: T) {
534
- const check = this.props.disableDrop || (() => false);
572
+ isDraggable(data: T) {
573
+ const check = this.props.disableDrag || (() => false);
535
574
  return !utils.access(data, check) ?? true;
536
575
  }
537
576
 
@@ -3,33 +3,44 @@ import { ActionTypes } from "../types/utils";
3
3
  import { initialState } from "./initial";
4
4
 
5
5
  /* Types */
6
- export type DndState = { dragId: null | string; cursor: Cursor };
6
+ export type DndState = {
7
+ dragId: null | string;
8
+ cursor: Cursor;
9
+ dragIds: string[];
10
+ parentId: null | string;
11
+ index: number;
12
+ };
7
13
 
8
14
  /* Actions */
9
15
  export const actions = {
10
16
  cursor(cursor: Cursor) {
11
17
  return { type: "DND_CURSOR" as const, cursor };
12
18
  },
13
- dragStart(id: string) {
14
- return { type: "DND_DRAG_START" as const, id };
19
+ dragStart(id: string, dragIds: string[]) {
20
+ return { type: "DND_DRAG_START" as const, id, dragIds };
15
21
  },
16
22
  dragEnd() {
17
23
  return { type: "DND_DRAG_END" as const };
18
24
  },
25
+ hovering(parentId: string | null, index: number) {
26
+ return { type: "DND_HOVERING" as const, parentId, index };
27
+ },
19
28
  };
20
29
 
21
30
  /* Reducer */
22
31
  export function reducer(
23
32
  state: DndState = initialState()["dnd"],
24
33
  action: ActionTypes<typeof actions>
25
- ) {
34
+ ): DndState {
26
35
  switch (action.type) {
27
36
  case "DND_CURSOR":
28
37
  return { ...state, cursor: action.cursor };
29
38
  case "DND_DRAG_START":
30
- return { ...state, dragId: action.id };
39
+ return { ...state, dragId: action.id, dragIds: action.dragIds };
31
40
  case "DND_DRAG_END":
32
- return { ...state, dragId: null };
41
+ return initialState()["dnd"];
42
+ case "DND_HOVERING":
43
+ return { ...state, parentId: action.parentId, index: action.index };
33
44
  default:
34
45
  return state;
35
46
  }
@@ -10,5 +10,11 @@ export const initialState = (props?: TreeProps<any>): RootState => ({
10
10
  drag: { id: null, idWillReceiveDrop: null },
11
11
  selection: { ids: new Set(), anchor: null, mostRecent: null },
12
12
  },
13
- dnd: { cursor: { type: "none" }, dragId: null },
13
+ dnd: {
14
+ cursor: { type: "none" },
15
+ dragId: null,
16
+ dragIds: [],
17
+ parentId: null,
18
+ index: -1,
19
+ },
14
20
  });
package/src/types/dnd.ts CHANGED
@@ -5,6 +5,5 @@ export type CursorLocation = {
5
5
  };
6
6
 
7
7
  export type DragItem = {
8
- dragIds: string[];
9
8
  id: string;
10
9
  };
@@ -4,7 +4,7 @@ import * as renderers from "./renderers";
4
4
  import { ElementType, MouseEventHandler } from "react";
5
5
  import { ListOnScrollProps } from "react-window";
6
6
  import { NodeApi } from "../interfaces/node-api";
7
- import { OpenMap, OpenSlice } from "../state/open-slice";
7
+ import { OpenMap } from "../state/open-slice";
8
8
 
9
9
  export interface TreeProps<T> {
10
10
  /* Data Options */
@@ -26,6 +26,7 @@ export interface TreeProps<T> {
26
26
 
27
27
  /* Sizes */
28
28
  rowHeight?: number;
29
+ overscanCount?: number;
29
30
  width?: number | string;
30
31
  height?: number;
31
32
  indent?: number;
@@ -34,13 +35,21 @@ export interface TreeProps<T> {
34
35
  padding?: number;
35
36
 
36
37
  /* Config */
38
+ childrenAccessor?: string | ((d: T) => T[] | null);
39
+ idAccessor?: string | ((d: T) => string);
37
40
  openByDefault?: boolean;
38
41
  selectionFollowsFocus?: boolean;
39
42
  disableMultiSelection?: boolean;
43
+ disableEdit?: string | boolean | BoolFunc<T>;
40
44
  disableDrag?: string | boolean | BoolFunc<T>;
41
- disableDrop?: string | boolean | BoolFunc<T>;
42
- childrenAccessor?: string | ((d: T) => T[] | null);
43
- idAccessor?: string | ((d: T) => string);
45
+ disableDrop?:
46
+ | string
47
+ | boolean
48
+ | ((args: {
49
+ parentNode: NodeApi<T>;
50
+ dragNodes: NodeApi<T>[];
51
+ index: number;
52
+ }) => boolean);
44
53
 
45
54
  /* Event Handlers */
46
55
  onActivate?: (node: NodeApi<T>) => void;
@@ -7,14 +7,6 @@ export interface IdObj {
7
7
 
8
8
  export type Identity = string | IdObj | null;
9
9
 
10
- // Forward ref can't forward generics without this little re-declare
11
- // https://fettblog.eu/typescript-react-generic-forward-refs/
12
- declare module "react" {
13
- function forwardRef<T, P = {}>(
14
- render: (props: P, ref: React.Ref<T>) => React.ReactElement | null
15
- ): (props: P & React.RefAttributes<T>) => React.ReactElement | null;
16
- }
17
-
18
10
  export type BoolFunc<T> = (data: T) => boolean;
19
11
 
20
12
  export type ActionTypes<
package/src/utils.ts CHANGED
@@ -173,6 +173,6 @@ export function getInsertParentId(tree: TreeApi<any>) {
173
173
  const focus = tree.focusedNode;
174
174
  if (!focus) return null;
175
175
  if (focus.isOpen) return focus.id;
176
- if (focus.parent) return focus.parent.id;
176
+ if (focus.parent && !focus.parent.isRoot) return focus.parent.id;
177
177
  return null;
178
178
  }
package/tsconfig.json CHANGED
@@ -1,28 +1,4 @@
1
1
  {
2
+ "extends": "../../tsconfig.json",
2
3
  "include": ["src/index.ts"],
3
- "compilerOptions": {
4
- /* Visit https://aka.ms/tsconfig.json to read more about this file */
5
-
6
- /* Language and Environment */
7
- "target": "ES5", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
8
- "jsx": "react-jsx", /* Specify what JSX code is generated. */
9
-
10
- /* Modules */
11
- "module": "CommonJS", /* Specify what module code is generated. */
12
- "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
13
-
14
- /* Emit */
15
- "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
16
- "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
17
-
18
- /* Interop Constraints */
19
- "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
20
- "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
21
-
22
- /* Type Checking */
23
- "strict": true, /* Enable all strict type-checking options. */
24
-
25
- /* Completeness */
26
- "skipLibCheck": true, /* Skip type checking all .d.ts files. */
27
- }
28
4
  }