@semiont/react-ui 0.5.27 → 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 (162) hide show
  1. package/dist/{PdfAnnotationCanvas.client-EVUPTUWZ.js → PdfAnnotationCanvas.client-C2IGG4SW.js} +31 -4
  2. package/dist/{ar-OU3DQGC6.js → ar-FABPTJVB.js} +39 -23
  3. package/dist/{bn-PHWCR6AZ.js → bn-LKP6BDMH.js} +39 -23
  4. package/dist/{chunk-PCRRBU7H.js → chunk-2GOHTTHW.js} +39 -23
  5. package/dist/{chunk-5VDTWRXJ.js → chunk-2YHEE63S.js} +31 -31
  6. package/dist/{cs-NEXYZ62I.js → cs-YQYNWHRG.js} +39 -23
  7. package/dist/{da-FAT43YCU.js → da-QHZOYKRY.js} +39 -23
  8. package/dist/{de-KRQ3WBCU.js → de-GKA7RD7J.js} +39 -23
  9. package/dist/{el-Q4IU3EKC.js → el-45T257AL.js} +39 -23
  10. package/dist/{en-2KADE7N4.js → en-RVW5EQ66.js} +2 -2
  11. package/dist/{es-2IO3R2MK.js → es-AVER7RU4.js} +39 -23
  12. package/dist/{fa-Q5GOQFXX.js → fa-K3VPK3O2.js} +39 -23
  13. package/dist/{fi-R6NMRWBE.js → fi-5NEKF7EB.js} +39 -23
  14. package/dist/{fr-QY4D5E6J.js → fr-FUMNDLBZ.js} +39 -23
  15. package/dist/{he-X6Y77XHY.js → he-3JGNA3PR.js} +39 -23
  16. package/dist/{hi-XL7IOEQM.js → hi-IJY375DF.js} +39 -23
  17. package/dist/{id-QZ4ZZS67.js → id-LWHKJ7ZD.js} +39 -23
  18. package/dist/index.css +279 -74
  19. package/dist/index.d.ts +170 -145
  20. package/dist/index.js +2743 -2365
  21. package/dist/{it-ME2Q7OB6.js → it-EBVOV4RW.js} +39 -23
  22. package/dist/{ja-HX7QASRI.js → ja-KWRIX2NF.js} +39 -23
  23. package/dist/{ko-EQO5AHAV.js → ko-L5CJMFDS.js} +39 -23
  24. package/dist/{ms-UILFSF3I.js → ms-LSNMJDR2.js} +39 -23
  25. package/dist/{nl-NNI45PMK.js → nl-ZB32MB7U.js} +39 -23
  26. package/dist/{no-MAL5F6P6.js → no-4GTNY7M5.js} +39 -23
  27. package/dist/{pl-4RMY6JAJ.js → pl-LUHBLTHB.js} +39 -23
  28. package/dist/{pt-VQH2X3QQ.js → pt-C4H3UNQ6.js} +39 -23
  29. package/dist/{ro-XXCQO2OG.js → ro-GGITS5V4.js} +39 -23
  30. package/dist/{sv-7Z6EJ6U4.js → sv-T56RTLBP.js} +39 -23
  31. package/dist/test-utils.js +2 -2
  32. package/dist/{th-L3DXXYVQ.js → th-22X2IWCB.js} +39 -23
  33. package/dist/{tr-P3DFVLFJ.js → tr-77TFG62H.js} +39 -23
  34. package/dist/{uk-7C5D3PXS.js → uk-MIIL6NXT.js} +39 -23
  35. package/dist/{vi-ZLTLEO7P.js → vi-7JYOIGNV.js} +39 -23
  36. package/dist/{zh-5FHVWDIN.js → zh-ID6DRYU4.js} +39 -23
  37. package/package.json +9 -8
  38. package/src/components/AssistProgress.tsx +36 -2
  39. package/src/components/CodeMirrorRenderer.tsx +8 -8
  40. package/src/components/__tests__/AssistProgress.test.tsx +59 -0
  41. package/src/components/modals/ComposeStep.tsx +218 -0
  42. package/src/components/modals/ConfigureGatherStep.tsx +10 -18
  43. package/src/components/modals/ConfigureGenerationStep.tsx +35 -19
  44. package/src/components/modals/ConfigureSearchStep.tsx +19 -0
  45. package/src/components/modals/ContextSummary.tsx +185 -72
  46. package/src/components/modals/CorpusPane.tsx +75 -0
  47. package/src/components/modals/DiscardPrompt.tsx +38 -0
  48. package/src/components/modals/GatherContextStep.tsx +237 -107
  49. package/src/components/modals/ReferenceWizardModal.tsx +238 -50
  50. package/src/components/modals/ResourceGenerateModal.tsx +216 -108
  51. package/src/components/modals/SearchModal.css +337 -101
  52. package/src/components/modals/SearchResultsStep.tsx +61 -68
  53. package/src/components/modals/WizardFooter.tsx +7 -1
  54. package/src/components/modals/__tests__/ComposeStep.test.tsx +152 -0
  55. package/src/components/modals/__tests__/ConfigureGatherStep.test.tsx +14 -26
  56. package/src/components/modals/__tests__/ConfigureGenerationStep.test.tsx +35 -0
  57. package/src/components/modals/__tests__/ConfigureSearchStep.test.tsx +24 -1
  58. package/src/components/modals/__tests__/GatherContextStep.resource.test.tsx +463 -25
  59. package/src/components/modals/__tests__/ReferenceWizardModal.test.tsx +417 -38
  60. package/src/components/modals/__tests__/ResourceGenerateModal.test.tsx +276 -85
  61. package/src/components/modals/__tests__/SearchResultsStep.test.tsx +61 -0
  62. package/src/components/modals/__tests__/WizardFooter.test.tsx +113 -4
  63. package/src/components/pdf-annotation/PdfAnnotationCanvas.tsx +34 -1
  64. package/src/components/pdf-annotation/__tests__/PdfAnnotationCanvas.test.tsx +38 -1
  65. package/src/components/resource/AnnotateView.tsx +3 -3
  66. package/src/components/resource/BrowseView.tsx +5 -5
  67. package/src/components/resource/ResourceViewer.tsx +4 -4
  68. package/src/components/resource/__tests__/AnnotateView.embeddable.test.tsx +1 -1
  69. package/src/components/resource/__tests__/BrowseView.embeddable.test.tsx +1 -1
  70. package/src/components/resource/__tests__/BrowseView.test.tsx +9 -9
  71. package/src/components/resource/annotate-renderers.tsx +3 -3
  72. package/src/components/resource/panels/AssistSection.css +35 -0
  73. package/src/components/resource/panels/ReferenceEntry.tsx +9 -2
  74. package/src/components/resource/panels/ReferencesPanel.tsx +4 -0
  75. package/src/components/resource/panels/ResourceInfoPanel.tsx +89 -20
  76. package/src/components/resource/panels/UnifiedAnnotationsPanel.tsx +7 -2
  77. package/src/components/resource/panels/__tests__/ReferenceEntry.test.tsx +41 -0
  78. package/src/components/resource/panels/__tests__/ReferencesPanel.test.tsx +33 -1
  79. package/src/components/resource/panels/__tests__/ResourceInfoPanel.test.tsx +148 -6
  80. package/src/features/resource-compose/__tests__/ResourceComposePage.test.tsx +0 -65
  81. package/src/features/resource-compose/components/ResourceComposePage.tsx +17 -130
  82. package/src/features/resource-compose/state/__tests__/compose-page-state-unit.test.ts +1 -100
  83. package/src/features/resource-compose/state/compose-page-state-unit.ts +5 -57
  84. package/src/features/resource-viewer/__tests__/ResourceViewerPage.test.tsx +71 -15
  85. package/src/features/resource-viewer/components/ResourceViewerPage.tsx +133 -59
  86. package/src/styles/core/forms.css +35 -8
  87. package/src/styles/features/resource-viewer.css +0 -22
  88. package/src/styles/features/resource.css +0 -4
  89. package/translations/ar.json +38 -22
  90. package/translations/bn.json +38 -22
  91. package/translations/cs.json +38 -22
  92. package/translations/da.json +38 -22
  93. package/translations/de.json +38 -22
  94. package/translations/el.json +38 -22
  95. package/translations/en.json +38 -22
  96. package/translations/es.json +38 -22
  97. package/translations/fa.json +38 -22
  98. package/translations/fi.json +38 -22
  99. package/translations/fr.json +38 -22
  100. package/translations/he.json +38 -22
  101. package/translations/hi.json +38 -22
  102. package/translations/id.json +38 -22
  103. package/translations/it.json +38 -22
  104. package/translations/ja.json +38 -22
  105. package/translations/ko.json +38 -22
  106. package/translations/ms.json +38 -22
  107. package/translations/nl.json +38 -22
  108. package/translations/no.json +38 -22
  109. package/translations/pl.json +38 -22
  110. package/translations/pt.json +38 -22
  111. package/translations/ro.json +38 -22
  112. package/translations/sv.json +38 -22
  113. package/translations/th.json +38 -22
  114. package/translations/tr.json +38 -22
  115. package/translations/uk.json +38 -22
  116. package/translations/vi.json +38 -22
  117. package/translations/zh.json +38 -22
  118. package/dist/PdfAnnotationCanvas.client-EVUPTUWZ.js.map +0 -1
  119. package/dist/PdfAnnotationCanvas.client-TGDPPGXJ.css.map +0 -1
  120. package/dist/ar-OU3DQGC6.js.map +0 -1
  121. package/dist/bn-PHWCR6AZ.js.map +0 -1
  122. package/dist/chunk-5VDTWRXJ.js.map +0 -1
  123. package/dist/chunk-BTUG3VJJ.js.map +0 -1
  124. package/dist/chunk-O23TLLXW.js.map +0 -1
  125. package/dist/chunk-PCRRBU7H.js.map +0 -1
  126. package/dist/chunk-QT7LYM72.js.map +0 -1
  127. package/dist/chunk-VXASXU4K.js.map +0 -1
  128. package/dist/cs-NEXYZ62I.js.map +0 -1
  129. package/dist/da-FAT43YCU.js.map +0 -1
  130. package/dist/de-KRQ3WBCU.js.map +0 -1
  131. package/dist/el-Q4IU3EKC.js.map +0 -1
  132. package/dist/en-2KADE7N4.js.map +0 -1
  133. package/dist/es-2IO3R2MK.js.map +0 -1
  134. package/dist/fa-Q5GOQFXX.js.map +0 -1
  135. package/dist/fi-R6NMRWBE.js.map +0 -1
  136. package/dist/fr-QY4D5E6J.js.map +0 -1
  137. package/dist/he-X6Y77XHY.js.map +0 -1
  138. package/dist/hi-XL7IOEQM.js.map +0 -1
  139. package/dist/id-QZ4ZZS67.js.map +0 -1
  140. package/dist/index.css.map +0 -1
  141. package/dist/index.js.map +0 -1
  142. package/dist/integrations/css-modules-helper.js.map +0 -1
  143. package/dist/integrations/styled-components-theme.js.map +0 -1
  144. package/dist/it-ME2Q7OB6.js.map +0 -1
  145. package/dist/ja-HX7QASRI.js.map +0 -1
  146. package/dist/ko-EQO5AHAV.js.map +0 -1
  147. package/dist/ms-UILFSF3I.js.map +0 -1
  148. package/dist/nl-NNI45PMK.js.map +0 -1
  149. package/dist/no-MAL5F6P6.js.map +0 -1
  150. package/dist/pl-4RMY6JAJ.js.map +0 -1
  151. package/dist/pt-VQH2X3QQ.js.map +0 -1
  152. package/dist/ro-XXCQO2OG.js.map +0 -1
  153. package/dist/sv-7Z6EJ6U4.js.map +0 -1
  154. package/dist/test-utils.css.map +0 -1
  155. package/dist/test-utils.js.map +0 -1
  156. package/dist/th-L3DXXYVQ.js.map +0 -1
  157. package/dist/tr-P3DFVLFJ.js.map +0 -1
  158. package/dist/uk-7C5D3PXS.js.map +0 -1
  159. package/dist/vi-ZLTLEO7P.js.map +0 -1
  160. package/dist/zh-5FHVWDIN.js.map +0 -1
  161. package/src/components/modals/ResourceSearchModal.tsx +0 -224
  162. package/src/components/modals/__tests__/ResourceSearchModal.test.tsx +0 -163
@@ -6,12 +6,12 @@
6
6
  */
7
7
 
8
8
  import React, { useState, useEffect, useCallback } from 'react';
9
- import { assistProgressTranslations } from '../../../lib/assist-progress-copy';
10
9
  import { useResourceViewedReport } from '../hooks/useResourceViewedReport';
11
- import type { components, ResourceDescriptor, ResourceId, GatheredContext, EventMap } from '@semiont/core';
10
+ import type { components, ResourceDescriptor, ResourceId, EventMap } from '@semiont/core';
12
11
  import type { ConnectionState } from '@semiont/core';
13
12
  import { annotationId } from '@semiont/core';
14
- import { getLanguage, getPrimaryRepresentation, getPrimaryMediaType, capabilitiesOf } from '@semiont/core';
13
+ import type { ComposeParams } from '../../../components/modals/ComposeStep';
14
+ import { getLanguage, getPrimaryRepresentation, getPrimaryMediaType, capabilitiesOf, extensionForMediaType } from '@semiont/core';
15
15
  import { ANNOTATORS } from '@semiont/react-ui';
16
16
  import { ErrorBoundary } from '@semiont/react-ui';
17
17
  import { AnnotationHistory } from '@semiont/react-ui';
@@ -30,6 +30,7 @@ import { useCollaborators } from '../../../hooks/useCollaborators';
30
30
  import { mediaUrl } from '../../../lib/media-url';
31
31
  import { useToast } from '../../../components/Toast';
32
32
  import { useOutcomeToasts } from '../../../hooks/useOutcomeToasts';
33
+ import { useGenerationArrival } from '../../../hooks/useGenerationArrival';
33
34
  import { useTheme } from '../../../contexts/ThemeContext';
34
35
  import { useLineNumbers } from '../../../contexts/LineNumbersContext';
35
36
  import { useHoverDelay } from '../../../hooks/useHoverDelay';
@@ -45,7 +46,6 @@ import { useShellStateUnit } from '../../../hooks/useShellStateUnit';
45
46
  import { useTranslations } from '../../../contexts/TranslationContext';
46
47
  import { ReferenceWizardModal } from '../../../components/modals/ReferenceWizardModal';
47
48
  import { ResourceGenerateModal } from '../../../components/modals/ResourceGenerateModal';
48
- import { AssistProgress } from '../../../components/AssistProgress';
49
49
  import type { GenerationConfig } from '../../../components/modals/ConfigureGenerationStep';
50
50
 
51
51
  type SemiontResource = ResourceDescriptor;
@@ -120,6 +120,7 @@ export interface ResourceViewerPageProps {
120
120
  * @subscribes yield:clone - Clone the current resource
121
121
  * @subscribes beckon:sparkle - Trigger sparkle animation
122
122
  * @subscribes mark:added - Annotation was created (sparkle)
123
+ * @subscribes mark:body-updated - Reference resolved via a linking-add operation (sparkle, both loci)
123
124
  * @subscribes browse:resource-open - Open a resource in the viewer (local links + the launcher's tour verbs)
124
125
  * @subscribes browse:entity-type-clicked - Navigate filtered by entity type
125
126
  *
@@ -143,7 +144,6 @@ export function ResourceViewerPage({
143
144
  // Translations
144
145
  const tw = useTranslations('ReferenceWizard');
145
146
  const tg = useTranslations('ResourceGenerate');
146
- const ta = useTranslations('AssistProgress');
147
147
 
148
148
  const browser = useSemiont();
149
149
  const session = useObservable(browser.activeSession$);
@@ -177,7 +177,7 @@ export function ResourceViewerPage({
177
177
  const { theme } = useTheme();
178
178
  const { showLineNumbers } = useLineNumbers();
179
179
  const { hoverDelayMs } = useHoverDelay();
180
- const { triggerSparkleAnimation, clearNewAnnotationId, newAnnotationIds } = useResourceAnnotations();
180
+ const { triggerSparkleAnimation, clearSparkle, sparkleAnnotationIds } = useResourceAnnotations();
181
181
 
182
182
  // Render mode chooses the content path: 'text' decodes inline; 'image'
183
183
  // and 'pdf' go through the media-token (binary) path. 'none'/registry-miss
@@ -240,9 +240,27 @@ export function ResourceViewerPage({
240
240
  const onScrollCompleted = stateUnit?.browse.onScrollCompleted;
241
241
  const generationProgress = useObservable(stateUnit?.yield.progress$) ?? null;
242
242
  const isGenerating = useObservable(stateUnit?.yield.isGenerating$) ?? false;
243
+ const generationOutcome = useObservable(stateUnit?.yield.outcome$) ?? null;
244
+
245
+ // GENERATION-ARRIVAL P2: a completion witnessed on this page reveals the
246
+ // derivation edge the worker minted — the annotations panel opens on
247
+ // References, scrolls to the provenance reference, and its sparkle is
248
+ // re-armed (the mark:added glow burned its window unseen). Never navigates
249
+ // (A2); a held outcome on remount stays quiet (D6, inside the hook).
250
+ const handleGenerationArrival = useCallback((annId: string) => {
251
+ browser.emit('panel:open', { panel: 'annotations', scrollToAnnotationId: annId, motivation: 'linking' });
252
+ triggerSparkleAnimation(annId);
253
+ }, [browser, triggerSparkleAnimation]);
254
+ useGenerationArrival(generationOutcome, annotations, handleGenerationArrival);
255
+
243
256
  const gatherContext = useObservable(stateUnit?.gather.context$) ?? null;
244
257
  const gatherLoading = useObservable(stateUnit?.gather.loading$) ?? false;
245
258
  const gatherError = useObservable(stateUnit?.gather.error$) ?? null;
259
+ // Resource-gather slots (FLOW-LIFECYCLE-CONVERGENCE D2a: separate from the
260
+ // annotation slots above — the two gathers can be live at once).
261
+ const resourceGatherContext = useObservable(stateUnit?.gather.resourceContext$) ?? null;
262
+ const resourceGatherLoading = useObservable(stateUnit?.gather.resourceLoading$) ?? false;
263
+ const resourceGatherError = useObservable(stateUnit?.gather.resourceError$) ?? null;
246
264
  const wizardState = useObservable(stateUnit?.wizard$);
247
265
  const wizardOpen = wizardState?.open ?? false;
248
266
  const wizardAnnotationId = wizardState?.annotationId ?? null;
@@ -256,7 +274,7 @@ export function ResourceViewerPage({
256
274
  }, [stateUnit]);
257
275
 
258
276
  const handleWizardGenerateSubmit = useCallback((referenceId: string, config: GenerationConfig) => {
259
- clearNewAnnotationId(annotationId(referenceId));
277
+ clearSparkle(annotationId(referenceId));
260
278
  stateUnit?.yield.generate(config.context, {
261
279
  title: config.title,
262
280
  storageUri: config.storagePath,
@@ -269,7 +287,7 @@ export function ResourceViewerPage({
269
287
  temperature: config.temperature,
270
288
  maxTokens: config.maxTokens,
271
289
  });
272
- }, [stateUnit, clearNewAnnotationId, resource]);
290
+ }, [stateUnit, clearSparkle, resource]);
273
291
 
274
292
  // Resource-generate flow (GENERATE-FROM-BUTTON): drive the SAME yield progress$
275
293
  // the annotation path uses so the full `AssistProgress` widget shows — NOT a
@@ -301,26 +319,43 @@ export function ResourceViewerPage({
301
319
  }
302
320
  }, [rUri, semiont, showSuccess, showError]);
303
321
 
304
- const handleWizardComposeNavigate = useCallback((
305
- context: GatheredContext,
306
- annId: string,
307
- resId: string,
308
- title: string,
309
- entTypes: string[],
310
- ) => {
311
- // Store context in sessionStorage for the compose page
312
- sessionStorage.setItem(`gather-context:${annId}`, JSON.stringify(context));
313
- const params = new URLSearchParams({
314
- annotationUri: annId,
315
- sourceDocumentId: resId,
316
- name: title,
317
- entityTypes: entTypes.join(','),
318
- });
319
- browser.emit('nav:push', {
320
- path: `/know/compose?${params.toString()}`,
321
- reason: 'compose-from-wizard',
322
- });
323
- }, [browser]);
322
+ // COMPOSE-IN-MODAL P3: create-and-link, in place. The old flow stashed the
323
+ // context in sessionStorage and navigated to the compose page; the modal
324
+ // already holds the context, so the side-channel dies with the mode.
325
+ // Text-only by design — uploads stay on the standalone compose page.
326
+ const handleWizardComposeSubmit = useCallback(async (referenceId: string, params: ComposeParams) => {
327
+ if (!semiont) throw new Error('No active session');
328
+ try {
329
+ const format = 'text/markdown';
330
+ const file = new File(
331
+ [new Blob([params.content], { type: format })],
332
+ params.name + extensionForMediaType(format),
333
+ { type: format },
334
+ );
335
+ const newResourceId = await new Promise<ResourceId>((resolve, reject) => {
336
+ semiont.yield.resource({
337
+ name: params.name,
338
+ file,
339
+ format,
340
+ entityTypes: params.entityTypes,
341
+ language: params.language,
342
+ storageUri: params.storagePath,
343
+ }).subscribe({
344
+ next: (event) => { if (event.phase === 'finished') resolve(event.resourceId); },
345
+ error: reject,
346
+ });
347
+ });
348
+ await semiont.bind.body(
349
+ rUri,
350
+ annotationId(referenceId),
351
+ [{ op: 'add', item: { type: 'SpecificResource' as const, source: newResourceId, purpose: 'linking' as const } }],
352
+ );
353
+ showSuccess('Reference successfully linked to the new resource');
354
+ } catch (error) {
355
+ showError(`Failed to compose resource: ${error instanceof Error ? error.message : String(error)}`);
356
+ throw error; // ComposeStep re-enables its footer on rejection
357
+ }
358
+ }, [semiont, rUri, showSuccess, showError]);
324
359
 
325
360
  // Add resource to open tabs when it loads, and record it as this KB's
326
361
  // last-viewed for the /know landing route to resume from. Both are per-KB
@@ -392,6 +427,19 @@ export function ResourceViewerPage({
392
427
  triggerSparkleAnimation(stored.payload.annotation.id);
393
428
  }, [triggerSparkleAnimation]);
394
429
 
430
+ // RESOLUTION-SPARKLE D2: a reference resolving — Compose, Search → Link, a
431
+ // Generate job landing, or a remote collaborator — is a body update whose
432
+ // operations add a linking SpecificResource. Exactly that sparkles; an unlink
433
+ // (remove) or an entity-tag body change stays dark.
434
+ const handleAnnotationBodyUpdated = useCallback((stored: EventMap['mark:body-updated']) => {
435
+ const resolves = stored.payload.operations.some(
436
+ (op) => op.op === 'add' && op.item.type === 'SpecificResource' && op.item.purpose === 'linking',
437
+ );
438
+ if (resolves) {
439
+ triggerSparkleAnimation(stored.payload.annotationId);
440
+ }
441
+ }, [triggerSparkleAnimation]);
442
+
395
443
  const handleResourceOpen = useCallback(({ resourceId }: { resourceId: string }) => {
396
444
  if (routes.resourceDetail) {
397
445
  const path = routes.resourceDetail(resourceId);
@@ -421,6 +469,7 @@ export function ResourceViewerPage({
421
469
  'yield:clone': handleResourceClone,
422
470
  'beckon:sparkle': handleAnnotationSparkle,
423
471
  'mark:added': handleAnnotationAdded,
472
+ 'mark:body-updated': handleAnnotationBodyUpdated,
424
473
  'browse:resource-open': handleResourceOpen,
425
474
  'browse:entity-type-clicked': handleEntityTypeClicked,
426
475
  });
@@ -490,21 +539,6 @@ export function ResourceViewerPage({
490
539
  </h2>
491
540
  </div>
492
541
  </div>
493
- {/* Resource-generation progress (GENERATE-FROM-BUTTON P7) — no annotationId ⇒ a resource-gen job */}
494
- {generationProgress && !generationProgress.annotationId && (
495
- <AssistProgress
496
- progress={generationProgress}
497
- dataType="generation"
498
- // The ending is the owner's fact and every owner must state it
499
- // (CLEAN-PROGRESS D1). This call site used to pass neither
500
- // `ended` nor `onDismiss`, so a finished generation stayed in its
501
- // running form and then vanished on a timer.
502
- ended={!isGenerating}
503
- onCancel={() => session?.client.job.cancelRequest('generation')}
504
- onDismiss={() => stateUnit?.yield.dismissProgress()}
505
- translations={assistProgressTranslations(ta)}
506
- />
507
- )}
508
542
  {/* Scrollable body wrapper - contains document content, header is sibling above */}
509
543
  <div className="semiont-document-viewer__scrollable-body" lang={getLanguage(resource) || undefined}>
510
544
  <ErrorBoundary
@@ -544,7 +578,7 @@ export function ResourceViewerPage({
544
578
  onSelectionMotivationChange={toolbarPrefs.setSelectionMotivation}
545
579
  shape={toolbarPrefs.shape}
546
580
  onShapeChange={toolbarPrefs.setShape}
547
- newAnnotationIds={newAnnotationIds}
581
+ sparkleAnnotationIds={sparkleAnnotationIds}
548
582
  generatingReferenceId={generationProgress?.annotationId ?? null}
549
583
  showLineNumbers={showLineNumbers}
550
584
  hoverDelayMs={hoverDelayMs}
@@ -594,6 +628,7 @@ export function ResourceViewerPage({
594
628
  onRetryAnnotations={stateUnit?.annotations.retry}
595
629
  entityTypesError={entityTypesError}
596
630
  generatingReferenceId={generationProgress?.annotationId ?? null}
631
+ sparkleAnnotationIds={sparkleAnnotationIds}
597
632
  referencedBy={referencedBy}
598
633
  referencedByLoading={referencedByLoading}
599
634
  referencedByError={referencedByError}
@@ -604,7 +639,7 @@ export function ResourceViewerPage({
604
639
  scrollToAnnotationId={scrollToAnnotationId}
605
640
  hoveredAnnotationId={hoveredAnnotationId}
606
641
  onScrollCompleted={onScrollCompleted}
607
- initialTab={panelInitialTab?.tab as any}
642
+ initialTab={panelInitialTab?.tab}
608
643
  initialTabGeneration={panelInitialTab?.generation}
609
644
  Link={Link}
610
645
  routes={routes}
@@ -644,6 +679,15 @@ export function ResourceViewerPage({
644
679
  wasDerivedFrom={resource.wasDerivedFrom}
645
680
  generator={resource.generator as components['schemas']['Agent'] | components['schemas']['Agent'][] | undefined}
646
681
  onGenerate={() => setGenerateOpen(true)}
682
+ // The panel is generation's progress surface (GENERATE-FROM-
683
+ // RESOURCE D7); no annotationId ⇒ a resource-gen job — the
684
+ // annotation path's frame renders in the reference wizard.
685
+ isGenerating={isGenerating}
686
+ generationProgress={
687
+ generationProgress && !generationProgress.annotationId ? generationProgress : null
688
+ }
689
+ generationOutcome={generationOutcome}
690
+ onDismissProgress={() => stateUnit?.yield.dismissProgress()}
647
691
  />
648
692
  )}
649
693
 
@@ -681,26 +725,33 @@ export function ResourceViewerPage({
681
725
  resourceId={wizardResourceId}
682
726
  defaultTitle={wizardDefaultTitle}
683
727
  entityTypes={wizardEntityTypes}
728
+ resourceName={resource.name}
684
729
  locale={locale}
685
730
  context={gatherContext}
686
731
  contextLoading={gatherLoading}
687
732
  contextError={gatherError}
688
733
  onGenerateSubmit={handleWizardGenerateSubmit}
689
734
  onLinkResource={handleWizardLinkResource}
690
- onComposeNavigate={handleWizardComposeNavigate}
735
+ onComposeSubmit={handleWizardComposeSubmit}
736
+ entityTypeOptions={allEntityTypes}
737
+ hoverDelayMs={hoverDelayMs}
691
738
  translations={{
692
- gatherTitle: tw('gatherTitle'),
693
- configureGenerationTitle: tw('configureGenerationTitle'),
694
- configureSearchTitle: tw('configureSearchTitle'),
695
- searchResultsTitle: tw('searchResultsTitle'),
739
+ resolveTitle: tw('resolveTitle'),
696
740
  sourceContextLabel: tw('sourceContextLabel'),
697
741
  connectionsLabel: tw('connectionsLabel'),
698
742
  citedByLabel: tw('citedByLabel'),
699
743
  userHintLabel: tw('userHintLabel'),
744
+ userHintEffect: tw('userHintEffect'),
700
745
  userHintPlaceholder: tw('userHintPlaceholder'),
746
+ graphPaneTitle: tw('graphPaneTitle'),
747
+ graphEmpty: tw('graphEmpty'),
748
+ resourceLinkLabel: tw('resourceLinkLabel'),
749
+ corpusPaneTitle: tw('corpusPaneTitle'),
750
+ corpusEmpty: tw('corpusEmpty'),
751
+ excludedReceipt: tw('excludedReceipt'),
752
+ machineRead: tw('machineRead'),
701
753
  loadingContext: tw('loadingContext'),
702
754
  failedContext: tw('failedContext'),
703
- cancel: tw('cancel'),
704
755
  search: tw('search'),
705
756
  searching: tw('searching'),
706
757
  generate: tw('generate'),
@@ -712,6 +763,7 @@ export function ResourceViewerPage({
712
763
  noResults: tw('noResults'),
713
764
  resourceTitle: tw('resourceTitle'),
714
765
  resourceTitlePlaceholder: tw('resourceTitlePlaceholder'),
766
+ saveLocation: tw('saveLocation'),
715
767
  additionalInstructions: tw('additionalInstructions'),
716
768
  additionalInstructionsPlaceholder: tw('additionalInstructionsPlaceholder'),
717
769
  language: tw('language'),
@@ -725,6 +777,14 @@ export function ResourceViewerPage({
725
777
  maxResults: tw('maxResults'),
726
778
  semanticScoring: tw('semanticScoring'),
727
779
  semanticScoringHelp: tw('semanticScoringHelp'),
780
+ searchFailed: tw('searchFailed'),
781
+ entityTypes: tw('entityTypes'),
782
+ contentLabel: tw('contentLabel'),
783
+ createAndLink: tw('createAndLink'),
784
+ creatingAndLinking: tw('creatingAndLinking'),
785
+ discardDraftPrompt: tw('discardDraftPrompt'),
786
+ discardDraft: tw('discardDraft'),
787
+ keepEditing: tw('keepEditing'),
728
788
  }}
729
789
  />
730
790
 
@@ -734,31 +794,42 @@ export function ResourceViewerPage({
734
794
  isOpen={generateOpen}
735
795
  onClose={() => setGenerateOpen(false)}
736
796
  resourceId={rUri}
737
- defaultTitle=""
797
+ // Seed the proposed title from the source resource's name (GFR D4/A4);
798
+ // the field stays editable and required.
799
+ defaultTitle={resource.name}
738
800
  locale={locale}
739
801
  entityTypeOptions={allEntityTypes}
740
802
  onGenerateSubmit={handleResourceGenerateSubmit}
803
+ gatherContext={resourceGatherContext}
804
+ gatherLoading={resourceGatherLoading}
805
+ gatherError={resourceGatherError}
806
+ onGather={(options) => stateUnit?.gather.gatherResource(rUri, options)}
741
807
  translations={{
742
- gatherTitle: tg('gatherTitle'),
743
- reviewTitle: tg('reviewTitle'),
744
- configureTitle: tg('configureTitle'),
745
- next: tg('next'),
746
- back: tg('back'),
747
- cancel: tg('cancel'),
808
+ title: tg('title'),
748
809
  gatherIntro: tg('gatherIntro'),
749
810
  includeContent: tg('includeContent'),
750
811
  includeSummary: tg('includeSummary'),
751
812
  gatherDepth: tg('gatherDepth'),
752
813
  gatherMaxResources: tg('gatherMaxResources'),
753
814
  gatherButton: tg('gatherButton'),
754
- excludeLabel: tg('excludeLabel'),
815
+ editGather: tg('editGather'),
816
+ recallLabel: tg('recallLabel'),
755
817
  loadingContext: tg('loadingContext'),
756
818
  failedContext: tg('failedContext'),
757
819
  sourceContextLabel: tg('sourceContextLabel'),
758
820
  connectionsLabel: tg('connectionsLabel'),
759
821
  citedByLabel: tg('citedByLabel'),
822
+ graphPaneTitle: tg('graphPaneTitle'),
823
+ graphEmpty: tg('graphEmpty'),
824
+ resourceLinkLabel: tg('resourceLinkLabel'),
825
+ corpusPaneTitle: tg('corpusPaneTitle'),
826
+ corpusEmpty: tg('corpusEmpty'),
827
+ excludedReceipt: tg('excludedReceipt'),
828
+ machineRead: tg('machineRead'),
829
+ score: tg('score'),
760
830
  resourceTitle: tg('resourceTitle'),
761
831
  resourceTitlePlaceholder: tg('resourceTitlePlaceholder'),
832
+ saveLocation: tg('saveLocation'),
762
833
  additionalInstructions: tg('additionalInstructions'),
763
834
  additionalInstructionsPlaceholder: tg('additionalInstructionsPlaceholder'),
764
835
  language: tg('language'),
@@ -770,6 +841,9 @@ export function ResourceViewerPage({
770
841
  maxLengthHelp: tg('maxLengthHelp'),
771
842
  maxLengthCeiling: tg('maxLengthCeiling'),
772
843
  generate: tg('generate'),
844
+ discardDraftPrompt: tg('discardDraftPrompt'),
845
+ discardDraft: tg('discardDraft'),
846
+ keepEditing: tg('keepEditing'),
773
847
  }}
774
848
  />
775
849
  </div>
@@ -61,8 +61,14 @@
61
61
  gap: 0.5rem;
62
62
  }
63
63
 
64
+ /* Inline-flex with a gap so the control never touches its text — the gap on
65
+ the FIELD wrapper only helps when the input is a sibling; several forms
66
+ nest the input inside the label, where only this reaches. */
64
67
  .semiont-form__checkbox-label,
65
68
  .semiont-form__radio-label {
69
+ display: inline-flex;
70
+ align-items: center;
71
+ gap: 0.5rem;
66
72
  font-size: 0.875rem;
67
73
  color: var(--semiont-text-primary);
68
74
  }
@@ -97,6 +103,15 @@
97
103
  color: var(--semiont-text-secondary);
98
104
  }
99
105
 
106
+ /* A help sentence scoped to a whole inline row rather than one column —
107
+ full width under the row, so its height never stretches the row's flex
108
+ siblings. Right-aligned: the row's `--end` column is what it describes,
109
+ and the sentence should end beneath that cell. */
110
+ .semiont-form__help--row {
111
+ margin-top: 0.5rem;
112
+ text-align: right;
113
+ }
114
+
100
115
  /* Fieldset and legend */
101
116
  .semiont-form__fieldset {
102
117
  border: 1px solid var(--semiont-color-gray-200);
@@ -232,12 +247,6 @@
232
247
  are now defined in /styles/core/ as they are fundamental UI elements.
233
248
  See: core/textareas.css, core/selects.css, core/checkboxes.css */
234
249
 
235
- /* Scrollable form body — keeps form within viewport height */
236
- .semiont-form--scrollable {
237
- overflow-y: auto;
238
- max-height: 70vh;
239
- padding-right: 0.25rem;
240
- }
241
250
 
242
251
  /* Inline row — lays out multiple fields side by side */
243
252
  .semiont-form__inline-row {
@@ -253,13 +262,31 @@
253
262
  }
254
263
 
255
264
  /* Grow modifier — field takes remaining space */
256
- .semiont-form__field--grow {
265
+ /* A slider column: flexible, but a 0-to-1 range gains nothing past ~26rem —
266
+ uncapped it stretches into a band and drags the row's other columns apart. */
267
+ .semiont-form__field--slider {
257
268
  flex: 1;
258
269
  min-width: 0;
270
+ max-width: 26rem;
271
+ }
272
+
273
+ /* Pushed to the row's end — pairs with a right-aligned `__help--row`
274
+ footnote below, so the sentence ends under the cell it describes instead
275
+ of floating at the far left with a void to its right. */
276
+ .semiont-form__field--end {
277
+ margin-left: auto;
259
278
  }
260
279
 
261
280
  /* Narrow modifier — fixed compact width for short numeric inputs */
281
+ /* Sized by content with a floor, not a fixed box: a fixed 5.5rem wrapped
282
+ labels like "Max resources" onto two lines, which stretched that column
283
+ and knocked the row's inputs out of alignment. */
262
284
  .semiont-form__field--narrow {
263
- width: 5.5rem;
285
+ width: auto;
286
+ min-width: 5.5rem;
264
287
  flex-shrink: 0;
265
288
  }
289
+
290
+ .semiont-form__field--inline > .semiont-form__label {
291
+ white-space: nowrap;
292
+ }
@@ -620,28 +620,6 @@
620
620
  font-size: 1rem;
621
621
  }
622
622
 
623
- .semiont-page__reference-notice {
624
- background-color: var(--semiont-color-blue-50);
625
- border: 1px solid var(--semiont-color-blue-200);
626
- border-radius: var(--semiont-radius-md);
627
- padding: 0.75rem 1rem;
628
- margin-top: 1rem;
629
- }
630
-
631
- [data-theme="dark"] .semiont-page__reference-notice {
632
- background-color: rgba(59, 130, 246, 0.1);
633
- border-color: var(--semiont-color-blue-800);
634
- }
635
-
636
- .semiont-page__reference-notice-text {
637
- color: var(--semiont-color-blue-700);
638
- font-size: 0.875rem;
639
- }
640
-
641
- [data-theme="dark"] .semiont-page__reference-notice-text {
642
- color: var(--semiont-color-blue-300);
643
- }
644
-
645
623
  /* Image Annotation Canvas */
646
624
  .semiont-svg-drawing-canvas {
647
625
  position: relative;
@@ -79,10 +79,6 @@
79
79
  }
80
80
  }
81
81
 
82
- .semiont-form__entity-types-display {
83
- margin-top: 0.5rem;
84
- }
85
-
86
82
  .semiont-form__entity-type-tags {
87
83
  display: flex;
88
84
  flex-wrap: wrap;
@@ -10,6 +10,8 @@
10
10
  "codeCompleteCreated": "تم إنشاء {{count}} {{kind}}",
11
11
  "codeGeneratingResource": "جارٍ التوليد…",
12
12
  "codeCreatingResource": "إنشاء المورد…",
13
+ "codeCompleteGenerated": "تم إنشاء المورد",
14
+ "codeCompleteGeneratedTruncated": "تم إنشاء المورد — اقتُطع عند حد الطول",
13
15
  "kindHighlight": "تظليلات",
14
16
  "kindComment": "تعليقات",
15
17
  "kindAssessment": "تقييمات",
@@ -244,6 +246,7 @@
244
246
  "noIncomingReferences": "لا توجد مراجع واردة",
245
247
  "stub": "مرجع مبدئي (غير مربوط)",
246
248
  "resolved": "مرجع محلول (مربوط)",
249
+ "derived": "مشتق",
247
250
  "open": "فتح",
248
251
  "unlink": "إلغاء الربط",
249
252
  "resolve": "حل المرجع",
@@ -251,7 +254,6 @@
251
254
  "createReference": "إنشاء مرجع",
252
255
  "entityTypesOptional": "أنواع الكيانات (اختياري)",
253
256
  "fragmentSelected": "تم تحديد جزء",
254
- "imageRegionSelected": "تم تحديد منطقة من الصورة",
255
257
  "annotateReferences": "توضيح المراجع",
256
258
  "selectEntityTypes": "أنواع الكيانات:",
257
259
  "select": "تحديد",
@@ -262,8 +264,6 @@
262
264
  "annotating": "جارٍ التوضيح...",
263
265
  "includeDescriptiveReferences": "تضمين المراجع الوصفية",
264
266
  "descriptiveReferencesTooltip": "البحث أيضًا عن عبارات مثل 'الرئيس التنفيذي'، 'عملاق التكنولوجيا'، 'الفيزيائي' (بالإضافة إلى الأسماء)",
265
- "annotationProgressTitle": "توضيح مراجع الكيانات",
266
- "cancelAnnotation": "إلغاء التوضيح",
267
267
  "found": "تم العثور على {{count}}",
268
268
  "complete": "اكتمل التوضيح!",
269
269
  "failed": "فشل التوضيح",
@@ -378,19 +378,14 @@
378
378
  },
379
379
  "AnnotateView": {},
380
380
  "ResourceGenerate": {
381
- "gatherTitle": "تكوين الجمع",
382
- "reviewTitle": "مراجعة السياق",
383
- "configureTitle": "تكوين التوليد",
384
- "next": "التالي",
385
- "back": "رجوع",
386
- "cancel": "إلغاء",
387
381
  "gatherIntro": "اختر ما تريد تضمينه في السياق المُجمَّع.",
388
382
  "includeContent": "تضمين محتوى المورد",
389
383
  "includeSummary": "تضمين الملخص",
390
384
  "gatherDepth": "العمق",
391
385
  "gatherMaxResources": "الحد الأقصى للموارد",
392
386
  "gatherButton": "جمع",
393
- "excludeLabel": "استبعاد من الاسترجاع",
387
+ "editGather": "تغيير إعدادات الجمع",
388
+ "recallLabel": "مضمَّن في الاسترجاع — ألغِ التحديد للاستبعاد",
394
389
  "loadingContext": "جارٍ جمع السياق...",
395
390
  "failedContext": "فشل في جمع السياق",
396
391
  "sourceContextLabel": "المورد",
@@ -408,18 +403,22 @@
408
403
  "maxLength": "الحد الأقصى للطول",
409
404
  "maxLengthHelp": "العدد الأقصى من الرموز",
410
405
  "generate": "توليد",
411
- "progressTitle": "جارٍ توليد المورد",
412
- "progressCancel": "إلغاء التوليد",
413
- "progressInProgress": "جارٍ التوليد…",
414
- "progressComplete": "اكتمل التوليد!",
415
- "progressFailed": "فشل التوليد",
416
- "maxLengthCeiling": "محدود بـ {{maxOutputTokens}} رمزًا بواسطة {{model}}."
406
+ "maxLengthCeiling": "محدود بـ {{maxOutputTokens}} رمزًا بواسطة {{model}}.",
407
+ "graphPaneTitle": "الجوار",
408
+ "graphEmpty": "لا روابط بعد.",
409
+ "resourceLinkLabel": "رابط مورد",
410
+ "corpusPaneTitle": "مقاطع مشابهة",
411
+ "corpusEmpty": "لم يُعثر على مقاطع مشابهة.",
412
+ "excludedReceipt": "استُبعد {{types}} من هذا الاسترجاع",
413
+ "machineRead": "OCR",
414
+ "score": "درجة",
415
+ "saveLocation": "موقع الحفظ",
416
+ "discardDraftPrompt": "هل تريد تجاهل هذه المسودة؟",
417
+ "discardDraft": "تجاهل",
418
+ "keepEditing": "متابعة التحرير",
419
+ "title": "إنشاء من هذا المورد"
417
420
  },
418
421
  "ReferenceWizard": {
419
- "gatherTitle": "السياق المُجمَّع",
420
- "configureGenerationTitle": "تكوين التوليد",
421
- "configureSearchTitle": "إعدادات البحث",
422
- "searchResultsTitle": "نتائج البحث",
423
422
  "sourceContextLabel": "سياق التعليق التوضيحي في المورد",
424
423
  "connectionsLabel": "التعليقات التوضيحية للأقران",
425
424
  "citedByLabel": "المورد مُستشهد به من قِبل",
@@ -427,7 +426,6 @@
427
426
  "userHintPlaceholder": "صف ما يشير إليه هذا التعليق التوضيحي...",
428
427
  "loadingContext": "جارٍ جمع السياق...",
429
428
  "failedContext": "فشل في جمع السياق",
430
- "cancel": "إلغاء",
431
429
  "generate": "توليد",
432
430
  "compose": "تأليف",
433
431
  "resolutionStrategyLabel": "استراتيجية الحل",
@@ -450,8 +448,26 @@
450
448
  "semanticScoring": "التقييم الدلالي",
451
449
  "semanticScoringHelp": "استخدام الذكاء الاصطناعي لتقييم النتائج حسب الصلة الدلالية",
452
450
  "searching": "جاري البحث...",
451
+ "searchFailed": "فشل البحث",
453
452
  "search": "بحث",
454
- "maxLengthCeiling": "محدود بـ {{maxOutputTokens}} رمزًا بواسطة {{model}}."
453
+ "maxLengthCeiling": "محدود بـ {{maxOutputTokens}} رمزًا بواسطة {{model}}.",
454
+ "graphPaneTitle": "الجوار",
455
+ "graphEmpty": "لا روابط بعد — حلّ هذه الإشارة ينشئ أول رابط.",
456
+ "resourceLinkLabel": "رابط مورد",
457
+ "corpusPaneTitle": "مقاطع مشابهة",
458
+ "corpusEmpty": "لم يُعثر على مقاطع مشابهة — من غير المرجح أن يُجدي البحث.",
459
+ "excludedReceipt": "استُبعد {{types}} من هذا الاسترجاع",
460
+ "machineRead": "OCR",
461
+ "userHintEffect": "يوجّه البحث والتوليد",
462
+ "saveLocation": "موقع الحفظ",
463
+ "entityTypes": "أنواع الكيانات",
464
+ "contentLabel": "المحتوى",
465
+ "createAndLink": "إنشاء وربط",
466
+ "creatingAndLinking": "جارٍ الإنشاء والربط…",
467
+ "discardDraftPrompt": "هل تريد تجاهل هذه المسودة؟",
468
+ "discardDraft": "تجاهل",
469
+ "keepEditing": "متابعة التحرير",
470
+ "resolveTitle": "حل المرجع"
455
471
  },
456
472
  "OutcomeToasts": {
457
473
  "createFailed": "تعذّر إنشاء التعليق التوضيحي: {{detail}}",