@intellectif/lk-react 23.1.0 → 23.1.2

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 (360) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +9 -5
  3. package/dist/ActivityErrorBoundary-B379hvtL.cjs +39 -0
  4. package/dist/ActivityErrorBoundary-B379hvtL.cjs.map +1 -0
  5. package/dist/ActivityErrorBoundary-Dw6SbWv3.js +34 -0
  6. package/dist/ActivityErrorBoundary-Dw6SbWv3.js.map +1 -0
  7. package/dist/ActivityMedia-CQQTRNl7.cjs +641 -0
  8. package/dist/ActivityMedia-CQQTRNl7.cjs.map +1 -0
  9. package/dist/ActivityMedia-vDiP-Psa.js +636 -0
  10. package/dist/ActivityMedia-vDiP-Psa.js.map +1 -0
  11. package/dist/ActivityPreview-1hhTkYuj.js +240 -0
  12. package/dist/ActivityPreview-1hhTkYuj.js.map +1 -0
  13. package/dist/ActivityPreview-BKr34exz.cjs +245 -0
  14. package/dist/ActivityPreview-BKr34exz.cjs.map +1 -0
  15. package/dist/ActivitySequence-CkX87pfB.js +839 -0
  16. package/dist/ActivitySequence-CkX87pfB.js.map +1 -0
  17. package/dist/ActivitySequence-CmoSyDnp.cjs +844 -0
  18. package/dist/ActivitySequence-CmoSyDnp.cjs.map +1 -0
  19. package/dist/Dictation-BlxRp-3k.js +926 -0
  20. package/dist/Dictation-BlxRp-3k.js.map +1 -0
  21. package/dist/Dictation-jECzL88E.cjs +931 -0
  22. package/dist/Dictation-jECzL88E.cjs.map +1 -0
  23. package/dist/FeedbackRegion-BNNMtTY-.cjs +108 -0
  24. package/dist/FeedbackRegion-BNNMtTY-.cjs.map +1 -0
  25. package/dist/FeedbackRegion-CyPSp8bA.js +85 -0
  26. package/dist/FeedbackRegion-CyPSp8bA.js.map +1 -0
  27. package/dist/FillInTheBlanks-B6xzqYXx.js +474 -0
  28. package/dist/FillInTheBlanks-B6xzqYXx.js.map +1 -0
  29. package/dist/FillInTheBlanks-BpKhdHg2.cjs +479 -0
  30. package/dist/FillInTheBlanks-BpKhdHg2.cjs.map +1 -0
  31. package/dist/GapSelect-DUSiaEQH.js +441 -0
  32. package/dist/GapSelect-DUSiaEQH.js.map +1 -0
  33. package/dist/GapSelect-payTq_Zn.cjs +446 -0
  34. package/dist/GapSelect-payTq_Zn.cjs.map +1 -0
  35. package/dist/InteractiveVideo-BguGv-HA.cjs +2955 -0
  36. package/dist/InteractiveVideo-BguGv-HA.cjs.map +1 -0
  37. package/dist/InteractiveVideo-Cg2jbU3j.js +2944 -0
  38. package/dist/InteractiveVideo-Cg2jbU3j.js.map +1 -0
  39. package/dist/LkAiProvider-DAPpA3PQ.d.cts +84 -0
  40. package/dist/LkAiProvider-DAPpA3PQ.d.cts.map +1 -0
  41. package/dist/LkAiProvider-QdEcIhoo.d.ts +84 -0
  42. package/dist/LkAiProvider-QdEcIhoo.d.ts.map +1 -0
  43. package/dist/LkIntlProvider-D_FdYXjQ.js +375 -0
  44. package/dist/LkIntlProvider-D_FdYXjQ.js.map +1 -0
  45. package/dist/LkIntlProvider-oi57lYB0.cjs +410 -0
  46. package/dist/LkIntlProvider-oi57lYB0.cjs.map +1 -0
  47. package/dist/MultipleChoice-COn5MtKY.cjs +433 -0
  48. package/dist/MultipleChoice-COn5MtKY.cjs.map +1 -0
  49. package/dist/MultipleChoice-Dra0_KYD.js +428 -0
  50. package/dist/MultipleChoice-Dra0_KYD.js.map +1 -0
  51. package/dist/PronunciationFeedback-DlMPGjkR.cjs +831 -0
  52. package/dist/PronunciationFeedback-DlMPGjkR.cjs.map +1 -0
  53. package/dist/PronunciationFeedback-Dxd6XPkO.js +772 -0
  54. package/dist/PronunciationFeedback-Dxd6XPkO.js.map +1 -0
  55. package/dist/ReadAloud-C8RhaUqV.js +1092 -0
  56. package/dist/{chunk-DC4CQCK5.js.map → ReadAloud-C8RhaUqV.js.map} +1 -1
  57. package/dist/ReadAloud-akDehitT.cjs +1103 -0
  58. package/dist/ReadAloud-akDehitT.cjs.map +1 -0
  59. package/dist/StimulusPanel-BgzByfkb.js +74 -0
  60. package/dist/StimulusPanel-BgzByfkb.js.map +1 -0
  61. package/dist/StimulusPanel-b66gaN3i.cjs +79 -0
  62. package/dist/StimulusPanel-b66gaN3i.cjs.map +1 -0
  63. package/dist/ThemeProvider-B6DyGqzh.d.cts +62 -0
  64. package/dist/ThemeProvider-B6DyGqzh.d.cts.map +1 -0
  65. package/dist/ThemeProvider-BCrxBaY-.d.ts +62 -0
  66. package/dist/ThemeProvider-BCrxBaY-.d.ts.map +1 -0
  67. package/dist/ThemeProvider-BRN1tj4n.cjs +187 -0
  68. package/dist/ThemeProvider-BRN1tj4n.cjs.map +1 -0
  69. package/dist/ThemeProvider-C7K9iMLX.js +158 -0
  70. package/dist/ThemeProvider-C7K9iMLX.js.map +1 -0
  71. package/dist/WrittenResponse-Bj3eFmGl.cjs +491 -0
  72. package/dist/WrittenResponse-Bj3eFmGl.cjs.map +1 -0
  73. package/dist/WrittenResponse-Cl8G6nO_.js +486 -0
  74. package/dist/WrittenResponse-Cl8G6nO_.js.map +1 -0
  75. package/dist/ai/LkAiProvider.cjs +34 -14
  76. package/dist/ai/LkAiProvider.cjs.map +1 -1
  77. package/dist/ai/LkAiProvider.d.cts +2 -83
  78. package/dist/ai/LkAiProvider.d.ts +2 -83
  79. package/dist/ai/LkAiProvider.js +33 -2
  80. package/dist/ai/LkAiProvider.js.map +1 -1
  81. package/dist/ai/useAiHelp.cjs +7 -25
  82. package/dist/ai/useAiHelp.d.cts +175 -177
  83. package/dist/ai/useAiHelp.d.cts.map +1 -0
  84. package/dist/ai/useAiHelp.d.ts +175 -177
  85. package/dist/ai/useAiHelp.d.ts.map +1 -0
  86. package/dist/ai/useAiHelp.js +3 -4
  87. package/dist/components/ActivityPreview.cjs +3 -29
  88. package/dist/components/ActivityPreview.d.cts +2 -81
  89. package/dist/components/ActivityPreview.d.ts +2 -81
  90. package/dist/components/ActivityPreview.js +2 -20
  91. package/dist/components/ActivitySequence.cjs +3 -30
  92. package/dist/components/ActivitySequence.d.cts +2 -432
  93. package/dist/components/ActivitySequence.d.ts +2 -432
  94. package/dist/components/ActivitySequence.js +2 -21
  95. package/dist/components/Dictation.cjs +4 -21
  96. package/dist/components/Dictation.d.cts +2 -19
  97. package/dist/components/Dictation.d.ts +2 -19
  98. package/dist/components/Dictation.js +3 -12
  99. package/dist/components/FillInTheBlanks.cjs +4 -20
  100. package/dist/components/FillInTheBlanks.d.cts +2 -30
  101. package/dist/components/FillInTheBlanks.d.ts +2 -30
  102. package/dist/components/FillInTheBlanks.js +3 -11
  103. package/dist/components/GapSelect.cjs +4 -20
  104. package/dist/components/GapSelect.d.cts +2 -27
  105. package/dist/components/GapSelect.d.ts +2 -27
  106. package/dist/components/GapSelect.js +3 -11
  107. package/dist/components/InteractiveVideo.cjs +5 -32
  108. package/dist/components/InteractiveVideo.d.cts +3 -291
  109. package/dist/components/InteractiveVideo.d.ts +3 -291
  110. package/dist/components/InteractiveVideo.js +3 -19
  111. package/dist/components/MultipleChoice.cjs +4 -20
  112. package/dist/components/MultipleChoice.d.cts +2 -26
  113. package/dist/components/MultipleChoice.d.ts +2 -26
  114. package/dist/components/MultipleChoice.js +3 -11
  115. package/dist/components/PronunciationFeedback.cjs +4 -17
  116. package/dist/components/PronunciationFeedback.d.cts +2 -90
  117. package/dist/components/PronunciationFeedback.d.ts +2 -90
  118. package/dist/components/PronunciationFeedback.js +3 -8
  119. package/dist/components/ReadAloud.cjs +4 -22
  120. package/dist/components/ReadAloud.d.cts +7 -11
  121. package/dist/components/ReadAloud.d.cts.map +1 -0
  122. package/dist/components/ReadAloud.d.ts +7 -11
  123. package/dist/components/ReadAloud.d.ts.map +1 -0
  124. package/dist/components/ReadAloud.js +3 -13
  125. package/dist/components/StimulusPanel.cjs +3 -14
  126. package/dist/components/StimulusPanel.d.cts +2 -51
  127. package/dist/components/StimulusPanel.d.ts +2 -51
  128. package/dist/components/StimulusPanel.js +2 -5
  129. package/dist/components/WrittenResponse.cjs +4 -19
  130. package/dist/components/WrittenResponse.d.cts +3 -18
  131. package/dist/components/WrittenResponse.d.ts +3 -18
  132. package/dist/components/WrittenResponse.js +3 -10
  133. package/dist/direction-Dq0_HtA5.js +183 -0
  134. package/dist/direction-Dq0_HtA5.js.map +1 -0
  135. package/dist/direction-K1pj0HCA.cjs +200 -0
  136. package/dist/direction-K1pj0HCA.cjs.map +1 -0
  137. package/dist/hooks/useActivityState.cjs +28 -10
  138. package/dist/hooks/useActivityState.cjs.map +1 -1
  139. package/dist/hooks/useActivityState.d.cts +25 -24
  140. package/dist/hooks/useActivityState.d.cts.map +1 -0
  141. package/dist/hooks/useActivityState.d.ts +25 -24
  142. package/dist/hooks/useActivityState.d.ts.map +1 -0
  143. package/dist/hooks/useActivityState.js +28 -2
  144. package/dist/hooks/useActivityState.js.map +1 -1
  145. package/dist/hooks/useSpeechRecorder.cjs +5 -16
  146. package/dist/hooks/useSpeechRecorder.d.cts +2 -127
  147. package/dist/hooks/useSpeechRecorder.d.ts +2 -127
  148. package/dist/hooks/useSpeechRecorder.js +3 -3
  149. package/dist/hooks/useXAPI.cjs +126 -10
  150. package/dist/hooks/useXAPI.cjs.map +1 -1
  151. package/dist/hooks/useXAPI.d.cts +14 -14
  152. package/dist/hooks/useXAPI.d.cts.map +1 -0
  153. package/dist/hooks/useXAPI.d.ts +14 -14
  154. package/dist/hooks/useXAPI.d.ts.map +1 -0
  155. package/dist/hooks/useXAPI.js +126 -2
  156. package/dist/hooks/useXAPI.js.map +1 -1
  157. package/dist/i18n/LkIntlProvider.cjs +9 -32
  158. package/dist/i18n/LkIntlProvider.d.cts +34 -38
  159. package/dist/i18n/LkIntlProvider.d.cts.map +1 -0
  160. package/dist/i18n/LkIntlProvider.d.ts +34 -38
  161. package/dist/i18n/LkIntlProvider.d.ts.map +1 -0
  162. package/dist/i18n/LkIntlProvider.js +3 -3
  163. package/dist/index-6P4rJHrJ.d.cts +432 -0
  164. package/dist/index-6P4rJHrJ.d.cts.map +1 -0
  165. package/dist/index-90CX504k.d.ts +90 -0
  166. package/dist/index-90CX504k.d.ts.map +1 -0
  167. package/dist/index-B_SgnjsC.d.cts +291 -0
  168. package/dist/index-B_SgnjsC.d.cts.map +1 -0
  169. package/dist/index-BavVW5z5.d.cts +25 -0
  170. package/dist/index-BavVW5z5.d.cts.map +1 -0
  171. package/dist/index-BhHv6Fiu.d.cts +28 -0
  172. package/dist/index-BhHv6Fiu.d.cts.map +1 -0
  173. package/dist/index-Bsu8VciA.d.ts +432 -0
  174. package/dist/index-Bsu8VciA.d.ts.map +1 -0
  175. package/dist/index-C1KGpD1k.d.ts +49 -0
  176. package/dist/index-C1KGpD1k.d.ts.map +1 -0
  177. package/dist/index-CKTpYTCC.d.cts +49 -0
  178. package/dist/index-CKTpYTCC.d.cts.map +1 -0
  179. package/dist/index-CO_SRFJj.d.ts +16 -0
  180. package/dist/index-CO_SRFJj.d.ts.map +1 -0
  181. package/dist/index-CSsuUsP7.d.cts +124 -0
  182. package/dist/index-CSsuUsP7.d.cts.map +1 -0
  183. package/dist/index-CunUyeuN.d.cts +78 -0
  184. package/dist/index-CunUyeuN.d.cts.map +1 -0
  185. package/dist/index-CzfRzks6.d.cts +90 -0
  186. package/dist/index-CzfRzks6.d.cts.map +1 -0
  187. package/dist/index-D14xtpBS.d.cts +24 -0
  188. package/dist/index-D14xtpBS.d.cts.map +1 -0
  189. package/dist/index-DHRPAPZf.d.ts +291 -0
  190. package/dist/index-DHRPAPZf.d.ts.map +1 -0
  191. package/dist/index-DLV6cK26.d.cts +16 -0
  192. package/dist/index-DLV6cK26.d.cts.map +1 -0
  193. package/dist/index-DbCCQ9cP.d.ts +124 -0
  194. package/dist/index-DbCCQ9cP.d.ts.map +1 -0
  195. package/dist/index-DeV5B2m5.d.ts +24 -0
  196. package/dist/index-DeV5B2m5.d.ts.map +1 -0
  197. package/dist/index-TZCJVSge.d.ts +28 -0
  198. package/dist/index-TZCJVSge.d.ts.map +1 -0
  199. package/dist/index-ZVvLHsd3.d.ts +25 -0
  200. package/dist/index-ZVvLHsd3.d.ts.map +1 -0
  201. package/dist/index-eQwBgpSw.d.ts +78 -0
  202. package/dist/index-eQwBgpSw.d.ts.map +1 -0
  203. package/dist/index.cjs +118 -163
  204. package/dist/index.cjs.map +1 -1
  205. package/dist/index.d.cts +20 -24
  206. package/dist/index.d.ts +20 -24
  207. package/dist/index.js +84 -29
  208. package/dist/index.js.map +1 -1
  209. package/dist/theme/ThemeProvider.cjs +8 -28
  210. package/dist/theme/ThemeProvider.d.cts +2 -59
  211. package/dist/theme/ThemeProvider.d.ts +2 -59
  212. package/dist/theme/ThemeProvider.js +3 -3
  213. package/dist/tries-CbbtZkdG.cjs +363 -0
  214. package/dist/tries-CbbtZkdG.cjs.map +1 -0
  215. package/dist/tries-DTHSrLCm.js +310 -0
  216. package/dist/tries-DTHSrLCm.js.map +1 -0
  217. package/dist/types-BOQd93x3.d.cts +994 -0
  218. package/dist/types-BOQd93x3.d.cts.map +1 -0
  219. package/dist/types-HIrgF_mS.d.ts +994 -0
  220. package/dist/types-HIrgF_mS.d.ts.map +1 -0
  221. package/dist/useAiHelp-B-ccDL5Q.js +906 -0
  222. package/dist/useAiHelp-B-ccDL5Q.js.map +1 -0
  223. package/dist/useAiHelp-h9yOLFqt.cjs +995 -0
  224. package/dist/useAiHelp-h9yOLFqt.cjs.map +1 -0
  225. package/dist/useSpeechRecorder--O_f-xvt.cjs +720 -0
  226. package/dist/useSpeechRecorder--O_f-xvt.cjs.map +1 -0
  227. package/dist/useSpeechRecorder-DtAYvl02.d.cts +154 -0
  228. package/dist/useSpeechRecorder-DtAYvl02.d.cts.map +1 -0
  229. package/dist/useSpeechRecorder-DtAYvl02.d.ts +154 -0
  230. package/dist/useSpeechRecorder-DtAYvl02.d.ts.map +1 -0
  231. package/dist/useSpeechRecorder-zIi9Dlw8.js +709 -0
  232. package/dist/useSpeechRecorder-zIi9Dlw8.js.map +1 -0
  233. package/package.json +10 -11
  234. package/dist/WrittenResponse-B7A5gHMj.d.ts +0 -115
  235. package/dist/WrittenResponse-BpL9p2Hn.d.cts +0 -115
  236. package/dist/ai/useAiHelp.cjs.map +0 -1
  237. package/dist/ai/useAiHelp.js.map +0 -1
  238. package/dist/chunk-2PNSVBLQ.cjs +0 -54
  239. package/dist/chunk-2PNSVBLQ.cjs.map +0 -1
  240. package/dist/chunk-2TW6WLBC.js +0 -80
  241. package/dist/chunk-2TW6WLBC.js.map +0 -1
  242. package/dist/chunk-4ZZWZSWI.js +0 -61
  243. package/dist/chunk-4ZZWZSWI.js.map +0 -1
  244. package/dist/chunk-6N43WDVG.js +0 -29
  245. package/dist/chunk-6N43WDVG.js.map +0 -1
  246. package/dist/chunk-7ALBSPYR.cjs +0 -436
  247. package/dist/chunk-7ALBSPYR.cjs.map +0 -1
  248. package/dist/chunk-7NFY3M3W.js +0 -234
  249. package/dist/chunk-7NFY3M3W.js.map +0 -1
  250. package/dist/chunk-7SB2MJA4.js +0 -29
  251. package/dist/chunk-7SB2MJA4.js.map +0 -1
  252. package/dist/chunk-ABJJ3LII.js +0 -434
  253. package/dist/chunk-ABJJ3LII.js.map +0 -1
  254. package/dist/chunk-BIGGXHAW.cjs +0 -342
  255. package/dist/chunk-BIGGXHAW.cjs.map +0 -1
  256. package/dist/chunk-C7QZE5BI.js +0 -430
  257. package/dist/chunk-C7QZE5BI.js.map +0 -1
  258. package/dist/chunk-CWTUWNV3.cjs +0 -2937
  259. package/dist/chunk-CWTUWNV3.cjs.map +0 -1
  260. package/dist/chunk-DC4CQCK5.js +0 -915
  261. package/dist/chunk-DS6HN3YR.cjs +0 -496
  262. package/dist/chunk-DS6HN3YR.cjs.map +0 -1
  263. package/dist/chunk-FDQR4GAZ.js +0 -240
  264. package/dist/chunk-FDQR4GAZ.js.map +0 -1
  265. package/dist/chunk-FKGMSOJF.js +0 -394
  266. package/dist/chunk-FKGMSOJF.js.map +0 -1
  267. package/dist/chunk-G6PXJ2SA.js +0 -823
  268. package/dist/chunk-G6PXJ2SA.js.map +0 -1
  269. package/dist/chunk-HNLRVRQR.js +0 -335
  270. package/dist/chunk-HNLRVRQR.js.map +0 -1
  271. package/dist/chunk-J3C72RPK.cjs +0 -31
  272. package/dist/chunk-J3C72RPK.cjs.map +0 -1
  273. package/dist/chunk-K63VPFOV.cjs +0 -134
  274. package/dist/chunk-K63VPFOV.cjs.map +0 -1
  275. package/dist/chunk-KFLIDTDU.cjs +0 -825
  276. package/dist/chunk-KFLIDTDU.cjs.map +0 -1
  277. package/dist/chunk-KHKH5LCT.cjs +0 -250
  278. package/dist/chunk-KHKH5LCT.cjs.map +0 -1
  279. package/dist/chunk-LBEKRN6Y.cjs +0 -664
  280. package/dist/chunk-LBEKRN6Y.cjs.map +0 -1
  281. package/dist/chunk-LPUWXIPR.cjs +0 -578
  282. package/dist/chunk-LPUWXIPR.cjs.map +0 -1
  283. package/dist/chunk-MCO52PV5.js +0 -520
  284. package/dist/chunk-MCO52PV5.js.map +0 -1
  285. package/dist/chunk-MKXEM2C5.cjs +0 -396
  286. package/dist/chunk-MKXEM2C5.cjs.map +0 -1
  287. package/dist/chunk-MXNC5UNO.js +0 -563
  288. package/dist/chunk-MXNC5UNO.js.map +0 -1
  289. package/dist/chunk-NAK55BYU.cjs +0 -859
  290. package/dist/chunk-NAK55BYU.cjs.map +0 -1
  291. package/dist/chunk-NDBMKGQ5.cjs +0 -599
  292. package/dist/chunk-NDBMKGQ5.cjs.map +0 -1
  293. package/dist/chunk-OD65OZIW.cjs +0 -159
  294. package/dist/chunk-OD65OZIW.cjs.map +0 -1
  295. package/dist/chunk-ORT3KLGI.js +0 -50
  296. package/dist/chunk-ORT3KLGI.js.map +0 -1
  297. package/dist/chunk-PNNUPUH4.cjs +0 -82
  298. package/dist/chunk-PNNUPUH4.cjs.map +0 -1
  299. package/dist/chunk-PWHECW6N.js +0 -2934
  300. package/dist/chunk-PWHECW6N.js.map +0 -1
  301. package/dist/chunk-RBS5A2DF.js +0 -857
  302. package/dist/chunk-RBS5A2DF.js.map +0 -1
  303. package/dist/chunk-RPWUDXG5.cjs +0 -63
  304. package/dist/chunk-RPWUDXG5.cjs.map +0 -1
  305. package/dist/chunk-TCDJY3H6.js +0 -494
  306. package/dist/chunk-TCDJY3H6.js.map +0 -1
  307. package/dist/chunk-TP5UMRAU.cjs +0 -918
  308. package/dist/chunk-TP5UMRAU.cjs.map +0 -1
  309. package/dist/chunk-TS7J6DTY.js +0 -597
  310. package/dist/chunk-TS7J6DTY.js.map +0 -1
  311. package/dist/chunk-TUVENMXB.cjs +0 -20
  312. package/dist/chunk-TUVENMXB.cjs.map +0 -1
  313. package/dist/chunk-UDCQTOVU.cjs +0 -523
  314. package/dist/chunk-UDCQTOVU.cjs.map +0 -1
  315. package/dist/chunk-UHKZXOXD.js +0 -128
  316. package/dist/chunk-UHKZXOXD.js.map +0 -1
  317. package/dist/chunk-V6BA44DS.cjs +0 -236
  318. package/dist/chunk-V6BA44DS.cjs.map +0 -1
  319. package/dist/chunk-XO5R73Y4.js +0 -653
  320. package/dist/chunk-XO5R73Y4.js.map +0 -1
  321. package/dist/chunk-XOR4MPEN.cjs +0 -31
  322. package/dist/chunk-XOR4MPEN.cjs.map +0 -1
  323. package/dist/chunk-YORQQXGO.js +0 -155
  324. package/dist/chunk-YORQQXGO.js.map +0 -1
  325. package/dist/chunk-YY4PFR3Z.cjs +0 -432
  326. package/dist/chunk-YY4PFR3Z.cjs.map +0 -1
  327. package/dist/chunk-ZPI6Q42R.js +0 -17
  328. package/dist/chunk-ZPI6Q42R.js.map +0 -1
  329. package/dist/components/ActivityPreview.cjs.map +0 -1
  330. package/dist/components/ActivityPreview.js.map +0 -1
  331. package/dist/components/ActivitySequence.cjs.map +0 -1
  332. package/dist/components/ActivitySequence.js.map +0 -1
  333. package/dist/components/Dictation.cjs.map +0 -1
  334. package/dist/components/Dictation.js.map +0 -1
  335. package/dist/components/FillInTheBlanks.cjs.map +0 -1
  336. package/dist/components/FillInTheBlanks.js.map +0 -1
  337. package/dist/components/GapSelect.cjs.map +0 -1
  338. package/dist/components/GapSelect.js.map +0 -1
  339. package/dist/components/InteractiveVideo.cjs.map +0 -1
  340. package/dist/components/InteractiveVideo.js.map +0 -1
  341. package/dist/components/MultipleChoice.cjs.map +0 -1
  342. package/dist/components/MultipleChoice.js.map +0 -1
  343. package/dist/components/PronunciationFeedback.cjs.map +0 -1
  344. package/dist/components/PronunciationFeedback.js.map +0 -1
  345. package/dist/components/ReadAloud.cjs.map +0 -1
  346. package/dist/components/ReadAloud.js.map +0 -1
  347. package/dist/components/StimulusPanel.cjs.map +0 -1
  348. package/dist/components/StimulusPanel.js.map +0 -1
  349. package/dist/components/WrittenResponse.cjs.map +0 -1
  350. package/dist/components/WrittenResponse.js.map +0 -1
  351. package/dist/hooks/useSpeechRecorder.cjs.map +0 -1
  352. package/dist/hooks/useSpeechRecorder.js.map +0 -1
  353. package/dist/i18n/LkIntlProvider.cjs.map +0 -1
  354. package/dist/i18n/LkIntlProvider.js.map +0 -1
  355. package/dist/machine-CuwKqWXC.d.cts +0 -26
  356. package/dist/machine-CuwKqWXC.d.ts +0 -26
  357. package/dist/theme/ThemeProvider.cjs.map +0 -1
  358. package/dist/theme/ThemeProvider.js.map +0 -1
  359. package/dist/types-C4IsUQsK.d.ts +0 -989
  360. package/dist/types-CJgZWtl4.d.cts +0 -989
@@ -0,0 +1,844 @@
1
+ 'use client';
2
+ const require_useAiHelp = require("./useAiHelp-h9yOLFqt.cjs");
3
+ const require_LkIntlProvider = require("./LkIntlProvider-oi57lYB0.cjs");
4
+ const require_Dictation = require("./Dictation-jECzL88E.cjs");
5
+ const require_FillInTheBlanks = require("./FillInTheBlanks-BpKhdHg2.cjs");
6
+ const require_GapSelect = require("./GapSelect-payTq_Zn.cjs");
7
+ const require_MultipleChoice = require("./MultipleChoice-COn5MtKY.cjs");
8
+ const require_ReadAloud = require("./ReadAloud-akDehitT.cjs");
9
+ const require_WrittenResponse = require("./WrittenResponse-Bj3eFmGl.cjs");
10
+ const require_StimulusPanel = require("./StimulusPanel-b66gaN3i.cjs");
11
+ let react = require("react");
12
+ let react_jsx_runtime = require("react/jsx-runtime");
13
+ let _intellectif_lk_core = require("@intellectif/lk-core");
14
+ //#region src/components/ActivitySequence/ActivitySequence.tsx
15
+ /**
16
+ * One slot's key for the life of a set: its pane's React key, and the name its
17
+ * portal node is held under.
18
+ */
19
+ function slotKeyOf(setKey, slot) {
20
+ return `${setKey}::slot-${slot.slotId}-${slot.activity.id}`;
21
+ }
22
+ /** The authored-entry prefix of a slot id: `"3"` for `"3"` and for `"3.1"`. */
23
+ function entryKeyOf(slot) {
24
+ return slot.slotId.split(".")[0] ?? slot.slotId;
25
+ }
26
+ /**
27
+ * Names the capture groups of one pager, so a slot's microphone belongs to that
28
+ * pager alone. Per mount, for the reason the playback groups are: slot ids are
29
+ * short and repeat ("0", "1.0"), so two pagers on one page — a review beside a
30
+ * live attempt — would share a group, and hiding one's first question would
31
+ * stop the other's recorder. The name never reaches the DOM, so a server and
32
+ * the client that hydrates it may mint different ones.
33
+ */
34
+ let captureScopeCount = 0;
35
+ /**
36
+ * A pane that is kept MOUNTED but shown only when it is the current one, and
37
+ * that stops any media it contains on the way out.
38
+ *
39
+ * `hidden` alone is not enough. It resolves to `display: none`, and CSS does
40
+ * not touch playback: an `<audio>` or `<video>` inside a hidden subtree keeps
41
+ * playing to the end. (The HTML spec pauses a media element when it is
42
+ * REMOVED from the document — a different thing, and the thing this pager
43
+ * deliberately does not do, because unmounting is what used to destroy the
44
+ * learner's answers.) So a recording started for one question would carry on
45
+ * underneath the next, which for a listening paper means the passage plays
46
+ * while the learner is somewhere else entirely.
47
+ *
48
+ * Pausing preserves `currentTime`: coming back to a group resumes where the
49
+ * learner left off. Nothing auto-plays on the way in — starting audio the
50
+ * learner did not ask for is its own defect.
51
+ *
52
+ * `embed` media (a provider iframe) cannot be paused this way: controlling a
53
+ * third-party player needs its own JS API, which the SDK has no reliable
54
+ * access to because the author supplies the embed URL. Use `audio`/`video`
55
+ * media for anything that must stop when the learner navigates.
56
+ *
57
+ * A microphone is the other way round: it is not an element in this subtree, so
58
+ * no query can find it. A slot pane hands its content a `channel` through
59
+ * `SequenceSlotContext` — never a prop, so nothing on a public component's
60
+ * signature can name it — whose `captureGroup` the pane's recorders join, and
61
+ * hiding the pane stops them: a learner who navigates away mid-take must not
62
+ * leave the microphone live under the next question.
63
+ */
64
+ function SequencePane({ className, hidden, channel, children }) {
65
+ const ref = (0, react.useRef)(null);
66
+ const captureGroup = channel?.captureGroup;
67
+ (0, react.useEffect)(() => {
68
+ if (!hidden) return;
69
+ if (captureGroup !== void 0) require_ReadAloud.stopCaptureGroup(captureGroup);
70
+ const node = ref.current;
71
+ if (node === null) return;
72
+ for (const media of node.querySelectorAll("audio, video")) {
73
+ const element = media;
74
+ if (!element.paused) element.pause();
75
+ }
76
+ }, [hidden, captureGroup]);
77
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
78
+ className,
79
+ hidden,
80
+ ref,
81
+ children: channel === void 0 ? children : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_useAiHelp.SequenceSlotContext.Provider, {
82
+ value: channel,
83
+ children
84
+ })
85
+ });
86
+ }
87
+ /**
88
+ * Presents a set of activities as an in-place pager: one question visible at a
89
+ * time, navigated with Prev/Next (no page scrolling). Linear free navigation —
90
+ * the learner may move back and forth; activities keep their own submit and
91
+ * scoring. On navigation, focus moves to the question region and the position
92
+ * is announced via an aria-live region.
93
+ *
94
+ * Item groups are flattened into consecutive questions; the group's stimulus
95
+ * is mounted ONCE, beside the question region rather than inside it, and shown
96
+ * alongside every question in the group — so a passage stays put, and a
97
+ * recording keeps its position, as the learner moves between its questions.
98
+ */
99
+ /**
100
+ * Whether an activity shuffles its own options, and therefore needs a seed of
101
+ * its own. Read structurally: `shuffle` is a per-type content field, not part
102
+ * of the sequence entry contract.
103
+ */
104
+ function shufflesItsOwnOptions(entry) {
105
+ const item = entry;
106
+ return item?.shuffle === true || item?.shuffleChoices === true;
107
+ }
108
+ function ActivitySequence({ activities, renderers, onActivityComplete, onComplete, onFinished, onSubmit, onInteraction, renderMode = "practice", shuffle, shuffleSeed, defaultIndex, onIndexChange, responses, submittedSlotIds, outcomes, sanitizeHtml, theme, locale, disabled, mediaBudget, recordingBinding, assessments, workletUrl, strings, ai, delivery, scoring }) {
109
+ const sessionIdRef = (0, react.useRef)(null);
110
+ const s = require_LkIntlProvider.useLkStrings(strings);
111
+ const mediaPlays = mediaBudget?.plays;
112
+ const [captureScope] = (0, react.useState)(() => {
113
+ captureScopeCount += 1;
114
+ return `lk-seq-capture-${captureScopeCount}`;
115
+ });
116
+ const shuffleEntries = shuffle === "entries";
117
+ const needsSeed = shuffleEntries || activities.some((entry) => (0, _intellectif_lk_core.isItemGroup)(entry) ? entry.shuffle === "within-group" || entry.items.some(shufflesItsOwnOptions) : shufflesItsOwnOptions(entry));
118
+ if (needsSeed && shuffleSeed === void 0 && renderMode !== "practice") throw new Error(`ActivitySequence: renderMode "${renderMode}" requires a \`shuffleSeed\` when anything in the sequence shuffles: shuffle="entries", a group with shuffle: "within-group", or an activity's own \`data.shuffle\` (multiple choice) or \`data.shuffleChoices\` (gap select), including an activity inside a group. Pass the attempt id, so the server can rebuild every order the learner saw from that one seed.`);
119
+ const seed = needsSeed ? shuffleSeed ?? (sessionIdRef.current ??= require_useAiHelp.randomSessionId()) : void 0;
120
+ const slots = (0, react.useMemo)(() => (0, _intellectif_lk_core.flattenSequence)(activities, {
121
+ shuffleEntries,
122
+ ...seed !== void 0 ? { seed } : {}
123
+ }), [
124
+ activities,
125
+ shuffleEntries,
126
+ seed
127
+ ]);
128
+ const [index, setIndex] = (0, react.useState)(() => {
129
+ const requested = Math.trunc(defaultIndex ?? 0);
130
+ if (!Number.isFinite(requested)) return 0;
131
+ return Math.min(Math.max(0, requested), Math.max(0, slots.length - 1));
132
+ });
133
+ const outcomesRef = (0, react.useRef)(null);
134
+ const outcomeSlotsRef = (0, react.useRef)(null);
135
+ const takesRef = (0, react.useRef)(/* @__PURE__ */ new Map());
136
+ const setGenerationRef = (0, react.useRef)(0);
137
+ const indexRef = (0, react.useRef)(index);
138
+ const reportedRef = (0, react.useRef)(false);
139
+ const channelsRef = (0, react.useRef)(/* @__PURE__ */ new Map());
140
+ const callsRef = (0, react.useRef)(/* @__PURE__ */ new Map());
141
+ const hostPendingRef = (0, react.useRef)(/* @__PURE__ */ new Set());
142
+ const [portals, setPortals] = (0, react.useState)(() => /* @__PURE__ */ new Map());
143
+ const portalRefsRef = (0, react.useRef)(/* @__PURE__ */ new Map());
144
+ const modeRef = (0, react.useRef)(renderMode);
145
+ modeRef.current = renderMode;
146
+ const deliveryRef = (0, react.useRef)((0, _intellectif_lk_core.resolveDeliveryPolicy)(delivery));
147
+ deliveryRef.current = (0, _intellectif_lk_core.resolveDeliveryPolicy)(delivery);
148
+ const scoringKey = JSON.stringify(scoring ?? null);
149
+ const scoringInForce = (0, react.useMemo)(() => scoring === void 0 || scoring === null ? void 0 : (0, _intellectif_lk_core.resolveItemScoringPolicy)(scoring), [scoringKey]);
150
+ const scoringRef = (0, react.useRef)(scoringInForce);
151
+ scoringRef.current = scoringInForce;
152
+ const [, setReported] = (0, react.useState)(false);
153
+ const triesRef = (0, react.useRef)(/* @__PURE__ */ new Map());
154
+ const triedRef = (0, react.useRef)(/* @__PURE__ */ new Map());
155
+ const latestRef = (0, react.useRef)(null);
156
+ const aliveRef = (0, react.useRef)(true);
157
+ (0, react.useEffect)(() => {
158
+ aliveRef.current = true;
159
+ return () => {
160
+ aliveRef.current = false;
161
+ };
162
+ }, []);
163
+ if (outcomesRef.current === null) {
164
+ const submittedAtMount = new Set(submittedSlotIds ?? []);
165
+ outcomesRef.current = slots.map((slot) => submittedAtMount.has(slot.slotId) ? {
166
+ kind: "restored",
167
+ index: slot.index,
168
+ slotId: slot.slotId,
169
+ activityId: slot.activity.id,
170
+ ...responses !== void 0 && Object.hasOwn(responses, slot.slotId) ? { response: responses[slot.slotId] } : {}
171
+ } : null);
172
+ outcomeSlotsRef.current = slots;
173
+ }
174
+ const regionRef = (0, react.useRef)(null);
175
+ const mountedRef = (0, react.useRef)(false);
176
+ const setKey = JSON.stringify(slots.map((slot) => [slot.slotId, slot.activity.id]));
177
+ const [prevSetKey, setPrevSetKey] = (0, react.useState)(setKey);
178
+ const seedKey = `${setKey}::${mediaBudget?.resumeKey ?? ""}`;
179
+ const mountSetKeyRef = (0, react.useRef)(setKey);
180
+ const mountSeedKeyRef = (0, react.useRef)(seedKey);
181
+ const seedsApply = mountSetKeyRef.current === setKey;
182
+ const mediaSeedsApply = mountSeedKeyRef.current === seedKey || seedsApply;
183
+ if (mountSeedKeyRef.current !== seedKey) mountSeedKeyRef.current = seedKey;
184
+ const submitted = (0, react.useMemo)(() => new Set(submittedSlotIds ?? []), [submittedSlotIds]);
185
+ if (prevSetKey !== setKey) {
186
+ setPrevSetKey(setKey);
187
+ setIndex(0);
188
+ indexRef.current = 0;
189
+ outcomesRef.current = slots.map(() => null);
190
+ outcomeSlotsRef.current = slots;
191
+ takesRef.current = /* @__PURE__ */ new Map();
192
+ setGenerationRef.current += 1;
193
+ channelsRef.current = /* @__PURE__ */ new Map();
194
+ callsRef.current = /* @__PURE__ */ new Map();
195
+ hostPendingRef.current = /* @__PURE__ */ new Set();
196
+ portalRefsRef.current = /* @__PURE__ */ new Map();
197
+ reportedRef.current = false;
198
+ triesRef.current = /* @__PURE__ */ new Map();
199
+ triedRef.current = /* @__PURE__ */ new Map();
200
+ setReported(false);
201
+ }
202
+ const setGeneration = setGenerationRef.current;
203
+ (0, react.useEffect)(() => {
204
+ if (mountedRef.current) regionRef.current?.focus();
205
+ else mountedRef.current = true;
206
+ }, [index]);
207
+ const reportedIndexRef = (0, react.useRef)(null);
208
+ (0, react.useEffect)(() => {
209
+ if (reportedIndexRef.current === index) return;
210
+ const first = reportedIndexRef.current === null;
211
+ reportedIndexRef.current = index;
212
+ if (first && index === Math.trunc(defaultIndex ?? 0)) return;
213
+ onIndexChange?.(index);
214
+ }, [
215
+ index,
216
+ defaultIndex,
217
+ onIndexChange
218
+ ]);
219
+ (0, react.useEffect)(() => {
220
+ if (indexRef.current === index) return;
221
+ indexRef.current = index;
222
+ latestRef.current?.reportIfFinished();
223
+ }, [index]);
224
+ const stimulusMounts = (0, react.useMemo)(() => {
225
+ const mounts = /* @__PURE__ */ new Map();
226
+ for (const slot of slots) {
227
+ if (slot.group === void 0) continue;
228
+ const entryKey = entryKeyOf(slot);
229
+ const existing = mounts.get(entryKey);
230
+ if (existing === void 0) mounts.set(entryKey, {
231
+ entryKey,
232
+ group: slot.group,
233
+ first: slot.index,
234
+ last: slot.index
235
+ });
236
+ else existing.last = slot.index;
237
+ }
238
+ return [...mounts.values()];
239
+ }, [slots]);
240
+ const total = slots.length;
241
+ const current = slots[index];
242
+ const go = (next) => {
243
+ setIndex(next);
244
+ };
245
+ /**
246
+ * Fires the whole-set callbacks — once, together — when every slot is done
247
+ * and no take is still on its way.
248
+ *
249
+ * **A take on its way holds the report.** A practice read-aloud records its
250
+ * `responded` outcome the moment its take is stored, and its grade can land
251
+ * after the last slot was filled; reporting then handed `onFinished` the raw
252
+ * outcome, and the grade a moment later could never reach it. So a slot
253
+ * whose latest take is being stored or judged is not done. The take states
254
+ * come from the component itself, through the slot's channel, and every way a
255
+ * take can end reports an end — a grade, a take with no grade, a failure
256
+ * nobody can retry, an unmount — so a take that settles never holds a set.
257
+ *
258
+ * **So does a failure the learner can still retry, on the question in front
259
+ * of them.** Reporting there reported a set whose answer "Try again" was about
260
+ * to change: the retry stored and graded the take, and `onComplete` then
261
+ * described a different set from the `onFinished` before it. Once the learner
262
+ * moves to another question the failure no longer holds the report: the slot
263
+ * completes as whatever it last stored, or as `unsubmitted` when that is
264
+ * nothing — never as a `recording` of `null`, which is the blank a learner
265
+ * chooses and a grader marks 0. `unsubmitted` is a `practice` outcome only:
266
+ * an exam question with no stored take is unanswered, and the learner has a
267
+ * blank to hand in if that is their answer.
268
+ */
269
+ const reportIfFinished = () => {
270
+ const held = outcomesRef.current;
271
+ const presented = outcomeSlotsRef.current;
272
+ if (held === null || presented === null || reportedRef.current) return;
273
+ if (hostPendingRef.current.size > 0) return;
274
+ for (const [at, state] of triesRef.current) if (state === "retrying" || at === indexRef.current) return;
275
+ const items = [];
276
+ for (const [at, outcome] of held.entries()) {
277
+ const take = takesRef.current.get(at);
278
+ if (take?.state === "in-flight" || take?.state === "retryable" && at === indexRef.current) return;
279
+ const slot = presented[at];
280
+ if (outcome !== null) items.push(outcome);
281
+ else if (take?.state === "retryable" && renderMode === "practice" && slot !== void 0) items.push({
282
+ kind: "unsubmitted",
283
+ index: at,
284
+ slotId: slot.slotId,
285
+ activityId: slot.activity.id
286
+ });
287
+ else return;
288
+ }
289
+ reportedRef.current = true;
290
+ setReported(true);
291
+ onFinished?.(items);
292
+ const scored = [];
293
+ for (const item of items) {
294
+ if (item.kind !== "scored") return;
295
+ scored.push(item.result);
296
+ }
297
+ onComplete?.(scored);
298
+ };
299
+ /**
300
+ * Records a finished slot and reports the set when it is done — the one place
301
+ * a slot's outcome is decided.
302
+ *
303
+ * **An outcome must come from the set on screen.** A grade can settle after
304
+ * the paper changed — an assessment held across a swap of `activities`, or a
305
+ * consumer's own renderer grading asynchronously — and it arrives through a
306
+ * callback from the render that started it. Accepted, it landed in whatever
307
+ * slot of the NEW paper had its index, and could report that paper fully
308
+ * scored though nobody had answered it. Ids cannot tell the papers apart: a
309
+ * new paper can reuse both the slot id and the activity id, and a loading
310
+ * blip reuses every id there is. `generation` can: it is the set the callback
311
+ * was handed out for, and it is refused unless that set is still current.
312
+ *
313
+ * **A slot that already holds an outcome is FINAL**: the first outcome wins,
314
+ * so a renderer that reports twice keeps what it reported first. There is one
315
+ * exception.
316
+ *
317
+ * **The exception is a `practice` read-aloud, and it is decided by `take`.**
318
+ * That slot records `responded` when a take is stored, because a take that
319
+ * comes back unscorable produces no grade at all and the slot would otherwise
320
+ * stay `null` for ever. Each take has a number (`mintTake`), unique on the page
321
+ * and larger for a later take, carried by everything the component reports
322
+ * about it. The invariant:
323
+ *
324
+ * **The score and the response a slot holds always describe the same take.**
325
+ *
326
+ * - A `responded` for a newer take replaces whatever the slot holds, a grade
327
+ * included: `onSubmit` has already told the host about that take, so a
328
+ * grade kept for the older one would sit beside a response it does not
329
+ * grade.
330
+ * - A `scored` lands only for the slot's latest take, once, and replaces that
331
+ * take's `responded`. A grade for any other take — one the learner has
332
+ * since replaced, even one still in flight when they did — is dropped
333
+ * rather than filed against a take it did not grade.
334
+ * - A `restored` slot is never replaced: it was submitted before this mount,
335
+ * and a resumed attempt must not be re-reported as if it had just been sat.
336
+ *
337
+ * A grade therefore lands once per take, and `onActivityComplete` — the
338
+ * per-item hook, keyed by `slotId` — only ever grades the answer `onSubmit`
339
+ * last reported for that slot. The whole-set callbacks stay once per set
340
+ * whatever is replaced — see `reportedRef`.
341
+ */
342
+ const record = (outcome, generation, take, tried) => {
343
+ const held = outcomesRef.current;
344
+ if (held === null || generation !== setGenerationRef.current) return;
345
+ const at = outcome.index;
346
+ const holding = held[at];
347
+ let accepted = outcome;
348
+ if (tried !== void 0) {
349
+ const latest = triedRef.current.get(at);
350
+ if (holding?.kind === "restored") return;
351
+ if (holding != null && (reportedRef.current || latest === void 0 || tried <= latest)) return;
352
+ triedRef.current.set(at, tried);
353
+ } else if (take === void 0) {
354
+ if (holding != null) return;
355
+ } else {
356
+ if (holding?.kind === "restored") return;
357
+ const latest = takesRef.current.get(at);
358
+ if (outcome.kind === "responded") {
359
+ if (latest !== void 0 && (take < latest.take || take === latest.take && latest.response !== void 0)) return;
360
+ takesRef.current.set(at, {
361
+ take,
362
+ state: latest?.take === take ? latest.state : "settled",
363
+ response: outcome.response
364
+ });
365
+ } else if (outcome.kind === "scored") {
366
+ if (latest?.take !== take || latest.response === void 0 || holding?.kind === "scored") return;
367
+ accepted = {
368
+ ...outcome,
369
+ response: latest.response
370
+ };
371
+ } else return;
372
+ }
373
+ const next = held.slice();
374
+ next[at] = accepted;
375
+ outcomesRef.current = next;
376
+ if (accepted.kind === "scored") onActivityComplete?.(accepted.result, accepted.index, accepted.slotId);
377
+ reportIfFinished();
378
+ };
379
+ /**
380
+ * The learner committed an answer to a slot: the body of the `onSubmit` every
381
+ * question is handed, the SDK's own components and a host's renderer alike.
382
+ */
383
+ const submitSlot = (generation, at, response) => {
384
+ if (generation !== setGenerationRef.current) return;
385
+ onSubmit?.(response, {
386
+ slotId: at.slotId,
387
+ index: at.index,
388
+ activityId: at.activityId
389
+ });
390
+ if (at.type === "written-response") return;
391
+ if (renderMode !== "practice") {
392
+ record({
393
+ kind: "responded",
394
+ index: at.index,
395
+ slotId: at.slotId,
396
+ activityId: at.activityId,
397
+ response
398
+ }, generation);
399
+ return;
400
+ }
401
+ if (at.type === "read-aloud") record({
402
+ kind: "responded",
403
+ index: at.index,
404
+ slotId: at.slotId,
405
+ activityId: at.activityId,
406
+ response
407
+ }, generation, require_useAiHelp.takeOf(response) ?? require_useAiHelp.mintTake());
408
+ };
409
+ /** A slot produced a grade: the body of the `onComplete` every question is handed. */
410
+ const completeSlot = (generation, at, result) => {
411
+ const takesAnswers = renderMode === "practice" && at.type === "read-aloud";
412
+ const outcome = {
413
+ kind: "scored",
414
+ index: at.index,
415
+ slotId: at.slotId,
416
+ activityId: at.activityId,
417
+ result
418
+ };
419
+ const tried = takesAnswers ? void 0 : require_useAiHelp.takeOf(result);
420
+ if (tried !== void 0 && renderMode === "practice") {
421
+ record(outcome, generation, void 0, tried);
422
+ return;
423
+ }
424
+ record(outcome, generation, takesAnswers ? require_useAiHelp.takeOf(result) ?? takesRef.current.get(at.index)?.take : void 0);
425
+ };
426
+ /**
427
+ * A host's question withdrew its answer. The slot holds nothing again — its
428
+ * outcome and, with it, the take any grade would be filed against — so the
429
+ * set is unfinished until it is answered again.
430
+ *
431
+ * A set already reported stays reported: the whole-set callbacks fire once,
432
+ * and a consumer who persists on them must not be handed one attempt twice.
433
+ */
434
+ const clearSlot = (generation, at) => {
435
+ const held = outcomesRef.current;
436
+ if (!aliveRef.current || held === null || generation !== setGenerationRef.current) return;
437
+ takesRef.current.delete(at.index);
438
+ if (held[at.index] == null) return;
439
+ const next = held.slice();
440
+ next[at.index] = null;
441
+ outcomesRef.current = next;
442
+ };
443
+ /** A host's question is waiting on work of its own, or has stopped waiting. */
444
+ const hostPending = (generation, at, pending) => {
445
+ if (!aliveRef.current || generation !== setGenerationRef.current) return;
446
+ const waiting = hostPendingRef.current;
447
+ if (pending) {
448
+ waiting.add(at.index);
449
+ return;
450
+ }
451
+ if (!waiting.delete(at.index)) return;
452
+ reportIfFinished();
453
+ };
454
+ /** A host's question reported an interaction: its activity and the moment, filled in. */
455
+ const emitFor = (generation, at, type, payload) => {
456
+ if (!aliveRef.current || generation !== setGenerationRef.current) return;
457
+ onInteraction?.({
458
+ type,
459
+ activityId: at.activityId,
460
+ timestamp: Date.now(),
461
+ payload: payload ?? {}
462
+ });
463
+ };
464
+ /**
465
+ * What a slot's channel reports: the state of one of its takes. A take older
466
+ * than the slot's latest has been replaced, and a report from a set that is
467
+ * no longer current, or reaching a pager that is unmounting, describes
468
+ * nothing on screen.
469
+ */
470
+ const updateTake = (generation, at, take, state) => {
471
+ if (!aliveRef.current || generation !== setGenerationRef.current) return;
472
+ const latest = takesRef.current.get(at);
473
+ if (latest !== void 0 && take < latest.take) return;
474
+ takesRef.current.set(at, latest?.take === take ? {
475
+ ...latest,
476
+ state
477
+ } : {
478
+ take,
479
+ state
480
+ });
481
+ reportIfFinished();
482
+ };
483
+ /**
484
+ * What a slot's channel reports: where its question is with its tries. One
485
+ * that stops offering or making a try may leave the set with nothing to wait
486
+ * for.
487
+ */
488
+ const updateTries = (generation, at, state) => {
489
+ if (!aliveRef.current || generation !== setGenerationRef.current) return;
490
+ const was = triesRef.current.get(at);
491
+ if (state === "none") triesRef.current.delete(at);
492
+ else triesRef.current.set(at, state);
493
+ if (was !== void 0 && was !== state) reportIfFinished();
494
+ };
495
+ latestRef.current = {
496
+ updateTake,
497
+ updateTries,
498
+ reportIfFinished,
499
+ submitSlot,
500
+ completeSlot,
501
+ clearSlot,
502
+ hostPending,
503
+ emit: emitFor
504
+ };
505
+ /**
506
+ * The calls one slot makes, made once per slot per set. They reach the latest
507
+ * render through `latestRef`, so they can keep one identity while the props
508
+ * they report to change — what a host renderer needs to hold them in an
509
+ * effect, and what the pager needs so a host that re-renders on every
510
+ * keystroke does not re-run one.
511
+ */
512
+ const callsFor = (slot) => {
513
+ const key = `${slot.index}::${slot.slotId}`;
514
+ let calls = callsRef.current.get(key);
515
+ if (calls === void 0) {
516
+ const generation = setGeneration;
517
+ const at = {
518
+ slotId: slot.slotId,
519
+ index: slot.index,
520
+ activityId: slot.activity.id,
521
+ type: slot.activity.type
522
+ };
523
+ calls = {
524
+ slot: {
525
+ slotId: at.slotId,
526
+ index: at.index,
527
+ activityId: at.activityId
528
+ },
529
+ onSubmit: (response) => latestRef.current?.submitSlot(generation, at, response),
530
+ onComplete: (result) => latestRef.current?.completeSlot(generation, at, result),
531
+ clear: () => latestRef.current?.clearSlot(generation, at),
532
+ setPending: (pending) => latestRef.current?.hostPending(generation, at, pending === true),
533
+ emit: (type, payload) => latestRef.current?.emit(generation, at, type, payload)
534
+ };
535
+ callsRef.current.set(key, calls);
536
+ }
537
+ return calls;
538
+ };
539
+ /**
540
+ * Where a host-drawn question portals: a node inside its own pane, so it is
541
+ * hidden with the question it belongs to and painted with it in fullscreen.
542
+ * One ref callback per slot, kept, because a new one each render detaches and
543
+ * re-attaches the node on every commit.
544
+ */
545
+ const portalRefFor = (key) => {
546
+ let callback = portalRefsRef.current.get(key);
547
+ if (callback === void 0) {
548
+ callback = (node) => {
549
+ setPortals((held) => {
550
+ if (node === null) {
551
+ if (!held.has(key)) return held;
552
+ const next = new Map(held);
553
+ next.delete(key);
554
+ return next;
555
+ }
556
+ if (held.get(key) === node) return held;
557
+ const next = new Map(held);
558
+ next.set(key, node);
559
+ return next;
560
+ });
561
+ };
562
+ portalRefsRef.current.set(key, callback);
563
+ }
564
+ return callback;
565
+ };
566
+ /** The channel a slot's pane hands its content: its capture group and its takes. */
567
+ const channelFor = (slot) => {
568
+ const key = `${slot.index}::${slot.slotId}`;
569
+ let channel = channelsRef.current.get(key);
570
+ if (channel === void 0) {
571
+ const generation = setGeneration;
572
+ const at = slot.index;
573
+ channel = {
574
+ captureGroup: `${captureScope}::${slot.slotId}`,
575
+ get renderMode() {
576
+ return modeRef.current;
577
+ },
578
+ get delivery() {
579
+ return deliveryRef.current;
580
+ },
581
+ get scoring() {
582
+ return scoringRef.current;
583
+ },
584
+ get triesClosed() {
585
+ return reportedRef.current;
586
+ },
587
+ triesState: (state) => {
588
+ latestRef.current?.updateTries(generation, at, state);
589
+ },
590
+ takeState: (take, state) => {
591
+ latestRef.current?.updateTake(generation, at, take, state);
592
+ }
593
+ };
594
+ channelsRef.current.set(key, channel);
595
+ }
596
+ return channel;
597
+ };
598
+ if (!current) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "lk-seq" });
599
+ const budgetedMedia = slots.flatMap((slot) => {
600
+ const found = [];
601
+ const own = slot.activity.media;
602
+ if (own !== void 0 && (0, _intellectif_lk_core.resolvePlaybackPolicy)(own).maxPlays !== null) found.push({
603
+ key: (0, _intellectif_lk_core.slotMediaKey)(slot.slotId),
604
+ url: own.url
605
+ });
606
+ const stimulus = slot.group?.stimulus.media;
607
+ if (stimulus !== void 0 && (0, _intellectif_lk_core.resolvePlaybackPolicy)(stimulus).maxPlays !== null) found.push({
608
+ key: (0, _intellectif_lk_core.stimulusMediaKey)(slot.slotId),
609
+ url: stimulus.url
610
+ });
611
+ return found;
612
+ });
613
+ const budgetEnforced = mediaBudget?.enforced ?? renderMode !== "review";
614
+ if (budgetedMedia.length > 0 && renderMode === "exam" && budgetEnforced) {
615
+ if (mediaBudget?.onPlayConsumed === void 0) throw new Error(`ActivitySequence: renderMode "exam" with media that declares \`maxPlays\` requires \`mediaBudget.onPlayConsumed\`. The SDK persists nothing, so without it the count lives only in this mount: a refresh silently restores the full budget, and a paper that grants unlimited plays while showing "2 plays remaining" is indistinguishable — to the learner and to an appeal — from one that works. Budgeted media: ${[...new Set(budgetedMedia.map((m) => m.key))].join(", ")}.`);
616
+ if ((responses !== void 0 && Object.keys(responses).length > 0 || submittedSlotIds !== void 0 && submittedSlotIds.length > 0) && mediaBudget.plays === void 0) throw new Error("ActivitySequence: this is a resumed attempt (`responses`/`submittedSlotIds` were supplied) but `mediaBudget.plays` is absent. A resume that omits the ledger hands the learner a fresh budget at exactly the moment it matters. Pass `restoreMediaPlayLedger(plan, stored).entries`, or `{}` to state explicitly that nothing was spent.");
617
+ }
618
+ const keysByUrl = /* @__PURE__ */ new Map();
619
+ for (const { key, url } of budgetedMedia) {
620
+ const keys = keysByUrl.get(url) ?? /* @__PURE__ */ new Set();
621
+ keys.add(key);
622
+ keysByUrl.set(url, keys);
623
+ }
624
+ for (const [url, keys] of keysByUrl) if (keys.size > 1) throw new Error(`ActivitySequence: media ${JSON.stringify(url)} is budgeted under ${keys.size} separate keys (${[...keys].join(", ")}), so one recording grants ${keys.size} × maxPlays. Put the questions that share a recording in an item group — a group's stimulus is one recording with one budget.`);
625
+ /** The per-media binding handed to a component or to the stimulus panel. */
626
+ const bindingFor = (key, slot) => {
627
+ if (mediaBudget === void 0) return;
628
+ const entry = mediaSeedsApply && mediaPlays !== void 0 && Object.hasOwn(mediaPlays, key) ? mediaPlays[key] : void 0;
629
+ return {
630
+ key,
631
+ slotId: slot.slotId,
632
+ index: slot.index,
633
+ activityId: slot.activity.id,
634
+ ...entry !== void 0 ? { entry } : {},
635
+ ...mediaBudget.enforced !== void 0 ? { enforced: mediaBudget.enforced } : {},
636
+ ...mediaBudget.onPlayConsumed !== void 0 ? { onPlayConsumed: mediaBudget.onPlayConsumed } : {},
637
+ ...mediaBudget.onPlayRefunded !== void 0 ? { onPlayRefunded: mediaBudget.onPlayRefunded } : {},
638
+ ...mediaBudget.onPosition !== void 0 ? { onPosition: mediaBudget.onPosition } : {},
639
+ ...mediaBudget.strings !== void 0 ? { strings: mediaBudget.strings } : {}
640
+ };
641
+ };
642
+ /**
643
+ * The per-slot recording binding handed to a read-aloud, modelled on
644
+ * `bindingFor`: the sequence-level methods are called with the slot they
645
+ * belong to, and `assess` / `playbackUrl` are copied only when the consumer
646
+ * supplied them — a binding carrying `assess: undefined` is a binding the
647
+ * component would try to call.
648
+ *
649
+ * It watches nothing. The pager used to watch the promises it handed out to
650
+ * decide when a set was finished, and a promise knows nothing of the take
651
+ * that asked for it: a late failure from a paper no longer on screen landed
652
+ * in a new paper that reused the slot's ids, as a blank. What a take came to
653
+ * is reported by the component, numbered by take, through the slot's channel
654
+ * — see `record` and `reportIfFinished`.
655
+ *
656
+ * A consumer's own renderer is handed no binding.
657
+ */
658
+ const recordingBindingFor = (slot) => {
659
+ if (recordingBinding === void 0) return;
660
+ const at = {
661
+ slotId: slot.slotId,
662
+ index: slot.index,
663
+ activityId: slot.activity.id
664
+ };
665
+ const { assess, playbackUrl } = recordingBinding;
666
+ return {
667
+ upload: (take) => recordingBinding.upload(take, at),
668
+ ...assess !== void 0 ? { assess: (ref) => assess.call(recordingBinding, ref, at) } : {},
669
+ ...playbackUrl !== void 0 ? { playbackUrl: (ref) => playbackUrl.call(recordingBinding, ref, at) } : {}
670
+ };
671
+ };
672
+ const forwarded = {
673
+ ...onInteraction ? { onInteraction } : {},
674
+ renderMode,
675
+ ...sanitizeHtml ? { sanitizeHtml } : {},
676
+ ...strings !== void 0 ? { strings } : {},
677
+ ...ai !== void 0 && renderMode !== "exam" ? { ai } : {},
678
+ ...delivery !== void 0 && delivery !== null ? { delivery } : {},
679
+ ...scoring !== void 0 && scoring !== null ? { scoring } : {},
680
+ ...theme ? { theme } : {},
681
+ ...locale ? { locale } : {},
682
+ ...disabled ? { disabled } : {}
683
+ };
684
+ const renderSlot = (slot) => {
685
+ const activity = slot.activity;
686
+ const { slotId, index: slotIndex } = slot;
687
+ const activityId = activity.id;
688
+ const restored = seedsApply && responses !== void 0 && Object.hasOwn(responses, slotId) ? responses[slotId] : void 0;
689
+ const slotOutcome = outcomes !== void 0 && Object.hasOwn(outcomes, slotId) ? outcomes[slotId] : void 0;
690
+ const slotBinding = bindingFor((0, _intellectif_lk_core.slotMediaKey)(slotId), slot);
691
+ const calls = callsFor(slot);
692
+ const childProps = {
693
+ ...restored !== void 0 ? { defaultValue: restored } : {},
694
+ ...seedsApply && submitted.has(slotId) ? { defaultSubmitted: true } : {},
695
+ ...slotOutcome !== void 0 ? { outcome: slotOutcome } : {},
696
+ onComplete: calls.onComplete,
697
+ onSubmit: calls.onSubmit,
698
+ ...forwarded,
699
+ ...slotBinding !== void 0 ? { mediaBudget: slotBinding } : {}
700
+ };
701
+ const CustomRenderer = renderers?.[activity.type];
702
+ if (CustomRenderer) {
703
+ const portalKey = slotKeyOf(setKey, slot);
704
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CustomRenderer, {
705
+ data: activity,
706
+ ...childProps,
707
+ question: {
708
+ slot: calls.slot,
709
+ active: slotIndex === index,
710
+ portalContainer: portals.get(portalKey) ?? null,
711
+ clear: calls.clear,
712
+ setPending: calls.setPending,
713
+ emit: calls.emit
714
+ }
715
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
716
+ className: "lk-seq-portal",
717
+ ref: portalRefFor(portalKey)
718
+ })] });
719
+ }
720
+ if (activity.type === "multiple-choice") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_MultipleChoice.MultipleChoice, {
721
+ data: activity,
722
+ ...shuffleSeed !== void 0 ? { shuffleSeed } : {},
723
+ ...childProps
724
+ });
725
+ if (activity.type === "fill-in-the-blanks") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_FillInTheBlanks.FillInTheBlanks, {
726
+ data: activity,
727
+ ...childProps
728
+ });
729
+ if (activity.type === "gap-select") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_GapSelect.GapSelect, {
730
+ data: activity,
731
+ ...shuffleSeed !== void 0 ? { shuffleSeed } : {},
732
+ ...childProps
733
+ });
734
+ if (activity.type === "dictation") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Dictation.Dictation, {
735
+ data: activity,
736
+ ...childProps
737
+ });
738
+ if (activity.type === "read-aloud") {
739
+ const slotRecordingBinding = recordingBindingFor(slot);
740
+ const slotAssessment = assessments !== void 0 && Object.hasOwn(assessments, slotId) ? assessments[slotId] : void 0;
741
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_ReadAloud.ReadAloud, {
742
+ data: activity,
743
+ ...childProps,
744
+ ...slotRecordingBinding !== void 0 ? { recordingBinding: slotRecordingBinding } : {},
745
+ ...slotAssessment !== void 0 ? { assessment: slotAssessment } : {},
746
+ ...workletUrl !== void 0 ? { workletUrl } : {}
747
+ });
748
+ }
749
+ if (activity.type === "written-response") {
750
+ const { onComplete: _neverGrades, ...writtenResponseProps } = childProps;
751
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_WrittenResponse.WrittenResponse, {
752
+ data: activity,
753
+ ...writtenResponseProps,
754
+ onSubmitted: (submission) => record({
755
+ kind: "submitted",
756
+ index: slotIndex,
757
+ slotId,
758
+ activityId,
759
+ submission
760
+ }, setGeneration)
761
+ });
762
+ }
763
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
764
+ className: "lk-seq-unsupported",
765
+ role: "note",
766
+ children: s.unsupportedActivity
767
+ });
768
+ };
769
+ const currentEntryKey = entryKeyOf(current);
770
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
771
+ className: "lk-seq",
772
+ lang: locale,
773
+ children: [
774
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
775
+ className: "lk-seq-progress",
776
+ "aria-live": "polite",
777
+ role: "status",
778
+ children: s.questionProgress(index + 1, total)
779
+ }),
780
+ stimulusMounts.map(({ entryKey, group, first, last }) => {
781
+ const firstSlot = slots[first];
782
+ const stimulusBinding = firstSlot === void 0 ? void 0 : bindingFor((0, _intellectif_lk_core.stimulusMediaKey)(firstSlot.slotId), firstSlot);
783
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SequencePane, {
784
+ className: "lk-seq-stimulus",
785
+ hidden: entryKey !== currentEntryKey,
786
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_StimulusPanel.StimulusPanel, {
787
+ stimulus: group.stimulus,
788
+ range: {
789
+ first: first + 1,
790
+ last: last + 1
791
+ },
792
+ renderMode,
793
+ ...sanitizeHtml ? { sanitizeHtml } : {},
794
+ ...locale ? { locale } : {},
795
+ ...onInteraction ? { onInteraction } : {},
796
+ ...disabled ? { disabled } : {},
797
+ ...strings !== void 0 ? { strings } : {},
798
+ ...stimulusBinding !== void 0 ? { mediaBudget: stimulusBinding } : {}
799
+ })
800
+ }, `${setKey}::group-${entryKey}`);
801
+ }),
802
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
803
+ className: "lk-seq-question",
804
+ ref: regionRef,
805
+ tabIndex: -1,
806
+ "aria-label": s.questionProgress(index + 1, total),
807
+ children: slots.map((slot) => {
808
+ const slotKey = slotKeyOf(setKey, slot);
809
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SequencePane, {
810
+ className: "lk-seq-slot",
811
+ hidden: slot.index !== index,
812
+ channel: channelFor(slot),
813
+ children: renderSlot(slot)
814
+ }, slotKey);
815
+ })
816
+ }),
817
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
818
+ className: "lk-seq-nav",
819
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
820
+ type: "button",
821
+ className: "lk-seq-prev",
822
+ onClick: () => go(index - 1),
823
+ disabled: index === 0,
824
+ children: s.previous
825
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
826
+ type: "button",
827
+ className: "lk-seq-next",
828
+ onClick: () => go(index + 1),
829
+ disabled: index === total - 1,
830
+ children: s.next
831
+ })]
832
+ })
833
+ ]
834
+ });
835
+ }
836
+ //#endregion
837
+ Object.defineProperty(exports, "ActivitySequence", {
838
+ enumerable: true,
839
+ get: function() {
840
+ return ActivitySequence;
841
+ }
842
+ });
843
+
844
+ //# sourceMappingURL=ActivitySequence-CmoSyDnp.cjs.map