Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/channels.md
Original file line number Diff line number Diff line change
Expand Up @@ -1709,7 +1709,8 @@ Escape and Option+Arrow for the shell.
conversation is not among the rows, next starts from the top and previous from the
bottom. A conversation listed in two sections is stepped over once. The shortcuts
are unavailable, leaving the key alone, while the sidebar renders no rows (for
example behind another page's own sidebar). Stepping activates the row's own
example behind another page's own sidebar) or focus is in a text field outside the
composer, which keeps Option+Arrow for editing. Stepping activates the row's own
button, so it takes the exact path of a click: the saved selection, navigation
intent, session staleness guard and Solo's immediate activation. The list scrolls
just far enough to show the row, and nothing above it moves.
Expand Down
14 changes: 14 additions & 0 deletions src/bundled/channels/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,20 @@ it("steps only while the sidebar renders rows, and not from a terminal", () => {
expect(next.when()).toBe(false);
});

it("stays available in the message composer but not in other text fields", () => {
const next = registered().get("next-conversation");
sidebar("a", "*b", "c");
document.body.insertAdjacentHTML(
"beforeend",
`<textarea aria-label="Canvas Markdown"></textarea>
<form data-composer-surface=""><div role="textbox" tabindex="0"></div></form>`,
);
document.querySelector<HTMLElement>("textarea")?.focus();
expect(next.when()).toBe(false);
document.querySelector<HTMLElement>('[role="textbox"]')?.focus();
expect(next.when()).toBe(true);
});

it("registers a plain Escape that waits for an open conversation to mark read", () => {
const shortcut = registered().get("mark-read");
expect(shortcut).toMatchObject({
Expand Down
11 changes: 8 additions & 3 deletions src/bundled/channels/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { isApplePlatform } from "../../features/shortcuts/format";
import type { ArchiveShortcut, ReadShortcut } from "./ChannelsPage";
import {
conversationRows,
inFieldOutsideComposer,
inTerminal,
stepConversation,
} from "./conversation-rows";
Expand Down Expand Up @@ -72,8 +73,9 @@ export const apply: PluginModule["apply"] = (ctx) => {
when: () => !!archive.current?.available(),
run: () => archive.current?.run(),
});
// Slack's sidebar stepping. Terminals keep Option+Arrow, and stepping is
// unavailable (the key is left alone) while the sidebar renders no rows.
// Slack's sidebar stepping. Terminals and text fields outside the composer
// keep Option+Arrow, and stepping is unavailable (the key is left alone)
// while the sidebar renders no rows.
const stepping = [
["previous-conversation", "Previous conversation", "ArrowUp", false, 30],
["next-conversation", "Next conversation", "ArrowDown", false, 31],
Expand All @@ -99,7 +101,10 @@ export const apply: PluginModule["apply"] = (ctx) => {
binding: { key, alt: true, shift: unreadOnly },
order,
allowInEditable: true,
when: () => !inTerminal() && conversationRows().length > 0,
when: () =>
!inTerminal() &&
!inFieldOutsideComposer() &&
conversationRows().length > 0,
run: () =>
stepConversation(key === "ArrowUp" ? "previous" : "next", unreadOnly),
});
Expand Down
Loading