@intellectif/lk-react 16.0.0 → 16.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +3 -3
  3. package/dist/{WrittenResponse-C2zw-1jK.d.cts → WrittenResponse-6tSj6U3G.d.cts} +1 -1
  4. package/dist/{WrittenResponse-CTiNpSCC.d.ts → WrittenResponse-xJ7I_5yq.d.ts} +1 -1
  5. package/dist/{chunk-P5FGJMMI.cjs → chunk-2S3MK4VX.cjs} +5 -5
  6. package/dist/{chunk-P5FGJMMI.cjs.map → chunk-2S3MK4VX.cjs.map} +1 -1
  7. package/dist/{chunk-ZA5QUQ2V.cjs → chunk-2TFNDHJ5.cjs} +13 -13
  8. package/dist/{chunk-ZA5QUQ2V.cjs.map → chunk-2TFNDHJ5.cjs.map} +1 -1
  9. package/dist/{chunk-AEUP63CZ.js → chunk-2XNCPLHU.js} +5 -5
  10. package/dist/{chunk-AEUP63CZ.js.map → chunk-2XNCPLHU.js.map} +1 -1
  11. package/dist/{chunk-4X7NFEDB.js → chunk-3UXRX4KU.js} +5 -5
  12. package/dist/{chunk-4X7NFEDB.js.map → chunk-3UXRX4KU.js.map} +1 -1
  13. package/dist/{chunk-UYRQEIB7.js → chunk-5QHVYOME.js} +5 -5
  14. package/dist/{chunk-UYRQEIB7.js.map → chunk-5QHVYOME.js.map} +1 -1
  15. package/dist/{chunk-RJGCT35F.cjs → chunk-B6S5ADHR.cjs} +13 -13
  16. package/dist/{chunk-RJGCT35F.cjs.map → chunk-B6S5ADHR.cjs.map} +1 -1
  17. package/dist/{chunk-HJLVWZOM.js → chunk-BI547RIA.js} +4 -4
  18. package/dist/{chunk-HJLVWZOM.js.map → chunk-BI547RIA.js.map} +1 -1
  19. package/dist/{chunk-BO64SLHL.cjs → chunk-DFMBVA7D.cjs} +8 -8
  20. package/dist/{chunk-BO64SLHL.cjs.map → chunk-DFMBVA7D.cjs.map} +1 -1
  21. package/dist/{chunk-ICAYWVNF.js → chunk-DKZWUIQD.js} +3 -3
  22. package/dist/{chunk-ICAYWVNF.js.map → chunk-DKZWUIQD.js.map} +1 -1
  23. package/dist/{chunk-3IHVDQRC.js → chunk-DVOPHC2Q.js} +275 -74
  24. package/dist/chunk-DVOPHC2Q.js.map +1 -0
  25. package/dist/{chunk-ALDGRDYD.cjs → chunk-FZWWVJE4.cjs} +24 -24
  26. package/dist/{chunk-ALDGRDYD.cjs.map → chunk-FZWWVJE4.cjs.map} +1 -1
  27. package/dist/{chunk-OOYKKO3V.js → chunk-GDMM2WEG.js} +11 -11
  28. package/dist/{chunk-OOYKKO3V.js.map → chunk-GDMM2WEG.js.map} +1 -1
  29. package/dist/{chunk-W32ND3ZR.js → chunk-GUPBIEUA.js} +6 -6
  30. package/dist/{chunk-W32ND3ZR.js.map → chunk-GUPBIEUA.js.map} +1 -1
  31. package/dist/{chunk-T33AJYLW.js → chunk-IQI5I2X5.js} +5 -5
  32. package/dist/{chunk-T33AJYLW.js.map → chunk-IQI5I2X5.js.map} +1 -1
  33. package/dist/{chunk-NOF6HJDV.js → chunk-JPDR6TTA.js} +4 -4
  34. package/dist/{chunk-NOF6HJDV.js.map → chunk-JPDR6TTA.js.map} +1 -1
  35. package/dist/{chunk-QIA5FAAW.js → chunk-KSAINXRG.js} +3 -2
  36. package/dist/chunk-KSAINXRG.js.map +1 -0
  37. package/dist/{chunk-2WM2KSO7.cjs → chunk-ML6L4LJH.cjs} +25 -25
  38. package/dist/{chunk-2WM2KSO7.cjs.map → chunk-ML6L4LJH.cjs.map} +1 -1
  39. package/dist/{chunk-UISZWFI7.cjs → chunk-MQAZJQRE.cjs} +3 -2
  40. package/dist/chunk-MQAZJQRE.cjs.map +1 -0
  41. package/dist/{chunk-QADR2XMQ.cjs → chunk-OO24JGYH.cjs} +18 -18
  42. package/dist/{chunk-QADR2XMQ.cjs.map → chunk-OO24JGYH.cjs.map} +1 -1
  43. package/dist/{chunk-JYC2VV3Y.cjs → chunk-PTJTC6A3.cjs} +12 -12
  44. package/dist/{chunk-JYC2VV3Y.cjs.map → chunk-PTJTC6A3.cjs.map} +1 -1
  45. package/dist/{chunk-WGIMLXRW.cjs → chunk-PXGJHZKJ.cjs} +6 -6
  46. package/dist/{chunk-WGIMLXRW.cjs.map → chunk-PXGJHZKJ.cjs.map} +1 -1
  47. package/dist/{chunk-2YZZL5FV.cjs → chunk-RSQFGF5W.cjs} +13 -13
  48. package/dist/{chunk-2YZZL5FV.cjs.map → chunk-RSQFGF5W.cjs.map} +1 -1
  49. package/dist/{chunk-OXUUE3HX.cjs → chunk-TRP5Z3XW.cjs} +5 -5
  50. package/dist/{chunk-OXUUE3HX.cjs.map → chunk-TRP5Z3XW.cjs.map} +1 -1
  51. package/dist/{chunk-4AQ4SWJ3.js → chunk-VC2MPB2Y.js} +5 -5
  52. package/dist/{chunk-4AQ4SWJ3.js.map → chunk-VC2MPB2Y.js.map} +1 -1
  53. package/dist/{chunk-A2CPCOJA.cjs → chunk-WOYCT5M6.cjs} +284 -83
  54. package/dist/chunk-WOYCT5M6.cjs.map +1 -0
  55. package/dist/{chunk-WBLRUJ77.js → chunk-ZEDMFTKD.js} +10 -10
  56. package/dist/{chunk-WBLRUJ77.js.map → chunk-ZEDMFTKD.js.map} +1 -1
  57. package/dist/{chunk-UIGSH2XB.js → chunk-ZPCO3CEB.js} +3 -3
  58. package/dist/{chunk-UIGSH2XB.js.map → chunk-ZPCO3CEB.js.map} +1 -1
  59. package/dist/{chunk-DMCFARGP.cjs → chunk-ZSY4VANQ.cjs} +13 -13
  60. package/dist/{chunk-DMCFARGP.cjs.map → chunk-ZSY4VANQ.cjs.map} +1 -1
  61. package/dist/components/ActivityPreview.cjs +12 -12
  62. package/dist/components/ActivityPreview.d.cts +2 -2
  63. package/dist/components/ActivityPreview.d.ts +2 -2
  64. package/dist/components/ActivityPreview.js +11 -11
  65. package/dist/components/ActivitySequence.cjs +13 -13
  66. package/dist/components/ActivitySequence.d.cts +2 -2
  67. package/dist/components/ActivitySequence.d.ts +2 -2
  68. package/dist/components/ActivitySequence.js +12 -12
  69. package/dist/components/Dictation.cjs +5 -5
  70. package/dist/components/Dictation.d.cts +1 -1
  71. package/dist/components/Dictation.d.ts +1 -1
  72. package/dist/components/Dictation.js +4 -4
  73. package/dist/components/FillInTheBlanks.cjs +5 -5
  74. package/dist/components/FillInTheBlanks.d.cts +1 -1
  75. package/dist/components/FillInTheBlanks.d.ts +1 -1
  76. package/dist/components/FillInTheBlanks.js +4 -4
  77. package/dist/components/GapSelect.cjs +5 -5
  78. package/dist/components/GapSelect.d.cts +1 -1
  79. package/dist/components/GapSelect.d.ts +1 -1
  80. package/dist/components/GapSelect.js +4 -4
  81. package/dist/components/InteractiveVideo.cjs +12 -12
  82. package/dist/components/InteractiveVideo.d.cts +117 -6
  83. package/dist/components/InteractiveVideo.d.ts +117 -6
  84. package/dist/components/InteractiveVideo.js +10 -10
  85. package/dist/components/MultipleChoice.cjs +5 -5
  86. package/dist/components/MultipleChoice.d.cts +1 -1
  87. package/dist/components/MultipleChoice.d.ts +1 -1
  88. package/dist/components/MultipleChoice.js +4 -4
  89. package/dist/components/PronunciationFeedback.cjs +4 -4
  90. package/dist/components/PronunciationFeedback.d.cts +1 -1
  91. package/dist/components/PronunciationFeedback.d.ts +1 -1
  92. package/dist/components/PronunciationFeedback.js +3 -3
  93. package/dist/components/ReadAloud.cjs +6 -6
  94. package/dist/components/ReadAloud.d.cts +2 -2
  95. package/dist/components/ReadAloud.d.ts +2 -2
  96. package/dist/components/ReadAloud.js +5 -5
  97. package/dist/components/StimulusPanel.cjs +4 -4
  98. package/dist/components/StimulusPanel.d.cts +1 -1
  99. package/dist/components/StimulusPanel.d.ts +1 -1
  100. package/dist/components/StimulusPanel.js +3 -3
  101. package/dist/components/WrittenResponse.cjs +5 -5
  102. package/dist/components/WrittenResponse.d.cts +3 -3
  103. package/dist/components/WrittenResponse.d.ts +3 -3
  104. package/dist/components/WrittenResponse.js +4 -4
  105. package/dist/i18n/LkIntlProvider.cjs +7 -7
  106. package/dist/i18n/LkIntlProvider.d.cts +2 -2
  107. package/dist/i18n/LkIntlProvider.d.ts +2 -2
  108. package/dist/i18n/LkIntlProvider.js +1 -1
  109. package/dist/index.cjs +32 -32
  110. package/dist/index.d.cts +3 -3
  111. package/dist/index.d.ts +3 -3
  112. package/dist/index.js +14 -14
  113. package/dist/{strings-zY2QQYpU.d.cts → strings-C6wM5aUQ.d.cts} +2 -0
  114. package/dist/{strings-Dgc5-DeA.d.ts → strings-Cd_2F-Bw.d.ts} +2 -0
  115. package/dist/theme/skin.css +16 -0
  116. package/package.json +1 -1
  117. package/dist/chunk-3IHVDQRC.js.map +0 -1
  118. package/dist/chunk-A2CPCOJA.cjs.map +0 -1
  119. package/dist/chunk-QIA5FAAW.js.map +0 -1
  120. package/dist/chunk-UISZWFI7.cjs.map +0 -1
@@ -1,13 +1,13 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
- var chunkDMCFARGP_cjs = require('./chunk-DMCFARGP.cjs');
5
- var chunkZA5QUQ2V_cjs = require('./chunk-ZA5QUQ2V.cjs');
6
- var chunkRJGCT35F_cjs = require('./chunk-RJGCT35F.cjs');
7
- var chunk2YZZL5FV_cjs = require('./chunk-2YZZL5FV.cjs');
8
- var chunk2WM2KSO7_cjs = require('./chunk-2WM2KSO7.cjs');
9
- var chunkP5FGJMMI_cjs = require('./chunk-P5FGJMMI.cjs');
10
- var chunkUISZWFI7_cjs = require('./chunk-UISZWFI7.cjs');
4
+ var chunkZSY4VANQ_cjs = require('./chunk-ZSY4VANQ.cjs');
5
+ var chunk2TFNDHJ5_cjs = require('./chunk-2TFNDHJ5.cjs');
6
+ var chunkB6S5ADHR_cjs = require('./chunk-B6S5ADHR.cjs');
7
+ var chunkRSQFGF5W_cjs = require('./chunk-RSQFGF5W.cjs');
8
+ var chunkML6L4LJH_cjs = require('./chunk-ML6L4LJH.cjs');
9
+ var chunk2S3MK4VX_cjs = require('./chunk-2S3MK4VX.cjs');
10
+ var chunkMQAZJQRE_cjs = require('./chunk-MQAZJQRE.cjs');
11
11
  var lkCore = require('@intellectif/lk-core');
12
12
  var react = require('react');
13
13
  var jsxRuntime = require('react/jsx-runtime');
@@ -702,8 +702,10 @@ function EndScreen({
702
702
  strings,
703
703
  onOpenQuiz,
704
704
  onWatchAgain,
705
+ pending,
705
706
  onFinish
706
707
  }) {
708
+ const pendingId = `${idPrefix}-end-pending`;
707
709
  const headingRef = react.useRef(null);
708
710
  react.useEffect(() => {
709
711
  headingRef.current?.focus();
@@ -728,12 +730,23 @@ function EndScreen({
728
730
  ]
729
731
  }
730
732
  ) }, quiz.id)) }) : null,
733
+ onFinish !== void 0 && pending ? /* @__PURE__ */ jsxRuntime.jsx("p", { id: pendingId, className: "lk-iv-end-pending", role: "status", children: strings.videoAnswerPending }) : null,
731
734
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "lk-iv-end-actions", children: [
732
735
  /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "lk-iv-action", onClick: onWatchAgain, children: [
733
736
  /* @__PURE__ */ jsxRuntime.jsx(ReplayIcon, {}),
734
737
  strings.videoWatchAgain
735
738
  ] }),
736
- onFinish !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "lk-iv-action lk-iv-action-primary", onClick: onFinish, children: strings.videoFinish }) : null
739
+ onFinish !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
740
+ "button",
741
+ {
742
+ type: "button",
743
+ className: "lk-iv-action lk-iv-action-primary",
744
+ "aria-disabled": pending || void 0,
745
+ "aria-describedby": pending ? pendingId : void 0,
746
+ onClick: onFinish,
747
+ children: strings.videoFinish
748
+ }
749
+ ) : null
737
750
  ] })
738
751
  ] }) });
739
752
  }
@@ -1205,13 +1218,13 @@ function Player(props) {
1205
1218
  theme,
1206
1219
  sanitizeHtml
1207
1220
  } = props;
1208
- const strings = chunkUISZWFI7_cjs.useLkStrings(props.strings);
1221
+ const strings = chunkMQAZJQRE_cjs.useLkStrings(props.strings);
1209
1222
  const group = react.useRef(props.group).current;
1210
1223
  const timeline = group.timeline ?? { cues: [] };
1211
1224
  const media = group.stimulus.media;
1212
1225
  const chapters = timeline.chapters ?? [];
1213
1226
  const devError = react.useMemo(() => {
1214
- if (!chunkP5FGJMMI_cjs.isDevelopment()) {
1227
+ if (!chunk2S3MK4VX_cjs.isDevelopment()) {
1215
1228
  return null;
1216
1229
  }
1217
1230
  if (group.timeline === void 0) {
@@ -1288,18 +1301,61 @@ function Player(props) {
1288
1301
  });
1289
1302
  const answeredRef = react.useRef(answered);
1290
1303
  answeredRef.current = answered;
1291
- const scores = react.useRef(/* @__PURE__ */ new Map());
1292
- const markAnswered = react.useCallback((slotId) => {
1304
+ const setSlotAnswered = react.useCallback((slotId, on) => {
1293
1305
  setAnswered((previous) => {
1294
- if (previous.has(slotId)) {
1306
+ if (previous.has(slotId) === on) {
1295
1307
  return previous;
1296
1308
  }
1297
1309
  const next = new Set(previous);
1298
- next.add(slotId);
1310
+ if (on) {
1311
+ next.add(slotId);
1312
+ } else {
1313
+ next.delete(slotId);
1314
+ }
1299
1315
  answeredRef.current = next;
1300
1316
  return next;
1301
1317
  });
1302
1318
  }, []);
1319
+ const [scores, setScores] = react.useState(() => /* @__PURE__ */ new Map());
1320
+ const setSlotScore = react.useCallback((slotId, score) => {
1321
+ setScores((previous) => {
1322
+ if (previous.get(slotId) === score) {
1323
+ return previous;
1324
+ }
1325
+ const next = new Map(previous);
1326
+ if (score === void 0) {
1327
+ next.delete(slotId);
1328
+ } else {
1329
+ next.set(slotId, score);
1330
+ }
1331
+ return next;
1332
+ });
1333
+ }, []);
1334
+ const [pending, setPendingState] = react.useState(() => /* @__PURE__ */ new Set());
1335
+ const pendingRef = react.useRef(pending);
1336
+ const setPendingKey = react.useCallback((key, on) => {
1337
+ setPendingState((previous) => {
1338
+ if (previous.has(key) === on) {
1339
+ return previous;
1340
+ }
1341
+ const next = new Set(previous);
1342
+ if (on) {
1343
+ next.add(key);
1344
+ } else {
1345
+ next.delete(key);
1346
+ }
1347
+ pendingRef.current = next;
1348
+ return next;
1349
+ });
1350
+ }, []);
1351
+ const latestTakes = react.useRef(/* @__PURE__ */ new Map());
1352
+ const alive = react.useRef(true);
1353
+ react.useEffect(() => {
1354
+ alive.current = true;
1355
+ return () => {
1356
+ alive.current = false;
1357
+ };
1358
+ }, []);
1303
1359
  const finished = react.useCallback(
1304
1360
  (cueId) => (slotsByCue.get(cueId) ?? []).every((slot) => answeredRef.current.has(slot.slotId)),
1305
1361
  [slotsByCue]
@@ -1308,6 +1364,7 @@ function Player(props) {
1308
1364
  const videoRef = react.useRef(null);
1309
1365
  const playButtonRef = react.useRef(null);
1310
1366
  const quizHeadingRef = react.useRef(null);
1367
+ const [portalContainer, setPortalContainer] = react.useState(null);
1311
1368
  const [playing, setPlaying] = react.useState(false);
1312
1369
  const [waiting, setWaiting] = react.useState(false);
1313
1370
  const [errorCode, setErrorCode] = react.useState(null);
@@ -1557,9 +1614,9 @@ function Player(props) {
1557
1614
  const loaded = react.useRef(/* @__PURE__ */ new Map());
1558
1615
  const loadCues = react.useCallback((track) => {
1559
1616
  const key = trackKey(track);
1560
- const pending = loading.current.get(key);
1561
- if (pending !== void 0) {
1562
- return pending;
1617
+ const pending2 = loading.current.get(key);
1618
+ if (pending2 !== void 0) {
1619
+ return pending2;
1563
1620
  }
1564
1621
  const request = Promise.resolve().then(
1565
1622
  () => loaderRef.current ? loaderRef.current(track) : fetch(track.src, { credentials: "same-origin" }).then((response) => {
@@ -1888,7 +1945,7 @@ function Player(props) {
1888
1945
  }));
1889
1946
  const totalQuestions = quizzes.reduce((sum, quiz) => sum + quiz.total, 0);
1890
1947
  const answeredCount = quizzes.reduce((sum, quiz) => sum + quiz.answered, 0);
1891
- const graded = [...scores.current.values()];
1948
+ const graded = [...scores.values()];
1892
1949
  const percent = graded.length === 0 ? null : Math.round(graded.reduce((a, b) => a + b, 0) / graded.length * 100);
1893
1950
  const summary = react.useCallback(() => {
1894
1951
  return {
@@ -1910,11 +1967,12 @@ function Player(props) {
1910
1967
  finishedOnce.current = true;
1911
1968
  onFinished?.(summary());
1912
1969
  }, [onFinished, summary]);
1970
+ const answerPending = pending.size > 0;
1913
1971
  react.useEffect(() => {
1914
- if (ended && totalQuestions > 0 && answeredCount === totalQuestions && renderMode !== "review") {
1972
+ if (ended && !answerPending && totalQuestions > 0 && answeredCount === totalQuestions && renderMode !== "review") {
1915
1973
  finish();
1916
1974
  }
1917
- }, [ended, totalQuestions, answeredCount, renderMode, finish]);
1975
+ }, [ended, answerPending, totalQuestions, answeredCount, renderMode, finish]);
1918
1976
  const slotBindings = react.useMemo(() => {
1919
1977
  const bindings = /* @__PURE__ */ new Map();
1920
1978
  if (recordingBinding === void 0) {
@@ -1935,70 +1993,172 @@ function Player(props) {
1935
1993
  }
1936
1994
  return bindings;
1937
1995
  }, [slots, recordingBinding]);
1938
- const renderQuestion = (slot, cueId) => {
1939
- const activity = slot.activity;
1940
- const place = {
1941
- slotId: slot.slotId,
1942
- index: slot.index,
1943
- activityId: activity.id,
1944
- cueId
1996
+ const places = react.useMemo(() => {
1997
+ const byId = /* @__PURE__ */ new Map();
1998
+ for (const [cueId, cueSlots] of slotsByCue) {
1999
+ for (const slot of cueSlots) {
2000
+ byId.set(slot.slotId, {
2001
+ slotId: slot.slotId,
2002
+ index: slot.index,
2003
+ activityId: slot.activity.id,
2004
+ cueId
2005
+ });
2006
+ }
2007
+ }
2008
+ return byId;
2009
+ }, [slotsByCue]);
2010
+ const reportTo = react.useRef({ onSubmit, onActivityComplete, onInteraction, renderMode });
2011
+ reportTo.current = { onSubmit, onActivityComplete, onInteraction, renderMode };
2012
+ const calls = react.useRef(/* @__PURE__ */ new Map());
2013
+ const callsFor = (place) => {
2014
+ const made = calls.current.get(place.slotId);
2015
+ if (made !== void 0) {
2016
+ return made;
2017
+ }
2018
+ const { slotId } = place;
2019
+ const warned = /* @__PURE__ */ new Set();
2020
+ const refused = (call) => {
2021
+ if (reportTo.current.renderMode !== "review") {
2022
+ return false;
2023
+ }
2024
+ if (chunk2S3MK4VX_cjs.isDevelopment() && !warned.has(call)) {
2025
+ warned.add(call);
2026
+ console.warn(
2027
+ `InteractiveVideo: \`${call}()\` was called for question "${slotId}" in renderMode "review", where nothing is submittable. It was ignored.`
2028
+ );
2029
+ }
2030
+ return true;
2031
+ };
2032
+ const next = {
2033
+ submit: (response) => {
2034
+ if (!alive.current || refused("submit")) {
2035
+ return;
2036
+ }
2037
+ setSlotAnswered(slotId, true);
2038
+ reportTo.current.onSubmit?.(response, place);
2039
+ },
2040
+ complete: (result) => {
2041
+ if (!alive.current || refused("complete")) {
2042
+ return;
2043
+ }
2044
+ setSlotAnswered(slotId, true);
2045
+ setSlotScore(slotId, result.maxScore > 0 ? result.score / result.maxScore : void 0);
2046
+ reportTo.current.onActivityComplete?.(result, place);
2047
+ },
2048
+ clear: () => {
2049
+ if (!alive.current || refused("clear")) {
2050
+ return;
2051
+ }
2052
+ setSlotAnswered(slotId, false);
2053
+ setSlotScore(slotId, void 0);
2054
+ },
2055
+ setPending: (on) => {
2056
+ if (!alive.current) {
2057
+ return;
2058
+ }
2059
+ setPendingKey(`host:${slotId}`, on === true);
2060
+ },
2061
+ emit: (type, payload) => {
2062
+ if (!alive.current) {
2063
+ return;
2064
+ }
2065
+ reportTo.current.onInteraction?.({
2066
+ type,
2067
+ activityId: place.activityId,
2068
+ timestamp: Date.now(),
2069
+ ...payload !== void 0 ? { payload } : {}
2070
+ });
2071
+ }
1945
2072
  };
1946
- const restored = props.responses !== void 0 && Object.hasOwn(props.responses, slot.slotId) ? props.responses[slot.slotId] : void 0;
1947
- const outcome = props.outcomes !== void 0 && Object.hasOwn(props.outcomes, slot.slotId) ? props.outcomes[slot.slotId] : void 0;
2073
+ calls.current.set(slotId, next);
2074
+ return next;
2075
+ };
2076
+ const reportTake = (slotId, take, state) => {
2077
+ if (!alive.current) {
2078
+ return;
2079
+ }
2080
+ const latest = latestTakes.current.get(slotId);
2081
+ if (latest !== void 0 && take < latest) {
2082
+ return;
2083
+ }
2084
+ latestTakes.current.set(slotId, take);
2085
+ setPendingKey(`take:${slotId}`, state === "in-flight");
2086
+ };
2087
+ const channels = react.useRef(/* @__PURE__ */ new Map());
2088
+ const channelFor = (slotId) => {
2089
+ let channel = channels.current.get(slotId);
2090
+ if (channel === void 0) {
2091
+ channel = {
2092
+ captureGroup: `${playerId}::${slotId}`,
2093
+ takeState: (take, state) => reportTake(slotId, take, state)
2094
+ };
2095
+ channels.current.set(slotId, channel);
2096
+ }
2097
+ return channel;
2098
+ };
2099
+ const seedsFor = (slotId) => ({
2100
+ restored: props.responses !== void 0 && Object.hasOwn(props.responses, slotId) ? props.responses[slotId] : void 0,
2101
+ outcome: props.outcomes !== void 0 && Object.hasOwn(props.outcomes, slotId) ? props.outcomes[slotId] : void 0
2102
+ });
2103
+ const questionFor = (slot, place, active) => {
2104
+ const { restored, outcome } = seedsFor(slot.slotId);
2105
+ return {
2106
+ activity: slot.activity,
2107
+ slot: place,
2108
+ renderMode,
2109
+ active,
2110
+ ...locale !== void 0 ? { locale } : {},
2111
+ ...restored !== void 0 ? { defaultValue: restored } : {},
2112
+ defaultSubmitted: submitted.has(slot.slotId),
2113
+ ...outcome !== void 0 ? { outcome } : {},
2114
+ portalContainer,
2115
+ ...callsFor(place)
2116
+ };
2117
+ };
2118
+ const sdkQuestion = (slot, place) => {
2119
+ const activity = slot.activity;
2120
+ const { restored, outcome } = seedsFor(slot.slotId);
2121
+ const reported = callsFor(place);
1948
2122
  const common = {
1949
2123
  renderMode,
1950
2124
  ...restored !== void 0 ? { defaultValue: restored } : {},
1951
2125
  ...submitted.has(slot.slotId) ? { defaultSubmitted: true } : {},
1952
2126
  ...outcome !== void 0 ? { outcome } : {},
1953
- onSubmit: (response) => {
1954
- markAnswered(slot.slotId);
1955
- onSubmit?.(response, place);
1956
- },
1957
- onComplete: (result) => {
1958
- markAnswered(slot.slotId);
1959
- if (result.maxScore > 0) {
1960
- scores.current.set(slot.slotId, result.score / result.maxScore);
1961
- }
1962
- onActivityComplete?.(result, place);
1963
- },
2127
+ onSubmit: reported.submit,
2128
+ onComplete: reported.complete,
1964
2129
  ...onInteraction !== void 0 ? { onInteraction } : {},
1965
2130
  ...sanitizeHtml !== void 0 ? { sanitizeHtml } : {},
1966
2131
  ...props.strings !== void 0 ? { strings: props.strings } : {},
1967
2132
  ...locale !== void 0 ? { locale } : {}
1968
2133
  };
1969
- let question;
1970
2134
  switch (activity.type) {
1971
2135
  case "multiple-choice":
1972
- question = /* @__PURE__ */ jsxRuntime.jsx(
1973
- chunkDMCFARGP_cjs.MultipleChoice,
2136
+ return /* @__PURE__ */ jsxRuntime.jsx(
2137
+ chunkZSY4VANQ_cjs.MultipleChoice,
1974
2138
  {
1975
2139
  data: activity,
1976
2140
  ...common,
1977
2141
  ...shuffleSeed !== void 0 ? { shuffleSeed } : {}
1978
2142
  }
1979
2143
  );
1980
- break;
1981
2144
  case "fill-in-the-blanks":
1982
- question = /* @__PURE__ */ jsxRuntime.jsx(chunkZA5QUQ2V_cjs.FillInTheBlanks, { data: activity, ...common });
1983
- break;
2145
+ return /* @__PURE__ */ jsxRuntime.jsx(chunk2TFNDHJ5_cjs.FillInTheBlanks, { data: activity, ...common });
1984
2146
  case "gap-select":
1985
- question = /* @__PURE__ */ jsxRuntime.jsx(
1986
- chunkRJGCT35F_cjs.GapSelect,
2147
+ return /* @__PURE__ */ jsxRuntime.jsx(
2148
+ chunkB6S5ADHR_cjs.GapSelect,
1987
2149
  {
1988
2150
  data: activity,
1989
2151
  ...common,
1990
2152
  ...shuffleSeed !== void 0 ? { shuffleSeed } : {}
1991
2153
  }
1992
2154
  );
1993
- break;
1994
2155
  case "dictation":
1995
- question = /* @__PURE__ */ jsxRuntime.jsx(chunk2YZZL5FV_cjs.Dictation, { data: activity, ...common });
1996
- break;
2156
+ return /* @__PURE__ */ jsxRuntime.jsx(chunkRSQFGF5W_cjs.Dictation, { data: activity, ...common });
1997
2157
  case "read-aloud": {
1998
2158
  const binding = slotBindings.get(slot.slotId);
1999
2159
  const assessment = props.assessments !== void 0 && Object.hasOwn(props.assessments, slot.slotId) ? props.assessments[slot.slotId] : void 0;
2000
- question = /* @__PURE__ */ jsxRuntime.jsx(
2001
- chunk2WM2KSO7_cjs.ReadAloud,
2160
+ return /* @__PURE__ */ jsxRuntime.jsx(
2161
+ chunkML6L4LJH_cjs.ReadAloud,
2002
2162
  {
2003
2163
  data: activity,
2004
2164
  ...common,
@@ -2007,21 +2167,10 @@ function Player(props) {
2007
2167
  ...workletUrl !== void 0 ? { workletUrl } : {}
2008
2168
  }
2009
2169
  );
2010
- break;
2011
2170
  }
2012
2171
  default:
2013
- question = null;
2014
- }
2015
- return question;
2016
- };
2017
- const channels = react.useRef(/* @__PURE__ */ new Map());
2018
- const channelFor = (slotId) => {
2019
- let channel = channels.current.get(slotId);
2020
- if (channel === void 0) {
2021
- channel = { captureGroup: `${playerId}::${slotId}`, takeState: () => void 0 };
2022
- channels.current.set(slotId, channel);
2172
+ return null;
2023
2173
  }
2024
- return channel;
2025
2174
  };
2026
2175
  if (devError !== null) {
2027
2176
  throw devError;
@@ -2442,7 +2591,7 @@ function Player(props) {
2442
2591
  "aria-labelledby": `${playerId}-quiz-title`,
2443
2592
  hidden: openQuiz === null,
2444
2593
  onKeyDown: (event) => {
2445
- if (event.key === "Escape" && !required && openQuiz !== null) {
2594
+ if (event.key === "Escape" && !event.defaultPrevented && !required && openQuiz !== null) {
2446
2595
  event.preventDefault();
2447
2596
  closeQuiz("skip");
2448
2597
  }
@@ -2489,15 +2638,29 @@ function Player(props) {
2489
2638
  ] }) : null
2490
2639
  ] }) : null,
2491
2640
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "lk-iv-quiz-body", children: cues.filter((cue) => mounted.has(cue.id)).map(
2492
- (cue) => (slotsByCue.get(cue.id) ?? []).map((slot, index) => /* @__PURE__ */ jsxRuntime.jsx(
2493
- QuestionPane,
2494
- {
2495
- hidden: !(openQuiz?.cueId === cue.id && step === index),
2496
- channel: channelFor(slot.slotId),
2497
- children: renderQuestion(slot, cue.id)
2498
- },
2499
- slot.slotId
2500
- ))
2641
+ (cue) => (slotsByCue.get(cue.id) ?? []).map((slot, index) => {
2642
+ const shown = openQuiz?.cueId === cue.id && step === index;
2643
+ const place = places.get(slot.slotId);
2644
+ return /* @__PURE__ */ jsxRuntime.jsx(
2645
+ QuestionPane,
2646
+ {
2647
+ hidden: !shown,
2648
+ channel: channelFor(slot.slotId),
2649
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2650
+ SlotQuestion,
2651
+ {
2652
+ title: slot.activity.title,
2653
+ strings,
2654
+ render: props.renderQuestion,
2655
+ question: props.renderQuestion === void 0 ? void 0 : questionFor(slot, place, shown),
2656
+ sdk: () => sdkQuestion(slot, place),
2657
+ setHostPending: callsFor(place).setPending
2658
+ }
2659
+ )
2660
+ },
2661
+ slot.slotId
2662
+ );
2663
+ })
2501
2664
  ) }),
2502
2665
  openCue !== void 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "lk-iv-quiz-foot", children: [
2503
2666
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "lk-iv-quiz-foot-start", children: [
@@ -2553,7 +2716,14 @@ function Player(props) {
2553
2716
  }
2554
2717
  },
2555
2718
  onWatchAgain: togglePlay,
2556
- onFinish: renderMode === "review" ? void 0 : finish
2719
+ pending: answerPending,
2720
+ onFinish: renderMode === "review" ? void 0 : () => {
2721
+ if (pendingRef.current.size > 0) {
2722
+ announce(strings.videoAnswerPending);
2723
+ return;
2724
+ }
2725
+ finish();
2726
+ }
2557
2727
  }
2558
2728
  ) : null,
2559
2729
  sheet ? /* @__PURE__ */ jsxRuntime.jsx(
@@ -2604,12 +2774,43 @@ function Player(props) {
2604
2774
  }
2605
2775
  }
2606
2776
  ) : null,
2607
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "lk-iv-live", "aria-live": "polite", "aria-atomic": "true", children: announcement })
2777
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "lk-iv-live", "aria-live": "polite", "aria-atomic": "true", children: announcement }),
2778
+ /* @__PURE__ */ jsxRuntime.jsx("div", { ref: setPortalContainer, className: "lk-iv-portal" })
2608
2779
  ]
2609
2780
  }
2610
2781
  )
2611
2782
  );
2612
2783
  }
2784
+ function SlotQuestion({
2785
+ title,
2786
+ strings,
2787
+ ...content
2788
+ }) {
2789
+ return /* @__PURE__ */ jsxRuntime.jsx(
2790
+ chunk2S3MK4VX_cjs.ActivityErrorBoundary,
2791
+ {
2792
+ ...title !== void 0 ? { activityTitle: title } : {},
2793
+ strings,
2794
+ children: /* @__PURE__ */ jsxRuntime.jsx(SlotContent, { ...content })
2795
+ }
2796
+ );
2797
+ }
2798
+ function SlotContent({
2799
+ render,
2800
+ question,
2801
+ sdk,
2802
+ setHostPending
2803
+ }) {
2804
+ const hosted = render !== void 0 && question !== void 0 ? render(question) : void 0;
2805
+ const hosting = hosted !== void 0;
2806
+ react.useEffect(() => {
2807
+ if (!hosting) {
2808
+ return;
2809
+ }
2810
+ return () => setHostPending(false);
2811
+ }, [hosting, setHostPending]);
2812
+ return hosting ? hosted : sdk();
2813
+ }
2613
2814
  function QuestionPane({
2614
2815
  hidden,
2615
2816
  channel,
@@ -2621,7 +2822,7 @@ function QuestionPane({
2621
2822
  if (!hidden) {
2622
2823
  return;
2623
2824
  }
2624
- chunk2WM2KSO7_cjs.stopCaptureGroup(captureGroup);
2825
+ chunkML6L4LJH_cjs.stopCaptureGroup(captureGroup);
2625
2826
  for (const media of ref.current?.querySelectorAll("audio, video") ?? []) {
2626
2827
  const element = media;
2627
2828
  if (!element.paused) {
@@ -2629,7 +2830,7 @@ function QuestionPane({
2629
2830
  }
2630
2831
  }
2631
2832
  }, [hidden, captureGroup]);
2632
- return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: "lk-iv-question", hidden, children: /* @__PURE__ */ jsxRuntime.jsx(chunk2WM2KSO7_cjs.SequenceSlotContext.Provider, { value: channel, children }) });
2833
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: "lk-iv-question", hidden, children: /* @__PURE__ */ jsxRuntime.jsx(chunkML6L4LJH_cjs.SequenceSlotContext.Provider, { value: channel, children }) });
2633
2834
  }
2634
2835
  function bufferedAhead(video) {
2635
2836
  const ranges = video.buffered;
@@ -2669,9 +2870,9 @@ function markerState(quizSlots, answered, renderMode, outcomes) {
2669
2870
  return "unreached";
2670
2871
  }
2671
2872
  function InteractiveVideo2(props) {
2672
- const strings = chunkUISZWFI7_cjs.useLkStrings(props.strings);
2873
+ const strings = chunkMQAZJQRE_cjs.useLkStrings(props.strings);
2673
2874
  return /* @__PURE__ */ jsxRuntime.jsx(
2674
- chunkP5FGJMMI_cjs.ActivityErrorBoundary,
2875
+ chunk2S3MK4VX_cjs.ActivityErrorBoundary,
2675
2876
  {
2676
2877
  ...props.group?.title !== void 0 ? { activityTitle: props.group.title } : {},
2677
2878
  strings,
@@ -2682,5 +2883,5 @@ function InteractiveVideo2(props) {
2682
2883
 
2683
2884
  exports.InteractiveVideo = InteractiveVideo2;
2684
2885
  exports.resolveCaptionTracks = resolveCaptionTracks;
2685
- //# sourceMappingURL=chunk-A2CPCOJA.cjs.map
2686
- //# sourceMappingURL=chunk-A2CPCOJA.cjs.map
2886
+ //# sourceMappingURL=chunk-WOYCT5M6.cjs.map
2887
+ //# sourceMappingURL=chunk-WOYCT5M6.cjs.map