@semiont/react-ui 0.4.21 → 0.5.0
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.
- package/dist/{PdfAnnotationCanvas.client-6ZGFEN2N.mjs → PdfAnnotationCanvas.client-5QESNO5H.mjs} +10 -9
- package/dist/PdfAnnotationCanvas.client-5QESNO5H.mjs.map +1 -0
- package/dist/{chunk-KEDFYI6N.mjs → chunk-4NOUO3W6.mjs} +2 -2
- package/dist/{chunk-KEDFYI6N.mjs.map → chunk-4NOUO3W6.mjs.map} +1 -1
- package/dist/index.d.mts +54 -79
- package/dist/index.mjs +255 -254
- package/dist/index.mjs.map +1 -1
- package/dist/test-utils.d.mts +3 -1
- package/dist/test-utils.mjs +14 -8
- package/dist/test-utils.mjs.map +1 -1
- package/package.json +2 -1
- package/src/components/AnnotateReferencesProgressWidget.tsx +1 -1
- package/src/components/CodeMirrorRenderer.tsx +5 -3
- package/src/components/LiveRegion.tsx +1 -2
- package/src/components/StatusDisplay.tsx +1 -1
- package/src/components/__tests__/StatusDisplay.test.tsx +3 -1
- package/src/components/annotation/AnnotateToolbar.tsx +5 -7
- package/src/components/annotation-popups/JsonLdView.tsx +1 -2
- package/src/components/annotation-popups/__tests__/JsonLdView.test.tsx +1 -1
- package/src/components/image-annotation/AnnotationOverlay.tsx +12 -14
- package/src/components/image-annotation/SvgDrawingCanvas.tsx +8 -13
- package/src/components/modals/ConfigureGenerationStep.tsx +1 -2
- package/src/components/modals/ReferenceWizardModal.tsx +1 -1
- package/src/components/modals/ResourceSearchModal.tsx +3 -3
- package/src/components/modals/SearchModal.tsx +2 -1
- package/src/components/modals/SearchResultsStep.tsx +1 -3
- package/src/components/modals/__tests__/SearchModal.accessibility.test.tsx +6 -2
- package/src/components/modals/__tests__/SearchModal.basic.test.tsx +6 -2
- package/src/components/modals/__tests__/SearchModal.keyboard.test.tsx +6 -2
- package/src/components/modals/__tests__/SearchModal.visual.test.tsx +6 -2
- package/src/components/pdf-annotation/PdfAnnotationCanvas.tsx +11 -12
- package/src/components/pdf-annotation/__tests__/PdfAnnotationCanvas.test.tsx +1 -1
- package/src/components/resource/AnnotateView.tsx +2 -5
- package/src/components/resource/BrowseView.tsx +6 -4
- package/src/components/resource/ResourceViewer.tsx +7 -11
- package/src/components/resource/__tests__/BrowseView.test.tsx +4 -4
- package/src/components/resource/__tests__/ResourceViewer.mode-switch.test.tsx +1 -0
- package/src/components/resource/__tests__/event-formatting.test.ts +6 -2
- package/src/components/resource/event-formatting.ts +2 -3
- package/src/components/resource/panels/AssessmentEntry.tsx +3 -5
- package/src/components/resource/panels/AssessmentPanel.tsx +5 -5
- package/src/components/resource/panels/AssistSection.tsx +6 -10
- package/src/components/resource/panels/CollaborationPanel.tsx +1 -1
- package/src/components/resource/panels/CommentEntry.tsx +3 -5
- package/src/components/resource/panels/CommentsPanel.tsx +5 -5
- package/src/components/resource/panels/HighlightEntry.tsx +3 -5
- package/src/components/resource/panels/HighlightPanel.tsx +3 -3
- package/src/components/resource/panels/ReferenceEntry.tsx +7 -9
- package/src/components/resource/panels/ReferencesPanel.tsx +8 -11
- package/src/components/resource/panels/ResourceInfoPanel.tsx +5 -5
- package/src/components/resource/panels/StatisticsPanel.tsx +2 -3
- package/src/components/resource/panels/TagEntry.tsx +3 -5
- package/src/components/resource/panels/TaggingPanel.tsx +8 -11
- package/src/components/resource/panels/UnifiedAnnotationsPanel.tsx +1 -1
- package/src/components/resource/panels/__tests__/AssessmentEntry.test.tsx +4 -4
- package/src/components/resource/panels/__tests__/AssessmentPanel.test.tsx +4 -5
- package/src/components/resource/panels/__tests__/CommentEntry.test.tsx +4 -4
- package/src/components/resource/panels/__tests__/CommentsPanel.test.tsx +4 -5
- package/src/components/resource/panels/__tests__/HighlightEntry.test.tsx +4 -4
- package/src/components/resource/panels/__tests__/HighlightPanel.annotationProgress.test.tsx +1 -1
- package/src/components/resource/panels/__tests__/ReferenceEntry.test.tsx +4 -4
- package/src/components/resource/panels/__tests__/ResourceInfoPanel.test.tsx +21 -14
- package/src/components/resource/panels/__tests__/StatisticsPanel.test.tsx +3 -3
- package/src/components/resource/panels/__tests__/TagEntry.test.tsx +4 -4
- package/src/components/resource/panels/__tests__/TaggingPanel.test.tsx +4 -5
- package/src/components/settings/SettingsPanel.tsx +1 -1
- package/src/components/settings/__tests__/SettingsPanel.test.tsx +3 -3
- package/src/features/admin-devops/components/AdminDevOpsPage.tsx +1 -2
- package/src/features/admin-exchange/components/AdminExchangePage.tsx +1 -1
- package/src/features/admin-exchange/components/ImportCard.tsx +1 -2
- package/src/features/admin-security/components/AdminSecurityPage.tsx +1 -2
- package/src/features/admin-users/components/AdminUsersPage.tsx +1 -1
- package/src/features/moderate-entity-tags/components/EntityTagsPage.tsx +1 -2
- package/src/features/moderate-recent/components/RecentDocumentsPage.tsx +1 -2
- package/src/features/moderate-tag-schemas/components/TagSchemasPage.tsx +1 -1
- package/src/features/moderation-linked-data/components/LinkedDataPage.tsx +1 -1
- package/src/features/resource-compose/components/ResourceComposePage.tsx +3 -2
- package/src/features/resource-discovery/components/ResourceCard.tsx +1 -2
- package/src/features/resource-discovery/components/ResourceDiscoveryPage.tsx +3 -4
- package/src/features/resource-viewer/__tests__/ResourceViewerPage.test.tsx +4 -5
- package/src/features/resource-viewer/components/ResourceViewerPage.tsx +12 -11
- package/dist/PdfAnnotationCanvas.client-6ZGFEN2N.mjs.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@semiont/react-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "React components and hooks for Semiont",
|
|
5
5
|
"main": "./dist/index.mjs",
|
|
6
6
|
"types": "./dist/index.d.mts",
|
|
@@ -104,6 +104,7 @@
|
|
|
104
104
|
"dependencies": {
|
|
105
105
|
"@semiont/api-client": "*",
|
|
106
106
|
"@semiont/core": "*",
|
|
107
|
+
"@semiont/sdk": "*",
|
|
107
108
|
"react-error-boundary": "^4.1.2"
|
|
108
109
|
}
|
|
109
110
|
}
|
|
@@ -24,7 +24,7 @@ export function AnnotateReferencesProgressWidget({ progress, annotationType = 'r
|
|
|
24
24
|
|
|
25
25
|
const handleCancel = () => {
|
|
26
26
|
// Emit event for job cancellation
|
|
27
|
-
session?.client.
|
|
27
|
+
session?.client.job.cancelRequest('annotation');
|
|
28
28
|
};
|
|
29
29
|
|
|
30
30
|
if (!progress) return null;
|
|
@@ -6,7 +6,9 @@ import { EditorState, RangeSetBuilder, StateField, StateEffect, Compartment } fr
|
|
|
6
6
|
import { markdown } from '@codemirror/lang-markdown';
|
|
7
7
|
import { ReferenceResolutionWidget, showWidgetPreview, hideWidgetPreview } from '../lib/codemirror-widgets';
|
|
8
8
|
import { scrollAnnotationIntoView } from '../lib/scroll-utils';
|
|
9
|
-
import {
|
|
9
|
+
import { annotationId as toAnnotationId } from '@semiont/core';
|
|
10
|
+
import { isReference } from '@semiont/core';
|
|
11
|
+
import { createHoverHandlers, type SemiontSession } from '@semiont/sdk';
|
|
10
12
|
import {
|
|
11
13
|
convertSegmentPositions,
|
|
12
14
|
computeAnnotationDecorations,
|
|
@@ -301,7 +303,7 @@ export function CodeMirrorRenderer({
|
|
|
301
303
|
const container = view.dom;
|
|
302
304
|
|
|
303
305
|
const { handleMouseEnter, handleMouseLeave, cleanup: cleanupHover } = createHoverHandlers(
|
|
304
|
-
(
|
|
306
|
+
(id) => sessionRef.current?.client.beckon.hover(id),
|
|
305
307
|
hoverDelayMs
|
|
306
308
|
);
|
|
307
309
|
|
|
@@ -309,7 +311,7 @@ export function CodeMirrorRenderer({
|
|
|
309
311
|
const target = e.target as HTMLElement;
|
|
310
312
|
const annotationElement = target.closest('[data-annotation-id]');
|
|
311
313
|
const annotationId = annotationElement?.getAttribute('data-annotation-id');
|
|
312
|
-
if (annotationId) handleMouseEnter(annotationId);
|
|
314
|
+
if (annotationId) handleMouseEnter(toAnnotationId(annotationId));
|
|
313
315
|
};
|
|
314
316
|
|
|
315
317
|
const handleMouseOut = (e: MouseEvent) => {
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import React, { useState, createContext, useContext, useCallback } from 'react';
|
|
4
|
-
import type { components } from '@semiont/core';
|
|
5
4
|
import type { Annotator } from '../lib/annotation-registry';
|
|
6
5
|
|
|
7
|
-
type Annotation
|
|
6
|
+
import type { Annotation } from '@semiont/core';
|
|
8
7
|
|
|
9
8
|
interface LiveRegionContextType {
|
|
10
9
|
announce: (message: string, priority?: 'polite' | 'assertive') => void;
|
|
@@ -8,7 +8,9 @@ import { StatusDisplay } from '../StatusDisplay';
|
|
|
8
8
|
|
|
9
9
|
let mockGetStatus: ReturnType<typeof vi.fn>;
|
|
10
10
|
const stableMockClient = {
|
|
11
|
-
|
|
11
|
+
admin: {
|
|
12
|
+
get status() { return mockGetStatus; },
|
|
13
|
+
},
|
|
12
14
|
};
|
|
13
15
|
const stableMockSession = { client: stableMockClient };
|
|
14
16
|
const stableActiveSession$ = new BehaviorSubject<any>(stableMockSession);
|
|
@@ -189,11 +189,9 @@ export function AnnotateToolbar({
|
|
|
189
189
|
const handleSelectionClick = (motivation: SelectionMotivation | null) => {
|
|
190
190
|
// If null is clicked, always deselect. Otherwise toggle.
|
|
191
191
|
if (motivation === null) {
|
|
192
|
-
session?.client.
|
|
192
|
+
session?.client.mark.changeSelection(null);
|
|
193
193
|
} else {
|
|
194
|
-
session?.client.
|
|
195
|
-
motivation: selectedMotivation === motivation ? null : motivation
|
|
196
|
-
});
|
|
194
|
+
session?.client.mark.changeSelection(selectedMotivation === motivation ? null : motivation);
|
|
197
195
|
}
|
|
198
196
|
// Close dropdown after selection
|
|
199
197
|
setSelectionPinned(false);
|
|
@@ -201,21 +199,21 @@ export function AnnotateToolbar({
|
|
|
201
199
|
};
|
|
202
200
|
|
|
203
201
|
const handleClickClick = (action: ClickAction) => {
|
|
204
|
-
session?.client.
|
|
202
|
+
session?.client.mark.changeClick(action);
|
|
205
203
|
// Close dropdown after selection
|
|
206
204
|
setClickPinned(false);
|
|
207
205
|
setClickHovered(false);
|
|
208
206
|
};
|
|
209
207
|
|
|
210
208
|
const handleShapeClick = (shape: ShapeType) => {
|
|
211
|
-
session?.client.
|
|
209
|
+
session?.client.mark.changeShape(shape);
|
|
212
210
|
// Close dropdown after selection
|
|
213
211
|
setShapePinned(false);
|
|
214
212
|
setShapeHovered(false);
|
|
215
213
|
};
|
|
216
214
|
|
|
217
215
|
const handleModeToggle = () => {
|
|
218
|
-
session?.client.
|
|
216
|
+
session?.client.mark.toggleMode();
|
|
219
217
|
setModePinned(false);
|
|
220
218
|
setModeHovered(false);
|
|
221
219
|
};
|
|
@@ -8,9 +8,8 @@ import { oneDark } from '@codemirror/theme-one-dark';
|
|
|
8
8
|
import { syntaxHighlighting } from '@codemirror/language';
|
|
9
9
|
import { jsonLightTheme, jsonLightHighlightStyle } from '../../lib/codemirror-json-theme';
|
|
10
10
|
import { useLineNumbers } from '../../hooks/useLineNumbers';
|
|
11
|
-
import type { components } from '@semiont/core';
|
|
12
11
|
|
|
13
|
-
type Annotation
|
|
12
|
+
import type { Annotation } from '@semiont/core';
|
|
14
13
|
|
|
15
14
|
interface JsonLdViewProps {
|
|
16
15
|
annotation: Annotation;
|
|
@@ -5,7 +5,7 @@ import userEvent from '@testing-library/user-event';
|
|
|
5
5
|
import '@testing-library/jest-dom';
|
|
6
6
|
import type { components } from '@semiont/core';
|
|
7
7
|
|
|
8
|
-
type Annotation
|
|
8
|
+
import type { Annotation } from '@semiont/core';
|
|
9
9
|
|
|
10
10
|
// Mock CodeMirror modules
|
|
11
11
|
vi.mock('@codemirror/view', () => {
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useMemo } from 'react';
|
|
4
|
-
import type {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
type Annotation = components['schemas']['Annotation'];
|
|
10
|
-
|
|
4
|
+
import type { Annotation } from '@semiont/core';
|
|
5
|
+
import { getSvgSelector, isHighlight, isReference, isAssessment, isComment, isTag, isBodyResolved, isResolvedReference } from '@semiont/core';
|
|
6
|
+
import { createHoverHandlers } from '@semiont/sdk';
|
|
7
|
+
import { parseSvgSelector } from '@semiont/core';
|
|
8
|
+
import type { SemiontSession } from '@semiont/sdk';
|
|
11
9
|
interface AnnotationOverlayProps {
|
|
12
10
|
annotations: Annotation[];
|
|
13
11
|
imageWidth: number;
|
|
@@ -80,7 +78,7 @@ export function AnnotationOverlay({
|
|
|
80
78
|
const scaleY = displayHeight / imageHeight;
|
|
81
79
|
|
|
82
80
|
const { handleMouseEnter, handleMouseLeave } = useMemo(
|
|
83
|
-
() => createHoverHandlers((
|
|
81
|
+
() => createHoverHandlers((id) => session?.client.beckon.hover(id), hoverDelayMs),
|
|
84
82
|
[session, hoverDelayMs]
|
|
85
83
|
);
|
|
86
84
|
|
|
@@ -130,7 +128,7 @@ export function AnnotationOverlay({
|
|
|
130
128
|
className="semiont-annotation-overlay__shape"
|
|
131
129
|
data-hovered={isHovered ? 'true' : 'false'}
|
|
132
130
|
data-selected={isSelected ? 'true' : 'false'}
|
|
133
|
-
onClick={() => session?.client.
|
|
131
|
+
onClick={() => session?.client.browse.click(annotation.id, annotation.motivation)}
|
|
134
132
|
onMouseEnter={() => handleMouseEnter(annotation.id)}
|
|
135
133
|
onMouseLeave={handleMouseLeave}
|
|
136
134
|
/>
|
|
@@ -143,7 +141,7 @@ export function AnnotationOverlay({
|
|
|
143
141
|
style={{ userSelect: 'none' }}
|
|
144
142
|
onClick={(e) => {
|
|
145
143
|
e.stopPropagation();
|
|
146
|
-
session?.client.
|
|
144
|
+
session?.client.browse.click(annotation.id, annotation.motivation);
|
|
147
145
|
}}
|
|
148
146
|
onMouseEnter={() => handleMouseEnter(annotation.id)}
|
|
149
147
|
onMouseLeave={handleMouseLeave}
|
|
@@ -177,7 +175,7 @@ export function AnnotationOverlay({
|
|
|
177
175
|
className="semiont-annotation-overlay__shape"
|
|
178
176
|
data-hovered={isHovered ? 'true' : 'false'}
|
|
179
177
|
data-selected={isSelected ? 'true' : 'false'}
|
|
180
|
-
onClick={() => session?.client.
|
|
178
|
+
onClick={() => session?.client.browse.click(annotation.id, annotation.motivation)}
|
|
181
179
|
onMouseEnter={() => handleMouseEnter(annotation.id)}
|
|
182
180
|
onMouseLeave={handleMouseLeave}
|
|
183
181
|
/>
|
|
@@ -190,7 +188,7 @@ export function AnnotationOverlay({
|
|
|
190
188
|
style={{ userSelect: 'none' }}
|
|
191
189
|
onClick={(e) => {
|
|
192
190
|
e.stopPropagation();
|
|
193
|
-
session?.client.
|
|
191
|
+
session?.client.browse.click(annotation.id, annotation.motivation);
|
|
194
192
|
}}
|
|
195
193
|
onMouseEnter={() => handleMouseEnter(annotation.id)}
|
|
196
194
|
onMouseLeave={handleMouseLeave}
|
|
@@ -237,7 +235,7 @@ export function AnnotationOverlay({
|
|
|
237
235
|
className="semiont-annotation-overlay__shape"
|
|
238
236
|
data-hovered={isHovered ? 'true' : 'false'}
|
|
239
237
|
data-selected={isSelected ? 'true' : 'false'}
|
|
240
|
-
onClick={() => session?.client.
|
|
238
|
+
onClick={() => session?.client.browse.click(annotation.id, annotation.motivation)}
|
|
241
239
|
onMouseEnter={() => handleMouseEnter(annotation.id)}
|
|
242
240
|
onMouseLeave={handleMouseLeave}
|
|
243
241
|
/>
|
|
@@ -250,7 +248,7 @@ export function AnnotationOverlay({
|
|
|
250
248
|
style={{ userSelect: 'none' }}
|
|
251
249
|
onClick={(e) => {
|
|
252
250
|
e.stopPropagation();
|
|
253
|
-
session?.client.
|
|
251
|
+
session?.client.browse.click(annotation.id, annotation.motivation);
|
|
254
252
|
}}
|
|
255
253
|
onMouseEnter={() => handleMouseEnter(annotation.id)}
|
|
256
254
|
onMouseLeave={handleMouseLeave}
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import React, { useRef, useState, useEffect, useCallback } from 'react';
|
|
4
|
-
import type {
|
|
5
|
-
import { createRectangleSvg, createCircleSvg, createPolygonSvg, scaleSvgToNative, parseSvgSelector, Point } from '@semiont/
|
|
4
|
+
import type { Annotation } from '@semiont/core';
|
|
5
|
+
import { createRectangleSvg, createCircleSvg, createPolygonSvg, scaleSvgToNative, parseSvgSelector, Point } from '@semiont/core';
|
|
6
6
|
import { AnnotationOverlay } from './AnnotationOverlay';
|
|
7
7
|
import type { SelectionMotivation } from '../annotation/AnnotateToolbar';
|
|
8
|
-
import type { SemiontSession } from '@semiont/
|
|
8
|
+
import type { SemiontSession } from '@semiont/sdk';
|
|
9
9
|
import { useHoverDelay } from '../../hooks/useHoverDelay';
|
|
10
10
|
|
|
11
|
-
type Annotation = components['schemas']['Annotation'];
|
|
12
|
-
|
|
13
11
|
export type DrawingMode = 'rectangle' | 'polygon' | 'circle' | 'freeform' | null;
|
|
14
12
|
|
|
15
13
|
/**
|
|
@@ -212,7 +210,7 @@ export function SvgDrawingCanvas({
|
|
|
212
210
|
});
|
|
213
211
|
|
|
214
212
|
if (clickedAnnotation) {
|
|
215
|
-
session?.client.
|
|
213
|
+
session?.client.browse.click(clickedAnnotation.id, clickedAnnotation.motivation);
|
|
216
214
|
setIsDrawing(false);
|
|
217
215
|
setStartPoint(null);
|
|
218
216
|
setCurrentPoint(null);
|
|
@@ -275,13 +273,10 @@ export function SvgDrawingCanvas({
|
|
|
275
273
|
|
|
276
274
|
// Emit annotation:requested event with SvgSelector
|
|
277
275
|
if (session && selectedMotivation) {
|
|
278
|
-
session.client.
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
},
|
|
283
|
-
motivation: selectedMotivation
|
|
284
|
-
});
|
|
276
|
+
session.client.mark.request(
|
|
277
|
+
{ type: 'SvgSelector', value: nativeSvg },
|
|
278
|
+
selectedMotivation,
|
|
279
|
+
);
|
|
285
280
|
}
|
|
286
281
|
|
|
287
282
|
// Reset drawing state
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import React, { useState } from 'react';
|
|
4
4
|
import type { GatheredContext } from '@semiont/core';
|
|
5
|
-
import { LOCALES } from '@semiont/
|
|
6
|
-
|
|
5
|
+
import { LOCALES } from '@semiont/core';
|
|
7
6
|
export interface GenerationConfig {
|
|
8
7
|
title: string;
|
|
9
8
|
storagePath: string;
|
|
@@ -143,7 +143,7 @@ export function ReferenceWizardModal({
|
|
|
143
143
|
if (!annotationId || !context || !resourceId) return;
|
|
144
144
|
setIsSearching(true);
|
|
145
145
|
const contextWithHint = userHint ? { ...context, userHint } : context;
|
|
146
|
-
session?.client.
|
|
146
|
+
session?.client.match.requestSearch({
|
|
147
147
|
correlationId: crypto.randomUUID(),
|
|
148
148
|
resourceId,
|
|
149
149
|
referenceId: annotationId,
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
import { useState, useEffect, useRef } from 'react';
|
|
4
4
|
import { Dialog, DialogPanel, DialogTitle, Transition, TransitionChild } from '@headlessui/react';
|
|
5
5
|
import { map } from 'rxjs/operators';
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
6
|
+
import { getResourceId, getPrimaryRepresentation } from '@semiont/core';
|
|
7
|
+
import { createSearchPipeline } from '@semiont/sdk';
|
|
8
8
|
import { useSemiont } from '../../session/SemiontProvider';
|
|
9
9
|
import { useObservable } from '../../hooks/useObservable';
|
|
10
10
|
import { useSearchAnnouncements } from '../../hooks/useSearchAnnouncements';
|
|
11
11
|
|
|
12
|
-
type ResourceDescriptor
|
|
12
|
+
import type { ResourceDescriptor } from '@semiont/core';
|
|
13
13
|
|
|
14
14
|
type SearchResult = {
|
|
15
15
|
id: string;
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
import React, { useState, useEffect, useRef } from 'react';
|
|
4
4
|
import { Dialog, DialogPanel, Transition, TransitionChild } from '@headlessui/react';
|
|
5
5
|
import { map } from 'rxjs/operators';
|
|
6
|
-
import { getResourceId
|
|
6
|
+
import { getResourceId } from '@semiont/core';
|
|
7
|
+
import { createSearchPipeline } from '@semiont/sdk';
|
|
7
8
|
import { useSearchAnnouncements } from '../../hooks/useSearchAnnouncements';
|
|
8
9
|
import { useSemiont } from '../../session/SemiontProvider';
|
|
9
10
|
import { useObservable } from '../../hooks/useObservable';
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type { GatheredContext, ResourceDescriptor } from '@semiont/core';
|
|
4
4
|
import { ContextSummary } from './ContextSummary';
|
|
5
5
|
import type { ContextSummaryTranslations } from './ContextSummary';
|
|
6
6
|
|
|
7
|
-
type ResourceDescriptor = components['schemas']['ResourceDescriptor'];
|
|
8
|
-
|
|
9
7
|
export type ScoredResult = ResourceDescriptor & {
|
|
10
8
|
score?: number;
|
|
11
9
|
matchReason?: string;
|
|
@@ -15,9 +15,13 @@ vi.mock('../../../hooks/useSearchAnnouncements', () => ({
|
|
|
15
15
|
}));
|
|
16
16
|
|
|
17
17
|
// Mock getResourceId
|
|
18
|
-
vi.mock('@semiont/
|
|
18
|
+
vi.mock('@semiont/core', async (importOriginal) => {
|
|
19
|
+
const actual = await importOriginal<typeof import('@semiont/core')>();
|
|
20
|
+
return {
|
|
21
|
+
...actual,
|
|
19
22
|
getResourceId: vi.fn((resource: any) => resource?.id)
|
|
20
|
-
}
|
|
23
|
+
};
|
|
24
|
+
});
|
|
21
25
|
|
|
22
26
|
describe.skip('SearchModal Component - Accessibility', () => {
|
|
23
27
|
// TODO: All SearchModal tests skipped due to HeadlessUI Dialog + jsdom memory issues
|
|
@@ -16,9 +16,13 @@ vi.mock('../../../hooks/useSearchAnnouncements', () => ({
|
|
|
16
16
|
}));
|
|
17
17
|
|
|
18
18
|
// Mock getResourceId
|
|
19
|
-
vi.mock('@semiont/
|
|
19
|
+
vi.mock('@semiont/core', async (importOriginal) => {
|
|
20
|
+
const actual = await importOriginal<typeof import('@semiont/core')>();
|
|
21
|
+
return {
|
|
22
|
+
...actual,
|
|
20
23
|
getResourceId: vi.fn((resource: any) => resource?.id)
|
|
21
|
-
}
|
|
24
|
+
};
|
|
25
|
+
});
|
|
22
26
|
|
|
23
27
|
describe('SearchModal Component - Basic Rendering', () => {
|
|
24
28
|
const defaultProps = {
|
|
@@ -15,9 +15,13 @@ vi.mock('../../../hooks/useSearchAnnouncements', () => ({
|
|
|
15
15
|
}));
|
|
16
16
|
|
|
17
17
|
// Mock getResourceId
|
|
18
|
-
vi.mock('@semiont/
|
|
18
|
+
vi.mock('@semiont/core', async (importOriginal) => {
|
|
19
|
+
const actual = await importOriginal<typeof import('@semiont/core')>();
|
|
20
|
+
return {
|
|
21
|
+
...actual,
|
|
19
22
|
getResourceId: vi.fn((resource: any) => resource?.id)
|
|
20
|
-
}
|
|
23
|
+
};
|
|
24
|
+
});
|
|
21
25
|
|
|
22
26
|
describe.skip('SearchModal Component - Keyboard Navigation', () => {
|
|
23
27
|
// TODO: All SearchModal tests skipped due to HeadlessUI Dialog + jsdom memory issues
|
|
@@ -15,9 +15,13 @@ vi.mock('../../../hooks/useSearchAnnouncements', () => ({
|
|
|
15
15
|
}));
|
|
16
16
|
|
|
17
17
|
// Mock getResourceId
|
|
18
|
-
vi.mock('@semiont/
|
|
18
|
+
vi.mock('@semiont/core', async (importOriginal) => {
|
|
19
|
+
const actual = await importOriginal<typeof import('@semiont/core')>();
|
|
20
|
+
return {
|
|
21
|
+
...actual,
|
|
19
22
|
getResourceId: vi.fn((resource: any) => resource?.id)
|
|
20
|
-
}
|
|
23
|
+
};
|
|
24
|
+
});
|
|
21
25
|
|
|
22
26
|
describe.skip('SearchModal Component - Visual States', () => {
|
|
23
27
|
// TODO: All SearchModal tests skipped due to HeadlessUI Dialog + jsdom memory issues
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import React, { useRef, useState, useCallback, useEffect, useMemo } from 'react';
|
|
4
|
-
import type {
|
|
5
|
-
import {
|
|
4
|
+
import type { Annotation } from '@semiont/core';
|
|
5
|
+
import { getTargetSelector } from '@semiont/core';
|
|
6
|
+
import { createHoverHandlers, type SemiontSession } from '@semiont/sdk';
|
|
6
7
|
import type { SelectionMotivation } from '../annotation/AnnotateToolbar';
|
|
7
8
|
import {
|
|
8
9
|
canvasToPdfCoordinates,
|
|
@@ -19,8 +20,6 @@ import {
|
|
|
19
20
|
} from '../../lib/browser-pdfjs';
|
|
20
21
|
import './PdfAnnotationCanvas.css';
|
|
21
22
|
|
|
22
|
-
type Annotation = components['schemas']['Annotation'];
|
|
23
|
-
|
|
24
23
|
export type DrawingMode = 'rectangle' | 'circle' | 'polygon' | null;
|
|
25
24
|
|
|
26
25
|
/**
|
|
@@ -278,7 +277,7 @@ export function PdfAnnotationCanvas({
|
|
|
278
277
|
});
|
|
279
278
|
|
|
280
279
|
if (clickedAnnotation) {
|
|
281
|
-
session?.client.
|
|
280
|
+
session?.client.browse.click(clickedAnnotation.id, clickedAnnotation.motivation);
|
|
282
281
|
setIsDrawing(false);
|
|
283
282
|
setSelection(null);
|
|
284
283
|
return;
|
|
@@ -317,14 +316,14 @@ export function PdfAnnotationCanvas({
|
|
|
317
316
|
|
|
318
317
|
// Emit annotation:requested event with FragmentSelector
|
|
319
318
|
if (selectedMotivation) {
|
|
320
|
-
session.client.
|
|
321
|
-
|
|
319
|
+
session.client.mark.request(
|
|
320
|
+
{
|
|
322
321
|
type: 'FragmentSelector',
|
|
323
322
|
conformsTo: 'http://tools.ietf.org/rfc/rfc3778',
|
|
324
|
-
value: fragmentSelector
|
|
323
|
+
value: fragmentSelector,
|
|
325
324
|
},
|
|
326
|
-
|
|
327
|
-
|
|
325
|
+
selectedMotivation,
|
|
326
|
+
);
|
|
328
327
|
}
|
|
329
328
|
|
|
330
329
|
// Keep drawing state active to show preview until annotation is persisted
|
|
@@ -355,7 +354,7 @@ export function PdfAnnotationCanvas({
|
|
|
355
354
|
|
|
356
355
|
// Hover handlers with currentHover guard and dwell delay
|
|
357
356
|
const { handleMouseEnter, handleMouseLeave } = useMemo(
|
|
358
|
-
() => createHoverHandlers((
|
|
357
|
+
() => createHoverHandlers((id) => session?.client.beckon.hover(id), hoverDelayMs),
|
|
359
358
|
[session, hoverDelayMs]
|
|
360
359
|
);
|
|
361
360
|
|
|
@@ -455,7 +454,7 @@ export function PdfAnnotationCanvas({
|
|
|
455
454
|
cursor: 'pointer',
|
|
456
455
|
opacity: isSelected ? 1 : isHovered ? 0.9 : 0.7
|
|
457
456
|
}}
|
|
458
|
-
onClick={() => session?.client.
|
|
457
|
+
onClick={() => session?.client.browse.click(ann.id, ann.motivation)}
|
|
459
458
|
onMouseEnter={() => handleMouseEnter(ann.id)}
|
|
460
459
|
onMouseLeave={handleMouseLeave}
|
|
461
460
|
/>
|
|
@@ -14,7 +14,7 @@ import { PdfAnnotationCanvas } from '../PdfAnnotationCanvas';
|
|
|
14
14
|
import { resourceId } from '@semiont/core';
|
|
15
15
|
import type { components } from '@semiont/core';
|
|
16
16
|
|
|
17
|
-
type Annotation
|
|
17
|
+
import type { Annotation } from '@semiont/core';
|
|
18
18
|
|
|
19
19
|
// Mock browser-pdfjs module
|
|
20
20
|
vi.mock('../../../lib/browser-pdfjs', () => ({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useRef, useEffect, useCallback, lazy, Suspense } from 'react';
|
|
4
|
-
import { getMimeCategory, isPdfMimeType } from '@semiont/
|
|
4
|
+
import { getMimeCategory, isPdfMimeType } from '@semiont/core';
|
|
5
5
|
import { ANNOTATORS } from '../../lib/annotation-registry';
|
|
6
6
|
import { segmentTextWithAnnotations } from '../../lib/text-segmentation';
|
|
7
7
|
import { buildTextSelectors, fallbackTextPosition } from '../../lib/text-selection-handler';
|
|
@@ -176,10 +176,7 @@ export function AnnotateView({
|
|
|
176
176
|
const selectors = buildTextSelectors(content, text, start, end);
|
|
177
177
|
if (!selectors) return;
|
|
178
178
|
|
|
179
|
-
session?.client.
|
|
180
|
-
selector: selectors,
|
|
181
|
-
motivation: selectedMotivation
|
|
182
|
-
});
|
|
179
|
+
session?.client.mark.request(selectors, selectedMotivation);
|
|
183
180
|
|
|
184
181
|
// Clear selection after creating annotation
|
|
185
182
|
selection.removeAllRanges();
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
import { useEffect, useRef, useCallback, useMemo, memo, lazy, Suspense } from 'react';
|
|
4
4
|
import ReactMarkdown from 'react-markdown';
|
|
5
5
|
import remarkGfm from 'remark-gfm';
|
|
6
|
-
import {
|
|
6
|
+
import { annotationId as toAnnotationId } from '@semiont/core';
|
|
7
|
+
import { getMimeCategory, isPdfMimeType } from '@semiont/core';
|
|
8
|
+
import { createHoverHandlers } from '@semiont/sdk';
|
|
7
9
|
import { ANNOTATORS } from '../../lib/annotation-registry';
|
|
8
10
|
import { scrollAnnotationIntoView } from '../../lib/scroll-utils';
|
|
9
11
|
import { ImageViewer } from '../viewers';
|
|
@@ -135,13 +137,13 @@ export const BrowseView = memo(function BrowseView({
|
|
|
135
137
|
if (annotationId && annotationType === 'reference') {
|
|
136
138
|
const annotation = allAnnotations.find(a => a.id === annotationId);
|
|
137
139
|
if (annotation) {
|
|
138
|
-
session.client.
|
|
140
|
+
session.client.browse.click(annotation.id, annotation.motivation);
|
|
139
141
|
}
|
|
140
142
|
}
|
|
141
143
|
};
|
|
142
144
|
|
|
143
145
|
const { handleMouseEnter, handleMouseLeave, cleanup: cleanupHover } = createHoverHandlers(
|
|
144
|
-
(
|
|
146
|
+
(id) => session.client.beckon.hover(id),
|
|
145
147
|
hoverDelayMs
|
|
146
148
|
);
|
|
147
149
|
|
|
@@ -150,7 +152,7 @@ export const BrowseView = memo(function BrowseView({
|
|
|
150
152
|
const target = e.target as HTMLElement;
|
|
151
153
|
const annotationElement = target.closest('[data-annotation-id]');
|
|
152
154
|
const annotationId = annotationElement?.getAttribute('data-annotation-id');
|
|
153
|
-
if (annotationId) handleMouseEnter(annotationId);
|
|
155
|
+
if (annotationId) handleMouseEnter(toAnnotationId(annotationId));
|
|
154
156
|
};
|
|
155
157
|
|
|
156
158
|
// Single mouseout handler for the container - fires once on exit
|
|
@@ -6,9 +6,8 @@ import { AnnotateView, type SelectionMotivation, type ClickAction, type ShapeTyp
|
|
|
6
6
|
import { BrowseView } from './BrowseView';
|
|
7
7
|
import { PopupContainer } from '../annotation-popups/SharedPopupElements';
|
|
8
8
|
import { JsonLdView } from '../annotation-popups/JsonLdView';
|
|
9
|
-
import type { components } from '@semiont/core';
|
|
10
|
-
import {
|
|
11
|
-
import { getExactText, getTargetSelector, isHighlight, isAssessment, isReference, isComment, isTag, getBodySource } from '@semiont/api-client';
|
|
9
|
+
import type { Annotation, AnnotationId, ResourceDescriptor as SemiontResource, components } from '@semiont/core';
|
|
10
|
+
import { getExactText, getTargetSelector, isHighlight, isAssessment, isReference, isComment, isTag, getBodySource } from '@semiont/core';
|
|
12
11
|
import { useEventSubscriptions } from '../../contexts/useEventSubscription';
|
|
13
12
|
import { useSemiont } from '../../session/SemiontProvider';
|
|
14
13
|
import { useObservable } from '../../hooks/useObservable';
|
|
@@ -17,9 +16,6 @@ import { ANNOTATORS } from '../../lib/annotation-registry';
|
|
|
17
16
|
import type { AnnotationsCollection } from '../../types/annotation-props';
|
|
18
17
|
import { getSelectorType, getSelectedShapeForSelectorType, saveSelectedShapeForSelectorType } from '../../lib/media-shapes';
|
|
19
18
|
|
|
20
|
-
type Annotation = components['schemas']['Annotation'];
|
|
21
|
-
type SemiontResource = components['schemas']['ResourceDescriptor'];
|
|
22
|
-
|
|
23
19
|
/**
|
|
24
20
|
* ResourceViewer - Display and interact with resource content and annotations
|
|
25
21
|
*
|
|
@@ -84,7 +80,7 @@ export function ResourceViewer({
|
|
|
84
80
|
if (!resource['@id']) {
|
|
85
81
|
throw new Error('Resource has no @id');
|
|
86
82
|
}
|
|
87
|
-
const rUri =
|
|
83
|
+
const rUri = resource['@id'];
|
|
88
84
|
|
|
89
85
|
// Helper to get MIME type from resource
|
|
90
86
|
const getMimeType = (): string => {
|
|
@@ -241,10 +237,10 @@ export function ResourceViewer({
|
|
|
241
237
|
};
|
|
242
238
|
};
|
|
243
239
|
|
|
244
|
-
// Handle deleting annotations
|
|
245
|
-
const handleDeleteAnnotation = useCallback((id:
|
|
246
|
-
session?.client.
|
|
247
|
-
}, [session]);
|
|
240
|
+
// Handle deleting annotations
|
|
241
|
+
const handleDeleteAnnotation = useCallback((id: AnnotationId) => {
|
|
242
|
+
session?.client.mark.delete(rUri, id);
|
|
243
|
+
}, [session, rUri]);
|
|
248
244
|
|
|
249
245
|
// Handle annotation clicks - memoized
|
|
250
246
|
const handleAnnotationClick = useCallback((annotation: Annotation, event?: React.MouseEvent) => {
|
|
@@ -5,7 +5,7 @@ import { BrowseView } from '../BrowseView';
|
|
|
5
5
|
import type { components, EventBus } from '@semiont/core';
|
|
6
6
|
import { createTestSemiontWrapper } from '../../../test-utils';
|
|
7
7
|
|
|
8
|
-
type Annotation
|
|
8
|
+
import type { Annotation } from '@semiont/core';
|
|
9
9
|
|
|
10
10
|
// Mock ResourceAnnotationsContext - keep this simple
|
|
11
11
|
let mockNewAnnotationIds = new Set<string>();
|
|
@@ -15,9 +15,9 @@ vi.mock('../../../contexts/ResourceAnnotationsContext', () => ({
|
|
|
15
15
|
})),
|
|
16
16
|
}));
|
|
17
17
|
|
|
18
|
-
// Mock @semiont/
|
|
19
|
-
vi.mock('@semiont/
|
|
20
|
-
const actual = await vi.importActual('@semiont/
|
|
18
|
+
// Mock @semiont/core utilities (these helpers and `resourceId` all live in core).
|
|
19
|
+
vi.mock('@semiont/core', async () => {
|
|
20
|
+
const actual = await vi.importActual('@semiont/core');
|
|
21
21
|
return {
|
|
22
22
|
...actual,
|
|
23
23
|
getMimeCategory: vi.fn((mimeType: string) => {
|