@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,491 @@
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_hooks_useActivityState = require("./hooks/useActivityState.cjs");
7
+ const require_ActivityMedia = require("./ActivityMedia-CQQTRNl7.cjs");
8
+ const require_FeedbackRegion = require("./FeedbackRegion-BNNMtTY-.cjs");
9
+ let react = require("react");
10
+ let react_jsx_runtime = require("react/jsx-runtime");
11
+ let _intellectif_lk_core = require("@intellectif/lk-core");
12
+ //#region src/components/WrittenResponse/WrittenResponse.tsx
13
+ /**
14
+ * Reads the text out of a learner response. Another activity type's response
15
+ * shape (the `value`/`defaultValue` props take the `LearnerResponse` union,
16
+ * so a generic runner can hand any of them over) reads as empty rather than
17
+ * throwing mid-exam.
18
+ */
19
+ function textOf(response) {
20
+ return response !== void 0 && response.type === "written-response" ? response.text : "";
21
+ }
22
+ /**
23
+ * One criterion's score as a percentage of its OWN maximum.
24
+ *
25
+ * `CriterionScore.maxScore` defaults to 1 — the SDK's scaled convention — but
26
+ * a grader may work out of 100, or out of 9 for a CEFR band, and
27
+ * `gradeFromRubric` deliberately stores those judgements verbatim so a grade
28
+ * stays auditable in the units the grader actually used. It normalises when it
29
+ * computes the total; anything DISPLAYING a criterion has to normalise too, or
30
+ * a perfectly ordinary 82/100 renders as "8200%". This is the same guard the
31
+ * overall score already applies against `outcome.maxScore`.
32
+ */
33
+ function criterionPercent(criterion) {
34
+ const max = criterion.maxScore !== void 0 && criterion.maxScore > 0 ? criterion.maxScore : 1;
35
+ return `${Math.round(criterion.score / max * 100)}%`;
36
+ }
37
+ /**
38
+ * Pairs each correction with a list key that is unique by construction. The
39
+ * same mistake made twice carries the same `original`/`corrected` pair, so
40
+ * the grader's `range` is what tells the occurrences apart. `range` is
41
+ * optional and nothing validates it, so a correction without one — or one
42
+ * whose range the grader already used — is keyed by its position instead.
43
+ * Only position keys start with `#`, so the two kinds never collide.
44
+ */
45
+ function keyedCorrections(corrections) {
46
+ const used = /* @__PURE__ */ new Set();
47
+ return corrections.map((correction, index) => {
48
+ const anchored = correction.range ? `${correction.range.start}-${correction.range.end}:${correction.corrected}` : void 0;
49
+ const key = anchored !== void 0 && !used.has(anchored) ? anchored : `#${index}`;
50
+ used.add(key);
51
+ return {
52
+ key,
53
+ correction
54
+ };
55
+ });
56
+ }
57
+ /**
58
+ * Renders the server-computed outcome in `review` mode. The grade shown here
59
+ * always came back from the asynchronous grader — nothing on this path scores,
60
+ * infers, or defaults a grade. A `written-response` outcome carries no
61
+ * per-item `details` (there are no options or blanks to mark), so the render
62
+ * is the scaled score, the pass state, and the grader's feedback.
63
+ */
64
+ function CriteriaList({ criteria, s }) {
65
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
66
+ className: "lk-wr-criteria",
67
+ children: criteria.map((criterion) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
68
+ className: "lk-wr-criterion",
69
+ "data-na": String(criterion.notApplicable === true),
70
+ children: [
71
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
72
+ className: "lk-wr-criterion-name",
73
+ children: criterion.name
74
+ }),
75
+ criterion.notApplicable === true ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
76
+ className: "lk-wr-criterion-score",
77
+ children: s.notApplicable
78
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
79
+ className: "lk-wr-criterion-score",
80
+ children: criterion.band ?? (typeof criterion.score === "number" ? criterionPercent(criterion) : "")
81
+ }),
82
+ criterion.comment ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
83
+ className: "lk-wr-criterion-comment",
84
+ children: criterion.comment
85
+ }) : null
86
+ ]
87
+ }, criterion.name))
88
+ });
89
+ }
90
+ function CorrectionsList({ corrections, label }) {
91
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
92
+ className: "lk-wr-corrections",
93
+ ...label !== void 0 ? { "aria-label": label } : {},
94
+ children: keyedCorrections(corrections).map(({ key, correction }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
95
+ className: "lk-wr-correction",
96
+ children: [
97
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("del", {
98
+ className: "lk-wr-correction-original",
99
+ children: correction.original
100
+ }),
101
+ " ",
102
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ins", {
103
+ className: "lk-wr-correction-corrected",
104
+ children: correction.corrected
105
+ }),
106
+ correction.explanation ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
107
+ className: "lk-wr-correction-explanation",
108
+ children: correction.explanation
109
+ }) : null
110
+ ]
111
+ }, key))
112
+ });
113
+ }
114
+ function GradeBody({ grade, s }) {
115
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
116
+ grade.feedback ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
117
+ className: "lk-wr-grade-feedback",
118
+ children: grade.feedback
119
+ }) : null,
120
+ grade.criteria && grade.criteria.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CriteriaList, {
121
+ criteria: grade.criteria,
122
+ s
123
+ }) : null,
124
+ grade.corrections && grade.corrections.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CorrectionsList, { corrections: grade.corrections }) : null,
125
+ grade.requiresHumanReview === true ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
126
+ className: "lk-wr-review-flag",
127
+ children: s.awaitingHumanReview
128
+ }) : null
129
+ ] });
130
+ }
131
+ /**
132
+ * "Get feedback on my draft", and the feedback: what a model said, the
133
+ * corrections it proposed — each quoting the learner's own words, or the SDK
134
+ * would have refused it — its comment on each criterion, and the rubric's
135
+ * total as an indication, never a grade. A revision since the feedback is
136
+ * said, because its corrections may point at words that are gone.
137
+ */
138
+ function DraftFeedback({ help, draft, disabled, s }) {
139
+ const buttonRef = (0, react.useRef)(null);
140
+ const panelRef = (0, react.useRef)(null);
141
+ const refocus = (0, react.useRef)(false);
142
+ const latest = help.latest;
143
+ (0, react.useEffect)(() => {
144
+ if (latest !== null && refocus.current) {
145
+ refocus.current = false;
146
+ panelRef.current?.focus();
147
+ }
148
+ }, [latest]);
149
+ (0, react.useEffect)(() => {
150
+ if (help.status === "unavailable") refocus.current = false;
151
+ }, [help.status]);
152
+ if (!help.offered && help.used === 0) return null;
153
+ const loading = help.status === "loading";
154
+ const empty = draft.trim() === "";
155
+ const ask = () => {
156
+ refocus.current = typeof document !== "undefined" && document.activeElement === buttonRef.current;
157
+ help.ask();
158
+ };
159
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
160
+ className: "lk-ai lk-wr-ai",
161
+ "data-state": help.status,
162
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
163
+ "aria-live": "polite",
164
+ children: [latest !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
165
+ ref: panelRef,
166
+ className: "lk-ai-panel",
167
+ tabIndex: -1,
168
+ "aria-label": s.aiWritingFeedbackHeading,
169
+ "data-current": String(help.current),
170
+ children: [
171
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
172
+ className: "lk-ai-heading",
173
+ children: s.aiWritingFeedbackHeading
174
+ }),
175
+ help.current ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
176
+ className: "lk-ai-note",
177
+ children: s.aiWritingFeedbackOutdated
178
+ }),
179
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
180
+ className: "lk-ai-text",
181
+ children: latest.text
182
+ }),
183
+ latest.corrections.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CorrectionsList, {
184
+ corrections: latest.corrections,
185
+ label: s.aiCorrections
186
+ }) : null,
187
+ latest.criteria.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CriteriaList, {
188
+ criteria: latest.criteria,
189
+ s
190
+ }) : null,
191
+ latest.indicativeScore !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
192
+ className: "lk-wr-indicative",
193
+ children: s.aiIndicativeScore(Math.round(latest.indicativeScore * 100))
194
+ }) : null,
195
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
196
+ className: "lk-ai-notice",
197
+ children: s.aiNotice
198
+ })
199
+ ]
200
+ }) : null, help.status === "unavailable" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
201
+ className: "lk-ai-unavailable",
202
+ children: s.aiWritingFeedbackUnavailable
203
+ }) : null]
204
+ }), help.offered ? help.used < help.limit ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
205
+ ref: buttonRef,
206
+ type: "button",
207
+ className: "lk-ai-button",
208
+ "aria-busy": loading || void 0,
209
+ "aria-disabled": loading || empty || disabled || void 0,
210
+ onClick: ask,
211
+ children: loading ? s.aiWritingFeedbackLoading : s.aiWritingFeedback
212
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
213
+ className: "lk-ai-note",
214
+ children: s.aiNoMoreWritingFeedback
215
+ }) : null]
216
+ });
217
+ }
218
+ /**
219
+ * Renders the server-computed outcome in `review` mode. The grade shown here
220
+ * always came back from the grader — nothing on this path scores, infers, or
221
+ * defaults a grade.
222
+ */
223
+ function OutcomeSummary({ outcome, s }) {
224
+ if (outcome.status === "scored" || outcome.status === "graded") {
225
+ const percent = outcome.maxScore > 0 ? Math.round(outcome.score / outcome.maxScore * 100) : Math.round(outcome.score * 100);
226
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
227
+ className: "lk-wr-outcome",
228
+ "data-status": outcome.status,
229
+ "data-passed": String(outcome.passed),
230
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
231
+ className: "lk-wr-grade",
232
+ children: s.scoreAnnouncement(percent, outcome.passed)
233
+ }), outcome.status === "graded" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GradeBody, {
234
+ grade: outcome.grade,
235
+ s
236
+ }) : outcome.feedback ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
237
+ className: "lk-wr-grade-feedback",
238
+ children: outcome.feedback
239
+ }) : null]
240
+ });
241
+ }
242
+ if (outcome.status === "deferred") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
243
+ className: "lk-wr-outcome",
244
+ "data-status": "deferred",
245
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
246
+ className: "lk-wr-grade",
247
+ children: s.awaitingGrade
248
+ })
249
+ });
250
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
251
+ className: "lk-wr-outcome",
252
+ "data-status": "unscorable",
253
+ "data-reason": outcome.reason,
254
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
255
+ className: "lk-wr-grade",
256
+ children: s.couldNotBeGraded
257
+ })
258
+ });
259
+ }
260
+ function WrittenResponse$1({ data, onSubmitted, onSubmit, value, defaultValue, defaultSubmitted, onChange, renderMode = "practice", outcome, sanitizeHtml, mediaBudget, mediaStrings, strings, onInteraction, theme, locale, disabled, delivery, ai: aiProp }) {
261
+ const s = require_LkIntlProvider.useLkStrings(strings);
262
+ const policy = require_FeedbackRegion.useDeliveryPolicy(delivery);
263
+ const ai = require_ai_LkAiProvider.useLearnerAi(aiProp);
264
+ const devError = (0, react.useMemo)(() => {
265
+ if (!require_useAiHelp.isDevelopment()) return null;
266
+ const result = (0, _intellectif_lk_core.validateActivity)("written-response", data);
267
+ return result.success ? null : new _intellectif_lk_core.ActivitySchemaError("written-response", result.errors);
268
+ }, [data]);
269
+ const { state, start, complete, getTimeSpent, reset } = require_hooks_useActivityState.useActivityState(defaultSubmitted === true ? "completed" : "idle");
270
+ const isControlled = value !== void 0;
271
+ const [innerText, setInnerText] = (0, react.useState)(() => textOf(defaultValue));
272
+ const [summary, setSummary] = (0, react.useState)(null);
273
+ /**
274
+ * Rich text is rendered ONLY through a caller-supplied sanitiser, and only
275
+ * when the author actually shipped the HTML sidecar. Without both, the
276
+ * plain-text prompt is rendered as an escaped React child.
277
+ */
278
+ const promptHtml = (0, react.useMemo)(() => {
279
+ if (sanitizeHtml === void 0 || typeof data.promptHtml !== "string") return null;
280
+ return sanitizeHtml(data.promptHtml);
281
+ }, [data.promptHtml, sanitizeHtml]);
282
+ const defaultTextRef = (0, react.useRef)(textOf(defaultValue));
283
+ (0, react.useEffect)(() => {
284
+ defaultTextRef.current = textOf(defaultValue);
285
+ }, [defaultValue]);
286
+ const defaultSubmittedRef = (0, react.useRef)(defaultSubmitted);
287
+ (0, react.useEffect)(() => {
288
+ defaultSubmittedRef.current = defaultSubmitted;
289
+ }, [defaultSubmitted]);
290
+ const lastDataRef = (0, react.useRef)(data);
291
+ (0, react.useEffect)(() => {
292
+ if (lastDataRef.current === data) return;
293
+ lastDataRef.current = data;
294
+ setInnerText(defaultTextRef.current);
295
+ setSummary(null);
296
+ reset(defaultSubmittedRef.current === true ? "completed" : "idle");
297
+ }, [data, reset]);
298
+ const draft = isControlled ? textOf(value) : innerText;
299
+ const writingFeedback = require_useAiHelp.useAiWritingFeedback({
300
+ data,
301
+ response: {
302
+ type: "written-response",
303
+ text: draft,
304
+ wordCount: (0, _intellectif_lk_core.countWords)(draft)
305
+ },
306
+ submitted: state === "completed",
307
+ renderMode,
308
+ delivery: policy,
309
+ disabled: disabled === true,
310
+ ...ai !== void 0 ? { ai } : {},
311
+ ...locale !== void 0 ? { locale } : {},
312
+ ...onInteraction !== void 0 ? { onInteraction } : {}
313
+ });
314
+ if (devError) throw devError;
315
+ const isExam = renderMode === "exam";
316
+ const isReview = renderMode === "review";
317
+ const text = isControlled ? textOf(value) : innerText;
318
+ const inactive = disabled === true || state === "completed" || isReview;
319
+ const wordCount = (0, _intellectif_lk_core.countWords)(text);
320
+ const withinBounds = wordCount >= data.minWords && wordCount <= data.maxWords;
321
+ const handleChange = (next) => {
322
+ if (inactive) return;
323
+ if (state === "idle") start();
324
+ if (!isControlled) setInnerText(next);
325
+ const nextWordCount = (0, _intellectif_lk_core.countWords)(next);
326
+ onChange?.({
327
+ type: "written-response",
328
+ text: next,
329
+ wordCount: nextWordCount
330
+ });
331
+ onInteraction?.({
332
+ type: "text-changed",
333
+ activityId: data.id,
334
+ timestamp: Date.now(),
335
+ payload: { wordCount: nextWordCount }
336
+ });
337
+ };
338
+ if (data.redacted === true && renderMode === "practice") throw new Error(`Written Response "${data.id}" received redacted activity data in renderMode "practice". Practice runs the local submit path and emits a practice-mode xAPI statement, so an exam item wired this way is graded nowhere and looks fine while it happens. Render redacted data with renderMode="exam" (server grades) or "review" (pass \`outcome\`).`);
339
+ const handleSubmit = (event) => {
340
+ event.preventDefault();
341
+ if (inactive || text.trim().length === 0) return;
342
+ let finalWordCount = wordCount;
343
+ let finalWithinBounds = withinBounds;
344
+ if (!isExam) {
345
+ const itemOutcome = (0, _intellectif_lk_core.evaluate)(data, {
346
+ type: "written-response",
347
+ text,
348
+ wordCount
349
+ });
350
+ const partial = itemOutcome.status === "deferred" ? itemOutcome.partial : void 0;
351
+ if (typeof partial?.wordCount === "number") finalWordCount = partial.wordCount;
352
+ if (typeof partial?.withinWordBounds === "boolean") finalWithinBounds = partial.withinWordBounds;
353
+ }
354
+ complete();
355
+ const timeSpent = getTimeSpent();
356
+ const xapiStatement = _intellectif_lk_core.xAPIBuilder.buildSubmittedStatement({
357
+ actor: require_useAiHelp.ANONYMOUS_ACTOR,
358
+ object: {
359
+ id: require_useAiHelp.objectIdFor(data.id),
360
+ name: { [data.locale ?? "en-US"]: data.title },
361
+ type: "http://adlnet.gov/expapi/activities/cmi.interaction",
362
+ interactionType: "long-fill-in"
363
+ },
364
+ timeSpentMs: timeSpent,
365
+ response: text,
366
+ resultExtensions: {
367
+ "urn:learning-kit:extension:word-count": finalWordCount,
368
+ "urn:learning-kit:extension:within-word-bounds": finalWithinBounds
369
+ }
370
+ });
371
+ onSubmit?.({
372
+ type: "written-response",
373
+ text,
374
+ wordCount: finalWordCount
375
+ });
376
+ onSubmitted?.({
377
+ text,
378
+ wordCount: finalWordCount,
379
+ withinWordBounds: finalWithinBounds,
380
+ timeSpent,
381
+ xapiStatement
382
+ });
383
+ setSummary(s.responseSubmitted);
384
+ onInteraction?.({
385
+ type: "submitted",
386
+ activityId: data.id,
387
+ timestamp: Date.now(),
388
+ payload: {
389
+ wordCount: finalWordCount,
390
+ withinWordBounds: finalWithinBounds
391
+ }
392
+ });
393
+ };
394
+ const promptId = `${data.id}-prompt`;
395
+ const counterId = `${data.id}-counter`;
396
+ const boundsLabel = s.wordBounds(data.minWords, data.maxWords);
397
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
398
+ className: "lk-wr",
399
+ "aria-label": data.title,
400
+ lang: locale,
401
+ "data-render-mode": renderMode,
402
+ style: theme,
403
+ onSubmit: handleSubmit,
404
+ children: [
405
+ data.media ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_ActivityMedia.ActivityMedia, {
406
+ media: data.media,
407
+ renderMode,
408
+ ...mediaBudget !== void 0 ? { mediaBudget } : {},
409
+ ...mediaStrings !== void 0 ? { mediaStrings } : {},
410
+ ...strings !== void 0 ? { strings } : {},
411
+ ...onInteraction !== void 0 ? { onInteraction } : {},
412
+ ...locale !== void 0 ? { locale } : {}
413
+ }) : null,
414
+ promptHtml === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
415
+ className: "lk-wr-prompt",
416
+ id: promptId,
417
+ children: data.prompt
418
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
419
+ className: "lk-wr-prompt",
420
+ id: promptId,
421
+ dangerouslySetInnerHTML: { __html: promptHtml }
422
+ }),
423
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
424
+ className: "lk-wr-textarea",
425
+ "aria-labelledby": promptId,
426
+ "aria-describedby": counterId,
427
+ value: text,
428
+ onChange: (event) => handleChange(event.target.value),
429
+ disabled: !isReview && inactive,
430
+ readOnly: isReview,
431
+ rows: 8
432
+ }),
433
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
434
+ className: "lk-wr-counter",
435
+ id: counterId,
436
+ "aria-live": "polite",
437
+ "data-within-bounds": withinBounds,
438
+ children: [
439
+ s.wordCount(wordCount),
440
+ " (",
441
+ boundsLabel,
442
+ ")"
443
+ ]
444
+ }),
445
+ ai?.writingFeedback !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DraftFeedback, {
446
+ help: writingFeedback,
447
+ draft: text,
448
+ disabled: disabled === true,
449
+ s
450
+ }) : null,
451
+ isReview ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
452
+ type: "submit",
453
+ className: "lk-wr-submit",
454
+ disabled: inactive || text.trim().length === 0,
455
+ children: s.submit
456
+ }),
457
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_FeedbackRegion.FeedbackRegion, {
458
+ id: `${data.id}-feedback`,
459
+ children: isReview ? outcome && (policy.feedback || !require_FeedbackRegion.outcomeShowsMarks(outcome)) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OutcomeSummary, {
460
+ outcome,
461
+ s
462
+ }) : null : summary
463
+ })
464
+ ]
465
+ });
466
+ }
467
+ //#endregion
468
+ //#region src/components/WrittenResponse/index.tsx
469
+ /**
470
+ * Public Written Response activity: a labelled textarea with a live word
471
+ * counter for free-text writing graded asynchronously (AI or human). The core
472
+ * is wrapped in `ActivityErrorBoundary` so a render failure (incl. the dev
473
+ * schema-validation throw) degrades to an accessible fallback.
474
+ */
475
+ function WrittenResponse(props) {
476
+ const strings = require_LkIntlProvider.useLkStrings(props.strings);
477
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_ActivityErrorBoundary.ActivityErrorBoundary, {
478
+ activityTitle: props.data?.title,
479
+ strings,
480
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WrittenResponse$1, { ...props })
481
+ });
482
+ }
483
+ //#endregion
484
+ Object.defineProperty(exports, "WrittenResponse", {
485
+ enumerable: true,
486
+ get: function() {
487
+ return WrittenResponse;
488
+ }
489
+ });
490
+
491
+ //# sourceMappingURL=WrittenResponse-Bj3eFmGl.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WrittenResponse-Bj3eFmGl.cjs","names":["useRef","WrittenResponse","useLkStrings","useDeliveryPolicy","useLearnerAi","useMemo","isDevelopment","validateActivity","ActivitySchemaError","useActivityState","useState","useAiWritingFeedback","countWords","evaluate","xAPIBuilder","ANONYMOUS_ACTOR","objectIdFor","ActivityMedia","FeedbackRegion","outcomeShowsMarks","useLkStrings","ActivityErrorBoundary","WrittenResponseCore"],"sources":["../src/components/WrittenResponse/WrittenResponse.tsx","../src/components/WrittenResponse/index.tsx"],"sourcesContent":["'use client';\n\nimport {\n ActivitySchemaError,\n type CriterionScore,\n countWords,\n type DeliveryPolicy,\n evaluate,\n type GradeRecord,\n type InlineCorrection,\n type InteractionEvent,\n type ItemOutcome,\n type LearnerResponse,\n type ThemeTokens,\n validateActivity,\n type WrittenResponseData,\n type XAPIStatement,\n xAPIBuilder,\n} from '@intellectif/lk-core';\nimport { type CSSProperties, useEffect, useMemo, useRef, useState } from 'react';\nimport { type LearnerAi, useLearnerAi } from '../../ai/LkAiProvider.js';\nimport { type AiWritingFeedbackHelp, useAiWritingFeedback } from '../../ai/useAiHelp.js';\nimport { useActivityState } from '../../hooks/useActivityState.js';\nimport { useLkStrings } from '../../i18n/LkIntlProvider.js';\nimport type { LkStrings, LkStringsOverride } from '../../i18n/strings.js';\nimport { ANONYMOUS_ACTOR, isDevelopment, objectIdFor } from '../_internal.js';\nimport { ActivityMedia } from '../shared/ActivityMedia.js';\nimport { outcomeShowsMarks, useDeliveryPolicy } from '../shared/delivery.js';\nimport { FeedbackRegion } from '../shared/FeedbackRegion.js';\nimport type {\n HtmlSanitizer,\n MediaBudgetBinding,\n MediaTransportStrings,\n Renderable,\n RenderMode,\n} from '../types.js';\n\n/**\n * Payload delivered when the learner submits a written response. Grading is\n * DEFERRED (asynchronous AI/human grading), so there is no score here — and\n * deliberately no fake one: an ungraded submission must never be shown or\n * stored as a 0. The consumer persists `text` and grades it out-of-band.\n */\nexport interface WrittenResponseSubmission {\n /** The submitted text, verbatim. */\n text: string;\n /** Word count of `text`, recomputed with the canonical `countWords()`. */\n wordCount: number;\n /** Whether `wordCount` falls within the activity's `[minWords, maxWords]`. */\n withinWordBounds: boolean;\n /** Time in milliseconds from first interaction to submission. */\n timeSpent: number;\n /** The SUBMITTED-verb xAPI statement built for this submission (no score fields). */\n xapiStatement: XAPIStatement;\n}\n\n/**\n * Props for {@link WrittenResponse}. Mirrors `ActivityProps` except for the\n * completion callback: a deferred-grading activity completes with a\n * {@link WrittenResponseSubmission} (`onSubmitted`), not a scored\n * `ActivityResult` (`onComplete`), on purpose: fabricating a score of 0 for\n * ungraded work is the exact bug this type exists to fix. Everything else — controlled value, render\n * mode, server outcome, rich text — follows the shared `ActivityProps`\n * contract verbatim.\n */\nexport interface WrittenResponseProps {\n /** Activity content. Accepts a `redact()` projection in `exam` mode. */\n data: Renderable<WrittenResponseData>;\n /**\n * Called on submit with the ungraded submission (text, recomputed word\n * count, bounds flag, timing, xAPI statement). Fires in `practice` and\n * `exam` mode, after `onSubmit`; never in `review`.\n *\n * Optional since lk-react 2.1.0 so a `review`-mode render (which has no submit\n * control) and an exam runner that only wants the raw response through\n * `onSubmit` do not have to pass a no-op. Supply it in `practice`/`exam`\n * unless `onSubmit` already captures everything you persist.\n */\n onSubmitted?: (submission: WrittenResponseSubmission) => void;\n /**\n * Called on submit with the raw learner response and no grade, BEFORE\n * `onSubmitted`. This is the only submit callback an exam runner needs:\n * the server grades the text and returns an {@link ItemOutcome} later.\n */\n onSubmit?: (response: LearnerResponse) => void;\n /**\n * Controlled value: the learner's current response. When present the\n * textarea renders from it (never from internal state) and every keystroke\n * goes out through `onChange` — restore an in-progress attempt, autosave a\n * delta, or drive a review render with it.\n */\n value?: LearnerResponse;\n /** Initial response for an uncontrolled component (ignored when `value` is set). */\n defaultValue?: LearnerResponse;\n /**\n * Mount as already submitted — read at mount only. Without it a resumed\n * attempt reopens an essay the learner had already submitted as editable\n * and re-submittable.\n */\n defaultSubmitted?: boolean;\n /** Fires on every change to the learner's response. Required for a controlled component. */\n onChange?: (response: LearnerResponse) => void;\n /**\n * Presentation mode, default `practice`. `practice` and `exam` are nearly\n * identical here — a written response is never graded client-side, so\n * there is no local score to withhold; `exam` additionally never calls\n * `evaluate()` and renders happily from a `redact()` projection.\n * `review` is read-only and shows the server's `outcome`.\n */\n renderMode?: RenderMode;\n /**\n * Server-computed outcome, rendered by `review` mode: `deferred` shows a\n * \"not graded yet\" affordance, `scored` shows the returned grade and\n * feedback. Ignored in other modes — this component never manufactures an\n * outcome of its own.\n */\n outcome?: ItemOutcome;\n /** Renders `data.promptHtml` when provided. See `HtmlSanitizer`. */\n sanitizeHtml?: HtmlSanitizer;\n /** Binds this activity's own `data.media` to a play budget. See {@link MediaBudgetBinding}. */\n mediaBudget?: MediaBudgetBinding;\n /** Translations for the audio transport chrome. See {@link MediaTransportStrings}. */\n mediaStrings?: Partial<MediaTransportStrings>;\n /** Overrides the SDK's chrome text for this activity. See {@link LkIntlProvider}. */\n strings?: LkStringsOverride;\n onInteraction?: (event: InteractionEvent) => void;\n /** Per-instance token overrides, applied as inline CSS vars on the root. */\n theme?: Partial<ThemeTokens>;\n locale?: string;\n disabled?: boolean;\n /**\n * The delivery policy. An essay is graded later, so `feedback` reaches it —\n * `false` reads a returned grade back as nothing in `review` — and so does\n * AI feedback on a draft, which needs `feedback`, `solutions` and\n * `ai.explanations`. See `DeliveryPolicy` in lk-core.\n */\n delivery?: DeliveryPolicy | null;\n /**\n * The host's AI ports, overriding `LkAiProvider`'s. With a `writingFeedback`\n * port, a learner in `practice` can ask for feedback on a draft before\n * submitting it — up to `maxWritingFeedback` times — and revise. Every\n * correction in it quotes the learner's own words, or the SDK refuses it.\n * Never in `exam` or `review`. See {@link LearnerAi}.\n */\n ai?: LearnerAi;\n}\n\n/**\n * Reads the text out of a learner response. Another activity type's response\n * shape (the `value`/`defaultValue` props take the `LearnerResponse` union,\n * so a generic runner can hand any of them over) reads as empty rather than\n * throwing mid-exam.\n */\nfunction textOf(response: LearnerResponse | undefined): string {\n return response !== undefined && response.type === 'written-response' ? response.text : '';\n}\n\n/**\n * One criterion's score as a percentage of its OWN maximum.\n *\n * `CriterionScore.maxScore` defaults to 1 — the SDK's scaled convention — but\n * a grader may work out of 100, or out of 9 for a CEFR band, and\n * `gradeFromRubric` deliberately stores those judgements verbatim so a grade\n * stays auditable in the units the grader actually used. It normalises when it\n * computes the total; anything DISPLAYING a criterion has to normalise too, or\n * a perfectly ordinary 82/100 renders as \"8200%\". This is the same guard the\n * overall score already applies against `outcome.maxScore`.\n */\nfunction criterionPercent(criterion: CriterionScore): string {\n const max = criterion.maxScore !== undefined && criterion.maxScore > 0 ? criterion.maxScore : 1;\n return `${Math.round(((criterion.score as number) / max) * 100)}%`;\n}\n\n/**\n * Pairs each correction with a list key that is unique by construction. The\n * same mistake made twice carries the same `original`/`corrected` pair, so\n * the grader's `range` is what tells the occurrences apart. `range` is\n * optional and nothing validates it, so a correction without one — or one\n * whose range the grader already used — is keyed by its position instead.\n * Only position keys start with `#`, so the two kinds never collide.\n */\nfunction keyedCorrections(\n corrections: readonly InlineCorrection[],\n): { key: string; correction: InlineCorrection }[] {\n const used = new Set<string>();\n return corrections.map((correction, index) => {\n const anchored = correction.range\n ? `${correction.range.start}-${correction.range.end}:${correction.corrected}`\n : undefined;\n const key = anchored !== undefined && !used.has(anchored) ? anchored : `#${index}`;\n used.add(key);\n return { key, correction };\n });\n}\n\n/**\n * Renders the server-computed outcome in `review` mode. The grade shown here\n * always came back from the asynchronous grader — nothing on this path scores,\n * infers, or defaults a grade. A `written-response` outcome carries no\n * per-item `details` (there are no options or blanks to mark), so the render\n * is the scaled score, the pass state, and the grader's feedback.\n */\nfunction CriteriaList({ criteria, s }: { criteria: readonly CriterionScore[]; s: LkStrings }) {\n return (\n <ul className=\"lk-wr-criteria\">\n {criteria.map((criterion) => (\n <li\n className=\"lk-wr-criterion\"\n key={criterion.name}\n data-na={String(criterion.notApplicable === true)}\n >\n <span className=\"lk-wr-criterion-name\">{criterion.name}</span>\n {criterion.notApplicable === true ? (\n <span className=\"lk-wr-criterion-score\">{s.notApplicable}</span>\n ) : (\n <span className=\"lk-wr-criterion-score\">\n {criterion.band ??\n (typeof criterion.score === 'number' ? criterionPercent(criterion) : '')}\n </span>\n )}\n {criterion.comment ? (\n <span className=\"lk-wr-criterion-comment\">{criterion.comment}</span>\n ) : null}\n </li>\n ))}\n </ul>\n );\n}\n\nfunction CorrectionsList({\n corrections,\n label,\n}: {\n corrections: readonly InlineCorrection[];\n label?: string;\n}) {\n return (\n <ul className=\"lk-wr-corrections\" {...(label !== undefined ? { 'aria-label': label } : {})}>\n {keyedCorrections(corrections).map(({ key, correction }) => (\n <li className=\"lk-wr-correction\" key={key}>\n <del className=\"lk-wr-correction-original\">{correction.original}</del>{' '}\n <ins className=\"lk-wr-correction-corrected\">{correction.corrected}</ins>\n {correction.explanation ? (\n <span className=\"lk-wr-correction-explanation\">{correction.explanation}</span>\n ) : null}\n </li>\n ))}\n </ul>\n );\n}\n\nfunction GradeBody({ grade, s }: { grade: GradeRecord; s: LkStrings }) {\n return (\n <>\n {grade.feedback ? <p className=\"lk-wr-grade-feedback\">{grade.feedback}</p> : null}\n {grade.criteria && grade.criteria.length > 0 ? (\n <CriteriaList criteria={grade.criteria} s={s} />\n ) : null}\n {grade.corrections && grade.corrections.length > 0 ? (\n <CorrectionsList corrections={grade.corrections} />\n ) : null}\n {grade.requiresHumanReview === true ? (\n <p className=\"lk-wr-review-flag\">{s.awaitingHumanReview}</p>\n ) : null}\n </>\n );\n}\n\n/**\n * \"Get feedback on my draft\", and the feedback: what a model said, the\n * corrections it proposed — each quoting the learner's own words, or the SDK\n * would have refused it — its comment on each criterion, and the rubric's\n * total as an indication, never a grade. A revision since the feedback is\n * said, because its corrections may point at words that are gone.\n */\nfunction DraftFeedback({\n help,\n draft,\n disabled,\n s,\n}: {\n help: AiWritingFeedbackHelp;\n draft: string;\n disabled: boolean;\n s: LkStrings;\n}) {\n const buttonRef = useRef<HTMLButtonElement>(null);\n const panelRef = useRef<HTMLElement>(null);\n const refocus = useRef(false);\n const latest = help.latest;\n\n // The feedback lands beside the button that asked; focus follows it there,\n // so a screen reader reads it from its heading rather than all at once.\n useEffect(() => {\n if (latest !== null && refocus.current) {\n refocus.current = false;\n panelRef.current?.focus();\n }\n }, [latest]);\n useEffect(() => {\n if (help.status === 'unavailable') {\n refocus.current = false;\n }\n }, [help.status]);\n\n if (!help.offered && help.used === 0) {\n return null;\n }\n const loading = help.status === 'loading';\n const empty = draft.trim() === '';\n const ask = (): void => {\n refocus.current =\n typeof document !== 'undefined' && document.activeElement === buttonRef.current;\n help.ask();\n };\n return (\n <div className=\"lk-ai lk-wr-ai\" data-state={help.status}>\n <div aria-live=\"polite\">\n {latest !== null ? (\n <section\n ref={panelRef}\n className=\"lk-ai-panel\"\n tabIndex={-1}\n aria-label={s.aiWritingFeedbackHeading}\n data-current={String(help.current)}\n >\n <p className=\"lk-ai-heading\">{s.aiWritingFeedbackHeading}</p>\n {help.current ? null : <p className=\"lk-ai-note\">{s.aiWritingFeedbackOutdated}</p>}\n <p className=\"lk-ai-text\">{latest.text}</p>\n {latest.corrections.length > 0 ? (\n <CorrectionsList corrections={latest.corrections} label={s.aiCorrections} />\n ) : null}\n {latest.criteria.length > 0 ? <CriteriaList criteria={latest.criteria} s={s} /> : null}\n {latest.indicativeScore !== null ? (\n <p className=\"lk-wr-indicative\">\n {s.aiIndicativeScore(Math.round(latest.indicativeScore * 100))}\n </p>\n ) : null}\n <p className=\"lk-ai-notice\">{s.aiNotice}</p>\n </section>\n ) : null}\n {help.status === 'unavailable' ? (\n <p className=\"lk-ai-unavailable\">{s.aiWritingFeedbackUnavailable}</p>\n ) : null}\n </div>\n {help.offered ? (\n help.used < help.limit ? (\n <button\n ref={buttonRef}\n type=\"button\"\n className=\"lk-ai-button\"\n aria-busy={loading || undefined}\n // aria-disabled rather than disabled: focus stays on the button.\n aria-disabled={loading || empty || disabled || undefined}\n onClick={ask}\n >\n {loading ? s.aiWritingFeedbackLoading : s.aiWritingFeedback}\n </button>\n ) : (\n <p className=\"lk-ai-note\">{s.aiNoMoreWritingFeedback}</p>\n )\n ) : null}\n </div>\n );\n}\n\n/**\n * Renders the server-computed outcome in `review` mode. The grade shown here\n * always came back from the grader — nothing on this path scores, infers, or\n * defaults a grade.\n */\nfunction OutcomeSummary({ outcome, s }: { outcome: ItemOutcome; s: LkStrings }) {\n if (outcome.status === 'scored' || outcome.status === 'graded') {\n // `score` is scaled [0–1] against `maxScore`; normalising by `maxScore`\n // is a no-op for the canonical maxScore of 1 and keeps an unscaled\n // grader payload (8.5 / 10) from rendering as 850%.\n const percent =\n outcome.maxScore > 0\n ? Math.round((outcome.score / outcome.maxScore) * 100)\n : Math.round(outcome.score * 100);\n return (\n <div\n className=\"lk-wr-outcome\"\n data-status={outcome.status}\n data-passed={String(outcome.passed)}\n >\n <p className=\"lk-wr-grade\">{s.scoreAnnouncement(percent, outcome.passed)}</p>\n {outcome.status === 'graded' ? (\n <GradeBody grade={outcome.grade} s={s} />\n ) : outcome.feedback ? (\n <p className=\"lk-wr-grade-feedback\">{outcome.feedback}</p>\n ) : null}\n </div>\n );\n }\n if (outcome.status === 'deferred') {\n return (\n <div className=\"lk-wr-outcome\" data-status=\"deferred\">\n <p className=\"lk-wr-grade\">{s.awaitingGrade}</p>\n </div>\n );\n }\n // `unscorable` reasons are developer-facing strings; surface the state, not\n // the reason, and leave it on the element for diagnostics.\n return (\n <div className=\"lk-wr-outcome\" data-status=\"unscorable\" data-reason={outcome.reason}>\n <p className=\"lk-wr-grade\">{s.couldNotBeGraded}</p>\n </div>\n );\n}\n\nexport function WrittenResponse({\n data,\n onSubmitted,\n onSubmit,\n value,\n defaultValue,\n defaultSubmitted,\n onChange,\n renderMode = 'practice',\n outcome,\n sanitizeHtml,\n mediaBudget,\n mediaStrings,\n strings,\n onInteraction,\n theme,\n locale,\n disabled,\n delivery,\n ai: aiProp,\n}: WrittenResponseProps) {\n // Dev-only boundary validation, same convention as MC/FIB. The\n // content schema is loose, so a `redact()` projection validates too.\n const s = useLkStrings(strings);\n // An essay is graded later, so `feedback` is the one setting that reaches\n // it: whether a returned grade — the score, each criterion, the corrections\n // — is read back in review.\n const policy = useDeliveryPolicy(delivery);\n const ai = useLearnerAi(aiProp);\n\n const devError = useMemo(() => {\n if (!isDevelopment()) {\n return null;\n }\n const result = validateActivity('written-response', data);\n return result.success ? null : new ActivitySchemaError('written-response', result.errors);\n }, [data]);\n\n const { state, start, complete, getTimeSpent, reset } = useActivityState(\n defaultSubmitted === true ? 'completed' : 'idle',\n );\n const isControlled = value !== undefined;\n const [innerText, setInnerText] = useState<string>(() => textOf(defaultValue));\n const [summary, setSummary] = useState<string | null>(null);\n\n /**\n * Rich text is rendered ONLY through a caller-supplied sanitiser, and only\n * when the author actually shipped the HTML sidecar. Without both, the\n * plain-text prompt is rendered as an escaped React child.\n */\n const promptHtml = useMemo(() => {\n if (sanitizeHtml === undefined || typeof data.promptHtml !== 'string') {\n return null;\n }\n return sanitizeHtml(data.promptHtml);\n }, [data.promptHtml, sanitizeHtml]);\n\n // Latest seed text, kept in a ref so `defaultValue` is NOT a reset trigger:\n // callers pass an object literal, whose identity changes every render.\n const defaultTextRef = useRef<string>(textOf(defaultValue));\n useEffect(() => {\n defaultTextRef.current = textOf(defaultValue);\n }, [defaultValue]);\n\n // Reset on data-prop change: back to the seed (empty when there\n // is none — the v1 behaviour), never the previous activity's draft.\n // Mirror `defaultSubmitted` so the reset below returns to the SEEDED state.\n // Resetting unconditionally to idle unlocked an item the learner had already\n // committed — which made `defaultSubmitted` a no-op here, since this effect\n // runs right after the first paint.\n const defaultSubmittedRef = useRef(defaultSubmitted);\n useEffect(() => {\n defaultSubmittedRef.current = defaultSubmitted;\n }, [defaultSubmitted]);\n\n // Identity guard so the MOUNT run is a no-op. Without it this effect fires\n // after the first paint and undoes every seed it was just given; with it,\n // only a real `data` change resets. A parent that rebuilds structurally\n // identical entries in render (`activities={raw.map(redact)}`) must not\n // unlock or revert a restored answer — the pager already remounts a slot\n // whose activity actually changed, via its key.\n const lastDataRef = useRef(data);\n useEffect(() => {\n if (lastDataRef.current === data) {\n return;\n }\n lastDataRef.current = data;\n setInnerText(defaultTextRef.current);\n setSummary(null);\n reset(defaultSubmittedRef.current === true ? 'completed' : 'idle');\n }, [data, reset]);\n\n // Feedback on a draft is a hook, so it is read here, before the throws below.\n const draft = isControlled ? textOf(value) : innerText;\n const writingFeedback = useAiWritingFeedback({\n data,\n response: { type: 'written-response', text: draft, wordCount: countWords(draft) },\n submitted: state === 'completed',\n renderMode,\n delivery: policy,\n disabled: disabled === true,\n ...(ai !== undefined ? { ai } : {}),\n ...(locale !== undefined ? { locale } : {}),\n ...(onInteraction !== undefined ? { onInteraction } : {}),\n });\n\n if (devError) {\n throw devError;\n }\n\n const isExam = renderMode === 'exam';\n const isReview = renderMode === 'review';\n\n const text = isControlled ? textOf(value) : innerText;\n const submitted = state === 'completed';\n const inactive = disabled === true || submitted || isReview;\n const wordCount = countWords(text);\n const withinBounds = wordCount >= data.minWords && wordCount <= data.maxWords;\n\n const handleChange = (next: string): void => {\n if (inactive) {\n return;\n }\n if (state === 'idle') {\n start();\n }\n // A controlled component renders from `props.value` only; the caller's\n // state is the single source of truth for the text.\n if (!isControlled) {\n setInnerText(next);\n }\n const nextWordCount = countWords(next);\n onChange?.({ type: 'written-response', text: next, wordCount: nextWordCount });\n onInteraction?.({\n type: 'text-changed',\n activityId: data.id,\n timestamp: Date.now(),\n payload: { wordCount: nextWordCount },\n });\n };\n\n // Practice reveals nothing an essay could leak, but it DOES run the local\n // submit path and emit a practice xAPI statement for work the server is\n // supposed to grade. MultipleChoice and FillInTheBlanks have refused\n // redacted data in `practice` since 0.5.0; this component silently accepted\n // it, so an all-essay redacted paper mounted without `renderMode` looked\n // entirely healthy end to end. Fail at render, like its siblings.\n if (data.redacted === true && renderMode === 'practice') {\n throw new Error(\n `Written Response \"${data.id}\" received redacted activity data in renderMode \"practice\". ` +\n 'Practice runs the local submit path and emits a practice-mode xAPI statement, so an ' +\n 'exam item wired this way is graded nowhere and looks fine while it happens. ' +\n 'Render redacted data with renderMode=\"exam\" (server grades) or \"review\" (pass `outcome`).',\n );\n }\n\n const handleSubmit = (event: React.FormEvent): void => {\n event.preventDefault();\n if (inactive || text.trim().length === 0) {\n return;\n }\n let finalWordCount = wordCount;\n let finalWithinBounds = withinBounds;\n // `exam` mode must not call evaluate(): the component does not grade, and\n // a redacted projection carries no scoring input anyway. The two facts\n // evaluate() returns for a deferred type (recomputed word count, bounds)\n // are exactly what is computed above, so the payload is identical either\n // way; practice keeps going through core so the numbers stay canonical.\n if (!isExam) {\n const itemOutcome = evaluate(data, { type: 'written-response', text, wordCount });\n const partial = itemOutcome.status === 'deferred' ? itemOutcome.partial : undefined;\n if (typeof partial?.wordCount === 'number') {\n finalWordCount = partial.wordCount;\n }\n if (typeof partial?.withinWordBounds === 'boolean') {\n finalWithinBounds = partial.withinWordBounds;\n }\n }\n complete();\n const timeSpent = getTimeSpent();\n const xapiStatement = xAPIBuilder.buildSubmittedStatement({\n actor: ANONYMOUS_ACTOR,\n object: {\n id: objectIdFor(data.id),\n name: { [data.locale ?? 'en-US']: data.title },\n type: 'http://adlnet.gov/expapi/activities/cmi.interaction',\n interactionType: 'long-fill-in',\n },\n timeSpentMs: timeSpent,\n response: text,\n resultExtensions: {\n 'urn:learning-kit:extension:word-count': finalWordCount,\n 'urn:learning-kit:extension:within-word-bounds': finalWithinBounds,\n },\n });\n // Raw response first (an exam runner persists this), then the fuller\n // ungraded submission — mirroring `onSubmit` before `onComplete`.\n onSubmit?.({ type: 'written-response', text, wordCount: finalWordCount });\n onSubmitted?.({\n text,\n wordCount: finalWordCount,\n withinWordBounds: finalWithinBounds,\n timeSpent,\n xapiStatement,\n });\n setSummary(s.responseSubmitted);\n onInteraction?.({\n type: 'submitted',\n activityId: data.id,\n timestamp: Date.now(),\n payload: { wordCount: finalWordCount, withinWordBounds: finalWithinBounds },\n });\n };\n\n const promptId = `${data.id}-prompt`;\n const counterId = `${data.id}-counter`;\n const boundsLabel = s.wordBounds(data.minWords, data.maxWords);\n\n return (\n <form\n className=\"lk-wr\"\n aria-label={data.title}\n lang={locale}\n data-render-mode={renderMode}\n style={theme as CSSProperties | undefined}\n onSubmit={handleSubmit}\n >\n {data.media ? (\n <ActivityMedia\n media={data.media}\n renderMode={renderMode}\n {...(mediaBudget !== undefined ? { mediaBudget } : {})}\n {...(mediaStrings !== undefined ? { mediaStrings } : {})}\n {...(strings !== undefined ? { strings } : {})}\n {...(onInteraction !== undefined ? { onInteraction } : {})}\n {...(locale !== undefined ? { locale } : {})}\n />\n ) : null}\n {promptHtml === null ? (\n <p className=\"lk-wr-prompt\" id={promptId}>\n {data.prompt}\n </p>\n ) : (\n // A div, not a p: sanitised author HTML may contain block content.\n <div\n className=\"lk-wr-prompt\"\n id={promptId}\n // biome-ignore lint/security/noDangerouslySetInnerHtml: rendered only through the caller-supplied HtmlSanitizer — the SDK never injects unsanitised markup\n dangerouslySetInnerHTML={{ __html: promptHtml }}\n />\n )}\n <textarea\n className=\"lk-wr-textarea\"\n aria-labelledby={promptId}\n aria-describedby={counterId}\n value={text}\n onChange={(event) => handleChange(event.target.value)}\n // `review` uses readOnly rather than disabled: the submitted essay\n // must stay focusable, selectable and scrollable for a screen reader\n // and a keyboard, while remaining uneditable.\n disabled={!isReview && inactive}\n readOnly={isReview}\n rows={8}\n />\n <div\n className=\"lk-wr-counter\"\n id={counterId}\n aria-live=\"polite\"\n data-within-bounds={withinBounds}\n >\n {s.wordCount(wordCount)} ({boundsLabel})\n </div>\n {ai?.writingFeedback !== undefined ? (\n <DraftFeedback help={writingFeedback} draft={text} disabled={disabled === true} s={s} />\n ) : null}\n {isReview ? null : (\n <button\n type=\"submit\"\n className=\"lk-wr-submit\"\n disabled={inactive || text.trim().length === 0}\n >\n {s.submit}\n </button>\n )}\n <FeedbackRegion id={`${data.id}-feedback`}>\n {isReview ? (\n outcome && (policy.feedback || !outcomeShowsMarks(outcome)) ? (\n <OutcomeSummary outcome={outcome} s={s} />\n ) : null\n ) : (\n summary\n )}\n </FeedbackRegion>\n </form>\n );\n}\n","'use client';\n\nimport { useLkStrings } from '../../i18n/LkIntlProvider.js';\nimport { ActivityErrorBoundary } from '../ActivityErrorBoundary.js';\nimport {\n WrittenResponse as WrittenResponseCore,\n type WrittenResponseProps,\n} from './WrittenResponse.js';\n\nexport type { HtmlSanitizer, Renderable, RenderMode } from '../types.js';\nexport type { WrittenResponseProps, WrittenResponseSubmission } from './WrittenResponse.js';\n\n/**\n * Public Written Response activity: a labelled textarea with a live word\n * counter for free-text writing graded asynchronously (AI or human). The core\n * is wrapped in `ActivityErrorBoundary` so a render failure (incl. the dev\n * schema-validation throw) degrades to an accessible fallback.\n */\nexport function WrittenResponse(props: WrittenResponseProps): React.JSX.Element {\n // Read here rather than in the boundary: a class component cannot call a\n // hook, and the fallback it renders is learner-facing text like any other.\n const strings = useLkStrings(props.strings);\n return (\n <ActivityErrorBoundary activityTitle={props.data?.title} strings={strings}>\n <WrittenResponseCore {...props} />\n </ActivityErrorBoundary>\n );\n}\n"],"mappings":"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"}