Skip to content

Commit 9839c0c

Browse files
committed
fix issues with selected and scrollToIndex after selected
1 parent 6eb7b6d commit 9839c0c

File tree

2 files changed

+28
-43
lines changed

2 files changed

+28
-43
lines changed

src/primitives/Virtual.tsx

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,15 @@ function createVirtual<T>(
4646
return props.uniformSize !== false;
4747
});
4848

49-
type SliceState = { start: number; slice: T[]; selected: number, delta: number, shiftBy: number, atStart: boolean };
49+
type SliceState = { start: number; slice: T[]; selected: number, delta: number, shiftBy: number, atStart: boolean; cursor: number };
5050
const [slice, setSlice] = s.createSignal<SliceState>({
5151
start: 0,
5252
slice: [],
5353
selected: 0,
5454
delta: 0,
5555
shiftBy: 0,
5656
atStart: true,
57+
cursor: 0,
5758
});
5859

5960
function normalizeDeltaForWindow(delta: number, windowLen: number): number {
@@ -86,7 +87,7 @@ function createVirtual<T>(
8687

8788
function computeSlice(c: number, delta: number, prev: SliceState): SliceState {
8889
const total = itemCount();
89-
if (total === 0) return { start: 0, slice: [], selected: 0, delta, shiftBy: 0, atStart: true };
90+
if (total === 0) return { start: 0, slice: [], selected: 0, delta, shiftBy: 0, atStart: true, cursor: 0 };
9091

9192
const length = props.displaySize + bufferSize();
9293
let start = prev.start;
@@ -186,7 +187,7 @@ function createVirtual<T>(
186187
atStart = false;
187188
} else {
188189
// ScrollToIndex was called
189-
if (Math.abs(c - prev.start) > 1) {
190+
if (c !== prev.cursor) {
190191
start = c;
191192
if (c === 0) {
192193
atStart = true;
@@ -286,7 +287,7 @@ function createVirtual<T>(
286287
: items().slice(start, start + length);
287288
}
288289

289-
const state: SliceState = { start, slice: newSlice, selected, delta, shiftBy, atStart };
290+
const state: SliceState = { start, slice: newSlice, selected, delta, shiftBy, atStart, cursor: c };
290291

291292
if (props.debugInfo) {
292293
console.log(`[Virtual]`, {
@@ -412,6 +413,15 @@ function createVirtual<T>(
412413
if (lng.hasFocus(viewRef)) {
413414
viewRef.children[activeIndex]?.setFocus();
414415
}
416+
417+
if (newState.shiftBy === 0) return;
418+
419+
const childSize = computeSize(slice().selected);
420+
// Original Position is offset to support scrollToIndex
421+
originalPosition = originalPosition ?? viewRef.lng[axis];
422+
targetPosition = targetPosition ?? viewRef.lng[axis];
423+
424+
viewRef.lng[axis] = (viewRef.lng[axis] || 0) + (childSize * -1);
415425
});
416426
};
417427

src/primitives/utils/handleNavigation.ts

Lines changed: 14 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,7 @@ function idxInArray(idx: number, arr: readonly any[]): boolean {
66
return idx >= 0 && idx < arr.length;
77
}
88

9-
function findFirstFocusableChildIdx(
10-
el: lngp.NavigableElement,
11-
from = 0,
12-
delta = 1,
13-
): number {
9+
function findFirstFocusableChildIdx(el: lngp.NavigableElement, from = 0, delta = 1): number {
1410
for (let i = from; ; i += delta) {
1511
if (!idxInArray(i, el.children)) {
1612
if (el.wrap) {
@@ -46,9 +42,7 @@ function selectChild(el: lngp.NavigableElement, index: number): boolean {
4642
}
4743

4844
/** @deprecated Use {@link navigableForwardFocus} instead */
49-
export function onGridFocus(
50-
_?: lngp.OnSelectedChanged,
51-
): lng.ForwardFocusHandler {
45+
export function onGridFocus(_?: lngp.OnSelectedChanged): lng.ForwardFocusHandler {
5246
return function () {
5347
return navigableForwardFocus.call(this, this);
5448
};
@@ -72,6 +66,10 @@ export const navigableForwardFocus: lng.ForwardFocusHandler = function () {
7266

7367
let selected = Math.max(navigable.selected, 0);
7468

69+
if (this.children.length === 0) {
70+
return false;
71+
}
72+
7573
if (selected !== 0) {
7674
selected = lng.clamp(selected, 0, Math.max(0, this.children.length - 1));
7775
while (!idxInArray(selected, this.children)) {
@@ -85,14 +83,9 @@ export const navigableForwardFocus: lng.ForwardFocusHandler = function () {
8583
return selectChild(navigable, selected);
8684
};
8785

88-
export function handleNavigation(
89-
direction: 'up' | 'right' | 'down' | 'left',
90-
): lng.KeyHandler {
86+
export function handleNavigation(direction: 'up' | 'right' | 'down' | 'left'): lng.KeyHandler {
9187
return function () {
92-
return moveSelection(
93-
this as lngp.NavigableElement,
94-
direction === 'up' || direction === 'left' ? -1 : 1,
95-
);
88+
return moveSelection(this as lngp.NavigableElement, direction === 'up' || direction === 'left' ? -1 : 1);
9689
};
9790
}
9891

@@ -113,19 +106,13 @@ export function handleNavigation(
113106
* ```
114107
*/
115108
export const navigableHandleNavigation: lng.KeyHandler = function (e) {
116-
return moveSelection(
117-
this as lngp.NavigableElement,
118-
e.key === 'ArrowUp' || e.key === 'ArrowLeft' ? -1 : 1,
119-
);
109+
return moveSelection(this as lngp.NavigableElement, e.key === 'ArrowUp' || e.key === 'ArrowLeft' ? -1 : 1);
120110
};
121111

122112
/**
123113
* Moves the selection within a {@link lngp.NavigableElement}.
124114
*/
125-
export function moveSelection(
126-
el: lngp.NavigableElement,
127-
delta: number,
128-
): boolean {
115+
export function moveSelection(el: lngp.NavigableElement, delta: number): boolean {
129116
let selected = findFirstFocusableChildIdx(el, el.selected + delta, delta);
130117

131118
if (selected === -1) {
@@ -148,8 +135,7 @@ export function moveSelection(
148135
lng.assertTruthy(lastSelectedChild instanceof lng.ElementNode);
149136

150137
const num = lastSelectedChild.selected || 0;
151-
active.selected =
152-
num < active.children.length ? num : active.children.length - 1;
138+
active.selected = num < active.children.length ? num : active.children.length - 1;
153139
}
154140

155141
return selectChild(el, selected);
@@ -161,10 +147,7 @@ function distanceBetweenRectCenters(a: lng.Rect, b: lng.Rect): number {
161147
return Math.sqrt(dx * dx + dy * dy);
162148
}
163149

164-
function findClosestFocusableChildIdx(
165-
el: lng.ElementNode,
166-
prevEl: lng.ElementNode,
167-
): number {
150+
function findClosestFocusableChildIdx(el: lng.ElementNode, prevEl: lng.ElementNode): number {
168151
// select child closest to the previous active element
169152
const prevRect = lng.getElementScreenRect(prevEl);
170153
const elRect = lng.getElementScreenRect(el);
@@ -272,11 +255,7 @@ export const spatialHandleNavigation: lng.KeyHandler = function (e) {
272255

273256
// Select next/prev child in the current column/row
274257
if (flexDelta !== 0) {
275-
for (
276-
let i = selected + flexDelta;
277-
idxInArray(i, this.children);
278-
i += flexDelta
279-
) {
258+
for (let i = selected + flexDelta; idxInArray(i, this.children); i += flexDelta) {
280259
const child = this.children[i]!;
281260
if (child.skipFocus) continue;
282261

@@ -291,11 +270,7 @@ export const spatialHandleNavigation: lng.KeyHandler = function (e) {
291270
let closestIdx = -1;
292271
let closestDist = Infinity;
293272

294-
for (
295-
let i = selected + crossDelta;
296-
idxInArray(i, this.children);
297-
i += crossDelta
298-
) {
273+
for (let i = selected + crossDelta; idxInArray(i, this.children); i += crossDelta) {
299274
const child = this.children[i]!;
300275
if (child.skipFocus) continue;
301276

0 commit comments

Comments
 (0)