@conform-ed/qti-react 0.0.12 → 0.0.13

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.
Files changed (65) hide show
  1. package/dist/index.js +4566 -212
  2. package/package.json +3 -1
  3. package/src/capability.ts +24 -0
  4. package/src/content-model.ts +104 -5
  5. package/src/graphic.ts +103 -0
  6. package/src/index.ts +139 -3
  7. package/src/interactions/associate.ts +22 -0
  8. package/src/interactions/drawing.ts +24 -0
  9. package/src/interactions/end-attempt.ts +19 -0
  10. package/src/interactions/extended-text.ts +21 -0
  11. package/src/interactions/gap-match.ts +22 -0
  12. package/src/interactions/graphic.ts +104 -0
  13. package/src/interactions/hottext.ts +21 -0
  14. package/src/interactions/index.ts +57 -2
  15. package/src/interactions/match.ts +27 -0
  16. package/src/interactions/media.ts +24 -0
  17. package/src/interactions/order.ts +21 -0
  18. package/src/interactions/slider.ts +24 -0
  19. package/src/interactions/upload.ts +19 -0
  20. package/src/normalized-item.ts +561 -0
  21. package/src/pci/index.ts +22 -0
  22. package/src/pci/interaction.ts +42 -0
  23. package/src/pci/markup.ts +102 -0
  24. package/src/pci/mount.ts +135 -0
  25. package/src/pci/registry.ts +240 -0
  26. package/src/pci/response.ts +138 -0
  27. package/src/pci/skin.ts +87 -0
  28. package/src/reference-skin/associate.ts +98 -0
  29. package/src/reference-skin/choice.ts +44 -0
  30. package/src/reference-skin/content.ts +30 -0
  31. package/src/reference-skin/drawing.ts +150 -0
  32. package/src/reference-skin/end-attempt.ts +27 -0
  33. package/src/reference-skin/extended-text.ts +35 -0
  34. package/src/reference-skin/gap-match.ts +69 -0
  35. package/src/reference-skin/graphic-associate.ts +123 -0
  36. package/src/reference-skin/graphic-base.ts +142 -0
  37. package/src/reference-skin/graphic-gap-match.ts +143 -0
  38. package/src/reference-skin/graphic-order.ts +76 -0
  39. package/src/reference-skin/hotspot.ts +43 -0
  40. package/src/reference-skin/hottext.ts +42 -0
  41. package/src/reference-skin/index.ts +75 -0
  42. package/src/reference-skin/inline-choice.ts +42 -0
  43. package/src/reference-skin/match.ts +80 -0
  44. package/src/reference-skin/media.ts +74 -0
  45. package/src/reference-skin/order.ts +79 -0
  46. package/src/reference-skin/position-object.ts +84 -0
  47. package/src/reference-skin/select-point.ts +87 -0
  48. package/src/reference-skin/slider.ts +41 -0
  49. package/src/reference-skin/text-entry.ts +31 -0
  50. package/src/reference-skin/upload.ts +46 -0
  51. package/src/response-processing.ts +178 -29
  52. package/src/rp/evaluate.ts +828 -0
  53. package/src/rp/index.ts +30 -0
  54. package/src/rp/interpreter.ts +251 -0
  55. package/src/rp/template-processing.ts +295 -0
  56. package/src/rp/templates.ts +190 -0
  57. package/src/rp/types.ts +161 -0
  58. package/src/rp/values.ts +198 -0
  59. package/src/runtime.ts +474 -28
  60. package/src/store.ts +155 -5
  61. package/src/test/controller.ts +806 -0
  62. package/src/test/index.ts +25 -0
  63. package/src/test/session-store.ts +244 -0
  64. package/src/test/types.ts +203 -0
  65. package/src/types.ts +27 -1
@@ -0,0 +1,104 @@
1
+ /**
2
+ * The graphic interaction family: descriptors share the object (stage image) and
3
+ * hotspot (shape/coords) schemas. Coordinates are numbers in image space, normalized
4
+ * upstream from the QTI coords attribute.
5
+ */
6
+
7
+ import { z } from "zod";
8
+
9
+ import { defineInteraction } from "../runtime";
10
+ import type { ResponseValue } from "../types";
11
+
12
+ const objectSchema = z.object({
13
+ data: z.string().min(1),
14
+ width: z.number().optional(),
15
+ height: z.number().optional(),
16
+ type: z.string().optional(),
17
+ });
18
+
19
+ const hotspotSchema = z.looseObject({
20
+ identifier: z.string().min(1),
21
+ shape: z.string().min(1),
22
+ coords: z.array(z.number()),
23
+ });
24
+
25
+ function nullInitial(): ResponseValue {
26
+ return null;
27
+ }
28
+
29
+ export const hotspotInteraction = defineInteraction({
30
+ kind: "hotspotInteraction",
31
+ schema: z.object({
32
+ kind: z.literal("hotspotInteraction"),
33
+ responseIdentifier: z.string().min(1),
34
+ object: objectSchema,
35
+ hotspotChoices: z.array(hotspotSchema).min(1),
36
+ maxChoices: z.number().int().optional(),
37
+ }),
38
+ scoring: "qti-standard",
39
+ initialResponse: nullInitial,
40
+ });
41
+
42
+ export const graphicOrderInteraction = defineInteraction({
43
+ kind: "graphicOrderInteraction",
44
+ schema: z.object({
45
+ kind: z.literal("graphicOrderInteraction"),
46
+ responseIdentifier: z.string().min(1),
47
+ object: objectSchema,
48
+ hotspotChoices: z.array(hotspotSchema).min(1),
49
+ }),
50
+ scoring: "qti-standard",
51
+ initialResponse: nullInitial,
52
+ });
53
+
54
+ export const graphicAssociateInteraction = defineInteraction({
55
+ kind: "graphicAssociateInteraction",
56
+ schema: z.object({
57
+ kind: z.literal("graphicAssociateInteraction"),
58
+ responseIdentifier: z.string().min(1),
59
+ object: objectSchema,
60
+ associableHotspots: z.array(hotspotSchema).min(2),
61
+ maxAssociations: z.number().int().optional(),
62
+ }),
63
+ scoring: "qti-standard",
64
+ initialResponse: nullInitial,
65
+ });
66
+
67
+ export const graphicGapMatchInteraction = defineInteraction({
68
+ kind: "graphicGapMatchInteraction",
69
+ schema: z.object({
70
+ kind: z.literal("graphicGapMatchInteraction"),
71
+ responseIdentifier: z.string().min(1),
72
+ object: objectSchema,
73
+ gapImgs: z.array(z.looseObject({ identifier: z.string().min(1), object: objectSchema.optional() })).min(1),
74
+ associableHotspots: z.array(hotspotSchema).min(1),
75
+ }),
76
+ scoring: "qti-standard",
77
+ initialResponse: nullInitial,
78
+ });
79
+
80
+ export const selectPointInteraction = defineInteraction({
81
+ kind: "selectPointInteraction",
82
+ schema: z.object({
83
+ kind: z.literal("selectPointInteraction"),
84
+ responseIdentifier: z.string().min(1),
85
+ object: objectSchema,
86
+ maxChoices: z.number().int().optional(),
87
+ }),
88
+ scoring: "qti-standard",
89
+ initialResponse: nullInitial,
90
+ });
91
+
92
+ /** The common single-interaction stage; multi-interaction stages fail validation. */
93
+ export const positionObjectStage = defineInteraction({
94
+ kind: "positionObjectStage",
95
+ schema: z.object({
96
+ kind: z.literal("positionObjectStage"),
97
+ responseIdentifier: z.string().min(1),
98
+ stageObject: objectSchema,
99
+ object: objectSchema,
100
+ maxChoices: z.number().int().optional(),
101
+ }),
102
+ scoring: "qti-standard",
103
+ initialResponse: nullInitial,
104
+ });
@@ -0,0 +1,21 @@
1
+ import { z } from "zod";
2
+
3
+ import { defineInteraction } from "../runtime";
4
+ import type { ResponseValue } from "../types";
5
+
6
+ const hottextInteractionNodeSchema = z.object({
7
+ kind: z.literal("hottextInteraction"),
8
+ responseIdentifier: z.string().min(1),
9
+ maxChoices: z.number().int().optional(),
10
+ // Flow content with `kind: "hottext"` nodes nested anywhere inside it.
11
+ content: z.array(z.looseObject({ kind: z.string().min(1) })).min(1),
12
+ });
13
+
14
+ export const hottextInteraction = defineInteraction({
15
+ kind: "hottextInteraction",
16
+ schema: hottextInteractionNodeSchema,
17
+ scoring: "qti-standard",
18
+ initialResponse(): ResponseValue {
19
+ return null;
20
+ },
21
+ });
@@ -1,16 +1,71 @@
1
1
  import type { InteractionDescriptor } from "../runtime";
2
2
 
3
+ import { associateInteraction } from "./associate";
3
4
  import { choiceInteraction } from "./choice";
5
+ import { drawingInteraction } from "./drawing";
6
+ import { endAttemptInteraction } from "./end-attempt";
7
+ import { extendedTextInteraction } from "./extended-text";
8
+ import { gapMatchInteraction } from "./gap-match";
9
+ import {
10
+ graphicAssociateInteraction,
11
+ graphicGapMatchInteraction,
12
+ graphicOrderInteraction,
13
+ hotspotInteraction,
14
+ positionObjectStage,
15
+ selectPointInteraction,
16
+ } from "./graphic";
17
+ import { hottextInteraction } from "./hottext";
4
18
  import { inlineChoiceInteraction } from "./inline-choice";
19
+ import { matchInteraction } from "./match";
20
+ import { mediaInteraction } from "./media";
21
+ import { orderInteraction } from "./order";
22
+ import { sliderInteraction } from "./slider";
5
23
  import { textEntryInteraction } from "./text-entry";
24
+ import { uploadInteraction } from "./upload";
6
25
 
26
+ export { associateInteraction } from "./associate";
7
27
  export { choiceInteraction } from "./choice";
28
+ export { drawingInteraction } from "./drawing";
29
+ export { endAttemptInteraction } from "./end-attempt";
30
+ export { extendedTextInteraction } from "./extended-text";
31
+ export { gapMatchInteraction } from "./gap-match";
32
+ export {
33
+ graphicAssociateInteraction,
34
+ graphicGapMatchInteraction,
35
+ graphicOrderInteraction,
36
+ hotspotInteraction,
37
+ positionObjectStage,
38
+ selectPointInteraction,
39
+ } from "./graphic";
40
+ export { hottextInteraction } from "./hottext";
8
41
  export { inlineChoiceInteraction } from "./inline-choice";
42
+ export { matchInteraction } from "./match";
43
+ export { mediaInteraction } from "./media";
44
+ export { orderInteraction } from "./order";
45
+ export { sliderInteraction } from "./slider";
9
46
  export { textEntryInteraction } from "./text-entry";
47
+ export { uploadInteraction } from "./upload";
10
48
 
11
- /** The v0 interaction set conform-ed ships; emergent assembles these plus its extensions. */
49
+ /** The interaction set conform-ed ships; consumers assemble these plus their extensions. */
12
50
  export const qtiCoreInteractions: readonly InteractionDescriptor[] = [
51
+ associateInteraction,
13
52
  choiceInteraction,
14
- textEntryInteraction,
53
+ drawingInteraction,
54
+ endAttemptInteraction,
55
+ extendedTextInteraction,
56
+ gapMatchInteraction,
57
+ graphicAssociateInteraction,
58
+ graphicGapMatchInteraction,
59
+ graphicOrderInteraction,
60
+ hotspotInteraction,
61
+ hottextInteraction,
15
62
  inlineChoiceInteraction,
63
+ matchInteraction,
64
+ mediaInteraction,
65
+ orderInteraction,
66
+ positionObjectStage,
67
+ selectPointInteraction,
68
+ sliderInteraction,
69
+ textEntryInteraction,
70
+ uploadInteraction,
16
71
  ];
@@ -0,0 +1,27 @@
1
+ import { z } from "zod";
2
+
3
+ import { defineInteraction } from "../runtime";
4
+ import type { ResponseValue } from "../types";
5
+
6
+ const simpleMatchSetSchema = z.object({
7
+ simpleAssociableChoices: z
8
+ .array(z.looseObject({ identifier: z.string().min(1), matchMax: z.number().int().optional() }))
9
+ .min(1),
10
+ });
11
+
12
+ const matchInteractionNodeSchema = z.object({
13
+ kind: z.literal("matchInteraction"),
14
+ responseIdentifier: z.string().min(1),
15
+ // QTI: exactly two match sets; responses are directedPairs source→target.
16
+ simpleMatchSets: z.array(simpleMatchSetSchema).length(2),
17
+ maxAssociations: z.number().int().optional(),
18
+ });
19
+
20
+ export const matchInteraction = defineInteraction({
21
+ kind: "matchInteraction",
22
+ schema: matchInteractionNodeSchema,
23
+ scoring: "qti-standard",
24
+ initialResponse(): ResponseValue {
25
+ return null;
26
+ },
27
+ });
@@ -0,0 +1,24 @@
1
+ import { z } from "zod";
2
+
3
+ import { defineInteraction } from "../runtime";
4
+ import type { ResponseValue } from "../types";
5
+
6
+ const mediaInteractionNodeSchema = z.object({
7
+ kind: z.literal("mediaInteraction"),
8
+ responseIdentifier: z.string().min(1),
9
+ autostart: z.boolean().optional(),
10
+ minPlays: z.number().int().optional(),
11
+ maxPlays: z.number().int().optional(),
12
+ loop: z.boolean().optional(),
13
+ // Flow content containing the audio/video element the interaction wraps.
14
+ content: z.array(z.looseObject({ kind: z.string().min(1) })).min(1),
15
+ });
16
+
17
+ export const mediaInteraction = defineInteraction({
18
+ kind: "mediaInteraction",
19
+ schema: mediaInteractionNodeSchema,
20
+ scoring: "qti-standard",
21
+ initialResponse(): ResponseValue {
22
+ return null;
23
+ },
24
+ });
@@ -0,0 +1,21 @@
1
+ import { z } from "zod";
2
+
3
+ import { defineInteraction } from "../runtime";
4
+ import type { ResponseValue } from "../types";
5
+
6
+ const orderInteractionNodeSchema = z.object({
7
+ kind: z.literal("orderInteraction"),
8
+ responseIdentifier: z.string().min(1),
9
+ simpleChoices: z.array(z.looseObject({ identifier: z.string().min(1) })).min(1),
10
+ shuffle: z.boolean().optional(),
11
+ orientation: z.enum(["horizontal", "vertical"]).optional(),
12
+ });
13
+
14
+ export const orderInteraction = defineInteraction({
15
+ kind: "orderInteraction",
16
+ schema: orderInteractionNodeSchema,
17
+ scoring: "qti-standard",
18
+ initialResponse(): ResponseValue {
19
+ return null;
20
+ },
21
+ });
@@ -0,0 +1,24 @@
1
+ import { z } from "zod";
2
+
3
+ import { defineInteraction } from "../runtime";
4
+ import type { ResponseValue } from "../types";
5
+
6
+ const sliderInteractionNodeSchema = z.object({
7
+ kind: z.literal("sliderInteraction"),
8
+ responseIdentifier: z.string().min(1),
9
+ lowerBound: z.number(),
10
+ upperBound: z.number(),
11
+ step: z.number().optional(),
12
+ stepLabel: z.boolean().optional(),
13
+ orientation: z.enum(["horizontal", "vertical"]).optional(),
14
+ reverse: z.boolean().optional(),
15
+ });
16
+
17
+ export const sliderInteraction = defineInteraction({
18
+ kind: "sliderInteraction",
19
+ schema: sliderInteractionNodeSchema,
20
+ scoring: "qti-standard",
21
+ initialResponse(): ResponseValue {
22
+ return null;
23
+ },
24
+ });
@@ -0,0 +1,19 @@
1
+ import { z } from "zod";
2
+
3
+ import { defineInteraction } from "../runtime";
4
+ import type { ResponseValue } from "../types";
5
+
6
+ const uploadInteractionNodeSchema = z.object({
7
+ kind: z.literal("uploadInteraction"),
8
+ responseIdentifier: z.string().min(1),
9
+ type: z.string().optional(),
10
+ });
11
+
12
+ export const uploadInteraction = defineInteraction({
13
+ kind: "uploadInteraction",
14
+ schema: uploadInteractionNodeSchema,
15
+ scoring: "qti-standard",
16
+ initialResponse(): ResponseValue {
17
+ return null;
18
+ },
19
+ });