diff --git a/src/vscode-tree-item/vscode-tree-item.ts b/src/vscode-tree-item/vscode-tree-item.ts index 9b20439ca..46733ca9b 100644 --- a/src/vscode-tree-item/vscode-tree-item.ts +++ b/src/vscode-tree-item/vscode-tree-item.ts @@ -120,7 +120,6 @@ export class VscodeTreeItem extends VscElement { hasBranchItem: false, rootElement: null, activeItem: null, - highlightedItems: [], }; @consume({context: configContext, subscribe: true}) @@ -335,9 +334,16 @@ export class VscodeTreeItem extends VscElement { if (isShiftDown && this._configContext.multiSelect) { this._selectRange(); this._treeContextState.emitSelectEvent?.(); + + this.updateComplete.then(() => { + this._treeContextState.highlightIndentGuides?.(); + }); } else { this._selectItem(isCtrlDown); this._treeContextState.emitSelectEvent?.(); + this.updateComplete.then(() => { + this._treeContextState.highlightIndentGuides?.(); + }); if (this._configContext.expandMode === ExpandMode.singleClick) { if (this.branch && !(this._configContext.multiSelect && isCtrlDown)) { @@ -351,10 +357,6 @@ export class VscodeTreeItem extends VscElement { if (!isShiftDown) { this._treeContextState.prevFocusedItem = this; } - - this.updateComplete.then(() => { - this._treeContextState.highlightGuides?.(); - }); } private _handleDoubleClick(ev: MouseEvent) { diff --git a/src/vscode-tree/helpers.test.ts b/src/vscode-tree/helpers.test.ts index 9a92873a9..fbc665d92 100644 --- a/src/vscode-tree/helpers.test.ts +++ b/src/vscode-tree/helpers.test.ts @@ -1,5 +1,5 @@ import {expect, fixture, html} from '@open-wc/testing'; -import {findLastChildItem, findPrevItem} from './helpers'; +import {findLastChildItem, findNextItem, findPrevItem} from './helpers'; import {VscodeTreeItem} from '../vscode-tree-item'; import '../vscode-tree-item/vscode-tree-item.js'; import {VscodeTree} from './vscode-tree'; @@ -66,7 +66,7 @@ describe('vscode-tree helpers', () => { expect(findPrevItem(item2)).to.eq(item1); }); - it('returns last children of the opened branch', async () => { + it('returns last child of the opened branch', async () => { const el = await fixture(html` @@ -114,16 +114,133 @@ describe('vscode-tree helpers', () => { 1 1.1 - 1.2 + 1.2 + + 1.3 + 1.3.1 + 1.3.2 + 1.3.3 + 2 `); const item1 = el.querySelector('#item1')!; - const item1_2 = el.querySelector('#item1_2')!; + const item1_3_3 = el.querySelector('#item1_3_3')!; + + expect(findLastChildItem(item1)).to.eq(item1_3_3); + }); + + it('does not traverse the closed branches', async () => { + const el = await fixture(html` + + + 1 + 1.1 + 1.2 + + 1.3 + 1.3.1 + 1.3.2 + 1.3.3 + + + 2 + + `); + + const item1 = el.querySelector('#item1')!; + const item1_3 = el.querySelector('#item1_3')!; + + expect(findLastChildItem(item1)).to.eq(item1_3); + }); + + it('returns the passed item if it is not a tree-item', async () => { + const el = await fixture(html`
`); + + expect(findLastChildItem(el as VscodeTreeItem)).to.eq(el); + }); + + it('returns the passed item if it does not have a child', async () => { + await fixture( + html` + leaf + ` + ); + + const item = document.getElementById('leaf')! as VscodeTreeItem; + + expect(findLastChildItem(item)).to.eq(item); + }); + }); + + describe('findNextItem()', () => { + it('returns null if does not have parent element', () => { + const el = document.createElement('vscode-tree-item'); + + expect(findNextItem(el)).to.be.null; + }); + + it('returns null if it is not a tree item', async () => { + const el = await fixture( + html`
` + ); + + expect(findNextItem(el.querySelector('#item') as VscodeTreeItem)).to.be + .null; + }); + + it('returns last children of the opened branch', async () => { + const el = await fixture(html` + + + 1 + 1.1 + 1.2 + + 2 + + `); + + const item1 = el.querySelector('#item1')!; + const item1_1 = el.querySelector('#item1_1')!; + + expect(findNextItem(item1)).to.eq(item1_1); + }); + + it('returns the next sibling if the opened branch does not contain any item', async () => { + const el = await fixture(html` + + 1 + 2 + + `); + + const item1 = el.querySelector('#item1')!; + const item2 = el.querySelector('#item2')!; + + expect(findNextItem(item1)).to.eq(item2); + }); + + it('returns the next ancestor', async () => { + const el = await fixture(html` + + + 1 + + 1.1 + 1.1.1 + + + 2 + + `); + + const item1_1_1 = el.querySelector('#item1_1_1')!; + const item2 = el.querySelector('#item2')!; - expect(findLastChildItem(item1)).to.eq(item1_2); + expect(findNextItem(item1_1_1)).to.eq(item2); }); }); }); diff --git a/src/vscode-tree/tree-context.ts b/src/vscode-tree/tree-context.ts index e22a5fa63..870434f73 100644 --- a/src/vscode-tree/tree-context.ts +++ b/src/vscode-tree/tree-context.ts @@ -15,8 +15,8 @@ export interface TreeContext { hasBranchItem: boolean; rootElement: VscodeTree | null; activeItem: VscodeTreeItem | null; - highlightedItems: VscodeTreeItem[]; - highlightGuides?: () => void; + highlightedItems?: Set; + highlightIndentGuides?: () => void; emitSelectEvent?: () => void; } diff --git a/src/vscode-tree/vscode-tree.ts b/src/vscode-tree/vscode-tree.ts index a26efb741..733650640 100644 --- a/src/vscode-tree/vscode-tree.ts +++ b/src/vscode-tree/vscode-tree.ts @@ -160,9 +160,9 @@ export class VscodeTree extends VscElement { prevFocusedItem: null, hasBranchItem: false, rootElement: this, - highlightedItems: [], - highlightGuides: () => { - this._highlightGuides(); + highlightedItems: new Set(), + highlightIndentGuides: () => { + this._highlightIndentGuides(); }, emitSelectEvent: () => { this._emitSelectEvent(); @@ -258,43 +258,37 @@ export class VscodeTree extends VscElement { this.dispatchEvent(ev); } - private _highlightGuides() { - const {activeItem, highlightedItems, selectedItems} = - this._treeContextState; + private _highlightIndentGuideOfItem(item: VscodeTreeItem) { + if (item.branch && item.open) { + item.highlightedGuides = true; + this._treeContextState.highlightedItems?.add(item); + } else { + const parent = findParentItem(item); - highlightedItems.forEach((i) => (i.highlightedGuides = false)); + if (parent) { + parent.highlightedGuides = true; + this._treeContextState.highlightedItems?.add(parent); + } + } + } - if (activeItem) { - this._treeContextState.highlightedItems = []; + private _highlightIndentGuides() { + if (this.indentGuides === IndentGuides.none) { + return; + } - if (activeItem.branch && activeItem.open) { - activeItem.highlightedGuides = true; - this._treeContextState.highlightedItems.push(activeItem); - } else { - const parent = findParentItem(activeItem); + this._treeContextState.highlightedItems?.forEach( + (i) => (i.highlightedGuides = false) + ); + this._treeContextState.highlightedItems?.clear(); - if (parent && parent.branch) { - parent.highlightedGuides = true; - this._treeContextState.highlightedItems.push(parent); - } - } + if (this._treeContextState.activeItem) { + this._highlightIndentGuideOfItem(this._treeContextState.activeItem); } - if (selectedItems) { - selectedItems.forEach((item) => { - if (item.branch && item.open) { - item.highlightedGuides = true; - this._treeContextState.highlightedItems.push(item); - } else { - const parent = findParentItem(item); - - if (parent && parent.branch) { - parent.highlightedGuides = true; - this._treeContextState.highlightedItems.push(item); - } - } - }); - } + this._treeContextState.selectedItems.forEach((item) => { + this._highlightIndentGuideOfItem(item); + }); } private _updateConfigContext(changedProperties: PropertyValues) { @@ -326,6 +320,7 @@ export class VscodeTree extends VscElement { item.updateComplete.then(() => { item.focus(); + this._highlightIndentGuides(); }); } @@ -430,6 +425,8 @@ export class VscodeTree extends VscElement { this._treeContextState.selectedItems.forEach( (li) => (li.selected = false) ); + this._treeContextState.selectedItems.clear(); + this._highlightIndentGuides(); focusedItem.selected = true; this._emitSelectEvent(); @@ -496,8 +493,6 @@ export class VscodeTree extends VscElement { firstChild.active = true; } } - - this._highlightGuides(); }); };