@intellectif/lk-react 13.0.0 → 14.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/README.md +11 -3
  3. package/dist/{WrittenResponse-B5p_-RnJ.d.ts → WrittenResponse-DrzI89Wg.d.ts} +1 -1
  4. package/dist/{WrittenResponse-DWtS4tOL.d.cts → WrittenResponse-rRpOr9W1.d.cts} +1 -1
  5. package/dist/{chunk-UU2NV6SU.cjs → chunk-4Y5TELVU.cjs} +14 -13
  6. package/dist/chunk-4Y5TELVU.cjs.map +1 -0
  7. package/dist/{chunk-XAGWBVK3.js → chunk-5CP2Z6IS.js} +6 -5
  8. package/dist/chunk-5CP2Z6IS.js.map +1 -0
  9. package/dist/{chunk-NVUFEMPZ.cjs → chunk-5JCTJFQU.cjs} +30 -16
  10. package/dist/chunk-5JCTJFQU.cjs.map +1 -0
  11. package/dist/chunk-5JFMXBH7.js +888 -0
  12. package/dist/chunk-5JFMXBH7.js.map +1 -0
  13. package/dist/{chunk-NVP6UEQQ.js → chunk-AS2QGND5.js} +4 -4
  14. package/dist/{chunk-NVP6UEQQ.js.map → chunk-AS2QGND5.js.map} +1 -1
  15. package/dist/{chunk-3Q4I4KT6.js → chunk-AWQ53DON.js} +78 -2
  16. package/dist/chunk-AWQ53DON.js.map +1 -0
  17. package/dist/{chunk-DQERNAWI.js → chunk-B4BCEQNO.js} +26 -31
  18. package/dist/chunk-B4BCEQNO.js.map +1 -0
  19. package/dist/chunk-BRPEB43C.cjs +13 -0
  20. package/dist/chunk-BRPEB43C.cjs.map +1 -0
  21. package/dist/{chunk-74QXBWCI.cjs → chunk-CTW3G3EH.cjs} +6 -6
  22. package/dist/{chunk-74QXBWCI.cjs.map → chunk-CTW3G3EH.cjs.map} +1 -1
  23. package/dist/{chunk-AMGK7DDM.cjs → chunk-D4DQFTA7.cjs} +2 -2
  24. package/dist/chunk-D4DQFTA7.cjs.map +1 -0
  25. package/dist/{chunk-R7DI5UMU.js → chunk-DB4DLHN6.js} +22 -4
  26. package/dist/chunk-DB4DLHN6.js.map +1 -0
  27. package/dist/{chunk-K3EA547J.cjs → chunk-DPEY7DSE.cjs} +27 -33
  28. package/dist/chunk-DPEY7DSE.cjs.map +1 -0
  29. package/dist/{chunk-W4MXRZAB.js → chunk-IDYZ2FA2.js} +6 -5
  30. package/dist/chunk-IDYZ2FA2.js.map +1 -0
  31. package/dist/{chunk-K7NMNOPI.cjs → chunk-JG4DWAUJ.cjs} +15 -14
  32. package/dist/chunk-JG4DWAUJ.cjs.map +1 -0
  33. package/dist/chunk-KIO6QXGT.cjs +894 -0
  34. package/dist/chunk-KIO6QXGT.cjs.map +1 -0
  35. package/dist/chunk-MCO52PV5.js +520 -0
  36. package/dist/chunk-MCO52PV5.js.map +1 -0
  37. package/dist/{chunk-HT4FFZZQ.cjs → chunk-MZITNWZ2.cjs} +233 -38
  38. package/dist/chunk-MZITNWZ2.cjs.map +1 -0
  39. package/dist/{chunk-Z63JRG4M.cjs → chunk-N536RUCZ.cjs} +15 -14
  40. package/dist/chunk-N536RUCZ.cjs.map +1 -0
  41. package/dist/{chunk-PSHNTDKG.js → chunk-NJAF34GN.js} +13 -161
  42. package/dist/chunk-NJAF34GN.js.map +1 -0
  43. package/dist/chunk-OD65OZIW.cjs +159 -0
  44. package/dist/chunk-OD65OZIW.cjs.map +1 -0
  45. package/dist/{chunk-2GXSA322.cjs → chunk-PSUKWVKU.cjs} +15 -14
  46. package/dist/chunk-PSUKWVKU.cjs.map +1 -0
  47. package/dist/chunk-RCMYEWBE.js +11 -0
  48. package/dist/chunk-RCMYEWBE.js.map +1 -0
  49. package/dist/{chunk-PY53ABWC.js → chunk-RCPW6HVY.js} +23 -9
  50. package/dist/chunk-RCPW6HVY.js.map +1 -0
  51. package/dist/{chunk-DQNVAXG6.js → chunk-RXS455MR.js} +2 -2
  52. package/dist/chunk-RXS455MR.js.map +1 -0
  53. package/dist/chunk-TUVEJLOT.js +537 -0
  54. package/dist/chunk-TUVEJLOT.js.map +1 -0
  55. package/dist/{chunk-YZWXVZB3.js → chunk-U432HTUW.js} +6 -5
  56. package/dist/chunk-U432HTUW.js.map +1 -0
  57. package/dist/chunk-UDCQTOVU.cjs +523 -0
  58. package/dist/chunk-UDCQTOVU.cjs.map +1 -0
  59. package/dist/{chunk-5N7OLFHB.js → chunk-UDQS5INQ.js} +6 -5
  60. package/dist/chunk-UDQS5INQ.js.map +1 -0
  61. package/dist/{chunk-YILH4ETT.js → chunk-UDZWYHDV.js} +226 -31
  62. package/dist/chunk-UDZWYHDV.js.map +1 -0
  63. package/dist/{chunk-SBIJJ374.cjs → chunk-UMDWVMB5.cjs} +24 -6
  64. package/dist/chunk-UMDWVMB5.cjs.map +1 -0
  65. package/dist/{chunk-MA7GXUWC.cjs → chunk-VSFHJ7FB.cjs} +78 -2
  66. package/dist/chunk-VSFHJ7FB.cjs.map +1 -0
  67. package/dist/{chunk-J73TDY7J.cjs → chunk-WC4OD3EE.cjs} +25 -173
  68. package/dist/chunk-WC4OD3EE.cjs.map +1 -0
  69. package/dist/chunk-YM64MS4G.cjs +547 -0
  70. package/dist/chunk-YM64MS4G.cjs.map +1 -0
  71. package/dist/chunk-YORQQXGO.js +155 -0
  72. package/dist/chunk-YORQQXGO.js.map +1 -0
  73. package/dist/components/ActivityPreview.cjs +15 -10
  74. package/dist/components/ActivityPreview.d.cts +9 -3
  75. package/dist/components/ActivityPreview.d.ts +9 -3
  76. package/dist/components/ActivityPreview.js +14 -9
  77. package/dist/components/ActivitySequence.cjs +16 -11
  78. package/dist/components/ActivitySequence.d.cts +115 -4
  79. package/dist/components/ActivitySequence.d.ts +115 -4
  80. package/dist/components/ActivitySequence.js +15 -10
  81. package/dist/components/Dictation.cjs +7 -5
  82. package/dist/components/Dictation.d.cts +2 -1
  83. package/dist/components/Dictation.d.ts +2 -1
  84. package/dist/components/Dictation.js +6 -4
  85. package/dist/components/FillInTheBlanks.cjs +6 -5
  86. package/dist/components/FillInTheBlanks.d.cts +2 -1
  87. package/dist/components/FillInTheBlanks.d.ts +2 -1
  88. package/dist/components/FillInTheBlanks.js +5 -4
  89. package/dist/components/GapSelect.cjs +6 -5
  90. package/dist/components/GapSelect.d.cts +2 -1
  91. package/dist/components/GapSelect.d.ts +2 -1
  92. package/dist/components/GapSelect.js +5 -4
  93. package/dist/components/MultipleChoice.cjs +6 -5
  94. package/dist/components/MultipleChoice.d.cts +2 -1
  95. package/dist/components/MultipleChoice.d.ts +2 -1
  96. package/dist/components/MultipleChoice.js +5 -4
  97. package/dist/components/PronunciationFeedback.cjs +16 -0
  98. package/dist/components/PronunciationFeedback.cjs.map +1 -0
  99. package/dist/components/PronunciationFeedback.d.cts +67 -0
  100. package/dist/components/PronunciationFeedback.d.ts +67 -0
  101. package/dist/components/PronunciationFeedback.js +7 -0
  102. package/dist/components/PronunciationFeedback.js.map +1 -0
  103. package/dist/components/ReadAloud.cjs +21 -0
  104. package/dist/components/ReadAloud.cjs.map +1 -0
  105. package/dist/components/ReadAloud.d.cts +15 -0
  106. package/dist/components/ReadAloud.d.ts +15 -0
  107. package/dist/components/ReadAloud.js +12 -0
  108. package/dist/components/ReadAloud.js.map +1 -0
  109. package/dist/components/StimulusPanel.cjs +4 -4
  110. package/dist/components/StimulusPanel.d.cts +2 -1
  111. package/dist/components/StimulusPanel.d.ts +2 -1
  112. package/dist/components/StimulusPanel.js +3 -3
  113. package/dist/components/WrittenResponse.cjs +6 -5
  114. package/dist/components/WrittenResponse.d.cts +4 -3
  115. package/dist/components/WrittenResponse.d.ts +4 -3
  116. package/dist/components/WrittenResponse.js +5 -4
  117. package/dist/hooks/useSpeechRecorder.cjs +17 -0
  118. package/dist/hooks/useSpeechRecorder.cjs.map +1 -0
  119. package/dist/hooks/useSpeechRecorder.d.cts +127 -0
  120. package/dist/hooks/useSpeechRecorder.d.ts +127 -0
  121. package/dist/hooks/useSpeechRecorder.js +4 -0
  122. package/dist/hooks/useSpeechRecorder.js.map +1 -0
  123. package/dist/i18n/LkIntlProvider.cjs +7 -7
  124. package/dist/i18n/LkIntlProvider.d.cts +3 -2
  125. package/dist/i18n/LkIntlProvider.d.ts +3 -2
  126. package/dist/i18n/LkIntlProvider.js +1 -1
  127. package/dist/index.cjs +53 -32
  128. package/dist/index.cjs.map +1 -1
  129. package/dist/index.d.cts +6 -2
  130. package/dist/index.d.ts +6 -2
  131. package/dist/index.js +17 -12
  132. package/dist/index.js.map +1 -1
  133. package/dist/machine-CuwKqWXC.d.cts +26 -0
  134. package/dist/machine-CuwKqWXC.d.ts +26 -0
  135. package/dist/{strings-DPTyLpHt.d.cts → strings-l8Wv1Xax.d.ts} +230 -4
  136. package/dist/{strings-DPTyLpHt.d.ts → strings-wjAF2ONm.d.cts} +230 -4
  137. package/dist/theme/ThemeProvider.cjs +6 -6
  138. package/dist/theme/ThemeProvider.d.cts +4 -4
  139. package/dist/theme/ThemeProvider.d.ts +4 -4
  140. package/dist/theme/ThemeProvider.js +1 -1
  141. package/dist/theme/skin.css +612 -3
  142. package/package.json +33 -3
  143. package/dist/chunk-2GXSA322.cjs.map +0 -1
  144. package/dist/chunk-3Q4I4KT6.js.map +0 -1
  145. package/dist/chunk-5N7OLFHB.js.map +0 -1
  146. package/dist/chunk-AMGK7DDM.cjs.map +0 -1
  147. package/dist/chunk-DQERNAWI.js.map +0 -1
  148. package/dist/chunk-DQNVAXG6.js.map +0 -1
  149. package/dist/chunk-HT4FFZZQ.cjs.map +0 -1
  150. package/dist/chunk-J73TDY7J.cjs.map +0 -1
  151. package/dist/chunk-K3EA547J.cjs.map +0 -1
  152. package/dist/chunk-K7NMNOPI.cjs.map +0 -1
  153. package/dist/chunk-MA7GXUWC.cjs.map +0 -1
  154. package/dist/chunk-NVUFEMPZ.cjs.map +0 -1
  155. package/dist/chunk-PSHNTDKG.js.map +0 -1
  156. package/dist/chunk-PY53ABWC.js.map +0 -1
  157. package/dist/chunk-R7DI5UMU.js.map +0 -1
  158. package/dist/chunk-SBIJJ374.cjs.map +0 -1
  159. package/dist/chunk-UU2NV6SU.cjs.map +0 -1
  160. package/dist/chunk-W4MXRZAB.js.map +0 -1
  161. package/dist/chunk-XAGWBVK3.js.map +0 -1
  162. package/dist/chunk-YILH4ETT.js.map +0 -1
  163. package/dist/chunk-YZWXVZB3.js.map +0 -1
  164. package/dist/chunk-Z63JRG4M.cjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/shared/playback-refusal.ts","../src/components/shared/read-grade.ts","../src/components/PronunciationFeedback/PronunciationFeedback.tsx","../src/components/PronunciationFeedback/index.tsx"],"names":["useState","PronunciationFeedback","jsx"],"mappings":";;;;;;;AAsBO,SAAS,mBAAmB,GAAA,EAGjC;AACA,EAAA,MAAM,CAAC,UAAA,EAAY,aAAa,CAAA,GAAI,SAAwB,IAAI,CAAA;AAChE,EAAA,MAAM,MAAA,GAAS,WAAA,CAAY,CAAC,OAAA,KAA8B;AACxD,IAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,YAAA,CAAa,KAAK,CAAA;AACzC,IAAA,IAAI,WAAW,IAAA,EAAM;AACnB,MAAA,aAAA,CAAc,MAAM,CAAA;AAAA,IACtB;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AACL,EAAA,OAAO,EAAE,SAAS,GAAA,KAAQ,IAAA,IAAQ,QAAQ,MAAA,IAAa,GAAA,KAAQ,YAAY,MAAA,EAAO;AACpF;AAOO,SAAS,gBAAgB,KAAA,EAAyB;AACvD,EAAA,OACE,OAAO,KAAA,KAAU,QAAA,IACjB,KAAA,KAAU,IAAA,IACT,MAA6B,IAAA,KAAS,mBAAA;AAE3C;;;ACiDA,IAAM,UAAA,GAA4C;AAAA,EAChD,UAAA;AAAA,EACA,SAAA;AAAA,EACA,cAAA;AAAA,EACA;AACF,CAAA;AAEA,IAAM,QAAA,GAAsC;AAAA,EAC1C,SAAA;AAAA,EACA,WAAA;AAAA,EACA,kBAAA;AAAA,EACA;AACF,CAAA;AASA,IAAM,SAAA,GAAY,IAAA;AAElB,SAAS,SAAS,KAAA,EAAkD;AAClE,EAAA,OAAO,OAAO,UAAU,QAAA,IAAY,KAAA,KAAU,QAAQ,CAAC,KAAA,CAAM,QAAQ,KAAK,CAAA;AAC5E;AAEA,SAAS,eAAe,KAAA,EAAiC;AACvD,EAAA,OAAO,OAAO,KAAA,KAAU,QAAA,IAAY,MAAA,CAAO,SAAS,KAAK,CAAA;AAC3D;AAGA,SAAS,SAAS,KAAA,EAA2C;AAC3D,EAAA,OAAO,KAAA,KAAU,UAAa,KAAA,KAAU,IAAA;AAC1C;AAGA,SAAS,SAAA,CAAU,OAAgB,GAAA,EAA4B;AAC7D,EAAA,IAAI,CAAC,cAAA,CAAe,KAAK,CAAA,IAAK,QAAQ,CAAA,EAAG;AACvC,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IAAI,SAAS,GAAA,EAAK;AAChB,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,OAAO,KAAA,GAAQ,GAAA,IAAO,GAAA,GAAM,SAAA,GAAY,GAAA,GAAM,IAAA;AAChD;AAGA,SAAS,WAAW,KAAA,EAA4C;AAC9D,EAAA,OACE,OAAO,KAAA,KAAU,QAAA,IAChB,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,IAAK,KAAA,CAAM,KAAA,CAAM,CAAC,KAAA,KAAU,OAAO,UAAU,QAAQ,CAAA;AAE7E;AAGA,SAAS,OAAA,CAAW,MAAe,OAAA,EAAe;AAChD,EAAA,IAAI;AACF,IAAA,OAAO,IAAA,EAAK;AAAA,EACd,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,OAAA;AAAA,EACT;AACF;AAEA,SAAS,cAAc,KAAA,EAAuC;AAC5D,EAAA,IAAI,CAAC,QAAA,CAAS,KAAK,KAAK,OAAO,KAAA,CAAM,SAAS,QAAA,EAAU;AACtD,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,MAAM,EAAE,QAAA,EAAU,aAAA,EAAc,GAAI,KAAA;AACpC,EAAA,IAAI,CAAC,SAAS,QAAQ,CAAA,IAAK,EAAE,cAAA,CAAe,QAAQ,CAAA,IAAK,QAAA,GAAW,CAAA,CAAA,EAAI;AACtE,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IAAI,CAAC,QAAA,CAAS,aAAa,CAAA,IAAK,OAAO,kBAAkB,SAAA,EAAW;AAClE,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,KAAA,CAAM,KAAK,CAAA,GAAI,SAAY,SAAA,CAAU,KAAA,CAAM,KAAA,EAAO,QAAA,IAAY,CAAC,CAAA;AACtF,EAAA,IAAI,UAAU,IAAA,EAAM;AAClB,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO;AAAA,IACL,MAAM,KAAA,CAAM,IAAA;AAAA,IACZ,GAAI,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,KAAU,EAAC;AAAA,IACvC,GAAI,CAAC,QAAA,CAAS,QAAQ,IAAI,EAAE,QAAA,KAAa,EAAC;AAAA,IAC1C,GAAI,aAAA,KAAkB,IAAA,GAAO,EAAE,aAAA,KAAkB;AAAC,GACpD;AACF;AAEA,SAAS,WAAW,KAAA,EAAsC;AACxD,EAAA,IAAI,CAAC,QAAA,CAAS,KAAK,CAAA,EAAG;AACpB,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,MAAM,EAAE,QAAQ,OAAA,EAAS,OAAA,EAAS,iBAAiB,eAAA,EAAiB,MAAA,EAAQ,OAAM,GAAI,KAAA;AACtF,EAAA,IACE,OAAO,MAAA,KAAW,QAAA,IAClB,OAAO,OAAA,KAAY,SAAA,IACnB,CAAC,UAAA,CAAW,eAAe,CAAA,IAC3B,CAAC,UAAA,CAAW,eAAe,CAAA,EAC3B;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,MAAM,iBAAiB,QAAA,CAAS,IAAA,CAAK,CAAC,KAAA,KAAU,UAAU,OAAO,CAAA;AACjE,EAAA,IAAI,CAAC,QAAA,CAAS,OAAO,CAAA,IAAK,mBAAmB,MAAA,EAAW;AACtD,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IAAI,CAAC,QAAA,CAAS,MAAM,KAAK,CAAC,cAAA,CAAe,MAAM,CAAA,EAAG;AAChD,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,eAAe,QAAA,CAAS,KAAK,IAAI,MAAA,GAAY,SAAA,CAAU,OAAO,CAAC,CAAA;AACrE,EAAA,IAAI,iBAAiB,IAAA,EAAM;AACzB,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO;AAAA,IACL,MAAA;AAAA,IACA,OAAA;AAAA,IACA,eAAA;AAAA,IACA,eAAA;AAAA,IACA,GAAI,cAAA,KAAmB,MAAA,GAAY,EAAE,OAAA,EAAS,cAAA,KAAmB,EAAC;AAAA,IAClE,GAAI,CAAC,QAAA,CAAS,MAAM,IAAI,EAAE,MAAA,KAAW,EAAC;AAAA,IACtC,GAAI,YAAA,KAAiB,MAAA,GAAY,EAAE,KAAA,EAAO,YAAA,KAAiB;AAAC,GAC9D;AACF;AAEA,SAAS,YAAY,KAAA,EAA6C;AAChE,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACzB,IAAA,OAAO,MAAA;AAAA,EACT;AACA,EAAA,MAAM,UAA2B,EAAC;AAClC,EAAA,KAAA,MAAW,SAAS,KAAA,EAAO;AACzB,IAAA,MAAM,MAAA,GAAS,WAAW,KAAK,CAAA;AAC/B,IAAA,IAAI,WAAW,IAAA,EAAM;AACnB,MAAA,OAAO,MAAA;AAAA,IACT;AACA,IAAA,OAAA,CAAQ,KAAK,MAAM,CAAA;AAAA,EACrB;AACA,EAAA,OAAO,OAAA;AACT;AAMO,SAAS,UAAU,KAAA,EAAkC;AAC1D,EAAA,OAAO,QAAQ,MAAM;AACnB,IAAA,IAAI,CAAC,QAAA,CAAS,KAAK,CAAA,EAAG;AACpB,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,MAAM,EAAE,QAAA,EAAU,MAAA,EAAO,GAAI,KAAA;AAC7B,IAAA,IAAI,CAAC,eAAe,QAAQ,CAAA,IAAK,YAAY,CAAA,IAAK,OAAO,WAAW,SAAA,EAAW;AAC7E,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,KAAA,CAAM,KAAA,EAAO,QAAQ,CAAA;AAC7C,IAAA,IAAI,UAAU,IAAA,EAAM;AAClB,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,MAAM,QAAA,GAAW,KAAA,CAAM,OAAA,CAAQ,KAAA,CAAM,QAAQ,IACzC,KAAA,CAAM,QAAA,CAAS,OAAA,CAAQ,CAAC,KAAA,KAAU;AAChC,MAAA,MAAM,SAAA,GAAY,cAAc,KAAK,CAAA;AACrC,MAAA,OAAO,SAAA,KAAc,IAAA,GAAO,EAAC,GAAI,CAAC,SAAS,CAAA;AAAA,IAC7C,CAAC,CAAA,GACD,KAAA,CAAA;AACJ,IAAA,MAAM,OAAA,GAAU,WAAA,CAAY,KAAA,CAAM,OAAO,CAAA;AACzC,IAAA,MAAM,KAAA,GAAqB;AAAA,MACzB,KAAA;AAAA,MACA,QAAA;AAAA,MACA,MAAA;AAAA,MACA,UAAU,OAAO,KAAA,CAAM,QAAA,KAAa,QAAA,GAAW,MAAM,QAAA,GAAW,IAAA;AAAA,MAChE,GAAI,QAAA,KAAa,KAAA,CAAA,GAAY,EAAE,QAAA,KAAa,EAAC;AAAA,MAC7C,GAAI,OAAA,KAAY,KAAA,CAAA,GAAY,EAAE,OAAA,KAAY;AAAC,KAC7C;AACA,IAAA,OAAO,KAAA;AAAA,EACT,GAAG,IAAI,CAAA;AACT;AAGO,SAAS,gBAAgB,KAAA,EAA0B;AACxD,EAAA,OAAO,KAAA,CAAM,QAAQ,KAAA,CAAM,QAAA;AAC7B;AAGO,SAAS,eAAe,KAAA,EAA0B;AACvD,EAAA,OAAO,IAAA,CAAK,KAAA,CAAM,eAAA,CAAgB,KAAK,IAAI,GAAG,CAAA;AAChD;AAYO,SAAS,YAAY,KAAA,EAA4C;AACtE,EAAA,IAAI,QAAA,CAAS,KAAK,CAAA,EAAG;AACnB,IAAA,OAAO,MAAA;AAAA,EACT;AACA,EAAA,OAAO,OAAA;AAAA,IACL,MAAsB;AACpB,MAAA,IAAI,CAAC,QAAA,CAAS,KAAK,CAAA,EAAG;AACpB,QAAA,OAAO,EAAE,IAAA,EAAM,YAAA,EAAc,MAAA,EAAQ,KAAA,CAAA,EAAU;AAAA,MACjD;AACA,MAAA,QAAQ,MAAM,MAAA;AAAQ,QACpB,KAAK,UAAA;AACH,UAAA,OAAO,EAAE,MAAM,UAAA,EAAW;AAAA,QAC5B,KAAK,YAAA;AACH,UAAA,OAAO;AAAA,YACL,IAAA,EAAM,YAAA;AAAA,YACN,MAAM,OAAO,KAAA,CAAM,IAAA,KAAS,QAAA,GAAW,MAAM,IAAA,GAAO,KAAA;AAAA,WACtD;AAAA,QACF,KAAK,QAAA,EAAU;AACb,UAAA,MAAM,KAAA,GAAQ,UAAU,KAAK,CAAA;AAC7B,UAAA,OAAO,KAAA,KAAU,IAAA,GACb,EAAE,IAAA,EAAM,YAAA,EAAc,MAAA,EAAQ,QAAA,EAAS,GACvC,EAAE,IAAA,EAAM,QAAA,EAAU,MAAA,EAAQ,UAAU,KAAA,EAAM;AAAA,QAChD;AAAA,QACA,KAAK,QAAA,EAAU;AACb,UAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,KAAA,CAAM,KAAK,CAAA;AACnC,UAAA,OAAO,UAAU,IAAA,IAAQ,SAAA,CAAU,KAAK,CAAA,KAAM,OAC1C,EAAE,IAAA,EAAM,YAAA,EAAc,MAAA,EAAQ,UAAS,GACvC,EAAE,MAAM,QAAA,EAAU,MAAA,EAAQ,UAAU,KAAA,EAAM;AAAA,QAChD;AAAA,QACA;AACE,UAAA,OAAO,EAAE,IAAA,EAAM,YAAA,EAAc,MAAA,EAAQ,KAAA,CAAA,EAAU;AAAA;AACnD,IACF,CAAA;AAAA,IACA,EAAE,IAAA,EAAM,YAAA,EAAc,MAAA,EAAQ,MAAA;AAAU,GAC1C;AACF;AAYO,SAAS,iBAAiB,KAAA,EAA+B;AAC9D,EAAA,MAAM,OAAA,GAAyB;AAAA,IAC7B,MAAA,EAAQ,QAAA;AAAA,IACR,KAAA,EAAO,IAAA;AAAA,IACP,UAAA,EAAY,IAAA;AAAA,IACZ,cAAA,EAAgB;AAAA,GAClB;AACA,EAAA,OAAO,QAAQ,MAAqB;AAClC,IAAA,IAAI,CAAC,QAAA,CAAS,KAAK,CAAA,EAAG;AACpB,MAAA,OAAO,OAAA;AAAA,IACT;AACA,IAAA,IAAI,KAAA,CAAM,WAAW,QAAA,EAAU;AAC7B,MAAA,OAAO,EAAE,MAAA,EAAQ,QAAA,EAAU,SAAA,EAAW,KAAA,CAAM,cAAc,IAAA,EAAK;AAAA,IACjE;AACA,IAAA,IAAI,KAAA,CAAM,WAAW,YAAA,EAAc;AACjC,MAAA,OAAO;AAAA,QACL,MAAA,EAAQ,YAAA;AAAA,QACR,MAAM,OAAO,KAAA,CAAM,IAAA,KAAS,QAAA,GAAW,MAAM,IAAA,GAAO,KAAA;AAAA,OACtD;AAAA,IACF;AACA,IAAA,IAAI,KAAA,CAAM,WAAW,QAAA,EAAU;AAC7B,MAAA,OAAO,OAAA;AAAA,IACT;AACA,IAAA,MAAM,UAAA,GAAa,YAAA,CAAa,KAAA,CAAM,UAAU,CAAA;AAChD,IAAA,MAAM,cAAA,GAAiB,OAAA;AAAA,MACrB,MACE,OAAO,UAAA,EAAY,cAAA,KAAmB,QAAA,GAAW,WAAW,cAAA,GAAiB,KAAA,CAAA;AAAA,MAC/E,KAAA;AAAA,KACF;AACA,IAAA,OAAO,EAAE,QAAQ,QAAA,EAAU,KAAA,EAAO,UAAU,KAAA,CAAM,KAAK,CAAA,EAAG,UAAA,EAAY,cAAA,EAAe;AAAA,EACvF,GAAG,OAAO,CAAA;AACZ;AAMO,SAAS,aAAa,KAAA,EAAyC;AACpE,EAAA,OAAO,QAAA,CAAS,KAAK,CAAA,GAAK,KAAA,GAAwC,IAAA;AACpE;AAGA,SAAS,mBAAmB,SAAA,EAA+C;AACzE,EAAA,IAAI,SAAA,CAAU,aAAA,KAAkB,IAAA,IAAQ,SAAA,CAAU,UAAU,MAAA,EAAW;AACrE,IAAA,OAAO,MAAA;AAAA,EACT;AACA,EAAA,OAAO,KAAK,KAAA,CAAO,SAAA,CAAU,SAAS,SAAA,CAAU,QAAA,IAAY,KAAM,GAAG,CAAA;AACvE;AAaO,SAAS,cAAA,CACd,YACA,KAAA,EACoB;AACpB,EAAA,MAAM,QAAA,GAAW,KAAA,EAAO,QAAA,IAAY,EAAC;AACrC,EAAA,IAAI,QAAA,CAAS,SAAS,CAAA,EAAG;AACvB,IAAA,OAAO,UAAA,CAAW,GAAA,CAAI,CAAC,SAAA,KAAc;AACnC,MAAA,MAAM,YAAY,QAAA,CAAS,IAAA,CAAK,CAAC,KAAA,KAAU,KAAA,CAAM,SAAS,SAAS,CAAA;AACnE,MAAA,OAAO;AAAA,QACL,SAAA;AAAA,QACA,OAAA,EAAS,SAAA,KAAc,MAAA,GAAY,MAAA,GAAY,mBAAmB,SAAS;AAAA,OAC7E;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AACA,EAAA,MAAM,MAAA,GAAS,QAAQ,MAAO,QAAA,CAAS,UAAU,CAAA,GAAI,UAAA,CAAW,MAAA,GAAS,KAAA,CAAA,EAAY,MAAS,CAAA;AAC9F,EAAA,OAAO,UAAA,CAAW,GAAA,CAAI,CAAC,SAAA,KAAc;AACnC,IAAA,MAAM,KAAA,GAAQ,SAAA;AAAA,MACZ,OAAA,CAAQ,MAAO,QAAA,CAAS,MAAM,IAAI,MAAA,CAAO,SAAS,CAAA,GAAI,KAAA,CAAA,EAAY,MAAS,CAAA;AAAA,MAC3E;AAAA,KACF;AAEA,IAAA,OAAO,EAAE,WAAW,OAAA,EAAS,KAAA,KAAU,OAAO,MAAA,GAAY,IAAA,CAAK,KAAA,CAAM,KAAK,CAAA,EAAE;AAAA,EAC9E,CAAC,CAAA;AACH;ACtYO,IAAM,eAAA,GAAiC;AAAA,EAC5C,QAAA,EAAU,UAAA;AAAA,EACV,KAAA,EAAO,CAAA;AAAA,EACP,MAAA,EAAQ,CAAA;AAAA,EACR,MAAA,EAAQ,EAAA;AAAA,EACR,OAAA,EAAS,CAAA;AAAA,EACT,QAAA,EAAU,QAAA;AAAA,EACV,IAAA,EAAM,eAAA;AAAA,EACN,QAAA,EAAU,YAAA;AAAA,EACV,UAAA,EAAY,QAAA;AAAA,EACZ,MAAA,EAAQ;AACV;AAGA,IAAM,aAAA,GAA4D;AAAA,EAChE,SAAA;AAAA,EACA,eAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA;AAyDA,SAAS,cAAc,UAAA,EAAyD;AAC9E,EAAA,IAAI;AACF,IAAA,OAAO,yBAAyB,UAAU,CAAA;AAAA,EAC5C,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO;AAAA,MACL,OAAA,EAAS,KAAA;AAAA,MACT,MAAA,EAAQ,CAAC,EAAE,IAAA,EAAM,IAAI,OAAA,EAAS,mCAAA,EAAqC,IAAA,EAAM,YAAA,EAAc;AAAA,KACzF;AAAA,EACF;AACF;AAGA,SAAS,UAAU,IAAA,EAAkD;AACnE,EAAA,IAAI,SAAS,MAAA,EAAW;AACtB,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,OACE,IAAA,CAAK,QAAA,KAAa,MAAA,IACjB,IAAA,CAAK,SAAA,KAAc,MAAA,IAAa,IAAA,CAAK,SAAA,CAAU,MAAA,GAAS,CAAA,IACxD,IAAA,CAAK,QAAA,KAAa,MAAA,IAAa,KAAK,QAAA,CAAS,MAAA,GAAS,CAAA,IACvD,IAAA,CAAK,MAAA,KAAW,MAAA,IACf,OAAO,IAAA,CAAK,OAAA,KAAY,QAAA,IAAY,OAAO,IAAA,CAAK,UAAA,KAAe,QAAA;AAEpE;AAGA,SAAS,IAAA,CAAK,YAAgC,SAAA,EAAwC;AACpF,EAAA,OACE,SAAA,KAAc,UACd,OAAO,UAAA,KAAe,YACtB,MAAA,CAAO,QAAA,CAAS,UAAU,CAAA,IAC1B,UAAA,GAAa,SAAA;AAEjB;AAGA,SAAS,YAAA,CAAa,OAAA,EAAwB,KAAA,EAAe,CAAA,EAAsB;AACjF,EAAA,OAAO,OAAA,CAAQ,MAAA,IAAU,CAAA,CAAE,4BAAA,CAA6B,QAAQ,CAAC,CAAA;AACnE;AAaO,SAAS,YAAA,CAAa,OAA+B,CAAA,EAAsB;AAChF,EAAA,QAAQ,MAAM,KAAA;AAAO,IACnB,KAAK,SAAA;AACH,MAAA,OAAO,CAAA,CAAE,wBAAA,CAAyB,KAAA,CAAM,SAAS,CAAA;AAAA,IACnD,KAAK,eAAA;AACH,MAAA,OAAO,CAAA,CAAE,8BAAA,CAA+B,KAAA,CAAM,SAAS,CAAA;AAAA,IACzD,KAAK,SAAA;AACH,MAAA,OAAO,CAAA,CAAE,wBAAA,CAAyB,KAAA,CAAM,SAAS,CAAA;AAAA,IACnD;AACE,MAAA,OAAO,CAAA,CAAE,yBAAA,CAA0B,KAAA,CAAM,KAAK,CAAA;AAAA;AAEpD;AAoCO,SAAS,qBAAA,CAAsB;AAAA,EACpC,IAAA;AAAA,EACA,UAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA;AAAA,EACA,cAAA;AAAA,EACA,iBAAA;AAAA,EACA,MAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CAAA,EAA+B;AAC7B,EAAA,MAAM,CAAA,GAAI,aAAa,OAAO,CAAA;AAC9B,EAAA,MAAM,MAAM,KAAA,EAAM;AAClB,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAIA,SAAwB,IAAI,CAAA;AAE5D,EAAA,MAAM,OAAA,GAAU,QAAQ,MAAM,aAAA,CAAc,UAAU,CAAA,EAAG,CAAC,UAAU,CAAC,CAAA;AAErE,EAAA,MAAM,QAAA,GAAW,OAAA;AAAA,IACf,MACE,aAAA,EAAc,IAAK,CAAC,OAAA,CAAQ,OAAA,GACxB,IAAI,mBAAA,CAAoB,YAAA,EAAc,OAAA,CAAQ,MAAM,CAAA,GACpD,IAAA;AAAA,IACN,CAAC,OAAO;AAAA,GACV;AAKA,EAAA,MAAM,KAAA,GAAQ,OAAA;AAAA,IACZ,MAAO,OAAA,CAAQ,OAAA,GAAU,eAAe,IAAA,EAAM,OAAA,CAAQ,IAAI,CAAA,GAAI,IAAA;AAAA,IAC9D,CAAC,SAAS,IAAI;AAAA,GAChB;AAKA,EAAA,MAAM,OAAA,GAAU,OAAA;AAAA,IACd,MAAO,KAAA,KAAU,MAAA,IAAa,UAAU,IAAA,GAAO,MAAA,GAAY,UAAU,KAAK,CAAA;AAAA,IAC1E,CAAC,KAAK;AAAA,GACR;AACA,EAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,MAAM,cAAA,CAAe,UAAA,EAAY,OAAO,CAAA,EAAG,CAAC,UAAA,EAAY,OAAO,CAAC,CAAA;AAI3F,EAAA,MAAM,QAAA,GAAW,OAAyB,IAAI,CAAA;AAC9C,EAAA,MAAM,OAAA,GAAU,OAA6C,IAAI,CAAA;AACjE,EAAA,MAAM,QAAA,GAAW,mBAAmB,QAAQ,CAAA;AAG5C,EAAA,MAAM,QAAA,GAAW,QAAA,KAAa,MAAA,IAAa,CAAC,QAAA,CAAS,OAAA;AACrD,EAAA,SAAA;AAAA,IACE,MAAM,MAAM;AACV,MAAA,IAAI,OAAA,CAAQ,YAAY,IAAA,EAAM;AAC5B,QAAA,YAAA,CAAa,QAAQ,OAAO,CAAA;AAAA,MAC9B;AAAA,IACF,CAAA;AAAA,IACA;AAAC,GACH;AAGA,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,MAAM,QAAA;AAAA,EACR;AAGA,EAAA,MAAM,QAAA,GAAW,CAAC,OAAA,EAAiB,UAAA,KAA6B;AAC9D,IAAA,MAAM,UAAU,QAAA,CAAS,OAAA;AACzB,IAAA,IAAI,YAAY,IAAA,EAAM;AACpB,MAAA;AAAA,IACF;AACA,IAAA,IAAI,OAAA,CAAQ,YAAY,IAAA,EAAM;AAC5B,MAAA,YAAA,CAAa,QAAQ,OAAO,CAAA;AAAA,IAC9B;AACA,IAAA,OAAA,CAAQ,cAAc,OAAA,GAAU,GAAA;AAChC,IAAA,IAAI;AACF,MAAA,KAAK,OAAA,CAAQ,IAAA,EAAK,CAAE,KAAA,CAAM,CAAC,KAAA,KAAmB;AAI5C,QAAA,IAAI,eAAA,CAAgB,KAAK,CAAA,EAAG;AAC1B,UAAA,QAAA,CAAS,OAAO,OAAO,CAAA;AAAA,QACzB;AAAA,MACF,CAAC,CAAA;AAAA,IACH,CAAA,CAAA,MAAQ;AAAA,IAER;AACA,IAAA,OAAA,CAAQ,OAAA,GAAU,WAAW,MAAM;AACjC,MAAA,OAAA,CAAQ,OAAA,GAAU,IAAA;AAClB,MAAA,OAAA,CAAQ,KAAA,EAAM;AAAA,IAChB,GAAG,UAAU,CAAA;AAAA,EACf,CAAA;AAMA,EAAA,MAAM,cAAc,OAAO,IAAA,CAAK,MAAA,KAAW,QAAA,GAAW,KAAK,MAAA,GAAS,MAAA;AACpE,EAAA,MAAM,UAAA,GAAa,iBAAA,CAAkB,IAAA,CAAK,MAAM,CAAA;AAEhD,EAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,OAAA,GAAU,OAAA,CAAQ,KAAK,eAAA,GAAkB,MAAA;AAClE,EAAA,MAAM,WAAW,OAAA,CAAQ,OAAA,GAAU,OAAA,CAAQ,IAAA,CAAK,SAAS,kBAAA,GAAqB,MAAA;AAG9E,EAAA,MAAM,gBAAuC,OAAA,CAAQ,OAAA,GAAU,OAAA,CAAQ,IAAA,CAAK,QAAQ,EAAC;AAErF,EAAA,uBACE,IAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAU,OAAA;AAAA,MACV,cAAY,CAAA,CAAE,0BAAA;AAAA,MACd,IAAA,EAAM,MAAA;AAAA,MACN,KAAA,EAAO,KAAA;AAAA,MAEN,QAAA,EAAA;AAAA,QAAA,OAAA,KAAY,MAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BASX,IAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,SAAA,EAAU,aAAA;AAAA,cACT,GAAI,OAAA,KAAY,IAAA,GAAO,EAAE,aAAA,EAAe,OAAO,OAAA,CAAQ,MAAM,CAAA,EAAE,GAAI,EAAC;AAAA,cAErE,QAAA,EAAA;AAAA,gCAAA,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,aAAA,EACV,QAAA,EAAA,OAAA,KAAY,OACT,CAAA,CAAE,gBAAA,GACF,CAAA,CAAE,iBAAA,CAAkB,cAAA,CAAe,OAAO,CAAA,EAAG,OAAA,CAAQ,MAAM,CAAA,EACjE,CAAA;AAAA,gBAKC,OAAA,EAAS,QAAA,mBACR,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,wBAAuB,GAAA,EAAI,MAAA,EACrC,QAAA,EAAA,OAAA,CAAQ,QAAA,EACX,CAAA,GACE;AAAA;AAAA;AAAA;AACN,YACE,IAAA;AAAA,4BAEH,IAAA,EAAA,EAAG,SAAA,EAAU,kBAAA,EACX,QAAA,EAAA,UAAA,CAAW,IAAI,CAAC,EAAE,SAAA,EAAW,OAAA,uBAC5B,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,iBAAA,EAAkC,kBAAgB,SAAA,EAC/D,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,QAAG,SAAA,EAAU,sBAAA,EAAwB,QAAA,EAAA,CAAA,CAAE,sBAAA,CAAuB,SAAS,CAAA,EAAE,CAAA;AAAA,0BAI1E,GAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,uBAAA,EACX,QAAA,EAAA,OAAA,KAAY,SAAY,CAAA,CAAE,wBAAA,GAA2B,CAAA,EAAG,OAAO,CAAA,CAAA,CAAA,EAClE;AAAA,SAAA,EAAA,EAPoC,SAQtC,CACD,CAAA,EACH,CAAA;AAAA,QAEC,KAAA,KAAU,uBACT,IAAA,CAAA,QAAA,EAAA,EAKE,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,aAAA,EAAc,YAAA,EAAY,CAAA,CAAE,uBAAA,EAAyB,GAAA,EAAK,UAAA,EACrE,QAAA,EAAA,KAAA,CAAM,GAAA,CAAI,CAAC,KAAA,EAAO,KAAA,KAAU;AAC3B,YAAA,MAAM,QAAA,GAAW,YAAA,CAAa,KAAA,EAAO,CAAC,CAAA;AACtC,YAAA,MAAM,QAAQ,KAAA,CAAM,KAAA,KAAU,UAAA,GAAa,KAAA,CAAM,QAAQ,KAAA,CAAM,SAAA;AAC/D,YAAA,MAAM,IAAA,GACJ,MAAM,SAAA,KAAc,MAAA,GAAY,SAAY,aAAA,CAAc,EAAA,CAAG,MAAM,SAAS,CAAA;AAC9E,YAAA,MAAM,OAAO,QAAA,KAAa,KAAA;AAC1B,YAAA,MAAM,OAAA,GAAU,CAAA,EAAG,GAAG,CAAA,EAAA,EAAK,KAAK,CAAA,CAAA;AAChC,YAAA,uBACE,IAAA;AAAA,cAAC,IAAA;AAAA,cAAA;AAAA,gBAGC,SAAA,EAAU,YAAA;AAAA,gBACV,cAAY,KAAA,CAAM,KAAA;AAAA,gBAMlB,QAAA,EAAA;AAAA,kCAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,oBAAA,EAAqB,KAAA,EAAO,iBACzC,QAAA,EAAA,QAAA,EACH,CAAA;AAAA,kCAIA,GAAA;AAAA,oBAAC,MAAA;AAAA,oBAAA;AAAA,sBACC,SAAA,EAAU,iBAAA;AAAA,sBACV,aAAA,EAAY,MAAA;AAAA,sBACZ,KAAK,UAAA,IAAc,MAAA;AAAA,sBACnB,IAAA,EAAM,WAAA;AAAA,sBAEL,QAAA,EAAA;AAAA;AAAA,mBACH;AAAA,kBACC,SAAA,CAAU,IAAI,CAAA,mBACb,IAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,oCAAA,GAAA;AAAA,sBAAC,QAAA;AAAA,sBAAA;AAAA,wBACC,IAAA,EAAK,QAAA;AAAA,wBACL,SAAA,EAAU,mBAAA;AAAA,wBACV,eAAA,EAAe,IAAA;AAAA,wBACf,eAAA,EAAe,OAAA;AAAA,wBACf,OAAA,EAAS,MAAM,WAAA,CAAY,IAAA,GAAO,OAAO,KAAK,CAAA;AAAA,wBAE7C,QAAA,EAAA,CAAA,CAAE,yBAAyB,KAAK;AAAA;AAAA,qBACnC;AAAA,oBACC,uBACC,IAAA,CAAC,KAAA,EAAA,EAAI,EAAA,EAAI,OAAA,EAAS,WAAU,mBAAA,EAC1B,QAAA,EAAA;AAAA,sCAAA,IAAA,CAAC,IAAA,EAAA,EAAG,WAAU,kBAAA,EACZ,QAAA,EAAA;AAAA,wCAAA,GAAA,CAAC,IAAA,EAAA,EAAI,QAAA,EAAA,CAAA,CAAE,sBAAA,CAAuB,UAAU,CAAA,EAAE,CAAA;AAAA,wCAC1C,GAAA,CAAC,IAAA,EAAA,EACE,QAAA,EAAA,IAAA,CAAK,QAAA,KAAa,MAAA,GACf,CAAA,CAAE,wBAAA,GACF,CAAA,EAAG,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,QAAQ,CAAC,CAAA,CAAA,CAAA,EAClC,CAAA;AAAA,wBACC,KAAK,SAAA,KAAc,MAAA,IAAa,KAAK,SAAA,CAAU,MAAA,GAAS,oBACvD,IAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,0CAAA,GAAA,CAAC,IAAA,EAAA,EAAI,YAAE,sBAAA,EAAuB,CAAA;AAAA,0CAC9B,GAAA,CAAC,IAAA,EAAA,EACC,QAAA,kBAAA,GAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,iBAAA,EACX,QAAA,EAAA,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,CAAC,QAAA,EAAU,QAAA,qBAC7B,GAAA;AAAA,4BAAC,IAAA;AAAA,4BAAA;AAAA,8BAGC,KAAK,UAAA,IAAc,MAAA;AAAA,8BACnB,IAAA,EAAM,WAAA;AAAA,8BAEL,QAAA,EAAA,QAAA,CAAS,QAAA,KAAa,MAAA,GACnB,QAAA,CAAS,OACT,CAAA,CAAE,6BAAA;AAAA,gCACA,QAAA,CAAS,IAAA;AAAA,gCACT,QAAA,CAAS;AAAA;AACX,6BAAA;AAAA,4BATC;AAAA,2BAWR,GACH,CAAA,EACF;AAAA,yBAAA,EACF,CAAA,GACE,IAAA;AAAA,wBACH,KAAK,QAAA,KAAa,MAAA,IAAa,KAAK,QAAA,CAAS,MAAA,GAAS,oBACrD,IAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,0CAAA,GAAA,CAAC,IAAA,EAAA,EAAI,YAAE,qBAAA,EAAsB,CAAA;AAAA,0CAC7B,GAAA,CAAC,IAAA,EAAA,EACC,QAAA,kBAAA,GAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,gBAAA,EACX,QAAA,EAAA,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,CAAC,OAAA,EAAS,QAAA,qBAC3B,IAAA;AAAA,4BAAC,IAAA;AAAA,4BAAA;AAAA,8BAGC,SAAA,EAAU,eAAA;AAAA,8BAEV,QAAA,EAAA;AAAA,gDAAA,GAAA,CAAC,UAAK,SAAA,EAAU,sBAAA,EACb,uBAAa,OAAA,EAAS,QAAA,EAAU,CAAC,CAAA,EACpC,CAAA;AAAA,gCACC,QAAQ,OAAA,KAAY,MAAA,IACrB,QAAQ,OAAA,CAAQ,MAAA,GAAS,oBACvB,IAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,kDAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,mBAAA,EACb,QAAA,EAAA,CAAA,CAAE,oBAAA,EACL,CAAA;AAAA,kDACA,GAAA,CAAC,QAAG,SAAA,EAAU,gBAAA,EACX,kBAAQ,OAAA,CAAQ,GAAA,CAAI,CAAC,SAAA,EAAW,IAAA,qBAC/B,GAAA;AAAA,oCAAC,IAAA;AAAA,oCAAA;AAAA,sCAIE,QAAA,EAAA,SAAA,CAAU;AAAA,qCAAA;AAAA,oCAFN;AAAA,mCAIR,CAAA,EACH;AAAA,iCAAA,EACF,CAAA,GACE;AAAA;AAAA,6BAAA;AAAA,4BAvBC;AAAA,2BAyBR,GACH,CAAA,EACF;AAAA,yBAAA,EACF,CAAA,GACE;AAAA,uBAAA,EACN,CAAA;AAAA,sBACC,QAAA,IACD,OAAO,IAAA,CAAK,OAAA,KAAY,YACxB,OAAO,IAAA,CAAK,eAAe,QAAA,mBACzB,GAAA;AAAA,wBAAC,QAAA;AAAA,wBAAA;AAAA,0BACC,IAAA,EAAK,QAAA;AAAA,0BACL,SAAA,EAAU,iBAAA;AAAA,0BACV,SAAS,MACP,QAAA,CAAS,IAAA,CAAK,OAAA,EAAmB,KAAK,UAAoB,CAAA;AAAA,0BAG3D,QAAA,EAAA,CAAA,CAAE,sBAAsB,KAAK;AAAA;AAAA,uBAChC,GACE,IAAA;AAAA,sBACH,IAAA,CAAK,IAAA,CAAK,MAAA,EAAQ,UAAA,EAAY,cAAc,CAAA,mBAC3C,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,aAAA,EAAc,YAAA,EAAW,YAAA,EACnC,QAAA,EAAA,CAAA,CAAE,8BACL,CAAA,GACE,IAAA;AAAA,sBACH,IAAA,CAAK,IAAA,CAAK,MAAA,EAAQ,OAAA,EAAS,cAAc,CAAA,mBACxC,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,aAAA,EAAc,YAAA,EAAW,SAAA,EACnC,QAAA,EAAA,CAAA,CAAE,2BACL,CAAA,GACE;AAAA,qBAAA,EACN,CAAA,GACE;AAAA,mBAAA,EACN,CAAA,GACE;AAAA;AAAA,eAAA;AAAA,cAnIC;AAAA,aAoIP;AAAA,UAEJ,CAAC,CAAA,EACH,CAAA;AAAA,8BACC,IAAA,EAAA,EAAG,SAAA,EAAU,gBACX,QAAA,EAAA,aAAA,CAAc,GAAA,CAAI,CAAC,KAAA,qBAClB,GAAA,CAAC,IAAA,EAAA,EAAe,YAAA,EAAY,OACzB,QAAA,EAAA,CAAA,CAAE,mBAAA,CAAoB,KAAK,CAAA,EAAA,EADrB,KAET,CACD,CAAA,EACH,CAAA;AAAA,UAIC,QAAA,KAAa,wBAAQ,GAAA,CAAC,GAAA,EAAA,EAAE,WAAU,gBAAA,EAAkB,QAAA,EAAA,CAAA,CAAE,sBAAqB,CAAA,GAAO;AAAA,SAAA,EACrF,CAAA,GACE,IAAA;AAAA,QAEH,IAAA,CAAK,QAAA,EAAU,iBAAiB,CAAA,mBAC/B,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,gBAAA,EAAiB,IAAA,EAAK,MAAA,EAChC,QAAA,EAAA,CAAA,CAAE,qBAAA,EACL,CAAA,GACE,IAAA;AAAA,QAEH,QAAA,KAAa,MAAA,GAAY,IAAA,GAAO,QAAA,CAAS,OAAA,mBACxC,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,yBAAA,EAA0B,IAAA,EAAK,MAAA,EACzC,QAAA,EAAA,CAAA,CAAE,4BAAA,EACL,CAAA;AAAA;AAAA,0BAGA,GAAA;AAAA,YAAC,OAAA;AAAA,YAAA;AAAA,cACC,GAAA,EAAK,QAAA;AAAA,cACL,SAAA,EAAU,aAAA;AAAA,cACV,GAAA,EAAK,QAAA;AAAA,cACL,OAAA,EAAQ,UAAA;AAAA,cACR,SAAS,CAAC,KAAA,KAAU,QAAA,CAAS,MAAA,CAAO,MAAM,aAAa;AAAA;AAAA;AACzD;AAAA;AAAA;AAAA,GAEJ;AAEJ;ACjhBO,SAASC,uBAAsB,KAAA,EAAmC;AACvE,EAAA,MAAM,OAAA,GAAU,YAAA,CAAa,KAAA,CAAM,OAAO,CAAA;AAC1C,EAAA,uBACEC,IAAC,qBAAA,EAAA,EAAsB,OAAA,EACrB,0BAAAA,GAAAA,CAAC,qBAAA,EAAA,EAA2B,GAAG,KAAA,EAAO,CAAA,EACxC,CAAA;AAEJ","file":"chunk-TUVEJLOT.js","sourcesContent":["'use client';\n\nimport { useCallback, useState } from 'react';\n\n/**\n * Whether the page refused to play the learner's own take, and the handler\n * every element that plays it reports a refusal through.\n *\n * The take is played from a `blob:` URL — the preview of a take not yet sent —\n * or from a link a review minted, and a page can refuse either without a word:\n * a Content-Security-Policy whose `media-src` does not allow `blob:` blocks the\n * load, the element fires `error`, and every control that plays it goes on\n * looking as if it works. So the refusal is decided in one place, by the URL\n * that was refused: a new take is a new URL and starts out playable again, and\n * a refusal an element reports after it was handed another URL cannot mark the\n * new one.\n *\n * `refuse` takes the element, not the URL, and reads the address the element\n * is loading at the moment it fails: an `error` belongs to the source the\n * element holds when it fires, and a closure's URL may already be a render\n * behind it.\n */\nexport function usePlaybackRefusal(url: string | null | undefined): {\n refused: boolean;\n refuse: (element: HTMLMediaElement) => void;\n} {\n const [refusedUrl, setRefusedUrl] = useState<string | null>(null);\n const refuse = useCallback((element: HTMLMediaElement) => {\n const source = element.getAttribute('src');\n if (source !== null) {\n setRefusedUrl(source);\n }\n }, []);\n return { refused: url !== null && url !== undefined && url === refusedUrl, refuse };\n}\n\n/**\n * Whether a rejected `play()` is the page refusing the source, rather than an\n * autoplay policy refusing the gesture. Only the first is the take's to report:\n * an autoplay refusal says nothing about whether the take can be played.\n */\nexport function isSourceRefusal(error: unknown): boolean {\n return (\n typeof error === 'object' &&\n error !== null &&\n (error as { name?: unknown }).name === 'NotSupportedError'\n );\n}\n","'use client';\n\nimport type {\n CriterionScore,\n GradeRecord,\n ReadAloudDimension,\n ScoringDetail,\n ScoringOutcome,\n SpeechAssessment,\n} from '@intellectif/lk-core';\n\n/**\n * The one reader of a grade that arrives from a host.\n *\n * Nothing validates a `GradeRecord`, an `ItemOutcome` or an assess result on\n * the way in: each is the application's, it crosses a network, and a field a\n * backend serialised as `null`, as a string or as an object is the ordinary way\n * to meet one. Every render path used to dereference them in its own way, so\n * every guard added for one shape left its sibling open — `criteria: null`\n * guarded and `criteria: [null]` not, a numeric `score` guarded and a string\n * `maxScore` shown as 8200%, `feedback` as an object taking a whole activity\n * down, `passed: null` dropping a grade from every callback in development and\n * sending an invalid statement in production.\n *\n * So the question \"what did the host send?\" has one answer, given here. The\n * panel, the outcome summary, the announcement, the decision about who shows\n * the score, `onComplete` and the xAPI statement read ONLY what these functions\n * return, and a payload they refuse is shown as could-not-be-graded — never the\n * error boundary, never `NaN`, never a percentage invented from a string.\n *\n * The rules, once:\n *\n * - **A required field is well-formed or the grade is refused.** `score` and\n * `maxScore` are finite numbers, `maxScore` above 0 and `score` between 0 and\n * it; `passed` is a boolean. A numeric string is not a number: `\"100\"` is how\n * a grade out of 100 turned into 8200%, and coercing it would only move the\n * guess somewhere else.\n * - **An optional field is absent when it is `undefined` or `null`** — how a\n * backend writes an absent optional — and otherwise well-formed or dropped.\n * `feedback` that is not a string is no feedback.\n * - **`criteria` keeps each well-formed entry and drops the rest.** Criteria are\n * named rows, each independent: an entry that cannot be read names no row.\n * - **`details` is read whole or not at all.** It is the word marks in order,\n * and a list with one word quietly missing would tell a learner they never\n * read a word they did.\n * - **Nothing here throws.** A payload whose getter throws is a payload that\n * cannot be read.\n */\n\n/** Marks a grade as read by {@link readGrade}. Type-only: it never exists at run time. */\ndeclare const READ: unique symbol;\n\n/**\n * A grade {@link readGrade} has checked: `0 <= score <= maxScore`, `maxScore >\n * 0`, both finite, `passed` a boolean, `feedback` a string or `null`, and\n * `criteria` and `details` (when present) holding only well-formed entries.\n * Still a `GradeRecord`, so it can be handed to anything that takes one — and\n * reading it again gives the same grade.\n */\nexport type ReadGrade = GradeRecord & { readonly [READ]: true };\n\n/** A stored outcome, as a renderer may show it. */\nexport type OutcomeReading =\n /** A grade to show: the outcome's own for `scored`, its `grade` for `graded`. */\n | { kind: 'graded'; status: 'scored' | 'graded'; grade: ReadGrade }\n | { kind: 'deferred' }\n /** `code` is a developer's label: put on an attribute, never shown. */\n | { kind: 'unscorable'; code: string | undefined }\n /** Claimed a grade, or claimed nothing a renderer knows, and could not be read. */\n | { kind: 'unreadable'; status: 'scored' | 'graded' | undefined };\n\n/** An assessor's answer, as a renderer and a statement may use it. */\nexport type AssessReading =\n | {\n status: 'graded';\n /** `null` when what came back cannot be read as a grade. */\n grade: ReadGrade | null;\n /** The evidence when it is an object at all; whether it VALIDATES is the panel's question. */\n assessment: SpeechAssessment | null;\n recognizedText: string | undefined;\n }\n | { status: 'unscorable'; code: string | undefined }\n | { status: 'failed'; retryable: boolean };\n\n/** One dimension row: a whole percentage, or `undefined` for a dimension nobody measured. */\nexport interface DimensionReading {\n dimension: ReadAloudDimension;\n percent: number | undefined;\n}\n\n/**\n * Every dimension a read-aloud grade can weigh, in the order a learner reads\n * them: what was said, how it flowed, how much of it was there, and how it was\n * pitched. Fixed rather than derived from the evidence, so a dimension the\n * engine did not measure is reported as unmeasured instead of vanishing.\n */\nconst DIMENSIONS: readonly ReadAloudDimension[] = [\n 'accuracy',\n 'fluency',\n 'completeness',\n 'prosody',\n];\n\nconst OUTCOMES: readonly ScoringOutcome[] = [\n 'correct',\n 'incorrect',\n 'correct-omission',\n 'incorrect-omission',\n];\n\n/**\n * How far past its own maximum a score may sit and still be read as that\n * maximum. A grader that sums weighted parts lands on `1.0000000000000002`\n * for a perfect take as readily as on `1`, and \"could not be graded\" is the\n * wrong thing to tell the learner who earned it. Far below any difference a\n * whole percentage can show.\n */\nconst OVERSHOOT = 1e-9;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value);\n}\n\n/** An optional field a backend left out, written either way it writes one. */\nfunction isAbsent(value: unknown): value is null | undefined {\n return value === undefined || value === null;\n}\n\n/** A score on `0..max`, a hair of overshoot read as `max`; `null` for anything else. */\nfunction withinMax(score: unknown, max: number): number | null {\n if (!isFiniteNumber(score) || score < 0) {\n return null;\n }\n if (score <= max) {\n return score;\n }\n return score - max <= max * OVERSHOOT ? max : null;\n}\n\n/** A learner's or a reference response: a string, or strings. */\nfunction isResponse(value: unknown): value is string | string[] {\n return (\n typeof value === 'string' ||\n (Array.isArray(value) && value.every((entry) => typeof entry === 'string'))\n );\n}\n\n/** Runs a read that touches a host's object, whose getters may throw. */\nfunction guarded<T>(read: () => T, refused: T): T {\n try {\n return read();\n } catch {\n return refused;\n }\n}\n\nfunction readCriterion(value: unknown): CriterionScore | null {\n if (!isRecord(value) || typeof value.name !== 'string') {\n return null;\n }\n const { maxScore, notApplicable } = value;\n if (!isAbsent(maxScore) && !(isFiniteNumber(maxScore) && maxScore > 0)) {\n return null;\n }\n if (!isAbsent(notApplicable) && typeof notApplicable !== 'boolean') {\n return null;\n }\n // `CriterionScore.maxScore` defaults to 1, the SDK's scaled convention.\n const score = isAbsent(value.score) ? undefined : withinMax(value.score, maxScore ?? 1);\n if (score === null) {\n return null;\n }\n return {\n name: value.name,\n ...(score !== undefined ? { score } : {}),\n ...(!isAbsent(maxScore) ? { maxScore } : {}),\n ...(notApplicable === true ? { notApplicable } : {}),\n };\n}\n\nfunction readDetail(value: unknown): ScoringDetail | null {\n if (!isRecord(value)) {\n return null;\n }\n const { itemId, correct, outcome, learnerResponse, correctResponse, weight, score } = value;\n if (\n typeof itemId !== 'string' ||\n typeof correct !== 'boolean' ||\n !isResponse(learnerResponse) ||\n !isResponse(correctResponse)\n ) {\n return null;\n }\n const checkedOutcome = OUTCOMES.find((known) => known === outcome);\n if (!isAbsent(outcome) && checkedOutcome === undefined) {\n return null;\n }\n if (!isAbsent(weight) && !isFiniteNumber(weight)) {\n return null;\n }\n // A detail's own score is a fraction of 1.\n const checkedScore = isAbsent(score) ? undefined : withinMax(score, 1);\n if (checkedScore === null) {\n return null;\n }\n return {\n itemId,\n correct,\n learnerResponse,\n correctResponse,\n ...(checkedOutcome !== undefined ? { outcome: checkedOutcome } : {}),\n ...(!isAbsent(weight) ? { weight } : {}),\n ...(checkedScore !== undefined ? { score: checkedScore } : {}),\n };\n}\n\nfunction readDetails(value: unknown): ScoringDetail[] | undefined {\n if (!Array.isArray(value)) {\n return undefined;\n }\n const details: ScoringDetail[] = [];\n for (const entry of value) {\n const detail = readDetail(entry);\n if (detail === null) {\n return undefined;\n }\n details.push(detail);\n }\n return details;\n}\n\n/**\n * A host's grade as a checked copy, or `null` when it carries no grade that can\n * be shown or reported. See the module notes for the rules.\n */\nexport function readGrade(value: unknown): ReadGrade | null {\n return guarded(() => {\n if (!isRecord(value)) {\n return null;\n }\n const { maxScore, passed } = value;\n if (!isFiniteNumber(maxScore) || maxScore <= 0 || typeof passed !== 'boolean') {\n return null;\n }\n const score = withinMax(value.score, maxScore);\n if (score === null) {\n return null;\n }\n const criteria = Array.isArray(value.criteria)\n ? value.criteria.flatMap((entry) => {\n const criterion = readCriterion(entry);\n return criterion === null ? [] : [criterion];\n })\n : undefined;\n const details = readDetails(value.details);\n const grade: GradeRecord = {\n score,\n maxScore,\n passed,\n feedback: typeof value.feedback === 'string' ? value.feedback : null,\n ...(criteria !== undefined ? { criteria } : {}),\n ...(details !== undefined ? { details } : {}),\n };\n return grade as ReadGrade;\n }, null);\n}\n\n/** A read grade as a fraction of 1: in `0..1`, because the reader made it so. */\nexport function fractionOfGrade(grade: ReadGrade): number {\n return grade.score / grade.maxScore;\n}\n\n/** A read grade as a whole percentage: in `0..100`, because the reader made it so. */\nexport function percentOfGrade(grade: ReadGrade): number {\n return Math.round(fractionOfGrade(grade) * 100);\n}\n\n/**\n * A stored outcome as a renderer may show it, or `undefined` for none —\n * `null` included, which is how a backend writes an absent optional.\n *\n * A `graded` outcome is read through its `grade`, the record\n * `outcomeFromGrade` mirrors onto it, so the summary and the panel beside it\n * can never show two different numbers; and it must be well-formed as a whole,\n * its own `score`, `maxScore` and `passed` included — a payload with a corrupt\n * copy of the grade is not one to pick a side of.\n */\nexport function readOutcome(value: unknown): OutcomeReading | undefined {\n if (isAbsent(value)) {\n return undefined;\n }\n return guarded(\n (): OutcomeReading => {\n if (!isRecord(value)) {\n return { kind: 'unreadable', status: undefined };\n }\n switch (value.status) {\n case 'deferred':\n return { kind: 'deferred' };\n case 'unscorable':\n return {\n kind: 'unscorable',\n code: typeof value.code === 'string' ? value.code : undefined,\n };\n case 'scored': {\n const grade = readGrade(value);\n return grade === null\n ? { kind: 'unreadable', status: 'scored' }\n : { kind: 'graded', status: 'scored', grade };\n }\n case 'graded': {\n const grade = readGrade(value.grade);\n return grade === null || readGrade(value) === null\n ? { kind: 'unreadable', status: 'graded' }\n : { kind: 'graded', status: 'graded', grade };\n }\n default:\n return { kind: 'unreadable', status: undefined };\n }\n },\n { kind: 'unreadable', status: undefined },\n );\n}\n\n/**\n * An assessor's answer as a renderer and a statement may use it.\n *\n * `failed` and `unscorable` need little: a `retryable` that is not `true`\n * offers no retry, which never spends an application's money on a guess, and a\n * `code` that is not a string is no code. Everything else — a `graded` result,\n * and anything that is not an object or names no status this component knows —\n * is read as a judgement: its grade when one can be read, its evidence when it\n * is an object. A judgement with neither is shown as could-not-be-graded.\n */\nexport function readAssessResult(value: unknown): AssessReading {\n const nothing: AssessReading = {\n status: 'graded',\n grade: null,\n assessment: null,\n recognizedText: undefined,\n };\n return guarded((): AssessReading => {\n if (!isRecord(value)) {\n return nothing;\n }\n if (value.status === 'failed') {\n return { status: 'failed', retryable: value.retryable === true };\n }\n if (value.status === 'unscorable') {\n return {\n status: 'unscorable',\n code: typeof value.code === 'string' ? value.code : undefined,\n };\n }\n if (value.status !== 'graded') {\n return nothing;\n }\n const assessment = readEvidence(value.assessment);\n const recognizedText = guarded(\n () =>\n typeof assessment?.recognizedText === 'string' ? assessment.recognizedText : undefined,\n undefined,\n );\n return { status: 'graded', grade: readGrade(value.grade), assessment, recognizedText };\n }, nothing);\n}\n\n/**\n * Evidence worth handing to the panel: an object. Whether it validates is the\n * panel's to decide, because what a refusal costs differs by mode.\n */\nexport function readEvidence(value: unknown): SpeechAssessment | null {\n return isRecord(value) ? (value as unknown as SpeechAssessment) : null;\n}\n\n/** One criterion's whole percentage of its own maximum, or `undefined` when it carries none. */\nfunction percentOfCriterion(criterion: CriterionScore): number | undefined {\n if (criterion.notApplicable === true || criterion.score === undefined) {\n return undefined;\n }\n return Math.round((criterion.score / (criterion.maxScore ?? 1)) * 100);\n}\n\n/**\n * The dimension rows, from one source for the whole set and never a mix: the\n * grade's criteria when it has any it can read, and the evidence's own scores\n * otherwise. A dimension pulled out of the evidence and set beside graded ones\n * would read as if it had counted towards the grade.\n *\n * The evidence is read as defensively as the grade: in production the panel\n * shows these rows even for evidence the validator refused, which can carry\n * anything at all under `scores`. `scale` is 100 by schema, so an evidence\n * score is already a percentage — and one outside `0..100` is not one.\n */\nexport function readDimensions(\n assessment: unknown,\n grade: ReadGrade | null | undefined,\n): DimensionReading[] {\n const criteria = grade?.criteria ?? [];\n if (criteria.length > 0) {\n return DIMENSIONS.map((dimension) => {\n const criterion = criteria.find((entry) => entry.name === dimension);\n return {\n dimension,\n percent: criterion === undefined ? undefined : percentOfCriterion(criterion),\n };\n });\n }\n const scores = guarded(() => (isRecord(assessment) ? assessment.scores : undefined), undefined);\n return DIMENSIONS.map((dimension) => {\n const score = withinMax(\n guarded(() => (isRecord(scores) ? scores[dimension] : undefined), undefined),\n 100,\n );\n // Rounded rather than reformatted: the engine's own number is what was graded.\n return { dimension, percent: score === null ? undefined : Math.round(score) };\n });\n}\n","'use client';\n\nimport {\n ActivitySchemaError,\n alignReadAloud,\n type GradeRecord,\n type ReadAloudData,\n type ReadAloudWordAlignment,\n type SpeechAssessment,\n type SpeechPhoneme,\n type SpeechWord,\n type ThemeTokens,\n type ValidationResult,\n validateSpeechAssessment,\n} from '@intellectif/lk-core';\nimport { type CSSProperties, useEffect, useId, useMemo, useRef, useState } from 'react';\nimport { localeDirectionOf } from '../../i18n/direction.js';\nimport { useLkStrings } from '../../i18n/LkIntlProvider.js';\nimport type { LkStrings, LkStringsOverride } from '../../i18n/strings.js';\nimport { isDevelopment } from '../_internal.js';\nimport { isSourceRefusal, usePlaybackRefusal } from '../shared/playback-refusal.js';\nimport { percentOfGrade, readDimensions, readGrade } from '../shared/read-grade.js';\n\n/**\n * Present for assistive technology, invisible on screen. Inline rather than\n * left to the optional skin, for the reason `<Dictation>` gives: the per-word\n * sentences are the marks' only channel for a screen reader, and a page that\n * does not load the skin would otherwise show every one of them beside its\n * word. Exported so `<ReadAloud>`, whose review fallback renders the same\n * marks from stored details, carries one definition rather than a copy.\n */\nexport const VISUALLY_HIDDEN: CSSProperties = {\n position: 'absolute',\n width: 1,\n height: 1,\n margin: -1,\n padding: 0,\n overflow: 'hidden',\n clip: 'rect(0 0 0 0)',\n clipPath: 'inset(50%)',\n whiteSpace: 'nowrap',\n border: 0,\n};\n\n/** The four marking states, in the order the legend lists them. */\nconst LEGEND_STATES: readonly ReadAloudWordAlignment['state'][] = [\n 'correct',\n 'mispronounced',\n 'omitted',\n 'inserted',\n];\n\nexport interface PronunciationFeedbackProps {\n /**\n * The item's reading and its language. Only these two fields, because they\n * are the only ones a mark depends on — everything else about the activity\n * belongs to whoever rendered it.\n */\n data: Pick<ReadAloudData, 'referenceText' | 'locale'>;\n /**\n * The assessor's evidence. Checked with `validateSpeechAssessment` before it\n * is aligned: see the note on this component about what a bad one costs.\n */\n assessment: SpeechAssessment;\n /**\n * The grade the evidence produced, when one exists. Its `criteria` are what\n * the dimensions are read from, because they are the numbers the learner was\n * actually graded on. A grade that cannot be read — a score that is not a\n * number between 0 and its maximum, a `passed` that is not a boolean — is\n * shown as could-not-be-graded, never as a percentage made up from it.\n */\n grade?: GradeRecord;\n /**\n * The learner's own take, playable. With it, each word that carries timings\n * gets a button that plays just that word. A take the page refuses to play —\n * a `blob:` URL under a Content-Security-Policy whose `media-src` does not\n * allow one, most often — offers no such button, and the panel says the take\n * cannot be played here.\n */\n audioUrl?: string;\n /**\n * Confidence above which a break note is shown, 0..1. **No default**: how\n * confident an engine has to be before a pause is worth telling a learner\n * about is a calibration, and the SDK has no calibrated answer. Without it no\n * break note is shown at all.\n */\n breakThreshold?: number;\n /** The same, for the monotone note read off `assessment.prosody`. */\n monotoneThreshold?: number;\n /**\n * BCP 47 tag stamped as `lang` on the root: the INTERFACE language, the one\n * this component's own sentences are written in. It is not `data.locale`,\n * which is the language of the reading and is put on the words themselves.\n */\n locale?: string;\n /** Per-instance token overrides, applied as inline CSS vars on the root. */\n theme?: Partial<ThemeTokens>;\n /** Overrides the SDK's chrome text for this panel. See {@link LkIntlProvider}. */\n strings?: LkStringsOverride;\n}\n\n/**\n * What the validator says about evidence that may not even be readable. Its\n * cross-field rules read the value directly, so a getter that throws escapes\n * it — and evidence that cannot be read is evidence refused, not a reason to\n * take the grade beside it down.\n */\nfunction checkEvidence(assessment: unknown): ValidationResult<SpeechAssessment> {\n try {\n return validateSpeechAssessment(assessment);\n } catch {\n return {\n success: false,\n errors: [{ path: [], message: 'The assessment could not be read.', code: 'unreadable' }],\n };\n }\n}\n\n/** Whether a word carries anything a disclosure would have to show. */\nfunction hasDetail(word: SpeechWord | undefined): word is SpeechWord {\n if (word === undefined) {\n return false;\n }\n return (\n word.accuracy !== undefined ||\n (word.syllables !== undefined && word.syllables.length > 0) ||\n (word.phonemes !== undefined && word.phonemes.length > 0) ||\n word.breaks !== undefined ||\n (typeof word.startMs === 'number' && typeof word.durationMs === 'number')\n );\n}\n\n/** A confidence that clears the caller's threshold. No threshold, no note. */\nfunction past(confidence: number | undefined, threshold: number | undefined): boolean {\n return (\n threshold !== undefined &&\n typeof confidence === 'number' &&\n Number.isFinite(confidence) &&\n confidence > threshold\n );\n}\n\n/** One phoneme, named by its symbol or — when the engine named none — by its place. */\nfunction phonemeLabel(phoneme: SpeechPhoneme, index: number, s: LkStrings): string {\n return phoneme.symbol ?? s.pronunciationPhonemePosition(index + 1);\n}\n\n/**\n * What a screen reader hears for one marked word — the marks' only channel for\n * assistive technology, since the glyph and the decoration are both hidden from\n * it. Exported because `<ReadAloud>`'s review fallback marks the same four\n * states from stored details, and a second copy of these four sentences would\n * be a second thing to translate.\n *\n * Branches on `state` and **never** on `heard === ''`: an inserted word whose\n * text normalises to nothing carries the empty string too, and would otherwise\n * be announced as an omission.\n */\nexport function markSentence(entry: ReadAloudWordAlignment, s: LkStrings): string {\n switch (entry.state) {\n case 'correct':\n return s.pronunciationWordCorrect(entry.reference);\n case 'mispronounced':\n return s.pronunciationWordMispronounced(entry.reference);\n case 'omitted':\n return s.pronunciationWordOmitted(entry.reference);\n default:\n return s.pronunciationWordInserted(entry.heard);\n }\n}\n\n/**\n * The per-word marks of a read-aloud take, plus the dimensions they were\n * graded on.\n *\n * **A bad assessment never destroys a good grade.** `alignReadAloud` throws a\n * `TypeError` for evidence `validateSpeechAssessment` refuses, so this\n * component runs the validator first. In development the refusal is thrown as\n * an `ActivitySchemaError`, which is the package's dev-error convention and\n * puts the problem in front of whoever wired the adapter up. In production the\n * dimensions and the grade are rendered and the word list is left out — a\n * learner who earned 82% should see 82%, not \"this activity could not be\n * displayed\" from an error boundary.\n *\n * **Nor does a bad grade take the evidence down.** `grade` is read, not\n * trusted: a score that is not a number between 0 and its maximum, or a\n * `passed` that is not a boolean, is shown as could-not-be-graded beside the\n * dimensions and the marks, and criteria that cannot be read name no dimension.\n *\n * There is **no `renderMode`**: nothing here submits, grades or reveals an\n * answer key. A read-aloud item has none, and the marks exist only once a\n * server has graded the take, so there is no mode in which they must be\n * withheld.\n *\n * ```tsx\n * <PronunciationFeedback\n * data={item}\n * assessment={assessment}\n * grade={grade}\n * audioUrl={takeUrl}\n * breakThreshold={0.75}\n * monotoneThreshold={0.6}\n * />\n * ```\n */\nexport function PronunciationFeedback({\n data,\n assessment,\n grade,\n audioUrl,\n breakThreshold,\n monotoneThreshold,\n locale,\n theme,\n strings,\n}: PronunciationFeedbackProps) {\n const s = useLkStrings(strings);\n const ids = useId();\n const [openWord, setOpenWord] = useState<number | null>(null);\n\n const checked = useMemo(() => checkEvidence(assessment), [assessment]);\n\n const devError = useMemo(\n () =>\n isDevelopment() && !checked.success\n ? new ActivitySchemaError('read-aloud', checked.errors)\n : null,\n [checked],\n );\n\n // The checked copy, never the argument, for the same reason lk-core aligns\n // from it: a property getter cannot answer the validator one word and the\n // aligner another.\n const words = useMemo<ReadAloudWordAlignment[] | null>(\n () => (checked.success ? alignReadAloud(data, checked.data) : null),\n [checked, data],\n );\n\n // The grade as the one reader of a host's grade reads it: `undefined` when\n // none was given, and `null` when one was and cannot be shown. Everything\n // below that shows a number reads this and the dimension rows, never `grade`.\n const reading = useMemo(\n () => (grade === undefined || grade === null ? undefined : readGrade(grade)),\n [grade],\n );\n const dimensions = useMemo(() => readDimensions(assessment, reading), [assessment, reading]);\n\n // The take, for the per-word play buttons. A ref and an effect, never a read\n // during render: this component server-renders like every other one here.\n const audioRef = useRef<HTMLAudioElement>(null);\n const stopRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const playback = usePlaybackRefusal(audioUrl);\n // A take the page refused is offered to no button: pressed, each would do\n // nothing, which is the silent failure the note below replaces.\n const playable = audioUrl !== undefined && !playback.refused;\n useEffect(\n () => () => {\n if (stopRef.current !== null) {\n clearTimeout(stopRef.current);\n }\n },\n [],\n );\n\n // All hooks are called before this throw, so hook order stays stable.\n if (devError) {\n throw devError;\n }\n\n /** Plays one word out of the take, and stops at the end of it. */\n const playWord = (startMs: number, durationMs: number): void => {\n const element = audioRef.current;\n if (element === null) {\n return;\n }\n if (stopRef.current !== null) {\n clearTimeout(stopRef.current);\n }\n element.currentTime = startMs / 1000;\n try {\n void element.play().catch((error: unknown) => {\n // An autoplay refusal is not this component's to report; a source the\n // page will not load is, and the element's own `error` may not have\n // fired yet for an engine that loads nothing until asked.\n if (isSourceRefusal(error)) {\n playback.refuse(element);\n }\n });\n } catch {\n /* an engine with no media stack at all; the button simply does nothing */\n }\n stopRef.current = setTimeout(() => {\n stopRef.current = null;\n element.pause();\n }, durationMs);\n };\n\n // The reading's own language and the direction its tag names, put on the\n // words and on nothing else: the sentences beside them are interface text.\n // No `_`→`-` normalisation, unlike `<Dictation>` — `ReadAloudData.locale` is\n // canonical by schema, so there is nothing to normalise.\n const contentLang = typeof data.locale === 'string' ? data.locale : undefined;\n const contentDir = localeDirectionOf(data.locale);\n\n const alphabet = checked.success ? checked.data.phonemeAlphabet : undefined;\n const monotone = checked.success ? checked.data.prosody?.monotoneConfidence : undefined;\n // Read through `at`, not through an index: `wordIndex` belongs to a public\n // type a caller may have built by hand, and it is allowed to point nowhere.\n const evidenceWords: readonly SpeechWord[] = checked.success ? checked.data.words : [];\n\n return (\n <section\n className=\"lk-pf\"\n aria-label={s.pronunciationFeedbackLabel}\n lang={locale}\n style={theme as CSSProperties | undefined}\n >\n {reading !== undefined ? (\n // `.lk-pf-grade` is load-bearing beyond the skin: `<ReadAloud>` looks\n // for it after the commit to decide whether it must render the score\n // itself, so a grade is never lost between the two components. It\n // hands this panel only a grade it has already read, so the block it\n // finds always carries the score.\n //\n // `data-passed` only where there is a verdict: a grade that could not\n // be read has none, and styling it as a fail would invent one.\n <div\n className=\"lk-pf-grade\"\n {...(reading !== null ? { 'data-passed': String(reading.passed) } : {})}\n >\n <p className=\"lk-pf-score\">\n {reading === null\n ? s.couldNotBeGraded\n : s.scoreAnnouncement(percentOfGrade(reading), reading.passed)}\n </p>\n {/* The grader's words, isolated: their direction is their own, so an\n English comment in an Arabic interface keeps its full stop at its\n end. Their language is not guessed — feedback may be written in\n either the interface's language or the reading's. */}\n {reading?.feedback ? (\n <p className=\"lk-pf-grade-feedback\" dir=\"auto\">\n {reading.feedback}\n </p>\n ) : null}\n </div>\n ) : null}\n\n <dl className=\"lk-pf-dimensions\">\n {dimensions.map(({ dimension, percent }) => (\n <div className=\"lk-pf-dimension\" key={dimension} data-dimension={dimension}>\n <dt className=\"lk-pf-dimension-name\">{s.pronunciationDimension(dimension)}</dt>\n {/* An absent score is NEVER a 0: a dimension nobody measured and a\n dimension measured at nothing are different findings, and only\n one of them is the learner's. */}\n <dd className=\"lk-pf-dimension-score\">\n {percent === undefined ? s.pronunciationNotAssessed : `${percent}%`}\n </dd>\n </div>\n ))}\n </dl>\n\n {words !== null ? (\n <>\n {/* The list's name and the hidden sentences are interface text and\n keep the interface language; only the words carry the reading's.\n Its direction is the reading's, never resolved from the list's own\n text: the first strong character there is a hidden sentence. */}\n <ol className=\"lk-pf-words\" aria-label={s.pronunciationWordsLabel} dir={contentDir}>\n {words.map((entry, index) => {\n const sentence = markSentence(entry, s);\n const shown = entry.state === 'inserted' ? entry.heard : entry.reference;\n const word =\n entry.wordIndex === undefined ? undefined : evidenceWords.at(entry.wordIndex);\n const open = openWord === index;\n const panelId = `${ids}-w${index}`;\n return (\n <li\n // biome-ignore lint/suspicious/noArrayIndexKey: alignment order is the identity; words repeat\n key={index}\n className=\"lk-pf-word\"\n data-state={entry.state}\n >\n {/* The state's only channel for assistive technology, and\n exactly one channel: the same sentence as a `title` is an\n accessible description, which a screen reader reads\n straight after the name it duplicates. */}\n <span className=\"lk-visually-hidden\" style={VISUALLY_HIDDEN}>\n {sentence}\n </span>\n {/* Decoration: the glyph the skin draws and the word itself.\n Hidden from assistive technology, which already has the\n sentence above — and the glyph is never the only channel. */}\n <span\n className=\"lk-pf-word-text\"\n aria-hidden=\"true\"\n dir={contentDir ?? 'auto'}\n lang={contentLang}\n >\n {shown}\n </span>\n {hasDetail(word) ? (\n <>\n <button\n type=\"button\"\n className=\"lk-pf-word-toggle\"\n aria-expanded={open}\n aria-controls={panelId}\n onClick={() => setOpenWord(open ? null : index)}\n >\n {s.pronunciationWordDetails(shown)}\n </button>\n {open ? (\n <div id={panelId} className=\"lk-pf-word-detail\">\n <dl className=\"lk-pf-word-facts\">\n <dt>{s.pronunciationDimension('accuracy')}</dt>\n <dd>\n {word.accuracy === undefined\n ? s.pronunciationNotAssessed\n : `${Math.round(word.accuracy)}%`}\n </dd>\n {word.syllables !== undefined && word.syllables.length > 0 ? (\n <>\n <dt>{s.pronunciationSyllables}</dt>\n <dd>\n <ul className=\"lk-pf-syllables\">\n {word.syllables.map((syllable, position) => (\n <li\n // biome-ignore lint/suspicious/noArrayIndexKey: syllables are positional and repeat within a word\n key={position}\n dir={contentDir ?? 'auto'}\n lang={contentLang}\n >\n {syllable.grapheme === undefined\n ? syllable.text\n : s.pronunciationSyllableSpelling(\n syllable.text,\n syllable.grapheme,\n )}\n </li>\n ))}\n </ul>\n </dd>\n </>\n ) : null}\n {word.phonemes !== undefined && word.phonemes.length > 0 ? (\n <>\n <dt>{s.pronunciationPhonemes}</dt>\n <dd>\n <ul className=\"lk-pf-phonemes\">\n {word.phonemes.map((phoneme, position) => (\n <li\n // biome-ignore lint/suspicious/noArrayIndexKey: a word may sound the same phoneme twice\n key={position}\n className=\"lk-pf-phoneme\"\n >\n <span className=\"lk-pf-phoneme-symbol\">\n {phonemeLabel(phoneme, position, s)}\n </span>\n {phoneme.heardAs !== undefined &&\n phoneme.heardAs.length > 0 ? (\n <>\n <span className=\"lk-pf-heard-label\">\n {s.pronunciationHeardAs}\n </span>\n <ul className=\"lk-pf-heard-as\">\n {phoneme.heardAs.map((candidate, rank) => (\n <li\n // biome-ignore lint/suspicious/noArrayIndexKey: candidates are ranked and a symbol may repeat\n key={rank}\n >\n {candidate.symbol}\n </li>\n ))}\n </ul>\n </>\n ) : null}\n </li>\n ))}\n </ul>\n </dd>\n </>\n ) : null}\n </dl>\n {playable &&\n typeof word.startMs === 'number' &&\n typeof word.durationMs === 'number' ? (\n <button\n type=\"button\"\n className=\"lk-pf-word-play\"\n onClick={() =>\n playWord(word.startMs as number, word.durationMs as number)\n }\n >\n {s.pronunciationPlayWord(shown)}\n </button>\n ) : null}\n {past(word.breaks?.unexpected, breakThreshold) ? (\n <p className=\"lk-pf-break\" data-break=\"unexpected\">\n {s.pronunciationBreakUnexpected}\n </p>\n ) : null}\n {past(word.breaks?.missing, breakThreshold) ? (\n <p className=\"lk-pf-break\" data-break=\"missing\">\n {s.pronunciationBreakMissing}\n </p>\n ) : null}\n </div>\n ) : null}\n </>\n ) : null}\n </li>\n );\n })}\n </ol>\n <ul className=\"lk-pf-legend\">\n {LEGEND_STATES.map((state) => (\n <li key={state} data-state={state}>\n {s.pronunciationLegend(state)}\n </li>\n ))}\n </ul>\n {/* Only where there are symbols to explain, and only for the alphabet\n this note names. An engine that reported another one, or none at\n all, gets no note rather than a wrong one. */}\n {alphabet === 'ipa' ? <p className=\"lk-pf-alphabet\">{s.pronunciationIpaNote}</p> : null}\n </>\n ) : null}\n\n {past(monotone, monotoneThreshold) ? (\n <p className=\"lk-pf-monotone\" role=\"note\">\n {s.pronunciationMonotone}\n </p>\n ) : null}\n\n {audioUrl === undefined ? null : playback.refused ? (\n <p className=\"lk-pf-audio-unavailable\" role=\"note\">\n {s.readAloudPlaybackUnavailable}\n </p>\n ) : (\n // biome-ignore lint/a11y/useMediaCaption: the learner's own take has no caption track to offer, and this element is never played as content — it carries no controls and exists only so one word can be replayed from a button that names it\n <audio\n ref={audioRef}\n className=\"lk-pf-audio\"\n src={audioUrl}\n preload=\"metadata\"\n onError={(event) => playback.refuse(event.currentTarget)}\n />\n )}\n </section>\n );\n}\n","'use client';\n\nimport { useLkStrings } from '../../i18n/LkIntlProvider.js';\nimport { ActivityErrorBoundary } from '../ActivityErrorBoundary.js';\nimport {\n PronunciationFeedback as PronunciationFeedbackCore,\n type PronunciationFeedbackProps,\n} from './PronunciationFeedback.js';\n\nexport type { PronunciationFeedbackProps } from './PronunciationFeedback.js';\n\n/**\n * Public pronunciation-feedback panel: the core wrapped in\n * `ActivityErrorBoundary` so a render failure (the dev throw for evidence\n * `validateSpeechAssessment` refuses among them) degrades to an accessible\n * fallback instead of crashing the host.\n *\n * **No `activityTitle`.** Its `data` is two fields of a read-aloud item and\n * carries no title, so the production fallback is the unnamed one. Naming it\n * would mean inventing a title for a panel that never had one.\n */\nexport function PronunciationFeedback(props: PronunciationFeedbackProps) {\n const strings = useLkStrings(props.strings);\n return (\n <ActivityErrorBoundary strings={strings}>\n <PronunciationFeedbackCore {...props} />\n </ActivityErrorBoundary>\n );\n}\n"]}
@@ -1,8 +1,9 @@
1
1
  'use client';
2
- import { ActivityErrorBoundary, isDevelopment, FeedbackRegion, ANONYMOUS_ACTOR, objectIdFor } from './chunk-DQERNAWI.js';
3
- import { ActivityMedia } from './chunk-R7DI5UMU.js';
2
+ import { FeedbackRegion } from './chunk-RCMYEWBE.js';
3
+ import { ActivityErrorBoundary, isDevelopment, ANONYMOUS_ACTOR, objectIdFor } from './chunk-B4BCEQNO.js';
4
+ import { ActivityMedia } from './chunk-DB4DLHN6.js';
4
5
  import { useActivityState } from './chunk-6N43WDVG.js';
5
- import { useLkStrings } from './chunk-3Q4I4KT6.js';
6
+ import { useLkStrings } from './chunk-AWQ53DON.js';
6
7
  import { validateActivity, ActivitySchemaError, countWords, evaluate, xAPIBuilder } from '@intellectif/lk-core';
7
8
  import { useMemo, useState, useRef, useEffect } from 'react';
8
9
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
@@ -285,5 +286,5 @@ function WrittenResponse2(props) {
285
286
  }
286
287
 
287
288
  export { WrittenResponse2 as WrittenResponse };
288
- //# sourceMappingURL=chunk-YZWXVZB3.js.map
289
- //# sourceMappingURL=chunk-YZWXVZB3.js.map
289
+ //# sourceMappingURL=chunk-U432HTUW.js.map
290
+ //# sourceMappingURL=chunk-U432HTUW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/WrittenResponse/WrittenResponse.tsx","../src/components/WrittenResponse/index.tsx"],"names":["WrittenResponse","jsx"],"mappings":"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","file":"chunk-U432HTUW.js","sourcesContent":["'use client';\n\nimport {\n ActivitySchemaError,\n type CriterionScore,\n countWords,\n evaluate,\n type GradeRecord,\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 { 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 { 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`) — deviation from Req 22.8 recorded in the\n * roadmap (§3.1): fabricating a score of 0 for ungraded work is the exact\n * 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\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 * 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 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 <ul className=\"lk-wr-criteria\">\n {grade.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 ) : null}\n {grade.corrections && grade.corrections.length > 0 ? (\n <ul className=\"lk-wr-corrections\">\n {grade.corrections.map((correction) => (\n <li className=\"lk-wr-correction\" key={`${correction.original}:${correction.corrected}`}>\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 ) : null}\n {grade.requiresHumanReview === true ? (\n <p className=\"lk-wr-review-flag\">{s.awaitingHumanReview}</p>\n ) : null}\n </>\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}: WrittenResponseProps) {\n // Dev-only boundary validation (Req 2.3), same convention as MC/FIB. The\n // content schema is loose, so a `redact()` projection validates too.\n const s = useLkStrings(strings);\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 (Req 3.7): 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 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 {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 ? outcome ? <OutcomeSummary outcome={outcome} s={s} /> : null : summary}\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) {\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"]}