@tinyweb_dev/oe-exam-sdk 1.0.8 → 1.0.10

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 (138) hide show
  1. package/dist/components/exams/take/components/QuestionRenderer.js +1 -5
  2. package/dist/components/exams/take/components/question-renderers/ChooseThenAnswerGroupRenderer.js +1 -1
  3. package/dist/components/exams/take/components/question-renderers/MoversCrossOutWordGroupRenderer.js +24 -10
  4. package/dist/components/exams/take/components/question-renderers/MoversCrosswordPuzzleRenderer.js +1 -1
  5. package/dist/components/exams/take/components/question-renderers/MoversFillInBlankGroupRenderer.js +2 -1
  6. package/dist/components/exams/take/components/speaking/renderers/SpeakingSpontaneousQaGroupRenderer.js +12 -2
  7. package/dist/components/exams/take/hooks/useSpontaneousQaGroupRendererSetup.js +2 -1
  8. package/dist/components/exams/take/utils/answer-transformers.js +16 -1
  9. package/dist/components/exams/take/utils/cross-out-word-group.transformer.js +4 -6
  10. package/dist/components/exams/take/utils/question-transformers.d.ts +5 -0
  11. package/dist/components/exams/take/utils/question-transformers.js +6 -0
  12. package/dist/components/questions/_shared/components/compact/KidChoiceRow.d.ts +12 -0
  13. package/dist/components/questions/_shared/components/compact/KidChoiceRow.js +33 -0
  14. package/dist/components/questions/_shared/components/compact/KidInstruction.d.ts +5 -0
  15. package/dist/components/questions/_shared/components/compact/KidInstruction.js +9 -0
  16. package/dist/components/questions/_shared/components/compact/KidPrompt.d.ts +5 -0
  17. package/dist/components/questions/_shared/components/compact/KidPrompt.js +9 -0
  18. package/dist/components/questions/_shared/components/compact/KidQuestionCard.d.ts +12 -0
  19. package/dist/components/questions/_shared/components/compact/KidQuestionCard.js +7 -0
  20. package/dist/components/questions/_shared/components/compact/index.d.ts +4 -0
  21. package/dist/components/questions/_shared/components/compact/index.js +4 -0
  22. package/dist/components/questions/_shared/types/answer-the-question-group.type.d.ts +3 -0
  23. package/dist/components/questions/_shared/types/choose-then-answer-group.type.d.ts +17 -0
  24. package/dist/components/questions/_shared/types/cross-out-word-group.type.d.ts +1 -0
  25. package/dist/components/questions/_shared/types/crossword-puzzle.type.d.ts +5 -1
  26. package/dist/components/questions/_shared/types/spontaneous-qa-group.type.d.ts +17 -0
  27. package/dist/components/questions/_shared/types/true-false-correct-group.type.d.ts +1 -0
  28. package/dist/components/questions/_shared/types/true-false-group.type.d.ts +1 -0
  29. package/dist/components/questions/types/answer-the-question/AnswerTheQuestionClient.js +18 -19
  30. package/dist/components/questions/types/answer-the-question-group/AnswerTheQuestionGroupClient.d.ts +1 -1
  31. package/dist/components/questions/types/answer-the-question-group/AnswerTheQuestionGroupClient.js +16 -17
  32. package/dist/components/questions/types/answer-the-question-group/AnswerTheQuestionGroupCreator.js +7 -4
  33. package/dist/components/questions/types/answer-the-question-group/map-answer-the-question-group-data.js +2 -0
  34. package/dist/components/questions/types/answer-the-question-group/transform.js +12 -5
  35. package/dist/components/questions/types/arrange-letters-into-words/ArrangeLettersIntoWordsClient.js +17 -11
  36. package/dist/components/questions/types/choose-correct-adjective/ChooseCorrectAdjectiveClient.js +15 -42
  37. package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerClient.js +15 -36
  38. package/dist/components/questions/types/choose-the-correct-answer-group/ChooseTheCorrectAnswerGroupClient.js +9 -32
  39. package/dist/components/questions/types/choose-then-answer-group/ChooseThenAnswerGroupClient.d.ts +1 -1
  40. package/dist/components/questions/types/choose-then-answer-group/ChooseThenAnswerGroupClient.js +76 -11
  41. package/dist/components/questions/types/choose-then-answer-group/ChooseThenAnswerGroupCreator.js +54 -6
  42. package/dist/components/questions/types/choose-then-answer-group/map-choose-then-answer-group-data.d.ts +4 -1
  43. package/dist/components/questions/types/choose-then-answer-group/map-choose-then-answer-group-data.js +39 -2
  44. package/dist/components/questions/types/choose-then-answer-group/transform.js +27 -14
  45. package/dist/components/questions/types/cross-out-word-group/CrossOutWordGroupClient.d.ts +1 -1
  46. package/dist/components/questions/types/cross-out-word-group/CrossOutWordGroupClient.js +76 -7
  47. package/dist/components/questions/types/cross-out-word-group/CrossOutWordGroupCreator.js +24 -44
  48. package/dist/components/questions/types/cross-out-word-group/index.d.ts +1 -0
  49. package/dist/components/questions/types/cross-out-word-group/index.js +1 -0
  50. package/dist/components/questions/types/cross-out-word-group/map-cross-out-word-group-data.js +9 -9
  51. package/dist/components/questions/types/cross-out-word-group/tokenize.d.ts +2 -0
  52. package/dist/components/questions/types/cross-out-word-group/tokenize.js +11 -0
  53. package/dist/components/questions/types/cross-out-word-group/transform.js +2 -4
  54. package/dist/components/questions/types/crossword-puzzle/CrosswordPuzzleClient.d.ts +2 -1
  55. package/dist/components/questions/types/crossword-puzzle/CrosswordPuzzleClient.js +20 -8
  56. package/dist/components/questions/types/crossword-puzzle/CrosswordPuzzleCreator.js +68 -11
  57. package/dist/components/questions/types/crossword-puzzle/transform.js +59 -30
  58. package/dist/components/questions/types/fill-in-blank/FillInBlankClient.js +26 -31
  59. package/dist/components/questions/types/fill-in-blank-group/FillInBlankAnswerKey.d.ts +6 -0
  60. package/dist/components/questions/types/fill-in-blank-group/FillInBlankAnswerKey.js +17 -0
  61. package/dist/components/questions/types/fill-in-blank-group/FillInBlankGroupClient.js +32 -28
  62. package/dist/components/questions/types/fill-in-blank-group/FillInBlankGroupCreator.js +109 -26
  63. package/dist/components/questions/types/fill-in-blank-group/FillInBlankGroupMediaField.js +21 -11
  64. package/dist/components/questions/types/fill-in-blank-group/blank-utils.d.ts +1 -0
  65. package/dist/components/questions/types/fill-in-blank-group/blank-utils.js +4 -1
  66. package/dist/components/questions/types/fill-missing-words-in-grid/FillMissingWordsInGridClient.js +32 -31
  67. package/dist/components/questions/types/find-words-in-matrix/FindWordsInMatrixClient.d.ts +12 -2
  68. package/dist/components/questions/types/find-words-in-matrix/FindWordsInMatrixClient.js +188 -46
  69. package/dist/components/questions/types/find-words-in-matrix/FindWordsInMatrixCreator.js +6 -2
  70. package/dist/components/questions/types/find-words-in-matrix/transform.js +5 -0
  71. package/dist/components/questions/types/label-the-picture/LabelThePictureClient.js +4 -3
  72. package/dist/components/questions/types/listen-and-choose-from-answer-group/ListenAndChooseFromAnswerGroupClient.js +11 -30
  73. package/dist/components/questions/types/listen-and-speak-answer/ListenAndSpeakAnswerClient.js +7 -6
  74. package/dist/components/questions/types/listen-and-speak-compare-images/ListenAndSpeakCompareImagesClient.js +2 -1
  75. package/dist/components/questions/types/listen-and-speak-image-group/ListenAndSpeakImageGroupClient.js +14 -13
  76. package/dist/components/questions/types/listen-and-speak-info-exchange/ListenAndSpeakInfoExchangeClient.js +4 -3
  77. package/dist/components/questions/types/listen-and-speak-odd-one-out/ListenAndSpeakOddOneOutClient.js +4 -3
  78. package/dist/components/questions/types/listen-and-speak-question-list/ListenAndSpeakQuestionListClient.js +11 -10
  79. package/dist/components/questions/types/listen-and-speak-with-story-images/ListenAndSpeakWithStoryImagesClient.js +4 -3
  80. package/dist/components/questions/types/match-by-writing-answer/MatchByWritingAnswerClient.js +13 -11
  81. package/dist/components/questions/types/match-columns-to-make-sentences/MatchColumnsToMakeSentencesClient.js +17 -14
  82. package/dist/components/questions/types/match-word-to-picture/MatchWordToPictureClient.js +16 -12
  83. package/dist/components/questions/types/match-word-to-picture/MatchWordToPictureGroupClient.js +14 -14
  84. package/dist/components/questions/types/match-word-to-picture-group/MatchWordToPictureGroupClient.js +13 -13
  85. package/dist/components/questions/types/matching-with-lines-group/MatchingWithLinesGroupClient.js +7 -6
  86. package/dist/components/questions/types/read-passage-and-answer-questions/ReadPassageAndAnswerQuestionsClient.js +8 -26
  87. package/dist/components/questions/types/sort-words-into-categories/SortWordsIntoCategoriesClient.js +2 -1
  88. package/dist/components/questions/types/speaking-conversation/SpeakingConversationPreviewClient.js +6 -5
  89. package/dist/components/questions/types/speaking-cue-card/SpeakingCueCardClient.js +2 -1
  90. package/dist/components/questions/types/speaking-describe-image/SpeakingDescribeImageClient.js +5 -4
  91. package/dist/components/questions/types/spontaneous-qa-group/SpontaneousQaGroupClient.d.ts +1 -1
  92. package/dist/components/questions/types/spontaneous-qa-group/SpontaneousQaGroupClient.js +54 -11
  93. package/dist/components/questions/types/spontaneous-qa-group/SpontaneousQaGroupCreator.js +11 -7
  94. package/dist/components/questions/types/spontaneous-qa-group/creator-helpers.js +8 -2
  95. package/dist/components/questions/types/spontaneous-qa-group/flatten.d.ts +1 -0
  96. package/dist/components/questions/types/spontaneous-qa-group/flatten.js +4 -2
  97. package/dist/components/questions/types/spontaneous-qa-group/map-spontaneous-qa-group-data.js +5 -3
  98. package/dist/components/questions/types/spontaneous-qa-group/register.js +5 -2
  99. package/dist/components/questions/types/spontaneous-qa-group/transform.js +6 -2
  100. package/dist/components/questions/types/true-false/TrueFalseClient.js +5 -54
  101. package/dist/components/questions/types/true-false-correct-group/TrueFalseCorrectGroupClient.d.ts +1 -1
  102. package/dist/components/questions/types/true-false-correct-group/TrueFalseCorrectGroupClient.js +39 -19
  103. package/dist/components/questions/types/true-false-group/TrueFalseGroupClient.d.ts +1 -1
  104. package/dist/components/questions/types/true-false-group/TrueFalseGroupClient.js +20 -19
  105. package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphClient.js +76 -81
  106. package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormClient.js +17 -16
  107. package/dist/components/questions/types/word-order-and-match-group/WordOrderAndMatchGroupClient.js +31 -36
  108. package/dist/components/questions/types/word-ordering/WordOrderingClient.js +15 -14
  109. package/dist/components/questions/types/word-ordering-group/WordOrderingGroupClient.js +9 -8
  110. package/dist/components/questions/types/write-correct-verb-form/WriteCorrectVerbFormClient.js +16 -13
  111. package/dist/components/questions/viewer/AnswerTheQuestionGroupViewer.d.ts +3 -2
  112. package/dist/components/questions/viewer/AnswerTheQuestionGroupViewer.js +12 -5
  113. package/dist/components/questions/viewer/ChooseThenAnswerGroupViewer.d.ts +3 -2
  114. package/dist/components/questions/viewer/ChooseThenAnswerGroupViewer.js +4 -3
  115. package/dist/components/questions/viewer/CrossOutWordGroupViewer.d.ts +3 -1
  116. package/dist/components/questions/viewer/CrossOutWordGroupViewer.js +12 -2
  117. package/dist/components/questions/viewer/FillInBlankGroupViewer.d.ts +6 -2
  118. package/dist/components/questions/viewer/FillInBlankGroupViewer.js +13 -7
  119. package/dist/components/questions/viewer/QuestionViewer.d.ts +9 -1
  120. package/dist/components/questions/viewer/QuestionViewer.js +23 -10
  121. package/dist/components/questions/viewer/SpontaneousQaGroupViewer.d.ts +7 -1
  122. package/dist/components/questions/viewer/SpontaneousQaGroupViewer.js +14 -2
  123. package/dist/components/questions/viewer/TrueFalseCorrectGroupViewer.d.ts +3 -2
  124. package/dist/components/questions/viewer/TrueFalseCorrectGroupViewer.js +14 -4
  125. package/dist/components/questions/viewer/TrueFalseGroupViewer.d.ts +5 -2
  126. package/dist/components/questions/viewer/TrueFalseGroupViewer.js +14 -4
  127. package/dist/components/questions/viewer/WordOrderAndMatchGroupViewer.d.ts +6 -2
  128. package/dist/components/questions/viewer/WordOrderAndMatchGroupViewer.js +26 -6
  129. package/dist/components/results/renderers/ReviewAnswerTheQuestionGroupRenderer.js +1 -1
  130. package/dist/components/results/renderers/review-question-body-movers.js +1 -1
  131. package/dist/components/results/review-data.js +8 -1
  132. package/dist/shared/lib/utils/question-reverse-transform.js +39 -5
  133. package/dist/shared/types/questions/answer-the-question-group.d.ts +8 -3
  134. package/dist/shared/types/questions/answer-the-question-group.js +5 -0
  135. package/dist/shared/types/questions/choose-then-answer-group.d.ts +3 -0
  136. package/dist/shared/types/questions/crossword-puzzle.d.ts +1 -0
  137. package/dist/shared/types/questions/find-words-in-matrix.d.ts +1 -0
  138. package/package.json +1 -1
@@ -38,7 +38,7 @@ import { MatchWordToPictureViewer } from './MatchWordToPictureViewer';
38
38
  import { MatchWordToPictureGroupViewer } from './MatchWordToPictureGroupViewer';
39
39
  import { MatchColumnsToMakeSentencesViewer } from './MatchColumnsToMakeSentencesViewer';
40
40
  import { WordOrderingGroupViewer } from './WordOrderingGroupViewer';
41
- export function QuestionViewer({ question, onSubmitAnswer, isReviewMode = false, userAnswer, }) {
41
+ export function QuestionViewer({ question, onSubmitAnswer, isReviewMode = false, userAnswer, gradeDetails, }) {
42
42
  const [selectedAnswer, setSelectedAnswer] = useState(userAnswer || null);
43
43
  const [playCount, setPlayCount] = useState(0);
44
44
  const audioRef = useRef(null);
@@ -477,6 +477,19 @@ export function QuestionViewer({ question, onSubmitAnswer, isReviewMode = false,
477
477
  }
478
478
  return (_jsxs("div", { className: "space-y-3", children: [content.title ? _jsx("h3", { className: "text-center text-lg font-bold uppercase text-slate-800", children: content.title }) : null, content.imageUrl ? (_jsx("div", { className: "flex justify-center", children: _jsx("img", { src: String(content.imageUrl), alt: "", className: "max-h-[180px] rounded-lg object-contain" }) })) : null, _jsx("div", { className: "space-y-2 text-base leading-relaxed text-slate-800", children: paragraph.split('\n').map((line, li) => (_jsx("div", { className: "flex flex-wrap items-baseline", children: renderLine(line, `wfp-${li}`) }, `wfp-l${li}`))) }), isReviewMode && correctAnswers.length > 0 ? (_jsxs("div", { className: "rounded-lg border border-emerald-200 bg-emerald-50/80 p-2.5 text-sm text-emerald-800", children: [_jsx("span", { className: "font-semibold", children: "\u0110\u00E1p \u00E1n: " }), correctAnswers.map((a, i) => (_jsxs("span", { className: "mr-2", children: ["(", i + 1, ") ", _jsx("span", { className: "font-bold underline", children: a || '—' })] }, `wfp-a${i}`)))] })) : null] }));
479
479
  };
480
+ const renderCrosswordPuzzle = () => {
481
+ const raw = userAnswer && typeof userAnswer === 'object' && !Array.isArray(userAnswer)
482
+ ? userAnswer
483
+ : {};
484
+ const answers = raw.answers && typeof raw.answers === 'object' && !Array.isArray(raw.answers)
485
+ ? raw.answers
486
+ : raw;
487
+ return (_jsx(CrosswordPuzzleClient, { content: question.content, correctAnswer: question.correctAnswer ?? question.answer, isReviewMode: isReviewMode, questionNumber: question.questionNumber, userAnswers: answers, onAnswerChange: isReviewMode
488
+ ? undefined
489
+ : (key, value) => {
490
+ onSubmitAnswer?.({ answers: { ...answers, [key]: value } });
491
+ } }));
492
+ };
480
493
  const renderQuestion = () => {
481
494
  const resolvedType = String(question.type ||
482
495
  question.questionType ||
@@ -488,9 +501,9 @@ export function QuestionViewer({ question, onSubmitAnswer, isReviewMode = false,
488
501
  case 'CHOOSE_THE_CORRECT_ANSWER_GROUP':
489
502
  return (_jsx(ChooseTheCorrectAnswerGroupViewer, { question: question, isReviewMode: isReviewMode, userAnswer: userAnswer, onSubmitAnswer: onSubmitAnswer }));
490
503
  case 'TRUE_FALSE_GROUP':
491
- return (_jsx(TrueFalseGroupViewer, { question: question, isReviewMode: isReviewMode, userAnswer: userAnswer }));
504
+ return (_jsx(TrueFalseGroupViewer, { question: question, isReviewMode: isReviewMode, userAnswer: userAnswer, onSubmitAnswer: onSubmitAnswer }));
492
505
  case 'TRUE_FALSE_CORRECT_GROUP':
493
- return (_jsx(TrueFalseCorrectGroupViewer, { question: question, isReviewMode: isReviewMode, userAnswer: userAnswer }));
506
+ return (_jsx(TrueFalseCorrectGroupViewer, { question: question, isReviewMode: isReviewMode, userAnswer: userAnswer, onSubmitAnswer: onSubmitAnswer }));
494
507
  case 'FILL_IN_BLANK_GROUP':
495
508
  return (_jsx(FillInBlankGroupViewer, { question: question, isReviewMode: isReviewMode, userAnswer: userAnswer, onSubmitAnswer: onSubmitAnswer }));
496
509
  case 'MATCHING_WITH_LINES_GROUP':
@@ -498,20 +511,20 @@ export function QuestionViewer({ question, onSubmitAnswer, isReviewMode = false,
498
511
  case 'MATCH_COLUMNS_TO_MAKE_SENTENCES':
499
512
  return (_jsx(MatchColumnsToMakeSentencesViewer, { question: question, isReviewMode: isReviewMode, userAnswer: userAnswer, onSubmitAnswer: onSubmitAnswer }));
500
513
  case 'CROSS_OUT_WORD_GROUP':
501
- return (_jsx(CrossOutWordGroupViewer, { question: question, isReviewMode: isReviewMode }));
514
+ return (_jsx(CrossOutWordGroupViewer, { question: question, isReviewMode: isReviewMode, userAnswer: userAnswer, onSubmitAnswer: onSubmitAnswer }));
502
515
  case 'ANSWER_THE_QUESTION':
503
516
  return (_jsx(AnswerTheQuestionViewer, { question: question, isReviewMode: isReviewMode, userAnswer: typeof userAnswer === 'string' ? userAnswer : undefined, onSubmitAnswer: onSubmitAnswer }));
504
517
  case 'ANSWER_THE_QUESTION_GROUP':
505
- return (_jsx(AnswerTheQuestionGroupViewer, { question: question, isReviewMode: isReviewMode, userAnswer: userAnswer }));
518
+ return (_jsx(AnswerTheQuestionGroupViewer, { question: question, isReviewMode: isReviewMode, userAnswer: userAnswer, onSubmitAnswer: onSubmitAnswer }));
506
519
  case 'SPEAKING_CUE_CARD':
507
520
  return (_jsx(SpeakingCueCardClient, { questionData: mapQuestionToSpeakingCueCardData(question), isReviewMode: isReviewMode }));
508
521
  case 'SPONTANEOUS_QA':
509
522
  return (_jsx(SpontaneousQAClient, { questionData: mapQuestionToSpontaneousQAData(question), isReviewMode: isReviewMode }));
510
523
  case 'SPONTANEOUS_QA_GROUP':
511
- return (_jsx(SpontaneousQaGroupViewer, { question: question, isReviewMode: isReviewMode }));
524
+ return (_jsx(SpontaneousQaGroupViewer, { question: question, isReviewMode: isReviewMode, userAnswer: userAnswer, gradeDetails: gradeDetails, disabled: !onSubmitAnswer }));
512
525
  case 'WORD_ORDER_AND_MATCH_GROUP':
513
526
  case 'WORD_ORDER_AND_MATCH':
514
- return (_jsx(WordOrderAndMatchGroupViewer, { question: question, isReviewMode: isReviewMode, userAnswer: userAnswer }));
527
+ return (_jsx(WordOrderAndMatchGroupViewer, { question: question, isReviewMode: isReviewMode, userAnswer: userAnswer, onSubmitAnswer: onSubmitAnswer }));
515
528
  case 'WORD_ORDERING_GROUP':
516
529
  return (_jsx(WordOrderingGroupViewer, { question: question, isReviewMode: isReviewMode, userAnswer: userAnswer, onSubmitAnswer: onSubmitAnswer }));
517
530
  case 'MATCH_WORD_TO_PICTURE_GROUP':
@@ -551,13 +564,13 @@ export function QuestionViewer({ question, onSubmitAnswer, isReviewMode = false,
551
564
  case 'WORD_FILL_STRUCTURED_FORM':
552
565
  return (_jsx(WordFillStructuredFormViewer, { question: question, isReviewMode: isReviewMode, userAnswer: userAnswer, onSubmitAnswer: onSubmitAnswer }));
553
566
  case 'CROSSWORD_PUZZLE':
554
- return (_jsx(CrosswordPuzzleClient, { content: question.content, correctAnswer: question.answer, isReviewMode: isReviewMode, userAnswers: userAnswer }));
567
+ return renderCrosswordPuzzle();
555
568
  case 'FIND_WORDS_IN_MATRIX':
556
- return (_jsx(FindWordsInMatrixClient, { content: question.content, correctAnswer: question.answer, showSolution: isReviewMode }));
569
+ return (_jsx(FindWordsInMatrixClient, { content: question.content, correctAnswer: question.correctAnswer ?? question.answer, showSolution: isReviewMode, userAnswer: userAnswer, onAnswerChange: isReviewMode ? undefined : onSubmitAnswer }));
557
570
  case 'SORT_WORDS_INTO_CATEGORIES':
558
571
  return (_jsx(SortWordsIntoCategoriesViewer, { question: question, isReviewMode: isReviewMode, userAnswer: userAnswer, onSubmitAnswer: onSubmitAnswer }));
559
572
  case 'CHOOSE_THEN_ANSWER_GROUP':
560
- return (_jsx(ChooseThenAnswerGroupViewer, { question: question, isReviewMode: isReviewMode, userAnswer: userAnswer, onSubmitAnswer: onSubmitAnswer }));
573
+ return (_jsx(ChooseThenAnswerGroupViewer, { question: question, isReviewMode: isReviewMode, userAnswer: userAnswer, gradeDetails: gradeDetails, onSubmitAnswer: onSubmitAnswer }));
561
574
  default:
562
575
  return _jsxs("div", { children: ["Lo\u1EA1i c\u00E2u h\u1ECFi kh\u00F4ng \u0111\u01B0\u1EE3c h\u1ED7 tr\u1EE3: ", question.type] });
563
576
  }
@@ -1,5 +1,11 @@
1
1
  import type { Question } from '../../../shared/types/entities/question.types';
2
- export declare function SpontaneousQaGroupViewer({ question, isReviewMode, }: {
2
+ import type { SpontaneousQaGroupGradeDetail } from '../_shared/types/spontaneous-qa-group.type';
3
+ export declare function SpontaneousQaGroupViewer({ question, isReviewMode, userAnswer, onItemRecorded, uploadingIndex, gradeDetails, disabled, }: {
3
4
  question: Question;
4
5
  isReviewMode?: boolean;
6
+ userAnswer?: unknown;
7
+ onItemRecorded?: (flattenIndex: number, blob: Blob) => void;
8
+ uploadingIndex?: number | null;
9
+ gradeDetails?: SpontaneousQaGroupGradeDetail[];
10
+ disabled?: boolean;
5
11
  }): import("react").JSX.Element;
@@ -2,6 +2,18 @@
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { SpontaneousQaGroupClient } from '../types/spontaneous-qa-group/SpontaneousQaGroupClient';
4
4
  import { mapQuestionToSpontaneousQaGroupData } from '../types/spontaneous-qa-group/map-spontaneous-qa-group-data';
5
- export function SpontaneousQaGroupViewer({ question, isReviewMode = false, }) {
6
- return (_jsx(SpontaneousQaGroupClient, { questionData: mapQuestionToSpontaneousQaGroupData(question), isReviewMode: isReviewMode }));
5
+ function readStudentAnswer(value) {
6
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
7
+ return undefined;
8
+ }
9
+ const keys = value.audioKeys;
10
+ if (!Array.isArray(keys)) {
11
+ return undefined;
12
+ }
13
+ return {
14
+ audioKeys: keys.map((key) => (typeof key === 'string' && key.trim() !== '' ? key : null)),
15
+ };
16
+ }
17
+ export function SpontaneousQaGroupViewer({ question, isReviewMode = false, userAnswer, onItemRecorded, uploadingIndex, gradeDetails, disabled, }) {
18
+ return (_jsx(SpontaneousQaGroupClient, { questionData: mapQuestionToSpontaneousQaGroupData(question), isReviewMode: isReviewMode, userAnswer: readStudentAnswer(userAnswer), onItemRecorded: isReviewMode ? undefined : onItemRecorded, uploadingIndex: uploadingIndex, gradeDetails: isReviewMode ? undefined : gradeDetails, disabled: disabled }));
7
19
  }
@@ -3,7 +3,8 @@ import type { TrueFalseCorrectStudentItemAnswer } from '../_shared/types/true-fa
3
3
  type TrueFalseCorrectGroupViewerProps = {
4
4
  question: Question;
5
5
  isReviewMode?: boolean;
6
- userAnswer?: TrueFalseCorrectStudentItemAnswer[];
6
+ userAnswer?: unknown;
7
+ onSubmitAnswer?: (answer: TrueFalseCorrectStudentItemAnswer[]) => void;
7
8
  };
8
- export declare function TrueFalseCorrectGroupViewer({ question, isReviewMode, userAnswer, }: TrueFalseCorrectGroupViewerProps): import("react").JSX.Element;
9
+ export declare function TrueFalseCorrectGroupViewer({ question, isReviewMode, userAnswer, onSubmitAnswer, }: TrueFalseCorrectGroupViewerProps): import("react").JSX.Element;
9
10
  export {};
@@ -2,13 +2,23 @@
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { TrueFalseCorrectGroupClient } from '../types/true-false-correct-group/TrueFalseCorrectGroupClient';
4
4
  import { mapQuestionToTrueFalseCorrectGroupData } from '../types/true-false-correct-group/map-true-false-correct-group-data';
5
- export function TrueFalseCorrectGroupViewer({ question, isReviewMode = false, userAnswer, }) {
5
+ function readStudentAnswers(value) {
6
+ if (Array.isArray(value)) {
7
+ return value;
8
+ }
9
+ if (value && typeof value === 'object' && Array.isArray(value.answer)) {
10
+ return value.answer;
11
+ }
12
+ return undefined;
13
+ }
14
+ export function TrueFalseCorrectGroupViewer({ question, isReviewMode = false, userAnswer, onSubmitAnswer, }) {
6
15
  const questionData = mapQuestionToTrueFalseCorrectGroupData(question);
7
- const reviewAnswers = isReviewMode && !userAnswer
16
+ const storedAnswers = readStudentAnswers(userAnswer);
17
+ const reviewAnswers = isReviewMode && !storedAnswers
8
18
  ? questionData.items.map((item) => ({
9
19
  isTrue: item.isTrue,
10
20
  correction: item.correction,
11
21
  }))
12
- : userAnswer;
13
- return (_jsx(TrueFalseCorrectGroupClient, { questionData: questionData, isReviewMode: isReviewMode, userAnswers: reviewAnswers }));
22
+ : storedAnswers;
23
+ return (_jsx(TrueFalseCorrectGroupClient, { questionData: questionData, isReviewMode: isReviewMode, userAnswers: reviewAnswers, onAnswerChange: isReviewMode ? undefined : onSubmitAnswer }));
14
24
  }
@@ -2,7 +2,10 @@ import type { Question } from '../../../shared/types/entities/question.types';
2
2
  type TrueFalseGroupViewerProps = {
3
3
  question: Question;
4
4
  isReviewMode?: boolean;
5
- userAnswer?: boolean[];
5
+ userAnswer?: boolean[] | {
6
+ answer?: boolean[];
7
+ };
8
+ onSubmitAnswer?: (answer: boolean[]) => void;
6
9
  };
7
- export declare function TrueFalseGroupViewer({ question, isReviewMode, userAnswer, }: TrueFalseGroupViewerProps): import("react").JSX.Element;
10
+ export declare function TrueFalseGroupViewer({ question, isReviewMode, userAnswer, onSubmitAnswer, }: TrueFalseGroupViewerProps): import("react").JSX.Element;
8
11
  export {};
@@ -2,10 +2,20 @@
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { TrueFalseGroupClient } from '../types/true-false-group/TrueFalseGroupClient';
4
4
  import { mapQuestionToTrueFalseGroupData } from '../types/true-false-group/map-true-false-group-data';
5
- export function TrueFalseGroupViewer({ question, isReviewMode = false, userAnswer, }) {
5
+ function readBooleanAnswers(value) {
6
+ if (Array.isArray(value)) {
7
+ return value;
8
+ }
9
+ if (value && typeof value === 'object' && Array.isArray(value.answer)) {
10
+ return value.answer;
11
+ }
12
+ return undefined;
13
+ }
14
+ export function TrueFalseGroupViewer({ question, isReviewMode = false, userAnswer, onSubmitAnswer, }) {
6
15
  const questionData = mapQuestionToTrueFalseGroupData(question);
7
- const reviewAnswers = isReviewMode && !userAnswer
16
+ const storedAnswers = readBooleanAnswers(userAnswer);
17
+ const reviewAnswers = isReviewMode && !storedAnswers
8
18
  ? questionData.items.map((item) => item.correctAnswer)
9
- : userAnswer;
10
- return (_jsx(TrueFalseGroupClient, { questionData: questionData, isReviewMode: isReviewMode, userAnswers: reviewAnswers }));
19
+ : storedAnswers;
20
+ return (_jsx(TrueFalseGroupClient, { questionData: questionData, isReviewMode: isReviewMode, userAnswers: reviewAnswers, onAnswerChange: isReviewMode ? undefined : onSubmitAnswer }));
11
21
  }
@@ -1,6 +1,10 @@
1
1
  import type { Question } from '../../../shared/types/entities/question.types';
2
- export declare function WordOrderAndMatchGroupViewer({ question, isReviewMode, userAnswer, }: {
2
+ export declare function WordOrderAndMatchGroupViewer({ question, isReviewMode, userAnswer, onSubmitAnswer, }: {
3
3
  question: Question;
4
4
  isReviewMode?: boolean;
5
- userAnswer?: any;
5
+ userAnswer?: unknown;
6
+ onSubmitAnswer?: (answer: Array<{
7
+ orderedPhrase: string;
8
+ matchLabel: string;
9
+ }>) => void;
6
10
  }): import("react").JSX.Element;
@@ -76,20 +76,40 @@ function resolveGroup(question) {
76
76
  items: itemsRaw.map((item, idx) => mapItem(item, idx, answersRaw[idx])),
77
77
  };
78
78
  }
79
- export function WordOrderAndMatchGroupViewer({ question, isReviewMode = false, userAnswer, }) {
79
+ function readMatchAnswers(value) {
80
+ if (Array.isArray(value)) {
81
+ return value;
82
+ }
83
+ if (value && typeof value === 'object' && Array.isArray(value.answer)) {
84
+ return value.answer;
85
+ }
86
+ return undefined;
87
+ }
88
+ export function WordOrderAndMatchGroupViewer({ question, isReviewMode = false, userAnswer, onSubmitAnswer, }) {
80
89
  const { instruction, matchOptions, items } = resolveGroup(question);
81
90
  const questionData = {
82
91
  instruction,
83
92
  matchOptions,
84
93
  items,
85
94
  };
86
- const autoUserAnswers = isReviewMode
95
+ const storedAnswers = readMatchAnswers(userAnswer);
96
+ const autoUserAnswers = isReviewMode && !storedAnswers
87
97
  ? items.map((item) => ({
88
98
  orderedPhrase: item.orderedPhrase,
89
99
  matchLabel: item.matchLabel,
90
100
  }))
91
- : Array.isArray(userAnswer)
92
- ? userAnswer
93
- : undefined;
94
- return (_jsx(WordOrderAndMatchGroupClient, { questionData: questionData, isReviewMode: isReviewMode, userAnswers: autoUserAnswers }));
101
+ : storedAnswers;
102
+ return (_jsx(WordOrderAndMatchGroupClient, { questionData: questionData, isReviewMode: isReviewMode, userAnswers: autoUserAnswers, onAnswerChange: isReviewMode
103
+ ? undefined
104
+ : (itemIndex, next) => {
105
+ const current = items.map((_, index) => {
106
+ const existing = storedAnswers?.[index];
107
+ return {
108
+ orderedPhrase: existing?.orderedPhrase || '',
109
+ matchLabel: existing?.matchLabel || '',
110
+ };
111
+ });
112
+ current[itemIndex] = next;
113
+ onSubmitAnswer?.(current);
114
+ } }));
95
115
  }
@@ -31,6 +31,6 @@ export function ReviewAnswerTheQuestionGroupRenderer({ partNumber, partName, que
31
31
  ? 'border-red-200 bg-red-50 text-red-800'
32
32
  : 'border-gray-200 bg-gray-50 text-gray-700'}`, children: question.isExample
33
33
  ? (question.exampleAnswer || '(Câu mẫu)')
34
- : (studentAnswer || '(Chưa trả lời)') }), expectedAnswers.length > 0 && (_jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-xs font-medium text-gray-500", children: "\u0110\u00E1p \u00E1n m\u1EABu (AI)" }), _jsx("ul", { className: "list-disc space-y-1 pl-5 text-sm text-gray-700", children: expectedAnswers.map((answer) => (_jsx("li", { children: answer }, answer))) })] })), feedback && (_jsx("p", { className: "text-xs text-violet-700", children: feedback }))] })] }, question.id));
34
+ : (studentAnswer || '(Chưa trả lời)') }), expectedAnswers.length > 0 && (_jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-xs font-medium text-gray-500", children: "\u0110\u00E1p \u00E1n" }), _jsx("ul", { className: "list-disc space-y-1 pl-5 text-sm text-gray-700", children: expectedAnswers.map((answer) => (_jsx("li", { children: answer }, answer))) })] })), feedback && (_jsx("p", { className: "text-xs text-violet-700", children: feedback }))] })] }, question.id));
35
35
  })] }));
36
36
  }
@@ -218,7 +218,7 @@ export function renderMoversReviewBody(ctx) {
218
218
  case 'CROSSWORD_PUZZLE': {
219
219
  const data = transformCrosswordPuzzle(apiQuestions);
220
220
  const firstQuestion = apiQuestions[0];
221
- return (_jsx(MoversCrosswordPuzzleRenderer, { partNumber: partNo, partName: part.name, instruction: part.instructions || data.instruction, questionCount: questionCount, title: data.title, gridSize: data.gridSize, clues: data.clues, answers: answers, correctAnswers: data.correctAnswers, onAnswerChange: handleAnswerChange, isReviewMode: true, caseSensitive: firstQuestion?.correct_answer?.caseSensitive || false }));
221
+ return (_jsx(MoversCrosswordPuzzleRenderer, { partNumber: partNo, partName: part.name, instruction: part.instructions || data.instruction, questionCount: questionCount, title: data.title, gridSize: data.gridSize, markedColumn: data.markedColumn, hiddenWord: data.hiddenWord, clues: data.clues, answers: answers, correctAnswers: data.correctAnswers, onAnswerChange: handleAnswerChange, isReviewMode: true, caseSensitive: data.caseSensitive || firstQuestion?.correct_answer?.caseSensitive || false }));
222
222
  }
223
223
  default:
224
224
  return null;
@@ -140,13 +140,20 @@ function addCorrectAnswerMaps(result, answer) {
140
140
  texts.forEach((text, index) => { result.correctAnswerTextMap[`${answer.questionId}-blank-${index}`] = text; });
141
141
  if (answer.questionType === 'LABEL_THE_PICTURE' && isRecord(correct.labels))
142
142
  Object.entries(correct.labels).forEach(([id, value]) => { result.correctAnswerTextMap[id] = String(value); });
143
- if ((answer.questionType === 'FILL_MISSING_WORDS_IN_GRID' || answer.questionType === 'CROSSWORD_PUZZLE') && isRecord(correct.cells || correct.answers)) {
143
+ if (answer.questionType === 'FILL_MISSING_WORDS_IN_GRID' && isRecord(correct.cells || correct.answers)) {
144
144
  const rawCells = (correct.cells || correct.answers);
145
145
  result.cellAnswersMap[answer.questionId] = {
146
146
  cells: Object.fromEntries(Object.entries(rawCells).map(([k, v]) => [k, { correctAnswer: String(v) }])),
147
147
  caseSensitive: correct.caseSensitive === true,
148
148
  };
149
149
  }
150
+ if (answer.questionType === 'CROSSWORD_PUZZLE' && isRecord(correct.cells)) {
151
+ const rawCells = correct.cells;
152
+ result.cellAnswersMap[answer.questionId] = {
153
+ cells: Object.fromEntries(Object.entries(rawCells).map(([k, v]) => [k, { correctAnswer: String(v) }])),
154
+ caseSensitive: correct.caseSensitive === true,
155
+ };
156
+ }
150
157
  }
151
158
  function transformStudentAnswer(questionId, questionType, value) {
152
159
  if (value == null)
@@ -315,6 +315,7 @@ const reverseAnswerTheQuestionGroup = (apiQuestion) => {
315
315
  items,
316
316
  explanation: asString(apiQuestion.explanation),
317
317
  points: items.reduce((total, item) => (item.isExample ? total : total + item.points), 0),
318
+ ...(meta.gradingType === 'MAPPING' ? { gradingType: 'MAPPING' } : {}),
318
319
  },
319
320
  };
320
321
  };
@@ -404,6 +405,13 @@ const reverseChooseThenAnswerGroup = (apiQuestion) => {
404
405
  question: asString(itemContent.question),
405
406
  options,
406
407
  optionId: asString(rawAnswer.optionId) || options[0]?.id || '',
408
+ expectedAnswers: (() => {
409
+ const raw = asArray(rawAnswer.expectedAnswers)
410
+ .filter((value) => typeof value === 'string')
411
+ .map((value) => value.trim())
412
+ .filter((value) => value !== '');
413
+ return raw.length > 0 ? raw : [''];
414
+ })(),
407
415
  isExample,
408
416
  points: isExample ? 0 : asNumber(item.points, 1),
409
417
  questionNumber: asNumber(item.questionNumber, index + 1),
@@ -529,18 +537,27 @@ const reverseCrossOutWordGroup = (apiQuestion) => {
529
537
  const fallback = asRecord(fallbackAnswers[index]);
530
538
  const answerRaw = Object.keys(itemAnswer).length > 0 ? itemAnswer : fallback;
531
539
  const isExample = item.isExample === true;
532
- const type = itemContent.type === 'CROSS_OUT_AND_REPLACE' ||
533
- answerRaw.type === 'CROSS_OUT_AND_REPLACE'
540
+ const type = itemContent.type === 'CROSS_OUT_AND_REPLACE'
534
541
  ? 'CROSS_OUT_AND_REPLACE'
535
- : 'CROSS_OUT';
542
+ : itemContent.type === 'CROSS_OUT'
543
+ ? 'CROSS_OUT'
544
+ : answerRaw.type === 'CROSS_OUT_AND_REPLACE'
545
+ ? 'CROSS_OUT_AND_REPLACE'
546
+ : 'CROSS_OUT';
547
+ const rawIndex = answerRaw.wordIndex;
548
+ const wordIndex = typeof rawIndex === 'number' && Number.isInteger(rawIndex) && rawIndex >= 0
549
+ ? rawIndex
550
+ : null;
536
551
  const correctAnswer = type === 'CROSS_OUT_AND_REPLACE'
537
552
  ? {
538
553
  type: 'CROSS_OUT_AND_REPLACE',
554
+ wordIndex,
539
555
  crossOut: asString(answerRaw.crossOut),
540
556
  replaceWith: asString(answerRaw.replaceWith),
541
557
  }
542
558
  : {
543
559
  type: 'CROSS_OUT',
560
+ wordIndex,
544
561
  crossOut: asString(answerRaw.crossOut),
545
562
  };
546
563
  return {
@@ -630,12 +647,14 @@ const reverseSpontaneousQaGroup = (apiQuestion) => {
630
647
  const fallback = asRecord(flattenedAnswers[questionIndex]);
631
648
  const expected = asArray(childAnswer.expectedAnswers ?? fallback.expectedAnswers)
632
649
  .filter((value) => typeof value === 'string');
650
+ const isExample = child.isExample === true;
633
651
  return {
634
652
  questionText: asString(childContent.questionText),
635
653
  inputType: asString(childContent.inputType, 'TEXT') === 'AUDIO' ? 'AUDIO' : 'TEXT',
636
654
  audioUrl: asString(childContent.audioUrl),
637
655
  expectedAnswers: expected.length > 0 ? expected : [''],
638
- points: asNumber(child.points, 1),
656
+ isExample,
657
+ points: isExample ? 0 : asNumber(child.points, 1),
639
658
  questionNumber: asNumber(child.questionNumber, questionIndex + 1),
640
659
  };
641
660
  }),
@@ -882,6 +901,9 @@ function reverseCrosswordPuzzle(apiQuestion) {
882
901
  const rows = apiContent.gridSize?.rows || apiContent.rows || 12;
883
902
  const cols = apiContent.gridSize?.cols || apiContent.cols || 12;
884
903
  const title = apiContent.title || '';
904
+ const type = apiContent.type === 'HIDDEN_WORD' ? 'HIDDEN_WORD' : 'STANDARD';
905
+ const instruction = asString(apiQuestion.instruction, asString(apiContent.instruction));
906
+ const markedColumn = typeof apiContent.markedColumn === 'number' ? apiContent.markedColumn : undefined;
885
907
  const across = Array.isArray(apiContent.clues?.across) ? apiContent.clues.across : [];
886
908
  const down = Array.isArray(apiContent.clues?.down) ? apiContent.clues.down : [];
887
909
  const answers = apiAnswer.answers || {};
@@ -896,6 +918,7 @@ function reverseCrosswordPuzzle(apiQuestion) {
896
918
  length: a.length || 1,
897
919
  direction: 'across',
898
920
  answer: answers[`across-${a.number}`] || '',
921
+ ...(a.isExample === true ? { isExample: true } : {}),
899
922
  });
900
923
  }
901
924
  for (const d of down) {
@@ -908,24 +931,32 @@ function reverseCrosswordPuzzle(apiQuestion) {
908
931
  length: d.length || 1,
909
932
  direction: 'down',
910
933
  answer: answers[`down-${d.number}`] || '',
934
+ ...(d.isExample === true ? { isExample: true } : {}),
911
935
  });
912
936
  }
913
937
  return {
914
938
  content: {
939
+ type,
915
940
  title,
941
+ instruction,
916
942
  rows,
917
943
  cols,
918
944
  gridSize: { rows, cols },
945
+ ...(type === 'HIDDEN_WORD' && markedColumn ? { markedColumn } : {}),
919
946
  clues: { across, down },
920
947
  },
921
948
  answer: {
949
+ type,
922
950
  title,
951
+ instruction,
923
952
  rows,
924
953
  cols,
954
+ ...(type === 'HIDDEN_WORD' && markedColumn ? { markedColumn } : {}),
955
+ hiddenWord: answers['hidden-word'] || '',
925
956
  clues,
926
957
  answers,
927
958
  caseSensitive: apiAnswer.caseSensitive || false,
928
- explanation: apiQuestion.explanation || '',
959
+ explanation: asString(apiQuestion.explanation),
929
960
  },
930
961
  };
931
962
  }
@@ -936,6 +967,7 @@ function reverseFindWordsInMatrix(apiQuestion) {
936
967
  const rows = apiContent.gridSize?.rows || (Array.isArray(apiContent.grid) ? apiContent.grid.length : 14);
937
968
  const cols = apiContent.gridSize?.cols || (Array.isArray(apiContent.grid?.[0]) ? apiContent.grid[0].length : 14);
938
969
  const title = apiContent.title || '';
970
+ const instruction = typeof apiContent.instruction === 'string' ? apiContent.instruction : '';
939
971
  const grid = Array.isArray(apiContent.grid) ? apiContent.grid : [];
940
972
  const categories = Array.isArray(apiContent.categories) ? apiContent.categories : [];
941
973
  const wordBank = Array.isArray(apiContent.wordBank) ? apiContent.wordBank : [];
@@ -969,6 +1001,7 @@ function reverseFindWordsInMatrix(apiQuestion) {
969
1001
  content: {
970
1002
  type,
971
1003
  title,
1004
+ instruction,
972
1005
  rows,
973
1006
  cols,
974
1007
  gridSize: { rows, cols },
@@ -981,6 +1014,7 @@ function reverseFindWordsInMatrix(apiQuestion) {
981
1014
  answer: {
982
1015
  type,
983
1016
  title,
1017
+ instruction,
984
1018
  rows,
985
1019
  cols,
986
1020
  grid,
@@ -1,4 +1,8 @@
1
- export declare const ANSWER_THE_QUESTION_GROUP_GRADING_TYPE: "AI";
1
+ export declare const ANSWER_THE_QUESTION_GROUP_GRADING_TYPES: readonly ["AI", "MAPPING"];
2
+ export type AnswerTheQuestionGroupGradingType = (typeof ANSWER_THE_QUESTION_GROUP_GRADING_TYPES)[number];
3
+ /** Default for newly created groups. */
4
+ export declare const ANSWER_THE_QUESTION_GROUP_GRADING_TYPE: AnswerTheQuestionGroupGradingType;
5
+ export declare function resolveAnswerTheQuestionGroupGradingType(value: unknown): AnswerTheQuestionGroupGradingType;
2
6
  export interface AnswerTheQuestionGroupItemContent {
3
7
  question: string;
4
8
  imageUrl?: string | string[];
@@ -20,8 +24,9 @@ export interface AnswerTheQuestionGroupContent {
20
24
  passage?: string;
21
25
  audioUrl?: string;
22
26
  imageUrl?: string | string[];
23
- gradingType: typeof ANSWER_THE_QUESTION_GROUP_GRADING_TYPE;
24
- isAiGraded: true;
27
+ /** AI = LLM short-answer; MAPPING = exact-match expectedAnswers. */
28
+ gradingType: AnswerTheQuestionGroupGradingType;
29
+ isAiGraded: boolean;
25
30
  };
26
31
  items: AnswerTheQuestionGroupItem[];
27
32
  }
@@ -1 +1,6 @@
1
+ export const ANSWER_THE_QUESTION_GROUP_GRADING_TYPES = ['AI', 'MAPPING'];
2
+ /** Default for newly created groups. */
1
3
  export const ANSWER_THE_QUESTION_GROUP_GRADING_TYPE = 'AI';
4
+ export function resolveAnswerTheQuestionGroupGradingType(value) {
5
+ return value === 'MAPPING' ? 'MAPPING' : 'AI';
6
+ }
@@ -4,6 +4,7 @@ export interface ChooseThenAnswerOption {
4
4
  }
5
5
  export interface ChooseThenAnswerItemAnswer {
6
6
  optionId: string;
7
+ expectedAnswers?: string[];
7
8
  }
8
9
  export interface ChooseThenAnswerStudentItemAnswer {
9
10
  optionId: string;
@@ -27,6 +28,8 @@ export interface ChooseThenAnswerGroupContent {
27
28
  meta?: {
28
29
  instruction?: string;
29
30
  title?: string;
31
+ gradingType?: 'AI';
32
+ isAiGraded?: boolean;
30
33
  };
31
34
  items: ChooseThenAnswerGroupItem[];
32
35
  }
@@ -20,6 +20,7 @@ export type CrosswordSubtype = 'STANDARD' | 'HIDDEN_WORD';
20
20
  export interface CrosswordPuzzleContent {
21
21
  type?: CrosswordSubtype;
22
22
  title?: string;
23
+ instruction?: string;
23
24
  gridSize: {
24
25
  rows: number;
25
26
  cols: number;
@@ -30,6 +30,7 @@ export interface ExampleSelection {
30
30
  export interface FindWordsInMatrixContent {
31
31
  type?: FindWordsInMatrixType;
32
32
  title?: string;
33
+ instruction?: string;
33
34
  gridSize: {
34
35
  rows: number;
35
36
  cols: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tinyweb_dev/oe-exam-sdk",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "Reusable OceanEdu question components.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",