vuetify 2.4.4 → 2.4.5
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/json/attributes.json +7 -7
- package/dist/json/web-types.json +12 -12
- package/dist/vuetify.css +3 -0
- package/dist/vuetify.css.map +1 -1
- package/dist/vuetify.js +88 -34
- package/dist/vuetify.js.map +1 -1
- package/dist/vuetify.min.css +2 -2
- package/dist/vuetify.min.js +2 -2
- package/es5/components/VCalendar/VCalendarCategory.js +8 -6
- package/es5/components/VCalendar/VCalendarCategory.js.map +1 -1
- package/es5/components/VCombobox/VCombobox.js +7 -1
- package/es5/components/VCombobox/VCombobox.js.map +1 -1
- package/es5/components/VData/VData.js +1 -1
- package/es5/components/VData/VData.js.map +1 -1
- package/es5/components/VFileInput/VFileInput.js +1 -1
- package/es5/components/VFileInput/VFileInput.js.map +1 -1
- package/es5/components/VLazy/VLazy.js +3 -8
- package/es5/components/VLazy/VLazy.js.map +1 -1
- package/es5/components/VList/VListItem.js +1 -1
- package/es5/components/VList/VListItem.js.map +1 -1
- package/es5/components/VRating/VRating.js +0 -1
- package/es5/components/VRating/VRating.js.map +1 -1
- package/es5/components/VSelect/VSelect.js +19 -10
- package/es5/components/VSelect/VSelect.js.map +1 -1
- package/es5/components/VTextField/VTextField.js +8 -2
- package/es5/components/VTextField/VTextField.js.map +1 -1
- package/es5/framework.js +1 -1
- package/es5/locale/sk.js +1 -1
- package/es5/locale/sk.js.map +1 -1
- package/es5/services/theme/utils.js +10 -10
- package/es5/services/theme/utils.js.map +1 -1
- package/es5/util/dom.js +33 -0
- package/es5/util/dom.js.map +1 -0
- package/lib/components/VCalendar/VCalendarCategory.js +7 -5
- package/lib/components/VCalendar/VCalendarCategory.js.map +1 -1
- package/lib/components/VCombobox/VCombobox.js +6 -1
- package/lib/components/VCombobox/VCombobox.js.map +1 -1
- package/lib/components/VData/VData.js +1 -1
- package/lib/components/VData/VData.js.map +1 -1
- package/lib/components/VFileInput/VFileInput.js +1 -1
- package/lib/components/VFileInput/VFileInput.js.map +1 -1
- package/lib/components/VLazy/VLazy.js +3 -8
- package/lib/components/VLazy/VLazy.js.map +1 -1
- package/lib/components/VList/VListItem.js +1 -1
- package/lib/components/VList/VListItem.js.map +1 -1
- package/lib/components/VRating/VRating.js +0 -1
- package/lib/components/VRating/VRating.js.map +1 -1
- package/lib/components/VSelect/VSelect.js +9 -2
- package/lib/components/VSelect/VSelect.js.map +1 -1
- package/lib/components/VTextField/VTextField.js +7 -2
- package/lib/components/VTextField/VTextField.js.map +1 -1
- package/lib/framework.js +1 -1
- package/lib/locale/sk.js +1 -1
- package/lib/locale/sk.js.map +1 -1
- package/lib/util/dom.js +24 -0
- package/lib/util/dom.js.map +1 -0
- package/package.json +2 -2
- package/src/components/VAutocomplete/__tests__/VAutocomplete.spec.ts +3 -1
- package/src/components/VAutocomplete/__tests__/VAutocomplete2.spec.ts +3 -0
- package/src/components/VAutocomplete/__tests__/VAutocomplete3.spec.ts +1 -0
- package/src/components/VCalendar/VCalendarCategory.ts +7 -5
- package/src/components/VCombobox/VCombobox.ts +10 -0
- package/src/components/VCombobox/__tests__/VCombobox-multiple.spec.ts +1 -1
- package/src/components/VCombobox/__tests__/VCombobox.spec.ts +1 -0
- package/src/components/VData/VData.ts +1 -1
- package/src/components/VDataTable/VDataTableHeader.sass +2 -0
- package/src/components/VFileInput/VFileInput.ts +1 -1
- package/src/components/VLazy/VLazy.ts +6 -11
- package/src/components/VList/VListItem.ts +1 -1
- package/src/components/VList/__tests__/VListItem.spec.ts +1 -1
- package/src/components/VRating/VRating.ts +0 -1
- package/src/components/VSelect/VSelect.ts +13 -4
- package/src/components/VSelect/__tests__/VSelect.spec.ts +67 -0
- package/src/components/VSelect/__tests__/VSelect2.spec.ts +26 -0
- package/src/components/VSelect/__tests__/__snapshots__/VSelect2.spec.ts.snap +4 -4
- package/src/components/VTextField/VTextField.ts +9 -4
- package/src/components/VTextField/__tests__/VTextField.spec.ts +15 -4
- package/src/locale/sk.ts +1 -1
- package/src/util/__tests__/dom.spec.ts +42 -0
- package/src/util/dom.ts +24 -0
- package/types/services/icons.d.ts +2 -2
|
@@ -156,6 +156,7 @@ describe('VAutocomplete.ts', () => {
|
|
|
156
156
|
|
|
157
157
|
it('should not hide menu when no data but has no-data slot', async () => {
|
|
158
158
|
const wrapper = mountFunction({
|
|
159
|
+
attachToDocument: true,
|
|
159
160
|
propsData: {
|
|
160
161
|
combobox: true,
|
|
161
162
|
},
|
|
@@ -278,6 +279,7 @@ describe('VAutocomplete.ts', () => {
|
|
|
278
279
|
|
|
279
280
|
it('should not show menu when items are updated and hide-no-data is enabled', async () => {
|
|
280
281
|
const wrapper = mountFunction({
|
|
282
|
+
attachToDocument: true,
|
|
281
283
|
propsData: {
|
|
282
284
|
hideNoData: true,
|
|
283
285
|
items: ['Something first'],
|
|
@@ -373,6 +375,7 @@ describe('VAutocomplete.ts', () => {
|
|
|
373
375
|
// https://github.com/vuetifyjs/vuetify/issues/4580
|
|
374
376
|
it('should display menu when hide-no-date and hide-selected are enabled and selected item does not match search', async () => {
|
|
375
377
|
const wrapper = mountFunction({
|
|
378
|
+
attachToDocument: true,
|
|
376
379
|
propsData: {
|
|
377
380
|
items: [1, 2],
|
|
378
381
|
value: 1,
|
|
@@ -43,6 +43,7 @@ describe('VAutocomplete.ts', () => {
|
|
|
43
43
|
// https://github.com/vuetifyjs/vuetify/issues/7259
|
|
44
44
|
it('should update search when same item is selected', async () => {
|
|
45
45
|
const wrapper = mountFunction({
|
|
46
|
+
attachToDocument: true,
|
|
46
47
|
propsData: {
|
|
47
48
|
items: ['foo'],
|
|
48
49
|
value: 'foo',
|
|
@@ -71,11 +71,13 @@ export default VCalendarDaily.extend({
|
|
|
71
71
|
}, categoryName === null ? this.categoryForInvalid : categoryName)
|
|
72
72
|
},
|
|
73
73
|
genDays (): VNode[] {
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
74
|
+
const days: VNode[] = []
|
|
75
|
+
this.days.forEach(d => {
|
|
76
|
+
const day = new Array(this.parsedCategories.length)
|
|
77
|
+
day.fill(d)
|
|
78
|
+
days.push(...day.map((v, i) => this.genDay(v, 0, i)))
|
|
79
|
+
})
|
|
80
|
+
return days
|
|
79
81
|
},
|
|
80
82
|
genDay (day: CalendarTimestamp, index: number, categoryIndex: number): VNode {
|
|
81
83
|
const category = this.parsedCategories[categoryIndex]
|
|
@@ -154,6 +154,16 @@ export default VAutocomplete.extend({
|
|
|
154
154
|
this.updateEditing()
|
|
155
155
|
} else {
|
|
156
156
|
VAutocomplete.options.methods.selectItem.call(this, item)
|
|
157
|
+
|
|
158
|
+
// if selected item contains search value,
|
|
159
|
+
// remove the search string
|
|
160
|
+
if (
|
|
161
|
+
this.internalSearch &&
|
|
162
|
+
this.multiple &&
|
|
163
|
+
this.getText(item).toLocaleLowerCase().includes(this.internalSearch.toLocaleLowerCase())
|
|
164
|
+
) {
|
|
165
|
+
this.internalSearch = null
|
|
166
|
+
}
|
|
157
167
|
}
|
|
158
168
|
},
|
|
159
169
|
setSelectedItems () {
|
|
@@ -365,7 +365,7 @@ export default Vue.extend({
|
|
|
365
365
|
// Make sure we don't try to display non-existant page if items suddenly change
|
|
366
366
|
// TODO: Could possibly move this to pageStart/pageStop?
|
|
367
367
|
if (this.serverItemsLength === -1 && items.length <= this.pageStart) {
|
|
368
|
-
this.internalOptions.page = Math.max(1, this.internalOptions.
|
|
368
|
+
this.internalOptions.page = Math.max(1, Math.ceil(items.length / this.internalOptions.itemsPerPage))
|
|
369
369
|
}
|
|
370
370
|
|
|
371
371
|
return items.slice(this.pageStart, this.pageStop)
|
|
@@ -120,7 +120,7 @@ export default VTextField.extend({
|
|
|
120
120
|
return this.$attrs.hasOwnProperty('multiple')
|
|
121
121
|
},
|
|
122
122
|
text (): string[] {
|
|
123
|
-
if (!this.isDirty) return [this.placeholder]
|
|
123
|
+
if (!this.isDirty && (this.isFocused || !this.hasLabel)) return [this.placeholder]
|
|
124
124
|
|
|
125
125
|
return this.internalArrayValue.map((file: File) => {
|
|
126
126
|
const {
|
|
@@ -52,18 +52,13 @@ export default mixins(
|
|
|
52
52
|
|
|
53
53
|
methods: {
|
|
54
54
|
genContent () {
|
|
55
|
-
const
|
|
55
|
+
const children = this.isActive && getSlot(this)
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (this.isActive) children.push(slot)
|
|
63
|
-
|
|
64
|
-
return this.$createElement('transition', {
|
|
65
|
-
props: { name: this.transition },
|
|
66
|
-
}, children)
|
|
57
|
+
return this.transition
|
|
58
|
+
? this.$createElement('transition', {
|
|
59
|
+
props: { name: this.transition },
|
|
60
|
+
}, children)
|
|
61
|
+
: children
|
|
67
62
|
},
|
|
68
63
|
onObserve (
|
|
69
64
|
entries: IntersectionObserverEntry[],
|
|
@@ -139,7 +139,7 @@ export default baseMixins.extend<options>().extend({
|
|
|
139
139
|
} else if (this.isInNav) {
|
|
140
140
|
// do nothing, role is inherit
|
|
141
141
|
} else if (this.isInGroup) {
|
|
142
|
-
attrs.role = '
|
|
142
|
+
attrs.role = 'option'
|
|
143
143
|
attrs['aria-selected'] = String(this.isActive)
|
|
144
144
|
} else if (this.isInMenu) {
|
|
145
145
|
attrs.role = this.isClickable ? 'menuitem' : undefined
|
|
@@ -202,7 +202,7 @@ describe('VListItem.ts', () => {
|
|
|
202
202
|
const wrapper3 = mountFunction({
|
|
203
203
|
provide: { isInGroup: true },
|
|
204
204
|
})
|
|
205
|
-
expect(wrapper3.element.getAttribute('role')).toBe('
|
|
205
|
+
expect(wrapper3.element.getAttribute('role')).toBe('option')
|
|
206
206
|
|
|
207
207
|
// In menu
|
|
208
208
|
const wrapper4 = mountFunction({
|
|
@@ -224,7 +224,6 @@ export default mixins(
|
|
|
224
224
|
|
|
225
225
|
return this.$createElement(VIcon, this.setTextColor(this.getColor(props), {
|
|
226
226
|
attrs: {
|
|
227
|
-
tabindex: -1,
|
|
228
227
|
'aria-label': this.$vuetify.lang.t(this.iconLabel, i + 1, Number(this.length)),
|
|
229
228
|
},
|
|
230
229
|
directives: this.directives,
|
|
@@ -155,9 +155,15 @@ export default baseMixins.extend<options>().extend({
|
|
|
155
155
|
return `list-${this._uid}`
|
|
156
156
|
},
|
|
157
157
|
computedCounterValue (): number {
|
|
158
|
-
|
|
159
|
-
? this.selectedItems
|
|
160
|
-
: (this.getText(this.selectedItems[0]) || '').toString()
|
|
158
|
+
const value = this.multiple
|
|
159
|
+
? this.selectedItems
|
|
160
|
+
: (this.getText(this.selectedItems[0]) || '').toString()
|
|
161
|
+
|
|
162
|
+
if (typeof this.counterValue === 'function') {
|
|
163
|
+
return this.counterValue(value)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return value.length
|
|
161
167
|
},
|
|
162
168
|
directives (): VNodeDirective[] | undefined {
|
|
163
169
|
return this.isFocused ? [{
|
|
@@ -790,6 +796,9 @@ export default baseMixins.extend<options>().extend({
|
|
|
790
796
|
|
|
791
797
|
window.requestAnimationFrame(() => {
|
|
792
798
|
menu.getTiles()
|
|
799
|
+
|
|
800
|
+
if (!menu.hasClickableTiles) return this.activateMenu()
|
|
801
|
+
|
|
793
802
|
switch (keyCode) {
|
|
794
803
|
case keyCodes.up:
|
|
795
804
|
menu.prevTile()
|
|
@@ -804,7 +813,7 @@ export default baseMixins.extend<options>().extend({
|
|
|
804
813
|
menu.lastTile()
|
|
805
814
|
break
|
|
806
815
|
}
|
|
807
|
-
|
|
816
|
+
this.selectItem(this.allItems[this.getMenuIndex()])
|
|
808
817
|
})
|
|
809
818
|
},
|
|
810
819
|
selectItem (item: object) {
|
|
@@ -3,6 +3,7 @@ import Vue from 'vue'
|
|
|
3
3
|
|
|
4
4
|
// Components
|
|
5
5
|
import VSelect from '../VSelect'
|
|
6
|
+
import VDialog from '../../VDialog/VDialog'
|
|
6
7
|
import {
|
|
7
8
|
VListItem,
|
|
8
9
|
VListItemTitle,
|
|
@@ -14,6 +15,8 @@ import {
|
|
|
14
15
|
mount,
|
|
15
16
|
Wrapper,
|
|
16
17
|
} from '@vue/test-utils'
|
|
18
|
+
import { keyCodes } from '../../../util/helpers'
|
|
19
|
+
import { waitAnimationFrame } from '../../../../test'
|
|
17
20
|
|
|
18
21
|
// eslint-disable-next-line max-statements
|
|
19
22
|
describe('VSelect.ts', () => {
|
|
@@ -456,4 +459,68 @@ describe('VSelect.ts', () => {
|
|
|
456
459
|
|
|
457
460
|
expect(wrapper.vm.$attrs.autocomplete).toBe('on')
|
|
458
461
|
})
|
|
462
|
+
|
|
463
|
+
// Based on issue: https://github.com/vuetifyjs/vuetify/issues/12769
|
|
464
|
+
it('should cycle through selected items as per kep up & down without closing hosting menu dialog', async () => {
|
|
465
|
+
const items = ['Foo', 'Bar', 'Fizz', 'Buzz']
|
|
466
|
+
|
|
467
|
+
const dialogClickOutside = jest.fn()
|
|
468
|
+
|
|
469
|
+
const dialogWrapper = mount(VDialog, {
|
|
470
|
+
slots: {
|
|
471
|
+
default: {
|
|
472
|
+
render: h => h(VSelect, {
|
|
473
|
+
props: {
|
|
474
|
+
items,
|
|
475
|
+
},
|
|
476
|
+
}),
|
|
477
|
+
},
|
|
478
|
+
},
|
|
479
|
+
propsData: {
|
|
480
|
+
value: false,
|
|
481
|
+
fullscreen: true,
|
|
482
|
+
},
|
|
483
|
+
mocks: {
|
|
484
|
+
$vuetify: {
|
|
485
|
+
lang: {
|
|
486
|
+
t: (val: string) => val,
|
|
487
|
+
},
|
|
488
|
+
theme: {
|
|
489
|
+
dark: false,
|
|
490
|
+
},
|
|
491
|
+
breakpoint: {},
|
|
492
|
+
},
|
|
493
|
+
},
|
|
494
|
+
}) as Wrapper<InstanceType<typeof VDialog>>
|
|
495
|
+
|
|
496
|
+
dialogWrapper.vm.$on('click:outside', dialogClickOutside)
|
|
497
|
+
|
|
498
|
+
// Open dialog
|
|
499
|
+
dialogWrapper.setProps({ value: true })
|
|
500
|
+
await dialogWrapper.vm.$nextTick()
|
|
501
|
+
|
|
502
|
+
// Confirm Dialog is open
|
|
503
|
+
expect(dialogWrapper.vm.isActive).toBe(true)
|
|
504
|
+
|
|
505
|
+
const selectWrapper = dialogWrapper.find({ name: 'v-select' }) as Wrapper<Instance>
|
|
506
|
+
|
|
507
|
+
// Press key down twice to move selected item from null to Bar
|
|
508
|
+
const keyDownEvent = new KeyboardEvent('keydown', { keyCode: keyCodes.down })
|
|
509
|
+
selectWrapper.vm.onKeyDown(keyDownEvent)
|
|
510
|
+
await waitAnimationFrame()
|
|
511
|
+
selectWrapper.vm.onKeyDown(keyDownEvent)
|
|
512
|
+
await waitAnimationFrame()
|
|
513
|
+
expect(selectWrapper.vm.internalValue).toBe('Bar')
|
|
514
|
+
|
|
515
|
+
// Press key up once to move selected item from Bar to Foo
|
|
516
|
+
const keyUpEvent = new KeyboardEvent('keyup', { keyCode: keyCodes.up })
|
|
517
|
+
selectWrapper.vm.onKeyDown(keyUpEvent)
|
|
518
|
+
await waitAnimationFrame()
|
|
519
|
+
expect(selectWrapper.vm.internalValue).toBe('Foo')
|
|
520
|
+
|
|
521
|
+
// Confirm dialog click outside event has not been called
|
|
522
|
+
expect(dialogClickOutside).toHaveBeenCalledTimes(0)
|
|
523
|
+
// Confirm dialog is still open
|
|
524
|
+
expect(dialogWrapper.vm.isActive).toBe(true)
|
|
525
|
+
})
|
|
459
526
|
})
|
|
@@ -162,6 +162,32 @@ describe('VSelect.ts', () => {
|
|
|
162
162
|
expect(wrapper.vm.computedCounterValue).toBe(2)
|
|
163
163
|
})
|
|
164
164
|
|
|
165
|
+
it('should return the correct counter value', async () => {
|
|
166
|
+
const wrapper = mountFunction({
|
|
167
|
+
propsData: {
|
|
168
|
+
items: ['foo', 'bar'],
|
|
169
|
+
value: 'foo',
|
|
170
|
+
},
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
expect(wrapper.vm.computedCounterValue).toBe(3)
|
|
174
|
+
|
|
175
|
+
wrapper.setProps({
|
|
176
|
+
multiple: true,
|
|
177
|
+
value: ['foo'],
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
expect(wrapper.vm.computedCounterValue).toBe(1)
|
|
181
|
+
|
|
182
|
+
wrapper.setProps({
|
|
183
|
+
counterValue: (value?: string): number => 2,
|
|
184
|
+
multiple: false,
|
|
185
|
+
value: undefined,
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
expect(wrapper.vm.computedCounterValue).toBe(2)
|
|
189
|
+
})
|
|
190
|
+
|
|
165
191
|
it('should emit a single change event', async () => {
|
|
166
192
|
const wrapper = mountFunction({
|
|
167
193
|
attachToDocument: true,
|
|
@@ -6,7 +6,7 @@ exports[`VSelect.ts should be clearable with prop, dirty and multi select 1`] =
|
|
|
6
6
|
<div role="button"
|
|
7
7
|
aria-haspopup="listbox"
|
|
8
8
|
aria-expanded="false"
|
|
9
|
-
aria-owns="list-
|
|
9
|
+
aria-owns="list-106"
|
|
10
10
|
class="v-input__slot"
|
|
11
11
|
>
|
|
12
12
|
<div class="v-select__slot">
|
|
@@ -14,7 +14,7 @@ exports[`VSelect.ts should be clearable with prop, dirty and multi select 1`] =
|
|
|
14
14
|
<div class="v-select__selection v-select__selection--comma">
|
|
15
15
|
1
|
|
16
16
|
</div>
|
|
17
|
-
<input id="input-
|
|
17
|
+
<input id="input-106"
|
|
18
18
|
readonly="readonly"
|
|
19
19
|
type="text"
|
|
20
20
|
aria-readonly="false"
|
|
@@ -66,7 +66,7 @@ exports[`VSelect.ts should be clearable with prop, dirty and single select 1`] =
|
|
|
66
66
|
<div role="button"
|
|
67
67
|
aria-haspopup="listbox"
|
|
68
68
|
aria-expanded="false"
|
|
69
|
-
aria-owns="list-
|
|
69
|
+
aria-owns="list-99"
|
|
70
70
|
class="v-input__slot"
|
|
71
71
|
>
|
|
72
72
|
<div class="v-select__slot">
|
|
@@ -74,7 +74,7 @@ exports[`VSelect.ts should be clearable with prop, dirty and single select 1`] =
|
|
|
74
74
|
<div class="v-select__selection v-select__selection--comma">
|
|
75
75
|
1
|
|
76
76
|
</div>
|
|
77
|
-
<input id="input-
|
|
77
|
+
<input id="input-99"
|
|
78
78
|
readonly="readonly"
|
|
79
79
|
type="text"
|
|
80
80
|
aria-readonly="false"
|
|
@@ -18,6 +18,7 @@ import resize from '../../directives/resize'
|
|
|
18
18
|
import ripple from '../../directives/ripple'
|
|
19
19
|
|
|
20
20
|
// Utilities
|
|
21
|
+
import { attachedRoot } from '../../util/dom'
|
|
21
22
|
import { convertToUnit, keyCodes } from '../../util/helpers'
|
|
22
23
|
import { breaking, consoleWarn } from '../../util/console'
|
|
23
24
|
|
|
@@ -446,7 +447,10 @@ export default baseMixins.extend<options>().extend({
|
|
|
446
447
|
onFocus (e?: Event) {
|
|
447
448
|
if (!this.$refs.input) return
|
|
448
449
|
|
|
449
|
-
|
|
450
|
+
const root = attachedRoot(this.$el)
|
|
451
|
+
if (!root) return
|
|
452
|
+
|
|
453
|
+
if (root.activeElement !== this.$refs.input) {
|
|
450
454
|
return this.$refs.input.focus()
|
|
451
455
|
}
|
|
452
456
|
|
|
@@ -500,9 +504,10 @@ export default baseMixins.extend<options>().extend({
|
|
|
500
504
|
if (
|
|
501
505
|
!this.autofocus ||
|
|
502
506
|
typeof document === 'undefined' ||
|
|
503
|
-
!this.$refs.input
|
|
504
|
-
|
|
505
|
-
|
|
507
|
+
!this.$refs.input) return false
|
|
508
|
+
|
|
509
|
+
const root = attachedRoot(this.$el)
|
|
510
|
+
if (!root || root.activeElement === this.$refs.input) return false
|
|
506
511
|
|
|
507
512
|
this.$refs.input.focus()
|
|
508
513
|
|
|
@@ -96,7 +96,9 @@ describe('VTextField.ts', () => { // eslint-disable-line max-statements
|
|
|
96
96
|
})
|
|
97
97
|
|
|
98
98
|
it('should start validating on input', async () => {
|
|
99
|
-
const wrapper = mountFunction(
|
|
99
|
+
const wrapper = mountFunction({
|
|
100
|
+
attachToDocument: true,
|
|
101
|
+
})
|
|
100
102
|
|
|
101
103
|
expect(wrapper.vm.shouldValidate).toEqual(false)
|
|
102
104
|
wrapper.setProps({ value: 'asd' })
|
|
@@ -218,6 +220,7 @@ describe('VTextField.ts', () => { // eslint-disable-line max-statements
|
|
|
218
220
|
it('should start validating on blur', async () => {
|
|
219
221
|
const rule = jest.fn().mockReturnValue(true)
|
|
220
222
|
const wrapper = mountFunction({
|
|
223
|
+
attachToDocument: true,
|
|
221
224
|
propsData: {
|
|
222
225
|
rules: [rule],
|
|
223
226
|
validateOnBlur: true,
|
|
@@ -291,7 +294,9 @@ describe('VTextField.ts', () => { // eslint-disable-line max-statements
|
|
|
291
294
|
})
|
|
292
295
|
},
|
|
293
296
|
}
|
|
294
|
-
const wrapper = mount(component
|
|
297
|
+
const wrapper = mount(component, {
|
|
298
|
+
attachToDocument: true,
|
|
299
|
+
})
|
|
295
300
|
|
|
296
301
|
const input = wrapper.findAll('input').at(0)
|
|
297
302
|
|
|
@@ -640,7 +645,9 @@ describe('VTextField.ts', () => { // eslint-disable-line max-statements
|
|
|
640
645
|
})
|
|
641
646
|
|
|
642
647
|
it('should have focus and blur methods', async () => {
|
|
643
|
-
const wrapper = mountFunction(
|
|
648
|
+
const wrapper = mountFunction({
|
|
649
|
+
attachToDocument: true,
|
|
650
|
+
})
|
|
644
651
|
const onBlur = jest.spyOn(wrapper.vm.$refs.input, 'blur')
|
|
645
652
|
const onFocus = jest.spyOn(wrapper.vm.$refs.input, 'focus')
|
|
646
653
|
|
|
@@ -777,7 +784,9 @@ describe('VTextField.ts', () => { // eslint-disable-line max-statements
|
|
|
777
784
|
})
|
|
778
785
|
},
|
|
779
786
|
}
|
|
780
|
-
const wrapper = mount(component
|
|
787
|
+
const wrapper = mount(component, {
|
|
788
|
+
attachToDocument: true,
|
|
789
|
+
})
|
|
781
790
|
|
|
782
791
|
const inputElement = wrapper.findAll('input').at(0)
|
|
783
792
|
const clearIcon = wrapper.find('.v-input__icon--clear .v-icon')
|
|
@@ -812,6 +821,7 @@ describe('VTextField.ts', () => { // eslint-disable-line max-statements
|
|
|
812
821
|
|
|
813
822
|
it('should autofocus text-field when intersected', async () => {
|
|
814
823
|
const wrapper = mountFunction({
|
|
824
|
+
attachToDocument: true,
|
|
815
825
|
propsData: { autofocus: true },
|
|
816
826
|
})
|
|
817
827
|
const input = wrapper.find('input')
|
|
@@ -844,6 +854,7 @@ describe('VTextField.ts', () => { // eslint-disable-line max-statements
|
|
|
844
854
|
|
|
845
855
|
it('should use the correct icon color when using the solo inverted prop', () => {
|
|
846
856
|
const wrapper = mountFunction({
|
|
857
|
+
attachToDocument: true,
|
|
847
858
|
propsData: { soloInverted: true },
|
|
848
859
|
mocks: {
|
|
849
860
|
$vuetify: {
|
package/src/locale/sk.ts
CHANGED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import Vue from 'vue'
|
|
2
|
+
import {
|
|
3
|
+
mount,
|
|
4
|
+
} from '@vue/test-utils'
|
|
5
|
+
import {
|
|
6
|
+
attachedRoot,
|
|
7
|
+
} from '../dom'
|
|
8
|
+
|
|
9
|
+
const FooComponent = Vue.extend({
|
|
10
|
+
render (h) {
|
|
11
|
+
return h('div', ['foo'])
|
|
12
|
+
},
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
describe('dom', () => {
|
|
16
|
+
it('should properly detect an element\'s root', () => {
|
|
17
|
+
const shadowHost = document.createElement('div')
|
|
18
|
+
expect(attachedRoot(shadowHost)).toBeNull()
|
|
19
|
+
|
|
20
|
+
const shadowRoot = shadowHost.attachShadow({ mode: 'closed' })
|
|
21
|
+
expect(attachedRoot(shadowRoot)).toBeNull()
|
|
22
|
+
|
|
23
|
+
document.body.appendChild(shadowHost)
|
|
24
|
+
expect(attachedRoot(shadowHost)).toBe(document)
|
|
25
|
+
|
|
26
|
+
expect(attachedRoot(shadowRoot)).toBe(shadowRoot)
|
|
27
|
+
|
|
28
|
+
const insideDiv = document.createElement('div')
|
|
29
|
+
expect(attachedRoot(insideDiv)).toBeNull()
|
|
30
|
+
|
|
31
|
+
shadowRoot.appendChild(insideDiv)
|
|
32
|
+
expect(attachedRoot(insideDiv)).toBe(shadowRoot)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('should detect the root of mounted components', () => {
|
|
36
|
+
const attachedWrapper = mount(FooComponent, { attachToDocument: true })
|
|
37
|
+
expect(attachedRoot(attachedWrapper.element)).toBe(document)
|
|
38
|
+
|
|
39
|
+
const detachedWrapper = mount(FooComponent, { attachToDocument: false })
|
|
40
|
+
expect(attachedRoot(detachedWrapper.element)).toBeNull()
|
|
41
|
+
})
|
|
42
|
+
})
|
package/src/util/dom.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns:
|
|
3
|
+
* - 'null' if the node is not attached to the DOM
|
|
4
|
+
* - the root node (HTMLDocument | ShadowRoot) otherwise
|
|
5
|
+
*/
|
|
6
|
+
export function attachedRoot (node: Node): null | HTMLDocument | ShadowRoot {
|
|
7
|
+
/* istanbul ignore next */
|
|
8
|
+
if (typeof node.getRootNode !== 'function') {
|
|
9
|
+
// Shadow DOM not supported (IE11), lets find the root of this node
|
|
10
|
+
while (node.parentNode) node = node.parentNode
|
|
11
|
+
|
|
12
|
+
// The root parent is the document if the node is attached to the DOM
|
|
13
|
+
if (node !== document) return null
|
|
14
|
+
|
|
15
|
+
return document
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const root = node.getRootNode()
|
|
19
|
+
|
|
20
|
+
// The composed root node is the document if the node is attached to the DOM
|
|
21
|
+
if (root !== document && root.getRootNode({ composed: true }) !== document) return null
|
|
22
|
+
|
|
23
|
+
return root as HTMLDocument | ShadowRoot
|
|
24
|
+
}
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import { Component } from 'vue'
|
|
3
3
|
|
|
4
4
|
export interface Icons extends IconsOptions {
|
|
5
|
-
component?: Component | string
|
|
6
5
|
iconfont: Iconfont
|
|
7
6
|
values: VuetifyIcons
|
|
8
7
|
}
|
|
@@ -10,13 +9,14 @@ export interface Icons extends IconsOptions {
|
|
|
10
9
|
export type Iconfont = 'mdi' | 'mdiSvg' | 'md' | 'fa' | 'faSvg' | 'fa4'
|
|
11
10
|
|
|
12
11
|
export interface IconsOptions {
|
|
12
|
+
component?: Component | string
|
|
13
13
|
/**
|
|
14
14
|
* Select a base icon font to use. Note that none of these are included, you must install them yourself
|
|
15
15
|
*
|
|
16
16
|
* md: <a href="https://material.io/icons">material.io</a> (default)
|
|
17
17
|
* mdi: <a href="https://materialdesignicons.com">MDI</a>
|
|
18
18
|
* fa: <a href="https://fontawesome.com/get-started/web-fonts-with-css">FontAwesome 5</a>
|
|
19
|
-
* fa4: <a href="">FontAwesome 4</a>
|
|
19
|
+
* fa4: <a href="https://fontawesome.com/v4.7.0/">FontAwesome 4</a>
|
|
20
20
|
* faSvg: <a href="https://fontawesome.com/how-to-use/on-the-web/using-with/vuejs">FontAwesome SVG</a>
|
|
21
21
|
*/
|
|
22
22
|
iconfont?: Iconfont
|