@assistant-ui/react 0.15.15 → 0.15.17
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.
- package/README.md +3 -3
- package/dist/devtools/DevToolsHooks.d.ts +0 -2
- package/dist/devtools/DevToolsHooks.d.ts.map +1 -1
- package/dist/devtools/DevToolsHooks.js +10 -12
- package/dist/devtools/DevToolsHooks.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js +2 -2
- package/dist/mcp-apps/McpAppRenderer.d.ts +6 -1
- package/dist/mcp-apps/McpAppRenderer.d.ts.map +1 -1
- package/dist/mcp-apps/McpAppRenderer.js +20 -13
- package/dist/mcp-apps/McpAppRenderer.js.map +1 -1
- package/dist/mcp-apps/McpAppsRemoteHost.d.ts.map +1 -1
- package/dist/mcp-apps/McpAppsRemoteHost.js +20 -17
- package/dist/mcp-apps/McpAppsRemoteHost.js.map +1 -1
- package/dist/mcp-apps/app-frame.d.ts.map +1 -1
- package/dist/mcp-apps/app-frame.js +189 -94
- package/dist/mcp-apps/app-frame.js.map +1 -1
- package/dist/mcp-apps/bridge.d.ts.map +1 -1
- package/dist/mcp-apps/bridge.js +2 -8
- package/dist/mcp-apps/bridge.js.map +1 -1
- package/dist/mcp-apps/index.d.ts +2 -2
- package/dist/model-context/frame/useAssistantFrameHost.d.ts +1 -1
- package/dist/model-context/frame/useAssistantFrameHost.js +10 -11
- package/dist/model-context/frame/useAssistantFrameHost.js.map +1 -1
- package/dist/model-context/makeAssistantVisible.js +1 -1
- package/dist/model-context/makeAssistantVisible.js.map +1 -1
- package/dist/primitives/actionBar/ActionBarCopy.js +3 -3
- package/dist/primitives/actionBar/ActionBarCopy.js.map +1 -1
- package/dist/primitives/actionBar/ActionBarExportMarkdown.d.ts.map +1 -1
- package/dist/primitives/actionBar/ActionBarExportMarkdown.js +7 -4
- package/dist/primitives/actionBar/ActionBarExportMarkdown.js.map +1 -1
- package/dist/primitives/actionBar/ActionBarFeedbackNegative.js +3 -3
- package/dist/primitives/actionBar/ActionBarFeedbackNegative.js.map +1 -1
- package/dist/primitives/actionBar/ActionBarFeedbackPositive.js +3 -3
- package/dist/primitives/actionBar/ActionBarFeedbackPositive.js.map +1 -1
- package/dist/primitives/actionBar/ActionBarRoot.js.map +1 -1
- package/dist/primitives/actionBar/ActionBarStopSpeaking.js +3 -3
- package/dist/primitives/actionBar/ActionBarStopSpeaking.js.map +1 -1
- package/dist/primitives/actionBarMore/ActionBarMoreContent.js.map +1 -1
- package/dist/primitives/actionBarMore/ActionBarMoreItem.js.map +1 -1
- package/dist/primitives/actionBarMore/ActionBarMoreRoot.js.map +1 -1
- package/dist/primitives/actionBarMore/ActionBarMoreSeparator.js.map +1 -1
- package/dist/primitives/actionBarMore/ActionBarMoreTrigger.js.map +1 -1
- package/dist/primitives/actionBarMore/scope.d.ts +2 -2
- package/dist/primitives/actionBarMore/scope.d.ts.map +1 -1
- package/dist/primitives/actionBarMore/scope.js.map +1 -1
- package/dist/primitives/assistantModal/AssistantModalAnchor.js.map +1 -1
- package/dist/primitives/assistantModal/AssistantModalContent.js +1 -1
- package/dist/primitives/assistantModal/AssistantModalContent.js.map +1 -1
- package/dist/primitives/assistantModal/AssistantModalRoot.js.map +1 -1
- package/dist/primitives/assistantModal/AssistantModalTrigger.js.map +1 -1
- package/dist/primitives/assistantModal/scope.d.ts +2 -2
- package/dist/primitives/assistantModal/scope.d.ts.map +1 -1
- package/dist/primitives/assistantModal/scope.js.map +1 -1
- package/dist/primitives/branchPicker/BranchPickerRoot.d.ts.map +1 -1
- package/dist/primitives/branchPicker/BranchPickerRoot.js +20 -15
- package/dist/primitives/branchPicker/BranchPickerRoot.js.map +1 -1
- package/dist/primitives/composer/ComposerAttachmentDropzone.js +1 -1
- package/dist/primitives/composer/ComposerAttachmentDropzone.js.map +1 -1
- package/dist/primitives/composer/ComposerDictationTranscript.d.ts +2 -2
- package/dist/primitives/composer/ComposerDictationTranscript.js +2 -2
- package/dist/primitives/composer/ComposerDictationTranscript.js.map +1 -1
- package/dist/primitives/composer/ComposerInput.js +1 -3
- package/dist/primitives/composer/ComposerInput.js.map +1 -1
- package/dist/primitives/composer/ComposerQuote.js +5 -5
- package/dist/primitives/composer/ComposerQuote.js.map +1 -1
- package/dist/primitives/composer/ComposerRoot.js +3 -3
- package/dist/primitives/composer/ComposerRoot.js.map +1 -1
- package/dist/primitives/composer/trigger/TriggerPopover.d.ts +5 -0
- package/dist/primitives/composer/trigger/TriggerPopover.d.ts.map +1 -1
- package/dist/primitives/composer/trigger/TriggerPopover.js +157 -130
- package/dist/primitives/composer/trigger/TriggerPopover.js.map +1 -1
- package/dist/primitives/composer/trigger/TriggerPopoverBack.js +3 -3
- package/dist/primitives/composer/trigger/TriggerPopoverBack.js.map +1 -1
- package/dist/primitives/composer/trigger/TriggerPopoverCategories.js +4 -4
- package/dist/primitives/composer/trigger/TriggerPopoverCategories.js.map +1 -1
- package/dist/primitives/composer/trigger/TriggerPopoverItems.js +4 -4
- package/dist/primitives/composer/trigger/TriggerPopoverItems.js.map +1 -1
- package/dist/primitives/composer/trigger/TriggerPopoverResource.d.ts +2 -0
- package/dist/primitives/composer/trigger/TriggerPopoverResource.d.ts.map +1 -1
- package/dist/primitives/composer/trigger/TriggerPopoverResource.js +63 -61
- package/dist/primitives/composer/trigger/TriggerPopoverResource.js.map +1 -1
- package/dist/primitives/composer/trigger/TriggerPopoverRootContext.d.ts +2 -0
- package/dist/primitives/composer/trigger/TriggerPopoverRootContext.d.ts.map +1 -1
- package/dist/primitives/composer/trigger/TriggerPopoverRootContext.js.map +1 -1
- package/dist/primitives/composer/trigger/detectTrigger.d.ts +21 -1
- package/dist/primitives/composer/trigger/detectTrigger.d.ts.map +1 -0
- package/dist/primitives/composer/trigger/detectTrigger.js +17 -3
- package/dist/primitives/composer/trigger/detectTrigger.js.map +1 -1
- package/dist/primitives/composer/trigger/index.d.ts +3 -1
- package/dist/primitives/composer/trigger/index.d.ts.map +1 -1
- package/dist/primitives/composer/trigger/index.js.map +1 -1
- package/dist/primitives/composer/trigger/triggerDetectionResource.d.ts +3 -4
- package/dist/primitives/composer/trigger/triggerDetectionResource.d.ts.map +1 -1
- package/dist/primitives/composer/trigger/triggerDetectionResource.js +15 -14
- package/dist/primitives/composer/trigger/triggerDetectionResource.js.map +1 -1
- package/dist/primitives/composer/trigger/triggerSelectionResource.d.ts.map +1 -1
- package/dist/primitives/composer/trigger/triggerSelectionResource.js +10 -7
- package/dist/primitives/composer/trigger/triggerSelectionResource.js.map +1 -1
- package/dist/primitives/composer.d.ts +3 -2
- package/dist/primitives/composer.js.map +1 -1
- package/dist/primitives/error/ErrorMessage.js.map +1 -1
- package/dist/primitives/message/MessageIf.js.map +1 -1
- package/dist/primitives/message/MessageParts.js.map +1 -1
- package/dist/primitives/message/MessagePartsGrouped.js.map +1 -1
- package/dist/primitives/message/MessageRoot.js +4 -4
- package/dist/primitives/message/MessageRoot.js.map +1 -1
- package/dist/primitives/message.js +1 -1
- package/dist/primitives/messagePart/MessagePartText.js.map +1 -1
- package/dist/primitives/selectionToolbar/SelectionToolbarQuote.js +3 -3
- package/dist/primitives/selectionToolbar/SelectionToolbarQuote.js.map +1 -1
- package/dist/primitives/selectionToolbar/SelectionToolbarRoot.js +3 -3
- package/dist/primitives/selectionToolbar/SelectionToolbarRoot.js.map +1 -1
- package/dist/primitives/thread/ThreadIf.js.map +1 -1
- package/dist/primitives/thread/ThreadRoot.d.ts +3 -0
- package/dist/primitives/thread/ThreadRoot.d.ts.map +1 -1
- package/dist/primitives/thread/ThreadRoot.js +3 -0
- package/dist/primitives/thread/ThreadRoot.js.map +1 -1
- package/dist/primitives/thread/ThreadViewport.js +3 -3
- package/dist/primitives/thread/ThreadViewport.js.map +1 -1
- package/dist/primitives/thread/ThreadViewportFooter.js +3 -3
- package/dist/primitives/thread/ThreadViewportFooter.js.map +1 -1
- package/dist/primitives/thread/useThreadViewportAutoScroll.js +1 -1
- package/dist/primitives/thread/useThreadViewportAutoScroll.js.map +1 -1
- package/dist/primitives/threadList/ThreadListNew.js +3 -3
- package/dist/primitives/threadList/ThreadListNew.js.map +1 -1
- package/dist/primitives/threadListFocusGroup.d.ts +2 -1
- package/dist/primitives/threadListFocusGroup.d.ts.map +1 -1
- package/dist/primitives/threadListFocusGroup.js +2 -2
- package/dist/primitives/threadListFocusGroup.js.map +1 -1
- package/dist/primitives/threadListItem/ThreadListItemRoot.js +3 -3
- package/dist/primitives/threadListItem/ThreadListItemRoot.js.map +1 -1
- package/dist/primitives/threadListItem/ThreadListItemTrigger.js +1 -1
- package/dist/primitives/threadListItem/ThreadListItemTrigger.js.map +1 -1
- package/dist/primitives/threadListItemMore/ThreadListItemMoreContent.js +1 -1
- package/dist/primitives/threadListItemMore/ThreadListItemMoreContent.js.map +1 -1
- package/dist/primitives/threadListItemMore/ThreadListItemMoreItem.js.map +1 -1
- package/dist/primitives/threadListItemMore/ThreadListItemMoreRoot.js +1 -1
- package/dist/primitives/threadListItemMore/ThreadListItemMoreRoot.js.map +1 -1
- package/dist/primitives/threadListItemMore/ThreadListItemMoreSeparator.js.map +1 -1
- package/dist/primitives/threadListItemMore/ThreadListItemMoreTrigger.js +1 -2
- package/dist/primitives/threadListItemMore/ThreadListItemMoreTrigger.js.map +1 -1
- package/dist/primitives/threadListItemMore/scope.d.ts +2 -2
- package/dist/primitives/threadListItemMore/scope.d.ts.map +1 -1
- package/dist/primitives/threadListItemMore/scope.js.map +1 -1
- package/dist/sandbox-host/SandboxHost.d.ts.map +1 -1
- package/dist/sandbox-host/SandboxHost.js +138 -68
- package/dist/sandbox-host/SandboxHost.js.map +1 -1
- package/dist/unstable/useComposerInputHistory.js +1 -1
- package/dist/unstable/useLiveCompletionAdapter.js +3 -1
- package/dist/unstable/useLiveCompletionAdapter.js.map +1 -1
- package/dist/unstable/useSlashCommandAdapter.js +41 -27
- package/dist/unstable/useSlashCommandAdapter.js.map +1 -1
- package/dist/utils/Primitive.d.ts +2 -2
- package/dist/utils/Primitive.js +2 -2
- package/dist/utils/Primitive.js.map +1 -1
- package/dist/utils/createActionButton.js +3 -3
- package/dist/utils/createActionButton.js.map +1 -1
- package/dist/utils/hooks/useOnResizeContent.js +1 -1
- package/dist/utils/hooks/useOnResizeContent.js.map +1 -1
- package/dist/utils/hooks/useOnScrollToBottom.js +1 -1
- package/dist/utils/hooks/useOnScrollToBottom.js.map +1 -1
- package/dist/utils/invokeCallbackSafely.d.ts +5 -0
- package/dist/utils/invokeCallbackSafely.d.ts.map +1 -0
- package/dist/utils/invokeCallbackSafely.js +15 -0
- package/dist/utils/invokeCallbackSafely.js.map +1 -0
- package/dist/utils/smooth/SmoothContext.d.ts +30 -6
- package/dist/utils/smooth/SmoothContext.d.ts.map +1 -1
- package/dist/utils/smooth/useSmooth.d.ts +3 -0
- package/dist/utils/smooth/useSmooth.d.ts.map +1 -1
- package/dist/utils/smooth/useSmooth.js +17 -2
- package/dist/utils/smooth/useSmooth.js.map +1 -1
- package/dist/utils/useToolArgsFieldStatus.d.ts +5 -1
- package/package.json +12 -20
- package/src/devtools/DevToolsHooks.test.ts +40 -0
- package/src/devtools/DevToolsHooks.ts +10 -15
- package/src/index.ts +9 -1
- package/src/mcp-apps/McpAppRenderer.test.tsx +133 -4
- package/src/mcp-apps/McpAppRenderer.tsx +28 -21
- package/src/mcp-apps/McpAppsRemoteHost.concurrent.test.tsx +215 -0
- package/src/mcp-apps/McpAppsRemoteHost.ts +28 -12
- package/src/mcp-apps/app-frame.test.tsx +102 -0
- package/src/mcp-apps/app-frame.tsx +17 -4
- package/src/mcp-apps/bridge.test.ts +21 -0
- package/src/mcp-apps/bridge.ts +2 -14
- package/src/mcp-apps/index.ts +1 -0
- package/src/model-context/frame/AssistantFrame.test.ts +3 -3
- package/src/model-context/frame/SPEC_AssistantFrame.md +1 -1
- package/src/model-context/frame/useAssistantFrameHost.ts +2 -2
- package/src/model-context/makeAssistantVisible.tsx +1 -1
- package/src/primitives/actionBar/ActionBarCopy.tsx +1 -1
- package/src/primitives/actionBar/ActionBarExportMarkdown.test.tsx +67 -0
- package/src/primitives/actionBar/ActionBarExportMarkdown.tsx +4 -2
- package/src/primitives/actionBar/ActionBarFeedbackNegative.tsx +1 -1
- package/src/primitives/actionBar/ActionBarFeedbackPositive.tsx +1 -1
- package/src/primitives/actionBar/ActionBarStopSpeaking.tsx +1 -1
- package/src/primitives/actionBarMore/scope.ts +2 -2
- package/src/primitives/assistantModal/AssistantModalContent.tsx +1 -1
- package/src/primitives/assistantModal/scope.ts +2 -2
- package/src/primitives/branchPicker/BranchPickerRoot.tsx +5 -3
- package/src/primitives/composer/ComposerAttachmentDropzone.tsx +1 -1
- package/src/primitives/composer/ComposerDictationTranscript.tsx +2 -2
- package/src/primitives/composer/ComposerInput.test.tsx +2 -1
- package/src/primitives/composer/ComposerInput.tsx +3 -3
- package/src/primitives/composer/ComposerQuote.tsx +1 -1
- package/src/primitives/composer/ComposerRoot.tsx +1 -1
- package/src/primitives/composer/trigger/TriggerPopover.tsx +16 -1
- package/src/primitives/composer/trigger/TriggerPopoverBack.tsx +1 -1
- package/src/primitives/composer/trigger/TriggerPopoverCategories.tsx +1 -1
- package/src/primitives/composer/trigger/TriggerPopoverItems.tsx +1 -1
- package/src/primitives/composer/trigger/TriggerPopoverResource.ts +4 -1
- package/src/primitives/composer/trigger/TriggerPopoverRootContext.tsx +2 -0
- package/src/primitives/composer/trigger/detectTrigger.test.ts +88 -5
- package/src/primitives/composer/trigger/detectTrigger.ts +50 -9
- package/src/primitives/composer/trigger/index.ts +1 -0
- package/src/primitives/composer/trigger/triggerDetectionResource.ts +10 -7
- package/src/primitives/composer/trigger/triggerSelectionResource.test.ts +147 -0
- package/src/primitives/composer/trigger/triggerSelectionResource.ts +3 -4
- package/src/primitives/composer.ts +1 -0
- package/src/primitives/message/MessageRoot.tsx +1 -1
- package/src/primitives/selectionToolbar/SelectionToolbarQuote.tsx +1 -1
- package/src/primitives/selectionToolbar/SelectionToolbarRoot.tsx +1 -1
- package/src/primitives/thread/ThreadRoot.tsx +3 -0
- package/src/primitives/thread/ThreadViewport.tsx +1 -1
- package/src/primitives/thread/ThreadViewportFooter.tsx +1 -1
- package/src/primitives/thread/useThreadViewportAutoScroll.ts +1 -1
- package/src/primitives/threadList/ThreadListNew.tsx +1 -1
- package/src/primitives/threadListFocusGroup.ts +2 -2
- package/src/primitives/threadListItem/ThreadListItemRoot.tsx +1 -1
- package/src/primitives/threadListItem/ThreadListItemTrigger.tsx +1 -1
- package/src/primitives/threadListItemMore/ThreadListItemMoreContent.tsx +1 -1
- package/src/primitives/threadListItemMore/ThreadListItemMoreRoot.tsx +1 -1
- package/src/primitives/threadListItemMore/ThreadListItemMoreTrigger.tsx +2 -2
- package/src/primitives/threadListItemMore/scope.ts +2 -2
- package/src/sandbox-host/SandboxHost.test.tsx +106 -1
- package/src/sandbox-host/SandboxHost.tsx +22 -5
- package/src/tests/RemoteThreadListRuntime.adapterProvider.test.tsx +31 -1
- package/src/unstable/useLiveCompletionAdapter.test.tsx +117 -1
- package/src/unstable/useLiveCompletionAdapter.ts +4 -1
- package/src/unstable/useSlashCommandAdapter.test.tsx +141 -0
- package/src/unstable/useSlashCommandAdapter.ts +52 -17
- package/src/utils/Primitive.tsx +2 -2
- package/src/utils/createActionButton.tsx +1 -1
- package/src/utils/hooks/useOnResizeContent.ts +1 -1
- package/src/utils/hooks/useOnScrollToBottom.ts +1 -1
- package/src/utils/invokeCallbackSafely.ts +11 -0
- package/src/utils/smooth/useSmooth.test.tsx +110 -0
- package/src/utils/smooth/useSmooth.ts +21 -7
- package/dist/context/react/utils/ensureBinding.d.ts +0 -5
- package/dist/context/react/utils/ensureBinding.d.ts.map +0 -1
- package/dist/context/react/utils/ensureBinding.js +0 -24
- package/dist/context/react/utils/ensureBinding.js.map +0 -1
- package/dist/context/react/utils/useRuntimeState.d.ts +0 -13
- package/dist/context/react/utils/useRuntimeState.d.ts.map +0 -1
- package/dist/context/react/utils/useRuntimeState.js +0 -33
- package/dist/context/react/utils/useRuntimeState.js.map +0 -1
- package/dist/legacy-runtime/runtime/MessagePartRuntime.d.ts +0 -3
- package/dist/legacy-runtime/runtime/MessagePartRuntime.js +0 -2
- package/dist/legacy-runtime/runtime/MessageRuntime.d.ts +0 -3
- package/dist/legacy-runtime/runtime/MessageRuntime.js +0 -2
- package/dist/legacy-runtime/runtime/ThreadListRuntime.d.ts +0 -3
- package/dist/legacy-runtime/runtime/ThreadListRuntime.js +0 -2
- package/src/context/react/utils/ensureBinding.ts +0 -46
- package/src/context/react/utils/useRuntimeState.ts +0 -46
- package/src/legacy-runtime/runtime/MessagePartRuntime.ts +0 -2
- package/src/legacy-runtime/runtime/MessageRuntime.ts +0 -3
- package/src/legacy-runtime/runtime/ThreadListRuntime.ts +0 -4
|
@@ -222,4 +222,114 @@ describe("useSmooth", () => {
|
|
|
222
222
|
frame();
|
|
223
223
|
expect(result.current.text).toBe("z");
|
|
224
224
|
});
|
|
225
|
+
|
|
226
|
+
it("drains completed text when a queued frame never runs", () => {
|
|
227
|
+
vi.spyOn(globalThis, "requestAnimationFrame").mockReturnValue(1);
|
|
228
|
+
vi.spyOn(globalThis, "cancelAnimationFrame").mockImplementation(() => {});
|
|
229
|
+
|
|
230
|
+
const { result, rerender } = renderHook((state) => useSmooth(state, true), {
|
|
231
|
+
initialProps: runningState(""),
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
rerender(runningState("hello"));
|
|
235
|
+
rerender(textState("hello"));
|
|
236
|
+
|
|
237
|
+
expect(result.current.text).toBe("hello");
|
|
238
|
+
expect(result.current.status.type).toBe("complete");
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it("keeps draining after the source settles when frames are flowing", () => {
|
|
242
|
+
const raf: FrameRequestCallback[] = [];
|
|
243
|
+
vi.spyOn(globalThis, "requestAnimationFrame").mockImplementation((cb) => {
|
|
244
|
+
raf.push(cb);
|
|
245
|
+
return raf.length;
|
|
246
|
+
});
|
|
247
|
+
vi.spyOn(globalThis, "cancelAnimationFrame").mockImplementation(() => {});
|
|
248
|
+
let now = 1000;
|
|
249
|
+
vi.spyOn(Date, "now").mockImplementation(() => now);
|
|
250
|
+
|
|
251
|
+
const frame = () => {
|
|
252
|
+
if (raf.length === 0) return;
|
|
253
|
+
const cb = raf.shift()!;
|
|
254
|
+
now += 16;
|
|
255
|
+
act(() => {
|
|
256
|
+
cb(now);
|
|
257
|
+
});
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
const { result, rerender } = renderHook(
|
|
261
|
+
(state) =>
|
|
262
|
+
useSmooth(state, {
|
|
263
|
+
maxCharsPerFrame: 1,
|
|
264
|
+
maxCharIntervalMs: 1,
|
|
265
|
+
drainMs: 250,
|
|
266
|
+
}),
|
|
267
|
+
{ initialProps: runningState("hello") },
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
frame();
|
|
271
|
+
const mid = result.current.text;
|
|
272
|
+
expect(mid.length).toBeGreaterThan(0);
|
|
273
|
+
expect(mid.length).toBeLessThan("hello".length);
|
|
274
|
+
expect(result.current.status.type).toBe("running");
|
|
275
|
+
|
|
276
|
+
rerender(textState("hello"));
|
|
277
|
+
expect(result.current.text).toBe(mid);
|
|
278
|
+
expect(result.current.status.type).toBe("running");
|
|
279
|
+
|
|
280
|
+
frame();
|
|
281
|
+
expect(result.current.text.length).toBeGreaterThan(mid.length);
|
|
282
|
+
|
|
283
|
+
let guard = 0;
|
|
284
|
+
while (result.current.text !== "hello" && guard < 20) {
|
|
285
|
+
guard++;
|
|
286
|
+
frame();
|
|
287
|
+
}
|
|
288
|
+
expect(result.current.text).toBe("hello");
|
|
289
|
+
expect(result.current.status.type).toBe("complete");
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
it("snaps when a settled part replaces the text instead of looping the animator", () => {
|
|
293
|
+
const raf: FrameRequestCallback[] = [];
|
|
294
|
+
vi.spyOn(globalThis, "requestAnimationFrame").mockImplementation((cb) => {
|
|
295
|
+
raf.push(cb);
|
|
296
|
+
return raf.length;
|
|
297
|
+
});
|
|
298
|
+
vi.spyOn(globalThis, "cancelAnimationFrame").mockImplementation(() => {});
|
|
299
|
+
let now = 1000;
|
|
300
|
+
vi.spyOn(Date, "now").mockImplementation(() => now);
|
|
301
|
+
|
|
302
|
+
const frame = () => {
|
|
303
|
+
if (raf.length === 0) return;
|
|
304
|
+
const cb = raf.shift()!;
|
|
305
|
+
now += 16;
|
|
306
|
+
act(() => {
|
|
307
|
+
cb(now);
|
|
308
|
+
});
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
const { result, rerender } = renderHook(
|
|
312
|
+
(state) =>
|
|
313
|
+
useSmooth(state, {
|
|
314
|
+
maxCharsPerFrame: 1,
|
|
315
|
+
maxCharIntervalMs: 1,
|
|
316
|
+
drainMs: 250,
|
|
317
|
+
}),
|
|
318
|
+
{ initialProps: runningState("hello world") },
|
|
319
|
+
);
|
|
320
|
+
|
|
321
|
+
frame();
|
|
322
|
+
expect(result.current.text.length).toBeGreaterThan(0);
|
|
323
|
+
const queued = raf.length;
|
|
324
|
+
|
|
325
|
+
rerender(textState("hi"));
|
|
326
|
+
expect(result.current.text).toBe("hi");
|
|
327
|
+
expect(result.current.status.type).toBe("complete");
|
|
328
|
+
expect(raf.length).toBeLessThanOrEqual(queued);
|
|
329
|
+
|
|
330
|
+
const after = raf.length;
|
|
331
|
+
frame();
|
|
332
|
+
expect(result.current.text).toBe("hi");
|
|
333
|
+
expect(raf.length).toBeLessThanOrEqual(after);
|
|
334
|
+
});
|
|
225
335
|
});
|
|
@@ -8,7 +8,7 @@ import type {
|
|
|
8
8
|
TextMessagePart,
|
|
9
9
|
MessagePartState,
|
|
10
10
|
} from "@assistant-ui/core";
|
|
11
|
-
import { useCallbackRef } from "
|
|
11
|
+
import { useCallbackRef } from "radix-ui/internal";
|
|
12
12
|
import { useMediaQuery } from "../hooks/useMediaQuery";
|
|
13
13
|
import { useSmoothStatusStore } from "./SmoothContext";
|
|
14
14
|
import { writableStore } from "../../context/ReadonlyStore";
|
|
@@ -137,6 +137,9 @@ const positiveOr = (value: number | undefined, fallback: number): number =>
|
|
|
137
137
|
* `true` uses the default rate, and a {@link SmoothOptions} object tunes
|
|
138
138
|
* the reveal. Returns the part state with `text` replaced by the revealed
|
|
139
139
|
* prefix and `status` reporting `running` until the reveal catches up.
|
|
140
|
+
* If the source settles before any character has been revealed, the text
|
|
141
|
+
* is committed immediately so a missed animation frame cannot leave an
|
|
142
|
+
* empty bubble.
|
|
140
143
|
*
|
|
141
144
|
* The reveal auto-disables under `prefers-reduced-motion: reduce`,
|
|
142
145
|
* committing the full text immediately; this takes precedence over an
|
|
@@ -229,13 +232,10 @@ export const useSmooth = (
|
|
|
229
232
|
return;
|
|
230
233
|
}
|
|
231
234
|
|
|
232
|
-
// Discontinuity: part flipped, or new text breaks continuation
|
|
233
|
-
// of the animator's current target. Either case requires
|
|
234
|
-
// resetting the cursor — without the part check, a new part
|
|
235
|
-
// whose text happens to share a prefix with the previous target
|
|
236
|
-
// would keep the stale cursor and flicker.
|
|
237
235
|
const partChanged = animatorPartRef.current !== part;
|
|
238
236
|
animatorPartRef.current = part;
|
|
237
|
+
// A new part whose text shares a prefix with the previous target would
|
|
238
|
+
// keep the stale cursor and flicker without this reset.
|
|
239
239
|
if (partChanged || !text.startsWith(animatorRef.targetText)) {
|
|
240
240
|
if (state.status.type === "running") {
|
|
241
241
|
animatorRef.currentText = "";
|
|
@@ -246,13 +246,27 @@ export const useSmooth = (
|
|
|
246
246
|
animatorRef.currentText = text;
|
|
247
247
|
animatorRef.targetText = text;
|
|
248
248
|
animatorRef.stop();
|
|
249
|
+
setText(text);
|
|
249
250
|
}
|
|
250
251
|
return;
|
|
251
252
|
}
|
|
252
253
|
|
|
253
254
|
animatorRef.targetText = text;
|
|
255
|
+
if (state.status.type !== "running") {
|
|
256
|
+
// No character has painted. A pending frame that never runs would
|
|
257
|
+
// leave an empty bubble after settle.
|
|
258
|
+
if (animatorRef.currentText === "") {
|
|
259
|
+
animatorRef.currentText = text;
|
|
260
|
+
animatorRef.stop();
|
|
261
|
+
setText(text);
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
animatorRef.start();
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
|
|
254
268
|
animatorRef.start();
|
|
255
|
-
}, [animatorRef, enabled, text, state.status.type, part]);
|
|
269
|
+
}, [animatorRef, enabled, text, state.status.type, part, setText]);
|
|
256
270
|
|
|
257
271
|
useEffect(() => {
|
|
258
272
|
return () => {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ensureBinding.d.ts","names":[],"sources":["../../../../src/context/react/utils/ensureBinding.ts"],"mappings":";cAmCa,gBAAiB"}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
//#region src/context/react/utils/ensureBinding.ts
|
|
2
|
-
const debugVerifyPrototype = (runtime, prototype) => {
|
|
3
|
-
const unboundMethods = Object.getOwnPropertyNames(prototype).filter((methodStr) => {
|
|
4
|
-
const descriptor = Object.getOwnPropertyDescriptor(prototype, methodStr);
|
|
5
|
-
const isMethod = descriptor && typeof descriptor.value === "function";
|
|
6
|
-
if (!isMethod) return false;
|
|
7
|
-
const methodName = methodStr;
|
|
8
|
-
return isMethod && !methodName.startsWith("_") && methodName !== "constructor" && prototype[methodName] === runtime[methodName];
|
|
9
|
-
});
|
|
10
|
-
if (unboundMethods.length > 0) throw new Error(`The following methods are not bound: ${JSON.stringify(unboundMethods)}`);
|
|
11
|
-
const prototypePrototype = Object.getPrototypeOf(prototype);
|
|
12
|
-
if (prototypePrototype && prototypePrototype !== Object.prototype) debugVerifyPrototype(runtime, prototypePrototype);
|
|
13
|
-
};
|
|
14
|
-
const ensureBinding = (r) => {
|
|
15
|
-
const runtime = r;
|
|
16
|
-
if (runtime.__isBound) return;
|
|
17
|
-
runtime.__internal_bindMethods?.();
|
|
18
|
-
runtime.__isBound = true;
|
|
19
|
-
if (process.env.NODE_ENV !== "production") debugVerifyPrototype(runtime, Object.getPrototypeOf(runtime));
|
|
20
|
-
};
|
|
21
|
-
//#endregion
|
|
22
|
-
export { ensureBinding };
|
|
23
|
-
|
|
24
|
-
//# sourceMappingURL=ensureBinding.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ensureBinding.js","names":["Bindable","__internal_bindMethods","__isBound","debugVerifyPrototype","runtime","Record","prototype","unboundMethods","Object","getOwnPropertyNames","filter","methodStr","descriptor","getOwnPropertyDescriptor","isMethod","value","methodName","startsWith","length","Error","JSON","stringify","prototypePrototype","getPrototypeOf","ensureBinding","r","process","env","NODE_ENV"],"sources":["../../../../src/context/react/utils/ensureBinding.ts"],"sourcesContent":["type Bindable = {\n __internal_bindMethods?: () => void;\n __isBound?: boolean;\n};\nconst debugVerifyPrototype = (\n runtime: Record<string, unknown>,\n prototype: any,\n) => {\n const unboundMethods = Object.getOwnPropertyNames(prototype).filter(\n (methodStr) => {\n const descriptor = Object.getOwnPropertyDescriptor(prototype, methodStr);\n const isMethod = descriptor && typeof descriptor.value === \"function\";\n if (!isMethod) return false;\n\n const methodName = methodStr as keyof typeof runtime | \"constructor\";\n return (\n isMethod &&\n !methodName.startsWith(\"_\") &&\n methodName !== \"constructor\" &&\n prototype[methodName] === runtime[methodName]\n );\n },\n );\n\n if (unboundMethods.length > 0) {\n throw new Error(\n `The following methods are not bound: ${JSON.stringify(unboundMethods)}`,\n );\n }\n\n const prototypePrototype = Object.getPrototypeOf(prototype);\n if (prototypePrototype && prototypePrototype !== Object.prototype) {\n debugVerifyPrototype(runtime, prototypePrototype);\n }\n};\nexport const ensureBinding = (r: unknown) => {\n const runtime = r as Bindable;\n if (runtime.__isBound) return;\n\n runtime.__internal_bindMethods?.();\n runtime.__isBound = true;\n\n if (process.env.NODE_ENV !== \"production\") {\n debugVerifyPrototype(runtime, Object.getPrototypeOf(runtime));\n }\n};\n"],"mappings":";AAIA,MAAMG,wBACJC,SACAE,cACG;CACH,MAAMC,iBAAiBC,OAAOC,oBAAoBH,SAAS,CAAC,CAACI,QAC1DC,cAAc;EACb,MAAMC,aAAaJ,OAAOK,yBAAyBP,WAAWK,SAAS;EACvE,MAAMG,WAAWF,cAAc,OAAOA,WAAWG,UAAU;EAC3D,IAAI,CAACD,UAAU,OAAO;EAEtB,MAAME,aAAaL;EACnB,OACEG,YACA,CAACE,WAAWC,WAAW,GAAG,KAC1BD,eAAe,iBACfV,UAAUU,gBAAgBZ,QAAQY;CAEtC,CACF;CAEA,IAAIT,eAAeW,SAAS,GAC1B,MAAM,IAAIC,MACR,wCAAwCC,KAAKC,UAAUd,cAAc,GACvE;CAGF,MAAMe,qBAAqBd,OAAOe,eAAejB,SAAS;CAC1D,IAAIgB,sBAAsBA,uBAAuBd,OAAOF,WACtDH,qBAAqBC,SAASkB,kBAAkB;AAEpD;AACA,MAAaE,iBAAiBC,MAAe;CAC3C,MAAMrB,UAAUqB;CAChB,IAAIrB,QAAQF,WAAW;CAEvBE,QAAQH,yBAAyB;CACjCG,QAAQF,YAAY;CAEpB,IAAIwB,QAAQC,IAAIC,aAAa,cAC3BzB,qBAAqBC,SAASI,OAAOe,eAAenB,OAAO,CAAC;AAEhE"}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { Unsubscribe } from "@assistant-ui/core";
|
|
2
|
-
//#region src/context/react/utils/useRuntimeState.d.ts
|
|
3
|
-
type SubscribableRuntime<TState> = {
|
|
4
|
-
getState: () => TState;
|
|
5
|
-
subscribe: (callback: () => void) => Unsubscribe;
|
|
6
|
-
};
|
|
7
|
-
declare function useRuntimeStateInternal<TState, TSelected>(runtime: SubscribableRuntime<TState>, selector?: ((state: TState) => TSelected | TState) | undefined): TSelected | TState;
|
|
8
|
-
declare function useRuntimeState<TState>(runtime: SubscribableRuntime<TState>): TState;
|
|
9
|
-
declare function useRuntimeState<TState, TSelected>(runtime: SubscribableRuntime<TState>, selector: (state: TState) => TSelected): TSelected;
|
|
10
|
-
declare function useRuntimeState<TState, TSelected>(runtime: SubscribableRuntime<TState>, selector: ((state: TState) => TSelected) | undefined): TSelected | TState;
|
|
11
|
-
//#endregion
|
|
12
|
-
export { SubscribableRuntime, useRuntimeState, useRuntimeStateInternal };
|
|
13
|
-
//# sourceMappingURL=useRuntimeState.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useRuntimeState.d.ts","names":[],"sources":["../../../../src/context/react/utils/useRuntimeState.ts"],"mappings":";;KAIY,oBAAoB;EAC9B,gBAAgB;EAChB,YAAY,yBAAyB;;iBAGvB,wBAAwB,QAAQ,WAC9C,SAAS,oBAAoB,SAC7B,aAAY,OAAO,WAAW,YAAY,sBACzC,YAAY;iBAcC,gBAAgB,QAC9B,SAAS,oBAAoB,UAC5B;iBACa,gBAAgB,QAAQ,WACtC,SAAS,oBAAoB,SAC7B,WAAW,OAAO,WAAW,YAC5B;iBACa,gBAAgB,QAAQ,WACtC,SAAS,oBAAoB,SAC7B,YAAY,OAAO,WAAW,yBAC7B,YAAY"}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { ensureBinding } from "./ensureBinding.js";
|
|
2
|
-
import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
|
|
3
|
-
import { useDebugValue, useSyncExternalStore } from "@assistant-ui/tap/react-shim";
|
|
4
|
-
//#region src/context/react/utils/useRuntimeState.ts
|
|
5
|
-
function useRuntimeStateInternal(runtime, t0) {
|
|
6
|
-
const $ = c(4);
|
|
7
|
-
const selector = t0 === void 0 ? identity : t0;
|
|
8
|
-
ensureBinding(runtime);
|
|
9
|
-
let t1;
|
|
10
|
-
let t2;
|
|
11
|
-
if ($[0] !== runtime || $[1] !== selector) {
|
|
12
|
-
t1 = () => selector(runtime.getState());
|
|
13
|
-
t2 = () => selector(runtime.getState());
|
|
14
|
-
$[0] = runtime;
|
|
15
|
-
$[1] = selector;
|
|
16
|
-
$[2] = t1;
|
|
17
|
-
$[3] = t2;
|
|
18
|
-
} else {
|
|
19
|
-
t1 = $[2];
|
|
20
|
-
t2 = $[3];
|
|
21
|
-
}
|
|
22
|
-
const slice = useSyncExternalStore(runtime.subscribe, t1, t2);
|
|
23
|
-
useDebugValue(slice);
|
|
24
|
-
return slice;
|
|
25
|
-
}
|
|
26
|
-
const identity = (arg) => arg;
|
|
27
|
-
function useRuntimeState(runtime, selector) {
|
|
28
|
-
return useRuntimeStateInternal(runtime, selector);
|
|
29
|
-
}
|
|
30
|
-
//#endregion
|
|
31
|
-
export { useRuntimeState, useRuntimeStateInternal };
|
|
32
|
-
|
|
33
|
-
//# sourceMappingURL=useRuntimeState.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useRuntimeState.js","names":["Unsubscribe","useDebugValue","useSyncExternalStore","ensureBinding","SubscribableRuntime","getState","TState","subscribe","callback","useRuntimeStateInternal","runtime","t0","$","_c","selector","undefined","identity","t1","t2","slice","arg","T","useRuntimeState","state","TSelected"],"sources":["../../../../src/context/react/utils/useRuntimeState.ts"],"sourcesContent":["import type { Unsubscribe } from \"@assistant-ui/core\";\nimport { useDebugValue, useSyncExternalStore } from \"react\";\nimport { ensureBinding } from \"./ensureBinding\";\n\nexport type SubscribableRuntime<TState> = {\n getState: () => TState;\n subscribe: (callback: () => void) => Unsubscribe;\n};\n\nexport function useRuntimeStateInternal<TState, TSelected>(\n runtime: SubscribableRuntime<TState>,\n selector: ((state: TState) => TSelected | TState) | undefined = identity,\n): TSelected | TState {\n // TODO move to useRuntimeState\n ensureBinding(runtime);\n\n const slice = useSyncExternalStore(\n runtime.subscribe,\n () => selector(runtime.getState()),\n () => selector(runtime.getState()),\n );\n useDebugValue(slice);\n return slice;\n}\n\nconst identity = <T>(arg: T): T => arg;\nexport function useRuntimeState<TState>(\n runtime: SubscribableRuntime<TState>,\n): TState;\nexport function useRuntimeState<TState, TSelected>(\n runtime: SubscribableRuntime<TState>,\n selector: (state: TState) => TSelected,\n): TSelected;\nexport function useRuntimeState<TState, TSelected>(\n runtime: SubscribableRuntime<TState>,\n selector: ((state: TState) => TSelected) | undefined,\n): TSelected | TState;\nexport function useRuntimeState<TState, TSelected>(\n runtime: SubscribableRuntime<TState>,\n selector?: ((state: TState) => TSelected) | undefined,\n): TSelected | TState {\n // ensure that the runtime is bound\n // ensureBinding(runtime);\n\n return useRuntimeStateInternal(runtime, selector);\n}\n"],"mappings":";;;;AASA,SAAOS,wBAAAC,SAAAC,IAAA;CAAA,MAAAC,IAAAC,EAAA,CAAA;CAEL,MAAAC,WAAAH,OAAAI,KAAAA,IAAAC,WAAAL;CAGAR,cAAcO,OAAO;CAAC,IAAAO;CAAA,IAAAC;CAAA,IAAAN,EAAA,OAAAF,WAAAE,EAAA,OAAAE,UAAA;EAIpBG,WAAMH,SAASJ,QAAOL,SAAU,CAAC;EACjCa,WAAMJ,SAASJ,QAAOL,SAAU,CAAC;EAACO,EAAA,KAAAF;EAAAE,EAAA,KAAAE;EAAAF,EAAA,KAAAK;EAAAL,EAAA,KAAAM;CAAA,OAAA;EAAAD,KAAAL,EAAA;EAAAM,KAAAN,EAAA;CAAA;CAHpC,MAAAO,QAAcjB,qBACZQ,QAAOH,WACPU,IACAC,EACF;CACAjB,cAAckB,KAAK;CAAC,OACbA;AAAK;AAGd,MAAMH,YAAeI,QAAcA;AAYnC,SAAOE,gBAAAZ,SAAAI,UAAA;CAAA,OAOEL,wBAAwBC,SAASI,QAAQ;AAAC"}
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import { ThreadListRuntime, ThreadListState } from "@assistant-ui/core";
|
|
2
|
-
import { ThreadListRuntimeCoreBinding, ThreadListRuntimeImpl } from "@assistant-ui/core/internal";
|
|
3
|
-
export { type ThreadListRuntime, type ThreadListRuntimeCoreBinding, ThreadListRuntimeImpl, type ThreadListState };
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
type Bindable = {
|
|
2
|
-
__internal_bindMethods?: () => void;
|
|
3
|
-
__isBound?: boolean;
|
|
4
|
-
};
|
|
5
|
-
const debugVerifyPrototype = (
|
|
6
|
-
runtime: Record<string, unknown>,
|
|
7
|
-
prototype: any,
|
|
8
|
-
) => {
|
|
9
|
-
const unboundMethods = Object.getOwnPropertyNames(prototype).filter(
|
|
10
|
-
(methodStr) => {
|
|
11
|
-
const descriptor = Object.getOwnPropertyDescriptor(prototype, methodStr);
|
|
12
|
-
const isMethod = descriptor && typeof descriptor.value === "function";
|
|
13
|
-
if (!isMethod) return false;
|
|
14
|
-
|
|
15
|
-
const methodName = methodStr as keyof typeof runtime | "constructor";
|
|
16
|
-
return (
|
|
17
|
-
isMethod &&
|
|
18
|
-
!methodName.startsWith("_") &&
|
|
19
|
-
methodName !== "constructor" &&
|
|
20
|
-
prototype[methodName] === runtime[methodName]
|
|
21
|
-
);
|
|
22
|
-
},
|
|
23
|
-
);
|
|
24
|
-
|
|
25
|
-
if (unboundMethods.length > 0) {
|
|
26
|
-
throw new Error(
|
|
27
|
-
`The following methods are not bound: ${JSON.stringify(unboundMethods)}`,
|
|
28
|
-
);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const prototypePrototype = Object.getPrototypeOf(prototype);
|
|
32
|
-
if (prototypePrototype && prototypePrototype !== Object.prototype) {
|
|
33
|
-
debugVerifyPrototype(runtime, prototypePrototype);
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
export const ensureBinding = (r: unknown) => {
|
|
37
|
-
const runtime = r as Bindable;
|
|
38
|
-
if (runtime.__isBound) return;
|
|
39
|
-
|
|
40
|
-
runtime.__internal_bindMethods?.();
|
|
41
|
-
runtime.__isBound = true;
|
|
42
|
-
|
|
43
|
-
if (process.env.NODE_ENV !== "production") {
|
|
44
|
-
debugVerifyPrototype(runtime, Object.getPrototypeOf(runtime));
|
|
45
|
-
}
|
|
46
|
-
};
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import type { Unsubscribe } from "@assistant-ui/core";
|
|
2
|
-
import { useDebugValue, useSyncExternalStore } from "react";
|
|
3
|
-
import { ensureBinding } from "./ensureBinding";
|
|
4
|
-
|
|
5
|
-
export type SubscribableRuntime<TState> = {
|
|
6
|
-
getState: () => TState;
|
|
7
|
-
subscribe: (callback: () => void) => Unsubscribe;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export function useRuntimeStateInternal<TState, TSelected>(
|
|
11
|
-
runtime: SubscribableRuntime<TState>,
|
|
12
|
-
selector: ((state: TState) => TSelected | TState) | undefined = identity,
|
|
13
|
-
): TSelected | TState {
|
|
14
|
-
// TODO move to useRuntimeState
|
|
15
|
-
ensureBinding(runtime);
|
|
16
|
-
|
|
17
|
-
const slice = useSyncExternalStore(
|
|
18
|
-
runtime.subscribe,
|
|
19
|
-
() => selector(runtime.getState()),
|
|
20
|
-
() => selector(runtime.getState()),
|
|
21
|
-
);
|
|
22
|
-
useDebugValue(slice);
|
|
23
|
-
return slice;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const identity = <T>(arg: T): T => arg;
|
|
27
|
-
export function useRuntimeState<TState>(
|
|
28
|
-
runtime: SubscribableRuntime<TState>,
|
|
29
|
-
): TState;
|
|
30
|
-
export function useRuntimeState<TState, TSelected>(
|
|
31
|
-
runtime: SubscribableRuntime<TState>,
|
|
32
|
-
selector: (state: TState) => TSelected,
|
|
33
|
-
): TSelected;
|
|
34
|
-
export function useRuntimeState<TState, TSelected>(
|
|
35
|
-
runtime: SubscribableRuntime<TState>,
|
|
36
|
-
selector: ((state: TState) => TSelected) | undefined,
|
|
37
|
-
): TSelected | TState;
|
|
38
|
-
export function useRuntimeState<TState, TSelected>(
|
|
39
|
-
runtime: SubscribableRuntime<TState>,
|
|
40
|
-
selector?: ((state: TState) => TSelected) | undefined,
|
|
41
|
-
): TSelected | TState {
|
|
42
|
-
// ensure that the runtime is bound
|
|
43
|
-
// ensureBinding(runtime);
|
|
44
|
-
|
|
45
|
-
return useRuntimeStateInternal(runtime, selector);
|
|
46
|
-
}
|