@intellectif/lk-react 20.0.0 → 22.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/README.md +33 -5
  3. package/dist/{WrittenResponse-D2YI8xOK.d.ts → WrittenResponse-CgRrjM4S.d.ts} +14 -4
  4. package/dist/{WrittenResponse-obIDDYDH.d.cts → WrittenResponse-D2K1VW_V.d.cts} +14 -4
  5. package/dist/ai/LkAiProvider.cjs +3 -3
  6. package/dist/ai/LkAiProvider.d.cts +17 -4
  7. package/dist/ai/LkAiProvider.d.ts +17 -4
  8. package/dist/ai/LkAiProvider.js +1 -1
  9. package/dist/ai/useAiHelp.cjs +9 -5
  10. package/dist/ai/useAiHelp.d.cts +58 -3
  11. package/dist/ai/useAiHelp.d.ts +58 -3
  12. package/dist/ai/useAiHelp.js +3 -3
  13. package/dist/{chunk-BGA2IVQY.js → chunk-3GLYK37F.js} +119 -26
  14. package/dist/chunk-3GLYK37F.js.map +1 -0
  15. package/dist/{chunk-LX2X4KC7.cjs → chunk-5YGVGMMV.cjs} +7 -7
  16. package/dist/{chunk-LX2X4KC7.cjs.map → chunk-5YGVGMMV.cjs.map} +1 -1
  17. package/dist/{chunk-3XP6VO4G.js → chunk-62K4Q565.js} +139 -45
  18. package/dist/chunk-62K4Q565.js.map +1 -0
  19. package/dist/{chunk-CEUEXISZ.cjs → chunk-6QY7GC55.cjs} +131 -50
  20. package/dist/chunk-6QY7GC55.cjs.map +1 -0
  21. package/dist/chunk-7EEKZWTQ.js +241 -0
  22. package/dist/chunk-7EEKZWTQ.js.map +1 -0
  23. package/dist/{chunk-3FBBP5QR.cjs → chunk-B4JRBV56.cjs} +6 -6
  24. package/dist/{chunk-3FBBP5QR.cjs.map → chunk-B4JRBV56.cjs.map} +1 -1
  25. package/dist/{chunk-RT2PP4SO.cjs → chunk-BL5SIBQA.cjs} +30 -30
  26. package/dist/{chunk-RT2PP4SO.cjs.map → chunk-BL5SIBQA.cjs.map} +1 -1
  27. package/dist/{chunk-YRNEOBXA.js → chunk-C4PSJ3ZC.js} +19 -2
  28. package/dist/chunk-C4PSJ3ZC.js.map +1 -0
  29. package/dist/{chunk-FEOFX4QW.js → chunk-FB47DQPS.js} +3 -3
  30. package/dist/{chunk-FEOFX4QW.js.map → chunk-FB47DQPS.js.map} +1 -1
  31. package/dist/chunk-FKNEHCNT.cjs +251 -0
  32. package/dist/chunk-FKNEHCNT.cjs.map +1 -0
  33. package/dist/{chunk-AG7MWZYZ.js → chunk-FPM2GQZY.js} +144 -55
  34. package/dist/chunk-FPM2GQZY.js.map +1 -0
  35. package/dist/{chunk-NWNQ2PHT.js → chunk-HNZ3JMAN.js} +8 -8
  36. package/dist/{chunk-NWNQ2PHT.js.map → chunk-HNZ3JMAN.js.map} +1 -1
  37. package/dist/{chunk-BY4UQH2Y.js → chunk-HYOUMTPW.js} +3 -3
  38. package/dist/{chunk-BY4UQH2Y.js.map → chunk-HYOUMTPW.js.map} +1 -1
  39. package/dist/{chunk-7K4B2EMU.js → chunk-HZIT24BK.js} +4 -4
  40. package/dist/{chunk-7K4B2EMU.js.map → chunk-HZIT24BK.js.map} +1 -1
  41. package/dist/{chunk-BJLQKJZX.cjs → chunk-J2QIHZ3H.cjs} +2 -2
  42. package/dist/chunk-J2QIHZ3H.cjs.map +1 -0
  43. package/dist/{chunk-DZVF3IGB.cjs → chunk-JII7XSCT.cjs} +59 -25
  44. package/dist/chunk-JII7XSCT.cjs.map +1 -0
  45. package/dist/{chunk-HI6BUUIJ.js → chunk-KFPCZ7N3.js} +48 -14
  46. package/dist/chunk-KFPCZ7N3.js.map +1 -0
  47. package/dist/{chunk-W6DMHN33.js → chunk-LRWFU3KS.js} +10 -10
  48. package/dist/{chunk-W6DMHN33.js.map → chunk-LRWFU3KS.js.map} +1 -1
  49. package/dist/{chunk-G7AGM2Y7.js → chunk-LX4JI262.js} +4 -4
  50. package/dist/{chunk-G7AGM2Y7.js.map → chunk-LX4JI262.js.map} +1 -1
  51. package/dist/{chunk-IXMT7X3E.cjs → chunk-M4UJBLVR.cjs} +17 -6
  52. package/dist/chunk-M4UJBLVR.cjs.map +1 -0
  53. package/dist/{chunk-AHGB5HH6.cjs → chunk-NFGUJ52G.cjs} +19 -2
  54. package/dist/chunk-NFGUJ52G.cjs.map +1 -0
  55. package/dist/{chunk-PWLJDP3X.cjs → chunk-NP5YC4NV.cjs} +95 -27
  56. package/dist/chunk-NP5YC4NV.cjs.map +1 -0
  57. package/dist/{chunk-ZDYNAWDZ.cjs → chunk-OJGTJOWI.cjs} +2 -2
  58. package/dist/chunk-OJGTJOWI.cjs.map +1 -0
  59. package/dist/{chunk-ORBU3XKH.js → chunk-PJMXHDY5.js} +16 -5
  60. package/dist/chunk-PJMXHDY5.js.map +1 -0
  61. package/dist/{chunk-TRMWBJWT.cjs → chunk-PZVRZ6OX.cjs} +141 -10
  62. package/dist/chunk-PZVRZ6OX.cjs.map +1 -0
  63. package/dist/{chunk-QKW2GGTV.js → chunk-R4ZNFDTK.js} +84 -16
  64. package/dist/chunk-R4ZNFDTK.js.map +1 -0
  65. package/dist/{chunk-YNDKAYW3.js → chunk-RX3A6KIY.js} +2 -2
  66. package/dist/chunk-RX3A6KIY.js.map +1 -0
  67. package/dist/{chunk-UHIOVOFK.cjs → chunk-TQN5CJO6.cjs} +125 -32
  68. package/dist/chunk-TQN5CJO6.cjs.map +1 -0
  69. package/dist/{chunk-AQIAQHJC.js → chunk-TRXUZSOY.js} +138 -8
  70. package/dist/chunk-TRXUZSOY.js.map +1 -0
  71. package/dist/{chunk-WBLYD5QA.js → chunk-U4KTOH7C.js} +2 -2
  72. package/dist/chunk-U4KTOH7C.js.map +1 -0
  73. package/dist/{chunk-L7WY5YFQ.cjs → chunk-UKUHVCZX.cjs} +5 -5
  74. package/dist/{chunk-L7WY5YFQ.cjs.map → chunk-UKUHVCZX.cjs.map} +1 -1
  75. package/dist/{chunk-HREA5SMB.cjs → chunk-UWFJGFB6.cjs} +116 -47
  76. package/dist/chunk-UWFJGFB6.cjs.map +1 -0
  77. package/dist/{chunk-JLDSCHY5.cjs → chunk-UXTYFEIC.cjs} +150 -61
  78. package/dist/chunk-UXTYFEIC.cjs.map +1 -0
  79. package/dist/{chunk-5GI53C6T.js → chunk-V2QZM2P2.js} +109 -40
  80. package/dist/chunk-V2QZM2P2.js.map +1 -0
  81. package/dist/{chunk-6S2CKZ4H.cjs → chunk-WFGDKBBP.cjs} +145 -51
  82. package/dist/chunk-WFGDKBBP.cjs.map +1 -0
  83. package/dist/{chunk-APZ6JFN6.cjs → chunk-Y5H4NOM6.cjs} +5 -5
  84. package/dist/{chunk-APZ6JFN6.cjs.map → chunk-Y5H4NOM6.cjs.map} +1 -1
  85. package/dist/{chunk-IQ55QNBI.js → chunk-YIXO6C4Z.js} +125 -44
  86. package/dist/chunk-YIXO6C4Z.js.map +1 -0
  87. package/dist/{chunk-LK5VXNMR.cjs → chunk-ZUE32Z67.cjs} +18 -18
  88. package/dist/{chunk-LK5VXNMR.cjs.map → chunk-ZUE32Z67.cjs.map} +1 -1
  89. package/dist/components/ActivityPreview.cjs +17 -17
  90. package/dist/components/ActivityPreview.d.cts +2 -2
  91. package/dist/components/ActivityPreview.d.ts +2 -2
  92. package/dist/components/ActivityPreview.js +16 -16
  93. package/dist/components/ActivitySequence.cjs +18 -18
  94. package/dist/components/ActivitySequence.d.cts +22 -4
  95. package/dist/components/ActivitySequence.d.ts +22 -4
  96. package/dist/components/ActivitySequence.js +17 -17
  97. package/dist/components/Dictation.cjs +10 -10
  98. package/dist/components/Dictation.d.cts +1 -1
  99. package/dist/components/Dictation.d.ts +1 -1
  100. package/dist/components/Dictation.js +9 -9
  101. package/dist/components/FillInTheBlanks.cjs +10 -10
  102. package/dist/components/FillInTheBlanks.d.cts +1 -1
  103. package/dist/components/FillInTheBlanks.d.ts +1 -1
  104. package/dist/components/FillInTheBlanks.js +9 -9
  105. package/dist/components/GapSelect.cjs +10 -10
  106. package/dist/components/GapSelect.d.cts +1 -1
  107. package/dist/components/GapSelect.d.ts +1 -1
  108. package/dist/components/GapSelect.js +9 -9
  109. package/dist/components/InteractiveVideo.cjs +17 -17
  110. package/dist/components/InteractiveVideo.d.cts +19 -3
  111. package/dist/components/InteractiveVideo.d.ts +19 -3
  112. package/dist/components/InteractiveVideo.js +15 -15
  113. package/dist/components/MultipleChoice.cjs +10 -10
  114. package/dist/components/MultipleChoice.d.cts +1 -1
  115. package/dist/components/MultipleChoice.d.ts +1 -1
  116. package/dist/components/MultipleChoice.js +9 -9
  117. package/dist/components/PronunciationFeedback.cjs +4 -4
  118. package/dist/components/PronunciationFeedback.d.cts +1 -1
  119. package/dist/components/PronunciationFeedback.d.ts +1 -1
  120. package/dist/components/PronunciationFeedback.js +3 -3
  121. package/dist/components/ReadAloud.cjs +8 -8
  122. package/dist/components/ReadAloud.d.cts +2 -2
  123. package/dist/components/ReadAloud.d.ts +2 -2
  124. package/dist/components/ReadAloud.js +7 -7
  125. package/dist/components/StimulusPanel.cjs +4 -4
  126. package/dist/components/StimulusPanel.d.cts +1 -1
  127. package/dist/components/StimulusPanel.d.ts +1 -1
  128. package/dist/components/StimulusPanel.js +3 -3
  129. package/dist/components/WrittenResponse.cjs +9 -7
  130. package/dist/components/WrittenResponse.d.cts +3 -3
  131. package/dist/components/WrittenResponse.d.ts +3 -3
  132. package/dist/components/WrittenResponse.js +8 -6
  133. package/dist/i18n/LkIntlProvider.cjs +7 -7
  134. package/dist/i18n/LkIntlProvider.d.cts +2 -2
  135. package/dist/i18n/LkIntlProvider.d.ts +2 -2
  136. package/dist/i18n/LkIntlProvider.js +1 -1
  137. package/dist/index.cjs +45 -41
  138. package/dist/index.cjs.map +1 -1
  139. package/dist/index.d.cts +3 -3
  140. package/dist/index.d.ts +3 -3
  141. package/dist/index.js +19 -19
  142. package/dist/index.js.map +1 -1
  143. package/dist/theme/skin.css +78 -0
  144. package/dist/{types-B_PCcqO-.d.cts → types-CO0XLEN6.d.cts} +67 -1
  145. package/dist/{types-C-GMCJ0g.d.ts → types-CrtIcRcK.d.ts} +67 -1
  146. package/package.json +3 -3
  147. package/dist/chunk-3XP6VO4G.js.map +0 -1
  148. package/dist/chunk-5GI53C6T.js.map +0 -1
  149. package/dist/chunk-6S2CKZ4H.cjs.map +0 -1
  150. package/dist/chunk-AG7MWZYZ.js.map +0 -1
  151. package/dist/chunk-AHGB5HH6.cjs.map +0 -1
  152. package/dist/chunk-AQIAQHJC.js.map +0 -1
  153. package/dist/chunk-BGA2IVQY.js.map +0 -1
  154. package/dist/chunk-BJLQKJZX.cjs.map +0 -1
  155. package/dist/chunk-CEUEXISZ.cjs.map +0 -1
  156. package/dist/chunk-DZVF3IGB.cjs.map +0 -1
  157. package/dist/chunk-HI6BUUIJ.js.map +0 -1
  158. package/dist/chunk-HREA5SMB.cjs.map +0 -1
  159. package/dist/chunk-IQ55QNBI.js.map +0 -1
  160. package/dist/chunk-IXMT7X3E.cjs.map +0 -1
  161. package/dist/chunk-JLDSCHY5.cjs.map +0 -1
  162. package/dist/chunk-NOC2M6LU.cjs +0 -118
  163. package/dist/chunk-NOC2M6LU.cjs.map +0 -1
  164. package/dist/chunk-ORBU3XKH.js.map +0 -1
  165. package/dist/chunk-PWLJDP3X.cjs.map +0 -1
  166. package/dist/chunk-QKW2GGTV.js.map +0 -1
  167. package/dist/chunk-RUS42NMN.js +0 -115
  168. package/dist/chunk-RUS42NMN.js.map +0 -1
  169. package/dist/chunk-TRMWBJWT.cjs.map +0 -1
  170. package/dist/chunk-UHIOVOFK.cjs.map +0 -1
  171. package/dist/chunk-WBLYD5QA.js.map +0 -1
  172. package/dist/chunk-YNDKAYW3.js.map +0 -1
  173. package/dist/chunk-YRNEOBXA.js.map +0 -1
  174. package/dist/chunk-ZDYNAWDZ.cjs.map +0 -1
@@ -0,0 +1,241 @@
1
+ 'use client';
2
+ import { useAiExplanation, useAiHints } from './chunk-TRXUZSOY.js';
3
+ import { SequenceSlotContext } from './chunk-U4KTOH7C.js';
4
+ import { useRef, useEffect, useContext, useMemo, useState, useCallback } from 'react';
5
+ import { jsxs, jsx } from 'react/jsx-runtime';
6
+ import { resolveItemScoringPolicy, scoreTries } from '@intellectif/lk-core';
7
+
8
+ function situation(input) {
9
+ const { data, response, submitted, renderMode, ai, locale, onInteraction, delivery } = input;
10
+ return {
11
+ data,
12
+ response,
13
+ submitted,
14
+ renderMode,
15
+ delivery,
16
+ ...ai !== void 0 ? { ai } : {},
17
+ ...locale !== void 0 ? { locale } : {},
18
+ ...onInteraction !== void 0 ? { onInteraction } : {}
19
+ };
20
+ }
21
+ function AiExplanation({
22
+ outcome,
23
+ ...rest
24
+ }) {
25
+ const s = rest.strings;
26
+ const help = useAiExplanation({
27
+ ...situation(rest),
28
+ ...outcome !== void 0 ? { outcome } : {}
29
+ });
30
+ const buttonRef = useRef(null);
31
+ const panelRef = useRef(null);
32
+ const refocus = useRef(false);
33
+ useEffect(() => {
34
+ if (help.status === "shown" && refocus.current) {
35
+ refocus.current = false;
36
+ panelRef.current?.focus();
37
+ }
38
+ if (help.status === "unavailable") {
39
+ refocus.current = false;
40
+ }
41
+ }, [help.status]);
42
+ if (!help.offered) {
43
+ return null;
44
+ }
45
+ const ask = () => {
46
+ refocus.current = typeof document !== "undefined" && document.activeElement === buttonRef.current;
47
+ help.ask();
48
+ };
49
+ const loading = help.status === "loading";
50
+ return /* @__PURE__ */ jsxs("div", { className: "lk-ai", "data-state": help.status, children: [
51
+ help.explanation === null ? /* @__PURE__ */ jsx(
52
+ "button",
53
+ {
54
+ ref: buttonRef,
55
+ type: "button",
56
+ className: "lk-ai-button",
57
+ "aria-busy": loading || void 0,
58
+ "aria-disabled": loading || void 0,
59
+ onClick: ask,
60
+ children: loading ? s.aiExplaining : s.aiExplain
61
+ }
62
+ ) : null,
63
+ /* @__PURE__ */ jsx("div", { "aria-live": "polite", children: help.explanation !== null ? /* @__PURE__ */ jsxs(
64
+ "section",
65
+ {
66
+ ref: panelRef,
67
+ className: "lk-ai-panel",
68
+ tabIndex: -1,
69
+ "aria-label": s.aiExplanation,
70
+ children: [
71
+ /* @__PURE__ */ jsx("p", { className: "lk-ai-heading", children: s.aiExplanation }),
72
+ /* @__PURE__ */ jsx("p", { className: "lk-ai-text", children: help.explanation.text }),
73
+ /* @__PURE__ */ jsx("p", { className: "lk-ai-notice", children: s.aiNotice })
74
+ ]
75
+ }
76
+ ) : help.status === "unavailable" ? /* @__PURE__ */ jsx("p", { className: "lk-ai-unavailable", children: s.aiExplanationUnavailable }) : null })
77
+ ] });
78
+ }
79
+ function useComponentAiHints({
80
+ disabled,
81
+ ...rest
82
+ }) {
83
+ return useAiHints({ ...situation(rest), disabled });
84
+ }
85
+ function AiHints({
86
+ help,
87
+ ai,
88
+ strings: s
89
+ }) {
90
+ const used = help.used;
91
+ if (ai?.hint === void 0 || !help.offered && used === 0) {
92
+ return null;
93
+ }
94
+ const loading = help.status === "loading";
95
+ return /* @__PURE__ */ jsxs("div", { className: "lk-ai lk-ai-hint-area", "data-state": help.status, children: [
96
+ /* @__PURE__ */ jsxs("div", { "aria-live": "polite", children: [
97
+ used > 0 ? /* @__PURE__ */ jsx("ol", { className: "lk-ai-hints", "aria-label": s.aiHints, children: help.hints.map((hint, index) => (
98
+ // Hints are only ever appended, so a position is a stable key.
99
+ // biome-ignore lint/suspicious/noArrayIndexKey: an append-only list
100
+ /* @__PURE__ */ jsxs("li", { className: "lk-ai-hint", children: [
101
+ /* @__PURE__ */ jsx("span", { className: "lk-ai-hint-label", children: s.aiHintNumber(index + 1) }),
102
+ " ",
103
+ /* @__PURE__ */ jsx("span", { className: "lk-ai-text", children: hint.text })
104
+ ] }, index)
105
+ )) }) : null,
106
+ help.status === "unavailable" ? /* @__PURE__ */ jsx("p", { className: "lk-ai-unavailable", children: s.aiHintUnavailable }) : null
107
+ ] }),
108
+ help.offered ? used < help.limit ? /* @__PURE__ */ jsx(
109
+ "button",
110
+ {
111
+ type: "button",
112
+ className: "lk-ai-button",
113
+ "aria-busy": loading || void 0,
114
+ "aria-disabled": loading || void 0,
115
+ onClick: help.ask,
116
+ children: loading ? s.aiHintLoading : s.aiHint
117
+ }
118
+ ) : /* @__PURE__ */ jsx("p", { className: "lk-ai-note", children: s.aiNoMoreHints }) : null,
119
+ used > 0 ? /* @__PURE__ */ jsx("p", { className: "lk-ai-notice", children: s.aiNotice }) : null
120
+ ] });
121
+ }
122
+ function useItemScoringPolicy(given) {
123
+ const around = useContext(SequenceSlotContext)?.scoring;
124
+ const key = policyKey(given);
125
+ const own = useMemo(
126
+ () => around === void 0 ? resolveItemScoringPolicy(given) : null,
127
+ [around, key]
128
+ );
129
+ return around ?? own;
130
+ }
131
+ function policyKey(given) {
132
+ try {
133
+ return JSON.stringify(given) ?? "";
134
+ } catch {
135
+ return String(given);
136
+ }
137
+ }
138
+ function hintsOf(response) {
139
+ const count = response?.hintsRevealed;
140
+ return typeof count === "number" && Number.isSafeInteger(count) && count > 0 ? count : 0;
141
+ }
142
+ var fullMarks = (one) => one.score / one.maxScore >= 1 - 1e-9;
143
+ function offersAfter(now, made, shut) {
144
+ const last = made[made.length - 1];
145
+ return now.graded && !now.disabled && !shut && now.channel?.triesClosed !== true && last !== void 0 && made.length < 1 + now.policy.retries && !fullMarks(last);
146
+ }
147
+ function useTries({ policy, graded, submitted, disabled }) {
148
+ const channel = useContext(SequenceSlotContext);
149
+ const [tries, setTries] = useState([]);
150
+ const [closed, setClosed] = useState(false);
151
+ const triesRef = useRef([]);
152
+ const closedRef = useRef(false);
153
+ const latest = useRef({ policy, graded, disabled, channel });
154
+ latest.current = { policy, graded, disabled, channel };
155
+ const record = useCallback((one) => {
156
+ const next = [...triesRef.current, one];
157
+ triesRef.current = next;
158
+ setTries(next);
159
+ if (offersAfter(latest.current, next, closedRef.current)) {
160
+ latest.current.channel?.triesState("offered");
161
+ }
162
+ return scoreTries(next, latest.current.policy);
163
+ }, []);
164
+ const close = useCallback(() => {
165
+ closedRef.current = true;
166
+ setClosed(true);
167
+ }, []);
168
+ const reset = useCallback(() => {
169
+ triesRef.current = [];
170
+ closedRef.current = false;
171
+ setTries([]);
172
+ setClosed(false);
173
+ }, []);
174
+ const allowed = 1 + policy.retries;
175
+ const left = Math.max(0, allowed - tries.length);
176
+ const open = submitted && offersAfter(latest.current, tries, closed);
177
+ const retrying = !submitted && tries.length > 0 && !closed && graded && !disabled && channel?.triesClosed !== true;
178
+ const state = open ? "offered" : retrying ? "retrying" : "none";
179
+ const report = channel?.triesState;
180
+ useEffect(() => {
181
+ report?.(state);
182
+ }, [report, state]);
183
+ useEffect(() => () => report?.("none"), [report]);
184
+ const counted = useMemo(
185
+ () => tries.length === 0 ? null : scoreTries(tries, policy),
186
+ [tries, policy]
187
+ );
188
+ return { tries, counted, open, left, record, close, reset };
189
+ }
190
+ var percentOf = (fraction) => Math.round(fraction * 100);
191
+ function triesSummary(s, policy, counted, offered) {
192
+ const parts = [];
193
+ const latest = counted.tries.length - 1;
194
+ const mine = counted.tries[latest];
195
+ if (mine !== void 0) {
196
+ if (counted.counted !== latest) {
197
+ parts.push(
198
+ s.countedTry(
199
+ policy.counts === "best" ? "best" : "first",
200
+ percentOf(mine.scored / mine.maxScore)
201
+ )
202
+ );
203
+ } else if (mine.scored !== mine.score) {
204
+ parts.push(s.scoreBeforeCosts(percentOf(mine.score / mine.maxScore)));
205
+ }
206
+ }
207
+ if (offered) {
208
+ parts.push(
209
+ s.triesLeft(policy.retries + 1 - counted.tries.length, percentOf(policy.retryPenalty))
210
+ );
211
+ }
212
+ return parts.join(" ");
213
+ }
214
+ function TryActions({
215
+ tries,
216
+ solutions,
217
+ strings: s,
218
+ onRetry,
219
+ onClose
220
+ }) {
221
+ if (!tries.open) {
222
+ return null;
223
+ }
224
+ return /* @__PURE__ */ jsxs("div", { className: "lk-tries", children: [
225
+ /* @__PURE__ */ jsx("button", { type: "button", className: "lk-tries-again", onClick: onRetry, children: s.tryAgain }),
226
+ /* @__PURE__ */ jsx("button", { type: "button", className: "lk-tries-close", onClick: onClose, children: solutions ? s.showAnswer : s.keepAnswer })
227
+ ] });
228
+ }
229
+ function HintCost({
230
+ policy,
231
+ strings: s
232
+ }) {
233
+ if (policy.hintPenalty <= 0) {
234
+ return null;
235
+ }
236
+ return /* @__PURE__ */ jsx("p", { className: "lk-hint-cost", children: s.hintCost(percentOf(policy.hintPenalty)) });
237
+ }
238
+
239
+ export { AiExplanation, AiHints, HintCost, TryActions, hintsOf, triesSummary, useComponentAiHints, useItemScoringPolicy, useTries };
240
+ //# sourceMappingURL=chunk-7EEKZWTQ.js.map
241
+ //# sourceMappingURL=chunk-7EEKZWTQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/shared/AiHelp.tsx","../src/components/shared/tries.tsx"],"names":["useRef","useEffect","jsxs","jsx"],"mappings":"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","file":"chunk-7EEKZWTQ.js","sourcesContent":["'use client';\n\nimport type {\n InteractionEvent,\n ItemOutcome,\n LearnerResponse,\n ResolvedDeliveryPolicy,\n} from '@intellectif/lk-core';\nimport { useEffect, useRef } from 'react';\nimport type { LearnerAi } from '../../ai/LkAiProvider.js';\nimport { type AiHintsHelp, useAiExplanation, useAiHints } from '../../ai/useAiHelp.js';\nimport type { LkStrings } from '../../i18n/strings.js';\nimport type { RenderableActivity, RenderMode } from '../types.js';\n\ninterface Situation {\n ai: LearnerAi | undefined;\n data: RenderableActivity;\n renderMode: RenderMode;\n submitted: boolean;\n /** The learner's answer as it stands: submitted, restored, or being written. */\n response: LearnerResponse;\n /** The component's `locale`, the default language for what is written. */\n locale: string | undefined;\n onInteraction: ((event: InteractionEvent) => void) | undefined;\n strings: LkStrings;\n /** The policy the component resolved, the paper's included. */\n delivery: ResolvedDeliveryPolicy;\n}\n\n/** What the hooks take, from what a component holds: the optional half, without `undefined` values. */\nfunction situation(input: Situation): {\n data: RenderableActivity;\n response: LearnerResponse;\n submitted: boolean;\n renderMode: RenderMode;\n ai?: LearnerAi;\n locale?: string;\n onInteraction?: (event: InteractionEvent) => void;\n delivery: ResolvedDeliveryPolicy;\n} {\n const { data, response, submitted, renderMode, ai, locale, onInteraction, delivery } = input;\n return {\n data,\n response,\n submitted,\n renderMode,\n delivery,\n ...(ai !== undefined ? { ai } : {}),\n ...(locale !== undefined ? { locale } : {}),\n ...(onInteraction !== undefined ? { onInteraction } : {}),\n };\n}\n\n/**\n * \"Explain my answer\": the SDK's own surface over {@link useAiExplanation} — a\n * button, the explanation with who wrote it, and \"not available\" when a call\n * fails or its answer is refused.\n *\n * Nothing renders without a port, or where the rules say no explanation.\n */\nexport function AiExplanation({\n outcome,\n ...rest\n}: Situation & { outcome: ItemOutcome | undefined }) {\n const s = rest.strings;\n const help = useAiExplanation({\n ...situation(rest),\n ...(outcome !== undefined ? { outcome } : {}),\n });\n const buttonRef = useRef<HTMLButtonElement>(null);\n const panelRef = useRef<HTMLElement>(null);\n const refocus = useRef(false);\n\n // The button that asked goes away when the explanation arrives; focus moves\n // to what it asked for rather than falling to the page.\n useEffect(() => {\n if (help.status === 'shown' && refocus.current) {\n refocus.current = false;\n panelRef.current?.focus();\n }\n if (help.status === 'unavailable') {\n refocus.current = false;\n }\n }, [help.status]);\n\n if (!help.offered) {\n return null;\n }\n\n const ask = (): void => {\n refocus.current =\n typeof document !== 'undefined' && document.activeElement === buttonRef.current;\n help.ask();\n };\n\n const loading = help.status === 'loading';\n return (\n <div className=\"lk-ai\" data-state={help.status}>\n {help.explanation === null ? (\n <button\n ref={buttonRef}\n type=\"button\"\n className=\"lk-ai-button\"\n aria-busy={loading || undefined}\n aria-disabled={loading || undefined}\n onClick={ask}\n >\n {loading ? s.aiExplaining : s.aiExplain}\n </button>\n ) : null}\n <div aria-live=\"polite\">\n {help.explanation !== null ? (\n <section\n ref={panelRef}\n className=\"lk-ai-panel\"\n tabIndex={-1}\n aria-label={s.aiExplanation}\n >\n <p className=\"lk-ai-heading\">{s.aiExplanation}</p>\n <p className=\"lk-ai-text\">{help.explanation.text}</p>\n <p className=\"lk-ai-notice\">{s.aiNotice}</p>\n </section>\n ) : help.status === 'unavailable' ? (\n <p className=\"lk-ai-unavailable\">{s.aiExplanationUnavailable}</p>\n ) : null}\n </div>\n </div>\n );\n}\n\n/**\n * The AI hints of one of the SDK's own questions: {@link useAiHints}, called\n * by the component itself so it can count the hints its learner was shown.\n */\nexport function useComponentAiHints({\n disabled,\n ...rest\n}: Situation & { disabled: boolean }): AiHintsHelp {\n return useAiHints({ ...situation(rest), disabled });\n}\n\n/**\n * \"Get a hint\": the SDK's own surface over {@link useAiHints} — a button, the\n * hints given so far as a numbered list, and who wrote them.\n *\n * The hints stay listed after submit, so the learner can see what they were\n * given, but no more can be asked for — until a \"Try again\" reopens the\n * answer, when the same list carries on. Another question starts with none.\n */\nexport function AiHints({\n help,\n ai,\n strings: s,\n}: {\n help: AiHintsHelp;\n ai: LearnerAi | undefined;\n strings: LkStrings;\n}) {\n const used = help.used;\n\n if (ai?.hint === undefined || (!help.offered && used === 0)) {\n return null;\n }\n\n const loading = help.status === 'loading';\n return (\n <div className=\"lk-ai lk-ai-hint-area\" data-state={help.status}>\n <div aria-live=\"polite\">\n {used > 0 ? (\n <ol className=\"lk-ai-hints\" aria-label={s.aiHints}>\n {help.hints.map((hint, index) => (\n // Hints are only ever appended, so a position is a stable key.\n // biome-ignore lint/suspicious/noArrayIndexKey: an append-only list\n <li key={index} className=\"lk-ai-hint\">\n <span className=\"lk-ai-hint-label\">{s.aiHintNumber(index + 1)}</span>{' '}\n <span className=\"lk-ai-text\">{hint.text}</span>\n </li>\n ))}\n </ol>\n ) : null}\n {help.status === 'unavailable' ? (\n <p className=\"lk-ai-unavailable\">{s.aiHintUnavailable}</p>\n ) : null}\n </div>\n {help.offered ? (\n used < help.limit ? (\n <button\n type=\"button\"\n className=\"lk-ai-button\"\n aria-busy={loading || undefined}\n aria-disabled={loading || undefined}\n onClick={help.ask}\n >\n {loading ? s.aiHintLoading : s.aiHint}\n </button>\n ) : (\n <p className=\"lk-ai-note\">{s.aiNoMoreHints}</p>\n )\n ) : null}\n {used > 0 ? <p className=\"lk-ai-notice\">{s.aiNotice}</p> : null}\n </div>\n );\n}\n","'use client';\n\nimport {\n type ItemScoringPolicy,\n type ItemTriesScore,\n type ItemTry,\n type ResolvedItemScoringPolicy,\n resolveItemScoringPolicy,\n scoreTries,\n} from '@intellectif/lk-core';\nimport { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';\nimport type { LkStrings } from '../../i18n/strings.js';\nimport { SequenceSlotContext, type TriesState } from './sequence-slot.js';\n\n/**\n * The scoring policy a question is under: the paper's, when the paper around\n * it was given one, else its own.\n *\n * Not combined, as delivery policies are: a cost and a count of tries have no\n * \"stricter\" to pick. The paper decides, as it decides the mode — so a\n * question drawn inside a set is scored by the set's rules whatever it was\n * handed.\n *\n * A policy `validateItemScoringPolicy` refuses throws here, at render. Every\n * setting in it moves a grade, and there is no safe way to read one wrongly:\n * the question fails loudly rather than grade by a guess.\n */\nexport function useItemScoringPolicy(\n given: ItemScoringPolicy | null | undefined,\n): ResolvedItemScoringPolicy {\n const around = useContext(SequenceSlotContext)?.scoring;\n const key = policyKey(given);\n // biome-ignore lint/correctness/useExhaustiveDependencies: the policy's content is the trigger, not its identity\n const own = useMemo(\n () => (around === undefined ? resolveItemScoringPolicy(given) : null),\n [around, key],\n );\n return around ?? (own as ResolvedItemScoringPolicy);\n}\n\nfunction policyKey(given: unknown): string {\n try {\n return JSON.stringify(given) ?? '';\n } catch {\n return String(given);\n }\n}\n\n/** A hint count as a response carries it: anything but a whole number above 0 is none. */\nexport function hintsOf(response: unknown): number {\n const count = (response as { hintsRevealed?: unknown } | null | undefined)?.hintsRevealed;\n return typeof count === 'number' && Number.isSafeInteger(count) && count > 0 ? count : 0;\n}\n\n/** Whether a try earned every mark there was: float noise above the maximum included. */\nconst fullMarks = (one: ItemTry): boolean => one.score / one.maxScore >= 1 - 1e-9;\n\n/** Whether, after the tries `made`, a question offers another: the rule `open` reads. */\nfunction offersAfter(\n now: {\n policy: ResolvedItemScoringPolicy;\n graded: boolean;\n disabled: boolean;\n channel: { triesClosed: boolean } | null;\n },\n made: readonly ItemTry[],\n shut: boolean,\n): boolean {\n const last = made[made.length - 1];\n return (\n now.graded &&\n !now.disabled &&\n !shut &&\n now.channel?.triesClosed !== true &&\n last !== undefined &&\n made.length < 1 + now.policy.retries &&\n !fullMarks(last)\n );\n}\n\nexport interface TriesInput {\n policy: ResolvedItemScoringPolicy;\n /**\n * Whether the component grades this answer itself and the learner may see\n * how it went: `practice`, with `feedback` on. \"Try again\" anywhere else\n * would be meaningless, or would say an answer was wrong on a paper that\n * does not say so.\n */\n graded: boolean;\n submitted: boolean;\n disabled: boolean;\n}\n\nexport interface Tries {\n /** Every graded try so far, in order. */\n tries: readonly ItemTry[];\n /** The question's score under the policy, once a try has been graded. */\n counted: ItemTriesScore | null;\n /**\n * Whether the learner is being offered another try at a graded answer: the\n * last try earned less than full marks, the policy has tries left, and\n * nothing has closed the question. While it is, the question shows no right\n * answer and no explanation — either would hand over the answer the next try\n * is for.\n */\n open: boolean;\n /** Tries still to come after the last graded one. */\n left: number;\n /** Records a graded try and returns the question's score under the policy. */\n record: (graded: ItemTry) => ItemTriesScore;\n /** Ends the question's tries: \"Show answer\". */\n close: () => void;\n /** Forgets every try: a different question. */\n reset: () => void;\n}\n\n/**\n * The tries a question has had and whether it offers another: the SDK's own\n * components' rules for \"Try again\", in one place.\n *\n * Reports whether a try is on offer to the paper around the question, which\n * waits for it before reporting the set while the question is on screen — and\n * closes every question's tries once it has reported.\n */\nexport function useTries({ policy, graded, submitted, disabled }: TriesInput): Tries {\n const channel = useContext(SequenceSlotContext);\n const [tries, setTries] = useState<readonly ItemTry[]>([]);\n const [closed, setClosed] = useState(false);\n // Written synchronously, so a submit that records a try and reports it reads\n // every try before it, whatever React has rendered.\n const triesRef = useRef<readonly ItemTry[]>([]);\n const closedRef = useRef(false);\n const latest = useRef({ policy, graded, disabled, channel });\n latest.current = { policy, graded, disabled, channel };\n\n const record = useCallback((one: ItemTry): ItemTriesScore => {\n const next = [...triesRef.current, one];\n triesRef.current = next;\n setTries(next);\n // An offer of another try is reported before the grade is handed on, not\n // after the next render: the paper reports its set when a grade fills its\n // last slot, and must already know to wait. The end of the tries is not:\n // said now, it would let the paper report the grade this try is replacing.\n // The effect below says it once this grade has landed.\n if (offersAfter(latest.current, next, closedRef.current)) {\n latest.current.channel?.triesState('offered');\n }\n return scoreTries(next, latest.current.policy);\n }, []);\n const close = useCallback(() => {\n closedRef.current = true;\n setClosed(true);\n }, []);\n const reset = useCallback(() => {\n triesRef.current = [];\n closedRef.current = false;\n setTries([]);\n setClosed(false);\n }, []);\n\n const allowed = 1 + policy.retries;\n const left = Math.max(0, allowed - tries.length);\n const open = submitted && offersAfter(latest.current, tries, closed);\n // A try the learner is making now — after \"Try again\", before the answer is\n // in again. Reporting the set then would hand on the grade the learner is in\n // the middle of replacing.\n const retrying =\n !submitted &&\n tries.length > 0 &&\n !closed &&\n graded &&\n !disabled &&\n channel?.triesClosed !== true;\n const state: TriesState = open ? 'offered' : retrying ? 'retrying' : 'none';\n\n const report = channel?.triesState;\n useEffect(() => {\n report?.(state);\n }, [report, state]);\n // A question that goes away offers nothing: the paper must not wait for it.\n useEffect(() => () => report?.('none'), [report]);\n\n const counted = useMemo(\n () => (tries.length === 0 ? null : scoreTries(tries, policy)),\n [tries, policy],\n );\n return { tries, counted, open, left, record, close, reset };\n}\n\n/** A fraction of the marks as the whole percentage a learner reads. */\nexport const percentOf = (fraction: number): number => Math.round(fraction * 100);\n\n/**\n * The sentences after the score, on a question whose policy changed it: which\n * try counts when it is not the one just made, what this answer scored before\n * its costs, and how many tries are left.\n */\nexport function triesSummary(\n s: LkStrings,\n policy: ResolvedItemScoringPolicy,\n counted: ItemTriesScore,\n offered: boolean,\n): string {\n const parts: string[] = [];\n const latest = counted.tries.length - 1;\n const mine = counted.tries[latest];\n if (mine !== undefined) {\n if (counted.counted !== latest) {\n parts.push(\n s.countedTry(\n policy.counts === 'best' ? 'best' : 'first',\n percentOf(mine.scored / mine.maxScore),\n ),\n );\n } else if (mine.scored !== mine.score) {\n parts.push(s.scoreBeforeCosts(percentOf(mine.score / mine.maxScore)));\n }\n }\n if (offered) {\n parts.push(\n s.triesLeft(policy.retries + 1 - counted.tries.length, percentOf(policy.retryPenalty)),\n );\n }\n return parts.join(' ');\n}\n\n/**\n * \"Try again\" and \"Show answer\" — or \"Keep this answer\", on a paper that shows\n * no right answers — after a graded try that did not earn full marks.\n */\nexport function TryActions({\n tries,\n solutions,\n strings: s,\n onRetry,\n onClose,\n}: {\n tries: Tries;\n /** Whether closing the question will show the right answer. */\n solutions: boolean;\n strings: LkStrings;\n onRetry: () => void;\n onClose: () => void;\n}): React.JSX.Element | null {\n if (!tries.open) {\n return null;\n }\n return (\n <div className=\"lk-tries\">\n <button type=\"button\" className=\"lk-tries-again\" onClick={onRetry}>\n {s.tryAgain}\n </button>\n <button type=\"button\" className=\"lk-tries-close\" onClick={onClose}>\n {solutions ? s.showAnswer : s.keepAnswer}\n </button>\n </div>\n );\n}\n\n/** What a hint costs, said before the learner asks for one. */\nexport function HintCost({\n policy,\n strings: s,\n}: {\n policy: ResolvedItemScoringPolicy;\n strings: LkStrings;\n}): React.JSX.Element | null {\n if (policy.hintPenalty <= 0) {\n return null;\n }\n return <p className=\"lk-hint-cost\">{s.hintCost(percentOf(policy.hintPenalty))}</p>;\n}\n"]}
@@ -1,8 +1,8 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
- var chunkL7WY5YFQ_cjs = require('./chunk-L7WY5YFQ.cjs');
5
- var chunkAHGB5HH6_cjs = require('./chunk-AHGB5HH6.cjs');
4
+ var chunkUKUHVCZX_cjs = require('./chunk-UKUHVCZX.cjs');
5
+ var chunkNFGUJ52G_cjs = require('./chunk-NFGUJ52G.cjs');
6
6
  var react = require('react');
7
7
  var jsxRuntime = require('react/jsx-runtime');
8
8
 
@@ -19,7 +19,7 @@ function StimulusPanel({
19
19
  strings
20
20
  }) {
21
21
  const titleId = react.useId();
22
- const s = chunkAHGB5HH6_cjs.useLkStrings(strings);
22
+ const s = chunkNFGUJ52G_cjs.useLkStrings(strings);
23
23
  const bodyHtml = react.useMemo(() => {
24
24
  if (sanitizeHtml === void 0 || typeof stimulus.bodyHtml !== "string") {
25
25
  return null;
@@ -33,7 +33,7 @@ function StimulusPanel({
33
33
  stimulus.title !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "lk-stimulus-title", id: titleId, ...contentLang, children: stimulus.title }) : null,
34
34
  rangeText !== null ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "lk-stimulus-range", children: rangeText }) : null,
35
35
  stimulus.media !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
36
- chunkL7WY5YFQ_cjs.ActivityMedia,
36
+ chunkUKUHVCZX_cjs.ActivityMedia,
37
37
  {
38
38
  media: stimulus.media,
39
39
  ...renderMode !== void 0 ? { renderMode } : {},
@@ -59,5 +59,5 @@ function StimulusPanel({
59
59
  }
60
60
 
61
61
  exports.StimulusPanel = StimulusPanel;
62
- //# sourceMappingURL=chunk-3FBBP5QR.cjs.map
63
- //# sourceMappingURL=chunk-3FBBP5QR.cjs.map
62
+ //# sourceMappingURL=chunk-B4JRBV56.cjs.map
63
+ //# sourceMappingURL=chunk-B4JRBV56.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/StimulusPanel/StimulusPanel.tsx"],"names":["useId","useLkStrings","useMemo","jsxs","jsx","ActivityMedia"],"mappings":"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","file":"chunk-3FBBP5QR.cjs","sourcesContent":["'use client';\n\nimport type { InteractionEvent, Stimulus } from '@intellectif/lk-core';\nimport { useId, useMemo } from 'react';\nimport { useLkStrings } from '../../i18n/LkIntlProvider.js';\nimport type { LkStringsOverride } from '../../i18n/strings.js';\nimport { ActivityMedia } from '../shared/ActivityMedia.js';\nimport type {\n HtmlSanitizer,\n MediaBudgetBinding,\n MediaTransportStrings,\n RenderMode,\n} from '../types.js';\n\nexport interface StimulusPanelProps {\n stimulus: Stimulus;\n /**\n * 1-based presented positions of the first and last question this material\n * serves, rendered as \"Questions 3–8\" so a learner knows how far the\n * passage carries.\n */\n range?: { first: number; last: number };\n /** Renders `stimulus.bodyHtml` when provided. See `HtmlSanitizer`. */\n sanitizeHtml?: HtmlSanitizer;\n locale?: string;\n /**\n * Forwarded to the stimulus's own media. `review` keeps the browser's control\n * bar even under an enforcing policy — a graded paper cannot be changed by\n * listening again.\n */\n renderMode?: RenderMode;\n /**\n * Binds this group's recording to a play budget the consumer persists. One\n * recording serves every question in the group, so the key is derived from\n * the ENTRY rather than the slot — see `stimulusMediaKey()` in lk-core.\n */\n mediaBudget?: MediaBudgetBinding;\n /** Translations for the audio transport chrome. */\n mediaStrings?: Partial<MediaTransportStrings>;\n onInteraction?: (event: InteractionEvent) => void;\n disabled?: boolean;\n /** Overrides the SDK's chrome text for this panel. See {@link LkIntlProvider}. */\n strings?: LkStringsOverride;\n}\n\n/**\n * Presents a shared stimulus — the passage, recording or image an item group's\n * questions refer to. A landmark region named by its title (or by its kind),\n * so a screen-reader user can jump back to the material from any question.\n *\n * Rich text follows the SDK-wide rule: `bodyHtml` is rendered only through a\n * caller-supplied sanitiser, and the plain `body` is the fallback — which the\n * schema guarantees exists whenever `bodyHtml` does.\n */\nexport function StimulusPanel({\n stimulus,\n range,\n sanitizeHtml,\n locale,\n renderMode,\n mediaBudget,\n mediaStrings,\n onInteraction,\n disabled,\n strings,\n}: StimulusPanelProps): React.JSX.Element {\n const titleId = useId();\n const s = useLkStrings(strings);\n\n const bodyHtml = useMemo(() => {\n if (sanitizeHtml === undefined || typeof stimulus.bodyHtml !== 'string') {\n return null;\n }\n return sanitizeHtml(stimulus.bodyHtml);\n }, [stimulus.bodyHtml, sanitizeHtml]);\n\n const rangeText = range === undefined ? null : s.stimulusRange(range.first, range.last);\n\n const naming =\n stimulus.title !== undefined\n ? { 'aria-labelledby': titleId }\n : { 'aria-label': s.stimulusKind[stimulus.kind] };\n\n // The AUTHORED parts carry the stimulus language; the SDK's own chrome does\n // not. Declaring `stimulus.locale` on the whole region made a screen reader\n // read \"Recording\" and \"Questions 3–5\" — English strings this package ships\n // — in the passage's voice, so a Spanish listening panel announced its own\n // name and the only orientation text in it with Spanish phonetics\n // (WCAG 3.1.2 Language of Parts). Scope the declaration to the content it\n // actually describes.\n const contentLang = stimulus.locale !== undefined ? { lang: stimulus.locale } : {};\n\n return (\n <section className=\"lk-stimulus\" data-kind={stimulus.kind} lang={locale} {...naming}>\n {stimulus.title !== undefined ? (\n <p className=\"lk-stimulus-title\" id={titleId} {...contentLang}>\n {stimulus.title}\n </p>\n ) : null}\n {rangeText !== null ? <p className=\"lk-stimulus-range\">{rangeText}</p> : null}\n {stimulus.media !== undefined ? (\n <ActivityMedia\n media={stimulus.media}\n {...(renderMode !== undefined ? { renderMode } : {})}\n {...(mediaBudget !== undefined ? { mediaBudget } : {})}\n {...(mediaStrings !== undefined ? { mediaStrings } : {})}\n {...(strings !== undefined ? { strings } : {})}\n {...(onInteraction !== undefined ? { onInteraction } : {})}\n {...(disabled !== undefined ? { disabled } : {})}\n {...(locale !== undefined ? { locale } : {})}\n />\n ) : null}\n {bodyHtml !== null ? (\n <div\n className=\"lk-stimulus-body\"\n data-format=\"html\"\n {...contentLang}\n // biome-ignore lint/security/noDangerouslySetInnerHtml: rendered only through the caller-supplied HtmlSanitizer — the SDK never injects unsanitised markup\n dangerouslySetInnerHTML={{ __html: bodyHtml }}\n />\n ) : stimulus.body !== undefined ? (\n <div className=\"lk-stimulus-body\" data-format=\"text\" {...contentLang}>\n {stimulus.body}\n </div>\n ) : null}\n {stimulus.attribution !== undefined ? (\n <p className=\"lk-stimulus-attribution\" {...contentLang}>\n <cite>{stimulus.attribution}</cite>\n </p>\n ) : null}\n </section>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/components/StimulusPanel/StimulusPanel.tsx"],"names":["useId","useLkStrings","useMemo","jsxs","jsx","ActivityMedia"],"mappings":";;;;;;;AAsDO,SAAS,aAAA,CAAc;AAAA,EAC5B,QAAA;AAAA,EACA,KAAA;AAAA,EACA,YAAA;AAAA,EACA,MAAA;AAAA,EACA,UAAA;AAAA,EACA,WAAA;AAAA,EACA,YAAA;AAAA,EACA,aAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA,EAA0C;AACxC,EAAA,MAAM,UAAUA,WAAA,EAAM;AACtB,EAAA,MAAM,CAAA,GAAIC,+BAAa,OAAO,CAAA;AAE9B,EAAA,MAAM,QAAA,GAAWC,cAAQ,MAAM;AAC7B,IAAA,IAAI,YAAA,KAAiB,MAAA,IAAa,OAAO,QAAA,CAAS,aAAa,QAAA,EAAU;AACvE,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,OAAO,YAAA,CAAa,SAAS,QAAQ,CAAA;AAAA,EACvC,CAAA,EAAG,CAAC,QAAA,CAAS,QAAA,EAAU,YAAY,CAAC,CAAA;AAEpC,EAAA,MAAM,SAAA,GAAY,UAAU,MAAA,GAAY,IAAA,GAAO,EAAE,aAAA,CAAc,KAAA,CAAM,KAAA,EAAO,KAAA,CAAM,IAAI,CAAA;AAEtF,EAAA,MAAM,MAAA,GACJ,QAAA,CAAS,KAAA,KAAU,MAAA,GACf,EAAE,iBAAA,EAAmB,OAAA,EAAQ,GAC7B,EAAE,YAAA,EAAc,CAAA,CAAE,YAAA,CAAa,QAAA,CAAS,IAAI,CAAA,EAAE;AASpD,EAAA,MAAM,WAAA,GAAc,SAAS,MAAA,KAAW,MAAA,GAAY,EAAE,IAAA,EAAM,QAAA,CAAS,MAAA,EAAO,GAAI,EAAC;AAEjF,EAAA,uBACEC,eAAA,CAAC,SAAA,EAAA,EAAQ,SAAA,EAAU,aAAA,EAAc,WAAA,EAAW,SAAS,IAAA,EAAM,IAAA,EAAM,MAAA,EAAS,GAAG,MAAA,EAC1E,QAAA,EAAA;AAAA,IAAA,QAAA,CAAS,KAAA,KAAU,MAAA,mBAClBC,cAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,mBAAA,EAAoB,EAAA,EAAI,OAAA,EAAU,GAAG,WAAA,EAC/C,QAAA,EAAA,QAAA,CAAS,KAAA,EACZ,CAAA,GACE,IAAA;AAAA,IACH,cAAc,IAAA,mBAAOA,cAAA,CAAC,OAAE,SAAA,EAAU,mBAAA,EAAqB,qBAAU,CAAA,GAAO,IAAA;AAAA,IACxE,QAAA,CAAS,UAAU,MAAA,mBAClBA,cAAA;AAAA,MAACC,+BAAA;AAAA,MAAA;AAAA,QACC,OAAO,QAAA,CAAS,KAAA;AAAA,QACf,GAAI,UAAA,KAAe,MAAA,GAAY,EAAE,UAAA,KAAe,EAAC;AAAA,QACjD,GAAI,WAAA,KAAgB,MAAA,GAAY,EAAE,WAAA,KAAgB,EAAC;AAAA,QACnD,GAAI,YAAA,KAAiB,MAAA,GAAY,EAAE,YAAA,KAAiB,EAAC;AAAA,QACrD,GAAI,OAAA,KAAY,MAAA,GAAY,EAAE,OAAA,KAAY,EAAC;AAAA,QAC3C,GAAI,aAAA,KAAkB,MAAA,GAAY,EAAE,aAAA,KAAkB,EAAC;AAAA,QACvD,GAAI,QAAA,KAAa,MAAA,GAAY,EAAE,QAAA,KAAa,EAAC;AAAA,QAC7C,GAAI,MAAA,KAAW,MAAA,GAAY,EAAE,MAAA,KAAW;AAAC;AAAA,KAC5C,GACE,IAAA;AAAA,IACH,aAAa,IAAA,mBACZD,cAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAU,kBAAA;AAAA,QACV,aAAA,EAAY,MAAA;AAAA,QACX,GAAG,WAAA;AAAA,QAEJ,uBAAA,EAAyB,EAAE,MAAA,EAAQ,QAAA;AAAS;AAAA,KAC9C,GACE,QAAA,CAAS,IAAA,KAAS,MAAA,kCACnB,KAAA,EAAA,EAAI,SAAA,EAAU,kBAAA,EAAmB,aAAA,EAAY,MAAA,EAAQ,GAAG,WAAA,EACtD,QAAA,EAAA,QAAA,CAAS,MACZ,CAAA,GACE,IAAA;AAAA,IACH,QAAA,CAAS,WAAA,KAAgB,MAAA,mBACxBA,cAAA,CAAC,OAAE,SAAA,EAAU,yBAAA,EAA2B,GAAG,WAAA,EACzC,QAAA,kBAAAA,cAAA,CAAC,MAAA,EAAA,EAAM,QAAA,EAAA,QAAA,CAAS,WAAA,EAAY,GAC9B,CAAA,GACE;AAAA,GAAA,EACN,CAAA;AAEJ","file":"chunk-B4JRBV56.cjs","sourcesContent":["'use client';\n\nimport type { InteractionEvent, Stimulus } from '@intellectif/lk-core';\nimport { useId, useMemo } from 'react';\nimport { useLkStrings } from '../../i18n/LkIntlProvider.js';\nimport type { LkStringsOverride } from '../../i18n/strings.js';\nimport { ActivityMedia } from '../shared/ActivityMedia.js';\nimport type {\n HtmlSanitizer,\n MediaBudgetBinding,\n MediaTransportStrings,\n RenderMode,\n} from '../types.js';\n\nexport interface StimulusPanelProps {\n stimulus: Stimulus;\n /**\n * 1-based presented positions of the first and last question this material\n * serves, rendered as \"Questions 3–8\" so a learner knows how far the\n * passage carries.\n */\n range?: { first: number; last: number };\n /** Renders `stimulus.bodyHtml` when provided. See `HtmlSanitizer`. */\n sanitizeHtml?: HtmlSanitizer;\n locale?: string;\n /**\n * Forwarded to the stimulus's own media. `review` keeps the browser's control\n * bar even under an enforcing policy — a graded paper cannot be changed by\n * listening again.\n */\n renderMode?: RenderMode;\n /**\n * Binds this group's recording to a play budget the consumer persists. One\n * recording serves every question in the group, so the key is derived from\n * the ENTRY rather than the slot — see `stimulusMediaKey()` in lk-core.\n */\n mediaBudget?: MediaBudgetBinding;\n /** Translations for the audio transport chrome. */\n mediaStrings?: Partial<MediaTransportStrings>;\n onInteraction?: (event: InteractionEvent) => void;\n disabled?: boolean;\n /** Overrides the SDK's chrome text for this panel. See {@link LkIntlProvider}. */\n strings?: LkStringsOverride;\n}\n\n/**\n * Presents a shared stimulus — the passage, recording or image an item group's\n * questions refer to. A landmark region named by its title (or by its kind),\n * so a screen-reader user can jump back to the material from any question.\n *\n * Rich text follows the SDK-wide rule: `bodyHtml` is rendered only through a\n * caller-supplied sanitiser, and the plain `body` is the fallback — which the\n * schema guarantees exists whenever `bodyHtml` does.\n */\nexport function StimulusPanel({\n stimulus,\n range,\n sanitizeHtml,\n locale,\n renderMode,\n mediaBudget,\n mediaStrings,\n onInteraction,\n disabled,\n strings,\n}: StimulusPanelProps): React.JSX.Element {\n const titleId = useId();\n const s = useLkStrings(strings);\n\n const bodyHtml = useMemo(() => {\n if (sanitizeHtml === undefined || typeof stimulus.bodyHtml !== 'string') {\n return null;\n }\n return sanitizeHtml(stimulus.bodyHtml);\n }, [stimulus.bodyHtml, sanitizeHtml]);\n\n const rangeText = range === undefined ? null : s.stimulusRange(range.first, range.last);\n\n const naming =\n stimulus.title !== undefined\n ? { 'aria-labelledby': titleId }\n : { 'aria-label': s.stimulusKind[stimulus.kind] };\n\n // The AUTHORED parts carry the stimulus language; the SDK's own chrome does\n // not. Declaring `stimulus.locale` on the whole region made a screen reader\n // read \"Recording\" and \"Questions 3–5\" — English strings this package ships\n // — in the passage's voice, so a Spanish listening panel announced its own\n // name and the only orientation text in it with Spanish phonetics\n // (WCAG 3.1.2 Language of Parts). Scope the declaration to the content it\n // actually describes.\n const contentLang = stimulus.locale !== undefined ? { lang: stimulus.locale } : {};\n\n return (\n <section className=\"lk-stimulus\" data-kind={stimulus.kind} lang={locale} {...naming}>\n {stimulus.title !== undefined ? (\n <p className=\"lk-stimulus-title\" id={titleId} {...contentLang}>\n {stimulus.title}\n </p>\n ) : null}\n {rangeText !== null ? <p className=\"lk-stimulus-range\">{rangeText}</p> : null}\n {stimulus.media !== undefined ? (\n <ActivityMedia\n media={stimulus.media}\n {...(renderMode !== undefined ? { renderMode } : {})}\n {...(mediaBudget !== undefined ? { mediaBudget } : {})}\n {...(mediaStrings !== undefined ? { mediaStrings } : {})}\n {...(strings !== undefined ? { strings } : {})}\n {...(onInteraction !== undefined ? { onInteraction } : {})}\n {...(disabled !== undefined ? { disabled } : {})}\n {...(locale !== undefined ? { locale } : {})}\n />\n ) : null}\n {bodyHtml !== null ? (\n <div\n className=\"lk-stimulus-body\"\n data-format=\"html\"\n {...contentLang}\n // biome-ignore lint/security/noDangerouslySetInnerHtml: rendered only through the caller-supplied HtmlSanitizer — the SDK never injects unsanitised markup\n dangerouslySetInnerHTML={{ __html: bodyHtml }}\n />\n ) : stimulus.body !== undefined ? (\n <div className=\"lk-stimulus-body\" data-format=\"text\" {...contentLang}>\n {stimulus.body}\n </div>\n ) : null}\n {stimulus.attribution !== undefined ? (\n <p className=\"lk-stimulus-attribution\" {...contentLang}>\n <cite>{stimulus.attribution}</cite>\n </p>\n ) : null}\n </section>\n );\n}\n"]}
@@ -1,16 +1,16 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
- var chunkLX2X4KC7_cjs = require('./chunk-LX2X4KC7.cjs');
4
+ var chunk5YGVGMMV_cjs = require('./chunk-5YGVGMMV.cjs');
5
5
  var chunkUDCQTOVU_cjs = require('./chunk-UDCQTOVU.cjs');
6
6
  var chunkOD65OZIW_cjs = require('./chunk-OD65OZIW.cjs');
7
- var chunkIXMT7X3E_cjs = require('./chunk-IXMT7X3E.cjs');
8
- var chunkBJLQKJZX_cjs = require('./chunk-BJLQKJZX.cjs');
9
- var chunkAPZ6JFN6_cjs = require('./chunk-APZ6JFN6.cjs');
7
+ var chunkM4UJBLVR_cjs = require('./chunk-M4UJBLVR.cjs');
8
+ var chunkJ2QIHZ3H_cjs = require('./chunk-J2QIHZ3H.cjs');
9
+ var chunkY5H4NOM6_cjs = require('./chunk-Y5H4NOM6.cjs');
10
10
  var chunkEANGKAKG_cjs = require('./chunk-EANGKAKG.cjs');
11
- var chunkL7WY5YFQ_cjs = require('./chunk-L7WY5YFQ.cjs');
11
+ var chunkUKUHVCZX_cjs = require('./chunk-UKUHVCZX.cjs');
12
12
  var chunkXOR4MPEN_cjs = require('./chunk-XOR4MPEN.cjs');
13
- var chunkAHGB5HH6_cjs = require('./chunk-AHGB5HH6.cjs');
13
+ var chunkNFGUJ52G_cjs = require('./chunk-NFGUJ52G.cjs');
14
14
  var lkCore = require('@intellectif/lk-core');
15
15
  var react = require('react');
16
16
  var jsxRuntime = require('react/jsx-runtime');
@@ -160,7 +160,7 @@ function OutcomeSummary({
160
160
  "data-status": reading.status,
161
161
  "data-passed": String(reading.grade.passed),
162
162
  children: scoreShown ? null : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
163
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "lk-ra-grade", children: s.scoreAnnouncement(chunkLX2X4KC7_cjs.percentOfGrade(reading.grade), reading.grade.passed) }),
163
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "lk-ra-grade", children: s.scoreAnnouncement(chunk5YGVGMMV_cjs.percentOfGrade(reading.grade), reading.grade.passed) }),
164
164
  reading.grade.feedback ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "lk-ra-grade-feedback", dir: "auto", children: reading.grade.feedback }) : null
165
165
  ] })
166
166
  }
@@ -212,10 +212,10 @@ function ReadAloud({
212
212
  delivery
213
213
  }) {
214
214
  const isExam = renderMode === "exam";
215
- const policy = chunkIXMT7X3E_cjs.useDeliveryPolicy(delivery);
215
+ const policy = chunkM4UJBLVR_cjs.useDeliveryPolicy(delivery);
216
216
  const isReview = renderMode === "review";
217
- const s = chunkAHGB5HH6_cjs.useLkStrings(strings);
218
- const slot = react.useContext(chunkBJLQKJZX_cjs.SequenceSlotContext);
217
+ const s = chunkNFGUJ52G_cjs.useLkStrings(strings);
218
+ const slot = react.useContext(chunkJ2QIHZ3H_cjs.SequenceSlotContext);
219
219
  const captureGroup = slot?.captureGroup;
220
220
  const devError = react.useMemo(() => {
221
221
  if (!chunkEANGKAKG_cjs.isDevelopment()) {
@@ -409,7 +409,7 @@ function ReadAloud({
409
409
  [data, s.readAloudSlowRecording]
410
410
  );
411
411
  const takeAudio = isReview ? playbackUrl : takeUrl;
412
- const playback = chunkLX2X4KC7_cjs.usePlaybackRefusal(takeAudio);
412
+ const playback = chunk5YGVGMMV_cjs.usePlaybackRefusal(takeAudio);
413
413
  const submitRef = react.useRef(null);
414
414
  if (devError) {
415
415
  throw devError;
@@ -456,7 +456,7 @@ function ReadAloud({
456
456
  if (run !== runRef.current) {
457
457
  return;
458
458
  }
459
- const result = chunkLX2X4KC7_cjs.readAssessResult(answer);
459
+ const result = chunk5YGVGMMV_cjs.readAssessResult(answer);
460
460
  if (result.status === "failed") {
461
461
  raise({ kind: "assess-failed", take: take2, retryable: result.retryable });
462
462
  fire("assessment-failed", { takes, durationMs, retryable: result.retryable });
@@ -480,7 +480,7 @@ function ReadAloud({
480
480
  return;
481
481
  }
482
482
  onComplete?.(
483
- chunkBJLQKJZX_cjs.stampTake(
483
+ chunkJ2QIHZ3H_cjs.stampTake(
484
484
  {
485
485
  score: grade.score,
486
486
  maxScore: grade.maxScore,
@@ -499,7 +499,7 @@ function ReadAloud({
499
499
  // optional, and an empty list is the honest reading of "no per-word
500
500
  // marks were stored" — never a mark of its own.
501
501
  scoringResult: {
502
- score: chunkLX2X4KC7_cjs.fractionOfGrade(grade),
502
+ score: chunk5YGVGMMV_cjs.fractionOfGrade(grade),
503
503
  maxScore: 1,
504
504
  passed: grade.passed,
505
505
  feedback: grade.feedback,
@@ -519,7 +519,7 @@ function ReadAloud({
519
519
  submittingRef.current = true;
520
520
  const takes = recorder.takesUsed;
521
521
  const run = runRef.current;
522
- const take2 = chunkBJLQKJZX_cjs.mintTake();
522
+ const take2 = chunkJ2QIHZ3H_cjs.mintTake();
523
523
  beginTakeReport(take2);
524
524
  try {
525
525
  let ref = null;
@@ -545,7 +545,7 @@ function ReadAloud({
545
545
  setUploaded(ref);
546
546
  fire("recording-uploaded", { takes, durationMs: current.durationMs });
547
547
  }
548
- onSubmit?.(chunkBJLQKJZX_cjs.stampTake(responseOf(ref, takes), take2));
548
+ onSubmit?.(chunkJ2QIHZ3H_cjs.stampTake(responseOf(ref, takes), take2));
549
549
  fire("submitted", { takes, durationMs: current?.durationMs ?? 0 });
550
550
  if (isExam || ref === null) {
551
551
  complete();
@@ -593,8 +593,8 @@ function ReadAloud({
593
593
  };
594
594
  const contentLang = typeof data.locale === "string" ? data.locale : void 0;
595
595
  const contentDir = chunkOD65OZIW_cjs.localeDirectionOf(data.locale);
596
- const outcomeReading = react.useMemo(() => chunkLX2X4KC7_cjs.readOutcome(outcome), [outcome]);
597
- const keptEvidence = react.useMemo(() => chunkLX2X4KC7_cjs.readEvidence(assessment), [assessment]);
596
+ const outcomeReading = react.useMemo(() => chunk5YGVGMMV_cjs.readOutcome(outcome), [outcome]);
597
+ const keptEvidence = react.useMemo(() => chunk5YGVGMMV_cjs.readEvidence(assessment), [assessment]);
598
598
  const storedGrade = outcomeReading?.kind === "graded" && outcomeReading.status === "graded" ? outcomeReading.grade : null;
599
599
  const storedMarks = react.useMemo(
600
600
  () => policy.feedback && isReview && keptEvidence === null && storedGrade?.details !== void 0 ? marksFromDetails(storedGrade.details) : null,
@@ -642,7 +642,7 @@ function ReadAloud({
642
642
  return { text: s.answerSubmitted, feedback: null };
643
643
  }
644
644
  return {
645
- text: `${s.answerSubmitted} ${s.scoreAnnouncement(chunkLX2X4KC7_cjs.percentOfGrade(grade), grade.passed)}`,
645
+ text: `${s.answerSubmitted} ${s.scoreAnnouncement(chunk5YGVGMMV_cjs.percentOfGrade(grade), grade.passed)}`,
646
646
  feedback: grade.feedback
647
647
  };
648
648
  }
@@ -675,7 +675,7 @@ function ReadAloud({
675
675
  data.media !== void 0 ? /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { className: "lk-ra-model", children: [
676
676
  /* @__PURE__ */ jsxRuntime.jsx("legend", { className: "lk-ra-model-label", children: s.readAloudModelRecording }),
677
677
  /* @__PURE__ */ jsxRuntime.jsx(
678
- chunkL7WY5YFQ_cjs.ActivityMedia,
678
+ chunkUKUHVCZX_cjs.ActivityMedia,
679
679
  {
680
680
  media: data.media,
681
681
  renderMode,
@@ -692,7 +692,7 @@ function ReadAloud({
692
692
  slowMedia !== void 0 ? /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { className: "lk-ra-model", "data-slow": "true", children: [
693
693
  /* @__PURE__ */ jsxRuntime.jsx("legend", { className: "lk-ra-model-label", children: s.readAloudSlowRecording }),
694
694
  /* @__PURE__ */ jsxRuntime.jsx(
695
- chunkL7WY5YFQ_cjs.ActivityMedia,
695
+ chunkUKUHVCZX_cjs.ActivityMedia,
696
696
  {
697
697
  media: slowMedia,
698
698
  renderMode,
@@ -825,7 +825,7 @@ function ReadAloud({
825
825
  busy ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "lk-ra-pending", role: "status", "aria-busy": "true", children: phase.kind === "uploading" ? s.readAloudUploading : s.readAloudAssessing }) : null,
826
826
  alertText !== null ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "lk-ra-alert", role: "alert", children: alertText }, errorNonce) : null,
827
827
  feedbackAssessment !== null ? /* @__PURE__ */ jsxRuntime.jsx(
828
- chunkLX2X4KC7_cjs.PronunciationFeedback,
828
+ chunk5YGVGMMV_cjs.PronunciationFeedback,
829
829
  {
830
830
  data: { referenceText: data.referenceText, locale: data.locale },
831
831
  assessment: feedbackAssessment,
@@ -839,14 +839,14 @@ function ReadAloud({
839
839
  ) : null,
840
840
  storedMarks !== null ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "lk-ra-marks", children: [
841
841
  /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "lk-ra-words", "aria-label": s.pronunciationWordsLabel, dir: contentDir, children: storedMarks.map((entry, index) => {
842
- const sentence = chunkLX2X4KC7_cjs.markSentence(entry, s);
842
+ const sentence = chunk5YGVGMMV_cjs.markSentence(entry, s);
843
843
  return /* @__PURE__ */ jsxRuntime.jsxs(
844
844
  "li",
845
845
  {
846
846
  className: "lk-ra-word",
847
847
  "data-state": entry.state,
848
848
  children: [
849
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "lk-visually-hidden", style: chunkLX2X4KC7_cjs.VISUALLY_HIDDEN, children: sentence }),
849
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "lk-visually-hidden", style: chunk5YGVGMMV_cjs.VISUALLY_HIDDEN, children: sentence }),
850
850
  /* @__PURE__ */ jsxRuntime.jsx(
851
851
  "span",
852
852
  {
@@ -864,7 +864,7 @@ function ReadAloud({
864
864
  }) }),
865
865
  /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "lk-ra-legend", children: STORED_STATES.map((state2) => /* @__PURE__ */ jsxRuntime.jsx("li", { "data-state": state2, children: s.pronunciationLegend(state2) }, state2)) })
866
866
  ] }) : null,
867
- /* @__PURE__ */ jsxRuntime.jsx(chunkIXMT7X3E_cjs.FeedbackRegion, { id: `${data.id}-feedback`, children: isReview ? (
867
+ /* @__PURE__ */ jsxRuntime.jsx(chunkM4UJBLVR_cjs.FeedbackRegion, { id: `${data.id}-feedback`, children: isReview ? (
868
868
  // A grade read back is feedback; "not graded yet" and a grade that
869
869
  // could not be read are not.
870
870
  outcomeReading !== void 0 && (policy.feedback || outcomeReading.kind !== "graded") ? /* @__PURE__ */ jsxRuntime.jsx(OutcomeSummary, { reading: outcomeReading, s, scoreShown: gradeShownInPanel }) : null
@@ -874,18 +874,18 @@ function ReadAloud({
874
874
  // but a live region is the only thing that TELLS a screen-reader
875
875
  // learner a grade arrived, since nothing takes focus. Clipped rather
876
876
  // than `display: none`, which would stop it being announced at all.
877
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "lk-visually-hidden", style: chunkLX2X4KC7_cjs.VISUALLY_HIDDEN, children: /* @__PURE__ */ jsxRuntime.jsx(AnnouncementText, { announcement }) })
877
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "lk-visually-hidden", style: chunk5YGVGMMV_cjs.VISUALLY_HIDDEN, children: /* @__PURE__ */ jsxRuntime.jsx(AnnouncementText, { announcement }) })
878
878
  ) : /* @__PURE__ */ jsxRuntime.jsx(AnnouncementText, { announcement }) })
879
879
  ]
880
880
  }
881
881
  );
882
882
  }
883
883
  function ReadAloud2(props) {
884
- const strings = chunkAHGB5HH6_cjs.useLkStrings(props.strings);
885
- return /* @__PURE__ */ jsxRuntime.jsx(chunkAPZ6JFN6_cjs.ActivityErrorBoundary, { activityTitle: props.data?.title, strings, children: /* @__PURE__ */ jsxRuntime.jsx(ReadAloud, { ...props }) });
884
+ const strings = chunkNFGUJ52G_cjs.useLkStrings(props.strings);
885
+ return /* @__PURE__ */ jsxRuntime.jsx(chunkY5H4NOM6_cjs.ActivityErrorBoundary, { activityTitle: props.data?.title, strings, children: /* @__PURE__ */ jsxRuntime.jsx(ReadAloud, { ...props }) });
886
886
  }
887
887
 
888
888
  exports.ReadAloud = ReadAloud2;
889
889
  exports.stopCaptureGroup = stopCaptureGroup;
890
- //# sourceMappingURL=chunk-RT2PP4SO.cjs.map
891
- //# sourceMappingURL=chunk-RT2PP4SO.cjs.map
890
+ //# sourceMappingURL=chunk-BL5SIBQA.cjs.map
891
+ //# sourceMappingURL=chunk-BL5SIBQA.cjs.map