@qti-editor/core 1.3.2 → 1.4.1

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.
@@ -10,6 +10,10 @@ export interface ComposerItemContext {
10
10
  lang?: string;
11
11
  title?: string;
12
12
  itemBody?: Document;
13
+ items?: Array<{
14
+ identifier?: string;
15
+ title?: string;
16
+ }>;
13
17
  }
14
18
  export interface ResponseDeclaration {
15
19
  identifier: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/composer/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAErE,MAAM,WAAW,mBAAmB;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;IAC/C,QAAQ,EAAE,YAAY,GAAG,cAAc,GAAG,OAAO,GAAG,QAAQ,CAAC;IAC7D,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACpC,aAAa,CAAC,EAAE;QACd,YAAY,EAAE,MAAM,CAAC;QACrB,OAAO,EAAE,KAAK,CAAC;YACb,MAAM,EAAE,MAAM,CAAC;YACf,WAAW,EAAE,MAAM,CAAC;YACpB,aAAa,EAAE,OAAO,CAAC;SACxB,CAAC,CAAC;KACJ,CAAC;IACF,sBAAsB,CAAC,EAAE,sBAAsB,CAAC;IAChD,WAAW,CAAC,EAAE;QACZ,YAAY,EAAE,MAAM,CAAC;QACrB,OAAO,EAAE,KAAK,CAAC;YACb,KAAK,EAAE,QAAQ,GAAG,MAAM,CAAC;YACzB,MAAM,EAAE,MAAM,CAAC;YACf,WAAW,EAAE,MAAM,CAAC;SACrB,CAAC,CAAC;KACJ,CAAC;IACF,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAiED,wBAAgB,2BAA2B,CAAC,YAAY,CAAC,EAAE,OAAO,GAAG,IAAI,GAAG,mBAAmB,EAAE,CAOhG;AAkFD,wBAAgB,sBAAsB,CAAC,WAAW,CAAC,EAAE,mBAAmB,GAAG,MAAM,CAqHhF;AAED;;;;;;;;GAQG;AACH,wBAAgB,+BAA+B,CAAC,WAAW,CAAC,EAAE,mBAAmB,GAAG,MAAM,CAkCzF;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,WAAW,CAAC,EAAE,mBAAmB,GAAG,MAAM,CAUtF;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,CAAC,EAAE,mBAAmB,GAAG,MAAM,CAK5E;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,CAAC,EAAE,mBAAmB,GAAG,KAAK,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAyChI;AAiMD,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CA4B7C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/composer/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAErE,MAAM,WAAW,mBAAmB;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACxD;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;IAC/C,QAAQ,EAAE,YAAY,GAAG,cAAc,GAAG,OAAO,GAAG,QAAQ,CAAC;IAC7D,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACpC,aAAa,CAAC,EAAE;QACd,YAAY,EAAE,MAAM,CAAC;QACrB,OAAO,EAAE,KAAK,CAAC;YACb,MAAM,EAAE,MAAM,CAAC;YACf,WAAW,EAAE,MAAM,CAAC;YACpB,aAAa,EAAE,OAAO,CAAC;SACxB,CAAC,CAAC;KACJ,CAAC;IACF,sBAAsB,CAAC,EAAE,sBAAsB,CAAC;IAChD,WAAW,CAAC,EAAE;QACZ,YAAY,EAAE,MAAM,CAAC;QACrB,OAAO,EAAE,KAAK,CAAC;YACb,KAAK,EAAE,QAAQ,GAAG,MAAM,CAAC;YACzB,MAAM,EAAE,MAAM,CAAC;YACf,WAAW,EAAE,MAAM,CAAC;SACrB,CAAC,CAAC;KACJ,CAAC;IACF,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAkGD,wBAAgB,2BAA2B,CAAC,YAAY,CAAC,EAAE,OAAO,GAAG,IAAI,GAAG,mBAAmB,EAAE,CAOhG;AAkFD,wBAAgB,sBAAsB,CAAC,WAAW,CAAC,EAAE,mBAAmB,GAAG,MAAM,CAmIhF;AAED;;;;;;;;GAQG;AACH,wBAAgB,+BAA+B,CAAC,WAAW,CAAC,EAAE,mBAAmB,GAAG,MAAM,CAqDzF;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,WAAW,CAAC,EAAE,mBAAmB,GAAG,MAAM,CAUtF;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,CAAC,EAAE,mBAAmB,GAAG,MAAM,CAK5E;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,CAAC,EAAE,mBAAmB,GAAG,KAAK,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CA0DhI;AAoKD,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CA4B7C"}
@@ -24,6 +24,28 @@ const TEXT_ENTRY_DATA_ATTRIBUTE_MAPPINGS = [
24
24
  const SELECT_POINT_DATA_ATTRIBUTE_MAPPINGS = [
25
25
  { source: 'area-mappings', target: 'data-area-mappings' },
26
26
  ];
27
+ function sanitizeIdentifier(value, fallback) {
28
+ const sanitized = value?.trim().replace(/[^A-Za-z0-9_.-]+/g, '-').replace(/^-+|-+$/g, '');
29
+ return sanitized || fallback;
30
+ }
31
+ function hashIdentifierSeed(value) {
32
+ let hash = 0x811c9dc5;
33
+ for (let i = 0; i < value.length; i += 1) {
34
+ hash ^= value.charCodeAt(i);
35
+ hash = Math.imul(hash, 0x01000193);
36
+ }
37
+ return (hash >>> 0).toString(36);
38
+ }
39
+ function createAutoIdentifier(options) {
40
+ const titleBase = sanitizeIdentifier(options.title, '');
41
+ const base = titleBase || sanitizeIdentifier(options.baseIdentifier, 'item');
42
+ const serializedBody = options.body == null
43
+ ? ''
44
+ : new XMLSerializer().serializeToString(options.body instanceof Document ? options.body.documentElement : options.body);
45
+ const seed = [base, options.itemNumber ?? 1, serializedBody].join('|');
46
+ const suffix = hashIdentifierSeed(seed).slice(0, 8);
47
+ return `${base}-${suffix}`;
48
+ }
27
49
  function parseCorrectResponseValues(declaration) {
28
50
  const value = declaration.correctResponse;
29
51
  if (value == null)
@@ -140,7 +162,11 @@ export function buildAssessmentItemXml(itemContext) {
140
162
  const root = xmlDoc.documentElement;
141
163
  root.setAttribute('xmlns', QTI_NS);
142
164
  root.setAttributeNS(XSI_NS, 'xsi:schemaLocation', SCHEMA_LOCATION);
143
- root.setAttribute('identifier', itemContext.identifier?.trim() || 'item-1');
165
+ root.setAttribute('identifier', sanitizeIdentifier(itemContext.identifier, createAutoIdentifier({
166
+ title: itemContext.title,
167
+ baseIdentifier: itemContext.identifier,
168
+ body: itemContext.itemBody,
169
+ })));
144
170
  root.setAttribute('title', itemContext.title?.trim() || 'Untitled Item');
145
171
  root.setAttribute('adaptive', 'false');
146
172
  root.setAttribute('time-dependent', 'false');
@@ -153,7 +179,7 @@ export function buildAssessmentItemXml(itemContext) {
153
179
  const composedItemBody = sourceBodyRoot != null
154
180
  ? xmlDoc.importNode(sourceBodyRoot, true)
155
181
  : xmlDoc.createElementNS(QTI_NS, 'qti-item-body');
156
- const { declarations, responseTemplate, maxScore } = composeAndNormalizeItemBody(composedItemBody, xmlDoc);
182
+ const { declarations, responseTemplate, maxScore, hasAutomatedProcessing } = composeAndNormalizeItemBody(composedItemBody, xmlDoc);
157
183
  declarations.forEach(declaration => {
158
184
  const responseDeclaration = xmlDoc.createElementNS(QTI_NS, 'qti-response-declaration');
159
185
  responseDeclaration.setAttribute('identifier', declaration.identifier);
@@ -218,17 +244,20 @@ export function buildAssessmentItemXml(itemContext) {
218
244
  root.appendChild(maxScoreOutcomeDeclaration);
219
245
  }
220
246
  root.appendChild(composedItemBody);
221
- if (maxScore > 0) {
222
- if (declarations.length === 1) {
247
+ if (maxScore > 0 && hasAutomatedProcessing) {
248
+ const single = declarations.length === 1 ? declarations[0] : null;
249
+ const canUseTemplate = single !== null &&
250
+ !(single.responseProcessingKind === 'match_correct' && (single.score ?? 1) !== 1);
251
+ if (canUseTemplate) {
223
252
  const responseProcessing = xmlDoc.createElementNS(QTI_NS, 'qti-response-processing');
224
253
  responseProcessing.setAttribute('template', responseTemplate);
225
254
  root.appendChild(responseProcessing);
226
255
  }
227
- else if (declarations.length > 1) {
256
+ else {
228
257
  root.appendChild(buildMultiInteractionResponseProcessing(xmlDoc, declarations));
229
258
  }
230
259
  }
231
- return new XMLSerializer().serializeToString(xmlDoc);
260
+ return new XMLSerializer().serializeToString(xmlDoc).replace(/\s+xmlns=""/g, '');
232
261
  }
233
262
  /**
234
263
  * Build multiple QTI assessment items from a single editor document.
@@ -248,17 +277,36 @@ export function buildMultipleAssessmentItemsXml(itemContext) {
248
277
  return buildAssessmentItemXml(itemContext);
249
278
  }
250
279
  // Build multiple items
251
- const baseIdentifier = itemContext.identifier?.trim() || 'item';
280
+ const baseIdentifier = sanitizeIdentifier(itemContext.identifier, 'item');
252
281
  const baseTitle = itemContext.title?.trim() || 'Untitled Item';
253
282
  const lang = itemContext.lang?.trim() || 'en';
283
+ const usedIdentifiers = new Set();
254
284
  const itemXmls = fragments.map((fragmentBody, index) => {
255
285
  const itemNumber = index + 1;
286
+ const perItem = itemContext.items?.[index];
256
287
  const fragmentDoc = document.implementation.createDocument(QTI_NS, 'qti-item-body', null);
257
288
  const importedFragment = fragmentDoc.importNode(fragmentBody, true);
258
289
  fragmentDoc.replaceChild(importedFragment, fragmentDoc.documentElement);
290
+ let identifier = perItem?.identifier?.trim();
291
+ if (!identifier) {
292
+ identifier = createAutoIdentifier({
293
+ title: perItem?.title || `${baseTitle} ${itemNumber}`,
294
+ baseIdentifier: `${baseIdentifier}-${itemNumber}`,
295
+ itemNumber,
296
+ body: fragmentDoc,
297
+ });
298
+ }
299
+ identifier = sanitizeIdentifier(identifier, `${baseIdentifier}-${itemNumber}`);
300
+ let uniqueIdentifier = identifier;
301
+ let duplicateIndex = 2;
302
+ while (usedIdentifiers.has(uniqueIdentifier)) {
303
+ uniqueIdentifier = `${identifier}-${duplicateIndex}`;
304
+ duplicateIndex += 1;
305
+ }
306
+ usedIdentifiers.add(uniqueIdentifier);
259
307
  const fragmentContext = {
260
- identifier: `${baseIdentifier}-${itemNumber}`,
261
- title: `${baseTitle} ${itemNumber}`,
308
+ identifier: uniqueIdentifier,
309
+ title: perItem?.title?.trim() || `${baseTitle} ${itemNumber}`,
262
310
  lang,
263
311
  itemBody: fragmentDoc,
264
312
  };
@@ -303,33 +351,49 @@ export function getItemFragmentXmls(itemContext) {
303
351
  const fragments = splitItemBodyAtDividers(itemContext.itemBody);
304
352
  // If only one fragment (no dividers), return single item
305
353
  if (fragments.length <= 1) {
306
- const xml = buildAssessmentItemXml(itemContext);
307
- return [{
308
- identifier: itemContext.identifier?.trim() || 'item-1',
309
- title: itemContext.title?.trim() || 'Untitled Item',
310
- xml,
311
- }];
354
+ const perItem = itemContext.items?.[0];
355
+ const identifier = sanitizeIdentifier(perItem?.identifier || itemContext.identifier, createAutoIdentifier({
356
+ title: perItem?.title || itemContext.title,
357
+ baseIdentifier: itemContext.identifier,
358
+ itemNumber: 1,
359
+ body: itemContext.itemBody,
360
+ }));
361
+ const title = perItem?.title?.trim() || itemContext.title?.trim() || 'Untitled Item';
362
+ const xml = buildAssessmentItemXml({ ...itemContext, identifier, title });
363
+ return [{ identifier, title, xml }];
312
364
  }
313
- const baseIdentifier = itemContext.identifier?.trim() || 'item';
365
+ const baseIdentifier = sanitizeIdentifier(itemContext.identifier, 'item');
314
366
  const baseTitle = itemContext.title?.trim() || 'Untitled Item';
315
367
  const lang = itemContext.lang?.trim() || 'en';
368
+ const usedIdentifiers = new Set();
316
369
  return fragments.map((fragmentBody, index) => {
317
370
  const itemNumber = index + 1;
371
+ const perItem = itemContext.items?.[index];
372
+ const title = perItem?.title?.trim() || `${baseTitle} ${itemNumber}`;
318
373
  const fragmentDoc = document.implementation.createDocument(QTI_NS, 'qti-item-body', null);
319
374
  const importedFragment = fragmentDoc.importNode(fragmentBody, true);
320
375
  fragmentDoc.replaceChild(importedFragment, fragmentDoc.documentElement);
321
- const identifier = `${baseIdentifier}-${itemNumber}`;
322
- const title = `${baseTitle} ${itemNumber}`;
323
- const fragmentContext = {
324
- identifier,
325
- title,
326
- lang,
327
- itemBody: fragmentDoc,
328
- };
376
+ let identifier = perItem?.identifier?.trim();
377
+ if (!identifier) {
378
+ identifier = createAutoIdentifier({
379
+ title,
380
+ baseIdentifier: `${baseIdentifier}-${itemNumber}`,
381
+ itemNumber,
382
+ body: fragmentDoc,
383
+ });
384
+ }
385
+ identifier = sanitizeIdentifier(identifier, `${baseIdentifier}-${itemNumber}`);
386
+ let uniqueIdentifier = identifier;
387
+ let duplicateIndex = 2;
388
+ while (usedIdentifiers.has(uniqueIdentifier)) {
389
+ uniqueIdentifier = `${identifier}-${duplicateIndex}`;
390
+ duplicateIndex += 1;
391
+ }
392
+ usedIdentifiers.add(uniqueIdentifier);
329
393
  return {
330
- identifier,
394
+ identifier: uniqueIdentifier,
331
395
  title,
332
- xml: buildAssessmentItemXml(fragmentContext),
396
+ xml: buildAssessmentItemXml({ identifier: uniqueIdentifier, title, lang, itemBody: fragmentDoc }),
333
397
  };
334
398
  });
335
399
  }
@@ -368,14 +432,17 @@ function composeAndNormalizeItemBody(itemBody, xmlDoc) {
368
432
  if (composeResult.responseDeclaration) {
369
433
  maxScore += composeResult.responseDeclaration.score ?? 1;
370
434
  }
371
- if (composeResult.responseDeclaration && !seenIdentifiers.has(composeResult.responseDeclaration.identifier)) {
435
+ if (composeResult.responseDeclaration) {
436
+ const declaration = composeResult.responseDeclaration;
437
+ if (seenIdentifiers.has(declaration.identifier)) {
438
+ const freshId = `RESPONSE_${crypto.randomUUID()}`;
439
+ composeResult.normalizedElement.setAttribute('response-identifier', freshId);
440
+ declaration.identifier = freshId;
441
+ }
372
442
  const responseProcessingKind = composeResult
373
443
  .responseProcessingKind;
374
- declarations.push({
375
- ...composeResult.responseDeclaration,
376
- responseProcessingKind,
377
- });
378
- seenIdentifiers.add(composeResult.responseDeclaration.identifier);
444
+ declarations.push({ ...declaration, responseProcessingKind });
445
+ seenIdentifiers.add(declaration.identifier);
379
446
  }
380
447
  if (composeResult.responseProcessingTemplate && composeResult.responseDeclaration) {
381
448
  templateCandidates.add(composeResult.responseProcessingTemplate);
@@ -392,16 +459,17 @@ function composeAndNormalizeItemBody(itemBody, xmlDoc) {
392
459
  itemBody.querySelectorAll('[score]').forEach(element => {
393
460
  element.removeAttribute('score');
394
461
  });
395
- normalizeResponseIdentifiers(itemBody, declarations);
396
462
  if (declarations.length === 1 && templateCandidates.size === 1) {
397
- return { declarations, responseTemplate: Array.from(templateCandidates)[0], maxScore };
463
+ return { declarations, responseTemplate: Array.from(templateCandidates)[0], maxScore, hasAutomatedProcessing: true };
398
464
  }
399
- return { declarations, responseTemplate: MATCH_CORRECT_TEMPLATE, maxScore };
465
+ return { declarations, responseTemplate: MATCH_CORRECT_TEMPLATE, maxScore, hasAutomatedProcessing: templateCandidates.size > 0 };
400
466
  }
401
467
  function buildMultiInteractionResponseProcessing(xmlDoc, declarations) {
402
468
  const responseProcessing = xmlDoc.createElementNS(QTI_NS, 'qti-response-processing');
403
469
  declarations.forEach(declaration => {
404
- const kind = declaration.responseProcessingKind ?? 'match_correct';
470
+ if (declaration.responseProcessingKind === undefined)
471
+ return;
472
+ const kind = declaration.responseProcessingKind;
405
473
  if (kind === 'match_correct') {
406
474
  responseProcessing.appendChild(createMatchCorrectContribution(xmlDoc, declaration.identifier, declaration.score ?? 1));
407
475
  return;
@@ -434,16 +502,12 @@ function createMatchCorrectContribution(xmlDoc, responseIdentifier, score = 1) {
434
502
  }
435
503
  function createMapResponseContribution(xmlDoc, responseIdentifier) {
436
504
  const mapResponse = xmlDoc.createElementNS(QTI_NS, 'qti-map-response');
437
- const variable = xmlDoc.createElementNS(QTI_NS, 'qti-variable');
438
- variable.setAttribute('identifier', responseIdentifier);
439
- mapResponse.appendChild(variable);
505
+ mapResponse.setAttribute('identifier', responseIdentifier);
440
506
  return createScoreIncrement(xmlDoc, mapResponse);
441
507
  }
442
508
  function createMapResponsePointContribution(xmlDoc, responseIdentifier) {
443
509
  const mapResponsePoint = xmlDoc.createElementNS(QTI_NS, 'qti-map-response-point');
444
- const variable = xmlDoc.createElementNS(QTI_NS, 'qti-variable');
445
- variable.setAttribute('identifier', responseIdentifier);
446
- mapResponsePoint.appendChild(variable);
510
+ mapResponsePoint.setAttribute('identifier', responseIdentifier);
447
511
  return createScoreIncrement(xmlDoc, mapResponsePoint);
448
512
  }
449
513
  function createScoreIncrement(xmlDoc, contribution) {
@@ -457,34 +521,6 @@ function createScoreIncrement(xmlDoc, contribution) {
457
521
  setOutcomeValue.appendChild(sum);
458
522
  return setOutcomeValue;
459
523
  }
460
- function normalizeResponseIdentifiers(itemBody, declarations) {
461
- if (declarations.length === 0)
462
- return;
463
- const identifierMap = new Map();
464
- if (declarations.length === 1) {
465
- identifierMap.set(declarations[0].identifier, 'RESPONSE');
466
- }
467
- else {
468
- declarations.forEach((declaration, index) => {
469
- identifierMap.set(declaration.identifier, `RESPONSE${index + 1}`);
470
- });
471
- }
472
- itemBody.querySelectorAll('[response-identifier]').forEach(interaction => {
473
- const currentIdentifier = interaction.getAttribute('response-identifier')?.trim();
474
- if (!currentIdentifier)
475
- return;
476
- const mappedIdentifier = identifierMap.get(currentIdentifier);
477
- if (mappedIdentifier) {
478
- interaction.setAttribute('response-identifier', mappedIdentifier);
479
- }
480
- });
481
- declarations.forEach(declaration => {
482
- const mappedIdentifier = identifierMap.get(declaration.identifier);
483
- if (mappedIdentifier) {
484
- declaration.identifier = mappedIdentifier;
485
- }
486
- });
487
- }
488
524
  export function formatXml(xml) {
489
525
  const PADDING = ' ';
490
526
  const reg = /(>)(<)(\/*)/g;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qti-editor/core",
3
- "version": "1.3.2",
3
+ "version": "1.4.1",
4
4
  "description": "QTI semantics, composer registry, and XML export orchestration for QTI Editor",
5
5
  "repository": {
6
6
  "type": "git",
@@ -24,19 +24,19 @@
24
24
  }
25
25
  },
26
26
  "dependencies": {
27
- "@qti-editor/interfaces": "1.2.0",
28
- "@qti-editor/interaction-associate": "1.2.1",
29
- "@qti-editor/interaction-choice": "1.2.1",
30
- "@qti-editor/interaction-extended-text": "1.2.1",
31
- "@qti-editor/interaction-gap-match": "1.1.0",
32
- "@qti-editor/interaction-hottext": "1.2.2",
33
- "@qti-editor/interaction-inline-choice": "1.2.1",
34
- "@qti-editor/interaction-match": "1.2.0",
35
- "@qti-editor/interaction-order": "0.6.0",
36
- "@qti-editor/interaction-select-point": "1.2.0",
37
- "@qti-editor/interaction-shared": "1.3.0",
38
- "@qti-editor/interaction-text-entry": "1.2.0",
39
- "@qti-editor/qti-item-divider": "1.1.0"
27
+ "@qti-editor/interfaces": "1.2.1",
28
+ "@qti-editor/interaction-associate": "1.2.4",
29
+ "@qti-editor/interaction-choice": "1.2.3",
30
+ "@qti-editor/interaction-extended-text": "1.3.1",
31
+ "@qti-editor/interaction-gap-match": "1.1.2",
32
+ "@qti-editor/interaction-hottext": "1.2.4",
33
+ "@qti-editor/interaction-inline-choice": "1.3.1",
34
+ "@qti-editor/interaction-match": "1.2.2",
35
+ "@qti-editor/interaction-order": "0.6.2",
36
+ "@qti-editor/interaction-select-point": "1.2.2",
37
+ "@qti-editor/interaction-shared": "1.3.2",
38
+ "@qti-editor/interaction-text-entry": "1.2.2",
39
+ "@qti-editor/qti-item-divider": "1.1.3"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@types/node": "^20.0.0",