@pocketprep/ui-kit 3.8.4 → 3.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/@pocketprep/ui-kit.css +1 -1
- package/dist/@pocketprep/ui-kit.js +14469 -17731
- package/dist/@pocketprep/ui-kit.js.map +1 -1
- package/dist/@pocketprep/ui-kit.umd.cjs +19 -29
- package/dist/@pocketprep/ui-kit.umd.cjs.map +1 -1
- package/eslint.config.ts +38 -11
- package/lib/SVGDefinitions.vue +32 -35
- package/lib/components/Banners/Banner.vue +10 -14
- package/lib/components/Blobs/Blob.vue +6 -14
- package/lib/components/Blobs/BlobEmptyState.vue +9 -8
- package/lib/components/Blobs/blob.d.ts +1 -1
- package/lib/components/BundleIcons/BundleIcon.vue +36 -63
- package/lib/components/BundleIcons/bundleIcon.d.ts +1 -1
- package/lib/components/Bundles/BundleList.vue +71 -59
- package/lib/components/Bundles/BundleSearch.vue +93 -117
- package/lib/components/Bundles/PremiumPill.vue +6 -12
- package/lib/components/Buttons/Button.vue +32 -35
- package/lib/components/Buttons/Link.vue +32 -31
- package/lib/components/Buttons/Tab.vue +14 -17
- package/lib/components/Calendar/Calendar.vue +87 -85
- package/lib/components/Charts/Bar.vue +192 -263
- package/lib/components/Charts/Pie.vue +55 -61
- package/lib/components/Charts/highcharts-wrap.ts +81 -0
- package/lib/components/Controls/SegmentControl.vue +26 -24
- package/lib/components/Controls/Slider.vue +51 -47
- package/lib/components/Controls/ToggleSwitch.vue +33 -31
- package/lib/components/EmptyStates/EmptyState.vue +69 -73
- package/lib/components/Exams/ExamCard.vue +59 -47
- package/lib/components/Exams/ExamMenuCard.vue +30 -28
- package/lib/components/Filters/FilterDropdown.vue +83 -86
- package/lib/components/Filters/FilterOptions.vue +83 -88
- package/lib/components/Forms/Checkbox.vue +27 -27
- package/lib/components/Forms/CheckboxOption.vue +30 -30
- package/lib/components/Forms/Errors.vue +21 -24
- package/lib/components/Forms/Input.vue +71 -59
- package/lib/components/Forms/Radio.vue +2 -2
- package/lib/components/Forms/RadioButton.vue +8 -8
- package/lib/components/Forms/Select.vue +265 -257
- package/lib/components/Forms/Textarea.vue +49 -35
- package/lib/components/Icons/IconAccordionArrow.vue +7 -9
- package/lib/components/Icons/IconActivity.vue +7 -9
- package/lib/components/Icons/IconAdd.vue +7 -11
- package/lib/components/Icons/IconAddCircle.vue +7 -9
- package/lib/components/Icons/IconArrow.vue +7 -9
- package/lib/components/Icons/IconBarChart.vue +7 -9
- package/lib/components/Icons/IconCalendar.vue +7 -9
- package/lib/components/Icons/IconCalendarPicker.vue +7 -9
- package/lib/components/Icons/IconChat.vue +7 -9
- package/lib/components/Icons/IconCheck.vue +7 -9
- package/lib/components/Icons/IconClose.vue +7 -9
- package/lib/components/Icons/IconConcept.vue +1 -1
- package/lib/components/Icons/IconCorrect.vue +7 -9
- package/lib/components/Icons/IconEdit.vue +7 -11
- package/lib/components/Icons/IconExam.vue +7 -9
- package/lib/components/Icons/IconExternalLink.vue +7 -9
- package/lib/components/Icons/IconEyeHide.vue +7 -9
- package/lib/components/Icons/IconEyeShow.vue +7 -9
- package/lib/components/Icons/IconFilter.vue +7 -9
- package/lib/components/Icons/IconFilterActive.vue +7 -9
- package/lib/components/Icons/IconFlag.vue +7 -9
- package/lib/components/Icons/IconFlagContent.vue +8 -9
- package/lib/components/Icons/IconFlagFeedback.vue +8 -10
- package/lib/components/Icons/IconFlagFilled.vue +7 -9
- package/lib/components/Icons/IconFullView.vue +7 -9
- package/lib/components/Icons/IconFullViewActive.vue +7 -9
- package/lib/components/Icons/IconGridDrag.vue +2 -2
- package/lib/components/Icons/IconHandle.vue +7 -9
- package/lib/components/Icons/IconHeart.vue +7 -9
- package/lib/components/Icons/IconHelp.vue +7 -9
- package/lib/components/Icons/IconHighlight.vue +2 -2
- package/lib/components/Icons/IconHourglass.vue +7 -9
- package/lib/components/Icons/IconImage.vue +7 -9
- package/lib/components/Icons/IconIncorrect.vue +7 -9
- package/lib/components/Icons/IconInfo.vue +7 -9
- package/lib/components/Icons/IconKeyboard.vue +7 -9
- package/lib/components/Icons/IconLaunch.vue +7 -9
- package/lib/components/Icons/IconLevelUp.vue +7 -9
- package/lib/components/Icons/IconLightbulb.vue +7 -9
- package/lib/components/Icons/IconLightning.vue +7 -9
- package/lib/components/Icons/IconLink.vue +7 -9
- package/lib/components/Icons/IconList.vue +7 -9
- package/lib/components/Icons/IconLoading.vue +7 -9
- package/lib/components/Icons/IconLoading2.vue +11 -11
- package/lib/components/Icons/IconLock.vue +7 -9
- package/lib/components/Icons/IconMissedQuestions.vue +7 -9
- package/lib/components/Icons/IconMoon.vue +7 -9
- package/lib/components/Icons/IconPaginationArrow.vue +7 -9
- package/lib/components/Icons/IconPaginationArrowDouble.vue +7 -9
- package/lib/components/Icons/IconPassage.vue +7 -9
- package/lib/components/Icons/IconPencil.vue +7 -9
- package/lib/components/Icons/IconPeople.vue +7 -9
- package/lib/components/Icons/IconPercent.vue +7 -9
- package/lib/components/Icons/IconPerson.vue +8 -9
- package/lib/components/Icons/IconPresent.vue +7 -9
- package/lib/components/Icons/IconPreview.vue +7 -9
- package/lib/components/Icons/IconQuestions.vue +7 -9
- package/lib/components/Icons/IconQuick10.vue +7 -9
- package/lib/components/Icons/IconQuickActions.vue +2 -2
- package/lib/components/Icons/IconRecommendedFilter.vue +1 -1
- package/lib/components/Icons/IconRemoveCircle.vue +7 -9
- package/lib/components/Icons/IconReviewFlag.vue +7 -9
- package/lib/components/Icons/IconSearch.vue +7 -9
- package/lib/components/Icons/IconShare.vue +7 -9
- package/lib/components/Icons/IconSideBar.vue +7 -9
- package/lib/components/Icons/IconSideBarActive.vue +7 -9
- package/lib/components/Icons/IconStar.vue +1 -1
- package/lib/components/Icons/IconStopwatch.vue +7 -9
- package/lib/components/Icons/IconStrike.vue +7 -9
- package/lib/components/Icons/IconSubject.vue +7 -9
- package/lib/components/Icons/IconText.vue +7 -9
- package/lib/components/Icons/IconTimer.vue +8 -9
- package/lib/components/Icons/IconWarning.vue +7 -9
- package/lib/components/Icons/icon.d.ts +1 -1
- package/lib/components/Loaders/SkeletonLoader.vue +1 -5
- package/lib/components/Modal/Modal.vue +23 -29
- package/lib/components/Modal/ModalContainer.vue +135 -133
- package/lib/components/Onboarding/EmailAuth.vue +66 -70
- package/lib/components/Onboarding/MagicCodeEntry.vue +88 -83
- package/lib/components/Pagination/QuestionReviewPagination.vue +3 -3
- package/lib/components/Pagination/TablePagination.vue +47 -44
- package/lib/components/PhonePerson/PhonePerson.vue +18 -18
- package/lib/components/PhonePerson/phonePerson.d.ts +1 -1
- package/lib/components/Quiz/FlagToggle.vue +45 -44
- package/lib/components/Quiz/GlobalMetricsToggle.vue +29 -28
- package/lib/components/Quiz/KeyboardShortcutsButton.vue +16 -23
- package/lib/components/Quiz/KeyboardShortcutsModal.vue +36 -37
- package/lib/components/Quiz/Question/BuildListChoicesContainer.vue +65 -65
- package/lib/components/Quiz/Question/ChoicesContainer.vue +5 -5
- package/lib/components/Quiz/Question/DropdownExplanation.vue +5 -5
- package/lib/components/Quiz/Question/Explanation.vue +6 -6
- package/lib/components/Quiz/Question/MPMCChoicesContainer.vue +17 -17
- package/lib/components/Quiz/Question/MPMCRadioGroup.vue +2 -2
- package/lib/components/Quiz/Question/MatrixChoicesContainer.vue +39 -39
- package/lib/components/Quiz/Question/MatrixRadioGroup.vue +6 -6
- package/lib/components/Quiz/Question/MobileMatrixChoicesContainer.vue +27 -28
- package/lib/components/Quiz/Question/MobileMatrixRadioGroup.vue +2 -2
- package/lib/components/Quiz/Question/PassageAndImage.vue +3 -3
- package/lib/components/Quiz/Question/PassageAndImageDropdown.vue +7 -7
- package/lib/components/Quiz/Question/Paywall.vue +2 -2
- package/lib/components/Quiz/Question/QuestionContext.vue +1 -1
- package/lib/components/Quiz/Question/StatsSummary.vue +2 -2
- package/lib/components/Quiz/Question/Summary.vue +11 -11
- package/lib/components/Quiz/Question.vue +90 -82
- package/lib/components/Quiz/QuizContainer.vue +1 -1
- package/lib/components/Quiz/QuizProgressBar.vue +23 -23
- package/lib/components/Quiz/question.d.ts +3 -3
- package/lib/components/Search/Pill.vue +16 -19
- package/lib/components/Search/Search.vue +52 -47
- package/lib/components/SidePanels/SidePanel.vue +168 -174
- package/lib/components/Tables/Table.vue +135 -122
- package/lib/components/Tables/TableActions.vue +81 -76
- package/lib/components/Tables/table.d.ts +1 -1
- package/lib/components/Tags/Tag.vue +49 -39
- package/lib/components/Toasts/Toast.vue +44 -42
- package/lib/components/Tooltips/OverflowTooltip.vue +39 -45
- package/lib/components/Tooltips/Tooltip.vue +69 -70
- package/lib/directives.ts +4 -4
- package/lib/utils.ts +13 -12
- package/package.json +27 -28
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
@keydown="keydownListener"
|
|
12
12
|
>
|
|
13
13
|
<div
|
|
14
|
-
class="uikit-modal-container__clickable"
|
|
14
|
+
class="uikit-modal-container__clickable"
|
|
15
15
|
@click.self="emitClose"
|
|
16
16
|
@mousedown.self.prevent
|
|
17
17
|
/>
|
|
@@ -33,160 +33,162 @@
|
|
|
33
33
|
</div>
|
|
34
34
|
</template>
|
|
35
35
|
|
|
36
|
-
<script lang="ts">
|
|
37
|
-
import { Vue, Component, Prop, Emit, Watch } from 'vue-facing-decorator'
|
|
36
|
+
<script setup lang="ts">
|
|
38
37
|
import Modal from '../Modal/Modal.vue'
|
|
39
|
-
import { dark } from '../../directives'
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
},
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
38
|
+
import { dark as vDark } from '../../directives'
|
|
39
|
+
import { onBeforeUnmount, onMounted, ref, useTemplateRef, watch } from 'vue'
|
|
40
|
+
|
|
41
|
+
const {
|
|
42
|
+
showCloseButton = false,
|
|
43
|
+
customCloseStyles = {},
|
|
44
|
+
isDarkMode = false,
|
|
45
|
+
trapFocus = true,
|
|
46
|
+
removeHeadBorderBottom = false,
|
|
47
|
+
} = defineProps<{
|
|
48
|
+
showCloseButton?: boolean
|
|
49
|
+
customCloseStyles?: Record<string, string>
|
|
50
|
+
isDarkMode?: boolean
|
|
51
|
+
trapFocus?: boolean
|
|
52
|
+
removeHeadBorderBottom?: boolean
|
|
53
|
+
}>()
|
|
54
|
+
|
|
55
|
+
const emit = defineEmits<{
|
|
56
|
+
'close': []
|
|
57
|
+
'mounted': []
|
|
58
|
+
'unmounted': []
|
|
59
|
+
}>()
|
|
60
|
+
|
|
61
|
+
const focusListener = ref<Parameters<typeof addEventListener>[1] | null>(null)
|
|
62
|
+
const modalNumber = ref(0)
|
|
63
|
+
|
|
64
|
+
const modalContainerRef = useTemplateRef<HTMLElement>('modalContainer')
|
|
65
|
+
|
|
66
|
+
const numberOfModals = () => {
|
|
67
|
+
return document.querySelectorAll('.uikit-modal-container').length
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
onMounted(() => {
|
|
71
|
+
modalNumber.value = numberOfModals()
|
|
72
|
+
// Prevent an error where multiple modals trigger a loop
|
|
73
|
+
// TODO: Find a way to have only the latest modal's focusListener active
|
|
74
|
+
|
|
75
|
+
const focusableSelectors = 'button, [href], input, select, textarea, [tabindex]'
|
|
76
|
+
|
|
77
|
+
// Reset focus to last element in modal so next tab will move it to top
|
|
78
|
+
const modalContainerEl = modalContainerRef.value
|
|
79
|
+
const modalFocusableEls = modalContainerEl && Array.from<HTMLElement>(modalContainerEl
|
|
80
|
+
.querySelectorAll(focusableSelectors))
|
|
81
|
+
.filter(el => !('disabled' in el && el.disabled === true))
|
|
82
|
+
if (modalFocusableEls?.length) {
|
|
83
|
+
modalFocusableEls[modalFocusableEls.length - 1]?.focus()
|
|
84
|
+
modalFocusableEls[modalFocusableEls.length - 1]?.blur()
|
|
62
85
|
}
|
|
63
86
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
)
|
|
95
|
-
const reversedModalChildren = [ ...focusableModalChildren ].reverse()
|
|
96
|
-
const lastFocusableModalChild = reversedModalChildren.find(
|
|
97
|
-
el => !!el.getBoundingClientRect().width
|
|
98
|
-
)
|
|
99
|
-
if (firstFocusableModalChild) {
|
|
100
|
-
const relatedTarget = (event as FocusEvent).relatedTarget // The element last focused
|
|
101
|
-
if (relatedTarget === firstFocusableModalChild && lastFocusableModalChild) {
|
|
102
|
-
// If focus moves from first element -> outside modal, focus the last element instead
|
|
103
|
-
lastFocusableModalChild.focus()
|
|
104
|
-
} else if (relatedTarget === lastFocusableModalChild && firstFocusableModalChild) {
|
|
105
|
-
// If focus moves from last element -> outside modal, focus the first element instead
|
|
106
|
-
firstFocusableModalChild.focus()
|
|
107
|
-
} else if (relatedTarget && relatedTarget instanceof HTMLElement) {
|
|
108
|
-
// If focus goes outside in a different way, return focus to where it came from if possible
|
|
109
|
-
relatedTarget.focus()
|
|
110
|
-
} else {
|
|
111
|
-
// Otherwise, just return focus to the first element
|
|
112
|
-
firstFocusableModalChild.focus()
|
|
113
|
-
}
|
|
87
|
+
focusListener.value = event => {
|
|
88
|
+
if (modalNumber.value === numberOfModals()) { // Only focus on the last open panel
|
|
89
|
+
const target = (event as FocusEvent).target as HTMLElement // The element receiving focus
|
|
90
|
+
const isFocusOutside = target && modalContainerEl && !modalContainerEl.contains(target)
|
|
91
|
+
const hasCalendarClass = target?.classList
|
|
92
|
+
&& Array.from(target.classList).find(
|
|
93
|
+
c => c === 'button-next-month' || c === 'button-previous-month' || c === 'day-item'
|
|
94
|
+
)
|
|
95
|
+
if (isFocusOutside && !hasCalendarClass) {
|
|
96
|
+
const focusableModalChildren = Array.from<HTMLElement>(modalContainerEl.querySelectorAll(
|
|
97
|
+
focusableSelectors
|
|
98
|
+
))
|
|
99
|
+
const firstFocusableModalChild = focusableModalChildren.find(
|
|
100
|
+
el => !!el.getBoundingClientRect().width
|
|
101
|
+
)
|
|
102
|
+
const reversedModalChildren = [ ...focusableModalChildren ].reverse()
|
|
103
|
+
const lastFocusableModalChild = reversedModalChildren.find(
|
|
104
|
+
el => !!el.getBoundingClientRect().width
|
|
105
|
+
)
|
|
106
|
+
if (firstFocusableModalChild) {
|
|
107
|
+
const relatedTarget = (event as FocusEvent).relatedTarget // The element last focused
|
|
108
|
+
if (relatedTarget === firstFocusableModalChild && lastFocusableModalChild) {
|
|
109
|
+
// If focus moves from first element -> outside modal, focus the last element instead
|
|
110
|
+
lastFocusableModalChild.focus()
|
|
111
|
+
} else if (relatedTarget === lastFocusableModalChild && firstFocusableModalChild) {
|
|
112
|
+
// If focus moves from last element -> outside modal, focus the first element instead
|
|
113
|
+
firstFocusableModalChild.focus()
|
|
114
|
+
} else if (relatedTarget && relatedTarget instanceof HTMLElement) {
|
|
115
|
+
// If focus goes outside in a different way, return focus to where it came from if possible
|
|
116
|
+
relatedTarget.focus()
|
|
114
117
|
} else {
|
|
115
|
-
//
|
|
116
|
-
|
|
117
|
-
modalContainerEl.tabIndex = 0
|
|
118
|
-
}
|
|
119
|
-
modalContainerEl.focus()
|
|
118
|
+
// Otherwise, just return focus to the first element
|
|
119
|
+
firstFocusableModalChild.focus()
|
|
120
120
|
}
|
|
121
|
+
} else {
|
|
122
|
+
// If the modal doesn't have any focusable children, focus the container instead
|
|
123
|
+
if (modalContainerEl.tabIndex === -1) {
|
|
124
|
+
modalContainerEl.tabIndex = 0
|
|
125
|
+
}
|
|
126
|
+
modalContainerEl.focus()
|
|
121
127
|
}
|
|
122
128
|
}
|
|
123
129
|
}
|
|
124
|
-
// Trap the user's focus within the modal - don't allow focusing elements behind the overlay
|
|
125
|
-
if (this.trapFocus) {
|
|
126
|
-
document.addEventListener('focusin', this.focusListener)
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// prevent scrolling outside of modal
|
|
130
|
-
const openModalCount = Number(document.body.getAttribute('data-openModalCount'))
|
|
131
|
-
document.body.setAttribute('data-openModalCount', String(openModalCount + 1))
|
|
132
|
-
document.body.classList.add('uikit-modal-open')
|
|
133
|
-
|
|
134
|
-
this.emitMounted()
|
|
135
130
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
document.removeEventListener('focusin', this.focusListener)
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const openModalCount = Number(document.body.getAttribute('data-openModalCount'))
|
|
143
|
-
document.body.setAttribute('data-openModalCount', String(openModalCount - 1))
|
|
144
|
-
if (openModalCount <= 1) {
|
|
145
|
-
document.body.classList.remove('uikit-modal-open')
|
|
146
|
-
}
|
|
147
|
-
this.emitUnmounted()
|
|
131
|
+
// Trap the user's focus within the modal - don't allow focusing elements behind the overlay
|
|
132
|
+
if (trapFocus) {
|
|
133
|
+
document.addEventListener('focusin', focusListener.value)
|
|
148
134
|
}
|
|
149
135
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
136
|
+
// prevent scrolling outside of modal
|
|
137
|
+
const openModalCount = Number(document.body.getAttribute('data-openModalCount'))
|
|
138
|
+
document.body.setAttribute('data-openModalCount', String(openModalCount + 1))
|
|
139
|
+
document.body.classList.add('uikit-modal-open')
|
|
154
140
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
141
|
+
emitMounted()
|
|
142
|
+
})
|
|
158
143
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
144
|
+
onBeforeUnmount(() => {
|
|
145
|
+
if (focusListener.value) {
|
|
146
|
+
document.removeEventListener('focusin', focusListener.value)
|
|
162
147
|
}
|
|
163
148
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
149
|
+
const openModalCount = Number(document.body.getAttribute('data-openModalCount'))
|
|
150
|
+
document.body.setAttribute('data-openModalCount', String(openModalCount - 1))
|
|
151
|
+
if (openModalCount <= 1) {
|
|
152
|
+
document.body.classList.remove('uikit-modal-open')
|
|
167
153
|
}
|
|
154
|
+
emitUnmounted()
|
|
155
|
+
})
|
|
168
156
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
return
|
|
157
|
+
const keydownListener = (e: Event | KeyboardEvent) => {
|
|
158
|
+
if (!('key' in e)) {
|
|
159
|
+
return
|
|
172
160
|
}
|
|
173
161
|
|
|
174
|
-
@
|
|
175
|
-
|
|
176
|
-
return true
|
|
162
|
+
if (e.key.match(/^[A-Za-z0-9\s\-_@]$/)) {
|
|
163
|
+
e.stopPropagation()
|
|
177
164
|
}
|
|
178
165
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
if (this.focusListener) {
|
|
182
|
-
if (this.trapFocus) {
|
|
183
|
-
document.addEventListener('focusin', this.focusListener)
|
|
184
|
-
} else {
|
|
185
|
-
document.removeEventListener('focusin', this.focusListener)
|
|
186
|
-
}
|
|
187
|
-
}
|
|
166
|
+
if (e.key === 'Escape') {
|
|
167
|
+
emitClose()
|
|
188
168
|
}
|
|
189
169
|
}
|
|
170
|
+
|
|
171
|
+
const emitClose = () => {
|
|
172
|
+
emit('close')
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const emitMounted = () => {
|
|
176
|
+
emit('mounted')
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const emitUnmounted = () => {
|
|
180
|
+
emit('unmounted')
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
watch(() => trapFocus, () => {
|
|
184
|
+
if (focusListener.value) {
|
|
185
|
+
if (trapFocus) {
|
|
186
|
+
document.addEventListener('focusin', focusListener.value)
|
|
187
|
+
} else {
|
|
188
|
+
document.removeEventListener('focusin', focusListener.value)
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
})
|
|
190
192
|
</script>
|
|
191
193
|
|
|
192
194
|
<style lang="scss">
|
|
@@ -246,4 +248,4 @@ export default class ModalContainer extends Vue {
|
|
|
246
248
|
}
|
|
247
249
|
}
|
|
248
250
|
}
|
|
249
|
-
</style>
|
|
251
|
+
</style>
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
:class="{
|
|
12
12
|
'uikit-email-auth__magic-code-entry--error': errorMessage,
|
|
13
13
|
}"
|
|
14
|
-
:error="errorMessage"
|
|
14
|
+
:error="!!errorMessage"
|
|
15
15
|
:modelValue="modelValue"
|
|
16
|
-
@update:modelValue="emitUpdateModelValue"
|
|
16
|
+
@update:modelValue="emitUpdateModelValue"
|
|
17
17
|
@error="(err: string) => errorMessage = err"
|
|
18
18
|
@submit="submitSignIn"
|
|
19
19
|
/>
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
<Icon class="uikit-email-auth__error-message-icon" type="warning" />
|
|
22
22
|
<span>{{ errorMessage }}</span>
|
|
23
23
|
</div>
|
|
24
|
-
<
|
|
24
|
+
<PocketButton
|
|
25
25
|
class="uikit-email-auth__sign-in-btn"
|
|
26
26
|
:class="{
|
|
27
27
|
'uikit-email-auth__sign-in-btn--error': errorMessage,
|
|
@@ -32,94 +32,90 @@
|
|
|
32
32
|
@click="submitSignIn"
|
|
33
33
|
>
|
|
34
34
|
Sign In
|
|
35
|
-
</
|
|
36
|
-
<
|
|
35
|
+
</PocketButton>
|
|
36
|
+
<PocketButton
|
|
37
37
|
type="tertiary"
|
|
38
38
|
class="uikit-email-auth__resend-email-btn"
|
|
39
39
|
:disabled="isResending"
|
|
40
40
|
@click="resendEmail"
|
|
41
41
|
>
|
|
42
42
|
Resend Email
|
|
43
|
-
</
|
|
43
|
+
</PocketButton>
|
|
44
44
|
</div>
|
|
45
45
|
</template>
|
|
46
46
|
|
|
47
|
-
<script lang="ts">
|
|
48
|
-
import { Vue, Component, Prop, Watch, Emit } from 'vue-facing-decorator'
|
|
47
|
+
<script setup lang="ts">
|
|
49
48
|
import Icon from '../Icons/Icon.vue'
|
|
50
|
-
import
|
|
51
|
-
import Link from '../Buttons/Link.vue'
|
|
49
|
+
import PocketButton from '../Buttons/Button.vue'
|
|
52
50
|
import MagicCodeEntry from '../Onboarding/MagicCodeEntry.vue'
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (
|
|
83
|
-
|
|
51
|
+
import { ref, watch } from 'vue'
|
|
52
|
+
|
|
53
|
+
const {
|
|
54
|
+
parentError = '',
|
|
55
|
+
parentIsLoading = false,
|
|
56
|
+
email,
|
|
57
|
+
modelValue = '',
|
|
58
|
+
} = defineProps<{
|
|
59
|
+
parentError?: string
|
|
60
|
+
parentIsLoading?: boolean
|
|
61
|
+
email: string
|
|
62
|
+
modelValue?: string
|
|
63
|
+
}>()
|
|
64
|
+
|
|
65
|
+
const emit = defineEmits<{
|
|
66
|
+
'submit': [results: { email: string; code: string }]
|
|
67
|
+
'resend': [resendInfo: { email: string }]
|
|
68
|
+
'update:modelValue': [code: string]
|
|
69
|
+
}>()
|
|
70
|
+
|
|
71
|
+
const errorMessage = ref('')
|
|
72
|
+
const isLoading = ref(false)
|
|
73
|
+
const isResending = ref(false)
|
|
74
|
+
|
|
75
|
+
const submitSignIn = () => {
|
|
76
|
+
isLoading.value = true
|
|
77
|
+
errorMessage.value = ''
|
|
78
|
+
|
|
79
|
+
if (email && modelValue) {
|
|
80
|
+
if (modelValue.trim().length !== 6) {
|
|
81
|
+
errorMessage.value = 'Code must be six digits'
|
|
82
|
+
} else {
|
|
83
|
+
emitSubmit({ email, code: modelValue })
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
this.errorMessage = ''
|
|
87
|
+
isLoading.value = false
|
|
88
|
+
}
|
|
90
89
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
90
|
+
const resendEmail = () => {
|
|
91
|
+
errorMessage.value = ''
|
|
92
|
+
isResending.value = true
|
|
93
|
+
emitResend({ email })
|
|
94
|
+
isResending.value = false
|
|
95
|
+
}
|
|
98
96
|
|
|
99
|
-
|
|
97
|
+
watch(() => parentError, (newVal: string, oldVal: string) => {
|
|
98
|
+
if (newVal !== oldVal) {
|
|
99
|
+
errorMessage.value = newVal
|
|
100
100
|
}
|
|
101
|
+
})
|
|
101
102
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
this.emitResend({ email: this.email })
|
|
106
|
-
this.isResending = false
|
|
103
|
+
watch(() => parentIsLoading, (newVal: boolean, oldVal: boolean) => {
|
|
104
|
+
if (newVal !== oldVal) {
|
|
105
|
+
isLoading.value = newVal
|
|
107
106
|
}
|
|
107
|
+
})
|
|
108
108
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
109
|
+
const emitSubmit = (results: { email: string; code: string }) => {
|
|
110
|
+
emit('submit', results)
|
|
111
|
+
}
|
|
113
112
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
113
|
+
const emitResend = (resendInfo: { email: string }) => {
|
|
114
|
+
emit('resend', resendInfo)
|
|
115
|
+
}
|
|
118
116
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
return code
|
|
122
|
-
}
|
|
117
|
+
const emitUpdateModelValue = (code: string) => {
|
|
118
|
+
emit('update:modelValue', code)
|
|
123
119
|
}
|
|
124
120
|
</script>
|
|
125
121
|
|
|
@@ -220,4 +216,4 @@ export default class EmailAuth extends Vue {
|
|
|
220
216
|
}
|
|
221
217
|
}
|
|
222
218
|
}
|
|
223
|
-
</style>
|
|
219
|
+
</style>
|