Merge branch 'search-results-hotkeys' into 'develop'

Allow up/down hotkey navigation in posts search results

See merge request soapbox-pub/soapbox-fe!1588
environments/review-develop-3zknud/deployments/436
marcin mikołajczak 2 years ago
commit a652aa75a2

@ -86,7 +86,7 @@ const StatusList: React.FC<IStatusList> = ({
index,
behavior: 'smooth',
done: () => {
const element: HTMLElement | null = document.querySelector(`#status-list [data-index="${index}"] .focusable`);
const element = document.querySelector<HTMLDivElement>(`#status-list [data-index="${index}"] .focusable`);
element?.focus();
},
});

@ -1,5 +1,5 @@
import classNames from 'classnames';
import React, { useEffect } from 'react';
import React, { useEffect, useRef } from 'react';
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
import { expandSearch, setFilter } from 'soapbox/actions/search';
@ -14,6 +14,8 @@ import PlaceholderHashtag from 'soapbox/features/placeholder/components/placehol
import PlaceholderStatus from 'soapbox/features/placeholder/components/placeholder_status';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
import type { OrderedSet as ImmutableOrderedSet } from 'immutable';
import type { VirtuosoHandle } from 'react-virtuoso';
import type { SearchFilter } from 'soapbox/reducers/search';
const messages = defineMessages({
@ -23,6 +25,8 @@ const messages = defineMessages({
});
const SearchResults = () => {
const node = useRef<VirtuosoHandle>(null);
const intl = useIntl();
const dispatch = useAppDispatch();
@ -60,6 +64,35 @@ const SearchResults = () => {
return <Tabs items={items} activeItem={selectedFilter} />;
};
const getCurrentIndex = (id: string): number => {
return resultsIds?.keySeq().findIndex(key => key === id);
};
const handleMoveUp = (id: string) => {
if (!resultsIds) return;
const elementIndex = getCurrentIndex(id) - 1;
selectChild(elementIndex);
};
const handleMoveDown = (id: string) => {
if (!resultsIds) return;
const elementIndex = getCurrentIndex(id) + 1;
selectChild(elementIndex);
};
const selectChild = (index: number) => {
node.current?.scrollIntoView({
index,
behavior: 'smooth',
done: () => {
const element = document.querySelector<HTMLDivElement>(`#search-results [data-index="${index}"] .focusable`);
element?.focus();
},
});
};
useEffect(() => {
dispatch(fetchTrendingStatuses());
}, []);
@ -69,6 +102,7 @@ const SearchResults = () => {
let loaded;
let noResultsMessage;
let placeholderComponent = PlaceholderStatus as React.ComponentType;
let resultsIds: ImmutableOrderedSet<string>;
if (selectedFilter === 'accounts') {
hasMore = results.accountsHasMore;
@ -99,13 +133,25 @@ const SearchResults = () => {
if (results.statuses && results.statuses.size > 0) {
searchResults = results.statuses.map((statusId: string) => (
// @ts-ignore
<StatusContainer key={statusId} id={statusId} />
<StatusContainer
key={statusId}
id={statusId}
onMoveUp={handleMoveUp}
onMoveDown={handleMoveDown}
/>
));
resultsIds = results.statuses;
} else if (!submitted && trendingStatuses && !trendingStatuses.isEmpty()) {
searchResults = trendingStatuses.map((statusId: string) => (
// @ts-ignore
<StatusContainer key={statusId} id={statusId} />
<StatusContainer
key={statusId}
id={statusId}
onMoveUp={handleMoveUp}
onMoveDown={handleMoveDown}
/>
));
resultsIds = trendingStatuses;
} else if (loaded) {
noResultsMessage = (
<div className='empty-column-indicator'>
@ -147,6 +193,8 @@ const SearchResults = () => {
{noResultsMessage || (
<ScrollableList
id='search-results'
ref={node}
key={selectedFilter}
scrollKey={`${selectedFilter}:${value}`}
isLoading={submitted && !loaded}

Loading…
Cancel
Save