@assistant-ui/react
Version:
Typescript/React library for AI Chat
138 lines (137 loc) • 4.81 kB
JavaScript
"use client";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/utils/smooth/useSmooth.tsx
var useSmooth_exports = {};
__export(useSmooth_exports, {
useSmooth: () => useSmooth
});
module.exports = __toCommonJS(useSmooth_exports);
var import_react = require("react");
var import_context = require("../../context/index.js");
var import_react_use_callback_ref = require("@radix-ui/react-use-callback-ref");
var import_SmoothContext = require("./SmoothContext.js");
var import_ReadonlyStore = require("../../context/ReadonlyStore.js");
var TextStreamAnimator = class {
constructor(currentText, setText) {
this.currentText = currentText;
this.setText = setText;
}
animationFrameId = null;
lastUpdateTime = Date.now();
targetText = "";
start() {
if (this.animationFrameId !== null) return;
this.lastUpdateTime = Date.now();
this.animate();
}
stop() {
if (this.animationFrameId !== null) {
cancelAnimationFrame(this.animationFrameId);
this.animationFrameId = null;
}
}
animate = () => {
const currentTime = Date.now();
const deltaTime = currentTime - this.lastUpdateTime;
let timeToConsume = deltaTime;
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;
}
if (charsToAdd !== remainingChars) {
this.animationFrameId = requestAnimationFrame(this.animate);
} 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);
};
};
var SMOOTH_STATUS = Object.freeze({
type: "running"
});
var useSmooth = (state, smooth = false) => {
const { text } = state;
const id = (0, import_context.useMessage)({
optional: true,
selector: (m) => m.id
});
const idRef = (0, import_react.useRef)(id);
const [displayedText, setDisplayedText] = (0, import_react.useState)(text);
const smoothStatusStore = (0, import_SmoothContext.useSmoothStatusStore)({ optional: true });
const setText = (0, import_react_use_callback_ref.useCallbackRef)((text2) => {
setDisplayedText(text2);
if (smoothStatusStore) {
const target = displayedText !== text2 || state.status.type === "running" ? SMOOTH_STATUS : state.status;
(0, import_ReadonlyStore.writableStore)(smoothStatusStore).setState(target, true);
}
});
(0, import_react.useEffect)(() => {
if (smoothStatusStore) {
const target = displayedText !== text || state.status.type === "running" ? SMOOTH_STATUS : state.status;
(0, import_ReadonlyStore.writableStore)(smoothStatusStore).setState(target, true);
}
}, [smoothStatusStore, text, displayedText, state.status]);
const [animatorRef] = (0, import_react.useState)(
new TextStreamAnimator(text, setText)
);
(0, import_react.useEffect)(() => {
if (!smooth) {
animatorRef.stop();
return;
}
if (idRef.current !== id || !text.startsWith(animatorRef.targetText)) {
idRef.current = id;
setText(text);
animatorRef.currentText = text;
animatorRef.targetText = text;
animatorRef.stop();
return;
}
animatorRef.targetText = text;
animatorRef.start();
}, [setText, animatorRef, id, smooth, text]);
(0, import_react.useEffect)(() => {
return () => {
animatorRef.stop();
};
}, [animatorRef]);
return (0, import_react.useMemo)(
() => smooth ? {
type: "text",
text: displayedText,
status: text === displayedText ? state.status : SMOOTH_STATUS
} : state,
[smooth, displayedText, state, text]
);
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
useSmooth
});
//# sourceMappingURL=useSmooth.js.map
;