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

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 (307) 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/features/agent/chat/AgentRightPanel.d.ts +5 -1
  13. package/lib/features/agent/chat/AgentRightPanel.d.ts.map +1 -1
  14. package/lib/features/agent/chat/AgentRightPanel.js +2 -2
  15. package/lib/features/agent/chat/AgentRightPanel.js.map +1 -1
  16. package/lib/features/agent/chat/ArtifactsTab.d.ts +5 -1
  17. package/lib/features/agent/chat/ArtifactsTab.d.ts.map +1 -1
  18. package/lib/features/agent/chat/ArtifactsTab.js +48 -11
  19. package/lib/features/agent/chat/ArtifactsTab.js.map +1 -1
  20. package/lib/features/agent/chat/DocumentEditingActionCard.d.ts +6 -0
  21. package/lib/features/agent/chat/DocumentEditingActionCard.d.ts.map +1 -0
  22. package/lib/features/agent/chat/DocumentEditingActionCard.js +129 -0
  23. package/lib/features/agent/chat/DocumentEditingActionCard.js.map +1 -0
  24. package/lib/features/agent/chat/ModernAgentConversation.d.ts +19 -1
  25. package/lib/features/agent/chat/ModernAgentConversation.d.ts.map +1 -1
  26. package/lib/features/agent/chat/ModernAgentConversation.js +125 -27
  27. package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
  28. package/lib/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.d.ts +45 -0
  29. package/lib/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.d.ts.map +1 -0
  30. package/lib/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.js +40 -0
  31. package/lib/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.js.map +1 -0
  32. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts +3 -1
  33. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
  34. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +94 -49
  35. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
  36. package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.d.ts +2 -1
  37. package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.d.ts.map +1 -1
  38. package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.js +9 -5
  39. package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.js.map +1 -1
  40. package/lib/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.d.ts +25 -0
  41. package/lib/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.d.ts.map +1 -0
  42. package/lib/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.js +33 -0
  43. package/lib/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.js.map +1 -0
  44. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts +3 -1
  45. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts.map +1 -1
  46. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js +22 -24
  47. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
  48. package/lib/features/agent/chat/ModernAgentOutput/ResourceChangeSummary.d.ts +14 -0
  49. package/lib/features/agent/chat/ModernAgentOutput/ResourceChangeSummary.d.ts.map +1 -0
  50. package/lib/features/agent/chat/ModernAgentOutput/ResourceChangeSummary.js +21 -0
  51. package/lib/features/agent/chat/ModernAgentOutput/ResourceChangeSummary.js.map +1 -0
  52. package/lib/features/agent/chat/ModernAgentOutput/ResourceChip.d.ts +30 -0
  53. package/lib/features/agent/chat/ModernAgentOutput/ResourceChip.d.ts.map +1 -0
  54. package/lib/features/agent/chat/ModernAgentOutput/ResourceChip.js +53 -0
  55. package/lib/features/agent/chat/ModernAgentOutput/ResourceChip.js.map +1 -0
  56. package/lib/features/agent/chat/ModernAgentOutput/ToolCallGroup.d.ts.map +1 -1
  57. package/lib/features/agent/chat/ModernAgentOutput/ToolCallGroup.js +21 -2
  58. package/lib/features/agent/chat/ModernAgentOutput/ToolCallGroup.js.map +1 -1
  59. package/lib/features/agent/chat/ModernAgentOutput/resourceLinks.d.ts +6 -0
  60. package/lib/features/agent/chat/ModernAgentOutput/resourceLinks.d.ts.map +1 -0
  61. package/lib/features/agent/chat/ModernAgentOutput/resourceLinks.js +29 -0
  62. package/lib/features/agent/chat/ModernAgentOutput/resourceLinks.js.map +1 -0
  63. package/lib/features/agent/chat/ModernAgentOutput/resourceSummary.d.ts +33 -0
  64. package/lib/features/agent/chat/ModernAgentOutput/resourceSummary.d.ts.map +1 -0
  65. package/lib/features/agent/chat/ModernAgentOutput/resourceSummary.js +129 -0
  66. package/lib/features/agent/chat/ModernAgentOutput/resourceSummary.js.map +1 -0
  67. package/lib/features/agent/chat/ModernAgentOutput/utils.d.ts +7 -0
  68. package/lib/features/agent/chat/ModernAgentOutput/utils.d.ts.map +1 -1
  69. package/lib/features/agent/chat/ModernAgentOutput/utils.js +11 -1
  70. package/lib/features/agent/chat/ModernAgentOutput/utils.js.map +1 -1
  71. package/lib/features/agent/chat/hooks/useAgentStream.d.ts +1 -1
  72. package/lib/features/agent/chat/hooks/useAgentStream.d.ts.map +1 -1
  73. package/lib/features/agent/chat/hooks/useAgentStream.js +24 -9
  74. package/lib/features/agent/chat/hooks/useAgentStream.js.map +1 -1
  75. package/lib/features/agent/chat/index.d.ts +2 -1
  76. package/lib/features/agent/chat/index.d.ts.map +1 -1
  77. package/lib/features/agent/chat/index.js +3 -0
  78. package/lib/features/agent/chat/index.js.map +1 -1
  79. package/lib/features/store/objects/DocumentSearchResults.js +2 -2
  80. package/lib/features/store/objects/DocumentSearchResults.js.map +1 -1
  81. package/lib/features/store/objects/components/ContentOverview.d.ts +2 -1
  82. package/lib/features/store/objects/components/ContentOverview.d.ts.map +1 -1
  83. package/lib/features/store/objects/components/ContentOverview.js +86 -15
  84. package/lib/features/store/objects/components/ContentOverview.js.map +1 -1
  85. package/lib/features/store/objects/components/DocumentEditingConfigurationSelector.d.ts +16 -0
  86. package/lib/features/store/objects/components/DocumentEditingConfigurationSelector.d.ts.map +1 -0
  87. package/lib/features/store/objects/components/DocumentEditingConfigurationSelector.js +116 -0
  88. package/lib/features/store/objects/components/DocumentEditingConfigurationSelector.js.map +1 -0
  89. package/lib/features/store/objects/components/DocumentEditingLockStatus.d.ts +7 -0
  90. package/lib/features/store/objects/components/DocumentEditingLockStatus.d.ts.map +1 -0
  91. package/lib/features/store/objects/components/DocumentEditingLockStatus.js +13 -0
  92. package/lib/features/store/objects/components/DocumentEditingLockStatus.js.map +1 -0
  93. package/lib/features/store/objects/components/DocumentEditingPanel.d.ts +48 -0
  94. package/lib/features/store/objects/components/DocumentEditingPanel.d.ts.map +1 -0
  95. package/lib/features/store/objects/components/DocumentEditingPanel.js +720 -0
  96. package/lib/features/store/objects/components/DocumentEditingPanel.js.map +1 -0
  97. package/lib/features/store/objects/components/TextEditorPanel.d.ts.map +1 -1
  98. package/lib/features/store/objects/components/TextEditorPanel.js +22 -9
  99. package/lib/features/store/objects/components/TextEditorPanel.js.map +1 -1
  100. package/lib/features/store/objects/components/documentArtifactRefs.d.ts +26 -0
  101. package/lib/features/store/objects/components/documentArtifactRefs.d.ts.map +1 -0
  102. package/lib/features/store/objects/components/documentArtifactRefs.js +52 -0
  103. package/lib/features/store/objects/components/documentArtifactRefs.js.map +1 -0
  104. package/lib/features/store/objects/components/documentEditingAgentConfig.d.ts +4 -0
  105. package/lib/features/store/objects/components/documentEditingAgentConfig.d.ts.map +1 -0
  106. package/lib/features/store/objects/components/documentEditingAgentConfig.js +40 -0
  107. package/lib/features/store/objects/components/documentEditingAgentConfig.js.map +1 -0
  108. package/lib/features/store/objects/components/documentEditingPrompts.d.ts +3 -0
  109. package/lib/features/store/objects/components/documentEditingPrompts.d.ts.map +1 -0
  110. package/lib/features/store/objects/components/documentEditingPrompts.js +13 -0
  111. package/lib/features/store/objects/components/documentEditingPrompts.js.map +1 -0
  112. package/lib/features/store/objects/components/documentEditingRun.d.ts +27 -0
  113. package/lib/features/store/objects/components/documentEditingRun.d.ts.map +1 -0
  114. package/lib/features/store/objects/components/documentEditingRun.js +126 -0
  115. package/lib/features/store/objects/components/documentEditingRun.js.map +1 -0
  116. package/lib/features/store/objects/components/documentEditingTarget.d.ts +20 -0
  117. package/lib/features/store/objects/components/documentEditingTarget.d.ts.map +1 -0
  118. package/lib/features/store/objects/components/documentEditingTarget.js +40 -0
  119. package/lib/features/store/objects/components/documentEditingTarget.js.map +1 -0
  120. package/lib/features/store/objects/components/index.d.ts +1 -0
  121. package/lib/features/store/objects/components/index.d.ts.map +1 -1
  122. package/lib/features/store/objects/components/index.js +1 -0
  123. package/lib/features/store/objects/components/index.js.map +1 -1
  124. package/lib/features/store/objects/components/useContentPanelHooks.d.ts +5 -1
  125. package/lib/features/store/objects/components/useContentPanelHooks.d.ts.map +1 -1
  126. package/lib/features/store/objects/components/useContentPanelHooks.js +53 -29
  127. package/lib/features/store/objects/components/useContentPanelHooks.js.map +1 -1
  128. package/lib/features/store/objects/components/useDownloadFile.d.ts +2 -1
  129. package/lib/features/store/objects/components/useDownloadFile.d.ts.map +1 -1
  130. package/lib/features/store/objects/components/useDownloadFile.js +3 -0
  131. package/lib/features/store/objects/components/useDownloadFile.js.map +1 -1
  132. package/lib/features/store/objects/selection/actions/StartWorkflowButton.js +1 -1
  133. package/lib/features/store/objects/selection/actions/StartWorkflowButton.js.map +1 -1
  134. package/lib/i18n/locales/ar.json +118 -1
  135. package/lib/i18n/locales/de.json +118 -1
  136. package/lib/i18n/locales/en.json +118 -0
  137. package/lib/i18n/locales/es.json +118 -1
  138. package/lib/i18n/locales/fr.json +118 -1
  139. package/lib/i18n/locales/it.json +118 -1
  140. package/lib/i18n/locales/ja.json +118 -1
  141. package/lib/i18n/locales/ko.json +118 -1
  142. package/lib/i18n/locales/pt.json +118 -1
  143. package/lib/i18n/locales/ru.json +118 -1
  144. package/lib/i18n/locales/tr.json +118 -1
  145. package/lib/i18n/locales/zh-TW.json +118 -1
  146. package/lib/i18n/locales/zh.json +118 -1
  147. package/lib/rich-text/EditorToolbar.d.ts +37 -0
  148. package/lib/rich-text/EditorToolbar.d.ts.map +1 -0
  149. package/lib/rich-text/EditorToolbar.js +215 -0
  150. package/lib/rich-text/EditorToolbar.js.map +1 -0
  151. package/lib/rich-text/VertesiaRichTextEditor.d.ts +26 -0
  152. package/lib/rich-text/VertesiaRichTextEditor.d.ts.map +1 -0
  153. package/lib/rich-text/VertesiaRichTextEditor.js +67 -0
  154. package/lib/rich-text/VertesiaRichTextEditor.js.map +1 -0
  155. package/lib/rich-text/index.d.ts +2 -0
  156. package/lib/rich-text/index.d.ts.map +1 -0
  157. package/lib/rich-text/index.js +2 -0
  158. package/lib/rich-text/index.js.map +1 -0
  159. package/lib/vertesia-ui-core.js +2 -2
  160. package/lib/vertesia-ui-core.js.map +1 -1
  161. package/lib/vertesia-ui-features.js +35 -30
  162. package/lib/vertesia-ui-features.js.map +1 -1
  163. package/lib/vertesia-ui-i18n.js +14 -14
  164. package/lib/vertesia-ui-i18n.js.map +1 -1
  165. package/lib/vertesia-ui-rich-text.js +5 -0
  166. package/lib/vertesia-ui-rich-text.js.map +1 -0
  167. package/lib/vertesia-ui-widgets.js +25 -7
  168. package/lib/vertesia-ui-widgets.js.map +1 -1
  169. package/lib/widgets/markdown/AgentResourceResolver.d.ts +31 -0
  170. package/lib/widgets/markdown/AgentResourceResolver.d.ts.map +1 -0
  171. package/lib/widgets/markdown/AgentResourceResolver.js +39 -0
  172. package/lib/widgets/markdown/AgentResourceResolver.js.map +1 -0
  173. package/lib/widgets/markdown/ArtifactEditingSurface.d.ts +63 -0
  174. package/lib/widgets/markdown/ArtifactEditingSurface.d.ts.map +1 -0
  175. package/lib/widgets/markdown/ArtifactEditingSurface.js +582 -0
  176. package/lib/widgets/markdown/ArtifactEditingSurface.js.map +1 -0
  177. package/lib/widgets/markdown/CollaborativeMarkdownRenderer.d.ts +69 -0
  178. package/lib/widgets/markdown/CollaborativeMarkdownRenderer.d.ts.map +1 -0
  179. package/lib/widgets/markdown/CollaborativeMarkdownRenderer.js +374 -0
  180. package/lib/widgets/markdown/CollaborativeMarkdownRenderer.js.map +1 -0
  181. package/lib/widgets/markdown/MarkdownLink.d.ts +3 -1
  182. package/lib/widgets/markdown/MarkdownLink.d.ts.map +1 -1
  183. package/lib/widgets/markdown/MarkdownLink.js +41 -14
  184. package/lib/widgets/markdown/MarkdownLink.js.map +1 -1
  185. package/lib/widgets/markdown/MarkdownRenderer.d.ts +8 -1
  186. package/lib/widgets/markdown/MarkdownRenderer.d.ts.map +1 -1
  187. package/lib/widgets/markdown/MarkdownRenderer.js +20 -4
  188. package/lib/widgets/markdown/MarkdownRenderer.js.map +1 -1
  189. package/lib/widgets/markdown/index.d.ts +5 -1
  190. package/lib/widgets/markdown/index.d.ts.map +1 -1
  191. package/lib/widgets/markdown/index.js +5 -1
  192. package/lib/widgets/markdown/index.js.map +1 -1
  193. package/lib/widgets/markdown/normalizeCustomSchemeLinks.d.ts.map +1 -1
  194. package/lib/widgets/markdown/normalizeCustomSchemeLinks.js +14 -2
  195. package/lib/widgets/markdown/normalizeCustomSchemeLinks.js.map +1 -1
  196. package/lib/widgets/markdown/textDiff.d.ts +52 -0
  197. package/lib/widgets/markdown/textDiff.d.ts.map +1 -0
  198. package/lib/widgets/markdown/textDiff.js +362 -0
  199. package/lib/widgets/markdown/textDiff.js.map +1 -0
  200. package/lib/widgets/markdown/useArtifactContent.d.ts +5 -3
  201. package/lib/widgets/markdown/useArtifactContent.d.ts.map +1 -1
  202. package/lib/widgets/markdown/useArtifactContent.js +6 -3
  203. package/lib/widgets/markdown/useArtifactContent.js.map +1 -1
  204. package/lib/widgets/markdown/useResolvedUrl.d.ts +1 -5
  205. package/lib/widgets/markdown/useResolvedUrl.d.ts.map +1 -1
  206. package/lib/widgets/markdown/useResolvedUrl.js +19 -31
  207. package/lib/widgets/markdown/useResolvedUrl.js.map +1 -1
  208. package/lib/widgets/xml-viewer/hooks/useXMLViewer.d.ts +9 -0
  209. package/lib/widgets/xml-viewer/hooks/useXMLViewer.d.ts.map +1 -1
  210. package/lib/widgets/xml-viewer/hooks/useXMLViewer.js +20 -17
  211. package/lib/widgets/xml-viewer/hooks/useXMLViewer.js.map +1 -1
  212. package/package.json +13 -9
  213. package/src/__tests__/a11y.test.tsx +4 -1
  214. package/src/__tests__/axe-helper.ts +17 -7
  215. package/src/__tests__/setup.ts +25 -0
  216. package/src/core/components/shadcn/filters/filterBar.tsx +1 -0
  217. package/src/core/components/shadcn/modal/dialog.tsx +3 -1
  218. package/src/core/components/shadcn/tabs.test.tsx +65 -0
  219. package/src/core/components/shadcn/tabs.tsx +25 -3
  220. package/src/features/agent/chat/AgentRightPanel.tsx +16 -1
  221. package/src/features/agent/chat/ArtifactsTab.test.tsx +55 -0
  222. package/src/features/agent/chat/ArtifactsTab.tsx +203 -52
  223. package/src/features/agent/chat/DocumentEditingActionCard.test.tsx +105 -0
  224. package/src/features/agent/chat/DocumentEditingActionCard.tsx +210 -0
  225. package/src/features/agent/chat/ModernAgentConversation.test.tsx +237 -40
  226. package/src/features/agent/chat/ModernAgentConversation.tsx +247 -75
  227. package/src/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.test.tsx +79 -0
  228. package/src/features/agent/chat/ModernAgentOutput/AgentMarkdownAnchor.tsx +94 -0
  229. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.test.tsx +257 -34
  230. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +217 -105
  231. package/src/features/agent/chat/ModernAgentOutput/AttachmentPreview.tsx +17 -0
  232. package/src/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.test.tsx +44 -0
  233. package/src/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.tsx +88 -0
  234. package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +30 -46
  235. package/src/features/agent/chat/ModernAgentOutput/ResourceChangeSummary.tsx +40 -0
  236. package/src/features/agent/chat/ModernAgentOutput/ResourceChip.test.tsx +148 -0
  237. package/src/features/agent/chat/ModernAgentOutput/ResourceChip.tsx +141 -0
  238. package/src/features/agent/chat/ModernAgentOutput/ToolCallGroup.tsx +33 -1
  239. package/src/features/agent/chat/ModernAgentOutput/resourceLinks.tsx +43 -0
  240. package/src/features/agent/chat/ModernAgentOutput/resourceSummary.test.ts +229 -0
  241. package/src/features/agent/chat/ModernAgentOutput/resourceSummary.ts +152 -0
  242. package/src/features/agent/chat/ModernAgentOutput/utils.test.ts +17 -0
  243. package/src/features/agent/chat/ModernAgentOutput/utils.ts +14 -1
  244. package/src/features/agent/chat/hooks/useAgentStream.test.tsx +188 -0
  245. package/src/features/agent/chat/hooks/useAgentStream.ts +28 -8
  246. package/src/features/agent/chat/index.ts +11 -0
  247. package/src/features/store/objects/DocumentSearchResults.tsx +2 -2
  248. package/src/features/store/objects/components/ContentOverview.tsx +216 -65
  249. package/src/features/store/objects/components/DocumentEditingConfigurationSelector.test.ts +34 -0
  250. package/src/features/store/objects/components/DocumentEditingConfigurationSelector.tsx +211 -0
  251. package/src/features/store/objects/components/DocumentEditingLockStatus.test.tsx +32 -0
  252. package/src/features/store/objects/components/DocumentEditingLockStatus.tsx +45 -0
  253. package/src/features/store/objects/components/DocumentEditingPanel.test.tsx +336 -0
  254. package/src/features/store/objects/components/DocumentEditingPanel.tsx +1236 -0
  255. package/src/features/store/objects/components/TextEditorPanel.test.tsx +48 -0
  256. package/src/features/store/objects/components/TextEditorPanel.tsx +41 -20
  257. package/src/features/store/objects/components/documentArtifactRefs.test.ts +65 -0
  258. package/src/features/store/objects/components/documentArtifactRefs.ts +72 -0
  259. package/src/features/store/objects/components/documentEditingAgentConfig.test.ts +28 -0
  260. package/src/features/store/objects/components/documentEditingAgentConfig.ts +41 -0
  261. package/src/features/store/objects/components/documentEditingPrompts.test.ts +26 -0
  262. package/src/features/store/objects/components/documentEditingPrompts.ts +12 -0
  263. package/src/features/store/objects/components/documentEditingRun.test.ts +176 -0
  264. package/src/features/store/objects/components/documentEditingRun.ts +184 -0
  265. package/src/features/store/objects/components/documentEditingTarget.test.ts +96 -0
  266. package/src/features/store/objects/components/documentEditingTarget.ts +63 -0
  267. package/src/features/store/objects/components/index.ts +1 -0
  268. package/src/features/store/objects/components/useContentPanelHooks.ts +52 -27
  269. package/src/features/store/objects/components/useDownloadFile.test.ts +20 -0
  270. package/src/features/store/objects/components/useDownloadFile.ts +5 -1
  271. package/src/features/store/objects/selection/actions/StartWorkflowButton.tsx +2 -2
  272. package/src/i18n/locales/ar.json +118 -1
  273. package/src/i18n/locales/de.json +118 -1
  274. package/src/i18n/locales/en.json +118 -0
  275. package/src/i18n/locales/es.json +118 -1
  276. package/src/i18n/locales/fr.json +118 -1
  277. package/src/i18n/locales/it.json +118 -1
  278. package/src/i18n/locales/ja.json +118 -1
  279. package/src/i18n/locales/ko.json +118 -1
  280. package/src/i18n/locales/pt.json +118 -1
  281. package/src/i18n/locales/ru.json +118 -1
  282. package/src/i18n/locales/tr.json +118 -1
  283. package/src/i18n/locales/zh-TW.json +118 -1
  284. package/src/i18n/locales/zh.json +118 -1
  285. package/src/rich-text/EditorToolbar.tsx +708 -0
  286. package/src/rich-text/VertesiaRichTextEditor.test.tsx +211 -0
  287. package/src/rich-text/VertesiaRichTextEditor.tsx +241 -0
  288. package/src/rich-text/index.ts +9 -0
  289. package/src/session/UserSession.test.ts +11 -11
  290. package/src/widgets/markdown/AgentResourceResolver.test.ts +24 -0
  291. package/src/widgets/markdown/AgentResourceResolver.tsx +70 -0
  292. package/src/widgets/markdown/ArtifactEditingSurface.test.tsx +537 -0
  293. package/src/widgets/markdown/ArtifactEditingSurface.tsx +878 -0
  294. package/src/widgets/markdown/CollaborativeMarkdownRenderer.test.tsx +484 -0
  295. package/src/widgets/markdown/CollaborativeMarkdownRenderer.tsx +825 -0
  296. package/src/widgets/markdown/MarkdownLink.test.tsx +122 -0
  297. package/src/widgets/markdown/MarkdownLink.tsx +102 -17
  298. package/src/widgets/markdown/MarkdownRenderer.tsx +30 -3
  299. package/src/widgets/markdown/index.ts +39 -1
  300. package/src/widgets/markdown/normalizeCustomSchemeLinks.ts +15 -2
  301. package/src/widgets/markdown/textDiff.test.ts +156 -0
  302. package/src/widgets/markdown/textDiff.ts +399 -0
  303. package/src/widgets/markdown/useArtifactContent.ts +9 -3
  304. package/src/widgets/markdown/useResolvedUrl.test.ts +29 -40
  305. package/src/widgets/markdown/useResolvedUrl.ts +33 -35
  306. package/src/widgets/xml-viewer/hooks/useXMLViewer.test.ts +26 -0
  307. package/src/widgets/xml-viewer/hooks/useXMLViewer.ts +23 -18
@@ -0,0 +1,537 @@
1
+ /** @vitest-environment jsdom */
2
+
3
+ import { fireEvent, render, screen, waitFor } from '@testing-library/react';
4
+ import userEvent from '@testing-library/user-event';
5
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
6
+ import { I18nProvider } from '../../i18n/index.js';
7
+ import {
8
+ ArtifactEditingSurface,
9
+ type ArtifactEditingSurfaceDocumentEdit,
10
+ applyArtifactRefreshChanges,
11
+ getMarkdownChangeRegions,
12
+ isArtifactRefreshEvent,
13
+ } from './ArtifactEditingSurface.js';
14
+ import type { MarkdownEditingAction } from './CollaborativeMarkdownRenderer.js';
15
+
16
+ const mocks = vi.hoisted(() => {
17
+ const getArtifactContent = vi.fn();
18
+ const updateArtifactContent = vi.fn();
19
+ return {
20
+ client: { agents: { getArtifactContent, updateArtifactContent } },
21
+ getArtifactContent,
22
+ updateArtifactContent,
23
+ };
24
+ });
25
+
26
+ vi.mock('@vertesia/ui/session', () => ({
27
+ useUserSession: () => ({
28
+ client: mocks.client,
29
+ }),
30
+ }));
31
+
32
+ function renderSurface(props?: {
33
+ refreshKey?: number;
34
+ viewMode?: 'components' | 'document';
35
+ baselineContent?: string;
36
+ readOnly?: boolean;
37
+ allowComments?: boolean;
38
+ onAction?: (action: MarkdownEditingAction) => void;
39
+ onSendMessage?: (message: string) => void;
40
+ onSendChangesToAgent?: () => void;
41
+ hasUnsentChanges?: boolean;
42
+ toolbarStatus?: React.ReactNode;
43
+ flushChangesRef?: React.MutableRefObject<(() => Promise<false | ArtifactEditingSurfaceDocumentEdit>) | null>;
44
+ }) {
45
+ return render(
46
+ <I18nProvider lng="en">
47
+ <ArtifactEditingSurface
48
+ runId="run-1"
49
+ path="drafts/document.md"
50
+ refreshKey={props?.refreshKey}
51
+ viewMode={props?.viewMode}
52
+ baselineContent={props?.baselineContent}
53
+ readOnly={props?.readOnly}
54
+ allowComments={props?.allowComments}
55
+ onAction={props?.onAction}
56
+ onSendMessage={props?.onSendMessage}
57
+ onSendChangesToAgent={props?.onSendChangesToAgent}
58
+ hasUnsentChanges={props?.hasUnsentChanges}
59
+ toolbarStatus={props?.toolbarStatus}
60
+ flushChangesRef={props?.flushChangesRef}
61
+ />
62
+ </I18nProvider>,
63
+ );
64
+ }
65
+
66
+ describe('ArtifactEditingSurface', () => {
67
+ beforeEach(() => {
68
+ vi.resetAllMocks();
69
+ mocks.getArtifactContent.mockResolvedValue({
70
+ path: 'drafts/document.md',
71
+ content: 'Original paragraph.',
72
+ generation: 'generation-1',
73
+ });
74
+ mocks.updateArtifactContent.mockResolvedValue({
75
+ path: 'drafts/document.md',
76
+ generation: 'generation-2',
77
+ });
78
+ });
79
+
80
+ it('conditionally saves a direct block edit to the artifact and marks the action applied', async () => {
81
+ const onAction = vi.fn();
82
+ renderSurface({ onAction });
83
+
84
+ await screen.findByText('Original paragraph.');
85
+ fireEvent.click(screen.getByRole('button', { name: 'Edit selection' }));
86
+ fireEvent.change(screen.getByRole('textbox'), { target: { value: 'Revised paragraph.' } });
87
+ fireEvent.click(screen.getByRole('button', { name: 'Send' }));
88
+
89
+ await waitFor(() => {
90
+ expect(mocks.updateArtifactContent).toHaveBeenCalledWith('run-1', 'drafts/document.md', {
91
+ content: 'Revised paragraph.',
92
+ generation: 'generation-1',
93
+ });
94
+ });
95
+ expect(await screen.findByText('Revised paragraph.')).not.toBeNull();
96
+ expect(onAction).toHaveBeenCalledWith(
97
+ expect.objectContaining({
98
+ action: 'edit',
99
+ applied: true,
100
+ base_version: 'generation-2',
101
+ user_change: { before: 'Original paragraph.', after: 'Revised paragraph.' },
102
+ }),
103
+ );
104
+ });
105
+
106
+ it('keeps rendered content mounted while loading a newer artifact generation', async () => {
107
+ const pendingRefresh = new Promise<never>(() => undefined);
108
+ const view = renderSurface();
109
+ await screen.findByText('Original paragraph.');
110
+
111
+ mocks.getArtifactContent.mockReturnValueOnce(pendingRefresh);
112
+ view.rerender(
113
+ <I18nProvider lng="en">
114
+ <ArtifactEditingSurface runId="run-1" path="drafts/document.md" refreshKey={1} />
115
+ </I18nProvider>,
116
+ );
117
+
118
+ expect(screen.getByText('Original paragraph.')).not.toBeNull();
119
+ });
120
+
121
+ it('applies streamed replacements before the background artifact reconciliation finishes', async () => {
122
+ const pendingRefresh = new Promise<never>(() => undefined);
123
+ const view = renderSurface();
124
+ await screen.findByText('Original paragraph.');
125
+
126
+ mocks.getArtifactContent.mockReturnValueOnce(pendingRefresh);
127
+ view.rerender(
128
+ <I18nProvider lng="en">
129
+ <ArtifactEditingSurface
130
+ runId="run-1"
131
+ path="drafts/document.md"
132
+ refreshKey={1}
133
+ refreshDetails={{
134
+ changes: [
135
+ {
136
+ operation: 'replace',
137
+ before: 'Original paragraph.',
138
+ after: 'Revised paragraph.',
139
+ replace_all: false,
140
+ },
141
+ ],
142
+ }}
143
+ />
144
+ </I18nProvider>,
145
+ );
146
+
147
+ expect(await screen.findByText('Revised paragraph.')).not.toBeNull();
148
+ });
149
+
150
+ it('edits and conditionally persists the working copy in full-document mode', async () => {
151
+ const user = userEvent.setup();
152
+ renderSurface({ viewMode: 'document' });
153
+
154
+ const editor = await screen.findByRole('textbox', { name: 'Markdown document editor' });
155
+ await user.click(editor);
156
+ await user.type(editor, ' revised');
157
+
158
+ await waitFor(
159
+ () => {
160
+ expect(mocks.updateArtifactContent).toHaveBeenCalledWith('run-1', 'drafts/document.md', {
161
+ content: expect.stringContaining('revised'),
162
+ generation: 'generation-1',
163
+ });
164
+ },
165
+ { timeout: 2500 },
166
+ );
167
+ });
168
+
169
+ it('uses the floating selection comment control instead of a redundant toolbar button', async () => {
170
+ renderSurface({
171
+ viewMode: 'document',
172
+ readOnly: true,
173
+ allowComments: true,
174
+ onSendMessage: vi.fn(),
175
+ });
176
+
177
+ const editor = await screen.findByRole('textbox', { name: 'Markdown document editor' });
178
+ expect(editor.getAttribute('contenteditable')).toBe('false');
179
+ expect(screen.queryByRole('button', { name: 'Comment on selection' })).toBeNull();
180
+ });
181
+
182
+ it('exposes the pending direct-edit hand-off inside the full-document editor toolbar', async () => {
183
+ const onSendChangesToAgent = vi.fn();
184
+ renderSurface({
185
+ viewMode: 'document',
186
+ onSendChangesToAgent,
187
+ hasUnsentChanges: true,
188
+ toolbarStatus: <span>AI is editing</span>,
189
+ });
190
+
191
+ const button = await screen.findByRole('button', { name: 'Send changes to agent' });
192
+ expect(screen.getByRole('toolbar').contains(button)).toBe(true);
193
+ expect(button.previousElementSibling?.textContent).toBe('AI is editing');
194
+ expect(button).toHaveProperty('disabled', false);
195
+ fireEvent.click(button);
196
+ expect(onSendChangesToAgent).toHaveBeenCalledTimes(1);
197
+ });
198
+
199
+ it('flushes the latest editor transaction before handing changes to the agent', async () => {
200
+ const user = userEvent.setup();
201
+ const flushChangesRef: React.MutableRefObject<
202
+ (() => Promise<false | ArtifactEditingSurfaceDocumentEdit>) | null
203
+ > = { current: null };
204
+ renderSurface({ viewMode: 'document', flushChangesRef });
205
+
206
+ const editor = await screen.findByRole('textbox', { name: 'Markdown document editor' });
207
+ await user.click(editor);
208
+ await user.type(editor, ' immediate');
209
+
210
+ expect(flushChangesRef.current).not.toBeNull();
211
+ // The flush reports the delta since the agent's last known content so the
212
+ // caller can hand the agent an exact diff of the direct edits.
213
+ expect(await flushChangesRef.current?.()).toEqual({
214
+ previous: 'Original paragraph.',
215
+ current: expect.stringContaining('immediate'),
216
+ });
217
+ expect(mocks.updateArtifactContent).toHaveBeenCalledWith('run-1', 'drafts/document.md', {
218
+ content: expect.stringContaining('immediate'),
219
+ generation: 'generation-1',
220
+ });
221
+ });
222
+
223
+ it('flushes a pending debounced document save when the editor unmounts', async () => {
224
+ mocks.getArtifactContent.mockResolvedValueOnce({
225
+ path: 'drafts/document.md',
226
+ content: '#',
227
+ generation: 'generation-1',
228
+ });
229
+ const view = renderSurface({ viewMode: 'document' });
230
+
231
+ fireEvent.click(await screen.findByRole('button', { name: 'Edit Markdown source' }));
232
+ const sourceEditor = screen.getByRole('textbox', { name: 'Markdown source editor' });
233
+ fireEvent.focus(sourceEditor);
234
+ fireEvent.change(sourceEditor, {
235
+ target: { value: '## Updated heading' },
236
+ });
237
+ expect(mocks.updateArtifactContent).not.toHaveBeenCalled();
238
+
239
+ view.unmount();
240
+
241
+ await waitFor(() => {
242
+ expect(mocks.updateArtifactContent).toHaveBeenCalledWith('run-1', 'drafts/document.md', {
243
+ content: '## Updated heading',
244
+ generation: 'generation-1',
245
+ });
246
+ });
247
+ });
248
+
249
+ it('shows a navigable ruler for changes from the original document', async () => {
250
+ renderSurface({ viewMode: 'document', baselineContent: 'Different paragraph.' });
251
+
252
+ await screen.findByRole('textbox', { name: 'Markdown document editor' });
253
+ expect(screen.getByRole('navigation', { name: 'Change ruler' })).not.toBeNull();
254
+ expect(screen.getByRole('button', { name: 'Change near line 1' })).not.toBeNull();
255
+ });
256
+
257
+ it('keeps the focused editor base generation when the agent refreshes the artifact', async () => {
258
+ const user = userEvent.setup();
259
+ const view = renderSurface({ viewMode: 'document' });
260
+ const editor = await screen.findByRole('textbox', { name: 'Markdown document editor' });
261
+ await user.click(editor);
262
+
263
+ mocks.getArtifactContent.mockResolvedValueOnce({
264
+ path: 'drafts/document.md',
265
+ content: 'Agent revision.',
266
+ generation: 'generation-agent',
267
+ });
268
+ view.rerender(
269
+ <I18nProvider lng="en">
270
+ <ArtifactEditingSurface runId="run-1" path="drafts/document.md" refreshKey={1} viewMode="document" />
271
+ </I18nProvider>,
272
+ );
273
+ await waitFor(() => expect(mocks.getArtifactContent).toHaveBeenCalledTimes(2));
274
+
275
+ await user.type(editor, ' local edit');
276
+
277
+ await waitFor(
278
+ () => {
279
+ expect(mocks.updateArtifactContent).toHaveBeenCalledTimes(1);
280
+ expect(mocks.updateArtifactContent).toHaveBeenLastCalledWith('run-1', 'drafts/document.md', {
281
+ content: expect.stringContaining('local edit'),
282
+ generation: 'generation-1',
283
+ });
284
+ },
285
+ { timeout: 2500 },
286
+ );
287
+ });
288
+
289
+ it('rebases focused full-document edits over a non-overlapping agent change after 412', async () => {
290
+ const user = userEvent.setup();
291
+ const baseContent = 'First paragraph.\n\nSecond paragraph.';
292
+ const remoteContent = 'First paragraph updated remotely.\n\nSecond paragraph.';
293
+ mocks.getArtifactContent
294
+ .mockResolvedValueOnce({
295
+ path: 'drafts/document.md',
296
+ content: baseContent,
297
+ generation: 'generation-1',
298
+ })
299
+ .mockResolvedValueOnce({
300
+ path: 'drafts/document.md',
301
+ content: remoteContent,
302
+ generation: 'generation-agent',
303
+ })
304
+ .mockResolvedValueOnce({
305
+ path: 'drafts/document.md',
306
+ content: remoteContent,
307
+ generation: 'generation-agent',
308
+ });
309
+ mocks.updateArtifactContent
310
+ .mockRejectedValueOnce({ status: 412 })
311
+ .mockResolvedValueOnce({ path: 'drafts/document.md', generation: 'generation-merged' });
312
+
313
+ const view = renderSurface({ viewMode: 'document' });
314
+ const editor = await screen.findByRole('textbox', { name: 'Markdown document editor' });
315
+ await user.click(editor);
316
+
317
+ view.rerender(
318
+ <I18nProvider lng="en">
319
+ <ArtifactEditingSurface runId="run-1" path="drafts/document.md" refreshKey={1} viewMode="document" />
320
+ </I18nProvider>,
321
+ );
322
+ await waitFor(() => expect(mocks.getArtifactContent).toHaveBeenCalledTimes(2));
323
+
324
+ editor.focus();
325
+ const secondParagraphText = editor.querySelectorAll('p')[1]?.firstChild;
326
+ if (!secondParagraphText) {
327
+ throw new Error('Expected the second paragraph to have a text node');
328
+ }
329
+ const range = document.createRange();
330
+ range.setStart(secondParagraphText, secondParagraphText.textContent?.length ?? 0);
331
+ range.collapse(true);
332
+ const selection = window.getSelection();
333
+ selection?.removeAllRanges();
334
+ selection?.addRange(range);
335
+ await user.type(editor, '!', { skipClick: true });
336
+
337
+ await waitFor(
338
+ () => {
339
+ expect(mocks.updateArtifactContent).toHaveBeenNthCalledWith(2, 'run-1', 'drafts/document.md', {
340
+ content: expect.stringMatching(/updated remotely[\s\S]*Second paragraph\.!/),
341
+ generation: 'generation-agent',
342
+ });
343
+ },
344
+ { timeout: 2500 },
345
+ );
346
+ expect(screen.queryByRole('alert')).toBeNull();
347
+ expect(editor.textContent).toContain('First paragraph updated remotely.');
348
+ });
349
+
350
+ it('preserves overlapping full-document edits behind a conflict banner after 412', async () => {
351
+ const user = userEvent.setup();
352
+ mocks.getArtifactContent
353
+ .mockResolvedValueOnce({
354
+ path: 'drafts/document.md',
355
+ content: 'Original paragraph.',
356
+ generation: 'generation-1',
357
+ })
358
+ .mockResolvedValueOnce({
359
+ path: 'drafts/document.md',
360
+ content: 'Remote paragraph.',
361
+ generation: 'generation-agent',
362
+ });
363
+ mocks.updateArtifactContent.mockRejectedValueOnce({ status: 412 });
364
+ renderSurface({ viewMode: 'document' });
365
+
366
+ const editor = await screen.findByRole('textbox', { name: 'Markdown document editor' });
367
+ await user.click(editor);
368
+ await user.type(editor, ' local edit');
369
+
370
+ expect((await screen.findByRole('alert')).textContent).toContain('Working copy changed elsewhere');
371
+ expect(screen.getByRole('button', { name: 'Try merge again' })).not.toBeNull();
372
+ expect(editor.textContent).toContain('local edit');
373
+ expect(screen.queryByText('Saved to working copy')).toBeNull();
374
+ expect(mocks.updateArtifactContent).toHaveBeenCalledTimes(1);
375
+
376
+ fireEvent.click(screen.getByRole('button', { name: 'Try merge again' }));
377
+ await waitFor(() => expect(screen.queryByRole('alert')).toBeNull());
378
+ expect(mocks.updateArtifactContent).toHaveBeenNthCalledWith(2, 'run-1', 'drafts/document.md', {
379
+ content: expect.stringContaining('local edit'),
380
+ generation: 'generation-1',
381
+ });
382
+ });
383
+
384
+ it('rebases a component edit and reports it as applied after 412', async () => {
385
+ const user = userEvent.setup();
386
+ const onAction = vi.fn();
387
+ const baseContent = 'First paragraph.\n\nSecond paragraph.';
388
+ const remoteContent = 'First paragraph updated remotely.\n\nSecond paragraph.';
389
+ mocks.getArtifactContent
390
+ .mockResolvedValueOnce({
391
+ path: 'drafts/document.md',
392
+ content: baseContent,
393
+ generation: 'generation-1',
394
+ })
395
+ .mockResolvedValueOnce({
396
+ path: 'drafts/document.md',
397
+ content: remoteContent,
398
+ generation: 'generation-agent',
399
+ });
400
+ mocks.updateArtifactContent
401
+ .mockRejectedValueOnce({ status: 412 })
402
+ .mockResolvedValueOnce({ path: 'drafts/document.md', generation: 'generation-merged' });
403
+ renderSurface({ onAction });
404
+
405
+ await screen.findByText('Second paragraph.');
406
+ const editButtons = screen.getAllByRole('button', { name: 'Edit selection' });
407
+ fireEvent.click(editButtons[editButtons.length - 1]);
408
+ const editor = await screen.findByRole('textbox');
409
+ await user.click(editor);
410
+ await user.clear(editor);
411
+ await user.type(editor, 'Second paragraph edited locally.');
412
+ fireEvent.click(screen.getByRole('button', { name: 'Send' }));
413
+
414
+ await waitFor(() => {
415
+ expect(mocks.updateArtifactContent).toHaveBeenNthCalledWith(2, 'run-1', 'drafts/document.md', {
416
+ content: 'First paragraph updated remotely.\n\nSecond paragraph edited locally.',
417
+ generation: 'generation-agent',
418
+ });
419
+ });
420
+ expect(await screen.findByText('First paragraph updated remotely.')).not.toBeNull();
421
+ expect(await screen.findByText('Second paragraph edited locally.')).not.toBeNull();
422
+ expect(onAction).toHaveBeenCalledWith(
423
+ expect.objectContaining({ applied: true, base_version: 'generation-merged' }),
424
+ );
425
+ });
426
+
427
+ it('retains a conflicted component action and notifies the agent after retry succeeds', async () => {
428
+ const user = userEvent.setup();
429
+ const onAction = vi.fn();
430
+ mocks.getArtifactContent
431
+ .mockResolvedValueOnce({
432
+ path: 'drafts/document.md',
433
+ content: 'Original paragraph.',
434
+ generation: 'generation-1',
435
+ })
436
+ .mockResolvedValueOnce({
437
+ path: 'drafts/document.md',
438
+ content: 'Remote paragraph.',
439
+ generation: 'generation-agent',
440
+ });
441
+ mocks.updateArtifactContent.mockRejectedValueOnce({ status: 412 });
442
+ renderSurface({ onAction });
443
+
444
+ await screen.findByText('Original paragraph.');
445
+ fireEvent.click(screen.getByRole('button', { name: 'Edit selection' }));
446
+ const editor = await screen.findByRole('textbox');
447
+ await user.click(editor);
448
+ await user.clear(editor);
449
+ await user.type(editor, 'Local paragraph.');
450
+ fireEvent.click(screen.getByRole('button', { name: 'Send' }));
451
+
452
+ await screen.findByRole('alert');
453
+ expect(onAction).not.toHaveBeenCalled();
454
+ fireEvent.click(screen.getByRole('button', { name: 'Try merge again' }));
455
+
456
+ await waitFor(() => {
457
+ expect(onAction).toHaveBeenCalledWith(
458
+ expect.objectContaining({ applied: true, base_version: 'generation-2' }),
459
+ );
460
+ });
461
+ expect(await screen.findByText('Local paragraph.')).not.toBeNull();
462
+ expect(screen.queryByRole('alert')).toBeNull();
463
+ });
464
+ });
465
+
466
+ describe('getMarkdownChangeRegions', () => {
467
+ it('maps additions and removals onto distinct current-document line regions', () => {
468
+ expect(getMarkdownChangeRegions('One\nTwo\nThree', 'One\nChanged\nThree\nFour')).toEqual([
469
+ { startLine: 1, endLine: 1 },
470
+ { startLine: 3, endLine: 3 },
471
+ ]);
472
+ });
473
+
474
+ it('returns no regions for unchanged Markdown', () => {
475
+ expect(getMarkdownChangeRegions('Same', 'Same')).toEqual([]);
476
+ });
477
+ });
478
+
479
+ describe('isArtifactRefreshEvent', () => {
480
+ it('accepts dedicated artifact updates and legacy path-bearing edit completions', () => {
481
+ expect(
482
+ isArtifactRefreshEvent(
483
+ { event_class: 'artifact_updated', path: 'drafts/document.md' },
484
+ 'drafts/document.md',
485
+ ),
486
+ ).toBe(true);
487
+ expect(
488
+ isArtifactRefreshEvent(
489
+ {
490
+ event_class: 'activity',
491
+ tool: 'edit_artifact',
492
+ tool_status: 'completed',
493
+ path: 'drafts/document.md',
494
+ },
495
+ 'drafts/document.md',
496
+ ),
497
+ ).toBe(true);
498
+ });
499
+
500
+ it('rejects unrelated progress and other artifact paths', () => {
501
+ expect(
502
+ isArtifactRefreshEvent(
503
+ {
504
+ event_class: 'activity',
505
+ tool: 'edit_artifact',
506
+ tool_status: 'running',
507
+ path: 'drafts/document.md',
508
+ },
509
+ 'drafts/document.md',
510
+ ),
511
+ ).toBe(false);
512
+ expect(
513
+ isArtifactRefreshEvent({ event_class: 'artifact_updated', path: 'drafts/other.md' }, 'drafts/document.md'),
514
+ ).toBe(false);
515
+ });
516
+ });
517
+
518
+ describe('applyArtifactRefreshChanges', () => {
519
+ it('applies sequential replacements from the stream details payload', () => {
520
+ expect(
521
+ applyArtifactRefreshChanges('Goals\n- One\n- Two', {
522
+ changes: [
523
+ { operation: 'replace', before: '- One', after: '- First', replace_all: false },
524
+ { operation: 'replace', before: '- Two', after: '- Second', replace_all: false },
525
+ ],
526
+ }),
527
+ ).toBe('Goals\n- First\n- Second');
528
+ });
529
+
530
+ it('falls back when the streamed change cannot be applied safely', () => {
531
+ expect(
532
+ applyArtifactRefreshChanges('Repeated Repeated', {
533
+ changes: [{ operation: 'replace', before: 'Repeated', after: 'Changed', replace_all: false }],
534
+ }),
535
+ ).toBeUndefined();
536
+ });
537
+ });