@intellectif/lk-react 15.0.0 → 16.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 (129) hide show
  1. package/CHANGELOG.md +95 -0
  2. package/README.md +3 -3
  3. package/dist/{WrittenResponse-BPbhERgk.d.cts → WrittenResponse-6tSj6U3G.d.cts} +1 -1
  4. package/dist/{WrittenResponse-ZAxLR_AU.d.ts → WrittenResponse-xJ7I_5yq.d.ts} +1 -1
  5. package/dist/{chunk-53YOZOGN.cjs → chunk-2S3MK4VX.cjs} +5 -5
  6. package/dist/{chunk-53YOZOGN.cjs.map → chunk-2S3MK4VX.cjs.map} +1 -1
  7. package/dist/{chunk-4H3JTX74.cjs → chunk-2TFNDHJ5.cjs} +13 -13
  8. package/dist/{chunk-4H3JTX74.cjs.map → chunk-2TFNDHJ5.cjs.map} +1 -1
  9. package/dist/{chunk-AF72QUBI.js → chunk-2XNCPLHU.js} +5 -5
  10. package/dist/{chunk-AF72QUBI.js.map → chunk-2XNCPLHU.js.map} +1 -1
  11. package/dist/{chunk-RT5FTHUU.js → chunk-3UXRX4KU.js} +5 -5
  12. package/dist/{chunk-RT5FTHUU.js.map → chunk-3UXRX4KU.js.map} +1 -1
  13. package/dist/{chunk-CE6OGJE6.js → chunk-5QHVYOME.js} +5 -5
  14. package/dist/{chunk-CE6OGJE6.js.map → chunk-5QHVYOME.js.map} +1 -1
  15. package/dist/{chunk-EKBEKDWO.cjs → chunk-B6S5ADHR.cjs} +13 -13
  16. package/dist/{chunk-EKBEKDWO.cjs.map → chunk-B6S5ADHR.cjs.map} +1 -1
  17. package/dist/{chunk-QM4AV6EG.js → chunk-BI547RIA.js} +4 -4
  18. package/dist/{chunk-QM4AV6EG.js.map → chunk-BI547RIA.js.map} +1 -1
  19. package/dist/{chunk-WKOV25NP.cjs → chunk-DFMBVA7D.cjs} +8 -8
  20. package/dist/{chunk-WKOV25NP.cjs.map → chunk-DFMBVA7D.cjs.map} +1 -1
  21. package/dist/{chunk-ZJMTHPHY.js → chunk-DKZWUIQD.js} +3 -3
  22. package/dist/{chunk-ZJMTHPHY.js.map → chunk-DKZWUIQD.js.map} +1 -1
  23. package/dist/{chunk-2HAEQDHQ.js → chunk-DVOPHC2Q.js} +755 -201
  24. package/dist/chunk-DVOPHC2Q.js.map +1 -0
  25. package/dist/{chunk-DQ3VVU5T.cjs → chunk-FZWWVJE4.cjs} +24 -24
  26. package/dist/{chunk-DQ3VVU5T.cjs.map → chunk-FZWWVJE4.cjs.map} +1 -1
  27. package/dist/{chunk-I2QGW4GD.js → chunk-GDMM2WEG.js} +11 -11
  28. package/dist/{chunk-I2QGW4GD.js.map → chunk-GDMM2WEG.js.map} +1 -1
  29. package/dist/{chunk-QEB6O6GU.js → chunk-GUPBIEUA.js} +6 -6
  30. package/dist/{chunk-QEB6O6GU.js.map → chunk-GUPBIEUA.js.map} +1 -1
  31. package/dist/{chunk-33BQNWAQ.js → chunk-IQI5I2X5.js} +5 -5
  32. package/dist/{chunk-33BQNWAQ.js.map → chunk-IQI5I2X5.js.map} +1 -1
  33. package/dist/{chunk-YWQH35VO.js → chunk-JPDR6TTA.js} +4 -4
  34. package/dist/{chunk-YWQH35VO.js.map → chunk-JPDR6TTA.js.map} +1 -1
  35. package/dist/{chunk-UCKA22ZJ.cjs → chunk-K63VPFOV.cjs} +9 -2
  36. package/dist/chunk-K63VPFOV.cjs.map +1 -0
  37. package/dist/{chunk-52GXJNQ3.js → chunk-KSAINXRG.js} +9 -2
  38. package/dist/chunk-KSAINXRG.js.map +1 -0
  39. package/dist/{chunk-ZH5WT2IE.cjs → chunk-ML6L4LJH.cjs} +25 -25
  40. package/dist/{chunk-ZH5WT2IE.cjs.map → chunk-ML6L4LJH.cjs.map} +1 -1
  41. package/dist/{chunk-Z6TVOAO5.cjs → chunk-MQAZJQRE.cjs} +9 -2
  42. package/dist/chunk-MQAZJQRE.cjs.map +1 -0
  43. package/dist/{chunk-UAYWLYFW.cjs → chunk-OO24JGYH.cjs} +18 -18
  44. package/dist/{chunk-UAYWLYFW.cjs.map → chunk-OO24JGYH.cjs.map} +1 -1
  45. package/dist/{chunk-26GQO5I2.cjs → chunk-PTJTC6A3.cjs} +12 -12
  46. package/dist/{chunk-26GQO5I2.cjs.map → chunk-PTJTC6A3.cjs.map} +1 -1
  47. package/dist/{chunk-DP3DM7FR.cjs → chunk-PXGJHZKJ.cjs} +6 -6
  48. package/dist/{chunk-DP3DM7FR.cjs.map → chunk-PXGJHZKJ.cjs.map} +1 -1
  49. package/dist/{chunk-XMJE34FY.cjs → chunk-RSQFGF5W.cjs} +13 -13
  50. package/dist/{chunk-XMJE34FY.cjs.map → chunk-RSQFGF5W.cjs.map} +1 -1
  51. package/dist/{chunk-FKGUKFC7.cjs → chunk-TRP5Z3XW.cjs} +5 -5
  52. package/dist/{chunk-FKGUKFC7.cjs.map → chunk-TRP5Z3XW.cjs.map} +1 -1
  53. package/dist/{chunk-EVBYEWHO.js → chunk-UHKZXOXD.js} +9 -2
  54. package/dist/chunk-UHKZXOXD.js.map +1 -0
  55. package/dist/{chunk-IE5ZNCWN.js → chunk-VC2MPB2Y.js} +5 -5
  56. package/dist/{chunk-IE5ZNCWN.js.map → chunk-VC2MPB2Y.js.map} +1 -1
  57. package/dist/{chunk-SRD4KVAP.cjs → chunk-WOYCT5M6.cjs} +764 -209
  58. package/dist/chunk-WOYCT5M6.cjs.map +1 -0
  59. package/dist/{chunk-H6I2JDNW.js → chunk-ZEDMFTKD.js} +10 -10
  60. package/dist/{chunk-H6I2JDNW.js.map → chunk-ZEDMFTKD.js.map} +1 -1
  61. package/dist/{chunk-HA3VRF6E.js → chunk-ZPCO3CEB.js} +3 -3
  62. package/dist/{chunk-HA3VRF6E.js.map → chunk-ZPCO3CEB.js.map} +1 -1
  63. package/dist/{chunk-L7NE7PR4.cjs → chunk-ZSY4VANQ.cjs} +13 -13
  64. package/dist/{chunk-L7NE7PR4.cjs.map → chunk-ZSY4VANQ.cjs.map} +1 -1
  65. package/dist/components/ActivityPreview.cjs +12 -12
  66. package/dist/components/ActivityPreview.d.cts +2 -2
  67. package/dist/components/ActivityPreview.d.ts +2 -2
  68. package/dist/components/ActivityPreview.js +11 -11
  69. package/dist/components/ActivitySequence.cjs +13 -13
  70. package/dist/components/ActivitySequence.d.cts +2 -2
  71. package/dist/components/ActivitySequence.d.ts +2 -2
  72. package/dist/components/ActivitySequence.js +12 -12
  73. package/dist/components/Dictation.cjs +5 -5
  74. package/dist/components/Dictation.d.cts +1 -1
  75. package/dist/components/Dictation.d.ts +1 -1
  76. package/dist/components/Dictation.js +4 -4
  77. package/dist/components/FillInTheBlanks.cjs +5 -5
  78. package/dist/components/FillInTheBlanks.d.cts +1 -1
  79. package/dist/components/FillInTheBlanks.d.ts +1 -1
  80. package/dist/components/FillInTheBlanks.js +4 -4
  81. package/dist/components/GapSelect.cjs +5 -5
  82. package/dist/components/GapSelect.d.cts +1 -1
  83. package/dist/components/GapSelect.d.ts +1 -1
  84. package/dist/components/GapSelect.js +4 -4
  85. package/dist/components/InteractiveVideo.cjs +15 -11
  86. package/dist/components/InteractiveVideo.d.cts +164 -7
  87. package/dist/components/InteractiveVideo.d.ts +164 -7
  88. package/dist/components/InteractiveVideo.js +10 -10
  89. package/dist/components/MultipleChoice.cjs +5 -5
  90. package/dist/components/MultipleChoice.d.cts +1 -1
  91. package/dist/components/MultipleChoice.d.ts +1 -1
  92. package/dist/components/MultipleChoice.js +4 -4
  93. package/dist/components/PronunciationFeedback.cjs +4 -4
  94. package/dist/components/PronunciationFeedback.d.cts +1 -1
  95. package/dist/components/PronunciationFeedback.d.ts +1 -1
  96. package/dist/components/PronunciationFeedback.js +3 -3
  97. package/dist/components/ReadAloud.cjs +6 -6
  98. package/dist/components/ReadAloud.d.cts +2 -2
  99. package/dist/components/ReadAloud.d.ts +2 -2
  100. package/dist/components/ReadAloud.js +5 -5
  101. package/dist/components/StimulusPanel.cjs +4 -4
  102. package/dist/components/StimulusPanel.d.cts +1 -1
  103. package/dist/components/StimulusPanel.d.ts +1 -1
  104. package/dist/components/StimulusPanel.js +3 -3
  105. package/dist/components/WrittenResponse.cjs +5 -5
  106. package/dist/components/WrittenResponse.d.cts +3 -3
  107. package/dist/components/WrittenResponse.d.ts +3 -3
  108. package/dist/components/WrittenResponse.js +4 -4
  109. package/dist/i18n/LkIntlProvider.cjs +7 -7
  110. package/dist/i18n/LkIntlProvider.d.cts +2 -2
  111. package/dist/i18n/LkIntlProvider.d.ts +2 -2
  112. package/dist/i18n/LkIntlProvider.js +1 -1
  113. package/dist/index.cjs +41 -37
  114. package/dist/index.d.cts +3 -3
  115. package/dist/index.d.ts +3 -3
  116. package/dist/index.js +15 -15
  117. package/dist/{strings-5588Q4Te.d.cts → strings-C6wM5aUQ.d.cts} +23 -2
  118. package/dist/{strings-D0IWcsUm.d.ts → strings-Cd_2F-Bw.d.ts} +23 -2
  119. package/dist/theme/ThemeProvider.cjs +6 -6
  120. package/dist/theme/ThemeProvider.js +1 -1
  121. package/dist/theme/defaults.css +7 -0
  122. package/dist/theme/skin.css +60 -6
  123. package/package.json +3 -3
  124. package/dist/chunk-2HAEQDHQ.js.map +0 -1
  125. package/dist/chunk-52GXJNQ3.js.map +0 -1
  126. package/dist/chunk-EVBYEWHO.js.map +0 -1
  127. package/dist/chunk-SRD4KVAP.cjs.map +0 -1
  128. package/dist/chunk-UCKA22ZJ.cjs.map +0 -1
  129. package/dist/chunk-Z6TVOAO5.cjs.map +0 -1
@@ -1,7 +1,8 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { ItemGroup, MediaProgress, LearnerResponse, ItemOutcome, ActivityResult, InteractionEvent, SpeechAssessment, MediaTrack, ThemeTokens } from '@intellectif/lk-core';
3
- import { g as RenderableActivity, e as RenderMode, i as SequenceRecordingSlot, h as SequenceRecordingBinding, V as VideoPreferences, a as LkStringsOverride, H as HtmlSanitizer } from '../strings-5588Q4Te.cjs';
4
- export { C as CaptionSize } from '../strings-5588Q4Te.cjs';
2
+ import { ItemGroup, MediaProgress, LearnerResponse, ItemOutcome, ActivityResult, InteractionEvent, InteractionKind, SpeechAssessment, MediaTrack, ThemeTokens } from '@intellectif/lk-core';
3
+ import { ReactNode } from 'react';
4
+ import { g as RenderableActivity, e as RenderMode, i as SequenceRecordingSlot, h as SequenceRecordingBinding, V as VideoPreferences, a as LkStringsOverride, H as HtmlSanitizer } from '../strings-C6wM5aUQ.cjs';
5
+ export { C as CaptionSize } from '../strings-C6wM5aUQ.cjs';
5
6
  import '../machine-CuwKqWXC.cjs';
6
7
 
7
8
  /** An item group whose items may be `redact()` projections: the client's view of an interactive video. */
@@ -19,6 +20,87 @@ interface InteractiveVideoSummary {
19
20
  status: 'answered' | 'skipped' | 'unreached';
20
21
  }[];
21
22
  }
23
+ /**
24
+ * One question, as `renderQuestion` is handed it: what to draw, and the six
25
+ * calls through which the video learns what the learner did.
26
+ *
27
+ * The calls are the ones the SDK's own components make, so a question the host
28
+ * draws counts exactly as one the SDK draws — in the step dots, in whether a
29
+ * required quiz lets the learner go on, on the end card and in `onFinished`.
30
+ * Each keeps ONE identity per question for the life of the player, so it is
31
+ * safe in an effect's dependencies, and each does nothing once the player has
32
+ * unmounted.
33
+ */
34
+ interface InteractiveVideoQuestion {
35
+ /** The question, as the SDK would have rendered it: full data, or a `redact()` projection. */
36
+ activity: RenderableActivity;
37
+ /** Where it sits: the same object `onSubmit` and `onActivityComplete` are handed, for the life of the player. */
38
+ slot: InteractiveVideoSlot;
39
+ /**
40
+ * Passed through untouched. The SDK cannot enforce a mode for pixels it does
41
+ * not draw: in `exam` the host must not reveal correctness, and in `review`
42
+ * nothing is submittable — `submit`, `complete` and `clear` are ignored there.
43
+ */
44
+ renderMode: RenderMode;
45
+ /**
46
+ * `true` while this question is the one on screen: its quiz is open and it is
47
+ * the current step. `false` from the moment it leaves the screen — another
48
+ * step, the quiz closing, another quiz opening — and `true` again when the
49
+ * learner comes back.
50
+ *
51
+ * WHEN IT TURNS `false`, STOP THE MICROPHONE, ANY TIMER AND ANY SPEECH. The
52
+ * video pauses the `<audio>` and `<video>` elements inside the question and
53
+ * stops the recorders the SDK started, but it cannot reach a recorder it did
54
+ * not create.
55
+ */
56
+ active: boolean;
57
+ locale?: string;
58
+ /** The answer restored from `responses`. A starting value: read it once, as the SDK's components do. */
59
+ defaultValue?: LearnerResponse;
60
+ /** Whether `submittedSlotIds` names this question: it was handed in before this attempt resumed. */
61
+ defaultSubmitted: boolean;
62
+ /** Its stored outcome from `outcomes`: review, or the grade of a question graded later. Read live. */
63
+ outcome?: ItemOutcome;
64
+ /**
65
+ * An element inside the player, for popovers and tooltips. Portal into it
66
+ * rather than into `document.body`: in fullscreen only the player is painted,
67
+ * and anything outside it silently vanishes. It is drawn above the quiz, is
68
+ * the same element for the life of the player — one for every question, so
69
+ * key what you put in it — and is `null` only before the player's first
70
+ * commit.
71
+ */
72
+ portalContainer: HTMLElement | null;
73
+ /**
74
+ * The learner committed an answer: marks the question answered and forwards
75
+ * to `onSubmit(response, slot)`. Latest wins: call it again for a new take or
76
+ * a corrected answer.
77
+ */
78
+ submit(response: LearnerResponse): void;
79
+ /**
80
+ * The answer has a result: marks the question answered, keeps `score / maxScore`
81
+ * for the end card when `maxScore > 0`, and forwards to
82
+ * `onActivityComplete(result, slot)`. Latest wins. Counts as answered on its
83
+ * own, without a `submit`, and forwards exactly what was called — no
84
+ * `onSubmit` is invented for it.
85
+ */
86
+ complete(result: ActivityResult): void;
87
+ /**
88
+ * The learner withdrew the answer — a "Try again". The question is unanswered
89
+ * again and its score forgotten: its step dot empties, a required quiz holds
90
+ * the learner again, and `onFinished` would report it `skipped`. Calls no
91
+ * host callback: the host already knows.
92
+ */
93
+ clear(): void;
94
+ /**
95
+ * Work is on its way for this question — an upload, an assessment. While any
96
+ * question is pending, Finish on the end card waits, and a video that ends
97
+ * does not finish by itself; closing the quiz, paging and seeking do not wait.
98
+ * Call `setPending(false)` however the work ends, a failure included.
99
+ */
100
+ setPending(pending: boolean): void;
101
+ /** Forwards to `onInteraction`, with this question's `activityId` and the time filled in. */
102
+ emit(type: InteractionKind, payload?: Record<string, unknown>): void;
103
+ }
22
104
  interface InteractiveVideoProps {
23
105
  /** An item group with a video stimulus and a timeline. Redacted projections in exam and review. */
24
106
  group: RenderableItemGroup;
@@ -40,10 +122,39 @@ interface InteractiveVideoProps {
40
122
  outcomes?: Readonly<Record<string, ItemOutcome>>;
41
123
  onSubmit?: (response: LearnerResponse, slot: InteractiveVideoSlot) => void;
42
124
  onActivityComplete?: (result: ActivityResult, slot: InteractiveVideoSlot) => void;
43
- /** Once per mount: when the learner presses Finish, or the video ends with every question answered. */
125
+ /**
126
+ * Once per mount: when the learner presses Finish, or the video ends with every
127
+ * question answered — either way, only once no answer is still on its way.
128
+ */
44
129
  onFinished?: (summary: InteractiveVideoSummary) => void;
45
130
  onInteraction?: (event: InteractionEvent) => void;
46
- /** Where read-aloud takes are stored and judged. Required when the video holds a read-aloud, outside review. */
131
+ /**
132
+ * Draws a question yourself. Called for each question once its quiz has
133
+ * opened, and on every render after;
134
+ * return `undefined` for the SDK's own component, so a host can take over one
135
+ * activity type and leave the rest. `null` draws nothing, and is kept.
136
+ *
137
+ * The video still owns everything around the question: when it opens,
138
+ * whether it counts as answered, whether a required quiz lets the learner go
139
+ * on, pausing, resume and the end summary — all through the calls on
140
+ * {@link InteractiveVideoQuestion}. A question the host draws is never
141
+ * treated differently from one the SDK draws.
142
+ *
143
+ * THE HOST MUST STOP ITS MICROPHONE WHEN `active` TURNS `false`: the SDK stops
144
+ * only the recorders it created. And the SDK cannot keep a mode for pixels it
145
+ * does not draw: in `exam` reveal no correctness, and in `review` accept no
146
+ * answer.
147
+ *
148
+ * What you return is keyed by the question's slot and stays mounted for the
149
+ * life of the player, like the SDK's own questions, and sits inside the same
150
+ * error boundary: a throw degrades that one question, never the video.
151
+ */
152
+ renderQuestion?: (question: InteractiveVideoQuestion) => ReactNode | undefined;
153
+ /**
154
+ * Where read-aloud takes are stored and judged. Required for every read-aloud
155
+ * the SDK draws itself, outside review; a video whose read-alouds are all
156
+ * drawn by `renderQuestion` needs none.
157
+ */
47
158
  recordingBinding?: SequenceRecordingBinding;
48
159
  /** Speech assessments by slot id, so `review` shows the marks behind a read-aloud's grade. Read live. */
49
160
  assessments?: Readonly<Record<string, SpeechAssessment>>;
@@ -55,8 +166,30 @@ interface InteractiveVideoProps {
55
166
  * could not do for a URL that needs an Authorization header.
56
167
  */
57
168
  captionsLoader?: (track: MediaTrack) => Promise<string>;
58
- /** Overrides what the learner's browser remembers. */
169
+ /**
170
+ * FORCES preferences: each field given here overrides what the learner chose,
171
+ * every time the video opens. For a starting point the learner can still
172
+ * change — a language pair, say — pass `defaultPreferences` instead. Read when
173
+ * the video opens; the learner's own changes after that hold.
174
+ */
59
175
  preferences?: Partial<VideoPreferences>;
176
+ /**
177
+ * Preferences to start from, below what the learner chose in this browser:
178
+ * each field applies until the learner changes it. A host that keeps the
179
+ * learner's choice on their account passes it back here — on a new device
180
+ * nothing is stored, so the account's choice applies; on the same device the
181
+ * stored choice is that same choice. Read live: a value that arrives after
182
+ * the video opens still fills every field nobody chose.
183
+ */
184
+ defaultPreferences?: Partial<VideoPreferences>;
185
+ /**
186
+ * After each change the learner makes — a menu, a shortcut, the volume, the
187
+ * speed — with the preferences now in force and the fields that changed.
188
+ * Never when the video opens, and never for `preferences`. The player still
189
+ * remembers the change in this browser; this is for a host that keeps it on
190
+ * the learner's account as well.
191
+ */
192
+ onPreferencesChange?: (next: VideoPreferences, change: Partial<VideoPreferences>) => void;
60
193
  /** A short label in the corner, such as a lesson code. */
61
194
  label?: string;
62
195
  /** Seed for the option order of multiple-choice and gap-select questions: the attempt id. */
@@ -67,6 +200,30 @@ interface InteractiveVideoProps {
67
200
  sanitizeHtml?: HtmlSanitizer;
68
201
  }
69
202
 
203
+ /** The two lines a learner can have: which track each shows, if any. */
204
+ interface CaptionTracks {
205
+ primary?: MediaTrack;
206
+ secondary?: MediaTrack;
207
+ }
208
+ /**
209
+ * Which track each caption line shows, from the learner's two choices.
210
+ *
211
+ * The primary line always shows something while there are tracks:
212
+ * 1. the track in `captionLanguage` (case-insensitive);
213
+ * 2. else one of the same primary language — `pt` finds `pt-BR`, `es` finds
214
+ * `es-419`;
215
+ * 3. else the `default` track;
216
+ * 4. else the first.
217
+ *
218
+ * Where two tracks share a language, the `captions` one wins.
219
+ *
220
+ * The secondary line is stricter: it appears only when `secondaryCaptionLanguage`
221
+ * is set and matches a track in another language, by steps 1 and 2 alone —
222
+ * never the default, never the first. A second line the learner did not choose
223
+ * must never appear.
224
+ */
225
+ declare function resolveCaptionTracks(tracks: readonly MediaTrack[], preferences: Pick<VideoPreferences, 'captionLanguage' | 'secondaryCaptionLanguage'>): CaptionTracks;
226
+
70
227
  /**
71
228
  * Public interactive video: the player wrapped in `ActivityErrorBoundary`, so a
72
229
  * render failure — the development-time schema check among them — degrades to
@@ -74,4 +231,4 @@ interface InteractiveVideoProps {
74
231
  */
75
232
  declare function InteractiveVideo(props: InteractiveVideoProps): react_jsx_runtime.JSX.Element;
76
233
 
77
- export { InteractiveVideo, type InteractiveVideoProps, type InteractiveVideoSlot, type InteractiveVideoSummary, type RenderableItemGroup, VideoPreferences };
234
+ export { type CaptionTracks, InteractiveVideo, type InteractiveVideoProps, type InteractiveVideoQuestion, type InteractiveVideoSlot, type InteractiveVideoSummary, type RenderableItemGroup, VideoPreferences, resolveCaptionTracks };
@@ -1,7 +1,8 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { ItemGroup, MediaProgress, LearnerResponse, ItemOutcome, ActivityResult, InteractionEvent, SpeechAssessment, MediaTrack, ThemeTokens } from '@intellectif/lk-core';
3
- import { g as RenderableActivity, e as RenderMode, i as SequenceRecordingSlot, h as SequenceRecordingBinding, V as VideoPreferences, a as LkStringsOverride, H as HtmlSanitizer } from '../strings-D0IWcsUm.js';
4
- export { C as CaptionSize } from '../strings-D0IWcsUm.js';
2
+ import { ItemGroup, MediaProgress, LearnerResponse, ItemOutcome, ActivityResult, InteractionEvent, InteractionKind, SpeechAssessment, MediaTrack, ThemeTokens } from '@intellectif/lk-core';
3
+ import { ReactNode } from 'react';
4
+ import { g as RenderableActivity, e as RenderMode, i as SequenceRecordingSlot, h as SequenceRecordingBinding, V as VideoPreferences, a as LkStringsOverride, H as HtmlSanitizer } from '../strings-Cd_2F-Bw.js';
5
+ export { C as CaptionSize } from '../strings-Cd_2F-Bw.js';
5
6
  import '../machine-CuwKqWXC.js';
6
7
 
7
8
  /** An item group whose items may be `redact()` projections: the client's view of an interactive video. */
@@ -19,6 +20,87 @@ interface InteractiveVideoSummary {
19
20
  status: 'answered' | 'skipped' | 'unreached';
20
21
  }[];
21
22
  }
23
+ /**
24
+ * One question, as `renderQuestion` is handed it: what to draw, and the six
25
+ * calls through which the video learns what the learner did.
26
+ *
27
+ * The calls are the ones the SDK's own components make, so a question the host
28
+ * draws counts exactly as one the SDK draws — in the step dots, in whether a
29
+ * required quiz lets the learner go on, on the end card and in `onFinished`.
30
+ * Each keeps ONE identity per question for the life of the player, so it is
31
+ * safe in an effect's dependencies, and each does nothing once the player has
32
+ * unmounted.
33
+ */
34
+ interface InteractiveVideoQuestion {
35
+ /** The question, as the SDK would have rendered it: full data, or a `redact()` projection. */
36
+ activity: RenderableActivity;
37
+ /** Where it sits: the same object `onSubmit` and `onActivityComplete` are handed, for the life of the player. */
38
+ slot: InteractiveVideoSlot;
39
+ /**
40
+ * Passed through untouched. The SDK cannot enforce a mode for pixels it does
41
+ * not draw: in `exam` the host must not reveal correctness, and in `review`
42
+ * nothing is submittable — `submit`, `complete` and `clear` are ignored there.
43
+ */
44
+ renderMode: RenderMode;
45
+ /**
46
+ * `true` while this question is the one on screen: its quiz is open and it is
47
+ * the current step. `false` from the moment it leaves the screen — another
48
+ * step, the quiz closing, another quiz opening — and `true` again when the
49
+ * learner comes back.
50
+ *
51
+ * WHEN IT TURNS `false`, STOP THE MICROPHONE, ANY TIMER AND ANY SPEECH. The
52
+ * video pauses the `<audio>` and `<video>` elements inside the question and
53
+ * stops the recorders the SDK started, but it cannot reach a recorder it did
54
+ * not create.
55
+ */
56
+ active: boolean;
57
+ locale?: string;
58
+ /** The answer restored from `responses`. A starting value: read it once, as the SDK's components do. */
59
+ defaultValue?: LearnerResponse;
60
+ /** Whether `submittedSlotIds` names this question: it was handed in before this attempt resumed. */
61
+ defaultSubmitted: boolean;
62
+ /** Its stored outcome from `outcomes`: review, or the grade of a question graded later. Read live. */
63
+ outcome?: ItemOutcome;
64
+ /**
65
+ * An element inside the player, for popovers and tooltips. Portal into it
66
+ * rather than into `document.body`: in fullscreen only the player is painted,
67
+ * and anything outside it silently vanishes. It is drawn above the quiz, is
68
+ * the same element for the life of the player — one for every question, so
69
+ * key what you put in it — and is `null` only before the player's first
70
+ * commit.
71
+ */
72
+ portalContainer: HTMLElement | null;
73
+ /**
74
+ * The learner committed an answer: marks the question answered and forwards
75
+ * to `onSubmit(response, slot)`. Latest wins: call it again for a new take or
76
+ * a corrected answer.
77
+ */
78
+ submit(response: LearnerResponse): void;
79
+ /**
80
+ * The answer has a result: marks the question answered, keeps `score / maxScore`
81
+ * for the end card when `maxScore > 0`, and forwards to
82
+ * `onActivityComplete(result, slot)`. Latest wins. Counts as answered on its
83
+ * own, without a `submit`, and forwards exactly what was called — no
84
+ * `onSubmit` is invented for it.
85
+ */
86
+ complete(result: ActivityResult): void;
87
+ /**
88
+ * The learner withdrew the answer — a "Try again". The question is unanswered
89
+ * again and its score forgotten: its step dot empties, a required quiz holds
90
+ * the learner again, and `onFinished` would report it `skipped`. Calls no
91
+ * host callback: the host already knows.
92
+ */
93
+ clear(): void;
94
+ /**
95
+ * Work is on its way for this question — an upload, an assessment. While any
96
+ * question is pending, Finish on the end card waits, and a video that ends
97
+ * does not finish by itself; closing the quiz, paging and seeking do not wait.
98
+ * Call `setPending(false)` however the work ends, a failure included.
99
+ */
100
+ setPending(pending: boolean): void;
101
+ /** Forwards to `onInteraction`, with this question's `activityId` and the time filled in. */
102
+ emit(type: InteractionKind, payload?: Record<string, unknown>): void;
103
+ }
22
104
  interface InteractiveVideoProps {
23
105
  /** An item group with a video stimulus and a timeline. Redacted projections in exam and review. */
24
106
  group: RenderableItemGroup;
@@ -40,10 +122,39 @@ interface InteractiveVideoProps {
40
122
  outcomes?: Readonly<Record<string, ItemOutcome>>;
41
123
  onSubmit?: (response: LearnerResponse, slot: InteractiveVideoSlot) => void;
42
124
  onActivityComplete?: (result: ActivityResult, slot: InteractiveVideoSlot) => void;
43
- /** Once per mount: when the learner presses Finish, or the video ends with every question answered. */
125
+ /**
126
+ * Once per mount: when the learner presses Finish, or the video ends with every
127
+ * question answered — either way, only once no answer is still on its way.
128
+ */
44
129
  onFinished?: (summary: InteractiveVideoSummary) => void;
45
130
  onInteraction?: (event: InteractionEvent) => void;
46
- /** Where read-aloud takes are stored and judged. Required when the video holds a read-aloud, outside review. */
131
+ /**
132
+ * Draws a question yourself. Called for each question once its quiz has
133
+ * opened, and on every render after;
134
+ * return `undefined` for the SDK's own component, so a host can take over one
135
+ * activity type and leave the rest. `null` draws nothing, and is kept.
136
+ *
137
+ * The video still owns everything around the question: when it opens,
138
+ * whether it counts as answered, whether a required quiz lets the learner go
139
+ * on, pausing, resume and the end summary — all through the calls on
140
+ * {@link InteractiveVideoQuestion}. A question the host draws is never
141
+ * treated differently from one the SDK draws.
142
+ *
143
+ * THE HOST MUST STOP ITS MICROPHONE WHEN `active` TURNS `false`: the SDK stops
144
+ * only the recorders it created. And the SDK cannot keep a mode for pixels it
145
+ * does not draw: in `exam` reveal no correctness, and in `review` accept no
146
+ * answer.
147
+ *
148
+ * What you return is keyed by the question's slot and stays mounted for the
149
+ * life of the player, like the SDK's own questions, and sits inside the same
150
+ * error boundary: a throw degrades that one question, never the video.
151
+ */
152
+ renderQuestion?: (question: InteractiveVideoQuestion) => ReactNode | undefined;
153
+ /**
154
+ * Where read-aloud takes are stored and judged. Required for every read-aloud
155
+ * the SDK draws itself, outside review; a video whose read-alouds are all
156
+ * drawn by `renderQuestion` needs none.
157
+ */
47
158
  recordingBinding?: SequenceRecordingBinding;
48
159
  /** Speech assessments by slot id, so `review` shows the marks behind a read-aloud's grade. Read live. */
49
160
  assessments?: Readonly<Record<string, SpeechAssessment>>;
@@ -55,8 +166,30 @@ interface InteractiveVideoProps {
55
166
  * could not do for a URL that needs an Authorization header.
56
167
  */
57
168
  captionsLoader?: (track: MediaTrack) => Promise<string>;
58
- /** Overrides what the learner's browser remembers. */
169
+ /**
170
+ * FORCES preferences: each field given here overrides what the learner chose,
171
+ * every time the video opens. For a starting point the learner can still
172
+ * change — a language pair, say — pass `defaultPreferences` instead. Read when
173
+ * the video opens; the learner's own changes after that hold.
174
+ */
59
175
  preferences?: Partial<VideoPreferences>;
176
+ /**
177
+ * Preferences to start from, below what the learner chose in this browser:
178
+ * each field applies until the learner changes it. A host that keeps the
179
+ * learner's choice on their account passes it back here — on a new device
180
+ * nothing is stored, so the account's choice applies; on the same device the
181
+ * stored choice is that same choice. Read live: a value that arrives after
182
+ * the video opens still fills every field nobody chose.
183
+ */
184
+ defaultPreferences?: Partial<VideoPreferences>;
185
+ /**
186
+ * After each change the learner makes — a menu, a shortcut, the volume, the
187
+ * speed — with the preferences now in force and the fields that changed.
188
+ * Never when the video opens, and never for `preferences`. The player still
189
+ * remembers the change in this browser; this is for a host that keeps it on
190
+ * the learner's account as well.
191
+ */
192
+ onPreferencesChange?: (next: VideoPreferences, change: Partial<VideoPreferences>) => void;
60
193
  /** A short label in the corner, such as a lesson code. */
61
194
  label?: string;
62
195
  /** Seed for the option order of multiple-choice and gap-select questions: the attempt id. */
@@ -67,6 +200,30 @@ interface InteractiveVideoProps {
67
200
  sanitizeHtml?: HtmlSanitizer;
68
201
  }
69
202
 
203
+ /** The two lines a learner can have: which track each shows, if any. */
204
+ interface CaptionTracks {
205
+ primary?: MediaTrack;
206
+ secondary?: MediaTrack;
207
+ }
208
+ /**
209
+ * Which track each caption line shows, from the learner's two choices.
210
+ *
211
+ * The primary line always shows something while there are tracks:
212
+ * 1. the track in `captionLanguage` (case-insensitive);
213
+ * 2. else one of the same primary language — `pt` finds `pt-BR`, `es` finds
214
+ * `es-419`;
215
+ * 3. else the `default` track;
216
+ * 4. else the first.
217
+ *
218
+ * Where two tracks share a language, the `captions` one wins.
219
+ *
220
+ * The secondary line is stricter: it appears only when `secondaryCaptionLanguage`
221
+ * is set and matches a track in another language, by steps 1 and 2 alone —
222
+ * never the default, never the first. A second line the learner did not choose
223
+ * must never appear.
224
+ */
225
+ declare function resolveCaptionTracks(tracks: readonly MediaTrack[], preferences: Pick<VideoPreferences, 'captionLanguage' | 'secondaryCaptionLanguage'>): CaptionTracks;
226
+
70
227
  /**
71
228
  * Public interactive video: the player wrapped in `ActivityErrorBoundary`, so a
72
229
  * render failure — the development-time schema check among them — degrades to
@@ -74,4 +231,4 @@ interface InteractiveVideoProps {
74
231
  */
75
232
  declare function InteractiveVideo(props: InteractiveVideoProps): react_jsx_runtime.JSX.Element;
76
233
 
77
- export { InteractiveVideo, type InteractiveVideoProps, type InteractiveVideoSlot, type InteractiveVideoSummary, type RenderableItemGroup, VideoPreferences };
234
+ export { type CaptionTracks, InteractiveVideo, type InteractiveVideoProps, type InteractiveVideoQuestion, type InteractiveVideoSlot, type InteractiveVideoSummary, type RenderableItemGroup, VideoPreferences, resolveCaptionTracks };
@@ -1,17 +1,17 @@
1
1
  'use client';
2
- export { InteractiveVideo } from '../chunk-2HAEQDHQ.js';
3
- import '../chunk-RT5FTHUU.js';
4
- import '../chunk-IE5ZNCWN.js';
5
- import '../chunk-CE6OGJE6.js';
6
- import '../chunk-33BQNWAQ.js';
7
- import '../chunk-QEB6O6GU.js';
8
- import '../chunk-QM4AV6EG.js';
2
+ export { InteractiveVideo, resolveCaptionTracks } from '../chunk-DVOPHC2Q.js';
3
+ import '../chunk-3UXRX4KU.js';
4
+ import '../chunk-VC2MPB2Y.js';
5
+ import '../chunk-5QHVYOME.js';
6
+ import '../chunk-IQI5I2X5.js';
7
+ import '../chunk-GUPBIEUA.js';
8
+ import '../chunk-BI547RIA.js';
9
9
  import '../chunk-MCO52PV5.js';
10
10
  import '../chunk-YORQQXGO.js';
11
11
  import '../chunk-RCMYEWBE.js';
12
- import '../chunk-ZJMTHPHY.js';
13
- import '../chunk-HA3VRF6E.js';
12
+ import '../chunk-DKZWUIQD.js';
13
+ import '../chunk-ZPCO3CEB.js';
14
14
  import '../chunk-6N43WDVG.js';
15
- import '../chunk-52GXJNQ3.js';
15
+ import '../chunk-KSAINXRG.js';
16
16
  //# sourceMappingURL=InteractiveVideo.js.map
17
17
  //# sourceMappingURL=InteractiveVideo.js.map
@@ -1,18 +1,18 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
- var chunkL7NE7PR4_cjs = require('../chunk-L7NE7PR4.cjs');
4
+ var chunkZSY4VANQ_cjs = require('../chunk-ZSY4VANQ.cjs');
5
5
  require('../chunk-BRPEB43C.cjs');
6
- require('../chunk-53YOZOGN.cjs');
7
- require('../chunk-FKGUKFC7.cjs');
6
+ require('../chunk-2S3MK4VX.cjs');
7
+ require('../chunk-TRP5Z3XW.cjs');
8
8
  require('../chunk-XOR4MPEN.cjs');
9
- require('../chunk-Z6TVOAO5.cjs');
9
+ require('../chunk-MQAZJQRE.cjs');
10
10
 
11
11
 
12
12
 
13
13
  Object.defineProperty(exports, "MultipleChoice", {
14
14
  enumerable: true,
15
- get: function () { return chunkL7NE7PR4_cjs.MultipleChoice; }
15
+ get: function () { return chunkZSY4VANQ_cjs.MultipleChoice; }
16
16
  });
17
17
  //# sourceMappingURL=MultipleChoice.cjs.map
18
18
  //# sourceMappingURL=MultipleChoice.cjs.map
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { MultipleChoiceData } from '@intellectif/lk-core';
3
- import { A as ActivityProps } from '../strings-5588Q4Te.cjs';
3
+ import { A as ActivityProps } from '../strings-C6wM5aUQ.cjs';
4
4
  import '../machine-CuwKqWXC.cjs';
5
5
 
6
6
  interface MultipleChoiceProps extends ActivityProps<MultipleChoiceData> {
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { MultipleChoiceData } from '@intellectif/lk-core';
3
- import { A as ActivityProps } from '../strings-D0IWcsUm.js';
3
+ import { A as ActivityProps } from '../strings-Cd_2F-Bw.js';
4
4
  import '../machine-CuwKqWXC.js';
5
5
 
6
6
  interface MultipleChoiceProps extends ActivityProps<MultipleChoiceData> {
@@ -1,9 +1,9 @@
1
1
  'use client';
2
- export { MultipleChoice } from '../chunk-RT5FTHUU.js';
2
+ export { MultipleChoice } from '../chunk-3UXRX4KU.js';
3
3
  import '../chunk-RCMYEWBE.js';
4
- import '../chunk-ZJMTHPHY.js';
5
- import '../chunk-HA3VRF6E.js';
4
+ import '../chunk-DKZWUIQD.js';
5
+ import '../chunk-ZPCO3CEB.js';
6
6
  import '../chunk-6N43WDVG.js';
7
- import '../chunk-52GXJNQ3.js';
7
+ import '../chunk-KSAINXRG.js';
8
8
  //# sourceMappingURL=MultipleChoice.js.map
9
9
  //# sourceMappingURL=MultipleChoice.js.map
@@ -1,16 +1,16 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
- var chunkWKOV25NP_cjs = require('../chunk-WKOV25NP.cjs');
4
+ var chunkDFMBVA7D_cjs = require('../chunk-DFMBVA7D.cjs');
5
5
  require('../chunk-OD65OZIW.cjs');
6
- require('../chunk-53YOZOGN.cjs');
7
- require('../chunk-Z6TVOAO5.cjs');
6
+ require('../chunk-2S3MK4VX.cjs');
7
+ require('../chunk-MQAZJQRE.cjs');
8
8
 
9
9
 
10
10
 
11
11
  Object.defineProperty(exports, "PronunciationFeedback", {
12
12
  enumerable: true,
13
- get: function () { return chunkWKOV25NP_cjs.PronunciationFeedback; }
13
+ get: function () { return chunkDFMBVA7D_cjs.PronunciationFeedback; }
14
14
  });
15
15
  //# sourceMappingURL=PronunciationFeedback.cjs.map
16
16
  //# sourceMappingURL=PronunciationFeedback.cjs.map
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReadAloudData, SpeechAssessment, GradeRecord, ThemeTokens } from '@intellectif/lk-core';
3
- import { a as LkStringsOverride } from '../strings-5588Q4Te.cjs';
3
+ import { a as LkStringsOverride } from '../strings-C6wM5aUQ.cjs';
4
4
  import '../machine-CuwKqWXC.cjs';
5
5
 
6
6
  interface PronunciationFeedbackProps {
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReadAloudData, SpeechAssessment, GradeRecord, ThemeTokens } from '@intellectif/lk-core';
3
- import { a as LkStringsOverride } from '../strings-D0IWcsUm.js';
3
+ import { a as LkStringsOverride } from '../strings-Cd_2F-Bw.js';
4
4
  import '../machine-CuwKqWXC.js';
5
5
 
6
6
  interface PronunciationFeedbackProps {
@@ -1,7 +1,7 @@
1
1
  'use client';
2
- export { PronunciationFeedback } from '../chunk-QM4AV6EG.js';
2
+ export { PronunciationFeedback } from '../chunk-BI547RIA.js';
3
3
  import '../chunk-YORQQXGO.js';
4
- import '../chunk-ZJMTHPHY.js';
5
- import '../chunk-52GXJNQ3.js';
4
+ import '../chunk-DKZWUIQD.js';
5
+ import '../chunk-KSAINXRG.js';
6
6
  //# sourceMappingURL=PronunciationFeedback.js.map
7
7
  //# sourceMappingURL=PronunciationFeedback.js.map
@@ -1,21 +1,21 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
- var chunkZH5WT2IE_cjs = require('../chunk-ZH5WT2IE.cjs');
5
- require('../chunk-WKOV25NP.cjs');
4
+ var chunkML6L4LJH_cjs = require('../chunk-ML6L4LJH.cjs');
5
+ require('../chunk-DFMBVA7D.cjs');
6
6
  require('../chunk-UDCQTOVU.cjs');
7
7
  require('../chunk-OD65OZIW.cjs');
8
8
  require('../chunk-BRPEB43C.cjs');
9
- require('../chunk-53YOZOGN.cjs');
10
- require('../chunk-FKGUKFC7.cjs');
9
+ require('../chunk-2S3MK4VX.cjs');
10
+ require('../chunk-TRP5Z3XW.cjs');
11
11
  require('../chunk-XOR4MPEN.cjs');
12
- require('../chunk-Z6TVOAO5.cjs');
12
+ require('../chunk-MQAZJQRE.cjs');
13
13
 
14
14
 
15
15
 
16
16
  Object.defineProperty(exports, "ReadAloud", {
17
17
  enumerable: true,
18
- get: function () { return chunkZH5WT2IE_cjs.ReadAloud; }
18
+ get: function () { return chunkML6L4LJH_cjs.ReadAloud; }
19
19
  });
20
20
  //# sourceMappingURL=ReadAloud.cjs.map
21
21
  //# sourceMappingURL=ReadAloud.cjs.map
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { c as ReadAloudProps } from '../strings-5588Q4Te.cjs';
3
- export { R as ReadAloudAssessResult, d as RecordingBinding } from '../strings-5588Q4Te.cjs';
2
+ import { c as ReadAloudProps } from '../strings-C6wM5aUQ.cjs';
3
+ export { R as ReadAloudAssessResult, d as RecordingBinding } from '../strings-C6wM5aUQ.cjs';
4
4
  export { R as RecordedTake } from '../machine-CuwKqWXC.cjs';
5
5
  import '@intellectif/lk-core';
6
6
 
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { c as ReadAloudProps } from '../strings-D0IWcsUm.js';
3
- export { R as ReadAloudAssessResult, d as RecordingBinding } from '../strings-D0IWcsUm.js';
2
+ import { c as ReadAloudProps } from '../strings-Cd_2F-Bw.js';
3
+ export { R as ReadAloudAssessResult, d as RecordingBinding } from '../strings-Cd_2F-Bw.js';
4
4
  export { R as RecordedTake } from '../machine-CuwKqWXC.js';
5
5
  import '@intellectif/lk-core';
6
6
 
@@ -1,12 +1,12 @@
1
1
  'use client';
2
- export { ReadAloud } from '../chunk-QEB6O6GU.js';
3
- import '../chunk-QM4AV6EG.js';
2
+ export { ReadAloud } from '../chunk-GUPBIEUA.js';
3
+ import '../chunk-BI547RIA.js';
4
4
  import '../chunk-MCO52PV5.js';
5
5
  import '../chunk-YORQQXGO.js';
6
6
  import '../chunk-RCMYEWBE.js';
7
- import '../chunk-ZJMTHPHY.js';
8
- import '../chunk-HA3VRF6E.js';
7
+ import '../chunk-DKZWUIQD.js';
8
+ import '../chunk-ZPCO3CEB.js';
9
9
  import '../chunk-6N43WDVG.js';
10
- import '../chunk-52GXJNQ3.js';
10
+ import '../chunk-KSAINXRG.js';
11
11
  //# sourceMappingURL=ReadAloud.js.map
12
12
  //# sourceMappingURL=ReadAloud.js.map
@@ -1,15 +1,15 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
- var chunkDP3DM7FR_cjs = require('../chunk-DP3DM7FR.cjs');
5
- require('../chunk-FKGUKFC7.cjs');
6
- require('../chunk-Z6TVOAO5.cjs');
4
+ var chunkPXGJHZKJ_cjs = require('../chunk-PXGJHZKJ.cjs');
5
+ require('../chunk-TRP5Z3XW.cjs');
6
+ require('../chunk-MQAZJQRE.cjs');
7
7
 
8
8
 
9
9
 
10
10
  Object.defineProperty(exports, "StimulusPanel", {
11
11
  enumerable: true,
12
- get: function () { return chunkDP3DM7FR_cjs.StimulusPanel; }
12
+ get: function () { return chunkPXGJHZKJ_cjs.StimulusPanel; }
13
13
  });
14
14
  //# sourceMappingURL=StimulusPanel.cjs.map
15
15
  //# sourceMappingURL=StimulusPanel.cjs.map