@citolab/qti-components 8.0.0 → 8.0.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.
- package/cdn/index.global.js +1 -1
- package/cdn/index.js +591 -217
- package/dist/base.d.ts +135 -9
- package/dist/{chunk-MJVPNN7W.js → chunk-3AJOQCDU.js} +2 -2
- package/dist/chunk-7HC5SMCU.js +102 -0
- package/dist/chunk-7HC5SMCU.js.map +1 -0
- package/dist/{chunk-MGF5F3S2.js → chunk-CAO4JRLY.js} +2 -2
- package/dist/{chunk-5SJS36BI.js → chunk-F4BNJWYN.js} +1 -1
- package/dist/{chunk-5SJS36BI.js.map → chunk-F4BNJWYN.js.map} +1 -1
- package/dist/{chunk-5QYII4OZ.js → chunk-LVBIQDPM.js} +2 -2
- package/dist/{chunk-W4QZPCNC.js → chunk-QECOPVPO.js} +2 -2
- package/dist/{chunk-LZJHHZQ2.js → chunk-RXGDQDOV.js} +177 -173
- package/dist/chunk-RXGDQDOV.js.map +1 -0
- package/dist/{chunk-KYEZRYO6.js → chunk-XU7HNT4F.js} +4 -4
- package/dist/computed-item.types.d-BKZdSLLJ.d.ts +19 -0
- package/dist/computed.types.d-rKLSPvVG.d.ts +42 -0
- package/dist/config.context.d-BvU9r-Mg.d.ts +91 -0
- package/dist/corrections.d.ts +432 -1
- package/dist/corrections.js +5 -5
- package/dist/elements.d.ts +393 -1
- package/dist/index.d.ts +58 -9
- package/dist/index.js +16 -8
- package/dist/interaction.d-D4MstYRz.d.ts +115 -0
- package/dist/interaction.interface.d-CvjHM2bi.d.ts +46 -0
- package/dist/interactions.d.ts +1569 -1
- package/dist/interactions.js +2 -2
- package/dist/item.css +588 -214
- package/dist/item.d.ts +92 -1
- package/dist/item.js +3 -3
- package/dist/item.types.d-QU7LljEK.d.ts +82 -0
- package/dist/loader.d.ts +22 -1
- package/dist/processing.d.ts +730 -1
- package/dist/qti-components-jsx.d.ts +221 -231
- package/dist/qti-components-jsx.js +1 -0
- package/dist/qti-condition-expression.d-aMvBvpc6.d.ts +8 -0
- package/dist/qti-expression.d-BietT_8b.d.ts +31 -0
- package/dist/qti-feedback.d-DZbad0RN.d.ts +21 -0
- package/dist/qti-rule-base.d-ajOnfGXY.d.ts +16 -0
- package/dist/qti-transform-test.d-BL7GGFJj.d.ts +70 -0
- package/dist/qti.context.d-CejJMlfZ.d.ts +50 -0
- package/dist/response.d-_8y4kjGP.d.ts +106 -0
- package/dist/test.d.ts +699 -1
- package/dist/test.js +11 -3
- package/dist/transformers.d.ts +18 -1
- package/package.json +11 -8
- package/dist/chunk-LZJHHZQ2.js.map +0 -1
- package/dist/chunk-WCQ26LV7.js +0 -102
- package/dist/chunk-WCQ26LV7.js.map +0 -1
- /package/dist/{chunk-MJVPNN7W.js.map → chunk-3AJOQCDU.js.map} +0 -0
- /package/dist/{chunk-MGF5F3S2.js.map → chunk-CAO4JRLY.js.map} +0 -0
- /package/dist/{chunk-5QYII4OZ.js.map → chunk-LVBIQDPM.js.map} +0 -0
- /package/dist/{chunk-W4QZPCNC.js.map → chunk-QECOPVPO.js.map} +0 -0
- /package/dist/{chunk-KYEZRYO6.js.map → chunk-XU7HNT4F.js.map} +0 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Interface for any object that can process QTI rules
|
|
5
|
+
*/
|
|
6
|
+
interface QtiRuleBase {
|
|
7
|
+
process(): any;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Abstract base class for QTI rule DOM elements
|
|
11
|
+
*/
|
|
12
|
+
declare abstract class QtiRuleElement extends LitElement implements QtiRuleBase {
|
|
13
|
+
abstract process(): any;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export { type QtiRuleBase as Q, QtiRuleElement as a };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
interface ModuleResolutionConfig {
|
|
2
|
+
waitSeconds?: number;
|
|
3
|
+
context?: string;
|
|
4
|
+
catchError?: boolean;
|
|
5
|
+
urlArgs?: string;
|
|
6
|
+
paths: {
|
|
7
|
+
[key: string]: string | string[];
|
|
8
|
+
};
|
|
9
|
+
shim?: {
|
|
10
|
+
[key: string]: {
|
|
11
|
+
deps?: string[];
|
|
12
|
+
exports?: string;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
type transformItemApi = {
|
|
18
|
+
load: (uri: string, signal?: AbortSignal) => Promise<transformItemApi>;
|
|
19
|
+
parse: (xmlString: string) => transformItemApi;
|
|
20
|
+
path: (location: string) => transformItemApi;
|
|
21
|
+
fn: (fn: (xmlFragment: XMLDocument) => void) => transformItemApi;
|
|
22
|
+
pciHooks: (uri: string) => transformItemApi;
|
|
23
|
+
configurePci: (baseUrl: string, getModuleResolutionConfig: (baseUrl: string, fileUrl: string) => Promise<ModuleResolutionConfig>, selector?: string) => Promise<transformItemApi>;
|
|
24
|
+
extendElementName: (elementName: string, extend: string) => transformItemApi;
|
|
25
|
+
extendElementsWithClass: (param?: string) => transformItemApi;
|
|
26
|
+
customInteraction: (baseRef: string, baseItem: string) => transformItemApi;
|
|
27
|
+
convertCDATAtoComment: () => transformItemApi;
|
|
28
|
+
shuffleInteractions: (seed?: string | number | null) => transformItemApi;
|
|
29
|
+
stripStyleSheets: () => transformItemApi;
|
|
30
|
+
html: () => string;
|
|
31
|
+
xml: () => string;
|
|
32
|
+
htmlDoc: (registry?: CustomElementRegistry) => DocumentFragment;
|
|
33
|
+
xmlDoc: () => XMLDocument;
|
|
34
|
+
};
|
|
35
|
+
declare const qtiTransformItem: () => transformItemApi;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Returns an object with methods to load, parse and transform QTI tests.
|
|
39
|
+
* @returns An object with methods to load, parse and transform QTI tests.
|
|
40
|
+
* @example
|
|
41
|
+
* const qtiTransformer = qtiTransformTest();
|
|
42
|
+
* await qtiTransformer.load('https://example.com/test.xml');
|
|
43
|
+
* const items = qtiTransformer.items();
|
|
44
|
+
* const html = qtiTransformer.html();
|
|
45
|
+
* const xml = qtiTransformer.xml();
|
|
46
|
+
*/
|
|
47
|
+
type transformTestApi = {
|
|
48
|
+
load: (uri: string, signal?: AbortSignal) => Promise<transformTestApi>;
|
|
49
|
+
parse: (xmlString: string) => transformTestApi;
|
|
50
|
+
path: (location: string) => transformTestApi;
|
|
51
|
+
fn: (fn: (xmlFragment: XMLDocument) => void) => transformTestApi;
|
|
52
|
+
/**
|
|
53
|
+
* Deterministically shuffle the children of every section that carries a
|
|
54
|
+
* <qti-ordering shuffle="true">, honoring fixed items and nested
|
|
55
|
+
* keep-together / visible rules. The same seed reproduces the same order.
|
|
56
|
+
*/
|
|
57
|
+
shuffleOrdering: (seed?: string | number | null) => transformTestApi;
|
|
58
|
+
items: () => {
|
|
59
|
+
identifier: string;
|
|
60
|
+
href: string;
|
|
61
|
+
category: string;
|
|
62
|
+
}[];
|
|
63
|
+
html: () => string;
|
|
64
|
+
xml: () => string;
|
|
65
|
+
htmlDoc: (registry?: CustomElementRegistry) => DocumentFragment;
|
|
66
|
+
xmlDoc: () => XMLDocument;
|
|
67
|
+
};
|
|
68
|
+
declare const qtiTransformTest: () => transformTestApi;
|
|
69
|
+
|
|
70
|
+
export { type ModuleResolutionConfig as M, qtiTransformTest as a, type transformTestApi as b, qtiTransformItem as q, type transformItemApi as t };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A validated deterministic shuffle seed.
|
|
3
|
+
*
|
|
4
|
+
* Branded so that only values verified through {@link isSeed} (or constructed via
|
|
5
|
+
* {@link asSeed}) can be assigned where a seed is expected. This prevents arbitrary
|
|
6
|
+
* strings from silently being used as a seed.
|
|
7
|
+
*
|
|
8
|
+
* A usable seed is a non-empty string of letters, digits and hyphens (e.g. a GUID
|
|
9
|
+
* "N" format like `8f14e45fceea167a5a36dedd4bea2543`, or a readable label like
|
|
10
|
+
* `delivery-2026-06-05`). Whitespace and other characters are rejected.
|
|
11
|
+
*/
|
|
12
|
+
type Seed = string & {
|
|
13
|
+
readonly __seedBrand: 'Seed';
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Runtime type guard that narrows an unknown value to a {@link Seed}.
|
|
17
|
+
* Use this at boundaries (e.g. values coming from XML, a host application or a
|
|
18
|
+
* backend) before treating a string as a seed.
|
|
19
|
+
*/
|
|
20
|
+
declare const isSeed: (value: unknown) => value is Seed;
|
|
21
|
+
/**
|
|
22
|
+
* Validates and brands a value as a {@link Seed}, returning `undefined` when the
|
|
23
|
+
* value is missing or not in a usable seed format.
|
|
24
|
+
*/
|
|
25
|
+
declare const asSeed: (value: unknown) => Seed | undefined;
|
|
26
|
+
type QtiContextType = {
|
|
27
|
+
testIdentifier: string;
|
|
28
|
+
candidateIdentifier: string;
|
|
29
|
+
environmentIdentifier: string;
|
|
30
|
+
/**
|
|
31
|
+
* Optional deterministic seed for shuffling.
|
|
32
|
+
*
|
|
33
|
+
* When set, it is used to reproduce a stable shuffle order across reloads/restarts:
|
|
34
|
+
* - test ordering in `test-container` (`<qti-ordering shuffle="true">`),
|
|
35
|
+
* - seeded item interaction shuffling in `item-container` and during test navigation.
|
|
36
|
+
*
|
|
37
|
+
* Typically generated once per session by the host/backend and passed in via
|
|
38
|
+
* `QTI_CONTEXT`. When omitted, each item falls back to its own URI-derived seed.
|
|
39
|
+
*/
|
|
40
|
+
seed?: Seed;
|
|
41
|
+
[key: string]: string | string[];
|
|
42
|
+
};
|
|
43
|
+
interface QtiContext {
|
|
44
|
+
QTI_CONTEXT: QtiContextType;
|
|
45
|
+
}
|
|
46
|
+
declare const qtiContext: {
|
|
47
|
+
__context__: Readonly<QtiContext>;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export { type QtiContext as Q, type Seed as S, type QtiContextType as a, asSeed as b, isSeed as i, qtiContext as q };
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical `response="..."` / `correct-response="..."` attribute codec.
|
|
3
|
+
*
|
|
4
|
+
* Authors put a single string on an interaction element. This module is the
|
|
5
|
+
* single source of truth for how that string parses into the runtime's
|
|
6
|
+
* internal value AND how an editor serializes the internal value back to the
|
|
7
|
+
* attribute. Both `@qti-components/*` interactions and `@citolab/prose-qti`
|
|
8
|
+
* (the editor) import from here — no per-codebase parsers, no drift.
|
|
9
|
+
*
|
|
10
|
+
* The two attributes share the same grammar; the codec is agnostic about
|
|
11
|
+
* which of them is being parsed.
|
|
12
|
+
*
|
|
13
|
+
* ---
|
|
14
|
+
*
|
|
15
|
+
* Format reference (per interaction):
|
|
16
|
+
*
|
|
17
|
+
* | Interaction | base-type | cardinality | attribute value |
|
|
18
|
+
* |----------------------|---------------|----------------------|---------------------------|
|
|
19
|
+
* | choice | identifier | single / multiple | "A" / "A,B,C" |
|
|
20
|
+
* | inline-choice | identifier | single | "Y" |
|
|
21
|
+
* | hottext | identifier | single / multiple | "h1" / "h1,h2" |
|
|
22
|
+
* | hotspot | identifier | single / multiple | "spot1" / "spot1,spot2" |
|
|
23
|
+
* | order | identifier | ordered | "a,b,c" (order matters) |
|
|
24
|
+
* | graphic-order | identifier | ordered | "spot1,spot2,spot3" |
|
|
25
|
+
* | match | directedPair | multiple | "src1 tgt1,src2 tgt2" |
|
|
26
|
+
* | associate | directedPair | multiple | "A B,C D" |
|
|
27
|
+
* | gap-match | directedPair | multiple | "gtext1 gap1,..." |
|
|
28
|
+
* | graphic-associate | directedPair | multiple | "spot1 spot2,..." |
|
|
29
|
+
* | graphic-gap-match | directedPair | multiple | "gimg1 spot1,..." |
|
|
30
|
+
* | select-point | point | single / multiple | "100 150" / "100 150,…" |
|
|
31
|
+
* | slider | integer | single | "50" |
|
|
32
|
+
* | text-entry | string | single | "paris" |
|
|
33
|
+
*
|
|
34
|
+
* Rules:
|
|
35
|
+
* - Comma `,` separates VALUES (different identifiers / pairs / points).
|
|
36
|
+
* - Space ` ` separates PARTS within one value (pair members or point coords).
|
|
37
|
+
* - Each value is trimmed on parse.
|
|
38
|
+
* - No escape mechanism. Identifiers that contain commas cannot round-trip.
|
|
39
|
+
*/
|
|
40
|
+
/** Canonical parsed value of a `response` / `correct-response` attribute. */
|
|
41
|
+
type ResponseValue = string | string[] | null;
|
|
42
|
+
/** Identifier literal — opaque QTI identifier (e.g. `"choice1"`). */
|
|
43
|
+
type Identifier = string;
|
|
44
|
+
/** Directed pair literal — `"sourceId targetId"`. Used by match / associate / gap-match. */
|
|
45
|
+
type DirectedPair = `${string} ${string}`;
|
|
46
|
+
/** Point literal — `"x y"` integer coordinates. Used by select-point / graphic-*. */
|
|
47
|
+
type Point = `${number} ${number}`;
|
|
48
|
+
/**
|
|
49
|
+
* Parse a raw `response` / `correct-response` attribute string into the
|
|
50
|
+
* canonical value.
|
|
51
|
+
*
|
|
52
|
+
* - `null` / `undefined` / empty → `null`
|
|
53
|
+
* - no comma → trimmed string
|
|
54
|
+
* - one or more commas → trimmed array (single-element collapses to a string)
|
|
55
|
+
*/
|
|
56
|
+
declare function parseResponseAttribute(raw: string | null | undefined): ResponseValue;
|
|
57
|
+
/**
|
|
58
|
+
* Serialize a canonical value back to the attribute string. Returns `null` for
|
|
59
|
+
* empty inputs so a Lit `@property({ reflect: true })` drops the attribute.
|
|
60
|
+
*/
|
|
61
|
+
declare function serializeResponseAttribute(value: ResponseValue): string | null;
|
|
62
|
+
/**
|
|
63
|
+
* Iterate over the comma-separated entries in a response value, regardless of
|
|
64
|
+
* whether the caller has the raw string, the parsed string, or a string[].
|
|
65
|
+
* Yields trimmed non-empty entries.
|
|
66
|
+
*/
|
|
67
|
+
declare function iterResponseValues(raw: ResponseValue): Generator<string>;
|
|
68
|
+
/** Parse a directed-pair value into `{ source, target }`. Throws on malformed input. */
|
|
69
|
+
declare function parsePair(value: string): {
|
|
70
|
+
source: string;
|
|
71
|
+
target: string;
|
|
72
|
+
};
|
|
73
|
+
/** Serialize a directed pair to canonical `"source target"` form. */
|
|
74
|
+
declare function serializePair(source: string, target: string): DirectedPair;
|
|
75
|
+
/** Parse a point value into `{ x, y }`. Throws on malformed input. */
|
|
76
|
+
declare function parsePoint(value: string): {
|
|
77
|
+
x: number;
|
|
78
|
+
y: number;
|
|
79
|
+
};
|
|
80
|
+
/** Serialize a point to canonical `"x y"` form. */
|
|
81
|
+
declare function serializePoint(x: number, y: number): Point;
|
|
82
|
+
/**
|
|
83
|
+
* Ready-to-use Lit `converter` for `response` / `correct-response` attributes.
|
|
84
|
+
* Assign to the `converter` option:
|
|
85
|
+
*
|
|
86
|
+
* @property({ attribute: 'response', converter: responseAttributeConverter({ emptyAs: [] }) })
|
|
87
|
+
*
|
|
88
|
+
* `emptyAs` picks the sentinel returned when the attribute is absent / blank.
|
|
89
|
+
* Three sentinels exist across the codebase — match the one your call site
|
|
90
|
+
* already uses. Future work may normalize to a single sentinel.
|
|
91
|
+
*
|
|
92
|
+
* - '' (empty string) — ChoicesMixin convention
|
|
93
|
+
* - [] — DragDropSlottedMixin / graphic-associate convention
|
|
94
|
+
* - null — base interaction / select-point convention
|
|
95
|
+
*
|
|
96
|
+
* On the serialize side, the `emptyAs` value roundtrips back to `null` so a
|
|
97
|
+
* `reflect: true` property drops the attribute rather than emitting `""`.
|
|
98
|
+
*/
|
|
99
|
+
declare function responseAttributeConverter<E extends '' | null | readonly unknown[]>(opts: {
|
|
100
|
+
emptyAs: E;
|
|
101
|
+
}): {
|
|
102
|
+
fromAttribute: (value: string | null) => ResponseValue | E;
|
|
103
|
+
toAttribute: (value: ResponseValue | E) => string | null;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export { type DirectedPair as D, type Identifier as I, type Point as P, type ResponseValue as R, parsePoint as a, parseResponseAttribute as b, serializePoint as c, serializeResponseAttribute as d, iterResponseValues as i, parsePair as p, responseAttributeConverter as r, serializePair as s };
|