@intellectif/lk-react 18.0.0 → 18.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.
Files changed (149) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +3 -1
  3. package/dist/{WrittenResponse-B4kY-U0v.d.ts → WrittenResponse-CeHY5u3W.d.ts} +1 -1
  4. package/dist/{WrittenResponse-Dl3zah22.d.cts → WrittenResponse-DT_Yqbq1.d.cts} +1 -1
  5. package/dist/ai/useAiHelp.cjs +20 -0
  6. package/dist/ai/useAiHelp.cjs.map +1 -0
  7. package/dist/ai/useAiHelp.d.cts +146 -0
  8. package/dist/ai/useAiHelp.d.ts +146 -0
  9. package/dist/ai/useAiHelp.js +7 -0
  10. package/dist/ai/useAiHelp.js.map +1 -0
  11. package/dist/{chunk-Z5XY66PO.cjs → chunk-3SDCALS3.cjs} +16 -16
  12. package/dist/chunk-3SDCALS3.cjs.map +1 -0
  13. package/dist/{chunk-QA42VDTA.cjs → chunk-3SJ7TVL6.cjs} +12 -11
  14. package/dist/chunk-3SJ7TVL6.cjs.map +1 -0
  15. package/dist/{chunk-V5BTVGPA.js → chunk-4NERCBOW.js} +4 -3
  16. package/dist/chunk-4NERCBOW.js.map +1 -0
  17. package/dist/{chunk-UYQBEPNZ.js → chunk-6NY7OTOO.js} +15 -8
  18. package/dist/chunk-6NY7OTOO.js.map +1 -0
  19. package/dist/{chunk-RZ52SEYV.cjs → chunk-7GYAUA56.cjs} +10 -9
  20. package/dist/chunk-7GYAUA56.cjs.map +1 -0
  21. package/dist/{chunk-BAKLJKFZ.cjs → chunk-APZ6JFN6.cjs} +4 -29
  22. package/dist/chunk-APZ6JFN6.cjs.map +1 -0
  23. package/dist/chunk-BURYHHBM.js +114 -0
  24. package/dist/chunk-BURYHHBM.js.map +1 -0
  25. package/dist/{chunk-H63O5HPW.cjs → chunk-CQNKZ435.cjs} +8 -7
  26. package/dist/chunk-CQNKZ435.cjs.map +1 -0
  27. package/dist/chunk-EANGKAKG.cjs +32 -0
  28. package/dist/chunk-EANGKAKG.cjs.map +1 -0
  29. package/dist/{chunk-YTGRXD23.js → chunk-FEOFX4QW.js} +4 -25
  30. package/dist/chunk-FEOFX4QW.js.map +1 -0
  31. package/dist/{chunk-QJW3K6JN.js → chunk-G7AGM2Y7.js} +4 -3
  32. package/dist/chunk-G7AGM2Y7.js.map +1 -0
  33. package/dist/{chunk-HZMILQYO.js → chunk-GM4PXDZ2.js} +5 -4
  34. package/dist/chunk-GM4PXDZ2.js.map +1 -0
  35. package/dist/{chunk-QHK6PTUR.js → chunk-IKV2I7KT.js} +5 -4
  36. package/dist/chunk-IKV2I7KT.js.map +1 -0
  37. package/dist/{chunk-TI23GIFM.cjs → chunk-JH77MAON.cjs} +12 -11
  38. package/dist/chunk-JH77MAON.cjs.map +1 -0
  39. package/dist/{chunk-6DTW5T3Z.js → chunk-JSRKES2Z.js} +5 -4
  40. package/dist/chunk-JSRKES2Z.js.map +1 -0
  41. package/dist/chunk-JVWLXVYG.cjs +27 -0
  42. package/dist/chunk-JVWLXVYG.cjs.map +1 -0
  43. package/dist/{chunk-UQIRDE52.cjs → chunk-LX2X4KC7.cjs} +6 -5
  44. package/dist/chunk-LX2X4KC7.cjs.map +1 -0
  45. package/dist/{chunk-KWKB74KL.js → chunk-MKWBLNTD.js} +198 -44
  46. package/dist/chunk-MKWBLNTD.js.map +1 -0
  47. package/dist/chunk-NWGQ7JML.cjs +117 -0
  48. package/dist/chunk-NWGQ7JML.cjs.map +1 -0
  49. package/dist/{chunk-6RRFH7C4.cjs → chunk-NZM3M5IR.cjs} +39 -54
  50. package/dist/chunk-NZM3M5IR.cjs.map +1 -0
  51. package/dist/chunk-PPFVTXGJ.js +27 -0
  52. package/dist/chunk-PPFVTXGJ.js.map +1 -0
  53. package/dist/{chunk-3TJSFPO4.cjs → chunk-PROKRNL2.cjs} +26 -19
  54. package/dist/chunk-PROKRNL2.cjs.map +1 -0
  55. package/dist/chunk-TEAVPUMX.js +22 -0
  56. package/dist/chunk-TEAVPUMX.js.map +1 -0
  57. package/dist/{chunk-ALH6TUX2.js → chunk-THHFIP4N.js} +5 -4
  58. package/dist/chunk-THHFIP4N.js.map +1 -0
  59. package/dist/chunk-TL3GVPBO.cjs +234 -0
  60. package/dist/chunk-TL3GVPBO.cjs.map +1 -0
  61. package/dist/{chunk-XEGBGKHV.cjs → chunk-TXMP5AOW.cjs} +206 -52
  62. package/dist/chunk-TXMP5AOW.cjs.map +1 -0
  63. package/dist/{chunk-KP57YCYQ.js → chunk-UXV3V5NH.js} +23 -35
  64. package/dist/chunk-UXV3V5NH.js.map +1 -0
  65. package/dist/{chunk-H3IRVX7J.js → chunk-WSPVQR4O.js} +9 -9
  66. package/dist/chunk-WSPVQR4O.js.map +1 -0
  67. package/dist/{chunk-JKMBFHER.cjs → chunk-X4YU6BX7.cjs} +12 -11
  68. package/dist/chunk-X4YU6BX7.cjs.map +1 -0
  69. package/dist/chunk-YGJE7RSW.js +231 -0
  70. package/dist/chunk-YGJE7RSW.js.map +1 -0
  71. package/dist/components/ActivityPreview.cjs +14 -11
  72. package/dist/components/ActivityPreview.d.cts +7 -3
  73. package/dist/components/ActivityPreview.d.ts +7 -3
  74. package/dist/components/ActivityPreview.js +13 -10
  75. package/dist/components/ActivitySequence.cjs +14 -11
  76. package/dist/components/ActivitySequence.d.cts +75 -11
  77. package/dist/components/ActivitySequence.d.ts +75 -11
  78. package/dist/components/ActivitySequence.js +13 -10
  79. package/dist/components/Dictation.cjs +7 -4
  80. package/dist/components/Dictation.d.cts +1 -1
  81. package/dist/components/Dictation.d.ts +1 -1
  82. package/dist/components/Dictation.js +6 -3
  83. package/dist/components/FillInTheBlanks.cjs +7 -4
  84. package/dist/components/FillInTheBlanks.d.cts +1 -1
  85. package/dist/components/FillInTheBlanks.d.ts +1 -1
  86. package/dist/components/FillInTheBlanks.js +6 -3
  87. package/dist/components/GapSelect.cjs +7 -4
  88. package/dist/components/GapSelect.d.cts +1 -1
  89. package/dist/components/GapSelect.d.ts +1 -1
  90. package/dist/components/GapSelect.js +6 -3
  91. package/dist/components/InteractiveVideo.cjs +14 -11
  92. package/dist/components/InteractiveVideo.d.cts +2 -2
  93. package/dist/components/InteractiveVideo.d.ts +2 -2
  94. package/dist/components/InteractiveVideo.js +12 -9
  95. package/dist/components/MultipleChoice.cjs +7 -4
  96. package/dist/components/MultipleChoice.d.cts +1 -1
  97. package/dist/components/MultipleChoice.d.ts +1 -1
  98. package/dist/components/MultipleChoice.js +6 -3
  99. package/dist/components/PronunciationFeedback.cjs +4 -3
  100. package/dist/components/PronunciationFeedback.d.cts +1 -1
  101. package/dist/components/PronunciationFeedback.d.ts +1 -1
  102. package/dist/components/PronunciationFeedback.js +3 -2
  103. package/dist/components/ReadAloud.cjs +6 -4
  104. package/dist/components/ReadAloud.d.cts +2 -2
  105. package/dist/components/ReadAloud.d.ts +2 -2
  106. package/dist/components/ReadAloud.js +5 -3
  107. package/dist/components/StimulusPanel.d.cts +1 -1
  108. package/dist/components/StimulusPanel.d.ts +1 -1
  109. package/dist/components/WrittenResponse.cjs +4 -3
  110. package/dist/components/WrittenResponse.d.cts +3 -3
  111. package/dist/components/WrittenResponse.d.ts +3 -3
  112. package/dist/components/WrittenResponse.js +3 -2
  113. package/dist/i18n/LkIntlProvider.d.cts +2 -2
  114. package/dist/i18n/LkIntlProvider.d.ts +2 -2
  115. package/dist/index.cjs +34 -23
  116. package/dist/index.cjs.map +1 -1
  117. package/dist/index.d.cts +4 -3
  118. package/dist/index.d.ts +4 -3
  119. package/dist/index.js +15 -12
  120. package/dist/index.js.map +1 -1
  121. package/dist/{strings-PCYKWCwd.d.ts → types-BY-4S5Rd.d.ts} +761 -761
  122. package/dist/{strings-BOPKhnS-.d.cts → types-DtPYG1hh.d.cts} +761 -761
  123. package/package.json +11 -1
  124. package/dist/chunk-3TJSFPO4.cjs.map +0 -1
  125. package/dist/chunk-5F4Q6JT7.cjs +0 -289
  126. package/dist/chunk-5F4Q6JT7.cjs.map +0 -1
  127. package/dist/chunk-6DTW5T3Z.js.map +0 -1
  128. package/dist/chunk-6RRFH7C4.cjs.map +0 -1
  129. package/dist/chunk-ALH6TUX2.js.map +0 -1
  130. package/dist/chunk-BAKLJKFZ.cjs.map +0 -1
  131. package/dist/chunk-GR33G5QM.js +0 -286
  132. package/dist/chunk-GR33G5QM.js.map +0 -1
  133. package/dist/chunk-H3IRVX7J.js.map +0 -1
  134. package/dist/chunk-H63O5HPW.cjs.map +0 -1
  135. package/dist/chunk-HZMILQYO.js.map +0 -1
  136. package/dist/chunk-JKMBFHER.cjs.map +0 -1
  137. package/dist/chunk-KP57YCYQ.js.map +0 -1
  138. package/dist/chunk-KWKB74KL.js.map +0 -1
  139. package/dist/chunk-QA42VDTA.cjs.map +0 -1
  140. package/dist/chunk-QHK6PTUR.js.map +0 -1
  141. package/dist/chunk-QJW3K6JN.js.map +0 -1
  142. package/dist/chunk-RZ52SEYV.cjs.map +0 -1
  143. package/dist/chunk-TI23GIFM.cjs.map +0 -1
  144. package/dist/chunk-UQIRDE52.cjs.map +0 -1
  145. package/dist/chunk-UYQBEPNZ.js.map +0 -1
  146. package/dist/chunk-V5BTVGPA.js.map +0 -1
  147. package/dist/chunk-XEGBGKHV.cjs.map +0 -1
  148. package/dist/chunk-YTGRXD23.js.map +0 -1
  149. package/dist/chunk-Z5XY66PO.cjs.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,49 @@
1
1
  # @intellectif/lk-react
2
2
 
3
+ ## 18.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 50c3285: A question a host draws inside `<ActivitySequence>` gets everything one the SDK draws has, and the AI
8
+ rules are available without the SDK's buttons.
9
+
10
+ - **`renderers` overrides get a `question` prop** (`SequenceQuestion`), the pager's half of the
11
+ contract, as `renderQuestion` gave one to `<InteractiveVideo>` in 16.1.0:
12
+ - `active` — whether this is the question on screen. **Stop the microphone, any timer and any
13
+ speech when it turns `false`:** the pager pauses the media inside the question and stops the
14
+ recorders the SDK started, but cannot reach one it did not create;
15
+ - `setPending(true/false)` — work of your own is on its way (an upload, a save, a judgement).
16
+ `onFinished` and `onComplete` wait for it, so a set is never reported a moment before the last
17
+ answer settles. Call it with `false` however the work ends, a failure included;
18
+ - `portalContainer` — a node inside this question's own pane. Portal a popover into it rather than
19
+ into `document.body`, and it is hidden when the learner pages away and painted with the question
20
+ in fullscreen;
21
+ - `clear()` — the learner withdrew their answer: the slot holds nothing again, and the set is
22
+ unfinished until it is answered again;
23
+ - `emit(type, payload?)` — an interaction, with this question's `activityId` and the time filled
24
+ in;
25
+ - `slot` — the identity to store the answer against, the same object `onSubmit` is handed.
26
+ - **Every call keeps one identity for the life of the set**, `onSubmit` and `onComplete` included, so
27
+ a renderer may hold them in an effect and a host that re-renders on every keystroke does not re-run
28
+ it.
29
+ - **New: `useAiHints` and `useAiExplanation`** (`@intellectif/lk-react/ai/useAiHelp`, also on the
30
+ root) — AI help for a question you draw yourself: the same rules, facts, checks and records the
31
+ bundled components use, with your own markup. `ask` does nothing where the rules say no, so a page
32
+ drawing its own button reaches no model in an `exam`. The SDK's own components are built on these
33
+ hooks, so there is one implementation of the rules and not two.
34
+ - **The paper decides the mode.** A question inside `<ActivitySequence>` or `<InteractiveVideo>` now
35
+ knows the mode it is being delivered in, so the hooks refuse help on an `exam` paper even when the
36
+ host does not pass `renderMode` to them, or passes `practice` — which a component that defaults it
37
+ can do inside an exam. Without that, a host's own question under an `LkAiProvider` could reach a
38
+ model on a paper of record.
39
+
40
+ `ActivityRenderer` is now `ComponentType<ActivityProps & { question?: SequenceQuestion }>`. A
41
+ renderer written as `ComponentType<ActivityProps>` still fits and simply ignores the new prop; only
42
+ assigning an `ActivityRenderer` _back_ to a `ComponentType<ActivityProps>` variable needs a widened
43
+ annotation.
44
+
45
+ See `docs/ai.md` and the `renderers` documentation on `<ActivitySequence>`.
46
+
3
47
  ## 18.0.0
4
48
 
5
49
  ### Patch Changes
package/README.md CHANGED
@@ -82,7 +82,8 @@ export function Demo() {
82
82
  - **`shuffleSeed`** — one seed drives question order *and* each item's option order, so a review render reproduces exactly the arrangement the learner sat. Shuffling in `exam` / `review` mode **requires** it.
83
83
  - **`<StimulusPanel>`** — a shared passage / recording / image (an item group's stimulus) as a landmark region; the sequence uses it, and a custom runner can too.
84
84
  - **`<ActivityPreview>`** — an editor's preview. Renders a draft in any `renderMode` with a simulated `response` (marked with `evaluate()` in `review`), and a translatable notice — or your `fallback`, handed the issues — while `validateDraft` says the draft is not finished. Nothing it renders is recorded, and a recording's play limit is counted in memory only.
85
- - **Custom activity types** — `renderers={{ 'my-type': MyRenderer }}` on the sequence; a key matching a built-in overrides it, so you can replace a bundled renderer without forking the sequencer.
85
+ - **Custom activity types** — `renderers={{ 'my-type': MyRenderer }}` on the sequence; a key matching a built-in overrides it, so you can replace a bundled renderer without forking the sequencer. A renderer is given the same contract the SDK's own components have: a `question` prop that says when it is the question on screen (so it can stop its microphone), holds the set while its own work is in flight, gives it somewhere to portal a popover, and reports what the learner did through calls that keep one identity.
86
+ - **AI help in a question you draw** — `useAiHints` and `useAiExplanation` give a host's own renderer the rules, the facts and the refusals the bundled components use, without their buttons. `ask` does nothing where the rules say no, so an exam reaches no model however the page asks.
86
87
  - **Rich text, opt-in** — `sanitizeHtml` renders author-supplied `questionHtml` / `promptHtml`. The SDK ships **no** sanitiser and injects no HTML without one; without it the escaped plain-text field is used. (`FillInTheBlanks` ignores `passageHtml` by design — its passage hosts the answer inputs.)
87
88
  - **Media per question** — optional `image` / `audio` / `video` / `embed` (YouTube/Vimeo iframe) above the question; alt-text required for `image`/`embed` (WCAG).
88
89
  - **Playback policy for listening papers** — an audio recording can declare `maxPlays`, `seek: 'none'` and `rate: 'fixed'`. The SDK then renders its own accessible transport (44px targets, a live plays-remaining status, an exhausted button that stays focusable and says why) and enforces the policy from the element's own events, so a hardware media key goes through the budget too. Wire `mediaBudget` on `<ActivitySequence>` to make a play budget survive a refresh.
@@ -116,6 +117,7 @@ export function Demo() {
116
117
  | `@intellectif/lk-react/hooks/useSpeechRecorder` | Microphone capture to 16 kHz mono WAV, and `CAPTURE_PROCESSOR_SOURCE` for a self-hosted worklet |
117
118
  | `@intellectif/lk-react/hooks/useXAPI` | LRS delivery (retry, never-throws) |
118
119
  | `@intellectif/lk-react/ai/LkAiProvider` | `<LkAiProvider>`, `useLearnerAi`, and the `LearnerAi` type |
120
+ | `@intellectif/lk-react/ai/useAiHelp` | `useAiHints`, `useAiExplanation` — the AI rules without the SDK's own buttons |
119
121
  | `@intellectif/lk-react/i18n/LkIntlProvider` | `<LkIntlProvider>`, `useLkStrings`, `useLkDirection`, `DEFAULT_STRINGS`, `mergeStrings`, `directionForLocale` |
120
122
  | `@intellectif/lk-react/theme/ThemeProvider` | `<ThemeProvider>`, `darkTheme`, `useTheme`, `createTailwindTheme` |
121
123
  | `@intellectif/lk-react/theme/defaults.css` | Tokens (required) |
@@ -1,5 +1,5 @@
1
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 './strings-PCYKWCwd.js';
2
+ import { f as Renderable, e as RenderMode, H as HtmlSanitizer, M as MediaBudgetBinding, b as MediaTransportStrings, a as LkStringsOverride } from './types-BY-4S5Rd.js';
3
3
 
4
4
  /**
5
5
  * Payload delivered when the learner submits a written response. Grading is
@@ -1,5 +1,5 @@
1
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 './strings-BOPKhnS-.cjs';
2
+ import { f as Renderable, e as RenderMode, H as HtmlSanitizer, M as MediaBudgetBinding, b as MediaTransportStrings, a as LkStringsOverride } from './types-DtPYG1hh.cjs';
3
3
 
4
4
  /**
5
5
  * Payload delivered when the learner submits a written response. Grading is
@@ -0,0 +1,20 @@
1
+ 'use client';
2
+ 'use strict';
3
+
4
+ var chunkTL3GVPBO_cjs = require('../chunk-TL3GVPBO.cjs');
5
+ require('../chunk-ZDYNAWDZ.cjs');
6
+ require('../chunk-JVWLXVYG.cjs');
7
+ require('../chunk-EANGKAKG.cjs');
8
+
9
+
10
+
11
+ Object.defineProperty(exports, "useAiExplanation", {
12
+ enumerable: true,
13
+ get: function () { return chunkTL3GVPBO_cjs.useAiExplanation; }
14
+ });
15
+ Object.defineProperty(exports, "useAiHints", {
16
+ enumerable: true,
17
+ get: function () { return chunkTL3GVPBO_cjs.useAiHints; }
18
+ });
19
+ //# sourceMappingURL=useAiHelp.cjs.map
20
+ //# sourceMappingURL=useAiHelp.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"useAiHelp.cjs"}
@@ -0,0 +1,146 @@
1
+ import { AiTextResult, LearnerResponse, InteractionEvent, ItemOutcome } from '@intellectif/lk-core';
2
+ import { g as RenderableActivity, e as RenderMode } from '../types-DtPYG1hh.cjs';
3
+ import { LearnerAi } from './LkAiProvider.cjs';
4
+ import '../machine-CuwKqWXC.cjs';
5
+ import 'react';
6
+
7
+ /**
8
+ * The question AI help is being asked about, as the SDK's own components know
9
+ * it. A host drawing its own question passes what it has; everything optional
10
+ * defaults to what the components pass.
11
+ */
12
+ interface AiHelpSituation {
13
+ /** The question, as `data` is given to any activity component. */
14
+ data: RenderableActivity;
15
+ /** The learner's answer as it stands: submitted, restored, or being written. */
16
+ response: LearnerResponse;
17
+ /** Whether the learner has committed that answer. */
18
+ submitted: boolean;
19
+ /**
20
+ * Pass on the `renderMode` your question was given. Left out, the paper
21
+ * around the question answers for it — a question inside `<ActivitySequence>`
22
+ * or `<InteractiveVideo>` knows its mode — and `practice` only where there is
23
+ * no paper at all. An `exam` around the question wins over anything passed
24
+ * here.
25
+ */
26
+ renderMode?: RenderMode;
27
+ /**
28
+ * The AI ports to use, overriding {@link LkAiProvider}'s for this question.
29
+ * A question inside `<ActivitySequence>` or `<InteractiveVideo>` is handed
30
+ * the ports in force as `ai` — pass that straight in.
31
+ */
32
+ ai?: LearnerAi;
33
+ /** The interface language: the default language for what a model writes. */
34
+ locale?: string;
35
+ /** Where `ai-hint-shown` and `ai-explanation-shown` go. */
36
+ onInteraction?: (event: InteractionEvent) => void;
37
+ }
38
+ interface AiExplanationInput extends AiHelpSituation {
39
+ /** The grade of record, which `review` explains. */
40
+ outcome?: ItemOutcome;
41
+ }
42
+ interface AiExplanationHelp {
43
+ /**
44
+ * Whether to offer the learner an explanation at all: a port is present, the
45
+ * answer is graded, the type is one the SDK explains, and the author left
46
+ * explanations on. False in `exam`, always.
47
+ */
48
+ offered: boolean;
49
+ status: 'idle' | 'loading' | 'shown' | 'unavailable';
50
+ /** What to show, once it has arrived and been checked. Its `text` is text, never HTML. */
51
+ explanation: AiTextResult | null;
52
+ /**
53
+ * Asks the port, when the learner presses something. Does nothing while a
54
+ * call is on its way, and nothing at all where `offered` is false — so an
55
+ * exam cannot reach a model through this hook, whatever ports are in scope.
56
+ *
57
+ * One identity for the life of the question, so it is safe in an effect's
58
+ * dependencies.
59
+ */
60
+ ask: () => void;
61
+ }
62
+ interface AiHintsInput extends AiHelpSituation {
63
+ /** A disabled question gives no hints, as it takes no answer. */
64
+ disabled?: boolean;
65
+ }
66
+ interface AiHintsHelp {
67
+ /**
68
+ * Whether the learner may ask for hints here at all: a port is present, the
69
+ * mode is `practice`, the answer is not in, the question is not disabled or
70
+ * redacted, the type takes hints and the author left them on. It stays true
71
+ * once `used` reaches `limit` — there are no more to give, but the question
72
+ * is still one that gives them.
73
+ */
74
+ offered: boolean;
75
+ status: 'idle' | 'loading' | 'unavailable';
76
+ /** Every hint shown for this question, in the order they were given. */
77
+ hints: readonly AiTextResult[];
78
+ /** The host's `maxHints`, as a whole number from 1 to 10 (3 by default). */
79
+ limit: number;
80
+ /** How many hints have been shown. A refused hint is not counted. */
81
+ used: number;
82
+ /**
83
+ * Asks for the next hint. Does nothing at the limit, while a call is on its
84
+ * way, or where `offered` is false. One identity for the life of the
85
+ * question.
86
+ */
87
+ ask: () => void;
88
+ }
89
+ /**
90
+ * "Explain my answer", without the SDK's own button and panel: the rules, the
91
+ * call, the checks and the record, for a question you draw yourself.
92
+ *
93
+ * It is what `<MultipleChoice>` and the others use, so a host's own question
94
+ * offers help on exactly the same terms: never in `exam`, never where the
95
+ * item's author switched explanations off, and never an explanation whose
96
+ * verdict contradicts the grade the SDK computed.
97
+ *
98
+ * ```tsx
99
+ * const { offered, status, explanation, ask } = useAiExplanation({
100
+ * data, response, submitted, renderMode, outcome, ai: question.ai,
101
+ * });
102
+ * if (!offered) return null;
103
+ * return explanation === null ? (
104
+ * <button type="button" onClick={ask} aria-busy={status === 'loading'}>Explain my answer</button>
105
+ * ) : (
106
+ * <section>
107
+ * <p>{explanation.text}</p>
108
+ * <p>Written by AI. It can make mistakes.</p>
109
+ * </section>
110
+ * );
111
+ * ```
112
+ *
113
+ * **Say who wrote it.** The SDK's own panel carries "Written by AI. It can make
114
+ * mistakes."; a page that drops that line passes a model's words off as the
115
+ * course's.
116
+ *
117
+ * When the answer or its grade changes, the explanation is dropped and a call
118
+ * still on its way is abandoned — a late explanation never lands beside an
119
+ * answer it was not written for — as it is when the caller unmounts.
120
+ */
121
+ declare function useAiExplanation(input: AiExplanationInput): AiExplanationHelp;
122
+ /**
123
+ * "Get a hint", without the SDK's own button and list: the rules, the call, the
124
+ * checks and the record, for a question you draw yourself.
125
+ *
126
+ * It is what `<MultipleChoice>` and the others use, so a host's own question
127
+ * gives hints on exactly the same terms: only in `practice` before submit, up
128
+ * to the host's limit, never on a redacted item or a type the SDK does not hint
129
+ * for, and never a hint that gives the answer away — which is refused rather
130
+ * than shown, and not counted.
131
+ *
132
+ * ```tsx
133
+ * const { offered, status, hints, used, limit, ask } = useAiHints({
134
+ * data, response, submitted, renderMode, ai: question.ai,
135
+ * });
136
+ * ```
137
+ *
138
+ * **Say who wrote them**, as the SDK's own list does: "Written by AI. It can
139
+ * make mistakes."
140
+ *
141
+ * Keep the hints on screen after submit — the learner can see what they were
142
+ * given — while `offered` turns false. Another question starts with none.
143
+ */
144
+ declare function useAiHints(input: AiHintsInput): AiHintsHelp;
145
+
146
+ export { type AiExplanationHelp, type AiExplanationInput, type AiHelpSituation, type AiHintsHelp, type AiHintsInput, useAiExplanation, useAiHints };
@@ -0,0 +1,146 @@
1
+ import { AiTextResult, LearnerResponse, InteractionEvent, ItemOutcome } from '@intellectif/lk-core';
2
+ import { g as RenderableActivity, e as RenderMode } from '../types-BY-4S5Rd.js';
3
+ import { LearnerAi } from './LkAiProvider.js';
4
+ import '../machine-CuwKqWXC.js';
5
+ import 'react';
6
+
7
+ /**
8
+ * The question AI help is being asked about, as the SDK's own components know
9
+ * it. A host drawing its own question passes what it has; everything optional
10
+ * defaults to what the components pass.
11
+ */
12
+ interface AiHelpSituation {
13
+ /** The question, as `data` is given to any activity component. */
14
+ data: RenderableActivity;
15
+ /** The learner's answer as it stands: submitted, restored, or being written. */
16
+ response: LearnerResponse;
17
+ /** Whether the learner has committed that answer. */
18
+ submitted: boolean;
19
+ /**
20
+ * Pass on the `renderMode` your question was given. Left out, the paper
21
+ * around the question answers for it — a question inside `<ActivitySequence>`
22
+ * or `<InteractiveVideo>` knows its mode — and `practice` only where there is
23
+ * no paper at all. An `exam` around the question wins over anything passed
24
+ * here.
25
+ */
26
+ renderMode?: RenderMode;
27
+ /**
28
+ * The AI ports to use, overriding {@link LkAiProvider}'s for this question.
29
+ * A question inside `<ActivitySequence>` or `<InteractiveVideo>` is handed
30
+ * the ports in force as `ai` — pass that straight in.
31
+ */
32
+ ai?: LearnerAi;
33
+ /** The interface language: the default language for what a model writes. */
34
+ locale?: string;
35
+ /** Where `ai-hint-shown` and `ai-explanation-shown` go. */
36
+ onInteraction?: (event: InteractionEvent) => void;
37
+ }
38
+ interface AiExplanationInput extends AiHelpSituation {
39
+ /** The grade of record, which `review` explains. */
40
+ outcome?: ItemOutcome;
41
+ }
42
+ interface AiExplanationHelp {
43
+ /**
44
+ * Whether to offer the learner an explanation at all: a port is present, the
45
+ * answer is graded, the type is one the SDK explains, and the author left
46
+ * explanations on. False in `exam`, always.
47
+ */
48
+ offered: boolean;
49
+ status: 'idle' | 'loading' | 'shown' | 'unavailable';
50
+ /** What to show, once it has arrived and been checked. Its `text` is text, never HTML. */
51
+ explanation: AiTextResult | null;
52
+ /**
53
+ * Asks the port, when the learner presses something. Does nothing while a
54
+ * call is on its way, and nothing at all where `offered` is false — so an
55
+ * exam cannot reach a model through this hook, whatever ports are in scope.
56
+ *
57
+ * One identity for the life of the question, so it is safe in an effect's
58
+ * dependencies.
59
+ */
60
+ ask: () => void;
61
+ }
62
+ interface AiHintsInput extends AiHelpSituation {
63
+ /** A disabled question gives no hints, as it takes no answer. */
64
+ disabled?: boolean;
65
+ }
66
+ interface AiHintsHelp {
67
+ /**
68
+ * Whether the learner may ask for hints here at all: a port is present, the
69
+ * mode is `practice`, the answer is not in, the question is not disabled or
70
+ * redacted, the type takes hints and the author left them on. It stays true
71
+ * once `used` reaches `limit` — there are no more to give, but the question
72
+ * is still one that gives them.
73
+ */
74
+ offered: boolean;
75
+ status: 'idle' | 'loading' | 'unavailable';
76
+ /** Every hint shown for this question, in the order they were given. */
77
+ hints: readonly AiTextResult[];
78
+ /** The host's `maxHints`, as a whole number from 1 to 10 (3 by default). */
79
+ limit: number;
80
+ /** How many hints have been shown. A refused hint is not counted. */
81
+ used: number;
82
+ /**
83
+ * Asks for the next hint. Does nothing at the limit, while a call is on its
84
+ * way, or where `offered` is false. One identity for the life of the
85
+ * question.
86
+ */
87
+ ask: () => void;
88
+ }
89
+ /**
90
+ * "Explain my answer", without the SDK's own button and panel: the rules, the
91
+ * call, the checks and the record, for a question you draw yourself.
92
+ *
93
+ * It is what `<MultipleChoice>` and the others use, so a host's own question
94
+ * offers help on exactly the same terms: never in `exam`, never where the
95
+ * item's author switched explanations off, and never an explanation whose
96
+ * verdict contradicts the grade the SDK computed.
97
+ *
98
+ * ```tsx
99
+ * const { offered, status, explanation, ask } = useAiExplanation({
100
+ * data, response, submitted, renderMode, outcome, ai: question.ai,
101
+ * });
102
+ * if (!offered) return null;
103
+ * return explanation === null ? (
104
+ * <button type="button" onClick={ask} aria-busy={status === 'loading'}>Explain my answer</button>
105
+ * ) : (
106
+ * <section>
107
+ * <p>{explanation.text}</p>
108
+ * <p>Written by AI. It can make mistakes.</p>
109
+ * </section>
110
+ * );
111
+ * ```
112
+ *
113
+ * **Say who wrote it.** The SDK's own panel carries "Written by AI. It can make
114
+ * mistakes."; a page that drops that line passes a model's words off as the
115
+ * course's.
116
+ *
117
+ * When the answer or its grade changes, the explanation is dropped and a call
118
+ * still on its way is abandoned — a late explanation never lands beside an
119
+ * answer it was not written for — as it is when the caller unmounts.
120
+ */
121
+ declare function useAiExplanation(input: AiExplanationInput): AiExplanationHelp;
122
+ /**
123
+ * "Get a hint", without the SDK's own button and list: the rules, the call, the
124
+ * checks and the record, for a question you draw yourself.
125
+ *
126
+ * It is what `<MultipleChoice>` and the others use, so a host's own question
127
+ * gives hints on exactly the same terms: only in `practice` before submit, up
128
+ * to the host's limit, never on a redacted item or a type the SDK does not hint
129
+ * for, and never a hint that gives the answer away — which is refused rather
130
+ * than shown, and not counted.
131
+ *
132
+ * ```tsx
133
+ * const { offered, status, hints, used, limit, ask } = useAiHints({
134
+ * data, response, submitted, renderMode, ai: question.ai,
135
+ * });
136
+ * ```
137
+ *
138
+ * **Say who wrote them**, as the SDK's own list does: "Written by AI. It can
139
+ * make mistakes."
140
+ *
141
+ * Keep the hints on screen after submit — the learner can see what they were
142
+ * given — while `offered` turns false. Another question starts with none.
143
+ */
144
+ declare function useAiHints(input: AiHintsInput): AiHintsHelp;
145
+
146
+ export { type AiExplanationHelp, type AiExplanationInput, type AiHelpSituation, type AiHintsHelp, type AiHintsInput, useAiExplanation, useAiHints };
@@ -0,0 +1,7 @@
1
+ 'use client';
2
+ export { useAiExplanation, useAiHints } from '../chunk-YGJE7RSW.js';
3
+ import '../chunk-YNDKAYW3.js';
4
+ import '../chunk-TEAVPUMX.js';
5
+ import '../chunk-PPFVTXGJ.js';
6
+ //# sourceMappingURL=useAiHelp.js.map
7
+ //# sourceMappingURL=useAiHelp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"useAiHelp.js"}
@@ -1,13 +1,13 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
- var chunkH63O5HPW_cjs = require('./chunk-H63O5HPW.cjs');
5
- var chunkJKMBFHER_cjs = require('./chunk-JKMBFHER.cjs');
6
- var chunkTI23GIFM_cjs = require('./chunk-TI23GIFM.cjs');
7
- var chunkQA42VDTA_cjs = require('./chunk-QA42VDTA.cjs');
8
- var chunkRZ52SEYV_cjs = require('./chunk-RZ52SEYV.cjs');
9
- var chunk6RRFH7C4_cjs = require('./chunk-6RRFH7C4.cjs');
10
- var chunkBAKLJKFZ_cjs = require('./chunk-BAKLJKFZ.cjs');
4
+ var chunkCQNKZ435_cjs = require('./chunk-CQNKZ435.cjs');
5
+ var chunkX4YU6BX7_cjs = require('./chunk-X4YU6BX7.cjs');
6
+ var chunkJH77MAON_cjs = require('./chunk-JH77MAON.cjs');
7
+ var chunk3SJ7TVL6_cjs = require('./chunk-3SJ7TVL6.cjs');
8
+ var chunk7GYAUA56_cjs = require('./chunk-7GYAUA56.cjs');
9
+ var chunkNZM3M5IR_cjs = require('./chunk-NZM3M5IR.cjs');
10
+ var chunkAPZ6JFN6_cjs = require('./chunk-APZ6JFN6.cjs');
11
11
  var chunkAHGB5HH6_cjs = require('./chunk-AHGB5HH6.cjs');
12
12
  var lkCore = require('@intellectif/lk-core');
13
13
  var react = require('react');
@@ -106,7 +106,7 @@ function ActivityPreview({
106
106
  const data = result.data;
107
107
  const key = `${renderMode}:${responseKey}:${recordingKeyOf(data)}`;
108
108
  if (marking?.kind === "failed") {
109
- return /* @__PURE__ */ jsxRuntime.jsx(chunkBAKLJKFZ_cjs.ActivityErrorBoundary, { activityTitle: data.title, strings: s, children: /* @__PURE__ */ jsxRuntime.jsx(Rethrow, { error: marking.error }) }, key);
109
+ return /* @__PURE__ */ jsxRuntime.jsx(chunkAPZ6JFN6_cjs.ActivityErrorBoundary, { activityTitle: data.title, strings: s, children: /* @__PURE__ */ jsxRuntime.jsx(Rethrow, { error: marking.error }) }, key);
110
110
  }
111
111
  const shared = {
112
112
  renderMode,
@@ -133,7 +133,7 @@ function ActivityPreview({
133
133
  switch (data.type) {
134
134
  case "multiple-choice":
135
135
  return /* @__PURE__ */ jsxRuntime.jsx(
136
- chunkJKMBFHER_cjs.MultipleChoice,
136
+ chunkX4YU6BX7_cjs.MultipleChoice,
137
137
  {
138
138
  data,
139
139
  shuffleSeed: shuffleSeed ?? PREVIEW_SHUFFLE_SEED,
@@ -142,10 +142,10 @@ function ActivityPreview({
142
142
  key
143
143
  );
144
144
  case "fill-in-the-blanks":
145
- return /* @__PURE__ */ jsxRuntime.jsx(chunkTI23GIFM_cjs.FillInTheBlanks, { data, ...shared }, key);
145
+ return /* @__PURE__ */ jsxRuntime.jsx(chunkJH77MAON_cjs.FillInTheBlanks, { data, ...shared }, key);
146
146
  case "gap-select":
147
147
  return /* @__PURE__ */ jsxRuntime.jsx(
148
- chunkQA42VDTA_cjs.GapSelect,
148
+ chunk3SJ7TVL6_cjs.GapSelect,
149
149
  {
150
150
  data,
151
151
  shuffleSeed: shuffleSeed ?? PREVIEW_SHUFFLE_SEED,
@@ -154,11 +154,11 @@ function ActivityPreview({
154
154
  key
155
155
  );
156
156
  case "written-response":
157
- return /* @__PURE__ */ jsxRuntime.jsx(chunkH63O5HPW_cjs.WrittenResponse, { data, ...shared }, key);
157
+ return /* @__PURE__ */ jsxRuntime.jsx(chunkCQNKZ435_cjs.WrittenResponse, { data, ...shared }, key);
158
158
  case "dictation":
159
- return /* @__PURE__ */ jsxRuntime.jsx(chunkRZ52SEYV_cjs.Dictation, { data, ...shared }, key);
159
+ return /* @__PURE__ */ jsxRuntime.jsx(chunk7GYAUA56_cjs.Dictation, { data, ...shared }, key);
160
160
  case "read-aloud":
161
- return /* @__PURE__ */ jsxRuntime.jsx(chunk6RRFH7C4_cjs.ReadAloud, { data, recordingBinding: PREVIEW_RECORDING, ...shared }, key);
161
+ return /* @__PURE__ */ jsxRuntime.jsx(chunkNZM3M5IR_cjs.ReadAloud, { data, recordingBinding: PREVIEW_RECORDING, ...shared }, key);
162
162
  default:
163
163
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "lk-preview-unsupported", role: "note", children: s.unsupportedActivity });
164
164
  }
@@ -232,5 +232,5 @@ function contentKeyOf(value, enclosing = /* @__PURE__ */ new Set()) {
232
232
  }
233
233
 
234
234
  exports.ActivityPreview = ActivityPreview;
235
- //# sourceMappingURL=chunk-Z5XY66PO.cjs.map
236
- //# sourceMappingURL=chunk-Z5XY66PO.cjs.map
235
+ //# sourceMappingURL=chunk-3SDCALS3.cjs.map
236
+ //# sourceMappingURL=chunk-3SDCALS3.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/ActivityPreview/ActivityPreview.tsx"],"names":["useLkStrings","useMemo","validateDraft","evaluate","slotMediaKey","jsx","Fragment","ActivityErrorBoundary","MultipleChoice","FillInTheBlanks","GapSelect","WrittenResponse","Dictation","ReadAloud"],"mappings":"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","file":"chunk-3SDCALS3.cjs","sourcesContent":["'use client';\n\nimport {\n type ActivityType,\n type DraftNotComplete,\n evaluate,\n type ItemOutcome,\n type LearnerResponse,\n slotMediaKey,\n type ThemeTokens,\n validateDraft,\n} from '@intellectif/lk-core';\nimport { type ReactNode, useMemo } from 'react';\nimport { useLkStrings } from '../../i18n/LkIntlProvider.js';\nimport type { LkStringsOverride } from '../../i18n/strings.js';\nimport { ActivityErrorBoundary } from '../ActivityErrorBoundary.js';\nimport type { ActivityRenderer } from '../ActivitySequence/index.js';\nimport { Dictation } from '../Dictation/index.js';\nimport { FillInTheBlanks } from '../FillInTheBlanks/index.js';\nimport { GapSelect } from '../GapSelect/index.js';\nimport { MultipleChoice } from '../MultipleChoice/index.js';\nimport { ReadAloud } from '../ReadAloud/index.js';\nimport type { RecordingBinding } from '../ReadAloud/ReadAloud.js';\nimport type { HtmlSanitizer, MediaBudgetBinding, RenderMode } from '../types.js';\nimport { WrittenResponse } from '../WrittenResponse/index.js';\n\n/**\n * The option-shuffle seed a preview uses when none is given. Fixed, so a\n * shuffled question holds still while its author edits it instead of\n * re-ordering on every remount.\n */\nconst PREVIEW_SHUFFLE_SEED = 'lk-activity-preview';\n\n/**\n * The slot a previewed activity stands in for. A recording's play budget is\n * keyed to it and lives only in this mount: the preview counts plays so an\n * author hears the limit a learner gets, and records none of them.\n */\nconst PREVIEW_SLOT_ID = 'preview';\n\n/** Numbers the takes a preview mints keys for, so two are never the same take. */\nlet previewTakeCount = 0;\n\n/**\n * The store a previewed read-aloud records into: it keys the take so the whole\n * flow — record, play it back, submit — runs for the author, and keeps it\n * nowhere, like every other thing a preview does not record.\n *\n * It judges nothing, deliberately. `assess` is optional precisely so this can\n * exist: an author trying a reading out has no assessor to point at, and a\n * preview that demanded one would refuse to render the most common case. The\n * default `practice` mode then shows the \"assessment is not available\" notice,\n * which is the truth about this binding rather than a failure.\n */\nconst PREVIEW_RECORDING: RecordingBinding = {\n upload: async (take) => {\n previewTakeCount += 1;\n return {\n key: `${PREVIEW_SLOT_ID}-take-${previewTakeCount}`,\n mimeType: take.mimeType,\n durationMs: take.durationMs,\n };\n },\n};\n\nexport interface ActivityPreviewProps {\n /**\n * The activity as an editor holds it right now, finished or not. It is checked\n * with `validateDraft` before anything renders — by content, on every render —\n * so a half-written question never reaches a component that assumes a valid\n * one.\n */\n draft: unknown;\n /** The mode to preview in. Defaults to `practice`. */\n renderMode?: RenderMode;\n /**\n * A learner response to show as if a learner had given it. In `practice` and\n * `exam` it seeds the answer, which stays editable; in `review` it is the\n * submitted answer, marked by `evaluate()` unless `outcome` is given.\n */\n response?: LearnerResponse;\n /**\n * The outcome `review` marks the response with, instead of the one\n * `evaluate()` computes — which is how to preview a returned grade on a written\n * response, since the SDK cannot score one. Ignored in other modes.\n */\n outcome?: ItemOutcome;\n /**\n * Rendered in place of the activity while the draft is not complete, with the\n * issues `validateDraft` found — so an editor can list them in its own words.\n * The issue messages are English, and a preview that rendered them would put\n * untranslatable text on screen. Without it, the preview shows the\n * `previewIncomplete` or `previewInvalid` string.\n */\n fallback?: (result: DraftNotComplete) => ReactNode;\n /**\n * Renderers for activity types beyond the built-ins, keyed by `type`, as on\n * `<ActivitySequence>`. An entry receives the shared prop contract and\n * nothing else, so — like the shuffle seed below — the in-memory recording\n * binding a previewed read-aloud is given does not reach one. Nor does the\n * `question` a sequence hands a renderer: a preview is one question with no\n * set around it, so there is no slot to report to and nothing to page away\n * from. A renderer that uses it must treat it as optional, which its type\n * already says.\n */\n renderers?: Readonly<Record<string, ActivityRenderer>>;\n /**\n * Seeds `<MultipleChoice>`'s option shuffle. Defaults to a fixed seed, so the\n * order holds while options are edited; adding or removing one deals them\n * again, because the shuffle orders by position. A `renderers` entry is given\n * no seed, as on `<ActivitySequence>`.\n */\n shuffleSeed?: string;\n /** Renders author-supplied rich text. See `HtmlSanitizer`. */\n sanitizeHtml?: HtmlSanitizer;\n /** Overrides the SDK's chrome text, for the preview's notice and the activity alike. */\n strings?: LkStringsOverride;\n /** Per-instance token overrides, passed to the activity. */\n theme?: Partial<ThemeTokens>;\n /** BCP 47 tag of the interface language, passed to the activity. */\n locale?: string;\n}\n\ntype Marking = { kind: 'marked'; outcome: ItemOutcome } | { kind: 'failed'; error: Error };\n\n/**\n * Renders an activity from an editor's draft, in any render mode, with a\n * simulated learner response — and renders a notice instead while the draft is\n * not an activity yet.\n *\n * Nothing it renders is recorded: no callback is wired, so a practice attempt in\n * a preview scores locally and goes nowhere, and a recording's play limit is\n * counted in memory only.\n *\n * A draft with no string `type`, a type nobody registered, and a `response` of a\n * different type from the draft are wiring errors, and throw.\n */\nexport function ActivityPreview({\n draft,\n renderMode = 'practice',\n response,\n outcome,\n fallback,\n renderers,\n shuffleSeed,\n sanitizeHtml,\n strings,\n theme,\n locale,\n}: ActivityPreviewProps) {\n const s = useLkStrings(strings);\n const type = isRecord(draft) && typeof draft.type === 'string' ? draft.type : undefined;\n\n // Validated on the draft's CONTENT, not its identity. The activity components\n // restart whenever `data` changes identity, and an editor that rebuilds its\n // payload on every change would otherwise restart the question an author is\n // trying out each time anything else on the page was edited. The key is read\n // on every render, so a draft changed in place is checked again too.\n const contentKey = contentKeyOf(draft);\n // biome-ignore lint/correctness/useExhaustiveDependencies: the draft's content (contentKey) is the trigger, not its identity\n const result = useMemo(\n () => (type === undefined ? undefined : validateDraft(type as ActivityType, draft)),\n [type, contentKey],\n );\n const activity = result?.status === 'complete' ? result.data : undefined;\n const responseFits = response === undefined || response.type === type;\n const responseKey = response === undefined ? 'none' : contentKeyOf(response);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: the response's content (responseKey) is the trigger, not its identity\n const marking = useMemo((): Marking | undefined => {\n if (renderMode !== 'review' || activity === undefined) {\n return undefined;\n }\n if (outcome !== undefined) {\n return { kind: 'marked', outcome };\n }\n if (response === undefined || !responseFits) {\n return undefined;\n }\n try {\n return { kind: 'marked', outcome: evaluate(activity, response) };\n } catch (thrown) {\n // Scored here, during this component's own render, where no error boundary\n // inside the activity can catch it — so it is handed to one below.\n return {\n kind: 'failed',\n error: thrown instanceof Error ? thrown : new Error(String(thrown)),\n };\n }\n }, [renderMode, activity, outcome, responseKey, responseFits]);\n\n const activityId = activity?.id;\n const mediaBudget = useMemo<MediaBudgetBinding>(\n () => ({\n key: slotMediaKey(PREVIEW_SLOT_ID),\n slotId: PREVIEW_SLOT_ID,\n index: 0,\n ...(activityId !== undefined ? { activityId } : {}),\n }),\n [activityId],\n );\n\n // All hooks are called before these throws, so hook order stays stable.\n if (type === undefined || result === undefined) {\n throw new Error(\n '<ActivityPreview> needs a draft object with a string `type`, to know which activity to check and render.',\n );\n }\n // Checked against the draft's own type, whatever state the draft is in. A\n // mis-wired response is a wiring error however unfinished the draft is, and\n // waiting for the draft to be complete would throw on the very edit that\n // completes it.\n if (response !== undefined && !responseFits) {\n throw new Error(\n `<ActivityPreview> was given a \"${response.type}\" response for a \"${type}\" activity.`,\n );\n }\n if (result.status !== 'complete') {\n if (fallback !== undefined) {\n return <>{fallback(result)}</>;\n }\n return (\n <div\n className=\"lk-preview-unavailable\"\n role=\"note\"\n data-status={result.status}\n {...(locale !== undefined ? { lang: locale } : {})}\n >\n {result.status === 'invalid' ? s.previewInvalid : s.previewIncomplete}\n </div>\n );\n }\n const data = result.data;\n\n // A different simulated response, or a different mode, mounts the activity\n // afresh, play count included: a seeded answer is read at mount, and a practice\n // attempt the author submitted must not carry over into an exam preview. So\n // does a different recording or playback policy, which is a different listening\n // budget — the transport reads its count once, when it mounts.\n const key = `${renderMode}:${responseKey}:${recordingKeyOf(data)}`;\n\n if (marking?.kind === 'failed') {\n // The response is one the scorer cannot read, or a registered scorer threw.\n // Shown as the activity's error fallback, as a render failure would be.\n return (\n <ActivityErrorBoundary key={key} activityTitle={data.title} strings={s}>\n <Rethrow error={marking.error} />\n </ActivityErrorBoundary>\n );\n }\n\n const shared = {\n renderMode,\n // Without a binding a budgeted recording counts nothing in `practice`, and in\n // `exam` the media component refuses to render at all — rightly, on a real\n // paper, where nothing would persist the count. A preview persists nothing by\n // design, so it keeps the count in memory and says so.\n mediaBudget,\n ...(sanitizeHtml !== undefined ? { sanitizeHtml } : {}),\n ...(strings !== undefined ? { strings } : {}),\n ...(theme !== undefined ? { theme } : {}),\n ...(locale !== undefined ? { locale } : {}),\n // Seeded rather than controlled, in every mode, exactly as `<ActivitySequence>`\n // hands a restored answer to its slots — so a renderer written for the\n // sequence reads it here too. `review` is read-only either way, and `key`\n // above re-seeds whenever the response changes.\n ...(response !== undefined ? { defaultValue: response } : {}),\n ...(marking !== undefined ? { outcome: marking.outcome } : {}),\n };\n\n const Custom = renderers?.[data.type];\n if (Custom !== undefined) {\n return <Custom key={key} data={data} {...shared} />;\n }\n switch (data.type) {\n case 'multiple-choice':\n return (\n <MultipleChoice\n key={key}\n data={data}\n shuffleSeed={shuffleSeed ?? PREVIEW_SHUFFLE_SEED}\n {...shared}\n />\n );\n case 'fill-in-the-blanks':\n return <FillInTheBlanks key={key} data={data} {...shared} />;\n case 'gap-select':\n return (\n <GapSelect\n key={key}\n data={data}\n shuffleSeed={shuffleSeed ?? PREVIEW_SHUFFLE_SEED}\n {...shared}\n />\n );\n case 'written-response':\n return <WrittenResponse key={key} data={data} {...shared} />;\n case 'dictation':\n return <Dictation key={key} data={data} {...shared} />;\n case 'read-aloud':\n return <ReadAloud key={key} data={data} recordingBinding={PREVIEW_RECORDING} {...shared} />;\n default:\n return (\n <div className=\"lk-preview-unsupported\" role=\"note\">\n {s.unsupportedActivity}\n </div>\n );\n }\n}\n\n/** Throws `error` while rendering, so the error boundary around it shows its fallback. */\nfunction Rethrow({ error }: { error: Error }): never {\n throw error;\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * The recording and its playback policy — not its description, which changes\n * no budget — plus the slower file a dictation or a read-aloud carries, which\n * follows the same policy and must remount when it is swapped for another.\n */\nfunction recordingKeyOf(data: unknown): string {\n const media = isRecord(data) ? data.media : undefined;\n const slowMedia = isRecord(data) ? data.slowMedia : undefined;\n const slowUrl = isRecord(slowMedia) ? slowMedia.url : undefined;\n if (!isRecord(media) && slowUrl === undefined) {\n return '';\n }\n return contentKeyOf([\n isRecord(media) ? media.type : undefined,\n isRecord(media) ? media.url : undefined,\n isRecord(media) ? media.playback : undefined,\n slowUrl,\n ]);\n}\n\nconst identities = new WeakMap<object, number>();\nlet lastIdentity = 0;\n\n/** A key for a value compared by identity: the same object always gets the same one. */\nfunction identityKeyOf(value: object): string {\n let identity = identities.get(value);\n if (identity === undefined) {\n lastIdentity += 1;\n identity = lastIdentity;\n identities.set(value, identity);\n }\n return `#${identity}`;\n}\n\n/**\n * A string that changes exactly when a value's content does.\n *\n * Object keys are sorted, because key order is not content: a draft saved to a\n * JSON column comes back with its keys reordered. Every value is written in a\n * form no other value shares — JSON would write a non-finite number as `null`\n * and drop `undefined`, and those decide different issues. What JSON does not\n * describe — an instance of a class, a function, a reference back to an\n * enclosing object — is compared by identity, and a symbol by its description.\n */\nfunction contentKeyOf(value: unknown, enclosing: Set<object> = new Set()): string {\n switch (typeof value) {\n case 'string':\n return JSON.stringify(value);\n case 'number':\n // `String` keeps NaN, the infinities and every other number apart; only -0\n // needs saying.\n return Object.is(value, -0) ? '-0' : String(value);\n case 'bigint':\n return `${value}n`;\n case 'boolean':\n case 'undefined':\n return String(value);\n case 'symbol':\n return `Symbol(${JSON.stringify(value.description ?? null)})`;\n case 'function':\n return identityKeyOf(value);\n }\n // Every other `typeof` has returned above: this is `null`, or an object.\n if (value === null || typeof value !== 'object') {\n return 'null';\n }\n const prototype = Object.getPrototypeOf(value);\n const plain = Array.isArray(value) || prototype === Object.prototype || prototype === null;\n if (!plain || enclosing.has(value)) {\n return identityKeyOf(value);\n }\n enclosing.add(value);\n try {\n if (Array.isArray(value)) {\n return `[${Array.from(value, (item) => contentKeyOf(item, enclosing)).join(',')}]`;\n }\n const record = value as Record<string, unknown>;\n const fields = Object.keys(record)\n .sort()\n .map((field) => `${JSON.stringify(field)}:${contentKeyOf(record[field], enclosing)}`);\n return `{${fields.join(',')}}`;\n } finally {\n enclosing.delete(value);\n }\n}\n"]}
@@ -1,10 +1,11 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
- var chunk5F4Q6JT7_cjs = require('./chunk-5F4Q6JT7.cjs');
4
+ var chunkNWGQ7JML_cjs = require('./chunk-NWGQ7JML.cjs');
5
5
  var chunkZDYNAWDZ_cjs = require('./chunk-ZDYNAWDZ.cjs');
6
6
  var chunkBRPEB43C_cjs = require('./chunk-BRPEB43C.cjs');
7
- var chunkBAKLJKFZ_cjs = require('./chunk-BAKLJKFZ.cjs');
7
+ var chunkAPZ6JFN6_cjs = require('./chunk-APZ6JFN6.cjs');
8
+ var chunkEANGKAKG_cjs = require('./chunk-EANGKAKG.cjs');
8
9
  var chunkL7WY5YFQ_cjs = require('./chunk-L7WY5YFQ.cjs');
9
10
  var chunkXOR4MPEN_cjs = require('./chunk-XOR4MPEN.cjs');
10
11
  var chunkAHGB5HH6_cjs = require('./chunk-AHGB5HH6.cjs');
@@ -78,7 +79,7 @@ function GapSelect({
78
79
  const s = chunkAHGB5HH6_cjs.useLkStrings(strings);
79
80
  const ai = chunkZDYNAWDZ_cjs.useLearnerAi(aiProp);
80
81
  const devError = react.useMemo(() => {
81
- if (!chunkBAKLJKFZ_cjs.isDevelopment()) {
82
+ if (!chunkEANGKAKG_cjs.isDevelopment()) {
82
83
  return null;
83
84
  }
84
85
  if (data.redacted === true) {
@@ -128,7 +129,7 @@ function GapSelect({
128
129
  const sessionIdRef = react.useRef(null);
129
130
  const choicesByGap = react.useMemo(() => {
130
131
  const map = /* @__PURE__ */ new Map();
131
- const seedSource = shuffleSeed ?? (sessionIdRef.current ??= chunkBAKLJKFZ_cjs.randomSessionId());
132
+ const seedSource = shuffleSeed ?? (sessionIdRef.current ??= chunkEANGKAKG_cjs.randomSessionId());
132
133
  for (const gap of data.gaps) {
133
134
  const choices = choicesFor(data.banks, gap);
134
135
  map.set(
@@ -183,9 +184,9 @@ function GapSelect({
183
184
  complete();
184
185
  const timeSpent = getTimeSpent();
185
186
  const xapiStatement = lkCore.xAPIBuilder.buildAnsweredStatement({
186
- actor: chunkBAKLJKFZ_cjs.ANONYMOUS_ACTOR,
187
+ actor: chunkEANGKAKG_cjs.ANONYMOUS_ACTOR,
187
188
  object: {
188
- id: chunkBAKLJKFZ_cjs.objectIdFor(data.id),
189
+ id: chunkEANGKAKG_cjs.objectIdFor(data.id),
189
190
  name: { [data.locale ?? "en-US"]: data.title },
190
191
  ...lkCore.xapiDefinitionFor(data)
191
192
  },
@@ -299,7 +300,7 @@ function GapSelect({
299
300
  ] }, seg.id);
300
301
  }) }),
301
302
  /* @__PURE__ */ jsxRuntime.jsx(
302
- chunk5F4Q6JT7_cjs.AiHints,
303
+ chunkNWGQ7JML_cjs.AiHints,
303
304
  {
304
305
  ai,
305
306
  data,
@@ -326,7 +327,7 @@ function GapSelect({
326
327
  ) : null,
327
328
  /* @__PURE__ */ jsxRuntime.jsx(chunkBRPEB43C_cjs.FeedbackRegion, { id: `${data.id}-feedback`, children: isReview ? reviewSummary : summary }),
328
329
  /* @__PURE__ */ jsxRuntime.jsx(
329
- chunk5F4Q6JT7_cjs.AiExplanation,
330
+ chunkNWGQ7JML_cjs.AiExplanation,
330
331
  {
331
332
  ai,
332
333
  data,
@@ -345,9 +346,9 @@ function GapSelect({
345
346
  }
346
347
  function GapSelect2(props) {
347
348
  const strings = chunkAHGB5HH6_cjs.useLkStrings(props.strings);
348
- return /* @__PURE__ */ jsxRuntime.jsx(chunkBAKLJKFZ_cjs.ActivityErrorBoundary, { activityTitle: props.data?.title, strings, children: /* @__PURE__ */ jsxRuntime.jsx(GapSelect, { ...props }) });
349
+ return /* @__PURE__ */ jsxRuntime.jsx(chunkAPZ6JFN6_cjs.ActivityErrorBoundary, { activityTitle: props.data?.title, strings, children: /* @__PURE__ */ jsxRuntime.jsx(GapSelect, { ...props }) });
349
350
  }
350
351
 
351
352
  exports.GapSelect = GapSelect2;
352
- //# sourceMappingURL=chunk-QA42VDTA.cjs.map
353
- //# sourceMappingURL=chunk-QA42VDTA.cjs.map
353
+ //# sourceMappingURL=chunk-3SJ7TVL6.cjs.map
354
+ //# sourceMappingURL=chunk-3SJ7TVL6.cjs.map