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