mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-08-04 14:57:42 +00:00
feat(client): add view-transition morph helper for composer surfaces
Wrap a state update in startViewTransition (with a synchronous flush) so elements sharing a view-transition-name animate their position, size and shape between two states instead of swapping. The composer band gets its own named, opaque snapshot group stacked above the morphing element: without it a surface travelling between the thread and the composer paints over the input and bleeds through the strip below it. Falls back to a plain update where the API is unavailable and for reduced-motion users.
This commit is contained in:
parent
db34b7163b
commit
8320943ba5
4 changed files with 42 additions and 1 deletions
|
|
@ -126,9 +126,14 @@ function ChatView({ index = 0, project }: { index?: number; project?: TChatProje
|
|||
)}
|
||||
>
|
||||
{content}
|
||||
{/* Named + opaque so a view transition (the ask_user_question
|
||||
popover ⇄ chat-card morph) paints the whole composer band
|
||||
over the travelling card instead of letting it show
|
||||
through below the composer. The background matches the
|
||||
page, so normal rendering is unchanged. */}
|
||||
<div
|
||||
className={cn(
|
||||
'w-full',
|
||||
'w-full bg-presentation [view-transition-name:chat-form]',
|
||||
isLandingPage && 'max-w-3xl transition-all duration-200 xl:max-w-4xl',
|
||||
)}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -3027,3 +3027,17 @@ html {
|
|||
.sharepoint-picker-bg {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/* ask_user_question popover <-> chat-card morph (view transition) */
|
||||
::view-transition-group(ask-question),
|
||||
::view-transition-old(ask-question),
|
||||
::view-transition-new(ask-question) {
|
||||
animation-duration: 280ms;
|
||||
animation-timing-function: cubic-bezier(0.32, 0.72, 0.22, 1);
|
||||
}
|
||||
|
||||
/* The composer keeps its own snapshot group stacked above the morphing
|
||||
question card, so the card travels behind the ChatForm, not over it. */
|
||||
::view-transition-group(chat-form) {
|
||||
z-index: 2;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ export * from './share';
|
|||
export * from './files';
|
||||
export * from './latex';
|
||||
export * from './tilde';
|
||||
export * from './morph';
|
||||
export * from './forms';
|
||||
export * from './roles';
|
||||
export * from './errors';
|
||||
|
|
|
|||
21
client/src/utils/morph.ts
Normal file
21
client/src/utils/morph.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { flushSync } from 'react-dom';
|
||||
|
||||
/**
|
||||
* Runs a state update inside a same-document view transition when supported,
|
||||
* so elements sharing a `view-transition-name` morph (position, size, shape)
|
||||
* between the two states instead of swapping. Falls back to applying the
|
||||
* update directly. Call from user-event handlers only: the update is flushed
|
||||
* synchronously so the browser can snapshot the old and new layouts.
|
||||
*/
|
||||
export function morphTransition(update: () => void): void {
|
||||
if (
|
||||
typeof document.startViewTransition !== 'function' ||
|
||||
window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
||||
) {
|
||||
update();
|
||||
return;
|
||||
}
|
||||
document.startViewTransition(() => {
|
||||
flushSync(update);
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue