Pressing Esc in left pane composer menu should go back
This commit is contained in:
parent
2d35fa8f57
commit
f05d45ac9b
12 changed files with 168 additions and 5 deletions
|
@ -348,8 +348,30 @@ export const LeftPane: React.FC<PropsType> = ({
|
||||||
// It also ensures that we scroll to the top when switching views.
|
// It also ensures that we scroll to the top when switching views.
|
||||||
const listKey = preRowsNode ? 1 : 0;
|
const listKey = preRowsNode ? 1 : 0;
|
||||||
|
|
||||||
|
// We disable this lint rule because we're trying to capture bubbled events. See [the
|
||||||
|
// lint rule's docs][0].
|
||||||
|
//
|
||||||
|
// [0]: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/645900a0e296ca7053dbf6cd9e12cc85849de2d5/docs/rules/no-static-element-interactions.md#case-the-event-handler-is-only-being-used-to-capture-bubbled-events
|
||||||
|
/* eslint-disable jsx-a11y/no-static-element-interactions */
|
||||||
return (
|
return (
|
||||||
<div className="module-left-pane">
|
<div
|
||||||
|
className="module-left-pane"
|
||||||
|
onKeyDown={event => {
|
||||||
|
if (event.key === 'Escape') {
|
||||||
|
const backAction = helper.getBackAction({
|
||||||
|
showInbox,
|
||||||
|
startComposing,
|
||||||
|
showChooseGroupMembers,
|
||||||
|
});
|
||||||
|
if (backAction) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
backAction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* eslint-enable jsx-a11y/no-static-element-interactions */}
|
||||||
<div className="module-left-pane__header">
|
<div className="module-left-pane__header">
|
||||||
{helper.getHeaderContents({
|
{helper.getHeaderContents({
|
||||||
i18n,
|
i18n,
|
||||||
|
|
|
@ -39,7 +39,7 @@ export class LeftPaneArchiveHelper extends LeftPaneHelper<
|
||||||
return (
|
return (
|
||||||
<div className="module-left-pane__header__contents">
|
<div className="module-left-pane__header__contents">
|
||||||
<button
|
<button
|
||||||
onClick={showInbox}
|
onClick={this.getBackAction({ showInbox })}
|
||||||
className="module-left-pane__header__contents__back-button"
|
className="module-left-pane__header__contents__back-button"
|
||||||
title={i18n('backToInbox')}
|
title={i18n('backToInbox')}
|
||||||
aria-label={i18n('backToInbox')}
|
aria-label={i18n('backToInbox')}
|
||||||
|
@ -52,6 +52,10 @@ export class LeftPaneArchiveHelper extends LeftPaneHelper<
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getBackAction({ showInbox }: { showInbox: () => void }): () => void {
|
||||||
|
return showInbox;
|
||||||
|
}
|
||||||
|
|
||||||
getPreRowsNode({ i18n }: Readonly<{ i18n: LocalizerType }>): ReactChild {
|
getPreRowsNode({ i18n }: Readonly<{ i18n: LocalizerType }>): ReactChild {
|
||||||
return (
|
return (
|
||||||
<div className="module-left-pane__archive-helper-text">
|
<div className="module-left-pane__archive-helper-text">
|
||||||
|
|
|
@ -86,7 +86,7 @@ export class LeftPaneChooseGroupMembersHelper extends LeftPaneHelper<
|
||||||
<button
|
<button
|
||||||
aria-label={backButtonLabel}
|
aria-label={backButtonLabel}
|
||||||
className="module-left-pane__header__contents__back-button"
|
className="module-left-pane__header__contents__back-button"
|
||||||
onClick={startComposing}
|
onClick={this.getBackAction({ startComposing })}
|
||||||
title={backButtonLabel}
|
title={backButtonLabel}
|
||||||
type="button"
|
type="button"
|
||||||
/>
|
/>
|
||||||
|
@ -97,6 +97,14 @@ export class LeftPaneChooseGroupMembersHelper extends LeftPaneHelper<
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getBackAction({
|
||||||
|
startComposing,
|
||||||
|
}: {
|
||||||
|
startComposing: () => void;
|
||||||
|
}): () => void {
|
||||||
|
return startComposing;
|
||||||
|
}
|
||||||
|
|
||||||
getPreRowsNode({
|
getPreRowsNode({
|
||||||
closeCantAddContactToGroupModal,
|
closeCantAddContactToGroupModal,
|
||||||
closeMaximumGroupSizeModal,
|
closeMaximumGroupSizeModal,
|
||||||
|
|
|
@ -61,7 +61,7 @@ export class LeftPaneComposeHelper extends LeftPaneHelper<
|
||||||
return (
|
return (
|
||||||
<div className="module-left-pane__header__contents">
|
<div className="module-left-pane__header__contents">
|
||||||
<button
|
<button
|
||||||
onClick={showInbox}
|
onClick={this.getBackAction({ showInbox })}
|
||||||
className="module-left-pane__header__contents__back-button"
|
className="module-left-pane__header__contents__back-button"
|
||||||
title={i18n('backToInbox')}
|
title={i18n('backToInbox')}
|
||||||
aria-label={i18n('backToInbox')}
|
aria-label={i18n('backToInbox')}
|
||||||
|
@ -74,6 +74,10 @@ export class LeftPaneComposeHelper extends LeftPaneHelper<
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getBackAction({ showInbox }: { showInbox: () => void }): () => void {
|
||||||
|
return showInbox;
|
||||||
|
}
|
||||||
|
|
||||||
getPreRowsNode({
|
getPreRowsNode({
|
||||||
i18n,
|
i18n,
|
||||||
onChangeComposeSearchTerm,
|
onChangeComposeSearchTerm,
|
||||||
|
|
|
@ -30,6 +30,16 @@ export abstract class LeftPaneHelper<T> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getBackAction(
|
||||||
|
_: Readonly<{
|
||||||
|
showInbox: () => void;
|
||||||
|
startComposing: () => void;
|
||||||
|
showChooseGroupMembers: () => void;
|
||||||
|
}>
|
||||||
|
): undefined | (() => void) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
shouldRenderNetworkStatusAndUpdateDialog(): boolean {
|
shouldRenderNetworkStatusAndUpdateDialog(): boolean {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ export class LeftPaneSetGroupMetadataHelper extends LeftPaneHelper<
|
||||||
aria-label={backButtonLabel}
|
aria-label={backButtonLabel}
|
||||||
className="module-left-pane__header__contents__back-button"
|
className="module-left-pane__header__contents__back-button"
|
||||||
disabled={this.isCreating}
|
disabled={this.isCreating}
|
||||||
onClick={showChooseGroupMembers}
|
onClick={this.getBackAction({ showChooseGroupMembers })}
|
||||||
title={backButtonLabel}
|
title={backButtonLabel}
|
||||||
type="button"
|
type="button"
|
||||||
/>
|
/>
|
||||||
|
@ -78,6 +78,14 @@ export class LeftPaneSetGroupMetadataHelper extends LeftPaneHelper<
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getBackAction({
|
||||||
|
showChooseGroupMembers,
|
||||||
|
}: {
|
||||||
|
showChooseGroupMembers: () => void;
|
||||||
|
}): undefined | (() => void) {
|
||||||
|
return this.isCreating ? undefined : showChooseGroupMembers;
|
||||||
|
}
|
||||||
|
|
||||||
getPreRowsNode({
|
getPreRowsNode({
|
||||||
clearGroupCreationError,
|
clearGroupCreationError,
|
||||||
createGroup,
|
createGroup,
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import { assert } from 'chai';
|
import { assert } from 'chai';
|
||||||
|
import * as sinon from 'sinon';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { RowType } from '../../../components/ConversationList';
|
import { RowType } from '../../../components/ConversationList';
|
||||||
import { FindDirection } from '../../../components/leftPane/LeftPaneHelper';
|
import { FindDirection } from '../../../components/leftPane/LeftPaneHelper';
|
||||||
|
@ -15,6 +16,15 @@ describe('LeftPaneArchiveHelper', () => {
|
||||||
type: 'direct' as const,
|
type: 'direct' as const,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('getBackAction', () => {
|
||||||
|
it('returns the "show inbox" action', () => {
|
||||||
|
const showInbox = sinon.fake();
|
||||||
|
const helper = new LeftPaneArchiveHelper({ archivedConversations: [] });
|
||||||
|
|
||||||
|
assert.strictEqual(helper.getBackAction({ showInbox }), showInbox);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('getRowCount', () => {
|
describe('getRowCount', () => {
|
||||||
it('returns the number of archived conversations', () => {
|
it('returns the number of archived conversations', () => {
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
|
|
|
@ -45,6 +45,18 @@ describe('LeftPaneChooseGroupMembersHelper', () => {
|
||||||
sinonSandbox.restore();
|
sinonSandbox.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('getBackAction', () => {
|
||||||
|
it('returns the "show composer" action', () => {
|
||||||
|
const startComposing = sinon.fake();
|
||||||
|
const helper = new LeftPaneChooseGroupMembersHelper(defaults);
|
||||||
|
|
||||||
|
assert.strictEqual(
|
||||||
|
helper.getBackAction({ startComposing }),
|
||||||
|
startComposing
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('getRowCount', () => {
|
describe('getRowCount', () => {
|
||||||
it('returns 0 if there are no contacts', () => {
|
it('returns 0 if there are no contacts', () => {
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
|
|
|
@ -35,6 +35,19 @@ describe('LeftPaneComposeHelper', () => {
|
||||||
sinonSandbox.restore();
|
sinonSandbox.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('getBackAction', () => {
|
||||||
|
it('returns the "show inbox" action', () => {
|
||||||
|
const showInbox = sinon.fake();
|
||||||
|
const helper = new LeftPaneComposeHelper({
|
||||||
|
composeContacts: [],
|
||||||
|
regionCode: 'US',
|
||||||
|
searchTerm: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(helper.getBackAction({ showInbox }), showInbox);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('getRowCount', () => {
|
describe('getRowCount', () => {
|
||||||
it('returns 1 (for the "new group" button) if not searching and there are no contacts', () => {
|
it('returns 1 (for the "new group" button) if not searching and there are no contacts', () => {
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import { assert } from 'chai';
|
import { assert } from 'chai';
|
||||||
|
import * as sinon from 'sinon';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { RowType } from '../../../components/ConversationList';
|
import { RowType } from '../../../components/ConversationList';
|
||||||
import { FindDirection } from '../../../components/leftPane/LeftPaneHelper';
|
import { FindDirection } from '../../../components/leftPane/LeftPaneHelper';
|
||||||
|
@ -15,6 +16,24 @@ describe('LeftPaneInboxHelper', () => {
|
||||||
type: 'direct' as const,
|
type: 'direct' as const,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('getBackAction', () => {
|
||||||
|
it("returns undefined; you can't go back from the main inbox", () => {
|
||||||
|
const helper = new LeftPaneInboxHelper({
|
||||||
|
conversations: [],
|
||||||
|
pinnedConversations: [],
|
||||||
|
archivedConversations: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.isUndefined(
|
||||||
|
helper.getBackAction({
|
||||||
|
showChooseGroupMembers: sinon.fake(),
|
||||||
|
showInbox: sinon.fake(),
|
||||||
|
startComposing: sinon.fake(),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('getRowCount', () => {
|
describe('getRowCount', () => {
|
||||||
it('returns 0 if there are no conversations', () => {
|
it('returns 0 if there are no conversations', () => {
|
||||||
const helper = new LeftPaneInboxHelper({
|
const helper = new LeftPaneInboxHelper({
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import { assert } from 'chai';
|
import { assert } from 'chai';
|
||||||
|
import * as sinon from 'sinon';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { RowType } from '../../../components/ConversationList';
|
import { RowType } from '../../../components/ConversationList';
|
||||||
|
|
||||||
|
@ -19,6 +20,25 @@ describe('LeftPaneSearchHelper', () => {
|
||||||
conversationId: uuid(),
|
conversationId: uuid(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('getBackAction', () => {
|
||||||
|
it('returns undefined; going back is handled elsewhere in the app', () => {
|
||||||
|
const helper = new LeftPaneSearchHelper({
|
||||||
|
conversationResults: { isLoading: false, results: [] },
|
||||||
|
contactResults: { isLoading: false, results: [] },
|
||||||
|
messageResults: { isLoading: false, results: [] },
|
||||||
|
searchTerm: 'foo',
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.isUndefined(
|
||||||
|
helper.getBackAction({
|
||||||
|
showChooseGroupMembers: sinon.fake(),
|
||||||
|
showInbox: sinon.fake(),
|
||||||
|
startComposing: sinon.fake(),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('getRowCount', () => {
|
describe('getRowCount', () => {
|
||||||
it('returns 0 when there are no search results', () => {
|
it('returns 0 when there are no search results', () => {
|
||||||
const helper = new LeftPaneSearchHelper({
|
const helper = new LeftPaneSearchHelper({
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import { assert } from 'chai';
|
import { assert } from 'chai';
|
||||||
|
import * as sinon from 'sinon';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { RowType } from '../../../components/ConversationList';
|
import { RowType } from '../../../components/ConversationList';
|
||||||
|
|
||||||
|
@ -14,6 +15,38 @@ describe('LeftPaneSetGroupMetadataHelper', () => {
|
||||||
type: 'direct' as const,
|
type: 'direct' as const,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('getBackAction', () => {
|
||||||
|
it('returns the "show composer" action if a request is not active', () => {
|
||||||
|
const showChooseGroupMembers = sinon.fake();
|
||||||
|
const helper = new LeftPaneSetGroupMetadataHelper({
|
||||||
|
groupAvatar: undefined,
|
||||||
|
groupName: '',
|
||||||
|
hasError: false,
|
||||||
|
isCreating: false,
|
||||||
|
selectedContacts: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(
|
||||||
|
helper.getBackAction({ showChooseGroupMembers }),
|
||||||
|
showChooseGroupMembers
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns undefined (i.e., you can't go back) if a request is active", () => {
|
||||||
|
const helper = new LeftPaneSetGroupMetadataHelper({
|
||||||
|
groupAvatar: undefined,
|
||||||
|
groupName: 'Foo Bar',
|
||||||
|
hasError: false,
|
||||||
|
isCreating: true,
|
||||||
|
selectedContacts: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.isUndefined(
|
||||||
|
helper.getBackAction({ showChooseGroupMembers: sinon.fake() })
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('getRowCount', () => {
|
describe('getRowCount', () => {
|
||||||
it('returns 0 if there are no contacts', () => {
|
it('returns 0 if there are no contacts', () => {
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
|
|
Loading…
Reference in a new issue