Skip to content

Commit 9cb3292

Browse files
committed
Fix range selection
1 parent ee34499 commit 9cb3292

5 files changed

Lines changed: 104 additions & 24 deletions

File tree

dev/vscode-list.html

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,36 @@ <h2 class="story-title">Basic example</h2>
7777
</vscode-list-item>
7878
</vscode-list-item>
7979
</vscode-list-item>
80+
<vscode-list-item>
81+
<vscode-icon name="folder" slot="icon-branch"></vscode-icon>
82+
<vscode-icon name="folder-opened" slot="icon-branch-opened"></vscode-icon>
83+
<vscode-icon name="file" slot="icon-leaf"></vscode-icon>
84+
dolor
85+
<vscode-list-item>
86+
<vscode-icon name="folder" slot="icon-branch"></vscode-icon>
87+
<vscode-icon name="folder-opened" slot="icon-branch-opened"></vscode-icon>
88+
<vscode-icon name="file" slot="icon-leaf"></vscode-icon>
89+
lorem
90+
</vscode-list-item>
91+
<vscode-list-item>
92+
<vscode-icon name="folder" slot="icon-branch"></vscode-icon>
93+
<vscode-icon name="folder-opened" slot="icon-branch-opened"></vscode-icon>
94+
<vscode-icon name="file" slot="icon-leaf"></vscode-icon>
95+
ipsum
96+
<vscode-list-item>
97+
<vscode-icon name="folder" slot="icon-branch"></vscode-icon>
98+
<vscode-icon name="folder-opened" slot="icon-branch-opened"></vscode-icon>
99+
<vscode-icon name="file" slot="icon-leaf"></vscode-icon>
100+
lorem
101+
</vscode-list-item>
102+
<vscode-list-item>
103+
<vscode-icon name="folder" slot="icon-branch"></vscode-icon>
104+
<vscode-icon name="folder-opened" slot="icon-branch-opened"></vscode-icon>
105+
<vscode-icon name="file" slot="icon-leaf"></vscode-icon>
106+
lorem
107+
</vscode-list-item>
108+
</vscode-list-item>
109+
</vscode-list-item>
80110
<vscode-list-item>
81111
<vscode-icon name="folder" slot="icon-branch"></vscode-icon>
82112
<vscode-icon name="folder-opened" slot="icon-branch-opened"></vscode-icon>
@@ -91,6 +121,7 @@ <h2 class="story-title">Basic example</h2>
91121
dolor
92122
</vscode-list-item>
93123
</vscode-list>
124+
<input type="text">
94125
</component-preview>
95126
</div>
96127
</div>

src/vscode-list-item/vscode-list-item.ts

Lines changed: 59 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ export class VscodeListItem extends VscElement {
6464
indent: 8,
6565
multiSelect: false,
6666
selectedItems: new Set(),
67+
allItems: null,
68+
itemListUpToDate: false,
6769
focusedItem: null,
6870
prevFocusedItem: null,
6971
focusItem: () => {
@@ -116,28 +118,59 @@ export class VscodeListItem extends VscElement {
116118
return;
117119
}
118120

119-
const prevFocusedLevel = +(prevFocused.dataset.level ?? '');
120-
const focusedLevel = +(this.dataset.level ?? '');
121+
if (!this._listContextState.itemListUpToDate) {
122+
this._listContextState.allItems =
123+
this._listContextState.rootElement!.querySelectorAll(
124+
'vscode-list-item'
125+
);
121126

122-
let closestAncestor: VscodeListItem | null;
127+
if (this._listContextState.allItems) {
128+
this._listContextState.allItems.forEach((li, i) => {
129+
li.dataset.score = i.toString();
130+
});
131+
}
123132

124-
if (focusedLevel > prevFocusedLevel) {
125-
closestAncestor = findAncestorOnSpecificLevel(this, prevFocusedLevel);
126-
} else if (focusedLevel < prevFocusedLevel) {
127-
closestAncestor = findAncestorOnSpecificLevel(prevFocused, focusedLevel);
128-
} else {
129-
closestAncestor = prevFocused;
133+
this._listContextState.itemListUpToDate = true;
130134
}
131135

132-
const from = +(closestAncestor?.dataset.index ?? '');
133-
const to = +(this.dataset.index ?? '');
136+
let from = +(prevFocused.dataset.score ?? -1);
137+
let to = +(this.dataset.score ?? -1);
134138

135-
for (let i = from; i <= to; i++) {
136-
const li = this.parentElement?.querySelector(
137-
`:scope > [data-index="${i}"]`
138-
) as VscodeListItem;
139-
selectItemAndAllVisibleDescendants(li);
139+
if (from > to) {
140+
[from, to] = [to, from];
140141
}
142+
143+
this._listContextState.selectedItems.forEach((li) => (li.selected = false));
144+
this._listContextState.selectedItems.clear();
145+
146+
this._selectItemsAndAllVisibleDescendants(from, to);
147+
// console.log(from, to);
148+
}
149+
150+
private _selectItemsAndAllVisibleDescendants(from: number, to: number) {
151+
let i = from;
152+
153+
while (i <= to) {
154+
if (this._listContextState.allItems) {
155+
const item = this._listContextState.allItems[i];
156+
157+
if (item.branch && !item.open) {
158+
item.selected = true;
159+
const numChildren = item.querySelectorAll('vscode-list-item').length;
160+
i += numChildren;
161+
} else if (item.branch && item.open) {
162+
item.selected = true;
163+
i += this._selectItemsAndAllVisibleDescendants(i + 1, to);
164+
} else {
165+
item.selected = true;
166+
i += 1;
167+
}
168+
}
169+
}
170+
171+
console.log(i);
172+
173+
return i;
141174
}
142175

143176
private _mainSlotChange() {
@@ -156,6 +189,7 @@ export class VscodeListItem extends VscElement {
156189

157190
private _handleMainSlotChange = () => {
158191
this._mainSlotChange();
192+
this._listContextState.itemListUpToDate = false;
159193
};
160194

161195
private _handleComponentFocus = () => {
@@ -180,16 +214,19 @@ export class VscodeListItem extends VscElement {
180214

181215
if (isShiftDown) {
182216
this._selectRange();
183-
return;
184-
}
185-
186-
this._selectItem(isCtrlDown);
217+
} else {
218+
this._selectItem(isCtrlDown);
187219

188-
if (this.branch && !(this._listContextState.multiSelect && isCtrlDown)) {
189-
this.open = !this.open;
220+
if (this.branch && !(this._listContextState.multiSelect && isCtrlDown)) {
221+
this.open = !this.open;
222+
}
190223
}
191224

192225
this._focusItem(this);
226+
227+
if (!isShiftDown) {
228+
this._listContextState.prevFocusedItem = this;
229+
}
193230
};
194231

195232
connectedCallback(): void {

src/vscode-list/helpers.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type {VscodeListItem} from '../vscode-list-item';
1+
import {VscodeListItem} from '../vscode-list-item';
22
import type {VscodeList} from './vscode-list';
33

44
const isListItem = (item: HTMLElement): item is VscodeListItem =>
@@ -11,6 +11,7 @@ export const initPathTrackerProps = (
1111
parentElement: VscodeList | VscodeListItem,
1212
items: VscodeListItem[]
1313
): void => {
14+
console.log('initTrackerProps');
1415
const numChildren = items.length;
1516
const parentElementLevel = isListRoot(parentElement)
1617
? -1
@@ -162,10 +163,16 @@ export const findAncestorOnSpecificLevel = (
162163
};
163164

164165
export const selectItemAndAllVisibleDescendants = (item: VscodeListItem) => {
166+
if (!item) {
167+
return;
168+
}
169+
165170
item.selected = true;
166171

167172
if (item.branch && item.open) {
168-
const children = item.querySelectorAll<VscodeListItem>(':scope > vscode-list-item');
173+
const children = item.querySelectorAll<VscodeListItem>(
174+
':scope > vscode-list-item'
175+
);
169176

170177
children.forEach((c) => {
171178
selectItemAndAllVisibleDescendants(c);

src/vscode-list/list-context.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ export interface ListContext {
77
arrows: boolean;
88
multiSelect: boolean;
99
selectedItems: Set<VscodeListItem>;
10+
allItems: NodeListOf<VscodeListItem> | null;
11+
itemListUpToDate: boolean;
1012
focusedItem: VscodeListItem | null;
1113
prevFocusedItem: VscodeListItem | null;
1214
focusItem: (item: VscodeListItem) => void;

src/vscode-list/vscode-list.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ export class VscodeList extends VscElement {
5454
indent: 8,
5555
multiSelect: false,
5656
selectedItems: new Set(),
57+
allItems: null,
58+
itemListUpToDate: false,
5759
focusedItem: null,
5860
prevFocusedItem: null,
5961
hasBranchItem: false,
@@ -155,6 +157,7 @@ export class VscodeList extends VscElement {
155157
};
156158

157159
private _handleSlotChange = () => {
160+
this._listContextState.itemListUpToDate = false;
158161
initPathTrackerProps(this, this._assignedListItems);
159162

160163
const firstChild = this.querySelector('vscode-list-item');

0 commit comments

Comments
 (0)