@pocketprep/ui-kit 3.0.29 → 3.0.31

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.
@@ -54,60 +54,65 @@ export default class ModalContainer extends Vue {
54
54
  savedYPosition = 0
55
55
 
56
56
  mounted () {
57
- const focusableSelectors = 'button, [href], input, select, textarea, [tabindex]'
58
-
59
- // Reset focus to last element in modal so next tab will move it to top
60
- const modalContainerEl = this.$refs['modalContainer'] as HTMLElement
61
- const modalFocusableEls = Array.from<HTMLElement>(modalContainerEl.querySelectorAll(focusableSelectors))
62
- if (modalFocusableEls.length) {
63
- modalFocusableEls[modalFocusableEls.length - 1]?.focus()
64
- modalFocusableEls[modalFocusableEls.length - 1]?.blur()
65
- }
66
-
67
- // Trap the user's focus within the modal - don't allow focusing elements behind the overlay
68
- this.focusListener = event => {
69
- const target = (event as FocusEvent).target as HTMLElement // The element receiving focus
70
- const isFocusOutside = target && modalContainerEl && !modalContainerEl.contains(target)
71
- const hasCalendarClass = target
72
- && Array.from(target.classList).find(
73
- c => c === 'button-next-month' || c === 'button-previous-month' || c === 'day-item'
74
- )
75
- if (isFocusOutside && !hasCalendarClass) {
76
- const focusableModalChildren = Array.from<HTMLElement>(modalContainerEl.querySelectorAll(
77
- focusableSelectors
78
- ))
79
- const firstFocusableModalChild = focusableModalChildren.find(
80
- el => !!el.getBoundingClientRect().width
81
- )
82
- const reversedModalChildren = [ ...focusableModalChildren ].reverse()
83
- const lastFocusableModalChild = reversedModalChildren.find(
84
- el => !!el.getBoundingClientRect().width
85
- )
86
- if (firstFocusableModalChild) {
87
- const relatedTarget = (event as FocusEvent).relatedTarget // The element last focused
88
- if (relatedTarget === firstFocusableModalChild && lastFocusableModalChild) {
89
- // If focus moves from first element -> outside modal, focus the last element instead
90
- lastFocusableModalChild.focus()
91
- } else if (relatedTarget === lastFocusableModalChild && firstFocusableModalChild) {
92
- // If focus moves from last element -> outside modal, focus the first element instead
93
- firstFocusableModalChild.focus()
94
- } else if (relatedTarget && relatedTarget instanceof HTMLElement) {
95
- // If focus goes outside in a different way, return focus to where it came from if possible
96
- relatedTarget.focus()
57
+ // Prevent an error where multiple modals trigger a loop
58
+ // TODO: Find a way to have only the latest modal's focusListener active
59
+ const openModals = document.querySelectorAll('.uikit-modal-container')
60
+ if (openModals.length === 1) {
61
+ const focusableSelectors = 'button, [href], input, select, textarea, [tabindex]'
62
+
63
+ // Reset focus to last element in modal so next tab will move it to top
64
+ const modalContainerEl = this.$refs['modalContainer'] as HTMLElement
65
+ const modalFocusableEls = Array.from<HTMLElement>(modalContainerEl.querySelectorAll(focusableSelectors))
66
+ if (modalFocusableEls.length) {
67
+ modalFocusableEls[modalFocusableEls.length - 1]?.focus()
68
+ modalFocusableEls[modalFocusableEls.length - 1]?.blur()
69
+ }
70
+
71
+ // Trap the user's focus within the modal - don't allow focusing elements behind the overlay
72
+ this.focusListener = event => {
73
+ const target = (event as FocusEvent).target as HTMLElement // The element receiving focus
74
+ const isFocusOutside = target && modalContainerEl && !modalContainerEl.contains(target)
75
+ const hasCalendarClass = target
76
+ && Array.from(target.classList).find(
77
+ c => c === 'button-next-month' || c === 'button-previous-month' || c === 'day-item'
78
+ )
79
+ if (isFocusOutside && !hasCalendarClass) {
80
+ const focusableModalChildren = Array.from<HTMLElement>(modalContainerEl.querySelectorAll(
81
+ focusableSelectors
82
+ ))
83
+ const firstFocusableModalChild = focusableModalChildren.find(
84
+ el => !!el.getBoundingClientRect().width
85
+ )
86
+ const reversedModalChildren = [ ...focusableModalChildren ].reverse()
87
+ const lastFocusableModalChild = reversedModalChildren.find(
88
+ el => !!el.getBoundingClientRect().width
89
+ )
90
+ if (firstFocusableModalChild) {
91
+ const relatedTarget = (event as FocusEvent).relatedTarget // The element last focused
92
+ if (relatedTarget === firstFocusableModalChild && lastFocusableModalChild) {
93
+ // If focus moves from first element -> outside modal, focus the last element instead
94
+ lastFocusableModalChild.focus()
95
+ } else if (relatedTarget === lastFocusableModalChild && firstFocusableModalChild) {
96
+ // If focus moves from last element -> outside modal, focus the first element instead
97
+ firstFocusableModalChild.focus()
98
+ } else if (relatedTarget && relatedTarget instanceof HTMLElement) {
99
+ // If focus goes outside in a different way, return focus to where it came from if possible
100
+ relatedTarget.focus()
101
+ } else {
102
+ // Otherwise, just return focus to the first element
103
+ firstFocusableModalChild.focus()
104
+ }
97
105
  } else {
98
- // Otherwise, just return focus to the first element
99
- firstFocusableModalChild.focus()
100
- }
101
- } else {
102
- // If the modal doesn't have any focusable children, focus the container instead
103
- if (modalContainerEl.tabIndex === -1) {
104
- modalContainerEl.tabIndex = 0
106
+ // If the modal doesn't have any focusable children, focus the container instead
107
+ if (modalContainerEl.tabIndex === -1) {
108
+ modalContainerEl.tabIndex = 0
109
+ }
110
+ modalContainerEl.focus()
105
111
  }
106
- modalContainerEl.focus()
107
112
  }
108
113
  }
114
+ document.addEventListener('focusin', this.focusListener)
109
115
  }
110
- document.addEventListener('focusin', this.focusListener)
111
116
 
112
117
  // prevent scrolling outside of modal
113
118
  const openModalCount = Number(document.body.getAttribute('data-openModalCount'))
@@ -18,6 +18,12 @@
18
18
  @click="emitClose"
19
19
  />
20
20
  </slot>
21
+ <div
22
+ class="uikit-question__tag-mobile"
23
+ v-breakpoint:questionEl="breakpoints"
24
+ >
25
+ <slot name="tagMobile" />
26
+ </div>
21
27
  <div
22
28
  v-breakpoint:questionEl="breakpoints"
23
29
  class="uikit-question__main"
@@ -80,6 +86,12 @@
80
86
  </div>
81
87
  </h2>
82
88
  </slot>
89
+ <div
90
+ class="uikit-question__tag"
91
+ v-breakpoint:questionEl="breakpoints"
92
+ >
93
+ <slot name="tag" />
94
+ </div>
83
95
  </div>
84
96
  </slot>
85
97
  <div
@@ -564,6 +576,23 @@
564
576
  />
565
577
  </div>
566
578
  </template>
579
+ <div
580
+ v-breakpoint:questionEl="breakpoints"
581
+ class="uikit-question__motivational-moment"
582
+ :class="{
583
+ 'uikit-question__motivational-moment--mcr': isMCR,
584
+ 'uikit-question__motivational-moment--explanation': showExplanation,
585
+ 'uikit-question__motivational-moment--passage-and-image': showPassageAndImage,
586
+ }"
587
+ >
588
+ <slot
589
+ name="motivationalMoment"
590
+ :showAnswers="showAnswers"
591
+ :answerKeys="answerKeys"
592
+ :choiceKey="choice.key"
593
+ :isCorrect="isCorrect"
594
+ />
595
+ </div>
567
596
  </div>
568
597
  <slot
569
598
  name="showNamesTable"
@@ -704,6 +733,21 @@
704
733
  </div>
705
734
  </div>
706
735
  </slot>
736
+ <div
737
+ v-breakpoint:questionEl="breakpoints"
738
+ class="uikit-question__motivational-moment-bottom"
739
+ :class="{
740
+ 'uikit-question__motivational-moment-bottom--mcr': isMCR,
741
+ 'uikit-question__motivational-moment-bottom--explanation': showExplanation,
742
+ 'uikit-question__motivational-moment-bottom--passage-and-image': showPassageAndImage,
743
+ }"
744
+ >
745
+ <slot
746
+ name="motivationalMomentBottom"
747
+ :showAnswers="showAnswers"
748
+ :isCorrect="isCorrect"
749
+ />
750
+ </div>
707
751
  <div
708
752
  v-if="!reviewMode"
709
753
  v-breakpoint:questionEl="breakpoints"
@@ -2106,6 +2150,26 @@ export default class Question extends Vue {
2106
2150
  font-weight: 500;
2107
2151
  }
2108
2152
 
2153
+ &__tag {
2154
+ margin-top: 8px;
2155
+ margin-bottom: -5px;
2156
+
2157
+ &--mobile {
2158
+ display: none;
2159
+ }
2160
+ }
2161
+
2162
+ &__tag-mobile {
2163
+ display: none;
2164
+ position: absolute;
2165
+ top: 14px;
2166
+ right: 14px;
2167
+
2168
+ &--mobile {
2169
+ display: block;
2170
+ }
2171
+ }
2172
+
2109
2173
  &__prompt {
2110
2174
  outline: none;
2111
2175
  font-weight: 600;
@@ -3158,6 +3222,44 @@ export default class Question extends Vue {
3158
3222
  }
3159
3223
  }
3160
3224
 
3225
+ &__motivational-moment {
3226
+ position: absolute;
3227
+ right: -150px;
3228
+ top: 20px;
3229
+
3230
+ &--mcr {
3231
+ display: none;
3232
+ }
3233
+
3234
+ &--passage-and-image {
3235
+ display: none;
3236
+ }
3237
+
3238
+ &--explanation {
3239
+ display: none;
3240
+ }
3241
+
3242
+ &--tablet-portrait {
3243
+ display: none;
3244
+ }
3245
+ }
3246
+
3247
+ &__motivational-moment-bottom {
3248
+ display: none;
3249
+
3250
+ &--mcr {
3251
+ display: block;
3252
+ }
3253
+
3254
+ &--passage-and-image:not(#{&}--tablet-portrait) {
3255
+ display: block;
3256
+ }
3257
+
3258
+ &--tablet-portrait {
3259
+ display: block;
3260
+ }
3261
+ }
3262
+
3161
3263
  &__summary {
3162
3264
  position: relative;
3163
3265
  background-color: $white;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pocketprep/ui-kit",
3
- "version": "3.0.29",
3
+ "version": "3.0.31",
4
4
  "description": "Pocket Prep UI Kit",
5
5
  "author": "pocketprep",
6
6
  "scripts": {