@lessonkit/react 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/block-catalog.v1.json +6 -0
- package/dist/index.cjs +110 -63
- package/dist/index.d.cts +239 -35
- package/dist/index.d.ts +239 -35
- package/dist/index.js +110 -61
- package/package.json +6 -6
package/block-catalog.v1.json
CHANGED
|
@@ -247,6 +247,12 @@
|
|
|
247
247
|
"type": "string",
|
|
248
248
|
"required": true,
|
|
249
249
|
"description": "Correct choice value (must match one choice)."
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
"name": "passingScore",
|
|
253
|
+
"type": "number",
|
|
254
|
+
"required": false,
|
|
255
|
+
"description": "Minimum score required to pass (defaults to maxScore when omitted)."
|
|
250
256
|
}
|
|
251
257
|
],
|
|
252
258
|
"requiredIds": [
|
package/dist/index.cjs
CHANGED
|
@@ -70,8 +70,8 @@ var import_react2 = require("react");
|
|
|
70
70
|
// src/provider/useLessonkitProviderRuntime.ts
|
|
71
71
|
var import_react = require("react");
|
|
72
72
|
var import_core8 = require("@lessonkit/core");
|
|
73
|
-
var import_xapi3 = require("@lessonkit/xapi");
|
|
74
73
|
var import_xapi4 = require("@lessonkit/xapi");
|
|
74
|
+
var import_xapi5 = require("@lessonkit/xapi");
|
|
75
75
|
|
|
76
76
|
// src/runtime/emitTelemetry.ts
|
|
77
77
|
var import_core2 = require("@lessonkit/core");
|
|
@@ -169,6 +169,29 @@ function createXapiClientFromConfig(config, queue) {
|
|
|
169
169
|
// src/runtime/session.ts
|
|
170
170
|
var import_core5 = require("@lessonkit/core");
|
|
171
171
|
|
|
172
|
+
// src/runtime/courseStartedPipeline.ts
|
|
173
|
+
var import_xapi3 = require("@lessonkit/xapi");
|
|
174
|
+
function emitCourseStartedNonTrackingPipeline(opts) {
|
|
175
|
+
let xapiStatementSent = false;
|
|
176
|
+
if (!opts.skipXapi && opts.xapi) {
|
|
177
|
+
const statement = (0, import_xapi3.telemetryEventToXAPIStatement)(opts.event);
|
|
178
|
+
if (statement) {
|
|
179
|
+
opts.xapi.send(statement);
|
|
180
|
+
xapiStatementSent = true;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
forwardTelemetryToLxpack(opts.event, opts.lxpackBridge);
|
|
184
|
+
const emitCtx = {
|
|
185
|
+
courseId: opts.event.courseId,
|
|
186
|
+
sessionId: opts.event.sessionId,
|
|
187
|
+
attemptId: opts.event.attemptId
|
|
188
|
+
};
|
|
189
|
+
for (const sink of opts.extraSinks ?? []) {
|
|
190
|
+
sink.emit(opts.event, emitCtx);
|
|
191
|
+
}
|
|
192
|
+
return { xapiStatementSent };
|
|
193
|
+
}
|
|
194
|
+
|
|
172
195
|
// src/runtime/plugins.ts
|
|
173
196
|
var import_core6 = require("@lessonkit/core");
|
|
174
197
|
function createReactPluginHost(plugins) {
|
|
@@ -220,8 +243,9 @@ var defaultStorage = (0, import_core3.createSessionStoragePort)();
|
|
|
220
243
|
function isTrackingActive(tracking) {
|
|
221
244
|
return tracking?.enabled !== false;
|
|
222
245
|
}
|
|
223
|
-
|
|
224
|
-
|
|
246
|
+
function isCourseStartedSinkSettled(result) {
|
|
247
|
+
return result === "emitted";
|
|
248
|
+
}
|
|
225
249
|
function buildCourseStartedEvent(opts) {
|
|
226
250
|
const pluginCtx = buildPluginContext({
|
|
227
251
|
courseId: opts.courseId,
|
|
@@ -239,31 +263,27 @@ function buildCourseStartedEvent(opts) {
|
|
|
239
263
|
return opts.pluginHost ? opts.pluginHost.runTelemetry(built, pluginCtx) : built;
|
|
240
264
|
}
|
|
241
265
|
function emitCourseStartedPipelineOnly(opts) {
|
|
242
|
-
const pluginCtx = buildPluginContext({
|
|
243
|
-
courseId: opts.courseId,
|
|
244
|
-
sessionId: opts.sessionId,
|
|
245
|
-
attemptId: opts.attemptId,
|
|
246
|
-
user: opts.user
|
|
247
|
-
});
|
|
248
266
|
try {
|
|
249
|
-
|
|
250
|
-
pluginHost: null,
|
|
251
|
-
tracking: noopTrackingClient,
|
|
252
|
-
xapi: opts.xapi,
|
|
267
|
+
const { xapiStatementSent } = emitCourseStartedNonTrackingPipeline({
|
|
253
268
|
event: opts.event,
|
|
254
|
-
|
|
269
|
+
xapi: opts.xapi,
|
|
255
270
|
lxpackBridge: opts.lxpackBridge,
|
|
256
|
-
extraSinks: opts.extraSinks
|
|
271
|
+
extraSinks: opts.extraSinks,
|
|
272
|
+
skipXapi: opts.skipXapi
|
|
257
273
|
});
|
|
258
274
|
(0, import_core5.markCourseStarted)(opts.storage, opts.sessionId, opts.courseId);
|
|
259
|
-
|
|
275
|
+
(0, import_core5.markCourseStartedPipelineDelivered)(opts.storage, opts.sessionId, opts.courseId);
|
|
276
|
+
if (xapiStatementSent) {
|
|
277
|
+
opts.onXapiStatementSent?.();
|
|
278
|
+
}
|
|
279
|
+
return "emitted";
|
|
260
280
|
} catch {
|
|
261
|
-
return
|
|
281
|
+
return "failed";
|
|
262
282
|
}
|
|
263
283
|
}
|
|
264
284
|
function emitCourseStarted(opts) {
|
|
265
285
|
const event = buildCourseStartedEvent(opts);
|
|
266
|
-
if (event === null) return
|
|
286
|
+
if (event === null) return "filtered";
|
|
267
287
|
const trackingAlreadyEmitted = (0, import_core5.hasCourseStartedEmittedToTracking)(
|
|
268
288
|
opts.storage,
|
|
269
289
|
opts.sessionId,
|
|
@@ -274,14 +294,19 @@ function emitCourseStarted(opts) {
|
|
|
274
294
|
opts.tracking.track(event);
|
|
275
295
|
(0, import_core5.markCourseStartedEmittedToTracking)(opts.storage, opts.sessionId, opts.courseId);
|
|
276
296
|
} catch {
|
|
277
|
-
return
|
|
297
|
+
return "failed";
|
|
278
298
|
}
|
|
279
299
|
}
|
|
280
|
-
return emitCourseStartedPipelineOnly({
|
|
300
|
+
return emitCourseStartedPipelineOnly({
|
|
301
|
+
...opts,
|
|
302
|
+
event,
|
|
303
|
+
skipXapi: opts.skipXapi,
|
|
304
|
+
onXapiStatementSent: opts.onXapiStatementSent
|
|
305
|
+
});
|
|
281
306
|
}
|
|
282
307
|
function emitCourseStartedToTrackingOnly(opts) {
|
|
283
308
|
const event = buildCourseStartedEvent(opts);
|
|
284
|
-
if (event === null) return
|
|
309
|
+
if (event === null) return "filtered";
|
|
285
310
|
const trackingAlreadyEmitted = (0, import_core5.hasCourseStartedEmittedToTracking)(
|
|
286
311
|
opts.storage,
|
|
287
312
|
opts.sessionId,
|
|
@@ -292,28 +317,21 @@ function emitCourseStartedToTrackingOnly(opts) {
|
|
|
292
317
|
opts.tracking.track(event);
|
|
293
318
|
(0, import_core5.markCourseStartedEmittedToTracking)(opts.storage, opts.sessionId, opts.courseId);
|
|
294
319
|
} catch {
|
|
295
|
-
return
|
|
320
|
+
return "failed";
|
|
296
321
|
}
|
|
297
322
|
}
|
|
298
|
-
const pluginCtx = buildPluginContext({
|
|
299
|
-
courseId: opts.courseId,
|
|
300
|
-
sessionId: opts.sessionId,
|
|
301
|
-
attemptId: opts.attemptId,
|
|
302
|
-
user: opts.user
|
|
303
|
-
});
|
|
304
323
|
try {
|
|
305
|
-
|
|
306
|
-
pluginHost: null,
|
|
307
|
-
tracking: noopTrackingClient,
|
|
308
|
-
xapi: null,
|
|
324
|
+
emitCourseStartedNonTrackingPipeline({
|
|
309
325
|
event,
|
|
310
|
-
|
|
326
|
+
xapi: null,
|
|
311
327
|
lxpackBridge: opts.lxpackBridge,
|
|
312
|
-
extraSinks: opts.extraSinks
|
|
328
|
+
extraSinks: opts.extraSinks,
|
|
329
|
+
skipXapi: true
|
|
313
330
|
});
|
|
314
|
-
|
|
331
|
+
(0, import_core5.markCourseStartedPipelineDelivered)(opts.storage, opts.sessionId, opts.courseId);
|
|
332
|
+
return "emitted";
|
|
315
333
|
} catch {
|
|
316
|
-
return
|
|
334
|
+
return "failed";
|
|
317
335
|
}
|
|
318
336
|
}
|
|
319
337
|
function emitPendingCourseStarted(opts) {
|
|
@@ -328,13 +346,28 @@ function emitPendingCourseStarted(opts) {
|
|
|
328
346
|
}
|
|
329
347
|
if (trackingEmitted && !sessionStarted) {
|
|
330
348
|
const event = buildCourseStartedEvent(opts);
|
|
331
|
-
if (event === null) return
|
|
349
|
+
if (event === null) return "filtered";
|
|
332
350
|
return emitCourseStartedPipelineOnly({ ...opts, event });
|
|
333
351
|
}
|
|
334
352
|
if (!trackingEmitted && !sessionStarted) {
|
|
335
353
|
return emitCourseStarted(opts);
|
|
336
354
|
}
|
|
337
|
-
|
|
355
|
+
const pipelineDelivered = (0, import_core5.hasCourseStartedPipelineDelivered)(
|
|
356
|
+
opts.storage,
|
|
357
|
+
opts.sessionId,
|
|
358
|
+
opts.courseId
|
|
359
|
+
);
|
|
360
|
+
if (sessionStarted && trackingEmitted && !pipelineDelivered) {
|
|
361
|
+
const event = buildCourseStartedEvent(opts);
|
|
362
|
+
if (event === null) return "filtered";
|
|
363
|
+
return emitCourseStartedPipelineOnly({
|
|
364
|
+
...opts,
|
|
365
|
+
event,
|
|
366
|
+
skipXapi: opts.skipXapi,
|
|
367
|
+
onXapiStatementSent: opts.onXapiStatementSent
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
return "emitted";
|
|
338
371
|
}
|
|
339
372
|
function assertTrackingSinkConfig(tracking) {
|
|
340
373
|
if (!tracking?.sink || !tracking?.batchSink) return;
|
|
@@ -421,7 +454,7 @@ function useLessonkitProviderRuntime(config) {
|
|
|
421
454
|
}, []);
|
|
422
455
|
const activeLessonIdRef = (0, import_react.useRef)(progress.activeLessonId);
|
|
423
456
|
activeLessonIdRef.current = progress.activeLessonId;
|
|
424
|
-
const xapiQueueRef = (0, import_react.useRef)((0,
|
|
457
|
+
const xapiQueueRef = (0, import_react.useRef)((0, import_xapi4.createInMemoryXAPIQueue)());
|
|
425
458
|
const xapiRef = (0, import_react.useRef)(null);
|
|
426
459
|
const [xapi, setXapi] = (0, import_react.useState)(null);
|
|
427
460
|
const prevXapiCourseIdRef = (0, import_react.useRef)(normalizedCourseId);
|
|
@@ -442,7 +475,7 @@ function useLessonkitProviderRuntime(config) {
|
|
|
442
475
|
}
|
|
443
476
|
void xapiRef.current?.flush();
|
|
444
477
|
}
|
|
445
|
-
xapiQueueRef.current = (0,
|
|
478
|
+
xapiQueueRef.current = (0, import_xapi4.createInMemoryXAPIQueue)();
|
|
446
479
|
prevXapiCourseIdRef.current = courseId;
|
|
447
480
|
xapiCourseStartedSentOnClientRef.current = false;
|
|
448
481
|
}
|
|
@@ -460,21 +493,24 @@ function useLessonkitProviderRuntime(config) {
|
|
|
460
493
|
const needsBootstrap = !skipBootstrap && !xapiCourseStartedSentOnClientRef.current && (!alreadyStarted || clientChanged);
|
|
461
494
|
if (needsBootstrap) {
|
|
462
495
|
try {
|
|
463
|
-
const
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
)
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
if (
|
|
475
|
-
|
|
496
|
+
const event = buildCourseStartedEvent({
|
|
497
|
+
pluginHost: pluginHostRef.current,
|
|
498
|
+
courseId: cid,
|
|
499
|
+
sessionId,
|
|
500
|
+
attemptId: attemptIdRef.current,
|
|
501
|
+
user: userRef.current,
|
|
502
|
+
lxpackBridge: lxpackBridgeModeRef.current
|
|
503
|
+
});
|
|
504
|
+
if (event === null) {
|
|
505
|
+
} else {
|
|
506
|
+
const statement = (0, import_xapi5.telemetryEventToXAPIStatement)(event);
|
|
507
|
+
if (statement) {
|
|
508
|
+
next.send(statement);
|
|
509
|
+
if (!alreadyStarted) {
|
|
510
|
+
(0, import_core5.markCourseStarted)(defaultStorage, sessionId, cid);
|
|
511
|
+
}
|
|
512
|
+
xapiCourseStartedSentOnClientRef.current = true;
|
|
476
513
|
}
|
|
477
|
-
xapiCourseStartedSentOnClientRef.current = true;
|
|
478
514
|
}
|
|
479
515
|
} catch {
|
|
480
516
|
}
|
|
@@ -548,7 +584,7 @@ function useLessonkitProviderRuntime(config) {
|
|
|
548
584
|
if (!trackingActive) {
|
|
549
585
|
courseStartedEmittedToSinkRef.current = false;
|
|
550
586
|
} else if (!courseStartedEmittedToSinkRef.current) {
|
|
551
|
-
const
|
|
587
|
+
const result = emitPendingCourseStarted({
|
|
552
588
|
pluginHost: pluginHostRef.current,
|
|
553
589
|
tracking: next,
|
|
554
590
|
xapi: xapiRef.current,
|
|
@@ -558,12 +594,13 @@ function useLessonkitProviderRuntime(config) {
|
|
|
558
594
|
attemptId: attemptIdRef.current,
|
|
559
595
|
user: userRef.current,
|
|
560
596
|
lxpackBridge: lxpackBridgeModeRef.current,
|
|
561
|
-
extraSinks: extraSinksRef.current
|
|
597
|
+
extraSinks: extraSinksRef.current,
|
|
598
|
+
skipXapi: xapiCourseStartedSentOnClientRef.current,
|
|
599
|
+
onXapiStatementSent: () => {
|
|
600
|
+
xapiCourseStartedSentOnClientRef.current = true;
|
|
601
|
+
}
|
|
562
602
|
});
|
|
563
|
-
|
|
564
|
-
(0, import_core5.markCourseStartedEmittedToTracking)(defaultStorage, sessionId, cid);
|
|
565
|
-
}
|
|
566
|
-
courseStartedEmittedToSinkRef.current = emitted;
|
|
603
|
+
courseStartedEmittedToSinkRef.current = isCourseStartedSinkSettled(result);
|
|
567
604
|
} else if (trackingActive) {
|
|
568
605
|
courseStartedEmittedToSinkRef.current = true;
|
|
569
606
|
}
|
|
@@ -644,7 +681,7 @@ function useLessonkitProviderRuntime(config) {
|
|
|
644
681
|
} catch {
|
|
645
682
|
}
|
|
646
683
|
if (!courseStartedEmittedToSinkRef.current) {
|
|
647
|
-
const
|
|
684
|
+
const result = emitPendingCourseStarted({
|
|
648
685
|
pluginHost: pluginHostRef.current,
|
|
649
686
|
tracking: trackingRef.current,
|
|
650
687
|
xapi: xapiRef.current,
|
|
@@ -656,7 +693,7 @@ function useLessonkitProviderRuntime(config) {
|
|
|
656
693
|
lxpackBridge: lxpackBridgeModeRef.current,
|
|
657
694
|
extraSinks: extraSinksRef.current
|
|
658
695
|
});
|
|
659
|
-
courseStartedEmittedToSinkRef.current =
|
|
696
|
+
courseStartedEmittedToSinkRef.current = isCourseStartedSinkSettled(result);
|
|
660
697
|
}
|
|
661
698
|
})();
|
|
662
699
|
}, [normalizedCourseId, normalizedConfig.tracking?.enabled, syncProgress]);
|
|
@@ -893,6 +930,10 @@ function isDevEnvironment3() {
|
|
|
893
930
|
return typeof g.process !== "undefined" && g.process.env?.NODE_ENV !== "production";
|
|
894
931
|
}
|
|
895
932
|
function normalizeComponentId(id, path) {
|
|
933
|
+
if (path === "courseId") return (0, import_core9.assertValidId)(id, "courseId");
|
|
934
|
+
if (path === "lessonId") return (0, import_core9.assertValidId)(id, "lessonId");
|
|
935
|
+
if (path === "checkId") return (0, import_core9.assertValidId)(id, "checkId");
|
|
936
|
+
if (path === "blockId") return (0, import_core9.assertValidId)(id, "blockId");
|
|
896
937
|
return (0, import_core9.assertValidId)(id, path);
|
|
897
938
|
}
|
|
898
939
|
|
|
@@ -1386,7 +1427,13 @@ var BLOCK_CATALOG = [
|
|
|
1386
1427
|
{ name: "checkId", type: "CheckId", required: true, description: "Stable check identifier for telemetry and LXPack assessments." },
|
|
1387
1428
|
{ name: "question", type: "string", required: true, description: "Question text shown above choices." },
|
|
1388
1429
|
{ name: "choices", type: "string[]", required: true, description: "Radio button choice labels." },
|
|
1389
|
-
{ name: "answer", type: "string", required: true, description: "Correct choice value (must match one choice)." }
|
|
1430
|
+
{ name: "answer", type: "string", required: true, description: "Correct choice value (must match one choice)." },
|
|
1431
|
+
{
|
|
1432
|
+
name: "passingScore",
|
|
1433
|
+
type: "number",
|
|
1434
|
+
required: false,
|
|
1435
|
+
description: "Minimum score required to pass (defaults to maxScore when omitted)."
|
|
1436
|
+
}
|
|
1390
1437
|
],
|
|
1391
1438
|
requiredIds: ["checkId"],
|
|
1392
1439
|
parentConstraints: ["Lesson"],
|
package/dist/index.d.cts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import * as _lessonkit_core from '@lessonkit/core';
|
|
4
|
-
import { CourseId, TelemetryUser, TrackingClient, LessonkitPlugin, ProgressState, LessonId, TelemetryEventName,
|
|
4
|
+
import { CourseId, TelemetryUser, TrackingClient, LessonkitPlugin, ProgressState, LessonId, TelemetryEventName, TelemetryDataFor, PluginHost, BlockId, CheckId } from '@lessonkit/core';
|
|
5
5
|
export { AssessmentScoreInput, AssessmentScoreResult, InteractionBlockRegistration, LessonkitPlugin, LessonkitPluginContext, LessonkitPluginKind, PluginHost, PluginRegistry, TelemetryPipelineSink, buildTelemetryEvent, createLessonkitRuntime, createPluginRegistry, createTelemetryPipeline, defineAssessmentPlugin, defineLifecyclePlugin, defineTelemetryPlugin } from '@lessonkit/core';
|
|
6
|
+
import { AssessmentDescriptor } from '@lessonkit/lxpack';
|
|
6
7
|
import { XAPITransport, XAPIClient } from '@lessonkit/xapi';
|
|
8
|
+
import { LxpackBridgeMode } from '@lessonkit/lxpack/bridge';
|
|
7
9
|
import { LessonkitThemeV1, ThemePresetName, PartialLessonkitThemeV1 } from '@lessonkit/themes';
|
|
8
10
|
export { ThemePresetName } from '@lessonkit/themes';
|
|
9
11
|
|
|
@@ -31,7 +33,7 @@ type LessonkitConfig = {
|
|
|
31
33
|
};
|
|
32
34
|
lxpack?: {
|
|
33
35
|
/** Forward completion events to `window.parent.lxpackBridge.v1` when embedded (default `auto`). */
|
|
34
|
-
bridge?:
|
|
36
|
+
bridge?: LxpackBridgeMode;
|
|
35
37
|
};
|
|
36
38
|
/** Framework plugins (analytics, LMS, assessment, interaction, AI). */
|
|
37
39
|
plugins?: LessonkitPlugin[];
|
|
@@ -41,6 +43,10 @@ type LessonkitConfig = {
|
|
|
41
43
|
sinks?: _lessonkit_core.TelemetryPipelineSink[];
|
|
42
44
|
};
|
|
43
45
|
|
|
46
|
+
type LessonkitProviderProps = {
|
|
47
|
+
config: LessonkitConfig;
|
|
48
|
+
children: React.ReactNode;
|
|
49
|
+
};
|
|
44
50
|
type LessonkitRuntime = {
|
|
45
51
|
config: LessonkitConfig;
|
|
46
52
|
tracking: TrackingClient;
|
|
@@ -54,65 +60,57 @@ type LessonkitRuntime = {
|
|
|
54
60
|
setActiveLesson: (lessonId: LessonId) => void;
|
|
55
61
|
completeLesson: (lessonId: LessonId) => void;
|
|
56
62
|
completeCourse: () => void;
|
|
57
|
-
track: (name:
|
|
63
|
+
track: <N extends TelemetryEventName>(name: N, data?: TelemetryDataFor<N>, opts?: {
|
|
58
64
|
lessonId?: LessonId;
|
|
59
65
|
}) => void;
|
|
60
66
|
plugins: PluginHost | null;
|
|
61
67
|
};
|
|
62
|
-
declare function LessonkitProvider(props:
|
|
63
|
-
config: LessonkitConfig;
|
|
64
|
-
children: React.ReactNode;
|
|
65
|
-
}): react_jsx_runtime.JSX.Element;
|
|
68
|
+
declare function LessonkitProvider(props: LessonkitProviderProps): react_jsx_runtime.JSX.Element;
|
|
66
69
|
|
|
67
70
|
/** @internal Reset module warnings between tests. */
|
|
68
71
|
declare function resetQuizWarningsForTests(): void;
|
|
69
|
-
|
|
72
|
+
type CourseProps = {
|
|
70
73
|
title: string;
|
|
71
74
|
courseId: CourseId;
|
|
72
|
-
config?: Omit<
|
|
75
|
+
config?: Omit<LessonkitConfig, "courseId">;
|
|
73
76
|
children: React.ReactNode;
|
|
74
|
-
}
|
|
75
|
-
|
|
77
|
+
};
|
|
78
|
+
type LessonProps = {
|
|
76
79
|
title: string;
|
|
77
80
|
lessonId: LessonId;
|
|
78
81
|
/** When false, unmount does not emit lesson_completed (for routed multi-pane layouts). Default true. */
|
|
79
82
|
autoCompleteOnUnmount?: boolean;
|
|
80
83
|
children: React.ReactNode;
|
|
81
|
-
}
|
|
82
|
-
|
|
84
|
+
};
|
|
85
|
+
type ScenarioProps = {
|
|
83
86
|
blockId?: BlockId;
|
|
84
87
|
children: React.ReactNode;
|
|
85
|
-
}
|
|
86
|
-
|
|
88
|
+
};
|
|
89
|
+
type ReflectionProps = {
|
|
87
90
|
blockId?: BlockId;
|
|
88
91
|
prompt?: string;
|
|
89
92
|
hint?: string;
|
|
90
93
|
value?: string;
|
|
91
94
|
onChange?: (value: string) => void;
|
|
92
95
|
children?: React.ReactNode;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
choices: string[];
|
|
98
|
-
answer: string;
|
|
99
|
-
passingScore?: number;
|
|
100
|
-
}): react_jsx_runtime.JSX.Element;
|
|
101
|
-
declare function Quiz(props: {
|
|
102
|
-
checkId: CheckId;
|
|
103
|
-
question: string;
|
|
104
|
-
choices: string[];
|
|
105
|
-
answer: string;
|
|
106
|
-
passingScore?: number;
|
|
107
|
-
}): react_jsx_runtime.JSX.Element;
|
|
108
|
-
declare function ProgressTracker(props: {
|
|
96
|
+
};
|
|
97
|
+
type QuizProps = AssessmentDescriptor;
|
|
98
|
+
type KnowledgeCheckProps = AssessmentDescriptor;
|
|
99
|
+
type ProgressTrackerProps = {
|
|
109
100
|
totalLessons?: number;
|
|
110
|
-
}
|
|
101
|
+
};
|
|
102
|
+
declare function Course(props: CourseProps): react_jsx_runtime.JSX.Element;
|
|
103
|
+
declare function Lesson(props: LessonProps): react_jsx_runtime.JSX.Element;
|
|
104
|
+
declare function Scenario(props: ScenarioProps): react_jsx_runtime.JSX.Element;
|
|
105
|
+
declare function Reflection(props: ReflectionProps): react_jsx_runtime.JSX.Element;
|
|
106
|
+
declare function KnowledgeCheck(props: KnowledgeCheckProps): react_jsx_runtime.JSX.Element;
|
|
107
|
+
declare function Quiz(props: QuizProps): react_jsx_runtime.JSX.Element;
|
|
108
|
+
declare function ProgressTracker(props: ProgressTrackerProps): react_jsx_runtime.JSX.Element;
|
|
111
109
|
|
|
112
110
|
declare function useLessonkit(): LessonkitRuntime;
|
|
113
111
|
declare function useProgress(): _lessonkit_core.ProgressState;
|
|
114
112
|
declare function useTracking(): {
|
|
115
|
-
track: (name:
|
|
113
|
+
track: <N extends _lessonkit_core.TelemetryEventName>(name: N, data?: _lessonkit_core.TelemetryDataFor<N>, opts?: {
|
|
116
114
|
lessonId?: LessonId;
|
|
117
115
|
}) => void;
|
|
118
116
|
};
|
|
@@ -189,8 +187,214 @@ type BlockCatalogEntry = {
|
|
|
189
187
|
manualTracking?: string;
|
|
190
188
|
};
|
|
191
189
|
};
|
|
192
|
-
declare const BLOCK_CATALOG:
|
|
190
|
+
declare const BLOCK_CATALOG: ({
|
|
191
|
+
type: string;
|
|
192
|
+
category: "container";
|
|
193
|
+
description: string;
|
|
194
|
+
props: ({
|
|
195
|
+
name: string;
|
|
196
|
+
type: string;
|
|
197
|
+
required: true;
|
|
198
|
+
description: string;
|
|
199
|
+
} | {
|
|
200
|
+
name: string;
|
|
201
|
+
type: string;
|
|
202
|
+
required: false;
|
|
203
|
+
description: string;
|
|
204
|
+
})[];
|
|
205
|
+
requiredIds: string[];
|
|
206
|
+
a11y: {
|
|
207
|
+
element: string;
|
|
208
|
+
ariaLabel: string;
|
|
209
|
+
keyboard: string;
|
|
210
|
+
notes: string;
|
|
211
|
+
liveRegions?: undefined;
|
|
212
|
+
};
|
|
213
|
+
theming: {
|
|
214
|
+
surface: "global-inherit";
|
|
215
|
+
stylingNotes: string;
|
|
216
|
+
dataAttributes?: undefined;
|
|
217
|
+
};
|
|
218
|
+
telemetry: {
|
|
219
|
+
emits: string[];
|
|
220
|
+
manualTracking?: undefined;
|
|
221
|
+
requiresActiveLesson?: undefined;
|
|
222
|
+
};
|
|
223
|
+
parentConstraints?: undefined;
|
|
224
|
+
optionalIds?: undefined;
|
|
225
|
+
aliases?: undefined;
|
|
226
|
+
} | {
|
|
227
|
+
type: string;
|
|
228
|
+
category: "container";
|
|
229
|
+
description: string;
|
|
230
|
+
props: ({
|
|
231
|
+
name: string;
|
|
232
|
+
type: string;
|
|
233
|
+
required: true;
|
|
234
|
+
description: string;
|
|
235
|
+
} | {
|
|
236
|
+
name: string;
|
|
237
|
+
type: string;
|
|
238
|
+
required: false;
|
|
239
|
+
description: string;
|
|
240
|
+
})[];
|
|
241
|
+
requiredIds: string[];
|
|
242
|
+
parentConstraints: string[];
|
|
243
|
+
a11y: {
|
|
244
|
+
element: string;
|
|
245
|
+
ariaLabel: string;
|
|
246
|
+
keyboard: string;
|
|
247
|
+
notes: string;
|
|
248
|
+
liveRegions?: undefined;
|
|
249
|
+
};
|
|
250
|
+
theming: {
|
|
251
|
+
surface: "global-inherit";
|
|
252
|
+
stylingNotes: string;
|
|
253
|
+
dataAttributes?: undefined;
|
|
254
|
+
};
|
|
255
|
+
telemetry: {
|
|
256
|
+
emits: string[];
|
|
257
|
+
manualTracking?: undefined;
|
|
258
|
+
requiresActiveLesson?: undefined;
|
|
259
|
+
};
|
|
260
|
+
optionalIds?: undefined;
|
|
261
|
+
aliases?: undefined;
|
|
262
|
+
} | {
|
|
263
|
+
type: string;
|
|
264
|
+
category: "content";
|
|
265
|
+
description: string;
|
|
266
|
+
props: ({
|
|
267
|
+
name: string;
|
|
268
|
+
type: string;
|
|
269
|
+
required: false;
|
|
270
|
+
description: string;
|
|
271
|
+
} | {
|
|
272
|
+
name: string;
|
|
273
|
+
type: string;
|
|
274
|
+
required: true;
|
|
275
|
+
description: string;
|
|
276
|
+
})[];
|
|
277
|
+
requiredIds: never[];
|
|
278
|
+
optionalIds: string[];
|
|
279
|
+
parentConstraints: string[];
|
|
280
|
+
a11y: {
|
|
281
|
+
element: string;
|
|
282
|
+
ariaLabel: string;
|
|
283
|
+
keyboard: string;
|
|
284
|
+
notes: string;
|
|
285
|
+
liveRegions?: undefined;
|
|
286
|
+
};
|
|
287
|
+
theming: {
|
|
288
|
+
surface: "global-inherit";
|
|
289
|
+
dataAttributes: string[];
|
|
290
|
+
stylingNotes: string;
|
|
291
|
+
};
|
|
292
|
+
telemetry: {
|
|
293
|
+
emits: never[];
|
|
294
|
+
manualTracking: string;
|
|
295
|
+
requiresActiveLesson?: undefined;
|
|
296
|
+
};
|
|
297
|
+
aliases?: undefined;
|
|
298
|
+
} | {
|
|
299
|
+
type: string;
|
|
300
|
+
category: "content";
|
|
301
|
+
description: string;
|
|
302
|
+
props: {
|
|
303
|
+
name: string;
|
|
304
|
+
type: string;
|
|
305
|
+
required: false;
|
|
306
|
+
description: string;
|
|
307
|
+
}[];
|
|
308
|
+
requiredIds: never[];
|
|
309
|
+
optionalIds: string[];
|
|
310
|
+
parentConstraints: string[];
|
|
311
|
+
a11y: {
|
|
312
|
+
element: string;
|
|
313
|
+
ariaLabel: string;
|
|
314
|
+
keyboard: string;
|
|
315
|
+
notes: string;
|
|
316
|
+
liveRegions?: undefined;
|
|
317
|
+
};
|
|
318
|
+
theming: {
|
|
319
|
+
surface: "global-inherit";
|
|
320
|
+
dataAttributes: string[];
|
|
321
|
+
stylingNotes: string;
|
|
322
|
+
};
|
|
323
|
+
telemetry: {
|
|
324
|
+
emits: never[];
|
|
325
|
+
requiresActiveLesson: true;
|
|
326
|
+
manualTracking: string;
|
|
327
|
+
};
|
|
328
|
+
aliases?: undefined;
|
|
329
|
+
} | {
|
|
330
|
+
type: string;
|
|
331
|
+
aliases: string[];
|
|
332
|
+
category: "assessment";
|
|
333
|
+
description: string;
|
|
334
|
+
props: ({
|
|
335
|
+
name: string;
|
|
336
|
+
type: string;
|
|
337
|
+
required: true;
|
|
338
|
+
description: string;
|
|
339
|
+
} | {
|
|
340
|
+
name: string;
|
|
341
|
+
type: string;
|
|
342
|
+
required: false;
|
|
343
|
+
description: string;
|
|
344
|
+
})[];
|
|
345
|
+
requiredIds: string[];
|
|
346
|
+
parentConstraints: string[];
|
|
347
|
+
a11y: {
|
|
348
|
+
element: string;
|
|
349
|
+
ariaLabel: string;
|
|
350
|
+
keyboard: string;
|
|
351
|
+
liveRegions: string;
|
|
352
|
+
notes: string;
|
|
353
|
+
};
|
|
354
|
+
theming: {
|
|
355
|
+
surface: "global-inherit";
|
|
356
|
+
dataAttributes: string[];
|
|
357
|
+
stylingNotes: string;
|
|
358
|
+
};
|
|
359
|
+
telemetry: {
|
|
360
|
+
emits: string[];
|
|
361
|
+
requiresActiveLesson: true;
|
|
362
|
+
manualTracking?: undefined;
|
|
363
|
+
};
|
|
364
|
+
optionalIds?: undefined;
|
|
365
|
+
} | {
|
|
366
|
+
type: string;
|
|
367
|
+
category: "chrome";
|
|
368
|
+
description: string;
|
|
369
|
+
props: {
|
|
370
|
+
name: string;
|
|
371
|
+
type: string;
|
|
372
|
+
required: false;
|
|
373
|
+
description: string;
|
|
374
|
+
}[];
|
|
375
|
+
requiredIds: never[];
|
|
376
|
+
parentConstraints: string[];
|
|
377
|
+
a11y: {
|
|
378
|
+
element: string;
|
|
379
|
+
ariaLabel: string;
|
|
380
|
+
keyboard: string;
|
|
381
|
+
notes: string;
|
|
382
|
+
liveRegions?: undefined;
|
|
383
|
+
};
|
|
384
|
+
theming: {
|
|
385
|
+
surface: "global-inherit";
|
|
386
|
+
stylingNotes: string;
|
|
387
|
+
dataAttributes?: undefined;
|
|
388
|
+
};
|
|
389
|
+
telemetry: {
|
|
390
|
+
emits: never[];
|
|
391
|
+
manualTracking?: undefined;
|
|
392
|
+
requiresActiveLesson?: undefined;
|
|
393
|
+
};
|
|
394
|
+
optionalIds?: undefined;
|
|
395
|
+
aliases?: undefined;
|
|
396
|
+
})[];
|
|
193
397
|
declare function buildBlockCatalog(): BlockCatalogEntry[];
|
|
194
398
|
declare function getBlockCatalogEntry(type: string): BlockCatalogEntry | undefined;
|
|
195
399
|
|
|
196
|
-
export { BLOCK_CATALOG, type BlockCatalogEntry, type BlockPropSpec, Course, KnowledgeCheck, Lesson, type LessonkitConfig, LessonkitProvider, type LessonkitRuntime, ProgressTracker, Quiz, Reflection, Scenario, type ThemeContextValue, type ThemeMode, ThemeProvider, type ThemeProviderProps, type ThemeResolvedMode, blockCatalogVersion, buildBlockCatalog, getBlockCatalogEntry, resetQuizWarningsForTests, useCompletion, useLessonkit, useProgress, useQuizState, useTheme, useTracking };
|
|
400
|
+
export { BLOCK_CATALOG, type BlockCatalogEntry, type BlockPropSpec, Course, type CourseProps, KnowledgeCheck, type KnowledgeCheckProps, Lesson, type LessonProps, type LessonkitConfig, LessonkitProvider, type LessonkitProviderProps, type LessonkitRuntime, ProgressTracker, type ProgressTrackerProps, Quiz, type QuizProps, Reflection, type ReflectionProps, Scenario, type ScenarioProps, type ThemeContextValue, type ThemeMode, ThemeProvider, type ThemeProviderProps, type ThemeResolvedMode, blockCatalogVersion, buildBlockCatalog, getBlockCatalogEntry, resetQuizWarningsForTests, useCompletion, useLessonkit, useProgress, useQuizState, useTheme, useTracking };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import * as _lessonkit_core from '@lessonkit/core';
|
|
4
|
-
import { CourseId, TelemetryUser, TrackingClient, LessonkitPlugin, ProgressState, LessonId, TelemetryEventName,
|
|
4
|
+
import { CourseId, TelemetryUser, TrackingClient, LessonkitPlugin, ProgressState, LessonId, TelemetryEventName, TelemetryDataFor, PluginHost, BlockId, CheckId } from '@lessonkit/core';
|
|
5
5
|
export { AssessmentScoreInput, AssessmentScoreResult, InteractionBlockRegistration, LessonkitPlugin, LessonkitPluginContext, LessonkitPluginKind, PluginHost, PluginRegistry, TelemetryPipelineSink, buildTelemetryEvent, createLessonkitRuntime, createPluginRegistry, createTelemetryPipeline, defineAssessmentPlugin, defineLifecyclePlugin, defineTelemetryPlugin } from '@lessonkit/core';
|
|
6
|
+
import { AssessmentDescriptor } from '@lessonkit/lxpack';
|
|
6
7
|
import { XAPITransport, XAPIClient } from '@lessonkit/xapi';
|
|
8
|
+
import { LxpackBridgeMode } from '@lessonkit/lxpack/bridge';
|
|
7
9
|
import { LessonkitThemeV1, ThemePresetName, PartialLessonkitThemeV1 } from '@lessonkit/themes';
|
|
8
10
|
export { ThemePresetName } from '@lessonkit/themes';
|
|
9
11
|
|
|
@@ -31,7 +33,7 @@ type LessonkitConfig = {
|
|
|
31
33
|
};
|
|
32
34
|
lxpack?: {
|
|
33
35
|
/** Forward completion events to `window.parent.lxpackBridge.v1` when embedded (default `auto`). */
|
|
34
|
-
bridge?:
|
|
36
|
+
bridge?: LxpackBridgeMode;
|
|
35
37
|
};
|
|
36
38
|
/** Framework plugins (analytics, LMS, assessment, interaction, AI). */
|
|
37
39
|
plugins?: LessonkitPlugin[];
|
|
@@ -41,6 +43,10 @@ type LessonkitConfig = {
|
|
|
41
43
|
sinks?: _lessonkit_core.TelemetryPipelineSink[];
|
|
42
44
|
};
|
|
43
45
|
|
|
46
|
+
type LessonkitProviderProps = {
|
|
47
|
+
config: LessonkitConfig;
|
|
48
|
+
children: React.ReactNode;
|
|
49
|
+
};
|
|
44
50
|
type LessonkitRuntime = {
|
|
45
51
|
config: LessonkitConfig;
|
|
46
52
|
tracking: TrackingClient;
|
|
@@ -54,65 +60,57 @@ type LessonkitRuntime = {
|
|
|
54
60
|
setActiveLesson: (lessonId: LessonId) => void;
|
|
55
61
|
completeLesson: (lessonId: LessonId) => void;
|
|
56
62
|
completeCourse: () => void;
|
|
57
|
-
track: (name:
|
|
63
|
+
track: <N extends TelemetryEventName>(name: N, data?: TelemetryDataFor<N>, opts?: {
|
|
58
64
|
lessonId?: LessonId;
|
|
59
65
|
}) => void;
|
|
60
66
|
plugins: PluginHost | null;
|
|
61
67
|
};
|
|
62
|
-
declare function LessonkitProvider(props:
|
|
63
|
-
config: LessonkitConfig;
|
|
64
|
-
children: React.ReactNode;
|
|
65
|
-
}): react_jsx_runtime.JSX.Element;
|
|
68
|
+
declare function LessonkitProvider(props: LessonkitProviderProps): react_jsx_runtime.JSX.Element;
|
|
66
69
|
|
|
67
70
|
/** @internal Reset module warnings between tests. */
|
|
68
71
|
declare function resetQuizWarningsForTests(): void;
|
|
69
|
-
|
|
72
|
+
type CourseProps = {
|
|
70
73
|
title: string;
|
|
71
74
|
courseId: CourseId;
|
|
72
|
-
config?: Omit<
|
|
75
|
+
config?: Omit<LessonkitConfig, "courseId">;
|
|
73
76
|
children: React.ReactNode;
|
|
74
|
-
}
|
|
75
|
-
|
|
77
|
+
};
|
|
78
|
+
type LessonProps = {
|
|
76
79
|
title: string;
|
|
77
80
|
lessonId: LessonId;
|
|
78
81
|
/** When false, unmount does not emit lesson_completed (for routed multi-pane layouts). Default true. */
|
|
79
82
|
autoCompleteOnUnmount?: boolean;
|
|
80
83
|
children: React.ReactNode;
|
|
81
|
-
}
|
|
82
|
-
|
|
84
|
+
};
|
|
85
|
+
type ScenarioProps = {
|
|
83
86
|
blockId?: BlockId;
|
|
84
87
|
children: React.ReactNode;
|
|
85
|
-
}
|
|
86
|
-
|
|
88
|
+
};
|
|
89
|
+
type ReflectionProps = {
|
|
87
90
|
blockId?: BlockId;
|
|
88
91
|
prompt?: string;
|
|
89
92
|
hint?: string;
|
|
90
93
|
value?: string;
|
|
91
94
|
onChange?: (value: string) => void;
|
|
92
95
|
children?: React.ReactNode;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
choices: string[];
|
|
98
|
-
answer: string;
|
|
99
|
-
passingScore?: number;
|
|
100
|
-
}): react_jsx_runtime.JSX.Element;
|
|
101
|
-
declare function Quiz(props: {
|
|
102
|
-
checkId: CheckId;
|
|
103
|
-
question: string;
|
|
104
|
-
choices: string[];
|
|
105
|
-
answer: string;
|
|
106
|
-
passingScore?: number;
|
|
107
|
-
}): react_jsx_runtime.JSX.Element;
|
|
108
|
-
declare function ProgressTracker(props: {
|
|
96
|
+
};
|
|
97
|
+
type QuizProps = AssessmentDescriptor;
|
|
98
|
+
type KnowledgeCheckProps = AssessmentDescriptor;
|
|
99
|
+
type ProgressTrackerProps = {
|
|
109
100
|
totalLessons?: number;
|
|
110
|
-
}
|
|
101
|
+
};
|
|
102
|
+
declare function Course(props: CourseProps): react_jsx_runtime.JSX.Element;
|
|
103
|
+
declare function Lesson(props: LessonProps): react_jsx_runtime.JSX.Element;
|
|
104
|
+
declare function Scenario(props: ScenarioProps): react_jsx_runtime.JSX.Element;
|
|
105
|
+
declare function Reflection(props: ReflectionProps): react_jsx_runtime.JSX.Element;
|
|
106
|
+
declare function KnowledgeCheck(props: KnowledgeCheckProps): react_jsx_runtime.JSX.Element;
|
|
107
|
+
declare function Quiz(props: QuizProps): react_jsx_runtime.JSX.Element;
|
|
108
|
+
declare function ProgressTracker(props: ProgressTrackerProps): react_jsx_runtime.JSX.Element;
|
|
111
109
|
|
|
112
110
|
declare function useLessonkit(): LessonkitRuntime;
|
|
113
111
|
declare function useProgress(): _lessonkit_core.ProgressState;
|
|
114
112
|
declare function useTracking(): {
|
|
115
|
-
track: (name:
|
|
113
|
+
track: <N extends _lessonkit_core.TelemetryEventName>(name: N, data?: _lessonkit_core.TelemetryDataFor<N>, opts?: {
|
|
116
114
|
lessonId?: LessonId;
|
|
117
115
|
}) => void;
|
|
118
116
|
};
|
|
@@ -189,8 +187,214 @@ type BlockCatalogEntry = {
|
|
|
189
187
|
manualTracking?: string;
|
|
190
188
|
};
|
|
191
189
|
};
|
|
192
|
-
declare const BLOCK_CATALOG:
|
|
190
|
+
declare const BLOCK_CATALOG: ({
|
|
191
|
+
type: string;
|
|
192
|
+
category: "container";
|
|
193
|
+
description: string;
|
|
194
|
+
props: ({
|
|
195
|
+
name: string;
|
|
196
|
+
type: string;
|
|
197
|
+
required: true;
|
|
198
|
+
description: string;
|
|
199
|
+
} | {
|
|
200
|
+
name: string;
|
|
201
|
+
type: string;
|
|
202
|
+
required: false;
|
|
203
|
+
description: string;
|
|
204
|
+
})[];
|
|
205
|
+
requiredIds: string[];
|
|
206
|
+
a11y: {
|
|
207
|
+
element: string;
|
|
208
|
+
ariaLabel: string;
|
|
209
|
+
keyboard: string;
|
|
210
|
+
notes: string;
|
|
211
|
+
liveRegions?: undefined;
|
|
212
|
+
};
|
|
213
|
+
theming: {
|
|
214
|
+
surface: "global-inherit";
|
|
215
|
+
stylingNotes: string;
|
|
216
|
+
dataAttributes?: undefined;
|
|
217
|
+
};
|
|
218
|
+
telemetry: {
|
|
219
|
+
emits: string[];
|
|
220
|
+
manualTracking?: undefined;
|
|
221
|
+
requiresActiveLesson?: undefined;
|
|
222
|
+
};
|
|
223
|
+
parentConstraints?: undefined;
|
|
224
|
+
optionalIds?: undefined;
|
|
225
|
+
aliases?: undefined;
|
|
226
|
+
} | {
|
|
227
|
+
type: string;
|
|
228
|
+
category: "container";
|
|
229
|
+
description: string;
|
|
230
|
+
props: ({
|
|
231
|
+
name: string;
|
|
232
|
+
type: string;
|
|
233
|
+
required: true;
|
|
234
|
+
description: string;
|
|
235
|
+
} | {
|
|
236
|
+
name: string;
|
|
237
|
+
type: string;
|
|
238
|
+
required: false;
|
|
239
|
+
description: string;
|
|
240
|
+
})[];
|
|
241
|
+
requiredIds: string[];
|
|
242
|
+
parentConstraints: string[];
|
|
243
|
+
a11y: {
|
|
244
|
+
element: string;
|
|
245
|
+
ariaLabel: string;
|
|
246
|
+
keyboard: string;
|
|
247
|
+
notes: string;
|
|
248
|
+
liveRegions?: undefined;
|
|
249
|
+
};
|
|
250
|
+
theming: {
|
|
251
|
+
surface: "global-inherit";
|
|
252
|
+
stylingNotes: string;
|
|
253
|
+
dataAttributes?: undefined;
|
|
254
|
+
};
|
|
255
|
+
telemetry: {
|
|
256
|
+
emits: string[];
|
|
257
|
+
manualTracking?: undefined;
|
|
258
|
+
requiresActiveLesson?: undefined;
|
|
259
|
+
};
|
|
260
|
+
optionalIds?: undefined;
|
|
261
|
+
aliases?: undefined;
|
|
262
|
+
} | {
|
|
263
|
+
type: string;
|
|
264
|
+
category: "content";
|
|
265
|
+
description: string;
|
|
266
|
+
props: ({
|
|
267
|
+
name: string;
|
|
268
|
+
type: string;
|
|
269
|
+
required: false;
|
|
270
|
+
description: string;
|
|
271
|
+
} | {
|
|
272
|
+
name: string;
|
|
273
|
+
type: string;
|
|
274
|
+
required: true;
|
|
275
|
+
description: string;
|
|
276
|
+
})[];
|
|
277
|
+
requiredIds: never[];
|
|
278
|
+
optionalIds: string[];
|
|
279
|
+
parentConstraints: string[];
|
|
280
|
+
a11y: {
|
|
281
|
+
element: string;
|
|
282
|
+
ariaLabel: string;
|
|
283
|
+
keyboard: string;
|
|
284
|
+
notes: string;
|
|
285
|
+
liveRegions?: undefined;
|
|
286
|
+
};
|
|
287
|
+
theming: {
|
|
288
|
+
surface: "global-inherit";
|
|
289
|
+
dataAttributes: string[];
|
|
290
|
+
stylingNotes: string;
|
|
291
|
+
};
|
|
292
|
+
telemetry: {
|
|
293
|
+
emits: never[];
|
|
294
|
+
manualTracking: string;
|
|
295
|
+
requiresActiveLesson?: undefined;
|
|
296
|
+
};
|
|
297
|
+
aliases?: undefined;
|
|
298
|
+
} | {
|
|
299
|
+
type: string;
|
|
300
|
+
category: "content";
|
|
301
|
+
description: string;
|
|
302
|
+
props: {
|
|
303
|
+
name: string;
|
|
304
|
+
type: string;
|
|
305
|
+
required: false;
|
|
306
|
+
description: string;
|
|
307
|
+
}[];
|
|
308
|
+
requiredIds: never[];
|
|
309
|
+
optionalIds: string[];
|
|
310
|
+
parentConstraints: string[];
|
|
311
|
+
a11y: {
|
|
312
|
+
element: string;
|
|
313
|
+
ariaLabel: string;
|
|
314
|
+
keyboard: string;
|
|
315
|
+
notes: string;
|
|
316
|
+
liveRegions?: undefined;
|
|
317
|
+
};
|
|
318
|
+
theming: {
|
|
319
|
+
surface: "global-inherit";
|
|
320
|
+
dataAttributes: string[];
|
|
321
|
+
stylingNotes: string;
|
|
322
|
+
};
|
|
323
|
+
telemetry: {
|
|
324
|
+
emits: never[];
|
|
325
|
+
requiresActiveLesson: true;
|
|
326
|
+
manualTracking: string;
|
|
327
|
+
};
|
|
328
|
+
aliases?: undefined;
|
|
329
|
+
} | {
|
|
330
|
+
type: string;
|
|
331
|
+
aliases: string[];
|
|
332
|
+
category: "assessment";
|
|
333
|
+
description: string;
|
|
334
|
+
props: ({
|
|
335
|
+
name: string;
|
|
336
|
+
type: string;
|
|
337
|
+
required: true;
|
|
338
|
+
description: string;
|
|
339
|
+
} | {
|
|
340
|
+
name: string;
|
|
341
|
+
type: string;
|
|
342
|
+
required: false;
|
|
343
|
+
description: string;
|
|
344
|
+
})[];
|
|
345
|
+
requiredIds: string[];
|
|
346
|
+
parentConstraints: string[];
|
|
347
|
+
a11y: {
|
|
348
|
+
element: string;
|
|
349
|
+
ariaLabel: string;
|
|
350
|
+
keyboard: string;
|
|
351
|
+
liveRegions: string;
|
|
352
|
+
notes: string;
|
|
353
|
+
};
|
|
354
|
+
theming: {
|
|
355
|
+
surface: "global-inherit";
|
|
356
|
+
dataAttributes: string[];
|
|
357
|
+
stylingNotes: string;
|
|
358
|
+
};
|
|
359
|
+
telemetry: {
|
|
360
|
+
emits: string[];
|
|
361
|
+
requiresActiveLesson: true;
|
|
362
|
+
manualTracking?: undefined;
|
|
363
|
+
};
|
|
364
|
+
optionalIds?: undefined;
|
|
365
|
+
} | {
|
|
366
|
+
type: string;
|
|
367
|
+
category: "chrome";
|
|
368
|
+
description: string;
|
|
369
|
+
props: {
|
|
370
|
+
name: string;
|
|
371
|
+
type: string;
|
|
372
|
+
required: false;
|
|
373
|
+
description: string;
|
|
374
|
+
}[];
|
|
375
|
+
requiredIds: never[];
|
|
376
|
+
parentConstraints: string[];
|
|
377
|
+
a11y: {
|
|
378
|
+
element: string;
|
|
379
|
+
ariaLabel: string;
|
|
380
|
+
keyboard: string;
|
|
381
|
+
notes: string;
|
|
382
|
+
liveRegions?: undefined;
|
|
383
|
+
};
|
|
384
|
+
theming: {
|
|
385
|
+
surface: "global-inherit";
|
|
386
|
+
stylingNotes: string;
|
|
387
|
+
dataAttributes?: undefined;
|
|
388
|
+
};
|
|
389
|
+
telemetry: {
|
|
390
|
+
emits: never[];
|
|
391
|
+
manualTracking?: undefined;
|
|
392
|
+
requiresActiveLesson?: undefined;
|
|
393
|
+
};
|
|
394
|
+
optionalIds?: undefined;
|
|
395
|
+
aliases?: undefined;
|
|
396
|
+
})[];
|
|
193
397
|
declare function buildBlockCatalog(): BlockCatalogEntry[];
|
|
194
398
|
declare function getBlockCatalogEntry(type: string): BlockCatalogEntry | undefined;
|
|
195
399
|
|
|
196
|
-
export { BLOCK_CATALOG, type BlockCatalogEntry, type BlockPropSpec, Course, KnowledgeCheck, Lesson, type LessonkitConfig, LessonkitProvider, type LessonkitRuntime, ProgressTracker, Quiz, Reflection, Scenario, type ThemeContextValue, type ThemeMode, ThemeProvider, type ThemeProviderProps, type ThemeResolvedMode, blockCatalogVersion, buildBlockCatalog, getBlockCatalogEntry, resetQuizWarningsForTests, useCompletion, useLessonkit, useProgress, useQuizState, useTheme, useTracking };
|
|
400
|
+
export { BLOCK_CATALOG, type BlockCatalogEntry, type BlockPropSpec, Course, type CourseProps, KnowledgeCheck, type KnowledgeCheckProps, Lesson, type LessonProps, type LessonkitConfig, LessonkitProvider, type LessonkitProviderProps, type LessonkitRuntime, ProgressTracker, type ProgressTrackerProps, Quiz, type QuizProps, Reflection, type ReflectionProps, Scenario, type ScenarioProps, type ThemeContextValue, type ThemeMode, ThemeProvider, type ThemeProviderProps, type ThemeResolvedMode, blockCatalogVersion, buildBlockCatalog, getBlockCatalogEntry, resetQuizWarningsForTests, useCompletion, useLessonkit, useProgress, useQuizState, useTheme, useTracking };
|
package/dist/index.js
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
} from "react";
|
|
17
17
|
import { createLessonkitRuntime, createTrackingClient as createTrackingClient2, assertValidId } from "@lessonkit/core";
|
|
18
18
|
import { createInMemoryXAPIQueue } from "@lessonkit/xapi";
|
|
19
|
-
import { telemetryEventToXAPIStatement as
|
|
19
|
+
import { telemetryEventToXAPIStatement as telemetryEventToXAPIStatement3 } from "@lessonkit/xapi";
|
|
20
20
|
|
|
21
21
|
// src/runtime/emitTelemetry.ts
|
|
22
22
|
import { buildTelemetryEvent, tryBuildTelemetryEvent } from "@lessonkit/core";
|
|
@@ -135,9 +135,34 @@ import {
|
|
|
135
135
|
markCourseStarted,
|
|
136
136
|
hasCourseStartedEmittedToTracking,
|
|
137
137
|
markCourseStartedEmittedToTracking,
|
|
138
|
+
hasCourseStartedPipelineDelivered,
|
|
139
|
+
markCourseStartedPipelineDelivered,
|
|
138
140
|
migrateCourseStartedMark
|
|
139
141
|
} from "@lessonkit/core";
|
|
140
142
|
|
|
143
|
+
// src/runtime/courseStartedPipeline.ts
|
|
144
|
+
import { telemetryEventToXAPIStatement as telemetryEventToXAPIStatement2 } from "@lessonkit/xapi";
|
|
145
|
+
function emitCourseStartedNonTrackingPipeline(opts) {
|
|
146
|
+
let xapiStatementSent = false;
|
|
147
|
+
if (!opts.skipXapi && opts.xapi) {
|
|
148
|
+
const statement = telemetryEventToXAPIStatement2(opts.event);
|
|
149
|
+
if (statement) {
|
|
150
|
+
opts.xapi.send(statement);
|
|
151
|
+
xapiStatementSent = true;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
forwardTelemetryToLxpack(opts.event, opts.lxpackBridge);
|
|
155
|
+
const emitCtx = {
|
|
156
|
+
courseId: opts.event.courseId,
|
|
157
|
+
sessionId: opts.event.sessionId,
|
|
158
|
+
attemptId: opts.event.attemptId
|
|
159
|
+
};
|
|
160
|
+
for (const sink of opts.extraSinks ?? []) {
|
|
161
|
+
sink.emit(opts.event, emitCtx);
|
|
162
|
+
}
|
|
163
|
+
return { xapiStatementSent };
|
|
164
|
+
}
|
|
165
|
+
|
|
141
166
|
// src/runtime/plugins.ts
|
|
142
167
|
import { createPluginRegistry } from "@lessonkit/core";
|
|
143
168
|
function createReactPluginHost(plugins) {
|
|
@@ -189,8 +214,9 @@ var defaultStorage = createSessionStoragePort();
|
|
|
189
214
|
function isTrackingActive(tracking) {
|
|
190
215
|
return tracking?.enabled !== false;
|
|
191
216
|
}
|
|
192
|
-
|
|
193
|
-
|
|
217
|
+
function isCourseStartedSinkSettled(result) {
|
|
218
|
+
return result === "emitted";
|
|
219
|
+
}
|
|
194
220
|
function buildCourseStartedEvent(opts) {
|
|
195
221
|
const pluginCtx = buildPluginContext({
|
|
196
222
|
courseId: opts.courseId,
|
|
@@ -208,31 +234,27 @@ function buildCourseStartedEvent(opts) {
|
|
|
208
234
|
return opts.pluginHost ? opts.pluginHost.runTelemetry(built, pluginCtx) : built;
|
|
209
235
|
}
|
|
210
236
|
function emitCourseStartedPipelineOnly(opts) {
|
|
211
|
-
const pluginCtx = buildPluginContext({
|
|
212
|
-
courseId: opts.courseId,
|
|
213
|
-
sessionId: opts.sessionId,
|
|
214
|
-
attemptId: opts.attemptId,
|
|
215
|
-
user: opts.user
|
|
216
|
-
});
|
|
217
237
|
try {
|
|
218
|
-
|
|
219
|
-
pluginHost: null,
|
|
220
|
-
tracking: noopTrackingClient,
|
|
221
|
-
xapi: opts.xapi,
|
|
238
|
+
const { xapiStatementSent } = emitCourseStartedNonTrackingPipeline({
|
|
222
239
|
event: opts.event,
|
|
223
|
-
|
|
240
|
+
xapi: opts.xapi,
|
|
224
241
|
lxpackBridge: opts.lxpackBridge,
|
|
225
|
-
extraSinks: opts.extraSinks
|
|
242
|
+
extraSinks: opts.extraSinks,
|
|
243
|
+
skipXapi: opts.skipXapi
|
|
226
244
|
});
|
|
227
245
|
markCourseStarted(opts.storage, opts.sessionId, opts.courseId);
|
|
228
|
-
|
|
246
|
+
markCourseStartedPipelineDelivered(opts.storage, opts.sessionId, opts.courseId);
|
|
247
|
+
if (xapiStatementSent) {
|
|
248
|
+
opts.onXapiStatementSent?.();
|
|
249
|
+
}
|
|
250
|
+
return "emitted";
|
|
229
251
|
} catch {
|
|
230
|
-
return
|
|
252
|
+
return "failed";
|
|
231
253
|
}
|
|
232
254
|
}
|
|
233
255
|
function emitCourseStarted(opts) {
|
|
234
256
|
const event = buildCourseStartedEvent(opts);
|
|
235
|
-
if (event === null) return
|
|
257
|
+
if (event === null) return "filtered";
|
|
236
258
|
const trackingAlreadyEmitted = hasCourseStartedEmittedToTracking(
|
|
237
259
|
opts.storage,
|
|
238
260
|
opts.sessionId,
|
|
@@ -243,14 +265,19 @@ function emitCourseStarted(opts) {
|
|
|
243
265
|
opts.tracking.track(event);
|
|
244
266
|
markCourseStartedEmittedToTracking(opts.storage, opts.sessionId, opts.courseId);
|
|
245
267
|
} catch {
|
|
246
|
-
return
|
|
268
|
+
return "failed";
|
|
247
269
|
}
|
|
248
270
|
}
|
|
249
|
-
return emitCourseStartedPipelineOnly({
|
|
271
|
+
return emitCourseStartedPipelineOnly({
|
|
272
|
+
...opts,
|
|
273
|
+
event,
|
|
274
|
+
skipXapi: opts.skipXapi,
|
|
275
|
+
onXapiStatementSent: opts.onXapiStatementSent
|
|
276
|
+
});
|
|
250
277
|
}
|
|
251
278
|
function emitCourseStartedToTrackingOnly(opts) {
|
|
252
279
|
const event = buildCourseStartedEvent(opts);
|
|
253
|
-
if (event === null) return
|
|
280
|
+
if (event === null) return "filtered";
|
|
254
281
|
const trackingAlreadyEmitted = hasCourseStartedEmittedToTracking(
|
|
255
282
|
opts.storage,
|
|
256
283
|
opts.sessionId,
|
|
@@ -261,28 +288,21 @@ function emitCourseStartedToTrackingOnly(opts) {
|
|
|
261
288
|
opts.tracking.track(event);
|
|
262
289
|
markCourseStartedEmittedToTracking(opts.storage, opts.sessionId, opts.courseId);
|
|
263
290
|
} catch {
|
|
264
|
-
return
|
|
291
|
+
return "failed";
|
|
265
292
|
}
|
|
266
293
|
}
|
|
267
|
-
const pluginCtx = buildPluginContext({
|
|
268
|
-
courseId: opts.courseId,
|
|
269
|
-
sessionId: opts.sessionId,
|
|
270
|
-
attemptId: opts.attemptId,
|
|
271
|
-
user: opts.user
|
|
272
|
-
});
|
|
273
294
|
try {
|
|
274
|
-
|
|
275
|
-
pluginHost: null,
|
|
276
|
-
tracking: noopTrackingClient,
|
|
277
|
-
xapi: null,
|
|
295
|
+
emitCourseStartedNonTrackingPipeline({
|
|
278
296
|
event,
|
|
279
|
-
|
|
297
|
+
xapi: null,
|
|
280
298
|
lxpackBridge: opts.lxpackBridge,
|
|
281
|
-
extraSinks: opts.extraSinks
|
|
299
|
+
extraSinks: opts.extraSinks,
|
|
300
|
+
skipXapi: true
|
|
282
301
|
});
|
|
283
|
-
|
|
302
|
+
markCourseStartedPipelineDelivered(opts.storage, opts.sessionId, opts.courseId);
|
|
303
|
+
return "emitted";
|
|
284
304
|
} catch {
|
|
285
|
-
return
|
|
305
|
+
return "failed";
|
|
286
306
|
}
|
|
287
307
|
}
|
|
288
308
|
function emitPendingCourseStarted(opts) {
|
|
@@ -297,13 +317,28 @@ function emitPendingCourseStarted(opts) {
|
|
|
297
317
|
}
|
|
298
318
|
if (trackingEmitted && !sessionStarted) {
|
|
299
319
|
const event = buildCourseStartedEvent(opts);
|
|
300
|
-
if (event === null) return
|
|
320
|
+
if (event === null) return "filtered";
|
|
301
321
|
return emitCourseStartedPipelineOnly({ ...opts, event });
|
|
302
322
|
}
|
|
303
323
|
if (!trackingEmitted && !sessionStarted) {
|
|
304
324
|
return emitCourseStarted(opts);
|
|
305
325
|
}
|
|
306
|
-
|
|
326
|
+
const pipelineDelivered = hasCourseStartedPipelineDelivered(
|
|
327
|
+
opts.storage,
|
|
328
|
+
opts.sessionId,
|
|
329
|
+
opts.courseId
|
|
330
|
+
);
|
|
331
|
+
if (sessionStarted && trackingEmitted && !pipelineDelivered) {
|
|
332
|
+
const event = buildCourseStartedEvent(opts);
|
|
333
|
+
if (event === null) return "filtered";
|
|
334
|
+
return emitCourseStartedPipelineOnly({
|
|
335
|
+
...opts,
|
|
336
|
+
event,
|
|
337
|
+
skipXapi: opts.skipXapi,
|
|
338
|
+
onXapiStatementSent: opts.onXapiStatementSent
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
return "emitted";
|
|
307
342
|
}
|
|
308
343
|
function assertTrackingSinkConfig(tracking) {
|
|
309
344
|
if (!tracking?.sink || !tracking?.batchSink) return;
|
|
@@ -429,21 +464,24 @@ function useLessonkitProviderRuntime(config) {
|
|
|
429
464
|
const needsBootstrap = !skipBootstrap && !xapiCourseStartedSentOnClientRef.current && (!alreadyStarted || clientChanged);
|
|
430
465
|
if (needsBootstrap) {
|
|
431
466
|
try {
|
|
432
|
-
const
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
)
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
if (
|
|
444
|
-
|
|
467
|
+
const event = buildCourseStartedEvent({
|
|
468
|
+
pluginHost: pluginHostRef.current,
|
|
469
|
+
courseId: cid,
|
|
470
|
+
sessionId,
|
|
471
|
+
attemptId: attemptIdRef.current,
|
|
472
|
+
user: userRef.current,
|
|
473
|
+
lxpackBridge: lxpackBridgeModeRef.current
|
|
474
|
+
});
|
|
475
|
+
if (event === null) {
|
|
476
|
+
} else {
|
|
477
|
+
const statement = telemetryEventToXAPIStatement3(event);
|
|
478
|
+
if (statement) {
|
|
479
|
+
next.send(statement);
|
|
480
|
+
if (!alreadyStarted) {
|
|
481
|
+
markCourseStarted(defaultStorage, sessionId, cid);
|
|
482
|
+
}
|
|
483
|
+
xapiCourseStartedSentOnClientRef.current = true;
|
|
445
484
|
}
|
|
446
|
-
xapiCourseStartedSentOnClientRef.current = true;
|
|
447
485
|
}
|
|
448
486
|
} catch {
|
|
449
487
|
}
|
|
@@ -517,7 +555,7 @@ function useLessonkitProviderRuntime(config) {
|
|
|
517
555
|
if (!trackingActive) {
|
|
518
556
|
courseStartedEmittedToSinkRef.current = false;
|
|
519
557
|
} else if (!courseStartedEmittedToSinkRef.current) {
|
|
520
|
-
const
|
|
558
|
+
const result = emitPendingCourseStarted({
|
|
521
559
|
pluginHost: pluginHostRef.current,
|
|
522
560
|
tracking: next,
|
|
523
561
|
xapi: xapiRef.current,
|
|
@@ -527,12 +565,13 @@ function useLessonkitProviderRuntime(config) {
|
|
|
527
565
|
attemptId: attemptIdRef.current,
|
|
528
566
|
user: userRef.current,
|
|
529
567
|
lxpackBridge: lxpackBridgeModeRef.current,
|
|
530
|
-
extraSinks: extraSinksRef.current
|
|
568
|
+
extraSinks: extraSinksRef.current,
|
|
569
|
+
skipXapi: xapiCourseStartedSentOnClientRef.current,
|
|
570
|
+
onXapiStatementSent: () => {
|
|
571
|
+
xapiCourseStartedSentOnClientRef.current = true;
|
|
572
|
+
}
|
|
531
573
|
});
|
|
532
|
-
|
|
533
|
-
markCourseStartedEmittedToTracking(defaultStorage, sessionId, cid);
|
|
534
|
-
}
|
|
535
|
-
courseStartedEmittedToSinkRef.current = emitted;
|
|
574
|
+
courseStartedEmittedToSinkRef.current = isCourseStartedSinkSettled(result);
|
|
536
575
|
} else if (trackingActive) {
|
|
537
576
|
courseStartedEmittedToSinkRef.current = true;
|
|
538
577
|
}
|
|
@@ -613,7 +652,7 @@ function useLessonkitProviderRuntime(config) {
|
|
|
613
652
|
} catch {
|
|
614
653
|
}
|
|
615
654
|
if (!courseStartedEmittedToSinkRef.current) {
|
|
616
|
-
const
|
|
655
|
+
const result = emitPendingCourseStarted({
|
|
617
656
|
pluginHost: pluginHostRef.current,
|
|
618
657
|
tracking: trackingRef.current,
|
|
619
658
|
xapi: xapiRef.current,
|
|
@@ -625,7 +664,7 @@ function useLessonkitProviderRuntime(config) {
|
|
|
625
664
|
lxpackBridge: lxpackBridgeModeRef.current,
|
|
626
665
|
extraSinks: extraSinksRef.current
|
|
627
666
|
});
|
|
628
|
-
courseStartedEmittedToSinkRef.current =
|
|
667
|
+
courseStartedEmittedToSinkRef.current = isCourseStartedSinkSettled(result);
|
|
629
668
|
}
|
|
630
669
|
})();
|
|
631
670
|
}, [normalizedCourseId, normalizedConfig.tracking?.enabled, syncProgress]);
|
|
@@ -862,6 +901,10 @@ function isDevEnvironment3() {
|
|
|
862
901
|
return typeof g.process !== "undefined" && g.process.env?.NODE_ENV !== "production";
|
|
863
902
|
}
|
|
864
903
|
function normalizeComponentId(id, path) {
|
|
904
|
+
if (path === "courseId") return assertValidId2(id, "courseId");
|
|
905
|
+
if (path === "lessonId") return assertValidId2(id, "lessonId");
|
|
906
|
+
if (path === "checkId") return assertValidId2(id, "checkId");
|
|
907
|
+
if (path === "blockId") return assertValidId2(id, "blockId");
|
|
865
908
|
return assertValidId2(id, path);
|
|
866
909
|
}
|
|
867
910
|
|
|
@@ -1378,7 +1421,13 @@ var BLOCK_CATALOG = [
|
|
|
1378
1421
|
{ name: "checkId", type: "CheckId", required: true, description: "Stable check identifier for telemetry and LXPack assessments." },
|
|
1379
1422
|
{ name: "question", type: "string", required: true, description: "Question text shown above choices." },
|
|
1380
1423
|
{ name: "choices", type: "string[]", required: true, description: "Radio button choice labels." },
|
|
1381
|
-
{ name: "answer", type: "string", required: true, description: "Correct choice value (must match one choice)." }
|
|
1424
|
+
{ name: "answer", type: "string", required: true, description: "Correct choice value (must match one choice)." },
|
|
1425
|
+
{
|
|
1426
|
+
name: "passingScore",
|
|
1427
|
+
type: "number",
|
|
1428
|
+
required: false,
|
|
1429
|
+
description: "Minimum score required to pass (defaults to maxScore when omitted)."
|
|
1430
|
+
}
|
|
1382
1431
|
],
|
|
1383
1432
|
requiredIds: ["checkId"],
|
|
1384
1433
|
parentConstraints: ["Lesson"],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lessonkit/react",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "React components and hooks for building learning experiences with LessonKit.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -56,11 +56,11 @@
|
|
|
56
56
|
"react-dom": ">=18"
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@lessonkit/accessibility": "1.0.
|
|
60
|
-
"@lessonkit/core": "1.0.
|
|
61
|
-
"@lessonkit/lxpack": "1.0.
|
|
62
|
-
"@lessonkit/themes": "1.0.
|
|
63
|
-
"@lessonkit/xapi": "1.0.
|
|
59
|
+
"@lessonkit/accessibility": "1.0.1",
|
|
60
|
+
"@lessonkit/core": "1.0.1",
|
|
61
|
+
"@lessonkit/lxpack": "1.0.1",
|
|
62
|
+
"@lessonkit/themes": "1.0.1",
|
|
63
|
+
"@lessonkit/xapi": "1.0.1"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
66
|
"@storybook/addon-essentials": "8.6.18",
|