@manifest-editor/creator-api 1.3.1 → 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -27,6 +27,8 @@ var src_exports = {};
27
27
  __export(src_exports, {
28
28
  Creator: () => Creator,
29
29
  CreatorResource: () => CreatorResource,
30
+ creatorHelper: () => creatorHelper,
31
+ defineCreator: () => defineCreator,
30
32
  getEmptyType: () => getEmptyType,
31
33
  matchBasedOnResource: () => matchBasedOnResource,
32
34
  randomId: () => randomId,
@@ -36,11 +38,13 @@ module.exports = __toCommonJS(src_exports);
36
38
 
37
39
  // src/Creator.ts
38
40
  var import_vault = require("@iiif/helpers/vault");
41
+ var import_actions2 = require("@iiif/helpers/vault/actions");
39
42
 
40
43
  // src/CreatorRuntime.ts
41
44
  var import_actions = require("@iiif/helpers/vault/actions");
42
45
 
43
46
  // src/CreatorResource.ts
47
+ var import_parser3 = require("@iiif/parser");
44
48
  var import_editor_api = require("@manifest-editor/editor-api");
45
49
 
46
50
  // src/ReferencedResource.ts
@@ -153,10 +157,7 @@ function matchBasedOnResource(resource, list, options) {
153
157
  continue;
154
158
  }
155
159
  if (def.supports.custom) {
156
- const isValid = def.supports.custom(
157
- { property, resource: parent, atIndex: resource.index },
158
- options.vault
159
- );
160
+ const isValid = def.supports.custom({ property, resource: parent, atIndex: resource.index }, options.vault);
160
161
  if (!isValid) {
161
162
  continue;
162
163
  }
@@ -174,11 +175,22 @@ function matchBasedOnResource(resource, list, options) {
174
175
  }
175
176
  return supported;
176
177
  }
178
+ function creatorHelper(ctx, parent, property, definition) {
179
+ return (payload, options = {}) => {
180
+ if (typeof parent !== "string") {
181
+ options.parent = {
182
+ property,
183
+ resource: parent,
184
+ atIndex: options?.parent?.atIndex
185
+ };
186
+ }
187
+ return ctx.create(definition, payload, options);
188
+ };
189
+ }
177
190
 
178
191
  // src/CreatorResource.ts
179
- var import_parser3 = require("@iiif/parser");
180
192
  var CreatorResource = class _CreatorResource {
181
- constructor(data, vault) {
193
+ constructor(inputData, vault) {
182
194
  __publicField(this, "resource");
183
195
  __publicField(this, "warnings", []);
184
196
  __publicField(this, "errors", []);
@@ -188,6 +200,7 @@ var CreatorResource = class _CreatorResource {
188
200
  __publicField(this, "vault");
189
201
  __publicField(this, "specificResource");
190
202
  this.vault = vault;
203
+ let data = { ...inputData };
191
204
  if (data.type === "SpecificResource") {
192
205
  const source = data.source;
193
206
  this.specificResource = { ...data, source: { id: source.id, type: resolveType(source.type) } };
@@ -210,7 +223,6 @@ var CreatorResource = class _CreatorResource {
210
223
  const rangeRef = new ReferencedResource(range, vault);
211
224
  newRange.push(rangeRef);
212
225
  data[key] = rangeRef;
213
- continue;
214
226
  }
215
227
  data[key] = newRange;
216
228
  continue;
@@ -487,13 +499,25 @@ var CreatorRuntime = class {
487
499
  this.payload = payload;
488
500
  this.configs = createConfigs;
489
501
  this.options = {
490
- targetType: (options || {}).targetType || definition.resourceType,
502
+ targetType: options?.targetType || definition.resourceType,
491
503
  ...options || {}
492
504
  };
493
505
  }
494
506
  async run() {
495
507
  const instance = new CreatorInstance(this.vault, this.options, this.configs, this.previewVault);
496
508
  const result = await this.definition.create(this.payload, instance);
509
+ if (Array.isArray(result)) {
510
+ const results = [];
511
+ for (const item of result) {
512
+ if (item instanceof CreatorResource) {
513
+ results.push(item);
514
+ } else {
515
+ results.push(new CreatorResource(item, this.vault));
516
+ }
517
+ }
518
+ this.resource = results;
519
+ return this.resource;
520
+ }
497
521
  if (result instanceof CreatorResource) {
498
522
  this.resource = result;
499
523
  } else {
@@ -505,26 +529,29 @@ var CreatorRuntime = class {
505
529
  if (!this.resource) {
506
530
  return [];
507
531
  }
532
+ const allResources = Array.isArray(this.resource) ? this.resource : [this.resource];
508
533
  const actions = [];
509
534
  const resources = {};
510
535
  const mapping = {};
511
- if (this.options.parent) {
512
- this.resource.setPartOf(this.options.parent.resource.id);
513
- }
514
- const embedded = this.resource.getAllEmbeddedResources();
515
- const allItems = [...embedded, this.resource];
516
- for (const item of allItems) {
517
- const resource = item.getVaultResource();
518
- if (!resource.type || !resource.id) {
519
- continue;
536
+ for (const resource of allResources) {
537
+ if (this.options.parent) {
538
+ resource.setPartOf(this.options.parent.resource.id);
520
539
  }
521
- const type = resolveType(resource.type);
522
- resources[type] = resources[type] ? resources[type] : {};
523
- resources[type][resource.id] = resource;
524
- mapping[resource.id] = type;
540
+ const embedded = resource.getAllEmbeddedResources();
541
+ const allItems = [...embedded, resource];
542
+ for (const item of allItems) {
543
+ const resource2 = item.getVaultResource();
544
+ if (!resource2.type || !resource2.id) {
545
+ continue;
546
+ }
547
+ const type = resolveType(resource2.type);
548
+ resources[type] = resources[type] ? resources[type] : {};
549
+ resources[type][resource2.id] = resource2;
550
+ mapping[resource2.id] = type;
551
+ }
552
+ actions.push((0, import_actions.importEntities)({ entities: resources }));
553
+ actions.push((0, import_actions.addMappings)({ mapping }));
525
554
  }
526
- actions.push((0, import_actions.importEntities)({ entities: resources }));
527
- actions.push((0, import_actions.addMappings)({ mapping }));
528
555
  return actions;
529
556
  }
530
557
  commit(afterActions = []) {
@@ -533,12 +560,14 @@ var CreatorRuntime = class {
533
560
  }
534
561
  const actions = this.getActions();
535
562
  this.vault.dispatch((0, import_actions.batchActions)({ actions: [...actions, ...afterActions] }));
563
+ if (Array.isArray(this.resource)) {
564
+ return this.resource.map((resource) => resource.ref());
565
+ }
536
566
  return this.resource.ref();
537
567
  }
538
568
  };
539
569
 
540
570
  // src/Creator.ts
541
- var import_actions2 = require("@iiif/helpers/vault/actions");
542
571
  var Creator = class {
543
572
  constructor(vault, configs, previewVault) {
544
573
  __publicField(this, "configs");
@@ -549,11 +578,7 @@ var Creator = class {
549
578
  this.previewVault = previewVault || new import_vault.Vault();
550
579
  }
551
580
  matchBasedOnResource(resource) {
552
- return matchBasedOnResource(
553
- resource,
554
- this.configs || [],
555
- { vault: this.vault }
556
- );
581
+ return matchBasedOnResource(resource, this.configs || [], { vault: this.vault });
557
582
  }
558
583
  async create(definition, payload, options) {
559
584
  const foundDefinition = this.configs.find((t) => t.id === definition);
@@ -587,28 +612,31 @@ var Creator = class {
587
612
  }
588
613
  }
589
614
  const runtime = new CreatorRuntime(this.vault, foundDefinition, payload, this.configs, this.previewVault, options);
590
- const resource = await runtime.run();
615
+ const run = await runtime.run();
616
+ const allResources = Array.isArray(run) ? run : [run];
591
617
  const afterActions = [];
592
- if (options?.parent) {
593
- if (options.parent.property === "start" || options.parent.property === "target") {
594
- afterActions.push(
595
- import_actions2.entityActions.modifyEntityField({
596
- id: options.parent.resource.id,
597
- type: options.parent.resource.type,
598
- value: resource.ref(),
599
- key: options.parent.property
600
- })
601
- );
602
- } else {
603
- afterActions.push(
604
- import_actions2.entityActions.addReference({
605
- id: options.parent.resource.id,
606
- type: options.parent.resource.type,
607
- reference: resource.ref(),
608
- key: options.parent.property,
609
- index: options.parent.atIndex
610
- })
611
- );
618
+ for (const resource of allResources) {
619
+ if (options?.parent) {
620
+ if (options.parent.property === "start" || options.parent.property === "target") {
621
+ afterActions.push(
622
+ import_actions2.entityActions.modifyEntityField({
623
+ id: options.parent.resource.id,
624
+ type: options.parent.resource.type,
625
+ value: resource.ref(),
626
+ key: options.parent.property
627
+ })
628
+ );
629
+ } else {
630
+ afterActions.push(
631
+ import_actions2.entityActions.addReference({
632
+ id: options.parent.resource.id,
633
+ type: options.parent.resource.type,
634
+ reference: resource.ref(),
635
+ key: options.parent.property,
636
+ index: options.parent.atIndex
637
+ })
638
+ );
639
+ }
612
640
  }
613
641
  }
614
642
  const result = runtime.commit(afterActions);
@@ -616,7 +644,10 @@ var Creator = class {
616
644
  if (foundDefinition.sideEffects) {
617
645
  for (const sideEffect of foundDefinition.sideEffects) {
618
646
  if (sideEffect.run) {
619
- await sideEffect.run(result, { vault: this.vault, options });
647
+ const allResults = Array.isArray(result) ? result : [result];
648
+ for (const item of allResults) {
649
+ await sideEffect.run(item, { vault: this.vault, options });
650
+ }
620
651
  }
621
652
  }
622
653
  }
@@ -624,3 +655,8 @@ var Creator = class {
624
655
  return result;
625
656
  }
626
657
  };
658
+
659
+ // src/creator-register.ts
660
+ function defineCreator(options) {
661
+ return options;
662
+ }
package/dist/index.d.cts CHANGED
@@ -1,6 +1,7 @@
1
- import * as _iiif_presentation_3 from '@iiif/presentation-3';
2
- import { Reference, SpecificResource } from '@iiif/presentation-3';
3
1
  import { Vault, Entities } from '@iiif/helpers/vault';
2
+ import * as _iiif_presentation_3 from '@iiif/presentation-3';
3
+ import { Reference, SpecificResource, LinkingProperties, StructuralProperties, TechnicalProperties, DescriptiveProperties, Annotation, NavPlaceExtension } from '@iiif/presentation-3';
4
+ import { resources } from '@manifest-editor/editor-api';
4
5
  import { ReactNode } from 'react';
5
6
 
6
7
  declare class ReferencedResource {
@@ -77,7 +78,7 @@ declare class CreatorResource {
77
78
  embedded: CreatorResource[];
78
79
  vault: Vault;
79
80
  specificResource?: SpecificResource;
80
- constructor(data: any, vault: Vault);
81
+ constructor(inputData: any, vault: Vault);
81
82
  get(): any;
82
83
  ref(): {
83
84
  created?: string | undefined;
@@ -124,8 +125,31 @@ declare class CreatorInstance implements CreatorFunctionContext {
124
125
  generateId(type: string, parent?: Reference | ReferencedResource): string;
125
126
  ref(idOrRef: string | Reference): ReferencedResource;
126
127
  embed(data: any): CreatorResource;
127
- create(definition: string, payload: any, options?: Partial<CreatorOptions>): Promise<CreatorResource>;
128
+ create(definition: string, payload: any, options?: Partial<CreatorOptions>): Promise<any>;
129
+ }
130
+
131
+ declare function defineCreator<const Payload = any, const ID = Readonly<string>, const ResourceType extends AllAvailableParentTypes = never, const AdditionalResourceTypes extends Array<AllAvailableParentTypes> = [], const AllResourceTypes = [ResourceType, ...AdditionalResourceTypes], const SupportsParentTypes extends Array<AllAvailableParentTypes> = AllParentTypes, const SupportsParentFields extends Array<AllProperties> = [], const CreateReturnType = any>(options: SpecificCreatorDefinition<Payload, ID, ResourceType, AdditionalResourceTypes, AllResourceTypes, SupportsParentTypes, SupportsParentFields, CreateReturnType>): SpecificCreatorDefinition<Payload, ID, ResourceType, AdditionalResourceTypes, AllResourceTypes, SupportsParentTypes, SupportsParentFields, CreateReturnType>;
132
+ declare namespace IIIFManifestEditor {
133
+ interface CreatorDefinitions {
134
+ }
128
135
  }
136
+ type ExtractCreatorGenerics<T extends CreatorDefinition> = T extends SpecificCreatorDefinition<infer Payload, infer ID, infer ResourceType, infer AdditionalResourceTypes, infer AllResourceTypes, infer SupportsParentTypes, infer SupportsParentFields, infer CreateReturnType> ? {
137
+ Payload: Payload;
138
+ ID: ID;
139
+ ResourceType: ResourceType;
140
+ AdditionalResourceTypes: AdditionalResourceTypes;
141
+ AllResourceTypes: AllResourceTypes;
142
+ SupportsParentTypes: SupportsParentTypes;
143
+ SupportsParentFields: SupportsParentFields;
144
+ CreateReturnType: CreateReturnType;
145
+ } : never;
146
+ type CreatorSupportsParentTypes<T, Type extends AllAvailableParentTypes> = T extends CreatorDefinition ? ExtractCreatorGenerics<T>["SupportsParentTypes"] extends never ? false : HelperInArray<Type, ExtractCreatorGenerics<T>["SupportsParentTypes"]> : false;
147
+ type CreatorSupportsParentFields<T, Field extends AllProperties> = T extends CreatorDefinition ? ExtractCreatorGenerics<T>["SupportsParentFields"] extends never ? false : HelperInArray<Field, ExtractCreatorGenerics<T>["SupportsParentFields"]> : false;
148
+ type CreatorSupportsParent<T, Type extends AllAvailableParentTypes, Field extends AllProperties> = T extends CreatorDefinition ? CreatorSupportsParentTypes<T, Type> extends true ? CreatorSupportsParentFields<T, Field> extends true ? true : false : false : false;
149
+ type HelperInArray<ToFind, Array extends readonly any[]> = Array extends readonly [infer Head, ...infer Tail] ? Head extends ToFind ? true : HelperInArray<ToFind, Tail> : false;
150
+ type CreatorDefinitionFilterByParent<Type extends AllAvailableParentTypes, Field extends AllProperties = AllProperties, CD extends IIIFManifestEditor.CreatorDefinitions = IIIFManifestEditor.CreatorDefinitions> = {
151
+ [K in keyof CD]: CreatorSupportsParent<CD[K], Type, Field> extends true ? CD[K] : never;
152
+ }[keyof CD];
129
153
 
130
154
  interface CreatorContext<T = any> {
131
155
  vault: Vault;
@@ -133,12 +157,14 @@ interface CreatorContext<T = any> {
133
157
  validate: (payload: T) => Promise<boolean> | boolean;
134
158
  runCreate: (payload: T) => void;
135
159
  }
160
+ type ResolvedCreatorReturn<T extends CreatorDefinition> = Awaited<ExtractCreatorGenerics<T>["CreateReturnType"]> extends any[] ? CreatorResource[] : CreatorResource;
136
161
  interface CreatorFunctionContext {
162
+ vault: Vault;
137
163
  options: CreatorOptions;
138
164
  ref(idOrRef: string | Reference): ReferencedResource;
139
165
  embed(data: any): CreatorResource;
140
- create(definition: string, payload: any, options?: Partial<CreatorOptions>): Promise<CreatorResource>;
141
- create<Definition extends CreatorDefinition = any>(definition: Definition["id"], payload: GetCreatorPayload<Definition>, options?: Partial<CreatorOptions>): Promise<CreatorResource>;
166
+ create(definition: string, payload: any, options?: Partial<CreatorOptions>): Promise<CreatorResource | CreatorResource[]>;
167
+ create<Definition extends CreatorDefinition = any>(definition: Definition["id"], payload: GetCreatorPayload<Definition>, options?: Partial<CreatorOptions>): Promise<ResolvedCreatorReturn<Definition>>;
142
168
  generateId(type: string, parent?: Reference | ReferencedResource): string;
143
169
  getParent(): Reference | undefined;
144
170
  getTarget(): SpecificResource | Reference | undefined;
@@ -157,20 +183,34 @@ interface CreatorOptions {
157
183
  parent?: CreatorParent;
158
184
  initialData?: any;
159
185
  }
160
- interface CreatorDefinition<Payload = any> {
161
- id: string;
186
+ type AllAvailableParentTypes = keyof typeof resources.supported;
187
+ type GetSupportedResourceFields<Resource extends AllAvailableParentTypes> = {} & (typeof resources.supported)[Resource]["allowed"][number];
188
+ type AllProperties = ({} & keyof LinkingProperties) | ({} & keyof StructuralProperties<any>) | ({} & keyof TechnicalProperties) | ({} & keyof DescriptiveProperties) | ({} & keyof Annotation) | ({} & keyof NavPlaceExtension);
189
+ type AllParentTypes = [
190
+ "Collection",
191
+ "Manifest",
192
+ "Canvas",
193
+ "Annotation",
194
+ "AnnotationPage",
195
+ "Range",
196
+ "AnnotationCollection",
197
+ "ContentResource",
198
+ "Agent"
199
+ ];
200
+ interface SpecificCreatorDefinition<Payload = any, ID = Readonly<string>, ResourceType extends AllAvailableParentTypes = never, AdditionalResourceTypes extends Array<AllAvailableParentTypes> = [], AllResourceTypes = [ResourceType, ...AdditionalResourceTypes], SupportsParentTypes extends Array<AllAvailableParentTypes> = AllParentTypes, SupportsParentFields extends Array<AllProperties> = [], CreateReturnType = any | Promise<any> | any[] | Promise<any[]>> {
201
+ readonly id: ID;
162
202
  label: string;
163
203
  summary?: string;
164
204
  icon?: any;
165
205
  dependencies?: string[];
166
206
  tags?: string[];
167
- create: (payload: Payload, ctx: CreatorInstance) => any | Promise<any>;
207
+ create: (payload: Payload, ctx: CreatorInstance) => CreateReturnType;
168
208
  validate?: (payload: Payload, vault: Vault) => void | Promise<void>;
169
209
  render?: (ctx: CreatorContext<Payload>) => ReactNode;
170
210
  renderCanvas?: (ctx: CreatorContext<Payload>) => ReactNode | null;
171
211
  renderModal?: (ctx: CreatorContext<Payload>) => ReactNode;
172
- resourceType: string;
173
- additionalTypes?: string[];
212
+ resourceType: ResourceType;
213
+ additionalTypes?: AdditionalResourceTypes;
174
214
  resourceFields: string[];
175
215
  embeddedResources?: string[];
176
216
  staticFields?: Record<string, any>;
@@ -178,14 +218,15 @@ interface CreatorDefinition<Payload = any> {
178
218
  hiddenModal?: boolean;
179
219
  supports: {
180
220
  initialData?: boolean;
181
- parentTypes?: string[];
182
- parentFields?: string[];
221
+ parentTypes?: SupportsParentTypes;
222
+ parentFields?: SupportsParentFields;
183
223
  parentFieldMap?: Record<string, string[]>;
184
224
  custom?: (parent: CreatorParent, vault: Vault) => boolean;
185
225
  disallowPainting?: boolean;
186
226
  };
187
227
  sideEffects?: Array<CreatorSideEffect>;
188
228
  }
229
+ type CreatorDefinition<Payload = any> = SpecificCreatorDefinition<Payload, any, any, any, any, any, any>;
189
230
  interface CreatorSideEffect {
190
231
  run?: (result: any, ctx: {
191
232
  options: CreatorOptions;
@@ -214,8 +255,8 @@ declare class Creator {
214
255
  vault: Vault;
215
256
  previewVault: Vault;
216
257
  constructor(vault: Vault, configs: CreatorDefinition[], previewVault?: Vault);
217
- matchBasedOnResource(resource: CreatableResource): CreatorDefinition<any>[];
218
- create(definition: string, payload: any, options?: Partial<CreatorOptions>): Promise<Reference>;
258
+ matchBasedOnResource(resource: CreatableResource): CreatorDefinition[];
259
+ create(definition: string, payload: any, options?: Partial<CreatorOptions>): Promise<Reference | Reference[]>;
219
260
  }
220
261
 
221
262
  declare function resolveType(type: string): keyof Entities;
@@ -224,5 +265,9 @@ declare function randomId(): string;
224
265
  declare function matchBasedOnResource(resource: CreatableResource, list: CreatorDefinition[], options: {
225
266
  vault: Vault;
226
267
  }): CreatorDefinition[];
268
+ declare function creatorHelper<const ResourceType extends AllAvailableParentTypes, const Parent extends {
269
+ id: string;
270
+ type: ResourceType;
271
+ }, const ResourceField extends GetSupportedResourceFields<ResourceType>, const CID extends CreatorDefinitionFilterByParent<ResourceType, ResourceField>["id"], Payload = GetCreatorPayload<IIIFManifestEditor.CreatorDefinitions[CID]>, Return = ResolvedCreatorReturn<IIIFManifestEditor.CreatorDefinitions[CID]>>(ctx: CreatorFunctionContext, parent: Parent | ResourceType, property: ResourceField, definition: CID): (payload: Payload, options?: Partial<CreatorOptions>) => Promise<Return>;
227
272
 
228
- export { type CreatableResource, Creator, type CreatorContext, type CreatorDefinition, type CreatorFunctionContext, type CreatorOptions, CreatorResource, type CreatorSideEffect, type GetCreatorPayload, getEmptyType, matchBasedOnResource, randomId, resolveType };
273
+ export { type AllAvailableParentTypes, type AllParentTypes, type AllProperties, type CreatableResource, Creator, type CreatorContext, type CreatorDefinition, type CreatorDefinitionFilterByParent, type CreatorFunctionContext, type CreatorOptions, CreatorResource, type CreatorSideEffect, type ExtractCreatorGenerics, type GetCreatorPayload, type GetSupportedResourceFields, IIIFManifestEditor, type ResolvedCreatorReturn, type SpecificCreatorDefinition, creatorHelper, defineCreator, getEmptyType, matchBasedOnResource, randomId, resolveType };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
- import * as _iiif_presentation_3 from '@iiif/presentation-3';
2
- import { Reference, SpecificResource } from '@iiif/presentation-3';
3
1
  import { Vault, Entities } from '@iiif/helpers/vault';
2
+ import * as _iiif_presentation_3 from '@iiif/presentation-3';
3
+ import { Reference, SpecificResource, LinkingProperties, StructuralProperties, TechnicalProperties, DescriptiveProperties, Annotation, NavPlaceExtension } from '@iiif/presentation-3';
4
+ import { resources } from '@manifest-editor/editor-api';
4
5
  import { ReactNode } from 'react';
5
6
 
6
7
  declare class ReferencedResource {
@@ -77,7 +78,7 @@ declare class CreatorResource {
77
78
  embedded: CreatorResource[];
78
79
  vault: Vault;
79
80
  specificResource?: SpecificResource;
80
- constructor(data: any, vault: Vault);
81
+ constructor(inputData: any, vault: Vault);
81
82
  get(): any;
82
83
  ref(): {
83
84
  created?: string | undefined;
@@ -124,8 +125,31 @@ declare class CreatorInstance implements CreatorFunctionContext {
124
125
  generateId(type: string, parent?: Reference | ReferencedResource): string;
125
126
  ref(idOrRef: string | Reference): ReferencedResource;
126
127
  embed(data: any): CreatorResource;
127
- create(definition: string, payload: any, options?: Partial<CreatorOptions>): Promise<CreatorResource>;
128
+ create(definition: string, payload: any, options?: Partial<CreatorOptions>): Promise<any>;
129
+ }
130
+
131
+ declare function defineCreator<const Payload = any, const ID = Readonly<string>, const ResourceType extends AllAvailableParentTypes = never, const AdditionalResourceTypes extends Array<AllAvailableParentTypes> = [], const AllResourceTypes = [ResourceType, ...AdditionalResourceTypes], const SupportsParentTypes extends Array<AllAvailableParentTypes> = AllParentTypes, const SupportsParentFields extends Array<AllProperties> = [], const CreateReturnType = any>(options: SpecificCreatorDefinition<Payload, ID, ResourceType, AdditionalResourceTypes, AllResourceTypes, SupportsParentTypes, SupportsParentFields, CreateReturnType>): SpecificCreatorDefinition<Payload, ID, ResourceType, AdditionalResourceTypes, AllResourceTypes, SupportsParentTypes, SupportsParentFields, CreateReturnType>;
132
+ declare namespace IIIFManifestEditor {
133
+ interface CreatorDefinitions {
134
+ }
128
135
  }
136
+ type ExtractCreatorGenerics<T extends CreatorDefinition> = T extends SpecificCreatorDefinition<infer Payload, infer ID, infer ResourceType, infer AdditionalResourceTypes, infer AllResourceTypes, infer SupportsParentTypes, infer SupportsParentFields, infer CreateReturnType> ? {
137
+ Payload: Payload;
138
+ ID: ID;
139
+ ResourceType: ResourceType;
140
+ AdditionalResourceTypes: AdditionalResourceTypes;
141
+ AllResourceTypes: AllResourceTypes;
142
+ SupportsParentTypes: SupportsParentTypes;
143
+ SupportsParentFields: SupportsParentFields;
144
+ CreateReturnType: CreateReturnType;
145
+ } : never;
146
+ type CreatorSupportsParentTypes<T, Type extends AllAvailableParentTypes> = T extends CreatorDefinition ? ExtractCreatorGenerics<T>["SupportsParentTypes"] extends never ? false : HelperInArray<Type, ExtractCreatorGenerics<T>["SupportsParentTypes"]> : false;
147
+ type CreatorSupportsParentFields<T, Field extends AllProperties> = T extends CreatorDefinition ? ExtractCreatorGenerics<T>["SupportsParentFields"] extends never ? false : HelperInArray<Field, ExtractCreatorGenerics<T>["SupportsParentFields"]> : false;
148
+ type CreatorSupportsParent<T, Type extends AllAvailableParentTypes, Field extends AllProperties> = T extends CreatorDefinition ? CreatorSupportsParentTypes<T, Type> extends true ? CreatorSupportsParentFields<T, Field> extends true ? true : false : false : false;
149
+ type HelperInArray<ToFind, Array extends readonly any[]> = Array extends readonly [infer Head, ...infer Tail] ? Head extends ToFind ? true : HelperInArray<ToFind, Tail> : false;
150
+ type CreatorDefinitionFilterByParent<Type extends AllAvailableParentTypes, Field extends AllProperties = AllProperties, CD extends IIIFManifestEditor.CreatorDefinitions = IIIFManifestEditor.CreatorDefinitions> = {
151
+ [K in keyof CD]: CreatorSupportsParent<CD[K], Type, Field> extends true ? CD[K] : never;
152
+ }[keyof CD];
129
153
 
130
154
  interface CreatorContext<T = any> {
131
155
  vault: Vault;
@@ -133,12 +157,14 @@ interface CreatorContext<T = any> {
133
157
  validate: (payload: T) => Promise<boolean> | boolean;
134
158
  runCreate: (payload: T) => void;
135
159
  }
160
+ type ResolvedCreatorReturn<T extends CreatorDefinition> = Awaited<ExtractCreatorGenerics<T>["CreateReturnType"]> extends any[] ? CreatorResource[] : CreatorResource;
136
161
  interface CreatorFunctionContext {
162
+ vault: Vault;
137
163
  options: CreatorOptions;
138
164
  ref(idOrRef: string | Reference): ReferencedResource;
139
165
  embed(data: any): CreatorResource;
140
- create(definition: string, payload: any, options?: Partial<CreatorOptions>): Promise<CreatorResource>;
141
- create<Definition extends CreatorDefinition = any>(definition: Definition["id"], payload: GetCreatorPayload<Definition>, options?: Partial<CreatorOptions>): Promise<CreatorResource>;
166
+ create(definition: string, payload: any, options?: Partial<CreatorOptions>): Promise<CreatorResource | CreatorResource[]>;
167
+ create<Definition extends CreatorDefinition = any>(definition: Definition["id"], payload: GetCreatorPayload<Definition>, options?: Partial<CreatorOptions>): Promise<ResolvedCreatorReturn<Definition>>;
142
168
  generateId(type: string, parent?: Reference | ReferencedResource): string;
143
169
  getParent(): Reference | undefined;
144
170
  getTarget(): SpecificResource | Reference | undefined;
@@ -157,20 +183,34 @@ interface CreatorOptions {
157
183
  parent?: CreatorParent;
158
184
  initialData?: any;
159
185
  }
160
- interface CreatorDefinition<Payload = any> {
161
- id: string;
186
+ type AllAvailableParentTypes = keyof typeof resources.supported;
187
+ type GetSupportedResourceFields<Resource extends AllAvailableParentTypes> = {} & (typeof resources.supported)[Resource]["allowed"][number];
188
+ type AllProperties = ({} & keyof LinkingProperties) | ({} & keyof StructuralProperties<any>) | ({} & keyof TechnicalProperties) | ({} & keyof DescriptiveProperties) | ({} & keyof Annotation) | ({} & keyof NavPlaceExtension);
189
+ type AllParentTypes = [
190
+ "Collection",
191
+ "Manifest",
192
+ "Canvas",
193
+ "Annotation",
194
+ "AnnotationPage",
195
+ "Range",
196
+ "AnnotationCollection",
197
+ "ContentResource",
198
+ "Agent"
199
+ ];
200
+ interface SpecificCreatorDefinition<Payload = any, ID = Readonly<string>, ResourceType extends AllAvailableParentTypes = never, AdditionalResourceTypes extends Array<AllAvailableParentTypes> = [], AllResourceTypes = [ResourceType, ...AdditionalResourceTypes], SupportsParentTypes extends Array<AllAvailableParentTypes> = AllParentTypes, SupportsParentFields extends Array<AllProperties> = [], CreateReturnType = any | Promise<any> | any[] | Promise<any[]>> {
201
+ readonly id: ID;
162
202
  label: string;
163
203
  summary?: string;
164
204
  icon?: any;
165
205
  dependencies?: string[];
166
206
  tags?: string[];
167
- create: (payload: Payload, ctx: CreatorInstance) => any | Promise<any>;
207
+ create: (payload: Payload, ctx: CreatorInstance) => CreateReturnType;
168
208
  validate?: (payload: Payload, vault: Vault) => void | Promise<void>;
169
209
  render?: (ctx: CreatorContext<Payload>) => ReactNode;
170
210
  renderCanvas?: (ctx: CreatorContext<Payload>) => ReactNode | null;
171
211
  renderModal?: (ctx: CreatorContext<Payload>) => ReactNode;
172
- resourceType: string;
173
- additionalTypes?: string[];
212
+ resourceType: ResourceType;
213
+ additionalTypes?: AdditionalResourceTypes;
174
214
  resourceFields: string[];
175
215
  embeddedResources?: string[];
176
216
  staticFields?: Record<string, any>;
@@ -178,14 +218,15 @@ interface CreatorDefinition<Payload = any> {
178
218
  hiddenModal?: boolean;
179
219
  supports: {
180
220
  initialData?: boolean;
181
- parentTypes?: string[];
182
- parentFields?: string[];
221
+ parentTypes?: SupportsParentTypes;
222
+ parentFields?: SupportsParentFields;
183
223
  parentFieldMap?: Record<string, string[]>;
184
224
  custom?: (parent: CreatorParent, vault: Vault) => boolean;
185
225
  disallowPainting?: boolean;
186
226
  };
187
227
  sideEffects?: Array<CreatorSideEffect>;
188
228
  }
229
+ type CreatorDefinition<Payload = any> = SpecificCreatorDefinition<Payload, any, any, any, any, any, any>;
189
230
  interface CreatorSideEffect {
190
231
  run?: (result: any, ctx: {
191
232
  options: CreatorOptions;
@@ -214,8 +255,8 @@ declare class Creator {
214
255
  vault: Vault;
215
256
  previewVault: Vault;
216
257
  constructor(vault: Vault, configs: CreatorDefinition[], previewVault?: Vault);
217
- matchBasedOnResource(resource: CreatableResource): CreatorDefinition<any>[];
218
- create(definition: string, payload: any, options?: Partial<CreatorOptions>): Promise<Reference>;
258
+ matchBasedOnResource(resource: CreatableResource): CreatorDefinition[];
259
+ create(definition: string, payload: any, options?: Partial<CreatorOptions>): Promise<Reference | Reference[]>;
219
260
  }
220
261
 
221
262
  declare function resolveType(type: string): keyof Entities;
@@ -224,5 +265,9 @@ declare function randomId(): string;
224
265
  declare function matchBasedOnResource(resource: CreatableResource, list: CreatorDefinition[], options: {
225
266
  vault: Vault;
226
267
  }): CreatorDefinition[];
268
+ declare function creatorHelper<const ResourceType extends AllAvailableParentTypes, const Parent extends {
269
+ id: string;
270
+ type: ResourceType;
271
+ }, const ResourceField extends GetSupportedResourceFields<ResourceType>, const CID extends CreatorDefinitionFilterByParent<ResourceType, ResourceField>["id"], Payload = GetCreatorPayload<IIIFManifestEditor.CreatorDefinitions[CID]>, Return = ResolvedCreatorReturn<IIIFManifestEditor.CreatorDefinitions[CID]>>(ctx: CreatorFunctionContext, parent: Parent | ResourceType, property: ResourceField, definition: CID): (payload: Payload, options?: Partial<CreatorOptions>) => Promise<Return>;
227
272
 
228
- export { type CreatableResource, Creator, type CreatorContext, type CreatorDefinition, type CreatorFunctionContext, type CreatorOptions, CreatorResource, type CreatorSideEffect, type GetCreatorPayload, getEmptyType, matchBasedOnResource, randomId, resolveType };
273
+ export { type AllAvailableParentTypes, type AllParentTypes, type AllProperties, type CreatableResource, Creator, type CreatorContext, type CreatorDefinition, type CreatorDefinitionFilterByParent, type CreatorFunctionContext, type CreatorOptions, CreatorResource, type CreatorSideEffect, type ExtractCreatorGenerics, type GetCreatorPayload, type GetSupportedResourceFields, IIIFManifestEditor, type ResolvedCreatorReturn, type SpecificCreatorDefinition, creatorHelper, defineCreator, getEmptyType, matchBasedOnResource, randomId, resolveType };
package/dist/index.js CHANGED
@@ -7,11 +7,13 @@ var __publicField = (obj, key, value) => {
7
7
 
8
8
  // src/Creator.ts
9
9
  import { Vault } from "@iiif/helpers/vault";
10
+ import { entityActions } from "@iiif/helpers/vault/actions";
10
11
 
11
12
  // src/CreatorRuntime.ts
12
- import { importEntities, addMappings, batchActions } from "@iiif/helpers/vault/actions";
13
+ import { addMappings, batchActions, importEntities } from "@iiif/helpers/vault/actions";
13
14
 
14
15
  // src/CreatorResource.ts
16
+ import { HAS_PART, PART_OF } from "@iiif/parser";
15
17
  import { references } from "@manifest-editor/editor-api";
16
18
 
17
19
  // src/ReferencedResource.ts
@@ -134,10 +136,7 @@ function matchBasedOnResource(resource, list, options) {
134
136
  continue;
135
137
  }
136
138
  if (def.supports.custom) {
137
- const isValid = def.supports.custom(
138
- { property, resource: parent, atIndex: resource.index },
139
- options.vault
140
- );
139
+ const isValid = def.supports.custom({ property, resource: parent, atIndex: resource.index }, options.vault);
141
140
  if (!isValid) {
142
141
  continue;
143
142
  }
@@ -155,11 +154,22 @@ function matchBasedOnResource(resource, list, options) {
155
154
  }
156
155
  return supported;
157
156
  }
157
+ function creatorHelper(ctx, parent, property, definition) {
158
+ return (payload, options = {}) => {
159
+ if (typeof parent !== "string") {
160
+ options.parent = {
161
+ property,
162
+ resource: parent,
163
+ atIndex: options?.parent?.atIndex
164
+ };
165
+ }
166
+ return ctx.create(definition, payload, options);
167
+ };
168
+ }
158
169
 
159
170
  // src/CreatorResource.ts
160
- import { HAS_PART, PART_OF } from "@iiif/parser";
161
171
  var CreatorResource = class _CreatorResource {
162
- constructor(data, vault) {
172
+ constructor(inputData, vault) {
163
173
  __publicField(this, "resource");
164
174
  __publicField(this, "warnings", []);
165
175
  __publicField(this, "errors", []);
@@ -169,6 +179,7 @@ var CreatorResource = class _CreatorResource {
169
179
  __publicField(this, "vault");
170
180
  __publicField(this, "specificResource");
171
181
  this.vault = vault;
182
+ let data = { ...inputData };
172
183
  if (data.type === "SpecificResource") {
173
184
  const source = data.source;
174
185
  this.specificResource = { ...data, source: { id: source.id, type: resolveType(source.type) } };
@@ -191,7 +202,6 @@ var CreatorResource = class _CreatorResource {
191
202
  const rangeRef = new ReferencedResource(range, vault);
192
203
  newRange.push(rangeRef);
193
204
  data[key] = rangeRef;
194
- continue;
195
205
  }
196
206
  data[key] = newRange;
197
207
  continue;
@@ -468,13 +478,25 @@ var CreatorRuntime = class {
468
478
  this.payload = payload;
469
479
  this.configs = createConfigs;
470
480
  this.options = {
471
- targetType: (options || {}).targetType || definition.resourceType,
481
+ targetType: options?.targetType || definition.resourceType,
472
482
  ...options || {}
473
483
  };
474
484
  }
475
485
  async run() {
476
486
  const instance = new CreatorInstance(this.vault, this.options, this.configs, this.previewVault);
477
487
  const result = await this.definition.create(this.payload, instance);
488
+ if (Array.isArray(result)) {
489
+ const results = [];
490
+ for (const item of result) {
491
+ if (item instanceof CreatorResource) {
492
+ results.push(item);
493
+ } else {
494
+ results.push(new CreatorResource(item, this.vault));
495
+ }
496
+ }
497
+ this.resource = results;
498
+ return this.resource;
499
+ }
478
500
  if (result instanceof CreatorResource) {
479
501
  this.resource = result;
480
502
  } else {
@@ -486,26 +508,29 @@ var CreatorRuntime = class {
486
508
  if (!this.resource) {
487
509
  return [];
488
510
  }
511
+ const allResources = Array.isArray(this.resource) ? this.resource : [this.resource];
489
512
  const actions = [];
490
513
  const resources = {};
491
514
  const mapping = {};
492
- if (this.options.parent) {
493
- this.resource.setPartOf(this.options.parent.resource.id);
494
- }
495
- const embedded = this.resource.getAllEmbeddedResources();
496
- const allItems = [...embedded, this.resource];
497
- for (const item of allItems) {
498
- const resource = item.getVaultResource();
499
- if (!resource.type || !resource.id) {
500
- continue;
515
+ for (const resource of allResources) {
516
+ if (this.options.parent) {
517
+ resource.setPartOf(this.options.parent.resource.id);
501
518
  }
502
- const type = resolveType(resource.type);
503
- resources[type] = resources[type] ? resources[type] : {};
504
- resources[type][resource.id] = resource;
505
- mapping[resource.id] = type;
519
+ const embedded = resource.getAllEmbeddedResources();
520
+ const allItems = [...embedded, resource];
521
+ for (const item of allItems) {
522
+ const resource2 = item.getVaultResource();
523
+ if (!resource2.type || !resource2.id) {
524
+ continue;
525
+ }
526
+ const type = resolveType(resource2.type);
527
+ resources[type] = resources[type] ? resources[type] : {};
528
+ resources[type][resource2.id] = resource2;
529
+ mapping[resource2.id] = type;
530
+ }
531
+ actions.push(importEntities({ entities: resources }));
532
+ actions.push(addMappings({ mapping }));
506
533
  }
507
- actions.push(importEntities({ entities: resources }));
508
- actions.push(addMappings({ mapping }));
509
534
  return actions;
510
535
  }
511
536
  commit(afterActions = []) {
@@ -514,12 +539,14 @@ var CreatorRuntime = class {
514
539
  }
515
540
  const actions = this.getActions();
516
541
  this.vault.dispatch(batchActions({ actions: [...actions, ...afterActions] }));
542
+ if (Array.isArray(this.resource)) {
543
+ return this.resource.map((resource) => resource.ref());
544
+ }
517
545
  return this.resource.ref();
518
546
  }
519
547
  };
520
548
 
521
549
  // src/Creator.ts
522
- import { entityActions } from "@iiif/helpers/vault/actions";
523
550
  var Creator = class {
524
551
  constructor(vault, configs, previewVault) {
525
552
  __publicField(this, "configs");
@@ -530,11 +557,7 @@ var Creator = class {
530
557
  this.previewVault = previewVault || new Vault();
531
558
  }
532
559
  matchBasedOnResource(resource) {
533
- return matchBasedOnResource(
534
- resource,
535
- this.configs || [],
536
- { vault: this.vault }
537
- );
560
+ return matchBasedOnResource(resource, this.configs || [], { vault: this.vault });
538
561
  }
539
562
  async create(definition, payload, options) {
540
563
  const foundDefinition = this.configs.find((t) => t.id === definition);
@@ -568,28 +591,31 @@ var Creator = class {
568
591
  }
569
592
  }
570
593
  const runtime = new CreatorRuntime(this.vault, foundDefinition, payload, this.configs, this.previewVault, options);
571
- const resource = await runtime.run();
594
+ const run = await runtime.run();
595
+ const allResources = Array.isArray(run) ? run : [run];
572
596
  const afterActions = [];
573
- if (options?.parent) {
574
- if (options.parent.property === "start" || options.parent.property === "target") {
575
- afterActions.push(
576
- entityActions.modifyEntityField({
577
- id: options.parent.resource.id,
578
- type: options.parent.resource.type,
579
- value: resource.ref(),
580
- key: options.parent.property
581
- })
582
- );
583
- } else {
584
- afterActions.push(
585
- entityActions.addReference({
586
- id: options.parent.resource.id,
587
- type: options.parent.resource.type,
588
- reference: resource.ref(),
589
- key: options.parent.property,
590
- index: options.parent.atIndex
591
- })
592
- );
597
+ for (const resource of allResources) {
598
+ if (options?.parent) {
599
+ if (options.parent.property === "start" || options.parent.property === "target") {
600
+ afterActions.push(
601
+ entityActions.modifyEntityField({
602
+ id: options.parent.resource.id,
603
+ type: options.parent.resource.type,
604
+ value: resource.ref(),
605
+ key: options.parent.property
606
+ })
607
+ );
608
+ } else {
609
+ afterActions.push(
610
+ entityActions.addReference({
611
+ id: options.parent.resource.id,
612
+ type: options.parent.resource.type,
613
+ reference: resource.ref(),
614
+ key: options.parent.property,
615
+ index: options.parent.atIndex
616
+ })
617
+ );
618
+ }
593
619
  }
594
620
  }
595
621
  const result = runtime.commit(afterActions);
@@ -597,7 +623,10 @@ var Creator = class {
597
623
  if (foundDefinition.sideEffects) {
598
624
  for (const sideEffect of foundDefinition.sideEffects) {
599
625
  if (sideEffect.run) {
600
- await sideEffect.run(result, { vault: this.vault, options });
626
+ const allResults = Array.isArray(result) ? result : [result];
627
+ for (const item of allResults) {
628
+ await sideEffect.run(item, { vault: this.vault, options });
629
+ }
601
630
  }
602
631
  }
603
632
  }
@@ -605,9 +634,16 @@ var Creator = class {
605
634
  return result;
606
635
  }
607
636
  };
637
+
638
+ // src/creator-register.ts
639
+ function defineCreator(options) {
640
+ return options;
641
+ }
608
642
  export {
609
643
  Creator,
610
644
  CreatorResource,
645
+ creatorHelper,
646
+ defineCreator,
611
647
  getEmptyType,
612
648
  matchBasedOnResource,
613
649
  randomId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@manifest-editor/creator-api",
3
- "version": "1.3.1",
3
+ "version": "1.4.2",
4
4
  "type": "module",
5
5
  "bugs": "https://github.com/digirati-co-uk/iiif-manifest-editor/issues",
6
6
  "repository": {
@@ -43,10 +43,10 @@
43
43
  },
44
44
  "dependencies": {
45
45
  "@iiif/helpers": "^1.3.1",
46
- "@iiif/parser": "^2.1.7",
46
+ "@iiif/parser": "^2.1.8",
47
47
  "@iiif/presentation-3": "^2.2.3",
48
48
  "@iiif/presentation-3-normalized": "^0.9.7",
49
- "@manifest-editor/editor-api": "1.3.1",
49
+ "@manifest-editor/editor-api": "1.4.0",
50
50
  "polygon-editor": "^0.0.6",
51
51
  "react-iiif-vault": "^1.2.1"
52
52
  },
@@ -59,5 +59,5 @@
59
59
  "publishConfig": {
60
60
  "access": "public"
61
61
  },
62
- "gitHead": "920fe405869996394c204c6eae70f446aab78986"
62
+ "gitHead": "7da90acfb83545d53d34ba95b86c8d5492005e81"
63
63
  }