@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,831 @@
1
+ 'use client';
2
+ const require_ai_LkAiProvider = require("./ai/LkAiProvider.cjs");
3
+ const require_useAiHelp = require("./useAiHelp-h9yOLFqt.cjs");
4
+ const require_LkIntlProvider = require("./LkIntlProvider-oi57lYB0.cjs");
5
+ const require_ActivityErrorBoundary = require("./ActivityErrorBoundary-B379hvtL.cjs");
6
+ const require_direction = require("./direction-K1pj0HCA.cjs");
7
+ let react = require("react");
8
+ let react_jsx_runtime = require("react/jsx-runtime");
9
+ let _intellectif_lk_core = require("@intellectif/lk-core");
10
+ //#region src/components/shared/AiCoaching.tsx
11
+ /**
12
+ * "Coach me on this reading": the SDK's own surface over {@link useAiCoaching}
13
+ * — a button, the coaching with who wrote it, and "not available" when a call
14
+ * fails or its answer is refused. `<PronunciationFeedback>` renders it under
15
+ * the marks it shows, and `<ReadAloud>` under the marks a review reads back
16
+ * from a stored grade.
17
+ *
18
+ * Each word coached is shown as the marks show it, in the reading's own
19
+ * language and direction; its tip is in the learner's. Nothing renders without
20
+ * a port, or where the rules say no coaching.
21
+ */
22
+ function ReadingCoaching({ strings: s, contentLang, contentDir, ...input }) {
23
+ const help = require_useAiHelp.useAiCoaching(input);
24
+ const buttonRef = (0, react.useRef)(null);
25
+ const panelRef = (0, react.useRef)(null);
26
+ const refocus = (0, react.useRef)(false);
27
+ (0, react.useEffect)(() => {
28
+ if (help.status === "shown" && refocus.current) {
29
+ refocus.current = false;
30
+ panelRef.current?.focus();
31
+ }
32
+ if (help.status === "unavailable") refocus.current = false;
33
+ }, [help.status]);
34
+ if (!help.offered) return null;
35
+ const ask = () => {
36
+ refocus.current = typeof document !== "undefined" && document.activeElement === buttonRef.current;
37
+ help.ask();
38
+ };
39
+ const loading = help.status === "loading";
40
+ const coaching = help.coaching;
41
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
42
+ className: "lk-ai lk-ai-coaching",
43
+ "data-state": help.status,
44
+ children: [coaching === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
45
+ ref: buttonRef,
46
+ type: "button",
47
+ className: "lk-ai-button",
48
+ "aria-busy": loading || void 0,
49
+ "aria-disabled": loading || void 0,
50
+ onClick: ask,
51
+ children: loading ? s.aiCoachingLoading : s.aiCoaching
52
+ }) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
53
+ "aria-live": "polite",
54
+ children: coaching !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
55
+ ref: panelRef,
56
+ className: "lk-ai-panel",
57
+ tabIndex: -1,
58
+ "aria-label": s.aiCoachingHeading,
59
+ children: [
60
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
61
+ className: "lk-ai-heading",
62
+ children: s.aiCoachingHeading
63
+ }),
64
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
65
+ className: "lk-ai-text",
66
+ children: coaching.text
67
+ }),
68
+ coaching.words.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
69
+ className: "lk-ai-coaching-words",
70
+ "aria-label": s.aiCoachingWords,
71
+ children: coaching.words.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
72
+ className: "lk-ai-coaching-word",
73
+ children: [
74
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
75
+ className: "lk-ai-coaching-target",
76
+ dir: contentDir ?? "auto",
77
+ lang: contentLang,
78
+ children: entry.word
79
+ }),
80
+ entry.sound !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
81
+ className: "lk-ai-coaching-sound",
82
+ children: s.aiCoachingSound(entry.sound.expected, entry.sound.heard)
83
+ }) : null,
84
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
85
+ className: "lk-ai-text",
86
+ children: entry.tip
87
+ })
88
+ ]
89
+ }, entry.itemId))
90
+ }) : null,
91
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
92
+ className: "lk-ai-notice",
93
+ children: s.aiNotice
94
+ })
95
+ ]
96
+ }) : help.status === "unavailable" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
97
+ className: "lk-ai-unavailable",
98
+ children: s.aiCoachingUnavailable
99
+ }) : null
100
+ })]
101
+ });
102
+ }
103
+ //#endregion
104
+ //#region src/components/shared/playback-refusal.ts
105
+ /**
106
+ * Whether the page refused to play the learner's own take, and the handler
107
+ * every element that plays it reports a refusal through.
108
+ *
109
+ * The take is played from a `blob:` URL — the preview of a take not yet sent —
110
+ * or from a link a review minted, and a page can refuse either without a word:
111
+ * a Content-Security-Policy whose `media-src` does not allow `blob:` blocks the
112
+ * load, the element fires `error`, and every control that plays it goes on
113
+ * looking as if it works. So the refusal is decided in one place, by the URL
114
+ * that was refused: a new take is a new URL and starts out playable again, and
115
+ * a refusal an element reports after it was handed another URL cannot mark the
116
+ * new one.
117
+ *
118
+ * `refuse` takes the element, not the URL, and reads the address the element
119
+ * is loading at the moment it fails: an `error` belongs to the source the
120
+ * element holds when it fires, and a closure's URL may already be a render
121
+ * behind it.
122
+ */
123
+ function usePlaybackRefusal(url) {
124
+ const [refusedUrl, setRefusedUrl] = (0, react.useState)(null);
125
+ const refuse = (0, react.useCallback)((element) => {
126
+ const source = element.getAttribute("src");
127
+ if (source !== null) setRefusedUrl(source);
128
+ }, []);
129
+ return {
130
+ refused: url !== null && url !== void 0 && url === refusedUrl,
131
+ refuse
132
+ };
133
+ }
134
+ /**
135
+ * Whether a rejected `play()` is the page refusing the source, rather than an
136
+ * autoplay policy refusing the gesture. Only the first is the take's to report:
137
+ * an autoplay refusal says nothing about whether the take can be played.
138
+ */
139
+ function isSourceRefusal(error) {
140
+ return typeof error === "object" && error !== null && error.name === "NotSupportedError";
141
+ }
142
+ //#endregion
143
+ //#region src/components/shared/read-grade.ts
144
+ /**
145
+ * Every dimension a read-aloud grade can weigh, in the order a learner reads
146
+ * them: what was said, how it flowed, how much of it was there, and how it was
147
+ * pitched. Fixed rather than derived from the evidence, so a dimension the
148
+ * engine did not measure is reported as unmeasured instead of vanishing.
149
+ */
150
+ const DIMENSIONS = [
151
+ "accuracy",
152
+ "fluency",
153
+ "completeness",
154
+ "prosody"
155
+ ];
156
+ const OUTCOMES = [
157
+ "correct",
158
+ "incorrect",
159
+ "correct-omission",
160
+ "incorrect-omission"
161
+ ];
162
+ /**
163
+ * How far past its own maximum a score may sit and still be read as that
164
+ * maximum. A grader that sums weighted parts lands on `1.0000000000000002`
165
+ * for a perfect take as readily as on `1`, and "could not be graded" is the
166
+ * wrong thing to tell the learner who earned it. Far below any difference a
167
+ * whole percentage can show.
168
+ */
169
+ const OVERSHOOT = 1e-9;
170
+ function isRecord(value) {
171
+ return typeof value === "object" && value !== null && !Array.isArray(value);
172
+ }
173
+ function isFiniteNumber(value) {
174
+ return typeof value === "number" && Number.isFinite(value);
175
+ }
176
+ /** An optional field a backend left out, written either way it writes one. */
177
+ function isAbsent(value) {
178
+ return value === void 0 || value === null;
179
+ }
180
+ /** A score on `0..max`, a hair of overshoot read as `max`; `null` for anything else. */
181
+ function withinMax(score, max) {
182
+ if (!isFiniteNumber(score) || score < 0) return null;
183
+ if (score <= max) return score;
184
+ return score - max <= max * OVERSHOOT ? max : null;
185
+ }
186
+ /** A learner's or a reference response: a string, or strings. */
187
+ function isResponse(value) {
188
+ return typeof value === "string" || Array.isArray(value) && value.every((entry) => typeof entry === "string");
189
+ }
190
+ /** Runs a read that touches a host's object, whose getters may throw. */
191
+ function guarded(read, refused) {
192
+ try {
193
+ return read();
194
+ } catch {
195
+ return refused;
196
+ }
197
+ }
198
+ function readCriterion(value) {
199
+ if (!isRecord(value) || typeof value.name !== "string") return null;
200
+ const { maxScore, notApplicable } = value;
201
+ if (!isAbsent(maxScore) && !(isFiniteNumber(maxScore) && maxScore > 0)) return null;
202
+ if (!isAbsent(notApplicable) && typeof notApplicable !== "boolean") return null;
203
+ const score = isAbsent(value.score) ? void 0 : withinMax(value.score, maxScore ?? 1);
204
+ if (score === null) return null;
205
+ return {
206
+ name: value.name,
207
+ ...score !== void 0 ? { score } : {},
208
+ ...!isAbsent(maxScore) ? { maxScore } : {},
209
+ ...notApplicable === true ? { notApplicable } : {}
210
+ };
211
+ }
212
+ function readDetail(value) {
213
+ if (!isRecord(value)) return null;
214
+ const { itemId, correct, outcome, learnerResponse, correctResponse, weight, score } = value;
215
+ if (typeof itemId !== "string" || !isResponse(learnerResponse) || !isResponse(correctResponse)) return null;
216
+ const checkedOutcome = OUTCOMES.find((known) => known === outcome);
217
+ if (!isAbsent(outcome) && checkedOutcome === void 0) return null;
218
+ if (!isAbsent(correct) && typeof correct !== "boolean") return null;
219
+ if (checkedOutcome === void 0 && typeof correct !== "boolean") return null;
220
+ if (!isAbsent(weight) && !isFiniteNumber(weight)) return null;
221
+ const checkedScore = isAbsent(score) ? void 0 : withinMax(score, 1);
222
+ if (checkedScore === null) return null;
223
+ return {
224
+ itemId,
225
+ learnerResponse,
226
+ correctResponse,
227
+ ...checkedOutcome !== void 0 ? { outcome: checkedOutcome } : { correct },
228
+ ...!isAbsent(weight) ? { weight } : {},
229
+ ...checkedScore !== void 0 ? { score: checkedScore } : {}
230
+ };
231
+ }
232
+ function readDetails(value) {
233
+ if (!Array.isArray(value)) return;
234
+ const details = [];
235
+ for (const entry of value) {
236
+ const detail = readDetail(entry);
237
+ if (detail === null) return;
238
+ details.push(detail);
239
+ }
240
+ return details;
241
+ }
242
+ /**
243
+ * A host's grade as a checked copy, or `null` when it carries no grade that can
244
+ * be shown or reported. See the module notes for the rules.
245
+ */
246
+ function readGrade(value) {
247
+ return guarded(() => {
248
+ if (!isRecord(value)) return null;
249
+ const { maxScore, passed } = value;
250
+ if (!isFiniteNumber(maxScore) || maxScore <= 0 || typeof passed !== "boolean") return null;
251
+ const score = withinMax(value.score, maxScore);
252
+ if (score === null) return null;
253
+ const criteria = Array.isArray(value.criteria) ? value.criteria.flatMap((entry) => {
254
+ const criterion = readCriterion(entry);
255
+ return criterion === null ? [] : [criterion];
256
+ }) : void 0;
257
+ const details = readDetails(value.details);
258
+ return {
259
+ score,
260
+ maxScore,
261
+ passed,
262
+ feedback: typeof value.feedback === "string" ? value.feedback : null,
263
+ ...criteria !== void 0 ? { criteria } : {},
264
+ ...details !== void 0 ? { details } : {}
265
+ };
266
+ }, null);
267
+ }
268
+ /** A read grade as a fraction of 1: in `0..1`, because the reader made it so. */
269
+ function fractionOfGrade(grade) {
270
+ return grade.score / grade.maxScore;
271
+ }
272
+ /** A read grade as a whole percentage: in `0..100`, because the reader made it so. */
273
+ function percentOfGrade(grade) {
274
+ return Math.round(fractionOfGrade(grade) * 100);
275
+ }
276
+ /**
277
+ * A stored outcome as a renderer may show it, or `undefined` for none —
278
+ * `null` included, which is how a backend writes an absent optional.
279
+ *
280
+ * A `graded` outcome is read through its `grade`, the record
281
+ * `outcomeFromGrade` mirrors onto it, so the summary and the panel beside it
282
+ * can never show two different numbers; and it must be well-formed as a whole,
283
+ * its own `score`, `maxScore` and `passed` included — a payload with a corrupt
284
+ * copy of the grade is not one to pick a side of.
285
+ */
286
+ function readOutcome(value) {
287
+ if (isAbsent(value)) return;
288
+ return guarded(() => {
289
+ if (!isRecord(value)) return {
290
+ kind: "unreadable",
291
+ status: void 0
292
+ };
293
+ switch (value.status) {
294
+ case "deferred": return { kind: "deferred" };
295
+ case "unscorable": return {
296
+ kind: "unscorable",
297
+ code: typeof value.code === "string" ? value.code : void 0
298
+ };
299
+ case "scored": {
300
+ const grade = readGrade(value);
301
+ return grade === null ? {
302
+ kind: "unreadable",
303
+ status: "scored"
304
+ } : {
305
+ kind: "graded",
306
+ status: "scored",
307
+ grade
308
+ };
309
+ }
310
+ case "graded": {
311
+ const grade = readGrade(value.grade);
312
+ return grade === null || readGrade(value) === null ? {
313
+ kind: "unreadable",
314
+ status: "graded"
315
+ } : {
316
+ kind: "graded",
317
+ status: "graded",
318
+ grade
319
+ };
320
+ }
321
+ default: return {
322
+ kind: "unreadable",
323
+ status: void 0
324
+ };
325
+ }
326
+ }, {
327
+ kind: "unreadable",
328
+ status: void 0
329
+ });
330
+ }
331
+ /**
332
+ * An assessor's answer as a renderer and a statement may use it.
333
+ *
334
+ * `failed` and `unscorable` need little: a `retryable` that is not `true`
335
+ * offers no retry, which never spends an application's money on a guess, and a
336
+ * `code` that is not a string is no code. Everything else — a `graded` result,
337
+ * and anything that is not an object or names no status this component knows —
338
+ * is read as a judgement: its grade when one can be read, its evidence when it
339
+ * is an object. A judgement with neither is shown as could-not-be-graded.
340
+ */
341
+ function readAssessResult(value) {
342
+ const nothing = {
343
+ status: "graded",
344
+ grade: null,
345
+ assessment: null,
346
+ recognizedText: void 0
347
+ };
348
+ return guarded(() => {
349
+ if (!isRecord(value)) return nothing;
350
+ if (value.status === "failed") return {
351
+ status: "failed",
352
+ retryable: value.retryable === true
353
+ };
354
+ if (value.status === "unscorable") return {
355
+ status: "unscorable",
356
+ code: typeof value.code === "string" ? value.code : void 0
357
+ };
358
+ if (value.status !== "graded") return nothing;
359
+ const assessment = readEvidence(value.assessment);
360
+ const recognizedText = guarded(() => typeof assessment?.recognizedText === "string" ? assessment.recognizedText : void 0, void 0);
361
+ return {
362
+ status: "graded",
363
+ grade: readGrade(value.grade),
364
+ assessment,
365
+ recognizedText
366
+ };
367
+ }, nothing);
368
+ }
369
+ /**
370
+ * Evidence worth handing to the panel: an object. Whether it validates is the
371
+ * panel's to decide, because what a refusal costs differs by mode.
372
+ */
373
+ function readEvidence(value) {
374
+ return isRecord(value) ? value : null;
375
+ }
376
+ /** One criterion's whole percentage of its own maximum, or `undefined` when it carries none. */
377
+ function percentOfCriterion(criterion) {
378
+ if (criterion.notApplicable === true || criterion.score === void 0) return;
379
+ return Math.round(criterion.score / (criterion.maxScore ?? 1) * 100);
380
+ }
381
+ /**
382
+ * The dimension rows, from one source for the whole set and never a mix: the
383
+ * grade's criteria when it has any it can read, and the evidence's own scores
384
+ * otherwise. A dimension pulled out of the evidence and set beside graded ones
385
+ * would read as if it had counted towards the grade.
386
+ *
387
+ * The evidence is read as defensively as the grade: in production the panel
388
+ * shows these rows even for evidence the validator refused, which can carry
389
+ * anything at all under `scores`. `scale` is 100 by schema, so an evidence
390
+ * score is already a percentage — and one outside `0..100` is not one.
391
+ */
392
+ function readDimensions(assessment, grade) {
393
+ const criteria = grade?.criteria ?? [];
394
+ if (criteria.length > 0) return DIMENSIONS.map((dimension) => {
395
+ const criterion = criteria.find((entry) => entry.name === dimension);
396
+ return {
397
+ dimension,
398
+ percent: criterion === void 0 ? void 0 : percentOfCriterion(criterion)
399
+ };
400
+ });
401
+ const scores = guarded(() => isRecord(assessment) ? assessment.scores : void 0, void 0);
402
+ return DIMENSIONS.map((dimension) => {
403
+ const score = withinMax(guarded(() => isRecord(scores) ? scores[dimension] : void 0, void 0), 100);
404
+ return {
405
+ dimension,
406
+ percent: score === null ? void 0 : Math.round(score)
407
+ };
408
+ });
409
+ }
410
+ //#endregion
411
+ //#region src/components/PronunciationFeedback/PronunciationFeedback.tsx
412
+ /**
413
+ * Present for assistive technology, invisible on screen. Inline rather than
414
+ * left to the optional skin, for the reason `<Dictation>` gives: the per-word
415
+ * sentences are the marks' only channel for a screen reader, and a page that
416
+ * does not load the skin would otherwise show every one of them beside its
417
+ * word. Exported so `<ReadAloud>`, whose review fallback renders the same
418
+ * marks from stored details, carries one definition rather than a copy.
419
+ */
420
+ const VISUALLY_HIDDEN = {
421
+ position: "absolute",
422
+ width: 1,
423
+ height: 1,
424
+ margin: -1,
425
+ padding: 0,
426
+ overflow: "hidden",
427
+ clip: "rect(0 0 0 0)",
428
+ clipPath: "inset(50%)",
429
+ whiteSpace: "nowrap",
430
+ border: 0
431
+ };
432
+ /** The four marking states, in the order the legend lists them. */
433
+ const LEGEND_STATES = [
434
+ "correct",
435
+ "mispronounced",
436
+ "omitted",
437
+ "inserted"
438
+ ];
439
+ /**
440
+ * What the validator says about evidence that may not even be readable. Its
441
+ * cross-field rules read the value directly, so a getter that throws escapes
442
+ * it — and evidence that cannot be read is evidence refused, not a reason to
443
+ * take the grade beside it down.
444
+ */
445
+ function checkEvidence(assessment) {
446
+ try {
447
+ return (0, _intellectif_lk_core.validateSpeechAssessment)(assessment);
448
+ } catch {
449
+ return {
450
+ success: false,
451
+ errors: [{
452
+ path: [],
453
+ message: "The assessment could not be read.",
454
+ code: "unreadable"
455
+ }]
456
+ };
457
+ }
458
+ }
459
+ /** Whether a word carries anything a disclosure would have to show. */
460
+ function hasDetail(word) {
461
+ if (word === void 0) return false;
462
+ return word.accuracy !== void 0 || word.syllables !== void 0 && word.syllables.length > 0 || word.phonemes !== void 0 && word.phonemes.length > 0 || word.breaks !== void 0 || typeof word.startMs === "number" && typeof word.durationMs === "number";
463
+ }
464
+ /** A confidence that clears the caller's threshold. No threshold, no note. */
465
+ function past(confidence, threshold) {
466
+ return threshold !== void 0 && typeof confidence === "number" && Number.isFinite(confidence) && confidence > threshold;
467
+ }
468
+ /** One phoneme, named by its symbol or — when the engine named none — by its place. */
469
+ function phonemeLabel(phoneme, index, s) {
470
+ return phoneme.symbol ?? s.pronunciationPhonemePosition(index + 1);
471
+ }
472
+ /**
473
+ * What a screen reader hears for one marked word — the marks' only channel for
474
+ * assistive technology, since the glyph and the decoration are both hidden from
475
+ * it. Exported because `<ReadAloud>`'s review fallback marks the same four
476
+ * states from stored details, and a second copy of these four sentences would
477
+ * be a second thing to translate.
478
+ *
479
+ * Branches on `state` and **never** on `heard === ''`: an inserted word whose
480
+ * text normalises to nothing carries the empty string too, and would otherwise
481
+ * be announced as an omission.
482
+ */
483
+ function markSentence(entry, s) {
484
+ switch (entry.state) {
485
+ case "correct": return s.pronunciationWordCorrect(entry.reference);
486
+ case "mispronounced": return s.pronunciationWordMispronounced(entry.reference);
487
+ case "omitted": return s.pronunciationWordOmitted(entry.reference);
488
+ default: return s.pronunciationWordInserted(entry.heard);
489
+ }
490
+ }
491
+ /**
492
+ * The per-word marks of a read-aloud take, plus the dimensions they were
493
+ * graded on.
494
+ *
495
+ * **A bad assessment never destroys a good grade.** `alignReadAloud` throws a
496
+ * `TypeError` for evidence `validateSpeechAssessment` refuses, so this
497
+ * component runs the validator first. In development the refusal is thrown as
498
+ * an `ActivitySchemaError`, which is the package's dev-error convention and
499
+ * puts the problem in front of whoever wired the adapter up. In production the
500
+ * dimensions and the grade are rendered and the word list is left out — a
501
+ * learner who earned 82% should see 82%, not "this activity could not be
502
+ * displayed" from an error boundary.
503
+ *
504
+ * **Nor does a bad grade take the evidence down.** `grade` is read, not
505
+ * trusted: a score that is not a number between 0 and its maximum, or a
506
+ * `passed` that is not a boolean, is shown as could-not-be-graded beside the
507
+ * dimensions and the marks, and criteria that cannot be read name no dimension.
508
+ *
509
+ * **The marks show in any mode**: nothing here submits, grades or reveals an
510
+ * answer key. A read-aloud item has none, and the marks exist only once a
511
+ * server has graded the take, so there is no mode in which they must be
512
+ * withheld. `renderMode` is read for one thing only — AI coaching, which is
513
+ * never offered in `exam`.
514
+ *
515
+ * **AI coaching**, with a `pronunciationCoaching` port and a `data` that
516
+ * carries the item's `id` and `title`: a button under the marks asks a model
517
+ * to explain them. The marks are the engine's and are never re-scored, and
518
+ * coaching on a word not marked here, or a sound the engine did not report,
519
+ * is refused whole. See `useAiCoaching` to draw your own.
520
+ *
521
+ * ```tsx
522
+ * <PronunciationFeedback
523
+ * data={item}
524
+ * assessment={assessment}
525
+ * grade={grade}
526
+ * audioUrl={takeUrl}
527
+ * breakThreshold={0.75}
528
+ * monotoneThreshold={0.6}
529
+ * ai={{ pronunciationCoaching: (request, { signal }) => api.coach(request, signal) }}
530
+ * />
531
+ * ```
532
+ */
533
+ function PronunciationFeedback$1({ data, assessment, grade, audioUrl, breakThreshold, monotoneThreshold, locale, theme, strings, ai, renderMode, delivery, onInteraction }) {
534
+ const s = require_LkIntlProvider.useLkStrings(strings);
535
+ const ids = (0, react.useId)();
536
+ const [openWord, setOpenWord] = (0, react.useState)(null);
537
+ const checked = (0, react.useMemo)(() => checkEvidence(assessment), [assessment]);
538
+ const devError = (0, react.useMemo)(() => require_useAiHelp.isDevelopment() && !checked.success ? new _intellectif_lk_core.ActivitySchemaError("read-aloud", checked.errors) : null, [checked]);
539
+ const words = (0, react.useMemo)(() => checked.success ? (0, _intellectif_lk_core.alignReadAloud)(data, checked.data) : null, [checked, data]);
540
+ const reading = (0, react.useMemo)(() => grade === void 0 || grade === null ? void 0 : readGrade(grade), [grade]);
541
+ const dimensions = (0, react.useMemo)(() => readDimensions(assessment, reading), [assessment, reading]);
542
+ const audioRef = (0, react.useRef)(null);
543
+ const stopRef = (0, react.useRef)(null);
544
+ const playback = usePlaybackRefusal(audioUrl);
545
+ const playable = audioUrl !== void 0 && !playback.refused;
546
+ (0, react.useEffect)(() => () => {
547
+ if (stopRef.current !== null) clearTimeout(stopRef.current);
548
+ }, []);
549
+ const coachable = typeof data.id === "string" && typeof data.title === "string";
550
+ const coachingPort = require_ai_LkAiProvider.useLearnerAi(ai)?.pronunciationCoaching !== void 0;
551
+ (0, react.useEffect)(() => {
552
+ if (require_useAiHelp.isDevelopment() && coachingPort && !coachable) console.warn("learning-kit: <PronunciationFeedback> offers no AI coaching without `data.id` and `data.title`. Pass the whole read-aloud item as `data`, or `ai={{}}` to go without.");
553
+ }, [coachingPort, coachable]);
554
+ if (devError) throw devError;
555
+ /** Plays one word out of the take, and stops at the end of it. */
556
+ const playWord = (startMs, durationMs) => {
557
+ const element = audioRef.current;
558
+ if (element === null) return;
559
+ if (stopRef.current !== null) clearTimeout(stopRef.current);
560
+ element.currentTime = startMs / 1e3;
561
+ try {
562
+ element.play().catch((error) => {
563
+ if (isSourceRefusal(error)) playback.refuse(element);
564
+ });
565
+ } catch {}
566
+ stopRef.current = setTimeout(() => {
567
+ stopRef.current = null;
568
+ element.pause();
569
+ }, durationMs);
570
+ };
571
+ const contentLang = typeof data.locale === "string" ? data.locale : void 0;
572
+ const contentDir = require_direction.localeDirectionOf(data.locale);
573
+ const alphabet = checked.success ? checked.data.phonemeAlphabet : void 0;
574
+ const monotone = checked.success ? checked.data.prosody?.monotoneConfidence : void 0;
575
+ const evidenceWords = checked.success ? checked.data.words : [];
576
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
577
+ className: "lk-pf",
578
+ "aria-label": s.pronunciationFeedbackLabel,
579
+ lang: locale,
580
+ style: theme,
581
+ children: [
582
+ reading !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
583
+ className: "lk-pf-grade",
584
+ ...reading !== null ? { "data-passed": String(reading.passed) } : {},
585
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
586
+ className: "lk-pf-score",
587
+ children: reading === null ? s.couldNotBeGraded : s.scoreAnnouncement(percentOfGrade(reading), reading.passed)
588
+ }), reading?.feedback ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
589
+ className: "lk-pf-grade-feedback",
590
+ dir: "auto",
591
+ children: reading.feedback
592
+ }) : null]
593
+ }) : null,
594
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dl", {
595
+ className: "lk-pf-dimensions",
596
+ children: dimensions.map(({ dimension, percent }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
597
+ className: "lk-pf-dimension",
598
+ "data-dimension": dimension,
599
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", {
600
+ className: "lk-pf-dimension-name",
601
+ children: s.pronunciationDimension(dimension)
602
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", {
603
+ className: "lk-pf-dimension-score",
604
+ children: percent === void 0 ? s.pronunciationNotAssessed : `${percent}%`
605
+ })]
606
+ }, dimension))
607
+ }),
608
+ words !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
609
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ol", {
610
+ className: "lk-pf-words",
611
+ "aria-label": s.pronunciationWordsLabel,
612
+ dir: contentDir,
613
+ children: words.map((entry, index) => {
614
+ const sentence = markSentence(entry, s);
615
+ const shown = entry.state === "inserted" ? entry.heard : entry.reference;
616
+ const word = entry.wordIndex === void 0 ? void 0 : evidenceWords.at(entry.wordIndex);
617
+ const open = openWord === index;
618
+ const panelId = `${ids}-w${index}`;
619
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
620
+ className: "lk-pf-word",
621
+ "data-state": entry.state,
622
+ children: [
623
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
624
+ className: "lk-visually-hidden",
625
+ style: VISUALLY_HIDDEN,
626
+ children: sentence
627
+ }),
628
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
629
+ className: "lk-pf-word-text",
630
+ "aria-hidden": "true",
631
+ dir: contentDir ?? "auto",
632
+ lang: contentLang,
633
+ children: shown
634
+ }),
635
+ hasDetail(word) ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
636
+ type: "button",
637
+ className: "lk-pf-word-toggle",
638
+ "aria-expanded": open,
639
+ "aria-controls": panelId,
640
+ onClick: () => setOpenWord(open ? null : index),
641
+ children: s.pronunciationWordDetails(shown)
642
+ }), open ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
643
+ id: panelId,
644
+ className: "lk-pf-word-detail",
645
+ children: [
646
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("dl", {
647
+ className: "lk-pf-word-facts",
648
+ children: [
649
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: s.pronunciationDimension("accuracy") }),
650
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: word.accuracy === void 0 ? s.pronunciationNotAssessed : `${Math.round(word.accuracy)}%` }),
651
+ word.syllables !== void 0 && word.syllables.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: s.pronunciationSyllables }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
652
+ className: "lk-pf-syllables",
653
+ children: word.syllables.map((syllable, position) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
654
+ dir: contentDir ?? "auto",
655
+ lang: contentLang,
656
+ children: syllable.grapheme === void 0 ? syllable.text : s.pronunciationSyllableSpelling(syllable.text, syllable.grapheme)
657
+ }, position))
658
+ }) })] }) : null,
659
+ word.phonemes !== void 0 && word.phonemes.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: s.pronunciationPhonemes }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
660
+ className: "lk-pf-phonemes",
661
+ children: word.phonemes.map((phoneme, position) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
662
+ className: "lk-pf-phoneme",
663
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
664
+ className: "lk-pf-phoneme-symbol",
665
+ children: phonemeLabel(phoneme, position, s)
666
+ }), phoneme.heardAs !== void 0 && phoneme.heardAs.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
667
+ className: "lk-pf-heard-label",
668
+ children: s.pronunciationHeardAs
669
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
670
+ className: "lk-pf-heard-as",
671
+ children: phoneme.heardAs.map((candidate, rank) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: candidate.symbol }, rank))
672
+ })] }) : null]
673
+ }, position))
674
+ }) })] }) : null
675
+ ]
676
+ }),
677
+ playable && typeof word.startMs === "number" && typeof word.durationMs === "number" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
678
+ type: "button",
679
+ className: "lk-pf-word-play",
680
+ onClick: () => playWord(word.startMs, word.durationMs),
681
+ children: s.pronunciationPlayWord(shown)
682
+ }) : null,
683
+ past(word.breaks?.unexpected, breakThreshold) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
684
+ className: "lk-pf-break",
685
+ "data-break": "unexpected",
686
+ children: s.pronunciationBreakUnexpected
687
+ }) : null,
688
+ past(word.breaks?.missing, breakThreshold) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
689
+ className: "lk-pf-break",
690
+ "data-break": "missing",
691
+ children: s.pronunciationBreakMissing
692
+ }) : null
693
+ ]
694
+ }) : null] }) : null
695
+ ]
696
+ }, index);
697
+ })
698
+ }),
699
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
700
+ className: "lk-pf-legend",
701
+ children: LEGEND_STATES.map((state) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
702
+ "data-state": state,
703
+ children: s.pronunciationLegend(state)
704
+ }, state))
705
+ }),
706
+ alphabet === "ipa" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
707
+ className: "lk-pf-alphabet",
708
+ children: s.pronunciationIpaNote
709
+ }) : null,
710
+ coachable && checked.success ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReadingCoaching, {
711
+ data: {
712
+ id: data.id,
713
+ title: data.title,
714
+ referenceText: data.referenceText,
715
+ locale: data.locale,
716
+ ...data.instructions !== void 0 ? { instructions: data.instructions } : {},
717
+ ...data.ai !== void 0 ? { ai: data.ai } : {}
718
+ },
719
+ assessment: checked.data,
720
+ ...grade !== void 0 ? { grade } : {},
721
+ ...renderMode !== void 0 ? { renderMode } : {},
722
+ ...ai !== void 0 ? { ai } : {},
723
+ ...locale !== void 0 ? { locale } : {},
724
+ ...onInteraction !== void 0 ? { onInteraction } : {},
725
+ ...delivery !== void 0 ? { delivery } : {},
726
+ strings: s,
727
+ contentLang,
728
+ contentDir
729
+ }) : null
730
+ ] }) : null,
731
+ past(monotone, monotoneThreshold) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
732
+ className: "lk-pf-monotone",
733
+ role: "note",
734
+ children: s.pronunciationMonotone
735
+ }) : null,
736
+ audioUrl === void 0 ? null : playback.refused ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
737
+ className: "lk-pf-audio-unavailable",
738
+ role: "note",
739
+ children: s.readAloudPlaybackUnavailable
740
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("audio", {
741
+ ref: audioRef,
742
+ className: "lk-pf-audio",
743
+ src: audioUrl,
744
+ preload: "metadata",
745
+ onError: (event) => playback.refuse(event.currentTarget)
746
+ })
747
+ ]
748
+ });
749
+ }
750
+ //#endregion
751
+ //#region src/components/PronunciationFeedback/index.tsx
752
+ /**
753
+ * Public pronunciation-feedback panel: the core wrapped in
754
+ * `ActivityErrorBoundary` so a render failure (the dev throw for evidence
755
+ * `validateSpeechAssessment` refuses among them) degrades to an accessible
756
+ * fallback instead of crashing the host.
757
+ *
758
+ * **No `activityTitle`.** Its `data` is two fields of a read-aloud item and
759
+ * carries no title, so the production fallback is the unnamed one. Naming it
760
+ * would mean inventing a title for a panel that never had one.
761
+ */
762
+ function PronunciationFeedback(props) {
763
+ const strings = require_LkIntlProvider.useLkStrings(props.strings);
764
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_ActivityErrorBoundary.ActivityErrorBoundary, {
765
+ strings,
766
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PronunciationFeedback$1, { ...props })
767
+ });
768
+ }
769
+ //#endregion
770
+ Object.defineProperty(exports, "PronunciationFeedback", {
771
+ enumerable: true,
772
+ get: function() {
773
+ return PronunciationFeedback;
774
+ }
775
+ });
776
+ Object.defineProperty(exports, "ReadingCoaching", {
777
+ enumerable: true,
778
+ get: function() {
779
+ return ReadingCoaching;
780
+ }
781
+ });
782
+ Object.defineProperty(exports, "VISUALLY_HIDDEN", {
783
+ enumerable: true,
784
+ get: function() {
785
+ return VISUALLY_HIDDEN;
786
+ }
787
+ });
788
+ Object.defineProperty(exports, "fractionOfGrade", {
789
+ enumerable: true,
790
+ get: function() {
791
+ return fractionOfGrade;
792
+ }
793
+ });
794
+ Object.defineProperty(exports, "markSentence", {
795
+ enumerable: true,
796
+ get: function() {
797
+ return markSentence;
798
+ }
799
+ });
800
+ Object.defineProperty(exports, "percentOfGrade", {
801
+ enumerable: true,
802
+ get: function() {
803
+ return percentOfGrade;
804
+ }
805
+ });
806
+ Object.defineProperty(exports, "readAssessResult", {
807
+ enumerable: true,
808
+ get: function() {
809
+ return readAssessResult;
810
+ }
811
+ });
812
+ Object.defineProperty(exports, "readEvidence", {
813
+ enumerable: true,
814
+ get: function() {
815
+ return readEvidence;
816
+ }
817
+ });
818
+ Object.defineProperty(exports, "readOutcome", {
819
+ enumerable: true,
820
+ get: function() {
821
+ return readOutcome;
822
+ }
823
+ });
824
+ Object.defineProperty(exports, "usePlaybackRefusal", {
825
+ enumerable: true,
826
+ get: function() {
827
+ return usePlaybackRefusal;
828
+ }
829
+ });
830
+
831
+ //# sourceMappingURL=PronunciationFeedback-DlMPGjkR.cjs.map