@ghentcdh/annotation-vue 0.0.1-alpha.10
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 +263 -0
- package/index.d.ts +6 -0
- package/index.js +443 -0
- package/index.umd.cjs +1 -0
- package/lib/composables/useAnnotationDefinitions.d.ts +39 -0
- package/lib/loader/annotation-definition.loader.d.ts +10 -0
- package/lib/router/annotation-namespace.plugin.d.ts +23 -0
- package/lib/router/annotation-namespace.routes.d.ts +17 -0
- package/lib/service/annotation-definition.service.d.ts +12 -0
- package/lib/types/annotation-vue.types.d.ts +20 -0
- package/package.json +24 -0
package/README.md
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# @ghentcdh/annotation-vue
|
|
2
|
+
|
|
3
|
+
Vue 3 package for working with annotation definitions client-side — no NestJS backend required. Loads JSON annotation
|
|
4
|
+
configs, builds definitions via `@ghentcdh/annotation-core`, and exposes them as reactive Vue composables using
|
|
5
|
+
provide/inject.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
Peer dependencies:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
vue >= 3.5
|
|
13
|
+
@ghentcdh/annotation-core
|
|
14
|
+
@ghentcdh/w3c-utils
|
|
15
|
+
vue-router >= 4 (optional — only needed for router plugin)
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
### Provide/inject pattern
|
|
21
|
+
|
|
22
|
+
Call `provideAnnotationDefinitions` once at the root component. All descendants use `useAnnotationDefinitions()` to
|
|
23
|
+
inject.
|
|
24
|
+
|
|
25
|
+
**Root component (provide):**
|
|
26
|
+
|
|
27
|
+
```vue
|
|
28
|
+
|
|
29
|
+
<template>
|
|
30
|
+
<slot />
|
|
31
|
+
</template>
|
|
32
|
+
|
|
33
|
+
<script setup lang="ts">
|
|
34
|
+
import { provideAnnotationDefinitions } from '@ghentcdh/annotation-vue';
|
|
35
|
+
|
|
36
|
+
// import.meta.glob must be a string literal — call it here, pass result in
|
|
37
|
+
const resourceFolder = import.meta.glob('./configs/*.json', { eager: true });
|
|
38
|
+
|
|
39
|
+
const { definitions } = provideAnnotationDefinitions({
|
|
40
|
+
config: {
|
|
41
|
+
baseUrl: 'http://localhost:3000/',
|
|
42
|
+
app: 'myapp',
|
|
43
|
+
prefix: 'myapp',
|
|
44
|
+
isDev: true,
|
|
45
|
+
cacheTTLms: 0,
|
|
46
|
+
},
|
|
47
|
+
resourceFolder, // auto-loads definitions on creation
|
|
48
|
+
});
|
|
49
|
+
</script>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Child component (inject):**
|
|
53
|
+
|
|
54
|
+
```vue
|
|
55
|
+
|
|
56
|
+
<template>
|
|
57
|
+
<div v-for="def in definitions" :key="def.id">
|
|
58
|
+
{{ def.label }}
|
|
59
|
+
</div>
|
|
60
|
+
</template>
|
|
61
|
+
|
|
62
|
+
<script setup lang="ts">
|
|
63
|
+
import { useAnnotationDefinitions } from '@ghentcdh/annotation-vue';
|
|
64
|
+
|
|
65
|
+
// No options needed — state is injected from ancestor
|
|
66
|
+
const { definitions, getDefinitionById } = useAnnotationDefinitions();
|
|
67
|
+
</script>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### provideAnnotationDefinitions options
|
|
71
|
+
|
|
72
|
+
| Option | Type | Required | Description |
|
|
73
|
+
|------------------------|----------------------------|----------|----------------------------------------------------|
|
|
74
|
+
| `config` | `AnnotationDefConfig` | yes | Base URL, app name, prefix, cache settings |
|
|
75
|
+
| `resourceFolder` | `GlobModules` | no | `import.meta.glob` result — auto-loads on creation |
|
|
76
|
+
| `createHighlightStyle` | `(def) => AnnotationStyle` | no | Custom style builder |
|
|
77
|
+
| `factory` | `ContextBuilderFactory` | no | Custom context builder factory |
|
|
78
|
+
|
|
79
|
+
### Returned state (both provide and inject)
|
|
80
|
+
|
|
81
|
+
| Property | Type | Description |
|
|
82
|
+
|-----------------------|--------------------------------------------------------|-----------------------------------------|
|
|
83
|
+
| `definitions` | `ComputedRef<VueAnnotationDefinition[]>` | All definitions, reactively transformed |
|
|
84
|
+
| `definitionsMap` | `ComputedRef<Record<string, VueAnnotationDefinition>>` | Definitions keyed by ID |
|
|
85
|
+
| `getDefinitionById` | `(id: string) => VueAnnotationDefinition \| undefined` | Lookup by ID |
|
|
86
|
+
| `loadFromGlob` | `(modules: GlobModules) => void` | Load from `import.meta.glob` result |
|
|
87
|
+
| `loadFromConfigs` | `(configs: AnnotationJsonConfig[]) => void` | Load from config array |
|
|
88
|
+
| `loadFromDefinitions` | `(defs: CoreAnnotationDefinition[]) => void` | Load pre-built definitions |
|
|
89
|
+
| `service` | `AnnotationDefinitionService` | Underlying synchronous service |
|
|
90
|
+
|
|
91
|
+
### Loading definitions manually
|
|
92
|
+
|
|
93
|
+
If you don't pass `resourceFolder`, load later:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
const state = provideAnnotationDefinitions({ config });
|
|
97
|
+
|
|
98
|
+
// From glob
|
|
99
|
+
const modules = import.meta.glob('./configs/*.json', { eager: true });
|
|
100
|
+
state.loadFromGlob(modules);
|
|
101
|
+
|
|
102
|
+
// From config array
|
|
103
|
+
state.loadFromConfigs([
|
|
104
|
+
{ id: 'comment', name: 'Comment', color: '#ff0000' },
|
|
105
|
+
{ id: 'entity', name: 'Entity', color: '#00ff00', allowedChildren: ['comment'] },
|
|
106
|
+
]);
|
|
107
|
+
|
|
108
|
+
// From pre-built core definitions
|
|
109
|
+
state.loadFromDefinitions(coreDefinitions);
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### VueAnnotationDefinition
|
|
113
|
+
|
|
114
|
+
Enriched version of core `AnnotationDefinition`, with:
|
|
115
|
+
|
|
116
|
+
- `label` — mapped from core `name`
|
|
117
|
+
- `style: AnnotationStyle` — built from `id`, `name`, `color`, `target`
|
|
118
|
+
- `schema: FormValidationDef` — wraps `ui_schema`, `json_schema`, `metadata_schema`
|
|
119
|
+
- `allowedChildren: KeyLabel[]` — string IDs resolved to `{ key, label, icon? }` objects
|
|
120
|
+
- `allowedLinks: KeyLabel[]` — same resolution
|
|
121
|
+
- `_core` — raw reference to the core `AnnotationDefinition`
|
|
122
|
+
|
|
123
|
+
### Custom highlight styles
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
provideAnnotationDefinitions({
|
|
127
|
+
config,
|
|
128
|
+
resourceFolder,
|
|
129
|
+
createHighlightStyle: (def) => ({
|
|
130
|
+
id: def.id,
|
|
131
|
+
name: def.name,
|
|
132
|
+
color: def.color,
|
|
133
|
+
target: def.target ?? 'highlight',
|
|
134
|
+
}),
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### AnnotationDefinitionService
|
|
139
|
+
|
|
140
|
+
Synchronous, plain TS class (no NestJS dependency). Mirrors API service interface:
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
import { AnnotationDefinitionService } from '@ghentcdh/annotation-vue';
|
|
144
|
+
|
|
145
|
+
const service = new AnnotationDefinitionService(definitions);
|
|
146
|
+
|
|
147
|
+
service.findAll(); // AnnotationDefinition[]
|
|
148
|
+
service.findById('comment'); // AnnotationDefinition | undefined
|
|
149
|
+
service.findAllGrouped(); // Record<string, AnnotationDefinition>
|
|
150
|
+
service.getAllContextBuilders(); // unknown[]
|
|
151
|
+
service.getContextBuilder(id); // unknown | undefined
|
|
152
|
+
service.setDefinitions(defs); // replace all definitions
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Router plugin (optional, requires `vue-router`)
|
|
156
|
+
|
|
157
|
+
Registers Vue Router routes that mirror the NestJS `AnnotationNamespaceController` endpoints. Useful for serving
|
|
158
|
+
annotation definitions client-side without a backend.
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
import { createRouter, createWebHistory } from 'vue-router';
|
|
162
|
+
import {
|
|
163
|
+
AnnotationNamespacePlugin,
|
|
164
|
+
AnnotationDefinitionService,
|
|
165
|
+
} from '@ghentcdh/annotation-vue';
|
|
166
|
+
|
|
167
|
+
const service = new AnnotationDefinitionService(definitions);
|
|
168
|
+
const router = createRouter({ history: createWebHistory(), routes: [] });
|
|
169
|
+
|
|
170
|
+
// Option A: Vue plugin
|
|
171
|
+
app.use(AnnotationNamespacePlugin, {
|
|
172
|
+
router,
|
|
173
|
+
service,
|
|
174
|
+
basePath: '/ns', // default: '/ns'
|
|
175
|
+
config, // optional AnnotationDefConfig for AnnotationStyle context
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// Option B: Direct install
|
|
179
|
+
import { installAnnotationNamespaceRoutes } from '@ghentcdh/annotation-vue';
|
|
180
|
+
|
|
181
|
+
installAnnotationNamespaceRoutes(router, service, { basePath: '/ns' });
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Registered routes:
|
|
185
|
+
|
|
186
|
+
| Path | Name | Description |
|
|
187
|
+
|-------------------------|-----------------------------|-------------------------------|
|
|
188
|
+
| `/ns` | `annotation-ns-all` | All definitions |
|
|
189
|
+
| `/ns/anno.jsonld` | `annotation-ns-all-jsonld` | All JSON-LD contexts |
|
|
190
|
+
| `/ns/:id.jsonld` | `annotation-ns-jsonld` | Single JSON-LD context |
|
|
191
|
+
| `/ns/:type/anno.jsonld` | `annotation-ns-type-jsonld` | JSON-LD + forms for type |
|
|
192
|
+
| `/ns/:id/schemas` | `annotation-ns-schemas` | Schemas subset for definition |
|
|
193
|
+
| `/ns/:id` | `annotation-ns-by-id` | Single definition |
|
|
194
|
+
|
|
195
|
+
### Path helpers
|
|
196
|
+
|
|
197
|
+
Generate URL paths without installing routes:
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
import { createAnnotationNamespacePaths } from '@ghentcdh/annotation-vue';
|
|
201
|
+
|
|
202
|
+
const paths = createAnnotationNamespacePaths('/ns');
|
|
203
|
+
paths.all; // '/ns'
|
|
204
|
+
paths.allJsonLd; // '/ns/anno.jsonld'
|
|
205
|
+
paths.byId('comment'); // '/ns/comment'
|
|
206
|
+
paths.jsonLdById('comment'); // '/ns/comment.jsonld'
|
|
207
|
+
paths.schemasById('comment'); // '/ns/comment/schemas'
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Resolve defintions from third party server
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
│
|
|
214
|
+
│ // Simple — single app.use() │
|
|
215
|
+
│ app.use(AnnotationPlugin, { │
|
|
216
|
+
│ config: annotationDefConfig, │
|
|
217
|
+
│ router, │
|
|
218
|
+
│ definitionsUrl: '/api/ns', │
|
|
219
|
+
│
|
|
220
|
+
})
|
|
221
|
+
; │
|
|
222
|
+
│ │
|
|
223
|
+
│ // Custom fetch (auth headers, axios, etc.) │
|
|
224
|
+
│ app.use(AnnotationPlugin, { │
|
|
225
|
+
│ config: annotationDefConfig, │
|
|
226
|
+
│ router, │
|
|
227
|
+
│ definitionsUrl: '/api/ns', │
|
|
228
|
+
│ fetchFn: async (url) => { │
|
|
229
|
+
│ const { data } = await axios.get(url, { headers: { Authorization: `Bearer ${token}` } }); │
|
|
230
|
+
│ return data; │
|
|
231
|
+
│
|
|
232
|
+
}, │
|
|
233
|
+
│
|
|
234
|
+
})
|
|
235
|
+
;
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Package structure
|
|
239
|
+
|
|
240
|
+
```
|
|
241
|
+
src/
|
|
242
|
+
index.ts # Barrel export
|
|
243
|
+
lib/
|
|
244
|
+
types/
|
|
245
|
+
annotation-vue.types.ts # KeyLabel, FormValidationDef, VueAnnotationDefinition
|
|
246
|
+
service/
|
|
247
|
+
annotation-definition.service.ts # Synchronous definition service
|
|
248
|
+
loader/
|
|
249
|
+
annotation-definition.loader.ts # import.meta.glob + config array loaders
|
|
250
|
+
composables/
|
|
251
|
+
useAnnotationDefinitions.ts # Provide/inject composable
|
|
252
|
+
router/
|
|
253
|
+
annotation-namespace.routes.ts # Route records + path helpers
|
|
254
|
+
annotation-namespace.plugin.ts # Vue Router plugin
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Build & test
|
|
258
|
+
|
|
259
|
+
```sh
|
|
260
|
+
pnpm nx build annotation-vue
|
|
261
|
+
pnpm nx test annotation-vue
|
|
262
|
+
pnpm nx lint annotation-vue
|
|
263
|
+
```
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export * from './lib/types/annotation-vue.types';
|
|
2
|
+
export { AnnotationDefinitionService } from './lib/service/annotation-definition.service';
|
|
3
|
+
export { type DefinitionsFetchFn, type GlobModules, loadAnnotationDefinitionsFromGlob, loadAnnotationDefinitionsFromConfigs, loadAnnotationDefinitionsFromUrl, } from './lib/loader/annotation-definition.loader';
|
|
4
|
+
export { type AnnotationDefinitionsState, type ProvideAnnotationDefinitionsOptions, provideAnnotationDefinitions, useAnnotationDefinitions, createAnnotationDefinitionsState, } from './lib/composables/useAnnotationDefinitions';
|
|
5
|
+
export { type AnnotationNamespaceRoutePaths, createAnnotationNamespacePaths, createAnnotationNamespaceRoutes, NAMESPACE_ROUTE_META, } from './lib/router/annotation-namespace.routes';
|
|
6
|
+
export { type AnnotationNamespacePluginOptions, type AnnotationPluginOptions, installAnnotationNamespaceRoutes, AnnotationNamespacePlugin, AnnotationPlugin, } from './lib/router/annotation-namespace.plugin';
|
package/index.js
ADDED
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
import { z as e } from "zod";
|
|
2
|
+
import { contextBuilder as t } from "@ghentcdh/w3c-utils";
|
|
3
|
+
import { createHighlightStyle as n } from "@ghentcdh/annotated-text";
|
|
4
|
+
import { ControlBuilder as r, LayoutBuilder as i } from "@ghentcdh/crouton-forms-vue";
|
|
5
|
+
import { computed as a, defineComponent as o, h as s, inject as c, markRaw as l, provide as u, reactive as d, ref as f } from "vue";
|
|
6
|
+
//#region packages/annotation-vue/src/lib/service/annotation-definition.service.ts
|
|
7
|
+
var p = class {
|
|
8
|
+
definitions = [];
|
|
9
|
+
groupedDefinitions = {};
|
|
10
|
+
constructor(e = []) {
|
|
11
|
+
e.length && this.setDefinitions(e);
|
|
12
|
+
}
|
|
13
|
+
setDefinitions(e) {
|
|
14
|
+
this.definitions = e, this.groupedDefinitions = e.reduce((e, t) => (e[t.id] = t, e), {});
|
|
15
|
+
}
|
|
16
|
+
findAll() {
|
|
17
|
+
return this.definitions;
|
|
18
|
+
}
|
|
19
|
+
findById(e) {
|
|
20
|
+
return this.groupedDefinitions[e];
|
|
21
|
+
}
|
|
22
|
+
findAllGrouped() {
|
|
23
|
+
return this.groupedDefinitions;
|
|
24
|
+
}
|
|
25
|
+
getAllContextBuilders() {
|
|
26
|
+
return this.definitions.map((e) => e.context);
|
|
27
|
+
}
|
|
28
|
+
getContextBuilder(e) {
|
|
29
|
+
return this.findById(e)?.context;
|
|
30
|
+
}
|
|
31
|
+
}, m = ["text"], h = e.object({
|
|
32
|
+
text: e.string(),
|
|
33
|
+
textDirection: e.enum(["ltr", "rtl"]).default("ltr"),
|
|
34
|
+
processingLanguage: e.string().default("en"),
|
|
35
|
+
label: e.string().optional(),
|
|
36
|
+
offset: e.number().optional().default(0)
|
|
37
|
+
});
|
|
38
|
+
e.object({
|
|
39
|
+
id: e.string(),
|
|
40
|
+
uri: e.string(),
|
|
41
|
+
type: e.enum(m),
|
|
42
|
+
content: h
|
|
43
|
+
});
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region packages/annotation-core/src/lib/types/annotation.contex.ts
|
|
46
|
+
var g = "AnnotationMetadata", _ = e.custom();
|
|
47
|
+
e.object({
|
|
48
|
+
id: e.string(),
|
|
49
|
+
name: e.string(),
|
|
50
|
+
columns: e.array(_),
|
|
51
|
+
json_schema: e.any().optional(),
|
|
52
|
+
json_ld: e.any().optional(),
|
|
53
|
+
ui_schema: e.any().optional(),
|
|
54
|
+
metadata_schema: e.any().optional(),
|
|
55
|
+
color: e.string(),
|
|
56
|
+
type: e.string().optional(),
|
|
57
|
+
icon: e.string().optional(),
|
|
58
|
+
isRoot: e.boolean().default(!0),
|
|
59
|
+
allowedChildren: e.array(e.string()).default([]),
|
|
60
|
+
allowedLinks: e.array(e.string()).default([]),
|
|
61
|
+
context: e.custom(),
|
|
62
|
+
target: e.enum([
|
|
63
|
+
"gutter",
|
|
64
|
+
"underline",
|
|
65
|
+
"highlight"
|
|
66
|
+
]).default("highlight")
|
|
67
|
+
});
|
|
68
|
+
//#endregion
|
|
69
|
+
//#region packages/annotation-core/src/lib/utils/annotation.context-builder.ts
|
|
70
|
+
var v = {
|
|
71
|
+
baseUrl: "http://localhost:3000/",
|
|
72
|
+
app: "ghentcdh",
|
|
73
|
+
prefix: "ghentcdh",
|
|
74
|
+
isDev: !1,
|
|
75
|
+
cacheTTLms: 1200 * 1e3
|
|
76
|
+
}, y = (e = {}) => {
|
|
77
|
+
let t = e.baseUrl ?? v.baseUrl, n = t.endsWith("/") ? t : `${t}/`, r = e.isDev ?? !1, i = r ? 0 : 1200 * 1e3;
|
|
78
|
+
return {
|
|
79
|
+
baseUrl: n,
|
|
80
|
+
contextUrl: `${n}ns/`,
|
|
81
|
+
app: e.app ?? v.app,
|
|
82
|
+
prefix: e.prefix ?? v.prefix,
|
|
83
|
+
isDev: r,
|
|
84
|
+
cacheTTLms: i
|
|
85
|
+
};
|
|
86
|
+
}, b = (e, n) => {
|
|
87
|
+
let { prefix: r, baseUrl: i, contextUrl: a } = y(n), o = g;
|
|
88
|
+
return t(r, i).setType(r, o).addPrefix(e, `${r}:${e}`).setContextUri(`${a}${e}.jsonld`);
|
|
89
|
+
}, x = e.object({
|
|
90
|
+
id: e.string(),
|
|
91
|
+
name: e.string(),
|
|
92
|
+
target: e.enum([
|
|
93
|
+
"gutter",
|
|
94
|
+
"underline",
|
|
95
|
+
"highlight"
|
|
96
|
+
]).optional().default("underline"),
|
|
97
|
+
color: e.string().optional()
|
|
98
|
+
}), S = "AnnotationStyle", C = (e) => {
|
|
99
|
+
let { prefix: n, baseUrl: r, contextUrl: i } = y(e);
|
|
100
|
+
return t(n, r).setType(n, S).setContextUri(`${i}${S}.jsonld`).parseZodSchema(x);
|
|
101
|
+
}, w = (e) => {
|
|
102
|
+
let t = r.properties(e.id);
|
|
103
|
+
if (t.customLabel(e.label), !e.fieldInput) return t;
|
|
104
|
+
let { type: n, options: i = {} } = e.fieldInput;
|
|
105
|
+
return n === "autocomplete" ? t.autocomplete({
|
|
106
|
+
...i.uri && { uri: i.uri },
|
|
107
|
+
...i.resource && { resource: i.resource },
|
|
108
|
+
...i.valueKey && { valueKey: i.valueKey },
|
|
109
|
+
...i.labelKey && { labelKey: i.labelKey },
|
|
110
|
+
...i.enableCreate !== void 0 && { enableCreate: i.enableCreate },
|
|
111
|
+
...i.colspan && { colspan: i.colspan }
|
|
112
|
+
}) : n === "select" ? t.select({
|
|
113
|
+
...i.values && { values: i.values },
|
|
114
|
+
...i.clearable !== void 0 && { clearable: i.clearable },
|
|
115
|
+
...i.storeValue !== void 0 && { storeValue: i.storeValue },
|
|
116
|
+
...i.emitObject !== void 0 && { emitObject: i.emitObject },
|
|
117
|
+
...i.colspan && { colspan: i.colspan }
|
|
118
|
+
}) : t.control(n, { ...i.colspan && { colspan: i.colspan } });
|
|
119
|
+
}, T = (e) => {
|
|
120
|
+
let t = i.grid();
|
|
121
|
+
return e.filter((e) => !e.hiddenInForm).forEach((e) => t.addControl(w(e))), t.build();
|
|
122
|
+
}, E = (e) => {
|
|
123
|
+
let t = i.grid();
|
|
124
|
+
return e.filter((e) => !e.hiddenInMetadata).forEach((e) => t.addControl(w(e).readonly())), t.build();
|
|
125
|
+
}, D = (t) => {
|
|
126
|
+
if (t.type === "object" && t.properties) {
|
|
127
|
+
let n = {};
|
|
128
|
+
for (let [e, r] of Object.entries(t.properties)) n[e] = D(r);
|
|
129
|
+
return e.object(n);
|
|
130
|
+
}
|
|
131
|
+
return e.string();
|
|
132
|
+
}, O = (t, n, r) => {
|
|
133
|
+
let i = b(t, r), a = n.columns ?? [];
|
|
134
|
+
if (!a.length) return i;
|
|
135
|
+
let o = {};
|
|
136
|
+
for (let e of a) {
|
|
137
|
+
let t = D(e.type ?? { type: "string" });
|
|
138
|
+
o[e.id] = e.required === !1 ? t.optional() : t;
|
|
139
|
+
}
|
|
140
|
+
return Object.keys(o).length ? i.parseZodSchema(e.object(o)) : i;
|
|
141
|
+
}, k = (e, t, n = O) => {
|
|
142
|
+
let r = n(e.id, e, t), i = e.columns ?? [], a = i.length > 0, o = e.ui_schema ?? (a ? T(i) : void 0), s = e.metadata_schema ?? (a ? E(i) : void 0), c = {
|
|
143
|
+
id: e.id,
|
|
144
|
+
name: e.name,
|
|
145
|
+
color: e.color,
|
|
146
|
+
isRoot: e.isRoot ?? !0,
|
|
147
|
+
columns: i,
|
|
148
|
+
context: r,
|
|
149
|
+
json_ld: r.toJsonLdContext(),
|
|
150
|
+
json_schema: o ? r.toJsonSchema() : null,
|
|
151
|
+
allowedChildren: e.allowedChildren ?? [],
|
|
152
|
+
allowedLinks: e.allowedLinks ?? [],
|
|
153
|
+
target: e.target ?? "highlight"
|
|
154
|
+
};
|
|
155
|
+
return o && (c.ui_schema = o), s && (c.metadata_schema = s), e.type && (c.type = e.type), e.icon && (c.icon = e.icon), c;
|
|
156
|
+
}, A = (e, t, n) => e.map((e) => k(e, t, n)), j = (e) => "default" in e ? e.default : e, M = (e, t, n) => N(Object.values(e).map(j), t, n), N = (e, t, n) => A(e, t, n), P = async (e) => {
|
|
157
|
+
let t = await fetch(e);
|
|
158
|
+
if (!t.ok) throw Error(`Failed to fetch annotation definitions: ${t.status} ${t.statusText}`);
|
|
159
|
+
return t.json();
|
|
160
|
+
}, F = async (e, t, n, r = P) => N(await r(e), t, n), I = Symbol("annotation-definitions"), L = (e, t) => e ? e.reduce((e, n) => {
|
|
161
|
+
let r = t[n];
|
|
162
|
+
if (r) {
|
|
163
|
+
let t = {
|
|
164
|
+
key: r.id,
|
|
165
|
+
label: r.name
|
|
166
|
+
};
|
|
167
|
+
r.icon && (t.icon = r.icon), e.push(t);
|
|
168
|
+
}
|
|
169
|
+
return e;
|
|
170
|
+
}, []) : [], R = (e, t, n, r) => {
|
|
171
|
+
let i = {
|
|
172
|
+
uiSchema: e.ui_schema ?? null,
|
|
173
|
+
jsonSchema: e.json_schema ?? null,
|
|
174
|
+
metaDataSchema: e.metadata_schema ?? null,
|
|
175
|
+
validation: (e) => e
|
|
176
|
+
};
|
|
177
|
+
return {
|
|
178
|
+
id: e.id,
|
|
179
|
+
name: e.name,
|
|
180
|
+
label: e.name,
|
|
181
|
+
color: e.color,
|
|
182
|
+
style: {
|
|
183
|
+
default: n(e.color),
|
|
184
|
+
active: r(e.color)
|
|
185
|
+
},
|
|
186
|
+
schema: i,
|
|
187
|
+
allowedChildren: L(e.allowedChildren, t),
|
|
188
|
+
allowedLinks: L(e.allowedLinks, t),
|
|
189
|
+
isRoot: e.isRoot ?? !0,
|
|
190
|
+
icon: e.icon,
|
|
191
|
+
type: e.type,
|
|
192
|
+
target: e.target,
|
|
193
|
+
context: e.context,
|
|
194
|
+
_core: e
|
|
195
|
+
};
|
|
196
|
+
}, z = (e) => {
|
|
197
|
+
let { config: t, factory: r } = e, i = e.createHighlightStyle ?? n, o = e.activeHighlightStyle ?? i, s = l(new p()), c = f([]), u = a(() => {
|
|
198
|
+
let e = s.findAllGrouped();
|
|
199
|
+
return c.value.map((t) => R(t, e, i, o));
|
|
200
|
+
}), m = a(() => u.value.reduce((e, t) => (e[t.id] = t, e), {})), h = (e) => m.value[e], g = (e) => {
|
|
201
|
+
s.setDefinitions(e), c.value = e;
|
|
202
|
+
}, _ = (e) => {
|
|
203
|
+
g(M(e, t, r));
|
|
204
|
+
}, v = (e) => {
|
|
205
|
+
g(N(e, t, r));
|
|
206
|
+
}, y = f(!1), b = f(null);
|
|
207
|
+
return d({
|
|
208
|
+
configuration: t,
|
|
209
|
+
definitions: u,
|
|
210
|
+
definitionsMap: m,
|
|
211
|
+
getDefinitionById: h,
|
|
212
|
+
loadFromGlob: _,
|
|
213
|
+
loadFromConfigs: v,
|
|
214
|
+
loadFromDefinitions: g,
|
|
215
|
+
loadFromUrl: async (e, n) => {
|
|
216
|
+
y.value = !0, b.value = null;
|
|
217
|
+
try {
|
|
218
|
+
g(await F(e, t, r, n));
|
|
219
|
+
} catch (e) {
|
|
220
|
+
b.value = e instanceof Error ? e : Error(String(e));
|
|
221
|
+
} finally {
|
|
222
|
+
y.value = !1;
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
loading: y,
|
|
226
|
+
error: b,
|
|
227
|
+
service: s
|
|
228
|
+
});
|
|
229
|
+
}, B = (e) => {
|
|
230
|
+
let t = z(e);
|
|
231
|
+
return e.resourceFolder && t.loadFromGlob(e.resourceFolder), e.definitionsUrl && t.loadFromUrl(e.definitionsUrl, e.fetchFn), u(I, t), t;
|
|
232
|
+
}, V = () => {
|
|
233
|
+
let e = c(I);
|
|
234
|
+
if (!e) throw Error("useAnnotationDefinitions() must be called inside a component that called provideAnnotationDefinitions()");
|
|
235
|
+
return e;
|
|
236
|
+
}, H = (e = "/ns") => {
|
|
237
|
+
let t = e.endsWith("/") ? e.slice(0, -1) : e;
|
|
238
|
+
return {
|
|
239
|
+
all: t,
|
|
240
|
+
allJsonLd: `${t}/anno.jsonld`,
|
|
241
|
+
byId: (e) => `${t}/${e}`,
|
|
242
|
+
jsonLdById: (e) => `${t}/${e}.jsonld`,
|
|
243
|
+
schemasById: (e) => `${t}/${e}/schemas`,
|
|
244
|
+
typeJsonLd: (e) => `${t}/${e}/anno.jsonld`
|
|
245
|
+
};
|
|
246
|
+
}, U = o({
|
|
247
|
+
name: "JsonView",
|
|
248
|
+
props: {
|
|
249
|
+
data: {
|
|
250
|
+
type: [
|
|
251
|
+
Object,
|
|
252
|
+
Array,
|
|
253
|
+
String,
|
|
254
|
+
Number
|
|
255
|
+
],
|
|
256
|
+
default: null
|
|
257
|
+
},
|
|
258
|
+
title: {
|
|
259
|
+
type: String,
|
|
260
|
+
required: !1,
|
|
261
|
+
default: ""
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
setup(e) {
|
|
265
|
+
let t = a(() => JSON.stringify(e.data, null, 2)), n = a(() => !1), r = () => {
|
|
266
|
+
navigator.clipboard.writeText(t.value);
|
|
267
|
+
}, i = () => {
|
|
268
|
+
let n = new Blob([t.value], { type: "application/json" }), r = URL.createObjectURL(n), i = document.createElement("a");
|
|
269
|
+
i.href = r, i.download = `${e.title || "data"}.json`, i.click(), URL.revokeObjectURL(r);
|
|
270
|
+
};
|
|
271
|
+
return () => s("div", { style: {
|
|
272
|
+
fontFamily: "monospace",
|
|
273
|
+
fontSize: "13px",
|
|
274
|
+
padding: "16px",
|
|
275
|
+
maxWidth: "100%",
|
|
276
|
+
boxSizing: "border-box"
|
|
277
|
+
} }, [s("div", { style: {
|
|
278
|
+
display: "flex",
|
|
279
|
+
alignItems: "center",
|
|
280
|
+
gap: "8px",
|
|
281
|
+
marginBottom: "12px",
|
|
282
|
+
flexWrap: "wrap"
|
|
283
|
+
} }, [
|
|
284
|
+
e.title ? s("span", { style: {
|
|
285
|
+
fontWeight: "bold",
|
|
286
|
+
fontSize: "14px",
|
|
287
|
+
marginRight: "auto"
|
|
288
|
+
} }, e.title) : null,
|
|
289
|
+
s("button", {
|
|
290
|
+
onClick: r,
|
|
291
|
+
style: {
|
|
292
|
+
cursor: "pointer",
|
|
293
|
+
padding: "4px 10px",
|
|
294
|
+
fontSize: "12px",
|
|
295
|
+
border: "1px solid #ccc",
|
|
296
|
+
borderRadius: "4px",
|
|
297
|
+
background: "#f5f5f5"
|
|
298
|
+
}
|
|
299
|
+
}, n.value ? "Copied" : "Copy"),
|
|
300
|
+
s("button", {
|
|
301
|
+
onClick: i,
|
|
302
|
+
style: {
|
|
303
|
+
cursor: "pointer",
|
|
304
|
+
padding: "4px 10px",
|
|
305
|
+
fontSize: "12px",
|
|
306
|
+
border: "1px solid #ccc",
|
|
307
|
+
borderRadius: "4px",
|
|
308
|
+
background: "#f5f5f5"
|
|
309
|
+
}
|
|
310
|
+
}, "Download")
|
|
311
|
+
]), s("pre", { style: {
|
|
312
|
+
margin: 0,
|
|
313
|
+
whiteSpace: "pre-wrap",
|
|
314
|
+
wordBreak: "break-word",
|
|
315
|
+
background: "#fafafa",
|
|
316
|
+
border: "1px solid #e0e0e0",
|
|
317
|
+
borderRadius: "4px",
|
|
318
|
+
padding: "12px",
|
|
319
|
+
overflow: "auto"
|
|
320
|
+
} }, t.value)]);
|
|
321
|
+
}
|
|
322
|
+
}), W = {
|
|
323
|
+
namespace: !0,
|
|
324
|
+
layout: "blank"
|
|
325
|
+
}, G = (e, t, n) => {
|
|
326
|
+
let r = e.endsWith("/") ? e.slice(0, -1) : e, i = { ...W };
|
|
327
|
+
return [
|
|
328
|
+
{
|
|
329
|
+
path: `${r}/anno.jsonld`,
|
|
330
|
+
name: "annotation-ns-all-jsonld",
|
|
331
|
+
component: U,
|
|
332
|
+
meta: i,
|
|
333
|
+
props: () => ({
|
|
334
|
+
title: "All JSON-LD contexts",
|
|
335
|
+
data: t.getAllContextBuilders().map((e) => e.toJsonLdContext())
|
|
336
|
+
})
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
path: `${r}/:id.jsonld`,
|
|
340
|
+
name: "annotation-ns-jsonld",
|
|
341
|
+
component: U,
|
|
342
|
+
meta: i,
|
|
343
|
+
props: (e) => {
|
|
344
|
+
let r = e.params.id;
|
|
345
|
+
if (r === "AnnotationStyle" && n) return {
|
|
346
|
+
title: `${r}.jsonld`,
|
|
347
|
+
data: C(n).toJsonLdContext()
|
|
348
|
+
};
|
|
349
|
+
let i = t.findById(r);
|
|
350
|
+
return {
|
|
351
|
+
title: `${r}.jsonld`,
|
|
352
|
+
data: i?.json_ld ?? null
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
path: `${r}/:type/anno.jsonld`,
|
|
358
|
+
name: "annotation-ns-type-jsonld",
|
|
359
|
+
component: U,
|
|
360
|
+
meta: i,
|
|
361
|
+
props: (e) => {
|
|
362
|
+
let n = e.params.type, r = t.getContextBuilder(n);
|
|
363
|
+
return r ? {
|
|
364
|
+
title: `${n}/anno.jsonld`,
|
|
365
|
+
data: {
|
|
366
|
+
jsonLd: r.toJsonLdContext(),
|
|
367
|
+
forms: r.toJsonSchema()
|
|
368
|
+
}
|
|
369
|
+
} : {
|
|
370
|
+
title: n,
|
|
371
|
+
data: null
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
path: `${r}/:id/schemas`,
|
|
377
|
+
name: "annotation-ns-schemas",
|
|
378
|
+
component: U,
|
|
379
|
+
meta: i,
|
|
380
|
+
props: (e) => {
|
|
381
|
+
let n = e.params.id, r = t.findById(n);
|
|
382
|
+
return r ? {
|
|
383
|
+
title: `${n}/schemas`,
|
|
384
|
+
data: {
|
|
385
|
+
id: r.id,
|
|
386
|
+
name: r.name,
|
|
387
|
+
json_schema: r.json_schema,
|
|
388
|
+
ui_schema: r.ui_schema,
|
|
389
|
+
metadata_schema: r.metadata_schema,
|
|
390
|
+
columns: r.columns,
|
|
391
|
+
isRoot: r.isRoot,
|
|
392
|
+
allowedChildren: r.allowedChildren,
|
|
393
|
+
allowedLinks: r.allowedLinks,
|
|
394
|
+
type: r.type,
|
|
395
|
+
icon: r.icon,
|
|
396
|
+
target: r.target
|
|
397
|
+
}
|
|
398
|
+
} : {
|
|
399
|
+
title: n,
|
|
400
|
+
data: null
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
},
|
|
404
|
+
{
|
|
405
|
+
path: `${r}/:id`,
|
|
406
|
+
name: "annotation-ns-by-id",
|
|
407
|
+
component: U,
|
|
408
|
+
meta: i,
|
|
409
|
+
props: (e) => {
|
|
410
|
+
let n = e.params.id;
|
|
411
|
+
return {
|
|
412
|
+
title: n,
|
|
413
|
+
data: t.findById(n) ?? null
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
path: r,
|
|
419
|
+
name: "annotation-ns-all",
|
|
420
|
+
component: U,
|
|
421
|
+
meta: i,
|
|
422
|
+
props: () => ({
|
|
423
|
+
title: "All definitions",
|
|
424
|
+
data: t.findAll()
|
|
425
|
+
})
|
|
426
|
+
}
|
|
427
|
+
];
|
|
428
|
+
}, K = (e, t, n) => {
|
|
429
|
+
G(n?.basePath ?? "/ns", t, n?.config).forEach((t) => e.addRoute(t));
|
|
430
|
+
}, q = { install(e, t) {
|
|
431
|
+
K(t.router, t.service, {
|
|
432
|
+
basePath: t.basePath,
|
|
433
|
+
config: t.config
|
|
434
|
+
});
|
|
435
|
+
} }, J = { install(e, t) {
|
|
436
|
+
let n = z(t);
|
|
437
|
+
return t.resourceFolder && n.loadFromGlob(t.resourceFolder), t.definitionsUrl && n.loadFromUrl(t.definitionsUrl, t.fetchFn), e.provide(I, n), K(t.router, n.service, {
|
|
438
|
+
basePath: t.basePath,
|
|
439
|
+
config: t.config
|
|
440
|
+
}), n;
|
|
441
|
+
} };
|
|
442
|
+
//#endregion
|
|
443
|
+
export { p as AnnotationDefinitionService, q as AnnotationNamespacePlugin, J as AnnotationPlugin, W as NAMESPACE_ROUTE_META, z as createAnnotationDefinitionsState, H as createAnnotationNamespacePaths, G as createAnnotationNamespaceRoutes, K as installAnnotationNamespaceRoutes, N as loadAnnotationDefinitionsFromConfigs, M as loadAnnotationDefinitionsFromGlob, F as loadAnnotationDefinitionsFromUrl, B as provideAnnotationDefinitions, V as useAnnotationDefinitions };
|
package/index.umd.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("zod"),require("@ghentcdh/w3c-utils"),require("@ghentcdh/annotated-text"),require("@ghentcdh/crouton-forms-vue"),require("vue")):typeof define==`function`&&define.amd?define([`exports`,`zod`,`@ghentcdh/w3c-utils`,`@ghentcdh/annotated-text`,`@ghentcdh/crouton-forms-vue`,`vue`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e[`annotation-vue`]={},e.zod,e._ghentcdh_w3c_utils,e._ghentcdh_annotated_text,e._ghentcdh_crouton_forms_vue,e.vue))})(this,function(e,t,n,r,i,a){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var o=class{definitions=[];groupedDefinitions={};constructor(e=[]){e.length&&this.setDefinitions(e)}setDefinitions(e){this.definitions=e,this.groupedDefinitions=e.reduce((e,t)=>(e[t.id]=t,e),{})}findAll(){return this.definitions}findById(e){return this.groupedDefinitions[e]}findAllGrouped(){return this.groupedDefinitions}getAllContextBuilders(){return this.definitions.map(e=>e.context)}getContextBuilder(e){return this.findById(e)?.context}},s=[`text`],c=t.z.object({text:t.z.string(),textDirection:t.z.enum([`ltr`,`rtl`]).default(`ltr`),processingLanguage:t.z.string().default(`en`),label:t.z.string().optional(),offset:t.z.number().optional().default(0)});t.z.object({id:t.z.string(),uri:t.z.string(),type:t.z.enum(s),content:c});var l=`AnnotationMetadata`,u=t.z.custom();t.z.object({id:t.z.string(),name:t.z.string(),columns:t.z.array(u),json_schema:t.z.any().optional(),json_ld:t.z.any().optional(),ui_schema:t.z.any().optional(),metadata_schema:t.z.any().optional(),color:t.z.string(),type:t.z.string().optional(),icon:t.z.string().optional(),isRoot:t.z.boolean().default(!0),allowedChildren:t.z.array(t.z.string()).default([]),allowedLinks:t.z.array(t.z.string()).default([]),context:t.z.custom(),target:t.z.enum([`gutter`,`underline`,`highlight`]).default(`highlight`)});var d={baseUrl:`http://localhost:3000/`,app:`ghentcdh`,prefix:`ghentcdh`,isDev:!1,cacheTTLms:1200*1e3},f=(e={})=>{let t=e.baseUrl??d.baseUrl,n=t.endsWith(`/`)?t:`${t}/`,r=e.isDev??!1,i=r?0:1200*1e3;return{baseUrl:n,contextUrl:`${n}ns/`,app:e.app??d.app,prefix:e.prefix??d.prefix,isDev:r,cacheTTLms:i}},p=(e,t)=>{let{prefix:r,baseUrl:i,contextUrl:a}=f(t),o=l;return(0,n.contextBuilder)(r,i).setType(r,o).addPrefix(e,`${r}:${e}`).setContextUri(`${a}${e}.jsonld`)},m=t.z.object({id:t.z.string(),name:t.z.string(),target:t.z.enum([`gutter`,`underline`,`highlight`]).optional().default(`underline`),color:t.z.string().optional()}),h=`AnnotationStyle`,g=e=>{let{prefix:t,baseUrl:r,contextUrl:i}=f(e);return(0,n.contextBuilder)(t,r).setType(t,h).setContextUri(`${i}${h}.jsonld`).parseZodSchema(m)},_=e=>{let t=i.ControlBuilder.properties(e.id);if(t.customLabel(e.label),!e.fieldInput)return t;let{type:n,options:r={}}=e.fieldInput;return n===`autocomplete`?t.autocomplete({...r.uri&&{uri:r.uri},...r.resource&&{resource:r.resource},...r.valueKey&&{valueKey:r.valueKey},...r.labelKey&&{labelKey:r.labelKey},...r.enableCreate!==void 0&&{enableCreate:r.enableCreate},...r.colspan&&{colspan:r.colspan}}):n===`select`?t.select({...r.values&&{values:r.values},...r.clearable!==void 0&&{clearable:r.clearable},...r.storeValue!==void 0&&{storeValue:r.storeValue},...r.emitObject!==void 0&&{emitObject:r.emitObject},...r.colspan&&{colspan:r.colspan}}):t.control(n,{...r.colspan&&{colspan:r.colspan}})},v=e=>{let t=i.LayoutBuilder.grid();return e.filter(e=>!e.hiddenInForm).forEach(e=>t.addControl(_(e))),t.build()},y=e=>{let t=i.LayoutBuilder.grid();return e.filter(e=>!e.hiddenInMetadata).forEach(e=>t.addControl(_(e).readonly())),t.build()},b=e=>{if(e.type===`object`&&e.properties){let n={};for(let[t,r]of Object.entries(e.properties))n[t]=b(r);return t.z.object(n)}return t.z.string()},x=(e,n,r)=>{let i=p(e,r),a=n.columns??[];if(!a.length)return i;let o={};for(let e of a){let t=b(e.type??{type:`string`});o[e.id]=e.required===!1?t.optional():t}return Object.keys(o).length?i.parseZodSchema(t.z.object(o)):i},S=(e,t,n=x)=>{let r=n(e.id,e,t),i=e.columns??[],a=i.length>0,o=e.ui_schema??(a?v(i):void 0),s=e.metadata_schema??(a?y(i):void 0),c={id:e.id,name:e.name,color:e.color,isRoot:e.isRoot??!0,columns:i,context:r,json_ld:r.toJsonLdContext(),json_schema:o?r.toJsonSchema():null,allowedChildren:e.allowedChildren??[],allowedLinks:e.allowedLinks??[],target:e.target??`highlight`};return o&&(c.ui_schema=o),s&&(c.metadata_schema=s),e.type&&(c.type=e.type),e.icon&&(c.icon=e.icon),c},C=(e,t,n)=>e.map(e=>S(e,t,n)),w=e=>`default`in e?e.default:e,T=(e,t,n)=>E(Object.values(e).map(w),t,n),E=(e,t,n)=>C(e,t,n),D=async e=>{let t=await fetch(e);if(!t.ok)throw Error(`Failed to fetch annotation definitions: ${t.status} ${t.statusText}`);return t.json()},O=async(e,t,n,r=D)=>E(await r(e),t,n),k=Symbol(`annotation-definitions`),A=(e,t)=>e?e.reduce((e,n)=>{let r=t[n];if(r){let t={key:r.id,label:r.name};r.icon&&(t.icon=r.icon),e.push(t)}return e},[]):[],j=(e,t,n,r)=>{let i={uiSchema:e.ui_schema??null,jsonSchema:e.json_schema??null,metaDataSchema:e.metadata_schema??null,validation:e=>e};return{id:e.id,name:e.name,label:e.name,color:e.color,style:{default:n(e.color),active:r(e.color)},schema:i,allowedChildren:A(e.allowedChildren,t),allowedLinks:A(e.allowedLinks,t),isRoot:e.isRoot??!0,icon:e.icon,type:e.type,target:e.target,context:e.context,_core:e}},M=e=>{let{config:t,factory:n}=e,i=e.createHighlightStyle??r.createHighlightStyle,s=e.activeHighlightStyle??i,c=(0,a.markRaw)(new o),l=(0,a.ref)([]),u=(0,a.computed)(()=>{let e=c.findAllGrouped();return l.value.map(t=>j(t,e,i,s))}),d=(0,a.computed)(()=>u.value.reduce((e,t)=>(e[t.id]=t,e),{})),f=e=>d.value[e],p=e=>{c.setDefinitions(e),l.value=e},m=e=>{p(T(e,t,n))},h=e=>{p(E(e,t,n))},g=(0,a.ref)(!1),_=(0,a.ref)(null);return(0,a.reactive)({configuration:t,definitions:u,definitionsMap:d,getDefinitionById:f,loadFromGlob:m,loadFromConfigs:h,loadFromDefinitions:p,loadFromUrl:async(e,r)=>{g.value=!0,_.value=null;try{p(await O(e,t,n,r))}catch(e){_.value=e instanceof Error?e:Error(String(e))}finally{g.value=!1}},loading:g,error:_,service:c})},N=e=>{let t=M(e);return e.resourceFolder&&t.loadFromGlob(e.resourceFolder),e.definitionsUrl&&t.loadFromUrl(e.definitionsUrl,e.fetchFn),(0,a.provide)(k,t),t},P=()=>{let e=(0,a.inject)(k);if(!e)throw Error(`useAnnotationDefinitions() must be called inside a component that called provideAnnotationDefinitions()`);return e},F=(e=`/ns`)=>{let t=e.endsWith(`/`)?e.slice(0,-1):e;return{all:t,allJsonLd:`${t}/anno.jsonld`,byId:e=>`${t}/${e}`,jsonLdById:e=>`${t}/${e}.jsonld`,schemasById:e=>`${t}/${e}/schemas`,typeJsonLd:e=>`${t}/${e}/anno.jsonld`}},I=(0,a.defineComponent)({name:`JsonView`,props:{data:{type:[Object,Array,String,Number],default:null},title:{type:String,required:!1,default:``}},setup(e){let t=(0,a.computed)(()=>JSON.stringify(e.data,null,2)),n=(0,a.computed)(()=>!1),r=()=>{navigator.clipboard.writeText(t.value)},i=()=>{let n=new Blob([t.value],{type:`application/json`}),r=URL.createObjectURL(n),i=document.createElement(`a`);i.href=r,i.download=`${e.title||`data`}.json`,i.click(),URL.revokeObjectURL(r)};return()=>(0,a.h)(`div`,{style:{fontFamily:`monospace`,fontSize:`13px`,padding:`16px`,maxWidth:`100%`,boxSizing:`border-box`}},[(0,a.h)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`,marginBottom:`12px`,flexWrap:`wrap`}},[e.title?(0,a.h)(`span`,{style:{fontWeight:`bold`,fontSize:`14px`,marginRight:`auto`}},e.title):null,(0,a.h)(`button`,{onClick:r,style:{cursor:`pointer`,padding:`4px 10px`,fontSize:`12px`,border:`1px solid #ccc`,borderRadius:`4px`,background:`#f5f5f5`}},n.value?`Copied`:`Copy`),(0,a.h)(`button`,{onClick:i,style:{cursor:`pointer`,padding:`4px 10px`,fontSize:`12px`,border:`1px solid #ccc`,borderRadius:`4px`,background:`#f5f5f5`}},`Download`)]),(0,a.h)(`pre`,{style:{margin:0,whiteSpace:`pre-wrap`,wordBreak:`break-word`,background:`#fafafa`,border:`1px solid #e0e0e0`,borderRadius:`4px`,padding:`12px`,overflow:`auto`}},t.value)])}}),L={namespace:!0,layout:`blank`},R=(e,t,n)=>{let r=e.endsWith(`/`)?e.slice(0,-1):e,i={...L};return[{path:`${r}/anno.jsonld`,name:`annotation-ns-all-jsonld`,component:I,meta:i,props:()=>({title:`All JSON-LD contexts`,data:t.getAllContextBuilders().map(e=>e.toJsonLdContext())})},{path:`${r}/:id.jsonld`,name:`annotation-ns-jsonld`,component:I,meta:i,props:e=>{let r=e.params.id;if(r===`AnnotationStyle`&&n)return{title:`${r}.jsonld`,data:g(n).toJsonLdContext()};let i=t.findById(r);return{title:`${r}.jsonld`,data:i?.json_ld??null}}},{path:`${r}/:type/anno.jsonld`,name:`annotation-ns-type-jsonld`,component:I,meta:i,props:e=>{let n=e.params.type,r=t.getContextBuilder(n);return r?{title:`${n}/anno.jsonld`,data:{jsonLd:r.toJsonLdContext(),forms:r.toJsonSchema()}}:{title:n,data:null}}},{path:`${r}/:id/schemas`,name:`annotation-ns-schemas`,component:I,meta:i,props:e=>{let n=e.params.id,r=t.findById(n);return r?{title:`${n}/schemas`,data:{id:r.id,name:r.name,json_schema:r.json_schema,ui_schema:r.ui_schema,metadata_schema:r.metadata_schema,columns:r.columns,isRoot:r.isRoot,allowedChildren:r.allowedChildren,allowedLinks:r.allowedLinks,type:r.type,icon:r.icon,target:r.target}}:{title:n,data:null}}},{path:`${r}/:id`,name:`annotation-ns-by-id`,component:I,meta:i,props:e=>{let n=e.params.id;return{title:n,data:t.findById(n)??null}}},{path:r,name:`annotation-ns-all`,component:I,meta:i,props:()=>({title:`All definitions`,data:t.findAll()})}]},z=(e,t,n)=>{R(n?.basePath??`/ns`,t,n?.config).forEach(t=>e.addRoute(t))};e.AnnotationDefinitionService=o,e.AnnotationNamespacePlugin={install(e,t){z(t.router,t.service,{basePath:t.basePath,config:t.config})}},e.AnnotationPlugin={install(e,t){let n=M(t);return t.resourceFolder&&n.loadFromGlob(t.resourceFolder),t.definitionsUrl&&n.loadFromUrl(t.definitionsUrl,t.fetchFn),e.provide(k,n),z(t.router,n.service,{basePath:t.basePath,config:t.config}),n}},e.NAMESPACE_ROUTE_META=L,e.createAnnotationDefinitionsState=M,e.createAnnotationNamespacePaths=F,e.createAnnotationNamespaceRoutes=R,e.installAnnotationNamespaceRoutes=z,e.loadAnnotationDefinitionsFromConfigs=E,e.loadAnnotationDefinitionsFromGlob=T,e.loadAnnotationDefinitionsFromUrl=O,e.provideAnnotationDefinitions=N,e.useAnnotationDefinitions=P});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { InjectionKey } from 'vue';
|
|
2
|
+
import { AnnotationDefConfig, AnnotationDefinition as CoreAnnotationDefinition, AnnotationJsonConfig, ContextBuilderFactory } from '@ghentcdh/annotation-core';
|
|
3
|
+
import { createHighlightStyle } from '@ghentcdh/annotated-text';
|
|
4
|
+
import { VueAnnotationDefinition } from '../types/annotation-vue.types';
|
|
5
|
+
import { AnnotationDefinitionService } from '../service/annotation-definition.service';
|
|
6
|
+
import { DefinitionsFetchFn, GlobModules } from '../loader/annotation-definition.loader';
|
|
7
|
+
export type AnnotationDefinitionsState = {
|
|
8
|
+
configuration: AnnotationDefConfig;
|
|
9
|
+
definitions: VueAnnotationDefinition[];
|
|
10
|
+
definitionsMap: Record<string, VueAnnotationDefinition>;
|
|
11
|
+
getDefinitionById: (id: string) => VueAnnotationDefinition | undefined;
|
|
12
|
+
loadFromGlob: (modules: GlobModules) => void;
|
|
13
|
+
loadFromConfigs: (configs: AnnotationJsonConfig[]) => void;
|
|
14
|
+
loadFromDefinitions: (defs: CoreAnnotationDefinition[]) => void;
|
|
15
|
+
loadFromUrl: (url: string, fetchFn?: DefinitionsFetchFn) => Promise<void>;
|
|
16
|
+
loading: boolean;
|
|
17
|
+
error: Error | null;
|
|
18
|
+
service: AnnotationDefinitionService;
|
|
19
|
+
};
|
|
20
|
+
export type ProvideAnnotationDefinitionsOptions = {
|
|
21
|
+
config: AnnotationDefConfig;
|
|
22
|
+
resourceFolder?: GlobModules;
|
|
23
|
+
createHighlightStyle?: typeof createHighlightStyle;
|
|
24
|
+
activeHighlightStyle?: typeof createHighlightStyle;
|
|
25
|
+
factory?: ContextBuilderFactory;
|
|
26
|
+
definitionsUrl?: string;
|
|
27
|
+
fetchFn?: DefinitionsFetchFn;
|
|
28
|
+
};
|
|
29
|
+
export declare const ANNOTATION_DEFINITIONS_KEY: InjectionKey<AnnotationDefinitionsState>;
|
|
30
|
+
export declare const createAnnotationDefinitionsState: (options: ProvideAnnotationDefinitionsOptions) => AnnotationDefinitionsState;
|
|
31
|
+
/**
|
|
32
|
+
* Called once at root — creates state, provides to descendants.
|
|
33
|
+
* If `resourceFolder` given, loads definitions immediately.
|
|
34
|
+
*/
|
|
35
|
+
export declare const provideAnnotationDefinitions: (options: ProvideAnnotationDefinitionsOptions) => AnnotationDefinitionsState;
|
|
36
|
+
/**
|
|
37
|
+
* Called in child components — injects state from ancestor.
|
|
38
|
+
*/
|
|
39
|
+
export declare const useAnnotationDefinitions: () => AnnotationDefinitionsState;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AnnotationJsonConfig, AnnotationDefConfig, AnnotationDefinition, ContextBuilderFactory } from '@ghentcdh/annotation-core';
|
|
2
|
+
type GlobModule = {
|
|
3
|
+
default: AnnotationJsonConfig;
|
|
4
|
+
} | AnnotationJsonConfig;
|
|
5
|
+
export type GlobModules = Record<string, GlobModule>;
|
|
6
|
+
export declare const loadAnnotationDefinitionsFromGlob: (modules: GlobModules, config: AnnotationDefConfig, factory?: ContextBuilderFactory) => AnnotationDefinition[];
|
|
7
|
+
export declare const loadAnnotationDefinitionsFromConfigs: (configs: AnnotationJsonConfig[], config: AnnotationDefConfig, factory?: ContextBuilderFactory) => AnnotationDefinition[];
|
|
8
|
+
export type DefinitionsFetchFn = (url: string) => Promise<AnnotationJsonConfig[]>;
|
|
9
|
+
export declare const loadAnnotationDefinitionsFromUrl: (url: string, config: AnnotationDefConfig, factory?: ContextBuilderFactory, fetchFn?: DefinitionsFetchFn) => Promise<AnnotationDefinition[]>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Plugin } from 'vue';
|
|
2
|
+
import { Router } from 'vue-router';
|
|
3
|
+
import { AnnotationDefConfig } from '@ghentcdh/annotation-core';
|
|
4
|
+
import { AnnotationDefinitionService } from '../service/annotation-definition.service';
|
|
5
|
+
import { ProvideAnnotationDefinitionsOptions } from '../composables/useAnnotationDefinitions';
|
|
6
|
+
export type AnnotationNamespacePluginOptions = {
|
|
7
|
+
router: Router;
|
|
8
|
+
service: AnnotationDefinitionService;
|
|
9
|
+
basePath?: string;
|
|
10
|
+
config?: AnnotationDefConfig;
|
|
11
|
+
};
|
|
12
|
+
export type AnnotationPluginOptions = ProvideAnnotationDefinitionsOptions & {
|
|
13
|
+
router: Router;
|
|
14
|
+
basePath?: string;
|
|
15
|
+
};
|
|
16
|
+
export declare const installAnnotationNamespaceRoutes: (router: Router, service: AnnotationDefinitionService, options?: {
|
|
17
|
+
basePath?: string;
|
|
18
|
+
config?: AnnotationDefConfig;
|
|
19
|
+
}) => void;
|
|
20
|
+
export declare const AnnotationNamespacePlugin: Plugin<[
|
|
21
|
+
AnnotationNamespacePluginOptions
|
|
22
|
+
]>;
|
|
23
|
+
export declare const AnnotationPlugin: Plugin<[AnnotationPluginOptions]>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { RouteRecordRaw } from 'vue-router';
|
|
2
|
+
import { AnnotationDefConfig } from '@ghentcdh/annotation-core';
|
|
3
|
+
import { AnnotationDefinitionService } from '../service/annotation-definition.service';
|
|
4
|
+
export type AnnotationNamespaceRoutePaths = {
|
|
5
|
+
all: string;
|
|
6
|
+
allJsonLd: string;
|
|
7
|
+
byId: (id: string) => string;
|
|
8
|
+
jsonLdById: (id: string) => string;
|
|
9
|
+
schemasById: (id: string) => string;
|
|
10
|
+
typeJsonLd: (type: string) => string;
|
|
11
|
+
};
|
|
12
|
+
export declare const createAnnotationNamespacePaths: (basePath?: string) => AnnotationNamespaceRoutePaths;
|
|
13
|
+
export declare const NAMESPACE_ROUTE_META: {
|
|
14
|
+
readonly namespace: true;
|
|
15
|
+
readonly layout: "blank";
|
|
16
|
+
};
|
|
17
|
+
export declare const createAnnotationNamespaceRoutes: (basePath: string, service: AnnotationDefinitionService, config?: AnnotationDefConfig) => RouteRecordRaw[];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AnnotationDefinition } from '@ghentcdh/annotation-core';
|
|
2
|
+
export declare class AnnotationDefinitionService {
|
|
3
|
+
private definitions;
|
|
4
|
+
private groupedDefinitions;
|
|
5
|
+
constructor(definitions?: AnnotationDefinition[]);
|
|
6
|
+
setDefinitions(definitions: AnnotationDefinition[]): void;
|
|
7
|
+
findAll(): AnnotationDefinition[];
|
|
8
|
+
findById(id: string): AnnotationDefinition | undefined;
|
|
9
|
+
findAllGrouped(): Record<string, AnnotationDefinition>;
|
|
10
|
+
getAllContextBuilders(): unknown[];
|
|
11
|
+
getContextBuilder(type: string): unknown | undefined;
|
|
12
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { AnnotationDefinition as CoreAnnotationDefinition, FormValidationDef, KeyLabel } from '@ghentcdh/annotation-core';
|
|
2
|
+
import { ContextBuilder } from '@ghentcdh/w3c-utils';
|
|
3
|
+
import { CustomAnnotationStyle } from '@ghentcdh/annotated-text';
|
|
4
|
+
export type { KeyLabel, FormValidationDef } from '@ghentcdh/annotation-core';
|
|
5
|
+
export type VueAnnotationDefinition = {
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
label: string;
|
|
9
|
+
color: string;
|
|
10
|
+
style: CustomAnnotationStyle;
|
|
11
|
+
schema: FormValidationDef;
|
|
12
|
+
allowedChildren: KeyLabel[];
|
|
13
|
+
allowedLinks: KeyLabel[];
|
|
14
|
+
isRoot: boolean;
|
|
15
|
+
icon?: string;
|
|
16
|
+
type?: string;
|
|
17
|
+
target?: 'gutter' | 'underline' | 'highlight';
|
|
18
|
+
context: ContextBuilder;
|
|
19
|
+
_core: CoreAnnotationDefinition;
|
|
20
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ghentcdh/annotation-vue",
|
|
3
|
+
"version": "0.0.1-alpha.10",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "https://github.com/GhentCDH/annotation-editor"
|
|
7
|
+
},
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "./index.js",
|
|
10
|
+
"types": "./index.d.ts",
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@ghentcdh/annotated-text": "^1.0.9"
|
|
13
|
+
},
|
|
14
|
+
"peerDependencies": {
|
|
15
|
+
"vue": "^3.5.0",
|
|
16
|
+
"@ghentcdh/w3c-utils": "*",
|
|
17
|
+
"vue-router": "^5.0.0"
|
|
18
|
+
},
|
|
19
|
+
"peerDependenciesMeta": {
|
|
20
|
+
"vue-router": {
|
|
21
|
+
"optional": true
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|