triiiceratops 0.11.0 → 0.11.2
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/README.md +17 -9
- package/dist/{ArrowCounterClockwise-CN8KGaI0.js → ArrowCounterClockwise-B_hB6fl1.js} +1 -1
- package/dist/X-Boj9jj2h.js +890 -0
- package/dist/{annotation_tool_point-BpZXtX5D.js → annotation_tool_point-rZvdAtGa.js} +1 -1
- package/dist/annotorious-openseadragon.es-tb5X-LtF.js +33045 -0
- package/dist/components/AnnotationOverlay.svelte +10 -17
- package/dist/components/DemoHeader.svelte +4 -5
- package/dist/components/MetadataDialog.svelte +4 -1
- package/dist/components/OSDViewer.svelte +8 -2
- package/dist/components/SearchPanel.svelte +8 -5
- package/dist/components/ThemeToggle.svelte +1 -1
- package/dist/components/ThumbnailGallery.svelte +4 -4
- package/dist/components/Toolbar.svelte +5 -4
- package/dist/components/TriiiceratopsViewerElement.svelte +3 -1
- package/dist/custom-element.js +1 -0
- package/dist/{image_filters_reset-CyWg622b.js → image_filters_reset-CAUhlDWt.js} +1 -1
- package/dist/plugins/annotation-editor/AnnotationEditorController.svelte +5 -3
- package/dist/plugins/annotation-editor/AnnotationEditorPanel.svelte +3 -3
- package/dist/plugins/annotation-editor/AnnotationManager.svelte.d.ts +3 -0
- package/dist/plugins/annotation-editor/AnnotationManager.svelte.js +19 -14
- package/dist/plugins/annotation-editor/loader.svelte.js +2 -2
- package/dist/plugins/annotation-editor.js +1228 -32159
- package/dist/plugins/image-manipulation/ImageManipulationController.svelte +1 -1
- package/dist/plugins/image-manipulation.js +3 -3
- package/dist/state/manifests.svelte.d.ts +2 -1
- package/dist/state/manifests.svelte.js +5 -9
- package/dist/state/manifests.test.js +52 -50
- package/dist/state/viewer.svelte.d.ts +2 -1
- package/dist/state/viewer.svelte.js +8 -8
- package/dist/triiiceratops-bundle.js +1167 -1179
- package/dist/triiiceratops-element.iife.js +26 -26
- package/dist/triiiceratops.css +1 -1
- package/dist/utils/annotationAdapter.js +2 -2
- package/dist/utils/annotationAdapter.test.js +0 -1
- package/package.json +12 -2
- package/dist/X-i_EmjXwW.js +0 -906
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import ImageManipulationPanel from './ImageManipulationPanel.svelte';
|
|
10
10
|
|
|
11
11
|
// Props from the plugin system
|
|
12
|
-
let { isOpen = false, close } = $props();
|
|
12
|
+
let { isOpen: _isOpen = false, close } = $props();
|
|
13
13
|
|
|
14
14
|
const viewerState = getContext<ViewerState>(VIEWER_STATE_KEY);
|
|
15
15
|
let filters = $state<ImageFilters>({ ...DEFAULT_FILTERS });
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import "svelte/internal/disclose-version";
|
|
2
2
|
import * as e from "svelte/internal/client";
|
|
3
3
|
import { getContext as s0 } from "svelte";
|
|
4
|
-
import { l as l0, s as i0, X as n0, c as o0, V as c0, g as v0 } from "../X-
|
|
5
|
-
import { A as d0 } from "../ArrowCounterClockwise-
|
|
6
|
-
import { i as _0, a as g0, b as f0, g as u0, c as h0, e as m0, d as p0, f as b0 } from "../image_filters_reset-
|
|
4
|
+
import { l as l0, s as i0, X as n0, c as o0, V as c0, g as v0 } from "../X-Boj9jj2h.js";
|
|
5
|
+
import { A as d0 } from "../ArrowCounterClockwise-B_hB6fl1.js";
|
|
6
|
+
import { i as _0, a as g0, b as f0, g as u0, c as h0, e as m0, d as p0, f as b0 } from "../image_filters_reset-CAUhlDWt.js";
|
|
7
7
|
const G = {
|
|
8
8
|
brightness: 100,
|
|
9
9
|
contrast: 100,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SvelteMap } from 'svelte/reactivity';
|
|
1
2
|
export interface ManifestEntry {
|
|
2
3
|
json?: any;
|
|
3
4
|
manifesto?: any;
|
|
@@ -6,7 +7,7 @@ export interface ManifestEntry {
|
|
|
6
7
|
}
|
|
7
8
|
export declare class ManifestsState {
|
|
8
9
|
manifests: Record<string, ManifestEntry>;
|
|
9
|
-
userAnnotations:
|
|
10
|
+
userAnnotations: SvelteMap<string, any[]>;
|
|
10
11
|
constructor();
|
|
11
12
|
private userAnnotationKey;
|
|
12
13
|
setUserAnnotations(manifestId: string, canvasId: string, annotations: any[]): void;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { SvelteMap } from 'svelte/reactivity';
|
|
1
2
|
import * as manifesto from 'manifesto.js';
|
|
2
3
|
export class ManifestsState {
|
|
3
4
|
manifests = $state({});
|
|
4
5
|
// User-created annotations (from plugins like annotation editor)
|
|
5
|
-
userAnnotations =
|
|
6
|
+
userAnnotations = new SvelteMap();
|
|
6
7
|
constructor() { }
|
|
7
8
|
// === User Annotations API ===
|
|
8
9
|
userAnnotationKey(manifestId, canvasId) {
|
|
@@ -10,17 +11,12 @@ export class ManifestsState {
|
|
|
10
11
|
}
|
|
11
12
|
setUserAnnotations(manifestId, canvasId, annotations) {
|
|
12
13
|
const key = this.userAnnotationKey(manifestId, canvasId);
|
|
13
|
-
|
|
14
|
-
const newMap = new Map(this.userAnnotations);
|
|
15
|
-
newMap.set(key, annotations);
|
|
16
|
-
this.userAnnotations = newMap;
|
|
14
|
+
this.userAnnotations.set(key, annotations);
|
|
17
15
|
}
|
|
18
16
|
clearUserAnnotations(manifestId, canvasId) {
|
|
19
17
|
const key = this.userAnnotationKey(manifestId, canvasId);
|
|
20
18
|
if (this.userAnnotations.has(key)) {
|
|
21
|
-
|
|
22
|
-
newMap.delete(key);
|
|
23
|
-
this.userAnnotations = newMap;
|
|
19
|
+
this.userAnnotations.delete(key);
|
|
24
20
|
}
|
|
25
21
|
}
|
|
26
22
|
getUserAnnotations(manifestId, canvasId) {
|
|
@@ -109,7 +105,7 @@ export class ManifestsState {
|
|
|
109
105
|
// Manifesto wraps the JSON. We can access the underlying JSON via canvas.__jsonld
|
|
110
106
|
// Or better, use canvas.getContent() if it works, but for external lists manual fetch is robust.
|
|
111
107
|
const canvasJson = canvas.__jsonld;
|
|
112
|
-
|
|
108
|
+
const annotations = [];
|
|
113
109
|
// Helper to parse list using Manifesto
|
|
114
110
|
const parseList = (listJson) => {
|
|
115
111
|
// manifesto.create is not available in 4.3.0 or not exported nicely?
|
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from
|
|
2
|
-
import { ManifestsState } from
|
|
3
|
-
import * as manifesto from
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { ManifestsState } from './manifests.svelte';
|
|
3
|
+
import * as manifesto from 'manifesto.js';
|
|
4
4
|
// Mock manifesto.js since it's an external dependency
|
|
5
|
-
vi.mock(
|
|
5
|
+
vi.mock('manifesto.js', async (importOriginal) => {
|
|
6
6
|
const actual = await importOriginal();
|
|
7
7
|
return {
|
|
8
8
|
...actual,
|
|
9
|
-
parseManifest: vi.fn((
|
|
9
|
+
parseManifest: vi.fn((_json) => {
|
|
10
10
|
// Minimal mock of a manifesto object
|
|
11
11
|
return {
|
|
12
12
|
getSequences: () => [
|
|
13
13
|
{
|
|
14
|
-
getCanvases: () => [{ id:
|
|
14
|
+
getCanvases: () => [{ id: 'canvas1' }],
|
|
15
15
|
getCanvasById: (id) => {
|
|
16
|
-
if (id ===
|
|
16
|
+
if (id === 'canvas1') {
|
|
17
17
|
return {
|
|
18
|
-
id:
|
|
18
|
+
id: 'canvas1',
|
|
19
19
|
__jsonld: {
|
|
20
20
|
otherContent: [
|
|
21
21
|
{
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
'@id': 'http://example.org/list1',
|
|
23
|
+
'@type': 'sc:AnnotationList',
|
|
24
24
|
},
|
|
25
25
|
],
|
|
26
26
|
annotations: [
|
|
27
27
|
// v3 style
|
|
28
28
|
{
|
|
29
|
-
id:
|
|
30
|
-
type:
|
|
29
|
+
id: 'http://example.org/list2',
|
|
30
|
+
type: 'AnnotationPage',
|
|
31
31
|
},
|
|
32
32
|
],
|
|
33
33
|
},
|
|
@@ -41,80 +41,82 @@ vi.mock("manifesto.js", async (importOriginal) => {
|
|
|
41
41
|
}),
|
|
42
42
|
};
|
|
43
43
|
});
|
|
44
|
-
describe(
|
|
44
|
+
describe('ManifestsState', () => {
|
|
45
45
|
let state;
|
|
46
46
|
const mockFetch = vi.fn();
|
|
47
47
|
beforeEach(() => {
|
|
48
|
-
vi.stubGlobal(
|
|
48
|
+
vi.stubGlobal('fetch', mockFetch);
|
|
49
49
|
state = new ManifestsState();
|
|
50
50
|
mockFetch.mockReset();
|
|
51
51
|
});
|
|
52
52
|
afterEach(() => {
|
|
53
53
|
vi.restoreAllMocks();
|
|
54
54
|
});
|
|
55
|
-
describe(
|
|
56
|
-
it(
|
|
55
|
+
describe('fetchManifest', () => {
|
|
56
|
+
it('should fetch and store a manifest', async () => {
|
|
57
57
|
const mockManifest = {
|
|
58
|
-
|
|
59
|
-
label:
|
|
58
|
+
'@id': 'http://example.org/manifest',
|
|
59
|
+
label: 'Test Manifest',
|
|
60
60
|
};
|
|
61
61
|
mockFetch.mockResolvedValueOnce({
|
|
62
62
|
ok: true,
|
|
63
63
|
json: async () => mockManifest,
|
|
64
64
|
});
|
|
65
|
-
await state.fetchManifest(
|
|
66
|
-
expect(mockFetch).toHaveBeenCalledWith(
|
|
67
|
-
expect(state.manifests[
|
|
68
|
-
expect(state.manifests[
|
|
69
|
-
expect(state.manifests[
|
|
65
|
+
await state.fetchManifest('http://example.org/manifest');
|
|
66
|
+
expect(mockFetch).toHaveBeenCalledWith('http://example.org/manifest');
|
|
67
|
+
expect(state.manifests['http://example.org/manifest']).toBeDefined();
|
|
68
|
+
expect(state.manifests['http://example.org/manifest'].json).toEqual(mockManifest);
|
|
69
|
+
expect(state.manifests['http://example.org/manifest'].isFetching).toBe(false);
|
|
70
70
|
expect(manifesto.parseManifest).toHaveBeenCalledWith(mockManifest);
|
|
71
71
|
});
|
|
72
|
-
it(
|
|
73
|
-
mockFetch.mockRejectedValueOnce(new Error(
|
|
74
|
-
await state.fetchManifest(
|
|
75
|
-
expect(state.manifests[
|
|
76
|
-
expect(state.manifests[
|
|
72
|
+
it('should handle fetch errors', async () => {
|
|
73
|
+
mockFetch.mockRejectedValueOnce(new Error('Network Error'));
|
|
74
|
+
await state.fetchManifest('http://example.org/error');
|
|
75
|
+
expect(state.manifests['http://example.org/error'].error).toBe('Network Error');
|
|
76
|
+
expect(state.manifests['http://example.org/error'].isFetching).toBe(false);
|
|
77
77
|
});
|
|
78
|
-
it(
|
|
78
|
+
it('should not fetch if already fetched', async () => {
|
|
79
79
|
// Prime the state
|
|
80
|
-
state.manifests[
|
|
80
|
+
state.manifests['http://example.org/cached'] = {
|
|
81
81
|
isFetching: false,
|
|
82
82
|
json: {},
|
|
83
83
|
};
|
|
84
|
-
await state.fetchManifest(
|
|
84
|
+
await state.fetchManifest('http://example.org/cached');
|
|
85
85
|
expect(mockFetch).not.toHaveBeenCalled();
|
|
86
86
|
});
|
|
87
87
|
});
|
|
88
|
-
describe(
|
|
89
|
-
it(
|
|
88
|
+
describe('getCanvases', () => {
|
|
89
|
+
it('should return canvases from parsed manifest', async () => {
|
|
90
90
|
// Mock internal state directly to avoid fetch overhead
|
|
91
|
-
state.manifests[
|
|
91
|
+
state.manifests['http://example.org/manifest'] = {
|
|
92
92
|
manifesto: {
|
|
93
93
|
getSequences: () => [
|
|
94
94
|
{
|
|
95
|
-
getCanvases: () => [
|
|
95
|
+
getCanvases: () => ['mockCanvas1', 'mockCanvas2'],
|
|
96
96
|
},
|
|
97
97
|
],
|
|
98
98
|
},
|
|
99
99
|
};
|
|
100
|
-
const canvases = state.getCanvases(
|
|
101
|
-
expect(canvases).toEqual([
|
|
100
|
+
const canvases = state.getCanvases('http://example.org/manifest');
|
|
101
|
+
expect(canvases).toEqual(['mockCanvas1', 'mockCanvas2']);
|
|
102
102
|
});
|
|
103
|
-
it(
|
|
104
|
-
const canvases = state.getCanvases(
|
|
103
|
+
it('should return empty array if manifest not found', () => {
|
|
104
|
+
const canvases = state.getCanvases('http://example.org/missing');
|
|
105
105
|
expect(canvases).toEqual([]);
|
|
106
106
|
});
|
|
107
107
|
});
|
|
108
|
-
describe(
|
|
109
|
-
it(
|
|
108
|
+
describe('manualGetAnnotations', () => {
|
|
109
|
+
it('should extract annotations and trigger fetch for external lists', async () => {
|
|
110
110
|
// Setup mock state with a manifest that has a canvas
|
|
111
|
-
state.manifests[
|
|
111
|
+
state.manifests['http://example.org/manifest'] = {
|
|
112
112
|
manifesto: {
|
|
113
113
|
getSequences: () => [
|
|
114
114
|
{
|
|
115
115
|
getCanvasById: () => ({
|
|
116
116
|
__jsonld: {
|
|
117
|
-
otherContent: [
|
|
117
|
+
otherContent: [
|
|
118
|
+
{ '@id': 'http://example.org/list1' },
|
|
119
|
+
],
|
|
118
120
|
},
|
|
119
121
|
}),
|
|
120
122
|
},
|
|
@@ -124,24 +126,24 @@ describe("ManifestsState", () => {
|
|
|
124
126
|
// Mock the fetch for the annotation list
|
|
125
127
|
mockFetch.mockResolvedValue({
|
|
126
128
|
ok: true,
|
|
127
|
-
json: async () => ({ resources: [{
|
|
129
|
+
json: async () => ({ resources: [{ '@id': 'anno1' }] }),
|
|
128
130
|
});
|
|
129
131
|
// First call triggers fetch
|
|
130
132
|
// manualGetAnnotations calls fetchAnnotationList which is async, but manualGetAnnotations itself is synchronous and returns partial data
|
|
131
|
-
state.manualGetAnnotations(
|
|
133
|
+
state.manualGetAnnotations('http://example.org/manifest', 'canvas1');
|
|
132
134
|
// We need to wait for the async fetchAnnotationList to complete.
|
|
133
135
|
// Since it's not returned, we can wait a tick or use `vi.waitFor` if available,
|
|
134
136
|
// but simpler here is just to await a small delay since we are mocking.
|
|
135
137
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
136
|
-
expect(mockFetch).toHaveBeenCalledWith(
|
|
138
|
+
expect(mockFetch).toHaveBeenCalledWith('http://example.org/list1');
|
|
137
139
|
// Simulate update after fetch (in real app this is reactive, here we manually update state)
|
|
138
|
-
state.manifests[
|
|
139
|
-
json: { resources: [{
|
|
140
|
+
state.manifests['http://example.org/list1'] = {
|
|
141
|
+
json: { resources: [{ '@id': 'anno1' }] },
|
|
140
142
|
};
|
|
141
143
|
// Second call should return the annotations
|
|
142
|
-
const annos = state.manualGetAnnotations(
|
|
144
|
+
const annos = state.manualGetAnnotations('http://example.org/manifest', 'canvas1');
|
|
143
145
|
expect(annos).toHaveLength(1);
|
|
144
|
-
expect(annos[0][
|
|
146
|
+
expect(annos[0]['@id']).toBe('anno1');
|
|
145
147
|
});
|
|
146
148
|
});
|
|
147
149
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SvelteSet } from 'svelte/reactivity';
|
|
1
2
|
import type { ViewerConfig } from '../types/config';
|
|
2
3
|
import type { PluginMenuButton, PluginPanel, PluginDef } from '../types/plugin';
|
|
3
4
|
/**
|
|
@@ -27,7 +28,7 @@ export declare class ViewerState {
|
|
|
27
28
|
isFullScreen: boolean;
|
|
28
29
|
showMetadataDialog: boolean;
|
|
29
30
|
dockSide: string;
|
|
30
|
-
visibleAnnotationIds:
|
|
31
|
+
visibleAnnotationIds: SvelteSet<string>;
|
|
31
32
|
config: ViewerConfig;
|
|
32
33
|
get showToggle(): boolean;
|
|
33
34
|
get showCanvasNav(): boolean;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SvelteSet, SvelteMap } from 'svelte/reactivity';
|
|
1
2
|
import { manifestsState } from './manifests.svelte.js';
|
|
2
3
|
export class ViewerState {
|
|
3
4
|
manifestId = $state(null);
|
|
@@ -10,7 +11,7 @@ export class ViewerState {
|
|
|
10
11
|
isFullScreen = $state(false);
|
|
11
12
|
showMetadataDialog = $state(false);
|
|
12
13
|
dockSide = $state('bottom');
|
|
13
|
-
visibleAnnotationIds =
|
|
14
|
+
visibleAnnotationIds = new SvelteSet();
|
|
14
15
|
// UI Configuration
|
|
15
16
|
config = $state({});
|
|
16
17
|
// Derived configuration specific getters
|
|
@@ -328,7 +329,7 @@ export class ViewerState {
|
|
|
328
329
|
const data = await response.json();
|
|
329
330
|
const resources = data.resources || [];
|
|
330
331
|
// Group results by canvas index
|
|
331
|
-
const resultsByCanvas = new
|
|
332
|
+
const resultsByCanvas = new SvelteMap();
|
|
332
333
|
// Helper to parse xywh
|
|
333
334
|
const parseSelector = (onVal) => {
|
|
334
335
|
const val = typeof onVal === 'string'
|
|
@@ -362,7 +363,7 @@ export class ViewerState {
|
|
|
362
363
|
// We will take the first valid canvas we find for the annotations.
|
|
363
364
|
let canvasIndex = -1;
|
|
364
365
|
let bounds = null;
|
|
365
|
-
|
|
366
|
+
const allBounds = [];
|
|
366
367
|
for (const annoId of annotations) {
|
|
367
368
|
const annotation = resources.find((r) => r['@id'] === annoId || r.id === annoId);
|
|
368
369
|
if (annotation && annotation.on) {
|
|
@@ -406,7 +407,7 @@ export class ViewerState {
|
|
|
406
407
|
label = canvas.label[0]?.value;
|
|
407
408
|
}
|
|
408
409
|
}
|
|
409
|
-
catch (
|
|
410
|
+
catch (_e) {
|
|
410
411
|
/* ignore */
|
|
411
412
|
}
|
|
412
413
|
resultsByCanvas.set(canvasIndex, {
|
|
@@ -454,7 +455,7 @@ export class ViewerState {
|
|
|
454
455
|
label = canvas.label[0]?.value;
|
|
455
456
|
}
|
|
456
457
|
}
|
|
457
|
-
catch (
|
|
458
|
+
catch (_e) {
|
|
458
459
|
/* ignore */
|
|
459
460
|
}
|
|
460
461
|
if (!resultsByCanvas.has(canvasIndex)) {
|
|
@@ -527,7 +528,7 @@ export class ViewerState {
|
|
|
527
528
|
/** OpenSeadragon viewer instance (set by OSDViewer) */
|
|
528
529
|
osdViewer = $state.raw(null);
|
|
529
530
|
/** Event handlers for inter-plugin communication */
|
|
530
|
-
pluginEventHandlers = new
|
|
531
|
+
pluginEventHandlers = new SvelteMap();
|
|
531
532
|
// ==================== PLUGIN METHODS ====================
|
|
532
533
|
/**
|
|
533
534
|
* Register a plugin with this viewer instance.
|
|
@@ -557,8 +558,7 @@ export class ViewerState {
|
|
|
557
558
|
isVisible: () => isOpen,
|
|
558
559
|
props: {
|
|
559
560
|
...def.props,
|
|
560
|
-
// Pass
|
|
561
|
-
isOpen: isOpen,
|
|
561
|
+
// Pass closer to component
|
|
562
562
|
close: () => {
|
|
563
563
|
isOpen = false;
|
|
564
564
|
},
|