@manifest-editor/creators 1.3.1 → 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.
package/dist/index.js CHANGED
@@ -1,24 +1,15 @@
1
1
  import {
2
2
  ManifestBrowserCreatorForm
3
- } from "./chunk-KLSWX2QF.js";
3
+ } from "./chunk-S3JO5Y3Z.js";
4
4
 
5
5
  // src/Annotation/AudioAnnotation/index.tsx
6
6
  import { AudioIcon } from "@manifest-editor/components";
7
+ import { defineCreator } from "@manifest-editor/creator-api";
7
8
 
8
9
  // src/Annotation/AudioAnnotation/create-audio-annotation.tsx
9
- import { useEffect as useEffect2, useState as useState2 } from "react";
10
-
11
- // ../ui/atoms/PaddedSidebarContainer.tsx
12
- import styled from "styled-components";
13
- var PaddedSidebarContainer = styled.div`
14
- padding: 0 0.7em;
15
- margin: 0.7em 0;
16
- flex: 1;
17
- overflow: visible;
18
- `;
19
-
20
- // src/Annotation/AudioAnnotation/create-audio-annotation.tsx
21
- 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";
22
13
 
23
14
  // ../ui/ui/MediaControls/MediaControls.tsx
24
15
  import { formatTime, useMediaActions, useMediaElements, useMediaState } from "react-iiif-vault";
@@ -71,14 +62,14 @@ var VolumeOffIcon = ({ title, ...props }) => /* @__PURE__ */ jsxs("svg", { ...pr
71
62
  ] });
72
63
 
73
64
  // ../ui/ui/MediaControls/MediaControls.styles.ts
74
- import styled2, { css } from "styled-components";
75
- var AudioPlayerContainer = styled2.div`
65
+ import styled, { css } from "styled-components";
66
+ var AudioPlayerContainer = styled.div`
76
67
  background: #ededed; // Not in variable.
77
68
  display: flex;
78
69
  padding: 0.5em;
79
70
  align-items: center;
80
71
  `;
81
- var BaseButton = styled2.button`
72
+ var BaseButton = styled.button`
82
73
  cursor: pointer;
83
74
  padding: 0.75em 1.5em;
84
75
  font-size: 0.938em;
@@ -90,7 +81,7 @@ var BaseButton = styled2.button`
90
81
  vertical-align: top;
91
82
  white-space: nowrap;
92
83
  `;
93
- var PlayButton = styled2(BaseButton)`
84
+ var PlayButton = styled(BaseButton)`
94
85
  width: 2em;
95
86
  height: 2em;
96
87
  overflow: hidden;
@@ -105,19 +96,19 @@ var PlayButton = styled2(BaseButton)`
105
96
  color: #999;
106
97
  }
107
98
  `;
108
- var TimeDisplay = styled2.div`
99
+ var TimeDisplay = styled.div`
109
100
  margin: 0 1em;
110
101
  font-size: 0.85em;
111
102
  color: #000;
112
103
  `;
113
- var ProgressContainer = styled2.div`
104
+ var ProgressContainer = styled.div`
114
105
  flex: 1 1 0px;
115
106
  height: 6px;
116
107
  display: flex;
117
108
  position: relative;
118
109
  padding: 15px 0;
119
110
  `;
120
- var ProgressCurrent = styled2.div`
111
+ var ProgressCurrent = styled.div`
121
112
  background: #d85680;
122
113
  height: 6px;
123
114
  pointer-events: none;
@@ -127,7 +118,7 @@ var ProgressCurrent = styled2.div`
127
118
  border-radius: 3px;
128
119
  transition: width 200ms;
129
120
  `;
130
- var ProgressBackground = styled2.div`
121
+ var ProgressBackground = styled.div`
131
122
  position: absolute;
132
123
  top: 13px;
133
124
  left: 0;
@@ -137,7 +128,7 @@ var ProgressBackground = styled2.div`
137
128
  pointer-events: none;
138
129
  background: #fff;
139
130
  `;
140
- var SoundButton = styled2(BaseButton)`
131
+ var SoundButton = styled(BaseButton)`
141
132
  width: 2em;
142
133
  height: 2em;
143
134
  overflow: hidden;
@@ -147,11 +138,11 @@ var SoundButton = styled2(BaseButton)`
147
138
  padding: 0;
148
139
  margin: 0;
149
140
  `;
150
- var SoundContainer = styled2.div`
141
+ var SoundContainer = styled.div`
151
142
  display: flex;
152
143
  align-items: center;
153
144
  `;
154
- var VolumeContainer = styled2.div`
145
+ var VolumeContainer = styled.div`
155
146
  width: 0;
156
147
  overflow: hidden;
157
148
  transition: width 500ms;
@@ -161,7 +152,7 @@ var VolumeContainer = styled2.div`
161
152
  width: 150px;
162
153
  `}
163
154
  `;
164
- var VolumeSlider = styled2.input.attrs({ type: "range" })`
155
+ var VolumeSlider = styled.input.attrs({ type: "range" })`
165
156
  width: 120px;
166
157
  margin: 0 15px;
167
158
  `;
@@ -169,24 +160,35 @@ var VolumeSlider = styled2.input.attrs({ type: "range" })`
169
160
  // ../ui/madoc/components/icons/Spinner.tsx
170
161
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
171
162
  function Spinner(props) {
172
- 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: [
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
- ] }) });
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
+ );
186
188
  }
187
189
 
188
190
  // ../ui/atoms/VisuallHidden/VisuallHidden.tsx
189
- import styled3, { css as css2 } from "styled-components";
191
+ import styled2, { css as css2 } from "styled-components";
190
192
  var visuallyHidden = css2`
191
193
  clip: rect(1px, 1px, 1px, 1px);
192
194
  clip-path: inset(50%);
@@ -197,7 +199,7 @@ var visuallyHidden = css2`
197
199
  padding: 0;
198
200
  position: absolute;
199
201
  `;
200
- var VisuallyHiddenLabel = styled3.label`
202
+ var VisuallyHiddenLabel = styled2.label`
201
203
  ${visuallyHidden}
202
204
  `;
203
205
 
@@ -289,99 +291,18 @@ function MediaControls(props) {
289
291
  ] });
290
292
  }
291
293
 
292
- // src/Annotation/AudioAnnotation/create-audio-annotation.tsx
293
- import { CanvasPanel } from "react-iiif-vault";
294
- import { getValue } from "@iiif/helpers";
295
- import {
296
- Input,
297
- InputContainer,
298
- InputLabel,
299
- LanguageFieldEditor,
300
- FormFieldWrapper
301
- } from "@manifest-editor/editors";
302
-
303
- // ../ui/atoms/Button.tsx
304
- import styled4 from "styled-components";
305
- var ButtonReset = styled4.button`
306
- border: none;
307
- outline: none;
308
- background-color: transparent;
309
- margin: 0;
310
- padding: 0;
311
- font-size: inherit;
312
- color: inherit;
313
- cursor: pointer;
314
- &:hover {
315
- color: inherit;
316
- }
317
- `;
318
- var Button = styled4.button`
319
- padding: 0.5rem 1rem;
320
- color: ${(props) => props.theme.color.main || "none"};
321
- background-color: ${(props) => props.theme.color.white || "white"};
322
- border-radius: inherit;
323
- border: none;
324
- cursor: pointer;
325
- display: flex;
326
- align-items: center;
327
- font-size: 0.85em;
328
- :disabled {
329
- opacity: 0.65;
330
- cursor: not-allowed;
331
- }
332
-
333
- &:hover {
334
- background: #eee;
335
- }
336
- `;
337
- var SmallButton = styled4(Button)`
338
- padding: 0.25em ${(props) => props.theme.padding.xs || "0.4em"};
339
- height: unset;
340
- background: none;
341
- `;
342
- var SecondaryButton = styled4(Button)`
343
- {
344
- padding: 0 ${(props) => props.theme.padding.medium || "1rem"};
345
- color: ${(props) => props.theme.color.main || "#B84C74;"};
346
- background-color: ${(props) => props.theme.color.white || "white"};
347
- border: 1px solid ${(props) => props.theme.color.main || "#B84C74;"};
348
- border-radius: 0.25rem;
349
- cursor: pointer;
350
- height: 2rem;
351
- display: flex;
352
- align-items: center;
353
- white-space: nowrap;
354
- font-size: 0.75rem;
355
-
356
- :disabled {
357
- opacity: 0.65;
358
- cursor: not-allowed;
359
- }
360
- }
361
- `;
362
- var CalltoButton = styled4(Button)`
363
- padding: 0 ${(props) => props.theme.padding.medium || "1rem"};
364
- color: ${(props) => props.theme.color.white || "white"};
365
- background-color: ${(props) => props.theme.color.main || "#B84C74;"};
366
- border: 1px solid #eee;
367
- border-radius: 0.25rem;
368
- cursor: pointer;
369
- justify-content: center;
370
- display: flex;
371
- align-items: center;
372
- &:hover {
373
- background-color: ${(props) => props.theme.color.mainHover || "#B84C74;"};
374
- }
375
- `;
376
- var ButtonGroup = styled4.div`
377
- display: flex;
378
- flex-direction: row;
379
- flex-wrap: wrap;
380
- align-items: flex-start;
381
- 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;
382
301
  `;
383
302
 
384
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";
385
306
  import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
386
307
  async function createAudioAnnotation(data, ctx) {
387
308
  const annotation = {
@@ -389,7 +310,7 @@ async function createAudioAnnotation(data, ctx) {
389
310
  type: "Annotation"
390
311
  };
391
312
  const targetType = ctx.options.targetType;
392
- const body = await ctx.embed({
313
+ const body = ctx.embed({
393
314
  id: data.url,
394
315
  type: "Sound",
395
316
  format: "audio/mp4",
@@ -455,17 +376,9 @@ function CreateAudioAnnotationForm(props) {
455
376
  }, [url]);
456
377
  return /* @__PURE__ */ jsxs4(PaddedSidebarContainer, { children: [
457
378
  error ? /* @__PURE__ */ jsx4(ErrorMessage, { children: error }) : null,
458
- /* @__PURE__ */ jsxs4(InputContainer, { children: [
379
+ /* @__PURE__ */ jsxs4(InputContainer, { $wide: true, children: [
459
380
  /* @__PURE__ */ jsx4(InputLabel, { htmlFor: "audio-url", children: "URL" }),
460
- /* @__PURE__ */ jsx4(
461
- Input,
462
- {
463
- type: "text",
464
- id: "audio-url",
465
- value: url,
466
- onChange: (e) => setUrl(e.target.value)
467
- }
468
- )
381
+ /* @__PURE__ */ jsx4(Input, { type: "text", id: "audio-url", value: url, onChange: (e) => setUrl(e.target.value) })
469
382
  ] }),
470
383
  url && !error ? /* @__PURE__ */ jsx4("div", { children: /* @__PURE__ */ jsx4(
471
384
  LanguageFieldEditor,
@@ -476,42 +389,27 @@ function CreateAudioAnnotationForm(props) {
476
389
  fields: label,
477
390
  onSave: (e) => setLabel(e.toInternationalString())
478
391
  },
479
- url + "__" + duration
392
+ `${url}__${duration}`
480
393
  ) }) : null,
481
- url && !error ? /* @__PURE__ */ jsx4(
482
- CanvasPanel.AudioHTML,
394
+ url && !error ? /* @__PURE__ */ jsx4(CanvasPanel.AudioHTML, { media: { url, duration, type: "Sound" }, children: /* @__PURE__ */ jsx4(
395
+ MediaControls,
483
396
  {
484
- media: { url, duration, type: "Sound" },
485
- children: /* @__PURE__ */ jsx4(
486
- MediaControls,
487
- {
488
- onError: (error2) => setError(error2),
489
- onDuration: (duration2) => setDuration(duration2)
490
- },
491
- url + "__" + duration
492
- )
397
+ onError: (error2) => setError(error2),
398
+ onDuration: (duration2) => setDuration(~~duration2)
493
399
  },
494
- url + "__" + duration
495
- ) : null,
400
+ `${url}__${duration}`
401
+ ) }, `${url}__${duration}`) : null,
496
402
  duration && !error ? /* @__PURE__ */ jsxs4(FormFieldWrapper, { children: [
497
403
  /* @__PURE__ */ jsx4(InputLabel, { htmlFor: "duration", children: "Duration" }),
498
- /* @__PURE__ */ jsx4(
499
- Input,
500
- {
501
- type: "number",
502
- id: "duration",
503
- value: duration,
504
- onChange: (e) => setDuration(e.target.valueAsNumber)
505
- }
506
- )
404
+ /* @__PURE__ */ jsx4(Input, { type: "number", id: "duration", value: duration, onChange: (e) => setDuration(e.target.valueAsNumber) })
507
405
  ] }) : null,
508
- 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" })
509
407
  ] });
510
408
  }
511
409
 
512
410
  // src/Annotation/AudioAnnotation/index.tsx
513
411
  import { jsx as jsx5 } from "react/jsx-runtime";
514
- var audioAnnotation = {
412
+ var audioAnnotation = defineCreator({
515
413
  id: "@manifest-editor/audio-annotation",
516
414
  create: createAudioAnnotation,
517
415
  label: "Audio",
@@ -531,18 +429,15 @@ var audioAnnotation = {
531
429
  staticFields: {
532
430
  type: "Annotation"
533
431
  }
534
- };
432
+ });
535
433
 
536
434
  // src/Annotation/CaptionedImageAnnotation/index.tsx
537
435
  import { AddImageIcon } from "@manifest-editor/components";
436
+ import { defineCreator as defineCreator2 } from "@manifest-editor/creator-api";
538
437
 
539
438
  // src/Annotation/CaptionedImageAnnotation/create-captioned-image-annotation.tsx
540
- import {
541
- Input as Input2,
542
- InputContainer as InputContainer2,
543
- InputLabel as InputLabel2,
544
- LanguageFieldEditor as LanguageFieldEditor2
545
- } from "@manifest-editor/editors";
439
+ import { ActionButton as ActionButton2 } from "@manifest-editor/components";
440
+ import { Input as Input2, InputContainer as InputContainer2, InputLabel as InputLabel2, LanguageFieldEditor as LanguageFieldEditor2 } from "@manifest-editor/editors";
546
441
  import { useState as useState3 } from "react";
547
442
  import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
548
443
  async function createCaptionedImageAnnotation(data, ctx) {
@@ -644,13 +539,13 @@ function CreateCaptionedImageAnnotation(props) {
644
539
  }
645
540
  )
646
541
  ] }),
647
- /* @__PURE__ */ jsx6(Button, { type: "submit", children: "Create" })
542
+ /* @__PURE__ */ jsx6(ActionButton2, { primary: true, large: true, type: "submit", children: "Create" })
648
543
  ] }) });
649
544
  }
650
545
 
651
546
  // src/Annotation/CaptionedImageAnnotation/index.tsx
652
547
  import { jsx as jsx7 } from "react/jsx-runtime";
653
- var captionedImageAnnotation = {
548
+ var captionedImageAnnotation = defineCreator2({
654
549
  id: "@manifest-editor/captioned-image-annotation",
655
550
  create: createCaptionedImageAnnotation,
656
551
  label: "Captioned image",
@@ -670,18 +565,17 @@ var captionedImageAnnotation = {
670
565
  staticFields: {
671
566
  type: "Annotation"
672
567
  }
673
- };
568
+ });
674
569
 
675
570
  // src/Annotation/HTMLAnnotation/index.tsx
676
- import { HTMLIcon as HTMLIcon2 } from "@manifest-editor/components";
571
+ import { HTMLIcon } from "@manifest-editor/components";
572
+ import { defineCreator as defineCreator3 } from "@manifest-editor/creator-api";
677
573
 
678
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";
679
578
  import { useState as useState4 } from "react";
680
- import {
681
- InputContainer as InputContainer3,
682
- InputLabel as InputLabel3,
683
- LanguageFieldEditor as LanguageFieldEditor3
684
- } from "@manifest-editor/editors";
685
579
  import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
686
580
  async function createHtmlAnnotation(data, ctx) {
687
581
  const annotation = {
@@ -746,36 +640,34 @@ async function createHtmlAnnotation(data, ctx) {
746
640
  }
747
641
  function CreateHTMLAnnotation(props) {
748
642
  const [body, setBody] = useState4({ en: [""] });
643
+ const isEmpty = getValue2(body).trim() === "";
749
644
  const onSubmit = () => {
750
645
  props.runCreate({
751
646
  body
752
647
  });
753
648
  };
754
649
  return /* @__PURE__ */ jsxs6(PaddedSidebarContainer, { children: [
755
- /* @__PURE__ */ jsxs6(InputContainer3, { children: [
756
- /* @__PURE__ */ jsx8(InputLabel3, { children: "HTML Body" }),
757
- /* @__PURE__ */ jsx8(
758
- LanguageFieldEditor3,
759
- {
760
- focusId: "html-content",
761
- label: "HTML Content",
762
- fields: body,
763
- onSave: (e) => setBody(e.toInternationalString())
764
- }
765
- )
766
- ] }),
767
- /* @__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" })
768
660
  ] });
769
661
  }
770
662
 
771
663
  // src/Annotation/HTMLAnnotation/index.tsx
772
664
  import { jsx as jsx9 } from "react/jsx-runtime";
773
- var htmlAnnotation = {
665
+ var htmlAnnotation = defineCreator3({
774
666
  id: "@manifest-editor/html-annotation",
775
667
  create: createHtmlAnnotation,
776
668
  label: "HTML",
777
669
  summary: "HTML annotation",
778
- icon: /* @__PURE__ */ jsx9(HTMLIcon2, {}),
670
+ icon: /* @__PURE__ */ jsx9(HTMLIcon, {}),
779
671
  render(ctx) {
780
672
  return /* @__PURE__ */ jsx9(CreateHTMLAnnotation, { ...ctx });
781
673
  },
@@ -790,10 +682,11 @@ var htmlAnnotation = {
790
682
  staticFields: {
791
683
  type: "Annotation"
792
684
  }
793
- };
685
+ });
794
686
 
795
687
  // src/Annotation/ImageServiceAnnotation/index.tsx
796
688
  import { IIIFLogo } from "@manifest-editor/components";
689
+ import { defineCreator as defineCreator4 } from "@manifest-editor/creator-api";
797
690
 
798
691
  // src/side-effects/reposition-multiple-images.ts
799
692
  import { isImageService } from "@iiif/parser/image-3";
@@ -981,16 +874,33 @@ var resizeToFitService = {
981
874
  }
982
875
  };
983
876
 
877
+ // src/Annotation/ImageServiceAnnotation/create-service-annotation.tsx
878
+ import {
879
+ creatorHelper
880
+ } from "@manifest-editor/creator-api";
881
+
984
882
  // src/ContentResource/ImageServiceCreator/create-image-service.tsx
985
883
  import {
986
- imageServiceRequestToString,
884
+ canonicalServiceUrl,
987
885
  createImageServiceRequest,
988
- canonicalServiceUrl
886
+ imageServiceRequestToString,
887
+ parseImageServiceRequest
989
888
  } from "@iiif/parser/image-3";
990
- 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";
991
894
  import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
992
895
  async function createImageServer(data, ctx) {
993
- 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);
994
904
  const imageId = imageServiceRequestToString({
995
905
  identifier: request.identifier,
996
906
  server: request.server,
@@ -1015,37 +925,64 @@ async function createImageServer(data, ctx) {
1015
925
  id: imageId,
1016
926
  type: "Image",
1017
927
  format: data.format || "image/jpeg",
1018
- height: data.height || data.service.height,
1019
- width: data.width || data.service.width,
928
+ height: data.height || service.height,
929
+ width: data.width || service.width,
1020
930
  service: data.embedService === false ? void 0 : [data.service]
1021
931
  });
1022
932
  return resource;
1023
933
  }
934
+ function getCanonicalUrl(url) {
935
+ return url.endsWith("default.jpg") ? imageServiceRequestToString({
936
+ ...parseImageServiceRequest(url),
937
+ type: "info"
938
+ }) : canonicalServiceUrl(url);
939
+ }
1024
940
  function CreateImageServerForm(props) {
941
+ const [url, setUrl] = useState5("");
1025
942
  const onSubmit = (e) => {
1026
943
  e.preventDefault();
1027
944
  const data = new FormData(e.target);
1028
945
  const formData = Object.fromEntries(data.entries());
1029
- const url = formData.url;
1030
- if (url) {
1031
- const canon = canonicalServiceUrl(url);
1032
- fetch(canon).then((r) => r.json()).then((service) => {
1033
- if (service["@id"]) {
1034
- service.id = service["@id"];
1035
- }
1036
- if (service["@type"]) {
1037
- service.type = service["@type"];
1038
- }
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) => {
1039
953
  props.runCreate({ url: formData.url, service });
1040
954
  });
1041
955
  }
1042
956
  };
1043
957
  return /* @__PURE__ */ jsx10(PaddedSidebarContainer, { children: /* @__PURE__ */ jsxs7("form", { onSubmit, children: [
1044
- /* @__PURE__ */ jsxs7(InputContainer4, { $wide: true, children: [
1045
- /* @__PURE__ */ jsx10(InputLabel4, { htmlFor: "id", children: "Link to image service" }),
1046
- /* @__PURE__ */ jsx10(Input3, { id: "url", name: "url", defaultValue: "" })
1047
- ] }),
1048
- /* @__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" }) })
1049
986
  ] }) });
1050
987
  }
1051
988
 
@@ -1057,13 +994,10 @@ async function createImageServiceAnnotation(data, ctx) {
1057
994
  type: "Annotation"
1058
995
  };
1059
996
  const targetType = ctx.options.targetType;
1060
- const resource = await ctx.create(
1061
- "@manifest-editor/image-service-creator",
1062
- data,
1063
- {
1064
- parent: { resource: annotation, property: "body" }
1065
- }
1066
- );
997
+ const createImage = creatorHelper(ctx, "Annotation", "body", "@manifest-editor/image-service-creator");
998
+ const resource = await createImage(data, {
999
+ parent: { resource: annotation, property: "body" }
1000
+ });
1067
1001
  if (targetType === "Annotation") {
1068
1002
  return {
1069
1003
  ...annotation,
@@ -1092,12 +1026,21 @@ async function createImageServiceAnnotation(data, ctx) {
1092
1026
  type: "AnnotationPage",
1093
1027
  items: [annotationResource]
1094
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
+ }
1095
1037
  return ctx.embed({
1096
1038
  id: canvasId,
1097
1039
  type: "Canvas",
1098
1040
  label: data.label || { en: ["Untitled canvas"] },
1099
1041
  height: resource.resource.height || 1e3,
1100
1042
  width: resource.resource.width || 1e3,
1043
+ thumbnail: thumbnail ? [thumbnail] : void 0,
1101
1044
  items: [page]
1102
1045
  });
1103
1046
  }
@@ -1108,7 +1051,7 @@ function CreateImageServiceAnnotationForm(props) {
1108
1051
 
1109
1052
  // src/Annotation/ImageServiceAnnotation/index.tsx
1110
1053
  import { jsx as jsx12 } from "react/jsx-runtime";
1111
- var imageServiceAnnotation = {
1054
+ var imageServiceAnnotation = defineCreator4({
1112
1055
  id: "@manifest-editor/image-service-annotation",
1113
1056
  create: createImageServiceAnnotation,
1114
1057
  label: "IIIF Image",
@@ -1126,22 +1069,25 @@ var imageServiceAnnotation = {
1126
1069
  parentTypes: ["AnnotationPage", "Manifest"],
1127
1070
  parentFields: ["items"]
1128
1071
  },
1129
- sideEffects: [
1130
- resizeToFitService,
1131
- resizeResourceToEmptyCanvas,
1132
- repositionMultipleImages
1133
- ],
1072
+ sideEffects: [resizeToFitService, resizeResourceToEmptyCanvas, repositionMultipleImages],
1134
1073
  staticFields: {
1135
1074
  type: "Annotation"
1136
1075
  }
1137
- };
1076
+ });
1138
1077
 
1139
1078
  // src/Annotation/ImageUrlAnnotation/index.tsx
1140
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";
1141
1086
 
1142
1087
  // src/ContentResource/ImageUrlCreator/create-image-url.tsx
1143
- import { InputContainer as InputContainer5, InputLabel as InputLabel5, Input as Input4 } from "@manifest-editor/editors";
1144
- 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";
1145
1091
  import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
1146
1092
  async function createImageUrl(data, ctx) {
1147
1093
  if (!data.height || !data.width) {
@@ -1170,11 +1116,11 @@ function CreateImageUrlForm(props) {
1170
1116
  }
1171
1117
  };
1172
1118
  return /* @__PURE__ */ jsx13(PaddedSidebarContainer, { children: /* @__PURE__ */ jsxs8("form", { onSubmit, children: [
1173
- /* @__PURE__ */ jsxs8(InputContainer5, { $wide: true, children: [
1174
- /* @__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" }),
1175
1121
  /* @__PURE__ */ jsx13(Input4, { id: "url", name: "url", defaultValue: "" })
1176
1122
  ] }),
1177
- /* @__PURE__ */ jsx13(Button, { type: "submit", children: "Create" })
1123
+ /* @__PURE__ */ jsx13(ActionButton5, { primary: true, large: true, type: "submit", children: "Create" })
1178
1124
  ] }) });
1179
1125
  }
1180
1126
 
@@ -1186,20 +1132,17 @@ async function createImageUrlAnnotation(data, ctx) {
1186
1132
  type: "Annotation"
1187
1133
  };
1188
1134
  const targetType = ctx.options.targetType;
1189
- const resource = await ctx.create(
1190
- "@manifest-editor/image-url-creator",
1191
- data,
1192
- {
1193
- parent: { resource: annotation, property: "body" }
1194
- }
1195
- );
1135
+ const createImage = creatorHelper2(ctx, "Annotation", "body", "@manifest-editor/image-url-creator");
1136
+ const resource = await createImage(data, {
1137
+ parent: { resource: annotation, property: "body" }
1138
+ });
1196
1139
  if (targetType === "Annotation") {
1197
- return {
1140
+ return ctx.embed({
1198
1141
  ...annotation,
1199
1142
  body: [resource],
1200
1143
  motivation: data.motivation || "painting",
1201
1144
  target: ctx.getTarget()
1202
- };
1145
+ });
1203
1146
  }
1204
1147
  if (targetType === "Canvas") {
1205
1148
  const canvasId = ctx.generateId("canvas");
@@ -1230,6 +1173,7 @@ async function createImageUrlAnnotation(data, ctx) {
1230
1173
  items: [page]
1231
1174
  });
1232
1175
  }
1176
+ throw new Error("Unsupported target type");
1233
1177
  }
1234
1178
  function CreateImageUrlAnnotationForm(props) {
1235
1179
  return /* @__PURE__ */ jsx14(CreateImageUrlForm, { ...props });
@@ -1237,7 +1181,7 @@ function CreateImageUrlAnnotationForm(props) {
1237
1181
 
1238
1182
  // src/Annotation/ImageUrlAnnotation/index.tsx
1239
1183
  import { jsx as jsx15 } from "react/jsx-runtime";
1240
- var imageUrlAnnotation = {
1184
+ var imageUrlAnnotation = defineCreator5({
1241
1185
  id: "@manifest-editor/image-url-annotation",
1242
1186
  create: createImageUrlAnnotation,
1243
1187
  label: "Image",
@@ -1255,25 +1199,95 @@ var imageUrlAnnotation = {
1255
1199
  parentTypes: ["AnnotationPage", "Manifest"],
1256
1200
  parentFields: ["items"]
1257
1201
  },
1258
- sideEffects: [
1259
- resizeToFitService,
1260
- resizeResourceToEmptyCanvas,
1261
- repositionMultipleImages
1262
- ],
1202
+ sideEffects: [resizeToFitService, resizeResourceToEmptyCanvas, repositionMultipleImages],
1263
1203
  staticFields: {
1264
1204
  type: "Annotation"
1265
1205
  }
1266
- };
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
+ });
1267
1280
 
1268
1281
  // src/Annotation/NoBodyAnnotation/index.tsx
1269
1282
  import { EmptyCanvasIcon } from "@manifest-editor/components";
1270
- import { jsx as jsx16 } from "react/jsx-runtime";
1271
- 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({
1272
1286
  id: "@manifest-editor/no-body-annotation",
1273
1287
  create: createNoBodyAnnotation,
1274
1288
  label: "Annotation without body",
1275
1289
  summary: "Add an annotation that only has motivation and target",
1276
- icon: /* @__PURE__ */ jsx16(EmptyCanvasIcon, {}),
1290
+ icon: /* @__PURE__ */ jsx18(EmptyCanvasIcon, {}),
1277
1291
  resourceType: "Annotation",
1278
1292
  resourceFields: ["id", "type", "motivation", "target"],
1279
1293
  supports: {
@@ -1286,7 +1300,7 @@ var noBodyAnnotation = {
1286
1300
  staticFields: {
1287
1301
  type: "Annotation"
1288
1302
  }
1289
- };
1303
+ });
1290
1304
  function createNoBodyAnnotation(data, ctx) {
1291
1305
  return ctx.embed({
1292
1306
  id: ctx.generateId("annotation"),
@@ -1299,21 +1313,16 @@ function createNoBodyAnnotation(data, ctx) {
1299
1313
 
1300
1314
  // src/Annotation/VideoAnnotation/index.tsx
1301
1315
  import { VideoIcon } from "@manifest-editor/components";
1316
+ import { defineCreator as defineCreator8 } from "@manifest-editor/creator-api";
1302
1317
 
1303
1318
  // src/Annotation/VideoAnnotation/create-video-annotation.tsx
1304
- import { getValue as getValue2 } from "@iiif/helpers";
1305
- import { ErrorMessage as ErrorMessage2 } from "@manifest-editor/components";
1306
- import {
1307
- DimensionsTriplet,
1308
- Input as Input5,
1309
- InputContainer as InputContainer6,
1310
- InputLabel as InputLabel6,
1311
- LanguageFieldEditor as LanguageFieldEditor4
1312
- } from "@manifest-editor/editors";
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";
1313
1322
 
1314
1323
  // ../ui/ui/VideoPlayer/VideoPlayer.tsx
1315
1324
  import { CanvasPanel as CanvasPanel2, MediaPlayerProvider, useSimpleMediaPlayer } from "react-iiif-vault";
1316
- import { jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
1325
+ import { jsx as jsx19, jsxs as jsxs10 } from "react/jsx-runtime";
1317
1326
  function VideoPlayer({
1318
1327
  media,
1319
1328
  onError,
@@ -1322,7 +1331,7 @@ function VideoPlayer({
1322
1331
  onDimensions
1323
1332
  }) {
1324
1333
  const [{ element, currentTime, progress }, state, actions] = useSimpleMediaPlayer({ duration });
1325
- return /* @__PURE__ */ jsxs9(
1334
+ return /* @__PURE__ */ jsxs10(
1326
1335
  MediaPlayerProvider,
1327
1336
  {
1328
1337
  element,
@@ -1331,7 +1340,7 @@ function VideoPlayer({
1331
1340
  currentTime,
1332
1341
  progress,
1333
1342
  children: [
1334
- /* @__PURE__ */ jsx17(
1343
+ /* @__PURE__ */ jsx19(
1335
1344
  "div",
1336
1345
  {
1337
1346
  style: {
@@ -1339,18 +1348,18 @@ function VideoPlayer({
1339
1348
  aspectRatio: `${media.width}/${media.height}`,
1340
1349
  position: "relative"
1341
1350
  },
1342
- children: /* @__PURE__ */ jsx17(CanvasPanel2.VideoHTML, { element, media, playPause: actions.playPause })
1351
+ children: /* @__PURE__ */ jsx19(CanvasPanel2.VideoHTML, { element, media, playPause: actions.playPause })
1343
1352
  }
1344
1353
  ),
1345
- /* @__PURE__ */ jsx17(MediaControls, { onError, onDuration, onDimensions })
1354
+ /* @__PURE__ */ jsx19(MediaControls, { onError, onDuration, onDimensions })
1346
1355
  ]
1347
1356
  }
1348
1357
  );
1349
1358
  }
1350
1359
 
1351
1360
  // src/Annotation/VideoAnnotation/create-video-annotation.tsx
1352
- import { useEffect as useEffect3, useState as useState5 } from "react";
1353
- 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";
1354
1363
  async function createVideoAnnotation(data, ctx) {
1355
1364
  const annotation = {
1356
1365
  id: ctx.generateId("annotation"),
@@ -1368,7 +1377,7 @@ async function createVideoAnnotation(data, ctx) {
1368
1377
  if (targetType === "Annotation") {
1369
1378
  return ctx.embed({
1370
1379
  ...annotation,
1371
- label: getValue2(data.label) && data.label,
1380
+ label: getValue3(data.label) && data.label,
1372
1381
  motivation: data.motivation || ctx.options.initialData?.motivation || "painting",
1373
1382
  body,
1374
1383
  target: ctx.getTarget()
@@ -1406,12 +1415,12 @@ async function createVideoAnnotation(data, ctx) {
1406
1415
  }
1407
1416
  }
1408
1417
  function CreateVideoAnnotationForm(props) {
1409
- const [url, setUrl] = useState5("");
1410
- const [duration, setDuration] = useState5(0);
1411
- const [width, setWidth] = useState5(0);
1412
- const [height, setHeight] = useState5(0);
1413
- const [error, setError] = useState5("");
1414
- 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: [""] });
1415
1424
  const onSubmit = () => {
1416
1425
  props.runCreate({
1417
1426
  url,
@@ -1429,21 +1438,13 @@ function CreateVideoAnnotationForm(props) {
1429
1438
  setLabel({ en: [labelFromUrl || ""] });
1430
1439
  }
1431
1440
  }, [url]);
1432
- return /* @__PURE__ */ jsxs10(PaddedSidebarContainer, { children: [
1433
- error ? /* @__PURE__ */ jsx18(ErrorMessage2, { children: error }) : null,
1434
- /* @__PURE__ */ jsxs10(InputContainer6, { children: [
1435
- /* @__PURE__ */ jsx18(InputLabel6, { htmlFor: "video-url", children: "URL" }),
1436
- /* @__PURE__ */ jsx18(
1437
- Input5,
1438
- {
1439
- type: "text",
1440
- id: "video-url",
1441
- value: url,
1442
- onChange: (e) => setUrl(e.target.value)
1443
- }
1444
- )
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) })
1445
1446
  ] }),
1446
- url && !error ? /* @__PURE__ */ jsx18("div", { children: /* @__PURE__ */ jsx18(
1447
+ url && !error ? /* @__PURE__ */ jsx20("div", { children: /* @__PURE__ */ jsx20(
1447
1448
  LanguageFieldEditor4,
1448
1449
  {
1449
1450
  containerId: "label",
@@ -1452,9 +1453,9 @@ function CreateVideoAnnotationForm(props) {
1452
1453
  fields: label,
1453
1454
  onSave: (e) => setLabel(e.toInternationalString())
1454
1455
  },
1455
- url + "__" + duration
1456
+ `${url}__${duration}`
1456
1457
  ) }) : null,
1457
- url && !error ? /* @__PURE__ */ jsx18(
1458
+ url && !error ? /* @__PURE__ */ jsx20("div", { className: "mb-4 bg-black", children: /* @__PURE__ */ jsx20(
1458
1459
  VideoPlayer,
1459
1460
  {
1460
1461
  duration,
@@ -1472,8 +1473,8 @@ function CreateVideoAnnotationForm(props) {
1472
1473
  setHeight(h || 0);
1473
1474
  }
1474
1475
  }
1475
- ) : null,
1476
- !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(
1477
1478
  DimensionsTriplet,
1478
1479
  {
1479
1480
  widthId: "width",
@@ -1487,20 +1488,20 @@ function CreateVideoAnnotationForm(props) {
1487
1488
  changeDuration: (v) => setDuration(v)
1488
1489
  }
1489
1490
  ) }) : null,
1490
- 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" })
1491
1492
  ] });
1492
1493
  }
1493
1494
 
1494
1495
  // src/Annotation/VideoAnnotation/index.tsx
1495
- import { jsx as jsx19 } from "react/jsx-runtime";
1496
- var videoAnnotation = {
1496
+ import { jsx as jsx21 } from "react/jsx-runtime";
1497
+ var videoAnnotation = defineCreator8({
1497
1498
  id: "@manifest-editor/video-annotation",
1498
1499
  create: createVideoAnnotation,
1499
1500
  label: "Video",
1500
1501
  summary: "Video annotation",
1501
- icon: /* @__PURE__ */ jsx19(VideoIcon, {}),
1502
+ icon: /* @__PURE__ */ jsx21(VideoIcon, {}),
1502
1503
  render(ctx) {
1503
- return /* @__PURE__ */ jsx19(CreateVideoAnnotationForm, { ...ctx });
1504
+ return /* @__PURE__ */ jsx21(CreateVideoAnnotationForm, { ...ctx });
1504
1505
  },
1505
1506
  resourceType: "Annotation",
1506
1507
  resourceFields: ["id", "type", "motivation", "body", "target"],
@@ -1513,11 +1514,14 @@ var videoAnnotation = {
1513
1514
  staticFields: {
1514
1515
  type: "Annotation"
1515
1516
  }
1516
- };
1517
+ });
1518
+
1519
+ // src/AnnotationPage/EmptyAnnotationPage/index.tsx
1520
+ import { defineCreator as defineCreator9 } from "@manifest-editor/creator-api";
1517
1521
 
1518
1522
  // ../ui/icons/ThumbnailStripIcon.tsx
1519
- import { jsx as jsx20, jsxs as jsxs11 } from "react/jsx-runtime";
1520
- var ThumbnailStripIcon = () => /* @__PURE__ */ jsx20(
1523
+ import { jsx as jsx22, jsxs as jsxs12 } from "react/jsx-runtime";
1524
+ var ThumbnailStripIcon = () => /* @__PURE__ */ jsx22(
1521
1525
  "svg",
1522
1526
  {
1523
1527
  xmlns: "http://www.w3.org/2000/svg",
@@ -1526,16 +1530,16 @@ var ThumbnailStripIcon = () => /* @__PURE__ */ jsx20(
1526
1530
  width: "24px",
1527
1531
  fill: "#000000",
1528
1532
  transform: "scale(-1, 1)",
1529
- children: /* @__PURE__ */ jsxs11("g", { children: [
1530
- /* @__PURE__ */ jsx20("rect", { fill: "none", height: "24", width: "24" }),
1531
- /* @__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" })
1532
1536
  ] })
1533
1537
  }
1534
1538
  );
1535
1539
 
1536
1540
  // src/AnnotationPage/EmptyAnnotationPage/index.tsx
1537
- import { jsx as jsx21 } from "react/jsx-runtime";
1538
- var emptyAnnotationPage = {
1541
+ import { jsx as jsx23 } from "react/jsx-runtime";
1542
+ var emptyAnnotationPage = defineCreator9({
1539
1543
  id: "@manifest-editor/empty-annotation-page",
1540
1544
  create: (data, ctx) => {
1541
1545
  return ctx.embed({
@@ -1547,7 +1551,7 @@ var emptyAnnotationPage = {
1547
1551
  },
1548
1552
  label: "Empty annotation page",
1549
1553
  summary: "AnnotationPage with nothing",
1550
- icon: /* @__PURE__ */ jsx21(ThumbnailStripIcon, {}),
1554
+ icon: /* @__PURE__ */ jsx23(ThumbnailStripIcon, {}),
1551
1555
  resourceType: "AnnotationPage",
1552
1556
  resourceFields: ["id", "type", "items"],
1553
1557
  supports: {
@@ -1558,12 +1562,13 @@ var emptyAnnotationPage = {
1558
1562
  Range: ["annotations"]
1559
1563
  }
1560
1564
  }
1561
- };
1565
+ });
1562
1566
 
1563
1567
  // src/Canvas/EmptyCanvas/index.tsx
1564
1568
  import { EmptyCanvasIcon as EmptyCanvasIcon2 } from "@manifest-editor/components";
1565
- import { jsx as jsx22 } from "react/jsx-runtime";
1566
- 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({
1567
1572
  id: "@manifest-editor/empty-canvas",
1568
1573
  create: (data, ctx) => {
1569
1574
  const canvasId = ctx.generateId("canvas");
@@ -1583,16 +1588,17 @@ var emptyCanvas = {
1583
1588
  },
1584
1589
  label: "Empty canvas",
1585
1590
  summary: "No content",
1586
- icon: /* @__PURE__ */ jsx22(EmptyCanvasIcon2, {}),
1591
+ icon: /* @__PURE__ */ jsx24(EmptyCanvasIcon2, {}),
1587
1592
  resourceType: "Canvas",
1588
1593
  resourceFields: ["id", "type", "label", "height", "width", "items"],
1589
1594
  supports: {
1590
1595
  parentTypes: ["Manifest"],
1591
1596
  parentFields: ["items"]
1592
1597
  }
1593
- };
1598
+ });
1594
1599
 
1595
1600
  // src/Canvas/InternalCanvas/index.tsx
1601
+ import { defineCreator as defineCreator11 } from "@manifest-editor/creator-api";
1596
1602
  import { IIIFExplorer } from "@manifest-editor/iiif-browser";
1597
1603
  import { useManifest, useVault } from "react-iiif-vault";
1598
1604
 
@@ -1612,26 +1618,26 @@ function invariant(condition, message) {
1612
1618
  }
1613
1619
 
1614
1620
  // src/Canvas/InternalCanvas/index.tsx
1615
- import { jsx as jsx23 } from "react/jsx-runtime";
1616
- var internalCanvas = {
1621
+ import { jsx as jsx25 } from "react/jsx-runtime";
1622
+ var internalCanvas = defineCreator11({
1617
1623
  id: "@manifest-editor/internal-canvas",
1618
1624
  create: createInternalCanvas,
1619
1625
  label: "Internal canvas link",
1620
1626
  summary: "Canvas from the same manifest",
1621
- icon: /* @__PURE__ */ jsx23(ThumbnailStripIcon, {}),
1627
+ icon: /* @__PURE__ */ jsx25(ThumbnailStripIcon, {}),
1622
1628
  resourceType: "Canvas",
1623
1629
  resourceFields: ["id", "type", "label"],
1624
1630
  supports: {
1625
1631
  parentTypes: ["Manifest"],
1626
1632
  parentFields: ["start"]
1627
1633
  },
1628
- render: (ctx) => /* @__PURE__ */ jsx23(InternalCanvas, { ...ctx })
1629
- };
1634
+ render: (ctx) => /* @__PURE__ */ jsx25(InternalCanvas, { ...ctx })
1635
+ });
1630
1636
  function InternalCanvas(props) {
1631
1637
  const manifest = useManifest();
1632
1638
  const vault = useVault();
1633
1639
  invariant(manifest, "Manifest is not loaded");
1634
- return /* @__PURE__ */ jsx23(
1640
+ return /* @__PURE__ */ jsx25(
1635
1641
  IIIFExplorer,
1636
1642
  {
1637
1643
  vault,
@@ -1657,22 +1663,22 @@ async function createInternalCanvas(data, ctx) {
1657
1663
  return ctx.embed({ id: data.id, type: "Canvas" });
1658
1664
  }
1659
1665
 
1666
+ // src/ContentResource/HTMLBodyCreator/index.tsx
1667
+ import { defineCreator as defineCreator12 } from "@manifest-editor/creator-api";
1668
+
1660
1669
  // ../ui/icons/TextFormatIcon.tsx
1661
- import { jsx as jsx24, jsxs as jsxs12 } from "react/jsx-runtime";
1662
- var TextFormatIcon = (props) => /* @__PURE__ */ jsxs12("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", height: "1em", width: "1em", ...props, children: [
1663
- /* @__PURE__ */ jsx24("path", { d: "M0 0h24v24H0z", fill: "none" }),
1664
- /* @__PURE__ */ jsx24("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" })
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" })
1665
1674
  ] });
1666
1675
 
1667
1676
  // src/ContentResource/HTMLBodyCreator/create-html-body.tsx
1668
- import {
1669
- InputContainer as InputContainer7,
1670
- InputLabel as InputLabel7,
1671
- RichTextLanguageField
1672
- } 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";
1673
1679
  import { useConfig } from "@manifest-editor/shell";
1674
- import { useState as useState6 } from "react";
1675
- import { jsx as jsx25, jsxs as jsxs13 } from "react/jsx-runtime";
1680
+ import { useState as useState7 } from "react";
1681
+ import { jsx as jsx27, jsxs as jsxs14 } from "react/jsx-runtime";
1676
1682
  async function createHtmlBody(data, ctx) {
1677
1683
  return ctx.embed({
1678
1684
  id: ctx.generateId(`html/${data.language}`),
@@ -1684,18 +1690,18 @@ async function createHtmlBody(data, ctx) {
1684
1690
  }
1685
1691
  function CreateHTMLBodyForm(props) {
1686
1692
  const { i18n } = useConfig();
1687
- const [body, setBodyValue] = useState6("<p></p>");
1688
- const [language, setLang] = useState6(i18n.defaultLanguage);
1693
+ const [body, setBodyValue] = useState7("<p></p>");
1694
+ const [language, setLang] = useState7(i18n.defaultLanguage);
1689
1695
  const onSubmit = () => {
1690
1696
  props.runCreate({
1691
1697
  language,
1692
1698
  body
1693
1699
  });
1694
1700
  };
1695
- return /* @__PURE__ */ jsxs13(PaddedSidebarContainer, { children: [
1696
- /* @__PURE__ */ jsxs13(InputContainer7, { children: [
1697
- /* @__PURE__ */ jsx25(InputLabel7, { children: "HTML Body" }),
1698
- /* @__PURE__ */ jsx25(
1701
+ return /* @__PURE__ */ jsxs14(PaddedSidebarContainer, { children: [
1702
+ /* @__PURE__ */ jsxs14(InputContainer6, { children: [
1703
+ /* @__PURE__ */ jsx27(InputLabel6, { children: "HTML Body" }),
1704
+ /* @__PURE__ */ jsx27(
1699
1705
  RichTextLanguageField,
1700
1706
  {
1701
1707
  value: body,
@@ -1706,20 +1712,20 @@ function CreateHTMLBodyForm(props) {
1706
1712
  }
1707
1713
  )
1708
1714
  ] }),
1709
- /* @__PURE__ */ jsx25(Button, { onClick: () => onSubmit(), children: "Create" })
1715
+ /* @__PURE__ */ jsx27(ActionButton8, { primary: true, large: true, type: "button", onPress: onSubmit, children: "Create" })
1710
1716
  ] });
1711
1717
  }
1712
1718
 
1713
1719
  // src/ContentResource/HTMLBodyCreator/index.tsx
1714
- import { jsx as jsx26 } from "react/jsx-runtime";
1715
- var htmlBodyCreator = {
1720
+ import { jsx as jsx28 } from "react/jsx-runtime";
1721
+ var htmlBodyCreator = defineCreator12({
1716
1722
  id: "@manifest-editor/html-body-creator",
1717
1723
  create: createHtmlBody,
1718
1724
  label: "HTML Body",
1719
1725
  summary: "Add HTML annotation body",
1720
- icon: /* @__PURE__ */ jsx26(TextFormatIcon, {}),
1726
+ icon: /* @__PURE__ */ jsx28(TextFormatIcon, {}),
1721
1727
  render(ctx) {
1722
- return /* @__PURE__ */ jsx26(CreateHTMLBodyForm, { ...ctx });
1728
+ return /* @__PURE__ */ jsx28(CreateHTMLBodyForm, { ...ctx });
1723
1729
  },
1724
1730
  resourceType: "ContentResource",
1725
1731
  resourceFields: ["id", "language", "type", "format", "value"],
@@ -1731,17 +1737,14 @@ var htmlBodyCreator = {
1731
1737
  type: "TextualBody",
1732
1738
  format: "text/html"
1733
1739
  }
1734
- };
1740
+ });
1735
1741
 
1736
1742
  // src/ContentResource/IIIFBrowserCreator/index.tsx
1737
1743
  import { IIIFBrowserIcon } from "@manifest-editor/components";
1744
+ import { defineCreator as defineCreator13 } from "@manifest-editor/creator-api";
1738
1745
 
1739
1746
  // src/ContentResource/IIIFBrowserCreator/iiif-browser-creator.tsx
1740
- import {
1741
- Vault,
1742
- normaliseContentState,
1743
- parseContentState
1744
- } from "@iiif/helpers";
1747
+ import { Vault } from "@iiif/helpers";
1745
1748
  import { getImageServices } from "@iiif/parser/image-3";
1746
1749
  import { lazy } from "react";
1747
1750
  function croppedRegion(imageServiceId, region, size) {
@@ -1751,145 +1754,148 @@ function croppedRegion(imageServiceId, region, size) {
1751
1754
  }
1752
1755
  async function createFromIIIFBrowserOutput(data, ctx) {
1753
1756
  const targetType = ctx.options.targetType;
1754
- if (Array.isArray(data.output)) {
1755
- throw new Error("Multiple items not yet supported");
1756
- }
1757
- const contentState = normaliseContentState(
1758
- typeof data.output === "string" ? parseContentState(data.output) : data.output
1759
- );
1760
- if (!contentState.target || contentState.target.length === 0) {
1761
- throw new Error("No target found in content state");
1762
- }
1763
- const target = contentState.target[0];
1764
- const type = target.source.type;
1765
- const previewVault = new Vault();
1766
- if (targetType === "Canvas" || targetType === "Annotation" || targetType === "ContentResource") {
1767
- if (type === "Canvas") {
1768
- const canvasId = target.source.id;
1769
- const manifestId = target.source.partOf?.find(
1770
- (t) => t.type === "Manifest"
1771
- );
1772
- invariant(manifestId, "Could not load external resource without partOf");
1773
- const manifest = await previewVault.loadManifest(manifestId);
1774
- invariant(manifest, "Manifest not found");
1775
- const canvasRef = manifest.items.find((item) => item.id === canvasId);
1776
- invariant(canvasRef, "Canvas not found");
1777
- const canvas = previewVault.get(canvasRef);
1778
- if (targetType === "Canvas" && target.selector?.type !== "BoxSelector") {
1779
- return ctx.embed(previewVault.toPresentation3(canvas));
1780
- }
1781
- const annotationPage = previewVault.get(canvas.items[0]);
1782
- const annotation = previewVault.get(annotationPage.items[0]);
1783
- if (targetType === "Annotation" || targetType === "Canvas" || targetType === "ContentResource") {
1784
- const fullAnnotation = previewVault.toPresentation3(annotation);
1785
- fullAnnotation.id = ctx.generateId("Annotation");
1786
- let service = null;
1787
- const dimensions = { width: 0, height: 0 };
1788
- if (fullAnnotation?.body?.service) {
1789
- const width = fullAnnotation?.body.width;
1790
- const height = fullAnnotation?.body.height;
1791
- service = getImageServices(fullAnnotation?.body)[0];
1792
- if (service && (!service.width || !service.height)) {
1793
- service.width = width;
1794
- service.height = height;
1795
- }
1796
- dimensions.width = width;
1797
- dimensions.height = height;
1798
- if (data.trackSize) {
1799
- data.trackSize(dimensions);
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"] };
1800
1776
  }
1777
+ returnResources.push(ctx.embed(fullCanvas));
1778
+ continue;
1801
1779
  }
1802
- if (target.selector && target.selector.type === "BoxSelector") {
1803
- const selector = {
1804
- "@context": "http://iiif.io/api/annex/openannotation/context.json",
1805
- type: "iiif:ImageApiSelector",
1806
- region: [
1807
- ~~target.selector.spatial.x,
1808
- ~~target.selector.spatial.y,
1809
- ~~target.selector.spatial.width,
1810
- ~~target.selector.spatial.height
1811
- ].join(",")
1812
- };
1813
- const newBody = { ...fullAnnotation.body };
1814
- let thumbnailId = "";
1815
- if (service) {
1816
- const id = service.id || service["@id"] || "";
1817
- if (id) {
1818
- newBody.id = croppedRegion(id, target.selector.spatial, "max");
1819
- thumbnailId = croppedRegion(id, target.selector.spatial, "512,");
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);
1820
1799
  }
1821
1800
  }
1822
- fullAnnotation.body = {
1823
- id: ctx.generateId("SpecificResource", annotation),
1824
- type: "SpecificResource",
1825
- source: newBody,
1826
- selector
1827
- };
1828
- if (data.trackSize) {
1829
- data.trackSize({
1830
- width: ~~target.selector.spatial.width,
1831
- height: ~~target.selector.spatial.height
1832
- });
1833
- }
1834
- if (targetType === "ContentResource") {
1835
- return fullAnnotation.body;
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
- return ctx.embed({
1847
- id: canvasId2,
1848
- type: "Canvas",
1849
- width: ~~target.selector.spatial.width,
1850
- height: ~~target.selector.spatial.height,
1851
- thumbnail: thumbnailId ? [
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(
1852
1847
  ctx.embed({
1853
- id: thumbnailId,
1854
- type: "Image",
1855
- format: "image/jpeg",
1856
- width: 512,
1857
- height: Math.round(
1858
- target.selector.spatial.height / target.selector.spatial.width * 512
1859
- )
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]
1860
1863
  })
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;
1864
1874
  }
1865
- return ctx.embed({
1866
- ...fullAnnotation,
1867
- target: ctx.getTarget()
1868
- });
1875
+ returnResources.push(
1876
+ ctx.embed({
1877
+ ...previewVault.toPresentation3(annotation),
1878
+ target: ctx.getTarget()
1879
+ })
1880
+ );
1869
1881
  }
1870
- return ctx.embed({
1871
- ...previewVault.toPresentation3(annotation),
1872
- target: ctx.getTarget()
1873
- });
1874
1882
  }
1875
1883
  }
1876
1884
  }
1877
- throw new Error("Not yet supported.");
1885
+ return returnResources;
1878
1886
  }
1879
- var IIIFBrowserCreatorForm = lazy(
1880
- () => import("./iiif-browser-form.lazy-HZ3M2DXT.js")
1881
- );
1887
+ var IIIFBrowserCreatorForm = lazy(() => import("./iiif-browser-form.lazy-FQDZQ3UW.js"));
1882
1888
 
1883
1889
  // src/ContentResource/IIIFBrowserCreator/index.tsx
1884
- import { jsx as jsx27 } from "react/jsx-runtime";
1885
- var iiifBrowserCreator = {
1890
+ import { jsx as jsx29 } from "react/jsx-runtime";
1891
+ var iiifBrowserCreator = defineCreator13({
1886
1892
  id: "@manifest-editor/iiif-browser-creator",
1887
1893
  create: createFromIIIFBrowserOutput,
1888
1894
  label: "IIIF Browser",
1889
1895
  summary: "Browse IIIF Resources",
1890
- icon: /* @__PURE__ */ jsx27(IIIFBrowserIcon, {}),
1896
+ icon: /* @__PURE__ */ jsx29(IIIFBrowserIcon, {}),
1891
1897
  render(ctx) {
1892
- return /* @__PURE__ */ jsx27(IIIFBrowserCreatorForm, { ...ctx });
1898
+ return /* @__PURE__ */ jsx29(IIIFBrowserCreatorForm, { ...ctx });
1893
1899
  },
1894
1900
  hiddenModal: true,
1895
1901
  tags: ["image", "image-service"],
@@ -1898,49 +1904,49 @@ var iiifBrowserCreator = {
1898
1904
  additionalTypes: ["Annotation", "Canvas"],
1899
1905
  supports: {
1900
1906
  parentTypes: ["Annotation", "Manifest", "AnnotationPage"],
1907
+ parentFields: ["body", "items"],
1901
1908
  parentFieldMap: {
1902
1909
  Annotation: ["body"],
1903
1910
  Manifest: ["items"],
1904
1911
  AnnotationPage: ["items"]
1905
1912
  }
1906
1913
  },
1907
- sideEffects: [
1908
- resizeToFitService,
1909
- resizeResourceToEmptyCanvas,
1910
- repositionMultipleImages
1911
- ],
1914
+ sideEffects: [resizeToFitService, resizeResourceToEmptyCanvas, repositionMultipleImages],
1912
1915
  staticFields: {}
1913
- };
1916
+ });
1914
1917
 
1915
1918
  // src/ContentResource/ImageServiceCreator/index.tsx
1916
- import { jsx as jsx28 } from "react/jsx-runtime";
1917
- 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({
1918
1923
  id: "@manifest-editor/image-service-creator",
1919
1924
  create: createImageServer,
1920
1925
  label: "Image Service",
1921
1926
  summary: "Add an image from Image Service",
1922
- icon: /* @__PURE__ */ jsx28(TextFormatIcon, {}),
1927
+ icon: /* @__PURE__ */ jsx30(IIIFLogo2, { style: { padding: 10 } }),
1923
1928
  render(ctx) {
1924
- return /* @__PURE__ */ jsx28(CreateImageServerForm, { ...ctx });
1929
+ return /* @__PURE__ */ jsx30(CreateImageServerForm, { ...ctx });
1925
1930
  },
1926
1931
  resourceType: "ContentResource",
1927
1932
  resourceFields: ["id", "type", "height", "width", "format", "service"],
1928
1933
  supports: {
1929
1934
  parentFields: ["logo", "body", "thumbnail"]
1930
1935
  }
1931
- };
1936
+ });
1932
1937
 
1933
1938
  // src/ContentResource/ImageUrlCreator/index.tsx
1934
1939
  import { AddImageIcon as AddImageIcon3 } from "@manifest-editor/components";
1935
- import { jsx as jsx29 } from "react/jsx-runtime";
1936
- 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({
1937
1943
  id: "@manifest-editor/image-url-creator",
1938
1944
  create: createImageUrl,
1939
1945
  label: "Image",
1940
1946
  summary: "Image from a URL",
1941
- icon: /* @__PURE__ */ jsx29(AddImageIcon3, {}),
1947
+ icon: /* @__PURE__ */ jsx31(AddImageIcon3, {}),
1942
1948
  render(ctx) {
1943
- return /* @__PURE__ */ jsx29(CreateImageUrlForm, { ...ctx });
1949
+ return /* @__PURE__ */ jsx31(CreateImageUrlForm, { ...ctx });
1944
1950
  },
1945
1951
  resourceType: "ContentResource",
1946
1952
  resourceFields: ["format"],
@@ -1950,17 +1956,39 @@ var imageUrlCreator = {
1950
1956
  staticFields: {
1951
1957
  type: "Image"
1952
1958
  }
1953
- };
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";
1954
1986
 
1955
1987
  // src/ContentResource/PlaintextCreator/create-plaintext.tsx
1956
- import {
1957
- LanguageFieldEditor as LanguageFieldEditor5,
1958
- InputContainer as InputContainer8,
1959
- InputLabel as InputLabel8,
1960
- Input as Input6
1961
- } from "@manifest-editor/editors";
1962
- import { useState as useState7 } from "react";
1963
- 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";
1964
1992
  async function createPlaintext(data, ctx) {
1965
1993
  return ctx.embed({
1966
1994
  id: data.url,
@@ -1970,7 +1998,7 @@ async function createPlaintext(data, ctx) {
1970
1998
  });
1971
1999
  }
1972
2000
  function CreatePlaintextForm(props) {
1973
- const [label, setLabel] = useState7({
2001
+ const [label, setLabel] = useState8({
1974
2002
  en: ["View as text"]
1975
2003
  });
1976
2004
  const onSubmit = (e) => {
@@ -1981,8 +2009,8 @@ function CreatePlaintextForm(props) {
1981
2009
  props.runCreate({ url: formData.url, label });
1982
2010
  }
1983
2011
  };
1984
- return /* @__PURE__ */ jsx30(PaddedSidebarContainer, { children: /* @__PURE__ */ jsxs14("form", { onSubmit, children: [
1985
- /* @__PURE__ */ jsx30(
2012
+ return /* @__PURE__ */ jsx33(PaddedSidebarContainer, { children: /* @__PURE__ */ jsxs15("form", { onSubmit, children: [
2013
+ /* @__PURE__ */ jsx33(
1986
2014
  LanguageFieldEditor5,
1987
2015
  {
1988
2016
  focusId: "label",
@@ -1991,24 +2019,24 @@ function CreatePlaintextForm(props) {
1991
2019
  onSave: (e) => setLabel(e.toInternationalString())
1992
2020
  }
1993
2021
  ),
1994
- /* @__PURE__ */ jsxs14(InputContainer8, { $wide: true, children: [
1995
- /* @__PURE__ */ jsx30(InputLabel8, { htmlFor: "id", children: "Link to plaintext" }),
1996
- /* @__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: "" })
1997
2025
  ] }),
1998
- /* @__PURE__ */ jsx30(Button, { type: "submit", children: "Create" })
2026
+ /* @__PURE__ */ jsx33(ActionButton9, { primary: true, large: true, type: "submit", children: "Create" })
1999
2027
  ] }) });
2000
2028
  }
2001
2029
 
2002
2030
  // src/ContentResource/PlaintextCreator/index.tsx
2003
- import { jsx as jsx31 } from "react/jsx-runtime";
2004
- var plaintextCreator = {
2031
+ import { jsx as jsx34 } from "react/jsx-runtime";
2032
+ var plaintextCreator = defineCreator17({
2005
2033
  id: "@manifest-editor/plaintext-creator",
2006
2034
  create: createPlaintext,
2007
2035
  label: "Plaintext",
2008
2036
  summary: "Add link to an plaintext",
2009
- icon: /* @__PURE__ */ jsx31(TextFormatIcon, {}),
2037
+ icon: /* @__PURE__ */ jsx34(TextFormatIcon, {}),
2010
2038
  render(ctx) {
2011
- return /* @__PURE__ */ jsx31(CreatePlaintextForm, { ...ctx });
2039
+ return /* @__PURE__ */ jsx34(CreatePlaintextForm, { ...ctx });
2012
2040
  },
2013
2041
  resourceType: "ContentResource",
2014
2042
  resourceFields: ["label", "format"],
@@ -2018,26 +2046,228 @@ var plaintextCreator = {
2018
2046
  staticFields: {
2019
2047
  format: "text/plain"
2020
2048
  }
2021
- };
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";
2022
2256
 
2023
2257
  // ../ui/icons/LinkIcon.tsx
2024
- import { jsx as jsx32, jsxs as jsxs15 } from "react/jsx-runtime";
2258
+ import { jsx as jsx37, jsxs as jsxs17 } from "react/jsx-runtime";
2025
2259
  function LinkIcon() {
2026
- return /* @__PURE__ */ jsxs15("svg", { xmlns: "http://www.w3.org/2000/svg", height: "24px", viewBox: "0 0 24 24", width: "24px", fill: "#000000", children: [
2027
- /* @__PURE__ */ jsx32("path", { d: "M0 0h24v24H0z", fill: "none" }),
2028
- /* @__PURE__ */ jsx32("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" })
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" })
2029
2263
  ] });
2030
2264
  }
2031
2265
 
2032
2266
  // src/ContentResource/WebPageCreator/create-web-page.tsx
2033
- import {
2034
- LanguageFieldEditor as LanguageFieldEditor6,
2035
- InputContainer as InputContainer9,
2036
- InputLabel as InputLabel9,
2037
- Input as Input7
2038
- } from "@manifest-editor/editors";
2039
- import { useState as useState8 } from "react";
2040
- import { jsx as jsx33, jsxs as jsxs16 } 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";
2041
2271
  async function createWebPage(data, ctx) {
2042
2272
  return ctx.embed({
2043
2273
  id: data.url,
@@ -2047,7 +2277,7 @@ async function createWebPage(data, ctx) {
2047
2277
  });
2048
2278
  }
2049
2279
  function CreateWebPageForm(props) {
2050
- const [label, setLabel] = useState8({ en: [""] });
2280
+ const [label, setLabel] = useState10({ en: [""] });
2051
2281
  const onSubmit = (e) => {
2052
2282
  e.preventDefault();
2053
2283
  const data = new FormData(e.target);
@@ -2056,8 +2286,8 @@ function CreateWebPageForm(props) {
2056
2286
  props.runCreate({ url: formData.url, label });
2057
2287
  }
2058
2288
  };
2059
- return /* @__PURE__ */ jsx33(PaddedSidebarContainer, { children: /* @__PURE__ */ jsxs16("form", { onSubmit, children: [
2060
- /* @__PURE__ */ jsx33(
2289
+ return /* @__PURE__ */ jsx38(PaddedSidebarContainer, { children: /* @__PURE__ */ jsxs18("form", { onSubmit, children: [
2290
+ /* @__PURE__ */ jsx38(
2061
2291
  LanguageFieldEditor6,
2062
2292
  {
2063
2293
  focusId: "label",
@@ -2066,38 +2296,40 @@ function CreateWebPageForm(props) {
2066
2296
  onSave: (e) => setLabel(e.toInternationalString())
2067
2297
  }
2068
2298
  ),
2069
- /* @__PURE__ */ jsxs16(InputContainer9, { $wide: true, children: [
2070
- /* @__PURE__ */ jsx33(InputLabel9, { htmlFor: "id", children: "Link" }),
2071
- /* @__PURE__ */ jsx33(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: "" })
2072
2302
  ] }),
2073
- /* @__PURE__ */ jsx33(Button, { type: "submit", children: "Create link" })
2303
+ /* @__PURE__ */ jsx38(ActionButton11, { primary: true, large: true, type: "submit", children: "Create link" })
2074
2304
  ] }) });
2075
2305
  }
2076
2306
 
2077
2307
  // src/ContentResource/WebPageCreator/index.tsx
2078
- import { jsx as jsx34 } from "react/jsx-runtime";
2079
- var webPageCreator = {
2308
+ import { jsx as jsx39 } from "react/jsx-runtime";
2309
+ var webPageCreator = defineCreator19({
2080
2310
  id: "@manifest-editor/web-page-creator",
2081
2311
  create: createWebPage,
2082
2312
  label: "Web page",
2083
2313
  summary: "Add link to an external web page",
2084
- icon: /* @__PURE__ */ jsx34(LinkIcon, {}),
2314
+ icon: /* @__PURE__ */ jsx39(LinkIcon, {}),
2085
2315
  render(ctx) {
2086
- return /* @__PURE__ */ jsx34(CreateWebPageForm, { ...ctx });
2316
+ return /* @__PURE__ */ jsx39(CreateWebPageForm, { ...ctx });
2087
2317
  },
2088
2318
  resourceType: "ContentResource",
2089
2319
  resourceFields: ["label", "format"],
2090
2320
  supports: {
2091
2321
  parentFields: ["seeAlso", "rendering", "homepage"]
2092
2322
  }
2093
- };
2323
+ });
2094
2324
 
2095
2325
  // src/ContentResource/YouTubeCreator/index.tsx
2096
2326
  import { YouTubeIcon } from "@manifest-editor/components";
2327
+ import { defineCreator as defineCreator20 } from "@manifest-editor/creator-api";
2097
2328
 
2098
2329
  // src/ContentResource/YouTubeCreator/create-youtube-body.tsx
2099
- import { Input as Input8, InputContainer as InputContainer10, InputLabel as InputLabel10 } from "@manifest-editor/editors";
2100
- 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";
2101
2333
  var ytRegex = /^.*(?:(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/|shorts\/)|(?:(?:watch)?\?vi?=|&vi?=))([^#&?]*).*/;
2102
2334
  function getYouTubeId(url) {
2103
2335
  const id = (url || "").match(ytRegex);
@@ -2175,27 +2407,27 @@ function YouTubeForm(props) {
2175
2407
  props.runCreate({ youtubeUrl: formData.youtubeUrl });
2176
2408
  }
2177
2409
  };
2178
- return /* @__PURE__ */ jsx35(PaddedSidebarContainer, { children: /* @__PURE__ */ jsxs17("form", { onSubmit, children: [
2179
- /* @__PURE__ */ jsxs17(InputContainer10, { $wide: true, children: [
2180
- /* @__PURE__ */ jsx35(InputLabel10, { htmlFor: "id", children: "Link to YouTube" }),
2181
- /* @__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: "" })
2182
2414
  ] }),
2183
- /* @__PURE__ */ jsx35(Button, { type: "submit", children: "Create" })
2415
+ /* @__PURE__ */ jsx40(ActionButton12, { primary: true, large: true, type: "submit", children: "Create" })
2184
2416
  ] }) });
2185
2417
  }
2186
2418
 
2187
2419
  // src/ContentResource/YouTubeCreator/index.tsx
2188
- import { jsx as jsx36 } from "react/jsx-runtime";
2189
- var youTubeBodyCreator = {
2420
+ import { jsx as jsx41 } from "react/jsx-runtime";
2421
+ var youTubeBodyCreator = defineCreator20({
2190
2422
  id: "@manifest-editor/youtube",
2191
2423
  create: createYoutubeBody,
2192
2424
  label: "YouTube",
2193
2425
  summary: "Embed YouTube",
2194
- icon: /* @__PURE__ */ jsx36(YouTubeIcon, {}),
2426
+ icon: /* @__PURE__ */ jsx41(YouTubeIcon, {}),
2195
2427
  resourceType: "ContentResource",
2196
2428
  additionalTypes: ["Canvas", "Annotation"],
2197
2429
  resourceFields: ["id", "type", "service"],
2198
- render: (ctx) => /* @__PURE__ */ jsx36(YouTubeForm, { ...ctx }),
2430
+ render: (ctx) => /* @__PURE__ */ jsx41(YouTubeForm, { ...ctx }),
2199
2431
  supports: {
2200
2432
  parentTypes: ["Annotation", "Manifest", "AnnotationPage"],
2201
2433
  parentFieldMap: {
@@ -2207,16 +2439,14 @@ var youTubeBodyCreator = {
2207
2439
  staticFields: {
2208
2440
  type: "Video"
2209
2441
  }
2210
- };
2442
+ });
2211
2443
 
2212
2444
  // src/Manifest/ManifestBrowserCreator/index.tsx
2213
2445
  import { IIIFBrowserIcon as IIIFBrowserIcon2 } from "@manifest-editor/components";
2446
+ import { defineCreator as defineCreator21 } from "@manifest-editor/creator-api";
2214
2447
 
2215
2448
  // src/Manifest/ManifestBrowserCreator/manifest-browser-creator.tsx
2216
- import {
2217
- normaliseContentState as normaliseContentState2,
2218
- parseContentState as parseContentState2
2219
- } from "@iiif/helpers";
2449
+ import { createThumbnailHelper, normaliseContentState as normaliseContentState2, parseContentState as parseContentState2 } from "@iiif/helpers";
2220
2450
  import { lazy as lazy2 } from "react";
2221
2451
  async function createFromManifestBrowserOutput(data, ctx) {
2222
2452
  const targetType = ctx.options.targetType;
@@ -2228,23 +2458,34 @@ async function createFromManifestBrowserOutput(data, ctx) {
2228
2458
  );
2229
2459
  const target = contentState.target[0];
2230
2460
  const previewVault = ctx.getPreviewVault();
2461
+ const thumbnails = createThumbnailHelper(previewVault);
2231
2462
  if (!target) {
2232
2463
  throw new Error("No target found in content state");
2233
2464
  }
2234
2465
  if (targetType === "Manifest") {
2235
2466
  const manifestId = target.source.id;
2236
2467
  invariant(manifestId, "Could not find Manifest ID");
2237
- 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");
2238
2471
  return ctx.embed({
2239
2472
  id: target.source.id,
2240
2473
  type: "Manifest",
2241
- 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
2242
2482
  });
2243
2483
  }
2244
2484
  if (targetType === "Collection") {
2245
2485
  const collectionId = target.source.id;
2246
2486
  invariant(collectionId, "Could not find Manifest ID");
2247
- const collection = await previewVault.get(collectionId);
2487
+ const collection = await previewVault.loadManifest(collectionId);
2488
+ invariant(collection, "Collection not found");
2248
2489
  return ctx.embed({
2249
2490
  id: target.source.id,
2250
2491
  type: "Collection",
@@ -2253,20 +2494,18 @@ async function createFromManifestBrowserOutput(data, ctx) {
2253
2494
  }
2254
2495
  throw new Error("Not yet supported.");
2255
2496
  }
2256
- var ManifestBrowserCreatorForm2 = lazy2(
2257
- () => import("./manifest-browser-form.lazy-MYI26AX4.js")
2258
- );
2497
+ var ManifestBrowserCreatorForm2 = lazy2(() => import("./manifest-browser-form.lazy-HJJKFMR6.js"));
2259
2498
 
2260
2499
  // src/Manifest/ManifestBrowserCreator/index.tsx
2261
- import { jsx as jsx37 } from "react/jsx-runtime";
2262
- var manifestBrowserCreator = {
2500
+ import { jsx as jsx42 } from "react/jsx-runtime";
2501
+ var manifestBrowserCreator = defineCreator21({
2263
2502
  id: "@manifest-editor/manifest-browser-creator",
2264
2503
  create: createFromManifestBrowserOutput,
2265
2504
  label: "IIIF Browser",
2266
2505
  summary: "Browse IIIF Resources",
2267
- icon: /* @__PURE__ */ jsx37(IIIFBrowserIcon2, {}),
2506
+ icon: /* @__PURE__ */ jsx42(IIIFBrowserIcon2, {}),
2268
2507
  render(ctx) {
2269
- return /* @__PURE__ */ jsx37(ManifestBrowserCreatorForm, { ...ctx });
2508
+ return /* @__PURE__ */ jsx42(ManifestBrowserCreatorForm, { ...ctx });
2270
2509
  },
2271
2510
  resourceType: "Manifest",
2272
2511
  resourceFields: ["id", "label"],
@@ -2279,7 +2518,7 @@ var manifestBrowserCreator = {
2279
2518
  },
2280
2519
  sideEffects: [],
2281
2520
  staticFields: {}
2282
- };
2521
+ });
2283
2522
 
2284
2523
  // src/index.ts
2285
2524
  var allCreators = [
@@ -2300,7 +2539,10 @@ var allCreators = [
2300
2539
  emptyAnnotationPage,
2301
2540
  noBodyAnnotation,
2302
2541
  internalCanvas,
2303
- captionedImageAnnotation
2542
+ captionedImageAnnotation,
2543
+ imageUrlListCreator,
2544
+ imageUrlListAnnotation,
2545
+ thumbnailCreator
2304
2546
  ];
2305
2547
  export {
2306
2548
  CreateAudioAnnotationForm,
@@ -2311,10 +2553,13 @@ export {
2311
2553
  CreateImageServiceAnnotationForm,
2312
2554
  CreateImageUrlAnnotationForm,
2313
2555
  CreateImageUrlForm,
2556
+ CreateImageUrlListForm,
2314
2557
  CreatePlaintextForm,
2558
+ CreateThumbnailForm,
2315
2559
  CreateVideoAnnotationForm,
2316
2560
  CreateWebPageForm,
2317
2561
  IIIFBrowserCreatorForm,
2562
+ ManifestBrowserCreatorForm2 as ManifestBrowserCreatorForm,
2318
2563
  YouTubeForm,
2319
2564
  allCreators,
2320
2565
  audioAnnotation,
@@ -2322,14 +2567,18 @@ export {
2322
2567
  createAudioAnnotation,
2323
2568
  createCaptionedImageAnnotation,
2324
2569
  createFromIIIFBrowserOutput,
2570
+ createFromManifestBrowserOutput,
2325
2571
  createHtmlAnnotation,
2326
2572
  createHtmlBody,
2327
2573
  createImageServer,
2328
2574
  createImageServiceAnnotation,
2329
2575
  createImageUrl,
2330
2576
  createImageUrlAnnotation,
2577
+ createImageUrlList,
2578
+ createImageUrlListAnnotation,
2331
2579
  createNoBodyAnnotation,
2332
2580
  createPlaintext,
2581
+ createThumbnail,
2333
2582
  createVideoAnnotation,
2334
2583
  createWebPage,
2335
2584
  createYoutubeBody,
@@ -2343,6 +2592,8 @@ export {
2343
2592
  imageServiceCreator,
2344
2593
  imageUrlAnnotation,
2345
2594
  imageUrlCreator,
2595
+ imageUrlListAnnotation,
2596
+ imageUrlListCreator,
2346
2597
  internalCanvas,
2347
2598
  manifestBrowserCreator,
2348
2599
  noBodyAnnotation,