@manifest-editor/creators 1.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 +21 -0
- package/dist/chunk-7FSKLOVQ.js +33 -0
- package/dist/chunk-YSQDPG26.js +30 -0
- package/dist/iiif-browser-form.lazy-C3VAAY7I.js +34 -0
- package/dist/iiif-browser-form.lazy-PL3WMLU5.js +33 -0
- package/dist/iiif-browser-form.lazy-QLO62DFA.js +32 -0
- package/dist/iiif-browser-form.lazy-ZADCSMAN.js +32 -0
- package/dist/index.cjs +2082 -0
- package/dist/index.d.cts +40 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.js +1972 -0
- package/dist/manifest-browser-form.lazy-FLU4HSPW.js +7 -0
- package/dist/manifest-browser-form.lazy-WRWZPVRC.js +6 -0
- package/package.json +73 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1972 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ManifestBrowserCreatorForm
|
|
3
|
+
} from "./chunk-7FSKLOVQ.js";
|
|
4
|
+
|
|
5
|
+
// src/Canvas/EmptyCanvas/index.tsx
|
|
6
|
+
import { EmptyCanvasIcon } from "@manifest-editor/components";
|
|
7
|
+
import { jsx } from "react/jsx-runtime";
|
|
8
|
+
var emptyCanvas = {
|
|
9
|
+
id: "@manifest-editor/empty-canvas",
|
|
10
|
+
create: createEmptyCanvas,
|
|
11
|
+
label: "Empty canvas",
|
|
12
|
+
summary: "No content",
|
|
13
|
+
icon: /* @__PURE__ */ jsx(EmptyCanvasIcon, {}),
|
|
14
|
+
resourceType: "Canvas",
|
|
15
|
+
resourceFields: ["id", "type", "label", "height", "width", "items"],
|
|
16
|
+
supports: {
|
|
17
|
+
parentTypes: ["Manifest"],
|
|
18
|
+
parentFields: ["items"]
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
async function createEmptyCanvas(data, ctx) {
|
|
22
|
+
const canvasId = ctx.generateId("canvas");
|
|
23
|
+
const page = ctx.embed({
|
|
24
|
+
id: ctx.generateId("annotation-page", { id: canvasId, type: "Canvas" }),
|
|
25
|
+
type: "AnnotationPage",
|
|
26
|
+
items: []
|
|
27
|
+
});
|
|
28
|
+
return {
|
|
29
|
+
id: canvasId,
|
|
30
|
+
type: "Canvas",
|
|
31
|
+
label: data.label || { en: [""] },
|
|
32
|
+
height: data.height || 1e3,
|
|
33
|
+
width: data.width || 1e3,
|
|
34
|
+
items: [page]
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ../ui/icons/TextFormatIcon.tsx
|
|
39
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
40
|
+
var TextFormatIcon = (props) => /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", height: "1em", width: "1em", ...props, children: [
|
|
41
|
+
/* @__PURE__ */ jsx2("path", { d: "M0 0h24v24H0z", fill: "none" }),
|
|
42
|
+
/* @__PURE__ */ jsx2("path", { d: "M5 17v2h14v-2H5zm4.5-4.2h5l.9 2.2h2.1L12.75 4h-1.5L6.5 15h2.1l.9-2.2zM12 5.98 13.87 11h-3.74L12 5.98z" })
|
|
43
|
+
] });
|
|
44
|
+
|
|
45
|
+
// src/ContentResource/PlaintextCreator/create-plaintext.tsx
|
|
46
|
+
import { LanguageFieldEditor, InputContainer, InputLabel, Input } from "@manifest-editor/editors";
|
|
47
|
+
|
|
48
|
+
// ../ui/atoms/Button.tsx
|
|
49
|
+
import styled from "styled-components";
|
|
50
|
+
var ButtonReset = styled.button`
|
|
51
|
+
border: none;
|
|
52
|
+
outline: none;
|
|
53
|
+
background-color: transparent;
|
|
54
|
+
margin: 0;
|
|
55
|
+
padding: 0;
|
|
56
|
+
font-size: inherit;
|
|
57
|
+
color: inherit;
|
|
58
|
+
cursor: pointer;
|
|
59
|
+
&:hover {
|
|
60
|
+
color: inherit;
|
|
61
|
+
}
|
|
62
|
+
`;
|
|
63
|
+
var Button = styled.button`
|
|
64
|
+
padding: 0.5rem 1rem;
|
|
65
|
+
color: ${(props) => props.theme.color.main || "none"};
|
|
66
|
+
background-color: ${(props) => props.theme.color.white || "white"};
|
|
67
|
+
border-radius: inherit;
|
|
68
|
+
border: none;
|
|
69
|
+
cursor: pointer;
|
|
70
|
+
display: flex;
|
|
71
|
+
align-items: center;
|
|
72
|
+
font-size: 0.85em;
|
|
73
|
+
:disabled {
|
|
74
|
+
opacity: 0.65;
|
|
75
|
+
cursor: not-allowed;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
&:hover {
|
|
79
|
+
background: #eee;
|
|
80
|
+
}
|
|
81
|
+
`;
|
|
82
|
+
var SmallButton = styled(Button)`
|
|
83
|
+
padding: 0.25em ${(props) => props.theme.padding.xs || "0.4em"};
|
|
84
|
+
height: unset;
|
|
85
|
+
background: none;
|
|
86
|
+
`;
|
|
87
|
+
var SecondaryButton = styled(Button)`
|
|
88
|
+
{
|
|
89
|
+
padding: 0 ${(props) => props.theme.padding.medium || "1rem"};
|
|
90
|
+
color: ${(props) => props.theme.color.main || "#B84C74;"};
|
|
91
|
+
background-color: ${(props) => props.theme.color.white || "white"};
|
|
92
|
+
border: 1px solid ${(props) => props.theme.color.main || "#B84C74;"};
|
|
93
|
+
border-radius: 0.25rem;
|
|
94
|
+
cursor: pointer;
|
|
95
|
+
height: 2rem;
|
|
96
|
+
display: flex;
|
|
97
|
+
align-items: center;
|
|
98
|
+
white-space: nowrap;
|
|
99
|
+
font-size: 0.75rem;
|
|
100
|
+
|
|
101
|
+
:disabled {
|
|
102
|
+
opacity: 0.65;
|
|
103
|
+
cursor: not-allowed;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
`;
|
|
107
|
+
var CalltoButton = styled(Button)`
|
|
108
|
+
padding: 0 ${(props) => props.theme.padding.medium || "1rem"};
|
|
109
|
+
color: ${(props) => props.theme.color.white || "white"};
|
|
110
|
+
background-color: ${(props) => props.theme.color.main || "#B84C74;"};
|
|
111
|
+
border: 1px solid #eee;
|
|
112
|
+
border-radius: 0.25rem;
|
|
113
|
+
cursor: pointer;
|
|
114
|
+
justify-content: center;
|
|
115
|
+
display: flex;
|
|
116
|
+
align-items: center;
|
|
117
|
+
&:hover {
|
|
118
|
+
background-color: ${(props) => props.theme.color.mainHover || "#B84C74;"};
|
|
119
|
+
}
|
|
120
|
+
`;
|
|
121
|
+
var ButtonGroup = styled.div`
|
|
122
|
+
display: flex;
|
|
123
|
+
flex-direction: row;
|
|
124
|
+
flex-wrap: wrap;
|
|
125
|
+
align-items: flex-start;
|
|
126
|
+
justify-content: ${(props) => props.$right ? "flex-end" : "flex-start"};
|
|
127
|
+
`;
|
|
128
|
+
|
|
129
|
+
// ../ui/atoms/PaddedSidebarContainer.tsx
|
|
130
|
+
import styled2 from "styled-components";
|
|
131
|
+
var PaddedSidebarContainer = styled2.div`
|
|
132
|
+
padding: 0 0.7em;
|
|
133
|
+
margin: 0.7em 0;
|
|
134
|
+
flex: 1;
|
|
135
|
+
overflow: visible;
|
|
136
|
+
`;
|
|
137
|
+
|
|
138
|
+
// src/ContentResource/PlaintextCreator/create-plaintext.tsx
|
|
139
|
+
import { useState } from "react";
|
|
140
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
141
|
+
async function createPlaintext(data, ctx) {
|
|
142
|
+
return ctx.embed({
|
|
143
|
+
id: data.url,
|
|
144
|
+
type: "Text",
|
|
145
|
+
label: data.label,
|
|
146
|
+
format: "text/plain"
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
function CreatePlaintextForm(props) {
|
|
150
|
+
const [label, setLabel] = useState({ en: ["View as text"] });
|
|
151
|
+
const onSubmit = (e) => {
|
|
152
|
+
e.preventDefault();
|
|
153
|
+
const data = new FormData(e.target);
|
|
154
|
+
const formData = Object.fromEntries(data.entries());
|
|
155
|
+
if (formData.url) {
|
|
156
|
+
props.runCreate({ url: formData.url, label });
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
return /* @__PURE__ */ jsx3(PaddedSidebarContainer, { children: /* @__PURE__ */ jsxs2("form", { onSubmit, children: [
|
|
160
|
+
/* @__PURE__ */ jsx3(
|
|
161
|
+
LanguageFieldEditor,
|
|
162
|
+
{
|
|
163
|
+
focusId: "label",
|
|
164
|
+
label: "Label",
|
|
165
|
+
fields: label,
|
|
166
|
+
onSave: (e) => setLabel(e.toInternationalString())
|
|
167
|
+
}
|
|
168
|
+
),
|
|
169
|
+
/* @__PURE__ */ jsxs2(InputContainer, { $wide: true, children: [
|
|
170
|
+
/* @__PURE__ */ jsx3(InputLabel, { htmlFor: "id", children: "Link to plaintext" }),
|
|
171
|
+
/* @__PURE__ */ jsx3(Input, { id: "url", name: "url", defaultValue: "" })
|
|
172
|
+
] }),
|
|
173
|
+
/* @__PURE__ */ jsx3(Button, { type: "submit", children: "Create" })
|
|
174
|
+
] }) });
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// src/ContentResource/PlaintextCreator/index.tsx
|
|
178
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
179
|
+
var plaintextCreator = {
|
|
180
|
+
id: "@manifest-editor/plaintext-creator",
|
|
181
|
+
create: createPlaintext,
|
|
182
|
+
label: "Plaintext",
|
|
183
|
+
summary: "Add link to an plaintext",
|
|
184
|
+
icon: /* @__PURE__ */ jsx4(TextFormatIcon, {}),
|
|
185
|
+
render(ctx) {
|
|
186
|
+
return /* @__PURE__ */ jsx4(CreatePlaintextForm, { ...ctx });
|
|
187
|
+
},
|
|
188
|
+
resourceType: "ContentResource",
|
|
189
|
+
resourceFields: ["label", "format"],
|
|
190
|
+
supports: {
|
|
191
|
+
parentFields: ["seeAlso", "rendering", "homepage"]
|
|
192
|
+
},
|
|
193
|
+
staticFields: {
|
|
194
|
+
format: "text/plain"
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
// src/ContentResource/WebPageCreator/create-web-page.tsx
|
|
199
|
+
import { LanguageFieldEditor as LanguageFieldEditor2, InputContainer as InputContainer2, InputLabel as InputLabel2, Input as Input2 } from "@manifest-editor/editors";
|
|
200
|
+
import { useState as useState2 } from "react";
|
|
201
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
202
|
+
async function createWebPage(data, ctx) {
|
|
203
|
+
return ctx.embed({
|
|
204
|
+
id: data.url,
|
|
205
|
+
type: "Text",
|
|
206
|
+
label: data.label,
|
|
207
|
+
format: "text/html"
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
function CreateWebPageForm(props) {
|
|
211
|
+
const [label, setLabel] = useState2({ en: [""] });
|
|
212
|
+
const onSubmit = (e) => {
|
|
213
|
+
e.preventDefault();
|
|
214
|
+
const data = new FormData(e.target);
|
|
215
|
+
const formData = Object.fromEntries(data.entries());
|
|
216
|
+
if (formData.url) {
|
|
217
|
+
props.runCreate({ url: formData.url, label });
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
return /* @__PURE__ */ jsx5(PaddedSidebarContainer, { children: /* @__PURE__ */ jsxs3("form", { onSubmit, children: [
|
|
221
|
+
/* @__PURE__ */ jsx5(
|
|
222
|
+
LanguageFieldEditor2,
|
|
223
|
+
{
|
|
224
|
+
focusId: "label",
|
|
225
|
+
label: "Label",
|
|
226
|
+
fields: label,
|
|
227
|
+
onSave: (e) => setLabel(e.toInternationalString())
|
|
228
|
+
}
|
|
229
|
+
),
|
|
230
|
+
/* @__PURE__ */ jsxs3(InputContainer2, { $wide: true, children: [
|
|
231
|
+
/* @__PURE__ */ jsx5(InputLabel2, { htmlFor: "id", children: "Link" }),
|
|
232
|
+
/* @__PURE__ */ jsx5(Input2, { id: "url", name: "url", defaultValue: "" })
|
|
233
|
+
] }),
|
|
234
|
+
/* @__PURE__ */ jsx5(Button, { type: "submit", children: "Create link" })
|
|
235
|
+
] }) });
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// ../ui/icons/LinkIcon.tsx
|
|
239
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
240
|
+
function LinkIcon() {
|
|
241
|
+
return /* @__PURE__ */ jsxs4("svg", { xmlns: "http://www.w3.org/2000/svg", height: "24px", viewBox: "0 0 24 24", width: "24px", fill: "#000000", children: [
|
|
242
|
+
/* @__PURE__ */ jsx6("path", { d: "M0 0h24v24H0z", fill: "none" }),
|
|
243
|
+
/* @__PURE__ */ jsx6("path", { d: "M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z" })
|
|
244
|
+
] });
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// src/ContentResource/WebPageCreator/index.tsx
|
|
248
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
249
|
+
var webPageCreator = {
|
|
250
|
+
id: "@manifest-editor/web-page-creator",
|
|
251
|
+
create: createWebPage,
|
|
252
|
+
label: "Web page",
|
|
253
|
+
summary: "Add link to an external web page",
|
|
254
|
+
icon: /* @__PURE__ */ jsx7(LinkIcon, {}),
|
|
255
|
+
render(ctx) {
|
|
256
|
+
return /* @__PURE__ */ jsx7(CreateWebPageForm, { ...ctx });
|
|
257
|
+
},
|
|
258
|
+
resourceType: "ContentResource",
|
|
259
|
+
resourceFields: ["label", "format"],
|
|
260
|
+
supports: {
|
|
261
|
+
parentFields: ["seeAlso", "rendering", "homepage"]
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
// src/ContentResource/HTMLBodyCreator/create-html-body.tsx
|
|
266
|
+
import { InputContainer as InputContainer3, InputLabel as InputLabel3, RichTextLanguageField } from "@manifest-editor/editors";
|
|
267
|
+
import { useConfig } from "@manifest-editor/shell";
|
|
268
|
+
import { useState as useState3 } from "react";
|
|
269
|
+
import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
270
|
+
async function createHtmlBody(data, ctx) {
|
|
271
|
+
return ctx.embed({
|
|
272
|
+
id: ctx.generateId(`html/${data.language}`),
|
|
273
|
+
language: data.language,
|
|
274
|
+
type: "TextualBody",
|
|
275
|
+
format: "text/html",
|
|
276
|
+
value: data.body || ""
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
function CreateHTMLBodyForm(props) {
|
|
280
|
+
const { i18n } = useConfig();
|
|
281
|
+
const [body, setBodyValue] = useState3("<p></p>");
|
|
282
|
+
const [language, setLang] = useState3(i18n.defaultLanguage);
|
|
283
|
+
const onSubmit = () => {
|
|
284
|
+
props.runCreate({
|
|
285
|
+
language,
|
|
286
|
+
body
|
|
287
|
+
});
|
|
288
|
+
};
|
|
289
|
+
return /* @__PURE__ */ jsxs5(PaddedSidebarContainer, { children: [
|
|
290
|
+
/* @__PURE__ */ jsxs5(InputContainer3, { children: [
|
|
291
|
+
/* @__PURE__ */ jsx8(InputLabel3, { children: "HTML Body" }),
|
|
292
|
+
/* @__PURE__ */ jsx8(
|
|
293
|
+
RichTextLanguageField,
|
|
294
|
+
{
|
|
295
|
+
value: body,
|
|
296
|
+
language,
|
|
297
|
+
onUpdateLanguage: (lng) => setLang(lng),
|
|
298
|
+
languages: i18n.availableLanguages,
|
|
299
|
+
onUpdate: (e) => setBodyValue(e)
|
|
300
|
+
}
|
|
301
|
+
)
|
|
302
|
+
] }),
|
|
303
|
+
/* @__PURE__ */ jsx8(Button, { onClick: () => onSubmit(), children: "Create" })
|
|
304
|
+
] });
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// src/ContentResource/HTMLBodyCreator/index.tsx
|
|
308
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
309
|
+
var htmlBodyCreator = {
|
|
310
|
+
id: "@manifest-editor/html-body-creator",
|
|
311
|
+
create: createHtmlBody,
|
|
312
|
+
label: "HTML Body",
|
|
313
|
+
summary: "Add HTML annotation body",
|
|
314
|
+
icon: /* @__PURE__ */ jsx9(TextFormatIcon, {}),
|
|
315
|
+
render(ctx) {
|
|
316
|
+
return /* @__PURE__ */ jsx9(CreateHTMLBodyForm, { ...ctx });
|
|
317
|
+
},
|
|
318
|
+
resourceType: "ContentResource",
|
|
319
|
+
resourceFields: ["id", "language", "type", "format", "value"],
|
|
320
|
+
supports: {
|
|
321
|
+
parentTypes: ["Annotation"],
|
|
322
|
+
parentFields: ["body"]
|
|
323
|
+
},
|
|
324
|
+
staticFields: {
|
|
325
|
+
type: "TextualBody",
|
|
326
|
+
format: "text/html"
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
// src/Annotation/HTMLAnnotation/create-html-annotation.tsx
|
|
331
|
+
import { useState as useState4 } from "react";
|
|
332
|
+
import { InputContainer as InputContainer4, InputLabel as InputLabel4, LanguageFieldEditor as LanguageFieldEditor3 } from "@manifest-editor/editors";
|
|
333
|
+
import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
334
|
+
async function createHtmlAnnotation(data, ctx) {
|
|
335
|
+
const annotation = {
|
|
336
|
+
id: ctx.generateId("annotation"),
|
|
337
|
+
type: "Annotation"
|
|
338
|
+
};
|
|
339
|
+
const targetType = ctx.options.targetType;
|
|
340
|
+
const languages = Object.keys(data.body);
|
|
341
|
+
const bodies = [];
|
|
342
|
+
for (const language of languages) {
|
|
343
|
+
const body = data.body[language].join("\n");
|
|
344
|
+
if (body) {
|
|
345
|
+
bodies.push(
|
|
346
|
+
await ctx.create(
|
|
347
|
+
"@manifest-editor/html-body-creator",
|
|
348
|
+
{
|
|
349
|
+
language,
|
|
350
|
+
body
|
|
351
|
+
},
|
|
352
|
+
{ parent: { resource: annotation, property: "items" } }
|
|
353
|
+
)
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
if (targetType === "Annotation") {
|
|
358
|
+
return ctx.embed({
|
|
359
|
+
...annotation,
|
|
360
|
+
motivation: data.motivation || ctx.options.initialData?.motivation || "painting",
|
|
361
|
+
body: bodies,
|
|
362
|
+
target: ctx.getTarget()
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
if (targetType === "Canvas") {
|
|
366
|
+
const canvasId = ctx.generateId("canvas");
|
|
367
|
+
const pageId = ctx.generateId("annotation-page", { id: canvasId, type: "Canvas" });
|
|
368
|
+
const annotationResource = ctx.embed({
|
|
369
|
+
...annotation,
|
|
370
|
+
motivation: "painting",
|
|
371
|
+
body: bodies,
|
|
372
|
+
target: { type: "SpecificResource", source: { id: canvasId, type: "Canvas" } }
|
|
373
|
+
});
|
|
374
|
+
const page = ctx.embed({
|
|
375
|
+
id: pageId,
|
|
376
|
+
type: "AnnotationPage",
|
|
377
|
+
items: [annotationResource]
|
|
378
|
+
});
|
|
379
|
+
return ctx.embed({
|
|
380
|
+
id: canvasId,
|
|
381
|
+
type: "Canvas",
|
|
382
|
+
label: data.label || { en: ["Untitled HTML canvas"] },
|
|
383
|
+
height: data.height || 1e3,
|
|
384
|
+
width: data.width || 1e3,
|
|
385
|
+
items: [page]
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
function CreateHTMLAnnotation(props) {
|
|
390
|
+
const [body, setBody] = useState4({ en: [""] });
|
|
391
|
+
const onSubmit = () => {
|
|
392
|
+
props.runCreate({
|
|
393
|
+
body
|
|
394
|
+
});
|
|
395
|
+
};
|
|
396
|
+
return /* @__PURE__ */ jsxs6(PaddedSidebarContainer, { children: [
|
|
397
|
+
/* @__PURE__ */ jsxs6(InputContainer4, { children: [
|
|
398
|
+
/* @__PURE__ */ jsx10(InputLabel4, { children: "HTML Body" }),
|
|
399
|
+
/* @__PURE__ */ jsx10(
|
|
400
|
+
LanguageFieldEditor3,
|
|
401
|
+
{
|
|
402
|
+
focusId: "html-content",
|
|
403
|
+
label: "HTML Content",
|
|
404
|
+
fields: body,
|
|
405
|
+
onSave: (e) => setBody(e.toInternationalString())
|
|
406
|
+
}
|
|
407
|
+
)
|
|
408
|
+
] }),
|
|
409
|
+
/* @__PURE__ */ jsx10(Button, { onClick: () => onSubmit(), children: "Create" })
|
|
410
|
+
] });
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// src/Annotation/HTMLAnnotation/index.tsx
|
|
414
|
+
import { HTMLIcon } from "@manifest-editor/components";
|
|
415
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
416
|
+
var htmlAnnotation = {
|
|
417
|
+
id: "@manifest-editor/html-annotation",
|
|
418
|
+
create: createHtmlAnnotation,
|
|
419
|
+
label: "HTML",
|
|
420
|
+
summary: "HTML annotation",
|
|
421
|
+
icon: /* @__PURE__ */ jsx11(HTMLIcon, {}),
|
|
422
|
+
render(ctx) {
|
|
423
|
+
return /* @__PURE__ */ jsx11(CreateHTMLAnnotation, { ...ctx });
|
|
424
|
+
},
|
|
425
|
+
resourceType: "Annotation",
|
|
426
|
+
resourceFields: ["id", "type", "motivation", "body", "target"],
|
|
427
|
+
additionalTypes: ["Canvas"],
|
|
428
|
+
supports: {
|
|
429
|
+
initialData: true,
|
|
430
|
+
parentTypes: ["AnnotationPage", "Manifest"],
|
|
431
|
+
parentFields: ["items"]
|
|
432
|
+
},
|
|
433
|
+
staticFields: {
|
|
434
|
+
type: "Annotation"
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
// ../ui/icons/ThumbnailStripIcon.tsx
|
|
439
|
+
import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
440
|
+
var ThumbnailStripIcon = () => /* @__PURE__ */ jsx12(
|
|
441
|
+
"svg",
|
|
442
|
+
{
|
|
443
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
444
|
+
height: "24px",
|
|
445
|
+
viewBox: "0 0 24 24",
|
|
446
|
+
width: "24px",
|
|
447
|
+
fill: "#000000",
|
|
448
|
+
transform: "scale(-1, 1)",
|
|
449
|
+
children: /* @__PURE__ */ jsxs7("g", { children: [
|
|
450
|
+
/* @__PURE__ */ jsx12("rect", { fill: "none", height: "24", width: "24" }),
|
|
451
|
+
/* @__PURE__ */ jsx12("path", { d: "M16,20H2V4h14V20z M18,8h4V4h-4V8z M18,20h4v-4h-4V20z M18,14h4v-4h-4V14z" })
|
|
452
|
+
] })
|
|
453
|
+
}
|
|
454
|
+
);
|
|
455
|
+
|
|
456
|
+
// src/AnnotationPage/EmptyAnnotationPage/index.tsx
|
|
457
|
+
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
458
|
+
var emptyAnnotationPage = {
|
|
459
|
+
id: "@manifest-editor/empty-annotation-page",
|
|
460
|
+
create: createEmptyAnnotationPage,
|
|
461
|
+
label: "Empty annotation page",
|
|
462
|
+
summary: "AnnotationPage with nothing",
|
|
463
|
+
icon: /* @__PURE__ */ jsx13(ThumbnailStripIcon, {}),
|
|
464
|
+
resourceType: "AnnotationPage",
|
|
465
|
+
resourceFields: ["id", "type", "items"],
|
|
466
|
+
supports: {
|
|
467
|
+
parentTypes: ["Manifest", "Canvas", "Range"],
|
|
468
|
+
parentFieldMap: {
|
|
469
|
+
Manifest: ["annotations"],
|
|
470
|
+
Canvas: ["items", "annotations"],
|
|
471
|
+
Range: ["annotations"]
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
};
|
|
475
|
+
async function createEmptyAnnotationPage(data, ctx) {
|
|
476
|
+
return ctx.embed({
|
|
477
|
+
id: ctx.generateId("annotations"),
|
|
478
|
+
type: "AnnotationPage",
|
|
479
|
+
items: []
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// src/ContentResource/YouTubeCreator/index.tsx
|
|
484
|
+
import { YouTubeIcon } from "@manifest-editor/components";
|
|
485
|
+
|
|
486
|
+
// src/ContentResource/YouTubeCreator/create-youtube-body.tsx
|
|
487
|
+
import { InputContainer as InputContainer5, InputLabel as InputLabel5, Input as Input3 } from "@manifest-editor/editors";
|
|
488
|
+
import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
489
|
+
var ytRegex = /^.*(?:(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/|shorts\/)|(?:(?:watch)?\?vi?=|&vi?=))([^#&?]*).*/;
|
|
490
|
+
function getYouTubeId(url) {
|
|
491
|
+
const id = (url || "").match(ytRegex);
|
|
492
|
+
return id ? id[1] : null;
|
|
493
|
+
}
|
|
494
|
+
async function createYoutubeBody(data, ctx) {
|
|
495
|
+
const id = getYouTubeId(data.youtubeUrl);
|
|
496
|
+
const body = ctx.embed({
|
|
497
|
+
id: `https://www.youtube.com/watch?v=${id}`,
|
|
498
|
+
type: "Video",
|
|
499
|
+
service: [
|
|
500
|
+
{
|
|
501
|
+
profile: "http://digirati.com/objectifier",
|
|
502
|
+
params: {
|
|
503
|
+
data: `https://www.youtube.com/embed/${id}`
|
|
504
|
+
}
|
|
505
|
+
},
|
|
506
|
+
{
|
|
507
|
+
id: `https://www.youtube.com/watch?v=${id}`,
|
|
508
|
+
profile: "https://www.youtube.com"
|
|
509
|
+
}
|
|
510
|
+
]
|
|
511
|
+
});
|
|
512
|
+
if (ctx.options.targetType === "Canvas") {
|
|
513
|
+
const canvasId = ctx.generateId("canvas");
|
|
514
|
+
const pageId = ctx.generateId("annotation-page", { id: canvasId, type: "Canvas" });
|
|
515
|
+
const annotation = await ctx.embed({
|
|
516
|
+
id: ctx.generateId("annotation", { id: pageId, type: "AnnotationPage" }),
|
|
517
|
+
type: "Annotation",
|
|
518
|
+
motivation: "painting",
|
|
519
|
+
body: [body],
|
|
520
|
+
target: { type: "SpecificResource", source: { id: canvasId, type: "Canvas" } }
|
|
521
|
+
});
|
|
522
|
+
const page = ctx.embed({
|
|
523
|
+
id: pageId,
|
|
524
|
+
type: "AnnotationPage",
|
|
525
|
+
items: [annotation]
|
|
526
|
+
});
|
|
527
|
+
return ctx.embed({
|
|
528
|
+
id: canvasId,
|
|
529
|
+
type: "Canvas",
|
|
530
|
+
label: data.label || { en: ["Untitled YouTube canvas"] },
|
|
531
|
+
height: data.height || 1e3,
|
|
532
|
+
width: data.width || 1e3,
|
|
533
|
+
duration: data.duration || 1,
|
|
534
|
+
items: [page]
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
if (ctx.options.targetType === "Annotation" || ctx.options.targetType === "Canvas") {
|
|
538
|
+
return ctx.embed({
|
|
539
|
+
id: ctx.generateId("annotation"),
|
|
540
|
+
type: "Annotation",
|
|
541
|
+
motivation: "painting",
|
|
542
|
+
body: [body],
|
|
543
|
+
target: ctx.getTarget()
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
return body;
|
|
547
|
+
}
|
|
548
|
+
function YouTubeForm(props) {
|
|
549
|
+
const onSubmit = (e) => {
|
|
550
|
+
e.preventDefault();
|
|
551
|
+
const data = new FormData(e.target);
|
|
552
|
+
const formData = Object.fromEntries(data.entries());
|
|
553
|
+
if (formData.youtubeUrl) {
|
|
554
|
+
props.runCreate({ youtubeUrl: formData.youtubeUrl });
|
|
555
|
+
}
|
|
556
|
+
};
|
|
557
|
+
return /* @__PURE__ */ jsx14(PaddedSidebarContainer, { children: /* @__PURE__ */ jsxs8("form", { onSubmit, children: [
|
|
558
|
+
/* @__PURE__ */ jsxs8(InputContainer5, { $wide: true, children: [
|
|
559
|
+
/* @__PURE__ */ jsx14(InputLabel5, { htmlFor: "id", children: "Link to YouTube" }),
|
|
560
|
+
/* @__PURE__ */ jsx14(Input3, { id: "youtubeUrl", name: "youtubeUrl", defaultValue: "" })
|
|
561
|
+
] }),
|
|
562
|
+
/* @__PURE__ */ jsx14(Button, { type: "submit", children: "Create" })
|
|
563
|
+
] }) });
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// src/ContentResource/YouTubeCreator/index.tsx
|
|
567
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
568
|
+
var youTubeBodyCreator = {
|
|
569
|
+
id: "@manifest-editor/youtube",
|
|
570
|
+
create: createYoutubeBody,
|
|
571
|
+
label: "YouTube",
|
|
572
|
+
summary: "Embed YouTube",
|
|
573
|
+
icon: /* @__PURE__ */ jsx15(YouTubeIcon, {}),
|
|
574
|
+
resourceType: "ContentResource",
|
|
575
|
+
additionalTypes: ["Canvas", "Annotation"],
|
|
576
|
+
resourceFields: ["id", "type", "service"],
|
|
577
|
+
render: (ctx) => /* @__PURE__ */ jsx15(YouTubeForm, { ...ctx }),
|
|
578
|
+
supports: {
|
|
579
|
+
parentTypes: ["Annotation", "Manifest", "AnnotationPage"],
|
|
580
|
+
parentFieldMap: {
|
|
581
|
+
Annotation: ["body"],
|
|
582
|
+
Manifest: ["items"],
|
|
583
|
+
AnnotationPage: ["items"]
|
|
584
|
+
}
|
|
585
|
+
},
|
|
586
|
+
staticFields: {
|
|
587
|
+
type: "Video"
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
|
|
591
|
+
// src/ContentResource/ImageUrlCreator/create-image-url.tsx
|
|
592
|
+
import { InputContainer as InputContainer6, InputLabel as InputLabel6, Input as Input4 } from "@manifest-editor/editors";
|
|
593
|
+
import { getImageDimensions, getFormat } from "@manifest-editor/shell";
|
|
594
|
+
import { jsx as jsx16, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
595
|
+
async function createImageUrl(data, ctx) {
|
|
596
|
+
if (!data.height || !data.width) {
|
|
597
|
+
const dimensions = await getImageDimensions(data.url);
|
|
598
|
+
if (dimensions) {
|
|
599
|
+
data.height = dimensions.height;
|
|
600
|
+
data.width = dimensions.width;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
return ctx.embed({
|
|
604
|
+
id: data.url,
|
|
605
|
+
type: "Image",
|
|
606
|
+
format: data.format || await getFormat(data.url),
|
|
607
|
+
height: data.height,
|
|
608
|
+
width: data.width,
|
|
609
|
+
service: data.service ? Array.isArray(data.service) ? data.service : [data.service] : void 0
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
function CreateImageUrlForm(props) {
|
|
613
|
+
const onSubmit = (e) => {
|
|
614
|
+
e.preventDefault();
|
|
615
|
+
const data = new FormData(e.target);
|
|
616
|
+
const formData = Object.fromEntries(data.entries());
|
|
617
|
+
if (formData.url) {
|
|
618
|
+
props.runCreate({ url: formData.url });
|
|
619
|
+
}
|
|
620
|
+
};
|
|
621
|
+
return /* @__PURE__ */ jsx16(PaddedSidebarContainer, { children: /* @__PURE__ */ jsxs9("form", { onSubmit, children: [
|
|
622
|
+
/* @__PURE__ */ jsxs9(InputContainer6, { $wide: true, children: [
|
|
623
|
+
/* @__PURE__ */ jsx16(InputLabel6, { htmlFor: "id", children: "Link to Image" }),
|
|
624
|
+
/* @__PURE__ */ jsx16(Input4, { id: "url", name: "url", defaultValue: "" })
|
|
625
|
+
] }),
|
|
626
|
+
/* @__PURE__ */ jsx16(Button, { type: "submit", children: "Create" })
|
|
627
|
+
] }) });
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// src/ContentResource/ImageUrlCreator/index.tsx
|
|
631
|
+
import { AddImageIcon } from "@manifest-editor/components";
|
|
632
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
633
|
+
var imageUrlCreator = {
|
|
634
|
+
id: "@manifest-editor/image-url-creator",
|
|
635
|
+
create: createImageUrl,
|
|
636
|
+
label: "Image",
|
|
637
|
+
summary: "Image from a URL",
|
|
638
|
+
icon: /* @__PURE__ */ jsx17(AddImageIcon, {}),
|
|
639
|
+
render(ctx) {
|
|
640
|
+
return /* @__PURE__ */ jsx17(CreateImageUrlForm, { ...ctx });
|
|
641
|
+
},
|
|
642
|
+
resourceType: "ContentResource",
|
|
643
|
+
resourceFields: ["format"],
|
|
644
|
+
supports: {
|
|
645
|
+
parentFields: ["logo", "body", "thumbnail"]
|
|
646
|
+
},
|
|
647
|
+
staticFields: {
|
|
648
|
+
type: "Image"
|
|
649
|
+
}
|
|
650
|
+
};
|
|
651
|
+
|
|
652
|
+
// src/ContentResource/ImageServiceCreator/create-image-service.tsx
|
|
653
|
+
import {
|
|
654
|
+
imageServiceRequestToString,
|
|
655
|
+
createImageServiceRequest,
|
|
656
|
+
canonicalServiceUrl
|
|
657
|
+
} from "@iiif/parser/image-3";
|
|
658
|
+
import { InputContainer as InputContainer7, InputLabel as InputLabel7, Input as Input5 } from "@manifest-editor/editors";
|
|
659
|
+
import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
660
|
+
async function createImageServer(data, ctx) {
|
|
661
|
+
const request = createImageServiceRequest(data.service);
|
|
662
|
+
const imageId = imageServiceRequestToString({
|
|
663
|
+
identifier: request.identifier,
|
|
664
|
+
server: request.server,
|
|
665
|
+
scheme: request.scheme,
|
|
666
|
+
type: "image",
|
|
667
|
+
size: {
|
|
668
|
+
max: !data.size?.width && !data.size?.height,
|
|
669
|
+
confined: false,
|
|
670
|
+
upscaled: false,
|
|
671
|
+
...data.size || {}
|
|
672
|
+
},
|
|
673
|
+
format: "jpg",
|
|
674
|
+
// This isn't how it should be modelled, always full,
|
|
675
|
+
// region: data.selector ? data.selector : { full: true },
|
|
676
|
+
region: { full: true },
|
|
677
|
+
rotation: { angle: 0 },
|
|
678
|
+
quality: "default",
|
|
679
|
+
prefix: request.prefix,
|
|
680
|
+
originalPath: request.originalPath
|
|
681
|
+
});
|
|
682
|
+
const resource = ctx.embed({
|
|
683
|
+
id: imageId,
|
|
684
|
+
type: "Image",
|
|
685
|
+
format: data.format || "image/jpeg",
|
|
686
|
+
height: data.height || data.service.height,
|
|
687
|
+
width: data.width || data.service.width,
|
|
688
|
+
service: data.embedService === false ? void 0 : [data.service]
|
|
689
|
+
});
|
|
690
|
+
return resource;
|
|
691
|
+
}
|
|
692
|
+
function CreateImageServerForm(props) {
|
|
693
|
+
const onSubmit = (e) => {
|
|
694
|
+
e.preventDefault();
|
|
695
|
+
const data = new FormData(e.target);
|
|
696
|
+
const formData = Object.fromEntries(data.entries());
|
|
697
|
+
const url = formData.url;
|
|
698
|
+
if (url) {
|
|
699
|
+
const canon = canonicalServiceUrl(url);
|
|
700
|
+
fetch(canon).then((r) => r.json()).then((service) => {
|
|
701
|
+
if (service["@id"]) {
|
|
702
|
+
service.id = service["@id"];
|
|
703
|
+
}
|
|
704
|
+
if (service["@type"]) {
|
|
705
|
+
service.type = service["@type"];
|
|
706
|
+
}
|
|
707
|
+
props.runCreate({ url: formData.url, service });
|
|
708
|
+
});
|
|
709
|
+
}
|
|
710
|
+
};
|
|
711
|
+
return /* @__PURE__ */ jsx18(PaddedSidebarContainer, { children: /* @__PURE__ */ jsxs10("form", { onSubmit, children: [
|
|
712
|
+
/* @__PURE__ */ jsxs10(InputContainer7, { $wide: true, children: [
|
|
713
|
+
/* @__PURE__ */ jsx18(InputLabel7, { htmlFor: "id", children: "Link to image service" }),
|
|
714
|
+
/* @__PURE__ */ jsx18(Input5, { id: "url", name: "url", defaultValue: "" })
|
|
715
|
+
] }),
|
|
716
|
+
/* @__PURE__ */ jsx18(Button, { type: "submit", children: "Create" })
|
|
717
|
+
] }) });
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
// src/ContentResource/ImageServiceCreator/index.tsx
|
|
721
|
+
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
722
|
+
var imageServiceCreator = {
|
|
723
|
+
id: "@manifest-editor/image-service-creator",
|
|
724
|
+
create: createImageServer,
|
|
725
|
+
label: "Image Service",
|
|
726
|
+
summary: "Add an image from Image Service",
|
|
727
|
+
icon: /* @__PURE__ */ jsx19(TextFormatIcon, {}),
|
|
728
|
+
render(ctx) {
|
|
729
|
+
return /* @__PURE__ */ jsx19(CreateImageServerForm, { ...ctx });
|
|
730
|
+
},
|
|
731
|
+
resourceType: "ContentResource",
|
|
732
|
+
resourceFields: ["id", "type", "height", "width", "format", "service"],
|
|
733
|
+
supports: {
|
|
734
|
+
parentFields: ["logo", "body", "thumbnail"]
|
|
735
|
+
},
|
|
736
|
+
staticFields: {
|
|
737
|
+
type: "Image"
|
|
738
|
+
}
|
|
739
|
+
};
|
|
740
|
+
|
|
741
|
+
// src/side-effects/reposition-multiple-images.ts
|
|
742
|
+
import { isImageService } from "@iiif/parser/image-3";
|
|
743
|
+
import { EditorInstance } from "@manifest-editor/editor-api";
|
|
744
|
+
import { centerRectangles } from "@manifest-editor/editors";
|
|
745
|
+
var repositionMultipleImages = {
|
|
746
|
+
canvasInteraction: true,
|
|
747
|
+
spatial: true,
|
|
748
|
+
async run(result, { vault, options }) {
|
|
749
|
+
if (result && result.type === "Annotation" && options.targetType === "Annotation") {
|
|
750
|
+
const fullAnno = vault.get(result);
|
|
751
|
+
const target = fullAnno.target;
|
|
752
|
+
if (!(target && target.source?.type === "Canvas")) {
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
755
|
+
const canvasRef = target.source;
|
|
756
|
+
const canvas = vault.get(canvasRef);
|
|
757
|
+
if (!canvas.items) {
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
const annoPage = vault.get(canvas.items[0]);
|
|
761
|
+
if (!annoPage) {
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
if (annoPage.items.length < 2) {
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
767
|
+
const bodies = vault.get(fullAnno.body);
|
|
768
|
+
const body = bodies[0];
|
|
769
|
+
const selector = fullAnno.body[0]?.selector;
|
|
770
|
+
const serviceList = body.service || [];
|
|
771
|
+
const imageService = serviceList.find((s) => isImageService(s));
|
|
772
|
+
if (imageService) {
|
|
773
|
+
if (imageService.width && imageService.height) {
|
|
774
|
+
if (imageService.width !== body.width) {
|
|
775
|
+
vault.modifyEntityField({ id: body.id, type: "ContentResource" }, "width", imageService.width);
|
|
776
|
+
}
|
|
777
|
+
if (imageService.height !== body.height) {
|
|
778
|
+
vault.modifyEntityField({ id: body.id, type: "ContentResource" }, "height", imageService.height);
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
let width = imageService?.width || body.width;
|
|
783
|
+
let height = imageService?.height || body.height;
|
|
784
|
+
if (selector) {
|
|
785
|
+
if ((selector.type === "iiif:ImageApiSelector" || selector.type === "ImageApiSelector") && selector.region) {
|
|
786
|
+
const [x, y, width_, height_] = selector.region.split(",");
|
|
787
|
+
width = Number(width_) || width;
|
|
788
|
+
height = Number(height_) || height;
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
const editor = new EditorInstance({ vault, reference: result });
|
|
792
|
+
const imagePosition = centerRectangles(
|
|
793
|
+
canvas,
|
|
794
|
+
{
|
|
795
|
+
width,
|
|
796
|
+
height
|
|
797
|
+
},
|
|
798
|
+
0.6
|
|
799
|
+
);
|
|
800
|
+
editor.annotation.target.setPosition(imagePosition);
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
};
|
|
804
|
+
|
|
805
|
+
// src/side-effects/resize-resource-to-empty-canvas.ts
|
|
806
|
+
import { EditorInstance as EditorInstance2 } from "@manifest-editor/editor-api";
|
|
807
|
+
var resizeResourceToEmptyCanvas = {
|
|
808
|
+
canvasInteraction: true,
|
|
809
|
+
spatial: true,
|
|
810
|
+
async run(result, { vault, options }) {
|
|
811
|
+
if (result && result.type === "Annotation" && options.targetType === "Annotation") {
|
|
812
|
+
const fullAnno = vault.get(result);
|
|
813
|
+
const target = fullAnno.target;
|
|
814
|
+
if (!(target && target.source?.type === "Canvas")) {
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
const canvasRef = target.source;
|
|
818
|
+
const canvas = vault.get(canvasRef);
|
|
819
|
+
if (!canvas.items) {
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
const annoPage = vault.get(canvas.items[0]);
|
|
823
|
+
if (!annoPage) {
|
|
824
|
+
return;
|
|
825
|
+
}
|
|
826
|
+
if (annoPage.items.length > 1) {
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
829
|
+
const bodies = vault.get(fullAnno.body);
|
|
830
|
+
if (bodies.length !== 1) {
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
const body = bodies[0];
|
|
834
|
+
const selector = fullAnno.body[0]?.selector;
|
|
835
|
+
const service = (body.service || [])[0];
|
|
836
|
+
let width = service?.width || body.width;
|
|
837
|
+
let height = service?.height || body.height;
|
|
838
|
+
const duration = body.duration || service?.duration;
|
|
839
|
+
if (selector) {
|
|
840
|
+
if ((selector.type === "iiif:ImageApiSelector" || selector.type === "ImageApiSelector") && selector.region) {
|
|
841
|
+
const [x, y, width_, height_] = selector.region.split(",");
|
|
842
|
+
width = Number(width_) || width;
|
|
843
|
+
height = Number(height_) || height;
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
const editor = new EditorInstance2({ vault, reference: canvasRef });
|
|
847
|
+
vault.batch(() => {
|
|
848
|
+
if (typeof width !== "undefined") {
|
|
849
|
+
editor.technical.width.set(width);
|
|
850
|
+
}
|
|
851
|
+
if (typeof height !== "undefined") {
|
|
852
|
+
editor.technical.height.set(height);
|
|
853
|
+
}
|
|
854
|
+
if (typeof duration !== "undefined") {
|
|
855
|
+
editor.technical.duration.set(duration);
|
|
856
|
+
}
|
|
857
|
+
});
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
};
|
|
861
|
+
|
|
862
|
+
// src/side-effects/resize-to-fit-service.ts
|
|
863
|
+
import { isImageService as isImageService2 } from "@atlas-viewer/iiif-image-api";
|
|
864
|
+
var resizeToFitService = {
|
|
865
|
+
canvasInteraction: true,
|
|
866
|
+
spatial: true,
|
|
867
|
+
async run(result, { vault, options }) {
|
|
868
|
+
if (result && result.type === "Annotation" && options.targetType === "Annotation") {
|
|
869
|
+
const fullAnno = vault.get(result);
|
|
870
|
+
const target = fullAnno.target;
|
|
871
|
+
if (!(target && target.source?.type === "Canvas")) {
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
874
|
+
const canvasRef = target.source;
|
|
875
|
+
const canvas = vault.get(canvasRef);
|
|
876
|
+
if (!canvas.items) {
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
879
|
+
const annoPage = vault.get(canvas.items[0]);
|
|
880
|
+
if (!annoPage) {
|
|
881
|
+
return;
|
|
882
|
+
}
|
|
883
|
+
const resourceBody = Array.isArray(fullAnno.body) ? fullAnno.body[0] : fullAnno.body;
|
|
884
|
+
if (resourceBody.type === "SpecificResource" && resourceBody.selector) {
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
const bodies = vault.get(fullAnno.body);
|
|
888
|
+
const body = bodies[0];
|
|
889
|
+
const serviceList = body.service || [];
|
|
890
|
+
const imageService = serviceList.find((s) => isImageService2(s));
|
|
891
|
+
if (imageService) {
|
|
892
|
+
if (imageService.width && imageService.height) {
|
|
893
|
+
if (imageService.width !== body.width) {
|
|
894
|
+
vault.modifyEntityField({ id: body.id, type: "ContentResource" }, "width", imageService.width);
|
|
895
|
+
}
|
|
896
|
+
if (imageService.height !== body.height) {
|
|
897
|
+
vault.modifyEntityField({ id: body.id, type: "ContentResource" }, "height", imageService.height);
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
};
|
|
904
|
+
|
|
905
|
+
// src/Annotation/ImageServiceAnnotation/create-service-annotation.tsx
|
|
906
|
+
import { jsx as jsx20 } from "react/jsx-runtime";
|
|
907
|
+
async function createImageServiceAnnotation(data, ctx) {
|
|
908
|
+
const annotation = {
|
|
909
|
+
id: ctx.generateId("annotation"),
|
|
910
|
+
type: "Annotation"
|
|
911
|
+
};
|
|
912
|
+
const targetType = ctx.options.targetType;
|
|
913
|
+
const resource = await ctx.create("@manifest-editor/image-service-creator", data, {
|
|
914
|
+
parent: { resource: annotation, property: "body" }
|
|
915
|
+
});
|
|
916
|
+
if (targetType === "Annotation") {
|
|
917
|
+
return {
|
|
918
|
+
...annotation,
|
|
919
|
+
body: [resource],
|
|
920
|
+
motivation: data.motivation || "painting",
|
|
921
|
+
target: ctx.getTarget()
|
|
922
|
+
};
|
|
923
|
+
}
|
|
924
|
+
if (targetType === "Canvas") {
|
|
925
|
+
const canvasId = ctx.generateId("canvas");
|
|
926
|
+
const pageId = ctx.generateId("annotation-page", { id: canvasId, type: "Canvas" });
|
|
927
|
+
const annotationResource = ctx.embed({
|
|
928
|
+
...annotation,
|
|
929
|
+
motivation: "painting",
|
|
930
|
+
body: [resource],
|
|
931
|
+
target: { type: "SpecificResource", source: { id: canvasId, type: "Canvas" } }
|
|
932
|
+
});
|
|
933
|
+
const page = ctx.embed({
|
|
934
|
+
id: pageId,
|
|
935
|
+
type: "AnnotationPage",
|
|
936
|
+
items: [annotationResource]
|
|
937
|
+
});
|
|
938
|
+
return ctx.embed({
|
|
939
|
+
id: canvasId,
|
|
940
|
+
type: "Canvas",
|
|
941
|
+
label: data.label || { en: ["Untitled canvas"] },
|
|
942
|
+
height: resource.resource.height || 1e3,
|
|
943
|
+
width: resource.resource.width || 1e3,
|
|
944
|
+
items: [page]
|
|
945
|
+
});
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
function CreateImageServiceAnnotationForm(props) {
|
|
949
|
+
return /* @__PURE__ */ jsx20(CreateImageServerForm, { ...props });
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
// src/Annotation/ImageServiceAnnotation/index.tsx
|
|
953
|
+
import { IIIFLogo } from "@manifest-editor/components";
|
|
954
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
955
|
+
var imageServiceAnnotation = {
|
|
956
|
+
id: "@manifest-editor/image-service-annotation",
|
|
957
|
+
create: createImageServiceAnnotation,
|
|
958
|
+
label: "IIIF Image",
|
|
959
|
+
dependencies: ["@manifest-editor/image-service-creator"],
|
|
960
|
+
summary: "IIIF Image service",
|
|
961
|
+
icon: /* @__PURE__ */ jsx21(IIIFLogo, { style: { padding: 10 } }),
|
|
962
|
+
render(ctx) {
|
|
963
|
+
return /* @__PURE__ */ jsx21(CreateImageServiceAnnotationForm, { ...ctx });
|
|
964
|
+
},
|
|
965
|
+
resourceType: "Annotation",
|
|
966
|
+
resourceFields: ["id", "type", "motivation", "body", "target"],
|
|
967
|
+
additionalTypes: ["Canvas"],
|
|
968
|
+
supports: {
|
|
969
|
+
parentTypes: ["AnnotationPage", "Manifest"],
|
|
970
|
+
parentFields: ["items"]
|
|
971
|
+
},
|
|
972
|
+
sideEffects: [resizeToFitService, resizeResourceToEmptyCanvas, repositionMultipleImages],
|
|
973
|
+
staticFields: {
|
|
974
|
+
type: "Annotation"
|
|
975
|
+
}
|
|
976
|
+
};
|
|
977
|
+
|
|
978
|
+
// src/Annotation/NoBodyAnnotation/index.tsx
|
|
979
|
+
import { EmptyCanvasIcon as EmptyCanvasIcon2 } from "@manifest-editor/components";
|
|
980
|
+
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
981
|
+
var noBodyAnnotation = {
|
|
982
|
+
id: "@manifest-editor/no-body-annotation",
|
|
983
|
+
create: createNoBodyAnnotation,
|
|
984
|
+
label: "Annotation without body",
|
|
985
|
+
summary: "Add an annotation that only has motivation and target",
|
|
986
|
+
icon: /* @__PURE__ */ jsx22(EmptyCanvasIcon2, {}),
|
|
987
|
+
resourceType: "Annotation",
|
|
988
|
+
resourceFields: ["id", "type", "motivation", "target"],
|
|
989
|
+
supports: {
|
|
990
|
+
initialData: true,
|
|
991
|
+
parentTypes: ["AnnotationPage"],
|
|
992
|
+
parentFields: ["items"],
|
|
993
|
+
disallowPainting: true
|
|
994
|
+
},
|
|
995
|
+
sideEffects: [],
|
|
996
|
+
staticFields: {
|
|
997
|
+
type: "Annotation"
|
|
998
|
+
}
|
|
999
|
+
};
|
|
1000
|
+
function createNoBodyAnnotation(data, ctx) {
|
|
1001
|
+
return ctx.embed({
|
|
1002
|
+
id: ctx.generateId("annotation"),
|
|
1003
|
+
type: "Annotation",
|
|
1004
|
+
label: data?.label,
|
|
1005
|
+
motivation: data.motivation || ctx.options.initialData?.motivation || "highlighting",
|
|
1006
|
+
target: ctx.getTarget()
|
|
1007
|
+
});
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
// src/ContentResource/IIIFBrowserCreator/iiif-browser-creator.tsx
|
|
1011
|
+
import { normaliseContentState, parseContentState } from "@iiif/helpers";
|
|
1012
|
+
import { lazy } from "react";
|
|
1013
|
+
|
|
1014
|
+
// ../../node_modules/.pnpm/tiny-invariant@1.3.3/node_modules/tiny-invariant/dist/esm/tiny-invariant.js
|
|
1015
|
+
var isProduction = false;
|
|
1016
|
+
var prefix = "Invariant failed";
|
|
1017
|
+
function invariant(condition, message) {
|
|
1018
|
+
if (condition) {
|
|
1019
|
+
return;
|
|
1020
|
+
}
|
|
1021
|
+
if (isProduction) {
|
|
1022
|
+
throw new Error(prefix);
|
|
1023
|
+
}
|
|
1024
|
+
var provided = typeof message === "function" ? message() : message;
|
|
1025
|
+
var value = provided ? "".concat(prefix, ": ").concat(provided) : prefix;
|
|
1026
|
+
throw new Error(value);
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
// src/ContentResource/IIIFBrowserCreator/iiif-browser-creator.tsx
|
|
1030
|
+
async function createFromIIIFBrowserOutput(data, ctx) {
|
|
1031
|
+
const targetType = ctx.options.targetType;
|
|
1032
|
+
if (Array.isArray(data.output)) {
|
|
1033
|
+
throw new Error("Multiple items not yet supported");
|
|
1034
|
+
}
|
|
1035
|
+
const contentState = normaliseContentState(
|
|
1036
|
+
typeof data.output === "string" ? parseContentState(data.output) : data.output
|
|
1037
|
+
);
|
|
1038
|
+
if (!contentState.target || contentState.target.length === 0) {
|
|
1039
|
+
throw new Error("No target found in content state");
|
|
1040
|
+
}
|
|
1041
|
+
const target = contentState.target[0];
|
|
1042
|
+
const type = target.source.type;
|
|
1043
|
+
const previewVault = ctx.getPreviewVault();
|
|
1044
|
+
if (targetType === "Canvas" || targetType === "Annotation") {
|
|
1045
|
+
if (type === "Canvas") {
|
|
1046
|
+
const canvasId = target.source.id;
|
|
1047
|
+
const manifestId = target.source.partOf?.find((t) => t.type === "Manifest");
|
|
1048
|
+
invariant(manifestId, "Could not load external resource without partOf");
|
|
1049
|
+
const manifest = await previewVault.loadManifest(manifestId);
|
|
1050
|
+
invariant(manifest, "Manifest not found");
|
|
1051
|
+
const canvasRef = manifest.items.find((item) => item.id === canvasId);
|
|
1052
|
+
invariant(canvasRef, "Canvas not found");
|
|
1053
|
+
const canvas = previewVault.get(canvasRef);
|
|
1054
|
+
if (targetType === "Canvas") {
|
|
1055
|
+
return ctx.embed(previewVault.toPresentation3(canvas));
|
|
1056
|
+
}
|
|
1057
|
+
const annotationPage = previewVault.get(canvas.items[0]);
|
|
1058
|
+
const annotation = previewVault.get(annotationPage.items[0]);
|
|
1059
|
+
if (targetType === "Annotation") {
|
|
1060
|
+
const fullAnnotation = previewVault.toPresentation3(annotation);
|
|
1061
|
+
if (fullAnnotation && fullAnnotation?.body?.service) {
|
|
1062
|
+
const width = fullAnnotation?.body.width;
|
|
1063
|
+
const height = fullAnnotation?.body.height;
|
|
1064
|
+
const service = Array.isArray(fullAnnotation?.body?.service) ? fullAnnotation?.body?.service[0] : fullAnnotation?.body?.service;
|
|
1065
|
+
if (!service.width || !service.height) {
|
|
1066
|
+
service.width = width;
|
|
1067
|
+
service.height = height;
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
if (target.selector && target.selector.type === "BoxSelector") {
|
|
1071
|
+
const selector = {
|
|
1072
|
+
"@context": "http://iiif.io/api/annex/openannotation/context.json",
|
|
1073
|
+
type: "iiif:ImageApiSelector",
|
|
1074
|
+
region: [
|
|
1075
|
+
~~target.selector.spatial.x,
|
|
1076
|
+
~~target.selector.spatial.y,
|
|
1077
|
+
~~target.selector.spatial.width,
|
|
1078
|
+
~~target.selector.spatial.height
|
|
1079
|
+
].join(",")
|
|
1080
|
+
};
|
|
1081
|
+
fullAnnotation.body = {
|
|
1082
|
+
id: ctx.generateId("SpecificResource", annotation),
|
|
1083
|
+
type: "SpecificResource",
|
|
1084
|
+
source: fullAnnotation.body,
|
|
1085
|
+
selector
|
|
1086
|
+
};
|
|
1087
|
+
return ctx.embed({
|
|
1088
|
+
...fullAnnotation,
|
|
1089
|
+
target: ctx.getTarget()
|
|
1090
|
+
});
|
|
1091
|
+
}
|
|
1092
|
+
return ctx.embed({
|
|
1093
|
+
...previewVault.toPresentation3(annotation),
|
|
1094
|
+
target: ctx.getTarget()
|
|
1095
|
+
});
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
throw new Error("Not yet supported.");
|
|
1100
|
+
}
|
|
1101
|
+
var IIIFBrowserCreatorForm = lazy(() => import("./iiif-browser-form.lazy-PL3WMLU5.js"));
|
|
1102
|
+
|
|
1103
|
+
// src/ContentResource/IIIFBrowserCreator/index.tsx
|
|
1104
|
+
import { IIIFBrowserIcon } from "@manifest-editor/components";
|
|
1105
|
+
import { jsx as jsx23 } from "react/jsx-runtime";
|
|
1106
|
+
var iiifBrowserCreator = {
|
|
1107
|
+
id: "@manifest-editor/iiif-browser-creator",
|
|
1108
|
+
create: createFromIIIFBrowserOutput,
|
|
1109
|
+
label: "IIIF Browser",
|
|
1110
|
+
summary: "Browse IIIF Resources",
|
|
1111
|
+
icon: /* @__PURE__ */ jsx23(IIIFBrowserIcon, {}),
|
|
1112
|
+
render(ctx) {
|
|
1113
|
+
return /* @__PURE__ */ jsx23(IIIFBrowserCreatorForm, { ...ctx });
|
|
1114
|
+
},
|
|
1115
|
+
resourceType: "ContentResource",
|
|
1116
|
+
resourceFields: ["id", "language", "type", "format", "value"],
|
|
1117
|
+
additionalTypes: ["Annotation", "Canvas"],
|
|
1118
|
+
supports: {
|
|
1119
|
+
parentTypes: ["Annotation", "Manifest", "AnnotationPage"],
|
|
1120
|
+
parentFieldMap: {
|
|
1121
|
+
Annotation: ["body"],
|
|
1122
|
+
Manifest: ["items"],
|
|
1123
|
+
AnnotationPage: ["items"]
|
|
1124
|
+
}
|
|
1125
|
+
},
|
|
1126
|
+
sideEffects: [resizeToFitService, resizeResourceToEmptyCanvas, repositionMultipleImages],
|
|
1127
|
+
staticFields: {}
|
|
1128
|
+
};
|
|
1129
|
+
|
|
1130
|
+
// src/Canvas/InternalCanvas/index.tsx
|
|
1131
|
+
import { useManifest, useVault } from "react-iiif-vault";
|
|
1132
|
+
import { IIIFExplorer } from "@manifest-editor/iiif-browser";
|
|
1133
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
1134
|
+
var internalCanvas = {
|
|
1135
|
+
id: "@manifest-editor/internal-canvas",
|
|
1136
|
+
create: createInternalCanvas,
|
|
1137
|
+
label: "Internal canvas link",
|
|
1138
|
+
summary: "Canvas from the same manifest",
|
|
1139
|
+
icon: /* @__PURE__ */ jsx24(ThumbnailStripIcon, {}),
|
|
1140
|
+
resourceType: "Canvas",
|
|
1141
|
+
resourceFields: ["id", "type", "label"],
|
|
1142
|
+
supports: {
|
|
1143
|
+
parentTypes: ["Manifest"],
|
|
1144
|
+
parentFields: ["start"]
|
|
1145
|
+
},
|
|
1146
|
+
render: (ctx) => /* @__PURE__ */ jsx24(InternalCanvas, { ...ctx })
|
|
1147
|
+
};
|
|
1148
|
+
function InternalCanvas(props) {
|
|
1149
|
+
const manifest = useManifest();
|
|
1150
|
+
const vault = useVault();
|
|
1151
|
+
invariant(manifest, "Manifest is not loaded");
|
|
1152
|
+
return /* @__PURE__ */ jsx24(
|
|
1153
|
+
IIIFExplorer,
|
|
1154
|
+
{
|
|
1155
|
+
vault,
|
|
1156
|
+
entry: manifest,
|
|
1157
|
+
window: false,
|
|
1158
|
+
hideHeader: true,
|
|
1159
|
+
hideBack: true,
|
|
1160
|
+
output: { type: "url" },
|
|
1161
|
+
outputTargets: [
|
|
1162
|
+
{
|
|
1163
|
+
type: "callback",
|
|
1164
|
+
label: "Select canvas",
|
|
1165
|
+
cb: (url) => {
|
|
1166
|
+
props.runCreate({ id: url });
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
],
|
|
1170
|
+
outputTypes: ["Canvas"]
|
|
1171
|
+
}
|
|
1172
|
+
);
|
|
1173
|
+
}
|
|
1174
|
+
async function createInternalCanvas(data, ctx) {
|
|
1175
|
+
return ctx.embed({ id: data.id, type: "Canvas" });
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
// src/Annotation/ImageUrlAnnotation/create-image-url-annotation.tsx
|
|
1179
|
+
import { jsx as jsx25 } from "react/jsx-runtime";
|
|
1180
|
+
async function createImageUrlAnnotation(data, ctx) {
|
|
1181
|
+
const annotation = {
|
|
1182
|
+
id: ctx.generateId("annotation"),
|
|
1183
|
+
type: "Annotation"
|
|
1184
|
+
};
|
|
1185
|
+
const targetType = ctx.options.targetType;
|
|
1186
|
+
const resource = await ctx.create("@manifest-editor/image-url-creator", data, {
|
|
1187
|
+
parent: { resource: annotation, property: "body" }
|
|
1188
|
+
});
|
|
1189
|
+
if (targetType === "Annotation") {
|
|
1190
|
+
return {
|
|
1191
|
+
...annotation,
|
|
1192
|
+
body: [resource],
|
|
1193
|
+
motivation: data.motivation || "painting",
|
|
1194
|
+
target: ctx.getTarget()
|
|
1195
|
+
};
|
|
1196
|
+
}
|
|
1197
|
+
if (targetType === "Canvas") {
|
|
1198
|
+
const canvasId = ctx.generateId("canvas");
|
|
1199
|
+
const pageId = ctx.generateId("annotation-page", { id: canvasId, type: "Canvas" });
|
|
1200
|
+
const annotationResource = ctx.embed({
|
|
1201
|
+
...annotation,
|
|
1202
|
+
motivation: "painting",
|
|
1203
|
+
body: [resource],
|
|
1204
|
+
target: { type: "SpecificResource", source: { id: canvasId, type: "Canvas" } }
|
|
1205
|
+
});
|
|
1206
|
+
const page = ctx.embed({
|
|
1207
|
+
id: pageId,
|
|
1208
|
+
type: "AnnotationPage",
|
|
1209
|
+
items: [annotationResource]
|
|
1210
|
+
});
|
|
1211
|
+
return ctx.embed({
|
|
1212
|
+
id: canvasId,
|
|
1213
|
+
type: "Canvas",
|
|
1214
|
+
label: data.label || { en: ["Untitled canvas"] },
|
|
1215
|
+
height: resource.resource.height || 1e3,
|
|
1216
|
+
width: resource.resource.width || 1e3,
|
|
1217
|
+
items: [page]
|
|
1218
|
+
});
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
function CreateImageUrlAnnotationForm(props) {
|
|
1222
|
+
return /* @__PURE__ */ jsx25(CreateImageUrlForm, { ...props });
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
// src/Annotation/ImageUrlAnnotation/index.tsx
|
|
1226
|
+
import { AddImageIcon as AddImageIcon2 } from "@manifest-editor/components";
|
|
1227
|
+
import { jsx as jsx26 } from "react/jsx-runtime";
|
|
1228
|
+
var imageUrlAnnotation = {
|
|
1229
|
+
id: "@manifest-editor/image-url-annotation",
|
|
1230
|
+
create: createImageUrlAnnotation,
|
|
1231
|
+
label: "Image",
|
|
1232
|
+
dependencies: ["@manifest-editor/image-url-creator"],
|
|
1233
|
+
summary: "Image from URL",
|
|
1234
|
+
icon: /* @__PURE__ */ jsx26(AddImageIcon2, {}),
|
|
1235
|
+
render(ctx) {
|
|
1236
|
+
return /* @__PURE__ */ jsx26(CreateImageUrlAnnotationForm, { ...ctx });
|
|
1237
|
+
},
|
|
1238
|
+
resourceType: "Annotation",
|
|
1239
|
+
resourceFields: ["id", "type", "motivation", "body", "target"],
|
|
1240
|
+
additionalTypes: ["Canvas"],
|
|
1241
|
+
supports: {
|
|
1242
|
+
parentTypes: ["AnnotationPage", "Manifest"],
|
|
1243
|
+
parentFields: ["items"]
|
|
1244
|
+
},
|
|
1245
|
+
sideEffects: [resizeToFitService, resizeResourceToEmptyCanvas, repositionMultipleImages],
|
|
1246
|
+
staticFields: {
|
|
1247
|
+
type: "Annotation"
|
|
1248
|
+
}
|
|
1249
|
+
};
|
|
1250
|
+
|
|
1251
|
+
// src/Annotation/AudioAnnotation/create-audio-annotation.tsx
|
|
1252
|
+
import { useEffect as useEffect2, useState as useState6 } from "react";
|
|
1253
|
+
|
|
1254
|
+
// ../ui/atoms/callouts/ErrorMessage.tsx
|
|
1255
|
+
import styled3, { css } from "styled-components";
|
|
1256
|
+
var ErrorMessage = styled3.div`
|
|
1257
|
+
border: 2px solid ${(props) => props.theme.color.danger || "red"};
|
|
1258
|
+
width: 100%;
|
|
1259
|
+
border-radius: 5px;
|
|
1260
|
+
padding: ${(props) => props.theme.padding.small || "0.5rem"}
|
|
1261
|
+
${(props) => props.theme.padding.medium || "1rem"};
|
|
1262
|
+
line-height: 1.9em;
|
|
1263
|
+
display: flex;
|
|
1264
|
+
align-items: center;
|
|
1265
|
+
a {
|
|
1266
|
+
color: ${(props) => props.theme.color.white || "white"};
|
|
1267
|
+
}
|
|
1268
|
+
${(props) => props.$small && css`
|
|
1269
|
+
font-size: 0.75em;
|
|
1270
|
+
white-space: nowrap;
|
|
1271
|
+
padding: ${props.theme.padding.xs || "0.25rem"} ${props.theme.padding.small || "0.5rem"};
|
|
1272
|
+
line-height: 1.6em;
|
|
1273
|
+
width: fit-content;
|
|
1274
|
+
`}
|
|
1275
|
+
`;
|
|
1276
|
+
|
|
1277
|
+
// ../ui/ui/MediaControls/MediaControls.tsx
|
|
1278
|
+
import { formatTime, useMediaActions, useMediaElements, useMediaState } from "react-iiif-vault";
|
|
1279
|
+
import { useLayoutEffect, useState as useState5 } from "react";
|
|
1280
|
+
|
|
1281
|
+
// ../ui/ui/MediaControls/MediaControls.icons.tsx
|
|
1282
|
+
import { jsx as jsx27, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1283
|
+
var PlayIcon = (props) => /* @__PURE__ */ jsxs11("svg", { ...props, viewBox: "4 4 16 16", xmlns: "http://www.w3.org/2000/svg", height: "1em", width: "1em", children: [
|
|
1284
|
+
props.title ? /* @__PURE__ */ jsx27("title", { children: props.title }) : null,
|
|
1285
|
+
/* @__PURE__ */ jsx27("path", { d: "M0 0h24v24H0z", fill: "none" }),
|
|
1286
|
+
/* @__PURE__ */ jsx27("path", { d: "M8 5v14l11-7z", fill: "currentColor" })
|
|
1287
|
+
] });
|
|
1288
|
+
var PauseIcon = (props) => /* @__PURE__ */ jsxs11("svg", { ...props, viewBox: "4 4 16 16", xmlns: "http://www.w3.org/2000/svg", height: "1em", width: "1em", children: [
|
|
1289
|
+
props.title ? /* @__PURE__ */ jsx27("title", { children: props.title }) : null,
|
|
1290
|
+
/* @__PURE__ */ jsx27("path", { d: "M0 0h24v24H0z", fill: "none" }),
|
|
1291
|
+
/* @__PURE__ */ jsx27("path", { fill: "currentColor", d: "M6 19h4V5H6v14zm8-14v14h4V5h-4z" })
|
|
1292
|
+
] });
|
|
1293
|
+
var VolumeUpIcon = ({ title, ...props }) => /* @__PURE__ */ jsxs11("svg", { ...props, xmlns: "http://www.w3.org/2000/svg", height: "1em", width: "1em", viewBox: "2 2 20 20", children: [
|
|
1294
|
+
title ? /* @__PURE__ */ jsx27("title", { children: title }) : null,
|
|
1295
|
+
/* @__PURE__ */ jsx27("path", { d: "M0 0h24v24H0z", fill: "none" }),
|
|
1296
|
+
/* @__PURE__ */ jsx27(
|
|
1297
|
+
"path",
|
|
1298
|
+
{
|
|
1299
|
+
fill: "currentColor",
|
|
1300
|
+
d: "M3 9v6h4l5 5V4L7 9H3zm13.5 3A4.5 4.5 0 0 0 14 7.97v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"
|
|
1301
|
+
}
|
|
1302
|
+
)
|
|
1303
|
+
] });
|
|
1304
|
+
var VolumeDownIcon = ({ title, ...props }) => /* @__PURE__ */ jsxs11("svg", { ...props, xmlns: "http://www.w3.org/2000/svg", height: "1em", width: "1em", viewBox: "2 2 20 20", children: [
|
|
1305
|
+
title ? /* @__PURE__ */ jsx27("title", { children: title }) : null,
|
|
1306
|
+
/* @__PURE__ */ jsx27("path", { d: "M0 0h24v24H0z", fill: "none" }),
|
|
1307
|
+
/* @__PURE__ */ jsx27(
|
|
1308
|
+
"path",
|
|
1309
|
+
{
|
|
1310
|
+
fill: "currentColor",
|
|
1311
|
+
d: "M18.5 12c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM5 9v6h4l5 5V4L9 9H5z"
|
|
1312
|
+
}
|
|
1313
|
+
)
|
|
1314
|
+
] });
|
|
1315
|
+
var VolumeOffIcon = ({ title, ...props }) => /* @__PURE__ */ jsxs11("svg", { ...props, xmlns: "http://www.w3.org/2000/svg", height: "1em", width: "1em", viewBox: "2 2 20 20", children: [
|
|
1316
|
+
title ? /* @__PURE__ */ jsx27("title", { children: title }) : null,
|
|
1317
|
+
/* @__PURE__ */ jsx27("path", { d: "M0 0h24v24H0z", fill: "none" }),
|
|
1318
|
+
/* @__PURE__ */ jsx27(
|
|
1319
|
+
"path",
|
|
1320
|
+
{
|
|
1321
|
+
fill: "currentColor",
|
|
1322
|
+
d: "M16.5 12A4.5 4.5 0 0 0 14 7.97v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51A8.796 8.796 0 0 0 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3 3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06a8.99 8.99 0 0 0 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4 9.91 6.09 12 8.18V4z"
|
|
1323
|
+
}
|
|
1324
|
+
)
|
|
1325
|
+
] });
|
|
1326
|
+
|
|
1327
|
+
// ../ui/ui/MediaControls/MediaControls.styles.ts
|
|
1328
|
+
import styled4, { css as css2 } from "styled-components";
|
|
1329
|
+
var AudioPlayerContainer = styled4.div`
|
|
1330
|
+
background: #ededed; // Not in variable.
|
|
1331
|
+
display: flex;
|
|
1332
|
+
padding: 0.5em;
|
|
1333
|
+
align-items: center;
|
|
1334
|
+
`;
|
|
1335
|
+
var BaseButton = styled4.button`
|
|
1336
|
+
cursor: pointer;
|
|
1337
|
+
padding: 0.75em 1.5em;
|
|
1338
|
+
font-size: 0.938em;
|
|
1339
|
+
background: none;
|
|
1340
|
+
color: inherit;
|
|
1341
|
+
border: none;
|
|
1342
|
+
text-decoration: none;
|
|
1343
|
+
display: inline-block;
|
|
1344
|
+
vertical-align: top;
|
|
1345
|
+
white-space: nowrap;
|
|
1346
|
+
`;
|
|
1347
|
+
var PlayButton = styled4(BaseButton)`
|
|
1348
|
+
width: 2em;
|
|
1349
|
+
height: 2em;
|
|
1350
|
+
overflow: hidden;
|
|
1351
|
+
font-size: 1.1em;
|
|
1352
|
+
background: #fff;
|
|
1353
|
+
border-radius: 3px;
|
|
1354
|
+
padding: 0;
|
|
1355
|
+
margin: 0;
|
|
1356
|
+
color: #000; // Not in colours
|
|
1357
|
+
|
|
1358
|
+
&:disabled {
|
|
1359
|
+
color: #999;
|
|
1360
|
+
}
|
|
1361
|
+
`;
|
|
1362
|
+
var TimeDisplay = styled4.div`
|
|
1363
|
+
margin: 0 1em;
|
|
1364
|
+
font-size: 0.85em;
|
|
1365
|
+
color: #000;
|
|
1366
|
+
`;
|
|
1367
|
+
var ProgressContainer = styled4.div`
|
|
1368
|
+
flex: 1 1 0px;
|
|
1369
|
+
height: 6px;
|
|
1370
|
+
display: flex;
|
|
1371
|
+
position: relative;
|
|
1372
|
+
padding: 15px 0;
|
|
1373
|
+
`;
|
|
1374
|
+
var ProgressCurrent = styled4.div`
|
|
1375
|
+
background: #d85680;
|
|
1376
|
+
height: 6px;
|
|
1377
|
+
pointer-events: none;
|
|
1378
|
+
position: absolute;
|
|
1379
|
+
top: 13px;
|
|
1380
|
+
left: 0;
|
|
1381
|
+
border-radius: 3px;
|
|
1382
|
+
transition: width 200ms;
|
|
1383
|
+
`;
|
|
1384
|
+
var ProgressBackground = styled4.div`
|
|
1385
|
+
position: absolute;
|
|
1386
|
+
top: 13px;
|
|
1387
|
+
left: 0;
|
|
1388
|
+
height: 6px;
|
|
1389
|
+
border-radius: 3px;
|
|
1390
|
+
width: 100%;
|
|
1391
|
+
pointer-events: none;
|
|
1392
|
+
background: #fff;
|
|
1393
|
+
`;
|
|
1394
|
+
var SoundButton = styled4(BaseButton)`
|
|
1395
|
+
width: 2em;
|
|
1396
|
+
height: 2em;
|
|
1397
|
+
overflow: hidden;
|
|
1398
|
+
font-size: 1.1em;
|
|
1399
|
+
background: transparent;
|
|
1400
|
+
border-radius: 3px;
|
|
1401
|
+
padding: 0;
|
|
1402
|
+
margin: 0;
|
|
1403
|
+
`;
|
|
1404
|
+
var SoundContainer = styled4.div`
|
|
1405
|
+
display: flex;
|
|
1406
|
+
align-items: center;
|
|
1407
|
+
`;
|
|
1408
|
+
var VolumeContainer = styled4.div`
|
|
1409
|
+
width: 0;
|
|
1410
|
+
overflow: hidden;
|
|
1411
|
+
transition: width 500ms;
|
|
1412
|
+
color: #4a473f; // Not in colours
|
|
1413
|
+
|
|
1414
|
+
${(props) => props.$isOpen && css2`
|
|
1415
|
+
width: 150px;
|
|
1416
|
+
`}
|
|
1417
|
+
`;
|
|
1418
|
+
var VolumeSlider = styled4.input.attrs({ type: "range" })`
|
|
1419
|
+
width: 120px;
|
|
1420
|
+
margin: 0 15px;
|
|
1421
|
+
`;
|
|
1422
|
+
|
|
1423
|
+
// ../ui/madoc/components/icons/Spinner.tsx
|
|
1424
|
+
import { jsx as jsx28, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1425
|
+
function Spinner(props) {
|
|
1426
|
+
return /* @__PURE__ */ jsx28("svg", { width: "1em", height: "1em", viewBox: "0 0 42 42", xmlns: "http://www.w3.org/2000/svg", stroke: "#fff", ...props, children: /* @__PURE__ */ jsxs12("g", { transform: "translate(2 2)", strokeWidth: 5, fill: "none", fillRule: "evenodd", children: [
|
|
1427
|
+
/* @__PURE__ */ jsx28("circle", { strokeOpacity: 0.5, cx: 18, cy: 18, r: 18 }),
|
|
1428
|
+
/* @__PURE__ */ jsx28("path", { d: "M36 18c0-9.94-8.06-18-18-18", children: /* @__PURE__ */ jsx28(
|
|
1429
|
+
"animateTransform",
|
|
1430
|
+
{
|
|
1431
|
+
attributeName: "transform",
|
|
1432
|
+
type: "rotate",
|
|
1433
|
+
from: "0 18 18",
|
|
1434
|
+
to: "360 18 18",
|
|
1435
|
+
dur: "1s",
|
|
1436
|
+
repeatCount: "indefinite"
|
|
1437
|
+
}
|
|
1438
|
+
) })
|
|
1439
|
+
] }) });
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
// ../ui/atoms/VisuallHidden/VisuallHidden.tsx
|
|
1443
|
+
import styled5, { css as css3 } from "styled-components";
|
|
1444
|
+
var visuallyHidden = css3`
|
|
1445
|
+
clip: rect(1px, 1px, 1px, 1px);
|
|
1446
|
+
clip-path: inset(50%);
|
|
1447
|
+
height: 1px;
|
|
1448
|
+
width: 1px;
|
|
1449
|
+
margin: -1px;
|
|
1450
|
+
overflow: hidden;
|
|
1451
|
+
padding: 0;
|
|
1452
|
+
position: absolute;
|
|
1453
|
+
`;
|
|
1454
|
+
var VisuallyHiddenLabel = styled5.label`
|
|
1455
|
+
${visuallyHidden}
|
|
1456
|
+
`;
|
|
1457
|
+
|
|
1458
|
+
// ../ui/ui/MediaControls/MediaControls.tsx
|
|
1459
|
+
import { jsx as jsx29, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1460
|
+
function MediaControls(props) {
|
|
1461
|
+
const [isVolumeOpen, setIsVolumeOpen] = useState5(false);
|
|
1462
|
+
const { progress, currentTime, element } = useMediaElements();
|
|
1463
|
+
const { duration, isMuted, volume, isPlaying, playRequested } = useMediaState();
|
|
1464
|
+
const { setVolume, toggleMute, play, pause, setDurationPercent } = useMediaActions();
|
|
1465
|
+
const Volume = isMuted || volume === 0 ? VolumeOffIcon : volume > 50 ? VolumeUpIcon : VolumeDownIcon;
|
|
1466
|
+
useLayoutEffect(() => {
|
|
1467
|
+
if (element.current) {
|
|
1468
|
+
const $el = element.current;
|
|
1469
|
+
if ($el.error && props.onError) {
|
|
1470
|
+
props.onError($el.error?.message || "Unknown error");
|
|
1471
|
+
return;
|
|
1472
|
+
}
|
|
1473
|
+
const onError = () => {
|
|
1474
|
+
if (props.onError) {
|
|
1475
|
+
props.onError($el.error?.message || "Unknown error");
|
|
1476
|
+
}
|
|
1477
|
+
};
|
|
1478
|
+
const loadedMetadata = () => {
|
|
1479
|
+
if ($el.duration && props.onDuration) {
|
|
1480
|
+
props.onDuration($el.duration);
|
|
1481
|
+
}
|
|
1482
|
+
if (props.onDimensions && $el instanceof HTMLVideoElement) {
|
|
1483
|
+
props.onDimensions($el.videoWidth, $el.videoHeight);
|
|
1484
|
+
}
|
|
1485
|
+
};
|
|
1486
|
+
$el.addEventListener("loadedmetadata", loadedMetadata);
|
|
1487
|
+
$el.addEventListener("error", onError);
|
|
1488
|
+
return () => {
|
|
1489
|
+
$el.removeEventListener("loadedmetadata", loadedMetadata);
|
|
1490
|
+
$el.removeEventListener("error", onError);
|
|
1491
|
+
};
|
|
1492
|
+
}
|
|
1493
|
+
}, []);
|
|
1494
|
+
return /* @__PURE__ */ jsxs13(AudioPlayerContainer, { children: [
|
|
1495
|
+
/* @__PURE__ */ jsx29(
|
|
1496
|
+
PlayButton,
|
|
1497
|
+
{
|
|
1498
|
+
disabled: playRequested,
|
|
1499
|
+
onClick: () => {
|
|
1500
|
+
if (isPlaying) {
|
|
1501
|
+
pause();
|
|
1502
|
+
} else {
|
|
1503
|
+
play();
|
|
1504
|
+
}
|
|
1505
|
+
},
|
|
1506
|
+
children: playRequested ? /* @__PURE__ */ jsx29(Spinner, { stroke: "#999" }) : isPlaying ? /* @__PURE__ */ jsx29(PauseIcon, { title: "Pause" }) : /* @__PURE__ */ jsx29(PlayIcon, { title: "Play" })
|
|
1507
|
+
}
|
|
1508
|
+
),
|
|
1509
|
+
/* @__PURE__ */ jsx29(TimeDisplay, { ref: currentTime, children: "0:00" }),
|
|
1510
|
+
/* @__PURE__ */ jsxs13(
|
|
1511
|
+
ProgressContainer,
|
|
1512
|
+
{
|
|
1513
|
+
onClick: (e) => {
|
|
1514
|
+
const { left, width } = e.currentTarget.getBoundingClientRect();
|
|
1515
|
+
const percent = (e.pageX - left) / width;
|
|
1516
|
+
setDurationPercent(percent);
|
|
1517
|
+
},
|
|
1518
|
+
children: [
|
|
1519
|
+
/* @__PURE__ */ jsx29(ProgressBackground, {}),
|
|
1520
|
+
duration ? /* @__PURE__ */ jsx29(ProgressCurrent, { ref: progress }) : null
|
|
1521
|
+
]
|
|
1522
|
+
}
|
|
1523
|
+
),
|
|
1524
|
+
/* @__PURE__ */ jsx29(TimeDisplay, { children: formatTime(duration) }),
|
|
1525
|
+
/* @__PURE__ */ jsxs13(SoundContainer, { onMouseEnter: () => setIsVolumeOpen(true), onMouseLeave: () => setIsVolumeOpen(false), children: [
|
|
1526
|
+
/* @__PURE__ */ jsx29(VolumeContainer, { $isOpen: isVolumeOpen, children: /* @__PURE__ */ jsxs13("span", { children: [
|
|
1527
|
+
/* @__PURE__ */ jsx29(VisuallyHiddenLabel, { htmlFor: "audio-slider", children: "Change volume" }),
|
|
1528
|
+
/* @__PURE__ */ jsx29(
|
|
1529
|
+
VolumeSlider,
|
|
1530
|
+
{
|
|
1531
|
+
id: "audio-slider",
|
|
1532
|
+
role: "slider",
|
|
1533
|
+
disabled: isMuted,
|
|
1534
|
+
min: "0",
|
|
1535
|
+
max: "100",
|
|
1536
|
+
value: volume,
|
|
1537
|
+
onChange: (e) => setVolume(Number(e.currentTarget.value))
|
|
1538
|
+
}
|
|
1539
|
+
)
|
|
1540
|
+
] }) }),
|
|
1541
|
+
/* @__PURE__ */ jsx29(SoundButton, { onClick: () => toggleMute(), children: /* @__PURE__ */ jsx29(Volume, { title: isMuted ? "Mute" : "Unmute" }) })
|
|
1542
|
+
] })
|
|
1543
|
+
] });
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
// src/Annotation/AudioAnnotation/create-audio-annotation.tsx
|
|
1547
|
+
import { CanvasPanel } from "react-iiif-vault";
|
|
1548
|
+
import { getValue } from "@iiif/helpers";
|
|
1549
|
+
import { Input as Input6, InputContainer as InputContainer8, InputLabel as InputLabel8, LanguageFieldEditor as LanguageFieldEditor4, FormFieldWrapper } from "@manifest-editor/editors";
|
|
1550
|
+
import { jsx as jsx30, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1551
|
+
async function createAudioAnnotation(data, ctx) {
|
|
1552
|
+
const annotation = {
|
|
1553
|
+
id: ctx.generateId("annotation"),
|
|
1554
|
+
type: "Annotation"
|
|
1555
|
+
};
|
|
1556
|
+
const targetType = ctx.options.targetType;
|
|
1557
|
+
const body = await ctx.embed({
|
|
1558
|
+
id: data.url,
|
|
1559
|
+
type: "Sound",
|
|
1560
|
+
format: "audio/mp4",
|
|
1561
|
+
duration: data.duration || 0
|
|
1562
|
+
});
|
|
1563
|
+
if (targetType === "Annotation") {
|
|
1564
|
+
return ctx.embed({
|
|
1565
|
+
...annotation,
|
|
1566
|
+
label: getValue(data.label) && data.label,
|
|
1567
|
+
motivation: data.motivation || ctx.options.initialData?.motivation || "painting",
|
|
1568
|
+
body,
|
|
1569
|
+
target: ctx.getTarget()
|
|
1570
|
+
});
|
|
1571
|
+
}
|
|
1572
|
+
if (targetType === "Canvas") {
|
|
1573
|
+
const canvasId = ctx.generateId("canvas");
|
|
1574
|
+
const pageId = ctx.generateId("annotation-page", { id: canvasId, type: "Canvas" });
|
|
1575
|
+
const annotationResource = ctx.embed({
|
|
1576
|
+
...annotation,
|
|
1577
|
+
motivation: "painting",
|
|
1578
|
+
body,
|
|
1579
|
+
target: { type: "SpecificResource", source: { id: canvasId, type: "Canvas" } }
|
|
1580
|
+
});
|
|
1581
|
+
const page = ctx.embed({
|
|
1582
|
+
id: pageId,
|
|
1583
|
+
type: "AnnotationPage",
|
|
1584
|
+
items: [annotationResource]
|
|
1585
|
+
});
|
|
1586
|
+
return ctx.embed({
|
|
1587
|
+
id: canvasId,
|
|
1588
|
+
type: "Canvas",
|
|
1589
|
+
label: data.label || { en: ["Untitled HTML canvas"] },
|
|
1590
|
+
duration: data.duration || 0,
|
|
1591
|
+
items: [page]
|
|
1592
|
+
});
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
function CreateAudioAnnotationForm(props) {
|
|
1596
|
+
const [url, setUrl] = useState6("");
|
|
1597
|
+
const [duration, setDuration] = useState6(0);
|
|
1598
|
+
const [error, setError] = useState6("");
|
|
1599
|
+
const [label, setLabel] = useState6({ en: [""] });
|
|
1600
|
+
const onSubmit = () => {
|
|
1601
|
+
props.runCreate({
|
|
1602
|
+
url,
|
|
1603
|
+
duration,
|
|
1604
|
+
label
|
|
1605
|
+
});
|
|
1606
|
+
};
|
|
1607
|
+
useEffect2(() => {
|
|
1608
|
+
setError("");
|
|
1609
|
+
setDuration(0);
|
|
1610
|
+
if (url) {
|
|
1611
|
+
const labelFromUrl = url.split("/").pop()?.split(".").shift();
|
|
1612
|
+
setLabel({ en: [labelFromUrl || ""] });
|
|
1613
|
+
}
|
|
1614
|
+
}, [url]);
|
|
1615
|
+
return /* @__PURE__ */ jsxs14(PaddedSidebarContainer, { children: [
|
|
1616
|
+
error ? /* @__PURE__ */ jsx30(ErrorMessage, { children: error }) : null,
|
|
1617
|
+
/* @__PURE__ */ jsxs14(InputContainer8, { children: [
|
|
1618
|
+
/* @__PURE__ */ jsx30(InputLabel8, { htmlFor: "audio-url", children: "URL" }),
|
|
1619
|
+
/* @__PURE__ */ jsx30(Input6, { type: "text", id: "audio-url", value: url, onChange: (e) => setUrl(e.target.value) })
|
|
1620
|
+
] }),
|
|
1621
|
+
url && !error ? /* @__PURE__ */ jsx30("div", { children: /* @__PURE__ */ jsx30(
|
|
1622
|
+
LanguageFieldEditor4,
|
|
1623
|
+
{
|
|
1624
|
+
containerId: "label",
|
|
1625
|
+
focusId: "label_",
|
|
1626
|
+
label: "Label",
|
|
1627
|
+
fields: label,
|
|
1628
|
+
onSave: (e) => setLabel(e.toInternationalString())
|
|
1629
|
+
},
|
|
1630
|
+
url + "__" + duration
|
|
1631
|
+
) }) : null,
|
|
1632
|
+
url && !error ? /* @__PURE__ */ jsx30(CanvasPanel.AudioHTML, { media: { url, duration, type: "Sound" }, children: /* @__PURE__ */ jsx30(
|
|
1633
|
+
MediaControls,
|
|
1634
|
+
{
|
|
1635
|
+
onError: (error2) => setError(error2),
|
|
1636
|
+
onDuration: (duration2) => setDuration(duration2)
|
|
1637
|
+
},
|
|
1638
|
+
url + "__" + duration
|
|
1639
|
+
) }, url + "__" + duration) : null,
|
|
1640
|
+
duration && !error ? /* @__PURE__ */ jsxs14(FormFieldWrapper, { children: [
|
|
1641
|
+
/* @__PURE__ */ jsx30(InputLabel8, { htmlFor: "duration", children: "Duration" }),
|
|
1642
|
+
/* @__PURE__ */ jsx30(Input6, { type: "number", id: "duration", value: duration, onChange: (e) => setDuration(e.target.valueAsNumber) })
|
|
1643
|
+
] }) : null,
|
|
1644
|
+
url && !error && /* @__PURE__ */ jsx30(Button, { onClick: onSubmit, children: "Add audio" })
|
|
1645
|
+
] });
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
// src/Annotation/AudioAnnotation/index.tsx
|
|
1649
|
+
import { AudioIcon } from "@manifest-editor/components";
|
|
1650
|
+
import { jsx as jsx31 } from "react/jsx-runtime";
|
|
1651
|
+
var audioAnnotation = {
|
|
1652
|
+
id: "@manifest-editor/audio-annotation",
|
|
1653
|
+
create: createAudioAnnotation,
|
|
1654
|
+
label: "Audio",
|
|
1655
|
+
summary: "Audio annotation",
|
|
1656
|
+
icon: /* @__PURE__ */ jsx31(AudioIcon, {}),
|
|
1657
|
+
render(ctx) {
|
|
1658
|
+
return /* @__PURE__ */ jsx31(CreateAudioAnnotationForm, { ...ctx });
|
|
1659
|
+
},
|
|
1660
|
+
resourceType: "Annotation",
|
|
1661
|
+
resourceFields: ["id", "type", "motivation", "body", "target"],
|
|
1662
|
+
additionalTypes: ["Canvas"],
|
|
1663
|
+
supports: {
|
|
1664
|
+
initialData: true,
|
|
1665
|
+
parentTypes: ["AnnotationPage", "Manifest"],
|
|
1666
|
+
parentFields: ["items"]
|
|
1667
|
+
},
|
|
1668
|
+
staticFields: {
|
|
1669
|
+
type: "Annotation"
|
|
1670
|
+
}
|
|
1671
|
+
};
|
|
1672
|
+
|
|
1673
|
+
// src/Annotation/VideoAnnotation/create-video-annotation.tsx
|
|
1674
|
+
import { getValue as getValue2 } from "@iiif/helpers";
|
|
1675
|
+
import { InputContainer as InputContainer9, InputLabel as InputLabel9, Input as Input7, LanguageFieldEditor as LanguageFieldEditor5, DimensionsTriplet } from "@manifest-editor/editors";
|
|
1676
|
+
import { useState as useState7, useEffect as useEffect3 } from "react";
|
|
1677
|
+
|
|
1678
|
+
// ../ui/ui/VideoPlayer/VideoPlayer.tsx
|
|
1679
|
+
import { CanvasPanel as CanvasPanel2, MediaPlayerProvider, useSimpleMediaPlayer } from "react-iiif-vault";
|
|
1680
|
+
import { jsx as jsx32, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1681
|
+
function VideoPlayer({
|
|
1682
|
+
media,
|
|
1683
|
+
onError,
|
|
1684
|
+
duration,
|
|
1685
|
+
onDuration,
|
|
1686
|
+
onDimensions
|
|
1687
|
+
}) {
|
|
1688
|
+
const [{ element, currentTime, progress }, state, actions] = useSimpleMediaPlayer({ duration });
|
|
1689
|
+
return /* @__PURE__ */ jsxs15(
|
|
1690
|
+
MediaPlayerProvider,
|
|
1691
|
+
{
|
|
1692
|
+
element,
|
|
1693
|
+
state,
|
|
1694
|
+
actions,
|
|
1695
|
+
currentTime,
|
|
1696
|
+
progress,
|
|
1697
|
+
children: [
|
|
1698
|
+
/* @__PURE__ */ jsx32(
|
|
1699
|
+
"div",
|
|
1700
|
+
{
|
|
1701
|
+
style: {
|
|
1702
|
+
maxHeight: 400,
|
|
1703
|
+
aspectRatio: `${media.width}/${media.height}`,
|
|
1704
|
+
position: "relative"
|
|
1705
|
+
},
|
|
1706
|
+
children: /* @__PURE__ */ jsx32(CanvasPanel2.VideoHTML, { element, media, playPause: actions.playPause })
|
|
1707
|
+
}
|
|
1708
|
+
),
|
|
1709
|
+
/* @__PURE__ */ jsx32(MediaControls, { onError, onDuration, onDimensions })
|
|
1710
|
+
]
|
|
1711
|
+
}
|
|
1712
|
+
);
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1715
|
+
// src/Annotation/VideoAnnotation/create-video-annotation.tsx
|
|
1716
|
+
import { jsx as jsx33, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1717
|
+
async function createVideoAnnotation(data, ctx) {
|
|
1718
|
+
const annotation = {
|
|
1719
|
+
id: ctx.generateId("annotation"),
|
|
1720
|
+
type: "Annotation"
|
|
1721
|
+
};
|
|
1722
|
+
const targetType = ctx.options.targetType;
|
|
1723
|
+
const body = await ctx.embed({
|
|
1724
|
+
id: data.url,
|
|
1725
|
+
type: "Video",
|
|
1726
|
+
format: "video/mp4",
|
|
1727
|
+
width: data.width,
|
|
1728
|
+
height: data.height,
|
|
1729
|
+
duration: data.duration || 0
|
|
1730
|
+
});
|
|
1731
|
+
if (targetType === "Annotation") {
|
|
1732
|
+
return ctx.embed({
|
|
1733
|
+
...annotation,
|
|
1734
|
+
label: getValue2(data.label) && data.label,
|
|
1735
|
+
motivation: data.motivation || ctx.options.initialData?.motivation || "painting",
|
|
1736
|
+
body,
|
|
1737
|
+
target: ctx.getTarget()
|
|
1738
|
+
});
|
|
1739
|
+
}
|
|
1740
|
+
if (targetType === "Canvas") {
|
|
1741
|
+
const canvasId = ctx.generateId("canvas");
|
|
1742
|
+
const pageId = ctx.generateId("annotation-page", { id: canvasId, type: "Canvas" });
|
|
1743
|
+
const annotationResource = ctx.embed({
|
|
1744
|
+
...annotation,
|
|
1745
|
+
motivation: "painting",
|
|
1746
|
+
body,
|
|
1747
|
+
target: { type: "SpecificResource", source: { id: canvasId, type: "Canvas" } }
|
|
1748
|
+
});
|
|
1749
|
+
const page = ctx.embed({
|
|
1750
|
+
id: pageId,
|
|
1751
|
+
type: "AnnotationPage",
|
|
1752
|
+
items: [annotationResource]
|
|
1753
|
+
});
|
|
1754
|
+
return ctx.embed({
|
|
1755
|
+
id: canvasId,
|
|
1756
|
+
type: "Canvas",
|
|
1757
|
+
label: data.label || { en: ["Untitled HTML canvas"] },
|
|
1758
|
+
duration: data.duration || 0,
|
|
1759
|
+
width: data.width,
|
|
1760
|
+
height: data.height,
|
|
1761
|
+
items: [page]
|
|
1762
|
+
});
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
function CreateVideoAnnotationForm(props) {
|
|
1766
|
+
const [url, setUrl] = useState7("");
|
|
1767
|
+
const [duration, setDuration] = useState7(0);
|
|
1768
|
+
const [width, setWidth] = useState7(0);
|
|
1769
|
+
const [height, setHeight] = useState7(0);
|
|
1770
|
+
const [error, setError] = useState7("");
|
|
1771
|
+
const [label, setLabel] = useState7({ en: [""] });
|
|
1772
|
+
const onSubmit = () => {
|
|
1773
|
+
props.runCreate({
|
|
1774
|
+
url,
|
|
1775
|
+
duration,
|
|
1776
|
+
label,
|
|
1777
|
+
width,
|
|
1778
|
+
height
|
|
1779
|
+
});
|
|
1780
|
+
};
|
|
1781
|
+
useEffect3(() => {
|
|
1782
|
+
setError("");
|
|
1783
|
+
setDuration(0);
|
|
1784
|
+
if (url) {
|
|
1785
|
+
const labelFromUrl = url.split("/").pop()?.split(".").shift();
|
|
1786
|
+
setLabel({ en: [labelFromUrl || ""] });
|
|
1787
|
+
}
|
|
1788
|
+
}, [url]);
|
|
1789
|
+
return /* @__PURE__ */ jsxs16(PaddedSidebarContainer, { children: [
|
|
1790
|
+
error ? /* @__PURE__ */ jsx33(ErrorMessage, { children: error }) : null,
|
|
1791
|
+
/* @__PURE__ */ jsxs16(InputContainer9, { children: [
|
|
1792
|
+
/* @__PURE__ */ jsx33(InputLabel9, { htmlFor: "video-url", children: "URL" }),
|
|
1793
|
+
/* @__PURE__ */ jsx33(Input7, { type: "text", id: "video-url", value: url, onChange: (e) => setUrl(e.target.value) })
|
|
1794
|
+
] }),
|
|
1795
|
+
url && !error ? /* @__PURE__ */ jsx33("div", { children: /* @__PURE__ */ jsx33(
|
|
1796
|
+
LanguageFieldEditor5,
|
|
1797
|
+
{
|
|
1798
|
+
containerId: "label",
|
|
1799
|
+
focusId: "label_",
|
|
1800
|
+
label: "Label",
|
|
1801
|
+
fields: label,
|
|
1802
|
+
onSave: (e) => setLabel(e.toInternationalString())
|
|
1803
|
+
},
|
|
1804
|
+
url + "__" + duration
|
|
1805
|
+
) }) : null,
|
|
1806
|
+
url && !error ? /* @__PURE__ */ jsx33(
|
|
1807
|
+
VideoPlayer,
|
|
1808
|
+
{
|
|
1809
|
+
duration,
|
|
1810
|
+
onDuration: (d) => setDuration(d),
|
|
1811
|
+
onError: (err) => setError(err),
|
|
1812
|
+
media: {
|
|
1813
|
+
url,
|
|
1814
|
+
duration,
|
|
1815
|
+
height,
|
|
1816
|
+
width,
|
|
1817
|
+
type: "Video"
|
|
1818
|
+
},
|
|
1819
|
+
onDimensions: (w, h) => {
|
|
1820
|
+
setWidth(w || 0);
|
|
1821
|
+
setHeight(h || 0);
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
) : null,
|
|
1825
|
+
!error && (duration || width || height) ? /* @__PURE__ */ jsx33(InputContainer9, { $wide: true, children: /* @__PURE__ */ jsx33(
|
|
1826
|
+
DimensionsTriplet,
|
|
1827
|
+
{
|
|
1828
|
+
widthId: "width",
|
|
1829
|
+
width: width || 0,
|
|
1830
|
+
changeWidth: (v) => setWidth(v),
|
|
1831
|
+
heightId: "height",
|
|
1832
|
+
height: height || 0,
|
|
1833
|
+
changeHeight: (v) => setHeight(v),
|
|
1834
|
+
durationId: "duration",
|
|
1835
|
+
duration: duration || 0,
|
|
1836
|
+
changeDuration: (v) => setDuration(v)
|
|
1837
|
+
}
|
|
1838
|
+
) }) : null,
|
|
1839
|
+
url && !error && /* @__PURE__ */ jsx33(Button, { onClick: onSubmit, children: "Add video" })
|
|
1840
|
+
] });
|
|
1841
|
+
}
|
|
1842
|
+
|
|
1843
|
+
// src/Annotation/VideoAnnotation/index.tsx
|
|
1844
|
+
import { VideoIcon } from "@manifest-editor/components";
|
|
1845
|
+
import { jsx as jsx34 } from "react/jsx-runtime";
|
|
1846
|
+
var videoAnnotation = {
|
|
1847
|
+
id: "@manifest-editor/video-annotation",
|
|
1848
|
+
create: createVideoAnnotation,
|
|
1849
|
+
label: "Video",
|
|
1850
|
+
summary: "Video annotation",
|
|
1851
|
+
icon: /* @__PURE__ */ jsx34(VideoIcon, {}),
|
|
1852
|
+
render(ctx) {
|
|
1853
|
+
return /* @__PURE__ */ jsx34(CreateVideoAnnotationForm, { ...ctx });
|
|
1854
|
+
},
|
|
1855
|
+
resourceType: "Annotation",
|
|
1856
|
+
resourceFields: ["id", "type", "motivation", "body", "target"],
|
|
1857
|
+
additionalTypes: ["Canvas"],
|
|
1858
|
+
supports: {
|
|
1859
|
+
initialData: true,
|
|
1860
|
+
parentTypes: ["AnnotationPage", "Manifest"],
|
|
1861
|
+
parentFields: ["items"]
|
|
1862
|
+
},
|
|
1863
|
+
staticFields: {
|
|
1864
|
+
type: "Annotation"
|
|
1865
|
+
}
|
|
1866
|
+
};
|
|
1867
|
+
|
|
1868
|
+
// src/Manifest/ManifestBrowserCreator/manifest-browser-creator.tsx
|
|
1869
|
+
import { normaliseContentState as normaliseContentState2, parseContentState as parseContentState2 } from "@iiif/helpers";
|
|
1870
|
+
import { lazy as lazy2 } from "react";
|
|
1871
|
+
async function createFromManifestBrowserOutput(data, ctx) {
|
|
1872
|
+
const targetType = ctx.options.targetType;
|
|
1873
|
+
if (Array.isArray(data.output)) {
|
|
1874
|
+
throw new Error("Multiple items not yet supported");
|
|
1875
|
+
}
|
|
1876
|
+
const contentState = normaliseContentState2(
|
|
1877
|
+
typeof data.output === "string" ? parseContentState2(data.output) : data.output
|
|
1878
|
+
);
|
|
1879
|
+
const target = contentState.target[0];
|
|
1880
|
+
const previewVault = ctx.getPreviewVault();
|
|
1881
|
+
if (!target) {
|
|
1882
|
+
throw new Error("No target found in content state");
|
|
1883
|
+
}
|
|
1884
|
+
if (targetType === "Manifest") {
|
|
1885
|
+
const manifestId = target.source.id;
|
|
1886
|
+
invariant(manifestId, "Could not find Manifest ID");
|
|
1887
|
+
const manifest = await previewVault.get(manifestId);
|
|
1888
|
+
return ctx.embed({
|
|
1889
|
+
id: target.source.id,
|
|
1890
|
+
type: "Manifest",
|
|
1891
|
+
label: manifest.label
|
|
1892
|
+
});
|
|
1893
|
+
}
|
|
1894
|
+
if (targetType === "Collection") {
|
|
1895
|
+
const collectionId = target.source.id;
|
|
1896
|
+
invariant(collectionId, "Could not find Manifest ID");
|
|
1897
|
+
const collection = await previewVault.get(collectionId);
|
|
1898
|
+
return ctx.embed({
|
|
1899
|
+
id: target.source.id,
|
|
1900
|
+
type: "Collection",
|
|
1901
|
+
label: collection.label
|
|
1902
|
+
});
|
|
1903
|
+
}
|
|
1904
|
+
throw new Error("Not yet supported.");
|
|
1905
|
+
}
|
|
1906
|
+
var ManifestBrowserCreatorForm2 = lazy2(() => import("./manifest-browser-form.lazy-WRWZPVRC.js"));
|
|
1907
|
+
|
|
1908
|
+
// src/Manifest/ManifestBrowserCreator/index.tsx
|
|
1909
|
+
import { IIIFBrowserIcon as IIIFBrowserIcon2 } from "@manifest-editor/components";
|
|
1910
|
+
import { jsx as jsx35 } from "react/jsx-runtime";
|
|
1911
|
+
var manifestBrowserCreator = {
|
|
1912
|
+
id: "@manifest-editor/manifest-browser-creator",
|
|
1913
|
+
create: createFromManifestBrowserOutput,
|
|
1914
|
+
label: "IIIF Browser",
|
|
1915
|
+
summary: "Browse IIIF Resources",
|
|
1916
|
+
icon: /* @__PURE__ */ jsx35(IIIFBrowserIcon2, {}),
|
|
1917
|
+
render(ctx) {
|
|
1918
|
+
return /* @__PURE__ */ jsx35(ManifestBrowserCreatorForm, { ...ctx });
|
|
1919
|
+
},
|
|
1920
|
+
resourceType: "Manifest",
|
|
1921
|
+
resourceFields: ["id", "label"],
|
|
1922
|
+
additionalTypes: ["Collection"],
|
|
1923
|
+
supports: {
|
|
1924
|
+
parentTypes: ["Collection"],
|
|
1925
|
+
parentFieldMap: {
|
|
1926
|
+
Collection: ["items"]
|
|
1927
|
+
}
|
|
1928
|
+
},
|
|
1929
|
+
sideEffects: [],
|
|
1930
|
+
staticFields: {}
|
|
1931
|
+
};
|
|
1932
|
+
|
|
1933
|
+
// src/index.ts
|
|
1934
|
+
var allCreators = [
|
|
1935
|
+
// Images first.
|
|
1936
|
+
imageServiceCreator,
|
|
1937
|
+
imageServiceAnnotation,
|
|
1938
|
+
imageUrlCreator,
|
|
1939
|
+
imageUrlAnnotation,
|
|
1940
|
+
videoAnnotation,
|
|
1941
|
+
audioAnnotation,
|
|
1942
|
+
htmlBodyCreator,
|
|
1943
|
+
htmlAnnotation,
|
|
1944
|
+
youTubeBodyCreator,
|
|
1945
|
+
iiifBrowserCreator,
|
|
1946
|
+
emptyCanvas,
|
|
1947
|
+
plaintextCreator,
|
|
1948
|
+
webPageCreator,
|
|
1949
|
+
emptyAnnotationPage,
|
|
1950
|
+
noBodyAnnotation,
|
|
1951
|
+
internalCanvas
|
|
1952
|
+
];
|
|
1953
|
+
export {
|
|
1954
|
+
allCreators,
|
|
1955
|
+
audioAnnotation,
|
|
1956
|
+
emptyAnnotationPage,
|
|
1957
|
+
emptyCanvas,
|
|
1958
|
+
htmlAnnotation,
|
|
1959
|
+
htmlBodyCreator,
|
|
1960
|
+
iiifBrowserCreator,
|
|
1961
|
+
imageServiceAnnotation,
|
|
1962
|
+
imageServiceCreator,
|
|
1963
|
+
imageUrlAnnotation,
|
|
1964
|
+
imageUrlCreator,
|
|
1965
|
+
internalCanvas,
|
|
1966
|
+
manifestBrowserCreator,
|
|
1967
|
+
noBodyAnnotation,
|
|
1968
|
+
plaintextCreator,
|
|
1969
|
+
videoAnnotation,
|
|
1970
|
+
webPageCreator,
|
|
1971
|
+
youTubeBodyCreator
|
|
1972
|
+
};
|