@intellectif/lk-react 20.0.0 → 22.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 +42 -0
- package/README.md +33 -5
- package/dist/{WrittenResponse-D2YI8xOK.d.ts → WrittenResponse-CgRrjM4S.d.ts} +14 -4
- package/dist/{WrittenResponse-obIDDYDH.d.cts → WrittenResponse-D2K1VW_V.d.cts} +14 -4
- package/dist/ai/LkAiProvider.cjs +3 -3
- package/dist/ai/LkAiProvider.d.cts +17 -4
- package/dist/ai/LkAiProvider.d.ts +17 -4
- package/dist/ai/LkAiProvider.js +1 -1
- package/dist/ai/useAiHelp.cjs +9 -5
- package/dist/ai/useAiHelp.d.cts +58 -3
- package/dist/ai/useAiHelp.d.ts +58 -3
- package/dist/ai/useAiHelp.js +3 -3
- package/dist/{chunk-BGA2IVQY.js → chunk-3GLYK37F.js} +119 -26
- package/dist/chunk-3GLYK37F.js.map +1 -0
- package/dist/{chunk-LX2X4KC7.cjs → chunk-5YGVGMMV.cjs} +7 -7
- package/dist/{chunk-LX2X4KC7.cjs.map → chunk-5YGVGMMV.cjs.map} +1 -1
- package/dist/{chunk-3XP6VO4G.js → chunk-62K4Q565.js} +139 -45
- package/dist/chunk-62K4Q565.js.map +1 -0
- package/dist/{chunk-CEUEXISZ.cjs → chunk-6QY7GC55.cjs} +131 -50
- package/dist/chunk-6QY7GC55.cjs.map +1 -0
- package/dist/chunk-7EEKZWTQ.js +241 -0
- package/dist/chunk-7EEKZWTQ.js.map +1 -0
- package/dist/{chunk-3FBBP5QR.cjs → chunk-B4JRBV56.cjs} +6 -6
- package/dist/{chunk-3FBBP5QR.cjs.map → chunk-B4JRBV56.cjs.map} +1 -1
- package/dist/{chunk-RT2PP4SO.cjs → chunk-BL5SIBQA.cjs} +30 -30
- package/dist/{chunk-RT2PP4SO.cjs.map → chunk-BL5SIBQA.cjs.map} +1 -1
- package/dist/{chunk-YRNEOBXA.js → chunk-C4PSJ3ZC.js} +19 -2
- package/dist/chunk-C4PSJ3ZC.js.map +1 -0
- package/dist/{chunk-FEOFX4QW.js → chunk-FB47DQPS.js} +3 -3
- package/dist/{chunk-FEOFX4QW.js.map → chunk-FB47DQPS.js.map} +1 -1
- package/dist/chunk-FKNEHCNT.cjs +251 -0
- package/dist/chunk-FKNEHCNT.cjs.map +1 -0
- package/dist/{chunk-AG7MWZYZ.js → chunk-FPM2GQZY.js} +144 -55
- package/dist/chunk-FPM2GQZY.js.map +1 -0
- package/dist/{chunk-NWNQ2PHT.js → chunk-HNZ3JMAN.js} +8 -8
- package/dist/{chunk-NWNQ2PHT.js.map → chunk-HNZ3JMAN.js.map} +1 -1
- package/dist/{chunk-BY4UQH2Y.js → chunk-HYOUMTPW.js} +3 -3
- package/dist/{chunk-BY4UQH2Y.js.map → chunk-HYOUMTPW.js.map} +1 -1
- package/dist/{chunk-7K4B2EMU.js → chunk-HZIT24BK.js} +4 -4
- package/dist/{chunk-7K4B2EMU.js.map → chunk-HZIT24BK.js.map} +1 -1
- package/dist/{chunk-BJLQKJZX.cjs → chunk-J2QIHZ3H.cjs} +2 -2
- package/dist/chunk-J2QIHZ3H.cjs.map +1 -0
- package/dist/{chunk-DZVF3IGB.cjs → chunk-JII7XSCT.cjs} +59 -25
- package/dist/chunk-JII7XSCT.cjs.map +1 -0
- package/dist/{chunk-HI6BUUIJ.js → chunk-KFPCZ7N3.js} +48 -14
- package/dist/chunk-KFPCZ7N3.js.map +1 -0
- package/dist/{chunk-W6DMHN33.js → chunk-LRWFU3KS.js} +10 -10
- package/dist/{chunk-W6DMHN33.js.map → chunk-LRWFU3KS.js.map} +1 -1
- package/dist/{chunk-G7AGM2Y7.js → chunk-LX4JI262.js} +4 -4
- package/dist/{chunk-G7AGM2Y7.js.map → chunk-LX4JI262.js.map} +1 -1
- package/dist/{chunk-IXMT7X3E.cjs → chunk-M4UJBLVR.cjs} +17 -6
- package/dist/chunk-M4UJBLVR.cjs.map +1 -0
- package/dist/{chunk-AHGB5HH6.cjs → chunk-NFGUJ52G.cjs} +19 -2
- package/dist/chunk-NFGUJ52G.cjs.map +1 -0
- package/dist/{chunk-PWLJDP3X.cjs → chunk-NP5YC4NV.cjs} +95 -27
- package/dist/chunk-NP5YC4NV.cjs.map +1 -0
- package/dist/{chunk-ZDYNAWDZ.cjs → chunk-OJGTJOWI.cjs} +2 -2
- package/dist/chunk-OJGTJOWI.cjs.map +1 -0
- package/dist/{chunk-ORBU3XKH.js → chunk-PJMXHDY5.js} +16 -5
- package/dist/chunk-PJMXHDY5.js.map +1 -0
- package/dist/{chunk-TRMWBJWT.cjs → chunk-PZVRZ6OX.cjs} +141 -10
- package/dist/chunk-PZVRZ6OX.cjs.map +1 -0
- package/dist/{chunk-QKW2GGTV.js → chunk-R4ZNFDTK.js} +84 -16
- package/dist/chunk-R4ZNFDTK.js.map +1 -0
- package/dist/{chunk-YNDKAYW3.js → chunk-RX3A6KIY.js} +2 -2
- package/dist/chunk-RX3A6KIY.js.map +1 -0
- package/dist/{chunk-UHIOVOFK.cjs → chunk-TQN5CJO6.cjs} +125 -32
- package/dist/chunk-TQN5CJO6.cjs.map +1 -0
- package/dist/{chunk-AQIAQHJC.js → chunk-TRXUZSOY.js} +138 -8
- package/dist/chunk-TRXUZSOY.js.map +1 -0
- package/dist/{chunk-WBLYD5QA.js → chunk-U4KTOH7C.js} +2 -2
- package/dist/chunk-U4KTOH7C.js.map +1 -0
- package/dist/{chunk-L7WY5YFQ.cjs → chunk-UKUHVCZX.cjs} +5 -5
- package/dist/{chunk-L7WY5YFQ.cjs.map → chunk-UKUHVCZX.cjs.map} +1 -1
- package/dist/{chunk-HREA5SMB.cjs → chunk-UWFJGFB6.cjs} +116 -47
- package/dist/chunk-UWFJGFB6.cjs.map +1 -0
- package/dist/{chunk-JLDSCHY5.cjs → chunk-UXTYFEIC.cjs} +150 -61
- package/dist/chunk-UXTYFEIC.cjs.map +1 -0
- package/dist/{chunk-5GI53C6T.js → chunk-V2QZM2P2.js} +109 -40
- package/dist/chunk-V2QZM2P2.js.map +1 -0
- package/dist/{chunk-6S2CKZ4H.cjs → chunk-WFGDKBBP.cjs} +145 -51
- package/dist/chunk-WFGDKBBP.cjs.map +1 -0
- package/dist/{chunk-APZ6JFN6.cjs → chunk-Y5H4NOM6.cjs} +5 -5
- package/dist/{chunk-APZ6JFN6.cjs.map → chunk-Y5H4NOM6.cjs.map} +1 -1
- package/dist/{chunk-IQ55QNBI.js → chunk-YIXO6C4Z.js} +125 -44
- package/dist/chunk-YIXO6C4Z.js.map +1 -0
- package/dist/{chunk-LK5VXNMR.cjs → chunk-ZUE32Z67.cjs} +18 -18
- package/dist/{chunk-LK5VXNMR.cjs.map → chunk-ZUE32Z67.cjs.map} +1 -1
- package/dist/components/ActivityPreview.cjs +17 -17
- package/dist/components/ActivityPreview.d.cts +2 -2
- package/dist/components/ActivityPreview.d.ts +2 -2
- package/dist/components/ActivityPreview.js +16 -16
- package/dist/components/ActivitySequence.cjs +18 -18
- package/dist/components/ActivitySequence.d.cts +22 -4
- package/dist/components/ActivitySequence.d.ts +22 -4
- package/dist/components/ActivitySequence.js +17 -17
- package/dist/components/Dictation.cjs +10 -10
- package/dist/components/Dictation.d.cts +1 -1
- package/dist/components/Dictation.d.ts +1 -1
- package/dist/components/Dictation.js +9 -9
- package/dist/components/FillInTheBlanks.cjs +10 -10
- package/dist/components/FillInTheBlanks.d.cts +1 -1
- package/dist/components/FillInTheBlanks.d.ts +1 -1
- package/dist/components/FillInTheBlanks.js +9 -9
- package/dist/components/GapSelect.cjs +10 -10
- package/dist/components/GapSelect.d.cts +1 -1
- package/dist/components/GapSelect.d.ts +1 -1
- package/dist/components/GapSelect.js +9 -9
- package/dist/components/InteractiveVideo.cjs +17 -17
- package/dist/components/InteractiveVideo.d.cts +19 -3
- package/dist/components/InteractiveVideo.d.ts +19 -3
- package/dist/components/InteractiveVideo.js +15 -15
- package/dist/components/MultipleChoice.cjs +10 -10
- package/dist/components/MultipleChoice.d.cts +1 -1
- package/dist/components/MultipleChoice.d.ts +1 -1
- package/dist/components/MultipleChoice.js +9 -9
- package/dist/components/PronunciationFeedback.cjs +4 -4
- package/dist/components/PronunciationFeedback.d.cts +1 -1
- package/dist/components/PronunciationFeedback.d.ts +1 -1
- package/dist/components/PronunciationFeedback.js +3 -3
- package/dist/components/ReadAloud.cjs +8 -8
- package/dist/components/ReadAloud.d.cts +2 -2
- package/dist/components/ReadAloud.d.ts +2 -2
- package/dist/components/ReadAloud.js +7 -7
- package/dist/components/StimulusPanel.cjs +4 -4
- package/dist/components/StimulusPanel.d.cts +1 -1
- package/dist/components/StimulusPanel.d.ts +1 -1
- package/dist/components/StimulusPanel.js +3 -3
- package/dist/components/WrittenResponse.cjs +9 -7
- package/dist/components/WrittenResponse.d.cts +3 -3
- package/dist/components/WrittenResponse.d.ts +3 -3
- package/dist/components/WrittenResponse.js +8 -6
- package/dist/i18n/LkIntlProvider.cjs +7 -7
- package/dist/i18n/LkIntlProvider.d.cts +2 -2
- package/dist/i18n/LkIntlProvider.d.ts +2 -2
- package/dist/i18n/LkIntlProvider.js +1 -1
- package/dist/index.cjs +45 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +19 -19
- package/dist/index.js.map +1 -1
- package/dist/theme/skin.css +78 -0
- package/dist/{types-B_PCcqO-.d.cts → types-CO0XLEN6.d.cts} +67 -1
- package/dist/{types-C-GMCJ0g.d.ts → types-CrtIcRcK.d.ts} +67 -1
- package/package.json +3 -3
- package/dist/chunk-3XP6VO4G.js.map +0 -1
- package/dist/chunk-5GI53C6T.js.map +0 -1
- package/dist/chunk-6S2CKZ4H.cjs.map +0 -1
- package/dist/chunk-AG7MWZYZ.js.map +0 -1
- package/dist/chunk-AHGB5HH6.cjs.map +0 -1
- package/dist/chunk-AQIAQHJC.js.map +0 -1
- package/dist/chunk-BGA2IVQY.js.map +0 -1
- package/dist/chunk-BJLQKJZX.cjs.map +0 -1
- package/dist/chunk-CEUEXISZ.cjs.map +0 -1
- package/dist/chunk-DZVF3IGB.cjs.map +0 -1
- package/dist/chunk-HI6BUUIJ.js.map +0 -1
- package/dist/chunk-HREA5SMB.cjs.map +0 -1
- package/dist/chunk-IQ55QNBI.js.map +0 -1
- package/dist/chunk-IXMT7X3E.cjs.map +0 -1
- package/dist/chunk-JLDSCHY5.cjs.map +0 -1
- package/dist/chunk-NOC2M6LU.cjs +0 -118
- package/dist/chunk-NOC2M6LU.cjs.map +0 -1
- package/dist/chunk-ORBU3XKH.js.map +0 -1
- package/dist/chunk-PWLJDP3X.cjs.map +0 -1
- package/dist/chunk-QKW2GGTV.js.map +0 -1
- package/dist/chunk-RUS42NMN.js +0 -115
- package/dist/chunk-RUS42NMN.js.map +0 -1
- package/dist/chunk-TRMWBJWT.cjs.map +0 -1
- package/dist/chunk-UHIOVOFK.cjs.map +0 -1
- package/dist/chunk-WBLYD5QA.js.map +0 -1
- package/dist/chunk-YNDKAYW3.js.map +0 -1
- package/dist/chunk-YRNEOBXA.js.map +0 -1
- package/dist/chunk-ZDYNAWDZ.cjs.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/Dictation/Dictation.tsx","../src/components/Dictation/index.tsx"],"names":["characterDirectionOf","jsx","jsxs","Fragment","useLkStrings","useLearnerAi","useDeliveryPolicy","useMemo","isDevelopment","assertRedacted","result","validateActivity","ActivitySchemaError","useActivityState","useState","useRef","useEffect","useId","score","xAPIBuilder","ANONYMOUS_ACTOR","objectIdFor","xapiDefinitionFor","localeDirectionOf","alignDictation","diffDictationChars","textDirectionOf","ActivityMedia","DICTATION_MAX_TEXT_LENGTH","FeedbackRegion","outcomeShowsMarks","AiExplanation","Dictation","ActivityErrorBoundary"],"mappings":"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","file":"chunk-HREA5SMB.cjs","sourcesContent":["'use client';\n\nimport {\n type ActivityMedia as ActivityMediaData,\n ActivitySchemaError,\n alignDictation,\n assertRedacted,\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, 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 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 = detail.outcome !== undefined ? detail.outcome === 'correct' : detail.correct;\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}: 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\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 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\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 reset(defaultSubmittedRef.current === true ? 'completed' : 'idle');\n }, [data, reset]);\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 // 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\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 if (inactive || hintsShown === 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 scoringResult = score('dictation', data as DictationData, response);\n complete();\n const timeSpent = getTimeSpent();\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(scoringResult);\n onComplete?.({\n score: scoringResult.score,\n maxScore: scoringResult.maxScore,\n passed: scoringResult.passed,\n timeSpent,\n xapiStatement,\n });\n const correctWords = scoringResult.details.filter(\n (detail) => (detail.outcome ?? (detail.correct ? 'correct' : 'incorrect')) === 'correct',\n ).length;\n setSummary({\n text: `${s.answerSubmitted} ${s.scoreAnnouncement(\n Math.round(scoringResult.score * 100),\n scoringResult.passed,\n )} ${s.dictationWordsSummary(correctWords, scoringResult.details.length)}`,\n feedback: scoringResult.feedback,\n });\n fireInteraction('submitted', {\n length: text.length,\n hintsRevealed: reportedHints,\n score: scoringResult.score,\n });\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 const sentenceDiff = useMemo<DictationCharOp[] | null>(\n () =>\n alignment !== null && alignment.attempt !== ''\n ? diffDictationChars(alignment.reference, alignment.attempt)\n : null,\n [alignment],\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 s.dictationWordWrong(word.attempt, word.reference);\n case 'missing':\n return s.dictationWordMissing(word.reference);\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 return (\n <form\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 {hintsShown > 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\n ? { 'data-marks': 'characters' }\n : {})}\n >\n {word.status === 'incorrect' && alignment !== null ? (\n <CharOps\n ops={diffDictationChars(word.reference, word.attempt)}\n contentDir={contentDir}\n />\n ) : word.status === 'missing' ? (\n word.reference\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 && policy.solutions ? (\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 id={`${data.id}-feedback`}>\n <AnnouncementText\n announcement={\n isReview\n ? policy.feedback || !outcomeShowsMarks(outcome)\n ? reviewSummary\n : null\n : policy.feedback || summary === null\n ? summary\n : { text: s.answerSubmitted, feedback: null }\n }\n />\n </FeedbackRegion>\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 delivery={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"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/GapSelect/GapSelect.tsx","../src/components/GapSelect/index.tsx"],"names":["result","GapSelect","jsx"],"mappings":"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","file":"chunk-IQ55QNBI.js","sourcesContent":["'use client';\n\nimport {\n ActivitySchemaError,\n assertRedacted,\n type GapSelectBank,\n type GapSelectChoice,\n type GapSelectData,\n type GapSelectGap,\n type GapSelectLearnerResponse,\n type LearnerResponse,\n type ScoringDetail,\n type ScoringResult,\n score,\n seededShuffle,\n validateActivity,\n xAPIBuilder,\n xapiDefinitionFor,\n} from '@intellectif/lk-core';\nimport { type CSSProperties, useEffect, useMemo, useRef, useState } from 'react';\nimport { useLearnerAi } from '../../ai/LkAiProvider.js';\nimport { useActivityState } from '../../hooks/useActivityState.js';\nimport { useLkStrings } from '../../i18n/LkIntlProvider.js';\nimport { ANONYMOUS_ACTOR, isDevelopment, objectIdFor, randomSessionId } from '../_internal.js';\nimport { ActivityMedia } from '../shared/ActivityMedia.js';\nimport { AiExplanation, AiHints } from '../shared/AiHelp.js';\nimport { outcomeShowsMarks, useDeliveryPolicy } from '../shared/delivery.js';\nimport { FeedbackRegion } from '../shared/FeedbackRegion.js';\nimport type { ActivityProps } from '../types.js';\n\nexport interface GapSelectProps extends ActivityProps<GapSelectData> {\n /**\n * Seeds the per-gap choice shuffle when `data.shuffleChoices` is set. Pass\n * the attempt id, exactly as on `<MultipleChoice>`: an order nobody can\n * reproduce cannot be reconciled with the attempt a server recorded. Without\n * one, a random per-mount seed is used — stable within the mount, and\n * deliberately not reproducible.\n */\n shuffleSeed?: string;\n}\n\nconst PLACEHOLDER = /\\{\\{\\s*([^{}]+?)\\s*\\}\\}/g;\n\ntype Segment = { kind: 'text'; value: string } | { kind: 'gap'; id: string; ordinal: number };\n\n/** Splits a passage into literal text and its `{{id}}` gaps, in order. */\nfunction parsePassage(passage: string): Segment[] {\n const segments: Segment[] = [];\n const re = new RegExp(PLACEHOLDER);\n let last = 0;\n let ordinal = 0;\n let match = re.exec(passage);\n while (match !== null) {\n if (match.index > last) {\n segments.push({ kind: 'text', value: passage.slice(last, match.index) });\n }\n ordinal += 1;\n segments.push({ kind: 'gap', id: match[1] as string, ordinal });\n last = match.index + match[0].length;\n match = re.exec(passage);\n }\n if (last < passage.length) {\n segments.push({ kind: 'text', value: passage.slice(last) });\n }\n return segments;\n}\n\nconst NO_SELECTIONS: Record<string, string> = {};\n\n/**\n * The selections out of a `LearnerResponse`. A response of another activity\n * type reads as \"nothing selected\" rather than throwing — a controlled host\n * that has not yet swapped its state on an activity change would otherwise\n * crash the attempt.\n */\nfunction selectionsOf(response: LearnerResponse | undefined): Record<string, string> {\n return response !== undefined && response.type === 'gap-select'\n ? response.selections\n : NO_SELECTIONS;\n}\n\n/** Per-gap correctness keyed by gap id, preferring the unambiguous `outcome`. */\nfunction correctnessByItem(details: readonly ScoringDetail[]): Map<string, boolean> {\n const map = new Map<string, boolean>();\n for (const detail of details) {\n map.set(\n detail.itemId,\n detail.outcome !== undefined ? detail.outcome === 'correct' : detail.correct,\n );\n }\n return map;\n}\n\n/**\n * The choices a gap offers: its own list, or the bank it names.\n *\n * Both survive redaction — they are what the learner picks from — so this is\n * the one resolution that works identically on full and redacted data.\n */\nfunction choicesFor(\n banks: readonly GapSelectBank[] | undefined,\n gap: GapSelectGap,\n): readonly GapSelectChoice[] {\n if (gap.choices !== undefined) {\n return gap.choices;\n }\n return banks?.find((bank) => bank.id === gap.bankId)?.choices ?? [];\n}\n\nexport function GapSelect({\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 shuffleSeed,\n ai: aiProp,\n delivery,\n}: GapSelectProps) {\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\n const devError = useMemo(() => {\n if (!isDevelopment()) {\n return null;\n }\n if (data.redacted === true) {\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('gap-select', data);\n return result.success ? null : new ActivitySchemaError('gap-select', result.errors);\n }, [data]);\n\n const { state, start, complete, getTimeSpent, reset } = useActivityState(\n defaultSubmitted === true ? 'completed' : 'idle',\n );\n const isControlled = value !== undefined;\n const [internalSelections, setInternalSelections] = useState<Record<string, string>>(() =>\n selectionsOf(defaultValue),\n );\n const [result, setResult] = useState<ScoringResult | null>(null);\n const [summary, setSummary] = useState<string | null>(null);\n const [feedbackHidden, setFeedbackHidden] = useState(false);\n\n const selections = isControlled ? selectionsOf(value) : internalSelections;\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 setInternalSelections(selectionsOf(defaultValueRef.current));\n setResult(null);\n setSummary(null);\n setFeedbackHidden(false);\n reset(defaultSubmittedRef.current === true ? 'completed' : 'idle');\n }, [data, reset]);\n\n const segments = useMemo(() => parsePassage(data.passage), [data.passage]);\n const gapById = useMemo(() => new Map(data.gaps.map((gap) => [gap.id, gap])), [data.gaps]);\n\n const sessionIdRef = useRef<string | null>(null);\n /**\n * The choices each gap shows, in the order it shows them.\n *\n * Seeded PER GAP, not once for the activity: two gaps drawing on the same\n * word bank must not be dealt the same order, or the bank's distractors line\n * up column-wise and the second gap becomes easier than the first.\n */\n const choicesByGap = useMemo(() => {\n const map = new Map<string, readonly GapSelectChoice[]>();\n // biome-ignore lint/suspicious/noAssignInExpressions: sanctioned lazy ref initialization\n const seedSource = shuffleSeed ?? (sessionIdRef.current ??= randomSessionId());\n for (const gap of data.gaps) {\n const choices = choicesFor(data.banks, gap);\n map.set(\n gap.id,\n data.shuffleChoices === true\n ? seededShuffle(choices, `${seedSource}:${data.id}:${gap.id}`)\n : choices,\n );\n }\n return map;\n }, [data, shuffleSeed]);\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 // answered. Fail at render instead, in production too, exactly as every other\n // built-in does.\n if (data.redacted === true && renderMode === 'practice') {\n throw new Error(\n `Gap Select \"${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: right and wrong, and the\n // author's feedback. A gap select never writes in the right choice, so\n // `solutions` has nothing here to hide.\n const marking = revealing && policy.feedback;\n\n const fireInteraction = (\n type: 'gap-selected' | 'submitted',\n payload: Record<string, unknown>,\n ): void => {\n onInteraction?.({ type, activityId: data.id, timestamp: Date.now(), payload });\n };\n\n const handleSelect = (gapId: string, choiceId: string): void => {\n if (inactive) {\n return;\n }\n if (state === 'idle') {\n start();\n }\n const next = { ...selections, [gapId]: choiceId };\n if (!isControlled) {\n setInternalSelections(next);\n }\n onChange?.({ type: 'gap-select', selections: next });\n fireInteraction('gap-selected', { gapId, choiceId });\n };\n\n const handleSubmit = (event: React.FormEvent): void => {\n event.preventDefault();\n if (inactive) {\n return;\n }\n const response: GapSelectLearnerResponse = { type: 'gap-select', selections };\n onSubmit?.(response);\n\n if (isExam) {\n // The client neither grades nor reveals: no score(), no read of any\n // answer-key field, no onComplete, and no xAPI statement — its\n // correctResponsesPattern IS the answer key.\n complete();\n setSummary(s.answerSubmitted);\n fireInteraction('submitted', { selections });\n return;\n }\n\n const scoringResult = score('gap-select', data as GapSelectData, response);\n complete();\n const timeSpent = getTimeSpent();\n const xapiStatement = xAPIBuilder.buildAnsweredStatement({\n actor: ANONYMOUS_ACTOR,\n object: {\n id: objectIdFor(data.id),\n name: { [data.locale ?? 'en-US']: data.title },\n ...xapiDefinitionFor(data),\n },\n scoringResult,\n timeSpentMs: timeSpent,\n response: JSON.stringify(selections),\n });\n setResult(scoringResult);\n onComplete?.({\n score: scoringResult.score,\n maxScore: scoringResult.maxScore,\n passed: scoringResult.passed,\n timeSpent,\n xapiStatement,\n });\n const overall = scoringResult.feedback;\n setSummary(\n `${s.answerSubmitted} ${s.scoreAnnouncement(\n Math.round(scoringResult.score * 100),\n scoringResult.passed,\n )}${overall ? ` ${overall}` : ''}`,\n );\n fireInteraction('submitted', { selections, score: scoringResult.score });\n };\n\n const correctByGap = useMemo(() => {\n if (isExam) {\n return new Map<string, boolean>();\n }\n if (isReview) {\n return outcome?.status === 'scored'\n ? correctnessByItem(outcome.details)\n : new Map<string, boolean>();\n }\n return correctnessByItem(result?.details ?? []);\n }, [isExam, isReview, outcome, result]);\n\n const reviewSummary = useMemo(() => {\n if (!isReview || outcome === undefined) {\n return null;\n }\n if (outcome.status === 'scored') {\n return `${s.scoreAnnouncement(Math.round(outcome.score * 100), outcome.passed)}${\n outcome.feedback ? ` ${outcome.feedback}` : ''\n }`;\n }\n if (outcome.status === 'deferred') {\n return s.notGradedYet;\n }\n if (outcome.status === 'graded') {\n const percent =\n outcome.maxScore > 0\n ? Math.round((outcome.score / outcome.maxScore) * 100)\n : Math.round(outcome.score * 100);\n return `${s.scoreAnnouncement(percent, outcome.passed)}${\n outcome.feedback ? ` ${outcome.feedback}` : ''\n }`;\n }\n return s.noGradeAvailable;\n }, [isReview, outcome, s]);\n\n const anyFeedback = data.gaps.some((gap) => gap.feedback !== undefined);\n\n return (\n <form\n className=\"lk-gs\"\n aria-label={data.title}\n lang={locale}\n data-render-mode={renderMode}\n style={theme as CSSProperties | undefined}\n onSubmit={handleSubmit}\n >\n {data.media ? (\n <ActivityMedia\n media={data.media}\n renderMode={renderMode}\n {...(mediaBudget !== undefined ? { mediaBudget } : {})}\n {...(mediaStrings !== undefined ? { mediaStrings } : {})}\n {...(strings !== undefined ? { strings } : {})}\n {...(onInteraction !== undefined ? { onInteraction } : {})}\n {...(locale !== undefined ? { locale } : {})}\n />\n ) : null}\n <fieldset disabled={inactive}>\n <p className=\"lk-gs-passage\">\n {segments.map((seg, i) => {\n if (seg.kind === 'text') {\n // biome-ignore lint/suspicious/noArrayIndexKey: passage segments are positional and static\n return <span key={`t${i}`}>{seg.value}</span>;\n }\n const gap = gapById.get(seg.id);\n if (!gap) {\n return null;\n }\n const choices = choicesByGap.get(seg.id) ?? [];\n const correctness = correctByGap.get(seg.id);\n // Read defensively and never in exam: a redact() projection omits\n // both at runtime while the type still says they are there.\n const gapFeedback = isExam ? undefined : gap.feedback;\n return (\n <span key={seg.id} className=\"lk-gs-gap\">\n <select\n className=\"lk-gs-select\"\n aria-label={s.gapLabel(seg.ordinal)}\n value={selections[seg.id] ?? ''}\n disabled={inactive}\n aria-disabled={inactive || undefined}\n data-correct={\n marking && correctness !== undefined ? String(correctness) : undefined\n }\n onChange={(e) => handleSelect(seg.id, e.target.value)}\n >\n {/*\n The empty entry is part of the contract, not a decoration.\n It is how a learner leaves a gap alone — and how they take\n an answer back — so \"not answered\" stays distinguishable\n from \"answered wrongly\" all the way into ItemOutcome, where\n the scorer reports it as `incorrect-omission`.\n */}\n <option value=\"\">{s.gapPlaceholder}</option>\n {choices.map((choice) => (\n <option key={choice.id} value={choice.id}>\n {choice.text}\n </option>\n ))}\n </select>\n {marking && !feedbackHidden && gapFeedback ? (\n <span\n className=\"lk-gs-gap-feedback\"\n role=\"note\"\n data-correct={correctness !== undefined ? String(correctness) : undefined}\n >\n {gapFeedback}\n </span>\n ) : null}\n </span>\n );\n })}\n </p>\n <AiHints\n ai={ai}\n data={data}\n renderMode={renderMode}\n submitted={submitted}\n disabled={disabled === true}\n response={{ type: 'gap-select', selections }}\n locale={locale}\n onInteraction={onInteraction}\n strings={s}\n delivery={policy}\n />\n {isReview ? null : (\n <button type=\"submit\" disabled={inactive}>\n {isExam ? s.submitAnswers : s.checkAnswers}\n </button>\n )}\n </fieldset>\n {marking && anyFeedback ? (\n <button\n type=\"button\"\n className=\"lk-gs-feedback-toggle\"\n aria-expanded={!feedbackHidden}\n onClick={() => setFeedbackHidden((h) => !h)}\n >\n {feedbackHidden ? s.showFeedback : s.hideFeedback}\n </button>\n ) : null}\n <FeedbackRegion id={`${data.id}-feedback`}>\n {isReview\n ? policy.feedback || !outcomeShowsMarks(outcome)\n ? reviewSummary\n : null\n : policy.feedback || summary === null\n ? summary\n : s.answerSubmitted}\n </FeedbackRegion>\n <AiExplanation\n ai={ai}\n data={data}\n renderMode={renderMode}\n submitted={submitted}\n response={{ type: 'gap-select', selections }}\n outcome={outcome}\n locale={locale}\n onInteraction={onInteraction}\n strings={s}\n delivery={policy}\n />\n </form>\n );\n}\n","'use client';\n\nimport { useLkStrings } from '../../i18n/LkIntlProvider.js';\nimport { ActivityErrorBoundary } from '../ActivityErrorBoundary.js';\nimport { GapSelect as GapSelectCore, type GapSelectProps } from './GapSelect.js';\n\nexport type { GapSelectProps } from './GapSelect.js';\n\n/**\n * Public Gap Select 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 GapSelect(props: GapSelectProps) {\n const strings = useLkStrings(props.strings);\n return (\n <ActivityErrorBoundary activityTitle={props.data?.title} strings={strings}>\n <GapSelectCore {...props} />\n </ActivityErrorBoundary>\n );\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/shared/delivery.ts","../src/components/shared/FeedbackRegion.tsx"],"names":["useContext","SequenceSlotContext","useEffect","isDevelopment","validateDeliveryPolicy","combineDeliveryPolicies","jsx"],"mappings":";;;;;;;;AAyBO,SAAS,kBACd,KAAA,EACwB;AACxB,EAAA,MAAM,MAAA,GAASA,gBAAA,CAAWC,qCAAmB,CAAA,EAAG,QAAA;AAChD,EAAA,MAAM,GAAA,GAAM,UAAU,KAAK,CAAA;AAE3B,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAACC,+BAAA,EAAc,IAAK,KAAA,KAAU,MAAA,IAAa,UAAU,IAAA,EAAM;AAC7D,MAAA;AAAA,IACF;AACA,IAAA,MAAM,OAAA,GAAUC,8BAAuB,KAAK,CAAA;AAC5C,IAAA,IAAI,CAAC,QAAQ,OAAA,EAAS;AACpB,MAAA,OAAA,CAAQ,IAAA;AAAA,QACN,6GAA6G,OAAA,CAAQ,MAAA,CAClH,GAAA,CAAI,CAAC,UAAU,CAAA,EAAG,KAAA,CAAM,IAAA,IAAQ,QAAQ,WAAM,KAAA,CAAM,OAAO,EAAE,CAAA,CAC7D,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,OACf;AAAA,IACF;AAAA,EACF,CAAA,EAAG,CAAC,GAAG,CAAC,CAAA;AACR,EAAA,OAAOC,8BAAA,CAAwB,OAAO,MAAM,CAAA;AAC9C;AAGA,SAAS,UAAU,KAAA,EAAwB;AACzC,EAAA,IAAI;AACF,IAAA,OAAO,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA,IAAK,EAAA;AAAA,EAClC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,OAAO,KAAK,CAAA;AAAA,EACrB;AACF;AAOO,SAAS,kBAAkB,OAAA,EAA2C;AAC3E,EAAA,OAAO,OAAA,EAAS,MAAA,KAAW,QAAA,IAAY,OAAA,EAAS,MAAA,KAAW,QAAA;AAC7D;ACjDO,SAAS,cAAA,CAAe,EAAE,EAAA,EAAI,SAAA,EAAW,UAAS,EAAwB;AAC/E,EAAA,uBACEC,cAAA,CAAC,SAAI,EAAA,EAAQ,SAAA,EAAsB,aAAU,QAAA,EAAS,aAAA,EAAY,QAC/D,QAAA,EACH,CAAA;AAEJ","file":"chunk-IXMT7X3E.cjs","sourcesContent":["'use client';\n\nimport {\n combineDeliveryPolicies,\n type DeliveryPolicy,\n type ItemOutcome,\n type ResolvedDeliveryPolicy,\n validateDeliveryPolicy,\n} from '@intellectif/lk-core';\nimport { useContext, useEffect } from 'react';\nimport { isDevelopment } from '../_internal.js';\nimport { SequenceSlotContext } from './sequence-slot.js';\n\n/**\n * The delivery policy a question is under: the one it was handed, and the one\n * of the paper around it, whichever is stricter setting by setting.\n *\n * The paper's comes from the slot channel, never from a prop, for the reason\n * the mode does: a host that draws its own question is expected to pass\n * `delivery` on and nothing makes it. A paper that switched hints off keeps\n * them off in every question it holds, however that question was drawn.\n *\n * A policy that would not pass `validateDeliveryPolicy` is still applied — a\n * setting nobody can read restricts — and a development build says so once.\n */\nexport function useDeliveryPolicy(\n given: DeliveryPolicy | null | undefined,\n): ResolvedDeliveryPolicy {\n const around = useContext(SequenceSlotContext)?.delivery;\n const key = policyKey(given);\n // biome-ignore lint/correctness/useExhaustiveDependencies: the policy's content is the trigger, not its identity\n useEffect(() => {\n if (!isDevelopment() || given === undefined || given === null) {\n return;\n }\n const checked = validateDeliveryPolicy(given);\n if (!checked.success) {\n console.warn(\n `learning-kit: this delivery policy is not valid, and its unreadable settings are applied as restrictions: ${checked.issues\n .map((issue) => `${issue.path || 'policy'} — ${issue.message}`)\n .join('; ')}`,\n );\n }\n }, [key]);\n return combineDeliveryPolicies(given, around);\n}\n\n/** A policy's content as a string, so a new object with the same settings is the same policy. */\nfunction policyKey(given: unknown): string {\n try {\n return JSON.stringify(given) ?? '';\n } catch {\n return String(given);\n }\n}\n\n/**\n * Whether reading an outcome back says how the answer was marked — a score, a\n * pass or a fail — which a policy without `feedback` does not show. \"Not graded\n * yet\" and \"No grade available\" say nothing about the answer, and stay.\n */\nexport function outcomeShowsMarks(outcome: ItemOutcome | undefined): boolean {\n return outcome?.status === 'scored' || outcome?.status === 'graded';\n}\n","import type { ReactNode } from 'react';\n\nexport interface FeedbackRegionProps {\n /** Identifier so activity inputs can reference this region via aria. */\n id?: string;\n className?: string;\n children?: ReactNode;\n}\n\n/**\n * A polite ARIA live region. Screen readers announce content injected here\n * (score, feedback, state changes) without moving focus. Pure/presentational\n * — safe to render in any environment.\n */\nexport function FeedbackRegion({ id, className, children }: FeedbackRegionProps) {\n return (\n <div id={id} className={className} aria-live=\"polite\" aria-atomic=\"true\">\n {children}\n </div>\n );\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/MultipleChoice/MultipleChoice.tsx","../src/components/MultipleChoice/index.tsx"],"names":["useLkStrings","useLearnerAi","useDeliveryPolicy","useMemo","isDevelopment","validateActivity","ActivitySchemaError","useRef","useActivityState","useState","useEffect","randomSessionId","seededShuffle","score","xAPIBuilder","ANONYMOUS_ACTOR","objectIdFor","xapiDefinitionFor","jsxs","jsx","Fragment","ActivityMedia","AiHints","FeedbackRegion","outcomeShowsMarks","AiExplanation","MultipleChoice","ActivityErrorBoundary"],"mappings":"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","file":"chunk-JLDSCHY5.cjs","sourcesContent":["'use client';\n\nimport {\n ActivitySchemaError,\n type ItemOutcome,\n type LearnerResponse,\n type MultipleChoiceData,\n type MultipleChoiceLearnerResponse,\n type MultipleChoiceOption,\n type ScoringDetail,\n score,\n seededShuffle,\n validateActivity,\n xAPIBuilder,\n xapiDefinitionFor,\n} from '@intellectif/lk-core';\nimport { type CSSProperties, Fragment, useEffect, useMemo, useRef, useState } from 'react';\nimport { useLearnerAi } from '../../ai/LkAiProvider.js';\nimport { useActivityState } from '../../hooks/useActivityState.js';\nimport { useLkStrings } from '../../i18n/LkIntlProvider.js';\nimport type { LkStrings } from '../../i18n/strings.js';\nimport { ANONYMOUS_ACTOR, isDevelopment, objectIdFor, randomSessionId } from '../_internal.js';\nimport { ActivityMedia } from '../shared/ActivityMedia.js';\nimport { AiExplanation, AiHints } from '../shared/AiHelp.js';\nimport { outcomeShowsMarks, useDeliveryPolicy } from '../shared/delivery.js';\nimport { FeedbackRegion } from '../shared/FeedbackRegion.js';\nimport type { ActivityProps } from '../types.js';\n\n/**\n * Selected option ids carried by a learner response. Any other response shape\n * (a caller wiring the wrong item's state through `value`) reads as \"nothing\n * selected\" rather than throwing mid-exam.\n */\nfunction selectionOf(response: LearnerResponse | undefined): string[] {\n return response?.type === 'multiple-choice' ? response.selectedOptionIds : [];\n}\n\n/**\n * Whether an option is part of the correct answer, derived from the SERVER's\n * outcome — review mode never holds an answer key of its own.\n * {@link ScoringDetail.outcome} states this unambiguously. For 0.2-era details\n * that carry only the deprecated `correct` flag (which means \"the learner\n * ACTED correctly on this option\", not \"this option is the answer\") the fact\n * is still recoverable, because we know whether the learner selected it:\n * `isCorrect = wasSelected ? correct : !correct`.\n */\nfunction isAnswerOption(detail: ScoringDetail, wasSelected: boolean): boolean {\n switch (detail.outcome) {\n case 'correct':\n case 'incorrect-omission':\n return true;\n case 'incorrect':\n case 'correct-omission':\n return false;\n default:\n return wasSelected ? detail.correct : !detail.correct;\n }\n}\n\n/**\n * Announcement for `review` mode, built only from the server-supplied outcome.\n *\n * The authored overall feedback is appended by this function rather than being\n * baked into the score sentence, so a translation of \"Score 80%. Passed.\" never\n * has to carry the author's words with it.\n */\nfunction reviewAnnouncement(outcome: ItemOutcome | undefined, s: LkStrings): string | null {\n if (outcome === undefined) {\n return null;\n }\n if (outcome.status === 'scored') {\n const overall = outcome.feedback;\n return `${s.scoreAnnouncement(Math.round(outcome.score * 100), outcome.passed)}${\n overall ? ` ${overall}` : ''\n }`;\n }\n if (outcome.status === 'deferred') {\n // Never \"0%\": ungraded is not the same as wrong.\n return s.notGradedYet;\n }\n if (outcome.status === 'unscorable') {\n return s.noGradeAvailable;\n }\n // `graded` is left silent here deliberately: a returned GradeRecord on a\n // multiple-choice item has no rubric to render, and announcing a bare\n // percentage would duplicate what the marking already shows.\n return null;\n}\n\nexport interface MultipleChoiceProps extends ActivityProps<MultipleChoiceData> {\n /**\n * Seed for the deterministic option shuffle. Supply one (e.g. the attempt\n * id) to make the shuffled order reproducible server-side, stable across\n * page reloads, and identical between SSR and hydration. When absent, a\n * random per-mount session seed is used (order stable within the mount\n * only — the behaviour before `shuffleSeed` existed).\n */\n shuffleSeed?: string;\n}\n\nexport function MultipleChoice({\n data,\n onComplete,\n onSubmit,\n value,\n defaultValue,\n defaultSubmitted,\n onChange,\n renderMode = 'practice',\n outcome,\n sanitizeHtml,\n mediaBudget,\n mediaStrings,\n onInteraction,\n theme,\n locale,\n disabled,\n shuffleSeed,\n strings,\n ai: aiProp,\n delivery,\n}: MultipleChoiceProps) {\n const s = useLkStrings(strings);\n const ai = useLearnerAi(aiProp);\n const policy = useDeliveryPolicy(delivery);\n\n // Dev-only boundary validation (Req 2.3). Throwing during render lets\n // ActivityErrorBoundary catch it. Memoised so it only re-runs on data change.\n const devError = useMemo(() => {\n if (!isDevelopment()) {\n return null;\n }\n // A `redact()` projection cannot satisfy the full content schema — the\n // answer key is gone by design — and must not be checked against the\n // strict redacted schema either, since a `reveal: 'after-submit'`\n // projection legitimately carries answer-key fields for review renders.\n if (data.redacted === true) {\n return null;\n }\n const result = validateActivity('multiple-choice', data);\n return result.success ? null : new ActivitySchemaError('multiple-choice', result.errors);\n }, [data]);\n\n // Lazily created only when shuffling without a caller seed: avoids calling\n // crypto.randomUUID (absent on non-secure http origins) unless needed.\n const sessionIdRef = useRef<string | null>(null);\n const { state, start, complete, getTimeSpent, reset } = useActivityState(\n defaultSubmitted === true ? 'completed' : 'idle',\n );\n // Uncontrolled state. `defaultValue` seeds the mount only (React convention);\n // to re-seed later, remount with a `key` or drive the component with `value`.\n const [internalSelection, setInternalSelection] = useState<string[]>(() =>\n selectionOf(defaultValue),\n );\n const [summary, setSummary] = useState<string | null>(null);\n\n // Reset on data-prop CHANGE (Req 3.7). The identity guard makes the mount\n // run a no-op, which it always was before `defaultValue` existed — without\n // it this effect would wipe the seed immediately after the first render.\n // (It also makes the reset StrictMode-safe: a remount with unchanged data\n // no longer discards the learner's selection.)\n // Resets back to `defaultValue`, not to empty. Clearing looked safer — it\n // cannot carry a stale answer into a different question — but `data`\n // identity is a poor proxy for \"different question\": a parent that builds\n // entries in render (`activities={raw.map(redact)}`, the documented exam\n // pattern) hands over a new object every render, and clearing wiped every\n // RESTORED answer on the first unrelated re-render, silently. `defaultValue`\n // is by definition the caller's seed for the CURRENT data, which is what\n // FillInTheBlanks already reset to; the two now agree.\n const defaultValueRef = useRef(defaultValue);\n useEffect(() => {\n defaultValueRef.current = defaultValue;\n }, [defaultValue]);\n // A data change must return the item to its SEED, submitted state included —\n // resetting to idle unlocked work the learner had already committed.\n const defaultSubmittedRef = useRef(defaultSubmitted);\n useEffect(() => {\n defaultSubmittedRef.current = defaultSubmitted;\n }, [defaultSubmitted]);\n const lastDataRef = useRef(data);\n useEffect(() => {\n if (lastDataRef.current === data) {\n return;\n }\n lastDataRef.current = data;\n setInternalSelection(selectionOf(defaultValueRef.current));\n setSummary(null);\n reset(defaultSubmittedRef.current === true ? 'completed' : 'idle');\n }, [data, reset]);\n\n const displayedOptions = useMemo<MultipleChoiceOption[]>(() => {\n if (!data.shuffle) {\n return [...data.options];\n }\n // biome-ignore lint/suspicious/noAssignInExpressions: sanctioned lazy ref initialization\n const seedSource = shuffleSeed ?? (sessionIdRef.current ??= randomSessionId());\n // The seed string is unchanged from when the algorithm lived in this file,\n // so an order a consumer recorded against a seed still reproduces.\n return seededShuffle(data.options, `${seedSource}:${data.id}`);\n }, [data, shuffleSeed]);\n\n // Per-option correctness for `review`, indexed by option id. Null unless the\n // caller supplied a SCORED outcome — the only source of truth this mode has.\n const reviewDetails = useMemo(() => {\n if (renderMode !== 'review' || outcome === undefined || outcome.status !== 'scored') {\n return null;\n }\n return new Map(outcome.details.map((detail) => [detail.itemId, detail]));\n }, [renderMode, outcome]);\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, which a redacted projection cannot support:\n // `score()` would throw from the submit handler — where no error boundary\n // can catch it — AFTER the learner has answered. Fail loudly at render\n // instead, in production too. Wiring an exam item into the self-grading\n // mode is precisely the accident `renderMode` exists to prevent.\n if (data.redacted === true && renderMode === 'practice') {\n throw new Error(\n `Multiple Choice \"${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 isSingle = data.mode === 'single';\n const isExam = renderMode === 'exam';\n const isReview = renderMode === 'review';\n const submitted = state === 'completed';\n const inactive = disabled === true || submitted || isReview;\n const isControlled = value !== undefined;\n const selected = isControlled ? selectionOf(value) : internalSelection;\n /**\n * Whether correctness and authored feedback may be shown. Practice earns it\n * by grading locally after submit; review shows what the server already\n * graded. Exam never reveals anything — not before, not after submit.\n */\n const reveal = isReview || (renderMode === 'practice' && submitted);\n /**\n * What the delivery policy lets that reveal show. `marks`: right and wrong at\n * all, and the author's feedback. `solutions`: the right answer where the\n * learner did not choose it — without it, only the options the learner chose\n * are marked, so a missed correct option is not given away.\n */\n const marks = reveal && policy.feedback;\n const solutions = marks && policy.solutions;\n\n const fireInteraction = (\n type: 'option-selected' | 'option-deselected' | 'submitted',\n payload: Record<string, unknown>,\n ): void => {\n onInteraction?.({ type, activityId: data.id, timestamp: Date.now(), payload });\n };\n\n /** Single funnel for every response change: owns state only when uncontrolled. */\n const emitChange = (selectedOptionIds: string[]): void => {\n if (!isControlled) {\n setInternalSelection(selectedOptionIds);\n }\n onChange?.({ type: 'multiple-choice', selectedOptionIds });\n };\n\n const selectSingle = (optionId: string): void => {\n if (inactive) {\n return;\n }\n if (state === 'idle') {\n start();\n }\n emitChange([optionId]);\n fireInteraction('option-selected', { optionId });\n };\n\n const toggleMulti = (optionId: string, checked: boolean): void => {\n if (inactive) {\n return;\n }\n if (state === 'idle') {\n start();\n }\n emitChange(checked ? [...selected, optionId] : selected.filter((id) => id !== optionId));\n fireInteraction(checked ? 'option-selected' : 'option-deselected', { optionId });\n };\n\n const handleSubmit = (event: React.FormEvent): void => {\n event.preventDefault();\n if (inactive) {\n return;\n }\n const response: MultipleChoiceLearnerResponse = {\n type: 'multiple-choice',\n selectedOptionIds: selected,\n };\n // Always first, and before anything that can throw: an exam runner must be\n // able to persist the raw response no matter what happens after.\n onSubmit?.(response);\n\n if (isExam) {\n // No score(), no answer key read, no onComplete, no xAPI — the server\n // grades. The announcement deliberately carries no correctness signal.\n complete();\n setSummary(s.answerSubmitted);\n fireInteraction('submitted', { selectedOptionIds: selected });\n return;\n }\n\n const scoringResult = score('multiple-choice', data as MultipleChoiceData, response);\n complete();\n const timeSpent = getTimeSpent();\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 // Activity-type IRI, interaction type and correct-responses pattern\n // come from the REGISTERED descriptor, so a consumer-registered type\n // gets correct interop without touching this component.\n ...xapiDefinitionFor(data),\n choices: data.options.map((option) => ({\n id: option.id,\n description: { [data.locale ?? 'en-US']: option.text },\n })),\n },\n scoringResult,\n timeSpentMs: timeSpent,\n response: selected.join(','),\n });\n onComplete?.({\n score: scoringResult.score,\n maxScore: scoringResult.maxScore,\n passed: scoringResult.passed,\n timeSpent,\n xapiStatement,\n });\n // Core selects the authored overall feedback on `passed` (B3 fix).\n const overall = scoringResult.feedback;\n setSummary(\n `${s.answerSubmitted} ${s.scoreAnnouncement(\n Math.round(scoringResult.score * 100),\n scoringResult.passed,\n )}${overall ? ` ${overall}` : ''}`,\n );\n fireInteraction('submitted', {\n selectedOptionIds: selected,\n score: scoringResult.score,\n });\n };\n\n const questionId = `${data.id}-question`;\n // Rich text renders ONLY through a caller-supplied sanitiser; without one we\n // fall back to the plain-text field, escaped by React (types.ts HtmlSanitizer).\n const questionHtml =\n sanitizeHtml !== undefined && data.questionHtml !== undefined\n ? sanitizeHtml(data.questionHtml)\n : null;\n\n const optionList = displayedOptions.map((option) => {\n const checked = selected.includes(option.id);\n // `data-correct` means \"this option is part of the correct answer\".\n let correctness: string | undefined;\n // An option the learner did not choose is marked only where solutions\n // show: marking the right one they missed would hand them the answer.\n const markable = marks && (solutions || checked);\n if (isReview) {\n const detail = reviewDetails?.get(option.id);\n correctness =\n !markable || detail === undefined ? undefined : String(isAnswerOption(detail, checked));\n } else if (markable) {\n correctness = String(option.isCorrect);\n }\n const media = option.media;\n // A picture goes INSIDE the label: it has no controls of its own, clicking\n // it is how a learner picks that option, and its `alt` joins the option's\n // accessible name. A recording cannot — see below.\n const picture =\n media?.type === 'image' ? (\n <img className=\"lk-mc-option-image\" src={media.url} alt={media.alt ?? ''} />\n ) : null;\n\n const label = (\n <label className=\"lk-mc-option\" data-correct={correctness}>\n <input\n type={isSingle ? 'radio' : 'checkbox'}\n name={isSingle ? `${data.id}-options` : undefined}\n value={option.id}\n checked={checked}\n disabled={inactive}\n aria-disabled={inactive || undefined}\n onChange={(e) =>\n isSingle ? selectSingle(option.id) : toggleMulti(option.id, e.target.checked)\n }\n />\n <span>{option.text}</span>\n {picture}\n {markable && option.feedback ? (\n <span className=\"lk-mc-option-feedback\" role=\"note\">\n {option.feedback}\n </span>\n ) : null}\n </label>\n );\n\n if (media?.type !== 'audio') {\n return <Fragment key={option.id}>{label}</Fragment>;\n }\n\n // A recording sits OUTSIDE the label, deliberately. A <label> activates its\n // control for any click inside it, so an <audio> nested in one would select\n // the option the moment the learner pressed play — and a listening item is\n // answered by comparing all the recordings before choosing any of them.\n // Selecting an option must stay something the learner does on purpose.\n return (\n <div className=\"lk-mc-option-media\" key={option.id}>\n {label}\n {/* biome-ignore lint/a11y/useMediaCaption: captions are optional in the data contract — a <track> is rendered when captionsUrl is provided; absence is the author's documented choice (Req 14.5) */}\n <audio\n className=\"lk-mc-option-audio\"\n src={media.url}\n controls\n preload=\"none\"\n aria-label={media.alt ?? option.text}\n >\n {media.captionsUrl ? (\n <track kind=\"captions\" src={media.captionsUrl} label={media.alt ?? option.text} />\n ) : null}\n </audio>\n </div>\n );\n });\n\n return (\n <div className=\"lk-mc\" lang={locale} style={theme as CSSProperties | undefined}>\n {data.media ? (\n <ActivityMedia\n media={data.media}\n renderMode={renderMode}\n {...(mediaBudget !== undefined ? { mediaBudget } : {})}\n {...(mediaStrings !== undefined ? { mediaStrings } : {})}\n {...(strings !== undefined ? { strings } : {})}\n {...(onInteraction !== undefined ? { onInteraction } : {})}\n {...(locale !== undefined ? { locale } : {})}\n />\n ) : null}\n <form onSubmit={handleSubmit}>\n <fieldset disabled={inactive}>\n {questionHtml === null ? (\n <legend id={questionId}>{data.question}</legend>\n ) : (\n <legend\n id={questionId}\n // biome-ignore lint/security/noDangerouslySetInnerHtml: HTML is the output of the caller-supplied sanitizeHtml (types.ts HtmlSanitizer contract)\n dangerouslySetInnerHTML={{ __html: questionHtml }}\n />\n )}\n {/*\n single: an explicit radiogroup is meaningful (fieldset's implicit\n role is `group`, not `radiogroup`). multi: the fieldset + legend\n already provide a named group — an explicit role=\"group\" here would\n be a redundant, duplicate same-named group in the a11y tree, so we\n use a plain layout div. (Refines the design ARIA sketch.)\n */}\n {isSingle ? (\n <div role=\"radiogroup\" aria-labelledby={questionId}>\n {optionList}\n </div>\n ) : (\n <div>{optionList}</div>\n )}\n <AiHints\n ai={ai}\n data={data}\n renderMode={renderMode}\n submitted={submitted}\n disabled={disabled === true}\n response={{ type: 'multiple-choice', selectedOptionIds: selected }}\n locale={locale}\n onInteraction={onInteraction}\n strings={s}\n delivery={policy}\n />\n {/* review is read-only: there is nothing left to submit. */}\n {isReview ? null : (\n <button type=\"submit\" disabled={inactive}>\n {s.submit}\n </button>\n )}\n </fieldset>\n </form>\n <FeedbackRegion id={`${data.id}-feedback`}>\n {isReview\n ? // A grade read back is feedback; \"not graded yet\" is not.\n policy.feedback || !outcomeShowsMarks(outcome)\n ? reviewAnnouncement(outcome, s)\n : null\n : // Without feedback a submit says only that it was received, as\n // an exam's does — the score still reaches `onComplete`.\n policy.feedback || summary === ''\n ? summary\n : s.answerSubmitted}\n </FeedbackRegion>\n <AiExplanation\n ai={ai}\n data={data}\n renderMode={renderMode}\n submitted={submitted}\n response={{ type: 'multiple-choice', selectedOptionIds: selected }}\n outcome={outcome}\n locale={locale}\n onInteraction={onInteraction}\n strings={s}\n delivery={policy}\n />\n </div>\n );\n}\n","'use client';\n\nimport { useLkStrings } from '../../i18n/LkIntlProvider.js';\nimport { ActivityErrorBoundary } from '../ActivityErrorBoundary.js';\nimport {\n MultipleChoice as MultipleChoiceCore,\n type MultipleChoiceProps,\n} from './MultipleChoice.js';\n\nexport type { MultipleChoiceProps } from './MultipleChoice.js';\n\n/**\n * Public Multiple Choice activity: the core component wrapped in\n * `ActivityErrorBoundary` so a render failure (incl. the dev schema-validation\n * throw) degrades to an accessible fallback instead of crashing the host.\n */\nexport function MultipleChoice(props: MultipleChoiceProps) {\n // Read here rather than in the boundary: a class component cannot call a\n // hook, and the fallback it renders is learner-facing text like any other.\n const strings = useLkStrings(props.strings);\n return (\n <ActivityErrorBoundary activityTitle={props.data?.title} strings={strings}>\n <MultipleChoiceCore {...props} />\n </ActivityErrorBoundary>\n );\n}\n"]}
|
package/dist/chunk-NOC2M6LU.cjs
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
var chunkTRMWBJWT_cjs = require('./chunk-TRMWBJWT.cjs');
|
|
5
|
-
var react = require('react');
|
|
6
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
7
|
-
|
|
8
|
-
function situation(input) {
|
|
9
|
-
const { data, response, submitted, renderMode, ai, locale, onInteraction, delivery } = input;
|
|
10
|
-
return {
|
|
11
|
-
data,
|
|
12
|
-
response,
|
|
13
|
-
submitted,
|
|
14
|
-
renderMode,
|
|
15
|
-
delivery,
|
|
16
|
-
...ai !== void 0 ? { ai } : {},
|
|
17
|
-
...locale !== void 0 ? { locale } : {},
|
|
18
|
-
...onInteraction !== void 0 ? { onInteraction } : {}
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
function AiExplanation({
|
|
22
|
-
outcome,
|
|
23
|
-
...rest
|
|
24
|
-
}) {
|
|
25
|
-
const s = rest.strings;
|
|
26
|
-
const help = chunkTRMWBJWT_cjs.useAiExplanation({
|
|
27
|
-
...situation(rest),
|
|
28
|
-
...outcome !== void 0 ? { outcome } : {}
|
|
29
|
-
});
|
|
30
|
-
const buttonRef = react.useRef(null);
|
|
31
|
-
const panelRef = react.useRef(null);
|
|
32
|
-
const refocus = react.useRef(false);
|
|
33
|
-
react.useEffect(() => {
|
|
34
|
-
if (help.status === "shown" && refocus.current) {
|
|
35
|
-
refocus.current = false;
|
|
36
|
-
panelRef.current?.focus();
|
|
37
|
-
}
|
|
38
|
-
if (help.status === "unavailable") {
|
|
39
|
-
refocus.current = false;
|
|
40
|
-
}
|
|
41
|
-
}, [help.status]);
|
|
42
|
-
if (!help.offered) {
|
|
43
|
-
return null;
|
|
44
|
-
}
|
|
45
|
-
const ask = () => {
|
|
46
|
-
refocus.current = typeof document !== "undefined" && document.activeElement === buttonRef.current;
|
|
47
|
-
help.ask();
|
|
48
|
-
};
|
|
49
|
-
const loading = help.status === "loading";
|
|
50
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "lk-ai", "data-state": help.status, children: [
|
|
51
|
-
help.explanation === null ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
52
|
-
"button",
|
|
53
|
-
{
|
|
54
|
-
ref: buttonRef,
|
|
55
|
-
type: "button",
|
|
56
|
-
className: "lk-ai-button",
|
|
57
|
-
"aria-busy": loading || void 0,
|
|
58
|
-
"aria-disabled": loading || void 0,
|
|
59
|
-
onClick: ask,
|
|
60
|
-
children: loading ? s.aiExplaining : s.aiExplain
|
|
61
|
-
}
|
|
62
|
-
) : null,
|
|
63
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { "aria-live": "polite", children: help.explanation !== null ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
64
|
-
"section",
|
|
65
|
-
{
|
|
66
|
-
ref: panelRef,
|
|
67
|
-
className: "lk-ai-panel",
|
|
68
|
-
tabIndex: -1,
|
|
69
|
-
"aria-label": s.aiExplanation,
|
|
70
|
-
children: [
|
|
71
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "lk-ai-heading", children: s.aiExplanation }),
|
|
72
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "lk-ai-text", children: help.explanation.text }),
|
|
73
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "lk-ai-notice", children: s.aiNotice })
|
|
74
|
-
]
|
|
75
|
-
}
|
|
76
|
-
) : help.status === "unavailable" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "lk-ai-unavailable", children: s.aiExplanationUnavailable }) : null })
|
|
77
|
-
] });
|
|
78
|
-
}
|
|
79
|
-
function AiHints({ disabled, ...rest }) {
|
|
80
|
-
const s = rest.strings;
|
|
81
|
-
const help = chunkTRMWBJWT_cjs.useAiHints({ ...situation(rest), disabled });
|
|
82
|
-
const used = help.used;
|
|
83
|
-
if (rest.ai?.hint === void 0 || !help.offered && used === 0) {
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
|
-
const loading = help.status === "loading";
|
|
87
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "lk-ai lk-ai-hint-area", "data-state": help.status, children: [
|
|
88
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { "aria-live": "polite", children: [
|
|
89
|
-
used > 0 ? /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "lk-ai-hints", "aria-label": s.aiHints, children: help.hints.map((hint, index) => (
|
|
90
|
-
// Hints are only ever appended, so a position is a stable key.
|
|
91
|
-
// biome-ignore lint/suspicious/noArrayIndexKey: an append-only list
|
|
92
|
-
/* @__PURE__ */ jsxRuntime.jsxs("li", { className: "lk-ai-hint", children: [
|
|
93
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "lk-ai-hint-label", children: s.aiHintNumber(index + 1) }),
|
|
94
|
-
" ",
|
|
95
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "lk-ai-text", children: hint.text })
|
|
96
|
-
] }, index)
|
|
97
|
-
)) }) : null,
|
|
98
|
-
help.status === "unavailable" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "lk-ai-unavailable", children: s.aiHintUnavailable }) : null
|
|
99
|
-
] }),
|
|
100
|
-
help.offered ? used < help.limit ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
101
|
-
"button",
|
|
102
|
-
{
|
|
103
|
-
type: "button",
|
|
104
|
-
className: "lk-ai-button",
|
|
105
|
-
"aria-busy": loading || void 0,
|
|
106
|
-
"aria-disabled": loading || void 0,
|
|
107
|
-
onClick: help.ask,
|
|
108
|
-
children: loading ? s.aiHintLoading : s.aiHint
|
|
109
|
-
}
|
|
110
|
-
) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "lk-ai-note", children: s.aiNoMoreHints }) : null,
|
|
111
|
-
used > 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "lk-ai-notice", children: s.aiNotice }) : null
|
|
112
|
-
] });
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
exports.AiExplanation = AiExplanation;
|
|
116
|
-
exports.AiHints = AiHints;
|
|
117
|
-
//# sourceMappingURL=chunk-NOC2M6LU.cjs.map
|
|
118
|
-
//# sourceMappingURL=chunk-NOC2M6LU.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/shared/AiHelp.tsx"],"names":["useAiExplanation","useRef","useEffect","jsx","jsxs","useAiHints"],"mappings":"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","file":"chunk-NOC2M6LU.cjs","sourcesContent":["'use client';\n\nimport type {\n InteractionEvent,\n ItemOutcome,\n LearnerResponse,\n ResolvedDeliveryPolicy,\n} from '@intellectif/lk-core';\nimport { useEffect, useRef } from 'react';\nimport type { LearnerAi } from '../../ai/LkAiProvider.js';\nimport { useAiExplanation, useAiHints } from '../../ai/useAiHelp.js';\nimport type { LkStrings } from '../../i18n/strings.js';\nimport type { RenderableActivity, RenderMode } from '../types.js';\n\ninterface Situation {\n ai: LearnerAi | undefined;\n data: RenderableActivity;\n renderMode: RenderMode;\n submitted: boolean;\n /** The learner's answer as it stands: submitted, restored, or being written. */\n response: LearnerResponse;\n /** The component's `locale`, the default language for what is written. */\n locale: string | undefined;\n onInteraction: ((event: InteractionEvent) => void) | undefined;\n strings: LkStrings;\n /** The policy the component resolved, the paper's included. */\n delivery: ResolvedDeliveryPolicy;\n}\n\n/** What the hooks take, from what a component holds: the optional half, without `undefined` values. */\nfunction situation(input: Situation): {\n data: RenderableActivity;\n response: LearnerResponse;\n submitted: boolean;\n renderMode: RenderMode;\n ai?: LearnerAi;\n locale?: string;\n onInteraction?: (event: InteractionEvent) => void;\n delivery: ResolvedDeliveryPolicy;\n} {\n const { data, response, submitted, renderMode, ai, locale, onInteraction, delivery } = input;\n return {\n data,\n response,\n submitted,\n renderMode,\n delivery,\n ...(ai !== undefined ? { ai } : {}),\n ...(locale !== undefined ? { locale } : {}),\n ...(onInteraction !== undefined ? { onInteraction } : {}),\n };\n}\n\n/**\n * \"Explain my answer\": the SDK's own surface over {@link useAiExplanation} — a\n * button, the explanation with who wrote it, and \"not available\" when a call\n * fails or its answer is refused.\n *\n * Nothing renders without a port, or where the rules say no explanation.\n */\nexport function AiExplanation({\n outcome,\n ...rest\n}: Situation & { outcome: ItemOutcome | undefined }) {\n const s = rest.strings;\n const help = useAiExplanation({\n ...situation(rest),\n ...(outcome !== undefined ? { outcome } : {}),\n });\n const buttonRef = useRef<HTMLButtonElement>(null);\n const panelRef = useRef<HTMLElement>(null);\n const refocus = useRef(false);\n\n // The button that asked goes away when the explanation arrives; focus moves\n // to what it asked for rather than falling to the page.\n useEffect(() => {\n if (help.status === 'shown' && refocus.current) {\n refocus.current = false;\n panelRef.current?.focus();\n }\n if (help.status === 'unavailable') {\n refocus.current = false;\n }\n }, [help.status]);\n\n if (!help.offered) {\n return null;\n }\n\n const ask = (): void => {\n refocus.current =\n typeof document !== 'undefined' && document.activeElement === buttonRef.current;\n help.ask();\n };\n\n const loading = help.status === 'loading';\n return (\n <div className=\"lk-ai\" data-state={help.status}>\n {help.explanation === null ? (\n <button\n ref={buttonRef}\n type=\"button\"\n className=\"lk-ai-button\"\n aria-busy={loading || undefined}\n aria-disabled={loading || undefined}\n onClick={ask}\n >\n {loading ? s.aiExplaining : s.aiExplain}\n </button>\n ) : null}\n <div aria-live=\"polite\">\n {help.explanation !== null ? (\n <section\n ref={panelRef}\n className=\"lk-ai-panel\"\n tabIndex={-1}\n aria-label={s.aiExplanation}\n >\n <p className=\"lk-ai-heading\">{s.aiExplanation}</p>\n <p className=\"lk-ai-text\">{help.explanation.text}</p>\n <p className=\"lk-ai-notice\">{s.aiNotice}</p>\n </section>\n ) : help.status === 'unavailable' ? (\n <p className=\"lk-ai-unavailable\">{s.aiExplanationUnavailable}</p>\n ) : null}\n </div>\n </div>\n );\n}\n\n/**\n * \"Get a hint\": the SDK's own surface over {@link useAiHints} — a button, the\n * hints given so far as a numbered list, and who wrote them.\n *\n * The hints stay listed after submit, so the learner can see what they were\n * given, but no more can be asked for. Another question starts with none.\n */\nexport function AiHints({ disabled, ...rest }: Situation & { disabled: boolean }) {\n const s = rest.strings;\n const help = useAiHints({ ...situation(rest), disabled });\n const used = help.used;\n\n if (rest.ai?.hint === undefined || (!help.offered && used === 0)) {\n return null;\n }\n\n const loading = help.status === 'loading';\n return (\n <div className=\"lk-ai lk-ai-hint-area\" data-state={help.status}>\n <div aria-live=\"polite\">\n {used > 0 ? (\n <ol className=\"lk-ai-hints\" aria-label={s.aiHints}>\n {help.hints.map((hint, index) => (\n // Hints are only ever appended, so a position is a stable key.\n // biome-ignore lint/suspicious/noArrayIndexKey: an append-only list\n <li key={index} className=\"lk-ai-hint\">\n <span className=\"lk-ai-hint-label\">{s.aiHintNumber(index + 1)}</span>{' '}\n <span className=\"lk-ai-text\">{hint.text}</span>\n </li>\n ))}\n </ol>\n ) : null}\n {help.status === 'unavailable' ? (\n <p className=\"lk-ai-unavailable\">{s.aiHintUnavailable}</p>\n ) : null}\n </div>\n {help.offered ? (\n used < help.limit ? (\n <button\n type=\"button\"\n className=\"lk-ai-button\"\n aria-busy={loading || undefined}\n aria-disabled={loading || undefined}\n onClick={help.ask}\n >\n {loading ? s.aiHintLoading : s.aiHint}\n </button>\n ) : (\n <p className=\"lk-ai-note\">{s.aiNoMoreHints}</p>\n )\n ) : null}\n {used > 0 ? <p className=\"lk-ai-notice\">{s.aiNotice}</p> : null}\n </div>\n );\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/shared/delivery.ts","../src/components/shared/FeedbackRegion.tsx"],"names":[],"mappings":";;;;;;AAyBO,SAAS,kBACd,KAAA,EACwB;AACxB,EAAA,MAAM,MAAA,GAAS,UAAA,CAAW,mBAAmB,CAAA,EAAG,QAAA;AAChD,EAAA,MAAM,GAAA,GAAM,UAAU,KAAK,CAAA;AAE3B,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,aAAA,EAAc,IAAK,KAAA,KAAU,MAAA,IAAa,UAAU,IAAA,EAAM;AAC7D,MAAA;AAAA,IACF;AACA,IAAA,MAAM,OAAA,GAAU,uBAAuB,KAAK,CAAA;AAC5C,IAAA,IAAI,CAAC,QAAQ,OAAA,EAAS;AACpB,MAAA,OAAA,CAAQ,IAAA;AAAA,QACN,6GAA6G,OAAA,CAAQ,MAAA,CAClH,GAAA,CAAI,CAAC,UAAU,CAAA,EAAG,KAAA,CAAM,IAAA,IAAQ,QAAQ,WAAM,KAAA,CAAM,OAAO,EAAE,CAAA,CAC7D,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,OACf;AAAA,IACF;AAAA,EACF,CAAA,EAAG,CAAC,GAAG,CAAC,CAAA;AACR,EAAA,OAAO,uBAAA,CAAwB,OAAO,MAAM,CAAA;AAC9C;AAGA,SAAS,UAAU,KAAA,EAAwB;AACzC,EAAA,IAAI;AACF,IAAA,OAAO,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA,IAAK,EAAA;AAAA,EAClC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,OAAO,KAAK,CAAA;AAAA,EACrB;AACF;AAOO,SAAS,kBAAkB,OAAA,EAA2C;AAC3E,EAAA,OAAO,OAAA,EAAS,MAAA,KAAW,QAAA,IAAY,OAAA,EAAS,MAAA,KAAW,QAAA;AAC7D;ACjDO,SAAS,cAAA,CAAe,EAAE,EAAA,EAAI,SAAA,EAAW,UAAS,EAAwB;AAC/E,EAAA,uBACE,GAAA,CAAC,SAAI,EAAA,EAAQ,SAAA,EAAsB,aAAU,QAAA,EAAS,aAAA,EAAY,QAC/D,QAAA,EACH,CAAA;AAEJ","file":"chunk-ORBU3XKH.js","sourcesContent":["'use client';\n\nimport {\n combineDeliveryPolicies,\n type DeliveryPolicy,\n type ItemOutcome,\n type ResolvedDeliveryPolicy,\n validateDeliveryPolicy,\n} from '@intellectif/lk-core';\nimport { useContext, useEffect } from 'react';\nimport { isDevelopment } from '../_internal.js';\nimport { SequenceSlotContext } from './sequence-slot.js';\n\n/**\n * The delivery policy a question is under: the one it was handed, and the one\n * of the paper around it, whichever is stricter setting by setting.\n *\n * The paper's comes from the slot channel, never from a prop, for the reason\n * the mode does: a host that draws its own question is expected to pass\n * `delivery` on and nothing makes it. A paper that switched hints off keeps\n * them off in every question it holds, however that question was drawn.\n *\n * A policy that would not pass `validateDeliveryPolicy` is still applied — a\n * setting nobody can read restricts — and a development build says so once.\n */\nexport function useDeliveryPolicy(\n given: DeliveryPolicy | null | undefined,\n): ResolvedDeliveryPolicy {\n const around = useContext(SequenceSlotContext)?.delivery;\n const key = policyKey(given);\n // biome-ignore lint/correctness/useExhaustiveDependencies: the policy's content is the trigger, not its identity\n useEffect(() => {\n if (!isDevelopment() || given === undefined || given === null) {\n return;\n }\n const checked = validateDeliveryPolicy(given);\n if (!checked.success) {\n console.warn(\n `learning-kit: this delivery policy is not valid, and its unreadable settings are applied as restrictions: ${checked.issues\n .map((issue) => `${issue.path || 'policy'} — ${issue.message}`)\n .join('; ')}`,\n );\n }\n }, [key]);\n return combineDeliveryPolicies(given, around);\n}\n\n/** A policy's content as a string, so a new object with the same settings is the same policy. */\nfunction policyKey(given: unknown): string {\n try {\n return JSON.stringify(given) ?? '';\n } catch {\n return String(given);\n }\n}\n\n/**\n * Whether reading an outcome back says how the answer was marked — a score, a\n * pass or a fail — which a policy without `feedback` does not show. \"Not graded\n * yet\" and \"No grade available\" say nothing about the answer, and stay.\n */\nexport function outcomeShowsMarks(outcome: ItemOutcome | undefined): boolean {\n return outcome?.status === 'scored' || outcome?.status === 'graded';\n}\n","import type { ReactNode } from 'react';\n\nexport interface FeedbackRegionProps {\n /** Identifier so activity inputs can reference this region via aria. */\n id?: string;\n className?: string;\n children?: ReactNode;\n}\n\n/**\n * A polite ARIA live region. Screen readers announce content injected here\n * (score, feedback, state changes) without moving focus. Pure/presentational\n * — safe to render in any environment.\n */\nexport function FeedbackRegion({ id, className, children }: FeedbackRegionProps) {\n return (\n <div id={id} className={className} aria-live=\"polite\" aria-atomic=\"true\">\n {children}\n </div>\n );\n}\n"]}
|