@intellectif/lk-react 18.1.0 → 20.0.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/CHANGELOG.md +69 -0
- package/README.md +2 -1
- package/dist/{WrittenResponse-CeHY5u3W.d.ts → WrittenResponse-D2YI8xOK.d.ts} +8 -2
- package/dist/{WrittenResponse-DT_Yqbq1.d.cts → WrittenResponse-obIDDYDH.d.cts} +8 -2
- package/dist/ai/useAiHelp.cjs +4 -4
- package/dist/ai/useAiHelp.d.cts +8 -2
- package/dist/ai/useAiHelp.d.ts +8 -2
- package/dist/ai/useAiHelp.js +2 -2
- package/dist/{chunk-IKV2I7KT.js → chunk-3XP6VO4G.js} +22 -15
- package/dist/chunk-3XP6VO4G.js.map +1 -0
- package/dist/{chunk-GM4PXDZ2.js → chunk-5GI53C6T.js} +22 -13
- package/dist/chunk-5GI53C6T.js.map +1 -0
- package/dist/{chunk-JH77MAON.cjs → chunk-6S2CKZ4H.cjs} +24 -17
- package/dist/chunk-6S2CKZ4H.cjs.map +1 -0
- package/dist/{chunk-JSRKES2Z.js → chunk-AG7MWZYZ.js} +25 -11
- package/dist/chunk-AG7MWZYZ.js.map +1 -0
- package/dist/{chunk-YGJE7RSW.js → chunk-AQIAQHJC.js} +42 -14
- package/dist/chunk-AQIAQHJC.js.map +1 -0
- package/dist/{chunk-4NERCBOW.js → chunk-BGA2IVQY.js} +7 -5
- package/dist/chunk-BGA2IVQY.js.map +1 -0
- package/dist/{chunk-JVWLXVYG.cjs → chunk-BJLQKJZX.cjs} +2 -2
- package/dist/chunk-BJLQKJZX.cjs.map +1 -0
- package/dist/{chunk-3SJ7TVL6.cjs → chunk-CEUEXISZ.cjs} +18 -13
- package/dist/chunk-CEUEXISZ.cjs.map +1 -0
- package/dist/{chunk-PROKRNL2.cjs → chunk-DZVF3IGB.cjs} +24 -18
- package/dist/chunk-DZVF3IGB.cjs.map +1 -0
- package/dist/{chunk-6NY7OTOO.js → chunk-HI6BUUIJ.js} +18 -12
- package/dist/chunk-HI6BUUIJ.js.map +1 -0
- package/dist/{chunk-7GYAUA56.cjs → chunk-HREA5SMB.cjs} +23 -14
- package/dist/chunk-HREA5SMB.cjs.map +1 -0
- package/dist/{chunk-THHFIP4N.js → chunk-IQ55QNBI.js} +16 -11
- package/dist/chunk-IQ55QNBI.js.map +1 -0
- package/dist/chunk-IXMT7X3E.cjs +44 -0
- package/dist/chunk-IXMT7X3E.cjs.map +1 -0
- package/dist/{chunk-X4YU6BX7.cjs → chunk-JLDSCHY5.cjs} +27 -13
- package/dist/chunk-JLDSCHY5.cjs.map +1 -0
- package/dist/{chunk-3SDCALS3.cjs → chunk-LK5VXNMR.cjs} +14 -14
- package/dist/{chunk-3SDCALS3.cjs.map → chunk-LK5VXNMR.cjs.map} +1 -1
- package/dist/{chunk-NWGQ7JML.cjs → chunk-NOC2M6LU.cjs} +7 -6
- package/dist/chunk-NOC2M6LU.cjs.map +1 -0
- package/dist/{chunk-UXV3V5NH.js → chunk-NWNQ2PHT.js} +23 -11
- package/dist/chunk-NWNQ2PHT.js.map +1 -0
- package/dist/chunk-ORBU3XKH.js +40 -0
- package/dist/chunk-ORBU3XKH.js.map +1 -0
- package/dist/{chunk-TXMP5AOW.cjs → chunk-PWLJDP3X.cjs} +29 -20
- package/dist/chunk-PWLJDP3X.cjs.map +1 -0
- package/dist/{chunk-MKWBLNTD.js → chunk-QKW2GGTV.js} +20 -11
- package/dist/chunk-QKW2GGTV.js.map +1 -0
- package/dist/{chunk-NZM3M5IR.cjs → chunk-RT2PP4SO.cjs} +27 -15
- package/dist/chunk-RT2PP4SO.cjs.map +1 -0
- package/dist/{chunk-BURYHHBM.js → chunk-RUS42NMN.js} +5 -4
- package/dist/chunk-RUS42NMN.js.map +1 -0
- package/dist/{chunk-TL3GVPBO.cjs → chunk-TRMWBJWT.cjs} +41 -13
- package/dist/chunk-TRMWBJWT.cjs.map +1 -0
- package/dist/{chunk-CQNKZ435.cjs → chunk-UHIOVOFK.cjs} +7 -5
- package/dist/chunk-UHIOVOFK.cjs.map +1 -0
- package/dist/{chunk-WSPVQR4O.js → chunk-W6DMHN33.js} +8 -8
- package/dist/{chunk-WSPVQR4O.js.map → chunk-W6DMHN33.js.map} +1 -1
- package/dist/{chunk-TEAVPUMX.js → chunk-WBLYD5QA.js} +2 -2
- package/dist/chunk-WBLYD5QA.js.map +1 -0
- package/dist/components/ActivityPreview.cjs +12 -12
- package/dist/components/ActivityPreview.d.cts +2 -2
- package/dist/components/ActivityPreview.d.ts +2 -2
- package/dist/components/ActivityPreview.js +11 -11
- package/dist/components/ActivitySequence.cjs +12 -12
- package/dist/components/ActivitySequence.d.cts +16 -4
- package/dist/components/ActivitySequence.d.ts +16 -4
- package/dist/components/ActivitySequence.js +11 -11
- package/dist/components/Dictation.cjs +6 -6
- package/dist/components/Dictation.d.cts +1 -1
- package/dist/components/Dictation.d.ts +1 -1
- package/dist/components/Dictation.js +5 -5
- package/dist/components/FillInTheBlanks.cjs +6 -6
- package/dist/components/FillInTheBlanks.d.cts +1 -1
- package/dist/components/FillInTheBlanks.d.ts +1 -1
- package/dist/components/FillInTheBlanks.js +5 -5
- package/dist/components/GapSelect.cjs +6 -6
- package/dist/components/GapSelect.d.cts +1 -1
- package/dist/components/GapSelect.d.ts +1 -1
- package/dist/components/GapSelect.js +5 -5
- package/dist/components/InteractiveVideo.cjs +12 -12
- package/dist/components/InteractiveVideo.d.cts +16 -3
- package/dist/components/InteractiveVideo.d.ts +16 -3
- package/dist/components/InteractiveVideo.js +10 -10
- package/dist/components/MultipleChoice.cjs +6 -6
- package/dist/components/MultipleChoice.d.cts +1 -1
- package/dist/components/MultipleChoice.d.ts +1 -1
- package/dist/components/MultipleChoice.js +5 -5
- package/dist/components/PronunciationFeedback.d.cts +1 -1
- package/dist/components/PronunciationFeedback.d.ts +1 -1
- package/dist/components/ReadAloud.cjs +4 -4
- package/dist/components/ReadAloud.d.cts +2 -2
- package/dist/components/ReadAloud.d.ts +2 -2
- package/dist/components/ReadAloud.js +3 -3
- package/dist/components/StimulusPanel.d.cts +1 -1
- package/dist/components/StimulusPanel.d.ts +1 -1
- package/dist/components/WrittenResponse.cjs +4 -3
- package/dist/components/WrittenResponse.d.cts +3 -3
- package/dist/components/WrittenResponse.d.ts +3 -3
- package/dist/components/WrittenResponse.js +3 -2
- package/dist/i18n/LkIntlProvider.d.cts +2 -2
- package/dist/i18n/LkIntlProvider.d.ts +2 -2
- package/dist/index.cjs +25 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +13 -13
- package/dist/index.js.map +1 -1
- package/dist/{types-DtPYG1hh.d.cts → types-B_PCcqO-.d.cts} +9 -1
- package/dist/{types-BY-4S5Rd.d.ts → types-C-GMCJ0g.d.ts} +9 -1
- package/package.json +3 -3
- package/dist/chunk-3SJ7TVL6.cjs.map +0 -1
- package/dist/chunk-4NERCBOW.js.map +0 -1
- package/dist/chunk-6NY7OTOO.js.map +0 -1
- package/dist/chunk-7GYAUA56.cjs.map +0 -1
- package/dist/chunk-BRPEB43C.cjs +0 -13
- package/dist/chunk-BRPEB43C.cjs.map +0 -1
- package/dist/chunk-BURYHHBM.js.map +0 -1
- package/dist/chunk-CQNKZ435.cjs.map +0 -1
- package/dist/chunk-GM4PXDZ2.js.map +0 -1
- package/dist/chunk-IKV2I7KT.js.map +0 -1
- package/dist/chunk-JH77MAON.cjs.map +0 -1
- package/dist/chunk-JSRKES2Z.js.map +0 -1
- package/dist/chunk-JVWLXVYG.cjs.map +0 -1
- package/dist/chunk-MKWBLNTD.js.map +0 -1
- package/dist/chunk-NWGQ7JML.cjs.map +0 -1
- package/dist/chunk-NZM3M5IR.cjs.map +0 -1
- package/dist/chunk-PROKRNL2.cjs.map +0 -1
- package/dist/chunk-RCMYEWBE.js +0 -11
- package/dist/chunk-RCMYEWBE.js.map +0 -1
- package/dist/chunk-TEAVPUMX.js.map +0 -1
- package/dist/chunk-THHFIP4N.js.map +0 -1
- package/dist/chunk-TL3GVPBO.cjs.map +0 -1
- package/dist/chunk-TXMP5AOW.cjs.map +0 -1
- package/dist/chunk-UXV3V5NH.js.map +0 -1
- package/dist/chunk-X4YU6BX7.cjs.map +0 -1
- package/dist/chunk-YGJE7RSW.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,74 @@
|
|
|
1
1
|
# @intellectif/lk-react
|
|
2
2
|
|
|
3
|
+
## 20.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- 73a37e3: Every activity, `<ActivitySequence>` and `<InteractiveVideo>` take a `delivery` policy: what the school
|
|
8
|
+
running a paper lets a learner see. Each setting only takes away from what `renderMode` shows, and an
|
|
9
|
+
absent or empty policy takes nothing — every test that existed before passes unchanged.
|
|
10
|
+
|
|
11
|
+
- **`feedback: false`** — no marks, no score, no authored feedback; the learner sees "Answer
|
|
12
|
+
submitted." and `onComplete` still receives the grade. In `review` a grade is not read back, while
|
|
13
|
+
"Not graded yet" still is. A read-aloud shows no grade or marks after a take, a written response
|
|
14
|
+
no returned grade, and the video's end card counts answers instead of scoring them.
|
|
15
|
+
- **`solutions: false`** — the right answer is never shown beside a wrong one: multiple choice marks
|
|
16
|
+
only the options the learner chose (and hides feedback written on the ones they did not),
|
|
17
|
+
`showCorrectAnswers` writes nothing into a blank, a dictation offers no "Show solution".
|
|
18
|
+
- **`hints: false`** — no hints of any kind: the author's fill-in-the-blanks hints, a dictation's
|
|
19
|
+
word hints, and AI hints. The author's hints stay **on in `exam` by default, as they always were**:
|
|
20
|
+
an authored hint is part of the item and the same for every learner, so a paper of record may offer
|
|
21
|
+
it. A paper whose hints are help rather than part of the question switches them off.
|
|
22
|
+
- **`ai: { hints?, explanations? }`** — the deployment's switches for AI help, beside the author's on
|
|
23
|
+
the item and the host's ports. "Explain my answer" also needs `feedback` and `solutions`: it explains
|
|
24
|
+
a grade, and all but always names the right answer.
|
|
25
|
+
- **The paper decides.** A pager publishes its policy to every question it holds, which combines it
|
|
26
|
+
with its own, whichever is stricter. A `renderers` override is handed it as `delivery`, a video's
|
|
27
|
+
`renderQuestion` as `question.delivery` spelled out, and `useAiHints` / `useAiExplanation` take a
|
|
28
|
+
`delivery` input and read the paper's themselves — so a host's question that ignores what it was
|
|
29
|
+
handed still offers no AI help the paper forbids.
|
|
30
|
+
- **An unreadable policy restricts**, never allows, and a development build warns once.
|
|
31
|
+
|
|
32
|
+
**Major** because the peer range moves to `@intellectif/lk-core@^0.20.0`. `InteractiveVideoQuestion`
|
|
33
|
+
gains a required `delivery` field — a host constructing one by hand, in a test say, needs to add it.
|
|
34
|
+
|
|
35
|
+
See `docs/delivery.md`.
|
|
36
|
+
|
|
37
|
+
### Patch Changes
|
|
38
|
+
|
|
39
|
+
- Updated dependencies [73a37e3]
|
|
40
|
+
- @intellectif/lk-core@0.20.0
|
|
41
|
+
|
|
42
|
+
## 19.0.0
|
|
43
|
+
|
|
44
|
+
### Major Changes
|
|
45
|
+
|
|
46
|
+
- d576382: AI help now reports what it cost and what was refused.
|
|
47
|
+
|
|
48
|
+
- **`ai-hint-shown` and `ai-explanation-shown` carry `usage`** when your port sent it, beside the
|
|
49
|
+
`provenance` they already carried. What a learner was shown and what it cost are then one record,
|
|
50
|
+
keyed to the attempt — no second channel to reconcile.
|
|
51
|
+
- **`ai-help-refused` is new**, from the same one implementation the components and the hooks share
|
|
52
|
+
(`useAiHints`, `useAiExplanation`). It fires where a learner is told help is not available, with
|
|
53
|
+
`feature` (`hint` or `explanation`), `reason` (`reveals-answer`, `contradicts-grade`, `malformed`,
|
|
54
|
+
`empty`, `too-long`) and, for a hint, `hintNumber`. **The text is never carried:** a hint refused
|
|
55
|
+
for revealing the answer contains the answer, and interactions are logged.
|
|
56
|
+
|
|
57
|
+
A host that keeps every interaction will start seeing this kind. It is additive — nothing that
|
|
58
|
+
was emitted before has changed — but a `switch` over `InteractionKind` with no default will not
|
|
59
|
+
know it.
|
|
60
|
+
|
|
61
|
+
**Major** because the peer range moves to `@intellectif/lk-core@^0.19.0`, whose `ai-check` entry
|
|
62
|
+
point and `AiTextResult.usage` come with it. No React API was removed or renamed, and a host that
|
|
63
|
+
passes no AI port sees nothing new.
|
|
64
|
+
|
|
65
|
+
See `docs/ai.md`.
|
|
66
|
+
|
|
67
|
+
### Patch Changes
|
|
68
|
+
|
|
69
|
+
- Updated dependencies [d576382]
|
|
70
|
+
- @intellectif/lk-core@0.19.0
|
|
71
|
+
|
|
3
72
|
## 18.1.0
|
|
4
73
|
|
|
5
74
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -73,7 +73,8 @@ export function Demo() {
|
|
|
73
73
|
- **`<PronunciationFeedback>`** — the marks on their own, for a review screen that has evidence but no activity: the graded dimensions (accuracy, fluency, completeness, prosody — one the engine did not measure reads "not assessed", **never 0%**), and every word marked `correct` / `mispronounced` / `omitted` / `inserted` with a hidden sentence per word for screen readers and a glyph plus a text decoration for everyone else. A word opens onto its syllables, its sounds, what was heard instead, and a button that plays just that word. Evidence it cannot trust is checked before it is aligned, so in production a malformed assessment costs the word list — never the grade beside it.
|
|
74
74
|
- **`<WrittenResponse>`** — free-text writing with a live word counter and bounds messaging, graded **asynchronously**: it emits an ungraded submission (never a fake zero) and a SUBMITTED-verb xAPI statement, and renders a returned `GradeRecord` in `review` mode with per-criterion scores and inline corrections.
|
|
75
75
|
- **`<InteractiveVideo>`** — a video that stops at each quiz and asks its questions over itself, then plays on. **A formative tool**, for lessons and practice — deliver official summative exams with `<ActivitySequence>`. One player: a progress bar that marks every quiz and previews the caption under the pointer, speed, volume, captions drawn from WebVTT it parses itself (through a `captionsLoader` when the file needs the learner's credentials) — in one language or two at once, a second line under the first for a learner matching what they hear to what it means — a contents and transcript panel, picture-in-picture, fullscreen and a keyboard map with a shortcut sheet. A quiz covers the video and grows the player rather than scrolling inside it, every question of an opened quiz stays mounted so a rewind loses no answer, the controls are `inert` while it is open, and a **required** quiz holds both playback and seeking until it is answered. Answers report with the slot the question sits in and the quiz it belongs to, and `onProgress` gives a resume point that is never past an unanswered required quiz. A host with renderers of its own draws any question itself through `renderQuestion` — the video still counts it, tells it when it leaves the screen so it can stop its microphone, and holds Finish while its answer is still on its way. See the [interactive video guide](https://github.com/intellectif/learning-kit/blob/main/docs/interactive-video.md).
|
|
76
|
-
- **
|
|
76
|
+
- **Delivery policies** — `delivery` on any activity, `<ActivitySequence>` or `<InteractiveVideo>` switches off feedback, solutions, hints or AI help for that paper, so one question serves practice and a final without being authored twice. It can only take away, an empty policy is exactly the default, and a pager's policy holds in every question it holds — a host's own renderer included. See [Delivery policies](https://github.com/intellectif/learning-kit/blob/main/docs/delivery.md).
|
|
77
|
+
- **AI help for learners** — "Explain my answer" after grading and "Get a hint" before submit, in `<MultipleChoice>`, `<FillInTheBlanks>`, `<GapSelect>` and `<Dictation>` (explanations only), through ports **you** supply with `<LkAiProvider>` or an `ai` prop (also on `<ActivitySequence>` and `<InteractiveVideo>`). The SDK never calls a model or holds a key: it builds the facts your model is given, refuses an explanation that contradicts the grade and a hint that contains the answer, marks everything a model wrote, and drops a late answer. Never in `exam`. What was shown reaches `onInteraction` with the model that wrote it and what the call cost; what was refused reaches it with the reason, and never the text. See the [AI guide](https://github.com/intellectif/learning-kit/blob/main/docs/ai.md).
|
|
77
78
|
- **`<ActivitySequence>`** — in-place "question set" pager (Previous/Next, "Question X of N", no scrolling, focus-managed). Accepts item groups and keeps their stimulus beside every question; `onSubmit` reports every raw answer with its `slotId`, which is the only response channel an `exam` sequence has. `onFinished` is the completion signal for a set that mixes scored and deferred-graded items, where `onComplete` can never fire. A read-aloud slot takes its storage from `recordingBinding`, whose methods are told which slot a take belongs to, and a `review` its per-word marks from `assessments`, keyed by `slotId` — there is a [worked example](https://github.com/intellectif/learning-kit/blob/main/docs/speech-assessment.md#in-a-question-set).
|
|
78
79
|
- **Resume and review a whole attempt** — `<ActivitySequence>` takes `defaultIndex`, `responses` and `submittedSlotIds` (read at mount; remount with a `key` to show a different attempt), so an interrupted paper reopens on the right question with the right answers and already-committed questions still committed. `onIndexChange` reports every position the pager lands on, including a clamp it had to apply. Pass `renderMode="review"` plus server-computed `outcomes` to render a finished attempt read-only. Pairs with `serializeAttemptState` / `restoreAttemptState` in `lk-core`.
|
|
79
80
|
- **`renderMode`** — `practice` (default: the component scores locally and reveals correctness), `exam` (never scores, never reveals; submit emits the raw response for the server to grade), `review` (read-only, marks correctness only from an `outcome` you supply). This is the single switch that takes grading off the client.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { XAPIStatement, WrittenResponseData, LearnerResponse, ItemOutcome, InteractionEvent, ThemeTokens } from '@intellectif/lk-core';
|
|
2
|
-
import { f as Renderable, e as RenderMode, H as HtmlSanitizer, M as MediaBudgetBinding, b as MediaTransportStrings, a as LkStringsOverride } from './types-
|
|
1
|
+
import { XAPIStatement, WrittenResponseData, LearnerResponse, ItemOutcome, InteractionEvent, ThemeTokens, DeliveryPolicy } from '@intellectif/lk-core';
|
|
2
|
+
import { f as Renderable, e as RenderMode, H as HtmlSanitizer, M as MediaBudgetBinding, b as MediaTransportStrings, a as LkStringsOverride } from './types-C-GMCJ0g.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Payload delivered when the learner submits a written response. Grading is
|
|
@@ -94,6 +94,12 @@ interface WrittenResponseProps {
|
|
|
94
94
|
theme?: Partial<ThemeTokens>;
|
|
95
95
|
locale?: string;
|
|
96
96
|
disabled?: boolean;
|
|
97
|
+
/**
|
|
98
|
+
* The delivery policy. An essay is graded later, so only `feedback` reaches
|
|
99
|
+
* it: `false` reads a returned grade back as nothing in `review`. See
|
|
100
|
+
* `DeliveryPolicy` in lk-core.
|
|
101
|
+
*/
|
|
102
|
+
delivery?: DeliveryPolicy | null;
|
|
97
103
|
}
|
|
98
104
|
|
|
99
105
|
export type { WrittenResponseProps as W, WrittenResponseSubmission as a };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { XAPIStatement, WrittenResponseData, LearnerResponse, ItemOutcome, InteractionEvent, ThemeTokens } from '@intellectif/lk-core';
|
|
2
|
-
import { f as Renderable, e as RenderMode, H as HtmlSanitizer, M as MediaBudgetBinding, b as MediaTransportStrings, a as LkStringsOverride } from './types-
|
|
1
|
+
import { XAPIStatement, WrittenResponseData, LearnerResponse, ItemOutcome, InteractionEvent, ThemeTokens, DeliveryPolicy } from '@intellectif/lk-core';
|
|
2
|
+
import { f as Renderable, e as RenderMode, H as HtmlSanitizer, M as MediaBudgetBinding, b as MediaTransportStrings, a as LkStringsOverride } from './types-B_PCcqO-.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Payload delivered when the learner submits a written response. Grading is
|
|
@@ -94,6 +94,12 @@ interface WrittenResponseProps {
|
|
|
94
94
|
theme?: Partial<ThemeTokens>;
|
|
95
95
|
locale?: string;
|
|
96
96
|
disabled?: boolean;
|
|
97
|
+
/**
|
|
98
|
+
* The delivery policy. An essay is graded later, so only `feedback` reaches
|
|
99
|
+
* it: `false` reads a returned grade back as nothing in `review`. See
|
|
100
|
+
* `DeliveryPolicy` in lk-core.
|
|
101
|
+
*/
|
|
102
|
+
delivery?: DeliveryPolicy | null;
|
|
97
103
|
}
|
|
98
104
|
|
|
99
105
|
export type { WrittenResponseProps as W, WrittenResponseSubmission as a };
|
package/dist/ai/useAiHelp.cjs
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
4
|
+
var chunkTRMWBJWT_cjs = require('../chunk-TRMWBJWT.cjs');
|
|
5
5
|
require('../chunk-ZDYNAWDZ.cjs');
|
|
6
|
-
require('../chunk-
|
|
6
|
+
require('../chunk-BJLQKJZX.cjs');
|
|
7
7
|
require('../chunk-EANGKAKG.cjs');
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
Object.defineProperty(exports, "useAiExplanation", {
|
|
12
12
|
enumerable: true,
|
|
13
|
-
get: function () { return
|
|
13
|
+
get: function () { return chunkTRMWBJWT_cjs.useAiExplanation; }
|
|
14
14
|
});
|
|
15
15
|
Object.defineProperty(exports, "useAiHints", {
|
|
16
16
|
enumerable: true,
|
|
17
|
-
get: function () { return
|
|
17
|
+
get: function () { return chunkTRMWBJWT_cjs.useAiHints; }
|
|
18
18
|
});
|
|
19
19
|
//# sourceMappingURL=useAiHelp.cjs.map
|
|
20
20
|
//# sourceMappingURL=useAiHelp.cjs.map
|
package/dist/ai/useAiHelp.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AiTextResult, LearnerResponse, InteractionEvent, ItemOutcome } from '@intellectif/lk-core';
|
|
2
|
-
import { g as RenderableActivity, e as RenderMode } from '../types-
|
|
1
|
+
import { AiTextResult, LearnerResponse, InteractionEvent, DeliveryPolicy, ItemOutcome } from '@intellectif/lk-core';
|
|
2
|
+
import { g as RenderableActivity, e as RenderMode } from '../types-B_PCcqO-.cjs';
|
|
3
3
|
import { LearnerAi } from './LkAiProvider.cjs';
|
|
4
4
|
import '../machine-CuwKqWXC.cjs';
|
|
5
5
|
import 'react';
|
|
@@ -34,6 +34,12 @@ interface AiHelpSituation {
|
|
|
34
34
|
locale?: string;
|
|
35
35
|
/** Where `ai-hint-shown` and `ai-explanation-shown` go. */
|
|
36
36
|
onInteraction?: (event: InteractionEvent) => void;
|
|
37
|
+
/**
|
|
38
|
+
* The delivery policy your question was handed. The paper around the
|
|
39
|
+
* question holds as well — a set that switched AI hints off keeps them off
|
|
40
|
+
* here, whatever is passed — so leaving it out never turns anything on.
|
|
41
|
+
*/
|
|
42
|
+
delivery?: DeliveryPolicy | null;
|
|
37
43
|
}
|
|
38
44
|
interface AiExplanationInput extends AiHelpSituation {
|
|
39
45
|
/** The grade of record, which `review` explains. */
|
package/dist/ai/useAiHelp.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AiTextResult, LearnerResponse, InteractionEvent, ItemOutcome } from '@intellectif/lk-core';
|
|
2
|
-
import { g as RenderableActivity, e as RenderMode } from '../types-
|
|
1
|
+
import { AiTextResult, LearnerResponse, InteractionEvent, DeliveryPolicy, ItemOutcome } from '@intellectif/lk-core';
|
|
2
|
+
import { g as RenderableActivity, e as RenderMode } from '../types-C-GMCJ0g.js';
|
|
3
3
|
import { LearnerAi } from './LkAiProvider.js';
|
|
4
4
|
import '../machine-CuwKqWXC.js';
|
|
5
5
|
import 'react';
|
|
@@ -34,6 +34,12 @@ interface AiHelpSituation {
|
|
|
34
34
|
locale?: string;
|
|
35
35
|
/** Where `ai-hint-shown` and `ai-explanation-shown` go. */
|
|
36
36
|
onInteraction?: (event: InteractionEvent) => void;
|
|
37
|
+
/**
|
|
38
|
+
* The delivery policy your question was handed. The paper around the
|
|
39
|
+
* question holds as well — a set that switched AI hints off keeps them off
|
|
40
|
+
* here, whatever is passed — so leaving it out never turns anything on.
|
|
41
|
+
*/
|
|
42
|
+
delivery?: DeliveryPolicy | null;
|
|
37
43
|
}
|
|
38
44
|
interface AiExplanationInput extends AiHelpSituation {
|
|
39
45
|
/** The grade of record, which `review` explains. */
|
package/dist/ai/useAiHelp.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
export { useAiExplanation, useAiHints } from '../chunk-
|
|
2
|
+
export { useAiExplanation, useAiHints } from '../chunk-AQIAQHJC.js';
|
|
3
3
|
import '../chunk-YNDKAYW3.js';
|
|
4
|
-
import '../chunk-
|
|
4
|
+
import '../chunk-WBLYD5QA.js';
|
|
5
5
|
import '../chunk-PPFVTXGJ.js';
|
|
6
6
|
//# sourceMappingURL=useAiHelp.js.map
|
|
7
7
|
//# sourceMappingURL=useAiHelp.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { AiHints, AiExplanation } from './chunk-
|
|
2
|
+
import { AiHints, AiExplanation } from './chunk-RUS42NMN.js';
|
|
3
3
|
import { useLearnerAi } from './chunk-YNDKAYW3.js';
|
|
4
|
-
import { FeedbackRegion } from './chunk-
|
|
4
|
+
import { useDeliveryPolicy, FeedbackRegion, outcomeShowsMarks } from './chunk-ORBU3XKH.js';
|
|
5
5
|
import { ActivityErrorBoundary } from './chunk-FEOFX4QW.js';
|
|
6
6
|
import { isDevelopment, ANONYMOUS_ACTOR, objectIdFor } from './chunk-PPFVTXGJ.js';
|
|
7
7
|
import { ActivityMedia } from './chunk-BY4UQH2Y.js';
|
|
@@ -65,12 +65,14 @@ function FillInTheBlanks({
|
|
|
65
65
|
locale,
|
|
66
66
|
disabled,
|
|
67
67
|
showCorrectAnswers,
|
|
68
|
-
ai: aiProp
|
|
68
|
+
ai: aiProp,
|
|
69
|
+
delivery
|
|
69
70
|
}) {
|
|
70
71
|
const isExam = renderMode === "exam";
|
|
71
72
|
const isReview = renderMode === "review";
|
|
72
73
|
const s = useLkStrings(strings);
|
|
73
74
|
const ai = useLearnerAi(aiProp);
|
|
75
|
+
const policy = useDeliveryPolicy(delivery);
|
|
74
76
|
const devError = useMemo(() => {
|
|
75
77
|
if (!isDevelopment()) {
|
|
76
78
|
return null;
|
|
@@ -139,6 +141,8 @@ function FillInTheBlanks({
|
|
|
139
141
|
const submitted = state === "completed";
|
|
140
142
|
const inactive = disabled === true || submitted || isReview;
|
|
141
143
|
const revealing = isReview ? outcome?.status === "scored" : !isExam && submitted;
|
|
144
|
+
const marking = revealing && policy.feedback;
|
|
145
|
+
const showingAnswers = marking && policy.solutions && showCorrectAnswers === true;
|
|
142
146
|
const fireInteraction = (type, payload) => {
|
|
143
147
|
onInteraction?.({ type, activityId: data.id, timestamp: Date.now(), payload });
|
|
144
148
|
};
|
|
@@ -280,8 +284,9 @@ function FillInTheBlanks({
|
|
|
280
284
|
const blankFeedback = isExam ? void 0 : blank.feedback;
|
|
281
285
|
const correctness = correctByBlank.get(seg.id);
|
|
282
286
|
const hintId = `${data.id}-hint-${seg.id}`;
|
|
287
|
+
const hint = policy.hints ? blank.hint : void 0;
|
|
283
288
|
const correctAnswer = acceptedAnswers?.[0];
|
|
284
|
-
if (
|
|
289
|
+
if (showingAnswers && correctness === false && correctAnswer) {
|
|
285
290
|
return /* @__PURE__ */ jsx("span", { className: "lk-fib-answer", "data-correct": "false", children: correctAnswer }, seg.id);
|
|
286
291
|
}
|
|
287
292
|
return /* @__PURE__ */ jsxs("span", { className: "lk-fib-blank", children: [
|
|
@@ -290,15 +295,15 @@ function FillInTheBlanks({
|
|
|
290
295
|
{
|
|
291
296
|
type: "text",
|
|
292
297
|
"aria-label": s.blankLabel(seg.ordinal),
|
|
293
|
-
"aria-describedby":
|
|
298
|
+
"aria-describedby": hint ? hintId : void 0,
|
|
294
299
|
value: answers[seg.id] ?? "",
|
|
295
300
|
disabled: inactive,
|
|
296
301
|
"aria-disabled": inactive || void 0,
|
|
297
|
-
"data-correct":
|
|
302
|
+
"data-correct": marking && correctness !== void 0 ? String(correctness) : void 0,
|
|
298
303
|
onChange: (e) => handleChange(seg.id, e.target.value)
|
|
299
304
|
}
|
|
300
305
|
),
|
|
301
|
-
|
|
306
|
+
hint ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
302
307
|
/* @__PURE__ */ jsx(
|
|
303
308
|
"button",
|
|
304
309
|
{
|
|
@@ -329,9 +334,9 @@ function FillInTheBlanks({
|
|
|
329
334
|
)
|
|
330
335
|
}
|
|
331
336
|
),
|
|
332
|
-
/* @__PURE__ */ jsx("span", { id: hintId, "aria-live": "polite", children: revealed.has(seg.id) ?
|
|
337
|
+
/* @__PURE__ */ jsx("span", { id: hintId, "aria-live": "polite", children: revealed.has(seg.id) ? hint : "" })
|
|
333
338
|
] }) : null,
|
|
334
|
-
|
|
339
|
+
marking && !feedbackHidden && blankFeedback ? /* @__PURE__ */ jsx(
|
|
335
340
|
"span",
|
|
336
341
|
{
|
|
337
342
|
className: "lk-fib-blank-feedback",
|
|
@@ -353,12 +358,13 @@ function FillInTheBlanks({
|
|
|
353
358
|
response: { type: "fill-in-the-blanks", answers },
|
|
354
359
|
locale,
|
|
355
360
|
onInteraction,
|
|
356
|
-
strings: s
|
|
361
|
+
strings: s,
|
|
362
|
+
delivery: policy
|
|
357
363
|
}
|
|
358
364
|
),
|
|
359
365
|
isReview ? null : /* @__PURE__ */ jsx("button", { type: "submit", disabled: inactive, children: isExam ? s.submitAnswers : s.checkAnswers })
|
|
360
366
|
] }),
|
|
361
|
-
|
|
367
|
+
marking && data.blanks.some((b) => b.feedback) ? /* @__PURE__ */ jsx(
|
|
362
368
|
"button",
|
|
363
369
|
{
|
|
364
370
|
type: "button",
|
|
@@ -368,7 +374,7 @@ function FillInTheBlanks({
|
|
|
368
374
|
children: feedbackHidden ? s.showFeedback : s.hideFeedback
|
|
369
375
|
}
|
|
370
376
|
) : null,
|
|
371
|
-
/* @__PURE__ */ jsx(FeedbackRegion, { id: `${data.id}-feedback`, children: isReview ? reviewSummary : summary }),
|
|
377
|
+
/* @__PURE__ */ jsx(FeedbackRegion, { id: `${data.id}-feedback`, children: isReview ? policy.feedback || !outcomeShowsMarks(outcome) ? reviewSummary : null : policy.feedback || summary === null ? summary : s.answerSubmitted }),
|
|
372
378
|
/* @__PURE__ */ jsx(
|
|
373
379
|
AiExplanation,
|
|
374
380
|
{
|
|
@@ -380,7 +386,8 @@ function FillInTheBlanks({
|
|
|
380
386
|
outcome,
|
|
381
387
|
locale,
|
|
382
388
|
onInteraction,
|
|
383
|
-
strings: s
|
|
389
|
+
strings: s,
|
|
390
|
+
delivery: policy
|
|
384
391
|
}
|
|
385
392
|
)
|
|
386
393
|
]
|
|
@@ -393,5 +400,5 @@ function FillInTheBlanks2(props) {
|
|
|
393
400
|
}
|
|
394
401
|
|
|
395
402
|
export { FillInTheBlanks2 as FillInTheBlanks };
|
|
396
|
-
//# sourceMappingURL=chunk-
|
|
397
|
-
//# sourceMappingURL=chunk-
|
|
403
|
+
//# sourceMappingURL=chunk-3XP6VO4G.js.map
|
|
404
|
+
//# sourceMappingURL=chunk-3XP6VO4G.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/FillInTheBlanks/FillInTheBlanks.tsx","../src/components/FillInTheBlanks/index.tsx"],"names":["result","FillInTheBlanks","jsx"],"mappings":"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","file":"chunk-3XP6VO4G.js","sourcesContent":["'use client';\n\nimport {\n ActivitySchemaError,\n assertRedacted,\n type FillInTheBlanksData,\n type FillInTheBlanksLearnerResponse,\n type LearnerResponse,\n type ScoringDetail,\n type ScoringResult,\n score,\n validateActivity,\n xAPIBuilder,\n xapiDefinitionFor,\n} from '@intellectif/lk-core';\nimport { type CSSProperties, useEffect, useMemo, useRef, useState } from 'react';\nimport { useLearnerAi } from '../../ai/LkAiProvider.js';\nimport { useActivityState } from '../../hooks/useActivityState.js';\nimport { useLkStrings } from '../../i18n/LkIntlProvider.js';\nimport { ANONYMOUS_ACTOR, isDevelopment, objectIdFor } from '../_internal.js';\nimport { ActivityMedia } from '../shared/ActivityMedia.js';\nimport { AiExplanation, AiHints } from '../shared/AiHelp.js';\nimport { outcomeShowsMarks, useDeliveryPolicy } from '../shared/delivery.js';\nimport { FeedbackRegion } from '../shared/FeedbackRegion.js';\nimport type { ActivityProps } from '../types.js';\n\nexport interface FillInTheBlanksProps extends ActivityProps<FillInTheBlanksData> {\n /**\n * After submission, replace each incorrectly-answered blank with its first\n * accepted answer, styled distinctly (Req 5.7). Component-specific prop: it\n * is presentation, not activity data, and is outside the fixed Req-3.1 set.\n *\n * Ignored in `exam` mode — revealing the key is precisely what an exam must\n * not do, and on a `redact()` projection there is no key to reveal. In\n * `review` mode it applies only to blanks the supplied `outcome` marks\n * incorrect, and only when the caller passed data that still carries the key\n * (e.g. `redact(data, { reveal: 'after-submit' })`).\n */\n showCorrectAnswers?: boolean;\n}\n\nconst PLACEHOLDER = /\\{\\{\\s*([^{}]+?)\\s*\\}\\}/g;\n\ntype Segment = { kind: 'text'; value: string } | { kind: 'blank'; id: string; ordinal: number };\n\nfunction parsePassage(passage: string): Segment[] {\n const segments: Segment[] = [];\n const re = new RegExp(PLACEHOLDER);\n let last = 0;\n let ordinal = 0;\n let match = re.exec(passage);\n while (match !== null) {\n if (match.index > last) {\n segments.push({ kind: 'text', value: passage.slice(last, match.index) });\n }\n ordinal += 1;\n segments.push({ kind: 'blank', id: match[1] as string, ordinal });\n last = match.index + match[0].length;\n match = re.exec(passage);\n }\n if (last < passage.length) {\n segments.push({ kind: 'text', value: passage.slice(last) });\n }\n return segments;\n}\n\n/** Shared empty map: keeps the \"no response supplied\" path allocation-free. */\nconst NO_ANSWERS: Record<string, string> = {};\n\n/**\n * Reads the answer map out of a `LearnerResponse`. A response of another\n * activity type is treated as \"no answers\" rather than throwing: a controlled\n * host that has not yet swapped its state on an activity change would\n * otherwise crash the attempt.\n */\nfunction answersOf(response: LearnerResponse | undefined): Record<string, string> {\n return response !== undefined && response.type === 'fill-in-the-blanks'\n ? response.answers\n : NO_ANSWERS;\n}\n\n/**\n * Per-item correctness keyed by blank id. Prefers the unambiguous `outcome`\n * field (always written by the built-in scorers since lk-core 0.3.0) and\n * falls back to the deprecated `correct` boolean so a 0.2-era\n * consumer-constructed `ItemOutcome` still marks correctly in `review`.\n */\nfunction correctnessByItem(details: readonly ScoringDetail[]): Map<string, boolean> {\n const map = new Map<string, boolean>();\n for (const detail of details) {\n map.set(\n detail.itemId,\n detail.outcome !== undefined ? detail.outcome === 'correct' : detail.correct,\n );\n }\n return map;\n}\n\nexport function FillInTheBlanks({\n data,\n onComplete,\n onSubmit,\n onChange,\n onInteraction,\n value,\n defaultValue,\n defaultSubmitted,\n renderMode = 'practice',\n outcome,\n sanitizeHtml,\n mediaBudget,\n mediaStrings,\n strings,\n theme,\n locale,\n disabled,\n showCorrectAnswers,\n ai: aiProp,\n delivery,\n}: FillInTheBlanksProps) {\n const isExam = renderMode === 'exam';\n const isReview = renderMode === 'review';\n\n // Dev-only boundary validation (Req 2.3); throws in render so the wrapping\n // ActivityErrorBoundary catches it. Re-runs only when data changes.\n const s = useLkStrings(strings);\n const ai = useLearnerAi(aiProp);\n const policy = useDeliveryPolicy(delivery);\n\n const devError = useMemo(() => {\n if (!isDevelopment()) {\n return null;\n }\n if (data.redacted === true) {\n // A redact() projection cannot satisfy the full content schema — the\n // answer key is gone by design. Validate it against the STRICT redacted\n // schema instead, which additionally proves the payload is learner-safe.\n try {\n assertRedacted(data);\n return null;\n } catch (error) {\n return error instanceof Error ? error : new Error(String(error));\n }\n }\n const result = validateActivity('fill-in-the-blanks', data);\n return result.success ? null : new ActivitySchemaError('fill-in-the-blanks', result.errors);\n }, [data]);\n\n const { state, start, complete, getTimeSpent, reset } = useActivityState(\n defaultSubmitted === true ? 'completed' : 'idle',\n );\n // Controlled when `value` is supplied: the answers rendered are ALWAYS the\n // caller's, and internal state is never read. Uncontrolled otherwise,\n // seeded from `defaultValue`.\n const isControlled = value !== undefined;\n const [internalAnswers, setInternalAnswers] = useState<Record<string, string>>(() =>\n answersOf(defaultValue),\n );\n const [revealed, setRevealed] = useState<Set<string>>(() => new Set());\n const [result, setResult] = useState<ScoringResult | null>(null);\n const [summary, setSummary] = useState<string | null>(null);\n const [feedbackHidden, setFeedbackHidden] = useState(false);\n\n const answers = isControlled ? answersOf(value) : internalAnswers;\n\n // `defaultValue` is read only by the reset effect, and it is commonly an\n // inline object literal — putting it in that effect's deps would re-seed\n // (and wipe) the learner's typing on every render. Mirror it into a ref in\n // its own effect, which commits before the reset effect below.\n const defaultValueRef = useRef(defaultValue);\n useEffect(() => {\n defaultValueRef.current = defaultValue;\n }, [defaultValue]);\n\n // Mirror `defaultSubmitted` so the reset below returns to the SEEDED state.\n // Resetting unconditionally to idle unlocked an item the learner had already\n // committed — which made `defaultSubmitted` a no-op here, since this effect\n // runs right after the first paint.\n const defaultSubmittedRef = useRef(defaultSubmitted);\n useEffect(() => {\n defaultSubmittedRef.current = defaultSubmitted;\n }, [defaultSubmitted]);\n\n // Identity guard so the MOUNT run is a no-op. Without it this effect fires\n // after the first paint and undoes every seed it was just given; with it,\n // only a real `data` change resets. A parent that rebuilds structurally\n // identical entries in render (`activities={raw.map(redact)}`) must not\n // unlock or revert a restored answer — the pager already remounts a slot\n // whose activity actually changed, via its key.\n const lastDataRef = useRef(data);\n // `data` is an intentional reset trigger (Req 3.7); it is already in the\n // dependency list. The identity guard below skips the mount run.\n useEffect(() => {\n if (lastDataRef.current === data) {\n return;\n }\n lastDataRef.current = data;\n setInternalAnswers(answersOf(defaultValueRef.current));\n setRevealed(new Set());\n setResult(null);\n setSummary(null);\n setFeedbackHidden(false);\n reset(defaultSubmittedRef.current === true ? 'completed' : 'idle');\n }, [data, reset]);\n\n /*\n * RICH TEXT — deliberate, documented limitation (see `sanitizeHtml`).\n *\n * Every other activity can render its `*Html` field through the caller's\n * sanitiser, because the rich text is a LEAF: the sanitised string is\n * handed to one `dangerouslySetInnerHTML` node and nothing is inserted into\n * it. A fill-in-the-blanks passage is not a leaf — it is the CONTAINER of\n * the React-controlled `<input>`s, one per `{{id}}` placeholder.\n *\n * Placing those inputs inside sanitised HTML means slicing the sanitised\n * string at the placeholders and injecting each slice as its own HTML\n * fragment, which is unsafe and broken on both counts:\n * 1. Broken: the slices are unbalanced. `<p>A {{x}} B</p>` yields `<p>A `\n * and ` B</p>`; the fragment parser auto-closes both, so the input\n * lands OUTSIDE the paragraph and the authored block structure is\n * destroyed.\n * 2. Unsafe: the sanitiser's guarantee covers the document it returned,\n * not arbitrary substrings of it. A placeholder inside an attribute\n * (`<img alt=\"{{x}}\">`) splits mid-attribute, and re-parsing the\n * halves in a fresh context is exactly the mutation (mXSS) class of\n * transformation that voids a sanitiser's output guarantee. An exam\n * runner must never depend on that.\n *\n * The safe alternative — parse the sanitised string once into a detached\n * DOM, split only TEXT nodes at placeholders, and portal the inputs into\n * anchors — needs a DOM at render time (no SSR) and a large imperative\n * subsystem. Until that lands, the plain-text `passage` is rendered (always\n * escaped by React), which is correct, answerable, and safe in every mode.\n * `data.passageHtml` is carried and redacted by lk-core regardless, so no\n * authored content is lost — only this component declines to render it.\n */\n useEffect(() => {\n if (isDevelopment() && sanitizeHtml !== undefined && data.passageHtml !== undefined) {\n console.warn(\n '[lk-react] FillInTheBlanks ignores `passageHtml`: the passage hosts the answer inputs, ' +\n 'so rich HTML cannot be split at {{placeholders}} without voiding the sanitiser. ' +\n 'Rendering the plain `passage` instead.',\n );\n }\n }, [sanitizeHtml, data.passageHtml]);\n\n const segments = useMemo(() => parsePassage(data.passage), [data.passage]);\n const blankById = useMemo(() => new Map(data.blanks.map((b) => [b.id, b])), [data.blanks]);\n\n if (devError) {\n throw devError;\n }\n // Practice grades locally, which a redacted projection cannot support: the\n // submit handler below calls `score()`, which throws RedactedScoringError —\n // from an event handler, where no error boundary can catch it, AFTER the\n // learner has typed their answers. Fail loudly at render instead, in\n // production too. This mirrors the identical guard in MultipleChoice;\n // without it the two built-ins disagreed about the same accident, and\n // wiring an exam item into the self-grading mode is precisely what\n // `renderMode` exists to prevent.\n if (data.redacted === true && renderMode === 'practice') {\n throw new Error(\n `Fill-in-the-Blanks \"${data.id}\" received redacted activity data in renderMode \"practice\", ` +\n 'which grades locally and has no answer key to grade against. ' +\n 'Render redacted data with renderMode=\"exam\" (server grades) or \"review\" (pass `outcome`).',\n );\n }\n\n const submitted = state === 'completed';\n const inactive = disabled === true || submitted || isReview;\n\n /**\n * Whether the component may show answer-key-derived information (per-blank\n * correctness, authored feedback, correct answers). NEVER in `exam`; in\n * `practice` only after the component scored locally; in `review` only once\n * the caller supplies a SCORED outcome — an item that is still awaiting a\n * grade must not have its key revealed just because it is being read back.\n */\n const revealing = isReview ? outcome?.status === 'scored' : !isExam && submitted;\n // What the delivery policy lets that reveal show: right and wrong at all,\n // with the author's feedback, and the correct answers `showCorrectAnswers`\n // would write into a wrong blank.\n const marking = revealing && policy.feedback;\n const showingAnswers = marking && policy.solutions && showCorrectAnswers === true;\n\n const fireInteraction = (\n type: 'blank-filled' | 'hint-requested' | 'submitted',\n payload: Record<string, unknown>,\n ): void => {\n onInteraction?.({ type, activityId: data.id, timestamp: Date.now(), payload });\n };\n\n const handleChange = (blankId: string, text: string): void => {\n if (inactive) {\n return;\n }\n if (state === 'idle') {\n start();\n }\n const next = { ...answers, [blankId]: text };\n if (!isControlled) {\n setInternalAnswers(next);\n }\n onChange?.({ type: 'fill-in-the-blanks', answers: next });\n fireInteraction('blank-filled', { blankId, value: text });\n };\n\n const toggleHint = (blankId: string): void => {\n if (inactive) {\n return;\n }\n if (state === 'idle') {\n start();\n }\n setRevealed((prev) => {\n const next = new Set(prev);\n if (next.has(blankId)) {\n next.delete(blankId);\n return next;\n }\n next.add(blankId);\n return next;\n });\n // Only a reveal is a \"hint requested\"; hiding is not a new request.\n if (!revealed.has(blankId)) {\n fireInteraction('hint-requested', { blankId });\n }\n };\n\n const handleSubmit = (event: React.FormEvent): void => {\n event.preventDefault();\n if (inactive) {\n return;\n }\n const response: FillInTheBlanksLearnerResponse = { type: 'fill-in-the-blanks', answers };\n // Fires in every submitting mode and always BEFORE onComplete, so an exam\n // runner can persist the raw response regardless of local grading.\n onSubmit?.(response);\n\n if (isExam) {\n // EXAM: the client neither grades nor reveals. No score()/evaluate(), no\n // read of any answer-key field, no onComplete — and no xAPI statement,\n // because its `correctResponsesPattern` IS the answer key. The server\n // owns the grade; it emits the statement.\n complete();\n setSummary(s.answerSubmitted);\n fireInteraction('submitted', { answers });\n return;\n }\n\n // PRACTICE: unchanged v1 behaviour. `data` carries the key here — exam\n // mode is the only path that may be handed a redact() projection.\n const scoringResult = score('fill-in-the-blanks', data as FillInTheBlanksData, response);\n complete();\n const timeSpent = getTimeSpent();\n const xapiStatement = xAPIBuilder.buildAnsweredStatement({\n actor: ANONYMOUS_ACTOR,\n object: {\n id: objectIdFor(data.id),\n name: { [data.locale ?? 'en-US']: data.title },\n ...xapiDefinitionFor(data),\n },\n scoringResult,\n timeSpentMs: timeSpent,\n response: JSON.stringify(answers),\n });\n setResult(scoringResult);\n onComplete?.({\n score: scoringResult.score,\n maxScore: scoringResult.maxScore,\n passed: scoringResult.passed,\n timeSpent,\n xapiStatement,\n });\n // Core selects the authored overall feedback on `passed` (B3 fix).\n const overall = scoringResult.feedback;\n setSummary(\n `${s.answerSubmitted} ${s.scoreAnnouncement(\n Math.round(scoringResult.score * 100),\n scoringResult.passed,\n )}${overall ? ` ${overall}` : ''}`,\n );\n fireInteraction('submitted', { answers, score: scoringResult.score });\n };\n\n const correctByBlank = useMemo(() => {\n if (isExam) {\n // Nothing is ever marked client-side in an exam.\n return new Map<string, boolean>();\n }\n if (isReview) {\n // Correctness comes ONLY from the server-computed outcome; the component\n // never scores in review, so an absent/ungraded outcome marks nothing.\n return outcome?.status === 'scored'\n ? correctnessByItem(outcome.details)\n : new Map<string, boolean>();\n }\n return correctnessByItem(result?.details ?? []);\n }, [isExam, isReview, outcome, result]);\n\n /** Review has no local score: its summary is read off `outcome`, or nothing. */\n const reviewSummary = useMemo(() => {\n if (!isReview || outcome === undefined) {\n return null;\n }\n if (outcome.status === 'scored') {\n return `${s.scoreAnnouncement(Math.round(outcome.score * 100), outcome.passed)}${\n outcome.feedback ? ` ${outcome.feedback}` : ''\n }`;\n }\n if (outcome.status === 'deferred') {\n return s.notGradedYet;\n }\n // `graded` used to fall into the arm below and announce \"No grade\n // available.\" over a grade that had come back. Normalised by maxScore so a\n // grader payload of 8.5 / 10 does not read as 850% — same guard as\n // `<WrittenResponse>`.\n if (outcome.status === 'graded') {\n const percent =\n outcome.maxScore > 0\n ? Math.round((outcome.score / outcome.maxScore) * 100)\n : Math.round(outcome.score * 100);\n return `${s.scoreAnnouncement(percent, outcome.passed)}${\n outcome.feedback ? ` ${outcome.feedback}` : ''\n }`;\n }\n return s.noGradeAvailable;\n }, [isReview, outcome, s]);\n\n return (\n <form\n className=\"lk-fib\"\n aria-label={data.title}\n lang={locale}\n data-render-mode={renderMode}\n style={theme as CSSProperties | undefined}\n onSubmit={handleSubmit}\n >\n {data.media ? (\n <ActivityMedia\n media={data.media}\n renderMode={renderMode}\n {...(mediaBudget !== undefined ? { mediaBudget } : {})}\n {...(mediaStrings !== undefined ? { mediaStrings } : {})}\n {...(strings !== undefined ? { strings } : {})}\n {...(onInteraction !== undefined ? { onInteraction } : {})}\n {...(locale !== undefined ? { locale } : {})}\n />\n ) : null}\n <fieldset disabled={inactive}>\n <p className=\"lk-fib-passage\">\n {segments.map((seg, i) => {\n if (seg.kind === 'text') {\n // biome-ignore lint/suspicious/noArrayIndexKey: passage segments are positional and static\n return <span key={`t${i}`}>{seg.value}</span>;\n }\n const blank = blankById.get(seg.id);\n if (!blank) {\n return null;\n }\n // `Renderable` only widens `scoringStrategy` at the type level, so\n // the answer-key fields still LOOK required here while a redact()\n // projection omits them at runtime. Read them defensively, and\n // never at all in exam mode.\n const acceptedAnswers: string[] | undefined = isExam\n ? undefined\n : blank.acceptedAnswers;\n const blankFeedback = isExam ? undefined : blank.feedback;\n const correctness = correctByBlank.get(seg.id);\n const hintId = `${data.id}-hint-${seg.id}`;\n // The author's hint, where the delivery policy offers hints. On in\n // every mode by default — including `exam`, where it is public.\n const hint = policy.hints ? blank.hint : undefined;\n const correctAnswer = acceptedAnswers?.[0];\n if (showingAnswers && correctness === false && correctAnswer) {\n return (\n <span key={seg.id} className=\"lk-fib-answer\" data-correct=\"false\">\n {correctAnswer}\n </span>\n );\n }\n return (\n <span key={seg.id} className=\"lk-fib-blank\">\n <input\n type=\"text\"\n aria-label={s.blankLabel(seg.ordinal)}\n aria-describedby={hint ? hintId : undefined}\n value={answers[seg.id] ?? ''}\n disabled={inactive}\n aria-disabled={inactive || undefined}\n data-correct={\n marking && correctness !== undefined ? String(correctness) : undefined\n }\n onChange={(e) => handleChange(seg.id, e.target.value)}\n />\n {/*\n Hints stay available in exam mode by design: lk-core's field\n policy classifies `blanks.hint` as `public`, so it survives\n redact() and is not part of the answer key.\n */}\n {hint ? (\n <>\n {/*\n Default affordance is an icon; the accessible NAME stays\n text via aria-label (screen readers + tests rely on it).\n The glyph is restylable/replaceable via .lk-fib-hint-btn.\n */}\n <button\n type=\"button\"\n className=\"lk-fib-hint-btn\"\n aria-controls={hintId}\n aria-expanded={revealed.has(seg.id)}\n aria-label={revealed.has(seg.id) ? s.hideHint : s.showHint}\n disabled={inactive}\n onClick={() => toggleHint(seg.id)}\n >\n <svg\n className=\"lk-fib-hint-icon\"\n viewBox=\"0 0 24 24\"\n width=\"16\"\n height=\"16\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <path\n fill=\"currentColor\"\n d=\"M9 21h6v-1H9v1Zm3-19a7 7 0 0 0-4 12.74V17h8v-2.26A7 7 0 0 0 12 2Z\"\n />\n </svg>\n </button>\n {/*\n Not role=\"tooltip\": a real ARIA tooltip is a named\n hover/focus popup with strict WCAG 1.4.13 constraints.\n This is an accessible click-to-toggle disclosure that is\n the input's aria-describedby target and is announced via\n aria-live; the skin gives it a tooltip-like *visual*\n without the tooltip *semantics*. (Refines Task 15.3.)\n */}\n <span id={hintId} aria-live=\"polite\">\n {revealed.has(seg.id) ? hint : ''}\n </span>\n </>\n ) : null}\n {marking && !feedbackHidden && blankFeedback ? (\n <span\n className=\"lk-fib-blank-feedback\"\n role=\"note\"\n data-correct={correctness !== undefined ? String(correctness) : undefined}\n >\n {blankFeedback}\n </span>\n ) : null}\n </span>\n );\n })}\n </p>\n <AiHints\n ai={ai}\n data={data}\n renderMode={renderMode}\n submitted={submitted}\n disabled={disabled === true}\n response={{ type: 'fill-in-the-blanks', answers }}\n locale={locale}\n onInteraction={onInteraction}\n strings={s}\n delivery={policy}\n />\n {/* Review is read-only: there is nothing to submit. */}\n {isReview ? null : (\n <button type=\"submit\" disabled={inactive}>\n {isExam ? s.submitAnswers : s.checkAnswers}\n </button>\n )}\n </fieldset>\n {marking && data.blanks.some((b) => b.feedback) ? (\n <button\n type=\"button\"\n className=\"lk-fib-feedback-toggle\"\n aria-expanded={!feedbackHidden}\n onClick={() => setFeedbackHidden((h) => !h)}\n >\n {feedbackHidden ? s.showFeedback : s.hideFeedback}\n </button>\n ) : null}\n <FeedbackRegion id={`${data.id}-feedback`}>\n {isReview\n ? policy.feedback || !outcomeShowsMarks(outcome)\n ? reviewSummary\n : null\n : policy.feedback || summary === null\n ? summary\n : s.answerSubmitted}\n </FeedbackRegion>\n <AiExplanation\n ai={ai}\n data={data}\n renderMode={renderMode}\n submitted={submitted}\n response={{ type: 'fill-in-the-blanks', answers }}\n outcome={outcome}\n locale={locale}\n onInteraction={onInteraction}\n strings={s}\n delivery={policy}\n />\n </form>\n );\n}\n","'use client';\n\nimport { useLkStrings } from '../../i18n/LkIntlProvider.js';\nimport { ActivityErrorBoundary } from '../ActivityErrorBoundary.js';\nimport {\n FillInTheBlanks as FillInTheBlanksCore,\n type FillInTheBlanksProps,\n} from './FillInTheBlanks.js';\n\nexport type { FillInTheBlanksProps } from './FillInTheBlanks.js';\n\n/**\n * Public Fill-in-the-Blanks activity: the core 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 FillInTheBlanks(props: FillInTheBlanksProps) {\n // Read here rather than in the boundary: a class component cannot call a\n // hook, and the fallback it renders is learner-facing text like any other.\n const strings = useLkStrings(props.strings);\n return (\n <ActivityErrorBoundary activityTitle={props.data?.title} strings={strings}>\n <FillInTheBlanksCore {...props} />\n </ActivityErrorBoundary>\n );\n}\n"]}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { AiExplanation } from './chunk-
|
|
2
|
+
import { AiExplanation } from './chunk-RUS42NMN.js';
|
|
3
3
|
import { useLearnerAi } from './chunk-YNDKAYW3.js';
|
|
4
4
|
import { localeDirectionOf, textDirectionOf, characterDirectionOf } from './chunk-YORQQXGO.js';
|
|
5
|
-
import { FeedbackRegion } from './chunk-
|
|
5
|
+
import { useDeliveryPolicy, FeedbackRegion, outcomeShowsMarks } from './chunk-ORBU3XKH.js';
|
|
6
6
|
import { ActivityErrorBoundary } from './chunk-FEOFX4QW.js';
|
|
7
7
|
import { isDevelopment, ANONYMOUS_ACTOR, objectIdFor } from './chunk-PPFVTXGJ.js';
|
|
8
8
|
import { ActivityMedia } from './chunk-BY4UQH2Y.js';
|
|
@@ -310,12 +310,14 @@ function Dictation({
|
|
|
310
310
|
theme,
|
|
311
311
|
locale,
|
|
312
312
|
disabled,
|
|
313
|
-
ai: aiProp
|
|
313
|
+
ai: aiProp,
|
|
314
|
+
delivery
|
|
314
315
|
}) {
|
|
315
316
|
const isExam = renderMode === "exam";
|
|
316
317
|
const isReview = renderMode === "review";
|
|
317
318
|
const s = useLkStrings(strings);
|
|
318
319
|
const ai = useLearnerAi(aiProp);
|
|
320
|
+
const policy = useDeliveryPolicy(delivery);
|
|
319
321
|
const hasKey = typeof data.transcript === "string";
|
|
320
322
|
const devError = useMemo(() => {
|
|
321
323
|
if (!isDevelopment()) {
|
|
@@ -405,12 +407,13 @@ function Dictation({
|
|
|
405
407
|
const submitted = state === "completed";
|
|
406
408
|
const inactive = disabled === true || submitted || isReview;
|
|
407
409
|
const revealing = isReview ? outcome?.status === "scored" : !isExam && submitted;
|
|
410
|
+
const marking = revealing && policy.feedback;
|
|
408
411
|
const transcript = isExam || !hasKey ? void 0 : data.transcript;
|
|
409
412
|
const hintWords = useMemo(
|
|
410
413
|
() => transcript === void 0 ? [] : hintWordsOf(transcript),
|
|
411
414
|
[transcript]
|
|
412
415
|
);
|
|
413
|
-
const hintsOffered = data.hints?.mode === "progressive-words" && !isExam && !isReview && transcript !== void 0;
|
|
416
|
+
const hintsOffered = policy.hints && data.hints?.mode === "progressive-words" && !isExam && !isReview && transcript !== void 0;
|
|
414
417
|
const hintsEnabled = hintsOffered && !submitted;
|
|
415
418
|
const hintTotal = hintWords.length;
|
|
416
419
|
const hintsShown = Math.min(revealed, hintTotal);
|
|
@@ -536,8 +539,8 @@ function Dictation({
|
|
|
536
539
|
const contentLang = typeof data.locale === "string" ? data.locale.replaceAll("_", "-") : void 0;
|
|
537
540
|
const localeDir = localeDirectionOf(data.locale);
|
|
538
541
|
const alignment = useMemo(
|
|
539
|
-
() =>
|
|
540
|
-
[
|
|
542
|
+
() => marking && transcript !== void 0 && (!isReview || hasResponse) ? alignDictation(data, text) : null,
|
|
543
|
+
[marking, transcript, isReview, hasResponse, data, text]
|
|
541
544
|
);
|
|
542
545
|
const sentenceDiff = useMemo(
|
|
543
546
|
() => alignment !== null && alignment.attempt !== "" ? diffDictationChars(alignment.reference, alignment.attempt) : null,
|
|
@@ -548,7 +551,7 @@ function Dictation({
|
|
|
548
551
|
[isReview, alignment, outcome]
|
|
549
552
|
);
|
|
550
553
|
const words = alignment?.words ?? detailWords;
|
|
551
|
-
const marksShown =
|
|
554
|
+
const marksShown = marking && words !== null;
|
|
552
555
|
const contentDir = localeDir ?? textDirectionOf(transcript ?? words?.map((word) => word.reference).join(" ") ?? "");
|
|
553
556
|
const nothingTyped = alignment !== null ? alignment.attempt === "" : words?.every((word) => word.attempt === "") ?? false;
|
|
554
557
|
const passed = isReview ? outcome?.status === "scored" || outcome?.status === "graded" ? outcome.passed : void 0 : result?.passed;
|
|
@@ -674,7 +677,7 @@ function Dictation({
|
|
|
674
677
|
value: text,
|
|
675
678
|
disabled: inactive,
|
|
676
679
|
"aria-disabled": inactive || void 0,
|
|
677
|
-
"data-correct":
|
|
680
|
+
"data-correct": marking && passed !== void 0 && (!isReview || hasResponse) ? String(passed) : void 0,
|
|
678
681
|
onChange: (event) => handleTextChange(event.target.value)
|
|
679
682
|
}
|
|
680
683
|
),
|
|
@@ -726,7 +729,7 @@ function Dictation({
|
|
|
726
729
|
] }),
|
|
727
730
|
/* @__PURE__ */ jsx("p", { className: "lk-dc-diff-note", children: s.dictationDiffNote })
|
|
728
731
|
] }),
|
|
729
|
-
transcript !== void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
732
|
+
transcript !== void 0 && policy.solutions ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
730
733
|
/* @__PURE__ */ jsx(
|
|
731
734
|
"button",
|
|
732
735
|
{
|
|
@@ -753,7 +756,12 @@ function Dictation({
|
|
|
753
756
|
) : null
|
|
754
757
|
] }) : null
|
|
755
758
|
] }) : null,
|
|
756
|
-
/* @__PURE__ */ jsx(FeedbackRegion, { id: `${data.id}-feedback`, children: /* @__PURE__ */ jsx(
|
|
759
|
+
/* @__PURE__ */ jsx(FeedbackRegion, { id: `${data.id}-feedback`, children: /* @__PURE__ */ jsx(
|
|
760
|
+
AnnouncementText,
|
|
761
|
+
{
|
|
762
|
+
announcement: isReview ? policy.feedback || !outcomeShowsMarks(outcome) ? reviewSummary : null : policy.feedback || summary === null ? summary : { text: s.answerSubmitted, feedback: null }
|
|
763
|
+
}
|
|
764
|
+
) }),
|
|
757
765
|
/* @__PURE__ */ jsx(
|
|
758
766
|
AiExplanation,
|
|
759
767
|
{
|
|
@@ -765,7 +773,8 @@ function Dictation({
|
|
|
765
773
|
outcome,
|
|
766
774
|
locale,
|
|
767
775
|
onInteraction,
|
|
768
|
-
strings: s
|
|
776
|
+
strings: s,
|
|
777
|
+
delivery: policy
|
|
769
778
|
}
|
|
770
779
|
)
|
|
771
780
|
]
|
|
@@ -778,5 +787,5 @@ function Dictation2(props) {
|
|
|
778
787
|
}
|
|
779
788
|
|
|
780
789
|
export { Dictation2 as Dictation };
|
|
781
|
-
//# sourceMappingURL=chunk-
|
|
782
|
-
//# sourceMappingURL=chunk-
|
|
790
|
+
//# sourceMappingURL=chunk-5GI53C6T.js.map
|
|
791
|
+
//# sourceMappingURL=chunk-5GI53C6T.js.map
|