diff --git a/frontend/layout/lib/layoutModel.ts b/frontend/layout/lib/layoutModel.ts index d491e6a6..00b0de6d 100644 --- a/frontend/layout/lib/layoutModel.ts +++ b/frontend/layout/lib/layoutModel.ts @@ -101,7 +101,7 @@ export class LayoutModel { /** * An ordered list of node ids starting from the top left corner to the bottom right corner. */ - leafOrder: Atom; + leafOrder: PrimitiveAtom; /** * A map of node models for currently-active leafs. */ @@ -210,18 +210,7 @@ export class LayoutModel { this.resizeHandleSizePx = 2 * this.halfResizeHandleSizePx; this.leafs = atom([]); - this.leafOrder = atom((get) => { - const leafs = get(this.leafs); - const additionalProps = get(this.additionalProps); - return leafs - .map((node) => node.id) - .sort((a, b) => { - const treeKeyA = additionalProps[a]?.treeKey; - const treeKeyB = additionalProps[b]?.treeKey; - if (!treeKeyA || !treeKeyB) return; - return treeKeyA.localeCompare(treeKeyB); - }); - }); + this.leafOrder = atom([]); this.nodeModels = new Map(); this.additionalProps = atom({}); @@ -406,7 +395,9 @@ export class LayoutModel { this.leafs, newLeafs.sort((a, b) => a.id.localeCompare(b.id)) ); - this.validateFocusedNode(newLeafs); + const newLeafOrder = getLeafOrder(newLeafs, newAdditionalProps); + this.setter(this.leafOrder, newLeafOrder); + this.validateFocusedNode(newLeafOrder); this.cleanupNodeModels(); } }; @@ -523,24 +514,27 @@ export class LayoutModel { /** * Checks whether the focused node id has changed and, if so, whether to update the focused node stack. If the focused node was deleted, will pop the latest value from the stack. - * @param newLeafs The new leafs array to use when searching for stale nodes in the stack. + * @param leafOrder The new leaf order array to use when searching for stale nodes in the stack. */ - private validateFocusedNode(newLeafs: LayoutNode[]) { + private validateFocusedNode(leafOrder: string[]) { if (this.treeState.focusedNodeId !== this.focusedNodeId) { // Remove duplicates and stale entries from focus stack. - const leafIds = newLeafs.map((leaf) => leaf.id); const newFocusedNodeIdStack: string[] = []; for (const id of this.focusedNodeIdStack) { - if (leafIds.includes(id) && !newFocusedNodeIdStack.includes(id)) newFocusedNodeIdStack.push(id); + if (leafOrder.includes(id) && !newFocusedNodeIdStack.includes(id)) newFocusedNodeIdStack.push(id); } this.focusedNodeIdStack = newFocusedNodeIdStack; // Update the focused node and stack based on the changes in the tree state. - if (this.treeState.focusedNodeId) { - this.focusedNodeIdStack.unshift(this.treeState.focusedNodeId); - } else { - this.treeState.focusedNodeId = this.focusedNodeIdStack.shift(); + if (!this.treeState.focusedNodeId) { + if (this.focusedNodeIdStack.length > 0) { + this.treeState.focusedNodeId = this.focusedNodeIdStack.shift(); + } else { + this.treeState.focusedNodeId = leafOrder[0]; + console.log("next insert loc", this.treeState.focusedNodeId); + } } + this.focusedNodeIdStack.unshift(this.treeState.focusedNodeId); } } @@ -992,3 +986,14 @@ export class LayoutModel { return this.getNodeRectById(node.id); } } + +function getLeafOrder(leafs: LayoutNode[], additionalProps: Record): string[] { + return leafs + .map((node) => node.id) + .sort((a, b) => { + const treeKeyA = additionalProps[a]?.treeKey; + const treeKeyB = additionalProps[b]?.treeKey; + if (!treeKeyA || !treeKeyB) return; + return treeKeyA.localeCompare(treeKeyB); + }); +} diff --git a/frontend/layout/lib/layoutNode.ts b/frontend/layout/lib/layoutNode.ts index a616475f..319edcf0 100644 --- a/frontend/layout/lib/layoutNode.ts +++ b/frontend/layout/lib/layoutNode.ts @@ -1,6 +1,7 @@ // Copyright 2024, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 +import { DEFAULT_MAX_CHILDREN } from "./layoutTree"; import { DefaultNodeSize, FlexDirection, LayoutNode } from "./types"; import { reverseFlexDirection } from "./utils"; @@ -222,7 +223,10 @@ export function balanceNode( * @param maxChildren The maximum number of children a node can have. * @returns The node to insert into and the index at which to insert. */ -export function findNextInsertLocation(node: LayoutNode, maxChildren: number): { node: LayoutNode; index: number } { +export function findNextInsertLocation( + node: LayoutNode, + maxChildren = DEFAULT_MAX_CHILDREN +): { node: LayoutNode; index: number } { const insertLoc = findNextInsertLocationHelper(node, maxChildren, 1); return { node: insertLoc?.node, index: insertLoc?.index }; } diff --git a/frontend/layout/lib/layoutTree.ts b/frontend/layout/lib/layoutTree.ts index 0a69c32f..dccab4cc 100644 --- a/frontend/layout/lib/layoutTree.ts +++ b/frontend/layout/lib/layoutTree.ts @@ -29,6 +29,8 @@ import { MoveOperation, } from "./types"; +export const DEFAULT_MAX_CHILDREN = 5; + /** * Computes an operation for inserting a new node into the tree in the given direction relative to the specified node. * @@ -262,7 +264,7 @@ export function insertNode(layoutState: LayoutTreeState, action: LayoutTreeInser if (!layoutState.rootNode) { layoutState.rootNode = action.node; } else { - const insertLoc = findNextInsertLocation(layoutState.rootNode, 5); + const insertLoc = findNextInsertLocation(layoutState.rootNode, DEFAULT_MAX_CHILDREN); addChildAt(insertLoc.node, insertLoc.index, action.node); if (action.magnified) { layoutState.magnifiedNodeId = action.node.id;