react-arborist 3.6.1 → 3.8.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.
- package/dist/main/components/cursor.js +1 -2
- package/dist/main/components/default-container.js +31 -1
- package/dist/main/components/default-cursor.js +1 -1
- package/dist/main/components/default-drag-preview.d.ts +1 -1
- package/dist/main/components/default-drag-preview.js +1 -1
- package/dist/main/components/default-row.d.ts +1 -1
- package/dist/main/components/default-row.js +1 -1
- package/dist/main/components/list-outer-element.d.ts +1 -0
- package/dist/main/components/list-outer-element.js +4 -3
- package/dist/main/components/provider.d.ts +1 -1
- package/dist/main/components/provider.js +2 -2
- package/dist/main/components/provider.test.js +70 -0
- package/dist/main/components/row-container.d.ts +1 -1
- package/dist/main/components/row-container.js +2 -3
- package/dist/main/dnd/drag-hook.js +1 -0
- package/dist/main/hooks/use-validated-props.js +1 -2
- package/dist/main/index.d.ts +3 -0
- package/dist/main/index.js +7 -1
- package/dist/main/interfaces/node-api.js +4 -1
- package/dist/main/interfaces/tree-api.d.ts +27 -5
- package/dist/main/interfaces/tree-api.js +98 -14
- package/dist/main/interfaces/tree-api.test.js +31 -0
- package/dist/main/state/drag-slice.js +1 -2
- package/dist/main/types/state.d.ts +1 -1
- package/dist/main/types/tree-props.d.ts +6 -2
- package/dist/module/components/cursor.js +1 -2
- package/dist/module/components/default-container.js +32 -2
- package/dist/module/components/default-cursor.js +1 -1
- package/dist/module/components/default-drag-preview.d.ts +1 -1
- package/dist/module/components/default-drag-preview.js +1 -1
- package/dist/module/components/default-row.d.ts +1 -1
- package/dist/module/components/default-row.js +1 -1
- package/dist/module/components/list-outer-element.d.ts +1 -0
- package/dist/module/components/list-outer-element.js +2 -2
- package/dist/module/components/provider.d.ts +1 -1
- package/dist/module/components/provider.js +4 -4
- package/dist/module/components/provider.test.js +71 -1
- package/dist/module/components/row-container.d.ts +1 -1
- package/dist/module/components/row-container.js +2 -3
- package/dist/module/dnd/compute-drop.js +1 -1
- package/dist/module/dnd/drag-hook.js +1 -0
- package/dist/module/hooks/use-validated-props.js +1 -2
- package/dist/module/index.d.ts +3 -0
- package/dist/module/index.js +3 -0
- package/dist/module/interfaces/node-api.js +4 -1
- package/dist/module/interfaces/tree-api.d.ts +27 -5
- package/dist/module/interfaces/tree-api.js +98 -14
- package/dist/module/interfaces/tree-api.test.js +31 -0
- package/dist/module/state/drag-slice.js +1 -2
- package/dist/module/types/state.d.ts +1 -1
- package/dist/module/types/tree-props.d.ts +6 -2
- package/package.json +27 -27
- package/src/components/cursor.tsx +1 -2
- package/src/components/default-container.tsx +40 -19
- package/src/components/default-cursor.tsx +1 -5
- package/src/components/default-drag-preview.tsx +3 -16
- package/src/components/default-node.tsx +0 -1
- package/src/components/default-row.tsx +2 -13
- package/src/components/drag-preview-container.tsx +1 -1
- package/src/components/list-inner-element.tsx +1 -1
- package/src/components/list-outer-element.tsx +3 -4
- package/src/components/provider.test.tsx +85 -9
- package/src/components/provider.tsx +8 -23
- package/src/components/row-container.tsx +4 -9
- package/src/components/tree.tsx +2 -6
- package/src/context.ts +2 -3
- package/src/data/create-index.ts +0 -1
- package/src/data/create-list.ts +1 -2
- package/src/data/create-root.ts +2 -9
- package/src/data/simple-tree.ts +5 -3
- package/src/dnd/compute-drop.ts +6 -15
- package/src/dnd/drag-hook.ts +1 -0
- package/src/dnd/measure-hover.ts +2 -6
- package/src/dnd/outer-drop-hook.ts +1 -1
- package/src/hooks/use-fresh-node.ts +0 -1
- package/src/hooks/use-simple-tree.ts +2 -8
- package/src/hooks/use-validated-props.ts +4 -8
- package/src/index.ts +3 -0
- package/src/interfaces/node-api.ts +2 -2
- package/src/interfaces/tree-api.test.ts +35 -0
- package/src/interfaces/tree-api.ts +103 -36
- package/src/state/dnd-slice.ts +1 -1
- package/src/state/drag-slice.ts +2 -5
- package/src/state/edit-slice.ts +1 -4
- package/src/state/focus-slice.ts +1 -1
- package/src/state/open-slice.ts +2 -5
- package/src/state/selection-slice.ts +2 -6
- package/src/types/handlers.ts +1 -3
- package/src/types/renderers.ts +0 -1
- package/src/types/state.ts +1 -1
- package/src/types/tree-props.ts +11 -11
- package/src/types/utils.ts +2 -3
- package/src/utils.ts +5 -14
|
@@ -10,8 +10,7 @@ function reducer(state = (0, initial_1.initialState)().nodes.drag, action) {
|
|
|
10
10
|
case "DND_DRAG_END":
|
|
11
11
|
return Object.assign(Object.assign({}, state), { id: null, destinationParentId: null, destinationIndex: null, selectedIds: [] });
|
|
12
12
|
case "DND_HOVERING":
|
|
13
|
-
if (action.parentId !== state.destinationParentId ||
|
|
14
|
-
action.index != state.destinationIndex) {
|
|
13
|
+
if (action.parentId !== state.destinationParentId || action.index != state.destinationIndex) {
|
|
15
14
|
return Object.assign(Object.assign({}, state), { destinationParentId: action.parentId, destinationIndex: action.index });
|
|
16
15
|
}
|
|
17
16
|
else {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { NodeApi } from "../interfaces/node-api";
|
|
2
|
-
export type NodeState = typeof NodeApi.prototype["state"];
|
|
2
|
+
export type NodeState = (typeof NodeApi.prototype)["state"];
|
|
@@ -2,10 +2,12 @@ import { BoolFunc } from "./utils";
|
|
|
2
2
|
import * as handlers from "./handlers";
|
|
3
3
|
import * as renderers from "./renderers";
|
|
4
4
|
import { ElementType, MouseEventHandler } from "react";
|
|
5
|
-
import { ListOnScrollProps } from "react-window";
|
|
5
|
+
import { ListOnScrollProps, CommonProps as ReactWindowCommonProps } from "react-window";
|
|
6
6
|
import { NodeApi } from "../interfaces/node-api";
|
|
7
7
|
import { OpenMap } from "../state/open-slice";
|
|
8
8
|
import { useDragDropManager, DndProviderProps } from "react-dnd";
|
|
9
|
+
/** Returns the height in pixels for a given node's row. */
|
|
10
|
+
export type RowHeightAccessor<T> = (node: NodeApi<T>) => number;
|
|
9
11
|
export interface TreeProps<T> {
|
|
10
12
|
data?: readonly T[];
|
|
11
13
|
initialData?: readonly T[];
|
|
@@ -18,7 +20,7 @@ export interface TreeProps<T> {
|
|
|
18
20
|
renderDragPreview?: ElementType<renderers.DragPreviewProps>;
|
|
19
21
|
renderCursor?: ElementType<renderers.CursorProps>;
|
|
20
22
|
renderContainer?: ElementType<{}>;
|
|
21
|
-
rowHeight?: number
|
|
23
|
+
rowHeight?: number | RowHeightAccessor<T>;
|
|
22
24
|
overscanCount?: number;
|
|
23
25
|
width?: number | string;
|
|
24
26
|
height?: number;
|
|
@@ -57,4 +59,6 @@ export interface TreeProps<T> {
|
|
|
57
59
|
backend: unknown;
|
|
58
60
|
}>["backend"];
|
|
59
61
|
dndManager?: ReturnType<typeof useDragDropManager>;
|
|
62
|
+
outerElementType?: ReactWindowCommonProps["outerElementType"];
|
|
63
|
+
innerElementType?: ReactWindowCommonProps["innerElementType"];
|
|
60
64
|
}
|
|
@@ -8,8 +8,7 @@ export function Cursor() {
|
|
|
8
8
|
if (!cursor || cursor.type !== "line")
|
|
9
9
|
return null;
|
|
10
10
|
const indent = tree.indent;
|
|
11
|
-
const top = tree.
|
|
12
|
-
((_b = (_a = tree.props.padding) !== null && _a !== void 0 ? _a : tree.props.paddingTop) !== null && _b !== void 0 ? _b : 0);
|
|
11
|
+
const top = tree.rowTopPosition(cursor.index) + ((_b = (_a = tree.props.padding) !== null && _a !== void 0 ? _a : tree.props.paddingTop) !== null && _b !== void 0 ? _b : 0);
|
|
13
12
|
const left = indent * cursor.level;
|
|
14
13
|
const Cursor = tree.renderCursor;
|
|
15
14
|
return _jsx(Cursor, { top, left, indent });
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { FixedSizeList } from "react-window";
|
|
2
|
+
import { FixedSizeList, VariableSizeList } from "react-window";
|
|
3
3
|
import { useDataUpdates, useTreeApi } from "../context";
|
|
4
4
|
import { focusNextElement, focusPrevElement } from "../utils";
|
|
5
5
|
import { ListOuterElement } from "./list-outer-element";
|
|
@@ -230,5 +230,35 @@ export function DefaultContainer() {
|
|
|
230
230
|
});
|
|
231
231
|
if (node)
|
|
232
232
|
tree.focus(node.id);
|
|
233
|
-
}, children: _jsx(
|
|
233
|
+
}, children: _jsx(List, {}) }));
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Fixed-height trees (numeric rowHeight) render a FixedSizeList, preserving the
|
|
237
|
+
* original O(1) layout and avoiding VariableSizeList's measurement cache. Only
|
|
238
|
+
* the function form, which needs per-row heights, uses VariableSizeList.
|
|
239
|
+
*/
|
|
240
|
+
function List() {
|
|
241
|
+
var _a, _b;
|
|
242
|
+
const tree = useTreeApi();
|
|
243
|
+
const commonProps = {
|
|
244
|
+
className: tree.props.className,
|
|
245
|
+
outerRef: tree.listEl,
|
|
246
|
+
itemCount: tree.visibleNodes.length,
|
|
247
|
+
height: tree.height,
|
|
248
|
+
width: tree.width,
|
|
249
|
+
overscanCount: tree.overscanCount,
|
|
250
|
+
itemKey: (index) => { var _a; return ((_a = tree.visibleNodes[index]) === null || _a === void 0 ? void 0 : _a.id) || index; },
|
|
251
|
+
outerElementType: (_a = tree.props.outerElementType) !== null && _a !== void 0 ? _a : ListOuterElement,
|
|
252
|
+
innerElementType: (_b = tree.props.innerElementType) !== null && _b !== void 0 ? _b : ListInnerElement,
|
|
253
|
+
onScroll: tree.props.onScroll,
|
|
254
|
+
onItemsRendered: tree.onItemsRendered.bind(tree),
|
|
255
|
+
};
|
|
256
|
+
if (typeof tree.props.rowHeight === "function") {
|
|
257
|
+
return (
|
|
258
|
+
// @ts-ignore
|
|
259
|
+
_jsx(VariableSizeList, Object.assign({}, commonProps, { itemSize: tree.rowHeightAt, ref: tree.list, children: RowContainer })));
|
|
260
|
+
}
|
|
261
|
+
return (
|
|
262
|
+
// @ts-ignore
|
|
263
|
+
_jsx(FixedSizeList, Object.assign({}, commonProps, { itemSize: tree.rowHeight, ref: tree.list, children: RowContainer })));
|
|
234
264
|
}
|
|
@@ -17,7 +17,7 @@ const circleStyle = {
|
|
|
17
17
|
boxShadow: "0 0 0 3px #4B91E2",
|
|
18
18
|
borderRadius: "50%",
|
|
19
19
|
};
|
|
20
|
-
export const DefaultCursor = React.memo(function DefaultCursor({ top, left, indent
|
|
20
|
+
export const DefaultCursor = React.memo(function DefaultCursor({ top, left, indent }) {
|
|
21
21
|
const style = {
|
|
22
22
|
position: "absolute",
|
|
23
23
|
pointerEvents: "none",
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { DragPreviewProps } from "../types/renderers";
|
|
2
|
-
export declare function DefaultDragPreview({ offset, mouse, id, dragIds, isDragging
|
|
2
|
+
export declare function DefaultDragPreview({ offset, mouse, id, dragIds, isDragging }: DragPreviewProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -22,7 +22,7 @@ const getCountStyle = (offset) => {
|
|
|
22
22
|
const { x, y } = offset;
|
|
23
23
|
return { transform: `translate(${x + 10}px, ${y + 10}px)` };
|
|
24
24
|
};
|
|
25
|
-
export function DefaultDragPreview({ offset, mouse, id, dragIds, isDragging
|
|
25
|
+
export function DefaultDragPreview({ offset, mouse, id, dragIds, isDragging }) {
|
|
26
26
|
return (_jsxs(Overlay, { isDragging: isDragging, children: [_jsx(Position, { offset: offset, children: _jsx(PreviewNode, { id: id, dragIds: dragIds }) }), _jsx(Count, { mouse: mouse, count: dragIds.length })] }));
|
|
27
27
|
}
|
|
28
28
|
const Overlay = memo(function Overlay(props) {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { RowRendererProps } from "../types/renderers";
|
|
2
|
-
export declare function DefaultRow<T>({ node, attrs, innerRef, children
|
|
2
|
+
export declare function DefaultRow<T>({ node, attrs, innerRef, children }: RowRendererProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
export function DefaultRow({ node, attrs, innerRef, children
|
|
2
|
+
export function DefaultRow({ node, attrs, innerRef, children }) {
|
|
3
3
|
return (_jsx("div", Object.assign({}, attrs, { ref: innerRef, onFocus: (e) => e.stopPropagation(), onClick: node.handleClick, children: children })));
|
|
4
4
|
}
|
|
@@ -23,10 +23,10 @@ export const ListOuterElement = forwardRef(function Outer(props, ref) {
|
|
|
23
23
|
tree.deselectAll();
|
|
24
24
|
}, children: [_jsx(DropContainer, {}), children] })));
|
|
25
25
|
});
|
|
26
|
-
const DropContainer = () => {
|
|
26
|
+
export const DropContainer = () => {
|
|
27
27
|
const tree = useTreeApi();
|
|
28
28
|
return (_jsx("div", { style: {
|
|
29
|
-
height: tree.visibleNodes.length
|
|
29
|
+
height: tree.rowTopPosition(tree.visibleNodes.length),
|
|
30
30
|
width: "100%",
|
|
31
31
|
position: "absolute",
|
|
32
32
|
left: "0",
|
|
@@ -6,5 +6,5 @@ type Props<T> = {
|
|
|
6
6
|
imperativeHandle: React.Ref<TreeApi<T> | undefined>;
|
|
7
7
|
children: ReactNode;
|
|
8
8
|
};
|
|
9
|
-
export declare function TreeProvider<T>({ treeProps, imperativeHandle, children
|
|
9
|
+
export declare function TreeProvider<T>({ treeProps, imperativeHandle, children }: Props<T>): import("react/jsx-runtime").JSX.Element;
|
|
10
10
|
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useImperativeHandle, useMemo, useRef
|
|
2
|
+
import { useEffect, useImperativeHandle, useMemo, useRef } from "react";
|
|
3
3
|
import { useSyncExternalStore } from "use-sync-external-store/shim";
|
|
4
|
-
import { DataUpdatesContext, DndContext, NodesContext, TreeApiContext
|
|
4
|
+
import { DataUpdatesContext, DndContext, NodesContext, TreeApiContext } from "../context";
|
|
5
5
|
import { TreeApi } from "../interfaces/tree-api";
|
|
6
6
|
import { initialState } from "../state/initial";
|
|
7
7
|
import { rootReducer } from "../state/root-reducer";
|
|
@@ -10,7 +10,7 @@ import { DndProvider } from "react-dnd";
|
|
|
10
10
|
import { createStore } from "redux";
|
|
11
11
|
import { actions as visibility } from "../state/open-slice";
|
|
12
12
|
const SERVER_STATE = initialState();
|
|
13
|
-
export function TreeProvider({ treeProps, imperativeHandle, children
|
|
13
|
+
export function TreeProvider({ treeProps, imperativeHandle, children }) {
|
|
14
14
|
const list = useRef(null);
|
|
15
15
|
const listEl = useRef(null);
|
|
16
16
|
const store = useRef(
|
|
@@ -26,7 +26,7 @@ export function TreeProvider({ treeProps, imperativeHandle, children, }) {
|
|
|
26
26
|
useMemo(() => {
|
|
27
27
|
updateCount.current += 1;
|
|
28
28
|
api.update(treeProps);
|
|
29
|
-
},
|
|
29
|
+
}, Object.values(treeProps));
|
|
30
30
|
/* Rebuild visible nodes when open state changes, without clobbering
|
|
31
31
|
props set imperatively via api.update(). Bumping updateCount keeps
|
|
32
32
|
DataUpdates consumers (e.g. DefaultContainer) in sync. */
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { createRef } from "react";
|
|
3
|
-
import { act, render } from "@testing-library/react";
|
|
3
|
+
import { act, render, screen } from "@testing-library/react";
|
|
4
|
+
import { FixedSizeList, VariableSizeList } from "react-window";
|
|
4
5
|
import { Tree } from "./tree";
|
|
5
6
|
const data = [
|
|
6
7
|
{
|
|
@@ -29,3 +30,72 @@ test("imperative tree.update() props survive node toggles (#228)", () => {
|
|
|
29
30
|
});
|
|
30
31
|
expect(api.rowHeight).toBe(48);
|
|
31
32
|
});
|
|
33
|
+
/* Backwards compatibility: switching FixedSizeList -> VariableSizeList must not
|
|
34
|
+
change layout for a numeric rowHeight. With openByDefault, all four nodes
|
|
35
|
+
(1 > 2, 3 > 4) are visible in DFS order. */
|
|
36
|
+
test("numeric rowHeight positions rows at index * height (#238 back-compat)", () => {
|
|
37
|
+
render(_jsx(Tree, { data: data, rowHeight: 24, openByDefault: true }));
|
|
38
|
+
const rows = screen.getAllByRole("treeitem");
|
|
39
|
+
expect(rows).toHaveLength(4);
|
|
40
|
+
rows.forEach((row, i) => {
|
|
41
|
+
expect(row.style.height).toBe("24px");
|
|
42
|
+
expect(row.style.top).toBe(`${i * 24}px`);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
test("function rowHeight gives each row its own height and cumulative top (#238)", () => {
|
|
46
|
+
const heights = { "1": 40, "2": 20, "3": 30, "4": 10 };
|
|
47
|
+
render(_jsx(Tree, { data: data, rowHeight: (node) => heights[node.id], openByDefault: true }));
|
|
48
|
+
const rows = screen.getAllByRole("treeitem");
|
|
49
|
+
expect(rows).toHaveLength(4);
|
|
50
|
+
const expected = [40, 20, 30, 10];
|
|
51
|
+
let top = 0;
|
|
52
|
+
rows.forEach((row, i) => {
|
|
53
|
+
expect(row.style.height).toBe(`${expected[i]}px`);
|
|
54
|
+
expect(row.style.top).toBe(`${top}px`);
|
|
55
|
+
top += expected[i];
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
test("mutations tell the list to recompute heights (#238)", () => {
|
|
59
|
+
const ref = createRef();
|
|
60
|
+
/* Only variable-height mode renders a VariableSizeList with a measurement
|
|
61
|
+
cache to recompute, so use a function rowHeight here. */
|
|
62
|
+
render(_jsx(Tree, { data: data, ref: ref, rowHeight: () => 24, openByDefault: true }));
|
|
63
|
+
const api = ref.current;
|
|
64
|
+
const reset = jest.spyOn(api.list.current, "resetAfterIndex");
|
|
65
|
+
act(() => api.close("1"));
|
|
66
|
+
expect(reset).toHaveBeenCalled();
|
|
67
|
+
reset.mockClear();
|
|
68
|
+
act(() => api.open("1"));
|
|
69
|
+
expect(reset).toHaveBeenCalled();
|
|
70
|
+
});
|
|
71
|
+
/* react-window caches measurements by index and never invalidates them itself.
|
|
72
|
+
When data changes via props in variable-height mode, those cached sizes belong
|
|
73
|
+
to the wrong rows, so update() must drop the cache. It runs during render, so
|
|
74
|
+
it uses the shouldForceUpdate=false variant. */
|
|
75
|
+
test("changing data in variable-height mode resets the list cache (#238)", () => {
|
|
76
|
+
const ref = createRef();
|
|
77
|
+
const rowHeight = (node) => (node.isInternal ? 40 : 20);
|
|
78
|
+
const { rerender } = render(_jsx(Tree, { data: data, ref: ref, rowHeight: rowHeight, openByDefault: true }));
|
|
79
|
+
const reset = jest.spyOn(ref.current.list.current, "resetAfterIndex");
|
|
80
|
+
const nextData = [{ id: "9", name: "fresh" }, ...data];
|
|
81
|
+
act(() => {
|
|
82
|
+
rerender(_jsx(Tree, { data: nextData, ref: ref, rowHeight: rowHeight, openByDefault: true }));
|
|
83
|
+
});
|
|
84
|
+
expect(reset).toHaveBeenCalledWith(0, false);
|
|
85
|
+
});
|
|
86
|
+
/* The numeric path must stay on FixedSizeList: it has constant item sizes, so
|
|
87
|
+
there is no measurement cache to go stale and none of VariableSizeList's
|
|
88
|
+
overhead. A FixedSizeList has no resetAfterIndex method at all. */
|
|
89
|
+
test("numeric rowHeight renders a cache-free FixedSizeList (#238)", () => {
|
|
90
|
+
const ref = createRef();
|
|
91
|
+
render(_jsx(Tree, { data: data, ref: ref, rowHeight: 24, openByDefault: true }));
|
|
92
|
+
const list = ref.current.list.current;
|
|
93
|
+
expect(list).toBeInstanceOf(FixedSizeList);
|
|
94
|
+
expect("resetAfterIndex" in list).toBe(false);
|
|
95
|
+
});
|
|
96
|
+
/* The function path uses VariableSizeList so per-row heights are possible. */
|
|
97
|
+
test("function rowHeight renders a VariableSizeList (#238)", () => {
|
|
98
|
+
const ref = createRef();
|
|
99
|
+
render(_jsx(Tree, { data: data, ref: ref, rowHeight: () => 24, openByDefault: true }));
|
|
100
|
+
expect(ref.current.list.current).toBeInstanceOf(VariableSizeList);
|
|
101
|
+
});
|
|
@@ -3,5 +3,5 @@ type Props = {
|
|
|
3
3
|
style: React.CSSProperties;
|
|
4
4
|
index: number;
|
|
5
5
|
};
|
|
6
|
-
export declare const RowContainer: React.MemoExoticComponent<(<T>({ index, style
|
|
6
|
+
export declare const RowContainer: React.MemoExoticComponent<(<T>({ index, style }: Props) => import("react/jsx-runtime").JSX.Element)>;
|
|
7
7
|
export {};
|
|
@@ -4,7 +4,7 @@ import { useDataUpdates, useNodesContext, useTreeApi } from "../context";
|
|
|
4
4
|
import { useDragHook } from "../dnd/drag-hook";
|
|
5
5
|
import { useDropHook } from "../dnd/drop-hook";
|
|
6
6
|
import { useFreshNode } from "../hooks/use-fresh-node";
|
|
7
|
-
export const RowContainer = React.memo(function RowContainer({ index, style
|
|
7
|
+
export const RowContainer = React.memo(function RowContainer({ index, style }) {
|
|
8
8
|
/* When will the <Row> will re-render.
|
|
9
9
|
*
|
|
10
10
|
* The row component is memo'd so it will only render
|
|
@@ -35,8 +35,7 @@ export const RowContainer = React.memo(function RowContainer({ index, style, })
|
|
|
35
35
|
const nodeStyle = useMemo(() => ({ paddingLeft: indent }), [indent]);
|
|
36
36
|
const rowStyle = useMemo(() => {
|
|
37
37
|
var _a, _b;
|
|
38
|
-
return (Object.assign(Object.assign({}, style), { top: parseFloat(style.top) +
|
|
39
|
-
((_b = (_a = tree.props.padding) !== null && _a !== void 0 ? _a : tree.props.paddingTop) !== null && _b !== void 0 ? _b : 0) }));
|
|
38
|
+
return (Object.assign(Object.assign({}, style), { top: parseFloat(style.top) + ((_b = (_a = tree.props.padding) !== null && _a !== void 0 ? _a : tree.props.paddingTop) !== null && _b !== void 0 ? _b : 0) }));
|
|
40
39
|
}, [style, tree.props.padding, tree.props.paddingTop]);
|
|
41
40
|
const rowAttrs = {
|
|
42
41
|
role: "treeitem",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { bound, indexOf, isClosed, isItem, isOpenWithEmptyChildren
|
|
1
|
+
import { bound, indexOf, isClosed, isItem, isOpenWithEmptyChildren } from "../utils";
|
|
2
2
|
function measureHover(el, offset) {
|
|
3
3
|
const rect = el.getBoundingClientRect();
|
|
4
4
|
const x = offset.x - Math.round(rect.x);
|
|
@@ -3,8 +3,7 @@ export function useValidatedProps(props) {
|
|
|
3
3
|
if (props.initialData && props.data) {
|
|
4
4
|
throw new Error(`React Arborist Tree => Provide either a data or initialData prop, but not both.`);
|
|
5
5
|
}
|
|
6
|
-
if (props.initialData &&
|
|
7
|
-
(props.onCreate || props.onDelete || props.onMove || props.onRename)) {
|
|
6
|
+
if (props.initialData && (props.onCreate || props.onDelete || props.onMove || props.onRename)) {
|
|
8
7
|
throw new Error(`React Arborist Tree => You passed the initialData prop along with a data handler.
|
|
9
8
|
Use the data prop if you want to provide your own handlers.`);
|
|
10
9
|
}
|
package/dist/module/index.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
export { Tree } from "./components/tree";
|
|
2
|
+
export { DropContainer } from "./components/list-outer-element";
|
|
3
|
+
export { ListOuterElement } from "./components/list-outer-element";
|
|
4
|
+
export { ListInnerElement } from "./components/list-inner-element";
|
|
2
5
|
export * from "./types/handlers";
|
|
3
6
|
export * from "./types/renderers";
|
|
4
7
|
export * from "./types/state";
|
package/dist/module/index.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
/* The Public Api */
|
|
2
2
|
export { Tree } from "./components/tree";
|
|
3
|
+
export { DropContainer } from "./components/list-outer-element";
|
|
4
|
+
export { ListOuterElement } from "./components/list-outer-element";
|
|
5
|
+
export { ListInnerElement } from "./components/list-inner-element";
|
|
3
6
|
export * from "./types/handlers";
|
|
4
7
|
export * from "./types/renderers";
|
|
5
8
|
export * from "./types/state";
|
|
@@ -3,7 +3,10 @@ export class NodeApi {
|
|
|
3
3
|
constructor(params) {
|
|
4
4
|
this.handleClick = (e) => {
|
|
5
5
|
if (e.metaKey && !this.tree.props.disableMultiSelection) {
|
|
6
|
-
|
|
6
|
+
if (this.isSelected)
|
|
7
|
+
this.deselect();
|
|
8
|
+
else
|
|
9
|
+
this.selectMulti();
|
|
7
10
|
}
|
|
8
11
|
else if (e.shiftKey && !this.tree.props.disableMultiSelection) {
|
|
9
12
|
this.selectContiguous();
|
|
@@ -2,7 +2,7 @@ import { EditResult } from "../types/handlers";
|
|
|
2
2
|
import { Identity, IdObj } from "../types/utils";
|
|
3
3
|
import { TreeProps } from "../types/tree-props";
|
|
4
4
|
import { MutableRefObject } from "react";
|
|
5
|
-
import { Align, FixedSizeList, ListOnItemsRenderedProps } from "react-window";
|
|
5
|
+
import { Align, FixedSizeList, ListOnItemsRenderedProps, VariableSizeList } from "react-window";
|
|
6
6
|
import { DefaultRow } from "../components/default-row";
|
|
7
7
|
import { DefaultNode } from "../components/default-node";
|
|
8
8
|
import { NodeApi } from "./node-api";
|
|
@@ -14,7 +14,7 @@ import { Store } from "redux";
|
|
|
14
14
|
export declare class TreeApi<T> {
|
|
15
15
|
store: Store<RootState, Actions>;
|
|
16
16
|
props: TreeProps<T>;
|
|
17
|
-
list: MutableRefObject<FixedSizeList | null>;
|
|
17
|
+
list: MutableRefObject<FixedSizeList | VariableSizeList | null>;
|
|
18
18
|
listEl: MutableRefObject<HTMLDivElement | null>;
|
|
19
19
|
static editPromise: null | ((args: EditResult) => void);
|
|
20
20
|
root: NodeApi<T>;
|
|
@@ -24,7 +24,8 @@ export declare class TreeApi<T> {
|
|
|
24
24
|
idToIndex: {
|
|
25
25
|
[id: string]: number;
|
|
26
26
|
};
|
|
27
|
-
|
|
27
|
+
private rowOffsets;
|
|
28
|
+
constructor(store: Store<RootState, Actions>, props: TreeProps<T>, list: MutableRefObject<FixedSizeList | VariableSizeList | null>, listEl: MutableRefObject<HTMLDivElement | null>);
|
|
28
29
|
update(props: TreeProps<T>): void;
|
|
29
30
|
dispatch(action: Actions): {
|
|
30
31
|
type: "FOCUS";
|
|
@@ -121,7 +122,28 @@ export declare class TreeApi<T> {
|
|
|
121
122
|
get width(): string | number;
|
|
122
123
|
get height(): number;
|
|
123
124
|
get indent(): number;
|
|
125
|
+
/**
|
|
126
|
+
* The fixed row height. When a `rowHeight` function is supplied for variable
|
|
127
|
+
* heights, this returns the default (24); use `rowHeightAt(index)` to get the
|
|
128
|
+
* height of a specific row.
|
|
129
|
+
*/
|
|
124
130
|
get rowHeight(): number;
|
|
131
|
+
/**
|
|
132
|
+
* The height of the row at `index`, evaluating the `rowHeight` function if
|
|
133
|
+
* given. Falls back to the default height for an out-of-range index so this
|
|
134
|
+
* never feeds an invalid `0` to react-window's `itemSize`.
|
|
135
|
+
*/
|
|
136
|
+
rowHeightAt: (index: number) => number;
|
|
137
|
+
/** The pixel offset of the top of the row at `index` from the top of the list. */
|
|
138
|
+
rowTopPosition: (index: number) => number;
|
|
139
|
+
/**
|
|
140
|
+
* Tell the underlying virtualized list to recompute row heights at and after
|
|
141
|
+
* `index`. Call this if a `rowHeight` function's output changes for reasons
|
|
142
|
+
* the tree can't observe (e.g. external state).
|
|
143
|
+
*/
|
|
144
|
+
redrawList: (afterIndex?: number) => void;
|
|
145
|
+
/** Lazily-built prefix sum where offsets[i] is the top of row i. */
|
|
146
|
+
private getRowOffsets;
|
|
125
147
|
get overscanCount(): number;
|
|
126
148
|
get searchTerm(): string;
|
|
127
149
|
get matchFn(): (node: NodeApi<T>) => boolean;
|
|
@@ -185,8 +207,8 @@ export declare class TreeApi<T> {
|
|
|
185
207
|
canDrop(): boolean;
|
|
186
208
|
hideCursor(): void;
|
|
187
209
|
showCursor(cursor: Cursor): void;
|
|
188
|
-
open(identity: Identity): void;
|
|
189
|
-
close(identity: Identity): void;
|
|
210
|
+
open(identity: Identity, redraw?: boolean): void;
|
|
211
|
+
close(identity: Identity, redraw?: boolean): void;
|
|
190
212
|
toggle(identity: Identity): void;
|
|
191
213
|
openParents(identity: Identity): void;
|
|
192
214
|
openSiblings(node: NodeApi<T>): void;
|