@assistant-ui/react 0.15.23 → 0.15.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (212) hide show
  1. package/README.md +44 -23
  2. package/dist/assistant-transport.js.map +1 -1
  3. package/dist/cloud-renderer/CloudRendererHost.js.map +1 -1
  4. package/dist/context/providers/MessageProvider.js.map +1 -1
  5. package/dist/context/providers/ThreadViewportProvider.js.map +1 -1
  6. package/dist/hooks/useToolCallElapsed.d.ts +3 -1
  7. package/dist/hooks/useToolCallElapsed.d.ts.map +1 -1
  8. package/dist/hooks/useToolCallElapsed.js +7 -8
  9. package/dist/hooks/useToolCallElapsed.js.map +1 -1
  10. package/dist/index.d.ts +10 -4
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +3 -3
  13. package/dist/legacy-runtime/AssistantRuntimeProvider.js.map +1 -1
  14. package/dist/mcp-apps/app-frame.js.map +1 -1
  15. package/dist/model-context/frame/useAssistantFrameHost.js.map +1 -1
  16. package/dist/model-context/makeAssistantVisible.d.ts +1 -0
  17. package/dist/model-context/makeAssistantVisible.d.ts.map +1 -1
  18. package/dist/model-context/makeAssistantVisible.js +31 -12
  19. package/dist/model-context/makeAssistantVisible.js.map +1 -1
  20. package/dist/primitives/actionBar/ActionBarCopy.js.map +1 -1
  21. package/dist/primitives/actionBar/ActionBarEdit.js.map +1 -1
  22. package/dist/primitives/actionBar/ActionBarExportMarkdown.js.map +1 -1
  23. package/dist/primitives/actionBar/ActionBarFeedbackNegative.js.map +1 -1
  24. package/dist/primitives/actionBar/ActionBarFeedbackPositive.js.map +1 -1
  25. package/dist/primitives/actionBar/ActionBarReload.js.map +1 -1
  26. package/dist/primitives/actionBar/ActionBarRoot.js.map +1 -1
  27. package/dist/primitives/actionBar/ActionBarSpeak.js.map +1 -1
  28. package/dist/primitives/actionBar/ActionBarStopSpeaking.js.map +1 -1
  29. package/dist/primitives/actionBar/useActionBarFloatStatus.js.map +1 -1
  30. package/dist/primitives/actionBarMore/ActionBarMoreContent.js.map +1 -1
  31. package/dist/primitives/actionBarMore/ActionBarMoreItem.js.map +1 -1
  32. package/dist/primitives/actionBarMore/ActionBarMoreRoot.js.map +1 -1
  33. package/dist/primitives/actionBarMore/ActionBarMoreSeparator.js.map +1 -1
  34. package/dist/primitives/actionBarMore/ActionBarMoreTrigger.js.map +1 -1
  35. package/dist/primitives/actionBarMore/scope.js.map +1 -1
  36. package/dist/primitives/assistantModal/AssistantModalAnchor.js.map +1 -1
  37. package/dist/primitives/assistantModal/AssistantModalContent.js.map +1 -1
  38. package/dist/primitives/assistantModal/AssistantModalRoot.js.map +1 -1
  39. package/dist/primitives/assistantModal/AssistantModalTrigger.js.map +1 -1
  40. package/dist/primitives/assistantModal/popoverRenderPrimitives.js.map +1 -1
  41. package/dist/primitives/assistantModal/scope.js.map +1 -1
  42. package/dist/primitives/attachment/AttachmentName.js.map +1 -1
  43. package/dist/primitives/attachment/AttachmentRemove.js.map +1 -1
  44. package/dist/primitives/attachment/AttachmentRoot.js.map +1 -1
  45. package/dist/primitives/attachment/AttachmentThumb.js.map +1 -1
  46. package/dist/primitives/branchPicker/BranchPickerCount.js.map +1 -1
  47. package/dist/primitives/branchPicker/BranchPickerNext.js.map +1 -1
  48. package/dist/primitives/branchPicker/BranchPickerNumber.js.map +1 -1
  49. package/dist/primitives/branchPicker/BranchPickerPrevious.js.map +1 -1
  50. package/dist/primitives/branchPicker/BranchPickerRoot.js.map +1 -1
  51. package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.js.map +1 -1
  52. package/dist/primitives/chainOfThought/ChainOfThoughtRoot.js.map +1 -1
  53. package/dist/primitives/composer/ComposerAddAttachment.js.map +1 -1
  54. package/dist/primitives/composer/ComposerCancel.js.map +1 -1
  55. package/dist/primitives/composer/ComposerDictate.js.map +1 -1
  56. package/dist/primitives/composer/ComposerDictationTranscript.js.map +1 -1
  57. package/dist/primitives/composer/ComposerInput.d.ts +1 -1
  58. package/dist/primitives/composer/ComposerInput.d.ts.map +1 -1
  59. package/dist/primitives/composer/ComposerInput.js +4 -3
  60. package/dist/primitives/composer/ComposerInput.js.map +1 -1
  61. package/dist/primitives/composer/ComposerInputPluginContext.js.map +1 -1
  62. package/dist/primitives/composer/ComposerQuote.js.map +1 -1
  63. package/dist/primitives/composer/ComposerRoot.js.map +1 -1
  64. package/dist/primitives/composer/ComposerSend.js.map +1 -1
  65. package/dist/primitives/composer/ComposerStopDictation.js.map +1 -1
  66. package/dist/primitives/composer/trigger/TriggerPopover.d.ts +11 -11
  67. package/dist/primitives/composer/trigger/TriggerPopover.d.ts.map +1 -1
  68. package/dist/primitives/composer/trigger/TriggerPopover.js +62 -60
  69. package/dist/primitives/composer/trigger/TriggerPopover.js.map +1 -1
  70. package/dist/primitives/composer/trigger/TriggerPopoverAction.d.ts +8 -8
  71. package/dist/primitives/composer/trigger/TriggerPopoverAction.d.ts.map +1 -1
  72. package/dist/primitives/composer/trigger/TriggerPopoverAction.js +6 -6
  73. package/dist/primitives/composer/trigger/TriggerPopoverAction.js.map +1 -1
  74. package/dist/primitives/composer/trigger/TriggerPopoverBack.js.map +1 -1
  75. package/dist/primitives/composer/trigger/TriggerPopoverCategories.d.ts +3 -3
  76. package/dist/primitives/composer/trigger/TriggerPopoverCategories.d.ts.map +1 -1
  77. package/dist/primitives/composer/trigger/TriggerPopoverCategories.js.map +1 -1
  78. package/dist/primitives/composer/trigger/TriggerPopoverDirective.d.ts +9 -9
  79. package/dist/primitives/composer/trigger/TriggerPopoverDirective.d.ts.map +1 -1
  80. package/dist/primitives/composer/trigger/TriggerPopoverDirective.js +7 -7
  81. package/dist/primitives/composer/trigger/TriggerPopoverDirective.js.map +1 -1
  82. package/dist/primitives/composer/trigger/TriggerPopoverItems.d.ts +5 -5
  83. package/dist/primitives/composer/trigger/TriggerPopoverItems.d.ts.map +1 -1
  84. package/dist/primitives/composer/trigger/TriggerPopoverItems.js.map +1 -1
  85. package/dist/primitives/composer/trigger/TriggerPopoverResource.js.map +1 -1
  86. package/dist/primitives/composer/trigger/TriggerPopoverRootContext.d.ts +8 -8
  87. package/dist/primitives/composer/trigger/TriggerPopoverRootContext.js +8 -8
  88. package/dist/primitives/composer/trigger/TriggerPopoverRootContext.js.map +1 -1
  89. package/dist/primitives/composer/trigger/index.d.ts +1 -1
  90. package/dist/primitives/composer/trigger/index.js.map +1 -1
  91. package/dist/primitives/composer/trigger/triggerDetectionResource.js.map +1 -1
  92. package/dist/primitives/composer/trigger/triggerKeyboardResource.js.map +1 -1
  93. package/dist/primitives/composer/trigger/triggerNavigationResource.js.map +1 -1
  94. package/dist/primitives/composer/trigger/triggerSelectionResource.js.map +1 -1
  95. package/dist/primitives/composer/useComposerInputState.js.map +1 -1
  96. package/dist/primitives/composer.d.ts +20 -1
  97. package/dist/primitives/composer.d.ts.map +1 -1
  98. package/dist/primitives/composer.js +8 -1
  99. package/dist/primitives/composer.js.map +1 -1
  100. package/dist/primitives/dropdownMenuRenderPrimitives.js.map +1 -1
  101. package/dist/primitives/error/ErrorMessage.js.map +1 -1
  102. package/dist/primitives/error/ErrorRoot.js.map +1 -1
  103. package/dist/primitives/message/MessageIf.js.map +1 -1
  104. package/dist/primitives/message/MessageParts.js.map +1 -1
  105. package/dist/primitives/message/MessagePartsGrouped.d.ts.map +1 -1
  106. package/dist/primitives/message/MessagePartsGrouped.js +42 -17
  107. package/dist/primitives/message/MessagePartsGrouped.js.map +1 -1
  108. package/dist/primitives/message/MessageRoot.js.map +1 -1
  109. package/dist/primitives/messagePart/MessagePartImage.js.map +1 -1
  110. package/dist/primitives/queueItem/QueueItemRemove.js.map +1 -1
  111. package/dist/primitives/queueItem/QueueItemSteer.js.map +1 -1
  112. package/dist/primitives/queueItem/QueueItemText.js.map +1 -1
  113. package/dist/primitives/reasoning/useScrollLock.js.map +1 -1
  114. package/dist/primitives/selectionToolbar/SelectionToolbarQuote.js.map +1 -1
  115. package/dist/primitives/selectionToolbar/SelectionToolbarRoot.js.map +1 -1
  116. package/dist/primitives/suggestion/SuggestionDescription.js.map +1 -1
  117. package/dist/primitives/suggestion/SuggestionTitle.js.map +1 -1
  118. package/dist/primitives/suggestion/SuggestionTrigger.js.map +1 -1
  119. package/dist/primitives/thread/ThreadIf.js.map +1 -1
  120. package/dist/primitives/thread/ThreadLoadEarlier.d.ts +19 -0
  121. package/dist/primitives/thread/ThreadLoadEarlier.d.ts.map +1 -0
  122. package/dist/primitives/thread/ThreadLoadEarlier.js +36 -0
  123. package/dist/primitives/thread/ThreadLoadEarlier.js.map +1 -0
  124. package/dist/primitives/thread/ThreadMessages.d.ts +1 -1
  125. package/dist/primitives/thread/ThreadMessages.d.ts.map +1 -1
  126. package/dist/primitives/thread/ThreadMessages.js +2 -2
  127. package/dist/primitives/thread/ThreadRoot.d.ts.map +1 -1
  128. package/dist/primitives/thread/ThreadRoot.js +2 -0
  129. package/dist/primitives/thread/ThreadRoot.js.map +1 -1
  130. package/dist/primitives/thread/ThreadScrollToBottom.js.map +1 -1
  131. package/dist/primitives/thread/ThreadSuggestion.js.map +1 -1
  132. package/dist/primitives/thread/ThreadViewport.js.map +1 -1
  133. package/dist/primitives/thread/ThreadViewportFooter.js.map +1 -1
  134. package/dist/primitives/thread/topAnchor/useTopAnchorReserve.js.map +1 -1
  135. package/dist/primitives/thread/useThreadViewportAutoScroll.d.ts.map +1 -1
  136. package/dist/primitives/thread/useThreadViewportAutoScroll.js +111 -2
  137. package/dist/primitives/thread/useThreadViewportAutoScroll.js.map +1 -1
  138. package/dist/primitives/thread.d.ts +2 -0
  139. package/dist/primitives/thread.d.ts.map +1 -1
  140. package/dist/primitives/thread.js +5 -2
  141. package/dist/primitives/thread.js.map +1 -1
  142. package/dist/primitives/threadList/ThreadListLoadMore.js.map +1 -1
  143. package/dist/primitives/threadList/ThreadListNew.js.map +1 -1
  144. package/dist/primitives/threadList/ThreadListRoot.js.map +1 -1
  145. package/dist/primitives/threadListItem/ThreadListItemArchive.js.map +1 -1
  146. package/dist/primitives/threadListItem/ThreadListItemDelete.js.map +1 -1
  147. package/dist/primitives/threadListItem/ThreadListItemRoot.js.map +1 -1
  148. package/dist/primitives/threadListItem/ThreadListItemTrigger.js.map +1 -1
  149. package/dist/primitives/threadListItem/ThreadListItemUnarchive.js.map +1 -1
  150. package/dist/primitives/threadListItemMore/ThreadListItemMoreContent.js.map +1 -1
  151. package/dist/primitives/threadListItemMore/ThreadListItemMoreItem.js.map +1 -1
  152. package/dist/primitives/threadListItemMore/ThreadListItemMoreRoot.js.map +1 -1
  153. package/dist/primitives/threadListItemMore/ThreadListItemMoreSeparator.js.map +1 -1
  154. package/dist/primitives/threadListItemMore/ThreadListItemMoreTrigger.js.map +1 -1
  155. package/dist/primitives/threadListItemMore/scope.js.map +1 -1
  156. package/dist/sandbox-host/SandboxHost.d.ts.map +1 -1
  157. package/dist/sandbox-host/SandboxHost.js +6 -1
  158. package/dist/sandbox-host/SandboxHost.js.map +1 -1
  159. package/dist/unstable/useMessageStallDetection.d.ts.map +1 -1
  160. package/dist/unstable/useMessageStallDetection.js +10 -6
  161. package/dist/unstable/useMessageStallDetection.js.map +1 -1
  162. package/dist/unstable/useModelContextSnapshot.js.map +1 -1
  163. package/dist/unstable/webmcp/WebMcpRegistrationResource.js.map +1 -1
  164. package/dist/unstable/webmcp/useWebMcpProvider.js.map +1 -1
  165. package/dist/utils/Primitive.js.map +1 -1
  166. package/dist/utils/createActionButton.js.map +1 -1
  167. package/dist/utils/hooks/useManagedRef.js.map +1 -1
  168. package/dist/utils/hooks/useMediaQuery.js.map +1 -1
  169. package/dist/utils/hooks/useOnResizeContent.js.map +1 -1
  170. package/dist/utils/hooks/useOnScrollToBottom.js.map +1 -1
  171. package/dist/utils/hooks/useSizeHandle.js.map +1 -1
  172. package/dist/utils/isCompositionKey.d.ts +2 -0
  173. package/dist/utils/isCompositionKey.d.ts.map +1 -0
  174. package/dist/utils/isCompositionKey.js +6 -0
  175. package/dist/utils/isCompositionKey.js.map +1 -0
  176. package/dist/utils/smooth/SmoothContext.js.map +1 -1
  177. package/dist/utils/smooth/useSmooth.js +6 -6
  178. package/dist/utils/smooth/useSmooth.js.map +1 -1
  179. package/package.json +12 -11
  180. package/src/hooks/useToolCallElapsed.test.tsx +35 -0
  181. package/src/hooks/useToolCallElapsed.ts +9 -7
  182. package/src/index.ts +28 -3
  183. package/src/model-context/makeAssistantVisible.test.tsx +315 -5
  184. package/src/model-context/makeAssistantVisible.tsx +43 -7
  185. package/src/primitives/composer/ComposerInput.test.tsx +33 -1
  186. package/src/primitives/composer/ComposerInput.tsx +4 -3
  187. package/src/primitives/composer/trigger/TriggerPopover.tsx +11 -11
  188. package/src/primitives/composer/trigger/TriggerPopoverAction.tsx +10 -13
  189. package/src/primitives/composer/trigger/TriggerPopoverCategories.tsx +2 -2
  190. package/src/primitives/composer/trigger/TriggerPopoverDirective.tsx +11 -14
  191. package/src/primitives/composer/trigger/TriggerPopoverExports.test.ts +61 -0
  192. package/src/primitives/composer/trigger/TriggerPopoverItems.tsx +3 -3
  193. package/src/primitives/composer/trigger/TriggerPopoverRootContext.tsx +8 -8
  194. package/src/primitives/composer.ts +21 -1
  195. package/src/primitives/message/MessagePartsGrouped.test.tsx +271 -1
  196. package/src/primitives/message/MessagePartsGrouped.tsx +14 -6
  197. package/src/primitives/message/MessageRoot.test.tsx +125 -2
  198. package/src/primitives/thread/ThreadLoadEarlier.tsx +35 -0
  199. package/src/primitives/thread/ThreadMessages.tsx +1 -0
  200. package/src/primitives/thread/ThreadRoot.test.tsx +33 -0
  201. package/src/primitives/thread/ThreadRoot.tsx +3 -0
  202. package/src/primitives/thread/useThreadViewportAutoScroll.test.tsx +256 -5
  203. package/src/primitives/thread/useThreadViewportAutoScroll.ts +147 -1
  204. package/src/primitives/thread.ts +2 -0
  205. package/src/sandbox-host/SandboxHost.test.tsx +34 -0
  206. package/src/sandbox-host/SandboxHost.tsx +8 -4
  207. package/src/tests/toolCallTiming.test.tsx +19 -2
  208. package/src/unstable/useMessageStallDetection.test.tsx +40 -0
  209. package/src/unstable/useMessageStallDetection.ts +10 -6
  210. package/src/utils/isCompositionKey.ts +5 -0
  211. package/src/utils/smooth/useSmooth.test.tsx +16 -5
  212. package/src/utils/smooth/useSmooth.ts +7 -7
@@ -0,0 +1,40 @@
1
+ // @vitest-environment jsdom
2
+
3
+ import { renderToString } from "react-dom/server";
4
+ import { afterEach, describe, expect, it, vi } from "vitest";
5
+
6
+ const { message } = vi.hoisted(() => ({
7
+ message: {
8
+ status: { type: "running" as const },
9
+ content: [{ type: "text" as const, text: "streaming" }],
10
+ },
11
+ }));
12
+
13
+ vi.mock("@assistant-ui/store", async (importOriginal) => ({
14
+ ...(await importOriginal<typeof import("@assistant-ui/store")>()),
15
+ useAuiState: (selector: (state: { message: typeof message }) => unknown) =>
16
+ selector({ message }),
17
+ }));
18
+
19
+ vi.mock("@assistant-ui/store/internal", async (importOriginal) => ({
20
+ ...(await importOriginal<typeof import("@assistant-ui/store/internal")>()),
21
+ useShallowSelector: <T,>(selector: T) => selector,
22
+ }));
23
+
24
+ import { unstable_useMessageStallDetection } from "./useMessageStallDetection";
25
+
26
+ describe("unstable_useMessageStallDetection", () => {
27
+ afterEach(() => {
28
+ vi.restoreAllMocks();
29
+ });
30
+
31
+ it("does not read the wall clock during server render", () => {
32
+ const nowSpy = vi.spyOn(Date, "now");
33
+ const Probe = () => (
34
+ <span>{String(unstable_useMessageStallDetection().stalled)}</span>
35
+ );
36
+
37
+ expect(renderToString(<Probe />)).toBe("<span>false</span>");
38
+ expect(nowSpy).not.toHaveBeenCalled();
39
+ });
40
+ });
@@ -57,9 +57,9 @@ export function unstable_useMessageStallDetection(
57
57
  );
58
58
 
59
59
  const running = activity[0] === true;
60
- const lastActivityRef = useRef(Date.now());
60
+ const lastActivityRef = useRef(0);
61
61
  const [stalled, setStalled] = useState(false);
62
- const [, setTick] = useState(0);
62
+ const [now, setNow] = useState(0);
63
63
 
64
64
  useEffect(() => {
65
65
  if (!running) return undefined;
@@ -73,26 +73,30 @@ export function unstable_useMessageStallDetection(
73
73
  return undefined;
74
74
  }
75
75
 
76
+ const stall = () => {
77
+ setNow(Date.now());
78
+ setStalled(true);
79
+ };
76
80
  const sinceActivity = Date.now() - lastActivityRef.current;
77
81
  if (sinceActivity >= thresholdMs) {
78
- setStalled(true);
82
+ stall();
79
83
  return undefined;
80
84
  }
81
85
 
82
86
  setStalled(false);
83
- const id = setTimeout(() => setStalled(true), thresholdMs - sinceActivity);
87
+ const id = setTimeout(stall, thresholdMs - sinceActivity);
84
88
  return () => clearTimeout(id);
85
89
  }, [running, activity, thresholdMs]);
86
90
 
87
91
  useEffect(() => {
88
92
  if (!stalled) return undefined;
89
- const id = setInterval(() => setTick((t) => t + 1), 1000);
93
+ const id = setInterval(() => setNow(Date.now()), 1000);
90
94
  return () => clearInterval(id);
91
95
  }, [stalled]);
92
96
 
93
97
  if (!stalled) return { stalled: false, stalledForMs: 0 };
94
98
  return {
95
99
  stalled: true,
96
- stalledForMs: Math.max(0, Date.now() - lastActivityRef.current),
100
+ stalledForMs: Math.max(0, now - lastActivityRef.current),
97
101
  };
98
102
  }
@@ -0,0 +1,5 @@
1
+ // A keydown that ends an IME composition can arrive after compositionend with
2
+ // isComposing false and keyCode 229, as the Enter that commits one does in
3
+ // Safari.
4
+ export const isCompositionKey = (event: KeyboardEvent) =>
5
+ event.isComposing || event.keyCode === 229;
@@ -1,5 +1,6 @@
1
1
  /** @vitest-environment jsdom */
2
2
  import { act, renderHook } from "@testing-library/react";
3
+ import { renderToString } from "react-dom/server";
3
4
  import { afterEach, describe, expect, it, vi } from "vitest";
4
5
  import type {
5
6
  MessagePartState,
@@ -68,7 +69,7 @@ const driveAndCount = (minCommitMs: number) => {
68
69
  .spyOn(globalThis, "cancelAnimationFrame")
69
70
  .mockImplementation(() => {});
70
71
  let now = 1000;
71
- const nowSpy = vi.spyOn(Date, "now").mockImplementation(() => now);
72
+ const nowSpy = vi.spyOn(performance, "now").mockImplementation(() => now);
72
73
 
73
74
  const state = runningState("0123456789");
74
75
  const { result, unmount } = renderHook(() =>
@@ -105,6 +106,16 @@ describe("useSmooth", () => {
105
106
  Reflect.deleteProperty(window, "matchMedia");
106
107
  });
107
108
 
109
+ it("does not read the wall clock during server render", () => {
110
+ const nowSpy = vi.spyOn(Date, "now");
111
+ const Probe = () => (
112
+ <span>{useSmooth(runningState("streaming"), true).text}</span>
113
+ );
114
+
115
+ expect(renderToString(<Probe />)).toBe("<span></span>");
116
+ expect(nowSpy).not.toHaveBeenCalled();
117
+ });
118
+
108
119
  it("returns the input state unchanged when disabled", () => {
109
120
  const state = textState("hello");
110
121
  const { result } = renderHook(() => useSmooth(state, false));
@@ -189,8 +200,8 @@ describe("useSmooth", () => {
189
200
  return raf.length;
190
201
  });
191
202
  vi.spyOn(globalThis, "cancelAnimationFrame").mockImplementation(() => {});
192
- let now = 1_000_000;
193
- vi.spyOn(Date, "now").mockImplementation(() => now);
203
+ let now = 0;
204
+ vi.spyOn(performance, "now").mockImplementation(() => now);
194
205
 
195
206
  const frame = () => {
196
207
  if (raf.length === 0) return;
@@ -246,7 +257,7 @@ describe("useSmooth", () => {
246
257
  });
247
258
  vi.spyOn(globalThis, "cancelAnimationFrame").mockImplementation(() => {});
248
259
  let now = 1000;
249
- vi.spyOn(Date, "now").mockImplementation(() => now);
260
+ vi.spyOn(performance, "now").mockImplementation(() => now);
250
261
 
251
262
  const frame = () => {
252
263
  if (raf.length === 0) return;
@@ -297,7 +308,7 @@ describe("useSmooth", () => {
297
308
  });
298
309
  vi.spyOn(globalThis, "cancelAnimationFrame").mockImplementation(() => {});
299
310
  let now = 1000;
300
- vi.spyOn(Date, "now").mockImplementation(() => now);
311
+ vi.spyOn(performance, "now").mockImplementation(() => now);
301
312
 
302
313
  const frame = () => {
303
314
  if (raf.length === 0) return;
@@ -49,8 +49,8 @@ const DEFAULT_MAX_CHAR_INTERVAL_MS = 5;
49
49
 
50
50
  class TextStreamAnimator {
51
51
  private animationFrameId: number | null = null;
52
- private lastUpdateTime: number = Date.now();
53
- public lastCommitTime: number = 0;
52
+ private lastUpdateTime: number = 0;
53
+ public lastCommitTime: number = -Infinity;
54
54
 
55
55
  public targetText: string = "";
56
56
  public drainMs: number = DEFAULT_DRAIN_MS;
@@ -68,7 +68,7 @@ class TextStreamAnimator {
68
68
 
69
69
  start() {
70
70
  if (this.animationFrameId !== null) return;
71
- this.lastUpdateTime = Date.now();
71
+ this.lastUpdateTime = performance.now();
72
72
  this.animate();
73
73
  }
74
74
 
@@ -80,7 +80,7 @@ class TextStreamAnimator {
80
80
  }
81
81
 
82
82
  private animate = () => {
83
- const currentTime = Date.now();
83
+ const currentTime = performance.now();
84
84
  const deltaTime = currentTime - this.lastUpdateTime;
85
85
  let timeToConsume = deltaTime;
86
86
 
@@ -214,8 +214,8 @@ export const useSmooth = (
214
214
  }
215
215
  }, [smoothStatusStore, enabled, text, displayedText, state.status]);
216
216
 
217
- const [animatorRef] = useState<TextStreamAnimator>(
218
- new TextStreamAnimator(displayedText, setText),
217
+ const [animatorRef] = useState(
218
+ () => new TextStreamAnimator(displayedText, setText),
219
219
  );
220
220
 
221
221
  useEffect(() => {
@@ -240,7 +240,7 @@ export const useSmooth = (
240
240
  if (state.status.type === "running") {
241
241
  animatorRef.currentText = "";
242
242
  animatorRef.targetText = text;
243
- animatorRef.lastCommitTime = 0;
243
+ animatorRef.lastCommitTime = -Infinity;
244
244
  animatorRef.start();
245
245
  } else {
246
246
  animatorRef.currentText = text;