@dimailn/vuetify 2.7.2-alpha20 → 2.7.2-alpha22
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/vuetify.js +214 -84
- package/dist/vuetify.js.map +1 -1
- package/dist/vuetify.min.css +1 -1
- package/dist/vuetify.min.js +2 -2
- package/es5/components/VOverlay/VOverlay.js +2 -3
- package/es5/components/VOverlay/VOverlay.js.map +1 -1
- package/es5/components/VProgressCircular/VProgressCircular.js +5 -3
- package/es5/components/VProgressCircular/VProgressCircular.js.map +1 -1
- package/es5/components/VProgressLinear/VProgressLinear.js +41 -19
- package/es5/components/VProgressLinear/VProgressLinear.js.map +1 -1
- package/es5/components/VTabs/VTabs.js +1 -1
- package/es5/components/VTabs/VTabs.js.map +1 -1
- package/es5/components/VTabs/VTabsBar.js.map +1 -1
- package/es5/components/VVirtualScroll/VVirtualScroll.js +15 -16
- package/es5/components/VVirtualScroll/VVirtualScroll.js.map +1 -1
- package/es5/components/VWindow/VWindow.js +13 -5
- package/es5/components/VWindow/VWindow.js.map +1 -1
- package/es5/components/VWindow/VWindowItem.js +9 -5
- package/es5/components/VWindow/VWindowItem.js.map +1 -1
- package/es5/framework.js +1 -1
- package/es5/install.js +10 -33
- package/es5/install.js.map +1 -1
- package/es5/mixins/detachable/index.js +2 -3
- package/es5/mixins/detachable/index.js.map +1 -1
- package/es5/mixins/overlayable/index.js.map +1 -1
- package/es5/util/helpers.js +44 -0
- package/es5/util/helpers.js.map +1 -1
- package/es5/util/legacyEventsMixin.js +48 -0
- package/es5/util/legacyEventsMixin.js.map +1 -0
- package/lib/components/VOverlay/VOverlay.js +1 -2
- package/lib/components/VOverlay/VOverlay.js.map +1 -1
- package/lib/components/VProgressCircular/VProgressCircular.js +5 -3
- package/lib/components/VProgressCircular/VProgressCircular.js.map +1 -1
- package/lib/components/VProgressLinear/VProgressLinear.js +35 -17
- package/lib/components/VProgressLinear/VProgressLinear.js.map +1 -1
- package/lib/components/VTabs/VTabs.js +1 -1
- package/lib/components/VTabs/VTabs.js.map +1 -1
- package/lib/components/VTabs/VTabsBar.js.map +1 -1
- package/lib/components/VVirtualScroll/VVirtualScroll.js +8 -11
- package/lib/components/VVirtualScroll/VVirtualScroll.js.map +1 -1
- package/lib/components/VWindow/VWindow.js +7 -3
- package/lib/components/VWindow/VWindow.js.map +1 -1
- package/lib/components/VWindow/VWindowItem.js +3 -1
- package/lib/components/VWindow/VWindowItem.js.map +1 -1
- package/lib/framework.js +1 -1
- package/lib/install.js +5 -28
- package/lib/install.js.map +1 -1
- package/lib/mixins/detachable/index.js +3 -4
- package/lib/mixins/detachable/index.js.map +1 -1
- package/lib/mixins/overlayable/index.js.map +1 -1
- package/lib/util/helpers.js +42 -0
- package/lib/util/helpers.js.map +1 -1
- package/lib/util/legacyEventsMixin.js +37 -0
- package/lib/util/legacyEventsMixin.js.map +1 -0
- package/package.json +1 -1
- package/src/components/VAvatar/__tests__/VAvatar.spec.ts +72 -10
- package/src/components/VOverlay/VOverlay.ts +1 -1
- package/src/components/VOverlay/__tests__/VOverlay.spec.ts +6 -6
- package/src/components/VProgressCircular/VProgressCircular.ts +6 -5
- package/src/components/VProgressCircular/__tests__/VProgressCircular.spec.ts +28 -21
- package/src/components/VProgressCircular/__tests__/__snapshots__/VProgressCircular.spec.ts.snap +62 -62
- package/src/components/VProgressLinear/VProgressLinear.ts +42 -22
- package/src/components/VProgressLinear/__tests__/VProgressLinear.spec.ts +378 -71
- package/src/components/VProgressLinear/__tests__/__snapshots__/VProgressLinear.spec.ts.snap +53 -79
- package/src/components/VSheet/__tests__/VSheet.spec.ts +5 -5
- package/src/components/VTabs/VTabs.ts +1 -1
- package/src/components/VTabs/VTabsBar.ts +7 -5
- package/src/components/VTabs/__tests__/VTab.spec.ts +48 -37
- package/src/components/VTabs/__tests__/VTabs.spec.ts +134 -79
- package/src/components/VTabs/__tests__/VTabsBar.spec.ts +67 -26
- package/src/components/VTabs/__tests__/VTabsSlider.spec.ts +7 -6
- package/src/components/VTabs/__tests__/__snapshots__/VTabs.spec.ts.snap +1 -3
- package/src/components/VVirtualScroll/VVirtualScroll.ts +14 -13
- package/src/components/VVirtualScroll/__tests__/VVirtualScroll.spec.ts +26 -19
- package/src/components/VWindow/VWindow.ts +9 -5
- package/src/components/VWindow/VWindowItem.ts +3 -1
- package/src/components/VWindow/__tests__/VWindow.spec.ts +226 -185
- package/src/components/VWindow/__tests__/VWindowItem.spec.ts +162 -132
- package/src/install.ts +10 -32
- package/src/mixins/applicationable/__tests__/applicationable.spec.ts +31 -27
- package/src/mixins/colorable/__tests__/colorable.spec.ts +9 -6
- package/src/mixins/detachable/index.ts +2 -1
- package/src/mixins/elevatable/__tests__/elevatable.spec.ts +14 -13
- package/src/mixins/intersectable/__tests__/intersectable.spec.ts +35 -29
- package/src/mixins/menuable/__tests__/menuable.spec.ts +76 -33
- package/src/mixins/mobile/__tests__/mobile.spec.ts +9 -6
- package/src/mixins/overlayable/__tests__/overlayable.spec.ts +32 -24
- package/src/mixins/overlayable/index.ts +1 -1
- package/src/mixins/proxyable/__tests__/proxyable.spec.ts +18 -17
- package/src/mixins/registrable/__tests__/registrable.spec.ts +31 -0
- package/src/mixins/rippleable/__tests__/rippleable.spec.ts +10 -9
- package/src/mixins/roundable/__tests__/roundable.spec.ts +7 -5
- package/src/mixins/routable/__tests__/routable.spec.ts +60 -52
- package/src/mixins/scrollable/__tests__/scrollable.spec.ts +56 -27
- package/src/mixins/selectable/__tests__/selectable.spec.ts +22 -9
- package/src/util/__tests__/helpers.spec.ts +62 -1
- package/src/util/helpers.ts +42 -1
- package/src/util/legacyEventsMixin.ts +34 -0
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import Routable from '../'
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import
|
|
2
|
+
import { mount, Wrapper } from '@vue/test-utils'
|
|
3
|
+
import { createRouter, createWebHistory } from 'vue-router'
|
|
4
|
+
import { nextTick } from 'vue'
|
|
5
5
|
|
|
6
6
|
describe('routable.ts', () => {
|
|
7
|
-
let mountFunction: (options?: object) => Wrapper<
|
|
8
|
-
let router:
|
|
9
|
-
let localVue: typeof Vue
|
|
7
|
+
let mountFunction: (options?: object) => Wrapper<any>
|
|
8
|
+
let router: any
|
|
10
9
|
|
|
11
10
|
beforeEach(() => {
|
|
12
|
-
router =
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
router = createRouter({
|
|
12
|
+
history: createWebHistory(),
|
|
13
|
+
routes: [
|
|
14
|
+
{ path: '/', component: { template: '<div>Home</div>' } },
|
|
15
|
+
{ path: '/foo', component: { template: '<div>Foo</div>' } },
|
|
16
|
+
],
|
|
17
|
+
})
|
|
15
18
|
|
|
16
19
|
mountFunction = (options = {}) => {
|
|
17
20
|
return mount({
|
|
@@ -24,74 +27,79 @@ describe('routable.ts', () => {
|
|
|
24
27
|
default: 'exact-active',
|
|
25
28
|
},
|
|
26
29
|
},
|
|
27
|
-
|
|
28
|
-
const { tag, data, directives } = this.generateRouteLink()
|
|
29
|
-
|
|
30
|
-
data.attrs = {
|
|
31
|
-
...data.attrs,
|
|
32
|
-
}
|
|
33
|
-
data.on = {
|
|
34
|
-
...data.on,
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return withDirectives(
|
|
38
|
-
h(tag, data, this.$slots.default),
|
|
39
|
-
directives
|
|
40
|
-
)
|
|
41
|
-
},
|
|
30
|
+
template: '<div ref="link" :class="classes"></div>',
|
|
42
31
|
}, {
|
|
43
|
-
|
|
44
|
-
|
|
32
|
+
global: {
|
|
33
|
+
plugins: [router],
|
|
34
|
+
},
|
|
45
35
|
...options,
|
|
46
36
|
})
|
|
47
37
|
}
|
|
48
38
|
})
|
|
49
|
-
|
|
39
|
+
|
|
40
|
+
it('should have correct computed properties', async () => {
|
|
50
41
|
const wrapper = mountFunction({
|
|
51
|
-
|
|
42
|
+
props: {
|
|
52
43
|
to: '/',
|
|
53
44
|
},
|
|
54
45
|
})
|
|
55
46
|
|
|
56
|
-
expect(wrapper.vm.
|
|
47
|
+
expect(wrapper.vm.isLink).toBeTruthy() // isLink returns the 'to' value, which is truthy
|
|
48
|
+
expect(wrapper.vm.isClickable).toBe(true)
|
|
57
49
|
})
|
|
58
50
|
|
|
59
|
-
it('should
|
|
51
|
+
it('should have correct classes computed property', async () => {
|
|
60
52
|
const wrapper = mountFunction({
|
|
61
|
-
|
|
53
|
+
props: {
|
|
62
54
|
to: '/',
|
|
55
|
+
activeClass: 'custom-active',
|
|
63
56
|
},
|
|
64
57
|
})
|
|
65
|
-
await wrapper.vm.$nextTick()
|
|
66
|
-
expect(wrapper.vm.isActive).toBe(true)
|
|
67
58
|
|
|
68
|
-
|
|
69
|
-
|
|
59
|
+
expect(wrapper.vm.classes).toBeDefined()
|
|
60
|
+
})
|
|
70
61
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
62
|
+
it('should handle disabled state', async () => {
|
|
63
|
+
const wrapper = mountFunction({
|
|
64
|
+
props: {
|
|
65
|
+
to: '/',
|
|
66
|
+
disabled: true,
|
|
67
|
+
},
|
|
68
|
+
})
|
|
74
69
|
|
|
75
|
-
wrapper.vm
|
|
76
|
-
await wrapper.vm.$nextTick()
|
|
77
|
-
await wrapper.vm.$nextTick()
|
|
78
|
-
expect(wrapper.vm.isActive).toBe(true)
|
|
70
|
+
expect(wrapper.vm.isClickable).toBe(false)
|
|
79
71
|
})
|
|
80
72
|
|
|
81
|
-
it('should
|
|
73
|
+
it('should handle notALink prop', async () => {
|
|
82
74
|
const wrapper = mountFunction({
|
|
83
|
-
|
|
84
|
-
to: '/
|
|
75
|
+
props: {
|
|
76
|
+
to: '/',
|
|
77
|
+
notALink: true,
|
|
85
78
|
},
|
|
86
79
|
})
|
|
87
|
-
await wrapper.vm.$nextTick()
|
|
88
|
-
expect(wrapper.vm.isActive).toBe(false)
|
|
89
80
|
|
|
90
|
-
|
|
91
|
-
|
|
81
|
+
expect(wrapper.vm.isClickable).toBe(false)
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it('should handle href prop', async () => {
|
|
85
|
+
const wrapper = mountFunction({
|
|
86
|
+
props: {
|
|
87
|
+
href: 'https://example.com',
|
|
88
|
+
},
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
expect(wrapper.vm.isLink).toBe('https://example.com')
|
|
92
|
+
expect(wrapper.vm.isClickable).toBe(true)
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
it('should handle link prop', async () => {
|
|
96
|
+
const wrapper = mountFunction({
|
|
97
|
+
props: {
|
|
98
|
+
link: true,
|
|
99
|
+
},
|
|
100
|
+
})
|
|
92
101
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
expect(wrapper.vm.isActive).toBe(true)
|
|
102
|
+
expect(wrapper.vm.isLink).toBe(true)
|
|
103
|
+
expect(wrapper.vm.isClickable).toBe(true)
|
|
96
104
|
})
|
|
97
105
|
})
|
|
@@ -2,28 +2,28 @@
|
|
|
2
2
|
import Scrollable from '../'
|
|
3
3
|
|
|
4
4
|
// Utilities
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
Wrapper,
|
|
8
|
-
} from '@vue/test-utils'
|
|
5
|
+
import { mount, VueWrapper } from '@vue/test-utils'
|
|
6
|
+
import { defineComponent, h } from 'vue'
|
|
9
7
|
import { scrollWindow } from '../../../../test'
|
|
10
8
|
|
|
11
9
|
describe('Scrollable.ts', () => {
|
|
12
|
-
type Instance = InstanceType<typeof Scrollable
|
|
13
|
-
let mountFunction: (options?: object) =>
|
|
10
|
+
type Instance = InstanceType<typeof Scrollable>;
|
|
11
|
+
let mountFunction: (options?: object) => VueWrapper<Instance>
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
const createMockComponent = (options = {}) => {
|
|
14
|
+
return defineComponent({
|
|
17
15
|
mixins: [Scrollable],
|
|
18
|
-
|
|
16
|
+
...options,
|
|
17
|
+
render () {
|
|
19
18
|
return h('div', {
|
|
20
|
-
|
|
21
|
-
name: 'scroll',
|
|
22
|
-
value: this.onScroll,
|
|
23
|
-
}],
|
|
19
|
+
onScroll: this.onScroll,
|
|
24
20
|
})
|
|
25
21
|
},
|
|
26
|
-
}
|
|
22
|
+
})
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
const Mock = createMockComponent()
|
|
27
27
|
mountFunction = (options = {}) => {
|
|
28
28
|
return mount(Mock, {
|
|
29
29
|
...options,
|
|
@@ -34,15 +34,22 @@ describe('Scrollable.ts', () => {
|
|
|
34
34
|
it('should set isScrollingUp', async () => {
|
|
35
35
|
const wrapper = mountFunction()
|
|
36
36
|
|
|
37
|
+
// Сначала скроллим вниз
|
|
37
38
|
await scrollWindow(1000)
|
|
39
|
+
wrapper.vm.onScroll()
|
|
40
|
+
await wrapper.vm.$nextTick()
|
|
38
41
|
expect(wrapper.vm.isScrollingUp).toBe(false)
|
|
42
|
+
|
|
43
|
+
// Затем скроллим вверх
|
|
39
44
|
await scrollWindow(0)
|
|
45
|
+
wrapper.vm.onScroll()
|
|
46
|
+
await wrapper.vm.$nextTick()
|
|
40
47
|
expect(wrapper.vm.isScrollingUp).toBe(true)
|
|
41
48
|
})
|
|
42
49
|
|
|
43
50
|
it('should set a custom target', async () => {
|
|
44
51
|
const wrapper = mountFunction({
|
|
45
|
-
|
|
52
|
+
props: {
|
|
46
53
|
scrollTarget: 'body',
|
|
47
54
|
},
|
|
48
55
|
})
|
|
@@ -53,10 +60,12 @@ describe('Scrollable.ts', () => {
|
|
|
53
60
|
|
|
54
61
|
it('should do nothing if !canScroll', async () => {
|
|
55
62
|
const wrapper = mountFunction({
|
|
56
|
-
data
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
63
|
+
data () {
|
|
64
|
+
return {
|
|
65
|
+
currentScroll: 100,
|
|
66
|
+
previousScroll: 0,
|
|
67
|
+
}
|
|
68
|
+
},
|
|
60
69
|
computed: {
|
|
61
70
|
canScroll () {
|
|
62
71
|
return false
|
|
@@ -65,6 +74,7 @@ describe('Scrollable.ts', () => {
|
|
|
65
74
|
})
|
|
66
75
|
|
|
67
76
|
await scrollWindow(1000)
|
|
77
|
+
wrapper.vm.onScroll()
|
|
68
78
|
|
|
69
79
|
expect(wrapper.vm.currentScroll).toBe(100)
|
|
70
80
|
expect(wrapper.vm.previousScroll).toBe(0)
|
|
@@ -72,40 +82,59 @@ describe('Scrollable.ts', () => {
|
|
|
72
82
|
|
|
73
83
|
it('should accept a custom scrollThreshold', async () => {
|
|
74
84
|
const thresholdMet = jest.fn()
|
|
75
|
-
|
|
85
|
+
|
|
86
|
+
// Создаем специальный компонент с методом thresholdMet
|
|
87
|
+
const MockWithThreshold = createMockComponent({
|
|
88
|
+
props: {
|
|
89
|
+
scrollThreshold: {
|
|
90
|
+
type: Number,
|
|
91
|
+
default: 300,
|
|
92
|
+
},
|
|
93
|
+
},
|
|
76
94
|
methods: {
|
|
77
95
|
thresholdMet,
|
|
78
96
|
},
|
|
79
|
-
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
const wrapper = mount(MockWithThreshold, {
|
|
100
|
+
props: {
|
|
80
101
|
scrollThreshold: 1000,
|
|
81
102
|
},
|
|
82
103
|
})
|
|
83
104
|
|
|
105
|
+
// Скроллим меньше порога
|
|
84
106
|
await scrollWindow(900)
|
|
107
|
+
wrapper.vm.onScroll()
|
|
85
108
|
await wrapper.vm.$nextTick()
|
|
86
109
|
|
|
87
110
|
expect(thresholdMet).not.toHaveBeenCalled()
|
|
88
111
|
|
|
112
|
+
// Скроллим больше порога
|
|
89
113
|
await scrollWindow(1001)
|
|
114
|
+
wrapper.vm.onScroll()
|
|
90
115
|
await wrapper.vm.$nextTick()
|
|
91
116
|
expect(thresholdMet).toHaveBeenCalled()
|
|
92
117
|
})
|
|
93
118
|
|
|
94
|
-
it('should reset savedScroll when isActive state changes', () => {
|
|
119
|
+
it('should reset savedScroll when isActive state changes', async () => {
|
|
95
120
|
const wrapper = mountFunction({
|
|
96
|
-
data
|
|
97
|
-
|
|
98
|
-
|
|
121
|
+
data () {
|
|
122
|
+
return {
|
|
123
|
+
savedScroll: 100,
|
|
124
|
+
}
|
|
125
|
+
},
|
|
99
126
|
})
|
|
100
127
|
|
|
101
|
-
|
|
128
|
+
// В Vue 3 используем прямое изменение данных
|
|
129
|
+
wrapper.vm.isActive = true
|
|
130
|
+
await wrapper.vm.$nextTick()
|
|
102
131
|
|
|
103
132
|
expect(wrapper.vm.savedScroll).toBe(0)
|
|
104
133
|
})
|
|
105
134
|
|
|
106
135
|
it(`should warn if target isn't present`, async () => {
|
|
107
136
|
mountFunction({
|
|
108
|
-
|
|
137
|
+
props: {
|
|
109
138
|
scrollTarget: '#test',
|
|
110
139
|
},
|
|
111
140
|
})
|
|
@@ -4,17 +4,22 @@ import Selectable from '../index'
|
|
|
4
4
|
// Utilities
|
|
5
5
|
import {
|
|
6
6
|
mount,
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
VueWrapper,
|
|
8
|
+
MountingOptions,
|
|
9
|
+
enableAutoUnmount,
|
|
9
10
|
} from '@vue/test-utils'
|
|
11
|
+
import { ComponentPublicInstance, h, defineComponent } from 'vue'
|
|
10
12
|
|
|
11
13
|
describe('Selectable.ts', () => {
|
|
12
|
-
const Mock =
|
|
13
|
-
|
|
14
|
+
const Mock = defineComponent({
|
|
15
|
+
mixins: [Selectable],
|
|
16
|
+
render: () => h('div'),
|
|
14
17
|
})
|
|
15
18
|
|
|
16
|
-
type Instance = InstanceType<typeof Mock>
|
|
17
|
-
let mountFunction: (options?:
|
|
19
|
+
type Instance = ComponentPublicInstance & InstanceType<typeof Mock>
|
|
20
|
+
let mountFunction: (options?: MountingOptions<Instance>) => VueWrapper<Instance>
|
|
21
|
+
|
|
22
|
+
enableAutoUnmount(afterEach)
|
|
18
23
|
|
|
19
24
|
beforeEach(() => {
|
|
20
25
|
mountFunction = (options = {}) => {
|
|
@@ -30,11 +35,19 @@ describe('Selectable.ts', () => {
|
|
|
30
35
|
expect(wrapper.vm.lazyValue).toBeUndefined()
|
|
31
36
|
expect(wrapper.vm.hasColor).toBeUndefined()
|
|
32
37
|
|
|
33
|
-
wrapper.setProps({
|
|
34
|
-
|
|
35
|
-
await wrapper.vm.$nextTick()
|
|
38
|
+
await wrapper.setProps({ modelValue: true })
|
|
36
39
|
|
|
37
40
|
expect(wrapper.vm.lazyValue).toBe(true)
|
|
38
41
|
expect(wrapper.vm.hasColor).toBe(true)
|
|
39
42
|
})
|
|
43
|
+
|
|
44
|
+
it('should handle disabled state', async () => {
|
|
45
|
+
const wrapper = mountFunction({
|
|
46
|
+
props: {
|
|
47
|
+
disabled: true,
|
|
48
|
+
},
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
expect(wrapper.vm.rippleState).toBeUndefined()
|
|
52
|
+
})
|
|
40
53
|
})
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import Vue from 'vue/dist/vue.common.js'
|
|
2
1
|
import {
|
|
3
2
|
deepEqual,
|
|
4
3
|
getNestedValue,
|
|
@@ -10,6 +9,7 @@ import {
|
|
|
10
9
|
humanReadableFileSize,
|
|
11
10
|
sortItems,
|
|
12
11
|
createSimpleFunctional,
|
|
12
|
+
normalizeClasses,
|
|
13
13
|
} from '../helpers'
|
|
14
14
|
import { mount } from '@vue/test-utils'
|
|
15
15
|
|
|
@@ -379,3 +379,64 @@ describe('helpers', () => {
|
|
|
379
379
|
expect(items).toStrictEqual([{ string: 'bar', number: 3 }, { string: 'baz', number: 2 }, { string: 'baz', number: 1 }, { string: 'foo', number: 1 }])
|
|
380
380
|
})
|
|
381
381
|
})
|
|
382
|
+
|
|
383
|
+
describe('normalizeClasses', () => {
|
|
384
|
+
it('should return empty object for undefined input', () => {
|
|
385
|
+
expect(normalizeClasses(undefined)).toEqual({})
|
|
386
|
+
})
|
|
387
|
+
|
|
388
|
+
it('should return empty object for null input', () => {
|
|
389
|
+
expect(normalizeClasses(null as any)).toEqual({})
|
|
390
|
+
})
|
|
391
|
+
|
|
392
|
+
it('should normalize string classes', () => {
|
|
393
|
+
expect(normalizeClasses('class1 class2 class3')).toEqual({
|
|
394
|
+
class1: true,
|
|
395
|
+
class2: true,
|
|
396
|
+
class3: true
|
|
397
|
+
})
|
|
398
|
+
})
|
|
399
|
+
|
|
400
|
+
it('should handle string with extra spaces', () => {
|
|
401
|
+
expect(normalizeClasses(' class1 class2 ')).toEqual({
|
|
402
|
+
class1: true,
|
|
403
|
+
class2: true
|
|
404
|
+
})
|
|
405
|
+
})
|
|
406
|
+
|
|
407
|
+
it('should return object as is', () => {
|
|
408
|
+
const classes = { class1: true, class2: false }
|
|
409
|
+
expect(normalizeClasses(classes)).toBe(classes)
|
|
410
|
+
})
|
|
411
|
+
|
|
412
|
+
it('should normalize array of strings', () => {
|
|
413
|
+
expect(normalizeClasses(['class1', 'class2', 'class3'])).toEqual({
|
|
414
|
+
class1: true,
|
|
415
|
+
class2: true,
|
|
416
|
+
class3: true
|
|
417
|
+
})
|
|
418
|
+
})
|
|
419
|
+
|
|
420
|
+
it('should normalize array of objects', () => {
|
|
421
|
+
expect(normalizeClasses([{ class1: true }, { class2: false }])).toEqual({
|
|
422
|
+
class1: true,
|
|
423
|
+
class2: false
|
|
424
|
+
})
|
|
425
|
+
})
|
|
426
|
+
|
|
427
|
+
it('should normalize mixed array', () => {
|
|
428
|
+
expect(normalizeClasses(['class1', { class2: true }, 'class3'])).toEqual({
|
|
429
|
+
class1: true,
|
|
430
|
+
class2: true,
|
|
431
|
+
class3: true
|
|
432
|
+
})
|
|
433
|
+
})
|
|
434
|
+
|
|
435
|
+
it('should handle empty string', () => {
|
|
436
|
+
expect(normalizeClasses('')).toEqual({})
|
|
437
|
+
})
|
|
438
|
+
|
|
439
|
+
it('should handle string with only spaces', () => {
|
|
440
|
+
expect(normalizeClasses(' ')).toEqual({})
|
|
441
|
+
})
|
|
442
|
+
})
|
package/src/util/helpers.ts
CHANGED
|
@@ -531,4 +531,45 @@ export function normalizeAttrs (attrs) {
|
|
|
531
531
|
}
|
|
532
532
|
|
|
533
533
|
return obj
|
|
534
|
-
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* Нормализует классы из различных форматов в объект
|
|
538
|
+
* @param classes - классы в виде строки, объекта или массива
|
|
539
|
+
* @returns объект с нормализованными классами
|
|
540
|
+
*/
|
|
541
|
+
export function normalizeClasses (classes: string | Record<string, any> | Array<string | Record<string, any>> | undefined): Record<string, any> {
|
|
542
|
+
if (!classes) return {}
|
|
543
|
+
|
|
544
|
+
if (typeof classes === 'object' && !Array.isArray(classes)) {
|
|
545
|
+
return classes
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
if (typeof classes === 'string') {
|
|
549
|
+
const trimmed = classes.trim()
|
|
550
|
+
if (!trimmed) return {}
|
|
551
|
+
|
|
552
|
+
return trimmed.split(/\s+/).reduce((acc, cls) => {
|
|
553
|
+
acc[cls] = true
|
|
554
|
+
return acc
|
|
555
|
+
}, {} as Record<string, any>)
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
if (Array.isArray(classes)) {
|
|
559
|
+
return classes.reduce((acc, cls) => {
|
|
560
|
+
if (typeof cls === 'string') {
|
|
561
|
+
const trimmed = cls.trim()
|
|
562
|
+
if (trimmed) {
|
|
563
|
+
trimmed.split(/\s+/).forEach(className => {
|
|
564
|
+
acc[className] = true
|
|
565
|
+
})
|
|
566
|
+
}
|
|
567
|
+
} else if (cls && typeof cls === 'object') {
|
|
568
|
+
Object.assign(acc, cls)
|
|
569
|
+
}
|
|
570
|
+
return acc
|
|
571
|
+
}, {} as Record<string, any>)
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
return {}
|
|
575
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Legacy events mixin for Vue 3 migration
|
|
2
|
+
// Provides $on, $off, and $emitLegacy methods to maintain compatibility with Vue 2 code
|
|
3
|
+
|
|
4
|
+
export const legacyEventsMixin = {
|
|
5
|
+
methods: {
|
|
6
|
+
$emitLegacy (eventName: string, args?: any) {
|
|
7
|
+
if (!this.eventsLegacy || !this.eventsLegacy[eventName]) return
|
|
8
|
+
|
|
9
|
+
this.eventsLegacy[eventName].forEach((listener: Function) => listener(args))
|
|
10
|
+
},
|
|
11
|
+
$on (eventName: string, listener: Function) {
|
|
12
|
+
this.eventsLegacy ||= {}
|
|
13
|
+
this.eventsLegacy[eventName] ||= []
|
|
14
|
+
this.eventsLegacy[eventName].push(listener)
|
|
15
|
+
// console.warn("$on is not available")
|
|
16
|
+
},
|
|
17
|
+
$off (eventName: string, listener: Function) {
|
|
18
|
+
if (this.eventsLegacy && this.eventsLegacy[eventName]) {
|
|
19
|
+
this.eventsLegacy[eventName] = this.eventsLegacy[eventName].filter((_listener: Function) => _listener !== listener)
|
|
20
|
+
}
|
|
21
|
+
// console.warn('$off is not available')
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
computed: {
|
|
25
|
+
$listeners () {
|
|
26
|
+
const names = Object.keys(this.$attrs).filter(name => name.startsWith('on'))
|
|
27
|
+
|
|
28
|
+
return names.reduce((listeners, name) => {
|
|
29
|
+
listeners[name] = this.$attrs[name]
|
|
30
|
+
return listeners
|
|
31
|
+
}, {})
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
}
|