@annotorious/react-manifold 0.0.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/LICENSE +28 -0
- package/README.md +7 -0
- package/package.json +40 -0
- package/src/Annotorious.tsx +48 -0
- package/src/AnnotoriousManifold.tsx +140 -0
- package/src/AnnotoriousManifoldInstance.ts +95 -0
- package/src/index.ts +3 -0
- package/src/synchronizeInstances.tsx +11 -0
- package/test/33054-000002-0001.jpg +0 -0
- package/test/App.tsx +50 -0
- package/test/index.css +18 -0
- package/test/index.html +12 -0
- package/test/index.tsx +13 -0
- package/tsconfig.json +26 -0
- package/tsconfig.node.json +10 -0
- package/vite.config.js +40 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023, Annotorious
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Annotorious React Manifold
|
|
2
|
+
|
|
3
|
+
A utility to manage multiple parallel Annotorious instances more efficiently.
|
|
4
|
+
|
|
5
|
+
- Listen to annotation lifecycle events across all instances with just one listener.
|
|
6
|
+
- Find, retrieve and manipulate annotations across instances easily.
|
|
7
|
+
- Add multiple Annotorious instances with the same image, and let the Manifold handle live state sync.
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@annotorious/react-manifold",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "A utility to manage multiple parallel Annotorious instances more efficiently",
|
|
5
|
+
"author": "Rainer Simon",
|
|
6
|
+
"license": "BSD-3-Clause",
|
|
7
|
+
"homepage": "https://github.com/annotorious/annotorious-react-manifold#readme",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/annotorious/annotorious-react-manifold.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/annotorious/annotorious-react-manifold/issues"
|
|
14
|
+
},
|
|
15
|
+
"type": "module",
|
|
16
|
+
"scripts": {
|
|
17
|
+
"start": "vite",
|
|
18
|
+
"build": "tsc && vite build"
|
|
19
|
+
},
|
|
20
|
+
"main": "src/index.ts",
|
|
21
|
+
"sideEffects": false,
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/react": "^18.2.35",
|
|
24
|
+
"@types/react-dom": "^18.2.14",
|
|
25
|
+
"@vitejs/plugin-react": "^4.1.1",
|
|
26
|
+
"svelte": "^3.59.2",
|
|
27
|
+
"typescript": "^4.9.5",
|
|
28
|
+
"vite": "^4.5.0",
|
|
29
|
+
"vite-plugin-dts": "^3.6.3",
|
|
30
|
+
"vite-tsconfig-paths": "^4.2.1"
|
|
31
|
+
},
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"@annotorious/react": "^3.0.0-pre-alpha-55",
|
|
34
|
+
"react": "16.8.0 || >=17.x || >=18.x",
|
|
35
|
+
"react-dom": "16.8.0 || >=17.x || >=18.x"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@annotorious/core": "^3.0.0-pre-alpha-55"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { ReactNode, useContext, useEffect } from 'react';
|
|
2
|
+
import { Annotation, Annotator, useAnnotator } from '@annotorious/react';
|
|
3
|
+
import { Annotorious as AnnotoriousInstance } from '@annotorious/react';
|
|
4
|
+
import { AnnotoriousManifoldContext } from './AnnotoriousManifold';
|
|
5
|
+
|
|
6
|
+
interface AnnotoriousProps {
|
|
7
|
+
|
|
8
|
+
children: ReactNode;
|
|
9
|
+
|
|
10
|
+
source: string;
|
|
11
|
+
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Consumes the standard Annotorious context, and passes the Annotator
|
|
16
|
+
* upwards to the manifold.
|
|
17
|
+
*/
|
|
18
|
+
const AnnotoriousInstanceShim = <I extends Annotation = Annotation, E extends unknown = Annotation>(props: AnnotoriousProps) => {
|
|
19
|
+
|
|
20
|
+
const anno = useAnnotator<Annotator<I, E>>();
|
|
21
|
+
|
|
22
|
+
const { connectAnnotator } = useContext(AnnotoriousManifoldContext);
|
|
23
|
+
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (anno)
|
|
26
|
+
return connectAnnotator(props.source, anno);
|
|
27
|
+
}, [anno]);
|
|
28
|
+
|
|
29
|
+
return <>{props.children}</>;
|
|
30
|
+
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* An alternative <Annotorious /> component that mimicks the original
|
|
35
|
+
* from @annotorious/react, but injects the shim component, which connects
|
|
36
|
+
* the Annotator to the Manifold.
|
|
37
|
+
*/
|
|
38
|
+
export const Annotorious = (props: AnnotoriousProps) => {
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<AnnotoriousInstance>
|
|
42
|
+
<AnnotoriousInstanceShim source={props.source}>
|
|
43
|
+
{props.children}
|
|
44
|
+
</AnnotoriousInstanceShim>
|
|
45
|
+
</AnnotoriousInstance>
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { ReactNode, createContext, useContext, useEffect, useRef, useState } from 'react';
|
|
2
|
+
import type { Annotation, Annotator, StoreChangeEvent } from '@annotorious/core';
|
|
3
|
+
import { AnnotoriousManifoldInstance, createManifoldInstance } from './AnnotoriousManifoldInstance';
|
|
4
|
+
|
|
5
|
+
interface AnnotoriousManifoldContextValue {
|
|
6
|
+
|
|
7
|
+
annotators: Map<string, Annotator<any, unknown>>;
|
|
8
|
+
|
|
9
|
+
annotations: Map<string, Annotation[]>;
|
|
10
|
+
|
|
11
|
+
selection: ManifoldSelection;
|
|
12
|
+
|
|
13
|
+
connectAnnotator(source: string, anno: Annotator<any, unknown>): () => void;
|
|
14
|
+
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface ManifoldSelection<T extends Annotation = Annotation> {
|
|
18
|
+
|
|
19
|
+
source?: string;
|
|
20
|
+
|
|
21
|
+
selected: { annotation: T, editable?: boolean }[],
|
|
22
|
+
|
|
23
|
+
pointerEvent?: PointerEvent;
|
|
24
|
+
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// @ts-ignore
|
|
28
|
+
export const AnnotoriousManifoldContext = createContext<AnnotoriousManifoldContextValue>();
|
|
29
|
+
|
|
30
|
+
export const AnnotoriousManifold = (props: { children: ReactNode }) => {
|
|
31
|
+
|
|
32
|
+
const [annotators, setAnnotators] = useState<Map<string, Annotator<any, unknown>>>(new Map());
|
|
33
|
+
|
|
34
|
+
const [annotations, setAnnotations] = useState<Map<string, Annotation[]>>(new Map());
|
|
35
|
+
|
|
36
|
+
const [selection, setSelection] =
|
|
37
|
+
useState<ManifoldSelection>({ selected: [] });
|
|
38
|
+
|
|
39
|
+
// To prevent selection state updates when de-selecting other annotators
|
|
40
|
+
const muteSelectionEvents = useRef<boolean>(false);
|
|
41
|
+
|
|
42
|
+
const connectAnnotator = (source: string, anno: Annotator<any, unknown>) => {
|
|
43
|
+
// Add the annotator to the state
|
|
44
|
+
setAnnotators(m => new Map(m.entries()).set(source, anno))
|
|
45
|
+
|
|
46
|
+
const { store } = anno.state;
|
|
47
|
+
const selectionState = anno.state.selection;
|
|
48
|
+
|
|
49
|
+
// Add the annotations to the state
|
|
50
|
+
setAnnotations(m => new Map(m.entries()).set(source, store.all()));
|
|
51
|
+
|
|
52
|
+
const onStoreChange = () =>
|
|
53
|
+
setAnnotations(m => new Map(m.entries()).set(source, store.all()));
|
|
54
|
+
|
|
55
|
+
store.observe(onStoreChange);
|
|
56
|
+
|
|
57
|
+
// Track selection
|
|
58
|
+
let selectionStoreObserver: (event: StoreChangeEvent<Annotation>) => void;
|
|
59
|
+
|
|
60
|
+
const unsubscribeSelection = selectionState.subscribe(({ selected, pointerEvent }) => {
|
|
61
|
+
if (selectionStoreObserver)
|
|
62
|
+
store.unobserve(selectionStoreObserver);
|
|
63
|
+
|
|
64
|
+
const resolved = (selected || [])
|
|
65
|
+
.map(({ id, editable }) => ({ annotation: store.getAnnotation(id), editable }));
|
|
66
|
+
|
|
67
|
+
// Set the new selection
|
|
68
|
+
if (!muteSelectionEvents.current)
|
|
69
|
+
setSelection({ source, selected: resolved, pointerEvent });
|
|
70
|
+
|
|
71
|
+
// Track the state of the selected annotations in the store
|
|
72
|
+
selectionStoreObserver = event => {
|
|
73
|
+
const { updated } = event.changes;
|
|
74
|
+
|
|
75
|
+
setSelection(({ source, selected }) => ({
|
|
76
|
+
source,
|
|
77
|
+
selected: selected.map(({ annotation, editable }) => {
|
|
78
|
+
const next = updated.find(u => u.oldValue.id === annotation.id);
|
|
79
|
+
return next ? { annotation: next.newValue, editable } : { annotation, editable };
|
|
80
|
+
}),
|
|
81
|
+
pointerEvent
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
store.observe(selectionStoreObserver, { annotations: selected.map(({ id }) => id) });
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
return () => {
|
|
89
|
+
// Remove annotator
|
|
90
|
+
setAnnotators(m => new Map(Array.from(m.entries()).filter(([key, _]) => key !== source)));
|
|
91
|
+
|
|
92
|
+
// Remove & untrack annotations
|
|
93
|
+
setAnnotations(m => new Map(Array.from(m.entries()).filter(([key, _]) => key !== source)));
|
|
94
|
+
store.unobserve(onStoreChange);
|
|
95
|
+
|
|
96
|
+
// Un-track selection
|
|
97
|
+
unsubscribeSelection();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
if (selection.source) {
|
|
103
|
+
muteSelectionEvents.current = true;
|
|
104
|
+
|
|
105
|
+
Array.from(annotators.entries()).forEach(([source, anno]) => {
|
|
106
|
+
if (source !== selection.source)
|
|
107
|
+
anno.setSelected();
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
muteSelectionEvents.current = false;
|
|
111
|
+
}
|
|
112
|
+
}, [selection, annotators]);
|
|
113
|
+
|
|
114
|
+
return (
|
|
115
|
+
<AnnotoriousManifoldContext.Provider value={{
|
|
116
|
+
annotators,
|
|
117
|
+
annotations,
|
|
118
|
+
selection,
|
|
119
|
+
connectAnnotator
|
|
120
|
+
}}>
|
|
121
|
+
{props.children}
|
|
122
|
+
</AnnotoriousManifoldContext.Provider>
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export const useAnnotoriousManifold = <I extends Annotation = Annotation, E extends unknown = Annotation>() => {
|
|
128
|
+
const { annotators } = useContext(AnnotoriousManifoldContext);
|
|
129
|
+
return createManifoldInstance(annotators) as AnnotoriousManifoldInstance<I, E>;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export const useAnnotations = <T extends Annotation>() => {
|
|
133
|
+
const { annotations } = useContext(AnnotoriousManifoldContext);
|
|
134
|
+
return annotations as Map<string, T[]>;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export const useSelection = <T extends Annotation>() => {
|
|
138
|
+
const { selection } = useContext(AnnotoriousManifoldContext);
|
|
139
|
+
return selection as ManifoldSelection<T>;
|
|
140
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Annotation,
|
|
3
|
+
AnnotationBody,
|
|
4
|
+
Annotator,
|
|
5
|
+
LifecycleEvents,
|
|
6
|
+
Origin
|
|
7
|
+
} from '@annotorious/core';
|
|
8
|
+
|
|
9
|
+
export interface AnnotoriousManifoldInstance<I extends Annotation = Annotation, E extends unknown = Annotation> {
|
|
10
|
+
|
|
11
|
+
annotators: Annotator<I, E>[];
|
|
12
|
+
|
|
13
|
+
sources: string[];
|
|
14
|
+
|
|
15
|
+
// style: DrawingStyle | ((annotation: I) => DrawingStyle) | undefined;
|
|
16
|
+
|
|
17
|
+
addBody(body: AnnotationBody, origin?: Origin): void;
|
|
18
|
+
|
|
19
|
+
clear(origin: Origin): void;
|
|
20
|
+
|
|
21
|
+
deleteAnnotation(id: string, origin?: Origin): E | undefined;
|
|
22
|
+
|
|
23
|
+
destroy(): void;
|
|
24
|
+
|
|
25
|
+
getAnnotationById(id: string): E | undefined;
|
|
26
|
+
|
|
27
|
+
getAnnotations(): E[];
|
|
28
|
+
|
|
29
|
+
on<T extends keyof LifecycleEvents<E>>(event: T, callback: LifecycleEvents<E>[T]): void;
|
|
30
|
+
|
|
31
|
+
off<T extends keyof LifecycleEvents<E>>(event: T, callback: LifecycleEvents<E>[T]): void;
|
|
32
|
+
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const createManifoldInstance = <I extends Annotation = Annotation, E extends unknown = Annotation>(
|
|
36
|
+
annotators: Map<string, Annotator<I, E>>
|
|
37
|
+
): AnnotoriousManifoldInstance<I, E> => {
|
|
38
|
+
|
|
39
|
+
const find = (annotationId: string): { annotation?: E, annotator?: Annotator<I, E> } =>
|
|
40
|
+
Array.from(annotators.values()).reduce((found, annotator) => {
|
|
41
|
+
if (found)
|
|
42
|
+
return found;
|
|
43
|
+
|
|
44
|
+
const annotation = annotator.getAnnotationById(annotationId);
|
|
45
|
+
if (annotation)
|
|
46
|
+
return { annotation, annotator };
|
|
47
|
+
}, undefined as { annotation: E, annotator: Annotator<I, E> } | undefined ) ||
|
|
48
|
+
|
|
49
|
+
{ annotation: undefined, annotator: undefined };
|
|
50
|
+
|
|
51
|
+
/*********/
|
|
52
|
+
/** API **/
|
|
53
|
+
/*********/
|
|
54
|
+
|
|
55
|
+
const addBody = (body: AnnotationBody, origin = Origin.LOCAL) => {
|
|
56
|
+
const { annotator } = find(body.annotation);
|
|
57
|
+
if (annotator)
|
|
58
|
+
annotator.state.store.addBody(body, origin);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const clear = (origin = Origin.LOCAL) =>
|
|
62
|
+
Array.from(annotators.values()).forEach(a => a.state.store.clear(origin));
|
|
63
|
+
|
|
64
|
+
const deleteAnnotation = (id: string, origin = Origin.LOCAL) => {
|
|
65
|
+
const { annotation, annotator } = find(id);
|
|
66
|
+
|
|
67
|
+
if (annotator) {
|
|
68
|
+
annotator.state.store.deleteAnnotation(id, origin);
|
|
69
|
+
return annotation;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const destroy = () =>
|
|
74
|
+
Array.from(annotators.values()).forEach(a => a.destroy());
|
|
75
|
+
|
|
76
|
+
const getAnnotationById = (id: string) =>
|
|
77
|
+
find(id).annotation;
|
|
78
|
+
|
|
79
|
+
const getAnnotations = () =>
|
|
80
|
+
Array.from(annotators.values()).reduce((all, annotator) =>
|
|
81
|
+
[...all, ...annotator.getAnnotations()], [] as E[])
|
|
82
|
+
|
|
83
|
+
// @ts-ignore
|
|
84
|
+
return {
|
|
85
|
+
annotators: [...annotators.values()],
|
|
86
|
+
sources: [...annotators.keys()],
|
|
87
|
+
addBody,
|
|
88
|
+
clear,
|
|
89
|
+
deleteAnnotation,
|
|
90
|
+
destroy,
|
|
91
|
+
getAnnotationById,
|
|
92
|
+
getAnnotations
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Annotation, Annotator } from '@annotorious/core';
|
|
2
|
+
|
|
3
|
+
export const synchronizeInstances = <I extends Annotation = Annotation, E extends unknown = Annotation>(
|
|
4
|
+
instances: Annotator<I, E>[]
|
|
5
|
+
) => {
|
|
6
|
+
|
|
7
|
+
// TODO listen on all instances, broadcast changes on one instance to the others
|
|
8
|
+
|
|
9
|
+
return null;
|
|
10
|
+
|
|
11
|
+
}
|
|
Binary file
|
package/test/App.tsx
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React, { useEffect } from 'react';
|
|
2
|
+
import { OpenSeadragonAnnotator, OpenSeadragonViewer } from '@annotorious/react';
|
|
3
|
+
import { Annotorious, useAnnotoriousManifold } from '../src';
|
|
4
|
+
|
|
5
|
+
const ViewerTile = (props: { url: string }) => {
|
|
6
|
+
|
|
7
|
+
return (
|
|
8
|
+
<div className="viewer-tile">
|
|
9
|
+
<Annotorious source={props.url}>
|
|
10
|
+
<OpenSeadragonAnnotator>
|
|
11
|
+
<OpenSeadragonViewer
|
|
12
|
+
className="osd-container"
|
|
13
|
+
options={{
|
|
14
|
+
prefixUrl: 'https://cdn.jsdelivr.net/npm/openseadragon@3.1/build/openseadragon/images/',
|
|
15
|
+
tileSources: {
|
|
16
|
+
type: 'image',
|
|
17
|
+
url: props.url
|
|
18
|
+
},
|
|
19
|
+
gestureSettingsMouse: {
|
|
20
|
+
clickToZoom: false
|
|
21
|
+
},
|
|
22
|
+
showRotationControl: true,
|
|
23
|
+
crossOriginPolicy: 'Anonymous'
|
|
24
|
+
}} />
|
|
25
|
+
</OpenSeadragonAnnotator>
|
|
26
|
+
</Annotorious>
|
|
27
|
+
</div>
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const App = () => {
|
|
33
|
+
|
|
34
|
+
const manifold = useAnnotoriousManifold();
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
console.log('annotators', manifold.annotators);
|
|
38
|
+
}, [manifold.annotators]);
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<div className="container">
|
|
42
|
+
<ViewerTile url="33054-000002-0001.jpg" />
|
|
43
|
+
<ViewerTile url="33054-000002-0001.jpg" />
|
|
44
|
+
<ViewerTile url="33054-000002-0001.jpg" />
|
|
45
|
+
<ViewerTile url="33054-000002-0001.jpg" />
|
|
46
|
+
</div>
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
}
|
|
50
|
+
|
package/test/index.css
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
.container {
|
|
2
|
+
display: grid;
|
|
3
|
+
gap: 1.5vh;
|
|
4
|
+
grid-template-columns: 1fr 1fr;
|
|
5
|
+
height: 100%;
|
|
6
|
+
width: 100%;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.viewer-tile {
|
|
10
|
+
background-color: green;
|
|
11
|
+
height: 48vh;
|
|
12
|
+
position: relative;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.osd-container {
|
|
16
|
+
height: 100%;
|
|
17
|
+
width: 100%;
|
|
18
|
+
}
|
package/test/index.html
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Annotorious React Manifold</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="app"></div>
|
|
10
|
+
<script type="module" src="./index.tsx"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
package/test/index.tsx
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { createRoot } from 'react-dom/client';
|
|
3
|
+
import { AnnotoriousManifold } from '../src';
|
|
4
|
+
import { App } from './App';
|
|
5
|
+
|
|
6
|
+
import './index.css';
|
|
7
|
+
|
|
8
|
+
const root = createRoot(document.getElementById('app') as Element);
|
|
9
|
+
root.render(
|
|
10
|
+
<AnnotoriousManifold>
|
|
11
|
+
<App />
|
|
12
|
+
</AnnotoriousManifold>
|
|
13
|
+
);
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"allowJs": false,
|
|
4
|
+
"allowSyntheticDefaultImports": true,
|
|
5
|
+
"baseUrl": ".",
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"declarationDir": "types",
|
|
8
|
+
"declarationMap": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"isolatedModules": false,
|
|
12
|
+
"jsx": "react-jsx",
|
|
13
|
+
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
|
14
|
+
"module": "ESNext",
|
|
15
|
+
"moduleResolution": "node",
|
|
16
|
+
"noEmit": true,
|
|
17
|
+
"outDir": "dist",
|
|
18
|
+
"resolveJsonModule": true,
|
|
19
|
+
"skipLibCheck": true,
|
|
20
|
+
"sourceMap": true,
|
|
21
|
+
"target": "ESNext",
|
|
22
|
+
"useDefineForClassFields": true
|
|
23
|
+
},
|
|
24
|
+
"include": ["src"],
|
|
25
|
+
"references": [{ "path": "./tsconfig.node.json" }],
|
|
26
|
+
}
|
package/vite.config.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
import react from '@vitejs/plugin-react';
|
|
3
|
+
import tsConfigPaths from 'vite-tsconfig-paths';
|
|
4
|
+
import dts from 'vite-plugin-dts';
|
|
5
|
+
|
|
6
|
+
import * as packageJson from './package.json';
|
|
7
|
+
|
|
8
|
+
export default defineConfig({
|
|
9
|
+
plugins: [
|
|
10
|
+
react(),
|
|
11
|
+
tsConfigPaths(),
|
|
12
|
+
dts({
|
|
13
|
+
include: ['./src/'],
|
|
14
|
+
entryRoot: './src'
|
|
15
|
+
})
|
|
16
|
+
],
|
|
17
|
+
server: {
|
|
18
|
+
open: '/test/index.html'
|
|
19
|
+
},
|
|
20
|
+
build: {
|
|
21
|
+
lib: {
|
|
22
|
+
entry: './src/index.ts',
|
|
23
|
+
formats: ['es'],
|
|
24
|
+
fileName: (format) => `annotorious-react-manifold.${format}.js`
|
|
25
|
+
},
|
|
26
|
+
rollupOptions: {
|
|
27
|
+
external: [
|
|
28
|
+
...Object.keys(packageJson.peerDependencies)
|
|
29
|
+
],
|
|
30
|
+
output: {
|
|
31
|
+
preserveModules: true,
|
|
32
|
+
assetFileNames: 'annotorious-react-manifold.[ext]',
|
|
33
|
+
globals: {
|
|
34
|
+
react: 'React'
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
sourcemap: true
|
|
39
|
+
}
|
|
40
|
+
});
|