@pocketprep/ui-kit 3.5.11 → 3.5.13
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 +2161 -2111
- 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/Controls/Slider.vue +67 -1
- package/lib/components/Icons/IconAdd.vue +3 -1
- package/lib/components/Modal/ModalContainer.vue +60 -35
- package/lib/components/SidePanels/SidePanel.vue +31 -2
- package/package.json +1 -1
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
<div
|
|
3
3
|
v-dark="isDarkMode"
|
|
4
4
|
class="uikit-slider"
|
|
5
|
-
:class="{
|
|
5
|
+
:class="{
|
|
6
|
+
[`uikit-slider--${size}`]: true,
|
|
7
|
+
'uikit-slider--disabled': disabled
|
|
8
|
+
}"
|
|
6
9
|
>
|
|
7
10
|
<div v-dark="isDarkMode" class="uikit-slider__number uikit-slider__min">
|
|
8
11
|
{{ min }}
|
|
@@ -11,6 +14,7 @@
|
|
|
11
14
|
<div
|
|
12
15
|
v-dark="isDarkMode"
|
|
13
16
|
class="uikit-slider__filled"
|
|
17
|
+
:class="{'uikit-slider__filled--disabled': disabled}"
|
|
14
18
|
:style="{ width: `${filledWidth}%` }"
|
|
15
19
|
/>
|
|
16
20
|
<input
|
|
@@ -24,7 +28,9 @@
|
|
|
24
28
|
:aria-valuemin="min"
|
|
25
29
|
:aria-valuemax="max"
|
|
26
30
|
:aria-valuenow="sliderValue"
|
|
31
|
+
:disabled="disabled"
|
|
27
32
|
class="uikit-slider__slide-input"
|
|
33
|
+
:class="{'uikit-slider__slide-input--disabled': disabled}"
|
|
28
34
|
>
|
|
29
35
|
</div>
|
|
30
36
|
<div v-dark="isDarkMode" class="uikit-slider__number uikit-slider__max">
|
|
@@ -50,6 +56,7 @@ export default class Slider extends Vue {
|
|
|
50
56
|
@Prop({ default: 'large' }) size!: 'small' | 'large'
|
|
51
57
|
@Prop({ default: false }) isDarkMode!: boolean
|
|
52
58
|
@Prop({ default: null }) inputId!: string | null
|
|
59
|
+
@Prop({ default: false }) disabled!: boolean
|
|
53
60
|
|
|
54
61
|
sliderValue = 0
|
|
55
62
|
|
|
@@ -339,6 +346,61 @@ export default class Slider extends Vue {
|
|
|
339
346
|
background-color: $brand-black;
|
|
340
347
|
}
|
|
341
348
|
}
|
|
349
|
+
|
|
350
|
+
&--disabled {
|
|
351
|
+
cursor: default;
|
|
352
|
+
|
|
353
|
+
&:hover {
|
|
354
|
+
&::-webkit-slider-thumb {
|
|
355
|
+
background: $white;
|
|
356
|
+
cursor: default;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
&::-moz-range-thumb {
|
|
360
|
+
background: $white;
|
|
361
|
+
cursor: default;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
&::-ms-thumb {
|
|
365
|
+
background: $white;
|
|
366
|
+
cursor: default;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
&::-webkit-slider-runnable-track {
|
|
371
|
+
background: $pearl;
|
|
372
|
+
cursor: default;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
&::-moz-range-track {
|
|
376
|
+
background: $pearl;
|
|
377
|
+
cursor: default;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
&::-webkit-slider-thumb {
|
|
381
|
+
border-color: $steel;
|
|
382
|
+
|
|
383
|
+
&:hover {
|
|
384
|
+
background: $white;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
&::-moz-range-thumb {
|
|
389
|
+
border-color: $steel;
|
|
390
|
+
|
|
391
|
+
&:hover {
|
|
392
|
+
background: $white;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
&::-ms-thumb {
|
|
397
|
+
border-color: $steel;
|
|
398
|
+
|
|
399
|
+
&:hover {
|
|
400
|
+
background: $white;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
342
404
|
}
|
|
343
405
|
|
|
344
406
|
&__filled {
|
|
@@ -349,6 +411,10 @@ export default class Slider extends Vue {
|
|
|
349
411
|
top: 13px;
|
|
350
412
|
border-radius: 3px;
|
|
351
413
|
|
|
414
|
+
&--disabled {
|
|
415
|
+
background: $steel;
|
|
416
|
+
}
|
|
417
|
+
|
|
352
418
|
&--dark {
|
|
353
419
|
background: $banana-bread;
|
|
354
420
|
}
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
</template>
|
|
34
34
|
|
|
35
35
|
<script lang="ts">
|
|
36
|
-
import { Vue, Component, Prop, Emit } from 'vue-facing-decorator'
|
|
36
|
+
import { Vue, Component, Prop, Emit, Watch } from 'vue-facing-decorator'
|
|
37
37
|
import Modal from '../Modal/Modal.vue'
|
|
38
38
|
import { dark } from '../../directives'
|
|
39
39
|
|
|
@@ -74,52 +74,53 @@ export default class ModalContainer extends Vue {
|
|
|
74
74
|
modalFocusableEls[modalFocusableEls.length - 1]?.blur()
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
this.
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const hasCalendarClass = target
|
|
77
|
+
|
|
78
|
+
this.focusListener = event => {
|
|
79
|
+
if (this.modalNumber === this.numberOfModals()) { // Only focus on the last open panel
|
|
80
|
+
const target = (event as FocusEvent).target as HTMLElement // The element receiving focus
|
|
81
|
+
const isFocusOutside = target && modalContainerEl && !modalContainerEl.contains(target)
|
|
82
|
+
const hasCalendarClass = target
|
|
84
83
|
&& Array.from(target.classList).find(
|
|
85
84
|
c => c === 'button-next-month' || c === 'button-previous-month' || c === 'day-item'
|
|
86
85
|
)
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
86
|
+
if (isFocusOutside && !hasCalendarClass) {
|
|
87
|
+
const focusableModalChildren = Array.from<HTMLElement>(modalContainerEl.querySelectorAll(
|
|
88
|
+
focusableSelectors
|
|
89
|
+
))
|
|
90
|
+
const firstFocusableModalChild = focusableModalChildren.find(
|
|
91
|
+
el => !!el.getBoundingClientRect().width
|
|
92
|
+
)
|
|
93
|
+
const reversedModalChildren = [ ...focusableModalChildren ].reverse()
|
|
94
|
+
const lastFocusableModalChild = reversedModalChildren.find(
|
|
95
|
+
el => !!el.getBoundingClientRect().width
|
|
96
|
+
)
|
|
97
|
+
if (firstFocusableModalChild) {
|
|
98
|
+
const relatedTarget = (event as FocusEvent).relatedTarget // The element last focused
|
|
99
|
+
if (relatedTarget === firstFocusableModalChild && lastFocusableModalChild) {
|
|
101
100
|
// If focus moves from first element -> outside modal, focus the last element instead
|
|
102
|
-
|
|
103
|
-
|
|
101
|
+
lastFocusableModalChild.focus()
|
|
102
|
+
} else if (relatedTarget === lastFocusableModalChild && firstFocusableModalChild) {
|
|
104
103
|
// If focus moves from last element -> outside modal, focus the first element instead
|
|
105
|
-
|
|
106
|
-
|
|
104
|
+
firstFocusableModalChild.focus()
|
|
105
|
+
} else if (relatedTarget && relatedTarget instanceof HTMLElement) {
|
|
107
106
|
// If focus goes outside in a different way, return focus to where it came from if possible
|
|
108
|
-
|
|
109
|
-
} else {
|
|
110
|
-
// Otherwise, just return focus to the first element
|
|
111
|
-
firstFocusableModalChild.focus()
|
|
112
|
-
}
|
|
107
|
+
relatedTarget.focus()
|
|
113
108
|
} else {
|
|
109
|
+
// Otherwise, just return focus to the first element
|
|
110
|
+
firstFocusableModalChild.focus()
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
114
113
|
// If the modal doesn't have any focusable children, focus the container instead
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
modalContainerEl.focus()
|
|
114
|
+
if (modalContainerEl.tabIndex === -1) {
|
|
115
|
+
modalContainerEl.tabIndex = 0
|
|
119
116
|
}
|
|
117
|
+
modalContainerEl.focus()
|
|
120
118
|
}
|
|
121
119
|
}
|
|
122
120
|
}
|
|
121
|
+
}
|
|
122
|
+
// Trap the user's focus within the modal - don't allow focusing elements behind the overlay
|
|
123
|
+
if (this.trapFocus) {
|
|
123
124
|
document.addEventListener('focusin', this.focusListener)
|
|
124
125
|
}
|
|
125
126
|
|
|
@@ -127,6 +128,8 @@ export default class ModalContainer extends Vue {
|
|
|
127
128
|
const openModalCount = Number(document.body.getAttribute('data-openModalCount'))
|
|
128
129
|
document.body.setAttribute('data-openModalCount', String(openModalCount + 1))
|
|
129
130
|
document.body.classList.add('uikit-modal-open')
|
|
131
|
+
|
|
132
|
+
this.emitMounted()
|
|
130
133
|
}
|
|
131
134
|
|
|
132
135
|
beforeUnmount () {
|
|
@@ -139,6 +142,7 @@ export default class ModalContainer extends Vue {
|
|
|
139
142
|
if (openModalCount <= 1) {
|
|
140
143
|
document.body.classList.remove('uikit-modal-open')
|
|
141
144
|
}
|
|
145
|
+
this.emitUnmounted()
|
|
142
146
|
}
|
|
143
147
|
|
|
144
148
|
keydownListener (e: Event | KeyboardEvent) {
|
|
@@ -159,6 +163,27 @@ export default class ModalContainer extends Vue {
|
|
|
159
163
|
emitClose () {
|
|
160
164
|
return true
|
|
161
165
|
}
|
|
166
|
+
|
|
167
|
+
@Emit('mounted')
|
|
168
|
+
emitMounted () {
|
|
169
|
+
return true
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
@Emit('unmounted')
|
|
173
|
+
emitUnmounted () {
|
|
174
|
+
return true
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
@Watch('trapFocus')
|
|
178
|
+
toggleTrapFocus () {
|
|
179
|
+
if (this.focusListener) {
|
|
180
|
+
if (this.trapFocus) {
|
|
181
|
+
document.addEventListener('focusin', this.focusListener)
|
|
182
|
+
} else {
|
|
183
|
+
document.removeEventListener('focusin', this.focusListener)
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
162
187
|
}
|
|
163
188
|
</script>
|
|
164
189
|
|
|
@@ -123,7 +123,7 @@
|
|
|
123
123
|
</template>
|
|
124
124
|
|
|
125
125
|
<script lang="ts">
|
|
126
|
-
import { Component, Vue, Prop, Emit } from 'vue-facing-decorator'
|
|
126
|
+
import { Component, Vue, Prop, Emit, Watch } from 'vue-facing-decorator'
|
|
127
127
|
import Button from '../Buttons/Button.vue'
|
|
128
128
|
import Icon from '../Icons/Icon.vue'
|
|
129
129
|
import { dark } from '../../directives'
|
|
@@ -151,6 +151,7 @@ export default class SidePanel extends Vue {
|
|
|
151
151
|
@Prop({ default: false }) isTeachSidePanel!: boolean
|
|
152
152
|
@Prop({ default: false }) isDarkMode!: boolean
|
|
153
153
|
@Prop({ default: true }) showCancelButton!: boolean
|
|
154
|
+
@Prop({ default: true }) trapFocus!: boolean
|
|
154
155
|
|
|
155
156
|
openSidePanel = false
|
|
156
157
|
notContentHeight = this.tabs?.length ? 262 : 218
|
|
@@ -227,12 +228,16 @@ export default class SidePanel extends Vue {
|
|
|
227
228
|
}
|
|
228
229
|
}
|
|
229
230
|
|
|
230
|
-
|
|
231
|
+
if (this.trapFocus) {
|
|
232
|
+
document.addEventListener('focusin', this.focusListener)
|
|
233
|
+
}
|
|
231
234
|
|
|
232
235
|
// prevent scrolling outside of modal
|
|
233
236
|
const openSidePanelCount = Number(document.body.getAttribute('data-openSidePanelCount'))
|
|
234
237
|
document.body.setAttribute('data-openSidePanelCount', String(openSidePanelCount + 1))
|
|
235
238
|
document.body.classList.add('uikit-sidepanel-open')
|
|
239
|
+
|
|
240
|
+
this.emitMounted()
|
|
236
241
|
}
|
|
237
242
|
|
|
238
243
|
beforeUnmount () {
|
|
@@ -246,6 +251,8 @@ export default class SidePanel extends Vue {
|
|
|
246
251
|
document.body.classList.remove('uikit-sidepanel-open')
|
|
247
252
|
document.body.scrollTo(0, 0)
|
|
248
253
|
}
|
|
254
|
+
|
|
255
|
+
this.emitUnmounted()
|
|
249
256
|
}
|
|
250
257
|
|
|
251
258
|
selectTab (e: MouseEvent | KeyboardEvent, tabName: string) {
|
|
@@ -288,6 +295,28 @@ export default class SidePanel extends Vue {
|
|
|
288
295
|
emitSelectTab (tabName: string) {
|
|
289
296
|
return tabName
|
|
290
297
|
}
|
|
298
|
+
|
|
299
|
+
@Emit('mounted')
|
|
300
|
+
emitMounted () {
|
|
301
|
+
return true
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
@Emit('unmounted')
|
|
305
|
+
emitUnmounted () {
|
|
306
|
+
return true
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
@Watch('trapFocus')
|
|
311
|
+
toggleTrapFocus () {
|
|
312
|
+
if (this.focusListener) {
|
|
313
|
+
if (this.trapFocus) {
|
|
314
|
+
document.addEventListener('focusin', this.focusListener)
|
|
315
|
+
} else {
|
|
316
|
+
document.removeEventListener('focusin', this.focusListener)
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
291
320
|
}
|
|
292
321
|
</script>
|
|
293
322
|
|