tessera-learn 0.0.8 → 0.0.10

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.
@@ -1,71 +0,0 @@
1
- import type { Interaction } from '../runtime/interaction.js';
2
-
3
- /**
4
- * Shape contributed by a question component when it registers with a `<Quiz>`.
5
- * `useQuestion` always supplies both `id` and `interaction`; custom widgets
6
- * may omit `interaction` (presentational steps that don't report to the LMS),
7
- * in which case they're skipped by `buildQuizInteractions`.
8
- */
9
- export interface QuizQuestionApi {
10
- id: string;
11
- /** Optional weight for the score rollup. Default 1 — `Σ(w·correct)/Σ(w)*100`. */
12
- weight?: number;
13
- checkAnswer: (answer: unknown) => boolean;
14
- reset?: () => void;
15
- render?: unknown;
16
- interaction?: () => Interaction;
17
- }
18
-
19
- /**
20
- * Reactive context published by `<Quiz>` (and `useQuiz`) under the
21
- * `'tessera-quiz'` Svelte context key. Question widgets read this through
22
- * `getContext<QuizContext>('tessera-quiz')` to coordinate with their host.
23
- *
24
- * All accessors are getters so the consumer re-runs when the underlying rune
25
- * state changes — destructuring the object will break reactivity.
26
- */
27
- export interface QuizContext {
28
- registerQuestion(api: QuizQuestionApi): number;
29
- setRender(index: number, render: unknown): void;
30
- setAnswer(index: number, answer: unknown): void;
31
- getAnswer(index: number): unknown;
32
- readonly submitted: boolean;
33
- readonly reviewing: boolean;
34
- readonly showFeedback: boolean;
35
- feedbackVisible(index: number): boolean;
36
- isAnswerLocked(index: number): boolean;
37
- isLockedCorrect(index: number): boolean;
38
- }
39
-
40
- export interface QuizInteractionEntry {
41
- id: string;
42
- interaction: Interaction;
43
- correct: boolean;
44
- }
45
-
46
- /**
47
- * Build the per-question payload included in `tessera-quiz-complete`.
48
- *
49
- * Skips questions whose `interaction` is missing or returns nullish — custom
50
- * widgets may register without an interaction reporter (e.g. presentational
51
- * "press to continue" steps), and those simply don't contribute to the
52
- * `cmi.interactions` / xAPI Answered stream.
53
- */
54
- export function buildQuizInteractions(
55
- questions: QuizQuestionApi[],
56
- answers: Map<number, unknown>
57
- ): QuizInteractionEntry[] {
58
- const entries: QuizInteractionEntry[] = [];
59
- for (let i = 0; i < questions.length; i++) {
60
- const q = questions[i];
61
- if (typeof q.interaction !== 'function') continue;
62
- const interaction = q.interaction();
63
- if (!interaction) continue;
64
- entries.push({
65
- id: q.id,
66
- interaction,
67
- correct: q.checkAnswer(answers.get(i)),
68
- });
69
- }
70
- return entries;
71
- }
@@ -1,26 +0,0 @@
1
- <script>
2
- import { onMount } from 'svelte';
3
-
4
- let showSlowMessage = $state(false);
5
- let timer;
6
-
7
- onMount(() => {
8
- timer = setTimeout(() => {
9
- showSlowMessage = true;
10
- }, 5000);
11
-
12
- return () => clearTimeout(timer);
13
- });
14
- </script>
15
-
16
- <div class="tessera-skeleton" aria-busy="true" aria-label="Loading page content">
17
- <div class="tessera-skeleton-line"></div>
18
- <div class="tessera-skeleton-line"></div>
19
- <div class="tessera-skeleton-line"></div>
20
- <div class="tessera-skeleton-line"></div>
21
- <div class="tessera-skeleton-line"></div>
22
- <div class="tessera-skeleton-line"></div>
23
- {#if showSlowMessage}
24
- <p class="tessera-skeleton-message">Still loading…</p>
25
- {/if}
26
- </div>