@vertesia/ui 1.5.0-dev.20260722.120446Z → 1.5.0-dev.20260804.124748Z

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 (415) hide show
  1. package/lib/core/components/shadcn/filters/filterBar.d.ts.map +1 -1
  2. package/lib/core/components/shadcn/filters/filterBar.js +1 -1
  3. package/lib/core/components/shadcn/filters/filterBar.js.map +1 -1
  4. package/lib/core/components/shadcn/modal/dialog.d.ts +1 -1
  5. package/lib/core/components/shadcn/modal/dialog.d.ts.map +1 -1
  6. package/lib/core/components/shadcn/modal/dialog.js +2 -0
  7. package/lib/core/components/shadcn/modal/dialog.js.map +1 -1
  8. package/lib/core/components/shadcn/tabs.d.ts +12 -1
  9. package/lib/core/components/shadcn/tabs.d.ts.map +1 -1
  10. package/lib/core/components/shadcn/tabs.js +12 -4
  11. package/lib/core/components/shadcn/tabs.js.map +1 -1
  12. package/lib/core/hooks/useScrollableSearch.d.ts +1 -1
  13. package/lib/core/hooks/useScrollableSearch.d.ts.map +1 -1
  14. package/lib/core/hooks/useScrollableSearch.js +15 -2
  15. package/lib/core/hooks/useScrollableSearch.js.map +1 -1
  16. package/lib/env/index.d.ts +4 -0
  17. package/lib/env/index.d.ts.map +1 -1
  18. package/lib/env/index.js.map +1 -1
  19. package/lib/features/agent/chat/AgentRequestInputOverlay.d.ts +1 -1
  20. package/lib/features/agent/chat/AgentRequestInputOverlay.d.ts.map +1 -1
  21. package/lib/features/agent/chat/AgentRequestInputOverlay.js +3 -8
  22. package/lib/features/agent/chat/AgentRequestInputOverlay.js.map +1 -1
  23. package/lib/features/agent/chat/AgentRightPanel.d.ts +5 -1
  24. package/lib/features/agent/chat/AgentRightPanel.d.ts.map +1 -1
  25. package/lib/features/agent/chat/AgentRightPanel.js +2 -2
  26. package/lib/features/agent/chat/AgentRightPanel.js.map +1 -1
  27. package/lib/features/agent/chat/ArtifactsTab.d.ts +5 -1
  28. package/lib/features/agent/chat/ArtifactsTab.d.ts.map +1 -1
  29. package/lib/features/agent/chat/ArtifactsTab.js +48 -11
  30. package/lib/features/agent/chat/ArtifactsTab.js.map +1 -1
  31. package/lib/features/agent/chat/DocumentEditingActionCard.d.ts +6 -0
  32. package/lib/features/agent/chat/DocumentEditingActionCard.d.ts.map +1 -0
  33. package/lib/features/agent/chat/DocumentEditingActionCard.js +129 -0
  34. package/lib/features/agent/chat/DocumentEditingActionCard.js.map +1 -0
  35. package/lib/features/agent/chat/ModernAgentConversation.d.ts +27 -2
  36. package/lib/features/agent/chat/ModernAgentConversation.d.ts.map +1 -1
  37. package/lib/features/agent/chat/ModernAgentConversation.js +174 -40
  38. package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
  39. package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.d.ts +2 -1
  40. package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.d.ts.map +1 -1
  41. package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.js +25 -10
  42. package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.js.map +1 -1
  43. package/lib/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.d.ts +45 -0
  44. package/lib/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.d.ts.map +1 -0
  45. package/lib/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.js +40 -0
  46. package/lib/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.js.map +1 -0
  47. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts +3 -1
  48. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
  49. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +118 -58
  50. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
  51. package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.d.ts +2 -1
  52. package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.d.ts.map +1 -1
  53. package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.js +23 -7
  54. package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.js.map +1 -1
  55. package/lib/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.d.ts +25 -0
  56. package/lib/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.d.ts.map +1 -0
  57. package/lib/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.js +33 -0
  58. package/lib/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.js.map +1 -0
  59. package/lib/features/agent/chat/ModernAgentOutput/Header.js +2 -2
  60. package/lib/features/agent/chat/ModernAgentOutput/Header.js.map +1 -1
  61. package/lib/features/agent/chat/ModernAgentOutput/MessageInput.d.ts +2 -1
  62. package/lib/features/agent/chat/ModernAgentOutput/MessageInput.d.ts.map +1 -1
  63. package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js +2 -2
  64. package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js.map +1 -1
  65. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts +3 -1
  66. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts.map +1 -1
  67. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js +23 -25
  68. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
  69. package/lib/features/agent/chat/ModernAgentOutput/ResourceChangeSummary.d.ts +14 -0
  70. package/lib/features/agent/chat/ModernAgentOutput/ResourceChangeSummary.d.ts.map +1 -0
  71. package/lib/features/agent/chat/ModernAgentOutput/ResourceChangeSummary.js +21 -0
  72. package/lib/features/agent/chat/ModernAgentOutput/ResourceChangeSummary.js.map +1 -0
  73. package/lib/features/agent/chat/ModernAgentOutput/ResourceChip.d.ts +30 -0
  74. package/lib/features/agent/chat/ModernAgentOutput/ResourceChip.d.ts.map +1 -0
  75. package/lib/features/agent/chat/ModernAgentOutput/ResourceChip.js +53 -0
  76. package/lib/features/agent/chat/ModernAgentOutput/ResourceChip.js.map +1 -0
  77. package/lib/features/agent/chat/ModernAgentOutput/ToolCallGroup.d.ts.map +1 -1
  78. package/lib/features/agent/chat/ModernAgentOutput/ToolCallGroup.js +21 -2
  79. package/lib/features/agent/chat/ModernAgentOutput/ToolCallGroup.js.map +1 -1
  80. package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.d.ts +9 -1
  81. package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.d.ts.map +1 -1
  82. package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.js +97 -2
  83. package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.js.map +1 -1
  84. package/lib/features/agent/chat/ModernAgentOutput/resourceLinks.d.ts +6 -0
  85. package/lib/features/agent/chat/ModernAgentOutput/resourceLinks.d.ts.map +1 -0
  86. package/lib/features/agent/chat/ModernAgentOutput/resourceLinks.js +29 -0
  87. package/lib/features/agent/chat/ModernAgentOutput/resourceLinks.js.map +1 -0
  88. package/lib/features/agent/chat/ModernAgentOutput/resourceSummary.d.ts +33 -0
  89. package/lib/features/agent/chat/ModernAgentOutput/resourceSummary.d.ts.map +1 -0
  90. package/lib/features/agent/chat/ModernAgentOutput/resourceSummary.js +129 -0
  91. package/lib/features/agent/chat/ModernAgentOutput/resourceSummary.js.map +1 -0
  92. package/lib/features/agent/chat/ModernAgentOutput/utils.d.ts +7 -0
  93. package/lib/features/agent/chat/ModernAgentOutput/utils.d.ts.map +1 -1
  94. package/lib/features/agent/chat/ModernAgentOutput/utils.js +11 -1
  95. package/lib/features/agent/chat/ModernAgentOutput/utils.js.map +1 -1
  96. package/lib/features/agent/chat/hooks/useAgentStream.d.ts +1 -1
  97. package/lib/features/agent/chat/hooks/useAgentStream.d.ts.map +1 -1
  98. package/lib/features/agent/chat/hooks/useAgentStream.js +34 -10
  99. package/lib/features/agent/chat/hooks/useAgentStream.js.map +1 -1
  100. package/lib/features/agent/chat/index.d.ts +2 -1
  101. package/lib/features/agent/chat/index.d.ts.map +1 -1
  102. package/lib/features/agent/chat/index.js +3 -0
  103. package/lib/features/agent/chat/index.js.map +1 -1
  104. package/lib/features/facets/PromptsFacetsNav.d.ts +8 -6
  105. package/lib/features/facets/PromptsFacetsNav.d.ts.map +1 -1
  106. package/lib/features/facets/PromptsFacetsNav.js +8 -3
  107. package/lib/features/facets/PromptsFacetsNav.js.map +1 -1
  108. package/lib/features/store/objects/DocumentSearchResults.js +2 -2
  109. package/lib/features/store/objects/DocumentSearchResults.js.map +1 -1
  110. package/lib/features/store/objects/components/ContentOverview.d.ts +2 -1
  111. package/lib/features/store/objects/components/ContentOverview.d.ts.map +1 -1
  112. package/lib/features/store/objects/components/ContentOverview.js +90 -16
  113. package/lib/features/store/objects/components/ContentOverview.js.map +1 -1
  114. package/lib/features/store/objects/components/DocumentEditingConfigurationSelector.d.ts +16 -0
  115. package/lib/features/store/objects/components/DocumentEditingConfigurationSelector.d.ts.map +1 -0
  116. package/lib/features/store/objects/components/DocumentEditingConfigurationSelector.js +116 -0
  117. package/lib/features/store/objects/components/DocumentEditingConfigurationSelector.js.map +1 -0
  118. package/lib/features/store/objects/components/DocumentEditingLockStatus.d.ts +7 -0
  119. package/lib/features/store/objects/components/DocumentEditingLockStatus.d.ts.map +1 -0
  120. package/lib/features/store/objects/components/DocumentEditingLockStatus.js +13 -0
  121. package/lib/features/store/objects/components/DocumentEditingLockStatus.js.map +1 -0
  122. package/lib/features/store/objects/components/DocumentEditingPanel.d.ts +48 -0
  123. package/lib/features/store/objects/components/DocumentEditingPanel.d.ts.map +1 -0
  124. package/lib/features/store/objects/components/DocumentEditingPanel.js +720 -0
  125. package/lib/features/store/objects/components/DocumentEditingPanel.js.map +1 -0
  126. package/lib/features/store/objects/components/TextEditorPanel.d.ts.map +1 -1
  127. package/lib/features/store/objects/components/TextEditorPanel.js +22 -9
  128. package/lib/features/store/objects/components/TextEditorPanel.js.map +1 -1
  129. package/lib/features/store/objects/components/documentArtifactRefs.d.ts +26 -0
  130. package/lib/features/store/objects/components/documentArtifactRefs.d.ts.map +1 -0
  131. package/lib/features/store/objects/components/documentArtifactRefs.js +52 -0
  132. package/lib/features/store/objects/components/documentArtifactRefs.js.map +1 -0
  133. package/lib/features/store/objects/components/documentEditingAgentConfig.d.ts +4 -0
  134. package/lib/features/store/objects/components/documentEditingAgentConfig.d.ts.map +1 -0
  135. package/lib/features/store/objects/components/documentEditingAgentConfig.js +40 -0
  136. package/lib/features/store/objects/components/documentEditingAgentConfig.js.map +1 -0
  137. package/lib/features/store/objects/components/documentEditingPrompts.d.ts +3 -0
  138. package/lib/features/store/objects/components/documentEditingPrompts.d.ts.map +1 -0
  139. package/lib/features/store/objects/components/documentEditingPrompts.js +13 -0
  140. package/lib/features/store/objects/components/documentEditingPrompts.js.map +1 -0
  141. package/lib/features/store/objects/components/documentEditingRun.d.ts +27 -0
  142. package/lib/features/store/objects/components/documentEditingRun.d.ts.map +1 -0
  143. package/lib/features/store/objects/components/documentEditingRun.js +126 -0
  144. package/lib/features/store/objects/components/documentEditingRun.js.map +1 -0
  145. package/lib/features/store/objects/components/documentEditingTarget.d.ts +20 -0
  146. package/lib/features/store/objects/components/documentEditingTarget.d.ts.map +1 -0
  147. package/lib/features/store/objects/components/documentEditingTarget.js +40 -0
  148. package/lib/features/store/objects/components/documentEditingTarget.js.map +1 -0
  149. package/lib/features/store/objects/components/index.d.ts +1 -0
  150. package/lib/features/store/objects/components/index.d.ts.map +1 -1
  151. package/lib/features/store/objects/components/index.js +1 -0
  152. package/lib/features/store/objects/components/index.js.map +1 -1
  153. package/lib/features/store/objects/components/useContentPanelHooks.d.ts +36 -4
  154. package/lib/features/store/objects/components/useContentPanelHooks.d.ts.map +1 -1
  155. package/lib/features/store/objects/components/useContentPanelHooks.js +53 -29
  156. package/lib/features/store/objects/components/useContentPanelHooks.js.map +1 -1
  157. package/lib/features/store/objects/components/useDownloadFile.d.ts +2 -1
  158. package/lib/features/store/objects/components/useDownloadFile.d.ts.map +1 -1
  159. package/lib/features/store/objects/components/useDownloadFile.js +3 -0
  160. package/lib/features/store/objects/components/useDownloadFile.js.map +1 -1
  161. package/lib/features/store/objects/search/DocumentSearchContext.d.ts +128 -6
  162. package/lib/features/store/objects/search/DocumentSearchContext.d.ts.map +1 -1
  163. package/lib/features/store/objects/selection/ObjectsActionContext.d.ts +2 -2
  164. package/lib/features/store/objects/selection/ObjectsActionContext.d.ts.map +1 -1
  165. package/lib/features/store/objects/selection/ObjectsActionSpec.d.ts +2 -2
  166. package/lib/features/store/objects/selection/ObjectsActionSpec.d.ts.map +1 -1
  167. package/lib/features/store/objects/selection/SelectionActions.d.ts +2 -2
  168. package/lib/features/store/objects/selection/SelectionActions.d.ts.map +1 -1
  169. package/lib/features/store/objects/selection/actions/StartWorkflowButton.js +1 -1
  170. package/lib/features/store/objects/selection/actions/StartWorkflowButton.js.map +1 -1
  171. package/lib/features/store/objects/upload/DocumentUploadModal.js.map +1 -1
  172. package/lib/features/store/types/IntakePolicyEditor.d.ts +2 -2
  173. package/lib/features/store/types/IntakePolicyEditor.d.ts.map +1 -1
  174. package/lib/features/store/types/IntakePolicyEditor.js +5 -1
  175. package/lib/features/store/types/IntakePolicyEditor.js.map +1 -1
  176. package/lib/features/store/types/IntakePolicyForm.d.ts.map +1 -1
  177. package/lib/features/store/types/IntakePolicyForm.js +2 -2
  178. package/lib/features/store/types/IntakePolicyForm.js.map +1 -1
  179. package/lib/features/store/types/ObjectSchemaEditor.d.ts +2 -2
  180. package/lib/features/store/types/ObjectSchemaEditor.d.ts.map +1 -1
  181. package/lib/features/store/types/SelectContentType.d.ts +2 -2
  182. package/lib/features/store/types/SelectContentType.d.ts.map +1 -1
  183. package/lib/features/store/types/SelectContentType.js.map +1 -1
  184. package/lib/features/store/types/SelectContentTypeModal.d.ts +2 -2
  185. package/lib/features/store/types/SelectContentTypeModal.d.ts.map +1 -1
  186. package/lib/features/store/types/SelectContentTypeModal.js.map +1 -1
  187. package/lib/features/store/types/TableLayoutEditor.d.ts +2 -2
  188. package/lib/features/store/types/TableLayoutEditor.d.ts.map +1 -1
  189. package/lib/features/store/types/TypeRegistry.d.ts +1267 -6
  190. package/lib/features/store/types/TypeRegistry.d.ts.map +1 -1
  191. package/lib/features/store/types/TypeRegistry.js +5 -0
  192. package/lib/features/store/types/TypeRegistry.js.map +1 -1
  193. package/lib/features/store/types/intake-policy-editor.logic.d.ts +9 -1
  194. package/lib/features/store/types/intake-policy-editor.logic.d.ts.map +1 -1
  195. package/lib/features/store/types/intake-policy-editor.logic.js +9 -1
  196. package/lib/features/store/types/intake-policy-editor.logic.js.map +1 -1
  197. package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts +1251 -1
  198. package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts.map +1 -1
  199. package/lib/features/store/types/typeCatalogCache.d.ts +2 -2
  200. package/lib/features/store/types/typeCatalogCache.d.ts.map +1 -1
  201. package/lib/features/store/types/typeCatalogCache.js +4 -0
  202. package/lib/features/store/types/typeCatalogCache.js.map +1 -1
  203. package/lib/features/user/UserInfo.d.ts +118 -7
  204. package/lib/features/user/UserInfo.d.ts.map +1 -1
  205. package/lib/i18n/locales/ar.json +120 -2
  206. package/lib/i18n/locales/de.json +120 -2
  207. package/lib/i18n/locales/en.json +123 -1
  208. package/lib/i18n/locales/es.json +120 -2
  209. package/lib/i18n/locales/fr.json +120 -2
  210. package/lib/i18n/locales/it.json +120 -2
  211. package/lib/i18n/locales/ja.json +120 -2
  212. package/lib/i18n/locales/ko.json +120 -2
  213. package/lib/i18n/locales/pt.json +120 -2
  214. package/lib/i18n/locales/ru.json +120 -2
  215. package/lib/i18n/locales/tr.json +120 -2
  216. package/lib/i18n/locales/zh-TW.json +120 -2
  217. package/lib/i18n/locales/zh.json +120 -2
  218. package/lib/rich-text/EditorToolbar.d.ts +37 -0
  219. package/lib/rich-text/EditorToolbar.d.ts.map +1 -0
  220. package/lib/rich-text/EditorToolbar.js +215 -0
  221. package/lib/rich-text/EditorToolbar.js.map +1 -0
  222. package/lib/rich-text/VertesiaRichTextEditor.d.ts +26 -0
  223. package/lib/rich-text/VertesiaRichTextEditor.d.ts.map +1 -0
  224. package/lib/rich-text/VertesiaRichTextEditor.js +67 -0
  225. package/lib/rich-text/VertesiaRichTextEditor.js.map +1 -0
  226. package/lib/rich-text/index.d.ts +2 -0
  227. package/lib/rich-text/index.d.ts.map +1 -0
  228. package/lib/rich-text/index.js +2 -0
  229. package/lib/rich-text/index.js.map +1 -0
  230. package/lib/session/UserSession.d.ts +18 -4
  231. package/lib/session/UserSession.d.ts.map +1 -1
  232. package/lib/shell/apps/AppInstallationProvider.d.ts +222 -2
  233. package/lib/shell/apps/AppInstallationProvider.d.ts.map +1 -1
  234. package/lib/shell/login/InviteAcceptModal.js.map +1 -1
  235. package/lib/vertesia-ui-core.js +3 -3
  236. package/lib/vertesia-ui-core.js.map +1 -1
  237. package/lib/vertesia-ui-features.js +35 -30
  238. package/lib/vertesia-ui-features.js.map +1 -1
  239. package/lib/vertesia-ui-i18n.js +14 -14
  240. package/lib/vertesia-ui-i18n.js.map +1 -1
  241. package/lib/vertesia-ui-rich-text.js +5 -0
  242. package/lib/vertesia-ui-rich-text.js.map +1 -0
  243. package/lib/vertesia-ui-widgets.js +25 -7
  244. package/lib/vertesia-ui-widgets.js.map +1 -1
  245. package/lib/widgets/markdown/AgentResourceResolver.d.ts +31 -0
  246. package/lib/widgets/markdown/AgentResourceResolver.d.ts.map +1 -0
  247. package/lib/widgets/markdown/AgentResourceResolver.js +39 -0
  248. package/lib/widgets/markdown/AgentResourceResolver.js.map +1 -0
  249. package/lib/widgets/markdown/ArtifactEditingSurface.d.ts +63 -0
  250. package/lib/widgets/markdown/ArtifactEditingSurface.d.ts.map +1 -0
  251. package/lib/widgets/markdown/ArtifactEditingSurface.js +582 -0
  252. package/lib/widgets/markdown/ArtifactEditingSurface.js.map +1 -0
  253. package/lib/widgets/markdown/CollaborativeMarkdownRenderer.d.ts +69 -0
  254. package/lib/widgets/markdown/CollaborativeMarkdownRenderer.d.ts.map +1 -0
  255. package/lib/widgets/markdown/CollaborativeMarkdownRenderer.js +374 -0
  256. package/lib/widgets/markdown/CollaborativeMarkdownRenderer.js.map +1 -0
  257. package/lib/widgets/markdown/MarkdownLink.d.ts +3 -1
  258. package/lib/widgets/markdown/MarkdownLink.d.ts.map +1 -1
  259. package/lib/widgets/markdown/MarkdownLink.js +41 -14
  260. package/lib/widgets/markdown/MarkdownLink.js.map +1 -1
  261. package/lib/widgets/markdown/MarkdownRenderer.d.ts +8 -1
  262. package/lib/widgets/markdown/MarkdownRenderer.d.ts.map +1 -1
  263. package/lib/widgets/markdown/MarkdownRenderer.js +20 -4
  264. package/lib/widgets/markdown/MarkdownRenderer.js.map +1 -1
  265. package/lib/widgets/markdown/index.d.ts +5 -1
  266. package/lib/widgets/markdown/index.d.ts.map +1 -1
  267. package/lib/widgets/markdown/index.js +5 -1
  268. package/lib/widgets/markdown/index.js.map +1 -1
  269. package/lib/widgets/markdown/normalizeCustomSchemeLinks.d.ts.map +1 -1
  270. package/lib/widgets/markdown/normalizeCustomSchemeLinks.js +14 -2
  271. package/lib/widgets/markdown/normalizeCustomSchemeLinks.js.map +1 -1
  272. package/lib/widgets/markdown/textDiff.d.ts +52 -0
  273. package/lib/widgets/markdown/textDiff.d.ts.map +1 -0
  274. package/lib/widgets/markdown/textDiff.js +362 -0
  275. package/lib/widgets/markdown/textDiff.js.map +1 -0
  276. package/lib/widgets/markdown/useArtifactContent.d.ts +5 -3
  277. package/lib/widgets/markdown/useArtifactContent.d.ts.map +1 -1
  278. package/lib/widgets/markdown/useArtifactContent.js +6 -3
  279. package/lib/widgets/markdown/useArtifactContent.js.map +1 -1
  280. package/lib/widgets/markdown/useResolvedUrl.d.ts +1 -5
  281. package/lib/widgets/markdown/useResolvedUrl.d.ts.map +1 -1
  282. package/lib/widgets/markdown/useResolvedUrl.js +19 -31
  283. package/lib/widgets/markdown/useResolvedUrl.js.map +1 -1
  284. package/lib/widgets/monacoEditor/MonacoEditor.d.ts +7 -1
  285. package/lib/widgets/monacoEditor/MonacoEditor.d.ts.map +1 -1
  286. package/lib/widgets/monacoEditor/MonacoEditor.js +62 -6
  287. package/lib/widgets/monacoEditor/MonacoEditor.js.map +1 -1
  288. package/lib/widgets/xml-viewer/hooks/useXMLViewer.d.ts +9 -0
  289. package/lib/widgets/xml-viewer/hooks/useXMLViewer.d.ts.map +1 -1
  290. package/lib/widgets/xml-viewer/hooks/useXMLViewer.js +20 -17
  291. package/lib/widgets/xml-viewer/hooks/useXMLViewer.js.map +1 -1
  292. package/package.json +36 -32
  293. package/src/__tests__/a11y.test.tsx +4 -1
  294. package/src/__tests__/axe-helper.ts +17 -7
  295. package/src/__tests__/setup.ts +25 -0
  296. package/src/core/components/shadcn/filters/filterBar.tsx +1 -0
  297. package/src/core/components/shadcn/modal/dialog.tsx +3 -1
  298. package/src/core/components/shadcn/tabs.test.tsx +65 -0
  299. package/src/core/components/shadcn/tabs.tsx +25 -3
  300. package/src/core/hooks/useScrollableSearch.test.tsx +139 -0
  301. package/src/core/hooks/useScrollableSearch.tsx +17 -3
  302. package/src/env/index.ts +2 -0
  303. package/src/features/agent/chat/AgentChatPlaybackControls.test.tsx +2 -0
  304. package/src/features/agent/chat/AgentRequestInputOverlay.test.tsx +51 -6
  305. package/src/features/agent/chat/AgentRequestInputOverlay.tsx +5 -7
  306. package/src/features/agent/chat/AgentRightPanel.tsx +16 -1
  307. package/src/features/agent/chat/ArtifactsTab.test.tsx +55 -0
  308. package/src/features/agent/chat/ArtifactsTab.tsx +203 -52
  309. package/src/features/agent/chat/DocumentEditingActionCard.test.tsx +105 -0
  310. package/src/features/agent/chat/DocumentEditingActionCard.tsx +210 -0
  311. package/src/features/agent/chat/ModernAgentConversation.test.tsx +432 -43
  312. package/src/features/agent/chat/ModernAgentConversation.tsx +352 -96
  313. package/src/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.tsx +75 -20
  314. package/src/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.test.tsx +79 -0
  315. package/src/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.tsx +94 -0
  316. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.test.tsx +369 -34
  317. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +279 -115
  318. package/src/features/agent/chat/ModernAgentOutput/AttachmentPreview.tsx +53 -4
  319. package/src/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.test.tsx +44 -0
  320. package/src/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.tsx +88 -0
  321. package/src/features/agent/chat/ModernAgentOutput/Header.tsx +2 -2
  322. package/src/features/agent/chat/ModernAgentOutput/MessageInput.test.tsx +71 -0
  323. package/src/features/agent/chat/ModernAgentOutput/MessageInput.tsx +3 -1
  324. package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +48 -50
  325. package/src/features/agent/chat/ModernAgentOutput/ResourceChangeSummary.tsx +40 -0
  326. package/src/features/agent/chat/ModernAgentOutput/ResourceChip.test.tsx +148 -0
  327. package/src/features/agent/chat/ModernAgentOutput/ResourceChip.tsx +141 -0
  328. package/src/features/agent/chat/ModernAgentOutput/ToolCallGroup.tsx +33 -1
  329. package/src/features/agent/chat/ModernAgentOutput/requestInputMessages.test.ts +95 -0
  330. package/src/features/agent/chat/ModernAgentOutput/requestInputMessages.ts +111 -1
  331. package/src/features/agent/chat/ModernAgentOutput/resourceLinks.tsx +43 -0
  332. package/src/features/agent/chat/ModernAgentOutput/resourceSummary.test.ts +229 -0
  333. package/src/features/agent/chat/ModernAgentOutput/resourceSummary.ts +152 -0
  334. package/src/features/agent/chat/ModernAgentOutput/utils.test.ts +17 -0
  335. package/src/features/agent/chat/ModernAgentOutput/utils.ts +14 -1
  336. package/src/features/agent/chat/hooks/useAgentStream.test.tsx +245 -0
  337. package/src/features/agent/chat/hooks/useAgentStream.ts +38 -9
  338. package/src/features/agent/chat/index.ts +12 -0
  339. package/src/features/facets/PromptsFacetsNav.tsx +17 -9
  340. package/src/features/store/objects/DocumentSearchResults.tsx +2 -2
  341. package/src/features/store/objects/components/ContentOverview.tsx +220 -66
  342. package/src/features/store/objects/components/DocumentEditingConfigurationSelector.test.ts +34 -0
  343. package/src/features/store/objects/components/DocumentEditingConfigurationSelector.tsx +211 -0
  344. package/src/features/store/objects/components/DocumentEditingLockStatus.test.tsx +32 -0
  345. package/src/features/store/objects/components/DocumentEditingLockStatus.tsx +45 -0
  346. package/src/features/store/objects/components/DocumentEditingPanel.test.tsx +336 -0
  347. package/src/features/store/objects/components/DocumentEditingPanel.tsx +1236 -0
  348. package/src/features/store/objects/components/TextEditorPanel.test.tsx +48 -0
  349. package/src/features/store/objects/components/TextEditorPanel.tsx +41 -20
  350. package/src/features/store/objects/components/documentArtifactRefs.test.ts +65 -0
  351. package/src/features/store/objects/components/documentArtifactRefs.ts +72 -0
  352. package/src/features/store/objects/components/documentEditingAgentConfig.test.ts +28 -0
  353. package/src/features/store/objects/components/documentEditingAgentConfig.ts +41 -0
  354. package/src/features/store/objects/components/documentEditingPrompts.test.ts +26 -0
  355. package/src/features/store/objects/components/documentEditingPrompts.ts +12 -0
  356. package/src/features/store/objects/components/documentEditingRun.test.ts +176 -0
  357. package/src/features/store/objects/components/documentEditingRun.ts +184 -0
  358. package/src/features/store/objects/components/documentEditingTarget.test.ts +96 -0
  359. package/src/features/store/objects/components/documentEditingTarget.ts +63 -0
  360. package/src/features/store/objects/components/index.ts +1 -0
  361. package/src/features/store/objects/components/useContentPanelHooks.ts +52 -27
  362. package/src/features/store/objects/components/useDownloadFile.test.ts +20 -0
  363. package/src/features/store/objects/components/useDownloadFile.ts +5 -1
  364. package/src/features/store/objects/selection/ObjectsActionContext.tsx +2 -2
  365. package/src/features/store/objects/selection/ObjectsActionSpec.ts +2 -2
  366. package/src/features/store/objects/selection/SelectionActions.tsx +2 -2
  367. package/src/features/store/objects/selection/actions/StartWorkflowButton.tsx +2 -2
  368. package/src/features/store/objects/upload/DocumentUploadModal.tsx +2 -2
  369. package/src/features/store/types/IntakePolicyEditor.tsx +12 -4
  370. package/src/features/store/types/IntakePolicyForm.tsx +25 -0
  371. package/src/features/store/types/ObjectSchemaEditor.tsx +2 -2
  372. package/src/features/store/types/SelectContentType.tsx +9 -9
  373. package/src/features/store/types/SelectContentTypeModal.tsx +5 -5
  374. package/src/features/store/types/TableLayoutEditor.tsx +2 -2
  375. package/src/features/store/types/TypeRegistry.ts +8 -3
  376. package/src/features/store/types/intake-policy-editor.logic.ts +10 -2
  377. package/src/features/store/types/typeCatalogCache.ts +10 -3
  378. package/src/i18n/locales/ar.json +120 -2
  379. package/src/i18n/locales/de.json +120 -2
  380. package/src/i18n/locales/en.json +123 -1
  381. package/src/i18n/locales/es.json +120 -2
  382. package/src/i18n/locales/fr.json +120 -2
  383. package/src/i18n/locales/it.json +120 -2
  384. package/src/i18n/locales/ja.json +120 -2
  385. package/src/i18n/locales/ko.json +120 -2
  386. package/src/i18n/locales/pt.json +120 -2
  387. package/src/i18n/locales/ru.json +120 -2
  388. package/src/i18n/locales/tr.json +120 -2
  389. package/src/i18n/locales/zh-TW.json +120 -2
  390. package/src/i18n/locales/zh.json +120 -2
  391. package/src/rich-text/EditorToolbar.tsx +708 -0
  392. package/src/rich-text/VertesiaRichTextEditor.test.tsx +211 -0
  393. package/src/rich-text/VertesiaRichTextEditor.tsx +241 -0
  394. package/src/rich-text/index.ts +9 -0
  395. package/src/session/UserSession.test.ts +11 -11
  396. package/src/shell/login/InviteAcceptModal.tsx +4 -4
  397. package/src/widgets/markdown/AgentResourceResolver.test.ts +24 -0
  398. package/src/widgets/markdown/AgentResourceResolver.tsx +70 -0
  399. package/src/widgets/markdown/ArtifactEditingSurface.test.tsx +541 -0
  400. package/src/widgets/markdown/ArtifactEditingSurface.tsx +878 -0
  401. package/src/widgets/markdown/CollaborativeMarkdownRenderer.test.tsx +484 -0
  402. package/src/widgets/markdown/CollaborativeMarkdownRenderer.tsx +825 -0
  403. package/src/widgets/markdown/MarkdownLink.test.tsx +122 -0
  404. package/src/widgets/markdown/MarkdownLink.tsx +102 -17
  405. package/src/widgets/markdown/MarkdownRenderer.tsx +30 -3
  406. package/src/widgets/markdown/index.ts +39 -1
  407. package/src/widgets/markdown/normalizeCustomSchemeLinks.ts +15 -2
  408. package/src/widgets/markdown/textDiff.test.ts +156 -0
  409. package/src/widgets/markdown/textDiff.ts +399 -0
  410. package/src/widgets/markdown/useArtifactContent.ts +9 -3
  411. package/src/widgets/markdown/useResolvedUrl.test.ts +29 -40
  412. package/src/widgets/markdown/useResolvedUrl.ts +33 -35
  413. package/src/widgets/monacoEditor/MonacoEditor.tsx +83 -7
  414. package/src/widgets/xml-viewer/hooks/useXMLViewer.test.ts +26 -0
  415. package/src/widgets/xml-viewer/hooks/useXMLViewer.ts +23 -18
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vertesia/ui",
3
- "version": "1.5.0-dev.20260722.120446Z",
3
+ "version": "1.5.0-dev.20260804.124748Z",
4
4
  "description": "Vertesia UI components and and hooks",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -24,24 +24,24 @@
24
24
  "@floating-ui/dom": "^1.8.0",
25
25
  "@floating-ui/react": "^0.27.20",
26
26
  "@monaco-editor/react": "^4.7.0",
27
- "@radix-ui/react-checkbox": "^1.3.7",
28
- "@radix-ui/react-collapsible": "^1.1.16",
29
- "@radix-ui/react-dialog": "^1.1.19",
30
- "@radix-ui/react-direction": "^1.1.2",
31
- "@radix-ui/react-dismissable-layer": "^1.1.15",
32
- "@radix-ui/react-dropdown-menu": "^2.1.20",
33
- "@radix-ui/react-focus-guards": "^1.1.4",
34
- "@radix-ui/react-focus-scope": "^1.1.12",
35
- "@radix-ui/react-label": "^2.1.11",
36
- "@radix-ui/react-popover": "^1.1.19",
37
- "@radix-ui/react-portal": "^1.1.13",
38
- "@radix-ui/react-radio-group": "^1.4.3",
39
- "@radix-ui/react-separator": "^1.1.11",
40
- "@radix-ui/react-slider": "^1.4.3",
41
- "@radix-ui/react-slot": "^1.3.0",
42
- "@radix-ui/react-switch": "^1.3.3",
43
- "@radix-ui/react-tabs": "^1.1.17",
44
- "@radix-ui/react-tooltip": "^1.2.12",
27
+ "@radix-ui/react-checkbox": "^1.3.11",
28
+ "@radix-ui/react-collapsible": "^1.1.20",
29
+ "@radix-ui/react-dialog": "^1.1.23",
30
+ "@radix-ui/react-direction": "^1.1.4",
31
+ "@radix-ui/react-dismissable-layer": "^1.1.19",
32
+ "@radix-ui/react-dropdown-menu": "^2.1.24",
33
+ "@radix-ui/react-focus-guards": "^1.1.6",
34
+ "@radix-ui/react-focus-scope": "^1.1.16",
35
+ "@radix-ui/react-label": "^2.1.15",
36
+ "@radix-ui/react-popover": "^1.1.23",
37
+ "@radix-ui/react-portal": "^1.1.17",
38
+ "@radix-ui/react-radio-group": "^1.4.7",
39
+ "@radix-ui/react-separator": "^1.1.15",
40
+ "@radix-ui/react-slider": "^1.4.7",
41
+ "@radix-ui/react-slot": "^1.3.3",
42
+ "@radix-ui/react-switch": "^1.3.7",
43
+ "@radix-ui/react-tabs": "^1.1.21",
44
+ "@radix-ui/react-tooltip": "^1.2.16",
45
45
  "ajv": "^8.20.0",
46
46
  "ajv-formats": "^3.0.1",
47
47
  "aria-hidden": "^1.2.6",
@@ -52,16 +52,15 @@
52
52
  "debounce": "^3.0.0",
53
53
  "dompurify": "^3.4.12",
54
54
  "fast-xml-parser": "^5.10.1",
55
- "fast-xml-validator": "^1.2.0",
56
55
  "firebase": "^12.16.0",
57
56
  "framer-motion": "^12.42.2",
58
57
  "i18next": "^26.3.6",
59
58
  "jwt-decode": "^4.0.0",
60
- "katex": "^0.17.0",
59
+ "katex": "^0.18.1",
61
60
  "lodash-es": "^4.18.1",
62
- "lucide-react": "^1.24.0",
61
+ "lucide-react": "^1.27.0",
63
62
  "mermaid": "^11.16.0",
64
- "monaco-editor": "^0.55.1",
63
+ "monaco-editor": "^0.56.0",
65
64
  "motion": "^12.42.2",
66
65
  "papaparse": "^5.5.4",
67
66
  "react": "19.2.7",
@@ -69,7 +68,7 @@
69
68
  "react-date-picker": "^12.0.2",
70
69
  "react-dom": "19.2.7",
71
70
  "react-error-boundary": "^6.1.2",
72
- "react-i18next": "^17.0.9",
71
+ "react-i18next": "^17.0.11",
73
72
  "react-markdown": "^10.1.0",
74
73
  "react-pdf": "^10.4.1",
75
74
  "react-remove-scroll": "^2.7.2",
@@ -87,13 +86,14 @@
87
86
  "tailwind-merge": "^3.6.0",
88
87
  "ts-md5": "^2.0.1",
89
88
  "unist-util-visit": "^5.1.0",
90
- "vega": "^6.2.0",
89
+ "vega": "^6.3.1",
91
90
  "vega-embed": "^7.1.0",
92
91
  "vega-lite": "^6.4.3",
93
- "@vertesia/client": "1.5.0-dev.20260722.120446Z",
94
- "@vertesia/json": "1.5.0-dev.20260722.120446Z",
95
- "@vertesia/fusion-ux": "1.5.0-dev.20260722.120446Z",
96
- "@vertesia/common": "1.5.0-dev.20260722.120446Z"
92
+ "@vertesia/client": "1.5.0-dev.20260804.124748Z",
93
+ "@vertesia/common": "1.5.0-dev.20260804.124748Z",
94
+ "@vertesia/fusion-ux": "1.5.0-dev.20260804.124748Z",
95
+ "@vertesia/rich-text": "1.5.0-dev.20260804.124748Z",
96
+ "@vertesia/json": "1.5.0-dev.20260804.124748Z"
97
97
  },
98
98
  "devDependencies": {
99
99
  "@testing-library/react": "^16.3.2",
@@ -106,9 +106,9 @@
106
106
  "@types/react-dom": "19.2.3",
107
107
  "axe-core": "^4.12.1",
108
108
  "culori": "^4.0.2",
109
- "i18next-cli": "^1.65.0",
109
+ "i18next-cli": "^1.66.2",
110
110
  "jsdom": "^29.1.1",
111
- "rolldown": "1.1.5",
111
+ "rolldown": "1.2.0",
112
112
  "typescript": "^6.0.3",
113
113
  "vitest": "^4.1.10",
114
114
  "vitest-axe": "^0.1.0",
@@ -150,6 +150,10 @@
150
150
  "types": "./lib/widgets/index.d.ts",
151
151
  "default": "./lib/widgets/index.js"
152
152
  },
153
+ "./rich-text": {
154
+ "types": "./lib/rich-text/index.d.ts",
155
+ "default": "./lib/rich-text/index.js"
156
+ },
153
157
  "./code": {
154
158
  "types": "./lib/code/index.d.ts",
155
159
  "default": "./lib/code/index.js"
@@ -180,7 +184,7 @@
180
184
  "url": "https://github.com/vertesia/composableai.git",
181
185
  "directory": "packages/ui"
182
186
  },
183
- "gitHead": "203c30e5a8ddc583ac9f1acce0f5445eb38a9551",
187
+ "gitHead": "87ac9166db2b38bd1be6e37adf0414ea83e402ee",
184
188
  "scripts": {
185
189
  "clean:lib": "rimraf ./lib ./tsconfig.tsbuildinfo",
186
190
  "clean": "rimraf ./node_modules ./lib ./tsconfig.tsbuildinfo",
@@ -320,7 +320,10 @@ describe('@vertesia/ui accessibility (axe)', () => {
320
320
  const { baseElement } = renderWithProviders(<Harness />);
321
321
  // Radix portals the dialog into document.body, not the render container.
322
322
  // noCloseButton avoids the Button.alt -> aria-label gap (deferred to Section 3).
323
- expect(await axe(baseElement)).toHaveNoViolations();
323
+ // Radix focus guards are intentionally focusable, visually hidden sentinels. Newer
324
+ // axe-core versions flag their tabindex + aria-hidden combination even though they
325
+ // are infrastructure outside the dialog's accessible content.
326
+ expect(await axe(baseElement, { exclude: ['[data-radix-focus-guard]'] })).toHaveNoViolations();
324
327
  });
325
328
 
326
329
  it('Table with column headers and sortable button has no violations', async () => {
@@ -1,6 +1,17 @@
1
- import type { AxeResults } from 'axe-core';
1
+ import axeCore, { type AxeResults, type RunOptions } from 'axe-core';
2
2
  import { axe as baseAxe } from 'vitest-axe';
3
3
 
4
+ const RUN_OPTIONS: RunOptions = {
5
+ rules: {
6
+ 'color-contrast': { enabled: false },
7
+ },
8
+ };
9
+
10
+ export interface AxeTestOptions {
11
+ /** Selectors to omit from this specific axe run while testing the rest of the container. */
12
+ exclude?: string[];
13
+ }
14
+
4
15
  /**
5
16
  * Project-wide axe runner.
6
17
  *
@@ -14,10 +25,9 @@ import { axe as baseAxe } from 'vitest-axe';
14
25
  * Lives in a `.ts` file (not `.tsx`) to keep its module init free of React/JSX
15
26
  * resolution concerns.
16
27
  */
17
- export function axe(container: Element | string): Promise<AxeResults> {
18
- return baseAxe(container, {
19
- rules: {
20
- 'color-contrast': { enabled: false },
21
- },
22
- });
28
+ export function axe(container: Element | string, options: AxeTestOptions = {}): Promise<AxeResults> {
29
+ if (options.exclude?.length && typeof container !== 'string') {
30
+ return axeCore.run({ include: [container], exclude: options.exclude }, RUN_OPTIONS);
31
+ }
32
+ return baseAxe(container, RUN_OPTIONS);
23
33
  }
@@ -72,3 +72,28 @@ if (typeof globalThis.ResizeObserver === 'undefined') {
72
72
  (globalThis as unknown as { ResizeObserver: typeof ResizeObserverPolyfill }).ResizeObserver =
73
73
  ResizeObserverPolyfill;
74
74
  }
75
+
76
+ // Chart and Mermaid modules probe canvas support during import. jsdom's default
77
+ // implementation only logs a noisy "not implemented" error, so return the same
78
+ // unsupported value without polluting otherwise successful UI test output.
79
+ if (typeof HTMLCanvasElement !== 'undefined') {
80
+ Object.defineProperty(HTMLCanvasElement.prototype, 'getContext', {
81
+ configurable: true,
82
+ value: () => null,
83
+ });
84
+ }
85
+
86
+ // ProseMirror asks the browser for caret geometry during pointer/keyboard input.
87
+ // jsdom has no layout engine, so provide stable empty geometry for interaction tests.
88
+ if (typeof document !== 'undefined' && typeof document.elementFromPoint !== 'function') {
89
+ document.elementFromPoint = () => document.querySelector('.ProseMirror') ?? document.body;
90
+ }
91
+ if (typeof Range !== 'undefined') {
92
+ const emptyRect = () => new DOMRect(0, 0, 0, 0);
93
+ if (typeof Range.prototype.getBoundingClientRect !== 'function') {
94
+ Range.prototype.getBoundingClientRect = emptyRect;
95
+ }
96
+ if (typeof Range.prototype.getClientRects !== 'function') {
97
+ Range.prototype.getClientRects = () => [] as unknown as DOMRectList;
98
+ }
99
+ }
@@ -318,6 +318,7 @@ const FilterBtn = ({ className }: { className?: string }) => {
318
318
  variant="outline"
319
319
  role="combobox"
320
320
  aria-expanded={open}
321
+ aria-label={t('filter.filter')}
321
322
  size="md"
322
323
  className={cn('transition group flex gap-1.5', className)}
323
324
  >
@@ -16,7 +16,7 @@ interface ModalProps {
16
16
  className?: string;
17
17
  allowOverflow?: boolean;
18
18
  disableCloseOnClickOutside?: boolean;
19
- size?: 'sm' | 'md' | 'lg' | 'xl';
19
+ size?: 'sm' | 'md' | 'lg' | 'xl' | 'full';
20
20
  action?: React.ReactNode;
21
21
  }
22
22
  const ModalContext = createContext<boolean>(false);
@@ -54,6 +54,8 @@ export function Modal({
54
54
  return 'max-w-[80vw] md:max-w-[60vw]';
55
55
  case 'xl':
56
56
  return 'max-w-[95vw] lg:max-w-[80vw]';
57
+ case 'full':
58
+ return 'h-[calc(100vh-2rem)] max-w-[calc(100vw-2rem)]';
57
59
  default:
58
60
  return 'max-w-[60vw] lg:max-w-[40vw]';
59
61
  }
@@ -0,0 +1,65 @@
1
+ import { fireEvent, render, screen } from '@testing-library/react';
2
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
3
+ import { Tabs, TabsBar, TabsPanel } from './tabs';
4
+
5
+ const TABS = [
6
+ { name: 'first', label: 'First', href: '#first', content: <div>First panel</div> },
7
+ { name: 'second', label: 'Second', href: '#second', content: <div>Second panel</div> },
8
+ ];
9
+
10
+ function renderTabs(canChangeTab?: (nextTab: string, currentTab?: string) => boolean) {
11
+ return render(
12
+ <Tabs tabs={TABS} defaultValue="first" canChangeTab={canChangeTab}>
13
+ <TabsBar />
14
+ <TabsPanel />
15
+ </Tabs>,
16
+ );
17
+ }
18
+
19
+ describe('Tabs canChangeTab', () => {
20
+ beforeEach(() => {
21
+ window.history.replaceState(null, '', '/');
22
+ });
23
+
24
+ it('cancels the switch and leaves the hash alone when the guard returns false', () => {
25
+ const canChangeTab = vi.fn().mockReturnValue(false);
26
+ renderTabs(canChangeTab);
27
+
28
+ fireEvent.click(screen.getByRole('tab', { name: 'Second' }));
29
+
30
+ expect(canChangeTab).toHaveBeenCalledWith('second', 'first');
31
+ expect(screen.getByText('First panel')).toBeDefined();
32
+ expect(screen.queryByText('Second panel')).toBeNull();
33
+ expect(window.location.hash).toBe('');
34
+ });
35
+
36
+ it('allows the switch when the guard returns true', () => {
37
+ const canChangeTab = vi.fn().mockReturnValue(true);
38
+ renderTabs(canChangeTab);
39
+
40
+ fireEvent.click(screen.getByRole('tab', { name: 'Second' }));
41
+
42
+ expect(screen.getByText('Second panel')).toBeDefined();
43
+ expect(window.location.hash).toBe('#second');
44
+ });
45
+
46
+ it('does not consult the guard when the active tab is clicked again', () => {
47
+ const canChangeTab = vi.fn().mockReturnValue(false);
48
+ renderTabs(canChangeTab);
49
+
50
+ fireEvent.click(screen.getByRole('tab', { name: 'First' }));
51
+
52
+ expect(canChangeTab).not.toHaveBeenCalled();
53
+ expect(screen.getByText('First panel')).toBeDefined();
54
+ });
55
+
56
+ it('still switches from a hash change so a cancelled switch can be resumed', () => {
57
+ const canChangeTab = vi.fn().mockReturnValue(false);
58
+ renderTabs(canChangeTab);
59
+
60
+ window.location.hash = 'second';
61
+ fireEvent(window, new HashChangeEvent('hashchange'));
62
+
63
+ expect(screen.getByText('Second panel')).toBeDefined();
64
+ });
65
+ });
@@ -15,6 +15,17 @@ export interface Tab {
15
15
  is_allowed?: boolean;
16
16
  }
17
17
 
18
+ /**
19
+ * Guard consulted before switching to another tab. Return `false` to cancel the switch — the active
20
+ * tab, the URL hash and the browser history are all left untouched, so the guard can hold the user
21
+ * on a tab that has unsaved changes while a confirmation is shown.
22
+ *
23
+ * It is only called when the target tab differs from the active one, but it may be called more than
24
+ * once for a single attempted switch (a click reaches both the trigger and the Radix root), so any
25
+ * side effect it performs must be idempotent.
26
+ */
27
+ export type CanChangeTab = (nextTab: string, currentTab?: string) => boolean;
28
+
18
29
  const TabsContext = React.createContext<{
19
30
  size?: number;
20
31
  tabs?: Tab[];
@@ -23,6 +34,7 @@ const TabsContext = React.createContext<{
23
34
  responsive?: boolean;
24
35
  variant?: 'tabs' | 'pills';
25
36
  updateHash?: boolean;
37
+ canChangeTab?: CanChangeTab;
26
38
  }>({
27
39
  size: undefined,
28
40
  tabs: undefined,
@@ -45,6 +57,7 @@ interface TabsProps {
45
57
  responsive?: boolean;
46
58
  variant?: 'tabs' | 'pills';
47
59
  updateHash?: boolean;
60
+ canChangeTab?: CanChangeTab;
48
61
  }
49
62
 
50
63
  const Tabs = ({
@@ -59,6 +72,7 @@ const Tabs = ({
59
72
  responsive = false,
60
73
  variant = 'tabs',
61
74
  updateHash = true,
75
+ canChangeTab,
62
76
  }: TabsProps) => {
63
77
  // Filter tabs based on is_allowed (undefined or true means visible)
64
78
  const visibleTabs = React.useMemo(
@@ -121,6 +135,9 @@ const Tabs = ({
121
135
 
122
136
  const handleValueChange = React.useCallback(
123
137
  (newValue: string) => {
138
+ // Bail before touching the value or the history so a cancelled switch is a no-op.
139
+ if (newValue !== value && canChangeTab && !canChangeTab(newValue, value)) return;
140
+
124
141
  setValue(newValue);
125
142
 
126
143
  // Update the URL hash when tab changes (only if updateHash is true and not controlled by parent)
@@ -135,7 +152,7 @@ const Tabs = ({
135
152
  onTabChange(newValue);
136
153
  }
137
154
  },
138
- [current, onTabChange, updateHash],
155
+ [current, onTabChange, updateHash, canChangeTab, value],
139
156
  );
140
157
 
141
158
  const setTab = React.useCallback(
@@ -155,6 +172,7 @@ const Tabs = ({
155
172
  responsive: responsive,
156
173
  variant,
157
174
  updateHash,
175
+ canChangeTab,
158
176
  }}
159
177
  >
160
178
  <TabsPrimitive.Root
@@ -176,13 +194,17 @@ interface TabsBarProps {
176
194
  }
177
195
 
178
196
  const TabsBar = ({ className, sticky, direction }: TabsBarProps) => {
179
- const { tabs, size, current, setTab, responsive, variant, updateHash } = React.useContext(TabsContext);
197
+ const { tabs, size, current, setTab, responsive, variant, updateHash, canChangeTab } =
198
+ React.useContext(TabsContext);
180
199
 
181
200
  const fullWidth = size !== 0;
182
201
 
183
202
  const handleTabChange = React.useCallback(
184
203
  (tabName: string) => {
185
204
  if (!tabs || !setTab) return;
205
+ // Consulted here too: this path pushes the tab href before `setTab` reaches the guard in
206
+ // `Tabs`, so a cancelled switch would otherwise leave the URL pointing at the other tab.
207
+ if (tabName !== current && canChangeTab && !canChangeTab(tabName, current)) return;
186
208
 
187
209
  const tab = tabs.find((t) => t.name === tabName);
188
210
 
@@ -194,7 +216,7 @@ const TabsBar = ({ className, sticky, direction }: TabsBarProps) => {
194
216
 
195
217
  setTab(tabName);
196
218
  },
197
- [tabs, setTab, updateHash],
219
+ [tabs, setTab, updateHash, canChangeTab, current],
198
220
  );
199
221
 
200
222
  if (!tabs || !setTab) {
@@ -0,0 +1,139 @@
1
+ import { act, render } from '@testing-library/react';
2
+ import { useRef, useState } from 'react';
3
+ import { beforeAll, describe, expect, it, vi } from 'vitest';
4
+ import { type ScrollableSearchResult, useDefaultScrollableSearch } from './useScrollableSearch';
5
+
6
+ beforeAll(() => {
7
+ // jsdom has no IntersectionObserver; the hook only needs it constructible.
8
+ vi.stubGlobal(
9
+ 'IntersectionObserver',
10
+ class {
11
+ observe() {}
12
+ unobserve() {}
13
+ disconnect() {}
14
+ },
15
+ );
16
+ });
17
+
18
+ /**
19
+ * Regression tests for the infinite request loop: callers pass an INLINE search
20
+ * closure (new identity every render). The fetch effect must not depend on that
21
+ * identity, otherwise every completed request re-triggers the effect forever.
22
+ */
23
+
24
+ type Item = { id: number };
25
+
26
+ function flush(): Promise<void> {
27
+ // Drain the microtask queue so pending search promises settle.
28
+ return act(() => Promise.resolve());
29
+ }
30
+
31
+ function Harness({
32
+ searchFn,
33
+ onApi,
34
+ }: {
35
+ searchFn: (payload: unknown, offset: number, limit: number) => Promise<Item[]>;
36
+ onApi: (api: ScrollableSearchResult<Item, unknown, number>) => void;
37
+ }) {
38
+ const loadMoreRef = useRef<HTMLDivElement>(null);
39
+ // Unrelated state to force extra re-renders, as a real page would.
40
+ const [, setTick] = useState(0);
41
+ const api = useDefaultScrollableSearch<Item, unknown>({
42
+ // Inline closure ON PURPOSE — new identity on every render, like real callers.
43
+ async search(payload, offset, limit) {
44
+ return searchFn(payload, offset, limit);
45
+ },
46
+ pageSize: 2,
47
+ nextPageTrigger: loadMoreRef,
48
+ payload: {},
49
+ });
50
+ onApi(api);
51
+ return (
52
+ <div>
53
+ <button type="button" data-testid="rerender" onClick={() => setTick((t) => t + 1)} />
54
+ <div ref={loadMoreRef} />
55
+ </div>
56
+ );
57
+ }
58
+
59
+ function setup(searchFn: (payload: unknown, offset: number, limit: number) => Promise<Item[]>) {
60
+ let api!: ScrollableSearchResult<Item, unknown, number>;
61
+ const utils = render(
62
+ <Harness
63
+ searchFn={searchFn}
64
+ onApi={(a) => {
65
+ api = a;
66
+ }}
67
+ />,
68
+ );
69
+ return { ...utils, getApi: () => api };
70
+ }
71
+
72
+ describe('useDefaultScrollableSearch', () => {
73
+ it('fetches exactly once on mount despite inline search closures and re-renders', async () => {
74
+ const searchFn = vi.fn(async () => [{ id: 1 }, { id: 2 }]);
75
+ const { getApi } = setup(searchFn);
76
+
77
+ await flush();
78
+ expect(searchFn).toHaveBeenCalledTimes(1);
79
+ expect(getApi().result).toEqual([{ id: 1 }, { id: 2 }]);
80
+
81
+ // Extra render cycles (state updates elsewhere on the page) must NOT re-fetch.
82
+ await flush();
83
+ await flush();
84
+ expect(searchFn).toHaveBeenCalledTimes(1);
85
+ });
86
+
87
+ it('searchMore appends the next page (single extra request)', async () => {
88
+ const pages: Item[][] = [[{ id: 1 }, { id: 2 }], [{ id: 3 }]];
89
+ const searchFn = vi.fn(async (_p: unknown, offset: number) => pages[offset / 2] ?? []);
90
+ const { getApi } = setup(searchFn);
91
+ await flush();
92
+
93
+ act(() => getApi().searchMore());
94
+ await flush();
95
+
96
+ expect(searchFn).toHaveBeenCalledTimes(2);
97
+ expect(getApi().result).toEqual([{ id: 1 }, { id: 2 }, { id: 3 }]);
98
+ // Page of 1 < pageSize still probes once more only when triggered — no auto loop.
99
+ await flush();
100
+ expect(searchFn).toHaveBeenCalledTimes(2);
101
+ });
102
+
103
+ it('refresh() re-fetches even on the first page (same payload, same page)', async () => {
104
+ const searchFn = vi.fn(async () => [{ id: 1 }]);
105
+ const { getApi } = setup(searchFn);
106
+ await flush();
107
+ expect(searchFn).toHaveBeenCalledTimes(1);
108
+
109
+ act(() => getApi().refresh());
110
+ await flush();
111
+ expect(searchFn).toHaveBeenCalledTimes(2);
112
+ });
113
+
114
+ it('empty result stops pagination (hasMore=false) and does not re-fetch', async () => {
115
+ const searchFn = vi.fn(async () => []);
116
+ const { getApi } = setup(searchFn);
117
+ await flush();
118
+
119
+ expect(searchFn).toHaveBeenCalledTimes(1);
120
+ expect(getApi().hasMore).toBe(false);
121
+
122
+ act(() => getApi().searchMore());
123
+ await flush();
124
+ // nextPage is null — searchMore is a no-op.
125
+ expect(searchFn).toHaveBeenCalledTimes(1);
126
+ });
127
+
128
+ it('a failing search sets error once and does not retry in a loop', async () => {
129
+ const searchFn = vi.fn(async () => {
130
+ throw new Error('boom');
131
+ });
132
+ const { getApi } = setup(searchFn);
133
+ await flush();
134
+ await flush();
135
+
136
+ expect(getApi().error?.message).toBe('boom');
137
+ expect(searchFn).toHaveBeenCalledTimes(1);
138
+ });
139
+ });
@@ -48,7 +48,7 @@ interface ScrollableSearchOptions<ResultT, PayloadT, PageT = number> {
48
48
  nextPageTrigger: React.RefObject<HTMLElement | null>;
49
49
  }
50
50
 
51
- interface ScrollableSearchResult<ResultT, PayloadT, PageT = number> {
51
+ export interface ScrollableSearchResult<ResultT, PayloadT, PageT = number> {
52
52
  /**
53
53
  * Initiates a new search with the given payload
54
54
  * @param payload The search payload
@@ -105,15 +105,27 @@ export function useScrollableSearch<ResultT, PayloadT, PageT = number>(
105
105
  const [results, setResults] = useState<ResultT[]>([]);
106
106
  const [nextPage, setNextPage] = useState<PageT | null>(null);
107
107
  const [isSearching, setIsSearching] = useState(false);
108
+ // Bumped by search()/refresh() so the fetch effect re-runs even when the
109
+ // payload/page state is unchanged (e.g. refresh on the first page).
110
+ const [refreshTick, setRefreshTick] = useState(0);
108
111
 
109
112
  // Track current request to prevent stale results
110
113
  const requestIdRef = useRef(0);
111
114
 
115
+ // Latest-ref for the search function: callers routinely pass an inline
116
+ // closure, which gets a new identity on every render. Depending on it in
117
+ // the fetch effect made every completed request re-trigger the effect —
118
+ // an infinite request loop. The ref always points at the latest closure
119
+ // without participating in the effect's dependencies.
120
+ const searchFnRef = useRef(opts.search);
121
+ searchFnRef.current = opts.search;
122
+
112
123
  const search = (payload: PayloadT) => {
113
124
  setPage(null);
114
125
  setResults([]); // Clear old results immediately
115
126
  setNextPage(null);
116
127
  setLastPayload(payload);
128
+ setRefreshTick((tick) => tick + 1);
117
129
  };
118
130
 
119
131
  const searchMore = () => {
@@ -122,13 +134,15 @@ export function useScrollableSearch<ResultT, PayloadT, PageT = number>(
122
134
  }
123
135
  };
124
136
 
137
+ // biome-ignore lint/correctness/useExhaustiveDependencies: refreshTick is an intentional external trigger — refresh() bumps it to re-run the fetch when payload/page are unchanged
125
138
  useEffect(() => {
126
139
  // Increment request ID to mark previous requests as stale
127
140
  requestIdRef.current += 1;
128
141
  const currentRequestId = requestIdRef.current;
129
142
 
130
143
  setIsSearching(true);
131
- opts.search(lastPayload, page, pageSize)
144
+ searchFnRef
145
+ .current(lastPayload, page, pageSize)
132
146
  .then((r) => {
133
147
  // Only update state if this is still the current request
134
148
  if (currentRequestId !== requestIdRef.current) {
@@ -158,7 +172,7 @@ export function useScrollableSearch<ResultT, PayloadT, PageT = number>(
158
172
  setIsSearching(false);
159
173
  }
160
174
  });
161
- }, [...dependencies, lastPayload, opts.search, page, pageSize]);
175
+ }, [...dependencies, lastPayload, refreshTick, page, pageSize]);
162
176
 
163
177
  // Intersection observer for infinite scrolling
164
178
  useIntersectionObserver(
package/src/env/index.ts CHANGED
@@ -17,6 +17,8 @@ export interface EnvProps {
17
17
  sts: string; // Security Token Service endpoint
18
18
  git?: string; // Smart HTTP app source git endpoint
19
19
  mcp?: string;
20
+ /** Appgen app-gateway endpoint (serves live development previews and app bundles). */
21
+ gateway?: string;
20
22
  };
21
23
  firebase?: {
22
24
  apiKey: string;
@@ -24,6 +24,8 @@ describe('AgentChatPlaybackControls', () => {
24
24
  <AgentChatPlaybackControls cursor="live" messages={messages} onChangeCursor={onChangeCursor} />,
25
25
  );
26
26
 
27
+ expect(screen.getByText('Debug')).toBeTruthy();
28
+
27
29
  fireEvent.click(screen.getByRole('button', { name: 'Jump to first message' }));
28
30
 
29
31
  expect(onChangeCursor).toHaveBeenCalledWith(0);