Skip to content

Commit

Permalink
Added create leaf and create internal
Browse files Browse the repository at this point in the history
  • Loading branch information
jameskerr committed Apr 3, 2024
1 parent 613039c commit 2b485dd
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 12 deletions.
40 changes: 35 additions & 5 deletions modules/react-arborist/src/commands/default-commands.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { NodeController } from "../controllers/node-controller";
import { TreeController } from "../controllers/tree-controller";
import { NodeObject } from "../nodes/node-object";
import { NodeType } from "../nodes/source-data-accessor";
import { focusNextElement, focusPrevElement } from "../utils";

export type Tree = TreeController<any>;
Expand Down Expand Up @@ -73,12 +76,39 @@ export function focusOutsidePrev(tree: Tree) {
export function destroy(tree: Tree) {
if (confirm("Are you sure you want to delete?")) {
if (tree.selectedIds.length) {
tree.props.nodes.onChange({ type: "destroy", ids: tree.selectedIds });
tree.destroy(tree.selectedIds);
} else if (tree.focusedNode) {
tree.props.nodes.onChange({
type: "destroy",
ids: [tree.focusedNode.id],
});
tree.destroy([tree.focusedNode.id]);
}
}
}

function create(tree: Tree, nodeType: NodeType) {
const node = tree.focusedNode;
const parentId = getInsertParentId(node);
const index = getInsertIndex(tree, node);
const data = tree.props.nodes.initialize({ nodeType });
tree.create({ parentId, index, data });
tree.edit(data.id);
tree.focus(data.id);
}

export function createLeaf(tree: Tree) {
create(tree, "leaf");
}

export function createInternal(tree: Tree) {
create(tree, "internal");
}

function getInsertParentId(focus: NodeController<any> | null) {
if (!focus) return null;
if (focus.isOpen) return focus.id;
return focus.parentId;
}

function getInsertIndex(tree: Tree, focus: NodeController<any> | null) {
if (!focus) return tree.props.nodes.value.length;
if (focus.isOpen) return 0;
return focus.childIndex + 1;
}
2 changes: 1 addition & 1 deletion modules/react-arborist/src/components/tree-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,6 @@ function NodeRenderer<T>(props: {
node: NodeController<T>;
}) {
const { node, attrs } = props;
const style = { attrs };

function onSubmit(e: any) {
e.preventDefault();
Expand Down Expand Up @@ -208,6 +207,7 @@ function NodeRenderer<T>(props: {
{node.isEditing ? (
<form onSubmit={onSubmit} style={{ display: "contents" }}>
<input
autoFocus
type="text"
name="name"
defaultValue={
Expand Down
22 changes: 21 additions & 1 deletion modules/react-arborist/src/controllers/tree-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,26 @@ export class TreeController<T> {
});
}

/* CRUD Operations */

create(args: { parentId: string | null; index: number; data: T }) {
this.props.nodes.onChange({ type: "create", ...args });
}

update(args: { id: string; changes: Partial<T> }) {
this.props.nodes.onChange({ type: "update", ...args });
}

destroy(ids: string[]) {
this.props.nodes.onChange({ type: "destroy", ids: ids });
}

/* Edit State */

get isEditing() {
return this.props.edit.value !== null;
}

isEditId(id: string) {
return this.props.edit.value === id;
}
Expand All @@ -194,8 +212,9 @@ export class TreeController<T> {
}

submit(id: string, changes: Partial<T>) {
this.props.nodes.onChange({ type: "update", id, changes });
this.update({ id, changes });
this.props.edit.onChange({ value: null });
this.focus(id);
}

/* Selection State */
Expand Down Expand Up @@ -365,6 +384,7 @@ export class TreeController<T> {

/* Keyboard Shortcuts */
handleKeyDown(e: React.KeyboardEvent<HTMLDivElement>) {
if (this.isEditing) return;
const focused = this.focusedNode;
const shortcut = new ShortcutManager<any>(this.props.shortcuts).find(
e.nativeEvent,
Expand Down
8 changes: 8 additions & 0 deletions modules/react-arborist/src/nodes/default-accessors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ export function createDefaultAccessors<T>(): SourceDataAccessors<T> {
return true;
}
},
initialize: ({ nodeType }) => {
const data = {
id: new Date().getTime().toString(),
name: "",
} as any;
if (nodeType === "internal") data.children = [];
return data;
},
sortBy: [],
sortOrder: [],
};
Expand Down
8 changes: 8 additions & 0 deletions modules/react-arborist/src/nodes/source-data-accessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@ import { createDefaultAccessors } from "./default-accessors";

type GetSortField<T> = (d: T) => number | string | boolean;
type SortOrder = "asc" | "desc";
type Initializer<T> = (args: { nodeType: NodeType }) => T;

export type NodeType = "leaf" | "internal";

export type SourceDataAccessors<T> = {
id: (d: T) => string;
children: (d: T) => T[] | null;
isLeaf: (d: T) => boolean;
initialize: Initializer<T>;
sortBy: GetSortField<T> | GetSortField<T>[];
sortOrder: SortOrder | SortOrder[];
};
Expand All @@ -19,6 +23,10 @@ export class SourceDataAccessor<T> {
this.access = { ...createDefaultAccessors(), ...accessors };
}

initialize(args: { nodeType: NodeType }) {
return this.access.initialize(args);
}

getId(d: T): string {
return this.access.id(d);
}
Expand Down
5 changes: 5 additions & 0 deletions modules/react-arborist/src/nodes/tree-manager.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
NodeType,
SourceDataAccessor,
SourceDataAccessors,
} from "./source-data-accessor";
Expand All @@ -18,6 +19,10 @@ export class TreeManager<T> {
});
}

initialize(args: { nodeType: NodeType }): T {
return this.accessor.initialize(args);
}

create(args: { parentId: string | null; index: number; data: T }) {
const { parentId, index, data } = args;
if (!parentId) {
Expand Down
3 changes: 2 additions & 1 deletion modules/react-arborist/src/nodes/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { PartialController } from "../types/utils";
import { NodeObject } from "./node-object";
import { NodeType } from "./source-data-accessor";

export type CreateEvent<T> = {
type: "create";
Expand Down Expand Up @@ -36,4 +37,4 @@ export type NodesState<T> = NodeObject<T>[];
export type NodesPartialController<T> = PartialController<
NodesState<T>,
NodesOnChangeEvent<T>
>;
> & { initialize: (args: { nodeType: NodeType }) => T };
2 changes: 1 addition & 1 deletion modules/react-arborist/src/nodes/use-nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export function useNodes<T>(

return {
setSourceData,
initialize: (args) => treeManager.initialize(args),
value: treeManager.nodes as NodeObject<T>[],
onChange: (event: NodesOnChangeEvent<T>) => {
switch (event.type) {
Expand All @@ -23,7 +24,6 @@ export function useNodes<T>(
treeManager.move(event);
break;
case "update":
console.log(event);
treeManager.update(event);
break;
case "destroy":
Expand Down
9 changes: 6 additions & 3 deletions modules/react-arborist/src/shortcuts/default-shortcuts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@ export const defaultShortcuts: ShortcutAttrs[] = [
{ key: "Tab", command: "focusOutsideNext" },
{ key: "Shift+Tab", command: "focusOutsidePrev" },

/* CRUD */
{ key: "Backspace", command: "destroy" },
// { key: "Tab", command: "focusNextOutside" },
// { key: "Shift+Tab", command: "focusNextOutside" },
// { key: "Shift+Tab", command: "focusNextOutside" },
{ key: "a", command: "createLeaf" },
{ key: "Shift+A", command: "createInternal" },

/* Selection */

// { key: "Meta+ArrowDown", command: "activate" },
// { key: "Shift+ArrowDown", command: "extendSelectionDown" },
// { key: "Shift+ArrowUp", command: "extendSelectionUp" },
Expand Down

0 comments on commit 2b485dd

Please sign in to comment.