@semiont/react-ui 0.5.26 → 0.5.28

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 (242) hide show
  1. package/README.md +28 -4
  2. package/dist/{PdfAnnotationCanvas.client-6ZSF6ZTJ.js → PdfAnnotationCanvas.client-C2IGG4SW.js} +33 -6
  3. package/dist/{PdfAnnotationCanvas.client-JCJMXWWJ.css → PdfAnnotationCanvas.client-TGDPPGXJ.css} +6 -1
  4. package/dist/{ar-YTUUGK2O.js → ar-FABPTJVB.js} +88 -26
  5. package/dist/{bn-ASGNGPMD.js → bn-LKP6BDMH.js} +88 -26
  6. package/dist/{chunk-L3WKRWP3.js → chunk-2GOHTTHW.js} +88 -26
  7. package/dist/{chunk-OBQOZCJE.js → chunk-2YHEE63S.js} +31 -31
  8. package/dist/{cs-WMYVAOZY.js → cs-YQYNWHRG.js} +88 -26
  9. package/dist/{da-FSHHN4D6.js → da-QHZOYKRY.js} +88 -26
  10. package/dist/{de-FJFO3TPT.js → de-GKA7RD7J.js} +88 -26
  11. package/dist/{el-XOH4QIAG.js → el-45T257AL.js} +88 -26
  12. package/dist/{en-3FCBW3YD.js → en-RVW5EQ66.js} +4 -2
  13. package/dist/{es-HDX4QI7E.js → es-AVER7RU4.js} +88 -26
  14. package/dist/{fa-DJ6WTFTJ.js → fa-K3VPK3O2.js} +88 -26
  15. package/dist/{fi-4S7H7W7U.js → fi-5NEKF7EB.js} +88 -26
  16. package/dist/{fr-6UJSYHXC.js → fr-FUMNDLBZ.js} +88 -26
  17. package/dist/{he-ZZJOHJX2.js → he-3JGNA3PR.js} +88 -26
  18. package/dist/{hi-HZJTAW7U.js → hi-IJY375DF.js} +88 -26
  19. package/dist/{id-E3I6ILEM.js → id-LWHKJ7ZD.js} +88 -26
  20. package/dist/index.css +380 -524
  21. package/dist/index.d.ts +318 -192
  22. package/dist/index.js +2960 -2421
  23. package/dist/integrations/css-modules-helper.js +1 -3
  24. package/dist/{it-ULAPAD7U.js → it-EBVOV4RW.js} +88 -26
  25. package/dist/{ja-SAHZQ4CZ.js → ja-KWRIX2NF.js} +88 -26
  26. package/dist/{ko-DFU2ADQ4.js → ko-L5CJMFDS.js} +88 -26
  27. package/dist/{ms-NWL76XNT.js → ms-LSNMJDR2.js} +88 -26
  28. package/dist/{nl-ATCM76WN.js → nl-ZB32MB7U.js} +88 -26
  29. package/dist/{no-UIAQ5RJF.js → no-4GTNY7M5.js} +88 -26
  30. package/dist/{pl-NOECQDXD.js → pl-LUHBLTHB.js} +88 -26
  31. package/dist/{pt-SVWIIUPC.js → pt-C4H3UNQ6.js} +88 -26
  32. package/dist/{ro-NR2DRTZG.js → ro-GGITS5V4.js} +88 -26
  33. package/dist/{sv-STVJ37JP.js → sv-T56RTLBP.js} +88 -26
  34. package/dist/test-utils.css +1 -1
  35. package/dist/test-utils.d.ts +1 -1
  36. package/dist/test-utils.js +2 -2
  37. package/dist/{th-UWQR4K54.js → th-22X2IWCB.js} +88 -26
  38. package/dist/{tr-WNXZSD27.js → tr-77TFG62H.js} +88 -26
  39. package/dist/{uk-SJRMB47Y.js → uk-MIIL6NXT.js} +88 -26
  40. package/dist/{vi-TMRQFES2.js → vi-7JYOIGNV.js} +88 -26
  41. package/dist/{zh-QOL3LYEM.js → zh-ID6DRYU4.js} +88 -26
  42. package/package.json +11 -10
  43. package/src/components/AssistProgress.tsx +178 -134
  44. package/src/components/CodeMirrorRenderer.tsx +8 -8
  45. package/src/components/{EntityFoundLog.tsx → ItemFoundLog.tsx} +12 -7
  46. package/src/components/ProtectedErrorBoundary.css +3 -1
  47. package/src/components/StatusDisplay.css +1 -1
  48. package/src/components/Toast.css +3 -1
  49. package/src/components/__tests__/AssistProgress.test.tsx +268 -141
  50. package/src/components/annotation/annotation-entries.css +0 -4
  51. package/src/components/annotation/references.css +0 -4
  52. package/src/components/image-annotation/AnnotationOverlay.tsx +6 -6
  53. package/src/components/image-annotation/SvgDrawingCanvas.tsx +1 -1
  54. package/src/components/image-annotation/__tests__/AnnotationOverlay.click.test.tsx +7 -9
  55. package/src/components/image-annotation/__tests__/SvgDrawingCanvas.click.test.tsx +1 -2
  56. package/src/components/layout/Header.css +0 -4
  57. package/src/components/layout/LeftSidebar.css +0 -4
  58. package/src/components/modals/ComposeStep.tsx +218 -0
  59. package/src/components/modals/ConfigureGatherStep.tsx +10 -18
  60. package/src/components/modals/ConfigureGenerationStep.tsx +131 -54
  61. package/src/components/modals/ConfigureSearchStep.tsx +42 -40
  62. package/src/components/modals/ContextSummary.tsx +185 -72
  63. package/src/components/modals/CorpusPane.tsx +75 -0
  64. package/src/components/modals/DiscardPrompt.tsx +38 -0
  65. package/src/components/modals/GatherContextStep.tsx +237 -107
  66. package/src/components/modals/ReferenceWizardModal.tsx +287 -60
  67. package/src/components/modals/ResourceGenerateModal.tsx +233 -109
  68. package/src/components/modals/SearchModal.css +335 -111
  69. package/src/components/modals/SearchModal.tsx +1 -1
  70. package/src/components/modals/SearchResultsStep.tsx +63 -88
  71. package/src/components/modals/WizardFooter.tsx +69 -0
  72. package/src/components/modals/__tests__/ComposeStep.test.tsx +152 -0
  73. package/src/components/modals/__tests__/ConfigureGatherStep.test.tsx +14 -26
  74. package/src/components/modals/__tests__/ConfigureGenerationStep.test.tsx +290 -0
  75. package/src/components/modals/__tests__/ConfigureSearchStep.test.tsx +95 -0
  76. package/src/components/modals/__tests__/GatherContextStep.resource.test.tsx +463 -25
  77. package/src/components/modals/__tests__/ReferenceWizardModal.test.tsx +635 -0
  78. package/src/components/modals/__tests__/ResourceGenerateModal.test.tsx +277 -85
  79. package/src/components/modals/__tests__/SearchModal.search-wiring.test.tsx +6 -2
  80. package/src/components/modals/__tests__/SearchResultsStep.test.tsx +61 -0
  81. package/src/components/modals/__tests__/WizardFooter.test.tsx +344 -0
  82. package/src/components/modals/modals.css +16 -42
  83. package/src/components/navigation/NavigationTabs.css +0 -20
  84. package/src/components/pdf-annotation/PdfAnnotationCanvas.css +21 -2
  85. package/src/components/pdf-annotation/PdfAnnotationCanvas.tsx +36 -3
  86. package/src/components/pdf-annotation/__tests__/PdfAnnotationCanvas.test.tsx +41 -6
  87. package/src/components/resource/AnnotateView.tsx +19 -8
  88. package/src/components/resource/AnnotationHistory.tsx +2 -0
  89. package/src/components/resource/BrowseView.tsx +20 -9
  90. package/src/components/resource/ResourceViewer.tsx +27 -28
  91. package/src/components/resource/__tests__/AnnotateView.embeddable.test.tsx +1 -1
  92. package/src/components/resource/__tests__/AnnotateView.focus.test.tsx +50 -0
  93. package/src/components/resource/__tests__/AnnotationHistory.test.tsx +2 -0
  94. package/src/components/resource/__tests__/BrowseView.embeddable.test.tsx +1 -1
  95. package/src/components/resource/__tests__/BrowseView.test.tsx +38 -12
  96. package/src/components/resource/__tests__/ResourceViewer.embeddable.test.tsx +47 -3
  97. package/src/components/resource/annotate-renderers.tsx +3 -3
  98. package/src/components/resource/event-formatting.ts +0 -3
  99. package/src/components/resource/panels/AssessmentEntry.tsx +1 -1
  100. package/src/components/resource/panels/AssessmentPanel.css +5 -6
  101. package/src/components/resource/panels/AssistSection.css +95 -263
  102. package/src/components/resource/panels/AssistSection.tsx +4 -4
  103. package/src/components/resource/panels/AssistShell.tsx +12 -4
  104. package/src/components/resource/panels/CollaborationPanel.css +47 -22
  105. package/src/components/resource/panels/CollaborationPanel.tsx +93 -2
  106. package/src/components/resource/panels/CommentEntry.tsx +1 -1
  107. package/src/components/resource/panels/CommentsPanel.css +0 -16
  108. package/src/components/resource/panels/HighlightEntry.tsx +1 -1
  109. package/src/components/resource/panels/HighlightPanel.css +0 -7
  110. package/src/components/resource/panels/JsonLdPanel.css +0 -4
  111. package/src/components/resource/panels/ReferenceEntry.tsx +10 -3
  112. package/src/components/resource/panels/ReferencesPanel.css +0 -12
  113. package/src/components/resource/panels/ReferencesPanel.tsx +16 -20
  114. package/src/components/resource/panels/ResourceInfoPanel.css +0 -32
  115. package/src/components/resource/panels/ResourceInfoPanel.tsx +89 -20
  116. package/src/components/resource/panels/StatisticsPanel.css +0 -20
  117. package/src/components/resource/panels/TagEntry.tsx +1 -1
  118. package/src/components/resource/panels/TaggingPanel.css +0 -4
  119. package/src/components/resource/panels/TaggingPanel.tsx +2 -10
  120. package/src/components/resource/panels/UnifiedAnnotationsPanel.css +0 -4
  121. package/src/components/resource/panels/UnifiedAnnotationsPanel.tsx +7 -2
  122. package/src/components/resource/panels/__tests__/AssessmentEntry.test.tsx +0 -1
  123. package/src/components/resource/panels/__tests__/AssistSection.test.tsx +48 -50
  124. package/src/components/resource/panels/__tests__/AssistShell.test.tsx +11 -6
  125. package/src/components/resource/panels/__tests__/CollaborationPanel.test.tsx +89 -0
  126. package/src/components/resource/panels/__tests__/CommentEntry.test.tsx +1 -2
  127. package/src/components/resource/panels/__tests__/HighlightEntry.test.tsx +0 -1
  128. package/src/components/resource/panels/__tests__/HighlightPanel.annotationProgress.test.tsx +44 -36
  129. package/src/components/resource/panels/__tests__/ReferenceEntry.test.tsx +41 -1
  130. package/src/components/resource/panels/__tests__/ReferencesPanel.headless.test.tsx +1 -1
  131. package/src/components/resource/panels/__tests__/ReferencesPanel.test.tsx +67 -54
  132. package/src/components/resource/panels/__tests__/ResourceInfoPanel.test.tsx +185 -7
  133. package/src/components/resource/panels/__tests__/TagEntry.test.tsx +0 -1
  134. package/src/components/settings/SettingsPanel.css +0 -4
  135. package/src/features/auth/auth.css +2 -26
  136. package/src/features/resource-compose/__tests__/ResourceComposePage.test.tsx +0 -65
  137. package/src/features/resource-compose/components/ResourceComposePage.tsx +17 -130
  138. package/src/features/resource-compose/state/__tests__/compose-page-state-unit.test.ts +1 -76
  139. package/src/features/resource-compose/state/compose-page-state-unit.ts +5 -48
  140. package/src/features/resource-discovery/__tests__/ResourceDiscoveryPage.test.tsx +55 -0
  141. package/src/features/resource-discovery/components/ResourceDiscoveryPage.tsx +29 -0
  142. package/src/features/resource-discovery/state/__tests__/discover-state-unit.test.ts +53 -3
  143. package/src/features/resource-discovery/state/discover-state-unit.ts +29 -8
  144. package/src/features/resource-viewer/__tests__/ResourceViewerPage.test.tsx +71 -15
  145. package/src/features/resource-viewer/components/ResourceViewerPage.tsx +166 -71
  146. package/src/features/resource-viewer/hooks/__tests__/useResourceViewedReport.test.tsx +63 -0
  147. package/src/features/resource-viewer/hooks/useResourceViewedReport.ts +33 -0
  148. package/src/features/resource-viewer/state/__tests__/resource-viewer-page-state-unit.test.ts +2 -2
  149. package/src/features/resource-viewer/state/resource-viewer-page-state-unit.ts +1 -1
  150. package/src/styles/core/buttons.css +3 -1
  151. package/src/styles/core/forms.css +35 -29
  152. package/src/styles/core/indicators.css +0 -4
  153. package/src/styles/core/inputs.css +0 -4
  154. package/src/styles/core/progress.css +2 -34
  155. package/src/styles/core/sliders.css +0 -4
  156. package/src/styles/core/toggles.css +0 -4
  157. package/src/styles/features/resource-discovery.css +13 -0
  158. package/src/styles/features/resource-viewer.css +0 -42
  159. package/src/styles/features/resource.css +0 -4
  160. package/src/styles/motivations/motivation-assessment.css +2 -2
  161. package/src/styles/panels/history-panel.css +0 -40
  162. package/src/styles/panels/user-panel.css +0 -3
  163. package/src/styles/patterns/panel-helpers.css +0 -27
  164. package/src/styles/patterns/panel-sections.css +0 -59
  165. package/src/styles/patterns/panels-base.css +0 -32
  166. package/translations/ar.json +84 -24
  167. package/translations/bn.json +84 -24
  168. package/translations/cs.json +84 -24
  169. package/translations/da.json +84 -24
  170. package/translations/de.json +84 -24
  171. package/translations/el.json +84 -24
  172. package/translations/en.json +84 -24
  173. package/translations/es.json +84 -24
  174. package/translations/fa.json +84 -24
  175. package/translations/fi.json +84 -24
  176. package/translations/fr.json +84 -24
  177. package/translations/he.json +84 -24
  178. package/translations/hi.json +84 -24
  179. package/translations/id.json +84 -24
  180. package/translations/it.json +84 -24
  181. package/translations/ja.json +84 -24
  182. package/translations/ko.json +84 -24
  183. package/translations/ms.json +84 -24
  184. package/translations/nl.json +84 -24
  185. package/translations/no.json +84 -24
  186. package/translations/pl.json +84 -24
  187. package/translations/pt.json +84 -24
  188. package/translations/ro.json +84 -24
  189. package/translations/sv.json +84 -24
  190. package/translations/th.json +84 -24
  191. package/translations/tr.json +84 -24
  192. package/translations/uk.json +84 -24
  193. package/translations/vi.json +84 -24
  194. package/translations/zh.json +84 -24
  195. package/dist/PdfAnnotationCanvas.client-6ZSF6ZTJ.js.map +0 -1
  196. package/dist/PdfAnnotationCanvas.client-JCJMXWWJ.css.map +0 -1
  197. package/dist/ar-YTUUGK2O.js.map +0 -1
  198. package/dist/bn-ASGNGPMD.js.map +0 -1
  199. package/dist/chunk-BTUG3VJJ.js.map +0 -1
  200. package/dist/chunk-L3WKRWP3.js.map +0 -1
  201. package/dist/chunk-O23TLLXW.js.map +0 -1
  202. package/dist/chunk-OBQOZCJE.js.map +0 -1
  203. package/dist/chunk-QT7LYM72.js.map +0 -1
  204. package/dist/chunk-VXASXU4K.js.map +0 -1
  205. package/dist/chunk-XUDKYAVC.js +0 -21
  206. package/dist/chunk-XUDKYAVC.js.map +0 -1
  207. package/dist/cs-WMYVAOZY.js.map +0 -1
  208. package/dist/da-FSHHN4D6.js.map +0 -1
  209. package/dist/de-FJFO3TPT.js.map +0 -1
  210. package/dist/el-XOH4QIAG.js.map +0 -1
  211. package/dist/en-3FCBW3YD.js.map +0 -1
  212. package/dist/es-HDX4QI7E.js.map +0 -1
  213. package/dist/fa-DJ6WTFTJ.js.map +0 -1
  214. package/dist/fi-4S7H7W7U.js.map +0 -1
  215. package/dist/fr-6UJSYHXC.js.map +0 -1
  216. package/dist/he-ZZJOHJX2.js.map +0 -1
  217. package/dist/hi-HZJTAW7U.js.map +0 -1
  218. package/dist/id-E3I6ILEM.js.map +0 -1
  219. package/dist/index.css.map +0 -1
  220. package/dist/index.js.map +0 -1
  221. package/dist/integrations/css-modules-helper.js.map +0 -1
  222. package/dist/integrations/styled-components-theme.js.map +0 -1
  223. package/dist/it-ULAPAD7U.js.map +0 -1
  224. package/dist/ja-SAHZQ4CZ.js.map +0 -1
  225. package/dist/ko-DFU2ADQ4.js.map +0 -1
  226. package/dist/ms-NWL76XNT.js.map +0 -1
  227. package/dist/nl-ATCM76WN.js.map +0 -1
  228. package/dist/no-UIAQ5RJF.js.map +0 -1
  229. package/dist/pl-NOECQDXD.js.map +0 -1
  230. package/dist/pt-SVWIIUPC.js.map +0 -1
  231. package/dist/ro-NR2DRTZG.js.map +0 -1
  232. package/dist/sv-STVJ37JP.js.map +0 -1
  233. package/dist/test-utils.css.map +0 -1
  234. package/dist/test-utils.js.map +0 -1
  235. package/dist/th-UWQR4K54.js.map +0 -1
  236. package/dist/tr-WNXZSD27.js.map +0 -1
  237. package/dist/uk-SJRMB47Y.js.map +0 -1
  238. package/dist/vi-TMRQFES2.js.map +0 -1
  239. package/dist/zh-QOL3LYEM.js.map +0 -1
  240. package/src/components/modals/ResourceSearchModal.tsx +0 -224
  241. package/src/components/modals/__tests__/ResourceSearchModal.test.tsx +0 -159
  242. package/src/integrations/tailwind-plugin.cjs +0 -224
@@ -22,7 +22,7 @@ import type { Annotation, AnnotationId } from '@semiont/core';
22
22
 
23
23
  // Mock translations - simulates useTranslations('HighlightPanel')
24
24
  // The mock receives keys like 'title', 'noHighlights', etc. and returns translated strings
25
- const mockT = vi.fn((key: string) => {
25
+ const mockT = vi.fn((key: string, params?: Record<string, unknown>) => {
26
26
  const translations: Record<string, string> = {
27
27
  title: 'Highlights',
28
28
  noHighlights: 'No highlights yet',
@@ -34,8 +34,31 @@ const mockT = vi.fn((key: string) => {
34
34
  densitySparse: 'Sparse',
35
35
  densityDense: 'Dense',
36
36
  annotate: 'Annotate',
37
+ annotating: 'Annotating...',
37
38
  };
38
- return translations[key] || key;
39
+ // P3: the coded status line. Interpolates `{{var}}` like production —
40
+ // a mock that ignored params would let copy that cannot interpolate in the
41
+ // app still pass here.
42
+ Object.assign(translations, {
43
+ codeLoading: 'Loading…',
44
+ codeAnalyzing: 'Marking…',
45
+ codeDetectingEntities: 'Marking…',
46
+ codeCompleteCreated: 'Created {{count}} {{kind}}',
47
+ kindHighlight: 'highlights',
48
+ subject: '{{kind}}: {{label}}',
49
+ subjectWithPosition: '{{kind}}: {{label}} ({{done}} of {{total}})',
50
+ subjectKindEntityType: 'Entity type',
51
+ subjectKindCategory: 'Category',
52
+ // CLEAN-PROGRESS D3: the widget's own strings now come from the
53
+ // AssistProgress namespace, not from each panel's.
54
+ cancel: 'Cancel',
55
+ inProgress: 'Annotating...',
56
+ });
57
+ let out = translations[key] || key;
58
+ for (const [k, v] of Object.entries((params ?? {}) as Record<string, unknown>)) {
59
+ out = out.replace(`{{${k}}}`, String(v));
60
+ }
61
+ return out;
39
62
  });
40
63
 
41
64
  vi.mock('../../../../contexts/TranslationContext', () => ({
@@ -85,16 +108,14 @@ describe('HighlightPanel + AssistSection Integration', () => {
85
108
  pendingAnnotation={null}
86
109
  isAssisting={true}
87
110
  progress={{
88
- stage: 'analyzing',
89
111
  percentage: 30,
90
- message: 'Analyzing text for highlights...',
91
112
  }}
92
113
  annotateMode={true}
93
114
  />
94
115
  );
95
116
 
96
117
  // Verify AssistSection received and rendered the progress
97
- expect(screen.getByText('Analyzing text for highlights...')).toBeInTheDocument();
118
+ expect(screen.getByText('Annotating...')).toBeInTheDocument();
98
119
  });
99
120
 
100
121
  it('should pass null progress to AssistSection', () => {
@@ -136,16 +157,15 @@ describe('HighlightPanel + AssistSection Integration', () => {
136
157
  pendingAnnotation={null}
137
158
  isAssisting={false}
138
159
  progress={{
139
- stage: 'complete',
160
+ message: { code: 'complete-created', count: 3, kind: 'highlight' },
140
161
  percentage: 100,
141
- message: 'Complete! Created 14 highlights',
142
162
  }}
143
163
  annotateMode={true}
144
164
  />
145
165
  );
146
166
 
147
167
  // Progress should still be visible
148
- expect(screen.getByText('Complete! Created 14 highlights')).toBeInTheDocument();
168
+ expect(screen.getByText('Created 3 highlights')).toBeInTheDocument();
149
169
  // Form should NOT be visible
150
170
  expect(screen.queryByPlaceholderText('Enter custom instructions...')).not.toBeInTheDocument();
151
171
  });
@@ -157,19 +177,17 @@ describe('HighlightPanel + AssistSection Integration', () => {
157
177
  pendingAnnotation={null}
158
178
  isAssisting={true}
159
179
  progress={{
160
- stage: 'analyzing',
161
180
  percentage: 0,
162
- message: 'Analyzing...',
163
181
  requestParams: [
164
- { label: 'Instructions', value: 'Find important points' },
165
- { label: 'Density', value: '5' },
182
+ { label: 'instructions', value: 'Find important points' },
183
+ { label: 'density', value: '5' },
166
184
  ],
167
185
  }}
168
186
  annotateMode={true}
169
187
  />
170
188
  );
171
189
 
172
- expect(screen.getByText('paramsTitle')).toBeInTheDocument();
190
+ expect(screen.getByTestId('semiont-assist-params')).toBeInTheDocument();
173
191
  expect(screen.getByText('Find important points')).toBeInTheDocument();
174
192
  expect(screen.getByText('5')).toBeInTheDocument();
175
193
  });
@@ -211,15 +229,13 @@ describe('HighlightPanel + AssistSection Integration', () => {
211
229
  pendingAnnotation={null}
212
230
  isAssisting={true}
213
231
  progress={{
214
- stage: 'analyzing',
215
232
  percentage: 0,
216
- message: 'Analyzing...',
217
233
  }}
218
234
  annotateMode={true}
219
235
  />
220
236
  );
221
237
 
222
- expect(screen.getByText('Analyzing...')).toBeInTheDocument();
238
+ expect(screen.getByText('Annotating...')).toBeInTheDocument();
223
239
 
224
240
  // Switch to browse mode
225
241
  rerender(
@@ -228,16 +244,14 @@ describe('HighlightPanel + AssistSection Integration', () => {
228
244
  pendingAnnotation={null}
229
245
  isAssisting={true}
230
246
  progress={{
231
- stage: 'analyzing',
232
247
  percentage: 0,
233
- message: 'Analyzing...',
234
248
  }}
235
249
  annotateMode={false}
236
250
  />
237
251
  );
238
252
 
239
253
  // Progress should be hidden
240
- expect(screen.queryByText('Analyzing...')).not.toBeInTheDocument();
254
+ expect(screen.queryByText('Annotating...')).not.toBeInTheDocument();
241
255
  });
242
256
  });
243
257
 
@@ -264,16 +278,15 @@ describe('HighlightPanel + AssistSection Integration', () => {
264
278
  pendingAnnotation={null}
265
279
  isAssisting={false}
266
280
  progress={{
267
- stage: 'complete',
281
+ message: { code: 'complete-created', count: 3, kind: 'highlight' },
268
282
  percentage: 100,
269
- message: 'Done!',
270
283
  }}
271
284
  annotateMode={true}
272
285
  />
273
286
  );
274
287
 
275
288
  // Progress should be visible
276
- expect(screen.getByText('Done!')).toBeInTheDocument();
289
+ expect(screen.getByText('Created 3 highlights')).toBeInTheDocument();
277
290
  // Form should be hidden
278
291
  expect(screen.queryByPlaceholderText('Enter custom instructions...')).not.toBeInTheDocument();
279
292
  });
@@ -285,15 +298,15 @@ describe('HighlightPanel + AssistSection Integration', () => {
285
298
  pendingAnnotation={null}
286
299
  isAssisting={true}
287
300
  progress={{
288
- stage: 'started',
289
301
  percentage: 0,
290
- message: 'Starting...',
291
302
  }}
292
303
  annotateMode={true}
293
304
  />
294
305
  );
295
306
 
296
- expect(screen.getByText('Starting...')).toBeInTheDocument();
307
+ // Stage is the observable across non-terminal updates now that the
308
+ // status text is a single translated string (the wire carries codes).
309
+ expect(document.querySelector('.semiont-assist-progress')).toHaveAttribute('data-ended', 'false');
297
310
 
298
311
  // Update to analyzing
299
312
  rerender(
@@ -302,16 +315,14 @@ describe('HighlightPanel + AssistSection Integration', () => {
302
315
  pendingAnnotation={null}
303
316
  isAssisting={true}
304
317
  progress={{
305
- stage: 'analyzing',
306
318
  percentage: 50,
307
- message: 'Analyzing...',
308
319
  }}
309
320
  annotateMode={true}
310
321
  />
311
322
  );
312
323
 
313
- expect(screen.queryByText('Starting...')).not.toBeInTheDocument();
314
- expect(screen.getByText('Analyzing...')).toBeInTheDocument();
324
+ expect(document.querySelector('.semiont-assist-progress')).toHaveAttribute('data-ended', 'false');
325
+ expect(screen.getByText('Annotating...')).toBeInTheDocument();
315
326
 
316
327
  // Update to complete
317
328
  rerender(
@@ -320,16 +331,15 @@ describe('HighlightPanel + AssistSection Integration', () => {
320
331
  pendingAnnotation={null}
321
332
  isAssisting={false}
322
333
  progress={{
323
- stage: 'complete',
334
+ message: { code: 'complete-created', count: 3, kind: 'highlight' },
324
335
  percentage: 100,
325
- message: 'Complete!',
326
336
  }}
327
337
  annotateMode={true}
328
338
  />
329
339
  );
330
340
 
331
- expect(screen.queryByText('Analyzing...')).not.toBeInTheDocument();
332
- expect(screen.getByText('Complete!')).toBeInTheDocument();
341
+ expect(screen.queryByText('Annotating...')).not.toBeInTheDocument();
342
+ expect(screen.getByText('Created 3 highlights')).toBeInTheDocument();
333
343
  });
334
344
  });
335
345
 
@@ -341,16 +351,14 @@ describe('HighlightPanel + AssistSection Integration', () => {
341
351
  pendingAnnotation={null}
342
352
  isAssisting={true}
343
353
  progress={{
344
- stage: 'analyzing',
345
354
  percentage: 0,
346
- message: 'Analyzing...',
347
355
  }}
348
356
  annotateMode={true}
349
357
  />
350
358
  );
351
359
 
352
360
  // Both progress and highlights should be visible
353
- expect(screen.getByText('Analyzing...')).toBeInTheDocument();
361
+ expect(screen.getByText('Annotating...')).toBeInTheDocument();
354
362
  expect(screen.getByText('Highlights')).toBeInTheDocument();
355
363
  });
356
364
 
@@ -94,6 +94,24 @@ describe('ReferenceEntry', () => {
94
94
  mockGetEntityTypes.mockReturnValue([]);
95
95
  });
96
96
 
97
+ // RESOLUTION-SPARKLE D6: a just-resolved reference announces itself on the
98
+ // panel entry's icon with the same `.annotation-sparkle` glow the document
99
+ // span uses. The host decides WHEN (membership in the sparkle set); the
100
+ // entry only renders the boolean.
101
+ describe('Resolution sparkle', () => {
102
+ it('carries the sparkle animation on the icon when sparkle is set', () => {
103
+ const { container } = renderEntry({ sparkle: true });
104
+
105
+ expect(container.querySelector('.semiont-reference-icon')).toHaveClass('annotation-sparkle');
106
+ });
107
+
108
+ it('does not sparkle by default', () => {
109
+ const { container } = renderEntry();
110
+
111
+ expect(container.querySelector('.semiont-reference-icon')).not.toHaveClass('annotation-sparkle');
112
+ });
113
+ });
114
+
97
115
  describe('Rendering', () => {
98
116
  it('should render the selected text in quotes', () => {
99
117
  renderEntry();
@@ -172,6 +190,29 @@ describe('ReferenceEntry', () => {
172
190
 
173
191
  expect(screen.getByText(/My Linked Document/)).toBeInTheDocument();
174
192
  });
193
+
194
+ it('a resource-level derivation headlines Derived, never the generic type label', () => {
195
+ // The provenance edge minted by resource-focus generation: no selector
196
+ // (nothing to quote), resolved body naming the derived resource. The
197
+ // generic "Annotation" label said nothing — the qualifier says what
198
+ // the entry IS; the link line below says what it points at. Inference
199
+ // is from shape (the wire vocabulary deliberately has no 'deriving'
200
+ // purpose); the unresolved case keeps the plain type label.
201
+ mockGetAnnotationExactText.mockReturnValue('');
202
+ mockIsBodyResolved.mockReturnValue(true);
203
+ mockGetBodySource.mockReturnValue('gen-doc');
204
+
205
+ const provenanceRef = {
206
+ ...createMockReference({ target: { source: 'resource-1' } }),
207
+ _resolvedDocumentName: 'generated from Cedar County, Iowa',
208
+ };
209
+
210
+ renderEntry({ reference: provenanceRef as Annotation });
211
+
212
+ expect(screen.getByText('ReferencesPanel.derived')).toBeInTheDocument();
213
+ expect(screen.queryByText('Annotation')).not.toBeInTheDocument();
214
+ expect(screen.getByText(/generated from Cedar County, Iowa/)).toBeInTheDocument();
215
+ });
175
216
  });
176
217
 
177
218
  describe('Entity types', () => {
@@ -236,7 +277,6 @@ describe('ReferenceEntry', () => {
236
277
 
237
278
  expect(clickHandler).toHaveBeenCalledWith({
238
279
  annotationId: 'ref-1',
239
- motivation: 'linking',
240
280
  });
241
281
 
242
282
  subscription.unsubscribe();
@@ -82,7 +82,7 @@ describe('ReferencesPanel — headless (session prop, no providers)', () => {
82
82
  expect(entryText).toBeInTheDocument();
83
83
 
84
84
  fireEvent.click(entryText);
85
- expect(client.browse.click).toHaveBeenCalledWith('ref-1', 'linking');
85
+ expect(client.browse.click).toHaveBeenCalledWith('ref-1');
86
86
  });
87
87
 
88
88
  describe('incoming references — terminal load failure', () => {
@@ -4,7 +4,7 @@ import { render, screen, waitFor } from '@testing-library/react';
4
4
  import userEvent from '@testing-library/user-event';
5
5
  import '@testing-library/jest-dom';
6
6
  import { ReferencesPanel } from '../ReferencesPanel';
7
- import type { EventBus } from '@semiont/core';
7
+ import type { Annotation, AnnotationId, EventBus } from '@semiont/core';
8
8
  import type { SemiontSession } from '@semiont/sdk';
9
9
  import { createTestSemiontWrapper } from '../../../../test-utils';
10
10
 
@@ -66,6 +66,12 @@ vi.mock('../../../../contexts/TranslationContext', () => ({
66
66
  includeDescriptiveReferences: 'Include descriptive references',
67
67
  descriptiveReferencesTooltip: 'Also find phrases like \'the CEO\', \'the tech giant\', \'the physicist\' (in addition to names)',
68
68
  cancel: 'Cancel',
69
+ annotating: 'Annotating...',
70
+ // CLEAN-PROGRESS D3: the widget's own strings come from the
71
+ // AssistProgress namespace now, not from this panel's.
72
+ inProgress: 'Annotating...',
73
+ complete: 'Annotation complete!',
74
+ failed: 'Annotation failed',
69
75
  };
70
76
  let result = translations[key] || key;
71
77
  // Replace {count} with actual count value if provided
@@ -112,6 +118,38 @@ describe('ReferencesPanel Component', () => {
112
118
  vi.restoreAllMocks();
113
119
  });
114
120
 
121
+ // RESOLUTION-SPARKLE D6: the panel threads the host's sparkle set down to
122
+ // the entries — exactly the ids in the set glow, nothing else.
123
+ describe('Resolution sparkle threading', () => {
124
+ const linkingReference = (id: string): Annotation => ({
125
+ '@context': 'http://www.w3.org/ns/anno.jsonld',
126
+ id: id as AnnotationId,
127
+ type: 'Annotation',
128
+ motivation: 'linking',
129
+ created: '2026-08-21T12:00:00Z',
130
+ modified: '2026-08-21T12:00:00Z',
131
+ target: {
132
+ source: 'res-1',
133
+ selector: { type: 'TextQuoteSelector', exact: `text of ${id}` },
134
+ },
135
+ body: { type: 'SpecificResource', source: 'linked-doc', purpose: 'linking' },
136
+ });
137
+
138
+ it('sparkles exactly the entries named by sparkleAnnotationIds', () => {
139
+ const { container } = renderWithEventBus(
140
+ <ReferencesPanel
141
+ {...panelProps()}
142
+ annotations={[linkingReference('ann-dark'), linkingReference('ann-lit')]}
143
+ sparkleAnnotationIds={new Set(['ann-lit'])}
144
+ />,
145
+ );
146
+
147
+ const sparkling = container.querySelectorAll('.semiont-reference-icon.annotation-sparkle');
148
+ expect(sparkling).toHaveLength(1);
149
+ expect(sparkling[0]!.closest('.semiont-annotation-entry')).toHaveTextContent('text of ann-lit');
150
+ });
151
+ });
152
+
115
153
  describe('Rendering', () => {
116
154
  it('should render panel with title', () => {
117
155
  renderWithEventBus(<ReferencesPanel {...panelProps()} />);
@@ -325,7 +363,7 @@ describe('ReferencesPanel Component', () => {
325
363
  <ReferencesPanel
326
364
  {...panelProps()}
327
365
  isAssisting={true}
328
- progress={{ stage: 'analyzing', percentage: 0, message: 'Detecting references...', completedEntityTypes: [] }}
366
+ progress={{ percentage: 0, completedItems: [] }}
329
367
  />
330
368
  );
331
369
 
@@ -335,10 +373,8 @@ describe('ReferencesPanel Component', () => {
335
373
  {...panelProps()}
336
374
  isAssisting={false}
337
375
  progress={{
338
- stage: 'complete',
339
376
  percentage: 100,
340
- message: 'Annotation complete',
341
- completedEntityTypes: [{ entityType: 'Person', foundCount: 5 }],
377
+ completedItems: [{ value: 'Person', foundCount: 5 }],
342
378
  }}
343
379
  />
344
380
  );
@@ -378,21 +414,19 @@ describe('ReferencesPanel Component', () => {
378
414
  <ReferencesPanel
379
415
  {...panelProps()}
380
416
  isAssisting={true}
381
- progress={{ stage: 'analyzing', percentage: 0, message: 'Detecting references...', completedEntityTypes: [] }}
417
+ progress={{ percentage: 0, completedItems: [] }}
382
418
  />
383
419
  );
384
420
 
385
- expect(screen.getByText('Detecting references...')).toBeInTheDocument();
421
+ expect(screen.getByText('Annotating...')).toBeInTheDocument();
386
422
  });
387
423
 
388
424
  it('should pass progress data to widget', () => {
389
425
  const progress = {
390
- stage: 'complete',
391
426
  percentage: 100,
392
- message: 'Annotation complete',
393
- completedEntityTypes: [
394
- { entityType: 'Person', foundCount: 5 },
395
- { entityType: 'Organization', foundCount: 3 },
427
+ completedItems: [
428
+ { value: 'Person', foundCount: 5 },
429
+ { value: 'Organization', foundCount: 3 },
396
430
  ],
397
431
  };
398
432
 
@@ -419,10 +453,8 @@ describe('ReferencesPanel Component', () => {
419
453
  {...panelProps()}
420
454
  isAssisting={false}
421
455
  progress={{
422
- stage: 'complete',
423
456
  percentage: 100,
424
- message: 'Annotation complete',
425
- completedEntityTypes: [{ entityType: 'Person', foundCount: 5 }],
457
+ completedItems: [{ value: 'Person', foundCount: 5 }],
426
458
  }}
427
459
  />
428
460
  );
@@ -440,7 +472,7 @@ describe('ReferencesPanel Component', () => {
440
472
  <ReferencesPanel
441
473
  {...panelProps()}
442
474
  isAssisting={true}
443
- progress={{ stage: 'analyzing', percentage: 0, message: 'Detecting references...', completedEntityTypes: [] }}
475
+ progress={{ percentage: 0, completedItems: [] }}
444
476
  />
445
477
  );
446
478
 
@@ -453,13 +485,12 @@ describe('ReferencesPanel Component', () => {
453
485
  <ReferencesPanel
454
486
  {...panelProps()}
455
487
  isAssisting={true}
456
- progress={{ stage: 'analyzing', percentage: 0, message: 'Detecting references...', completedEntityTypes: [] }}
488
+ progress={{ percentage: 0, completedItems: [] }}
457
489
  />
458
490
  );
459
491
 
460
- // Real AssistProgress titles the cancel button with t('cancelAnnotation')
461
- // (the mock translator echoes unknown keys).
462
- const cancelButton = screen.getByTitle('cancelAnnotation');
492
+ // The control's label comes from the AssistProgress namespace's `cancel`.
493
+ const cancelButton = screen.getByTitle('Cancel');
463
494
  expect(cancelButton).toBeInTheDocument();
464
495
  });
465
496
  });
@@ -471,12 +502,10 @@ describe('ReferencesPanel Component', () => {
471
502
  {...panelProps()}
472
503
  isAssisting={false}
473
504
  progress={{
474
- stage: 'complete',
475
505
  percentage: 100,
476
- message: 'Annotation complete',
477
- completedEntityTypes: [
478
- { entityType: 'Person', foundCount: 5 },
479
- { entityType: 'Organization', foundCount: 3 },
506
+ completedItems: [
507
+ { value: 'Person', foundCount: 5 },
508
+ { value: 'Organization', foundCount: 3 },
480
509
  ],
481
510
  }}
482
511
  />
@@ -501,10 +530,8 @@ describe('ReferencesPanel Component', () => {
501
530
  {...panelProps()}
502
531
  isAssisting={false}
503
532
  progress={{
504
- stage: 'complete',
505
533
  percentage: 100,
506
- message: 'Annotation complete',
507
- completedEntityTypes: [{ entityType: 'Person', foundCount: 5 }],
534
+ completedItems: [{ value: 'Person', foundCount: 5 }],
508
535
  }}
509
536
  />
510
537
  );
@@ -521,10 +548,8 @@ describe('ReferencesPanel Component', () => {
521
548
  {...panelProps()}
522
549
  isAssisting={false}
523
550
  progress={{
524
- stage: 'complete',
525
551
  percentage: 100,
526
- message: 'Annotation complete',
527
- completedEntityTypes: [{ entityType: 'Person', foundCount: 5 }],
552
+ completedItems: [{ value: 'Person', foundCount: 5 }],
528
553
  }}
529
554
  />
530
555
  );
@@ -541,10 +566,8 @@ describe('ReferencesPanel Component', () => {
541
566
  {...panelProps()}
542
567
  isAssisting={false}
543
568
  progress={{
544
- stage: 'complete',
545
569
  percentage: 100,
546
- message: 'Annotation complete',
547
- completedEntityTypes: [{ entityType: 'Person', foundCount: 5 }],
570
+ completedItems: [{ value: 'Person', foundCount: 5 }],
548
571
  }}
549
572
  />
550
573
  );
@@ -564,10 +587,8 @@ describe('ReferencesPanel Component', () => {
564
587
  {...panelProps()}
565
588
  isAssisting={false}
566
589
  progress={{
567
- stage: 'complete',
568
590
  percentage: 100,
569
- message: 'Annotation complete',
570
- completedEntityTypes: [{ entityType: 'Person', foundCount: 5 }],
591
+ completedItems: [{ value: 'Person', foundCount: 5 }],
571
592
  }}
572
593
  />
573
594
  );
@@ -587,10 +608,8 @@ describe('ReferencesPanel Component', () => {
587
608
  {...panelProps()}
588
609
  isAssisting={false}
589
610
  progress={{
590
- stage: 'complete',
591
611
  percentage: 100,
592
- message: 'Annotation complete',
593
- completedEntityTypes: [],
612
+ completedItems: [],
594
613
  }}
595
614
  />
596
615
  );
@@ -615,12 +634,12 @@ describe('ReferencesPanel Component', () => {
615
634
  <ReferencesPanel
616
635
  {...panelProps()}
617
636
  isAssisting={true}
618
- progress={{ stage: 'analyzing', percentage: 0, message: 'Detecting references...', completedEntityTypes: [] }}
637
+ progress={{ percentage: 0, completedItems: [] }}
619
638
  />
620
639
  );
621
640
 
622
641
  // Detecting state
623
- expect(screen.getByText('Detecting references...')).toBeInTheDocument();
642
+ expect(screen.getByText('Annotating...')).toBeInTheDocument();
624
643
  expect(screen.queryByText('Select entity types')).not.toBeInTheDocument();
625
644
  });
626
645
 
@@ -629,12 +648,12 @@ describe('ReferencesPanel Component', () => {
629
648
  <ReferencesPanel
630
649
  {...panelProps()}
631
650
  isAssisting={true}
632
- progress={{ stage: 'analyzing', percentage: 0, message: 'Detecting references...', completedEntityTypes: [] }}
651
+ progress={{ percentage: 0, completedItems: [] }}
633
652
  />
634
653
  );
635
654
 
636
655
  // Detecting
637
- expect(screen.getByText('Detecting references...')).toBeInTheDocument();
656
+ expect(screen.getByText('Annotating...')).toBeInTheDocument();
638
657
 
639
658
  // Complete - first trigger useEffect to copy to lastDetectionLog
640
659
  rerender(
@@ -642,10 +661,8 @@ describe('ReferencesPanel Component', () => {
642
661
  {...panelProps()}
643
662
  isAssisting={false}
644
663
  progress={{
645
- stage: 'complete',
646
664
  percentage: 100,
647
- message: 'Annotation complete',
648
- completedEntityTypes: [{ entityType: 'Person', foundCount: 5 }],
665
+ completedItems: [{ value: 'Person', foundCount: 5 }],
649
666
  }}
650
667
  />
651
668
  );
@@ -655,7 +672,7 @@ describe('ReferencesPanel Component', () => {
655
672
  <ReferencesPanel {...panelProps()} isAssisting={false} progress={null} />
656
673
  );
657
674
 
658
- expect(screen.queryByText('Annotation complete')).not.toBeInTheDocument();
675
+ expect(screen.queryByText('Annotation complete!')).not.toBeInTheDocument();
659
676
  // Both log and selection UI should be visible
660
677
  expect(screen.getByText('Person:')).toBeInTheDocument();
661
678
  expect(screen.getByText('Select entity types')).toBeInTheDocument();
@@ -667,10 +684,8 @@ describe('ReferencesPanel Component', () => {
667
684
  {...panelProps()}
668
685
  isAssisting={false}
669
686
  progress={{
670
- stage: 'complete',
671
687
  percentage: 100,
672
- message: 'Annotation complete',
673
- completedEntityTypes: [{ entityType: 'Person', foundCount: 5 }],
688
+ completedItems: [{ value: 'Person', foundCount: 5 }],
674
689
  }}
675
690
  />
676
691
  );
@@ -761,10 +776,8 @@ describe('ReferencesPanel Component', () => {
761
776
  {...panelProps()}
762
777
  isAssisting={false}
763
778
  progress={{
764
- stage: 'complete',
765
779
  percentage: 100,
766
- message: 'Annotation complete',
767
- completedEntityTypes: [{ entityType: 'Person', foundCount: 0 }],
780
+ completedItems: [{ value: 'Person', foundCount: 0 }],
768
781
  }}
769
782
  />
770
783
  );