Merge branch 'hotkey-nav' into 'develop'
Fix hotkey navigation? See merge request soapbox-pub/soapbox-fe!1409
This commit is contained in:
commit
f90f76ae02
6 changed files with 54 additions and 44 deletions
|
@ -42,6 +42,7 @@ interface IScrollableList extends VirtuosoProps<any, any> {
|
|||
onRefresh?: () => Promise<any>,
|
||||
className?: string,
|
||||
itemClassName?: string,
|
||||
id?: string,
|
||||
style?: React.CSSProperties,
|
||||
useWindowScroll?: boolean
|
||||
}
|
||||
|
@ -60,6 +61,7 @@ const ScrollableList = React.forwardRef<VirtuosoHandle, IScrollableList>(({
|
|||
onLoadMore,
|
||||
className,
|
||||
itemClassName,
|
||||
id,
|
||||
hasMore,
|
||||
placeholderComponent: Placeholder,
|
||||
placeholderCount = 0,
|
||||
|
@ -133,6 +135,7 @@ const ScrollableList = React.forwardRef<VirtuosoHandle, IScrollableList>(({
|
|||
const renderFeed = (): JSX.Element => (
|
||||
<Virtuoso
|
||||
ref={ref}
|
||||
id={id}
|
||||
useWindowScroll={useWindowScroll}
|
||||
className={className}
|
||||
data={data}
|
||||
|
|
|
@ -282,13 +282,11 @@ class Status extends ImmutablePureComponent<IStatus, IStatusState> {
|
|||
}
|
||||
|
||||
handleHotkeyMoveUp = (e?: KeyboardEvent): void => {
|
||||
// FIXME: what's going on here?
|
||||
// this.props.onMoveUp(this.props.status.id, e?.target?.getAttribute('data-featured'));
|
||||
this.props.onMoveUp(this.props.status.id, this.props.featured);
|
||||
}
|
||||
|
||||
handleHotkeyMoveDown = (e?: KeyboardEvent): void => {
|
||||
// FIXME: what's going on here?
|
||||
// this.props.onMoveDown(this.props.status.id, e?.target?.getAttribute('data-featured'));
|
||||
this.props.onMoveDown(this.props.status.id, this.props.featured);
|
||||
}
|
||||
|
||||
handleHotkeyToggleHidden = (): void => {
|
||||
|
@ -601,7 +599,7 @@ class Status extends ImmutablePureComponent<IStatus, IStatusState> {
|
|||
return (
|
||||
<HotKeys handlers={handlers} data-testid='status'>
|
||||
<div
|
||||
className='status cursor-pointer'
|
||||
className={classNames('status cursor-pointer', { focusable: this.props.focusable })}
|
||||
tabIndex={this.props.focusable && !this.props.muted ? 0 : undefined}
|
||||
data-featured={featured ? 'true' : null}
|
||||
aria-label={textForScreenReader(intl, status, rebloggedByText)}
|
||||
|
|
|
@ -77,18 +77,18 @@ export default class StatusList extends ImmutablePureComponent {
|
|||
this.props.onLoadMore(loadMoreID);
|
||||
}, 300, { leading: true })
|
||||
|
||||
_selectChild(index, align_top) {
|
||||
const container = this.node.node;
|
||||
const element = container.querySelector(`article:nth-of-type(${index + 1}) .focusable`);
|
||||
_selectChild(index) {
|
||||
this.node.scrollIntoView({
|
||||
index,
|
||||
behavior: 'smooth',
|
||||
done: () => {
|
||||
const element = document.querySelector(`#status-list [data-index="${index}"] .focusable`);
|
||||
|
||||
if (element) {
|
||||
if (align_top && container.scrollTop > element.offsetTop) {
|
||||
element.scrollIntoView(true);
|
||||
} else if (!align_top && container.scrollTop + container.clientHeight < element.offsetTop + element.offsetHeight) {
|
||||
element.scrollIntoView(false);
|
||||
}
|
||||
element.focus();
|
||||
}
|
||||
if (element) {
|
||||
element.focus();
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
handleDequeueTimeline = () => {
|
||||
|
@ -216,6 +216,7 @@ export default class StatusList extends ImmutablePureComponent {
|
|||
message={messages.queue}
|
||||
/>,
|
||||
<ScrollableList
|
||||
id='status-list'
|
||||
key='scrollable-list'
|
||||
isLoading={isLoading}
|
||||
showLoading={isLoading && statusIds.size === 0}
|
||||
|
|
|
@ -20,26 +20,26 @@ export default class ConversationsList extends ImmutablePureComponent {
|
|||
|
||||
handleMoveUp = id => {
|
||||
const elementIndex = this.getCurrentIndex(id) - 1;
|
||||
this._selectChild(elementIndex, true);
|
||||
this._selectChild(elementIndex);
|
||||
}
|
||||
|
||||
handleMoveDown = id => {
|
||||
const elementIndex = this.getCurrentIndex(id) + 1;
|
||||
this._selectChild(elementIndex, false);
|
||||
this._selectChild(elementIndex);
|
||||
}
|
||||
|
||||
_selectChild(index, align_top) {
|
||||
const container = this.node.node;
|
||||
const element = container.querySelector(`article:nth-of-type(${index + 1}) .focusable`);
|
||||
_selectChild(index) {
|
||||
this.node.scrollIntoView({
|
||||
index,
|
||||
behavior: 'smooth',
|
||||
done: () => {
|
||||
const element = document.querySelector(`#direct-list [data-index="${index}"] .focusable`);
|
||||
|
||||
if (element) {
|
||||
if (align_top && container.scrollTop > element.offsetTop) {
|
||||
element.scrollIntoView(true);
|
||||
} else if (!align_top && container.scrollTop + container.clientHeight < element.offsetTop + element.offsetHeight) {
|
||||
element.scrollIntoView(false);
|
||||
}
|
||||
element.focus();
|
||||
}
|
||||
if (element) {
|
||||
element.focus();
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
setRef = c => {
|
||||
|
@ -58,7 +58,9 @@ export default class ConversationsList extends ImmutablePureComponent {
|
|||
<ScrollableList
|
||||
{...other}
|
||||
onLoadMore={onLoadMore && this.handleLoadOlder}
|
||||
scrollKey='direct' ref={this.setRef}
|
||||
id='direct-list'
|
||||
scrollKey='direct'
|
||||
ref={this.setRef}
|
||||
isLoading={isLoading}
|
||||
showLoading={isLoading && conversations.size === 0}
|
||||
>
|
||||
|
|
|
@ -111,32 +111,37 @@ class Notifications extends React.PureComponent {
|
|||
this.props.dispatch(scrollTopNotifications(false));
|
||||
}, 100);
|
||||
|
||||
setRef = c => {
|
||||
this.node = c;
|
||||
}
|
||||
|
||||
setColumnRef = c => {
|
||||
this.column = c;
|
||||
}
|
||||
|
||||
handleMoveUp = id => {
|
||||
const elementIndex = this.props.notifications.findIndex(item => item !== null && item.get('id') === id) - 1;
|
||||
this._selectChild(elementIndex, true);
|
||||
this._selectChild(elementIndex);
|
||||
}
|
||||
|
||||
handleMoveDown = id => {
|
||||
const elementIndex = this.props.notifications.findIndex(item => item !== null && item.get('id') === id) + 1;
|
||||
this._selectChild(elementIndex, false);
|
||||
this._selectChild(elementIndex);
|
||||
}
|
||||
|
||||
_selectChild(index, align_top) {
|
||||
const container = this.column;
|
||||
const element = container.querySelector(`article:nth-of-type(${index + 1}) .focusable`);
|
||||
_selectChild(index) {
|
||||
this.node.scrollIntoView({
|
||||
index,
|
||||
behavior: 'smooth',
|
||||
done: () => {
|
||||
const container = this.column;
|
||||
const element = container.querySelector(`[data-index="${index}"] .focusable`);
|
||||
|
||||
if (element) {
|
||||
if (align_top && container.scrollTop > element.offsetTop) {
|
||||
element.scrollIntoView(true);
|
||||
} else if (!align_top && container.scrollTop + container.clientHeight < element.offsetTop + element.offsetHeight) {
|
||||
element.scrollIntoView(false);
|
||||
}
|
||||
element.focus();
|
||||
}
|
||||
if (element) {
|
||||
element.focus();
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
handleDequeueNotifications = () => {
|
||||
|
@ -161,6 +166,7 @@ class Notifications extends React.PureComponent {
|
|||
const scrollContainer = (
|
||||
<PullToRefresh onRefresh={this.handleRefresh}>
|
||||
<Virtuoso
|
||||
ref={this.setRef}
|
||||
useWindowScroll
|
||||
data={showLoading ? Array(20).fill() : notifications.toArray()}
|
||||
startReached={this.handleScrollToTop}
|
||||
|
|
|
@ -715,7 +715,7 @@ class Status extends ImmutablePureComponent<IStatus, IStatusState> {
|
|||
<HotKeys handlers={handlers}>
|
||||
<div
|
||||
ref={this.setStatusRef}
|
||||
className={classNames('detailed-status__wrapper')}
|
||||
className='detailed-status__wrapper focusable'
|
||||
tabIndex={0}
|
||||
// FIXME: no "reblogged by" text is added for the screen reader
|
||||
aria-label={textForScreenReader(intl, status)}
|
||||
|
|
Loading…
Reference in a new issue