@assistant-ui/react 0.15.31 → 0.15.32
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/dist/_virtual/_rolldown/runtime.js +1 -2
- package/dist/adapters/OpenAIRealtimeVoiceAdapter.js +1 -2
- package/dist/assistant-transport.js +1 -2
- package/dist/cloud-renderer/CloudRendererHost.js +1 -2
- package/dist/context/ReadonlyStore.js +1 -2
- package/dist/context/providers/MessageProvider.js +1 -2
- package/dist/context/providers/ThreadViewportProvider.js +1 -2
- package/dist/context/react/ThreadViewportContext.js +1 -2
- package/dist/context/react/utils/createContextHook.js +1 -2
- package/dist/context/react/utils/createContextStoreHook.js +1 -2
- package/dist/context/stores/ThreadViewport.js +1 -2
- package/dist/devtools/DevToolsHooks.js +1 -2
- package/dist/hooks/useMessageQuote.js +1 -2
- package/dist/hooks/useMessageTiming.js +1 -2
- package/dist/hooks/useToolCallElapsed.js +1 -2
- package/dist/internal.js +1 -2
- package/dist/legacy-runtime/AssistantRuntimeProvider.js +1 -2
- package/dist/mcp-apps/McpAppRenderer.d.ts.map +1 -1
- package/dist/mcp-apps/McpAppRenderer.js +3 -3
- package/dist/mcp-apps/McpAppRenderer.js.map +1 -1
- package/dist/mcp-apps/McpAppsRemoteHost.js +1 -2
- package/dist/mcp-apps/app-frame.js +1 -2
- package/dist/mcp-apps/bridge.js +1 -2
- package/dist/mcp-apps/csp.js +1 -2
- package/dist/mcp-apps/types.js +1 -2
- package/dist/mcp-apps/utils.js +1 -2
- package/dist/model-context/frame/useAssistantFrameHost.js +1 -2
- package/dist/model-context/makeAssistantVisible.js +1 -2
- package/dist/primitives/actionBar/ActionBarCopy.js +1 -2
- package/dist/primitives/actionBar/ActionBarEdit.js +1 -2
- package/dist/primitives/actionBar/ActionBarExportMarkdown.js +1 -2
- package/dist/primitives/actionBar/ActionBarFeedbackNegative.js +1 -2
- package/dist/primitives/actionBar/ActionBarFeedbackPositive.js +1 -2
- package/dist/primitives/actionBar/ActionBarInteractionContext.js +1 -2
- package/dist/primitives/actionBar/ActionBarReload.js +1 -2
- package/dist/primitives/actionBar/ActionBarRoot.js +1 -2
- package/dist/primitives/actionBar/ActionBarSpeak.js +1 -2
- package/dist/primitives/actionBar/ActionBarStopSpeaking.js +1 -2
- package/dist/primitives/actionBar/useActionBarFloatStatus.js +1 -2
- package/dist/primitives/actionBar.js +1 -2
- package/dist/primitives/actionBarMore/ActionBarMoreContent.js +1 -2
- package/dist/primitives/actionBarMore/ActionBarMoreItem.js +1 -2
- package/dist/primitives/actionBarMore/ActionBarMoreRoot.js +1 -2
- package/dist/primitives/actionBarMore/ActionBarMoreSeparator.js +1 -2
- package/dist/primitives/actionBarMore/ActionBarMoreTrigger.js +1 -2
- package/dist/primitives/actionBarMore/scope.js +1 -2
- package/dist/primitives/actionBarMore.js +1 -2
- package/dist/primitives/assistantModal/AssistantModalAnchor.js +1 -2
- package/dist/primitives/assistantModal/AssistantModalContent.js +1 -2
- package/dist/primitives/assistantModal/AssistantModalRoot.js +1 -2
- package/dist/primitives/assistantModal/AssistantModalTrigger.js +1 -2
- package/dist/primitives/assistantModal/popoverRenderPrimitives.js +1 -2
- package/dist/primitives/assistantModal/scope.js +1 -2
- package/dist/primitives/assistantModal.js +1 -2
- package/dist/primitives/attachment/AttachmentName.js +1 -2
- package/dist/primitives/attachment/AttachmentRemove.js +1 -2
- package/dist/primitives/attachment/AttachmentRoot.js +1 -2
- package/dist/primitives/attachment/AttachmentThumb.js +1 -2
- package/dist/primitives/attachment.js +1 -2
- package/dist/primitives/branchPicker/BranchPickerCount.js +1 -2
- package/dist/primitives/branchPicker/BranchPickerNext.js +1 -2
- package/dist/primitives/branchPicker/BranchPickerNumber.js +1 -2
- package/dist/primitives/branchPicker/BranchPickerPrevious.js +1 -2
- package/dist/primitives/branchPicker/BranchPickerRoot.js +1 -2
- package/dist/primitives/branchPicker.js +1 -2
- package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.d.ts +5 -4
- package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.d.ts.map +1 -1
- package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.js +57 -20
- package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.js.map +1 -1
- package/dist/primitives/chainOfThought/ChainOfThoughtRoot.js +1 -2
- package/dist/primitives/chainOfThought.js +1 -2
- package/dist/primitives/composer/ComposerAddAttachment.js +1 -2
- package/dist/primitives/composer/ComposerAttachmentDropzone.js +1 -2
- package/dist/primitives/composer/ComposerCancel.js +1 -2
- package/dist/primitives/composer/ComposerCompactContext.js +1 -2
- package/dist/primitives/composer/ComposerDictate.js +1 -2
- package/dist/primitives/composer/ComposerDictationTranscript.js +1 -2
- package/dist/primitives/composer/ComposerInput.js +1 -2
- package/dist/primitives/composer/ComposerInputPluginContext.js +1 -2
- package/dist/primitives/composer/ComposerQuote.js +1 -2
- package/dist/primitives/composer/ComposerResume.js +1 -2
- package/dist/primitives/composer/ComposerRoot.js +1 -2
- package/dist/primitives/composer/ComposerSend.js +1 -2
- package/dist/primitives/composer/ComposerStopDictation.js +1 -2
- package/dist/primitives/composer/composerInputSelector.js +1 -2
- package/dist/primitives/composer/trigger/TriggerPopover.js +1 -2
- package/dist/primitives/composer/trigger/TriggerPopoverAction.js +1 -2
- package/dist/primitives/composer/trigger/TriggerPopoverBack.js +1 -2
- package/dist/primitives/composer/trigger/TriggerPopoverCategories.js +1 -2
- package/dist/primitives/composer/trigger/TriggerPopoverDirective.js +1 -2
- package/dist/primitives/composer/trigger/TriggerPopoverItems.js +1 -2
- package/dist/primitives/composer/trigger/TriggerPopoverResource.js +1 -2
- package/dist/primitives/composer/trigger/TriggerPopoverRootContext.js +1 -2
- package/dist/primitives/composer/trigger/detectTrigger.js +1 -2
- package/dist/primitives/composer/trigger/index.js +1 -2
- package/dist/primitives/composer/trigger/matchesTriggerItemQuery.js +1 -2
- package/dist/primitives/composer/trigger/triggerDetectionResource.js +1 -2
- package/dist/primitives/composer/trigger/triggerKeyboardResource.js +1 -2
- package/dist/primitives/composer/trigger/triggerNavigationResource.js +1 -2
- package/dist/primitives/composer/trigger/triggerSelectionResource.js +1 -2
- package/dist/primitives/composer/useComposerCancelWithFocus.js +1 -2
- package/dist/primitives/composer/useComposerInputState.js +1 -2
- package/dist/primitives/composer.js +1 -2
- package/dist/primitives/dropdownMenuRenderPrimitives.js +1 -2
- package/dist/primitives/error/ErrorMessage.js +1 -2
- package/dist/primitives/error/ErrorRoot.js +1 -2
- package/dist/primitives/error.js +1 -2
- package/dist/primitives/message/MessageError.js +1 -2
- package/dist/primitives/message/MessageIf.js +1 -2
- package/dist/primitives/message/MessageParts.js +1 -2
- package/dist/primitives/message/MessagePartsGrouped.js +1 -2
- package/dist/primitives/message/MessageRoot.js +1 -2
- package/dist/primitives/message.js +1 -2
- package/dist/primitives/messagePart/MessagePartImage.js +1 -2
- package/dist/primitives/messagePart/MessagePartText.js +1 -2
- package/dist/primitives/messagePart/useMessagePartData.js +1 -2
- package/dist/primitives/messagePart/useMessagePartFile.js +1 -2
- package/dist/primitives/messagePart/useMessagePartImage.js +1 -2
- package/dist/primitives/messagePart/useMessagePartReasoning.js +1 -2
- package/dist/primitives/messagePart/useMessagePartSource.js +1 -2
- package/dist/primitives/messagePart/useMessagePartText.js +1 -2
- package/dist/primitives/messagePart.js +1 -2
- package/dist/primitives/queueItem/QueueItemRemove.js +1 -2
- package/dist/primitives/queueItem/QueueItemSteer.js +1 -2
- package/dist/primitives/queueItem/QueueItemText.js +1 -2
- package/dist/primitives/queueItem.js +1 -2
- package/dist/primitives/reasoning/useScrollLock.d.ts.map +1 -1
- package/dist/primitives/reasoning/useScrollLock.js +41 -25
- package/dist/primitives/reasoning/useScrollLock.js.map +1 -1
- package/dist/primitives/selectionToolbar/SelectionToolbarQuote.js +1 -2
- package/dist/primitives/selectionToolbar/SelectionToolbarRoot.js +1 -2
- package/dist/primitives/selectionToolbar.js +1 -2
- package/dist/primitives/suggestion/SuggestionDescription.js +1 -2
- package/dist/primitives/suggestion/SuggestionTitle.js +1 -2
- package/dist/primitives/suggestion/SuggestionTrigger.js +1 -2
- package/dist/primitives/suggestion.js +1 -2
- package/dist/primitives/thread/ThreadEmpty.js +1 -2
- package/dist/primitives/thread/ThreadIf.js +1 -2
- package/dist/primitives/thread/ThreadLoadEarlier.js +1 -2
- package/dist/primitives/thread/ThreadRoot.js +1 -2
- package/dist/primitives/thread/ThreadRootElementContext.js +1 -2
- package/dist/primitives/thread/ThreadScrollToBottom.js +1 -2
- package/dist/primitives/thread/ThreadSuggestion.js +1 -2
- package/dist/primitives/thread/ThreadViewport.js +1 -2
- package/dist/primitives/thread/ThreadViewportFooter.js +1 -2
- package/dist/primitives/thread/topAnchor/computeTopAnchorSlack.js +1 -2
- package/dist/primitives/thread/topAnchor/createReserveObservers.js +1 -2
- package/dist/primitives/thread/topAnchor/mountTopAnchorReserve.js +1 -2
- package/dist/primitives/thread/topAnchor/topAnchorTurn.js +1 -2
- package/dist/primitives/thread/topAnchor/topAnchorUtils.js +1 -2
- package/dist/primitives/thread/topAnchor/useTopAnchorReserve.js +1 -2
- package/dist/primitives/thread/useThreadViewportAutoScroll.js +1 -2
- package/dist/primitives/thread.js +1 -2
- package/dist/primitives/threadList/ThreadListLoadMore.js +1 -2
- package/dist/primitives/threadList/ThreadListNew.js +1 -2
- package/dist/primitives/threadList/ThreadListRoot.js +1 -2
- package/dist/primitives/threadList.js +1 -2
- package/dist/primitives/threadListFocusGroup.js +1 -2
- package/dist/primitives/threadListItem/ThreadListItemArchive.js +1 -2
- package/dist/primitives/threadListItem/ThreadListItemDelete.js +1 -2
- package/dist/primitives/threadListItem/ThreadListItemRoot.d.ts.map +1 -1
- package/dist/primitives/threadListItem/ThreadListItemRoot.js +2 -3
- package/dist/primitives/threadListItem/ThreadListItemRoot.js.map +1 -1
- package/dist/primitives/threadListItem/ThreadListItemTrigger.js +1 -2
- package/dist/primitives/threadListItem/ThreadListItemUnarchive.js +1 -2
- package/dist/primitives/threadListItem.js +1 -2
- package/dist/primitives/threadListItemMore/ThreadListItemMoreContent.js +1 -2
- package/dist/primitives/threadListItemMore/ThreadListItemMoreItem.js +1 -2
- package/dist/primitives/threadListItemMore/ThreadListItemMoreRoot.js +1 -2
- package/dist/primitives/threadListItemMore/ThreadListItemMoreSeparator.js +1 -2
- package/dist/primitives/threadListItemMore/ThreadListItemMoreTrigger.js +1 -2
- package/dist/primitives/threadListItemMore/scope.js +1 -2
- package/dist/primitives/threadListItemMore.js +1 -2
- package/dist/sandbox-host/SandboxHost.js +1 -2
- package/dist/unstable/useComposerInput.js +1 -2
- package/dist/unstable/useComposerInputHistory.js +1 -2
- package/dist/unstable/useLiveCompletionAdapter.js +1 -2
- package/dist/unstable/useMentionAdapter.js +1 -2
- package/dist/unstable/useMessageStallDetection.js +1 -2
- package/dist/unstable/useModelContextSnapshot.js +1 -2
- package/dist/unstable/useSlashCommandAdapter.js +1 -2
- package/dist/unstable/webmcp/WebMcpRegistrationResource.js +1 -2
- package/dist/unstable/webmcp/convertTools.js +1 -2
- package/dist/unstable/webmcp/useWebMcpProvider.js +1 -2
- package/dist/unstable/webmcp/webmcp-host.js +1 -2
- package/dist/utils/Primitive.js +1 -2
- package/dist/utils/createActionButton.js +1 -2
- package/dist/utils/getSelectionMessageId.js +1 -2
- package/dist/utils/hooks/useManagedRef.js +1 -2
- package/dist/utils/hooks/useMediaQuery.js +1 -2
- package/dist/utils/hooks/useOnScrollToBottom.js +1 -2
- package/dist/utils/hooks/useSizeHandle.js +1 -2
- package/dist/utils/isCompositionKey.js +1 -2
- package/dist/utils/smooth/SmoothContext.js +1 -2
- package/dist/utils/smooth/useSmooth.d.ts.map +1 -1
- package/dist/utils/smooth/useSmooth.js +11 -4
- package/dist/utils/smooth/useSmooth.js.map +1 -1
- package/dist/utils/useIsomorphicLayoutEffect.js +0 -1
- package/package.json +6 -6
- package/src/mcp-apps/McpAppRenderer.composer.test.tsx +111 -0
- package/src/mcp-apps/McpAppRenderer.test.tsx +24 -23
- package/src/mcp-apps/McpAppRenderer.tsx +9 -1
- package/src/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.test.tsx +91 -0
- package/src/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.tsx +54 -0
- package/src/primitives/reasoning/useScrollLock.test.tsx +71 -2
- package/src/primitives/reasoning/useScrollLock.ts +78 -51
- package/src/primitives/threadListItem/ThreadListItemRoot.tsx +4 -1
- package/src/primitives/threadListItem/ThreadListKeyboardNav.test.tsx +25 -0
- package/src/utils/smooth/useSmooth.test.tsx +113 -4
- package/src/utils/smooth/useSmooth.ts +16 -2
- package/src/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.ts +0 -49
|
@@ -5,7 +5,7 @@ import { ThreadListItemPrimitiveUnarchive } from "./threadListItem/ThreadListIte
|
|
|
5
5
|
import { ThreadListItemPrimitiveDelete } from "./threadListItem/ThreadListItemDelete.js";
|
|
6
6
|
import { ThreadListItemPrimitiveTrigger } from "./threadListItem/ThreadListItemTrigger.js";
|
|
7
7
|
import { ThreadListItemPrimitiveTitle } from "./threadListItem/ThreadListItemTitle.js";
|
|
8
|
-
|
|
8
|
+
// src/primitives/threadListItem.ts
|
|
9
9
|
var threadListItem_exports = /* @__PURE__ */ __exportAll({
|
|
10
10
|
Archive: () => ThreadListItemPrimitiveArchive,
|
|
11
11
|
Delete: () => ThreadListItemPrimitiveDelete,
|
|
@@ -14,7 +14,6 @@ var threadListItem_exports = /* @__PURE__ */ __exportAll({
|
|
|
14
14
|
Trigger: () => ThreadListItemPrimitiveTrigger,
|
|
15
15
|
Unarchive: () => ThreadListItemPrimitiveUnarchive
|
|
16
16
|
});
|
|
17
|
-
//#endregion
|
|
18
17
|
export { ThreadListItemPrimitiveArchive as Archive, ThreadListItemPrimitiveDelete as Delete, ThreadListItemPrimitiveRoot as Root, ThreadListItemPrimitiveTitle as Title, ThreadListItemPrimitiveTrigger as Trigger, ThreadListItemPrimitiveUnarchive as Unarchive, threadListItem_exports };
|
|
19
18
|
|
|
20
19
|
//# sourceMappingURL=threadListItem.js.map
|
|
@@ -8,7 +8,7 @@ import { forwardRef } from "@assistant-ui/tap/react-shim";
|
|
|
8
8
|
import { jsx } from "react/jsx-runtime";
|
|
9
9
|
import { composeEventHandlers } from "radix-ui/internal";
|
|
10
10
|
import { Direction, DropdownMenu } from "radix-ui";
|
|
11
|
-
|
|
11
|
+
// src/primitives/threadListItemMore/ThreadListItemMoreContent.tsx
|
|
12
12
|
const ThreadListItemMorePrimitiveContent = forwardRef((t0, forwardedRef) => {
|
|
13
13
|
const $ = c(21);
|
|
14
14
|
const { __scopeThreadListItemMore, portalProps, sideOffset: t1, ...props } = t0;
|
|
@@ -82,7 +82,6 @@ const ThreadListItemMorePrimitiveContent = forwardRef((t0, forwardedRef) => {
|
|
|
82
82
|
return t8;
|
|
83
83
|
});
|
|
84
84
|
ThreadListItemMorePrimitiveContent.displayName = "ThreadListItemMorePrimitive.Content";
|
|
85
|
-
//#endregion
|
|
86
85
|
export { ThreadListItemMorePrimitiveContent };
|
|
87
86
|
|
|
88
87
|
//# sourceMappingURL=ThreadListItemMoreContent.js.map
|
|
@@ -4,7 +4,7 @@ import { useDropdownMenuScope } from "./scope.js";
|
|
|
4
4
|
import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
|
|
5
5
|
import { forwardRef } from "@assistant-ui/tap/react-shim";
|
|
6
6
|
import { jsx } from "react/jsx-runtime";
|
|
7
|
-
|
|
7
|
+
// src/primitives/threadListItemMore/ThreadListItemMoreItem.tsx
|
|
8
8
|
const ThreadListItemMorePrimitiveItem = forwardRef((t0, ref) => {
|
|
9
9
|
const $ = c(7);
|
|
10
10
|
let __scopeThreadListItemMore;
|
|
@@ -34,7 +34,6 @@ const ThreadListItemMorePrimitiveItem = forwardRef((t0, ref) => {
|
|
|
34
34
|
return t1;
|
|
35
35
|
});
|
|
36
36
|
ThreadListItemMorePrimitiveItem.displayName = "ThreadListItemMorePrimitive.Item";
|
|
37
|
-
//#endregion
|
|
38
37
|
export { ThreadListItemMorePrimitiveItem };
|
|
39
38
|
|
|
40
39
|
//# sourceMappingURL=ThreadListItemMoreItem.js.map
|
|
@@ -5,7 +5,7 @@ import { createContext, useContext } from "@assistant-ui/tap/react-shim";
|
|
|
5
5
|
import { jsx } from "react/jsx-runtime";
|
|
6
6
|
import { useControllableState } from "radix-ui/internal";
|
|
7
7
|
import { DropdownMenu } from "radix-ui";
|
|
8
|
-
|
|
8
|
+
// src/primitives/threadListItemMore/ThreadListItemMoreRoot.tsx
|
|
9
9
|
const ThreadListItemMoreSetOpenContext = createContext(() => {});
|
|
10
10
|
const useThreadListItemMoreSetOpen = () => {
|
|
11
11
|
return useContext(ThreadListItemMoreSetOpenContext);
|
|
@@ -112,7 +112,6 @@ const ThreadListItemMorePrimitiveRoot = (t0) => {
|
|
|
112
112
|
return t7;
|
|
113
113
|
};
|
|
114
114
|
ThreadListItemMorePrimitiveRoot.displayName = "ThreadListItemMorePrimitive.Root";
|
|
115
|
-
//#endregion
|
|
116
115
|
export { ThreadListItemMorePrimitiveRoot, useThreadListItemMoreSetOpen, useThreadListItemMoreSharedFocusGroup };
|
|
117
116
|
|
|
118
117
|
//# sourceMappingURL=ThreadListItemMoreRoot.js.map
|
|
@@ -4,7 +4,7 @@ import { useDropdownMenuScope } from "./scope.js";
|
|
|
4
4
|
import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
|
|
5
5
|
import { forwardRef } from "@assistant-ui/tap/react-shim";
|
|
6
6
|
import { jsx } from "react/jsx-runtime";
|
|
7
|
-
|
|
7
|
+
// src/primitives/threadListItemMore/ThreadListItemMoreSeparator.tsx
|
|
8
8
|
const ThreadListItemMorePrimitiveSeparator = forwardRef((t0, ref) => {
|
|
9
9
|
const $ = c(7);
|
|
10
10
|
let __scopeThreadListItemMore;
|
|
@@ -34,7 +34,6 @@ const ThreadListItemMorePrimitiveSeparator = forwardRef((t0, ref) => {
|
|
|
34
34
|
return t1;
|
|
35
35
|
});
|
|
36
36
|
ThreadListItemMorePrimitiveSeparator.displayName = "ThreadListItemMorePrimitive.Separator";
|
|
37
|
-
//#endregion
|
|
38
37
|
export { ThreadListItemMorePrimitiveSeparator };
|
|
39
38
|
|
|
40
39
|
//# sourceMappingURL=ThreadListItemMoreSeparator.js.map
|
|
@@ -8,7 +8,7 @@ import { forwardRef } from "@assistant-ui/tap/react-shim";
|
|
|
8
8
|
import { jsx } from "react/jsx-runtime";
|
|
9
9
|
import { composeEventHandlers, useComposedRefs } from "radix-ui/internal";
|
|
10
10
|
import { Direction } from "radix-ui";
|
|
11
|
-
|
|
11
|
+
// src/primitives/threadListItemMore/ThreadListItemMoreTrigger.tsx
|
|
12
12
|
const ThreadListItemMorePrimitiveTrigger = forwardRef((t0, ref) => {
|
|
13
13
|
const $ = c(10);
|
|
14
14
|
const { __scopeThreadListItemMore, ...rest } = t0;
|
|
@@ -51,7 +51,6 @@ const ThreadListItemMorePrimitiveTrigger = forwardRef((t0, ref) => {
|
|
|
51
51
|
return t3;
|
|
52
52
|
});
|
|
53
53
|
ThreadListItemMorePrimitiveTrigger.displayName = "ThreadListItemMorePrimitive.Trigger";
|
|
54
|
-
//#endregion
|
|
55
54
|
export { ThreadListItemMorePrimitiveTrigger };
|
|
56
55
|
|
|
57
56
|
//# sourceMappingURL=ThreadListItemMoreTrigger.js.map
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { DropdownMenu } from "radix-ui";
|
|
2
|
-
|
|
2
|
+
// src/primitives/threadListItemMore/scope.ts
|
|
3
3
|
const useDropdownMenuScope = DropdownMenu.createDropdownMenuScope();
|
|
4
|
-
//#endregion
|
|
5
4
|
export { useDropdownMenuScope };
|
|
6
5
|
|
|
7
6
|
//# sourceMappingURL=scope.js.map
|
|
@@ -4,7 +4,7 @@ import { ThreadListItemMorePrimitiveTrigger } from "./threadListItemMore/ThreadL
|
|
|
4
4
|
import { ThreadListItemMorePrimitiveContent } from "./threadListItemMore/ThreadListItemMoreContent.js";
|
|
5
5
|
import { ThreadListItemMorePrimitiveItem } from "./threadListItemMore/ThreadListItemMoreItem.js";
|
|
6
6
|
import { ThreadListItemMorePrimitiveSeparator } from "./threadListItemMore/ThreadListItemMoreSeparator.js";
|
|
7
|
-
|
|
7
|
+
// src/primitives/threadListItemMore.ts
|
|
8
8
|
var threadListItemMore_exports = /* @__PURE__ */ __exportAll({
|
|
9
9
|
Content: () => ThreadListItemMorePrimitiveContent,
|
|
10
10
|
Item: () => ThreadListItemMorePrimitiveItem,
|
|
@@ -12,7 +12,6 @@ var threadListItemMore_exports = /* @__PURE__ */ __exportAll({
|
|
|
12
12
|
Separator: () => ThreadListItemMorePrimitiveSeparator,
|
|
13
13
|
Trigger: () => ThreadListItemMorePrimitiveTrigger
|
|
14
14
|
});
|
|
15
|
-
//#endregion
|
|
16
15
|
export { ThreadListItemMorePrimitiveContent as Content, ThreadListItemMorePrimitiveItem as Item, ThreadListItemMorePrimitiveRoot as Root, ThreadListItemMorePrimitiveSeparator as Separator, ThreadListItemMorePrimitiveTrigger as Trigger, threadListItemMore_exports };
|
|
17
16
|
|
|
18
17
|
//# sourceMappingURL=threadListItemMore.js.map
|
|
@@ -5,7 +5,7 @@ import { useEffect, useRef, useState } from "@assistant-ui/tap/react-shim";
|
|
|
5
5
|
import { invokeUserCallback } from "@assistant-ui/core/internal";
|
|
6
6
|
import { jsx } from "react/jsx-runtime";
|
|
7
7
|
import { SafeContentFrame, isShimLoadError } from "safe-content-frame";
|
|
8
|
-
|
|
8
|
+
// src/sandbox-host/SandboxHost.tsx
|
|
9
9
|
const DEFAULT_PRODUCT = "assistant-ui-sandbox";
|
|
10
10
|
const DEFAULT_MAX_HEIGHT = 800;
|
|
11
11
|
const LOAD_TIMEOUT_MS = 1e4;
|
|
@@ -184,7 +184,6 @@ function SandboxHost(t0) {
|
|
|
184
184
|
} else t9 = $[20];
|
|
185
185
|
return t9;
|
|
186
186
|
}
|
|
187
|
-
//#endregion
|
|
188
187
|
export { SandboxHost, isSandboxFrameMessage };
|
|
189
188
|
|
|
190
189
|
//# sourceMappingURL=SandboxHost.js.map
|
|
@@ -4,7 +4,7 @@ import { useComposerSend } from "@assistant-ui/core/react";
|
|
|
4
4
|
import { useCallback } from "@assistant-ui/tap/react-shim";
|
|
5
5
|
import { useAui } from "@assistant-ui/store";
|
|
6
6
|
import { flushTapSync } from "@assistant-ui/tap";
|
|
7
|
-
|
|
7
|
+
// src/unstable/useComposerInput.ts
|
|
8
8
|
/**
|
|
9
9
|
* Headless bridge to the composer's text value and send action, for building a
|
|
10
10
|
* custom composer input without `ComposerPrimitive.Input`. It is a thin bridge,
|
|
@@ -74,7 +74,6 @@ function unstable_useComposerInput(options) {
|
|
|
74
74
|
function unstable_useTriggerPopoverAriaProps() {
|
|
75
75
|
return useTriggerPopoverAriaProps();
|
|
76
76
|
}
|
|
77
|
-
//#endregion
|
|
78
77
|
export { unstable_useComposerInput, unstable_useTriggerPopoverAriaProps };
|
|
79
78
|
|
|
80
79
|
//# sourceMappingURL=useComposerInput.js.map
|
|
@@ -4,7 +4,7 @@ import { useCallback, useEffect, useMemo, useRef } from "@assistant-ui/tap/react
|
|
|
4
4
|
import { useAui } from "@assistant-ui/store";
|
|
5
5
|
import { flushTapSync } from "@assistant-ui/tap";
|
|
6
6
|
import { getThreadMessageText } from "@assistant-ui/core/internal";
|
|
7
|
-
|
|
7
|
+
// src/unstable/useComposerInputHistory.ts
|
|
8
8
|
const deriveHistory = (messages) => {
|
|
9
9
|
const entries = [];
|
|
10
10
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
@@ -111,7 +111,6 @@ function unstable_useComposerInputHistory() {
|
|
|
111
111
|
}, [aui, popoverCtx]);
|
|
112
112
|
return useMemo(() => ({ onKeyDown }), [onKeyDown]);
|
|
113
113
|
}
|
|
114
|
-
//#endregion
|
|
115
114
|
export { unstable_useComposerInputHistory };
|
|
116
115
|
|
|
117
116
|
//# sourceMappingURL=useComposerInputHistory.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useIsomorphicLayoutEffect } from "../utils/useIsomorphicLayoutEffect.js";
|
|
3
3
|
import { useCallback, useEffect, useMemo, useRef, useState } from "@assistant-ui/tap/react-shim";
|
|
4
|
-
|
|
4
|
+
// src/unstable/useLiveCompletionAdapter.ts
|
|
5
5
|
/** Sentinel that no real query (including the empty string) equals, so the first query always fetches. */
|
|
6
6
|
const NO_QUERY = "\0";
|
|
7
7
|
/**
|
|
@@ -174,7 +174,6 @@ function unstable_useLiveCompletionAdapter(options) {
|
|
|
174
174
|
isLoading
|
|
175
175
|
};
|
|
176
176
|
}
|
|
177
|
-
//#endregion
|
|
178
177
|
export { unstable_useLiveCompletionAdapter };
|
|
179
178
|
|
|
180
179
|
//# sourceMappingURL=useLiveCompletionAdapter.js.map
|
|
@@ -4,7 +4,7 @@ import { shallowEqualRecords, useModelContextSnapshot } from "./useModelContextS
|
|
|
4
4
|
import { unstable_defaultDirectiveFormatter } from "@assistant-ui/core";
|
|
5
5
|
import { useMemo } from "@assistant-ui/tap/react-shim";
|
|
6
6
|
import { useAui } from "@assistant-ui/store";
|
|
7
|
-
|
|
7
|
+
// src/unstable/useMentionAdapter.ts
|
|
8
8
|
const EMPTY_TOOL_MENTIONS = Object.freeze({});
|
|
9
9
|
const toolMentionSource = {
|
|
10
10
|
empty: EMPTY_TOOL_MENTIONS,
|
|
@@ -126,7 +126,6 @@ function toTriggerItem(m) {
|
|
|
126
126
|
...metadata !== void 0 ? { metadata } : {}
|
|
127
127
|
};
|
|
128
128
|
}
|
|
129
|
-
//#endregion
|
|
130
129
|
export { unstable_useMentionAdapter };
|
|
131
130
|
|
|
132
131
|
//# sourceMappingURL=useMentionAdapter.js.map
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { useEffect, useRef, useState } from "@assistant-ui/tap/react-shim";
|
|
3
3
|
import { useAuiState } from "@assistant-ui/store";
|
|
4
4
|
import { useShallowSelector } from "@assistant-ui/store/internal";
|
|
5
|
-
|
|
5
|
+
// src/unstable/useMessageStallDetection.ts
|
|
6
6
|
/**
|
|
7
7
|
* Detects mid-run output stalls on the current message: while the message is
|
|
8
8
|
* running, watches its text, reasoning, and tool-argument values plus tool-result
|
|
@@ -68,7 +68,6 @@ function unstable_useMessageStallDetection(options) {
|
|
|
68
68
|
stalledForMs: Math.max(0, now - lastActivityRef.current)
|
|
69
69
|
};
|
|
70
70
|
}
|
|
71
|
-
//#endregion
|
|
72
71
|
export { unstable_useMessageStallDetection };
|
|
73
72
|
|
|
74
73
|
//# sourceMappingURL=useMessageStallDetection.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
|
|
3
3
|
import { useEffect, useState } from "@assistant-ui/tap/react-shim";
|
|
4
|
-
|
|
4
|
+
// src/unstable/useModelContextSnapshot.ts
|
|
5
5
|
/**
|
|
6
6
|
* `getModelContext()` rebuilds its result on every call, so a projection of the
|
|
7
7
|
* fields a consumer observes is held in state and refreshed on notification
|
|
@@ -55,7 +55,6 @@ const shallowEqualRecords = (previous, next) => {
|
|
|
55
55
|
if (keys.length !== Object.keys(next).length) return false;
|
|
56
56
|
return keys.every((key) => Object.hasOwn(next, key) && previous[key] === next[key]);
|
|
57
57
|
};
|
|
58
|
-
//#endregion
|
|
59
58
|
export { shallowEqualRecords, useModelContextSnapshot };
|
|
60
59
|
|
|
61
60
|
//# sourceMappingURL=useModelContextSnapshot.js.map
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { useIsomorphicLayoutEffect } from "../utils/useIsomorphicLayoutEffect.js";
|
|
3
3
|
import { matchesTriggerItemQuery } from "../primitives/composer/trigger/matchesTriggerItemQuery.js";
|
|
4
4
|
import { useMemo, useRef } from "@assistant-ui/tap/react-shim";
|
|
5
|
-
|
|
5
|
+
// src/unstable/useSlashCommandAdapter.ts
|
|
6
6
|
/**
|
|
7
7
|
* Bundles slash command definitions (with inline `execute` callbacks) into
|
|
8
8
|
* `{adapter, action}` that plug directly into `ComposerTriggerPopover`.
|
|
@@ -75,7 +75,6 @@ function areTriggerItemsEqual(previous, next) {
|
|
|
75
75
|
return nextItem !== void 0 && item.id === nextItem.id && item.label === nextItem.label && item.description === nextItem.description && item.metadata?.icon === nextItem.metadata?.icon;
|
|
76
76
|
});
|
|
77
77
|
}
|
|
78
|
-
//#endregion
|
|
79
78
|
export { unstable_useSlashCommandAdapter };
|
|
80
79
|
|
|
81
80
|
//# sourceMappingURL=useSlashCommandAdapter.js.map
|
|
@@ -2,7 +2,7 @@ import { toWebMcpTool } from "./convertTools.js";
|
|
|
2
2
|
import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
|
|
3
3
|
import { useEffect, useRef, useState } from "@assistant-ui/tap/react-shim";
|
|
4
4
|
import { resource } from "@assistant-ui/tap";
|
|
5
|
-
|
|
5
|
+
// src/unstable/webmcp/WebMcpRegistrationResource.ts
|
|
6
6
|
const notPermitted = (error) => error?.name === "NotAllowedError";
|
|
7
7
|
const notPermittedMessage = (name) => `[assistant-ui] WebMCP registration for tool "${name}" was not permitted; the page's tools permission is disabled.`;
|
|
8
8
|
const useWebMcpRegistration = (t0) => {
|
|
@@ -67,7 +67,6 @@ const useWebMcpRegistration = (t0) => {
|
|
|
67
67
|
return refused ? null : name;
|
|
68
68
|
};
|
|
69
69
|
const WebMcpRegistrationResource = resource(useWebMcpRegistration);
|
|
70
|
-
//#endregion
|
|
71
70
|
export { WebMcpRegistrationResource };
|
|
72
71
|
|
|
73
72
|
//# sourceMappingURL=WebMcpRegistrationResource.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { generateId } from "@assistant-ui/core/internal";
|
|
2
2
|
import { ToolResponse, toJSONSchema } from "assistant-stream";
|
|
3
|
-
|
|
3
|
+
// src/unstable/webmcp/convertTools.ts
|
|
4
4
|
/**
|
|
5
5
|
* The predicate the WebMCP provider uses when no `filter` is passed: an enabled
|
|
6
6
|
* frontend tool with a client-side `execute`. A tool authored without a `type`
|
|
@@ -155,7 +155,6 @@ const toWebMcpTool = (name, getTool, lifecycleSignal) => ({
|
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
157
|
});
|
|
158
|
-
//#endregion
|
|
159
158
|
export { defaultWebMcpFilter, toMcpContent, toWebMcpInputSchema, toWebMcpTool };
|
|
160
159
|
|
|
161
160
|
//# sourceMappingURL=convertTools.js.map
|
|
@@ -8,7 +8,7 @@ import { useCallback, useEffect, useInsertionEffect, useRef, useState, useSyncEx
|
|
|
8
8
|
import { useAui } from "@assistant-ui/store";
|
|
9
9
|
import { useResources, useTapRoot, withKey } from "@assistant-ui/tap";
|
|
10
10
|
import { shallowEqual } from "@assistant-ui/store/internal";
|
|
11
|
-
|
|
11
|
+
// src/unstable/webmcp/useWebMcpProvider.ts
|
|
12
12
|
const EMPTY_NAMES = Object.freeze([]);
|
|
13
13
|
const EMPTY_TOOLS = Object.freeze({});
|
|
14
14
|
const warned = /* @__PURE__ */ new WeakSet();
|
|
@@ -111,7 +111,6 @@ const unstable_useWebMcpProvider = (options = {}) => {
|
|
|
111
111
|
registeredToolNames
|
|
112
112
|
};
|
|
113
113
|
};
|
|
114
|
-
//#endregion
|
|
115
114
|
export { unstable_useWebMcpProvider };
|
|
116
115
|
|
|
117
116
|
//# sourceMappingURL=useWebMcpProvider.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// src/unstable/webmcp/webmcp-host.ts
|
|
2
2
|
const isThenable = (value) => typeof value?.then === "function";
|
|
3
3
|
const resolveModelContext = () => {
|
|
4
4
|
const context = globalThis.document?.modelContext ?? globalThis.navigator?.modelContext;
|
|
@@ -23,7 +23,6 @@ const getDefaultWebMcpHost = () => {
|
|
|
23
23
|
};
|
|
24
24
|
return createHost(context);
|
|
25
25
|
};
|
|
26
|
-
//#endregion
|
|
27
26
|
export { getDefaultWebMcpHost };
|
|
28
27
|
|
|
29
28
|
//# sourceMappingURL=webmcp-host.js.map
|
package/dist/utils/Primitive.js
CHANGED
|
@@ -3,7 +3,7 @@ import { cloneElement, forwardRef, isValidElement } from "@assistant-ui/tap/reac
|
|
|
3
3
|
import { jsx } from "react/jsx-runtime";
|
|
4
4
|
import { Primitive as Primitive$1 } from "radix-ui/internal";
|
|
5
5
|
import { Slot } from "radix-ui";
|
|
6
|
-
|
|
6
|
+
// src/utils/Primitive.tsx
|
|
7
7
|
/**
|
|
8
8
|
* Thin wrapper around Radix `Primitive` that adds `render` prop support.
|
|
9
9
|
*
|
|
@@ -126,7 +126,6 @@ const Primitive = NODES.reduce((acc, node) => {
|
|
|
126
126
|
acc[node] = createPrimitive(node);
|
|
127
127
|
return acc;
|
|
128
128
|
}, {});
|
|
129
|
-
//#endregion
|
|
130
129
|
export { Primitive, renderSlot, withRenderProp };
|
|
131
130
|
|
|
132
131
|
//# sourceMappingURL=Primitive.js.map
|
|
@@ -3,7 +3,7 @@ import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
|
|
|
3
3
|
import { forwardRef } from "@assistant-ui/tap/react-shim";
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
5
|
import { composeEventHandlers } from "radix-ui/internal";
|
|
6
|
-
|
|
6
|
+
// src/utils/createActionButton.tsx
|
|
7
7
|
const createActionButton = (displayName, useActionButton, forwardProps = []) => {
|
|
8
8
|
const ActionButton = forwardRef((props, forwardedRef) => {
|
|
9
9
|
const $ = c(6);
|
|
@@ -39,7 +39,6 @@ const createActionButton = (displayName, useActionButton, forwardProps = []) =>
|
|
|
39
39
|
ActionButton.displayName = displayName;
|
|
40
40
|
return ActionButton;
|
|
41
41
|
};
|
|
42
|
-
//#endregion
|
|
43
42
|
export { createActionButton };
|
|
44
43
|
|
|
45
44
|
//# sourceMappingURL=createActionButton.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// src/utils/getSelectionMessageId.ts
|
|
2
2
|
const QUOTE_SELECTABLE_SELECTOR = "[data-aui-quote-selectable]";
|
|
3
3
|
const getElement = (node) => {
|
|
4
4
|
return node instanceof HTMLElement ? node : node?.parentElement ?? null;
|
|
@@ -79,7 +79,6 @@ const getSelectionMessageId = (selection, root) => {
|
|
|
79
79
|
for (const { commonAncestorContainer } of ranges) if (!scope.contains(commonAncestorContainer)) return null;
|
|
80
80
|
return intersectsExcluded(scope, ranges) ? null : messageId;
|
|
81
81
|
};
|
|
82
|
-
//#endregion
|
|
83
82
|
export { getSelectionMessageId };
|
|
84
83
|
|
|
85
84
|
//# sourceMappingURL=getSelectionMessageId.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
|
|
2
2
|
import { useRef } from "@assistant-ui/tap/react-shim";
|
|
3
|
-
|
|
3
|
+
// src/utils/hooks/useManagedRef.ts
|
|
4
4
|
const useManagedRef = (callback) => {
|
|
5
5
|
const $ = c(2);
|
|
6
6
|
const cleanupRef = useRef(void 0);
|
|
@@ -18,7 +18,6 @@ const useManagedRef = (callback) => {
|
|
|
18
18
|
} else t0 = $[1];
|
|
19
19
|
return t0;
|
|
20
20
|
};
|
|
21
|
-
//#endregion
|
|
22
21
|
export { useManagedRef };
|
|
23
22
|
|
|
24
23
|
//# sourceMappingURL=useManagedRef.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
|
|
3
3
|
import { useSyncExternalStore } from "@assistant-ui/tap/react-shim";
|
|
4
|
-
|
|
4
|
+
// src/utils/hooks/useMediaQuery.ts
|
|
5
5
|
const getServerSnapshot = () => false;
|
|
6
6
|
const noopUnsubscribe = () => {};
|
|
7
7
|
const useMediaQuery = (query) => {
|
|
@@ -29,7 +29,6 @@ const useMediaQuery = (query) => {
|
|
|
29
29
|
} else t1 = $[3];
|
|
30
30
|
return useSyncExternalStore(subscribe, t1, getServerSnapshot);
|
|
31
31
|
};
|
|
32
|
-
//#endregion
|
|
33
32
|
export { useMediaQuery };
|
|
34
33
|
|
|
35
34
|
//# sourceMappingURL=useMediaQuery.js.map
|
|
@@ -3,7 +3,7 @@ import { useThreadViewport } from "../../context/react/ThreadViewportContext.js"
|
|
|
3
3
|
import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
|
|
4
4
|
import { useEffect } from "@assistant-ui/tap/react-shim";
|
|
5
5
|
import { useCallbackRef } from "radix-ui/internal";
|
|
6
|
-
|
|
6
|
+
// src/utils/hooks/useOnScrollToBottom.ts
|
|
7
7
|
const useOnScrollToBottom = (callback) => {
|
|
8
8
|
const $ = c(4);
|
|
9
9
|
const callbackRef = useCallbackRef(callback);
|
|
@@ -26,7 +26,6 @@ const useOnScrollToBottom = (callback) => {
|
|
|
26
26
|
function _temp(vp) {
|
|
27
27
|
return vp.onScrollToBottom;
|
|
28
28
|
}
|
|
29
|
-
//#endregion
|
|
30
29
|
export { useOnScrollToBottom };
|
|
31
30
|
|
|
32
31
|
//# sourceMappingURL=useOnScrollToBottom.js.map
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { useManagedRef } from "./useManagedRef.js";
|
|
3
3
|
import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
|
|
4
4
|
import "@assistant-ui/tap/react-shim";
|
|
5
|
-
|
|
5
|
+
// src/utils/hooks/useSizeHandle.ts
|
|
6
6
|
/**
|
|
7
7
|
* Hook that creates a ref for tracking element size via a SizeHandle.
|
|
8
8
|
* Automatically sets up ResizeObserver and reports height changes.
|
|
@@ -36,7 +36,6 @@ const useSizeHandle = (register, getHeight) => {
|
|
|
36
36
|
} else t0 = $[2];
|
|
37
37
|
return useManagedRef(t0);
|
|
38
38
|
};
|
|
39
|
-
//#endregion
|
|
40
39
|
export { useSizeHandle };
|
|
41
40
|
|
|
42
41
|
//# sourceMappingURL=useSizeHandle.js.map
|
|
@@ -5,7 +5,7 @@ import { createContext, forwardRef, useContext, useState } from "@assistant-ui/t
|
|
|
5
5
|
import { useAui } from "@assistant-ui/store";
|
|
6
6
|
import { create } from "zustand";
|
|
7
7
|
import { jsx } from "react/jsx-runtime";
|
|
8
|
-
|
|
8
|
+
// src/utils/smooth/SmoothContext.tsx
|
|
9
9
|
const SmoothContext = createContext(null);
|
|
10
10
|
const makeSmoothContext = (initialState) => {
|
|
11
11
|
return { useSmoothStatus: create(() => initialState) };
|
|
@@ -65,7 +65,6 @@ function useSmoothContext(options) {
|
|
|
65
65
|
return context;
|
|
66
66
|
}
|
|
67
67
|
const { useSmoothStatus, useSmoothStatusStore } = createContextStoreHook(useSmoothContext, "useSmoothStatus");
|
|
68
|
-
//#endregion
|
|
69
68
|
export { SmoothContextProvider, useSmoothStatus, useSmoothStatusStore, withSmoothContextProvider };
|
|
70
69
|
|
|
71
70
|
//# sourceMappingURL=SmoothContext.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSmooth.d.ts","sourceRoot":"","sources":["../../../src/utils/smooth/useSmooth.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAEV,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EACjB,MAAM,oBAAoB,CAAC;AAM5B;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC,CAAC;AAwFF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,SAAS,GACpB,OAAO,gBAAgB,GAAG,CAAC,eAAe,GAAG,oBAAoB,CAAC,EAClE,SAAQ,OAAO,GAAG,aAAqB,KACtC,gBAAgB,GAAG,CAAC,eAAe,GAAG,oBAAoB,
|
|
1
|
+
{"version":3,"file":"useSmooth.d.ts","sourceRoot":"","sources":["../../../src/utils/smooth/useSmooth.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAEV,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EACjB,MAAM,oBAAoB,CAAC;AAM5B;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC,CAAC;AAwFF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,SAAS,GACpB,OAAO,gBAAgB,GAAG,CAAC,eAAe,GAAG,oBAAoB,CAAC,EAClE,SAAQ,OAAO,GAAG,aAAqB,KACtC,gBAAgB,GAAG,CAAC,eAAe,GAAG,oBAAoB,CA+I5D,CAAC"}
|
|
@@ -5,7 +5,7 @@ import { useSmoothStatusStore } from "./SmoothContext.js";
|
|
|
5
5
|
import { useEffect, useMemo, useRef, useState } from "@assistant-ui/tap/react-shim";
|
|
6
6
|
import { useAui, useAuiState } from "@assistant-ui/store";
|
|
7
7
|
import { useCallbackRef } from "radix-ui/internal";
|
|
8
|
-
|
|
8
|
+
// src/utils/smooth/useSmooth.ts
|
|
9
9
|
const DEFAULT_DRAIN_MS = 250;
|
|
10
10
|
const DEFAULT_MAX_CHAR_INTERVAL_MS = 5;
|
|
11
11
|
var TextStreamAnimator = class {
|
|
@@ -120,6 +120,11 @@ const useSmooth = (state, smooth = false) => {
|
|
|
120
120
|
state.status
|
|
121
121
|
]);
|
|
122
122
|
const [animatorRef] = useState(() => new TextStreamAnimator(displayedText, setText));
|
|
123
|
+
const [prevEnabled, setPrevEnabled] = useState(enabled);
|
|
124
|
+
if (enabled !== prevEnabled) {
|
|
125
|
+
setPrevEnabled(enabled);
|
|
126
|
+
if (enabled && part === prevPart && text.startsWith(animatorRef.currentText)) setDisplayedText(animatorRef.currentText);
|
|
127
|
+
}
|
|
123
128
|
useEffect(() => {
|
|
124
129
|
animatorRef.drainMs = drainMs;
|
|
125
130
|
animatorRef.maxCharIntervalMs = maxCharIntervalMs;
|
|
@@ -134,12 +139,15 @@ const useSmooth = (state, smooth = false) => {
|
|
|
134
139
|
]);
|
|
135
140
|
const animatorPartRef = useRef(part);
|
|
136
141
|
useEffect(() => {
|
|
142
|
+
const partChanged = animatorPartRef.current !== part;
|
|
143
|
+
animatorPartRef.current = part;
|
|
137
144
|
if (!enabled) {
|
|
138
145
|
animatorRef.stop();
|
|
146
|
+
animatorRef.currentText = text;
|
|
147
|
+
animatorRef.targetText = text;
|
|
148
|
+
animatorRef.lastCommitTime = -Infinity;
|
|
139
149
|
return;
|
|
140
150
|
}
|
|
141
|
-
const partChanged = animatorPartRef.current !== part;
|
|
142
|
-
animatorPartRef.current = part;
|
|
143
151
|
if (partChanged || !text.startsWith(animatorRef.targetText)) {
|
|
144
152
|
if (state.status.type === "running") {
|
|
145
153
|
animatorRef.currentText = "";
|
|
@@ -190,7 +198,6 @@ const useSmooth = (state, smooth = false) => {
|
|
|
190
198
|
text
|
|
191
199
|
]);
|
|
192
200
|
};
|
|
193
|
-
//#endregion
|
|
194
201
|
export { useSmooth };
|
|
195
202
|
|
|
196
203
|
//# sourceMappingURL=useSmooth.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSmooth.js","names":["useEffect","useMemo","useRef","useState","useAui","useAuiState","MessagePartStatus","ReasoningMessagePart","TextMessagePart","MessagePartState","useCallbackRef","useMediaQuery","useSmoothStatusStore","writableStore","SmoothOptions","drainMs","maxCharIntervalMs","maxCharsPerFrame","minCommitMs","DEFAULT_DRAIN_MS","DEFAULT_MAX_CHAR_INTERVAL_MS","TextStreamAnimator","animationFrameId","lastUpdateTime","lastCommitTime","Infinity","targetText","currentText","setText","newText","constructor","start","performance","now","animate","stop","cancelAnimationFrame","currentTime","deltaTime","timeToConsume","remainingChars","length","baseTimePerChar","Math","min","frameLimit","charsToAdd","requestAnimationFrame","slice","isComplete","SMOOTH_STATUS","Object","freeze","type","positiveOr","value","fallback","undefined","useSmooth","state","smooth","text","reduceMotion","options","enabled","displayedText","setDisplayedText","status","aui","part","prevPart","setPrevPart","startsWith","smoothStatusStore","optional","target","setState","animatorRef","animatorPartRef","partChanged","current"],"sources":["../../../src/utils/smooth/useSmooth.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { useAui, useAuiState } from \"@assistant-ui/store\";\nimport type {\n MessagePartStatus,\n ReasoningMessagePart,\n TextMessagePart,\n MessagePartState,\n} from \"@assistant-ui/core\";\nimport { useCallbackRef } from \"radix-ui/internal\";\nimport { useMediaQuery } from \"../hooks/useMediaQuery\";\nimport { useSmoothStatusStore } from \"./SmoothContext\";\nimport { writableStore } from \"../../context/ReadonlyStore\";\n\n/**\n * Tuning options for the smooth text streaming animation.\n */\nexport type SmoothOptions = {\n /**\n * Target time in milliseconds to drain the backlog of unrevealed\n * characters. Larger values reveal long backlogs more gradually.\n * @default 250\n */\n drainMs?: number | undefined;\n /**\n * Maximum time in milliseconds between revealed characters, i.e. the\n * slowest reveal rate when the backlog is short.\n * @default 5\n */\n maxCharIntervalMs?: number | undefined;\n /**\n * Maximum number of characters revealed per animation frame.\n * @default Infinity\n */\n maxCharsPerFrame?: number | undefined;\n /**\n * Minimum time in milliseconds between committed updates. The reveal keeps\n * advancing every frame, but the visible text (and the downstream re-render\n * and markdown re-parse it triggers) is committed at most once per interval.\n * The final frame always commits. `0` commits every frame.\n * @default 0\n */\n minCommitMs?: number | undefined;\n};\n\nconst DEFAULT_DRAIN_MS = 250;\nconst DEFAULT_MAX_CHAR_INTERVAL_MS = 5;\n\nclass TextStreamAnimator {\n private animationFrameId: number | null = null;\n private lastUpdateTime: number = 0;\n public lastCommitTime: number = -Infinity;\n\n public targetText: string = \"\";\n public drainMs: number = DEFAULT_DRAIN_MS;\n public maxCharIntervalMs: number = DEFAULT_MAX_CHAR_INTERVAL_MS;\n public maxCharsPerFrame: number = Infinity;\n public minCommitMs: number = 0;\n\n public currentText: string;\n private setText: (newText: string) => void;\n\n constructor(currentText: string, setText: (newText: string) => void) {\n this.currentText = currentText;\n this.setText = setText;\n }\n\n start() {\n if (this.animationFrameId !== null) return;\n this.lastUpdateTime = performance.now();\n this.animate();\n }\n\n stop() {\n if (this.animationFrameId !== null) {\n cancelAnimationFrame(this.animationFrameId);\n this.animationFrameId = null;\n }\n }\n\n private animate = () => {\n const currentTime = performance.now();\n const deltaTime = currentTime - this.lastUpdateTime;\n let timeToConsume = deltaTime;\n\n const remainingChars = this.targetText.length - this.currentText.length;\n const baseTimePerChar = Math.min(\n this.maxCharIntervalMs,\n this.drainMs / remainingChars,\n );\n\n const frameLimit = Math.min(remainingChars, this.maxCharsPerFrame);\n let charsToAdd = 0;\n while (timeToConsume >= baseTimePerChar && charsToAdd < frameLimit) {\n charsToAdd++;\n timeToConsume -= baseTimePerChar;\n }\n // A cap-limited frame must not bank its surplus time, or the next\n // frame would burst past the cap.\n if (charsToAdd === frameLimit && frameLimit === this.maxCharsPerFrame) {\n timeToConsume = 0;\n }\n\n if (charsToAdd !== remainingChars) {\n this.animationFrameId = requestAnimationFrame(this.animate);\n } else {\n this.animationFrameId = null;\n }\n if (charsToAdd === 0) return;\n\n this.currentText = this.targetText.slice(\n 0,\n this.currentText.length + charsToAdd,\n );\n this.lastUpdateTime = currentTime - timeToConsume;\n\n const isComplete = charsToAdd === remainingChars;\n if (isComplete || currentTime - this.lastCommitTime >= this.minCommitMs) {\n this.lastCommitTime = currentTime;\n this.setText(this.currentText);\n }\n };\n}\n\nconst SMOOTH_STATUS: MessagePartStatus = Object.freeze({\n type: \"running\",\n});\n\nconst positiveOr = (value: number | undefined, fallback: number): number =>\n value !== undefined && value > 0 ? value : fallback;\n\n/**\n * Animates streamed message part text with a typewriter-style reveal.\n *\n * Takes the current part state and a `smooth` argument: `false` disables,\n * `true` uses the default rate, and a {@link SmoothOptions} object tunes\n * the reveal. Returns the part state with `text` replaced by the revealed\n * prefix and `status` reporting `running` until the reveal catches up.\n * If the source settles before any character has been revealed, the text\n * is committed immediately so a missed animation frame cannot leave an\n * empty bubble.\n *\n * The reveal auto-disables under `prefers-reduced-motion: reduce`,\n * committing the full text immediately; this takes precedence over an\n * explicit `smooth={true}`.\n *\n * @example\n * ```tsx\n * const { text, status } = useSmooth(useMessagePartText(), {\n * drainMs: 500,\n * maxCharsPerFrame: 30,\n * });\n * ```\n */\nexport const useSmooth = (\n state: MessagePartState & (TextMessagePart | ReasoningMessagePart),\n smooth: boolean | SmoothOptions = false,\n): MessagePartState & (TextMessagePart | ReasoningMessagePart) => {\n const { text } = state;\n const reduceMotion = useMediaQuery(\"(prefers-reduced-motion: reduce)\");\n const options =\n typeof smooth === \"object\" && smooth !== null ? smooth : undefined;\n const enabled = smooth !== false && smooth !== null && !reduceMotion;\n const drainMs = positiveOr(options?.drainMs, DEFAULT_DRAIN_MS);\n const maxCharIntervalMs = positiveOr(\n options?.maxCharIntervalMs,\n DEFAULT_MAX_CHAR_INTERVAL_MS,\n );\n const maxCharsPerFrame = positiveOr(options?.maxCharsPerFrame, Infinity);\n const minCommitMs = positiveOr(options?.minCommitMs, 0);\n\n const [displayedText, setDisplayedText] = useState(\n state.status.type === \"running\" ? \"\" : text,\n );\n\n // Render-phase resync on part flip or text discontinuity, so the\n // first paint after a thread switch never shows the previous\n // part's text (#4051). `displayedText` is already a prefix of\n // `text` during normal streaming, so use it as the previous-text\n // reference instead of carrying separate state — avoids the\n // double render per streaming token. Read part identity through\n // `useAuiState` so we actually subscribe to its changes instead\n // of relying on a render-time proxy reference that may be stable\n // across thread swaps.\n const aui = useAui();\n const part = useAuiState(() => aui.part);\n const [prevPart, setPrevPart] = useState(part);\n if (part !== prevPart || !text.startsWith(displayedText)) {\n setPrevPart(part);\n setDisplayedText(state.status.type === \"running\" ? \"\" : text);\n }\n\n const smoothStatusStore = useSmoothStatusStore({ optional: true });\n const setText = useCallbackRef((text: string) => {\n setDisplayedText(text);\n if (smoothStatusStore) {\n const target =\n displayedText !== text || state.status.type === \"running\"\n ? SMOOTH_STATUS\n : state.status;\n writableStore(smoothStatusStore).setState(target, true);\n }\n });\n\n // TODO this is hacky\n useEffect(() => {\n if (smoothStatusStore) {\n const target =\n enabled && (displayedText !== text || state.status.type === \"running\")\n ? SMOOTH_STATUS\n : state.status;\n writableStore(smoothStatusStore).setState(target, true);\n }\n }, [smoothStatusStore, enabled, text, displayedText, state.status]);\n\n const [animatorRef] = useState(\n () => new TextStreamAnimator(displayedText, setText),\n );\n\n useEffect(() => {\n animatorRef.drainMs = drainMs;\n animatorRef.maxCharIntervalMs = maxCharIntervalMs;\n animatorRef.maxCharsPerFrame = maxCharsPerFrame;\n animatorRef.minCommitMs = minCommitMs;\n }, [animatorRef, drainMs, maxCharIntervalMs, maxCharsPerFrame, minCommitMs]);\n\n const animatorPartRef = useRef(part);\n useEffect(() => {\n if (!enabled) {\n animatorRef.stop();\n return;\n }\n\n const partChanged = animatorPartRef.current !== part;\n animatorPartRef.current = part;\n // A new part whose text shares a prefix with the previous target would\n // keep the stale cursor and flicker without this reset.\n if (partChanged || !text.startsWith(animatorRef.targetText)) {\n if (state.status.type === \"running\") {\n animatorRef.currentText = \"\";\n animatorRef.targetText = text;\n animatorRef.lastCommitTime = -Infinity;\n animatorRef.start();\n } else {\n animatorRef.currentText = text;\n animatorRef.targetText = text;\n animatorRef.stop();\n setText(text);\n }\n return;\n }\n\n animatorRef.targetText = text;\n if (state.status.type !== \"running\") {\n // No character has painted. A pending frame that never runs would\n // leave an empty bubble after settle.\n if (animatorRef.currentText === \"\") {\n animatorRef.currentText = text;\n animatorRef.stop();\n setText(text);\n return;\n }\n animatorRef.start();\n return;\n }\n\n animatorRef.start();\n }, [animatorRef, enabled, text, state.status.type, part, setText]);\n\n useEffect(() => {\n return () => {\n animatorRef.stop();\n };\n }, [animatorRef]);\n\n return useMemo(\n () =>\n enabled\n ? {\n ...state,\n text: displayedText,\n status: text === displayedText ? state.status : SMOOTH_STATUS,\n }\n : state,\n [enabled, displayedText, state, text],\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useSmooth.js","names":["useEffect","useMemo","useRef","useState","useAui","useAuiState","MessagePartStatus","ReasoningMessagePart","TextMessagePart","MessagePartState","useCallbackRef","useMediaQuery","useSmoothStatusStore","writableStore","SmoothOptions","drainMs","maxCharIntervalMs","maxCharsPerFrame","minCommitMs","DEFAULT_DRAIN_MS","DEFAULT_MAX_CHAR_INTERVAL_MS","TextStreamAnimator","animationFrameId","lastUpdateTime","lastCommitTime","Infinity","targetText","currentText","setText","newText","constructor","start","performance","now","animate","stop","cancelAnimationFrame","currentTime","deltaTime","timeToConsume","remainingChars","length","baseTimePerChar","Math","min","frameLimit","charsToAdd","requestAnimationFrame","slice","isComplete","SMOOTH_STATUS","Object","freeze","type","positiveOr","value","fallback","undefined","useSmooth","state","smooth","text","reduceMotion","options","enabled","displayedText","setDisplayedText","status","aui","part","prevPart","setPrevPart","startsWith","smoothStatusStore","optional","target","setState","animatorRef","prevEnabled","setPrevEnabled","animatorPartRef","partChanged","current"],"sources":["../../../src/utils/smooth/useSmooth.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { useAui, useAuiState } from \"@assistant-ui/store\";\nimport type {\n MessagePartStatus,\n ReasoningMessagePart,\n TextMessagePart,\n MessagePartState,\n} from \"@assistant-ui/core\";\nimport { useCallbackRef } from \"radix-ui/internal\";\nimport { useMediaQuery } from \"../hooks/useMediaQuery\";\nimport { useSmoothStatusStore } from \"./SmoothContext\";\nimport { writableStore } from \"../../context/ReadonlyStore\";\n\n/**\n * Tuning options for the smooth text streaming animation.\n */\nexport type SmoothOptions = {\n /**\n * Target time in milliseconds to drain the backlog of unrevealed\n * characters. Larger values reveal long backlogs more gradually.\n * @default 250\n */\n drainMs?: number | undefined;\n /**\n * Maximum time in milliseconds between revealed characters, i.e. the\n * slowest reveal rate when the backlog is short.\n * @default 5\n */\n maxCharIntervalMs?: number | undefined;\n /**\n * Maximum number of characters revealed per animation frame.\n * @default Infinity\n */\n maxCharsPerFrame?: number | undefined;\n /**\n * Minimum time in milliseconds between committed updates. The reveal keeps\n * advancing every frame, but the visible text (and the downstream re-render\n * and markdown re-parse it triggers) is committed at most once per interval.\n * The final frame always commits. `0` commits every frame.\n * @default 0\n */\n minCommitMs?: number | undefined;\n};\n\nconst DEFAULT_DRAIN_MS = 250;\nconst DEFAULT_MAX_CHAR_INTERVAL_MS = 5;\n\nclass TextStreamAnimator {\n private animationFrameId: number | null = null;\n private lastUpdateTime: number = 0;\n public lastCommitTime: number = -Infinity;\n\n public targetText: string = \"\";\n public drainMs: number = DEFAULT_DRAIN_MS;\n public maxCharIntervalMs: number = DEFAULT_MAX_CHAR_INTERVAL_MS;\n public maxCharsPerFrame: number = Infinity;\n public minCommitMs: number = 0;\n\n public currentText: string;\n private setText: (newText: string) => void;\n\n constructor(currentText: string, setText: (newText: string) => void) {\n this.currentText = currentText;\n this.setText = setText;\n }\n\n start() {\n if (this.animationFrameId !== null) return;\n this.lastUpdateTime = performance.now();\n this.animate();\n }\n\n stop() {\n if (this.animationFrameId !== null) {\n cancelAnimationFrame(this.animationFrameId);\n this.animationFrameId = null;\n }\n }\n\n private animate = () => {\n const currentTime = performance.now();\n const deltaTime = currentTime - this.lastUpdateTime;\n let timeToConsume = deltaTime;\n\n const remainingChars = this.targetText.length - this.currentText.length;\n const baseTimePerChar = Math.min(\n this.maxCharIntervalMs,\n this.drainMs / remainingChars,\n );\n\n const frameLimit = Math.min(remainingChars, this.maxCharsPerFrame);\n let charsToAdd = 0;\n while (timeToConsume >= baseTimePerChar && charsToAdd < frameLimit) {\n charsToAdd++;\n timeToConsume -= baseTimePerChar;\n }\n // A cap-limited frame must not bank its surplus time, or the next\n // frame would burst past the cap.\n if (charsToAdd === frameLimit && frameLimit === this.maxCharsPerFrame) {\n timeToConsume = 0;\n }\n\n if (charsToAdd !== remainingChars) {\n this.animationFrameId = requestAnimationFrame(this.animate);\n } else {\n this.animationFrameId = null;\n }\n if (charsToAdd === 0) return;\n\n this.currentText = this.targetText.slice(\n 0,\n this.currentText.length + charsToAdd,\n );\n this.lastUpdateTime = currentTime - timeToConsume;\n\n const isComplete = charsToAdd === remainingChars;\n if (isComplete || currentTime - this.lastCommitTime >= this.minCommitMs) {\n this.lastCommitTime = currentTime;\n this.setText(this.currentText);\n }\n };\n}\n\nconst SMOOTH_STATUS: MessagePartStatus = Object.freeze({\n type: \"running\",\n});\n\nconst positiveOr = (value: number | undefined, fallback: number): number =>\n value !== undefined && value > 0 ? value : fallback;\n\n/**\n * Animates streamed message part text with a typewriter-style reveal.\n *\n * Takes the current part state and a `smooth` argument: `false` disables,\n * `true` uses the default rate, and a {@link SmoothOptions} object tunes\n * the reveal. Returns the part state with `text` replaced by the revealed\n * prefix and `status` reporting `running` until the reveal catches up.\n * If the source settles before any character has been revealed, the text\n * is committed immediately so a missed animation frame cannot leave an\n * empty bubble.\n *\n * The reveal auto-disables under `prefers-reduced-motion: reduce`,\n * committing the full text immediately; this takes precedence over an\n * explicit `smooth={true}`.\n *\n * @example\n * ```tsx\n * const { text, status } = useSmooth(useMessagePartText(), {\n * drainMs: 500,\n * maxCharsPerFrame: 30,\n * });\n * ```\n */\nexport const useSmooth = (\n state: MessagePartState & (TextMessagePart | ReasoningMessagePart),\n smooth: boolean | SmoothOptions = false,\n): MessagePartState & (TextMessagePart | ReasoningMessagePart) => {\n const { text } = state;\n const reduceMotion = useMediaQuery(\"(prefers-reduced-motion: reduce)\");\n const options =\n typeof smooth === \"object\" && smooth !== null ? smooth : undefined;\n const enabled = smooth !== false && smooth !== null && !reduceMotion;\n const drainMs = positiveOr(options?.drainMs, DEFAULT_DRAIN_MS);\n const maxCharIntervalMs = positiveOr(\n options?.maxCharIntervalMs,\n DEFAULT_MAX_CHAR_INTERVAL_MS,\n );\n const maxCharsPerFrame = positiveOr(options?.maxCharsPerFrame, Infinity);\n const minCommitMs = positiveOr(options?.minCommitMs, 0);\n\n const [displayedText, setDisplayedText] = useState(\n state.status.type === \"running\" ? \"\" : text,\n );\n\n // Render-phase resync on part flip or text discontinuity, so the\n // first paint after a thread switch never shows the previous\n // part's text (#4051). `displayedText` is already a prefix of\n // `text` during normal streaming, so use it as the previous-text\n // reference instead of carrying separate state — avoids the\n // double render per streaming token. Read part identity through\n // `useAuiState` so we actually subscribe to its changes instead\n // of relying on a render-time proxy reference that may be stable\n // across thread swaps.\n const aui = useAui();\n const part = useAuiState(() => aui.part);\n const [prevPart, setPrevPart] = useState(part);\n if (part !== prevPart || !text.startsWith(displayedText)) {\n setPrevPart(part);\n setDisplayedText(state.status.type === \"running\" ? \"\" : text);\n }\n\n const smoothStatusStore = useSmoothStatusStore({ optional: true });\n const setText = useCallbackRef((text: string) => {\n setDisplayedText(text);\n if (smoothStatusStore) {\n const target =\n displayedText !== text || state.status.type === \"running\"\n ? SMOOTH_STATUS\n : state.status;\n writableStore(smoothStatusStore).setState(target, true);\n }\n });\n\n // TODO this is hacky\n useEffect(() => {\n if (smoothStatusStore) {\n const target =\n enabled && (displayedText !== text || state.status.type === \"running\")\n ? SMOOTH_STATUS\n : state.status;\n writableStore(smoothStatusStore).setState(target, true);\n }\n }, [smoothStatusStore, enabled, text, displayedText, state.status]);\n\n const [animatorRef] = useState(\n () => new TextStreamAnimator(displayedText, setText),\n );\n const [prevEnabled, setPrevEnabled] = useState(enabled);\n if (enabled !== prevEnabled) {\n setPrevEnabled(enabled);\n if (\n enabled &&\n part === prevPart &&\n text.startsWith(animatorRef.currentText)\n ) {\n setDisplayedText(animatorRef.currentText);\n }\n }\n\n useEffect(() => {\n animatorRef.drainMs = drainMs;\n animatorRef.maxCharIntervalMs = maxCharIntervalMs;\n animatorRef.maxCharsPerFrame = maxCharsPerFrame;\n animatorRef.minCommitMs = minCommitMs;\n }, [animatorRef, drainMs, maxCharIntervalMs, maxCharsPerFrame, minCommitMs]);\n\n const animatorPartRef = useRef(part);\n useEffect(() => {\n const partChanged = animatorPartRef.current !== part;\n animatorPartRef.current = part;\n if (!enabled) {\n animatorRef.stop();\n animatorRef.currentText = text;\n animatorRef.targetText = text;\n animatorRef.lastCommitTime = -Infinity;\n return;\n }\n\n // A new part whose text shares a prefix with the previous target would\n // keep the stale cursor and flicker without this reset.\n if (partChanged || !text.startsWith(animatorRef.targetText)) {\n if (state.status.type === \"running\") {\n animatorRef.currentText = \"\";\n animatorRef.targetText = text;\n animatorRef.lastCommitTime = -Infinity;\n animatorRef.start();\n } else {\n animatorRef.currentText = text;\n animatorRef.targetText = text;\n animatorRef.stop();\n setText(text);\n }\n return;\n }\n\n animatorRef.targetText = text;\n if (state.status.type !== \"running\") {\n // No character has painted. A pending frame that never runs would\n // leave an empty bubble after settle.\n if (animatorRef.currentText === \"\") {\n animatorRef.currentText = text;\n animatorRef.stop();\n setText(text);\n return;\n }\n animatorRef.start();\n return;\n }\n\n animatorRef.start();\n }, [animatorRef, enabled, text, state.status.type, part, setText]);\n\n useEffect(() => {\n return () => {\n animatorRef.stop();\n };\n }, [animatorRef]);\n\n return useMemo(\n () =>\n enabled\n ? {\n ...state,\n text: displayedText,\n status: text === displayedText ? state.status : SMOOTH_STATUS,\n }\n : state,\n [enabled, displayedText, state, text],\n );\n};\n"],"mappings":"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"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { useEffect, useLayoutEffect } from "@assistant-ui/tap/react-shim";
|
|
2
2
|
const useIsomorphicLayoutEffect = typeof globalThis.window !== "undefined" ? useLayoutEffect : useEffect;
|
|
3
|
-
//#endregion
|
|
4
3
|
export { useIsomorphicLayoutEffect };
|
|
5
4
|
|
|
6
5
|
//# sourceMappingURL=useIsomorphicLayoutEffect.js.map
|