@assistant-ui/react 0.15.15 → 0.15.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (267) hide show
  1. package/README.md +3 -3
  2. package/dist/devtools/DevToolsHooks.d.ts +0 -2
  3. package/dist/devtools/DevToolsHooks.d.ts.map +1 -1
  4. package/dist/devtools/DevToolsHooks.js +10 -12
  5. package/dist/devtools/DevToolsHooks.js.map +1 -1
  6. package/dist/index.d.ts +4 -3
  7. package/dist/index.js +2 -2
  8. package/dist/mcp-apps/McpAppRenderer.d.ts +6 -1
  9. package/dist/mcp-apps/McpAppRenderer.d.ts.map +1 -1
  10. package/dist/mcp-apps/McpAppRenderer.js +20 -13
  11. package/dist/mcp-apps/McpAppRenderer.js.map +1 -1
  12. package/dist/mcp-apps/McpAppsRemoteHost.d.ts.map +1 -1
  13. package/dist/mcp-apps/McpAppsRemoteHost.js +20 -17
  14. package/dist/mcp-apps/McpAppsRemoteHost.js.map +1 -1
  15. package/dist/mcp-apps/app-frame.d.ts.map +1 -1
  16. package/dist/mcp-apps/app-frame.js +189 -94
  17. package/dist/mcp-apps/app-frame.js.map +1 -1
  18. package/dist/mcp-apps/bridge.d.ts.map +1 -1
  19. package/dist/mcp-apps/bridge.js +2 -8
  20. package/dist/mcp-apps/bridge.js.map +1 -1
  21. package/dist/mcp-apps/index.d.ts +2 -2
  22. package/dist/model-context/frame/useAssistantFrameHost.d.ts +1 -1
  23. package/dist/model-context/frame/useAssistantFrameHost.js +10 -11
  24. package/dist/model-context/frame/useAssistantFrameHost.js.map +1 -1
  25. package/dist/model-context/makeAssistantVisible.js +1 -1
  26. package/dist/model-context/makeAssistantVisible.js.map +1 -1
  27. package/dist/primitives/actionBar/ActionBarCopy.js +3 -3
  28. package/dist/primitives/actionBar/ActionBarCopy.js.map +1 -1
  29. package/dist/primitives/actionBar/ActionBarExportMarkdown.d.ts.map +1 -1
  30. package/dist/primitives/actionBar/ActionBarExportMarkdown.js +7 -4
  31. package/dist/primitives/actionBar/ActionBarExportMarkdown.js.map +1 -1
  32. package/dist/primitives/actionBar/ActionBarFeedbackNegative.js +3 -3
  33. package/dist/primitives/actionBar/ActionBarFeedbackNegative.js.map +1 -1
  34. package/dist/primitives/actionBar/ActionBarFeedbackPositive.js +3 -3
  35. package/dist/primitives/actionBar/ActionBarFeedbackPositive.js.map +1 -1
  36. package/dist/primitives/actionBar/ActionBarRoot.js.map +1 -1
  37. package/dist/primitives/actionBar/ActionBarStopSpeaking.js +3 -3
  38. package/dist/primitives/actionBar/ActionBarStopSpeaking.js.map +1 -1
  39. package/dist/primitives/actionBarMore/ActionBarMoreContent.js.map +1 -1
  40. package/dist/primitives/actionBarMore/ActionBarMoreItem.js.map +1 -1
  41. package/dist/primitives/actionBarMore/ActionBarMoreRoot.js.map +1 -1
  42. package/dist/primitives/actionBarMore/ActionBarMoreSeparator.js.map +1 -1
  43. package/dist/primitives/actionBarMore/ActionBarMoreTrigger.js.map +1 -1
  44. package/dist/primitives/actionBarMore/scope.d.ts +2 -2
  45. package/dist/primitives/actionBarMore/scope.d.ts.map +1 -1
  46. package/dist/primitives/actionBarMore/scope.js.map +1 -1
  47. package/dist/primitives/assistantModal/AssistantModalAnchor.js.map +1 -1
  48. package/dist/primitives/assistantModal/AssistantModalContent.js +1 -1
  49. package/dist/primitives/assistantModal/AssistantModalContent.js.map +1 -1
  50. package/dist/primitives/assistantModal/AssistantModalRoot.js.map +1 -1
  51. package/dist/primitives/assistantModal/AssistantModalTrigger.js.map +1 -1
  52. package/dist/primitives/assistantModal/scope.d.ts +2 -2
  53. package/dist/primitives/assistantModal/scope.d.ts.map +1 -1
  54. package/dist/primitives/assistantModal/scope.js.map +1 -1
  55. package/dist/primitives/branchPicker/BranchPickerRoot.d.ts.map +1 -1
  56. package/dist/primitives/branchPicker/BranchPickerRoot.js +20 -15
  57. package/dist/primitives/branchPicker/BranchPickerRoot.js.map +1 -1
  58. package/dist/primitives/composer/ComposerAttachmentDropzone.js +1 -1
  59. package/dist/primitives/composer/ComposerAttachmentDropzone.js.map +1 -1
  60. package/dist/primitives/composer/ComposerDictationTranscript.d.ts +2 -2
  61. package/dist/primitives/composer/ComposerDictationTranscript.js +2 -2
  62. package/dist/primitives/composer/ComposerDictationTranscript.js.map +1 -1
  63. package/dist/primitives/composer/ComposerInput.js +1 -3
  64. package/dist/primitives/composer/ComposerInput.js.map +1 -1
  65. package/dist/primitives/composer/ComposerQuote.js +5 -5
  66. package/dist/primitives/composer/ComposerQuote.js.map +1 -1
  67. package/dist/primitives/composer/ComposerRoot.js +3 -3
  68. package/dist/primitives/composer/ComposerRoot.js.map +1 -1
  69. package/dist/primitives/composer/trigger/TriggerPopover.d.ts +5 -0
  70. package/dist/primitives/composer/trigger/TriggerPopover.d.ts.map +1 -1
  71. package/dist/primitives/composer/trigger/TriggerPopover.js +157 -130
  72. package/dist/primitives/composer/trigger/TriggerPopover.js.map +1 -1
  73. package/dist/primitives/composer/trigger/TriggerPopoverBack.js +3 -3
  74. package/dist/primitives/composer/trigger/TriggerPopoverBack.js.map +1 -1
  75. package/dist/primitives/composer/trigger/TriggerPopoverCategories.js +4 -4
  76. package/dist/primitives/composer/trigger/TriggerPopoverCategories.js.map +1 -1
  77. package/dist/primitives/composer/trigger/TriggerPopoverItems.js +4 -4
  78. package/dist/primitives/composer/trigger/TriggerPopoverItems.js.map +1 -1
  79. package/dist/primitives/composer/trigger/TriggerPopoverResource.d.ts +2 -0
  80. package/dist/primitives/composer/trigger/TriggerPopoverResource.d.ts.map +1 -1
  81. package/dist/primitives/composer/trigger/TriggerPopoverResource.js +63 -61
  82. package/dist/primitives/composer/trigger/TriggerPopoverResource.js.map +1 -1
  83. package/dist/primitives/composer/trigger/TriggerPopoverRootContext.d.ts +2 -0
  84. package/dist/primitives/composer/trigger/TriggerPopoverRootContext.d.ts.map +1 -1
  85. package/dist/primitives/composer/trigger/TriggerPopoverRootContext.js.map +1 -1
  86. package/dist/primitives/composer/trigger/detectTrigger.d.ts +21 -1
  87. package/dist/primitives/composer/trigger/detectTrigger.d.ts.map +1 -0
  88. package/dist/primitives/composer/trigger/detectTrigger.js +17 -3
  89. package/dist/primitives/composer/trigger/detectTrigger.js.map +1 -1
  90. package/dist/primitives/composer/trigger/index.d.ts +3 -1
  91. package/dist/primitives/composer/trigger/index.d.ts.map +1 -1
  92. package/dist/primitives/composer/trigger/index.js.map +1 -1
  93. package/dist/primitives/composer/trigger/triggerDetectionResource.d.ts +3 -4
  94. package/dist/primitives/composer/trigger/triggerDetectionResource.d.ts.map +1 -1
  95. package/dist/primitives/composer/trigger/triggerDetectionResource.js +15 -14
  96. package/dist/primitives/composer/trigger/triggerDetectionResource.js.map +1 -1
  97. package/dist/primitives/composer/trigger/triggerSelectionResource.d.ts.map +1 -1
  98. package/dist/primitives/composer/trigger/triggerSelectionResource.js +10 -7
  99. package/dist/primitives/composer/trigger/triggerSelectionResource.js.map +1 -1
  100. package/dist/primitives/composer.d.ts +3 -2
  101. package/dist/primitives/composer.js.map +1 -1
  102. package/dist/primitives/error/ErrorMessage.js.map +1 -1
  103. package/dist/primitives/message/MessageIf.js.map +1 -1
  104. package/dist/primitives/message/MessageParts.js.map +1 -1
  105. package/dist/primitives/message/MessagePartsGrouped.js.map +1 -1
  106. package/dist/primitives/message/MessageRoot.js +4 -4
  107. package/dist/primitives/message/MessageRoot.js.map +1 -1
  108. package/dist/primitives/message.js +1 -1
  109. package/dist/primitives/messagePart/MessagePartText.js.map +1 -1
  110. package/dist/primitives/selectionToolbar/SelectionToolbarQuote.js +3 -3
  111. package/dist/primitives/selectionToolbar/SelectionToolbarQuote.js.map +1 -1
  112. package/dist/primitives/selectionToolbar/SelectionToolbarRoot.js +3 -3
  113. package/dist/primitives/selectionToolbar/SelectionToolbarRoot.js.map +1 -1
  114. package/dist/primitives/thread/ThreadIf.js.map +1 -1
  115. package/dist/primitives/thread/ThreadRoot.d.ts +3 -0
  116. package/dist/primitives/thread/ThreadRoot.d.ts.map +1 -1
  117. package/dist/primitives/thread/ThreadRoot.js +3 -0
  118. package/dist/primitives/thread/ThreadRoot.js.map +1 -1
  119. package/dist/primitives/thread/ThreadViewport.js +3 -3
  120. package/dist/primitives/thread/ThreadViewport.js.map +1 -1
  121. package/dist/primitives/thread/ThreadViewportFooter.js +3 -3
  122. package/dist/primitives/thread/ThreadViewportFooter.js.map +1 -1
  123. package/dist/primitives/thread/useThreadViewportAutoScroll.js +1 -1
  124. package/dist/primitives/thread/useThreadViewportAutoScroll.js.map +1 -1
  125. package/dist/primitives/threadList/ThreadListNew.js +3 -3
  126. package/dist/primitives/threadList/ThreadListNew.js.map +1 -1
  127. package/dist/primitives/threadListFocusGroup.d.ts +2 -1
  128. package/dist/primitives/threadListFocusGroup.d.ts.map +1 -1
  129. package/dist/primitives/threadListFocusGroup.js +2 -2
  130. package/dist/primitives/threadListFocusGroup.js.map +1 -1
  131. package/dist/primitives/threadListItem/ThreadListItemRoot.js +3 -3
  132. package/dist/primitives/threadListItem/ThreadListItemRoot.js.map +1 -1
  133. package/dist/primitives/threadListItem/ThreadListItemTrigger.js +1 -1
  134. package/dist/primitives/threadListItem/ThreadListItemTrigger.js.map +1 -1
  135. package/dist/primitives/threadListItemMore/ThreadListItemMoreContent.js +1 -1
  136. package/dist/primitives/threadListItemMore/ThreadListItemMoreContent.js.map +1 -1
  137. package/dist/primitives/threadListItemMore/ThreadListItemMoreItem.js.map +1 -1
  138. package/dist/primitives/threadListItemMore/ThreadListItemMoreRoot.js +1 -1
  139. package/dist/primitives/threadListItemMore/ThreadListItemMoreRoot.js.map +1 -1
  140. package/dist/primitives/threadListItemMore/ThreadListItemMoreSeparator.js.map +1 -1
  141. package/dist/primitives/threadListItemMore/ThreadListItemMoreTrigger.js +1 -2
  142. package/dist/primitives/threadListItemMore/ThreadListItemMoreTrigger.js.map +1 -1
  143. package/dist/primitives/threadListItemMore/scope.d.ts +2 -2
  144. package/dist/primitives/threadListItemMore/scope.d.ts.map +1 -1
  145. package/dist/primitives/threadListItemMore/scope.js.map +1 -1
  146. package/dist/sandbox-host/SandboxHost.d.ts.map +1 -1
  147. package/dist/sandbox-host/SandboxHost.js +138 -68
  148. package/dist/sandbox-host/SandboxHost.js.map +1 -1
  149. package/dist/unstable/useComposerInputHistory.js +1 -1
  150. package/dist/unstable/useLiveCompletionAdapter.js +3 -1
  151. package/dist/unstable/useLiveCompletionAdapter.js.map +1 -1
  152. package/dist/unstable/useSlashCommandAdapter.js +41 -27
  153. package/dist/unstable/useSlashCommandAdapter.js.map +1 -1
  154. package/dist/utils/Primitive.d.ts +2 -2
  155. package/dist/utils/Primitive.js +2 -2
  156. package/dist/utils/Primitive.js.map +1 -1
  157. package/dist/utils/createActionButton.js +3 -3
  158. package/dist/utils/createActionButton.js.map +1 -1
  159. package/dist/utils/hooks/useOnResizeContent.js +1 -1
  160. package/dist/utils/hooks/useOnResizeContent.js.map +1 -1
  161. package/dist/utils/hooks/useOnScrollToBottom.js +1 -1
  162. package/dist/utils/hooks/useOnScrollToBottom.js.map +1 -1
  163. package/dist/utils/invokeCallbackSafely.d.ts +5 -0
  164. package/dist/utils/invokeCallbackSafely.d.ts.map +1 -0
  165. package/dist/utils/invokeCallbackSafely.js +15 -0
  166. package/dist/utils/invokeCallbackSafely.js.map +1 -0
  167. package/dist/utils/smooth/SmoothContext.d.ts +30 -6
  168. package/dist/utils/smooth/SmoothContext.d.ts.map +1 -1
  169. package/dist/utils/smooth/useSmooth.d.ts +3 -0
  170. package/dist/utils/smooth/useSmooth.d.ts.map +1 -1
  171. package/dist/utils/smooth/useSmooth.js +17 -2
  172. package/dist/utils/smooth/useSmooth.js.map +1 -1
  173. package/dist/utils/useToolArgsFieldStatus.d.ts +5 -1
  174. package/package.json +12 -20
  175. package/src/devtools/DevToolsHooks.test.ts +40 -0
  176. package/src/devtools/DevToolsHooks.ts +10 -15
  177. package/src/index.ts +9 -1
  178. package/src/mcp-apps/McpAppRenderer.test.tsx +133 -4
  179. package/src/mcp-apps/McpAppRenderer.tsx +28 -21
  180. package/src/mcp-apps/McpAppsRemoteHost.concurrent.test.tsx +215 -0
  181. package/src/mcp-apps/McpAppsRemoteHost.ts +28 -12
  182. package/src/mcp-apps/app-frame.test.tsx +102 -0
  183. package/src/mcp-apps/app-frame.tsx +17 -4
  184. package/src/mcp-apps/bridge.test.ts +21 -0
  185. package/src/mcp-apps/bridge.ts +2 -14
  186. package/src/mcp-apps/index.ts +1 -0
  187. package/src/model-context/frame/AssistantFrame.test.ts +3 -3
  188. package/src/model-context/frame/SPEC_AssistantFrame.md +1 -1
  189. package/src/model-context/frame/useAssistantFrameHost.ts +2 -2
  190. package/src/model-context/makeAssistantVisible.tsx +1 -1
  191. package/src/primitives/actionBar/ActionBarCopy.tsx +1 -1
  192. package/src/primitives/actionBar/ActionBarExportMarkdown.test.tsx +67 -0
  193. package/src/primitives/actionBar/ActionBarExportMarkdown.tsx +4 -2
  194. package/src/primitives/actionBar/ActionBarFeedbackNegative.tsx +1 -1
  195. package/src/primitives/actionBar/ActionBarFeedbackPositive.tsx +1 -1
  196. package/src/primitives/actionBar/ActionBarStopSpeaking.tsx +1 -1
  197. package/src/primitives/actionBarMore/scope.ts +2 -2
  198. package/src/primitives/assistantModal/AssistantModalContent.tsx +1 -1
  199. package/src/primitives/assistantModal/scope.ts +2 -2
  200. package/src/primitives/branchPicker/BranchPickerRoot.tsx +5 -3
  201. package/src/primitives/composer/ComposerAttachmentDropzone.tsx +1 -1
  202. package/src/primitives/composer/ComposerDictationTranscript.tsx +2 -2
  203. package/src/primitives/composer/ComposerInput.test.tsx +2 -1
  204. package/src/primitives/composer/ComposerInput.tsx +3 -3
  205. package/src/primitives/composer/ComposerQuote.tsx +1 -1
  206. package/src/primitives/composer/ComposerRoot.tsx +1 -1
  207. package/src/primitives/composer/trigger/TriggerPopover.tsx +16 -1
  208. package/src/primitives/composer/trigger/TriggerPopoverBack.tsx +1 -1
  209. package/src/primitives/composer/trigger/TriggerPopoverCategories.tsx +1 -1
  210. package/src/primitives/composer/trigger/TriggerPopoverItems.tsx +1 -1
  211. package/src/primitives/composer/trigger/TriggerPopoverResource.ts +4 -1
  212. package/src/primitives/composer/trigger/TriggerPopoverRootContext.tsx +2 -0
  213. package/src/primitives/composer/trigger/detectTrigger.test.ts +88 -5
  214. package/src/primitives/composer/trigger/detectTrigger.ts +50 -9
  215. package/src/primitives/composer/trigger/index.ts +1 -0
  216. package/src/primitives/composer/trigger/triggerDetectionResource.ts +10 -7
  217. package/src/primitives/composer/trigger/triggerSelectionResource.test.ts +147 -0
  218. package/src/primitives/composer/trigger/triggerSelectionResource.ts +3 -4
  219. package/src/primitives/composer.ts +1 -0
  220. package/src/primitives/message/MessageRoot.tsx +1 -1
  221. package/src/primitives/selectionToolbar/SelectionToolbarQuote.tsx +1 -1
  222. package/src/primitives/selectionToolbar/SelectionToolbarRoot.tsx +1 -1
  223. package/src/primitives/thread/ThreadRoot.tsx +3 -0
  224. package/src/primitives/thread/ThreadViewport.tsx +1 -1
  225. package/src/primitives/thread/ThreadViewportFooter.tsx +1 -1
  226. package/src/primitives/thread/useThreadViewportAutoScroll.ts +1 -1
  227. package/src/primitives/threadList/ThreadListNew.tsx +1 -1
  228. package/src/primitives/threadListFocusGroup.ts +2 -2
  229. package/src/primitives/threadListItem/ThreadListItemRoot.tsx +1 -1
  230. package/src/primitives/threadListItem/ThreadListItemTrigger.tsx +1 -1
  231. package/src/primitives/threadListItemMore/ThreadListItemMoreContent.tsx +1 -1
  232. package/src/primitives/threadListItemMore/ThreadListItemMoreRoot.tsx +1 -1
  233. package/src/primitives/threadListItemMore/ThreadListItemMoreTrigger.tsx +2 -2
  234. package/src/primitives/threadListItemMore/scope.ts +2 -2
  235. package/src/sandbox-host/SandboxHost.test.tsx +106 -1
  236. package/src/sandbox-host/SandboxHost.tsx +22 -5
  237. package/src/tests/RemoteThreadListRuntime.adapterProvider.test.tsx +31 -1
  238. package/src/unstable/useLiveCompletionAdapter.test.tsx +117 -1
  239. package/src/unstable/useLiveCompletionAdapter.ts +4 -1
  240. package/src/unstable/useSlashCommandAdapter.test.tsx +141 -0
  241. package/src/unstable/useSlashCommandAdapter.ts +52 -17
  242. package/src/utils/Primitive.tsx +2 -2
  243. package/src/utils/createActionButton.tsx +1 -1
  244. package/src/utils/hooks/useOnResizeContent.ts +1 -1
  245. package/src/utils/hooks/useOnScrollToBottom.ts +1 -1
  246. package/src/utils/invokeCallbackSafely.ts +11 -0
  247. package/src/utils/smooth/useSmooth.test.tsx +110 -0
  248. package/src/utils/smooth/useSmooth.ts +21 -7
  249. package/dist/context/react/utils/ensureBinding.d.ts +0 -5
  250. package/dist/context/react/utils/ensureBinding.d.ts.map +0 -1
  251. package/dist/context/react/utils/ensureBinding.js +0 -24
  252. package/dist/context/react/utils/ensureBinding.js.map +0 -1
  253. package/dist/context/react/utils/useRuntimeState.d.ts +0 -13
  254. package/dist/context/react/utils/useRuntimeState.d.ts.map +0 -1
  255. package/dist/context/react/utils/useRuntimeState.js +0 -33
  256. package/dist/context/react/utils/useRuntimeState.js.map +0 -1
  257. package/dist/legacy-runtime/runtime/MessagePartRuntime.d.ts +0 -3
  258. package/dist/legacy-runtime/runtime/MessagePartRuntime.js +0 -2
  259. package/dist/legacy-runtime/runtime/MessageRuntime.d.ts +0 -3
  260. package/dist/legacy-runtime/runtime/MessageRuntime.js +0 -2
  261. package/dist/legacy-runtime/runtime/ThreadListRuntime.d.ts +0 -3
  262. package/dist/legacy-runtime/runtime/ThreadListRuntime.js +0 -2
  263. package/src/context/react/utils/ensureBinding.ts +0 -46
  264. package/src/context/react/utils/useRuntimeState.ts +0 -46
  265. package/src/legacy-runtime/runtime/MessagePartRuntime.ts +0 -2
  266. package/src/legacy-runtime/runtime/MessageRuntime.ts +0 -3
  267. package/src/legacy-runtime/runtime/ThreadListRuntime.ts +0 -4
@@ -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 { type MutableRefObject, useEffect, useRef } from "react";
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>(null!);
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,
@@ -560,4 +560,25 @@ describe("createMcpAppBridge", () => {
560
560
  consoleError.mockRestore();
561
561
  bridge.dispose();
562
562
  });
563
+
564
+ it("preserves the onError receiver", () => {
565
+ const { frame } = makeFrame();
566
+ const handlers = {
567
+ calls: 0,
568
+ onError() {
569
+ expect(this).toBe(handlers);
570
+ this.calls += 1;
571
+ },
572
+ };
573
+ const bridge = createMcpAppBridge({ frame, handlers });
574
+
575
+ deliver(bridge, {
576
+ jsonrpc: "2.0",
577
+ method: "notifications/error",
578
+ params: { message: "kaboom" },
579
+ });
580
+
581
+ expect(handlers.calls).toBe(1);
582
+ bridge.dispose();
583
+ });
563
584
  });
@@ -1,4 +1,5 @@
1
1
  import type { SandboxHostFrame } from "../sandbox-host/SandboxHost";
2
+ import { invokeCallbackSafely } from "../utils/invokeCallbackSafely";
2
3
  import {
3
4
  MCP_APP_PROTOCOL_VERSION,
4
5
  type McpAppBridgeHandlers,
@@ -123,21 +124,8 @@ export function createMcpAppBridge(
123
124
  });
124
125
  };
125
126
 
126
- const reportErrorCallbackFailure = (error: unknown) => {
127
- console.error(
128
- "[assistant-ui] MCP App onError callback threw an error",
129
- error,
130
- );
131
- };
132
-
133
127
  const reportError = (error: Error) => {
134
- try {
135
- void Promise.resolve(handlers.onError?.(error)).catch(
136
- reportErrorCallbackFailure,
137
- );
138
- } catch (callbackError) {
139
- reportErrorCallbackFailure(callbackError);
140
- }
128
+ invokeCallbackSafely(() => handlers.onError?.(error), "MCP App onError");
141
129
  };
142
130
 
143
131
  const handleRequest = async (req: McpAppJsonRpcRequest) => {
@@ -13,5 +13,6 @@ export type {
13
13
  McpAppsHost,
14
14
  McpAppsRemoteHostOptions,
15
15
  McpAppToolCallParams,
16
+ McpAppBridgeHandlers,
16
17
  ToolCallMessagePartMcpMetadata,
17
18
  } from "./types";
@@ -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` to restrict message sources
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", // optional
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 "@radix-ui/react-compose-refs";
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 "@radix-ui/primitive";
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";
@@ -0,0 +1,67 @@
1
+ /**
2
+ * @vitest-environment jsdom
3
+ */
4
+ import { act } from "react";
5
+ import { createRoot, type Root } from "react-dom/client";
6
+ import type * as AssistantStore from "@assistant-ui/store";
7
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
8
+ import { ActionBarPrimitiveExportMarkdown } from "./ActionBarExportMarkdown";
9
+
10
+ const { getCopyText } = vi.hoisted(() => ({
11
+ getCopyText: vi.fn(() => "# Exported message"),
12
+ }));
13
+
14
+ (globalThis as Record<string, unknown>).IS_REACT_ACT_ENVIRONMENT = true;
15
+
16
+ vi.mock("@assistant-ui/store", async (importOriginal) => {
17
+ const actual = await importOriginal<typeof AssistantStore>();
18
+ return {
19
+ ...actual,
20
+ useAui: () => ({ message: { getCopyText } }),
21
+ useAuiState: () => true,
22
+ };
23
+ });
24
+
25
+ describe("ActionBarPrimitiveExportMarkdown", () => {
26
+ let container: HTMLDivElement;
27
+ let root: Root;
28
+
29
+ beforeEach(() => {
30
+ getCopyText.mockClear();
31
+ container = document.createElement("div");
32
+ document.body.appendChild(container);
33
+ root = createRoot(container);
34
+ });
35
+
36
+ afterEach(async () => {
37
+ await act(async () => {
38
+ root.unmount();
39
+ });
40
+ container.remove();
41
+ vi.restoreAllMocks();
42
+ });
43
+
44
+ it("handles rejected asynchronous exports", async () => {
45
+ const error = new Error("remote save failed");
46
+ const onExport = vi.fn().mockRejectedValue(error);
47
+ const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
48
+
49
+ await act(async () => {
50
+ root.render(
51
+ <ActionBarPrimitiveExportMarkdown onExport={onExport}>
52
+ Export
53
+ </ActionBarPrimitiveExportMarkdown>,
54
+ );
55
+ });
56
+
57
+ await act(async () => {
58
+ container.querySelector("button")!.click();
59
+ });
60
+
61
+ expect(onExport).toHaveBeenCalledWith("# Exported message");
62
+ expect(errorSpy).toHaveBeenCalledWith(
63
+ "[assistant-ui] markdown export failed:",
64
+ error,
65
+ );
66
+ });
67
+ });
@@ -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 "@radix-ui/primitive";
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
 
@@ -61,7 +61,9 @@ export const ActionBarPrimitiveExportMarkdown = forwardRef<
61
61
  ref={forwardedRef}
62
62
  disabled={disabled || !callback}
63
63
  onClick={composeEventHandlers(onClick, () => {
64
- callback?.();
64
+ void callback?.().catch((error: unknown) => {
65
+ console.error("[assistant-ui] markdown export failed:", error);
66
+ });
65
67
  })}
66
68
  />
67
69
  );
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { forwardRef } from "react";
4
4
  import type { ActionButtonProps } from "../../utils/createActionButton";
5
- import { composeEventHandlers } from "@radix-ui/primitive";
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 "@radix-ui/primitive";
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 "@radix-ui/primitive";
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 { Scope } from "@radix-ui/react-context";
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 "@radix-ui/primitive";
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 { Scope } from "@radix-ui/react-context";
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 };
@@ -6,7 +6,7 @@ import {
6
6
  forwardRef,
7
7
  type ComponentPropsWithoutRef,
8
8
  } from "react";
9
- import { MessagePrimitiveIf as If } from "../message/MessageIf";
9
+ import { AuiIf } from "@assistant-ui/store";
10
10
 
11
11
  export namespace BranchPickerPrimitiveRoot {
12
12
  export type Element = ComponentRef<typeof Primitive.div>;
@@ -42,9 +42,11 @@ export const BranchPickerPrimitiveRoot = forwardRef<
42
42
  BranchPickerPrimitiveRoot.Props
43
43
  >(({ hideWhenSingleBranch, ...rest }, ref) => {
44
44
  return (
45
- <If hasBranches={hideWhenSingleBranch ? true : undefined}>
45
+ <AuiIf
46
+ condition={(s) => !hideWhenSingleBranch || s.message.branchCount >= 2}
47
+ >
46
48
  <Primitive.div {...rest} ref={ref} />
47
- </If>
49
+ </AuiIf>
48
50
  );
49
51
  });
50
52
 
@@ -9,7 +9,7 @@ import {
9
9
  isValidElement,
10
10
  } from "react";
11
11
 
12
- import { composeEventHandlers } from "@radix-ui/primitive";
12
+ import { composeEventHandlers } from "radix-ui/internal";
13
13
  import { Slot } from "radix-ui";
14
14
  import type React from "react";
15
15
  import { useAui } from "@assistant-ui/store";
@@ -21,11 +21,11 @@ export namespace ComposerPrimitiveDictationTranscript {
21
21
  *
22
22
  * @example
23
23
  * ```tsx
24
- * <ComposerPrimitive.If dictation>
24
+ * <AuiIf condition={(s) => s.composer.dictation != null}>
25
25
  * <div className="dictation-preview">
26
26
  * <ComposerPrimitive.DictationTranscript />
27
27
  * </div>
28
- * </ComposerPrimitive.If>
28
+ * </AuiIf>
29
29
  * ```
30
30
  */
31
31
  export const ComposerPrimitiveDictationTranscript = forwardRef<
@@ -81,7 +81,8 @@ vi.mock("./trigger/TriggerPopoverRootContext", () => ({
81
81
 
82
82
  let escapeKeydownHandler: ((event: KeyboardEvent) => void) | null = null;
83
83
 
84
- vi.mock("@radix-ui/react-use-escape-keydown", () => ({
84
+ vi.mock("radix-ui/internal", async (importOriginal) => ({
85
+ ...(await importOriginal<typeof import("radix-ui/internal")>()),
85
86
  useEscapeKeydown: (handler: (event: KeyboardEvent) => void) => {
86
87
  escapeKeydownHandler = handler;
87
88
  },
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
- import { composeEventHandlers } from "@radix-ui/primitive";
4
- import { useComposedRefs } from "@radix-ui/react-compose-refs";
3
+ import { composeEventHandlers } from "radix-ui/internal";
4
+ import { useComposedRefs } from "radix-ui/internal";
5
5
  import { Slot } from "radix-ui";
6
6
  import {
7
7
  type ClipboardEvent,
@@ -19,7 +19,7 @@ import TextareaAutosize, {
19
19
  type TextareaAutosizeProps,
20
20
  type TextareaHeightChangeMeta,
21
21
  } from "react-textarea-autosize";
22
- import { useEscapeKeydown } from "@radix-ui/react-use-escape-keydown";
22
+ import { useEscapeKeydown } from "radix-ui/internal";
23
23
  import { useOnScrollToBottom } from "../../utils/hooks/useOnScrollToBottom";
24
24
  import { useMediaQuery } from "../../utils/hooks/useMediaQuery";
25
25
  import { useAui } from "@assistant-ui/store";
@@ -8,7 +8,7 @@ import {
8
8
  useCallback,
9
9
  } from "react";
10
10
  import { useAui, useAuiState } from "@assistant-ui/store";
11
- import { composeEventHandlers } from "@radix-ui/primitive";
11
+ import { composeEventHandlers } from "radix-ui/internal";
12
12
 
13
13
  // ---- Root ----
14
14
 
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { composeEventHandlers } from "@radix-ui/primitive";
3
+ import { composeEventHandlers } from "radix-ui/internal";
4
4
  import { useAuiState } from "@assistant-ui/store";
5
5
  import { Primitive } from "../../utils/Primitive";
6
6
  import {
@@ -28,6 +28,7 @@ import {
28
28
  useTriggerPopoverAriaPublish,
29
29
  useTriggerPopoverRootContext,
30
30
  } from "./TriggerPopoverRootContext";
31
+ import type { TriggerMatcher } from "./detectTrigger";
31
32
 
32
33
  const TriggerPopoverScopeContext =
33
34
  createContext<TriggerPopoverResourceOutput | null>(null);
@@ -70,6 +71,8 @@ export namespace ComposerPrimitiveTriggerPopover {
70
71
  > & {
71
72
  /** The character(s) that activate this trigger (e.g. `"@"`, `"/"`). Also serves as the trigger identity within the root. */
72
73
  readonly char: string;
74
+ /** Overrides trigger detection for both textarea and Lexical inputs. `endOffset` is the exclusive replace bound. */
75
+ readonly matcher?: TriggerMatcher | undefined;
73
76
  /** Adapter providing categories and items. */
74
77
  readonly adapter?: Unstable_TriggerAdapter | undefined;
75
78
  /** Whether the adapter is resolving items, surfaced to the popover scope for async sources. @default false */
@@ -111,6 +114,7 @@ export const ComposerPrimitiveTriggerPopover = forwardRef<
111
114
  (
112
115
  {
113
116
  char,
117
+ matcher,
114
118
  adapter,
115
119
  isLoading = false,
116
120
  "aria-label": ariaLabel,
@@ -122,6 +126,15 @@ export const ComposerPrimitiveTriggerPopover = forwardRef<
122
126
  const aui = useAui();
123
127
  const text = useAuiState((s) => s.composer.text);
124
128
  const popoverId = useId();
129
+ const matcherRef = useRef(matcher);
130
+ useEffect(() => {
131
+ matcherRef.current = matcher;
132
+ });
133
+ const [registeredMatcher] = useState(
134
+ () => (nextText: string, triggerChar: string, cursorPosition: number) =>
135
+ matcherRef.current!(nextText, triggerChar, cursorPosition),
136
+ );
137
+ const hasMatcher = matcher !== undefined;
125
138
 
126
139
  // Track in state (for resource reactivity) + ref (dev warning on duplicate registrations).
127
140
  const behaviorRef = useRef<TriggerBehavior | null>(null);
@@ -165,6 +178,7 @@ export const ComposerPrimitiveTriggerPopover = forwardRef<
165
178
  adapter,
166
179
  text,
167
180
  triggerChar: char,
181
+ matcher,
168
182
  behavior: behavior ?? undefined,
169
183
  aui,
170
184
  popoverId,
@@ -178,10 +192,11 @@ export const ComposerPrimitiveTriggerPopover = forwardRef<
178
192
  useEffect(() => {
179
193
  return root.register({
180
194
  char,
195
+ ...(hasMatcher ? { matcher: registeredMatcher } : {}),
181
196
  ...(behavior ? { behavior } : {}),
182
197
  resource: getResource(),
183
198
  });
184
- }, [root, char, behavior]);
199
+ }, [root, char, hasMatcher, behavior]);
185
200
 
186
201
  const pluginRegistry = useComposerInputPluginRegistryOptional();
187
202
  useEffect(() => {
@@ -6,7 +6,7 @@ import {
6
6
  type ComponentPropsWithoutRef,
7
7
  forwardRef,
8
8
  } from "react";
9
- import { composeEventHandlers } from "@radix-ui/primitive";
9
+ import { composeEventHandlers } from "radix-ui/internal";
10
10
  import { useTriggerPopoverScopeContext } from "./TriggerPopover";
11
11
 
12
12
  export namespace ComposerPrimitiveTriggerPopoverBack {
@@ -8,7 +8,7 @@ import {
8
8
  forwardRef,
9
9
  useCallback,
10
10
  } from "react";
11
- import { composeEventHandlers } from "@radix-ui/primitive";
11
+ import { composeEventHandlers } from "radix-ui/internal";
12
12
  import { useTriggerPopoverScopeContext } from "./TriggerPopover";
13
13
  import type { Unstable_TriggerCategory } from "@assistant-ui/core";
14
14
 
@@ -8,7 +8,7 @@ import {
8
8
  forwardRef,
9
9
  useCallback,
10
10
  } from "react";
11
- import { composeEventHandlers } from "@radix-ui/primitive";
11
+ import { composeEventHandlers } from "radix-ui/internal";
12
12
  import { useTriggerPopoverScopeContext } from "./TriggerPopover";
13
13
  import type { Unstable_TriggerItem } from "@assistant-ui/core";
14
14
 
@@ -14,6 +14,7 @@ import {
14
14
  type SelectItemOverride,
15
15
  type TriggerBehavior,
16
16
  } from "./triggerSelectionResource";
17
+ import type { TriggerMatcher } from "./detectTrigger";
17
18
 
18
19
  export type { SelectItemOverride, TriggerBehavior };
19
20
  export type { TriggerPopoverKeyEvent } from "./triggerKeyboardResource";
@@ -57,6 +58,7 @@ const useTriggerPopoverResource = ({
57
58
  adapter,
58
59
  text,
59
60
  triggerChar,
61
+ matcher,
60
62
  behavior,
61
63
  aui,
62
64
  popoverId,
@@ -65,6 +67,7 @@ const useTriggerPopoverResource = ({
65
67
  adapter: Unstable_TriggerAdapter | undefined;
66
68
  text: string;
67
69
  triggerChar: string;
70
+ matcher: TriggerMatcher | undefined;
68
71
  behavior: TriggerBehavior | undefined;
69
72
  aui: AssistantClient;
70
73
  /** Stable ID for accessible element IDs (pass React's useId() from component layer). */
@@ -72,7 +75,7 @@ const useTriggerPopoverResource = ({
72
75
  isLoading: boolean;
73
76
  }): TriggerPopoverResourceOutput => {
74
77
  const detection = useResource(
75
- TriggerDetectionResource({ text, triggerChar }),
78
+ TriggerDetectionResource({ text, triggerChar, matcher }),
76
79
  );
77
80
 
78
81
  const open =