@triiiceratops/plugin-annotation-editor 1.0.0-rc.6 → 1.0.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/README.md +332 -0
- package/dist/AnnotationStore.svelte.d.ts +25 -26
- package/dist/adapters/types.d.ts +1 -1
- package/dist/catalog.d.ts +3 -4
- package/dist/contextKey.d.ts +3 -3
- package/dist/drawingLayer.d.ts +22 -0
- package/dist/drawingSession.svelte.d.ts +101 -0
- package/dist/editableShape.d.ts +69 -0
- package/dist/geometry.d.ts +310 -0
- package/dist/icons.d.ts +4 -3
- package/dist/identity.d.ts +10 -0
- package/dist/iife.js +1 -1273
- package/dist/index.d.ts +1 -1
- package/dist/index.js +15 -6022
- package/dist/loader.svelte.d.ts +1 -1
- package/dist/plugin.d.ts +9 -5
- package/dist/testing/index.d.ts +2 -2
- package/dist/testing/index.js +1 -158
- package/dist/tools.d.ts +16 -0
- package/dist/types.d.ts +12 -15
- package/dist/viewerMirror.svelte.d.ts +47 -7
- package/package.json +10 -17
- package/dist/AnnotationManager.svelte.d.ts +0 -260
- package/dist/styles.d.ts +0 -11
package/dist/loader.svelte.d.ts
CHANGED
|
@@ -6,6 +6,6 @@ import type { AnnotationStore } from './AnnotationStore.svelte';
|
|
|
6
6
|
* (the panel may never open), so it drives the shared store directly: point the
|
|
7
7
|
* store at the current canvas and load; the store injects into this viewer's
|
|
8
8
|
* per-viewer display state (F10, ADR 0007). When the editor panel is mounted,
|
|
9
|
-
* its
|
|
9
|
+
* its drawing layer shares this same store, so both paths converge on one cache.
|
|
10
10
|
*/
|
|
11
11
|
export declare function createLoader(store: AnnotationStore): (viewerState: ViewerState) => void;
|
package/dist/plugin.d.ts
CHANGED
|
@@ -3,11 +3,15 @@
|
|
|
3
3
|
*
|
|
4
4
|
* `definePlugin` returns the framework-neutral factory core activates through the
|
|
5
5
|
* structural seam (it carries its own `activate(host)`); core never imports this
|
|
6
|
-
* package or its Svelte runtime. The
|
|
7
|
-
* per-viewer display sync, undo/redo, body editors,
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* package or its Svelte runtime. The domain machinery — Store, Adapter seam,
|
|
7
|
+
* per-viewer display sync, undo/redo, body editors, the drawing layer — is driven
|
|
8
|
+
* from the neutral `view.mount(container, context)` contract (see
|
|
9
|
+
* `mount.svelte.ts`).
|
|
10
|
+
*
|
|
11
|
+
* `uiId` is load-bearing, not cosmetic: core decides whether an annotation shape
|
|
12
|
+
* is editable by finding a toolbar button whose plugin id is the literal
|
|
13
|
+
* `'annotation-editor'` (`AnnotationShapeOverlay.svelte`). Renaming it makes
|
|
14
|
+
* every shape non-editable, and no test in this package would catch it.
|
|
11
15
|
*/
|
|
12
16
|
import { type SdkPlugin } from '@triiiceratops/plugin-sdk';
|
|
13
17
|
import type { AnnotationEditorConfig } from './types';
|
package/dist/testing/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { AnnotationStorageAdapter } from '../types';
|
|
2
2
|
/**
|
|
3
3
|
* Adapter authoring kit — a reusable conformance suite so adapter authors can
|
|
4
|
-
* verify their implementation against the contract the plugin relies on (
|
|
5
|
-
*
|
|
4
|
+
* verify their implementation against the contract the plugin relies on (F28 /
|
|
5
|
+
* SPEC §2.6).
|
|
6
6
|
*
|
|
7
7
|
* An adapter is pure storage: the plugin owns display sync, caching, id
|
|
8
8
|
* bookkeeping, timestamp/attribution stamping, and error handling. This suite
|
package/dist/testing/index.js
CHANGED
|
@@ -1,158 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
function w(i) {
|
|
3
|
-
const u = { ...i };
|
|
4
|
-
return delete u.__fullBodyLoaded, delete u.__bodyPreview, u;
|
|
5
|
-
}
|
|
6
|
-
function b(i, u) {
|
|
7
|
-
return typeof i == "string" ? i : i && typeof i == "object" ? i.id : u;
|
|
8
|
-
}
|
|
9
|
-
function f(i, u, h) {
|
|
10
|
-
return {
|
|
11
|
-
"@context": "http://www.w3.org/ns/anno.jsonld",
|
|
12
|
-
id: i,
|
|
13
|
-
type: "Annotation",
|
|
14
|
-
motivation: "commenting",
|
|
15
|
-
body: h ?? [
|
|
16
|
-
{ type: "TextualBody", purpose: "commenting", value: "hello" }
|
|
17
|
-
],
|
|
18
|
-
target: {
|
|
19
|
-
type: "SpecificResource",
|
|
20
|
-
source: u,
|
|
21
|
-
selector: {
|
|
22
|
-
type: "FragmentSelector",
|
|
23
|
-
conformsTo: "http://www.w3.org/TR/media-frags/",
|
|
24
|
-
value: "xywh=10,20,30,40"
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
function C(i, u = {}) {
|
|
30
|
-
const { supportsIdReconciliation: h, supportsHydrate: g, label: x } = u;
|
|
31
|
-
_(x ?? "AnnotationStorageAdapter contract", () => {
|
|
32
|
-
let o, d, t, m = 0;
|
|
33
|
-
A(() => {
|
|
34
|
-
o = i(), m += 1, d = `contract-manifest-${m}`, t = `contract-canvas-${m}`;
|
|
35
|
-
});
|
|
36
|
-
async function p(a) {
|
|
37
|
-
const r = await o.create(
|
|
38
|
-
d,
|
|
39
|
-
t,
|
|
40
|
-
structuredClone(a)
|
|
41
|
-
), e = b(r, a.id), s = (await o.load(d, t)).find((l) => l.id === e) ?? null;
|
|
42
|
-
if (!s) return { id: e, resolved: null };
|
|
43
|
-
if (s.__fullBodyLoaded === !1) {
|
|
44
|
-
n(typeof o.hydrate).toBe("function");
|
|
45
|
-
const l = await o.hydrate(d, t, e);
|
|
46
|
-
return { id: e, resolved: l };
|
|
47
|
-
}
|
|
48
|
-
return { id: e, resolved: s };
|
|
49
|
-
}
|
|
50
|
-
c("load returns an empty array for a canvas with no annotations", async () => {
|
|
51
|
-
const a = await o.load(d, t);
|
|
52
|
-
n(Array.isArray(a)).toBe(!0), n(a).toHaveLength(0);
|
|
53
|
-
}), c("create then load round-trips the annotation verbatim", async () => {
|
|
54
|
-
const a = f("anno-1", t), { id: r, resolved: e } = await p(a);
|
|
55
|
-
n(e).not.toBeNull(), n(w(e)).toEqual({
|
|
56
|
-
...a,
|
|
57
|
-
id: r
|
|
58
|
-
});
|
|
59
|
-
}), c("create preserves structured / unknown body shapes verbatim", async () => {
|
|
60
|
-
const a = {
|
|
61
|
-
type: "Dataset",
|
|
62
|
-
purpose: "linking",
|
|
63
|
-
value: {
|
|
64
|
-
nested: { deep: [1, 2, 3], flag: !0 },
|
|
65
|
-
ref: "https://example.org/entity/42"
|
|
66
|
-
},
|
|
67
|
-
extra: null
|
|
68
|
-
}, r = f(
|
|
69
|
-
"anno-structured",
|
|
70
|
-
t,
|
|
71
|
-
a
|
|
72
|
-
), { resolved: e } = await p(r);
|
|
73
|
-
n(e).not.toBeNull(), n(e.body).toEqual(a);
|
|
74
|
-
}), c("update replaces a stored annotation body", async () => {
|
|
75
|
-
const a = f("anno-2", t), { id: r } = await p(a), e = {
|
|
76
|
-
...a,
|
|
77
|
-
id: r,
|
|
78
|
-
body: [
|
|
79
|
-
{
|
|
80
|
-
type: "TextualBody",
|
|
81
|
-
purpose: "commenting",
|
|
82
|
-
value: "edited"
|
|
83
|
-
}
|
|
84
|
-
]
|
|
85
|
-
};
|
|
86
|
-
await o.update(
|
|
87
|
-
d,
|
|
88
|
-
t,
|
|
89
|
-
structuredClone(e)
|
|
90
|
-
);
|
|
91
|
-
const s = (await o.load(d, t)).find((v) => v.id === r);
|
|
92
|
-
n(s).toBeDefined();
|
|
93
|
-
const l = s?.__fullBodyLoaded === !1 ? await o.hydrate(d, t, r) : s;
|
|
94
|
-
n(w(l).body).toEqual(e.body);
|
|
95
|
-
}), c("delete removes a stored annotation", async () => {
|
|
96
|
-
const a = f("anno-3", t), { id: r } = await p(a);
|
|
97
|
-
await o.delete(d, t, r);
|
|
98
|
-
const e = await o.load(d, t);
|
|
99
|
-
n(e.find((y) => y.id === r)).toBeUndefined();
|
|
100
|
-
}), c("isolates annotations by manifest and canvas", async () => {
|
|
101
|
-
const a = f("anno-iso", t), { id: r } = await p(a), e = `${t}-other`, y = `${d}-other`;
|
|
102
|
-
n(await o.load(d, e)).toHaveLength(0), n(await o.load(y, t)).toHaveLength(0);
|
|
103
|
-
const s = await o.load(d, t);
|
|
104
|
-
n(s.find((l) => l.id === r)).toBeDefined();
|
|
105
|
-
}), h && c("returns a server-assigned id honored by update and delete", async () => {
|
|
106
|
-
const a = f("local-temp-id", t), r = await o.create(
|
|
107
|
-
d,
|
|
108
|
-
t,
|
|
109
|
-
structuredClone(a)
|
|
110
|
-
);
|
|
111
|
-
n(r == null).toBe(!1);
|
|
112
|
-
const e = b(r, a.id);
|
|
113
|
-
n(typeof e).toBe("string");
|
|
114
|
-
const y = {
|
|
115
|
-
...a,
|
|
116
|
-
id: e,
|
|
117
|
-
body: [
|
|
118
|
-
{
|
|
119
|
-
type: "TextualBody",
|
|
120
|
-
purpose: "commenting",
|
|
121
|
-
value: "reconciled-edit"
|
|
122
|
-
}
|
|
123
|
-
]
|
|
124
|
-
};
|
|
125
|
-
await o.update(
|
|
126
|
-
d,
|
|
127
|
-
t,
|
|
128
|
-
structuredClone(y)
|
|
129
|
-
);
|
|
130
|
-
let s = await o.load(d, t);
|
|
131
|
-
const l = s.find((B) => B.id === e);
|
|
132
|
-
n(l).toBeDefined();
|
|
133
|
-
const v = l?.__fullBodyLoaded === !1 ? await o.hydrate(
|
|
134
|
-
d,
|
|
135
|
-
t,
|
|
136
|
-
e
|
|
137
|
-
) : l;
|
|
138
|
-
n(w(v).body).toEqual(y.body), await o.delete(d, t, e), s = await o.load(d, t), n(
|
|
139
|
-
s.find((B) => B.id === e)
|
|
140
|
-
).toBeUndefined();
|
|
141
|
-
}), g && (c("exposes a hydrate method", () => {
|
|
142
|
-
n(typeof o.hydrate).toBe("function");
|
|
143
|
-
}), c("hydrate returns the full annotation for a known id", async () => {
|
|
144
|
-
const a = f("anno-hydrate", t), { id: r } = await p(a), e = await o.hydrate(d, t, r);
|
|
145
|
-
n(e).not.toBeNull(), n(w(e).body).toEqual(a.body);
|
|
146
|
-
}), c("hydrate returns null for an unknown id", async () => {
|
|
147
|
-
const a = await o.hydrate(
|
|
148
|
-
d,
|
|
149
|
-
t,
|
|
150
|
-
"no-such-annotation"
|
|
151
|
-
);
|
|
152
|
-
n(a).toBeNull();
|
|
153
|
-
}));
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
export {
|
|
157
|
-
C as runAdapterContractTests
|
|
158
|
-
};
|
|
1
|
+
import{describe as t,beforeEach as e,it as a,expect as o}from"vitest";function n(t){const e={...t};return delete e.__fullBodyLoaded,delete e.__bodyPreview,e}function d(t,e){return"string"==typeof t?t:t&&"object"==typeof t?t.id:e}function i(t,e,a){return{"@context":"http://www.w3.org/ns/anno.jsonld",id:t,type:"Annotation",motivation:"commenting",body:a??[{type:"TextualBody",purpose:"commenting",value:"hello"}],target:{type:"SpecificResource",source:e,selector:{type:"FragmentSelector",conformsTo:"http://www.w3.org/TR/media-frags/",value:"xywh=10,20,30,40"}}}}function r(r,s={}){const{supportsIdReconciliation:l,supportsHydrate:c,label:u}=s;t(u??"AnnotationStorageAdapter contract",()=>{let t,s,u,y=0;async function p(e){const a=d(await t.create(s,u,structuredClone(e)),e.id),n=(await t.load(s,u)).find(t=>t.id===a)??null;if(!n)return{id:a,resolved:null};if(!1===n.__fullBodyLoaded){o(typeof t.hydrate).toBe("function");const e=await t.hydrate(s,u,a);return{id:a,resolved:e}}return{id:a,resolved:n}}e(()=>{t=r(),y+=1,s=`contract-manifest-${y}`,u=`contract-canvas-${y}`}),a("load returns an empty array for a canvas with no annotations",async()=>{const e=await t.load(s,u);o(Array.isArray(e)).toBe(!0),o(e).toHaveLength(0)}),a("create then load round-trips the annotation verbatim",async()=>{const t=i("anno-1",u),{id:e,resolved:a}=await p(t);o(a).not.toBeNull(),o(n(a)).toEqual({...t,id:e})}),a("create preserves structured / unknown body shapes verbatim",async()=>{const t={type:"Dataset",purpose:"linking",value:{nested:{deep:[1,2,3],flag:!0},ref:"https://example.org/entity/42"},extra:null},e=i("anno-structured",u,t),{resolved:a}=await p(e);o(a).not.toBeNull(),o(a.body).toEqual(t)}),a("update replaces a stored annotation body",async()=>{const e=i("anno-2",u),{id:a}=await p(e),d={...e,id:a,body:[{type:"TextualBody",purpose:"commenting",value:"edited"}]};await t.update(s,u,structuredClone(d));const r=(await t.load(s,u)).find(t=>t.id===a);o(r).toBeDefined();const l=!1===r?.__fullBodyLoaded?await t.hydrate(s,u,a):r;o(n(l).body).toEqual(d.body)}),a("delete removes a stored annotation",async()=>{const e=i("anno-3",u),{id:a}=await p(e);await t.delete(s,u,a);const n=await t.load(s,u);o(n.find(t=>t.id===a)).toBeUndefined()}),a("isolates annotations by manifest and canvas",async()=>{const e=i("anno-iso",u),{id:a}=await p(e),n=`${u}-other`,d=`${s}-other`;o(await t.load(s,n)).toHaveLength(0),o(await t.load(d,u)).toHaveLength(0);const r=await t.load(s,u);o(r.find(t=>t.id===a)).toBeDefined()}),l&&a("returns a server-assigned id honored by update and delete",async()=>{const e=i("local-temp-id",u),a=await t.create(s,u,structuredClone(e));o(null==a).toBe(!1);const r=d(a,e.id);o(typeof r).toBe("string");const l={...e,id:r,body:[{type:"TextualBody",purpose:"commenting",value:"reconciled-edit"}]};await t.update(s,u,structuredClone(l));let c=await t.load(s,u);const y=c.find(t=>t.id===r);o(y).toBeDefined();const p=!1===y?.__fullBodyLoaded?await t.hydrate(s,u,r):y;o(n(p).body).toEqual(l.body),await t.delete(s,u,r),c=await t.load(s,u),o(c.find(t=>t.id===r)).toBeUndefined()}),c&&(a("exposes a hydrate method",()=>{o(typeof t.hydrate).toBe("function")}),a("hydrate returns the full annotation for a known id",async()=>{const e=i("anno-hydrate",u),{id:a}=await p(e),d=await t.hydrate(s,u,a);o(d).not.toBeNull(),o(n(d).body).toEqual(e.body)}),a("hydrate returns null for an unknown id",async()=>{const e=await t.hydrate(s,u,"no-such-annotation");o(e).toBeNull()}))})}export{r as runAdapterContractTests};
|
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { DrawingTool } from './types';
|
|
2
|
+
/** Every tool the plugin knows how to draw, in default button order. */
|
|
3
|
+
export declare const ALL_TOOLS: DrawingTool[];
|
|
4
|
+
/**
|
|
5
|
+
* Resolve the effective tool set and default tool from config so the panel and
|
|
6
|
+
* the drawing layer share one source of truth (F8). An empty/absent `tools` list
|
|
7
|
+
* means "all tools"; `defaultTool` is honored only when it's within `tools`,
|
|
8
|
+
* otherwise the first available tool wins.
|
|
9
|
+
*/
|
|
10
|
+
export declare function resolveTools(config: {
|
|
11
|
+
tools?: DrawingTool[];
|
|
12
|
+
defaultTool?: DrawingTool;
|
|
13
|
+
}): {
|
|
14
|
+
tools: DrawingTool[];
|
|
15
|
+
defaultTool: DrawingTool;
|
|
16
|
+
};
|
package/dist/types.d.ts
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
|
-
import type { User, DrawingStyle } from '@annotorious/openseadragon';
|
|
2
1
|
import type { Component } from 'svelte';
|
|
3
2
|
import type { PluginUiTarget } from '@triiiceratops/plugin-sdk';
|
|
4
|
-
import type { PointStyle } from 'triiiceratops/image-export';
|
|
5
3
|
import type { W3CAnnotation, AdapterLoadResult } from './adapters/types';
|
|
6
|
-
|
|
4
|
+
/**
|
|
5
|
+
* The person an annotation is attributed to. Only `id` and `name` are ever
|
|
6
|
+
* read — they are what creator stamping writes onto a new annotation — so the
|
|
7
|
+
* shape is declared here rather than borrowed from a drawing library.
|
|
8
|
+
*/
|
|
9
|
+
export interface AnnotationEditorUser {
|
|
10
|
+
id: string;
|
|
11
|
+
name?: string;
|
|
12
|
+
}
|
|
7
13
|
export interface AnnotationEditorRuntimeContext<HostContext = unknown, TBody = W3CAnnotationBody> {
|
|
8
14
|
manifestId: string | null;
|
|
9
15
|
canvasId: string | null;
|
|
10
16
|
isEditing: boolean;
|
|
11
17
|
selectedAnnotation: W3CAnnotation<TBody> | null;
|
|
12
|
-
user?:
|
|
18
|
+
user?: AnnotationEditorUser;
|
|
13
19
|
hostContext: HostContext | null;
|
|
14
20
|
}
|
|
15
21
|
export interface AnnotationEditorExtension<HostContext = unknown, TBody = W3CAnnotationBody> {
|
|
@@ -115,16 +121,7 @@ export interface AnnotationEditorConfig<TBody = W3CAnnotationBody, THostContext
|
|
|
115
121
|
/** Storage adapter for persistence */
|
|
116
122
|
adapter?: AnnotationStorageAdapter<TBody>;
|
|
117
123
|
/** Current user for attribution */
|
|
118
|
-
user?:
|
|
119
|
-
/** Drawing style for annotations while editing */
|
|
120
|
-
drawingStyle?: DrawingStyle;
|
|
121
|
-
/**
|
|
122
|
-
* Marker styling for point annotations (`PointSelector`). Consumed by both
|
|
123
|
-
* the read-only overlay and the editor so a point looks the same selected or
|
|
124
|
-
* not; `radius` is in screen pixels. Defaults to a red marker of radius 5
|
|
125
|
-
* (spec §3.4).
|
|
126
|
-
*/
|
|
127
|
-
pointStyle?: PointStyle;
|
|
124
|
+
user?: AnnotationEditorUser;
|
|
128
125
|
/** Available drawing tools */
|
|
129
126
|
tools?: DrawingTool[];
|
|
130
127
|
/** Default drawing tool */
|
|
@@ -157,7 +154,7 @@ export interface AnnotationEditorConfig<TBody = W3CAnnotationBody, THostContext
|
|
|
157
154
|
*/
|
|
158
155
|
onPersistenceError?: (error: AnnotationPersistenceError) => void;
|
|
159
156
|
}
|
|
160
|
-
export type DrawingTool = 'rectangle' | 'polygon' | 'point';
|
|
157
|
+
export type DrawingTool = 'rectangle' | 'ellipse' | 'polygon' | 'point' | 'wholeCanvas';
|
|
161
158
|
/** W3C Annotation Body */
|
|
162
159
|
export interface W3CAnnotationBody {
|
|
163
160
|
type?: string;
|
|
@@ -5,19 +5,44 @@
|
|
|
5
5
|
* OWN Svelte runtime) reads `viewerState.canvasId` inside an `$effect`, no
|
|
6
6
|
* dependency is registered because the two reactivity graphs don't cross. The
|
|
7
7
|
* plugin therefore mirrors the handful of fields its UI reacts to
|
|
8
|
-
* (`manifestId`, `canvasId`, `
|
|
8
|
+
* (`manifestId`, `canvasId`, `annotatableCanvasIds`, `surfaceOpen`) into
|
|
9
|
+
* plugin-runtime `$state`, kept in
|
|
9
10
|
* sync through the framework-neutral `ViewerState.subscribe` fan-out. Every other
|
|
10
11
|
* member/method (queries, display sync, the annotation-edit bus, the style root)
|
|
11
12
|
* delegates straight to the real state, so a mirror is a drop-in `ViewerState`
|
|
12
|
-
* for the controller, loader,
|
|
13
|
+
* for the controller, loader, drawing layer, and store.
|
|
13
14
|
*/
|
|
15
|
+
import type { PluginSurface } from '@triiiceratops/plugin-sdk';
|
|
14
16
|
import type { ViewerState } from 'triiiceratops';
|
|
17
|
+
/**
|
|
18
|
+
* The mirror as the plugin's UI consumes it: core's `ViewerState`, plus the
|
|
19
|
+
* mirrored fields core has no `ViewerState` member for.
|
|
20
|
+
*/
|
|
21
|
+
export type MirroredViewerState = ViewerState & {
|
|
22
|
+
readonly surfaceOpen: boolean;
|
|
23
|
+
};
|
|
15
24
|
export declare class ViewerStateMirror {
|
|
16
25
|
#private;
|
|
17
26
|
manifestId: string | null;
|
|
18
27
|
canvasId: string | null;
|
|
19
|
-
|
|
20
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Raw rather than deeply reactive: core replaces the array wholesale, and a
|
|
30
|
+
* `$state` proxy would never compare equal to the source's own reference,
|
|
31
|
+
* so the gate below could not tell an unchanged list from a new one. Core
|
|
32
|
+
* keeps that reference stable while the ids are unchanged.
|
|
33
|
+
*/
|
|
34
|
+
annotatableCanvasIds: string[];
|
|
35
|
+
/**
|
|
36
|
+
* Whether this plugin's own panel/flyout is open — the signal core names as
|
|
37
|
+
* the way a plugin observes open/close, since it mounts the plugin's
|
|
38
|
+
* content once per ACTIVATION and only re-parents it in and out of the
|
|
39
|
+
* surface, so a close destroys no component. It is not a `ViewerState`
|
|
40
|
+
* member: it reads off `PluginContext.surface`, which is a live projection
|
|
41
|
+
* over the viewer's plugin UI state, and every mutator of that state
|
|
42
|
+
* notifies through the same fan-out as the fields above.
|
|
43
|
+
*/
|
|
44
|
+
surfaceOpen: boolean;
|
|
45
|
+
constructor(real: ViewerState, surface: PluginSurface);
|
|
21
46
|
/** The per-viewer annotation-edit bus (mutated in place by the controller). */
|
|
22
47
|
get annotationEditBus(): ViewerState['annotationEditBus'];
|
|
23
48
|
getCanvases(manifestId: string, sequenceIndex?: number): unknown[];
|
|
@@ -25,11 +50,26 @@ export declare class ViewerStateMirror {
|
|
|
25
50
|
setUserAnnotations(manifestId: string, canvasId: string, annotations: unknown[]): void;
|
|
26
51
|
clearUserAnnotations(manifestId: string, canvasId: string): void;
|
|
27
52
|
getStyleRoot(): Document | ShadowRoot | null;
|
|
53
|
+
/**
|
|
54
|
+
* The owning viewer's config. Read for `pointStyle`, which core's read-only
|
|
55
|
+
* overlay resolves its own point marker from — the editor has to answer
|
|
56
|
+
* from the same object or a point changes size the moment it is selected.
|
|
57
|
+
*/
|
|
58
|
+
get config(): ViewerState['config'];
|
|
59
|
+
/**
|
|
60
|
+
* The canvas-space box the viewport shows. The keyboard's place-then-shape
|
|
61
|
+
* creation reads it to put a default shape at the centre of the view.
|
|
62
|
+
*/
|
|
63
|
+
get viewportBounds(): ViewerState['viewportBounds'];
|
|
64
|
+
canvasSize(canvasId?: string): ReturnType<ViewerState['canvasSize']>;
|
|
65
|
+
canvasToScreen(point: Parameters<ViewerState['canvasToScreen']>[0], canvasId?: string): ReturnType<ViewerState['canvasToScreen']>;
|
|
66
|
+
screenToCanvas(point: Parameters<ViewerState['screenToCanvas']>[0], canvasId?: string): ReturnType<ViewerState['screenToCanvas']>;
|
|
67
|
+
subscribeFrame(listener: () => void): () => void;
|
|
28
68
|
/** Drop the bridge's `ViewerState.subscribe` registration. */
|
|
29
69
|
destroy(): void;
|
|
30
70
|
}
|
|
31
|
-
/** Build a mirror and expose it
|
|
32
|
-
export declare function createViewerStateMirror(real: ViewerState): {
|
|
33
|
-
mirror:
|
|
71
|
+
/** Build a mirror and expose it as a `ViewerState` for the plugin UI. */
|
|
72
|
+
export declare function createViewerStateMirror(real: ViewerState, surface: PluginSurface): {
|
|
73
|
+
mirror: MirroredViewerState;
|
|
34
74
|
destroy: () => void;
|
|
35
75
|
};
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@triiiceratops/plugin-annotation-editor",
|
|
3
|
-
"version": "1.0.0
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "Annotation
|
|
5
|
+
"description": "Annotation editing for the Triiiceratops IIIF viewer: a first-party drawing layer with rectangle, ellipse, polygon, point and whole-canvas tools, full keyboard parity, and a pluggable storage adapter.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "David Flood",
|
|
8
8
|
"repository": {
|
|
@@ -10,12 +10,11 @@
|
|
|
10
10
|
"url": "git+https://github.com/d-flood/triiiceratops.git",
|
|
11
11
|
"directory": "packages/plugin-annotation-editor"
|
|
12
12
|
},
|
|
13
|
-
"homepage": "https://
|
|
13
|
+
"homepage": "https://triiiceratops.org/",
|
|
14
14
|
"publishConfig": {
|
|
15
15
|
"access": "public",
|
|
16
16
|
"provenance": true
|
|
17
17
|
},
|
|
18
|
-
"private": false,
|
|
19
18
|
"engines": {
|
|
20
19
|
"node": ">=22"
|
|
21
20
|
},
|
|
@@ -41,7 +40,7 @@
|
|
|
41
40
|
"./iife": "./dist/iife.js"
|
|
42
41
|
},
|
|
43
42
|
"scripts": {
|
|
44
|
-
"build": "pnpm build:esm && pnpm build:iife && pnpm build:types",
|
|
43
|
+
"build": "pnpm clean && pnpm build:esm && pnpm build:iife && pnpm build:types",
|
|
45
44
|
"build:esm": "BUILD_FORMAT=es vite build",
|
|
46
45
|
"build:iife": "BUILD_FORMAT=iife vite build",
|
|
47
46
|
"build:types": "tsc -p tsconfig.build.json",
|
|
@@ -53,24 +52,18 @@
|
|
|
53
52
|
"lint:fix": "eslint . --fix --max-warnings 0"
|
|
54
53
|
},
|
|
55
54
|
"peerDependencies": {
|
|
56
|
-
"triiiceratops": "^1.0.0
|
|
57
|
-
"@triiiceratops/plugin-sdk": "^1.0.0
|
|
58
|
-
},
|
|
59
|
-
"dependencies": {
|
|
60
|
-
"@annotorious/annotorious": "^3.7.19",
|
|
61
|
-
"@annotorious/openseadragon": "^3.7.19",
|
|
62
|
-
"openseadragon": "^5.0.1"
|
|
55
|
+
"triiiceratops": "^1.0.0",
|
|
56
|
+
"@triiiceratops/plugin-sdk": "^1.0.0"
|
|
63
57
|
},
|
|
64
58
|
"devDependencies": {
|
|
65
|
-
"@sveltejs/vite-plugin-svelte": "^6.2.
|
|
66
|
-
"@triiiceratops/plugin-sdk": "1.0.0
|
|
59
|
+
"@sveltejs/vite-plugin-svelte": "^6.2.4",
|
|
60
|
+
"@triiiceratops/plugin-sdk": "1.0.0",
|
|
67
61
|
"@triiiceratops/ui": "0.0.0",
|
|
68
62
|
"@types/node": "^24.10.1",
|
|
69
|
-
"@types/openseadragon": "^5.0.1",
|
|
70
63
|
"@vitest/coverage-v8": "4.0.15",
|
|
71
|
-
"svelte": "5.
|
|
64
|
+
"svelte": "5.56.10",
|
|
72
65
|
"svelte-check": "^4.3.4",
|
|
73
|
-
"triiiceratops": "1.0.0
|
|
66
|
+
"triiiceratops": "1.0.0",
|
|
74
67
|
"typescript": "~5.9.3",
|
|
75
68
|
"vite": "^6.0.0",
|
|
76
69
|
"vitest": "^4.0.15"
|