From 3edfdbe198d1c7f9d32f37fbf0e0cdbca0a913be Mon Sep 17 00:00:00 2001 From: maria-rcks Date: Fri, 30 Oct 2026 04:47:46 +0000 Subject: [PATCH] revert(web): remove the composer rich text toggle button and mod+/ shortcut Reverts #26777 and its follow-up #27375. Rich text stays switchable from Settings -> Chat -> Rich text composer. --- apps/web/src/components/chat/ChatComposer.tsx | 28 +------------ .../chat/ComposerRichTextToggle.tsx | 41 ------------------- .../src/components/chat/composerShortcuts.ts | 6 --- apps/web/src/keybindings.test.ts | 11 +---- docs/user/composer.md | 4 +- docs/user/keybindings.md | 1 - packages/contracts/src/keybindings.ts | 1 - packages/shared/src/keybindings.ts | 1 - 8 files changed, 3 insertions(+), 90 deletions(-) delete mode 100644 apps/web/src/components/chat/ComposerRichTextToggle.tsx diff --git a/apps/web/src/components/chat/ChatComposer.tsx b/apps/web/src/components/chat/ChatComposer.tsx index 56c73bcec16a6..d7878cc29a165 100644 --- a/apps/web/src/components/chat/ChatComposer.tsx +++ b/apps/web/src/components/chat/ChatComposer.tsx @@ -133,7 +133,6 @@ import { import { attachmentUploadBlockReason } from "../../lib/attachmentUploadState"; import type { AssistantCitationSourceAnchor } from "~/lib/assistantTextSelection"; import { shortcutLabelForCommand } from "../../keybindings"; -import { persistClientSettingsUpdate } from "../../hooks/useSettings"; import { type TerminalContextDraft, type TerminalContextSelection, @@ -199,7 +198,6 @@ import { ComposerRestingImagePreviews, } from "./ComposerAttachmentStrip"; import { ComposerPrimaryActions } from "./ComposerPrimaryActions"; -import { ComposerRichTextToggle } from "./ComposerRichTextToggle"; import { ComposerFooterPrimaryActions } from "./ComposerFooterControls"; import { ComposerPendingUserInputPanel } from "./ComposerPendingUserInputPanel"; import { ComposerPlanFollowUpBanner } from "./ComposerPlanFollowUpBanner"; @@ -306,7 +304,6 @@ export interface ChatComposerHandle { openModelPicker: () => void; stepReasoningEffort: (direction: 1 | -1) => void; toggleModelPicker: () => void; - toggleRichText: () => void; openControl: (command: KeybindingCommand) => void; isModelPickerOpen: () => boolean; isCaretAtStart: () => boolean; @@ -2855,13 +2852,6 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps) openModelPickerStable(); } }, - toggleRichText: () => { - if (isLiteralPendingAnswer) return; - persistClientSettingsUpdate((current) => ({ - ...current, - composerRichTextEnabled: !current.composerRichTextEnabled, - })).catch(console.error); - }, openControl: (command) => { if (composerBlurFrameRef.current !== null) { window.cancelAnimationFrame(composerBlurFrameRef.current); @@ -3439,23 +3429,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps) showMobilePendingAnswerActions && "hidden sm:flex", )} > - {composerAttachButton || !isLiteralPendingAnswer ? ( -
- {composerAttachButton} - {isLiteralPendingAnswer ? null : ( - - )} -
- ) : null} + {composerAttachButton ?
{composerAttachButton}
: null}
- event.preventDefault()} - onClick={() => void updateClientSettings({ composerRichTextEnabled: showingSource })} - /> - } - > - - - - {showingSource ? "Show formatting" : "Show Markdown source"} - {shortcutLabel ? ` · ${shortcutLabel}` : null} - - - ); -} diff --git a/apps/web/src/components/chat/composerShortcuts.ts b/apps/web/src/components/chat/composerShortcuts.ts index e55398996cea9..30beb9771968f 100644 --- a/apps/web/src/components/chat/composerShortcuts.ts +++ b/apps/web/src/components/chat/composerShortcuts.ts @@ -18,12 +18,6 @@ export function composerShortcutCommands( "modelPicker.toggle": ({ event }) => { if (!event.repeat) composerRef.current?.toggleModelPicker(); }, - "composer.toggleRichText": ({ event }) => { - // The flip remounts the editor, which would drop an unsaved citation comment. - if (event.target instanceof Element && event.target.closest("[data-citation-comment-editor]")) - return false; - if (!event.repeat) composerRef.current?.toggleRichText(); - }, "composer.increaseEffort": ({ event }) => { if (!event.repeat) composerRef.current?.stepReasoningEffort(1); }, diff --git a/apps/web/src/keybindings.test.ts b/apps/web/src/keybindings.test.ts index 96ae09296dea5..a0ba7fa7ee043 100644 --- a/apps/web/src/keybindings.test.ts +++ b/apps/web/src/keybindings.test.ts @@ -768,21 +768,12 @@ describe("composer and pull request shortcuts", () => { }); it.each(["MacIntel", "Win32", "Linux"])( - "resolves composer toggle and alternate send chords in their contexts on %s", + "reserves the alternate send chord for the focused composer on %s", (platform) => { const modifier = { metaKey: platform === "MacIntel", ctrlKey: platform !== "MacIntel", }; - for (const terminalFocus of [false, true]) { - assert.strictEqual( - resolveShortcutCommand(event({ key: "/", ...modifier }), DEFAULT_RESOLVED_KEYBINDINGS, { - platform, - context: { terminalFocus }, - }), - terminalFocus ? null : "composer.toggleRichText", - ); - } const shiftedEnter = event({ key: "Enter", shiftKey: true, ...modifier }); for (const composerRequiresModifier of [false, true]) { const context = { diff --git a/docs/user/composer.md b/docs/user/composer.md index 6156a126ca246..714572dfd5005 100644 --- a/docs/user/composer.md +++ b/docs/user/composer.md @@ -19,9 +19,7 @@ The composer writes Markdown and shows it styled as you type. Markers such as them. Lines starting with `- `, `1. `, `- [ ] `, `> `, `# ` or `---` become lists, task lists, quotes, headings and rules; ` ``` ` followed by Enter opens a code block. What you typed is what the agent receives, markers and numbering -included, and `#1234` without a space still looks up a pull request. To see the -plain Markdown instead, press the **¶** button beside attach; it is the same -switch as **Settings → Chat → Rich text composer**. +included, and `#1234` without a space still looks up a pull request. Enter sends. In a list or quote, **Shift+Enter** continues it, and Shift+Enter on an empty line moves out one level, then leaves it; **Tab** nests a list item diff --git a/docs/user/keybindings.md b/docs/user/keybindings.md index 0e8e17744019e..83989762c5b07 100644 --- a/docs/user/keybindings.md +++ b/docs/user/keybindings.md @@ -28,7 +28,6 @@ Use `mod+shift+e` for effort, `mod+shift+a` for permissions, `mod+shift+x` for t workspace, and `mod+shift+g` for the Git branch. The workspace menu includes the current checkout, a new worktree, and the previous worktree when available. Use `mod+shift+l` to reuse the previous worktree directly. -Use `mod+/` to switch the composer between rich text and its Markdown source. To change effort one step without opening the picker, bind **Composer: Increase Effort** and **Composer: Decrease Effort** in Keybindings. diff --git a/packages/contracts/src/keybindings.ts b/packages/contracts/src/keybindings.ts index cc55adb9ca81b..714e0a1d486a1 100644 --- a/packages/contracts/src/keybindings.ts +++ b/packages/contracts/src/keybindings.ts @@ -87,7 +87,6 @@ export const STATIC_KEYBINDING_COMMANDS = [ "appearance.cycle", "themeEditor.toggle", "composer.stash", - "composer.toggleRichText", "composer.sendAlternate", "composer.sendBackground", "composer.sendAndNewThread", diff --git a/packages/shared/src/keybindings.ts b/packages/shared/src/keybindings.ts index 8ae3f052afede..32292c0f9ef21 100644 --- a/packages/shared/src/keybindings.ts +++ b/packages/shared/src/keybindings.ts @@ -179,7 +179,6 @@ export const DEFAULT_KEYBINDINGS: ReadonlyArray = [ { key: "mod+alt+shift+a", command: "appearance.cycle", when: "!terminalFocus" }, { key: "mod+alt+shift+t", command: "themeEditor.toggle" }, { key: "mod+s", command: "composer.stash", when: "!terminalFocus" }, - { key: "mod+/", command: "composer.toggleRichText", when: "!terminalFocus" }, { key: "mod+shift+enter", command: "thread.steerQueuedMessage", when: "!terminalFocus" }, { key: "alt+arrowup", command: "thread.editQueuedMessage", when: "composerFocus" }, { key: "mod+enter", command: "composer.sendAlternate", when: "composerFocus && turnRunning" },