mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 21:15:32 +09:00
fix(app): keep quick switcher focus when results are recomputed (#1746)
This commit is contained in:
1 parent
30a61ce90f
commit
7b5c82c6cf
3 files changed
+64
-1
No files matched your search
@@ -19,6 +19,7 @@ import {
|
||||
generateQueryModeResults,
|
||||
resolveTransformedMember,
|
||||
} from '@app/features/search/state/QuickSwitcherResultGenerators';
|
||||
import {resolveRecomputedSelectedIndex} from '@app/features/search/state/QuickSwitcherSelection';
|
||||
import type {
|
||||
CandidateSets,
|
||||
ComputeResultsForQueryResult,
|
||||
@@ -404,10 +405,11 @@ class QuickSwitcher {
|
||||
if (options.invalidateCandidates ?? true) {
|
||||
this.invalidateCandidateSets();
|
||||
}
|
||||
const previous = this.results[this.selectedIndex];
|
||||
const {queryMode, results, selectedIndex} = this.computeResultsForQuery(this.query);
|
||||
this.queryMode = queryMode;
|
||||
this.results = results;
|
||||
this.selectedIndex = selectedIndex;
|
||||
this.selectedIndex = resolveRecomputedSelectedIndex(previous, results, selectedIndex);
|
||||
}
|
||||
|
||||
private computeResultsForQuery(query: string): ComputeResultsForQueryResult {
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import {resolveRecomputedSelectedIndex} from '@app/features/search/state/QuickSwitcherSelection';
|
||||
import type {QuickSwitcherResult} from '@app/features/search/state/QuickSwitcherTypes';
|
||||
import {QuickSwitcherResultTypes} from '@fluxer/constants/src/QuickSwitcherConstants';
|
||||
import {describe, expect, it} from 'vitest';
|
||||
|
||||
const result = (type: QuickSwitcherResult['type'], id: string) => ({type, id}) as QuickSwitcherResult;
|
||||
|
||||
describe('resolveRecomputedSelectedIndex', () => {
|
||||
it('follows the focused result when the list is reordered', () => {
|
||||
const previous = result(QuickSwitcherResultTypes.TEXT_CHANNEL, 'c3');
|
||||
const results = [
|
||||
result(QuickSwitcherResultTypes.TEXT_CHANNEL, 'c3'),
|
||||
result(QuickSwitcherResultTypes.TEXT_CHANNEL, 'c1'),
|
||||
result(QuickSwitcherResultTypes.TEXT_CHANNEL, 'c2'),
|
||||
];
|
||||
expect(resolveRecomputedSelectedIndex(previous, results, 0)).toBe(0);
|
||||
});
|
||||
|
||||
it('keeps the focused result when entries are inserted above it', () => {
|
||||
const previous = result(QuickSwitcherResultTypes.TEXT_CHANNEL, 'c2');
|
||||
const results = [
|
||||
result(QuickSwitcherResultTypes.HEADER, 'h1'),
|
||||
result(QuickSwitcherResultTypes.TEXT_CHANNEL, 'c9'),
|
||||
result(QuickSwitcherResultTypes.TEXT_CHANNEL, 'c2'),
|
||||
];
|
||||
expect(resolveRecomputedSelectedIndex(previous, results, 1)).toBe(2);
|
||||
});
|
||||
|
||||
it('falls back when the focused result disappears', () => {
|
||||
const previous = result(QuickSwitcherResultTypes.TEXT_CHANNEL, 'gone');
|
||||
const results = [result(QuickSwitcherResultTypes.TEXT_CHANNEL, 'c1')];
|
||||
expect(resolveRecomputedSelectedIndex(previous, results, 0)).toBe(0);
|
||||
});
|
||||
|
||||
it('does not confuse ids that repeat across result types', () => {
|
||||
const previous = result(QuickSwitcherResultTypes.GUILD, '42');
|
||||
const results = [result(QuickSwitcherResultTypes.TEXT_CHANNEL, '42'), result(QuickSwitcherResultTypes.GUILD, '42')];
|
||||
expect(resolveRecomputedSelectedIndex(previous, results, 0)).toBe(1);
|
||||
});
|
||||
|
||||
it('uses the fallback when nothing was focused', () => {
|
||||
expect(resolveRecomputedSelectedIndex(undefined, [result(QuickSwitcherResultTypes.GUILD, 'g')], 0)).toBe(0);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import type {QuickSwitcherResult} from '@app/features/search/state/QuickSwitcherTypes';
|
||||
|
||||
export function resolveRecomputedSelectedIndex(
|
||||
previous: QuickSwitcherResult | undefined,
|
||||
results: ReadonlyArray<QuickSwitcherResult>,
|
||||
fallbackIndex: number,
|
||||
): number {
|
||||
if (!previous) {
|
||||
return fallbackIndex;
|
||||
}
|
||||
const restored = results.findIndex((result) => result.type === previous.type && result.id === previous.id);
|
||||
return restored >= 0 ? restored : fallbackIndex;
|
||||
}
|
||||
Reference in new issue
Block a user