@lessonkit/react 1.3.1 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,576 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/testing.ts
31
+ var testing_exports = {};
32
+ __export(testing_exports, {
33
+ resetAssessmentWarningsForTests: () => resetAssessmentWarningsForTests,
34
+ resetCompoundValidationWarningsForTests: () => resetCompoundValidationWarningsForTests,
35
+ resetCourseStartedTrackingFlightForTests: () => resetCourseStartedTrackingFlightForTests,
36
+ resetLessonMountRegistryForTests: () => resetLessonMountRegistryForTests,
37
+ resetLessonkitProviderStorageForTests: () => resetLessonkitProviderStorageForTests,
38
+ resetQuizWarningsForTests: () => resetQuizWarningsForTests
39
+ });
40
+ module.exports = __toCommonJS(testing_exports);
41
+
42
+ // src/components/Quiz.tsx
43
+ var import_react12 = require("react");
44
+ var import_accessibility = require("@lessonkit/accessibility");
45
+
46
+ // src/assessment/AssessmentLessonGuard.tsx
47
+ var import_react2 = require("react");
48
+
49
+ // src/lessonContext.tsx
50
+ var import_react = require("react");
51
+ var LessonContext = (0, import_react.createContext)(void 0);
52
+ function useEnclosingLessonId() {
53
+ return (0, import_react.useContext)(LessonContext);
54
+ }
55
+
56
+ // src/runtime/validateComponentId.ts
57
+ var import_core = require("@lessonkit/core");
58
+ function isDevEnvironment() {
59
+ const g = globalThis;
60
+ return typeof g.process !== "undefined" && g.process.env?.NODE_ENV !== "production";
61
+ }
62
+ function normalizeComponentId(id, path) {
63
+ if (path === "courseId") return (0, import_core.assertValidId)(id, "courseId");
64
+ if (path === "lessonId") return (0, import_core.assertValidId)(id, "lessonId");
65
+ if (path === "checkId") return (0, import_core.assertValidId)(id, "checkId");
66
+ if (path === "blockId") return (0, import_core.assertValidId)(id, "blockId");
67
+ return (0, import_core.assertValidId)(id, path);
68
+ }
69
+
70
+ // src/assessment/AssessmentLessonGuard.tsx
71
+ var import_jsx_runtime = require("react/jsx-runtime");
72
+ var warnedAssessmentOutsideLesson = false;
73
+ function resetAssessmentWarningsForTests() {
74
+ warnedAssessmentOutsideLesson = false;
75
+ }
76
+ function AssessmentLessonGuard(props) {
77
+ const enclosingLessonId = useEnclosingLessonId();
78
+ const missingLesson = enclosingLessonId === void 0;
79
+ (0, import_react2.useEffect)(() => {
80
+ if (!missingLesson || isDevEnvironment()) return;
81
+ if (!warnedAssessmentOutsideLesson) {
82
+ warnedAssessmentOutsideLesson = true;
83
+ console.error(
84
+ `[lessonkit] <${props.blockLabel}> must be wrapped in <Lesson>; assessment telemetry will not be emitted.`
85
+ );
86
+ }
87
+ }, [missingLesson, props.blockLabel]);
88
+ if (missingLesson && isDevEnvironment()) {
89
+ throw new Error(`[lessonkit] <${props.blockLabel}> must be wrapped in <Lesson>`);
90
+ }
91
+ if (missingLesson) {
92
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("section", { role: "alert", "aria-label": `${props.blockLabel} configuration error`, "data-lk-check-id": props.checkId, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { children: [
93
+ props.blockLabel,
94
+ " must be placed inside a Lesson."
95
+ ] }) });
96
+ }
97
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: props.children(enclosingLessonId) });
98
+ }
99
+
100
+ // src/assessment/internal/buildAssessmentHandle.ts
101
+ function buildAssessmentHandle(opts) {
102
+ return {
103
+ getScore: opts.getScore,
104
+ getMaxScore: opts.getMaxScore,
105
+ getAnswerGiven: opts.getAnswerGiven,
106
+ resetTask: opts.resetTask,
107
+ showSolutions: opts.showSolutions,
108
+ getXAPIData: opts.getXAPIData,
109
+ ...opts.getCurrentState ? { getCurrentState: opts.getCurrentState } : {},
110
+ ...opts.resume ? { resume: opts.resume } : {}
111
+ };
112
+ }
113
+
114
+ // src/assessment/internal/resumeState.ts
115
+ function readBooleanField(state, key) {
116
+ const value = state[key];
117
+ if (value === true || value === false || value === null) return value;
118
+ return void 0;
119
+ }
120
+ function readStringField(state, key) {
121
+ const value = state[key];
122
+ if (typeof value === "string" || value === null) return value;
123
+ return void 0;
124
+ }
125
+ function readNumberField(state, key) {
126
+ const value = state[key];
127
+ if (typeof value === "number" && Number.isFinite(value)) return value;
128
+ if (value === null) return null;
129
+ return void 0;
130
+ }
131
+
132
+ // src/assessment/internal/useAssessmentHandleRegistration.ts
133
+ var import_react6 = require("react");
134
+
135
+ // src/compound/CompoundProvider.tsx
136
+ var import_react5 = __toESM(require("react"), 1);
137
+ var import_core2 = require("@lessonkit/core");
138
+
139
+ // src/compound/CompoundHydrationBridge.tsx
140
+ var import_react3 = require("react");
141
+ var import_jsx_runtime2 = require("react/jsx-runtime");
142
+ var CompoundHydrationBridgeContext = (0, import_react3.createContext)(
143
+ null
144
+ );
145
+
146
+ // src/compound/CompoundPageIndexContext.tsx
147
+ var import_react4 = require("react");
148
+ var import_jsx_runtime3 = require("react/jsx-runtime");
149
+ var CompoundPageIndexContext = (0, import_react4.createContext)(void 0);
150
+ function useCompoundPageIndex() {
151
+ return (0, import_react4.useContext)(CompoundPageIndexContext);
152
+ }
153
+
154
+ // src/compound/CompoundProvider.tsx
155
+ var import_jsx_runtime4 = require("react/jsx-runtime");
156
+ var CompoundRegistryContext = (0, import_react5.createContext)(null);
157
+ var CompoundHandlesVersionContext = (0, import_react5.createContext)(0);
158
+ function useRegisterAssessmentHandle(checkId, handle) {
159
+ const registry = (0, import_react5.useContext)(CompoundRegistryContext);
160
+ const pageIndex = useCompoundPageIndex();
161
+ import_react5.default.useLayoutEffect(() => {
162
+ if (!registry || !handle) return;
163
+ return registry.register(checkId, handle, pageIndex);
164
+ }, [registry, checkId, handle, pageIndex]);
165
+ }
166
+
167
+ // src/assessment/internal/useAssessmentHandleRegistration.ts
168
+ function useAssessmentHandleRegistration(checkId, handle, ref) {
169
+ (0, import_react6.useImperativeHandle)(ref, () => handle, [handle]);
170
+ useRegisterAssessmentHandle(checkId, handle);
171
+ }
172
+
173
+ // src/assessment/internal/usePluginScoring.ts
174
+ var import_react11 = require("react");
175
+
176
+ // src/hooks.ts
177
+ var import_react10 = require("react");
178
+
179
+ // src/context.tsx
180
+ var import_react8 = require("react");
181
+
182
+ // src/provider/useLessonkitProviderRuntime.ts
183
+ var import_react7 = require("react");
184
+ var import_core10 = require("@lessonkit/core");
185
+
186
+ // src/runtime/observability.ts
187
+ var import_xapi = require("@lessonkit/xapi");
188
+
189
+ // src/runtime/emitTelemetry.ts
190
+ var import_core4 = require("@lessonkit/core");
191
+
192
+ // src/runtime/telemetryPipeline.ts
193
+ var import_core3 = require("@lessonkit/core");
194
+ var import_xapi2 = require("@lessonkit/xapi");
195
+
196
+ // src/runtime/lxpackBridge.ts
197
+ var import_bridge = require("@lessonkit/lxpack/bridge");
198
+
199
+ // src/runtime/courseStartedPipeline.ts
200
+ var import_xapi3 = require("@lessonkit/xapi");
201
+
202
+ // src/runtime/plugins.ts
203
+ var import_core5 = require("@lessonkit/core");
204
+ function buildPluginContext(opts) {
205
+ return (0, import_core5.buildPluginContext)(opts);
206
+ }
207
+
208
+ // src/runtime/session.ts
209
+ var import_core6 = require("@lessonkit/core");
210
+
211
+ // src/provider/courseStarted/emit.ts
212
+ function createCourseStartedFlightScope() {
213
+ return {
214
+ trackingFlights: /* @__PURE__ */ new Map(),
215
+ emitFlights: /* @__PURE__ */ new Map()
216
+ };
217
+ }
218
+ var defaultFlightScope = createCourseStartedFlightScope();
219
+ function resetCourseStartedTrackingFlightForTests() {
220
+ defaultFlightScope.trackingFlights.clear();
221
+ defaultFlightScope.emitFlights.clear();
222
+ }
223
+
224
+ // src/provider/useLessonkitProviderRuntime.ts
225
+ var import_xapi5 = require("@lessonkit/xapi");
226
+
227
+ // src/runtime/ports.ts
228
+ var import_core7 = require("@lessonkit/core");
229
+
230
+ // src/provider/useLessonkitProviderRuntime.ts
231
+ var import_core11 = require("@lessonkit/core");
232
+
233
+ // src/runtime/progress.ts
234
+ var import_core8 = require("@lessonkit/core");
235
+
236
+ // src/runtime/xapi.ts
237
+ var import_xapi4 = require("@lessonkit/xapi");
238
+
239
+ // src/runtime/telemetry.ts
240
+ var import_core9 = require("@lessonkit/core");
241
+
242
+ // src/provider/useLessonkitProviderRuntime.ts
243
+ var providerStoragesForTests = /* @__PURE__ */ new Set();
244
+ function resetLessonkitProviderStorageForTests() {
245
+ for (const storage of providerStoragesForTests) {
246
+ (0, import_core7.resetStoragePortForTests)(storage);
247
+ }
248
+ providerStoragesForTests.clear();
249
+ (0, import_core11.resetSharedVolatileSessionIdForTests)();
250
+ }
251
+
252
+ // src/context.tsx
253
+ var import_jsx_runtime5 = require("react/jsx-runtime");
254
+ var LessonkitContext = (0, import_react8.createContext)(null);
255
+
256
+ // src/assessment/useAssessmentState.ts
257
+ var import_react9 = require("react");
258
+
259
+ // src/hooks.ts
260
+ function useLessonkit() {
261
+ const ctx = (0, import_react10.useContext)(LessonkitContext);
262
+ if (!ctx) throw new Error("LessonKit: missing LessonkitProvider");
263
+ return ctx;
264
+ }
265
+ function useQuizState(enclosingLessonId) {
266
+ const { track } = useLessonkit();
267
+ const trackOpts = enclosingLessonId ? { lessonId: enclosingLessonId } : void 0;
268
+ return (0, import_react10.useMemo)(
269
+ () => ({
270
+ answer: (opts) => {
271
+ track("quiz_answered", opts, trackOpts);
272
+ },
273
+ complete: (opts) => {
274
+ track("quiz_completed", opts, trackOpts);
275
+ }
276
+ }),
277
+ [track, enclosingLessonId]
278
+ );
279
+ }
280
+
281
+ // src/assessment/scoring.ts
282
+ function resolvePassingThreshold(passingScore, maxScore) {
283
+ return passingScore ?? maxScore;
284
+ }
285
+ function meetsPassingThreshold(score, maxScore, passingScore) {
286
+ const threshold = resolvePassingThreshold(passingScore, maxScore);
287
+ return score >= threshold;
288
+ }
289
+ function scoreFromCustom(custom, fallbackCorrect, fallbackMax = 1, passingScore) {
290
+ const maxScore = custom?.maxScore ?? fallbackMax;
291
+ const hasNumericScore = custom?.score != null && Number.isFinite(custom.score);
292
+ if (hasNumericScore) {
293
+ const passed2 = custom.passed !== void 0 ? custom.passed : meetsPassingThreshold(custom.score, maxScore, passingScore);
294
+ return { score: custom.score, maxScore, passed: passed2 };
295
+ }
296
+ if (custom?.passed !== void 0) {
297
+ const score2 = custom.passed ? maxScore : 0;
298
+ return { score: score2, maxScore, passed: custom.passed };
299
+ }
300
+ const score = fallbackCorrect ? maxScore : 0;
301
+ const passed = meetsPassingThreshold(score, maxScore, passingScore);
302
+ return { score, maxScore, passed };
303
+ }
304
+
305
+ // src/assessment/internal/usePluginScoring.ts
306
+ function usePluginScoring(checkId, lessonId) {
307
+ const { plugins, config, session } = useLessonkit();
308
+ const getPluginScore = (0, import_react11.useCallback)(
309
+ (response) => {
310
+ const pluginCtx = buildPluginContext({
311
+ courseId: config.courseId,
312
+ sessionId: session.sessionId,
313
+ attemptId: session.attemptId,
314
+ user: session.user
315
+ });
316
+ return plugins?.scoreAssessment({ checkId, lessonId, response }, pluginCtx) ?? null;
317
+ },
318
+ [checkId, config.courseId, lessonId, plugins, session.attemptId, session.sessionId, session.user]
319
+ );
320
+ const scoreResponse = (0, import_react11.useCallback)(
321
+ (response, defaultCorrect, maxScore = 1, passingScore) => scoreFromCustom(getPluginScore(response), defaultCorrect, maxScore, passingScore),
322
+ [getPluginScore]
323
+ );
324
+ const isChoiceCorrect = (0, import_react11.useCallback)(
325
+ (choice, answer, custom, passingScore) => {
326
+ if (!custom) return choice === answer;
327
+ if (custom.passed !== void 0) return custom.passed;
328
+ if (custom.maxScore != null && custom.maxScore > 0 && custom.score != null) {
329
+ return meetsPassingThreshold(custom.score, custom.maxScore, passingScore);
330
+ }
331
+ return choice === answer;
332
+ },
333
+ []
334
+ );
335
+ return { getPluginScore, scoreResponse, isChoiceCorrect };
336
+ }
337
+
338
+ // src/components/Quiz.tsx
339
+ var import_jsx_runtime6 = require("react/jsx-runtime");
340
+ function QuizInner(props, ref) {
341
+ const { enclosingLessonId } = props;
342
+ const checkId = (0, import_react12.useMemo)(() => normalizeComponentId(props.checkId, "checkId"), [props.checkId]);
343
+ const quiz = useQuizState(enclosingLessonId);
344
+ const { config } = useLessonkit();
345
+ const { scoreResponse } = usePluginScoring(checkId, enclosingLessonId);
346
+ const [selected, setSelected] = (0, import_react12.useState)(null);
347
+ const [selectionCorrect, setSelectionCorrect] = (0, import_react12.useState)(null);
348
+ const [quizPassed, setQuizPassed] = (0, import_react12.useState)(false);
349
+ const [completedScore, setCompletedScore] = (0, import_react12.useState)(null);
350
+ const [completedMaxScore, setCompletedMaxScore] = (0, import_react12.useState)(null);
351
+ const completedRef = (0, import_react12.useRef)(false);
352
+ const telemetryReplayedRef = (0, import_react12.useRef)(false);
353
+ const questionId = (0, import_react12.useId)();
354
+ const choicesKey = props.choices.join("\0");
355
+ (0, import_react12.useEffect)(() => {
356
+ completedRef.current = false;
357
+ telemetryReplayedRef.current = false;
358
+ setQuizPassed(false);
359
+ setSelected(null);
360
+ setSelectionCorrect(null);
361
+ setCompletedScore(null);
362
+ setCompletedMaxScore(null);
363
+ }, [checkId, props.answer, props.question, choicesKey]);
364
+ const passed = quizPassed;
365
+ const resolveScores = () => {
366
+ const maxScore = completedMaxScore ?? 1;
367
+ if (quizPassed) {
368
+ return { score: completedScore ?? maxScore, maxScore };
369
+ }
370
+ if (selected !== null && selectionCorrect) {
371
+ return { score: completedMaxScore ?? maxScore, maxScore };
372
+ }
373
+ return { score: 0, maxScore };
374
+ };
375
+ const replayTelemetry = (nextSelected, nextCorrect, nextPassed, nextScore, nextMaxScore) => {
376
+ if (!nextPassed || telemetryReplayedRef.current) return;
377
+ telemetryReplayedRef.current = true;
378
+ if (nextSelected !== null) {
379
+ quiz.answer({
380
+ checkId,
381
+ question: props.question,
382
+ choice: nextSelected,
383
+ correct: nextCorrect ?? false
384
+ });
385
+ }
386
+ quiz.complete({
387
+ checkId,
388
+ score: nextScore,
389
+ maxScore: nextMaxScore,
390
+ passingScore: props.passingScore ?? nextMaxScore
391
+ });
392
+ };
393
+ const handle = (0, import_react12.useMemo)(
394
+ () => buildAssessmentHandle({
395
+ checkId,
396
+ getScore: () => resolveScores().score,
397
+ getMaxScore: () => resolveScores().maxScore,
398
+ getAnswerGiven: () => selected !== null,
399
+ resetTask: () => {
400
+ completedRef.current = false;
401
+ telemetryReplayedRef.current = false;
402
+ setQuizPassed(false);
403
+ setSelected(null);
404
+ setSelectionCorrect(null);
405
+ setCompletedScore(null);
406
+ setCompletedMaxScore(null);
407
+ },
408
+ showSolutions: () => {
409
+ },
410
+ getXAPIData: () => {
411
+ const { score, maxScore } = resolveScores();
412
+ return {
413
+ checkId,
414
+ interactionType: "mcq",
415
+ response: selected ?? void 0,
416
+ correct: selectionCorrect ?? void 0,
417
+ score,
418
+ maxScore
419
+ };
420
+ },
421
+ getCurrentState: () => ({
422
+ selected,
423
+ selectionCorrect,
424
+ quizPassed,
425
+ completedScore,
426
+ completedMaxScore
427
+ }),
428
+ resume: (state) => {
429
+ const nextSelected = readStringField(state, "selected");
430
+ if (typeof nextSelected === "string" || nextSelected === null) setSelected(nextSelected);
431
+ const nextCorrect = readBooleanField(state, "selectionCorrect");
432
+ if (nextCorrect === true || nextCorrect === false || nextCorrect === null) {
433
+ setSelectionCorrect(nextCorrect);
434
+ }
435
+ const nextCompletedScore = readNumberField(state, "completedScore");
436
+ if (typeof nextCompletedScore === "number") setCompletedScore(nextCompletedScore);
437
+ const nextCompletedMaxScore = readNumberField(state, "completedMaxScore");
438
+ if (typeof nextCompletedMaxScore === "number") setCompletedMaxScore(nextCompletedMaxScore);
439
+ const nextPassed = readBooleanField(state, "quizPassed");
440
+ if (nextPassed === true || nextPassed === false) {
441
+ setQuizPassed(nextPassed);
442
+ completedRef.current = nextPassed;
443
+ if (nextPassed && config.tracking?.replayResumeEvents === true) {
444
+ const maxScore = nextCompletedMaxScore ?? 1;
445
+ const score = nextCompletedScore ?? (nextPassed ? maxScore : 0);
446
+ replayTelemetry(
447
+ nextSelected ?? null,
448
+ nextCorrect ?? null,
449
+ nextPassed,
450
+ score,
451
+ maxScore
452
+ );
453
+ }
454
+ }
455
+ }
456
+ }),
457
+ [
458
+ checkId,
459
+ completedMaxScore,
460
+ completedScore,
461
+ config.tracking?.replayResumeEvents,
462
+ props.passingScore,
463
+ props.question,
464
+ quiz,
465
+ quizPassed,
466
+ selected,
467
+ selectionCorrect
468
+ ]
469
+ );
470
+ useAssessmentHandleRegistration(checkId, handle, ref);
471
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("section", { "aria-label": "Quiz", "data-lk-check-id": checkId, children: [
472
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { id: questionId, children: props.question }),
473
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("fieldset", { "aria-labelledby": questionId, children: [
474
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("legend", { style: import_accessibility.visuallyHiddenStyle, children: "Quiz choices" }),
475
+ props.choices.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { style: { display: "block" }, children: [
476
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
477
+ "input",
478
+ {
479
+ type: "radio",
480
+ name: questionId,
481
+ value: c,
482
+ checked: selected === c,
483
+ disabled: passed && !props.enableRetry,
484
+ "aria-invalid": selected === c && selectionCorrect === false ? true : void 0,
485
+ onChange: () => {
486
+ if (passed && !props.enableRetry) return;
487
+ setSelected(c);
488
+ const defaultCorrect = c === props.answer;
489
+ const scored = scoreResponse(c, defaultCorrect, 1, props.passingScore);
490
+ setSelectionCorrect(scored.passed);
491
+ quiz.answer({
492
+ checkId,
493
+ question: props.question,
494
+ choice: c,
495
+ correct: scored.passed
496
+ });
497
+ if (scored.passed && !completedRef.current) {
498
+ completedRef.current = true;
499
+ setQuizPassed(true);
500
+ setCompletedScore(scored.score);
501
+ setCompletedMaxScore(scored.maxScore);
502
+ quiz.complete({
503
+ checkId,
504
+ score: scored.score,
505
+ maxScore: scored.maxScore,
506
+ passingScore: props.passingScore ?? scored.maxScore
507
+ });
508
+ } else if (!scored.passed && props.enableRetry === false && !completedRef.current) {
509
+ completedRef.current = true;
510
+ setCompletedScore(scored.score);
511
+ setCompletedMaxScore(scored.maxScore);
512
+ quiz.complete({
513
+ checkId,
514
+ score: scored.score,
515
+ maxScore: scored.maxScore,
516
+ passingScore: props.passingScore ?? scored.maxScore
517
+ });
518
+ }
519
+ }
520
+ }
521
+ ),
522
+ c
523
+ ] }, `${questionId}-${i}`))
524
+ ] }),
525
+ selected && selectionCorrect !== null ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { role: "status", "aria-live": "polite", children: selectionCorrect ? "Correct" : "Try again" }) : null,
526
+ props.enableRetry && passed ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
527
+ "button",
528
+ {
529
+ type: "button",
530
+ "data-testid": "quiz-retry",
531
+ onClick: () => {
532
+ completedRef.current = false;
533
+ telemetryReplayedRef.current = false;
534
+ setQuizPassed(false);
535
+ setSelected(null);
536
+ setSelectionCorrect(null);
537
+ setCompletedScore(null);
538
+ setCompletedMaxScore(null);
539
+ },
540
+ children: "Try again"
541
+ }
542
+ ) : null
543
+ ] });
544
+ }
545
+ var QuizInnerForwarded = (0, import_react12.forwardRef)(QuizInner);
546
+ var Quiz = (0, import_react12.forwardRef)(function Quiz2(props, ref) {
547
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(AssessmentLessonGuard, { blockLabel: "Quiz", checkId: props.checkId, children: (lessonId) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(QuizInnerForwarded, { ...props, enclosingLessonId: lessonId, ref }) });
548
+ });
549
+ function resetQuizWarningsForTests() {
550
+ resetAssessmentWarningsForTests();
551
+ }
552
+
553
+ // src/runtime/lessonMountRegistry.ts
554
+ var mountCounts = /* @__PURE__ */ new Map();
555
+ var warnedConcurrentLessons = false;
556
+ function resetLessonMountRegistryForTests() {
557
+ mountCounts.clear();
558
+ warnedConcurrentLessons = false;
559
+ }
560
+
561
+ // src/compound/validateChildren.ts
562
+ var import_react13 = __toESM(require("react"), 1);
563
+ var import_core12 = require("@lessonkit/core");
564
+ var warnedPairs = /* @__PURE__ */ new Set();
565
+ function resetCompoundValidationWarningsForTests() {
566
+ warnedPairs.clear();
567
+ }
568
+ // Annotate the CommonJS export names for ESM import in node:
569
+ 0 && (module.exports = {
570
+ resetAssessmentWarningsForTests,
571
+ resetCompoundValidationWarningsForTests,
572
+ resetCourseStartedTrackingFlightForTests,
573
+ resetLessonMountRegistryForTests,
574
+ resetLessonkitProviderStorageForTests,
575
+ resetQuizWarningsForTests
576
+ });
@@ -0,0 +1,16 @@
1
+ export { r as resetAssessmentWarningsForTests, a as resetQuizWarningsForTests } from './AssessmentLessonGuard-BzNPbjaV.cjs';
2
+ import '@lessonkit/core';
3
+ import 'react';
4
+
5
+ /** Reset registry state between tests. */
6
+ declare function resetLessonMountRegistryForTests(): void;
7
+
8
+ /** @internal Reset dev warnings between tests. */
9
+ declare function resetCompoundValidationWarningsForTests(): void;
10
+
11
+ /** @internal Reset in-flight course_started tracking guard between tests. */
12
+ declare function resetCourseStartedTrackingFlightForTests(): void;
13
+
14
+ declare function resetLessonkitProviderStorageForTests(): void;
15
+
16
+ export { resetCompoundValidationWarningsForTests, resetCourseStartedTrackingFlightForTests, resetLessonMountRegistryForTests, resetLessonkitProviderStorageForTests };
@@ -0,0 +1,16 @@
1
+ export { r as resetAssessmentWarningsForTests, a as resetQuizWarningsForTests } from './AssessmentLessonGuard-BzNPbjaV.js';
2
+ import '@lessonkit/core';
3
+ import 'react';
4
+
5
+ /** Reset registry state between tests. */
6
+ declare function resetLessonMountRegistryForTests(): void;
7
+
8
+ /** @internal Reset dev warnings between tests. */
9
+ declare function resetCompoundValidationWarningsForTests(): void;
10
+
11
+ /** @internal Reset in-flight course_started tracking guard between tests. */
12
+ declare function resetCourseStartedTrackingFlightForTests(): void;
13
+
14
+ declare function resetLessonkitProviderStorageForTests(): void;
15
+
16
+ export { resetCompoundValidationWarningsForTests, resetCourseStartedTrackingFlightForTests, resetLessonMountRegistryForTests, resetLessonkitProviderStorageForTests };
@@ -0,0 +1,18 @@
1
+ import {
2
+ resetLessonMountRegistryForTests,
3
+ resetQuizWarningsForTests
4
+ } from "./chunk-ELGQ4XI3.js";
5
+ import {
6
+ resetAssessmentWarningsForTests,
7
+ resetCompoundValidationWarningsForTests,
8
+ resetCourseStartedTrackingFlightForTests,
9
+ resetLessonkitProviderStorageForTests
10
+ } from "./chunk-7TJQJFYR.js";
11
+ export {
12
+ resetAssessmentWarningsForTests,
13
+ resetCompoundValidationWarningsForTests,
14
+ resetCourseStartedTrackingFlightForTests,
15
+ resetLessonMountRegistryForTests,
16
+ resetLessonkitProviderStorageForTests,
17
+ resetQuizWarningsForTests
18
+ };