react-arborist 3.10.3 → 3.10.5
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.
- package/dist/main/data/simple-tree.d.ts +14 -8
- package/dist/main/data/simple-tree.js +34 -15
- package/dist/main/data/simple-tree.test.d.ts +1 -0
- package/dist/main/data/simple-tree.test.js +63 -0
- package/dist/main/hooks/use-simple-tree.d.ts +2 -1
- package/dist/main/hooks/use-simple-tree.js +19 -4
- package/dist/main/hooks/use-simple-tree.test.d.ts +1 -0
- package/dist/main/hooks/use-simple-tree.test.js +32 -0
- package/dist/main/hooks/use-validated-props.js +4 -1
- package/dist/main/interfaces/tree-api.d.ts +33 -20
- package/dist/main/interfaces/tree-api.js +48 -23
- package/dist/main/interfaces/tree-api.test.js +48 -0
- package/dist/main/types/handlers.d.ts +1 -1
- package/dist/module/data/simple-tree.d.ts +14 -8
- package/dist/module/data/simple-tree.js +34 -15
- package/dist/module/data/simple-tree.test.d.ts +1 -0
- package/dist/module/data/simple-tree.test.js +61 -0
- package/dist/module/hooks/use-simple-tree.d.ts +2 -1
- package/dist/module/hooks/use-simple-tree.js +19 -4
- package/dist/module/hooks/use-simple-tree.test.d.ts +1 -0
- package/dist/module/hooks/use-simple-tree.test.js +30 -0
- package/dist/module/hooks/use-validated-props.js +4 -1
- package/dist/module/interfaces/tree-api.d.ts +33 -20
- package/dist/module/interfaces/tree-api.js +48 -23
- package/dist/module/interfaces/tree-api.test.js +48 -0
- package/dist/module/types/handlers.d.ts +1 -1
- package/package.json +1 -1
- package/src/data/simple-tree.test.ts +68 -0
- package/src/data/simple-tree.ts +53 -16
- package/src/hooks/use-simple-tree.test.ts +39 -0
- package/src/hooks/use-simple-tree.ts +26 -8
- package/src/hooks/use-validated-props.ts +4 -1
- package/src/interfaces/tree-api.test.ts +46 -0
- package/src/interfaces/tree-api.ts +68 -41
- package/src/types/handlers.ts +3 -1
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
2
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
12
|
const redux_1 = require("redux");
|
|
4
13
|
const root_reducer_1 = require("../state/root-reducer");
|
|
@@ -38,6 +47,45 @@ describe("tree.drop() fires onMove (#313)", () => {
|
|
|
38
47
|
expect(onMove).toHaveBeenCalledWith(expect.objectContaining({ parentId: "folder", index: 0 }));
|
|
39
48
|
});
|
|
40
49
|
});
|
|
50
|
+
describe("custom idAccessor is honored when methods receive raw data (#347)", () => {
|
|
51
|
+
const uuidData = [{ uuid: "a" }, { uuid: "b" }, { uuid: "c" }];
|
|
52
|
+
test("select(data) resolves the id through idAccessor", () => {
|
|
53
|
+
const onSelect = jest.fn();
|
|
54
|
+
const api = setupApi({ data: uuidData, idAccessor: "uuid", onSelect });
|
|
55
|
+
api.select(uuidData[1]);
|
|
56
|
+
expect(api.selectedIds.has("b")).toBe(true);
|
|
57
|
+
expect(api.selectedNodes.map((n) => n.id)).toEqual(["b"]);
|
|
58
|
+
});
|
|
59
|
+
test("focus(data) resolves the id through idAccessor", () => {
|
|
60
|
+
var _a;
|
|
61
|
+
const api = setupApi({ data: uuidData, idAccessor: "uuid" });
|
|
62
|
+
api.focus(uuidData[2]);
|
|
63
|
+
expect((_a = api.focusedNode) === null || _a === void 0 ? void 0 : _a.id).toBe("c");
|
|
64
|
+
});
|
|
65
|
+
test("delete(data) passes the accessor-derived id to onDelete", () => {
|
|
66
|
+
const onDelete = jest.fn();
|
|
67
|
+
const api = setupApi({ data: uuidData, idAccessor: "uuid", onDelete });
|
|
68
|
+
api.delete(uuidData[0]);
|
|
69
|
+
expect(onDelete).toHaveBeenCalledWith(expect.objectContaining({ ids: ["a"] }));
|
|
70
|
+
});
|
|
71
|
+
test("create() focuses the new node by its accessor-derived id", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
72
|
+
// create() passes the raw row data returned by onCreate straight to
|
|
73
|
+
// focus/edit/select; before the fix these read `.id` and lost the node.
|
|
74
|
+
const onCreate = () => ({ uuid: "new" });
|
|
75
|
+
const api = setupApi({ data: uuidData, idAccessor: "uuid", onCreate });
|
|
76
|
+
yield api.create();
|
|
77
|
+
expect(api.state.nodes.focus.id).toBe("new");
|
|
78
|
+
}));
|
|
79
|
+
test("a function idAccessor is honored too", () => {
|
|
80
|
+
const fnData = [{ meta: { key: "x" } }, { meta: { key: "y" } }];
|
|
81
|
+
const api = setupApi({
|
|
82
|
+
data: fnData,
|
|
83
|
+
idAccessor: (d) => d.meta.key,
|
|
84
|
+
});
|
|
85
|
+
api.select(fnData[1]);
|
|
86
|
+
expect(api.selectedIds.has("y")).toBe(true);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
41
89
|
test("rowHeight defaults to 24", () => {
|
|
42
90
|
const api = setupApi({});
|
|
43
91
|
expect(api.rowHeight).toBe(24);
|
|
@@ -5,7 +5,7 @@ export type CreateHandler<T> = (args: {
|
|
|
5
5
|
parentNode: NodeApi<T> | null;
|
|
6
6
|
index: number;
|
|
7
7
|
type: "internal" | "leaf";
|
|
8
|
-
}) => (IdObj | null) | Promise<IdObj | null>;
|
|
8
|
+
}) => (T | IdObj | null) | Promise<T | IdObj | null>;
|
|
9
9
|
export type MoveHandler<T> = (args: {
|
|
10
10
|
dragIds: string[];
|
|
11
11
|
dragNodes: NodeApi<T>[];
|
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
type
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
export type SimpleTreeOptions<T> = {
|
|
2
|
+
idAccessor?: string | ((d: T) => string);
|
|
3
|
+
childrenAccessor?: string | ((d: T) => readonly T[] | null | undefined);
|
|
4
|
+
};
|
|
5
|
+
type Accessors<T> = {
|
|
6
|
+
getId: (data: T) => string;
|
|
7
|
+
getChildren: (data: T) => readonly T[] | null | undefined;
|
|
8
|
+
childrenKey: string;
|
|
5
9
|
};
|
|
6
|
-
export declare class SimpleTree<T
|
|
10
|
+
export declare class SimpleTree<T> {
|
|
7
11
|
root: SimpleNode<T>;
|
|
8
|
-
|
|
12
|
+
private accessors;
|
|
13
|
+
constructor(data: T[], options?: SimpleTreeOptions<T>);
|
|
9
14
|
get data(): T[];
|
|
10
15
|
create(args: {
|
|
11
16
|
parentId: string | null;
|
|
@@ -26,12 +31,13 @@ export declare class SimpleTree<T extends SimpleData> {
|
|
|
26
31
|
}): void;
|
|
27
32
|
find(id: string, node?: SimpleNode<T>): SimpleNode<T> | null;
|
|
28
33
|
}
|
|
29
|
-
declare class SimpleNode<T
|
|
34
|
+
declare class SimpleNode<T> {
|
|
30
35
|
data: T;
|
|
31
36
|
parent: SimpleNode<T> | null;
|
|
37
|
+
private accessors;
|
|
32
38
|
id: string;
|
|
33
39
|
children?: SimpleNode<T>[];
|
|
34
|
-
constructor(data: T, parent: SimpleNode<T> | null);
|
|
40
|
+
constructor(data: T, parent: SimpleNode<T> | null, accessors: Accessors<T>, id?: string);
|
|
35
41
|
hasParent(): this is this & {
|
|
36
42
|
parent: SimpleNode<T>;
|
|
37
43
|
};
|
|
@@ -1,6 +1,17 @@
|
|
|
1
|
+
function resolveAccessors(options = {}) {
|
|
2
|
+
var _a, _b;
|
|
3
|
+
const id = (_a = options.idAccessor) !== null && _a !== void 0 ? _a : "id";
|
|
4
|
+
const children = (_b = options.childrenAccessor) !== null && _b !== void 0 ? _b : "children";
|
|
5
|
+
return {
|
|
6
|
+
getId: typeof id === "function" ? id : (data) => data[id],
|
|
7
|
+
getChildren: typeof children === "function" ? children : (data) => data[children],
|
|
8
|
+
childrenKey: typeof children === "string" ? children : "children",
|
|
9
|
+
};
|
|
10
|
+
}
|
|
1
11
|
export class SimpleTree {
|
|
2
|
-
constructor(data) {
|
|
3
|
-
this.
|
|
12
|
+
constructor(data, options = {}) {
|
|
13
|
+
this.accessors = resolveAccessors(options);
|
|
14
|
+
this.root = createRoot(data, this.accessors);
|
|
4
15
|
}
|
|
5
16
|
get data() {
|
|
6
17
|
var _a, _b;
|
|
@@ -46,22 +57,27 @@ export class SimpleTree {
|
|
|
46
57
|
return null;
|
|
47
58
|
}
|
|
48
59
|
}
|
|
49
|
-
function createRoot(data) {
|
|
50
|
-
|
|
51
|
-
|
|
60
|
+
function createRoot(data, accessors) {
|
|
61
|
+
// The synthetic root has no real data, so it gets an explicit id rather than
|
|
62
|
+
// running the user's accessor on `{}` — a function accessor that reaches into
|
|
63
|
+
// the data (e.g. `d => d.meta.id`) would otherwise throw during construction.
|
|
64
|
+
const root = new SimpleNode({}, null, accessors, "ROOT");
|
|
65
|
+
root.children = data.map((d) => createNode(d, root, accessors));
|
|
52
66
|
return root;
|
|
53
67
|
}
|
|
54
|
-
function createNode(data, parent) {
|
|
55
|
-
const node = new SimpleNode(data, parent);
|
|
56
|
-
|
|
57
|
-
|
|
68
|
+
function createNode(data, parent, accessors) {
|
|
69
|
+
const node = new SimpleNode(data, parent, accessors);
|
|
70
|
+
const children = accessors.getChildren(data);
|
|
71
|
+
if (children)
|
|
72
|
+
node.children = children.map((d) => createNode(d, node, accessors));
|
|
58
73
|
return node;
|
|
59
74
|
}
|
|
60
75
|
class SimpleNode {
|
|
61
|
-
constructor(data, parent) {
|
|
76
|
+
constructor(data, parent, accessors, id) {
|
|
62
77
|
this.data = data;
|
|
63
78
|
this.parent = parent;
|
|
64
|
-
this.
|
|
79
|
+
this.accessors = accessors;
|
|
80
|
+
this.id = id !== null && id !== void 0 ? id : accessors.getId(data);
|
|
65
81
|
}
|
|
66
82
|
hasParent() {
|
|
67
83
|
return !!this.parent;
|
|
@@ -71,16 +87,19 @@ class SimpleNode {
|
|
|
71
87
|
}
|
|
72
88
|
addChild(data, index) {
|
|
73
89
|
var _a, _b;
|
|
74
|
-
const node = createNode(data, this);
|
|
90
|
+
const node = createNode(data, this, this.accessors);
|
|
75
91
|
this.children = (_a = this.children) !== null && _a !== void 0 ? _a : [];
|
|
76
92
|
this.children.splice(index, 0, node);
|
|
77
|
-
|
|
78
|
-
this.data
|
|
93
|
+
const key = this.accessors.childrenKey;
|
|
94
|
+
const raw = this.data;
|
|
95
|
+
raw[key] = (_b = raw[key]) !== null && _b !== void 0 ? _b : [];
|
|
96
|
+
raw[key].splice(index, 0, data);
|
|
79
97
|
}
|
|
80
98
|
removeChild(index) {
|
|
81
99
|
var _a, _b;
|
|
82
100
|
(_a = this.children) === null || _a === void 0 ? void 0 : _a.splice(index, 1);
|
|
83
|
-
|
|
101
|
+
const raw = this.data;
|
|
102
|
+
(_b = raw[this.accessors.childrenKey]) === null || _b === void 0 ? void 0 : _b.splice(index, 1);
|
|
84
103
|
}
|
|
85
104
|
update(changes) {
|
|
86
105
|
if (this.hasParent()) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { SimpleTree } from "./simple-tree";
|
|
2
|
+
describe("SimpleTree with default accessors", () => {
|
|
3
|
+
const data = () => [
|
|
4
|
+
{ id: "1", name: "a", children: [{ id: "1a", name: "a-child" }] },
|
|
5
|
+
{ id: "2", name: "b" },
|
|
6
|
+
];
|
|
7
|
+
test("finds nodes by id, including nested ones", () => {
|
|
8
|
+
var _a, _b;
|
|
9
|
+
const tree = new SimpleTree(data());
|
|
10
|
+
expect((_a = tree.find("2")) === null || _a === void 0 ? void 0 : _a.data.name).toBe("b");
|
|
11
|
+
expect((_b = tree.find("1a")) === null || _b === void 0 ? void 0 : _b.data.name).toBe("a-child");
|
|
12
|
+
});
|
|
13
|
+
test("moves a node into a folder", () => {
|
|
14
|
+
const tree = new SimpleTree(data());
|
|
15
|
+
tree.move({ id: "2", parentId: "1", index: 1 });
|
|
16
|
+
expect(tree.data[0].children.map((c) => c.id)).toEqual(["1a", "2"]);
|
|
17
|
+
expect(tree.data).toHaveLength(1);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
describe("SimpleTree honors custom accessors (issue #73, #170)", () => {
|
|
21
|
+
// Custom keys: `uuid` for the id, `elements` for the children.
|
|
22
|
+
const data = () => [
|
|
23
|
+
{ uuid: "1", name: "a", elements: [{ uuid: "1a", name: "a-child" }] },
|
|
24
|
+
{ uuid: "2", name: "b" },
|
|
25
|
+
];
|
|
26
|
+
function tree() {
|
|
27
|
+
return new SimpleTree(data(), { idAccessor: "uuid", childrenAccessor: "elements" });
|
|
28
|
+
}
|
|
29
|
+
test("finds nodes by the custom id key, including nested ones", () => {
|
|
30
|
+
var _a, _b;
|
|
31
|
+
const t = tree();
|
|
32
|
+
expect((_a = t.find("2")) === null || _a === void 0 ? void 0 : _a.data.name).toBe("b");
|
|
33
|
+
expect((_b = t.find("1a")) === null || _b === void 0 ? void 0 : _b.data.name).toBe("a-child"); // read through `elements`
|
|
34
|
+
});
|
|
35
|
+
test("reorders a node, writing children back under the custom key (#170)", () => {
|
|
36
|
+
const t = tree();
|
|
37
|
+
t.move({ id: "2", parentId: "1", index: 1 });
|
|
38
|
+
expect(t.data).toHaveLength(1);
|
|
39
|
+
expect(t.data[0].elements.map((c) => c.uuid)).toEqual(["1a", "2"]);
|
|
40
|
+
});
|
|
41
|
+
test("moving a node with children into a childless node keeps its children (#73)", () => {
|
|
42
|
+
const t = tree();
|
|
43
|
+
// Put node "1" (which has children) inside node "2" (which has none).
|
|
44
|
+
t.move({ id: "1", parentId: "2", index: 0 });
|
|
45
|
+
expect(t.data.map((n) => n.uuid)).toEqual(["2"]);
|
|
46
|
+
const moved = t.find("1");
|
|
47
|
+
expect(moved === null || moved === void 0 ? void 0 : moved.data.elements.map((c) => c.uuid)).toEqual(["1a"]);
|
|
48
|
+
});
|
|
49
|
+
test("supports a function idAccessor", () => {
|
|
50
|
+
var _a;
|
|
51
|
+
const t = new SimpleTree(data(), { idAccessor: (d) => d.uuid, childrenAccessor: "elements" });
|
|
52
|
+
expect((_a = t.find("1a")) === null || _a === void 0 ? void 0 : _a.data.name).toBe("a-child");
|
|
53
|
+
t.move({ id: "2", parentId: "1", index: 1 });
|
|
54
|
+
expect(t.data[0].elements.map((c) => c.uuid)).toEqual(["1a", "2"]);
|
|
55
|
+
});
|
|
56
|
+
test("a function idAccessor that reaches into the data doesn't throw on construction", () => {
|
|
57
|
+
const nested = [{ meta: { id: "x" }, name: "x" }];
|
|
58
|
+
// The synthetic root must not run this accessor on its empty data.
|
|
59
|
+
expect(() => new SimpleTree(nested, { idAccessor: (d) => d.meta.id })).not.toThrow();
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { SimpleTreeOptions } from "../data/simple-tree";
|
|
1
2
|
import { CreateHandler, DeleteHandler, MoveHandler, RenameHandler } from "../types/handlers";
|
|
2
3
|
export type SimpleTreeData = {
|
|
3
4
|
id: string;
|
|
4
5
|
name: string;
|
|
5
6
|
children?: SimpleTreeData[];
|
|
6
7
|
};
|
|
7
|
-
export declare function useSimpleTree<T>(initialData: readonly T[]): readonly [readonly T[], {
|
|
8
|
+
export declare function useSimpleTree<T>(initialData: readonly T[], options?: SimpleTreeOptions<T>): readonly [readonly T[], {
|
|
8
9
|
onMove: MoveHandler<T>;
|
|
9
10
|
onRename: RenameHandler<T>;
|
|
10
11
|
onCreate: CreateHandler<T>;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { useMemo, useState } from "react";
|
|
2
2
|
import { SimpleTree } from "../data/simple-tree";
|
|
3
3
|
let nextId = 0;
|
|
4
|
-
export function useSimpleTree(initialData) {
|
|
4
|
+
export function useSimpleTree(initialData, options = {}) {
|
|
5
5
|
const [data, setData] = useState(initialData);
|
|
6
|
-
const
|
|
6
|
+
const idAccessor = options.idAccessor;
|
|
7
|
+
const childrenAccessor = options.childrenAccessor;
|
|
8
|
+
const tree = useMemo(() => new SimpleTree(data, { idAccessor, childrenAccessor }), [data, idAccessor, childrenAccessor]);
|
|
7
9
|
const onMove = (args) => {
|
|
8
10
|
for (const id of args.dragIds) {
|
|
9
11
|
tree.move({ id, parentId: args.parentId, index: args.index });
|
|
@@ -14,10 +16,23 @@ export function useSimpleTree(initialData) {
|
|
|
14
16
|
tree.update({ id, changes: { name } });
|
|
15
17
|
setData(tree.data);
|
|
16
18
|
};
|
|
19
|
+
// New nodes must carry their id/children under the same keys the accessors
|
|
20
|
+
// read, or the controller (and the tree's own accessId) can't find them
|
|
21
|
+
// afterward (issue #73). A function accessor can't be inverted to a writable
|
|
22
|
+
// key, so node creation with one isn't supportable — fail fast instead of
|
|
23
|
+
// returning a node that throws deeper in the tree.
|
|
24
|
+
const idKey = typeof idAccessor === "string" ? idAccessor : "id";
|
|
25
|
+
const childrenKey = typeof childrenAccessor === "string" ? childrenAccessor : "children";
|
|
17
26
|
const onCreate = ({ parentId, index, type }) => {
|
|
18
|
-
|
|
27
|
+
if (typeof idAccessor === "function") {
|
|
28
|
+
throw new Error(`React Arborist => initialData can't create nodes when idAccessor is a function: the generated id can't be written under a key the accessor reads. Use a string idAccessor, or the controlled \`data\` prop with your own onCreate.`);
|
|
29
|
+
}
|
|
30
|
+
if (type === "internal" && typeof childrenAccessor === "function") {
|
|
31
|
+
throw new Error(`React Arborist => initialData can't create folder nodes when childrenAccessor is a function: the new children array can't be written under a key the accessor reads. Use a string childrenAccessor, or the controlled \`data\` prop with your own onCreate.`);
|
|
32
|
+
}
|
|
33
|
+
const data = { [idKey]: `simple-tree-id-${nextId++}`, name: "" };
|
|
19
34
|
if (type === "internal")
|
|
20
|
-
data
|
|
35
|
+
data[childrenKey] = [];
|
|
21
36
|
tree.create({ parentId, index, data });
|
|
22
37
|
setData(tree.data);
|
|
23
38
|
return data;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { act, renderHook } from "@testing-library/react";
|
|
2
|
+
import { useSimpleTree } from "./use-simple-tree";
|
|
3
|
+
/* onCreate has to write a new node's id (and a folder's children) under a key
|
|
4
|
+
the accessors will read back. A function accessor can't be inverted to a key,
|
|
5
|
+
so creation with one must fail fast rather than return an unusable node
|
|
6
|
+
(issue #73 review follow-up). */
|
|
7
|
+
describe("useSimpleTree onCreate guards function accessors", () => {
|
|
8
|
+
function controllerFor(data, options) {
|
|
9
|
+
const { result } = renderHook(() => useSimpleTree(data, options));
|
|
10
|
+
return result.current[1];
|
|
11
|
+
}
|
|
12
|
+
const create = { parentId: null, parentNode: null, index: 0 };
|
|
13
|
+
test("throws when idAccessor is a function", () => {
|
|
14
|
+
const controller = controllerFor([{ uuid: "1", name: "a" }], { idAccessor: (d) => d.uuid });
|
|
15
|
+
expect(() => controller.onCreate(Object.assign(Object.assign({}, create), { type: "leaf" }))).toThrow(/idAccessor is a function/);
|
|
16
|
+
});
|
|
17
|
+
test("throws when creating a folder with a function childrenAccessor", () => {
|
|
18
|
+
const controller = controllerFor([{ id: "1", name: "a" }], {
|
|
19
|
+
childrenAccessor: (d) => d.kids,
|
|
20
|
+
});
|
|
21
|
+
expect(() => controller.onCreate(Object.assign(Object.assign({}, create), { type: "internal" }))).toThrow(/childrenAccessor is a function/);
|
|
22
|
+
});
|
|
23
|
+
test("a leaf can still be created when only childrenAccessor is a function", () => {
|
|
24
|
+
const controller = controllerFor([{ id: "1", name: "a" }], {
|
|
25
|
+
childrenAccessor: (d) => d.kids,
|
|
26
|
+
});
|
|
27
|
+
// onCreate calls setData, so run it inside act to keep the suite warning-clean.
|
|
28
|
+
expect(() => act(() => void controller.onCreate(Object.assign(Object.assign({}, create), { type: "leaf" })))).not.toThrow();
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -15,7 +15,10 @@ Use the data prop if you want to provide your own handlers.`);
|
|
|
15
15
|
*
|
|
16
16
|
* We will provide the real data and the handlers to update it.
|
|
17
17
|
* */
|
|
18
|
-
const [data, controller] = useSimpleTree(props.initialData
|
|
18
|
+
const [data, controller] = useSimpleTree(props.initialData, {
|
|
19
|
+
idAccessor: props.idAccessor,
|
|
20
|
+
childrenAccessor: props.childrenAccessor,
|
|
21
|
+
});
|
|
19
22
|
return Object.assign(Object.assign(Object.assign({}, props), controller), { data });
|
|
20
23
|
}
|
|
21
24
|
else {
|
|
@@ -149,6 +149,19 @@ export declare class TreeApi<T> {
|
|
|
149
149
|
get matchFn(): (node: NodeApi<T>) => boolean;
|
|
150
150
|
accessChildren(data: T): readonly T[] | null;
|
|
151
151
|
accessId(data: T): string;
|
|
152
|
+
/**
|
|
153
|
+
* Resolve an identifier to a node id. Public methods accept an id string, a
|
|
154
|
+
* NodeApi, or the raw row data; this is the one place that turns any of those
|
|
155
|
+
* into the string id used internally. Raw data is run through the configured
|
|
156
|
+
* `idAccessor` so a custom accessor (e.g. `uuid`) is honored everywhere, not
|
|
157
|
+
* just where nodes were built. A NodeApi already carries its accessor-derived
|
|
158
|
+
* `id`, so it is used directly rather than re-accessed (the accessor reads the
|
|
159
|
+
* underlying data, which a NodeApi does not expose under that key). Unlike
|
|
160
|
+
* `accessId`, an unresolved id comes back as `undefined` rather than throwing,
|
|
161
|
+
* preserving the previous behavior of the `id`-only lookup.
|
|
162
|
+
*/
|
|
163
|
+
identify(identity: string | IdObj | T): string;
|
|
164
|
+
identifyNull(identity: Identity | T): string | null;
|
|
152
165
|
get firstNode(): NodeApi<T>;
|
|
153
166
|
get lastNode(): NodeApi<T>;
|
|
154
167
|
get focusedNode(): NodeApi<T> | null;
|
|
@@ -158,7 +171,7 @@ export declare class TreeApi<T> {
|
|
|
158
171
|
get(id: string | null): NodeApi<T> | null;
|
|
159
172
|
at(index: number): NodeApi<T> | null;
|
|
160
173
|
nodesBetween(startId: string | null, endId: string | null): NodeApi<T>[];
|
|
161
|
-
indexOf(id: Identity): number | null;
|
|
174
|
+
indexOf(id: Identity | T): number | null;
|
|
162
175
|
get editingId(): string | null;
|
|
163
176
|
createInternal(): Promise<void>;
|
|
164
177
|
createLeaf(): Promise<void>;
|
|
@@ -167,36 +180,36 @@ export declare class TreeApi<T> {
|
|
|
167
180
|
parentId?: null | string;
|
|
168
181
|
index?: null | number;
|
|
169
182
|
}): Promise<void>;
|
|
170
|
-
delete(node: Identity | string
|
|
171
|
-
edit(node: string | IdObj): Promise<EditResult>;
|
|
172
|
-
submit(identity: Identity, value: string): Promise<void>;
|
|
183
|
+
delete(node: Identity | T | (string | IdObj | T)[]): Promise<void>;
|
|
184
|
+
edit(node: string | IdObj | T): Promise<EditResult>;
|
|
185
|
+
submit(identity: Identity | T, value: string): Promise<void>;
|
|
173
186
|
reset(): void;
|
|
174
|
-
activate(id: Identity): void;
|
|
187
|
+
activate(id: Identity | T): void;
|
|
175
188
|
private resolveEdit;
|
|
176
189
|
get selectedIds(): Set<string>;
|
|
177
190
|
get selectedNodes(): NodeApi<T>[];
|
|
178
|
-
focus(node: Identity, opts?: {
|
|
191
|
+
focus(node: Identity | T, opts?: {
|
|
179
192
|
scroll?: boolean;
|
|
180
193
|
}): void;
|
|
181
194
|
pageUp(): void;
|
|
182
195
|
pageDown(): void;
|
|
183
|
-
select(node: Identity, opts?: {
|
|
196
|
+
select(node: Identity | T, opts?: {
|
|
184
197
|
align?: Align;
|
|
185
198
|
focus?: boolean;
|
|
186
199
|
}): void;
|
|
187
|
-
deselect(node: Identity): void;
|
|
188
|
-
selectMulti(identity: Identity, opts?: {
|
|
200
|
+
deselect(node: Identity | T): void;
|
|
201
|
+
selectMulti(identity: Identity | T, opts?: {
|
|
189
202
|
align?: Align;
|
|
190
203
|
focus?: boolean;
|
|
191
204
|
}): void;
|
|
192
|
-
selectContiguous(identity: Identity): void;
|
|
205
|
+
selectContiguous(identity: Identity | T): void;
|
|
193
206
|
deselectAll(): void;
|
|
194
207
|
selectAll(): void;
|
|
195
208
|
private filterSelectableNodes;
|
|
196
209
|
setSelection(args: {
|
|
197
|
-
ids: (IdObj | string)[] | null;
|
|
198
|
-
anchor: Identity;
|
|
199
|
-
mostRecent: Identity;
|
|
210
|
+
ids: (IdObj | string | T)[] | null;
|
|
211
|
+
anchor: Identity | T;
|
|
212
|
+
mostRecent: Identity | T;
|
|
200
213
|
}): void;
|
|
201
214
|
get cursorParentId(): string | null;
|
|
202
215
|
get cursorOverFolder(): boolean;
|
|
@@ -208,14 +221,14 @@ export declare class TreeApi<T> {
|
|
|
208
221
|
drop(): void;
|
|
209
222
|
hideCursor(): void;
|
|
210
223
|
showCursor(cursor: Cursor): void;
|
|
211
|
-
open(identity: Identity, redraw?: boolean): void;
|
|
212
|
-
close(identity: Identity, redraw?: boolean): void;
|
|
213
|
-
toggle(identity: Identity): void;
|
|
214
|
-
openParents(identity: Identity): void;
|
|
224
|
+
open(identity: Identity | T, redraw?: boolean): void;
|
|
225
|
+
close(identity: Identity | T, redraw?: boolean): void;
|
|
226
|
+
toggle(identity: Identity | T): void;
|
|
227
|
+
openParents(identity: Identity | T): void;
|
|
215
228
|
openSiblings(node: NodeApi<T>): void;
|
|
216
229
|
openAll(): void;
|
|
217
230
|
closeAll(): void;
|
|
218
|
-
scrollTo(identity: Identity, align?: Align): Promise<void> | undefined;
|
|
231
|
+
scrollTo(identity: Identity | T, align?: Align): Promise<void> | undefined;
|
|
219
232
|
get isEditing(): boolean;
|
|
220
233
|
get isFiltered(): boolean;
|
|
221
234
|
get hasFocus(): boolean;
|
|
@@ -228,10 +241,10 @@ export declare class TreeApi<T> {
|
|
|
228
241
|
isDraggable(data: T): boolean;
|
|
229
242
|
isSelectable(data: T): boolean;
|
|
230
243
|
private isActionPossible;
|
|
231
|
-
isDragging(node: Identity): boolean;
|
|
244
|
+
isDragging(node: Identity | T): boolean;
|
|
232
245
|
isFocused(id: string): boolean;
|
|
233
246
|
isMatch(node: NodeApi<T>): boolean;
|
|
234
|
-
willReceiveDrop(node: Identity): boolean;
|
|
247
|
+
willReceiveDrop(node: Identity | T): boolean;
|
|
235
248
|
onFocus(): void;
|
|
236
249
|
onBlur(): void;
|
|
237
250
|
onItemsRendered(args: ListOnItemsRenderedProps): void;
|