react-arborist 1.2.0 → 2.0.0-rc.1
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/README.md +606 -144
- package/dist/components/{drop-cursor.d.ts → cursor.d.ts} +0 -0
- package/dist/components/default-container.d.ts +7 -0
- package/dist/components/default-cursor.d.ts +3 -0
- package/dist/components/default-drag-preview.d.ts +3 -0
- package/dist/components/default-node.d.ts +4 -0
- package/dist/components/default-row.d.ts +4 -0
- package/dist/components/drag-preview-container.d.ts +2 -0
- package/dist/components/list-inner-element.d.ts +2 -0
- package/dist/components/provider.d.ts +11 -0
- package/dist/components/row-container.d.ts +8 -0
- package/dist/components/tree-container.d.ts +2 -0
- package/dist/components/tree.d.ts +5 -4
- package/dist/context.d.ts +20 -2
- package/dist/data/create-index.d.ts +5 -0
- package/dist/data/create-list.d.ts +4 -0
- package/dist/data/create-root.d.ts +5 -0
- package/dist/data/simple-tree.d.ts +43 -0
- package/dist/dnd/compute-drop.d.ts +4 -4
- package/dist/dnd/drag-hook.d.ts +3 -4
- package/dist/dnd/drop-hook.d.ts +2 -3
- package/dist/hooks/use-fresh-node.d.ts +2 -0
- package/dist/hooks/use-simple-tree.d.ts +13 -0
- package/dist/hooks/use-validated-props.d.ts +3 -0
- package/dist/index.d.ts +8 -4
- package/dist/index.js +1948 -973
- package/dist/index.js.map +1 -1
- package/dist/interfaces/node-api.d.ts +67 -0
- package/dist/interfaces/tree-api.d.ts +113 -0
- package/dist/module.js +1935 -979
- package/dist/module.js.map +1 -1
- package/dist/state/dnd-slice.d.ts +20 -0
- package/dist/state/drag-slice.d.ts +7 -0
- package/dist/state/edit-slice.d.ts +8 -0
- package/dist/state/focus-slice.d.ts +12 -0
- package/dist/state/initial.d.ts +3 -0
- package/dist/state/open-slice.d.ts +30 -0
- package/dist/state/root-reducer.d.ts +13 -0
- package/dist/state/selection-slice.d.ts +36 -0
- package/dist/types/dnd.d.ts +9 -0
- package/dist/types/handlers.d.ts +24 -0
- package/dist/types/renderers.d.ts +30 -0
- package/dist/types/state.d.ts +2 -0
- package/dist/types/tree-props.d.ts +44 -0
- package/dist/types/utils.d.ts +21 -0
- package/dist/utils.d.ts +15 -6
- package/package.json +11 -7
- package/src/components/cursor.tsx +15 -0
- package/src/components/default-container.tsx +238 -0
- package/src/components/{default-drop-cursor.tsx → default-cursor.tsx} +9 -8
- package/src/components/{preview.tsx → default-drag-preview.tsx} +25 -41
- package/src/components/default-node.tsx +50 -0
- package/src/components/default-row.tsx +21 -0
- package/src/components/drag-preview-container.tsx +26 -0
- package/src/components/list-inner-element.tsx +22 -0
- package/src/components/list-outer-element.tsx +26 -15
- package/src/components/provider.tsx +97 -0
- package/src/components/row-container.tsx +82 -0
- package/src/components/tree-container.tsx +13 -0
- package/src/components/tree.tsx +16 -44
- package/src/context.ts +36 -0
- package/src/data/create-index.ts +9 -0
- package/src/data/create-list.ts +56 -0
- package/src/data/create-root.ts +54 -0
- package/src/data/simple-tree.ts +103 -0
- package/src/dnd/compute-drop.ts +16 -16
- package/src/dnd/drag-hook.ts +25 -19
- package/src/dnd/drop-hook.ts +31 -17
- package/src/dnd/outer-drop-hook.ts +1 -1
- package/src/hooks/use-fresh-node.ts +16 -0
- package/src/hooks/use-simple-tree.ts +55 -0
- package/src/hooks/use-validated-props.ts +35 -0
- package/src/index.ts +9 -19
- package/src/interfaces/node-api.ts +187 -0
- package/src/interfaces/tree-api.ts +557 -0
- package/src/state/dnd-slice.ts +36 -0
- package/src/state/drag-slice.ts +31 -0
- package/src/state/edit-slice.ts +19 -0
- package/src/state/focus-slice.ts +28 -0
- package/src/state/initial.ts +14 -0
- package/src/state/open-slice.ts +53 -0
- package/src/state/root-reducer.ts +21 -0
- package/src/state/selection-slice.ts +75 -0
- package/src/types/dnd.ts +10 -0
- package/src/types/handlers.ts +24 -0
- package/src/types/renderers.ts +34 -0
- package/src/types/state.ts +3 -0
- package/src/types/tree-props.ts +64 -0
- package/src/types/utils.ts +26 -0
- package/src/utils.ts +125 -11
- package/tsconfig.json +1 -1
- package/dist/components/default-drop-cursor.d.ts +0 -3
- package/dist/components/list.d.ts +0 -4
- package/dist/components/preview.d.ts +0 -2
- package/dist/components/row.d.ts +0 -8
- package/dist/data/enrich-tree.d.ts +0 -2
- package/dist/data/flatten-tree.d.ts +0 -2
- package/dist/provider.d.ts +0 -3
- package/dist/reducer.d.ts +0 -46
- package/dist/selection/range.d.ts +0 -13
- package/dist/selection/selection-hook.d.ts +0 -4
- package/dist/selection/selection.d.ts +0 -33
- package/dist/tree-api.d.ts +0 -50
- package/dist/types.d.ts +0 -122
- package/src/components/drop-cursor.tsx +0 -12
- package/src/components/list.tsx +0 -25
- package/src/components/row.tsx +0 -112
- package/src/context.tsx +0 -13
- package/src/data/enrich-tree.ts +0 -74
- package/src/data/flatten-tree.ts +0 -17
- package/src/provider.tsx +0 -41
- package/src/reducer.ts +0 -161
- package/src/selection/range.ts +0 -41
- package/src/selection/selection-hook.ts +0 -25
- package/src/selection/selection.test.ts +0 -111
- package/src/selection/selection.ts +0 -186
- package/src/tree-api.ts +0 -230
- package/src/types.ts +0 -148
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { ActionTypes } from "../types/utils";
|
|
2
|
+
|
|
3
|
+
/* Types */
|
|
4
|
+
export type OpenMap = { [id: string]: boolean };
|
|
5
|
+
export type OpenSlice = { unfiltered: OpenMap; filtered: OpenMap };
|
|
6
|
+
|
|
7
|
+
/* Actions */
|
|
8
|
+
export const actions = {
|
|
9
|
+
open(id: string, filtered: boolean) {
|
|
10
|
+
return { type: "VISIBILITY_OPEN" as const, id, filtered };
|
|
11
|
+
},
|
|
12
|
+
close(id: string, filtered: boolean) {
|
|
13
|
+
return { type: "VISIBILITY_CLOSE" as const, id, filtered };
|
|
14
|
+
},
|
|
15
|
+
toggle(id: string, filtered: boolean) {
|
|
16
|
+
return { type: "VISIBILITY_TOGGLE" as const, id, filtered };
|
|
17
|
+
},
|
|
18
|
+
clear(filtered: boolean) {
|
|
19
|
+
return { type: "VISIBILITY_CLEAR" as const, filtered };
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/* Reducer */
|
|
24
|
+
|
|
25
|
+
function openMapReducer(
|
|
26
|
+
state: OpenMap = {},
|
|
27
|
+
action: ActionTypes<typeof actions>
|
|
28
|
+
) {
|
|
29
|
+
if (action.type === "VISIBILITY_OPEN") {
|
|
30
|
+
return { ...state, [action.id]: true };
|
|
31
|
+
} else if (action.type === "VISIBILITY_CLOSE") {
|
|
32
|
+
return { ...state, [action.id]: false };
|
|
33
|
+
} else if (action.type === "VISIBILITY_TOGGLE") {
|
|
34
|
+
const prev = state[action.id];
|
|
35
|
+
return { ...state, [action.id]: !prev };
|
|
36
|
+
} else if (action.type === "VISIBILITY_CLEAR") {
|
|
37
|
+
return {};
|
|
38
|
+
} else {
|
|
39
|
+
return state;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function reducer(
|
|
44
|
+
state: OpenSlice = { filtered: {}, unfiltered: {} },
|
|
45
|
+
action: ActionTypes<typeof actions>
|
|
46
|
+
): OpenSlice {
|
|
47
|
+
if (!action.type.startsWith("VISIBILITY")) return state;
|
|
48
|
+
if (action.filtered) {
|
|
49
|
+
return { ...state, filtered: openMapReducer(state.filtered, action) };
|
|
50
|
+
} else {
|
|
51
|
+
return { ...state, unfiltered: openMapReducer(state.unfiltered, action) };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ActionFromReducer, combineReducers } from "redux";
|
|
2
|
+
import { reducer as focus } from "./focus-slice";
|
|
3
|
+
import { reducer as edit } from "./edit-slice";
|
|
4
|
+
import { reducer as dnd } from "./dnd-slice";
|
|
5
|
+
import { reducer as selection } from "./selection-slice";
|
|
6
|
+
import { reducer as open } from "./open-slice";
|
|
7
|
+
import { reducer as drag } from "./drag-slice";
|
|
8
|
+
|
|
9
|
+
export const rootReducer = combineReducers({
|
|
10
|
+
nodes: combineReducers({
|
|
11
|
+
focus,
|
|
12
|
+
edit,
|
|
13
|
+
open,
|
|
14
|
+
selection,
|
|
15
|
+
drag,
|
|
16
|
+
}),
|
|
17
|
+
dnd,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export type RootState = ReturnType<typeof rootReducer>;
|
|
21
|
+
export type Actions = ActionFromReducer<typeof rootReducer>;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { ActionTypes, IdObj } from "../types/utils";
|
|
2
|
+
import { identify } from "../utils";
|
|
3
|
+
import { initialState } from "./initial";
|
|
4
|
+
|
|
5
|
+
/* Types */
|
|
6
|
+
export type SelectionState = {
|
|
7
|
+
ids: Set<string>;
|
|
8
|
+
anchor: string | null;
|
|
9
|
+
mostRecent: string | null;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/* Actions */
|
|
13
|
+
export const actions = {
|
|
14
|
+
clear: () => ({ type: "SELECTION_CLEAR" as const }),
|
|
15
|
+
|
|
16
|
+
only: (id: string | IdObj) => ({
|
|
17
|
+
type: "SELECTION_ONLY" as const,
|
|
18
|
+
id: identify(id),
|
|
19
|
+
}),
|
|
20
|
+
|
|
21
|
+
add: (id: string | string[] | IdObj | IdObj[]) => ({
|
|
22
|
+
type: "SELECTION_ADD" as const,
|
|
23
|
+
ids: (Array.isArray(id) ? id : [id]).map(identify),
|
|
24
|
+
}),
|
|
25
|
+
|
|
26
|
+
remove: (id: string | string[] | IdObj | IdObj[]) => ({
|
|
27
|
+
type: "SELECTION_REMOVE" as const,
|
|
28
|
+
ids: (Array.isArray(id) ? id : [id]).map(identify),
|
|
29
|
+
}),
|
|
30
|
+
|
|
31
|
+
set: (ids: Set<string>) => ({
|
|
32
|
+
type: "SELECTION_SET" as const,
|
|
33
|
+
ids,
|
|
34
|
+
}),
|
|
35
|
+
|
|
36
|
+
mostRecent: (id: string | null | IdObj) => ({
|
|
37
|
+
type: "SELECTION_MOST_RECENT" as const,
|
|
38
|
+
id: id === null ? null : identify(id),
|
|
39
|
+
}),
|
|
40
|
+
|
|
41
|
+
anchor: (id: string | null | IdObj) => ({
|
|
42
|
+
type: "SELECTION_ANCHOR" as const,
|
|
43
|
+
id: id === null ? null : identify(id),
|
|
44
|
+
}),
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/* Reducer */
|
|
48
|
+
export function reducer(
|
|
49
|
+
state: SelectionState = initialState()["nodes"]["selection"],
|
|
50
|
+
action: ActionTypes<typeof actions>
|
|
51
|
+
): SelectionState {
|
|
52
|
+
const ids = state.ids;
|
|
53
|
+
switch (action.type) {
|
|
54
|
+
case "SELECTION_CLEAR":
|
|
55
|
+
return { ...state, ids: new Set() };
|
|
56
|
+
case "SELECTION_ONLY":
|
|
57
|
+
return { ...state, ids: new Set([action.id]) };
|
|
58
|
+
case "SELECTION_ADD":
|
|
59
|
+
if (action.ids.length === 0) return state;
|
|
60
|
+
action.ids.forEach((id) => ids.add(id));
|
|
61
|
+
return { ...state, ids: new Set(ids) };
|
|
62
|
+
case "SELECTION_REMOVE":
|
|
63
|
+
if (action.ids.length === 0) return state;
|
|
64
|
+
action.ids.forEach((id) => ids.delete(id));
|
|
65
|
+
return { ...state, ids: new Set(ids) };
|
|
66
|
+
case "SELECTION_SET":
|
|
67
|
+
return { ...state, ids: new Set(action.ids) };
|
|
68
|
+
case "SELECTION_MOST_RECENT":
|
|
69
|
+
return { ...state, mostRecent: action.id };
|
|
70
|
+
case "SELECTION_ANCHOR":
|
|
71
|
+
return { ...state, anchor: action.id };
|
|
72
|
+
default:
|
|
73
|
+
return state;
|
|
74
|
+
}
|
|
75
|
+
}
|
package/src/types/dnd.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { IdObj } from "./utils";
|
|
2
|
+
|
|
3
|
+
export type CreateHandler = (args: {
|
|
4
|
+
parentId: string | null;
|
|
5
|
+
index: number;
|
|
6
|
+
type: "internal" | "leaf";
|
|
7
|
+
}) => (IdObj | null) | Promise<IdObj | null>;
|
|
8
|
+
|
|
9
|
+
export type MoveHandler = (args: {
|
|
10
|
+
dragIds: string[];
|
|
11
|
+
parentId: string | null;
|
|
12
|
+
index: number;
|
|
13
|
+
}) => void | Promise<void>;
|
|
14
|
+
|
|
15
|
+
export type RenameHandler = (args: {
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
}) => void | Promise<void>;
|
|
19
|
+
|
|
20
|
+
export type DeleteHandler = (args: { ids: string[] }) => void | Promise<void>;
|
|
21
|
+
|
|
22
|
+
export type EditResult =
|
|
23
|
+
| { cancelled: true }
|
|
24
|
+
| { cancelled: false; value: string };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { CSSProperties, HTMLAttributes, ReactElement } from "react";
|
|
2
|
+
import { IdObj } from "./utils";
|
|
3
|
+
import { NodeApi } from "../interfaces/node-api";
|
|
4
|
+
import { TreeApi } from "../interfaces/tree-api";
|
|
5
|
+
import { XYCoord } from "react-dnd";
|
|
6
|
+
|
|
7
|
+
export type NodeRendererProps<T extends IdObj> = {
|
|
8
|
+
style: CSSProperties;
|
|
9
|
+
node: NodeApi<T>;
|
|
10
|
+
tree: TreeApi<T>;
|
|
11
|
+
dragHandle?: (el: HTMLDivElement | null) => void;
|
|
12
|
+
preview?: boolean;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type RowRendererProps<T extends IdObj> = {
|
|
16
|
+
node: NodeApi<T>;
|
|
17
|
+
innerRef: (el: HTMLDivElement | null) => void;
|
|
18
|
+
attrs: HTMLAttributes<any>;
|
|
19
|
+
children: ReactElement;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type DragPreviewProps = {
|
|
23
|
+
offset: XYCoord | null;
|
|
24
|
+
mouse: XYCoord | null;
|
|
25
|
+
id: string | null;
|
|
26
|
+
dragIds: string[];
|
|
27
|
+
isDragging: boolean;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type DropCursorProps = {
|
|
31
|
+
top: number;
|
|
32
|
+
left: number;
|
|
33
|
+
indent: number;
|
|
34
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { BoolFunc, IdObj } from "./utils";
|
|
2
|
+
import * as handlers from "./handlers";
|
|
3
|
+
import * as renderers from "./renderers";
|
|
4
|
+
import { ElementType, MouseEventHandler } from "react";
|
|
5
|
+
import { ListOnScrollProps } from "react-window";
|
|
6
|
+
import { NodeApi } from "../interfaces/node-api";
|
|
7
|
+
import { OpenMap, OpenSlice } from "../state/open-slice";
|
|
8
|
+
|
|
9
|
+
export interface TreeProps<T extends IdObj> {
|
|
10
|
+
/* Data Options */
|
|
11
|
+
data?: T[];
|
|
12
|
+
initialData?: T[];
|
|
13
|
+
|
|
14
|
+
/* Data Handlers */
|
|
15
|
+
onCreate?: handlers.CreateHandler;
|
|
16
|
+
onMove?: handlers.MoveHandler;
|
|
17
|
+
onRename?: handlers.RenameHandler;
|
|
18
|
+
onDelete?: handlers.DeleteHandler;
|
|
19
|
+
|
|
20
|
+
/* Renderers*/
|
|
21
|
+
children?: ElementType<renderers.NodeRendererProps<T>>;
|
|
22
|
+
renderRow?: ElementType<renderers.RowRendererProps<T>>;
|
|
23
|
+
renderDragPreview?: ElementType<renderers.DragPreviewProps>;
|
|
24
|
+
renderCursor?: ElementType<renderers.DropCursorProps>;
|
|
25
|
+
renderContainer?: ElementType<{}>;
|
|
26
|
+
|
|
27
|
+
/* Sizes */
|
|
28
|
+
rowHeight?: number;
|
|
29
|
+
width?: number;
|
|
30
|
+
height?: number;
|
|
31
|
+
indent?: number;
|
|
32
|
+
paddingTop?: number;
|
|
33
|
+
paddingBottom?: number;
|
|
34
|
+
padding?: number;
|
|
35
|
+
|
|
36
|
+
/* Config */
|
|
37
|
+
openByDefault?: boolean;
|
|
38
|
+
selectionFollowsFocus?: boolean;
|
|
39
|
+
disableDrag?: string | boolean | BoolFunc<T>;
|
|
40
|
+
disableDrop?: string | boolean | BoolFunc<T>;
|
|
41
|
+
childrenAccessor?: string | ((d: T) => T[]);
|
|
42
|
+
idAccessor?: string | ((d: T) => string);
|
|
43
|
+
|
|
44
|
+
/* Event Handlers */
|
|
45
|
+
onActivate?: (node: NodeApi<T>) => void;
|
|
46
|
+
onSelect?: (nodes: NodeApi<T>[]) => void;
|
|
47
|
+
onScroll?: (props: ListOnScrollProps) => void;
|
|
48
|
+
|
|
49
|
+
/* Selection */
|
|
50
|
+
selection?: string;
|
|
51
|
+
|
|
52
|
+
/* Open State */
|
|
53
|
+
initialOpenState?: OpenMap;
|
|
54
|
+
|
|
55
|
+
/* Search */
|
|
56
|
+
searchTerm?: string;
|
|
57
|
+
searchMatch?: (node: NodeApi<T>, searchTerm: string) => boolean;
|
|
58
|
+
|
|
59
|
+
/* Extra */
|
|
60
|
+
className?: string | undefined;
|
|
61
|
+
dndRootElement?: globalThis.Node | null;
|
|
62
|
+
onClick?: MouseEventHandler;
|
|
63
|
+
onContextMenu?: MouseEventHandler;
|
|
64
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { AnyAction } from "redux";
|
|
2
|
+
import { NodeApi } from "../interfaces/node-api";
|
|
3
|
+
|
|
4
|
+
export interface IdObj {
|
|
5
|
+
id: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type Identity = string | IdObj | null;
|
|
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
|
+
export type BoolFunc<T> = (data: T) => boolean;
|
|
19
|
+
|
|
20
|
+
export type ActionTypes<
|
|
21
|
+
Actions extends { [name: string]: (...args: any[]) => AnyAction }
|
|
22
|
+
> = ReturnType<Actions[keyof Actions]>;
|
|
23
|
+
|
|
24
|
+
export type SelectOptions = { multi?: boolean; contiguous?: boolean };
|
|
25
|
+
|
|
26
|
+
export type NodesById<T extends IdObj> = { [id: string]: NodeApi<T> };
|
package/src/utils.ts
CHANGED
|
@@ -1,24 +1,23 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { NodeApi } from "./interfaces/node-api";
|
|
2
|
+
import { IdObj } from "./types/utils";
|
|
2
3
|
|
|
3
4
|
export function bound(n: number, min: number, max: number) {
|
|
4
5
|
return Math.max(Math.min(n, max), min);
|
|
5
6
|
}
|
|
6
7
|
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
export function isItem(node: Node | null) {
|
|
10
|
-
return node && !isFolder(node);
|
|
8
|
+
export function isItem(node: NodeApi<any> | null) {
|
|
9
|
+
return node && node.isLeaf;
|
|
11
10
|
}
|
|
12
11
|
|
|
13
|
-
export function isClosed(node:
|
|
14
|
-
return node &&
|
|
12
|
+
export function isClosed(node: NodeApi<any> | null) {
|
|
13
|
+
return node && node.isInternal && !node.isOpen;
|
|
15
14
|
}
|
|
16
15
|
|
|
17
16
|
/**
|
|
18
17
|
* Is first param a decendent of the second param
|
|
19
18
|
*/
|
|
20
|
-
export const isDecendent = (a:
|
|
21
|
-
let n:
|
|
19
|
+
export const isDecendent = (a: NodeApi<any>, b: NodeApi<any>) => {
|
|
20
|
+
let n: NodeApi<any> | null = a;
|
|
22
21
|
while (n) {
|
|
23
22
|
if (n.id === b.id) return true;
|
|
24
23
|
n = n.parent;
|
|
@@ -26,10 +25,125 @@ export const isDecendent = (a: Node, b: Node) => {
|
|
|
26
25
|
return false;
|
|
27
26
|
};
|
|
28
27
|
|
|
29
|
-
export const indexOf = (node:
|
|
30
|
-
// This should probably not throw an error, but instead return null
|
|
28
|
+
export const indexOf = (node: NodeApi<any>) => {
|
|
31
29
|
if (!node.parent) throw Error("Node does not have a parent");
|
|
32
30
|
return node.parent.children!.findIndex((c) => c.id === node.id);
|
|
33
31
|
};
|
|
34
32
|
|
|
35
33
|
export function noop() {}
|
|
34
|
+
|
|
35
|
+
export function dfs(node: NodeApi<any>, id: string): NodeApi<any> | null {
|
|
36
|
+
if (!node) return null;
|
|
37
|
+
if (node.id === id) return node;
|
|
38
|
+
if (node.children) {
|
|
39
|
+
for (let child of node.children) {
|
|
40
|
+
const result = dfs(child, id);
|
|
41
|
+
if (result) return result;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function focusNextElement(target: HTMLElement) {
|
|
48
|
+
const elements = getFocusable(target);
|
|
49
|
+
|
|
50
|
+
let next: HTMLElement;
|
|
51
|
+
for (let i = 0; i < elements.length; ++i) {
|
|
52
|
+
const item = elements[i];
|
|
53
|
+
if (item === target) {
|
|
54
|
+
next = nextItem(elements, i);
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// @ts-ignore ??
|
|
60
|
+
next?.focus();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function focusPrevElement(target: HTMLElement) {
|
|
64
|
+
const elements = getFocusable(target);
|
|
65
|
+
let next: HTMLElement;
|
|
66
|
+
for (let i = 0; i < elements.length; ++i) {
|
|
67
|
+
const item = elements[i];
|
|
68
|
+
if (item === target) {
|
|
69
|
+
next = prevItem(elements, i);
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// @ts-ignore
|
|
74
|
+
next?.focus();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function nextItem(list: HTMLElement[], index: number) {
|
|
78
|
+
if (index + 1 < list.length) {
|
|
79
|
+
return list[index + 1] as HTMLElement;
|
|
80
|
+
} else {
|
|
81
|
+
return list[0] as HTMLElement;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function prevItem(list: HTMLElement[], index: number) {
|
|
86
|
+
if (index - 1 >= 0) {
|
|
87
|
+
return list[index - 1];
|
|
88
|
+
} else {
|
|
89
|
+
return list[list.length - 1];
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function getFocusable(target: HTMLElement) {
|
|
94
|
+
return Array.from(
|
|
95
|
+
document.querySelectorAll(
|
|
96
|
+
'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"]):not([disabled]), details:not([disabled]), summary:not(:disabled)'
|
|
97
|
+
)
|
|
98
|
+
).filter((e) => e === target || !target.contains(e)) as HTMLElement[];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function access<T = boolean>(
|
|
102
|
+
obj: any,
|
|
103
|
+
accessor: string | boolean | Function
|
|
104
|
+
): T {
|
|
105
|
+
if (typeof accessor === "boolean") return accessor as unknown as T;
|
|
106
|
+
if (typeof accessor === "string") return obj[accessor] as T;
|
|
107
|
+
return accessor(obj) as T;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function identifyNull(obj: string | IdObj | null) {
|
|
111
|
+
if (obj === null) return null;
|
|
112
|
+
else return identify(obj);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function identify(obj: string | IdObj) {
|
|
116
|
+
return typeof obj === "string" ? obj : obj.id;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function mergeRefs(...refs: any) {
|
|
120
|
+
return (instance: any) => {
|
|
121
|
+
refs.forEach((ref: any) => {
|
|
122
|
+
if (typeof ref === "function") {
|
|
123
|
+
ref(instance);
|
|
124
|
+
} else if (ref != null) {
|
|
125
|
+
ref.current = instance;
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function safeRun<T extends (...args: any[]) => any>(
|
|
132
|
+
fn: T | undefined,
|
|
133
|
+
...args: Parameters<T>
|
|
134
|
+
) {
|
|
135
|
+
if (fn) return fn(...args);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function waitFor(fn: () => boolean) {
|
|
139
|
+
return new Promise<void>((resolve, reject) => {
|
|
140
|
+
let tries = 0;
|
|
141
|
+
function check() {
|
|
142
|
+
tries += 1;
|
|
143
|
+
if (tries === 100) reject();
|
|
144
|
+
if (fn()) resolve();
|
|
145
|
+
else setTimeout(check, 10);
|
|
146
|
+
}
|
|
147
|
+
check();
|
|
148
|
+
});
|
|
149
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
/* Language and Environment */
|
|
7
7
|
"target": "ES5", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
|
8
|
-
"jsx": "
|
|
8
|
+
"jsx": "react-jsx", /* Specify what JSX code is generated. */
|
|
9
9
|
|
|
10
10
|
/* Modules */
|
|
11
11
|
"module": "CommonJS", /* Specify what module code is generated. */
|
package/dist/components/row.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { IdObj } from "../types";
|
|
3
|
-
declare type Props = {
|
|
4
|
-
style: React.CSSProperties;
|
|
5
|
-
index: number;
|
|
6
|
-
};
|
|
7
|
-
export declare const Row: React.MemoExoticComponent<(<T extends IdObj>({ index, style, }: Props) => JSX.Element)>;
|
|
8
|
-
export {};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import { TreeProps, IdObj, Node } from "../types";
|
|
2
|
-
export declare function enrichTree<T extends IdObj>(model: T, hideRoot?: boolean, getChildren?: TreeProps<T>["getChildren"], isOpen?: TreeProps<T>["isOpen"], disableDrag?: TreeProps<T>["disableDrag"], disableDrop?: TreeProps<T>["disableDrop"], openByDefault?: boolean): Node<T>;
|
package/dist/provider.d.ts
DELETED
package/dist/reducer.d.ts
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { Cursor } from "./dnd/compute-drop";
|
|
2
|
-
import { StateContext } from "./types";
|
|
3
|
-
export declare const initState: () => StateContext;
|
|
4
|
-
export declare const actions: {
|
|
5
|
-
setCursorLocation: (cursor: Cursor) => {
|
|
6
|
-
type: "SET_CURSOR_LOCATION";
|
|
7
|
-
cursor: Cursor;
|
|
8
|
-
};
|
|
9
|
-
setVisibleIds: (ids: string[], idMap: {
|
|
10
|
-
[id: string]: number;
|
|
11
|
-
}) => {
|
|
12
|
-
type: "SET_VISIBLE_IDS";
|
|
13
|
-
ids: string[];
|
|
14
|
-
idMap: {
|
|
15
|
-
[id: string]: number;
|
|
16
|
-
};
|
|
17
|
-
};
|
|
18
|
-
select: (index: number | null, meta: boolean, shift: boolean) => {
|
|
19
|
-
type: "SELECT";
|
|
20
|
-
index: number | null;
|
|
21
|
-
meta: boolean;
|
|
22
|
-
shift: boolean;
|
|
23
|
-
};
|
|
24
|
-
selectId: (id: string) => {
|
|
25
|
-
type: "SELECT_ID";
|
|
26
|
-
id: string;
|
|
27
|
-
};
|
|
28
|
-
edit: (id: string | null) => {
|
|
29
|
-
type: "EDIT";
|
|
30
|
-
id: string | null;
|
|
31
|
-
};
|
|
32
|
-
stepUp: (shift: boolean, ids: string[]) => {
|
|
33
|
-
type: "STEP_UP";
|
|
34
|
-
shift: boolean;
|
|
35
|
-
};
|
|
36
|
-
stepDown: (shift: boolean, ids: string[]) => {
|
|
37
|
-
type: "STEP_DOWN";
|
|
38
|
-
shift: boolean;
|
|
39
|
-
};
|
|
40
|
-
};
|
|
41
|
-
declare type ActionObj = {
|
|
42
|
-
[Prop in keyof typeof actions]: ReturnType<typeof actions[Prop]>;
|
|
43
|
-
};
|
|
44
|
-
export declare type Action = ActionObj[keyof ActionObj];
|
|
45
|
-
export declare function reducer(state: StateContext, action: Action): StateContext;
|
|
46
|
-
export {};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export declare class Range {
|
|
2
|
-
start: number;
|
|
3
|
-
end: number;
|
|
4
|
-
constructor(start: number, end: number);
|
|
5
|
-
serialize(): [number, number];
|
|
6
|
-
contains(n: number): boolean;
|
|
7
|
-
overlaps(r: Range): boolean;
|
|
8
|
-
combine(r: Range): void;
|
|
9
|
-
get size(): number;
|
|
10
|
-
clone(): Range;
|
|
11
|
-
map(fn: (index: any) => string): any;
|
|
12
|
-
isEqual(other: Range): boolean;
|
|
13
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { Range } from "./range";
|
|
2
|
-
declare type SelectionDirection = "forward" | "backward" | "none";
|
|
3
|
-
export declare type SelectionData = {
|
|
4
|
-
ranges: [number, number][];
|
|
5
|
-
currentIndex: number | null;
|
|
6
|
-
direction: SelectionDirection;
|
|
7
|
-
};
|
|
8
|
-
export declare class Selection {
|
|
9
|
-
ranges: Range[];
|
|
10
|
-
currentIndex: number | null;
|
|
11
|
-
direction: SelectionDirection;
|
|
12
|
-
items: any[];
|
|
13
|
-
static parse(data: SelectionData | null, items: any[]): Selection;
|
|
14
|
-
constructor(ranges?: [number, number][], currentIndex?: number | null, direction?: SelectionDirection, items?: any[]);
|
|
15
|
-
get current(): Range | null;
|
|
16
|
-
select(n: number): void;
|
|
17
|
-
multiSelect(n: number): void;
|
|
18
|
-
deselect(n: number): void;
|
|
19
|
-
getSelectedItems<T>(): T[];
|
|
20
|
-
extend(n: number): void;
|
|
21
|
-
contains(n: number | null): boolean;
|
|
22
|
-
getRanges(): [number, number][];
|
|
23
|
-
clear(): void;
|
|
24
|
-
serialize(): SelectionData;
|
|
25
|
-
isEqual(other: Selection): boolean;
|
|
26
|
-
private addRange;
|
|
27
|
-
private removeRange;
|
|
28
|
-
private isEmpty;
|
|
29
|
-
getAnchor(): number | null;
|
|
30
|
-
getFocus(): number;
|
|
31
|
-
private compact;
|
|
32
|
-
}
|
|
33
|
-
export {};
|
package/dist/tree-api.d.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { Dispatch, MutableRefObject } from "react";
|
|
2
|
-
import { FixedSizeList } from "react-window";
|
|
3
|
-
import { Cursor } from "./dnd/compute-drop";
|
|
4
|
-
import { Action } from "./reducer";
|
|
5
|
-
import { Node, StateContext, TreeProviderProps, EditResult, IdObj, DropCursorProps } from "./types";
|
|
6
|
-
export declare class TreeApi<T extends IdObj> {
|
|
7
|
-
dispatch: Dispatch<Action>;
|
|
8
|
-
state: StateContext;
|
|
9
|
-
props: TreeProviderProps<T>;
|
|
10
|
-
list: MutableRefObject<FixedSizeList | null>;
|
|
11
|
-
listEl: MutableRefObject<HTMLDivElement | null>;
|
|
12
|
-
private edits;
|
|
13
|
-
constructor(dispatch: Dispatch<Action>, state: StateContext, props: TreeProviderProps<T>, list: MutableRefObject<FixedSizeList | null>, listEl: MutableRefObject<HTMLDivElement | null>);
|
|
14
|
-
sync(other: TreeApi<T>): void;
|
|
15
|
-
getNode(id: string): Node<T> | null;
|
|
16
|
-
getSelectedIds(): string[];
|
|
17
|
-
edit(id: string | number): Promise<EditResult>;
|
|
18
|
-
submit(id: string | number, value: string): void;
|
|
19
|
-
reset(id: string | number): void;
|
|
20
|
-
private resolveEdit;
|
|
21
|
-
select(index: number | null, meta?: boolean, shift?: boolean): void;
|
|
22
|
-
selectById(id: string | number, meta?: boolean, shift?: boolean): void;
|
|
23
|
-
selectUpwards(shiftKey: boolean): void;
|
|
24
|
-
selectDownwards(shiftKey: boolean): void;
|
|
25
|
-
hideCursor(): void;
|
|
26
|
-
showCursor(cursor: Cursor): void;
|
|
27
|
-
scrollToId(id: string): void;
|
|
28
|
-
open(id: string): void;
|
|
29
|
-
openParents(id: string): void;
|
|
30
|
-
get visibleIds(): string[];
|
|
31
|
-
get idToIndex(): {
|
|
32
|
-
[id: string]: number;
|
|
33
|
-
};
|
|
34
|
-
get visibleNodes(): Node<T>[];
|
|
35
|
-
get width(): number;
|
|
36
|
-
get height(): number;
|
|
37
|
-
get indent(): number;
|
|
38
|
-
get renderer(): import("./types").NodeRenderer<T>;
|
|
39
|
-
get onToggle(): import("./types").ToggleHandler;
|
|
40
|
-
get rowHeight(): number;
|
|
41
|
-
get onClick(): import("react").MouseEventHandler<Element>;
|
|
42
|
-
get onContextMenu(): import("react").MouseEventHandler<Element>;
|
|
43
|
-
get onMove(): import("./types").MoveHandler;
|
|
44
|
-
get onEdit(): import("./types").EditHandler;
|
|
45
|
-
get cursorParentId(): string | null;
|
|
46
|
-
get cursorOverFolder(): boolean;
|
|
47
|
-
get editingId(): string | null;
|
|
48
|
-
isSelected(index: number | null): boolean;
|
|
49
|
-
renderDropCursor(props: DropCursorProps): JSX.Element;
|
|
50
|
-
}
|