Merge branch 'search-results-hotkeys' into 'develop'
Allow up/down hotkey navigation in posts search results See merge request soapbox-pub/soapbox-fe!1588
This commit is contained in:
commit
a652aa75a2
2 changed files with 52 additions and 4 deletions
|
@ -86,7 +86,7 @@ const StatusList: React.FC<IStatusList> = ({
|
||||||
index,
|
index,
|
||||||
behavior: 'smooth',
|
behavior: 'smooth',
|
||||||
done: () => {
|
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();
|
element?.focus();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect, useRef } from 'react';
|
||||||
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
|
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
|
||||||
|
|
||||||
import { expandSearch, setFilter } from 'soapbox/actions/search';
|
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 PlaceholderStatus from 'soapbox/features/placeholder/components/placeholder_status';
|
||||||
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
|
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';
|
import type { SearchFilter } from 'soapbox/reducers/search';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
@ -23,6 +25,8 @@ const messages = defineMessages({
|
||||||
});
|
});
|
||||||
|
|
||||||
const SearchResults = () => {
|
const SearchResults = () => {
|
||||||
|
const node = useRef<VirtuosoHandle>(null);
|
||||||
|
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
|
@ -60,6 +64,35 @@ const SearchResults = () => {
|
||||||
return <Tabs items={items} activeItem={selectedFilter} />;
|
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(() => {
|
useEffect(() => {
|
||||||
dispatch(fetchTrendingStatuses());
|
dispatch(fetchTrendingStatuses());
|
||||||
}, []);
|
}, []);
|
||||||
|
@ -69,6 +102,7 @@ const SearchResults = () => {
|
||||||
let loaded;
|
let loaded;
|
||||||
let noResultsMessage;
|
let noResultsMessage;
|
||||||
let placeholderComponent = PlaceholderStatus as React.ComponentType;
|
let placeholderComponent = PlaceholderStatus as React.ComponentType;
|
||||||
|
let resultsIds: ImmutableOrderedSet<string>;
|
||||||
|
|
||||||
if (selectedFilter === 'accounts') {
|
if (selectedFilter === 'accounts') {
|
||||||
hasMore = results.accountsHasMore;
|
hasMore = results.accountsHasMore;
|
||||||
|
@ -99,13 +133,25 @@ const SearchResults = () => {
|
||||||
if (results.statuses && results.statuses.size > 0) {
|
if (results.statuses && results.statuses.size > 0) {
|
||||||
searchResults = results.statuses.map((statusId: string) => (
|
searchResults = results.statuses.map((statusId: string) => (
|
||||||
// @ts-ignore
|
// @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()) {
|
} else if (!submitted && trendingStatuses && !trendingStatuses.isEmpty()) {
|
||||||
searchResults = trendingStatuses.map((statusId: string) => (
|
searchResults = trendingStatuses.map((statusId: string) => (
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
<StatusContainer key={statusId} id={statusId} />
|
<StatusContainer
|
||||||
|
key={statusId}
|
||||||
|
id={statusId}
|
||||||
|
onMoveUp={handleMoveUp}
|
||||||
|
onMoveDown={handleMoveDown}
|
||||||
|
/>
|
||||||
));
|
));
|
||||||
|
resultsIds = trendingStatuses;
|
||||||
} else if (loaded) {
|
} else if (loaded) {
|
||||||
noResultsMessage = (
|
noResultsMessage = (
|
||||||
<div className='empty-column-indicator'>
|
<div className='empty-column-indicator'>
|
||||||
|
@ -147,6 +193,8 @@ const SearchResults = () => {
|
||||||
|
|
||||||
{noResultsMessage || (
|
{noResultsMessage || (
|
||||||
<ScrollableList
|
<ScrollableList
|
||||||
|
id='search-results'
|
||||||
|
ref={node}
|
||||||
key={selectedFilter}
|
key={selectedFilter}
|
||||||
scrollKey={`${selectedFilter}:${value}`}
|
scrollKey={`${selectedFilter}:${value}`}
|
||||||
isLoading={submitted && !loaded}
|
isLoading={submitted && !loaded}
|
||||||
|
|
Loading…
Reference in a new issue