@intellectif/lk-react 23.0.1 → 23.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/README.md +4 -4
- package/dist/{WrittenResponse-CgRrjM4S.d.ts → WrittenResponse-B7A5gHMj.d.ts} +1 -1
- package/dist/{WrittenResponse-D2K1VW_V.d.cts → WrittenResponse-BpL9p2Hn.d.cts} +1 -1
- package/dist/ai/LkAiProvider.cjs +3 -3
- package/dist/ai/LkAiProvider.d.cts +12 -2
- package/dist/ai/LkAiProvider.d.ts +12 -2
- package/dist/ai/LkAiProvider.js +1 -1
- package/dist/ai/useAiHelp.cjs +9 -7
- package/dist/ai/useAiHelp.d.cts +82 -3
- package/dist/ai/useAiHelp.d.ts +82 -3
- package/dist/ai/useAiHelp.js +2 -4
- package/dist/{chunk-VPU6UY4O.cjs → chunk-2PNSVBLQ.cjs} +5 -6
- package/dist/chunk-2PNSVBLQ.cjs.map +1 -0
- package/dist/{chunk-HZIT24BK.js → chunk-4ZZWZSWI.js} +4 -4
- package/dist/{chunk-HZIT24BK.js.map → chunk-4ZZWZSWI.js.map} +1 -1
- package/dist/{chunk-B7JU52YQ.cjs → chunk-7ALBSPYR.cjs} +34 -35
- package/dist/chunk-7ALBSPYR.cjs.map +1 -0
- package/dist/{chunk-TGTP5DKF.js → chunk-7NFY3M3W.js} +10 -10
- package/dist/{chunk-TGTP5DKF.js.map → chunk-7NFY3M3W.js.map} +1 -1
- package/dist/{chunk-E4UF4XZM.js → chunk-7SB2MJA4.js} +4 -4
- package/dist/{chunk-E4UF4XZM.js.map → chunk-7SB2MJA4.js.map} +1 -1
- package/dist/{chunk-ERV666AR.js → chunk-ABJJ3LII.js} +9 -10
- package/dist/chunk-ABJJ3LII.js.map +1 -0
- package/dist/{chunk-NFGUJ52G.cjs → chunk-BIGGXHAW.cjs} +8 -2
- package/dist/chunk-BIGGXHAW.cjs.map +1 -0
- package/dist/{chunk-O7MINPKZ.js → chunk-C7QZE5BI.js} +9 -10
- package/dist/chunk-C7QZE5BI.js.map +1 -0
- package/dist/{chunk-IYGF7PZY.cjs → chunk-CWTUWNV3.cjs} +25 -26
- package/dist/chunk-CWTUWNV3.cjs.map +1 -0
- package/dist/{chunk-4MXECBZT.js → chunk-DC4CQCK5.js} +40 -13
- package/dist/chunk-DC4CQCK5.js.map +1 -0
- package/dist/{chunk-PGAPZ6UE.cjs → chunk-DS6HN3YR.cjs} +34 -35
- package/dist/chunk-DS6HN3YR.cjs.map +1 -0
- package/dist/{chunk-U5VFJVQ2.js → chunk-FDQR4GAZ.js} +3 -4
- package/dist/chunk-FDQR4GAZ.js.map +1 -0
- package/dist/{chunk-DPNCCWOV.js → chunk-FKGMSOJF.js} +8 -9
- package/dist/chunk-FKGMSOJF.js.map +1 -0
- package/dist/{chunk-SPSKDNEE.js → chunk-G6PXJ2SA.js} +11 -12
- package/dist/chunk-G6PXJ2SA.js.map +1 -0
- package/dist/{chunk-C4PSJ3ZC.js → chunk-HNLRVRQR.js} +8 -2
- package/dist/chunk-HNLRVRQR.js.map +1 -0
- package/dist/{chunk-FISEZBLF.cjs → chunk-J3C72RPK.cjs} +7 -7
- package/dist/{chunk-FISEZBLF.cjs.map → chunk-J3C72RPK.cjs.map} +1 -1
- package/dist/{chunk-SHDSOOBF.cjs → chunk-KFLIDTDU.cjs} +25 -26
- package/dist/chunk-KFLIDTDU.cjs.map +1 -0
- package/dist/{chunk-W6UMY7PF.cjs → chunk-KHKH5LCT.cjs} +7 -8
- package/dist/chunk-KHKH5LCT.cjs.map +1 -0
- package/dist/{chunk-7F2YQWMW.cjs → chunk-LBEKRN6Y.cjs} +122 -11
- package/dist/chunk-LBEKRN6Y.cjs.map +1 -0
- package/dist/{chunk-6RIM5EQP.cjs → chunk-LPUWXIPR.cjs} +197 -12
- package/dist/chunk-LPUWXIPR.cjs.map +1 -0
- package/dist/{chunk-XS6OYYVR.cjs → chunk-MKXEM2C5.cjs} +19 -20
- package/dist/chunk-MKXEM2C5.cjs.map +1 -0
- package/dist/{chunk-CXIP7ERK.js → chunk-MXNC5UNO.js} +182 -8
- package/dist/chunk-MXNC5UNO.js.map +1 -0
- package/dist/{chunk-MXZHL4U5.cjs → chunk-NAK55BYU.cjs} +31 -32
- package/dist/chunk-NAK55BYU.cjs.map +1 -0
- package/dist/{chunk-UKUHVCZX.cjs → chunk-NDBMKGQ5.cjs} +5 -5
- package/dist/{chunk-UKUHVCZX.cjs.map → chunk-NDBMKGQ5.cjs.map} +1 -1
- package/dist/{chunk-XYJBRKBZ.js → chunk-ORT3KLGI.js} +3 -4
- package/dist/chunk-ORT3KLGI.js.map +1 -0
- package/dist/{chunk-JMEZYYCE.js → chunk-PWHECW6N.js} +11 -12
- package/dist/chunk-PWHECW6N.js.map +1 -0
- package/dist/{chunk-6GQLCCGN.js → chunk-RBS5A2DF.js} +9 -10
- package/dist/chunk-RBS5A2DF.js.map +1 -0
- package/dist/{chunk-B4JRBV56.cjs → chunk-RPWUDXG5.cjs} +6 -6
- package/dist/{chunk-B4JRBV56.cjs.map → chunk-RPWUDXG5.cjs.map} +1 -1
- package/dist/{chunk-KI6DJ5ZF.js → chunk-TCDJY3H6.js} +9 -10
- package/dist/chunk-TCDJY3H6.js.map +1 -0
- package/dist/{chunk-DZ7VLLDQ.cjs → chunk-TP5UMRAU.cjs} +66 -39
- package/dist/chunk-TP5UMRAU.cjs.map +1 -0
- package/dist/{chunk-HYOUMTPW.js → chunk-TS7J6DTY.js} +3 -3
- package/dist/{chunk-HYOUMTPW.js.map → chunk-TS7J6DTY.js.map} +1 -1
- package/dist/{chunk-OJGTJOWI.cjs → chunk-TUVENMXB.cjs} +2 -2
- package/dist/chunk-TUVENMXB.cjs.map +1 -0
- package/dist/{chunk-WZ2TBXVB.cjs → chunk-V6BA44DS.cjs} +18 -18
- package/dist/{chunk-WZ2TBXVB.cjs.map → chunk-V6BA44DS.cjs.map} +1 -1
- package/dist/{chunk-2OP5YHRR.js → chunk-XO5R73Y4.js} +120 -10
- package/dist/chunk-XO5R73Y4.js.map +1 -0
- package/dist/{chunk-QAZO3ANW.cjs → chunk-YY4PFR3Z.cjs} +34 -35
- package/dist/chunk-YY4PFR3Z.cjs.map +1 -0
- package/dist/{chunk-RX3A6KIY.js → chunk-ZPI6Q42R.js} +2 -2
- package/dist/chunk-ZPI6Q42R.js.map +1 -0
- package/dist/components/ActivityPreview.cjs +16 -18
- package/dist/components/ActivityPreview.d.cts +2 -2
- package/dist/components/ActivityPreview.d.ts +2 -2
- package/dist/components/ActivityPreview.js +15 -17
- package/dist/components/ActivitySequence.cjs +17 -19
- package/dist/components/ActivitySequence.d.cts +2 -2
- package/dist/components/ActivitySequence.d.ts +2 -2
- package/dist/components/ActivitySequence.js +16 -18
- package/dist/components/Dictation.cjs +9 -11
- package/dist/components/Dictation.d.cts +1 -1
- package/dist/components/Dictation.d.ts +1 -1
- package/dist/components/Dictation.js +8 -10
- package/dist/components/FillInTheBlanks.cjs +9 -11
- package/dist/components/FillInTheBlanks.d.cts +1 -1
- package/dist/components/FillInTheBlanks.d.ts +1 -1
- package/dist/components/FillInTheBlanks.js +8 -10
- package/dist/components/GapSelect.cjs +9 -11
- package/dist/components/GapSelect.d.cts +1 -1
- package/dist/components/GapSelect.d.ts +1 -1
- package/dist/components/GapSelect.js +8 -10
- package/dist/components/InteractiveVideo.cjs +16 -18
- package/dist/components/InteractiveVideo.d.cts +2 -2
- package/dist/components/InteractiveVideo.d.ts +2 -2
- package/dist/components/InteractiveVideo.js +14 -16
- package/dist/components/MultipleChoice.cjs +9 -11
- package/dist/components/MultipleChoice.d.cts +1 -1
- package/dist/components/MultipleChoice.d.ts +1 -1
- package/dist/components/MultipleChoice.js +8 -10
- package/dist/components/PronunciationFeedback.cjs +6 -5
- package/dist/components/PronunciationFeedback.d.cts +28 -7
- package/dist/components/PronunciationFeedback.d.ts +28 -7
- package/dist/components/PronunciationFeedback.js +5 -4
- package/dist/components/ReadAloud.cjs +9 -9
- package/dist/components/ReadAloud.d.cts +2 -2
- package/dist/components/ReadAloud.d.ts +2 -2
- package/dist/components/ReadAloud.js +8 -8
- package/dist/components/StimulusPanel.cjs +4 -4
- package/dist/components/StimulusPanel.d.cts +1 -1
- package/dist/components/StimulusPanel.d.ts +1 -1
- package/dist/components/StimulusPanel.js +3 -3
- package/dist/components/WrittenResponse.cjs +8 -10
- package/dist/components/WrittenResponse.d.cts +3 -3
- package/dist/components/WrittenResponse.d.ts +3 -3
- package/dist/components/WrittenResponse.js +7 -9
- package/dist/i18n/LkIntlProvider.cjs +7 -7
- package/dist/i18n/LkIntlProvider.d.cts +2 -2
- package/dist/i18n/LkIntlProvider.d.ts +2 -2
- package/dist/i18n/LkIntlProvider.js +1 -1
- package/dist/index.cjs +58 -56
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +18 -20
- package/dist/index.js.map +1 -1
- package/dist/theme/skin.css +46 -1
- package/dist/{types-CrtIcRcK.d.ts → types-C4IsUQsK.d.ts} +16 -0
- package/dist/{types-CO0XLEN6.d.cts → types-CJgZWtl4.d.cts} +16 -0
- package/package.json +3 -3
- package/dist/chunk-2OP5YHRR.js.map +0 -1
- package/dist/chunk-4MXECBZT.js.map +0 -1
- package/dist/chunk-54DX6SLS.cjs +0 -42
- package/dist/chunk-54DX6SLS.cjs.map +0 -1
- package/dist/chunk-6GQLCCGN.js.map +0 -1
- package/dist/chunk-6RIM5EQP.cjs.map +0 -1
- package/dist/chunk-7F2YQWMW.cjs.map +0 -1
- package/dist/chunk-B7JU52YQ.cjs.map +0 -1
- package/dist/chunk-C4PSJ3ZC.js.map +0 -1
- package/dist/chunk-CXIP7ERK.js.map +0 -1
- package/dist/chunk-DPNCCWOV.js.map +0 -1
- package/dist/chunk-DXFCYNST.js +0 -35
- package/dist/chunk-DXFCYNST.js.map +0 -1
- package/dist/chunk-DZ7VLLDQ.cjs.map +0 -1
- package/dist/chunk-ERV666AR.js.map +0 -1
- package/dist/chunk-IYGF7PZY.cjs.map +0 -1
- package/dist/chunk-J2QIHZ3H.cjs +0 -27
- package/dist/chunk-J2QIHZ3H.cjs.map +0 -1
- package/dist/chunk-JMEZYYCE.js.map +0 -1
- package/dist/chunk-KI6DJ5ZF.js.map +0 -1
- package/dist/chunk-MXZHL4U5.cjs.map +0 -1
- package/dist/chunk-NFGUJ52G.cjs.map +0 -1
- package/dist/chunk-O7MINPKZ.js.map +0 -1
- package/dist/chunk-OJGTJOWI.cjs.map +0 -1
- package/dist/chunk-PGAPZ6UE.cjs.map +0 -1
- package/dist/chunk-QAZO3ANW.cjs.map +0 -1
- package/dist/chunk-RX3A6KIY.js.map +0 -1
- package/dist/chunk-SHDSOOBF.cjs.map +0 -1
- package/dist/chunk-SPSKDNEE.js.map +0 -1
- package/dist/chunk-U4KTOH7C.js +0 -22
- package/dist/chunk-U4KTOH7C.js.map +0 -1
- package/dist/chunk-U5VFJVQ2.js.map +0 -1
- package/dist/chunk-VPU6UY4O.cjs.map +0 -1
- package/dist/chunk-W6UMY7PF.cjs.map +0 -1
- package/dist/chunk-XS6OYYVR.cjs.map +0 -1
- package/dist/chunk-XYJBRKBZ.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/FillInTheBlanks/FillInTheBlanks.tsx","../src/components/FillInTheBlanks/index.tsx"],"names":["detailIsRight","useLkStrings","useLearnerAi","useDeliveryPolicy","useItemScoringPolicy","useMemo","isDevelopment","assertRedacted","result","validateActivity","ActivitySchemaError","useActivityState","useTries","useState","useRef","hintsOf","useEffect","useComponentAiHints","score","computePassThreshold","xAPIBuilder","ANONYMOUS_ACTOR","objectIdFor","xapiDefinitionFor","stampTake","mintTake","triesSummary","jsxs","jsx","ActivityMedia","Fragment","HintCost","AiHints","FeedbackRegion","outcomeShowsMarks","TryActions","AiExplanation","FillInTheBlanks","ActivityErrorBoundary"],"mappings":";;;;;;;;;;;;;;AAmDA,IAAM,WAAA,GAAc,0BAAA;AAIpB,SAAS,aAAa,OAAA,EAA4B;AAChD,EAAA,MAAM,WAAsB,EAAC;AAC7B,EAAA,MAAM,EAAA,GAAK,IAAI,MAAA,CAAO,WAAW,CAAA;AACjC,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,IAAI,OAAA,GAAU,CAAA;AACd,EAAA,IAAI,KAAA,GAAQ,EAAA,CAAG,IAAA,CAAK,OAAO,CAAA;AAC3B,EAAA,OAAO,UAAU,IAAA,EAAM;AACrB,IAAA,IAAI,KAAA,CAAM,QAAQ,IAAA,EAAM;AACtB,MAAA,QAAA,CAAS,IAAA,CAAK,EAAE,IAAA,EAAM,MAAA,EAAQ,KAAA,EAAO,OAAA,CAAQ,KAAA,CAAM,IAAA,EAAM,KAAA,CAAM,KAAK,CAAA,EAAG,CAAA;AAAA,IACzE;AACA,IAAA,OAAA,IAAW,CAAA;AACX,IAAA,QAAA,CAAS,IAAA,CAAK,EAAE,IAAA,EAAM,OAAA,EAAS,IAAI,KAAA,CAAM,CAAC,CAAA,EAAa,OAAA,EAAS,CAAA;AAChE,IAAA,IAAA,GAAO,KAAA,CAAM,KAAA,GAAQ,KAAA,CAAM,CAAC,CAAA,CAAE,MAAA;AAC9B,IAAA,KAAA,GAAQ,EAAA,CAAG,KAAK,OAAO,CAAA;AAAA,EACzB;AACA,EAAA,IAAI,IAAA,GAAO,QAAQ,MAAA,EAAQ;AACzB,IAAA,QAAA,CAAS,IAAA,CAAK,EAAE,IAAA,EAAM,MAAA,EAAQ,OAAO,OAAA,CAAQ,KAAA,CAAM,IAAI,CAAA,EAAG,CAAA;AAAA,EAC5D;AACA,EAAA,OAAO,QAAA;AACT;AAGA,IAAM,aAAqC,EAAC;AAQ5C,SAAS,UAAU,QAAA,EAA+D;AAChF,EAAA,OAAO,aAAa,MAAA,IAAa,QAAA,CAAS,IAAA,KAAS,oBAAA,GAC/C,SAAS,OAAA,GACT,UAAA;AACN;AAOA,SAAS,kBAAkB,OAAA,EAAyD;AAClF,EAAA,MAAM,GAAA,uBAAU,GAAA,EAAqB;AACrC,EAAA,KAAA,MAAW,UAAU,OAAA,EAAS;AAC5B,IAAA,GAAA,CAAI,GAAA,CAAI,MAAA,CAAO,MAAA,EAAQA,+BAAA,CAAc,MAAM,CAAC,CAAA;AAAA,EAC9C;AACA,EAAA,OAAO,GAAA;AACT;AAEO,SAAS,eAAA,CAAgB;AAAA,EAC9B,IAAA;AAAA,EACA,UAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA,aAAA;AAAA,EACA,KAAA;AAAA,EACA,YAAA;AAAA,EACA,gBAAA;AAAA,EACA,UAAA,GAAa,UAAA;AAAA,EACb,OAAA;AAAA,EACA,YAAA;AAAA,EACA,WAAA;AAAA,EACA,YAAA;AAAA,EACA,OAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA,QAAA;AAAA,EACA,kBAAA;AAAA,EACA,EAAA,EAAI,MAAA;AAAA,EACJ,QAAA;AAAA,EACA;AACF,CAAA,EAAyB;AACvB,EAAA,MAAM,SAAS,UAAA,KAAe,MAAA;AAC9B,EAAA,MAAM,WAAW,UAAA,KAAe,QAAA;AAIhC,EAAA,MAAM,CAAA,GAAIC,+BAAa,OAAO,CAAA;AAC9B,EAAA,MAAM,EAAA,GAAKC,+BAAa,MAAM,CAAA;AAC9B,EAAA,MAAM,MAAA,GAASC,oCAAkB,QAAQ,CAAA;AACzC,EAAA,MAAM,aAAA,GAAgBC,uCAAqB,OAAO,CAAA;AAElD,EAAA,MAAM,QAAA,GAAWC,cAAQ,MAAM;AAC7B,IAAA,IAAI,CAACC,iCAAc,EAAG;AACpB,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,IAAI,IAAA,CAAK,aAAa,IAAA,EAAM;AAI1B,MAAA,IAAI;AACF,QAAAC,qBAAA,CAAe,IAAI,CAAA;AACnB,QAAA,OAAO,IAAA;AAAA,MACT,SAAS,KAAA,EAAO;AACd,QAAA,OAAO,iBAAiB,KAAA,GAAQ,KAAA,GAAQ,IAAI,KAAA,CAAM,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,MACjE;AAAA,IACF;AACA,IAAA,MAAMC,OAAAA,GAASC,uBAAA,CAAiB,oBAAA,EAAsB,IAAI,CAAA;AAC1D,IAAA,OAAOD,QAAO,OAAA,GAAU,IAAA,GAAO,IAAIE,0BAAA,CAAoB,oBAAA,EAAsBF,QAAO,MAAM,CAAA;AAAA,EAC5F,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAET,EAAA,MAAM,EAAE,KAAA,EAAO,KAAA,EAAO,QAAA,EAAU,YAAA,EAAc,OAAM,GAAIG,kCAAA;AAAA,IACtD,gBAAA,KAAqB,OAAO,WAAA,GAAc;AAAA,GAC5C;AAEA,EAAA,MAAM,QAAQC,0BAAA,CAAS;AAAA,IACrB,MAAA,EAAQ,aAAA;AAAA,IACR,MAAA,EAAQ,UAAA,KAAe,UAAA,IAAc,MAAA,CAAO,QAAA;AAAA,IAC5C,WAAW,KAAA,KAAU,WAAA;AAAA,IACrB,UAAU,QAAA,KAAa;AAAA,GACxB,CAAA;AACD,EAAA,MAAM,aAAa,KAAA,CAAM,KAAA;AAIzB,EAAA,MAAM,eAAe,KAAA,KAAU,MAAA;AAC/B,EAAA,MAAM,CAAC,eAAA,EAAiB,kBAAkB,CAAA,GAAIC,cAAA;AAAA,IAAiC,MAC7E,UAAU,YAAY;AAAA,GACxB;AACA,EAAA,MAAM,CAAC,UAAU,WAAW,CAAA,GAAIA,eAAsB,sBAAM,IAAI,KAAK,CAAA;AAGrE,EAAA,MAAM,CAAC,MAAM,OAAO,CAAA,GAAIA,eAA8B,sBAAM,IAAI,KAAK,CAAA;AACrE,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAIA,eAA+B,IAAI,CAAA;AAC/D,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,eAAwB,IAAI,CAAA;AAC1D,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,eAAwB,IAAI,CAAA;AAC1D,EAAA,MAAM,CAAC,cAAA,EAAgB,iBAAiB,CAAA,GAAIA,eAAS,KAAK,CAAA;AAG1D,EAAA,MAAM,YAAA,GAAeC,YAAA,CAAOC,yBAAA,CAAQ,KAAA,IAAS,YAAY,CAAC,CAAA;AAC1D,EAAA,MAAM,OAAA,GAAUD,aAAwB,IAAI,CAAA;AAC5C,EAAA,MAAM,WAAA,GAAcA,aAAuB,IAAI,CAAA;AAC/C,EAAA,MAAM,aAAA,GAAgBA,aAAqC,IAAI,CAAA;AAE/D,EAAA,MAAM,OAAA,GAAU,YAAA,GAAe,SAAA,CAAU,KAAK,CAAA,GAAI,eAAA;AAMlD,EAAA,MAAM,eAAA,GAAkBA,aAAO,YAAY,CAAA;AAC3C,EAAAE,eAAA,CAAU,MAAM;AACd,IAAA,eAAA,CAAgB,OAAA,GAAU,YAAA;AAAA,EAC5B,CAAA,EAAG,CAAC,YAAY,CAAC,CAAA;AAMjB,EAAA,MAAM,mBAAA,GAAsBF,aAAO,gBAAgB,CAAA;AACnD,EAAAE,eAAA,CAAU,MAAM;AACd,IAAA,mBAAA,CAAoB,OAAA,GAAU,gBAAA;AAAA,EAChC,CAAA,EAAG,CAAC,gBAAgB,CAAC,CAAA;AAQrB,EAAA,MAAM,WAAA,GAAcF,aAAO,IAAI,CAAA;AAG/B,EAAAE,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,WAAA,CAAY,YAAY,IAAA,EAAM;AAChC,MAAA;AAAA,IACF;AACA,IAAA,WAAA,CAAY,OAAA,GAAU,IAAA;AACtB,IAAA,kBAAA,CAAmB,SAAA,CAAU,eAAA,CAAgB,OAAO,CAAC,CAAA;AACrD,IAAA,WAAA,iBAAY,IAAI,KAAK,CAAA;AACrB,IAAA,OAAA,iBAAQ,IAAI,KAAK,CAAA;AACjB,IAAA,SAAA,CAAU,IAAI,CAAA;AACd,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,iBAAA,CAAkB,KAAK,CAAA;AACvB,IAAA,YAAA,CAAa,OAAA,GAAUD,yBAAA,CAAQ,eAAA,CAAgB,OAAO,CAAA;AACtD,IAAA,UAAA,EAAW;AACX,IAAA,KAAA,CAAM,mBAAA,CAAoB,OAAA,KAAY,IAAA,GAAO,WAAA,GAAc,MAAM,CAAA;AAAA,EACnE,CAAA,EAAG,CAAC,IAAA,EAAM,KAAA,EAAO,UAAU,CAAC,CAAA;AAiC5B,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,IAAIV,iCAAc,IAAK,YAAA,KAAiB,MAAA,IAAa,IAAA,CAAK,gBAAgB,MAAA,EAAW;AACnF,MAAA,OAAA,CAAQ,IAAA;AAAA,QACN;AAAA,OAGF;AAAA,IACF;AAAA,EACF,CAAA,EAAG,CAAC,YAAA,EAAc,IAAA,CAAK,WAAW,CAAC,CAAA;AAEnC,EAAA,MAAM,QAAA,GAAWD,aAAA,CAAQ,MAAM,YAAA,CAAa,IAAA,CAAK,OAAO,CAAA,EAAG,CAAC,IAAA,CAAK,OAAO,CAAC,CAAA;AACzE,EAAA,MAAM,SAAA,GAAYA,cAAQ,MAAM,IAAI,IAAI,IAAA,CAAK,MAAA,CAAO,IAAI,CAAC,CAAA,KAAM,CAAC,CAAA,CAAE,EAAA,EAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAA,CAAK,MAAM,CAAC,CAAA;AAGzF,EAAA,MAAM,WAAW,KAAA,KAAU,WAAA;AAC3B,EAAA,MAAM,UAAUY,qCAAA,CAAoB;AAAA,IAClC,EAAA;AAAA,IACA,IAAA;AAAA,IACA,UAAA;AAAA,IACA,SAAA,EAAW,QAAA;AAAA,IACX,UAAU,QAAA,KAAa,IAAA;AAAA,IACvB,QAAA,EAAU,EAAE,IAAA,EAAM,oBAAA,EAAsB,OAAA,EAAQ;AAAA,IAChD,MAAA;AAAA,IACA,aAAA;AAAA,IACA,OAAA,EAAS,CAAA;AAAA,IACT,QAAA,EAAU;AAAA,GACX,CAAA;AAID,EAAA,MAAM,aAAA,GACJ,eAAe,UAAA,GAAa,YAAA,CAAa,UAAU,IAAA,CAAK,IAAA,GAAO,QAAQ,IAAA,GAAO,CAAA;AAChF,EAAA,MAAM,UAAA,GAAa,CACjB,IAAA,EACA,KAAA,GAAgB,aAAA,MACoB;AAAA,IACpC,IAAA,EAAM,oBAAA;AAAA,IACN,OAAA,EAAS,IAAA;AAAA,IACT,GAAI,KAAA,GAAQ,CAAA,GAAI,EAAE,aAAA,EAAe,KAAA,KAAU;AAAC,GAC9C,CAAA;AAEA,EAAA,MAAM,SAAA,GAAYH,YAAA,CAAO,OAAA,CAAQ,IAAI,CAAA;AAErC,EAAAE,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,SAAA,CAAU,OAAA,KAAY,OAAA,CAAQ,IAAA,EAAM;AACtC,MAAA;AAAA,IACF;AACA,IAAA,SAAA,CAAU,UAAU,OAAA,CAAQ,IAAA;AAC5B,IAAA,IAAI,OAAA,CAAQ,OAAO,CAAA,EAAG;AACpB,MAAA,QAAA,GAAW,UAAA,CAAW,OAAO,CAAC,CAAA;AAAA,IAChC;AAAA,EACF,CAAA,EAAG,CAAC,OAAA,CAAQ,IAAI,CAAC,CAAA;AACjB,EAAAA,eAAA,CAAU,MAAM;AACd,IAAA,MAAM,SAAS,aAAA,CAAc,OAAA;AAC7B,IAAA,IAAI,WAAW,IAAA,EAAM;AACnB,MAAA;AAAA,IACF;AACA,IAAA,aAAA,CAAc,OAAA,GAAU,IAAA;AACxB,IAAA,IAAI,WAAW,QAAA,EAAU;AACvB,MAAA,OAAA,CAAQ,OAAA,EAAS,aAAA,CAA2B,sBAAsB,CAAA,EAAG,KAAA,EAAM;AAAA,IAC7E,CAAA,MAAO;AACL,MAAA,WAAA,CAAY,SAAS,KAAA,EAAM;AAAA,IAC7B;AAAA,EACF,CAAC,CAAA;AAED,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,MAAM,QAAA;AAAA,EACR;AASA,EAAA,IAAI,IAAA,CAAK,QAAA,KAAa,IAAA,IAAQ,UAAA,KAAe,UAAA,EAAY;AACvD,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,oBAAA,EAAuB,KAAK,EAAE,CAAA,oNAAA;AAAA,KAGhC;AAAA,EACF;AAEA,EAAA,MAAM,YAAY,KAAA,KAAU,WAAA;AAC5B,EAAA,MAAM,QAAA,GAAW,QAAA,KAAa,IAAA,IAAQ,SAAA,IAAa,QAAA;AASnD,EAAA,MAAM,YAAY,QAAA,GAAW,OAAA,EAAS,MAAA,KAAW,QAAA,GAAW,CAAC,MAAA,IAAU,SAAA;AAIvE,EAAA,MAAM,OAAA,GAAU,aAAa,MAAA,CAAO,QAAA;AAEpC,EAAA,MAAM,iBAAiB,OAAA,IAAW,MAAA,CAAO,aAAa,kBAAA,KAAuB,IAAA,IAAQ,CAAC,KAAA,CAAM,IAAA;AAE5F,EAAA,MAAM,eAAA,GAAkB,CACtB,IAAA,EACA,OAAA,KACS;AACT,IAAA,aAAA,GAAgB,EAAE,IAAA,EAAM,UAAA,EAAY,IAAA,CAAK,EAAA,EAAI,WAAW,IAAA,CAAK,GAAA,EAAI,EAAG,OAAA,EAAS,CAAA;AAAA,EAC/E,CAAA;AAEA,EAAA,MAAM,YAAA,GAAe,CAAC,OAAA,EAAiB,IAAA,KAAuB;AAC5D,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA;AAAA,IACF;AACA,IAAA,IAAI,UAAU,MAAA,EAAQ;AACpB,MAAA,KAAA,EAAM;AAAA,IACR;AACA,IAAA,MAAM,OAAO,EAAE,GAAG,SAAS,CAAC,OAAO,GAAG,IAAA,EAAK;AAC3C,IAAA,IAAI,CAAC,YAAA,EAAc;AACjB,MAAA,kBAAA,CAAmB,IAAI,CAAA;AAAA,IACzB;AACA,IAAA,QAAA,GAAW,UAAA,CAAW,IAAI,CAAC,CAAA;AAC3B,IAAA,eAAA,CAAgB,cAAA,EAAgB,EAAE,OAAA,EAAS,KAAA,EAAO,MAAM,CAAA;AAAA,EAC1D,CAAA;AAEA,EAAA,MAAM,UAAA,GAAa,CAAC,OAAA,KAA0B;AAC5C,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA;AAAA,IACF;AACA,IAAA,IAAI,UAAU,MAAA,EAAQ;AACpB,MAAA,KAAA,EAAM;AAAA,IACR;AACA,IAAA,WAAA,CAAY,CAAC,IAAA,KAAS;AACpB,MAAA,MAAM,IAAA,GAAO,IAAI,GAAA,CAAI,IAAI,CAAA;AACzB,MAAA,IAAI,IAAA,CAAK,GAAA,CAAI,OAAO,CAAA,EAAG;AACrB,QAAA,IAAA,CAAK,OAAO,OAAO,CAAA;AACnB,QAAA,OAAO,IAAA;AAAA,MACT;AACA,MAAA,IAAA,CAAK,IAAI,OAAO,CAAA;AAChB,MAAA,OAAO,IAAA;AAAA,IACT,CAAC,CAAA;AAED,IAAA,IAAI,CAAC,QAAA,CAAS,GAAA,CAAI,OAAO,CAAA,EAAG;AAC1B,MAAA,eAAA,CAAgB,gBAAA,EAAkB,EAAE,OAAA,EAAS,CAAA;AAAA,IAC/C;AAEA,IAAA,IAAI,CAAC,IAAA,CAAK,GAAA,CAAI,OAAO,CAAA,EAAG;AACtB,MAAA,OAAA,CAAQ,CAAC,SAAS,IAAI,GAAA,CAAI,IAAI,CAAA,CAAE,GAAA,CAAI,OAAO,CAAC,CAAA;AAC5C,MAAA,IAAI,eAAe,UAAA,EAAY;AAC7B,QAAA,QAAA,GAAW,UAAA,CAAW,OAAA,EAAS,aAAA,GAAgB,CAAC,CAAC,CAAA;AAAA,MACnD;AAAA,IACF;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,YAAA,GAAe,CAAC,KAAA,KAAiC;AACrD,IAAA,KAAA,CAAM,cAAA,EAAe;AACrB,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA;AAAA,IACF;AACA,IAAA,MAAM,QAAA,GAAW,WAAW,OAAO,CAAA;AAGnC,IAAA,QAAA,GAAW,QAAQ,CAAA;AAEnB,IAAA,IAAI,MAAA,EAAQ;AAKV,MAAA,QAAA,EAAS;AACT,MAAA,UAAA,CAAW,EAAE,eAAe,CAAA;AAC5B,MAAA,eAAA,CAAgB,WAAA,EAAa,EAAE,OAAA,EAAS,CAAA;AACxC,MAAA;AAAA,IACF;AAIA,IAAA,MAAM,MAAA,GAASE,YAAA,CAAM,oBAAA,EAAsB,IAAA,EAA6B,QAAQ,CAAA;AAChF,IAAA,QAAA,EAAS;AACT,IAAA,MAAM,YAAY,YAAA,EAAa;AAE/B,IAAA,MAAM,OAAA,GAAU,MAAM,MAAA,CAAO;AAAA,MAC3B,OAAO,MAAA,CAAO,KAAA;AAAA,MACd,UAAU,MAAA,CAAO,QAAA;AAAA,MACjB;AAAA,KACD,CAAA;AACD,IAAA,MAAM,OAAO,OAAA,CAAQ,KAAA,CAAM,OAAA,CAAQ,KAAA,CAAM,SAAS,CAAC,CAAA;AACnD,IAAA,MAAM,MAAA,GAAS,IAAA,KAAS,MAAA,GAAY,MAAA,CAAO,QAAQ,IAAA,CAAK,MAAA;AACxD,IAAA,MAAM,aAAA,GACJ,MAAA,KAAW,MAAA,CAAO,KAAA,GACd,MAAA,GACA;AAAA,MACE,GAAG,MAAA;AAAA,MACH,KAAA,EAAO,MAAA;AAAA,MACP,MAAA,EAAQC,2BAAA,CAAqB,IAAA,EAA6B,MAAM;AAAA,KAClE;AACN,IAAA,MAAM,MAAA,GACJ,OAAA,CAAQ,KAAA,KAAU,aAAA,CAAc,KAAA,GAC5B,cAAc,MAAA,GACdA,2BAAA,CAAqB,IAAA,EAA6B,OAAA,CAAQ,KAAK,CAAA;AACrE,IAAA,MAAM,aAAA,GAAgBC,mBAAY,sBAAA,CAAuB;AAAA,MACvD,KAAA,EAAOC,iCAAA;AAAA,MACP,MAAA,EAAQ;AAAA,QACN,EAAA,EAAIC,6BAAA,CAAY,IAAA,CAAK,EAAE,CAAA;AAAA,QACvB,IAAA,EAAM,EAAE,CAAC,IAAA,CAAK,UAAU,OAAO,GAAG,KAAK,KAAA,EAAM;AAAA,QAC7C,GAAGC,yBAAkB,IAAI;AAAA,OAC3B;AAAA,MACA,aAAA;AAAA,MACA,WAAA,EAAa,SAAA;AAAA,MACb,QAAA,EAAU,IAAA,CAAK,SAAA,CAAU,OAAO;AAAA,KACjC,CAAA;AACD,IAAA,SAAA,CAAU,MAAM,CAAA;AAChB,IAAA,UAAA;AAAA,MACEC,2BAAA;AAAA,QACE,EAAE,OAAO,OAAA,CAAQ,KAAA,EAAO,UAAU,OAAA,CAAQ,QAAA,EAAU,MAAA,EAAQ,SAAA,EAAW,aAAA,EAAc;AAAA,QACrFC,0BAAA;AAAS;AACX,KACF;AAEA,IAAA,UAAA,CAAW,OAAO,QAAQ,CAAA;AAC1B,IAAA,UAAA;AAAA,MACE,CAAA,EAAG,CAAA,CAAE,eAAe,CAAA,CAAA,EAAI,CAAA,CAAE,iBAAA,CAAkB,IAAA,CAAK,KAAA,CAAM,OAAA,CAAQ,KAAA,GAAQ,GAAG,CAAA,EAAG,MAAM,CAAC,CAAA;AAAA,KACtF;AACA,IAAA,eAAA,CAAgB,aAAa,EAAE,OAAA,EAAS,KAAA,EAAO,aAAA,CAAc,OAAO,CAAA;AAAA,EACtE,CAAA;AAGA,EAAA,MAAM,QAAQ,MAAY;AACxB,IAAA,KAAA,CAAM,MAAM,CAAA;AACZ,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,aAAA,CAAc,OAAA,GAAU,QAAA;AAAA,EAC1B,CAAA;AAGA,EAAA,MAAM,aAAa,MAAY;AAC7B,IAAA,KAAA,CAAM,KAAA,EAAM;AACZ,IAAA,aAAA,CAAc,OAAA,GAAU,UAAA;AAAA,EAC1B,CAAA;AAEA,EAAA,MAAM,cAAA,GAAiBpB,cAAQ,MAAM;AACnC,IAAA,IAAI,MAAA,EAAQ;AAEV,MAAA,2BAAW,GAAA,EAAqB;AAAA,IAClC;AACA,IAAA,IAAI,QAAA,EAAU;AAGZ,MAAA,OAAO,OAAA,EAAS,WAAW,QAAA,GACvB,iBAAA,CAAkB,QAAQ,OAAO,CAAA,uBAC7B,GAAA,EAAqB;AAAA,IAC/B;AACA,IAAA,OAAO,iBAAA,CAAkB,MAAA,EAAQ,OAAA,IAAW,EAAE,CAAA;AAAA,EAChD,GAAG,CAAC,MAAA,EAAQ,QAAA,EAAU,OAAA,EAAS,MAAM,CAAC,CAAA;AAGtC,EAAA,MAAM,aAAA,GAAgBA,cAAQ,MAAM;AAClC,IAAA,IAAI,CAAC,QAAA,IAAY,OAAA,KAAY,MAAA,EAAW;AACtC,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,IAAI,OAAA,CAAQ,WAAW,QAAA,EAAU;AAC/B,MAAA,OAAO,GAAG,CAAA,CAAE,iBAAA,CAAkB,KAAK,KAAA,CAAM,OAAA,CAAQ,QAAQ,GAAG,CAAA,EAAG,QAAQ,MAAM,CAAC,GAC5E,OAAA,CAAQ,QAAA,GAAW,IAAI,OAAA,CAAQ,QAAQ,KAAK,EAC9C,CAAA,CAAA;AAAA,IACF;AACA,IAAA,IAAI,OAAA,CAAQ,WAAW,UAAA,EAAY;AACjC,MAAA,OAAO,CAAA,CAAE,YAAA;AAAA,IACX;AAKA,IAAA,IAAI,OAAA,CAAQ,WAAW,QAAA,EAAU;AAC/B,MAAA,MAAM,UACJ,OAAA,CAAQ,QAAA,GAAW,CAAA,GACf,IAAA,CAAK,MAAO,OAAA,CAAQ,KAAA,GAAQ,OAAA,CAAQ,QAAA,GAAY,GAAG,CAAA,GACnD,IAAA,CAAK,KAAA,CAAM,OAAA,CAAQ,QAAQ,GAAG,CAAA;AACpC,MAAA,OAAO,CAAA,EAAG,CAAA,CAAE,iBAAA,CAAkB,OAAA,EAAS,QAAQ,MAAM,CAAC,CAAA,EACpD,OAAA,CAAQ,QAAA,GAAW,CAAA,CAAA,EAAI,OAAA,CAAQ,QAAQ,KAAK,EAC9C,CAAA,CAAA;AAAA,IACF;AACA,IAAA,OAAO,CAAA,CAAE,gBAAA;AAAA,EACX,CAAA,EAAG,CAAC,QAAA,EAAU,OAAA,EAAS,CAAC,CAAC,CAAA;AAEzB,EAAA,MAAM,QACJ,CAAC,QAAA,IAAY,MAAA,CAAO,QAAA,IAAY,aAAa,KAAA,CAAM,OAAA,KAAY,IAAA,GAC3DqB,8BAAA,CAAa,GAAG,aAAA,EAAe,KAAA,CAAM,OAAA,EAAS,KAAA,CAAM,IAAI,CAAA,GACxD,EAAA;AACN,EAAA,MAAM,YACJ,OAAA,KAAY,IAAA,GACR,IAAA,GACA,CAAA,EAAG,OAAO,CAAA,EAAG,KAAA,GAAQ,CAAA,CAAA,EAAI,KAAK,KAAK,EAAE,CAAA,EAAG,UAAU,CAAA,CAAA,EAAI,OAAO,KAAK,EAAE,CAAA,CAAA;AAC1E,EAAA,MAAM,YAAA,GACJ,UAAA,KAAe,UAAA,IACf,CAAC,cACA,OAAA,CAAQ,OAAA,IAAY,MAAA,CAAO,KAAA,IAAS,KAAK,MAAA,CAAO,IAAA,CAAK,CAAC,KAAA,KAAU,MAAM,IAAI,CAAA,CAAA;AAE7E,EAAA,uBACEC,eAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,GAAA,EAAK,OAAA;AAAA,MACL,SAAA,EAAU,QAAA;AAAA,MACV,cAAY,IAAA,CAAK,KAAA;AAAA,MACjB,IAAA,EAAM,MAAA;AAAA,MACN,kBAAA,EAAkB,UAAA;AAAA,MAClB,KAAA,EAAO,KAAA;AAAA,MACP,QAAA,EAAU,YAAA;AAAA,MAET,QAAA,EAAA;AAAA,QAAA,IAAA,CAAK,KAAA,mBACJC,cAAA;AAAA,UAACC,+BAAA;AAAA,UAAA;AAAA,YACC,OAAO,IAAA,CAAK,KAAA;AAAA,YACZ,UAAA;AAAA,YACC,GAAI,WAAA,KAAgB,MAAA,GAAY,EAAE,WAAA,KAAgB,EAAC;AAAA,YACnD,GAAI,YAAA,KAAiB,MAAA,GAAY,EAAE,YAAA,KAAiB,EAAC;AAAA,YACrD,GAAI,OAAA,KAAY,MAAA,GAAY,EAAE,OAAA,KAAY,EAAC;AAAA,YAC3C,GAAI,aAAA,KAAkB,MAAA,GAAY,EAAE,aAAA,KAAkB,EAAC;AAAA,YACvD,GAAI,MAAA,KAAW,MAAA,GAAY,EAAE,MAAA,KAAW;AAAC;AAAA,SAC5C,GACE,IAAA;AAAA,wBACJF,eAAA,CAAC,UAAA,EAAA,EAAS,QAAA,EAAU,QAAA,EAClB,QAAA,EAAA;AAAA,0BAAAC,cAAA,CAAC,OAAE,SAAA,EAAU,gBAAA,EACV,mBAAS,GAAA,CAAI,CAAC,KAAK,CAAA,KAAM;AACxB,YAAA,IAAI,GAAA,CAAI,SAAS,MAAA,EAAQ;AAEvB,cAAA,sCAAQ,MAAA,EAAA,EAAoB,QAAA,EAAA,GAAA,CAAI,KAAA,EAAA,EAAd,CAAA,CAAA,EAAI,CAAC,CAAA,CAAe,CAAA;AAAA,YACxC;AACA,YAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,GAAA,CAAI,GAAA,CAAI,EAAE,CAAA;AAClC,YAAA,IAAI,CAAC,KAAA,EAAO;AACV,cAAA,OAAO,IAAA;AAAA,YACT;AAKA,YAAA,MAAM,eAAA,GAAwC,MAAA,GAC1C,MAAA,GACA,KAAA,CAAM,eAAA;AACV,YAAA,MAAM,aAAA,GAAgB,MAAA,GAAS,MAAA,GAAY,KAAA,CAAM,QAAA;AACjD,YAAA,MAAM,WAAA,GAAc,cAAA,CAAe,GAAA,CAAI,GAAA,CAAI,EAAE,CAAA;AAC7C,YAAA,MAAM,SAAS,CAAA,EAAG,IAAA,CAAK,EAAE,CAAA,MAAA,EAAS,IAAI,EAAE,CAAA,CAAA;AAGxC,YAAA,MAAM,IAAA,GAAO,MAAA,CAAO,KAAA,GAAQ,KAAA,CAAM,IAAA,GAAO,MAAA;AACzC,YAAA,MAAM,aAAA,GAAgB,kBAAkB,CAAC,CAAA;AACzC,YAAA,IAAI,cAAA,IAAkB,WAAA,KAAgB,KAAA,IAAS,aAAA,EAAe;AAC5D,cAAA,uBACEA,cAAA,CAAC,UAAkB,SAAA,EAAU,eAAA,EAAgB,gBAAa,OAAA,EACvD,QAAA,EAAA,aAAA,EAAA,EADQ,IAAI,EAEf,CAAA;AAAA,YAEJ;AACA,YAAA,uBACED,eAAA,CAAC,MAAA,EAAA,EAAkB,SAAA,EAAU,cAAA,EAC3B,QAAA,EAAA;AAAA,8BAAAC,cAAA;AAAA,gBAAC,OAAA;AAAA,gBAAA;AAAA,kBACC,IAAA,EAAK,MAAA;AAAA,kBACL,YAAA,EAAY,CAAA,CAAE,UAAA,CAAW,GAAA,CAAI,OAAO,CAAA;AAAA,kBACpC,kBAAA,EAAkB,OAAO,MAAA,GAAS,MAAA;AAAA,kBAClC,KAAA,EAAO,OAAA,CAAQ,GAAA,CAAI,EAAE,CAAA,IAAK,EAAA;AAAA,kBAC1B,QAAA,EAAU,QAAA;AAAA,kBACV,iBAAe,QAAA,IAAY,MAAA;AAAA,kBAC3B,gBACE,OAAA,IAAW,WAAA,KAAgB,MAAA,GAAY,MAAA,CAAO,WAAW,CAAA,GAAI,MAAA;AAAA,kBAE/D,QAAA,EAAU,CAAC,CAAA,KAAM,YAAA,CAAa,IAAI,EAAA,EAAI,CAAA,CAAE,OAAO,KAAK;AAAA;AAAA,eACtD;AAAA,cAMC,uBACCD,eAAA,CAAAG,mBAAA,EAAA,EAME,QAAA,EAAA;AAAA,gCAAAF,cAAA;AAAA,kBAAC,QAAA;AAAA,kBAAA;AAAA,oBACC,IAAA,EAAK,QAAA;AAAA,oBACL,SAAA,EAAU,iBAAA;AAAA,oBACV,eAAA,EAAe,MAAA;AAAA,oBACf,eAAA,EAAe,QAAA,CAAS,GAAA,CAAI,GAAA,CAAI,EAAE,CAAA;AAAA,oBAClC,YAAA,EAAY,SAAS,GAAA,CAAI,GAAA,CAAI,EAAE,CAAA,GAAI,CAAA,CAAE,WAAW,CAAA,CAAE,QAAA;AAAA,oBAClD,QAAA,EAAU,QAAA;AAAA,oBACV,OAAA,EAAS,MAAM,UAAA,CAAW,GAAA,CAAI,EAAE,CAAA;AAAA,oBAEhC,QAAA,kBAAAA,cAAA;AAAA,sBAAC,KAAA;AAAA,sBAAA;AAAA,wBACC,SAAA,EAAU,kBAAA;AAAA,wBACV,OAAA,EAAQ,WAAA;AAAA,wBACR,KAAA,EAAM,IAAA;AAAA,wBACN,MAAA,EAAO,IAAA;AAAA,wBACP,aAAA,EAAY,MAAA;AAAA,wBACZ,SAAA,EAAU,OAAA;AAAA,wBAEV,QAAA,kBAAAA,cAAA;AAAA,0BAAC,MAAA;AAAA,0BAAA;AAAA,4BACC,IAAA,EAAK,cAAA;AAAA,4BACL,CAAA,EAAE;AAAA;AAAA;AACJ;AAAA;AACF;AAAA,iBACF;AAAA,gCASAA,cAAA,CAAC,MAAA,EAAA,EAAK,EAAA,EAAI,MAAA,EAAQ,WAAA,EAAU,QAAA,EACzB,QAAA,EAAA,QAAA,CAAS,GAAA,CAAI,GAAA,CAAI,EAAE,CAAA,GAAI,IAAA,GAAO,EAAA,EACjC;AAAA,eAAA,EACF,CAAA,GACE,IAAA;AAAA,cACH,OAAA,IAAW,CAAC,cAAA,IAAkB,aAAA,mBAC7BA,cAAA;AAAA,gBAAC,MAAA;AAAA,gBAAA;AAAA,kBACC,SAAA,EAAU,uBAAA;AAAA,kBACV,IAAA,EAAK,MAAA;AAAA,kBACL,cAAA,EAAc,WAAA,KAAgB,MAAA,GAAY,MAAA,CAAO,WAAW,CAAA,GAAI,MAAA;AAAA,kBAE/D,QAAA,EAAA;AAAA;AAAA,eACH,GACE;AAAA,aAAA,EAAA,EArEK,IAAI,EAsEf,CAAA;AAAA,UAEJ,CAAC,CAAA,EACH,CAAA;AAAA,UACC,+BAAeA,cAAA,CAACG,0BAAA,EAAA,EAAS,QAAQ,aAAA,EAAe,OAAA,EAAS,GAAG,CAAA,GAAK,IAAA;AAAA,yCACjEC,yBAAA,EAAA,EAAQ,IAAA,EAAM,OAAA,EAAS,EAAA,EAAQ,SAAS,CAAA,EAAG,CAAA;AAAA,UAE3C,QAAA,GAAW,IAAA,mBACVJ,cAAA,CAAC,QAAA,EAAA,EAAO,IAAA,EAAK,QAAA,EAAS,QAAA,EAAU,QAAA,EAC7B,QAAA,EAAA,MAAA,GAAS,CAAA,CAAE,aAAA,GAAgB,CAAA,CAAE,YAAA,EAChC;AAAA,SAAA,EAEJ,CAAA;AAAA,QACC,OAAA,IAAW,KAAK,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,QAAQ,CAAA,mBAC5CA,cAAA;AAAA,UAAC,QAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,QAAA;AAAA,YACL,SAAA,EAAU,wBAAA;AAAA,YACV,iBAAe,CAAC,cAAA;AAAA,YAChB,SAAS,MAAM,iBAAA,CAAkB,CAAC,CAAA,KAAM,CAAC,CAAC,CAAA;AAAA,YAEzC,QAAA,EAAA,cAAA,GAAiB,CAAA,CAAE,YAAA,GAAe,CAAA,CAAE;AAAA;AAAA,SACvC,GACE,IAAA;AAAA,wBACJA,cAAA;AAAA,UAACK,gCAAA;AAAA,UAAA;AAAA,YACC,EAAA,EAAI,CAAA,EAAG,IAAA,CAAK,EAAE,CAAA,SAAA,CAAA;AAAA,YACb,GAAI,cAAc,OAAA,GAAU,CAAA,GAAI,EAAE,GAAA,EAAK,WAAA,KAAgB,EAAC;AAAA,YAExD,QAAA,EAAA,QAAA,GACG,MAAA,CAAO,QAAA,IAAY,CAACC,oCAAkB,OAAO,CAAA,GAC3C,aAAA,GACA,IAAA,GACF,MAAA,CAAO,QAAA,IAAY,OAAA,KAAY,IAAA,GAC7B,YACA,CAAA,CAAE;AAAA;AAAA,SACV;AAAA,wBACAN,cAAA;AAAA,UAACO,4BAAA;AAAA,UAAA;AAAA,YACC,KAAA;AAAA,YACA,SAAA,EAAW,MAAA,CAAO,SAAA,IAAa,kBAAA,KAAuB,IAAA;AAAA,YACtD,OAAA,EAAS,CAAA;AAAA,YACT,OAAA,EAAS,KAAA;AAAA,YACT,OAAA,EAAS;AAAA;AAAA,SACX;AAAA,wBACAP,cAAA;AAAA,UAACQ,+BAAA;AAAA,UAAA;AAAA,YACC,EAAA;AAAA,YACA,IAAA;AAAA,YACA,UAAA;AAAA,YACA,SAAA;AAAA,YACA,QAAA,EAAU,EAAE,IAAA,EAAM,oBAAA,EAAsB,OAAA,EAAQ;AAAA,YAChD,OAAA;AAAA,YACA,MAAA;AAAA,YACA,aAAA;AAAA,YACA,OAAA,EAAS,CAAA;AAAA,YAGT,QAAA,EAAU,MAAM,IAAA,GAAO,EAAE,GAAG,MAAA,EAAQ,SAAA,EAAW,OAAM,GAAI;AAAA;AAAA;AAC3D;AAAA;AAAA,GACF;AAEJ;ACxtBO,SAASC,iBAAgB,KAAA,EAA6B;AAG3D,EAAA,MAAM,OAAA,GAAUpC,8BAAA,CAAa,KAAA,CAAM,OAAO,CAAA;AAC1C,EAAA,uBACE2B,cAAAA,CAACU,uCAAA,EAAA,EAAsB,aAAA,EAAe,KAAA,CAAM,IAAA,EAAM,KAAA,EAAO,OAAA,EACvD,QAAA,kBAAAV,cAAAA,CAAC,eAAA,EAAA,EAAqB,GAAG,OAAO,CAAA,EAClC,CAAA;AAEJ","file":"chunk-DS6HN3YR.cjs","sourcesContent":["'use client';\n\nimport {\n ActivitySchemaError,\n assertRedacted,\n computePassThreshold,\n type FillInTheBlanksData,\n type FillInTheBlanksLearnerResponse,\n type LearnerResponse,\n type ScoringDetail,\n type ScoringResult,\n score,\n validateActivity,\n xAPIBuilder,\n xapiDefinitionFor,\n} from '@intellectif/lk-core';\nimport { type CSSProperties, useEffect, useMemo, useRef, useState } from 'react';\nimport { useLearnerAi } from '../../ai/LkAiProvider.js';\nimport { useActivityState } from '../../hooks/useActivityState.js';\nimport { useLkStrings } from '../../i18n/LkIntlProvider.js';\nimport { ANONYMOUS_ACTOR, detailIsRight, isDevelopment, objectIdFor } from '../_internal.js';\nimport { ActivityMedia } from '../shared/ActivityMedia.js';\nimport { AiExplanation, AiHints, useComponentAiHints } from '../shared/AiHelp.js';\nimport { outcomeShowsMarks, useDeliveryPolicy } from '../shared/delivery.js';\nimport { FeedbackRegion } from '../shared/FeedbackRegion.js';\nimport { mintTake, stampTake } from '../shared/sequence-slot.js';\nimport {\n HintCost,\n hintsOf,\n TryActions,\n triesSummary,\n useItemScoringPolicy,\n useTries,\n} from '../shared/tries.js';\nimport type { ActivityProps } from '../types.js';\n\nexport interface FillInTheBlanksProps extends ActivityProps<FillInTheBlanksData> {\n /**\n * After submission, replace each incorrectly-answered blank with its first\n * accepted answer, styled distinctly (Req 5.7). Component-specific prop: it\n * is presentation, not activity data, and is outside the fixed Req-3.1 set.\n *\n * Ignored in `exam` mode — revealing the key is precisely what an exam must\n * not do, and on a `redact()` projection there is no key to reveal. In\n * `review` mode it applies only to blanks the supplied `outcome` marks\n * incorrect, and only when the caller passed data that still carries the key\n * (e.g. `redact(data, { reveal: 'after-submit' })`).\n */\n showCorrectAnswers?: boolean;\n}\n\nconst PLACEHOLDER = /\\{\\{\\s*([^{}]+?)\\s*\\}\\}/g;\n\ntype Segment = { kind: 'text'; value: string } | { kind: 'blank'; id: string; ordinal: number };\n\nfunction parsePassage(passage: string): Segment[] {\n const segments: Segment[] = [];\n const re = new RegExp(PLACEHOLDER);\n let last = 0;\n let ordinal = 0;\n let match = re.exec(passage);\n while (match !== null) {\n if (match.index > last) {\n segments.push({ kind: 'text', value: passage.slice(last, match.index) });\n }\n ordinal += 1;\n segments.push({ kind: 'blank', id: match[1] as string, ordinal });\n last = match.index + match[0].length;\n match = re.exec(passage);\n }\n if (last < passage.length) {\n segments.push({ kind: 'text', value: passage.slice(last) });\n }\n return segments;\n}\n\n/** Shared empty map: keeps the \"no response supplied\" path allocation-free. */\nconst NO_ANSWERS: Record<string, string> = {};\n\n/**\n * Reads the answer map out of a `LearnerResponse`. A response of another\n * activity type is treated as \"no answers\" rather than throwing: a controlled\n * host that has not yet swapped its state on an activity change would\n * otherwise crash the attempt.\n */\nfunction answersOf(response: LearnerResponse | undefined): Record<string, string> {\n return response !== undefined && response.type === 'fill-in-the-blanks'\n ? response.answers\n : NO_ANSWERS;\n}\n\n/**\n * Per-item correctness keyed by blank id, from each detail's `outcome` — or,\n * on a grade stored before lk-core 0.3, its `correct` flag, so it still marks\n * in `review`.\n */\nfunction correctnessByItem(details: readonly ScoringDetail[]): Map<string, boolean> {\n const map = new Map<string, boolean>();\n for (const detail of details) {\n map.set(detail.itemId, detailIsRight(detail));\n }\n return map;\n}\n\nexport function FillInTheBlanks({\n data,\n onComplete,\n onSubmit,\n onChange,\n onInteraction,\n value,\n defaultValue,\n defaultSubmitted,\n renderMode = 'practice',\n outcome,\n sanitizeHtml,\n mediaBudget,\n mediaStrings,\n strings,\n theme,\n locale,\n disabled,\n showCorrectAnswers,\n ai: aiProp,\n delivery,\n scoring,\n}: FillInTheBlanksProps) {\n const isExam = renderMode === 'exam';\n const isReview = renderMode === 'review';\n\n // Dev-only boundary validation (Req 2.3); throws in render so the wrapping\n // ActivityErrorBoundary catches it. Re-runs only when data changes.\n const s = useLkStrings(strings);\n const ai = useLearnerAi(aiProp);\n const policy = useDeliveryPolicy(delivery);\n const scoringPolicy = useItemScoringPolicy(scoring);\n\n const devError = useMemo(() => {\n if (!isDevelopment()) {\n return null;\n }\n if (data.redacted === true) {\n // A redact() projection cannot satisfy the full content schema — the\n // answer key is gone by design. Validate it against the STRICT redacted\n // schema instead, which additionally proves the payload is learner-safe.\n try {\n assertRedacted(data);\n return null;\n } catch (error) {\n return error instanceof Error ? error : new Error(String(error));\n }\n }\n const result = validateActivity('fill-in-the-blanks', data);\n return result.success ? null : new ActivitySchemaError('fill-in-the-blanks', result.errors);\n }, [data]);\n\n const { state, start, complete, getTimeSpent, reset } = useActivityState(\n defaultSubmitted === true ? 'completed' : 'idle',\n );\n // Before anything that resets them: a new question starts with no tries.\n const tries = useTries({\n policy: scoringPolicy,\n graded: renderMode === 'practice' && policy.feedback,\n submitted: state === 'completed',\n disabled: disabled === true,\n });\n const resetTries = tries.reset;\n // Controlled when `value` is supplied: the answers rendered are ALWAYS the\n // caller's, and internal state is never read. Uncontrolled otherwise,\n // seeded from `defaultValue`.\n const isControlled = value !== undefined;\n const [internalAnswers, setInternalAnswers] = useState<Record<string, string>>(() =>\n answersOf(defaultValue),\n );\n const [revealed, setRevealed] = useState<Set<string>>(() => new Set());\n // Every blank whose hint has been shown on this mount, hidden again or not:\n // hiding a hint does not unsee it.\n const [seen, setSeen] = useState<ReadonlySet<string>>(() => new Set());\n const [result, setResult] = useState<ScoringResult | null>(null);\n const [summary, setSummary] = useState<string | null>(null);\n const [overall, setOverall] = useState<string | null>(null);\n const [feedbackHidden, setFeedbackHidden] = useState(false);\n // Hints the learner had been shown before this mount: a restored answer's\n // count stands, and the hints shown here add to it.\n const seedHintsRef = useRef(hintsOf(value ?? defaultValue));\n const formRef = useRef<HTMLFormElement>(null);\n const feedbackRef = useRef<HTMLDivElement>(null);\n const focusAfterRef = useRef<'answer' | 'feedback' | null>(null);\n\n const answers = isControlled ? answersOf(value) : internalAnswers;\n\n // `defaultValue` is read only by the reset effect, and it is commonly an\n // inline object literal — putting it in that effect's deps would re-seed\n // (and wipe) the learner's typing on every render. Mirror it into a ref in\n // its own effect, which commits before the reset effect below.\n const defaultValueRef = useRef(defaultValue);\n useEffect(() => {\n defaultValueRef.current = defaultValue;\n }, [defaultValue]);\n\n // Mirror `defaultSubmitted` so the reset below returns to the SEEDED state.\n // Resetting unconditionally to idle unlocked an item the learner had already\n // committed — which made `defaultSubmitted` a no-op here, since this effect\n // runs right after the first paint.\n const defaultSubmittedRef = useRef(defaultSubmitted);\n useEffect(() => {\n defaultSubmittedRef.current = defaultSubmitted;\n }, [defaultSubmitted]);\n\n // Identity guard so the MOUNT run is a no-op. Without it this effect fires\n // after the first paint and undoes every seed it was just given; with it,\n // only a real `data` change resets. A parent that rebuilds structurally\n // identical entries in render (`activities={raw.map(redact)}`) must not\n // unlock or revert a restored answer — the pager already remounts a slot\n // whose activity actually changed, via its key.\n const lastDataRef = useRef(data);\n // `data` is an intentional reset trigger (Req 3.7); it is already in the\n // dependency list. The identity guard below skips the mount run.\n useEffect(() => {\n if (lastDataRef.current === data) {\n return;\n }\n lastDataRef.current = data;\n setInternalAnswers(answersOf(defaultValueRef.current));\n setRevealed(new Set());\n setSeen(new Set());\n setResult(null);\n setSummary(null);\n setOverall(null);\n setFeedbackHidden(false);\n seedHintsRef.current = hintsOf(defaultValueRef.current);\n resetTries();\n reset(defaultSubmittedRef.current === true ? 'completed' : 'idle');\n }, [data, reset, resetTries]);\n\n /*\n * RICH TEXT — deliberate, documented limitation (see `sanitizeHtml`).\n *\n * Every other activity can render its `*Html` field through the caller's\n * sanitiser, because the rich text is a LEAF: the sanitised string is\n * handed to one `dangerouslySetInnerHTML` node and nothing is inserted into\n * it. A fill-in-the-blanks passage is not a leaf — it is the CONTAINER of\n * the React-controlled `<input>`s, one per `{{id}}` placeholder.\n *\n * Placing those inputs inside sanitised HTML means slicing the sanitised\n * string at the placeholders and injecting each slice as its own HTML\n * fragment, which is unsafe and broken on both counts:\n * 1. Broken: the slices are unbalanced. `<p>A {{x}} B</p>` yields `<p>A `\n * and ` B</p>`; the fragment parser auto-closes both, so the input\n * lands OUTSIDE the paragraph and the authored block structure is\n * destroyed.\n * 2. Unsafe: the sanitiser's guarantee covers the document it returned,\n * not arbitrary substrings of it. A placeholder inside an attribute\n * (`<img alt=\"{{x}}\">`) splits mid-attribute, and re-parsing the\n * halves in a fresh context is exactly the mutation (mXSS) class of\n * transformation that voids a sanitiser's output guarantee. An exam\n * runner must never depend on that.\n *\n * The safe alternative — parse the sanitised string once into a detached\n * DOM, split only TEXT nodes at placeholders, and portal the inputs into\n * anchors — needs a DOM at render time (no SSR) and a large imperative\n * subsystem. Until that lands, the plain-text `passage` is rendered (always\n * escaped by React), which is correct, answerable, and safe in every mode.\n * `data.passageHtml` is carried and redacted by lk-core regardless, so no\n * authored content is lost — only this component declines to render it.\n */\n useEffect(() => {\n if (isDevelopment() && sanitizeHtml !== undefined && data.passageHtml !== undefined) {\n console.warn(\n '[lk-react] FillInTheBlanks ignores `passageHtml`: the passage hosts the answer inputs, ' +\n 'so rich HTML cannot be split at {{placeholders}} without voiding the sanitiser. ' +\n 'Rendering the plain `passage` instead.',\n );\n }\n }, [sanitizeHtml, data.passageHtml]);\n\n const segments = useMemo(() => parsePassage(data.passage), [data.passage]);\n const blankById = useMemo(() => new Map(data.blanks.map((b) => [b.id, b])), [data.blanks]);\n\n // Hints are a hook, so they are read here, before the throws below.\n const answered = state === 'completed';\n const aiHints = useComponentAiHints({\n ai,\n data,\n renderMode,\n submitted: answered,\n disabled: disabled === true,\n response: { type: 'fill-in-the-blanks', answers },\n locale,\n onInteraction,\n strings: s,\n delivery: policy,\n });\n // Every hint the learner has been shown on this question, counted from its\n // start: the author's, one per blank, and AI hints. What a scoring policy\n // charges for — in practice only: an exam's hints are free and uncounted.\n const hintsRevealed =\n renderMode === 'practice' ? seedHintsRef.current + seen.size + aiHints.used : 0;\n const responseOf = (\n next: Record<string, string>,\n hints: number = hintsRevealed,\n ): FillInTheBlanksLearnerResponse => ({\n type: 'fill-in-the-blanks',\n answers: next,\n ...(hints > 0 ? { hintsRevealed: hints } : {}),\n });\n // An AI hint shown is part of the answer's record: say so as it happens.\n const aiSeenRef = useRef(aiHints.used);\n // biome-ignore lint/correctness/useExhaustiveDependencies: a new hint is the trigger, and the response it reports is this render's\n useEffect(() => {\n if (aiSeenRef.current === aiHints.used) {\n return;\n }\n aiSeenRef.current = aiHints.used;\n if (aiHints.used > 0) {\n onChange?.(responseOf(answers));\n }\n }, [aiHints.used]);\n useEffect(() => {\n const target = focusAfterRef.current;\n if (target === null) {\n return;\n }\n focusAfterRef.current = null;\n if (target === 'answer') {\n formRef.current?.querySelector<HTMLElement>('input:not(:disabled)')?.focus();\n } else {\n feedbackRef.current?.focus();\n }\n });\n\n if (devError) {\n throw devError;\n }\n // Practice grades locally, which a redacted projection cannot support: the\n // submit handler below calls `score()`, which throws RedactedScoringError —\n // from an event handler, where no error boundary can catch it, AFTER the\n // learner has typed their answers. Fail loudly at render instead, in\n // production too. This mirrors the identical guard in MultipleChoice;\n // without it the two built-ins disagreed about the same accident, and\n // wiring an exam item into the self-grading mode is precisely what\n // `renderMode` exists to prevent.\n if (data.redacted === true && renderMode === 'practice') {\n throw new Error(\n `Fill-in-the-Blanks \"${data.id}\" received redacted activity data in renderMode \"practice\", ` +\n 'which grades locally and has no answer key to grade against. ' +\n 'Render redacted data with renderMode=\"exam\" (server grades) or \"review\" (pass `outcome`).',\n );\n }\n\n const submitted = state === 'completed';\n const inactive = disabled === true || submitted || isReview;\n\n /**\n * Whether the component may show answer-key-derived information (per-blank\n * correctness, authored feedback, correct answers). NEVER in `exam`; in\n * `practice` only after the component scored locally; in `review` only once\n * the caller supplies a SCORED outcome — an item that is still awaiting a\n * grade must not have its key revealed just because it is being read back.\n */\n const revealing = isReview ? outcome?.status === 'scored' : !isExam && submitted;\n // What the delivery policy lets that reveal show: right and wrong at all,\n // with the author's feedback, and the correct answers `showCorrectAnswers`\n // would write into a wrong blank.\n const marking = revealing && policy.feedback;\n // Not while the learner is offered another try: the next try is for finding them.\n const showingAnswers = marking && policy.solutions && showCorrectAnswers === true && !tries.open;\n\n const fireInteraction = (\n type: 'blank-filled' | 'hint-requested' | 'submitted',\n payload: Record<string, unknown>,\n ): void => {\n onInteraction?.({ type, activityId: data.id, timestamp: Date.now(), payload });\n };\n\n const handleChange = (blankId: string, text: string): void => {\n if (inactive) {\n return;\n }\n if (state === 'idle') {\n start();\n }\n const next = { ...answers, [blankId]: text };\n if (!isControlled) {\n setInternalAnswers(next);\n }\n onChange?.(responseOf(next));\n fireInteraction('blank-filled', { blankId, value: text });\n };\n\n const toggleHint = (blankId: string): void => {\n if (inactive) {\n return;\n }\n if (state === 'idle') {\n start();\n }\n setRevealed((prev) => {\n const next = new Set(prev);\n if (next.has(blankId)) {\n next.delete(blankId);\n return next;\n }\n next.add(blankId);\n return next;\n });\n // Only a reveal is a \"hint requested\"; hiding is not a new request.\n if (!revealed.has(blankId)) {\n fireInteraction('hint-requested', { blankId });\n }\n // The first time a blank's hint shows, the answer's record says so.\n if (!seen.has(blankId)) {\n setSeen((prev) => new Set(prev).add(blankId));\n if (renderMode === 'practice') {\n onChange?.(responseOf(answers, hintsRevealed + 1));\n }\n }\n };\n\n const handleSubmit = (event: React.FormEvent): void => {\n event.preventDefault();\n if (inactive) {\n return;\n }\n const response = responseOf(answers);\n // Fires in every submitting mode and always BEFORE onComplete, so an exam\n // runner can persist the raw response regardless of local grading.\n onSubmit?.(response);\n\n if (isExam) {\n // EXAM: the client neither grades nor reveals. No score()/evaluate(), no\n // read of any answer-key field, no onComplete — and no xAPI statement,\n // because its `correctResponsesPattern` IS the answer key. The server\n // owns the grade; it emits the statement.\n complete();\n setSummary(s.answerSubmitted);\n fireInteraction('submitted', { answers });\n return;\n }\n\n // PRACTICE: unchanged v1 behaviour. `data` carries the key here — exam\n // mode is the only path that may be handed a redact() projection.\n const answer = score('fill-in-the-blanks', data as FillInTheBlanksData, response);\n complete();\n const timeSpent = getTimeSpent();\n // The question's score under the policy — see MultipleChoice.\n const counted = tries.record({\n score: answer.score,\n maxScore: answer.maxScore,\n hintsRevealed,\n });\n const mine = counted.tries[counted.tries.length - 1];\n const costed = mine === undefined ? answer.score : mine.scored;\n const scoringResult =\n costed === answer.score\n ? answer\n : {\n ...answer,\n score: costed,\n passed: computePassThreshold(data as FillInTheBlanksData, costed),\n };\n const passed =\n counted.score === scoringResult.score\n ? scoringResult.passed\n : computePassThreshold(data as FillInTheBlanksData, counted.score);\n const xapiStatement = xAPIBuilder.buildAnsweredStatement({\n actor: ANONYMOUS_ACTOR,\n object: {\n id: objectIdFor(data.id),\n name: { [data.locale ?? 'en-US']: data.title },\n ...xapiDefinitionFor(data),\n },\n scoringResult,\n timeSpentMs: timeSpent,\n response: JSON.stringify(answers),\n });\n setResult(answer);\n onComplete?.(\n stampTake(\n { score: counted.score, maxScore: counted.maxScore, passed, timeSpent, xapiStatement },\n mintTake(),\n ),\n );\n // Core selects the authored overall feedback on `passed` (B3 fix): the answer's.\n setOverall(answer.feedback);\n setSummary(\n `${s.answerSubmitted} ${s.scoreAnnouncement(Math.round(counted.score * 100), passed)}`,\n );\n fireInteraction('submitted', { answers, score: scoringResult.score });\n };\n\n /** \"Try again\": the answers stay, to be changed; the marks go. */\n const retry = (): void => {\n reset('idle');\n setSummary(null);\n setOverall(null);\n focusAfterRef.current = 'answer';\n };\n\n /** \"Show answer\": no more tries; the question shows what a finished one shows. */\n const closeTries = (): void => {\n tries.close();\n focusAfterRef.current = 'feedback';\n };\n\n const correctByBlank = useMemo(() => {\n if (isExam) {\n // Nothing is ever marked client-side in an exam.\n return new Map<string, boolean>();\n }\n if (isReview) {\n // Correctness comes ONLY from the server-computed outcome; the component\n // never scores in review, so an absent/ungraded outcome marks nothing.\n return outcome?.status === 'scored'\n ? correctnessByItem(outcome.details)\n : new Map<string, boolean>();\n }\n return correctnessByItem(result?.details ?? []);\n }, [isExam, isReview, outcome, result]);\n\n /** Review has no local score: its summary is read off `outcome`, or nothing. */\n const reviewSummary = useMemo(() => {\n if (!isReview || outcome === undefined) {\n return null;\n }\n if (outcome.status === 'scored') {\n return `${s.scoreAnnouncement(Math.round(outcome.score * 100), outcome.passed)}${\n outcome.feedback ? ` ${outcome.feedback}` : ''\n }`;\n }\n if (outcome.status === 'deferred') {\n return s.notGradedYet;\n }\n // `graded` used to fall into the arm below and announce \"No grade\n // available.\" over a grade that had come back. Normalised by maxScore so a\n // grader payload of 8.5 / 10 does not read as 850% — same guard as\n // `<WrittenResponse>`.\n if (outcome.status === 'graded') {\n const percent =\n outcome.maxScore > 0\n ? Math.round((outcome.score / outcome.maxScore) * 100)\n : Math.round(outcome.score * 100);\n return `${s.scoreAnnouncement(percent, outcome.passed)}${\n outcome.feedback ? ` ${outcome.feedback}` : ''\n }`;\n }\n return s.noGradeAvailable;\n }, [isReview, outcome, s]);\n\n const extra =\n !isReview && policy.feedback && submitted && tries.counted !== null\n ? triesSummary(s, scoringPolicy, tries.counted, tries.open)\n : '';\n const announced =\n summary === null\n ? null\n : `${summary}${extra ? ` ${extra}` : ''}${overall ? ` ${overall}` : ''}`;\n const hintsOffered =\n renderMode === 'practice' &&\n !submitted &&\n (aiHints.offered || (policy.hints && data.blanks.some((blank) => blank.hint)));\n\n return (\n <form\n ref={formRef}\n className=\"lk-fib\"\n aria-label={data.title}\n lang={locale}\n data-render-mode={renderMode}\n style={theme as CSSProperties | undefined}\n onSubmit={handleSubmit}\n >\n {data.media ? (\n <ActivityMedia\n media={data.media}\n renderMode={renderMode}\n {...(mediaBudget !== undefined ? { mediaBudget } : {})}\n {...(mediaStrings !== undefined ? { mediaStrings } : {})}\n {...(strings !== undefined ? { strings } : {})}\n {...(onInteraction !== undefined ? { onInteraction } : {})}\n {...(locale !== undefined ? { locale } : {})}\n />\n ) : null}\n <fieldset disabled={inactive}>\n <p className=\"lk-fib-passage\">\n {segments.map((seg, i) => {\n if (seg.kind === 'text') {\n // biome-ignore lint/suspicious/noArrayIndexKey: passage segments are positional and static\n return <span key={`t${i}`}>{seg.value}</span>;\n }\n const blank = blankById.get(seg.id);\n if (!blank) {\n return null;\n }\n // `Renderable` only widens `scoringStrategy` at the type level, so\n // the answer-key fields still LOOK required here while a redact()\n // projection omits them at runtime. Read them defensively, and\n // never at all in exam mode.\n const acceptedAnswers: string[] | undefined = isExam\n ? undefined\n : blank.acceptedAnswers;\n const blankFeedback = isExam ? undefined : blank.feedback;\n const correctness = correctByBlank.get(seg.id);\n const hintId = `${data.id}-hint-${seg.id}`;\n // The author's hint, where the delivery policy offers hints. On in\n // every mode by default — including `exam`, where it is public.\n const hint = policy.hints ? blank.hint : undefined;\n const correctAnswer = acceptedAnswers?.[0];\n if (showingAnswers && correctness === false && correctAnswer) {\n return (\n <span key={seg.id} className=\"lk-fib-answer\" data-correct=\"false\">\n {correctAnswer}\n </span>\n );\n }\n return (\n <span key={seg.id} className=\"lk-fib-blank\">\n <input\n type=\"text\"\n aria-label={s.blankLabel(seg.ordinal)}\n aria-describedby={hint ? hintId : undefined}\n value={answers[seg.id] ?? ''}\n disabled={inactive}\n aria-disabled={inactive || undefined}\n data-correct={\n marking && correctness !== undefined ? String(correctness) : undefined\n }\n onChange={(e) => handleChange(seg.id, e.target.value)}\n />\n {/*\n Hints stay available in exam mode by design: lk-core's field\n policy classifies `blanks.hint` as `public`, so it survives\n redact() and is not part of the answer key.\n */}\n {hint ? (\n <>\n {/*\n Default affordance is an icon; the accessible NAME stays\n text via aria-label (screen readers + tests rely on it).\n The glyph is restylable/replaceable via .lk-fib-hint-btn.\n */}\n <button\n type=\"button\"\n className=\"lk-fib-hint-btn\"\n aria-controls={hintId}\n aria-expanded={revealed.has(seg.id)}\n aria-label={revealed.has(seg.id) ? s.hideHint : s.showHint}\n disabled={inactive}\n onClick={() => toggleHint(seg.id)}\n >\n <svg\n className=\"lk-fib-hint-icon\"\n viewBox=\"0 0 24 24\"\n width=\"16\"\n height=\"16\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <path\n fill=\"currentColor\"\n d=\"M9 21h6v-1H9v1Zm3-19a7 7 0 0 0-4 12.74V17h8v-2.26A7 7 0 0 0 12 2Z\"\n />\n </svg>\n </button>\n {/*\n Not role=\"tooltip\": a real ARIA tooltip is a named\n hover/focus popup with strict WCAG 1.4.13 constraints.\n This is an accessible click-to-toggle disclosure that is\n the input's aria-describedby target and is announced via\n aria-live; the skin gives it a tooltip-like *visual*\n without the tooltip *semantics*. (Refines Task 15.3.)\n */}\n <span id={hintId} aria-live=\"polite\">\n {revealed.has(seg.id) ? hint : ''}\n </span>\n </>\n ) : null}\n {marking && !feedbackHidden && blankFeedback ? (\n <span\n className=\"lk-fib-blank-feedback\"\n role=\"note\"\n data-correct={correctness !== undefined ? String(correctness) : undefined}\n >\n {blankFeedback}\n </span>\n ) : null}\n </span>\n );\n })}\n </p>\n {hintsOffered ? <HintCost policy={scoringPolicy} strings={s} /> : null}\n <AiHints help={aiHints} ai={ai} strings={s} />\n {/* Review is read-only: there is nothing to submit. */}\n {isReview ? null : (\n <button type=\"submit\" disabled={inactive}>\n {isExam ? s.submitAnswers : s.checkAnswers}\n </button>\n )}\n </fieldset>\n {marking && data.blanks.some((b) => b.feedback) ? (\n <button\n type=\"button\"\n className=\"lk-fib-feedback-toggle\"\n aria-expanded={!feedbackHidden}\n onClick={() => setFeedbackHidden((h) => !h)}\n >\n {feedbackHidden ? s.showFeedback : s.hideFeedback}\n </button>\n ) : null}\n <FeedbackRegion\n id={`${data.id}-feedback`}\n {...(scoringPolicy.retries > 0 ? { ref: feedbackRef } : {})}\n >\n {isReview\n ? policy.feedback || !outcomeShowsMarks(outcome)\n ? reviewSummary\n : null\n : policy.feedback || summary === null\n ? announced\n : s.answerSubmitted}\n </FeedbackRegion>\n <TryActions\n tries={tries}\n solutions={policy.solutions && showCorrectAnswers === true}\n strings={s}\n onRetry={retry}\n onClose={closeTries}\n />\n <AiExplanation\n ai={ai}\n data={data}\n renderMode={renderMode}\n submitted={submitted}\n response={{ type: 'fill-in-the-blanks', answers }}\n outcome={outcome}\n locale={locale}\n onInteraction={onInteraction}\n strings={s}\n // An explanation all but always names the answer: not while another\n // try is on offer.\n delivery={tries.open ? { ...policy, solutions: false } : policy}\n />\n </form>\n );\n}\n","'use client';\n\nimport { useLkStrings } from '../../i18n/LkIntlProvider.js';\nimport { ActivityErrorBoundary } from '../ActivityErrorBoundary.js';\nimport {\n FillInTheBlanks as FillInTheBlanksCore,\n type FillInTheBlanksProps,\n} from './FillInTheBlanks.js';\n\nexport type { FillInTheBlanksProps } from './FillInTheBlanks.js';\n\n/**\n * Public Fill-in-the-Blanks activity: the core wrapped in\n * `ActivityErrorBoundary` so a render failure (incl. the dev schema-validation\n * throw) degrades to an accessible fallback instead of crashing the host.\n */\nexport function FillInTheBlanks(props: FillInTheBlanksProps) {\n // Read here rather than in the boundary: a class component cannot call a\n // hook, and the fallback it renders is learner-facing text like any other.\n const strings = useLkStrings(props.strings);\n return (\n <ActivityErrorBoundary activityTitle={props.data?.title} strings={strings}>\n <FillInTheBlanksCore {...props} />\n </ActivityErrorBoundary>\n );\n}\n"]}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { useAiExplanation, useAiHints } from './chunk-
|
|
3
|
-
import { SequenceSlotContext } from './chunk-U4KTOH7C.js';
|
|
2
|
+
import { useAiExplanation, useAiHints, SequenceSlotContext } from './chunk-MXNC5UNO.js';
|
|
4
3
|
import { useRef, useEffect, useContext, useMemo, useState, useCallback } from 'react';
|
|
5
4
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
5
|
import { resolveItemScoringPolicy, scoreTries } from '@intellectif/lk-core';
|
|
@@ -237,5 +236,5 @@ function HintCost({
|
|
|
237
236
|
}
|
|
238
237
|
|
|
239
238
|
export { AiExplanation, AiHints, HintCost, TryActions, hintsOf, triesSummary, useComponentAiHints, useItemScoringPolicy, useTries };
|
|
240
|
-
//# sourceMappingURL=chunk-
|
|
241
|
-
//# sourceMappingURL=chunk-
|
|
239
|
+
//# sourceMappingURL=chunk-FDQR4GAZ.js.map
|
|
240
|
+
//# sourceMappingURL=chunk-FDQR4GAZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/shared/AiHelp.tsx","../src/components/shared/tries.tsx"],"names":["useRef","useEffect","jsxs","jsx"],"mappings":"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","file":"chunk-FDQR4GAZ.js","sourcesContent":["'use client';\n\nimport type {\n InteractionEvent,\n ItemOutcome,\n LearnerResponse,\n ResolvedDeliveryPolicy,\n} from '@intellectif/lk-core';\nimport { useEffect, useRef } from 'react';\nimport type { LearnerAi } from '../../ai/LkAiProvider.js';\nimport { type AiHintsHelp, useAiExplanation, useAiHints } from '../../ai/useAiHelp.js';\nimport type { LkStrings } from '../../i18n/strings.js';\nimport type { RenderableActivity, RenderMode } from '../types.js';\n\ninterface Situation {\n ai: LearnerAi | undefined;\n data: RenderableActivity;\n renderMode: RenderMode;\n submitted: boolean;\n /** The learner's answer as it stands: submitted, restored, or being written. */\n response: LearnerResponse;\n /** The component's `locale`, the default language for what is written. */\n locale: string | undefined;\n onInteraction: ((event: InteractionEvent) => void) | undefined;\n strings: LkStrings;\n /** The policy the component resolved, the paper's included. */\n delivery: ResolvedDeliveryPolicy;\n}\n\n/** What the hooks take, from what a component holds: the optional half, without `undefined` values. */\nfunction situation(input: Situation): {\n data: RenderableActivity;\n response: LearnerResponse;\n submitted: boolean;\n renderMode: RenderMode;\n ai?: LearnerAi;\n locale?: string;\n onInteraction?: (event: InteractionEvent) => void;\n delivery: ResolvedDeliveryPolicy;\n} {\n const { data, response, submitted, renderMode, ai, locale, onInteraction, delivery } = input;\n return {\n data,\n response,\n submitted,\n renderMode,\n delivery,\n ...(ai !== undefined ? { ai } : {}),\n ...(locale !== undefined ? { locale } : {}),\n ...(onInteraction !== undefined ? { onInteraction } : {}),\n };\n}\n\n/**\n * \"Explain my answer\": the SDK's own surface over {@link useAiExplanation} — a\n * button, the explanation with who wrote it, and \"not available\" when a call\n * fails or its answer is refused.\n *\n * Nothing renders without a port, or where the rules say no explanation.\n */\nexport function AiExplanation({\n outcome,\n ...rest\n}: Situation & { outcome: ItemOutcome | undefined }) {\n const s = rest.strings;\n const help = useAiExplanation({\n ...situation(rest),\n ...(outcome !== undefined ? { outcome } : {}),\n });\n const buttonRef = useRef<HTMLButtonElement>(null);\n const panelRef = useRef<HTMLElement>(null);\n const refocus = useRef(false);\n\n // The button that asked goes away when the explanation arrives; focus moves\n // to what it asked for rather than falling to the page.\n useEffect(() => {\n if (help.status === 'shown' && refocus.current) {\n refocus.current = false;\n panelRef.current?.focus();\n }\n if (help.status === 'unavailable') {\n refocus.current = false;\n }\n }, [help.status]);\n\n if (!help.offered) {\n return null;\n }\n\n const ask = (): void => {\n refocus.current =\n typeof document !== 'undefined' && document.activeElement === buttonRef.current;\n help.ask();\n };\n\n const loading = help.status === 'loading';\n return (\n <div className=\"lk-ai\" data-state={help.status}>\n {help.explanation === null ? (\n <button\n ref={buttonRef}\n type=\"button\"\n className=\"lk-ai-button\"\n aria-busy={loading || undefined}\n aria-disabled={loading || undefined}\n onClick={ask}\n >\n {loading ? s.aiExplaining : s.aiExplain}\n </button>\n ) : null}\n <div aria-live=\"polite\">\n {help.explanation !== null ? (\n <section\n ref={panelRef}\n className=\"lk-ai-panel\"\n tabIndex={-1}\n aria-label={s.aiExplanation}\n >\n <p className=\"lk-ai-heading\">{s.aiExplanation}</p>\n <p className=\"lk-ai-text\">{help.explanation.text}</p>\n <p className=\"lk-ai-notice\">{s.aiNotice}</p>\n </section>\n ) : help.status === 'unavailable' ? (\n <p className=\"lk-ai-unavailable\">{s.aiExplanationUnavailable}</p>\n ) : null}\n </div>\n </div>\n );\n}\n\n/**\n * The AI hints of one of the SDK's own questions: {@link useAiHints}, called\n * by the component itself so it can count the hints its learner was shown.\n */\nexport function useComponentAiHints({\n disabled,\n ...rest\n}: Situation & { disabled: boolean }): AiHintsHelp {\n return useAiHints({ ...situation(rest), disabled });\n}\n\n/**\n * \"Get a hint\": the SDK's own surface over {@link useAiHints} — a button, the\n * hints given so far as a numbered list, and who wrote them.\n *\n * The hints stay listed after submit, so the learner can see what they were\n * given, but no more can be asked for — until a \"Try again\" reopens the\n * answer, when the same list carries on. Another question starts with none.\n */\nexport function AiHints({\n help,\n ai,\n strings: s,\n}: {\n help: AiHintsHelp;\n ai: LearnerAi | undefined;\n strings: LkStrings;\n}) {\n const used = help.used;\n\n if (ai?.hint === undefined || (!help.offered && used === 0)) {\n return null;\n }\n\n const loading = help.status === 'loading';\n return (\n <div className=\"lk-ai lk-ai-hint-area\" data-state={help.status}>\n <div aria-live=\"polite\">\n {used > 0 ? (\n <ol className=\"lk-ai-hints\" aria-label={s.aiHints}>\n {help.hints.map((hint, index) => (\n // Hints are only ever appended, so a position is a stable key.\n // biome-ignore lint/suspicious/noArrayIndexKey: an append-only list\n <li key={index} className=\"lk-ai-hint\">\n <span className=\"lk-ai-hint-label\">{s.aiHintNumber(index + 1)}</span>{' '}\n <span className=\"lk-ai-text\">{hint.text}</span>\n </li>\n ))}\n </ol>\n ) : null}\n {help.status === 'unavailable' ? (\n <p className=\"lk-ai-unavailable\">{s.aiHintUnavailable}</p>\n ) : null}\n </div>\n {help.offered ? (\n used < help.limit ? (\n <button\n type=\"button\"\n className=\"lk-ai-button\"\n aria-busy={loading || undefined}\n aria-disabled={loading || undefined}\n onClick={help.ask}\n >\n {loading ? s.aiHintLoading : s.aiHint}\n </button>\n ) : (\n <p className=\"lk-ai-note\">{s.aiNoMoreHints}</p>\n )\n ) : null}\n {used > 0 ? <p className=\"lk-ai-notice\">{s.aiNotice}</p> : null}\n </div>\n );\n}\n","'use client';\n\nimport {\n type ItemScoringPolicy,\n type ItemTriesScore,\n type ItemTry,\n type ResolvedItemScoringPolicy,\n resolveItemScoringPolicy,\n scoreTries,\n} from '@intellectif/lk-core';\nimport { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';\nimport type { LkStrings } from '../../i18n/strings.js';\nimport { SequenceSlotContext, type TriesState } from './sequence-slot.js';\n\n/**\n * The scoring policy a question is under: the paper's, when the paper around\n * it was given one, else its own.\n *\n * Not combined, as delivery policies are: a cost and a count of tries have no\n * \"stricter\" to pick. The paper decides, as it decides the mode — so a\n * question drawn inside a set is scored by the set's rules whatever it was\n * handed.\n *\n * A policy `validateItemScoringPolicy` refuses throws here, at render. Every\n * setting in it moves a grade, and there is no safe way to read one wrongly:\n * the question fails loudly rather than grade by a guess.\n */\nexport function useItemScoringPolicy(\n given: ItemScoringPolicy | null | undefined,\n): ResolvedItemScoringPolicy {\n const around = useContext(SequenceSlotContext)?.scoring;\n const key = policyKey(given);\n // biome-ignore lint/correctness/useExhaustiveDependencies: the policy's content is the trigger, not its identity\n const own = useMemo(\n () => (around === undefined ? resolveItemScoringPolicy(given) : null),\n [around, key],\n );\n return around ?? (own as ResolvedItemScoringPolicy);\n}\n\nfunction policyKey(given: unknown): string {\n try {\n return JSON.stringify(given) ?? '';\n } catch {\n return String(given);\n }\n}\n\n/** A hint count as a response carries it: anything but a whole number above 0 is none. */\nexport function hintsOf(response: unknown): number {\n const count = (response as { hintsRevealed?: unknown } | null | undefined)?.hintsRevealed;\n return typeof count === 'number' && Number.isSafeInteger(count) && count > 0 ? count : 0;\n}\n\n/** Whether a try earned every mark there was: float noise above the maximum included. */\nconst fullMarks = (one: ItemTry): boolean => one.score / one.maxScore >= 1 - 1e-9;\n\n/** Whether, after the tries `made`, a question offers another: the rule `open` reads. */\nfunction offersAfter(\n now: {\n policy: ResolvedItemScoringPolicy;\n graded: boolean;\n disabled: boolean;\n channel: { triesClosed: boolean } | null;\n },\n made: readonly ItemTry[],\n shut: boolean,\n): boolean {\n const last = made[made.length - 1];\n return (\n now.graded &&\n !now.disabled &&\n !shut &&\n now.channel?.triesClosed !== true &&\n last !== undefined &&\n made.length < 1 + now.policy.retries &&\n !fullMarks(last)\n );\n}\n\nexport interface TriesInput {\n policy: ResolvedItemScoringPolicy;\n /**\n * Whether the component grades this answer itself and the learner may see\n * how it went: `practice`, with `feedback` on. \"Try again\" anywhere else\n * would be meaningless, or would say an answer was wrong on a paper that\n * does not say so.\n */\n graded: boolean;\n submitted: boolean;\n disabled: boolean;\n}\n\nexport interface Tries {\n /** Every graded try so far, in order. */\n tries: readonly ItemTry[];\n /** The question's score under the policy, once a try has been graded. */\n counted: ItemTriesScore | null;\n /**\n * Whether the learner is being offered another try at a graded answer: the\n * last try earned less than full marks, the policy has tries left, and\n * nothing has closed the question. While it is, the question shows no right\n * answer and no explanation — either would hand over the answer the next try\n * is for.\n */\n open: boolean;\n /** Tries still to come after the last graded one. */\n left: number;\n /** Records a graded try and returns the question's score under the policy. */\n record: (graded: ItemTry) => ItemTriesScore;\n /** Ends the question's tries: \"Show answer\". */\n close: () => void;\n /** Forgets every try: a different question. */\n reset: () => void;\n}\n\n/**\n * The tries a question has had and whether it offers another: the SDK's own\n * components' rules for \"Try again\", in one place.\n *\n * Reports whether a try is on offer to the paper around the question, which\n * waits for it before reporting the set while the question is on screen — and\n * closes every question's tries once it has reported.\n */\nexport function useTries({ policy, graded, submitted, disabled }: TriesInput): Tries {\n const channel = useContext(SequenceSlotContext);\n const [tries, setTries] = useState<readonly ItemTry[]>([]);\n const [closed, setClosed] = useState(false);\n // Written synchronously, so a submit that records a try and reports it reads\n // every try before it, whatever React has rendered.\n const triesRef = useRef<readonly ItemTry[]>([]);\n const closedRef = useRef(false);\n const latest = useRef({ policy, graded, disabled, channel });\n latest.current = { policy, graded, disabled, channel };\n\n const record = useCallback((one: ItemTry): ItemTriesScore => {\n const next = [...triesRef.current, one];\n triesRef.current = next;\n setTries(next);\n // An offer of another try is reported before the grade is handed on, not\n // after the next render: the paper reports its set when a grade fills its\n // last slot, and must already know to wait. The end of the tries is not:\n // said now, it would let the paper report the grade this try is replacing.\n // The effect below says it once this grade has landed.\n if (offersAfter(latest.current, next, closedRef.current)) {\n latest.current.channel?.triesState('offered');\n }\n return scoreTries(next, latest.current.policy);\n }, []);\n const close = useCallback(() => {\n closedRef.current = true;\n setClosed(true);\n }, []);\n const reset = useCallback(() => {\n triesRef.current = [];\n closedRef.current = false;\n setTries([]);\n setClosed(false);\n }, []);\n\n const allowed = 1 + policy.retries;\n const left = Math.max(0, allowed - tries.length);\n const open = submitted && offersAfter(latest.current, tries, closed);\n // A try the learner is making now — after \"Try again\", before the answer is\n // in again. Reporting the set then would hand on the grade the learner is in\n // the middle of replacing.\n const retrying =\n !submitted &&\n tries.length > 0 &&\n !closed &&\n graded &&\n !disabled &&\n channel?.triesClosed !== true;\n const state: TriesState = open ? 'offered' : retrying ? 'retrying' : 'none';\n\n const report = channel?.triesState;\n useEffect(() => {\n report?.(state);\n }, [report, state]);\n // A question that goes away offers nothing: the paper must not wait for it.\n useEffect(() => () => report?.('none'), [report]);\n\n const counted = useMemo(\n () => (tries.length === 0 ? null : scoreTries(tries, policy)),\n [tries, policy],\n );\n return { tries, counted, open, left, record, close, reset };\n}\n\n/** A fraction of the marks as the whole percentage a learner reads. */\nexport const percentOf = (fraction: number): number => Math.round(fraction * 100);\n\n/**\n * The sentences after the score, on a question whose policy changed it: which\n * try counts when it is not the one just made, what this answer scored before\n * its costs, and how many tries are left.\n */\nexport function triesSummary(\n s: LkStrings,\n policy: ResolvedItemScoringPolicy,\n counted: ItemTriesScore,\n offered: boolean,\n): string {\n const parts: string[] = [];\n const latest = counted.tries.length - 1;\n const mine = counted.tries[latest];\n if (mine !== undefined) {\n if (counted.counted !== latest) {\n parts.push(\n s.countedTry(\n policy.counts === 'best' ? 'best' : 'first',\n percentOf(mine.scored / mine.maxScore),\n ),\n );\n } else if (mine.scored !== mine.score) {\n parts.push(s.scoreBeforeCosts(percentOf(mine.score / mine.maxScore)));\n }\n }\n if (offered) {\n parts.push(\n s.triesLeft(policy.retries + 1 - counted.tries.length, percentOf(policy.retryPenalty)),\n );\n }\n return parts.join(' ');\n}\n\n/**\n * \"Try again\" and \"Show answer\" — or \"Keep this answer\", on a paper that shows\n * no right answers — after a graded try that did not earn full marks.\n */\nexport function TryActions({\n tries,\n solutions,\n strings: s,\n onRetry,\n onClose,\n}: {\n tries: Tries;\n /** Whether closing the question will show the right answer. */\n solutions: boolean;\n strings: LkStrings;\n onRetry: () => void;\n onClose: () => void;\n}): React.JSX.Element | null {\n if (!tries.open) {\n return null;\n }\n return (\n <div className=\"lk-tries\">\n <button type=\"button\" className=\"lk-tries-again\" onClick={onRetry}>\n {s.tryAgain}\n </button>\n <button type=\"button\" className=\"lk-tries-close\" onClick={onClose}>\n {solutions ? s.showAnswer : s.keepAnswer}\n </button>\n </div>\n );\n}\n\n/** What a hint costs, said before the learner asks for one. */\nexport function HintCost({\n policy,\n strings: s,\n}: {\n policy: ResolvedItemScoringPolicy;\n strings: LkStrings;\n}): React.JSX.Element | null {\n if (policy.hintPenalty <= 0) {\n return null;\n }\n return <p className=\"lk-hint-cost\">{s.hintCost(percentOf(policy.hintPenalty))}</p>;\n}\n"]}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { isDevelopment, ANONYMOUS_ACTOR, objectIdFor } from './chunk-DXFCYNST.js';
|
|
7
|
-
import { ActivityMedia } from './chunk-HYOUMTPW.js';
|
|
2
|
+
import { useDeliveryPolicy, FeedbackRegion, outcomeShowsMarks } from './chunk-ORT3KLGI.js';
|
|
3
|
+
import { ActivityErrorBoundary } from './chunk-7SB2MJA4.js';
|
|
4
|
+
import { isDevelopment, useAiWritingFeedback, ANONYMOUS_ACTOR, objectIdFor } from './chunk-MXNC5UNO.js';
|
|
5
|
+
import { ActivityMedia } from './chunk-TS7J6DTY.js';
|
|
8
6
|
import { useActivityState } from './chunk-6N43WDVG.js';
|
|
9
|
-
import { useLkStrings } from './chunk-
|
|
7
|
+
import { useLkStrings } from './chunk-HNLRVRQR.js';
|
|
8
|
+
import { useLearnerAi } from './chunk-ZPI6Q42R.js';
|
|
10
9
|
import { validateActivity, ActivitySchemaError, countWords, evaluate, xAPIBuilder } from '@intellectif/lk-core';
|
|
11
10
|
import { useMemo, useState, useRef, useEffect } from 'react';
|
|
12
11
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -391,5 +390,5 @@ function WrittenResponse2(props) {
|
|
|
391
390
|
}
|
|
392
391
|
|
|
393
392
|
export { WrittenResponse2 as WrittenResponse };
|
|
394
|
-
//# sourceMappingURL=chunk-
|
|
395
|
-
//# sourceMappingURL=chunk-
|
|
393
|
+
//# sourceMappingURL=chunk-FKGMSOJF.js.map
|
|
394
|
+
//# sourceMappingURL=chunk-FKGMSOJF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/WrittenResponse/WrittenResponse.tsx","../src/components/WrittenResponse/index.tsx"],"names":["WrittenResponse","jsx"],"mappings":"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","file":"chunk-FKGMSOJF.js","sourcesContent":["'use client';\n\nimport {\n ActivitySchemaError,\n type CriterionScore,\n countWords,\n type DeliveryPolicy,\n evaluate,\n type GradeRecord,\n type InlineCorrection,\n type InteractionEvent,\n type ItemOutcome,\n type LearnerResponse,\n type ThemeTokens,\n validateActivity,\n type WrittenResponseData,\n type XAPIStatement,\n xAPIBuilder,\n} from '@intellectif/lk-core';\nimport { type CSSProperties, useEffect, useMemo, useRef, useState } from 'react';\nimport { type LearnerAi, useLearnerAi } from '../../ai/LkAiProvider.js';\nimport { type AiWritingFeedbackHelp, useAiWritingFeedback } from '../../ai/useAiHelp.js';\nimport { useActivityState } from '../../hooks/useActivityState.js';\nimport { useLkStrings } from '../../i18n/LkIntlProvider.js';\nimport type { LkStrings, LkStringsOverride } from '../../i18n/strings.js';\nimport { ANONYMOUS_ACTOR, isDevelopment, objectIdFor } from '../_internal.js';\nimport { ActivityMedia } from '../shared/ActivityMedia.js';\nimport { outcomeShowsMarks, useDeliveryPolicy } from '../shared/delivery.js';\nimport { FeedbackRegion } from '../shared/FeedbackRegion.js';\nimport type {\n HtmlSanitizer,\n MediaBudgetBinding,\n MediaTransportStrings,\n Renderable,\n RenderMode,\n} from '../types.js';\n\n/**\n * Payload delivered when the learner submits a written response. Grading is\n * DEFERRED (asynchronous AI/human grading), so there is no score here — and\n * deliberately no fake one: an ungraded submission must never be shown or\n * stored as a 0. The consumer persists `text` and grades it out-of-band.\n */\nexport interface WrittenResponseSubmission {\n /** The submitted text, verbatim. */\n text: string;\n /** Word count of `text`, recomputed with the canonical `countWords()`. */\n wordCount: number;\n /** Whether `wordCount` falls within the activity's `[minWords, maxWords]`. */\n withinWordBounds: boolean;\n /** Time in milliseconds from first interaction to submission. */\n timeSpent: number;\n /** The SUBMITTED-verb xAPI statement built for this submission (no score fields). */\n xapiStatement: XAPIStatement;\n}\n\n/**\n * Props for {@link WrittenResponse}. Mirrors `ActivityProps` except for the\n * completion callback: a deferred-grading activity completes with a\n * {@link WrittenResponseSubmission} (`onSubmitted`), not a scored\n * `ActivityResult` (`onComplete`) — deviation from Req 22.8 recorded in the\n * roadmap (§3.1): fabricating a score of 0 for ungraded work is the exact\n * bug this type exists to fix. Everything else — controlled value, render\n * mode, server outcome, rich text — follows the shared `ActivityProps`\n * contract verbatim.\n */\nexport interface WrittenResponseProps {\n /** Activity content. Accepts a `redact()` projection in `exam` mode. */\n data: Renderable<WrittenResponseData>;\n /**\n * Called on submit with the ungraded submission (text, recomputed word\n * count, bounds flag, timing, xAPI statement). Fires in `practice` and\n * `exam` mode, after `onSubmit`; never in `review`.\n *\n * Optional since lk-react 2.1.0 so a `review`-mode render (which has no submit\n * control) and an exam runner that only wants the raw response through\n * `onSubmit` do not have to pass a no-op. Supply it in `practice`/`exam`\n * unless `onSubmit` already captures everything you persist.\n */\n onSubmitted?: (submission: WrittenResponseSubmission) => void;\n /**\n * Called on submit with the raw learner response and no grade, BEFORE\n * `onSubmitted`. This is the only submit callback an exam runner needs:\n * the server grades the text and returns an {@link ItemOutcome} later.\n */\n onSubmit?: (response: LearnerResponse) => void;\n /**\n * Controlled value: the learner's current response. When present the\n * textarea renders from it (never from internal state) and every keystroke\n * goes out through `onChange` — restore an in-progress attempt, autosave a\n * delta, or drive a review render with it.\n */\n value?: LearnerResponse;\n /** Initial response for an uncontrolled component (ignored when `value` is set). */\n defaultValue?: LearnerResponse;\n /**\n * Mount as already submitted — read at mount only. Without it a resumed\n * attempt reopens an essay the learner had already submitted as editable\n * and re-submittable.\n */\n defaultSubmitted?: boolean;\n /** Fires on every change to the learner's response. Required for a controlled component. */\n onChange?: (response: LearnerResponse) => void;\n /**\n * Presentation mode, default `practice`. `practice` and `exam` are nearly\n * identical here — a written response is never graded client-side, so\n * there is no local score to withhold; `exam` additionally never calls\n * `evaluate()` and renders happily from a `redact()` projection.\n * `review` is read-only and shows the server's `outcome`.\n */\n renderMode?: RenderMode;\n /**\n * Server-computed outcome, rendered by `review` mode: `deferred` shows a\n * \"not graded yet\" affordance, `scored` shows the returned grade and\n * feedback. Ignored in other modes — this component never manufactures an\n * outcome of its own.\n */\n outcome?: ItemOutcome;\n /** Renders `data.promptHtml` when provided. See `HtmlSanitizer`. */\n sanitizeHtml?: HtmlSanitizer;\n /** Binds this activity's own `data.media` to a play budget. See {@link MediaBudgetBinding}. */\n mediaBudget?: MediaBudgetBinding;\n /** Translations for the audio transport chrome. See {@link MediaTransportStrings}. */\n mediaStrings?: Partial<MediaTransportStrings>;\n /** Overrides the SDK's chrome text for this activity. See {@link LkIntlProvider}. */\n strings?: LkStringsOverride;\n onInteraction?: (event: InteractionEvent) => void;\n /** Per-instance token overrides, applied as inline CSS vars on the root. */\n theme?: Partial<ThemeTokens>;\n locale?: string;\n disabled?: boolean;\n /**\n * The delivery policy. An essay is graded later, so `feedback` reaches it —\n * `false` reads a returned grade back as nothing in `review` — and so does\n * AI feedback on a draft, which needs `feedback`, `solutions` and\n * `ai.explanations`. See `DeliveryPolicy` in lk-core.\n */\n delivery?: DeliveryPolicy | null;\n /**\n * The host's AI ports, overriding `LkAiProvider`'s. With a `writingFeedback`\n * port, a learner in `practice` can ask for feedback on a draft before\n * submitting it — up to `maxWritingFeedback` times — and revise. Every\n * correction in it quotes the learner's own words, or the SDK refuses it.\n * Never in `exam` or `review`. See {@link LearnerAi}.\n */\n ai?: LearnerAi;\n}\n\n/**\n * Reads the text out of a learner response. Another activity type's response\n * shape (the `value`/`defaultValue` props take the `LearnerResponse` union,\n * so a generic runner can hand any of them over) reads as empty rather than\n * throwing mid-exam.\n */\nfunction textOf(response: LearnerResponse | undefined): string {\n return response !== undefined && response.type === 'written-response' ? response.text : '';\n}\n\n/**\n * One criterion's score as a percentage of its OWN maximum.\n *\n * `CriterionScore.maxScore` defaults to 1 — the SDK's scaled convention — but\n * a grader may work out of 100, or out of 9 for a CEFR band, and\n * `gradeFromRubric` deliberately stores those judgements verbatim so a grade\n * stays auditable in the units the grader actually used. It normalises when it\n * computes the total; anything DISPLAYING a criterion has to normalise too, or\n * a perfectly ordinary 82/100 renders as \"8200%\". This is the same guard the\n * overall score already applies against `outcome.maxScore`.\n */\nfunction criterionPercent(criterion: CriterionScore): string {\n const max = criterion.maxScore !== undefined && criterion.maxScore > 0 ? criterion.maxScore : 1;\n return `${Math.round(((criterion.score as number) / max) * 100)}%`;\n}\n\n/**\n * Pairs each correction with a list key that is unique by construction. The\n * same mistake made twice carries the same `original`/`corrected` pair, so\n * the grader's `range` is what tells the occurrences apart. `range` is\n * optional and nothing validates it, so a correction without one — or one\n * whose range the grader already used — is keyed by its position instead.\n * Only position keys start with `#`, so the two kinds never collide.\n */\nfunction keyedCorrections(\n corrections: readonly InlineCorrection[],\n): { key: string; correction: InlineCorrection }[] {\n const used = new Set<string>();\n return corrections.map((correction, index) => {\n const anchored = correction.range\n ? `${correction.range.start}-${correction.range.end}:${correction.corrected}`\n : undefined;\n const key = anchored !== undefined && !used.has(anchored) ? anchored : `#${index}`;\n used.add(key);\n return { key, correction };\n });\n}\n\n/**\n * Renders the server-computed outcome in `review` mode. The grade shown here\n * always came back from the asynchronous grader — nothing on this path scores,\n * infers, or defaults a grade. A `written-response` outcome carries no\n * per-item `details` (there are no options or blanks to mark), so the render\n * is the scaled score, the pass state, and the grader's feedback.\n */\nfunction CriteriaList({ criteria, s }: { criteria: readonly CriterionScore[]; s: LkStrings }) {\n return (\n <ul className=\"lk-wr-criteria\">\n {criteria.map((criterion) => (\n <li\n className=\"lk-wr-criterion\"\n key={criterion.name}\n data-na={String(criterion.notApplicable === true)}\n >\n <span className=\"lk-wr-criterion-name\">{criterion.name}</span>\n {criterion.notApplicable === true ? (\n <span className=\"lk-wr-criterion-score\">{s.notApplicable}</span>\n ) : (\n <span className=\"lk-wr-criterion-score\">\n {criterion.band ??\n (typeof criterion.score === 'number' ? criterionPercent(criterion) : '')}\n </span>\n )}\n {criterion.comment ? (\n <span className=\"lk-wr-criterion-comment\">{criterion.comment}</span>\n ) : null}\n </li>\n ))}\n </ul>\n );\n}\n\nfunction CorrectionsList({\n corrections,\n label,\n}: {\n corrections: readonly InlineCorrection[];\n label?: string;\n}) {\n return (\n <ul className=\"lk-wr-corrections\" {...(label !== undefined ? { 'aria-label': label } : {})}>\n {keyedCorrections(corrections).map(({ key, correction }) => (\n <li className=\"lk-wr-correction\" key={key}>\n <del className=\"lk-wr-correction-original\">{correction.original}</del>{' '}\n <ins className=\"lk-wr-correction-corrected\">{correction.corrected}</ins>\n {correction.explanation ? (\n <span className=\"lk-wr-correction-explanation\">{correction.explanation}</span>\n ) : null}\n </li>\n ))}\n </ul>\n );\n}\n\nfunction GradeBody({ grade, s }: { grade: GradeRecord; s: LkStrings }) {\n return (\n <>\n {grade.feedback ? <p className=\"lk-wr-grade-feedback\">{grade.feedback}</p> : null}\n {grade.criteria && grade.criteria.length > 0 ? (\n <CriteriaList criteria={grade.criteria} s={s} />\n ) : null}\n {grade.corrections && grade.corrections.length > 0 ? (\n <CorrectionsList corrections={grade.corrections} />\n ) : null}\n {grade.requiresHumanReview === true ? (\n <p className=\"lk-wr-review-flag\">{s.awaitingHumanReview}</p>\n ) : null}\n </>\n );\n}\n\n/**\n * \"Get feedback on my draft\", and the feedback: what a model said, the\n * corrections it proposed — each quoting the learner's own words, or the SDK\n * would have refused it — its comment on each criterion, and the rubric's\n * total as an indication, never a grade. A revision since the feedback is\n * said, because its corrections may point at words that are gone.\n */\nfunction DraftFeedback({\n help,\n draft,\n disabled,\n s,\n}: {\n help: AiWritingFeedbackHelp;\n draft: string;\n disabled: boolean;\n s: LkStrings;\n}) {\n const buttonRef = useRef<HTMLButtonElement>(null);\n const panelRef = useRef<HTMLElement>(null);\n const refocus = useRef(false);\n const latest = help.latest;\n\n // The feedback lands beside the button that asked; focus follows it there,\n // so a screen reader reads it from its heading rather than all at once.\n useEffect(() => {\n if (latest !== null && refocus.current) {\n refocus.current = false;\n panelRef.current?.focus();\n }\n }, [latest]);\n useEffect(() => {\n if (help.status === 'unavailable') {\n refocus.current = false;\n }\n }, [help.status]);\n\n if (!help.offered && help.used === 0) {\n return null;\n }\n const loading = help.status === 'loading';\n const empty = draft.trim() === '';\n const ask = (): void => {\n refocus.current =\n typeof document !== 'undefined' && document.activeElement === buttonRef.current;\n help.ask();\n };\n return (\n <div className=\"lk-ai lk-wr-ai\" data-state={help.status}>\n <div aria-live=\"polite\">\n {latest !== null ? (\n <section\n ref={panelRef}\n className=\"lk-ai-panel\"\n tabIndex={-1}\n aria-label={s.aiWritingFeedbackHeading}\n data-current={String(help.current)}\n >\n <p className=\"lk-ai-heading\">{s.aiWritingFeedbackHeading}</p>\n {help.current ? null : <p className=\"lk-ai-note\">{s.aiWritingFeedbackOutdated}</p>}\n <p className=\"lk-ai-text\">{latest.text}</p>\n {latest.corrections.length > 0 ? (\n <CorrectionsList corrections={latest.corrections} label={s.aiCorrections} />\n ) : null}\n {latest.criteria.length > 0 ? <CriteriaList criteria={latest.criteria} s={s} /> : null}\n {latest.indicativeScore !== null ? (\n <p className=\"lk-wr-indicative\">\n {s.aiIndicativeScore(Math.round(latest.indicativeScore * 100))}\n </p>\n ) : null}\n <p className=\"lk-ai-notice\">{s.aiNotice}</p>\n </section>\n ) : null}\n {help.status === 'unavailable' ? (\n <p className=\"lk-ai-unavailable\">{s.aiWritingFeedbackUnavailable}</p>\n ) : null}\n </div>\n {help.offered ? (\n help.used < help.limit ? (\n <button\n ref={buttonRef}\n type=\"button\"\n className=\"lk-ai-button\"\n aria-busy={loading || undefined}\n // aria-disabled rather than disabled: focus stays on the button.\n aria-disabled={loading || empty || disabled || undefined}\n onClick={ask}\n >\n {loading ? s.aiWritingFeedbackLoading : s.aiWritingFeedback}\n </button>\n ) : (\n <p className=\"lk-ai-note\">{s.aiNoMoreWritingFeedback}</p>\n )\n ) : null}\n </div>\n );\n}\n\n/**\n * Renders the server-computed outcome in `review` mode. The grade shown here\n * always came back from the grader — nothing on this path scores, infers, or\n * defaults a grade.\n */\nfunction OutcomeSummary({ outcome, s }: { outcome: ItemOutcome; s: LkStrings }) {\n if (outcome.status === 'scored' || outcome.status === 'graded') {\n // `score` is scaled [0–1] against `maxScore`; normalising by `maxScore`\n // is a no-op for the canonical maxScore of 1 and keeps an unscaled\n // grader payload (8.5 / 10) from rendering as 850%.\n const percent =\n outcome.maxScore > 0\n ? Math.round((outcome.score / outcome.maxScore) * 100)\n : Math.round(outcome.score * 100);\n return (\n <div\n className=\"lk-wr-outcome\"\n data-status={outcome.status}\n data-passed={String(outcome.passed)}\n >\n <p className=\"lk-wr-grade\">{s.scoreAnnouncement(percent, outcome.passed)}</p>\n {outcome.status === 'graded' ? (\n <GradeBody grade={outcome.grade} s={s} />\n ) : outcome.feedback ? (\n <p className=\"lk-wr-grade-feedback\">{outcome.feedback}</p>\n ) : null}\n </div>\n );\n }\n if (outcome.status === 'deferred') {\n return (\n <div className=\"lk-wr-outcome\" data-status=\"deferred\">\n <p className=\"lk-wr-grade\">{s.awaitingGrade}</p>\n </div>\n );\n }\n // `unscorable` reasons are developer-facing strings; surface the state, not\n // the reason, and leave it on the element for diagnostics.\n return (\n <div className=\"lk-wr-outcome\" data-status=\"unscorable\" data-reason={outcome.reason}>\n <p className=\"lk-wr-grade\">{s.couldNotBeGraded}</p>\n </div>\n );\n}\n\nexport function WrittenResponse({\n data,\n onSubmitted,\n onSubmit,\n value,\n defaultValue,\n defaultSubmitted,\n onChange,\n renderMode = 'practice',\n outcome,\n sanitizeHtml,\n mediaBudget,\n mediaStrings,\n strings,\n onInteraction,\n theme,\n locale,\n disabled,\n delivery,\n ai: aiProp,\n}: WrittenResponseProps) {\n // Dev-only boundary validation (Req 2.3), same convention as MC/FIB. The\n // content schema is loose, so a `redact()` projection validates too.\n const s = useLkStrings(strings);\n // An essay is graded later, so `feedback` is the one setting that reaches\n // it: whether a returned grade — the score, each criterion, the corrections\n // — is read back in review.\n const policy = useDeliveryPolicy(delivery);\n const ai = useLearnerAi(aiProp);\n\n const devError = useMemo(() => {\n if (!isDevelopment()) {\n return null;\n }\n const result = validateActivity('written-response', data);\n return result.success ? null : new ActivitySchemaError('written-response', result.errors);\n }, [data]);\n\n const { state, start, complete, getTimeSpent, reset } = useActivityState(\n defaultSubmitted === true ? 'completed' : 'idle',\n );\n const isControlled = value !== undefined;\n const [innerText, setInnerText] = useState<string>(() => textOf(defaultValue));\n const [summary, setSummary] = useState<string | null>(null);\n\n /**\n * Rich text is rendered ONLY through a caller-supplied sanitiser, and only\n * when the author actually shipped the HTML sidecar. Without both, the\n * plain-text prompt is rendered as an escaped React child.\n */\n const promptHtml = useMemo(() => {\n if (sanitizeHtml === undefined || typeof data.promptHtml !== 'string') {\n return null;\n }\n return sanitizeHtml(data.promptHtml);\n }, [data.promptHtml, sanitizeHtml]);\n\n // Latest seed text, kept in a ref so `defaultValue` is NOT a reset trigger:\n // callers pass an object literal, whose identity changes every render.\n const defaultTextRef = useRef<string>(textOf(defaultValue));\n useEffect(() => {\n defaultTextRef.current = textOf(defaultValue);\n }, [defaultValue]);\n\n // Reset on data-prop change (Req 3.7): back to the seed (empty when there\n // is none — the v1 behaviour), never the previous activity's draft.\n // Mirror `defaultSubmitted` so the reset below returns to the SEEDED state.\n // Resetting unconditionally to idle unlocked an item the learner had already\n // committed — which made `defaultSubmitted` a no-op here, since this effect\n // runs right after the first paint.\n const defaultSubmittedRef = useRef(defaultSubmitted);\n useEffect(() => {\n defaultSubmittedRef.current = defaultSubmitted;\n }, [defaultSubmitted]);\n\n // Identity guard so the MOUNT run is a no-op. Without it this effect fires\n // after the first paint and undoes every seed it was just given; with it,\n // only a real `data` change resets. A parent that rebuilds structurally\n // identical entries in render (`activities={raw.map(redact)}`) must not\n // unlock or revert a restored answer — the pager already remounts a slot\n // whose activity actually changed, via its key.\n const lastDataRef = useRef(data);\n useEffect(() => {\n if (lastDataRef.current === data) {\n return;\n }\n lastDataRef.current = data;\n setInnerText(defaultTextRef.current);\n setSummary(null);\n reset(defaultSubmittedRef.current === true ? 'completed' : 'idle');\n }, [data, reset]);\n\n // Feedback on a draft is a hook, so it is read here, before the throws below.\n const draft = isControlled ? textOf(value) : innerText;\n const writingFeedback = useAiWritingFeedback({\n data,\n response: { type: 'written-response', text: draft, wordCount: countWords(draft) },\n submitted: state === 'completed',\n renderMode,\n delivery: policy,\n disabled: disabled === true,\n ...(ai !== undefined ? { ai } : {}),\n ...(locale !== undefined ? { locale } : {}),\n ...(onInteraction !== undefined ? { onInteraction } : {}),\n });\n\n if (devError) {\n throw devError;\n }\n\n const isExam = renderMode === 'exam';\n const isReview = renderMode === 'review';\n\n const text = isControlled ? textOf(value) : innerText;\n const submitted = state === 'completed';\n const inactive = disabled === true || submitted || isReview;\n const wordCount = countWords(text);\n const withinBounds = wordCount >= data.minWords && wordCount <= data.maxWords;\n\n const handleChange = (next: string): void => {\n if (inactive) {\n return;\n }\n if (state === 'idle') {\n start();\n }\n // A controlled component renders from `props.value` only; the caller's\n // state is the single source of truth for the text.\n if (!isControlled) {\n setInnerText(next);\n }\n const nextWordCount = countWords(next);\n onChange?.({ type: 'written-response', text: next, wordCount: nextWordCount });\n onInteraction?.({\n type: 'text-changed',\n activityId: data.id,\n timestamp: Date.now(),\n payload: { wordCount: nextWordCount },\n });\n };\n\n // Practice reveals nothing an essay could leak, but it DOES run the local\n // submit path and emit a practice xAPI statement for work the server is\n // supposed to grade. MultipleChoice and FillInTheBlanks have refused\n // redacted data in `practice` since 0.5.0; this component silently accepted\n // it, so an all-essay redacted paper mounted without `renderMode` looked\n // entirely healthy end to end. Fail at render, like its siblings.\n if (data.redacted === true && renderMode === 'practice') {\n throw new Error(\n `Written Response \"${data.id}\" received redacted activity data in renderMode \"practice\". ` +\n 'Practice runs the local submit path and emits a practice-mode xAPI statement, so an ' +\n 'exam item wired this way is graded nowhere and looks fine while it happens. ' +\n 'Render redacted data with renderMode=\"exam\" (server grades) or \"review\" (pass `outcome`).',\n );\n }\n\n const handleSubmit = (event: React.FormEvent): void => {\n event.preventDefault();\n if (inactive || text.trim().length === 0) {\n return;\n }\n let finalWordCount = wordCount;\n let finalWithinBounds = withinBounds;\n // `exam` mode must not call evaluate(): the component does not grade, and\n // a redacted projection carries no scoring input anyway. The two facts\n // evaluate() returns for a deferred type (recomputed word count, bounds)\n // are exactly what is computed above, so the payload is identical either\n // way; practice keeps going through core so the numbers stay canonical.\n if (!isExam) {\n const itemOutcome = evaluate(data, { type: 'written-response', text, wordCount });\n const partial = itemOutcome.status === 'deferred' ? itemOutcome.partial : undefined;\n if (typeof partial?.wordCount === 'number') {\n finalWordCount = partial.wordCount;\n }\n if (typeof partial?.withinWordBounds === 'boolean') {\n finalWithinBounds = partial.withinWordBounds;\n }\n }\n complete();\n const timeSpent = getTimeSpent();\n const xapiStatement = xAPIBuilder.buildSubmittedStatement({\n actor: ANONYMOUS_ACTOR,\n object: {\n id: objectIdFor(data.id),\n name: { [data.locale ?? 'en-US']: data.title },\n type: 'http://adlnet.gov/expapi/activities/cmi.interaction',\n interactionType: 'long-fill-in',\n },\n timeSpentMs: timeSpent,\n response: text,\n resultExtensions: {\n 'urn:learning-kit:extension:word-count': finalWordCount,\n 'urn:learning-kit:extension:within-word-bounds': finalWithinBounds,\n },\n });\n // Raw response first (an exam runner persists this), then the fuller\n // ungraded submission — mirroring `onSubmit` before `onComplete`.\n onSubmit?.({ type: 'written-response', text, wordCount: finalWordCount });\n onSubmitted?.({\n text,\n wordCount: finalWordCount,\n withinWordBounds: finalWithinBounds,\n timeSpent,\n xapiStatement,\n });\n setSummary(s.responseSubmitted);\n onInteraction?.({\n type: 'submitted',\n activityId: data.id,\n timestamp: Date.now(),\n payload: { wordCount: finalWordCount, withinWordBounds: finalWithinBounds },\n });\n };\n\n const promptId = `${data.id}-prompt`;\n const counterId = `${data.id}-counter`;\n const boundsLabel = s.wordBounds(data.minWords, data.maxWords);\n\n return (\n <form\n className=\"lk-wr\"\n aria-label={data.title}\n lang={locale}\n data-render-mode={renderMode}\n style={theme as CSSProperties | undefined}\n onSubmit={handleSubmit}\n >\n {data.media ? (\n <ActivityMedia\n media={data.media}\n renderMode={renderMode}\n {...(mediaBudget !== undefined ? { mediaBudget } : {})}\n {...(mediaStrings !== undefined ? { mediaStrings } : {})}\n {...(strings !== undefined ? { strings } : {})}\n {...(onInteraction !== undefined ? { onInteraction } : {})}\n {...(locale !== undefined ? { locale } : {})}\n />\n ) : null}\n {promptHtml === null ? (\n <p className=\"lk-wr-prompt\" id={promptId}>\n {data.prompt}\n </p>\n ) : (\n // A div, not a p: sanitised author HTML may contain block content.\n <div\n className=\"lk-wr-prompt\"\n id={promptId}\n // biome-ignore lint/security/noDangerouslySetInnerHtml: rendered only through the caller-supplied HtmlSanitizer — the SDK never injects unsanitised markup\n dangerouslySetInnerHTML={{ __html: promptHtml }}\n />\n )}\n <textarea\n className=\"lk-wr-textarea\"\n aria-labelledby={promptId}\n aria-describedby={counterId}\n value={text}\n onChange={(event) => handleChange(event.target.value)}\n // `review` uses readOnly rather than disabled: the submitted essay\n // must stay focusable, selectable and scrollable for a screen reader\n // and a keyboard, while remaining uneditable.\n disabled={!isReview && inactive}\n readOnly={isReview}\n rows={8}\n />\n <div\n className=\"lk-wr-counter\"\n id={counterId}\n aria-live=\"polite\"\n data-within-bounds={withinBounds}\n >\n {s.wordCount(wordCount)} ({boundsLabel})\n </div>\n {ai?.writingFeedback !== undefined ? (\n <DraftFeedback help={writingFeedback} draft={text} disabled={disabled === true} s={s} />\n ) : null}\n {isReview ? null : (\n <button\n type=\"submit\"\n className=\"lk-wr-submit\"\n disabled={inactive || text.trim().length === 0}\n >\n {s.submit}\n </button>\n )}\n <FeedbackRegion id={`${data.id}-feedback`}>\n {isReview ? (\n outcome && (policy.feedback || !outcomeShowsMarks(outcome)) ? (\n <OutcomeSummary outcome={outcome} s={s} />\n ) : null\n ) : (\n summary\n )}\n </FeedbackRegion>\n </form>\n );\n}\n","'use client';\n\nimport { useLkStrings } from '../../i18n/LkIntlProvider.js';\nimport { ActivityErrorBoundary } from '../ActivityErrorBoundary.js';\nimport {\n WrittenResponse as WrittenResponseCore,\n type WrittenResponseProps,\n} from './WrittenResponse.js';\n\nexport type { HtmlSanitizer, Renderable, RenderMode } from '../types.js';\nexport type { WrittenResponseProps, WrittenResponseSubmission } from './WrittenResponse.js';\n\n/**\n * Public Written Response activity: a labelled textarea with a live word\n * counter for free-text writing graded asynchronously (AI or human). The core\n * is wrapped in `ActivityErrorBoundary` so a render failure (incl. the dev\n * schema-validation throw) degrades to an accessible fallback.\n */\nexport function WrittenResponse(props: WrittenResponseProps) {\n // Read here rather than in the boundary: a class component cannot call a\n // hook, and the fallback it renders is learner-facing text like any other.\n const strings = useLkStrings(props.strings);\n return (\n <ActivityErrorBoundary activityTitle={props.data?.title} strings={strings}>\n <WrittenResponseCore {...props} />\n </ActivityErrorBoundary>\n );\n}\n"]}
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { StimulusPanel } from './chunk-
|
|
3
|
-
import { WrittenResponse } from './chunk-
|
|
4
|
-
import { MultipleChoice } from './chunk-
|
|
5
|
-
import { FillInTheBlanks } from './chunk-
|
|
6
|
-
import { GapSelect } from './chunk-
|
|
7
|
-
import { Dictation } from './chunk-
|
|
8
|
-
import { ReadAloud, stopCaptureGroup } from './chunk-
|
|
9
|
-
import { takeOf, mintTake, SequenceSlotContext } from './chunk-
|
|
10
|
-
import {
|
|
11
|
-
import { useLkStrings } from './chunk-C4PSJ3ZC.js';
|
|
2
|
+
import { StimulusPanel } from './chunk-4ZZWZSWI.js';
|
|
3
|
+
import { WrittenResponse } from './chunk-FKGMSOJF.js';
|
|
4
|
+
import { MultipleChoice } from './chunk-C7QZE5BI.js';
|
|
5
|
+
import { FillInTheBlanks } from './chunk-TCDJY3H6.js';
|
|
6
|
+
import { GapSelect } from './chunk-ABJJ3LII.js';
|
|
7
|
+
import { Dictation } from './chunk-RBS5A2DF.js';
|
|
8
|
+
import { ReadAloud, stopCaptureGroup } from './chunk-DC4CQCK5.js';
|
|
9
|
+
import { randomSessionId, takeOf, mintTake, SequenceSlotContext } from './chunk-MXNC5UNO.js';
|
|
10
|
+
import { useLkStrings } from './chunk-HNLRVRQR.js';
|
|
12
11
|
import { isItemGroup, flattenSequence, resolveDeliveryPolicy, resolveItemScoringPolicy, resolvePlaybackPolicy, slotMediaKey, stimulusMediaKey } from '@intellectif/lk-core';
|
|
13
12
|
import { useRef, useState, useMemo, useEffect } from 'react';
|
|
14
13
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -820,5 +819,5 @@ function ActivitySequence({
|
|
|
820
819
|
}
|
|
821
820
|
|
|
822
821
|
export { ActivitySequence };
|
|
823
|
-
//# sourceMappingURL=chunk-
|
|
824
|
-
//# sourceMappingURL=chunk-
|
|
822
|
+
//# sourceMappingURL=chunk-G6PXJ2SA.js.map
|
|
823
|
+
//# sourceMappingURL=chunk-G6PXJ2SA.js.map
|