@manifest-editor/creator-api 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,17 +157,20 @@ 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>;
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>>;
141
167
  generateId(type: string, parent?: Reference | ReferencedResource): string;
142
168
  getParent(): Reference | undefined;
143
169
  getTarget(): SpecificResource | Reference | undefined;
144
170
  getParentResource(): SpecificResource | undefined;
145
171
  getPreviewVault(): Vault;
146
172
  }
173
+ type GetCreatorPayload<T extends CreatorDefinition> = T extends CreatorDefinition<infer Payload> ? Payload : never;
147
174
  interface CreatorParent {
148
175
  resource: Reference;
149
176
  property: string;
@@ -155,20 +182,34 @@ interface CreatorOptions {
155
182
  parent?: CreatorParent;
156
183
  initialData?: any;
157
184
  }
158
- interface CreatorDefinition {
159
- 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;
160
201
  label: string;
161
202
  summary?: string;
162
203
  icon?: any;
163
204
  dependencies?: string[];
164
205
  tags?: string[];
165
- create: (payload: any, ctx: CreatorInstance) => any | Promise<any>;
166
- validate?: (payload: any, vault: Vault) => void | Promise<void>;
167
- render?: (ctx: CreatorContext) => ReactNode;
168
- renderCanvas?: (ctx: CreatorContext) => ReactNode | null;
169
- renderModal?: (ctx: CreatorContext) => ReactNode;
170
- resourceType: string;
171
- additionalTypes?: string[];
206
+ create: (payload: Payload, ctx: CreatorInstance) => CreateReturnType;
207
+ validate?: (payload: Payload, vault: Vault) => void | Promise<void>;
208
+ render?: (ctx: CreatorContext<Payload>) => ReactNode;
209
+ renderCanvas?: (ctx: CreatorContext<Payload>) => ReactNode | null;
210
+ renderModal?: (ctx: CreatorContext<Payload>) => ReactNode;
211
+ resourceType: ResourceType;
212
+ additionalTypes?: AdditionalResourceTypes;
172
213
  resourceFields: string[];
173
214
  embeddedResources?: string[];
174
215
  staticFields?: Record<string, any>;
@@ -176,14 +217,15 @@ interface CreatorDefinition {
176
217
  hiddenModal?: boolean;
177
218
  supports: {
178
219
  initialData?: boolean;
179
- parentTypes?: string[];
180
- parentFields?: string[];
220
+ parentTypes?: SupportsParentTypes;
221
+ parentFields?: SupportsParentFields;
181
222
  parentFieldMap?: Record<string, string[]>;
182
223
  custom?: (parent: CreatorParent, vault: Vault) => boolean;
183
224
  disallowPainting?: boolean;
184
225
  };
185
226
  sideEffects?: Array<CreatorSideEffect>;
186
227
  }
228
+ type CreatorDefinition<Payload = any> = SpecificCreatorDefinition<Payload, any, any, any, any, any, any>;
187
229
  interface CreatorSideEffect {
188
230
  run?: (result: any, ctx: {
189
231
  options: CreatorOptions;
@@ -213,7 +255,7 @@ declare class Creator {
213
255
  previewVault: Vault;
214
256
  constructor(vault: Vault, configs: CreatorDefinition[], previewVault?: Vault);
215
257
  matchBasedOnResource(resource: CreatableResource): CreatorDefinition[];
216
- create(definition: string, payload: any, options?: Partial<CreatorOptions>): Promise<Reference>;
258
+ create(definition: string, payload: any, options?: Partial<CreatorOptions>): Promise<Reference | Reference[]>;
217
259
  }
218
260
 
219
261
  declare function resolveType(type: string): keyof Entities;
@@ -222,5 +264,9 @@ declare function randomId(): string;
222
264
  declare function matchBasedOnResource(resource: CreatableResource, list: CreatorDefinition[], options: {
223
265
  vault: Vault;
224
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>;
225
271
 
226
- export { type CreatableResource, Creator, type CreatorContext, type CreatorDefinition, type CreatorFunctionContext, type CreatorOptions, CreatorResource, type CreatorSideEffect, 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,17 +157,20 @@ 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>;
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>>;
141
167
  generateId(type: string, parent?: Reference | ReferencedResource): string;
142
168
  getParent(): Reference | undefined;
143
169
  getTarget(): SpecificResource | Reference | undefined;
144
170
  getParentResource(): SpecificResource | undefined;
145
171
  getPreviewVault(): Vault;
146
172
  }
173
+ type GetCreatorPayload<T extends CreatorDefinition> = T extends CreatorDefinition<infer Payload> ? Payload : never;
147
174
  interface CreatorParent {
148
175
  resource: Reference;
149
176
  property: string;
@@ -155,20 +182,34 @@ interface CreatorOptions {
155
182
  parent?: CreatorParent;
156
183
  initialData?: any;
157
184
  }
158
- interface CreatorDefinition {
159
- 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;
160
201
  label: string;
161
202
  summary?: string;
162
203
  icon?: any;
163
204
  dependencies?: string[];
164
205
  tags?: string[];
165
- create: (payload: any, ctx: CreatorInstance) => any | Promise<any>;
166
- validate?: (payload: any, vault: Vault) => void | Promise<void>;
167
- render?: (ctx: CreatorContext) => ReactNode;
168
- renderCanvas?: (ctx: CreatorContext) => ReactNode | null;
169
- renderModal?: (ctx: CreatorContext) => ReactNode;
170
- resourceType: string;
171
- additionalTypes?: string[];
206
+ create: (payload: Payload, ctx: CreatorInstance) => CreateReturnType;
207
+ validate?: (payload: Payload, vault: Vault) => void | Promise<void>;
208
+ render?: (ctx: CreatorContext<Payload>) => ReactNode;
209
+ renderCanvas?: (ctx: CreatorContext<Payload>) => ReactNode | null;
210
+ renderModal?: (ctx: CreatorContext<Payload>) => ReactNode;
211
+ resourceType: ResourceType;
212
+ additionalTypes?: AdditionalResourceTypes;
172
213
  resourceFields: string[];
173
214
  embeddedResources?: string[];
174
215
  staticFields?: Record<string, any>;
@@ -176,14 +217,15 @@ interface CreatorDefinition {
176
217
  hiddenModal?: boolean;
177
218
  supports: {
178
219
  initialData?: boolean;
179
- parentTypes?: string[];
180
- parentFields?: string[];
220
+ parentTypes?: SupportsParentTypes;
221
+ parentFields?: SupportsParentFields;
181
222
  parentFieldMap?: Record<string, string[]>;
182
223
  custom?: (parent: CreatorParent, vault: Vault) => boolean;
183
224
  disallowPainting?: boolean;
184
225
  };
185
226
  sideEffects?: Array<CreatorSideEffect>;
186
227
  }
228
+ type CreatorDefinition<Payload = any> = SpecificCreatorDefinition<Payload, any, any, any, any, any, any>;
187
229
  interface CreatorSideEffect {
188
230
  run?: (result: any, ctx: {
189
231
  options: CreatorOptions;
@@ -213,7 +255,7 @@ declare class Creator {
213
255
  previewVault: Vault;
214
256
  constructor(vault: Vault, configs: CreatorDefinition[], previewVault?: Vault);
215
257
  matchBasedOnResource(resource: CreatableResource): CreatorDefinition[];
216
- create(definition: string, payload: any, options?: Partial<CreatorOptions>): Promise<Reference>;
258
+ create(definition: string, payload: any, options?: Partial<CreatorOptions>): Promise<Reference | Reference[]>;
217
259
  }
218
260
 
219
261
  declare function resolveType(type: string): keyof Entities;
@@ -222,5 +264,9 @@ declare function randomId(): string;
222
264
  declare function matchBasedOnResource(resource: CreatableResource, list: CreatorDefinition[], options: {
223
265
  vault: Vault;
224
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>;
225
271
 
226
- export { type CreatableResource, Creator, type CreatorContext, type CreatorDefinition, type CreatorFunctionContext, type CreatorOptions, CreatorResource, type CreatorSideEffect, 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.0",
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.0",
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": "deba5190f58c11b91383eacd79715607ba5b8d24"
62
+ "gitHead": "4ca76024a42ec30c958f476a6fcd8d10592c12d3"
63
63
  }