@pocketprep/ui-kit 3.7.1 → 3.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/@pocketprep/ui-kit.css +1 -1
- package/dist/@pocketprep/ui-kit.js +8271 -8246
- package/dist/@pocketprep/ui-kit.js.map +1 -1
- package/dist/@pocketprep/ui-kit.umd.cjs +10 -10
- package/dist/@pocketprep/ui-kit.umd.cjs.map +1 -1
- package/lib/components/Quiz/Question/BuildListChoicesContainer.vue +11 -12
- package/lib/components/Quiz/Question/MPMCChoicesContainer.vue +5 -6
- package/lib/components/Quiz/Question/MPMCRadioGroup.vue +16 -0
- package/lib/components/Quiz/Question/QuestionContext.vue +27 -2
- package/lib/components/Quiz/Question/Summary.vue +4 -1
- package/lib/components/Quiz/Question/composables.ts +2 -1
- package/lib/components/Quiz/Question/injectionSymbols.ts +3 -1
- package/lib/components/Quiz/Question.vue +74 -16
- package/lib/components/Quiz/question.d.ts +6 -0
- package/package.json +1 -1
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
'uikit-question-build-list-choices-container--review-mode': reviewMode,
|
|
31
31
|
}"
|
|
32
32
|
role="list"
|
|
33
|
-
:aria-label="`
|
|
33
|
+
:aria-label="`List with ${orderedChoices.length} items`"
|
|
34
34
|
>
|
|
35
35
|
<li
|
|
36
36
|
v-for="(choice, index) in orderedChoices"
|
|
@@ -60,10 +60,9 @@
|
|
|
60
60
|
:class="{
|
|
61
61
|
'uikit-question-build-list-choices-container__choice--review-mode': reviewMode
|
|
62
62
|
}"
|
|
63
|
-
role="group"
|
|
64
|
-
:aria-label="`Choice ${index + 1}: ${stripHtmlTags(choice.text || '')}`"
|
|
65
63
|
:tabindex="-1"
|
|
66
|
-
@keydown="handleCardKeydown($event, index)"
|
|
64
|
+
@keydown.enter.stop="handleCardKeydown($event, index)"
|
|
65
|
+
@keydown.space.stop="handleCardKeydown($event, index)"
|
|
67
66
|
@click.prevent
|
|
68
67
|
@mousedown.prevent
|
|
69
68
|
:ref="(el) => setCardRef(el, choice.key)"
|
|
@@ -125,7 +124,7 @@
|
|
|
125
124
|
index === 0
|
|
126
125
|
}"
|
|
127
126
|
:disabled="index === 0"
|
|
128
|
-
:tabindex="
|
|
127
|
+
:tabindex="buttonsAreFocusable && index !== 0 ? 0 : -1"
|
|
129
128
|
@click.prevent.stop="moveChoiceUp(index)"
|
|
130
129
|
:aria-label="`Move '${stripHtmlTags(choice.text || '')}' up`"
|
|
131
130
|
:title="'Move up'"
|
|
@@ -145,7 +144,7 @@
|
|
|
145
144
|
index === orderedChoices.length - 1
|
|
146
145
|
}"
|
|
147
146
|
:disabled="index === orderedChoices.length - 1"
|
|
148
|
-
:tabindex="
|
|
147
|
+
:tabindex="buttonsAreFocusable && index !== orderedChoices.length - 1 ? 0 : -1"
|
|
149
148
|
@click.prevent.stop="moveChoiceDown(index)"
|
|
150
149
|
:aria-label="`Move '${stripHtmlTags(choice.text || '')}' down`"
|
|
151
150
|
:title="'Move down'"
|
|
@@ -166,7 +165,7 @@
|
|
|
166
165
|
</template>
|
|
167
166
|
|
|
168
167
|
<script setup lang="ts">
|
|
169
|
-
import { ref, watch, onMounted, type ComponentPublicInstance } from 'vue'
|
|
168
|
+
import { ref, watch, onMounted, computed, type ComponentPublicInstance } from 'vue'
|
|
170
169
|
import Icon from '../../Icons/Icon.vue'
|
|
171
170
|
import { dark as vDark, breakpoint as vBreakpoint } from '../../../directives'
|
|
172
171
|
import { useQuestionContext } from './composables'
|
|
@@ -197,6 +196,10 @@ const choiceRefs = ref<Map<string, HTMLDivElement>>(new Map())
|
|
|
197
196
|
const announcementMessage = ref<string>('')
|
|
198
197
|
const isMoveTriggeredByArrowKey = ref<boolean>(false)
|
|
199
198
|
|
|
199
|
+
const buttonsAreFocusable = computed(() => {
|
|
200
|
+
return !showBuildListOrder.value && !reviewMode.value
|
|
201
|
+
})
|
|
202
|
+
|
|
200
203
|
onMounted(() => {
|
|
201
204
|
updateOrderedChoices()
|
|
202
205
|
})
|
|
@@ -435,7 +438,7 @@ watch(selectedBuildListChoiceOrder, () => {
|
|
|
435
438
|
top: -8px;
|
|
436
439
|
bottom: -8px;
|
|
437
440
|
left: 8px;
|
|
438
|
-
right:
|
|
441
|
+
right: 14px;
|
|
439
442
|
border-radius: 11px;
|
|
440
443
|
pointer-events: none;
|
|
441
444
|
|
|
@@ -736,12 +739,10 @@ watch(selectedBuildListChoiceOrder, () => {
|
|
|
736
739
|
|
|
737
740
|
// TransitionGroup animations
|
|
738
741
|
.list-move,
|
|
739
|
-
.list-enter-active,
|
|
740
742
|
.list-leave-active {
|
|
741
743
|
transition: all 0.2s ease;
|
|
742
744
|
}
|
|
743
745
|
|
|
744
|
-
.list-enter-from,
|
|
745
746
|
.list-leave-to {
|
|
746
747
|
opacity: 0;
|
|
747
748
|
transform: translateX(30px);
|
|
@@ -755,12 +756,10 @@ watch(selectedBuildListChoiceOrder, () => {
|
|
|
755
756
|
// Respect prefers-reduced-motion
|
|
756
757
|
@media (prefers-reduced-motion: reduce) {
|
|
757
758
|
.list-move,
|
|
758
|
-
.list-enter-active,
|
|
759
759
|
.list-leave-active {
|
|
760
760
|
transition: none;
|
|
761
761
|
}
|
|
762
762
|
|
|
763
|
-
.list-enter-from,
|
|
764
763
|
.list-leave-to {
|
|
765
764
|
opacity: 1;
|
|
766
765
|
transform: none;
|
|
@@ -27,6 +27,7 @@ const {
|
|
|
27
27
|
isDarkMode,
|
|
28
28
|
showMPMCAnswers,
|
|
29
29
|
selectedMPMCChoices,
|
|
30
|
+
mpmcChoices,
|
|
30
31
|
} = useQuestionContext()
|
|
31
32
|
|
|
32
33
|
const mpmcRadioGrid = ref<IMPMCRadioOptions[] | undefined>(undefined)
|
|
@@ -37,10 +38,7 @@ const mpmcLabels = computed(() => {
|
|
|
37
38
|
})
|
|
38
39
|
|
|
39
40
|
const questionChoices = computed(() => {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
// Shuffle mpmc choices
|
|
43
|
-
return [ ...choices ].sort(() => Math.random() - 0.5)
|
|
41
|
+
return mpmcChoices.value
|
|
44
42
|
})
|
|
45
43
|
|
|
46
44
|
const choiceKeysByLabelIndexObj = computed(() => {
|
|
@@ -235,8 +233,9 @@ watch(selectedMPMCChoices, () => {
|
|
|
235
233
|
:aria-label="
|
|
236
234
|
`${stripHtmlTags(label)}. ${expandedPartNumbers.includes(labelIndex) ? 'Expanded' : 'Collapsed'}.`
|
|
237
235
|
"
|
|
238
|
-
@keydown.enter="openChoiceDropdown(labelIndex)"
|
|
239
|
-
@keydown.space.
|
|
236
|
+
@keydown.enter.stop="openChoiceDropdown(labelIndex)"
|
|
237
|
+
@keydown.space.stop="openChoiceDropdown(labelIndex)"
|
|
238
|
+
@mousedown.prevent
|
|
240
239
|
>
|
|
241
240
|
<div
|
|
242
241
|
class="uikit-question-mpmc-choices-container__part"
|
|
@@ -25,6 +25,10 @@ const selectedChoice = defineModel<TChoiceKey | null>({ default: null })
|
|
|
25
25
|
|
|
26
26
|
const selectChoice = (choiceKey: TChoiceKey) => {
|
|
27
27
|
selectedChoice.value = choiceKey
|
|
28
|
+
// Remove focus from the choice after selecting a choice
|
|
29
|
+
if (document.activeElement instanceof HTMLElement) {
|
|
30
|
+
document.activeElement.blur()
|
|
31
|
+
}
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
const radioButtonColor = (choice: TChoiceKey) => {
|
|
@@ -130,16 +134,28 @@ const radioButtonColor = (choice: TChoiceKey) => {
|
|
|
130
134
|
outline: none;
|
|
131
135
|
transition: background-color 0.2s ease;
|
|
132
136
|
|
|
137
|
+
&:last-child {
|
|
138
|
+
border-radius: 0 0 5px 5px;
|
|
139
|
+
}
|
|
140
|
+
|
|
133
141
|
&:not(&--show-answer) {
|
|
134
142
|
&:focus {
|
|
135
143
|
border: 0.5px solid $brand-blue;
|
|
136
144
|
}
|
|
145
|
+
|
|
146
|
+
&:hover {
|
|
147
|
+
background: $pearl;
|
|
148
|
+
}
|
|
137
149
|
}
|
|
138
150
|
|
|
139
151
|
&--dark {
|
|
140
152
|
&:focus:not(.uikit-mpmc-radio-group__option--show-answer) {
|
|
141
153
|
border: 0.5px solid $banana-bread;
|
|
142
154
|
}
|
|
155
|
+
|
|
156
|
+
&:hover:not(.uikit-mpmc-radio-group__option--show-answer) {
|
|
157
|
+
background-color: $moonlit-ocean;
|
|
158
|
+
}
|
|
143
159
|
}
|
|
144
160
|
}
|
|
145
161
|
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
? ` of ${quizLength}`
|
|
31
31
|
: ''
|
|
32
32
|
}${
|
|
33
|
-
(showAnswers || showMatrixAnswers)
|
|
34
|
-
?
|
|
33
|
+
(showAnswers || showMatrixAnswers || showBuildListOrder || showMPMCAnswers)
|
|
34
|
+
? isCorrectlyAnswered
|
|
35
35
|
? ', Answered Correctly'
|
|
36
36
|
: ', Answered Incorrectly'
|
|
37
37
|
: ''
|
|
@@ -62,6 +62,7 @@
|
|
|
62
62
|
import Icon from '../../Icons/Icon.vue'
|
|
63
63
|
import { dark as vDark, breakpoint as vBreakpoint } from '../../../directives'
|
|
64
64
|
import { useQuestionContext } from './composables'
|
|
65
|
+
import { computed } from 'vue'
|
|
65
66
|
|
|
66
67
|
const {
|
|
67
68
|
// questionEl is used by the breakpoint directive
|
|
@@ -72,15 +73,39 @@ const {
|
|
|
72
73
|
questionNumber,
|
|
73
74
|
isDarkMode,
|
|
74
75
|
isCorrect,
|
|
76
|
+
isBuildListQuestion,
|
|
77
|
+
isMatrixQuestion,
|
|
78
|
+
isMPMCQuestion,
|
|
79
|
+
isBuildListOrderCorrect,
|
|
80
|
+
isMatrixQuestionCorrect,
|
|
81
|
+
isMPMCQuestionCorrect,
|
|
75
82
|
contextIconType,
|
|
76
83
|
showAnswers,
|
|
84
|
+
showBuildListOrder,
|
|
77
85
|
showMatrixAnswers,
|
|
86
|
+
showMPMCAnswers,
|
|
78
87
|
} = useQuestionContext()
|
|
79
88
|
|
|
80
89
|
defineExpose({
|
|
81
90
|
questionEl,
|
|
82
91
|
})
|
|
83
92
|
|
|
93
|
+
const isCorrectlyAnswered = computed(() => {
|
|
94
|
+
if (isMatrixQuestion.value) {
|
|
95
|
+
return isMatrixQuestionCorrect.value
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (isBuildListQuestion) {
|
|
99
|
+
return isBuildListOrderCorrect.value
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (isMPMCQuestion.value) {
|
|
103
|
+
return isMPMCQuestionCorrect.value
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return isCorrect.value
|
|
107
|
+
})
|
|
108
|
+
|
|
84
109
|
</script>
|
|
85
110
|
|
|
86
111
|
<style lang="scss">
|
|
@@ -219,7 +219,8 @@ const toggleSummaryExplanationImageLongAlt = () => {
|
|
|
219
219
|
}
|
|
220
220
|
|
|
221
221
|
&--build-list-question-not-review-mode {
|
|
222
|
-
max-width:
|
|
222
|
+
max-width: 450px;
|
|
223
|
+
margin-left: -4px
|
|
223
224
|
}
|
|
224
225
|
|
|
225
226
|
&--matrix-question-review-mode#{&}--tablet-landscape,
|
|
@@ -229,6 +230,8 @@ const toggleSummaryExplanationImageLongAlt = () => {
|
|
|
229
230
|
|
|
230
231
|
&--mpmc-question {
|
|
231
232
|
max-width: 492px;
|
|
233
|
+
margin-left: 4px;
|
|
234
|
+
margin-top: 8px;
|
|
232
235
|
}
|
|
233
236
|
|
|
234
237
|
&--tablet-portrait {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { inject, ref } from 'vue'
|
|
2
2
|
import * as InjectionKeys from './injectionSymbols'
|
|
3
|
-
import type { TChoice, TChoiceKey, TMatrixChoiceKey, TBuildListChoice } from '../question'
|
|
3
|
+
import type { TChoice, TChoiceKey, TMatrixChoiceKey, TBuildListChoice, TMPMCChoice } from '../question'
|
|
4
4
|
|
|
5
5
|
export const useQuestionContext = () => {
|
|
6
6
|
const question = inject(InjectionKeys.questionKey)
|
|
@@ -16,6 +16,7 @@ export const useQuestionContext = () => {
|
|
|
16
16
|
choiceScores,
|
|
17
17
|
choices: inject(InjectionKeys.choicesKey, ref<TChoice[]>([])),
|
|
18
18
|
buildListChoices: inject(InjectionKeys.buildListChoicesKey, ref<TBuildListChoice[]>([])),
|
|
19
|
+
mpmcChoices: inject(InjectionKeys.mpmcChoicesKey, ref<TMPMCChoice[]>([])),
|
|
19
20
|
questionEl: inject(InjectionKeys.questionElKey, ref(null)),
|
|
20
21
|
breakpointsWithEl: inject(InjectionKeys.breakpointsWithElKey, ref({
|
|
21
22
|
breakpoints: {
|
|
@@ -11,12 +11,14 @@ import type {
|
|
|
11
11
|
TMatrixChoiceScores,
|
|
12
12
|
TBuildListChoiceScores,
|
|
13
13
|
TQuizMode,
|
|
14
|
+
TMPMCChoice,
|
|
14
15
|
} from '../question'
|
|
15
16
|
import type { ComputedRef, InjectionKey, Ref } from 'vue'
|
|
16
17
|
|
|
17
18
|
export const questionKey = Symbol('question') as InjectionKey<ComputedRef<Study.Class.QuestionJSON>>
|
|
18
19
|
export const choicesKey = Symbol('choices') as InjectionKey<ComputedRef<TChoice[]>>
|
|
19
|
-
export const buildListChoicesKey = Symbol('
|
|
20
|
+
export const buildListChoicesKey = Symbol('buildListChoices') as InjectionKey<ComputedRef<TBuildListChoice[]>>
|
|
21
|
+
export const mpmcChoicesKey = Symbol('mpmcChoices') as InjectionKey<ComputedRef<TMPMCChoice[]>>
|
|
20
22
|
export const questionElKey = Symbol('questionEl') as InjectionKey<Ref<Element | null>>
|
|
21
23
|
export const breakpointsWithElKey = Symbol('breakpointsWithEl') as InjectionKey<Ref<{
|
|
22
24
|
breakpoints: {
|
|
@@ -374,7 +374,6 @@
|
|
|
374
374
|
>
|
|
375
375
|
Check Answer
|
|
376
376
|
</PocketButton>
|
|
377
|
-
|
|
378
377
|
<PocketButton
|
|
379
378
|
v-else-if="(
|
|
380
379
|
showAnswers
|
|
@@ -471,6 +470,7 @@ import type {
|
|
|
471
470
|
TBuildListChoiceKey,
|
|
472
471
|
TChoice,
|
|
473
472
|
TBuildListChoice,
|
|
473
|
+
TMPMCChoice,
|
|
474
474
|
TChoiceScores,
|
|
475
475
|
TMatrixChoiceScores,
|
|
476
476
|
TBuildListChoiceScores,
|
|
@@ -801,6 +801,10 @@ const buildListChoices = computed(() => {
|
|
|
801
801
|
return shuffledChoices
|
|
802
802
|
})
|
|
803
803
|
|
|
804
|
+
const mpmcChoices = computed(() => {
|
|
805
|
+
return shuffleMPMCChoices([ ...props.question.choices ])
|
|
806
|
+
})
|
|
807
|
+
|
|
804
808
|
const isCorrect = computed(() => {
|
|
805
809
|
// In order to be correct, user must have selected all the answers and none of the distractors
|
|
806
810
|
return showAnswers.value
|
|
@@ -947,11 +951,11 @@ const isMatrixQuestionAnswered = computed(() => {
|
|
|
947
951
|
|
|
948
952
|
const isMPMCQuestionAnswered = computed(() => {
|
|
949
953
|
const mpmcLabels = question.value.mpmcLabels
|
|
950
|
-
const
|
|
954
|
+
const mpmcQuestionChoices = question.value.choices
|
|
951
955
|
const selectedMPMCLabelIndexes: number[] = []
|
|
952
956
|
|
|
953
957
|
selectedMPMCChoices.value.forEach(choice => {
|
|
954
|
-
const mpmcChoiceObj =
|
|
958
|
+
const mpmcChoiceObj = mpmcQuestionChoices.find(c => c.id === choice)
|
|
955
959
|
if (
|
|
956
960
|
mpmcChoiceObj?.labelIndex !== undefined
|
|
957
961
|
&& !selectedMPMCLabelIndexes.includes(mpmcChoiceObj?.labelIndex)
|
|
@@ -988,47 +992,77 @@ const prompt = computed(() => {
|
|
|
988
992
|
})
|
|
989
993
|
})
|
|
990
994
|
|
|
995
|
+
const isTEIsQuestionType = computed(() => {
|
|
996
|
+
return isMPMCQuestion.value || isMatrixQuestion.value || isBuildListQuestion.value
|
|
997
|
+
})
|
|
998
|
+
|
|
991
999
|
const keydownListener = (e: KeyboardEvent) => {
|
|
992
1000
|
switch (e.code) {
|
|
993
1001
|
case 'KeyA':
|
|
994
|
-
|
|
1002
|
+
if (!isTEIsQuestionType.value) {
|
|
1003
|
+
choices.value[0] && selectChoice(choices.value[0].key, true)
|
|
1004
|
+
}
|
|
995
1005
|
break
|
|
996
1006
|
case 'KeyB':
|
|
997
|
-
|
|
1007
|
+
if (!isTEIsQuestionType.value) {
|
|
1008
|
+
choices.value[1] && selectChoice(choices.value[1].key, true)
|
|
1009
|
+
}
|
|
998
1010
|
break
|
|
999
1011
|
case 'KeyC':
|
|
1000
|
-
|
|
1012
|
+
if (!isTEIsQuestionType.value) {
|
|
1013
|
+
choices.value[2] && selectChoice(choices.value[2].key, true)
|
|
1014
|
+
}
|
|
1001
1015
|
break
|
|
1002
1016
|
case 'KeyD':
|
|
1003
|
-
|
|
1017
|
+
if (!isTEIsQuestionType.value) {
|
|
1018
|
+
choices.value[3] && selectChoice(choices.value[3].key, true)
|
|
1019
|
+
}
|
|
1004
1020
|
break
|
|
1005
1021
|
case 'KeyE':
|
|
1006
|
-
|
|
1022
|
+
if (!isTEIsQuestionType.value) {
|
|
1023
|
+
choices.value[4] && selectChoice(choices.value[4].key, true)
|
|
1024
|
+
}
|
|
1007
1025
|
break
|
|
1008
1026
|
case 'KeyF':
|
|
1009
|
-
|
|
1027
|
+
if (!isTEIsQuestionType.value) {
|
|
1028
|
+
choices.value[5] && selectChoice(choices.value[5].key, true)
|
|
1029
|
+
}
|
|
1010
1030
|
break
|
|
1011
1031
|
case 'KeyG':
|
|
1012
|
-
|
|
1032
|
+
if (!isTEIsQuestionType.value) {
|
|
1033
|
+
choices.value[6] && selectChoice(choices.value[6].key, true)
|
|
1034
|
+
}
|
|
1013
1035
|
break
|
|
1014
1036
|
case 'KeyH':
|
|
1015
|
-
|
|
1037
|
+
if (!isTEIsQuestionType.value) {
|
|
1038
|
+
choices.value[7] && selectChoice(choices.value[7].key, true)
|
|
1039
|
+
}
|
|
1016
1040
|
break
|
|
1017
1041
|
case 'KeyI':
|
|
1018
|
-
|
|
1042
|
+
if (!isTEIsQuestionType.value) {
|
|
1043
|
+
choices.value[8] && selectChoice(choices.value[8].key, true)
|
|
1044
|
+
}
|
|
1019
1045
|
break
|
|
1020
1046
|
case 'KeyJ':
|
|
1021
|
-
|
|
1047
|
+
if (!isTEIsQuestionType.value) {
|
|
1048
|
+
choices.value[9] && selectChoice(choices.value[9].key, true)
|
|
1049
|
+
}
|
|
1022
1050
|
break
|
|
1023
1051
|
case 'KeyX':
|
|
1024
|
-
showAnswers.value
|
|
1052
|
+
(showAnswers.value || showMatrixAnswers.value || showBuildListOrder.value || showMPMCAnswers.value)
|
|
1053
|
+
&& toggleExplanation()
|
|
1025
1054
|
break
|
|
1026
1055
|
case 'Escape':
|
|
1027
1056
|
emitClose()
|
|
1028
1057
|
e.preventDefault()
|
|
1029
1058
|
break
|
|
1030
1059
|
case 'Enter':
|
|
1031
|
-
if (
|
|
1060
|
+
if (
|
|
1061
|
+
!showAnswers.value
|
|
1062
|
+
&& selectedChoices.value.length
|
|
1063
|
+
&& focusChoiceKey.value === null
|
|
1064
|
+
&& !isTEIsQuestionType.value
|
|
1065
|
+
) {
|
|
1032
1066
|
clickCheckAnswer()
|
|
1033
1067
|
e.preventDefault()
|
|
1034
1068
|
}
|
|
@@ -1163,6 +1197,30 @@ const shuffleBuildListChoices = (choicesToShuffle: TBuildListChoice[]): TBuildLi
|
|
|
1163
1197
|
: sortedChoices
|
|
1164
1198
|
}
|
|
1165
1199
|
|
|
1200
|
+
const shuffleMPMCChoices = (choicesToShuffle: TMPMCChoice[]): TMPMCChoice[]=> {
|
|
1201
|
+
const sortedChoices = choicesToShuffle.sort((a, b) => {
|
|
1202
|
+
const hashChar = (char: string, num: number) => ((num << 5) - num) + char.charCodeAt(0)
|
|
1203
|
+
|
|
1204
|
+
const aHash = a.text?.split('')
|
|
1205
|
+
.reduce((acc: number, char: string) => hashChar(char, acc) & hashChar(char, acc), 0)
|
|
1206
|
+
const bHash = b.text?.split('')
|
|
1207
|
+
.reduce((acc: number, char: string) => hashChar(char, acc) & hashChar(char, acc), 0)
|
|
1208
|
+
|
|
1209
|
+
return (aHash || 0) - (bHash || 0)
|
|
1210
|
+
})
|
|
1211
|
+
|
|
1212
|
+
return props.answerSeed
|
|
1213
|
+
? props.answerSeed.reduce<TMPMCChoice[]>((acc, i) => {
|
|
1214
|
+
const sortedChoice = sortedChoices[i]
|
|
1215
|
+
if (sortedChoice) {
|
|
1216
|
+
acc.push(sortedChoice)
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
return acc
|
|
1220
|
+
}, [])
|
|
1221
|
+
: sortedChoices
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1166
1224
|
const choiceFocusOut = (event: FocusEvent) => {
|
|
1167
1225
|
const relatedTarget = event.relatedTarget
|
|
1168
1226
|
if (
|
|
@@ -1426,7 +1484,6 @@ const clickCheckMatrixAnswer = () => {
|
|
|
1426
1484
|
const clickCheckMPMCAnswer = () => {
|
|
1427
1485
|
if (!props.hideAnswer) {
|
|
1428
1486
|
showMPMCAnswers.value = true
|
|
1429
|
-
|
|
1430
1487
|
emitCheckAnswer({
|
|
1431
1488
|
isCorrect: isMPMCQuestionCorrect.value,
|
|
1432
1489
|
selectedChoices: selectedMPMCChoices.value,
|
|
@@ -1621,6 +1678,7 @@ onBeforeUnmount(() => {
|
|
|
1621
1678
|
provide(InjectionKeys.questionKey, question)
|
|
1622
1679
|
provide(InjectionKeys.choicesKey, choices)
|
|
1623
1680
|
provide(InjectionKeys.buildListChoicesKey, buildListChoices)
|
|
1681
|
+
provide(InjectionKeys.mpmcChoicesKey, mpmcChoices)
|
|
1624
1682
|
provide(InjectionKeys.questionElKey, questionEl)
|
|
1625
1683
|
provide(InjectionKeys.breakpointsWithElKey, breakpointsWithEl)
|
|
1626
1684
|
provide(InjectionKeys.quizLengthKey, quizLength)
|
|
@@ -17,6 +17,12 @@ export type TBreakPointsObject = {
|
|
|
17
17
|
|
|
18
18
|
export type TChoice = { text?: string; key: TChoiceKey }
|
|
19
19
|
export type TBuildListChoice = { text?: string; key: TBuildListChoiceKey }
|
|
20
|
+
export type TMPMCChoice = {
|
|
21
|
+
text?: string
|
|
22
|
+
id?: string
|
|
23
|
+
isCorrect?: boolean
|
|
24
|
+
labelIndex?: number
|
|
25
|
+
}
|
|
20
26
|
|
|
21
27
|
export type TChoiceScores = Partial<Record<TChoiceKey, number>> & {
|
|
22
28
|
totalAnswered: number
|