Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TreeView] Use the order in which the items are displayed for type-ahead #12827

Merged
merged 2 commits into from
Apr 23, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,6 @@ function isPrintableCharacter(string: string) {
return !!string && string.length === 1 && !!string.match(/\S/);
}

function findNextFirstChar(firstChars: string[], startIndex: number, char: string) {
for (let i = startIndex; i < firstChars.length; i += 1) {
if (char === firstChars[i]) {
return i;
}
}
return -1;
}

export const useTreeViewKeyboardNavigation: TreeViewPlugin<
UseTreeViewKeyboardNavigationSignature
> = ({ instance, params, state }) => {
Expand Down Expand Up @@ -55,47 +46,31 @@ export const useTreeViewKeyboardNavigation: TreeViewPlugin<
firstCharMap.current = newFirstCharMap;
}, [state.items.itemMetaMap, params.getItemId, instance]);

const getFirstMatchingItem = (itemId: string, firstChar: string) => {
let start: number;
let index: number;
const lowercaseChar = firstChar.toLowerCase();

const firstCharIds: string[] = [];
const firstChars: string[] = [];
// This really only works since the ids are strings
Object.keys(firstCharMap.current).forEach((mapItemId) => {
const map = instance.getItemMeta(mapItemId);
const visible = map.parentId ? instance.isItemExpanded(map.parentId) : true;
const shouldBeSkipped = params.disabledItemsFocusable
? false
: instance.isItemDisabled(mapItemId);

if (visible && !shouldBeSkipped) {
firstCharIds.push(mapItemId);
firstChars.push(firstCharMap.current[mapItemId]);
}
});

// Get start index for search based on position of currentItem
start = firstCharIds.indexOf(itemId) + 1;
if (start >= firstCharIds.length) {
start = 0;
}
const getFirstMatchingItem = (itemId: string, query: string) => {
const cleanQuery = query.toLowerCase();

// Check remaining slots in the menu
index = findNextFirstChar(firstChars, start, lowercaseChar);
const getNextItem = (itemIdToCheck: string) => {
const nextItemId = getNextNavigableItem(instance, itemIdToCheck);
flaviendelangle marked this conversation as resolved.
Show resolved Hide resolved
// We reached the end of the tree, check from the beginning
if (nextItemId === null) {
return getFirstNavigableItem(instance);
}

// If not found in remaining slots, check from beginning
if (index === -1) {
index = findNextFirstChar(firstChars, 0, lowercaseChar);
}
return nextItemId;
};

// If a match was found...
if (index > -1) {
return firstCharIds[index];
let matchingItemId: string | null = null;
let currentItemId: string = getNextItem(itemId);
// The "currentItemId !== itemId" condition is to avoid an infinite loop when there is no matching item.
while (matchingItemId == null && currentItemId !== itemId) {
if (firstCharMap.current[currentItemId] === cleanQuery) {
matchingItemId = currentItemId;
} else {
currentItemId = getNextItem(currentItemId);
}
}

return null;
return matchingItemId;
};

const canToggleItemSelection = (itemId: string) =>
Expand Down