@intellectif/lk-react 1.0.1 → 2.1.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.
- package/dist/{chunk-5KW7TFX3.js → chunk-3X7MYAFT.js} +110 -29
- package/dist/chunk-3X7MYAFT.js.map +1 -0
- package/dist/chunk-7BT6OXAR.cjs +225 -0
- package/dist/chunk-7BT6OXAR.cjs.map +1 -0
- package/dist/{chunk-IZNMQSQP.js → chunk-E4MNA2IQ.js} +17 -3
- package/dist/chunk-E4MNA2IQ.js.map +1 -0
- package/dist/{chunk-TVK3SVV6.cjs → chunk-IYLQSNLE.cjs} +17 -3
- package/dist/chunk-IYLQSNLE.cjs.map +1 -0
- package/dist/{chunk-6OBRYL4C.cjs → chunk-QHOV2A6M.cjs} +11 -2
- package/dist/chunk-QHOV2A6M.cjs.map +1 -0
- package/dist/{chunk-RI53A36N.cjs → chunk-STLRKR2I.cjs} +18 -5
- package/dist/chunk-STLRKR2I.cjs.map +1 -0
- package/dist/{chunk-ZPD7BGCF.js → chunk-UASXUWHH.js} +18 -5
- package/dist/chunk-UASXUWHH.js.map +1 -0
- package/dist/{chunk-L3EV5LIX.js → chunk-UIGIYYGY.js} +11 -3
- package/dist/chunk-UIGIYYGY.js.map +1 -0
- package/dist/{chunk-O3GWWJFS.cjs → chunk-UXO6KYSZ.cjs} +112 -31
- package/dist/chunk-UXO6KYSZ.cjs.map +1 -0
- package/dist/chunk-W6BH2YMZ.cjs +259 -0
- package/dist/chunk-W6BH2YMZ.cjs.map +1 -0
- package/dist/chunk-XTJ22JAP.js +223 -0
- package/dist/chunk-XTJ22JAP.js.map +1 -0
- package/dist/chunk-ZVFWJTT4.js +257 -0
- package/dist/chunk-ZVFWJTT4.js.map +1 -0
- package/dist/components/ActivitySequence.cjs +5 -5
- package/dist/components/ActivitySequence.js +4 -4
- package/dist/components/FillInTheBlanks.cjs +3 -3
- package/dist/components/FillInTheBlanks.d.cts +7 -1
- package/dist/components/FillInTheBlanks.d.ts +7 -1
- package/dist/components/FillInTheBlanks.js +2 -2
- package/dist/components/MultipleChoice.cjs +3 -3
- package/dist/components/MultipleChoice.d.cts +14 -3
- package/dist/components/MultipleChoice.d.ts +14 -3
- package/dist/components/MultipleChoice.js +2 -2
- package/dist/components/WrittenResponse.cjs +14 -0
- package/dist/components/WrittenResponse.cjs.map +1 -0
- package/dist/components/WrittenResponse.d.cts +96 -0
- package/dist/components/WrittenResponse.d.ts +96 -0
- package/dist/components/WrittenResponse.js +5 -0
- package/dist/components/WrittenResponse.js.map +1 -0
- package/dist/hooks/useXAPI.cjs +2 -2
- package/dist/hooks/useXAPI.js +1 -1
- package/dist/index.cjs +19 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +13 -5
- package/dist/index.js.map +1 -1
- package/dist/theme/skin.css +85 -0
- package/dist/types-CNmjqD6M.d.cts +108 -0
- package/dist/types-CNmjqD6M.d.ts +108 -0
- package/package.json +13 -4
- package/dist/chunk-5KW7TFX3.js.map +0 -1
- package/dist/chunk-6OBRYL4C.cjs.map +0 -1
- package/dist/chunk-IZNMQSQP.js.map +0 -1
- package/dist/chunk-L3EV5LIX.js.map +0 -1
- package/dist/chunk-O3GWWJFS.cjs.map +0 -1
- package/dist/chunk-QBA6UXMS.cjs +0 -160
- package/dist/chunk-QBA6UXMS.cjs.map +0 -1
- package/dist/chunk-RI53A36N.cjs.map +0 -1
- package/dist/chunk-TVK3SVV6.cjs.map +0 -1
- package/dist/chunk-W2L66WHW.js +0 -158
- package/dist/chunk-W2L66WHW.js.map +0 -1
- package/dist/chunk-ZPD7BGCF.js.map +0 -1
- package/dist/types-iknDq5tf.d.cts +0 -17
- package/dist/types-iknDq5tf.d.ts +0 -17
package/dist/chunk-QBA6UXMS.cjs
DELETED
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var chunk6OBRYL4C_cjs = require('./chunk-6OBRYL4C.cjs');
|
|
4
|
-
var chunkHD2AIQRD_cjs = require('./chunk-HD2AIQRD.cjs');
|
|
5
|
-
var lkCore = require('@intellectif/lk-core');
|
|
6
|
-
var react = require('react');
|
|
7
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
8
|
-
|
|
9
|
-
function hashSeed(input) {
|
|
10
|
-
let h = 2166136261 >>> 0;
|
|
11
|
-
for (let i = 0; i < input.length; i += 1) {
|
|
12
|
-
h ^= input.charCodeAt(i);
|
|
13
|
-
h = Math.imul(h, 16777619) >>> 0;
|
|
14
|
-
}
|
|
15
|
-
return h;
|
|
16
|
-
}
|
|
17
|
-
function seededShuffle(items, seed) {
|
|
18
|
-
const out = [...items];
|
|
19
|
-
let s = seed >>> 0 || 1;
|
|
20
|
-
for (let i = out.length - 1; i > 0; i -= 1) {
|
|
21
|
-
s = Math.imul(s, 1664525) + 1013904223 >>> 0;
|
|
22
|
-
const j = s % (i + 1);
|
|
23
|
-
[out[i], out[j]] = [out[j], out[i]];
|
|
24
|
-
}
|
|
25
|
-
return out;
|
|
26
|
-
}
|
|
27
|
-
function MultipleChoice({
|
|
28
|
-
data,
|
|
29
|
-
onComplete,
|
|
30
|
-
onInteraction,
|
|
31
|
-
theme,
|
|
32
|
-
locale,
|
|
33
|
-
disabled
|
|
34
|
-
}) {
|
|
35
|
-
const devError = react.useMemo(() => {
|
|
36
|
-
if (!chunk6OBRYL4C_cjs.isDevelopment()) {
|
|
37
|
-
return null;
|
|
38
|
-
}
|
|
39
|
-
const result = lkCore.validateActivity("multiple-choice", data);
|
|
40
|
-
return result.success ? null : new lkCore.ActivitySchemaError("multiple-choice", result.errors);
|
|
41
|
-
}, [data]);
|
|
42
|
-
const [sessionId] = react.useState(() => crypto.randomUUID());
|
|
43
|
-
const { state, start, complete, getTimeSpent, reset } = chunkHD2AIQRD_cjs.useActivityState();
|
|
44
|
-
const [selected, setSelected] = react.useState([]);
|
|
45
|
-
const [summary, setSummary] = react.useState(null);
|
|
46
|
-
react.useEffect(() => {
|
|
47
|
-
setSelected([]);
|
|
48
|
-
setSummary(null);
|
|
49
|
-
reset();
|
|
50
|
-
}, [data, reset]);
|
|
51
|
-
const displayedOptions = react.useMemo(
|
|
52
|
-
() => data.shuffle ? seededShuffle(data.options, hashSeed(`${sessionId}:${data.id}`)) : [...data.options],
|
|
53
|
-
[data, sessionId]
|
|
54
|
-
);
|
|
55
|
-
if (devError) {
|
|
56
|
-
throw devError;
|
|
57
|
-
}
|
|
58
|
-
const isSingle = data.mode === "single";
|
|
59
|
-
const submitted = state === "completed";
|
|
60
|
-
const inactive = disabled === true || submitted;
|
|
61
|
-
const fireInteraction = (type, payload) => {
|
|
62
|
-
onInteraction?.({ type, activityId: data.id, timestamp: Date.now(), payload });
|
|
63
|
-
};
|
|
64
|
-
const selectSingle = (optionId) => {
|
|
65
|
-
if (inactive) {
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
if (state === "idle") {
|
|
69
|
-
start();
|
|
70
|
-
}
|
|
71
|
-
setSelected([optionId]);
|
|
72
|
-
fireInteraction("option-selected", { optionId });
|
|
73
|
-
};
|
|
74
|
-
const toggleMulti = (optionId, checked) => {
|
|
75
|
-
if (inactive) {
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
if (state === "idle") {
|
|
79
|
-
start();
|
|
80
|
-
}
|
|
81
|
-
setSelected((prev) => checked ? [...prev, optionId] : prev.filter((id) => id !== optionId));
|
|
82
|
-
fireInteraction(checked ? "option-selected" : "option-deselected", { optionId });
|
|
83
|
-
};
|
|
84
|
-
const handleSubmit = (event) => {
|
|
85
|
-
event.preventDefault();
|
|
86
|
-
if (inactive) {
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
const response = { type: "multiple-choice", selectedOptionIds: selected };
|
|
90
|
-
const scoringResult = lkCore.score("multiple-choice", data, response);
|
|
91
|
-
complete();
|
|
92
|
-
const timeSpent = getTimeSpent();
|
|
93
|
-
const xapiStatement = lkCore.xAPIBuilder.buildAnsweredStatement({
|
|
94
|
-
actor: chunk6OBRYL4C_cjs.ANONYMOUS_ACTOR,
|
|
95
|
-
object: { id: chunk6OBRYL4C_cjs.objectIdFor(data.id), name: { "en-US": data.title } },
|
|
96
|
-
scoringResult,
|
|
97
|
-
timeSpentMs: timeSpent,
|
|
98
|
-
response: selected.join(",")
|
|
99
|
-
});
|
|
100
|
-
onComplete({
|
|
101
|
-
score: scoringResult.score,
|
|
102
|
-
maxScore: scoringResult.maxScore,
|
|
103
|
-
passed: scoringResult.passed,
|
|
104
|
-
timeSpent,
|
|
105
|
-
xapiStatement
|
|
106
|
-
});
|
|
107
|
-
const overall = scoringResult.passed ? data.feedback?.correct : data.feedback?.incorrect;
|
|
108
|
-
setSummary(
|
|
109
|
-
`Answer submitted. Score ${Math.round(scoringResult.score * 100)}%. ${scoringResult.passed ? "Passed." : "Not passed."}${overall ? ` ${overall}` : ""}`
|
|
110
|
-
);
|
|
111
|
-
fireInteraction("submitted", {
|
|
112
|
-
selectedOptionIds: selected,
|
|
113
|
-
score: scoringResult.score
|
|
114
|
-
});
|
|
115
|
-
};
|
|
116
|
-
const questionId = `${data.id}-question`;
|
|
117
|
-
const optionList = displayedOptions.map((option) => {
|
|
118
|
-
const checked = selected.includes(option.id);
|
|
119
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
120
|
-
"label",
|
|
121
|
-
{
|
|
122
|
-
className: "lk-mc-option",
|
|
123
|
-
"data-correct": submitted ? String(option.isCorrect) : void 0,
|
|
124
|
-
children: [
|
|
125
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
126
|
-
"input",
|
|
127
|
-
{
|
|
128
|
-
type: isSingle ? "radio" : "checkbox",
|
|
129
|
-
name: isSingle ? `${data.id}-options` : void 0,
|
|
130
|
-
value: option.id,
|
|
131
|
-
checked,
|
|
132
|
-
disabled: inactive,
|
|
133
|
-
"aria-disabled": inactive || void 0,
|
|
134
|
-
onChange: (e) => isSingle ? selectSingle(option.id) : toggleMulti(option.id, e.target.checked)
|
|
135
|
-
}
|
|
136
|
-
),
|
|
137
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: option.text }),
|
|
138
|
-
submitted && option.feedback ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "lk-mc-option-feedback", role: "note", children: option.feedback }) : null
|
|
139
|
-
]
|
|
140
|
-
},
|
|
141
|
-
option.id
|
|
142
|
-
);
|
|
143
|
-
});
|
|
144
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "lk-mc", lang: locale, style: theme, children: [
|
|
145
|
-
data.media ? /* @__PURE__ */ jsxRuntime.jsx(chunk6OBRYL4C_cjs.ActivityMedia, { media: data.media }) : null,
|
|
146
|
-
/* @__PURE__ */ jsxRuntime.jsx("form", { onSubmit: handleSubmit, children: /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { disabled: inactive, children: [
|
|
147
|
-
/* @__PURE__ */ jsxRuntime.jsx("legend", { id: questionId, children: data.question }),
|
|
148
|
-
isSingle ? /* @__PURE__ */ jsxRuntime.jsx("div", { role: "radiogroup", "aria-labelledby": questionId, children: optionList }) : /* @__PURE__ */ jsxRuntime.jsx("div", { children: optionList }),
|
|
149
|
-
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", disabled: inactive, children: "Submit" })
|
|
150
|
-
] }) }),
|
|
151
|
-
/* @__PURE__ */ jsxRuntime.jsx(chunk6OBRYL4C_cjs.FeedbackRegion, { id: `${data.id}-feedback`, children: summary })
|
|
152
|
-
] });
|
|
153
|
-
}
|
|
154
|
-
function MultipleChoice2(props) {
|
|
155
|
-
return /* @__PURE__ */ jsxRuntime.jsx(chunk6OBRYL4C_cjs.ActivityErrorBoundary, { activityTitle: props.data?.title, children: /* @__PURE__ */ jsxRuntime.jsx(MultipleChoice, { ...props }) });
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
exports.MultipleChoice = MultipleChoice2;
|
|
159
|
-
//# sourceMappingURL=chunk-QBA6UXMS.cjs.map
|
|
160
|
-
//# sourceMappingURL=chunk-QBA6UXMS.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/MultipleChoice/MultipleChoice.tsx","../src/components/MultipleChoice/index.tsx"],"names":["useMemo","isDevelopment","validateActivity","ActivitySchemaError","useState","useActivityState","useEffect","score","xAPIBuilder","ANONYMOUS_ACTOR","objectIdFor","jsxs","jsx","ActivityMedia","FeedbackRegion","MultipleChoice","ActivityErrorBoundary"],"mappings":"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","file":"chunk-QBA6UXMS.cjs","sourcesContent":["'use client';\n\nimport {\n ActivitySchemaError,\n type MultipleChoiceData,\n type MultipleChoiceOption,\n score,\n validateActivity,\n xAPIBuilder,\n} from '@intellectif/lk-core';\nimport { type CSSProperties, useEffect, useMemo, useState } from 'react';\nimport { useActivityState } from '../../hooks/useActivityState.js';\nimport { ANONYMOUS_ACTOR, isDevelopment, objectIdFor } from '../_internal.js';\nimport { ActivityMedia } from '../shared/ActivityMedia.js';\nimport { FeedbackRegion } from '../shared/FeedbackRegion.js';\nimport type { ActivityProps } from '../types.js';\n\n/** FNV-1a hash → 32-bit seed. */\nfunction hashSeed(input: string): number {\n let h = 2166136261 >>> 0;\n for (let i = 0; i < input.length; i += 1) {\n h ^= input.charCodeAt(i);\n h = Math.imul(h, 16777619) >>> 0;\n }\n return h;\n}\n\n/** Deterministic LCG Fisher–Yates; returns a permutation (no loss/dupe). */\nfunction seededShuffle<T>(items: readonly T[], seed: number): T[] {\n const out = [...items];\n let s = seed >>> 0 || 1;\n for (let i = out.length - 1; i > 0; i -= 1) {\n s = (Math.imul(s, 1664525) + 1013904223) >>> 0;\n const j = s % (i + 1);\n [out[i], out[j]] = [out[j] as T, out[i] as T];\n }\n return out;\n}\n\nexport function MultipleChoice({\n data,\n onComplete,\n onInteraction,\n theme,\n locale,\n disabled,\n}: ActivityProps<MultipleChoiceData>) {\n // Dev-only boundary validation (Req 2.3). Throwing during render lets\n // ActivityErrorBoundary catch it. Memoised so it only re-runs on data change.\n const devError = useMemo(() => {\n if (!isDevelopment()) {\n return null;\n }\n const result = validateActivity('multiple-choice', data);\n return result.success ? null : new ActivitySchemaError('multiple-choice', result.errors);\n }, [data]);\n\n const [sessionId] = useState(() => crypto.randomUUID());\n const { state, start, complete, getTimeSpent, reset } = useActivityState();\n const [selected, setSelected] = useState<string[]>([]);\n const [summary, setSummary] = useState<string | null>(null);\n\n // Reset on data-prop change (Req 3.7). `data` is an intentional change\n // trigger (not read in the body); dropping it would break the reset.\n // biome-ignore lint/correctness/useExhaustiveDependencies: data is the reset trigger (Req 3.7)\n useEffect(() => {\n setSelected([]);\n setSummary(null);\n reset();\n }, [data, reset]);\n\n const displayedOptions = useMemo<MultipleChoiceOption[]>(\n () =>\n data.shuffle\n ? seededShuffle(data.options, hashSeed(`${sessionId}:${data.id}`))\n : [...data.options],\n [data, sessionId],\n );\n\n // All hooks are called before this throw, so hook order stays stable.\n if (devError) {\n throw devError;\n }\n\n const isSingle = data.mode === 'single';\n const submitted = state === 'completed';\n const inactive = disabled === true || submitted;\n\n const fireInteraction = (\n type: 'option-selected' | 'option-deselected' | 'submitted',\n payload: Record<string, unknown>,\n ): void => {\n onInteraction?.({ type, activityId: data.id, timestamp: Date.now(), payload });\n };\n\n const selectSingle = (optionId: string): void => {\n if (inactive) {\n return;\n }\n if (state === 'idle') {\n start();\n }\n setSelected([optionId]);\n fireInteraction('option-selected', { optionId });\n };\n\n const toggleMulti = (optionId: string, checked: boolean): void => {\n if (inactive) {\n return;\n }\n if (state === 'idle') {\n start();\n }\n setSelected((prev) => (checked ? [...prev, optionId] : prev.filter((id) => id !== optionId)));\n fireInteraction(checked ? 'option-selected' : 'option-deselected', { optionId });\n };\n\n const handleSubmit = (event: React.FormEvent): void => {\n event.preventDefault();\n if (inactive) {\n return;\n }\n const response = { type: 'multiple-choice', selectedOptionIds: selected } as const;\n const scoringResult = score('multiple-choice', data, response);\n complete();\n const timeSpent = getTimeSpent();\n const xapiStatement = xAPIBuilder.buildAnsweredStatement({\n actor: ANONYMOUS_ACTOR,\n object: { id: objectIdFor(data.id), name: { 'en-US': data.title } },\n scoringResult,\n timeSpentMs: timeSpent,\n response: selected.join(','),\n });\n onComplete({\n score: scoringResult.score,\n maxScore: scoringResult.maxScore,\n passed: scoringResult.passed,\n timeSpent,\n xapiStatement,\n });\n const overall = scoringResult.passed ? data.feedback?.correct : data.feedback?.incorrect;\n setSummary(\n `Answer submitted. Score ${Math.round(scoringResult.score * 100)}%. ${\n scoringResult.passed ? 'Passed.' : 'Not passed.'\n }${overall ? ` ${overall}` : ''}`,\n );\n fireInteraction('submitted', {\n selectedOptionIds: selected,\n score: scoringResult.score,\n });\n };\n\n const questionId = `${data.id}-question`;\n\n const optionList = displayedOptions.map((option) => {\n const checked = selected.includes(option.id);\n return (\n <label\n key={option.id}\n className=\"lk-mc-option\"\n data-correct={submitted ? String(option.isCorrect) : undefined}\n >\n <input\n type={isSingle ? 'radio' : 'checkbox'}\n name={isSingle ? `${data.id}-options` : undefined}\n value={option.id}\n checked={checked}\n disabled={inactive}\n aria-disabled={inactive || undefined}\n onChange={(e) =>\n isSingle ? selectSingle(option.id) : toggleMulti(option.id, e.target.checked)\n }\n />\n <span>{option.text}</span>\n {submitted && option.feedback ? (\n <span className=\"lk-mc-option-feedback\" role=\"note\">\n {option.feedback}\n </span>\n ) : null}\n </label>\n );\n });\n\n return (\n <div className=\"lk-mc\" lang={locale} style={theme as CSSProperties | undefined}>\n {data.media ? <ActivityMedia media={data.media} /> : null}\n <form onSubmit={handleSubmit}>\n <fieldset disabled={inactive}>\n <legend id={questionId}>{data.question}</legend>\n {/*\n single: an explicit radiogroup is meaningful (fieldset's implicit\n role is `group`, not `radiogroup`). multi: the fieldset + legend\n already provide a named group — an explicit role=\"group\" here would\n be a redundant, duplicate same-named group in the a11y tree, so we\n use a plain layout div. (Refines the design ARIA sketch.)\n */}\n {isSingle ? (\n <div role=\"radiogroup\" aria-labelledby={questionId}>\n {optionList}\n </div>\n ) : (\n <div>{optionList}</div>\n )}\n <button type=\"submit\" disabled={inactive}>\n Submit\n </button>\n </fieldset>\n </form>\n <FeedbackRegion id={`${data.id}-feedback`}>{summary}</FeedbackRegion>\n </div>\n );\n}\n","'use client';\n\nimport type { MultipleChoiceData } from '@intellectif/lk-core';\nimport { ActivityErrorBoundary } from '../ActivityErrorBoundary.js';\nimport type { ActivityProps } from '../types.js';\nimport { MultipleChoice as MultipleChoiceCore } from './MultipleChoice.js';\n\nexport type { ActivityProps } from '../types.js';\n\n/**\n * Public Multiple Choice activity: the core component wrapped in\n * `ActivityErrorBoundary` so a render failure (incl. the dev schema-validation\n * throw) degrades to an accessible fallback instead of crashing the host.\n */\nexport function MultipleChoice(props: ActivityProps<MultipleChoiceData>) {\n return (\n <ActivityErrorBoundary activityTitle={props.data?.title}>\n <MultipleChoiceCore {...props} />\n </ActivityErrorBoundary>\n );\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/ActivitySequence/ActivitySequence.tsx"],"names":["useState","useRef","useEffect","jsx","jsxs","MultipleChoice","FillInTheBlanks"],"mappings":"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","file":"chunk-RI53A36N.cjs","sourcesContent":["'use client';\n\nimport type {\n ActivityData,\n ActivityResult,\n InteractionEvent,\n ThemeTokens,\n} from '@intellectif/lk-core';\nimport { useEffect, useRef, useState } from 'react';\nimport { FillInTheBlanks } from '../FillInTheBlanks/index.js';\nimport { MultipleChoice } from '../MultipleChoice/index.js';\n\nexport interface ActivitySequenceProps {\n /** The ordered set of activities to present, one at a time. */\n activities: ActivityData[];\n /** Called whenever an individual activity is completed. */\n onActivityComplete?: (result: ActivityResult, index: number) => void;\n /** Called once every activity in the set has been completed. */\n onComplete?: (results: ActivityResult[]) => void;\n /** Forwarded to each activity. */\n onInteraction?: (event: InteractionEvent) => void;\n theme?: Partial<ThemeTokens>;\n locale?: string;\n disabled?: boolean;\n}\n\n/**\n * Presents a set of activities as an in-place pager: one question visible at a\n * time, navigated with Prev/Next (no page scrolling). Linear free navigation —\n * the learner may move back and forth; activities keep their own submit and\n * scoring. On navigation, focus moves to the question region and the position\n * is announced via an aria-live region.\n */\nexport function ActivitySequence({\n activities,\n onActivityComplete,\n onComplete,\n onInteraction,\n theme,\n locale,\n disabled,\n}: ActivitySequenceProps): React.JSX.Element {\n const [index, setIndex] = useState(0);\n const [results, setResults] = useState<(ActivityResult | null)[]>(() =>\n activities.map(() => null),\n );\n const regionRef = useRef<HTMLDivElement>(null);\n const mountedRef = useRef(false);\n\n // After a navigation (not the initial mount) move focus to the question\n // region so screen-reader / keyboard users land on the new question.\n // biome-ignore lint/correctness/useExhaustiveDependencies: index is the intended trigger\n useEffect(() => {\n if (mountedRef.current) {\n regionRef.current?.focus();\n } else {\n mountedRef.current = true;\n }\n }, [index]);\n\n const total = activities.length;\n const current = activities[index];\n\n const go = (next: number): void => {\n setIndex(next);\n };\n\n const handleComplete = (result: ActivityResult): void => {\n const nextResults = results.slice();\n nextResults[index] = result;\n setResults(nextResults);\n onActivityComplete?.(result, index);\n if (nextResults.every((r): r is ActivityResult => r !== null)) {\n onComplete?.(nextResults);\n }\n };\n\n if (!current) {\n return <div className=\"lk-seq\" />;\n }\n\n const childProps = {\n onComplete: handleComplete,\n ...(onInteraction ? { onInteraction } : {}),\n ...(theme ? { theme } : {}),\n ...(locale ? { locale } : {}),\n ...(disabled ? { disabled } : {}),\n };\n\n return (\n <div className=\"lk-seq\" lang={locale}>\n <div className=\"lk-seq-progress\" aria-live=\"polite\" role=\"status\">\n Question {index + 1} of {total}\n </div>\n\n <section\n className=\"lk-seq-question\"\n ref={regionRef}\n tabIndex={-1}\n aria-label={`Question ${index + 1} of ${total}`}\n >\n {current.type === 'multiple-choice' ? (\n <MultipleChoice data={current} {...childProps} />\n ) : (\n <FillInTheBlanks data={current} {...childProps} />\n )}\n </section>\n\n <div className=\"lk-seq-nav\">\n <button\n type=\"button\"\n className=\"lk-seq-prev\"\n onClick={() => go(index - 1)}\n disabled={index === 0}\n >\n Previous\n </button>\n <button\n type=\"button\"\n className=\"lk-seq-next\"\n onClick={() => go(index + 1)}\n disabled={index === total - 1}\n >\n Next\n </button>\n </div>\n </div>\n );\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/useXAPI.ts"],"names":["useRef","useCallback"],"mappings":";;;;;AAMA,IAAM,UAAA,GAAa,CAAC,GAAA,EAAM,GAAA,EAAM,GAAI,CAAA;AAGpC,SAAS,aAAa,KAAA,EAAuB;AAC3C,EAAA,MAAM,KAAA,GAAQ,IAAI,WAAA,EAAY,CAAE,OAAO,KAAK,CAAA;AAC5C,EAAA,IAAI,MAAA,GAAS,EAAA;AACb,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,MAAA,IAAU,MAAA,CAAO,aAAa,IAAI,CAAA;AAAA,EACpC;AACA,EAAA,OAAO,KAAK,MAAM,CAAA;AACpB;AAEA,SAAS,WAAW,IAAA,EAAkC;AACpD,EAAA,OAAO,KAAK,IAAA,KAAS,OAAA,GACjB,CAAA,MAAA,EAAS,YAAA,CAAa,GAAG,IAAA,CAAK,QAAQ,CAAA,CAAA,EAAI,IAAA,CAAK,QAAQ,CAAA,CAAE,CAAC,CAAA,CAAA,GAC1D,CAAA,OAAA,EAAU,KAAK,KAAK,CAAA,CAAA;AAC1B;AAEA,IAAM,KAAA,GAAQ,CAAC,EAAA,KAA8B,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC,CAAA;AAatF,SAAS,QAAQ,MAAA,EAAmC;AAGzD,EAAA,MAAM,SAAA,GAAYA,aAAO,MAAM,CAAA;AAC/B,EAAA,SAAA,CAAU,OAAA,GAAU,MAAA;AAEpB,EAAA,MAAM,aAAA,GAAgBC,iBAAA,CAAY,OAAO,SAAA,KAA4C;AACnF,IAAA,MAAM,MAAM,SAAA,CAAU,OAAA;AACtB,IAAA,MAAM,WAAA,GAAc,IAAI,UAAA,CAAW,MAAA;AAEnC,IAAA,KAAA,IAAS,OAAA,GAAU,CAAA,EAAG,OAAA,IAAW,WAAA,EAAa,WAAW,CAAA,EAAG;AAC1D,MAAA,IAAI,UAAA;AACJ,MAAA,IAAI,OAAA,GAAU,gBAAA;AAEd,MAAA,IAAI;AACF,QAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,GAAA,CAAI,QAAA,EAAU;AAAA,UACzC,MAAA,EAAQ,MAAA;AAAA,UACR,OAAA,EAAS;AAAA,YACP,cAAA,EAAgB,kBAAA;AAAA,YAChB,0BAAA,EAA4B,OAAA;AAAA,YAC5B,aAAA,EAAe,UAAA,CAAW,GAAA,CAAI,IAAI;AAAA,WACpC;AAAA,UACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,SAAS;AAAA,SAC/B,CAAA;AAED,QAAA,IAAI,SAAS,EAAA,EAAI;AACf,UAAA;AAAA,QACF;AAEA,QAAA,UAAA,GAAa,QAAA,CAAS,MAAA;AACtB,QAAA,OAAA,GAAU,CAAA,mBAAA,EAAsB,SAAS,MAAM,CAAA,CAAA;AAI/C,QAAA,IAAI,QAAA,CAAS,SAAS,GAAA,EAAK;AACzB,UAAA,GAAA,CAAI,UAAU,EAAE,SAAA,EAAW,OAAA,EAAS,UAAA,EAAY,SAAS,CAAA;AACzD,UAAA;AAAA,QACF;AAAA,MACF,SAAS,KAAA,EAAO;AACd,QAAA,OAAA,GAAU,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,eAAA;AAAA,MACrD;AAEA,MAAA,IAAI,YAAY,WAAA,EAAa;AAC3B,QAAA,GAAA,CAAI,OAAA,GAAU;AAAA,UACZ,SAAA;AAAA,UACA,OAAA;AAAA,UACA,GAAI,UAAA,KAAe,MAAA,GAAY,EAAE,UAAA,KAAe,EAAC;AAAA,UACjD;AAAA,SACD,CAAA;AACD,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,KAAA,CAAM,UAAA,CAAW,OAAA,GAAU,CAAC,CAAC,CAAA;AAAA,IACrC;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,OAAO,EAAE,aAAA,EAAc;AACzB","file":"chunk-TVK3SVV6.cjs","sourcesContent":["'use client';\n\nimport type { XAPIConfig, XAPIStatement } from '@intellectif/lk-core';\nimport { useCallback, useRef } from 'react';\n\n/** Backoff before retry 1 / 2 / 3 (Req 10.4). */\nconst BACKOFF_MS = [1000, 2000, 4000] as const;\n\n/** UTF-8-safe base64 (`btoa` is Latin1-only and breaks on non-ASCII creds). */\nfunction toBase64Utf8(input: string): string {\n const bytes = new TextEncoder().encode(input);\n let binary = '';\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n return btoa(binary);\n}\n\nfunction authHeader(auth: XAPIConfig['auth']): string {\n return auth.type === 'basic'\n ? `Basic ${toBase64Utf8(`${auth.username}:${auth.password}`)}`\n : `Bearer ${auth.token}`;\n}\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\nexport interface UseXAPIResult {\n /**\n * Sends a statement to the configured LRS. **Never rejects** — xAPI is\n * fire-and-forget telemetry that must not break the learner's activity\n * flow. Network errors and 5xx responses are retried (backoff 1s/2s/4s,\n * up to 3 retries); a 4xx fails immediately. Any final failure is delivered\n * to `config.onError`.\n */\n sendStatement: (statement: XAPIStatement) => Promise<void>;\n}\n\nexport function useXAPI(config: XAPIConfig): UseXAPIResult {\n // Keep the latest config without changing `sendStatement`'s identity when\n // callers pass an inline config object.\n const configRef = useRef(config);\n configRef.current = config;\n\n const sendStatement = useCallback(async (statement: XAPIStatement): Promise<void> => {\n const cfg = configRef.current;\n const maxAttempts = 1 + BACKOFF_MS.length;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {\n let statusCode: number | undefined;\n let message = 'Request failed';\n\n try {\n const response = await fetch(cfg.endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Experience-API-Version': '1.0.3',\n Authorization: authHeader(cfg.auth),\n },\n body: JSON.stringify(statement),\n });\n\n if (response.ok) {\n return;\n }\n\n statusCode = response.status;\n message = `LRS responded with ${response.status}`;\n\n // Only network errors and 5xx are retryable (Req 10.4). A 4xx is a\n // client error — fail immediately rather than waste retries.\n if (response.status < 500) {\n cfg.onError?.({ statement, attempt, statusCode, message });\n return;\n }\n } catch (error) {\n message = error instanceof Error ? error.message : 'Network error';\n }\n\n if (attempt === maxAttempts) {\n cfg.onError?.({\n statement,\n attempt,\n ...(statusCode !== undefined ? { statusCode } : {}),\n message,\n });\n return;\n }\n\n await sleep(BACKOFF_MS[attempt - 1]);\n }\n }, []);\n\n return { sendStatement };\n}\n"]}
|
package/dist/chunk-W2L66WHW.js
DELETED
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
import { ActivityErrorBoundary, isDevelopment, ActivityMedia, FeedbackRegion, ANONYMOUS_ACTOR, objectIdFor } from './chunk-L3EV5LIX.js';
|
|
2
|
-
import { useActivityState } from './chunk-5HVUKXF3.js';
|
|
3
|
-
import { validateActivity, ActivitySchemaError, score, xAPIBuilder } from '@intellectif/lk-core';
|
|
4
|
-
import { useMemo, useState, useEffect } from 'react';
|
|
5
|
-
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
6
|
-
|
|
7
|
-
function hashSeed(input) {
|
|
8
|
-
let h = 2166136261 >>> 0;
|
|
9
|
-
for (let i = 0; i < input.length; i += 1) {
|
|
10
|
-
h ^= input.charCodeAt(i);
|
|
11
|
-
h = Math.imul(h, 16777619) >>> 0;
|
|
12
|
-
}
|
|
13
|
-
return h;
|
|
14
|
-
}
|
|
15
|
-
function seededShuffle(items, seed) {
|
|
16
|
-
const out = [...items];
|
|
17
|
-
let s = seed >>> 0 || 1;
|
|
18
|
-
for (let i = out.length - 1; i > 0; i -= 1) {
|
|
19
|
-
s = Math.imul(s, 1664525) + 1013904223 >>> 0;
|
|
20
|
-
const j = s % (i + 1);
|
|
21
|
-
[out[i], out[j]] = [out[j], out[i]];
|
|
22
|
-
}
|
|
23
|
-
return out;
|
|
24
|
-
}
|
|
25
|
-
function MultipleChoice({
|
|
26
|
-
data,
|
|
27
|
-
onComplete,
|
|
28
|
-
onInteraction,
|
|
29
|
-
theme,
|
|
30
|
-
locale,
|
|
31
|
-
disabled
|
|
32
|
-
}) {
|
|
33
|
-
const devError = useMemo(() => {
|
|
34
|
-
if (!isDevelopment()) {
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
const result = validateActivity("multiple-choice", data);
|
|
38
|
-
return result.success ? null : new ActivitySchemaError("multiple-choice", result.errors);
|
|
39
|
-
}, [data]);
|
|
40
|
-
const [sessionId] = useState(() => crypto.randomUUID());
|
|
41
|
-
const { state, start, complete, getTimeSpent, reset } = useActivityState();
|
|
42
|
-
const [selected, setSelected] = useState([]);
|
|
43
|
-
const [summary, setSummary] = useState(null);
|
|
44
|
-
useEffect(() => {
|
|
45
|
-
setSelected([]);
|
|
46
|
-
setSummary(null);
|
|
47
|
-
reset();
|
|
48
|
-
}, [data, reset]);
|
|
49
|
-
const displayedOptions = useMemo(
|
|
50
|
-
() => data.shuffle ? seededShuffle(data.options, hashSeed(`${sessionId}:${data.id}`)) : [...data.options],
|
|
51
|
-
[data, sessionId]
|
|
52
|
-
);
|
|
53
|
-
if (devError) {
|
|
54
|
-
throw devError;
|
|
55
|
-
}
|
|
56
|
-
const isSingle = data.mode === "single";
|
|
57
|
-
const submitted = state === "completed";
|
|
58
|
-
const inactive = disabled === true || submitted;
|
|
59
|
-
const fireInteraction = (type, payload) => {
|
|
60
|
-
onInteraction?.({ type, activityId: data.id, timestamp: Date.now(), payload });
|
|
61
|
-
};
|
|
62
|
-
const selectSingle = (optionId) => {
|
|
63
|
-
if (inactive) {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
if (state === "idle") {
|
|
67
|
-
start();
|
|
68
|
-
}
|
|
69
|
-
setSelected([optionId]);
|
|
70
|
-
fireInteraction("option-selected", { optionId });
|
|
71
|
-
};
|
|
72
|
-
const toggleMulti = (optionId, checked) => {
|
|
73
|
-
if (inactive) {
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
if (state === "idle") {
|
|
77
|
-
start();
|
|
78
|
-
}
|
|
79
|
-
setSelected((prev) => checked ? [...prev, optionId] : prev.filter((id) => id !== optionId));
|
|
80
|
-
fireInteraction(checked ? "option-selected" : "option-deselected", { optionId });
|
|
81
|
-
};
|
|
82
|
-
const handleSubmit = (event) => {
|
|
83
|
-
event.preventDefault();
|
|
84
|
-
if (inactive) {
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
const response = { type: "multiple-choice", selectedOptionIds: selected };
|
|
88
|
-
const scoringResult = score("multiple-choice", data, response);
|
|
89
|
-
complete();
|
|
90
|
-
const timeSpent = getTimeSpent();
|
|
91
|
-
const xapiStatement = xAPIBuilder.buildAnsweredStatement({
|
|
92
|
-
actor: ANONYMOUS_ACTOR,
|
|
93
|
-
object: { id: objectIdFor(data.id), name: { "en-US": data.title } },
|
|
94
|
-
scoringResult,
|
|
95
|
-
timeSpentMs: timeSpent,
|
|
96
|
-
response: selected.join(",")
|
|
97
|
-
});
|
|
98
|
-
onComplete({
|
|
99
|
-
score: scoringResult.score,
|
|
100
|
-
maxScore: scoringResult.maxScore,
|
|
101
|
-
passed: scoringResult.passed,
|
|
102
|
-
timeSpent,
|
|
103
|
-
xapiStatement
|
|
104
|
-
});
|
|
105
|
-
const overall = scoringResult.passed ? data.feedback?.correct : data.feedback?.incorrect;
|
|
106
|
-
setSummary(
|
|
107
|
-
`Answer submitted. Score ${Math.round(scoringResult.score * 100)}%. ${scoringResult.passed ? "Passed." : "Not passed."}${overall ? ` ${overall}` : ""}`
|
|
108
|
-
);
|
|
109
|
-
fireInteraction("submitted", {
|
|
110
|
-
selectedOptionIds: selected,
|
|
111
|
-
score: scoringResult.score
|
|
112
|
-
});
|
|
113
|
-
};
|
|
114
|
-
const questionId = `${data.id}-question`;
|
|
115
|
-
const optionList = displayedOptions.map((option) => {
|
|
116
|
-
const checked = selected.includes(option.id);
|
|
117
|
-
return /* @__PURE__ */ jsxs(
|
|
118
|
-
"label",
|
|
119
|
-
{
|
|
120
|
-
className: "lk-mc-option",
|
|
121
|
-
"data-correct": submitted ? String(option.isCorrect) : void 0,
|
|
122
|
-
children: [
|
|
123
|
-
/* @__PURE__ */ jsx(
|
|
124
|
-
"input",
|
|
125
|
-
{
|
|
126
|
-
type: isSingle ? "radio" : "checkbox",
|
|
127
|
-
name: isSingle ? `${data.id}-options` : void 0,
|
|
128
|
-
value: option.id,
|
|
129
|
-
checked,
|
|
130
|
-
disabled: inactive,
|
|
131
|
-
"aria-disabled": inactive || void 0,
|
|
132
|
-
onChange: (e) => isSingle ? selectSingle(option.id) : toggleMulti(option.id, e.target.checked)
|
|
133
|
-
}
|
|
134
|
-
),
|
|
135
|
-
/* @__PURE__ */ jsx("span", { children: option.text }),
|
|
136
|
-
submitted && option.feedback ? /* @__PURE__ */ jsx("span", { className: "lk-mc-option-feedback", role: "note", children: option.feedback }) : null
|
|
137
|
-
]
|
|
138
|
-
},
|
|
139
|
-
option.id
|
|
140
|
-
);
|
|
141
|
-
});
|
|
142
|
-
return /* @__PURE__ */ jsxs("div", { className: "lk-mc", lang: locale, style: theme, children: [
|
|
143
|
-
data.media ? /* @__PURE__ */ jsx(ActivityMedia, { media: data.media }) : null,
|
|
144
|
-
/* @__PURE__ */ jsx("form", { onSubmit: handleSubmit, children: /* @__PURE__ */ jsxs("fieldset", { disabled: inactive, children: [
|
|
145
|
-
/* @__PURE__ */ jsx("legend", { id: questionId, children: data.question }),
|
|
146
|
-
isSingle ? /* @__PURE__ */ jsx("div", { role: "radiogroup", "aria-labelledby": questionId, children: optionList }) : /* @__PURE__ */ jsx("div", { children: optionList }),
|
|
147
|
-
/* @__PURE__ */ jsx("button", { type: "submit", disabled: inactive, children: "Submit" })
|
|
148
|
-
] }) }),
|
|
149
|
-
/* @__PURE__ */ jsx(FeedbackRegion, { id: `${data.id}-feedback`, children: summary })
|
|
150
|
-
] });
|
|
151
|
-
}
|
|
152
|
-
function MultipleChoice2(props) {
|
|
153
|
-
return /* @__PURE__ */ jsx(ActivityErrorBoundary, { activityTitle: props.data?.title, children: /* @__PURE__ */ jsx(MultipleChoice, { ...props }) });
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
export { MultipleChoice2 as MultipleChoice };
|
|
157
|
-
//# sourceMappingURL=chunk-W2L66WHW.js.map
|
|
158
|
-
//# sourceMappingURL=chunk-W2L66WHW.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/MultipleChoice/MultipleChoice.tsx","../src/components/MultipleChoice/index.tsx"],"names":["MultipleChoice","jsx"],"mappings":"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","file":"chunk-W2L66WHW.js","sourcesContent":["'use client';\n\nimport {\n ActivitySchemaError,\n type MultipleChoiceData,\n type MultipleChoiceOption,\n score,\n validateActivity,\n xAPIBuilder,\n} from '@intellectif/lk-core';\nimport { type CSSProperties, useEffect, useMemo, useState } from 'react';\nimport { useActivityState } from '../../hooks/useActivityState.js';\nimport { ANONYMOUS_ACTOR, isDevelopment, objectIdFor } from '../_internal.js';\nimport { ActivityMedia } from '../shared/ActivityMedia.js';\nimport { FeedbackRegion } from '../shared/FeedbackRegion.js';\nimport type { ActivityProps } from '../types.js';\n\n/** FNV-1a hash → 32-bit seed. */\nfunction hashSeed(input: string): number {\n let h = 2166136261 >>> 0;\n for (let i = 0; i < input.length; i += 1) {\n h ^= input.charCodeAt(i);\n h = Math.imul(h, 16777619) >>> 0;\n }\n return h;\n}\n\n/** Deterministic LCG Fisher–Yates; returns a permutation (no loss/dupe). */\nfunction seededShuffle<T>(items: readonly T[], seed: number): T[] {\n const out = [...items];\n let s = seed >>> 0 || 1;\n for (let i = out.length - 1; i > 0; i -= 1) {\n s = (Math.imul(s, 1664525) + 1013904223) >>> 0;\n const j = s % (i + 1);\n [out[i], out[j]] = [out[j] as T, out[i] as T];\n }\n return out;\n}\n\nexport function MultipleChoice({\n data,\n onComplete,\n onInteraction,\n theme,\n locale,\n disabled,\n}: ActivityProps<MultipleChoiceData>) {\n // Dev-only boundary validation (Req 2.3). Throwing during render lets\n // ActivityErrorBoundary catch it. Memoised so it only re-runs on data change.\n const devError = useMemo(() => {\n if (!isDevelopment()) {\n return null;\n }\n const result = validateActivity('multiple-choice', data);\n return result.success ? null : new ActivitySchemaError('multiple-choice', result.errors);\n }, [data]);\n\n const [sessionId] = useState(() => crypto.randomUUID());\n const { state, start, complete, getTimeSpent, reset } = useActivityState();\n const [selected, setSelected] = useState<string[]>([]);\n const [summary, setSummary] = useState<string | null>(null);\n\n // Reset on data-prop change (Req 3.7). `data` is an intentional change\n // trigger (not read in the body); dropping it would break the reset.\n // biome-ignore lint/correctness/useExhaustiveDependencies: data is the reset trigger (Req 3.7)\n useEffect(() => {\n setSelected([]);\n setSummary(null);\n reset();\n }, [data, reset]);\n\n const displayedOptions = useMemo<MultipleChoiceOption[]>(\n () =>\n data.shuffle\n ? seededShuffle(data.options, hashSeed(`${sessionId}:${data.id}`))\n : [...data.options],\n [data, sessionId],\n );\n\n // All hooks are called before this throw, so hook order stays stable.\n if (devError) {\n throw devError;\n }\n\n const isSingle = data.mode === 'single';\n const submitted = state === 'completed';\n const inactive = disabled === true || submitted;\n\n const fireInteraction = (\n type: 'option-selected' | 'option-deselected' | 'submitted',\n payload: Record<string, unknown>,\n ): void => {\n onInteraction?.({ type, activityId: data.id, timestamp: Date.now(), payload });\n };\n\n const selectSingle = (optionId: string): void => {\n if (inactive) {\n return;\n }\n if (state === 'idle') {\n start();\n }\n setSelected([optionId]);\n fireInteraction('option-selected', { optionId });\n };\n\n const toggleMulti = (optionId: string, checked: boolean): void => {\n if (inactive) {\n return;\n }\n if (state === 'idle') {\n start();\n }\n setSelected((prev) => (checked ? [...prev, optionId] : prev.filter((id) => id !== optionId)));\n fireInteraction(checked ? 'option-selected' : 'option-deselected', { optionId });\n };\n\n const handleSubmit = (event: React.FormEvent): void => {\n event.preventDefault();\n if (inactive) {\n return;\n }\n const response = { type: 'multiple-choice', selectedOptionIds: selected } as const;\n const scoringResult = score('multiple-choice', data, response);\n complete();\n const timeSpent = getTimeSpent();\n const xapiStatement = xAPIBuilder.buildAnsweredStatement({\n actor: ANONYMOUS_ACTOR,\n object: { id: objectIdFor(data.id), name: { 'en-US': data.title } },\n scoringResult,\n timeSpentMs: timeSpent,\n response: selected.join(','),\n });\n onComplete({\n score: scoringResult.score,\n maxScore: scoringResult.maxScore,\n passed: scoringResult.passed,\n timeSpent,\n xapiStatement,\n });\n const overall = scoringResult.passed ? data.feedback?.correct : data.feedback?.incorrect;\n setSummary(\n `Answer submitted. Score ${Math.round(scoringResult.score * 100)}%. ${\n scoringResult.passed ? 'Passed.' : 'Not passed.'\n }${overall ? ` ${overall}` : ''}`,\n );\n fireInteraction('submitted', {\n selectedOptionIds: selected,\n score: scoringResult.score,\n });\n };\n\n const questionId = `${data.id}-question`;\n\n const optionList = displayedOptions.map((option) => {\n const checked = selected.includes(option.id);\n return (\n <label\n key={option.id}\n className=\"lk-mc-option\"\n data-correct={submitted ? String(option.isCorrect) : undefined}\n >\n <input\n type={isSingle ? 'radio' : 'checkbox'}\n name={isSingle ? `${data.id}-options` : undefined}\n value={option.id}\n checked={checked}\n disabled={inactive}\n aria-disabled={inactive || undefined}\n onChange={(e) =>\n isSingle ? selectSingle(option.id) : toggleMulti(option.id, e.target.checked)\n }\n />\n <span>{option.text}</span>\n {submitted && option.feedback ? (\n <span className=\"lk-mc-option-feedback\" role=\"note\">\n {option.feedback}\n </span>\n ) : null}\n </label>\n );\n });\n\n return (\n <div className=\"lk-mc\" lang={locale} style={theme as CSSProperties | undefined}>\n {data.media ? <ActivityMedia media={data.media} /> : null}\n <form onSubmit={handleSubmit}>\n <fieldset disabled={inactive}>\n <legend id={questionId}>{data.question}</legend>\n {/*\n single: an explicit radiogroup is meaningful (fieldset's implicit\n role is `group`, not `radiogroup`). multi: the fieldset + legend\n already provide a named group — an explicit role=\"group\" here would\n be a redundant, duplicate same-named group in the a11y tree, so we\n use a plain layout div. (Refines the design ARIA sketch.)\n */}\n {isSingle ? (\n <div role=\"radiogroup\" aria-labelledby={questionId}>\n {optionList}\n </div>\n ) : (\n <div>{optionList}</div>\n )}\n <button type=\"submit\" disabled={inactive}>\n Submit\n </button>\n </fieldset>\n </form>\n <FeedbackRegion id={`${data.id}-feedback`}>{summary}</FeedbackRegion>\n </div>\n );\n}\n","'use client';\n\nimport type { MultipleChoiceData } from '@intellectif/lk-core';\nimport { ActivityErrorBoundary } from '../ActivityErrorBoundary.js';\nimport type { ActivityProps } from '../types.js';\nimport { MultipleChoice as MultipleChoiceCore } from './MultipleChoice.js';\n\nexport type { ActivityProps } from '../types.js';\n\n/**\n * Public Multiple Choice activity: the core component wrapped in\n * `ActivityErrorBoundary` so a render failure (incl. the dev schema-validation\n * throw) degrades to an accessible fallback instead of crashing the host.\n */\nexport function MultipleChoice(props: ActivityProps<MultipleChoiceData>) {\n return (\n <ActivityErrorBoundary activityTitle={props.data?.title}>\n <MultipleChoiceCore {...props} />\n </ActivityErrorBoundary>\n );\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/ActivitySequence/ActivitySequence.tsx"],"names":[],"mappings":"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","file":"chunk-ZPD7BGCF.js","sourcesContent":["'use client';\n\nimport type {\n ActivityData,\n ActivityResult,\n InteractionEvent,\n ThemeTokens,\n} from '@intellectif/lk-core';\nimport { useEffect, useRef, useState } from 'react';\nimport { FillInTheBlanks } from '../FillInTheBlanks/index.js';\nimport { MultipleChoice } from '../MultipleChoice/index.js';\n\nexport interface ActivitySequenceProps {\n /** The ordered set of activities to present, one at a time. */\n activities: ActivityData[];\n /** Called whenever an individual activity is completed. */\n onActivityComplete?: (result: ActivityResult, index: number) => void;\n /** Called once every activity in the set has been completed. */\n onComplete?: (results: ActivityResult[]) => void;\n /** Forwarded to each activity. */\n onInteraction?: (event: InteractionEvent) => void;\n theme?: Partial<ThemeTokens>;\n locale?: string;\n disabled?: boolean;\n}\n\n/**\n * Presents a set of activities as an in-place pager: one question visible at a\n * time, navigated with Prev/Next (no page scrolling). Linear free navigation —\n * the learner may move back and forth; activities keep their own submit and\n * scoring. On navigation, focus moves to the question region and the position\n * is announced via an aria-live region.\n */\nexport function ActivitySequence({\n activities,\n onActivityComplete,\n onComplete,\n onInteraction,\n theme,\n locale,\n disabled,\n}: ActivitySequenceProps): React.JSX.Element {\n const [index, setIndex] = useState(0);\n const [results, setResults] = useState<(ActivityResult | null)[]>(() =>\n activities.map(() => null),\n );\n const regionRef = useRef<HTMLDivElement>(null);\n const mountedRef = useRef(false);\n\n // After a navigation (not the initial mount) move focus to the question\n // region so screen-reader / keyboard users land on the new question.\n // biome-ignore lint/correctness/useExhaustiveDependencies: index is the intended trigger\n useEffect(() => {\n if (mountedRef.current) {\n regionRef.current?.focus();\n } else {\n mountedRef.current = true;\n }\n }, [index]);\n\n const total = activities.length;\n const current = activities[index];\n\n const go = (next: number): void => {\n setIndex(next);\n };\n\n const handleComplete = (result: ActivityResult): void => {\n const nextResults = results.slice();\n nextResults[index] = result;\n setResults(nextResults);\n onActivityComplete?.(result, index);\n if (nextResults.every((r): r is ActivityResult => r !== null)) {\n onComplete?.(nextResults);\n }\n };\n\n if (!current) {\n return <div className=\"lk-seq\" />;\n }\n\n const childProps = {\n onComplete: handleComplete,\n ...(onInteraction ? { onInteraction } : {}),\n ...(theme ? { theme } : {}),\n ...(locale ? { locale } : {}),\n ...(disabled ? { disabled } : {}),\n };\n\n return (\n <div className=\"lk-seq\" lang={locale}>\n <div className=\"lk-seq-progress\" aria-live=\"polite\" role=\"status\">\n Question {index + 1} of {total}\n </div>\n\n <section\n className=\"lk-seq-question\"\n ref={regionRef}\n tabIndex={-1}\n aria-label={`Question ${index + 1} of ${total}`}\n >\n {current.type === 'multiple-choice' ? (\n <MultipleChoice data={current} {...childProps} />\n ) : (\n <FillInTheBlanks data={current} {...childProps} />\n )}\n </section>\n\n <div className=\"lk-seq-nav\">\n <button\n type=\"button\"\n className=\"lk-seq-prev\"\n onClick={() => go(index - 1)}\n disabled={index === 0}\n >\n Previous\n </button>\n <button\n type=\"button\"\n className=\"lk-seq-next\"\n onClick={() => go(index + 1)}\n disabled={index === total - 1}\n >\n Next\n </button>\n </div>\n </div>\n );\n}\n"]}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { ActivityData, ActivityResult, InteractionEvent, ThemeTokens } from '@intellectif/lk-core';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* The consistent prop contract shared by every activity component (Req 3.1).
|
|
5
|
-
* Defined here (React-specific) rather than in lk-core, which is React-free.
|
|
6
|
-
*/
|
|
7
|
-
interface ActivityProps<TData extends ActivityData = ActivityData> {
|
|
8
|
-
data: TData;
|
|
9
|
-
onComplete: (result: ActivityResult) => void;
|
|
10
|
-
onInteraction?: (event: InteractionEvent) => void;
|
|
11
|
-
/** Per-instance token overrides, applied as inline CSS vars on the root. */
|
|
12
|
-
theme?: Partial<ThemeTokens>;
|
|
13
|
-
locale?: string;
|
|
14
|
-
disabled?: boolean;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export type { ActivityProps as A };
|
package/dist/types-iknDq5tf.d.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { ActivityData, ActivityResult, InteractionEvent, ThemeTokens } from '@intellectif/lk-core';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* The consistent prop contract shared by every activity component (Req 3.1).
|
|
5
|
-
* Defined here (React-specific) rather than in lk-core, which is React-free.
|
|
6
|
-
*/
|
|
7
|
-
interface ActivityProps<TData extends ActivityData = ActivityData> {
|
|
8
|
-
data: TData;
|
|
9
|
-
onComplete: (result: ActivityResult) => void;
|
|
10
|
-
onInteraction?: (event: InteractionEvent) => void;
|
|
11
|
-
/** Per-instance token overrides, applied as inline CSS vars on the root. */
|
|
12
|
-
theme?: Partial<ThemeTokens>;
|
|
13
|
-
locale?: string;
|
|
14
|
-
disabled?: boolean;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export type { ActivityProps as A };
|