@intellectif/lk-react 19.0.0 → 21.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.
Files changed (176) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/README.md +31 -2
  3. package/dist/{WrittenResponse-DT_Yqbq1.d.cts → WrittenResponse-BVPmrmQL.d.cts} +8 -2
  4. package/dist/{WrittenResponse-CeHY5u3W.d.ts → WrittenResponse-IAJvvL-g.d.ts} +8 -2
  5. package/dist/ai/LkAiProvider.cjs +3 -3
  6. package/dist/ai/LkAiProvider.d.cts +5 -3
  7. package/dist/ai/LkAiProvider.d.ts +5 -3
  8. package/dist/ai/LkAiProvider.js +1 -1
  9. package/dist/ai/useAiHelp.cjs +5 -5
  10. package/dist/ai/useAiHelp.d.cts +8 -2
  11. package/dist/ai/useAiHelp.d.ts +8 -2
  12. package/dist/ai/useAiHelp.js +3 -3
  13. package/dist/{chunk-7NNMDZUU.js → chunk-5MO7ACSB.js} +10 -10
  14. package/dist/{chunk-7NNMDZUU.js.map → chunk-5MO7ACSB.js.map} +1 -1
  15. package/dist/{chunk-7K4B2EMU.js → chunk-5Q2KFIZQ.js} +4 -4
  16. package/dist/{chunk-7K4B2EMU.js.map → chunk-5Q2KFIZQ.js.map} +1 -1
  17. package/dist/{chunk-APZ6JFN6.cjs → chunk-6SNNMVBV.cjs} +5 -5
  18. package/dist/{chunk-APZ6JFN6.cjs.map → chunk-6SNNMVBV.cjs.map} +1 -1
  19. package/dist/{chunk-L7WY5YFQ.cjs → chunk-7JBXDQTD.cjs} +5 -5
  20. package/dist/{chunk-L7WY5YFQ.cjs.map → chunk-7JBXDQTD.cjs.map} +1 -1
  21. package/dist/{chunk-UXV3V5NH.js → chunk-AY3WN4FB.js} +27 -15
  22. package/dist/chunk-AY3WN4FB.js.map +1 -0
  23. package/dist/{chunk-XAIJNGTU.cjs → chunk-CB2A56Q7.cjs} +137 -51
  24. package/dist/chunk-CB2A56Q7.cjs.map +1 -0
  25. package/dist/chunk-CQ37UD4T.cjs +251 -0
  26. package/dist/chunk-CQ37UD4T.cjs.map +1 -0
  27. package/dist/{chunk-YRNEOBXA.js → chunk-EYLBSS4Y.js} +11 -2
  28. package/dist/chunk-EYLBSS4Y.js.map +1 -0
  29. package/dist/{chunk-AHGB5HH6.cjs → chunk-GHKMX5UT.cjs} +11 -2
  30. package/dist/chunk-GHKMX5UT.cjs.map +1 -0
  31. package/dist/chunk-GND3OBVE.js +241 -0
  32. package/dist/chunk-GND3OBVE.js.map +1 -0
  33. package/dist/{chunk-WKA6FUR4.cjs → chunk-GPGCBDBN.cjs} +66 -26
  34. package/dist/chunk-GPGCBDBN.cjs.map +1 -0
  35. package/dist/{chunk-55W2472T.cjs → chunk-GW3YIPDE.cjs} +18 -18
  36. package/dist/{chunk-55W2472T.cjs.map → chunk-GW3YIPDE.cjs.map} +1 -1
  37. package/dist/{chunk-JVWLXVYG.cjs → chunk-J2QIHZ3H.cjs} +2 -2
  38. package/dist/chunk-J2QIHZ3H.cjs.map +1 -0
  39. package/dist/{chunk-SEQTGOOU.js → chunk-KRM6DX47.js} +151 -50
  40. package/dist/chunk-KRM6DX47.js.map +1 -0
  41. package/dist/{chunk-2X2NZF46.cjs → chunk-LHFC2BCM.cjs} +104 -27
  42. package/dist/chunk-LHFC2BCM.cjs.map +1 -0
  43. package/dist/{chunk-G7AGM2Y7.js → chunk-M3K6BF5M.js} +4 -4
  44. package/dist/{chunk-G7AGM2Y7.js.map → chunk-M3K6BF5M.js.map} +1 -1
  45. package/dist/chunk-M4UJBLVR.cjs +55 -0
  46. package/dist/chunk-M4UJBLVR.cjs.map +1 -0
  47. package/dist/{chunk-YNDKAYW3.js → chunk-MCTNLUKO.js} +2 -2
  48. package/dist/{chunk-YNDKAYW3.js.map → chunk-MCTNLUKO.js.map} +1 -1
  49. package/dist/{chunk-ZDYNAWDZ.cjs → chunk-MPHX3Y42.cjs} +2 -2
  50. package/dist/{chunk-ZDYNAWDZ.cjs.map → chunk-MPHX3Y42.cjs.map} +1 -1
  51. package/dist/{chunk-YIYMBCPV.js → chunk-NDIKHMLJ.js} +19 -10
  52. package/dist/chunk-NDIKHMLJ.js.map +1 -0
  53. package/dist/{chunk-LX2X4KC7.cjs → chunk-NILHU555.cjs} +7 -7
  54. package/dist/{chunk-LX2X4KC7.cjs.map → chunk-NILHU555.cjs.map} +1 -1
  55. package/dist/{chunk-ZME5FMED.cjs → chunk-OKEN6NJL.cjs} +157 -54
  56. package/dist/chunk-OKEN6NJL.cjs.map +1 -0
  57. package/dist/chunk-PJMXHDY5.js +51 -0
  58. package/dist/chunk-PJMXHDY5.js.map +1 -0
  59. package/dist/{chunk-OWV7VRMQ.js → chunk-U2BX2RWY.js} +93 -16
  60. package/dist/chunk-U2BX2RWY.js.map +1 -0
  61. package/dist/{chunk-TEAVPUMX.js → chunk-U4KTOH7C.js} +2 -2
  62. package/dist/chunk-U4KTOH7C.js.map +1 -0
  63. package/dist/{chunk-FEOFX4QW.js → chunk-U6SEII5V.js} +3 -3
  64. package/dist/{chunk-FEOFX4QW.js.map → chunk-U6SEII5V.js.map} +1 -1
  65. package/dist/{chunk-XUQ4KRTT.cjs → chunk-W2P5RILE.cjs} +156 -55
  66. package/dist/chunk-W2P5RILE.cjs.map +1 -0
  67. package/dist/{chunk-XHF376ES.js → chunk-W6TWQY6S.js} +152 -49
  68. package/dist/chunk-W6TWQY6S.js.map +1 -0
  69. package/dist/{chunk-NGFTSRKO.cjs → chunk-WGHMWBEJ.cjs} +126 -48
  70. package/dist/chunk-WGHMWBEJ.cjs.map +1 -0
  71. package/dist/{chunk-5QCZZBOX.js → chunk-WNDNQ6NR.js} +120 -42
  72. package/dist/chunk-WNDNQ6NR.js.map +1 -0
  73. package/dist/{chunk-NZM3M5IR.cjs → chunk-WXESKL75.cjs} +47 -35
  74. package/dist/chunk-WXESKL75.cjs.map +1 -0
  75. package/dist/{chunk-BY4UQH2Y.js → chunk-X4YWXZ4J.js} +3 -3
  76. package/dist/{chunk-BY4UQH2Y.js.map → chunk-X4YWXZ4J.js.map} +1 -1
  77. package/dist/{chunk-KOFA54C7.js → chunk-XB2AHEU5.js} +55 -15
  78. package/dist/chunk-XB2AHEU5.js.map +1 -0
  79. package/dist/{chunk-NLTU5JFD.js → chunk-XM5Q2ZCH.js} +132 -46
  80. package/dist/chunk-XM5Q2ZCH.js.map +1 -0
  81. package/dist/{chunk-CQNKZ435.cjs → chunk-XZCMUDFP.cjs} +14 -12
  82. package/dist/chunk-XZCMUDFP.cjs.map +1 -0
  83. package/dist/{chunk-SXU26SFO.cjs → chunk-Y4IDF5UO.cjs} +20 -11
  84. package/dist/chunk-Y4IDF5UO.cjs.map +1 -0
  85. package/dist/{chunk-3FBBP5QR.cjs → chunk-YWJ5XJDU.cjs} +6 -6
  86. package/dist/{chunk-3FBBP5QR.cjs.map → chunk-YWJ5XJDU.cjs.map} +1 -1
  87. package/dist/{chunk-4NERCBOW.js → chunk-ZDDBWUUA.js} +10 -8
  88. package/dist/chunk-ZDDBWUUA.js.map +1 -0
  89. package/dist/components/ActivityPreview.cjs +17 -17
  90. package/dist/components/ActivityPreview.d.cts +2 -2
  91. package/dist/components/ActivityPreview.d.ts +2 -2
  92. package/dist/components/ActivityPreview.js +16 -16
  93. package/dist/components/ActivitySequence.cjs +18 -18
  94. package/dist/components/ActivitySequence.d.cts +34 -4
  95. package/dist/components/ActivitySequence.d.ts +34 -4
  96. package/dist/components/ActivitySequence.js +17 -17
  97. package/dist/components/Dictation.cjs +10 -10
  98. package/dist/components/Dictation.d.cts +1 -1
  99. package/dist/components/Dictation.d.ts +1 -1
  100. package/dist/components/Dictation.js +9 -9
  101. package/dist/components/FillInTheBlanks.cjs +10 -10
  102. package/dist/components/FillInTheBlanks.d.cts +1 -1
  103. package/dist/components/FillInTheBlanks.d.ts +1 -1
  104. package/dist/components/FillInTheBlanks.js +9 -9
  105. package/dist/components/GapSelect.cjs +10 -10
  106. package/dist/components/GapSelect.d.cts +1 -1
  107. package/dist/components/GapSelect.d.ts +1 -1
  108. package/dist/components/GapSelect.js +9 -9
  109. package/dist/components/InteractiveVideo.cjs +17 -17
  110. package/dist/components/InteractiveVideo.d.cts +32 -3
  111. package/dist/components/InteractiveVideo.d.ts +32 -3
  112. package/dist/components/InteractiveVideo.js +15 -15
  113. package/dist/components/MultipleChoice.cjs +10 -10
  114. package/dist/components/MultipleChoice.d.cts +1 -1
  115. package/dist/components/MultipleChoice.d.ts +1 -1
  116. package/dist/components/MultipleChoice.js +9 -9
  117. package/dist/components/PronunciationFeedback.cjs +4 -4
  118. package/dist/components/PronunciationFeedback.d.cts +1 -1
  119. package/dist/components/PronunciationFeedback.d.ts +1 -1
  120. package/dist/components/PronunciationFeedback.js +3 -3
  121. package/dist/components/ReadAloud.cjs +8 -8
  122. package/dist/components/ReadAloud.d.cts +2 -2
  123. package/dist/components/ReadAloud.d.ts +2 -2
  124. package/dist/components/ReadAloud.js +7 -7
  125. package/dist/components/StimulusPanel.cjs +4 -4
  126. package/dist/components/StimulusPanel.d.cts +1 -1
  127. package/dist/components/StimulusPanel.d.ts +1 -1
  128. package/dist/components/StimulusPanel.js +3 -3
  129. package/dist/components/WrittenResponse.cjs +7 -6
  130. package/dist/components/WrittenResponse.d.cts +3 -3
  131. package/dist/components/WrittenResponse.d.ts +3 -3
  132. package/dist/components/WrittenResponse.js +6 -5
  133. package/dist/i18n/LkIntlProvider.cjs +7 -7
  134. package/dist/i18n/LkIntlProvider.d.cts +2 -2
  135. package/dist/i18n/LkIntlProvider.d.ts +2 -2
  136. package/dist/i18n/LkIntlProvider.js +1 -1
  137. package/dist/index.cjs +41 -41
  138. package/dist/index.cjs.map +1 -1
  139. package/dist/index.d.cts +2 -2
  140. package/dist/index.d.ts +2 -2
  141. package/dist/index.js +19 -19
  142. package/dist/index.js.map +1 -1
  143. package/dist/theme/skin.css +55 -0
  144. package/dist/{types-BY-4S5Rd.d.ts → types-7lGlo0zE.d.ts} +56 -1
  145. package/dist/{types-DtPYG1hh.d.cts → types-Botf4Wqj.d.cts} +56 -1
  146. package/package.json +3 -3
  147. package/dist/chunk-2X2NZF46.cjs.map +0 -1
  148. package/dist/chunk-4NERCBOW.js.map +0 -1
  149. package/dist/chunk-5QCZZBOX.js.map +0 -1
  150. package/dist/chunk-AHGB5HH6.cjs.map +0 -1
  151. package/dist/chunk-BRPEB43C.cjs +0 -13
  152. package/dist/chunk-BRPEB43C.cjs.map +0 -1
  153. package/dist/chunk-CQNKZ435.cjs.map +0 -1
  154. package/dist/chunk-JVWLXVYG.cjs.map +0 -1
  155. package/dist/chunk-KGDGYRBL.cjs +0 -117
  156. package/dist/chunk-KGDGYRBL.cjs.map +0 -1
  157. package/dist/chunk-KOFA54C7.js.map +0 -1
  158. package/dist/chunk-NGFTSRKO.cjs.map +0 -1
  159. package/dist/chunk-NLTU5JFD.js.map +0 -1
  160. package/dist/chunk-NZM3M5IR.cjs.map +0 -1
  161. package/dist/chunk-OWV7VRMQ.js.map +0 -1
  162. package/dist/chunk-QRT2W5N5.js +0 -114
  163. package/dist/chunk-QRT2W5N5.js.map +0 -1
  164. package/dist/chunk-RCMYEWBE.js +0 -11
  165. package/dist/chunk-RCMYEWBE.js.map +0 -1
  166. package/dist/chunk-SEQTGOOU.js.map +0 -1
  167. package/dist/chunk-SXU26SFO.cjs.map +0 -1
  168. package/dist/chunk-TEAVPUMX.js.map +0 -1
  169. package/dist/chunk-UXV3V5NH.js.map +0 -1
  170. package/dist/chunk-WKA6FUR4.cjs.map +0 -1
  171. package/dist/chunk-XAIJNGTU.cjs.map +0 -1
  172. package/dist/chunk-XHF376ES.js.map +0 -1
  173. package/dist/chunk-XUQ4KRTT.cjs.map +0 -1
  174. package/dist/chunk-YIYMBCPV.js.map +0 -1
  175. package/dist/chunk-YRNEOBXA.js.map +0 -1
  176. package/dist/chunk-ZME5FMED.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","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","AiExplanation","Dictation","ActivityErrorBoundary"],"mappings":"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","file":"chunk-NGFTSRKO.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 { 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}: DictationProps) {\n const isExam = renderMode === 'exam';\n const isReview = renderMode === 'review';\n const s = useLkStrings(strings);\n const ai = useLearnerAi(aiProp);\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\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 data.hints?.mode === 'progressive-words' && !isExam && !isReview && 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 revealing && transcript !== undefined && (!isReview || hasResponse)\n ? alignDictation(data, text)\n : null,\n [revealing, 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 = revealing && 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 revealing && 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 ? (\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 announcement={isReview ? reviewSummary : summary} />\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 />\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-NLTU5JFD.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 { 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}: GapSelectProps) {\n const isExam = renderMode === 'exam';\n const isReview = renderMode === 'review';\n const s = useLkStrings(strings);\n const ai = useLearnerAi(aiProp);\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\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 revealing && 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 {revealing && !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 />\n {isReview ? null : (\n <button type=\"submit\" disabled={inactive}>\n {isExam ? s.submitAnswers : s.checkAnswers}\n </button>\n )}\n </fieldset>\n {revealing && 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 ? reviewSummary : summary}\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 />\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/capture-registry.ts","../src/components/ReadAloud/recording-bounds.ts","../src/components/ReadAloud/ReadAloud.tsx","../src/components/ReadAloud/index.tsx"],"names":["READ_ALOUD_MAX_SECONDS","READ_ALOUD_MAX_TAKES","jsxs","Fragment","jsx","percentOfGrade","useLkStrings","useContext","SequenceSlotContext","useMemo","isDevelopment","assertRedacted","validateActivity","ActivitySchemaError","useSpeechRecorder","useActivityState","useState","useId","useRef","useEffect","take","useCallback","usePlaybackRefusal","readAssessResult","stampTake","xAPIBuilder","ANONYMOUS_ACTOR","objectIdFor","xapiDefinitionFor","fractionOfGrade","mintTake","localeDirectionOf","readOutcome","readEvidence","ActivityMedia","PronunciationFeedback","markSentence","VISUALLY_HIDDEN","state","FeedbackRegion","ReadAloud","ActivityErrorBoundary"],"mappings":"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","file":"chunk-NZM3M5IR.cjs","sourcesContent":["'use client';\n\n/**\n * Microphone captures that must stop when the region holding them goes away,\n * keyed by group name.\n *\n * Module-level for the reason `playback-group.ts` is: the thing that knows a\n * pane was hidden — the sequence — is not the thing holding the microphone,\n * and a context would have to be threaded through every activity component to\n * reach one. The caller mints the group name per region; a sequence uses the\n * slot's, so hiding one slot stops that slot's capture and no other's. The name\n * reaches a recorder only through `SequenceSlotContext`, never as a prop, so no\n * consumer string can join another region's group.\n *\n * This **supplements** a recorder's own teardown and never replaces it. The\n * sequence's pane effect runs only on a `hidden` transition, not on unmount,\n * and neither a preview nor a standalone render has panes at all — so a\n * component that records still releases the microphone from its own cleanup,\n * and this registry only covers the case where the component is left mounted\n * and merely hidden.\n *\n * No `useCaptureGroup` hook, unlike playback: that one re-registers after every\n * commit because the element behind a ref can be replaced while the ref object\n * is not, whereas a recorder's `stop` keeps one identity for the life of the\n * hook and a plain effect registers it exactly once.\n */\nconst groups = new Map<string, Set<() => void>>();\n\n/** Adds a capture's stop to a group; returns the matching removal. */\nexport function joinCaptureGroup(group: string, stop: () => void): () => void {\n let members = groups.get(group);\n if (members === undefined) {\n members = new Set();\n groups.set(group, members);\n }\n members.add(stop);\n return () => {\n const current = groups.get(group);\n if (current === undefined) {\n return;\n }\n current.delete(stop);\n if (current.size === 0) {\n groups.delete(group);\n }\n };\n}\n\n/**\n * Stops every capture in the group.\n *\n * The members are copied before they are called. Each `stop` is expected to\n * run its own removal, and a component that answers one by starting again\n * would otherwise be stopped by the sweep that its own stop provoked.\n */\nexport function stopCaptureGroup(group: string): void {\n const members = groups.get(group);\n if (members === undefined) {\n return;\n }\n for (const stop of [...members]) {\n stop();\n }\n}\n","'use client';\n\nimport { READ_ALOUD_MAX_SECONDS, READ_ALOUD_MAX_TAKES } from '@intellectif/lk-core';\n\n/** The bounds a take is captured under, as the recorder and the sentences use them. */\nexport interface RecordingBounds {\n /** Above 0, and at most `READ_ALOUD_MAX_SECONDS`. */\n maxSeconds: number;\n /** At least 0 and below `maxSeconds`, or `undefined` for no minimum. */\n minSeconds: number | undefined;\n /** A whole number from 1 to `READ_ALOUD_MAX_TAKES`, or `undefined` for no limit. */\n maxTakes: number | undefined;\n}\n\nconst isNumber = (value: unknown): value is number =>\n typeof value === 'number' && Number.isFinite(value);\n\n/**\n * The one reading of an item's `recording`: every bound the component captures\n * under, every sentence that names one, and the key that decides whether a new\n * `data` is a new reading all come from here, so no two of them can read the\n * same field differently.\n *\n * `practice` renders unvalidated content in production, so what comes in may\n * be anything a server stored. What comes out is always a set of bounds the\n * schema accepts, and bounds the schema accepts come out unchanged. Three\n * rules decide the rest, and each errs toward a take the learner can finish:\n *\n * - **A present bound that cannot be read is the schema's own ceiling**, never\n * no bound at all: a `maxSeconds` of `\"20\"` or `NaN` records up to\n * `READ_ALOUD_MAX_SECONDS`, and a `maxTakes` of `\"1\"` allows\n * `READ_ALOUD_MAX_TAKES`. Unreadable data can make the recorder stricter\n * than the ceiling, never looser: `maxTakes: \"1\"` used to mean unlimited\n * takes. `null` is an absent optional, as it is everywhere a host sends JSON.\n * - **A count is a whole number in range**: `0` and `1.5` read as `1`, `999`\n * as the ceiling.\n * - **A minimum the maximum cannot reach is no minimum.** A `minSeconds` of 30\n * under a `maxSeconds` of 20 stopped every take at 20 and then refused it as\n * too short, so the item could never be answered. The schema refuses that\n * pair; a reading that honoured it would leave the learner a dead end.\n */\nexport function readRecordingBounds(recording: unknown): RecordingBounds {\n const bounds =\n typeof recording === 'object' && recording !== null\n ? (recording as Record<string, unknown>)\n : {};\n const maxSeconds =\n isNumber(bounds.maxSeconds) && bounds.maxSeconds > 0\n ? Math.min(bounds.maxSeconds, READ_ALOUD_MAX_SECONDS)\n : READ_ALOUD_MAX_SECONDS;\n const minSeconds =\n isNumber(bounds.minSeconds) && bounds.minSeconds >= 0 && bounds.minSeconds < maxSeconds\n ? bounds.minSeconds\n : undefined;\n const takes = bounds.maxTakes;\n const maxTakes =\n takes === undefined || takes === null\n ? undefined\n : isNumber(takes)\n ? Math.min(Math.max(1, Math.floor(takes)), READ_ALOUD_MAX_TAKES)\n : READ_ALOUD_MAX_TAKES;\n return { maxSeconds, minSeconds, maxTakes };\n}\n\n/**\n * A length of audio as the whole seconds a sentence says beside `maxSeconds`,\n * never more than it. A bound may be fractional — the schema allows 2.5 — and\n * rounding a take that ran to it said \"3 of 2.5 seconds\". Rounded to the\n * nearest second for a finished take, and down for the counter of one still\n * running, which should not reach its bound before the take does.\n */\nexport function secondsWithin(\n milliseconds: number,\n maxSeconds: number,\n rounding: 'nearest' | 'down',\n): number {\n const seconds = milliseconds / 1000;\n const whole = rounding === 'nearest' ? Math.round(seconds) : Math.floor(seconds);\n return Math.min(Math.max(0, whole), maxSeconds);\n}\n","'use client';\n\nimport {\n type ActivityMedia as ActivityMediaData,\n ActivitySchemaError,\n assertRedacted,\n type GradeRecord,\n type InteractionKind,\n type LearnerResponse,\n type MediaPlaybackPolicy,\n type ReadAloudData,\n type ReadAloudLearnerResponse,\n type ReadAloudWordAlignment,\n type RecordingRef,\n type ScoringDetail,\n type SpeechAssessment,\n validateActivity,\n xAPIBuilder,\n xapiDefinitionFor,\n} from '@intellectif/lk-core';\nimport {\n type CSSProperties,\n useCallback,\n useContext,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { useActivityState } from '../../hooks/useActivityState.js';\nimport type { RecordedTake, SpeechRecorderStatus } from '../../hooks/useSpeechRecorder.js';\nimport { useSpeechRecorder } from '../../hooks/useSpeechRecorder.js';\nimport { localeDirectionOf } from '../../i18n/direction.js';\nimport { useLkStrings } from '../../i18n/LkIntlProvider.js';\nimport type { LkStrings } from '../../i18n/strings.js';\nimport { ANONYMOUS_ACTOR, isDevelopment, objectIdFor } from '../_internal.js';\nimport { PronunciationFeedback } from '../PronunciationFeedback/index.js';\nimport { markSentence, VISUALLY_HIDDEN } from '../PronunciationFeedback/PronunciationFeedback.js';\nimport { ActivityMedia } from '../shared/ActivityMedia.js';\nimport { joinCaptureGroup } from '../shared/capture-registry.js';\nimport { FeedbackRegion } from '../shared/FeedbackRegion.js';\nimport { usePlaybackRefusal } from '../shared/playback-refusal.js';\nimport {\n fractionOfGrade,\n type OutcomeReading,\n percentOfGrade,\n type ReadGrade,\n readAssessResult,\n readEvidence,\n readOutcome,\n} from '../shared/read-grade.js';\nimport {\n mintTake,\n SequenceSlotContext,\n stampTake,\n type TakeState,\n} from '../shared/sequence-slot.js';\nimport type { ActivityProps, Renderable } from '../types.js';\nimport { readRecordingBounds, secondsWithin } from './recording-bounds.js';\n\n/**\n * Names playback groups for the model recordings. Per mount and never derived\n * from `useId`: two separately hydrated roots derive the same id for the same\n * tree position, and their recordings would pause each other. The name never\n * reaches the DOM.\n */\nlet modelsGroupCount = 0;\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\n/** A stored mark's id, as `gradeReadAloud` numbers the reference words. */\nconst MARK_ID_RE = /^w\\d+$/;\n\n/** The states a mark rebuilt from stored details can carry: insertions are not stored. */\nconst STORED_STATES: readonly ReadAloudWordAlignment['state'][] = [\n 'correct',\n 'mispronounced',\n 'omitted',\n];\n\n/** The level meter's resolution, in steps the skin can select on. */\nconst LEVEL_STEPS = 10;\n\n/**\n * What an application's assessor came back with.\n *\n * `code` is a plain `string` and not `SpeechUnscorableCode`: an application's\n * own assessor may refuse a take for a reason the SDK has no name for, and a\n * narrower type would make it unreportable. This component classifies the two\n * codes that mean \"nothing was heard\" and treats every other one the same way.\n */\nexport type ReadAloudAssessResult =\n | { status: 'graded'; assessment: SpeechAssessment; grade: GradeRecord }\n | { status: 'unscorable'; code: string; assessment?: SpeechAssessment }\n | { status: 'failed'; retryable: boolean };\n\n/**\n * How a take reaches the application, and how a judgement comes back.\n *\n * Named `recordingBinding` rather than `recording` because both\n * `ReadAloudData.recording` (the bounds) and `ReadAloudLearnerResponse.recording`\n * (the stored take) already exist: the plain name would read as one of those.\n */\nexport interface RecordingBinding {\n /**\n * Puts the take in your storage and returns its key. **Required** outside\n * `review`: without it a learner can speak into a control that submits\n * nothing. Settle it — a promise that never does leaves the submit pending\n * for ever.\n */\n upload(take: RecordedTake): Promise<RecordingRef>;\n /**\n * Judges the stored take. `practice` only — an exam never assesses on the\n * client. Optional: a binding without it records, uploads and submits, and\n * the feedback is replaced by a notice.\n */\n assess?(ref: RecordingRef): Promise<ReadAloudAssessResult>;\n /** A playable link to a stored take. `review` only. */\n playbackUrl?(ref: RecordingRef): Promise<string>;\n}\n\nexport interface ReadAloudProps extends ActivityProps<ReadAloudData> {\n /** How a take is stored and judged. See {@link RecordingBinding}. */\n recordingBinding?: RecordingBinding;\n /**\n * The evidence behind a stored grade, for `review`. Without it a graded\n * outcome still shows its marks, rebuilt from `outcome.grade.details`; with\n * neither, the score is shown and no marks are.\n */\n assessment?: SpeechAssessment;\n /**\n * Confidence above which a break note is shown, 0..1, forwarded to\n * {@link PronunciationFeedback}. No default — see its own prop.\n */\n breakThreshold?: number;\n /** The same, for the monotone note. */\n monotoneThreshold?: number;\n /**\n * The URL of a self-hosted copy of `CAPTURE_PROCESSOR_SOURCE`, handed to the\n * recorder, for a Content-Security-Policy whose `script-src` does not allow\n * `blob:`. Without it the capture module is loaded from a `blob:` URL, and a\n * policy that refuses one sends every take through the deprecated\n * main-thread `ScriptProcessorNode` — a take that still records, so nothing\n * says so. See `useSpeechRecorder`'s option of the same name.\n */\n workletUrl?: string;\n /**\n * Never called. A read-aloud answer is a key in your storage, and there is\n * none until the take has been uploaded — so there is no intermediate\n * response to report, and reporting the take itself would offer a host a\n * recording it has nowhere to put. `onSubmit` carries the response, once.\n */\n onChange?: (response: LearnerResponse) => void;\n}\n\n/** What the live region says: the SDK's own sentence, then any grader feedback. */\ninterface Announcement {\n text: string;\n feedback: string | null;\n}\n\n/**\n * How far the submitted take has got. `idle` also means \"nothing submitted yet\".\n *\n * Every other phase names its `take`, the number `mintTake` gave the submit\n * that reached it: a phase describes one take, and a pager told about it must\n * be able to tell that take from the one before it.\n */\ntype SubmitPhase =\n | { kind: 'idle' }\n | { kind: 'uploading'; take: number }\n | { kind: 'upload-failed'; take: number }\n | { kind: 'assessing'; take: number }\n | { kind: 'submitted'; take: number }\n | { kind: 'unassessed'; take: number }\n /**\n * The assessor's judgement, as `readAssessResult` read it: `grade` is `null`\n * when what came back cannot be shown as a grade, and `assessment` is `null`\n * when there is no evidence to mark words from.\n */\n | {\n kind: 'graded';\n take: number;\n assessment: SpeechAssessment | null;\n grade: ReadGrade | null;\n }\n | { kind: 'unscorable'; take: number; code: string | undefined }\n | { kind: 'assess-failed'; take: number; retryable: boolean };\n\n/**\n * Whether the screen offers \"Try again\" for the take this phase describes —\n * the one answer to that question, read by the button that offers it and by\n * the take state a pager is told, so the two cannot disagree. A retry re-sends\n * the SAME take: a take that failed to upload is sent again, and a stored take\n * whose assessment failed is judged again without being uploaded twice.\n */\nfunction offersRetry(phase: SubmitPhase, uploaded: RecordingRef | null): boolean {\n return (\n phase.kind === 'upload-failed' ||\n (phase.kind === 'assess-failed' && phase.retryable && uploaded !== null)\n );\n}\n\n/**\n * The state of the phase's take, as a pager deciding whether its set is\n * finished reads it. Derived from the phase alone, so no path through a submit\n * can leave a pager waiting on a take this component has finished with: every\n * path ends in a phase.\n */\nfunction takeStateOf(phase: SubmitPhase, uploaded: RecordingRef | null): TakeState {\n if (phase.kind === 'uploading' || phase.kind === 'assessing') {\n return 'in-flight';\n }\n return offersRetry(phase, uploaded) ? 'retryable' : 'settled';\n}\n\n/**\n * Whether the recorder is capturing, or about to: the one answer to \"is a take\n * being recorded\", read by everything that must hold still for one. A\n * permission prompt counts — a prompt answered after the pane went away would\n * otherwise open a microphone nobody is in front of, and a model recording\n * played while the prompt is up would be charged a play and then silenced.\n */\nfunction capturing(status: SpeechRecorderStatus): boolean {\n return status === 'recording' || status === 'requesting-permission';\n}\n\n/**\n * What a take is a take OF: the item, the words, their language and the bounds\n * the take is captured under. A change to any of these is a different reading,\n * and a take of the old one answers nothing.\n *\n * Deliberately NOT the identity of `data`. `redact()` returns a new object on\n * every call, and `activities={raw.map(redact)}` is a documented way to pass a\n * paper, so a host that rebuilds its items on every render is ordinary — and a\n * reset keyed on identity silently threw away every grade still in flight and\n * refunded the take budget on each of those renders, so a `maxTakes: 1` exam\n * accepted a second take. The title, the instructions and the model recordings\n * are presentation; editing them leaves the take a take of the same reading.\n *\n * The bounds are the CLAMPED ones, which are what the recorder is given. Read\n * field by field into strings, so no value unvalidated data carries can make\n * the key throw.\n */\nfunction readingKeyOf(\n data: Renderable<ReadAloudData>,\n bounds: { maxSeconds: number; minSeconds: number | undefined; maxTakes: number | undefined },\n): string {\n const text = (value: unknown): string | null => (typeof value === 'string' ? value : null);\n return JSON.stringify([\n text(data.id),\n text(data.referenceText),\n text(data.locale),\n String(bounds.maxSeconds),\n String(bounds.minSeconds),\n String(bounds.maxTakes),\n ]);\n}\n\n/**\n * The slower model recording as an `ActivityMedia`: it follows the model\n * recording's playback policy minus `maxPlays` (`controls`, `seek`, `rate`,\n * the native hints), so a locked scrubber or a fixed speed binds both files —\n * and it never carries a budget of its own, so `<ActivityMedia>` never demands\n * a binding for it. `undefined` when there is no slow recording.\n */\nfunction slowMediaFor(\n data: Renderable<ReadAloudData>,\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 * Word marks rebuilt from stored scoring details — a server-recorded mark shown\n * after the fact, with no assessment on the client. Inserted words are not in\n * the details (`gradeReadAloud` stores one mark per REFERENCE word, and a word\n * the learner added is not one the item asked for), so none appear.\n *\n * The details are a read grade's, so every entry is well-formed; what is left\n * to decide here is whether they are word marks at all, rather than a rubric's\n * own breakdown.\n */\nfunction marksFromDetails(details: readonly ScoringDetail[]): ReadAloudWordAlignment[] | null {\n if (details.length === 0 || !details.every((detail) => MARK_ID_RE.test(detail.itemId))) {\n return null;\n }\n return details.map((detail) => {\n const heard = 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 state: ReadAloudWordAlignment['state'] = correct\n ? 'correct'\n : detail.outcome === 'incorrect-omission'\n ? 'omitted'\n : 'mispronounced';\n return {\n itemId: detail.itemId,\n reference,\n heard,\n state,\n // `ScoringDetail.score` is the word's accuracy divided by 100; the marks\n // carry it back in the units the assessment used.\n ...(typeof detail.score === 'number' ? { accuracy: detail.score * 100 } : {}),\n };\n });\n}\n\n/** The stored take a learner response points at, or `null` for a blank or another type. */\nfunction recordingOf(response: LearnerResponse | undefined): RecordingRef | null {\n return response !== undefined && response.type === 'read-aloud' ? response.recording : null;\n}\n\n/** The response this component emits; `takes` is written only when one was made. */\nfunction responseOf(recording: RecordingRef | null, takes: number): ReadAloudLearnerResponse {\n return { type: 'read-aloud', recording, ...(takes > 0 ? { takes } : {}) };\n}\n\n/**\n * Which learner message an unscorable code earns. The two codes that mean\n * \"nothing was heard\" send the learner back to a quieter room; every other one,\n * the SDK's and an application's own alike — and no code at all — says only\n * that this take could not be assessed. **The code itself is never shown** — it\n * is a developer's label.\n */\nfunction unscorableMessage(code: string | undefined, s: LkStrings): string {\n return code === 'no_speech' || code === 'insufficient_voiced_time'\n ? s.readAloudNotHeard\n : s.readAloudNotAssessed;\n}\n\n/**\n * The announcement, with grader feedback in its own isolated span: its\n * direction is its own, so an English \"Well read.\" in an Arabic interface keeps\n * its full stop at its end. Its language is not guessed — feedback may be\n * written in the interface's language or the reading'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\n/**\n * The server's outcome in `review`, as `readOutcome` read it. Nothing on this\n * path scores, infers or defaults a grade.\n *\n * `scoreShown` says whether the grade is already on screen — it is, whenever\n * `<PronunciationFeedback>` was given the same grade — so the sentence is not\n * rendered twice. The wrapper and its attributes are rendered either way,\n * because they are what a stylesheet and a diagnostic read.\n */\nfunction OutcomeSummary({\n reading,\n s,\n scoreShown,\n}: {\n reading: OutcomeReading;\n s: LkStrings;\n scoreShown: boolean;\n}) {\n switch (reading.kind) {\n case 'graded':\n return (\n <div\n className=\"lk-ra-outcome\"\n data-status={reading.status}\n data-passed={String(reading.grade.passed)}\n >\n {scoreShown ? null : (\n <>\n <p className=\"lk-ra-grade\">\n {s.scoreAnnouncement(percentOfGrade(reading.grade), reading.grade.passed)}\n </p>\n {reading.grade.feedback ? (\n <p className=\"lk-ra-grade-feedback\" dir=\"auto\">\n {reading.grade.feedback}\n </p>\n ) : null}\n </>\n )}\n </div>\n );\n case 'deferred':\n return (\n <div className=\"lk-ra-outcome\" data-status=\"deferred\">\n <p className=\"lk-ra-grade\">{s.awaitingGrade}</p>\n </div>\n );\n case 'unscorable':\n // An unscorable code is a developer-facing label: it goes on the element\n // for diagnostics and routing, and never in front of the learner as text.\n return (\n <div\n className=\"lk-ra-outcome\"\n data-status=\"unscorable\"\n {...(reading.code !== undefined ? { 'data-code': reading.code } : {})}\n >\n <p className=\"lk-ra-grade\">{s.couldNotBeGraded}</p>\n </div>\n );\n default:\n // A stored outcome that claims a grade and carries none that can be read\n // gets the deferred vocabulary's own sentence rather than \"Score NaN%.\":\n // there is a grade, and this screen cannot say what it was. No\n // `data-passed`, because there is no verdict to style.\n return (\n <div\n className=\"lk-ra-outcome\"\n {...(reading.status !== undefined ? { 'data-status': reading.status } : {})}\n >\n <p className=\"lk-ra-grade\">{s.couldNotBeGraded}</p>\n </div>\n );\n }\n}\n\n/**\n * Reads a text aloud and hands the recording to the application.\n *\n * The SDK records; it never judges. A take is captured as mono 16-bit PCM WAV\n * at 16 kHz — the one format `inspectWav` measures directly — handed to\n * `recordingBinding.upload`, and reported through `onSubmit`. Whether anything\n * assesses it, and where, is the application's: in `practice` an optional\n * `assess` may come back with a grade, and in `exam` nothing is ever assessed\n * on the client.\n *\n * **`recordingBinding.upload` is required outside `review`** and its absence\n * throws at render, in production too: a learner must never speak into a\n * control that stores nothing. `assess` is not required — a binding without it\n * records, uploads and submits, and shows a notice in place of the feedback.\n *\n * **A grade that comes back is read, not trusted** — whether `assess` returned\n * it or `outcome` carries it. A score that is not a number between 0 and its\n * maximum, or a `passed` that is not a boolean, is shown as could-not-be-graded\n * and never reaches `onComplete` or a statement; `onComplete` fires exactly when\n * a score is on screen, with that score.\n *\n * **Under a strict Content-Security-Policy** the take is played back from a\n * `blob:` URL, so `media-src` must allow `blob:` — refused, the player and the\n * per-word buttons give way to a note saying the take cannot be played here —\n * and the capture module loads from one too, so either `script-src` allows\n * `blob:` or `workletUrl` names a self-hosted copy of `CAPTURE_PROCESSOR_SOURCE`.\n *\n * ```tsx\n * <ReadAloud\n * data={item}\n * recordingBinding={{ upload, assess }}\n * onSubmit={persist}\n * onComplete={record}\n * />\n * ```\n */\nexport function ReadAloud({\n data,\n onComplete,\n onSubmit,\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 recordingBinding,\n assessment,\n breakThreshold,\n monotoneThreshold,\n workletUrl,\n}: ReadAloudProps) {\n const isExam = renderMode === 'exam';\n const isReview = renderMode === 'review';\n const s = useLkStrings(strings);\n // The pager slot this component sits in, if any: the capture group its pane\n // stops, and where the state of each take is reported. A context and never a\n // prop, so none of it is on this component's published signature — a\n // consumer string in a prop could stop another pager's microphone. `null`\n // for a standalone component, which then belongs to no group at all and\n // releases the microphone from its own unmount alone.\n const slot = useContext(SequenceSlotContext);\n const captureGroup = slot?.captureGroup;\n\n const devError = useMemo(() => {\n if (!isDevelopment()) {\n return null;\n }\n // No `hasKey` branch, unlike `<Dictation>`: a read-aloud item has no answer\n // key, so `redact()` produces a projection the strict redacted schema\n // describes exactly and there is no revealed variant to make room for.\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('read-aloud', data);\n return result.success ? null : new ActivitySchemaError('read-aloud', result.errors);\n }, [data]);\n\n // The bounds a take is captured under, READ and not merely defaulted, because\n // `practice` renders unvalidated content in production: a `maxSeconds` of\n // 100000 arms a recording that never stops itself, a `maxTakes` of \"1\" meant\n // unlimited takes, and a minimum above the maximum refused every take. One\n // reader owns all of it — see `readRecordingBounds`.\n const { maxSeconds, minSeconds, maxTakes } = readRecordingBounds(data.recording);\n const readingKey = readingKeyOf(data, { maxSeconds, minSeconds, maxTakes });\n\n const recorder = useSpeechRecorder(\n useMemo(\n () => ({\n maxDurationMs: maxSeconds * 1000,\n ...(minSeconds !== undefined ? { minDurationMs: minSeconds * 1000 } : {}),\n ...(maxTakes !== undefined ? { maxTakes } : {}),\n // Forwarded, never defaulted: without it the recorder mints its own\n // `blob:` module, which is the one a strict policy refuses.\n ...(workletUrl !== undefined ? { workletUrl } : {}),\n }),\n [maxSeconds, minSeconds, maxTakes, workletUrl],\n ),\n );\n\n const { state, start, complete, getTimeSpent, reset } = useActivityState(\n defaultSubmitted === true ? 'completed' : 'idle',\n );\n const [phase, setPhase] = useState<SubmitPhase>({ kind: 'idle' });\n const [uploaded, setUploaded] = useState<RecordingRef | null>(null);\n const [takeUrl, setTakeUrl] = useState<string | null>(null);\n const [playbackUrl, setPlaybackUrl] = useState<string | null>(null);\n // Re-keys the alert so the SAME message announces again — a learner who is\n // refused the microphone twice hears it twice.\n const [errorNonce, setErrorNonce] = useState(0);\n\n const ids = useId();\n const titleId = `${ids}-title`;\n // Per mount, not per activity id: two renderings of one item on a page (a\n // review list, a preview beside a sequence) are separate players.\n const [modelsGroup] = useState(() => {\n modelsGroupCount += 1;\n return `lk-ra-models-${modelsGroupCount}`;\n });\n\n // The latest callbacks, so an effect can fire an event without depending on a\n // binding or a handler the host rebuilds on every render.\n const interactionRef = useRef(onInteraction);\n interactionRef.current = onInteraction;\n const bindingRef = useRef(recordingBinding);\n bindingRef.current = recordingBinding;\n // Guards a second submit while one is in flight: two clicks would upload the\n // same take twice and charge the application for two assessments.\n const submittingRef = useRef(false);\n // Which reading this instance is on. Everything asynchronous reads it once\n // and re-reads it after every await, so an instance that has been unmounted,\n // or handed a different reading, reports nothing for the one it has left —\n // the treatment the playback-url effect below already gives itself.\n //\n // A counter rather than the boolean `live` that effect uses, because a\n // boolean cleared on the reading reset would stay cleared and leave a\n // perfectly live component unable to submit its next take.\n const runRef = useRef(0);\n // The pager slot as of the latest render, and the last take it was told\n // about, so an unmount can tell it that take is over — a take whose result\n // this instance will now never report must not hold a set open for ever.\n const slotRef = useRef(slot);\n slotRef.current = slot;\n const reportedTakeRef = useRef<number | null>(null);\n useEffect(\n () => () => {\n runRef.current += 1;\n const take = reportedTakeRef.current;\n if (take !== null) {\n slotRef.current?.takeState(take, 'settled');\n }\n },\n [],\n );\n\n const fire = useCallback(\n (type: InteractionKind, payload: Record<string, unknown>): void => {\n interactionRef.current?.({ type, activityId: data.id, timestamp: Date.now(), payload });\n },\n [data.id],\n );\n\n // `recording-started` and `recording-stopped` are reported from the recorder's\n // own status rather than from the click handlers: a take also ends when it\n // reaches its bound, and a handler would report only the ends a learner asked\n // for.\n const lastStatusRef = useRef<SpeechRecorderStatus>(recorder.status);\n useEffect(() => {\n if (lastStatusRef.current === recorder.status) {\n return;\n }\n lastStatusRef.current = recorder.status;\n if (recorder.status === 'recording') {\n fire('recording-started', { takes: recorder.takesUsed, durationMs: 0 });\n } else if (recorder.status === 'recorded' && recorder.take !== null) {\n fire('recording-stopped', {\n takes: recorder.takesUsed,\n durationMs: recorder.take.durationMs,\n });\n }\n }, [recorder.status, recorder.take, recorder.takesUsed, fire]);\n\n useEffect(() => {\n if (recorder.error !== null) {\n setErrorNonce((nonce) => nonce + 1);\n }\n }, [recorder.error]);\n\n // The take preview. Guarded because an embedder may forbid object URLs, and a\n // preview is worth less than the take it previews.\n const take = recorder.take;\n useEffect(() => {\n if (take === null || typeof URL.createObjectURL !== 'function') {\n return;\n }\n const url = URL.createObjectURL(take.blob);\n setTakeUrl(url);\n return () => {\n URL.revokeObjectURL(url);\n setTakeUrl(null);\n };\n }, [take]);\n\n const restored = recordingOf(value ?? defaultValue);\n const restoredKey = restored?.key ?? null;\n // Keyed by the reading as well as the take: the reading reset below clears\n // the link, and a link nothing mints again would leave the stored take with\n // no player for as long as it stays on screen.\n // biome-ignore lint/correctness/useExhaustiveDependencies: keyed by the stored take and the reading, not by the identity of a response object a host rebuilds every render\n useEffect(() => {\n const binding = bindingRef.current;\n if (!isReview || restored === null || binding?.playbackUrl === undefined) {\n return;\n }\n let live = true;\n void Promise.resolve(binding.playbackUrl(restored)).then(\n (url) => {\n if (live) {\n setPlaybackUrl(url);\n }\n },\n () => {\n /* a link that could not be minted; the marks still render without it */\n },\n );\n return () => {\n live = false;\n };\n }, [isReview, restoredKey, readingKey]);\n\n // What the registry may do to this component, and it is narrow: release the\n // DEVICE, and only while one is actually open.\n //\n // The pager stops a hidden slot's captures on EVERY hidden transition, so a\n // join that discarded unconditionally threw away a take that was already\n // encoded — and `discard` deliberately refunds nothing, so Next then Prev\n // left the learner an activity they could no longer answer and no message\n // saying why. That contradicts the pager's own founding principle: slots stay\n // mounted precisely so nobody silently loses an answer. A capture still\n // running has nothing to lose yet; a finished take has everything.\n //\n // The status is read from a ref so this callback keeps ONE identity and the\n // effect below joins the group exactly once, as `playback-group`'s does.\n const statusRef = useRef(recorder.status);\n statusRef.current = recorder.status;\n const releaseMicrophone = useCallback(() => {\n if (capturing(statusRef.current)) {\n recorder.discard();\n }\n }, [recorder.discard]);\n\n // The registry SUPPLEMENTS the recorder's own unmount cleanup; it covers the\n // one case that cleanup cannot, a component left mounted and merely hidden.\n useEffect(() => {\n if (captureGroup === undefined) {\n return;\n }\n return joinCaptureGroup(captureGroup, releaseMicrophone);\n }, [captureGroup, releaseMicrophone]);\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.\n const defaultSubmittedRef = useRef(defaultSubmitted);\n useEffect(() => {\n defaultSubmittedRef.current = defaultSubmitted;\n }, [defaultSubmitted]);\n // Keyed by the READING, never by the identity of `data` — see `readingKeyOf`\n // for the regression that identity caused. A host that rebuilds an\n // unchanged item keeps the take, the budget and any grade still in flight.\n const lastReadingRef = useRef(readingKey);\n useEffect(() => {\n if (lastReadingRef.current === readingKey) {\n return;\n }\n lastReadingRef.current = readingKey;\n submittingRef.current = false;\n // Anything still in flight belongs to the reading that has just left.\n runRef.current += 1;\n setPhase({ kind: 'idle' });\n setUploaded(null);\n setPlaybackUrl(null);\n // `reset`, not `discard`: the takes belong to the READING, and `discard`\n // refunds none of them on purpose. A new reading that inherited the old\n // one's spent takes renders a recorder that looks live and refuses to\n // record — reachable in `<ActivityPreview>`, whose remount key is derived\n // from the media alone, so an author who tries one take and then edits the\n // reference text can never record again without reloading the page.\n recorder.reset();\n reset(defaultSubmittedRef.current === true ? 'completed' : 'idle');\n }, [readingKey, reset, recorder.reset]);\n\n // What became of each take, told to the pager slot this sits in: the one\n // channel through which a sequence learns whether its set can be reported.\n //\n // Read from the committed PHASE, and only from it. Every way a submit can end\n // — a grade, a take with no grade, a failure, a retry, a learner recording\n // again, a reading reset — ends in a phase, so none of them can leave a set\n // waiting on a take this component is done with. And an effect runs after\n // the commit, which is after `onSubmit` and `onComplete` were called for the\n // same phase: a pager told a take has settled has already been handed\n // everything that take produced. The one state that must not wait for a\n // commit — a take on its way — is reported as the submit starts.\n const phaseTake = phase.kind === 'idle' ? null : phase.take;\n const phaseTakeState = takeStateOf(phase, uploaded);\n useEffect(() => {\n // An idle phase settles the take before it: re-recording drops a take\n // whose failure was being offered a retry, and so does a reading reset.\n const take = phaseTake ?? reportedTakeRef.current;\n if (slot === null || take === null) {\n return;\n }\n reportedTakeRef.current = take;\n slot.takeState(take, phaseTakeState);\n }, [slot, phaseTake, phaseTakeState]);\n\n // Model recordings stay silent for as long as the learner records: a\n // microphone that hears the model reading would assess the model's\n // pronunciation, not theirs.\n //\n // Pausing once, when the capture starts, is not enough — the play controls\n // are still on screen and still work throughout the take, so the hazard\n // simply moves one door along. The listener holds the guard for the whole\n // capture and is removed with it; `play` does not bubble, so it is taken in\n // the capture phase. It is what silences the browser's own control bar; a\n // budgeted model is refused before it is charged, by the `disabled` its\n // player is rendered with below.\n const modelsRef = useRef<HTMLDivElement>(null);\n const isCapturing = capturing(recorder.status);\n useEffect(() => {\n if (!isCapturing) {\n return;\n }\n const node = modelsRef.current;\n if (node === null) {\n return;\n }\n const hush = (): void => {\n for (const media of node.querySelectorAll('audio, video')) {\n const element = media as HTMLMediaElement;\n if (!element.paused) {\n element.pause();\n }\n }\n };\n hush();\n node.addEventListener('play', hush, true);\n return () => {\n node.removeEventListener('play', hush, true);\n };\n }, [isCapturing]);\n\n const slowMedia = useMemo(\n () => slowMediaFor(data, s.readAloudSlowRecording),\n [data, s.readAloudSlowRecording],\n );\n\n // The learner's own take, as every element that plays it plays it: the\n // preview before it is sent, the stored link a review mints, and the\n // per-word buttons in the feedback panel. One refusal covers all of them.\n const takeAudio = isReview ? playbackUrl : takeUrl;\n const playback = usePlaybackRefusal(takeAudio);\n // Where focus goes when a retry takes the \"Try again\" button away: the\n // submit it retries, which says it is busy for as long as the retry runs.\n const submitRef = useRef<HTMLButtonElement>(null);\n\n // All hooks are called before these throws, so hook order stays stable.\n if (devError) {\n throw devError;\n }\n // `review` needs no upload: it renders what a server already stored.\n if (!isReview && recordingBinding?.upload === undefined) {\n throw new Error(\n `ReadAloud \"${data.id}\" was rendered in renderMode \"${renderMode}\" without ` +\n '`recordingBinding.upload`. The learner could record a take that is stored ' +\n 'nowhere and submitted as nothing, which looks like a working activity the ' +\n 'whole way through. Pass a `recordingBinding` whose `upload` puts the take in ' +\n 'your storage and returns its key. `assess` is optional: without it the take is ' +\n 'still recorded, uploaded and submitted, and a notice replaces the feedback.',\n );\n }\n\n const submitted = state === 'completed';\n const inactive = disabled === true || submitted || isReview;\n const busy = phase.kind === 'uploading' || phase.kind === 'assessing';\n const takesLeft = maxTakes === undefined ? undefined : Math.max(0, maxTakes - recorder.takesUsed);\n\n /** Marks a failure so the alert announces even when the sentence repeats. */\n const raise = (next: SubmitPhase): void => {\n setErrorNonce((nonce) => nonce + 1);\n setPhase(next);\n };\n\n /**\n * Tells the pager slot, if there is one, that `take` is on its way — before\n * anything is awaited. The report a pager's set waits on must exist before\n * the first result it waits for can arrive; the take's later states follow\n * from the phase it reaches (see the effect above).\n */\n const beginTakeReport = (take: number): void => {\n reportedTakeRef.current = take;\n slot?.takeState(take, 'in-flight');\n };\n\n const runAssess = async (\n ref: RecordingRef,\n current: RecordedTake | null,\n take: number,\n ): Promise<void> => {\n const assess = bindingRef.current?.assess;\n const durationMs = current?.durationMs ?? 0;\n const takes = recorder.takesUsed;\n const run = runRef.current;\n if (assess === undefined) {\n // D5: a binding that stores but does not judge is a supported binding,\n // not a mistake — it is what an authoring preview supplies.\n setPhase({ kind: 'unassessed', take });\n return;\n }\n setPhase({ kind: 'assessing', take });\n fire('assessment-requested', { takes, durationMs });\n let answer: unknown;\n try {\n answer = await assess(ref);\n } catch {\n // Detached while the assessor was working: an instance that has been\n // unmounted, or handed a different reading, reports nothing for the one\n // it has left — not a phase, not an event, and not a grade.\n if (run !== runRef.current) {\n return;\n }\n raise({ kind: 'assess-failed', take, retryable: true });\n fire('assessment-failed', { takes, durationMs, retryable: true });\n return;\n }\n if (run !== runRef.current) {\n return;\n }\n // Read once, here, and nothing below touches `answer` again: the phase the\n // screen renders from, `onComplete` and the statement all take what the\n // reader returned, so they cannot disagree about what came back.\n const result = readAssessResult(answer);\n if (result.status === 'failed') {\n raise({ kind: 'assess-failed', take, retryable: result.retryable });\n fire('assessment-failed', { takes, durationMs, retryable: result.retryable });\n return;\n }\n if (result.status === 'unscorable') {\n // Reported as a failed assessment because that is what it is to a\n // consumer's log — a take that produced no grade — and `code` says which\n // kind. `retryable` is true because another take is offered.\n setPhase({ kind: 'unscorable', take, code: result.code });\n fire('assessment-failed', {\n takes,\n durationMs,\n retryable: true,\n ...(result.code !== undefined ? { code: result.code } : {}),\n });\n return;\n }\n const timeSpent = getTimeSpent();\n setPhase({ kind: 'graded', take, assessment: result.assessment, grade: result.grade });\n const grade = result.grade;\n if (grade === null) {\n // A judgement that carries no grade the reader can show is not an\n // `ActivityResult`: reporting one would mean inventing the score, exactly\n // as an `unscorable` result would. To a consumer's log it is what an\n // unscorable take is — an assessment that produced no grade, with another\n // take offered.\n fire('assessment-failed', { takes, durationMs, retryable: true });\n return;\n }\n\n // xAPI's `score.scaled` is a fraction in [-1, 1], and the SDK's builder\n // writes `ScoringResult.score` into it verbatim, then validates — so a\n // points-based grade (82 out of 100, which `GradeRecord` allows and a\n // grader's own units readily produce) does not merely ship a wrong number:\n // the build THROWS, and the grade never reaches the screen at all. The read\n // grade's fraction is in 0..1 by construction, and `passed` is a boolean by\n // construction, so the statement validates whatever the host sent. The\n // learner's own numbers go to `onComplete` untouched.\n //\n // Stamped with its take, as the response was: a pager records a grade only\n // for the take its slot holds now, so a grade that outlived a newer take\n // can never be filed beside that newer take's response.\n onComplete?.(\n stampTake(\n {\n score: grade.score,\n maxScore: grade.maxScore,\n passed: grade.passed,\n timeSpent,\n 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 timeSpentMs: timeSpent,\n response: result.recognizedText ?? '',\n // `ScoringResult.details` is required where `GradeRecord.details` is\n // optional, and an empty list is the honest reading of \"no per-word\n // marks were stored\" — never a mark of its own.\n scoringResult: {\n score: fractionOfGrade(grade),\n maxScore: 1,\n passed: grade.passed,\n feedback: grade.feedback,\n details: grade.details ?? [],\n },\n }),\n },\n take,\n ),\n );\n };\n\n const submitTake = async (current: RecordedTake | null): Promise<void> => {\n const binding = bindingRef.current;\n if (inactive || submittingRef.current || binding === undefined) {\n return;\n }\n submittingRef.current = true;\n const takes = recorder.takesUsed;\n const run = runRef.current;\n // Every submit is a take of its own, a retried upload included: a number\n // no earlier submit on this page had, so whatever an earlier one still\n // brings back cannot be taken for this one's.\n const take = mintTake();\n beginTakeReport(take);\n try {\n let ref: RecordingRef | null = null;\n if (current !== null) {\n setPhase({ kind: 'uploading', take });\n try {\n ref = await binding.upload(current);\n } catch {\n if (run !== runRef.current) {\n return;\n }\n // The take never reached storage, so nothing is submitted: a take\n // that failed to upload must not become a blank response.\n raise({ kind: 'upload-failed', take });\n fire('recording-upload-failed', {\n takes,\n durationMs: current.durationMs,\n retryable: true,\n });\n return;\n }\n // Detached while the take travelled. The bytes are in the application's\n // storage and this instance drops their key, which is a smaller cost\n // than the alternative: `onSubmit` carries no activity id, so a\n // response reported for a reading the learner has left is one a pager\n // would file against whatever is on screen now.\n if (run !== runRef.current) {\n return;\n }\n setUploaded(ref);\n fire('recording-uploaded', { takes, durationMs: current.durationMs });\n }\n onSubmit?.(stampTake(responseOf(ref, takes), take));\n fire('submitted', { takes, durationMs: current?.durationMs ?? 0 });\n if (isExam || ref === null) {\n // Exam never assesses, never scores, never reveals, and builds no xAPI\n // statement: its `correctResponsesPattern` would be the answer key, and\n // a read-aloud is graded on a server from the stored bytes.\n complete();\n setPhase({ kind: 'submitted', take });\n return;\n }\n await runAssess(ref, current, take);\n } finally {\n submittingRef.current = false;\n }\n };\n\n /**\n * Judges the take that is already stored, again — the SAME take, so the same\n * number. Guarded like a submit: an assessment costs an application money,\n * and two presses of one retry must not buy two of them.\n */\n const retryAssess = async (ref: RecordingRef, take: number): Promise<void> => {\n if (submittingRef.current) {\n return;\n }\n submittingRef.current = true;\n beginTakeReport(take);\n try {\n await runAssess(ref, recorder.take, take);\n } finally {\n submittingRef.current = false;\n }\n };\n\n const handleSubmit = (event: React.FormEvent): void => {\n event.preventDefault();\n if (inactive || busy || recorder.take === null || phase.kind !== 'idle') {\n return;\n }\n void submitTake(recorder.take);\n };\n\n const beginTake = (): void => {\n if (inactive || busy || !recorder.canRecord) {\n return;\n }\n if (recorder.take !== null) {\n fire('recording-discarded', {\n takes: recorder.takesUsed,\n durationMs: recorder.take.durationMs,\n });\n }\n setPhase({ kind: 'idle' });\n setUploaded(null);\n start();\n void recorder.start();\n };\n\n // The reading's own language and the direction its tag names. No `_`→`-`\n // normalisation, unlike `<Dictation>`: `ReadAloudData.locale` is canonical by\n // schema, so there is nothing to normalise.\n const contentLang = typeof data.locale === 'string' ? data.locale : undefined;\n const contentDir = localeDirectionOf(data.locale);\n\n // What the host sent, as the one reader of a host's grade reads it. Every\n // path below that shows or decides anything about a grade — the summary, the\n // panel, the marks, who renders the score, the announcement — reads these and\n // never `outcome` or `assessment` directly.\n const outcomeReading = useMemo(() => readOutcome(outcome), [outcome]);\n const keptEvidence = useMemo(() => readEvidence(assessment), [assessment]);\n const storedGrade =\n outcomeReading?.kind === 'graded' && outcomeReading.status === 'graded'\n ? outcomeReading.grade\n : null;\n // The marks a review shows: the assessment when the caller kept one, and the\n // stored details otherwise. With neither, the score is shown and no marks are.\n const storedMarks = useMemo(\n () =>\n isReview && keptEvidence === null && storedGrade?.details !== undefined\n ? marksFromDetails(storedGrade.details)\n : null,\n [isReview, keptEvidence, storedGrade],\n );\n const feedbackAssessment = isReview\n ? keptEvidence\n : phase.kind === 'graded'\n ? phase.assessment\n : null;\n const feedbackGrade = isReview ? storedGrade : phase.kind === 'graded' ? phase.grade : null;\n // A take the page refused to play is handed to no per-word button: each of\n // them would do nothing when pressed, and the note in the player's place\n // already says why.\n const feedbackAudio = playback.refused ? null : takeAudio;\n\n // Whether the score and the grader's words are already on screen inside the\n // feedback panel, which is what decides who renders them here.\n //\n // The props say the panel WAS GIVEN a grade; only the DOM says it rendered\n // one. The panel can fail outright — D2's dev throw for evidence the\n // validator refuses is one way, and nothing on either path validates a host's\n // grade either — and clipping on the props alone then hides a score that\n // exists nowhere, leaving a learner \"this activity could not be displayed\"\n // and no percentage at all. So the props may only ever clip for the single\n // commit before the fact arrives, and the fact may always un-clip: a grade on\n // screen twice is a far smaller defect than a grade nowhere. `.lk-pf-grade`\n // is the panel's own hook for this, named as such in its source.\n const rootRef = useRef<HTMLFormElement>(null);\n const [panelLostTheGrade, setPanelLostTheGrade] = useState(false);\n // Only a READ grade is handed to the panel, and the panel shows a read grade's\n // score without exception — so the prediction is made from the reader's\n // output, and never from a grade the panel would refuse.\n const panelHasGrade = feedbackAssessment !== null && feedbackGrade !== null;\n const gradeShownInPanel = panelHasGrade && !panelLostTheGrade;\n // Deliberately without a dependency list: what it reads is the committed DOM,\n // which no list can name. The updater keeps the settled value a fixed point,\n // so a render that changes nothing here costs one extra pass and then stops.\n useEffect(() => {\n const root = rootRef.current;\n const lost = panelHasGrade && (root === null || root.querySelector('.lk-pf-grade') === null);\n setPanelLostTheGrade((was) => (was === lost ? was : lost));\n });\n\n const announcement = useMemo<Announcement | null>(() => {\n if (isReview) {\n return null;\n }\n // The two moments of a capture, said once each. The per-second counter used\n // to be a live region of its own, so a ten-second take produced ten\n // announcements — and on any device without headphones a screen reader\n // speaks each of them into the take about to be assessed FOR PRONUNCIATION.\n // This component already stops the model recordings for exactly that\n // reason; the counter it generates itself is the same hazard.\n if (recorder.status === 'recording') {\n return { text: s.readAloudRecordingStarted, feedback: null };\n }\n // The length is in the sentence because the counter is no longer announced:\n // a take that ran to its bound reads back as \"20 of 20 seconds\", which is\n // how a learner hears that it stopped itself rather than that they stopped it.\n const stopped: Announcement | null =\n recorder.status === 'recorded' && take !== null\n ? {\n text: s.readAloudRecordingStopped(\n secondsWithin(take.durationMs, maxSeconds, 'nearest'),\n maxSeconds,\n ),\n feedback: null,\n }\n : null;\n if (isExam) {\n if (phase.kind === 'submitted' || submitted) {\n return { text: s.answerSubmitted, feedback: null };\n }\n return phase.kind === 'idle' ? stopped : null;\n }\n switch (phase.kind) {\n case 'graded': {\n const grade = phase.grade;\n // A judgement with no grade that can be read says so, in the same\n // sentence a review uses — never nothing, which reads as a grade\n // still on its way.\n return grade === null\n ? { text: `${s.answerSubmitted} ${s.couldNotBeGraded}`, feedback: null }\n : {\n text: `${s.answerSubmitted} ${s.scoreAnnouncement(percentOfGrade(grade), grade.passed)}`,\n feedback: grade.feedback,\n };\n }\n case 'unscorable':\n return { text: unscorableMessage(phase.code, s), feedback: null };\n case 'unassessed':\n return { text: s.readAloudAssessmentUnavailable, feedback: null };\n case 'idle':\n return stopped;\n default:\n // Uploading and assessing have their own pending sentence, and both\n // failures have an alert; a stale \"recording stopped\" beside either\n // would be the loudest thing on the screen.\n return null;\n }\n }, [isReview, isExam, phase, submitted, s, recorder.status, take, maxSeconds]);\n\n const alertText =\n recorder.error !== null\n ? s.readAloudRecorderError(recorder.error)\n : phase.kind === 'upload-failed'\n ? s.readAloudUploadFailed\n : phase.kind === 'assess-failed'\n ? s.readAloudAssessmentFailed\n : null;\n\n return (\n <form\n className=\"lk-ra\"\n ref={rootRef}\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-ra-title\" dir={contentDir ?? 'auto'} lang={contentLang}>\n {data.title}\n </p>\n\n {typeof data.instructions === 'string' && data.instructions !== '' ? (\n <p className=\"lk-ra-instructions\" dir={contentDir ?? 'auto'} lang={contentLang}>\n {data.instructions}\n </p>\n ) : null}\n\n {/* The reading itself. Never redacted: a read-aloud has no answer key, so\n the learner's copy carries the text in full. */}\n <p className=\"lk-ra-reference\" dir={contentDir ?? 'auto'} lang={contentLang}>\n {data.referenceText}\n </p>\n\n {data.media !== undefined || slowMedia !== undefined ? (\n <div className=\"lk-ra-models\" ref={modelsRef}>\n {/*\n Each model recording is a named group (a fieldset with a legend,\n which is what `role=\"group\"` plus a label spells natively), so the\n two players are told apart by name and not only by position.\n */}\n {data.media !== undefined ? (\n <fieldset className=\"lk-ra-model\">\n <legend className=\"lk-ra-model-label\">{s.readAloudModelRecording}</legend>\n {/* The ONLY budgeted recording: the binding is whatever the pager or the caller passes.\n Disabled while a take is captured, so a press is refused BEFORE a play is\n charged — silenced after the charge, it cost the learner a play they never\n heard. Nothing is announced for the refusal: a screen reader speaking now\n would speak into the take. */}\n <ActivityMedia\n media={data.media}\n renderMode={renderMode}\n playbackGroup={modelsGroup}\n {...(mediaBudget !== undefined ? { mediaBudget } : {})}\n {...(mediaStrings !== undefined ? { mediaStrings } : {})}\n {...(strings !== undefined ? { strings } : {})}\n {...(onInteraction !== undefined ? { onInteraction } : {})}\n {...(locale !== undefined ? { locale } : {})}\n {...(disabled === true || isCapturing ? { disabled: true } : {})}\n />\n </fieldset>\n ) : null}\n {slowMedia !== undefined ? (\n <fieldset className=\"lk-ra-model\" data-slow=\"true\">\n <legend className=\"lk-ra-model-label\">{s.readAloudSlowRecording}</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={modelsGroup}\n {...(mediaStrings !== undefined ? { mediaStrings } : {})}\n {...(strings !== undefined ? { strings } : {})}\n {...(locale !== undefined ? { locale } : {})}\n {...(disabled === true || isCapturing ? { disabled: true } : {})}\n />\n </fieldset>\n ) : null}\n </div>\n ) : null}\n\n {/* Gone once the item is committed, rather than left behind disabled: a\n submitted exam answer is not a control a learner should still meet. */}\n {isReview || submitted ? null : (\n <div\n className=\"lk-ra-recorder\"\n data-status={recorder.status}\n data-level={\n recorder.status === 'recording'\n ? Math.min(LEVEL_STEPS, Math.round(recorder.level * LEVEL_STEPS))\n : undefined\n }\n >\n {recorder.status === 'recording' ? (\n <button\n type=\"button\"\n className=\"lk-ra-stop\"\n disabled={inactive}\n onClick={() => recorder.stop()}\n >\n {s.readAloudStop}\n </button>\n ) : (\n // aria-disabled, never disabled, once the takes are spent: a\n // natively disabled button drops keyboard focus to the page body,\n // and this is the control a learner comes back to.\n <button\n type=\"button\"\n className=\"lk-ra-record\"\n disabled={inactive}\n aria-disabled={!recorder.canRecord || busy || undefined}\n onClick={beginTake}\n >\n {recorder.take === null ? s.readAloudRecord : s.readAloudRerecord}\n </button>\n )}\n {recorder.status === 'recording' ? (\n // Visible, and hidden from assistive technology, beside the level\n // meter the recorder's `data-level` drives. Its text changes every\n // whole second, so as a live region it announced ten times in a\n // ten-second take — into the microphone. What a screen-reader\n // learner needs instead is said once each, below.\n <p className=\"lk-ra-progress\" aria-hidden=\"true\">\n {s.readAloudRecordingProgress(\n secondsWithin(recorder.elapsedMs, maxSeconds, 'down'),\n maxSeconds,\n )}\n </p>\n ) : null}\n {takesLeft !== undefined && maxTakes !== undefined ? (\n <p className=\"lk-ra-takes\">{s.readAloudTakesRemaining(takesLeft, maxTakes)}</p>\n ) : null}\n </div>\n )}\n\n {takeAudio === null ? null : playback.refused ? (\n // In the player's place, not beside it: a player the page will not\n // load looks exactly like one that works until it is pressed, and then\n // does nothing. A note rather than an alert — the learner can still\n // submit, and nothing here asks them to act.\n <p className=\"lk-ra-take-unavailable\" role=\"note\">\n {s.readAloudPlaybackUnavailable}\n </p>\n ) : (\n // biome-ignore lint/a11y/useMediaCaption: the learner's own take has no caption track to offer; its accessible name says whose recording it is\n <audio\n className=\"lk-ra-take\"\n controls\n src={takeAudio}\n aria-label={s.readAloudYourRecording}\n onError={(event) => playback.refuse(event.currentTarget)}\n {...(isReview ? {} : { 'data-take': recorder.takesUsed })}\n />\n )}\n\n {isReview || submitted ? null : (\n <div className=\"lk-ra-actions\">\n <button\n ref={submitRef}\n type=\"submit\"\n className=\"lk-ra-submit\"\n disabled={disabled === true}\n aria-disabled={recorder.take === null || phase.kind !== 'idle' || undefined}\n aria-busy={busy || undefined}\n >\n {s.submit}\n </button>\n {isExam ? (\n // Explicit, and only here: an exam answer with no recording is a\n // decision a learner takes, never something a failed upload does\n // for them.\n <button\n type=\"button\"\n className=\"lk-ra-submit-blank\"\n disabled={inactive}\n aria-disabled={busy || undefined}\n onClick={() => {\n if (!busy) {\n void submitTake(null);\n }\n }}\n >\n {s.readAloudSubmitWithoutRecording}\n </button>\n ) : null}\n {offersRetry(phase, uploaded) ? (\n <button\n type=\"button\"\n className=\"lk-ra-retry\"\n onClick={() => {\n // The retry takes this button away with the phase it answers,\n // and focus on a removed element drops to the page body — a\n // keyboard learner is then back at the top of the page with no\n // idea the retry started. It goes to the submit being retried.\n submitRef.current?.focus();\n if (phase.kind === 'upload-failed') {\n void submitTake(recorder.take);\n } else if (phase.kind === 'assess-failed' && uploaded !== null) {\n void retryAssess(uploaded, phase.take);\n }\n }}\n >\n {s.readAloudTryAgain}\n </button>\n ) : null}\n </div>\n )}\n\n {busy ? (\n <p className=\"lk-ra-pending\" role=\"status\" aria-busy=\"true\">\n {phase.kind === 'uploading' ? s.readAloudUploading : s.readAloudAssessing}\n </p>\n ) : null}\n\n {alertText !== null ? (\n <p key={errorNonce} className=\"lk-ra-alert\" role=\"alert\">\n {alertText}\n </p>\n ) : null}\n\n {feedbackAssessment !== null ? (\n <PronunciationFeedback\n data={{ referenceText: data.referenceText, locale: data.locale }}\n assessment={feedbackAssessment}\n {...(feedbackGrade !== null ? { grade: feedbackGrade } : {})}\n {...(feedbackAudio !== null ? { audioUrl: feedbackAudio } : {})}\n {...(breakThreshold !== undefined ? { breakThreshold } : {})}\n {...(monotoneThreshold !== undefined ? { monotoneThreshold } : {})}\n {...(locale !== undefined ? { locale } : {})}\n {...(strings !== undefined ? { strings } : {})}\n />\n ) : null}\n\n {storedMarks !== null ? (\n <div className=\"lk-ra-marks\">\n {/* The list's name and the hidden sentences are interface text; only\n the words carry the reading's language. */}\n <ol className=\"lk-ra-words\" aria-label={s.pronunciationWordsLabel} dir={contentDir}>\n {storedMarks.map((entry, index) => {\n const sentence = markSentence(entry, s);\n return (\n <li\n // biome-ignore lint/suspicious/noArrayIndexKey: mark order is the identity; words repeat\n key={index}\n className=\"lk-ra-word\"\n data-state={entry.state}\n >\n {/* One channel for assistive technology, not two: the same\n sentence as a `title` is an accessible description, read\n straight after the name it repeats. */}\n <span className=\"lk-visually-hidden\" style={VISUALLY_HIDDEN}>\n {sentence}\n </span>\n <span\n className=\"lk-ra-word-text\"\n aria-hidden=\"true\"\n dir={contentDir ?? 'auto'}\n lang={contentLang}\n >\n {entry.reference}\n </span>\n </li>\n );\n })}\n </ol>\n {/* Three rows, not four: a stored mark set carries no insertions. */}\n <ul className=\"lk-ra-legend\">\n {STORED_STATES.map((state) => (\n <li key={state} data-state={state}>\n {s.pronunciationLegend(state)}\n </li>\n ))}\n </ul>\n </div>\n ) : null}\n\n <FeedbackRegion id={`${data.id}-feedback`}>\n {isReview ? (\n outcomeReading !== undefined ? (\n <OutcomeSummary reading={outcomeReading} s={s} scoreShown={gradeShownInPanel} />\n ) : null\n ) : gradeShownInPanel ? (\n // Announced, not repeated. A grade the feedback panel is already\n // showing would otherwise be read on screen twice, feedback and all —\n // but a live region is the only thing that TELLS a screen-reader\n // learner a grade arrived, since nothing takes focus. Clipped rather\n // than `display: none`, which would stop it being announced at all.\n <span className=\"lk-visually-hidden\" style={VISUALLY_HIDDEN}>\n <AnnouncementText announcement={announcement} />\n </span>\n ) : (\n <AnnouncementText announcement={announcement} />\n )}\n </FeedbackRegion>\n </form>\n );\n}\n","'use client';\n\nimport { useLkStrings } from '../../i18n/LkIntlProvider.js';\nimport { ActivityErrorBoundary } from '../ActivityErrorBoundary.js';\nimport { ReadAloud as ReadAloudCore, type ReadAloudProps } from './ReadAloud.js';\n\n// `RecordedTake` travels with `RecordingBinding` because `upload`, the one\n// method a binding must have, takes one: a binding written against this subpath\n// must not need a second import path to name its own argument.\nexport type { RecordedTake } from '../../hooks/useSpeechRecorder.js';\nexport type { ReadAloudAssessResult, ReadAloudProps, RecordingBinding } from './ReadAloud.js';\n\n/**\n * Public Read Aloud activity: the core wrapped in `ActivityErrorBoundary` so a\n * render failure (including the dev schema-validation throw and the\n * missing-`upload` guard) degrades to an accessible fallback instead of\n * crashing the host.\n */\nexport function ReadAloud(props: ReadAloudProps) {\n const strings = useLkStrings(props.strings);\n return (\n <ActivityErrorBoundary activityTitle={props.data?.title} strings={strings}>\n <ReadAloudCore {...props} />\n </ActivityErrorBoundary>\n );\n}\n"]}