@intellectif/lk-react 22.0.0 → 23.0.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 +20 -0
- package/dist/ai/useAiHelp.cjs +5 -5
- package/dist/ai/useAiHelp.js +2 -2
- package/dist/{chunk-LX4JI262.js → chunk-2OP5YHRR.js} +12 -7
- package/dist/chunk-2OP5YHRR.js.map +1 -0
- package/dist/{chunk-HNZ3JMAN.js → chunk-4MXECBZT.js} +7 -7
- package/dist/chunk-4MXECBZT.js.map +1 -0
- package/dist/{chunk-EANGKAKG.cjs → chunk-54DX6SLS.cjs} +12 -2
- package/dist/chunk-54DX6SLS.cjs.map +1 -0
- package/dist/{chunk-V2QZM2P2.js → chunk-6GQLCCGN.js} +8 -10
- package/dist/chunk-6GQLCCGN.js.map +1 -0
- package/dist/{chunk-PZVRZ6OX.cjs → chunk-6RIM5EQP.cjs} +4 -4
- package/dist/{chunk-PZVRZ6OX.cjs.map → chunk-6RIM5EQP.cjs.map} +1 -1
- package/dist/{chunk-5YGVGMMV.cjs → chunk-7F2YQWMW.cjs} +14 -9
- package/dist/chunk-7F2YQWMW.cjs.map +1 -0
- package/dist/{chunk-6QY7GC55.cjs → chunk-B7JU52YQ.cjs} +25 -28
- package/dist/chunk-B7JU52YQ.cjs.map +1 -0
- package/dist/{chunk-TRXUZSOY.js → chunk-CXIP7ERK.js} +3 -3
- package/dist/{chunk-TRXUZSOY.js.map → chunk-CXIP7ERK.js.map} +1 -1
- package/dist/{chunk-3GLYK37F.js → chunk-DPNCCWOV.js} +6 -6
- package/dist/{chunk-3GLYK37F.js.map → chunk-DPNCCWOV.js.map} +1 -1
- package/dist/{chunk-PPFVTXGJ.js → chunk-DXFCYNST.js} +11 -3
- package/dist/chunk-DXFCYNST.js.map +1 -0
- package/dist/{chunk-BL5SIBQA.cjs → chunk-DZ7VLLDQ.cjs} +24 -24
- package/dist/chunk-DZ7VLLDQ.cjs.map +1 -0
- package/dist/{chunk-FB47DQPS.js → chunk-E4UF4XZM.js} +3 -3
- package/dist/{chunk-FB47DQPS.js.map → chunk-E4UF4XZM.js.map} +1 -1
- package/dist/{chunk-YIXO6C4Z.js → chunk-ERV666AR.js} +7 -10
- package/dist/chunk-ERV666AR.js.map +1 -0
- package/dist/{chunk-Y5H4NOM6.cjs → chunk-FISEZBLF.cjs} +4 -4
- package/dist/{chunk-Y5H4NOM6.cjs.map → chunk-FISEZBLF.cjs.map} +1 -1
- package/dist/{chunk-JII7XSCT.cjs → chunk-IYGF7PZY.cjs} +19 -19
- package/dist/{chunk-JII7XSCT.cjs.map → chunk-IYGF7PZY.cjs.map} +1 -1
- package/dist/{chunk-KFPCZ7N3.js → chunk-JMEZYYCE.js} +9 -9
- package/dist/{chunk-KFPCZ7N3.js.map → chunk-JMEZYYCE.js.map} +1 -1
- package/dist/{chunk-62K4Q565.js → chunk-KI6DJ5ZF.js} +7 -10
- package/dist/chunk-KI6DJ5ZF.js.map +1 -0
- package/dist/{chunk-UWFJGFB6.cjs → chunk-MXZHL4U5.cjs} +21 -23
- package/dist/chunk-MXZHL4U5.cjs.map +1 -0
- package/dist/{chunk-FPM2GQZY.js → chunk-O7MINPKZ.js} +7 -7
- package/dist/chunk-O7MINPKZ.js.map +1 -0
- package/dist/{chunk-WFGDKBBP.cjs → chunk-PGAPZ6UE.cjs} +25 -28
- package/dist/chunk-PGAPZ6UE.cjs.map +1 -0
- package/dist/{chunk-UXTYFEIC.cjs → chunk-QAZO3ANW.cjs} +25 -25
- package/dist/chunk-QAZO3ANW.cjs.map +1 -0
- package/dist/{chunk-NP5YC4NV.cjs → chunk-SHDSOOBF.cjs} +17 -17
- package/dist/{chunk-NP5YC4NV.cjs.map → chunk-SHDSOOBF.cjs.map} +1 -1
- package/dist/{chunk-R4ZNFDTK.js → chunk-SPSKDNEE.js} +9 -9
- package/dist/{chunk-R4ZNFDTK.js.map → chunk-SPSKDNEE.js.map} +1 -1
- package/dist/{chunk-LRWFU3KS.js → chunk-TGTP5DKF.js} +9 -9
- package/dist/{chunk-LRWFU3KS.js.map → chunk-TGTP5DKF.js.map} +1 -1
- package/dist/{chunk-7EEKZWTQ.js → chunk-U5VFJVQ2.js} +3 -3
- package/dist/{chunk-7EEKZWTQ.js.map → chunk-U5VFJVQ2.js.map} +1 -1
- package/dist/{chunk-M4UJBLVR.cjs → chunk-VPU6UY4O.cjs} +4 -4
- package/dist/{chunk-M4UJBLVR.cjs.map → chunk-VPU6UY4O.cjs.map} +1 -1
- package/dist/{chunk-FKNEHCNT.cjs → chunk-W6UMY7PF.cjs} +5 -5
- package/dist/{chunk-FKNEHCNT.cjs.map → chunk-W6UMY7PF.cjs.map} +1 -1
- package/dist/{chunk-ZUE32Z67.cjs → chunk-WZ2TBXVB.cjs} +16 -16
- package/dist/{chunk-ZUE32Z67.cjs.map → chunk-WZ2TBXVB.cjs.map} +1 -1
- package/dist/{chunk-TQN5CJO6.cjs → chunk-XS6OYYVR.cjs} +13 -13
- package/dist/{chunk-TQN5CJO6.cjs.map → chunk-XS6OYYVR.cjs.map} +1 -1
- package/dist/{chunk-PJMXHDY5.js → chunk-XYJBRKBZ.js} +3 -3
- package/dist/{chunk-PJMXHDY5.js.map → chunk-XYJBRKBZ.js.map} +1 -1
- package/dist/components/ActivityPreview.cjs +14 -14
- package/dist/components/ActivityPreview.js +13 -13
- package/dist/components/ActivitySequence.cjs +14 -14
- package/dist/components/ActivitySequence.js +13 -13
- package/dist/components/Dictation.cjs +7 -7
- package/dist/components/Dictation.js +6 -6
- package/dist/components/FillInTheBlanks.cjs +7 -7
- package/dist/components/FillInTheBlanks.js +6 -6
- package/dist/components/GapSelect.cjs +7 -7
- package/dist/components/GapSelect.js +6 -6
- package/dist/components/InteractiveVideo.cjs +14 -14
- package/dist/components/InteractiveVideo.js +12 -12
- package/dist/components/MultipleChoice.cjs +7 -7
- package/dist/components/MultipleChoice.js +6 -6
- package/dist/components/PronunciationFeedback.cjs +4 -4
- package/dist/components/PronunciationFeedback.js +3 -3
- package/dist/components/ReadAloud.cjs +6 -6
- package/dist/components/ReadAloud.js +5 -5
- package/dist/components/WrittenResponse.cjs +6 -6
- package/dist/components/WrittenResponse.js +5 -5
- package/dist/index.cjs +29 -29
- package/dist/index.js +15 -15
- package/package.json +3 -3
- package/dist/chunk-5YGVGMMV.cjs.map +0 -1
- package/dist/chunk-62K4Q565.js.map +0 -1
- package/dist/chunk-6QY7GC55.cjs.map +0 -1
- package/dist/chunk-BL5SIBQA.cjs.map +0 -1
- package/dist/chunk-EANGKAKG.cjs.map +0 -1
- package/dist/chunk-FPM2GQZY.js.map +0 -1
- package/dist/chunk-HNZ3JMAN.js.map +0 -1
- package/dist/chunk-LX4JI262.js.map +0 -1
- package/dist/chunk-PPFVTXGJ.js.map +0 -1
- package/dist/chunk-UWFJGFB6.cjs.map +0 -1
- package/dist/chunk-UXTYFEIC.cjs.map +0 -1
- package/dist/chunk-V2QZM2P2.js.map +0 -1
- package/dist/chunk-WFGDKBBP.cjs.map +0 -1
- package/dist/chunk-YIXO6C4Z.js.map +0 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { useItemScoringPolicy, useTries, triesSummary, HintCost, TryActions, AiExplanation } from './chunk-
|
|
2
|
+
import { useItemScoringPolicy, useTries, triesSummary, HintCost, TryActions, AiExplanation } from './chunk-U5VFJVQ2.js';
|
|
3
3
|
import { useLearnerAi } from './chunk-RX3A6KIY.js';
|
|
4
4
|
import { localeDirectionOf, textDirectionOf, characterDirectionOf } from './chunk-YORQQXGO.js';
|
|
5
|
-
import { useDeliveryPolicy, FeedbackRegion, outcomeShowsMarks } from './chunk-
|
|
5
|
+
import { useDeliveryPolicy, FeedbackRegion, outcomeShowsMarks } from './chunk-XYJBRKBZ.js';
|
|
6
6
|
import { stampTake, mintTake } from './chunk-U4KTOH7C.js';
|
|
7
|
-
import { ActivityErrorBoundary } from './chunk-
|
|
8
|
-
import { isDevelopment, ANONYMOUS_ACTOR, objectIdFor } from './chunk-
|
|
7
|
+
import { ActivityErrorBoundary } from './chunk-E4UF4XZM.js';
|
|
8
|
+
import { isDevelopment, detailIsRight, ANONYMOUS_ACTOR, objectIdFor } from './chunk-DXFCYNST.js';
|
|
9
9
|
import { ActivityMedia } from './chunk-HYOUMTPW.js';
|
|
10
10
|
import { useActivityState } from './chunk-6N43WDVG.js';
|
|
11
11
|
import { useLkStrings } from './chunk-C4PSJ3ZC.js';
|
|
@@ -154,7 +154,7 @@ function wordsFromDetails(details) {
|
|
|
154
154
|
return details.map((detail) => {
|
|
155
155
|
const attempt = Array.isArray(detail.learnerResponse) ? detail.learnerResponse.join(" ") : detail.learnerResponse;
|
|
156
156
|
const reference = Array.isArray(detail.correctResponse) ? detail.correctResponse.join(" ") : detail.correctResponse;
|
|
157
|
-
const correct = detail
|
|
157
|
+
const correct = detailIsRight(detail);
|
|
158
158
|
const missing = detail.outcome === "incorrect-omission" || !correct && attempt === "";
|
|
159
159
|
return {
|
|
160
160
|
itemId: detail.itemId,
|
|
@@ -553,9 +553,7 @@ function Dictation({
|
|
|
553
553
|
mintTake()
|
|
554
554
|
)
|
|
555
555
|
);
|
|
556
|
-
const correctWords = answer.details.filter(
|
|
557
|
-
(detail) => (detail.outcome ?? (detail.correct ? "correct" : "incorrect")) === "correct"
|
|
558
|
-
).length;
|
|
556
|
+
const correctWords = answer.details.filter(detailIsRight).length;
|
|
559
557
|
setSolutionShown(false);
|
|
560
558
|
setSummary({
|
|
561
559
|
text: `${s.answerSubmitted} ${s.scoreAnnouncement(
|
|
@@ -856,5 +854,5 @@ function Dictation2(props) {
|
|
|
856
854
|
}
|
|
857
855
|
|
|
858
856
|
export { Dictation2 as Dictation };
|
|
859
|
-
//# sourceMappingURL=chunk-
|
|
860
|
-
//# sourceMappingURL=chunk-
|
|
857
|
+
//# sourceMappingURL=chunk-6GQLCCGN.js.map
|
|
858
|
+
//# sourceMappingURL=chunk-6GQLCCGN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/Dictation/Dictation.tsx","../src/components/Dictation/index.tsx"],"names":["result","passed","Dictation","jsx"],"mappings":"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","file":"chunk-6GQLCCGN.js","sourcesContent":["'use client';\n\nimport {\n type ActivityMedia as ActivityMediaData,\n ActivitySchemaError,\n alignDictation,\n assertRedacted,\n computePassThreshold,\n DICTATION_MAX_TEXT_LENGTH,\n type DictationAlignment,\n type DictationCharOp,\n type DictationData,\n type DictationLearnerResponse,\n type DictationWordAlignment,\n diffDictationChars,\n type LearnerResponse,\n type MediaPlaybackPolicy,\n type ScoringDetail,\n type ScoringResult,\n score,\n validateActivity,\n xAPIBuilder,\n xapiDefinitionFor,\n} from '@intellectif/lk-core';\nimport { type CSSProperties, useEffect, useId, useMemo, useRef, useState } from 'react';\nimport { useLearnerAi } from '../../ai/LkAiProvider.js';\nimport { useActivityState } from '../../hooks/useActivityState.js';\nimport { characterDirectionOf, localeDirectionOf, textDirectionOf } from '../../i18n/direction.js';\nimport { useLkStrings } from '../../i18n/LkIntlProvider.js';\nimport { ANONYMOUS_ACTOR, detailIsRight, isDevelopment, objectIdFor } from '../_internal.js';\nimport { ActivityMedia } from '../shared/ActivityMedia.js';\nimport { AiExplanation } 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 TryActions,\n triesSummary,\n useItemScoringPolicy,\n useTries,\n} from '../shared/tries.js';\nimport type { ActivityProps, Renderable } from '../types.js';\n\n// Nothing shuffles and nothing is seeded, so the shared contract is the whole\n// contract. Kept as an interface so a later prop lands here, not in a union.\nexport interface DictationProps extends ActivityProps<DictationData> {}\n\n/** How long the learner has to stop typing before one `text-changed` is emitted. */\nconst TEXT_CHANGED_DEBOUNCE_MS = 500;\n\n/**\n * Present for assistive technology, invisible on screen. Inline rather than\n * left to the optional skin: the per-word sentences are the marks' only\n * channel for a screen reader, and without this a page that does not load the\n * skin would show every one of them beside its word.\n */\nconst VISUALLY_HIDDEN: CSSProperties = {\n position: 'absolute',\n width: 1,\n height: 1,\n margin: -1,\n padding: 0,\n overflow: 'hidden',\n clip: 'rect(0 0 0 0)',\n clipPath: 'inset(50%)',\n whiteSpace: 'nowrap',\n border: 0,\n};\n\n/**\n * Names playback groups. Per mount and never derived from `useId`: two\n * separately hydrated roots derive the same id for the same tree position, and\n * their recordings would pause each other. The name never reaches the DOM.\n */\nlet recordingsGroupCount = 0;\n\n/**\n * A token with nothing spelled in it, as the scorer reads it once composed:\n * only punctuation, control, format and default-ignorable characters, the acute\n * accent, grave accent (and its fullwidth form) and modifier apostrophe the\n * scorer folds into an apostrophe, and the Arabic tatweel and N'Ko lajanyalan\n * it removes.\n */\nconst UNSPELLED_RE = new RegExp(\n `^[\\\\p{P}\\\\p{Cc}\\\\p{Cf}\\\\p{Default_Ignorable_Code_Point}${String.fromCodePoint(0xb4, 0x60, 0xff40, 0x2bc, 0x640, 0x7fa)}]*$`,\n 'u',\n);\n/**\n * Spacing as the scorer reads it: whitespace and NEXT LINE — but not the\n * byte-order mark, which JavaScript counts as whitespace and the scorer\n * removes as a format character, joining the letters on either side.\n */\nconst HINT_SPACE_RE = new RegExp(\n `(?:(?!${String.fromCodePoint(0xfeff)})\\\\s|${String.fromCodePoint(0x85)})+`,\n 'u',\n);\n/** A title with something in it a screen reader can say. */\nconst VISIBLE_TEXT_RE = /[^\\p{White_Space}\\p{Cc}\\p{Cf}\\p{Default_Ignorable_Code_Point}]/u;\n\nconst BULLET = '•';\nconst LEFT_TO_RIGHT_MARK = String.fromCodePoint(0x200e);\nconst RIGHT_TO_LEFT_MARK = String.fromCodePoint(0x200f);\n/**\n * Code points a font draws onto the character before them rather than beside\n * it — combining marks (variation selectors among them), the joiners, emoji\n * skin tones, tag characters, the vowel and final jamo of an old Hangul\n * syllable, and the Thai and Lao SARA AM, whose ring the font sets on the\n * consonant before — so their own span can have no width to decorate.\n */\nconst EXTENDING_RE = new RegExp(\n `^[\\\\p{M}${String.fromCodePoint(0x200c, 0x200d, 0xe33, 0xeb3)}${String.fromCodePoint(0x1f3fb)}-${String.fromCodePoint(0x1f3ff)}${String.fromCodePoint(0xe0020)}-${String.fromCodePoint(0xe007f)}${String.fromCodePoint(0x1160)}-${String.fromCodePoint(0x11ff)}${String.fromCodePoint(0xd7b0)}-${String.fromCodePoint(0xd7ff)}]$`,\n 'u',\n);\n/**\n * Viramas that stack the letter after them into one glyph without asking —\n * Devanagari, Bengali, Gujarati, Oriya, Telugu, Kannada and Malayalam, the\n * Burmese stacker, the Khmer coeng, and the Tai Tham, Balinese, Javanese,\n * Chakma and Brahmi signs. Not the Tamil, Gurmukhi or Sinhala virama, which is\n * drawn visibly and leaves most letters after it on their own.\n */\nconst STACKING_VIRAMAS = new Set(\n [\n 0x94d, 0x9cd, 0xacd, 0xb4d, 0xc4d, 0xccd, 0xd4d, 0x1039, 0x17d2, 0x1a60, 0x1b44, 0xa9c0,\n 0x11046, 0x11133,\n ].map((point) => String.fromCodePoint(point)),\n);\n/**\n * The letters a visible virama still draws into the letter before it: the\n * Gurmukhi RA, YA and VA, which fonts set under the consonant, and the Tamil\n * conjuncts KSSA (க்ஷ) and SHRII (ஸ்ரீ), which fonts draw as one glyph —\n * each keyed by its letter, virama and the letter before the virama.\n */\nconst SUBJOINED_AFTER = new Map<string, (before: readonly string[]) => boolean>([\n ...[0xa30, 0xa2f, 0xa35].map(\n (point) =>\n [\n String.fromCodePoint(point),\n (before: readonly string[]) => before.at(-1) === String.fromCodePoint(0xa4d),\n ] as const,\n ),\n [\n String.fromCodePoint(0xbb7),\n (before: readonly string[]) =>\n before.at(-1) === String.fromCodePoint(0xbcd) &&\n before.at(-2) === String.fromCodePoint(0xb95),\n ],\n [\n String.fromCodePoint(0xbb0),\n (before: readonly string[]) =>\n before.at(-1) === String.fromCodePoint(0xbcd) &&\n before.at(-2) === String.fromCodePoint(0xbb8),\n ],\n]);\n/** Viramas after which a zero-width joiner asks for a conjunct: every stacking one, and the Sinhala. */\nconst JOINABLE_VIRAMAS = new Set([...STACKING_VIRAMAS, String.fromCodePoint(0xdca)]);\nconst ZERO_WIDTH_JOINER = String.fromCodePoint(0x200d);\n/**\n * Characters the font draws into the letter after them: MALAYALAM LETTER DOT\n * REPH, set on the consonant after it, and the MONGOLIAN VOWEL SEPARATOR, which\n * has no width of its own and changes the shape of the vowel after it.\n */\nconst PREPENDED = new Set([String.fromCodePoint(0xd4e), String.fromCodePoint(0x180e)]);\nconst ARABIC_LAM = String.fromCodePoint(0x644);\n/** The alefs a lam before them fuses with into one glyph, in every Arabic font. */\nconst LIGATING_ALEFS = new Set(\n [0x622, 0x623, 0x625, 0x627, 0x671, 0x672, 0x673, 0x675].map((point) =>\n String.fromCodePoint(point),\n ),\n);\nconst REGIONAL_INDICATOR_RE = /^[\\u{1f1e6}-\\u{1f1ff}]$/u;\nconst LETTER_RE = /^\\p{L}$/u;\n/** A letter of any script but Latin, Greek or Cyrillic, whose common ligatures are only decorative. */\nconst LETTER_WITH_REQUIRED_LIGATURES_RE =\n /(?![\\p{Script=Latin}\\p{Script=Greek}\\p{Script=Cyrillic}])\\p{L}/u;\nconst DIGIT_RE = /^\\p{Nd}$/u;\n/**\n * Signs laid out with the European number beside them (bidirectional class\n * ET): the currency signs, the degree, plus-minus and per-mille signs.\n */\nconst NUMBER_SIGN_RE = new RegExp(\n `^[\\\\p{Sc}${String.fromCodePoint(0xb0, 0xb1, 0x2030, 0x2031, 0x212e, 0x2213)}]$`,\n 'u',\n);\n/** Letters of the Arabic, Syriac and Thaana blocks and their presentation forms: before them, a European number is not one. */\nconst ARABIC_LETTER_BLOCKS: readonly (readonly [number, number])[] = [\n [0x0600, 0x07bf],\n [0x0860, 0x08ff],\n [0xfb50, 0xfdff],\n [0xfe70, 0xfeff],\n];\n\n/**\n * The text out of a `LearnerResponse`. A response of another activity type\n * reads as nothing typed rather than throwing — a controlled host that has not\n * yet swapped its state on an activity change would otherwise crash the attempt.\n */\nfunction textOf(response: LearnerResponse | undefined): string {\n return response !== undefined && response.type === 'dictation' ? response.text : '';\n}\n\n/** The hint count out of a `LearnerResponse`; absent or another type reads as none. */\nfunction hintsOf(response: LearnerResponse | undefined): number {\n if (response === undefined || response.type !== 'dictation') {\n return 0;\n }\n const revealed = response.hintsRevealed;\n return typeof revealed === 'number' && Number.isInteger(revealed) && revealed > 0 ? revealed : 0;\n}\n\n/** The response this component emits; `hintsRevealed` is written only when there is one. */\nfunction responseOf(text: string, hintsRevealed: number): DictationLearnerResponse {\n return { type: 'dictation', text, ...(hintsRevealed > 0 ? { hintsRevealed } : {}) };\n}\n\n/**\n * The slower recording as an `ActivityMedia`: it follows the recording's\n * playback policy minus `maxPlays` (`controls`, `seek`, `rate`, the native\n * hints), so a locked scrubber or a fixed speed binds both files — and it never\n * carries a budget of its own, so `<ActivityMedia>` never demands a binding\n * for it. `undefined` when there is no slow recording.\n */\nfunction slowMediaFor(\n data: Renderable<DictationData>,\n label: string,\n): ActivityMediaData | undefined {\n const slow = data.slowMedia;\n if (slow === undefined) {\n return undefined;\n }\n const policy: MediaPlaybackPolicy = data.media?.playback ?? {};\n const { maxPlays: _budget, ...inherited } = policy;\n const hasPolicy = Object.values(inherited).some((value) => value !== undefined);\n return {\n type: 'audio',\n url: slow.url,\n alt: slow.alt ?? label,\n ...(hasPolicy ? { playback: inherited } : {}),\n };\n}\n\n/**\n * The transcript's words as a learner would read them: raw, in order, split at\n * whitespace. A token with nothing in it that is spelled — a dash, an ellipsis\n * — is joined to the word before it (or to the first word, when it leads), so\n * every reveal shows a word. A script written without spaces is one token, so\n * one reveal shows the whole sentence.\n */\nfunction hintWordsOf(transcript: string): string[] {\n const words: string[] = [];\n let leading = '';\n for (const token of transcript.split(HINT_SPACE_RE)) {\n if (token === '') {\n continue;\n }\n const last = words.length - 1;\n // Composed first: the Greek varia and oxia decompose to the grave and acute\n // accents, which the scorer folds into an apostrophe and removes.\n if (!UNSPELLED_RE.test(token.normalize('NFC'))) {\n words.push(leading === '' ? token : `${leading} ${token}`);\n leading = '';\n } else if (last >= 0) {\n words[last] = `${words[last]} ${token}`;\n } else {\n leading = leading === '' ? token : `${leading} ${token}`;\n }\n }\n return words;\n}\n\n/**\n * Word marks rebuilt from stored scoring details — a server-recorded mark\n * shown after an exam, with no transcript on the client. Extras are not in the\n * details (the scorer writes one per transcript word), so none appear.\n */\nfunction wordsFromDetails(details: readonly ScoringDetail[]): DictationWordAlignment[] | null {\n if (details.length === 0 || !details.every((detail) => /^w\\d+$/.test(detail.itemId))) {\n return null;\n }\n return details.map((detail) => {\n const attempt = Array.isArray(detail.learnerResponse)\n ? detail.learnerResponse.join(' ')\n : detail.learnerResponse;\n const reference = Array.isArray(detail.correctResponse)\n ? detail.correctResponse.join(' ')\n : detail.correctResponse;\n const correct = detailIsRight(detail);\n const missing = detail.outcome === 'incorrect-omission' || (!correct && attempt === '');\n return {\n itemId: detail.itemId,\n reference,\n attempt,\n similarity: detail.score ?? (correct ? 1 : 0),\n status: correct ? 'correct' : missing ? 'missing' : 'incorrect',\n };\n });\n}\n\n/** A run of character operations drawn as one glyph cluster, and how it is marked. */\ninterface MarkedCluster {\n op: DictationCharOp['op'];\n text: string;\n}\n\n/**\n * Whether `shown`, the character an operation displays, is drawn into the\n * cluster whose characters so far are `before`: a mark, a joiner or a skin tone\n * onto its base, a letter stacked under a virama, an alef fused with the lam\n * before it, the second half of a flag.\n */\nfunction extendsCluster(before: readonly string[], shown: string): boolean {\n const previous = before.at(-1) as string;\n if (EXTENDING_RE.test(shown)) {\n return true;\n }\n if (LETTER_RE.test(shown)) {\n if (\n STACKING_VIRAMAS.has(previous) ||\n PREPENDED.has(previous) ||\n SUBJOINED_AFTER.get(shown)?.(before) === true\n ) {\n return true;\n }\n if (previous === ZERO_WIDTH_JOINER && JOINABLE_VIRAMAS.has(before.at(-2) as string)) {\n return true;\n }\n }\n if (previous === ARABIC_LAM && LIGATING_ALEFS.has(shown)) {\n return true;\n }\n return (\n REGIONAL_INDICATOR_RE.test(shown) &&\n before.length % 2 === 1 &&\n before.every((character) => REGIONAL_INDICATOR_RE.test(character))\n );\n}\n\n/** The character an operation stands for: what should have been typed, or what was typed in excess. */\nfunction characterOf(op: DictationCharOp): string {\n return op.reference === '' ? op.attempt : op.reference;\n}\n\nfunction isArabicLetter(character: string | undefined): boolean {\n const point = character?.codePointAt(0);\n return (\n point !== undefined &&\n LETTER_RE.test(character as string) &&\n ARABIC_LETTER_BLOCKS.some(([first, last]) => point >= first && point <= last)\n );\n}\n\n/**\n * The directions missing characters' bullets are laid out in, by operation\n * index, worked out in two passes over the operations rather than a search\n * per bullet: a word of 2,000 emoji missing its letters took seconds to draw.\n *\n * A bullet takes the character's own direction when it has one — a digit runs\n * left to right, unless it is a digit of a right-to-left script. A currency,\n * degree or per-mille sign beside a digit is laid out with that number, left to\n * right, unless an Arabic letter comes before it, after which the number is not\n * a European one. Otherwise, for a space or a punctuation mark, it takes the\n * direction of the characters on both sides when they agree, and the content's\n * when they do not. A bare bullet is a neutral, which the bidirectional\n * algorithm would otherwise attach to the wrong side of a number or a word of\n * the other direction.\n */\nexport function bulletDirections(\n ops: readonly DictationCharOp[],\n contentDir: 'ltr' | 'rtl' | undefined,\n): Map<number, 'ltr' | 'rtl' | undefined> {\n const own = ops.map((op) => characterDirectionOf(characterOf(op)));\n const before: ('ltr' | 'rtl' | undefined)[] = [];\n const arabicBefore: boolean[] = [];\n let lastDirection: 'ltr' | 'rtl' | undefined;\n let lastLetterArabic = false;\n ops.forEach((op, index) => {\n before[index] = lastDirection;\n arabicBefore[index] = lastLetterArabic;\n lastDirection = own[index] ?? lastDirection;\n if (LETTER_RE.test(characterOf(op))) {\n lastLetterArabic = isArabicLetter(characterOf(op));\n }\n });\n const after: ('ltr' | 'rtl' | undefined)[] = [];\n let nextDirection: 'ltr' | 'rtl' | undefined;\n for (let index = ops.length - 1; index >= 0; index -= 1) {\n after[index] = nextDirection;\n nextDirection = own[index] ?? nextDirection;\n }\n const directions = new Map<number, 'ltr' | 'rtl' | undefined>();\n ops.forEach((op, index) => {\n if (op.op !== 'missing') {\n return;\n }\n const neighbourIsDigit = [ops[index - 1], ops[index + 1]].some(\n (neighbour) => neighbour !== undefined && DIGIT_RE.test(characterOf(neighbour)),\n );\n directions.set(\n index,\n own[index] ??\n (NUMBER_SIGN_RE.test(characterOf(op)) && neighbourIsDigit && !arabicBefore[index]\n ? 'ltr'\n : before[index] !== undefined && before[index] === after[index]\n ? before[index]\n : (contentDir ?? before[index] ?? after[index])),\n );\n });\n return directions;\n}\n\n/**\n * How a cluster is marked. One led by a missing character's bullet is missing,\n * whatever marks sit on the bullet: the character they belong to is not there.\n * Otherwise a cluster is marked as its wrong operations are when they agree —\n * a correct letter with an extra mark is `extra` — and as a substitution when\n * they do not.\n */\nfunction clusterOpOf(ops: readonly DictationCharOp[]): DictationCharOp['op'] {\n if ((ops[0] as DictationCharOp).op === 'missing') {\n return 'missing';\n }\n const wrong = new Set(ops.map((op) => op.op).filter((kind) => kind !== 'equal'));\n if (wrong.size === 0) {\n return 'equal';\n }\n return wrong.size === 1 ? ([...wrong][0] as DictationCharOp['op']) : 'substitute';\n}\n\n/**\n * Character operations grouped into what is drawn as one cluster, so a wrong\n * combining mark, joiner or stacked letter marks the glyph it is drawn into —\n * alone, its span has no width, and its underline or strike would not be\n * painted at all. A missing character's bullet carries only the marks drawn\n * onto it, never a letter that is drawn apart. A missing character's bullet is\n * wrapped in the direction mark of the character it stands for. Consecutive\n * correct clusters are one run: an engine that shapes each element on its own\n * would otherwise draw a correctly typed conjunct or a joined Mongolian word\n * broken apart.\n */\nfunction clustersOf(\n ops: readonly DictationCharOp[],\n contentDir: 'ltr' | 'rtl' | undefined,\n): MarkedCluster[] {\n const bullets = bulletDirections(ops, contentDir);\n const groups: { ops: DictationCharOp[]; shown: string[]; bullet?: 'ltr' | 'rtl' }[] = [];\n ops.forEach((op, index) => {\n const shown = op.op === 'missing' ? BULLET : op.attempt;\n const current = groups.at(-1);\n if (\n current !== undefined &&\n op.op !== 'missing' &&\n ((current.ops[0] as DictationCharOp).op === 'missing'\n ? EXTENDING_RE.test(shown)\n : extendsCluster(current.shown, shown))\n ) {\n current.ops.push(op);\n current.shown.push(shown);\n return;\n }\n const direction = bullets.get(index);\n groups.push({\n ops: [op],\n shown: [shown],\n ...(direction !== undefined ? { bullet: direction } : {}),\n });\n });\n const clusters: MarkedCluster[] = [];\n for (const group of groups) {\n const mark =\n group.bullet === undefined\n ? ''\n : group.bullet === 'rtl'\n ? RIGHT_TO_LEFT_MARK\n : LEFT_TO_RIGHT_MARK;\n const cluster = { op: clusterOpOf(group.ops), text: `${mark}${group.shown.join('')}${mark}` };\n const previous = clusters.at(-1);\n if (previous !== undefined && previous.op === 'equal' && cluster.op === 'equal') {\n previous.text += cluster.text;\n } else {\n clusters.push(cluster);\n }\n }\n return clusters;\n}\n\n/**\n * Character-level edit operations as decoration. Hidden from assistive\n * technology as a whole: a screen reader must never verbalise surrogate or\n * combining fragments one by one, and the word list already carries the\n * meaning. Sighted colour-blind and forced-colors users still get one\n * decoration per state, which the skin draws and the legend explains.\n */\nfunction CharOps({\n ops,\n contentDir,\n}: {\n ops: readonly DictationCharOp[];\n contentDir: 'ltr' | 'rtl' | undefined;\n}) {\n return clustersOf(ops, contentDir).map((cluster, index) => (\n <span\n // biome-ignore lint/suspicious/noArrayIndexKey: clusters are positional and recomputed whole\n key={index}\n className=\"lk-dc-op\"\n data-op={cluster.op}\n // A run with no letter whose script needs its common ligatures: the skin\n // turns them off there, so a font's \"fi\" cannot draw a wrong \"i\" into one glyph.\n {...(LETTER_WITH_REQUIRED_LIGATURES_RE.test(cluster.text)\n ? {}\n : { 'data-ligatures': 'decorative' })}\n aria-hidden=\"true\"\n >\n {cluster.text}\n </span>\n ));\n}\n\n/** What the live region says: the SDK's own sentences, then any authored feedback. */\ninterface Announcement {\n text: string;\n feedback: string | null;\n}\n\n/**\n * The announcement, with authored feedback in its own isolated span: its\n * direction is its own, so an English \"Well heard.\" in an Arabic interface\n * keeps its full stop at its end. Its language is not guessed — feedback may be\n * written in the interface's language or the dictation's.\n */\nfunction AnnouncementText({ announcement }: { announcement: Announcement | null }) {\n if (announcement === null) {\n return null;\n }\n return (\n <>\n {announcement.text}\n {announcement.feedback ? (\n <>\n {' '}\n <span dir=\"auto\">{announcement.feedback}</span>\n </>\n ) : null}\n </>\n );\n}\n\nexport function Dictation({\n data,\n onComplete,\n onSubmit,\n onChange,\n onInteraction,\n value,\n defaultValue,\n defaultSubmitted,\n renderMode = 'practice',\n outcome,\n mediaBudget,\n mediaStrings,\n strings,\n theme,\n locale,\n disabled,\n ai: aiProp,\n delivery,\n scoring,\n}: DictationProps) {\n const isExam = renderMode === 'exam';\n const isReview = renderMode === 'review';\n const s = useLkStrings(strings);\n const ai = useLearnerAi(aiProp);\n const policy = useDeliveryPolicy(delivery);\n const scoringPolicy = useItemScoringPolicy(scoring);\n\n // Whether the payload carries the transcript at all — the KEY, not the\n // `redacted` marker. `redact(data, { reveal: 'after-submit' })` stamps\n // `redacted: true` on a projection that still has its transcript, and that\n // projection is exactly what a review screen hands this component. A type\n // test only: no content is read here, and none is read in `exam` below.\n const hasKey = typeof (data as { transcript?: unknown }).transcript === 'string';\n\n const devError = useMemo(() => {\n if (!isDevelopment()) {\n return null;\n }\n if (data.redacted === true) {\n if (hasKey) {\n // An after-submit projection: the strict redacted schema has no\n // `transcript`, so `assertRedacted` would throw on the one payload\n // this component exists to render in review. Check the public subset.\n const shape = data as { type?: unknown; id?: unknown; title?: unknown };\n return shape.type === 'dictation' &&\n typeof shape.id === 'string' &&\n typeof shape.title === 'string'\n ? null\n : new Error(\n 'Dictation received a revealed projection (redacted: true with a transcript) that ' +\n 'is not a dictation: `type`, `id` and `title` are required.',\n );\n }\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('dictation', data);\n return result.success ? null : new ActivitySchemaError('dictation', result.errors);\n }, [data, hasKey]);\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 const isControlled = value !== undefined;\n const [internalText, setInternalText] = useState<string>(() => textOf(defaultValue));\n const [internalRevealed, setInternalRevealed] = useState<number>(() => hintsOf(defaultValue));\n const [result, setResult] = useState<ScoringResult | null>(null);\n const [summary, setSummary] = useState<Announcement | null>(null);\n const [solutionShown, setSolutionShown] = useState(false);\n const formRef = useRef<HTMLFormElement>(null);\n const feedbackRef = useRef<HTMLDivElement>(null);\n const focusAfterRef = useRef<'answer' | 'feedback' | null>(null);\n\n const text = isControlled ? textOf(value) : internalText;\n const revealed = isControlled ? hintsOf(value) : internalRevealed;\n\n const defaultValueRef = useRef(defaultValue);\n useEffect(() => {\n defaultValueRef.current = defaultValue;\n }, [defaultValue]);\n\n const defaultSubmittedRef = useRef(defaultSubmitted);\n useEffect(() => {\n defaultSubmittedRef.current = defaultSubmitted;\n }, [defaultSubmitted]);\n\n // Identity-guarded so the mount run is a no-op: without it this fires after\n // the first paint and undoes every seed it was just given (Req 3.7).\n const lastDataRef = useRef(data);\n useEffect(() => {\n if (lastDataRef.current === data) {\n return;\n }\n lastDataRef.current = data;\n setInternalText(textOf(defaultValueRef.current));\n setInternalRevealed(hintsOf(defaultValueRef.current));\n setResult(null);\n setSummary(null);\n setSolutionShown(false);\n resetTries();\n reset(defaultSubmittedRef.current === true ? 'completed' : 'idle');\n }, [data, reset, resetTries]);\n\n // `text-changed` is debounced so an autosaving host is not told about every\n // keystroke; only the length travels, never the text.\n const textChangedRef = useRef<{ timer: ReturnType<typeof setTimeout>; length: number } | null>(\n null,\n );\n useEffect(\n () => () => {\n if (textChangedRef.current !== null) {\n clearTimeout(textChangedRef.current.timer);\n }\n },\n [],\n );\n\n const revealButtonRef = useRef<HTMLButtonElement>(null);\n const ids = useId();\n const hintId = `${ids}-hint`;\n const titleId = `${ids}-title`;\n const solutionId = `${ids}-solution`;\n // Per mount, not per activity id: two renderings of one item on a page (a\n // review list of several attempts, a preview beside a sequence) are\n // separate players, and neither should pause the other's recordings.\n const [recordingsGroup] = useState(() => {\n recordingsGroupCount += 1;\n return `lk-dc-recordings-${recordingsGroupCount}`;\n });\n\n const slowMedia = useMemo(\n () => slowMediaFor(data, s.dictationSlowRecording),\n [data, s.dictationSlowRecording],\n );\n\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>('textarea')?.focus();\n } else {\n feedbackRef.current?.focus();\n }\n });\n\n // All hooks are called before these throws, so hook order stays stable.\n if (devError) {\n throw devError;\n }\n // Practice grades locally, and a redacted projection has no answer key to\n // grade against — `score()` would throw RedactedScoringError from the submit\n // handler, where no error boundary can reach it and after the learner has\n // typed. Fail at render instead, in production too, as every built-in does.\n if (data.redacted === true && renderMode === 'practice') {\n throw new Error(\n `Dictation \"${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 answer-key-derived information may be shown. Never in `exam`; in\n * `practice` only once this component has scored; in `review` only once the\n * caller supplies a SCORED outcome.\n */\n const revealing = isReview ? outcome?.status === 'scored' : !isExam && submitted;\n // What the delivery policy lets that reveal show: the marks, the score and\n // the author's feedback — and, only where solutions show too, the \"Show\n // solution\" panel, since the transcript is the whole answer.\n const marking = revealing && policy.feedback;\n // Whether the right answer may show: not where the paper withholds it, and\n // not while the learner is offered another try, which is for finding it.\n // Without it the marks still say which words are right, wrong, missing or\n // extra — but never what a wrong or missing word should have been.\n const solutionsShown = policy.solutions && !tries.open;\n\n // The transcript, read only outside `exam`. `Renderable` says it is a\n // string; a plain redacted projection has none, so it is read defensively\n // and every consumer of it goes through `alignDictation`'s own guards.\n const transcript: string | undefined =\n isExam || !hasKey ? undefined : (data as { transcript: string }).transcript;\n\n // Hints exist only where the transcript does and nothing has been graded:\n // practice, before submit. A plain redacted projection has no words to give.\n const hintWords = useMemo(\n () => (transcript === undefined ? [] : hintWordsOf(transcript)),\n [transcript],\n );\n const hintsOffered =\n policy.hints &&\n data.hints?.mode === 'progressive-words' &&\n !isExam &&\n !isReview &&\n transcript !== undefined;\n const hintsEnabled = hintsOffered && !submitted;\n const hintTotal = hintWords.length;\n const hintsShown = Math.min(revealed, hintTotal);\n // What a response reports: the words actually shown, and none where no hint\n // can be — whatever count a seeded or controlled value carries.\n const reportedHints = hintsOffered ? hintsShown : 0;\n\n const fireInteraction = (\n type: 'text-changed' | 'hint-requested' | 'submitted',\n payload: Record<string, unknown>,\n ): void => {\n onInteraction?.({ type, activityId: data.id, timestamp: Date.now(), payload });\n };\n\n const flushTextChanged = (): void => {\n const pending = textChangedRef.current;\n if (pending === null) {\n return;\n }\n clearTimeout(pending.timer);\n textChangedRef.current = null;\n fireInteraction('text-changed', { length: pending.length });\n };\n\n const handleTextChange = (next: string): void => {\n if (inactive) {\n return;\n }\n if (state === 'idle') {\n start();\n }\n if (!isControlled) {\n setInternalText(next);\n }\n onChange?.(responseOf(next, reportedHints));\n if (onInteraction === undefined) {\n return;\n }\n if (textChangedRef.current !== null) {\n clearTimeout(textChangedRef.current.timer);\n }\n textChangedRef.current = {\n length: next.length,\n timer: setTimeout(() => {\n const pending = textChangedRef.current;\n textChangedRef.current = null;\n if (pending !== null) {\n fireInteraction('text-changed', { length: pending.length });\n }\n }, TEXT_CHANGED_DEBOUNCE_MS),\n };\n };\n\n const setRevealed = (next: number): void => {\n if (!isControlled) {\n setInternalRevealed(next);\n }\n onChange?.(responseOf(text, next));\n };\n\n const revealNextHint = (): void => {\n if (inactive || hintsShown >= hintTotal) {\n return;\n }\n if (state === 'idle') {\n start();\n }\n const next = hintsShown + 1;\n setRevealed(next);\n fireInteraction('hint-requested', { revealed: next, total: hintTotal });\n };\n\n const resetHints = (): void => {\n // Under a hint cost the words shown stay shown: hiding them would not\n // unsee them, and the count they are charged by would say they were not.\n if (inactive || hintsShown === 0 || scoringPolicy.hintPenalty > 0) {\n return;\n }\n // The reset button leaves the page once nothing is revealed; hand focus to\n // the reveal button first, or the keyboard user lands on the page body.\n revealButtonRef.current?.focus();\n setRevealed(0);\n };\n\n const handleSubmit = (event: React.FormEvent): void => {\n event.preventDefault();\n if (inactive) {\n return;\n }\n const response = responseOf(text, reportedHints);\n onSubmit?.(response);\n flushTextChanged();\n\n if (isExam) {\n // The client neither grades nor reveals: no score(), no read of the\n // transcript, no onComplete, and no xAPI statement — its\n // correctResponsesPattern IS the answer key.\n complete();\n setSummary({ text: s.answerSubmitted, feedback: null });\n fireInteraction('submitted', { length: text.length, hintsRevealed: reportedHints });\n return;\n }\n\n const answer = score('dictation', data as DictationData, 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: reportedHints,\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 : { ...answer, score: costed, passed: computePassThreshold(data as DictationData, costed) };\n const passed =\n counted.score === scoringResult.score\n ? scoringResult.passed\n : computePassThreshold(data as DictationData, 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: response.text,\n });\n setResult(answer);\n onComplete?.(\n stampTake(\n { score: counted.score, maxScore: counted.maxScore, passed, timeSpent, xapiStatement },\n mintTake(),\n ),\n );\n const correctWords = answer.details.filter(detailIsRight).length;\n setSolutionShown(false);\n setSummary({\n text: `${s.answerSubmitted} ${s.scoreAnnouncement(\n Math.round(counted.score * 100),\n passed,\n )} ${s.dictationWordsSummary(correctWords, answer.details.length)}`,\n feedback: answer.feedback,\n });\n fireInteraction('submitted', {\n length: text.length,\n hintsRevealed: reportedHints,\n score: scoringResult.score,\n });\n };\n\n /** \"Try again\": the text stays, to be corrected; the marks go. Hints shown stay shown. */\n const retry = (): void => {\n reset('idle');\n setSummary(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 // A review may hold the key but not the learner's text — an outcome recorded\n // without its response. Recomputing from an empty box would contradict the\n // stored score, so the stored details are the record then.\n const given = isControlled ? value : defaultValue;\n const hasResponse = given !== undefined && given.type === 'dictation';\n // The dictation's language, and the direction its tag names when it names\n // one. Read defensively: stale data may carry a locale that is not a string.\n // A tag written with underscores reads as its hyphenated form, the only one `lang` accepts.\n const contentLang =\n typeof data.locale === 'string' ? data.locale.replaceAll('_', '-') : undefined;\n const localeDir = localeDirectionOf(data.locale);\n\n // The same comparison the scorer made — computed only when it may be shown.\n // The character diff is UI-only and needs memory proportional to the product\n // of the two lengths, so it lives here and nowhere near `score()`.\n const alignment = useMemo<DictationAlignment | null>(\n () =>\n marking && transcript !== undefined && (!isReview || hasResponse)\n ? alignDictation(data, text)\n : null,\n [marking, transcript, isReview, hasResponse, data, text],\n );\n // The character diff draws the transcript's letters beside the learner's, so\n // it is the right answer: only where that may show.\n const sentenceDiff = useMemo<DictationCharOp[] | null>(\n () =>\n alignment !== null && alignment.attempt !== '' && solutionsShown\n ? diffDictationChars(alignment.reference, alignment.attempt)\n : null,\n [alignment, solutionsShown],\n );\n\n // Review with no transcript on the client, or no response to recompute from:\n // a server-recorded mark still renders its word list from the stored details.\n const detailWords = useMemo<DictationWordAlignment[] | null>(\n () =>\n isReview && alignment === null && outcome?.status === 'scored'\n ? wordsFromDetails(outcome.details)\n : null,\n [isReview, alignment, outcome],\n );\n\n const words: DictationWordAlignment[] | null = alignment?.words ?? detailWords;\n const marksShown = marking && words !== null;\n // The authored content's direction: from its language, or else from the first\n // letter of the transcript (or of the stored words, when only they are here).\n // Never `auto` on a container: its first strong character could be a hidden\n // interface sentence, or whatever the learner typed. `undefined` — no letter\n // anywhere — inherits the interface's.\n const contentDir =\n localeDir ??\n textDirectionOf(transcript ?? words?.map((word) => word.reference).join(' ') ?? '');\n // Nothing survived normalisation: from the alignment when there is one, and\n // from the stored details otherwise (every transcript word unanswered).\n const nothingTyped =\n alignment !== null\n ? alignment.attempt === ''\n : (words?.every((word) => word.attempt === '') ?? false);\n\n const passed = isReview\n ? outcome?.status === 'scored' || outcome?.status === 'graded'\n ? outcome.passed\n : undefined\n : result?.passed;\n\n const reviewSummary = useMemo<Announcement | null>(() => {\n if (!isReview || outcome === undefined) {\n return null;\n }\n if (outcome.status === 'scored') {\n return {\n text: s.scoreAnnouncement(Math.round(outcome.score * 100), outcome.passed),\n feedback: outcome.feedback,\n };\n }\n if (outcome.status === 'deferred') {\n return { text: s.notGradedYet, feedback: null };\n }\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 {\n text: s.scoreAnnouncement(percent, outcome.passed),\n feedback: outcome.feedback ?? null,\n };\n }\n return { text: s.noGradeAvailable, feedback: null };\n }, [isReview, outcome, s]);\n\n const sentenceFor = (word: DictationWordAlignment): string => {\n switch (word.status) {\n case 'correct':\n return s.dictationWordCorrect(word.attempt);\n case 'incorrect':\n return solutionsShown\n ? s.dictationWordWrong(word.attempt, word.reference)\n : s.dictationWordWrongUnnamed(word.attempt);\n case 'missing':\n return solutionsShown\n ? s.dictationWordMissing(word.reference)\n : s.dictationWordMissingUnnamed;\n default:\n return s.dictationWordExtra(word.attempt);\n }\n };\n\n const acceptedTranscripts: readonly string[] | undefined =\n transcript === undefined || !Array.isArray(data.acceptedTranscripts)\n ? undefined\n : data.acceptedTranscripts.filter((entry): entry is string => typeof entry === 'string');\n\n const extra =\n !isReview && policy.feedback && submitted && tries.counted !== null\n ? triesSummary(s, scoringPolicy, tries.counted, tries.open)\n : '';\n\n return (\n <form\n ref={formRef}\n className=\"lk-dc\"\n // A title with nothing to say would name the form with silence.\n aria-labelledby={VISIBLE_TEXT_RE.test(data.title) ? titleId : undefined}\n lang={locale}\n data-render-mode={renderMode}\n style={theme as CSSProperties | undefined}\n onSubmit={handleSubmit}\n >\n {/*\n The form's name: read from here, it keeps the content's language. A\n paragraph of its own, so without a language to go by its own first\n letter decides its direction.\n */}\n <p id={titleId} className=\"lk-dc-title\" dir={localeDir ?? 'auto'} lang={contentLang}>\n {data.title}\n </p>\n\n {data.media !== undefined || slowMedia !== undefined ? (\n <div className=\"lk-dc-recordings\">\n {/*\n Each recording is a named group (a fieldset with a legend, which is\n what `role=\"group\"` plus a label spells natively), so the two\n transports are told apart by name and not only by position.\n */}\n {data.media !== undefined ? (\n <fieldset className=\"lk-dc-recording\">\n <legend className=\"lk-dc-recording-label\">{s.dictationRecording}</legend>\n {/* The ONLY budgeted recording: the binding is whatever the pager or the caller passes. */}\n <ActivityMedia\n media={data.media}\n renderMode={renderMode}\n playbackGroup={recordingsGroup}\n {...(mediaBudget !== undefined ? { mediaBudget } : {})}\n {...(mediaStrings !== undefined ? { mediaStrings } : {})}\n {...(strings !== undefined ? { strings } : {})}\n {...(onInteraction !== undefined ? { onInteraction } : {})}\n {...(locale !== undefined ? { locale } : {})}\n {...(disabled !== undefined ? { disabled } : {})}\n />\n </fieldset>\n ) : null}\n {slowMedia !== undefined ? (\n <fieldset className=\"lk-dc-recording\" data-slow=\"true\">\n <legend className=\"lk-dc-recording-label\">{s.dictationSlowRecording}</legend>\n {/* No budget of its own, by contract — so no binding is passed and none is demanded. */}\n <ActivityMedia\n media={slowMedia}\n renderMode={renderMode}\n playbackGroup={recordingsGroup}\n {...(mediaStrings !== undefined ? { mediaStrings } : {})}\n {...(strings !== undefined ? { strings } : {})}\n {...(locale !== undefined ? { locale } : {})}\n {...(disabled !== undefined ? { disabled } : {})}\n />\n </fieldset>\n ) : null}\n </div>\n ) : null}\n\n {hintsEnabled ? (\n <div className=\"lk-dc-hints\">\n {/*\n aria-disabled, never disabled, once every word is shown: a natively\n disabled button drops keyboard focus to the page body.\n */}\n <button\n ref={revealButtonRef}\n type=\"button\"\n className=\"lk-dc-hint-btn\"\n disabled={inactive}\n aria-disabled={hintsShown >= hintTotal || undefined}\n onClick={revealNextHint}\n >\n {s.dictationRevealNextWord(hintsShown, hintTotal)}\n </button>\n <HintCost policy={scoringPolicy} strings={s} />\n {hintsShown > 0 && scoringPolicy.hintPenalty <= 0 ? (\n <button\n type=\"button\"\n className=\"lk-dc-hint-reset\"\n disabled={inactive}\n onClick={resetHints}\n >\n {s.dictationResetHints}\n </button>\n ) : null}\n {/* Rendered before it has content, so the live region exists when the first word lands. */}\n <p id={hintId} className=\"lk-dc-hint\" role=\"status\" dir={contentDir} lang={contentLang}>\n {hintsShown > 0\n ? `${hintWords.slice(0, hintsShown).join(' ')}${hintsShown < hintTotal ? ' …' : ''}`\n : ''}\n </p>\n </div>\n ) : null}\n\n <fieldset disabled={inactive}>\n <textarea\n className=\"lk-dc-input\"\n aria-label={s.dictationInputLabel}\n aria-describedby={hintsEnabled && hintsShown > 0 ? hintId : undefined}\n // No content lang here: the element's accessible name is interface\n // text, and a screen reader voices a name in its element's language.\n dir=\"auto\"\n rows={3}\n maxLength={DICTATION_MAX_TEXT_LENGTH}\n // Assessment integrity, not style: a corrected or completed word is\n // not the learner's spelling.\n autoComplete=\"off\"\n autoCapitalize=\"none\"\n autoCorrect=\"off\"\n spellCheck={false}\n value={text}\n disabled={inactive}\n aria-disabled={inactive || undefined}\n data-correct={\n marking && passed !== undefined && (!isReview || hasResponse)\n ? String(passed)\n : undefined\n }\n onChange={(event) => handleTextChange(event.target.value)}\n />\n {isReview ? null : (\n // Enabled on empty text: an omission is a recorded answer.\n <button type=\"submit\" disabled={inactive}>\n {isExam ? s.submitAnswers : s.checkAnswers}\n </button>\n )}\n </fieldset>\n\n {marksShown ? (\n <div className=\"lk-dc-result\">\n {nothingTyped ? (\n <p className=\"lk-dc-nothing\" role=\"note\">\n {s.dictationNothingTyped}\n </p>\n ) : (\n <>\n {/*\n The word list is the assistive-technology channel: one hidden\n sentence per word says what happened to it. The visible token,\n its glyph and its character marks are decoration.\n */}\n {/*\n The list's name and the hidden sentences are interface text, so\n they keep the interface language; only the typed tokens carry\n the dictation's. Its direction is the dictation's, never\n resolved from the list's own text: the first strong character\n there would be a hidden interface sentence, or whatever the\n learner typed. Each word's own text may resolve from itself.\n */}\n <ol className=\"lk-dc-words\" aria-label={s.dictationMarksLabel} dir={contentDir}>\n {words?.map((word, index) => {\n const sentence = sentenceFor(word);\n return (\n <li\n // biome-ignore lint/suspicious/noArrayIndexKey: alignment order is the identity; words repeat\n key={index}\n className=\"lk-dc-word\"\n data-state={word.status}\n title={sentence}\n >\n <span className=\"lk-visually-hidden\" style={VISUALLY_HIDDEN}>\n {sentence}\n </span>\n <span\n className=\"lk-dc-word-text\"\n aria-hidden=\"true\"\n dir={contentDir ?? 'auto'}\n lang={contentLang}\n // A wrong word drawn as its character marks: the marks\n // carry the decoration, so the wrong characters stand\n // out from the right ones by shape, not colour alone.\n {...(word.status === 'incorrect' && alignment !== null && solutionsShown\n ? { 'data-marks': 'characters' }\n : {})}\n >\n {word.status === 'incorrect' && alignment !== null && solutionsShown ? (\n <CharOps\n ops={diffDictationChars(word.reference, word.attempt)}\n contentDir={contentDir}\n />\n ) : word.status === 'missing' ? (\n // Where the answer may not show, a gap the size of\n // nothing in particular: the word is missing, not named.\n solutionsShown ? (\n word.reference\n ) : (\n '…'\n )\n ) : (\n word.attempt\n )}\n </span>\n </li>\n );\n })}\n </ol>\n {sentenceDiff !== null ? (\n <p className=\"lk-dc-diff\" aria-hidden=\"true\" dir={contentDir} lang={contentLang}>\n <CharOps ops={sentenceDiff} contentDir={contentDir} />\n </p>\n ) : null}\n <ul className=\"lk-dc-legend\">\n <li data-state=\"correct\">{s.dictationLegendCorrect}</li>\n <li data-state=\"incorrect\">{s.dictationLegendWrong}</li>\n <li data-state=\"missing\">{s.dictationLegendMissing}</li>\n {alignment !== null ? <li data-state=\"extra\">{s.dictationLegendExtra}</li> : null}\n </ul>\n <p className=\"lk-dc-diff-note\">{s.dictationDiffNote}</p>\n </>\n )}\n {/*\n Offered after an empty answer too: a learner who could make out\n nothing is the one who most needs to read the sentence, and a\n single typed letter would reveal it anyway.\n */}\n {transcript !== undefined && solutionsShown ? (\n <>\n <button\n type=\"button\"\n className=\"lk-dc-solution-toggle\"\n aria-expanded={solutionShown}\n aria-controls={solutionId}\n onClick={() => setSolutionShown((shown) => !shown)}\n >\n {solutionShown ? s.hideSolution : s.showSolution}\n </button>\n {solutionShown ? (\n <blockquote\n id={solutionId}\n className=\"lk-dc-solution\"\n aria-label={s.dictationSolutionLabel}\n dir={contentDir}\n >\n <p lang={contentLang}>{transcript}</p>\n {acceptedTranscripts !== undefined && acceptedTranscripts.length > 0 ? (\n <ul className=\"lk-dc-solution-alternatives\" lang={contentLang}>\n {acceptedTranscripts.map((alternative) => (\n <li key={alternative}>{alternative}</li>\n ))}\n </ul>\n ) : null}\n </blockquote>\n ) : null}\n </>\n ) : null}\n </div>\n ) : null}\n\n <FeedbackRegion\n id={`${data.id}-feedback`}\n {...(scoringPolicy.retries > 0 ? { ref: feedbackRef } : {})}\n >\n <AnnouncementText\n announcement={\n isReview\n ? policy.feedback || !outcomeShowsMarks(outcome)\n ? reviewSummary\n : null\n : policy.feedback || summary === null\n ? summary === null || extra === ''\n ? summary\n : { ...summary, text: `${summary.text} ${extra}` }\n : { text: s.answerSubmitted, feedback: null }\n }\n />\n </FeedbackRegion>\n <TryActions\n tries={tries}\n solutions={policy.solutions && transcript !== undefined}\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={responseOf(text, reportedHints)}\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 { Dictation as DictationCore, type DictationProps } from './Dictation.js';\n\nexport type { DictationProps } from './Dictation.js';\n\n/**\n * Public Dictation activity: the core wrapped in `ActivityErrorBoundary` so a\n * render failure (including the dev schema-validation throw and the\n * redacted-in-`practice` guard) degrades to an accessible fallback instead of\n * crashing the host.\n */\nexport function Dictation(props: DictationProps) {\n const strings = useLkStrings(props.strings);\n return (\n <ActivityErrorBoundary activityTitle={props.data?.title} strings={strings}>\n <DictationCore {...props} />\n </ActivityErrorBoundary>\n );\n}\n"]}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
var chunkOJGTJOWI_cjs = require('./chunk-OJGTJOWI.cjs');
|
|
5
5
|
var chunkJ2QIHZ3H_cjs = require('./chunk-J2QIHZ3H.cjs');
|
|
6
|
-
var
|
|
6
|
+
var chunk54DX6SLS_cjs = require('./chunk-54DX6SLS.cjs');
|
|
7
7
|
var lkCore = require('@intellectif/lk-core');
|
|
8
8
|
var react = require('react');
|
|
9
9
|
|
|
@@ -45,7 +45,7 @@ function callPort(call) {
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
function warnRefused(feature, activityId, reason) {
|
|
48
|
-
if (
|
|
48
|
+
if (chunk54DX6SLS_cjs.isDevelopment()) {
|
|
49
49
|
console.warn(
|
|
50
50
|
`learning-kit: the AI ${feature} for "${activityId}" was not shown (${reason}). The learner saw "not available" instead.`
|
|
51
51
|
);
|
|
@@ -389,5 +389,5 @@ function useAiWritingFeedback(input) {
|
|
|
389
389
|
exports.useAiExplanation = useAiExplanation;
|
|
390
390
|
exports.useAiHints = useAiHints;
|
|
391
391
|
exports.useAiWritingFeedback = useAiWritingFeedback;
|
|
392
|
-
//# sourceMappingURL=chunk-
|
|
393
|
-
//# sourceMappingURL=chunk-
|
|
392
|
+
//# sourceMappingURL=chunk-6RIM5EQP.cjs.map
|
|
393
|
+
//# sourceMappingURL=chunk-6RIM5EQP.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ai/rules.ts","../src/ai/useAiHelp.ts"],"names":["OPEN_DELIVERY_POLICY","aiSupports","aiAllowedByContent","isDevelopment","useContext","SequenceSlotContext","combineDeliveryPolicies","useLearnerAi","useState","useRef","useEffect","useCallback","aiExplanationRequest","checkAiExplanation","aiHintRequest","checkAiHint","aiWritingFeedbackRequest","checkAiWritingFeedback"],"mappings":"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","file":"chunk-PZVRZ6OX.cjs","sourcesContent":["/**\n * When AI help is offered, and what the SDK does with what a port answers.\n *\n * Internal: these are the rules behind {@link useAiHints} and\n * {@link useAiExplanation}, which are what a host calls. They live apart from\n * the hooks so the hooks' module exports nothing but the hooks themselves.\n */\nimport {\n type AiRefusal,\n aiAllowedByContent,\n aiSupports,\n type ItemOutcome,\n type LearnerResponse,\n OPEN_DELIVERY_POLICY,\n type ResolvedDeliveryPolicy,\n} from '@intellectif/lk-core';\nimport { isDevelopment } from '../components/_internal.js';\nimport type { RenderableActivity, RenderMode } from '../components/types.js';\nimport type { LearnerAi } from './LkAiProvider.js';\n\n/** The most hints a question gives when the host names no number, and the most it may name. */\nconst DEFAULT_MAX_HINTS = 3;\nconst MAX_HINTS_CEILING = 10;\n\n/** A host's limit as a whole number from 1 to 10; anything else is the default, 3. */\nfunction limitOf(asked: unknown): number {\n return typeof asked === 'number' && Number.isInteger(asked) && asked >= 1\n ? Math.min(asked, MAX_HINTS_CEILING)\n : DEFAULT_MAX_HINTS;\n}\n\n/** `maxHints` as a whole number from 1 to 10; anything else is the default. */\nexport function hintLimit(ai: LearnerAi | undefined): number {\n return limitOf(ai?.maxHints);\n}\n\n/** `maxWritingFeedback` as a whole number from 1 to 10; anything else is the default. */\nexport function writingFeedbackLimit(ai: LearnerAi | undefined): number {\n return limitOf(ai?.maxWritingFeedback);\n}\n\n/**\n * Whether the learner may ask for feedback on a draft: `practice`, before\n * submit, on a written response that is not disabled or redacted, whose author\n * left explanations on. The paper's policy must show feedback and solutions —\n * a correction is the right form beside a wrong one — and allow AI\n * explanations, which writing feedback is: a model's words about the\n * learner's own answer.\n */\nexport function writingFeedbackOffered(input: {\n data: RenderableActivity;\n renderMode: RenderMode;\n submitted: boolean;\n disabled: boolean;\n delivery?: ResolvedDeliveryPolicy;\n}): boolean {\n const { data, renderMode, submitted, disabled } = input;\n const delivery = input.delivery ?? OPEN_DELIVERY_POLICY;\n return (\n delivery.feedback &&\n delivery.solutions &&\n delivery.ai.explanations &&\n renderMode === 'practice' &&\n !submitted &&\n !disabled &&\n data.redacted !== true &&\n aiSupports(data.type, 'writing-feedback') &&\n aiAllowedByContent(data, 'writing-feedback')\n );\n}\n\n/**\n * Whether the learner may ask for a hint: `practice`, before submit, on a\n * question that is not disabled, of a type that takes hints, whose author left\n * hints on, and whole — a redacted item is an exam's, and gives none.\n */\nexport function hintOffered(input: {\n data: RenderableActivity;\n renderMode: RenderMode;\n submitted: boolean;\n disabled: boolean;\n /** The paper's policy: hints at all, and AI hints in particular. Open when absent. */\n delivery?: ResolvedDeliveryPolicy;\n}): boolean {\n const { data, renderMode, submitted, disabled } = input;\n const delivery = input.delivery ?? OPEN_DELIVERY_POLICY;\n return (\n delivery.hints &&\n delivery.ai.hints &&\n renderMode === 'practice' &&\n !submitted &&\n !disabled &&\n data.redacted !== true &&\n aiSupports(data.type, 'hint') &&\n aiAllowedByContent(data, 'hint')\n );\n}\n\n/**\n * Whether the learner may ask for an explanation: of a graded answer — in\n * `practice` once submitted, or in `review` when the grade of record is\n * scored — of a type the SDK explains, whose author left explanations on.\n * Never in `exam`.\n */\nexport function explanationOffered(input: {\n data: RenderableActivity;\n renderMode: RenderMode;\n submitted: boolean;\n outcome: ItemOutcome | undefined;\n /**\n * The paper's policy. An explanation needs AI explanations on, and more: it\n * explains a grade, so it needs the grade shown (`feedback`), and it all but\n * always says what the right answer was, so it needs `solutions` too. On a\n * paper that hides the answer, \"Explain my answer\" would hand it over.\n */\n delivery?: ResolvedDeliveryPolicy;\n}): boolean {\n const { data, renderMode, submitted, outcome } = input;\n const delivery = input.delivery ?? OPEN_DELIVERY_POLICY;\n if (!delivery.feedback || !delivery.solutions || !delivery.ai.explanations) {\n return false;\n }\n const graded =\n (renderMode === 'practice' && submitted) ||\n (renderMode === 'review' && outcome?.status === 'scored');\n return graded && aiSupports(data.type, 'explanation') && aiAllowedByContent(data, 'explanation');\n}\n\n/** Calls a port, turning a synchronous throw into a rejection. */\nexport function callPort<T>(call: () => Promise<T>): Promise<T> {\n try {\n return Promise.resolve(call());\n } catch (error) {\n return Promise.reject(error);\n }\n}\n\n/** Tells a developer why a port's answer was not shown. Silent in production. */\nexport function warnRefused(\n feature: 'explanation' | 'hint' | 'writing feedback',\n activityId: string,\n reason: AiRefusal,\n): void {\n if (isDevelopment()) {\n console.warn(\n `learning-kit: the AI ${feature} for \"${activityId}\" was not shown (${reason}). The learner saw \"not available\" instead.`,\n );\n }\n}\n\n/** The language to write in: the host's choice for the learner, else the interface language. */\nexport const localeOf = (\n ai: LearnerAi | undefined,\n locale: string | undefined,\n): { learnerLocale?: string } => {\n const chosen = ai?.learnerLocale ?? locale;\n return chosen === undefined ? {} : { learnerLocale: chosen };\n};\n\n/** What an explanation is about: when any of it changes, the explanation shown no longer is. */\nexport function explanationKey(\n renderMode: RenderMode,\n submitted: boolean,\n response: LearnerResponse,\n outcome: ItemOutcome | undefined,\n): string {\n let graded = '';\n if (outcome !== undefined) {\n graded = `${outcome.status}:${'score' in outcome ? outcome.score : ''}`;\n }\n return `${renderMode}|${submitted}|${graded}|${JSON.stringify(response)}`;\n}\n","'use client';\n\nimport {\n type AiTextResult,\n type AiWritingFeedback,\n aiExplanationRequest,\n aiHintRequest,\n aiWritingFeedbackRequest,\n checkAiExplanation,\n checkAiHint,\n checkAiWritingFeedback,\n combineDeliveryPolicies,\n type DeliveryPolicy,\n type InteractionEvent,\n type ItemOutcome,\n type LearnerResponse,\n} from '@intellectif/lk-core';\nimport { useCallback, useContext, useEffect, useRef, useState } from 'react';\nimport { SequenceSlotContext } from '../components/shared/sequence-slot.js';\nimport type { RenderableActivity, RenderMode } from '../components/types.js';\nimport { type LearnerAi, useLearnerAi } from './LkAiProvider.js';\nimport {\n callPort,\n explanationKey,\n explanationOffered,\n hintLimit,\n hintOffered,\n localeOf,\n warnRefused,\n writingFeedbackLimit,\n writingFeedbackOffered,\n} from './rules.js';\n\n/**\n * The question AI help is being asked about, as the SDK's own components know\n * it. A host drawing its own question passes what it has; everything optional\n * defaults to what the components pass.\n */\nexport interface AiHelpSituation {\n /** The question, as `data` is given to any activity component. */\n data: RenderableActivity;\n /** The learner's answer as it stands: submitted, restored, or being written. */\n response: LearnerResponse;\n /** Whether the learner has committed that answer. */\n submitted: boolean;\n /**\n * Pass on the `renderMode` your question was given. Left out, the paper\n * around the question answers for it — a question inside `<ActivitySequence>`\n * or `<InteractiveVideo>` knows its mode — and `practice` only where there is\n * no paper at all. An `exam` around the question wins over anything passed\n * here.\n */\n renderMode?: RenderMode;\n /**\n * The AI ports to use, overriding {@link LkAiProvider}'s for this question.\n * A question inside `<ActivitySequence>` or `<InteractiveVideo>` is handed\n * the ports in force as `ai` — pass that straight in.\n */\n ai?: LearnerAi;\n /** The interface language: the default language for what a model writes. */\n locale?: string;\n /** Where `ai-hint-shown` and `ai-explanation-shown` go. */\n onInteraction?: (event: InteractionEvent) => void;\n /**\n * The delivery policy your question was handed. The paper around the\n * question holds as well — a set that switched AI hints off keeps them off\n * here, whatever is passed — so leaving it out never turns anything on.\n */\n delivery?: DeliveryPolicy | null;\n}\n\nexport interface AiExplanationInput extends AiHelpSituation {\n /** The grade of record, which `review` explains. */\n outcome?: ItemOutcome;\n}\n\nexport interface AiExplanationHelp {\n /**\n * Whether to offer the learner an explanation at all: a port is present, the\n * answer is graded, the type is one the SDK explains, and the author left\n * explanations on. False in `exam`, always.\n */\n offered: boolean;\n status: 'idle' | 'loading' | 'shown' | 'unavailable';\n /** What to show, once it has arrived and been checked. Its `text` is text, never HTML. */\n explanation: AiTextResult | null;\n /**\n * Asks the port, when the learner presses something. Does nothing while a\n * call is on its way, and nothing at all where `offered` is false — so an\n * exam cannot reach a model through this hook, whatever ports are in scope.\n *\n * One identity for the life of the question, so it is safe in an effect's\n * dependencies.\n */\n ask: () => void;\n}\n\nexport interface AiHintsInput extends AiHelpSituation {\n /** A disabled question gives no hints, as it takes no answer. */\n disabled?: boolean;\n}\n\nexport interface AiHintsHelp {\n /**\n * Whether the learner may ask for hints here at all: a port is present, the\n * mode is `practice`, the answer is not in, the question is not disabled or\n * redacted, the type takes hints and the author left them on. It stays true\n * once `used` reaches `limit` — there are no more to give, but the question\n * is still one that gives them.\n */\n offered: boolean;\n status: 'idle' | 'loading' | 'unavailable';\n /** Every hint shown for this question, in the order they were given. */\n hints: readonly AiTextResult[];\n /** The host's `maxHints`, as a whole number from 1 to 10 (3 by default). */\n limit: number;\n /** How many hints have been shown. A refused hint is not counted. */\n used: number;\n /**\n * Asks for the next hint. Does nothing at the limit, while a call is on its\n * way, or where `offered` is false. One identity for the life of the\n * question.\n */\n ask: () => void;\n}\n\n/**\n * The mode a question is answered in: what the caller says, and what the paper\n * around it says.\n *\n * A host drawing its own question is given `renderMode` like every other prop\n * and is expected to pass it on, but nothing makes it — and a hook that took\n * `practice` on trust would offer hints on a paper of record, as soon as an\n * `LkAiProvider` sat anywhere above the pager. So an `exam` around the question\n * wins, and where the caller says nothing the paper answers for it. A question\n * standing on its own belongs to no paper, and is `practice` as before.\n */\nfunction modeInForce(asked: RenderMode | undefined, around: RenderMode | undefined): RenderMode {\n if (around === 'exam') {\n return 'exam';\n }\n return asked ?? around ?? 'practice';\n}\n\n/**\n * What the record of help a learner was shown carries beside the fact of it:\n * who wrote it, and what the call cost — both only where the port sent them.\n *\n * The text is deliberately absent. A host that wants to keep what a learner\n * read has it in its own port; an interaction is a record of what happened, and\n * is kept for every learner and every question.\n */\nfunction shownPayload(result: AiTextResult): Record<string, unknown> {\n return {\n ...(result.provenance !== undefined ? { provenance: result.provenance } : {}),\n ...(result.usage !== undefined ? { usage: result.usage } : {}),\n };\n}\n\ntype ExplanationState =\n | { key: string; status: 'idle' | 'loading' | 'unavailable' }\n | { key: string; status: 'shown'; result: AiTextResult };\n\n/**\n * \"Explain my answer\", without the SDK's own button and panel: the rules, the\n * call, the checks and the record, for a question you draw yourself.\n *\n * It is what `<MultipleChoice>` and the others use, so a host's own question\n * offers help on exactly the same terms: never in `exam`, never where the\n * item's author switched explanations off, and never an explanation whose\n * verdict contradicts the grade the SDK computed.\n *\n * ```tsx\n * const { offered, status, explanation, ask } = useAiExplanation({\n * data, response, submitted, renderMode, outcome, ai: question.ai,\n * });\n * if (!offered) return null;\n * return explanation === null ? (\n * <button type=\"button\" onClick={ask} aria-busy={status === 'loading'}>Explain my answer</button>\n * ) : (\n * <section>\n * <p>{explanation.text}</p>\n * <p>Written by AI. It can make mistakes.</p>\n * </section>\n * );\n * ```\n *\n * **Say who wrote it.** The SDK's own panel carries \"Written by AI. It can make\n * mistakes.\"; a page that drops that line passes a model's words off as the\n * course's.\n *\n * When the answer or its grade changes, the explanation is dropped and a call\n * still on its way is abandoned — a late explanation never lands beside an\n * answer it was not written for — as it is when the caller unmounts.\n */\nexport function useAiExplanation(input: AiExplanationInput): AiExplanationHelp {\n const { data, response, submitted, outcome } = input;\n const around = useContext(SequenceSlotContext);\n const renderMode = modeInForce(input.renderMode, around?.renderMode);\n const delivery = combineDeliveryPolicies(input.delivery, around?.delivery);\n const ai = useLearnerAi(input.ai);\n const resetKey = explanationKey(renderMode, submitted, response, outcome);\n const [state, setState] = useState<ExplanationState>({ key: resetKey, status: 'idle' });\n const run = useRef(0);\n const controller = useRef<AbortController | null>(null);\n const current: ExplanationState =\n state.key === resetKey ? state : { key: resetKey, status: 'idle' };\n const offered =\n ai?.explain !== undefined &&\n explanationOffered({ data, renderMode, submitted, outcome, delivery });\n\n // What `ask` reads, as of this render, so `ask` itself can keep one identity\n // for the life of the question. The state goes in too: an event handler runs\n // after the render that set it, so the ref is what the learner last saw.\n const latest = useRef({ input, renderMode, ai, resetKey, offered, current });\n latest.current = { input, renderMode, ai, resetKey, offered, current };\n\n // Another answer, or the caller going away: abandon the call in flight.\n // biome-ignore lint/correctness/useExhaustiveDependencies: the key is the trigger — its cleanup runs when the answer changes\n useEffect(() => {\n return () => {\n run.current += 1;\n controller.current?.abort();\n controller.current = null;\n };\n }, [resetKey]);\n\n const ask = useCallback((): void => {\n const now = latest.current;\n const port = now.ai?.explain;\n if (port === undefined || !now.offered || now.current.status === 'loading') {\n return;\n }\n const key = now.resetKey;\n const request = aiExplanationRequest({\n data: now.input.data,\n response: now.input.response,\n ...(now.renderMode === 'review' && now.input.outcome !== undefined\n ? { outcome: now.input.outcome }\n : {}),\n ...localeOf(now.ai, now.input.locale),\n });\n if (request === null) {\n setState({ key, status: 'unavailable' });\n return;\n }\n run.current += 1;\n const mine = run.current;\n controller.current?.abort();\n const abort = new AbortController();\n controller.current = abort;\n setState({ key, status: 'loading' });\n callPort(() => port(request, { signal: abort.signal })).then(\n (raw) => {\n if (run.current !== mine) {\n return;\n }\n const checked = checkAiExplanation(raw, request);\n if (!checked.ok) {\n warnRefused('explanation', now.input.data.id, checked.refusal);\n setState({ key, status: 'unavailable' });\n latest.current.input.onInteraction?.({\n type: 'ai-help-refused',\n activityId: now.input.data.id,\n timestamp: Date.now(),\n payload: { feature: 'explanation', reason: checked.refusal },\n });\n return;\n }\n setState({ key, status: 'shown', result: checked.result });\n latest.current.input.onInteraction?.({\n type: 'ai-explanation-shown',\n activityId: now.input.data.id,\n timestamp: Date.now(),\n payload: shownPayload(checked.result),\n });\n },\n () => {\n if (run.current === mine) {\n setState({ key, status: 'unavailable' });\n }\n },\n );\n }, []);\n\n return {\n offered,\n status: current.status,\n explanation: current.status === 'shown' ? current.result : null,\n ask,\n };\n}\n\ninterface HintState {\n key: string;\n hints: AiTextResult[];\n status: 'idle' | 'loading' | 'unavailable';\n}\n\n/**\n * \"Get a hint\", without the SDK's own button and list: the rules, the call, the\n * checks and the record, for a question you draw yourself.\n *\n * It is what `<MultipleChoice>` and the others use, so a host's own question\n * gives hints on exactly the same terms: only in `practice` before submit, up\n * to the host's limit, never on a redacted item or a type the SDK does not hint\n * for, and never a hint that gives the answer away — which is refused rather\n * than shown, and not counted.\n *\n * ```tsx\n * const { offered, status, hints, used, limit, ask } = useAiHints({\n * data, response, submitted, renderMode, ai: question.ai,\n * });\n * ```\n *\n * **Say who wrote them**, as the SDK's own list does: \"Written by AI. It can\n * make mistakes.\"\n *\n * Keep the hints on screen after submit — the learner can see what they were\n * given — while `offered` turns false. Another question starts with none.\n */\nexport function useAiHints(input: AiHintsInput): AiHintsHelp {\n const { data, submitted } = input;\n const around = useContext(SequenceSlotContext);\n const renderMode = modeInForce(input.renderMode, around?.renderMode);\n const delivery = combineDeliveryPolicies(input.delivery, around?.delivery);\n const disabled = input.disabled === true;\n const ai = useLearnerAi(input.ai);\n const resetKey = data.id;\n const [state, setState] = useState<HintState>({ key: resetKey, hints: [], status: 'idle' });\n const run = useRef(0);\n const controller = useRef<AbortController | null>(null);\n const current: HintState =\n state.key === resetKey ? state : { key: resetKey, hints: [], status: 'idle' };\n const offered =\n ai?.hint !== undefined && hintOffered({ data, renderMode, submitted, disabled, delivery });\n const limit = hintLimit(ai);\n\n const latest = useRef({ input, renderMode, ai, offered, limit, current });\n latest.current = { input, renderMode, ai, offered, limit, current };\n\n // Another question, or the caller going away: abandon the call in flight.\n // biome-ignore lint/correctness/useExhaustiveDependencies: the key is the trigger — its cleanup runs when the question changes\n useEffect(() => {\n return () => {\n run.current += 1;\n controller.current?.abort();\n controller.current = null;\n };\n }, [resetKey]);\n\n // Submitted, or disabled, while a hint was on its way: it would arrive for an\n // answer that can no longer use it.\n useEffect(() => {\n if (!offered) {\n run.current += 1;\n controller.current?.abort();\n controller.current = null;\n setState((previous) =>\n previous.status === 'loading' ? { ...previous, status: 'idle' } : previous,\n );\n }\n }, [offered]);\n\n const ask = useCallback((): void => {\n const now = latest.current;\n const port = now.ai?.hint;\n const held = now.current;\n if (\n port === undefined ||\n !now.offered ||\n held.status === 'loading' ||\n held.hints.length >= now.limit\n ) {\n return;\n }\n const key = held.key;\n const request = aiHintRequest({\n data: now.input.data,\n response: now.input.response,\n previousHints: held.hints.map((hint) => hint.text),\n ...localeOf(now.ai, now.input.locale),\n });\n if (request === null) {\n setState({ ...held, status: 'unavailable' });\n return;\n }\n run.current += 1;\n const mine = run.current;\n controller.current?.abort();\n const abort = new AbortController();\n controller.current = abort;\n setState({ ...held, status: 'loading' });\n callPort(() => port(request, { signal: abort.signal })).then(\n (raw) => {\n if (run.current !== mine) {\n return;\n }\n const checked = checkAiHint(raw, request);\n if (!checked.ok) {\n warnRefused('hint', now.input.data.id, checked.refusal);\n setState((shown) => ({ ...shown, status: 'unavailable' }));\n latest.current.input.onInteraction?.({\n type: 'ai-help-refused',\n activityId: now.input.data.id,\n timestamp: Date.now(),\n payload: {\n feature: 'hint',\n reason: checked.refusal,\n hintNumber: request.hintNumber,\n },\n });\n return;\n }\n setState((shown) => ({\n ...shown,\n hints: shown.key === key ? [...shown.hints, checked.result] : shown.hints,\n status: 'idle',\n }));\n latest.current.input.onInteraction?.({\n type: 'ai-hint-shown',\n activityId: now.input.data.id,\n timestamp: Date.now(),\n payload: { hintNumber: request.hintNumber, ...shownPayload(checked.result) },\n });\n },\n () => {\n if (run.current === mine) {\n setState((shown) => ({ ...shown, status: 'unavailable' }));\n }\n },\n );\n }, []);\n\n return {\n offered,\n status: current.status,\n hints: current.hints,\n limit,\n used: current.hints.length,\n ask,\n };\n}\n\nexport interface AiWritingFeedbackInput extends AiHelpSituation {\n /** A disabled question takes no feedback, as it takes no answer. */\n disabled?: boolean;\n}\n\nexport interface AiWritingFeedbackHelp {\n /**\n * Whether the learner may ask for feedback here at all: a port is present,\n * the mode is `practice`, the answer is not in, the question is a written\n * response that is not disabled or redacted, its author left explanations on,\n * and the paper shows feedback and solutions and allows AI explanations. It\n * stays true once `used` reaches `limit`.\n */\n offered: boolean;\n status: 'idle' | 'loading' | 'unavailable';\n /** Every piece of feedback shown for this question, oldest first. */\n feedback: readonly AiWritingFeedback[];\n /** The latest, or `null` before any. Its `text` is text, never HTML. */\n latest: AiWritingFeedback | null;\n /**\n * Whether `latest` is about the draft as it stands. Once the learner revises,\n * its corrections point at words that may no longer be there: say so.\n */\n current: boolean;\n /** The host's `maxWritingFeedback`, as a whole number from 1 to 10 (3 by default). */\n limit: number;\n /** How many times feedback has been shown. A refused reply is not counted. */\n used: number;\n /**\n * Asks for feedback on the draft as it stands. Does nothing at the limit,\n * while a call is on its way, on an empty draft, or where `offered` is false.\n * One identity for the life of the question.\n */\n ask: () => void;\n}\n\ninterface WritingFeedbackState {\n key: string;\n shown: { feedback: AiWritingFeedback; about: string }[];\n status: 'idle' | 'loading' | 'unavailable';\n}\n\n/** The text of a written response; another type's response is no draft at all. */\nconst draftOf = (response: LearnerResponse): string =>\n response.type === 'written-response' ? response.text : '';\n\n/**\n * \"Get feedback on my draft\", without the SDK's own button and panel: the\n * rules, the call, the checks and the record, for a written response you draw\n * yourself.\n *\n * It is what `<WrittenResponse>` uses, so a host's own essay box gets feedback\n * on the same terms: only in `practice` before submit, up to the host's limit,\n * and never feedback that corrects words the learner did not write — which is\n * refused rather than shown, and not counted.\n *\n * ```tsx\n * const { offered, status, latest, current, used, limit, ask } = useAiWritingFeedback({\n * data, response, submitted, renderMode, ai: question.ai,\n * });\n * ```\n *\n * **Say who wrote it**, as the SDK's own panel does: \"Written by AI. It can make\n * mistakes.\" And show `indicativeScore` as what it is — an indication, not a\n * grade.\n */\nexport function useAiWritingFeedback(input: AiWritingFeedbackInput): AiWritingFeedbackHelp {\n const { data, submitted, response } = input;\n const around = useContext(SequenceSlotContext);\n const renderMode = modeInForce(input.renderMode, around?.renderMode);\n const delivery = combineDeliveryPolicies(input.delivery, around?.delivery);\n const disabled = input.disabled === true;\n const ai = useLearnerAi(input.ai);\n const resetKey = data.id;\n const [state, setState] = useState<WritingFeedbackState>({\n key: resetKey,\n shown: [],\n status: 'idle',\n });\n const run = useRef(0);\n const controller = useRef<AbortController | null>(null);\n const current: WritingFeedbackState =\n state.key === resetKey ? state : { key: resetKey, shown: [], status: 'idle' };\n const offered =\n ai?.writingFeedback !== undefined &&\n writingFeedbackOffered({ data, renderMode, submitted, disabled, delivery });\n const limit = writingFeedbackLimit(ai);\n\n const latest = useRef({ input, ai, offered, limit, current });\n latest.current = { input, ai, offered, limit, current };\n\n // Another question, or the caller going away: abandon the call in flight.\n // biome-ignore lint/correctness/useExhaustiveDependencies: the key is the trigger — its cleanup runs when the question changes\n useEffect(() => {\n return () => {\n run.current += 1;\n controller.current?.abort();\n controller.current = null;\n };\n }, [resetKey]);\n\n // Submitted, or disabled, while feedback was on its way: it would arrive for\n // a draft that can no longer be revised.\n useEffect(() => {\n if (!offered) {\n run.current += 1;\n controller.current?.abort();\n controller.current = null;\n setState((previous) =>\n previous.status === 'loading' ? { ...previous, status: 'idle' } : previous,\n );\n }\n }, [offered]);\n\n const ask = useCallback((): void => {\n const now = latest.current;\n const port = now.ai?.writingFeedback;\n const held = now.current;\n if (\n port === undefined ||\n !now.offered ||\n held.status === 'loading' ||\n held.shown.length >= now.limit\n ) {\n return;\n }\n const key = held.key;\n const about = draftOf(now.input.response);\n const request = aiWritingFeedbackRequest({\n data: now.input.data,\n response: now.input.response,\n previousFeedback: held.shown.map((one) => one.feedback.text),\n ...localeOf(now.ai, now.input.locale),\n });\n if (request === null) {\n // An empty draft: nothing to give feedback on, and nothing went wrong.\n return;\n }\n run.current += 1;\n const mine = run.current;\n controller.current?.abort();\n const abort = new AbortController();\n controller.current = abort;\n setState({ ...held, status: 'loading' });\n callPort(() => port(request, { signal: abort.signal })).then(\n (raw) => {\n if (run.current !== mine) {\n return;\n }\n const checked = checkAiWritingFeedback(raw, request);\n if (!checked.ok) {\n warnRefused('writing feedback', now.input.data.id, checked.refusal);\n setState((was) => ({ ...was, status: 'unavailable' }));\n latest.current.input.onInteraction?.({\n type: 'ai-help-refused',\n activityId: now.input.data.id,\n timestamp: Date.now(),\n payload: {\n feature: 'writing-feedback',\n reason: checked.refusal,\n draftNumber: request.draftNumber,\n },\n });\n return;\n }\n const { feedback } = checked;\n setState((was) => ({\n ...was,\n shown: was.key === key ? [...was.shown, { feedback, about }] : was.shown,\n status: 'idle',\n }));\n latest.current.input.onInteraction?.({\n type: 'ai-writing-feedback-shown',\n activityId: now.input.data.id,\n timestamp: Date.now(),\n payload: {\n draftNumber: request.draftNumber,\n corrections: feedback.corrections.length,\n ...(feedback.indicativeScore !== null\n ? { indicativeScore: feedback.indicativeScore }\n : {}),\n ...shownPayload(feedback),\n },\n });\n },\n () => {\n if (run.current === mine) {\n setState((was) => ({ ...was, status: 'unavailable' }));\n }\n },\n );\n }, []);\n\n const last = current.shown[current.shown.length - 1];\n return {\n offered,\n status: current.status,\n feedback: current.shown.map((one) => one.feedback),\n latest: last?.feedback ?? null,\n current: last !== undefined && last.about === draftOf(response),\n limit,\n used: current.shown.length,\n ask,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/ai/rules.ts","../src/ai/useAiHelp.ts"],"names":["OPEN_DELIVERY_POLICY","aiSupports","aiAllowedByContent","isDevelopment","useContext","SequenceSlotContext","combineDeliveryPolicies","useLearnerAi","useState","useRef","useEffect","useCallback","aiExplanationRequest","checkAiExplanation","aiHintRequest","checkAiHint","aiWritingFeedbackRequest","checkAiWritingFeedback"],"mappings":"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","file":"chunk-6RIM5EQP.cjs","sourcesContent":["/**\n * When AI help is offered, and what the SDK does with what a port answers.\n *\n * Internal: these are the rules behind {@link useAiHints} and\n * {@link useAiExplanation}, which are what a host calls. They live apart from\n * the hooks so the hooks' module exports nothing but the hooks themselves.\n */\nimport {\n type AiRefusal,\n aiAllowedByContent,\n aiSupports,\n type ItemOutcome,\n type LearnerResponse,\n OPEN_DELIVERY_POLICY,\n type ResolvedDeliveryPolicy,\n} from '@intellectif/lk-core';\nimport { isDevelopment } from '../components/_internal.js';\nimport type { RenderableActivity, RenderMode } from '../components/types.js';\nimport type { LearnerAi } from './LkAiProvider.js';\n\n/** The most hints a question gives when the host names no number, and the most it may name. */\nconst DEFAULT_MAX_HINTS = 3;\nconst MAX_HINTS_CEILING = 10;\n\n/** A host's limit as a whole number from 1 to 10; anything else is the default, 3. */\nfunction limitOf(asked: unknown): number {\n return typeof asked === 'number' && Number.isInteger(asked) && asked >= 1\n ? Math.min(asked, MAX_HINTS_CEILING)\n : DEFAULT_MAX_HINTS;\n}\n\n/** `maxHints` as a whole number from 1 to 10; anything else is the default. */\nexport function hintLimit(ai: LearnerAi | undefined): number {\n return limitOf(ai?.maxHints);\n}\n\n/** `maxWritingFeedback` as a whole number from 1 to 10; anything else is the default. */\nexport function writingFeedbackLimit(ai: LearnerAi | undefined): number {\n return limitOf(ai?.maxWritingFeedback);\n}\n\n/**\n * Whether the learner may ask for feedback on a draft: `practice`, before\n * submit, on a written response that is not disabled or redacted, whose author\n * left explanations on. The paper's policy must show feedback and solutions —\n * a correction is the right form beside a wrong one — and allow AI\n * explanations, which writing feedback is: a model's words about the\n * learner's own answer.\n */\nexport function writingFeedbackOffered(input: {\n data: RenderableActivity;\n renderMode: RenderMode;\n submitted: boolean;\n disabled: boolean;\n delivery?: ResolvedDeliveryPolicy;\n}): boolean {\n const { data, renderMode, submitted, disabled } = input;\n const delivery = input.delivery ?? OPEN_DELIVERY_POLICY;\n return (\n delivery.feedback &&\n delivery.solutions &&\n delivery.ai.explanations &&\n renderMode === 'practice' &&\n !submitted &&\n !disabled &&\n data.redacted !== true &&\n aiSupports(data.type, 'writing-feedback') &&\n aiAllowedByContent(data, 'writing-feedback')\n );\n}\n\n/**\n * Whether the learner may ask for a hint: `practice`, before submit, on a\n * question that is not disabled, of a type that takes hints, whose author left\n * hints on, and whole — a redacted item is an exam's, and gives none.\n */\nexport function hintOffered(input: {\n data: RenderableActivity;\n renderMode: RenderMode;\n submitted: boolean;\n disabled: boolean;\n /** The paper's policy: hints at all, and AI hints in particular. Open when absent. */\n delivery?: ResolvedDeliveryPolicy;\n}): boolean {\n const { data, renderMode, submitted, disabled } = input;\n const delivery = input.delivery ?? OPEN_DELIVERY_POLICY;\n return (\n delivery.hints &&\n delivery.ai.hints &&\n renderMode === 'practice' &&\n !submitted &&\n !disabled &&\n data.redacted !== true &&\n aiSupports(data.type, 'hint') &&\n aiAllowedByContent(data, 'hint')\n );\n}\n\n/**\n * Whether the learner may ask for an explanation: of a graded answer — in\n * `practice` once submitted, or in `review` when the grade of record is\n * scored — of a type the SDK explains, whose author left explanations on.\n * Never in `exam`.\n */\nexport function explanationOffered(input: {\n data: RenderableActivity;\n renderMode: RenderMode;\n submitted: boolean;\n outcome: ItemOutcome | undefined;\n /**\n * The paper's policy. An explanation needs AI explanations on, and more: it\n * explains a grade, so it needs the grade shown (`feedback`), and it all but\n * always says what the right answer was, so it needs `solutions` too. On a\n * paper that hides the answer, \"Explain my answer\" would hand it over.\n */\n delivery?: ResolvedDeliveryPolicy;\n}): boolean {\n const { data, renderMode, submitted, outcome } = input;\n const delivery = input.delivery ?? OPEN_DELIVERY_POLICY;\n if (!delivery.feedback || !delivery.solutions || !delivery.ai.explanations) {\n return false;\n }\n const graded =\n (renderMode === 'practice' && submitted) ||\n (renderMode === 'review' && outcome?.status === 'scored');\n return graded && aiSupports(data.type, 'explanation') && aiAllowedByContent(data, 'explanation');\n}\n\n/** Calls a port, turning a synchronous throw into a rejection. */\nexport function callPort<T>(call: () => Promise<T>): Promise<T> {\n try {\n return Promise.resolve(call());\n } catch (error) {\n return Promise.reject(error);\n }\n}\n\n/** Tells a developer why a port's answer was not shown. Silent in production. */\nexport function warnRefused(\n feature: 'explanation' | 'hint' | 'writing feedback',\n activityId: string,\n reason: AiRefusal,\n): void {\n if (isDevelopment()) {\n console.warn(\n `learning-kit: the AI ${feature} for \"${activityId}\" was not shown (${reason}). The learner saw \"not available\" instead.`,\n );\n }\n}\n\n/** The language to write in: the host's choice for the learner, else the interface language. */\nexport const localeOf = (\n ai: LearnerAi | undefined,\n locale: string | undefined,\n): { learnerLocale?: string } => {\n const chosen = ai?.learnerLocale ?? locale;\n return chosen === undefined ? {} : { learnerLocale: chosen };\n};\n\n/** What an explanation is about: when any of it changes, the explanation shown no longer is. */\nexport function explanationKey(\n renderMode: RenderMode,\n submitted: boolean,\n response: LearnerResponse,\n outcome: ItemOutcome | undefined,\n): string {\n let graded = '';\n if (outcome !== undefined) {\n graded = `${outcome.status}:${'score' in outcome ? outcome.score : ''}`;\n }\n return `${renderMode}|${submitted}|${graded}|${JSON.stringify(response)}`;\n}\n","'use client';\n\nimport {\n type AiTextResult,\n type AiWritingFeedback,\n aiExplanationRequest,\n aiHintRequest,\n aiWritingFeedbackRequest,\n checkAiExplanation,\n checkAiHint,\n checkAiWritingFeedback,\n combineDeliveryPolicies,\n type DeliveryPolicy,\n type InteractionEvent,\n type ItemOutcome,\n type LearnerResponse,\n} from '@intellectif/lk-core';\nimport { useCallback, useContext, useEffect, useRef, useState } from 'react';\nimport { SequenceSlotContext } from '../components/shared/sequence-slot.js';\nimport type { RenderableActivity, RenderMode } from '../components/types.js';\nimport { type LearnerAi, useLearnerAi } from './LkAiProvider.js';\nimport {\n callPort,\n explanationKey,\n explanationOffered,\n hintLimit,\n hintOffered,\n localeOf,\n warnRefused,\n writingFeedbackLimit,\n writingFeedbackOffered,\n} from './rules.js';\n\n/**\n * The question AI help is being asked about, as the SDK's own components know\n * it. A host drawing its own question passes what it has; everything optional\n * defaults to what the components pass.\n */\nexport interface AiHelpSituation {\n /** The question, as `data` is given to any activity component. */\n data: RenderableActivity;\n /** The learner's answer as it stands: submitted, restored, or being written. */\n response: LearnerResponse;\n /** Whether the learner has committed that answer. */\n submitted: boolean;\n /**\n * Pass on the `renderMode` your question was given. Left out, the paper\n * around the question answers for it — a question inside `<ActivitySequence>`\n * or `<InteractiveVideo>` knows its mode — and `practice` only where there is\n * no paper at all. An `exam` around the question wins over anything passed\n * here.\n */\n renderMode?: RenderMode;\n /**\n * The AI ports to use, overriding {@link LkAiProvider}'s for this question.\n * A question inside `<ActivitySequence>` or `<InteractiveVideo>` is handed\n * the ports in force as `ai` — pass that straight in.\n */\n ai?: LearnerAi;\n /** The interface language: the default language for what a model writes. */\n locale?: string;\n /** Where `ai-hint-shown` and `ai-explanation-shown` go. */\n onInteraction?: (event: InteractionEvent) => void;\n /**\n * The delivery policy your question was handed. The paper around the\n * question holds as well — a set that switched AI hints off keeps them off\n * here, whatever is passed — so leaving it out never turns anything on.\n */\n delivery?: DeliveryPolicy | null;\n}\n\nexport interface AiExplanationInput extends AiHelpSituation {\n /** The grade of record, which `review` explains. */\n outcome?: ItemOutcome;\n}\n\nexport interface AiExplanationHelp {\n /**\n * Whether to offer the learner an explanation at all: a port is present, the\n * answer is graded, the type is one the SDK explains, and the author left\n * explanations on. False in `exam`, always.\n */\n offered: boolean;\n status: 'idle' | 'loading' | 'shown' | 'unavailable';\n /** What to show, once it has arrived and been checked. Its `text` is text, never HTML. */\n explanation: AiTextResult | null;\n /**\n * Asks the port, when the learner presses something. Does nothing while a\n * call is on its way, and nothing at all where `offered` is false — so an\n * exam cannot reach a model through this hook, whatever ports are in scope.\n *\n * One identity for the life of the question, so it is safe in an effect's\n * dependencies.\n */\n ask: () => void;\n}\n\nexport interface AiHintsInput extends AiHelpSituation {\n /** A disabled question gives no hints, as it takes no answer. */\n disabled?: boolean;\n}\n\nexport interface AiHintsHelp {\n /**\n * Whether the learner may ask for hints here at all: a port is present, the\n * mode is `practice`, the answer is not in, the question is not disabled or\n * redacted, the type takes hints and the author left them on. It stays true\n * once `used` reaches `limit` — there are no more to give, but the question\n * is still one that gives them.\n */\n offered: boolean;\n status: 'idle' | 'loading' | 'unavailable';\n /** Every hint shown for this question, in the order they were given. */\n hints: readonly AiTextResult[];\n /** The host's `maxHints`, as a whole number from 1 to 10 (3 by default). */\n limit: number;\n /** How many hints have been shown. A refused hint is not counted. */\n used: number;\n /**\n * Asks for the next hint. Does nothing at the limit, while a call is on its\n * way, or where `offered` is false. One identity for the life of the\n * question.\n */\n ask: () => void;\n}\n\n/**\n * The mode a question is answered in: what the caller says, and what the paper\n * around it says.\n *\n * A host drawing its own question is given `renderMode` like every other prop\n * and is expected to pass it on, but nothing makes it — and a hook that took\n * `practice` on trust would offer hints on a paper of record, as soon as an\n * `LkAiProvider` sat anywhere above the pager. So an `exam` around the question\n * wins, and where the caller says nothing the paper answers for it. A question\n * standing on its own belongs to no paper, and is `practice` as before.\n */\nfunction modeInForce(asked: RenderMode | undefined, around: RenderMode | undefined): RenderMode {\n if (around === 'exam') {\n return 'exam';\n }\n return asked ?? around ?? 'practice';\n}\n\n/**\n * What the record of help a learner was shown carries beside the fact of it:\n * who wrote it, and what the call cost — both only where the port sent them.\n *\n * The text is deliberately absent. A host that wants to keep what a learner\n * read has it in its own port; an interaction is a record of what happened, and\n * is kept for every learner and every question.\n */\nfunction shownPayload(result: AiTextResult): Record<string, unknown> {\n return {\n ...(result.provenance !== undefined ? { provenance: result.provenance } : {}),\n ...(result.usage !== undefined ? { usage: result.usage } : {}),\n };\n}\n\ntype ExplanationState =\n | { key: string; status: 'idle' | 'loading' | 'unavailable' }\n | { key: string; status: 'shown'; result: AiTextResult };\n\n/**\n * \"Explain my answer\", without the SDK's own button and panel: the rules, the\n * call, the checks and the record, for a question you draw yourself.\n *\n * It is what `<MultipleChoice>` and the others use, so a host's own question\n * offers help on exactly the same terms: never in `exam`, never where the\n * item's author switched explanations off, and never an explanation whose\n * verdict contradicts the grade the SDK computed.\n *\n * ```tsx\n * const { offered, status, explanation, ask } = useAiExplanation({\n * data, response, submitted, renderMode, outcome, ai: question.ai,\n * });\n * if (!offered) return null;\n * return explanation === null ? (\n * <button type=\"button\" onClick={ask} aria-busy={status === 'loading'}>Explain my answer</button>\n * ) : (\n * <section>\n * <p>{explanation.text}</p>\n * <p>Written by AI. It can make mistakes.</p>\n * </section>\n * );\n * ```\n *\n * **Say who wrote it.** The SDK's own panel carries \"Written by AI. It can make\n * mistakes.\"; a page that drops that line passes a model's words off as the\n * course's.\n *\n * When the answer or its grade changes, the explanation is dropped and a call\n * still on its way is abandoned — a late explanation never lands beside an\n * answer it was not written for — as it is when the caller unmounts.\n */\nexport function useAiExplanation(input: AiExplanationInput): AiExplanationHelp {\n const { data, response, submitted, outcome } = input;\n const around = useContext(SequenceSlotContext);\n const renderMode = modeInForce(input.renderMode, around?.renderMode);\n const delivery = combineDeliveryPolicies(input.delivery, around?.delivery);\n const ai = useLearnerAi(input.ai);\n const resetKey = explanationKey(renderMode, submitted, response, outcome);\n const [state, setState] = useState<ExplanationState>({ key: resetKey, status: 'idle' });\n const run = useRef(0);\n const controller = useRef<AbortController | null>(null);\n const current: ExplanationState =\n state.key === resetKey ? state : { key: resetKey, status: 'idle' };\n const offered =\n ai?.explain !== undefined &&\n explanationOffered({ data, renderMode, submitted, outcome, delivery });\n\n // What `ask` reads, as of this render, so `ask` itself can keep one identity\n // for the life of the question. The state goes in too: an event handler runs\n // after the render that set it, so the ref is what the learner last saw.\n const latest = useRef({ input, renderMode, ai, resetKey, offered, current });\n latest.current = { input, renderMode, ai, resetKey, offered, current };\n\n // Another answer, or the caller going away: abandon the call in flight.\n // biome-ignore lint/correctness/useExhaustiveDependencies: the key is the trigger — its cleanup runs when the answer changes\n useEffect(() => {\n return () => {\n run.current += 1;\n controller.current?.abort();\n controller.current = null;\n };\n }, [resetKey]);\n\n const ask = useCallback((): void => {\n const now = latest.current;\n const port = now.ai?.explain;\n if (port === undefined || !now.offered || now.current.status === 'loading') {\n return;\n }\n const key = now.resetKey;\n const request = aiExplanationRequest({\n data: now.input.data,\n response: now.input.response,\n ...(now.renderMode === 'review' && now.input.outcome !== undefined\n ? { outcome: now.input.outcome }\n : {}),\n ...localeOf(now.ai, now.input.locale),\n });\n if (request === null) {\n setState({ key, status: 'unavailable' });\n return;\n }\n run.current += 1;\n const mine = run.current;\n controller.current?.abort();\n const abort = new AbortController();\n controller.current = abort;\n setState({ key, status: 'loading' });\n callPort(() => port(request, { signal: abort.signal })).then(\n (raw) => {\n if (run.current !== mine) {\n return;\n }\n const checked = checkAiExplanation(raw, request);\n if (!checked.ok) {\n warnRefused('explanation', now.input.data.id, checked.refusal);\n setState({ key, status: 'unavailable' });\n latest.current.input.onInteraction?.({\n type: 'ai-help-refused',\n activityId: now.input.data.id,\n timestamp: Date.now(),\n payload: { feature: 'explanation', reason: checked.refusal },\n });\n return;\n }\n setState({ key, status: 'shown', result: checked.result });\n latest.current.input.onInteraction?.({\n type: 'ai-explanation-shown',\n activityId: now.input.data.id,\n timestamp: Date.now(),\n payload: shownPayload(checked.result),\n });\n },\n () => {\n if (run.current === mine) {\n setState({ key, status: 'unavailable' });\n }\n },\n );\n }, []);\n\n return {\n offered,\n status: current.status,\n explanation: current.status === 'shown' ? current.result : null,\n ask,\n };\n}\n\ninterface HintState {\n key: string;\n hints: AiTextResult[];\n status: 'idle' | 'loading' | 'unavailable';\n}\n\n/**\n * \"Get a hint\", without the SDK's own button and list: the rules, the call, the\n * checks and the record, for a question you draw yourself.\n *\n * It is what `<MultipleChoice>` and the others use, so a host's own question\n * gives hints on exactly the same terms: only in `practice` before submit, up\n * to the host's limit, never on a redacted item or a type the SDK does not hint\n * for, and never a hint that gives the answer away — which is refused rather\n * than shown, and not counted.\n *\n * ```tsx\n * const { offered, status, hints, used, limit, ask } = useAiHints({\n * data, response, submitted, renderMode, ai: question.ai,\n * });\n * ```\n *\n * **Say who wrote them**, as the SDK's own list does: \"Written by AI. It can\n * make mistakes.\"\n *\n * Keep the hints on screen after submit — the learner can see what they were\n * given — while `offered` turns false. Another question starts with none.\n */\nexport function useAiHints(input: AiHintsInput): AiHintsHelp {\n const { data, submitted } = input;\n const around = useContext(SequenceSlotContext);\n const renderMode = modeInForce(input.renderMode, around?.renderMode);\n const delivery = combineDeliveryPolicies(input.delivery, around?.delivery);\n const disabled = input.disabled === true;\n const ai = useLearnerAi(input.ai);\n const resetKey = data.id;\n const [state, setState] = useState<HintState>({ key: resetKey, hints: [], status: 'idle' });\n const run = useRef(0);\n const controller = useRef<AbortController | null>(null);\n const current: HintState =\n state.key === resetKey ? state : { key: resetKey, hints: [], status: 'idle' };\n const offered =\n ai?.hint !== undefined && hintOffered({ data, renderMode, submitted, disabled, delivery });\n const limit = hintLimit(ai);\n\n const latest = useRef({ input, renderMode, ai, offered, limit, current });\n latest.current = { input, renderMode, ai, offered, limit, current };\n\n // Another question, or the caller going away: abandon the call in flight.\n // biome-ignore lint/correctness/useExhaustiveDependencies: the key is the trigger — its cleanup runs when the question changes\n useEffect(() => {\n return () => {\n run.current += 1;\n controller.current?.abort();\n controller.current = null;\n };\n }, [resetKey]);\n\n // Submitted, or disabled, while a hint was on its way: it would arrive for an\n // answer that can no longer use it.\n useEffect(() => {\n if (!offered) {\n run.current += 1;\n controller.current?.abort();\n controller.current = null;\n setState((previous) =>\n previous.status === 'loading' ? { ...previous, status: 'idle' } : previous,\n );\n }\n }, [offered]);\n\n const ask = useCallback((): void => {\n const now = latest.current;\n const port = now.ai?.hint;\n const held = now.current;\n if (\n port === undefined ||\n !now.offered ||\n held.status === 'loading' ||\n held.hints.length >= now.limit\n ) {\n return;\n }\n const key = held.key;\n const request = aiHintRequest({\n data: now.input.data,\n response: now.input.response,\n previousHints: held.hints.map((hint) => hint.text),\n ...localeOf(now.ai, now.input.locale),\n });\n if (request === null) {\n setState({ ...held, status: 'unavailable' });\n return;\n }\n run.current += 1;\n const mine = run.current;\n controller.current?.abort();\n const abort = new AbortController();\n controller.current = abort;\n setState({ ...held, status: 'loading' });\n callPort(() => port(request, { signal: abort.signal })).then(\n (raw) => {\n if (run.current !== mine) {\n return;\n }\n const checked = checkAiHint(raw, request);\n if (!checked.ok) {\n warnRefused('hint', now.input.data.id, checked.refusal);\n setState((shown) => ({ ...shown, status: 'unavailable' }));\n latest.current.input.onInteraction?.({\n type: 'ai-help-refused',\n activityId: now.input.data.id,\n timestamp: Date.now(),\n payload: {\n feature: 'hint',\n reason: checked.refusal,\n hintNumber: request.hintNumber,\n },\n });\n return;\n }\n setState((shown) => ({\n ...shown,\n hints: shown.key === key ? [...shown.hints, checked.result] : shown.hints,\n status: 'idle',\n }));\n latest.current.input.onInteraction?.({\n type: 'ai-hint-shown',\n activityId: now.input.data.id,\n timestamp: Date.now(),\n payload: { hintNumber: request.hintNumber, ...shownPayload(checked.result) },\n });\n },\n () => {\n if (run.current === mine) {\n setState((shown) => ({ ...shown, status: 'unavailable' }));\n }\n },\n );\n }, []);\n\n return {\n offered,\n status: current.status,\n hints: current.hints,\n limit,\n used: current.hints.length,\n ask,\n };\n}\n\nexport interface AiWritingFeedbackInput extends AiHelpSituation {\n /** A disabled question takes no feedback, as it takes no answer. */\n disabled?: boolean;\n}\n\nexport interface AiWritingFeedbackHelp {\n /**\n * Whether the learner may ask for feedback here at all: a port is present,\n * the mode is `practice`, the answer is not in, the question is a written\n * response that is not disabled or redacted, its author left explanations on,\n * and the paper shows feedback and solutions and allows AI explanations. It\n * stays true once `used` reaches `limit`.\n */\n offered: boolean;\n status: 'idle' | 'loading' | 'unavailable';\n /** Every piece of feedback shown for this question, oldest first. */\n feedback: readonly AiWritingFeedback[];\n /** The latest, or `null` before any. Its `text` is text, never HTML. */\n latest: AiWritingFeedback | null;\n /**\n * Whether `latest` is about the draft as it stands. Once the learner revises,\n * its corrections point at words that may no longer be there: say so.\n */\n current: boolean;\n /** The host's `maxWritingFeedback`, as a whole number from 1 to 10 (3 by default). */\n limit: number;\n /** How many times feedback has been shown. A refused reply is not counted. */\n used: number;\n /**\n * Asks for feedback on the draft as it stands. Does nothing at the limit,\n * while a call is on its way, on an empty draft, or where `offered` is false.\n * One identity for the life of the question.\n */\n ask: () => void;\n}\n\ninterface WritingFeedbackState {\n key: string;\n shown: { feedback: AiWritingFeedback; about: string }[];\n status: 'idle' | 'loading' | 'unavailable';\n}\n\n/** The text of a written response; another type's response is no draft at all. */\nconst draftOf = (response: LearnerResponse): string =>\n response.type === 'written-response' ? response.text : '';\n\n/**\n * \"Get feedback on my draft\", without the SDK's own button and panel: the\n * rules, the call, the checks and the record, for a written response you draw\n * yourself.\n *\n * It is what `<WrittenResponse>` uses, so a host's own essay box gets feedback\n * on the same terms: only in `practice` before submit, up to the host's limit,\n * and never feedback that corrects words the learner did not write — which is\n * refused rather than shown, and not counted.\n *\n * ```tsx\n * const { offered, status, latest, current, used, limit, ask } = useAiWritingFeedback({\n * data, response, submitted, renderMode, ai: question.ai,\n * });\n * ```\n *\n * **Say who wrote it**, as the SDK's own panel does: \"Written by AI. It can make\n * mistakes.\" And show `indicativeScore` as what it is — an indication, not a\n * grade.\n */\nexport function useAiWritingFeedback(input: AiWritingFeedbackInput): AiWritingFeedbackHelp {\n const { data, submitted, response } = input;\n const around = useContext(SequenceSlotContext);\n const renderMode = modeInForce(input.renderMode, around?.renderMode);\n const delivery = combineDeliveryPolicies(input.delivery, around?.delivery);\n const disabled = input.disabled === true;\n const ai = useLearnerAi(input.ai);\n const resetKey = data.id;\n const [state, setState] = useState<WritingFeedbackState>({\n key: resetKey,\n shown: [],\n status: 'idle',\n });\n const run = useRef(0);\n const controller = useRef<AbortController | null>(null);\n const current: WritingFeedbackState =\n state.key === resetKey ? state : { key: resetKey, shown: [], status: 'idle' };\n const offered =\n ai?.writingFeedback !== undefined &&\n writingFeedbackOffered({ data, renderMode, submitted, disabled, delivery });\n const limit = writingFeedbackLimit(ai);\n\n const latest = useRef({ input, ai, offered, limit, current });\n latest.current = { input, ai, offered, limit, current };\n\n // Another question, or the caller going away: abandon the call in flight.\n // biome-ignore lint/correctness/useExhaustiveDependencies: the key is the trigger — its cleanup runs when the question changes\n useEffect(() => {\n return () => {\n run.current += 1;\n controller.current?.abort();\n controller.current = null;\n };\n }, [resetKey]);\n\n // Submitted, or disabled, while feedback was on its way: it would arrive for\n // a draft that can no longer be revised.\n useEffect(() => {\n if (!offered) {\n run.current += 1;\n controller.current?.abort();\n controller.current = null;\n setState((previous) =>\n previous.status === 'loading' ? { ...previous, status: 'idle' } : previous,\n );\n }\n }, [offered]);\n\n const ask = useCallback((): void => {\n const now = latest.current;\n const port = now.ai?.writingFeedback;\n const held = now.current;\n if (\n port === undefined ||\n !now.offered ||\n held.status === 'loading' ||\n held.shown.length >= now.limit\n ) {\n return;\n }\n const key = held.key;\n const about = draftOf(now.input.response);\n const request = aiWritingFeedbackRequest({\n data: now.input.data,\n response: now.input.response,\n previousFeedback: held.shown.map((one) => one.feedback.text),\n ...localeOf(now.ai, now.input.locale),\n });\n if (request === null) {\n // An empty draft: nothing to give feedback on, and nothing went wrong.\n return;\n }\n run.current += 1;\n const mine = run.current;\n controller.current?.abort();\n const abort = new AbortController();\n controller.current = abort;\n setState({ ...held, status: 'loading' });\n callPort(() => port(request, { signal: abort.signal })).then(\n (raw) => {\n if (run.current !== mine) {\n return;\n }\n const checked = checkAiWritingFeedback(raw, request);\n if (!checked.ok) {\n warnRefused('writing feedback', now.input.data.id, checked.refusal);\n setState((was) => ({ ...was, status: 'unavailable' }));\n latest.current.input.onInteraction?.({\n type: 'ai-help-refused',\n activityId: now.input.data.id,\n timestamp: Date.now(),\n payload: {\n feature: 'writing-feedback',\n reason: checked.refusal,\n draftNumber: request.draftNumber,\n },\n });\n return;\n }\n const { feedback } = checked;\n setState((was) => ({\n ...was,\n shown: was.key === key ? [...was.shown, { feedback, about }] : was.shown,\n status: 'idle',\n }));\n latest.current.input.onInteraction?.({\n type: 'ai-writing-feedback-shown',\n activityId: now.input.data.id,\n timestamp: Date.now(),\n payload: {\n draftNumber: request.draftNumber,\n corrections: feedback.corrections.length,\n ...(feedback.indicativeScore !== null\n ? { indicativeScore: feedback.indicativeScore }\n : {}),\n ...shownPayload(feedback),\n },\n });\n },\n () => {\n if (run.current === mine) {\n setState((was) => ({ ...was, status: 'unavailable' }));\n }\n },\n );\n }, []);\n\n const last = current.shown[current.shown.length - 1];\n return {\n offered,\n status: current.status,\n feedback: current.shown.map((one) => one.feedback),\n latest: last?.feedback ?? null,\n current: last !== undefined && last.about === draftOf(response),\n limit,\n used: current.shown.length,\n ask,\n };\n}\n"]}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var chunkOD65OZIW_cjs = require('./chunk-OD65OZIW.cjs');
|
|
5
|
-
var
|
|
6
|
-
var
|
|
5
|
+
var chunkFISEZBLF_cjs = require('./chunk-FISEZBLF.cjs');
|
|
6
|
+
var chunk54DX6SLS_cjs = require('./chunk-54DX6SLS.cjs');
|
|
7
7
|
var chunkNFGUJ52G_cjs = require('./chunk-NFGUJ52G.cjs');
|
|
8
8
|
var lkCore = require('@intellectif/lk-core');
|
|
9
9
|
var react = require('react');
|
|
@@ -92,13 +92,19 @@ function readDetail(value) {
|
|
|
92
92
|
return null;
|
|
93
93
|
}
|
|
94
94
|
const { itemId, correct, outcome, learnerResponse, correctResponse, weight, score } = value;
|
|
95
|
-
if (typeof itemId !== "string" ||
|
|
95
|
+
if (typeof itemId !== "string" || !isResponse(learnerResponse) || !isResponse(correctResponse)) {
|
|
96
96
|
return null;
|
|
97
97
|
}
|
|
98
98
|
const checkedOutcome = OUTCOMES.find((known) => known === outcome);
|
|
99
99
|
if (!isAbsent(outcome) && checkedOutcome === void 0) {
|
|
100
100
|
return null;
|
|
101
101
|
}
|
|
102
|
+
if (!isAbsent(correct) && typeof correct !== "boolean") {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
if (checkedOutcome === void 0 && typeof correct !== "boolean") {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
102
108
|
if (!isAbsent(weight) && !isFiniteNumber(weight)) {
|
|
103
109
|
return null;
|
|
104
110
|
}
|
|
@@ -108,10 +114,9 @@ function readDetail(value) {
|
|
|
108
114
|
}
|
|
109
115
|
return {
|
|
110
116
|
itemId,
|
|
111
|
-
correct,
|
|
112
117
|
learnerResponse,
|
|
113
118
|
correctResponse,
|
|
114
|
-
...checkedOutcome !== void 0 ? { outcome: checkedOutcome } : {},
|
|
119
|
+
...checkedOutcome !== void 0 ? { outcome: checkedOutcome } : { correct },
|
|
115
120
|
...!isAbsent(weight) ? { weight } : {},
|
|
116
121
|
...checkedScore !== void 0 ? { score: checkedScore } : {}
|
|
117
122
|
};
|
|
@@ -325,7 +330,7 @@ function PronunciationFeedback({
|
|
|
325
330
|
const [openWord, setOpenWord] = react.useState(null);
|
|
326
331
|
const checked = react.useMemo(() => checkEvidence(assessment), [assessment]);
|
|
327
332
|
const devError = react.useMemo(
|
|
328
|
-
() =>
|
|
333
|
+
() => chunk54DX6SLS_cjs.isDevelopment() && !checked.success ? new lkCore.ActivitySchemaError("read-aloud", checked.errors) : null,
|
|
329
334
|
[checked]
|
|
330
335
|
);
|
|
331
336
|
const words = react.useMemo(
|
|
@@ -532,7 +537,7 @@ function PronunciationFeedback({
|
|
|
532
537
|
}
|
|
533
538
|
function PronunciationFeedback2(props) {
|
|
534
539
|
const strings = chunkNFGUJ52G_cjs.useLkStrings(props.strings);
|
|
535
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
540
|
+
return /* @__PURE__ */ jsxRuntime.jsx(chunkFISEZBLF_cjs.ActivityErrorBoundary, { strings, children: /* @__PURE__ */ jsxRuntime.jsx(PronunciationFeedback, { ...props }) });
|
|
536
541
|
}
|
|
537
542
|
|
|
538
543
|
exports.PronunciationFeedback = PronunciationFeedback2;
|
|
@@ -544,5 +549,5 @@ exports.readAssessResult = readAssessResult;
|
|
|
544
549
|
exports.readEvidence = readEvidence;
|
|
545
550
|
exports.readOutcome = readOutcome;
|
|
546
551
|
exports.usePlaybackRefusal = usePlaybackRefusal;
|
|
547
|
-
//# sourceMappingURL=chunk-
|
|
548
|
-
//# sourceMappingURL=chunk-
|
|
552
|
+
//# sourceMappingURL=chunk-7F2YQWMW.cjs.map
|
|
553
|
+
//# sourceMappingURL=chunk-7F2YQWMW.cjs.map
|