@manifest-editor/creator-api 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.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,9 +175,20 @@ 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
193
  constructor(data, vault) {
182
194
  __publicField(this, "resource");
@@ -210,7 +222,6 @@ var CreatorResource = class _CreatorResource {
210
222
  const rangeRef = new ReferencedResource(range, vault);
211
223
  newRange.push(rangeRef);
212
224
  data[key] = rangeRef;
213
- continue;
214
225
  }
215
226
  data[key] = newRange;
216
227
  continue;
@@ -487,13 +498,25 @@ var CreatorRuntime = class {
487
498
  this.payload = payload;
488
499
  this.configs = createConfigs;
489
500
  this.options = {
490
- targetType: (options || {}).targetType || definition.resourceType,
501
+ targetType: options?.targetType || definition.resourceType,
491
502
  ...options || {}
492
503
  };
493
504
  }
494
505
  async run() {
495
506
  const instance = new CreatorInstance(this.vault, this.options, this.configs, this.previewVault);
496
507
  const result = await this.definition.create(this.payload, instance);
508
+ if (Array.isArray(result)) {
509
+ const results = [];
510
+ for (const item of result) {
511
+ if (item instanceof CreatorResource) {
512
+ results.push(item);
513
+ } else {
514
+ results.push(new CreatorResource(item, this.vault));
515
+ }
516
+ }
517
+ this.resource = results;
518
+ return this.resource;
519
+ }
497
520
  if (result instanceof CreatorResource) {
498
521
  this.resource = result;
499
522
  } else {
@@ -505,26 +528,29 @@ var CreatorRuntime = class {
505
528
  if (!this.resource) {
506
529
  return [];
507
530
  }
531
+ const allResources = Array.isArray(this.resource) ? this.resource : [this.resource];
508
532
  const actions = [];
509
533
  const resources = {};
510
534
  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;
535
+ for (const resource of allResources) {
536
+ if (this.options.parent) {
537
+ resource.setPartOf(this.options.parent.resource.id);
520
538
  }
521
- const type = resolveType(resource.type);
522
- resources[type] = resources[type] ? resources[type] : {};
523
- resources[type][resource.id] = resource;
524
- mapping[resource.id] = type;
539
+ const embedded = resource.getAllEmbeddedResources();
540
+ const allItems = [...embedded, resource];
541
+ for (const item of allItems) {
542
+ const resource2 = item.getVaultResource();
543
+ if (!resource2.type || !resource2.id) {
544
+ continue;
545
+ }
546
+ const type = resolveType(resource2.type);
547
+ resources[type] = resources[type] ? resources[type] : {};
548
+ resources[type][resource2.id] = resource2;
549
+ mapping[resource2.id] = type;
550
+ }
551
+ actions.push((0, import_actions.importEntities)({ entities: resources }));
552
+ actions.push((0, import_actions.addMappings)({ mapping }));
525
553
  }
526
- actions.push((0, import_actions.importEntities)({ entities: resources }));
527
- actions.push((0, import_actions.addMappings)({ mapping }));
528
554
  return actions;
529
555
  }
530
556
  commit(afterActions = []) {
@@ -533,12 +559,14 @@ var CreatorRuntime = class {
533
559
  }
534
560
  const actions = this.getActions();
535
561
  this.vault.dispatch((0, import_actions.batchActions)({ actions: [...actions, ...afterActions] }));
562
+ if (Array.isArray(this.resource)) {
563
+ return this.resource.map((resource) => resource.ref());
564
+ }
536
565
  return this.resource.ref();
537
566
  }
538
567
  };
539
568
 
540
569
  // src/Creator.ts
541
- var import_actions2 = require("@iiif/helpers/vault/actions");
542
570
  var Creator = class {
543
571
  constructor(vault, configs, previewVault) {
544
572
  __publicField(this, "configs");
@@ -549,11 +577,7 @@ var Creator = class {
549
577
  this.previewVault = previewVault || new import_vault.Vault();
550
578
  }
551
579
  matchBasedOnResource(resource) {
552
- return matchBasedOnResource(
553
- resource,
554
- this.configs || [],
555
- { vault: this.vault }
556
- );
580
+ return matchBasedOnResource(resource, this.configs || [], { vault: this.vault });
557
581
  }
558
582
  async create(definition, payload, options) {
559
583
  const foundDefinition = this.configs.find((t) => t.id === definition);
@@ -587,28 +611,31 @@ var Creator = class {
587
611
  }
588
612
  }
589
613
  const runtime = new CreatorRuntime(this.vault, foundDefinition, payload, this.configs, this.previewVault, options);
590
- const resource = await runtime.run();
614
+ const run = await runtime.run();
615
+ const allResources = Array.isArray(run) ? run : [run];
591
616
  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
- );
617
+ for (const resource of allResources) {
618
+ if (options?.parent) {
619
+ if (options.parent.property === "start" || options.parent.property === "target") {
620
+ afterActions.push(
621
+ import_actions2.entityActions.modifyEntityField({
622
+ id: options.parent.resource.id,
623
+ type: options.parent.resource.type,
624
+ value: resource.ref(),
625
+ key: options.parent.property
626
+ })
627
+ );
628
+ } else {
629
+ afterActions.push(
630
+ import_actions2.entityActions.addReference({
631
+ id: options.parent.resource.id,
632
+ type: options.parent.resource.type,
633
+ reference: resource.ref(),
634
+ key: options.parent.property,
635
+ index: options.parent.atIndex
636
+ })
637
+ );
638
+ }
612
639
  }
613
640
  }
614
641
  const result = runtime.commit(afterActions);
@@ -616,7 +643,10 @@ var Creator = class {
616
643
  if (foundDefinition.sideEffects) {
617
644
  for (const sideEffect of foundDefinition.sideEffects) {
618
645
  if (sideEffect.run) {
619
- await sideEffect.run(result, { vault: this.vault, options });
646
+ const allResults = Array.isArray(result) ? result : [result];
647
+ for (const item of allResults) {
648
+ await sideEffect.run(item, { vault: this.vault, options });
649
+ }
620
650
  }
621
651
  }
622
652
  }
@@ -624,3 +654,8 @@ var Creator = class {
624
654
  return result;
625
655
  }
626
656
  };
657
+
658
+ // src/creator-register.ts
659
+ function defineCreator(options) {
660
+ return options;
661
+ }
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 {
@@ -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,13 @@ 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 {
137
162
  options: CreatorOptions;
138
163
  ref(idOrRef: string | Reference): ReferencedResource;
139
164
  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>;
165
+ create(definition: string, payload: any, options?: Partial<CreatorOptions>): Promise<CreatorResource | CreatorResource[]>;
166
+ create<Definition extends CreatorDefinition = any>(definition: Definition["id"], payload: GetCreatorPayload<Definition>, options?: Partial<CreatorOptions>): Promise<ResolvedCreatorReturn<Definition>>;
142
167
  generateId(type: string, parent?: Reference | ReferencedResource): string;
143
168
  getParent(): Reference | undefined;
144
169
  getTarget(): SpecificResource | Reference | undefined;
@@ -157,20 +182,34 @@ interface CreatorOptions {
157
182
  parent?: CreatorParent;
158
183
  initialData?: any;
159
184
  }
160
- interface CreatorDefinition<Payload = any> {
161
- id: string;
185
+ type AllAvailableParentTypes = keyof typeof resources.supported;
186
+ type GetSupportedResourceFields<Resource extends AllAvailableParentTypes> = {} & (typeof resources.supported)[Resource]["allowed"][number];
187
+ type AllProperties = ({} & keyof LinkingProperties) | ({} & keyof StructuralProperties<any>) | ({} & keyof TechnicalProperties) | ({} & keyof DescriptiveProperties) | ({} & keyof Annotation) | ({} & keyof NavPlaceExtension);
188
+ type AllParentTypes = [
189
+ "Collection",
190
+ "Manifest",
191
+ "Canvas",
192
+ "Annotation",
193
+ "AnnotationPage",
194
+ "Range",
195
+ "AnnotationCollection",
196
+ "ContentResource",
197
+ "Agent"
198
+ ];
199
+ 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[]>> {
200
+ readonly id: ID;
162
201
  label: string;
163
202
  summary?: string;
164
203
  icon?: any;
165
204
  dependencies?: string[];
166
205
  tags?: string[];
167
- create: (payload: Payload, ctx: CreatorInstance) => any | Promise<any>;
206
+ create: (payload: Payload, ctx: CreatorInstance) => CreateReturnType;
168
207
  validate?: (payload: Payload, vault: Vault) => void | Promise<void>;
169
208
  render?: (ctx: CreatorContext<Payload>) => ReactNode;
170
209
  renderCanvas?: (ctx: CreatorContext<Payload>) => ReactNode | null;
171
210
  renderModal?: (ctx: CreatorContext<Payload>) => ReactNode;
172
- resourceType: string;
173
- additionalTypes?: string[];
211
+ resourceType: ResourceType;
212
+ additionalTypes?: AdditionalResourceTypes;
174
213
  resourceFields: string[];
175
214
  embeddedResources?: string[];
176
215
  staticFields?: Record<string, any>;
@@ -178,14 +217,15 @@ interface CreatorDefinition<Payload = any> {
178
217
  hiddenModal?: boolean;
179
218
  supports: {
180
219
  initialData?: boolean;
181
- parentTypes?: string[];
182
- parentFields?: string[];
220
+ parentTypes?: SupportsParentTypes;
221
+ parentFields?: SupportsParentFields;
183
222
  parentFieldMap?: Record<string, string[]>;
184
223
  custom?: (parent: CreatorParent, vault: Vault) => boolean;
185
224
  disallowPainting?: boolean;
186
225
  };
187
226
  sideEffects?: Array<CreatorSideEffect>;
188
227
  }
228
+ type CreatorDefinition<Payload = any> = SpecificCreatorDefinition<Payload, any, any, any, any, any, any>;
189
229
  interface CreatorSideEffect {
190
230
  run?: (result: any, ctx: {
191
231
  options: CreatorOptions;
@@ -214,8 +254,8 @@ declare class Creator {
214
254
  vault: Vault;
215
255
  previewVault: Vault;
216
256
  constructor(vault: Vault, configs: CreatorDefinition[], previewVault?: Vault);
217
- matchBasedOnResource(resource: CreatableResource): CreatorDefinition<any>[];
218
- create(definition: string, payload: any, options?: Partial<CreatorOptions>): Promise<Reference>;
257
+ matchBasedOnResource(resource: CreatableResource): CreatorDefinition[];
258
+ create(definition: string, payload: any, options?: Partial<CreatorOptions>): Promise<Reference | Reference[]>;
219
259
  }
220
260
 
221
261
  declare function resolveType(type: string): keyof Entities;
@@ -224,5 +264,9 @@ declare function randomId(): string;
224
264
  declare function matchBasedOnResource(resource: CreatableResource, list: CreatorDefinition[], options: {
225
265
  vault: Vault;
226
266
  }): CreatorDefinition[];
267
+ declare function creatorHelper<const ResourceType extends AllAvailableParentTypes, const Parent extends {
268
+ id: string;
269
+ type: ResourceType;
270
+ }, 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
271
 
228
- export { type CreatableResource, Creator, type CreatorContext, type CreatorDefinition, type CreatorFunctionContext, type CreatorOptions, CreatorResource, type CreatorSideEffect, type GetCreatorPayload, getEmptyType, matchBasedOnResource, randomId, resolveType };
272
+ 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 {
@@ -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,13 @@ 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 {
137
162
  options: CreatorOptions;
138
163
  ref(idOrRef: string | Reference): ReferencedResource;
139
164
  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>;
165
+ create(definition: string, payload: any, options?: Partial<CreatorOptions>): Promise<CreatorResource | CreatorResource[]>;
166
+ create<Definition extends CreatorDefinition = any>(definition: Definition["id"], payload: GetCreatorPayload<Definition>, options?: Partial<CreatorOptions>): Promise<ResolvedCreatorReturn<Definition>>;
142
167
  generateId(type: string, parent?: Reference | ReferencedResource): string;
143
168
  getParent(): Reference | undefined;
144
169
  getTarget(): SpecificResource | Reference | undefined;
@@ -157,20 +182,34 @@ interface CreatorOptions {
157
182
  parent?: CreatorParent;
158
183
  initialData?: any;
159
184
  }
160
- interface CreatorDefinition<Payload = any> {
161
- id: string;
185
+ type AllAvailableParentTypes = keyof typeof resources.supported;
186
+ type GetSupportedResourceFields<Resource extends AllAvailableParentTypes> = {} & (typeof resources.supported)[Resource]["allowed"][number];
187
+ type AllProperties = ({} & keyof LinkingProperties) | ({} & keyof StructuralProperties<any>) | ({} & keyof TechnicalProperties) | ({} & keyof DescriptiveProperties) | ({} & keyof Annotation) | ({} & keyof NavPlaceExtension);
188
+ type AllParentTypes = [
189
+ "Collection",
190
+ "Manifest",
191
+ "Canvas",
192
+ "Annotation",
193
+ "AnnotationPage",
194
+ "Range",
195
+ "AnnotationCollection",
196
+ "ContentResource",
197
+ "Agent"
198
+ ];
199
+ 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[]>> {
200
+ readonly id: ID;
162
201
  label: string;
163
202
  summary?: string;
164
203
  icon?: any;
165
204
  dependencies?: string[];
166
205
  tags?: string[];
167
- create: (payload: Payload, ctx: CreatorInstance) => any | Promise<any>;
206
+ create: (payload: Payload, ctx: CreatorInstance) => CreateReturnType;
168
207
  validate?: (payload: Payload, vault: Vault) => void | Promise<void>;
169
208
  render?: (ctx: CreatorContext<Payload>) => ReactNode;
170
209
  renderCanvas?: (ctx: CreatorContext<Payload>) => ReactNode | null;
171
210
  renderModal?: (ctx: CreatorContext<Payload>) => ReactNode;
172
- resourceType: string;
173
- additionalTypes?: string[];
211
+ resourceType: ResourceType;
212
+ additionalTypes?: AdditionalResourceTypes;
174
213
  resourceFields: string[];
175
214
  embeddedResources?: string[];
176
215
  staticFields?: Record<string, any>;
@@ -178,14 +217,15 @@ interface CreatorDefinition<Payload = any> {
178
217
  hiddenModal?: boolean;
179
218
  supports: {
180
219
  initialData?: boolean;
181
- parentTypes?: string[];
182
- parentFields?: string[];
220
+ parentTypes?: SupportsParentTypes;
221
+ parentFields?: SupportsParentFields;
183
222
  parentFieldMap?: Record<string, string[]>;
184
223
  custom?: (parent: CreatorParent, vault: Vault) => boolean;
185
224
  disallowPainting?: boolean;
186
225
  };
187
226
  sideEffects?: Array<CreatorSideEffect>;
188
227
  }
228
+ type CreatorDefinition<Payload = any> = SpecificCreatorDefinition<Payload, any, any, any, any, any, any>;
189
229
  interface CreatorSideEffect {
190
230
  run?: (result: any, ctx: {
191
231
  options: CreatorOptions;
@@ -214,8 +254,8 @@ declare class Creator {
214
254
  vault: Vault;
215
255
  previewVault: Vault;
216
256
  constructor(vault: Vault, configs: CreatorDefinition[], previewVault?: Vault);
217
- matchBasedOnResource(resource: CreatableResource): CreatorDefinition<any>[];
218
- create(definition: string, payload: any, options?: Partial<CreatorOptions>): Promise<Reference>;
257
+ matchBasedOnResource(resource: CreatableResource): CreatorDefinition[];
258
+ create(definition: string, payload: any, options?: Partial<CreatorOptions>): Promise<Reference | Reference[]>;
219
259
  }
220
260
 
221
261
  declare function resolveType(type: string): keyof Entities;
@@ -224,5 +264,9 @@ declare function randomId(): string;
224
264
  declare function matchBasedOnResource(resource: CreatableResource, list: CreatorDefinition[], options: {
225
265
  vault: Vault;
226
266
  }): CreatorDefinition[];
267
+ declare function creatorHelper<const ResourceType extends AllAvailableParentTypes, const Parent extends {
268
+ id: string;
269
+ type: ResourceType;
270
+ }, 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
271
 
228
- export { type CreatableResource, Creator, type CreatorContext, type CreatorDefinition, type CreatorFunctionContext, type CreatorOptions, CreatorResource, type CreatorSideEffect, type GetCreatorPayload, getEmptyType, matchBasedOnResource, randomId, resolveType };
272
+ 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,9 +154,20 @@ 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
172
  constructor(data, vault) {
163
173
  __publicField(this, "resource");
@@ -191,7 +201,6 @@ var CreatorResource = class _CreatorResource {
191
201
  const rangeRef = new ReferencedResource(range, vault);
192
202
  newRange.push(rangeRef);
193
203
  data[key] = rangeRef;
194
- continue;
195
204
  }
196
205
  data[key] = newRange;
197
206
  continue;
@@ -468,13 +477,25 @@ var CreatorRuntime = class {
468
477
  this.payload = payload;
469
478
  this.configs = createConfigs;
470
479
  this.options = {
471
- targetType: (options || {}).targetType || definition.resourceType,
480
+ targetType: options?.targetType || definition.resourceType,
472
481
  ...options || {}
473
482
  };
474
483
  }
475
484
  async run() {
476
485
  const instance = new CreatorInstance(this.vault, this.options, this.configs, this.previewVault);
477
486
  const result = await this.definition.create(this.payload, instance);
487
+ if (Array.isArray(result)) {
488
+ const results = [];
489
+ for (const item of result) {
490
+ if (item instanceof CreatorResource) {
491
+ results.push(item);
492
+ } else {
493
+ results.push(new CreatorResource(item, this.vault));
494
+ }
495
+ }
496
+ this.resource = results;
497
+ return this.resource;
498
+ }
478
499
  if (result instanceof CreatorResource) {
479
500
  this.resource = result;
480
501
  } else {
@@ -486,26 +507,29 @@ var CreatorRuntime = class {
486
507
  if (!this.resource) {
487
508
  return [];
488
509
  }
510
+ const allResources = Array.isArray(this.resource) ? this.resource : [this.resource];
489
511
  const actions = [];
490
512
  const resources = {};
491
513
  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;
514
+ for (const resource of allResources) {
515
+ if (this.options.parent) {
516
+ resource.setPartOf(this.options.parent.resource.id);
501
517
  }
502
- const type = resolveType(resource.type);
503
- resources[type] = resources[type] ? resources[type] : {};
504
- resources[type][resource.id] = resource;
505
- mapping[resource.id] = type;
518
+ const embedded = resource.getAllEmbeddedResources();
519
+ const allItems = [...embedded, resource];
520
+ for (const item of allItems) {
521
+ const resource2 = item.getVaultResource();
522
+ if (!resource2.type || !resource2.id) {
523
+ continue;
524
+ }
525
+ const type = resolveType(resource2.type);
526
+ resources[type] = resources[type] ? resources[type] : {};
527
+ resources[type][resource2.id] = resource2;
528
+ mapping[resource2.id] = type;
529
+ }
530
+ actions.push(importEntities({ entities: resources }));
531
+ actions.push(addMappings({ mapping }));
506
532
  }
507
- actions.push(importEntities({ entities: resources }));
508
- actions.push(addMappings({ mapping }));
509
533
  return actions;
510
534
  }
511
535
  commit(afterActions = []) {
@@ -514,12 +538,14 @@ var CreatorRuntime = class {
514
538
  }
515
539
  const actions = this.getActions();
516
540
  this.vault.dispatch(batchActions({ actions: [...actions, ...afterActions] }));
541
+ if (Array.isArray(this.resource)) {
542
+ return this.resource.map((resource) => resource.ref());
543
+ }
517
544
  return this.resource.ref();
518
545
  }
519
546
  };
520
547
 
521
548
  // src/Creator.ts
522
- import { entityActions } from "@iiif/helpers/vault/actions";
523
549
  var Creator = class {
524
550
  constructor(vault, configs, previewVault) {
525
551
  __publicField(this, "configs");
@@ -530,11 +556,7 @@ var Creator = class {
530
556
  this.previewVault = previewVault || new Vault();
531
557
  }
532
558
  matchBasedOnResource(resource) {
533
- return matchBasedOnResource(
534
- resource,
535
- this.configs || [],
536
- { vault: this.vault }
537
- );
559
+ return matchBasedOnResource(resource, this.configs || [], { vault: this.vault });
538
560
  }
539
561
  async create(definition, payload, options) {
540
562
  const foundDefinition = this.configs.find((t) => t.id === definition);
@@ -568,28 +590,31 @@ var Creator = class {
568
590
  }
569
591
  }
570
592
  const runtime = new CreatorRuntime(this.vault, foundDefinition, payload, this.configs, this.previewVault, options);
571
- const resource = await runtime.run();
593
+ const run = await runtime.run();
594
+ const allResources = Array.isArray(run) ? run : [run];
572
595
  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
- );
596
+ for (const resource of allResources) {
597
+ if (options?.parent) {
598
+ if (options.parent.property === "start" || options.parent.property === "target") {
599
+ afterActions.push(
600
+ entityActions.modifyEntityField({
601
+ id: options.parent.resource.id,
602
+ type: options.parent.resource.type,
603
+ value: resource.ref(),
604
+ key: options.parent.property
605
+ })
606
+ );
607
+ } else {
608
+ afterActions.push(
609
+ entityActions.addReference({
610
+ id: options.parent.resource.id,
611
+ type: options.parent.resource.type,
612
+ reference: resource.ref(),
613
+ key: options.parent.property,
614
+ index: options.parent.atIndex
615
+ })
616
+ );
617
+ }
593
618
  }
594
619
  }
595
620
  const result = runtime.commit(afterActions);
@@ -597,7 +622,10 @@ var Creator = class {
597
622
  if (foundDefinition.sideEffects) {
598
623
  for (const sideEffect of foundDefinition.sideEffects) {
599
624
  if (sideEffect.run) {
600
- await sideEffect.run(result, { vault: this.vault, options });
625
+ const allResults = Array.isArray(result) ? result : [result];
626
+ for (const item of allResults) {
627
+ await sideEffect.run(item, { vault: this.vault, options });
628
+ }
601
629
  }
602
630
  }
603
631
  }
@@ -605,9 +633,16 @@ var Creator = class {
605
633
  return result;
606
634
  }
607
635
  };
636
+
637
+ // src/creator-register.ts
638
+ function defineCreator(options) {
639
+ return options;
640
+ }
608
641
  export {
609
642
  Creator,
610
643
  CreatorResource,
644
+ creatorHelper,
645
+ defineCreator,
611
646
  getEmptyType,
612
647
  matchBasedOnResource,
613
648
  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.0",
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": "4ca76024a42ec30c958f476a6fcd8d10592c12d3"
63
63
  }