Skip to content

Commit

Permalink
fix: useSmooth dev mode lagging (#456)
Browse files Browse the repository at this point in the history
  • Loading branch information
Yonom authored Jul 11, 2024
1 parent 249b0d8 commit 87efa87
Show file tree
Hide file tree
Showing 12 changed files with 308 additions and 72 deletions.
2 changes: 1 addition & 1 deletion apps/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.2",
"@radix-ui/themes": "^3.1.1",
"ai": "^3.2.19",
"ai": "^3.2.22",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"fumadocs-core": "12.4.2",
Expand Down
2 changes: 1 addition & 1 deletion examples/search-agent-for-e-commerce/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"@radix-ui/react-popover": "^1.1.1",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.2",
"ai": "^3.2.19",
"ai": "^3.2.22",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"embla-carousel-autoplay": "^8.1.6",
Expand Down
2 changes: 1 addition & 1 deletion examples/with-inline-suggestions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"@radix-ui/react-avatar": "^1.1.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.2",
"ai": "^3.2.19",
"ai": "^3.2.22",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"lucide-react": "^0.407.0",
Expand Down
4 changes: 2 additions & 2 deletions examples/with-openai-assistants/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
"@assistant-ui/react": "workspace:*",
"@assistant-ui/react-ai-sdk": "workspace:*",
"@radix-ui/react-avatar": "^1.1.0",
"ai": "^3.2.19",
"ai": "^3.2.22",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"lucide-react": "^0.407.0",
"next": "14.2.5",
"openai": "^4.52.5",
"openai": "^4.52.7",
"react": "^18",
"react-dom": "^18",
"tailwind-merge": "^2.4.0",
Expand Down
5 changes: 5 additions & 0 deletions examples/with-playground/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
2 changes: 1 addition & 1 deletion examples/with-vercel-ai-rsc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.2",
"ai": "3.2.19",
"ai": "3.2.22",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"lucide-react": "^0.407.0",
Expand Down
2 changes: 2 additions & 0 deletions packages/react-markdown/src/primitives/MarkdownText.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"use client";

import { INTERNAL, useContentPartText } from "@assistant-ui/react";
import type { ComponentType, FC } from "react";
import ReactMarkdown, { type Options } from "react-markdown";
Expand Down
2 changes: 1 addition & 1 deletion packages/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"conversational-ui",
"conversational-ai"
],
"version": "0.4.0",
"version": "0.4.1",
"license": "MIT",
"exports": {
".": {
Expand Down
2 changes: 2 additions & 0 deletions packages/react/src/primitives/contentPart/ContentPartText.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"use client";

import { Primitive } from "@radix-ui/react-primitive";
import { type ElementRef, forwardRef, ComponentPropsWithoutRef } from "react";
import { useContentPartText } from "../../primitive-hooks/contentPart/useContentPartText";
Expand Down
2 changes: 2 additions & 0 deletions packages/react/src/ui/thread-config.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"use client";

import { FC, PropsWithChildren, createContext, useContext } from "react";

import { AvatarProps } from "./base/avatar";
Expand Down
52 changes: 26 additions & 26 deletions packages/react/src/utils/hooks/useSmooth.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"use client";

import { useEffect, useState } from "react";

class TextStreamAnimator {
Expand All @@ -7,7 +9,8 @@ class TextStreamAnimator {
public targetText: string = "";

constructor(
private setText: (callback: (prevText: string) => string) => void,
public currentText: string,
private setText: (newText: string) => void,
) {}

start() {
Expand All @@ -28,40 +31,35 @@ class TextStreamAnimator {
const deltaTime = currentTime - this.lastUpdateTime;
let timeToConsume = deltaTime;

this.setText((currentText) => {
const targetText = this.targetText;

if (currentText === targetText) {
this.animationFrameId = null;
return currentText;
}

const remainingChars = targetText.length - currentText.length;
const baseTimePerChar = Math.min(5, 250 / remainingChars);
const remainingChars = this.targetText.length - this.currentText.length;
const baseTimePerChar = Math.min(5, 250 / remainingChars);

let charsToAdd = 0;
while (timeToConsume >= baseTimePerChar && charsToAdd < remainingChars) {
charsToAdd++;
timeToConsume -= baseTimePerChar;
}
let charsToAdd = 0;
while (timeToConsume >= baseTimePerChar && charsToAdd < remainingChars) {
charsToAdd++;
timeToConsume -= baseTimePerChar;
}

if (charsToAdd !== remainingChars) {
this.animationFrameId = requestAnimationFrame(this.animate);

if (charsToAdd === 0) {
return currentText;
}

const newText = targetText.slice(0, currentText.length + charsToAdd);
this.lastUpdateTime = currentTime - timeToConsume;
return newText;
});
} else {
this.animationFrameId = null;
}
if (charsToAdd === 0) return;

this.currentText = this.targetText.slice(
0,
this.currentText.length + charsToAdd,
);
this.lastUpdateTime = currentTime - timeToConsume;
this.setText(this.currentText);
};
}

export const useSmooth = (text: string, smooth: boolean = false) => {
const [displayedText, setDisplayedText] = useState(text);
const [animatorRef] = useState<TextStreamAnimator>(
new TextStreamAnimator(setDisplayedText),
new TextStreamAnimator(text, setDisplayedText),
);

useEffect(() => {
Expand All @@ -72,8 +70,10 @@ export const useSmooth = (text: string, smooth: boolean = false) => {

if (!text.startsWith(animatorRef.targetText)) {
setDisplayedText(text);
animatorRef.currentText = text;
animatorRef.targetText = text;
animatorRef.stop();

return;
}

Expand Down
Loading

0 comments on commit 87efa87

Please sign in to comment.