Web Lab 2: smooth Instructions ↔ AI Tutor tab transition#73282
Draft
breville wants to merge 3 commits into
Draft
Web Lab 2: smooth Instructions ↔ AI Tutor tab transition#73282breville wants to merge 3 commits into
breville wants to merge 3 commits into
Conversation
The Instructions and AI Tutor tabs both render the level's instructions, so
crossfading the two tab panels re-faded instructions that were already visible.
Render a single persistent AiTutorChatWithInstructionDrawer instance shared by
both tabs instead: the instructions element stays mounted and only resizes,
while the chat and the Hide/Show Instructions toggle fade and slide in.
- ResourcePanel renders one shared drawer panel covering both tabs, driven by
aiTutorActive = (currentTab === AiTutor). Other tabs keep the opacity
crossfade on .tabContent.
- The drawer height, chat, and toggle transition (height/opacity/top);
suppressed mid-drag and under prefers-reduced-motion.
- The chat is laid out at a fixed, bottom-anchored height (chatContentHeight)
and revealed by an animating clip window, so it is unveiled in place rather
than reflowing/sliding under the toggle.
- focus({preventScroll}) when focusing tab content, so auto-focusing the chat
input no longer scrolls the panel up for a frame on entering the AI Tutor tab.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
# Conflicts: # apps/src/lab2/views/components/Instructions/ResourcePanel/AiTutorChatWithInstructionsDrawer/AiTutorChatWithInstructionDrawer.tsx
…open Staging now defaults the AI Tutor instructions drawer to collapsed, so the default Instructions <-> AI Tutor switch is full-instructions <-> chat-only. Animating that morph looked bad: the chat grew in, and switching back remounted the instructions and replayed their slide-in. Gate the animation on drawer state instead. - animateLayout = !isCollapsed || <within close-settle window>; when the drawer is settled closed, an .instant class drops the height/opacity/top transitions so tab switches are instant (nothing grows or slides). Open-drawer switches and the open/close toggle still animate. - Keep the instructions drawer mounted even when hidden (height 0, padding 0, inert) instead of unmounting it, so switching tabs never remounts it and replays the instructions' slidein keyframe. - Drive the hidden drawer/toggle to height/top 0 synchronously (drawerHeight) rather than the effect-driven instructionsHeight, which lagged a frame and flashed the full-height drawer for one frame on switching to a closed tab. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Background
In weblab2, the info panel has separate Instructions and AI Tutor tabs. Both can show the level's instructions; the AI Tutor tab shows the instructions in a collapsible drawer above the chat. Because each tab rendered its own copy of the instructions and switching swapped the two panels, the transition was rough — instructions that were visible on both tabs would re-fade, the chat would grow in, and the instructions would replay their slide-in animation as if remounting.
This PR makes switching feel stable: nothing moves when it shouldn't, and the one case that benefits from motion — switching while the instructions drawer is open — animates smoothly.
What changed (user-visible)
prefers-reduced-motion.Video
weblab2-instructions-tutor-animation-1.mov
How it works
AiTutorChatWithInstructionDrawerinstance (driven byaiTutorActive = currentTab === Tabs.AiTutor) instead of each rendering its own instructions, so the instructions element never crossfades — it only resizes.inert), so switching tabs never remounts it and replays the instructions'slideinkeyframe.animateLayout = !isCollapsed || <within the close-settle window>. When the drawer is settled closed, an.instantclass drops the height/opacity/top transitions so tab switches are instant.instructionsHeight, which lagged a frame and briefly flashed the full-height drawer).focus({preventScroll: true})when focusing tab content, so auto-focusing the chat input no longer scrolls the panel up for a frame.chatContentHeight) and revealed by an animating clip window rather than reflowing.Scope
Gated to the weblab2 instructions-drawer case (
hasInstructionsDrawer && aiTutorVisible && longInstructions). Other tabs/labs are unaffected; they keep the existing opacity crossfade on.tabContent.Notes
staging, which defaults the AI Tutor drawer to collapsed and the initial weblab2 tab to Instructions; this PR's behavior is built on top of that. The merge reconciled staging'sAiTutorChatWithInstructionDrawerrefactor (removedisCollapsedByDefault, addedinitialWelcomeMessage) with this work.Testing
slideindoes not replay (margin/opacity stable), height is correct immediately (no slide).yarn typecheck, eslint, stylelint, and the pre-commit hook pass.🤖 Generated with Claude Code