@manifest-editor/creators 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +49 -0
  2. package/dist/chunk-AVISJS46.js +50 -0
  3. package/dist/chunk-ES62IRNT.js +50 -0
  4. package/dist/chunk-KLSWX2QF.js +38 -0
  5. package/dist/chunk-PFQB3PNW.js +47 -0
  6. package/dist/chunk-S3JO5Y3Z.js +50 -0
  7. package/dist/iiif-browser-form.lazy-3INAWCE5.js +54 -0
  8. package/dist/iiif-browser-form.lazy-4NX7YPGK.js +57 -0
  9. package/dist/iiif-browser-form.lazy-4X5LD2U4.js +51 -0
  10. package/dist/iiif-browser-form.lazy-5TF74M2Q.js +48 -0
  11. package/dist/iiif-browser-form.lazy-BHX6TGDY.js +58 -0
  12. package/dist/iiif-browser-form.lazy-C72INDSJ.js +57 -0
  13. package/dist/iiif-browser-form.lazy-DKKTAIO5.js +59 -0
  14. package/dist/iiif-browser-form.lazy-DPRO7R2W.js +59 -0
  15. package/dist/iiif-browser-form.lazy-EREIP6PZ.js +58 -0
  16. package/dist/iiif-browser-form.lazy-FQDZQ3UW.js +58 -0
  17. package/dist/iiif-browser-form.lazy-G7TCZSC2.js +58 -0
  18. package/dist/iiif-browser-form.lazy-HZ3M2DXT.js +57 -0
  19. package/dist/iiif-browser-form.lazy-I7KTYV3O.js +57 -0
  20. package/dist/iiif-browser-form.lazy-JMT72BLP.js +59 -0
  21. package/dist/iiif-browser-form.lazy-JX4S6NGX.js +48 -0
  22. package/dist/iiif-browser-form.lazy-KTB4BQBM.js +59 -0
  23. package/dist/iiif-browser-form.lazy-O35TC45U.js +49 -0
  24. package/dist/iiif-browser-form.lazy-OMDV43NQ.js +51 -0
  25. package/dist/iiif-browser-form.lazy-OXQVZ3GS.js +59 -0
  26. package/dist/iiif-browser-form.lazy-XORWZFSW.js +49 -0
  27. package/dist/index.cjs +1028 -537
  28. package/dist/index.d.cts +367 -21
  29. package/dist/index.d.ts +367 -21
  30. package/dist/index.js +954 -489
  31. package/dist/manifest-browser-form.lazy-FI4GGCPX.js +6 -0
  32. package/dist/manifest-browser-form.lazy-HJJKFMR6.js +6 -0
  33. package/dist/manifest-browser-form.lazy-MYI26AX4.js +6 -0
  34. package/dist/manifest-browser-form.lazy-XVYSAQAW.js +6 -0
  35. package/dist/manifest-browser-form.lazy-YYKOYF7R.js +6 -0
  36. package/package.json +12 -11
package/dist/index.js CHANGED
@@ -1,21 +1,15 @@
1
1
  import {
2
2
  ManifestBrowserCreatorForm
3
- } from "./chunk-7FSKLOVQ.js";
3
+ } from "./chunk-S3JO5Y3Z.js";
4
4
 
5
- // src/Annotation/AudioAnnotation/create-audio-annotation.tsx
6
- import { useEffect as useEffect2, useState as useState2 } from "react";
7
-
8
- // ../ui/atoms/PaddedSidebarContainer.tsx
9
- import styled from "styled-components";
10
- var PaddedSidebarContainer = styled.div`
11
- padding: 0 0.7em;
12
- margin: 0.7em 0;
13
- flex: 1;
14
- overflow: visible;
15
- `;
5
+ // src/Annotation/AudioAnnotation/index.tsx
6
+ import { AudioIcon } from "@manifest-editor/components";
7
+ import { defineCreator } from "@manifest-editor/creator-api";
16
8
 
17
9
  // src/Annotation/AudioAnnotation/create-audio-annotation.tsx
18
- import { ErrorMessage } from "@manifest-editor/components";
10
+ import { getValue } from "@iiif/helpers";
11
+ import { ActionButton, ErrorMessage } from "@manifest-editor/components";
12
+ import { FormFieldWrapper, Input, InputContainer, InputLabel, LanguageFieldEditor } from "@manifest-editor/editors";
19
13
 
20
14
  // ../ui/ui/MediaControls/MediaControls.tsx
21
15
  import { formatTime, useMediaActions, useMediaElements, useMediaState } from "react-iiif-vault";
@@ -68,14 +62,14 @@ var VolumeOffIcon = ({ title, ...props }) => /* @__PURE__ */ jsxs("svg", { ...pr
68
62
  ] });
69
63
 
70
64
  // ../ui/ui/MediaControls/MediaControls.styles.ts
71
- import styled2, { css } from "styled-components";
72
- var AudioPlayerContainer = styled2.div`
65
+ import styled, { css } from "styled-components";
66
+ var AudioPlayerContainer = styled.div`
73
67
  background: #ededed; // Not in variable.
74
68
  display: flex;
75
69
  padding: 0.5em;
76
70
  align-items: center;
77
71
  `;
78
- var BaseButton = styled2.button`
72
+ var BaseButton = styled.button`
79
73
  cursor: pointer;
80
74
  padding: 0.75em 1.5em;
81
75
  font-size: 0.938em;
@@ -87,7 +81,7 @@ var BaseButton = styled2.button`
87
81
  vertical-align: top;
88
82
  white-space: nowrap;
89
83
  `;
90
- var PlayButton = styled2(BaseButton)`
84
+ var PlayButton = styled(BaseButton)`
91
85
  width: 2em;
92
86
  height: 2em;
93
87
  overflow: hidden;
@@ -102,19 +96,19 @@ var PlayButton = styled2(BaseButton)`
102
96
  color: #999;
103
97
  }
104
98
  `;
105
- var TimeDisplay = styled2.div`
99
+ var TimeDisplay = styled.div`
106
100
  margin: 0 1em;
107
101
  font-size: 0.85em;
108
102
  color: #000;
109
103
  `;
110
- var ProgressContainer = styled2.div`
104
+ var ProgressContainer = styled.div`
111
105
  flex: 1 1 0px;
112
106
  height: 6px;
113
107
  display: flex;
114
108
  position: relative;
115
109
  padding: 15px 0;
116
110
  `;
117
- var ProgressCurrent = styled2.div`
111
+ var ProgressCurrent = styled.div`
118
112
  background: #d85680;
119
113
  height: 6px;
120
114
  pointer-events: none;
@@ -124,7 +118,7 @@ var ProgressCurrent = styled2.div`
124
118
  border-radius: 3px;
125
119
  transition: width 200ms;
126
120
  `;
127
- var ProgressBackground = styled2.div`
121
+ var ProgressBackground = styled.div`
128
122
  position: absolute;
129
123
  top: 13px;
130
124
  left: 0;
@@ -134,7 +128,7 @@ var ProgressBackground = styled2.div`
134
128
  pointer-events: none;
135
129
  background: #fff;
136
130
  `;
137
- var SoundButton = styled2(BaseButton)`
131
+ var SoundButton = styled(BaseButton)`
138
132
  width: 2em;
139
133
  height: 2em;
140
134
  overflow: hidden;
@@ -144,11 +138,11 @@ var SoundButton = styled2(BaseButton)`
144
138
  padding: 0;
145
139
  margin: 0;
146
140
  `;
147
- var SoundContainer = styled2.div`
141
+ var SoundContainer = styled.div`
148
142
  display: flex;
149
143
  align-items: center;
150
144
  `;
151
- var VolumeContainer = styled2.div`
145
+ var VolumeContainer = styled.div`
152
146
  width: 0;
153
147
  overflow: hidden;
154
148
  transition: width 500ms;
@@ -158,7 +152,7 @@ var VolumeContainer = styled2.div`
158
152
  width: 150px;
159
153
  `}
160
154
  `;
161
- var VolumeSlider = styled2.input.attrs({ type: "range" })`
155
+ var VolumeSlider = styled.input.attrs({ type: "range" })`
162
156
  width: 120px;
163
157
  margin: 0 15px;
164
158
  `;
@@ -166,24 +160,35 @@ var VolumeSlider = styled2.input.attrs({ type: "range" })`
166
160
  // ../ui/madoc/components/icons/Spinner.tsx
167
161
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
168
162
  function Spinner(props) {
169
- return /* @__PURE__ */ jsx2("svg", { width: "1em", height: "1em", viewBox: "0 0 42 42", xmlns: "http://www.w3.org/2000/svg", stroke: "#fff", ...props, children: /* @__PURE__ */ jsxs2("g", { transform: "translate(2 2)", strokeWidth: 5, fill: "none", fillRule: "evenodd", children: [
170
- /* @__PURE__ */ jsx2("circle", { strokeOpacity: 0.5, cx: 18, cy: 18, r: 18 }),
171
- /* @__PURE__ */ jsx2("path", { d: "M36 18c0-9.94-8.06-18-18-18", children: /* @__PURE__ */ jsx2(
172
- "animateTransform",
173
- {
174
- attributeName: "transform",
175
- type: "rotate",
176
- from: "0 18 18",
177
- to: "360 18 18",
178
- dur: "1s",
179
- repeatCount: "indefinite"
180
- }
181
- ) })
182
- ] }) });
163
+ return /* @__PURE__ */ jsx2(
164
+ "svg",
165
+ {
166
+ width: "1em",
167
+ height: "1em",
168
+ viewBox: "0 0 42 42",
169
+ xmlns: "http://www.w3.org/2000/svg",
170
+ stroke: "currentColor",
171
+ ...props,
172
+ children: /* @__PURE__ */ jsxs2("g", { transform: "translate(2 2)", strokeWidth: 5, fill: "none", fillRule: "evenodd", children: [
173
+ /* @__PURE__ */ jsx2("circle", { strokeOpacity: 0.5, cx: 18, cy: 18, r: 18 }),
174
+ /* @__PURE__ */ jsx2("path", { d: "M36 18c0-9.94-8.06-18-18-18", children: /* @__PURE__ */ jsx2(
175
+ "animateTransform",
176
+ {
177
+ attributeName: "transform",
178
+ type: "rotate",
179
+ from: "0 18 18",
180
+ to: "360 18 18",
181
+ dur: "1s",
182
+ repeatCount: "indefinite"
183
+ }
184
+ ) })
185
+ ] })
186
+ }
187
+ );
183
188
  }
184
189
 
185
190
  // ../ui/atoms/VisuallHidden/VisuallHidden.tsx
186
- import styled3, { css as css2 } from "styled-components";
191
+ import styled2, { css as css2 } from "styled-components";
187
192
  var visuallyHidden = css2`
188
193
  clip: rect(1px, 1px, 1px, 1px);
189
194
  clip-path: inset(50%);
@@ -194,7 +199,7 @@ var visuallyHidden = css2`
194
199
  padding: 0;
195
200
  position: absolute;
196
201
  `;
197
- var VisuallyHiddenLabel = styled3.label`
202
+ var VisuallyHiddenLabel = styled2.label`
198
203
  ${visuallyHidden}
199
204
  `;
200
205
 
@@ -286,93 +291,18 @@ function MediaControls(props) {
286
291
  ] });
287
292
  }
288
293
 
289
- // src/Annotation/AudioAnnotation/create-audio-annotation.tsx
290
- import { CanvasPanel } from "react-iiif-vault";
291
- import { getValue } from "@iiif/helpers";
292
- import { Input, InputContainer, InputLabel, LanguageFieldEditor, FormFieldWrapper } from "@manifest-editor/editors";
293
-
294
- // ../ui/atoms/Button.tsx
295
- import styled4 from "styled-components";
296
- var ButtonReset = styled4.button`
297
- border: none;
298
- outline: none;
299
- background-color: transparent;
300
- margin: 0;
301
- padding: 0;
302
- font-size: inherit;
303
- color: inherit;
304
- cursor: pointer;
305
- &:hover {
306
- color: inherit;
307
- }
308
- `;
309
- var Button = styled4.button`
310
- padding: 0.5rem 1rem;
311
- color: ${(props) => props.theme.color.main || "none"};
312
- background-color: ${(props) => props.theme.color.white || "white"};
313
- border-radius: inherit;
314
- border: none;
315
- cursor: pointer;
316
- display: flex;
317
- align-items: center;
318
- font-size: 0.85em;
319
- :disabled {
320
- opacity: 0.65;
321
- cursor: not-allowed;
322
- }
323
-
324
- &:hover {
325
- background: #eee;
326
- }
327
- `;
328
- var SmallButton = styled4(Button)`
329
- padding: 0.25em ${(props) => props.theme.padding.xs || "0.4em"};
330
- height: unset;
331
- background: none;
332
- `;
333
- var SecondaryButton = styled4(Button)`
334
- {
335
- padding: 0 ${(props) => props.theme.padding.medium || "1rem"};
336
- color: ${(props) => props.theme.color.main || "#B84C74;"};
337
- background-color: ${(props) => props.theme.color.white || "white"};
338
- border: 1px solid ${(props) => props.theme.color.main || "#B84C74;"};
339
- border-radius: 0.25rem;
340
- cursor: pointer;
341
- height: 2rem;
342
- display: flex;
343
- align-items: center;
344
- white-space: nowrap;
345
- font-size: 0.75rem;
346
-
347
- :disabled {
348
- opacity: 0.65;
349
- cursor: not-allowed;
350
- }
351
- }
352
- `;
353
- var CalltoButton = styled4(Button)`
354
- padding: 0 ${(props) => props.theme.padding.medium || "1rem"};
355
- color: ${(props) => props.theme.color.white || "white"};
356
- background-color: ${(props) => props.theme.color.main || "#B84C74;"};
357
- border: 1px solid #eee;
358
- border-radius: 0.25rem;
359
- cursor: pointer;
360
- justify-content: center;
361
- display: flex;
362
- align-items: center;
363
- &:hover {
364
- background-color: ${(props) => props.theme.color.mainHover || "#B84C74;"};
365
- }
366
- `;
367
- var ButtonGroup = styled4.div`
368
- display: flex;
369
- flex-direction: row;
370
- flex-wrap: wrap;
371
- align-items: flex-start;
372
- justify-content: ${(props) => props.$right ? "flex-end" : "flex-start"};
294
+ // ../ui/atoms/PaddedSidebarContainer.tsx
295
+ import styled3 from "styled-components";
296
+ var PaddedSidebarContainer = styled3.div`
297
+ padding: 0 0.7em;
298
+ margin: 0.7em 0;
299
+ flex: 1;
300
+ overflow: visible;
373
301
  `;
374
302
 
375
303
  // src/Annotation/AudioAnnotation/create-audio-annotation.tsx
304
+ import { useEffect as useEffect2, useState as useState2 } from "react";
305
+ import { CanvasPanel } from "react-iiif-vault";
376
306
  import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
377
307
  async function createAudioAnnotation(data, ctx) {
378
308
  const annotation = {
@@ -380,7 +310,7 @@ async function createAudioAnnotation(data, ctx) {
380
310
  type: "Annotation"
381
311
  };
382
312
  const targetType = ctx.options.targetType;
383
- const body = await ctx.embed({
313
+ const body = ctx.embed({
384
314
  id: data.url,
385
315
  type: "Sound",
386
316
  format: "audio/mp4",
@@ -397,12 +327,18 @@ async function createAudioAnnotation(data, ctx) {
397
327
  }
398
328
  if (targetType === "Canvas") {
399
329
  const canvasId = ctx.generateId("canvas");
400
- const pageId = ctx.generateId("annotation-page", { id: canvasId, type: "Canvas" });
330
+ const pageId = ctx.generateId("annotation-page", {
331
+ id: canvasId,
332
+ type: "Canvas"
333
+ });
401
334
  const annotationResource = ctx.embed({
402
335
  ...annotation,
403
336
  motivation: "painting",
404
337
  body,
405
- target: { type: "SpecificResource", source: { id: canvasId, type: "Canvas" } }
338
+ target: {
339
+ type: "SpecificResource",
340
+ source: { id: canvasId, type: "Canvas" }
341
+ }
406
342
  });
407
343
  const page = ctx.embed({
408
344
  id: pageId,
@@ -440,7 +376,7 @@ function CreateAudioAnnotationForm(props) {
440
376
  }, [url]);
441
377
  return /* @__PURE__ */ jsxs4(PaddedSidebarContainer, { children: [
442
378
  error ? /* @__PURE__ */ jsx4(ErrorMessage, { children: error }) : null,
443
- /* @__PURE__ */ jsxs4(InputContainer, { children: [
379
+ /* @__PURE__ */ jsxs4(InputContainer, { $wide: true, children: [
444
380
  /* @__PURE__ */ jsx4(InputLabel, { htmlFor: "audio-url", children: "URL" }),
445
381
  /* @__PURE__ */ jsx4(Input, { type: "text", id: "audio-url", value: url, onChange: (e) => setUrl(e.target.value) })
446
382
  ] }),
@@ -453,28 +389,27 @@ function CreateAudioAnnotationForm(props) {
453
389
  fields: label,
454
390
  onSave: (e) => setLabel(e.toInternationalString())
455
391
  },
456
- url + "__" + duration
392
+ `${url}__${duration}`
457
393
  ) }) : null,
458
394
  url && !error ? /* @__PURE__ */ jsx4(CanvasPanel.AudioHTML, { media: { url, duration, type: "Sound" }, children: /* @__PURE__ */ jsx4(
459
395
  MediaControls,
460
396
  {
461
397
  onError: (error2) => setError(error2),
462
- onDuration: (duration2) => setDuration(duration2)
398
+ onDuration: (duration2) => setDuration(~~duration2)
463
399
  },
464
- url + "__" + duration
465
- ) }, url + "__" + duration) : null,
400
+ `${url}__${duration}`
401
+ ) }, `${url}__${duration}`) : null,
466
402
  duration && !error ? /* @__PURE__ */ jsxs4(FormFieldWrapper, { children: [
467
403
  /* @__PURE__ */ jsx4(InputLabel, { htmlFor: "duration", children: "Duration" }),
468
404
  /* @__PURE__ */ jsx4(Input, { type: "number", id: "duration", value: duration, onChange: (e) => setDuration(e.target.valueAsNumber) })
469
405
  ] }) : null,
470
- url && !error && /* @__PURE__ */ jsx4(Button, { onClick: onSubmit, children: "Add audio" })
406
+ /* @__PURE__ */ jsx4(ActionButton, { primary: true, large: true, type: "button", onPress: onSubmit, isDisabled: !url || !!error, children: "Add audio" })
471
407
  ] });
472
408
  }
473
409
 
474
410
  // src/Annotation/AudioAnnotation/index.tsx
475
- import { AudioIcon } from "@manifest-editor/components";
476
411
  import { jsx as jsx5 } from "react/jsx-runtime";
477
- var audioAnnotation = {
412
+ var audioAnnotation = defineCreator({
478
413
  id: "@manifest-editor/audio-annotation",
479
414
  create: createAudioAnnotation,
480
415
  label: "Audio",
@@ -494,12 +429,14 @@ var audioAnnotation = {
494
429
  staticFields: {
495
430
  type: "Annotation"
496
431
  }
497
- };
432
+ });
498
433
 
499
434
  // src/Annotation/CaptionedImageAnnotation/index.tsx
500
435
  import { AddImageIcon } from "@manifest-editor/components";
436
+ import { defineCreator as defineCreator2 } from "@manifest-editor/creator-api";
501
437
 
502
438
  // src/Annotation/CaptionedImageAnnotation/create-captioned-image-annotation.tsx
439
+ import { ActionButton as ActionButton2 } from "@manifest-editor/components";
503
440
  import { Input as Input2, InputContainer as InputContainer2, InputLabel as InputLabel2, LanguageFieldEditor as LanguageFieldEditor2 } from "@manifest-editor/editors";
504
441
  import { useState as useState3 } from "react";
505
442
  import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
@@ -602,13 +539,13 @@ function CreateCaptionedImageAnnotation(props) {
602
539
  }
603
540
  )
604
541
  ] }),
605
- /* @__PURE__ */ jsx6(Button, { type: "submit", children: "Create" })
542
+ /* @__PURE__ */ jsx6(ActionButton2, { primary: true, large: true, type: "submit", children: "Create" })
606
543
  ] }) });
607
544
  }
608
545
 
609
546
  // src/Annotation/CaptionedImageAnnotation/index.tsx
610
547
  import { jsx as jsx7 } from "react/jsx-runtime";
611
- var captionedImageAnnotation = {
548
+ var captionedImageAnnotation = defineCreator2({
612
549
  id: "@manifest-editor/captioned-image-annotation",
613
550
  create: createCaptionedImageAnnotation,
614
551
  label: "Captioned image",
@@ -628,15 +565,17 @@ var captionedImageAnnotation = {
628
565
  staticFields: {
629
566
  type: "Annotation"
630
567
  }
631
- };
568
+ });
569
+
570
+ // src/Annotation/HTMLAnnotation/index.tsx
571
+ import { HTMLIcon } from "@manifest-editor/components";
572
+ import { defineCreator as defineCreator3 } from "@manifest-editor/creator-api";
632
573
 
633
574
  // src/Annotation/HTMLAnnotation/create-html-annotation.tsx
575
+ import { getValue as getValue2 } from "@iiif/helpers";
576
+ import { ActionButton as ActionButton3 } from "@manifest-editor/components";
577
+ import { LanguageFieldEditor as LanguageFieldEditor3 } from "@manifest-editor/editors";
634
578
  import { useState as useState4 } from "react";
635
- import {
636
- InputContainer as InputContainer3,
637
- InputLabel as InputLabel3,
638
- LanguageFieldEditor as LanguageFieldEditor3
639
- } from "@manifest-editor/editors";
640
579
  import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
641
580
  async function createHtmlAnnotation(data, ctx) {
642
581
  const annotation = {
@@ -701,37 +640,34 @@ async function createHtmlAnnotation(data, ctx) {
701
640
  }
702
641
  function CreateHTMLAnnotation(props) {
703
642
  const [body, setBody] = useState4({ en: [""] });
643
+ const isEmpty = getValue2(body).trim() === "";
704
644
  const onSubmit = () => {
705
645
  props.runCreate({
706
646
  body
707
647
  });
708
648
  };
709
649
  return /* @__PURE__ */ jsxs6(PaddedSidebarContainer, { children: [
710
- /* @__PURE__ */ jsxs6(InputContainer3, { children: [
711
- /* @__PURE__ */ jsx8(InputLabel3, { children: "HTML Body" }),
712
- /* @__PURE__ */ jsx8(
713
- LanguageFieldEditor3,
714
- {
715
- focusId: "html-content",
716
- label: "HTML Content",
717
- fields: body,
718
- onSave: (e) => setBody(e.toInternationalString())
719
- }
720
- )
721
- ] }),
722
- /* @__PURE__ */ jsx8(Button, { onClick: () => onSubmit(), children: "Create" })
650
+ /* @__PURE__ */ jsx8(
651
+ LanguageFieldEditor3,
652
+ {
653
+ focusId: "html-content",
654
+ label: "HTML Content",
655
+ fields: body,
656
+ onSave: (e) => setBody(e.toInternationalString())
657
+ }
658
+ ),
659
+ /* @__PURE__ */ jsx8(ActionButton3, { primary: true, large: true, type: "button", onPress: onSubmit, isDisabled: isEmpty, children: "Create" })
723
660
  ] });
724
661
  }
725
662
 
726
663
  // src/Annotation/HTMLAnnotation/index.tsx
727
- import { HTMLIcon as HTMLIcon2 } from "@manifest-editor/components";
728
664
  import { jsx as jsx9 } from "react/jsx-runtime";
729
- var htmlAnnotation = {
665
+ var htmlAnnotation = defineCreator3({
730
666
  id: "@manifest-editor/html-annotation",
731
667
  create: createHtmlAnnotation,
732
668
  label: "HTML",
733
669
  summary: "HTML annotation",
734
- icon: /* @__PURE__ */ jsx9(HTMLIcon2, {}),
670
+ icon: /* @__PURE__ */ jsx9(HTMLIcon, {}),
735
671
  render(ctx) {
736
672
  return /* @__PURE__ */ jsx9(CreateHTMLAnnotation, { ...ctx });
737
673
  },
@@ -746,7 +682,11 @@ var htmlAnnotation = {
746
682
  staticFields: {
747
683
  type: "Annotation"
748
684
  }
749
- };
685
+ });
686
+
687
+ // src/Annotation/ImageServiceAnnotation/index.tsx
688
+ import { IIIFLogo } from "@manifest-editor/components";
689
+ import { defineCreator as defineCreator4 } from "@manifest-editor/creator-api";
750
690
 
751
691
  // src/side-effects/reposition-multiple-images.ts
752
692
  import { isImageService } from "@iiif/parser/image-3";
@@ -771,7 +711,7 @@ var repositionMultipleImages = {
771
711
  if (!annoPage) {
772
712
  return;
773
713
  }
774
- if (annoPage.items.length < 2) {
714
+ if (annoPage.items.length < 2 && !canvas.behavior.includes("multi-image")) {
775
715
  return;
776
716
  }
777
717
  const bodies = vault.get(fullAnno.body);
@@ -782,10 +722,18 @@ var repositionMultipleImages = {
782
722
  if (imageService) {
783
723
  if (imageService.width && imageService.height) {
784
724
  if (imageService.width !== body.width) {
785
- vault.modifyEntityField({ id: body.id, type: "ContentResource" }, "width", imageService.width);
725
+ vault.modifyEntityField(
726
+ { id: body.id, type: "ContentResource" },
727
+ "width",
728
+ imageService.width
729
+ );
786
730
  }
787
731
  if (imageService.height !== body.height) {
788
- vault.modifyEntityField({ id: body.id, type: "ContentResource" }, "height", imageService.height);
732
+ vault.modifyEntityField(
733
+ { id: body.id, type: "ContentResource" },
734
+ "height",
735
+ imageService.height
736
+ );
789
737
  }
790
738
  }
791
739
  }
@@ -829,6 +777,9 @@ var resizeResourceToEmptyCanvas = {
829
777
  if (!canvas.items) {
830
778
  return;
831
779
  }
780
+ if (canvas.behavior.includes("multi-image")) {
781
+ return;
782
+ }
832
783
  const annoPage = vault.get(canvas.items[0]);
833
784
  if (!annoPage) {
834
785
  return;
@@ -886,6 +837,9 @@ var resizeToFitService = {
886
837
  if (!canvas.items) {
887
838
  return;
888
839
  }
840
+ if (canvas.behavior.includes("multi-image")) {
841
+ return;
842
+ }
889
843
  const annoPage = vault.get(canvas.items[0]);
890
844
  if (!annoPage) {
891
845
  return;
@@ -901,10 +855,18 @@ var resizeToFitService = {
901
855
  if (imageService) {
902
856
  if (imageService.width && imageService.height) {
903
857
  if (imageService.width !== body.width) {
904
- vault.modifyEntityField({ id: body.id, type: "ContentResource" }, "width", imageService.width);
858
+ vault.modifyEntityField(
859
+ { id: body.id, type: "ContentResource" },
860
+ "width",
861
+ imageService.width
862
+ );
905
863
  }
906
864
  if (imageService.height !== body.height) {
907
- vault.modifyEntityField({ id: body.id, type: "ContentResource" }, "height", imageService.height);
865
+ vault.modifyEntityField(
866
+ { id: body.id, type: "ContentResource" },
867
+ "height",
868
+ imageService.height
869
+ );
908
870
  }
909
871
  }
910
872
  }
@@ -912,16 +874,33 @@ var resizeToFitService = {
912
874
  }
913
875
  };
914
876
 
877
+ // src/Annotation/ImageServiceAnnotation/create-service-annotation.tsx
878
+ import {
879
+ creatorHelper
880
+ } from "@manifest-editor/creator-api";
881
+
915
882
  // src/ContentResource/ImageServiceCreator/create-image-service.tsx
916
883
  import {
917
- imageServiceRequestToString,
884
+ canonicalServiceUrl,
918
885
  createImageServiceRequest,
919
- canonicalServiceUrl
886
+ imageServiceRequestToString,
887
+ parseImageServiceRequest
920
888
  } from "@iiif/parser/image-3";
921
- import { InputContainer as InputContainer4, InputLabel as InputLabel4, Input as Input3 } from "@manifest-editor/editors";
889
+ import { ActionButton as ActionButton4 } from "@manifest-editor/components";
890
+ import { Input as Input3, InputContainer as InputContainer3, InputLabel as InputLabel3 } from "@manifest-editor/editors";
891
+ import { useState as useState5 } from "react";
892
+ import { ErrorBoundary } from "react-error-boundary";
893
+ import { ImageService as ImageServiceComponent } from "react-iiif-vault";
922
894
  import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
923
895
  async function createImageServer(data, ctx) {
924
- const request = createImageServiceRequest(data.service);
896
+ const service = { ...data.service };
897
+ if (service["@id"]) {
898
+ service.id = service["@id"];
899
+ }
900
+ if (service["@type"]) {
901
+ service.type = service["@type"];
902
+ }
903
+ const request = createImageServiceRequest(service);
925
904
  const imageId = imageServiceRequestToString({
926
905
  identifier: request.identifier,
927
906
  server: request.server,
@@ -946,37 +925,64 @@ async function createImageServer(data, ctx) {
946
925
  id: imageId,
947
926
  type: "Image",
948
927
  format: data.format || "image/jpeg",
949
- height: data.height || data.service.height,
950
- width: data.width || data.service.width,
928
+ height: data.height || service.height,
929
+ width: data.width || service.width,
951
930
  service: data.embedService === false ? void 0 : [data.service]
952
931
  });
953
932
  return resource;
954
933
  }
934
+ function getCanonicalUrl(url) {
935
+ return url.endsWith("default.jpg") ? imageServiceRequestToString({
936
+ ...parseImageServiceRequest(url),
937
+ type: "info"
938
+ }) : canonicalServiceUrl(url);
939
+ }
955
940
  function CreateImageServerForm(props) {
941
+ const [url, setUrl] = useState5("");
956
942
  const onSubmit = (e) => {
957
943
  e.preventDefault();
958
944
  const data = new FormData(e.target);
959
945
  const formData = Object.fromEntries(data.entries());
960
- const url = formData.url;
961
- if (url) {
962
- const canon = canonicalServiceUrl(url);
963
- fetch(canon).then((r) => r.json()).then((service) => {
964
- if (service["@id"]) {
965
- service.id = service["@id"];
966
- }
967
- if (service["@type"]) {
968
- service.type = service["@type"];
969
- }
946
+ const url2 = formData.url;
947
+ if (url2) {
948
+ const info = getCanonicalUrl(url2);
949
+ if (!info) {
950
+ throw new Error("Invalid image service request");
951
+ }
952
+ fetch(info).then((r) => r.json()).then((service) => {
970
953
  props.runCreate({ url: formData.url, service });
971
954
  });
972
955
  }
973
956
  };
974
957
  return /* @__PURE__ */ jsx10(PaddedSidebarContainer, { children: /* @__PURE__ */ jsxs7("form", { onSubmit, children: [
975
- /* @__PURE__ */ jsxs7(InputContainer4, { $wide: true, children: [
976
- /* @__PURE__ */ jsx10(InputLabel4, { htmlFor: "id", children: "Link to image service" }),
977
- /* @__PURE__ */ jsx10(Input3, { id: "url", name: "url", defaultValue: "" })
978
- ] }),
979
- /* @__PURE__ */ jsx10(Button, { type: "submit", children: "Create" })
958
+ /* @__PURE__ */ jsx10("div", { className: "flex gap-2 items-center", children: /* @__PURE__ */ jsxs7(InputContainer3, { $wide: true, children: [
959
+ /* @__PURE__ */ jsx10(InputLabel3, { htmlFor: "id", children: "Link to image service" }),
960
+ /* @__PURE__ */ jsx10(
961
+ Input3,
962
+ {
963
+ id: "url",
964
+ name: "url",
965
+ defaultValue: "",
966
+ onPaste: (e) => {
967
+ const text = e.clipboardData.getData("text/plain");
968
+ setUrl(text ? getCanonicalUrl(text) : "");
969
+ },
970
+ onBlur: (e) => setUrl(e.currentTarget.value ? getCanonicalUrl(e.currentTarget.value) : "")
971
+ }
972
+ )
973
+ ] }) }),
974
+ /* @__PURE__ */ jsx10("div", { className: "relative flex z-0 my-5 h-96 min-h-0 min-w-0 overflow-hidden bg-gray-200 rounded items-center justify-center", children: url.trim() ? /* @__PURE__ */ jsx10(ErrorBoundary, { fallbackRender: () => /* @__PURE__ */ jsx10("div", { children: "Invalid service" }), children: /* @__PURE__ */ jsx10(
975
+ ImageServiceComponent,
976
+ {
977
+ src: url,
978
+ fluid: true,
979
+ errorFallback: () => /* @__PURE__ */ jsx10("div", { children: "Invalid service" }),
980
+ background: "rgb(229,231,235)",
981
+ className: "h-full w-full",
982
+ containerProps: { className: "w-full h-full z-10" }
983
+ }
984
+ ) }) : /* @__PURE__ */ jsx10("div", { className: "text-grey-600", children: "Preview" }) }),
985
+ /* @__PURE__ */ jsx10("div", { children: /* @__PURE__ */ jsx10(ActionButton4, { primary: true, large: true, type: "submit", isDisabled: !url, children: "Create" }) })
980
986
  ] }) });
981
987
  }
982
988
 
@@ -988,7 +994,8 @@ async function createImageServiceAnnotation(data, ctx) {
988
994
  type: "Annotation"
989
995
  };
990
996
  const targetType = ctx.options.targetType;
991
- const resource = await ctx.create("@manifest-editor/image-service-creator", data, {
997
+ const createImage = creatorHelper(ctx, "Annotation", "body", "@manifest-editor/image-service-creator");
998
+ const resource = await createImage(data, {
992
999
  parent: { resource: annotation, property: "body" }
993
1000
  });
994
1001
  if (targetType === "Annotation") {
@@ -1001,24 +1008,39 @@ async function createImageServiceAnnotation(data, ctx) {
1001
1008
  }
1002
1009
  if (targetType === "Canvas") {
1003
1010
  const canvasId = ctx.generateId("canvas");
1004
- const pageId = ctx.generateId("annotation-page", { id: canvasId, type: "Canvas" });
1011
+ const pageId = ctx.generateId("annotation-page", {
1012
+ id: canvasId,
1013
+ type: "Canvas"
1014
+ });
1005
1015
  const annotationResource = ctx.embed({
1006
1016
  ...annotation,
1007
1017
  motivation: "painting",
1008
1018
  body: [resource],
1009
- target: { type: "SpecificResource", source: { id: canvasId, type: "Canvas" } }
1019
+ target: {
1020
+ type: "SpecificResource",
1021
+ source: { id: canvasId, type: "Canvas" }
1022
+ }
1010
1023
  });
1011
1024
  const page = ctx.embed({
1012
1025
  id: pageId,
1013
1026
  type: "AnnotationPage",
1014
1027
  items: [annotationResource]
1015
1028
  });
1029
+ let thumbnail = void 0;
1030
+ if (data.service?.sizes) {
1031
+ const createThumbnail2 = creatorHelper(ctx, "Canvas", "thumbnail", "@manifest-editor/thumbnail-image");
1032
+ thumbnail = await createThumbnail2({
1033
+ service: data.service,
1034
+ width: data.thumbnailSize || 400
1035
+ });
1036
+ }
1016
1037
  return ctx.embed({
1017
1038
  id: canvasId,
1018
1039
  type: "Canvas",
1019
1040
  label: data.label || { en: ["Untitled canvas"] },
1020
1041
  height: resource.resource.height || 1e3,
1021
1042
  width: resource.resource.width || 1e3,
1043
+ thumbnail: thumbnail ? [thumbnail] : void 0,
1022
1044
  items: [page]
1023
1045
  });
1024
1046
  }
@@ -1028,9 +1050,8 @@ function CreateImageServiceAnnotationForm(props) {
1028
1050
  }
1029
1051
 
1030
1052
  // src/Annotation/ImageServiceAnnotation/index.tsx
1031
- import { IIIFLogo } from "@manifest-editor/components";
1032
1053
  import { jsx as jsx12 } from "react/jsx-runtime";
1033
- var imageServiceAnnotation = {
1054
+ var imageServiceAnnotation = defineCreator4({
1034
1055
  id: "@manifest-editor/image-service-annotation",
1035
1056
  create: createImageServiceAnnotation,
1036
1057
  label: "IIIF Image",
@@ -1052,11 +1073,21 @@ var imageServiceAnnotation = {
1052
1073
  staticFields: {
1053
1074
  type: "Annotation"
1054
1075
  }
1055
- };
1076
+ });
1077
+
1078
+ // src/Annotation/ImageUrlAnnotation/index.tsx
1079
+ import { AddImageIcon as AddImageIcon2 } from "@manifest-editor/components";
1080
+ import { defineCreator as defineCreator5 } from "@manifest-editor/creator-api";
1081
+
1082
+ // src/Annotation/ImageUrlAnnotation/create-image-url-annotation.tsx
1083
+ import {
1084
+ creatorHelper as creatorHelper2
1085
+ } from "@manifest-editor/creator-api";
1056
1086
 
1057
1087
  // src/ContentResource/ImageUrlCreator/create-image-url.tsx
1058
- import { InputContainer as InputContainer5, InputLabel as InputLabel5, Input as Input4 } from "@manifest-editor/editors";
1059
- import { getImageDimensions, getFormat } from "@manifest-editor/shell";
1088
+ import { ActionButton as ActionButton5 } from "@manifest-editor/components";
1089
+ import { Input as Input4, InputContainer as InputContainer4, InputLabel as InputLabel4 } from "@manifest-editor/editors";
1090
+ import { getFormat, getImageDimensions } from "@manifest-editor/shell";
1060
1091
  import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
1061
1092
  async function createImageUrl(data, ctx) {
1062
1093
  if (!data.height || !data.width) {
@@ -1085,11 +1116,11 @@ function CreateImageUrlForm(props) {
1085
1116
  }
1086
1117
  };
1087
1118
  return /* @__PURE__ */ jsx13(PaddedSidebarContainer, { children: /* @__PURE__ */ jsxs8("form", { onSubmit, children: [
1088
- /* @__PURE__ */ jsxs8(InputContainer5, { $wide: true, children: [
1089
- /* @__PURE__ */ jsx13(InputLabel5, { htmlFor: "id", children: "Link to Image" }),
1119
+ /* @__PURE__ */ jsxs8(InputContainer4, { $wide: true, children: [
1120
+ /* @__PURE__ */ jsx13(InputLabel4, { htmlFor: "id", children: "Link to Image" }),
1090
1121
  /* @__PURE__ */ jsx13(Input4, { id: "url", name: "url", defaultValue: "" })
1091
1122
  ] }),
1092
- /* @__PURE__ */ jsx13(Button, { type: "submit", children: "Create" })
1123
+ /* @__PURE__ */ jsx13(ActionButton5, { primary: true, large: true, type: "submit", children: "Create" })
1093
1124
  ] }) });
1094
1125
  }
1095
1126
 
@@ -1101,25 +1132,32 @@ async function createImageUrlAnnotation(data, ctx) {
1101
1132
  type: "Annotation"
1102
1133
  };
1103
1134
  const targetType = ctx.options.targetType;
1104
- const resource = await ctx.create("@manifest-editor/image-url-creator", data, {
1135
+ const createImage = creatorHelper2(ctx, "Annotation", "body", "@manifest-editor/image-url-creator");
1136
+ const resource = await createImage(data, {
1105
1137
  parent: { resource: annotation, property: "body" }
1106
1138
  });
1107
1139
  if (targetType === "Annotation") {
1108
- return {
1140
+ return ctx.embed({
1109
1141
  ...annotation,
1110
1142
  body: [resource],
1111
1143
  motivation: data.motivation || "painting",
1112
1144
  target: ctx.getTarget()
1113
- };
1145
+ });
1114
1146
  }
1115
1147
  if (targetType === "Canvas") {
1116
1148
  const canvasId = ctx.generateId("canvas");
1117
- const pageId = ctx.generateId("annotation-page", { id: canvasId, type: "Canvas" });
1149
+ const pageId = ctx.generateId("annotation-page", {
1150
+ id: canvasId,
1151
+ type: "Canvas"
1152
+ });
1118
1153
  const annotationResource = ctx.embed({
1119
1154
  ...annotation,
1120
1155
  motivation: "painting",
1121
1156
  body: [resource],
1122
- target: { type: "SpecificResource", source: { id: canvasId, type: "Canvas" } }
1157
+ target: {
1158
+ type: "SpecificResource",
1159
+ source: { id: canvasId, type: "Canvas" }
1160
+ }
1123
1161
  });
1124
1162
  const page = ctx.embed({
1125
1163
  id: pageId,
@@ -1135,15 +1173,15 @@ async function createImageUrlAnnotation(data, ctx) {
1135
1173
  items: [page]
1136
1174
  });
1137
1175
  }
1176
+ throw new Error("Unsupported target type");
1138
1177
  }
1139
1178
  function CreateImageUrlAnnotationForm(props) {
1140
1179
  return /* @__PURE__ */ jsx14(CreateImageUrlForm, { ...props });
1141
1180
  }
1142
1181
 
1143
1182
  // src/Annotation/ImageUrlAnnotation/index.tsx
1144
- import { AddImageIcon as AddImageIcon2 } from "@manifest-editor/components";
1145
1183
  import { jsx as jsx15 } from "react/jsx-runtime";
1146
- var imageUrlAnnotation = {
1184
+ var imageUrlAnnotation = defineCreator5({
1147
1185
  id: "@manifest-editor/image-url-annotation",
1148
1186
  create: createImageUrlAnnotation,
1149
1187
  label: "Image",
@@ -1165,17 +1203,91 @@ var imageUrlAnnotation = {
1165
1203
  staticFields: {
1166
1204
  type: "Annotation"
1167
1205
  }
1168
- };
1206
+ });
1207
+
1208
+ // src/Annotation/ImageUrlListAnnotation/index.tsx
1209
+ import { ImageListIcon } from "@manifest-editor/components";
1210
+ import { defineCreator as defineCreator6 } from "@manifest-editor/creator-api";
1211
+
1212
+ // src/ContentResource/ImageUrlListCreator/create-image-url-list.tsx
1213
+ import { ActionButton as ActionButton6, Form } from "@manifest-editor/components";
1214
+ import {
1215
+ creatorHelper as creatorHelper3
1216
+ } from "@manifest-editor/creator-api";
1217
+ import { jsx as jsx16, jsxs as jsxs9 } from "react/jsx-runtime";
1218
+ async function createImageUrlList(payload, ctx) {
1219
+ const items = [];
1220
+ const createImage = creatorHelper3(ctx, "Annotation", "body", "@manifest-editor/image-url-creator");
1221
+ for (const image of payload.images) {
1222
+ items.push(await createImage(image, ctx.options));
1223
+ }
1224
+ return items;
1225
+ }
1226
+ function CreateImageUrlListForm(props) {
1227
+ const onSubmit = (e) => {
1228
+ e.preventDefault();
1229
+ const data = new FormData(e.target);
1230
+ const formData = Object.fromEntries(data.entries());
1231
+ if (formData.urls) {
1232
+ props.runCreate({ images: formData.urls.split("\n").map((url) => ({ url })) });
1233
+ }
1234
+ };
1235
+ return /* @__PURE__ */ jsx16(PaddedSidebarContainer, { children: /* @__PURE__ */ jsxs9(Form.Form, { onSubmit, children: [
1236
+ /* @__PURE__ */ jsxs9(Form.InputContainer, { className: "mb-4", children: [
1237
+ /* @__PURE__ */ jsx16(Form.Label, { children: "Enter a list of URLs (one per line)" }),
1238
+ /* @__PURE__ */ jsx16(Form.TextArea, { name: "urls", rows: "10" })
1239
+ ] }),
1240
+ /* @__PURE__ */ jsx16(ActionButton6, { primary: true, large: true, type: "submit", children: "Create" })
1241
+ ] }) });
1242
+ }
1243
+
1244
+ // src/Annotation/ImageUrlListAnnotation/create-image-url-list-annotation.tsx
1245
+ import { creatorHelper as creatorHelper4 } from "@manifest-editor/creator-api";
1246
+ async function createImageUrlListAnnotation(payload, ctx) {
1247
+ const items = [];
1248
+ const createAnnotation = creatorHelper4(ctx, "AnnotationPage", "items", "@manifest-editor/image-url-annotation");
1249
+ for (const image of payload.images) {
1250
+ items.push(await createAnnotation(image, ctx.options));
1251
+ }
1252
+ return items;
1253
+ }
1254
+
1255
+ // src/Annotation/ImageUrlListAnnotation/index.tsx
1256
+ import { jsx as jsx17 } from "react/jsx-runtime";
1257
+ var imageUrlListAnnotation = defineCreator6({
1258
+ id: "@manifest-editor/image-url-list-annotation",
1259
+ create: createImageUrlListAnnotation,
1260
+ label: "List of Images",
1261
+ dependencies: ["@manifest-editor/image-url-annotation"],
1262
+ summary: "List of Images from URLs",
1263
+ tags: ["image"],
1264
+ icon: /* @__PURE__ */ jsx17(ImageListIcon, {}),
1265
+ render(ctx) {
1266
+ return /* @__PURE__ */ jsx17(CreateImageUrlListForm, { ...ctx });
1267
+ },
1268
+ resourceType: "Annotation",
1269
+ resourceFields: ["id", "type", "motivation", "body", "target"],
1270
+ additionalTypes: ["Canvas"],
1271
+ supports: {
1272
+ parentTypes: ["AnnotationPage", "Manifest"],
1273
+ parentFields: ["items"]
1274
+ },
1275
+ sideEffects: [resizeToFitService, resizeResourceToEmptyCanvas, repositionMultipleImages],
1276
+ staticFields: {
1277
+ type: "Annotation"
1278
+ }
1279
+ });
1169
1280
 
1170
1281
  // src/Annotation/NoBodyAnnotation/index.tsx
1171
1282
  import { EmptyCanvasIcon } from "@manifest-editor/components";
1172
- import { jsx as jsx16 } from "react/jsx-runtime";
1173
- var noBodyAnnotation = {
1283
+ import { defineCreator as defineCreator7 } from "@manifest-editor/creator-api";
1284
+ import { jsx as jsx18 } from "react/jsx-runtime";
1285
+ var noBodyAnnotation = defineCreator7({
1174
1286
  id: "@manifest-editor/no-body-annotation",
1175
1287
  create: createNoBodyAnnotation,
1176
1288
  label: "Annotation without body",
1177
1289
  summary: "Add an annotation that only has motivation and target",
1178
- icon: /* @__PURE__ */ jsx16(EmptyCanvasIcon, {}),
1290
+ icon: /* @__PURE__ */ jsx18(EmptyCanvasIcon, {}),
1179
1291
  resourceType: "Annotation",
1180
1292
  resourceFields: ["id", "type", "motivation", "target"],
1181
1293
  supports: {
@@ -1188,7 +1300,7 @@ var noBodyAnnotation = {
1188
1300
  staticFields: {
1189
1301
  type: "Annotation"
1190
1302
  }
1191
- };
1303
+ });
1192
1304
  function createNoBodyAnnotation(data, ctx) {
1193
1305
  return ctx.embed({
1194
1306
  id: ctx.generateId("annotation"),
@@ -1199,15 +1311,18 @@ function createNoBodyAnnotation(data, ctx) {
1199
1311
  });
1200
1312
  }
1201
1313
 
1314
+ // src/Annotation/VideoAnnotation/index.tsx
1315
+ import { VideoIcon } from "@manifest-editor/components";
1316
+ import { defineCreator as defineCreator8 } from "@manifest-editor/creator-api";
1317
+
1202
1318
  // src/Annotation/VideoAnnotation/create-video-annotation.tsx
1203
- import { getValue as getValue2 } from "@iiif/helpers";
1204
- import { InputContainer as InputContainer6, InputLabel as InputLabel6, Input as Input5, LanguageFieldEditor as LanguageFieldEditor4, DimensionsTriplet } from "@manifest-editor/editors";
1205
- import { ErrorMessage as ErrorMessage2 } from "@manifest-editor/components";
1206
- import { useState as useState5, useEffect as useEffect3 } from "react";
1319
+ import { getValue as getValue3 } from "@iiif/helpers";
1320
+ import { ActionButton as ActionButton7, ErrorMessage as ErrorMessage2 } from "@manifest-editor/components";
1321
+ import { DimensionsTriplet, Input as Input5, InputContainer as InputContainer5, InputLabel as InputLabel5, LanguageFieldEditor as LanguageFieldEditor4 } from "@manifest-editor/editors";
1207
1322
 
1208
1323
  // ../ui/ui/VideoPlayer/VideoPlayer.tsx
1209
1324
  import { CanvasPanel as CanvasPanel2, MediaPlayerProvider, useSimpleMediaPlayer } from "react-iiif-vault";
1210
- import { jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
1325
+ import { jsx as jsx19, jsxs as jsxs10 } from "react/jsx-runtime";
1211
1326
  function VideoPlayer({
1212
1327
  media,
1213
1328
  onError,
@@ -1216,7 +1331,7 @@ function VideoPlayer({
1216
1331
  onDimensions
1217
1332
  }) {
1218
1333
  const [{ element, currentTime, progress }, state, actions] = useSimpleMediaPlayer({ duration });
1219
- return /* @__PURE__ */ jsxs9(
1334
+ return /* @__PURE__ */ jsxs10(
1220
1335
  MediaPlayerProvider,
1221
1336
  {
1222
1337
  element,
@@ -1225,7 +1340,7 @@ function VideoPlayer({
1225
1340
  currentTime,
1226
1341
  progress,
1227
1342
  children: [
1228
- /* @__PURE__ */ jsx17(
1343
+ /* @__PURE__ */ jsx19(
1229
1344
  "div",
1230
1345
  {
1231
1346
  style: {
@@ -1233,24 +1348,25 @@ function VideoPlayer({
1233
1348
  aspectRatio: `${media.width}/${media.height}`,
1234
1349
  position: "relative"
1235
1350
  },
1236
- children: /* @__PURE__ */ jsx17(CanvasPanel2.VideoHTML, { element, media, playPause: actions.playPause })
1351
+ children: /* @__PURE__ */ jsx19(CanvasPanel2.VideoHTML, { element, media, playPause: actions.playPause })
1237
1352
  }
1238
1353
  ),
1239
- /* @__PURE__ */ jsx17(MediaControls, { onError, onDuration, onDimensions })
1354
+ /* @__PURE__ */ jsx19(MediaControls, { onError, onDuration, onDimensions })
1240
1355
  ]
1241
1356
  }
1242
1357
  );
1243
1358
  }
1244
1359
 
1245
1360
  // src/Annotation/VideoAnnotation/create-video-annotation.tsx
1246
- import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
1361
+ import { useEffect as useEffect3, useState as useState6 } from "react";
1362
+ import { jsx as jsx20, jsxs as jsxs11 } from "react/jsx-runtime";
1247
1363
  async function createVideoAnnotation(data, ctx) {
1248
1364
  const annotation = {
1249
1365
  id: ctx.generateId("annotation"),
1250
1366
  type: "Annotation"
1251
1367
  };
1252
1368
  const targetType = ctx.options.targetType;
1253
- const body = await ctx.embed({
1369
+ const body = ctx.embed({
1254
1370
  id: data.url,
1255
1371
  type: "Video",
1256
1372
  format: "video/mp4",
@@ -1261,7 +1377,7 @@ async function createVideoAnnotation(data, ctx) {
1261
1377
  if (targetType === "Annotation") {
1262
1378
  return ctx.embed({
1263
1379
  ...annotation,
1264
- label: getValue2(data.label) && data.label,
1380
+ label: getValue3(data.label) && data.label,
1265
1381
  motivation: data.motivation || ctx.options.initialData?.motivation || "painting",
1266
1382
  body,
1267
1383
  target: ctx.getTarget()
@@ -1269,12 +1385,18 @@ async function createVideoAnnotation(data, ctx) {
1269
1385
  }
1270
1386
  if (targetType === "Canvas") {
1271
1387
  const canvasId = ctx.generateId("canvas");
1272
- const pageId = ctx.generateId("annotation-page", { id: canvasId, type: "Canvas" });
1388
+ const pageId = ctx.generateId("annotation-page", {
1389
+ id: canvasId,
1390
+ type: "Canvas"
1391
+ });
1273
1392
  const annotationResource = ctx.embed({
1274
1393
  ...annotation,
1275
1394
  motivation: "painting",
1276
1395
  body,
1277
- target: { type: "SpecificResource", source: { id: canvasId, type: "Canvas" } }
1396
+ target: {
1397
+ type: "SpecificResource",
1398
+ source: { id: canvasId, type: "Canvas" }
1399
+ }
1278
1400
  });
1279
1401
  const page = ctx.embed({
1280
1402
  id: pageId,
@@ -1293,12 +1415,12 @@ async function createVideoAnnotation(data, ctx) {
1293
1415
  }
1294
1416
  }
1295
1417
  function CreateVideoAnnotationForm(props) {
1296
- const [url, setUrl] = useState5("");
1297
- const [duration, setDuration] = useState5(0);
1298
- const [width, setWidth] = useState5(0);
1299
- const [height, setHeight] = useState5(0);
1300
- const [error, setError] = useState5("");
1301
- const [label, setLabel] = useState5({ en: [""] });
1418
+ const [url, setUrl] = useState6("");
1419
+ const [duration, setDuration] = useState6(0);
1420
+ const [width, setWidth] = useState6(0);
1421
+ const [height, setHeight] = useState6(0);
1422
+ const [error, setError] = useState6("");
1423
+ const [label, setLabel] = useState6({ en: [""] });
1302
1424
  const onSubmit = () => {
1303
1425
  props.runCreate({
1304
1426
  url,
@@ -1316,13 +1438,13 @@ function CreateVideoAnnotationForm(props) {
1316
1438
  setLabel({ en: [labelFromUrl || ""] });
1317
1439
  }
1318
1440
  }, [url]);
1319
- return /* @__PURE__ */ jsxs10(PaddedSidebarContainer, { children: [
1320
- error ? /* @__PURE__ */ jsx18(ErrorMessage2, { children: error }) : null,
1321
- /* @__PURE__ */ jsxs10(InputContainer6, { children: [
1322
- /* @__PURE__ */ jsx18(InputLabel6, { htmlFor: "video-url", children: "URL" }),
1323
- /* @__PURE__ */ jsx18(Input5, { type: "text", id: "video-url", value: url, onChange: (e) => setUrl(e.target.value) })
1441
+ return /* @__PURE__ */ jsxs11(PaddedSidebarContainer, { children: [
1442
+ error ? /* @__PURE__ */ jsx20(ErrorMessage2, { children: error }) : null,
1443
+ /* @__PURE__ */ jsxs11(InputContainer5, { $wide: true, children: [
1444
+ /* @__PURE__ */ jsx20(InputLabel5, { htmlFor: "video-url", children: "URL" }),
1445
+ /* @__PURE__ */ jsx20(Input5, { type: "text", id: "video-url", value: url, onChange: (e) => setUrl(e.target.value) })
1324
1446
  ] }),
1325
- url && !error ? /* @__PURE__ */ jsx18("div", { children: /* @__PURE__ */ jsx18(
1447
+ url && !error ? /* @__PURE__ */ jsx20("div", { children: /* @__PURE__ */ jsx20(
1326
1448
  LanguageFieldEditor4,
1327
1449
  {
1328
1450
  containerId: "label",
@@ -1331,9 +1453,9 @@ function CreateVideoAnnotationForm(props) {
1331
1453
  fields: label,
1332
1454
  onSave: (e) => setLabel(e.toInternationalString())
1333
1455
  },
1334
- url + "__" + duration
1456
+ `${url}__${duration}`
1335
1457
  ) }) : null,
1336
- url && !error ? /* @__PURE__ */ jsx18(
1458
+ url && !error ? /* @__PURE__ */ jsx20("div", { className: "mb-4 bg-black", children: /* @__PURE__ */ jsx20(
1337
1459
  VideoPlayer,
1338
1460
  {
1339
1461
  duration,
@@ -1351,8 +1473,8 @@ function CreateVideoAnnotationForm(props) {
1351
1473
  setHeight(h || 0);
1352
1474
  }
1353
1475
  }
1354
- ) : null,
1355
- !error && (duration || width || height) ? /* @__PURE__ */ jsx18(InputContainer6, { $wide: true, children: /* @__PURE__ */ jsx18(
1476
+ ) }) : null,
1477
+ !error && (duration || width || height) ? /* @__PURE__ */ jsx20(InputContainer5, { $wide: true, children: /* @__PURE__ */ jsx20(
1356
1478
  DimensionsTriplet,
1357
1479
  {
1358
1480
  widthId: "width",
@@ -1366,21 +1488,20 @@ function CreateVideoAnnotationForm(props) {
1366
1488
  changeDuration: (v) => setDuration(v)
1367
1489
  }
1368
1490
  ) }) : null,
1369
- url && !error && /* @__PURE__ */ jsx18(Button, { onClick: onSubmit, children: "Add video" })
1491
+ /* @__PURE__ */ jsx20(ActionButton7, { primary: true, large: true, type: "button", onPress: onSubmit, isDisabled: !url || !!error, children: "Add video" })
1370
1492
  ] });
1371
1493
  }
1372
1494
 
1373
1495
  // src/Annotation/VideoAnnotation/index.tsx
1374
- import { VideoIcon } from "@manifest-editor/components";
1375
- import { jsx as jsx19 } from "react/jsx-runtime";
1376
- var videoAnnotation = {
1496
+ import { jsx as jsx21 } from "react/jsx-runtime";
1497
+ var videoAnnotation = defineCreator8({
1377
1498
  id: "@manifest-editor/video-annotation",
1378
1499
  create: createVideoAnnotation,
1379
1500
  label: "Video",
1380
1501
  summary: "Video annotation",
1381
- icon: /* @__PURE__ */ jsx19(VideoIcon, {}),
1502
+ icon: /* @__PURE__ */ jsx21(VideoIcon, {}),
1382
1503
  render(ctx) {
1383
- return /* @__PURE__ */ jsx19(CreateVideoAnnotationForm, { ...ctx });
1504
+ return /* @__PURE__ */ jsx21(CreateVideoAnnotationForm, { ...ctx });
1384
1505
  },
1385
1506
  resourceType: "Annotation",
1386
1507
  resourceFields: ["id", "type", "motivation", "body", "target"],
@@ -1393,11 +1514,14 @@ var videoAnnotation = {
1393
1514
  staticFields: {
1394
1515
  type: "Annotation"
1395
1516
  }
1396
- };
1517
+ });
1518
+
1519
+ // src/AnnotationPage/EmptyAnnotationPage/index.tsx
1520
+ import { defineCreator as defineCreator9 } from "@manifest-editor/creator-api";
1397
1521
 
1398
1522
  // ../ui/icons/ThumbnailStripIcon.tsx
1399
- import { jsx as jsx20, jsxs as jsxs11 } from "react/jsx-runtime";
1400
- var ThumbnailStripIcon = () => /* @__PURE__ */ jsx20(
1523
+ import { jsx as jsx22, jsxs as jsxs12 } from "react/jsx-runtime";
1524
+ var ThumbnailStripIcon = () => /* @__PURE__ */ jsx22(
1401
1525
  "svg",
1402
1526
  {
1403
1527
  xmlns: "http://www.w3.org/2000/svg",
@@ -1406,21 +1530,28 @@ var ThumbnailStripIcon = () => /* @__PURE__ */ jsx20(
1406
1530
  width: "24px",
1407
1531
  fill: "#000000",
1408
1532
  transform: "scale(-1, 1)",
1409
- children: /* @__PURE__ */ jsxs11("g", { children: [
1410
- /* @__PURE__ */ jsx20("rect", { fill: "none", height: "24", width: "24" }),
1411
- /* @__PURE__ */ jsx20("path", { d: "M16,20H2V4h14V20z M18,8h4V4h-4V8z M18,20h4v-4h-4V20z M18,14h4v-4h-4V14z" })
1533
+ children: /* @__PURE__ */ jsxs12("g", { children: [
1534
+ /* @__PURE__ */ jsx22("rect", { fill: "none", height: "24", width: "24" }),
1535
+ /* @__PURE__ */ jsx22("path", { d: "M16,20H2V4h14V20z M18,8h4V4h-4V8z M18,20h4v-4h-4V20z M18,14h4v-4h-4V14z" })
1412
1536
  ] })
1413
1537
  }
1414
1538
  );
1415
1539
 
1416
1540
  // src/AnnotationPage/EmptyAnnotationPage/index.tsx
1417
- import { jsx as jsx21 } from "react/jsx-runtime";
1418
- var emptyAnnotationPage = {
1541
+ import { jsx as jsx23 } from "react/jsx-runtime";
1542
+ var emptyAnnotationPage = defineCreator9({
1419
1543
  id: "@manifest-editor/empty-annotation-page",
1420
- create: createEmptyAnnotationPage,
1544
+ create: (data, ctx) => {
1545
+ return ctx.embed({
1546
+ id: ctx.generateId("annotations"),
1547
+ label: data.label,
1548
+ type: "AnnotationPage",
1549
+ items: []
1550
+ });
1551
+ },
1421
1552
  label: "Empty annotation page",
1422
1553
  summary: "AnnotationPage with nothing",
1423
- icon: /* @__PURE__ */ jsx21(ThumbnailStripIcon, {}),
1554
+ icon: /* @__PURE__ */ jsx23(ThumbnailStripIcon, {}),
1424
1555
  resourceType: "AnnotationPage",
1425
1556
  resourceFields: ["id", "type", "items"],
1426
1557
  supports: {
@@ -1431,50 +1562,44 @@ var emptyAnnotationPage = {
1431
1562
  Range: ["annotations"]
1432
1563
  }
1433
1564
  }
1434
- };
1435
- async function createEmptyAnnotationPage(data, ctx) {
1436
- return ctx.embed({
1437
- id: ctx.generateId("annotations"),
1438
- label: data.label,
1439
- type: "AnnotationPage",
1440
- items: []
1441
- });
1442
- }
1565
+ });
1443
1566
 
1444
1567
  // src/Canvas/EmptyCanvas/index.tsx
1445
1568
  import { EmptyCanvasIcon as EmptyCanvasIcon2 } from "@manifest-editor/components";
1446
- import { jsx as jsx22 } from "react/jsx-runtime";
1447
- var emptyCanvas = {
1569
+ import { defineCreator as defineCreator10 } from "@manifest-editor/creator-api";
1570
+ import { jsx as jsx24 } from "react/jsx-runtime";
1571
+ var emptyCanvas = defineCreator10({
1448
1572
  id: "@manifest-editor/empty-canvas",
1449
- create: createEmptyCanvas,
1573
+ create: (data, ctx) => {
1574
+ const canvasId = ctx.generateId("canvas");
1575
+ const page = ctx.embed({
1576
+ id: ctx.generateId("annotation-page", { id: canvasId, type: "Canvas" }),
1577
+ type: "AnnotationPage",
1578
+ items: []
1579
+ });
1580
+ return {
1581
+ id: canvasId,
1582
+ type: "Canvas",
1583
+ label: data.label || { en: [""] },
1584
+ height: data.height || 1e3,
1585
+ width: data.width || 1e3,
1586
+ items: [page]
1587
+ };
1588
+ },
1450
1589
  label: "Empty canvas",
1451
1590
  summary: "No content",
1452
- icon: /* @__PURE__ */ jsx22(EmptyCanvasIcon2, {}),
1591
+ icon: /* @__PURE__ */ jsx24(EmptyCanvasIcon2, {}),
1453
1592
  resourceType: "Canvas",
1454
1593
  resourceFields: ["id", "type", "label", "height", "width", "items"],
1455
1594
  supports: {
1456
1595
  parentTypes: ["Manifest"],
1457
1596
  parentFields: ["items"]
1458
1597
  }
1459
- };
1460
- async function createEmptyCanvas(data, ctx) {
1461
- const canvasId = ctx.generateId("canvas");
1462
- const page = ctx.embed({
1463
- id: ctx.generateId("annotation-page", { id: canvasId, type: "Canvas" }),
1464
- type: "AnnotationPage",
1465
- items: []
1466
- });
1467
- return {
1468
- id: canvasId,
1469
- type: "Canvas",
1470
- label: data.label || { en: [""] },
1471
- height: data.height || 1e3,
1472
- width: data.width || 1e3,
1473
- items: [page]
1474
- };
1475
- }
1598
+ });
1476
1599
 
1477
1600
  // src/Canvas/InternalCanvas/index.tsx
1601
+ import { defineCreator as defineCreator11 } from "@manifest-editor/creator-api";
1602
+ import { IIIFExplorer } from "@manifest-editor/iiif-browser";
1478
1603
  import { useManifest, useVault } from "react-iiif-vault";
1479
1604
 
1480
1605
  // ../../node_modules/.pnpm/tiny-invariant@1.3.3/node_modules/tiny-invariant/dist/esm/tiny-invariant.js
@@ -1493,27 +1618,26 @@ function invariant(condition, message) {
1493
1618
  }
1494
1619
 
1495
1620
  // src/Canvas/InternalCanvas/index.tsx
1496
- import { IIIFExplorer } from "@manifest-editor/iiif-browser";
1497
- import { jsx as jsx23 } from "react/jsx-runtime";
1498
- var internalCanvas = {
1621
+ import { jsx as jsx25 } from "react/jsx-runtime";
1622
+ var internalCanvas = defineCreator11({
1499
1623
  id: "@manifest-editor/internal-canvas",
1500
1624
  create: createInternalCanvas,
1501
1625
  label: "Internal canvas link",
1502
1626
  summary: "Canvas from the same manifest",
1503
- icon: /* @__PURE__ */ jsx23(ThumbnailStripIcon, {}),
1627
+ icon: /* @__PURE__ */ jsx25(ThumbnailStripIcon, {}),
1504
1628
  resourceType: "Canvas",
1505
1629
  resourceFields: ["id", "type", "label"],
1506
1630
  supports: {
1507
1631
  parentTypes: ["Manifest"],
1508
1632
  parentFields: ["start"]
1509
1633
  },
1510
- render: (ctx) => /* @__PURE__ */ jsx23(InternalCanvas, { ...ctx })
1511
- };
1634
+ render: (ctx) => /* @__PURE__ */ jsx25(InternalCanvas, { ...ctx })
1635
+ });
1512
1636
  function InternalCanvas(props) {
1513
1637
  const manifest = useManifest();
1514
1638
  const vault = useVault();
1515
1639
  invariant(manifest, "Manifest is not loaded");
1516
- return /* @__PURE__ */ jsx23(
1640
+ return /* @__PURE__ */ jsx25(
1517
1641
  IIIFExplorer,
1518
1642
  {
1519
1643
  vault,
@@ -1539,11 +1663,22 @@ async function createInternalCanvas(data, ctx) {
1539
1663
  return ctx.embed({ id: data.id, type: "Canvas" });
1540
1664
  }
1541
1665
 
1666
+ // src/ContentResource/HTMLBodyCreator/index.tsx
1667
+ import { defineCreator as defineCreator12 } from "@manifest-editor/creator-api";
1668
+
1669
+ // ../ui/icons/TextFormatIcon.tsx
1670
+ import { jsx as jsx26, jsxs as jsxs13 } from "react/jsx-runtime";
1671
+ var TextFormatIcon = (props) => /* @__PURE__ */ jsxs13("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", height: "1em", width: "1em", ...props, children: [
1672
+ /* @__PURE__ */ jsx26("path", { d: "M0 0h24v24H0z", fill: "none" }),
1673
+ /* @__PURE__ */ jsx26("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" })
1674
+ ] });
1675
+
1542
1676
  // src/ContentResource/HTMLBodyCreator/create-html-body.tsx
1543
- import { InputContainer as InputContainer7, InputLabel as InputLabel7, RichTextLanguageField } from "@manifest-editor/editors";
1677
+ import { ActionButton as ActionButton8 } from "@manifest-editor/components";
1678
+ import { InputContainer as InputContainer6, InputLabel as InputLabel6, RichTextLanguageField } from "@manifest-editor/editors";
1544
1679
  import { useConfig } from "@manifest-editor/shell";
1545
- import { useState as useState6 } from "react";
1546
- import { jsx as jsx24, jsxs as jsxs12 } from "react/jsx-runtime";
1680
+ import { useState as useState7 } from "react";
1681
+ import { jsx as jsx27, jsxs as jsxs14 } from "react/jsx-runtime";
1547
1682
  async function createHtmlBody(data, ctx) {
1548
1683
  return ctx.embed({
1549
1684
  id: ctx.generateId(`html/${data.language}`),
@@ -1555,18 +1690,18 @@ async function createHtmlBody(data, ctx) {
1555
1690
  }
1556
1691
  function CreateHTMLBodyForm(props) {
1557
1692
  const { i18n } = useConfig();
1558
- const [body, setBodyValue] = useState6("<p></p>");
1559
- const [language, setLang] = useState6(i18n.defaultLanguage);
1693
+ const [body, setBodyValue] = useState7("<p></p>");
1694
+ const [language, setLang] = useState7(i18n.defaultLanguage);
1560
1695
  const onSubmit = () => {
1561
1696
  props.runCreate({
1562
1697
  language,
1563
1698
  body
1564
1699
  });
1565
1700
  };
1566
- return /* @__PURE__ */ jsxs12(PaddedSidebarContainer, { children: [
1567
- /* @__PURE__ */ jsxs12(InputContainer7, { children: [
1568
- /* @__PURE__ */ jsx24(InputLabel7, { children: "HTML Body" }),
1569
- /* @__PURE__ */ jsx24(
1701
+ return /* @__PURE__ */ jsxs14(PaddedSidebarContainer, { children: [
1702
+ /* @__PURE__ */ jsxs14(InputContainer6, { children: [
1703
+ /* @__PURE__ */ jsx27(InputLabel6, { children: "HTML Body" }),
1704
+ /* @__PURE__ */ jsx27(
1570
1705
  RichTextLanguageField,
1571
1706
  {
1572
1707
  value: body,
@@ -1577,27 +1712,20 @@ function CreateHTMLBodyForm(props) {
1577
1712
  }
1578
1713
  )
1579
1714
  ] }),
1580
- /* @__PURE__ */ jsx24(Button, { onClick: () => onSubmit(), children: "Create" })
1715
+ /* @__PURE__ */ jsx27(ActionButton8, { primary: true, large: true, type: "button", onPress: onSubmit, children: "Create" })
1581
1716
  ] });
1582
1717
  }
1583
1718
 
1584
- // ../ui/icons/TextFormatIcon.tsx
1585
- import { jsx as jsx25, jsxs as jsxs13 } from "react/jsx-runtime";
1586
- var TextFormatIcon = (props) => /* @__PURE__ */ jsxs13("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", height: "1em", width: "1em", ...props, children: [
1587
- /* @__PURE__ */ jsx25("path", { d: "M0 0h24v24H0z", fill: "none" }),
1588
- /* @__PURE__ */ jsx25("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" })
1589
- ] });
1590
-
1591
1719
  // src/ContentResource/HTMLBodyCreator/index.tsx
1592
- import { jsx as jsx26 } from "react/jsx-runtime";
1593
- var htmlBodyCreator = {
1720
+ import { jsx as jsx28 } from "react/jsx-runtime";
1721
+ var htmlBodyCreator = defineCreator12({
1594
1722
  id: "@manifest-editor/html-body-creator",
1595
1723
  create: createHtmlBody,
1596
1724
  label: "HTML Body",
1597
1725
  summary: "Add HTML annotation body",
1598
- icon: /* @__PURE__ */ jsx26(TextFormatIcon, {}),
1726
+ icon: /* @__PURE__ */ jsx28(TextFormatIcon, {}),
1599
1727
  render(ctx) {
1600
- return /* @__PURE__ */ jsx26(CreateHTMLBodyForm, { ...ctx });
1728
+ return /* @__PURE__ */ jsx28(CreateHTMLBodyForm, { ...ctx });
1601
1729
  },
1602
1730
  resourceType: "ContentResource",
1603
1731
  resourceFields: ["id", "language", "type", "format", "value"],
@@ -1609,121 +1737,165 @@ var htmlBodyCreator = {
1609
1737
  type: "TextualBody",
1610
1738
  format: "text/html"
1611
1739
  }
1612
- };
1740
+ });
1613
1741
 
1614
1742
  // src/ContentResource/IIIFBrowserCreator/index.tsx
1615
1743
  import { IIIFBrowserIcon } from "@manifest-editor/components";
1744
+ import { defineCreator as defineCreator13 } from "@manifest-editor/creator-api";
1616
1745
 
1617
1746
  // src/ContentResource/IIIFBrowserCreator/iiif-browser-creator.tsx
1618
- import {
1619
- normaliseContentState,
1620
- parseContentState
1621
- } from "@iiif/helpers";
1747
+ import { Vault } from "@iiif/helpers";
1748
+ import { getImageServices } from "@iiif/parser/image-3";
1622
1749
  import { lazy } from "react";
1750
+ function croppedRegion(imageServiceId, region, size) {
1751
+ return `${imageServiceId}/${Math.floor(region.x)},${Math.floor(region.y)},${Math.floor(region.width)},${Math.floor(
1752
+ region.height
1753
+ )}/${size}/0/default.jpg`;
1754
+ }
1623
1755
  async function createFromIIIFBrowserOutput(data, ctx) {
1624
1756
  const targetType = ctx.options.targetType;
1625
- if (Array.isArray(data.output)) {
1626
- throw new Error("Multiple items not yet supported");
1627
- }
1628
- const contentState = normaliseContentState(
1629
- typeof data.output === "string" ? parseContentState(data.output) : data.output
1630
- );
1631
- if (!contentState.target || contentState.target.length === 0) {
1632
- throw new Error("No target found in content state");
1633
- }
1634
- const target = contentState.target[0];
1635
- const type = target.source.type;
1636
- const previewVault = ctx.getPreviewVault();
1637
- if (targetType === "Canvas" || targetType === "Annotation") {
1638
- if (type === "Canvas") {
1639
- const canvasId = target.source.id;
1640
- const manifestId = target.source.partOf?.find(
1641
- (t) => t.type === "Manifest"
1642
- );
1643
- invariant(manifestId, "Could not load external resource without partOf");
1644
- const manifest = await previewVault.loadManifest(manifestId);
1645
- invariant(manifest, "Manifest not found");
1646
- const canvasRef = manifest.items.find((item) => item.id === canvasId);
1647
- invariant(canvasRef, "Canvas not found");
1648
- const canvas = previewVault.get(canvasRef);
1649
- if (targetType === "Canvas" && target.selector?.type !== "BoxSelector") {
1650
- return ctx.embed(previewVault.toPresentation3(canvas));
1651
- }
1652
- const annotationPage = previewVault.get(canvas.items[0]);
1653
- const annotation = previewVault.get(annotationPage.items[0]);
1654
- if (targetType === "Annotation" || targetType === "Canvas") {
1655
- const fullAnnotation = previewVault.toPresentation3(annotation);
1656
- if (fullAnnotation?.body?.service) {
1657
- const width = fullAnnotation?.body.width;
1658
- const height = fullAnnotation?.body.height;
1659
- const service = Array.isArray(fullAnnotation?.body?.service) ? fullAnnotation?.body?.service[0] : fullAnnotation?.body?.service;
1660
- if (!service.width || !service.height) {
1661
- service.width = width;
1662
- service.height = height;
1757
+ const resources = data.output;
1758
+ const returnResources = [];
1759
+ for (const { resource, selector, parent } of resources) {
1760
+ const type = resource.type;
1761
+ const previewVault = new Vault();
1762
+ if (targetType === "Canvas" || targetType === "Annotation" || targetType === "ContentResource") {
1763
+ if (type === "Canvas") {
1764
+ const canvasId = resource.id;
1765
+ const manifestId = parent?.type === "Manifest" ? parent.id : void 0;
1766
+ invariant(manifestId, "Could not find Manifest");
1767
+ const manifest = await previewVault.loadManifest(manifestId);
1768
+ invariant(manifest, "Manifest not found");
1769
+ const canvasRef = manifest.items.find((item) => item.id === canvasId);
1770
+ invariant(canvasRef, "Canvas not found");
1771
+ const canvas = previewVault.get(canvasRef);
1772
+ if (targetType === "Canvas" && selector?.type !== "BoxSelector") {
1773
+ const fullCanvas = previewVault.toPresentation3(canvas);
1774
+ if (!fullCanvas.label) {
1775
+ fullCanvas.label = { en: ["Untitled canvas"] };
1663
1776
  }
1777
+ returnResources.push(ctx.embed(fullCanvas));
1778
+ continue;
1664
1779
  }
1665
- if (target.selector && target.selector.type === "BoxSelector") {
1666
- const selector = {
1667
- "@context": "http://iiif.io/api/annex/openannotation/context.json",
1668
- type: "iiif:ImageApiSelector",
1669
- region: [
1670
- ~~target.selector.spatial.x,
1671
- ~~target.selector.spatial.y,
1672
- ~~target.selector.spatial.width,
1673
- ~~target.selector.spatial.height
1674
- ].join(",")
1675
- };
1676
- fullAnnotation.body = {
1677
- id: ctx.generateId("SpecificResource", annotation),
1678
- type: "SpecificResource",
1679
- source: fullAnnotation.body,
1680
- selector
1681
- };
1682
- if (targetType === "Canvas") {
1683
- const canvasId2 = ctx.generateId("Canvas", annotation);
1684
- fullAnnotation.target = canvasId2;
1685
- const pageId = ctx.generateId("Page", annotation);
1686
- const annotationPage2 = ctx.embed({
1687
- id: pageId,
1688
- type: "AnnotationPage",
1689
- items: [fullAnnotation]
1690
- });
1691
- return ctx.embed({
1692
- id: canvasId2,
1693
- type: "Canvas",
1694
- width: ~~target.selector.spatial.width,
1695
- height: ~~target.selector.spatial.height,
1696
- items: [annotationPage2]
1697
- });
1780
+ const annotationPage = previewVault.get(canvas.items[0]);
1781
+ const annotation = previewVault.get(annotationPage.items[0]);
1782
+ if (targetType === "Annotation" || targetType === "Canvas" || targetType === "ContentResource") {
1783
+ const fullAnnotation = previewVault.toPresentation3(annotation);
1784
+ fullAnnotation.id = ctx.generateId("Annotation");
1785
+ let service = null;
1786
+ const dimensions = { width: 0, height: 0 };
1787
+ if (fullAnnotation?.body?.service) {
1788
+ const width = fullAnnotation?.body.width;
1789
+ const height = fullAnnotation?.body.height;
1790
+ service = getImageServices(fullAnnotation?.body)[0];
1791
+ if (service && (!service.width || !service.height)) {
1792
+ service.width = width;
1793
+ service.height = height;
1794
+ }
1795
+ dimensions.width = width;
1796
+ dimensions.height = height;
1797
+ if (data.trackSize) {
1798
+ data.trackSize(dimensions);
1799
+ }
1800
+ }
1801
+ if (selector?.type === "BoxSelector") {
1802
+ const imageApiSelector = {
1803
+ "@context": "http://iiif.io/api/annex/openannotation/context.json",
1804
+ type: "iiif:ImageApiSelector",
1805
+ region: [
1806
+ ~~selector.spatial.x,
1807
+ ~~selector.spatial.y,
1808
+ ~~selector.spatial.width,
1809
+ ~~selector.spatial.height
1810
+ ].join(",")
1811
+ };
1812
+ const newBody = { ...fullAnnotation.body };
1813
+ let thumbnailId = "";
1814
+ if (service) {
1815
+ const id = service.id || service["@id"] || "";
1816
+ if (id) {
1817
+ newBody.id = croppedRegion(id, selector.spatial, "max");
1818
+ thumbnailId = croppedRegion(id, selector.spatial, "512,");
1819
+ }
1820
+ }
1821
+ fullAnnotation.body = {
1822
+ id: ctx.generateId("SpecificResource", annotation),
1823
+ type: "SpecificResource",
1824
+ source: newBody,
1825
+ selector: imageApiSelector
1826
+ };
1827
+ if (data.trackSize) {
1828
+ data.trackSize({
1829
+ width: ~~selector.spatial.width,
1830
+ height: ~~selector.spatial.height
1831
+ });
1832
+ }
1833
+ if (targetType === "ContentResource") {
1834
+ returnResources.push(fullAnnotation.body);
1835
+ continue;
1836
+ }
1837
+ if (targetType === "Canvas") {
1838
+ const canvasId2 = ctx.generateId("Canvas", annotation);
1839
+ fullAnnotation.target = canvasId2;
1840
+ const pageId = ctx.generateId("Page", annotation);
1841
+ const annotationPage2 = ctx.embed({
1842
+ id: pageId,
1843
+ type: "AnnotationPage",
1844
+ items: [fullAnnotation]
1845
+ });
1846
+ returnResources.push(
1847
+ ctx.embed({
1848
+ id: canvasId2,
1849
+ type: "Canvas",
1850
+ label: { en: ["Untitled canvas"] },
1851
+ width: ~~selector.spatial.width,
1852
+ height: ~~selector.spatial.height,
1853
+ thumbnail: thumbnailId ? [
1854
+ ctx.embed({
1855
+ id: thumbnailId,
1856
+ type: "Image",
1857
+ format: "image/jpeg",
1858
+ width: 512,
1859
+ height: Math.round(selector.spatial.height / selector.spatial.width * 512)
1860
+ })
1861
+ ] : void 0,
1862
+ items: [annotationPage2]
1863
+ })
1864
+ );
1865
+ continue;
1866
+ }
1867
+ returnResources.push(
1868
+ ctx.embed({
1869
+ ...fullAnnotation,
1870
+ target: ctx.getTarget()
1871
+ })
1872
+ );
1873
+ continue;
1698
1874
  }
1699
- return ctx.embed({
1700
- ...fullAnnotation,
1701
- target: ctx.getTarget()
1702
- });
1875
+ returnResources.push(
1876
+ ctx.embed({
1877
+ ...previewVault.toPresentation3(annotation),
1878
+ target: ctx.getTarget()
1879
+ })
1880
+ );
1703
1881
  }
1704
- return ctx.embed({
1705
- ...previewVault.toPresentation3(annotation),
1706
- target: ctx.getTarget()
1707
- });
1708
1882
  }
1709
1883
  }
1710
1884
  }
1711
- throw new Error("Not yet supported.");
1885
+ return returnResources;
1712
1886
  }
1713
- var IIIFBrowserCreatorForm = lazy(
1714
- () => import("./iiif-browser-form.lazy-W42LJ6X2.js")
1715
- );
1887
+ var IIIFBrowserCreatorForm = lazy(() => import("./iiif-browser-form.lazy-FQDZQ3UW.js"));
1716
1888
 
1717
1889
  // src/ContentResource/IIIFBrowserCreator/index.tsx
1718
- import { jsx as jsx27 } from "react/jsx-runtime";
1719
- var iiifBrowserCreator = {
1890
+ import { jsx as jsx29 } from "react/jsx-runtime";
1891
+ var iiifBrowserCreator = defineCreator13({
1720
1892
  id: "@manifest-editor/iiif-browser-creator",
1721
1893
  create: createFromIIIFBrowserOutput,
1722
1894
  label: "IIIF Browser",
1723
1895
  summary: "Browse IIIF Resources",
1724
- icon: /* @__PURE__ */ jsx27(IIIFBrowserIcon, {}),
1896
+ icon: /* @__PURE__ */ jsx29(IIIFBrowserIcon, {}),
1725
1897
  render(ctx) {
1726
- return /* @__PURE__ */ jsx27(IIIFBrowserCreatorForm, { ...ctx });
1898
+ return /* @__PURE__ */ jsx29(IIIFBrowserCreatorForm, { ...ctx });
1727
1899
  },
1728
1900
  hiddenModal: true,
1729
1901
  tags: ["image", "image-service"],
@@ -1732,52 +1904,49 @@ var iiifBrowserCreator = {
1732
1904
  additionalTypes: ["Annotation", "Canvas"],
1733
1905
  supports: {
1734
1906
  parentTypes: ["Annotation", "Manifest", "AnnotationPage"],
1907
+ parentFields: ["body", "items"],
1735
1908
  parentFieldMap: {
1736
1909
  Annotation: ["body"],
1737
1910
  Manifest: ["items"],
1738
1911
  AnnotationPage: ["items"]
1739
1912
  }
1740
1913
  },
1741
- sideEffects: [
1742
- resizeToFitService,
1743
- resizeResourceToEmptyCanvas,
1744
- repositionMultipleImages
1745
- ],
1914
+ sideEffects: [resizeToFitService, resizeResourceToEmptyCanvas, repositionMultipleImages],
1746
1915
  staticFields: {}
1747
- };
1916
+ });
1748
1917
 
1749
1918
  // src/ContentResource/ImageServiceCreator/index.tsx
1750
- import { jsx as jsx28 } from "react/jsx-runtime";
1751
- var imageServiceCreator = {
1919
+ import { IIIFLogo as IIIFLogo2 } from "@manifest-editor/components";
1920
+ import { defineCreator as defineCreator14 } from "@manifest-editor/creator-api";
1921
+ import { jsx as jsx30 } from "react/jsx-runtime";
1922
+ var imageServiceCreator = defineCreator14({
1752
1923
  id: "@manifest-editor/image-service-creator",
1753
1924
  create: createImageServer,
1754
1925
  label: "Image Service",
1755
1926
  summary: "Add an image from Image Service",
1756
- icon: /* @__PURE__ */ jsx28(TextFormatIcon, {}),
1927
+ icon: /* @__PURE__ */ jsx30(IIIFLogo2, { style: { padding: 10 } }),
1757
1928
  render(ctx) {
1758
- return /* @__PURE__ */ jsx28(CreateImageServerForm, { ...ctx });
1929
+ return /* @__PURE__ */ jsx30(CreateImageServerForm, { ...ctx });
1759
1930
  },
1760
1931
  resourceType: "ContentResource",
1761
1932
  resourceFields: ["id", "type", "height", "width", "format", "service"],
1762
1933
  supports: {
1763
1934
  parentFields: ["logo", "body", "thumbnail"]
1764
- },
1765
- staticFields: {
1766
- type: "Image"
1767
1935
  }
1768
- };
1936
+ });
1769
1937
 
1770
1938
  // src/ContentResource/ImageUrlCreator/index.tsx
1771
1939
  import { AddImageIcon as AddImageIcon3 } from "@manifest-editor/components";
1772
- import { jsx as jsx29 } from "react/jsx-runtime";
1773
- var imageUrlCreator = {
1940
+ import { defineCreator as defineCreator15 } from "@manifest-editor/creator-api";
1941
+ import { jsx as jsx31 } from "react/jsx-runtime";
1942
+ var imageUrlCreator = defineCreator15({
1774
1943
  id: "@manifest-editor/image-url-creator",
1775
1944
  create: createImageUrl,
1776
1945
  label: "Image",
1777
1946
  summary: "Image from a URL",
1778
- icon: /* @__PURE__ */ jsx29(AddImageIcon3, {}),
1947
+ icon: /* @__PURE__ */ jsx31(AddImageIcon3, {}),
1779
1948
  render(ctx) {
1780
- return /* @__PURE__ */ jsx29(CreateImageUrlForm, { ...ctx });
1949
+ return /* @__PURE__ */ jsx31(CreateImageUrlForm, { ...ctx });
1781
1950
  },
1782
1951
  resourceType: "ContentResource",
1783
1952
  resourceFields: ["format"],
@@ -1787,12 +1956,39 @@ var imageUrlCreator = {
1787
1956
  staticFields: {
1788
1957
  type: "Image"
1789
1958
  }
1790
- };
1959
+ });
1960
+
1961
+ // src/ContentResource/ImageUrlListCreator/index.tsx
1962
+ import { ImageListIcon as ImageListIcon2 } from "@manifest-editor/components";
1963
+ import { defineCreator as defineCreator16 } from "@manifest-editor/creator-api";
1964
+ import { jsx as jsx32 } from "react/jsx-runtime";
1965
+ var imageUrlListCreator = defineCreator16({
1966
+ id: "@manifest-editor/image-url-list",
1967
+ label: "Image URL List",
1968
+ summary: "Image from a list of URLs",
1969
+ create: createImageUrlList,
1970
+ icon: /* @__PURE__ */ jsx32(ImageListIcon2, {}),
1971
+ render(ctx) {
1972
+ return /* @__PURE__ */ jsx32(CreateImageUrlListForm, { ...ctx });
1973
+ },
1974
+ resourceType: "ContentResource",
1975
+ resourceFields: ["format"],
1976
+ supports: {
1977
+ parentFields: ["logo", "body", "thumbnail"]
1978
+ },
1979
+ staticFields: {
1980
+ type: "Image"
1981
+ }
1982
+ });
1983
+
1984
+ // src/ContentResource/PlaintextCreator/index.tsx
1985
+ import { defineCreator as defineCreator17 } from "@manifest-editor/creator-api";
1791
1986
 
1792
1987
  // src/ContentResource/PlaintextCreator/create-plaintext.tsx
1793
- import { LanguageFieldEditor as LanguageFieldEditor5, InputContainer as InputContainer8, InputLabel as InputLabel8, Input as Input6 } from "@manifest-editor/editors";
1794
- import { useState as useState7 } from "react";
1795
- import { jsx as jsx30, jsxs as jsxs14 } from "react/jsx-runtime";
1988
+ import { ActionButton as ActionButton9 } from "@manifest-editor/components";
1989
+ import { Input as Input6, InputContainer as InputContainer7, InputLabel as InputLabel7, LanguageFieldEditor as LanguageFieldEditor5 } from "@manifest-editor/editors";
1990
+ import { useState as useState8 } from "react";
1991
+ import { jsx as jsx33, jsxs as jsxs15 } from "react/jsx-runtime";
1796
1992
  async function createPlaintext(data, ctx) {
1797
1993
  return ctx.embed({
1798
1994
  id: data.url,
@@ -1802,7 +1998,9 @@ async function createPlaintext(data, ctx) {
1802
1998
  });
1803
1999
  }
1804
2000
  function CreatePlaintextForm(props) {
1805
- const [label, setLabel] = useState7({ en: ["View as text"] });
2001
+ const [label, setLabel] = useState8({
2002
+ en: ["View as text"]
2003
+ });
1806
2004
  const onSubmit = (e) => {
1807
2005
  e.preventDefault();
1808
2006
  const data = new FormData(e.target);
@@ -1811,8 +2009,8 @@ function CreatePlaintextForm(props) {
1811
2009
  props.runCreate({ url: formData.url, label });
1812
2010
  }
1813
2011
  };
1814
- return /* @__PURE__ */ jsx30(PaddedSidebarContainer, { children: /* @__PURE__ */ jsxs14("form", { onSubmit, children: [
1815
- /* @__PURE__ */ jsx30(
2012
+ return /* @__PURE__ */ jsx33(PaddedSidebarContainer, { children: /* @__PURE__ */ jsxs15("form", { onSubmit, children: [
2013
+ /* @__PURE__ */ jsx33(
1816
2014
  LanguageFieldEditor5,
1817
2015
  {
1818
2016
  focusId: "label",
@@ -1821,24 +2019,24 @@ function CreatePlaintextForm(props) {
1821
2019
  onSave: (e) => setLabel(e.toInternationalString())
1822
2020
  }
1823
2021
  ),
1824
- /* @__PURE__ */ jsxs14(InputContainer8, { $wide: true, children: [
1825
- /* @__PURE__ */ jsx30(InputLabel8, { htmlFor: "id", children: "Link to plaintext" }),
1826
- /* @__PURE__ */ jsx30(Input6, { id: "url", name: "url", defaultValue: "" })
2022
+ /* @__PURE__ */ jsxs15(InputContainer7, { $wide: true, children: [
2023
+ /* @__PURE__ */ jsx33(InputLabel7, { htmlFor: "id", children: "Link to plaintext" }),
2024
+ /* @__PURE__ */ jsx33(Input6, { id: "url", name: "url", defaultValue: "" })
1827
2025
  ] }),
1828
- /* @__PURE__ */ jsx30(Button, { type: "submit", children: "Create" })
2026
+ /* @__PURE__ */ jsx33(ActionButton9, { primary: true, large: true, type: "submit", children: "Create" })
1829
2027
  ] }) });
1830
2028
  }
1831
2029
 
1832
2030
  // src/ContentResource/PlaintextCreator/index.tsx
1833
- import { jsx as jsx31 } from "react/jsx-runtime";
1834
- var plaintextCreator = {
2031
+ import { jsx as jsx34 } from "react/jsx-runtime";
2032
+ var plaintextCreator = defineCreator17({
1835
2033
  id: "@manifest-editor/plaintext-creator",
1836
2034
  create: createPlaintext,
1837
2035
  label: "Plaintext",
1838
2036
  summary: "Add link to an plaintext",
1839
- icon: /* @__PURE__ */ jsx31(TextFormatIcon, {}),
2037
+ icon: /* @__PURE__ */ jsx34(TextFormatIcon, {}),
1840
2038
  render(ctx) {
1841
- return /* @__PURE__ */ jsx31(CreatePlaintextForm, { ...ctx });
2039
+ return /* @__PURE__ */ jsx34(CreatePlaintextForm, { ...ctx });
1842
2040
  },
1843
2041
  resourceType: "ContentResource",
1844
2042
  resourceFields: ["label", "format"],
@@ -1848,12 +2046,228 @@ var plaintextCreator = {
1848
2046
  staticFields: {
1849
2047
  format: "text/plain"
1850
2048
  }
1851
- };
2049
+ });
2050
+
2051
+ // src/ContentResource/ThumbnailCreator/index.tsx
2052
+ import { ScaledImageIcon } from "@manifest-editor/components";
2053
+ import { defineCreator as defineCreator18 } from "@manifest-editor/creator-api";
2054
+
2055
+ // src/ContentResource/ThumbnailCreator/create-thumbnail.tsx
2056
+ import { ActionButton as ActionButton10 } from "@manifest-editor/components";
2057
+ import { Input as Input7, InputContainer as InputContainer8, InputLabel as InputLabel8 } from "@manifest-editor/editors";
2058
+ import { useMemo, useState as useState9 } from "react";
2059
+
2060
+ // src/ContentResource/ThumbnailCreator/thumbnail-helpers.ts
2061
+ import {
2062
+ canonicalServiceUrl as canonicalServiceUrl3,
2063
+ createImageServiceRequest as createImageServiceRequest2,
2064
+ imageServiceRequestToString as imageServiceRequestToString2,
2065
+ parseImageServiceRequest as parseImageServiceRequest2
2066
+ } from "@iiif/parser/image-3";
2067
+ function serviceImageAtSize(service, size) {
2068
+ if (service["@id"]) {
2069
+ service.id = service["@id"];
2070
+ }
2071
+ if (service["@type"]) {
2072
+ service.type = service["@type"];
2073
+ }
2074
+ const request = createImageServiceRequest2(service);
2075
+ return imageServiceRequestToString2({
2076
+ identifier: request.identifier,
2077
+ server: request.server,
2078
+ scheme: request.scheme,
2079
+ type: "image",
2080
+ size: {
2081
+ max: false,
2082
+ confined: false,
2083
+ upscaled: false,
2084
+ width: size.width,
2085
+ height: size.height
2086
+ },
2087
+ format: "jpg",
2088
+ // This isn't how it should be modelled, always full,
2089
+ // region: data.selector ? data.selector : { full: true },
2090
+ region: { full: true },
2091
+ rotation: { angle: 0 },
2092
+ quality: "default",
2093
+ prefix: request.prefix,
2094
+ originalPath: request.originalPath
2095
+ });
2096
+ }
2097
+ function getCanonicalUrl2(url) {
2098
+ return url.endsWith("default.jpg") ? imageServiceRequestToString2({
2099
+ ...parseImageServiceRequest2(url),
2100
+ type: "info"
2101
+ }) : canonicalServiceUrl3(url);
2102
+ }
2103
+
2104
+ // src/ContentResource/ThumbnailCreator/create-thumbnail.tsx
2105
+ import { jsx as jsx35, jsxs as jsxs16 } from "react/jsx-runtime";
2106
+ async function createThumbnail(data, ctx) {
2107
+ const service = { ...data.service };
2108
+ const sizes = service.sizes;
2109
+ if (service["@id"]) {
2110
+ service.id = service["@id"];
2111
+ }
2112
+ if (service["@type"]) {
2113
+ service.type = service["@type"];
2114
+ }
2115
+ if (data.thumbnailUrl) {
2116
+ return ctx.embed({
2117
+ id: data.thumbnailUrl,
2118
+ type: "Image",
2119
+ format: "image/jpeg",
2120
+ width: data.width,
2121
+ height: data.height
2122
+ });
2123
+ }
2124
+ if (sizes) {
2125
+ const thumbnailSize = data.width || 400;
2126
+ let bestMatch = null;
2127
+ for (const size of sizes) {
2128
+ if (!bestMatch || Math.abs(size.width - thumbnailSize) < Math.abs(bestMatch.width - thumbnailSize)) {
2129
+ bestMatch = { width: size.width, height: size.height };
2130
+ }
2131
+ }
2132
+ if (bestMatch) {
2133
+ const imageId = serviceImageAtSize(service, bestMatch);
2134
+ return ctx.embed({
2135
+ id: imageId,
2136
+ type: "Image",
2137
+ format: "image/jpeg",
2138
+ width: bestMatch.width,
2139
+ height: bestMatch.height
2140
+ });
2141
+ }
2142
+ }
2143
+ return null;
2144
+ }
2145
+ function CreateThumbnailForm(props) {
2146
+ const [url, setUrl] = useState9("");
2147
+ const [service, setService] = useState9(null);
2148
+ const [selectedSize, setSelectedSize] = useState9({ width: 0, height: 0 });
2149
+ const previewUrl = useMemo(() => {
2150
+ if (!service)
2151
+ return null;
2152
+ if (!selectedSize.width || !selectedSize.height)
2153
+ return null;
2154
+ return serviceImageAtSize(service, selectedSize);
2155
+ }, [selectedSize, service]);
2156
+ const onSubmit = (e) => {
2157
+ e.preventDefault();
2158
+ const data = new FormData(e.target);
2159
+ const formData = Object.fromEntries(data.entries());
2160
+ const url2 = formData.url;
2161
+ if (url2) {
2162
+ const info = getCanonicalUrl2(url2);
2163
+ if (!info) {
2164
+ throw new Error("Invalid image service request");
2165
+ }
2166
+ fetch(info).then((r) => r.json()).then((service2) => {
2167
+ setService(service2);
2168
+ const size0 = service2.sizes?.[0];
2169
+ if (size0) {
2170
+ setSelectedSize(size0);
2171
+ }
2172
+ });
2173
+ }
2174
+ };
2175
+ if (service) {
2176
+ return /* @__PURE__ */ jsxs16(PaddedSidebarContainer, { children: [
2177
+ /* @__PURE__ */ jsxs16("div", { className: "mb-4", children: [
2178
+ /* @__PURE__ */ jsx35("div", { className: "mb-2", children: service["@id"] || service.id }),
2179
+ /* @__PURE__ */ jsx35("div", { className: "flex gap-2 mb-4", children: service.sizes?.map((size) => {
2180
+ const isSelected = size.width === selectedSize.width;
2181
+ return /* @__PURE__ */ jsxs16(
2182
+ ActionButton10,
2183
+ {
2184
+ primary: isSelected,
2185
+ isDisabled: isSelected,
2186
+ large: true,
2187
+ onPress: () => setSelectedSize(size),
2188
+ children: [
2189
+ size.width,
2190
+ "x",
2191
+ size.height
2192
+ ]
2193
+ },
2194
+ size.width
2195
+ );
2196
+ }) }),
2197
+ previewUrl ? /* @__PURE__ */ jsx35("img", { src: previewUrl, alt: "preview of selected resource" }) : null
2198
+ ] }),
2199
+ /* @__PURE__ */ jsx35(
2200
+ ActionButton10,
2201
+ {
2202
+ primary: true,
2203
+ large: true,
2204
+ isDisabled: !previewUrl,
2205
+ onPress: () => {
2206
+ if (!service)
2207
+ return;
2208
+ props.runCreate({ service, width: selectedSize.width, height: selectedSize.height });
2209
+ },
2210
+ children: "Add thumbnail"
2211
+ }
2212
+ )
2213
+ ] });
2214
+ }
2215
+ return /* @__PURE__ */ jsx35(PaddedSidebarContainer, { children: /* @__PURE__ */ jsxs16("form", { onSubmit, children: [
2216
+ /* @__PURE__ */ jsx35("div", { className: "flex gap-2 items-center", children: /* @__PURE__ */ jsxs16(InputContainer8, { $wide: true, children: [
2217
+ /* @__PURE__ */ jsx35(InputLabel8, { htmlFor: "id", children: "Link to image service" }),
2218
+ /* @__PURE__ */ jsx35(
2219
+ Input7,
2220
+ {
2221
+ id: "url",
2222
+ name: "url",
2223
+ defaultValue: "",
2224
+ onPaste: (e) => {
2225
+ const text = e.clipboardData.getData("text/plain");
2226
+ setUrl(text ? getCanonicalUrl2(text) : "");
2227
+ },
2228
+ onBlur: (e) => setUrl(e.currentTarget.value ? getCanonicalUrl2(e.currentTarget.value) : "")
2229
+ }
2230
+ )
2231
+ ] }) }),
2232
+ /* @__PURE__ */ jsx35("div", { children: /* @__PURE__ */ jsx35(ActionButton10, { primary: true, large: true, type: "submit", isDisabled: !url, children: "Select size" }) })
2233
+ ] }) });
2234
+ }
2235
+
2236
+ // src/ContentResource/ThumbnailCreator/index.tsx
2237
+ import { jsx as jsx36 } from "react/jsx-runtime";
2238
+ var thumbnailCreator = defineCreator18({
2239
+ id: "@manifest-editor/thumbnail-image",
2240
+ create: createThumbnail,
2241
+ label: "Thumbnail from service",
2242
+ summary: "Add thumbnail from an image service",
2243
+ icon: /* @__PURE__ */ jsx36(ScaledImageIcon, {}),
2244
+ render(ctx) {
2245
+ return /* @__PURE__ */ jsx36(CreateThumbnailForm, { ...ctx });
2246
+ },
2247
+ resourceType: "ContentResource",
2248
+ resourceFields: ["id", "type", "format"],
2249
+ supports: {
2250
+ parentFields: ["thumbnail"]
2251
+ }
2252
+ });
2253
+
2254
+ // src/ContentResource/WebPageCreator/index.tsx
2255
+ import { defineCreator as defineCreator19 } from "@manifest-editor/creator-api";
2256
+
2257
+ // ../ui/icons/LinkIcon.tsx
2258
+ import { jsx as jsx37, jsxs as jsxs17 } from "react/jsx-runtime";
2259
+ function LinkIcon() {
2260
+ return /* @__PURE__ */ jsxs17("svg", { xmlns: "http://www.w3.org/2000/svg", height: "24px", viewBox: "0 0 24 24", width: "24px", fill: "#000000", children: [
2261
+ /* @__PURE__ */ jsx37("path", { d: "M0 0h24v24H0z", fill: "none" }),
2262
+ /* @__PURE__ */ jsx37("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" })
2263
+ ] });
2264
+ }
1852
2265
 
1853
2266
  // src/ContentResource/WebPageCreator/create-web-page.tsx
1854
- import { LanguageFieldEditor as LanguageFieldEditor6, InputContainer as InputContainer9, InputLabel as InputLabel9, Input as Input7 } from "@manifest-editor/editors";
1855
- import { useState as useState8 } from "react";
1856
- import { jsx as jsx32, jsxs as jsxs15 } from "react/jsx-runtime";
2267
+ import { ActionButton as ActionButton11 } from "@manifest-editor/components";
2268
+ import { Input as Input8, InputContainer as InputContainer9, InputLabel as InputLabel9, LanguageFieldEditor as LanguageFieldEditor6 } from "@manifest-editor/editors";
2269
+ import { useState as useState10 } from "react";
2270
+ import { jsx as jsx38, jsxs as jsxs18 } from "react/jsx-runtime";
1857
2271
  async function createWebPage(data, ctx) {
1858
2272
  return ctx.embed({
1859
2273
  id: data.url,
@@ -1863,7 +2277,7 @@ async function createWebPage(data, ctx) {
1863
2277
  });
1864
2278
  }
1865
2279
  function CreateWebPageForm(props) {
1866
- const [label, setLabel] = useState8({ en: [""] });
2280
+ const [label, setLabel] = useState10({ en: [""] });
1867
2281
  const onSubmit = (e) => {
1868
2282
  e.preventDefault();
1869
2283
  const data = new FormData(e.target);
@@ -1872,8 +2286,8 @@ function CreateWebPageForm(props) {
1872
2286
  props.runCreate({ url: formData.url, label });
1873
2287
  }
1874
2288
  };
1875
- return /* @__PURE__ */ jsx32(PaddedSidebarContainer, { children: /* @__PURE__ */ jsxs15("form", { onSubmit, children: [
1876
- /* @__PURE__ */ jsx32(
2289
+ return /* @__PURE__ */ jsx38(PaddedSidebarContainer, { children: /* @__PURE__ */ jsxs18("form", { onSubmit, children: [
2290
+ /* @__PURE__ */ jsx38(
1877
2291
  LanguageFieldEditor6,
1878
2292
  {
1879
2293
  focusId: "label",
@@ -1882,52 +2296,48 @@ function CreateWebPageForm(props) {
1882
2296
  onSave: (e) => setLabel(e.toInternationalString())
1883
2297
  }
1884
2298
  ),
1885
- /* @__PURE__ */ jsxs15(InputContainer9, { $wide: true, children: [
1886
- /* @__PURE__ */ jsx32(InputLabel9, { htmlFor: "id", children: "Link" }),
1887
- /* @__PURE__ */ jsx32(Input7, { id: "url", name: "url", defaultValue: "" })
2299
+ /* @__PURE__ */ jsxs18(InputContainer9, { $wide: true, children: [
2300
+ /* @__PURE__ */ jsx38(InputLabel9, { htmlFor: "id", children: "Link" }),
2301
+ /* @__PURE__ */ jsx38(Input8, { id: "url", name: "url", defaultValue: "" })
1888
2302
  ] }),
1889
- /* @__PURE__ */ jsx32(Button, { type: "submit", children: "Create link" })
2303
+ /* @__PURE__ */ jsx38(ActionButton11, { primary: true, large: true, type: "submit", children: "Create link" })
1890
2304
  ] }) });
1891
2305
  }
1892
2306
 
1893
- // ../ui/icons/LinkIcon.tsx
1894
- import { jsx as jsx33, jsxs as jsxs16 } from "react/jsx-runtime";
1895
- function LinkIcon() {
1896
- return /* @__PURE__ */ jsxs16("svg", { xmlns: "http://www.w3.org/2000/svg", height: "24px", viewBox: "0 0 24 24", width: "24px", fill: "#000000", children: [
1897
- /* @__PURE__ */ jsx33("path", { d: "M0 0h24v24H0z", fill: "none" }),
1898
- /* @__PURE__ */ jsx33("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" })
1899
- ] });
1900
- }
1901
-
1902
2307
  // src/ContentResource/WebPageCreator/index.tsx
1903
- import { jsx as jsx34 } from "react/jsx-runtime";
1904
- var webPageCreator = {
2308
+ import { jsx as jsx39 } from "react/jsx-runtime";
2309
+ var webPageCreator = defineCreator19({
1905
2310
  id: "@manifest-editor/web-page-creator",
1906
2311
  create: createWebPage,
1907
2312
  label: "Web page",
1908
2313
  summary: "Add link to an external web page",
1909
- icon: /* @__PURE__ */ jsx34(LinkIcon, {}),
2314
+ icon: /* @__PURE__ */ jsx39(LinkIcon, {}),
1910
2315
  render(ctx) {
1911
- return /* @__PURE__ */ jsx34(CreateWebPageForm, { ...ctx });
2316
+ return /* @__PURE__ */ jsx39(CreateWebPageForm, { ...ctx });
1912
2317
  },
1913
2318
  resourceType: "ContentResource",
1914
2319
  resourceFields: ["label", "format"],
1915
2320
  supports: {
1916
2321
  parentFields: ["seeAlso", "rendering", "homepage"]
1917
2322
  }
1918
- };
2323
+ });
1919
2324
 
1920
2325
  // src/ContentResource/YouTubeCreator/index.tsx
1921
2326
  import { YouTubeIcon } from "@manifest-editor/components";
2327
+ import { defineCreator as defineCreator20 } from "@manifest-editor/creator-api";
1922
2328
 
1923
2329
  // src/ContentResource/YouTubeCreator/create-youtube-body.tsx
1924
- import { Input as Input8, InputContainer as InputContainer10, InputLabel as InputLabel10 } from "@manifest-editor/editors";
1925
- import { jsx as jsx35, jsxs as jsxs17 } from "react/jsx-runtime";
2330
+ import { ActionButton as ActionButton12 } from "@manifest-editor/components";
2331
+ import { Input as Input9, InputContainer as InputContainer10, InputLabel as InputLabel10 } from "@manifest-editor/editors";
2332
+ import { jsx as jsx40, jsxs as jsxs19 } from "react/jsx-runtime";
1926
2333
  var ytRegex = /^.*(?:(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/|shorts\/)|(?:(?:watch)?\?vi?=|&vi?=))([^#&?]*).*/;
1927
2334
  function getYouTubeId(url) {
1928
2335
  const id = (url || "").match(ytRegex);
1929
2336
  return id ? id[1] : null;
1930
2337
  }
2338
+ function validateYouTube(data) {
2339
+ return !!getYouTubeId(data.youtubeUrl);
2340
+ }
1931
2341
  async function createYoutubeBody(data, ctx) {
1932
2342
  const id = getYouTubeId(data.youtubeUrl);
1933
2343
  const body = ctx.embed({
@@ -1997,27 +2407,27 @@ function YouTubeForm(props) {
1997
2407
  props.runCreate({ youtubeUrl: formData.youtubeUrl });
1998
2408
  }
1999
2409
  };
2000
- return /* @__PURE__ */ jsx35(PaddedSidebarContainer, { children: /* @__PURE__ */ jsxs17("form", { onSubmit, children: [
2001
- /* @__PURE__ */ jsxs17(InputContainer10, { $wide: true, children: [
2002
- /* @__PURE__ */ jsx35(InputLabel10, { htmlFor: "id", children: "Link to YouTube" }),
2003
- /* @__PURE__ */ jsx35(Input8, { id: "youtubeUrl", name: "youtubeUrl", defaultValue: "" })
2410
+ return /* @__PURE__ */ jsx40(PaddedSidebarContainer, { children: /* @__PURE__ */ jsxs19("form", { onSubmit, children: [
2411
+ /* @__PURE__ */ jsxs19(InputContainer10, { $wide: true, children: [
2412
+ /* @__PURE__ */ jsx40(InputLabel10, { htmlFor: "id", children: "Link to YouTube" }),
2413
+ /* @__PURE__ */ jsx40(Input9, { id: "youtubeUrl", name: "youtubeUrl", defaultValue: "" })
2004
2414
  ] }),
2005
- /* @__PURE__ */ jsx35(Button, { type: "submit", children: "Create" })
2415
+ /* @__PURE__ */ jsx40(ActionButton12, { primary: true, large: true, type: "submit", children: "Create" })
2006
2416
  ] }) });
2007
2417
  }
2008
2418
 
2009
2419
  // src/ContentResource/YouTubeCreator/index.tsx
2010
- import { jsx as jsx36 } from "react/jsx-runtime";
2011
- var youTubeBodyCreator = {
2420
+ import { jsx as jsx41 } from "react/jsx-runtime";
2421
+ var youTubeBodyCreator = defineCreator20({
2012
2422
  id: "@manifest-editor/youtube",
2013
2423
  create: createYoutubeBody,
2014
2424
  label: "YouTube",
2015
2425
  summary: "Embed YouTube",
2016
- icon: /* @__PURE__ */ jsx36(YouTubeIcon, {}),
2426
+ icon: /* @__PURE__ */ jsx41(YouTubeIcon, {}),
2017
2427
  resourceType: "ContentResource",
2018
2428
  additionalTypes: ["Canvas", "Annotation"],
2019
2429
  resourceFields: ["id", "type", "service"],
2020
- render: (ctx) => /* @__PURE__ */ jsx36(YouTubeForm, { ...ctx }),
2430
+ render: (ctx) => /* @__PURE__ */ jsx41(YouTubeForm, { ...ctx }),
2021
2431
  supports: {
2022
2432
  parentTypes: ["Annotation", "Manifest", "AnnotationPage"],
2023
2433
  parentFieldMap: {
@@ -2029,10 +2439,14 @@ var youTubeBodyCreator = {
2029
2439
  staticFields: {
2030
2440
  type: "Video"
2031
2441
  }
2032
- };
2442
+ });
2443
+
2444
+ // src/Manifest/ManifestBrowserCreator/index.tsx
2445
+ import { IIIFBrowserIcon as IIIFBrowserIcon2 } from "@manifest-editor/components";
2446
+ import { defineCreator as defineCreator21 } from "@manifest-editor/creator-api";
2033
2447
 
2034
2448
  // src/Manifest/ManifestBrowserCreator/manifest-browser-creator.tsx
2035
- import { normaliseContentState as normaliseContentState2, parseContentState as parseContentState2 } from "@iiif/helpers";
2449
+ import { createThumbnailHelper, normaliseContentState as normaliseContentState2, parseContentState as parseContentState2 } from "@iiif/helpers";
2036
2450
  import { lazy as lazy2 } from "react";
2037
2451
  async function createFromManifestBrowserOutput(data, ctx) {
2038
2452
  const targetType = ctx.options.targetType;
@@ -2044,23 +2458,34 @@ async function createFromManifestBrowserOutput(data, ctx) {
2044
2458
  );
2045
2459
  const target = contentState.target[0];
2046
2460
  const previewVault = ctx.getPreviewVault();
2461
+ const thumbnails = createThumbnailHelper(previewVault);
2047
2462
  if (!target) {
2048
2463
  throw new Error("No target found in content state");
2049
2464
  }
2050
2465
  if (targetType === "Manifest") {
2051
2466
  const manifestId = target.source.id;
2052
2467
  invariant(manifestId, "Could not find Manifest ID");
2053
- const manifest = await previewVault.get(manifestId);
2468
+ const manifest = await previewVault.loadManifest(manifestId);
2469
+ const thumbnail = await thumbnails.getBestThumbnailAtSize(manifest, { width: 256, height: 256 }, false);
2470
+ invariant(manifest, "Manifest not found");
2054
2471
  return ctx.embed({
2055
2472
  id: target.source.id,
2056
2473
  type: "Manifest",
2057
- label: manifest.label
2474
+ label: manifest.label,
2475
+ summary: manifest.summary,
2476
+ thumbnail: thumbnail?.best ? [
2477
+ {
2478
+ id: thumbnail.best.id,
2479
+ type: "Image"
2480
+ }
2481
+ ] : void 0
2058
2482
  });
2059
2483
  }
2060
2484
  if (targetType === "Collection") {
2061
2485
  const collectionId = target.source.id;
2062
2486
  invariant(collectionId, "Could not find Manifest ID");
2063
- const collection = await previewVault.get(collectionId);
2487
+ const collection = await previewVault.loadManifest(collectionId);
2488
+ invariant(collection, "Collection not found");
2064
2489
  return ctx.embed({
2065
2490
  id: target.source.id,
2066
2491
  type: "Collection",
@@ -2069,19 +2494,18 @@ async function createFromManifestBrowserOutput(data, ctx) {
2069
2494
  }
2070
2495
  throw new Error("Not yet supported.");
2071
2496
  }
2072
- var ManifestBrowserCreatorForm2 = lazy2(() => import("./manifest-browser-form.lazy-WRWZPVRC.js"));
2497
+ var ManifestBrowserCreatorForm2 = lazy2(() => import("./manifest-browser-form.lazy-HJJKFMR6.js"));
2073
2498
 
2074
2499
  // src/Manifest/ManifestBrowserCreator/index.tsx
2075
- import { IIIFBrowserIcon as IIIFBrowserIcon2 } from "@manifest-editor/components";
2076
- import { jsx as jsx37 } from "react/jsx-runtime";
2077
- var manifestBrowserCreator = {
2500
+ import { jsx as jsx42 } from "react/jsx-runtime";
2501
+ var manifestBrowserCreator = defineCreator21({
2078
2502
  id: "@manifest-editor/manifest-browser-creator",
2079
2503
  create: createFromManifestBrowserOutput,
2080
2504
  label: "IIIF Browser",
2081
2505
  summary: "Browse IIIF Resources",
2082
- icon: /* @__PURE__ */ jsx37(IIIFBrowserIcon2, {}),
2506
+ icon: /* @__PURE__ */ jsx42(IIIFBrowserIcon2, {}),
2083
2507
  render(ctx) {
2084
- return /* @__PURE__ */ jsx37(ManifestBrowserCreatorForm, { ...ctx });
2508
+ return /* @__PURE__ */ jsx42(ManifestBrowserCreatorForm, { ...ctx });
2085
2509
  },
2086
2510
  resourceType: "Manifest",
2087
2511
  resourceFields: ["id", "label"],
@@ -2094,7 +2518,7 @@ var manifestBrowserCreator = {
2094
2518
  },
2095
2519
  sideEffects: [],
2096
2520
  staticFields: {}
2097
- };
2521
+ });
2098
2522
 
2099
2523
  // src/index.ts
2100
2524
  var allCreators = [
@@ -2115,14 +2539,52 @@ var allCreators = [
2115
2539
  emptyAnnotationPage,
2116
2540
  noBodyAnnotation,
2117
2541
  internalCanvas,
2118
- captionedImageAnnotation
2542
+ captionedImageAnnotation,
2543
+ imageUrlListCreator,
2544
+ imageUrlListAnnotation,
2545
+ thumbnailCreator
2119
2546
  ];
2120
2547
  export {
2548
+ CreateAudioAnnotationForm,
2549
+ CreateCaptionedImageAnnotation,
2550
+ CreateHTMLAnnotation,
2551
+ CreateHTMLBodyForm,
2552
+ CreateImageServerForm,
2553
+ CreateImageServiceAnnotationForm,
2554
+ CreateImageUrlAnnotationForm,
2555
+ CreateImageUrlForm,
2556
+ CreateImageUrlListForm,
2557
+ CreatePlaintextForm,
2558
+ CreateThumbnailForm,
2559
+ CreateVideoAnnotationForm,
2560
+ CreateWebPageForm,
2561
+ IIIFBrowserCreatorForm,
2562
+ ManifestBrowserCreatorForm2 as ManifestBrowserCreatorForm,
2563
+ YouTubeForm,
2121
2564
  allCreators,
2122
2565
  audioAnnotation,
2123
2566
  captionedImageAnnotation,
2567
+ createAudioAnnotation,
2568
+ createCaptionedImageAnnotation,
2569
+ createFromIIIFBrowserOutput,
2570
+ createFromManifestBrowserOutput,
2571
+ createHtmlAnnotation,
2572
+ createHtmlBody,
2573
+ createImageServer,
2574
+ createImageServiceAnnotation,
2575
+ createImageUrl,
2576
+ createImageUrlAnnotation,
2577
+ createImageUrlList,
2578
+ createImageUrlListAnnotation,
2579
+ createNoBodyAnnotation,
2580
+ createPlaintext,
2581
+ createThumbnail,
2582
+ createVideoAnnotation,
2583
+ createWebPage,
2584
+ createYoutubeBody,
2124
2585
  emptyAnnotationPage,
2125
2586
  emptyCanvas,
2587
+ getYouTubeId,
2126
2588
  htmlAnnotation,
2127
2589
  htmlBodyCreator,
2128
2590
  iiifBrowserCreator,
@@ -2130,10 +2592,13 @@ export {
2130
2592
  imageServiceCreator,
2131
2593
  imageUrlAnnotation,
2132
2594
  imageUrlCreator,
2595
+ imageUrlListAnnotation,
2596
+ imageUrlListCreator,
2133
2597
  internalCanvas,
2134
2598
  manifestBrowserCreator,
2135
2599
  noBodyAnnotation,
2136
2600
  plaintextCreator,
2601
+ validateYouTube,
2137
2602
  videoAnnotation,
2138
2603
  webPageCreator,
2139
2604
  youTubeBodyCreator