@agent-native/toolkit 0.204.0 → 0.204.1-nightly-20261008065100

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 (168) hide show
  1. package/agent-native.eject.json +2 -0
  2. package/dist/app/agent-page/AgentJobsTab.d.ts.map +1 -1
  3. package/dist/app/agent-page/AgentJobsTab.js +4 -2
  4. package/dist/app/agent-page/AgentJobsTab.js.map +1 -1
  5. package/dist/app/agent-page/AutomationDetailsDialog.d.ts +2 -1
  6. package/dist/app/agent-page/AutomationDetailsDialog.d.ts.map +1 -1
  7. package/dist/app/agent-page/AutomationDetailsDialog.js +8 -4
  8. package/dist/app/agent-page/AutomationDetailsDialog.js.map +1 -1
  9. package/dist/app/agent-page/ScheduledTriggerNotice.d.ts.map +1 -1
  10. package/dist/app/agent-page/ScheduledTriggerNotice.js +41 -19
  11. package/dist/app/agent-page/ScheduledTriggerNotice.js.map +1 -1
  12. package/dist/app/agent-page/use-jobs.d.ts +1 -1
  13. package/dist/app/agent-page/use-jobs.d.ts.map +1 -1
  14. package/dist/app/agentkit/react/components.d.ts.map +1 -1
  15. package/dist/app/agentkit/react/components.js +124 -45
  16. package/dist/app/agentkit/react/components.js.map +1 -1
  17. package/dist/app/agentkit/react/context.d.ts +22 -1
  18. package/dist/app/agentkit/react/context.d.ts.map +1 -1
  19. package/dist/app/agentkit/react/context.js +14 -1
  20. package/dist/app/agentkit/react/context.js.map +1 -1
  21. package/dist/app/agentkit/react/root.d.ts +3 -2
  22. package/dist/app/agentkit/react/root.d.ts.map +1 -1
  23. package/dist/app/agentkit/react/root.js +2 -2
  24. package/dist/app/agentkit/react/root.js.map +1 -1
  25. package/dist/app/agentkit/react/styles.css +32 -2
  26. package/dist/app/chat/AgentKitAssistantChat.d.ts.map +1 -1
  27. package/dist/app/chat/AgentKitAssistantChat.js +74 -7
  28. package/dist/app/chat/AgentKitAssistantChat.js.map +1 -1
  29. package/dist/app/chat/AgentPanel.js +1 -1
  30. package/dist/app/chat/AgentPanel.js.map +1 -1
  31. package/dist/app/chat/MultiTabAssistantChat.d.ts.map +1 -1
  32. package/dist/app/chat/MultiTabAssistantChat.js +10 -9
  33. package/dist/app/chat/MultiTabAssistantChat.js.map +1 -1
  34. package/dist/app/chat/RunStuckBanner.d.ts +8 -1
  35. package/dist/app/chat/RunStuckBanner.d.ts.map +1 -1
  36. package/dist/app/chat/RunStuckBanner.js +68 -6
  37. package/dist/app/chat/RunStuckBanner.js.map +1 -1
  38. package/dist/app/chat/chat/run-recovery.d.ts +4 -2
  39. package/dist/app/chat/chat/run-recovery.d.ts.map +1 -1
  40. package/dist/app/chat/chat/run-recovery.js +3 -3
  41. package/dist/app/chat/chat/run-recovery.js.map +1 -1
  42. package/dist/app/chat/chat/surface-types.d.ts +1 -0
  43. package/dist/app/chat/chat/surface-types.d.ts.map +1 -1
  44. package/dist/app/chat/composer/use-mention-search.d.ts +1 -0
  45. package/dist/app/chat/composer/use-mention-search.d.ts.map +1 -1
  46. package/dist/app/chat/fallback-chat-title.d.ts +2 -0
  47. package/dist/app/chat/fallback-chat-title.d.ts.map +1 -0
  48. package/dist/app/chat/fallback-chat-title.js +11 -0
  49. package/dist/app/chat/fallback-chat-title.js.map +1 -0
  50. package/dist/app/chat/feedback-report.d.ts +12 -0
  51. package/dist/app/chat/feedback-report.d.ts.map +1 -0
  52. package/dist/app/chat/feedback-report.js +21 -0
  53. package/dist/app/chat/feedback-report.js.map +1 -0
  54. package/dist/app/chat/reconcile-settled-run.d.ts +15 -0
  55. package/dist/app/chat/reconcile-settled-run.d.ts.map +1 -0
  56. package/dist/app/chat/reconcile-settled-run.js +41 -0
  57. package/dist/app/chat/reconcile-settled-run.js.map +1 -0
  58. package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
  59. package/dist/app/i18n/catalogs/ar-SA.js +9 -0
  60. package/dist/app/i18n/catalogs/ar-SA.js.map +1 -1
  61. package/dist/app/i18n/catalogs/de-DE.d.ts.map +1 -1
  62. package/dist/app/i18n/catalogs/de-DE.js +9 -0
  63. package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
  64. package/dist/app/i18n/catalogs/en-US.d.ts +9 -0
  65. package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
  66. package/dist/app/i18n/catalogs/en-US.js +9 -0
  67. package/dist/app/i18n/catalogs/en-US.js.map +1 -1
  68. package/dist/app/i18n/catalogs/es-ES.d.ts.map +1 -1
  69. package/dist/app/i18n/catalogs/es-ES.js +9 -0
  70. package/dist/app/i18n/catalogs/es-ES.js.map +1 -1
  71. package/dist/app/i18n/catalogs/fr-FR.d.ts.map +1 -1
  72. package/dist/app/i18n/catalogs/fr-FR.js +9 -0
  73. package/dist/app/i18n/catalogs/fr-FR.js.map +1 -1
  74. package/dist/app/i18n/catalogs/hi-IN.d.ts.map +1 -1
  75. package/dist/app/i18n/catalogs/hi-IN.js +9 -0
  76. package/dist/app/i18n/catalogs/hi-IN.js.map +1 -1
  77. package/dist/app/i18n/catalogs/ja-JP.d.ts.map +1 -1
  78. package/dist/app/i18n/catalogs/ja-JP.js +9 -0
  79. package/dist/app/i18n/catalogs/ja-JP.js.map +1 -1
  80. package/dist/app/i18n/catalogs/ko-KR.d.ts.map +1 -1
  81. package/dist/app/i18n/catalogs/ko-KR.js +9 -0
  82. package/dist/app/i18n/catalogs/ko-KR.js.map +1 -1
  83. package/dist/app/i18n/catalogs/pt-BR.d.ts.map +1 -1
  84. package/dist/app/i18n/catalogs/pt-BR.js +9 -0
  85. package/dist/app/i18n/catalogs/pt-BR.js.map +1 -1
  86. package/dist/app/i18n/catalogs/zh-CN.d.ts.map +1 -1
  87. package/dist/app/i18n/catalogs/zh-CN.js +9 -0
  88. package/dist/app/i18n/catalogs/zh-CN.js.map +1 -1
  89. package/dist/app/i18n/catalogs/zh-TW.d.ts.map +1 -1
  90. package/dist/app/i18n/catalogs/zh-TW.js +9 -0
  91. package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
  92. package/dist/app/providers/AppProviders.d.ts.map +1 -1
  93. package/dist/app/providers/AppProviders.js +7 -1
  94. package/dist/app/providers/AppProviders.js.map +1 -1
  95. package/dist/app/settings/shell/pages/audit.d.ts.map +1 -1
  96. package/dist/app/settings/shell/pages/audit.js +11 -2
  97. package/dist/app/settings/shell/pages/audit.js.map +1 -1
  98. package/dist/app/shared/AppShellSkeleton.d.ts.map +1 -1
  99. package/dist/app/shared/AppShellSkeleton.js +4 -0
  100. package/dist/app/shared/AppShellSkeleton.js.map +1 -1
  101. package/dist/composer/ComposerContextMenu.d.ts +14 -1
  102. package/dist/composer/ComposerContextMenu.d.ts.map +1 -1
  103. package/dist/composer/ComposerContextMenu.js +65 -19
  104. package/dist/composer/ComposerContextMenu.js.map +1 -1
  105. package/dist/composer/MentionPopover.d.ts.map +1 -1
  106. package/dist/composer/MentionPopover.js +3 -3
  107. package/dist/composer/MentionPopover.js.map +1 -1
  108. package/dist/composer/PromptComposer.d.ts +1 -1
  109. package/dist/composer/PromptComposer.d.ts.map +1 -1
  110. package/dist/composer/TiptapComposer.d.ts +2 -2
  111. package/dist/composer/TiptapComposer.d.ts.map +1 -1
  112. package/dist/composer/TiptapComposer.js +92 -36
  113. package/dist/composer/TiptapComposer.js.map +1 -1
  114. package/dist/composer/use-mention-search.d.ts +1 -0
  115. package/dist/composer/use-mention-search.d.ts.map +1 -1
  116. package/dist/composer/use-mention-search.js +8 -1
  117. package/dist/composer/use-mention-search.js.map +1 -1
  118. package/package.json +4 -4
  119. package/src/app/agent-page/AgentJobsTab.blocked.spec.tsx +43 -0
  120. package/src/app/agent-page/AgentJobsTab.tsx +14 -5
  121. package/src/app/agent-page/AutomationDetailsDialog.tsx +22 -8
  122. package/src/app/agent-page/ScheduledTriggerNotice.spec.tsx +45 -3
  123. package/src/app/agent-page/ScheduledTriggerNotice.tsx +52 -31
  124. package/src/app/agent-page/use-jobs.ts +1 -1
  125. package/src/app/agentkit/react/components.interaction.spec.tsx +311 -1
  126. package/src/app/agentkit/react/components.spec.tsx +106 -2
  127. package/src/app/agentkit/react/components.tsx +217 -80
  128. package/src/app/agentkit/react/context.tsx +36 -0
  129. package/src/app/agentkit/react/root.tsx +4 -0
  130. package/src/app/agentkit/react/styles.css +32 -2
  131. package/src/app/chat/AgentKitAssistantChat.spec.tsx +140 -18
  132. package/src/app/chat/AgentKitAssistantChat.tsx +123 -7
  133. package/src/app/chat/AgentPanel.header.spec.ts +43 -7
  134. package/src/app/chat/AgentPanel.tsx +1 -1
  135. package/src/app/chat/MultiTabAssistantChat.spec.tsx +34 -0
  136. package/src/app/chat/MultiTabAssistantChat.tsx +10 -9
  137. package/src/app/chat/RunStuckBanner.spec.tsx +258 -17
  138. package/src/app/chat/RunStuckBanner.tsx +107 -5
  139. package/src/app/chat/chat/run-recovery.tsx +10 -2
  140. package/src/app/chat/chat/surface-types.ts +1 -0
  141. package/src/app/chat/fallback-chat-title.ts +10 -0
  142. package/src/app/chat/feedback-report.spec.ts +45 -0
  143. package/src/app/chat/feedback-report.ts +27 -0
  144. package/src/app/chat/reconcile-settled-run.spec.ts +112 -0
  145. package/src/app/chat/reconcile-settled-run.ts +57 -0
  146. package/src/app/i18n/catalogs/ar-SA.ts +12 -0
  147. package/src/app/i18n/catalogs/de-DE.ts +12 -0
  148. package/src/app/i18n/catalogs/en-US.ts +12 -0
  149. package/src/app/i18n/catalogs/es-ES.ts +12 -0
  150. package/src/app/i18n/catalogs/fr-FR.ts +12 -0
  151. package/src/app/i18n/catalogs/hi-IN.ts +12 -0
  152. package/src/app/i18n/catalogs/ja-JP.ts +12 -0
  153. package/src/app/i18n/catalogs/ko-KR.ts +12 -0
  154. package/src/app/i18n/catalogs/pt-BR.ts +12 -0
  155. package/src/app/i18n/catalogs/zh-CN.ts +10 -0
  156. package/src/app/i18n/catalogs/zh-TW.ts +10 -0
  157. package/src/app/providers/AppProviders.spec.tsx +29 -0
  158. package/src/app/providers/AppProviders.tsx +13 -0
  159. package/src/app/settings/shell/pages/audit.spec.tsx +30 -0
  160. package/src/app/settings/shell/pages/audit.tsx +12 -1
  161. package/src/app/shared/AppShellSkeleton.tsx +4 -0
  162. package/src/composer/ComposerContextMenu.tsx +94 -22
  163. package/src/composer/ComposerPlusMenu.parity.spec.tsx +218 -233
  164. package/src/composer/MentionPopover.tsx +12 -3
  165. package/src/composer/PromptComposer.context.spec.tsx +527 -195
  166. package/src/composer/PromptComposer.tsx +1 -1
  167. package/src/composer/TiptapComposer.tsx +105 -37
  168. package/src/composer/use-mention-search.ts +8 -1
@@ -19,6 +19,7 @@ import {
19
19
  isHumanReadableDocumentTitle,
20
20
  normalizeDocumentTitle,
21
21
  } from "@agent-native/core/shared/document-title";
22
+ import { getMcpAppWidgetEmbedBootScriptBody } from "@agent-native/core/shared/mcp-app-widget-embed";
22
23
  import { getSsrBetaRedirectScriptBody } from "@agent-native/core/shared/ssr-beta-redirect";
23
24
  import { getSsrSessionBootstrapScriptBody } from "@agent-native/core/shared/ssr-session-bootstrap";
24
25
  import { Toaster } from "@agent-native/toolkit/ui/sonner";
@@ -98,6 +99,17 @@ function EarlyBetaRedirectScript() {
98
99
  );
99
100
  }
100
101
 
102
+ // Marks <html> as an MCP App widget before the server-rendered skeleton below
103
+ // paints, so the widget never flashes the app's own sidebar.
104
+ function McpAppWidgetBootScript() {
105
+ return (
106
+ <script
107
+ data-agent-native-mcp-widget-boot="1"
108
+ dangerouslySetInnerHTML={{ __html: getMcpAppWidgetEmbedBootScriptBody() }}
109
+ />
110
+ );
111
+ }
112
+
101
113
  function EarlySessionBootstrapScript() {
102
114
  return (
103
115
  <script
@@ -480,6 +492,7 @@ export function AppProviders({
480
492
 
481
493
  return (
482
494
  <>
495
+ <McpAppWidgetBootScript />
483
496
  {!sessionBypass && (
484
497
  <>
485
498
  <EarlySessionBootstrapScript />
@@ -165,6 +165,7 @@ describe("Audit log page", () => {
165
165
  event({ id: "human" }),
166
166
  event({
167
167
  id: "agent",
168
+ caller: "tool",
168
169
  actorKind: "agent",
169
170
  actorEmail: "member@example.com",
170
171
  summary: "Turned on Require citations",
@@ -193,6 +194,35 @@ describe("Audit log page", () => {
193
194
  expect(refused.textContent).toContain("Sep 23 · member@example.com");
194
195
  });
195
196
 
197
+ it("names the protocol when an outside agent made the change", async () => {
198
+ callActionMock.mockResolvedValue(
199
+ page(
200
+ [
201
+ event({
202
+ caller: "mcp",
203
+ actorKind: "agent",
204
+ actorEmail: "bob@example.com",
205
+ summary: "Updated the form",
206
+ app: "forms",
207
+ }),
208
+ ],
209
+ null,
210
+ ),
211
+ );
212
+ await render();
213
+
214
+ const [row] = rows();
215
+ expect(row.textContent).toContain("Sep 23 · Forms · Agent via MCP");
216
+ expect(row.textContent).not.toContain("bob@example.com");
217
+
218
+ await act(async () => {
219
+ row.click();
220
+ });
221
+ const dialog = document.querySelector('[role="dialog"]');
222
+ expect(dialog?.textContent).toContain("Changed byAgent via MCP");
223
+ expect(dialog?.textContent).toContain("On behalf ofbob@example.com");
224
+ });
225
+
196
226
  it("names the real count in Show N more and reveals the next page", async () => {
197
227
  const first = Array.from({ length: 25 }, (_, index) =>
198
228
  event({ id: `a-${index}` }),
@@ -67,8 +67,19 @@ export function auditAppLabel(app: string): string {
67
67
  .join(" ");
68
68
  }
69
69
 
70
+ const OUTSIDE_AGENT_PROTOCOLS: Record<string, string> = {
71
+ mcp: "MCP",
72
+ webmcp: "WebMCP",
73
+ a2a: "A2A",
74
+ };
75
+
70
76
  function actorLabel(event: AuditEvent, t: Translate): string {
71
- if (event.actorKind === "agent") return t("agentChat.common.agent");
77
+ if (event.actorKind === "agent") {
78
+ const protocol = OUTSIDE_AGENT_PROTOCOLS[event.caller];
79
+ return protocol
80
+ ? t("agentChat.settings.audit.agentVia", { protocol })
81
+ : t("agentChat.common.agent");
82
+ }
72
83
  if (event.actorKind === "system" || !event.actorEmail) {
73
84
  return t("agentChat.settings.audit.system");
74
85
  }
@@ -1,3 +1,4 @@
1
+ import { MCP_APP_WIDGET_EMBED_ATTRIBUTE } from "@agent-native/core/shared/mcp-app-widget-embed";
1
2
  import type { CSSProperties, ReactNode } from "react";
2
3
 
3
4
  const MUTED = "hsl(var(--muted, 240 5% 96.1%))";
@@ -1048,6 +1049,9 @@ export function AppShellSkeleton({
1048
1049
  }}
1049
1050
  >
1050
1051
  <style>{`
1052
+ html[${MCP_APP_WIDGET_EMBED_ATTRIBUTE}] [data-agent-native-app-skeleton] > :not(style) {
1053
+ display: none !important;
1054
+ }
1051
1055
  [data-agent-native-skeleton-block] {
1052
1056
  animation: an-app-shell-skeleton-pulse 1.2s ease-in-out infinite;
1053
1057
  }
@@ -95,6 +95,8 @@ export interface ComposerContextMenuProps {
95
95
  onRestoreFocus?: () => void;
96
96
  contextButtonTooltipDisabled?: boolean;
97
97
  disabled?: boolean;
98
+ /** Runs this action or opens its picker as a dialog; each new object is a new request. */
99
+ openEntry?: { id: string } | null;
98
100
  }
99
101
  interface ComposerContextPage {
100
102
  id: string;
@@ -106,6 +108,19 @@ interface ComposerContextDialogSession {
106
108
  scopeKey?: string;
107
109
  }
108
110
 
111
+ // Without a dialog presentation a picker selects one item through onSelect,
112
+ // which the dialog's single-select mode does too.
113
+ function asDialogPicker(
114
+ picker: ComposerContextPickerConfig,
115
+ ): ComposerContextPickerConfig {
116
+ return typeof picker.presentation === "object"
117
+ ? picker
118
+ : ({
119
+ ...picker,
120
+ presentation: { type: "dialog", mode: "single" },
121
+ } as ComposerContextPickerConfig);
122
+ }
123
+
109
124
  function findAction(
110
125
  items: readonly ComposerContextMenuItem[],
111
126
  id: string,
@@ -121,46 +136,73 @@ function findAction(
121
136
  }
122
137
  }
123
138
 
124
- export function getComposerContextMenuEntries(
139
+ export interface ComposerContextActionMatch {
140
+ action: ComposerContextMenuAction;
141
+ /** Category ids from the searched items down to the action. */
142
+ path: string[];
143
+ /** Labels of those categories, outermost first. */
144
+ categories: string[];
145
+ }
146
+
147
+ /** Every action under `items` that matches `query`; an empty query matches all. */
148
+ export function searchComposerContextActions(
125
149
  items: readonly ComposerContextMenuItem[],
126
- path: readonly string[],
127
150
  query: string,
128
- ): ComposerContextMenuItem[] {
129
- let scope = items;
130
- for (const id of path) {
131
- const category = scope.find((item) => item.id === id);
132
- if (!category?.children || category.disabled) return [];
133
- scope = category.children;
134
- }
151
+ ): ComposerContextActionMatch[] {
135
152
  const terms = query.trim().toLocaleLowerCase().split(/\s+/).filter(Boolean);
136
- if (!terms.length) return [...scope];
137
- const matches: ComposerContextMenuItem[] = [];
153
+ const matches: ComposerContextActionMatch[] = [];
138
154
  const visit = (
139
155
  entries: readonly ComposerContextMenuItem[],
140
- ancestors: string[],
141
- disabled = false,
156
+ path: string[],
157
+ categories: string[],
158
+ searchable: string[],
159
+ disabled: boolean,
142
160
  ) => {
143
161
  for (const entry of entries) {
144
- const searchable = [
145
- ...ancestors,
162
+ const text = [
163
+ ...searchable,
146
164
  entry.label,
147
165
  entry.description ?? "",
148
166
  ...(entry.keywords ?? []),
149
167
  ];
168
+ const entryDisabled = disabled || entry.disabled === true;
150
169
  if (entry.children)
151
- visit(entry.children, searchable, disabled || entry.disabled === true);
170
+ visit(
171
+ entry.children,
172
+ [...path, entry.id],
173
+ [...categories, entry.label],
174
+ text,
175
+ entryDisabled,
176
+ );
152
177
  else if (
153
- terms.every((term) =>
154
- searchable.join(" ").toLocaleLowerCase().includes(term),
155
- )
178
+ terms.every((term) => text.join(" ").toLocaleLowerCase().includes(term))
156
179
  )
157
- matches.push(disabled ? { ...entry, disabled: true } : entry);
180
+ matches.push({
181
+ action: entryDisabled ? { ...entry, disabled: true } : entry,
182
+ path,
183
+ categories,
184
+ });
158
185
  }
159
186
  };
160
- visit(scope, []);
187
+ visit(items, [], [], [], false);
161
188
  return matches;
162
189
  }
163
190
 
191
+ export function getComposerContextMenuEntries(
192
+ items: readonly ComposerContextMenuItem[],
193
+ path: readonly string[],
194
+ query: string,
195
+ ): ComposerContextMenuItem[] {
196
+ let scope = items;
197
+ for (const id of path) {
198
+ const category = scope.find((item) => item.id === id);
199
+ if (!category?.children || category.disabled) return [];
200
+ scope = category.children;
201
+ }
202
+ if (!query.trim()) return [...scope];
203
+ return searchComposerContextActions(scope, query).map(({ action }) => action);
204
+ }
205
+
164
206
  function ContextSubmenu({
165
207
  label,
166
208
  icon,
@@ -263,6 +305,7 @@ export function ComposerContextMenu({
263
305
  onRestoreFocus,
264
306
  contextButtonTooltipDisabled = false,
265
307
  disabled,
308
+ openEntry,
266
309
  }: ComposerContextMenuProps) {
267
310
  const t = useComposerRuntimeAdapters().translate!;
268
311
  const allItems = [...menuActionItems, ...items];
@@ -399,6 +442,35 @@ export function ComposerContextMenu({
399
442
  updatePath([...origin, action.id]);
400
443
  if (select && !action.picker) selectAction(action);
401
444
  };
445
+ const openRequestedEntry = (id: string) => {
446
+ if (disabled) return;
447
+ const action = findAction(allItems, id);
448
+ if (!action || action.disabled || action.render) {
449
+ reportError(
450
+ new Error(
451
+ t("agentChat.composer.contextActionFailed", {
452
+ defaultValue: "Could not add context.",
453
+ }),
454
+ ),
455
+ );
456
+ return;
457
+ }
458
+ setError(null);
459
+ if (!action.picker) {
460
+ selectAction(action);
461
+ return;
462
+ }
463
+ // A request starts outside the menu, so its picker opens as a dialog: a
464
+ // submenu opened programmatically loses focus to its parents and closes.
465
+ const session = { id: action.id, scopeKey: action.picker.scopeKey };
466
+ dialogRef.current = session;
467
+ setDialog(session);
468
+ };
469
+ const openRequestedEntryRef = useRef(openRequestedEntry);
470
+ openRequestedEntryRef.current = openRequestedEntry;
471
+ useEffect(() => {
472
+ if (openEntry) openRequestedEntryRef.current(openEntry.id);
473
+ }, [openEntry]);
402
474
  const currentAction = page ? findAction(allItems, page.id) : undefined;
403
475
  useEffect(() => {
404
476
  if (
@@ -718,7 +790,7 @@ export function ComposerContextMenu({
718
790
  <ComposerContextPickerDialog
719
791
  key={JSON.stringify([dialog.id, dialogAction.picker.scopeKey])}
720
792
  title={dialogAction.label}
721
- config={dialogAction.picker}
793
+ config={asDialogPicker(dialogAction.picker)}
722
794
  onClose={() => {
723
795
  if (dialogRef.current !== dialog) return;
724
796
  dialogRef.current = null;