mirror of https://github.com/buster-so/buster.git
update animation lifecycle
This commit is contained in:
parent
d437535d50
commit
a2ae1b8b38
|
@ -0,0 +1,27 @@
|
|||
import React, { createContext, useContext } from 'react';
|
||||
|
||||
interface AnimationContextValue {
|
||||
shouldStopAnimations: boolean;
|
||||
}
|
||||
|
||||
const AnimationContext = createContext<AnimationContextValue | undefined>(undefined);
|
||||
|
||||
export const AnimationProvider: React.FC<{
|
||||
children: React.ReactNode;
|
||||
shouldStopAnimations: boolean;
|
||||
}> = ({ children, shouldStopAnimations }) => {
|
||||
return (
|
||||
<AnimationContext.Provider value={{ shouldStopAnimations }}>
|
||||
{children}
|
||||
</AnimationContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useAnimationContext = () => {
|
||||
const context = useContext(AnimationContext);
|
||||
if (!context) {
|
||||
// Return default value if context is not provided
|
||||
return { shouldStopAnimations: false };
|
||||
}
|
||||
return context;
|
||||
};
|
|
@ -4,15 +4,7 @@ import { animateTokenizedText, createAnimationStyle } from './animation-helpers'
|
|||
import { cva } from 'class-variance-authority';
|
||||
import { StreamingMessageCode } from '../../../streaming/StreamingMessageCode';
|
||||
import { cn } from '@/lib/classMerge';
|
||||
|
||||
// Create a context to track list item state
|
||||
const ListItemContext = React.createContext<{
|
||||
isInListItem: boolean;
|
||||
initialHadParagraph: boolean | null;
|
||||
}>({
|
||||
isInListItem: false,
|
||||
initialHadParagraph: null
|
||||
});
|
||||
import { useAnimationContext, AnimationProvider } from './AnimationContext';
|
||||
|
||||
type MarkdownComponentProps = {
|
||||
children: React.ReactNode;
|
||||
|
@ -35,17 +27,14 @@ export const ParagraphComponent: React.FC<MarkdownComponentProps> = ({
|
|||
style,
|
||||
...rest
|
||||
}) => {
|
||||
const listItemContext = React.useContext(ListItemContext);
|
||||
|
||||
// If we're in a list item that started without paragraphs, don't render the p tag
|
||||
if (listItemContext.isInListItem && listItemContext.initialHadParagraph === false) {
|
||||
// Return children directly without the p tag wrapper
|
||||
return <>{animateTokenizedText(children, rest)}</>;
|
||||
}
|
||||
const { shouldStopAnimations } = useAnimationContext();
|
||||
|
||||
return (
|
||||
<p style={style} className={className} data-testid="paragraph-component">
|
||||
{animateTokenizedText(children, rest)}
|
||||
{animateTokenizedText(children, {
|
||||
...rest,
|
||||
animation: shouldStopAnimations ? 'none' : rest.animation
|
||||
})}
|
||||
</p>
|
||||
);
|
||||
};
|
||||
|
@ -263,21 +252,36 @@ export const ListItemComponent: React.FC<MarkdownComponentProps> = ({
|
|||
style,
|
||||
...rest
|
||||
}) => {
|
||||
return (
|
||||
<li
|
||||
style={style}
|
||||
className={cn(
|
||||
className,
|
||||
const numberOfChildren = React.Children.count(children);
|
||||
const stopAnimations = React.useRef(false);
|
||||
const previousChildrenLength = React.useRef(numberOfChildren);
|
||||
|
||||
'[&_span]:inline',
|
||||
// // Normal text flow
|
||||
'whitespace-normal',
|
||||
// Fix alignment of content
|
||||
'[&>span]:inline [&>span]:align-top',
|
||||
'[&>p]:inline [&>p]:align-top'
|
||||
)}>
|
||||
{animateTokenizedText(children, rest)}
|
||||
</li>
|
||||
const numberOfChildrenIsLessThanPrevious = numberOfChildren < previousChildrenLength.current;
|
||||
previousChildrenLength.current = numberOfChildren;
|
||||
|
||||
if (numberOfChildrenIsLessThanPrevious) {
|
||||
stopAnimations.current = true;
|
||||
}
|
||||
|
||||
return (
|
||||
<AnimationProvider shouldStopAnimations={stopAnimations.current}>
|
||||
<li
|
||||
style={style}
|
||||
className={cn(
|
||||
className,
|
||||
'[&_span]:inline',
|
||||
// // Normal text flow
|
||||
'whitespace-normal',
|
||||
// Fix alignment of content
|
||||
'[&>span]:inline [&>span]:align-top',
|
||||
'[&>p]:inline [&>p]:align-top'
|
||||
)}>
|
||||
{animateTokenizedText(children, {
|
||||
...rest,
|
||||
animation: stopAnimations.current ? 'none' : rest.animation
|
||||
})}
|
||||
</li>
|
||||
</AnimationProvider>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ const TokenizedText: React.FC<TokenizedTextProps> = React.memo(
|
|||
{chunk}
|
||||
</span>
|
||||
),
|
||||
[animationStyle]
|
||||
[animationStyle, doNotAnimateInitialText]
|
||||
);
|
||||
|
||||
const content = useMemo(() => {
|
||||
|
|
|
@ -16,7 +16,8 @@ export type MarkdownAnimation =
|
|||
| 'typewriter'
|
||||
| 'highlight'
|
||||
| 'blurAndSharpen'
|
||||
| 'dropIn';
|
||||
| 'dropIn'
|
||||
| 'none';
|
||||
|
||||
export type MarkdownAnimationTimingFunction = 'ease-in-out' | 'ease-out' | 'ease-in' | 'linear';
|
||||
|
||||
|
@ -34,7 +35,8 @@ export const animations: Record<MarkdownAnimation, string> = {
|
|||
typewriter: 'buster-typewriter',
|
||||
highlight: 'buster-highlight',
|
||||
blurAndSharpen: 'buster-blurAndSharpen',
|
||||
dropIn: 'buster-dropIn'
|
||||
dropIn: 'buster-dropIn',
|
||||
none: 'none'
|
||||
};
|
||||
|
||||
interface AnimationStyleProps {
|
||||
|
@ -50,11 +52,12 @@ export const createAnimationStyle = ({
|
|||
animationTimingFunction = 'ease-in-out',
|
||||
isStreamFinished = true
|
||||
}: AnimationStyleProps) => {
|
||||
if (animation === 'none' || isStreamFinished) {
|
||||
return { animation: 'none' };
|
||||
}
|
||||
|
||||
return {
|
||||
animation:
|
||||
animation && !isStreamFinished
|
||||
? `${animations[animation]} ${animationDuration}ms ${animationTimingFunction}`
|
||||
: 'none'
|
||||
animation: `${animations[animation]} ${animationDuration}ms ${animationTimingFunction}`
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -115,7 +118,6 @@ export const animateTokenizedText = (
|
|||
data-testid="other-markdown-element"
|
||||
style={{
|
||||
...createAnimationStyle(animationsProps),
|
||||
animationIterationCount: 1,
|
||||
whiteSpace: 'pre-wrap',
|
||||
display: isInlineElement ? 'inline' : 'inline-block'
|
||||
}}>
|
||||
|
@ -129,7 +131,6 @@ export const animateTokenizedText = (
|
|||
data-testid="animated-markdown-element"
|
||||
style={{
|
||||
...createAnimationStyle(animationsProps),
|
||||
animationIterationCount: 1,
|
||||
whiteSpace: 'pre-wrap',
|
||||
display: 'inline'
|
||||
}}>
|
||||
|
|
Loading…
Reference in New Issue