@stigmer/react 3.11.0 → 3.11.1-dev.20260812192248

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 (396) hide show
  1. package/agent-instance/AgentInstanceList.d.ts.map +1 -1
  2. package/agent-instance/AgentInstanceList.js +2 -1
  3. package/agent-instance/AgentInstanceList.js.map +1 -1
  4. package/api-key/ApiKeyListPanel.d.ts.map +1 -1
  5. package/api-key/ApiKeyListPanel.js +2 -1
  6. package/api-key/ApiKeyListPanel.js.map +1 -1
  7. package/attachment/AttachmentChipList.d.ts.map +1 -1
  8. package/attachment/AttachmentChipList.js +9 -8
  9. package/attachment/AttachmentChipList.js.map +1 -1
  10. package/attachment/AttachmentImageLightbox.d.ts.map +1 -1
  11. package/attachment/AttachmentImageLightbox.js +1 -1
  12. package/attachment/AttachmentImageLightbox.js.map +1 -1
  13. package/channel/AgentChannelsPanel.d.ts.map +1 -1
  14. package/channel/AgentChannelsPanel.js +2 -1
  15. package/channel/AgentChannelsPanel.js.map +1 -1
  16. package/channel/ChannelConversationsDialog.d.ts.map +1 -1
  17. package/channel/ChannelConversationsDialog.js +2 -1
  18. package/channel/ChannelConversationsDialog.js.map +1 -1
  19. package/channel/ChannelTemplatesDialog.d.ts.map +1 -1
  20. package/channel/ChannelTemplatesDialog.js +2 -1
  21. package/channel/ChannelTemplatesDialog.js.map +1 -1
  22. package/channel-app/internal.d.ts.map +1 -1
  23. package/channel-app/internal.js +2 -1
  24. package/channel-app/internal.js.map +1 -1
  25. package/composer/ComposerToolbar.d.ts.map +1 -1
  26. package/composer/ComposerToolbar.js +10 -7
  27. package/composer/ComposerToolbar.js.map +1 -1
  28. package/composer/ConfigureMenu.d.ts.map +1 -1
  29. package/composer/ConfigureMenu.js +2 -1
  30. package/composer/ConfigureMenu.js.map +1 -1
  31. package/composer/ContextChip.d.ts.map +1 -1
  32. package/composer/ContextChip.js +2 -1
  33. package/composer/ContextChip.js.map +1 -1
  34. package/composer/ContextPopover.d.ts.map +1 -1
  35. package/composer/ContextPopover.js +2 -1
  36. package/composer/ContextPopover.js.map +1 -1
  37. package/composer/SessionComposer.d.ts +13 -0
  38. package/composer/SessionComposer.d.ts.map +1 -1
  39. package/composer/SessionComposer.js +12 -2
  40. package/composer/SessionComposer.js.map +1 -1
  41. package/conversation/ConversationMediaAttachment.d.ts.map +1 -1
  42. package/conversation/ConversationMediaAttachment.js +2 -1
  43. package/conversation/ConversationMediaAttachment.js.map +1 -1
  44. package/conversation/ConversationTimelineView.d.ts.map +1 -1
  45. package/conversation/ConversationTimelineView.js +14 -4
  46. package/conversation/ConversationTimelineView.js.map +1 -1
  47. package/conversation/conversationPresentation.d.ts +28 -0
  48. package/conversation/conversationPresentation.d.ts.map +1 -1
  49. package/conversation/conversationPresentation.js +38 -1
  50. package/conversation/conversationPresentation.js.map +1 -1
  51. package/cursor-accounts/MemberCoverageTable.d.ts.map +1 -1
  52. package/cursor-accounts/MemberCoverageTable.js +6 -5
  53. package/cursor-accounts/MemberCoverageTable.js.map +1 -1
  54. package/dashboard/DashboardKPICards.d.ts.map +1 -1
  55. package/dashboard/DashboardKPICards.js +3 -1
  56. package/dashboard/DashboardKPICards.js.map +1 -1
  57. package/datastore/CollectionRecordsBrowser.d.ts.map +1 -1
  58. package/datastore/CollectionRecordsBrowser.js +5 -2
  59. package/datastore/CollectionRecordsBrowser.js.map +1 -1
  60. package/environment/EnvironmentVariableEditor.d.ts.map +1 -1
  61. package/environment/EnvironmentVariableEditor.js +2 -1
  62. package/environment/EnvironmentVariableEditor.js.map +1 -1
  63. package/execution/ApprovalCard.d.ts.map +1 -1
  64. package/execution/ApprovalCard.js +1 -1
  65. package/execution/ApprovalCard.js.map +1 -1
  66. package/execution/ArtifactRowView.d.ts.map +1 -1
  67. package/execution/ArtifactRowView.js +2 -1
  68. package/execution/ArtifactRowView.js.map +1 -1
  69. package/execution/FilePathLink.d.ts +4 -4
  70. package/execution/FilePathLink.d.ts.map +1 -1
  71. package/execution/FilePathLink.js +4 -4
  72. package/execution/FilePathLink.js.map +1 -1
  73. package/execution/McpToolDetail.d.ts.map +1 -1
  74. package/execution/McpToolDetail.js +2 -1
  75. package/execution/McpToolDetail.js.map +1 -1
  76. package/execution/MessageAttachments.d.ts.map +1 -1
  77. package/execution/MessageAttachments.js +10 -8
  78. package/execution/MessageAttachments.js.map +1 -1
  79. package/execution/MessageEntry.d.ts.map +1 -1
  80. package/execution/MessageEntry.js +2 -1
  81. package/execution/MessageEntry.js.map +1 -1
  82. package/execution/PlanArtifactCard.d.ts.map +1 -1
  83. package/execution/PlanArtifactCard.js +7 -4
  84. package/execution/PlanArtifactCard.js.map +1 -1
  85. package/execution/ToolCallDetail.d.ts.map +1 -1
  86. package/execution/ToolCallDetail.js +1 -1
  87. package/execution/ToolCallDetail.js.map +1 -1
  88. package/execution/ToolCallItem.d.ts.map +1 -1
  89. package/execution/ToolCallItem.js +5 -1
  90. package/execution/ToolCallItem.js.map +1 -1
  91. package/execution/WriteBackCard.d.ts.map +1 -1
  92. package/execution/WriteBackCard.js +6 -4
  93. package/execution/WriteBackCard.js.map +1 -1
  94. package/execution/artifact-row-item.d.ts +1 -1
  95. package/execution/artifact-row-item.d.ts.map +1 -1
  96. package/file-reference/FileReferenceChipList.d.ts.map +1 -1
  97. package/file-reference/FileReferenceChipList.js +6 -1
  98. package/file-reference/FileReferenceChipList.js.map +1 -1
  99. package/iam-policy/OrgMembersPanel.d.ts.map +1 -1
  100. package/iam-policy/OrgMembersPanel.js +6 -5
  101. package/iam-policy/OrgMembersPanel.js.map +1 -1
  102. package/iam-policy/ProviderBadge.d.ts.map +1 -1
  103. package/iam-policy/ProviderBadge.js +3 -2
  104. package/iam-policy/ProviderBadge.js.map +1 -1
  105. package/iam-policy/RoleSelector.d.ts.map +1 -1
  106. package/iam-policy/RoleSelector.js +1 -1
  107. package/iam-policy/RoleSelector.js.map +1 -1
  108. package/identity-provider/IdentityProviderListPanel.d.ts.map +1 -1
  109. package/identity-provider/IdentityProviderListPanel.js +2 -1
  110. package/identity-provider/IdentityProviderListPanel.js.map +1 -1
  111. package/internal/truncated-text.d.ts +17 -0
  112. package/internal/truncated-text.d.ts.map +1 -0
  113. package/internal/truncated-text.js +27 -0
  114. package/internal/truncated-text.js.map +1 -0
  115. package/invitation/InvitationManager.d.ts.map +1 -1
  116. package/invitation/InvitationManager.js +4 -3
  117. package/invitation/InvitationManager.js.map +1 -1
  118. package/library/ScopeToggle.d.ts.map +1 -1
  119. package/library/ScopeToggle.js +10 -2
  120. package/library/ScopeToggle.js.map +1 -1
  121. package/library/VisibilitySelector.d.ts.map +1 -1
  122. package/library/VisibilitySelector.js +2 -1
  123. package/library/VisibilitySelector.js.map +1 -1
  124. package/mcp-server/McpServerConfigPanel.d.ts +30 -1
  125. package/mcp-server/McpServerConfigPanel.d.ts.map +1 -1
  126. package/mcp-server/McpServerConfigPanel.js +18 -8
  127. package/mcp-server/McpServerConfigPanel.js.map +1 -1
  128. package/mcp-server/McpServerConnectDialog.d.ts +12 -1
  129. package/mcp-server/McpServerConnectDialog.d.ts.map +1 -1
  130. package/mcp-server/McpServerConnectDialog.js +8 -7
  131. package/mcp-server/McpServerConnectDialog.js.map +1 -1
  132. package/mcp-server/McpServerDetailView.d.ts.map +1 -1
  133. package/mcp-server/McpServerDetailView.js +4 -4
  134. package/mcp-server/McpServerDetailView.js.map +1 -1
  135. package/mcp-server/McpServerPicker.d.ts.map +1 -1
  136. package/mcp-server/McpServerPicker.js +86 -5
  137. package/mcp-server/McpServerPicker.js.map +1 -1
  138. package/mcp-server/McpToolSelector.d.ts.map +1 -1
  139. package/mcp-server/McpToolSelector.js +2 -1
  140. package/mcp-server/McpToolSelector.js.map +1 -1
  141. package/mcp-server/VendorApprovalBlockedNotice.d.ts +77 -0
  142. package/mcp-server/VendorApprovalBlockedNotice.d.ts.map +1 -0
  143. package/mcp-server/VendorApprovalBlockedNotice.js +62 -0
  144. package/mcp-server/VendorApprovalBlockedNotice.js.map +1 -0
  145. package/mcp-server/mcpServerSetupReducer.d.ts +18 -0
  146. package/mcp-server/mcpServerSetupReducer.d.ts.map +1 -1
  147. package/mcp-server/mcpServerSetupReducer.js +6 -0
  148. package/mcp-server/mcpServerSetupReducer.js.map +1 -1
  149. package/mcp-server/useMcpServerSetup.d.ts.map +1 -1
  150. package/mcp-server/useMcpServerSetup.js +7 -0
  151. package/mcp-server/useMcpServerSetup.js.map +1 -1
  152. package/oauth-app/OAuthAppListPanel.d.ts.map +1 -1
  153. package/oauth-app/OAuthAppListPanel.js +2 -1
  154. package/oauth-app/OAuthAppListPanel.js.map +1 -1
  155. package/package.json +4 -4
  156. package/platform-client/PlatformClientListPanel.d.ts.map +1 -1
  157. package/platform-client/PlatformClientListPanel.js +3 -2
  158. package/platform-client/PlatformClientListPanel.js.map +1 -1
  159. package/pricing-governance/BaselineEditor.d.ts.map +1 -1
  160. package/pricing-governance/BaselineEditor.js +7 -1
  161. package/pricing-governance/BaselineEditor.js.map +1 -1
  162. package/pricing-governance/ModelCatalogPanel.d.ts.map +1 -1
  163. package/pricing-governance/ModelCatalogPanel.js +2 -1
  164. package/pricing-governance/ModelCatalogPanel.js.map +1 -1
  165. package/pricing-governance/PricingGovernanceConsole.d.ts.map +1 -1
  166. package/pricing-governance/PricingGovernanceConsole.js +2 -1
  167. package/pricing-governance/PricingGovernanceConsole.js.map +1 -1
  168. package/pricing-governance/PricingGovernancePanel.d.ts.map +1 -1
  169. package/pricing-governance/PricingGovernancePanel.js +2 -1
  170. package/pricing-governance/PricingGovernancePanel.js.map +1 -1
  171. package/resource-workbench/components/StatusBadge.d.ts.map +1 -1
  172. package/resource-workbench/components/StatusBadge.js +2 -1
  173. package/resource-workbench/components/StatusBadge.js.map +1 -1
  174. package/schedule/CadenceField.d.ts.map +1 -1
  175. package/schedule/CadenceField.js +15 -8
  176. package/schedule/CadenceField.js.map +1 -1
  177. package/schedule/ScheduleRunsTable.d.ts.map +1 -1
  178. package/schedule/ScheduleRunsTable.js +3 -2
  179. package/schedule/ScheduleRunsTable.js.map +1 -1
  180. package/session/PlanEditor.d.ts.map +1 -1
  181. package/session/PlanEditor.js +3 -5
  182. package/session/PlanEditor.js.map +1 -1
  183. package/sharing/AgentShareList.d.ts.map +1 -1
  184. package/sharing/AgentShareList.js +3 -1
  185. package/sharing/AgentShareList.js.map +1 -1
  186. package/sharing/ShareAgentDialog.d.ts.map +1 -1
  187. package/sharing/ShareAgentDialog.js +2 -1
  188. package/sharing/ShareAgentDialog.js.map +1 -1
  189. package/skill/SkillDetailView.d.ts.map +1 -1
  190. package/skill/SkillDetailView.js +3 -2
  191. package/skill/SkillDetailView.js.map +1 -1
  192. package/src/__tests__/helpers/open-menu.ts +88 -0
  193. package/src/__tests__/portal-container.test.tsx +3 -3
  194. package/src/agent-instance/AgentInstanceList.tsx +5 -6
  195. package/src/agent-instance/__tests__/AgentInstanceList.test.tsx +5 -4
  196. package/src/api-key/ApiKeyListPanel.tsx +11 -3
  197. package/src/attachment/AttachmentChipList.tsx +74 -65
  198. package/src/attachment/AttachmentImageLightbox.tsx +5 -4
  199. package/src/attachment/__tests__/AttachmentChipList.test.tsx +4 -3
  200. package/src/channel/AgentChannelsPanel.tsx +5 -6
  201. package/src/channel/ChannelConversationsDialog.tsx +5 -3
  202. package/src/channel/ChannelTemplatesDialog.tsx +5 -6
  203. package/src/channel/__tests__/AgentChannelsPanel.test.tsx +14 -9
  204. package/src/channel-app/internal.tsx +5 -6
  205. package/src/composer/ComposerToolbar.tsx +122 -90
  206. package/src/composer/ConfigureMenu.tsx +33 -24
  207. package/src/composer/ContextChip.tsx +2 -3
  208. package/src/composer/ContextPopover.tsx +27 -18
  209. package/src/composer/SessionComposer.tsx +41 -9
  210. package/src/composer/__tests__/SessionComposer-agentSetupError.test.tsx +124 -0
  211. package/src/composer/__tests__/SessionComposer-lockAgent.test.tsx +4 -9
  212. package/src/conversation/ConversationMediaAttachment.tsx +2 -2
  213. package/src/conversation/ConversationTimelineView.tsx +19 -2
  214. package/src/conversation/__tests__/ConversationTimelineView.test.tsx +106 -3
  215. package/src/conversation/conversationPresentation.ts +52 -1
  216. package/src/cursor-accounts/MemberCoverageTable.tsx +15 -13
  217. package/src/cursor-accounts/__tests__/CursorAccountsConsole.test.tsx +4 -4
  218. package/src/dashboard/DashboardKPICards.tsx +2 -1
  219. package/src/datastore/CollectionRecordsBrowser.tsx +8 -7
  220. package/src/environment/EnvironmentVariableEditor.tsx +17 -6
  221. package/src/execution/ApprovalCard.tsx +1 -3
  222. package/src/execution/ArtifactRowView.tsx +68 -48
  223. package/src/execution/FilePathLink.tsx +43 -27
  224. package/src/execution/McpToolDetail.tsx +6 -2
  225. package/src/execution/MessageAttachments.tsx +57 -41
  226. package/src/execution/MessageEntry.tsx +22 -15
  227. package/src/execution/PlanArtifactCard.tsx +25 -18
  228. package/src/execution/ToolCallDetail.tsx +1 -4
  229. package/src/execution/ToolCallItem.tsx +18 -7
  230. package/src/execution/WriteBackCard.tsx +38 -29
  231. package/src/execution/__tests__/ArtifactRow.test.tsx +6 -2
  232. package/src/execution/__tests__/ArtifactRowView.test.tsx +5 -2
  233. package/src/execution/__tests__/FilePathLink.test.tsx +10 -6
  234. package/src/execution/__tests__/FileReviewCard.test.tsx +2 -1
  235. package/src/execution/__tests__/MessageEntry-attachments.test.tsx +3 -2
  236. package/src/execution/__tests__/MessageThread.test.tsx +6 -1
  237. package/src/execution/__tests__/artifact-row-tooltips.layout.test.tsx +115 -0
  238. package/src/execution/artifact-row-item.ts +1 -1
  239. package/src/file-reference/FileReferenceChipList.tsx +29 -17
  240. package/src/file-reference/__tests__/FileReferenceChipList.test.tsx +5 -2
  241. package/src/iam-policy/OrgMembersPanel.tsx +26 -19
  242. package/src/iam-policy/ProviderBadge.tsx +17 -10
  243. package/src/iam-policy/RoleSelector.tsx +0 -1
  244. package/src/identity-provider/IdentityProviderListPanel.tsx +11 -3
  245. package/src/internal/__tests__/truncated-text.layout.test.tsx +68 -0
  246. package/src/internal/__tests__/truncated-text.test.tsx +33 -0
  247. package/src/internal/truncated-text.tsx +81 -0
  248. package/src/invitation/InvitationManager.tsx +18 -5
  249. package/src/library/ScopeToggle.tsx +14 -2
  250. package/src/library/VisibilitySelector.tsx +21 -14
  251. package/src/mcp-server/McpServerConfigPanel.tsx +79 -37
  252. package/src/mcp-server/McpServerConnectDialog.tsx +41 -5
  253. package/src/mcp-server/McpServerDetailView.tsx +23 -39
  254. package/src/mcp-server/McpServerPicker.tsx +99 -7
  255. package/src/mcp-server/McpToolSelector.tsx +12 -7
  256. package/src/mcp-server/VendorApprovalBlockedNotice.tsx +221 -0
  257. package/src/mcp-server/__tests__/McpServerPicker.test.tsx +504 -0
  258. package/src/mcp-server/__tests__/VendorApprovalBlocked.surfaces.test.tsx +321 -0
  259. package/src/mcp-server/__tests__/VendorApprovalBlockedNotice.test.tsx +154 -0
  260. package/src/mcp-server/mcpServerSetupReducer.ts +24 -0
  261. package/src/mcp-server/useMcpServerSetup.ts +9 -0
  262. package/src/oauth-app/OAuthAppListPanel.tsx +11 -3
  263. package/src/platform-client/PlatformClientListPanel.tsx +35 -18
  264. package/src/pricing-governance/BaselineEditor.tsx +20 -0
  265. package/src/pricing-governance/ModelCatalogPanel.tsx +9 -5
  266. package/src/pricing-governance/PricingGovernanceConsole.tsx +9 -5
  267. package/src/pricing-governance/PricingGovernancePanel.tsx +13 -4
  268. package/src/pricing-governance/__tests__/ModelCatalogPanel.test.tsx +37 -0
  269. package/src/resource-workbench/components/StatusBadge.tsx +7 -3
  270. package/src/schedule/CadenceField.tsx +38 -27
  271. package/src/schedule/ScheduleRunsTable.tsx +23 -11
  272. package/src/schedule/__tests__/cadence-tooltips.layout.test.tsx +86 -0
  273. package/src/session/PlanEditor.tsx +9 -8
  274. package/src/sharing/AgentShareList.tsx +28 -22
  275. package/src/sharing/ShareAgentDialog.tsx +5 -6
  276. package/src/sharing/__tests__/AgentShareList.test.tsx +4 -4
  277. package/src/skill/SkillDetailView.tsx +23 -12
  278. package/src/version-history/VersionTimelineEntry.tsx +21 -12
  279. package/src/workflow/CanvasTransitionEdge.tsx +23 -16
  280. package/src/workflow/ExecutionActiveTaskIndicator.tsx +74 -59
  281. package/src/workflow/TaskPickerPopover.tsx +0 -1
  282. package/src/workflow/WorkflowCanvasEditor.tsx +95 -64
  283. package/src/workflow/WorkflowNode.tsx +13 -6
  284. package/src/workflow/WorkflowTaskApprovalSummary.tsx +18 -11
  285. package/src/workflow/WorkflowTaskList.tsx +2 -2
  286. package/src/workflow/WorkflowVersionBadge.tsx +33 -18
  287. package/src/workflow/WorkflowVersionTimeline.tsx +7 -6
  288. package/src/workflow/__tests__/WorkflowTaskApprovalSummary.test.tsx +3 -1
  289. package/src/workflow/__tests__/structured-data-viewer.test.tsx +5 -2
  290. package/src/workflow/execution-comparison/ExecutionComparisonView.tsx +5 -3
  291. package/src/workflow/execution-comparison/TaskComparisonTable.tsx +12 -5
  292. package/src/workflow/execution-history/ExecutionHistoryTable.tsx +24 -15
  293. package/src/workflow/inspector/InspectorHeader.tsx +20 -11
  294. package/src/workflow/inspector/NestedTaskList.tsx +18 -11
  295. package/src/workflow/inspector/WorkflowSummaryPanel.tsx +5 -3
  296. package/src/workflow/inspector/tabs/BranchesTab.tsx +61 -31
  297. package/src/workflow/instance/WorkflowInstanceList.tsx +5 -6
  298. package/src/workflow/instance/__tests__/WorkflowInstanceList.test.tsx +5 -4
  299. package/src/workflow/node-shell/DiffBadge.tsx +18 -11
  300. package/src/workflow/node-shell/ExecutionBadge.tsx +73 -46
  301. package/src/workflow/node-shell/NodeActions.tsx +128 -94
  302. package/src/workflow/task-detail/StructuredDataViewer.tsx +4 -2
  303. package/src/workspace/EditorTabs.tsx +102 -85
  304. package/src/workspace/ExplorerTree.tsx +47 -30
  305. package/src/workspace/FileViewer.tsx +11 -3
  306. package/src/workspace/PanelChip.tsx +32 -23
  307. package/src/workspace/WorkspaceEditor.tsx +21 -9
  308. package/src/workspace/WorkspaceSummary.tsx +21 -12
  309. package/src/workspace/WorkspaceSurface.tsx +86 -61
  310. package/src/workspace/__tests__/EditorTabs.test.tsx +5 -2
  311. package/src/workspace/__tests__/WorkspaceSurface.test.tsx +5 -2
  312. package/version-history/VersionTimelineEntry.d.ts.map +1 -1
  313. package/version-history/VersionTimelineEntry.js +2 -1
  314. package/version-history/VersionTimelineEntry.js.map +1 -1
  315. package/workflow/CanvasTransitionEdge.d.ts.map +1 -1
  316. package/workflow/CanvasTransitionEdge.js +3 -2
  317. package/workflow/CanvasTransitionEdge.js.map +1 -1
  318. package/workflow/ExecutionActiveTaskIndicator.d.ts.map +1 -1
  319. package/workflow/ExecutionActiveTaskIndicator.js +12 -11
  320. package/workflow/ExecutionActiveTaskIndicator.js.map +1 -1
  321. package/workflow/TaskPickerPopover.js +1 -1
  322. package/workflow/TaskPickerPopover.js.map +1 -1
  323. package/workflow/WorkflowCanvasEditor.d.ts.map +1 -1
  324. package/workflow/WorkflowCanvasEditor.js +9 -2
  325. package/workflow/WorkflowCanvasEditor.js.map +1 -1
  326. package/workflow/WorkflowNode.d.ts.map +1 -1
  327. package/workflow/WorkflowNode.js +2 -1
  328. package/workflow/WorkflowNode.js.map +1 -1
  329. package/workflow/WorkflowTaskApprovalSummary.d.ts.map +1 -1
  330. package/workflow/WorkflowTaskApprovalSummary.js +6 -4
  331. package/workflow/WorkflowTaskApprovalSummary.js.map +1 -1
  332. package/workflow/WorkflowTaskList.js +2 -2
  333. package/workflow/WorkflowTaskList.js.map +1 -1
  334. package/workflow/WorkflowVersionBadge.d.ts.map +1 -1
  335. package/workflow/WorkflowVersionBadge.js +2 -1
  336. package/workflow/WorkflowVersionBadge.js.map +1 -1
  337. package/workflow/WorkflowVersionTimeline.d.ts.map +1 -1
  338. package/workflow/WorkflowVersionTimeline.js +2 -1
  339. package/workflow/WorkflowVersionTimeline.js.map +1 -1
  340. package/workflow/execution-comparison/ExecutionComparisonView.d.ts.map +1 -1
  341. package/workflow/execution-comparison/ExecutionComparisonView.js +2 -1
  342. package/workflow/execution-comparison/ExecutionComparisonView.js.map +1 -1
  343. package/workflow/execution-comparison/TaskComparisonTable.d.ts.map +1 -1
  344. package/workflow/execution-comparison/TaskComparisonTable.js +2 -1
  345. package/workflow/execution-comparison/TaskComparisonTable.js.map +1 -1
  346. package/workflow/execution-history/ExecutionHistoryTable.d.ts.map +1 -1
  347. package/workflow/execution-history/ExecutionHistoryTable.js +6 -4
  348. package/workflow/execution-history/ExecutionHistoryTable.js.map +1 -1
  349. package/workflow/inspector/InspectorHeader.d.ts.map +1 -1
  350. package/workflow/inspector/InspectorHeader.js +4 -2
  351. package/workflow/inspector/InspectorHeader.js.map +1 -1
  352. package/workflow/inspector/NestedTaskList.d.ts.map +1 -1
  353. package/workflow/inspector/NestedTaskList.js +2 -1
  354. package/workflow/inspector/NestedTaskList.js.map +1 -1
  355. package/workflow/inspector/WorkflowSummaryPanel.d.ts.map +1 -1
  356. package/workflow/inspector/WorkflowSummaryPanel.js +2 -1
  357. package/workflow/inspector/WorkflowSummaryPanel.js.map +1 -1
  358. package/workflow/inspector/tabs/BranchesTab.d.ts.map +1 -1
  359. package/workflow/inspector/tabs/BranchesTab.js +5 -2
  360. package/workflow/inspector/tabs/BranchesTab.js.map +1 -1
  361. package/workflow/instance/WorkflowInstanceList.d.ts.map +1 -1
  362. package/workflow/instance/WorkflowInstanceList.js +2 -1
  363. package/workflow/instance/WorkflowInstanceList.js.map +1 -1
  364. package/workflow/node-shell/DiffBadge.d.ts.map +1 -1
  365. package/workflow/node-shell/DiffBadge.js +3 -2
  366. package/workflow/node-shell/DiffBadge.js.map +1 -1
  367. package/workflow/node-shell/ExecutionBadge.d.ts.map +1 -1
  368. package/workflow/node-shell/ExecutionBadge.js +5 -4
  369. package/workflow/node-shell/ExecutionBadge.js.map +1 -1
  370. package/workflow/node-shell/NodeActions.d.ts.map +1 -1
  371. package/workflow/node-shell/NodeActions.js +12 -11
  372. package/workflow/node-shell/NodeActions.js.map +1 -1
  373. package/workflow/task-detail/StructuredDataViewer.d.ts.map +1 -1
  374. package/workflow/task-detail/StructuredDataViewer.js +5 -1
  375. package/workflow/task-detail/StructuredDataViewer.js.map +1 -1
  376. package/workspace/EditorTabs.d.ts.map +1 -1
  377. package/workspace/EditorTabs.js +38 -37
  378. package/workspace/EditorTabs.js.map +1 -1
  379. package/workspace/ExplorerTree.d.ts.map +1 -1
  380. package/workspace/ExplorerTree.js +2 -1
  381. package/workspace/ExplorerTree.js.map +1 -1
  382. package/workspace/FileViewer.d.ts.map +1 -1
  383. package/workspace/FileViewer.js +2 -1
  384. package/workspace/FileViewer.js.map +1 -1
  385. package/workspace/PanelChip.d.ts.map +1 -1
  386. package/workspace/PanelChip.js +2 -1
  387. package/workspace/PanelChip.js.map +1 -1
  388. package/workspace/WorkspaceEditor.d.ts.map +1 -1
  389. package/workspace/WorkspaceEditor.js +2 -1
  390. package/workspace/WorkspaceEditor.js.map +1 -1
  391. package/workspace/WorkspaceSummary.d.ts.map +1 -1
  392. package/workspace/WorkspaceSummary.js +7 -2
  393. package/workspace/WorkspaceSummary.js.map +1 -1
  394. package/workspace/WorkspaceSurface.d.ts.map +1 -1
  395. package/workspace/WorkspaceSurface.js +12 -11
  396. package/workspace/WorkspaceSurface.js.map +1 -1
@@ -0,0 +1,115 @@
1
+ // The interactive-trigger tooltip contract from the native-title sweep
2
+ // (stigmer-cloud#268), pinned in a real Chromium on ArtifactRowView. When
3
+ // an enabled control is its own tooltip trigger, keyboard FOCUS opens the
4
+ // hint too — the concrete accessibility gain over the native `title` this
5
+ // replaced, which no keyboard user ever saw. Focus-open is real focus
6
+ // machinery (Base UI opens on focus-visible), so only a real browser can
7
+ // pin it honestly.
8
+
9
+ import "../../../dist/styles.css";
10
+
11
+ import { describe, it, expect, vi, afterEach } from "vitest";
12
+ import { render, cleanup } from "@testing-library/react";
13
+ import { userEvent } from "@vitest/browser/context";
14
+ import { ArtifactRowView } from "../ArtifactRowView.js";
15
+
16
+ const ITEM = {
17
+ name: "report.pdf",
18
+ tooltip: "/workspace/output/report.pdf",
19
+ subtitlePath: null,
20
+ sizeBytes: 2048,
21
+ isDirectory: false,
22
+ };
23
+
24
+ function renderRow() {
25
+ const pane = document.createElement("div");
26
+ pane.className = "stgm";
27
+ pane.style.width = "320px";
28
+ document.body.appendChild(pane);
29
+ render(
30
+ <ul>
31
+ <ArtifactRowView
32
+ item={ITEM}
33
+ onOpen={() => {}}
34
+ onDownload={() => {}}
35
+ isDownloading={false}
36
+ />
37
+ </ul>,
38
+ { container: pane },
39
+ );
40
+ return pane;
41
+ }
42
+
43
+ function portaledText(pane: HTMLElement): string {
44
+ return Array.from(document.body.children)
45
+ .filter((node) => node !== pane)
46
+ .map((node) => node.textContent ?? "")
47
+ .join(" ");
48
+ }
49
+
50
+ afterEach(() => {
51
+ cleanup();
52
+ document.querySelectorAll(".stgm").forEach((node) => node.remove());
53
+ });
54
+
55
+ describe("ArtifactRowView tooltips", () => {
56
+ it("opens the full-path hint on keyboard focus — no pointer required", async () => {
57
+ const pane = renderRow();
58
+ expect(pane.querySelector("[title]")).toBeNull();
59
+
60
+ // Tab reaches the open button (first focusable in the row); the
61
+ // tooltip must follow focus per the interactive-trigger pattern.
62
+ await userEvent.tab();
63
+ const openButton = Array.from(pane.querySelectorAll("button")).find((el) =>
64
+ el.textContent?.includes("report.pdf"),
65
+ );
66
+ expect(document.activeElement).toBe(openButton);
67
+
68
+ await vi.waitFor(
69
+ () => expect(portaledText(pane)).toContain("/workspace/output/report.pdf"),
70
+ { timeout: 3000, interval: 50 },
71
+ );
72
+ });
73
+
74
+ it("keeps the download hint hoverable through the wrapper span", async () => {
75
+ const pane = renderRow();
76
+
77
+ const download = Array.from(pane.querySelectorAll("button")).find(
78
+ (el) => el.getAttribute("aria-label") === "Download report.pdf",
79
+ );
80
+ await userEvent.hover(download!.parentElement!);
81
+ await vi.waitFor(
82
+ () => expect(portaledText(pane)).toContain("Download"),
83
+ { timeout: 3000, interval: 50 },
84
+ );
85
+ await userEvent.unhover(download!.parentElement!);
86
+ });
87
+
88
+ it("says 'Download ZIP' for a directory", async () => {
89
+ const pane = document.createElement("div");
90
+ pane.className = "stgm";
91
+ pane.style.width = "320px";
92
+ document.body.appendChild(pane);
93
+ render(
94
+ <ul>
95
+ <ArtifactRowView
96
+ item={{ ...ITEM, name: "bundle", tooltip: "bundle", isDirectory: true }}
97
+ onOpen={() => {}}
98
+ onDownload={() => {}}
99
+ isDownloading={false}
100
+ />
101
+ </ul>,
102
+ { container: pane },
103
+ );
104
+
105
+ const download = Array.from(pane.querySelectorAll("button")).find(
106
+ (el) => el.getAttribute("aria-label") === "Download bundle",
107
+ );
108
+ await userEvent.hover(download!.parentElement!);
109
+ await vi.waitFor(
110
+ () => expect(portaledText(pane)).toContain("Download ZIP"),
111
+ { timeout: 3000, interval: 50 },
112
+ );
113
+ await userEvent.unhover(download!.parentElement!);
114
+ });
115
+ });
@@ -19,7 +19,7 @@ import type { Artifact } from "@stigmer/protos/ai/stigmer/agentic/artifact/v1/ap
19
19
  export interface ArtifactRowItem {
20
20
  /** Display label (file or directory name). */
21
21
  readonly name: string;
22
- /** Hover title — the fullest location/name known for the artifact. */
22
+ /** House-tooltip content — the fullest location/name known for the artifact. */
23
23
  readonly tooltip: string;
24
24
  /**
25
25
  * Disambiguation subtitle rendered after the name when another row shares
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  import { cn } from "@stigmer/theme";
4
+ import { Tooltip, TooltipContent, TooltipTrigger } from "../internal/tooltip.js";
4
5
 
5
6
  /** Props for {@link FileReferenceChipList}. */
6
7
  export interface FileReferenceChipListProps {
@@ -83,24 +84,35 @@ function FileReferenceChip({
83
84
  const filename = path.split("/").pop() ?? path;
84
85
 
85
86
  return (
86
- <span
87
- role="listitem"
88
- aria-label={`Referenced file: ${path}`}
89
- title={path}
90
- className="stg:inline-flex stg:max-w-[200px] stg:items-center stg:gap-1 stg:rounded-md stg:bg-muted-subtle stg:px-2 stg:py-0.5 stg:text-xs stg:text-foreground"
91
- >
92
- <FileRefIcon />
93
- <span className="stg:truncate">{filename}</span>
94
- <button
95
- type="button"
96
- onClick={onRemove}
97
- disabled={disabled}
98
- className="stg:ml-0.5 stg:shrink-0 stg:text-muted-foreground stg:hover:text-destructive stg:disabled:pointer-events-none"
99
- aria-label={`Remove reference to ${path}`}
87
+ // The chip shows only the basename; the tooltip restores the full path,
88
+ // so it is a hover-always hint on the chip, not an overflow-gated
89
+ // TruncatedText.
90
+ <Tooltip>
91
+ <TooltipTrigger
92
+ render={
93
+ <span
94
+ role="listitem"
95
+ aria-label={`Referenced file: ${path}`}
96
+ className="stg:inline-flex stg:max-w-[200px] stg:items-center stg:gap-1 stg:rounded-md stg:bg-muted-subtle stg:px-2 stg:py-0.5 stg:text-xs stg:text-foreground"
97
+ />
98
+ }
100
99
  >
101
- <XIcon />
102
- </button>
103
- </span>
100
+ <FileRefIcon />
101
+ <span className="stg:truncate">{filename}</span>
102
+ <button
103
+ type="button"
104
+ onClick={onRemove}
105
+ disabled={disabled}
106
+ className="stg:ml-0.5 stg:shrink-0 stg:text-muted-foreground stg:hover:text-destructive stg:disabled:pointer-events-none"
107
+ aria-label={`Remove reference to ${path}`}
108
+ >
109
+ <XIcon />
110
+ </button>
111
+ </TooltipTrigger>
112
+ <TooltipContent side="top" className="stg:break-all">
113
+ {path}
114
+ </TooltipContent>
115
+ </Tooltip>
104
116
  );
105
117
  }
106
118
 
@@ -80,7 +80,7 @@ describe("FileReferenceChipList", () => {
80
80
  expect(list.getAttribute("aria-label")).toBe("Referenced workspace files");
81
81
  });
82
82
 
83
- it("sets title attribute on chip for full path tooltip", () => {
83
+ it("keeps the chip free of native titles — the full path rides the house tooltip", () => {
84
84
  render(
85
85
  <FileReferenceChipList
86
86
  refs={["src/deeply/nested/file.ts"]}
@@ -89,6 +89,9 @@ describe("FileReferenceChipList", () => {
89
89
  );
90
90
 
91
91
  const item = screen.getByRole("listitem");
92
- expect(item.getAttribute("title")).toBe("src/deeply/nested/file.ts");
92
+ expect(item.getAttribute("title")).toBeNull();
93
+ // The basename stays visible; the full path is the tooltip's content
94
+ // (reveal pinned in the real-browser suites).
95
+ expect(item.textContent).toContain("file.ts");
93
96
  });
94
97
  });
@@ -15,6 +15,7 @@ import {
15
15
  iamRoleFromString,
16
16
  iamRoleToString,
17
17
  } from "@stigmer/sdk";
18
+ import { Tooltip, TooltipContent, TooltipTrigger } from "../internal/tooltip.js";
18
19
  import { useResourceAccess } from "./useResourceAccess.js";
19
20
  import { usePrincipalsCount } from "./usePrincipalsCount.js";
20
21
  import { useWhoAmI } from "./useWhoAmI.js";
@@ -282,26 +283,32 @@ function MemberRow({
282
283
  function RoleBadge({ grant }: { grant: RoleGrant }) {
283
284
  const roleName = grant.role?.name || grant.role?.code || "Unknown";
284
285
  return (
285
- <span
286
- className={cn(
287
- "stg:inline-flex stg:items-center stg:rounded-md stg:border stg:px-2 stg:py-0.5 stg:text-[0.65rem] stg:font-medium",
288
- grant.isInherited
289
- ? "stg:border-border-muted stg:text-muted-foreground stg:bg-muted-subtle stg:italic"
290
- : "stg:border-border stg:bg-muted stg:text-foreground",
291
- )}
292
- title={
293
- grant.isInherited
286
+ <Tooltip>
287
+ <TooltipTrigger
288
+ render={
289
+ <span
290
+ className={cn(
291
+ "stg:inline-flex stg:items-center stg:rounded-md stg:border stg:px-2 stg:py-0.5 stg:text-[0.65rem] stg:font-medium",
292
+ grant.isInherited
293
+ ? "stg:border-border-muted stg:text-muted-foreground stg:bg-muted-subtle stg:italic"
294
+ : "stg:border-border stg:bg-muted stg:text-foreground",
295
+ )}
296
+ />
297
+ }
298
+ >
299
+ {roleName}
300
+ {grant.isInherited && (
301
+ <span className="stg:ml-1 stg:text-[0.55rem] stg:text-muted-foreground">
302
+ (inherited)
303
+ </span>
304
+ )}
305
+ </TooltipTrigger>
306
+ <TooltipContent side="top">
307
+ {grant.isInherited
294
308
  ? `Inherited from ${grant.ownerResource?.kind ?? "parent"}`
295
- : `Directly assigned`
296
- }
297
- >
298
- {roleName}
299
- {grant.isInherited && (
300
- <span className="stg:ml-1 stg:text-[0.55rem] stg:text-muted-foreground">
301
- (inherited)
302
- </span>
303
- )}
304
- </span>
309
+ : `Directly assigned`}
310
+ </TooltipContent>
311
+ </Tooltip>
305
312
  );
306
313
  }
307
314
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  import type { ApiResourceRefView } from "@stigmer/protos/ai/stigmer/iam/iampolicy/v1/io_pb";
4
4
  import { cn } from "@stigmer/theme";
5
+ import { Tooltip, TooltipContent, TooltipTrigger } from "../internal/tooltip.js";
5
6
 
6
7
  /**
7
8
  * The human-readable identity-source label for a principal, or `""` when none
@@ -39,15 +40,21 @@ export function ProviderBadge({ principal, className }: ProviderBadgeProps) {
39
40
  }
40
41
 
41
42
  return (
42
- <span
43
- className={cn(
44
- "stg:inline-flex stg:items-center stg:rounded stg:px-1.5 stg:py-0.5 stg:text-[0.6rem] stg:font-medium",
45
- "stg:bg-muted-subtle stg:text-muted-foreground",
46
- className,
47
- )}
48
- title={`Identity provider: ${label}`}
49
- >
50
- {label}
51
- </span>
43
+ <Tooltip>
44
+ <TooltipTrigger
45
+ render={
46
+ <span
47
+ className={cn(
48
+ "stg:inline-flex stg:items-center stg:rounded stg:px-1.5 stg:py-0.5 stg:text-[0.6rem] stg:font-medium",
49
+ "stg:bg-muted-subtle stg:text-muted-foreground",
50
+ className,
51
+ )}
52
+ />
53
+ }
54
+ >
55
+ {label}
56
+ </TooltipTrigger>
57
+ <TooltipContent side="top">{`Identity provider: ${label}`}</TooltipContent>
58
+ </Tooltip>
52
59
  );
53
60
  }
@@ -74,7 +74,6 @@ export function RoleSelector({
74
74
  return (
75
75
  <label
76
76
  key={opt.value}
77
- title={opt.description}
78
77
  className={cn(
79
78
  "stg:inline-flex stg:cursor-pointer stg:flex-col stg:rounded-md stg:border stg:px-3 stg:py-1.5 stg:text-xs stg:transition-colors",
80
79
  isChecked
@@ -5,6 +5,7 @@ import { cn } from "@stigmer/theme";
5
5
  import { getUserMessage } from "@stigmer/sdk";
6
6
  import { timestampDate } from "@bufbuild/protobuf/wkt";
7
7
  import type { IdentityProvider } from "@stigmer/protos/ai/stigmer/iam/identityprovider/v1/api_pb";
8
+ import { Tooltip, TooltipContent, TooltipTrigger } from "../internal/tooltip.js";
8
9
  import { useIdentityProviderList } from "./useIdentityProviderList.js";
9
10
  import { useDeleteIdentityProvider } from "./useDeleteIdentityProvider.js";
10
11
 
@@ -246,9 +247,16 @@ function IdpRow({
246
247
  </span>
247
248
  )}
248
249
  {createdAt && (
249
- <span title={`Created ${timestampDate(createdAt).toISOString()}`}>
250
- {formatShortDate(timestampDate(createdAt))}
251
- </span>
250
+ <Tooltip>
251
+ <TooltipTrigger
252
+ render={<time dateTime={timestampDate(createdAt).toISOString()} />}
253
+ >
254
+ {formatShortDate(timestampDate(createdAt))}
255
+ </TooltipTrigger>
256
+ <TooltipContent side="top">
257
+ {`Created ${timestampDate(createdAt).toISOString()}`}
258
+ </TooltipContent>
259
+ </Tooltip>
252
260
  )}
253
261
  </div>
254
262
 
@@ -0,0 +1,68 @@
1
+ // TruncatedText's overflow gating in a real Chromium (stigmer-cloud#268).
2
+ // The native `title` idiom this helper replaced fired whether or not the
3
+ // text was actually clipped; the helper opens the house tooltip ONLY when
4
+ // CSS truncation really happened. That distinction is a layout fact —
5
+ // happy-dom reports zero geometry — so only a real browser can pin it.
6
+
7
+ import "../../../dist/styles.css";
8
+
9
+ import { describe, it, expect, vi, afterEach } from "vitest";
10
+ import { render, cleanup } from "@testing-library/react";
11
+ import { userEvent } from "@vitest/browser/context";
12
+ import type { ReactElement } from "react";
13
+ import { TruncatedText } from "../truncated-text.js";
14
+
15
+ const LONG = "a-very-long-model-identifier/that-cannot-fit-in-eighty-pixels";
16
+ const SHORT = "fits";
17
+
18
+ /** A themed, hard-sized cell so truncation geometry is real. */
19
+ function renderInCell(ui: ReactElement, width: string) {
20
+ const cell = document.createElement("div");
21
+ cell.className = "stgm";
22
+ cell.style.width = width;
23
+ cell.style.display = "block";
24
+ document.body.appendChild(cell);
25
+ render(ui, { container: cell });
26
+ return cell;
27
+ }
28
+
29
+ function portaledText(cell: HTMLElement): string {
30
+ return Array.from(document.body.children)
31
+ .filter((node) => node !== cell)
32
+ .map((node) => node.textContent ?? "")
33
+ .join(" ");
34
+ }
35
+
36
+ afterEach(() => {
37
+ cleanup();
38
+ document.querySelectorAll(".stgm").forEach((node) => node.remove());
39
+ });
40
+
41
+ describe("TruncatedText overflow gating", () => {
42
+ it("reveals the full value on hover when the text is actually clipped", async () => {
43
+ const cell = renderInCell(<TruncatedText text={LONG} />, "80px");
44
+ expect(cell.querySelector("[title]")).toBeNull();
45
+
46
+ const span = cell.querySelector("span");
47
+ expect(span!.scrollWidth).toBeGreaterThan(span!.clientWidth);
48
+
49
+ await userEvent.hover(span!);
50
+ await vi.waitFor(
51
+ () => expect(portaledText(cell)).toContain(LONG),
52
+ { timeout: 3000, interval: 50 },
53
+ );
54
+ await userEvent.unhover(span!);
55
+ });
56
+
57
+ it("stays quiet when nothing is clipped — the tooltip would only repeat the cell", async () => {
58
+ const cell = renderInCell(<TruncatedText text={SHORT} />, "300px");
59
+
60
+ const span = cell.querySelector("span");
61
+ await userEvent.hover(span!);
62
+ // Base UI's default open delay is 600ms; wait past it and assert the
63
+ // portal never produced the tooltip.
64
+ await new Promise((resolve) => setTimeout(resolve, 1200));
65
+ expect(portaledText(cell)).not.toContain(SHORT);
66
+ await userEvent.unhover(span!);
67
+ });
68
+ });
@@ -0,0 +1,33 @@
1
+ // Fast structural pins for TruncatedText (the native-title sweep's
2
+ // truncation replacement, stigmer-cloud#268). Happy-dom can honestly pin
3
+ // the STRUCTURE — full text in the DOM, zero native titles, zero new tab
4
+ // stops; the overflow-gated REVEAL needs real layout and lives in
5
+ // truncated-text.layout.test.tsx.
6
+
7
+ import { describe, it, expect, afterEach } from "vitest";
8
+ import { render, cleanup, screen } from "@testing-library/react";
9
+ import { TruncatedText } from "../truncated-text.js";
10
+
11
+ afterEach(cleanup);
12
+
13
+ describe("TruncatedText", () => {
14
+ it("renders the full text in the DOM with no native title and no tab stop", () => {
15
+ render(<TruncatedText text="models/anthropic/claude-4.6-opus" />);
16
+
17
+ // CSS truncation is purely visual: screen readers and selection get
18
+ // the full value from the DOM, so no sr-only duplicate is needed.
19
+ const span = screen.getByText("models/anthropic/claude-4.6-opus");
20
+ expect(span.closest("[title]")).toBeNull();
21
+ expect(span.closest("[tabindex]")).toBeNull();
22
+ });
23
+
24
+ it("applies stg:truncate by default and yields to a line-clamp class", () => {
25
+ const { rerender } = render(<TruncatedText text="abc" />);
26
+ expect(screen.getByText("abc").className).toContain("stg:truncate");
27
+
28
+ rerender(<TruncatedText text="abc" className="stg:line-clamp-2" />);
29
+ const clamped = screen.getByText("abc");
30
+ expect(clamped.className).toContain("stg:line-clamp-2");
31
+ expect(clamped.className).not.toContain("stg:truncate");
32
+ });
33
+ });
@@ -0,0 +1,81 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import { cn } from "@stigmer/theme";
5
+ import { Tooltip, TooltipContent, TooltipTrigger } from "./tooltip.js";
6
+
7
+ // ---------------------------------------------------------------------------
8
+ // SDK-internal truncated-text span with an overflow-gated house tooltip.
9
+ //
10
+ // Replaces the `title={fullValue}` idiom on truncated cells (paths, hashes,
11
+ // model ids, …) after the native-title sweep (stigmer/stigmer-cloud#268).
12
+ // Native titles were OS-delayed and fired whether or not the text was
13
+ // actually clipped; this helper opens the house tooltip ONLY when the text
14
+ // truly overflows its box, checked at open time — a non-truncated cell
15
+ // stays tooltip-free.
16
+ //
17
+ // The trigger is a plain, non-focusable span (the StatusHint precedent in
18
+ // ConversationTimelineView): CSS truncation is purely visual, so the full
19
+ // text is already in the DOM for screen readers and selection — the tooltip
20
+ // is a sighted-pointer convenience, and a tab stop per table cell would be
21
+ // noise. Works with or without a `TooltipProvider` in scope (the provider
22
+ // only adds delay grouping); like ./tooltip.tsx, NOT exported from
23
+ // @stigmer/react.
24
+ // ---------------------------------------------------------------------------
25
+
26
+ interface TruncatedTextProps {
27
+ /** The full value: rendered inside the span and shown by the tooltip. */
28
+ readonly text: string;
29
+ /**
30
+ * Classes for the truncating span. `stg:truncate` is applied by default;
31
+ * pass a `stg:line-clamp-*` class instead for multi-line clamping (the
32
+ * overflow check covers both axes).
33
+ */
34
+ readonly className?: string;
35
+ /** Tooltip placement; truncated cells read best with the default "top". */
36
+ readonly side?: React.ComponentProps<typeof TooltipContent>["side"];
37
+ }
38
+
39
+ /** True when CSS actually clipped the element on either axis. */
40
+ function isOverflowing(el: HTMLElement): boolean {
41
+ return el.scrollWidth > el.clientWidth || el.scrollHeight > el.clientHeight;
42
+ }
43
+
44
+ export function TruncatedText({ text, className, side = "top" }: TruncatedTextProps) {
45
+ const spanRef = React.useRef<HTMLSpanElement>(null);
46
+ const [open, setOpen] = React.useState(false);
47
+
48
+ const handleOpenChange = React.useCallback((nextOpen: boolean) => {
49
+ if (nextOpen && spanRef.current && !isOverflowing(spanRef.current)) {
50
+ return; // Nothing is clipped — the tooltip would only repeat the cell.
51
+ }
52
+ setOpen(nextOpen);
53
+ }, []);
54
+
55
+ return (
56
+ <Tooltip open={open} onOpenChange={handleOpenChange}>
57
+ <TooltipTrigger
58
+ render={
59
+ <span
60
+ ref={spanRef}
61
+ className={cn(
62
+ // A plain inline span can neither truncate (overflow does not
63
+ // apply to inline boxes) nor be measured (clientWidth is 0 by
64
+ // spec), so the span defaults to block; cn()'s conflict
65
+ // resolution lets callers override with their own display
66
+ // class (inline-block, flex-1 cells, …).
67
+ "stg:block",
68
+ className?.match(/(?:^|\s)stg:line-clamp-/) ? undefined : "stg:truncate",
69
+ className,
70
+ )}
71
+ />
72
+ }
73
+ >
74
+ {text}
75
+ </TooltipTrigger>
76
+ <TooltipContent side={side} className="stg:break-all">
77
+ {text}
78
+ </TooltipContent>
79
+ </Tooltip>
80
+ );
81
+ }
@@ -15,6 +15,7 @@ import { useOrgInvitations } from "./useOrgInvitations.js";
15
15
  import { useCreateInvitation } from "./useCreateInvitation.js";
16
16
  import { useRevokeInvitation } from "./useRevokeInvitation.js";
17
17
  import { InvitationCreatedAlert } from "./InvitationCreatedAlert.js";
18
+ import { Tooltip, TooltipContent, TooltipTrigger } from "../internal/tooltip.js";
18
19
  import { RoleSelector } from "../iam-policy/RoleSelector.js";
19
20
 
20
21
  // ---------------------------------------------------------------------------
@@ -465,11 +466,23 @@ function InvitationRow({
465
466
 
466
467
  {/* Expiry */}
467
468
  {expiresAt && (
468
- <span className="stg:text-xs stg:text-muted-foreground" title={timestampDate(expiresAt).toISOString()}>
469
- {isActive
470
- ? formatRelativeExpiry(timestampDate(expiresAt))
471
- : formatShortDate(timestampDate(expiresAt))}
472
- </span>
469
+ <Tooltip>
470
+ <TooltipTrigger
471
+ render={
472
+ <time
473
+ dateTime={timestampDate(expiresAt).toISOString()}
474
+ className="stg:text-xs stg:text-muted-foreground"
475
+ />
476
+ }
477
+ >
478
+ {isActive
479
+ ? formatRelativeExpiry(timestampDate(expiresAt))
480
+ : formatShortDate(timestampDate(expiresAt))}
481
+ </TooltipTrigger>
482
+ <TooltipContent side="top">
483
+ {timestampDate(expiresAt).toISOString()}
484
+ </TooltipContent>
485
+ </Tooltip>
473
486
  )}
474
487
  </div>
475
488
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { useCallback, useRef } from "react";
4
4
  import { cn } from "@stigmer/theme";
5
+ import { Tooltip, TooltipContent, TooltipTrigger } from "../internal/tooltip.js";
5
6
  import type { ResourceListScope } from "../search/index.js";
6
7
 
7
8
  /** Props for {@link ScopeToggle}. */
@@ -116,7 +117,7 @@ export function ScopeToggle({
116
117
  const isSelected = value === option.value;
117
118
  const Icon = option.icon;
118
119
 
119
- return (
120
+ const radio = (
120
121
  <button
121
122
  key={option.value}
122
123
  ref={(el) => {
@@ -126,7 +127,6 @@ export function ScopeToggle({
126
127
  role="radio"
127
128
  aria-checked={isSelected}
128
129
  aria-label={option.ariaLabel}
129
- title={compact ? option.ariaLabel : undefined}
130
130
  tabIndex={isSelected ? 0 : -1}
131
131
  disabled={disabled}
132
132
  onClick={() => handleSelect(option.value)}
@@ -143,6 +143,18 @@ export function ScopeToggle({
143
143
  {!compact && option.label}
144
144
  </button>
145
145
  );
146
+
147
+ // Icon-only radios need their name discoverable by sighted users
148
+ // too: in compact mode each radio is its own tooltip trigger (hover
149
+ // and roving-tabindex focus both open it). Full mode shows visible
150
+ // labels, so a tooltip would only repeat them.
151
+ if (!compact) return radio;
152
+ return (
153
+ <Tooltip key={option.value}>
154
+ <TooltipTrigger render={radio} />
155
+ <TooltipContent side="top">{option.ariaLabel}</TooltipContent>
156
+ </Tooltip>
157
+ );
146
158
  })}
147
159
  </div>
148
160
  );
@@ -5,6 +5,7 @@ import { Popover } from "@base-ui/react/popover";
5
5
  import { cn } from "@stigmer/theme";
6
6
  import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
7
7
  import { useStigmerPortalContainer } from "../portal-container.js";
8
+ import { Tooltip, TooltipContent, TooltipTrigger } from "../internal/tooltip.js";
8
9
  import { ConfirmDialog } from "../resource-detail/ConfirmDialog.js";
9
10
  import { useConfirmAction } from "../resource-detail/useConfirmAction.js";
10
11
  import {
@@ -454,20 +455,26 @@ export function VisibilityBadge({
454
455
 
455
456
  if (onClick) {
456
457
  return (
457
- <button
458
- type="button"
459
- onClick={onClick}
460
- title="Manage access"
461
- aria-label={`${option.label} visibility — manage access`}
462
- className={cn(
463
- VISIBILITY_CHIP_CLASS,
464
- "stg:transition-colors stg:hover:bg-accent-hover stg:hover:text-foreground",
465
- "stg:focus-visible:outline-none stg:focus-visible:ring-2 stg:focus-visible:ring-ring",
466
- className,
467
- )}
468
- >
469
- {content}
470
- </button>
458
+ <Tooltip>
459
+ <TooltipTrigger
460
+ render={
461
+ <button
462
+ type="button"
463
+ onClick={onClick}
464
+ aria-label={`${option.label} visibility — manage access`}
465
+ className={cn(
466
+ VISIBILITY_CHIP_CLASS,
467
+ "stg:transition-colors stg:hover:bg-accent-hover stg:hover:text-foreground",
468
+ "stg:focus-visible:outline-none stg:focus-visible:ring-2 stg:focus-visible:ring-ring",
469
+ className,
470
+ )}
471
+ />
472
+ }
473
+ >
474
+ {content}
475
+ </TooltipTrigger>
476
+ <TooltipContent side="top">Manage access</TooltipContent>
477
+ </Tooltip>
471
478
  );
472
479
  }
473
480