@agent-native/toolkit 0.213.1 → 0.216.0
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/agent-native.eject.json +9 -0
- package/dist/app/agentkit/react/chat.d.ts.map +1 -1
- package/dist/app/agentkit/react/chat.js +2 -2
- package/dist/app/agentkit/react/chat.js.map +1 -1
- package/dist/app/agentkit/react/components.d.ts +4 -1
- package/dist/app/agentkit/react/components.d.ts.map +1 -1
- package/dist/app/agentkit/react/components.js +73 -13
- package/dist/app/agentkit/react/components.js.map +1 -1
- package/dist/app/agentkit/react/context.d.ts +19 -1
- package/dist/app/agentkit/react/context.d.ts.map +1 -1
- package/dist/app/agentkit/react/context.js +7 -1
- package/dist/app/agentkit/react/context.js.map +1 -1
- package/dist/app/agentkit/react/index.d.ts +2 -0
- package/dist/app/agentkit/react/index.d.ts.map +1 -1
- package/dist/app/agentkit/react/index.js +2 -0
- package/dist/app/agentkit/react/index.js.map +1 -1
- package/dist/app/agentkit/react/message-content-order.d.ts +21 -0
- package/dist/app/agentkit/react/message-content-order.d.ts.map +1 -0
- package/dist/app/agentkit/react/message-content-order.js +173 -0
- package/dist/app/agentkit/react/message-content-order.js.map +1 -0
- package/dist/app/agentkit/react/root.d.ts +6 -1
- package/dist/app/agentkit/react/root.d.ts.map +1 -1
- package/dist/app/agentkit/react/root.js +2 -2
- package/dist/app/agentkit/react/root.js.map +1 -1
- package/dist/app/agentkit/react/styles.css +45 -8
- package/dist/app/agentkit/react/transcript-layout.d.ts +51 -0
- package/dist/app/agentkit/react/transcript-layout.d.ts.map +1 -0
- package/dist/app/agentkit/react/transcript-layout.js +34 -0
- package/dist/app/agentkit/react/transcript-layout.js.map +1 -0
- package/dist/app/chat/AgentKitAssistantChat.d.ts.map +1 -1
- package/dist/app/chat/AgentKitAssistantChat.js +9 -4
- package/dist/app/chat/AgentKitAssistantChat.js.map +1 -1
- package/dist/app/chat/AgentPanel.d.ts +16 -2
- package/dist/app/chat/AgentPanel.d.ts.map +1 -1
- package/dist/app/chat/AgentPanel.js +26 -5
- package/dist/app/chat/AgentPanel.js.map +1 -1
- package/dist/app/chat/chat/index.d.ts +2 -0
- package/dist/app/chat/chat/index.d.ts.map +1 -1
- package/dist/app/chat/chat/index.js.map +1 -1
- package/dist/app/chat/chat/surface-types.d.ts +15 -0
- package/dist/app/chat/chat/surface-types.d.ts.map +1 -1
- package/dist/app/chat/chat/surface-types.js.map +1 -1
- package/dist/app/chat/chat/tool-call-display.d.ts +7 -2
- package/dist/app/chat/chat/tool-call-display.d.ts.map +1 -1
- package/dist/app/chat/chat/tool-call-display.js +10 -9
- package/dist/app/chat/chat/tool-call-display.js.map +1 -1
- package/dist/app/chat/chat/widgets/DataChartRenderer.d.ts.map +1 -1
- package/dist/app/chat/chat/widgets/DataChartRenderer.js +300 -33
- package/dist/app/chat/chat/widgets/DataChartRenderer.js.map +1 -1
- package/dist/app/chat/chat/widgets/DataChartWidget.d.ts +3 -2
- package/dist/app/chat/chat/widgets/DataChartWidget.d.ts.map +1 -1
- package/dist/app/chat/chat/widgets/DataChartWidget.js +18 -9
- package/dist/app/chat/chat/widgets/DataChartWidget.js.map +1 -1
- package/dist/app/chat/chat/widgets/DataInsightsWidget.js +1 -1
- package/dist/app/chat/chat/widgets/DataInsightsWidget.js.map +1 -1
- package/dist/app/chat/chat/widgets/DataTableWidget.d.ts +3 -2
- package/dist/app/chat/chat/widgets/DataTableWidget.d.ts.map +1 -1
- package/dist/app/chat/chat/widgets/DataTableWidget.js +10 -66
- package/dist/app/chat/chat/widgets/DataTableWidget.js.map +1 -1
- package/dist/app/chat/chat/widgets/DataWidgetDisplayControls.d.ts +11 -0
- package/dist/app/chat/chat/widgets/DataWidgetDisplayControls.d.ts.map +1 -0
- package/dist/app/chat/chat/widgets/DataWidgetDisplayControls.js +133 -0
- package/dist/app/chat/chat/widgets/DataWidgetDisplayControls.js.map +1 -0
- package/dist/app/chat/chat/widgets/builtin-tool-renderers.js +2 -2
- package/dist/app/chat/chat/widgets/builtin-tool-renderers.js.map +1 -1
- package/dist/app/chat/mcp-apps/McpAppRenderer.d.ts.map +1 -1
- package/dist/app/chat/mcp-apps/McpAppRenderer.js +6 -5
- package/dist/app/chat/mcp-apps/McpAppRenderer.js.map +1 -1
- package/dist/app/chat/mcp-apps/mcp-app-theme.d.ts +2 -0
- package/dist/app/chat/mcp-apps/mcp-app-theme.d.ts.map +1 -0
- package/dist/app/chat/mcp-apps/mcp-app-theme.js +11 -0
- package/dist/app/chat/mcp-apps/mcp-app-theme.js.map +1 -0
- package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ar-SA.js +9 -0
- package/dist/app/i18n/catalogs/ar-SA.js.map +1 -1
- package/dist/app/i18n/catalogs/de-DE.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/de-DE.js +9 -0
- package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
- package/dist/app/i18n/catalogs/en-US.d.ts +9 -0
- package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/en-US.js +9 -0
- package/dist/app/i18n/catalogs/en-US.js.map +1 -1
- package/dist/app/i18n/catalogs/es-ES.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/es-ES.js +9 -0
- package/dist/app/i18n/catalogs/es-ES.js.map +1 -1
- package/dist/app/i18n/catalogs/fr-FR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/fr-FR.js +9 -0
- package/dist/app/i18n/catalogs/fr-FR.js.map +1 -1
- package/dist/app/i18n/catalogs/hi-IN.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/hi-IN.js +9 -0
- package/dist/app/i18n/catalogs/hi-IN.js.map +1 -1
- package/dist/app/i18n/catalogs/ja-JP.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ja-JP.js +9 -0
- package/dist/app/i18n/catalogs/ja-JP.js.map +1 -1
- package/dist/app/i18n/catalogs/ko-KR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ko-KR.js +9 -0
- package/dist/app/i18n/catalogs/ko-KR.js.map +1 -1
- package/dist/app/i18n/catalogs/pt-BR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/pt-BR.js +9 -0
- package/dist/app/i18n/catalogs/pt-BR.js.map +1 -1
- package/dist/app/i18n/catalogs/zh-CN.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/zh-CN.js +9 -0
- package/dist/app/i18n/catalogs/zh-CN.js.map +1 -1
- package/dist/app/i18n/catalogs/zh-TW.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/zh-TW.js +9 -0
- package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
- package/dist/app/providers/AppProviders.d.ts +2 -1
- package/dist/app/providers/AppProviders.d.ts.map +1 -1
- package/dist/app/providers/AppProviders.js +4 -3
- package/dist/app/providers/AppProviders.js.map +1 -1
- package/dist/app/providers/ThemeFamilySync.d.ts +2 -0
- package/dist/app/providers/ThemeFamilySync.d.ts.map +1 -0
- package/dist/app/providers/ThemeFamilySync.js +6 -0
- package/dist/app/providers/ThemeFamilySync.js.map +1 -0
- package/dist/app/settings/account/PreferencesSettings.d.ts.map +1 -1
- package/dist/app/settings/account/PreferencesSettings.js +2 -1
- package/dist/app/settings/account/PreferencesSettings.js.map +1 -1
- package/dist/app/settings/account/ThemeFamilySettings.d.ts +2 -0
- package/dist/app/settings/account/ThemeFamilySettings.d.ts.map +1 -0
- package/dist/app/settings/account/ThemeFamilySettings.js +31 -0
- package/dist/app/settings/account/ThemeFamilySettings.js.map +1 -0
- package/dist/app/settings/account/search-entries.d.ts.map +1 -1
- package/dist/app/settings/account/search-entries.js +6 -0
- package/dist/app/settings/account/search-entries.js.map +1 -1
- package/dist/app/shared/DefaultSpinner.d.ts.map +1 -1
- package/dist/app/shared/DefaultSpinner.js +4 -5
- package/dist/app/shared/DefaultSpinner.js.map +1 -1
- package/dist/app/shared/ErrorBoundary.d.ts +1 -0
- package/dist/app/shared/ErrorBoundary.d.ts.map +1 -1
- package/dist/app/shared/ErrorBoundary.js +27 -12
- package/dist/app/shared/ErrorBoundary.js.map +1 -1
- package/dist/app/shared/PoweredByBadge.d.ts.map +1 -1
- package/dist/app/shared/PoweredByBadge.js +8 -49
- package/dist/app/shared/PoweredByBadge.js.map +1 -1
- package/dist/app/styles/agent-conversation.css +0 -23
- package/dist/app/styles/agent-native.css +1 -1
- package/dist/app/styles/theme-families.css +66 -0
- package/dist/composer/ComposerContextBanner.d.ts +24 -0
- package/dist/composer/ComposerContextBanner.d.ts.map +1 -0
- package/dist/composer/ComposerContextBanner.js +9 -0
- package/dist/composer/ComposerContextBanner.js.map +1 -0
- package/dist/composer/ComposerModePicker.d.ts +26 -0
- package/dist/composer/ComposerModePicker.d.ts.map +1 -0
- package/dist/composer/ComposerModePicker.js +14 -0
- package/dist/composer/ComposerModePicker.js.map +1 -0
- package/dist/composer/index.d.ts +2 -0
- package/dist/composer/index.d.ts.map +1 -1
- package/dist/composer/index.js +2 -0
- package/dist/composer/index.js.map +1 -1
- package/dist/styles.css +1 -0
- package/package.json +3 -3
- package/src/app/agentkit/react/chat.tsx +2 -0
- package/src/app/agentkit/react/components.interaction.spec.tsx +107 -0
- package/src/app/agentkit/react/components.spec.tsx +40 -1
- package/src/app/agentkit/react/components.tsx +186 -31
- package/src/app/agentkit/react/context.tsx +29 -0
- package/src/app/agentkit/react/index.ts +2 -0
- package/src/app/agentkit/react/lifecycle.spec.tsx +289 -4
- package/src/app/agentkit/react/message-content-order.spec.ts +190 -0
- package/src/app/agentkit/react/message-content-order.ts +246 -0
- package/src/app/agentkit/react/root.tsx +11 -0
- package/src/app/agentkit/react/styles.css +45 -8
- package/src/app/agentkit/react/transcript-layout.spec.ts +72 -0
- package/src/app/agentkit/react/transcript-layout.ts +97 -0
- package/src/app/auth/AuthPage.attribution.spec.tsx +6 -0
- package/src/app/chat/AgentKitAssistantChat.spec.tsx +58 -0
- package/src/app/chat/AgentKitAssistantChat.tsx +15 -1
- package/src/app/chat/AgentPanel.header.spec.ts +72 -14
- package/src/app/chat/AgentPanel.page-header-share.spec.tsx +101 -0
- package/src/app/chat/AgentPanel.tsx +111 -55
- package/src/app/chat/chat/index.ts +2 -0
- package/src/app/chat/chat/surface-types.ts +18 -0
- package/src/app/chat/chat/tool-call-display.spec.tsx +83 -0
- package/src/app/chat/chat/tool-call-display.tsx +40 -8
- package/src/app/chat/chat/widgets/DataChartRenderer.spec.tsx +849 -0
- package/src/app/chat/chat/widgets/DataChartRenderer.tsx +567 -72
- package/src/app/chat/chat/widgets/DataChartWidget.spec.tsx +432 -0
- package/src/app/chat/chat/widgets/DataChartWidget.ssr.spec.tsx +25 -0
- package/src/app/chat/chat/widgets/DataChartWidget.tsx +58 -33
- package/src/app/chat/chat/widgets/DataInsightsWidget.tsx +2 -2
- package/src/app/chat/chat/widgets/DataTableWidget.spec.tsx +37 -3
- package/src/app/chat/chat/widgets/DataTableWidget.tsx +22 -86
- package/src/app/chat/chat/widgets/DataWidgetDisplayControls.tsx +321 -0
- package/src/app/chat/chat/widgets/builtin-tool-renderers.tsx +5 -5
- package/src/app/chat/mcp-apps/McpAppRenderer.tsx +10 -5
- package/src/app/chat/mcp-apps/mcp-app-theme.spec.ts +30 -0
- package/src/app/chat/mcp-apps/mcp-app-theme.ts +11 -0
- package/src/app/i18n/catalogs/ar-SA.ts +10 -0
- package/src/app/i18n/catalogs/de-DE.ts +11 -0
- package/src/app/i18n/catalogs/en-US.ts +11 -0
- package/src/app/i18n/catalogs/es-ES.ts +12 -0
- package/src/app/i18n/catalogs/fr-FR.ts +12 -0
- package/src/app/i18n/catalogs/hi-IN.ts +10 -0
- package/src/app/i18n/catalogs/ja-JP.ts +11 -0
- package/src/app/i18n/catalogs/ko-KR.ts +10 -0
- package/src/app/i18n/catalogs/pt-BR.ts +11 -0
- package/src/app/i18n/catalogs/zh-CN.ts +9 -0
- package/src/app/i18n/catalogs/zh-TW.ts +10 -0
- package/src/app/providers/AppProviders.spec.tsx +71 -0
- package/src/app/providers/AppProviders.tsx +10 -0
- package/src/app/providers/ThemeFamilySync.tsx +6 -0
- package/src/app/settings/account/PreferencesSettings.spec.tsx +13 -2
- package/src/app/settings/account/PreferencesSettings.tsx +8 -0
- package/src/app/settings/account/ThemeFamilySettings.tsx +61 -0
- package/src/app/settings/account/search-entries.ts +6 -0
- package/src/app/shared/DefaultSpinner.spec.tsx +14 -0
- package/src/app/shared/DefaultSpinner.tsx +4 -5
- package/src/app/shared/ErrorBoundary.spec.tsx +45 -2
- package/src/app/shared/ErrorBoundary.tsx +37 -12
- package/src/app/shared/PoweredByBadge.spec.tsx +16 -0
- package/src/app/shared/PoweredByBadge.tsx +8 -50
- package/src/app/styles/agent-conversation.css +0 -23
- package/src/app/styles/agent-native.css +1 -1
- package/src/app/styles/agent-native.spec.ts +18 -0
- package/src/app/styles/theme-families.css +66 -0
- package/src/app/styles/theme-families.spec.ts +29 -0
- package/src/composer/ComposerContextBanner.spec.tsx +100 -0
- package/src/composer/ComposerContextBanner.tsx +77 -0
- package/src/composer/ComposerModePicker.spec.tsx +101 -0
- package/src/composer/ComposerModePicker.tsx +98 -0
- package/src/composer/index.ts +9 -0
- package/src/styles.css +1 -0
|
@@ -2093,12 +2093,22 @@ export const AgentKitAssistantChat = forwardRef<
|
|
|
2093
2093
|
threadId={threadId}
|
|
2094
2094
|
load={agentKitLoad}
|
|
2095
2095
|
onLoadError={onThreadRestoreLoadError}
|
|
2096
|
-
slots={
|
|
2096
|
+
slots={
|
|
2097
|
+
props.workedForSummarySlot
|
|
2098
|
+
? {
|
|
2099
|
+
...agentKitSlots,
|
|
2100
|
+
workedForSummary: props.workedForSummarySlot,
|
|
2101
|
+
}
|
|
2102
|
+
: agentKitSlots
|
|
2103
|
+
}
|
|
2097
2104
|
registry={agentKitRegistry}
|
|
2098
2105
|
labels={labels}
|
|
2106
|
+
resolveMessageContentOrder={props.resolveMessageContentOrder}
|
|
2099
2107
|
branchNavigation={props.branchNavigation}
|
|
2100
2108
|
loadRunUsage={loadRunUsage}
|
|
2101
2109
|
buildFeedbackReport={formatFeedbackReport}
|
|
2110
|
+
workedForRowLayout={props.workedForRowLayout}
|
|
2111
|
+
formatWorkedForDuration={props.formatWorkedForDuration}
|
|
2102
2112
|
onThreadForked={(thread) => props.onForkedThread?.(thread.id)}
|
|
2103
2113
|
onCopyMessage={({ text }) => {
|
|
2104
2114
|
const html = renderMarkdownToClipboardHtml(text);
|
|
@@ -5046,6 +5056,7 @@ const AgentKitAssistantChatBody = forwardRef<
|
|
|
5046
5056
|
className={props.className}
|
|
5047
5057
|
composerProps={{ attachmentsEnabled: fileStorageConfigured }}
|
|
5048
5058
|
hasRenderedMessages={hasRenderedMessages}
|
|
5059
|
+
transcriptLayout={props.transcriptLayout}
|
|
5049
5060
|
emptyComposerPlacement={
|
|
5050
5061
|
props.centerComposerWhenEmpty && !isRestoring ? "center" : "bottom"
|
|
5051
5062
|
}
|
|
@@ -5979,6 +5990,7 @@ function AgentKitComposerSurface({
|
|
|
5979
5990
|
})}
|
|
5980
5991
|
/>
|
|
5981
5992
|
{props.composerSlot}
|
|
5993
|
+
{props.composerContextBannerSlot}
|
|
5982
5994
|
{showHomeIntro ? (
|
|
5983
5995
|
<div className="agentkit-home-intro">{props.homeIntroSlot}</div>
|
|
5984
5996
|
) : null}
|
|
@@ -6461,6 +6473,8 @@ function AgentKitTool({ value, active }: AgentKitRenderProps<AgentToolCall>) {
|
|
|
6461
6473
|
chatUI={asRecord(metadata.chatUI) as never}
|
|
6462
6474
|
activity={metadata.activity === true}
|
|
6463
6475
|
isActiveTail={active === true}
|
|
6476
|
+
workedForRowLayout={surface.props.workedForRowLayout}
|
|
6477
|
+
formatWorkedForDuration={surface.props.formatWorkedForDuration}
|
|
6464
6478
|
/>
|
|
6465
6479
|
</SuppressInlineOpenAppContext.Provider>
|
|
6466
6480
|
</ChatRunningContext.Provider>
|
|
@@ -31,6 +31,8 @@ import {
|
|
|
31
31
|
shouldHandleAgentSidebarToggle,
|
|
32
32
|
shouldHandleAgentPanelChatShortcut,
|
|
33
33
|
shouldShowAgentPanelFullViewAction,
|
|
34
|
+
resolveAgentPanelPageHeaderActions,
|
|
35
|
+
resolveAgentPanelPageToolbarSlot,
|
|
34
36
|
shouldShowAgentPanelPageHeader,
|
|
35
37
|
shouldShowAgentPanelPageNewChatButton,
|
|
36
38
|
shouldShowAgentPanelChatTabBar,
|
|
@@ -350,22 +352,60 @@ describe("AgentPanel header tab visibility", () => {
|
|
|
350
352
|
expect(shouldDefaultAgentChatSurfacePageHeader(undefined)).toBe(false);
|
|
351
353
|
});
|
|
352
354
|
|
|
353
|
-
it("
|
|
354
|
-
|
|
355
|
+
it("keeps share and host toolbar actions when the title menu is hidden", async () => {
|
|
356
|
+
expect(
|
|
357
|
+
resolveAgentPanelPageHeaderActions({
|
|
358
|
+
showPageTitleMenu: false,
|
|
359
|
+
canShareActiveTab: true,
|
|
360
|
+
}),
|
|
361
|
+
).toEqual({ showPageTitleMenu: false, showShareAction: true });
|
|
355
362
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
363
|
+
const container = document.createElement("div");
|
|
364
|
+
document.body.append(container);
|
|
365
|
+
const root = createRoot(container);
|
|
366
|
+
const toggleHistory = vi.fn();
|
|
367
|
+
const clearActiveTab = vi.fn();
|
|
368
|
+
const toolbar = resolveAgentPanelPageToolbarSlot(
|
|
369
|
+
(actions) =>
|
|
370
|
+
React.createElement(
|
|
371
|
+
"div",
|
|
372
|
+
null,
|
|
373
|
+
React.createElement(
|
|
374
|
+
"button",
|
|
375
|
+
{ onClick: actions.toggleHistory },
|
|
376
|
+
actions.showHistory ? "Hide chats" : "All chats",
|
|
377
|
+
),
|
|
378
|
+
actions.activeTabMessageCount > 0
|
|
379
|
+
? React.createElement(
|
|
380
|
+
"button",
|
|
381
|
+
{ onClick: actions.clearActiveTab },
|
|
382
|
+
"Clear chat",
|
|
383
|
+
)
|
|
384
|
+
: null,
|
|
385
|
+
),
|
|
386
|
+
{
|
|
387
|
+
activeTabMessageCount: 2,
|
|
388
|
+
clearActiveTab,
|
|
389
|
+
showHistory: false,
|
|
390
|
+
toggleHistory,
|
|
391
|
+
},
|
|
367
392
|
);
|
|
368
|
-
|
|
393
|
+
|
|
394
|
+
try {
|
|
395
|
+
await act(async () => root.render(toolbar));
|
|
396
|
+
const buttons = container.querySelectorAll("button");
|
|
397
|
+
expect([...buttons].map((button) => button.textContent)).toEqual([
|
|
398
|
+
"All chats",
|
|
399
|
+
"Clear chat",
|
|
400
|
+
]);
|
|
401
|
+
await act(async () => buttons[0]?.click());
|
|
402
|
+
await act(async () => buttons[1]?.click());
|
|
403
|
+
expect(toggleHistory).toHaveBeenCalledOnce();
|
|
404
|
+
expect(clearActiveTab).toHaveBeenCalledOnce();
|
|
405
|
+
} finally {
|
|
406
|
+
await act(async () => root.unmount());
|
|
407
|
+
container.remove();
|
|
408
|
+
}
|
|
369
409
|
});
|
|
370
410
|
|
|
371
411
|
it("normalizes legacy and unknown modes back to chat", () => {
|
|
@@ -1193,6 +1233,24 @@ describe("AgentChatSurface chrome defaults", () => {
|
|
|
1193
1233
|
expect(surface.props.showHeader).toBe(true);
|
|
1194
1234
|
expect(surface.props.showTabBar).toBe(true);
|
|
1195
1235
|
});
|
|
1236
|
+
|
|
1237
|
+
it("allows a page host to hide only the title menu", () => {
|
|
1238
|
+
const surface = AgentChatSurface({
|
|
1239
|
+
mode: "page",
|
|
1240
|
+
showPageTitleMenu: false,
|
|
1241
|
+
});
|
|
1242
|
+
const panel = surface.props.children[1];
|
|
1243
|
+
const headerActions = resolveAgentPanelPageHeaderActions({
|
|
1244
|
+
showPageTitleMenu: false,
|
|
1245
|
+
canShareActiveTab: true,
|
|
1246
|
+
});
|
|
1247
|
+
|
|
1248
|
+
expect(panel.props.showPageTitleMenu).toBe(false);
|
|
1249
|
+
expect(headerActions).toEqual({
|
|
1250
|
+
showPageTitleMenu: false,
|
|
1251
|
+
showShareAction: true,
|
|
1252
|
+
});
|
|
1253
|
+
});
|
|
1196
1254
|
});
|
|
1197
1255
|
|
|
1198
1256
|
describe("AgentPanel stale lazy chunk recovery", () => {
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// @vitest-environment happy-dom
|
|
2
|
+
|
|
3
|
+
import React, { act } from "react";
|
|
4
|
+
import { createRoot, type Root } from "react-dom/client";
|
|
5
|
+
import { MemoryRouter } from "react-router";
|
|
6
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
7
|
+
|
|
8
|
+
import { AgentPanel } from "./AgentPanel.js";
|
|
9
|
+
|
|
10
|
+
type MockHeaderProps = {
|
|
11
|
+
renderOverlay?: (props: never) => React.ReactNode;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
vi.mock("./MultiTabAssistantChat.js", () => ({
|
|
15
|
+
MultiTabAssistantChat: ({ renderOverlay }: MockHeaderProps) =>
|
|
16
|
+
renderOverlay?.({
|
|
17
|
+
tabs: [{ id: "thread-1", label: "Current thread", status: "completed" }],
|
|
18
|
+
activeTabId: "thread-1",
|
|
19
|
+
activeTabMessageCount: 1,
|
|
20
|
+
activeTabIsPersisted: true,
|
|
21
|
+
setActiveTabId: vi.fn(),
|
|
22
|
+
addTab: vi.fn(),
|
|
23
|
+
closeTab: vi.fn(),
|
|
24
|
+
closeOtherTabs: vi.fn(),
|
|
25
|
+
closeAllTabs: vi.fn(),
|
|
26
|
+
clearActiveTab: vi.fn(),
|
|
27
|
+
showHistory: false,
|
|
28
|
+
toggleHistory: vi.fn(),
|
|
29
|
+
tabCount: 1,
|
|
30
|
+
} as never) ?? null,
|
|
31
|
+
}));
|
|
32
|
+
|
|
33
|
+
vi.mock("../sharing/index.js", () => ({
|
|
34
|
+
ShareButton: ({
|
|
35
|
+
triggerContent,
|
|
36
|
+
triggerClassName,
|
|
37
|
+
}: {
|
|
38
|
+
triggerContent?: React.ReactNode;
|
|
39
|
+
triggerClassName?: string;
|
|
40
|
+
}) => (
|
|
41
|
+
<button data-testid="share-trigger" data-trigger-class={triggerClassName}>
|
|
42
|
+
{triggerContent ?? "Share"}
|
|
43
|
+
</button>
|
|
44
|
+
),
|
|
45
|
+
}));
|
|
46
|
+
|
|
47
|
+
describe("AgentPanel page header share trigger", () => {
|
|
48
|
+
let root: Root | null = null;
|
|
49
|
+
let container: HTMLDivElement | null = null;
|
|
50
|
+
|
|
51
|
+
afterEach(async () => {
|
|
52
|
+
if (root) await act(async () => root?.unmount());
|
|
53
|
+
container?.remove();
|
|
54
|
+
root = null;
|
|
55
|
+
container = null;
|
|
56
|
+
localStorage.clear();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("renders the default icon and host-provided content through ShareButton", async () => {
|
|
60
|
+
container = document.createElement("div");
|
|
61
|
+
document.body.append(container);
|
|
62
|
+
root = createRoot(container);
|
|
63
|
+
|
|
64
|
+
const renderPanel = async (triggerContent?: React.ReactNode) =>
|
|
65
|
+
act(async () => {
|
|
66
|
+
root!.render(
|
|
67
|
+
<MemoryRouter>
|
|
68
|
+
<AgentPanel
|
|
69
|
+
storageKey="page-header-share-test"
|
|
70
|
+
showHeader={false}
|
|
71
|
+
showPageHeader
|
|
72
|
+
pageHeaderShareTriggerContent={triggerContent}
|
|
73
|
+
/>
|
|
74
|
+
</MemoryRouter>,
|
|
75
|
+
);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
await renderPanel();
|
|
79
|
+
const defaultButton = container.querySelector<HTMLButtonElement>(
|
|
80
|
+
'[data-testid="share-trigger"]',
|
|
81
|
+
);
|
|
82
|
+
expect(defaultButton?.querySelector("svg")).not.toBeNull();
|
|
83
|
+
expect(defaultButton?.dataset.triggerClass).toContain("size-8");
|
|
84
|
+
|
|
85
|
+
await renderPanel(
|
|
86
|
+
<span className="flex items-center gap-1.5">
|
|
87
|
+
<svg data-testid="custom-share-icon" aria-hidden="true" />
|
|
88
|
+
<span>Share</span>
|
|
89
|
+
</span>,
|
|
90
|
+
);
|
|
91
|
+
const customButton = container.querySelector<HTMLButtonElement>(
|
|
92
|
+
'[data-testid="share-trigger"]',
|
|
93
|
+
);
|
|
94
|
+
expect(customButton?.textContent).toBe("Share");
|
|
95
|
+
expect(
|
|
96
|
+
customButton?.querySelector('[data-testid="custom-share-icon"]'),
|
|
97
|
+
).not.toBeNull();
|
|
98
|
+
expect(customButton?.dataset.triggerClass).toContain("w-auto");
|
|
99
|
+
expect(customButton?.dataset.triggerClass).toContain("px-2");
|
|
100
|
+
});
|
|
101
|
+
});
|
|
@@ -441,6 +441,30 @@ export function shouldShowAgentPanelPageHeader(
|
|
|
441
441
|
);
|
|
442
442
|
}
|
|
443
443
|
|
|
444
|
+
export function resolveAgentPanelPageHeaderActions({
|
|
445
|
+
showPageTitleMenu = true,
|
|
446
|
+
canShareActiveTab,
|
|
447
|
+
}: {
|
|
448
|
+
showPageTitleMenu?: boolean;
|
|
449
|
+
canShareActiveTab: boolean;
|
|
450
|
+
}) {
|
|
451
|
+
return { showPageTitleMenu, showShareAction: canShareActiveTab };
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
export type AgentPanelPageToolbarActions = Pick<
|
|
455
|
+
MultiTabAssistantChatHeaderCallbackProps,
|
|
456
|
+
"activeTabMessageCount" | "clearActiveTab" | "showHistory" | "toggleHistory"
|
|
457
|
+
>;
|
|
458
|
+
|
|
459
|
+
export function resolveAgentPanelPageToolbarSlot(
|
|
460
|
+
slot:
|
|
461
|
+
| React.ReactNode
|
|
462
|
+
| ((actions: AgentPanelPageToolbarActions) => React.ReactNode),
|
|
463
|
+
actions: AgentPanelPageToolbarActions,
|
|
464
|
+
) {
|
|
465
|
+
return typeof slot === "function" ? slot(actions) : slot;
|
|
466
|
+
}
|
|
467
|
+
|
|
444
468
|
export function shouldShowAgentPanelCliTabBar(cliTabs: string[]) {
|
|
445
469
|
return cliTabs.length > 1;
|
|
446
470
|
}
|
|
@@ -583,8 +607,15 @@ export interface AgentPanelProps extends Omit<
|
|
|
583
607
|
showPageNewChatButton?: boolean;
|
|
584
608
|
showPageHeader?: boolean;
|
|
585
609
|
showPageHeaderWhenEmpty?: boolean;
|
|
610
|
+
/** Hide the default page title menu while keeping the shared page actions. */
|
|
611
|
+
showPageTitleMenu?: boolean;
|
|
586
612
|
pageHeaderLeadingSlot?: React.ReactNode;
|
|
587
|
-
|
|
613
|
+
/** Override the shared page header share button's icon and label contents. */
|
|
614
|
+
pageHeaderShareTriggerContent?: React.ReactNode;
|
|
615
|
+
/** Render host page actions alongside Share, with the active chat controls. */
|
|
616
|
+
pageToolbarSlot?:
|
|
617
|
+
| React.ReactNode
|
|
618
|
+
| ((actions: AgentPanelPageToolbarActions) => React.ReactNode);
|
|
588
619
|
onPageHeaderVisibilityChange?: (visible: boolean) => void;
|
|
589
620
|
chatOnly?: boolean;
|
|
590
621
|
agentPageHref?: string;
|
|
@@ -778,7 +809,9 @@ function AgentPanelInner({
|
|
|
778
809
|
showPageNewChatButton = false,
|
|
779
810
|
showPageHeader = false,
|
|
780
811
|
showPageHeaderWhenEmpty = false,
|
|
812
|
+
showPageTitleMenu = true,
|
|
781
813
|
pageHeaderLeadingSlot,
|
|
814
|
+
pageHeaderShareTriggerContent,
|
|
782
815
|
pageToolbarSlot,
|
|
783
816
|
onPageHeaderVisibilityChange,
|
|
784
817
|
chatOnly = false,
|
|
@@ -1694,11 +1727,16 @@ function AgentPanelInner({
|
|
|
1694
1727
|
showPageHeaderWhenEmpty,
|
|
1695
1728
|
activeTabIsPersisted,
|
|
1696
1729
|
);
|
|
1697
|
-
const canShareActiveTab =
|
|
1730
|
+
const canShareActiveTab = Boolean(
|
|
1698
1731
|
activeTab &&
|
|
1699
1732
|
(activeTabIsPersisted ||
|
|
1700
1733
|
activeTabMessageCount > 0 ||
|
|
1701
|
-
activeTab.status !== "idle")
|
|
1734
|
+
activeTab.status !== "idle"),
|
|
1735
|
+
);
|
|
1736
|
+
const pageHeaderActions = resolveAgentPanelPageHeaderActions({
|
|
1737
|
+
showPageTitleMenu,
|
|
1738
|
+
canShareActiveTab,
|
|
1739
|
+
});
|
|
1702
1740
|
const showNewChatAction =
|
|
1703
1741
|
showPageNewChatButton &&
|
|
1704
1742
|
shouldShowAgentPanelPageNewChatButton(
|
|
@@ -1707,6 +1745,12 @@ function AgentPanelInner({
|
|
|
1707
1745
|
activeTabMessageCount,
|
|
1708
1746
|
activeTabIsPersisted,
|
|
1709
1747
|
);
|
|
1748
|
+
const toolbarSlot = resolveAgentPanelPageToolbarSlot(pageToolbarSlot, {
|
|
1749
|
+
activeTabMessageCount,
|
|
1750
|
+
clearActiveTab,
|
|
1751
|
+
showHistory,
|
|
1752
|
+
toggleHistory,
|
|
1753
|
+
});
|
|
1710
1754
|
|
|
1711
1755
|
return (
|
|
1712
1756
|
<>
|
|
@@ -1730,62 +1774,64 @@ function AgentPanelInner({
|
|
|
1730
1774
|
<h1 className="truncate text-xs font-medium text-foreground">
|
|
1731
1775
|
{activeTab?.label || t("agentPanel.newChat")}
|
|
1732
1776
|
</h1>
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
<DropdownMenuTrigger asChild>
|
|
1738
|
-
<button
|
|
1739
|
-
type="button"
|
|
1740
|
-
data-agent-page-title-menu=""
|
|
1741
|
-
aria-label={t("agentPanel.panelOptions")}
|
|
1742
|
-
className="flex size-7 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent/60 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring data-[state=open]:bg-accent data-[state=open]:text-foreground"
|
|
1743
|
-
>
|
|
1744
|
-
<IconDotsVertical size={14} />
|
|
1745
|
-
</button>
|
|
1746
|
-
</DropdownMenuTrigger>
|
|
1747
|
-
<DropdownMenuContent
|
|
1748
|
-
align="start"
|
|
1749
|
-
sideOffset={5}
|
|
1750
|
-
className="w-44"
|
|
1751
|
-
onCloseAutoFocus={(event) => {
|
|
1752
|
-
consumeAgentPanelOverlayFocusRestore(
|
|
1753
|
-
pendingHeaderOverlayRef,
|
|
1754
|
-
event,
|
|
1755
|
-
);
|
|
1756
|
-
}}
|
|
1777
|
+
{pageHeaderActions.showPageTitleMenu ? (
|
|
1778
|
+
<DropdownMenu
|
|
1779
|
+
open={headerMenuOpen}
|
|
1780
|
+
onOpenChange={setHeaderMenuOpen}
|
|
1757
1781
|
>
|
|
1758
|
-
|
|
1759
|
-
<
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
toggleHistory,
|
|
1765
|
-
pendingHeaderOverlayRef,
|
|
1766
|
-
)
|
|
1767
|
-
}
|
|
1782
|
+
<DropdownMenuTrigger asChild>
|
|
1783
|
+
<button
|
|
1784
|
+
type="button"
|
|
1785
|
+
data-agent-page-title-menu=""
|
|
1786
|
+
aria-label={t("agentPanel.panelOptions")}
|
|
1787
|
+
className="flex size-7 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent/60 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring data-[state=open]:bg-accent data-[state=open]:text-foreground"
|
|
1768
1788
|
>
|
|
1769
|
-
<
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1789
|
+
<IconDotsVertical size={14} />
|
|
1790
|
+
</button>
|
|
1791
|
+
</DropdownMenuTrigger>
|
|
1792
|
+
<DropdownMenuContent
|
|
1793
|
+
align="start"
|
|
1794
|
+
sideOffset={5}
|
|
1795
|
+
className="w-44"
|
|
1796
|
+
onCloseAutoFocus={(event) => {
|
|
1797
|
+
consumeAgentPanelOverlayFocusRestore(
|
|
1798
|
+
pendingHeaderOverlayRef,
|
|
1799
|
+
event,
|
|
1800
|
+
);
|
|
1801
|
+
}}
|
|
1802
|
+
>
|
|
1803
|
+
{toggleHistory ? (
|
|
1804
|
+
<DropdownMenuItem
|
|
1805
|
+
onSelect={(event) =>
|
|
1806
|
+
deferAgentPanelOverlayOpen(
|
|
1807
|
+
event,
|
|
1808
|
+
closeHeaderMenuForOverlay,
|
|
1809
|
+
toggleHistory,
|
|
1810
|
+
pendingHeaderOverlayRef,
|
|
1811
|
+
)
|
|
1812
|
+
}
|
|
1813
|
+
>
|
|
1814
|
+
<IconHistory size={14} className="shrink-0" />
|
|
1815
|
+
{showHistory
|
|
1816
|
+
? t("agentPanel.hideChats")
|
|
1817
|
+
: t("agentPanel.allChats")}
|
|
1818
|
+
</DropdownMenuItem>
|
|
1819
|
+
) : null}
|
|
1820
|
+
{activeTabMessageCount > 0 ? (
|
|
1821
|
+
<DropdownMenuItem onSelect={clearActiveTab}>
|
|
1822
|
+
<IconX size={14} className="shrink-0" />
|
|
1823
|
+
{t("agentPanel.clearChat")}
|
|
1824
|
+
</DropdownMenuItem>
|
|
1825
|
+
) : null}
|
|
1826
|
+
</DropdownMenuContent>
|
|
1827
|
+
</DropdownMenu>
|
|
1828
|
+
) : null}
|
|
1783
1829
|
{activeTab?.status === "running" ? (
|
|
1784
1830
|
<span className="size-1.5 shrink-0 rounded-full bg-muted-foreground/55 animate-pulse motion-reduce:animate-none" />
|
|
1785
1831
|
) : null}
|
|
1786
1832
|
</div>
|
|
1787
1833
|
<div className="flex shrink-0 items-center gap-1">
|
|
1788
|
-
{
|
|
1834
|
+
{pageHeaderActions.showShareAction && activeTab ? (
|
|
1789
1835
|
<ShareButton
|
|
1790
1836
|
resourceType="chat_thread"
|
|
1791
1837
|
resourceId={activeTab.id}
|
|
@@ -1793,12 +1839,20 @@ function AgentPanelInner({
|
|
|
1793
1839
|
resourceTitle={activeTab.label || t("agentPanel.chat")}
|
|
1794
1840
|
shareUrl={getChatThreadShareUrl(activeTab.id)}
|
|
1795
1841
|
triggerContent={
|
|
1796
|
-
|
|
1842
|
+
pageHeaderShareTriggerContent ?? (
|
|
1843
|
+
<IconShare3 size={15} aria-hidden="true" />
|
|
1844
|
+
)
|
|
1797
1845
|
}
|
|
1798
|
-
triggerClassName=
|
|
1846
|
+
triggerClassName={cn(
|
|
1847
|
+
"h-8 border-0 bg-transparent shadow-none hover:bg-accent/60",
|
|
1848
|
+
pageHeaderShareTriggerContent === undefined ||
|
|
1849
|
+
pageHeaderShareTriggerContent === null
|
|
1850
|
+
? "size-8 p-0"
|
|
1851
|
+
: "w-auto px-2",
|
|
1852
|
+
)}
|
|
1799
1853
|
/>
|
|
1800
1854
|
) : null}
|
|
1801
|
-
{
|
|
1855
|
+
{toolbarSlot}
|
|
1802
1856
|
{showNewChatAction ? (
|
|
1803
1857
|
<button
|
|
1804
1858
|
type="button"
|
|
@@ -1826,9 +1880,11 @@ function AgentPanelInner({
|
|
|
1826
1880
|
headerMenuOpen,
|
|
1827
1881
|
onPageHeaderVisibilityChange,
|
|
1828
1882
|
pageHeaderLeadingSlot,
|
|
1883
|
+
pageHeaderShareTriggerContent,
|
|
1829
1884
|
pageToolbarSlot,
|
|
1830
1885
|
pendingHeaderOverlayRef,
|
|
1831
1886
|
setHeaderMenuOpen,
|
|
1887
|
+
showPageTitleMenu,
|
|
1832
1888
|
showPageNewChatButton,
|
|
1833
1889
|
t,
|
|
1834
1890
|
],
|
|
@@ -53,6 +53,8 @@ export type {
|
|
|
53
53
|
AssistantChatSubmitResult,
|
|
54
54
|
AgentChatSurfaceKind,
|
|
55
55
|
} from "./surface-types.js";
|
|
56
|
+
export type { AgentChatTranscriptLayout } from "../../agentkit/react/transcript-layout.js";
|
|
57
|
+
export type { AgentChatWorkedForRowLayout } from "../../agentkit/react/transcript-layout.js";
|
|
56
58
|
export type {
|
|
57
59
|
MultiTabAssistantChatProps,
|
|
58
60
|
MultiTabAssistantChatHeaderProps,
|
|
@@ -26,6 +26,12 @@ import type {
|
|
|
26
26
|
import type { ExportedMessageRepository } from "@assistant-ui/react";
|
|
27
27
|
import type * as React from "react";
|
|
28
28
|
|
|
29
|
+
import type { AgentKitWorkedForSummaryRenderProps } from "../../agentkit/react/context.js";
|
|
30
|
+
import type { AgentMessageContentOrderResolver } from "../../agentkit/react/message-content-order.js";
|
|
31
|
+
import type {
|
|
32
|
+
AgentChatTranscriptLayout,
|
|
33
|
+
AgentChatWorkedForRowLayout,
|
|
34
|
+
} from "../../agentkit/react/transcript-layout.js";
|
|
29
35
|
import type { AssistantChatHistoryConfig } from "./history-types.js";
|
|
30
36
|
import type { BuilderSetupCardLayout } from "./run-recovery.js";
|
|
31
37
|
|
|
@@ -236,6 +242,12 @@ export interface AssistantChatProps {
|
|
|
236
242
|
/** Optional content rendered in the empty state, below the suggestion
|
|
237
243
|
* buttons. Unlike `threadFooterSlot` this never survives the first message. */
|
|
238
244
|
emptyStateFooter?: React.ReactNode;
|
|
245
|
+
/** Optional transcript geometry. Omitted values keep the shared defaults. */
|
|
246
|
+
transcriptLayout?: AgentChatTranscriptLayout;
|
|
247
|
+
/** Optional elapsed-work row geometry. Omitted values keep the shared defaults. */
|
|
248
|
+
workedForRowLayout?: AgentChatWorkedForRowLayout;
|
|
249
|
+
/** Optional duration text for the shared completed-work row. */
|
|
250
|
+
formatWorkedForDuration?: (durationMs: number) => string;
|
|
239
251
|
/** Whether to show the header bar. Default: true */
|
|
240
252
|
showHeader?: boolean;
|
|
241
253
|
/** CSS class for the outer container */
|
|
@@ -267,6 +279,12 @@ export interface AssistantChatProps {
|
|
|
267
279
|
) => void;
|
|
268
280
|
/** Optional content rendered just above the composer input */
|
|
269
281
|
composerSlot?: React.ReactNode;
|
|
282
|
+
/** Optional shared context banner rendered above the composer input. */
|
|
283
|
+
composerContextBannerSlot?: React.ReactNode;
|
|
284
|
+
/** Optional renderer for the shared work-summary disclosure row. */
|
|
285
|
+
workedForSummarySlot?: React.ComponentType<AgentKitWorkedForSummaryRenderProps>;
|
|
286
|
+
/** Optional ordering policy for assistant message text and attached widgets. */
|
|
287
|
+
resolveMessageContentOrder?: AgentMessageContentOrderResolver;
|
|
270
288
|
/** App-owned context controller, mounted separately for each chat thread. */
|
|
271
289
|
composerContextProvider?: React.ComponentType<AssistantChatComposerContextProviderProps>;
|
|
272
290
|
/** Optional home content rendered above the composer on an empty chat. */
|
|
@@ -2698,9 +2698,17 @@ describe("WorkedForSummary", () => {
|
|
|
2698
2698
|
|
|
2699
2699
|
beforeEach(() => {
|
|
2700
2700
|
vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
|
|
2701
|
+
builderHandoffMocks.useAgentChatContext.mockReturnValue({ items: [] });
|
|
2701
2702
|
container = document.createElement("div");
|
|
2702
2703
|
document.body.appendChild(container);
|
|
2703
2704
|
root = createRoot(container);
|
|
2705
|
+
const render = root.render.bind(root);
|
|
2706
|
+
root.render = (children: ReactNode) =>
|
|
2707
|
+
render(
|
|
2708
|
+
<AgentNativeI18nProvider persistPreference={false}>
|
|
2709
|
+
{children}
|
|
2710
|
+
</AgentNativeI18nProvider>,
|
|
2711
|
+
);
|
|
2704
2712
|
});
|
|
2705
2713
|
|
|
2706
2714
|
afterEach(() => {
|
|
@@ -2740,6 +2748,17 @@ describe("WorkedForSummary", () => {
|
|
|
2740
2748
|
response: ["The query returned a 12% increase."],
|
|
2741
2749
|
},
|
|
2742
2750
|
}}
|
|
2751
|
+
workedForRowLayout={{
|
|
2752
|
+
chevronSize: 16,
|
|
2753
|
+
iconGap: 4,
|
|
2754
|
+
fontSize: 14,
|
|
2755
|
+
lineHeight: 20,
|
|
2756
|
+
paddingBlock: 12,
|
|
2757
|
+
paddingInline: 12,
|
|
2758
|
+
}}
|
|
2759
|
+
formatWorkedForDuration={(durationMs) =>
|
|
2760
|
+
`${durationMs / 1000} seconds`
|
|
2761
|
+
}
|
|
2743
2762
|
/>,
|
|
2744
2763
|
);
|
|
2745
2764
|
});
|
|
@@ -2748,6 +2767,8 @@ describe("WorkedForSummary", () => {
|
|
|
2748
2767
|
container.querySelectorAll<HTMLButtonElement>("button[aria-expanded]"),
|
|
2749
2768
|
).find((button) => button.textContent?.includes("Worked for"));
|
|
2750
2769
|
expect(workedFor).not.toBeNull();
|
|
2770
|
+
expect(workedFor?.style.fontSize).toBe("14px");
|
|
2771
|
+
expect(workedFor?.textContent).toContain("Worked for 5 seconds");
|
|
2751
2772
|
act(() => workedFor?.click());
|
|
2752
2773
|
|
|
2753
2774
|
expect(container.textContent).not.toContain("This private thought");
|
|
@@ -2795,6 +2816,68 @@ describe("WorkedForSummary", () => {
|
|
|
2795
2816
|
expect(container.textContent).toContain("Worked for 5m");
|
|
2796
2817
|
});
|
|
2797
2818
|
|
|
2819
|
+
it("keeps the disclosure chevron before the duration label", () => {
|
|
2820
|
+
act(() => {
|
|
2821
|
+
root.render(
|
|
2822
|
+
<WorkedForSummary durationMs={5_000}>
|
|
2823
|
+
<div>Details</div>
|
|
2824
|
+
</WorkedForSummary>,
|
|
2825
|
+
);
|
|
2826
|
+
});
|
|
2827
|
+
|
|
2828
|
+
const button = container.querySelector("button[aria-expanded]");
|
|
2829
|
+
expect(button?.children[0]?.tagName.toLowerCase()).toBe("svg");
|
|
2830
|
+
expect(button?.children[1]?.textContent).toBe("Worked for 5s");
|
|
2831
|
+
const buttonClasses = button?.className.split(/\s+/) ?? [];
|
|
2832
|
+
expect(buttonClasses).toContain("gap-1");
|
|
2833
|
+
expect(buttonClasses).toContain("p-3");
|
|
2834
|
+
expect(buttonClasses).toContain("text-start");
|
|
2835
|
+
expect(buttonClasses).not.toContain("text-left");
|
|
2836
|
+
const chevron = button?.children[0];
|
|
2837
|
+
expect(chevron?.getAttribute("class")?.split(/\s+/)).toContain(
|
|
2838
|
+
"rtl:-scale-x-100",
|
|
2839
|
+
);
|
|
2840
|
+
|
|
2841
|
+
act(() => button?.click());
|
|
2842
|
+
|
|
2843
|
+
expect(chevron?.getAttribute("class")?.split(/\s+/)).toContain(
|
|
2844
|
+
"rtl:-rotate-90",
|
|
2845
|
+
);
|
|
2846
|
+
});
|
|
2847
|
+
|
|
2848
|
+
it("applies optional geometry to the completed-work disclosure row", () => {
|
|
2849
|
+
act(() => {
|
|
2850
|
+
root.render(
|
|
2851
|
+
<WorkedForSummary
|
|
2852
|
+
durationMs={5_000}
|
|
2853
|
+
layout={{
|
|
2854
|
+
chevronSize: 16,
|
|
2855
|
+
iconGap: 4,
|
|
2856
|
+
fontSize: 14,
|
|
2857
|
+
lineHeight: 20,
|
|
2858
|
+
paddingBlock: 12,
|
|
2859
|
+
paddingInline: 12,
|
|
2860
|
+
}}
|
|
2861
|
+
>
|
|
2862
|
+
<div>Details</div>
|
|
2863
|
+
</WorkedForSummary>,
|
|
2864
|
+
);
|
|
2865
|
+
});
|
|
2866
|
+
|
|
2867
|
+
const button = container.querySelector<HTMLButtonElement>(
|
|
2868
|
+
"button[aria-expanded]",
|
|
2869
|
+
);
|
|
2870
|
+
const icon = button?.querySelector<SVGElement>("svg");
|
|
2871
|
+
expect(button?.style.gap).toBe("4px");
|
|
2872
|
+
expect(button?.style.fontSize).toBe("14px");
|
|
2873
|
+
expect(button?.style.lineHeight).toBe("20px");
|
|
2874
|
+
expect(button?.style.paddingBlock).toBe("12px");
|
|
2875
|
+
expect(button?.style.paddingInline).toBe("12px");
|
|
2876
|
+
expect(button?.style.fontFamily).toBe("inherit");
|
|
2877
|
+
expect(icon?.style.width).toBe("16px");
|
|
2878
|
+
expect(icon?.style.height).toBe("16px");
|
|
2879
|
+
});
|
|
2880
|
+
|
|
2798
2881
|
it("applies the running shimmer while the work summary is live", () => {
|
|
2799
2882
|
act(() => {
|
|
2800
2883
|
root.render(
|