Skip to content

add light animations for editing and todo/editing list#300201

Draft
justschen wants to merge 2 commits intomainfrom
justin/karrablast
Draft

add light animations for editing and todo/editing list#300201
justschen wants to merge 2 commits intomainfrom
justin/karrablast

Conversation

@justschen
Copy link
Collaborator

@justschen justschen commented Mar 9, 2026

video incoming sorry github isn't letting me upload

Copilot AI review requested due to automatic review settings March 9, 2026 15:50
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds new UI animations to the chat experience (above-input widgets, todo title flip, and edit bubble expansion) and updates supporting code/types used by the chat workbench.

Changes:

  • Add reveal/collapse and title-flip animations for above-input widgets (todo list, editing list, status/tip widgets, question carousel).
  • Animate the “edit request” input bubble expanding from the original bubble width.
  • Update Monaco type declarations and register a new CSS custom property for stylelint.

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
src/vs/workbench/contrib/chat/browser/widget/media/chat.css Adds new keyframes and classes for above-input reveal/collapse, todo title flip, and edit bubble expansion.
src/vs/workbench/contrib/chat/browser/widget/input/chatStatusWidget.ts Triggers the new reveal animation when the status widget becomes visible.
src/vs/workbench/contrib/chat/browser/widget/input/chatInputPart.ts Triggers reveal/collapse animations for the question carousel and working set list.
src/vs/workbench/contrib/chat/browser/widget/chatWidget.ts Captures bubble width and triggers reveal animation for the getting-started tip.
src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatTodoListWidget.ts Adds todo list expand/collapse animations, title flip animation logic, and shared animation helper functions.
src/vs/monaco.d.ts Tightens types for some editor options (notably placeholder).
build/lib/stylelint/vscode-known-variables.json Adds --chat-edit-bubble-width to the known variables list.
Comments suppressed due to low confidence (3)

src/vs/workbench/contrib/chat/browser/widget/media/chat.css:872

  • The reveal keyframe ends with max-height: 500px. Combined with animation-fill-mode: forwards on the reveal class, this can leave the element permanently capped at 500px (clipping content). Consider restoring max-height after the animation (e.g. removing the reveal class on animationend) or avoiding a fixed max-height in the final keyframe.
	to {
		opacity: 1;
		transform: translateY(0) scale(1);
		max-height: 500px;
	}

src/vs/workbench/contrib/chat/browser/widget/media/chat.css:883

  • Please add a reduced-motion override for these animations. VS Code commonly disables animations under .monaco-workbench.monaco-reduce-motion (see src/vs/workbench/contrib/chat/electron-browser/actions/media/voiceChatActions.css).
	animation: kf-chat-above-input-reveal 350ms cubic-bezier(0.25, 0.8, 0.25, 1) forwards;
	transform-origin: bottom center;

src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatTodoListWidget.ts:505

  • triggerRevealAnimation always leaves the chat-above-input-reveal class on the element. Since the CSS uses animation-fill-mode: forwards and animates max-height, consider removing the reveal class on animationend (or otherwise restoring layout styles) so the element doesn’t remain in an animation-filled state after the transition.
export function triggerRevealAnimation(element: HTMLElement): void {
	element.classList.remove('chat-above-input-reveal');
	element.classList.remove('chat-above-input-collapse');
	void element.offsetWidth; // Force reflow to restart animation
	element.classList.add('chat-above-input-reveal');

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +85 to 86
import { triggerRevealAnimation } from './chatContentParts/chatTodoListWidget.js';
import { ChatContentMarkdownRenderer } from './chatContentMarkdownRenderer.js';
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Importing triggerRevealAnimation from chatTodoListWidget.ts couples the main chat widget to the todo list implementation. Consider moving the animation helpers into a shared utility module and importing from there instead, so changes to the todo widget don’t unintentionally affect other widgets.

Copilot uses AI. Check for mistakes.
import { IChatContentPartRenderContext } from '../chatContentParts/chatContentParts.js';
import { CollapsibleListPool, IChatCollapsibleListItem } from '../chatContentParts/chatReferencesContentPart.js';
import { ChatTodoListWidget } from '../chatContentParts/chatTodoListWidget.js';
import { ChatTodoListWidget, triggerCollapseAnimation, triggerRevealAnimation } from '../chatContentParts/chatTodoListWidget.js';
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

triggerRevealAnimation/triggerCollapseAnimation are imported from chatTodoListWidget.ts, which couples the input part to the todo widget implementation. Since these helpers are now shared by multiple widgets, consider moving them into a small shared utility module to avoid unnecessary dependencies and keep the todo widget file focused.

Copilot uses AI. Check for mistakes.
Comment on lines +881 to +884
.todo-list-container.chat-above-input-reveal {
animation: kf-chat-above-input-reveal 350ms cubic-bezier(0.25, 0.8, 0.25, 1) forwards;
transform-origin: bottom center;
}
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reveal animation animates max-height but the reveal class doesn’t set overflow: hidden/clip, so children can paint outside the shrinking/growing box during the animation (causing overlap). Add an overflow rule for the reveal state if you want the height animation to actually constrain content during the transition.

Copilot uses AI. Check for mistakes.
Comment on lines +887 to +891
from {
opacity: 1;
max-height: 200px;
transform: translateY(0);
}
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kf-chat-above-input-collapse hardcodes max-height: 200px at the start of the animation. If the actual content is taller, it will snap/clip immediately when the collapse starts. Consider using a value that can’t be smaller than the element’s actual height (or setting the start height dynamically).

This issue also appears on line 868 of the same file.

Copilot uses AI. Check for mistakes.
Comment on lines +3270 to +3273
.interactive-request.editing .chat-edit-input-container {
animation: kf-chat-edit-bubble-expand 280ms cubic-bezier(0.32, 1.2, 0.5, 1) forwards;
transform-origin: right center;
}
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kf-chat-edit-bubble-expand should also be disabled when reduced motion is enabled; otherwise users with reduced motion will still get the bubble expansion animation.

This issue also appears on line 882 of the same file.

Copilot uses AI. Check for mistakes.
Comment on lines +19 to 22
import { triggerRevealAnimation } from '../chatContentParts/chatTodoListWidget.js';
import { ChatInputPartWidgetsRegistry, IChatInputPartWidget } from './chatInputPartWidgets.js';
import './media/chatStatusWidget.css';

Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These helpers are imported from chatTodoListWidget.ts, which pulls in the todo widget implementation and its dependencies. Since the animation helpers are now used by multiple unrelated widgets, please move them into a small dedicated module (e.g. chatWidgetAnimations.ts) to avoid unnecessary coupling/bundle cost and to keep the todo widget file focused.

Copilot uses AI. Check for mistakes.
Comment on lines +521 to +525
element.classList.add('chat-above-input-collapse');
element.addEventListener('animationend', () => {
element.style.display = 'none';
element.classList.remove('chat-above-input-collapse');
}, { once: true });
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The animationend handler here will run for any animation that ends on the element. If the element is re-shown (reveal animation started) before the collapse animation ends, this handler can fire on the reveal animation’s animationend and incorrectly set display: none. Guard on AnimationEvent.animationName (or otherwise cancel/remove any pending collapse handler) before hiding.

This issue also appears on line 501 of the same file.

Copilot uses AI. Check for mistakes.
Comment on lines +404 to +408
let exitGhost: HTMLElement | undefined;
if (shouldAnimate) {
exitGhost = dom.$('.todo-title-exit-ghost');
for (const child of Array.from(titleElement.childNodes)) {
exitGhost.appendChild(child.cloneNode(true));
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This clones all existing title children into the exit ghost. If an update happens while a previous .todo-title-exit-ghost is still present, the ghost itself will be cloned and can cause visual artifacts. Consider removing any existing .todo-title-exit-ghost before cloning, or skipping the flip animation while one is in progress.

Copilot uses AI. Check for mistakes.
Comment on lines +1566 to +1570
const bubbleWidth = item.renderedParts?.[0]?.domNode?.offsetWidth;
const bubbleWidthPct = bubbleWidth ? Math.round(bubbleWidth / rowContainer.offsetWidth * 100) : 60;

this.inputContainer = dom.$('.chat-edit-input-container');
this.inputContainer.style.setProperty('--chat-edit-bubble-width', `${bubbleWidthPct}%`);
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bubbleWidthPct divides by rowContainer.offsetWidth without guarding for 0. In cases where the row is not measurable (e.g. temporarily hidden), this can produce Infinity%/NaN% and break the CSS animation. Guard for rowContainer.offsetWidth > 0 before dividing and fall back to the default when it isn’t.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants