@assistant-ui/react 0.15.16 → 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/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 +19 -12
- 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/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.js +3 -3
- 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.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.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 +18 -19
- 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/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/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 +137 -70
- package/dist/sandbox-host/SandboxHost.js.map +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/smooth/SmoothContext.d.ts +24 -0
- package/dist/utils/smooth/SmoothContext.d.ts.map +1 -1
- package/dist/utils/smooth/useSmooth.js +1 -1
- package/dist/utils/smooth/useSmooth.js.map +1 -1
- package/dist/utils/useToolArgsFieldStatus.d.ts +5 -1
- package/package.json +11 -19
- 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/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.tsx +1 -1
- 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/composer/ComposerAttachmentDropzone.tsx +1 -1
- 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 +15 -3
- package/src/primitives/composer/trigger/triggerSelectionResource.ts +1 -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/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 +45 -1
- package/src/sandbox-host/SandboxHost.tsx +16 -3
- package/src/tests/RemoteThreadListRuntime.adapterProvider.test.tsx +31 -1
- package/src/unstable/useLiveCompletionAdapter.test.tsx +60 -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/smooth/useSmooth.ts +1 -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/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
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
useEffect,
|
|
5
|
+
useLayoutEffect,
|
|
5
6
|
useMemo,
|
|
6
7
|
useRef,
|
|
7
8
|
useState,
|
|
@@ -47,6 +48,14 @@ export type McpAppRendererOptions = {
|
|
|
47
48
|
hostInfo?: McpAppHostInfo;
|
|
48
49
|
/** Delivered to the widget on initialize and pushed via `notifications/host_context/changed` on change. */
|
|
49
50
|
hostContext?: McpAppHostContext;
|
|
51
|
+
/**
|
|
52
|
+
* Optional widget interaction and lifecycle handlers. Data-plane handlers
|
|
53
|
+
* (`callTool`, `readResource`, `listResources`) always use `host`.
|
|
54
|
+
*/
|
|
55
|
+
handlers?: Omit<
|
|
56
|
+
McpAppBridgeHandlers,
|
|
57
|
+
"callTool" | "readResource" | "listResources"
|
|
58
|
+
>;
|
|
50
59
|
/** Rendered when no MCP app is on the part, or while load is in flight / failed (unless overridden). */
|
|
51
60
|
fallback?: ReactNode;
|
|
52
61
|
/** Rendered while the resource is loading. Defaults to `fallback`. */
|
|
@@ -106,13 +115,9 @@ function InlineRenderer({
|
|
|
106
115
|
const aui = useAui();
|
|
107
116
|
const app = getMcpAppFromToolPart(part);
|
|
108
117
|
const cachedAppRef = useRef<McpAppMetadata | undefined>(undefined);
|
|
109
|
-
|
|
110
|
-
app != null
|
|
111
|
-
|
|
112
|
-
cachedAppRef.current?.serverId !== app.serverId)
|
|
113
|
-
) {
|
|
114
|
-
cachedAppRef.current = app;
|
|
115
|
-
}
|
|
118
|
+
useLayoutEffect(() => {
|
|
119
|
+
if (app != null) cachedAppRef.current = app;
|
|
120
|
+
}, [app]);
|
|
116
121
|
const appForRender = app ?? cachedAppRef.current;
|
|
117
122
|
|
|
118
123
|
const [loadedResource, setLoadedResource] = useState<LoadedResourceState>();
|
|
@@ -120,8 +125,7 @@ function InlineRenderer({
|
|
|
120
125
|
const host = useHostStore((state) => state.host);
|
|
121
126
|
const resourceUri = appForRender?.resourceUri;
|
|
122
127
|
const serverId = appForRender?.serverId;
|
|
123
|
-
const
|
|
124
|
-
serverIdRef.current = serverId;
|
|
128
|
+
const callerHandlers = opts.handlers;
|
|
125
129
|
useEffect(() => {
|
|
126
130
|
if (resourceUri == null) return;
|
|
127
131
|
let cancelled = false;
|
|
@@ -165,34 +169,37 @@ function InlineRenderer({
|
|
|
165
169
|
|
|
166
170
|
const bridgeHandlers = useMemo<McpAppBridgeHandlers>(
|
|
167
171
|
() => ({
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
172
|
+
...callerHandlers,
|
|
173
|
+
openLink: callerHandlers?.openLink ?? defaultOpenLink,
|
|
174
|
+
sendMessage:
|
|
175
|
+
callerHandlers?.sendMessage ??
|
|
176
|
+
((params) => {
|
|
177
|
+
const text = extractSendMessageText(params);
|
|
178
|
+
if (!text) return { ok: false, reason: "unrecognised params shape" };
|
|
179
|
+
aui.thread.append({ content: [{ type: "text", text }] });
|
|
180
|
+
return { ok: true };
|
|
181
|
+
}),
|
|
175
182
|
callTool: (params) =>
|
|
176
183
|
useHostStore.getState().host.callTool({
|
|
177
184
|
...params,
|
|
178
|
-
...(
|
|
185
|
+
...(serverId ? { serverId } : {}),
|
|
179
186
|
}),
|
|
180
187
|
readResource: (params) =>
|
|
181
188
|
useHostStore.getState().host.readResource({
|
|
182
189
|
...params,
|
|
183
|
-
...(
|
|
190
|
+
...(serverId ? { serverId } : {}),
|
|
184
191
|
}),
|
|
185
192
|
listResources: (params) => {
|
|
186
|
-
if (!
|
|
193
|
+
if (!serverId) {
|
|
187
194
|
return useHostStore.getState().host.listResources(params);
|
|
188
195
|
}
|
|
189
196
|
return useHostStore.getState().host.listResources({
|
|
190
197
|
...(isRecord(params) ? params : {}),
|
|
191
|
-
serverId
|
|
198
|
+
serverId,
|
|
192
199
|
});
|
|
193
200
|
},
|
|
194
201
|
}),
|
|
195
|
-
[aui, useHostStore],
|
|
202
|
+
[aui, callerHandlers, serverId, useHostStore],
|
|
196
203
|
);
|
|
197
204
|
|
|
198
205
|
const loadedResourceForApp =
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
|
|
3
|
+
import { act, render, waitFor } from "@testing-library/react";
|
|
4
|
+
import { useResource } from "@assistant-ui/tap";
|
|
5
|
+
import {
|
|
6
|
+
startTransition,
|
|
7
|
+
Suspense,
|
|
8
|
+
useLayoutEffect,
|
|
9
|
+
type ReactNode,
|
|
10
|
+
} from "react";
|
|
11
|
+
import { describe, expect, it, vi } from "vitest";
|
|
12
|
+
import type { McpAppsHost } from "./types";
|
|
13
|
+
import { McpAppsRemoteHost } from "./McpAppsRemoteHost";
|
|
14
|
+
|
|
15
|
+
describe("McpAppsRemoteHost concurrent rendering", () => {
|
|
16
|
+
it("keeps committed authorization options during an interrupted render", async () => {
|
|
17
|
+
const pending = new Promise<never>(() => {});
|
|
18
|
+
const fetch = vi.fn(async () => Response.json({ content: [] }));
|
|
19
|
+
let committedHost: McpAppsHost | undefined;
|
|
20
|
+
|
|
21
|
+
const Probe = ({
|
|
22
|
+
authorization,
|
|
23
|
+
suspend,
|
|
24
|
+
children,
|
|
25
|
+
}: {
|
|
26
|
+
authorization: string;
|
|
27
|
+
suspend: boolean;
|
|
28
|
+
children: ReactNode;
|
|
29
|
+
}) => {
|
|
30
|
+
const host = useResource(
|
|
31
|
+
McpAppsRemoteHost({
|
|
32
|
+
url: "/api/mcp-apps",
|
|
33
|
+
fetch,
|
|
34
|
+
headers: { authorization },
|
|
35
|
+
}),
|
|
36
|
+
);
|
|
37
|
+
useLayoutEffect(() => {
|
|
38
|
+
committedHost = host;
|
|
39
|
+
}, [host]);
|
|
40
|
+
if (suspend) throw pending;
|
|
41
|
+
return children;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const view = render(
|
|
45
|
+
<Suspense fallback={null}>
|
|
46
|
+
<Probe authorization="Bearer workspace-a" suspend={false}>
|
|
47
|
+
workspace-a
|
|
48
|
+
</Probe>
|
|
49
|
+
</Suspense>,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
act(() => {
|
|
53
|
+
startTransition(() => {
|
|
54
|
+
view.rerender(
|
|
55
|
+
<Suspense fallback={null}>
|
|
56
|
+
<Probe authorization="Bearer workspace-b" suspend>
|
|
57
|
+
workspace-b
|
|
58
|
+
</Probe>
|
|
59
|
+
</Suspense>,
|
|
60
|
+
);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
expect(view.container.textContent).toBe("workspace-a");
|
|
65
|
+
await committedHost?.callTool({ name: "search" });
|
|
66
|
+
|
|
67
|
+
expect(fetch).toHaveBeenCalledWith("/api/mcp-apps", {
|
|
68
|
+
method: "POST",
|
|
69
|
+
headers: {
|
|
70
|
+
"content-type": "application/json",
|
|
71
|
+
authorization: "Bearer workspace-a",
|
|
72
|
+
},
|
|
73
|
+
body: JSON.stringify({
|
|
74
|
+
method: "tools/call",
|
|
75
|
+
params: { name: "search" },
|
|
76
|
+
}),
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
view.unmount();
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("keeps the URL and authorization from one committed options snapshot", async () => {
|
|
83
|
+
const fetch = vi.fn(async () => Response.json({ content: [] }));
|
|
84
|
+
let currentHost: McpAppsHost | undefined;
|
|
85
|
+
|
|
86
|
+
const Probe = ({
|
|
87
|
+
url,
|
|
88
|
+
authorization,
|
|
89
|
+
}: {
|
|
90
|
+
url: string;
|
|
91
|
+
authorization: string;
|
|
92
|
+
}) => {
|
|
93
|
+
const host = useResource(
|
|
94
|
+
McpAppsRemoteHost({
|
|
95
|
+
url,
|
|
96
|
+
fetch,
|
|
97
|
+
headers: { authorization },
|
|
98
|
+
}),
|
|
99
|
+
);
|
|
100
|
+
useLayoutEffect(() => {
|
|
101
|
+
currentHost = host;
|
|
102
|
+
void host.callTool({ name: "layout-request" });
|
|
103
|
+
}, [host]);
|
|
104
|
+
return null;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const view = render(
|
|
108
|
+
<Probe url="/workspace-a/mcp" authorization="Bearer workspace-a" />,
|
|
109
|
+
);
|
|
110
|
+
fetch.mockClear();
|
|
111
|
+
|
|
112
|
+
view.rerender(
|
|
113
|
+
<Probe url="/workspace-b/mcp" authorization="Bearer workspace-b" />,
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
expect(fetch).toHaveBeenNthCalledWith(1, "/workspace-b/mcp", {
|
|
117
|
+
method: "POST",
|
|
118
|
+
headers: {
|
|
119
|
+
"content-type": "application/json",
|
|
120
|
+
authorization: "Bearer workspace-b",
|
|
121
|
+
},
|
|
122
|
+
body: JSON.stringify({
|
|
123
|
+
method: "tools/call",
|
|
124
|
+
params: { name: "layout-request" },
|
|
125
|
+
}),
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
await currentHost?.callTool({ name: "committed-request" });
|
|
129
|
+
|
|
130
|
+
expect(fetch).toHaveBeenNthCalledWith(2, "/workspace-b/mcp", {
|
|
131
|
+
method: "POST",
|
|
132
|
+
headers: {
|
|
133
|
+
"content-type": "application/json",
|
|
134
|
+
authorization: "Bearer workspace-b",
|
|
135
|
+
},
|
|
136
|
+
body: JSON.stringify({
|
|
137
|
+
method: "tools/call",
|
|
138
|
+
params: { name: "committed-request" },
|
|
139
|
+
}),
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
view.unmount();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("refreshes pending options when a URL switch render retries", async () => {
|
|
146
|
+
let authorization = "Bearer workspace-b-old";
|
|
147
|
+
let resumed = false;
|
|
148
|
+
let resume: (() => void) | undefined;
|
|
149
|
+
const pending = new Promise<void>((resolve) => {
|
|
150
|
+
resume = () => {
|
|
151
|
+
resumed = true;
|
|
152
|
+
resolve();
|
|
153
|
+
};
|
|
154
|
+
});
|
|
155
|
+
const fetch = vi.fn(async () => Response.json({ content: [] }));
|
|
156
|
+
|
|
157
|
+
const Probe = ({ url }: { url: string }) => {
|
|
158
|
+
const host = useResource(
|
|
159
|
+
McpAppsRemoteHost({
|
|
160
|
+
url,
|
|
161
|
+
fetch,
|
|
162
|
+
headers: {
|
|
163
|
+
authorization:
|
|
164
|
+
url === "/workspace-a/mcp" ? "Bearer workspace-a" : authorization,
|
|
165
|
+
},
|
|
166
|
+
}),
|
|
167
|
+
);
|
|
168
|
+
useLayoutEffect(() => {
|
|
169
|
+
void host.callTool({ name: "layout-request" });
|
|
170
|
+
}, [host]);
|
|
171
|
+
if (url === "/workspace-b/mcp" && !resumed) throw pending;
|
|
172
|
+
return <span>{url}</span>;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const view = render(
|
|
176
|
+
<Suspense fallback={null}>
|
|
177
|
+
<Probe url="/workspace-a/mcp" />
|
|
178
|
+
</Suspense>,
|
|
179
|
+
);
|
|
180
|
+
try {
|
|
181
|
+
fetch.mockClear();
|
|
182
|
+
|
|
183
|
+
act(() => {
|
|
184
|
+
startTransition(() => {
|
|
185
|
+
view.rerender(
|
|
186
|
+
<Suspense fallback={null}>
|
|
187
|
+
<Probe url="/workspace-b/mcp" />
|
|
188
|
+
</Suspense>,
|
|
189
|
+
);
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
expect(view.container.textContent).toBe("/workspace-a/mcp");
|
|
193
|
+
|
|
194
|
+
authorization = "Bearer workspace-b-new";
|
|
195
|
+
await act(async () => resume?.());
|
|
196
|
+
await waitFor(() =>
|
|
197
|
+
expect(view.container.textContent).toBe("/workspace-b/mcp"),
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
expect(fetch).toHaveBeenCalledWith("/workspace-b/mcp", {
|
|
201
|
+
method: "POST",
|
|
202
|
+
headers: {
|
|
203
|
+
"content-type": "application/json",
|
|
204
|
+
authorization: "Bearer workspace-b-new",
|
|
205
|
+
},
|
|
206
|
+
body: JSON.stringify({
|
|
207
|
+
method: "tools/call",
|
|
208
|
+
params: { name: "layout-request" },
|
|
209
|
+
}),
|
|
210
|
+
});
|
|
211
|
+
} finally {
|
|
212
|
+
view.unmount();
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useMemo, useRef } from "react";
|
|
1
|
+
import { useEffect, useMemo, useRef } from "react";
|
|
2
2
|
import { resource } from "@assistant-ui/tap";
|
|
3
3
|
import type {
|
|
4
4
|
McpAppResource,
|
|
@@ -111,20 +111,17 @@ const useMcpAppsRemoteHost = (
|
|
|
111
111
|
options: McpAppsRemoteHostOptions,
|
|
112
112
|
): McpAppsHost => {
|
|
113
113
|
const optionsRef = useRef(options);
|
|
114
|
-
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
optionsRef.current = options;
|
|
116
|
+
});
|
|
115
117
|
|
|
116
118
|
const url = options.url;
|
|
117
119
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
...(current.fetch !== undefined ? { fetch: current.fetch } : {}),
|
|
124
|
-
...(current.headers !== undefined ? { headers: current.headers } : {}),
|
|
125
|
-
};
|
|
126
|
-
};
|
|
127
|
-
return {
|
|
120
|
+
const hostState = useMemo(() => {
|
|
121
|
+
let pendingOptions = options;
|
|
122
|
+
const getCurrentOptions = () =>
|
|
123
|
+
optionsRef.current.url === url ? optionsRef.current : pendingOptions;
|
|
124
|
+
const host: McpAppsHost = {
|
|
128
125
|
loadResource: async (params) => {
|
|
129
126
|
const options = getCurrentOptions();
|
|
130
127
|
return parseMcpAppResource(
|
|
@@ -139,7 +136,26 @@ const useMcpAppsRemoteHost = (
|
|
|
139
136
|
listResources: (params) =>
|
|
140
137
|
postToHost(getCurrentOptions(), "resources/list", params),
|
|
141
138
|
};
|
|
139
|
+
return {
|
|
140
|
+
host,
|
|
141
|
+
updatePendingOptions: (next: McpAppsRemoteHostOptions) => {
|
|
142
|
+
pendingOptions = next;
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
// oxlint-disable-next-line react/exhaustive-deps -- URL changes replace the host identity; pending and same-URL options are refreshed outside the memo
|
|
142
146
|
}, [url]);
|
|
147
|
+
|
|
148
|
+
// The pending snapshot is read only while the committed ref still lags this
|
|
149
|
+
// host's URL, and every write to it carries that same render's options, so
|
|
150
|
+
// no render can pair one URL with another's credentials. A committed host can
|
|
151
|
+
// be written here (a child layout effect re-rendering synchronously runs
|
|
152
|
+
// before passive effects publish the ref), which stays coherent for the same
|
|
153
|
+
// reason.
|
|
154
|
+
if (optionsRef.current.url !== url) {
|
|
155
|
+
hostState.updatePendingOptions(options);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return hostState.host;
|
|
143
159
|
};
|
|
144
160
|
|
|
145
161
|
export const McpAppsRemoteHost = resource(useMcpAppsRemoteHost);
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
import { act, startTransition, Suspense } from "react";
|
|
3
|
+
import { cleanup, render } from "@testing-library/react";
|
|
4
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
5
|
+
import type {
|
|
6
|
+
SandboxBridge,
|
|
7
|
+
SandboxHostProps,
|
|
8
|
+
} from "../sandbox-host/SandboxHost";
|
|
9
|
+
import type { CreateMcpAppBridgeOptions, McpAppBridge } from "./bridge";
|
|
10
|
+
import { MCP_APP_MIME_TYPE } from "./types";
|
|
11
|
+
|
|
12
|
+
const { sandboxHostMock, createMcpAppBridgeMock } = vi.hoisted(() => ({
|
|
13
|
+
sandboxHostMock: vi.fn(),
|
|
14
|
+
createMcpAppBridgeMock: vi.fn(),
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
vi.mock("../sandbox-host/SandboxHost", () => ({
|
|
18
|
+
SandboxHost: sandboxHostMock,
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
vi.mock("./bridge", async (importOriginal) => ({
|
|
22
|
+
...(await importOriginal()),
|
|
23
|
+
createMcpAppBridge: createMcpAppBridgeMock,
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
import { McpAppFrame } from "./app-frame";
|
|
27
|
+
|
|
28
|
+
describe("McpAppFrame", () => {
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
cleanup();
|
|
31
|
+
vi.clearAllMocks();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("keeps bridge options scoped to committed renders", async () => {
|
|
35
|
+
let committedCreateBridge: SandboxHostProps["createBridge"] | null = null;
|
|
36
|
+
sandboxHostMock.mockImplementation((props: SandboxHostProps) => {
|
|
37
|
+
committedCreateBridge ??= props.createBridge;
|
|
38
|
+
return null;
|
|
39
|
+
});
|
|
40
|
+
const bridge: McpAppBridge = {
|
|
41
|
+
onMessage: vi.fn(),
|
|
42
|
+
dispose: vi.fn(),
|
|
43
|
+
notifyToolInput: vi.fn(),
|
|
44
|
+
notifyToolResult: vi.fn(),
|
|
45
|
+
notifyHostContextChanged: vi.fn(),
|
|
46
|
+
};
|
|
47
|
+
createMcpAppBridgeMock.mockReturnValue(bridge);
|
|
48
|
+
const callToolA = vi.fn();
|
|
49
|
+
const callToolB = vi.fn();
|
|
50
|
+
const interruptedRender = vi.fn();
|
|
51
|
+
const pending = new Promise<never>(() => {});
|
|
52
|
+
const Block = () => {
|
|
53
|
+
interruptedRender();
|
|
54
|
+
throw pending;
|
|
55
|
+
};
|
|
56
|
+
const view = (
|
|
57
|
+
workspace: string,
|
|
58
|
+
callTool: typeof callToolA,
|
|
59
|
+
blocked: boolean,
|
|
60
|
+
) => (
|
|
61
|
+
<Suspense fallback={null}>
|
|
62
|
+
<McpAppFrame
|
|
63
|
+
app={{ resourceUri: "ui://example/widget" }}
|
|
64
|
+
resource={{
|
|
65
|
+
uri: "ui://example/widget",
|
|
66
|
+
mimeType: MCP_APP_MIME_TYPE,
|
|
67
|
+
html: "",
|
|
68
|
+
}}
|
|
69
|
+
handlers={{ callTool }}
|
|
70
|
+
hostContext={{ workspace }}
|
|
71
|
+
/>
|
|
72
|
+
{blocked ? <Block /> : null}
|
|
73
|
+
</Suspense>
|
|
74
|
+
);
|
|
75
|
+
const rendered = render(view("workspace-a", callToolA, false));
|
|
76
|
+
|
|
77
|
+
act(() => {
|
|
78
|
+
startTransition(() =>
|
|
79
|
+
rendered.rerender(view("workspace-b", callToolB, true)),
|
|
80
|
+
);
|
|
81
|
+
});
|
|
82
|
+
expect(interruptedRender).toHaveBeenCalled();
|
|
83
|
+
expect(committedCreateBridge).not.toBeNull();
|
|
84
|
+
|
|
85
|
+
const sandboxBridge: SandboxBridge = committedCreateBridge!(
|
|
86
|
+
{
|
|
87
|
+
iframe: document.createElement("iframe"),
|
|
88
|
+
origin: "https://widget.example",
|
|
89
|
+
sendMessage: vi.fn(),
|
|
90
|
+
},
|
|
91
|
+
{ setHeight: vi.fn() },
|
|
92
|
+
);
|
|
93
|
+
const options = createMcpAppBridgeMock.mock
|
|
94
|
+
.calls[0]![0] as CreateMcpAppBridgeOptions;
|
|
95
|
+
expect(options.hostContext).toEqual({ workspace: "workspace-a" });
|
|
96
|
+
await options.handlers?.callTool?.({ name: "search" });
|
|
97
|
+
expect(callToolA).toHaveBeenCalledOnce();
|
|
98
|
+
expect(callToolB).not.toHaveBeenCalled();
|
|
99
|
+
|
|
100
|
+
sandboxBridge.dispose();
|
|
101
|
+
});
|
|
102
|
+
});
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
type MutableRefObject,
|
|
5
|
+
useEffect,
|
|
6
|
+
useLayoutEffect,
|
|
7
|
+
useRef,
|
|
8
|
+
} from "react";
|
|
4
9
|
import { type McpAppBridge, createMcpAppBridge } from "./bridge";
|
|
5
10
|
import {
|
|
6
11
|
SandboxHost,
|
|
@@ -121,14 +126,22 @@ export function McpAppFrame({
|
|
|
121
126
|
undefined,
|
|
122
127
|
);
|
|
123
128
|
|
|
124
|
-
const liveRef = useRef<LiveSnapshot>(
|
|
125
|
-
liveRef.current = {
|
|
129
|
+
const liveRef = useRef<LiveSnapshot>({
|
|
126
130
|
handlers,
|
|
127
131
|
hostInfo,
|
|
128
132
|
hostContext,
|
|
129
133
|
input,
|
|
130
134
|
output,
|
|
131
|
-
};
|
|
135
|
+
});
|
|
136
|
+
useLayoutEffect(() => {
|
|
137
|
+
liveRef.current = {
|
|
138
|
+
handlers,
|
|
139
|
+
hostInfo,
|
|
140
|
+
hostContext,
|
|
141
|
+
input,
|
|
142
|
+
output,
|
|
143
|
+
};
|
|
144
|
+
}, [handlers, hostInfo, hostContext, input, output]);
|
|
132
145
|
|
|
133
146
|
const createBridge = (
|
|
134
147
|
frame: SandboxHostFrame,
|
package/src/mcp-apps/index.ts
CHANGED
|
@@ -27,7 +27,7 @@ describe("AssistantFrame Integration", () => {
|
|
|
27
27
|
parentHandler({
|
|
28
28
|
data,
|
|
29
29
|
source: iframeWindow,
|
|
30
|
-
origin:
|
|
30
|
+
origin: window.location.origin,
|
|
31
31
|
} as MessageEvent);
|
|
32
32
|
});
|
|
33
33
|
}
|
|
@@ -44,7 +44,7 @@ describe("AssistantFrame Integration", () => {
|
|
|
44
44
|
iframeHandler({
|
|
45
45
|
data,
|
|
46
46
|
source: parentWindow, // parent window is the source for subscription
|
|
47
|
-
origin:
|
|
47
|
+
origin: window.location.origin,
|
|
48
48
|
} as MessageEvent);
|
|
49
49
|
});
|
|
50
50
|
}
|
|
@@ -104,7 +104,7 @@ describe("AssistantFrame Integration", () => {
|
|
|
104
104
|
type: "model-context-request",
|
|
105
105
|
}),
|
|
106
106
|
}),
|
|
107
|
-
|
|
107
|
+
window.location.origin,
|
|
108
108
|
);
|
|
109
109
|
});
|
|
110
110
|
|
|
@@ -88,7 +88,7 @@ All messages are wrapped with a channel identifier to avoid conflicts with other
|
|
|
88
88
|
|
|
89
89
|
#### Security Considerations
|
|
90
90
|
|
|
91
|
-
1. **Origin Validation**: Both sides can specify `targetOrigin`
|
|
91
|
+
1. **Origin Validation**: Both sides default to the current page's origin and can specify an exact `targetOrigin` for cross-origin frames; providers share a fail-closed origin policy
|
|
92
92
|
2. **Window Reference**: Host (parent) only accepts messages from the specific iframe window it's connected to
|
|
93
93
|
3. **Message Channel**: Using a unique channel identifier prevents cross-talk with other postMessage users
|
|
94
94
|
|
|
@@ -20,7 +20,7 @@ type UseAssistantFrameHostOptions = {
|
|
|
20
20
|
*
|
|
21
21
|
* useAssistantFrameHost({
|
|
22
22
|
* iframeRef,
|
|
23
|
-
* targetOrigin: "https://trusted-domain.com",
|
|
23
|
+
* targetOrigin: "https://trusted-domain.com",
|
|
24
24
|
* });
|
|
25
25
|
*
|
|
26
26
|
* return <iframe ref={iframeRef} src="..." />;
|
|
@@ -29,7 +29,7 @@ type UseAssistantFrameHostOptions = {
|
|
|
29
29
|
*/
|
|
30
30
|
export const useAssistantFrameHost = ({
|
|
31
31
|
iframeRef,
|
|
32
|
-
targetOrigin
|
|
32
|
+
targetOrigin,
|
|
33
33
|
register,
|
|
34
34
|
}: UseAssistantFrameHostOptions): void => {
|
|
35
35
|
useEffect(() => {
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
useContext,
|
|
13
13
|
} from "react";
|
|
14
14
|
import { useAui } from "@assistant-ui/store";
|
|
15
|
-
import { useComposedRefs } from "
|
|
15
|
+
import { useComposedRefs } from "radix-ui/internal";
|
|
16
16
|
import { tool } from "@assistant-ui/core";
|
|
17
17
|
|
|
18
18
|
const click = tool({
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { forwardRef } from "react";
|
|
4
4
|
import type { ActionButtonProps } from "../../utils/createActionButton";
|
|
5
|
-
import { composeEventHandlers } from "
|
|
5
|
+
import { composeEventHandlers } from "radix-ui/internal";
|
|
6
6
|
import { Primitive } from "../../utils/Primitive";
|
|
7
7
|
import { useActionBarCopy } from "@assistant-ui/core/react";
|
|
8
8
|
import { useAuiState } from "@assistant-ui/store";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { forwardRef, useCallback } from "react";
|
|
4
4
|
import type { ActionButtonProps } from "../../utils/createActionButton";
|
|
5
|
-
import { composeEventHandlers } from "
|
|
5
|
+
import { composeEventHandlers } from "radix-ui/internal";
|
|
6
6
|
import { Primitive } from "../../utils/Primitive";
|
|
7
7
|
import { useAuiState, useAui } from "@assistant-ui/store";
|
|
8
8
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { forwardRef } from "react";
|
|
4
4
|
import type { ActionButtonProps } from "../../utils/createActionButton";
|
|
5
|
-
import { composeEventHandlers } from "
|
|
5
|
+
import { composeEventHandlers } from "radix-ui/internal";
|
|
6
6
|
import { Primitive } from "../../utils/Primitive";
|
|
7
7
|
import { useAuiState } from "@assistant-ui/store";
|
|
8
8
|
import { useActionBarFeedbackNegative as useActionBarFeedbackNegativeBehavior } from "@assistant-ui/core/react";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { forwardRef } from "react";
|
|
4
4
|
import type { ActionButtonProps } from "../../utils/createActionButton";
|
|
5
|
-
import { composeEventHandlers } from "
|
|
5
|
+
import { composeEventHandlers } from "radix-ui/internal";
|
|
6
6
|
import { useAuiState } from "@assistant-ui/store";
|
|
7
7
|
import { Primitive } from "../../utils/Primitive";
|
|
8
8
|
import { useActionBarFeedbackPositive as useActionBarFeedbackPositiveBehavior } from "@assistant-ui/core/react";
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { forwardRef } from "react";
|
|
4
4
|
import type { ActionButtonProps } from "../../utils/createActionButton";
|
|
5
5
|
import { Primitive } from "../../utils/Primitive";
|
|
6
|
-
import { composeEventHandlers } from "
|
|
6
|
+
import { composeEventHandlers } from "radix-ui/internal";
|
|
7
7
|
import { useActionBarStopSpeaking as useActionBarStopSpeakingBehavior } from "@assistant-ui/core/react";
|
|
8
8
|
|
|
9
9
|
const useActionBarStopSpeaking = () => {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui";
|
|
2
|
-
import type {
|
|
2
|
+
import type { Context } from "radix-ui/internal";
|
|
3
3
|
|
|
4
4
|
export const useDropdownMenuScope: ReturnType<
|
|
5
5
|
typeof DropdownMenuPrimitive.createDropdownMenuScope
|
|
6
6
|
> = DropdownMenuPrimitive.createDropdownMenuScope();
|
|
7
7
|
|
|
8
|
-
export type ScopedProps<P> = P & { __scopeActionBarMore?: Scope };
|
|
8
|
+
export type ScopedProps<P> = P & { __scopeActionBarMore?: Context.Scope };
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
forwardRef,
|
|
7
7
|
} from "react";
|
|
8
8
|
import { Popover as PopoverPrimitive } from "radix-ui";
|
|
9
|
-
import { composeEventHandlers } from "
|
|
9
|
+
import { composeEventHandlers } from "radix-ui/internal";
|
|
10
10
|
import type { WithRenderPropProps } from "../../utils/Primitive";
|
|
11
11
|
import { PopoverRenderContent } from "./popoverRenderPrimitives";
|
|
12
12
|
import { type ScopedProps, usePopoverScope } from "./scope";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Popover as PopoverPrimitive } from "radix-ui";
|
|
2
|
-
import type {
|
|
2
|
+
import type { Context } from "radix-ui/internal";
|
|
3
3
|
|
|
4
4
|
export const usePopoverScope: ReturnType<
|
|
5
5
|
typeof PopoverPrimitive.createPopoverScope
|
|
6
6
|
> = PopoverPrimitive.createPopoverScope();
|
|
7
|
-
export type ScopedProps<P> = P & { __scopeAssistantModal?: Scope };
|
|
7
|
+
export type ScopedProps<P> = P & { __scopeAssistantModal?: Context.Scope };
|