@pocketprep/ui-kit 3.4.90 → 3.5.1

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 (88) hide show
  1. package/README.md +2 -2
  2. package/dist/@pocketprep/ui-kit.css +1 -0
  3. package/dist/@pocketprep/ui-kit.js +16490 -18228
  4. package/dist/@pocketprep/ui-kit.js.map +1 -1
  5. package/dist/@pocketprep/ui-kit.umd.cjs +11 -11
  6. package/dist/@pocketprep/ui-kit.umd.cjs.map +1 -1
  7. package/eslint.config.ts +111 -0
  8. package/lib/components/Banners/Banner.vue +2 -2
  9. package/lib/components/Bundles/BundleList.vue +1 -1
  10. package/lib/components/Bundles/BundleSearch.vue +43 -12
  11. package/lib/components/Bundles/PremiumPill.vue +2 -2
  12. package/lib/components/Buttons/Button.vue +19 -18
  13. package/lib/components/Buttons/Link.vue +9 -8
  14. package/lib/components/Buttons/Tab.vue +4 -3
  15. package/lib/components/Calendar/Calendar.vue +14 -2
  16. package/lib/components/Charts/Bar.vue +3 -3
  17. package/lib/components/Charts/Pie.vue +4 -4
  18. package/lib/components/Controls/SegmentControl.vue +8 -7
  19. package/lib/components/Controls/Slider.vue +2 -3
  20. package/lib/components/Controls/ToggleSwitch.vue +3 -2
  21. package/lib/components/EmptyStates/EmptyState.vue +3 -2
  22. package/lib/components/Exams/ExamCard.vue +3 -3
  23. package/lib/components/Exams/ExamMenuCard.vue +2 -2
  24. package/lib/components/Filters/FilterDropdown.vue +2 -2
  25. package/lib/components/Filters/FilterOptions.vue +2 -2
  26. package/lib/components/Forms/Checkbox.vue +2 -2
  27. package/lib/components/Forms/CheckboxOption.vue +2 -2
  28. package/lib/components/Forms/Errors.vue +2 -2
  29. package/lib/components/Forms/Input.vue +2 -2
  30. package/lib/components/Forms/Radio.vue +37 -39
  31. package/lib/components/Forms/RadioButton.vue +1 -1
  32. package/lib/components/Forms/Select.vue +7 -6
  33. package/lib/components/Forms/Textarea.vue +2 -2
  34. package/lib/components/Icons/Icon.vue +1 -0
  35. package/lib/components/Icons/IconEdit.vue +4 -2
  36. package/lib/components/Icons/IconFullViewActive.vue +1 -1
  37. package/lib/components/Icons/IconLoading2.vue +1 -3
  38. package/lib/components/Loaders/SkeletonLoader.vue +2 -2
  39. package/lib/components/Messaging/InfoMessage.vue +2 -2
  40. package/lib/components/Modal/Modal.vue +2 -2
  41. package/lib/components/Modal/ModalContainer.vue +2 -2
  42. package/lib/components/Onboarding/EmailAuth.vue +5 -5
  43. package/lib/components/Onboarding/MagicCodeEntry.vue +3 -4
  44. package/lib/components/Pagination/QuestionReviewPagination.vue +23 -21
  45. package/lib/components/Pagination/TablePagination.vue +2 -2
  46. package/lib/components/Quiz/FlagToggle.vue +2 -2
  47. package/lib/components/Quiz/GlobalMetricsToggle.vue +3 -2
  48. package/lib/components/Quiz/KeyboardShortcutsButton.vue +1 -1
  49. package/lib/components/Quiz/KeyboardShortcutsModal.vue +1 -1
  50. package/lib/components/Quiz/Question/ChoicesContainer.vue +99 -132
  51. package/lib/components/Quiz/Question/DropdownExplanation.vue +41 -55
  52. package/lib/components/Quiz/Question/Explanation.vue +49 -59
  53. package/lib/components/Quiz/Question/MatrixChoicesContainer.vue +208 -226
  54. package/lib/components/Quiz/Question/MatrixRadioGroup.vue +7 -6
  55. package/lib/components/Quiz/Question/MobileMatrixChoicesContainer.vue +315 -320
  56. package/lib/components/Quiz/Question/MobileMatrixRadioGroup.vue +14 -11
  57. package/lib/components/Quiz/Question/PassageAndImage.vue +34 -45
  58. package/lib/components/Quiz/Question/PassageAndImageDropdown.vue +39 -49
  59. package/lib/components/Quiz/Question/Paywall.vue +30 -41
  60. package/lib/components/Quiz/Question/QuestionContext.vue +24 -33
  61. package/lib/components/Quiz/Question/StatsSummary.vue +12 -22
  62. package/lib/components/Quiz/Question/Summary.vue +56 -66
  63. package/lib/components/Quiz/Question/composables.ts +71 -0
  64. package/lib/components/Quiz/Question/injectionSymbols.ts +69 -0
  65. package/lib/components/Quiz/Question.vue +810 -1009
  66. package/lib/components/Quiz/QuizContainer.vue +63 -67
  67. package/lib/components/Quiz/QuizProgress.vue +73 -77
  68. package/lib/components/Quiz/QuizProgressBar.vue +3 -2
  69. package/lib/components/Quiz/question.d.ts +4 -4
  70. package/lib/components/Search/Pill.vue +2 -2
  71. package/lib/components/Search/Search.vue +2 -2
  72. package/lib/components/SidePanels/SidePanel.vue +8 -3
  73. package/lib/components/Tables/Table.vue +4 -3
  74. package/lib/components/Tables/TableActions.vue +3 -3
  75. package/lib/components/Tags/Tag.vue +2 -2
  76. package/lib/components/Toasts/Toast.vue +5 -3
  77. package/lib/components/Tooltips/OverflowTooltip.vue +2 -2
  78. package/lib/components/Tooltips/Tooltip.vue +2 -2
  79. package/lib/directives.ts +28 -23
  80. package/lib/pocketprep-export.module.scss +3 -2
  81. package/lib/pocketprep.scss +2 -2
  82. package/lib/styles/_breakpoints.scss +12 -24
  83. package/lib/styles/_colors.scss +0 -1
  84. package/package.json +38 -29
  85. package/stylelint.config.js +38 -0
  86. package/.eslintrc.cjs +0 -74
  87. package/dist/style.css +0 -1
  88. package/stylelint.config.cjs +0 -22
@@ -13,14 +13,14 @@
13
13
 
14
14
  }"
15
15
  v-dark="isDarkMode"
16
- v-breakpoint:questionEl="breakpoints"
16
+ v-breakpoint="breakpointsWithEl"
17
17
  >
18
18
  <div
19
19
  class="uikit-question-mobile-matrix-choices-container__row-container"
20
20
  v-for="(rowLabel, rowIndex) in matrixRowLabels"
21
21
  :key="rowIndex"
22
22
  v-dark="isDarkMode"
23
- v-breakpoint:questionEl="breakpoints"
23
+ v-breakpoint="breakpointsWithEl"
24
24
  >
25
25
  <div
26
26
  class="uikit-question-mobile-matrix-choices-container__row"
@@ -29,7 +29,7 @@
29
29
  expandedRowNumbers.includes(rowIndex),
30
30
  }"
31
31
  v-dark="isDarkMode"
32
- v-breakpoint:questionEl="breakpoints"
32
+ v-breakpoint="breakpointsWithEl"
33
33
  @click.stop="toggleChoiceDropdown(rowIndex)"
34
34
  >
35
35
  <Icon
@@ -71,20 +71,13 @@
71
71
  v-for="(colHeader, colHeaderIndex) in selectedColumnHeaders"
72
72
  :key="colHeaderIndex"
73
73
  >
74
- <template v-if="
75
- selectedColumnHeaders &&
76
- selectedColumnHeaders[rowIndex] &&
77
- selectedColumnHeaders[rowIndex][colHeaderIndex]">
74
+ <template v-if="doesSelectedColumnHeaderExist(rowIndex, colHeaderIndex)">
78
75
  <div
79
76
  class="uikit-question-mobile-matrix-choices-container__selected-choice-labels"
80
77
  v-dark="isDarkMode"
81
- v-breakpoint:questionEl="breakpoints"
78
+ v-breakpoint="breakpointsWithEl"
82
79
  >
83
- {{ selectedColumnHeaders[rowIndex][colHeaderIndex] ===
84
- selectedColumnHeaders[rowIndex][selectedColumnHeaders[rowIndex].length - 1] ?
85
- stripHtmlTags(selectedColumnHeaders[rowIndex][colHeaderIndex]) :
86
- `${stripHtmlTags(selectedColumnHeaders[rowIndex][colHeaderIndex])},`
87
- }}
80
+ {{ getSelectedChoiceLabels(rowIndex, colHeaderIndex) }}
88
81
  </div>
89
82
  </template>
90
83
  </div>
@@ -117,7 +110,7 @@
117
110
  />
118
111
  <Checkbox
119
112
  v-else
120
- :model-value="matrixCheckboxGrid[rowIndex][columnIndex]"
113
+ :model-value="matrixCheckboxGrid[rowIndex]?.[columnIndex]"
121
114
  :is-dark-mode="isDarkMode"
122
115
  :disabled="showMatrixAnswers || reviewMode"
123
116
  :checkbox-styles="checkboxContainerStyling(rowIndex, columnIndex)"
@@ -128,8 +121,8 @@
128
121
  :class="{
129
122
  'uikit-question-mobile-matrix-choices-container__checkbox-label--distractor':
130
123
  (showMatrixAnswers || reviewMode) &&
131
- matrixChoiceLayout[rowIndex] &&
132
- matrixChoiceLayout[rowIndex][columnIndex]?.startsWith('d'),
124
+ matrixChoiceLayout?.[rowIndex] &&
125
+ matrixChoiceLayout?.[rowIndex]?.[columnIndex]?.startsWith('d'),
133
126
  }"
134
127
  >
135
128
  {{ stripHtmlTags(column) }}
@@ -151,7 +144,6 @@
151
144
  :matrix-answer-keys="matrixAnswerKeys"
152
145
  :is-dark-mode="isDarkMode"
153
146
  :question-el="questionEl"
154
- :breakpoints="breakpoints"
155
147
  :disabled="false"
156
148
  @update:modelValue="updateRadioRowSelection(rowIndex, $event)"
157
149
  />
@@ -161,394 +153,397 @@
161
153
  </div>
162
154
  </template>
163
155
 
164
- <script lang="ts">
165
- import { Component, Vue, Prop, Emit, Watch } from 'vue-facing-decorator'
156
+ <script setup lang="ts">
166
157
  import Icon from '../../Icons/Icon.vue'
167
- import PocketButton from '../../Buttons/Button.vue'
168
158
  import Checkbox from '../../Forms/Checkbox.vue'
169
159
  import MobileMatrixRadioGroup from './MobileMatrixRadioGroup.vue'
170
- import { dark, breakpoint } from '../../../directives'
171
- import type { TBreakPointsObject, IRadioOptions, TMatrixChoiceKey } from './../question'
172
- import type { Study } from '@pocketprep/types'
160
+ import { dark as vDark, breakpoint as vBreakpoint } from '../../../directives'
161
+ import { useQuestionContext } from './composables'
162
+ import type { IRadioOptions, TMatrixChoiceKey } from './../question'
173
163
  import BrandColors from '../../../pocketprep-export.module.scss'
164
+ import { computed, onMounted, ref, watch } from 'vue'
165
+
166
+ const emit = defineEmits<{
167
+ 'emitSelectedMatrixChoice': [matrixChoiceKeys: TMatrixChoiceKey[]]
168
+ }>()
169
+
170
+ const {
171
+ // questionEl is used by the breakpoint directive
172
+ questionEl,
173
+ question,
174
+ isMatrixQuestionCorrect,
175
+ reviewMode,
176
+ isDarkMode,
177
+ breakpointsWithEl,
178
+ showMatrixAnswers,
179
+ matrixAnswerKeys,
180
+ selectedMatrixChoices,
181
+ } = useQuestionContext()
182
+
183
+ const matrixCheckboxGrid = ref<boolean[][] | undefined>(undefined)
184
+ const matrixRadioGrid = ref<IRadioOptions[] | undefined>(undefined)
185
+ const expandedRowNumbers = ref<number[]>([])
186
+ const selectedColumnHeaders = ref<string[][]>([])
187
+ const brandColors = BrandColors
188
+
189
+ const stripHtmlTags = (string?: string) => {
190
+ if (string) {
191
+ const div = document.createElement('div')
192
+ div.innerHTML = string
193
+ return div.textContent || ''
194
+ }
195
+ return ''
196
+ }
197
+
198
+ const matrixChoiceLayout = computed(() => {
199
+ return question.value.matrixChoiceLayout
200
+ })
174
201
 
175
- @Component({
176
- components: {
177
- Icon,
178
- Checkbox,
179
- PocketButton,
180
- MobileMatrixRadioGroup,
181
- },
182
- directives: {
183
- dark,
184
- breakpoint,
185
- },
202
+ const defaultCheckboxGrid = computed(() => {
203
+ return matrixChoiceLayout.value?.map(row => {
204
+ const choiceRow = row.map(() => false)
205
+ return choiceRow
206
+ })
186
207
  })
187
- export default class MobileMatrixChoicesContainer extends Vue {
188
- @Prop({ default: false }) reviewMode!: boolean
189
- @Prop({ default: false }) isDarkMode!: boolean
190
- @Prop({ default: null }) questionEl!: Element | null
191
- @Prop({ default: {
192
- 'mobile': 767,
193
- 'tablet-portrait': 1023,
194
- 'tablet-landscape': 1439,
195
- } }) breakpoints!: TBreakPointsObject
196
- @Prop() question!: Study.Class.QuestionJSON
197
- @Prop() matrixChoiceLayout!: string[][]
198
- @Prop({ default: false }) showMatrixAnswers!: boolean
199
- @Prop({ default: false }) isUnanswered!: boolean
200
- @Prop({ default: false }) isMatrixQuestionCorrect!: boolean
201
- @Prop() matrixAnswerKeys!: TMatrixChoiceKey[]
202
- @Prop() matrixDistractorKeys!: TMatrixChoiceKey[]
203
- @Prop() selectedMatrixChoices!: TMatrixChoiceKey[]
204
- @Prop() matrixChoices!: TMatrixChoiceKey[]
205
-
206
- matrixCheckboxGrid: boolean[][] | undefined = undefined
207
- matrixRadioGrid: IRadioOptions[] | undefined = undefined
208
- expandedRowNumbers: number[] = []
209
- selectedColumnHeaders: string[][] = []
210
- brandColors = BrandColors
211
-
212
- stripHtmlTags (string?: string) {
213
- if (string) {
214
- const div = document.createElement('div')
215
- div.innerHTML = string
216
- return div.textContent || ''
208
+
209
+ const defaultRadioButtonGrid = computed(() => {
210
+ return matrixChoiceLayout.value?.map(row => {
211
+ return {
212
+ choices: row as TMatrixChoiceKey[],
213
+ value: null as TMatrixChoiceKey | null,
217
214
  }
218
- return ''
219
- }
215
+ })
216
+ })
220
217
 
221
- get defaultCheckboxGrid () {
222
- return this.matrixChoiceLayout?.map(row => {
223
- const choiceRow = row.map(() => false)
224
- return choiceRow
225
- })
226
- }
218
+ const matrixRowLabels = computed(() => {
219
+ return question.value.matrixLabels?.rows
220
+ })
227
221
 
228
- get defaultRadioButtonGrid () {
229
- return this.matrixChoiceLayout?.map(row => {
230
- return {
231
- choices: row as TMatrixChoiceKey[],
232
- value: null as TMatrixChoiceKey | null,
233
- }
234
- })
235
- }
222
+ const matrixColumnLabels = computed(() => {
223
+ return question.value.matrixLabels?.columns
224
+ })
236
225
 
237
- get matrixRowLabels () {
238
- return this.question.matrixLabels?.rows
226
+ onMounted(() => {
227
+ if (question.value.type === 'Matrix Checkbox') {
228
+ matrixCheckboxGrid.value = convertSelectedMatrixChoiceToCheckboxGrid()
239
229
  }
240
230
 
241
- get matrixColumnLabels () {
242
- return this.question.matrixLabels?.columns
231
+ if (question.value.type === 'Matrix Radio Button') {
232
+ matrixRadioGrid.value = convertSelectedMatrixChoiceToRadioBtnGrid()
243
233
  }
244
234
 
245
- mounted () {
246
- if (this.question.type === 'Matrix Checkbox') {
247
- this.matrixCheckboxGrid = this.convertSelectedMatrixChoiceToCheckboxGrid()
248
- }
235
+ question.value.matrixChoiceLayout?.forEach(() => {
236
+ selectedColumnHeaders.value.push([])
237
+ })
238
+ })
249
239
 
250
- if (this.question.type === 'Matrix Radio Button') {
251
- this.matrixRadioGrid = this.convertSelectedMatrixChoiceToRadioBtnGrid()
252
- }
240
+ const toggleChoiceDropdown = (rowIndex: number) => {
241
+ const includedRowNumberIndex = expandedRowNumbers.value.findIndex(row => row === rowIndex)
242
+ if (includedRowNumberIndex === -1) {
243
+ expandedRowNumbers.value.push(rowIndex)
244
+ } else {
245
+ expandedRowNumbers.value.splice(includedRowNumberIndex, 1)
246
+ }
247
+ }
253
248
 
254
- this.question.matrixChoiceLayout?.forEach(() => {
255
- this.selectedColumnHeaders.push([])
249
+ const selectedChoiceKey = (rowIndex: number, columnIndex: number) => {
250
+ const row = rowIndex += 1
251
+ const column = columnIndex += 1
252
+ if (selectedMatrixChoices.value.length && matrixAnswerKeys.value.length) {
253
+ const matrixSelectedChoiceKey = selectedMatrixChoices.value.find((choice) => {
254
+ const substring = choice.substring(1)
255
+ return substring === `${row}_${column}`
256
256
  })
257
- }
258
257
 
259
- toggleChoiceDropdown (rowIndex: number) {
260
- const includedRowNumberIndex = this.expandedRowNumbers.findIndex(row => row === rowIndex)
261
- if (includedRowNumberIndex === -1) {
262
- this.expandedRowNumbers.push(rowIndex)
263
- } else {
264
- this.expandedRowNumbers.splice(includedRowNumberIndex, 1)
265
- }
258
+ return matrixSelectedChoiceKey
266
259
  }
260
+ return undefined
261
+ }
267
262
 
268
- selectedChoiceKey (rowIndex: number, columnIndex: number) {
269
- const row = rowIndex += 1
270
- const column = columnIndex += 1
271
- if (this.selectedMatrixChoices.length && this.matrixAnswerKeys.length) {
272
- const matrixSelectedChoiceKey = this.selectedMatrixChoices.find((choice) => {
273
- const substring = choice.substring(1)
274
- return substring === `${row}_${column}`
275
- })
276
-
277
- return matrixSelectedChoiceKey
278
- }
279
- return undefined
280
- }
263
+ const getRadioRowSelection = (rowIndex: number) => {
264
+ return matrixRadioGrid.value?.[rowIndex]?.value
265
+ }
281
266
 
282
- getRadioRowSelection (rowIndex: number) {
283
- return this.matrixRadioGrid?.[rowIndex]?.value
284
- }
267
+ const getRadioRowChoices = (rowIndex: number) => {
268
+ const choices = matrixRadioGrid.value?.[rowIndex]?.choices
269
+ return choices
270
+ }
285
271
 
286
- getRadioRowChoices (rowIndex: number) {
287
- const choices = this.matrixRadioGrid?.[rowIndex]?.choices
288
- return choices
289
- }
272
+ const updateRadioRowSelection = (rowIndex: number, choiceKey: TMatrixChoiceKey | null) => {
273
+ const row = matrixRadioGrid.value?.[rowIndex]
274
+ if (row) {
275
+ row.value = choiceKey
290
276
 
291
- updateRadioRowSelection (rowIndex: number, choiceKey: TMatrixChoiceKey) {
292
- const row = this.matrixRadioGrid?.[rowIndex]
293
- if (row) {
294
- row.value = choiceKey
295
-
296
- // update row header label
297
- const choiceKeyIndex = row.choices.findIndex(choice => choice === choiceKey)
298
- const rowHeader = this.question.matrixLabels?.columns[choiceKeyIndex]
299
- if (rowHeader) {
300
- this.selectedColumnHeaders[rowIndex]?.pop()
301
- this.selectedColumnHeaders[rowIndex]?.push(rowHeader)
302
- }
277
+ // update row header label
278
+ const choiceKeyIndex = row.choices.findIndex(choice => choice === choiceKey)
279
+ const rowHeader = question.value.matrixLabels?.columns[choiceKeyIndex]
280
+ if (rowHeader) {
281
+ selectedColumnHeaders.value[rowIndex]?.pop()
282
+ selectedColumnHeaders.value[rowIndex]?.push(rowHeader)
303
283
  }
304
284
  }
285
+ }
305
286
 
306
- correctlySelectedChoice (rowIndex: number, columnIndex: number) {
307
- if (this.selectedMatrixChoices && this.matrixAnswerKeys) {
308
- const selectedChoice = this.selectedChoiceKey(rowIndex, columnIndex)
309
- if (selectedChoice && selectedChoice.startsWith('a') && this.matrixAnswerKeys.includes(selectedChoice)) {
310
- return true
311
- }
287
+ const correctlySelectedChoice = (rowIndex: number, columnIndex: number) => {
288
+ if (selectedMatrixChoices.value && matrixAnswerKeys.value) {
289
+ const selectedChoice = selectedChoiceKey(rowIndex, columnIndex)
290
+ if (selectedChoice && selectedChoice.startsWith('a') && matrixAnswerKeys.value.includes(selectedChoice)) {
291
+ return true
312
292
  }
313
- return false
314
293
  }
294
+ return false
295
+ }
315
296
 
316
- incorrectlySelectedChoice (rowIndex: number, columnIndex: number) {
317
- if (this.selectedMatrixChoices && this.matrixAnswerKeys) {
318
- const selectedChoice = this.selectedChoiceKey(rowIndex, columnIndex)
319
- if (selectedChoice && selectedChoice.startsWith('d')) {
320
- return true
321
- }
297
+ const incorrectlySelectedChoice = (rowIndex: number, columnIndex: number) => {
298
+ if (selectedMatrixChoices.value && matrixAnswerKeys.value) {
299
+ const selectedChoice = selectedChoiceKey(rowIndex, columnIndex)
300
+ if (selectedChoice?.startsWith('d')) {
301
+ return true
322
302
  }
323
- return false
324
- }
325
-
326
- correctAnswerButNotSelected (rowIndex: number, columnIndex: number) {
327
- const selectedChoice = this.selectedChoiceKey(rowIndex, columnIndex)
328
- const answerKey = this.matrixAnswerKeys.find(choice => choice === `a${rowIndex + 1}_${columnIndex + 1}`)
329
- return answerKey && !selectedChoice
330
303
  }
304
+ return false
305
+ }
306
+
307
+ const correctAnswerButNotSelected = (rowIndex: number, columnIndex: number) => {
308
+ const selectedChoice = selectedChoiceKey(rowIndex, columnIndex)
309
+ const answerKey = matrixAnswerKeys.value.find(choice => choice === `a${rowIndex + 1}_${columnIndex + 1}`)
310
+ return answerKey && !selectedChoice
311
+ }
331
312
 
332
- checkboxContainerStyling (rowIndex: number, columnIndex: number) {
333
- const isReviewMode = this.showMatrixAnswers || this.reviewMode
334
- const incorrectlySelectedChoice = this.incorrectlySelectedChoice(rowIndex, columnIndex)
313
+ const checkboxContainerStyling = (rowIndex: number, columnIndex: number) => {
314
+ const isReviewMode = showMatrixAnswers.value || reviewMode.value
335
315
 
336
- // check box is correctlySelected
337
- if (isReviewMode && this.correctlySelectedChoice(rowIndex, columnIndex)) {
338
- const borderColor = this.isDarkMode ? this.brandColors.jungleGreen : this.brandColors.cadaverous
339
- return {
340
- borderColor: `${borderColor} !important`,
341
- background: `${borderColor} !important`,
342
- }
316
+ // check box is correctlySelected
317
+ if (isReviewMode && correctlySelectedChoice(rowIndex, columnIndex)) {
318
+ const borderColor = isDarkMode.value ? brandColors.jungleGreen : brandColors.cadaverous
319
+ return {
320
+ borderColor: `${borderColor} !important`,
321
+ background: `${borderColor} !important`,
343
322
  }
323
+ }
344
324
 
345
- if (isReviewMode && incorrectlySelectedChoice) {
346
- return {
347
- background: `${this.brandColors.steel} !important`,
348
- border: `1px solid ${this.brandColors.steel} !important`,
349
- }
325
+ if (isReviewMode && incorrectlySelectedChoice(rowIndex, columnIndex)) {
326
+ return {
327
+ background: `${brandColors.steel} !important`,
328
+ border: `1px solid ${brandColors.steel} !important`,
350
329
  }
330
+ }
351
331
 
352
- if (isReviewMode && this.correctAnswerButNotSelected(rowIndex, columnIndex)) {
353
- return {
354
- background: 'transparent !important',
355
- border: `1px solid ${this.brandColors.slate} !important`,
356
- }
332
+ if (isReviewMode && correctAnswerButNotSelected(rowIndex, columnIndex)) {
333
+ return {
334
+ background: 'transparent !important',
335
+ border: `1px solid ${brandColors.slate} !important`,
357
336
  }
358
337
  }
338
+ }
359
339
 
360
- checkboxCheckStyling (rowIndex: number, columnIndex: number) {
361
- const isReviewMode = this.showMatrixAnswers || this.reviewMode
362
- if (isReviewMode && this.correctAnswerButNotSelected(rowIndex, columnIndex)) {
363
- const color = this.isDarkMode ? this.brandColors.jungleGreen : this.brandColors.cadaverous
364
- return {
365
- color: `${color} !important`,
366
- }
340
+ const checkboxCheckStyling = (rowIndex: number, columnIndex: number) => {
341
+ const isReviewMode = showMatrixAnswers.value || reviewMode.value
342
+ if (isReviewMode && correctAnswerButNotSelected(rowIndex, columnIndex)) {
343
+ const color = isDarkMode.value ? brandColors.jungleGreen : brandColors.cadaverous
344
+ return {
345
+ color: `${color} !important`,
367
346
  }
368
347
  }
348
+ }
369
349
 
370
- correctRow (rowIndex: number) {
371
- if (this.question?.matrixChoiceLayout && this.question?.matrixChoiceLayout[rowIndex]) {
372
- if (
373
- this.question?.type === 'Matrix Checkbox' &&
374
- this.matrixCheckboxGrid &&
375
- this.matrixCheckboxGrid[rowIndex]
376
- ) {
377
- const correctAnswerKeys = this.question?.matrixChoiceLayout[rowIndex].filter(choice =>
378
- choice.startsWith('a')
379
- )
380
- const selectedAnswerKeys = this.matrixCheckboxGrid[rowIndex].map((choice, choiceIndex) => {
381
- return this.selectedChoiceKey(rowIndex, choiceIndex)
382
- })
383
- const correctSelectedKeys = this.matrixCheckboxGrid[rowIndex].filter((choice, choiceIndex) => {
384
- const selectedChoice = this.selectedChoiceKey(rowIndex, choiceIndex)
385
- return selectedChoice?.startsWith('a')
386
- })
387
- return !selectedAnswerKeys.some(choice => choice?.startsWith('d')) &&
388
- (correctAnswerKeys.length === correctSelectedKeys.length)
389
- }
350
+ const correctRow = (rowIndex: number) => {
351
+ if (matrixChoiceLayout.value?.[rowIndex]) {
352
+ if (
353
+ question?.value.type === 'Matrix Checkbox' &&
354
+ matrixCheckboxGrid.value?.[rowIndex]
355
+ ) {
356
+ const correctAnswerKeys = matrixChoiceLayout.value[rowIndex]?.filter(choice =>
357
+ choice.startsWith('a')
358
+ )
359
+ const selectedAnswerKeys = matrixCheckboxGrid.value[rowIndex]?.map((choice, choiceIndex) => {
360
+ return selectedChoiceKey(rowIndex, choiceIndex)
361
+ })
362
+ const correctSelectedKeys = matrixCheckboxGrid.value[rowIndex]?.filter((choice, choiceIndex) => {
363
+ const selectedChoice = selectedChoiceKey(rowIndex, choiceIndex)
364
+ return selectedChoice?.startsWith('a')
365
+ })
366
+ return !selectedAnswerKeys?.some(choice => choice?.startsWith('d')) &&
367
+ (correctAnswerKeys?.length === correctSelectedKeys?.length)
368
+ }
390
369
 
391
- if (
392
- this.question?.type === 'Matrix Radio Button' &&
393
- this.matrixRadioGrid &&
394
- this.matrixRadioGrid[rowIndex]
395
- ) {
396
- const rowVal = this.matrixRadioGrid[rowIndex].value
397
- if (rowVal) {
398
- return rowVal.startsWith('a')
399
- }
400
- return false
370
+ if (
371
+ question?.value.type === 'Matrix Radio Button' &&
372
+ matrixRadioGrid.value?.[rowIndex]
373
+ ) {
374
+ const rowVal = matrixRadioGrid.value[rowIndex]?.value
375
+ if (rowVal) {
376
+ return rowVal.startsWith('a')
401
377
  }
378
+ return false
402
379
  }
403
- return false
404
380
  }
381
+ return false
382
+ }
405
383
 
406
- convertSelectedMatrixChoiceToCheckboxGrid () {
407
- const checkboxGrid = this.defaultCheckboxGrid
384
+ const convertSelectedMatrixChoiceToCheckboxGrid = () => {
385
+ const checkboxGrid = defaultCheckboxGrid.value
408
386
 
409
- // Reset this.selectedColumnHeaders string[][] in case in headers are still in the arrays
410
- // Let selectedMatrixChoices set those columns
411
- const columnMatrixLabels = this.question.matrixLabels?.rows
412
- const defaultSelectedColumnLabels: string[][] = []
413
- if (columnMatrixLabels) {
414
- columnMatrixLabels.forEach(() => {
415
- defaultSelectedColumnLabels.push([])
416
- })
387
+ // Reset selectedColumnHeaders string[][] in case in headers are still in the arrays
388
+ // Let selectedMatrixChoices set those columns
389
+ const columnMatrixLabels = question.value.matrixLabels?.rows
390
+ const defaultSelectedColumnLabels: string[][] = []
391
+ if (columnMatrixLabels) {
392
+ columnMatrixLabels.forEach(() => {
393
+ defaultSelectedColumnLabels.push([])
394
+ })
417
395
 
418
- this.selectedColumnHeaders = defaultSelectedColumnLabels
419
- }
396
+ selectedColumnHeaders.value = defaultSelectedColumnLabels
397
+ }
420
398
 
421
- this.selectedMatrixChoices.forEach(choice => {
422
- const rowIndex = Number(choice.substring(1, choice.indexOf('_'))) - 1
423
- const columnIndex = Number(choice.split('_').pop()) - 1
424
- if (checkboxGrid && checkboxGrid[rowIndex]) {
425
- checkboxGrid[rowIndex][columnIndex] = true
426
- if (this.selectedColumnHeaders[rowIndex] && this.question.matrixLabels?.columns[columnIndex]) {
427
- const columnHeader = this.question.matrixLabels?.columns[columnIndex]
428
- this.selectedColumnHeaders[rowIndex].push(columnHeader)
399
+ selectedMatrixChoices.value.forEach(choice => {
400
+ const rowIndex = Number(choice.substring(1, choice.indexOf('_'))) - 1
401
+ const columnIndex = Number(choice.split('_').pop()) - 1
402
+ const row = checkboxGrid?.[rowIndex]
403
+ if (row) {
404
+ row[columnIndex] = true
405
+ if (selectedColumnHeaders.value[rowIndex] && question.value.matrixLabels?.columns[columnIndex]) {
406
+ const columnHeader = question.value.matrixLabels?.columns[columnIndex]
407
+ if (columnHeader) {
408
+ selectedColumnHeaders.value[rowIndex]?.push(columnHeader)
429
409
  }
430
410
  }
431
- })
432
- return checkboxGrid
433
- }
434
-
435
- convertSelectedMatrixChoiceToRadioBtnGrid () {
436
- const radioBtnGrid = this.defaultRadioButtonGrid
437
-
438
- const columnMatrixLabels = this.question.matrixLabels?.rows
439
- const defaultSelectedColumnLabels: string[][] = []
440
- if (columnMatrixLabels) {
441
- columnMatrixLabels.forEach(() => {
442
- defaultSelectedColumnLabels.push([])
443
- })
444
-
445
- this.selectedColumnHeaders = defaultSelectedColumnLabels
446
411
  }
412
+ })
413
+ return checkboxGrid
414
+ }
447
415
 
448
- this.selectedMatrixChoices.forEach(choice => {
449
- const rowIndex = Number(choice.substring(1, choice.indexOf('_'))) - 1
450
- const columnIndex = Number(choice.split('_').pop()) - 1
451
- if (this.selectedColumnHeaders[rowIndex] && this.question.matrixLabels?.columns[columnIndex]) {
452
- const columnHeader = this.question.matrixLabels?.columns[columnIndex]
453
- // In case a column header is still in selectedColumnHeaders, remove it first and let
454
- // selectedMatrixChoices add selected column header based on selected choices
455
- this.selectedColumnHeaders[rowIndex].pop()
456
- this.selectedColumnHeaders[rowIndex].push(columnHeader)
457
- }
458
- if (radioBtnGrid && radioBtnGrid[rowIndex]) {
459
- radioBtnGrid[rowIndex].value = choice
460
- }
416
+ const convertSelectedMatrixChoiceToRadioBtnGrid = () => {
417
+ const radioBtnGrid = defaultRadioButtonGrid.value
418
+
419
+ const columnMatrixLabels = question.value.matrixLabels?.rows
420
+ const defaultSelectedColumnLabels: string[][] = []
421
+ if (columnMatrixLabels) {
422
+ columnMatrixLabels.forEach(() => {
423
+ defaultSelectedColumnLabels.push([])
461
424
  })
462
- return radioBtnGrid
425
+
426
+ selectedColumnHeaders.value = defaultSelectedColumnLabels
463
427
  }
464
428
 
465
- checkboxRowClicked (rowIndex: number, columnIndex: number) {
466
- if (this.matrixCheckboxGrid && this.matrixCheckboxGrid[rowIndex]) {
467
- this.matrixCheckboxGrid[rowIndex][columnIndex] = !this.matrixCheckboxGrid[rowIndex][columnIndex]
468
- const columnHeader = this.question.matrixLabels?.columns[columnIndex]
429
+ selectedMatrixChoices.value.forEach(choice => {
430
+ const rowIndex = Number(choice.substring(1, choice.indexOf('_'))) - 1
431
+ const columnIndex = Number(choice.split('_').pop()) - 1
432
+ if (selectedColumnHeaders.value[rowIndex] && question.value.matrixLabels?.columns[columnIndex]) {
433
+ const columnHeader = question.value.matrixLabels?.columns[columnIndex]
434
+ // In case a column header is still in selectedColumnHeaders, remove it first and let
435
+ // selectedMatrixChoices add selected column header based on selected choices
436
+ if (columnHeader) {
437
+ selectedColumnHeaders.value[rowIndex]?.pop()
438
+ selectedColumnHeaders.value[rowIndex]?.push(columnHeader)
439
+ }
440
+ }
441
+ const radioBtnGridRow = radioBtnGrid?.[rowIndex]
442
+ if (radioBtnGridRow) {
443
+ radioBtnGridRow.value = choice
444
+ }
445
+ })
446
+ return radioBtnGrid
447
+ }
469
448
 
470
- if (this.selectedColumnHeaders && this.selectedColumnHeaders[rowIndex] && columnHeader) {
471
- if (this.selectedColumnHeaders[rowIndex].includes(columnHeader)) {
472
- const columnHeaderIndex = this.selectedColumnHeaders[rowIndex].indexOf(columnHeader)
473
- if (columnHeaderIndex !== -1) {
474
- this.selectedColumnHeaders[rowIndex].splice(columnHeaderIndex, 1)
475
- }
476
- } else {
477
- this.selectedColumnHeaders[rowIndex].push(columnHeader)
449
+ const checkboxRowClicked = (rowIndex: number, columnIndex: number) => {
450
+ const matrixCheckboxGridRow = matrixCheckboxGrid.value?.[rowIndex]
451
+ if (matrixCheckboxGridRow) {
452
+ matrixCheckboxGridRow[columnIndex] = !matrixCheckboxGridRow[columnIndex]
453
+ const columnHeader = question.value.matrixLabels?.columns[columnIndex]
454
+
455
+ if (selectedColumnHeaders.value?.[rowIndex] && columnHeader) {
456
+ if (selectedColumnHeaders.value[rowIndex]?.includes(columnHeader)) {
457
+ const columnHeaderIndex = selectedColumnHeaders.value[rowIndex]?.indexOf(columnHeader)
458
+ if (columnHeaderIndex !== undefined && columnHeaderIndex !== -1) {
459
+ selectedColumnHeaders.value[rowIndex]?.splice(columnHeaderIndex, 1)
478
460
  }
461
+ } else {
462
+ selectedColumnHeaders.value[rowIndex]?.push(columnHeader)
479
463
  }
480
464
  }
481
465
  }
466
+ }
467
+
468
+ const doesSelectedColumnHeaderExist = (rowIndex: number, columnIndex: number) => {
469
+ return selectedColumnHeaders.value?.[rowIndex]?.[columnIndex] || false
470
+ }
482
471
 
483
- @Emit('emitSelectedMatrixChoice')
484
- emitSelectedMatrixChoice (matrixChoiceKeys: TMatrixChoiceKey[]) {
485
- return matrixChoiceKeys
472
+ const getSelectedChoiceLabels = (rowIndex: number, columnIndex: number) => {
473
+ const columnHeadersInRow = selectedColumnHeaders.value?.[rowIndex]
474
+ if (!columnHeadersInRow) {
475
+ return
486
476
  }
477
+ const selectedColumnHeader = columnHeadersInRow[columnIndex]
478
+ const lastColumnHeader = columnHeadersInRow[columnHeadersInRow.length - 1]
479
+ if (!selectedColumnHeader) {
480
+ return ''
481
+ }
482
+
483
+ return selectedColumnHeader === lastColumnHeader
484
+ ? stripHtmlTags(selectedColumnHeader)
485
+ : `${stripHtmlTags(selectedColumnHeader)},`
486
+ }
487
487
 
488
+ const emitSelectedMatrixChoice = (matrixChoiceKeys: TMatrixChoiceKey[]) => {
489
+ emit('emitSelectedMatrixChoice', matrixChoiceKeys)
490
+ }
488
491
 
489
- @Watch('matrixCheckboxGrid', { deep: true })
490
- matrixCheckboxGridChange () {
491
- if (this.matrixChoiceLayout && this.matrixCheckboxGrid && (!this.reviewMode || !this.showMatrixAnswers)) {
492
- const selectedCheckboxChoices: TMatrixChoiceKey[] = []
492
+ watch(matrixCheckboxGrid, () => {
493
+ if (matrixChoiceLayout.value && matrixCheckboxGrid.value && (!reviewMode.value || !showMatrixAnswers.value)) {
494
+ const selectedCheckboxChoices: TMatrixChoiceKey[] = []
493
495
 
494
- this.matrixCheckboxGrid.forEach((row, rowIndex) => {
495
- row.forEach((choice, choiceIndex) => {
496
- if (
497
- choice &&
498
- this.matrixChoiceLayout[rowIndex] &&
499
- this.matrixChoiceLayout[rowIndex][choiceIndex]
500
- ) {
501
- const choiceKey = this.matrixChoiceLayout[rowIndex][choiceIndex] as TMatrixChoiceKey
496
+ matrixCheckboxGrid.value.forEach((row, rowIndex) => {
497
+ row.forEach((choice, choiceIndex) => {
498
+ if (choice && matrixChoiceLayout?.value?.[rowIndex]?.[choiceIndex]) {
499
+ const choiceKey = matrixChoiceLayout.value?.[rowIndex]?.[choiceIndex] as TMatrixChoiceKey
500
+ if (choiceKey) {
502
501
  selectedCheckboxChoices.push(choiceKey)
503
502
  }
504
- })
503
+ }
505
504
  })
505
+ })
506
506
 
507
- this.emitSelectedMatrixChoice(selectedCheckboxChoices)
508
- }
507
+ emitSelectedMatrixChoice(selectedCheckboxChoices)
509
508
  }
509
+ }, { deep: true })
510
510
 
511
- @Watch('matrixRadioGrid', { deep: true })
512
- matrixRadioGridChange () {
513
- if (this.matrixChoiceLayout && this.matrixRadioGrid && (!this.reviewMode || !this.showMatrixAnswers)) {
514
- const selectedRadioButtonChoices: TMatrixChoiceKey[] = []
511
+ watch(matrixRadioGrid, () => {
512
+ if (matrixChoiceLayout.value && matrixRadioGrid.value && (!reviewMode.value || !showMatrixAnswers.value)) {
513
+ const selectedRadioButtonChoices: TMatrixChoiceKey[] = []
515
514
 
516
- this.matrixRadioGrid.forEach((row) => {
517
- if (row.value) {
518
- selectedRadioButtonChoices.push(row.value)
519
- }
520
- })
515
+ matrixRadioGrid.value.forEach((row) => {
516
+ if (row.value) {
517
+ selectedRadioButtonChoices.push(row.value)
518
+ }
519
+ })
521
520
 
522
- this.emitSelectedMatrixChoice(selectedRadioButtonChoices)
523
- }
521
+ emitSelectedMatrixChoice(selectedRadioButtonChoices)
524
522
  }
523
+ }, { deep: true })
525
524
 
526
- @Watch('showMatrixAnswers')
527
- closeRows () {
528
- if (this.showMatrixAnswers) {
529
- this.expandedRowNumbers = []
530
- }
525
+ watch(showMatrixAnswers, () => {
526
+ if (showMatrixAnswers) {
527
+ expandedRowNumbers.value = []
531
528
  }
529
+ })
532
530
 
533
- @Watch('selectedMatrixChoices')
534
- selectedMatrixChoicesChange () {
535
- if ((this.reviewMode || this.showMatrixAnswers) && this.question.type === 'Matrix Checkbox') {
536
- const selectedCheckboxGrid = this.convertSelectedMatrixChoiceToCheckboxGrid()
537
- this.matrixCheckboxGrid = selectedCheckboxGrid ? selectedCheckboxGrid : this.defaultCheckboxGrid
538
- }
539
-
540
- if ((this.reviewMode || this.showMatrixAnswers) && this.question.type === 'Matrix Radio Button') {
541
- const selectedRadioBtnGrid = this.convertSelectedMatrixChoiceToRadioBtnGrid()
542
- this.matrixRadioGrid = selectedRadioBtnGrid
543
- }
531
+ watch(selectedMatrixChoices, () => {
532
+ if ((reviewMode.value || showMatrixAnswers.value) && question.value.type === 'Matrix Checkbox') {
533
+ const selectedCheckboxGrid = convertSelectedMatrixChoiceToCheckboxGrid()
534
+ matrixCheckboxGrid.value = selectedCheckboxGrid ? selectedCheckboxGrid : defaultCheckboxGrid.value
544
535
  }
545
- }
546
536
 
537
+ if ((reviewMode.value || showMatrixAnswers.value) && question.value.type === 'Matrix Radio Button') {
538
+ const selectedRadioBtnGrid = convertSelectedMatrixChoiceToRadioBtnGrid()
539
+ matrixRadioGrid.value = selectedRadioBtnGrid
540
+ }
541
+ })
547
542
  </script>
548
543
 
549
544
  <style lang="scss">
550
- @import '../../../styles/colors';
551
- @import '../../../styles/breakpoints';
545
+ @use '@/styles/breakpoints' as *;
546
+ @use '@/styles/colors' as *;
552
547
 
553
548
  .uikit-question-mobile-matrix-choices-container {
554
549
  width: 100%;