@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,636 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { i as useLkStrings } from "./LkIntlProvider-D_FdYXjQ.js";
|
|
3
|
+
import { useCallback, useEffect, useId, useRef, useState } from "react";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { resolvePlaybackPolicy } from "@intellectif/lk-core";
|
|
6
|
+
//#region src/components/shared/playback-group.ts
|
|
7
|
+
/**
|
|
8
|
+
* Media elements that must not play at the same time, keyed by group name.
|
|
9
|
+
*
|
|
10
|
+
* Module-level on purpose: the two players of a dictation are two separate
|
|
11
|
+
* `<ActivityMedia>` mounts with no common ancestor that owns playback, and a
|
|
12
|
+
* context would have to be threaded through every activity component to reach
|
|
13
|
+
* them. A map keyed by a group name is the smaller mechanism, and it costs
|
|
14
|
+
* nothing to the components that do not name a group. The caller mints the
|
|
15
|
+
* name per mount — never from the activity id, which two renderings of one
|
|
16
|
+
* item share, and never from `useId`, which two separately hydrated roots
|
|
17
|
+
* share.
|
|
18
|
+
*/
|
|
19
|
+
const groups = /* @__PURE__ */ new Map();
|
|
20
|
+
/** Adds an element to a group; returns the matching removal. */
|
|
21
|
+
function joinPlaybackGroup(group, element) {
|
|
22
|
+
let members = groups.get(group);
|
|
23
|
+
if (members === void 0) {
|
|
24
|
+
members = /* @__PURE__ */ new Set();
|
|
25
|
+
groups.set(group, members);
|
|
26
|
+
}
|
|
27
|
+
members.add(element);
|
|
28
|
+
return () => {
|
|
29
|
+
const current = groups.get(group);
|
|
30
|
+
if (current === void 0) return;
|
|
31
|
+
current.delete(element);
|
|
32
|
+
if (current.size === 0) groups.delete(group);
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Pauses every OTHER member of the group. Called from a player's own `play`
|
|
37
|
+
* event, so whichever recording the learner starts silences the rest.
|
|
38
|
+
*
|
|
39
|
+
* Pausing charges nothing: a budgeted play is charged inside the starting
|
|
40
|
+
* player's own handler, and pausing another player neither refunds nor starts
|
|
41
|
+
* anything — its transport records the position, so a later resume is a
|
|
42
|
+
* resume and not a second play.
|
|
43
|
+
*/
|
|
44
|
+
function pausePlaybackGroupOthers(group, element) {
|
|
45
|
+
const members = groups.get(group);
|
|
46
|
+
if (members === void 0) return;
|
|
47
|
+
for (const member of members) if (member !== element && !member.paused) member.pause();
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Keeps `ref`'s element registered in `group` for as long as both exist.
|
|
51
|
+
*
|
|
52
|
+
* Re-registers after every commit rather than on a dependency list: the
|
|
53
|
+
* element behind a ref can change while the ref object does not — a player
|
|
54
|
+
* that swaps the SDK transport for the native bar when `renderMode` turns to
|
|
55
|
+
* `review` mounts a new `<audio>` — and a list of `[ref, group]` would leave
|
|
56
|
+
* the new element out of the group. Leaving and joining is a set delete and a
|
|
57
|
+
* set add.
|
|
58
|
+
*/
|
|
59
|
+
function usePlaybackGroup(ref, group) {
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
const element = ref.current;
|
|
62
|
+
if (group === void 0 || element === null) return;
|
|
63
|
+
return joinPlaybackGroup(group, element);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
//#endregion
|
|
67
|
+
//#region src/components/shared/AudioTransport.tsx
|
|
68
|
+
/**
|
|
69
|
+
* The SDK's own audio player, used whenever a policy has something to enforce.
|
|
70
|
+
*
|
|
71
|
+
* The browser's control bar cannot express a spent budget — its play button
|
|
72
|
+
* stays enabled — and a control that looks operable and does nothing is a
|
|
73
|
+
* WCAG 3.2.2 / 4.1.3 failure, so an enforcing policy replaces the bar rather
|
|
74
|
+
* than lying with it. What replaces it is a SUPERSET minus what the policy
|
|
75
|
+
* removes on purpose: play/pause, elapsed and total time, mute, volume, an
|
|
76
|
+
* optional speed control, an optional scrubber, and a live plays-remaining
|
|
77
|
+
* status. Volume and mute are never restricted by any policy — they affect no
|
|
78
|
+
* assessment property, and a learner in a lab with a locked OS volume has no
|
|
79
|
+
* other lever once the native bar is gone.
|
|
80
|
+
*/
|
|
81
|
+
/** A resume is a start within a quarter-second of where playback last stopped. */
|
|
82
|
+
const RESUME_EPSILON = .25;
|
|
83
|
+
/** Below this, a seek is the browser settling rather than the learner moving. */
|
|
84
|
+
const SEEK_EPSILON = .35;
|
|
85
|
+
/** A charged play that errors before this much audio played produced nothing. */
|
|
86
|
+
const NO_PROGRESS = .25;
|
|
87
|
+
const formatTime = (seconds) => {
|
|
88
|
+
if (!Number.isFinite(seconds) || seconds < 0) return "0:00";
|
|
89
|
+
const whole = Math.floor(seconds);
|
|
90
|
+
return `${Math.floor(whole / 60)}:${String(whole % 60).padStart(2, "0")}`;
|
|
91
|
+
};
|
|
92
|
+
function AudioTransport({ media, policy, renderMode = "practice", disabled = false, locale, mediaBudget, mediaStrings, strings, onInteraction, playbackGroup }) {
|
|
93
|
+
const elementRef = useRef(null);
|
|
94
|
+
const statusId = useId();
|
|
95
|
+
usePlaybackGroup(elementRef, playbackGroup);
|
|
96
|
+
const suppliedStrings = mediaBudget?.strings ?? mediaStrings;
|
|
97
|
+
const s = {
|
|
98
|
+
...useLkStrings(strings).media,
|
|
99
|
+
...mediaStrings,
|
|
100
|
+
...mediaBudget?.strings
|
|
101
|
+
};
|
|
102
|
+
const budgeted = (mediaBudget?.enforced ?? renderMode !== "review") && policy.maxPlays !== null && mediaBudget !== void 0;
|
|
103
|
+
const maxPlays = policy.maxPlays ?? 0;
|
|
104
|
+
const usedRef = useRef(mediaBudget?.entry?.plays ?? 0);
|
|
105
|
+
const pendingRef = useRef(false);
|
|
106
|
+
const resumeAtRef = useRef(null);
|
|
107
|
+
const highWaterRef = useRef(0);
|
|
108
|
+
const chargeRef = useRef(null);
|
|
109
|
+
const seededRef = useRef(false);
|
|
110
|
+
const lastPositionRef = useRef(-1);
|
|
111
|
+
const selfStartRef = useRef(false);
|
|
112
|
+
const paidRef = useRef(false);
|
|
113
|
+
const [used, setUsed] = useState(usedRef.current);
|
|
114
|
+
const [playing, setPlaying] = useState(false);
|
|
115
|
+
const [pending, setPending] = useState(false);
|
|
116
|
+
const [elapsed, setElapsed] = useState(0);
|
|
117
|
+
const [duration, setDuration] = useState(0);
|
|
118
|
+
const [muted, setMuted] = useState(false);
|
|
119
|
+
const [volume, setVolume] = useState(1);
|
|
120
|
+
const [confirming, setConfirming] = useState(false);
|
|
121
|
+
const [notice, setNotice] = useState("");
|
|
122
|
+
const [noticeNonce, setNoticeNonce] = useState(0);
|
|
123
|
+
const remaining = Math.max(0, maxPlays - used);
|
|
124
|
+
const announce = useCallback((message) => {
|
|
125
|
+
setNotice(message);
|
|
126
|
+
setNoticeNonce((n) => n + 1);
|
|
127
|
+
}, []);
|
|
128
|
+
const emit = useCallback((type, playsUsed) => {
|
|
129
|
+
if (!budgeted || mediaBudget === void 0 || onInteraction === void 0) return;
|
|
130
|
+
onInteraction({
|
|
131
|
+
type,
|
|
132
|
+
activityId: mediaBudget.activityId ?? mediaBudget.slotId,
|
|
133
|
+
timestamp: Date.now(),
|
|
134
|
+
payload: {
|
|
135
|
+
mediaKey: mediaBudget.key,
|
|
136
|
+
mediaType: "audio",
|
|
137
|
+
playsUsed,
|
|
138
|
+
maxPlays,
|
|
139
|
+
playsRemaining: Math.max(0, maxPlays - playsUsed)
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
}, [
|
|
143
|
+
budgeted,
|
|
144
|
+
mediaBudget,
|
|
145
|
+
maxPlays,
|
|
146
|
+
onInteraction
|
|
147
|
+
]);
|
|
148
|
+
const reportPosition = useCallback((seconds) => {
|
|
149
|
+
mediaBudget?.onPosition?.(mediaBudget.key, seconds);
|
|
150
|
+
}, [mediaBudget]);
|
|
151
|
+
/** A start within a hair of where playback last stopped is a resume, not a play. */
|
|
152
|
+
const isResume = useCallback((element) => {
|
|
153
|
+
const at = resumeAtRef.current;
|
|
154
|
+
return at !== null && Math.abs(element.currentTime - at) < RESUME_EPSILON;
|
|
155
|
+
}, []);
|
|
156
|
+
const buildClaim = useCallback(() => {
|
|
157
|
+
if (mediaBudget === void 0) return null;
|
|
158
|
+
return {
|
|
159
|
+
key: mediaBudget.key,
|
|
160
|
+
previousPlaysUsed: usedRef.current,
|
|
161
|
+
playsUsed: usedRef.current + 1,
|
|
162
|
+
maxPlays,
|
|
163
|
+
playsRemaining: Math.max(0, maxPlays - (usedRef.current + 1)),
|
|
164
|
+
slotId: mediaBudget.slotId,
|
|
165
|
+
index: mediaBudget.index,
|
|
166
|
+
...mediaBudget.activityId !== void 0 ? { activityId: mediaBudget.activityId } : {}
|
|
167
|
+
};
|
|
168
|
+
}, [mediaBudget, maxPlays]);
|
|
169
|
+
const refuse = useCallback(() => {
|
|
170
|
+
announce(s.noPlaysRemaining);
|
|
171
|
+
emit("media-play-refused", usedRef.current);
|
|
172
|
+
}, [
|
|
173
|
+
announce,
|
|
174
|
+
emit,
|
|
175
|
+
s.noPlaysRemaining
|
|
176
|
+
]);
|
|
177
|
+
const startPlayback = useCallback(() => {
|
|
178
|
+
const element = elementRef.current;
|
|
179
|
+
if (element === null) return;
|
|
180
|
+
highWaterRef.current = element.currentTime;
|
|
181
|
+
selfStartRef.current = true;
|
|
182
|
+
element.play().catch(() => {
|
|
183
|
+
selfStartRef.current = false;
|
|
184
|
+
});
|
|
185
|
+
}, []);
|
|
186
|
+
const commit = useCallback((claim) => {
|
|
187
|
+
const element = elementRef.current;
|
|
188
|
+
chargeRef.current = {
|
|
189
|
+
claim,
|
|
190
|
+
at: element?.currentTime ?? 0
|
|
191
|
+
};
|
|
192
|
+
usedRef.current = claim.playsUsed;
|
|
193
|
+
setUsed(claim.playsUsed);
|
|
194
|
+
emit("media-play-consumed", claim.playsUsed);
|
|
195
|
+
}, [emit]);
|
|
196
|
+
/**
|
|
197
|
+
* Charges a play, then starts it.
|
|
198
|
+
*
|
|
199
|
+
* The confirmed tier holds playback until the consumer's atomic write
|
|
200
|
+
* settles, which is the only construction that catches a second tab: two
|
|
201
|
+
* mounts seeded at 0 both claim 1, and only the server can tell them apart.
|
|
202
|
+
*/
|
|
203
|
+
const claimAndStart = useCallback((element, alreadyPlaying) => {
|
|
204
|
+
if (disabled) {
|
|
205
|
+
if (alreadyPlaying) element.pause();
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const claim = buildClaim();
|
|
209
|
+
if (claim === null) return;
|
|
210
|
+
const result = mediaBudget?.onPlayConsumed?.(claim);
|
|
211
|
+
if (result !== void 0 && typeof result.then === "function") {
|
|
212
|
+
if (alreadyPlaying) element.pause();
|
|
213
|
+
pendingRef.current = true;
|
|
214
|
+
setPending(true);
|
|
215
|
+
result.then((grant) => {
|
|
216
|
+
const granted = grant !== void 0 && Number.isInteger(grant.playsUsed) ? grant.playsUsed : claim.playsUsed;
|
|
217
|
+
if (granted > maxPlays) {
|
|
218
|
+
usedRef.current = granted;
|
|
219
|
+
setUsed(granted);
|
|
220
|
+
refuse();
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
commit({
|
|
224
|
+
...claim,
|
|
225
|
+
playsUsed: granted
|
|
226
|
+
});
|
|
227
|
+
startPlayback();
|
|
228
|
+
}).catch(() => {
|
|
229
|
+
announce(s.playFailed);
|
|
230
|
+
emit("media-play-errored", usedRef.current);
|
|
231
|
+
}).finally(() => {
|
|
232
|
+
pendingRef.current = false;
|
|
233
|
+
setPending(false);
|
|
234
|
+
});
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
commit(claim);
|
|
238
|
+
if (alreadyPlaying) paidRef.current = true;
|
|
239
|
+
else startPlayback();
|
|
240
|
+
}, [
|
|
241
|
+
disabled,
|
|
242
|
+
buildClaim,
|
|
243
|
+
mediaBudget,
|
|
244
|
+
maxPlays,
|
|
245
|
+
commit,
|
|
246
|
+
startPlayback,
|
|
247
|
+
refuse,
|
|
248
|
+
announce,
|
|
249
|
+
emit,
|
|
250
|
+
s.playFailed
|
|
251
|
+
]);
|
|
252
|
+
const handleButton = useCallback(() => {
|
|
253
|
+
const element = elementRef.current;
|
|
254
|
+
if (element === null || pendingRef.current || disabled) return;
|
|
255
|
+
if (!element.paused) {
|
|
256
|
+
element.pause();
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
if (!budgeted || isResume(element)) {
|
|
260
|
+
startPlayback();
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
if (remaining === 0) {
|
|
264
|
+
refuse();
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
if (remaining === 1 && !confirming) {
|
|
268
|
+
setConfirming(true);
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
setConfirming(false);
|
|
272
|
+
claimAndStart(element, false);
|
|
273
|
+
}, [
|
|
274
|
+
disabled,
|
|
275
|
+
budgeted,
|
|
276
|
+
isResume,
|
|
277
|
+
startPlayback,
|
|
278
|
+
remaining,
|
|
279
|
+
refuse,
|
|
280
|
+
confirming,
|
|
281
|
+
claimAndStart
|
|
282
|
+
]);
|
|
283
|
+
const handleLoadedMetadata = useCallback(() => {
|
|
284
|
+
const element = elementRef.current;
|
|
285
|
+
if (element === null) return;
|
|
286
|
+
setDuration(Number.isFinite(element.duration) ? element.duration : 0);
|
|
287
|
+
const at = mediaBudget?.entry?.at;
|
|
288
|
+
if (!seededRef.current && typeof at === "number" && Number.isFinite(at) && at > 0) {
|
|
289
|
+
seededRef.current = true;
|
|
290
|
+
highWaterRef.current = at;
|
|
291
|
+
resumeAtRef.current = at;
|
|
292
|
+
element.currentTime = at;
|
|
293
|
+
setElapsed(at);
|
|
294
|
+
}
|
|
295
|
+
}, [mediaBudget]);
|
|
296
|
+
/**
|
|
297
|
+
* The budget lives on the ELEMENT's `play` event, not on the button, so a
|
|
298
|
+
* hardware media key, a browser extension or a scripted `el.play()` is
|
|
299
|
+
* charged too — and an exhausted budget stops playback inside the event,
|
|
300
|
+
* before a sample is audible.
|
|
301
|
+
*/
|
|
302
|
+
const handlePlay = useCallback(() => {
|
|
303
|
+
const element = elementRef.current;
|
|
304
|
+
if (element === null) return;
|
|
305
|
+
if (disabled) {
|
|
306
|
+
element.pause();
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
if (playbackGroup !== void 0) pausePlaybackGroupOthers(playbackGroup, element);
|
|
310
|
+
if (selfStartRef.current) {
|
|
311
|
+
selfStartRef.current = false;
|
|
312
|
+
paidRef.current = true;
|
|
313
|
+
setPlaying(true);
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
if (pendingRef.current) {
|
|
317
|
+
setPlaying(true);
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
if (isResume(element)) {
|
|
321
|
+
paidRef.current = true;
|
|
322
|
+
setPlaying(true);
|
|
323
|
+
resumeAtRef.current = null;
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
if (!budgeted) {
|
|
327
|
+
paidRef.current = true;
|
|
328
|
+
setPlaying(true);
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
if (remaining === 0) {
|
|
332
|
+
element.pause();
|
|
333
|
+
refuse();
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
setPlaying(true);
|
|
337
|
+
claimAndStart(element, true);
|
|
338
|
+
}, [
|
|
339
|
+
disabled,
|
|
340
|
+
playbackGroup,
|
|
341
|
+
isResume,
|
|
342
|
+
budgeted,
|
|
343
|
+
remaining,
|
|
344
|
+
refuse,
|
|
345
|
+
claimAndStart
|
|
346
|
+
]);
|
|
347
|
+
const handlePause = useCallback(() => {
|
|
348
|
+
const element = elementRef.current;
|
|
349
|
+
setPlaying(false);
|
|
350
|
+
if (element === null) return;
|
|
351
|
+
if (!paidRef.current) return;
|
|
352
|
+
paidRef.current = false;
|
|
353
|
+
resumeAtRef.current = element.currentTime;
|
|
354
|
+
reportPosition(element.currentTime);
|
|
355
|
+
}, [reportPosition]);
|
|
356
|
+
const handleEnded = useCallback(() => {
|
|
357
|
+
paidRef.current = false;
|
|
358
|
+
setPlaying(false);
|
|
359
|
+
resumeAtRef.current = null;
|
|
360
|
+
highWaterRef.current = 0;
|
|
361
|
+
chargeRef.current = null;
|
|
362
|
+
setElapsed(0);
|
|
363
|
+
reportPosition(0);
|
|
364
|
+
}, [reportPosition]);
|
|
365
|
+
const handleTimeUpdate = useCallback(() => {
|
|
366
|
+
const element = elementRef.current;
|
|
367
|
+
if (element === null) return;
|
|
368
|
+
setElapsed(element.currentTime);
|
|
369
|
+
highWaterRef.current = Math.max(highWaterRef.current, element.currentTime);
|
|
370
|
+
const whole = Math.floor(element.currentTime);
|
|
371
|
+
if (whole !== lastPositionRef.current) {
|
|
372
|
+
lastPositionRef.current = whole;
|
|
373
|
+
reportPosition(element.currentTime);
|
|
374
|
+
}
|
|
375
|
+
}, [reportPosition]);
|
|
376
|
+
const handleSeeking = useCallback(() => {
|
|
377
|
+
const element = elementRef.current;
|
|
378
|
+
if (element === null || policy.seek !== "none") return;
|
|
379
|
+
if (Math.abs(element.currentTime - highWaterRef.current) > SEEK_EPSILON) {
|
|
380
|
+
element.currentTime = highWaterRef.current;
|
|
381
|
+
announce(s.seekBlocked);
|
|
382
|
+
}
|
|
383
|
+
}, [
|
|
384
|
+
policy.seek,
|
|
385
|
+
announce,
|
|
386
|
+
s.seekBlocked
|
|
387
|
+
]);
|
|
388
|
+
const handleRateChange = useCallback(() => {
|
|
389
|
+
const element = elementRef.current;
|
|
390
|
+
if (element === null || policy.rate !== "fixed" || element.playbackRate === 1) return;
|
|
391
|
+
element.playbackRate = 1;
|
|
392
|
+
announce(s.rateBlocked);
|
|
393
|
+
}, [
|
|
394
|
+
policy.rate,
|
|
395
|
+
announce,
|
|
396
|
+
s.rateBlocked
|
|
397
|
+
]);
|
|
398
|
+
const handleError = useCallback(() => {
|
|
399
|
+
const charge = chargeRef.current;
|
|
400
|
+
const element = elementRef.current;
|
|
401
|
+
const progressed = charge !== null && element !== null && element.currentTime - charge.at >= NO_PROGRESS;
|
|
402
|
+
if (charge !== null && !progressed) {
|
|
403
|
+
if (mediaBudget?.onPlayRefunded !== void 0) {
|
|
404
|
+
usedRef.current = charge.claim.previousPlaysUsed;
|
|
405
|
+
setUsed(charge.claim.previousPlaysUsed);
|
|
406
|
+
mediaBudget.onPlayRefunded(charge.claim);
|
|
407
|
+
emit("media-play-refunded", charge.claim.previousPlaysUsed);
|
|
408
|
+
} else emit("media-play-errored", usedRef.current);
|
|
409
|
+
}
|
|
410
|
+
chargeRef.current = null;
|
|
411
|
+
setPlaying(false);
|
|
412
|
+
announce(s.playFailed);
|
|
413
|
+
}, [
|
|
414
|
+
mediaBudget,
|
|
415
|
+
emit,
|
|
416
|
+
announce,
|
|
417
|
+
s.playFailed
|
|
418
|
+
]);
|
|
419
|
+
useEffect(() => {
|
|
420
|
+
const element = elementRef.current;
|
|
421
|
+
if (element !== null) {
|
|
422
|
+
element.volume = volume;
|
|
423
|
+
element.muted = muted;
|
|
424
|
+
}
|
|
425
|
+
}, [volume, muted]);
|
|
426
|
+
const exhausted = budgeted && remaining === 0;
|
|
427
|
+
const buttonLabel = pending ? s.preparing : playing ? s.pause : s.play;
|
|
428
|
+
return /* @__PURE__ */ jsxs("figure", {
|
|
429
|
+
className: "lk-media",
|
|
430
|
+
"data-controls": "minimal",
|
|
431
|
+
children: [
|
|
432
|
+
/* @__PURE__ */ jsxs("audio", {
|
|
433
|
+
ref: elementRef,
|
|
434
|
+
className: "lk-media-el",
|
|
435
|
+
preload: "metadata",
|
|
436
|
+
"aria-label": media.alt || void 0,
|
|
437
|
+
onLoadedMetadata: handleLoadedMetadata,
|
|
438
|
+
onPlay: handlePlay,
|
|
439
|
+
onPause: handlePause,
|
|
440
|
+
onEnded: handleEnded,
|
|
441
|
+
onTimeUpdate: handleTimeUpdate,
|
|
442
|
+
onSeeking: handleSeeking,
|
|
443
|
+
onRateChange: handleRateChange,
|
|
444
|
+
onError: handleError,
|
|
445
|
+
children: [/* @__PURE__ */ jsx("source", { src: media.url }), media.captionsUrl ? /* @__PURE__ */ jsx("track", {
|
|
446
|
+
kind: "captions",
|
|
447
|
+
src: media.captionsUrl,
|
|
448
|
+
default: true
|
|
449
|
+
}) : null]
|
|
450
|
+
}),
|
|
451
|
+
/* @__PURE__ */ jsxs("div", {
|
|
452
|
+
className: "lk-media-transport",
|
|
453
|
+
dir: "ltr",
|
|
454
|
+
...suppliedStrings !== void 0 && locale !== void 0 ? { lang: locale } : {},
|
|
455
|
+
children: [
|
|
456
|
+
/* @__PURE__ */ jsx("button", {
|
|
457
|
+
type: "button",
|
|
458
|
+
className: "lk-media-play",
|
|
459
|
+
onClick: handleButton,
|
|
460
|
+
"aria-disabled": exhausted || disabled || void 0,
|
|
461
|
+
"aria-busy": pending || void 0,
|
|
462
|
+
"aria-label": exhausted ? `${s.play} — ${s.noPlaysRemaining}` : void 0,
|
|
463
|
+
"aria-describedby": budgeted ? statusId : void 0,
|
|
464
|
+
children: buttonLabel
|
|
465
|
+
}),
|
|
466
|
+
/* @__PURE__ */ jsxs("span", {
|
|
467
|
+
className: "lk-media-time",
|
|
468
|
+
children: [
|
|
469
|
+
formatTime(elapsed),
|
|
470
|
+
" / ",
|
|
471
|
+
formatTime(duration)
|
|
472
|
+
]
|
|
473
|
+
}),
|
|
474
|
+
policy.seek === "allow" ? /* @__PURE__ */ jsx("input", {
|
|
475
|
+
type: "range",
|
|
476
|
+
className: "lk-media-scrub",
|
|
477
|
+
min: 0,
|
|
478
|
+
max: duration || 0,
|
|
479
|
+
step: .1,
|
|
480
|
+
value: Math.min(elapsed, duration || 0),
|
|
481
|
+
"aria-label": s.seek,
|
|
482
|
+
"aria-valuetext": s.timeValue(formatTime(elapsed), formatTime(duration)),
|
|
483
|
+
onChange: (event) => {
|
|
484
|
+
const element = elementRef.current;
|
|
485
|
+
if (element !== null) element.currentTime = Number(event.target.value);
|
|
486
|
+
}
|
|
487
|
+
}) : null,
|
|
488
|
+
/* @__PURE__ */ jsx("button", {
|
|
489
|
+
type: "button",
|
|
490
|
+
className: "lk-media-mute",
|
|
491
|
+
"aria-pressed": muted,
|
|
492
|
+
onClick: () => setMuted((m) => !m),
|
|
493
|
+
children: muted ? s.unmute : s.mute
|
|
494
|
+
}),
|
|
495
|
+
/* @__PURE__ */ jsx("input", {
|
|
496
|
+
type: "range",
|
|
497
|
+
className: "lk-media-volume",
|
|
498
|
+
min: 0,
|
|
499
|
+
max: 1,
|
|
500
|
+
step: .05,
|
|
501
|
+
value: volume,
|
|
502
|
+
"aria-label": s.volume,
|
|
503
|
+
onChange: (event) => setVolume(Number(event.target.value))
|
|
504
|
+
}),
|
|
505
|
+
policy.rate === "allow" ? /* @__PURE__ */ jsx("select", {
|
|
506
|
+
className: "lk-media-rate",
|
|
507
|
+
"aria-label": s.speed,
|
|
508
|
+
defaultValue: "1",
|
|
509
|
+
onChange: (event) => {
|
|
510
|
+
const element = elementRef.current;
|
|
511
|
+
if (element !== null) element.playbackRate = Number(event.target.value);
|
|
512
|
+
},
|
|
513
|
+
children: [
|
|
514
|
+
"0.75",
|
|
515
|
+
"1",
|
|
516
|
+
"1.25",
|
|
517
|
+
"1.5"
|
|
518
|
+
].map((rate) => /* @__PURE__ */ jsxs("option", {
|
|
519
|
+
value: rate,
|
|
520
|
+
children: [rate, "×"]
|
|
521
|
+
}, rate))
|
|
522
|
+
}) : null
|
|
523
|
+
]
|
|
524
|
+
}),
|
|
525
|
+
budgeted ? /* @__PURE__ */ jsx("p", {
|
|
526
|
+
className: "lk-media-plays",
|
|
527
|
+
id: statusId,
|
|
528
|
+
role: "status",
|
|
529
|
+
children: remaining > 0 ? s.playsRemaining(remaining, maxPlays) : s.noPlaysRemaining
|
|
530
|
+
}) : null,
|
|
531
|
+
/* @__PURE__ */ jsx("p", {
|
|
532
|
+
className: "lk-media-notice",
|
|
533
|
+
role: "alert",
|
|
534
|
+
children: notice
|
|
535
|
+
}, noticeNonce),
|
|
536
|
+
confirming ? /* @__PURE__ */ jsxs("fieldset", {
|
|
537
|
+
className: "lk-media-confirm",
|
|
538
|
+
children: [
|
|
539
|
+
/* @__PURE__ */ jsx("legend", { children: s.lastPlayConfirm }),
|
|
540
|
+
/* @__PURE__ */ jsx("button", {
|
|
541
|
+
type: "button",
|
|
542
|
+
className: "lk-media-confirm-start",
|
|
543
|
+
autoFocus: true,
|
|
544
|
+
onClick: () => {
|
|
545
|
+
const element = elementRef.current;
|
|
546
|
+
setConfirming(false);
|
|
547
|
+
if (element !== null) claimAndStart(element, false);
|
|
548
|
+
},
|
|
549
|
+
children: s.lastPlayStart
|
|
550
|
+
}),
|
|
551
|
+
/* @__PURE__ */ jsx("button", {
|
|
552
|
+
type: "button",
|
|
553
|
+
className: "lk-media-confirm-cancel",
|
|
554
|
+
onClick: () => setConfirming(false),
|
|
555
|
+
children: s.lastPlayCancel
|
|
556
|
+
})
|
|
557
|
+
]
|
|
558
|
+
}) : null
|
|
559
|
+
]
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
//#endregion
|
|
563
|
+
//#region src/components/shared/ActivityMedia.tsx
|
|
564
|
+
function ActivityMedia(props) {
|
|
565
|
+
const { media, renderMode = "practice", playbackGroup } = props;
|
|
566
|
+
const s = useLkStrings(props.strings);
|
|
567
|
+
const audioRef = useRef(null);
|
|
568
|
+
usePlaybackGroup(audioRef, media.type === "audio" ? playbackGroup : void 0);
|
|
569
|
+
if (media.type === "image") return /* @__PURE__ */ jsx("figure", {
|
|
570
|
+
className: "lk-media",
|
|
571
|
+
children: /* @__PURE__ */ jsx("img", {
|
|
572
|
+
className: "lk-media-el",
|
|
573
|
+
src: media.url,
|
|
574
|
+
alt: media.alt ?? ""
|
|
575
|
+
})
|
|
576
|
+
});
|
|
577
|
+
if (media.type === "audio") {
|
|
578
|
+
const policy = resolvePlaybackPolicy(media);
|
|
579
|
+
if (policy.maxPlays !== null && renderMode === "exam" && props.mediaBudget === void 0) throw new Error(`ActivityMedia: audio ${JSON.stringify(media.url)} declares maxPlays and is rendered in renderMode "exam" without a \`mediaBudget\` binding. Nothing would persist the count, so a refresh restores the full budget while the page says plays remain. Render it through <ActivitySequence mediaBudget={…}> or pass \`mediaBudget\` yourself.`);
|
|
580
|
+
if (policy.controls === "minimal" && renderMode !== "review") return /* @__PURE__ */ jsx(AudioTransport, {
|
|
581
|
+
...props,
|
|
582
|
+
media,
|
|
583
|
+
policy
|
|
584
|
+
});
|
|
585
|
+
const hints = renderMode === "review" ? [] : policy.nativeControlHints;
|
|
586
|
+
return /* @__PURE__ */ jsx("figure", {
|
|
587
|
+
className: "lk-media",
|
|
588
|
+
children: /* @__PURE__ */ jsxs("audio", {
|
|
589
|
+
ref: audioRef,
|
|
590
|
+
className: "lk-media-el",
|
|
591
|
+
controls: true,
|
|
592
|
+
"aria-label": media.alt || void 0,
|
|
593
|
+
...playbackGroup !== void 0 ? { onPlay: (event) => pausePlaybackGroupOthers(playbackGroup, event.currentTarget) } : {},
|
|
594
|
+
...hints.length > 0 ? { controlsList: hints.map((hint) => hint === "hide-download" ? "nodownload" : "noplaybackrate").join(" ") } : {},
|
|
595
|
+
children: [/* @__PURE__ */ jsx("source", { src: media.url }), media.captionsUrl ? /* @__PURE__ */ jsx("track", {
|
|
596
|
+
kind: "captions",
|
|
597
|
+
src: media.captionsUrl,
|
|
598
|
+
default: true
|
|
599
|
+
}) : null]
|
|
600
|
+
})
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
if (media.type === "embed") return /* @__PURE__ */ jsx("figure", {
|
|
604
|
+
className: "lk-media",
|
|
605
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
606
|
+
className: "lk-media-embed",
|
|
607
|
+
children: /* @__PURE__ */ jsx("iframe", {
|
|
608
|
+
className: "lk-media-el",
|
|
609
|
+
src: media.url,
|
|
610
|
+
title: media.alt ?? s.embeddedMedia,
|
|
611
|
+
loading: "lazy",
|
|
612
|
+
referrerPolicy: "strict-origin-when-cross-origin",
|
|
613
|
+
sandbox: "allow-scripts allow-same-origin allow-presentation",
|
|
614
|
+
allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share",
|
|
615
|
+
allowFullScreen: true
|
|
616
|
+
})
|
|
617
|
+
})
|
|
618
|
+
});
|
|
619
|
+
return /* @__PURE__ */ jsx("figure", {
|
|
620
|
+
className: "lk-media",
|
|
621
|
+
children: /* @__PURE__ */ jsxs("video", {
|
|
622
|
+
className: "lk-media-el",
|
|
623
|
+
controls: true,
|
|
624
|
+
"aria-label": media.alt || void 0,
|
|
625
|
+
children: [/* @__PURE__ */ jsx("source", { src: media.url }), media.captionsUrl ? /* @__PURE__ */ jsx("track", {
|
|
626
|
+
kind: "captions",
|
|
627
|
+
src: media.captionsUrl,
|
|
628
|
+
default: true
|
|
629
|
+
}) : null]
|
|
630
|
+
})
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
//#endregion
|
|
634
|
+
export { ActivityMedia as t };
|
|
635
|
+
|
|
636
|
+
//# sourceMappingURL=ActivityMedia-vDiP-Psa.js.map
|