@citolab/qti-components 8.0.0 → 8.0.2

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 (77) hide show
  1. package/cdn/index.global.js +1 -1
  2. package/cdn/index.js +690 -316
  3. package/dist/base.d.ts +135 -9
  4. package/dist/base.js +1 -1
  5. package/dist/chunk-4DB4SC5K.js +100 -0
  6. package/dist/chunk-4DB4SC5K.js.map +1 -0
  7. package/dist/{chunk-WVVMNF74.js → chunk-7AVWRQIS.js} +188 -160
  8. package/dist/{chunk-WVVMNF74.js.map → chunk-7AVWRQIS.js.map} +1 -1
  9. package/dist/{chunk-MGF5F3S2.js → chunk-BQFWCZFH.js} +2 -2
  10. package/dist/{chunk-5QYII4OZ.js → chunk-CK7AV2UJ.js} +147 -101
  11. package/dist/chunk-CK7AV2UJ.js.map +1 -0
  12. package/dist/chunk-G6GFQDVN.js +7 -0
  13. package/dist/chunk-G6GFQDVN.js.map +1 -0
  14. package/dist/{chunk-LZJHHZQ2.js → chunk-HBSWJC3B.js} +643 -553
  15. package/dist/chunk-HBSWJC3B.js.map +1 -0
  16. package/dist/chunk-HQESINXH.js +834 -0
  17. package/dist/chunk-HQESINXH.js.map +1 -0
  18. package/dist/{chunk-KYEZRYO6.js → chunk-J5SQLKNP.js} +145 -119
  19. package/dist/{chunk-KYEZRYO6.js.map → chunk-J5SQLKNP.js.map} +1 -1
  20. package/dist/{chunk-V5G7X53Y.js → chunk-NJQHUUTN.js} +2 -2
  21. package/dist/{chunk-W4QZPCNC.js → chunk-RSVRS5AK.js} +59 -58
  22. package/dist/chunk-RSVRS5AK.js.map +1 -0
  23. package/dist/{chunk-5SJS36BI.js → chunk-TWPXES3S.js} +642 -673
  24. package/dist/chunk-TWPXES3S.js.map +1 -0
  25. package/dist/{chunk-NA2N2WSG.js → chunk-VAE6HBKR.js} +176 -152
  26. package/dist/{chunk-NA2N2WSG.js.map → chunk-VAE6HBKR.js.map} +1 -1
  27. package/dist/{chunk-MJVPNN7W.js → chunk-ZII6M3SN.js} +2 -2
  28. package/dist/computed-item.types.d-BKZdSLLJ.d.ts +19 -0
  29. package/dist/computed.types.d-DpKIYO6e.d.ts +44 -0
  30. package/dist/config.context.d-BvU9r-Mg.d.ts +91 -0
  31. package/dist/corrections.d.ts +415 -1
  32. package/dist/corrections.js +8 -9
  33. package/dist/elements.d.ts +393 -1
  34. package/dist/elements.js +4 -5
  35. package/dist/index.d.ts +27 -9
  36. package/dist/index.js +21 -14
  37. package/dist/interaction.d-CJiMv8H7.d.ts +126 -0
  38. package/dist/interaction.interface.d-CvjHM2bi.d.ts +46 -0
  39. package/dist/interactions.d.ts +281 -1
  40. package/dist/interactions.js +4 -5
  41. package/dist/item.css +588 -214
  42. package/dist/item.d.ts +92 -1
  43. package/dist/item.js +5 -5
  44. package/dist/item.types.d-QU7LljEK.d.ts +82 -0
  45. package/dist/loader.d.ts +22 -1
  46. package/dist/processing.d.ts +730 -1
  47. package/dist/processing.js +2 -2
  48. package/dist/qti-components-jsx.d.ts +854 -844
  49. package/dist/qti-components-jsx.js +1 -0
  50. package/dist/qti-condition-expression.d-aMvBvpc6.d.ts +8 -0
  51. package/dist/qti-expression.d-BietT_8b.d.ts +31 -0
  52. package/dist/qti-feedback.d-DZbad0RN.d.ts +21 -0
  53. package/dist/qti-rule-base.d-ajOnfGXY.d.ts +16 -0
  54. package/dist/qti-test.d-_YAlhDbt.d.ts +702 -0
  55. package/dist/qti-text-entry-interaction.d-BGdfV9qG.d.ts +1567 -0
  56. package/dist/qti-transform-test.d-BL7GGFJj.d.ts +70 -0
  57. package/dist/qti.context.d-CejJMlfZ.d.ts +50 -0
  58. package/dist/response.d-_8y4kjGP.d.ts +106 -0
  59. package/dist/test.d.ts +32 -1
  60. package/dist/test.js +14 -7
  61. package/dist/transformers.d.ts +18 -1
  62. package/package.json +15 -11
  63. package/dist/chunk-5QYII4OZ.js.map +0 -1
  64. package/dist/chunk-5SJS36BI.js.map +0 -1
  65. package/dist/chunk-64XSIBGO.js +0 -241
  66. package/dist/chunk-64XSIBGO.js.map +0 -1
  67. package/dist/chunk-H3J7LFRO.js +0 -2243
  68. package/dist/chunk-H3J7LFRO.js.map +0 -1
  69. package/dist/chunk-LZJHHZQ2.js.map +0 -1
  70. package/dist/chunk-W4QZPCNC.js.map +0 -1
  71. package/dist/chunk-WCQ26LV7.js +0 -102
  72. package/dist/chunk-WCQ26LV7.js.map +0 -1
  73. package/dist/chunk-X3E5HXG2.js +0 -20
  74. package/dist/chunk-X3E5HXG2.js.map +0 -1
  75. /package/dist/{chunk-MGF5F3S2.js.map → chunk-BQFWCZFH.js.map} +0 -0
  76. /package/dist/{chunk-V5G7X53Y.js.map → chunk-NJQHUUTN.js.map} +0 -0
  77. /package/dist/{chunk-MJVPNN7W.js.map → chunk-ZII6M3SN.js.map} +0 -0
@@ -0,0 +1,1567 @@
1
+ import * as lit from 'lit';
2
+ import { LitElement, CSSResultGroup, PropertyValues } from 'lit';
3
+ import { I as Interaction } from './interaction.d-CJiMv8H7.js';
4
+ import { V as ValidatableInteraction } from './interaction.interface.d-CvjHM2bi.js';
5
+ import { C as ConfigContext } from './config.context.d-BvU9r-Mg.js';
6
+ import { B as BaseType, a as Cardinality, I as ItemContext, Q as QtiAreaMapEntry } from './item.types.d-QU7LljEK.js';
7
+ import { Q as QtiContext } from './qti.context.d-CejJMlfZ.js';
8
+ import * as lit_directives_ref_js from 'lit/directives/ref.js';
9
+
10
+ /**
11
+ * A drop target positioned over an image. Like `qti-gap`, it renders the chips it holds from
12
+ * `dragDropContext` rather than having them appended into it.
13
+ *
14
+ * @csspart drop - The region a chip lands in.
15
+ */
16
+ declare class QtiAssociableHotspot extends LitElement {
17
+ static styles: CSSResultGroup;
18
+ /** Carries `:state(filled)` while the hotspot holds a chip. */
19
+ internals: ElementInternals;
20
+ /** Opt-in marker read by `DragDropSlottedMixin`; see qti-gap. */
21
+ readonly acceptsDeclarativeDrops = true;
22
+ identifier: string;
23
+ private _dragDrop?;
24
+ /** The chips this hotspot holds. Stable node references, cloned once at drop time. */
25
+ get drags(): readonly HTMLElement[];
26
+ connectedCallback(): void;
27
+ render(): lit.TemplateResult<1>;
28
+ }
29
+ declare global {
30
+ interface HTMLElementTagNameMap {
31
+ 'qti-associable-hotspot': QtiAssociableHotspot;
32
+ }
33
+ }
34
+
35
+ /**
36
+ * A gap in the prose, and the first drop target to render its own chips.
37
+ *
38
+ * The interaction owns placement and publishes it on `dragDropContext`; this element subscribes and
39
+ * renders what it holds. Nothing appends into it. That inverts the old flow, where `handleDrop` did
40
+ * `cloneNode` + `appendChild` and the response was recovered afterwards by reading the DOM back
41
+ * out — which is why placement and the response could ever disagree at all.
42
+ *
43
+ * The chips land in this shadow root rather than in the light DOM, so a theme reaches them as
44
+ * `::part(drag)` — a bare `::part()` matches in any shadow root — instead of by tag. The gap's own
45
+ * `:state(filled)` says whether it holds anything.
46
+ *
47
+ * @customElement qti-gap
48
+ *
49
+ * @attr {string} identifier - Required. Value recorded as the gap side of the response pair.
50
+ * @attr {number} [match-max=1] - How many tokens this gap can hold; `0` means unlimited. Read
51
+ * from the DOM by the drag-drop mixin.
52
+ * @attr {number} [match-min=0] - Minimum tokens this gap must hold.
53
+ * @attr {boolean} [required=false] - Not implemented. Whether this gap must be filled for the
54
+ * response to be valid.
55
+ * @attr {string} template-identifier - Not implemented. Identifier of a template variable
56
+ * controlling this gap's visibility.
57
+ * @attr {'show'|'hide'} [show-hide=show] - Not implemented. How `template-identifier` controls
58
+ * visibility.
59
+ *
60
+ * @csspart drop - The region a chip lands in. Reserves the widest chip's box; see qti-gap.styles.
61
+ */
62
+ declare class QtiGap extends LitElement {
63
+ static styles: CSSResultGroup;
64
+ /** Carries `:state(filled)` while the gap holds a chip. */
65
+ internals: ElementInternals;
66
+ /**
67
+ * Opt-in marker, read by `DragDropSlottedMixin`. While this is true the interaction keeps this
68
+ * target's chips in its placement map and never touches this element's children.
69
+ */
70
+ readonly acceptsDeclarativeDrops = true;
71
+ tabindex: number | undefined;
72
+ identifier: string;
73
+ private _dragDrop?;
74
+ /** The chips this gap holds. Stable node references, cloned once at drop time by the interaction. */
75
+ get drags(): readonly HTMLElement[];
76
+ render(): lit.TemplateResult<1>;
77
+ }
78
+ declare global {
79
+ interface HTMLElementTagNameMap {
80
+ 'qti-gap': QtiGap;
81
+ }
82
+ }
83
+
84
+ declare class QtiGapImg extends LitElement {
85
+ static styles: CSSResultGroup;
86
+ tabindex: number | undefined;
87
+ /**
88
+ * `qti-gap-img` is a draggable chip, so it needs ElementInternals to carry the drag states
89
+ * (`dragging`, `placeholder`). It works without a shadow root.
90
+ *
91
+ * NOTE: this element never calls `super.connectedCallback()`, so Lit never enables updating
92
+ * and it has no shadow root — which makes `qti-gap-img.styles.ts` dead code. Fixing that means
93
+ * adding a `<slot>` to a `render()` first, otherwise the authored `<img>` child disappears.
94
+ */
95
+ internals: ElementInternals;
96
+ connectedCallback(): void;
97
+ }
98
+ declare global {
99
+ interface HTMLElementTagNameMap {
100
+ 'qti-gap-img': QtiGapImg;
101
+ }
102
+ }
103
+
104
+ declare const QtiHotspotChoice_base: (abstract new (...args: any[]) => ActiveElementMixinInterface) & typeof LitElement;
105
+ declare class QtiHotspotChoice extends QtiHotspotChoice_base {
106
+ static styles: CSSResultGroup;
107
+ order: number;
108
+ }
109
+ declare global {
110
+ interface HTMLElementTagNameMap {
111
+ 'qti-hotspot-choice': QtiHotspotChoice;
112
+ }
113
+ }
114
+
115
+ declare const QtiHottext_base: (abstract new (...args: any[]) => ActiveElementMixinInterface) & typeof LitElement;
116
+ /**
117
+ * A selectable span of text inside `qti-hottext-interaction`.
118
+ *
119
+ * @customElement qti-hottext
120
+ *
121
+ * @attr {string} identifier - Required. Value recorded in the response when this span is
122
+ * selected.
123
+ * @attr {string} template-identifier - Not implemented. Identifier of a template variable
124
+ * controlling this span's visibility.
125
+ * @attr {'show'|'hide'} [show-hide=show] - Not implemented. How `template-identifier` controls
126
+ * visibility.
127
+ */
128
+ declare class QtiHottext extends QtiHottext_base {
129
+ static styles: CSSResultGroup;
130
+ render(): lit.TemplateResult<1>;
131
+ }
132
+ declare global {
133
+ interface HTMLElementTagNameMap {
134
+ 'qti-hottext': QtiHottext;
135
+ }
136
+ }
137
+
138
+ declare class QtiPrompt extends LitElement {
139
+ static styles: CSSResultGroup;
140
+ render(): lit.TemplateResult<1>;
141
+ connectedCallback(): void;
142
+ }
143
+ declare global {
144
+ interface HTMLElementTagNameMap {
145
+ 'qti-prompt': QtiPrompt;
146
+ }
147
+ }
148
+
149
+ declare const QtiSimpleAssociableChoice_base: (abstract new (...args: any[]) => ActiveElementMixinInterface) & typeof LitElement;
150
+ /**
151
+ * A choice in one of the two match sets of `qti-match-interaction`, or in
152
+ * `qti-associate-interaction`.
153
+ *
154
+ * @customElement qti-simple-associable-choice
155
+ *
156
+ * @attr {string} identifier - Required. Value recorded in the response pair when this choice
157
+ * participates in an association.
158
+ * @attr {number} [match-max=1] - How many associations this choice may take part in; `0` means
159
+ * unlimited. On a target this is its capacity — the bucket size in a sorting item.
160
+ * @attr {number} [match-min=0] - Minimum associations this choice must take part in.
161
+ * @attr {boolean} [fixed=false] - Pins this choice in place when the enclosing interaction is
162
+ * shuffled.
163
+ * @attr {string} template-identifier - Not implemented. Identifier of a template variable
164
+ * controlling this choice's visibility.
165
+ * @attr {'show'|'hide'} [show-hide=show] - Not implemented. How `template-identifier` controls
166
+ * visibility.
167
+ */
168
+ declare class QtiSimpleAssociableChoice extends QtiSimpleAssociableChoice_base {
169
+ static styles: CSSResultGroup;
170
+ /** the minimal number of selections a candidate must make */
171
+ matchMin: number;
172
+ /** the maximum number of selections a candidate must make, the other options will be disabled when max options is checked */
173
+ matchMax: number;
174
+ fixed: boolean;
175
+ connectedCallback(): void;
176
+ /** Opt-in marker read by `DragDropSlottedMixin`; see qti-gap. */
177
+ readonly acceptsDeclarativeDrops = true;
178
+ private _dragDrop?;
179
+ /** The chips this choice holds when it acts as a drop target (match-interaction's second set). */
180
+ get drags(): readonly HTMLElement[];
181
+ render(): lit.TemplateResult<1>;
182
+ }
183
+ declare global {
184
+ interface HTMLElementTagNameMap {
185
+ 'qti-simple-associable-choice': QtiSimpleAssociableChoice;
186
+ }
187
+ }
188
+
189
+ declare const QtiSimpleChoice_base: (abstract new (...args: any[]) => ActiveElementMixinInterface) & typeof LitElement;
190
+ /**
191
+ * A choice, used by `qti-choice-interaction` and `qti-order-interaction`.
192
+ *
193
+ * The `control` part is one box whose *role* is carried by state, not by its name: a radio
194
+ * circle under `:state(radio)`, a checkbox square under `:state(checkbox)`, and a drag grip
195
+ * when the choice is draggable. Style it as `qti-simple-choice::part(control)`.
196
+ *
197
+ * @customElement qti-simple-choice
198
+ *
199
+ * @attr {string} identifier - Required. Value recorded in the response when this choice is
200
+ * selected, or its position when used for ordering.
201
+ * @attr {boolean} [fixed=false] - Pins this choice in place when the enclosing interaction is
202
+ * shuffled.
203
+ * @attr {string} template-identifier - Identifier of a template variable controlling this
204
+ * choice's visibility.
205
+ * @attr {'show'|'hide'} [show-hide=show] - How `template-identifier` controls visibility.
206
+ *
207
+ * @csspart control - The box before the label (radio / checkbox / drag grip).
208
+ * @csspart control-mark - The mark inside the box (inner dot / checkmark).
209
+ * @csspart label - The default slot holding the choice content.
210
+ * @csspart marker - The order-number badge, when `marker` is set.
211
+ */
212
+ declare class QtiSimpleChoice extends QtiSimpleChoice_base {
213
+ static styles: CSSResultGroup;
214
+ static shadowRootOptions: ShadowRootInit;
215
+ templateIdentifier: string | null;
216
+ showHide: string | null;
217
+ fixed: boolean;
218
+ marker: string;
219
+ get checked(): boolean;
220
+ render(): lit.TemplateResult<1>;
221
+ }
222
+ declare global {
223
+ interface HTMLElementTagNameMap {
224
+ 'qti-simple-choice': QtiSimpleChoice;
225
+ }
226
+ }
227
+
228
+ /**
229
+ * What each drop target currently holds, published by the drag-drop interaction.
230
+ *
231
+ * Today this is *derived* from the DOM in one place (`DragDropSlottedMixin`), replacing nine
232
+ * separate `querySelectorAll` readbacks scattered across capacity checks, association counts and
233
+ * response serialisation. It is the seam for the next step: once drop targets render their own
234
+ * chips from this context, the map becomes authoritative and the DOM becomes derived from it.
235
+ *
236
+ * Provided by the `qti-*-interaction`, never by `qti-assessment-item` - interactions must work
237
+ * standalone. Consumers read `this.ctx?.dragsByTarget?.[id] ?? []`.
238
+ *
239
+ * Reassign, never mutate: an in-place change does not notify consumers.
240
+ */
241
+ interface DragDropState {
242
+ /**
243
+ * Target identifier -> the drag identifiers it holds, in DOM order.
244
+ * Matched with the interaction's `draggablesSelector`, which is what the response is built from.
245
+ */
246
+ readonly dragsByTarget: Readonly<Record<string, readonly string[]>>;
247
+ /**
248
+ * Target identifier -> how many chips it holds for capacity purposes.
249
+ *
250
+ * Deliberately *not* `dragsByTarget[id].length`. Capacity counts
251
+ * `max(draggablesSelector matches, [qti-draggable] matches)`, because a dropped clone may not
252
+ * match the interaction's structural selector (match-interaction's nested choices do; a bare
253
+ * clone elsewhere may only carry the attribute). Response serialisation uses the selector
254
+ * only. Collapsing the two would silently change `matchMax` behaviour.
255
+ */
256
+ readonly countByTarget: Readonly<Record<string, number>>;
257
+ /**
258
+ * Target identifier -> the chip nodes it holds, for targets that render their own chips.
259
+ *
260
+ * This is the authoritative half. A target that opts in (`acceptsDeclarativeDrops`) renders
261
+ * `repeat(nodesByTarget[id])` into its own shadow root, and the interaction never appends into
262
+ * it. The nodes are cloned **once, when the drop happens**, and the same node reference is
263
+ * passed on every render -- Lit renders a `Node` by reference, so a stable node is moved, never
264
+ * recreated. Cloning inside `render()` would mint a new element per update: focus loss,
265
+ * restarted transitions, a half-built shadow root.
266
+ *
267
+ * Today it is still *derived* from the DOM alongside `dragsByTarget`. It becomes authoritative
268
+ * when the first target opts in to rendering its own chips.
269
+ */
270
+ readonly nodesByTarget: Readonly<Record<string, readonly HTMLElement[]>>;
271
+ }
272
+
273
+ interface ChoiceInterface {
274
+ identifier: string;
275
+ disabled: boolean;
276
+ readonly: boolean;
277
+ }
278
+ /**
279
+ * A mixin that adds choice functionality to a LitElement-based class.
280
+ * It dispatches events with a custom `type` and handles selection logic.
281
+ *
282
+ * @param Base - The base class to extend.
283
+ * @param type - The type of the choice, used in event names.
284
+ * @returns A new class extending the base class with choice functionality.
285
+ */
286
+ interface ActiveElementMixinInterface {
287
+ identifier: string;
288
+ tabIndex: number;
289
+ disabled: boolean;
290
+ readonly: boolean;
291
+ internals: ElementInternals;
292
+ }
293
+
294
+ type Choice = HTMLElement & ChoiceInterface & {
295
+ internals: ElementInternals;
296
+ };
297
+ interface ChoicesInterface extends ValidatableInteraction {
298
+ minChoices: number;
299
+ maxChoices: number;
300
+ value: string | null;
301
+ response: string | string[] | null;
302
+ }
303
+
304
+ /** The elements a measurement pass looks at. */
305
+ interface DropzoneAutoSizeTargets {
306
+ /** Measured. The largest of these decides the reservation. */
307
+ draggables: HTMLElement[];
308
+ /** Not measured — only their presence gates the pass (nothing to reserve for, nothing to do). */
309
+ droppables: HTMLElement[];
310
+ /** The chip banks, which get a matching `min-height` so an emptied bank does not collapse. */
311
+ dragContainers: HTMLElement[];
312
+ }
313
+ type DropzoneAutoSize = LitElement & {
314
+ autoSizeDropzones: boolean;
315
+ /**
316
+ * False when something else owns the width axis — see the class below.
317
+ *
318
+ * Declared as an accessor, not a `readonly` property. The class implements it as a getter and
319
+ * `DragDropSlottedMixin` overrides it with another getter; a property here makes that override a
320
+ * TS2611 ("defined as a property in the base, overridden as an accessor").
321
+ */
322
+ get autoSizeDropzoneWidth(): boolean;
323
+ updateMinDimensionsForDropZones(): void;
324
+ /** Overridable hooks — see the class below. Public because a subclass has to be able to say
325
+ * `override`, which the house style already does for `afterCache` and `isDragDropEnabled`. */
326
+ collectAutoSizeTargets(): DropzoneAutoSizeTargets;
327
+ dropzonePropertyTarget(): HTMLElement;
328
+ };
329
+
330
+ type MenuAutoSize = LitElement & {
331
+ updateMenuWidth(): void;
332
+ shouldAutoSizeMenu(): boolean;
333
+ menuAutoSizeExtraWidth(): number;
334
+ menuAutoSizePropertyTarget(): HTMLElement | null;
335
+ menuAutoSizeRows(): HTMLElement[];
336
+ withMenuMeasurable<T>(measure: () => T): T;
337
+ };
338
+
339
+ declare const QtiInlineChoice_base: (abstract new (...args: any[]) => ActiveElementMixinInterface) & typeof LitElement;
340
+ /**
341
+ * An option in the dropdown of `qti-inline-choice-interaction`.
342
+ *
343
+ * @customElement qti-inline-choice
344
+ *
345
+ * @attr {string} identifier - Required. Value recorded in the response when this option is
346
+ * selected.
347
+ * @attr {boolean} [fixed=false] - Pins this option in place when the interaction is shuffled.
348
+ * @attr {string} template-identifier - Not implemented. Identifier of a template variable
349
+ * controlling this option's visibility.
350
+ * @attr {'show'|'hide'} [show-hide=show] - Not implemented. How `template-identifier` controls
351
+ * visibility.
352
+ */
353
+ declare class QtiInlineChoice extends QtiInlineChoice_base {
354
+ #private;
355
+ static styles: CSSResultGroup;
356
+ identifier: string;
357
+ connectedCallback(): void;
358
+ disconnectedCallback(): void;
359
+ render(): lit.TemplateResult<1>;
360
+ }
361
+ declare global {
362
+ interface HTMLElementTagNameMap {
363
+ 'qti-inline-choice': QtiInlineChoice;
364
+ }
365
+ }
366
+
367
+ declare const QtiGapText_base: (abstract new (...args: any[]) => ActiveElementMixinInterface) & typeof LitElement;
368
+ /**
369
+ * A draggable text token that fills a `qti-gap` inside `qti-gap-match-interaction`.
370
+ *
371
+ * @customElement qti-gap-text
372
+ *
373
+ * @attr {string} identifier - Required. Value recorded in the response pair when this token is
374
+ * placed into a gap.
375
+ * @attr {number} [match-max=1] - How many gaps this token may fill; `0` means unlimited.
376
+ * Read from the DOM by the drag-drop mixin.
377
+ * @attr {number} [match-min=0] - Minimum gaps this token must fill.
378
+ * @attr {boolean} [fixed=false] - Pins this token in place when the interaction is shuffled.
379
+ * @attr {string} template-identifier - Not implemented. Identifier of a template variable
380
+ * controlling this token's visibility.
381
+ * @attr {'show'|'hide'} [show-hide=show] - Not implemented. How `template-identifier` controls
382
+ * visibility.
383
+ */
384
+ declare class QtiGapText extends QtiGapText_base {
385
+ static styles: CSSResultGroup;
386
+ tabindex: number | undefined;
387
+ connectedCallback(): void;
388
+ render(): lit.TemplateResult<1>;
389
+ }
390
+ declare global {
391
+ interface HTMLElementTagNameMap {
392
+ 'qti-gap-text': QtiGapText;
393
+ }
394
+ }
395
+
396
+ /**
397
+ * Collision detection algorithms for drag and drop interactions
398
+ * Based on dnd-kit collision detection strategies
399
+ */
400
+ type CollisionDetectionAlgorithm = 'pointerWithin' | 'rectangleIntersection' | 'closestCenter' | 'closestCorners' | 'closestCornersWithInventoryPriority';
401
+
402
+ type DragDropCore = Interaction & {
403
+ isDragDropEnabled(): boolean;
404
+ trackedDraggables: HTMLElement[];
405
+ trackedDroppables: HTMLElement[];
406
+ trackedDragContainers: HTMLElement[];
407
+ allDropzones: HTMLElement[];
408
+ dragState: DragState;
409
+ collisionDetectionAlgorithm: CollisionDetectionAlgorithm;
410
+ get response(): string | string[] | null;
411
+ set response(value: string | string[] | null);
412
+ saveResponse(value?: string | string[]): void;
413
+ validate(): boolean;
414
+ reportValidity(): boolean;
415
+ cacheInteractiveElements(): void;
416
+ resetDragState(): void;
417
+ afterCache(): void;
418
+ removeChipFromDroppable(droppable: HTMLElement | null, chip: HTMLElement): void;
419
+ allowDrop(draggable: HTMLElement, droppable: HTMLElement): boolean;
420
+ handleDrop(draggable: HTMLElement, droppable: HTMLElement): void;
421
+ handleInvalidDrop(dragSource: HTMLElement | null): void;
422
+ initiateDrag(dragElement: HTMLElement, startX: number, startY: number, inputType: 'mouse' | 'touch', eventSource?: 'pointer' | 'mouse' | 'touch', pointerId?: number, startedFromTrustedEvent?: boolean): void;
423
+ createDragClone(element: HTMLElement, rect: DOMRect): HTMLElement;
424
+ updateClonePosition(clientX: number, clientY: number): void;
425
+ activateAllDroppables(): void;
426
+ setupMoveObservables(inputType: 'mouse' | 'touch', eventSource?: 'pointer' | 'mouse' | 'touch'): void;
427
+ };
428
+ interface DragState {
429
+ dragging: boolean;
430
+ dragSource: HTMLElement | null;
431
+ dragClone: HTMLElement | null;
432
+ startOffset: {
433
+ x: number;
434
+ y: number;
435
+ };
436
+ currentTarget: HTMLElement | null;
437
+ sourceDroppable: HTMLElement | null;
438
+ inputType: 'mouse' | 'touch' | null;
439
+ pointerId?: number;
440
+ startedFromTrustedEvent?: boolean;
441
+ initialCoordinates?: {
442
+ x: number;
443
+ y: number;
444
+ };
445
+ activationTimeout?: number;
446
+ touchCleanup?: () => void;
447
+ lastTargetChangeTime?: number;
448
+ returnAnchorItems?: HTMLElement[];
449
+ /** Last pointer position, so the clone can be repositioned after it is re-hosted mid-drag. */
450
+ lastCoordinates?: {
451
+ x: number;
452
+ y: number;
453
+ };
454
+ }
455
+
456
+ type DragDropSlotted = DragDropCore & DropzoneAutoSize & {
457
+ minAssociations: number;
458
+ maxAssociations: number;
459
+ disableAnimations: boolean;
460
+ enableFlipAnimations: boolean;
461
+ validate(): boolean;
462
+ reportValidity(): boolean;
463
+ reset(): void;
464
+ saveResponse(value?: string | string[]): void;
465
+ shouldTreatBlockedMaxAsInvalid(): boolean;
466
+ shouldReturnToInventoryOnInventoryDrop(): boolean;
467
+ /** Placement, published on `dragDropContext`. An interaction that renders its own drop targets
468
+ * reads `nodesByTarget` straight out of it. */
469
+ _dragDrop: Readonly<DragDropState>;
470
+ /** The chips a target holds — from the placement map, or the DOM, depending on the target. */
471
+ chipsIn(droppable: HTMLElement): HTMLElement[];
472
+ isDeclarativeTarget(el: HTMLElement | null | undefined): boolean;
473
+ /** Republish placement on `dragDropContext` and re-render the targets that read it. */
474
+ syncDragDropState(): void;
475
+ /**
476
+ * How many associations exist, for `min-associations` / `max-associations`.
477
+ *
478
+ * The default counts placed chips, which is one-to-one with associations only when a chip *is*
479
+ * an association — a gap holding one chip, a match target holding one chip. Associate pairs two
480
+ * chips per association and overrides this. Declared here so it can be.
481
+ */
482
+ totalAssociationsFromState(): number;
483
+ };
484
+
485
+ /**
486
+ * Shared utilities for sortable drag-and-drop behavior.
487
+ * Used by both DragDropSortableMixin (standalone) and SlotSortableEnhancerMixin (composition).
488
+ */
489
+
490
+ /**
491
+ * Configuration for drop placeholder styling
492
+ */
493
+ interface PlaceholderConfig {
494
+ borderStyle?: string;
495
+ borderColor?: string;
496
+ background?: string;
497
+ transitionDuration?: number;
498
+ }
499
+
500
+ type DragDropSlottedSortable = DragDropSlotted & {
501
+ allowReorder: boolean;
502
+ readonly isDraggingFromSlot: boolean;
503
+ sortablePlaceholderConfig: PlaceholderConfig;
504
+ };
505
+
506
+ declare const QtiAssociateInteraction_base: (abstract new (...args: any[]) => DragDropSlottedSortable) & (abstract new (...args: any[]) => DragDropSlotted) & typeof Interaction;
507
+ /**
508
+ * Drag-and-drop associate interaction: candidates pair associable choices.
509
+ *
510
+ * @slot prompt - The prompt shown above the choices.
511
+ * @slot qti-simple-associable-choice - The associable choice sources.
512
+ *
513
+ * @csspart drags - Wrapper around the associable choice slot.
514
+ * @csspart drops - The container holding all drop targets.
515
+ * @csspart drop-row - Container for one left/right drop pair.
516
+ * @csspart drop - Each individual drop target.
517
+ * @csspart message - Live validation message region (role="alert").
518
+ */
519
+ declare class QtiAssociateInteraction extends QtiAssociateInteraction_base {
520
+ #private;
521
+ static styles: CSSResultGroup;
522
+ protected _childrenMap: Element[];
523
+ protected _registerChoiceHandler: (event: CustomEvent) => void;
524
+ constructor();
525
+ protected _registerChoice(event: CustomEvent): void;
526
+ protected getResponse(): string[];
527
+ /**
528
+ * How many associations the candidate has made.
529
+ *
530
+ * The mixin counts placed chips, which is right for gap-match — one chip in one gap is one
531
+ * association — and wrong here. An association is a *pair*, so three associations are six chips,
532
+ * and `max-associations="3"` compared 6 against 3 and declared the item invalid the moment it was
533
+ * correctly filled in.
534
+ *
535
+ * A half-filled row is not an association yet, and `getResponse()` already knows that: it emits a
536
+ * pair only when both sides hold a chip. Counting its entries counts associations by definition,
537
+ * and keeps the number validation sees equal to the number the response reports.
538
+ */
539
+ totalAssociationsFromState(): number;
540
+ getValue(val: string[]): string[];
541
+ render(): lit.TemplateResult<1>;
542
+ protected updated(changedProperties: Map<string, unknown>): void;
543
+ disconnectedCallback(): void;
544
+ }
545
+ declare global {
546
+ interface HTMLElementTagNameMap {
547
+ 'qti-associate-interaction': QtiAssociateInteraction;
548
+ }
549
+ }
550
+
551
+ type Orientation = 'horizontal' | 'vertical' | undefined;
552
+ declare const QtiChoiceInteraction_base: (abstract new (...args: any[]) => {}) & (abstract new (...args: any[]) => ChoicesInterface) & typeof Interaction;
553
+ /**
554
+ * A single-response or multiple-response choice interaction.
555
+ *
556
+ * @customElement qti-choice-interaction
557
+ *
558
+ * @attr {string} response-identifier - Required. Identifier of the bound response variable.
559
+ * @attr {number} [max-choices=1] - Maximum selectable choices. `1` is a single-response
560
+ * item; `0` means unlimited and makes it a multiple-response item.
561
+ * @attr {number} [min-choices=0] - Minimum selectable choices for a valid response.
562
+ * @attr {'horizontal'|'vertical'} [orientation=vertical] - Deprecated by QTI in favour of
563
+ * the `qti-orientation-*` class vocabulary.
564
+ * @attr {boolean} [shuffle=false] - Requests choice shuffling. Applied by the transform
565
+ * pipeline (`qti-transformers`), not by this element.
566
+ * @attr {'qti-orientation-horizontal'|'qti-orientation-vertical'|'qti-choices-stacking-1'|'qti-choices-stacking-2'|'qti-choices-stacking-3'|'qti-choices-stacking-4'|'qti-choices-stacking-5'|'qti-labels-none'|'qti-labels-decimal'|'qti-labels-lower-alpha'|'qti-labels-upper-alpha'|'qti-labels-suffix-none'|'qti-labels-suffix-period'|'qti-labels-suffix-parenthesis'|'qti-input-control-hidden'} class - QTI shared presentation vocabulary. Space-separated; takes precedence over `orientation`.
567
+ *
568
+ * @slot prompt - The prompt shown above the choices.
569
+ * @slot - Default slot for `qti-simple-choice` elements.
570
+ *
571
+ * @csspart prompt - Wrapper around the prompt slot.
572
+ * @csspart slot - Wrapper around the default slot containing the choices.
573
+ * @csspart message - Live validation message region (role="alert").
574
+ */
575
+ declare class QtiChoiceInteraction extends QtiChoiceInteraction_base implements ChoicesInterface {
576
+ #private;
577
+ static styles: CSSResultGroup;
578
+ /** @deprecated, use 'qti-orientation-horizontal' or 'qti-orientation-vertical' instead */
579
+ orientation: Orientation;
580
+ render(): lit.TemplateResult<1>;
581
+ }
582
+ declare global {
583
+ interface HTMLElementTagNameMap {
584
+ 'qti-choice-interaction': QtiChoiceInteraction;
585
+ }
586
+ }
587
+
588
+ /**
589
+ * A multi-line text-entry interaction.
590
+ *
591
+ * @customElement qti-extended-text-interaction
592
+ *
593
+ * @attr {string} response-identifier - Required. Identifier of the bound response variable.
594
+ * @attr {number} expected-length - Hint at the expected answer length in characters; sets the
595
+ * textarea's `maxlength`. Also the last-resort row count, used only when neither a
596
+ * `qti-height-lines-*` class nor `expected-lines` is present.
597
+ * @attr {string} pattern-mask - Regular expression the value must match to be valid.
598
+ * @attr {string} placeholder-text - Placeholder shown while the textarea is empty.
599
+ * @attr {string} data-patternmask-message - Custom validation message shown when
600
+ * `pattern-mask` fails. Part of the QTI shared interaction vocabulary.
601
+ * @attr {'qti-height-lines-3'|'qti-height-lines-6'|'qti-height-lines-15'} class - QTI shared
602
+ * presentation vocabulary controlling the rendered height. Outranks both `expected-lines`
603
+ * and `expected-length`.
604
+ * @attr {number} expected-lines - Expected number of lines of response, and the rendered row
605
+ * count unless a `qti-height-lines-*` class is present.
606
+ * @attr {number} [base=10] - Not implemented. Numeric base used when recording the value.
607
+ * @attr {string} string-identifier - Not implemented. Identifier of a second, string-typed
608
+ * response variable that also receives the raw entry.
609
+ * @attr {number} max-strings - Not implemented. Maximum number of separate string responses. QTI
610
+ * defines these for a multi-string response — several bound variables, one field each. This
611
+ * element renders a single textarea bound to one variable, so there is nothing for the bounds
612
+ * to count: reading them as a word or paragraph limit would invent a rule QTI does not state.
613
+ * Implement alongside multi-string rendering, not before it.
614
+ * @attr {number} min-strings - Not implemented. See `max-strings`.
615
+ * @attr {'plain'|'preformatted'|'xhtml'} [format=plain] - How the response is presented.
616
+ * `preformatted` renders the field monospaced; `xhtml` is accepted but downgraded to plain,
617
+ * because the field is a textarea with no rich-text editor behind it.
618
+ *
619
+ * @slot prompt - The prompt shown above the textarea.
620
+ *
621
+ * @csspart textarea - The textarea input element.
622
+ */
623
+ declare class QtiExtendedTextInteraction extends Interaction {
624
+ #private;
625
+ static styles: CSSResultGroup;
626
+ protected _rows: number;
627
+ /** expected length is mapped to the property maxlength on the textarea */
628
+ expectedLength: number;
629
+ /** QTI's own hint at the response height. Outranked by `qti-height-lines-*`; see `#resolveRows`. */
630
+ expectedLines: number;
631
+ /**
632
+ * How the response text is presented. Reflected so themes can key off
633
+ * `:host([format='preformatted'])`.
634
+ *
635
+ * `xhtml` is accepted and recorded but renders as `plain`: the field is a `<textarea>`, and
636
+ * there is no rich-text editor behind it. Downgrading loudly beats either refusing valid QTI
637
+ * or pretending to support formatting the candidate cannot actually produce.
638
+ */
639
+ format: 'plain' | 'preformatted' | 'xhtml';
640
+ protected _handleFormatChange: () => void;
641
+ patternMask: string;
642
+ /** text appearing in the extended-text-interaction if it is empty */
643
+ placeholderText: string;
644
+ dataPatternmaskMessage: string;
645
+ classNames: string;
646
+ protected _handleRowsInputChange(): void;
647
+ response: string | null;
648
+ protected _handleResponseChange: () => void;
649
+ get value(): string | null;
650
+ set value(val: string | null);
651
+ validate(): boolean;
652
+ reportValidity(): boolean;
653
+ /** The prompt, above the field. */
654
+ protected renderPrompt(): unknown;
655
+ /** The field itself. */
656
+ protected renderTextarea(): unknown;
657
+ /** Hidden until `Interaction.reportValidity` shows it. */
658
+ protected renderValidationMessage(): unknown;
659
+ render(): lit.TemplateResult<1>;
660
+ protected textChanged(event: Event): void;
661
+ }
662
+ declare global {
663
+ interface HTMLElementTagNameMap {
664
+ 'qti-extended-text-interaction': QtiExtendedTextInteraction;
665
+ }
666
+ }
667
+
668
+ declare const QtiGapMatchInteraction_base: (abstract new (...args: any[]) => DragDropSlottedSortable) & (abstract new (...args: any[]) => DragDropSlotted) & typeof Interaction;
669
+ /**
670
+ * Drag-and-drop gap-match interaction: candidates drag choices into gap targets.
671
+ *
672
+ * @customElement qti-gap-match-interaction
673
+ *
674
+ * @attr {string} response-identifier - Required. Identifier of the bound response variable.
675
+ * @attr {number} [max-associations=1] - Maximum gaps that may be filled across the whole
676
+ * interaction; `0` means unlimited.
677
+ * @attr {number} [min-associations=1] - Minimum filled gaps for a valid response.
678
+ * @attr {boolean} [shuffle=false] - Requests shuffling of the `qti-gap-text` sources. Applied
679
+ * by the transform pipeline (`qti-transformers`), not by this element.
680
+ * @attr {'qti-choices-top'|'qti-choices-bottom'|'qti-choices-left'|'qti-choices-right'} class -
681
+ * QTI shared presentation vocabulary positioning the gap-choices container.
682
+ * @attr {boolean} [auto-size-dropzones=true] - Extension, not QTI. Sizes every gap to the
683
+ * widest chip so placement does not reflow the prose. On by default: a gap is a slot, and a slot
684
+ * that is already the size of the chip it will hold does not resize when one lands in it.
685
+ * @attr {boolean} [disable-animations=false] - Extension, not QTI. Disables the FLIP move
686
+ * animation.
687
+ *
688
+ * @slot prompt - The prompt shown above the interaction.
689
+ * @slot drags - The draggable choice sources.
690
+ * @slot - Default slot for the drop targets (gaps).
691
+ *
692
+ * @csspart drags - Wrapper around the drag sources slot.
693
+ * @csspart drops - Wrapper around the drop targets slot.
694
+ * @csspart message - Live validation message region (role="alert").
695
+ */
696
+ declare class QtiGapMatchInteraction extends QtiGapMatchInteraction_base {
697
+ static styles: CSSResultGroup;
698
+ render(): lit.TemplateResult<1>;
699
+ }
700
+ declare global {
701
+ interface HTMLElementTagNameMap {
702
+ 'qti-gap-match-interaction': QtiGapMatchInteraction;
703
+ }
704
+ }
705
+
706
+ /**
707
+ * Graphic associate interaction: candidates connect points/hotspots on an image with lines.
708
+ *
709
+ * @slot prompt - The prompt shown above the image.
710
+ * @slot - Default slot for hotspot choices layered over the image.
711
+ *
712
+ * @csspart line - Each line drawn by the candidate.
713
+ * @csspart correct-line - Each line displayed as part of the correct response.
714
+ * @csspart point - Each in-progress endpoint indicator.
715
+ * @csspart message - Live validation message region (role="alert").
716
+ */
717
+ declare class QtiGraphicAssociateInteraction extends Interaction {
718
+ #private;
719
+ static styles: CSSResultGroup;
720
+ private startCoord;
721
+ private mouseCoord;
722
+ grImage: any[];
723
+ private _response;
724
+ constructor();
725
+ reset(): void;
726
+ validate(): boolean;
727
+ set response(val: string | string[] | null);
728
+ get response(): string[] | null;
729
+ /** Extension hook for optional SVG lines rendered above the candidate response. */
730
+ protected renderSupplementalLines(): unknown;
731
+ render(): lit.TemplateResult<1>;
732
+ firstUpdated(): void;
733
+ disconnectedCallback(): void;
734
+ }
735
+ declare global {
736
+ interface HTMLElementTagNameMap {
737
+ 'qti-graphic-associate-interaction': QtiGraphicAssociateInteraction;
738
+ }
739
+ }
740
+
741
+ declare const QtiGraphicGapMatchInteraction_base: (abstract new (...args: any[]) => DragDropSlottedSortable) & (abstract new (...args: any[]) => DragDropSlotted) & typeof Interaction;
742
+ /**
743
+ * Graphic gap-match interaction: candidates drag choices onto image hotspots.
744
+ *
745
+ * @slot prompt - The prompt shown above the image.
746
+ * @slot drags - The draggable choice sources.
747
+ * @slot - Default slot for the base image and hotspots.
748
+ *
749
+ * @csspart image - Wrapper around the image slot.
750
+ * @csspart drags - Wrapper around the drag sources slot.
751
+ * @csspart message - Live validation message region (role="alert").
752
+ */
753
+ declare class QtiGraphicGapMatchInteraction extends QtiGraphicGapMatchInteraction_base {
754
+ #private;
755
+ static styles: CSSResultGroup;
756
+ render(): lit.TemplateResult<1>;
757
+ shouldReturnToInventoryOnInventoryDrop(): boolean;
758
+ connectedCallback(): void;
759
+ disconnectedCallback(): void;
760
+ }
761
+ declare global {
762
+ interface HTMLElementTagNameMap {
763
+ 'qti-graphic-gap-match-interaction': QtiGraphicGapMatchInteraction;
764
+ }
765
+ }
766
+
767
+ type HotspotChoice = Choice & {
768
+ order: number;
769
+ };
770
+ declare const QtiGraphicOrderInteraction_base: (abstract new (...args: any[]) => ChoicesInterface) & typeof Interaction;
771
+ /**
772
+ * Graphic order interaction: candidates order hotspots on an image.
773
+ *
774
+ * @slot prompt - The prompt shown above the image.
775
+ * @slot - Default slot for the image and hotspot choices.
776
+ *
777
+ * @csspart message - Live validation message region (role="alert").
778
+ */
779
+ declare class QtiGraphicOrderInteraction extends QtiGraphicOrderInteraction_base {
780
+ #private;
781
+ static styles: CSSResultGroup;
782
+ protected choiceOrdering: boolean;
783
+ protected _choiceElements: Choice[];
784
+ render(): lit.TemplateResult<1>;
785
+ /** Extension hook for packages that add semantic color states to locator pins. */
786
+ protected resolvePinColor(_choice: HotspotChoice): string;
787
+ protected refreshLocatorPins(): void;
788
+ connectedCallback(): void;
789
+ disconnectedCallback(): void;
790
+ }
791
+ declare global {
792
+ interface HTMLElementTagNameMap {
793
+ 'qti-graphic-order-interaction': QtiGraphicOrderInteraction;
794
+ }
795
+ }
796
+
797
+ declare const QtiHotspotInteraction_base: (abstract new (...args: any[]) => ChoicesInterface) & typeof Interaction;
798
+ /**
799
+ * Hotspot interaction: candidates select one or more hotspots on an image.
800
+ *
801
+ * @slot prompt - The prompt shown above the image.
802
+ * @slot - Default slot for the image and hotspot choices.
803
+ */
804
+ declare class QtiHotspotInteraction extends QtiHotspotInteraction_base {
805
+ #private;
806
+ static styles: CSSResultGroup;
807
+ render(): lit.TemplateResult<1>;
808
+ connectedCallback(): void;
809
+ disconnectedCallback(): void;
810
+ }
811
+ declare global {
812
+ interface HTMLElementTagNameMap {
813
+ 'qti-hotspot-interaction': QtiHotspotInteraction;
814
+ }
815
+ }
816
+
817
+ declare const QtiHottextInteraction_base: (abstract new (...args: any[]) => ChoicesInterface) & typeof Interaction;
818
+ /**
819
+ * Hottext interaction: candidates select highlighted words within a text block.
820
+ *
821
+ * @customElement qti-hottext-interaction
822
+ *
823
+ * @attr {string} response-identifier - Required. Identifier of the bound response variable.
824
+ * @attr {number} [max-choices=1] - Maximum selectable hottexts; `0` means unlimited.
825
+ * @attr {number} [min-choices=0] - Minimum selectable hottexts for a valid response.
826
+ * @attr {'qti-unselected-hidden'} class - QTI shared presentation vocabulary.
827
+ * `qti-unselected-hidden` leaves the selectable words visually indistinguishable from the
828
+ * surrounding prose until they are selected.
829
+ *
830
+ * @slot - Default slot for the mixed content and `qti-hottext` choices.
831
+ *
832
+ * @csspart message - Live validation message region (role="alert").
833
+ */
834
+ declare class QtiHottextInteraction extends QtiHottextInteraction_base {
835
+ static styles: CSSResultGroup;
836
+ render: () => lit.TemplateResult<1>;
837
+ }
838
+
839
+ interface OptionType {
840
+ content: string | Node[];
841
+ value: string;
842
+ selected: boolean;
843
+ }
844
+ declare const QtiInlineChoiceInteraction_base: (abstract new (...args: any[]) => MenuAutoSize) & typeof Interaction;
845
+ /**
846
+ * Inline choice interaction: dropdown selector rendered inline with surrounding text.
847
+ *
848
+ * @customElement qti-inline-choice-interaction
849
+ *
850
+ * @attr {string} response-identifier - Required. Identifier of the bound response variable.
851
+ * @attr {string} data-prompt - Placeholder shown before a choice is picked. Falls back to
852
+ * the item configuration's `inlineChoicePrompt`, then to `select`.
853
+ * @attr {boolean} [shuffle=false] - Requests option shuffling. Applied by the transform
854
+ * pipeline (`qti-transformers`), not by this element.
855
+ * @attr {boolean} [required=false] - Whether a choice must be selected for the response to be
856
+ * valid. Written as `required="true"` / `required="false"`; a bare `required` is accepted too.
857
+ * @attr {number} [min-choices=0] - Equivalent spelling of `required`: `1` demands an answer.
858
+ * Absent from the QTI attribute table for this element but used by the conformance suite.
859
+ *
860
+ * @slot - Default slot for `qti-inline-choice` options.
861
+ *
862
+ * @csspart trigger - The dropdown trigger button.
863
+ * @csspart value - The currently displayed value inside the trigger.
864
+ * @csspart dropdown-icon - The chevron icon inside the trigger; also carries `dropdown-icon-open` when open.
865
+ * @csspart menu - The popover element containing the option list.
866
+ * @csspart option - Each option button; also carries `option-prompt` and `option-selected` variants.
867
+ * @csspart option-content - The content wrapper inside each option.
868
+ */
869
+ declare class QtiInlineChoiceInteraction extends QtiInlineChoiceInteraction_base {
870
+ #private;
871
+ constructor();
872
+ get isInline(): boolean;
873
+ static get styles(): lit.CSSResultGroup[];
874
+ protected options: OptionType[];
875
+ protected _dropdownOpen: boolean;
876
+ private _slotObserver;
877
+ private readonly _menuId;
878
+ configContext: ConfigContext;
879
+ /**
880
+ * Placeholder shown in the closed combobox before a choice is picked.
881
+ *
882
+ * Declared rather than read straight off `dataset` so it reaches the custom elements
883
+ * manifest, the generated types and the Storybook controls — and so that changing it
884
+ * re-renders, which reading `dataset` at render time never did.
885
+ *
886
+ * Falls back to the item configuration's `inlineChoicePrompt`, then to `select`.
887
+ */
888
+ dataPrompt: string;
889
+ protected _handleDataPromptChange: () => void;
890
+ /**
891
+ * Whether a choice must be selected for the response to be valid. QTI defaults this to
892
+ * false, so an untouched dropdown is a valid empty response unless an author opts in.
893
+ *
894
+ * QTI writes `required="true"` / `required="false"` rather than using HTML's bare-attribute
895
+ * boolean, so `required="false"` must read as false — which Lit's default Boolean converter
896
+ * would get backwards, since it only tests for the attribute's presence.
897
+ */
898
+ required: boolean;
899
+ /**
900
+ * Minimum selections for a valid response — in practice 0 or 1, since the dropdown holds one.
901
+ *
902
+ * Not in the QTI 3 Implementation Guide's attribute table for this element, which offers only
903
+ * `required`. It is in the conformance suite: `Advanced/Q12-inline-choice/inline-choice-sv-3`
904
+ * expresses "must answer" as `min-choices="1"`, and pairs it with `data-min-selections-message`.
905
+ * Authors reach for it because every sibling interaction takes it, so it is honoured here as an
906
+ * equivalent spelling of `required`.
907
+ */
908
+ minChoices: number;
909
+ protected _handleRequiredChange: () => void;
910
+ /** The closed combobox — the box showing the chosen option. */
911
+ protected renderTrigger(): unknown;
912
+ /** The popover listbox. */
913
+ protected renderMenu(): unknown;
914
+ /** Hidden until `Interaction.reportValidity` shows it. */
915
+ protected renderValidationMessage(): unknown;
916
+ render(): lit.TemplateResult<1>;
917
+ connectedCallback(): Promise<void>;
918
+ disconnectedCallback(): void;
919
+ willUpdate(changed: PropertyValues): void;
920
+ updated(changed: PropertyValues): void;
921
+ /**
922
+ * Autosizing is opt-in through `configContext.inlineChoiceAutosize`, and an explicit
923
+ * `qti-input-width-*` class always wins.
924
+ *
925
+ * That second check has to live here rather than in CSS: the measurement is written as an inline
926
+ * style on the trigger, and the width classes set the same property on `:host`, so the cascade
927
+ * would hand it to the measurement every time. Not writing at all is what makes the class win.
928
+ */
929
+ shouldAutoSizeMenu(): boolean;
930
+ /**
931
+ * The chevron sits in the trigger and not in the menu, so the menu never measures it.
932
+ *
933
+ * `offsetWidth`, NOT `getBoundingClientRect().width`: the icon rotates when the menu opens, and a
934
+ * client rect reports the TRANSFORMED box — so a chevron caught mid-rotation measures wider than
935
+ * it is, and the trigger grew and shrank by a few pixels on every open. offsetWidth is the layout
936
+ * box and ignores the transform. (Same trap the drag-drop clone code documents for a chip picked
937
+ * up mid-animation.)
938
+ */
939
+ menuAutoSizeExtraWidth(): number;
940
+ validate(): boolean;
941
+ reportValidity(): boolean;
942
+ reset(): void;
943
+ /**
944
+ * Captures an attribute-set response before slotted options have been
945
+ * gathered. `#updateOptions` consumes it once the options exist.
946
+ * `undefined` = no pending value.
947
+ */
948
+ private _pendingResponse;
949
+ set response(value: string | null);
950
+ get response(): string | null;
951
+ }
952
+ declare global {
953
+ interface HTMLElementTagNameMap {
954
+ 'qti-inline-choice-interaction': QtiInlineChoiceInteraction;
955
+ }
956
+ }
957
+
958
+ declare const QtiMatchInteraction_base: (abstract new (...args: any[]) => DragDropSlottedSortable) & (abstract new (...args: any[]) => DragDropSlotted) & typeof Interaction;
959
+ /**
960
+ * Match interaction: candidates pair items from two sets, either as drag-and-drop or as a tabular grid.
961
+ *
962
+ * @customElement qti-match-interaction
963
+ *
964
+ * @attr {string} response-identifier - Required. Identifier of the bound response variable.
965
+ * @attr {number} [max-associations=0] - Maximum pairings across the whole interaction; `0`
966
+ * means unlimited. QTI's own default is `1`; this element defaults to unlimited because a
967
+ * literal `1` breaks any multi-pair match item. See plans/interaction-attribute-spec-conformance.md.
968
+ * @attr {number} [min-associations=1] - Minimum pairings for a valid response.
969
+ * @attr {boolean} [shuffle=false] - Requests shuffling of both match sets. Applied by the
970
+ * transform pipeline (`qti-transformers`), not by this element.
971
+ * @attr {'qti-match-tabular'|'qti-choices-top'|'qti-choices-bottom'|'qti-choices-left'|'qti-choices-right'} class -
972
+ * QTI shared presentation vocabulary. `qti-match-tabular` renders a checkbox/radio grid
973
+ * instead of drag-and-drop; the `qti-choices-*` values position the source set.
974
+ * @attr {boolean} [auto-size-dropzones=false] - Extension, not QTI. Sizes every drop target to
975
+ * the widest chip so placement does not reflow the layout. The mixin default is `true`; this
976
+ * interaction is the one that overrides it to `false`, because a match target is a category card
977
+ * rather than a socket (see the field below and DROP-SIZING.md §1).
978
+ * @attr {boolean} [disable-animations=false] - Extension, not QTI. Disables the FLIP move
979
+ * animation.
980
+ *
981
+ * @slot prompt - The prompt shown above the interaction.
982
+ * @slot match-cols - Column headers (tabular mode).
983
+ * @slot match-rows - Row headers (tabular mode).
984
+ * @slot - Default slot for the two match sets (drag-and-drop mode).
985
+ *
986
+ * @csspart grid - The tabular grid container.
987
+ * @csspart corner - The top-left corner cell of the grid.
988
+ * @csspart cols-wrap - Wrapper row for the column headers.
989
+ * @csspart c-header - The column header slot wrapper.
990
+ * @csspart rows-wrap - Wrapper column for the row headers.
991
+ * @csspart r-header - The row header slot wrapper.
992
+ * @csspart checkbox-grid - The interactive cell grid area.
993
+ * @csspart input-cell - Each cell's label element.
994
+ * @csspart control - The visible checkbox/radio box (tabular mode). Also carries the variant
995
+ * tokens `radio` | `checkbox`, `checked`, and `correct` | `incorrect` — e.g.
996
+ * `::part(control radio checked correct)`. These mirror the custom-state vocabulary; the cells
997
+ * are plain spans in the shadow root, so they cannot carry real `:state()`.
998
+ * @csspart control-mark - The inner mark element; carries the same variant tokens as `control`.
999
+ * @csspart message - Live validation message region (role="alert").
1000
+ */
1001
+ declare class QtiMatchInteraction extends QtiMatchInteraction_base {
1002
+ static styles: CSSResultGroup;
1003
+ /**
1004
+ * Match targets are categories, not slots. They should look able to hold several answers, so they
1005
+ * take a flat floor (the `--qti-dropzone-min-height` fallback) rather than the size of the widest chip.
1006
+ *
1007
+ * This is a property of the INTERACTION, not of an individual target. A `match-max="1"` target is
1008
+ * still a category that happens to take one answer, and it sits in a grid beside targets that take
1009
+ * several — sizing each one to its own contents would make that grid ragged. So the whole
1010
+ * interaction opts out, and the per-target `match-max` decides nothing about size here.
1011
+ *
1012
+ * The interactions where a drop IS a slot — gap-match, order, associate — keep measurement on, and
1013
+ * their drops are exactly the widest chip plus the inset.
1014
+ */
1015
+ autoSizeDropzones: boolean;
1016
+ protected sourceChoices: QtiSimpleAssociableChoice[];
1017
+ protected targetChoices: QtiSimpleAssociableChoice[];
1018
+ protected lastCheckedRadio: HTMLInputElement | null;
1019
+ class: string;
1020
+ protected _response: string | string[];
1021
+ get response(): string[];
1022
+ set response(val: string[]);
1023
+ isDragDropEnabled(): boolean;
1024
+ initiateDrag(...args: any[]): void;
1025
+ afterCache(): void;
1026
+ responseIdentifier: string;
1027
+ connectedCallback(): Promise<void>;
1028
+ protected willUpdate(changed: PropertyValues): void;
1029
+ private syncTabularSlotting;
1030
+ protected handleRadioClick: (e: {
1031
+ target: HTMLInputElement;
1032
+ }) => void;
1033
+ protected handleRadioChange: (e: {
1034
+ target: any;
1035
+ }) => void;
1036
+ validate(): boolean;
1037
+ /** Extension hook for packages that add visual state tokens to tabular cells. */
1038
+ protected getCellStateVariant(_value: string, _checked: boolean): string;
1039
+ render(): lit.TemplateResult<1>;
1040
+ }
1041
+ declare global {
1042
+ interface HTMLElementTagNameMap {
1043
+ 'qti-match-interaction': QtiMatchInteraction;
1044
+ }
1045
+ }
1046
+
1047
+ declare const QtiOrderInteraction_base: (abstract new (...args: any[]) => DragDropSlottedSortable) & (abstract new (...args: any[]) => DragDropSlotted) & typeof Interaction;
1048
+ /**
1049
+ * Order interaction: candidates arrange choices into a target sequence.
1050
+ *
1051
+ * @customElement qti-order-interaction
1052
+ *
1053
+ * @attr {string} response-identifier - Required. Identifier of the bound response variable.
1054
+ * @attr {'horizontal'|'vertical'} [orientation=vertical] - Layout direction of the drop
1055
+ * sequence. Unlike on `qti-choice-interaction`, QTI does not deprecate this for order.
1056
+ * @attr {boolean} [shuffle=false] - Requests choice shuffling. Applied by the transform
1057
+ * pipeline (`qti-transformers`), not by this element.
1058
+ * @attr {number} [min-associations=1] - Non-QTI vocabulary inherited from the drag-drop
1059
+ * mixin; currently the only way to set the lower bound. QTI spells this `min-choices`.
1060
+ * @attr {number} [max-associations=0] - Non-QTI vocabulary inherited from the drag-drop
1061
+ * mixin; currently the only way to set the upper bound. QTI spells this `max-choices`.
1062
+ * @attr {number} min-choices - Not implemented. The QTI-correct spelling of the lower bound.
1063
+ * See plans/interaction-attribute-spec-conformance.md.
1064
+ * @attr {number} max-choices - Not implemented. The QTI-correct spelling of the upper bound.
1065
+ * See plans/interaction-attribute-spec-conformance.md.
1066
+ * @attr {boolean} [auto-size-dropzones=true] - Extension, not QTI. Sizes every drop target to
1067
+ * the widest chip so placement does not reflow the layout. On by default: an order slot is a
1068
+ * socket cut to one chip, and both axes are measured (see DROP-SIZING.md).
1069
+ * @attr {boolean} [disable-animations=false] - Extension, not QTI. Disables the FLIP move
1070
+ * animation.
1071
+ *
1072
+ * @slot prompt - The prompt shown above the interaction.
1073
+ * @slot drags - The draggable choice sources.
1074
+ *
1075
+ * @csspart container - The outer container wrapping drags and drops.
1076
+ * @csspart drags - Wrapper around the drag sources slot.
1077
+ * @csspart drops - The drop-target region.
1078
+ * @csspart drop - Each individual drop target.
1079
+ * @csspart drag - A choice that has been placed into a drop target.
1080
+ */
1081
+ declare class QtiOrderInteraction extends QtiOrderInteraction_base {
1082
+ static styles: lit.CSSResult[];
1083
+ protected childrenMap: Element[];
1084
+ protected nrChoices: number;
1085
+ /** orientation of choices */
1086
+ orientation: 'horizontal' | 'vertical';
1087
+ render(): lit.TemplateResult<1>;
1088
+ getValue(val: string[]): string[];
1089
+ protected getResponse(): string[];
1090
+ shouldTreatBlockedMaxAsInvalid(): boolean;
1091
+ firstUpdated(): Promise<void>;
1092
+ }
1093
+ declare global {
1094
+ interface HTMLElementTagNameMap {
1095
+ 'qti-order-interaction': QtiOrderInteraction;
1096
+ }
1097
+ }
1098
+
1099
+ /**
1100
+ * Shared status values for PCI lifecycle callbacks.
1101
+ *
1102
+ * Matches the status vocabulary used in IMS QTI 3 PCI documentation.
1103
+ */
1104
+ type PciInteractionStatus = 'interacting' | 'suspended' | 'closed' | 'solution' | 'review';
1105
+ /**
1106
+ * Correct response of a response declaration, mirroring `qti-correct-response`.
1107
+ *
1108
+ * `value` holds the authored `qti-value` content: a single value for `single`
1109
+ * cardinality, an array of values for every other cardinality.
1110
+ */
1111
+ interface PciCorrectResponse {
1112
+ value: string | string[];
1113
+ }
1114
+ /**
1115
+ * Response declaration passed into the `getInstance` configuration so a PCI can
1116
+ * render a correct response itself when the item is in `solution` status.
1117
+ *
1118
+ * Mirrors `qti-response-declaration` with camelCased names. Every field is
1119
+ * optional, a delivery engine passes as much or as little as it has, and
1120
+ * `correctResponse` is absent when the response variable has none.
1121
+ *
1122
+ * `correctResponse` is also withheld while the candidate is still working: it is
1123
+ * only sent when `status` is `solution` or `review`, so a PCI never holds the
1124
+ * answer key during `interacting`.
1125
+ *
1126
+ * See https://github.com/1EdTech/qti-project-management/issues/210
1127
+ */
1128
+ interface PciResponseDeclaration {
1129
+ baseType?: BaseType;
1130
+ cardinality?: Cardinality;
1131
+ correctResponse?: PciCorrectResponse;
1132
+ }
1133
+ /**
1134
+ * QTI base-type `file` representation.
1135
+ */
1136
+ type QtiFileData = {
1137
+ data: string;
1138
+ mime: string;
1139
+ name?: string;
1140
+ };
1141
+ type QtiBaseBoolean = boolean;
1142
+ type QtiBaseInteger = number;
1143
+ type QtiBaseFloat = number;
1144
+ type QtiBaseString = string;
1145
+ type QtiBasePoint = [number, number];
1146
+ type QtiBasePair = [string, string];
1147
+ type QtiBaseDirectedPair = [string, string];
1148
+ type QtiBaseDuration = string;
1149
+ type QtiBaseFile = QtiFileData;
1150
+ type QtiBaseUri = string;
1151
+ type QtiBaseIntOrIdentifier = number | string;
1152
+ type QtiBaseIdentifier = string;
1153
+ /**
1154
+ * A QTI record entry for `record` cardinality values.
1155
+ */
1156
+ type QtiRecordItem = {
1157
+ name: string;
1158
+ base?: QtiBaseTypeJSON | null;
1159
+ list?: QtiListTypeJSON | null;
1160
+ };
1161
+ type ResponseVariableType = QtiVariableJSON;
1162
+ /**
1163
+ * QTI Appendix-C style JSON representation for base cardinality.
1164
+ */
1165
+ type QtiBaseTypeJSON = {
1166
+ boolean?: QtiBaseBoolean;
1167
+ integer?: QtiBaseInteger;
1168
+ float?: QtiBaseFloat;
1169
+ string?: QtiBaseString;
1170
+ point?: QtiBasePoint;
1171
+ pair?: QtiBasePair;
1172
+ directedPair?: QtiBaseDirectedPair;
1173
+ duration?: QtiBaseDuration;
1174
+ file?: QtiBaseFile;
1175
+ uri?: QtiBaseUri;
1176
+ intOrIdentifier?: QtiBaseIntOrIdentifier;
1177
+ identifier?: QtiBaseIdentifier;
1178
+ } | null;
1179
+ /**
1180
+ * QTI Appendix-C style JSON representation for list cardinality.
1181
+ */
1182
+ type QtiListTypeJSON = {
1183
+ boolean?: QtiBaseBoolean[];
1184
+ integer?: QtiBaseInteger[];
1185
+ float?: QtiBaseFloat[];
1186
+ string?: QtiBaseString[];
1187
+ point?: QtiBasePoint[];
1188
+ pair?: QtiBasePair[];
1189
+ directedPair?: QtiBaseDirectedPair[];
1190
+ duration?: QtiBaseDuration[];
1191
+ file?: QtiBaseFile[];
1192
+ uri?: QtiBaseUri[];
1193
+ intOrIdentifier?: QtiBaseIntOrIdentifier[];
1194
+ identifier?: QtiBaseIdentifier[];
1195
+ } | null;
1196
+ /**
1197
+ * Complete QTI variable JSON envelope used by PCI bridge messaging.
1198
+ */
1199
+ declare type QtiVariableJSON = {
1200
+ base?: QtiBaseTypeJSON;
1201
+ list?: QtiListTypeJSON;
1202
+ record?: QtiRecordItem[] | null;
1203
+ };
1204
+
1205
+ declare class QtiPortableCustomInteraction extends Interaction {
1206
+ #private;
1207
+ protected _iframeLoaded: boolean;
1208
+ protected _interactionReady: boolean;
1209
+ protected _pendingMessages: Array<{
1210
+ method: string;
1211
+ params: any;
1212
+ }>;
1213
+ protected iframe: HTMLIFrameElement;
1214
+ protected _iframeMessageOrigin: string | null;
1215
+ static styles: CSSResultGroup;
1216
+ module: string;
1217
+ customInteractionTypeIdentifier: string;
1218
+ requirePathsJson: string;
1219
+ requireShimJson: string;
1220
+ requireJsUrl: string;
1221
+ baseUrl: string;
1222
+ useDefaultPaths: boolean;
1223
+ /**
1224
+ * Item lifecycle status handed to the PCI in its `getInstance` configuration.
1225
+ * A delivery engine sets `solution` to let a PCI render the correct response.
1226
+ */
1227
+ status: PciInteractionStatus;
1228
+ /**
1229
+ * Response declaration passed into the PCI configuration, so a PCI can render
1230
+ * the correct response itself instead of having it pushed in as a response.
1231
+ *
1232
+ * Derived from the item context, unless a host sets it explicitly - the
1233
+ * correct response viewer does, since it has no response declaration of its own.
1234
+ *
1235
+ * See https://github.com/1EdTech/qti-project-management/issues/210
1236
+ */
1237
+ set responseDeclaration(declaration: PciResponseDeclaration | null);
1238
+ get responseDeclaration(): PciResponseDeclaration | null;
1239
+ private _errorMessage;
1240
+ protected context?: ItemContext;
1241
+ protected qtiContext?: QtiContext;
1242
+ response: string | string[] | null;
1243
+ /**
1244
+ * Get direct child elements by tag name
1245
+ */
1246
+ private getDirectChildrenByTag;
1247
+ /**
1248
+ * Coerce a scalar value to the expected base-type when possible
1249
+ */
1250
+ private coerceBaseValue;
1251
+ /**
1252
+ * Normalize an input into a list form
1253
+ */
1254
+ private normalizeListValue;
1255
+ /**
1256
+ * Convert a variable value to QtiVariableJSON
1257
+ */
1258
+ private variableToQtiVariableJSON;
1259
+ /**
1260
+ * Convert a record object into QtiVariableJSON
1261
+ */
1262
+ private recordToQtiVariableJSON;
1263
+ /**
1264
+ * Build a record entry from an arbitrary value
1265
+ */
1266
+ private recordEntryFromValue;
1267
+ /**
1268
+ * Extract default QTI_CONTEXT values from qti-context-declaration elements
1269
+ */
1270
+ private getQtiContextDefaultsFromItem;
1271
+ /**
1272
+ * Build a QTI_CONTEXT record for PCI consumption
1273
+ */
1274
+ private getQtiContextRecord;
1275
+ /**
1276
+ * Collect template variables referenced by qti-template-variable children
1277
+ */
1278
+ private getTemplateVariables;
1279
+ /**
1280
+ * Collect context variables referenced by qti-context-variable children
1281
+ */
1282
+ private getContextVariables;
1283
+ /**
1284
+ * Converts response variables to QtiVariableJSON
1285
+ */
1286
+ protected responseVariablesToQtiVariableJSON(input: string | string[], cardinality: Cardinality, baseType: BaseType): QtiVariableJSON;
1287
+ validate(): boolean;
1288
+ set value(v: string | null);
1289
+ get value(): string | null;
1290
+ set boundTo(newValue: Record<string, ResponseVariableType>);
1291
+ get boundTo(): Record<string, QtiVariableJSON>;
1292
+ disconnectedCallback(): void;
1293
+ /**
1294
+ * IFRAME MODE: Send message to iframe
1295
+ */
1296
+ protected sendMessageToIframe(method: string, params: any): void;
1297
+ /**
1298
+ * IFRAME MODE: Handle iframe messages
1299
+ */
1300
+ protected handleIframeMessage: (event: MessageEvent) => void;
1301
+ /**
1302
+ * IFRAME MODE: Create iframe element
1303
+ */
1304
+ protected createIframe(): void;
1305
+ connectedCallback(): void;
1306
+ /**
1307
+ * IFRAME MODE: Generate iframe HTML content
1308
+ */
1309
+ protected generateIframeContent(): string;
1310
+ /**
1311
+ * Method to disable the PCI for review mode
1312
+ * This can be used when showing the correct response
1313
+ */
1314
+ disable(): void;
1315
+ /**
1316
+ * Method to enable the PCI for interactive mode
1317
+ */
1318
+ enable(): void;
1319
+ render(): lit.TemplateResult<1>;
1320
+ }
1321
+ declare global {
1322
+ interface HTMLElementTagNameMap {
1323
+ 'qti-portable-custom-interaction': QtiPortableCustomInteraction;
1324
+ }
1325
+ }
1326
+
1327
+ /**
1328
+ * Test-specific extension of QtiPortableCustomInteraction that adds methods
1329
+ * for interacting with the iframe content in tests.
1330
+ */
1331
+ declare class QtiPortableCustomInteractionTest extends QtiPortableCustomInteraction {
1332
+ #private;
1333
+ /** Wait until the PCI has completed its iframe handshake, even if it became ready before the test started. */
1334
+ waitForReady(timeout?: number): Promise<void>;
1335
+ /**
1336
+ * Gets the HTML content of the iframe for testing purposes
1337
+ * @returns Promise that resolves with the HTML content string
1338
+ */
1339
+ getIFrameContent(): Promise<string>;
1340
+ setTestContext(newContext: ItemContext): void;
1341
+ /**
1342
+ * Recreates the iframe completely
1343
+ * @returns Promise that resolves when the iframe is loaded
1344
+ */
1345
+ recreateIframe(): Promise<void>;
1346
+ /**
1347
+ * Override the original disconnectedCallback to handle iframe recreation
1348
+ */
1349
+ disconnectedCallback(): void;
1350
+ /**
1351
+ * Simulates a mouse click at specific coordinates within the iframe
1352
+ * @param x The x coordinate
1353
+ * @param y The y coordinate
1354
+ * @returns Promise that resolves when the click is performed
1355
+ */
1356
+ iFrameMouseClick(x: number, y: number): Promise<void>;
1357
+ /**
1358
+ * Clicks on an element identified by a CSS selector
1359
+ * @param selector The CSS selector string
1360
+ * @returns Promise that resolves with boolean indicating if the element was found and clicked
1361
+ */
1362
+ iFrameClickOnElement(selector: string): Promise<boolean>;
1363
+ /**
1364
+ * Clicks on an element containing the specified text
1365
+ * @param text The text to search for within elements
1366
+ * @returns Promise that resolves with boolean indicating if the element was found and clicked
1367
+ */
1368
+ iFrameClickOnElementByText(text: string): Promise<boolean>;
1369
+ /**
1370
+ * Sets the value of an input element identified by a CSS selector
1371
+ * @param selector The CSS selector string
1372
+ * @param value The value to set
1373
+ * @returns Promise that resolves with boolean indicating if the element was found and value was set
1374
+ */
1375
+ iFrameSetValueElement(selector: string, value: string): Promise<boolean>;
1376
+ /**
1377
+ * Gets the bounding client rect for an element inside the iframe
1378
+ * @param selector The CSS selector string
1379
+ * @returns Promise that resolves with the rect or null
1380
+ */
1381
+ iFrameGetBoundingClientRect(selector: string): Promise<{
1382
+ left: number;
1383
+ top: number;
1384
+ width: number;
1385
+ height: number;
1386
+ } | null>;
1387
+ /**
1388
+ * Sets the value of an input element containing the specified text
1389
+ * @param text The text to search for within elements
1390
+ * @param value The value to set
1391
+ * @returns Promise that resolves with boolean indicating if the element was found and value was set
1392
+ */
1393
+ iFrameSetValueElementByText(text: string, value: string): Promise<boolean>;
1394
+ /**
1395
+ * Performs a mousedown event on an element identified by a CSS selector
1396
+ * @param selector The CSS selector string
1397
+ * @returns Promise that resolves with boolean indicating if the element was found and mousedown was performed
1398
+ */
1399
+ iFrameMousedownOnElement(selector: string): Promise<boolean>;
1400
+ /**
1401
+ * Override the original generateIframeContent method to include
1402
+ * the test message handlers in the iframe HTML
1403
+ */
1404
+ generateIframeContent(): string;
1405
+ }
1406
+ declare global {
1407
+ interface HTMLElementTagNameMap {
1408
+ 'qti-portable-custom-interaction-test': QtiPortableCustomInteractionTest;
1409
+ }
1410
+ }
1411
+
1412
+ /**
1413
+ * Select-point interaction: candidates place points onto a background image.
1414
+ *
1415
+ * @customElement qti-select-point-interaction
1416
+ *
1417
+ * @attr {string} response-identifier - Required. Identifier of the bound response variable,
1418
+ * which must have base-type `point`.
1419
+ * @attr {number} [max-choices=0] - Maximum points the candidate may place; `0` means unlimited.
1420
+ * @attr {number} [min-choices=0] - Minimum points for a valid response.
1421
+ * @attr {string} area-mappings - Extension, not QTI. JSON array of
1422
+ * `{shape, coords, mappedValue?, defaultValue?}` entries used when no
1423
+ * `qti-response-declaration` supplies an `qti-area-mapping`.
1424
+ *
1425
+ * @slot prompt - The prompt shown above the image.
1426
+ * @slot - Default slot for the base image.
1427
+ *
1428
+ * @csspart point - Each selected point marker.
1429
+ * @cssprop --qti-select-point-icon - Marker mask image (SVG data URL). Should be a solid silhouette for color inheritance.
1430
+ * @cssprop --qti-select-point-marker-size - Marker size.
1431
+ * @cssprop --qti-select-point-marker-anchor - Vertical translate anchor (`-100%` for bottom tip, `-50%` for center).
1432
+ * @cssprop --qti-select-point-marker-color - Marker color; defaults to currentColor so it can be inherited.
1433
+ */
1434
+ declare class QtiSelectPointInteraction extends Interaction {
1435
+ #private;
1436
+ static styles: CSSResultGroup;
1437
+ maxChoices: number;
1438
+ minChoices: number;
1439
+ response: string[] | null;
1440
+ /**
1441
+ * Standalone area mapping as a JSON string. Mirrors the editor's
1442
+ * `#syncAreaEntriesFromAttribute` codec — each entry has `{shape, coords, mappedValue?, defaultValue?}`
1443
+ * and `shape` must be `'circle'` or `'rect'`. Used when no
1444
+ * `qti-response-declaration` provides `areaMapping`.
1445
+ *
1446
+ * @example
1447
+ * ```html
1448
+ * <qti-select-point-interaction area-mappings='[{"shape":"circle","coords":"191,393,10","mappedValue":1}]'>
1449
+ * ```
1450
+ */
1451
+ areaMappings: string | null;
1452
+ private _areaEntries;
1453
+ protected _handleAreaMappingsChange: () => void;
1454
+ protected get _effectiveAreaEntries(): QtiAreaMapEntry[];
1455
+ connectedCallback(): void;
1456
+ get responsePoints(): {
1457
+ x: number;
1458
+ y: number;
1459
+ }[];
1460
+ /** Extension hook for additional part tokens on a rendered response point. */
1461
+ protected pointPart(_point: string, _index: number): string;
1462
+ /** Extension hook for optional layers rendered above the response points. */
1463
+ protected renderSupplementalLayer(): unknown;
1464
+ /** Positions overlay elements that carry `data-coord` and `data-shape`. */
1465
+ protected positionOverlayElements(elements: Iterable<HTMLElement>): void;
1466
+ render(): lit.TemplateResult<1>;
1467
+ validate(): boolean;
1468
+ reportValidity(): boolean;
1469
+ firstUpdated(): void;
1470
+ disconnectedCallback(): void;
1471
+ }
1472
+ declare global {
1473
+ interface HTMLElementTagNameMap {
1474
+ 'qti-select-point-interaction': QtiSelectPointInteraction;
1475
+ }
1476
+ }
1477
+
1478
+ /**
1479
+ * Slider interaction: candidates pick a numeric value along a rail.
1480
+ *
1481
+ * @slot prompt - The prompt shown above the slider.
1482
+ *
1483
+ * @csspart slider - The slider root element.
1484
+ * @csspart bounds - The min/max bounds label wrapper.
1485
+ * @csspart ticks - The tick marks along the rail.
1486
+ * @csspart rail - The rail element the knob slides along.
1487
+ * @csspart knob - The draggable knob.
1488
+ * @csspart value - The current value display (used twice in the layout).
1489
+ * @csspart knob-correct - Ghost knob shown at the correct response position.
1490
+ */
1491
+ declare class QtiSliderInteraction extends Interaction {
1492
+ #private;
1493
+ static styles: CSSResultGroup;
1494
+ private _rail;
1495
+ min: number;
1496
+ max: number;
1497
+ step: number;
1498
+ validate(): boolean;
1499
+ connectedCallback(): void;
1500
+ get response(): string;
1501
+ set response(val: string | null);
1502
+ /** Extension hook for optional content rendered on the slider rail. */
1503
+ protected renderRailSupplement(): unknown;
1504
+ render(): lit.TemplateResult<1>;
1505
+ }
1506
+ declare global {
1507
+ interface HTMLElementTagNameMap {
1508
+ 'qti-slider-interaction': QtiSliderInteraction;
1509
+ }
1510
+ }
1511
+
1512
+ /**
1513
+ * Text-entry interaction: single-line inline text input.
1514
+ *
1515
+ * @customElement qti-text-entry-interaction
1516
+ *
1517
+ * @attr {string} response-identifier - Required. Identifier of the bound response variable.
1518
+ * @attr {number} expected-length - Hint at the expected answer length; drives the rendered
1519
+ * field width and the input's `maxlength`.
1520
+ * @attr {string} pattern-mask - Regular expression the value must match to be valid.
1521
+ * @attr {string} placeholder-text - Placeholder shown while the field is empty.
1522
+ * @attr {string} data-patternmask-message - Custom validation message shown when
1523
+ * `pattern-mask` fails. Part of the QTI shared interaction vocabulary.
1524
+ * @attr {number} [base=10] - Not implemented. Numeric base used when recording the value.
1525
+ * @attr {string} string-identifier - Not implemented. Identifier of a second, string-typed
1526
+ * response variable that also receives the raw entry.
1527
+ * @attr {string} format - Not implemented. QTI types this as a bare normalized string here rather
1528
+ * than as the `plain | preformatted | xhtml` vocabulary it defines for extended-text, and a
1529
+ * single-line input has no formatting to render: it can show neither preserved line breaks nor
1530
+ * markup. The field is always plain text, so this is not planned either.
1531
+ *
1532
+ * @csspart answer - The answer-key line, revealed above the field when the correct response is shown.
1533
+ * @csspart input - The text input element.
1534
+ * @csspart message - The validation message, hidden until `reportValidity` shows it.
1535
+ */
1536
+ declare class QtiTextEntryInteraction extends Interaction {
1537
+ static styles: CSSResultGroup;
1538
+ inputRef: lit_directives_ref_js.Ref<HTMLInputElement>;
1539
+ expectedLength: number;
1540
+ patternMask: string;
1541
+ placeholderText: string;
1542
+ dataPatternmaskMessage: string;
1543
+ response: string | null;
1544
+ private _input;
1545
+ protected _handleValueChange: () => void;
1546
+ get value(): string | null;
1547
+ set value(val: string | null);
1548
+ get isInline(): boolean;
1549
+ validate(): boolean;
1550
+ /** The answer-key line, revealed above the field when the correct response is shown. */
1551
+ protected renderAnswer(): unknown;
1552
+ /** The field itself. */
1553
+ protected renderInput(): unknown;
1554
+ /** Hidden until `Interaction.reportValidity` shows it. */
1555
+ protected renderValidationMessage(): unknown;
1556
+ render(): lit.TemplateResult<1>;
1557
+ protected textChanged(event: Event): void;
1558
+ reportValidity(): boolean;
1559
+ reset(): void;
1560
+ }
1561
+ declare global {
1562
+ interface HTMLElementTagNameMap {
1563
+ 'qti-text-entry-interaction': QtiTextEntryInteraction;
1564
+ }
1565
+ }
1566
+
1567
+ export { type Choice as C, type Orientation as O, QtiAssociableHotspot as Q, QtiAssociateInteraction as a, QtiChoiceInteraction as b, QtiExtendedTextInteraction as c, QtiGap as d, QtiGapImg as e, QtiGapMatchInteraction as f, QtiGapText as g, QtiGraphicAssociateInteraction as h, QtiGraphicGapMatchInteraction as i, QtiGraphicOrderInteraction as j, QtiHotspotChoice as k, QtiHotspotInteraction as l, QtiHottext as m, QtiHottextInteraction as n, QtiInlineChoice as o, QtiInlineChoiceInteraction as p, QtiMatchInteraction as q, QtiOrderInteraction as r, QtiPortableCustomInteraction as s, QtiPrompt as t, QtiSelectPointInteraction as u, QtiSimpleAssociableChoice as v, QtiSimpleChoice as w, QtiSliderInteraction as x, QtiTextEntryInteraction as y, QtiPortableCustomInteractionTest as z };